[
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.yml",
    "content": "name: Bug report\ndescription: Create a report to help us improve App Manager\nlabels: [Bug]\n\nbody:\n  - type: checkboxes\n    attributes:\n       label: Please check before submitting an issue\n       description: Checking the <a href=\"https://muntashirakon.github.io/AppManager/\">docs</a> before submitting an issue may solve your problem.\n       options:\n          - label: I know what my device, OS and App Manager versions are\n            required: true\n            \n          - label: I know how to take logs\n            required: true\n            \n          - label: I know how to reproduce the issue which may not be specific to my device\n            required: false\n\n\n  - type: textarea\n    attributes:\n        label: Describe the bug\n        description: A clear and concise description of what the bug is\n    validations:\n        required: true\n      \n\n  - type: textarea\n    attributes:\n        label: To Reproduce\n        description: Steps to reproduce the behaviour\n        placeholder: |\n          - 1. Go to '...'\n          - 2. Click on '....'\n          - 3. Scroll down to '....'\n          - 4. See error\n          \n\n  - type: textarea\n    attributes:\n        label: Expected behavior\n        description: A clear and concise description of what you expected to happen.\n    \n    \n  - type: textarea\n    attributes:\n        label: Screenshots\n        description: If applicable, add screenshots to help explain your problem.\n        \n        \n  - type: textarea\n    attributes:\n        label: Logs\n        description: If applicable, add crash or any other logs to help us figure out the problem.\n        \n        \n  - type: textarea\n    attributes:\n        label: Device info\n        value: |\n          - Device:\n          - OS Version:\n          - App Manager Version:\n          - Mode: Root/ADB/NonRoot\n    validations:\n        required: true\n\n\n  - type: textarea\n    attributes:\n        label: Additional context\n        description: Add any other context about the problem here.\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/config.yml",
    "content": "blank_issues_enabled: false\ncontact_links:\n  - name: 🐜 android-libraries Repo\n    url: https://github.com/MuntashirAkon/android-libraries\n    about: Please send requests for new trackers and libraries to this repository\n  - name: 📗 App Manager Docs\n    url: https://muntashirakon.github.io/AppManager/\n    about: Please read documentation carefully before submitting an issue\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/documentation.yml",
    "content": "name: Docs improvement\ndescription: Improve Docs and Readme\nlabels: [Documentation]\n\nbody:\n  - type: checkboxes\n    attributes:\n       label: Please check before submitting an issue\n       description: You must be familiar with the technical terms specified in the documentation. Also, if your problem comes from the translated version rather than the English original, please correct it from Weblate.\n       options:\n          - label: This issue is not related to the translated version of the documentation\n            required: true\n\n          - label: I know technical terms used in the documentation\n            required: true\n\n  - type: textarea\n    attributes:\n        label: Describe the problem area\n        description: A short and concise description of the already existing feature or documentation, e.g. uninstall in batch operations.\n    validations:\n        required: true\n\n  - type: textarea\n    attributes:\n        label: Current documentation if it present\n        description: Link or copy-and-paste the current description or refer by section number and title\n\n  - type: textarea\n    attributes:\n        label: Describe your suggestion\n        description: A clear and concise description of what you expect the documentation to contain, e.g. it should've been noted that uninstall in batch operations does not work in no-root mode\n    validations:\n        required: true\n\n  - type: textarea\n    attributes:\n        label: Additional context\n        description: Add any other context or screenshots about the documentation here.\n\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.yml",
    "content": "name: Feature request\ndescription: Suggest an idea for this project\nlabels: [Feature]\n\nbody:\n  - type: checkboxes\n    attributes:\n       label: Please check before submitting an issue\n       description: Checking the <a href=\"https://muntashirakon.github.io/AppManager/\">docs</a> before submitting an issue may solve your problem.\n       options:\n          - label: I am using the latest version of App Manager\n            required: true\n            \n          - label: I have searched the issues and haven't found anything relevant\n            required: true\n            \n          - label: I have read the docs\n            required: true\n\n\n  - type: textarea\n    attributes:\n        label: Describe a description of the new feature\n        description: A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]\n    validations:\n        required: true\n      \n\n  - type: textarea\n    attributes:\n        label: Describe the solution you'd like\n        description: A clear and concise description of what you want to happen.\n\n\n  - type: textarea\n    attributes:\n        label: Describe alternatives you've considered\n        description: A clear and concise description of any alternative solutions or features you've considered\n        \n  - type: textarea\n    attributes:\n        label: Additional context\n        description: Add any other context or screenshots about the feature request here.\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/help-wanted.yml",
    "content": "name: Help wanted\ndescription: Ask for help regarding a feature\nlabels: [Help Wanted]\n\nbody:\n\n  - type: textarea\n    attributes:\n        label: Describe the existing feature/documentation\n        description: A short and concise description of the already existing feature or documentation, e.g. uninstall in batch operations. The purpose of this template is to improve your knowledge regarding the feature.  For new features, use the feature request template. Use the bug report template if the feature is not working as expected.\n      \n\n  - type: textarea\n    attributes:\n        label: Describe your problem(s)\n        description: Describe the problem(s) you've faced while using the feature or reading the documentation.\n        \n        \n  - type: textarea\n    attributes:\n        label: Additional context\n        description: Add any other context or screenshots about the feature/documentation here.\n"
  },
  {
    "path": ".github/workflows/codeql.yml",
    "content": "name: \"CodeQL\"\n\non:\n  push:\n    branches: [ \"master\", \"AppManager-*\" ]\n  pull_request:\n    branches: [ \"master\" ]\n  schedule:\n    - cron: '43 14 * * 4'\n\njobs:\n  analyze:\n    name: Analyze\n    runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-latest' }}\n    timeout-minutes: ${{ (matrix.language == 'swift' && 120) || 360 }}\n    permissions:\n      actions: read\n      contents: read\n      security-events: write\n\n    strategy:\n      fail-fast: false\n      matrix:\n        language: [ 'java' ]\n\n    steps:\n      - name: Checkout repository\n        uses: actions/checkout@v4\n        with:\n          submodules: 'recursive'\n      - name: Set up JDK\n        uses: actions/setup-java@v4\n        with:\n          distribution: 'zulu'\n          java-version: '21'\n          cache: 'gradle'\n      - name: Initialize CodeQL\n        uses: github/codeql-action/init@v3\n        with:\n          languages: ${{ matrix.language }}\n      - name: Autobuild\n        uses: github/codeql-action/autobuild@v3\n      - name: Perform CodeQL Analysis\n        uses: github/codeql-action/analyze@v3\n        with:\n          category: \"/language:${{matrix.language}}\"\n"
  },
  {
    "path": ".github/workflows/lint.yml",
    "content": "name: Lint\n\non:\n  push:\n    branches:\n      - 'master'\n      - 'AppManager-*'\n    paths-ignore:\n      - 'fastlane/**'\n      - 'scripts/**'\n      - '*.md'\n  pull_request:\n    branches:\n      - 'master'\n      - 'AppManager-*'\n    paths-ignore:\n      - 'fastlane/**'\n      - 'scripts/**'\n      - '*.md'\n\njobs:\n  build:\n    runs-on: ubuntu-latest\n    steps:\n      - name: Clone the repository\n        uses: actions/checkout@v4\n        with:\n          submodules: 'recursive'\n      - name: Set up JDK\n        uses: actions/setup-java@v4\n        with:\n          distribution: 'zulu'\n          java-version: '21'\n          cache: 'gradle'\n      - name: Grant execute permission for gradlew\n        run: chmod +x gradlew\n      - name: Run lint\n        run: ./gradlew lint\n      - name: Upload lint results\n        if: ${{ always() }}\n        uses: actions/upload-artifact@v4\n        with:\n          path: ./app/build/reports/lint-results-debug.html\n"
  },
  {
    "path": ".github/workflows/tests.yml",
    "content": "name: Tests\n\non:\n  push:\n    branches:\n      - 'master'\n      - 'AppManager-*'\n    paths-ignore:\n      - 'fastlane/**'\n      - 'scripts/**'\n      - '*.md'\n  pull_request:\n    branches:\n      - 'master'\n      - 'AppManager-*'\n    paths-ignore:\n      - 'fastlane/**'\n      - 'scripts/**'\n      - '*.md'\n\njobs:\n  build:\n    runs-on: ubuntu-latest\n    steps:\n      - name: Clone the repository\n        uses: actions/checkout@v4\n        with:\n          submodules: 'recursive'\n      - name: Set up JDK\n        uses: actions/setup-java@v4\n        with:\n          distribution: 'zulu'\n          java-version: '21'\n          cache: 'gradle'\n      - name: Grant execute permission for gradlew\n        run: chmod +x gradlew\n      - name: Run tests\n        run: ./gradlew test\n      - name: Upload test results\n        if: ${{ always() }}\n        uses: actions/upload-artifact@v4\n        with:\n          name: unitTestResults\n          path: ./app/build/reports/tests/testDebugUnitTest/\n"
  },
  {
    "path": ".gitignore",
    "content": ".gradle/\n.idea/\ncrowdin.properties\nlocal.properties\n.DS_Store\nbuild/\napp/preRelease/\napp/release/\napp/debug/\napp/libs/am-common.jar\ntoybox/src/main/jniLibs\napp/src/main/assets/am.jar\napp/src/main/assets/main.jar\npids\nlogs\nnode_modules\nnpm-debug.log\ncoverage/\nrun\ndist\n.nyc_output\n.basement\nconfig.local.js\nbasement_dist\n*.apk\n*.iml\n*.jks\n*~\nscripts/KeyStore.sh\n"
  },
  {
    "path": ".gitmodules",
    "content": "[submodule \"scripts/android-libraries\"]\n\tpath = scripts/android-libraries\n\turl = https://github.com/MuntashirAkon/android-libraries.git\n[submodule \"scripts/android-debloat-list\"]\n\tpath = scripts/android-debloat-list\n\turl = https://github.com/MuntashirAkon/android-debloat-list.git\n"
  },
  {
    "path": ".run/Documentation.run.xml",
    "content": "<component name=\"ProjectRunConfigurationManager\">\n  <configuration default=\"false\" name=\"Documentation\" type=\"LATEX_RUN_CONFIGURATION\" factoryName=\"LaTeX configuration factory\" activateToolWindowBeforeRun=\"false\">\n    <texify>\n      <compiler>PDFLATEX</compiler>\n      <compiler-path>pdflatex</compiler-path>\n      <sumatra-path />\n      <pdf-viewer>NONE</pdf-viewer>\n      <viewer-command>open</viewer-command>\n      <compiler-arguments>-shell-escape</compiler-arguments>\n      <envs />\n      <main-file>$PROJECT_DIR$/docs/raw/en/main_vanilla.tex</main-file>\n      <output-path>$PROJECT_DIR$/docs/raw/en</output-path>\n      <auxil-path>{projectDir}/auxil</auxil-path>\n      <compile-twice>false</compile-twice>\n      <output-format>PDF</output-format>\n      <latex-distribution>TEXLIVE</latex-distribution>\n      <has-been-run>true</has-been-run>\n      <bib-run-config>[]</bib-run-config>\n      <makeindex-run-config>[]</makeindex-run-config>\n    </texify>\n    <method v=\"2\" />\n  </configuration>\n</component>"
  },
  {
    "path": ".run/app.run.xml",
    "content": "<component name=\"ProjectRunConfigurationManager\">\n  <configuration default=\"false\" name=\"app\" type=\"AndroidRunConfigurationType\" factoryName=\"Android App\" activateToolWindowBeforeRun=\"false\">\n    <module name=\"AppManager.app.main\" />\n    <option name=\"DEPLOY\" value=\"true\" />\n    <option name=\"DEPLOY_APK_FROM_BUNDLE\" value=\"false\" />\n    <option name=\"DEPLOY_AS_INSTANT\" value=\"false\" />\n    <option name=\"ARTIFACT_NAME\" value=\"\" />\n    <option name=\"PM_INSTALL_OPTIONS\" value=\"\" />\n    <option name=\"ALL_USERS\" value=\"false\" />\n    <option name=\"ALWAYS_INSTALL_WITH_PM\" value=\"true\" />\n    <option name=\"CLEAR_APP_STORAGE\" value=\"false\" />\n    <option name=\"DYNAMIC_FEATURES_DISABLED_LIST\" value=\"\" />\n    <option name=\"ACTIVITY_EXTRA_FLAGS\" value=\"\" />\n    <option name=\"MODE\" value=\"default_activity\" />\n    <option name=\"CLEAR_LOGCAT\" value=\"false\" />\n    <option name=\"SHOW_LOGCAT_AUTOMATICALLY\" value=\"false\" />\n    <option name=\"INSPECTION_WITHOUT_ACTIVITY_RESTART\" value=\"false\" />\n    <option name=\"TARGET_SELECTION_MODE\" value=\"DEVICE_AND_SNAPSHOT_COMBO_BOX\" />\n    <option name=\"DEBUGGER_TYPE\" value=\"Java\" />\n    <Java />\n    <Profilers>\n      <option name=\"ADVANCED_PROFILING_ENABLED\" value=\"false\" />\n      <option name=\"STARTUP_PROFILING_ENABLED\" value=\"false\" />\n      <option name=\"STARTUP_CPU_PROFILING_ENABLED\" value=\"false\" />\n      <option name=\"STARTUP_CPU_PROFILING_CONFIGURATION_NAME\" value=\"Java/Kotlin Method Sample (legacy)\" />\n      <option name=\"STARTUP_NATIVE_MEMORY_PROFILING_ENABLED\" value=\"false\" />\n      <option name=\"NATIVE_MEMORY_SAMPLE_RATE_BYTES\" value=\"2048\" />\n    </Profilers>\n    <option name=\"DEEP_LINK\" value=\"\" />\n    <option name=\"ACTIVITY_CLASS\" value=\"\" />\n    <option name=\"SEARCH_ACTIVITY_IN_GLOBAL_SCOPE\" value=\"false\" />\n    <option name=\"SKIP_ACTIVITY_VALIDATION\" value=\"false\" />\n    <method v=\"2\">\n      <option name=\"Android.Gradle.BeforeRunTask\" enabled=\"true\" />\n    </method>\n  </configuration>\n</component>"
  },
  {
    "path": ".run/app_details.run.xml",
    "content": "<component name=\"ProjectRunConfigurationManager\">\n  <configuration default=\"false\" name=\"app_details\" type=\"AndroidRunConfigurationType\" factoryName=\"Android App\" activateToolWindowBeforeRun=\"false\">\n    <module name=\"AppManager.app.main\" />\n    <option name=\"DEPLOY\" value=\"true\" />\n    <option name=\"DEPLOY_APK_FROM_BUNDLE\" value=\"false\" />\n    <option name=\"DEPLOY_AS_INSTANT\" value=\"false\" />\n    <option name=\"ARTIFACT_NAME\" value=\"\" />\n    <option name=\"PM_INSTALL_OPTIONS\" value=\"\" />\n    <option name=\"ALL_USERS\" value=\"false\" />\n    <option name=\"ALWAYS_INSTALL_WITH_PM\" value=\"true\" />\n    <option name=\"CLEAR_APP_STORAGE\" value=\"false\" />\n    <option name=\"DYNAMIC_FEATURES_DISABLED_LIST\" value=\"\" />\n    <option name=\"ACTIVITY_EXTRA_FLAGS\" value=\"-e pkg io.github.muntashirakon.AppManager.debug\" />\n    <option name=\"MODE\" value=\"specific_activity\" />\n    <option name=\"CLEAR_LOGCAT\" value=\"false\" />\n    <option name=\"SHOW_LOGCAT_AUTOMATICALLY\" value=\"false\" />\n    <option name=\"INSPECTION_WITHOUT_ACTIVITY_RESTART\" value=\"false\" />\n    <option name=\"TARGET_SELECTION_MODE\" value=\"DEVICE_AND_SNAPSHOT_COMBO_BOX\" />\n    <option name=\"DEBUGGER_TYPE\" value=\"Java\" />\n    <Java />\n    <Profilers>\n      <option name=\"ADVANCED_PROFILING_ENABLED\" value=\"false\" />\n      <option name=\"STARTUP_PROFILING_ENABLED\" value=\"false\" />\n      <option name=\"STARTUP_CPU_PROFILING_ENABLED\" value=\"false\" />\n      <option name=\"STARTUP_CPU_PROFILING_CONFIGURATION_NAME\" value=\"Java/Kotlin Method Sample (legacy)\" />\n      <option name=\"STARTUP_NATIVE_MEMORY_PROFILING_ENABLED\" value=\"false\" />\n      <option name=\"NATIVE_MEMORY_SAMPLE_RATE_BYTES\" value=\"2048\" />\n    </Profilers>\n    <option name=\"DEEP_LINK\" value=\"\" />\n    <option name=\"ACTIVITY_CLASS\" value=\"io.github.muntashirakon.AppManager.details.AppInfoActivity\" />\n    <option name=\"SEARCH_ACTIVITY_IN_GLOBAL_SCOPE\" value=\"false\" />\n    <option name=\"SKIP_ACTIVITY_VALIDATION\" value=\"false\" />\n    <method v=\"2\">\n      <option name=\"Android.Gradle.BeforeRunTask\" enabled=\"true\" />\n    </method>\n  </configuration>\n</component>"
  },
  {
    "path": ".run/fm.run.xml",
    "content": "<component name=\"ProjectRunConfigurationManager\">\n  <configuration default=\"false\" name=\"fm\" type=\"AndroidRunConfigurationType\" factoryName=\"Android App\" activateToolWindowBeforeRun=\"false\">\n    <module name=\"AppManager.app.main\" />\n    <option name=\"DEPLOY\" value=\"true\" />\n    <option name=\"DEPLOY_APK_FROM_BUNDLE\" value=\"false\" />\n    <option name=\"DEPLOY_AS_INSTANT\" value=\"false\" />\n    <option name=\"ARTIFACT_NAME\" value=\"\" />\n    <option name=\"PM_INSTALL_OPTIONS\" value=\"\" />\n    <option name=\"ALL_USERS\" value=\"false\" />\n    <option name=\"ALWAYS_INSTALL_WITH_PM\" value=\"true\" />\n    <option name=\"CLEAR_APP_STORAGE\" value=\"false\" />\n    <option name=\"DYNAMIC_FEATURES_DISABLED_LIST\" value=\"\" />\n    <option name=\"ACTIVITY_EXTRA_FLAGS\" value=\"\" />\n    <option name=\"MODE\" value=\"specific_activity\" />\n    <option name=\"CLEAR_LOGCAT\" value=\"false\" />\n    <option name=\"SHOW_LOGCAT_AUTOMATICALLY\" value=\"false\" />\n    <option name=\"INSPECTION_WITHOUT_ACTIVITY_RESTART\" value=\"false\" />\n    <option name=\"TARGET_SELECTION_MODE\" value=\"DEVICE_AND_SNAPSHOT_COMBO_BOX\" />\n    <option name=\"DEBUGGER_TYPE\" value=\"Java\" />\n    <Java />\n    <Profilers>\n      <option name=\"ADVANCED_PROFILING_ENABLED\" value=\"false\" />\n      <option name=\"STARTUP_PROFILING_ENABLED\" value=\"false\" />\n      <option name=\"STARTUP_CPU_PROFILING_ENABLED\" value=\"false\" />\n      <option name=\"STARTUP_CPU_PROFILING_CONFIGURATION_NAME\" value=\"Java/Kotlin Method Sample (legacy)\" />\n      <option name=\"STARTUP_NATIVE_MEMORY_PROFILING_ENABLED\" value=\"false\" />\n      <option name=\"NATIVE_MEMORY_SAMPLE_RATE_BYTES\" value=\"2048\" />\n    </Profilers>\n    <option name=\"DEEP_LINK\" value=\"\" />\n    <option name=\"ACTIVITY_CLASS\" value=\"io.github.muntashirakon.AppManager.fm.FmActivity\" />\n    <option name=\"SEARCH_ACTIVITY_IN_GLOBAL_SCOPE\" value=\"false\" />\n    <option name=\"SKIP_ACTIVITY_VALIDATION\" value=\"false\" />\n    <method v=\"2\">\n      <option name=\"Android.Gradle.BeforeRunTask\" enabled=\"true\" />\n    </method>\n  </configuration>\n</component>"
  },
  {
    "path": ".run/lint.run.xml",
    "content": "<component name=\"ProjectRunConfigurationManager\">\n  <configuration default=\"false\" name=\"lint\" type=\"GradleRunConfiguration\" factoryName=\"Gradle\">\n    <ExternalSystemSettings>\n      <option name=\"executionName\" />\n      <option name=\"externalProjectPath\" value=\"$PROJECT_DIR$\" />\n      <option name=\"externalSystemIdString\" value=\"GRADLE\" />\n      <option name=\"scriptParameters\" value=\"\" />\n      <option name=\"taskDescriptions\">\n        <list />\n      </option>\n      <option name=\"taskNames\">\n        <list>\n          <option value=\"lintDebug\" />\n        </list>\n      </option>\n      <option name=\"vmOptions\" />\n    </ExternalSystemSettings>\n    <ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>\n    <ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>\n    <DebugAllEnabled>false</DebugAllEnabled>\n    <method v=\"2\" />\n  </configuration>\n</component>"
  },
  {
    "path": ".run/settings.run.xml",
    "content": "<component name=\"ProjectRunConfigurationManager\">\n  <configuration default=\"false\" name=\"settings\" type=\"AndroidRunConfigurationType\" factoryName=\"Android App\" activateToolWindowBeforeRun=\"false\">\n    <module name=\"AppManager.app.main\" />\n    <option name=\"DEPLOY\" value=\"true\" />\n    <option name=\"DEPLOY_APK_FROM_BUNDLE\" value=\"false\" />\n    <option name=\"DEPLOY_AS_INSTANT\" value=\"false\" />\n    <option name=\"ARTIFACT_NAME\" value=\"\" />\n    <option name=\"PM_INSTALL_OPTIONS\" value=\"\" />\n    <option name=\"ALL_USERS\" value=\"false\" />\n    <option name=\"ALWAYS_INSTALL_WITH_PM\" value=\"true\" />\n    <option name=\"CLEAR_APP_STORAGE\" value=\"false\" />\n    <option name=\"DYNAMIC_FEATURES_DISABLED_LIST\" value=\"\" />\n    <option name=\"ACTIVITY_EXTRA_FLAGS\" value=\"\" />\n    <option name=\"MODE\" value=\"specific_activity\" />\n    <option name=\"CLEAR_LOGCAT\" value=\"false\" />\n    <option name=\"SHOW_LOGCAT_AUTOMATICALLY\" value=\"false\" />\n    <option name=\"INSPECTION_WITHOUT_ACTIVITY_RESTART\" value=\"false\" />\n    <option name=\"TARGET_SELECTION_MODE\" value=\"DEVICE_AND_SNAPSHOT_COMBO_BOX\" />\n    <option name=\"SELECTED_CLOUD_MATRIX_CONFIGURATION_ID\" value=\"-1\" />\n    <option name=\"SELECTED_CLOUD_MATRIX_PROJECT_ID\" value=\"\" />\n    <option name=\"DEBUGGER_TYPE\" value=\"Java\" />\n    <Auto>\n      <option name=\"USE_JAVA_AWARE_DEBUGGER\" value=\"false\" />\n      <option name=\"SHOW_STATIC_VARS\" value=\"true\" />\n      <option name=\"WORKING_DIR\" value=\"\" />\n      <option name=\"TARGET_LOGGING_CHANNELS\" value=\"lldb process:gdb-remote packets\" />\n      <option name=\"SHOW_OPTIMIZED_WARNING\" value=\"true\" />\n      <option name=\"ATTACH_ON_WAIT_FOR_DEBUGGER\" value=\"false\" />\n      <option name=\"DEBUG_SANDBOX_SDK\" value=\"false\" />\n    </Auto>\n    <Hybrid>\n      <option name=\"USE_JAVA_AWARE_DEBUGGER\" value=\"false\" />\n      <option name=\"SHOW_STATIC_VARS\" value=\"true\" />\n      <option name=\"WORKING_DIR\" value=\"\" />\n      <option name=\"TARGET_LOGGING_CHANNELS\" value=\"lldb process:gdb-remote packets\" />\n      <option name=\"SHOW_OPTIMIZED_WARNING\" value=\"true\" />\n      <option name=\"ATTACH_ON_WAIT_FOR_DEBUGGER\" value=\"false\" />\n      <option name=\"DEBUG_SANDBOX_SDK\" value=\"false\" />\n    </Hybrid>\n    <Java>\n      <option name=\"ATTACH_ON_WAIT_FOR_DEBUGGER\" value=\"false\" />\n      <option name=\"DEBUG_SANDBOX_SDK\" value=\"false\" />\n    </Java>\n    <Native>\n      <option name=\"USE_JAVA_AWARE_DEBUGGER\" value=\"false\" />\n      <option name=\"SHOW_STATIC_VARS\" value=\"true\" />\n      <option name=\"WORKING_DIR\" value=\"\" />\n      <option name=\"TARGET_LOGGING_CHANNELS\" value=\"lldb process:gdb-remote packets\" />\n      <option name=\"SHOW_OPTIMIZED_WARNING\" value=\"true\" />\n      <option name=\"ATTACH_ON_WAIT_FOR_DEBUGGER\" value=\"false\" />\n      <option name=\"DEBUG_SANDBOX_SDK\" value=\"false\" />\n    </Native>\n    <Profilers>\n      <option name=\"ADVANCED_PROFILING_ENABLED\" value=\"false\" />\n      <option name=\"STARTUP_PROFILING_ENABLED\" value=\"false\" />\n      <option name=\"STARTUP_CPU_PROFILING_ENABLED\" value=\"false\" />\n      <option name=\"STARTUP_CPU_PROFILING_CONFIGURATION_NAME\" value=\"Java/Kotlin Method Sample (legacy)\" />\n      <option name=\"STARTUP_NATIVE_MEMORY_PROFILING_ENABLED\" value=\"false\" />\n      <option name=\"NATIVE_MEMORY_SAMPLE_RATE_BYTES\" value=\"2048\" />\n    </Profilers>\n    <option name=\"DEEP_LINK\" value=\"\" />\n    <option name=\"ACTIVITY_CLASS\" value=\"io.github.muntashirakon.AppManager.settings.SettingsActivity\" />\n    <option name=\"SEARCH_ACTIVITY_IN_GLOBAL_SCOPE\" value=\"false\" />\n    <option name=\"SKIP_ACTIVITY_VALIDATION\" value=\"false\" />\n    <method v=\"2\">\n      <option name=\"Android.Gradle.BeforeRunTask\" enabled=\"true\" />\n    </method>\n  </configuration>\n</component>"
  },
  {
    "path": ".run/test.run.xml",
    "content": "<component name=\"ProjectRunConfigurationManager\">\n  <configuration default=\"false\" name=\"test\" type=\"GradleRunConfiguration\" factoryName=\"Gradle\">\n    <ExternalSystemSettings>\n      <option name=\"executionName\" />\n      <option name=\"externalProjectPath\" value=\"$PROJECT_DIR$\" />\n      <option name=\"externalSystemIdString\" value=\"GRADLE\" />\n      <option name=\"scriptParameters\" value=\"\" />\n      <option name=\"taskDescriptions\">\n        <list />\n      </option>\n      <option name=\"taskNames\">\n        <list>\n          <option value=\"testDebugUnitTest\" />\n        </list>\n      </option>\n      <option name=\"vmOptions\" />\n    </ExternalSystemSettings>\n    <ExternalSystemDebugServerProcess>true</ExternalSystemDebugServerProcess>\n    <ExternalSystemReattachDebugProcess>true</ExternalSystemReattachDebugProcess>\n    <DebugAllEnabled>false</DebugAllEnabled>\n    <method v=\"2\" />\n  </configuration>\n</component>"
  },
  {
    "path": "BUILDING.rst",
    "content": ".. SPDX-License-Identifier: GPL-3.0-or-later OR CC-BY-SA-4.0\n\n====================\nBuilding App Manager\n====================\n\nRequirements\n============\n\n* **Hardware:** Any computer with 8 GB RAM and 20 GB storage\n* **Operating system:** Linux/macOS/WSL\n* **Software:** Android Studio/IntelliJ IDEA, Gradle, Latex, pandoc, JDK 17+\n* **Active network connection:** Depending on your development environment,\n  you may need at least 20 GB data package.\n\nmacOS\n=====\n\nThe following steps are required only if you want to build APKS:\n\n- Install Homebrew::\n\n    /bin/bash -c \"$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)\"\n\n- Install bundletool::\n\n    brew install bundletool\n\nLinux|GNU\n=========\n\n- Install the development tools.\n\n  * For Debian/Ubuntu::\n\n      sudo apt-get install build-essential\n\n  * For Fedora/CentOS/RHEL::\n\n      sudo yum groupinstall \"Development Tools\"\n\n  * For Arch/Artix/Manjaro::\n\n      sudo pacman -S base-devel\n\n- Install `bundletool-all.jar`_ if you want to build APKS, and make sure it is\n  available as ``bundletool`` command.  A quick way would be to create an alias\n  as follows (assuming you're using ``bash``)::\n\n    echo \"alias bundletool='java -jar path/to/bundletool.jar'\" >> ~/.bashrc\n\n  Make sure to replace ``/path/to/bundletool-all.jar`` with the actual path for\n  **bundletool-all.jar**.\n\n  * For Arch/Artix/Majaro (with ``yay``)::\n\n      yay -S bundletool\n\n\nClone and Build App Manager\n===========================\n\n1. Clone the repo along with submodules::\n\n     git clone --recurse-submodules https://github.com/MuntashirAkon/AppManager.git\n\n   You can use the `--depth 1` argument if you don't want to clone past\n   commits.\n2. Open the project **AppManager** using Android Studio/IntelliJ IDEA.  The IDE\n   should start syncing automatically.  It will also download all the necessary\n   dependencies automatically provided you have a working network connection.\n3. Build debug version of App Manager from *Menu* > *Build* > *Make Project*,\n   or, from the terminal::\n\n     ./gradlew packageDebugUniversalApk\n\n   The command will generate a universal APK instead of a bundled app.\n\nCreate Bundled App\n==================\n\nTo create a bundled app in APKS format, run the following command::\n\n  ./scripts/aab_to_apks.sh type\n\nReplace ``type`` with ``release`` or ``debug`` based on your requirements.\nIt will ask for KeyStore credentials interactively.\n\nThe script above will also generate a universal APK.\n\n.. _bundletool-all.jar: https://github.com/google/bundletool\n\n\nBuild documentation\n===================\nSee  `docs/raw/en/README.md <docs/raw/en/README.md>`_\n"
  },
  {
    "path": "CONTRIBUTING.rst",
    "content": ".. SPDX-License-Identifier: GPL-3.0-or-later OR CC-BY-SA-4.0\n\n============\nContributing\n============\n\nYou are welcome contribute to App Manager!  This doesn't mean that you need\ncoding skills.  You can contribute to App Manager by creating helpful issues,\nattending discussions, improving documentations and translations, making icon\nfor icon packs, adding unrecognised libraries or ad/tracking signatures,\nreviewing the source code, as well as reporting security vulnerabilities.\n\nAI-Generated Contributions\n==========================\n\nTo maintain the legal integrity and clear provenance of App Manager's codebase\nunder the GPL-3.0-or-later license, we DO NOT accept contributions that are\ngenerated, in whole part or in part, by Artificial Intelligence (AI) or Large\nLanguage Models (LLMs). All contributions MUST be the original work of the\nhuman author(s) submitting the pull or merge request. By submitting a pull or\nmerge request, you affirm that the code was authored by you without the use of\ngenerative AI tools that produce functional code blocks.\n\nRules\n=====\n\n- If you are going to implement or work on any specific feature, please inform\n  us before doing so. Due to the complex nature of the project, integrating a\n  new feature could be challenging.\n- Your contributions are licensed under ``GPL-3.0-or-later`` by default.\n  Please see related `Linux documentations`_ to see how to add license headers\n  to a file, and remember the following:\n\n  * If the files your are contributing to do not have ``GPL-3.0-or-later``, add\n    it to the existing ``SPDX-License-Identifier`` using ``AND``, e.g.  ::\n\n        SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-or-later\n\n  * If the entire file or Java class is copied from another person or project,\n    you have to add a copyright statement adding the person who wrote it first\n    like this::\n\n        // Copyright 2004 Linus Torvalds\n\n    You can also add other contributors but they are not mandatory.  You do not\n    need to include your name because it can already be available via the\n    version control system.\n  * Do not add the **@author** tag as it is considered a bad practice.\n\n- You have to sign-off your work.  You can do that using the ``--signoff``\n  argument.  If you are not using command line or a software that does not\n  support it, you can add the following line at the end of your commit\n  message::\n\n    Signed-off-by: My Name <my.name@example.com>\n\n  We also support most of the `commit message conventions`_ from Linux.\n\n  App Manager is a legal software and its contributions are protected by\n  copyright laws. Consider using real credentials ie. real name and email as\n  we may be required to delete your valuable contributions in the event of\n  introducing new license or adding exceptions to the existing license.\n\n**Note:** Repositories located in sites other than GitHub are currently\nconsidered mirrors and any pull or merge requests submitted there will not be\naccepted.  Instead, you can submit patches (as ``.patch`` files) via email\nattachment.  My email address is am4android [at] riseup [dot] net.  Beware\nthat such emails may be publicly accessible in future.  GitHub pull requests\nwill be merged manually using the corresponding patches.  As a result, GitHub\nmay falsely mark them *closed* instead of *merged*.\n\n**Warning.** Every commit made by other users are thoroughly examined with the\nexception of commits made through Weblate.  So, if it is found that you are\nabusing the Weblate platform, you will be blocked on Weblate without a warning,\nand ALL your contributions to this project shall be removed.  This is a hobby\nproject, and like any hobby, I want to make things neat and clean.  Existing\ncontributors are also encouraged to report any abuse.  Your identity shall be\nkept secret.\n\n.. _Linux documentations: https://github.com/torvalds/linux/blob/master/Documentation/process/license-rules.rst\n.. _commit message conventions: https://git.wiki.kernel.org/index.php/CommitMessageConventions\n"
  },
  {
    "path": "COPYING",
    "content": "App Manager is provided under:\n\n\tSPDX-License-Identifier: GPL-3.0-or-later\n\nBeing under the terms of the GNU General Public License version 3 or\nlater, according with:\n\n\tLICENSES/GPL-3.0\n\nIn addition, other licenses may also apply. Please navigate to:\n\n\tLICENSES/\n\nto see all the licenses used in this project.\n\nAll contributions to the App Manager are subject to this COPYING file."
  },
  {
    "path": "LICENSES/Apache-2.0",
    "content": "Valid-License-Identifier: Apache-2.0\nSPDX-URL: https://spdx.org/licenses/Apache-2.0.html\nUsage-Guide:\n  To use the Apache License version 2.0 put the following SPDX tag/value\n  pair into a comment according to the placement guidelines in the\n  licensing rules documentation:\n    SPDX-License-Identifier: Apache-2.0\n  Do NOT use this license unless the files are copied from another work\n  under the same license. In such cases, use \"AND GPL-3.0-or-later\" so\n  that your contributions are under GPL-3.0+ license.\nLicense-Text:\n\nApache License\n\nVersion 2.0, January 2004\n\nhttp://www.apache.org/licenses/\n\nTERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION\n\n1. Definitions.\n\n\"License\" shall mean the terms and conditions for use, reproduction, and\ndistribution as defined by Sections 1 through 9 of this document.\n\n\"Licensor\" shall mean the copyright owner or entity authorized by the\ncopyright owner that is granting the License.\n\n\"Legal Entity\" shall mean the union of the acting entity and all other\nentities that control, are controlled by, or are under common control with\nthat entity. For the purposes of this definition, \"control\" means (i) the\npower, direct or indirect, to cause the direction or management of such\nentity, whether by contract or otherwise, or (ii) ownership of fifty\npercent (50%) or more of the outstanding shares, or (iii) beneficial\nownership of such entity.\n\n\"You\" (or \"Your\") shall mean an individual or Legal Entity exercising\npermissions granted by this License.\n\n\"Source\" form shall mean the preferred form for making modifications,\nincluding but not limited to software source code, documentation source,\nand configuration files.\n\n\"Object\" form shall mean any form resulting from mechanical transformation\nor translation of a Source form, including but not limited to compiled\nobject code, generated documentation, and conversions to other media types.\n\n\"Work\" shall mean the work of authorship, whether in Source or Object form,\nmade available under the License, as indicated by a copyright notice that\nis included in or attached to the work (an example is provided in the\nAppendix below).\n\n\"Derivative Works\" shall mean any work, whether in Source or Object form,\nthat is based on (or derived from) the Work and for which the editorial\nrevisions, annotations, elaborations, or other modifications represent, as\na whole, an original work of authorship. For the purposes of this License,\nDerivative Works shall not include works that remain separable from, or\nmerely link (or bind by name) to the interfaces of, the Work and Derivative\nWorks thereof.\n\n\"Contribution\" shall mean any work of authorship, including the original\nversion of the Work and any modifications or additions to that Work or\nDerivative Works thereof, that is intentionally submitted to Licensor for\ninclusion in the Work by the copyright owner or by an individual or Legal\nEntity authorized to submit on behalf of the copyright owner. For the\npurposes of this definition, \"submitted\" means any form of electronic,\nverbal, or written communication sent to the Licensor or its\nrepresentatives, including but not limited to communication on electronic\nmailing lists, source code control systems, and issue tracking systems that\nare managed by, or on behalf of, the Licensor for the purpose of discussing\nand improving the Work, but excluding communication that is conspicuously\nmarked or otherwise designated in writing by the copyright owner as \"Not a\nContribution.\"\n\n\"Contributor\" shall mean Licensor and any individual or Legal Entity on\nbehalf of whom a Contribution has been received by Licensor and\nsubsequently incorporated within the Work.\n\n2. Grant of Copyright License. Subject to the terms and conditions of this\n   License, each Contributor hereby grants to You a perpetual, worldwide,\n   non-exclusive, no-charge, royalty-free, irrevocable copyright license to\n   reproduce, prepare Derivative Works of, publicly display, publicly\n   perform, sublicense, and distribute the Work and such Derivative Works\n   in Source or Object form.\n\n3. Grant of Patent License. Subject to the terms and conditions of this\n   License, each Contributor hereby grants to You a perpetual, worldwide,\n   non-exclusive, no-charge, royalty-free, irrevocable (except as stated in\n   this section) patent license to make, have made, use, offer to sell,\n   sell, import, and otherwise transfer the Work, where such license\n   applies only to those patent claims licensable by such Contributor that\n   are necessarily infringed by their Contribution(s) alone or by\n   combination of their Contribution(s) with the Work to which such\n   Contribution(s) was submitted. If You institute patent litigation\n   against any entity (including a cross-claim or counterclaim in a\n   lawsuit) alleging that the Work or a Contribution incorporated within\n   the Work constitutes direct or contributory patent infringement, then\n   any patent licenses granted to You under this License for that Work\n   shall terminate as of the date such litigation is filed.\n\n4. Redistribution. You may reproduce and distribute copies of the Work or\n   Derivative Works thereof in any medium, with or without modifications,\n   and in Source or Object form, provided that You meet the following\n   conditions:\n\n   a. You must give any other recipients of the Work or Derivative Works a\n      copy of this License; and\n\n   b. You must cause any modified files to carry prominent notices stating\n      that You changed the files; and\n\n   c. You must retain, in the Source form of any Derivative Works that You\n      distribute, all copyright, patent, trademark, and attribution notices\n      from the Source form of the Work, excluding those notices that do not\n      pertain to any part of the Derivative Works; and\n\n   d. If the Work includes a \"NOTICE\" text file as part of its\n      distribution, then any Derivative Works that You distribute must\n      include a readable copy of the attribution notices contained within\n      such NOTICE file, excluding those notices that do not pertain to any\n      part of the Derivative Works, in at least one of the following\n      places: within a NOTICE text file distributed as part of the\n      Derivative Works; within the Source form or documentation, if\n      provided along with the Derivative Works; or, within a display\n      generated by the Derivative Works, if and wherever such third-party\n      notices normally appear. The contents of the NOTICE file are for\n      informational purposes only and do not modify the License. You may\n      add Your own attribution notices within Derivative Works that You\n      distribute, alongside or as an addendum to the NOTICE text from the\n      Work, provided that such additional attribution notices cannot be\n      construed as modifying the License.\n\n    You may add Your own copyright statement to Your modifications and may\n    provide additional or different license terms and conditions for use,\n    reproduction, or distribution of Your modifications, or for any such\n    Derivative Works as a whole, provided Your use, reproduction, and\n    distribution of the Work otherwise complies with the conditions stated\n    in this License.\n\n5. Submission of Contributions. Unless You explicitly state otherwise, any\n   Contribution intentionally submitted for inclusion in the Work by You to\n   the Licensor shall be under the terms and conditions of this License,\n   without any additional terms or conditions. Notwithstanding the above,\n   nothing herein shall supersede or modify the terms of any separate\n   license agreement you may have executed with Licensor regarding such\n   Contributions.\n\n6. Trademarks. This License does not grant permission to use the trade\n   names, trademarks, service marks, or product names of the Licensor,\n   except as required for reasonable and customary use in describing the\n   origin of the Work and reproducing the content of the NOTICE file.\n\n7. Disclaimer of Warranty. Unless required by applicable law or agreed to\n   in writing, Licensor provides the Work (and each Contributor provides\n   its Contributions) on an \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS\n   OF ANY KIND, either express or implied, including, without limitation,\n   any warranties or conditions of TITLE, NON-INFRINGEMENT,\n   MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely\n   responsible for determining the appropriateness of using or\n   redistributing the Work and assume any risks associated with Your\n   exercise of permissions under this License.\n\n8. Limitation of Liability. In no event and under no legal theory, whether\n   in tort (including negligence), contract, or otherwise, unless required\n   by applicable law (such as deliberate and grossly negligent acts) or\n   agreed to in writing, shall any Contributor be liable to You for\n   damages, including any direct, indirect, special, incidental, or\n   consequential damages of any character arising as a result of this\n   License or out of the use or inability to use the Work (including but\n   not limited to damages for loss of goodwill, work stoppage, computer\n   failure or malfunction, or any and all other commercial damages or\n   losses), even if such Contributor has been advised of the possibility of\n   such damages.\n\n9. Accepting Warranty or Additional Liability. While redistributing the\n   Work or Derivative Works thereof, You may choose to offer, and charge a\n   fee for, acceptance of support, warranty, indemnity, or other liability\n   obligations and/or rights consistent with this License. However, in\n   accepting such obligations, You may act only on Your own behalf and on\n   Your sole responsibility, not on behalf of any other Contributor, and\n   only if You agree to indemnify, defend, and hold each Contributor\n   harmless for any liability incurred by, or claims asserted against, such\n   Contributor by reason of your accepting any such warranty or additional\n   liability.\n\nEND OF TERMS AND CONDITIONS"
  },
  {
    "path": "LICENSES/BSD-2-Clause",
    "content": "Valid-License-Identifier: BSD-2-Clause\nSPDX-URL: https://spdx.org/licenses/BSD-2-Clause.html\nUsage-Guide:\n  To use the BSD 2-clause \"Simplified\" License put the following SPDX\n  tag/value pair into a comment according to the placement guidelines in\n  the licensing rules documentation:\n    SPDX-License-Identifier: BSD-2-Clause\n  Do NOT use this license unless the files are copied from another work\n  under the same license. In such cases, use \"AND GPL-3.0-or-later\" so\n  that your contributions are under GPL-3.0+ license.\nLicense-Text:\n\nCopyright (c) <year> <owner> . All rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n1. Redistributions of source code must retain the above copyright notice,\n   this list of conditions and the following disclaimer.\n\n2. Redistributions in binary form must reproduce the above copyright\n   notice, this list of conditions and the following disclaimer in the\n   documentation and/or other materials provided with the distribution.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\nARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\nLIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\nCONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\nSUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\nINTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\nCONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\nARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\nPOSSIBILITY OF SUCH DAMAGE."
  },
  {
    "path": "LICENSES/BSD-3-Clause",
    "content": "Valid-License-Identifier: BSD-3-Clause\nSPDX-URL: https://spdx.org/licenses/BSD-3-Clause.html\nUsage-Guide:\n  To use the BSD 3-clause \"New\" or \"Revised\" License put the following SPDX\n  tag/value pair into a comment according to the placement guidelines in\n  the licensing rules documentation:\n    SPDX-License-Identifier: BSD-3-Clause\nLicense-Text:\n\nCopyright (c) <year> <owner> . All rights reserved.\n\nRedistribution and use in source and binary forms, with or without\nmodification, are permitted provided that the following conditions are met:\n\n1. Redistributions of source code must retain the above copyright notice,\n   this list of conditions and the following disclaimer.\n\n2. Redistributions in binary form must reproduce the above copyright\n   notice, this list of conditions and the following disclaimer in the\n   documentation and/or other materials provided with the distribution.\n\n3. Neither the name of the copyright holder nor the names of its\n   contributors may be used to endorse or promote products derived from this\n   software without specific prior written permission.\n\nTHIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \"AS IS\"\nAND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\nIMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\nARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE\nLIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR\nCONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF\nSUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS\nINTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN\nCONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\nARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE\nPOSSIBILITY OF SUCH DAMAGE."
  },
  {
    "path": "LICENSES/CC-BY-SA-4.0",
    "content": "Valid-License-Identifier: CC-BY-SA-4.0\nSPDX-URL: https://spdx.org/licenses/CC-BY-SA-4.0\nUsage-Guide:\n  Do NOT use this license for code, but it's acceptable for content like artwork\n  or documentation. When using it for the latter, it's best to use it together\n  GPL-3.0-or-later license using \"OR\".\n  To use the Creative Commons Attribution-ShareAlike 4.0 International license\n  put the following SPDX tag/value pair into a comment according to the\n  placement guidelines in the licensing rules documentation:\n    SPDX-License-Identifier: CC-BY-SA-4.0\nLicense-Text:\n\nCreative Commons Attribution-ShareAlike 4.0 International\n\n=======================================================================\n\nCreative Commons Corporation (\"Creative Commons\") is not a law firm and\ndoes not provide legal services or legal advice. Distribution of\nCreative Commons public licenses does not create a lawyer-client or\nother relationship. Creative Commons makes its licenses and related\ninformation available on an \"as-is\" basis. Creative Commons gives no\nwarranties regarding its licenses, any material licensed under their\nterms and conditions, or any related information. Creative Commons\ndisclaims all liability for damages resulting from their use to the\nfullest extent possible.\n\nUsing Creative Commons Public Licenses\n\nCreative Commons public licenses provide a standard set of terms and\nconditions that creators and other rights holders may use to share\noriginal works of authorship and other material subject to copyright\nand certain other rights specified in the public license below. The\nfollowing considerations are for informational purposes only, are not\nexhaustive, and do not form part of our licenses.\n\n     Considerations for licensors: Our public licenses are\n     intended for use by those authorized to give the public\n     permission to use material in ways otherwise restricted by\n     copyright and certain other rights. Our licenses are\n     irrevocable. Licensors should read and understand the terms\n     and conditions of the license they choose before applying it.\n     Licensors should also secure all rights necessary before\n     applying our licenses so that the public can reuse the\n     material as expected. Licensors should clearly mark any\n     material not subject to the license. This includes other CC-\n     licensed material, or material used under an exception or\n     limitation to copyright. More considerations for licensors:\n\twiki.creativecommons.org/Considerations_for_licensors\n\n     Considerations for the public: By using one of our public\n     licenses, a licensor grants the public permission to use the\n     licensed material under specified terms and conditions. If\n     the licensor's permission is not necessary for any reason--for\n     example, because of any applicable exception or limitation to\n     copyright--then that use is not regulated by the license. Our\n     licenses grant only permissions under copyright and certain\n     other rights that a licensor has authority to grant. Use of\n     the licensed material may still be restricted for other\n     reasons, including because others have copyright or other\n     rights in the material. A licensor may make special requests,\n     such as asking that all changes be marked or described.\n     Although not required by our licenses, you are encouraged to\n     respect those requests where reasonable. More_considerations\n     for the public:\n\twiki.creativecommons.org/Considerations_for_licensees\n\n=======================================================================\n\nCreative Commons Attribution-ShareAlike 4.0 International Public\nLicense\n\nBy exercising the Licensed Rights (defined below), You accept and agree\nto be bound by the terms and conditions of this Creative Commons\nAttribution-ShareAlike 4.0 International Public License (\"Public\nLicense\"). To the extent this Public License may be interpreted as a\ncontract, You are granted the Licensed Rights in consideration of Your\nacceptance of these terms and conditions, and the Licensor grants You\nsuch rights in consideration of benefits the Licensor receives from\nmaking the Licensed Material available under these terms and\nconditions.\n\n\nSection 1 -- Definitions.\n\n  a. Adapted Material means material subject to Copyright and Similar\n     Rights that is derived from or based upon the Licensed Material\n     and in which the Licensed Material is translated, altered,\n     arranged, transformed, or otherwise modified in a manner requiring\n     permission under the Copyright and Similar Rights held by the\n     Licensor. For purposes of this Public License, where the Licensed\n     Material is a musical work, performance, or sound recording,\n     Adapted Material is always produced where the Licensed Material is\n     synched in timed relation with a moving image.\n\n  b. Adapter's License means the license You apply to Your Copyright\n     and Similar Rights in Your contributions to Adapted Material in\n     accordance with the terms and conditions of this Public License.\n\n  c. BY-SA Compatible License means a license listed at\n     creativecommons.org/compatiblelicenses, approved by Creative\n     Commons as essentially the equivalent of this Public License.\n\n  d. Copyright and Similar Rights means copyright and/or similar rights\n     closely related to copyright including, without limitation,\n     performance, broadcast, sound recording, and Sui Generis Database\n     Rights, without regard to how the rights are labeled or\n     categorized. For purposes of this Public License, the rights\n     specified in Section 2(b)(1)-(2) are not Copyright and Similar\n     Rights.\n\n  e. Effective Technological Measures means those measures that, in the\n     absence of proper authority, may not be circumvented under laws\n     fulfilling obligations under Article 11 of the WIPO Copyright\n     Treaty adopted on December 20, 1996, and/or similar international\n     agreements.\n\n  f. Exceptions and Limitations means fair use, fair dealing, and/or\n     any other exception or limitation to Copyright and Similar Rights\n     that applies to Your use of the Licensed Material.\n\n  g. License Elements means the license attributes listed in the name\n     of a Creative Commons Public License. The License Elements of this\n     Public License are Attribution and ShareAlike.\n\n  h. Licensed Material means the artistic or literary work, database,\n     or other material to which the Licensor applied this Public\n     License.\n\n  i. Licensed Rights means the rights granted to You subject to the\n     terms and conditions of this Public License, which are limited to\n     all Copyright and Similar Rights that apply to Your use of the\n     Licensed Material and that the Licensor has authority to license.\n\n  j. Licensor means the individual(s) or entity(ies) granting rights\n     under this Public License.\n\n  k. Share means to provide material to the public by any means or\n     process that requires permission under the Licensed Rights, such\n     as reproduction, public display, public performance, distribution,\n     dissemination, communication, or importation, and to make material\n     available to the public including in ways that members of the\n     public may access the material from a place and at a time\n     individually chosen by them.\n\n  l. Sui Generis Database Rights means rights other than copyright\n     resulting from Directive 96/9/EC of the European Parliament and of\n     the Council of 11 March 1996 on the legal protection of databases,\n     as amended and/or succeeded, as well as other essentially\n     equivalent rights anywhere in the world.\n\n  m. You means the individual or entity exercising the Licensed Rights\n     under this Public License. Your has a corresponding meaning.\n\n\nSection 2 -- Scope.\n\n  a. License grant.\n\n       1. Subject to the terms and conditions of this Public License,\n          the Licensor hereby grants You a worldwide, royalty-free,\n          non-sublicensable, non-exclusive, irrevocable license to\n          exercise the Licensed Rights in the Licensed Material to:\n\n            a. reproduce and Share the Licensed Material, in whole or\n               in part; and\n\n            b. produce, reproduce, and Share Adapted Material.\n\n       2. Exceptions and Limitations. For the avoidance of doubt, where\n          Exceptions and Limitations apply to Your use, this Public\n          License does not apply, and You do not need to comply with\n          its terms and conditions.\n\n       3. Term. The term of this Public License is specified in Section\n          6(a).\n\n       4. Media and formats; technical modifications allowed. The\n          Licensor authorizes You to exercise the Licensed Rights in\n          all media and formats whether now known or hereafter created,\n          and to make technical modifications necessary to do so. The\n          Licensor waives and/or agrees not to assert any right or\n          authority to forbid You from making technical modifications\n          necessary to exercise the Licensed Rights, including\n          technical modifications necessary to circumvent Effective\n          Technological Measures. For purposes of this Public License,\n          simply making modifications authorized by this Section 2(a)\n          (4) never produces Adapted Material.\n\n       5. Downstream recipients.\n\n            a. Offer from the Licensor -- Licensed Material. Every\n               recipient of the Licensed Material automatically\n               receives an offer from the Licensor to exercise the\n               Licensed Rights under the terms and conditions of this\n               Public License.\n\n            b. Additional offer from the Licensor -- Adapted Material.\n               Every recipient of Adapted Material from You\n               automatically receives an offer from the Licensor to\n               exercise the Licensed Rights in the Adapted Material\n               under the conditions of the Adapter's License You apply.\n\n            c. No downstream restrictions. You may not offer or impose\n               any additional or different terms or conditions on, or\n               apply any Effective Technological Measures to, the\n               Licensed Material if doing so restricts exercise of the\n               Licensed Rights by any recipient of the Licensed\n               Material.\n\n       6. No endorsement. Nothing in this Public License constitutes or\n          may be construed as permission to assert or imply that You\n          are, or that Your use of the Licensed Material is, connected\n          with, or sponsored, endorsed, or granted official status by,\n          the Licensor or others designated to receive attribution as\n          provided in Section 3(a)(1)(A)(i).\n\n  b. Other rights.\n\n       1. Moral rights, such as the right of integrity, are not\n          licensed under this Public License, nor are publicity,\n          privacy, and/or other similar personality rights; however, to\n          the extent possible, the Licensor waives and/or agrees not to\n          assert any such rights held by the Licensor to the limited\n          extent necessary to allow You to exercise the Licensed\n          Rights, but not otherwise.\n\n       2. Patent and trademark rights are not licensed under this\n          Public License.\n\n       3. To the extent possible, the Licensor waives any right to\n          collect royalties from You for the exercise of the Licensed\n          Rights, whether directly or through a collecting society\n          under any voluntary or waivable statutory or compulsory\n          licensing scheme. In all other cases the Licensor expressly\n          reserves any right to collect such royalties.\n\n\nSection 3 -- License Conditions.\n\nYour exercise of the Licensed Rights is expressly made subject to the\nfollowing conditions.\n\n  a. Attribution.\n\n       1. If You Share the Licensed Material (including in modified\n          form), You must:\n\n            a. retain the following if it is supplied by the Licensor\n               with the Licensed Material:\n\n                 i. identification of the creator(s) of the Licensed\n                    Material and any others designated to receive\n                    attribution, in any reasonable manner requested by\n                    the Licensor (including by pseudonym if\n                    designated);\n\n                ii. a copyright notice;\n\n               iii. a notice that refers to this Public License;\n\n                iv. a notice that refers to the disclaimer of\n                    warranties;\n\n                 v. a URI or hyperlink to the Licensed Material to the\n                    extent reasonably practicable;\n\n            b. indicate if You modified the Licensed Material and\n               retain an indication of any previous modifications; and\n\n            c. indicate the Licensed Material is licensed under this\n               Public License, and include the text of, or the URI or\n               hyperlink to, this Public License.\n\n       2. You may satisfy the conditions in Section 3(a)(1) in any\n          reasonable manner based on the medium, means, and context in\n          which You Share the Licensed Material. For example, it may be\n          reasonable to satisfy the conditions by providing a URI or\n          hyperlink to a resource that includes the required\n          information.\n\n       3. If requested by the Licensor, You must remove any of the\n          information required by Section 3(a)(1)(A) to the extent\n          reasonably practicable.\n\n  b. ShareAlike.\n\n     In addition to the conditions in Section 3(a), if You Share\n     Adapted Material You produce, the following conditions also apply.\n\n       1. The Adapter's License You apply must be a Creative Commons\n          license with the same License Elements, this version or\n          later, or a BY-SA Compatible License.\n\n       2. You must include the text of, or the URI or hyperlink to, the\n          Adapter's License You apply. You may satisfy this condition\n          in any reasonable manner based on the medium, means, and\n          context in which You Share Adapted Material.\n\n       3. You may not offer or impose any additional or different terms\n          or conditions on, or apply any Effective Technological\n          Measures to, Adapted Material that restrict exercise of the\n          rights granted under the Adapter's License You apply.\n\n\nSection 4 -- Sui Generis Database Rights.\n\nWhere the Licensed Rights include Sui Generis Database Rights that\napply to Your use of the Licensed Material:\n\n  a. for the avoidance of doubt, Section 2(a)(1) grants You the right\n     to extract, reuse, reproduce, and Share all or a substantial\n     portion of the contents of the database;\n\n  b. if You include all or a substantial portion of the database\n     contents in a database in which You have Sui Generis Database\n     Rights, then the database in which You have Sui Generis Database\n     Rights (but not its individual contents) is Adapted Material,\n\n     including for purposes of Section 3(b); and\n  c. You must comply with the conditions in Section 3(a) if You Share\n     all or a substantial portion of the contents of the database.\n\nFor the avoidance of doubt, this Section 4 supplements and does not\nreplace Your obligations under this Public License where the Licensed\nRights include other Copyright and Similar Rights.\n\n\nSection 5 -- Disclaimer of Warranties and Limitation of Liability.\n\n  a. UNLESS OTHERWISE SEPARATELY UNDERTAKEN BY THE LICENSOR, TO THE\n     EXTENT POSSIBLE, THE LICENSOR OFFERS THE LICENSED MATERIAL AS-IS\n     AND AS-AVAILABLE, AND MAKES NO REPRESENTATIONS OR WARRANTIES OF\n     ANY KIND CONCERNING THE LICENSED MATERIAL, WHETHER EXPRESS,\n     IMPLIED, STATUTORY, OR OTHER. THIS INCLUDES, WITHOUT LIMITATION,\n     WARRANTIES OF TITLE, MERCHANTABILITY, FITNESS FOR A PARTICULAR\n     PURPOSE, NON-INFRINGEMENT, ABSENCE OF LATENT OR OTHER DEFECTS,\n     ACCURACY, OR THE PRESENCE OR ABSENCE OF ERRORS, WHETHER OR NOT\n     KNOWN OR DISCOVERABLE. WHERE DISCLAIMERS OF WARRANTIES ARE NOT\n     ALLOWED IN FULL OR IN PART, THIS DISCLAIMER MAY NOT APPLY TO YOU.\n\n  b. TO THE EXTENT POSSIBLE, IN NO EVENT WILL THE LICENSOR BE LIABLE\n     TO YOU ON ANY LEGAL THEORY (INCLUDING, WITHOUT LIMITATION,\n     NEGLIGENCE) OR OTHERWISE FOR ANY DIRECT, SPECIAL, INDIRECT,\n     INCIDENTAL, CONSEQUENTIAL, PUNITIVE, EXEMPLARY, OR OTHER LOSSES,\n     COSTS, EXPENSES, OR DAMAGES ARISING OUT OF THIS PUBLIC LICENSE OR\n     USE OF THE LICENSED MATERIAL, EVEN IF THE LICENSOR HAS BEEN\n     ADVISED OF THE POSSIBILITY OF SUCH LOSSES, COSTS, EXPENSES, OR\n     DAMAGES. WHERE A LIMITATION OF LIABILITY IS NOT ALLOWED IN FULL OR\n     IN PART, THIS LIMITATION MAY NOT APPLY TO YOU.\n\n  c. The disclaimer of warranties and limitation of liability provided\n     above shall be interpreted in a manner that, to the extent\n     possible, most closely approximates an absolute disclaimer and\n     waiver of all liability.\n\n\nSection 6 -- Term and Termination.\n\n  a. This Public License applies for the term of the Copyright and\n     Similar Rights licensed here. However, if You fail to comply with\n     this Public License, then Your rights under this Public License\n     terminate automatically.\n\n  b. Where Your right to use the Licensed Material has terminated under\n     Section 6(a), it reinstates:\n\n       1. automatically as of the date the violation is cured, provided\n          it is cured within 30 days of Your discovery of the\n          violation; or\n\n       2. upon express reinstatement by the Licensor.\n\n     For the avoidance of doubt, this Section 6(b) does not affect any\n     right the Licensor may have to seek remedies for Your violations\n     of this Public License.\n\n  c. For the avoidance of doubt, the Licensor may also offer the\n     Licensed Material under separate terms or conditions or stop\n     distributing the Licensed Material at any time; however, doing so\n     will not terminate this Public License.\n\n  d. Sections 1, 5, 6, 7, and 8 survive termination of this Public\n     License.\n\n\nSection 7 -- Other Terms and Conditions.\n\n  a. The Licensor shall not be bound by any additional or different\n     terms or conditions communicated by You unless expressly agreed.\n\n  b. Any arrangements, understandings, or agreements regarding the\n     Licensed Material not stated herein are separate from and\n     independent of the terms and conditions of this Public License.\n\n\nSection 8 -- Interpretation.\n\n  a. For the avoidance of doubt, this Public License does not, and\n     shall not be interpreted to, reduce, limit, restrict, or impose\n     conditions on any use of the Licensed Material that could lawfully\n     be made without permission under this Public License.\n\n  b. To the extent possible, if any provision of this Public License is\n     deemed unenforceable, it shall be automatically reformed to the\n     minimum extent necessary to make it enforceable. If the provision\n     cannot be reformed, it shall be severed from this Public License\n     without affecting the enforceability of the remaining terms and\n     conditions.\n\n  c. No term or condition of this Public License will be waived and no\n     failure to comply consented to unless expressly agreed to by the\n     Licensor.\n\n  d. Nothing in this Public License constitutes or may be interpreted\n     as a limitation upon, or waiver of, any privileges and immunities\n     that apply to the Licensor or You, including from the legal\n     processes of any jurisdiction or authority.\n\n\n=======================================================================\n\nCreative Commons is not a party to its public\nlicenses. Notwithstanding, Creative Commons may elect to apply one of\nits public licenses to material it publishes and in those instances\nwill be considered the “Licensor.” The text of the Creative Commons\npublic licenses is dedicated to the public domain under the CC0 Public\nDomain Dedication. Except for the limited purpose of indicating that\nmaterial is shared under a Creative Commons public license or as\notherwise permitted by the Creative Commons policies published at\ncreativecommons.org/policies, Creative Commons does not authorize the\nuse of the trademark \"Creative Commons\" or any other trademark or logo\nof Creative Commons without its prior written consent including,\nwithout limitation, in connection with any unauthorized modifications\nto any of its public licenses or any other arrangements,\nunderstandings, or agreements concerning use of licensed material. For\nthe avoidance of doubt, this paragraph does not form part of the\npublic licenses.\n\nCreative Commons may be contacted at creativecommons.org.\n"
  },
  {
    "path": "LICENSES/GPL-2.0",
    "content": "Valid-License-Identifier: GPL-2.0+\nValid-License-Identifier: GPL-2.0-or-later\nSPDX-URL: https://spdx.org/licenses/GPL-2.0-or-later.html\nUsage-Guide:\n  To use this license in source code, put one of the following SPDX\n  tag/value pairs into a comment according to the placement\n  guidelines in the licensing rules documentation.\n  For 'GNU General Public License (GPL) version 2 or any later version' use:\n    SPDX-License-Identifier: GPL-2.0+\n  or\n    SPDX-License-Identifier: GPL-2.0-or-later\nLicense-Text:\n\n\t\t    GNU GENERAL PUBLIC LICENSE\n\t\t       Version 2, June 1991\n\n Copyright (C) 1989, 1991 Free Software Foundation, Inc.\n                       51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n Everyone is permitted to copy and distribute verbatim copies\n of this license document, but changing it is not allowed.\n\n\t\t\t    Preamble\n\n  The licenses for most software are designed to take away your\nfreedom to share and change it.  By contrast, the GNU General Public\nLicense is intended to guarantee your freedom to share and change free\nsoftware--to make sure the software is free for all its users.  This\nGeneral Public License applies to most of the Free Software\nFoundation's software and to any other program whose authors commit to\nusing it.  (Some other Free Software Foundation software is covered by\nthe GNU Library General Public License instead.)  You can apply it to\nyour programs, too.\n\n  When we speak of free software, we are referring to freedom, not\nprice.  Our General Public Licenses are designed to make sure that you\nhave the freedom to distribute copies of free software (and charge for\nthis service if you wish), that you receive source code or can get it\nif you want it, that you can change the software or use pieces of it\nin new free programs; and that you know you can do these things.\n\n  To protect your rights, we need to make restrictions that forbid\nanyone to deny you these rights or to ask you to surrender the rights.\nThese restrictions translate to certain responsibilities for you if you\ndistribute copies of the software, or if you modify it.\n\n  For example, if you distribute copies of such a program, whether\ngratis or for a fee, you must give the recipients all the rights that\nyou have.  You must make sure that they, too, receive or can get the\nsource code.  And you must show them these terms so they know their\nrights.\n\n  We protect your rights with two steps: (1) copyright the software, and\n(2) offer you this license which gives you legal permission to copy,\ndistribute and/or modify the software.\n\n  Also, for each author's protection and ours, we want to make certain\nthat everyone understands that there is no warranty for this free\nsoftware.  If the software is modified by someone else and passed on, we\nwant its recipients to know that what they have is not the original, so\nthat any problems introduced by others will not reflect on the original\nauthors' reputations.\n\n  Finally, any free program is threatened constantly by software\npatents.  We wish to avoid the danger that redistributors of a free\nprogram will individually obtain patent licenses, in effect making the\nprogram proprietary.  To prevent this, we have made it clear that any\npatent must be licensed for everyone's free use or not licensed at all.\n\n  The precise terms and conditions for copying, distribution and\nmodification follow.\n\f\n\t\t    GNU GENERAL PUBLIC LICENSE\n   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION\n\n  0. This License applies to any program or other work which contains\na notice placed by the copyright holder saying it may be distributed\nunder the terms of this General Public License.  The \"Program\", below,\nrefers to any such program or work, and a \"work based on the Program\"\nmeans either the Program or any derivative work under copyright law:\nthat is to say, a work containing the Program or a portion of it,\neither verbatim or with modifications and/or translated into another\nlanguage.  (Hereinafter, translation is included without limitation in\nthe term \"modification\".)  Each licensee is addressed as \"you\".\n\nActivities other than copying, distribution and modification are not\ncovered by this License; they are outside its scope.  The act of\nrunning the Program is not restricted, and the output from the Program\nis covered only if its contents constitute a work based on the\nProgram (independent of having been made by running the Program).\nWhether that is true depends on what the Program does.\n\n  1. You may copy and distribute verbatim copies of the Program's\nsource code as you receive it, in any medium, provided that you\nconspicuously and appropriately publish on each copy an appropriate\ncopyright notice and disclaimer of warranty; keep intact all the\nnotices that refer to this License and to the absence of any warranty;\nand give any other recipients of the Program a copy of this License\nalong with the Program.\n\nYou may charge a fee for the physical act of transferring a copy, and\nyou may at your option offer warranty protection in exchange for a fee.\n\n  2. You may modify your copy or copies of the Program or any portion\nof it, thus forming a work based on the Program, and copy and\ndistribute such modifications or work under the terms of Section 1\nabove, provided that you also meet all of these conditions:\n\n    a) You must cause the modified files to carry prominent notices\n    stating that you changed the files and the date of any change.\n\n    b) You must cause any work that you distribute or publish, that in\n    whole or in part contains or is derived from the Program or any\n    part thereof, to be licensed as a whole at no charge to all third\n    parties under the terms of this License.\n\n    c) If the modified program normally reads commands interactively\n    when run, you must cause it, when started running for such\n    interactive use in the most ordinary way, to print or display an\n    announcement including an appropriate copyright notice and a\n    notice that there is no warranty (or else, saying that you provide\n    a warranty) and that users may redistribute the program under\n    these conditions, and telling the user how to view a copy of this\n    License.  (Exception: if the Program itself is interactive but\n    does not normally print such an announcement, your work based on\n    the Program is not required to print an announcement.)\n\f\nThese requirements apply to the modified work as a whole.  If\nidentifiable sections of that work are not derived from the Program,\nand can be reasonably considered independent and separate works in\nthemselves, then this License, and its terms, do not apply to those\nsections when you distribute them as separate works.  But when you\ndistribute the same sections as part of a whole which is a work based\non the Program, the distribution of the whole must be on the terms of\nthis License, whose permissions for other licensees extend to the\nentire whole, and thus to each and every part regardless of who wrote it.\n\nThus, it is not the intent of this section to claim rights or contest\nyour rights to work written entirely by you; rather, the intent is to\nexercise the right to control the distribution of derivative or\ncollective works based on the Program.\n\nIn addition, mere aggregation of another work not based on the Program\nwith the Program (or with a work based on the Program) on a volume of\na storage or distribution medium does not bring the other work under\nthe scope of this License.\n\n  3. You may copy and distribute the Program (or a work based on it,\nunder Section 2) in object code or executable form under the terms of\nSections 1 and 2 above provided that you also do one of the following:\n\n    a) Accompany it with the complete corresponding machine-readable\n    source code, which must be distributed under the terms of Sections\n    1 and 2 above on a medium customarily used for software interchange; or,\n\n    b) Accompany it with a written offer, valid for at least three\n    years, to give any third party, for a charge no more than your\n    cost of physically performing source distribution, a complete\n    machine-readable copy of the corresponding source code, to be\n    distributed under the terms of Sections 1 and 2 above on a medium\n    customarily used for software interchange; or,\n\n    c) Accompany it with the information you received as to the offer\n    to distribute corresponding source code.  (This alternative is\n    allowed only for noncommercial distribution and only if you\n    received the program in object code or executable form with such\n    an offer, in accord with Subsection b above.)\n\nThe source code for a work means the preferred form of the work for\nmaking modifications to it.  For an executable work, complete source\ncode means all the source code for all modules it contains, plus any\nassociated interface definition files, plus the scripts used to\ncontrol compilation and installation of the executable.  However, as a\nspecial exception, the source code distributed need not include\nanything that is normally distributed (in either source or binary\nform) with the major components (compiler, kernel, and so on) of the\noperating system on which the executable runs, unless that component\nitself accompanies the executable.\n\nIf distribution of executable or object code is made by offering\naccess to copy from a designated place, then offering equivalent\naccess to copy the source code from the same place counts as\ndistribution of the source code, even though third parties are not\ncompelled to copy the source along with the object code.\n\f\n  4. You may not copy, modify, sublicense, or distribute the Program\nexcept as expressly provided under this License.  Any attempt\notherwise to copy, modify, sublicense or distribute the Program is\nvoid, and will automatically terminate your rights under this License.\nHowever, parties who have received copies, or rights, from you under\nthis License will not have their licenses terminated so long as such\nparties remain in full compliance.\n\n  5. You are not required to accept this License, since you have not\nsigned it.  However, nothing else grants you permission to modify or\ndistribute the Program or its derivative works.  These actions are\nprohibited by law if you do not accept this License.  Therefore, by\nmodifying or distributing the Program (or any work based on the\nProgram), you indicate your acceptance of this License to do so, and\nall its terms and conditions for copying, distributing or modifying\nthe Program or works based on it.\n\n  6. Each time you redistribute the Program (or any work based on the\nProgram), the recipient automatically receives a license from the\noriginal licensor to copy, distribute or modify the Program subject to\nthese terms and conditions.  You may not impose any further\nrestrictions on the recipients' exercise of the rights granted herein.\nYou are not responsible for enforcing compliance by third parties to\nthis License.\n\n  7. If, as a consequence of a court judgment or allegation of patent\ninfringement or for any other reason (not limited to patent issues),\nconditions are imposed on you (whether by court order, agreement or\notherwise) that contradict the conditions of this License, they do not\nexcuse you from the conditions of this License.  If you cannot\ndistribute so as to satisfy simultaneously your obligations under this\nLicense and any other pertinent obligations, then as a consequence you\nmay not distribute the Program at all.  For example, if a patent\nlicense would not permit royalty-free redistribution of the Program by\nall those who receive copies directly or indirectly through you, then\nthe only way you could satisfy both it and this License would be to\nrefrain entirely from distribution of the Program.\n\nIf any portion of this section is held invalid or unenforceable under\nany particular circumstance, the balance of the section is intended to\napply and the section as a whole is intended to apply in other\ncircumstances.\n\nIt is not the purpose of this section to induce you to infringe any\npatents or other property right claims or to contest validity of any\nsuch claims; this section has the sole purpose of protecting the\nintegrity of the free software distribution system, which is\nimplemented by public license practices.  Many people have made\ngenerous contributions to the wide range of software distributed\nthrough that system in reliance on consistent application of that\nsystem; it is up to the author/donor to decide if he or she is willing\nto distribute software through any other system and a licensee cannot\nimpose that choice.\n\nThis section is intended to make thoroughly clear what is believed to\nbe a consequence of the rest of this License.\n\f\n  8. If the distribution and/or use of the Program is restricted in\ncertain countries either by patents or by copyrighted interfaces, the\noriginal copyright holder who places the Program under this License\nmay add an explicit geographical distribution limitation excluding\nthose countries, so that distribution is permitted only in or among\ncountries not thus excluded.  In such case, this License incorporates\nthe limitation as if written in the body of this License.\n\n  9. The Free Software Foundation may publish revised and/or new versions\nof the General Public License from time to time.  Such new versions will\nbe similar in spirit to the present version, but may differ in detail to\naddress new problems or concerns.\n\nEach version is given a distinguishing version number.  If the Program\nspecifies a version number of this License which applies to it and \"any\nlater version\", you have the option of following the terms and conditions\neither of that version or of any later version published by the Free\nSoftware Foundation.  If the Program does not specify a version number of\nthis License, you may choose any version ever published by the Free Software\nFoundation.\n\n  10. If you wish to incorporate parts of the Program into other free\nprograms whose distribution conditions are different, write to the author\nto ask for permission.  For software which is copyrighted by the Free\nSoftware Foundation, write to the Free Software Foundation; we sometimes\nmake exceptions for this.  Our decision will be guided by the two goals\nof preserving the free status of all derivatives of our free software and\nof promoting the sharing and reuse of software generally.\n\n\t\t\t    NO WARRANTY\n\n  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY\nFOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN\nOTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES\nPROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED\nOR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF\nMERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS\nTO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE\nPROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,\nREPAIR OR CORRECTION.\n\n  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\nWILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR\nREDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,\nINCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING\nOUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED\nTO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY\nYOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER\nPROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE\nPOSSIBILITY OF SUCH DAMAGES.\n\n\t\t     END OF TERMS AND CONDITIONS\n\f\n\t    How to Apply These Terms to Your New Programs\n\n  If you develop a new program, and you want it to be of the greatest\npossible use to the public, the best way to achieve this is to make it\nfree software which everyone can redistribute and change under these terms.\n\n  To do so, attach the following notices to the program.  It is safest\nto attach them to the start of each source file to most effectively\nconvey the exclusion of warranty; and each file should have at least\nthe \"copyright\" line and a pointer to where the full notice is found.\n\n    <one line to give the program's name and a brief idea of what it does.>\n    Copyright (C) <year>  <name of author>\n\n    This program is free software; you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation; either version 2 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License\n    along with this program; if not, write to the Free Software\n    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA\n\n\nAlso add information on how to contact you by electronic and paper mail.\n\nIf the program is interactive, make it output a short notice like this\nwhen it starts in an interactive mode:\n\n    Gnomovision version 69, Copyright (C) year name of author\n    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.\n    This is free software, and you are welcome to redistribute it\n    under certain conditions; type `show c' for details.\n\nThe hypothetical commands `show w' and `show c' should show the appropriate\nparts of the General Public License.  Of course, the commands you use may\nbe called something other than `show w' and `show c'; they could even be\nmouse-clicks or menu items--whatever suits your program.\n\nYou should also get your employer (if you work as a programmer) or your\nschool, if any, to sign a \"copyright disclaimer\" for the program, if\nnecessary.  Here is a sample; alter the names:\n\n  Yoyodyne, Inc., hereby disclaims all copyright interest in the program\n  `Gnomovision' (which makes passes at compilers) written by James Hacker.\n\n  <signature of Ty Coon>, 1 April 1989\n  Ty Coon, President of Vice\n\nThis General Public License does not permit incorporating your program into\nproprietary programs.  If your program is a subroutine library, you may\nconsider it more useful to permit linking proprietary applications with the\nlibrary.  If this is what you want to do, use the GNU Library General\nPublic License instead of this License."
  },
  {
    "path": "LICENSES/GPL-3.0",
    "content": "Valid-License-Identifier: GPL-3.0+\nValid-License-Identifier: GPL-3.0-or-later\nSPDX-URL: https://spdx.org/licenses/GPL-3.0-or-later.html\nUsage-Guide:\n  To use this license in source code, put one of the following SPDX\n  tag/value pairs into a comment according to the placement\n  guidelines in the licensing rules documentation.\n  For 'GNU General Public License (GPL) version 3 or any later version' use:\n    SPDX-License-Identifier: GPL-3.0+\n  or\n    SPDX-License-Identifier: GPL-3.0-or-later\nLicense-Text:\n\n                    GNU GENERAL PUBLIC LICENSE\n                       Version 3, 29 June 2007\n\n Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>\n Everyone is permitted to copy and distribute verbatim copies\n of this license document, but changing it is not allowed.\n\n                            Preamble\n\n  The GNU General Public License is a free, copyleft license for\nsoftware and other kinds of works.\n\n  The licenses for most software and other practical works are designed\nto take away your freedom to share and change the works.  By contrast,\nthe GNU General Public License is intended to guarantee your freedom to\nshare and change all versions of a program--to make sure it remains free\nsoftware for all its users.  We, the Free Software Foundation, use the\nGNU General Public License for most of our software; it applies also to\nany other work released this way by its authors.  You can apply it to\nyour programs, too.\n\n  When we speak of free software, we are referring to freedom, not\nprice.  Our General Public Licenses are designed to make sure that you\nhave the freedom to distribute copies of free software (and charge for\nthem if you wish), that you receive source code or can get it if you\nwant it, that you can change the software or use pieces of it in new\nfree programs, and that you know you can do these things.\n\n  To protect your rights, we need to prevent others from denying you\nthese rights or asking you to surrender the rights.  Therefore, you have\ncertain responsibilities if you distribute copies of the software, or if\nyou modify it: responsibilities to respect the freedom of others.\n\n  For example, if you distribute copies of such a program, whether\ngratis or for a fee, you must pass on to the recipients the same\nfreedoms that you received.  You must make sure that they, too, receive\nor can get the source code.  And you must show them these terms so they\nknow their rights.\n\n  Developers that use the GNU GPL protect your rights with two steps:\n(1) assert copyright on the software, and (2) offer you this License\ngiving you legal permission to copy, distribute and/or modify it.\n\n  For the developers' and authors' protection, the GPL clearly explains\nthat there is no warranty for this free software.  For both users' and\nauthors' sake, the GPL requires that modified versions be marked as\nchanged, so that their problems will not be attributed erroneously to\nauthors of previous versions.\n\n  Some devices are designed to deny users access to install or run\nmodified versions of the software inside them, although the manufacturer\ncan do so.  This is fundamentally incompatible with the aim of\nprotecting users' freedom to change the software.  The systematic\npattern of such abuse occurs in the area of products for individuals to\nuse, which is precisely where it is most unacceptable.  Therefore, we\nhave designed this version of the GPL to prohibit the practice for those\nproducts.  If such problems arise substantially in other domains, we\nstand ready to extend this provision to those domains in future versions\nof the GPL, as needed to protect the freedom of users.\n\n  Finally, every program is threatened constantly by software patents.\nStates should not allow patents to restrict development and use of\nsoftware on general-purpose computers, but in those that do, we wish to\navoid the special danger that patents applied to a free program could\nmake it effectively proprietary.  To prevent this, the GPL assures that\npatents cannot be used to render the program non-free.\n\n  The precise terms and conditions for copying, distribution and\nmodification follow.\n\n                       TERMS AND CONDITIONS\n\n  0. Definitions.\n\n  \"This License\" refers to version 3 of the GNU General Public License.\n\n  \"Copyright\" also means copyright-like laws that apply to other kinds of\nworks, such as semiconductor masks.\n\n  \"The Program\" refers to any copyrightable work licensed under this\nLicense.  Each licensee is addressed as \"you\".  \"Licensees\" and\n\"recipients\" may be individuals or organizations.\n\n  To \"modify\" a work means to copy from or adapt all or part of the work\nin a fashion requiring copyright permission, other than the making of an\nexact copy.  The resulting work is called a \"modified version\" of the\nearlier work or a work \"based on\" the earlier work.\n\n  A \"covered work\" means either the unmodified Program or a work based\non the Program.\n\n  To \"propagate\" a work means to do anything with it that, without\npermission, would make you directly or secondarily liable for\ninfringement under applicable copyright law, except executing it on a\ncomputer or modifying a private copy.  Propagation includes copying,\ndistribution (with or without modification), making available to the\npublic, and in some countries other activities as well.\n\n  To \"convey\" a work means any kind of propagation that enables other\nparties to make or receive copies.  Mere interaction with a user through\na computer network, with no transfer of a copy, is not conveying.\n\n  An interactive user interface displays \"Appropriate Legal Notices\"\nto the extent that it includes a convenient and prominently visible\nfeature that (1) displays an appropriate copyright notice, and (2)\ntells the user that there is no warranty for the work (except to the\nextent that warranties are provided), that licensees may convey the\nwork under this License, and how to view a copy of this License.  If\nthe interface presents a list of user commands or options, such as a\nmenu, a prominent item in the list meets this criterion.\n\n  1. Source Code.\n\n  The \"source code\" for a work means the preferred form of the work\nfor making modifications to it.  \"Object code\" means any non-source\nform of a work.\n\n  A \"Standard Interface\" means an interface that either is an official\nstandard defined by a recognized standards body, or, in the case of\ninterfaces specified for a particular programming language, one that\nis widely used among developers working in that language.\n\n  The \"System Libraries\" of an executable work include anything, other\nthan the work as a whole, that (a) is included in the normal form of\npackaging a Major Component, but which is not part of that Major\nComponent, and (b) serves only to enable use of the work with that\nMajor Component, or to implement a Standard Interface for which an\nimplementation is available to the public in source code form.  A\n\"Major Component\", in this context, means a major essential component\n(kernel, window system, and so on) of the specific operating system\n(if any) on which the executable work runs, or a compiler used to\nproduce the work, or an object code interpreter used to run it.\n\n  The \"Corresponding Source\" for a work in object code form means all\nthe source code needed to generate, install, and (for an executable\nwork) run the object code and to modify the work, including scripts to\ncontrol those activities.  However, it does not include the work's\nSystem Libraries, or general-purpose tools or generally available free\nprograms which are used unmodified in performing those activities but\nwhich are not part of the work.  For example, Corresponding Source\nincludes interface definition files associated with source files for\nthe work, and the source code for shared libraries and dynamically\nlinked subprograms that the work is specifically designed to require,\nsuch as by intimate data communication or control flow between those\nsubprograms and other parts of the work.\n\n  The Corresponding Source need not include anything that users\ncan regenerate automatically from other parts of the Corresponding\nSource.\n\n  The Corresponding Source for a work in source code form is that\nsame work.\n\n  2. Basic Permissions.\n\n  All rights granted under this License are granted for the term of\ncopyright on the Program, and are irrevocable provided the stated\nconditions are met.  This License explicitly affirms your unlimited\npermission to run the unmodified Program.  The output from running a\ncovered work is covered by this License only if the output, given its\ncontent, constitutes a covered work.  This License acknowledges your\nrights of fair use or other equivalent, as provided by copyright law.\n\n  You may make, run and propagate covered works that you do not\nconvey, without conditions so long as your license otherwise remains\nin force.  You may convey covered works to others for the sole purpose\nof having them make modifications exclusively for you, or provide you\nwith facilities for running those works, provided that you comply with\nthe terms of this License in conveying all material for which you do\nnot control copyright.  Those thus making or running the covered works\nfor you must do so exclusively on your behalf, under your direction\nand control, on terms that prohibit them from making any copies of\nyour copyrighted material outside their relationship with you.\n\n  Conveying under any other circumstances is permitted solely under\nthe conditions stated below.  Sublicensing is not allowed; section 10\nmakes it unnecessary.\n\n  3. Protecting Users' Legal Rights From Anti-Circumvention Law.\n\n  No covered work shall be deemed part of an effective technological\nmeasure under any applicable law fulfilling obligations under article\n11 of the WIPO copyright treaty adopted on 20 December 1996, or\nsimilar laws prohibiting or restricting circumvention of such\nmeasures.\n\n  When you convey a covered work, you waive any legal power to forbid\ncircumvention of technological measures to the extent such circumvention\nis effected by exercising rights under this License with respect to\nthe covered work, and you disclaim any intention to limit operation or\nmodification of the work as a means of enforcing, against the work's\nusers, your or third parties' legal rights to forbid circumvention of\ntechnological measures.\n\n  4. Conveying Verbatim Copies.\n\n  You may convey verbatim copies of the Program's source code as you\nreceive it, in any medium, provided that you conspicuously and\nappropriately publish on each copy an appropriate copyright notice;\nkeep intact all notices stating that this License and any\nnon-permissive terms added in accord with section 7 apply to the code;\nkeep intact all notices of the absence of any warranty; and give all\nrecipients a copy of this License along with the Program.\n\n  You may charge any price or no price for each copy that you convey,\nand you may offer support or warranty protection for a fee.\n\n  5. Conveying Modified Source Versions.\n\n  You may convey a work based on the Program, or the modifications to\nproduce it from the Program, in the form of source code under the\nterms of section 4, provided that you also meet all of these conditions:\n\n    a) The work must carry prominent notices stating that you modified\n    it, and giving a relevant date.\n\n    b) The work must carry prominent notices stating that it is\n    released under this License and any conditions added under section\n    7.  This requirement modifies the requirement in section 4 to\n    \"keep intact all notices\".\n\n    c) You must license the entire work, as a whole, under this\n    License to anyone who comes into possession of a copy.  This\n    License will therefore apply, along with any applicable section 7\n    additional terms, to the whole of the work, and all its parts,\n    regardless of how they are packaged.  This License gives no\n    permission to license the work in any other way, but it does not\n    invalidate such permission if you have separately received it.\n\n    d) If the work has interactive user interfaces, each must display\n    Appropriate Legal Notices; however, if the Program has interactive\n    interfaces that do not display Appropriate Legal Notices, your\n    work need not make them do so.\n\n  A compilation of a covered work with other separate and independent\nworks, which are not by their nature extensions of the covered work,\nand which are not combined with it such as to form a larger program,\nin or on a volume of a storage or distribution medium, is called an\n\"aggregate\" if the compilation and its resulting copyright are not\nused to limit the access or legal rights of the compilation's users\nbeyond what the individual works permit.  Inclusion of a covered work\nin an aggregate does not cause this License to apply to the other\nparts of the aggregate.\n\n  6. Conveying Non-Source Forms.\n\n  You may convey a covered work in object code form under the terms\nof sections 4 and 5, provided that you also convey the\nmachine-readable Corresponding Source under the terms of this License,\nin one of these ways:\n\n    a) Convey the object code in, or embodied in, a physical product\n    (including a physical distribution medium), accompanied by the\n    Corresponding Source fixed on a durable physical medium\n    customarily used for software interchange.\n\n    b) Convey the object code in, or embodied in, a physical product\n    (including a physical distribution medium), accompanied by a\n    written offer, valid for at least three years and valid for as\n    long as you offer spare parts or customer support for that product\n    model, to give anyone who possesses the object code either (1) a\n    copy of the Corresponding Source for all the software in the\n    product that is covered by this License, on a durable physical\n    medium customarily used for software interchange, for a price no\n    more than your reasonable cost of physically performing this\n    conveying of source, or (2) access to copy the\n    Corresponding Source from a network server at no charge.\n\n    c) Convey individual copies of the object code with a copy of the\n    written offer to provide the Corresponding Source.  This\n    alternative is allowed only occasionally and noncommercially, and\n    only if you received the object code with such an offer, in accord\n    with subsection 6b.\n\n    d) Convey the object code by offering access from a designated\n    place (gratis or for a charge), and offer equivalent access to the\n    Corresponding Source in the same way through the same place at no\n    further charge.  You need not require recipients to copy the\n    Corresponding Source along with the object code.  If the place to\n    copy the object code is a network server, the Corresponding Source\n    may be on a different server (operated by you or a third party)\n    that supports equivalent copying facilities, provided you maintain\n    clear directions next to the object code saying where to find the\n    Corresponding Source.  Regardless of what server hosts the\n    Corresponding Source, you remain obligated to ensure that it is\n    available for as long as needed to satisfy these requirements.\n\n    e) Convey the object code using peer-to-peer transmission, provided\n    you inform other peers where the object code and Corresponding\n    Source of the work are being offered to the general public at no\n    charge under subsection 6d.\n\n  A separable portion of the object code, whose source code is excluded\nfrom the Corresponding Source as a System Library, need not be\nincluded in conveying the object code work.\n\n  A \"User Product\" is either (1) a \"consumer product\", which means any\ntangible personal property which is normally used for personal, family,\nor household purposes, or (2) anything designed or sold for incorporation\ninto a dwelling.  In determining whether a product is a consumer product,\ndoubtful cases shall be resolved in favor of coverage.  For a particular\nproduct received by a particular user, \"normally used\" refers to a\ntypical or common use of that class of product, regardless of the status\nof the particular user or of the way in which the particular user\nactually uses, or expects or is expected to use, the product.  A product\nis a consumer product regardless of whether the product has substantial\ncommercial, industrial or non-consumer uses, unless such uses represent\nthe only significant mode of use of the product.\n\n  \"Installation Information\" for a User Product means any methods,\nprocedures, authorization keys, or other information required to install\nand execute modified versions of a covered work in that User Product from\na modified version of its Corresponding Source.  The information must\nsuffice to ensure that the continued functioning of the modified object\ncode is in no case prevented or interfered with solely because\nmodification has been made.\n\n  If you convey an object code work under this section in, or with, or\nspecifically for use in, a User Product, and the conveying occurs as\npart of a transaction in which the right of possession and use of the\nUser Product is transferred to the recipient in perpetuity or for a\nfixed term (regardless of how the transaction is characterized), the\nCorresponding Source conveyed under this section must be accompanied\nby the Installation Information.  But this requirement does not apply\nif neither you nor any third party retains the ability to install\nmodified object code on the User Product (for example, the work has\nbeen installed in ROM).\n\n  The requirement to provide Installation Information does not include a\nrequirement to continue to provide support service, warranty, or updates\nfor a work that has been modified or installed by the recipient, or for\nthe User Product in which it has been modified or installed.  Access to a\nnetwork may be denied when the modification itself materially and\nadversely affects the operation of the network or violates the rules and\nprotocols for communication across the network.\n\n  Corresponding Source conveyed, and Installation Information provided,\nin accord with this section must be in a format that is publicly\ndocumented (and with an implementation available to the public in\nsource code form), and must require no special password or key for\nunpacking, reading or copying.\n\n  7. Additional Terms.\n\n  \"Additional permissions\" are terms that supplement the terms of this\nLicense by making exceptions from one or more of its conditions.\nAdditional permissions that are applicable to the entire Program shall\nbe treated as though they were included in this License, to the extent\nthat they are valid under applicable law.  If additional permissions\napply only to part of the Program, that part may be used separately\nunder those permissions, but the entire Program remains governed by\nthis License without regard to the additional permissions.\n\n  When you convey a copy of a covered work, you may at your option\nremove any additional permissions from that copy, or from any part of\nit.  (Additional permissions may be written to require their own\nremoval in certain cases when you modify the work.)  You may place\nadditional permissions on material, added by you to a covered work,\nfor which you have or can give appropriate copyright permission.\n\n  Notwithstanding any other provision of this License, for material you\nadd to a covered work, you may (if authorized by the copyright holders of\nthat material) supplement the terms of this License with terms:\n\n    a) Disclaiming warranty or limiting liability differently from the\n    terms of sections 15 and 16 of this License; or\n\n    b) Requiring preservation of specified reasonable legal notices or\n    author attributions in that material or in the Appropriate Legal\n    Notices displayed by works containing it; or\n\n    c) Prohibiting misrepresentation of the origin of that material, or\n    requiring that modified versions of such material be marked in\n    reasonable ways as different from the original version; or\n\n    d) Limiting the use for publicity purposes of names of licensors or\n    authors of the material; or\n\n    e) Declining to grant rights under trademark law for use of some\n    trade names, trademarks, or service marks; or\n\n    f) Requiring indemnification of licensors and authors of that\n    material by anyone who conveys the material (or modified versions of\n    it) with contractual assumptions of liability to the recipient, for\n    any liability that these contractual assumptions directly impose on\n    those licensors and authors.\n\n  All other non-permissive additional terms are considered \"further\nrestrictions\" within the meaning of section 10.  If the Program as you\nreceived it, or any part of it, contains a notice stating that it is\ngoverned by this License along with a term that is a further\nrestriction, you may remove that term.  If a license document contains\na further restriction but permits relicensing or conveying under this\nLicense, you may add to a covered work material governed by the terms\nof that license document, provided that the further restriction does\nnot survive such relicensing or conveying.\n\n  If you add terms to a covered work in accord with this section, you\nmust place, in the relevant source files, a statement of the\nadditional terms that apply to those files, or a notice indicating\nwhere to find the applicable terms.\n\n  Additional terms, permissive or non-permissive, may be stated in the\nform of a separately written license, or stated as exceptions;\nthe above requirements apply either way.\n\n  8. Termination.\n\n  You may not propagate or modify a covered work except as expressly\nprovided under this License.  Any attempt otherwise to propagate or\nmodify it is void, and will automatically terminate your rights under\nthis License (including any patent licenses granted under the third\nparagraph of section 11).\n\n  However, if you cease all violation of this License, then your\nlicense from a particular copyright holder is reinstated (a)\nprovisionally, unless and until the copyright holder explicitly and\nfinally terminates your license, and (b) permanently, if the copyright\nholder fails to notify you of the violation by some reasonable means\nprior to 60 days after the cessation.\n\n  Moreover, your license from a particular copyright holder is\nreinstated permanently if the copyright holder notifies you of the\nviolation by some reasonable means, this is the first time you have\nreceived notice of violation of this License (for any work) from that\ncopyright holder, and you cure the violation prior to 30 days after\nyour receipt of the notice.\n\n  Termination of your rights under this section does not terminate the\nlicenses of parties who have received copies or rights from you under\nthis License.  If your rights have been terminated and not permanently\nreinstated, you do not qualify to receive new licenses for the same\nmaterial under section 10.\n\n  9. Acceptance Not Required for Having Copies.\n\n  You are not required to accept this License in order to receive or\nrun a copy of the Program.  Ancillary propagation of a covered work\noccurring solely as a consequence of using peer-to-peer transmission\nto receive a copy likewise does not require acceptance.  However,\nnothing other than this License grants you permission to propagate or\nmodify any covered work.  These actions infringe copyright if you do\nnot accept this License.  Therefore, by modifying or propagating a\ncovered work, you indicate your acceptance of this License to do so.\n\n  10. Automatic Licensing of Downstream Recipients.\n\n  Each time you convey a covered work, the recipient automatically\nreceives a license from the original licensors, to run, modify and\npropagate that work, subject to this License.  You are not responsible\nfor enforcing compliance by third parties with this License.\n\n  An \"entity transaction\" is a transaction transferring control of an\norganization, or substantially all assets of one, or subdividing an\norganization, or merging organizations.  If propagation of a covered\nwork results from an entity transaction, each party to that\ntransaction who receives a copy of the work also receives whatever\nlicenses to the work the party's predecessor in interest had or could\ngive under the previous paragraph, plus a right to possession of the\nCorresponding Source of the work from the predecessor in interest, if\nthe predecessor has it or can get it with reasonable efforts.\n\n  You may not impose any further restrictions on the exercise of the\nrights granted or affirmed under this License.  For example, you may\nnot impose a license fee, royalty, or other charge for exercise of\nrights granted under this License, and you may not initiate litigation\n(including a cross-claim or counterclaim in a lawsuit) alleging that\nany patent claim is infringed by making, using, selling, offering for\nsale, or importing the Program or any portion of it.\n\n  11. Patents.\n\n  A \"contributor\" is a copyright holder who authorizes use under this\nLicense of the Program or a work on which the Program is based.  The\nwork thus licensed is called the contributor's \"contributor version\".\n\n  A contributor's \"essential patent claims\" are all patent claims\nowned or controlled by the contributor, whether already acquired or\nhereafter acquired, that would be infringed by some manner, permitted\nby this License, of making, using, or selling its contributor version,\nbut do not include claims that would be infringed only as a\nconsequence of further modification of the contributor version.  For\npurposes of this definition, \"control\" includes the right to grant\npatent sublicenses in a manner consistent with the requirements of\nthis License.\n\n  Each contributor grants you a non-exclusive, worldwide, royalty-free\npatent license under the contributor's essential patent claims, to\nmake, use, sell, offer for sale, import and otherwise run, modify and\npropagate the contents of its contributor version.\n\n  In the following three paragraphs, a \"patent license\" is any express\nagreement or commitment, however denominated, not to enforce a patent\n(such as an express permission to practice a patent or covenant not to\nsue for patent infringement).  To \"grant\" such a patent license to a\nparty means to make such an agreement or commitment not to enforce a\npatent against the party.\n\n  If you convey a covered work, knowingly relying on a patent license,\nand the Corresponding Source of the work is not available for anyone\nto copy, free of charge and under the terms of this License, through a\npublicly available network server or other readily accessible means,\nthen you must either (1) cause the Corresponding Source to be so\navailable, or (2) arrange to deprive yourself of the benefit of the\npatent license for this particular work, or (3) arrange, in a manner\nconsistent with the requirements of this License, to extend the patent\nlicense to downstream recipients.  \"Knowingly relying\" means you have\nactual knowledge that, but for the patent license, your conveying the\ncovered work in a country, or your recipient's use of the covered work\nin a country, would infringe one or more identifiable patents in that\ncountry that you have reason to believe are valid.\n\n  If, pursuant to or in connection with a single transaction or\narrangement, you convey, or propagate by procuring conveyance of, a\ncovered work, and grant a patent license to some of the parties\nreceiving the covered work authorizing them to use, propagate, modify\nor convey a specific copy of the covered work, then the patent license\nyou grant is automatically extended to all recipients of the covered\nwork and works based on it.\n\n  A patent license is \"discriminatory\" if it does not include within\nthe scope of its coverage, prohibits the exercise of, or is\nconditioned on the non-exercise of one or more of the rights that are\nspecifically granted under this License.  You may not convey a covered\nwork if you are a party to an arrangement with a third party that is\nin the business of distributing software, under which you make payment\nto the third party based on the extent of your activity of conveying\nthe work, and under which the third party grants, to any of the\nparties who would receive the covered work from you, a discriminatory\npatent license (a) in connection with copies of the covered work\nconveyed by you (or copies made from those copies), or (b) primarily\nfor and in connection with specific products or compilations that\ncontain the covered work, unless you entered into that arrangement,\nor that patent license was granted, prior to 28 March 2007.\n\n  Nothing in this License shall be construed as excluding or limiting\nany implied license or other defenses to infringement that may\notherwise be available to you under applicable patent law.\n\n  12. No Surrender of Others' Freedom.\n\n  If conditions are imposed on you (whether by court order, agreement or\notherwise) that contradict the conditions of this License, they do not\nexcuse you from the conditions of this License.  If you cannot convey a\ncovered work so as to satisfy simultaneously your obligations under this\nLicense and any other pertinent obligations, then as a consequence you may\nnot convey it at all.  For example, if you agree to terms that obligate you\nto collect a royalty for further conveying from those to whom you convey\nthe Program, the only way you could satisfy both those terms and this\nLicense would be to refrain entirely from conveying the Program.\n\n  13. Use with the GNU Affero General Public License.\n\n  Notwithstanding any other provision of this License, you have\npermission to link or combine any covered work with a work licensed\nunder version 3 of the GNU Affero General Public License into a single\ncombined work, and to convey the resulting work.  The terms of this\nLicense will continue to apply to the part which is the covered work,\nbut the special requirements of the GNU Affero General Public License,\nsection 13, concerning interaction through a network will apply to the\ncombination as such.\n\n  14. Revised Versions of this License.\n\n  The Free Software Foundation may publish revised and/or new versions of\nthe GNU General Public License from time to time.  Such new versions will\nbe similar in spirit to the present version, but may differ in detail to\naddress new problems or concerns.\n\n  Each version is given a distinguishing version number.  If the\nProgram specifies that a certain numbered version of the GNU General\nPublic License \"or any later version\" applies to it, you have the\noption of following the terms and conditions either of that numbered\nversion or of any later version published by the Free Software\nFoundation.  If the Program does not specify a version number of the\nGNU General Public License, you may choose any version ever published\nby the Free Software Foundation.\n\n  If the Program specifies that a proxy can decide which future\nversions of the GNU General Public License can be used, that proxy's\npublic statement of acceptance of a version permanently authorizes you\nto choose that version for the Program.\n\n  Later license versions may give you additional or different\npermissions.  However, no additional obligations are imposed on any\nauthor or copyright holder as a result of your choosing to follow a\nlater version.\n\n  15. Disclaimer of Warranty.\n\n  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY\nAPPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT\nHOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY\nOF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,\nTHE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\nPURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM\nIS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF\nALL NECESSARY SERVICING, REPAIR OR CORRECTION.\n\n  16. Limitation of Liability.\n\n  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\nWILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS\nTHE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY\nGENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE\nUSE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF\nDATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD\nPARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),\nEVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF\nSUCH DAMAGES.\n\n  17. Interpretation of Sections 15 and 16.\n\n  If the disclaimer of warranty and limitation of liability provided\nabove cannot be given local legal effect according to their terms,\nreviewing courts shall apply local law that most closely approximates\nan absolute waiver of all civil liability in connection with the\nProgram, unless a warranty or assumption of liability accompanies a\ncopy of the Program in return for a fee.\n\n                     END OF TERMS AND CONDITIONS\n\n            How to Apply These Terms to Your New Programs\n\n  If you develop a new program, and you want it to be of the greatest\npossible use to the public, the best way to achieve this is to make it\nfree software which everyone can redistribute and change under these terms.\n\n  To do so, attach the following notices to the program.  It is safest\nto attach them to the start of each source file to most effectively\nstate the exclusion of warranty; and each file should have at least\nthe \"copyright\" line and a pointer to where the full notice is found.\n\n    <one line to give the program's name and a brief idea of what it does.>\n    Copyright (C) <year>  <name of author>\n\n    This program is free software: you can redistribute it and/or modify\n    it under the terms of the GNU General Public License as published by\n    the Free Software Foundation, either version 3 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU General Public License for more details.\n\n    You should have received a copy of the GNU General Public License\n    along with this program.  If not, see <https://www.gnu.org/licenses/>.\n\nAlso add information on how to contact you by electronic and paper mail.\n\n  If the program does terminal interaction, make it output a short\nnotice like this when it starts in an interactive mode:\n\n    <program>  Copyright (C) <year>  <name of author>\n    This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'.\n    This is free software, and you are welcome to redistribute it\n    under certain conditions; type `show c' for details.\n\nThe hypothetical commands `show w' and `show c' should show the appropriate\nparts of the General Public License.  Of course, your program's commands\nmight be different; for a GUI interface, you would use an \"about box\".\n\n  You should also get your employer (if you work as a programmer) or school,\nif any, to sign a \"copyright disclaimer\" for the program, if necessary.\nFor more information on this, and how to apply and follow the GNU GPL, see\n<https://www.gnu.org/licenses/>.\n\n  The GNU General Public License does not permit incorporating your program\ninto proprietary programs.  If your program is a subroutine library, you\nmay consider it more useful to permit linking proprietary applications with\nthe library.  If this is what you want to do, use the GNU Lesser General\nPublic License instead of this License.  But first, please read\n<https://www.gnu.org/licenses/why-not-lgpl.html>."
  },
  {
    "path": "LICENSES/ISC",
    "content": "Valid-License-Identifier: ISC\nSPDX-URL: https://spdx.org/licenses/ISC.html\nUsage-Guide:\n  To use the ISC License put the following SPDX tag/value pair into a\n  comment according to the placement guidelines in the licensing rules\n  documentation:\n    SPDX-License-Identifier: ISC\n  Do NOT use this license unless the files are copied from another work\n  under the same license. In such cases, use \"AND GPL-3.0-or-later\" so\n  that your contributions are under GPL-3.0+ license.\nLicense-Text:\n\nISC License\n\nCopyright (c) <year> <copyright holders>\n\nPermission to use, copy, modify, and/or distribute this software for any\npurpose with or without fee is hereby granted, provided that the above\ncopyright notice and this permission notice appear in all copies.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\" AND THE AUTHOR DISCLAIMS ALL WARRANTIES\nWITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF\nMERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY\nSPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES\nWHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION\nOF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN\nCONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE."
  },
  {
    "path": "LICENSES/MIT",
    "content": "Valid-License-Identifier: MIT\nSPDX-URL: https://spdx.org/licenses/MIT.html\nUsage-Guide:\n  To use the MIT License put the following SPDX tag/value pair into a\n  comment according to the placement guidelines in the licensing rules\n  documentation:\n    SPDX-License-Identifier: MIT\n  Do NOT use this license unless the files are copied from another work\n  under the same license. In such cases, use \"AND GPL-3.0-or-later\" so\n  that your contributions are under GPL-3.0+ license.\nLicense-Text:\n\nMIT License\n\nCopyright (c) <year> <copyright holders>\n\nPermission is hereby granted, free of charge, to any person obtaining a\ncopy of this software and associated documentation files (the \"Software\"),\nto deal in the Software without restriction, including without limitation\nthe rights to use, copy, modify, merge, publish, distribute, sublicense,\nand/or sell copies of the Software, and to permit persons to whom the\nSoftware is furnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in\nall copies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\nFROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER\nDEALINGS IN THE SOFTWARE."
  },
  {
    "path": "LICENSES/WTFPL",
    "content": "Valid-License-Identifier: WTFPL\nSPDX-URL: https://spdx.org/licenses/WTFPL.html\nUsage-Guide:\n  To use the WTFPL put the following SPDX tag/value pair into a\n  comment according to the placement guidelines in the licensing rules\n  documentation:\n    SPDX-License-Identifier: WTFPL\n  Do NOT use this license unless the files are copied from another work\n  under the same license. In such cases, use \"AND GPL-3.0-or-later\" so\n  that your contributions are under GPL-3.0+ license.\nLicense-Text:\n\n            DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE\n                    Version 2, December 2004\n\n Copyright (C) 2004 Sam Hocevar <sam@hocevar.net>\n\n Everyone is permitted to copy and distribute verbatim or modified\n copies of this license document, and changing it is allowed as long\n as the name is changed.\n\n            DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE\n   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION\n\n  0. You just DO WHAT THE FUCK YOU WANT TO.\n"
  },
  {
    "path": "PRIVACY_POLICY.rst",
    "content": ".. SPDX-License-Identifier: GPL-3.0-or-later OR CC-BY-SA-4.0\n\n==============\nPrivacy Policy\n==============\n(DRAFT REVISION NO. 3)\n\n1. Definition\n=============\n\n- \"The Project\" refers to the App Manager project which includes the git\n  repositories (excluding The Project Hosting Providers), E-Mails, and their\n  maintainers. (See §6)\n- \"We\", \"Us\", and similar capitalized pronouns refer to the maintainers of\n  The Project.\n- \"E-Mail\" or \"E-Mails\" refers to the messages sent directly to the maintainers\n  of The Project.\n- \"The Software\" refers to App Manager software distributed by its maintainers.\n- \"The Project Hosting Providers\" refers to GitHub, GitLab, Codeberg, RiseUp,\n  and SourceHut.\n- \"Third-party Services\" refers to The Project Hosting Providers along with\n  VirusTotal, Pithus, F-Droid, and Hosted Weblate.\n- \"Third-party Websites\" refers to websites We do not control or operate.\n- \"You\", \"Yours\", and similar capitalized pronouns refer to anyone who uses\n  The Software or has contributed to The Project in any capacity.\n- \"PII\" refers to personally identifiable information.\n\n2. Information Collected from You\n=================================\n\n2.1. The Project\n---------------\nWe DO NOT collect any information that You have not provided voluntarily.\nThe sources of this information include your contributions on Git and any\nE-Mails you send.  This information may include PII, such as Your real name\nand E-Mail address.  If You send crash reports and logs via E-Mail, they may\nalso contain non-PII details, such as Your device name, operating system\nversion, software version, language, and more.\n\nThe official website for The Project is located at\nhttps://muntashirakon.github.io/AppManager/ and is hosted by GitHub (see §2.3).\nWe do not collect any information from this website.\n\n2.2. The Software\n-----------------\nWe DO NOT collect any information from The Software.\n\n2.3. Third-party Services\n-------------------------\nDepending on the services used, the privacy policy of the following services\nwill apply to You:\n\n- `GitHub`_ (Stars, issues, pull requests, discussions, releases, traffic)\n- `GitLab`_ (Stars, merge requests, traffic)\n- `Codeberg`_ (Stars, issues, pull requests)\n- `RiseUp`_ (Stars, issues, merge requests)\n- `SourceHut`_ (Tickets)\n- `VirusTotal`_ (Malware reports, file uploads, traffic)\n- `F-Droid`_ (F-Droid official repository and app store)\n- `Hosted Weblate`_ (Translations).\n\n2.4. Third-party Websites\n-------------------------\nLinks to Third-party Websites are provided for your benefit.  For your safety,\nit is recommended that You read and understand the privacy policy of these\nwebsites before visiting them.\n\n3. Data Retention Policy\n========================\nInformation collected through Git is stored indefinitely and is accessible to\nanyone, anywhere.  E-Mails that do not have legal significance can be retained\nfor a maximum of one year.  These E-Mails are stored offline in a partition\nthat is encrypted using FileVault.  However, E-Mails deemed legally significant\ncan be kept permanently, both online and offline.  To understand the data\nretention policies of the Third-party Services (as specified in §2.3) and\nThird-party Websites (as outlined in §2.4), please refer to their respective\nprivacy policies.\n\n4. Removal of Information\n=========================\nYou can request the removal of PII by either sending Us an E-Mail or creating\nan issue.  You can also request the removal of non-PII, but please note that\nthe removal is not guaranteed.  In both cases, the following types of\ninformation cannot be removed by Us:\n\n- Information present in a commit message, such as the ``Signed-off-by:`` tag\n- Information contained in a file (since they are a part of git history)\n- Forked repositories (You need to ask the person who forked the repository)\n- Reactions to GitHub issues, comments, and discussions (You need to remove\n  them Yourself)\n- Information stored by the Third-party Services or Third-party Websites (You\n  need to ask them Yourself).\n\nThe following information may or may not be removed:\n\n- Mentions in a comment\n- E-Mails deemed legally significant.\n\n5. Changes to the Privacy Policy\n================================\nAll changes, except those related to spelling or grammar, will be announced on\nall the official channels.  Unless stated otherwise, the updated privacy policy\nwill apply only to The Software released after the changes.\n\n6. Project Maintainers\n======================\n1. **Name:** Muntashir Al-Islam\n\n   **Email:** muntashirakon [at] riseup [dot] net\n\n.. _GitHub: https://docs.github.com/en/site-policy/privacy-policies/github-privacy-statement\n.. _GitLab: https://about.gitlab.com/privacy/\n.. _Codeberg: https://codeberg.org/codeberg/org/src/PrivacyPolicy.md\n.. _RiseUp: https://riseup.net/en/privacy-policy\n.. _SourceHut: https://man.sr.ht/privacy.md\n.. _VirusTotal: https://support.virustotal.com/hc/en-us/articles/115002168385-Privacy-Policy\n.. _F-Droid: https://f-droid.org/en/about/#terms-etc\n.. _Hosted Weblate: https://hosted.weblate.org/legal/privacy/\n"
  },
  {
    "path": "README.md",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later OR CC-BY-SA-4.0 -->\n\n<p align=\"center\">\n  <img src=\"docs/raw/images/icon.png\" alt=\"App Manager Logo\" height=\"150dp\">\n</p>\n\n<h1 align=\"center\">App Manager</h1>\n\n<p align=center>\n  <a href=\"https://muntashirakon.github.io/AppManager\">Docs</a> ·\n  <a href=\"https://github.com/MuntashirAkon/AppManager/releases\">Releases</a> ·\n  <a href=\"https://t.me/AppManagerChannel\">Telegram Channel</a>\n</p>\n\n---\n\n## Features\n\n### General features\n- Fully reproducible, copylefted libre software (GPLv3+)\n- Material 3 with dynamic colours\n- Display as much information as possible in the main page\n- List activities, broadcast receivers, services, providers, app ops, permissions, signatures, shared libraries, etc. of an application\n- Launch activities and services\n- Create shortcuts of activities\n- [Intercept activities](https://muntashirakon.github.io/AppManager/#sec:interceptor-page)\n- Scan for trackers and libraries in apps and list (all or only) tracking classes (and their code dump)\n- View/save the manifest of an app\n- Display app usage, data usage (mobile and Wi-Fi), and app storage info (requires “Usage Access” permission)\n- Install/uninstall APK files (including APKS, APKM and XAPK with OBB files)\n- Share APK files\n- Back up/restore APK files\n- Batch operations\n- Single-click operations\n- Logcat viewer, manager and exporter\n- [Profiles](https://muntashirakon.github.io/AppManager/#sec:profiles-page)\n- Debloater\n- Code editor\n- File manager\n- Simple terminal emulator\n- Open an app in Aurora Store or in your favourite F-Droid client\n- Sign APK files with custom signatures before installing\n- Backup encryption: OpenPGP via OpenKeychain, RSA, ECC (hybrid encryption with AES) and AES.\n- Track foreground UI components\n\n### Root/ADB-only features\n\n- Revoke runtime (AKA dangerous) and development permissions\n- Change the mode of an app op\n- Display/kill/force-stop running apps or processes\n- Clear app data or app cache\n- View/change net policy\n- Control battery optimization\n- Freeze/unfreeze apps\n\n### Root-only features\n\n- Block any activities, broadcast receivers, services, or providers of an app with native import/export as well as Watt and Blocker import support\n- View/edit/delete shared preferences of any app\n- Back up/restore apps with data, rules and extras (such as permissions, battery optimization, SSAID, etc.)\n- View system configurations including blacklisted or whitelisted apps, permissions, etc.\n- View/change SSAID.\n\n…and many more! This single app combines the features of 5 or 6 apps any tech-savvy person needs!\n\n### Upcoming features\n- Finder: Find app components, permissions etc. in all apps\n- Basic APK editing\n- Routine operations\n- Enable/disable app actions such as launch on boot\n- Crash monitor\n- Systemless disabling/uninstalling of the system apps\n- Import app list exported by App Manager\n- More advance terminal emulator\n- Database viewer and editor, etc.\n\n[<img src=\"https://fdroid.gitlab.io/artwork/badge/get-it-on.png\"\nalt=\"Get it on F-Droid\"\nheight=\"80\" />](https://f-droid.org/packages/io.github.muntashirakon.AppManager)\n\n## Translations\n\nHelp translate [the app strings](https://hosted.weblate.org/engage/app-manager/) and\n[the docs](https://hosted.weblate.org/projects/app-manager/docs/) at Hosted Weblate.\n\n\n[![Translation status](https://hosted.weblate.org/widgets/app-manager/-/multi-auto.svg)](https://hosted.weblate.org/engage/app-manager/)\n\n\n## Mirrors\n\n[Codeberg](https://codeberg.org/muntashir/AppManager) ·\n[GitLab](https://gitlab.com/muntashir/AppManager) ·\n[Riseup](https://0xacab.org/muntashir/AppManager) ·\n[sourcehut](https://git.sr.ht/~muntashir/AppManager)\n\n## Screenshots\n\n<img src=\"fastlane/metadata/android/en-US/images/phoneScreenshots/1.png\" height=\"500dp\" /><img src=\"fastlane/metadata/android/en-US/images/phoneScreenshots/2.png\" height=\"500dp\" /><img src=\"fastlane/metadata/android/en-US/images/phoneScreenshots/3.png\" height=\"500dp\" /><img src=\"fastlane/metadata/android/en-US/images/phoneScreenshots/4.png\" height=\"500dp\" /><img src=\"fastlane/metadata/android/en-US/images/phoneScreenshots/5.png\" height=\"500dp\" /><img src=\"fastlane/metadata/android/en-US/images/phoneScreenshots/6.png\" height=\"500dp\" /><img src=\"fastlane/metadata/android/en-US/images/phoneScreenshots/7.png\" height=\"500dp\" /><img src=\"fastlane/metadata/android/en-US/images/phoneScreenshots/8.png\" height=\"500dp\" /><img src=\"fastlane/metadata/android/en-US/images/phoneScreenshots/9.png\" height=\"500dp\" />\n\n## Build Instructions\nSee [BUILDING.rst](BUILDING.rst)\n\n## Contributing\n\nSee [CONTRIBUTING.rst](CONTRIBUTING.rst)\n\n## Donation and Funding\n\nAs of September 2024, App Manager is not accepting any financial support until further notice. But\nyou may still be able to send gifts (e.g., gift cards, subscriptions, food and drink, flowers, or\neven cash). Please contact the maintainer at muntashirakon [at] riseup [dot] net for further\nassistance.\n\nIn addition, the maintainers and contributors of this project DO NOT consent to the creation, sale,\nor promotion of tokens, cryptocurrencies, NFTs, or any other financial instruments that claim to\nrepresent this project, its code, or its community. Any such attempts are unauthorized and not\naffiliated with this project in any way.\n\n## Credits and Libraries\n\nA list of credits and libraries are available in the **About** section of the app.\n"
  },
  {
    "path": "app/.gitignore",
    "content": "/build\n*.apk\n.cxx\n*~\n"
  },
  {
    "path": "app/build.gradle",
    "content": "// SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-or-later\n\nplugins {\n    id('com.android.application')\n    id('dev.rikka.tools.refine') version \"${refine_version}\"\n}\n\nandroid {\n    namespace 'io.github.muntashirakon.AppManager'\n    compileSdk compile_sdk\n    buildToolsVersion = build_tools\n\n    defaultConfig {\n        applicationId 'io.github.muntashirakon.AppManager'\n        minSdk min_sdk\n        targetSdk target_sdk\n        versionCode 445\n        versionName \"4.0.5\"\n        javaCompileOptions {\n            annotationProcessorOptions {\n                arguments += [\n                        \"room.schemaLocation\": \"$projectDir/schemas\".toString(),\n                        \"room.incremental\"   : \"true\"\n                ]\n            }\n        }\n        externalNativeBuild {\n            cmake {\n                arguments \"-DANDROID_SUPPORT_FLEXIBLE_PAGE_SIZES=ON\"\n            }\n        }\n        // Add build time to BuildConfig\n        buildConfigField \"long\", \"BUILD_TIME_MILLIS\", \"${buildTime()}\"\n    }\n\n    signingConfigs {\n        debug {\n            storeFile file('dev_keystore.jks')\n            storePassword 'kJCp!Bda#PBdN2RLK%yMK@hatq&69E'\n            keyPassword 'kJCp!Bda#PBdN2RLK%yMK@hatq&69E'\n            keyAlias 'key0'\n        }\n    }\n\n    buildTypes {\n        release {\n            minifyEnabled false\n            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'\n            resValue \"string\", \"app_name\", \"App Manager\"\n        }\n        debug {\n            applicationIdSuffix '.debug'\n            versionNameSuffix '-DEBUG'\n            signingConfig signingConfigs.debug\n            resValue \"string\", \"app_name\", \"AM Debug\"\n        }\n    }\n    lint {\n        checkReleaseBuilds false\n        abortOnError false\n        checkDependencies true\n    }\n    compileOptions {\n        encoding \"UTF-8\"\n        // Flag to enable support for the new language APIs\n        coreLibraryDesugaringEnabled true\n        sourceCompatibility JavaVersion.VERSION_1_8\n        targetCompatibility JavaVersion.VERSION_1_8\n    }\n    externalNativeBuild {\n        cmake {\n            path 'src/main/cpp/CMakeLists.txt'\n        }\n    }\n    splits {\n        abi {\n            reset()\n            include 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64'\n            universalApk true\n        }\n    }\n    aaptOptions {\n        noCompress 'jar', 'sh'\n    }\n    testOptions {\n        unitTests {\n            includeAndroidResources = true\n        }\n    }\n    sourceSets {\n        androidTest.assets.srcDirs += files(\"$projectDir/schemas\".toString())\n    }\n    dependenciesInfo {\n        includeInApk false\n        includeInBundle false\n    }\n    packagingOptions {\n        jniLibs {\n            useLegacyPackaging true\n        }\n        resources {\n            excludes += ['META-INF/*.version']\n            merges += ['baksmali.properties']\n        }\n    }\n    buildFeatures {\n        aidl true\n        buildConfig true\n    }\n}\n\ndependencies {\n    compileOnly project(path: ':hiddenapi')\n    coreLibraryDesugaring \"com.android.tools:desugar_jdk_libs:${desugar_jdk_version}\"\n\n    // Core Libraries\n    implementation project(path: ':libcore:compat')\n    implementation project(path: ':libcore:io')\n    implementation project(path: ':libcore:ui')\n    implementation project(path: ':libserver')\n    implementation project(path: ':docs')\n\n    // API\n    implementation \"com.github.MuntashirAkon:unapkm-android:${unapkm_version}\"\n    implementation project(path: ':libopenpgp')\n\n    // APK Editing\n    implementation \"com.github.REAndroid:ARSCLib:${arsclib_version}\"\n    implementation \"com.github.MuntashirAkon:apksig-android:${apksig_version}\"\n    implementation \"com.github.MuntashirAkon:sun-security-android:${sun_security_version}\"\n    implementation \"org.bouncycastle:bcprov-jdk15to18:${bouncycastle_version}\"\n    implementation \"org.bouncycastle:bcpkix-jdk15to18:${bouncycastle_version}\"\n    implementation \"com.android.tools.smali:smali-baksmali:${baksmali_version}\"\n    implementation \"com.android.tools.smali:smali:${baksmali_version}\"\n    implementation \"com.github.MuntashirAkon.jadx:jadx-core:${jadx_version}\"\n    // Replace SLF4J with a placeholder\n    configurations {\n        configureEach {\n            exclude group: 'org.slf4j', module: 'slf4j-api'\n        }\n    }\n    implementation \"com.github.MuntashirAkon.jadx:jadx-dex-input:${jadx_version}\"\n    // Replace SLF4J with a placeholder\n    configurations {\n        configureEach {\n            exclude group: 'org.slf4j', module: 'slf4j-api'\n        }\n    }\n\n    // DB\n    implementation \"androidx.room:room-runtime:${room_version}\"\n    annotationProcessor \"androidx.room:room-compiler:${room_version}\"\n\n    // FM\n    implementation \"com.j256.simplemagic:simplemagic:${simplemagic_version}\"\n\n    // Privileged\n    implementation \"com.github.MuntashirAkon:libadb-android:${libadb_version}\"\n    implementation \"com.github.topjohnwu.libsu:core:${libsu_version}\"\n    implementation \"org.lsposed.hiddenapibypass:hiddenapibypass:${hiddenapibypass_version}\"\n    implementation \"dev.rikka.tools.refine:runtime:${refine_version}\"\n\n    // UI\n    implementation \"com.google.android.material:material:${material_version}\"\n    implementation \"androidx.core:core:${androidx_core_version}\"\n    implementation \"androidx.appcompat:appcompat:${appcompat_version}\"\n    // Fix duplicate classes issue in material\n    configurations {\n        configureEach {\n            exclude group: 'androidx.lifecycle', module: 'lifecycle-viewmodel-ktx'\n        }\n    }\n    implementation \"androidx.documentfile:documentfile:${documentfile_version}\"\n    implementation \"androidx.activity:activity:${activity_version}\"\n    implementation \"androidx.core:core-splashscreen:${splashscreen_version}\"\n    implementation \"androidx.biometric:biometric:${biometric_version}\"\n    implementation \"androidx.webkit:webkit:${webkit_version}\"\n    implementation \"io.github.Rosemoe.sora-editor:editor:${sora_editor_version}\"\n    implementation \"io.github.Rosemoe.sora-editor:language-textmate:${sora_editor_version}\"\n    implementation \"com.github.MuntashirAkon:time-duration-picker:${duration_picker}\"\n\n    // Utility\n    implementation \"com.google.code.gson:gson:${gson_version}\"\n    implementation \"com.github.luben:zstd-jni:${zstd_version}@aar\"\n\n//    debugImplementation 'com.squareup.leakcanary:leakcanary-android:2.9.1'\n\n    // Espresso UI Testing\n//    androidTestImplementation \"com.android.support.test.espresso:espresso-core:3.0.2\"\n    // Optional if you need to detect intents.\n//    androidTestImplementation \"com.android.support.test.espresso:espresso-intents:3.0.2\"\n\n    // Unit Testing\n    testImplementation \"junit:junit:${junit_version}\"\n    testImplementation \"org.robolectric:robolectric:${robolectric_version}\"\n}\n\npreBuild.dependsOn \":server:build\"\n\ndef buildTime() {\n    var commitTime = \"git show --no-patch --format=%ct000\".execute([], project.rootDir).text.trim()\n    if (isDigitsOnly(commitTime)) {\n        return Long.parseLong(commitTime)\n    }\n    println(\"Using system time as the build time.\")\n    return System.currentTimeMillis()\n}\n\nstatic def isDigitsOnly(CharSequence str) {\n    final int len = str.length()\n    for (int cp, i = 0; i < len; i += Character.charCount(cp)) {\n        cp = Character.codePointAt(str, i)\n        if (!Character.isDigit(cp)) {\n            return false\n        }\n    }\n    return true\n}\n"
  },
  {
    "path": "app/lint.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<lint>\n    <issue id=\"MissingTranslation\" severity=\"ignore\" />\n    <issue id=\"ImpliedQuantity\" severity=\"ignore\" />\n    <issue id=\"WakelockTimeout\" severity=\"ignore\" />\n\n    <issue id=\"LogConditional\" severity=\"informational\" />\n    <issue id=\"Registered\" severity=\"informational\" />\n    <issue id=\"UnknownNullness\" severity=\"informational\" />\n\n    <issue id=\"DuplicateStrings\" severity=\"warning\" />\n    <!-- In some cases, the linter produces wrong results for WrongConstant -->\n    <issue id=\"WrongConstant\" severity=\"warning\" />\n    <issue id=\"WrongThreadInterprocedural\" severity=\"warning\" />\n\n    <issue id=\"HardcodedText\" severity=\"error\" />\n</lint>\n"
  },
  {
    "path": "app/proguard-rules.pro",
    "content": "# Specify compression level\n-optimizationpasses 5\n# Algorithm for confusion\n-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*\n# Allow access to and modification of classes and class members with modifiers during optimization\n-allowaccessmodification\n# Rename file source to \"Sourcefile\" string\n-renamesourcefileattribute SourceFile\n# Keep line number\n-keepattributes SourceFile,LineNumberTable\n# Keep generics\n-keepattributes Signature\n# Keep all class members that implement the serializable interface\n-keepclassmembers class * implements java.io.Serializable {\n    static final long serialVersionUID;\n    private static final java.io.ObjectStreamField[] serialPersistentFields;\n    private void writeObject(java.io.ObjectOutputStream);\n    private void readObject(java.io.ObjectInputStream);\n    java.lang.Object writeReplace();\n    java.lang.Object readResolve();\n}\n# Keep all class members that implement the percelable interface\n-keepclassmembers class * implements android.os.Parcelable {\n    public static final ** CREATOR;\n    public int describeContents();\n    public void writeToParcel(android.os.Parcel, int);\n}\n# Keep preference fragments\n-keep public class * extends androidx.preference.PreferenceFragmentCompat {}\n# Keep XmlPullParsers FIXME: Otherwise abstract method exception would occur\n-keep public class * extends org.xmlpull.v1.XmlPullParser { *; }\n-keep public class * extends org.xmlpull.v1.XmlSerializer { *; }\n# Don't minify server-related classes FIXME\n-keep public class io.github.muntashirakon.AppManager.servermanager.** { *; }\n-keep public class io.github.muntashirakon.AppManager.server.** { *; }\n-keep public class io.github.muntashirakon.AppManager.ipc.** { *; }\n# Don't minify debug-sepcific resource file\n-keep public class io.github.muntashirakon.AppManager.debug.R$raw {*;}\n# Don't minify OpenPGP API\n-keep public class org.openintents.openpgp.IOpenPgpService { *; }\n-keep public class org.openintents.openpgp.IOpenPgpService2 { *; }\n# Don't minify Spake2 library\n-keep public class io.github.muntashirakon.crypto.spake2.** { *; }\n# Don't minify AOSP private APIs\n-keep class android.** { *; }\n-keep class com.android.** { *; }\n-keep class libcore.util.** { *; }\n-keep class org.xmlpull.v1.** { *; }\n"
  },
  {
    "path": "app/schemas/io.github.muntashirakon.AppManager.db.AppsDb/1.json",
    "content": "{\n  \"formatVersion\": 1,\n  \"database\": {\n    \"version\": 1,\n    \"identityHash\": \"d363fa70deeafe04c0457034f211df42\",\n    \"entities\": [\n      {\n        \"tableName\": \"app\",\n        \"createSql\": \"CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`package_name` TEXT NOT NULL, `user_id` INTEGER NOT NULL DEFAULT -10000, `label` TEXT, `version_name` TEXT, `version_code` INTEGER NOT NULL, `flags` INTEGER NOT NULL DEFAULT 0, `uid` INTEGER NOT NULL DEFAULT 0, `shared_uid` TEXT DEFAULT NULL, `first_install_time` INTEGER NOT NULL DEFAULT 0, `last_update_time` INTEGER NOT NULL DEFAULT 0, `target_sdk` INTEGER NOT NULL DEFAULT 0, `cert_name` TEXT DEFAULT '', `cert_algo` TEXT DEFAULT '', `is_installed` INTEGER NOT NULL DEFAULT true, `is_enabled` INTEGER NOT NULL DEFAULT false, `has_activities` INTEGER NOT NULL DEFAULT false, `has_splits` INTEGER NOT NULL DEFAULT false, `rules_count` INTEGER NOT NULL DEFAULT 0, `tracker_count` INTEGER NOT NULL DEFAULT 0, `last_action_time` INTEGER NOT NULL DEFAULT 0, PRIMARY KEY(`package_name`, `user_id`))\",\n        \"fields\": [\n          {\n            \"fieldPath\": \"packageName\",\n            \"columnName\": \"package_name\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"userId\",\n            \"columnName\": \"user_id\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"-10000\"\n          },\n          {\n            \"fieldPath\": \"packageLabel\",\n            \"columnName\": \"label\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": false\n          },\n          {\n            \"fieldPath\": \"versionName\",\n            \"columnName\": \"version_name\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": false\n          },\n          {\n            \"fieldPath\": \"versionCode\",\n            \"columnName\": \"version_code\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"flags\",\n            \"columnName\": \"flags\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"0\"\n          },\n          {\n            \"fieldPath\": \"uid\",\n            \"columnName\": \"uid\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"0\"\n          },\n          {\n            \"fieldPath\": \"sharedUserId\",\n            \"columnName\": \"shared_uid\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": false,\n            \"defaultValue\": \"NULL\"\n          },\n          {\n            \"fieldPath\": \"firstInstallTime\",\n            \"columnName\": \"first_install_time\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"0\"\n          },\n          {\n            \"fieldPath\": \"lastUpdateTime\",\n            \"columnName\": \"last_update_time\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"0\"\n          },\n          {\n            \"fieldPath\": \"sdk\",\n            \"columnName\": \"target_sdk\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"0\"\n          },\n          {\n            \"fieldPath\": \"certName\",\n            \"columnName\": \"cert_name\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": false,\n            \"defaultValue\": \"''\"\n          },\n          {\n            \"fieldPath\": \"certAlgo\",\n            \"columnName\": \"cert_algo\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": false,\n            \"defaultValue\": \"''\"\n          },\n          {\n            \"fieldPath\": \"isInstalled\",\n            \"columnName\": \"is_installed\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"true\"\n          },\n          {\n            \"fieldPath\": \"isEnabled\",\n            \"columnName\": \"is_enabled\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"false\"\n          },\n          {\n            \"fieldPath\": \"hasActivities\",\n            \"columnName\": \"has_activities\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"false\"\n          },\n          {\n            \"fieldPath\": \"hasSplits\",\n            \"columnName\": \"has_splits\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"false\"\n          },\n          {\n            \"fieldPath\": \"rulesCount\",\n            \"columnName\": \"rules_count\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"0\"\n          },\n          {\n            \"fieldPath\": \"trackerCount\",\n            \"columnName\": \"tracker_count\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"0\"\n          },\n          {\n            \"fieldPath\": \"lastActionTime\",\n            \"columnName\": \"last_action_time\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"0\"\n          }\n        ],\n        \"primaryKey\": {\n          \"columnNames\": [\n            \"package_name\",\n            \"user_id\"\n          ],\n          \"autoGenerate\": false\n        },\n        \"indices\": [],\n        \"foreignKeys\": []\n      },\n      {\n        \"tableName\": \"log_filter\",\n        \"createSql\": \"CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `name` TEXT)\",\n        \"fields\": [\n          {\n            \"fieldPath\": \"id\",\n            \"columnName\": \"id\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"name\",\n            \"columnName\": \"name\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": false\n          }\n        ],\n        \"primaryKey\": {\n          \"columnNames\": [\n            \"id\"\n          ],\n          \"autoGenerate\": true\n        },\n        \"indices\": [\n          {\n            \"name\": \"index_name\",\n            \"unique\": true,\n            \"columnNames\": [\n              \"name\"\n            ],\n            \"orders\": [],\n            \"createSql\": \"CREATE UNIQUE INDEX IF NOT EXISTS `index_name` ON `${TABLE_NAME}` (`name`)\"\n          }\n        ],\n        \"foreignKeys\": []\n      },\n      {\n        \"tableName\": \"file_hash\",\n        \"createSql\": \"CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`path` TEXT NOT NULL, `hash` TEXT, PRIMARY KEY(`path`))\",\n        \"fields\": [\n          {\n            \"fieldPath\": \"path\",\n            \"columnName\": \"path\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"hash\",\n            \"columnName\": \"hash\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": false\n          }\n        ],\n        \"primaryKey\": {\n          \"columnNames\": [\n            \"path\"\n          ],\n          \"autoGenerate\": false\n        },\n        \"indices\": [],\n        \"foreignKeys\": []\n      },\n      {\n        \"tableName\": \"backup\",\n        \"createSql\": \"CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`package_name` TEXT NOT NULL, `backup_name` TEXT NOT NULL, `label` TEXT, `version_name` TEXT, `version_code` INTEGER NOT NULL, `is_system` INTEGER NOT NULL, `has_splits` INTEGER NOT NULL, `has_rules` INTEGER NOT NULL, `backup_time` INTEGER NOT NULL, `crypto` TEXT, `meta_version` INTEGER NOT NULL, `flags` INTEGER NOT NULL, `user_id` INTEGER NOT NULL, `tar_type` TEXT, `has_key_store` INTEGER NOT NULL, `installer_app` TEXT, `info_hash` TEXT, PRIMARY KEY(`backup_name`, `package_name`))\",\n        \"fields\": [\n          {\n            \"fieldPath\": \"packageName\",\n            \"columnName\": \"package_name\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"backupName\",\n            \"columnName\": \"backup_name\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"label\",\n            \"columnName\": \"label\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": false\n          },\n          {\n            \"fieldPath\": \"versionName\",\n            \"columnName\": \"version_name\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": false\n          },\n          {\n            \"fieldPath\": \"versionCode\",\n            \"columnName\": \"version_code\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"isSystem\",\n            \"columnName\": \"is_system\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"hasSplits\",\n            \"columnName\": \"has_splits\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"hasRules\",\n            \"columnName\": \"has_rules\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"backupTime\",\n            \"columnName\": \"backup_time\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"crypto\",\n            \"columnName\": \"crypto\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": false\n          },\n          {\n            \"fieldPath\": \"version\",\n            \"columnName\": \"meta_version\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"flags\",\n            \"columnName\": \"flags\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"userId\",\n            \"columnName\": \"user_id\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"tarType\",\n            \"columnName\": \"tar_type\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": false\n          },\n          {\n            \"fieldPath\": \"hasKeyStore\",\n            \"columnName\": \"has_key_store\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"installer\",\n            \"columnName\": \"installer_app\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": false\n          },\n          {\n            \"fieldPath\": \"hash\",\n            \"columnName\": \"info_hash\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": false\n          }\n        ],\n        \"primaryKey\": {\n          \"columnNames\": [\n            \"backup_name\",\n            \"package_name\"\n          ],\n          \"autoGenerate\": false\n        },\n        \"indices\": [],\n        \"foreignKeys\": []\n      }\n    ],\n    \"views\": [],\n    \"setupQueries\": [\n      \"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)\",\n      \"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'd363fa70deeafe04c0457034f211df42')\"\n    ]\n  }\n}"
  },
  {
    "path": "app/schemas/io.github.muntashirakon.AppManager.db.AppsDb/2.json",
    "content": "{\n  \"formatVersion\": 1,\n  \"database\": {\n    \"version\": 2,\n    \"identityHash\": \"175f99951d829b88618a0e192ef9bedb\",\n    \"entities\": [\n      {\n        \"tableName\": \"app\",\n        \"createSql\": \"CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`package_name` TEXT NOT NULL, `user_id` INTEGER NOT NULL DEFAULT -10000, `label` TEXT, `version_name` TEXT, `version_code` INTEGER NOT NULL, `flags` INTEGER NOT NULL DEFAULT 0, `uid` INTEGER NOT NULL DEFAULT 0, `shared_uid` TEXT DEFAULT NULL, `first_install_time` INTEGER NOT NULL DEFAULT 0, `last_update_time` INTEGER NOT NULL DEFAULT 0, `target_sdk` INTEGER NOT NULL DEFAULT 0, `cert_name` TEXT DEFAULT '', `cert_algo` TEXT DEFAULT '', `is_installed` INTEGER NOT NULL DEFAULT true, `is_enabled` INTEGER NOT NULL DEFAULT false, `has_activities` INTEGER NOT NULL DEFAULT false, `has_splits` INTEGER NOT NULL DEFAULT false, `has_keystore` INTEGER NOT NULL DEFAULT false, `uses_saf` INTEGER NOT NULL DEFAULT false, `ssaid` TEXT DEFAULT '', `code_size` INTEGER NOT NULL DEFAULT 0, `data_size` INTEGER NOT NULL DEFAULT 0, `mobile_data` INTEGER NOT NULL DEFAULT 0, `wifi_data` INTEGER NOT NULL DEFAULT 0, `rules_count` INTEGER NOT NULL DEFAULT 0, `tracker_count` INTEGER NOT NULL DEFAULT 0, `open_count` INTEGER NOT NULL DEFAULT 0, `screen_time` INTEGER NOT NULL DEFAULT 0, `last_usage_time` INTEGER NOT NULL DEFAULT 0, `last_action_time` INTEGER NOT NULL DEFAULT 0, PRIMARY KEY(`package_name`, `user_id`))\",\n        \"fields\": [\n          {\n            \"fieldPath\": \"packageName\",\n            \"columnName\": \"package_name\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"userId\",\n            \"columnName\": \"user_id\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"-10000\"\n          },\n          {\n            \"fieldPath\": \"packageLabel\",\n            \"columnName\": \"label\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": false\n          },\n          {\n            \"fieldPath\": \"versionName\",\n            \"columnName\": \"version_name\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": false\n          },\n          {\n            \"fieldPath\": \"versionCode\",\n            \"columnName\": \"version_code\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"flags\",\n            \"columnName\": \"flags\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"0\"\n          },\n          {\n            \"fieldPath\": \"uid\",\n            \"columnName\": \"uid\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"0\"\n          },\n          {\n            \"fieldPath\": \"sharedUserId\",\n            \"columnName\": \"shared_uid\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": false,\n            \"defaultValue\": \"NULL\"\n          },\n          {\n            \"fieldPath\": \"firstInstallTime\",\n            \"columnName\": \"first_install_time\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"0\"\n          },\n          {\n            \"fieldPath\": \"lastUpdateTime\",\n            \"columnName\": \"last_update_time\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"0\"\n          },\n          {\n            \"fieldPath\": \"sdk\",\n            \"columnName\": \"target_sdk\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"0\"\n          },\n          {\n            \"fieldPath\": \"certName\",\n            \"columnName\": \"cert_name\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": false,\n            \"defaultValue\": \"''\"\n          },\n          {\n            \"fieldPath\": \"certAlgo\",\n            \"columnName\": \"cert_algo\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": false,\n            \"defaultValue\": \"''\"\n          },\n          {\n            \"fieldPath\": \"isInstalled\",\n            \"columnName\": \"is_installed\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"true\"\n          },\n          {\n            \"fieldPath\": \"isEnabled\",\n            \"columnName\": \"is_enabled\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"false\"\n          },\n          {\n            \"fieldPath\": \"hasActivities\",\n            \"columnName\": \"has_activities\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"false\"\n          },\n          {\n            \"fieldPath\": \"hasSplits\",\n            \"columnName\": \"has_splits\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"false\"\n          },\n          {\n            \"fieldPath\": \"hasKeystore\",\n            \"columnName\": \"has_keystore\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"false\"\n          },\n          {\n            \"fieldPath\": \"usesSaf\",\n            \"columnName\": \"uses_saf\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"false\"\n          },\n          {\n            \"fieldPath\": \"ssaid\",\n            \"columnName\": \"ssaid\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": false,\n            \"defaultValue\": \"''\"\n          },\n          {\n            \"fieldPath\": \"codeSize\",\n            \"columnName\": \"code_size\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"0\"\n          },\n          {\n            \"fieldPath\": \"dataSize\",\n            \"columnName\": \"data_size\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"0\"\n          },\n          {\n            \"fieldPath\": \"mobileDataUsage\",\n            \"columnName\": \"mobile_data\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"0\"\n          },\n          {\n            \"fieldPath\": \"wifiDataUsage\",\n            \"columnName\": \"wifi_data\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"0\"\n          },\n          {\n            \"fieldPath\": \"rulesCount\",\n            \"columnName\": \"rules_count\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"0\"\n          },\n          {\n            \"fieldPath\": \"trackerCount\",\n            \"columnName\": \"tracker_count\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"0\"\n          },\n          {\n            \"fieldPath\": \"openCount\",\n            \"columnName\": \"open_count\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"0\"\n          },\n          {\n            \"fieldPath\": \"screenTime\",\n            \"columnName\": \"screen_time\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"0\"\n          },\n          {\n            \"fieldPath\": \"lastUsageTime\",\n            \"columnName\": \"last_usage_time\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"0\"\n          },\n          {\n            \"fieldPath\": \"lastActionTime\",\n            \"columnName\": \"last_action_time\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"0\"\n          }\n        ],\n        \"primaryKey\": {\n          \"columnNames\": [\n            \"package_name\",\n            \"user_id\"\n          ],\n          \"autoGenerate\": false\n        },\n        \"indices\": [],\n        \"foreignKeys\": []\n      },\n      {\n        \"tableName\": \"log_filter\",\n        \"createSql\": \"CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `name` TEXT)\",\n        \"fields\": [\n          {\n            \"fieldPath\": \"id\",\n            \"columnName\": \"id\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"name\",\n            \"columnName\": \"name\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": false\n          }\n        ],\n        \"primaryKey\": {\n          \"columnNames\": [\n            \"id\"\n          ],\n          \"autoGenerate\": true\n        },\n        \"indices\": [\n          {\n            \"name\": \"index_name\",\n            \"unique\": true,\n            \"columnNames\": [\n              \"name\"\n            ],\n            \"orders\": [],\n            \"createSql\": \"CREATE UNIQUE INDEX IF NOT EXISTS `index_name` ON `${TABLE_NAME}` (`name`)\"\n          }\n        ],\n        \"foreignKeys\": []\n      },\n      {\n        \"tableName\": \"file_hash\",\n        \"createSql\": \"CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`path` TEXT NOT NULL, `hash` TEXT, PRIMARY KEY(`path`))\",\n        \"fields\": [\n          {\n            \"fieldPath\": \"path\",\n            \"columnName\": \"path\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"hash\",\n            \"columnName\": \"hash\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": false\n          }\n        ],\n        \"primaryKey\": {\n          \"columnNames\": [\n            \"path\"\n          ],\n          \"autoGenerate\": false\n        },\n        \"indices\": [],\n        \"foreignKeys\": []\n      },\n      {\n        \"tableName\": \"backup\",\n        \"createSql\": \"CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`package_name` TEXT NOT NULL, `backup_name` TEXT NOT NULL, `label` TEXT, `version_name` TEXT, `version_code` INTEGER NOT NULL, `is_system` INTEGER NOT NULL, `has_splits` INTEGER NOT NULL, `has_rules` INTEGER NOT NULL, `backup_time` INTEGER NOT NULL, `crypto` TEXT, `meta_version` INTEGER NOT NULL, `flags` INTEGER NOT NULL, `user_id` INTEGER NOT NULL, `tar_type` TEXT, `has_key_store` INTEGER NOT NULL, `installer_app` TEXT, `info_hash` TEXT, PRIMARY KEY(`backup_name`, `package_name`))\",\n        \"fields\": [\n          {\n            \"fieldPath\": \"packageName\",\n            \"columnName\": \"package_name\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"backupName\",\n            \"columnName\": \"backup_name\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"label\",\n            \"columnName\": \"label\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": false\n          },\n          {\n            \"fieldPath\": \"versionName\",\n            \"columnName\": \"version_name\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": false\n          },\n          {\n            \"fieldPath\": \"versionCode\",\n            \"columnName\": \"version_code\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"isSystem\",\n            \"columnName\": \"is_system\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"hasSplits\",\n            \"columnName\": \"has_splits\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"hasRules\",\n            \"columnName\": \"has_rules\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"backupTime\",\n            \"columnName\": \"backup_time\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"crypto\",\n            \"columnName\": \"crypto\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": false\n          },\n          {\n            \"fieldPath\": \"version\",\n            \"columnName\": \"meta_version\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"flags\",\n            \"columnName\": \"flags\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"userId\",\n            \"columnName\": \"user_id\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"tarType\",\n            \"columnName\": \"tar_type\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": false\n          },\n          {\n            \"fieldPath\": \"hasKeyStore\",\n            \"columnName\": \"has_key_store\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"installer\",\n            \"columnName\": \"installer_app\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": false\n          },\n          {\n            \"fieldPath\": \"hash\",\n            \"columnName\": \"info_hash\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": false\n          }\n        ],\n        \"primaryKey\": {\n          \"columnNames\": [\n            \"backup_name\",\n            \"package_name\"\n          ],\n          \"autoGenerate\": false\n        },\n        \"indices\": [],\n        \"foreignKeys\": []\n      }\n    ],\n    \"views\": [],\n    \"setupQueries\": [\n      \"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)\",\n      \"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '175f99951d829b88618a0e192ef9bedb')\"\n    ]\n  }\n}"
  },
  {
    "path": "app/schemas/io.github.muntashirakon.AppManager.db.AppsDb/3.json",
    "content": "{\n  \"formatVersion\": 1,\n  \"database\": {\n    \"version\": 3,\n    \"identityHash\": \"ac92def333f7b8a38eb1ceab89033e99\",\n    \"entities\": [\n      {\n        \"tableName\": \"app\",\n        \"createSql\": \"CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`package_name` TEXT NOT NULL, `user_id` INTEGER NOT NULL DEFAULT -10000, `label` TEXT, `version_name` TEXT, `version_code` INTEGER NOT NULL, `flags` INTEGER NOT NULL DEFAULT 0, `uid` INTEGER NOT NULL DEFAULT 0, `shared_uid` TEXT DEFAULT NULL, `first_install_time` INTEGER NOT NULL DEFAULT 0, `last_update_time` INTEGER NOT NULL DEFAULT 0, `target_sdk` INTEGER NOT NULL DEFAULT 0, `cert_name` TEXT DEFAULT '', `cert_algo` TEXT DEFAULT '', `is_installed` INTEGER NOT NULL DEFAULT true, `is_enabled` INTEGER NOT NULL DEFAULT false, `has_activities` INTEGER NOT NULL DEFAULT false, `has_splits` INTEGER NOT NULL DEFAULT false, `has_keystore` INTEGER NOT NULL DEFAULT false, `uses_saf` INTEGER NOT NULL DEFAULT false, `ssaid` TEXT DEFAULT '', `code_size` INTEGER NOT NULL DEFAULT 0, `data_size` INTEGER NOT NULL DEFAULT 0, `mobile_data` INTEGER NOT NULL DEFAULT 0, `wifi_data` INTEGER NOT NULL DEFAULT 0, `rules_count` INTEGER NOT NULL DEFAULT 0, `tracker_count` INTEGER NOT NULL DEFAULT 0, `open_count` INTEGER NOT NULL DEFAULT 0, `screen_time` INTEGER NOT NULL DEFAULT 0, `last_usage_time` INTEGER NOT NULL DEFAULT 0, `last_action_time` INTEGER NOT NULL DEFAULT 0, PRIMARY KEY(`package_name`, `user_id`))\",\n        \"fields\": [\n          {\n            \"fieldPath\": \"packageName\",\n            \"columnName\": \"package_name\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"userId\",\n            \"columnName\": \"user_id\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"-10000\"\n          },\n          {\n            \"fieldPath\": \"packageLabel\",\n            \"columnName\": \"label\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": false\n          },\n          {\n            \"fieldPath\": \"versionName\",\n            \"columnName\": \"version_name\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": false\n          },\n          {\n            \"fieldPath\": \"versionCode\",\n            \"columnName\": \"version_code\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"flags\",\n            \"columnName\": \"flags\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"0\"\n          },\n          {\n            \"fieldPath\": \"uid\",\n            \"columnName\": \"uid\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"0\"\n          },\n          {\n            \"fieldPath\": \"sharedUserId\",\n            \"columnName\": \"shared_uid\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": false,\n            \"defaultValue\": \"NULL\"\n          },\n          {\n            \"fieldPath\": \"firstInstallTime\",\n            \"columnName\": \"first_install_time\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"0\"\n          },\n          {\n            \"fieldPath\": \"lastUpdateTime\",\n            \"columnName\": \"last_update_time\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"0\"\n          },\n          {\n            \"fieldPath\": \"sdk\",\n            \"columnName\": \"target_sdk\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"0\"\n          },\n          {\n            \"fieldPath\": \"certName\",\n            \"columnName\": \"cert_name\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": false,\n            \"defaultValue\": \"''\"\n          },\n          {\n            \"fieldPath\": \"certAlgo\",\n            \"columnName\": \"cert_algo\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": false,\n            \"defaultValue\": \"''\"\n          },\n          {\n            \"fieldPath\": \"isInstalled\",\n            \"columnName\": \"is_installed\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"true\"\n          },\n          {\n            \"fieldPath\": \"isEnabled\",\n            \"columnName\": \"is_enabled\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"false\"\n          },\n          {\n            \"fieldPath\": \"hasActivities\",\n            \"columnName\": \"has_activities\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"false\"\n          },\n          {\n            \"fieldPath\": \"hasSplits\",\n            \"columnName\": \"has_splits\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"false\"\n          },\n          {\n            \"fieldPath\": \"hasKeystore\",\n            \"columnName\": \"has_keystore\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"false\"\n          },\n          {\n            \"fieldPath\": \"usesSaf\",\n            \"columnName\": \"uses_saf\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"false\"\n          },\n          {\n            \"fieldPath\": \"ssaid\",\n            \"columnName\": \"ssaid\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": false,\n            \"defaultValue\": \"''\"\n          },\n          {\n            \"fieldPath\": \"codeSize\",\n            \"columnName\": \"code_size\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"0\"\n          },\n          {\n            \"fieldPath\": \"dataSize\",\n            \"columnName\": \"data_size\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"0\"\n          },\n          {\n            \"fieldPath\": \"mobileDataUsage\",\n            \"columnName\": \"mobile_data\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"0\"\n          },\n          {\n            \"fieldPath\": \"wifiDataUsage\",\n            \"columnName\": \"wifi_data\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"0\"\n          },\n          {\n            \"fieldPath\": \"rulesCount\",\n            \"columnName\": \"rules_count\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"0\"\n          },\n          {\n            \"fieldPath\": \"trackerCount\",\n            \"columnName\": \"tracker_count\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"0\"\n          },\n          {\n            \"fieldPath\": \"openCount\",\n            \"columnName\": \"open_count\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"0\"\n          },\n          {\n            \"fieldPath\": \"screenTime\",\n            \"columnName\": \"screen_time\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"0\"\n          },\n          {\n            \"fieldPath\": \"lastUsageTime\",\n            \"columnName\": \"last_usage_time\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"0\"\n          },\n          {\n            \"fieldPath\": \"lastActionTime\",\n            \"columnName\": \"last_action_time\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"0\"\n          }\n        ],\n        \"primaryKey\": {\n          \"autoGenerate\": false,\n          \"columnNames\": [\n            \"package_name\",\n            \"user_id\"\n          ]\n        },\n        \"indices\": [],\n        \"foreignKeys\": []\n      },\n      {\n        \"tableName\": \"log_filter\",\n        \"createSql\": \"CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `name` TEXT)\",\n        \"fields\": [\n          {\n            \"fieldPath\": \"id\",\n            \"columnName\": \"id\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"name\",\n            \"columnName\": \"name\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": false\n          }\n        ],\n        \"primaryKey\": {\n          \"autoGenerate\": true,\n          \"columnNames\": [\n            \"id\"\n          ]\n        },\n        \"indices\": [\n          {\n            \"name\": \"index_name\",\n            \"unique\": true,\n            \"columnNames\": [\n              \"name\"\n            ],\n            \"orders\": [],\n            \"createSql\": \"CREATE UNIQUE INDEX IF NOT EXISTS `index_name` ON `${TABLE_NAME}` (`name`)\"\n          }\n        ],\n        \"foreignKeys\": []\n      },\n      {\n        \"tableName\": \"file_hash\",\n        \"createSql\": \"CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`path` TEXT NOT NULL, `hash` TEXT, PRIMARY KEY(`path`))\",\n        \"fields\": [\n          {\n            \"fieldPath\": \"path\",\n            \"columnName\": \"path\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"hash\",\n            \"columnName\": \"hash\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": false\n          }\n        ],\n        \"primaryKey\": {\n          \"autoGenerate\": false,\n          \"columnNames\": [\n            \"path\"\n          ]\n        },\n        \"indices\": [],\n        \"foreignKeys\": []\n      },\n      {\n        \"tableName\": \"backup\",\n        \"createSql\": \"CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`package_name` TEXT NOT NULL, `backup_name` TEXT NOT NULL, `label` TEXT, `version_name` TEXT, `version_code` INTEGER NOT NULL, `is_system` INTEGER NOT NULL, `has_splits` INTEGER NOT NULL, `has_rules` INTEGER NOT NULL, `backup_time` INTEGER NOT NULL, `crypto` TEXT, `meta_version` INTEGER NOT NULL, `flags` INTEGER NOT NULL, `user_id` INTEGER NOT NULL, `tar_type` TEXT, `has_key_store` INTEGER NOT NULL, `installer_app` TEXT, `info_hash` TEXT, PRIMARY KEY(`backup_name`, `package_name`))\",\n        \"fields\": [\n          {\n            \"fieldPath\": \"packageName\",\n            \"columnName\": \"package_name\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"backupName\",\n            \"columnName\": \"backup_name\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"label\",\n            \"columnName\": \"label\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": false\n          },\n          {\n            \"fieldPath\": \"versionName\",\n            \"columnName\": \"version_name\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": false\n          },\n          {\n            \"fieldPath\": \"versionCode\",\n            \"columnName\": \"version_code\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"isSystem\",\n            \"columnName\": \"is_system\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"hasSplits\",\n            \"columnName\": \"has_splits\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"hasRules\",\n            \"columnName\": \"has_rules\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"backupTime\",\n            \"columnName\": \"backup_time\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"crypto\",\n            \"columnName\": \"crypto\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": false\n          },\n          {\n            \"fieldPath\": \"version\",\n            \"columnName\": \"meta_version\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"flags\",\n            \"columnName\": \"flags\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"userId\",\n            \"columnName\": \"user_id\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"tarType\",\n            \"columnName\": \"tar_type\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": false\n          },\n          {\n            \"fieldPath\": \"hasKeyStore\",\n            \"columnName\": \"has_key_store\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"installer\",\n            \"columnName\": \"installer_app\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": false\n          },\n          {\n            \"fieldPath\": \"uuid\",\n            \"columnName\": \"info_hash\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": false\n          }\n        ],\n        \"primaryKey\": {\n          \"autoGenerate\": false,\n          \"columnNames\": [\n            \"backup_name\",\n            \"package_name\"\n          ]\n        },\n        \"indices\": [],\n        \"foreignKeys\": []\n      },\n      {\n        \"tableName\": \"op_history\",\n        \"createSql\": \"CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `type` TEXT NOT NULL, `time` INTEGER NOT NULL, `data` TEXT NOT NULL, `status` TEXT NOT NULL, `extra` TEXT)\",\n        \"fields\": [\n          {\n            \"fieldPath\": \"id\",\n            \"columnName\": \"id\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"type\",\n            \"columnName\": \"type\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"execTime\",\n            \"columnName\": \"time\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"serializedData\",\n            \"columnName\": \"data\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"status\",\n            \"columnName\": \"status\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"serializedExtra\",\n            \"columnName\": \"extra\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": false\n          }\n        ],\n        \"primaryKey\": {\n          \"autoGenerate\": true,\n          \"columnNames\": [\n            \"id\"\n          ]\n        },\n        \"indices\": [],\n        \"foreignKeys\": []\n      }\n    ],\n    \"views\": [],\n    \"setupQueries\": [\n      \"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)\",\n      \"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'ac92def333f7b8a38eb1ceab89033e99')\"\n    ]\n  }\n}"
  },
  {
    "path": "app/schemas/io.github.muntashirakon.AppManager.db.AppsDb/4.json",
    "content": "{\n  \"formatVersion\": 1,\n  \"database\": {\n    \"version\": 4,\n    \"identityHash\": \"7bb1cd35f0800b965e5a475458918b80\",\n    \"entities\": [\n      {\n        \"tableName\": \"app\",\n        \"createSql\": \"CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`package_name` TEXT NOT NULL, `user_id` INTEGER NOT NULL DEFAULT -10000, `label` TEXT, `version_name` TEXT, `version_code` INTEGER NOT NULL, `flags` INTEGER NOT NULL DEFAULT 0, `uid` INTEGER NOT NULL DEFAULT 0, `shared_uid` TEXT DEFAULT NULL, `first_install_time` INTEGER NOT NULL DEFAULT 0, `last_update_time` INTEGER NOT NULL DEFAULT 0, `target_sdk` INTEGER NOT NULL DEFAULT 0, `cert_name` TEXT DEFAULT '', `cert_algo` TEXT DEFAULT '', `is_installed` INTEGER NOT NULL DEFAULT true, `is_enabled` INTEGER NOT NULL DEFAULT false, `has_activities` INTEGER NOT NULL DEFAULT false, `has_splits` INTEGER NOT NULL DEFAULT false, `has_keystore` INTEGER NOT NULL DEFAULT false, `uses_saf` INTEGER NOT NULL DEFAULT false, `ssaid` TEXT DEFAULT '', `code_size` INTEGER NOT NULL DEFAULT 0, `data_size` INTEGER NOT NULL DEFAULT 0, `mobile_data` INTEGER NOT NULL DEFAULT 0, `wifi_data` INTEGER NOT NULL DEFAULT 0, `rules_count` INTEGER NOT NULL DEFAULT 0, `tracker_count` INTEGER NOT NULL DEFAULT 0, `open_count` INTEGER NOT NULL DEFAULT 0, `screen_time` INTEGER NOT NULL DEFAULT 0, `last_usage_time` INTEGER NOT NULL DEFAULT 0, `last_action_time` INTEGER NOT NULL DEFAULT 0, PRIMARY KEY(`package_name`, `user_id`))\",\n        \"fields\": [\n          {\n            \"fieldPath\": \"packageName\",\n            \"columnName\": \"package_name\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"userId\",\n            \"columnName\": \"user_id\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"-10000\"\n          },\n          {\n            \"fieldPath\": \"packageLabel\",\n            \"columnName\": \"label\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": false\n          },\n          {\n            \"fieldPath\": \"versionName\",\n            \"columnName\": \"version_name\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": false\n          },\n          {\n            \"fieldPath\": \"versionCode\",\n            \"columnName\": \"version_code\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"flags\",\n            \"columnName\": \"flags\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"0\"\n          },\n          {\n            \"fieldPath\": \"uid\",\n            \"columnName\": \"uid\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"0\"\n          },\n          {\n            \"fieldPath\": \"sharedUserId\",\n            \"columnName\": \"shared_uid\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": false,\n            \"defaultValue\": \"NULL\"\n          },\n          {\n            \"fieldPath\": \"firstInstallTime\",\n            \"columnName\": \"first_install_time\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"0\"\n          },\n          {\n            \"fieldPath\": \"lastUpdateTime\",\n            \"columnName\": \"last_update_time\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"0\"\n          },\n          {\n            \"fieldPath\": \"sdk\",\n            \"columnName\": \"target_sdk\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"0\"\n          },\n          {\n            \"fieldPath\": \"certName\",\n            \"columnName\": \"cert_name\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": false,\n            \"defaultValue\": \"''\"\n          },\n          {\n            \"fieldPath\": \"certAlgo\",\n            \"columnName\": \"cert_algo\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": false,\n            \"defaultValue\": \"''\"\n          },\n          {\n            \"fieldPath\": \"isInstalled\",\n            \"columnName\": \"is_installed\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"true\"\n          },\n          {\n            \"fieldPath\": \"isEnabled\",\n            \"columnName\": \"is_enabled\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"false\"\n          },\n          {\n            \"fieldPath\": \"hasActivities\",\n            \"columnName\": \"has_activities\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"false\"\n          },\n          {\n            \"fieldPath\": \"hasSplits\",\n            \"columnName\": \"has_splits\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"false\"\n          },\n          {\n            \"fieldPath\": \"hasKeystore\",\n            \"columnName\": \"has_keystore\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"false\"\n          },\n          {\n            \"fieldPath\": \"usesSaf\",\n            \"columnName\": \"uses_saf\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"false\"\n          },\n          {\n            \"fieldPath\": \"ssaid\",\n            \"columnName\": \"ssaid\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": false,\n            \"defaultValue\": \"''\"\n          },\n          {\n            \"fieldPath\": \"codeSize\",\n            \"columnName\": \"code_size\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"0\"\n          },\n          {\n            \"fieldPath\": \"dataSize\",\n            \"columnName\": \"data_size\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"0\"\n          },\n          {\n            \"fieldPath\": \"mobileDataUsage\",\n            \"columnName\": \"mobile_data\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"0\"\n          },\n          {\n            \"fieldPath\": \"wifiDataUsage\",\n            \"columnName\": \"wifi_data\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"0\"\n          },\n          {\n            \"fieldPath\": \"rulesCount\",\n            \"columnName\": \"rules_count\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"0\"\n          },\n          {\n            \"fieldPath\": \"trackerCount\",\n            \"columnName\": \"tracker_count\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"0\"\n          },\n          {\n            \"fieldPath\": \"openCount\",\n            \"columnName\": \"open_count\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"0\"\n          },\n          {\n            \"fieldPath\": \"screenTime\",\n            \"columnName\": \"screen_time\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"0\"\n          },\n          {\n            \"fieldPath\": \"lastUsageTime\",\n            \"columnName\": \"last_usage_time\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"0\"\n          },\n          {\n            \"fieldPath\": \"lastActionTime\",\n            \"columnName\": \"last_action_time\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"0\"\n          }\n        ],\n        \"primaryKey\": {\n          \"autoGenerate\": false,\n          \"columnNames\": [\n            \"package_name\",\n            \"user_id\"\n          ]\n        },\n        \"indices\": [],\n        \"foreignKeys\": []\n      },\n      {\n        \"tableName\": \"log_filter\",\n        \"createSql\": \"CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `name` TEXT)\",\n        \"fields\": [\n          {\n            \"fieldPath\": \"id\",\n            \"columnName\": \"id\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"name\",\n            \"columnName\": \"name\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": false\n          }\n        ],\n        \"primaryKey\": {\n          \"autoGenerate\": true,\n          \"columnNames\": [\n            \"id\"\n          ]\n        },\n        \"indices\": [\n          {\n            \"name\": \"index_name\",\n            \"unique\": true,\n            \"columnNames\": [\n              \"name\"\n            ],\n            \"orders\": [],\n            \"createSql\": \"CREATE UNIQUE INDEX IF NOT EXISTS `index_name` ON `${TABLE_NAME}` (`name`)\"\n          }\n        ],\n        \"foreignKeys\": []\n      },\n      {\n        \"tableName\": \"file_hash\",\n        \"createSql\": \"CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`path` TEXT NOT NULL, `hash` TEXT, PRIMARY KEY(`path`))\",\n        \"fields\": [\n          {\n            \"fieldPath\": \"path\",\n            \"columnName\": \"path\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"hash\",\n            \"columnName\": \"hash\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": false\n          }\n        ],\n        \"primaryKey\": {\n          \"autoGenerate\": false,\n          \"columnNames\": [\n            \"path\"\n          ]\n        },\n        \"indices\": [],\n        \"foreignKeys\": []\n      },\n      {\n        \"tableName\": \"backup\",\n        \"createSql\": \"CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`package_name` TEXT NOT NULL, `backup_name` TEXT NOT NULL, `label` TEXT, `version_name` TEXT, `version_code` INTEGER NOT NULL, `is_system` INTEGER NOT NULL, `has_splits` INTEGER NOT NULL, `has_rules` INTEGER NOT NULL, `backup_time` INTEGER NOT NULL, `crypto` TEXT, `meta_version` INTEGER NOT NULL, `flags` INTEGER NOT NULL, `user_id` INTEGER NOT NULL, `tar_type` TEXT, `has_key_store` INTEGER NOT NULL, `installer_app` TEXT, `info_hash` TEXT, PRIMARY KEY(`backup_name`, `package_name`))\",\n        \"fields\": [\n          {\n            \"fieldPath\": \"packageName\",\n            \"columnName\": \"package_name\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"backupName\",\n            \"columnName\": \"backup_name\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"label\",\n            \"columnName\": \"label\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": false\n          },\n          {\n            \"fieldPath\": \"versionName\",\n            \"columnName\": \"version_name\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": false\n          },\n          {\n            \"fieldPath\": \"versionCode\",\n            \"columnName\": \"version_code\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"isSystem\",\n            \"columnName\": \"is_system\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"hasSplits\",\n            \"columnName\": \"has_splits\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"hasRules\",\n            \"columnName\": \"has_rules\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"backupTime\",\n            \"columnName\": \"backup_time\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"crypto\",\n            \"columnName\": \"crypto\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": false\n          },\n          {\n            \"fieldPath\": \"version\",\n            \"columnName\": \"meta_version\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"flags\",\n            \"columnName\": \"flags\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"userId\",\n            \"columnName\": \"user_id\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"tarType\",\n            \"columnName\": \"tar_type\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": false\n          },\n          {\n            \"fieldPath\": \"hasKeyStore\",\n            \"columnName\": \"has_key_store\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"installer\",\n            \"columnName\": \"installer_app\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": false\n          },\n          {\n            \"fieldPath\": \"uuid\",\n            \"columnName\": \"info_hash\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": false\n          }\n        ],\n        \"primaryKey\": {\n          \"autoGenerate\": false,\n          \"columnNames\": [\n            \"backup_name\",\n            \"package_name\"\n          ]\n        },\n        \"indices\": [],\n        \"foreignKeys\": []\n      },\n      {\n        \"tableName\": \"op_history\",\n        \"createSql\": \"CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `type` TEXT NOT NULL, `time` INTEGER NOT NULL, `data` TEXT NOT NULL, `status` TEXT NOT NULL, `extra` TEXT)\",\n        \"fields\": [\n          {\n            \"fieldPath\": \"id\",\n            \"columnName\": \"id\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"type\",\n            \"columnName\": \"type\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"execTime\",\n            \"columnName\": \"time\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"serializedData\",\n            \"columnName\": \"data\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"status\",\n            \"columnName\": \"status\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"serializedExtra\",\n            \"columnName\": \"extra\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": false\n          }\n        ],\n        \"primaryKey\": {\n          \"autoGenerate\": true,\n          \"columnNames\": [\n            \"id\"\n          ]\n        },\n        \"indices\": [],\n        \"foreignKeys\": []\n      },\n      {\n        \"tableName\": \"fm_favorite\",\n        \"createSql\": \"CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `name` TEXT NOT NULL, `uri` TEXT NOT NULL, `init_uri` TEXT, `options` INTEGER NOT NULL, `order` INTEGER NOT NULL, `type` INTEGER NOT NULL)\",\n        \"fields\": [\n          {\n            \"fieldPath\": \"id\",\n            \"columnName\": \"id\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"name\",\n            \"columnName\": \"name\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"uri\",\n            \"columnName\": \"uri\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"initUri\",\n            \"columnName\": \"init_uri\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": false\n          },\n          {\n            \"fieldPath\": \"options\",\n            \"columnName\": \"options\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"order\",\n            \"columnName\": \"order\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"type\",\n            \"columnName\": \"type\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true\n          }\n        ],\n        \"primaryKey\": {\n          \"autoGenerate\": true,\n          \"columnNames\": [\n            \"id\"\n          ]\n        },\n        \"indices\": [],\n        \"foreignKeys\": []\n      }\n    ],\n    \"views\": [],\n    \"setupQueries\": [\n      \"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)\",\n      \"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '7bb1cd35f0800b965e5a475458918b80')\"\n    ]\n  }\n}"
  },
  {
    "path": "app/schemas/io.github.muntashirakon.AppManager.db.AppsDb/5.json",
    "content": "{\n  \"formatVersion\": 1,\n  \"database\": {\n    \"version\": 5,\n    \"identityHash\": \"c692d8d6e1657fb5d1332a3fb631e9d7\",\n    \"entities\": [\n      {\n        \"tableName\": \"app\",\n        \"createSql\": \"CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`package_name` TEXT NOT NULL, `user_id` INTEGER NOT NULL DEFAULT -10000, `label` TEXT, `version_name` TEXT, `version_code` INTEGER NOT NULL, `flags` INTEGER NOT NULL DEFAULT 0, `uid` INTEGER NOT NULL DEFAULT 0, `shared_uid` TEXT DEFAULT NULL, `first_install_time` INTEGER NOT NULL DEFAULT 0, `last_update_time` INTEGER NOT NULL DEFAULT 0, `target_sdk` INTEGER NOT NULL DEFAULT 0, `cert_name` TEXT DEFAULT '', `cert_algo` TEXT DEFAULT '', `is_installed` INTEGER NOT NULL DEFAULT true, `is_enabled` INTEGER NOT NULL DEFAULT false, `has_activities` INTEGER NOT NULL DEFAULT false, `has_splits` INTEGER NOT NULL DEFAULT false, `has_keystore` INTEGER NOT NULL DEFAULT false, `uses_saf` INTEGER NOT NULL DEFAULT false, `ssaid` TEXT DEFAULT '', `code_size` INTEGER NOT NULL DEFAULT 0, `data_size` INTEGER NOT NULL DEFAULT 0, `mobile_data` INTEGER NOT NULL DEFAULT 0, `wifi_data` INTEGER NOT NULL DEFAULT 0, `rules_count` INTEGER NOT NULL DEFAULT 0, `tracker_count` INTEGER NOT NULL DEFAULT 0, `open_count` INTEGER NOT NULL DEFAULT 0, `screen_time` INTEGER NOT NULL DEFAULT 0, `last_usage_time` INTEGER NOT NULL DEFAULT 0, `last_action_time` INTEGER NOT NULL DEFAULT 0, PRIMARY KEY(`package_name`, `user_id`))\",\n        \"fields\": [\n          {\n            \"fieldPath\": \"packageName\",\n            \"columnName\": \"package_name\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"userId\",\n            \"columnName\": \"user_id\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"-10000\"\n          },\n          {\n            \"fieldPath\": \"packageLabel\",\n            \"columnName\": \"label\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": false\n          },\n          {\n            \"fieldPath\": \"versionName\",\n            \"columnName\": \"version_name\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": false\n          },\n          {\n            \"fieldPath\": \"versionCode\",\n            \"columnName\": \"version_code\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"flags\",\n            \"columnName\": \"flags\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"0\"\n          },\n          {\n            \"fieldPath\": \"uid\",\n            \"columnName\": \"uid\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"0\"\n          },\n          {\n            \"fieldPath\": \"sharedUserId\",\n            \"columnName\": \"shared_uid\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": false,\n            \"defaultValue\": \"NULL\"\n          },\n          {\n            \"fieldPath\": \"firstInstallTime\",\n            \"columnName\": \"first_install_time\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"0\"\n          },\n          {\n            \"fieldPath\": \"lastUpdateTime\",\n            \"columnName\": \"last_update_time\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"0\"\n          },\n          {\n            \"fieldPath\": \"sdk\",\n            \"columnName\": \"target_sdk\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"0\"\n          },\n          {\n            \"fieldPath\": \"certName\",\n            \"columnName\": \"cert_name\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": false,\n            \"defaultValue\": \"''\"\n          },\n          {\n            \"fieldPath\": \"certAlgo\",\n            \"columnName\": \"cert_algo\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": false,\n            \"defaultValue\": \"''\"\n          },\n          {\n            \"fieldPath\": \"isInstalled\",\n            \"columnName\": \"is_installed\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"true\"\n          },\n          {\n            \"fieldPath\": \"isEnabled\",\n            \"columnName\": \"is_enabled\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"false\"\n          },\n          {\n            \"fieldPath\": \"hasActivities\",\n            \"columnName\": \"has_activities\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"false\"\n          },\n          {\n            \"fieldPath\": \"hasSplits\",\n            \"columnName\": \"has_splits\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"false\"\n          },\n          {\n            \"fieldPath\": \"hasKeystore\",\n            \"columnName\": \"has_keystore\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"false\"\n          },\n          {\n            \"fieldPath\": \"usesSaf\",\n            \"columnName\": \"uses_saf\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"false\"\n          },\n          {\n            \"fieldPath\": \"ssaid\",\n            \"columnName\": \"ssaid\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": false,\n            \"defaultValue\": \"''\"\n          },\n          {\n            \"fieldPath\": \"codeSize\",\n            \"columnName\": \"code_size\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"0\"\n          },\n          {\n            \"fieldPath\": \"dataSize\",\n            \"columnName\": \"data_size\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"0\"\n          },\n          {\n            \"fieldPath\": \"mobileDataUsage\",\n            \"columnName\": \"mobile_data\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"0\"\n          },\n          {\n            \"fieldPath\": \"wifiDataUsage\",\n            \"columnName\": \"wifi_data\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"0\"\n          },\n          {\n            \"fieldPath\": \"rulesCount\",\n            \"columnName\": \"rules_count\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"0\"\n          },\n          {\n            \"fieldPath\": \"trackerCount\",\n            \"columnName\": \"tracker_count\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"0\"\n          },\n          {\n            \"fieldPath\": \"openCount\",\n            \"columnName\": \"open_count\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"0\"\n          },\n          {\n            \"fieldPath\": \"screenTime\",\n            \"columnName\": \"screen_time\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"0\"\n          },\n          {\n            \"fieldPath\": \"lastUsageTime\",\n            \"columnName\": \"last_usage_time\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"0\"\n          },\n          {\n            \"fieldPath\": \"lastActionTime\",\n            \"columnName\": \"last_action_time\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"0\"\n          }\n        ],\n        \"primaryKey\": {\n          \"autoGenerate\": false,\n          \"columnNames\": [\n            \"package_name\",\n            \"user_id\"\n          ]\n        },\n        \"indices\": [],\n        \"foreignKeys\": []\n      },\n      {\n        \"tableName\": \"log_filter\",\n        \"createSql\": \"CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `name` TEXT)\",\n        \"fields\": [\n          {\n            \"fieldPath\": \"id\",\n            \"columnName\": \"id\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"name\",\n            \"columnName\": \"name\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": false\n          }\n        ],\n        \"primaryKey\": {\n          \"autoGenerate\": true,\n          \"columnNames\": [\n            \"id\"\n          ]\n        },\n        \"indices\": [\n          {\n            \"name\": \"index_name\",\n            \"unique\": true,\n            \"columnNames\": [\n              \"name\"\n            ],\n            \"orders\": [],\n            \"createSql\": \"CREATE UNIQUE INDEX IF NOT EXISTS `index_name` ON `${TABLE_NAME}` (`name`)\"\n          }\n        ],\n        \"foreignKeys\": []\n      },\n      {\n        \"tableName\": \"file_hash\",\n        \"createSql\": \"CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`path` TEXT NOT NULL, `hash` TEXT, PRIMARY KEY(`path`))\",\n        \"fields\": [\n          {\n            \"fieldPath\": \"path\",\n            \"columnName\": \"path\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"hash\",\n            \"columnName\": \"hash\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": false\n          }\n        ],\n        \"primaryKey\": {\n          \"autoGenerate\": false,\n          \"columnNames\": [\n            \"path\"\n          ]\n        },\n        \"indices\": [],\n        \"foreignKeys\": []\n      },\n      {\n        \"tableName\": \"backup\",\n        \"createSql\": \"CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`package_name` TEXT NOT NULL, `backup_name` TEXT NOT NULL, `label` TEXT, `version_name` TEXT, `version_code` INTEGER NOT NULL, `is_system` INTEGER NOT NULL, `has_splits` INTEGER NOT NULL, `has_rules` INTEGER NOT NULL, `backup_time` INTEGER NOT NULL, `crypto` TEXT, `meta_version` INTEGER NOT NULL, `flags` INTEGER NOT NULL, `user_id` INTEGER NOT NULL, `tar_type` TEXT, `has_key_store` INTEGER NOT NULL, `installer_app` TEXT, `info_hash` TEXT, PRIMARY KEY(`backup_name`, `package_name`))\",\n        \"fields\": [\n          {\n            \"fieldPath\": \"packageName\",\n            \"columnName\": \"package_name\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"backupName\",\n            \"columnName\": \"backup_name\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"label\",\n            \"columnName\": \"label\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": false\n          },\n          {\n            \"fieldPath\": \"versionName\",\n            \"columnName\": \"version_name\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": false\n          },\n          {\n            \"fieldPath\": \"versionCode\",\n            \"columnName\": \"version_code\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"isSystem\",\n            \"columnName\": \"is_system\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"hasSplits\",\n            \"columnName\": \"has_splits\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"hasRules\",\n            \"columnName\": \"has_rules\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"backupTime\",\n            \"columnName\": \"backup_time\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"crypto\",\n            \"columnName\": \"crypto\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": false\n          },\n          {\n            \"fieldPath\": \"version\",\n            \"columnName\": \"meta_version\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"flags\",\n            \"columnName\": \"flags\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"userId\",\n            \"columnName\": \"user_id\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"tarType\",\n            \"columnName\": \"tar_type\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": false\n          },\n          {\n            \"fieldPath\": \"hasKeyStore\",\n            \"columnName\": \"has_key_store\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"installer\",\n            \"columnName\": \"installer_app\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": false\n          },\n          {\n            \"fieldPath\": \"uuid\",\n            \"columnName\": \"info_hash\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": false\n          }\n        ],\n        \"primaryKey\": {\n          \"autoGenerate\": false,\n          \"columnNames\": [\n            \"backup_name\",\n            \"package_name\"\n          ]\n        },\n        \"indices\": [],\n        \"foreignKeys\": []\n      },\n      {\n        \"tableName\": \"op_history\",\n        \"createSql\": \"CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `type` TEXT NOT NULL, `time` INTEGER NOT NULL, `data` TEXT NOT NULL, `status` TEXT NOT NULL, `extra` TEXT)\",\n        \"fields\": [\n          {\n            \"fieldPath\": \"id\",\n            \"columnName\": \"id\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"type\",\n            \"columnName\": \"type\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"execTime\",\n            \"columnName\": \"time\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"serializedData\",\n            \"columnName\": \"data\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"status\",\n            \"columnName\": \"status\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"serializedExtra\",\n            \"columnName\": \"extra\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": false\n          }\n        ],\n        \"primaryKey\": {\n          \"autoGenerate\": true,\n          \"columnNames\": [\n            \"id\"\n          ]\n        },\n        \"indices\": [],\n        \"foreignKeys\": []\n      },\n      {\n        \"tableName\": \"fm_favorite\",\n        \"createSql\": \"CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `name` TEXT NOT NULL, `uri` TEXT NOT NULL, `init_uri` TEXT, `options` INTEGER NOT NULL, `order` INTEGER NOT NULL, `type` INTEGER NOT NULL)\",\n        \"fields\": [\n          {\n            \"fieldPath\": \"id\",\n            \"columnName\": \"id\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"name\",\n            \"columnName\": \"name\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"uri\",\n            \"columnName\": \"uri\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"initUri\",\n            \"columnName\": \"init_uri\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": false\n          },\n          {\n            \"fieldPath\": \"options\",\n            \"columnName\": \"options\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"order\",\n            \"columnName\": \"order\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"type\",\n            \"columnName\": \"type\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true\n          }\n        ],\n        \"primaryKey\": {\n          \"autoGenerate\": true,\n          \"columnNames\": [\n            \"id\"\n          ]\n        },\n        \"indices\": [],\n        \"foreignKeys\": []\n      },\n      {\n        \"tableName\": \"freeze_type\",\n        \"createSql\": \"CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`package_name` TEXT NOT NULL, `type` INTEGER NOT NULL, PRIMARY KEY(`package_name`))\",\n        \"fields\": [\n          {\n            \"fieldPath\": \"packageName\",\n            \"columnName\": \"package_name\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"type\",\n            \"columnName\": \"type\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true\n          }\n        ],\n        \"primaryKey\": {\n          \"autoGenerate\": false,\n          \"columnNames\": [\n            \"package_name\"\n          ]\n        },\n        \"indices\": [],\n        \"foreignKeys\": []\n      }\n    ],\n    \"views\": [],\n    \"setupQueries\": [\n      \"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)\",\n      \"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'c692d8d6e1657fb5d1332a3fb631e9d7')\"\n    ]\n  }\n}"
  },
  {
    "path": "app/schemas/io.github.muntashirakon.AppManager.db.AppsDb/6.json",
    "content": "{\n  \"formatVersion\": 1,\n  \"database\": {\n    \"version\": 6,\n    \"identityHash\": \"f72fb62329689ce1c1c5cda5c0ede949\",\n    \"entities\": [\n      {\n        \"tableName\": \"app\",\n        \"createSql\": \"CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`package_name` TEXT NOT NULL, `user_id` INTEGER NOT NULL DEFAULT -10000, `label` TEXT, `version_name` TEXT, `version_code` INTEGER NOT NULL, `flags` INTEGER NOT NULL DEFAULT 0, `uid` INTEGER NOT NULL DEFAULT 0, `shared_uid` TEXT DEFAULT NULL, `first_install_time` INTEGER NOT NULL DEFAULT 0, `last_update_time` INTEGER NOT NULL DEFAULT 0, `target_sdk` INTEGER NOT NULL DEFAULT 0, `cert_name` TEXT DEFAULT '', `cert_algo` TEXT DEFAULT '', `is_installed` INTEGER NOT NULL DEFAULT true, `is_only_data_installed` INTEGER NOT NULL DEFAULT 0, `is_enabled` INTEGER NOT NULL DEFAULT false, `has_activities` INTEGER NOT NULL DEFAULT false, `has_splits` INTEGER NOT NULL DEFAULT false, `has_keystore` INTEGER NOT NULL DEFAULT false, `uses_saf` INTEGER NOT NULL DEFAULT false, `ssaid` TEXT DEFAULT '', `code_size` INTEGER NOT NULL DEFAULT 0, `data_size` INTEGER NOT NULL DEFAULT 0, `mobile_data` INTEGER NOT NULL DEFAULT 0, `wifi_data` INTEGER NOT NULL DEFAULT 0, `rules_count` INTEGER NOT NULL DEFAULT 0, `tracker_count` INTEGER NOT NULL DEFAULT 0, `open_count` INTEGER NOT NULL DEFAULT 0, `screen_time` INTEGER NOT NULL DEFAULT 0, `last_usage_time` INTEGER NOT NULL DEFAULT 0, `last_action_time` INTEGER NOT NULL DEFAULT 0, PRIMARY KEY(`package_name`, `user_id`))\",\n        \"fields\": [\n          {\n            \"fieldPath\": \"packageName\",\n            \"columnName\": \"package_name\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"userId\",\n            \"columnName\": \"user_id\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"-10000\"\n          },\n          {\n            \"fieldPath\": \"packageLabel\",\n            \"columnName\": \"label\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": false\n          },\n          {\n            \"fieldPath\": \"versionName\",\n            \"columnName\": \"version_name\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": false\n          },\n          {\n            \"fieldPath\": \"versionCode\",\n            \"columnName\": \"version_code\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"flags\",\n            \"columnName\": \"flags\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"0\"\n          },\n          {\n            \"fieldPath\": \"uid\",\n            \"columnName\": \"uid\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"0\"\n          },\n          {\n            \"fieldPath\": \"sharedUserId\",\n            \"columnName\": \"shared_uid\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": false,\n            \"defaultValue\": \"NULL\"\n          },\n          {\n            \"fieldPath\": \"firstInstallTime\",\n            \"columnName\": \"first_install_time\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"0\"\n          },\n          {\n            \"fieldPath\": \"lastUpdateTime\",\n            \"columnName\": \"last_update_time\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"0\"\n          },\n          {\n            \"fieldPath\": \"sdk\",\n            \"columnName\": \"target_sdk\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"0\"\n          },\n          {\n            \"fieldPath\": \"certName\",\n            \"columnName\": \"cert_name\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": false,\n            \"defaultValue\": \"''\"\n          },\n          {\n            \"fieldPath\": \"certAlgo\",\n            \"columnName\": \"cert_algo\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": false,\n            \"defaultValue\": \"''\"\n          },\n          {\n            \"fieldPath\": \"isInstalled\",\n            \"columnName\": \"is_installed\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"true\"\n          },\n          {\n            \"fieldPath\": \"isOnlyDataInstalled\",\n            \"columnName\": \"is_only_data_installed\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"0\"\n          },\n          {\n            \"fieldPath\": \"isEnabled\",\n            \"columnName\": \"is_enabled\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"false\"\n          },\n          {\n            \"fieldPath\": \"hasActivities\",\n            \"columnName\": \"has_activities\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"false\"\n          },\n          {\n            \"fieldPath\": \"hasSplits\",\n            \"columnName\": \"has_splits\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"false\"\n          },\n          {\n            \"fieldPath\": \"hasKeystore\",\n            \"columnName\": \"has_keystore\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"false\"\n          },\n          {\n            \"fieldPath\": \"usesSaf\",\n            \"columnName\": \"uses_saf\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"false\"\n          },\n          {\n            \"fieldPath\": \"ssaid\",\n            \"columnName\": \"ssaid\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": false,\n            \"defaultValue\": \"''\"\n          },\n          {\n            \"fieldPath\": \"codeSize\",\n            \"columnName\": \"code_size\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"0\"\n          },\n          {\n            \"fieldPath\": \"dataSize\",\n            \"columnName\": \"data_size\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"0\"\n          },\n          {\n            \"fieldPath\": \"mobileDataUsage\",\n            \"columnName\": \"mobile_data\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"0\"\n          },\n          {\n            \"fieldPath\": \"wifiDataUsage\",\n            \"columnName\": \"wifi_data\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"0\"\n          },\n          {\n            \"fieldPath\": \"rulesCount\",\n            \"columnName\": \"rules_count\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"0\"\n          },\n          {\n            \"fieldPath\": \"trackerCount\",\n            \"columnName\": \"tracker_count\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"0\"\n          },\n          {\n            \"fieldPath\": \"openCount\",\n            \"columnName\": \"open_count\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"0\"\n          },\n          {\n            \"fieldPath\": \"screenTime\",\n            \"columnName\": \"screen_time\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"0\"\n          },\n          {\n            \"fieldPath\": \"lastUsageTime\",\n            \"columnName\": \"last_usage_time\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"0\"\n          },\n          {\n            \"fieldPath\": \"lastActionTime\",\n            \"columnName\": \"last_action_time\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"0\"\n          }\n        ],\n        \"primaryKey\": {\n          \"autoGenerate\": false,\n          \"columnNames\": [\n            \"package_name\",\n            \"user_id\"\n          ]\n        },\n        \"indices\": [],\n        \"foreignKeys\": []\n      },\n      {\n        \"tableName\": \"log_filter\",\n        \"createSql\": \"CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `name` TEXT)\",\n        \"fields\": [\n          {\n            \"fieldPath\": \"id\",\n            \"columnName\": \"id\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"name\",\n            \"columnName\": \"name\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": false\n          }\n        ],\n        \"primaryKey\": {\n          \"autoGenerate\": true,\n          \"columnNames\": [\n            \"id\"\n          ]\n        },\n        \"indices\": [\n          {\n            \"name\": \"index_name\",\n            \"unique\": true,\n            \"columnNames\": [\n              \"name\"\n            ],\n            \"orders\": [],\n            \"createSql\": \"CREATE UNIQUE INDEX IF NOT EXISTS `index_name` ON `${TABLE_NAME}` (`name`)\"\n          }\n        ],\n        \"foreignKeys\": []\n      },\n      {\n        \"tableName\": \"file_hash\",\n        \"createSql\": \"CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`path` TEXT NOT NULL, `hash` TEXT, PRIMARY KEY(`path`))\",\n        \"fields\": [\n          {\n            \"fieldPath\": \"path\",\n            \"columnName\": \"path\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"hash\",\n            \"columnName\": \"hash\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": false\n          }\n        ],\n        \"primaryKey\": {\n          \"autoGenerate\": false,\n          \"columnNames\": [\n            \"path\"\n          ]\n        },\n        \"indices\": [],\n        \"foreignKeys\": []\n      },\n      {\n        \"tableName\": \"backup\",\n        \"createSql\": \"CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`package_name` TEXT NOT NULL, `backup_name` TEXT NOT NULL, `label` TEXT, `version_name` TEXT, `version_code` INTEGER NOT NULL, `is_system` INTEGER NOT NULL, `has_splits` INTEGER NOT NULL, `has_rules` INTEGER NOT NULL, `backup_time` INTEGER NOT NULL, `crypto` TEXT, `meta_version` INTEGER NOT NULL, `flags` INTEGER NOT NULL, `user_id` INTEGER NOT NULL, `tar_type` TEXT, `has_key_store` INTEGER NOT NULL, `installer_app` TEXT, `info_hash` TEXT, PRIMARY KEY(`backup_name`, `package_name`))\",\n        \"fields\": [\n          {\n            \"fieldPath\": \"packageName\",\n            \"columnName\": \"package_name\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"backupName\",\n            \"columnName\": \"backup_name\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"label\",\n            \"columnName\": \"label\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": false\n          },\n          {\n            \"fieldPath\": \"versionName\",\n            \"columnName\": \"version_name\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": false\n          },\n          {\n            \"fieldPath\": \"versionCode\",\n            \"columnName\": \"version_code\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"isSystem\",\n            \"columnName\": \"is_system\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"hasSplits\",\n            \"columnName\": \"has_splits\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"hasRules\",\n            \"columnName\": \"has_rules\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"backupTime\",\n            \"columnName\": \"backup_time\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"crypto\",\n            \"columnName\": \"crypto\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": false\n          },\n          {\n            \"fieldPath\": \"version\",\n            \"columnName\": \"meta_version\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"flags\",\n            \"columnName\": \"flags\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"userId\",\n            \"columnName\": \"user_id\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"tarType\",\n            \"columnName\": \"tar_type\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": false\n          },\n          {\n            \"fieldPath\": \"hasKeyStore\",\n            \"columnName\": \"has_key_store\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"installer\",\n            \"columnName\": \"installer_app\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": false\n          },\n          {\n            \"fieldPath\": \"uuid\",\n            \"columnName\": \"info_hash\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": false\n          }\n        ],\n        \"primaryKey\": {\n          \"autoGenerate\": false,\n          \"columnNames\": [\n            \"backup_name\",\n            \"package_name\"\n          ]\n        },\n        \"indices\": [],\n        \"foreignKeys\": []\n      },\n      {\n        \"tableName\": \"op_history\",\n        \"createSql\": \"CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `type` TEXT NOT NULL, `time` INTEGER NOT NULL, `data` TEXT NOT NULL, `status` TEXT NOT NULL, `extra` TEXT)\",\n        \"fields\": [\n          {\n            \"fieldPath\": \"id\",\n            \"columnName\": \"id\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"type\",\n            \"columnName\": \"type\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"execTime\",\n            \"columnName\": \"time\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"serializedData\",\n            \"columnName\": \"data\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"status\",\n            \"columnName\": \"status\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"serializedExtra\",\n            \"columnName\": \"extra\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": false\n          }\n        ],\n        \"primaryKey\": {\n          \"autoGenerate\": true,\n          \"columnNames\": [\n            \"id\"\n          ]\n        },\n        \"indices\": [],\n        \"foreignKeys\": []\n      },\n      {\n        \"tableName\": \"fm_favorite\",\n        \"createSql\": \"CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `name` TEXT NOT NULL, `uri` TEXT NOT NULL, `init_uri` TEXT, `options` INTEGER NOT NULL, `order` INTEGER NOT NULL, `type` INTEGER NOT NULL)\",\n        \"fields\": [\n          {\n            \"fieldPath\": \"id\",\n            \"columnName\": \"id\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"name\",\n            \"columnName\": \"name\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"uri\",\n            \"columnName\": \"uri\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"initUri\",\n            \"columnName\": \"init_uri\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": false\n          },\n          {\n            \"fieldPath\": \"options\",\n            \"columnName\": \"options\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"order\",\n            \"columnName\": \"order\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"type\",\n            \"columnName\": \"type\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true\n          }\n        ],\n        \"primaryKey\": {\n          \"autoGenerate\": true,\n          \"columnNames\": [\n            \"id\"\n          ]\n        },\n        \"indices\": [],\n        \"foreignKeys\": []\n      },\n      {\n        \"tableName\": \"freeze_type\",\n        \"createSql\": \"CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`package_name` TEXT NOT NULL, `type` INTEGER NOT NULL, PRIMARY KEY(`package_name`))\",\n        \"fields\": [\n          {\n            \"fieldPath\": \"packageName\",\n            \"columnName\": \"package_name\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"type\",\n            \"columnName\": \"type\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true\n          }\n        ],\n        \"primaryKey\": {\n          \"autoGenerate\": false,\n          \"columnNames\": [\n            \"package_name\"\n          ]\n        },\n        \"indices\": [],\n        \"foreignKeys\": []\n      }\n    ],\n    \"views\": [],\n    \"setupQueries\": [\n      \"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)\",\n      \"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'f72fb62329689ce1c1c5cda5c0ede949')\"\n    ]\n  }\n}"
  },
  {
    "path": "app/schemas/io.github.muntashirakon.AppManager.db.AppsDb/7.json",
    "content": "{\n  \"formatVersion\": 1,\n  \"database\": {\n    \"version\": 7,\n    \"identityHash\": \"3b4a41c98cdc8966b52bd7a0a0f8ad58\",\n    \"entities\": [\n      {\n        \"tableName\": \"app\",\n        \"createSql\": \"CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`package_name` TEXT NOT NULL, `user_id` INTEGER NOT NULL DEFAULT -10000, `label` TEXT, `version_name` TEXT, `version_code` INTEGER NOT NULL, `flags` INTEGER NOT NULL DEFAULT 0, `uid` INTEGER NOT NULL DEFAULT 0, `shared_uid` TEXT DEFAULT NULL, `first_install_time` INTEGER NOT NULL DEFAULT 0, `last_update_time` INTEGER NOT NULL DEFAULT 0, `target_sdk` INTEGER NOT NULL DEFAULT 0, `cert_name` TEXT DEFAULT '', `cert_algo` TEXT DEFAULT '', `is_installed` INTEGER NOT NULL DEFAULT true, `is_only_data_installed` INTEGER NOT NULL DEFAULT 0, `is_enabled` INTEGER NOT NULL DEFAULT false, `has_activities` INTEGER NOT NULL DEFAULT false, `has_splits` INTEGER NOT NULL DEFAULT false, `has_keystore` INTEGER NOT NULL DEFAULT false, `uses_saf` INTEGER NOT NULL DEFAULT false, `ssaid` TEXT DEFAULT '', `code_size` INTEGER NOT NULL DEFAULT 0, `data_size` INTEGER NOT NULL DEFAULT 0, `mobile_data` INTEGER NOT NULL DEFAULT 0, `wifi_data` INTEGER NOT NULL DEFAULT 0, `rules_count` INTEGER NOT NULL DEFAULT 0, `tracker_count` INTEGER NOT NULL DEFAULT 0, `open_count` INTEGER NOT NULL DEFAULT 0, `screen_time` INTEGER NOT NULL DEFAULT 0, `last_usage_time` INTEGER NOT NULL DEFAULT 0, `last_action_time` INTEGER NOT NULL DEFAULT 0, PRIMARY KEY(`package_name`, `user_id`))\",\n        \"fields\": [\n          {\n            \"fieldPath\": \"packageName\",\n            \"columnName\": \"package_name\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"userId\",\n            \"columnName\": \"user_id\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"-10000\"\n          },\n          {\n            \"fieldPath\": \"packageLabel\",\n            \"columnName\": \"label\",\n            \"affinity\": \"TEXT\"\n          },\n          {\n            \"fieldPath\": \"versionName\",\n            \"columnName\": \"version_name\",\n            \"affinity\": \"TEXT\"\n          },\n          {\n            \"fieldPath\": \"versionCode\",\n            \"columnName\": \"version_code\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"flags\",\n            \"columnName\": \"flags\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"0\"\n          },\n          {\n            \"fieldPath\": \"uid\",\n            \"columnName\": \"uid\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"0\"\n          },\n          {\n            \"fieldPath\": \"sharedUserId\",\n            \"columnName\": \"shared_uid\",\n            \"affinity\": \"TEXT\",\n            \"defaultValue\": \"NULL\"\n          },\n          {\n            \"fieldPath\": \"firstInstallTime\",\n            \"columnName\": \"first_install_time\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"0\"\n          },\n          {\n            \"fieldPath\": \"lastUpdateTime\",\n            \"columnName\": \"last_update_time\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"0\"\n          },\n          {\n            \"fieldPath\": \"sdk\",\n            \"columnName\": \"target_sdk\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"0\"\n          },\n          {\n            \"fieldPath\": \"certName\",\n            \"columnName\": \"cert_name\",\n            \"affinity\": \"TEXT\",\n            \"defaultValue\": \"''\"\n          },\n          {\n            \"fieldPath\": \"certAlgo\",\n            \"columnName\": \"cert_algo\",\n            \"affinity\": \"TEXT\",\n            \"defaultValue\": \"''\"\n          },\n          {\n            \"fieldPath\": \"isInstalled\",\n            \"columnName\": \"is_installed\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"true\"\n          },\n          {\n            \"fieldPath\": \"isOnlyDataInstalled\",\n            \"columnName\": \"is_only_data_installed\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"0\"\n          },\n          {\n            \"fieldPath\": \"isEnabled\",\n            \"columnName\": \"is_enabled\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"false\"\n          },\n          {\n            \"fieldPath\": \"hasActivities\",\n            \"columnName\": \"has_activities\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"false\"\n          },\n          {\n            \"fieldPath\": \"hasSplits\",\n            \"columnName\": \"has_splits\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"false\"\n          },\n          {\n            \"fieldPath\": \"hasKeystore\",\n            \"columnName\": \"has_keystore\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"false\"\n          },\n          {\n            \"fieldPath\": \"usesSaf\",\n            \"columnName\": \"uses_saf\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"false\"\n          },\n          {\n            \"fieldPath\": \"ssaid\",\n            \"columnName\": \"ssaid\",\n            \"affinity\": \"TEXT\",\n            \"defaultValue\": \"''\"\n          },\n          {\n            \"fieldPath\": \"codeSize\",\n            \"columnName\": \"code_size\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"0\"\n          },\n          {\n            \"fieldPath\": \"dataSize\",\n            \"columnName\": \"data_size\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"0\"\n          },\n          {\n            \"fieldPath\": \"mobileDataUsage\",\n            \"columnName\": \"mobile_data\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"0\"\n          },\n          {\n            \"fieldPath\": \"wifiDataUsage\",\n            \"columnName\": \"wifi_data\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"0\"\n          },\n          {\n            \"fieldPath\": \"rulesCount\",\n            \"columnName\": \"rules_count\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"0\"\n          },\n          {\n            \"fieldPath\": \"trackerCount\",\n            \"columnName\": \"tracker_count\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"0\"\n          },\n          {\n            \"fieldPath\": \"openCount\",\n            \"columnName\": \"open_count\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"0\"\n          },\n          {\n            \"fieldPath\": \"screenTime\",\n            \"columnName\": \"screen_time\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"0\"\n          },\n          {\n            \"fieldPath\": \"lastUsageTime\",\n            \"columnName\": \"last_usage_time\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"0\"\n          },\n          {\n            \"fieldPath\": \"lastActionTime\",\n            \"columnName\": \"last_action_time\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true,\n            \"defaultValue\": \"0\"\n          }\n        ],\n        \"primaryKey\": {\n          \"autoGenerate\": false,\n          \"columnNames\": [\n            \"package_name\",\n            \"user_id\"\n          ]\n        }\n      },\n      {\n        \"tableName\": \"log_filter\",\n        \"createSql\": \"CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `name` TEXT)\",\n        \"fields\": [\n          {\n            \"fieldPath\": \"id\",\n            \"columnName\": \"id\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"name\",\n            \"columnName\": \"name\",\n            \"affinity\": \"TEXT\"\n          }\n        ],\n        \"primaryKey\": {\n          \"autoGenerate\": true,\n          \"columnNames\": [\n            \"id\"\n          ]\n        },\n        \"indices\": [\n          {\n            \"name\": \"index_name\",\n            \"unique\": true,\n            \"columnNames\": [\n              \"name\"\n            ],\n            \"orders\": [],\n            \"createSql\": \"CREATE UNIQUE INDEX IF NOT EXISTS `index_name` ON `${TABLE_NAME}` (`name`)\"\n          }\n        ]\n      },\n      {\n        \"tableName\": \"backup\",\n        \"createSql\": \"CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`package_name` TEXT NOT NULL, `backup_name` TEXT NOT NULL, `label` TEXT, `version_name` TEXT, `version_code` INTEGER NOT NULL, `is_system` INTEGER NOT NULL, `has_splits` INTEGER NOT NULL, `has_rules` INTEGER NOT NULL, `backup_time` INTEGER NOT NULL, `crypto` TEXT, `meta_version` INTEGER NOT NULL, `flags` INTEGER NOT NULL, `user_id` INTEGER NOT NULL, `tar_type` TEXT, `has_key_store` INTEGER NOT NULL, `installer_app` TEXT, `info_hash` TEXT, PRIMARY KEY(`backup_name`, `package_name`))\",\n        \"fields\": [\n          {\n            \"fieldPath\": \"packageName\",\n            \"columnName\": \"package_name\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"backupName\",\n            \"columnName\": \"backup_name\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"label\",\n            \"columnName\": \"label\",\n            \"affinity\": \"TEXT\"\n          },\n          {\n            \"fieldPath\": \"versionName\",\n            \"columnName\": \"version_name\",\n            \"affinity\": \"TEXT\"\n          },\n          {\n            \"fieldPath\": \"versionCode\",\n            \"columnName\": \"version_code\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"isSystem\",\n            \"columnName\": \"is_system\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"hasSplits\",\n            \"columnName\": \"has_splits\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"hasRules\",\n            \"columnName\": \"has_rules\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"backupTime\",\n            \"columnName\": \"backup_time\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"crypto\",\n            \"columnName\": \"crypto\",\n            \"affinity\": \"TEXT\"\n          },\n          {\n            \"fieldPath\": \"version\",\n            \"columnName\": \"meta_version\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"flags\",\n            \"columnName\": \"flags\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"userId\",\n            \"columnName\": \"user_id\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"tarType\",\n            \"columnName\": \"tar_type\",\n            \"affinity\": \"TEXT\"\n          },\n          {\n            \"fieldPath\": \"hasKeyStore\",\n            \"columnName\": \"has_key_store\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"installer\",\n            \"columnName\": \"installer_app\",\n            \"affinity\": \"TEXT\"\n          },\n          {\n            \"fieldPath\": \"uuid\",\n            \"columnName\": \"info_hash\",\n            \"affinity\": \"TEXT\"\n          }\n        ],\n        \"primaryKey\": {\n          \"autoGenerate\": false,\n          \"columnNames\": [\n            \"backup_name\",\n            \"package_name\"\n          ]\n        }\n      },\n      {\n        \"tableName\": \"op_history\",\n        \"createSql\": \"CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `type` TEXT NOT NULL, `time` INTEGER NOT NULL, `data` TEXT NOT NULL, `status` TEXT NOT NULL, `extra` TEXT)\",\n        \"fields\": [\n          {\n            \"fieldPath\": \"id\",\n            \"columnName\": \"id\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"type\",\n            \"columnName\": \"type\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"execTime\",\n            \"columnName\": \"time\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"serializedData\",\n            \"columnName\": \"data\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"status\",\n            \"columnName\": \"status\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"serializedExtra\",\n            \"columnName\": \"extra\",\n            \"affinity\": \"TEXT\"\n          }\n        ],\n        \"primaryKey\": {\n          \"autoGenerate\": true,\n          \"columnNames\": [\n            \"id\"\n          ]\n        }\n      },\n      {\n        \"tableName\": \"fm_favorite\",\n        \"createSql\": \"CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `name` TEXT NOT NULL, `uri` TEXT NOT NULL, `init_uri` TEXT, `options` INTEGER NOT NULL, `order` INTEGER NOT NULL, `type` INTEGER NOT NULL)\",\n        \"fields\": [\n          {\n            \"fieldPath\": \"id\",\n            \"columnName\": \"id\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"name\",\n            \"columnName\": \"name\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"uri\",\n            \"columnName\": \"uri\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"initUri\",\n            \"columnName\": \"init_uri\",\n            \"affinity\": \"TEXT\"\n          },\n          {\n            \"fieldPath\": \"options\",\n            \"columnName\": \"options\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"order\",\n            \"columnName\": \"order\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"type\",\n            \"columnName\": \"type\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true\n          }\n        ],\n        \"primaryKey\": {\n          \"autoGenerate\": true,\n          \"columnNames\": [\n            \"id\"\n          ]\n        }\n      },\n      {\n        \"tableName\": \"freeze_type\",\n        \"createSql\": \"CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`package_name` TEXT NOT NULL, `type` INTEGER NOT NULL, PRIMARY KEY(`package_name`))\",\n        \"fields\": [\n          {\n            \"fieldPath\": \"packageName\",\n            \"columnName\": \"package_name\",\n            \"affinity\": \"TEXT\",\n            \"notNull\": true\n          },\n          {\n            \"fieldPath\": \"type\",\n            \"columnName\": \"type\",\n            \"affinity\": \"INTEGER\",\n            \"notNull\": true\n          }\n        ],\n        \"primaryKey\": {\n          \"autoGenerate\": false,\n          \"columnNames\": [\n            \"package_name\"\n          ]\n        }\n      }\n    ],\n    \"setupQueries\": [\n      \"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)\",\n      \"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '3b4a41c98cdc8966b52bd7a0a0f8ad58')\"\n    ]\n  }\n}"
  },
  {
    "path": "app/src/debug/AndroidManifest.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-or-later -->\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <application>\n        <service\n            android:name=\".logcat.CrazyLoggerService\"\n            android:exported=\"false\" />\n    </application>\n</manifest>"
  },
  {
    "path": "app/src/debug/java/io/github/muntashirakon/AppManager/debug/R.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.debug;\n\npublic final class R {\n    public static final class raw {\n        public static final int appops = io.github.muntashirakon.AppManager.docs.R.raw.appops;\n        public static final int custom = io.github.muntashirakon.AppManager.docs.R.raw.custom;\n        public static final int icon = io.github.muntashirakon.AppManager.docs.R.raw.icon;\n        public static final int index = io.github.muntashirakon.AppManager.docs.R.raw.index;\n        public static final int main_page_entry_info_labeled = io.github.muntashirakon.AppManager.docs.R.raw.main_page_entry_info_labeled;\n    }\n}\n"
  },
  {
    "path": "app/src/main/AndroidManifest.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-or-later -->\n<manifest xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:installLocation=\"auto\">\n\n    <uses-feature\n        android:name=\"android.software.leanback\"\n        android:required=\"false\" />\n    <uses-feature\n        android:name=\"android.hardware.touchscreen\"\n        android:required=\"false\" />\n\n    <uses-permission android:name=\"android.permission.ACCESS_HIDDEN_PROFILES\" />\n    <uses-permission android:name=\"android.permission.ACCESS_NETWORK_STATE\" />\n    <uses-permission\n        android:name=\"android.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY\"\n        tools:ignore=\"ProtectedPermissions\" />\n    <uses-permission\n        android:name=\"android.permission.BACKUP\"\n        tools:ignore=\"ProtectedPermissions\" />\n    <uses-permission\n        android:name=\"android.permission.CHANGE_COMPONENT_ENABLED_STATE\"\n        tools:ignore=\"ProtectedPermissions\" />\n    <uses-permission\n        android:name=\"android.permission.CHANGE_OVERLAY_PACKAGES\"\n        tools:ignore=\"ProtectedPermissions\" />\n    <uses-permission\n        android:name=\"android.permission.CLEAR_APP_CACHE\"\n        tools:ignore=\"ProtectedPermissions\" />\n    <uses-permission\n        android:name=\"android.permission.CLEAR_APP_USER_DATA\"\n        tools:ignore=\"ProtectedPermissions\" />\n    <uses-permission\n        android:name=\"android.permission.DELETE_CACHE_FILES\"\n        tools:ignore=\"ProtectedPermissions\" />\n    <uses-permission\n        android:name=\"android.permission.DELETE_PACKAGES\"\n        tools:ignore=\"ProtectedPermissions\" />\n    <uses-permission\n        android:name=\"android.permission.DEVICE_POWER\"\n        tools:ignore=\"ProtectedPermissions\" />\n    <uses-permission\n        android:name=\"android.permission.DUMP\"\n        tools:ignore=\"ProtectedPermissions\" />\n    <uses-permission android:name=\"android.permission.ENFORCE_UPDATE_OWNERSHIP\" />\n    <uses-permission\n        android:name=\"android.permission.FORCE_STOP_PACKAGES\"\n        tools:ignore=\"ProtectedPermissions\" />\n    <uses-permission android:name=\"android.permission.FOREGROUND_SERVICE\" />\n    <uses-permission android:name=\"android.permission.FOREGROUND_SERVICE_DATA_SYNC\" />\n    <uses-permission android:name=\"android.permission.FOREGROUND_SERVICE_SPECIAL_USE\" />\n    <uses-permission\n        android:name=\"android.permission.GET_PACKAGE_SIZE\"\n        android:maxSdkVersion=\"25\" />\n    <uses-permission\n        android:name=\"android.permission.GET_APP_OPS_STATS\"\n        tools:ignore=\"ProtectedPermissions\" />\n    <uses-permission\n        android:name=\"android.permission.GET_RUNTIME_PERMISSIONS\"\n        tools:ignore=\"ProtectedPermissions\" />\n    <!--suppress DeprecatedClassUsageInspection -->\n    <uses-permission android:name=\"android.permission.GET_TASKS\" />\n    <uses-permission\n        android:name=\"android.permission.GRANT_RUNTIME_PERMISSIONS\"\n        tools:ignore=\"ProtectedPermissions\" />\n    <uses-permission\n        android:name=\"android.permission.INJECT_EVENTS\"\n        tools:ignore=\"ProtectedPermissions\" />\n    <uses-permission\n        android:name=\"com.android.permission.INSTALL_EXISTING_PACKAGES\"\n        tools:ignore=\"ProtectedPermissions\" />\n    <uses-permission\n        android:name=\"android.permission.INSTALL_TEST_ONLY_PACKAGE\"\n        tools:ignore=\"ProtectedPermissions\" />\n    <uses-permission\n        android:name=\"android.permission.INSTALL_PACKAGES\"\n        tools:ignore=\"ProtectedPermissions\" />\n    <uses-permission\n        android:name=\"android.permission.INTERACT_ACROSS_USERS\"\n        tools:ignore=\"ProtectedPermissions\" />\n    <uses-permission\n        android:name=\"android.permission.INTERACT_ACROSS_USERS_FULL\"\n        tools:ignore=\"ProtectedPermissions\" />\n    <uses-permission\n        android:name=\"android.permission.INTERNAL_DELETE_CACHE_FILES\"\n        tools:ignore=\"ProtectedPermissions\" />\n    <uses-permission android:name=\"android.permission.INTERNET\" />\n    <uses-permission\n        android:name=\"android.permission.KILL_UID\"\n        tools:ignore=\"ProtectedPermissions\" />\n    <uses-permission\n        android:name=\"android.permission.MANAGE_APP_OPS_MODES\"\n        tools:ignore=\"ProtectedPermissions\" />\n    <uses-permission\n        android:name=\"android.permission.MANAGE_APPOPS\"\n        tools:ignore=\"ProtectedPermissions\" />\n    <uses-permission\n        android:name=\"android.permission.MANAGE_EXTERNAL_STORAGE\"\n        tools:ignore=\"ScopedStorage\" />\n    <uses-permission\n        android:name=\"android.permission.MANAGE_NETWORK_POLICY\"\n        tools:ignore=\"ProtectedPermissions\" />\n    <uses-permission\n        android:name=\"android.permission.MANAGE_NOTIFICATION_LISTENERS\"\n        tools:ignore=\"ProtectedPermissions\" />\n    <uses-permission\n        android:name=\"android.permission.MANAGE_USERS\"\n        tools:ignore=\"ProtectedPermissions\" />\n    <uses-permission\n        android:name=\"android.permission.MANAGE_SENSORS\"\n        tools:ignore=\"ProtectedPermissions\" />\n    <uses-permission\n        android:name=\"android.permission.NETWORK_SETTINGS\"\n        tools:ignore=\"ProtectedPermissions\" />\n    <uses-permission\n        android:name=\"android.permission.PACKAGE_USAGE_STATS\"\n        tools:ignore=\"ProtectedPermissions\" />\n    <uses-permission android:name=\"android.permission.POST_NOTIFICATIONS\" />\n    <uses-permission\n        android:name=\"android.permission.QUERY_ALL_PACKAGES\"\n        tools:ignore=\"QueryAllPackagesPermission\" />\n    <uses-permission android:name=\"android.permission.READ_EXTERNAL_STORAGE\" />\n    <uses-permission\n        android:name=\"android.permission.READ_LOGS\"\n        tools:ignore=\"ProtectedPermissions\" />\n    <uses-permission android:name=\"android.permission.READ_PHONE_STATE\" />\n    <uses-permission\n        android:name=\"android.permission.REAL_GET_TASKS\"\n        tools:ignore=\"ProtectedPermissions\" />\n    <uses-permission android:name=\"android.permission.RECEIVE_BOOT_COMPLETED\" />\n    <uses-permission android:name=\"android.permission.REQUEST_DELETE_PACKAGES\" />\n    <uses-permission android:name=\"android.permission.REQUEST_INSTALL_PACKAGES\" />\n    <uses-permission\n        android:name=\"android.permission.REVOKE_RUNTIME_PERMISSIONS\"\n        tools:ignore=\"ProtectedPermissions\" />\n    <uses-permission\n        android:name=\"android.permission.START_ANY_ACTIVITY\"\n        tools:ignore=\"ProtectedPermissions\" />\n    <uses-permission\n        android:name=\"android.permission.SUSPEND_APPS\"\n        tools:ignore=\"ProtectedPermissions\" />\n    <uses-permission android:name=\"android.permission.SYSTEM_ALERT_WINDOW\" />\n    <uses-permission\n        android:name=\"android.permission.UPDATE_APP_OPS_STATS\"\n        tools:ignore=\"ProtectedPermissions\" />\n    <uses-permission\n        android:name=\"android.permission.UPDATE_DOMAIN_VERIFICATION_USER_SELECTION\"\n        tools:ignore=\"ProtectedPermissions\" />\n    <uses-permission android:name=\"android.permission.UPDATE_PACKAGES_WITHOUT_USER_ACTION\" />\n    <uses-permission android:name=\"android.permission.WAKE_LOCK\" />\n    <uses-permission android:name=\"android.permission.WRITE_EXTERNAL_STORAGE\" />\n    <uses-permission\n        android:name=\"android.permission.WRITE_SECURE_SETTINGS\"\n        tools:ignore=\"ProtectedPermissions\" />\n    <uses-permission android:name=\"com.android.launcher.permission.INSTALL_SHORTCUT\" />\n    <uses-permission android:name=\"com.termux.permission.RUN_COMMAND\" />\n\n    <application\n        android:name=\".AppManager\"\n        android:allowBackup=\"true\"\n        android:banner=\"@mipmap/ic_banner\"\n        android:dataExtractionRules=\"@xml/backup_rules\"\n        android:fullBackupContent=\"@xml/full_backup_rules\"\n        android:hasFragileUserData=\"true\"\n        android:icon=\"@mipmap/ic_launcher\"\n        android:label=\"@string/app_name\"\n        android:largeHeap=\"true\"\n        android:localeConfig=\"@xml/locales_config\"\n        android:networkSecurityConfig=\"@xml/network_security_config\"\n        android:requestLegacyExternalStorage=\"true\"\n        android:roundIcon=\"@mipmap/ic_launcher_round\"\n        android:supportsRtl=\"true\"\n        android:theme=\"@style/AppTheme\"\n        tools:ignore=\"UnusedAttribute\">\n        <activity\n            android:name=\".filters.FinderActivity\"\n            android:enableOnBackInvokedCallback=\"true\"\n            android:exported=\"false\"\n            android:label=\"@string/finder_title\" />\n        <activity\n            android:name=\".oneclickops.OneClickOpsActivity\"\n            android:enableOnBackInvokedCallback=\"true\"\n            android:exported=\"false\"\n            android:label=\"@string/one_click_ops\" />\n        <activity\n            android:name=\".runningapps.RunningAppsActivity\"\n            android:enableOnBackInvokedCallback=\"true\"\n            android:exported=\"true\"\n            android:label=\"@string/running_apps\" />\n        <activity\n            android:name=\".settings.SettingsActivity\"\n            android:enableOnBackInvokedCallback=\"true\"\n            android:exported=\"true\"\n            android:label=\"@string/app_settings\"\n            android:launchMode=\"singleTop\">\n            <intent-filter>\n                <action android:name=\"android.intent.action.APPLICATION_PREFERENCES\" />\n\n                <category android:name=\"android.intent.category.DEFAULT\" />\n            </intent-filter>\n            <intent-filter>\n                <action android:name=\"android.intent.action.VIEW\" />\n\n                <category android:name=\"android.intent.category.DEFAULT\" />\n                <category android:name=\"android.intent.category.BROWSABLE\" />\n\n                <data android:scheme=\"app-manager\" />\n                <data android:host=\"settings\" />\n            </intent-filter>\n        </activity>\n        <activity\n            android:name=\".sharedpref.SharedPrefsActivity\"\n            android:enableOnBackInvokedCallback=\"true\"\n            android:exported=\"false\"\n            android:taskAffinity=\"\" />\n        <activity\n            android:name=\".usage.AppUsageActivity\"\n            android:enableOnBackInvokedCallback=\"true\"\n            android:exported=\"true\" />\n        <activity\n            android:name=\".editor.CodeEditorActivity\"\n            android:configChanges=\"keyboard|keyboardHidden|locale|orientation|screenLayout|screenSize|smallestScreenSize|uiMode\"\n            android:enableOnBackInvokedCallback=\"true\"\n            android:exported=\"false\"\n            android:label=\"@string/title_code_editor\"\n            android:taskAffinity=\".editor.CodeEditorActivity\"\n            android:windowSoftInputMode=\"adjustResize\" />\n\n        <activity-alias\n            android:name=\".editor.EditorActivity\"\n            android:configChanges=\"orientation|keyboardHidden|screenSize|uiMode\"\n            android:exported=\"true\"\n            android:label=\"@string/title_code_editor\"\n            android:targetActivity=\".editor.CodeEditorActivity\"\n            android:taskAffinity=\".editor.CodeEditorActivity\"\n            android:windowSoftInputMode=\"adjustResize\">\n            <intent-filter>\n                <action android:name=\"android.intent.action.SEND\" />\n\n                <category android:name=\"android.intent.category.DEFAULT\" />\n                <category android:name=\"android.intent.category.ALTERNATIVE\" />\n\n                <data android:mimeType=\"text/*\" />\n                <data android:mimeType=\"application/axml\" />\n                <data android:mimeType=\"application/json\" />\n                <data android:mimeType=\"application/xml\" />\n            </intent-filter>\n            <intent-filter>\n                <action android:name=\"android.intent.action.VIEW\" />\n                <action android:name=\"android.intent.action.EDIT\" />\n\n                <category android:name=\"android.intent.category.DEFAULT\" />\n\n                <data android:scheme=\"file\" />\n                <data android:scheme=\"content\" />\n                <data android:mimeType=\"text/*\" />\n                <data android:mimeType=\"application/xml\" />\n                <data android:mimeType=\"application/xhtml+xml\" />\n                <data android:mimeType=\"application/vnd.wap.xhtml+xml\" />\n                <data android:mimeType=\"application/javascript\" />\n                <data android:mimeType=\"application/json\" />\n                <data android:mimeType=\"application/x-php\" />\n                <data android:mimeType=\"application/x-httpd-php\" />\n                <data android:mimeType=\"application/x-tcl\" />\n                <data android:mimeType=\"application/x-sh\" />\n                <data android:mimeType=\"application/x-csh\" />\n                <data android:mimeType=\"application/bat\" />\n                <data android:mimeType=\"application/mpegurl\" />\n                <data android:mimeType=\"application/x-mpegurl\" />\n                <data android:mimeType=\"application/x-bittorrent\" />\n                <data android:mimeType=\"application/vnd.google-earth.kml+xml\" />\n                <data android:mimeType=\"application/vnd.google-earth.kmz\" />\n                <data android:mimeType=\"application/x-sql\" />\n                <data android:mimeType=\"application/x-latex\" />\n                <data android:mimeType=\"application/x-subrip\" />\n                <data android:mimeType=\"application/x-yaml\" />\n                <data android:mimeType=\"application/axml\" />\n            </intent-filter>\n            <intent-filter>\n                <action android:name=\"android.intent.action.VIEW\" />\n                <action android:name=\"android.intent.action.EDIT\" />\n\n                <category android:name=\"android.intent.category.DEFAULT\" />\n\n                <data android:scheme=\"file\" />\n                <data android:scheme=\"content\" />\n                <data android:pathPattern=\"/.*\\.TXT\" />\n                <data android:pathPattern=\"/.*\\.txt\" />\n                <data android:pathPattern=\"/.*\\.txt?.*\" />\n                <data android:pathPattern=\"/.*\\..*\\.TXT\" />\n                <data android:pathPattern=\"/.*\\..*\\.txt\" />\n                <data android:pathPattern=\"/.*\\..*\\.txt?.*\" />\n                <data android:pathPattern=\"/.*\\.tex\" />\n                <data android:pathPattern=\"/.*\\.tex?.*\" />\n                <data android:pathPattern=\"/.*\\.micfg\" />\n                <data android:pathPattern=\"/.*\\.micfg?.*\" />\n                <data android:pathPattern=\"/.*\\..*\\.micfg\" />\n                <data android:pathPattern=\"/.*\\..*\\.micfg?.*\" />\n                <data android:pathPattern=\"/.*\\.mic\" />\n                <data android:pathPattern=\"/.*\\.mic?.*\" />\n                <data android:pathPattern=\"/.*\\..*\\.mic\" />\n                <data android:pathPattern=\"/.*\\..*\\.mic?.*\" />\n                <data android:pathPattern=\"/.*\\.JAVA\" />\n                <data android:pathPattern=\"/.*\\.java\" />\n                <data android:pathPattern=\"/.*\\.java?.*\" />\n                <data android:pathPattern=\"/.*\\..*\\.JAVA\" />\n                <data android:pathPattern=\"/.*\\..*\\.java\" />\n                <data android:pathPattern=\"/.*\\..*\\.java?.*\" />\n                <data android:pathPattern=\"/.*\\.KT\" />\n                <data android:pathPattern=\"/.*\\.kt\" />\n                <data android:pathPattern=\"/.*\\.kt?.*\" />\n                <data android:pathPattern=\"/.*\\..*\\.KT\" />\n                <data android:pathPattern=\"/.*\\..*\\.kt\" />\n                <data android:pathPattern=\"/.*\\..*\\.kt?.*\" />\n                <data android:pathPattern=\"/.*\\.KTS\" />\n                <data android:pathPattern=\"/.*\\.kts\" />\n                <data android:pathPattern=\"/.*\\.kts?.*\" />\n                <data android:pathPattern=\"/.*\\..*\\.KTS\" />\n                <data android:pathPattern=\"/.*\\..*\\.kts\" />\n                <data android:pathPattern=\"/.*\\..*\\.kts?.*\" />\n                <data android:pathPattern=\"/.*\\.SMALI\" />\n                <data android:pathPattern=\"/.*\\.smali\" />\n                <data android:pathPattern=\"/.*\\.smali?.*\" />\n                <data android:pathPattern=\"/.*\\..*\\.SMALI\" />\n                <data android:pathPattern=\"/.*\\..*\\.smali\" />\n                <data android:pathPattern=\"/.*\\..*\\.smali?.*\" />\n                <data android:pathPattern=\"/.*\\.CSS\" />\n                <data android:pathPattern=\"/.*\\.css\" />\n                <data android:pathPattern=\"/.*\\.css?.*\" />\n                <data android:pathPattern=\"/.*\\..*\\.CSS\" />\n                <data android:pathPattern=\"/.*\\..*\\.css\" />\n                <data android:pathPattern=\"/.*\\..*\\.css?.*\" />\n                <data android:pathPattern=\"/.*\\.HTM\" />\n                <data android:pathPattern=\"/.*\\.htm\" />\n                <data android:pathPattern=\"/.*\\.htm?.*\" />\n                <data android:pathPattern=\"/.*\\..*\\.HTM\" />\n                <data android:pathPattern=\"/.*\\..*\\.htm\" />\n                <data android:pathPattern=\"/.*\\..*\\.htm?.*\" />\n                <data android:pathPattern=\"/.*\\.HTML\" />\n                <data android:pathPattern=\"/.*\\.html\" />\n                <data android:pathPattern=\"/.*\\.html?.*\" />\n                <data android:pathPattern=\"/.*\\..*\\.HTML\" />\n                <data android:pathPattern=\"/.*\\..*\\.html\" />\n                <data android:pathPattern=\"/.*\\..*\\.html?.*\" />\n                <data android:pathPattern=\"/.*\\.PROP\" />\n                <data android:pathPattern=\"/.*\\.prop\" />\n                <data android:pathPattern=\"/.*\\.prop?.*\" />\n                <data android:pathPattern=\"/.*\\..*\\.PROP\" />\n                <data android:pathPattern=\"/.*\\..*\\.prop\" />\n                <data android:pathPattern=\"/.*\\..*\\.prop?.*\" />\n                <data android:pathPattern=\"/.*\\.SQL\" />\n                <data android:pathPattern=\"/.*\\.sql\" />\n                <data android:pathPattern=\"/.*\\.sql?.*\" />\n                <data android:pathPattern=\"/.*\\..*\\.SQL\" />\n                <data android:pathPattern=\"/.*\\..*\\.sql\" />\n                <data android:pathPattern=\"/.*\\..*\\.sql?.*\" />\n                <data android:pathPattern=\"/.*\\.TORRENT\" />\n                <data android:pathPattern=\"/.*\\.torrent\" />\n                <data android:pathPattern=\"/.*\\.torrent?.*\" />\n                <data android:pathPattern=\"/.*\\..*\\.TORRENT\" />\n                <data android:pathPattern=\"/.*\\..*\\.torrent\" />\n                <data android:pathPattern=\"/.*\\..*\\.torrent?.*\" />\n                <data android:pathPattern=\"/.*\\.XML\" />\n                <data android:pathPattern=\"/.*\\.xml\" />\n                <data android:pathPattern=\"/.*\\.xml?.*\" />\n                <data android:pathPattern=\"/.*\\..*\\.XML\" />\n                <data android:pathPattern=\"/.*\\..*\\.xml\" />\n                <data android:pathPattern=\"/.*\\..*\\.xml?.*\" />\n                <data android:pathPattern=\"/.*\\.GPG\" />\n                <data android:pathPattern=\"/.*\\.gpg\" />\n                <data android:pathPattern=\"/.*\\.gpg?.*\" />\n                <data android:pathPattern=\"/.*\\..*\\.GPG\" />\n                <data android:pathPattern=\"/.*\\..*\\.gpg\" />\n                <data android:pathPattern=\"/.*\\..*\\.gpg?.*\" />\n            </intent-filter>\n        </activity-alias>\n\n        <activity\n            android:name=\".scanner.ScannerActivity\"\n            android:enableOnBackInvokedCallback=\"true\"\n            android:exported=\"true\"\n            android:label=\"@string/scanner\">\n            <intent-filter>\n                <action android:name=\"android.intent.action.SEND\" />\n\n                <category android:name=\"android.intent.category.DEFAULT\" />\n\n                <data android:mimeType=\"application/vnd.android.package-archive\" />\n                <data android:mimeType=\"application/octet-stream\" />\n            </intent-filter>\n            <intent-filter>\n                <action android:name=\"android.intent.action.VIEW\" />\n\n                <category android:name=\"android.intent.category.DEFAULT\" />\n                <category android:name=\"android.intent.category.BROWSABLE\" />\n\n                <data android:scheme=\"file\" />\n                <data android:scheme=\"content\" />\n                <data android:host=\"*\" />\n                <data android:mimeType=\"application/vnd.android.package-archive\" />\n                <data android:mimeType=\"application/octet-stream\" />\n            </intent-filter>\n        </activity>\n        <activity\n            android:name=\".viewer.ExplorerActivity\"\n            android:enableOnBackInvokedCallback=\"false\"\n            android:enabled=\"true\"\n            android:exported=\"true\"\n            android:label=\"@string/explore\"\n            android:noHistory=\"true\"\n            android:theme=\"@style/AppTheme.TransparentBackground\">\n            <intent-filter>\n                <action android:name=\"android.intent.action.SEND\" />\n\n                <category android:name=\"android.intent.category.DEFAULT\" />\n\n                <data android:mimeType=\"application/vnd.android.package-archive\" />\n                <data android:mimeType=\"application/java-archive\" />\n                <data android:mimeType=\"application/x-dex\" />\n                <data android:mimeType=\"application/octet-stream\" />\n                <data android:mimeType=\"application/zip\" />\n            </intent-filter>\n            <intent-filter>\n                <action android:name=\"android.intent.action.VIEW\" />\n\n                <category android:name=\"android.intent.category.DEFAULT\" />\n                <category android:name=\"android.intent.category.BROWSABLE\" />\n\n                <data android:scheme=\"file\" />\n                <data android:scheme=\"content\" />\n                <data android:host=\"*\" />\n                <data android:mimeType=\"application/vnd.android.package-archive\" />\n                <data android:mimeType=\"application/java-archive\" />\n                <data android:mimeType=\"application/x-dex\" />\n                <data android:mimeType=\"application/octet-stream\" />\n                <data android:mimeType=\"application/zip\" />\n            </intent-filter>\n        </activity>\n        <activity\n            android:name=\".main.MainActivity\"\n            android:enableOnBackInvokedCallback=\"true\"\n            android:exported=\"true\">\n            <intent-filter android:label=\"@string/search\">\n                <action android:name=\"android.intent.action.VIEW\" />\n\n                <category android:name=\"android.intent.category.DEFAULT\" />\n                <category android:name=\"android.intent.category.BROWSABLE\" />\n\n                <data\n                    android:host=\"search\"\n                    android:scheme=\"market\" />\n            </intent-filter>\n        </activity>\n        <activity\n            android:name=\".terminal.TermActivity\"\n            android:enableOnBackInvokedCallback=\"true\"\n            android:exported=\"false\"\n            android:label=\"@string/title_terminal_emulator\"\n            android:taskAffinity=\"\"\n            android:windowSoftInputMode=\"stateUnchanged\" />\n        <activity\n            android:name=\".accessibility.activity.LeadingActivityTrackerActivity\"\n            android:enableOnBackInvokedCallback=\"false\"\n            android:excludeFromRecents=\"true\"\n            android:exported=\"false\"\n            android:label=\"@string/title_ui_tracker\"\n            android:theme=\"@style/AppTheme.TransparentBackground\" />\n        <activity\n            android:name=\".misc.LabsActivity\"\n            android:enableOnBackInvokedCallback=\"true\"\n            android:exported=\"true\"\n            android:label=\"@string/title_labs_activity\" />\n\n        <activity-alias\n            android:name=\".apk.installer.AppInfoActivity\"\n            android:exported=\"true\"\n            android:label=\"@string/app_info\"\n            android:targetActivity=\".details.AppDetailsActivity\">\n            <intent-filter>\n                <action android:name=\"android.intent.action.SHOW_APP_INFO\" />\n\n                <category android:name=\"android.intent.category.DEFAULT\" />\n            </intent-filter>\n        </activity-alias>\n\n        <activity-alias\n            android:name=\".details.AppInfoActivity\"\n            android:exported=\"true\"\n            android:label=\"@string/app_info\"\n            android:targetActivity=\".details.AppDetailsActivity\">\n            <intent-filter>\n                <action android:name=\"android.intent.action.VIEW\" />\n\n                <category android:name=\"android.intent.category.DEFAULT\" />\n                <category android:name=\"android.intent.category.BROWSABLE\" />\n\n                <data\n                    android:host=\"details\"\n                    android:scheme=\"app-manager\" />\n            </intent-filter>\n            <intent-filter>\n                <action android:name=\"android.intent.action.SEND\" />\n\n                <category android:name=\"android.intent.category.DEFAULT\" />\n\n                <data android:mimeType=\"application/vnd.android.package-archive\" />\n                <data android:mimeType=\"application/vnd.apkm\" />\n                <data android:mimeType=\"application/xapk-package-archive\" />\n                <data android:mimeType=\"application/octet-stream\" />\n            </intent-filter>\n            <intent-filter>\n                <action android:name=\"android.intent.action.VIEW\" />\n\n                <category android:name=\"android.intent.category.DEFAULT\" />\n                <category android:name=\"android.intent.category.BROWSABLE\" />\n\n                <data android:scheme=\"file\" />\n                <data android:scheme=\"content\" />\n                <data android:host=\"*\" />\n                <data android:mimeType=\"application/vnd.android.package-archive\" />\n                <data android:mimeType=\"application/vnd.apkm\" />\n                <data android:mimeType=\"application/xapk-package-archive\" />\n                <data android:mimeType=\"application/octet-stream\" />\n            </intent-filter>\n            <intent-filter>\n                <action android:name=\"android.intent.action.VIEW\" />\n\n                <category android:name=\"android.intent.category.DEFAULT\" />\n                <category android:name=\"android.intent.category.BROWSABLE\" />\n\n                <data android:scheme=\"file\" />\n                <data android:scheme=\"content\" />\n                <data android:host=\"*\" />\n                <data android:mimeType=\"*/*\" />\n                <data android:pathPattern=\".*\\\\.apkm\" />\n                <data android:pathPattern=\".*\\\\..*\\\\.apkm\" />\n                <data android:pathPattern=\".*\\\\..*\\\\..*\\\\.apkm\" />\n                <data android:pathPattern=\".*\\\\..*\\\\..*\\\\..*\\\\.apkm\" />\n                <data android:pathPattern=\".*\\\\..*\\\\..*\\\\..*\\\\..*\\\\.apkm\" />\n                <data android:pathPattern=\".*\\\\..*\\\\..*\\\\..*\\\\..*\\\\..*\\\\.apkm\" />\n                <data android:pathPattern=\".*\\\\..*\\\\..*\\\\..*\\\\..*\\\\..*\\\\..*\\\\.apkm\" />\n                <data android:pathPattern=\".*\\\\.apks\" />\n                <data android:pathPattern=\".*\\\\..*\\\\.apks\" />\n                <data android:pathPattern=\".*\\\\..*\\\\..*\\\\.apks\" />\n                <data android:pathPattern=\".*\\\\..*\\\\..*\\\\..*\\\\.apks\" />\n                <data android:pathPattern=\".*\\\\..*\\\\..*\\\\..*\\\\..*\\\\.apks\" />\n                <data android:pathPattern=\".*\\\\..*\\\\..*\\\\..*\\\\..*\\\\..*\\\\.apks\" />\n                <data android:pathPattern=\".*\\\\..*\\\\..*\\\\..*\\\\..*\\\\..*\\\\..*\\\\.apks\" />\n                <data android:pathPattern=\".*\\\\.xapk\" />\n                <data android:pathPattern=\".*\\\\..*\\\\.xapk\" />\n                <data android:pathPattern=\".*\\\\..*\\\\..*\\\\.xapk\" />\n                <data android:pathPattern=\".*\\\\..*\\\\..*\\\\..*\\\\.xapk\" />\n                <data android:pathPattern=\".*\\\\..*\\\\..*\\\\..*\\\\..*\\\\.xapk\" />\n                <data android:pathPattern=\".*\\\\..*\\\\..*\\\\..*\\\\..*\\\\..*\\\\.xapk\" />\n                <data android:pathPattern=\".*\\\\..*\\\\..*\\\\..*\\\\..*\\\\..*\\\\..*\\\\.xapk\" />\n            </intent-filter>\n        </activity-alias>\n\n        <activity\n            android:name=\".debloat.DebloaterActivity\"\n            android:enableOnBackInvokedCallback=\"true\"\n            android:exported=\"false\"\n            android:label=\"@string/debloater_title\" />\n        <activity\n            android:name=\".details.AppDetailsActivity\"\n            android:enableOnBackInvokedCallback=\"true\"\n            android:exported=\"false\" />\n        <activity\n            android:name=\".details.manifest.ManifestViewerActivity\"\n            android:enableOnBackInvokedCallback=\"true\"\n            android:exported=\"true\"\n            android:label=\"@string/manifest_viewer\">\n            <intent-filter>\n                <action android:name=\"android.intent.action.SEND\" />\n\n                <category android:name=\"android.intent.category.DEFAULT\" />\n\n                <data android:mimeType=\"application/vnd.android.package-archive\" />\n                <data android:mimeType=\"application/octet-stream\" />\n            </intent-filter>\n            <intent-filter>\n                <action android:name=\"android.intent.action.VIEW\" />\n\n                <category android:name=\"android.intent.category.DEFAULT\" />\n                <category android:name=\"android.intent.category.BROWSABLE\" />\n\n                <data android:scheme=\"file\" />\n                <data android:scheme=\"content\" />\n                <data android:host=\"*\" />\n                <data android:mimeType=\"application/vnd.android.package-archive\" />\n                <data android:mimeType=\"application/octet-stream\" />\n            </intent-filter>\n        </activity>\n        <activity\n            android:name=\".apk.installer.PackageInstallerActivity\"\n            android:enableOnBackInvokedCallback=\"false\"\n            android:excludeFromRecents=\"true\"\n            android:exported=\"true\"\n            android:label=\"@string/install\"\n            android:launchMode=\"singleInstance\"\n            android:taskAffinity=\"\"\n            android:theme=\"@style/AppTheme.TransparentBackground\">\n            <intent-filter>\n                <action android:name=\"android.intent.action.SEND\" />\n\n                <category android:name=\"android.intent.category.DEFAULT\" />\n\n                <data android:mimeType=\"application/vnd.android.package-archive\" />\n                <data android:mimeType=\"application/vnd.apkm\" />\n                <data android:mimeType=\"application/xapk-package-archive\" />\n                <data android:mimeType=\"application/octet-stream\" />\n            </intent-filter>\n            <intent-filter>\n                <action android:name=\"android.intent.action.SEND_MULTIPLE\" />\n\n                <category android:name=\"android.intent.category.DEFAULT\" />\n\n                <data android:mimeType=\"*/*\" />\n            </intent-filter>\n            <intent-filter>\n                <action android:name=\"android.intent.action.VIEW\" />\n                <action android:name=\"android.intent.action.INSTALL_PACKAGE\" />\n\n                <category android:name=\"android.intent.category.DEFAULT\" />\n                <category android:name=\"android.intent.category.BROWSABLE\" />\n\n                <data android:scheme=\"file\" />\n                <data android:scheme=\"content\" />\n                <data android:host=\"*\" />\n                <data android:mimeType=\"application/vnd.android.package-archive\" />\n                <data android:mimeType=\"application/vnd.apkm\" />\n                <data android:mimeType=\"application/xapk-package-archive\" />\n                <data android:mimeType=\"application/octet-stream\" />\n            </intent-filter>\n            <intent-filter>\n                <action android:name=\"android.intent.action.INSTALL_PACKAGE\" />\n\n                <category android:name=\"android.intent.category.DEFAULT\" />\n\n                <data android:scheme=\"content\" />\n                <data android:scheme=\"package\" />\n            </intent-filter>\n            <intent-filter>\n                <action android:name=\"android.intent.action.VIEW\" />\n\n                <category android:name=\"android.intent.category.DEFAULT\" />\n                <category android:name=\"android.intent.category.BROWSABLE\" />\n\n                <data android:scheme=\"file\" />\n                <data android:scheme=\"content\" />\n                <data android:host=\"*\" />\n                <data android:mimeType=\"*/*\" />\n                <data android:pathPattern=\".*\\\\.apkm\" />\n                <data android:pathPattern=\".*\\\\..*\\\\.apkm\" />\n                <data android:pathPattern=\".*\\\\..*\\\\..*\\\\.apkm\" />\n                <data android:pathPattern=\".*\\\\..*\\\\..*\\\\..*\\\\.apkm\" />\n                <data android:pathPattern=\".*\\\\..*\\\\..*\\\\..*\\\\..*\\\\.apkm\" />\n                <data android:pathPattern=\".*\\\\..*\\\\..*\\\\..*\\\\..*\\\\..*\\\\.apkm\" />\n                <data android:pathPattern=\".*\\\\..*\\\\..*\\\\..*\\\\..*\\\\..*\\\\..*\\\\.apkm\" />\n                <data android:pathPattern=\".*\\\\.apks\" />\n                <data android:pathPattern=\".*\\\\..*\\\\.apks\" />\n                <data android:pathPattern=\".*\\\\..*\\\\..*\\\\.apks\" />\n                <data android:pathPattern=\".*\\\\..*\\\\..*\\\\..*\\\\.apks\" />\n                <data android:pathPattern=\".*\\\\..*\\\\..*\\\\..*\\\\..*\\\\.apks\" />\n                <data android:pathPattern=\".*\\\\..*\\\\..*\\\\..*\\\\..*\\\\..*\\\\.apks\" />\n                <data android:pathPattern=\".*\\\\..*\\\\..*\\\\..*\\\\..*\\\\..*\\\\..*\\\\.apks\" />\n                <data android:pathPattern=\".*\\\\.xapk\" />\n                <data android:pathPattern=\".*\\\\..*\\\\.xapk\" />\n                <data android:pathPattern=\".*\\\\..*\\\\..*\\\\.xapk\" />\n                <data android:pathPattern=\".*\\\\..*\\\\..*\\\\..*\\\\.xapk\" />\n                <data android:pathPattern=\".*\\\\..*\\\\..*\\\\..*\\\\..*\\\\.xapk\" />\n                <data android:pathPattern=\".*\\\\..*\\\\..*\\\\..*\\\\..*\\\\..*\\\\.xapk\" />\n                <data android:pathPattern=\".*\\\\..*\\\\..*\\\\..*\\\\..*\\\\..*\\\\..*\\\\.xapk\" />\n            </intent-filter>\n        </activity>\n        <activity\n            android:name=\".crypto.OpenPGPCryptoActivity\"\n            android:enableOnBackInvokedCallback=\"false\"\n            android:excludeFromRecents=\"true\"\n            android:exported=\"false\"\n            android:launchMode=\"singleInstance\"\n            android:taskAffinity=\"\"\n            android:theme=\"@style/AppTheme.TransparentBackground\" />\n        <activity\n            android:name=\".crypto.ks.KeyStoreActivity\"\n            android:enableOnBackInvokedCallback=\"false\"\n            android:excludeFromRecents=\"true\"\n            android:exported=\"false\"\n            android:launchMode=\"singleInstance\"\n            android:taskAffinity=\"\"\n            android:theme=\"@style/AppTheme.TransparentBackground\" />\n        <activity\n            android:name=\".profiles.ProfilesActivity\"\n            android:enableOnBackInvokedCallback=\"true\"\n            android:exported=\"true\"\n            android:label=\"@string/profiles\" />\n        <activity\n            android:name=\".profiles.AppsProfileActivity\"\n            android:enableOnBackInvokedCallback=\"true\"\n            android:exported=\"false\" />\n        <activity\n            android:name=\".profiles.AppsFilterProfileActivity\"\n            android:enableOnBackInvokedCallback=\"true\"\n            android:exported=\"false\" />\n        <activity\n            android:name=\".sysconfig.SysConfigActivity\"\n            android:enableOnBackInvokedCallback=\"true\"\n            android:exported=\"false\"\n            android:label=\"@string/sys_config\" />\n        <activity\n            android:name=\".batchops.BatchOpsResultsActivity\"\n            android:enableOnBackInvokedCallback=\"true\"\n            android:excludeFromRecents=\"true\"\n            android:exported=\"false\"\n            android:launchMode=\"singleInstance\"\n            android:taskAffinity=\"\" />\n        <activity\n            android:name=\".history.ops.OpHistoryActivity\"\n            android:enableOnBackInvokedCallback=\"true\"\n            android:exported=\"true\"\n            android:icon=\"@drawable/ic_history\"\n            android:label=\"@string/op_history\" />\n        <activity\n            android:name=\".intercept.ActivityInterceptor\"\n            android:enableOnBackInvokedCallback=\"true\"\n            android:enabled=\"true\"\n            android:exported=\"true\"\n            android:label=\"@string/interceptor\"\n            android:taskAffinity=\"\"\n            android:windowSoftInputMode=\"stateUnchanged\">\n\n            <!-- matching any given mime type -->\n            <intent-filter tools:ignore=\"AppLinkUrlError\">\n                <action android:name=\"android.intent.action.APPLICATION_PREFERENCES\" />\n                <action android:name=\"android.service.quicksettings.action.QS_TILE\" />\n                <action android:name=\"android.intent.action.VIEW\" />\n                <action android:name=\"android.intent.action.EDIT\" />\n                <action android:name=\"android.intent.action.PICK\" />\n                <action android:name=\"android.intent.action.GET_CONTENT\" />\n                <action android:name=\"android.intent.action.CREATE_DOCUMENT\" />\n                <action android:name=\"android.intent.action.OPEN_DOCUMENT\" />\n                <action android:name=\"android.intent.action.OPEN_DOCUMENT_TREE\" />\n                <action android:name=\"android.intent.action.INSERT\" />\n                <action android:name=\"android.intent.action.INSERT_OR_EDIT\" />\n                <action android:name=\"android.intent.action.CALL_BUTTON\" />\n                <action android:name=\"android.intent.action.DIAL\" />\n                <!-- Used by camera to view photo taken -->\n                <action android:name=\"android.provider.action.REVIEW\" />\n                <action android:name=\"android.provider.action.REVIEW_SECURE\" />\n                <action android:name=\"com.android.camera.action.REVIEW\" />\n                <action android:name=\"com.android.camera.action.SPLIT_SCREEN_REVIEW\" />\n\n                <category android:name=\"android.intent.category.DEFAULT\" />\n                <category android:name=\"android.intent.category.BROWSABLE\" />\n                <category android:name=\"android.intent.category.OPENABLE\" />\n\n                <data android:mimeType=\"*/*\" />\n            </intent-filter>\n            <!-- same as above matching when no mime type is available (null) -->\n            <intent-filter tools:ignore=\"AppLinkUrlError\">\n                <action android:name=\"android.intent.action.APPLICATION_PREFERENCES\" />\n                <action android:name=\"android.service.quicksettings.action.QS_TILE\" />\n                <action android:name=\"android.intent.action.VIEW\" />\n                <action android:name=\"android.intent.action.EDIT\" />\n                <action android:name=\"android.intent.action.PICK\" />\n                <action android:name=\"android.intent.action.GET_CONTENT\" />\n                <action android:name=\"android.intent.action.CREATE_DOCUMENT\" />\n                <action android:name=\"android.intent.action.OPEN_DOCUMENT\" />\n                <action android:name=\"android.intent.action.OPEN_DOCUMENT_TREE\" />\n                <action android:name=\"android.intent.action.INSERT\" />\n                <action android:name=\"android.intent.action.INSERT_OR_EDIT\" />\n                <action android:name=\"android.intent.action.CALL_BUTTON\" />\n                <action android:name=\"android.intent.action.DIAL\" />\n                <!-- Used by camera to view photo taken -->\n                <action android:name=\"android.provider.action.REVIEW\" />\n                <action android:name=\"android.provider.action.REVIEW_SECURE\" />\n                <action android:name=\"com.android.camera.action.REVIEW\" />\n                <action android:name=\"com.android.camera.action.SPLIT_SCREEN_REVIEW\" />\n\n                <category android:name=\"android.intent.category.DEFAULT\" />\n                <category android:name=\"android.intent.category.BROWSABLE\" />\n                <category android:name=\"android.intent.category.OPENABLE\" />\n            </intent-filter>\n            <!-- scheme-intents without mime (mime==null) -->\n            <intent-filter>\n                <action android:name=\"android.intent.action.APPLICATION_PREFERENCES\" />\n                <action android:name=\"android.service.quicksettings.action.QS_TILE\" />\n                <action android:name=\"android.intent.action.VIEW\" />\n                <action android:name=\"android.intent.action.EDIT\" />\n                <action android:name=\"android.intent.action.PICK\" />\n                <action android:name=\"android.intent.action.GET_CONTENT\" />\n                <action android:name=\"android.intent.action.CREATE_DOCUMENT\" />\n                <action android:name=\"android.intent.action.OPEN_DOCUMENT\" />\n                <action android:name=\"android.intent.action.OPEN_DOCUMENT_TREE\" />\n                <action android:name=\"android.intent.action.INSERT\" />\n                <action android:name=\"android.intent.action.INSERT_OR_EDIT\" />\n                <action android:name=\"android.intent.action.CALL_BUTTON\" />\n                <action android:name=\"android.intent.action.DIAL\" />\n                <!-- Used by camera to view photo taken -->\n                <action android:name=\"android.provider.action.REVIEW\" />\n                <action android:name=\"android.provider.action.REVIEW_SECURE\" />\n                <action android:name=\"com.android.camera.action.REVIEW\" />\n                <action android:name=\"com.android.camera.action.SPLIT_SCREEN_REVIEW\" />\n\n                <category android:name=\"android.intent.category.DEFAULT\" />\n                <category android:name=\"android.intent.category.BROWSABLE\" />\n                <category android:name=\"android.intent.category.OPENABLE\" />\n\n                <data android:scheme=\"http\" />\n                <data android:scheme=\"https\" />\n                <data android:scheme=\"about\" />\n                <data android:scheme=\"javascript\" />\n                <data android:scheme=\"mailto\" />\n                <data android:scheme=\"geo\" />\n                <data android:scheme=\"file\" />\n                <data android:scheme=\"content\" />\n\n                <data android:scheme=\"rtsp\" />\n                <data android:scheme=\"rtmp\" />\n                <data android:scheme=\"ftp\" />\n                <data android:scheme=\"sftp\" />\n\n                <data android:scheme=\"skype\" />\n                <data android:scheme=\"sms\" />\n                <data android:scheme=\"smsto\" />\n                <data android:scheme=\"mms\" />\n                <data android:scheme=\"mmsto\" />\n                <data android:scheme=\"zxing\" />\n                <data android:scheme=\"spotify\" />\n                <data android:scheme=\"tel\" />\n                <data android:scheme=\"voicemail\" />\n                <data android:scheme=\"view-source\" />\n                <data android:scheme=\"sqlite\" />\n\n                <!-- Intercept Alipay links -->\n                <data android:scheme=\"alipays\" />\n\n                <!-- Intercept Google play links -->\n                <data android:scheme=\"market\" />\n                <data android:scheme=\"store\" />\n                <data android:scheme=\"android\" />\n\n                <!-- Intercept WeChat links -->\n                <data android:scheme=\"weixin\" />\n\n                <!-- Intercept WhatsApp links -->\n                <data android:scheme=\"whatsapp\" />\n                <data android:scheme=\"whatsapp-sheet\" />\n                <data android:scheme=\"whatsapp-consumer\" />\n            </intent-filter>\n            <!-- same scheme-intents but with mime (mime!=null) -->\n            <intent-filter>\n                <action android:name=\"android.intent.action.APPLICATION_PREFERENCES\" />\n                <action android:name=\"android.service.quicksettings.action.QS_TILE\" />\n                <action android:name=\"android.intent.action.VIEW\" />\n                <action android:name=\"android.intent.action.EDIT\" />\n                <action android:name=\"android.intent.action.PICK\" />\n                <action android:name=\"android.intent.action.GET_CONTENT\" />\n                <action android:name=\"android.intent.action.CREATE_DOCUMENT\" />\n                <action android:name=\"android.intent.action.OPEN_DOCUMENT\" />\n                <action android:name=\"android.intent.action.OPEN_DOCUMENT_TREE\" />\n                <action android:name=\"android.intent.action.INSERT\" />\n                <action android:name=\"android.intent.action.INSERT_OR_EDIT\" />\n                <action android:name=\"android.intent.action.CALL_BUTTON\" />\n                <action android:name=\"android.intent.action.DIAL\" />\n                <!-- Used by camera to view photo taken -->\n                <action android:name=\"android.provider.action.REVIEW\" />\n                <action android:name=\"android.provider.action.REVIEW_SECURE\" />\n                <action android:name=\"com.android.camera.action.REVIEW\" />\n                <action android:name=\"com.android.camera.action.SPLIT_SCREEN_REVIEW\" />\n\n                <category android:name=\"android.intent.category.DEFAULT\" />\n                <category android:name=\"android.intent.category.BROWSABLE\" />\n                <category android:name=\"android.intent.category.OPENABLE\" />\n\n                <data android:scheme=\"http\" />\n                <data android:scheme=\"https\" />\n                <data android:scheme=\"about\" />\n                <data android:scheme=\"javascript\" />\n                <data android:scheme=\"mailto\" />\n                <data android:scheme=\"geo\" />\n                <data android:scheme=\"file\" />\n                <data android:scheme=\"content\" />\n\n                <data android:scheme=\"rtsp\" />\n                <data android:scheme=\"rtmp\" />\n                <data android:scheme=\"ftp\" />\n                <data android:scheme=\"sftp\" />\n\n                <data android:scheme=\"skype\" />\n                <data android:scheme=\"sms\" />\n                <data android:scheme=\"smsto\" />\n                <data android:scheme=\"mms\" />\n                <data android:scheme=\"mmsto\" />\n                <data android:scheme=\"zxing\" />\n                <data android:scheme=\"spotify\" />\n                <data android:scheme=\"tel\" />\n                <data android:scheme=\"voicemail\" />\n                <data android:scheme=\"view-source\" />\n                <data android:scheme=\"sqlite\" />\n\n                <!-- Intercept Alipay links -->\n                <data android:scheme=\"alipays\" />\n\n                <!-- Intercept Google play links -->\n                <data android:scheme=\"market\" />\n                <data android:scheme=\"store\" />\n                <data android:scheme=\"android\" />\n\n                <!-- Intercept WeChat links -->\n                <data android:scheme=\"weixin\" />\n\n                <data android:mimeType=\"*/*\" />\n            </intent-filter>\n            <intent-filter>\n                <action android:name=\"android.intent.action.PICK\" />\n                <!-- Intercept wallpaper -->\n                <action android:name=\"android.intent.action.ATTACH_DATA\" />\n                <action android:name=\"android.intent.action.SET_WALLPAPER\" />\n\n                <category android:name=\"android.intent.category.DEFAULT\" />\n            </intent-filter>\n            <intent-filter>\n                <action android:name=\"android.intent.action.SEND\" />\n\n                <category android:name=\"android.intent.category.DEFAULT\" />\n                <category android:name=\"android.intent.category.BROWSABLE\" />\n\n                <data android:mimeType=\"*/*\" />\n            </intent-filter>\n            <intent-filter>\n                <action android:name=\"android.intent.action.SENDTO\" />\n\n                <category android:name=\"android.intent.category.DEFAULT\" />\n\n                <data android:mimeType=\"*/*\" />\n            </intent-filter>\n            <intent-filter>\n                <action android:name=\"android.intent.action.SENDTO\" />\n\n                <category android:name=\"android.intent.category.DEFAULT\" />\n\n                <data android:scheme=\"mailto\" />\n                <data android:scheme=\"sms\" />\n                <data android:scheme=\"smsto\" />\n            </intent-filter>\n            <intent-filter>\n                <action android:name=\"android.intent.action.SEND_MULTIPLE\" />\n\n                <category android:name=\"android.intent.category.DEFAULT\" />\n\n                <data android:mimeType=\"*/*\" />\n            </intent-filter>\n            <intent-filter>\n                <action android:name=\"android.intent.action.SEARCH\" />\n                <action android:name=\"android.intent.action.MEDIA_SEARCH\" />\n                <action android:name=\"android.intent.action.WEB_SEARCH\" />\n                <action android:name=\"android.speech.action.VOICE_SEARCH_HANDS_FREE\" />\n                <action android:name=\"android.media.action.MEDIA_PLAY_FROM_SEARCH\" />\n                <action android:name=\"android.media.action.TEXT_OPEN_FROM_SEARCH\" />\n                <action android:name=\"android.media.action.VIDEO_PLAY_FROM_SEARCH\" />\n            </intent-filter>\n            <intent-filter>\n                <action android:name=\"android.intent.action.SEARCH\" />\n                <action android:name=\"android.intent.action.MEDIA_SEARCH\" />\n                <action android:name=\"android.intent.action.WEB_SEARCH\" />\n                <action android:name=\"android.speech.action.VOICE_SEARCH_HANDS_FREE\" />\n                <action android:name=\"android.media.action.MEDIA_PLAY_FROM_SEARCH\" />\n                <action android:name=\"android.media.action.TEXT_OPEN_FROM_SEARCH\" />\n                <action android:name=\"android.media.action.VIDEO_PLAY_FROM_SEARCH\" />\n\n                <category android:name=\"android.intent.category.DEFAULT\" />\n            </intent-filter>\n            <intent-filter>\n                <action android:name=\"android.intent.action.ASSIST\" />\n\n                <category android:name=\"android.intent.category.DEFAULT\" />\n            </intent-filter>\n            <!-- Google Now note to self -->\n            <intent-filter>\n                <action android:name=\"com.google.android.gm.action.AUTO_SEND\" />\n\n                <category android:name=\"android.intent.category.DEFAULT\" />\n\n                <data android:mimeType=\"*/*\" />\n            </intent-filter>\n            <intent-filter>\n                <action android:name=\"com.google.zxing.client.android.SCAN\" />\n\n                <category android:name=\"android.intent.category.DEFAULT\" />\n            </intent-filter>\n            <intent-filter>\n                <action android:name=\"android.intent.action.VIEW\" />\n\n                <category android:name=\"android.intent.category.DEFAULT\" />\n                <category android:name=\"android.intent.category.BROWSABLE\" />\n\n                <data\n                    android:host=\"scan\"\n                    android:path=\"/\"\n                    android:scheme=\"zxing\" />\n            </intent-filter>\n            <!-- Intercept Samsung file manager -->\n            <intent-filter>\n                <action android:name=\"android.intent.action.VIEW\" />\n                <category android:name=\"android.intent.category.DEFAULT\" />\n\n                <data android:host=\"*\" />\n                <data android:scheme=\"file\" />\n                <data android:scheme=\"content\" />\n                <data android:mimeType=\"*/*\" />\n                <data android:pathPattern=\"/external/file/.*\" />\n            </intent-filter>\n            <intent-filter>\n                <action android:name=\"com.android.camera.action.CROP\" />\n\n                <category android:name=\"android.intent.category.DEFAULT\" />\n                <category android:name=\"android.intent.category.ALTERNATIVE\" />\n                <category android:name=\"android.intent.category.SELECTED_ALTERNATIVE\" />\n\n                <data android:scheme=\"content\" />\n                <data android:scheme=\"file\" />\n                <data android:mimeType=\"image/*\" />\n            </intent-filter>\n            <intent-filter>\n                <action android:name=\"android.intent.action.INSTALL_PACKAGE\" />\n                <action android:name=\"android.intent.action.UNINSTALL_PACKAGE\" />\n\n                <category android:name=\"android.intent.category.DEFAULT\" />\n                <category android:name=\"android.intent.category.BROWSABLE\" />\n\n                <data android:scheme=\"content\" />\n                <data android:scheme=\"file\" />\n                <data android:scheme=\"package\" />\n                <data android:host=\"*\" />\n                <data android:mimeType=\"application/*\" />\n            </intent-filter>\n            <!-- Camera -->\n            <intent-filter tools:ignore=\"AppLinkUrlError\">\n                <action android:name=\"android.media.action.IMAGE_CAPTURE\" />\n                <action android:name=\"android.media.action.IMAGE_CAPTURE_SECURE\" />\n                <action android:name=\"android.media.action.STILL_IMAGE_CAMERA\" />\n                <action android:name=\"android.media.action.STILL_IMAGE_CAMERA_SECURE\" />\n                <action android:name=\"android.media.action.VIDEO_CAMERA\" />\n                <action android:name=\"android.media.action.VIDEO_CAPTURE\" />\n\n                <category android:name=\"android.intent.category.DEFAULT\" />\n                <category android:name=\"android.intent.category.BROWSABLE\" />\n                <category android:name=\"android.intent.category.VOICE\" />\n            </intent-filter>\n            <!-- Music player -->\n            <intent-filter>\n                <action android:name=\"android.intent.action.MUSIC_PLAYER\" />\n\n                <category android:name=\"android.intent.category.DEFAULT\" />\n                <category android:name=\"android.intent.category.APP_MUSIC\" />\n            </intent-filter>\n        </activity>\n        <activity\n            android:name=\".misc.HelpActivity\"\n            android:enableOnBackInvokedCallback=\"true\"\n            android:exported=\"true\"\n            android:launchMode=\"singleTop\"\n            android:taskAffinity=\"\" />\n        <activity\n            android:name=\".crypto.auth.AuthManagerActivity\"\n            android:enableOnBackInvokedCallback=\"true\"\n            android:exported=\"false\"\n            android:label=\"@string/auth_manager_title\" />\n        <activity\n            android:name=\".crypto.auth.AuthFeatureDemultiplexer\"\n            android:enableOnBackInvokedCallback=\"false\"\n            android:exported=\"true\" />\n        <activity\n            android:name=\".details.ActivityLauncherShortcutActivity\"\n            android:enableOnBackInvokedCallback=\"false\"\n            android:excludeFromRecents=\"true\"\n            android:exported=\"false\"\n            android:launchMode=\"singleTask\"\n            android:noHistory=\"true\"\n            android:taskAffinity=\".details.ActivityLauncherShortcutActivity\"\n            android:theme=\"@style/AppTheme.TransparentBackground\" />\n        <activity\n            android:name=\".apk.behavior.FreezeUnfreezeActivity\"\n            android:enableOnBackInvokedCallback=\"false\"\n            android:excludeFromRecents=\"true\"\n            android:exported=\"false\"\n            android:launchMode=\"singleInstance\"\n            android:taskAffinity=\".apk.behavior.FreezeUnfreezeActivity\"\n            android:theme=\"@style/AppTheme.TransparentBackground\" />\n        <activity\n            android:name=\".profiles.ProfileApplierActivity\"\n            android:enableOnBackInvokedCallback=\"false\"\n            android:excludeFromRecents=\"true\"\n            android:exported=\"false\"\n            android:launchMode=\"singleInstance\"\n            android:taskAffinity=\".profiles.ProfileApplierActivity\"\n            android:theme=\"@style/AppTheme.TransparentBackground\" />\n        <activity\n            android:name=\".main.SplashActivity\"\n            android:enableOnBackInvokedCallback=\"true\"\n            android:exported=\"true\"\n            android:icon=\"@mipmap/ic_launcher\"\n            android:roundIcon=\"@mipmap/ic_launcher_round\"\n            android:theme=\"@style/AppTheme.Splash\">\n            <intent-filter>\n                <action android:name=\"android.intent.action.MAIN\" />\n\n                <category android:name=\"android.intent.category.DEFAULT\" />\n                <category android:name=\"android.intent.category.LAUNCHER\" />\n                <category android:name=\"android.intent.category.LEANBACK_LAUNCHER\" />\n            </intent-filter>\n        </activity>\n        <activity\n            android:name=\".logcat.LogViewerActivity\"\n            android:enableOnBackInvokedCallback=\"true\"\n            android:enabled=\"true\"\n            android:exported=\"true\"\n            android:label=\"@string/log_viewer\"\n            android:launchMode=\"singleTop\"\n            android:taskAffinity=\"\">\n            <intent-filter>\n                <action android:name=\"android.intent.action.SEND\" />\n\n                <category android:name=\"android.intent.category.DEFAULT\" />\n\n                <data android:mimeType=\"text/plain\" />\n                <data android:mimeType=\"application/octet-stream\" />\n                <data android:pathPattern=\".*\\\\.am.log\" />\n                <data android:pathPattern=\".*\\\\..*\\\\.am.log\" />\n                <data android:pathPattern=\".*\\\\..*\\\\..*\\\\.am.log\" />\n                <data android:pathPattern=\".*\\\\..*\\\\..*\\\\..*\\\\.am.log\" />\n                <data android:pathPattern=\".*\\\\..*\\\\..*\\\\..*\\\\..*\\\\.am.log\" />\n                <data android:pathPattern=\".*\\\\..*\\\\..*\\\\..*\\\\..*\\\\..*\\\\.am.log\" />\n                <data android:pathPattern=\".*\\\\..*\\\\..*\\\\..*\\\\..*\\\\..*\\\\..*\\\\.am.log\" />\n            </intent-filter>\n            <intent-filter>\n                <action android:name=\"android.intent.action.VIEW\" />\n\n                <category android:name=\"android.intent.category.DEFAULT\" />\n                <category android:name=\"android.intent.category.BROWSABLE\" />\n\n                <data android:scheme=\"file\" />\n                <data android:scheme=\"content\" />\n                <data android:host=\"*\" />\n                <data android:mimeType=\"text/plain\" />\n                <data android:mimeType=\"application/octet-stream\" />\n                <data android:pathPattern=\".*\\\\.am.log\" />\n                <data android:pathPattern=\".*\\\\..*\\\\.am.log\" />\n                <data android:pathPattern=\".*\\\\..*\\\\..*\\\\.am.log\" />\n                <data android:pathPattern=\".*\\\\..*\\\\..*\\\\..*\\\\.am.log\" />\n                <data android:pathPattern=\".*\\\\..*\\\\..*\\\\..*\\\\..*\\\\.am.log\" />\n                <data android:pathPattern=\".*\\\\..*\\\\..*\\\\..*\\\\..*\\\\..*\\\\.am.log\" />\n                <data android:pathPattern=\".*\\\\..*\\\\..*\\\\..*\\\\..*\\\\..*\\\\..*\\\\.am.log\" />\n            </intent-filter>\n        </activity>\n        <activity\n            android:name=\".logcat.RecordLogDialogActivity\"\n            android:enableOnBackInvokedCallback=\"false\"\n            android:exported=\"true\"\n            android:theme=\"@style/AppTheme.TransparentBackground\" />\n        <activity\n            android:name=\".fm.FmActivity\"\n            android:enableOnBackInvokedCallback=\"true\"\n            android:exported=\"true\"\n            android:icon=\"@mipmap/ic_launcher_fm\"\n            android:label=\"@string/files\"\n            android:roundIcon=\"@mipmap/ic_launcher_fm_round\"\n            android:taskAffinity=\".fm.FmActivity\">\n            <intent-filter android:label=\"@string/browse_files\">\n                <action android:name=\"android.intent.action.VIEW\" />\n                <action android:name=\"org.openintents.action.VIEW_DIRECTORY\" />\n\n                <category android:name=\"android.intent.category.DEFAULT\" />\n                <category android:name=\"android.intent.category.BROWSABLE\" />\n\n                <data android:mimeType=\"inode/directory\" />\n                <data android:mimeType=\"resource/folder\" />\n                <data android:mimeType=\"vnd.android.document/directory\" />\n                <data android:mimeType=\"vnd.android.cursor.dir/*\" />\n                <data android:mimeType=\"x-directory/normal\" />\n                <data\n                    android:scheme=\"\"\n                    tools:ignore=\"AppLinkUrlError\" />\n                <data android:scheme=\"file\" />\n                <data android:scheme=\"folder\" />\n                <data android:scheme=\"directory\" />\n                <data android:scheme=\"content\" />\n            </intent-filter>\n        </activity>\n\n        <activity-alias\n            android:name=\".fm.FilesActivity\"\n            android:enabled=\"false\"\n            android:exported=\"true\"\n            android:icon=\"@mipmap/ic_launcher_fm\"\n            android:label=\"@string/files\"\n            android:roundIcon=\"@mipmap/ic_launcher_fm_round\"\n            android:targetActivity=\".fm.FmActivity\"\n            android:taskAffinity=\".fm.FmActivity\">\n            <intent-filter>\n                <action android:name=\"android.intent.action.MAIN\" />\n\n                <category android:name=\"android.intent.category.DEFAULT\" />\n                <category android:name=\"android.intent.category.LAUNCHER\" />\n            </intent-filter>\n        </activity-alias>\n\n        <activity\n            android:name=\".fm.OpenWithActivity\"\n            android:enableOnBackInvokedCallback=\"false\"\n            android:exported=\"false\"\n            android:label=\"@string/file_open_with\"\n            android:theme=\"@style/AppTheme.TransparentBackground\" />\n        <activity\n            android:name=\".viewer.audio.AudioPlayerActivity\"\n            android:enableOnBackInvokedCallback=\"false\"\n            android:excludeFromRecents=\"true\"\n            android:exported=\"true\"\n            android:label=\"@string/title_audio_player\"\n            android:process=\":audio_player\"\n            android:taskAffinity=\".misc.music.AudioPlayerActivity\"\n            android:theme=\"@style/AppTheme.TransparentBackground\">\n            <intent-filter>\n                <action android:name=\"android.intent.action.SEND\" />\n\n                <category android:name=\"android.intent.category.DEFAULT\" />\n                <category android:name=\"android.intent.category.ALTERNATIVE\" />\n\n                <data android:mimeType=\"audio/*\" />\n                <data android:mimeType=\"vnd.android.cursor.dir/audio\" />\n            </intent-filter>\n            <intent-filter>\n                <action android:name=\"android.intent.action.SEND_MULTIPLE\" />\n\n                <category android:name=\"android.intent.category.DEFAULT\" />\n                <category android:name=\"android.intent.category.ALTERNATIVE\" />\n\n                <data android:mimeType=\"audio/*\" />\n                <data android:mimeType=\"vnd.android.cursor.dir/audio\" />\n            </intent-filter>\n            <intent-filter>\n                <action android:name=\"android.intent.action.VIEW\" />\n\n                <category android:name=\"android.intent.category.DEFAULT\" />\n                <category android:name=\"android.intent.category.BROWSABLE\" />\n\n                <data android:scheme=\"file\" />\n                <data android:scheme=\"content\" />\n                <data android:mimeType=\"audio/*\" />\n                <data android:mimeType=\"vnd.android.cursor.dir/audio\" />\n            </intent-filter>\n        </activity>\n        <activity\n            android:name=\".DummyActivity\"\n            android:allowTaskReparenting=\"true\"\n            android:alwaysRetainTaskState=\"false\"\n            android:clearTaskOnLaunch=\"true\"\n            android:enableOnBackInvokedCallback=\"false\"\n            android:enabled=\"true\"\n            android:excludeFromRecents=\"true\"\n            android:finishOnTaskLaunch=\"true\"\n            android:noHistory=\"true\"\n            android:stateNotNeeded=\"true\"\n            android:theme=\"@android:style/Theme.NoDisplay\" />\n\n        <service\n            android:name=\".apk.installer.PackageInstallerService\"\n            android:exported=\"false\"\n            android:foregroundServiceType=\"dataSync|specialUse\" />\n        <service\n            android:name=\".batchops.BatchOpsService\"\n            android:exported=\"false\"\n            android:foregroundServiceType=\"dataSync|specialUse\" />\n        <service\n            android:name=\".profiles.ProfileApplierService\"\n            android:exported=\"false\"\n            android:foregroundServiceType=\"dataSync|specialUse\" />\n        <service\n            android:name=\".logcat.LogcatRecordingService\"\n            android:exported=\"false\"\n            android:foregroundServiceType=\"dataSync|specialUse\" />\n        <service\n            android:name=\".apk.behavior.FreezeUnfreezeService\"\n            android:exported=\"false\"\n            android:foregroundServiceType=\"dataSync|specialUse\" />\n        <service\n            android:name=\".accessibility.NoRootAccessibilityService\"\n            android:exported=\"false\"\n            android:permission=\"android.permission.BIND_ACCESSIBILITY_SERVICE\">\n            <intent-filter>\n                <action android:name=\"android.accessibilityservice.AccessibilityService\" />\n            </intent-filter>\n\n            <meta-data\n                android:name=\"android.accessibilityservice\"\n                android:resource=\"@xml/accessibility_service_config\" />\n        </service>\n        <service\n            android:name=\".self.filecache.InternalCacheCleanerService\"\n            android:exported=\"false\" />\n        <service\n            android:name=\".session.SessionMonitoringService\"\n            android:exported=\"false\"\n            android:foregroundServiceType=\"dataSync|specialUse\" />\n        <service\n            android:name=\".servermanager.WifiWaitService\"\n            android:exported=\"false\"\n            android:foregroundServiceType=\"dataSync|specialUse\"\n            tools:targetApi=\"30\" />\n        <service\n            android:name=\".adb.AdbPairingService\"\n            android:exported=\"false\"\n            android:foregroundServiceType=\"dataSync|specialUse\"\n            tools:targetApi=\"r\" />\n\n        <receiver\n            android:name=\".servermanager.ServerStatusChangeReceiver\"\n            android:exported=\"true\"\n            android:permission=\"android.permission.UPDATE_APP_OPS_STATS\" />\n        <receiver\n            android:name=\".usage.ScreenTimeAppWidget\"\n            android:exported=\"true\"\n            android:label=\"@string/screen_time\">\n            <intent-filter>\n                <action android:name=\"android.appwidget.action.APPWIDGET_UPDATE\" />\n                <action android:name=\"android.appwidget.action.APPWIDGET_UPDATE_OPTIONS\" />\n                <action android:name=\"android.appwidget.action.APPWIDGET_DELETED\" />\n                <action android:name=\"android.appwidget.action.APPWIDGET_DISABLED\" />\n                <action android:name=\"android.appwidget.action.APPWIDGET_ENABLED\" />\n                <action android:name=\"android.appwidget.action.APPWIDGET_RESTORED\" />\n            </intent-filter>\n\n            <meta-data\n                android:name=\"android.appwidget.provider\"\n                android:resource=\"@xml/app_widget_info_screen_time\" />\n        </receiver>\n        <receiver\n            android:name=\".usage.DataUsageAppWidget\"\n            android:exported=\"true\"\n            android:label=\"@string/data_usage_msg\">\n            <intent-filter>\n                <action android:name=\"android.appwidget.action.APPWIDGET_UPDATE\" />\n                <action android:name=\"android.appwidget.action.APPWIDGET_UPDATE_OPTIONS\" />\n                <action android:name=\"android.appwidget.action.APPWIDGET_DELETED\" />\n                <action android:name=\"android.appwidget.action.APPWIDGET_DISABLED\" />\n                <action android:name=\"android.appwidget.action.APPWIDGET_ENABLED\" />\n                <action android:name=\"android.appwidget.action.APPWIDGET_RESTORED\" />\n            </intent-filter>\n\n            <meta-data\n                android:name=\"android.appwidget.provider\"\n                android:resource=\"@xml/app_widget_info_data_usage\" />\n        </receiver>\n        <receiver\n            android:name=\".oneclickops.ClearCacheAppWidget\"\n            android:exported=\"true\"\n            android:label=\"@string/clear_cache\">\n            <intent-filter>\n                <action android:name=\"android.appwidget.action.APPWIDGET_UPDATE\" />\n            </intent-filter>\n\n            <meta-data\n                android:name=\"android.appwidget.provider\"\n                android:resource=\"@xml/app_widget_info_clear_cache\" />\n        </receiver>\n        <receiver\n            android:name=\".logcat.RecordingWidgetProvider\"\n            android:exported=\"true\"\n            android:label=\"@string/record_log\">\n            <intent-filter>\n                <action android:name=\"android.appwidget.action.APPWIDGET_UPDATE\" />\n\n                <data android:scheme=\"log_viewer_widget\" />\n            </intent-filter>\n            <intent-filter>\n                <action android:name=\"android.appwidget.action.APPWIDGET_UPDATE\" />\n            </intent-filter>\n            <intent-filter>\n                <action android:name=\"${applicationId}.action.RECORD_OR_STOP\" />\n\n                <data android:scheme=\"log_viewer_widget\" />\n            </intent-filter>\n\n            <meta-data\n                android:name=\"android.appwidget.provider\"\n                android:resource=\"@xml/recording_widget_info\" />\n        </receiver>\n        <receiver\n            android:name=\".self.BootReceiver\"\n            android:exported=\"false\">\n            <intent-filter>\n                <action android:name=\"android.intent.action.BOOT_COMPLETED\" />\n            </intent-filter>\n        </receiver>\n\n        <provider\n            android:name=\".fm.FmProvider\"\n            android:authorities=\"${applicationId}.file\"\n            android:exported=\"false\"\n            android:grantUriPermissions=\"true\" />\n\n        <meta-data\n            android:name=\"android.permission.INTERNET.mode\"\n            android:value=\"runtime\" />\n    </application>\n\n</manifest>"
  },
  {
    "path": "app/src/main/aidl/io/github/muntashirakon/AppManager/IAMService.aidl",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager;\n\nimport android.os.IBinder;\n\nimport aosp.android.content.pm.ParceledListSlice;\nimport io.github.muntashirakon.AppManager.IRemoteProcess;\nimport io.github.muntashirakon.AppManager.IRemoteShell;\n\n// Transact code starts from 3\ninterface IAMService {\n    IRemoteProcess newProcess(in String[] cmd, in String[] env, in String dir) = 3;\n    IRemoteShell getShell(in String[] cmd) = 4;\n    ParceledListSlice getRunningProcesses() = 6;\n    int getUid() = 12;\n    void symlink(in String file, in String link) = 13;\n    IBinder getService(in String serviceName) = 14;\n}\n"
  },
  {
    "path": "app/src/main/aidl/io/github/muntashirakon/AppManager/IRemoteProcess.aidl",
    "content": "// SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager;\n\n// Copyright 2020 Rikka\ninterface IRemoteProcess {\n    ParcelFileDescriptor getOutputStream();\n    void closeOutputStream();\n    ParcelFileDescriptor getInputStream();\n    ParcelFileDescriptor getErrorStream();\n    int waitFor();\n    int exitValue();\n    void destroy();\n    boolean alive();\n    boolean waitForTimeout(long timeout, String unit);\n}\n"
  },
  {
    "path": "app/src/main/aidl/io/github/muntashirakon/AppManager/IRemoteShell.aidl",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager;\n\nimport io.github.muntashirakon.AppManager.IShellResult;\n\ninterface IRemoteShell {\n    void addCommand(in String[] commands);\n    void addInputStream(in ParcelFileDescriptor inputStream);\n    IShellResult exec();\n}\n"
  },
  {
    "path": "app/src/main/aidl/io/github/muntashirakon/AppManager/IShellResult.aidl",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager;\n\nimport aosp.android.content.pm.StringParceledListSlice;\n\ninterface IShellResult {\n    StringParceledListSlice getStdout();\n    StringParceledListSlice getStderr();\n    int getExitCode();\n    boolean isSuccessful();\n}\n"
  },
  {
    "path": "app/src/main/aidl/io/github/muntashirakon/AppManager/ipc/ps/ProcessEntry.aidl",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.ipc.ps;\n\nparcelable ProcessEntry;\n"
  },
  {
    "path": "app/src/main/aidl/io/github/muntashirakon/AppManager/ipc/ps/ProcessUsers.aidl",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.ipc.ps;\n\nparcelable ProcessUsers;\n"
  },
  {
    "path": "app/src/main/annotations/android/content/pm/annotations.xml",
    "content": "<!--\n  ~ SPDX-License-Identifier: GPL-3.0-or-later\n  -->\n\n<root>\n    <item name='android.content.pm.PackageInfo activities'>\n        <annotation name='androidx.annotation.Nullable' />\n    </item>\n    <item name='android.content.pm.PackageInfo permissions'>\n        <annotation name='androidx.annotation.Nullable' />\n    </item>\n    <item name='android.content.pm.PackageInfo providers'>\n        <annotation name='androidx.annotation.Nullable' />\n    </item>\n    <item name='android.content.pm.PackageInfo receivers'>\n        <annotation name='androidx.annotation.Nullable' />\n    </item>\n    <item name='android.content.pm.PackageInfo services'>\n        <annotation name='androidx.annotation.Nullable' />\n    </item>\n</root>"
  },
  {
    "path": "app/src/main/assets/blanks/blank.txt",
    "content": ""
  },
  {
    "path": "app/src/main/assets/debloat.json",
    "content": "[{\"id\":\"android\",\"description\":\"Android System\\nAndroid system framework? Apk file name: framework-res\\nCould be THE core of the android system.\\nProbably very unsafe to disable.\",\"removal\":\"unsafe\",\"type\":\"aosp\"},{\"id\":\"android.aosp.overlay\",\"description\":\"Refers to the Runtime Resource Overlay (RRO) framework that is built into the AOSP.\\nRRO allows for the dynamic modification of an app's resources at runtime,\\nEnabling the customization of the app's appearance and behavior without modifying its source code\\nhttps://source.android.com/docs/core/runtime/rros\",\"removal\":\"unsafe\",\"type\":\"aosp\"},{\"id\":\"android.auto_generated_rro__\",\"label\":\"android.auto_generated_rro__\",\"description\":\"RRO = Runtime Resources Overlay. Changes values of a package config, based in the overlay definitions. Overlays are heavily used by OEMs to customize the look and feel of Android.\",\"web\":[\"https://source.android.com/devices/architecture/rros\",\"https://code.tutsplus.com/tutorials/quick-tip-theme-android-with-the-runtime-resource-overlay-framework--cms-29708\"],\"removal\":\"caution\",\"type\":\"aosp\"},{\"id\":\"android.auto_generated_rro_product__\",\"label\":\"android.auto_generated_rro_product__\",\"description\":\"RRO = Runtime Resources Overlay. Used by OEMs to customize look and feel of certain applications.\",\"web\":[\"https://source.android.com/devices/architecture/rros\",\"https://code.tutsplus.com/tutorials/quick-tip-theme-android-with-the-runtime-resource-overlay-framework--cms-29708\"],\"removal\":\"caution\",\"type\":\"aosp\"},{\"id\":\"android.auto_generated_rro_vendor__\",\"label\":\"android.auto_generated_rro_vendor__\",\"description\":\"RRO = Runtime Resources Overlay. Used by OEMs to customize look and feel of certain applications.\",\"web\":[\"https://source.android.com/devices/architecture/rros\",\"https://code.tutsplus.com/tutorials/quick-tip-theme-android-with-the-runtime-resource-overlay-framework--cms-29708\"],\"removal\":\"caution\",\"type\":\"aosp\"},{\"id\":\"android.auto_generated_vendor_\",\"label\":\"android.auto_generated_vendor_\",\"description\":\"Auto generated vendor's stuff for Android Auto.\",\"web\":[\"https://www.android.com/intl/en_en/auto/\"],\"removal\":\"delete\",\"warning\":\"You may need this if you use Android Auto\",\"type\":\"aosp\"},{\"id\":\"android.overlay.common\",\"description\":\"It has some important settings and configurations related to Android.\",\"removal\":\"unsafe\",\"type\":\"aosp\"},{\"id\":\"android.overlay.target\",\"description\":\"It has some important settings and configurations related to Android.\",\"removal\":\"unsafe\",\"type\":\"aosp\"},{\"id\":\"android.qvaoverlay.common\",\"description\":\"This app has no code and is safe to remove.\",\"removal\":\"delete\",\"type\":\"aosp\"},{\"id\":\"com.android.adservices.api\",\"description\":\"Android AdServices. Introduced in Android 13 privacy sandbox beta components disabled on default.\\nhttps://source.android.com/docs/core/ota/modular-system/adservices\",\"removal\":\"delete\",\"type\":\"aosp\"},{\"id\":\"com.android.apps.tag\",\"label\":\"Tags\",\"description\":\"Support for NFC tags interactions (5 permissions, Contacts/Phone On by default).\\nNFC Tags are for instance used in buses to validate your transport card with your phone.\\nOther example: https://en.wikipedia.org/wiki/TecTile\\nYou will still be able to connect to a NFC device (e.g a speaker) with this disabled.\",\"removal\":\"replace\",\"type\":\"aosp\"},{\"id\":\"com.android.avatarpicker\",\"description\":\"Lets you assign pictures to contacts. It has two options: take picture from the camera, or choose from the gallery.\\nSource code: https://android.googlesource.com/platform/packages/apps/AvatarPicker\",\"removal\":\"replace\",\"type\":\"aosp\"},{\"id\":\"com.android.backupconfirm\",\"label\":\"com.android.backupconfirm\",\"description\":\"Restores Google settings with Google Backup restore.\\nDisplays confirmation popup when doing ADB backup.\",\"removal\":\"caution\",\"warning\":\"Disabling this package breaks ADB Backup and crashes on attempting to add a Google account\",\"type\":\"aosp\"},{\"id\":\"com.android.basicsmsreceiver\",\"description\":\"Gets SMS and creates notifications:\\nhttps://android.googlesource.com/platform/packages/apps/BasicSmsReceiver/+/jb-dev/src/com/android/basicsmsreceiver/BasicSmsReceiverApp.java\",\"removal\":\"caution\",\"type\":\"aosp\"},{\"id\":\"com.android.bio.face.service\",\"label\":\"com.android.bio.face.service\",\"description\":\"Handles facial recognition.\",\"removal\":\"caution\",\"type\":\"aosp\"},{\"id\":\"com.android.bips\",\"label\":\"Default Print Service\",\"description\":\"Generic printing service that should work with most printers.\\nWill break printing functionality if disabled, but other replacement print services can be downloaded from the Play Store.\",\"removal\":\"replace\",\"type\":\"aosp\"},{\"id\":\"com.android.bluetooth\",\"label\":\"Bluetooth\",\"description\":\"Handles all Bluetooth functionality including device discovery, pairing, and data transfer.\",\"removal\":\"caution\",\"warning\":\"Removing this will completely break Bluetooth functionality on the device.\",\"type\":\"aosp\"},{\"id\":\"com.android.bluetooth.overlay.common\",\"description\":\"Overlays are usually themes.\",\"removal\":\"caution\",\"type\":\"aosp\"},{\"id\":\"com.android.bluetoothmidiservice\",\"label\":\"Bluetooth MIDI Service\",\"description\":\"Provides classes for using the MIDI protocol over Bluetooth.\",\"removal\":\"delete\",\"warning\":\"Do not remove if you connect to a MIDI device via Bluetooth\",\"type\":\"aosp\"},{\"id\":\"com.android.bookmarkprovider\",\"label\":\"Bookmark Provider\",\"description\":\"Only exists for compatibility reasons to prevent apps querying it from getting null cursors they do not expect and crash.\",\"removal\":\"caution\",\"warning\":\"Apps targeting a very old SDK might crash. For example, disabling this on LDPlayer emulator crashes the default browser.\",\"type\":\"aosp\"},{\"id\":\"com.android.browser\",\"label\":\"Mi Browser\",\"description\":\"Mi Browser and browser for the LDPlayer emulator. It is a privacy nightmare and should be replaced.\",\"web\":[\"https://www.xda-developers.com/xiaomi-mi-web-browser-pro-mint-collecting-browsing-data-incognito-mode/\"],\"removal\":\"replace\",\"suggestions\":\"browsers\",\"type\":\"aosp\"},{\"id\":\"com.android.browser.provider\",\"label\":\"com.android.browser.provider\",\"description\":\"Old package (2014). Chrome bookmarks provider? Injects Picasa URL (https://picasaweb.google.com) in the Chrome browser's bookmarks in the browser.\",\"removal\":\"delete\",\"type\":\"aosp\"},{\"id\":\"com.android.calculator2\",\"label\":\"Calculator\",\"description\":\"The AOSP calculator app\\nSome OEMs (e.g. Huawei and Xiaomi) use the same package name for their app\",\"removal\":\"replace\",\"suggestions\":\"calculators\",\"type\":\"aosp\"},{\"id\":\"com.android.calendar\",\"label\":\"Calendar\",\"description\":\"The AOSP Calendar app.\\nSome OEMs (e.g. Huawei and Xiaomi) use the same package name for their app.\",\"removal\":\"replace\",\"suggestions\":\"calendars\",\"type\":\"aosp\"},{\"id\":\"com.android.calllogbackup\",\"label\":\"Call Log Backup/Restore\",\"description\":\"Call Logs Backup/Restore feature, runs in the background.\",\"web\":[\"https://android.googlesource.com/platform/packages/providers/CallLogProvider/+/refs/heads/master/src/com/android/calllogbackup\"],\"removal\":\"delete\",\"type\":\"aosp\"},{\"id\":\"com.android.camera\",\"description\":\"The stock AOSP camera app on many phones. However, on some Xiaomi phones, it is actually the Xiaomi Camera app. Deleting this will result in no camera app.\\nTry Open Camera as an open source alternative:\\nhttps://play.google.com/store/apps/details?id=net.sourceforge.opencamera&hl=en&gl=US\",\"removal\":\"replace\",\"type\":\"aosp\"},{\"id\":\"com.android.captiveportallogin\",\"label\":\"CaptivePortalLogin\",\"description\":\"Support for captive portal logins.\\nA captive portal login is a web page where users have to log in or accept terms of use. Common for public wifi networks.\",\"web\":[\"https://en.wikipedia.org/wiki/Captive_portal\"],\"removal\":\"delete\",\"type\":\"aosp\"},{\"id\":\"com.android.carrierconfig\",\"label\":\"com.android.carrierconfig\",\"description\":\"Dynamically provides configuration for the carrier network.\\nThe config contains: Roaming networks, Voicemail settings, SMS/MMS settings, VoLTE/IMS settings, and more.\\nIf a carrier app is installed it will be queried for overrides to these settings.\\nSeems to run on boot and when you swap SIM?\",\"web\":[\"https://source.android.com/devices/tech/config/carrier\",\"https://cs.android.com/android/platform/superproject/+/master:packages/apps/CarrierConfig/src/com/android/carrierconfig/DefaultCarrierConfigService.java\"],\"removal\":\"replace\",\"type\":\"aosp\"},{\"id\":\"com.android.carrierconfig.overlay.common\",\"description\":\"Needed for (com.android.carrierconfig).\",\"removal\":\"replace\",\"type\":\"aosp\"},{\"id\":\"com.android.carrierdefaultapp\",\"label\":\"CarrierDefaultApp\",\"description\":\"This package is a generic solution that allows carriers to indicate when a device has run OOB (Out Of Balance). Android devices that are OOB need carrier mitigation protocols to allow select data through (like to notify users their data/balance is out, or allow them to buy more data through the carrier app).\\nWill probably break that functionality if disabled, but is otherwise safe to disable (should only affect users that are out of data/balance?).\",\"web\":[\"https://source.android.com/devices/tech/connect/oob-users\"],\"removal\":\"caution\",\"type\":\"aosp\"},{\"id\":\"com.android.cellbroadcastreceiver\",\"label\":\"Emergency alerts\",\"description\":\"Cell broadcast is designed to deliver messages to multiple users in an area.\\nThis is notably used by ISPs to send Emergency/Government alerts.\\nRuns at boot time and is also triggered after exiting airplane mode.\",\"web\":[\"https://en.wikipedia.org/wiki/Cell_Broadcast\",\"https://www.androidcentral.com/amber-alerts-and-android-what-you-need-know\",\"https://android.googlesource.com/platform/packages/apps/CellBroadcastReceiver/+/refs/heads/master/src/com/android/cellbroadcastreceiver\"],\"removal\":\"caution\",\"type\":\"aosp\"},{\"id\":\"com.android.cellbroadcastreceiver.basiccolorblack.overlay\",\"label\":\"com.android.cellbroadcastreceiver.basiccolorblack.overlay\",\"description\":\"Dark theme overlay for com.android.cellbroadcastreceiver\",\"dependencies\":[\"com.android.cellbroadcastreceiver\"],\"removal\":\"caution\",\"type\":\"aosp\"},{\"id\":\"com.android.cellbroadcastreceiver.basiccolorwhite.overlay\",\"label\":\"com.android.cellbroadcastreceiver.basiccolorwhite.overlay\",\"description\":\"Light theme overlay for com.android.cellbroadcastreceiver\",\"dependencies\":[\"com.android.cellbroadcastreceiver\"],\"removal\":\"caution\",\"type\":\"aosp\"},{\"id\":\"com.android.cellbroadcastreceiver.module\",\"description\":\"Same as com.android.cellbroadcastreceiver.\\nCell broadcasting used to send emergency alerts.\\nhttps://en.wikipedia.org/wiki/Cell_Broadcast.\",\"dependencies\":[\"com.android.cellbroadcastreceiver\"],\"removal\":\"caution\",\"type\":\"aosp\"},{\"id\":\"com.android.cellbroadcastreceiver.overlay.common\",\"label\":\"com.android.cellbroadcastreceiver.overlay.common\",\"description\":\"Overlay for com.android.cellbroadcastreceiver. Inside the APK, I found unused things: show_brazil_settings, show_cmas_settings, show_etws_settings.\\nThey are unavailable and useless.\",\"removal\":\"delete\",\"type\":\"aosp\"},{\"id\":\"com.android.cellbroadcastservice\",\"description\":\"is designed to deliver messages to multiple users in an area.\\nThis is notably used by ISPs to send Emergency/Government alerts.\\nRuns in the background.\\nhttps://en.wikipedia.org/wiki/Cell_Broadcast\\nhttps://www.androidcentral.com/amber-alerts-and-android-what-you-need-know\",\"removal\":\"caution\",\"type\":\"aosp\"},{\"id\":\"com.android.certinstaller\",\"description\":\"Certificate installer\\nUsed for accepting and revoking Internet certificates.\\nCertificates identify ownership of public keys, for use in secure communications.\\nBreaks Wi-Fi if disabled.\",\"removal\":\"unsafe\",\"type\":\"aosp\"},{\"id\":\"com.android.companiondevicemanager\",\"label\":\"Companion Device Manager\",\"description\":\"This handles connections to nearby (usually not remote) devices, like Bluetooth Headphones, desktop Operating Systems, etc.\",\"removal\":\"caution\",\"warning\":\"Removing this package may result in the inability to read the SD card from your computer's file manager (via USB).\",\"type\":\"aosp\"},{\"id\":\"com.android.connectivity.resources\",\"description\":\"Network connectivity resources.\\nCause BOOTLOOP.\",\"removal\":\"unsafe\",\"type\":\"aosp\"},{\"id\":\"com.android.contacts\",\"label\":\"Contacts\",\"description\":\"The AOSP Contacts app.\\nSome OEMs (e.g. Xiaomi) use the same package name for their app.\",\"removal\":\"replace\",\"suggestions\":\"contacts\",\"type\":\"aosp\"},{\"id\":\"com.android.credentialmanager\",\"description\":\"Credential Manager\\nManages with Passwords, passkeys.\",\"removal\":\"replace\",\"type\":\"aosp\"},{\"id\":\"com.android.cts.ctsshim\",\"label\":\"Compatibility Test Suite\",\"description\":\"Used by manufacturer to test your copy of the device for performance. It just exists and doesn't run in background.\",\"web\":[\"https://source.android.com/docs/compatibility/cts\"],\"removal\":\"delete\",\"type\":\"aosp\"},{\"id\":\"com.android.cts.priv.ctsshim\",\"label\":\"Compatibility Test Suite\",\"description\":\"Verifies certain upgrade scenarios.\\nA shim is basically a compatibility layer for an API, that makes sure anything that uses the API does so correctly.\",\"web\":[\"https://android.googlesource.com/platform/frameworks/base/+/51e458e/packages/CtsShim\",\"https://en.wikipedia.org/wiki/Shim_(computing)\"],\"removal\":\"caution\",\"warning\":\"Disabling could mess with OTA updates.\",\"type\":\"aosp\"},{\"id\":\"com.android.defcontainer\",\"description\":\"Package Access Helper\\nDetermines the recommended install location for packages and if there is enough free space for the package.\",\"removal\":\"unsafe\",\"type\":\"aosp\"},{\"id\":\"com.android.deskclock\",\"label\":\"Clock\",\"description\":\"The AOSP Clock app\\nSome OEMs (e.g. Huawei and Xiaomi) use the same package name for their app.\",\"removal\":\"replace\",\"suggestions\":\"clocks\",\"type\":\"aosp\"},{\"id\":\"com.android.devicelockcontroller\",\"description\":\"This app can't be uninstalled or disabled.\\nCan restrict this device if the owner doesn't make payments per month for the new phone.\",\"removal\":\"unsafe\",\"type\":\"aosp\"},{\"id\":\"com.android.dialer\",\"label\":\"Phone\",\"description\":\"The AOSP Dialer/Phone app\\nDefault phone app on some older phones (like Oneplus 3).\",\"removal\":\"replace\",\"suggestions\":\"dialers\",\"type\":\"aosp\"},{\"id\":\"com.android.dialer.basiccolorblack.overlay\",\"description\":\"Dark theme overlay for AOSP Dialer?\",\"removal\":\"caution\",\"type\":\"aosp\"},{\"id\":\"com.android.dialer.basiccolorwhite.overlay\",\"description\":\"Light theme overlay for AOSP Dialer?\",\"removal\":\"caution\",\"type\":\"aosp\"},{\"id\":\"com.android.documentsui\",\"label\":\"Files\",\"description\":\"Occasionally runs in the background.\\nFile selector for other apps.\",\"removal\":\"unsafe\",\"warning\":\"Storage Access Framework (SAF) will break if this is disabled.\",\"type\":\"aosp\"},{\"id\":\"com.android.documentsui.a_overlay\",\"label\":\"com.android.documentsui.a_overlay\",\"description\":\"Some overlay for for \\\"Files\\\"?\",\"dependencies\":[\"com.android.documentsui\"],\"removal\":\"caution\",\"type\":\"aosp\"},{\"id\":\"com.android.dreams.basic\",\"label\":\"Basic Daydreams\",\"description\":\"Daydream (not Google Daydream VR) is an interactive screensaver mode built into Android.\\nWith it turned on, it activates and shows the screensaver of your choice when you dock or charge your device.\\nCan display the time, weather, quotes, photos, news, tweets, or anything else Daydream app developers can think of.\",\"web\":[\"https://developer.android.com/reference/android/service/dreams/DreamService\"],\"removal\":\"delete\",\"type\":\"aosp\"},{\"id\":\"com.android.dreams.phototable\",\"label\":\"Photo Screensavers\",\"description\":\"Daydream stuff, see com.android.dreams.basic\",\"removal\":\"delete\",\"type\":\"aosp\"},{\"id\":\"com.android.dreams.phototable.overlay\",\"label\":\"com.android.dreams.phototable.overlay\",\"description\":\"Overlay for the phototable daydream? Overlays are usually themes, but not sure about this one.\",\"removal\":\"delete\",\"type\":\"aosp\"},{\"id\":\"com.android.dynsystem\",\"description\":\"Dynamic System Updates\\nRuns on boot, but doesn't seem to run in the background beyond that.\\nTreble gives the ability to boot an AOSP Generic System Image (GSI) on any supported device.\\nDynamic System Updates allows to boot into a Generic System Image (GSI) without interfering with the current installation.\\nThat means the bootloader doesn’t need to be unlocked and the user data doesn’t need to be wiped.\\nhttps://developer.android.com/topic/dsu\",\"removal\":\"caution\",\"type\":\"aosp\"},{\"id\":\"com.android.egg\",\"label\":\"Android Easter Egg\",\"description\":\"Android's easter egg feature (spam-tap on the android version in the settings)\",\"removal\":\"delete\",\"type\":\"aosp\"},{\"id\":\"com.android.email\",\"label\":\"Email\",\"description\":\"The AOSP Email app.\\nSome OEMs (e.g. Huawei, Xiaomi, Oppo) use the same package name for their app.\",\"removal\":\"replace\",\"suggestions\":\"email_clients\",\"type\":\"aosp\"},{\"id\":\"com.android.email.partnerprovider\",\"label\":\"EmailPartnerProvider\",\"description\":\"Lets Google partners (OEM in most of the case) customize the default email settings.\\nThe manufacturer often changes the default signature displayed at the end of each of your mail (e.g \\\"Sent from my Nokia phone\\\")\",\"removal\":\"delete\",\"type\":\"aosp\"},{\"id\":\"com.android.emergency\",\"label\":\"Emergency information\",\"description\":\"Shows emergency info on lockscreen and power menu. Loads on device unlock/lockscreen and power menu, so it's basically always cached in RAM, but shouldn't use much/any battery. So, the main thing gained from disabling this package is the ~9MB RAM it uses.\",\"removal\":\"caution\",\"warning\":\"Removing this will break Safety and Emergency in Settings, and you will miss SOS alerts.\",\"type\":\"aosp\"},{\"id\":\"com.android.emergency.basiccolorblack.overlay\",\"description\":\"Dark theme for Emergency rescue?\",\"removal\":\"caution\",\"type\":\"aosp\"},{\"id\":\"com.android.emergency.basiccolorwhite.overlay\",\"description\":\"Dark theme for Emergency rescue?\",\"removal\":\"caution\",\"type\":\"aosp\"},{\"id\":\"com.android.exchange\",\"label\":\"Exchange Services\",\"description\":\"Handles all aspects of starting, maintaining, and stopping the various sync adapters for the email accounts.\\nIs it only needed for the email stock app?\\n\",\"removal\":\"replace\",\"suggestions\":\"email_clients\",\"type\":\"aosp\"},{\"id\":\"com.android.ext.adservices.api\",\"description\":\"Another component of Android AdServices.\\nIntroduced in Android 14.\\nhttps://source.android.com/docs/core/ota/modular-system/adservices\",\"removal\":\"delete\",\"type\":\"aosp\"},{\"id\":\"com.android.externalstorage\",\"label\":\"External Storage\",\"description\":\"Needed by apps to access external storage such as memory cards.\",\"removal\":\"unsafe\",\"warning\":\"Storage Access Framework (SAF) will break if this is disabled.\",\"type\":\"aosp\"},{\"id\":\"com.android.facelock\",\"label\":\"Trusted Face\",\"description\":\"Package for supporting the Face Unlock feature\",\"removal\":\"caution\",\"warning\":\"Do not remove if you use Face Unlock\",\"type\":\"aosp\"},{\"id\":\"com.android.federatedcompute.services\",\"description\":\"FederatedCompute\\nAnother component of OnDevicePersonalization. But this app learns things about users.\\nIntroduced in Android 14(`com.google.android.federatedcompute` Introduced in Android 13).\\nhttps://source.android.com/docs/core/ota/modular-system/ondevicepersonalization\",\"removal\":\"delete\",\"type\":\"aosp\"},{\"id\":\"com.android.fmradio\",\"label\":\"FM Radio\",\"description\":\"Plug in head phones and listen to the FM radio!\",\"removal\":\"replace\",\"suggestions\":\"radios\",\"type\":\"aosp\"},{\"id\":\"com.android.frameworkhwext.dark\",\"description\":\"Required components of the androidhwext.\\nBasic functionality of Huawei Phones.\",\"removal\":\"unsafe\",\"type\":\"aosp\"},{\"id\":\"com.android.frameworkhwext.honor\",\"description\":\"Required components of the androidhwext.\\nBasic functionality of Huawei Phones.\",\"removal\":\"unsafe\",\"type\":\"aosp\"},{\"id\":\"com.android.frameworkres.overlay\",\"description\":\"Runtime Resource Overlay\\nThis framework provides the ability to replace application resources while the application is running. More info:\\nhttps://source.android.com/docs/core/runtime/rros\",\"removal\":\"caution\",\"type\":\"aosp\"},{\"id\":\"com.android.galaxy4\",\"label\":\"Black Hole\",\"description\":\"Built-in Dynamic wallpaper\",\"removal\":\"delete\",\"type\":\"aosp\"},{\"id\":\"com.android.gallery3d\",\"label\":\"Gallery\",\"description\":\"The AOSP Gallery app, often vendors (e.g. Xiaomi) modify it to provide their own apps.\",\"removal\":\"replace\",\"suggestions\":\"gallery\",\"type\":\"aosp\"},{\"id\":\"com.android.health.connect.backuprestore\",\"description\":\"Backups data from Health Connect app.\",\"removal\":\"delete\",\"type\":\"aosp\"},{\"id\":\"com.android.healthconnect.controller\",\"description\":\"Health Connect\\nManage the health and fitness data on your phone, and control which apps can access it.\",\"removal\":\"delete\",\"type\":\"aosp\"},{\"id\":\"com.android.hotspot2\",\"label\":\"OsuLogin\",\"description\":\"Provides wifi tethering i.e. lets you share your mobile device's Internet connection with other devices.\",\"web\":[\"https://en.wikipedia.org/wiki/Tethering\"],\"removal\":\"caution\",\"type\":\"aosp\"},{\"id\":\"com.android.hotspot2.osulogin\",\"label\":\"OsuLogin\",\"description\":\"The sole purpose of the app is to provision credentials from the Wi-Fi network to the device and allow them to connect to Wi-Fi Hotspot 2.0.\",\"web\":[\"https://hackanons.com/2021/07/osulogin-android-everything-you-need-to-know.html\"],\"removal\":\"caution\",\"type\":\"aosp\"},{\"id\":\"com.android.htmlviewer\",\"label\":\"HTML Viewer\",\"description\":\"Allows apps to load URLs into the WebView, which allows web content to be displayed directly in the app.\",\"removal\":\"caution\",\"warning\":\"Removing this causes a bootloop on some MIUI 12.5.4+ phones.\",\"type\":\"aosp\"},{\"id\":\"com.android.inputdevices\",\"label\":\"Input Devices\",\"description\":\"Only contains a receiver named \\\"Android keyboard\\\", possibly for an external keyboard.\\nLocates available keyboard layouts. Apps can offer additional keyboard layouts to the user by declaring a suitable broadcast receiver in their manifest.\",\"removal\":\"caution\",\"warning\":\"If you are using the default Samsung keyboard, then deleting this package on some phones may cause the keyboard to completely stop working. You may get locked out of your phone if the only method to authenticate yourself is using password.\",\"type\":\"aosp\"},{\"id\":\"com.android.inputmethod.latin\",\"label\":\"Android Keyboard (AOSP)\",\"description\":\"The AOSP keyboard app\",\"removal\":\"replace\",\"warning\":\"Do NOT disable if you don't have another keyboard with direct boot mode support, or you'll be stuck at boot (no keyboard to unlock the phone).\",\"suggestions\":\"keyboards\",\"type\":\"aosp\"},{\"id\":\"com.android.intentresolver\",\"description\":\"'Share' functionality will be disabled after uninstalling this package on Android 14 and up. Additionally, motion photos will become broken.\",\"removal\":\"caution\",\"type\":\"aosp\"},{\"id\":\"com.android.internal.display.cutout.emulation.corner\",\"label\":\"Corner cutout\",\"description\":\"Display cutout variant.\",\"web\":[\"https://developer.android.com/guide/topics/display-cutout\",\"https://source.android.com/devices/tech/display/display-cutouts\"],\"removal\":\"unsafe\",\"warning\":\"Removing the app will cause bootloop.\",\"type\":\"aosp\"},{\"id\":\"com.android.internal.display.cutout.emulation.double\",\"label\":\"Double cutout\",\"description\":\"Display cutout variant.\",\"web\":[\"https://developer.android.com/guide/topics/display-cutout\",\"https://source.android.com/devices/tech/display/display-cutouts\"],\"removal\":\"unsafe\",\"warning\":\"Removing the app will cause bootloop.\",\"type\":\"aosp\"},{\"id\":\"com.android.internal.display.cutout.emulation.hole\",\"label\":\"Punch Hole cutout\",\"description\":\"Display cutout variant.\",\"web\":[\"https://developer.android.com/guide/topics/display-cutout\",\"https://source.android.com/devices/tech/display/display-cutouts\"],\"removal\":\"unsafe\",\"warning\":\"Removing the app will cause bootloop.\",\"type\":\"aosp\"},{\"id\":\"com.android.internal.display.cutout.emulation.narrow\",\"description\":\"Display cutout variant.\",\"web\":[\"https://developer.android.com/guide/topics/display-cutout\",\"https://source.android.com/devices/tech/display/display-cutouts\"],\"removal\":\"unsafe\",\"warning\":\"Removing the app will cause bootloop.\",\"type\":\"aosp\"},{\"id\":\"com.android.internal.display.cutout.emulation.noCutout\",\"label\":\"Hide\",\"description\":\"Display cutout variant.\",\"web\":[\"https://developer.android.com/guide/topics/display-cutout\",\"https://source.android.com/devices/tech/display/display-cutouts\"],\"removal\":\"unsafe\",\"warning\":\"Removing the app will cause bootloop.\",\"type\":\"aosp\"},{\"id\":\"com.android.internal.display.cutout.emulation.tall\",\"label\":\"Tall cutout\",\"description\":\"Display cutout variant.\",\"web\":[\"https://developer.android.com/guide/topics/display-cutout\",\"https://source.android.com/devices/tech/display/display-cutouts\"],\"removal\":\"unsafe\",\"warning\":\"Removing the app will cause bootloop.\",\"type\":\"aosp\"},{\"id\":\"com.android.internal.display.cutout.emulation.waterfall\",\"label\":\"Waterfall cutout\",\"description\":\"Display cutout variant.\",\"web\":[\"https://developer.android.com/guide/topics/display-cutout\",\"https://source.android.com/devices/tech/display/display-cutouts\"],\"removal\":\"unsafe\",\"warning\":\"Removing the app will cause bootloop.\",\"type\":\"aosp\"},{\"id\":\"com.android.internal.display.cutout.emulation.wide\",\"description\":\"Display cutout variant.\",\"web\":[\"https://developer.android.com/guide/topics/display-cutout\",\"https://source.android.com/devices/tech/display/display-cutouts\"],\"removal\":\"unsafe\",\"warning\":\"Removing the app will cause bootloop.\",\"type\":\"aosp\"},{\"id\":\"com.android.internal.systemui.navbar.gestural\",\"label\":\"Gestural Navigation Bar\",\"description\":\"Gesture navigation\\nLets you use swipes and other actions to navigate your device, rather than buttons.\",\"web\":[\"https://android-developers.googleblog.com/2019/08/gesture-navigation-backstory.html\"],\"removal\":\"caution\",\"type\":\"aosp\"},{\"id\":\"com.android.internal.systemui.navbar.gestural_extra_wide_back\",\"label\":\"Gestural Navigation Bar\",\"description\":\"Enables a setting increasing how far you need to move your finger to trigger the back gesture.\",\"removal\":\"caution\",\"type\":\"aosp\"},{\"id\":\"com.android.internal.systemui.navbar.gestural_narrow_back\",\"label\":\"Gestural Navigation Bar\",\"description\":\"Enables a setting decreasing how far you need to move your finger to trigger the back gesture.\",\"removal\":\"caution\",\"type\":\"aosp\"},{\"id\":\"com.android.internal.systemui.navbar.gestural_wide_back\",\"label\":\"Gestural Navigation Bar\",\"description\":\"Enables a setting increasing how far you need to move your finger to trigger the back gesture.\",\"removal\":\"caution\",\"type\":\"aosp\"},{\"id\":\"com.android.internal.systemui.navbar.hidegestural\",\"description\":\"Allows 'Gesture hint' to be disabled in Navigation bar > Swipe gestures.\",\"removal\":\"caution\",\"type\":\"aosp\"},{\"id\":\"com.android.internal.systemui.navbar.threebutton\",\"label\":\"3 Button Navigation Bar\",\"description\":\"The default system navbar? It's what you use when you don't use gesture navigation.\",\"removal\":\"caution\",\"type\":\"aosp\"},{\"id\":\"com.android.internal.systemui.navbar.transparent\",\"description\":\"Allows 'Transparent navigation bar' to be enabled in Developer options.\",\"removal\":\"caution\",\"type\":\"aosp\"},{\"id\":\"com.android.internal.systemui.navbar.twobutton\",\"label\":\"2 Button Navigation Bar\",\"description\":\"Enables a setting for using just 2 buttons in the system navbar?\",\"removal\":\"caution\",\"type\":\"aosp\"},{\"id\":\"com.android.internal.systemui.onehanded.gestural\",\"description\":\"one-handed mode, which can be found in the settings.\\none-handed mode will not work. Safe to remove if you dont use these setting.\",\"removal\":\"replace\",\"type\":\"aosp\"},{\"id\":\"com.android.keychain\",\"description\":\"Enables apps to use system wide credential KeyChain (shared credentials between apps)\\nhttps://security.stackexchange.com/questions/216716/android-keychain-what-is-a-system-wide-credential\\n\",\"removal\":\"unsafe\",\"type\":\"aosp\"},{\"id\":\"com.android.launcher3\",\"label\":\"Quickstep\",\"description\":\"The AOSP launcher. OEMs frequently use this to deliver their own launcher.\\nYou need to install another launcher before removing it.\",\"removal\":\"caution\",\"warning\":\"You need to install another launcher before removing it.\",\"suggestions\":\"launchers\",\"type\":\"aosp\"},{\"id\":\"com.android.localtransport\",\"description\":\"Backup transport for stashing stuff into a known location on disk, and later restoring from there.\\nNeeded for storing backup data locally on a device?\\nThis package also provides the backup confirmation UI.\\nhttps://developer.android.com/guide/topics/data/testingbackup\",\"removal\":\"unsafe\",\"type\":\"aosp\"},{\"id\":\"com.android.location.fused\",\"description\":\"Manages underlying location technologies, such as GPS and Wi-Fi.\",\"removal\":\"unsafe\",\"type\":\"aosp\"},{\"id\":\"com.android.magicsmoke\",\"label\":\"Magic Smoke Wallpapers\",\"description\":\"Bulit-in Live wallpaper.\",\"removal\":\"delete\",\"type\":\"aosp\"},{\"id\":\"com.android.managedprovisioning\",\"label\":\"Work Setup\",\"description\":\"Work Setup/Work profile setup\\nManages Android user account profiles.\\nThe typical use-case is setting up a corporate profile that is controlled by the employer on an employee's personal device, to keep personal and work data separate.\",\"web\":[\"https://support.google.com/work/android/answer/6191949\",\"https://developers.google.com/android/work/requirements/work-profile\",\"https://beta.pithus.org/report/922fa478f5b2a8784e33626f04ff039d510b9dd7d5fd06db5c55002b5b5afae1\"],\"removal\":\"caution\",\"warning\":\"Needed for sandbox apps such as Shelter or Insular/Island.\",\"type\":\"aosp\"},{\"id\":\"com.android.mms\",\"label\":\"Messages\",\"description\":\"The AOSP SMS app.\\nOccasionally runs in the background.\\nSome OEMs (like Huawei, Xiaomi, Vivo, Oppo) use the same package name for their app.\",\"removal\":\"replace\",\"suggestions\":\"sms\",\"type\":\"aosp\"},{\"id\":\"com.android.mms.service\",\"description\":\"Provides support for sending MMS.\\nIt doesn't cause bootloop.\",\"removal\":\"caution\",\"type\":\"aosp\"},{\"id\":\"com.android.modulemetadata\",\"label\":\"Module Metadata\",\"description\":\"It's used to manage and store metadata about installed modules, and is accessed by the system server.\",\"removal\":\"unsafe\",\"warning\":\"Breaks some Android core functionalities if disabled.\",\"type\":\"aosp\"},{\"id\":\"com.android.mtp\",\"description\":\"MTP Host\\nHandles MTP(Media Transfer Protocol), a protocol for transfering files between the device and a connected PC.\",\"removal\":\"unsafe\",\"type\":\"aosp\"},{\"id\":\"com.android.musicfx\",\"label\":\"MusicFX\",\"description\":\"Audio EQ (equalizer). Some 3rd-party music apps can use it to provide you EQ features.\",\"removal\":\"replace\",\"type\":\"aosp\"},{\"id\":\"com.android.musicvis\",\"label\":\"Music Visualization Wallpapers\",\"description\":\"Built-in live wallpaper\",\"removal\":\"delete\",\"type\":\"aosp\"},{\"id\":\"com.android.nearby.halfsheet\",\"description\":\"Useless frameworks to Wi-Fi connections, USB tethering, auto, usage.\\nEvery version has random code and the app is not running in the background.\",\"removal\":\"delete\",\"type\":\"aosp\"},{\"id\":\"com.android.networkstack.inprocess\",\"label\":\"NetworkStack\",\"description\":\"Related to the Network Stack module, which is an updatable Mainline module that ensures Android can adapt to evolving network standards and allows for interoperability with new implementations\",\"web\":[\"https://source.android.com/docs/core/ota/modular-system/networking\"],\"removal\":\"unsafe\",\"type\":\"aosp\"},{\"id\":\"com.android.networkstack.inprocess.overlay\",\"description\":\"Related to the Network Stack module,\\nwhich is an updatable Mainline module that ensures Android can adapt to evolving network standards and allows for interoperability with new implementations\\nhttps://source.android.com/docs/core/ota/modular-system/networking\",\"removal\":\"unsafe\",\"type\":\"aosp\"},{\"id\":\"com.android.networkstack.overlay\",\"description\":\"WiFi will not work after remove.\",\"removal\":\"unsafe\",\"type\":\"aosp\"},{\"id\":\"com.android.networkstack.permissionconfig\",\"description\":\"Defines a permission that enables modules to perform network-related tasks.\",\"web\":[\"https://source.android.com/devices/architecture/modular-system/networking\"],\"removal\":\"unsafe\",\"type\":\"aosp\"},{\"id\":\"com.android.networkstack.tethering.inprocess.overlay\",\"description\":\"Related to the Tethering module,\\nwhich allows an Android device to share its internet connection with other connected client devices.\\nThis package contains classes and components that are used for in-process overlay functionality within the Tethering module.\\nhttps://source.android.com/docs/core/ota/modular-system/tethering\",\"removal\":\"unsafe\",\"type\":\"aosp\"},{\"id\":\"com.android.networkstack.tethering.overlay\",\"description\":\"Component of the Network, Tethering module.\\nPackage is not a publicly documented.\",\"removal\":\"unsafe\",\"type\":\"aosp\"},{\"id\":\"com.android.nfc\",\"label\":\"Nfc Service\",\"description\":\"Runs in the background as part of the System.\\nI assume NFC breaks when disabled.\\nWill probably run even if disabled, like most system packages. So disabling/uninstalling is probably pointless.\",\"removal\":\"caution\",\"type\":\"aosp\"},{\"id\":\"com.android.noisefield\",\"label\":\"Bubbles\",\"description\":\"Built-in live wallpaper.\",\"removal\":\"delete\",\"type\":\"aosp\"},{\"id\":\"com.android.ondevicepersonalization.services\",\"description\":\"OnDevicePersonalization. Another thing to AdServices privacy sandbox.\\nIntroduced in Android 13.\\nhttps://source.android.com/docs/core/ota/modular-system/ondevicepersonalization\",\"removal\":\"delete\",\"type\":\"aosp\"},{\"id\":\"com.android.ons\",\"label\":\"com.android.ons\",\"description\":\"ons = Opportunistic Network Service\\nFrom what I can glean in the source code it seems like this provides a list of available networks and assigns each network a priority.\\nI've never seen it run on its own, so this might be part of some automatic network switching setting that I have turned off.\",\"web\":[\"https://cs.android.com/android/platform/superproject/+/master:packages/services/AlternativeNetworkAccess/src/com/android/ons/OpportunisticNetworkService.java\",\"https://developer.android.com/reference/android/telephony/AvailableNetworkInfo\",\"https://cs.android.com/android/platform/superproject/+/master:frameworks/base/telephony/java/android/telephony/AvailableNetworkInfo.java\"],\"removal\":\"caution\",\"type\":\"aosp\"},{\"id\":\"com.android.otaprovisioningclient\",\"label\":\"OTA Access Point Configuration\",\"description\":\"OTA (Over the air) is the method used by OEMs to push updates to your device.\\nAn OTA access point is used to run system software updates over a special gateway. This package is most likely customized by your OEM.\",\"removal\":\"caution\",\"type\":\"aosp\"},{\"id\":\"com.android.overlay.systemui\",\"description\":\"On some phones, it is an overlay to app \\\"com.google.android.apps.safetyhub\\\".\\nCheck out this app code and think about it.\",\"removal\":\"caution\",\"type\":\"aosp\"},{\"id\":\"com.android.packageinstaller\",\"description\":\"Handles installation, upgrade, and removal of applications.\\n\",\"removal\":\"unsafe\",\"type\":\"aosp\"},{\"id\":\"com.android.pacprocessor\",\"label\":\"PacProcessor\",\"description\":\"PAC (Proxy Auto-Config) is a file which defines how an app can automatically find the correct proxy server for fetching an URL.\\nShould be safe to remove if you don't use Auto-proxy (with PAC file config).\",\"web\":[\"https://en.wikipedia.org/wiki/Proxy_auto-config\"],\"removal\":\"caution\",\"type\":\"aosp\"},{\"id\":\"com.android.phasebeam\",\"label\":\"Phase beam\",\"description\":\"Built-in live wallpaper\",\"removal\":\"delete\",\"type\":\"aosp\"},{\"id\":\"com.android.phone\",\"description\":\"AOSP Dialer\\nRemoving this package breaks the software update/download and install screen on Samsung. WARNING: for me, it breaks the phone app completely with call routing enabled. Not sure about other cases.\",\"removal\":\"caution\",\"type\":\"aosp\"},{\"id\":\"com.android.phone.a_overlay\",\"description\":\"AOSP code for dialer app features.\\nSIM card will not be detected if disabled.\",\"removal\":\"unsafe\",\"type\":\"aosp\"},{\"id\":\"com.android.phone.basiccolorblack.overlay\",\"description\":\"Dark theme for phone app?\",\"removal\":\"caution\",\"type\":\"aosp\"},{\"id\":\"com.android.phone.basiccolorwhite.overlay\",\"description\":\"Light theme for phone app?\",\"removal\":\"caution\",\"type\":\"aosp\"},{\"id\":\"com.android.phone.overlay.common\",\"description\":\"Location and dialer things.\",\"removal\":\"unsafe\",\"type\":\"aosp\"},{\"id\":\"com.android.phone.recorder\",\"label\":\"Recorder\",\"description\":\"AOSP Call recorder function. Most of the time OEM use their own code for this.\\nSome OEMs (like Huawei & Xiaomi) use the same package name for their app\",\"removal\":\"replace\",\"suggestions\":\"call_recorders\",\"type\":\"aosp\"},{\"id\":\"com.android.printservice.recommendation\",\"label\":\"Print Service Recommendation Service\",\"description\":\"Recommends 3rd-party print services apps in the PlayStore. Printing will probably still work without it (by using the default print service).\",\"removal\":\"replace\",\"type\":\"aosp\"},{\"id\":\"com.android.printspooler\",\"label\":\"Print Spooler\",\"description\":\"Manages the printing process.\\nRuns on boot, but not beyond that.\",\"removal\":\"caution\",\"warning\":\"Apart from breaking the printing functionality, it also breaks the connection preferences submenu in the settings app on most devices.\",\"type\":\"aosp\"},{\"id\":\"com.android.protips\",\"label\":\"Home screen tips\",\"description\":\"Runs on boot.\\nThe tip popups you get on the homescreen.\",\"removal\":\"delete\",\"type\":\"aosp\"},{\"id\":\"com.android.providers.applications\",\"description\":\"Provides a list of installed applications.\\nContent providers encapsulate data, providing centralized management of data shared between apps.\\nhttps://developer.android.com/guide/topics/providers/content-providers.html\",\"removal\":\"unsafe\",\"type\":\"aosp\"},{\"id\":\"com.android.providers.blockednumber\",\"label\":\"Blocked Numbers Storage\",\"description\":\"Handles blocked number storage.\\nOn some devices this seems to be tied to the recent apps menu.\\nContent providers encapsulate data, providing centralized management of data shared between apps.\",\"web\":[\"https://gitlab.com/W1nst0n/universal-android-debloater/-/issues/6\",\"https://developer.android.com/guide/topics/providers/content-providers.html\"],\"removal\":\"caution\",\"type\":\"aosp\"},{\"id\":\"com.android.providers.calendar\",\"label\":\"Calendar Storage\",\"description\":\"Necessary for the stock Calendar app to work correctly.\\nContent providers encapsulate data, providing centralized management of data shared between apps.\",\"web\":[\"https://developer.android.com/guide/topics/providers/content-providers.html\"],\"removal\":\"caution\",\"type\":\"aosp\"},{\"id\":\"com.android.providers.contacts\",\"label\":\"Contacts Storage\",\"description\":\"Provider for contact data.\\nContent providers encapsulate data, providing centralized management of data shared between apps.\",\"web\":[\"https://developer.android.com/guide/topics/providers/content-providers.html\"],\"removal\":\"caution\",\"warning\":\"Breaks contact functionality if disabled. Not recommended to disable if you plan to use your device as a phone.\",\"type\":\"aosp\"},{\"id\":\"com.android.providers.downloads\",\"description\":\"Downloads Manager\\nProvider for downloaded files.\\nContent providers encapsulate data, providing centralized management of data shared between apps.\\nhttps://developer.android.com/guide/topics/providers/content-providers.html\",\"removal\":\"unsafe\",\"type\":\"aosp\"},{\"id\":\"com.android.providers.downloads.ui\",\"description\":\"Downloads\\nUser interface for downloads.\\nOn some OEM's this app has ads, tracking things.\",\"removal\":\"replace\",\"type\":\"aosp\"},{\"id\":\"com.android.providers.drm\",\"label\":\"DRM Protected Content Storage\",\"description\":\"Manages DRM storage on the device?\\nProbably required for some forms of DRM; disabling might break things like Netflix streaming, which relies on DRM to function.\",\"web\":[\"https://en.wikipedia.org/wiki/Digital_rights_management\"],\"removal\":\"caution\",\"type\":\"aosp\"},{\"id\":\"com.android.providers.media\",\"label\":\"Media Storage\",\"description\":\"Provider of media files (images, videos and such).\\nScans the device for media files and allows permitted apps access to them.\\nContent providers encapsulate data, providing centralized management of data shared between apps.\",\"web\":[\"https://developer.android.com/guide/topics/providers/content-providers.html\"],\"removal\":\"unsafe\",\"warning\":\"Breaks features related to media storage (images, videos, music, etc.) if disabled\",\"type\":\"aosp\"},{\"id\":\"com.android.providers.partnerbookmarks\",\"label\":\"com.android.providers.partnerbookmarks\",\"description\":\"Provides bookmarks about partners of Google in Chrome.\\n\",\"removal\":\"delete\",\"type\":\"aosp\"},{\"id\":\"com.android.providers.settings\",\"description\":\"Provider for settings app data.\\nContent providers encapsulate data, providing centralized management of data shared between apps.\\nhttps://developer.android.com/guide/topics/providers/content-providers.html\",\"removal\":\"unsafe\",\"type\":\"aosp\"},{\"id\":\"com.android.providers.telephony\",\"description\":\"Provider for telephony data.\\nHandles phone-related data such as text messages, APN list, etc.\\nContent providers encapsulate data, providing centralized management of data shared between apps.\\nhttps://developer.android.com/guide/topics/providers/content-providers.html\",\"removal\":\"unsafe\",\"type\":\"aosp\"},{\"id\":\"com.android.providers.userdictionary\",\"label\":\"User Dictionary\",\"description\":\"Handles user dictionary for keyboard apps.\\nContent providers encapsulate data, providing centralized management of data shared between apps.\",\"web\":[\"https://developer.android.com/guide/topics/providers/content-providers.html\"],\"removal\":\"caution\",\"warning\":\"Removing this package may cause settings menu to crash on some Huawei phones\",\"type\":\"aosp\"},{\"id\":\"com.android.provision\",\"description\":\"Provisioning is the process of setting up a network connection that will allow new users. \\nThis service is for example needed when the user's phone moves from one cell-tower to another.\\n\",\"removal\":\"unsafe\",\"type\":\"aosp\"},{\"id\":\"com.android.proxyhandler\",\"label\":\"ProxyHandler\",\"description\":\"Handles proxy config.\",\"removal\":\"caution\",\"warning\":\"Do not remove if you use a system proxy\",\"type\":\"aosp\"},{\"id\":\"com.android.quicksearchbox\",\"label\":\"Quick Search\",\"description\":\"Google quick search box. OEMs (e.g. Xiaomi) can modify this for their own use.\",\"removal\":\"delete\",\"type\":\"aosp\"},{\"id\":\"com.android.remoteprovisioner\",\"description\":\"RemoteProvisioner. Have random stuff: security, notifications, accessibility, test modes, data usage, metrics, logs.\\nIts something new introduced in Android 13.\\nAt this time this app is not available for users.\\nAnd looks very useless.\",\"removal\":\"delete\",\"type\":\"aosp\"},{\"id\":\"com.android.rkpdapp\",\"description\":\"RemoteProvisioner. Have random stuff: security, notifications, accessibility, test modes, data usage, metrics, logs.\\nIntroduced in android 14(it's the same app like `com.android.remoteprovisioner` Introduced in android 13).\\nAgain this app is not available for users.\\nAnd looks very useless.\",\"removal\":\"delete\",\"type\":\"aosp\"},{\"id\":\"com.android.runintest.ddrtest\",\"label\":\"DDRTest\",\"description\":\"RAM Stress tester\\nCan be run from the bootloader\\nNOTE: I'm not sure it's really from AOSP (seen in TCL Plex phone)\",\"removal\":\"delete\",\"type\":\"aosp\"},{\"id\":\"com.android.safetycenter.resources\",\"description\":\"Google Safety Center.\\nProbably affects malware detection in new app installs, Gmail, and Chrome. This will also revert back the \\\"Security & privacy\\\" look to the old style.\\nYou can use a libre spam-blocking and DNS-blocking solution instead of this.\\nhttps://safety.google\",\"removal\":\"delete\",\"type\":\"aosp\"},{\"id\":\"com.android.sdksandbox\",\"description\":\"Introduced in Android 13 privacy sandbox beta disabled on default.\\nCauses bootloop. Maybe this component is not only for privacy... (I think it's for testing privacy sandbox using Android Studio.)\\nhttps://source.android.com/docs/core/ota/modular-system/adservices\\nCause BOOTLOOP.\",\"removal\":\"unsafe\",\"type\":\"aosp\"},{\"id\":\"com.android.se\",\"label\":\"SecureElementApplication\",\"description\":\"Runs in the background as part of the system.\\nUnderlying implementation for the OMAPI SE service.\\nEnables apps to use the OpenMobile API to access secure elements(SE) to enable smart-card payments and other secure services.\\n\\nAn SE is a special chip (e.g SIM-card) for storing cryptographic secrets in a way that makes illicit use hard.\\nThe Open Mobile Alliance (OPA) is a standards organization which develops open standards for the mobile phone industry.\",\"removal\":\"caution\",\"warning\":\"ColorOS password lock requires this package.\",\"type\":\"aosp\"},{\"id\":\"com.android.se.overlay.target\",\"description\":\"Looks like needed to 'com.android.se'.\",\"removal\":\"replace\",\"type\":\"aosp\"},{\"id\":\"com.android.server.NetworkPermissionConfig\",\"description\":\"Network configurations.\",\"removal\":\"unsafe\",\"type\":\"aosp\"},{\"id\":\"com.android.server.telecom\",\"description\":\"Manages calls via your network provider or SIM and controls the phone modem?\",\"removal\":\"unsafe\",\"type\":\"aosp\"},{\"id\":\"com.android.server.telecom.a_overlay\",\"description\":\"Overlay for com.android.server.telecom?\",\"removal\":\"unsafe\",\"type\":\"aosp\"},{\"id\":\"com.android.server.telecom.basiccolorblack.overlay\",\"description\":\"Dark theme for something related to call network management?\",\"removal\":\"caution\",\"type\":\"aosp\"},{\"id\":\"com.android.server.telecom.basiccolorwhite.overlay\",\"description\":\"Light theme for something related to call network management?\",\"removal\":\"caution\",\"type\":\"aosp\"},{\"id\":\"com.android.server.telecom.overlay.common\",\"description\":\"Location and dialer things.\",\"removal\":\"unsafe\",\"type\":\"aosp\"},{\"id\":\"com.android.settings\",\"description\":\"AOSP Settings app.\",\"removal\":\"unsafe\",\"type\":\"aosp\"},{\"id\":\"com.android.settings.basiccolorblack.overlay\",\"description\":\"Dark theme overlay for the Settings app?\",\"removal\":\"caution\",\"type\":\"aosp\"},{\"id\":\"com.android.settings.basiccolorwhite.overlay\",\"description\":\"Light theme overlay for the Settings app?\",\"removal\":\"caution\",\"type\":\"aosp\"},{\"id\":\"com.android.settings.intelligence\",\"label\":\"Settings Suggestions\",\"description\":\"Handles the search and suggestions features in the settings app.\\nDoesn't run in the background, so there's little benefit in disabling.\",\"web\":[\"https://gitlab.com/W1nst0n/universal-android-debloater/-/issues/51\"],\"removal\":\"caution\",\"warning\":\"Disabling this package makes the Settings app crash when you tap on search.\",\"type\":\"aosp\"},{\"id\":\"com.android.settings.intelligence.basiccolorblack.overlay\",\"description\":\"Dark theme overlay for the search functionality in the Settings app?\",\"removal\":\"caution\",\"type\":\"aosp\"},{\"id\":\"com.android.settings.intelligence.basiccolorwhite.overlay\",\"description\":\"Light theme overlay for the search functionality in the Settings app?\",\"removal\":\"caution\",\"type\":\"aosp\"},{\"id\":\"com.android.sharedstoragebackup\",\"label\":\"com.android.sharedstoragebackup\",\"description\":\"Used during backup. Backs up the shared storage? (files accessible by every app with STORAGE permission)\\nThings have changed with Android 10. Don't know if this package is still relevant for new phones.\",\"web\":[\"https://blog.mindorks.com/understanding-the-scoped-storage-in-android\"],\"removal\":\"caution\",\"type\":\"aosp\"},{\"id\":\"com.android.shell\",\"description\":\"Shell\\nUnix shell that receives ADB commands sent from a PC.\\nThis is what UAD-ng uses to execute commands on Android devices. Proobably a bad idea to disable ;)\",\"removal\":\"unsafe\",\"type\":\"aosp\"},{\"id\":\"com.android.simappdialog\",\"label\":\"SIM App Dialog\",\"description\":\"Creates a pop-up asking if the user wants to install the carrier app when a SIM is inserted. Seems to be event-triggered, i.e., doesn't run in the background.\",\"web\":[\"https://android.googlesource.com/platform/frameworks/base/+/master/packages/SimAppDialog/src/com/android/simappdialog/InstallCarrierAppActivity.java\"],\"removal\":\"caution\",\"type\":\"aosp\"},{\"id\":\"com.android.smspush\",\"label\":\"com.android.smspush\",\"description\":\"This service is used to push/send specially formatted SMS messages that display an alert message to the user, and give them the option of connecting directly to a particular app.\\nFor instance, an SMS notifying the user of a new e-mail, with a URL link to connect directly to the e-mail app.\",\"web\":[\"https://web.archive.org/web/20200915164901/https://www.nowsms.com/doc/submitting-sms-messages/sending-wap-push-messages\"],\"removal\":\"replace\",\"suggestions\":\"sms\",\"type\":\"aosp\"},{\"id\":\"com.android.soundrecorder\",\"label\":\"Sound Recorder\",\"description\":\"AOSP Sound recorder. OEMs often use their own solution.\\nSome phones (Huawei and Xiaomi) also use this package name for their own recorder app.\",\"removal\":\"replace\",\"suggestions\":\"audio_recorders\",\"type\":\"aosp\"},{\"id\":\"com.android.statementservice\",\"description\":\"Intent Filter Verification Service\\nA Statement protocol allows websites to certify that some assets represent them. Android package can to subscribe to handling chosen URIs. This package will then be called to query the website and verify that it allows this. Android package can subscribe to handling chosen URIs. This package will then be called to query the website and verify that it allows this. Sources:\\n- https://developer.android.com/reference/android/content/Intent\\n- https://developer.android.com/guide/components/intents-filters\\n - https://android.stackexchange.com/questions/191163/what-does-the-intent-filter-verification-service-app-from-google-do\\n - https://github.com/google/digitalassetlinks/blob/master/well-known/details.md\\n - https://android.googlesource.com/platform/frameworks/base/+/6a34bb2\",\"removal\":\"unsafe\",\"type\":\"aosp\"},{\"id\":\"com.android.stk\",\"label\":\"SIM Toolkit\",\"description\":\"Enables carriers to initiate \\\"value-added services\\\". Basically, some operators provide SIM-cards with applications installed on them.\\nThis has been abused:\\n- SimJacker \\n- WIBattack.\\nNOTE: removing this package removes the launcher icon. \\\"com.android.stk\\\" relies on \\\"com.android.stk2\\\" and vice-versa.\",\"web\":[\"https://en.wikipedia.org/wiki/SIM_Application_Toolkit#cite_note-CellularZA-1\",\"https://thehackernews.com/2019/09/simjacker-mobile-hacking.html\",\"https://www.zdnet.com/article/new-sim-card-attack-disclosed-similar-to-simjacker/\",\"https://en.wikipedia.org/wiki/Mobile_identity_management\"],\"removal\":\"caution\",\"warning\":\"Disabling/uninstalling this package will break mobile identity management which could be used by apps (for example, your Bank) to authenticate you.\",\"type\":\"aosp\"},{\"id\":\"com.android.stk2\",\"label\":\"SIM Toolkit\",\"description\":\"Special package for dual-sim devices?\\nEnables carriers to initiate \\\"value-added services\\\". Basically, some operators provide SIM-cards with applications installed on them.\\nThis has been abused:\\n- SimJacker \\n- WIBattack.\\nNOTE: removing this package removes the launcher icon. \\\"com.android.stk2\\\" relies on \\\"com.android.stk\\\" and vice-versa.\",\"web\":[\"https://en.wikipedia.org/wiki/SIM_Application_Toolkit#cite_note-CellularZA-1\",\"https://thehackernews.com/2019/09/simjacker-mobile-hacking.html\",\"https://www.zdnet.com/article/new-sim-card-attack-disclosed-similar-to-simjacker/\",\"https://en.wikipedia.org/wiki/Mobile_identity_management\"],\"removal\":\"caution\",\"warning\":\"Vulnerable to hacking, should be disabled.\",\"type\":\"aosp\"},{\"id\":\"com.android.storagemanager\",\"label\":\"Smart Storage\",\"description\":\"Storage manager (Maintenance/Storage panel in the settings)\\nClean up unused files, show size of files regrouped by categories.\",\"removal\":\"caution\",\"warning\":\"May break the storage settings in Android Settings.\",\"type\":\"aosp\"},{\"id\":\"com.android.systemui\",\"description\":\"Everything you see in Android that's not an app. User interface of Android\\n\",\"removal\":\"unsafe\",\"type\":\"aosp\"},{\"id\":\"com.android.systemui.accessibility.accessibilitymenu\",\"description\":\"Hidden menu that only shows 2 buttons:\\nLarge buttons - that increases size of accessibility menu buttons,\\nand Help - that redirects to support google com site accessibility.\",\"removal\":\"delete\",\"type\":\"aosp\"},{\"id\":\"com.android.systemui.accessibility.accessibilitymenu.auto_generated_rro_product__\",\"description\":\"Product RRO for Accessibility menu.\",\"removal\":\"replace\",\"type\":\"aosp\"},{\"id\":\"com.android.systemui.gesture.line.overlay\",\"description\":\"Configurations to navigation bar.\",\"removal\":\"unsafe\",\"type\":\"aosp\"},{\"id\":\"com.android.systemui.icon.overlay\",\"description\":\"In code found configs icon mask.\",\"removal\":\"caution\",\"type\":\"aosp\"},{\"id\":\"com.android.systemui.navigation.bar.overlay\",\"description\":\"Configurations to navigation bar.\",\"removal\":\"unsafe\",\"type\":\"aosp\"},{\"id\":\"com.android.systemui.overlay\",\"description\":\"System UI Overlay. DO NOT remove this.\",\"removal\":\"unsafe\",\"type\":\"aosp\"},{\"id\":\"com.android.systemui.overlay.common\",\"description\":\"System UI Theme pack\\nThe package name is pretty self-explanatory.\",\"removal\":\"delete\",\"type\":\"aosp\"},{\"id\":\"com.android.systemui.theme.dark\",\"label\":\"Dark\",\"description\":\"Enables you to use Android dark theme.\",\"removal\":\"caution\",\"type\":\"aosp\"},{\"id\":\"com.android.theme.font.notoserifsource\",\"description\":\"Noto Serif / Source Sans Pro\",\"removal\":\"delete\",\"type\":\"aosp\"},{\"id\":\"com.android.theme.icon.circle\",\"label\":\"Circle\",\"description\":\"Android icons pack [Circle]\",\"removal\":\"delete\",\"type\":\"aosp\"},{\"id\":\"com.android.theme.icon.pebble\",\"label\":\"Pebble\",\"description\":\"Android icons pack [Pebble]\",\"removal\":\"delete\",\"type\":\"aosp\"},{\"id\":\"com.android.theme.icon.square\",\"label\":\"Square\",\"description\":\"Android icons pack [Square]\",\"removal\":\"delete\",\"type\":\"aosp\"},{\"id\":\"com.android.theme.icon.taperedrect\",\"label\":\"Tapered Rect\",\"description\":\"Android icons pack [Taperedrect]\",\"removal\":\"delete\",\"type\":\"aosp\"},{\"id\":\"com.android.theme.icon.vessel\",\"label\":\"Vessel\",\"description\":\"Android icons pack [Vessel]\",\"removal\":\"delete\",\"type\":\"aosp\"},{\"id\":\"com.android.theme.icon_pack.rounded.systemui\",\"label\":\"Rounded\",\"description\":\"Android icons pack [Rounded]\",\"removal\":\"delete\",\"type\":\"aosp\"},{\"id\":\"com.android.theme.icon_pack.rounded.themepicker\",\"label\":\"Rounded\",\"description\":\"Obviously related to the \\\"rounded\\\" icon pack but the full package is strange. A themepicker class only for a specific icon package?\",\"removal\":\"delete\",\"type\":\"aosp\"},{\"id\":\"com.android.timezone.updater\",\"label\":\"Time Zone Updater\",\"description\":\"Automatically updates the clock to correspond to your current time zone.\",\"removal\":\"caution\",\"warning\":\"This may cause a bootloop if removed. Timezone packages often causes that.\",\"type\":\"aosp\"},{\"id\":\"com.android.traceur\",\"label\":\"System Tracing\",\"description\":\"Recording device activity over a short period of time is known as system tracing. System tracing produces a trace file that can be used to generate a system report.\\nNot useful if you're not a developer.\",\"web\":[\"https://developer.android.com/topic/performance/tracing\"],\"removal\":\"delete\",\"type\":\"aosp\"},{\"id\":\"com.android.uwb.resources\",\"description\":\"Ultra-wideband (UWB) communication feature.\\nUWB is a radio technology that enables precise ranging between devices,\\nAllowing for accurate location measurements with an accuracy of 10 cm.\\nhttps://developer.android.com/develop/connectivity/uwb\\nhttps://source.android.com/docs/core/connect/uwb\",\"removal\":\"unsafe\",\"type\":\"aosp\"},{\"id\":\"com.android.virtualmachine.res\",\"description\":\"unknown app with no code that only has permissions to Use, Manage, Debug: Virtual Machine.\\nIntroduced in Android 14.\",\"removal\":\"delete\",\"type\":\"aosp\"},{\"id\":\"com.android.voicedialer\",\"label\":\"Voice Dialer\",\"description\":\"The AOSP Voice dialer. Lets you call someone or open an app with your voice from the dialer.\\nOEM often use their own code (embeded in their voice-controlled digital assistant)\\nSome OEMs (Huawei, Sony, Xiaomi) also use this package name for their own voice dialer app.\",\"removal\":\"replace\",\"suggestions\":\"dialers\",\"type\":\"aosp\"},{\"id\":\"com.android.vpndialogs\",\"label\":\"VpnDialogs\",\"description\":\"Provide VPN support to Android\\nSafe to remove if you don't plan to use a VPN.\",\"removal\":\"caution\",\"type\":\"aosp\"},{\"id\":\"com.android.wallpaper.holospiral\",\"label\":\"Holo Spiral\",\"description\":\"Built-in live wallpaper.\",\"removal\":\"delete\",\"type\":\"aosp\"},{\"id\":\"com.android.wallpaper.livepicker\",\"label\":\"Live Wallpaper Picker\",\"description\":\"Enables you to pick a live wallpaper.\",\"removal\":\"caution\",\"warning\":\"Removing it will break some weather applications (especially ones with widgets) and wallpaper applications like Muzei.\",\"type\":\"aosp\"},{\"id\":\"com.android.wallpaper.livepicker.overlay\",\"label\":\"com.android.wallpaper.livepicker.overlay\",\"description\":\"Overlay for live wallpaper picker? Overlays are usually themes, but not sure about this one.\",\"removal\":\"delete\",\"type\":\"aosp\"},{\"id\":\"com.android.wallpaperbackup\",\"label\":\"com.android.wallpaperbackup\",\"description\":\"Backs up and restores wallpaper and metadata related to it.\\nThis agent has its own package because it does full backup as opposed to SystemBackupAgent which does key/value backup.\\nThis class stages wallpaper files for backup by copying them into its own directory because of the following reasons:\\nNon-system users don't have permission to read the directory that the system stores the wallpaper files in\\nBackupAgent enforces that backed up files must live inside the package's getFilesDir()\\nThere are 3 files to back up:\\nThe \\\"wallpaper info\\\"  file which contains metadata like the crop applied to the wallpaper or the live wallpaper component name.\\nThe \\\"system\\\" wallpaper file.\\nAn optional \\\"lock\\\" wallpaper, which is shown on the lockscreen instead of the system wallpaper if set.\\nOn restore, the metadata file is parsed and WallpaperManager APIs are used to set the wallpaper.\\nNote that if there's a live wallpaper, the live wallpaper package name will be part of the metadata file and the wallpaper will be applied when the package it's installed.\",\"web\":[\"https://android.googlesource.com/platform/frameworks/base/+/master/packages/WallpaperBackup/src/com/android/wallpaperbackup/WallpaperBackupAgent.java\"],\"removal\":\"delete\",\"type\":\"aosp\"},{\"id\":\"com.android.wallpapercropper\",\"label\":\"com.android.wallpapercropper\",\"description\":\"Wallpaper cropper.\",\"removal\":\"delete\",\"type\":\"aosp\"},{\"id\":\"com.android.wallpaperpicker\",\"label\":\"com.android.wallpaperpicker\",\"description\":\"Enables you to pick a wallpaper.\",\"removal\":\"caution\",\"type\":\"aosp\"},{\"id\":\"com.android.webview\",\"label\":\"Android System WebView\",\"description\":\"enables Android apps to display web content within the app itself, based on Chrome.\",\"removal\":\"caution\",\"warning\":\"Make sure to have another Webview before uninstalling it or some apps may not work properly and crash.\",\"suggestions\":\"webviews\",\"type\":\"aosp\"},{\"id\":\"com.android.wifi.dialog\",\"description\":\"Needed for wifi dialogs.\\nCan brick basic functionality android.\",\"removal\":\"unsafe\",\"type\":\"aosp\"},{\"id\":\"com.android.wifi.mainline.resources.overlay\",\"description\":\"Related to the Wi-Fi module in the AOSP. The Wi-Fi module is a part of Project Mainline,\\nWhich allows for updates to specific system components outside of the normal Android release cycle.\\nThe package contains resources and overlays that are used to customize the Wi-Fi module.\\nThese overlays can be used to override default configurations and customize the behavior of the Wi-Fi module\\nhttps://source.android.com/docs/core/ota/modular-system/wifi\\nhttps://www.xda-developers.com/android-project-mainline-modules-explanation\",\"removal\":\"unsafe\",\"type\":\"aosp\"},{\"id\":\"com.android.wifi.resources\",\"label\":\"System Wi-Fi Resources\",\"description\":\"System Wi-Fi resources.\",\"removal\":\"unsafe\",\"type\":\"aosp\"},{\"id\":\"com.android.wifi.resources.overlay\",\"label\":\"com.android.wifi.resources.overlay\",\"description\":\"Contains resources that can be overlaid or customized to modify the behavior of the Wi-Fi module.\\nhttps://source.android.com/docs/core/ota/modular-system/wifi\",\"removal\":\"unsafe\",\"type\":\"aosp\"},{\"id\":\"com.android.wifi.resources.overlay.WifiResScanCountryCode\",\"label\":\"com.android.wifi.resources.overlay.WifiResScanCountryCode\",\"description\":\"Related to overlay for Wi-Fi scanning for country code.\",\"removal\":\"caution\",\"type\":\"aosp\"},{\"id\":\"com.android.wifi.system.mainline.resources.overlay\",\"description\":\"Related to the Wi-Fi module and its resources overlay.\\nThe Wi-Fi module in Android is updatable, meaning it can receive updates to functionality outside of the normal Android release cycle.\\nThe module provides a consistent Wi-Fi experience across Android devices and allows for fixes to interoperability issues through module updates\\nhttps://source.android.com/docs/core/ota/modular-system/wifi\",\"removal\":\"caution\",\"type\":\"aosp\"},{\"id\":\"com.android.wifi.system.resources.overlay\",\"description\":\"Contains resources that can be overlaid to customize the Wi-Fi module's behavior.\\nhttps://source.android.com/docs/core/ota/modular-system/wifi\",\"removal\":\"caution\",\"type\":\"aosp\"},{\"id\":\"com.example.android.notepad\",\"label\":\"NotePad\",\"description\":\"(Bad) notepad app.\",\"removal\":\"replace\",\"suggestions\":\"note_taking_apps\",\"type\":\"aosp\"},{\"id\":\"com.google.android.adservices.api\",\"description\":\"Introduced in Android 13 privacy sandbox beta components disabled on default.\\nhttps://source.android.com/docs/core/ota/modular-system/adservices\",\"removal\":\"delete\",\"type\":\"aosp\"},{\"id\":\"com.google.android.androidforwork\",\"description\":\"Assistant Android Work\\nNot needed, theres only user consent activity about that:\\n(Your organization controls your device and keeps it secure)\",\"removal\":\"delete\",\"type\":\"aosp\"},{\"id\":\"com.google.android.apps.googlecamera.fishfood\",\"description\":\"ApertureLensLauncher\\nNot sure how it works but redirects to google app lens `com.google.android.googlequicksearchbox`.\",\"removal\":\"delete\",\"type\":\"aosp\"},{\"id\":\"com.google.android.appsearch.apk\",\"description\":\"AppSearch is an on-device search library for managing locally stored structured data, with APIs for indexing data and retrieving data using full-text search. Use it to build custom in-app search capabilities for your users.\\nhttps://developer.android.com/jetpack/androidx/releases/appsearch\",\"removal\":\"caution\",\"type\":\"aosp\"},{\"id\":\"com.google.android.captiveportallogin\",\"label\":\"CaptivePortalLogin\",\"description\":\"it's the same as (com.android.captiveportallogin). Support for captive portal.\\nA captive portal login is a web page where the users have to input their login information or accept the displayed terms of use. \\nSome networks (typically public wifi network) use the captive portal login to block access until the user inputs \\nsome necessary information\\nNOTE : This package is a now a mandatory mainline module\\nhttps://en.wikipedia.org/wiki/Captive_portal\\nhttps://www.xda-developers.com/android-project-mainline-modules-explanation\",\"removal\":\"caution\",\"type\":\"aosp\"},{\"id\":\"com.google.android.carrierconfig\",\"label\":\"com.google.android.carrierconfig\",\"description\":\"Same as com.android.carrierconfig? Here's that description:\\nDynamically provides configuration for the carrier network.\\nThe config contains: Roaming networks, Voicemail settings, SMS/MMS settings, VoLTE/IMS settings, and more.\\nIf a carrier app is installed it will be queried for overrides to these settings.\\nSeems to run on boot and when you swap SIM card?\",\"web\":[\"https://source.android.com/devices/tech/config/carrier\",\"https://cs.android.com/android/platform/superproject/+/master:packages/apps/CarrierConfig/src/com/android/carrierconfig/DefaultCarrierConfigService.java\"],\"removal\":\"replace\",\"type\":\"aosp\"},{\"id\":\"com.google.android.connectivity.resources\",\"label\":\"System Connectivity Resources\",\"description\":\"Handles connectivity-related resources, such as Wi-Fi, Bluetooth, and cellular network management.\",\"removal\":\"unsafe\",\"warning\":\"Removing this packages causes a bootloop.\",\"type\":\"aosp\"},{\"id\":\"com.google.android.documentsui\",\"label\":\"Files\",\"description\":\"Occasionally runs in the background.\\nFile selector for other apps.\",\"removal\":\"unsafe\",\"warning\":\"Storage Access Framework (SAF) will break if this is disabled.\",\"type\":\"aosp\"},{\"id\":\"com.google.android.email\",\"label\":\"Email\",\"description\":\"Newer versions of AOSP Mail are renamed to com.android.email and Gmail was migrated to com.google.android.gm\",\"removal\":\"replace\",\"suggestions\":\"email_clients\",\"type\":\"aosp\"},{\"id\":\"com.google.android.ext.services\",\"description\":\"The ExtServices module updates framework components for core OS functionality such as notification ranking, autofill text-matching strategies, storage cache, package watchdog, and other services that run continually. This module is updatable, meaning it can receive updates to functionality outside of the normal Android release cycle.\\nCan run before the user unlocks the device (direct-boot aware) and Android 9+ version have internet and location permissions.\\n\\nWARNING: Causes bootloop on most Android 11+ phones. This module is related to the Android mainline project (which is a useful project).There is no reason to mess with this.\\n\\nSources:\\nhttps://source.android.com/devices/architecture/modular-system/extservices\\nhttps://arstechnica.com/gadgets/2016/11/android-extensions-could-be-googles-plan-to-make-android-updates-suck-less/\\nPithus analysis (Android 11): https://beta.pithus.org/report/e5e4a181082b88baf55e19aab0f9cb62e131d612eeaa73cddb510a52e0ff5c1a\",\"removal\":\"unsafe\",\"type\":\"aosp\"},{\"id\":\"com.google.android.ext.shared\",\"label\":\"Android Shared Library\",\"description\":\"Used to share common code between apps.\",\"removal\":\"unsafe\",\"type\":\"aosp\"},{\"id\":\"com.google.android.federatedcompute\",\"description\":\"FederatedCompute.\\nAnother component of OnDevicePersonalization. But this app learns things about users.\\nIntroduced in Android 13.\\nhttps://source.android.com/docs/core/ota/modular-system/ondevicepersonalization\",\"removal\":\"delete\",\"type\":\"aosp\"},{\"id\":\"com.google.android.gallery3d\",\"description\":\"Built-in Gallery app.\\nThe ID could be \\\"recycled\\\" by OEMs for their own gallery implementations.\",\"removal\":\"replace\",\"type\":\"aosp\"},{\"id\":\"com.google.android.hotspot2.osulogin\",\"description\":\"The sole purpose of the OsuLogin App is to provision credentials from the Wi-Fi network to the device and allow them to connect to Wi-Fi Hotspot 2.0. See https://hackanons.com/2021/07/osulogin-android-everything-you-need-to-know.html for more information.\",\"removal\":\"replace\",\"type\":\"aosp\"},{\"id\":\"com.google.android.modulemetadata\",\"description\":\"Module that contains metadata about the list of modules on the device. And that’s about it.\\nI wouldn't advise you to mess with it as it could break important modules (see #37)\\nGood explanation of what android modules are : https://www.xda-developers.com/android-project-mainline-modules-explanation/\",\"removal\":\"unsafe\",\"type\":\"aosp\"},{\"id\":\"com.google.android.nearby.halfsheet\",\"description\":\"Useless frameworks to Wi-Fi connections, USB tethering, auto, usage.\\nEvery version has random code and the app is not running in the background.\",\"removal\":\"delete\",\"type\":\"aosp\"},{\"id\":\"com.google.android.networkstack\",\"description\":\"Network Stack Components\\nhttps://source.android.com/devices/architecture/modular-system/networking\\nProvides common IP services, network connectivity monitoring, and captive login portal detection.\\n\",\"removal\":\"unsafe\",\"type\":\"aosp\"},{\"id\":\"com.google.android.networkstack.overlay\",\"description\":\"WiFi will not work after remove.\",\"removal\":\"unsafe\",\"type\":\"aosp\"},{\"id\":\"com.google.android.networkstack.permissionconfig\",\"description\":\"Network Stack Permission Configuration\\nDefines a permission that enables modules to perform network-related tasks.\\nhttps://source.android.com/devices/architecture/modular-system/networking\\n\",\"removal\":\"unsafe\",\"type\":\"aosp\"},{\"id\":\"com.google.android.networkstack.tethering\",\"label\":\"Tethering\",\"description\":\"Used for USB and/or Wi-Fi tethering?\",\"removal\":\"unsafe\",\"type\":\"aosp\"},{\"id\":\"com.google.android.networkstack.tethering.overlay\",\"label\":\"com.google.android.networkstack.tethering.overlay\",\"description\":\"Needed for tethering? I found: arrays.xml\\narray name (config_tether_usb_regexs)\\nitem rndis d\\nitem usb d\",\"removal\":\"unsafe\",\"type\":\"aosp\"},{\"id\":\"com.google.android.ondevicepersonalization.services\",\"description\":\"OnDevicePersonalization.\\nAnother thing to AdServices privacy sandbox.\\nIntroduced in Android 13.\\nhttps://source.android.com/docs/core/ota/modular-system/ondevicepersonalization\",\"removal\":\"delete\",\"type\":\"aosp\"},{\"id\":\"com.google.android.overlay.managedprovisioning\",\"description\":\"In code I have seen lists of some system apps and stuff of `managedprovisioning` user.\\nSafe to remove if you removed `com.android.managedprovisioning`.\\nBut it probably doesn't affect anything.\",\"removal\":\"caution\",\"type\":\"aosp\"},{\"id\":\"com.google.android.overlay.modules.captiveportallogin.forframework\",\"description\":\"Configs default captiveportallogin. (not needed)\\nNo effects after remove.\",\"removal\":\"delete\",\"type\":\"aosp\"},{\"id\":\"com.google.android.overlay.modules.cellbroadcastservice\",\"description\":\"\",\"removal\":\"caution\",\"type\":\"aosp\"},{\"id\":\"com.google.android.overlay.modules.ext.services\",\"label\":\"com.google.android.overlay.modules.ext.services\",\"dependencies\":[\"com.google.android.ext.services\"],\"description\":\"It's overlay that depends on (com.google.android.ext.services)\",\"removal\":\"unsafe\",\"warning\":\"Removing it causes bootloop.\",\"type\":\"aosp\"},{\"id\":\"com.google.android.overlay.modules.permissioncontroller\",\"label\":\"com.google.android.overlay.modules.permissioncontroller\",\"description\":\"I only detect on this app: help_app_permissions (link below). It looks very useless, not needed.\\nIt doesnt affect com.google.android.permissioncontroller\",\"web\":[\"https://support.google.com/googleplay/answer/6270602\"],\"removal\":\"delete\",\"warning\":\"when disabling this package on a Samsung N960F running Android Q, the pop-up UI reverts. Disabling this package (as it's an overlay) will also put the pop-up UI to (like full-screen notification) to the center instead of the bottom.\",\"type\":\"aosp\"},{\"id\":\"com.google.android.overlay.modules.permissioncontroller.forframework\",\"label\":\"com.google.android.overlay.modules.permissioncontroller.forframework\",\"description\":\"config_incidentReportApproverPackage\\nIt looks very useless.\\nNot needed, it doesnt affect on (com.google.android.permissioncontroller)\",\"removal\":\"caution\",\"type\":\"aosp\"},{\"id\":\"com.google.android.overlay.permissioncontroller\",\"description\":\"Breaks Google Play System updates (GPSu), related to Project Mainline. Page on Settings will crash altogether, or ask Play Store to be updated.\\nhttps://support.google.com/product-documentation/answer/14343500\",\"dependencies\":[\"com.android.vending\"],\"removal\":\"replace\",\"type\":\"aosp\"},{\"id\":\"com.google.android.packageinstaller\",\"description\":\"Google package installer. Seems to replace com.android.packageinstaller on newer phones. It is strangely not needed on older devices (you can still install APKs without it by using the AOSP package installer) but since Android 9, it also handles permissions control and could bootloop your device if removed.\\nOn Android 8.1, disabling the app also disabled the 'Permissions' settings within all the apps. Besides that, I couldn't install an '.apk' file download from outside the Play Store.\\nSource: https://source.android.com/docs/core/architecture/modular-system/permissioncontroller.\",\"removal\":\"unsafe\",\"type\":\"aosp\"},{\"id\":\"com.google.android.packageinstaller.a_overlay\",\"description\":\"Gives ability to install, update or remove applications on the device.\\nIf you delete this package, your phone will probably bootloop.\\n\",\"removal\":\"unsafe\",\"type\":\"aosp\"},{\"id\":\"com.google.android.permissioncontroller\",\"description\":\"Permission controller\\nControls app permissions.\\nhttps://source.android.com/devices/architecture/modular-system/permissioncontroller\",\"removal\":\"unsafe\",\"type\":\"aosp\"},{\"id\":\"com.google.android.photopicker\",\"description\":\"Photo picker\\nProvides a browsable interface that presents the user with their media library, sorted by date from newest to oldest. Safe, built-in way for users to grant your app access to only selected images and videos, instead of their entire media library.\\nhttps://developer.android.com/training/data-storage/shared/photopicker\",\"removal\":\"caution\",\"type\":\"aosp\"},{\"id\":\"com.google.android.printservice.recommendation\",\"label\":\"Print Service Recommendation Service\",\"description\":\"I think this has to do with recommending a printservice app you can get from the Play store. I think printing still works with this off.\",\"removal\":\"caution\",\"type\":\"aosp\"},{\"id\":\"com.google.android.providers.media.module\",\"label\":\"Media\",\"description\":\"In Android 11+ this provides file access to apps without \\\"Manage All Files\\\" permission. In previous versions it's just an index of all audio-visual (no text) files in the user's file-system (`/sdcard/`, `/storage/emulated/0/`, etc...). This allows music-players and photo-galleries to list files quickly, without caching their own indices..\\nContent providers encapsulate data, providing centralized management of data shared between apps.\",\"web\":[\"https://developer.android.com/guide/topics/providers/content-providers.html\"],\"removal\":\"unsafe\",\"warning\":\"Breaks file browsers and other forms of file access.\",\"type\":\"aosp\"},{\"id\":\"com.google.android.safetycenter.resources\",\"label\":\"Google Safety Center Resources\",\"description\":\"Google Safe Browsing.\",\"web\":[\"https://www.android.com/safety/\"],\"removal\":\"caution\",\"warning\":\"Crashes Security and Privacy settings if removed.\",\"type\":\"aosp\"},{\"id\":\"com.google.android.sdksandbox\",\"description\":\"Introduced in Android 13 privacy sandbox beta disabled on default.\\nCauses bootloop. Maybe this component is not only for privacy... (I think it's for testing privacy sandbox using Android Studio.)\\nhttps://source.android.com/docs/core/ota/modular-system/adservices\\nCause BOOTLOOP.\",\"removal\":\"unsafe\",\"type\":\"aosp\"},{\"id\":\"com.google.android.speech.pumpkin\",\"description\":\"PumpkinService\\nHas something to speech.\",\"removal\":\"replace\",\"type\":\"aosp\"},{\"id\":\"com.google.mainline.adservices\",\"description\":\"Adservices Train Version Package. AdServices too.\\nuses ondevicepersonalization.\\nIntroduced in Android 13\\nNOTE: This package is a mandatory mainline module, which is also not documented. I don't trust it when it comes to adservices.\",\"removal\":\"delete\",\"type\":\"aosp\"},{\"id\":\"org.chromium.webview_shell\",\"description\":\"Simple Browser for WebView tester used in AOSP.\",\"removal\":\"delete\",\"type\":\"aosp\"},{\"id\":\"ca.bell.wt.android.tunesappswidget\",\"label\":\"App Widget\",\"description\":\"Developped by Bell Canada, it is a home screen widget which shows advertisements, promotions, news, sports & entertainment.\",\"web\":[\"https://play.google.com/store/apps/details?id=ca.bell.wt.android.tunesappswidget\"],\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.LogiaGroup.LogiaDeck\",\"label\":\"Mobile Services Manager\",\"description\":\"Seems to be a spyware\",\"web\":[\"https://www.reddit.com/r/lgv20/comments/6u0wnf/what_is_mobile_services_manager_did_i_catch_a/\"],\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.Rogers.MyRogersTab\",\"description\":\"Appears to be the tablet version of MyRogers (https://play.google.com/store/apps/details?id=com.fivemobile.myaccount), an app to manage your account with Canadian carrier Rogers.\",\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.aetherpal.attdh.se\",\"label\":\"Device Help\",\"description\":\"Device Help for AT&T Samsung device.\\nDeveloped by Aetherpal, a company which sells smart remote controls tools.\\nI guess this app is used for tech support.\",\"web\":[\"https://docs.samsungknox.com/CCMode/G935A_O.pdf\",\"https://en.wikipedia.org/wiki/AetherPal\"],\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.aetherpal.attdh.zte\",\"label\":\"Device Help\",\"description\":\"Device Help for AT&T ZTE devices.\\nDeveloped by Aetherpal, a company which sells smart remote controls tools.\\nI guess this app is used for tech support.\",\"web\":[\"https://en.wikipedia.org/wiki/AetherPal\"],\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.altice.android.myapps\",\"description\":\"MyApps\\nit's probably for install apps but it's useless.\",\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.americanexpress.plenti\",\"description\":\"Plenti\\nGet points and promos with your American Express card\",\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.android.partnerbrowsercustomizations.tmobile\",\"description\":\"The proprietary application of the mobile operator T-Mobile, presumably displays ads, is responsible for the operation of some of the operator's settings\",\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.android.sprint.hiddenmenuapp\",\"label\":\"HiddenMenu\",\"description\":\"Lets you access hidden features tests/settings (you need to type a special code in the dialer).\",\"web\":[\"https://bestcellular.com/dial-codes/\"],\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.android.wifi.resources.overlay.WifiVodafoneOverlay\",\"label\":\"com.android.wifi.resources.overlay.WifiVodafoneOverlay\",\"description\":\"Not sure what it does\",\"web\":[\"https://beta.pithus.org/report/d8b19f854eb85ea97fbaeafb8c11842cf9b27f169b08d3e8b2659f52db9dd408\"],\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.asurion.android.mobilerecovery.att\",\"label\":\"AT&T Protect Plus\",\"description\":\"Discontinued and replaced by AT&T ProTech (com.asurion.android.protech.att)\\nHelp and support app. Lets you call or chat with a live U.S.-based AT&T ProTech support expert.\",\"web\":[\"https://en.wikipedia.org/wiki/Asurion\"],\"removal\":\"delete\",\"warning\":\"This app is developed by Asurion, a US company whose business is to sell insurances. All US carriers use Asurion for the phone insurances.\",\"type\":\"carrier\"},{\"id\":\"com.asurion.android.mobilerecovery.sprint\",\"label\":\"Sprint Protect\",\"description\":\"Let you find a phone, secure from viruses, back up data, and more.\",\"web\":[\"https://en.wikipedia.org/wiki/Asurion\"],\"removal\":\"delete\",\"warning\":\"This app is developed by Asurion, a US company whose business is to sell insurances. All US carriers use Asurion for the phone insurances.\",\"type\":\"carrier\"},{\"id\":\"com.asurion.android.mobilerecovery.sprint.vpl\",\"label\":\"Sprint Protect\",\"description\":\"Let you find a phone, secure from viruses, back up data, and more.\",\"web\":[\"https://en.wikipedia.org/wiki/Asurion\"],\"removal\":\"delete\",\"warning\":\"This app is developed by Asurion, a US company whose business is to sell insurances. All US carriers use Asurion for the phone insurances.\",\"type\":\"carrier\"},{\"id\":\"com.asurion.android.protech.att\",\"label\":\"AT&T ProTech\",\"description\":\"Help and support app. Lets you call or chat with a live U.S.-based AT&T ProTech support \\\"expert\\\".\",\"web\":[\"https://en.wikipedia.org/wiki/Asurion\"],\"removal\":\"delete\",\"warning\":\"This app is developed by Asurion, a US company whose business is to sell insurances. All US carriers use Asurion for the phone insurances.\",\"type\":\"carrier\"},{\"id\":\"com.asurion.android.verizon.vms\",\"label\":\"Digital Secure\",\"description\":\"Verizon's one-stop suite of privacy and security tools that is supposed to protect your devices from online threats, connect to public Wi-Fi with a secure VPN, take control with always-on dark web monitoring, and get guidance on online security from \\\"security experts\\\".\",\"web\":[\"https://play.google.com/store/apps/details?id=com.asurion.android.verizon.vms\",\"https://en.wikipedia.org/wiki/Asurion\"],\"removal\":\"delete\",\"warning\":\"This app is developed by Asurion, a US company whose business is to sell insurances. All US carriers use Asurion for the phone insurances.\",\"type\":\"carrier\"},{\"id\":\"com.asurion.home.sprint\",\"label\":\"Sprint Complete\",\"description\":\"Lets you call or chat with live tech experts! Maybe you will find the love of your life!\",\"web\":[\"https://en.wikipedia.org/wiki/Asurion\"],\"removal\":\"delete\",\"warning\":\"This app is developed by Asurion, a US company whose business is to sell insurances. All US carriers use Asurion for the phone insurances.\",\"type\":\"carrier\"},{\"id\":\"com.asurion.home.sprint.vpl\",\"label\":\"Tech Expert\",\"description\":\"Replaced by \\\"Sprint Complete\\\".\",\"web\":[\"https://en.wikipedia.org/wiki/Asurion\"],\"removal\":\"delete\",\"warning\":\"This app is developed by Asurion, a US company whose business is to sell insurances. All US carriers use Asurion for the phone insurances.\",\"type\":\"carrier\"},{\"id\":\"com.att.android.attsmartwifi\",\"label\":\"AT&T Smart Wi-Fi\",\"description\":\"Finds and auto-connects to available hotspots to minimize cellular data consumption.\\nAuto-connects is not a good idea. You are ok if you go on HTTPS websites. Use a VPN if you want to hide the domain names you visit, avoid usage restriction (no P2P, blacklisted websites...) and encrypt HTTP traffic.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.att.android.attsmartwifi\",\"https://www.europol.europa.eu/activities-services/public-awareness-and-prevention-guides/risks-of-using-public-wi-fi\",\"https://www.eff.org/deeplinks/2020/01/why-public-wi-fi-lot-safer-you-think\",\"https://thatoneprivacysite.net/choosing-the-best-vpn-for-you/\"],\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.att.callprotect\",\"label\":\"AT&T Call Protect\",\"description\":\"Spam call blocking app provided by Hiya.\",\"web\":[\"https://itmunch.com/robocall-caught-sending-customers-confidential-data-without-consent/\"],\"removal\":\"delete\",\"warning\":\"Never trust an app that automatically blocks spam calls.\",\"type\":\"carrier\"},{\"id\":\"com.att.csoiam.mobilekey\",\"label\":\"AT&T Sign in Helper\",\"description\":\"Allows AT&T applications to securely authenticate on Android devices.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.att.csoiam.mobilekey\"],\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.att.deviceunlock\",\"description\":\"Device Unlock\\nUseless app from AT&T. it's only for unlock device.\",\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.att.dh\",\"label\":\"Device Help\",\"description\":\"Troubleshooting app from AT&T.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.att.dh\"],\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.att.dtv.shaderemote\",\"label\":\"DIRECTV Remote App\",\"description\":\"Lets you control DIRECTV HD receivers in your home that are connected to Internet, from your phone. DIRECTV is a subsidiary of AT&T.\",\"web\":[\"https://en.wikipedia.org/wiki/DirecTV#Consumer_protection_lawsuits_and_violations\"],\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.att.iqi\",\"label\":\"Device Health\",\"description\":\"(AKA Carrier IQ) Gathers, stores and forwards diagnostic measurements on its behalf.\\nGreat! A rootkit.\",\"web\":[\"https://docs.samsungknox.com/CCMode/G935A_O.pdf\",\"https://en.wikipedia.org/wiki/Carrier_IQ#Rootkit_discovery_and_media_attention\"],\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.att.mobile.android.vvm\",\"label\":\"AT&T Visual Voicemail\",\"description\":\"Lets you manage your voicemail directly from the app without the need to dial into your mailbox.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.att.mobile.android.vvm\"],\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.att.mobilesecurity\",\"label\":\"AT&T ActiveArmor℠\",\"description\":\"AT&T android antivirus.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.att.mobilesecurity\"],\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.att.mobiletransfer\",\"label\":\"AT&T Mobile Transfer\",\"description\":\"Lets you transfer user data from an older AT&T phone to a new one.\",\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.att.myWireless\",\"label\":\"myAT&T\",\"description\":\"Lets you manage your AT&T account.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.att.myWireless\"],\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.att.personalcloud\",\"label\":\"AT&T Personal Cloud\",\"description\":\"It has paid extra features and data are obviously not E2EE (i.e AT&T can access them)\\nPrivacy nightmare and was poorly coded.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.att.personalcloud\",\"https://beta.pithus.org/report/bc54b5e2446ace90d9f992278d0ec320befe4983a76cb4fdcf47e565366e67b6\"],\"removal\":\"replace\",\"suggestions\":\"cloud_services\",\"type\":\"carrier\"},{\"id\":\"com.att.tv\",\"label\":\"DIRECTV\",\"description\":\"Lets you Stream TV live and on demand from your phone.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.att.tv\"],\"removal\":\"replace\",\"suggestions\":\"streaming_apps\",\"type\":\"carrier\"},{\"id\":\"com.att.tv.watchtv\",\"label\":\"AT&T WatchTV\",\"description\":\"Lets you stream TV live and VOD form your phone.\\nNo it's not the same thing than AT&T TV. Yes, it's a mess.\",\"web\":[\"https://www.cordcuttersnews.com/att-tv-vs-att-tv-now-whats-the-difference/\"],\"removal\":\"replace\",\"suggestions\":\"streaming_apps\",\"type\":\"carrier\"},{\"id\":\"com.aura.jet.att\",\"description\":\"AT&T Hub\\nApp from AT&T. Installs apps on oobe and its maded by advertising company 'ironSource'.\",\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.aura.oobe.att\",\"description\":\"AppCloud\\nApp from AT&T. Installs apps on oobe and its maded by advertising company 'ironSource'.\",\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.aura.oobe.motorola\",\"description\":\"MotoApps\\nIt's something to install apps, but it's an advertising company.\",\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.aura.oobe.samsung\",\"label\":\"AppCloud\",\"description\":\"It offers the \\\"Aura Out-Of-the-Box Experience\\\" (OOBE)\\nIt is some kind of post-install recommended apps setup from the carrier. Asks for your age and gender and then recommends you to install popular apps.\\nHas way too many permissions.\",\"web\":[\"https://en.wikipedia.org/wiki/IronSource\",\"https://aura.ironsrc.com/tools/drive-app-downloads/\",\"https://arxiv.org/pdf/2010.10088.pdf\",\"https://github.com/0x192/universal-android-debloater/issues/278\"],\"removal\":\"delete\",\"warning\":\"This app is developed by IronSource, an Israeli advertising company.\",\"type\":\"carrier\"},{\"id\":\"com.aura.oobe.samsung.gl\",\"label\":\"AppCloud\",\"description\":\"It offers the \\\"Aura Out-Of-the-Box Experience\\\" (OOBE)\\nIt is some kind of post-install recommended apps setup from the carrier. Asks for your age and gender and then recommends you to install popular apps.\\nHas way too many permissions.\",\"web\":[\"https://en.wikipedia.org/wiki/IronSource\",\"https://aura.ironsrc.com/tools/drive-app-downloads/\",\"https://arxiv.org/pdf/2010.10088.pdf\",\"https://github.com/0x192/universal-android-debloater/issues/278\"],\"removal\":\"delete\",\"warning\":\"This app is developed by IronSource, an Israeli advertising company.\",\"type\":\"carrier\"},{\"id\":\"com.aura.oobe.vodafone\",\"description\":\"Vodafone AppBox\\nIt is some kind of post-install recommended apps setup from the carrier.\\nAsks for your age and gender and then recommends you to install popular apps.\\nDeveloped by IronSource, an Israeli advertising company.\",\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.bc360.android.service\",\"description\":\"Verizon Adaptive Sound\\nProvides Voice Enhance, but according to the carrier.\\nDoes the same thing as the 'com.bc360.control' app.\",\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.bc360.control\",\"description\":\"Verizon Adaptive Sound\\nProvides Voice Enhance, but according to the carrier.\",\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.claroColombia.contenedor\",\"description\":\"Claro\\nIt's something to install apps, but it's an advertising company.\",\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.cricketwireless.minus\",\"description\":\"Cricket partner tab? better remove it. It probably have news or partner customization to chrome.\",\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.customermobile.preload.vzw\",\"label\":\"Verizon Store Demo Mode\",\"description\":\"Requires a lot of permissions and downloads a remote configuration file from an AWS-hosted domain over plain-text HTTP.\\nThis leaves the overall device and configuration vulnerable.\",\"web\":[\"https://thehackernews.com/2024/08/google-pixel-devices-shipped-with.html\"],\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.directv.promo.shade\",\"description\":\"DIRECTV Remote\\nOfficial app from DIRECTV (subsidiary of AT&T). With the DIRECTV Remote for AT&T Samsung devices, control of your favorite DIRECTV shows is just a swipe away. Swipe down from the status bar at the top of your screen to automatically connect and control your DIRECTV receivers, it's that simple.\",\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.dti.amx\",\"description\":\"it's used to choose app install? A lot trackers, permissions.\\nUseless.\",\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.dti.att\",\"label\":\"Mobile Services Manager\",\"description\":\"Formerly known as AT&T App Select.\\nI guess it lets you choose AT&T apps to install.\\nIt has a LOT of permissions.\",\"web\":[\"https://knowledge.protektoid.com/apps/com.dti.att/7a36d4f5f00bae044566221400719c75ea2f4f33bc2578a7f8210f36d718a8d6\"],\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.dti.bouyguestelecom\",\"description\":\"Bouygues AppCloud\\nit's probably for install apps but it's useless and have ads and a lot permissions.\",\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.dti.cricket\",\"description\":\"it's app for installing recommended apps? it's only used on first-boot setup and it's useless.\",\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.dti.motorola\",\"description\":\"Mobile Services Manager\\nit's something for install apps but it's useless and a lot permissions.\",\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.dti.samsung\",\"description\":\"Mobile Services Manager\\nDigital Turbine app, pre-install some apps/games to your phone and its made by advertising company.\",\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.dti.tim\",\"description\":\"Mobile Service Manager\\nIt's a system app that can't be opened but keeps running in the background. It can install/uninstall apps without notifying you, access internet, run at the boot of the system, kill background processes, ads and other permissions.\\nIt's only bloatware, OTA updates work the same without it. Uninstalling didn't give any negative side-effects.\",\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.dti.tracfone\",\"label\":\"Mobile Services\",\"description\":\"Installs sponsored apps automatically on Tracfone and affiliated carriers (Straight Talk, Total Wireless, etc)\",\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.felicanetworks.mfc\",\"description\":\"Chinese felicanetworks\",\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.felicanetworks.mfm\",\"description\":\"Setup Chinese felicanetworks\",\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.felicanetworks.mfm.main\",\"description\":\"Chinese felicanetworks\",\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.felicanetworks.mfs\",\"description\":\"Chinese felicanetworks\",\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.felicanetworks.mfw.a.boot\",\"description\":\"Chinese felicanetworks\",\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.google.omadm.trigger\",\"description\":\"OemDmTrigger\\nOMA Device Managment Verizon.\",\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.gsma.rcs\",\"description\":\"RCS\\nHidden RCS Messaging? or only Frameworks?\\nFeature code:184501\\nCarrier name: GSM Association.\",\"removal\":\"caution\",\"type\":\"carrier\"},{\"id\":\"com.hyperlync.Sprint.Backup\",\"label\":\"Sprint Backup\",\"description\":\"Lets you backup your phone’s content to your Sprint Backup account.\\nThis app was developed by Hyperlync Technologies an Israel-based company which provides cyber-security solutions. It is now owned by Edition Ltd, a big Singapore based company.\",\"web\":[\"https://www.reuters.com/companies/EDITol.SI\"],\"removal\":\"replace\",\"suggestions\":\"backup_apps\",\"type\":\"carrier\"},{\"id\":\"com.hyperlync.Sprint.CloudBinder\",\"label\":\"Sprint Cloud Binder\",\"description\":\"Hub for all you cloud accounts.\\nThis app was developed by Hyperlync Technologies an Israel-based company which provide cyber-security solutions.\\nIt is now owned by Edition Ltd, a big Singapore based company.\",\"web\":[\"https://www.reuters.com/companies/EDITol.SI\"],\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.inmobi.installer\",\"description\":\"it's installer advertising company app.\",\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.ironsource.appcloud.oobe.hutchison\",\"description\":\"AppCloud (discontinued) from ironSource, an advertising company.\\nWorth reading:\\nhttps://en.wikipedia.org/wiki/IronSource\",\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.jrd.verizonuriintentservice\",\"description\":\"\",\"removal\":\"caution\",\"type\":\"carrier\"},{\"id\":\"com.kmsjp\",\"description\":\"Kaspersky\\nAnti-virus pre-installed on some Huawei phone's in Japanese.\",\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.kuackmedia.orange\",\"description\":\"Altice Music\\nIt's a music application that allows you to stream music, but it comes pre-installed.\\nhttps://play.google.com/store/apps/details?id=com.kuackmedia.orange\",\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.locationlabs.cni.att\",\"label\":\"AT&T Smart Limits℠\",\"description\":\"A parental Control app.\",\"web\":[\"https://m.att.com/shopmobile/wireless/features/smart-limits.html\"],\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.locationlabs.finder.sprint\",\"label\":\"Sprint Family Locator\",\"description\":\"Lets you locate any phone registered under the Sprint family plan.\\nLocation labs is owned by AGV which is owned by Avast.\\nYou shouldn't trust Avast.\",\"web\":[\"https://www.vice.com/en_us/article/qjdkq7/avast-antivirus-sells-user-browsing-data-investigation\",\"https://www.pcmag.com/news/the-cost-of-avasts-free-antivirus-companies-can-spy-on-your-clicks\"],\"removal\":\"replace\",\"suggestions\":\"locators\",\"type\":\"carrier\"},{\"id\":\"com.locationlabs.finder.sprint.vpl\",\"label\":\"Sprint Family Locator\",\"description\":\"Lets you locate any phone registered under the Sprint family plan\\nLocation labs is owned by AGV which is owned by Avast.\\nYou shouldn't trust Avast.\",\"web\":[\"https://www.vice.com/en_us/article/qjdkq7/avast-antivirus-sells-user-browsing-data-investigation\",\"https://www.pcmag.com/news/the-cost-of-avasts-free-antivirus-companies-can-spy-on-your-clicks\"],\"removal\":\"replace\",\"suggestions\":\"locators\",\"type\":\"carrier\"},{\"id\":\"com.matchboxmobile.wisp\",\"label\":\"AT&T Hot Spots\",\"description\":\"Runs in background. Automatically connects you to a free AT&T wifi hotspot at one of their participating partner locations, such as Starbucks.\",\"web\":[\"https://docs.samsungknox.com/CCMode/G935A_O.pdf\"],\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.mobitv.client.sprinttvng\",\"label\":\"Sprint TV & Movies\",\"description\":\"Provided by MobiTV. Lets you watch live TV and VOD.\",\"web\":[\"https://en.wikipedia.org/wiki/MobiTV\"],\"removal\":\"replace\",\"suggestions\":\"streaming_apps\",\"type\":\"carrier\"},{\"id\":\"com.mobitv.client.tmobiletvhd\",\"label\":\"T-Mobile TV with Mobile HD\",\"description\":\"Discontinued and replaced by nl.tmobiletv.vinson, provided by MobiTV.\",\"web\":[\"https://en.wikipedia.org/wiki/MobiTV\",\"https://play.google.com/store/apps/details?id=nl.tmobiletv.vinson\"],\"removal\":\"replace\",\"suggestions\":\"streaming_apps\",\"type\":\"carrier\"},{\"id\":\"com.mobolize.sprint.securewifi\",\"label\":\"Secure WiFi\",\"description\":\"Sprint VPN app provided by Mobolize. You need to pay for using it.\\nYou'd better use a reliable third-party VPN if you really need to use one.\\nThis one runs in background all time and every time it sees a \\\"unsecured network\\\" it will popup to encourage you to pay for this VPN.\",\"removal\":\"replace\",\"suggestions\":\"vpn_services\",\"type\":\"carrier\"},{\"id\":\"com.motorola.att.phone.extensions\",\"label\":\"ATT Phone Extension\",\"description\":\"Provide access to AT&T extensions in you dialer.\",\"web\":[\"https://asecare.att.com/tutorials/adding-and-deleting-an-extension-on-your-officehand-mobile-app-2990/?product=AT&T%20Office@Hand\"],\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.motorola.attvowifi\",\"label\":\"Wi-Fi Calling\",\"description\":\"AT&T Wifi-calling app.\",\"web\":[\"https://www.att.com/shop/wireless/features/wifi-calling.html\"],\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.motorola.carrierconfig\",\"label\":\"Carrier Services\",\"description\":\"Related to various communication related actions.\",\"web\":[\"https://source.android.com/docs/core/connect/carrier\"],\"removal\":\"caution\",\"warning\":\"Disabling this app may cause network-related issues\",\"type\":\"carrier\"},{\"id\":\"com.motorola.ltebroadcastservices_vzw\",\"label\":\"com.motorola.ltebroadcastservices_vzw\",\"description\":\"LTE Broadcast services from Verizon. Allows your phone to receive broadcast message from Verizon?\",\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.motorola.mot5gmod\",\"label\":\"5G Moto Mod\",\"description\":\"Internet sharing using USB tethering and WiFi hotspot.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.motorola.mot5gmod\"],\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.motorola.omadm.sprint\",\"label\":\"SprintDM\",\"description\":\"Configuration of the device (including first time use), enabling and disabling features provided by carriers.\\nI believe it's only useful if you want to use a Sprint service with a non branded phone (not sure at all)\\nDisplays annoying notifications if you unlocked your bootloader.\",\"web\":[\"https://www.androidpolice.com/2015/03/10/android-5-1-includes-new-carrier-provisioning-api-allows-carriers-easier-methods-of-setting-up-services-on-devices-they-dont-control/\"],\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.motorola.omadm.usc\",\"description\":\"OMA Device Management for Verizon \\nHandles configuration of the device (including first time use), enabling and disabling features provided by carriers.\\nhttps://en.wikipedia.org/wiki/OMA_Device_Management\\nI believe it's only useful if you want to use a Verizon service with a non branded phone (not sure at all)\\nhttps://www.androidpolice.com/2015/03/10/android-5-1-includes-new-carrier-provisioning-api-allows-carriers-easier-methods-of-setting-up-services-on-devices-they-dont-control/\\nDisplays annoying notifications if you unlocked your bootloader\",\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.motorola.omadm.vzw\",\"label\":\"VzwDM\",\"description\":\"OMA Device Management for Verizon.\\nHandles configuration of the device (including first time use), enabling and disabling features provided by carriers.\\nI believe it's only useful if you want to use a Verizon service with a non branded phone (not sure at all)\\nDisplays annoying notifications if you unlocked your bootloader.\",\"web\":[\"https://en.wikipedia.org/wiki/OMA_Device_Management\",\"https://www.androidpolice.com/2015/03/10/android-5-1-includes-new-carrier-provisioning-api-allows-carriers-easier-methods-of-setting-up-services-on-devices-they-dont-control/\"],\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.motorola.service.vzw.entitlement\",\"label\":\"entitlement\",\"description\":\"\",\"web\":[\"https://android.stackexchange.com/questions/226580/how-is-verizon-suddenly-tracking-my-hot-spot-usage-on-android-and-how-do-i-disab\"],\"removal\":\"caution\",\"warning\":\"Deleting this package whill disable Hotspot functionality if you're a Verizon client. What you can do is preventing the phone from notifying the carrier about when you use hotspot.\",\"type\":\"carrier\"},{\"id\":\"com.motorola.sprintwfc\",\"label\":\"print Wifi Calling\",\"description\":\"Sprint Wifi Calling\\nProvides wifi calling to Sprint customers.\",\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.motorola.visualvoicemail\",\"label\":\"Verizon Visual Voicemail\",\"description\":\"On non-Verizon phones it has a generic \\\"Voicemail\\\" name and icon, and doesn't seem to active.\",\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.motorola.vzw.cloudsetup\",\"label\":\"Cloud setup\",\"description\":\"The exact functionality is unknown.\",\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.motorola.vzw.loader\",\"label\":\"com.motorola.vzw.loader\",\"description\":\"Exact functionality is unknown. Doesn't seem to break anything once removed.\",\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.motorola.vzw.mot5gmod\",\"label\":\"5G Moto Mod\",\"description\":\"Internet sharing using USB tethering and WiFi hotspot.\",\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.motorola.vzw.pco.extensions.pcoreceiver\",\"label\":\"PcoReceiver\",\"description\":\"VZW Carrier sim(Verizon). It's only for notifications.\\nYou can remove that if you don't use Verizon wireless or anything like that.\",\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.motorola.vzw.phone.extensions\",\"label\":\"PhoneExtns\",\"description\":\"Free HD wallpaper from verizon\",\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.motorola.vzw.provider\",\"label\":\"VzwUnifiedSettingsApp\",\"description\":\"Exact functionality is unknown. Label might be incorrect. Doesn't seem to break anything once removed.\",\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.motricity.verizon.ssodownloadable\",\"label\":\"Verizon Login\",\"description\":\"Originally by Motricity, now Voltari.\\nVoltari provides relevance-driven mobile advertising, mobile marketing, mobile merchandising, and predictive analytics solutions.\\nNeeded for \\\"My Verizon\\\".\",\"web\":[\"https://en.wikipedia.org/wiki/Voltari\",\"https://www.lightreading.com/motricity-holds-on-to-verizon-account/d/d-id/678478\"],\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.naviexpert.NaviExpert\",\"description\":\"Navigation T-Mobile\\nhttps://play.google.com/store/apps/details?id=com.naviexpert.NaviExpert\",\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.nextbit.app\",\"description\":\"docomo LIVE UX backup\\nit's on some japanese phones\",\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.nim.rogers\",\"description\":\"Texture, a digital magazine service created by Rogers Media. Discontinued in 2019.\",\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.nttdocomo.android.applicationmanager\",\"description\":\"Docomo Application Manager\",\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.nttdocomo.android.dhome\",\"description\":\"Docomo Launcher\",\"removal\":\"replace\",\"type\":\"carrier\"},{\"id\":\"com.nttdocomo.android.iconcier_contents\",\"description\":\"Diagnostics things only in this japanese app\",\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.nttdocomo.android.initialization\",\"description\":\"Docomo Initialization app\",\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.nttdocomo.android.rwpushcontroller\",\"description\":\"rwpushcontroller\\nAnother FeliCa Networks app, with japanese language\\nUseless frameworks\",\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.nttdocomo.android.store\",\"description\":\"Docomo App Market\",\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.oem.euiccpartnerapp\",\"description\":\"EuiccPartnerApp\\nNeeded for eSIM (eUICC)?\\nI think it's useless.\",\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.orange.aura.oobe\",\"label\":\"Orange Manual Selector\",\"description\":\"Makes unnecessary notifications\",\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.orange.mail.fr\",\"label\":\"Mail Orange\",\"description\":\"Managing your emails from the Mail Orange application. All your personal data is hosted in France and governed by French law.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.orange.mail.fr\"],\"removal\":\"replace\",\"suggestions\":\"email_clients\",\"type\":\"carrier\"},{\"id\":\"com.orange.miorange\",\"label\":\"Mi Orange\",\"description\":\"Lets you access to your Orange account and services\",\"web\":[\"https://play.google.com/store/apps/details?id=com.orange.miorange\"],\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.orange.mylivebox.fr\",\"label\":\"Ma Livebox\",\"description\":\"Lets you manage your Livebox from your phone.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.orange.mylivebox.fr\"],\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.orange.mysosh\",\"label\":\"MySosh France\",\"description\":\"Lets you access to your Sosh account\",\"web\":[\"https://play.google.com/store/apps/details?id=com.orange.mysosh\"],\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.orange.orangeetmoi\",\"label\":\"Orange et moi France\",\"description\":\"Orange customer space.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.orange.orangeetmoi\"],\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.orange.owtv\",\"label\":\"TV d'Orange\",\"description\":\"Lets you watch TV/VOD on your phone.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.orange.owtv\"],\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.orange.tdd\",\"label\":\"Transfert des données\",\"description\":\"Lets you transfer wirelessly: contacts, SMS, call log, calendar, photos, videos, audio files, etc., all from your old Android.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.orange.tdd\"],\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.orange.update\",\"label\":\"App Center\",\"description\":\"Handles Orange apps updates.\",\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.orange.update.OrangeUpdateApplication\",\"label\":\"com.orange.update.OrangeUpdateApplication\",\"description\":\"Obviously related to update.\",\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.orange.vvm\",\"label\":\"Messagerie vocale visuelle\",\"description\":\"Lets you manage your voicemail with an app.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.orange.vvm\"],\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.orange.wifiorange\",\"label\":\"Mon Réseau\",\"description\":\"Lets you measure your speed connection and find better Orange wifi hotspots.\\nInforms you also about near network incidents.\",\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.ptc.osp.gnc\",\"description\":\"Playing the Waiting Game by T-Mobile.\\nThis app is maded for listening to music.\",\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.samsung.attvvm\",\"label\":\"Samsung AT&T Visual Voicemail\",\"description\":\"A simple GUI for voicemail.\",\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.samsung.huxextension\",\"description\":\"Hux Extension\\nVerizon activation, registration\",\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.samsung.slsi.telephony.oem.oemrilhookservice\",\"description\":\"Part of the Samsung cellular modem infrastructure used by the OS to provide cellular support.\",\"removal\":\"caution\",\"type\":\"carrier\"},{\"id\":\"com.samsung.slsi.telephony.oemril\",\"description\":\"Part of the Samsung cellular modem infrastructure used by the OS to provide cellular support.\",\"removal\":\"caution\",\"type\":\"carrier\"},{\"id\":\"com.samsung.sprint.chameleon\",\"description\":\"Chameleon service which is a service designed to store sprint-specific properties (customizes some apps).\",\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.sec.android.app.ewidgetatt\",\"label\":\"Entertainment Widget\",\"description\":\"AT&T Widget for One UI.\",\"web\":[\"https://docs.samsungknox.com/CCMode/F707U_Q.pdf\"],\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.sec.android.app.tfstatus\",\"description\":\"Tracfone app, function unknown\",\"removal\":\"caution\",\"type\":\"carrier\"},{\"id\":\"com.sec.omadm\",\"label\":\"OMADM\",\"description\":\"Open Mobile Alliance Device Management. A protocol for management of mobile devices.\",\"web\":[\"https://en.wikipedia.org/wiki/OMA_Device_Management\"],\"removal\":\"caution\",\"type\":\"carrier\"},{\"id\":\"com.sec.omadmspr.syncmlphoneif\",\"label\":\"Sprint OMADM Phone Interface\",\"description\":\"OMADM = Open Mobile Alliance Device Management. A protocol for management of mobile devices.\",\"web\":[\"https://docs.samsungknox.com/CCMode/G950U1_P.pdf\",\"https://en.wikipedia.org/wiki/OMA_Device_Management\"],\"removal\":\"caution\",\"type\":\"carrier\"},{\"id\":\"com.sec.sprint.wfcstub\",\"label\":\"com.sec.sprint.wfcstub\",\"description\":\"Seems to be related to Wifi-Calling on Samsung phone.\",\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.securityandprivacy.android.verizon.vms\",\"label\":\"Digital Secure\",\"description\":\"I don't know why this apps is released twice on the Play store under 2 different package name.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.securityandprivacy.android.verizon.vms\"],\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.sfr.android.moncompte\",\"label\":\"SFR & Moi\",\"description\":\"Lets you manage your SFR account.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.sfr.android.moncompte\"],\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.sfr.android.sfrcloud\",\"label\":\"SFR Cloud\",\"description\":\"Cloud provided by SFR\",\"web\":[\"https://play.google.com/store/apps/details?id=com.sfr.android.sfrcloud\"],\"removal\":\"replace\",\"suggestions\":\"cloud_services\",\"type\":\"carrier\"},{\"id\":\"com.sfr.android.sfrjeux\",\"description\":\"My Games\\nit's not useful app for games and better uninstall it\",\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.sfr.android.sfrmail\",\"label\":\"SFR Mail\",\"description\":\"SFR Mail\",\"web\":[\"https://play.google.com/store/apps/details?id=com.sfr.android.sfrmail\"],\"removal\":\"replace\",\"suggestions\":\"email_clients\",\"type\":\"carrier\"},{\"id\":\"com.sfr.android.sfrplay\",\"label\":\"SFR Play\",\"description\":\"VOD streaming from SFR.\",\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.sfr.android.vvm\",\"label\":\"SFR Répondeur +\",\"description\":\"Lets you use your voice mail and manage your inbox without dialing into your voicemail.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.sfr.android.vvm\"],\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.shannon.imsservice\",\"description\":\"Verizon IMS service.\",\"removal\":\"replace\",\"type\":\"carrier\"},{\"id\":\"com.shannon.rcsservice\",\"description\":\"Verizon RCS service.\",\"removal\":\"replace\",\"type\":\"carrier\"},{\"id\":\"com.sprint.android.musicplus2033\",\"label\":\"Sprint Music Plus\",\"description\":\"Sprint’s official Music Store and player.\",\"removal\":\"replace\",\"suggestions\":\"music_apps\",\"type\":\"carrier\"},{\"id\":\"com.sprint.android.musicplus2033.vpl\",\"label\":\"Sprint Music Plus\",\"description\":\"Sprint’s official Music Store and player.\",\"removal\":\"replace\",\"suggestions\":\"music_apps\",\"type\":\"carrier\"},{\"id\":\"com.sprint.care\",\"label\":\"My Sprint\",\"description\":\"Lets you manage your Sprint Account and pay your bill.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.sprint.care\"],\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.sprint.ce.updater\",\"label\":\"Mobile Installer (ソフトバンク)\",\"description\":\"Used by Sprint to (force) install/update Sprint apps.\",\"web\":[\"https://community.sprint.com/t5/Samsung/How-to-stop-quot-Mobile-Installer-quot-from-pushing-apps-to/td-p/1036387\"],\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.sprint.ecid\",\"label\":\"Caller ID\",\"description\":\"Enables you to hide name and phone number when you make phone calls.\",\"web\":[\"https://www.sprint.com/en/support/solutions/services/restrict-your-caller-id-information.html\"],\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.sprint.fng\",\"label\":\"Sprint Spot\",\"description\":\"Provides Sprint postpaid customers a way to discover and access apps, services, games, TV & video, music, and more.\",\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.sprint.international.message\",\"label\":\"Sprint Worldwide\",\"description\":\"A help page for international travelers.\",\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.sprint.ms.cdm\",\"label\":\"Carrier Device Manager\",\"description\":\"Mobile Device Management (MDM) allows company’s IT department to reach inside your phone in the background, allowing them to ensure your device is secure, know where it is, and remotely erase your data if the phone is stolen.\",\"web\":[\"https://onezero.medium.com/dont-put-your-work-email-on-your-personal-phone-ef7fef956c2f\",\"https://blog.cdemi.io/never-accept-an-mdm-policy-on-your-personal-phone/\"],\"removal\":\"delete\",\"warning\":\"NEVER install a MDM tool on your personal phone.\",\"type\":\"carrier\"},{\"id\":\"com.sprint.ms.cnap\",\"label\":\"Caller ID\",\"description\":\"CNAP = Caller Name Presentation\\nLets you change the name that is displayed on caller ID when making a call.\\nStrange is it the same thing than \\\"com.sprint.ecid\\\" ?\",\"web\":[\"https://en.wikipedia.org/wiki/Calling_Name_Presentation\"],\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.sprint.ms.smf.services\",\"label\":\"Carrier Hub\",\"description\":\"Enables Sprint features (including Wifi calling) and products for devices operating on the Sprint network.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.sprint.ms.smf.services\"],\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.sprint.psdg.sw\",\"label\":\"Carrier Setup Wizard\",\"description\":\"The first time you turn your device on, a Welcome screen is displayed. It guides you through the basics of setting up your device.\\nHere it handles the setup of Sprint features/services.\",\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.sprint.safefound\",\"label\":\"Safe & Found\",\"description\":\"Mobile safety and security application that helps protect and locate your \\\"loved ones\\\".\\nYou have the ability to track and manage smartphones, tablets and Tracker all in one app.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.sprint.safefound\",\"https://www.sprint.com/en/support/solutions/services/safe-and-found.html\"],\"removal\":\"delete\",\"suggestions\":\"locators\",\"type\":\"carrier\"},{\"id\":\"com.sprint.safefound.vpl\",\"label\":\"Safe & Found\",\"description\":\"Mobile safety and security application that helps protect and locate your \\\"loved ones\\\".\\nYou have the ability to track and manage smartphones, tablets and Tracker all in one app.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.sprint.safefound\",\"https://www.sprint.com/en/support/solutions/services/safe-and-found.html\"],\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.sprint.topup\",\"label\":\"Sprint World Top-Up\",\"description\":\"Doesn't exist anymore?\",\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.sprint.w.installer\",\"label\":\"Mobile ID\",\"description\":\"Formerly, Sprint ID. \\nProvides mobile ID Packs featuring apps, ringers, wallpapers, widgets and more.\\nCan (and do) force install apps you disabled.\",\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.sprint.w.v8\",\"label\":\"Featured Apps\",\"description\":\"Old app Discover App (discontinued / new package name)\\nLets you discover Sprint apps?\",\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.sprint.zone\",\"label\":\"Sprint Zone\",\"description\":\"Helps the user find new apps, in addition to some carrier-specific functionality.\",\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.synchronoss.dcs.att.r2g\",\"label\":\"AT&T Ready2Go\",\"description\":\"Discontinued. Its purpose was to help you migrating your data to your new Android device.\",\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.tcl.vzwintents\",\"description\":\"\",\"removal\":\"caution\",\"type\":\"carrier\"},{\"id\":\"com.tct.vzwwifioffload\",\"description\":\"\",\"removal\":\"caution\",\"type\":\"carrier\"},{\"id\":\"com.telcel.contenedor\",\"description\":\"Telcel app, Advertising company to get promotions.\\nhttps://play.google.com/store/apps/details?id=com.telcel.contenedor\",\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.telecomsys.directedsms.android.SCG\",\"label\":\"Verizon Location Agent\",\"description\":\"Location tracking (does not impact GPS function if deleted, don't worry).\",\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.telus.checkup\",\"description\":\"Checkup app (from Mobile Klinik; a Canadian store for buying, selling, and repairing smartphones)\\nMainly used to run device-health diagnostics, estimate device value post-diagnostics (for re-selling at a Mobile Klinik location), and finding nearby Mobile Klinik locations to book appointments for device repair. Also contains ads and promotions for new devices and accessories.\\nGenerally regarded as bloatware because diagnostics are generic at best, and is eager to request many unnecessary and potentially invasive device permissions.\\nSafe to remove if you don't use it, and can be re-downloaded from the Google Play Store at any time.\",\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.telus.myaccount\",\"label\":\"My TELUS\",\"description\":\"It's used for managing your telus account.\\nSafe to remove if you don't use it\",\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.tmobile.pr.adapt\",\"label\":\"T-Mobile\",\"description\":\"A diagnostic tool for T-Mobile. This app can see all your installed apps, that you have allowed unknown sources on, that your rooted, and will deny your warranty saying your rooted. It constantly runs in the background.\",\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.tmobile.pr.mytmobile\",\"label\":\"T-Mobile\",\"description\":\"T-mobile app\",\"web\":[\"https://play.google.com/store/apps/details?id=com.tmobile.pr.mytmobile\"],\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.tmobile.services.nameid\",\"label\":\"T-Mobile Scam Shield\",\"description\":\"Name ID T-Mobile (powered by Hiya or cequint if on Samsung devices).\",\"web\":[\"https://play.google.com/store/apps/details?id=com.tmobile.services.nameid\",\"https://techcrunch.com/2019/08/09/many-robocall-blocking-apps-send-your-private-data-without-permission/\"],\"removal\":\"delete\",\"warning\":\"Never trust a company which promotes call ID/spam blocking features.\",\"type\":\"carrier\"},{\"id\":\"com.tmobile.simlock\",\"label\":\"Device Unlock\",\"description\":\"Allows you to request and apply a mobile device unlock directly from the device.\",\"web\":[\"https://support.t-mobile.com/docs/DOC-14011\"],\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.tmobile.vvm.application\",\"label\":\"T-Mobile Visual Voicemail\",\"description\":\"Lets you use your voice mail and manage your inbox without dialing into your voicemail.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.tmobile.vvm.application\"],\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.tracfone.preload.accountservices\",\"description\":\"TracPhone / StraightTalk application. It just shows IMEI, SIM, and phone number, as well as a way to see device properties.\\nComes preinstalled with any TracPhone or StraightTalk device. It can be downloaded from the playstore if needed for whatever reason.\\nHas Approximate and Precise location permissions, and Device ID permission.\\nRuns in the background for them to collect data.\",\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.vcast.mediamanager\",\"label\":\"Verizon Cloud\",\"description\":\"Verizon Cloud\",\"web\":[\"https://play.google.com/store/apps/details?id=com.vcast.mediamanager\"],\"removal\":\"replace\",\"suggestions\":\"cloud_services\",\"type\":\"carrier\"},{\"id\":\"com.verizon.cloudsetupwizard\",\"description\":\"\",\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.verizon.llkagent\",\"label\":\"Llkagent\",\"description\":\"Used for Verizon store demo mode.\",\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.verizon.loginengine.unbranded\",\"label\":\"Carrier Login Engine\",\"description\":\"Needed for wifi-calling.\",\"web\":[\"https://forum.xda-developers.com/t/samsung-factory-unlocked-s9-s9-will-now-have-verizon-wi-fi-calling.3841547/\"],\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.verizon.messaging.vzmsgs\",\"label\":\"Verizon Messages\",\"description\":\"Verizon Messages\",\"web\":[\"https://play.google.com/store/apps/details?id=com.verizon.messaging.vzmsgs\"],\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.verizon.mips.services\",\"label\":\"My Verizon Services\",\"description\":\"Related to My Verizon app. Required for hotspot.\",\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.verizon.obdm\",\"label\":\"D-MAT\",\"description\":\"It's a set of metrics-related modules. Google Play uses the version of the Telemetry module to determine\\nif updates are available for metrics-related modules and which security patch version to display to the end user.\\nThis module doesn’t contain active code and has no functionality on its own.\",\"web\":[\"https://gitlab.com/W1nst0n/universal-android-debloater/-/issues/27#note_410012436\"],\"removal\":\"caution\",\"warning\":\"Removing modules-related packages may not be safe since Android 11.\",\"type\":\"carrier\"},{\"id\":\"com.verizon.obdm_permissions\",\"label\":\"OBDM_Permissions\",\"description\":\"Has a LOT of permissions!\\nIt is used to hold shares and securities in dematerialised/electronic format.\\nSeems weird that Verizon provides this so it's likely not this.\",\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.verizon.permissions.appdirectedsms\",\"label\":\"com.verizon.permissions.appdirectedsms\",\"description\":\"Custom permissions for some verizon stuff?\",\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.verizon.permissions.vzwappapn\",\"label\":\"com.verizon.permissions.vzwappapn\",\"description\":\"Custom permissions used to set Verizon APN?\",\"web\":[\"https://docs.samsungknox.com/CCMode/N900V.pdf\"],\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.verizon.remoteSimlock\",\"description\":\"VZWRemoteSimlockService\\nRemote SimLock lock, unlock, looks more danger than useful app.\",\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.verizon.services\",\"description\":\"AppDirectedSMS\\nOMA Device Management for Verizon.\\nit's for wifi calling, sms\",\"removal\":\"replace\",\"type\":\"carrier\"},{\"id\":\"com.verizon.vzwavs\",\"label\":\"VzwAVS\",\"description\":\"Has a scary list of permissions. Doesn't seems to break anything if removed.\",\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.verizontelematics.verizonhum\",\"label\":\"Hum: GPS Locator\",\"description\":\"Hum is the connected car solution that helps you take care of your car and everyone in it. Keep tabs on your car’s health and track of its location.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.verizontelematics.verizonhum\"],\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.vznavigator.Generic\",\"label\":\"VZ Navigator\",\"description\":\"VZ Navigator (GPS app)\",\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.vzw.apnlib\",\"label\":\"apnlib\",\"description\":\"Kind of library for Verizon APN?\",\"web\":[\"https://developer.android.com/reference/android/telephony/data/ApnSetting\"],\"removal\":\"caution\",\"warning\":\"Removing it prevents calling or texting (breaks WiFi calling). On Auto Optimization, it causes auto reboots.\",\"type\":\"carrier\"},{\"id\":\"com.vzw.apnservice\",\"label\":\"VZWAPN\",\"description\":\"APN Services.\",\"web\":[\"https://developer.android.com/reference/android/telephony/data/ApnSetting\"],\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.vzw.easvalidation\",\"description\":\"\",\"removal\":\"caution\",\"type\":\"carrier\"},{\"id\":\"com.vzw.ecid\",\"label\":\"Verizon Call Filter\",\"description\":\"Auto-block spam and report any unwanted numbers.\\nNOTE : Never trust a company which promotes call ID/spam blocking features.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.vzw.ecid\"],\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.vzw.hss.myverizon\",\"label\":\"My Verizon\",\"description\":\"Lets you manage your Verizon account.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.vzw.hss.myverizon\"],\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.vzw.hss.widgets.infozone.large\",\"label\":\"My InfoZone™ Widget:Big Screen\",\"description\":\"Gives weekly tips, access to device info and account information.\",\"web\":[\"https://www.droid-life.com/2013/02/12/verizon-introduces-my-infozone-widget-allows-easy-access-to-tips-device-info-and-account-information/\"],\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.vzw.qualitydatalog\",\"label\":\"com.vzw.qualitydatalog\",\"description\":\"Logging stuff\",\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.wavemarket.waplauncher\",\"label\":\"AT&T Secure Family™\",\"description\":\"Parental control app.\\n7 trackers + 16 permissions.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.wavemarket.waplauncher\",\"https://reports.exodus-privacy.eu.org/en/reports/com.wavemarket.waplauncher/latest/\"],\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.whitepages.nameid.tmobile\",\"label\":\"T-Mobile Name ID\",\"description\":\"By WhitePages. Discontinued and replaced by com.tmobile.services.nameid.\",\"web\":[\"https://www.whitepages.com/\",\"https://www.fiercewireless.com/wireless/t-mobile-to-offer-name-id-service-from-whitepages\",\"https://www.geekwire.com/2016/whitepages-spins-caller-id-spam-blocking-app-startup-hiya/\"],\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"de.telekom.tsc\",\"label\":\"AppEnabler\",\"description\":\"TSC = Telecom Service Center. Used to display ads in notifications panel.\",\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"fr.bouyguestelecom.ecm.android\",\"label\":\"Bouygues Telecom\",\"description\":\"Lets you manage your Bouygues account.\",\"web\":[\"https://play.google.com/store/apps/details?id=fr.bouyguestelecom.ecm.android\"],\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"fr.bouyguestelecom.tv.android\",\"label\":\"B.tv\",\"description\":\"Lets you watch TV from your phone.\",\"web\":[\"https://play.google.com/store/apps/details?id=fr.bouyguestelecom.tv.android\"],\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"fr.bouyguestelecom.vvmandroid\",\"label\":\"Messagerie vocale visuelle\",\"description\":\"Voicemail application for Bouygues Telecom. This app may inject ads into your gallery\",\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"fr.orange.cineday\",\"label\":\"Orange Cineday\",\"description\":\"Useless app but Cineday is pretty nice.\\nEvery Tuesday you can invite the person of your choice in movies (within the limit of available seats).\\nYou can just use https://cineday.orange.fr/cineday/\",\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"hdopen.vivicitta\",\"description\":\"Companion\\nApp for training, so bloated and from T-Mobile\",\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"hu.telekom.telekomapp\",\"description\":\"Telekom\\nApp for subscriptions, so bloated (a lot spying) and from T-Mobile\",\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"hu.telekom.telekomtv\",\"description\":\"Mobile shopping\\nApp for watch tv on phone, so bloated (a lot spying) and from T-Mobile\",\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"jp.co.daj.consumer.ifilter.aflauncher\",\"description\":\"Something Japanese with useless code.\",\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"jp.co.omronsoft.iwnnime.ml\",\"description\":\"iWnn IME\\nJapanese keyboard pre-installed on some Huawei phone's.\",\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"jp.co.omronsoft.wnnext.skin.std_dark_type2_HW\",\"description\":\"Skin Dark mode to Japanese Keyboard.\",\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"jp.co.omronsoft.wnnext.skin.std_light_type2_HW\",\"description\":\"Skin Light mode to Japanese Keyboard.\",\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"jp.co.yahoo.android.ebookjapan.preinstall\",\"description\":\"eBookJapan\\nNot needed japanese.\",\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"net.aetherpal.device\",\"label\":\"AT&T Remote Support\",\"description\":\"Provided by Aetherpal (was acquired by VMware). It allows an AT&T Advanced Support representative to assist you by accessing your device remotely.\",\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"pl.tmobile.miboa\",\"description\":\"My T-Mobile\\nHas login activity and MailBox.\\nA lot metrics, analytics.\",\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"pl.tmobile.panel\",\"description\":\"MyBox\\nRequire sim card to run app\\nit's app store(discontinued?)\",\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"ro.cosmote.aps.wnwlite\",\"description\":\"TopApps(discontinued)\\nit's non english app. Installs recommended apps?\\nI can't launch the app because it displays an error that it can't connect to the Internet, even when Wi-Fi is on.\",\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"telekom.hu.android.mobilvasarlas\",\"description\":\"Mobile shopping\\nApp for shopping or paying, so bloated and from T-Mobile\",\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"tmobile.hu.android.epgmiab\",\"description\":\"Newsreel\\nAnother app to tv things, so bloated and from T-Mobile, not needed\",\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"uk.co.ee.myee\",\"label\":\"My EE\",\"description\":\"Lets you control your EE pay monthly, pay as you go and WiFi devices. Check your data, bills, packs and more, and keep an eye on your spending.\\nContains unnecessary analytics and most of the things the app does can be done by texting 150 from your mobile.\",\"web\":[\"https://play.google.com/store/apps/details?id=uk.co.ee.myee\",\"https://ee.co.uk/help/help-new/billing-usage-and-top-up/call-text-and-data-charges/how-can-i-get-help-by-texting-150-on-pay-as-you-go-or-flex\",\"https://reports.exodus-privacy.eu.org/fr/reports/uk.co.ee.myee/latest/\",\"https://beta.pithus.org/report/6e8de7e02aba34c4f02dc966b39002f60b0852f55da923cdccc4ba4c09ed4a4a\"],\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"us.com.dt.iq.appsource.tmobile\",\"label\":\"App Source\",\"description\":\"Discontinued. This app aimed at organizing all of your existing apps on the phone by category and helping you discover new apps through search and recommendations.\",\"removal\":\"delete\",\"type\":\"carrier\"},{\"id\":\"com.android.chrome\",\"label\":\"Google Chrome\",\"description\":\"Google Chrome: Slow & Painful\\nOccasionally runs in the background, not to mention how it tracks everything.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.android.chrome\",\"https://privacytests.org/android.html\",\"https://fidoalliance.org/passkeys/\"],\"removal\":\"replace\",\"warning\":\"Removing the app may break creating and storing passkeys on your phone, so keep this enabled if you want to use that form of authentication. Google Play Services can also provide this functionality on some devices. When Chrome is updated via the Play Store, the Trichrome Library is also updated automatically. If Chrome is disabled or removed, it may impact WebView functionality.\\nThis is because Chrome, WebView, and the Trichrome Library work together as a bundle starting from Android 10 (API 29) and above.\",\"suggestions\":\"browsers\",\"type\":\"google\"},{\"id\":\"com.android.hotwordenrollment.okgoogle\",\"label\":\"OK Google enrollment\",\"description\":\"\\\"OK Google\\\" detection service that hears everything.\",\"removal\":\"delete\",\"type\":\"google\"},{\"id\":\"com.android.hotwordenrollment.xgoogle\",\"label\":\"Google Assistant\",\"description\":\"Formerly, X Google enrollment. \\\"OK Google\\\" detection service that hears everything.\",\"removal\":\"delete\",\"type\":\"google\"},{\"id\":\"com.android.partnerbrowsercustomizations.chromeHomepage\",\"label\":\"com.android.partnerbrowsercustomizations.chromeHomepage\",\"description\":\"Horrible stuff for Google Chrome. This package bypass your DNS settings (for letting pass Google ads).\",\"removal\":\"delete\",\"type\":\"google\"},{\"id\":\"com.android.soundpicker\",\"label\":\"Sounds\",\"description\":\"Needed to pick up a phone ringtone. No weird permissions.\",\"web\":[\"https://beta.pithus.org/report/f5f7c265c6d98666c78267b91643bbfb635021d5d4f85c93407079ba4aad88ee\"],\"removal\":\"caution\",\"type\":\"google\"},{\"id\":\"com.android.systemui.plugin.globalactions.wallet\",\"label\":\"com.android.systemui.plugin.globalactions.wallet\",\"description\":\"Apk file name: QuickAccessWallet. This is the Google Pay widget in the power menu(hold power button for 1sec to show this menu), below the Emergency, Power off and Reboot buttons.\",\"removal\":\"delete\",\"type\":\"google\"},{\"id\":\"com.android.vending\",\"label\":\"Google Play Store\",\"description\":\"The malware delivery store. Most apps are full of ads, trackers and malware.\",\"web\":[\"https://www.xda-developers.com/google-play-store-more-safety/\"],\"removal\":\"caution\",\"suggestions\":\"app_stores\",\"type\":\"google\"},{\"id\":\"com.chrome.beta\",\"label\":\"Chrome Beta\",\"description\":\"The beta version of Google Chrome.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.chrome.beta\"],\"removal\":\"replace\",\"suggestions\":\"browsers\",\"type\":\"google\"},{\"id\":\"com.chrome.canary\",\"label\":\"Chrome Canary (Unstable)\",\"description\":\"Canary version of Google Chrome, usually provides nightly builds.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.chrome.canary\"],\"removal\":\"replace\",\"suggestions\":\"browsers\",\"type\":\"google\"},{\"id\":\"com.chrome.dev\",\"label\":\"Chrome Dev\",\"description\":\"Google Chrome developer edition.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.chrome.dev\"],\"removal\":\"replace\",\"suggestions\":\"browsers\",\"type\":\"google\"},{\"id\":\"com.google.android.GoogleCamera\",\"label\":\"Google Camera\",\"description\":\"Camera with incredible features with the cost of tracking. Try the tracker-free mods if you're too much into Google Camera.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.google.android.GoogleCamera\"],\"removal\":\"replace\",\"suggestions\":\"cameras\",\"type\":\"google\"},{\"id\":\"com.google.android.accessibility.soundamplifier\",\"description\":\"Accessibility sound amplifier (https://play.google.com/store/apps/details?id=com.google.android.accessibility.soundamplifier)\",\"removal\":\"delete\",\"type\":\"google\"},{\"id\":\"com.google.android.apps.access.wifi.consumer\",\"label\":\"Google Wifi\",\"description\":\"Google Wifi app\",\"removal\":\"delete\",\"type\":\"google\"},{\"id\":\"com.google.android.apps.adm\",\"label\":\"Google Find My Device\",\"description\":\"Lets you locate your Android device.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.google.android.apps.adm\"],\"removal\":\"delete\",\"suggestions\":\"locators\",\"type\":\"google\"},{\"id\":\"com.google.android.apps.ads.publisher\",\"label\":\"Google AdSense\",\"description\":\"Google Adsense app\",\"removal\":\"delete\",\"type\":\"google\"},{\"id\":\"com.google.android.apps.adwords\",\"label\":\"Google Ads\",\"description\":\"Lets you monitor your ad campaigns.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.google.android.apps.adwords\"],\"removal\":\"delete\",\"type\":\"google\"},{\"id\":\"com.google.android.apps.assistant\",\"label\":\"Google Assistant Go\",\"description\":\"Lightweight Google Assistant for low-end devices (Go edition)\",\"web\":[\"https://play.google.com/store/apps/details?id=com.google.android.apps.assistant\"],\"removal\":\"delete\",\"type\":\"google\"},{\"id\":\"com.google.android.apps.authenticator2\",\"label\":\"Google Authenticator\",\"description\":\"Generates 2-Step Verification codes on your phone.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.google.android.apps.authenticator2\"],\"removal\":\"replace\",\"suggestions\":\"authenticators\",\"type\":\"google\"},{\"id\":\"com.google.android.apps.blogger\",\"label\":\"Blogger\",\"description\":\"Official app for Blogger/blogspot.com\",\"web\":[\"https://play.google.com/store/apps/details?id=com.google.android.apps.blogger\"],\"removal\":\"delete\",\"type\":\"google\"},{\"id\":\"com.google.android.apps.books\",\"label\":\"Google Play Books\",\"description\":\"Lets you buy and read ebooks, audiobooks, comics and manga.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.google.android.apps.books\"],\"removal\":\"replace\",\"suggestions\":\"ebook_readers\",\"type\":\"google\"},{\"id\":\"com.google.android.apps.chromecast.app\",\"label\":\"Google Home\",\"description\":\"Lets you set up, manage, and control your Google Nest, Google Wifi, Google Home and Chromecast devices. Let Google harvest your data with your money.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.google.android.apps.chromecast.app\"],\"removal\":\"delete\",\"type\":\"google\"},{\"id\":\"com.google.android.apps.cloudprint\",\"label\":\"Cloud Print\",\"description\":\"Let you print anywhere from any Android tablet or smartphone via Google.\",\"removal\":\"replace\",\"type\":\"google\"},{\"id\":\"com.google.android.apps.cultural\",\"label\":\"Google Arts & Culture\",\"description\":\"Know and interact with arts but with a price: Your privacy.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.google.android.apps.cultural\"],\"removal\":\"delete\",\"type\":\"google\"},{\"id\":\"com.google.android.apps.currents\",\"label\":\"Google Currents\",\"description\":\"Discontinued.\",\"removal\":\"delete\",\"type\":\"google\"},{\"id\":\"com.google.android.apps.docs\",\"label\":\"Google Drive\",\"description\":\"The drive where no personal data should ever be kept unencrypted.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.google.android.apps.docs\"],\"removal\":\"delete\",\"suggestions\":\"cloud_services\",\"type\":\"google\"},{\"id\":\"com.google.android.apps.docs.editors.docs\",\"label\":\"Google Docs\",\"description\":\"Google Docs client for Android\",\"web\":[\"https://play.google.com/store/apps/details?id=com.google.android.apps.docs.editors.docs\"],\"removal\":\"delete\",\"type\":\"google\"},{\"id\":\"com.google.android.apps.docs.editors.sheets\",\"label\":\"Google Sheets\",\"description\":\"Google Sheets client for Android\",\"web\":[\"https://play.google.com/store/apps/details?id=com.google.android.apps.docs.editors.sheets\"],\"removal\":\"delete\",\"type\":\"google\"},{\"id\":\"com.google.android.apps.docs.editors.slides\",\"label\":\"Google Slides\",\"description\":\"Google Slides client for Android\",\"web\":[\"https://play.google.com/store/apps/details?id=com.google.android.apps.docs.editors.slides\"],\"removal\":\"delete\",\"type\":\"google\"},{\"id\":\"com.google.android.apps.dynamite\",\"label\":\"Google Chat\",\"description\":\"Previously Hangout Chat, is a communication and collaboration tool focusing on conversation.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.google.android.apps.dynamite\"],\"removal\":\"delete\",\"type\":\"google\"},{\"id\":\"com.google.android.apps.enterprise.cpanel\",\"label\":\"Google Admin\",\"description\":\"Lets you manage your Google Cloud account on-the-go.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.google.android.apps.enterprise.cpanel\"],\"removal\":\"delete\",\"type\":\"google\"},{\"id\":\"com.google.android.apps.enterprise.dmagent\",\"label\":\"Google Apps Device Policy\",\"description\":\"Allows your IT administrator to mandate security settings like screen lock or device encryption and keep corporate data safe.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.google.android.apps.enterprise.dmagent\"],\"removal\":\"delete\",\"type\":\"google\"},{\"id\":\"com.google.android.apps.fireball\",\"label\":\"Google Allo\",\"description\":\"Discontinued.\",\"removal\":\"delete\",\"type\":\"google\"},{\"id\":\"com.google.android.apps.fitness\",\"label\":\"Google Fit\",\"description\":\"Fitness tracker that does not respect your privacy.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.google.android.apps.fitness\"],\"removal\":\"delete\",\"suggestions\":\"fitness_trackers\",\"type\":\"google\"},{\"id\":\"com.google.android.apps.freighter\",\"label\":\"Google Datally\",\"description\":\"Discontinued.\",\"removal\":\"delete\",\"type\":\"google\"},{\"id\":\"com.google.android.apps.giant\",\"label\":\"Google Analytics\",\"description\":\"Lets you monitor all of your Analytics properties so that you can keep track of your business while you're on the go.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.google.android.apps.giant\"],\"removal\":\"delete\",\"type\":\"google\"},{\"id\":\"com.google.android.apps.googleassistant\",\"label\":\"Google Assistant\",\"description\":\"The assistant that can stab you on the back.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.google.android.apps.googleassistant\"],\"removal\":\"delete\",\"type\":\"google\"},{\"id\":\"com.google.android.apps.handwriting.ime\",\"label\":\"Google Handwriting Input\",\"description\":\"Google Handwriting Input\",\"removal\":\"replace\",\"type\":\"google\"},{\"id\":\"com.google.android.apps.hangoutsdialer\",\"label\":\"Hangouts Dialer\",\"description\":\"Discontinued.\",\"removal\":\"delete\",\"type\":\"google\"},{\"id\":\"com.google.android.apps.inbox\",\"label\":\"Inbox by Gmail\",\"description\":\"Discontinued.\",\"removal\":\"delete\",\"type\":\"google\"},{\"id\":\"com.google.android.apps.inputmethod.hindi\",\"label\":\"Google Indic Keyboard\",\"description\":\"(Discontinued) Google Keyboard + Hindi characters\",\"removal\":\"replace\",\"suggestions\":\"keyboards\",\"type\":\"google\"},{\"id\":\"com.google.android.apps.kids.familylink\",\"label\":\"Google Family Link\",\"description\":\"Parental controls app from Google.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.google.android.apps.kids.familylink\"],\"removal\":\"delete\",\"type\":\"google\"},{\"id\":\"com.google.android.apps.kids.familylinkhelper\",\"label\":\"Family Link parental controls\",\"description\":\"Companion app to Google Family Link.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.google.android.apps.kids.familylinkhelper\"],\"removal\":\"delete\",\"type\":\"google\"},{\"id\":\"com.google.android.apps.m4b\",\"label\":\"Google My Maps\",\"description\":\"Discontinued.\",\"removal\":\"delete\",\"type\":\"google\"},{\"id\":\"com.google.android.apps.magazines\",\"label\":\"Google News\",\"description\":\"A personalized news aggregator that organizes and highlights what’s happening in the world.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.google.android.apps.magazines\"],\"removal\":\"replace\",\"suggestions\":\"rss_readers\",\"type\":\"google\"},{\"id\":\"com.google.android.apps.maps\",\"label\":\"Google Maps\",\"description\":\"A map navigator that makes it easier for the govt agencies to locate you.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.google.android.apps.maps\"],\"removal\":\"replace\",\"suggestions\":\"maps\",\"type\":\"google\"},{\"id\":\"com.google.android.apps.mapslite\",\"label\":\"Google Maps Go\",\"description\":\"A map navigator that makes it easier for the govt agencies to locate you.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.google.android.apps.mapslite\"],\"removal\":\"replace\",\"suggestions\":\"maps\",\"type\":\"google\"},{\"id\":\"com.google.android.apps.mediahome.launcher\",\"description\":\"Entertainment Space\\nAll-in-one application for entertainment purposes like movies, games, books etc.\",\"removal\":\"delete\",\"type\":\"google\"},{\"id\":\"com.google.android.apps.meetings\",\"label\":\"Google Meet\",\"description\":\"Formerly Hangouts Meet. Lets you create, schedule or join an online meeting.\",\"removal\":\"replace\",\"suggestions\":\"meeting_apps\",\"type\":\"google\"},{\"id\":\"com.google.android.apps.messaging\",\"label\":\"Messages\",\"description\":\"RCS client from Google, also supports SMS/MMS. Runs in the background.\\nCould be a global dependency for SMS, MMS, RCS, OTP, and other services/verifications.\\nGSMA has recently standardized E2EE, but currently, there is not alternative available for Android.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.google.android.apps.messaging\"],\"removal\":\"replace\",\"warning\":\"Once disabled/uninstalled, even if reinstalled, a factory reset may be required to re-obtain full functionality.\",\"suggestions\":\"sms\",\"type\":\"google\"},{\"id\":\"com.google.android.apps.navlite\",\"label\":\"Navigation for Google Maps Go\",\"description\":\"Provides GPS turn-by-turn voice guided navigation and is optimized for performance on low-memory phones.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.google.android.apps.navlite\"],\"removal\":\"replace\",\"suggestions\":\"maps\",\"type\":\"google\"},{\"id\":\"com.google.android.apps.nbu.files\",\"label\":\"Files\",\"description\":\"Used to be for cleaning and sharing. But nowadays, it became a hybrid app. Runs in the background.\\nFOSS alternative is https://github.com/TeamAmaze/AmazeFileUtilities\",\"web\":[\"https://play.google.com/store/apps/details?id=com.google.android.apps.nbu.files\"],\"removal\":\"delete\",\"warning\":\"Android itself provides the options to clean up your device in Settings.\",\"type\":\"google\"},{\"id\":\"com.google.android.apps.nbu.paisa.user\",\"label\":\"Google Pay\",\"description\":\"Digital wallet and payment system.\\nYou really should not trust Google not to sell your data (even if they claim the contrary).\\nThe app itself has a LOT of permissions & login with your google account is mandatory to use the app.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.google.android.apps.nbu.paisa.user\",\"https://support.google.com/googlepay/answer/10223752?hl=en&co=GENIE.Platform%3DAndroid#zippy=%2Cinfo-that-google-may-collect\",\"https://venturebeat.com/2020/11/20/probeat-google-will-eventually-sell-ads-against-your-financial-data/\",\"https://www.bleepingcomputer.com/news/google/google-payment-privacy-settings-hidden-behind-special-url/\",\"https://beta.pithus.org/report/36b22c539b5f25c27a7699516c906351a25ba2daa2894eed08ae22f7a2a72c0e\"],\"removal\":\"delete\",\"type\":\"google\"},{\"id\":\"com.google.android.apps.nexuslauncher\",\"label\":\"Pixel Launcher\",\"description\":\"Used to be called Nexus Launcher (back when Google phones were called Nexus, not Pixel).\",\"web\":[\"https://play.google.com/store/apps/details?id=com.google.android.apps.nexuslauncher\"],\"removal\":\"caution\",\"warning\":\"Your system will break if there is no other launcher. So, download another launcher before removing it.\",\"suggestions\":\"launchers\",\"type\":\"google\"},{\"id\":\"com.google.android.apps.paidtasks\",\"label\":\"Google Opinion Rewards\",\"description\":\"Answer quick surveys and earn Rewards. If you insist on keeping it for earning free credits, just give them all the wrong answers :)\",\"web\":[\"https://play.google.com/store/apps/details?id=com.google.android.apps.paidtasks\"],\"removal\":\"delete\",\"type\":\"google\"},{\"id\":\"com.google.android.apps.pdfviewer\",\"label\":\"Google PDF Viewer\",\"description\":\"Discontinued. PDF viewers are very sensitive applications. You should always use an app that is uptodate.\",\"removal\":\"replace\",\"suggestions\":\"ebook_readers\",\"type\":\"google\"},{\"id\":\"com.google.android.apps.photos\",\"label\":\"Google Photos\",\"description\":\"Allows Google to scan and catalog all your photos so that it knows you and your relations more than you do.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.google.android.apps.photos\"],\"removal\":\"replace\",\"suggestions\":\"gallery\",\"type\":\"google\"},{\"id\":\"com.google.android.apps.photos.scanner\",\"label\":\"PhotoScan by Google Photos\",\"description\":\"Companion app to Google Photos for reviving old pictures.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.google.android.apps.photos.scanner\"],\"removal\":\"delete\",\"type\":\"google\"},{\"id\":\"com.google.android.apps.plus\",\"label\":\"Google+\",\"description\":\"Discontinued.\",\"removal\":\"delete\",\"type\":\"google\"},{\"id\":\"com.google.android.apps.podcasts\",\"label\":\"Google Podcasts\",\"description\":\"Lets you explore, subscribe and play podcasts.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.google.android.apps.podcasts\"],\"removal\":\"replace\",\"suggestions\":\"podcasts\",\"type\":\"google\"},{\"id\":\"com.google.android.apps.privacy.wildlife\",\"description\":\"VPN by Google One. Discontinued. Succeeded by VPN by Google and Google Fi VPN.\",\"removal\":\"delete\",\"type\":\"google\"},{\"id\":\"com.google.android.apps.recorder\",\"label\":\"Recorder\",\"description\":\"Audio recorder from Google LLC.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.google.android.apps.recorder\"],\"removal\":\"replace\",\"suggestions\":\"audio_recorders\",\"type\":\"google\"},{\"id\":\"com.google.android.apps.restore\",\"label\":\"Data Restore Tool\",\"description\":\"The backup restore wizard used for pulling Android system backups from your Google account.\\nRuns on boot.\\nYou only need this if you factory restore, in which case it’s automatically re-enabled for you.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.google.android.apps.restore\"],\"removal\":\"caution\",\"type\":\"google\"},{\"id\":\"com.google.android.apps.safetyhub\",\"label\":\"Personal Safety\",\"description\":\"A Pixel app that helps you prepare and react in an emergency by quickly calling emergency services (e.g if your phone detects that you've been in a car crash, it can call for help automatically).\\nThis app has obviously a lot of dangerous permissions due to its operation.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.google.android.apps.safetyhub\",\"https://beta.pithus.org/report/e207f7d0f59d9df268154b90fc10cd861d0483465e30bbac8f68a7b12340c67f\"],\"removal\":\"delete\",\"type\":\"google\"},{\"id\":\"com.google.android.apps.santatracker\",\"label\":\"Google Santa Tracker\",\"description\":\"Discontinued.\",\"removal\":\"delete\",\"type\":\"google\"},{\"id\":\"com.google.android.apps.scone\",\"description\":\"Automatically switches basebands between LTE and 5G on demand\",\"removal\":\"delete\",\"type\":\"google\"},{\"id\":\"com.google.android.apps.searchlite\",\"label\":\"Google Go\",\"description\":\"The Google search app made for low-RAM devices.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.google.android.apps.searchlite\"],\"removal\":\"delete\",\"type\":\"google\"},{\"id\":\"com.google.android.apps.security.securityhub\",\"description\":\"Checks security your phone(you can find it in settings). Not very useful.\\nhttps://play.google.com/store/apps/details?id=com.google.android.apps.security.securityhub\",\"removal\":\"delete\",\"type\":\"google\"},{\"id\":\"com.google.android.apps.setupwizard.searchselector\",\"label\":\"Search Engine Selector\",\"description\":\"The search selection screen in the setupwizard you see on new/factory reset phones. Runs on boot, but doesn't seem to run in the background beyond that.\",\"removal\":\"delete\",\"type\":\"google\"},{\"id\":\"com.google.android.apps.subscriptions.red\",\"label\":\"Google One\",\"description\":\"Lets you manage your Google cloud storage.\\nOccasionally runs in the background.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.google.android.apps.subscriptions.red\"],\"removal\":\"delete\",\"suggestions\":\"cloud_services\",\"type\":\"google\"},{\"id\":\"com.google.android.apps.tachyon\",\"label\":\"Google Meet\",\"description\":\"Formerly Google Duo. Lets you create, schedule or join an online meeting.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.google.android.apps.tachyon\"],\"removal\":\"replace\",\"suggestions\":\"meeting_apps\",\"type\":\"google\"},{\"id\":\"com.google.android.apps.tasks\",\"label\":\"Google Tasks\",\"description\":\"Manage, capture, and edit your tasks with synchronisation.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.google.android.apps.tasks\"],\"removal\":\"replace\",\"suggestions\":\"task_managers\",\"type\":\"google\"},{\"id\":\"com.google.android.apps.translate\",\"label\":\"Google Translate\",\"description\":\"Google Translate mobile client.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.google.android.apps.translate\"],\"removal\":\"replace\",\"suggestions\":\"translators\",\"type\":\"google\"},{\"id\":\"com.google.android.apps.travel.onthego\",\"label\":\"Google Trip\",\"description\":\"Discontinued.\",\"removal\":\"delete\",\"type\":\"google\"},{\"id\":\"com.google.android.apps.turbo\",\"label\":\"Device Health Services\",\"description\":\"Discontinued.\",\"removal\":\"caution\",\"warning\":\"Breaks battery settings.\",\"suggestions\":\"battery_managers\",\"type\":\"google\"},{\"id\":\"com.google.android.apps.tycho\",\"description\":\"Google Fi Wireless\\nhttps://play.google.com/store/apps/details?id=com.google.android.apps.tycho\",\"removal\":\"delete\",\"type\":\"google\"},{\"id\":\"com.google.android.apps.uploader\",\"label\":\"Picasa Uploader\",\"description\":\"Discontinued.\",\"removal\":\"delete\",\"type\":\"google\"},{\"id\":\"com.google.android.apps.vega\",\"label\":\"Google My Business\",\"description\":\"Discontinued.\",\"removal\":\"delete\",\"type\":\"google\"},{\"id\":\"com.google.android.apps.walletnfcrel\",\"label\":\"Google Wallet\",\"description\":\"Formerly Google Pay. Use cash, protect your privacy.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.google.android.apps.walletnfcrel\"],\"removal\":\"delete\",\"type\":\"google\"},{\"id\":\"com.google.android.apps.wallpaper\",\"label\":\"Wallpapers\",\"description\":\"Wallpaper app from Google. Lets you set wallpaper from various sources including Google Earth collection\",\"removal\":\"delete\",\"type\":\"google\"},{\"id\":\"com.google.android.apps.weather\",\"description\":\"The new Weather app by Google. If removed, \\\"At a Glance\\\" and the lock screen will still redirect to the Google app (like before).\\nhttps://play.google.com/store/apps/details?id=com.google.android.apps.weather\",\"removal\":\"delete\",\"type\":\"google\"},{\"id\":\"com.google.android.apps.wellbeing\",\"label\":\"Digital Wellbeing\",\"description\":\"Lets you track device and app usage and set usage limits.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.google.android.apps.wellbeing\"],\"removal\":\"caution\",\"warning\":\"It is a hard dependency for the settings app on Android 12+ on Pixel phones. After uninstalling, there will be an empty entry on Settings. Rebooting should make it disappear.\",\"type\":\"google\"},{\"id\":\"com.google.android.apps.work.oobconfig\",\"label\":\"Device Setup\",\"description\":\"Sets up device to be managed by EMM (Enterprise Mobility Management), which \\\"allows organizations to securely enable employee use of mobile devices\\\".\\nMight also be what does the actual management on your device, if you set it up as a work device.\\nOnly seems to run on boot(not in the background after boot) if you haven't set up your device as a work device.\\nI tried to disable it through UAD, but nothing happens? Seems immune to disabling?\\nhttps://bayton.org/2020/11/google-announce-big-changes-to-zero-touch/\\nhttps://bayton.org/docs/enterprise-mobility/android/what-is-android-zero-touch-enrolment/\\nContains 4 services: GcmJobService, GservicesChangedObserverService, AppMeasurementService and FirebaseInstanceIdService.\\nGCM(Google Cloud Messaging) was the backend for Android's push messaging system 2012-2019, after which it was replaced by FCM(Firebase Cloud Messaging). I assume the GCM/Firebase connection is for Push notification functionality.\\nThe MANAGE_CARRIER_OEM_UNLOCK_STATE permission hints at doing something with carrier locks?\\nNeeds Google Play Services to function?\",\"removal\":\"caution\",\"type\":\"google\"},{\"id\":\"com.google.android.apps.youtube.creator\",\"label\":\"YouTube Studio\",\"description\":\"Intended for YouTube creators to track their channel activities and analytics.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.google.android.apps.youtube.creator\"],\"removal\":\"delete\",\"type\":\"google\"},{\"id\":\"com.google.android.apps.youtube.gaming\",\"label\":\"YouTube Gaming\",\"description\":\"Discontinued in March 2019, features integrated in main YouTube app.\",\"removal\":\"delete\",\"type\":\"google\"},{\"id\":\"com.google.android.apps.youtube.kids\",\"label\":\"YouTube Kids\",\"description\":\"YouTube for kids.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.google.android.apps.youtube.kids\",\"https://qz.com/youtube-has-become-the-worlds-nanny-1850047610\"],\"removal\":\"replace\",\"suggestions\":\"streaming_apps\",\"type\":\"google\"},{\"id\":\"com.google.android.apps.youtube.mango\",\"label\":\"YouTube Go\",\"description\":\"Lite version of the YouTube app. Discontinued in August 2022. Still present in Google Play Store for some reason.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.google.android.apps.youtube.kids\",\"https://support.google.com/youtube/thread/162222567/youtube-go-is-going-away-in-august-of-this-year\"],\"removal\":\"replace\",\"suggestions\":\"streaming_apps\",\"type\":\"google\"},{\"id\":\"com.google.android.apps.youtube.music\",\"label\":\"YouTube Music\",\"description\":\"YouTube Music client for Android\",\"web\":[\"https://play.google.com/store/apps/details?id=com.google.android.apps.youtube.music\"],\"removal\":\"replace\",\"suggestions\":\"music_apps\",\"type\":\"google\"},{\"id\":\"com.google.android.apps.youtube.vr\",\"label\":\"YouTube VR\",\"description\":\"Watch YouTube in VR.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.google.android.apps.youtube.vr\"],\"removal\":\"delete\",\"type\":\"google\"},{\"id\":\"com.google.android.as\",\"label\":\"Android System Intelligence\",\"description\":\"Previously, Device Personalization Services. Runs in the background.\\n\\\"Enables intelligent features across Android\\\", like: Live Caption, Screen Attention, Improved Copy-Paste, App Predictions in the launcher, Notification Smart Actions, Smart Text Selection and Linkifying text in apps.\\nAlso known as device learning, e.g., enhanced keyboard auto suggestions, keeps the screen on when looking at it (with help of the camera), smart replies.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.google.android.as\",\"https://milaq.net/android-bloatware\"],\"removal\":\"delete\",\"type\":\"google\"},{\"id\":\"com.google.android.as.oss\",\"description\":\"Private Compute Services. On-device behavior analysis\\nEnables live caption, music recognition and smart replies.\\nSeems to be a dependency of System Intelligence.\\nhttps://play.google.com/store/apps/details?id=com.google.android.as.oss\\nhttps://milaq.net/android-bloatware\",\"removal\":\"delete\",\"type\":\"google\"},{\"id\":\"com.google.android.backup\",\"label\":\"Google Backup Transport\",\"description\":\"Allows Android apps to back up their data on Google servers (on Android 4.2).\",\"removal\":\"replace\",\"suggestions\":\"backup_apps\",\"type\":\"google\"},{\"id\":\"com.google.android.backuptransport\",\"label\":\"Google Backup Transport\",\"description\":\"Allows Android apps to back up their data on Google servers.\",\"removal\":\"replace\",\"suggestions\":\"backup_apps\",\"type\":\"google\"},{\"id\":\"com.google.android.calculator\",\"label\":\"Calculator\",\"description\":\"Calculator app from Google LLC. What sort of calculator collects personal info?\",\"web\":[\"https://play.google.com/store/apps/details?id=com.google.android.calculator\"],\"removal\":\"replace\",\"suggestions\":\"calculators\",\"type\":\"google\"},{\"id\":\"com.google.android.calendar\",\"label\":\"Google Calendar\",\"description\":\"Calendar app from Google LLC.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.google.android.calendar\"],\"removal\":\"replace\",\"suggestions\":\"calendars\",\"type\":\"google\"},{\"id\":\"com.google.android.cellbroadcastreceiver\",\"label\":\"Wireless emergency alerts\",\"dependencies\":[\"com.google.android.cellbroadcastservice\"],\"description\":\"Cell broadcast is designed to deliver messages to multiple users in an area.\\nThis is notably used by ISP to send Emergency/Government alerts.\\nRuns at boot and is also triggered after exiting airplane mode.\",\"web\":[\"https://en.wikipedia.org/wiki/Cell_Broadcast\",\"https://www.androidcentral.com/amber-alerts-and-android-what-you-need-know\",\"https://android.googlesource.com/platform/packages/apps/CellBroadcastReceiver/+/refs/heads/master/src/com/android/cellbroadcastreceiver\"],\"removal\":\"caution\",\"type\":\"google\"},{\"id\":\"com.google.android.cellbroadcastservice\",\"label\":\"Cell Broadcast Service\",\"required_by\":[\"com.google.android.cellbroadcastreceiver\"],\"description\":\"Cell broadcast is designed to deliver messages to multiple users in an area.\\nThis is notably used by ISP to send Emergency/Government alerts.\",\"web\":[\"https://en.wikipedia.org/wiki/Cell_Broadcast\",\"https://www.androidcentral.com/amber-alerts-and-android-what-you-need-know\"],\"removal\":\"caution\",\"type\":\"google\"},{\"id\":\"com.google.android.configupdater\",\"label\":\"ConfigUpdater\",\"description\":\"Intents used to provide unbundled updates of system data. All require the UPDATE_CONFIG permission. Updates:\\n- system wide certificate pins for TLS connections.\\n- System wide Intent firewall.\\n- List of permium SMS short codes.\\n- List of carrier provisioning URLs.\\n- Set of trusted logs used for Certificate Transparency support for TLS connections language detection model file\\n- Smart selection model file\\n- Conversation actions model file\\n- Network watchlist config file\\n- Intent action indicating that the updated carrier id config is available\\n- The emergency number database into the devices\\n- An integer to indicate the numeric version of the new data -- devices should only install if the update version is newer than the current one\\n- Hash of the database, which is encoded by base-16 SHA512.\",\"web\":[\"https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/os/ConfigUpdate.java\"],\"removal\":\"caution\",\"type\":\"google\"},{\"id\":\"com.google.android.contacts\",\"label\":\"Contacts\",\"description\":\"Contacts by Google LLC.\\nOccasionally runs in the background.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.google.android.contacts\"],\"removal\":\"replace\",\"suggestions\":\"contacts\",\"type\":\"google\"},{\"id\":\"com.google.android.deskclock\",\"label\":\"Clock\",\"description\":\"Clock by Google LLC.\",\"removal\":\"replace\",\"warning\":\"On some phones, removing this makes it so alarms and notifications only vibrate and don't make any sound (via any installed app), and makes the 'Alarm' section unavailable in 'Settings > Sound & Vibration'\",\"suggestions\":\"clocks\",\"type\":\"google\"},{\"id\":\"com.google.android.dialer\",\"label\":\"Phone\",\"description\":\"Formerly Google Dialer.\\nDefault dialer on some phones.\\nGoogle Analytics are embedded in the app, assume everything is datamined.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.google.android.dialer\",\"https://www.virustotal.com/gui/file/a978d90f27d5947dca33ed59b73bd8efbac67253f9ef7a343beb9197c8913d1a/details\"],\"removal\":\"replace\",\"suggestions\":\"dialers\",\"type\":\"google\"},{\"id\":\"com.google.android.feedback\",\"label\":\"Market Feedback Agent\",\"description\":\"This is the package that sends crash-report feedback to the Play Store? The crash pop-up still happens with this disabled.\\nDoesn't seem to run on its own.\\nHas permission to access system logs and package usage stats. Only connects to 4 Google domains. App developers likely have to go through the Play Store to access any sent data.\",\"web\":[\"https://beta.pithus.org/report/7041823ff880c207ed2ddacdc92e5ed803b1eb105e4483696d2152bea44903aa\"],\"removal\":\"delete\",\"type\":\"google\"},{\"id\":\"com.google.android.gm\",\"label\":\"Gmail\",\"description\":\"Gmail client from Google LLC. It also allows adding other E-Mail accounts.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.google.android.gm\"],\"removal\":\"replace\",\"suggestions\":\"email_clients\",\"type\":\"google\"},{\"id\":\"com.google.android.gm.lite\",\"label\":\"Gmail Go\",\"description\":\"Gmail client by Google LLC for low-end devices.\",\"removal\":\"replace\",\"suggestions\":\"email_clients\",\"type\":\"google\"},{\"id\":\"com.google.android.gms\",\"label\":\"Google Play services\",\"description\":\"GMS = Google Mobile Services. It is a layer that sits on top of the OS and provides a lot of proprietary Google APIs, giving apps access to various Google Services, such as: \\\"fused\\\"-location (internet and GPS chip), QR Code scanner, 2FA, G-Drive storage, Firebase API, Cloud Messaging, etc.\\nIf you remove it, all the apps relying on it will either:\\n- detect the lack of Play-Services and refuse to run\\n- detect the lack of Play-Services but allow you to run (improperly) by dismissing an annoying popup.\\nDisabling this package will improve battery life a lot.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.google.android.gms\"],\"removal\":\"caution\",\"warning\":\"Removing Google Play Services can cause bootloops. If you use “Find My Device”, you will need to remove it from the \\\"Device admin apps\\\" settings panel to be able to remove this package.\",\"type\":\"google\"},{\"id\":\"com.google.android.gms.location.history\",\"label\":\"Google Location History\",\"description\":\"This app has nothing in the code. Only png logo google and name.\",\"removal\":\"delete\",\"type\":\"google\"},{\"id\":\"com.google.android.gms.policy_sidecar_aps\",\"label\":\"com.google.android.gms.policy_sidecar_aps\",\"description\":\"Not sure what purpose it has, but it gets some network and phone data and connects to some Google domains, but never on its own; it has no permissions and never runs on its own, it likely exists as a helper package for other Google services.\\nDoesn't seem to exist in newer versions of Android; it's not in Android 11, but it is in 9.\\nNeeds a Google Account and Google Play Services to work.\\nGiven its name it could be related to Android auto?\\nSeems safe to remove, noticed no breakage (didn't test Android Auto though).\",\"web\":[\"https://beta.pithus.org/report/60835b97f38d9e64d4f554a73dab71c892153486a8e0fd81461c3d85359d9fae\"],\"removal\":\"delete\",\"type\":\"google\"},{\"id\":\"com.google.android.gms.supervision\",\"description\":\"Family Link parental controls\\nIt has something to Family Link parental controls.\\nIntroduced in android 13.\\nhttps://play.google.com/store/apps/details?id=com.google.android.gms.supervision\",\"removal\":\"delete\",\"type\":\"google\"},{\"id\":\"com.google.android.googlequicksearchbox\",\"label\":\"Google\",\"description\":\"Formerly, Google Search Box.\\nRuns in the background.\\nPointless. If you need a shortcut to Google on your homescreen just use a web-browser shortcut. Does also remove the Google Sound Search widget, but you can get that functionality from an app like Shazam, that additionally doesn't run in the background constantly like this package does.\\nThis app also powers the Google Discover page (the news 'widget' when you go to the left of the home screen) and the app symbol called 'Google'.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.google.android.googlequicksearchbox\"],\"removal\":\"caution\",\"warning\":\"Disabling this package also breaks the Ok Google Search functionality as well as Google Lens.\",\"type\":\"google\"},{\"id\":\"com.google.android.gsf\",\"label\":\"Google Services Framework\",\"description\":\"Supports the Play Services application in application updates, user authentication, location services, user searches & more.\\nSame recommendation as com.google.android.gms except I've never seen a bootloop because of deleting this package.\",\"web\":[\"https://android.stackexchange.com/questions/216176/what-is-the-exact-functionality-of-google-play-services-google-services-framew\",\"https://stackoverflow.com/questions/37337448/what-is-the-difference-between-google-service-frameworkgsfgoogle-mobile-servi\"],\"removal\":\"caution\",\"type\":\"google\"},{\"id\":\"com.google.android.gsf.login\",\"label\":\"Google Account Manager\",\"description\":\"Support for managing Google accounts.\",\"removal\":\"caution\",\"warning\":\"Safe to remove if you don't use a Google account.\",\"type\":\"google\"},{\"id\":\"com.google.android.health.connect.backuprestore\",\"description\":\"Health Connect for Android backup/restore.\",\"removal\":\"replace\",\"type\":\"google\"},{\"id\":\"com.google.android.healthconnect.controller\",\"description\":\"Health Connect by Android gives you a simple way to share data between your health, fitness, and wellbeing apps without compromising on privacy.\\nOnce you've downloaded Health Connect, you can access it through your settings by going to Settings > Apps > Health Connect, or from your Quick Settings menu.\\nhttps://play.google.com/store/apps/details?id=com.google.android.apps.healthdata\",\"removal\":\"replace\",\"type\":\"google\"},{\"id\":\"com.google.android.ims\",\"label\":\"Carrier Services\",\"description\":\"Runs in the background.\\nPlay store description claims power savings in addition to the features, but I don't see how that could be the case.\\nIMS(Ip Multimedia Subsystem) is an open industry standard for voice and multimedia communications over packet-based IP networks (VoLTE/VoIP/Wifi calling).\",\"web\":[\"https://play.google.com/store/apps/details?id=com.google.android.ims\"],\"removal\":\"delete\",\"type\":\"google\"},{\"id\":\"com.google.android.inputmethod.japanese\",\"label\":\"Google Japanese Input\",\"description\":\"(Discontinued) Google Keyboard + Japanese characters.\",\"removal\":\"replace\",\"suggestions\":\"keyboards\",\"type\":\"google\"},{\"id\":\"com.google.android.inputmethod.korean\",\"label\":\"Google Korean Input\",\"description\":\"(Discontinued) Google Keyboard + Korean characters.\",\"removal\":\"replace\",\"suggestions\":\"keyboards\",\"type\":\"google\"},{\"id\":\"com.google.android.inputmethod.latin\",\"label\":\"Gboard\",\"description\":\"Sometimes the only keyboard app on a phone.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.google.android.inputmethod.latin\"],\"removal\":\"replace\",\"warning\":\"Make sure you have another installed before you disable.\",\"suggestions\":\"keyboards\",\"type\":\"google\"},{\"id\":\"com.google.android.inputmethod.pinyin\",\"label\":\"Google Pinyin Input\",\"description\":\"(Discontinued) Google Keyboard + Pinyin (Chinese) characters\",\"removal\":\"replace\",\"suggestions\":\"keyboards\",\"type\":\"google\"},{\"id\":\"com.google.android.instantapps.supervisor\",\"label\":\"Instant Apps\",\"description\":\"Lets you try new games directly on Google Play.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.google.android.instantapps.supervisor\",\"https://www.zdnet.com/article/googles-instant-apps-goes-live-now-you-can-try-android-apps-before-installing-them/\"],\"removal\":\"delete\",\"type\":\"google\"},{\"id\":\"com.google.android.keep\",\"label\":\"Google Keep\",\"description\":\"Note taking app from Google.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.google.android.keep\"],\"removal\":\"replace\",\"suggestions\":\"note_taking_apps\",\"type\":\"google\"},{\"id\":\"com.google.android.launcher\",\"label\":\"Google Now Launcher\",\"description\":\"Launcher app from google.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.google.android.launcher\"],\"removal\":\"replace\",\"warning\":\"Make sure you have another installed before you disable.\",\"suggestions\":\"launchers\",\"type\":\"google\"},{\"id\":\"com.google.android.location\",\"label\":\"UnifiedNlp\",\"description\":\"Handles location services on older devices. On newer ones Google location services is part of Google Play Services and Android location service is provided by com.android.location.fused or com.android.location.\",\"removal\":\"replace\",\"type\":\"google\"},{\"id\":\"com.google.android.markup\",\"label\":\"Markup\",\"description\":\"Google Markup app made for modifying pictures, shipped by default on every Pie+ device.\",\"removal\":\"delete\",\"type\":\"google\"},{\"id\":\"com.google.android.marvin.talkback\",\"label\":\"Android Accessibility Suite\",\"description\":\"Helps blind and vision-impaired users.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.google.android.marvin.talkback\"],\"removal\":\"caution\",\"warning\":\"Removal causes com.motorola.dynamicvolume to not display the respective volume for individual apps when the volume button pressed. Seems to revert to an older (maybe testing) version of the dynamicvolume package?\",\"type\":\"google\"},{\"id\":\"com.google.android.music\",\"label\":\"Google Play Music\",\"description\":\"Discontinued and replaced by com.google.android.apps.youtube.music\",\"removal\":\"replace\",\"suggestions\":\"music_apps\",\"type\":\"google\"},{\"id\":\"com.google.android.onetimeinitializer\",\"label\":\"Google One Time Init\",\"description\":\"Provides first time setup, safe to remove.\",\"removal\":\"delete\",\"type\":\"google\"},{\"id\":\"com.google.android.overlay.gmsconfig\",\"description\":\"Useless configurations about webview, wifi and bluetooth to scan for better location. Everything works without it.\\nWARNING: causes the Galaxy App to force-close after a few seconds on a Samsung N960F running Android Q.\",\"removal\":\"replace\",\"type\":\"google\"},{\"id\":\"com.google.android.overlay.gmsconfig.asi\",\"description\":\"it's another component of\\nAndroid System Intelligence (previously Device Personalization Services)\",\"removal\":\"delete\",\"type\":\"google\"},{\"id\":\"com.google.android.overlay.gmsconfig.common\",\"label\":\"com.google.android.overlay.gmsconfig.common\",\"description\":\"If you delete this package, you won't be able to log in to your Google account on a Google app. But if you don't need to log in to a Google account, you can safely remove this.\",\"removal\":\"caution\",\"type\":\"google\"},{\"id\":\"com.google.android.overlay.gmsconfig.comms\",\"label\":\"com.google.android.overlay.gmsconfig.comms\",\"description\":\"Useless configurations for Google's Phone, Messages, Contacts apps, everything works without it.\",\"removal\":\"delete\",\"type\":\"google\"},{\"id\":\"com.google.android.overlay.gmsconfig.geotz\",\"description\":\"Provides Geolocation Time Zone detection.\\nand it's used by (com.google.android.overlay.gmsconfig.common)?\\nNo effects after remove.\",\"removal\":\"caution\",\"type\":\"google\"},{\"id\":\"com.google.android.overlay.gmsconfig.gsa\",\"label\":\"com.google.android.overlay.gmsconfig.gsa\",\"description\":\"configures default assistant? And have config to allow disabling assist disclosure?\\nI think it doesn't affect anything.\\nSafe to remove if you removed (com.google.android.googlequicksearchbox).\",\"removal\":\"caution\",\"type\":\"google\"},{\"id\":\"com.google.android.overlay.gmsconfig.personalsafety\",\"description\":\"Not needed for (com.google.android.apps.safetyhub).\",\"removal\":\"caution\",\"type\":\"google\"},{\"id\":\"com.google.android.overlay.gmsconfig.photos\",\"label\":\"com.google.android.overlay.gmsconfig.photos\",\"description\":\"Overlay to Gallery (com.google.android.apps.photos). Useless.\",\"removal\":\"delete\",\"type\":\"google\"},{\"id\":\"com.google.android.overlay.gmsconfig.searchlauncherqs\",\"description\":\"Useless gmsconfig. it's config default launcher but not needed.\",\"removal\":\"delete\",\"type\":\"google\"},{\"id\":\"com.google.android.overlay.gmsconfig.searchselector\",\"description\":\"Not needed for (com.google.android.apps.setupwizard.searchselector).\",\"removal\":\"delete\",\"type\":\"google\"},{\"id\":\"com.google.android.overlay.gmsconfig.ww\",\"description\":\"useless unused overlay gmsconfig to family link.\",\"removal\":\"delete\",\"type\":\"google\"},{\"id\":\"com.google.android.overlay.modules.cellbroadcastreceiver\",\"label\":\"com.google.android.overlay.modules.cellbroadcastreceiver\",\"dependencies\":[\"com.google.android.cellbroadcastreceiver\"],\"description\":\"Overlay (theme/notification) module for com.google.android.cellbroadcastreceiver\",\"web\":[\"https://docs.samsungknox.com/CCMode/G973F_LTE_R.pdf\"],\"removal\":\"caution\",\"type\":\"google\"},{\"id\":\"com.google.android.overlay.modules.documentsui\",\"label\":\"com.google.android.overlay.modules.documentsui\",\"description\":\"In code only found: `is_launcher_enabled` is set to false.\\nIt's only made to hide app icon (com.google.android.documentsui)\\nNo effects after removal (the launcher icon will be not back), it's useless.\",\"web\":[\"https://docs.samsungknox.com/CCMode/G973F_LTE_R.pdf\"],\"removal\":\"delete\",\"type\":\"google\"},{\"id\":\"com.google.android.partnersetup\",\"label\":\"Google Partner Setup\",\"description\":\"Occasionally runs in the background. Based on an unclear explanation online: Enables applications to interact with your Google account/apps, for example: adding a Google Calendar event from a To-Do app.\\nProbably safe to disable; Haven't noticed any consequences of disabling from weeks of use.\",\"removal\":\"caution\",\"type\":\"google\"},{\"id\":\"com.google.android.pixel.setupwizard\",\"label\":\"Pixel Setup\",\"description\":\"It's the basic configuration setup guides you through the basics of setting up Google features on your device. The package is only present on Pixel phones.\",\"removal\":\"caution\",\"warning\":\"Removing the package breaks the Google Play System update page found on \\\"Security & privacy\\\".\",\"type\":\"google\"},{\"id\":\"com.google.android.play.games\",\"label\":\"Google Play Games\",\"description\":\"Google Play Games.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.google.android.play.games\"],\"removal\":\"delete\",\"type\":\"google\"},{\"id\":\"com.google.android.projection.gearhead\",\"label\":\"Android Auto\",\"description\":\"Smart driving companion.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.google.android.projection.gearhead\"],\"removal\":\"delete\",\"type\":\"google\"},{\"id\":\"com.google.android.setupwizard\",\"label\":\"Android Setup\",\"description\":\"The factory reset device basic configuration setup guides you through the basics of setting up your device.\",\"web\":[\"https://en.wikipedia.org/wiki/Mobile_identity_management\"],\"removal\":\"caution\",\"warning\":\"Oddly enough, disabling/uninstalling this package will break mobile identity management which could be used by apps (for example your bank) to authenticate you.\",\"type\":\"google\"},{\"id\":\"com.google.android.setupwizard.a_overlay\",\"label\":\"com.google.android.setupwizard.a_overlay\",\"description\":\"Overlay for setupwizard?\",\"removal\":\"delete\",\"type\":\"google\"},{\"id\":\"com.google.android.soundpicker\",\"label\":\"Google Sounds\",\"description\":\"Removable if you already have another media select service.\",\"removal\":\"replace\",\"type\":\"google\"},{\"id\":\"com.google.android.street\",\"label\":\"Google Street View\",\"description\":\"(Discontinued) Google Street View\",\"removal\":\"delete\",\"type\":\"google\"},{\"id\":\"com.google.android.syncadapters.bookmarks\",\"label\":\"Google Bookmarks Sync\",\"description\":\"Synchronisation for Google Chrome bookmarks\",\"removal\":\"replace\",\"type\":\"google\"},{\"id\":\"com.google.android.syncadapters.calendar\",\"label\":\"Google Calendar Sync\",\"description\":\"Synchronisation for Google Calendar.\",\"removal\":\"replace\",\"type\":\"google\"},{\"id\":\"com.google.android.syncadapters.contacts\",\"label\":\"Google Contacts Sync\",\"description\":\"Synchronisation for Google Contacts.\",\"removal\":\"replace\",\"type\":\"google\"},{\"id\":\"com.google.android.tag\",\"label\":\"Tags\",\"description\":\"Support for NFC tags interactions (5 permissions : Contacts/Phone On by default).\\nNFC Tags are for instance used in bus to let you validate your transport card with your phone\\nOther example: https://en.wikipedia.org/wiki/TecTile\\nYou will still be able to connect to an NFC device (e.g a speaker) if removed.\",\"removal\":\"delete\",\"type\":\"google\"},{\"id\":\"com.google.android.talk\",\"label\":\"Hangouts\",\"description\":\"(Discontinued) Google Hangouts\",\"removal\":\"replace\",\"type\":\"google\"},{\"id\":\"com.google.android.tts\",\"label\":\"Speech Recognition and Synthesis\",\"description\":\"Default Text To Speech (TTS) engine on most of Android devices. It enables apps to convert text into voice.\\nNote: many apps like navigation and health/sport apps rely on a TTS engine to provide speech services.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.google.android.tts\",\"https://beta.pithus.org/report/f0a2303e1c1bd049bf1cdc5a3454dfe19b2aaf26008662c7a307aaec2538558b\"],\"removal\":\"replace\",\"suggestions\":\"tts\",\"type\":\"google\"},{\"id\":\"com.google.android.turboadapter\",\"description\":\"Device Health Services Adapter\\nAnother app for Device Health Services(discontinued)\",\"removal\":\"delete\",\"type\":\"google\"},{\"id\":\"com.google.android.tv.remote\",\"label\":\"Android TV Remote Control\",\"description\":\"(Discontinued) Android TV remote control\",\"removal\":\"delete\",\"type\":\"google\"},{\"id\":\"com.google.android.videoeditor\",\"label\":\"Movie Studio\",\"description\":\"(Discontinued) Google Movie Studio\",\"removal\":\"replace\",\"type\":\"google\"},{\"id\":\"com.google.android.videos\",\"label\":\"Google TV\",\"description\":\"Previously Google Play Movies & TV.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.google.android.videos\"],\"removal\":\"delete\",\"type\":\"google\"},{\"id\":\"com.google.android.voicesearch\",\"label\":\"Voice Search\",\"description\":\"(Discontinued) Google Voice Search (Speech-To-Text)\",\"removal\":\"delete\",\"type\":\"google\"},{\"id\":\"com.google.android.vr.home\",\"label\":\"Daydream\",\"description\":\"VR stuff.\",\"removal\":\"delete\",\"type\":\"google\"},{\"id\":\"com.google.android.vr.inputmethod\",\"label\":\"Daydream Keyboard\",\"description\":\"Daydream virtual keyboard, VR stuff.\",\"removal\":\"delete\",\"type\":\"google\"},{\"id\":\"com.google.android.wearable.app\",\"label\":\"Wear OS\",\"description\":\"Wear OS Smartwatch\",\"web\":[\"https://play.google.com/store/apps/details?id=com.google.android.wearable.app\"],\"removal\":\"delete\",\"type\":\"google\"},{\"id\":\"com.google.android.webview\",\"label\":\"Android System WebView\",\"description\":\"Allows Android apps to display content from the web directly inside the app. Based on Chrome.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.google.android.webview\"],\"removal\":\"replace\",\"warning\":\"Installing a third-party webview requires root.\",\"suggestions\":\"webviews\",\"type\":\"google\"},{\"id\":\"com.google.android.wifi.dialog\",\"description\":\"Wi-Fi dialog. App to launch user dialogs requested by the Wi-Fi service is stored here. Contains the Activity the dialogs are launched from.\\nhttps://source.android.com/docs/core/ota/modular-system/wifi\\nhttps://android.googlesource.com/platform/packages/apps/Settings/+/refs/heads/main/src/com/android/settings/wifi/WifiDialog.java\\nhttps://android.googlesource.com/platform/packages/apps/Settings/+/refs/heads/main/src/com/android/settings/wifi/WifiDialog2.kt\",\"removal\":\"caution\",\"type\":\"google\"},{\"id\":\"com.google.android.wifi.resources\",\"description\":\"Wi-Fi Service Resources. Overlay APK manifest is stored here. Extracts Wi-Fi configs.\\nhttps://source.android.com/docs/core/ota/modular-system/wifi\",\"removal\":\"unsafe\",\"type\":\"google\"},{\"id\":\"com.google.android.youtube\",\"label\":\"YouTube\",\"description\":\"The YouTube app\",\"web\":[\"https://play.google.com/store/apps/details?id=com.google.android.youtube\"],\"removal\":\"replace\",\"suggestions\":\"streaming_apps\",\"type\":\"google\"},{\"id\":\"com.google.ar.core\",\"label\":\"Google Play Services for AR\",\"description\":\"Augmented Reality stuff\",\"web\":[\"https://play.google.com/store/apps/details?id=com.google.ar.core\",\"https://beta.pithus.org/report/99ea324529f950fe351d22724f8b894cce19c16607fcc9c2855bc906b1f8e644\"],\"removal\":\"delete\",\"warning\":\"Disabling it can mess with apps that use it, like Pokemon GO.\",\"type\":\"google\"},{\"id\":\"com.google.ar.lens\",\"label\":\"Google Lens\",\"description\":\"Google Lens (for AR too)\",\"web\":[\"https://play.google.com/store/apps/details?id=com.google.ar.lens\"],\"removal\":\"delete\",\"type\":\"google\"},{\"id\":\"com.google.audio.hearing.visualization.accessibility.scribe\",\"label\":\"Live Transcribe & Notification\",\"description\":\"Provides push notifications for critical sounds around you. This feature can be helpful for people with hearing loss. Works offline\",\"web\":[\"https://play.google.com/store/apps/details?id=com.google.audio.hearing.visualization.accessibility.scribe\",\"https://blog.google/products/android/new-sound-notifications-on-android/\"],\"removal\":\"delete\",\"type\":\"google\"},{\"id\":\"com.google.chromeremotedesktop\",\"label\":\"Chrome Remote Desktop\",\"description\":\"Lets you access your computers from your Android device.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.google.chromeremotedesktop\"],\"removal\":\"delete\",\"type\":\"google\"},{\"id\":\"com.google.earth\",\"label\":\"Google Earth\",\"description\":\"The Google Earth app\",\"web\":[\"https://play.google.com/store/apps/details?id=com.google.earth\"],\"removal\":\"delete\",\"type\":\"google\"},{\"id\":\"com.google.mainline.telemetry\",\"description\":\"Contains data on which versions of modules are installed. Google Play uses this data to determine if updates are available for the modules, and to show which security patch is installed.\\nThis module doesn’t contain active code and has no functionality on its own.\\nAnyway I wont trust it when adservices are also in mainline.\\nhttps://www.xda-developers.com/android-project-mainline-modules-explanation/\\nhttps://gitlab.com/W1nst0n/universal-android-debloater/-/issues/27#note_410012436\",\"removal\":\"replace\",\"type\":\"google\"},{\"id\":\"com.google.marvin.talkback\",\"label\":\"Android Accessibility Suite\",\"description\":\"Helps blind and vision-impaired users. Discontinued and replaced by com.google.android.marvin.talkback\",\"removal\":\"delete\",\"type\":\"google\"},{\"id\":\"com.google.samples.apps.cardboarddemo\",\"label\":\"Cardboard\",\"description\":\"Google Cardboard (VR stuff)\",\"web\":[\"https://play.google.com/store/apps/details?id=com.google.samples.apps.cardboarddemo\"],\"removal\":\"delete\",\"type\":\"google\"},{\"id\":\"com.google.tango.measure\",\"label\":\"Measure\",\"description\":\"(Discontinued) Turn your phone into a tape measure.\",\"removal\":\"delete\",\"type\":\"google\"},{\"id\":\"com.google.vr.cyclops\",\"label\":\"Cardboard Camera\",\"description\":\"(Discontinued) Take photos you can experience in virtual reality—all on your smartphone (VR stuff).\",\"removal\":\"delete\",\"type\":\"google\"},{\"id\":\"com.google.vr.expeditions\",\"label\":\"Expeditions\",\"description\":\"See anything, go anywhere (VR stuff).\",\"removal\":\"delete\",\"type\":\"google\"},{\"id\":\"com.google.vr.vrcore\",\"label\":\"Google VR Services\",\"description\":\"Provides virtual reality functionality for Daydream and Cardboard apps.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.google.vr.vrcore\"],\"removal\":\"delete\",\"type\":\"google\"},{\"id\":\"com.google.zxing.client.android\",\"label\":\"Barcode Scanner\",\"description\":\"Discontinued. This is only an example app for the ZXing library.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.google.zxing.client.android\"],\"removal\":\"replace\",\"suggestions\":\"barcode_scanners\",\"type\":\"google\"},{\"id\":\"air.com.playtika.slotomania\",\"label\":\"Slotomania™ Slots Casino Games\",\"description\":\"Preinstalled game on some Samsung phones.\\nExodus report: 31 permissions, 13 trackers\",\"web\":[\"https://play.google.com/store/apps/details?id=air.com.playtika.slotomania\",\"https://reports.exodus-privacy.eu.org/reports/air.com.playtika.slotomania/latest/\"],\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"cci.usage\",\"label\":\"My Consumer Cellular\",\"description\":\"AKA My CC. Lets you manage your Consumer Cellular account, track your usage, pay your bill.\\nConsumer Cellular is an American postpaid mobile virtual network operator\",\"web\":[\"https://play.google.com/store/apps/details?id=cci.usage\",\"https://en.wikipedia.org/wiki/Consumer_Cellular\"],\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"co.sitic.pp\",\"label\":\"SYSdll\",\"description\":\"Designed to remotely lock the phone (by sending a simple SMS) in case you don't pay your bill \\nThis app was pre-installed on phone not served by that carrier (América Móvil) from South America.\\nNormally you should not have this app anymore because it was removed by Nokia during an Android 10 update.\\n\",\"web\":[\"https://www.reddit.com/r/Android/comments/fde3l6/3rd_party_telemetry_found_in_nokia_smartphones/fjh4zbx/?context=3\"],\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.UCMobile.intl\",\"label\":\"UC Browser\",\"description\":\"Insecure chinese web browser from Alibaba, which is well-known for its privacy & security issues.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.UCMobile.intl\",\"https://citizenlab.ca/2015/05/a-chatty-squirrel-privacy-and-security-issues-with-uc-browser/\",\"https://www.andmp.com/2019/05/advisory-unpatched-url-address-bar-vulnerability-in-latest-versions-of-UC-browers.html\",\"https://www.zscaler.com/blogs/security-research/uc-browser-app-abuses-may-have-exposed-500-million-users\"],\"removal\":\"replace\",\"suggestions\":\"browsers\",\"type\":\"misc\"},{\"id\":\"com.aaa.android.discounts\",\"label\":\"AAA\",\"description\":\"AAA = American Automobile Association\\nKind of GPS that helps you find Point of interest (POI) like hotels, restaurants, and car repair facilities from the AAA databases.\\nNOTE : You’ll have to sign up for an AAA membership to enjoy all of the features and functionality of the Android app.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.aaa.android.discounts\"],\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.aaa.android.discounts.vpl\",\"label\":\"AAA\",\"description\":\"AAA = American Automobile Association\\nKind of GPS that helps you find Point of interest (POI) like hotels, restaurants, and car repair facilities from the AAA databases.\\nNOTE : You’ll have to sign up for an AAA membership to enjoy all of the features and functionality of the Android app.\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.adups.fota\",\"label\":\"Wireless Update\",\"description\":\"(AKA System Update) FOTA = Firmware Over-the-air. Has a history of spying its users. If the installed version is below 5.4.x, it must be uninstalled.\",\"web\":[\"https://www.malwarebytes.com/blog/news/2017/12/mobile-menace-monday-upping-the-ante-on-adups-fwupgradeprovider\",\"https://www.cvedetails.com/vulnerability-list/vendor_id-16034/product_id-35606/year-2017/Adups-Adups-Fota.html\"],\"removal\":\"caution\",\"type\":\"misc\"},{\"id\":\"com.adups.fota.sysoper\",\"label\":\"UpgradeSys\",\"description\":\"FOTA = Firmware Over-the-air. Has a history of spying on its users.\",\"web\":[\"https://www.malwarebytes.com/blog/news/2017/12/mobile-menace-monday-upping-the-ante-on-adups-fwupgradeprovider\",\"https://www.cvedetails.com/vulnerability-list/vendor_id-16034/product_id-35606/year-2017/Adups-Adups-Fota.html\"],\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.agui.toolbox\",\"label\":\"Toolbox\",\"description\":\"Contains a bunch of small utilites, most have there own APP but are only accessible from the Toolbox UI\\nincluded; Noise test, Compass, Flashlight, Bubble Level, Picture Hanging, Heart rate, Measure height,\\nMagnifier,Alarm, Plumb Bob, Protractor, Speedometer & a Pedometer.\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.alibaba.aliexpresshd\",\"description\":\"AliExpress shopping/marketplace.\\nhttps://play.google.com/store/apps/details?id=com.alibaba.aliexpresshd\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.amazon.aa\",\"label\":\"Amazon Assistant\",\"description\":\"A spyware that shows you recommended products available on Amazon and price compare as you shop across the web.\",\"web\":[\"https://www.gadgetguy.com.au/amazon-assistant-spies-on-you/\"],\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.amazon.aa.attribution\",\"label\":\"Amazon Assistant Attribution\",\"description\":\"A spyware again tool that allows sellers to measure the impact of media channels **off Amazon** on sales.\",\"web\":[\"https://www.repricerexpress.com/amazon-attribution/\"],\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.amazon.appmanager\",\"label\":\"Mobile Device Information Provider\",\"description\":\"Maybe related to Kindle\",\"web\":[\"https://forum.xda-developers.com/t/are-these-phones-preloaded-with-amazon-spyware.4260299/\",\"https://www.reddit.com/r/AndroidQuestions/comments/89qy76/what_is_mobile_device_information_provider_app/\"],\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.amazon.avod.thirdpartyclient\",\"label\":\"Amazon Prime Video\",\"description\":\"VOD service from Amazon.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.amazon.avod.thirdpartyclient\",\"nhttps://en.wikipedia.org/wiki/Prime_Video\"],\"removal\":\"replace\",\"suggestions\":\"streaming_apps\",\"type\":\"misc\"},{\"id\":\"com.amazon.clouddrive.photos\",\"label\":\"Amazon Photos\",\"description\":\"Prime members get free prints delivery (US only) and unlimited photo storage (available in US, UK, CA, DE, FR, IT, ES and JP) for a lifetime of memories.\\nNon-Prime members: 5 GB full-resolution photo and video storage.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.amazon.clouddrive.photos\"],\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.amazon.fv\",\"label\":\"Amazon App suite\",\"description\":\"Provides access to Amazon digital content\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.amazon.kindle\",\"label\":\"Amazon Kindle\",\"description\":\"Kindle eBook reader app\",\"web\":[\"https://play.google.com/store/apps/details?id=com.amazon.kindle\"],\"removal\":\"replace\",\"suggestions\":\"ebook_readers\",\"type\":\"misc\"},{\"id\":\"com.amazon.mShop.android\",\"label\":\"Amazon Shopping\",\"description\":\"Shopping app from Amazon\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.amazon.mShop.android.shopping\",\"label\":\"Amazon Shopping\",\"description\":\"Shopping app from Amazon\\nSame package as com.amazon.mShop.android.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.amazon.mShop.android.shopping\"],\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.amazon.mShop.android.shopping.vpl\",\"label\":\"Amazon Shopping\",\"description\":\"Shopping app from Amazon\\nSame package as com.amazon.mShop.android.\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.amazon.mp3\",\"label\":\"Amazon Music\",\"description\":\"Amazon Music streaming app\",\"web\":[\"https://play.google.com/store/apps/details?id=com.amazon.mp3\"],\"removal\":\"replace\",\"suggestions\":\"music_apps\",\"type\":\"misc\"},{\"id\":\"com.amazon.venezia\",\"label\":\"Amazon AppStore\",\"description\":\"AppStore from Amazon\",\"removal\":\"replace\",\"suggestions\":\"app_stores\",\"type\":\"misc\"},{\"id\":\"com.android.ld.appstore\",\"label\":\"LD Gaming Appstore\",\"description\":\"LDPlayer is an Android Gaming emulator for PC (https://ldplayer.net/)\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.applovin.array.apphub.vincere\",\"label\":\"AppHub\",\"description\":\"Is known as tracker company, potentially adware!\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.aspiro.tidal\",\"label\":\"TIDAL Music\",\"description\":\"Tidal Music streaming app\",\"web\":[\"https://play.google.com/store/apps/details?id=com.aspiro.tidal\"],\"removal\":\"replace\",\"suggestions\":\"music_apps\",\"type\":\"misc\"},{\"id\":\"com.aspiro.tidal.vpl\",\"label\":\"TIDAL Music\",\"description\":\"Tidal Music streaming app\",\"removal\":\"replace\",\"suggestions\":\"music_apps\",\"type\":\"misc\"},{\"id\":\"com.audible.application\",\"label\":\"Audible\",\"description\":\"Stream Audible Audiobooks and Podcasts\",\"web\":[\"https://play.google.com/store/apps/details?id=com.audible.application\",\"https://help.audible.com/s/article/audible-privacy-information?language=en_US\"],\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.bleacherreport.android.teamstream\",\"label\":\"Bleacher Report\",\"description\":\"All about Sports News\",\"web\":[\"https://play.google.com/store/apps/details?id=com.bleacherreport.android.teamstream\"],\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.blurb.checkout\",\"label\":\"Blurb Checkout\",\"description\":\"Provides book purchase and checkout for Samsung’s Story Album app (discontinued)\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.booking\",\"label\":\"Booking.com\",\"description\":\"Book hotel or apartment, flights, rental cars, and more\",\"web\":[\"https://play.google.com/store/apps/details?id=com.booking\",\"https://en.wikipedia.org/wiki/Booking.com\",\"https://blog.usejournal.com/why-i-would-never-trust-booking-com-again-so-you-should-too-a2ab535ed915?gi=7ebe86eaa880\",\"https://ro-che.info/articles/2017-09-17-booking-com-manipulation\"],\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.caf.fmradio\",\"label\":\"FM Radio\",\"description\":\"FM Radio app\",\"web\":[\"https://source.codeaurora.org/quic/la/platform/vendor/qcom-opensource/fm/tree/fmapp2/src/com/caf/fmradio\"],\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.cequint.ecid\",\"label\":\"City ID\",\"description\":\"Caller ID from Cequint.\\nNever trust a company which promotes call ID/spam blocking features.\\nCequint was acquired by TNS (https://tnsi.com/)\",\"web\":[\"https://www.cequint.com/\",\"https://www.fiercewireless.com/wireless/t-mobile-to-launch-caller-id-service-from-cequint\",\"https://itmunch.com/robocall-caught-sending-customers-confidential-data-without-consent/\",\"https://www.geekwire.com/2013/earnouts-bad-cequint-execs-sue-parent-company/\"],\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.cnn.mobile.android.phone\",\"label\":\"CNN Breaking US & World News\",\"description\":\"News app from CNN\",\"web\":[\"https://play.google.com/store/apps/details?id=com.cnn.mobile.android.phone\"],\"removal\":\"replace\",\"suggestions\":\"rss_readers\",\"type\":\"misc\"},{\"id\":\"com.contextlogic.wish\",\"label\":\"Wish\",\"description\":\"Wish Shopping\",\"web\":[\"https://play.google.com/store/apps/details?id=com.contextlogic.wish\"],\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.cootek.smartinputv5.language.englishgb\",\"label\":\"TouchPal Keyboard\",\"description\":\"Keyboard app by Cootek a chinese company.\\nAdware (lots and lots of ads)\",\"web\":[\"https://www.buzzfeednews.com/article/craigsilverman/google-banned-cootek-adware\"],\"removal\":\"replace\",\"suggestions\":\"keyboards\",\"type\":\"misc\"},{\"id\":\"com.cootek.smartinputv5.language.spanishus\",\"label\":\"com.cootek.smartinputv5.language.spanishus\",\"description\":\"TouchPal Keyboard by Cootek a chinese company.\\nAdware (lots lots of ads)\",\"web\":[\"https://www.buzzfeednews.com/article/craigsilverman/google-banned-cootek-adware\"],\"removal\":\"replace\",\"suggestions\":\"keyboards\",\"type\":\"misc\"},{\"id\":\"com.crowdcare.agent.k\",\"label\":\"com.crowdcare.agent.k\",\"description\":\"Crowdcare is now Wysdom.AI.\\nFrom their Twitter description : The easiest way for businesses to improve customer satisfaction, contain costs and generate revenue by using #AI to power customer experiences.\\nWysdom.AI has joined the Microsoft Partner Network in 2018\",\"web\":[\"https://wysdom.ai/privacy-policy/\"],\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.debug.loggerui\",\"description\":\"DebugLoggerUI\\nSimilar to logcat, in some sense. Mostly focused on video graphics logging and network logging (includes Bluetooth). On some devices, it runs in the background (working non-cache RAM) even while not in use.\\nhttps://peterelst.com/what-is-debug-logger-ui-android\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.devhd.feedly\",\"label\":\"Feedly\",\"description\":\"Popular news aggregator application (RSS)\",\"web\":[\"https://play.google.com/store/apps/details?id=com.devhd.feedly\",\"https://feedly.com/i/legal/privacy\"],\"removal\":\"replace\",\"suggestions\":\"rss_readers\",\"type\":\"misc\"},{\"id\":\"com.digitalturbine.toolbar\",\"label\":\"Digital Turbine\",\"description\":\"Adware and used by carriers to showcase their apps\\nFYI: Digital Turbine is an advertising company.\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.diotek.sec.lookup.dictionary\",\"label\":\"Samsung Dictionary\",\"description\":\"Samsung dictionary from Diotek (Korean company)\",\"web\":[\"https://en.diotek.com/\"],\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.directv.dvrscheduler\",\"label\":\"DIRECTV on the Go\",\"description\":\"Offical app from DIRECTV (subsidiary of AT&T)\\nLets you watch Live TV, recorded shows, VODs and schedule recordings on your DVR\",\"web\":[\"https://play.google.com/store/apps/details?id=com.directv.dvrscheduler\",\"https://en.wikipedia.org/wiki/DirecTV#Consumer_protection_lawsuits_and_violations\"],\"removal\":\"replace\",\"suggestions\":\"streaming_apps\",\"type\":\"misc\"},{\"id\":\"com.discoveryscreen\",\"label\":\"Appflash\",\"description\":\"Verizon Spyware\",\"web\":[\"https://play.google.com/store/apps/details?id=com.discoveryscreen\",\"https://www.eff.org/deeplinks/2017/04/update-verizons-appflash-pre-installed-spyware-still-spyware\"],\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.disney.disneyplus\",\"label\":\"Disney+\",\"description\":\"Streaming app from Disney and co. (Pixar, Marvel, Star Wars, and National Geographic).\",\"web\":[\"https://play.google.com/store/apps/details?id=com.disney.disneyplus\"],\"removal\":\"replace\",\"suggestions\":\"streaming_apps\",\"type\":\"misc\"},{\"id\":\"com.dna.solitaireapp\",\"label\":\"Solitaire – Classic Card Game\",\"description\":\"Solitaire Game app from DNA company ?\",\"web\":[\"https://play.google.com/store/apps/details?id=com.dna.solitaireapp\"],\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.dolby.daxservice\",\"label\":\"Dolby\",\"description\":\"Runs in the background as part of the system. Runs even if disabled.\\n\\\"Optimizes system audio performance\\\" or something like that. This is likely the backend audio service, possibly applying settings from com.oneplus.sound.tuner (\\\"Dolby Atmos\\\") to the audio processing.\",\"removal\":\"caution\",\"type\":\"misc\"},{\"id\":\"com.draftkings.dknativermgGP.vpl\",\"label\":\"DraftKings - Daily Fantasy Sports for Cash\",\"description\":\"App has been removed from the Playstore.\",\"web\":[\"https://en.wikipedia.org/wiki/DraftKings\"],\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.drivemode\",\"label\":\"DraftKings - Daily Fantasy Sports for Cash\",\"description\":\"App has been removed from the Playstore.\\nDrivemode (https://play.google.com/store/apps/details?id=com.drivemode.android)\\nSimplifies how you manage calls and messages while driving.\",\"web\":[\"https://en.wikipedia.org/wiki/DraftKings\",\"https://drivemode.com/privacy-2/\"],\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.dsi.ant.plugins.antplus\",\"label\":\"ANT+ Plugins Service\",\"description\":\"ANT is a wireless protocol, similar to Bluetooth®, that is predominantly used for sport and fitness wireless connectivity. Pre-installed by the phone manufacturer, this service allows you to connect ANT+ devices to apps on your phone. ANT Wireless is a division of Garmin Canada Inc.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.dsi.ant.plugins.antplus\"],\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.dsi.ant.sample.acquirechannels\",\"label\":\"ANT + DUT\",\"description\":\"I don't know why there is \\\"sample\\\" in the name. Is this package really useful to find ANT channels ? \\n\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.dsi.ant.server\",\"label\":\"ANT Radio Service Test\",\"description\":\"ANT HAL (Hardware Abstraction Layer) Server.\\nANT is a wireless protocol, similar to Bluetooth, that is mainly used for sport and fitness trackers.\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.dsi.ant.service.socket\",\"label\":\"ANT Radio Service\",\"description\":\"ANT is a wireless protocol, similar to Bluetooth, that is mainly used for sport and fitness trackers.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.dsi.ant.service.socket\"],\"removal\":\"replace\",\"type\":\"misc\"},{\"id\":\"com.ebay.carrier\",\"label\":\"com.ebay.carrier\",\"description\":\"Kind of weird ebay apps pre-installed by carriers.\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.ebay.mobile\",\"label\":\"eBay\",\"description\":\"Online shopping and selling app\",\"web\":[\"https://play.google.com/store/apps/details?id=com.ebay.mobile\"],\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.ehernandez.radiolainolvidable\",\"label\":\"Radio La Inolvidable Peru\",\"description\":\"Spanish Radio app (no longer exist)\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.emoji.keyboard.touchpal\",\"label\":\"TouchPal Emoji Keyboard\",\"description\":\"Developed by Cootek a chinese company.\\nAdware (lots and lots of ads)\",\"web\":[\"https://www.buzzfeednews.com/article/craigsilverman/google-banned-cootek-adware\"],\"removal\":\"replace\",\"suggestions\":\"keyboards\",\"type\":\"misc\"},{\"id\":\"com.eterno\",\"label\":\"Dailyhunt\",\"description\":\"Daily hunt news aggregator\",\"web\":[\"https://play.google.com/store/apps/details?id=com.eterno\"],\"removal\":\"replace\",\"suggestions\":\"rss_readers\",\"type\":\"misc\"},{\"id\":\"com.evernote\",\"label\":\"Evernote\",\"description\":\"Popular note taking app\",\"web\":[\"https://play.google.com/store/apps/details?id=com.evernote\",\"https://evernote.com/privacy\",\"https://privacy.commonsense.org/evaluation/evernote\"],\"removal\":\"replace\",\"suggestions\":\"note_taking_apps\",\"type\":\"misc\"},{\"id\":\"com.example\",\"description\":\"Auto Dialer test\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.example.myapplication\",\"description\":\"Hidden app for testing:\\nBattery, WiFi, Bluetooth\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.facebook.appmanager\",\"label\":\"Facebook App Manager\",\"description\":\"Handles Facebook apps updates.\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.facebook.katana\",\"label\":\"Facebook\",\"description\":\"Facebook social media app\",\"web\":[\"https://play.google.com/store/apps/details?id=com.facebook.katana\"],\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.facebook.lite\",\"description\":\"Facebook Lite app (https://play.google.com/store/apps/details?id=com.facebook.lite)\\n\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.facebook.orca\",\"label\":\"Messenger\",\"description\":\"Facebook Messenger\",\"web\":[\"https://play.google.com/store/apps/details?id=com.facebook.orca\"],\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.facebook.services\",\"label\":\"com.facebook.services\",\"description\":\"Facebook Services is a tool that lets you manage different Facebook services automatically using your Android device.\\nIn particular, the tool focuses on searching for nearby shops and establishments based on your interests.\\nI don't know if this a dependency for com.facebook.katana but nobody cares because we all want to delete all the Facebook stuff right ?\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.facebook.system\",\"label\":\"com.facebook.system\",\"description\":\"Facebook App Installer (empty shell app which incites you to install the Facebook app)\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.fet.fridaywallet\",\"description\":\"friDay Wealth Management\\nProvides customized deposit goal progress management services\\nhttps://play.google.com/store/apps/details?id=com.fet.fridaywallet\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.fido.asm\",\"description\":\"FIDO UAF1.0 ASM\\nRelated to app fingerprint unlocking and payments. Safe to remove if you don't use password-less authentication to access online services.\",\"removal\":\"replace\",\"type\":\"misc\"},{\"id\":\"com.fido.uafclient\",\"description\":\"FIDO UAF1.0 Client\\nProbably related to FIDO digital key gadget (Client), probably safe to remove if you don't have any.\",\"removal\":\"replace\",\"type\":\"misc\"},{\"id\":\"com.finshell.fin\",\"label\":\"FinShell Pay\",\"description\":\"Provides various Payment and Financial Services. Pretty bad privacy policy.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.finshell.fin\",\"https://rwallet.finshell.co.in/html/user/privacy_policy.html\"],\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.fintech.life\",\"description\":\"Chinese app that spoofs as a Singapore financial and/or payment app to show advertisement notifications (mostly loans)\\nIt accesses locations, contacts, camera, mic by default, some people in Thailand also reported that they cannot use legitimate regional banking apps until this app was disabled or uninstalled with ADB method. While newer devices that start with Oppo ColorOS 13 and/or Realme UI 4 (around Android 13) are already baked in, it seems likely that it comes with a system update at older devices of those brands, so this is shady and constantly lost trust from many users.\\nhttps://safereddit.com/r/Thailand/comments/1hzdwhr\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.fw.upgrade.sysoper\",\"label\":\"UpgradeSys\",\"description\":\"FOTA = Firmware Over-the-air. Has a history of spying its users.\",\"web\":[\"https://www.malwarebytes.com/blog/news/2017/12/mobile-menace-monday-upping-the-ante-on-adups-fwupgradeprovider\",\"https://www.cvedetails.com/vulnerability-list/vendor_id-16034/product_id-35606/year-2017/Adups-Adups-Fota.html\"],\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.galaxyfirsatlari\",\"label\":\"Galaxy Fırsatları\",\"description\":\"Samsung-only app for Turkish people\\nRecommands you stuff to buy. You are supposed to save money but we all know this kind of apps\\nEncourages consumption.\\nExodus found 10 trackers and 17 permissions\",\"web\":[\"https://play.google.com/store/apps/details?id=com.galaxyfirsatlari\",\"https://reports.exodus-privacy.eu.org/fr/reports/143830/\"],\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.gd.mobicore.pa\",\"label\":\"RootPA\",\"description\":\"Mobicore is now Trustonic\\nTrustonic is a small OS running on the CPU providing a TEE, an isolated environment that runs in parallel with the operating system, guaranteeing code and data loaded inside to be protected.\\nSounds great, but it's closed source and \\\"normal\\\" devs can't use it for their apps.\\nSee \\\"com.trustonic.tuiservice\\\"\",\"removal\":\"caution\",\"type\":\"misc\"},{\"id\":\"com.generalmobi.go2pay\",\"label\":\"Go2Pay\",\"description\":\"Payment app that offers mobile pre-paid recharges and post-paid bill payment, data card recharges and bill payment,\\nDTH (Direct To Home Television) recharges through cashless transactions\",\"web\":[\"https://play.google.com/store/apps/details?id=com.generalmobi.go2pay\"],\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.glance.internet\",\"label\":\"Glance for realme\",\"description\":\"Displays unsolicited \\\"trending\\\" stories on Lockscreen\",\"web\":[\"https://play.google.com/store/apps/details?id=com.glance.internet\"],\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.gohappy.mobileapp\",\"description\":\"Shopping app of friDay\\nhttps://play.google.com/store/apps/details?id=com.gohappy.mobileacom.fetself\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.gotv.nflgamecenter.us.lite\",\"label\":\"NFL\",\"description\":\"NFL related latest news, highlights, stats & more\",\"web\":[\"https://play.google.com/store/apps/details?id=com.gotv.nflgamecenter.us.lite\"],\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.groupon\",\"label\":\"Groupon\",\"description\":\"Online shopping deals and coupons.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.groupon\",\"https://en.wikipedia.org/wiki/Groupon#Reception\"],\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.hancom.office.editor.hidden\",\"label\":\"Hancom Office Editor\",\"description\":\"Legacy Hancom Office Editor (Korean alternative to Microsoft Office). Featured in Samsung and LG phones\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.handmark.expressweather\",\"label\":\"1Weather\",\"description\":\"Forecasts alerts app (contain ads)\",\"web\":[\"https://play.google.com/store/apps/details?id=com.handmark.expressweather\"],\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.handmark.expressweather.vpl\",\"label\":\"1Weather\",\"description\":\"Forecasts alerts app (contain ads)\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.haoba.btsmart\",\"label\":\"com.haoba.btsmart\",\"description\":\"Agui Unibuds\",\"removal\":\"delete\",\"warning\":\"May only be needed if you use Uniherts Ear Buds (Unibuds)\",\"type\":\"misc\"},{\"id\":\"com.haokan.pictorial\",\"description\":\"92 Lock Screen for RealMe\\n92 is pronounce in Chinese as 'Hao Kan' (it's the company name), so it's a Chinese app. This not related to 'Lock Screen Magazine' and potentially inject ads in lock screen.\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.heytap.accessory\",\"label\":\"Quick Connect\",\"dependencies\":[\"com.heytap.mcs\"],\"required_by\":[\"com.oplus.synergy\"],\"description\":\"AKA Accessory Framework\\nQuick device connect feature. Can be disabled via hidden setting (Settings -> Search 'App Enhancement Services' -> Quick device connect) if not wanted.\\nAllows you to search for nearby devices and connect to them without having to go through the Bluetooth or WiFi Direct settings' Ghosh! 32 permissions just for this?\",\"web\":[\"https://beta.pithus.org/report/cc0ba95f0d0867ba6d883275cd2f6c4aa252ebc874f15f1ee240bb5bac330578\"],\"removal\":\"replace\",\"type\":\"misc\"},{\"id\":\"com.huaqin.FM\",\"label\":\"com.huaqin.FM\",\"description\":\"Radio app from huaqin a chinese company\\nNOTE : Transistor [https://f-droid.org/en/packages/org.y20k.transistor/] is much better\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.huaqin.batteryinfo\",\"description\":\"Tests hardware things.\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.huaqin.clearefs\",\"description\":\"Debugging logs Wifi, Bluetooth\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.huaqin.pocketbanreceiver\",\"description\":\"I found in code useless permissions BAN_BROADCAST and hello world!\\nThis app means nothing.\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.huaqin.sarcontroller\",\"description\":\"It have something like sar sensor, idk if it's for testing\\nbut mainactivity have chinese words and sar is for radio regulations?\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.huaqin.shutdownservice\",\"description\":\"ShutdownAfterScreenOff10MinutesService. Not needed\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.hulu.plus\",\"label\":\"Hulu\",\"description\":\"TV shows & movies streaming app.\\nFYI : Hulu is owned by Disney.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.hulu.plus\",\"https://www.digitaltrends.com/home-theater/hulu-vs-disney-plus/\",\"https://en.wikipedia.org/wiki/Hulu\"],\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.idea.questionnare\",\"label\":\"com.idea.questionnare\",\"description\":\"[NEED MORE INFO / NEED APK] Quizz app from MobileIdea company?\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.ideashower.readitlater.pro\",\"label\":\"Pocket\",\"description\":\"Allows you to save an article or web page to remote servers for later reading\\nWas purchased by Mozilla in 2017 but is still close source for now.\\nOpen-source alternative : https://wallabag.org/\",\"web\":[\"https://play.google.com/store/apps/details?id=com.ideashower.readitlater.pro\",\"https://getpocket.com/privacy\",\"https://en.wikipedia.org/wiki/Pocket_(service)\"],\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.imdb.mobile\",\"label\":\"IMDb\",\"description\":\"IMDb mobile app\",\"web\":[\"https://play.google.com/store/apps/details?id=com.imdb.mobile\",\"https://www.imdb.com/privacy\",\"https://en.wikipedia.org/wiki/IMDb\"],\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.infraware.polarisoffice5\",\"label\":\"Polaris Office\",\"description\":\"Polaris Office from US Infraware Inc company (Microsoft Office like)\\nhttps://play.google.com/store/apps/details?id=com.infraware.office.link\",\"web\":[\"https://en.wikipedia.org/wiki/Polaris_Office\"],\"removal\":\"replace\",\"type\":\"misc\"},{\"id\":\"com.instagram.android\",\"label\":\"Instagram\",\"description\":\"nstagram (from Meta) allows you to create and share your photos, stories, reels and videos with the friends and followers\",\"web\":[\"https://play.google.com/store/apps/details?id=com.instagram.android\",\"https://privacycenter.instagram.com/policy/\",\"https://en.wikipedia.org/wiki/Instagram\"],\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.ironsource.appcloud.oobe\",\"label\":\"AppCloud\",\"description\":\"AppCloud (discontinued) from ironSource, an advertising company\",\"web\":[\"https://en.wikipedia.org/wiki/IronSource\"],\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.ironsource.appcloud.oobe.huawei\",\"label\":\"Essential\",\"description\":\"An app that promotes some other apps (and encourages you to install them)\\nDeveloped by IronSource, a \\\"next-generation advertising company\\\" \\nhttps://aura.ironsrc.com/ (app) | https://company.ironsrc.com/ (company)\\nWhen you try to read their privacy policy you arrive to an outstanding blank PDF file!\",\"web\":[\"http://www.ironsrc.com/wp-content/uploads/2019/03/ironSource-Privacy-Policy.pdf\"],\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.ironsoure.appcloud.oobe.wiko\",\"description\":\"Provides first time setup for Wiko mobile\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.king.candycrush4\",\"label\":\"Candy Crush Friends\",\"description\":\"A Candy Crush game (com.king.candycrushsaga) variant app\",\"web\":[\"https://play.google.com/store/apps/details?id=com.king.candycrush4\",\"https://www.king.com/privacyPolicy\",\"https://en.wikipedia.org/wiki/Candy_Crush_Saga\"],\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.king.candycrushsaga\",\"label\":\"Candy Crush Saga\",\"description\":\"Main Candy Crush game app.\\nPre-installed in a lot of phones that helps its popularity\",\"web\":[\"https://play.google.com/store/apps/details?id=com.king.candycrushsaga\",\"https://www.king.com/privacyPolicy\",\"https://en.wikipedia.org/wiki/Candy_Crush_Saga\"],\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.king.candycrushsodasaga\",\"label\":\"Candy Crush Soda\",\"description\":\"A Candy Crush game (com.king.candycrushsaga) variant app\",\"web\":[\"https://play.google.com/store/apps/details?id=com.king.candycrushsodasaga\",\"https://www.king.com/privacyPolicy\",\"https://en.wikipedia.org/wiki/Candy_Crush_Saga\"],\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.kwai.video\",\"label\":\"Kwai\",\"description\":\"Just another one of the useless short video apps. Depending on the phone model, it may not be possible to uninstall properly but safe to disable. (Even disabled it still runs in the background).\",\"web\":[\"https://play.google.com/store/apps/details?id=com.kwai.video\"],\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.linkedin.android\",\"label\":\"Linkedin\",\"description\":\"One of the largest social network apps for online jobs\",\"web\":[\"https://play.google.com/store/apps/details?id=com.linkedin.android\",\"https://en.wikipedia.org/wiki/LinkedIn\"],\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.lookout\",\"label\":\"Lookout\",\"description\":\"Mobile Security & Antivirus by Lookout\",\"web\":[\"https://play.google.com/store/apps/details?id=com.lookout\"],\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.magiear.handsfree.assistant\",\"description\":\"Hands-Free Assistant\\nOnly has permission activity voice from mediatek.\\nhttps://play.google.com/store/apps/details?id=com.magiear.handsfree.assistant\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.mediatek\",\"label\":\"com.mediatek\",\"description\":\"Mediatek is a Taiwanese chipset manufacturer.\\nCan someone share the apk? This package name is really weird.\\nIt is most likely a set of general APIs for accessing general mediatek functionalities.\",\"removal\":\"unsafe\",\"warning\":\"Removing the app will cause bootloop.\",\"type\":\"misc\"},{\"id\":\"com.mediatek.FrameworkResOverlayExt\",\"description\":\"DisplayCutout founded in code.\",\"removal\":\"unsafe\",\"type\":\"misc\"},{\"id\":\"com.mediatek.MtkSettingsResOverlay\",\"description\":\"Nothing found in this app.\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.mediatek.SettingsProviderResOverlay\",\"description\":\"Nothing found in this app.\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.mediatek.aovtestapp\",\"description\":\"It tests in camera something.\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.mediatek.atci.service\",\"description\":\"Well this code is hard to understand, it have only notification stuff and needed for ims wifi calling.\",\"removal\":\"replace\",\"type\":\"misc\"},{\"id\":\"com.mediatek.atmwifimeta\",\"label\":\"ATMWifiMeta\",\"description\":\"wifi data logger you don't want\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.mediatek.autodialer\",\"description\":\"autodialer, have a lot useless code.\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.mediatek.batterywarning\",\"label\":\"com.mediatek.batterywarning\",\"description\":\"Issues warning when the battery is low or when the battery temperature is high.\",\"removal\":\"caution\",\"type\":\"misc\"},{\"id\":\"com.mediatek.bluetooth.dtt\",\"description\":\"Bluetooth logging.\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.mediatek.calendarimporter\",\"label\":\"VCalendar\",\"description\":\"Useful in China where Google isn’t available, but not needed for Google users.\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.mediatek.callrecorder\",\"label\":\"Call Recorder\",\"description\":\"This is not the kind of feature expected from a Soc company.\\nIf you remove this I guess you will not be able to record your calls from the stock dialer\\nCan someone share the apk and verify this?\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.mediatek.camera\",\"label\":\"Camera\",\"description\":\"Stock Camera app on some Mediatek phones.\",\"removal\":\"replace\",\"suggestions\":\"cameras\",\"type\":\"misc\"},{\"id\":\"com.mediatek.capctrl.service\",\"label\":\"RilCap\",\"description\":\"It has mtkradioex components used for corporate device management and telephony control.\",\"removal\":\"unsafe\",\"warning\":\"Removing this package will break key telephony functions, such as SIM detection and carrier configuration, and cause com.android.phone to crash repeatedly.\",\"type\":\"misc\"},{\"id\":\"com.mediatek.carrierexpress\",\"description\":\"Hidden operator configuration. it's Carrier Express app?\\nalso in code there a lot stuff about Custom Operator.\\nI dont know why it should be useful when it only has notifications:\\nSIM card detected or Switching the carrier etc.\\nit's useless.\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.mediatek.cellbroadcastuiresoverlay\",\"description\":\"This app have something to emergency.\",\"removal\":\"replace\",\"type\":\"misc\"},{\"id\":\"com.mediatek.dataprotection\",\"label\":\"Data Protection\",\"description\":\"Possibly related to user partition encryption/decryption.\\nA device should works flawlessly without it.\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.mediatek.duraspeed\",\"description\":\"A frontend to a Mediatek service that fully takes over Android's own Adaptive Battery management. Uninstalling this app will only remove the UI component, but not the system service that it's controlling. To completely disable Duraspeed you need to have it enabled first, open Duraspeed app via Settings, and set the toggle to 'Off'. Otherwise Duraspeed service will continue running despite there not being a Duraspeed entry in Settings which will lead to unexpected app freezes that affect FOSS apps such as Dialers/Phones and messengers.\",\"removal\":\"caution\",\"type\":\"misc\"},{\"id\":\"com.mediatek.emcamera\",\"description\":\"Useless camera calibration hidden app.\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.mediatek.engineermode\",\"label\":\"EngineerMode\",\"description\":\"Engineer mode you can access by dialing a secret code (*#*#3646633#*#* on some Xiaomi phones for instance)\\nIt enables you to access the debug/logged data and some hidden firmware settings.\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.mediatek.entitlement.fcm\",\"description\":\"it's only FCM(Firebase Cloud Messaging). No activities, google firebase. Not needed.\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.mediatek.factorymode\",\"description\":\"Tests hardware things.\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.mediatek.frameworkresoverlay\",\"description\":\"It have something to config AOD.\\nAnd power saving.\",\"removal\":\"unsafe\",\"type\":\"misc\"},{\"id\":\"com.mediatek.gba\",\"description\":\"Generic Bootstrapping Architecture.\\nHas ims, X-TMUS-IMEI, bsf.msg.lab.t-mobile.com things to encrypted calls ims probably\\n(thinking by looking at the classes.dex code). Connects to site bsf.ims.mncXXX.pub.3gppnetwork.org.\",\"removal\":\"caution\",\"type\":\"misc\"},{\"id\":\"com.mediatek.gbaservice\",\"description\":\"Generic Bootstrapping Architecture. A ‘common ground’ of code used for many MediaTek apps.\\nCan be removed if all other MediaTek apps are removed.\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.mediatek.gnss.nonframeworklbs\",\"description\":\"Have hidden activity and it's maybe for debug location requests, modem, VoWiFi and more.\\nNot useful.\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.mediatek.gnssdebugreport\",\"label\":\"GnssDebugReport\",\"description\":\"Hidden debug stuff.\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.mediatek.gpslocationupdate\",\"label\":\"GPSLocationUpdate\",\"description\":\"Info about gps and notifications. Probably not needed for location.\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.mediatek.ims\",\"label\":\"com.mediatek.im\",\"description\":\"Mediatek's implementation of IMS (low-level implementation?)\\nIMS(Ip Multimedia Subsystem) is an open industry standard for voice and multimedia communications over packet-based IP networks (VoLTE/VoIP/Wifi calling).\",\"web\":[\"https://www.programmersought.com/article/50164530665/\"],\"removal\":\"caution\",\"type\":\"misc\"},{\"id\":\"com.mediatek.ims.pco\",\"label\":\"com.mediatek.ims.pco\",\"description\":\"Protocol Configuration Options service for IMS\\nIMS(IP Multimedia Subsystem) is an open industry standard for voice and multimedia communications over packet-based IP networks (VoLTE/VoIP/Wifi calling). This package enable automatic configuration pushed by your carrier.\",\"removal\":\"caution\",\"warning\":\"Maybe needed if you use IMS\",\"type\":\"misc\"},{\"id\":\"com.mediatek.ims.rcsua.service\",\"description\":\"Needed to support IMS, RCS probably.\",\"removal\":\"replace\",\"type\":\"misc\"},{\"id\":\"com.mediatek.lbs.em2.ui\",\"label\":\"LocationEM2\",\"description\":\"Another GPS status/testing app. Removing it doesn’t stop GPS from working.\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.mediatek.location.lppe.main\",\"label\":\"LPPe Service\",\"description\":\"LPPE = LTE Positioning Protocol enhancements/extensions (LTE = \\\"4G\\\")\\nPositioning and assistance protocol between E-SMLC (mobile location center) and UE (User Equipement = phone)\\nI don't know the app has the permission to read SMS\",\"web\":[\"https://www.gpsworld.com/wirelessexpert-advice-positioning-protocol-next-gen-cell-phones-11125/\"],\"removal\":\"caution\",\"type\":\"misc\"},{\"id\":\"com.mediatek.location.mtkgeofence\",\"description\":\"Mtk Geofence\\nOnly logs in code\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.mediatek.location.mtknlp\",\"label\":\"Mtk Nlp\",\"description\":\"Network Location Provider? This app has location permissions and no code.\",\"removal\":\"caution\",\"type\":\"misc\"},{\"id\":\"com.mediatek.magtapp\",\"description\":\"MAGTApp\\nUnknown, has GameEventService, MAGTEventAppReceiver, but code doesn't look very useful.\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.mediatek.mdmconfig\",\"label\":\"MDMConfig\",\"description\":\"Mobile Device Management (MDM) allows company’s IT department to reach inside your phone in the background, allowing them to ensure your device is secure, know where it is, and remotely erase your data if the phone is stolen.\\nIt's a way to ensure employees stay productive and do not breach corporate policies\\nYou should NEVER have a MDM tool on your personal phone. Never.\\nThis package probably isn't a MDM tool on its own but you definitively don't need it on your phone.\\nCan someone share the apk?\",\"web\":[\"https://blog.cdemi.io/never-accept-an-mdm-policy-on-your-personal-phone/\"],\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.mediatek.mdmlsample\",\"label\":\"MDMLSample\",\"description\":\"It looks like debugging app.\\nBut I found some words SUBSCRIBE_TRAP, OTA, VoLTE\\nOther data is a lot of debugging code so it's not needed.\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.mediatek.miravision.ui\",\"label\":\"MiraVision\",\"description\":\"Provides extensive hardware and software optimizations that improve the viewing quality.\\nBUT I think it's not available and it's so bloated.\",\"web\":[\"https://www.mediatek.com/technology/miravision-for-smartphones\"],\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.mediatek.mms.appservice\",\"label\":\"com.mediatek.mms.appservice\",\"description\":\"Provides Voice message, Video message, Fax message, Text message in a messaging app?\",\"removal\":\"caution\",\"type\":\"misc\"},{\"id\":\"com.mediatek.mt6879.gamedriver\",\"description\":\"Mediatek Arm GPU Game Driver\\nGPU Game drivers for Mediatek MT6879CPU.\",\"removal\":\"unsafe\",\"type\":\"misc\"},{\"id\":\"com.mediatek.mt6983.gamedriver\",\"description\":\"Arm GPU Game Driver\",\"removal\":\"unsafe\",\"type\":\"misc\"},{\"id\":\"com.mediatek.mtklogger\",\"label\":\"MTKLogger\",\"description\":\"Logs debug data. Has a lot of permissions and run in background all the time.\\nDon't keep useless apps: reduce the attack surface\\nVulnerability found in this app in 2016\",\"web\":[\"https://nvd.nist.gov/vuln/detail/CVE-2016-10135\"],\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.mediatek.mtklogger.proxy\",\"description\":\"Logs debug data.\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.mediatek.nlpservice\",\"label\":\"Mediatek Network Location Provider\",\"description\":\"Provides periodic reports on the geographical location of the device. Each provider has a set of criteria under which it may be used. For example, some providers require GPS hardware and visibility to a number of satellites, while others require the use of the cellular radio, or access to a specific carrier's network, or to the internet.\\nI don't understand why this is needed; there already is one in 'com.google.android.gms'\\nI wonder if NLP can be replaced by https://github.com/microg/UnifiedNlp\\nI suggest testing if you get a better signal/battery performance with Mediatek NLP on or off.\",\"removal\":\"caution\",\"type\":\"misc\"},{\"id\":\"com.mediatek.omacp\",\"label\":\"Omacp\",\"description\":\"omacp = OMA Client Provisioning. A protocol specified by the Open Mobile Alliance (OMA).\\nConfiguration messages parser. Used for provisioning APN settings to devices via SMS.\\nIn my case, it was automatic and I never needed configuration messages.\\nMaybe it's useful if carriers change their APN. But you can still change the config manually, it's not difficult.\\nDunno why Mediatek handles this kind of things. Safe to remove. At worst, you'll need to manually config your APN.\\nOMACP can be abused.\",\"web\":[\"https://research.checkpoint.com/2019/advanced-sms-phishing-attacks-against-modern-android-based-smartphones/\",\"https://www.zdnet.com/article/samsung-huawei-lg-and-sony-phones-vulnerable-to-rogue-provisioning-messages/\"],\"removal\":\"caution\",\"type\":\"misc\"},{\"id\":\"com.mediatek.presence\",\"description\":\"App used to IMS, RCS. IP Voice Call.\",\"removal\":\"replace\",\"type\":\"misc\"},{\"id\":\"com.mediatek.providers.drm\",\"label\":\"DRM provider\",\"description\":\" It actually Beep Science is MediaTek’s default DRM vendor\\nProbably required for some forms of DRM; disabling might break things like Netflix streaming, which relies on DRM to function.\",\"web\":[\"https://en.wikipedia.org/wiki/Digital_rights_management\"],\"removal\":\"replace\",\"type\":\"misc\"},{\"id\":\"com.mediatek.schpwronoff\",\"description\":\"Set schedule power on & off.\",\"removal\":\"replace\",\"type\":\"misc\"},{\"id\":\"com.mediatek.sensorhub.ui\",\"description\":\"Testing sensors.\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.mediatek.simprocessor\",\"label\":\"com.mediatek.simprocessor\",\"description\":\"This controls and imports contacts saved on a SIM card. Not needed if you don't store your contacts on the SIM card\",\"removal\":\"replace\",\"type\":\"misc\"},{\"id\":\"com.mediatek.smartratswitch.service\",\"description\":\"it handles switching connection between network types. (4G/5G)\",\"removal\":\"caution\",\"type\":\"misc\"},{\"id\":\"com.mediatek.systemuiresoverlay\",\"description\":\"It have nothing in code.\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.mediatek.systemuiwmshellresoverlay\",\"description\":\"config pip_corner_radius only found.\",\"removal\":\"unsafe\",\"type\":\"misc\"},{\"id\":\"com.mediatek.telephony\",\"description\":\"allows you to get information about the available \\nSIMs/subscriptions and listen for changes or activity on the SIM cards, such as call or data activity or \\nconnected cell details. In addition, the API enables apps to create SMS messages and send them using \\na specific SIM card. it's not useful.\",\"removal\":\"replace\",\"type\":\"misc\"},{\"id\":\"com.mediatek.thermalmanager\",\"label\":\"MTK Thermal Manager\",\"description\":\"Hidden testing or logging app.\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.mediatek.voicecommand\",\"description\":\"It's for voice commands like control music playing or voice control for alarm, camera.\\nBut how to get access to it?\\nProbably you need that for voice recognition but not sure.\\nMaybe related to https://www.mediatek.com/products/smart-home/voice-assistant-devices\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.mediatek.voiceunlock\",\"description\":\"It's for voice commands like control music playing or voice control for alarm, camera.\\nBut how to get access to it?\\nProbably you need that for voice recognition but not sure.\\nMaybe related to https://www.mediatek.com/products/smart-home/voice-assistant-devices\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.mediatek.wfo.impl\",\"label\":\"com.mediatek.wfo.impl\",\"description\":\"According to olorin, it's a MediaTek’s default fingerprint app (and he removed it).\\nCan someone confirm what this package does?\\nRemember that any pre-installed apps you don't actually need just increase the surface attack.\\nAny app co-located on the device could modify a system property through an exported interface without proper authorization.\\nVulnerability found in 2019\",\"web\":[\"https://www.olorin.me/2019/09/08/debloating-the-umidigi-f1-play/\",\"https://nvd.nist.gov/vuln/detail/CVE-2019-15368\"],\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.mediatek.ygps\",\"label\":\"YGPS\",\"description\":\"GPS test and bug report utilities, accessed via Engineer Mode. Not needed.\",\"removal\":\"replace\",\"type\":\"misc\"},{\"id\":\"com.mediatek.zramwritebackoverlay\",\"description\":\"config zramWriteback = true. What is this used for?\",\"removal\":\"caution\",\"type\":\"misc\"},{\"id\":\"com.micredit.in\",\"label\":\"Mi Credit\",\"description\":\"App providing loans to MIUI users from India and China\",\"web\":[\"https://play.google.com/store/apps/details?id=com.micredit.in.gp\",\"https://web.archive.org/web/20221207193942/https://onsitego.com/blog/xiaomi-quietly-discontinues-mi-credit-mi-pay-india/\"],\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.microsoft.appmanager\",\"label\":\"Link to Windows\",\"description\":\"Microsoft app for synchronising your phone with a Windows PC.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.microsoft.appmanager\"],\"removal\":\"replace\",\"type\":\"misc\"},{\"id\":\"com.microsoft.office.excel\",\"label\":\"Microsoft Excel\",\"description\":\"Spreadsheets, business collaboration, charts and data analysis tool from Microsoft\",\"web\":[\"https://play.google.com/store/apps/details?id=com.microsoft.office.excel\"],\"removal\":\"replace\",\"type\":\"misc\"},{\"id\":\"com.microsoft.office.officehub\",\"label\":\"Microsoft Office Mobile\",\"description\":\"Includes the complete Word, PowerPoint, and Excel apps to offer a convenient office experience on the go.\",\"removal\":\"replace\",\"type\":\"misc\"},{\"id\":\"com.microsoft.office.officehubhl\",\"label\":\"Office Mobile hub\",\"description\":\"Office Mobile hub (on Samsung Phone)\\nIncludes the complete Word, PowerPoint, and Excel apps to offer a convenient office experience on the go.\",\"removal\":\"replace\",\"type\":\"misc\"},{\"id\":\"com.microsoft.office.officehubrow\",\"label\":\"Microsoft 365 (Office)\",\"description\":\"Word, Excel, PowerPoint, PDF scanner/editor, Cloud services...all in one app\",\"web\":[\"https://play.google.com/store/apps/details?id=com.microsoft.office.officehubrow\"],\"removal\":\"replace\",\"type\":\"misc\"},{\"id\":\"com.microsoft.office.onenote\",\"label\":\"Microsoft OneNote\",\"description\":\"Note taking app from Microsoft.\\nThis app has a lot of permissions. For example it has access to phone state, including the phone number of the device, current cellular network information, the status of any ongoing calls...\",\"web\":[\"https://play.google.com/store/apps/details?id=com.microsoft.office.onenote\"],\"removal\":\"replace\",\"suggestions\":\"note_taking_apps\",\"type\":\"misc\"},{\"id\":\"com.microsoft.office.outlook\",\"label\":\"Microsoft Outlook\",\"description\":\"Microsoft email application\",\"web\":[\"https://play.google.com/store/apps/details?id=com.microsoft.office.outlook\"],\"removal\":\"replace\",\"suggestions\":\"email_clients\",\"type\":\"misc\"},{\"id\":\"com.microsoft.office.powerpoint\",\"label\":\"Microsoft PowerPoint\",\"description\":\"Microsoft presentation and slides app\",\"web\":[\"https://play.google.com/store/apps/details?id=com.microsoft.office.outlook\"],\"removal\":\"replace\",\"type\":\"misc\"},{\"id\":\"com.microsoft.office.word\",\"label\":\"Microsoft Word\",\"description\":\"Create, edit, share microsoft Word documents much like you do on your PC\",\"web\":[\"https://play.google.com/store/apps/details?id=com.microsoft.office.word\"],\"removal\":\"replace\",\"type\":\"misc\"},{\"id\":\"com.microsoft.skydrive\",\"label\":\"Microsoft OneDrive\",\"description\":\"Cloud storage app from Microsoft\",\"web\":[\"https://play.google.com/store/apps/details?id=com.microsoft.skydrive\"],\"removal\":\"replace\",\"suggestions\":\"cloud_services\",\"type\":\"misc\"},{\"id\":\"com.microsoft.translator\",\"label\":\"Microsoft Translator\",\"description\":\"Translate text, voice, conversations, camera photos and screenshots etc with microsoft translator\",\"web\":[\"https://play.google.com/store/apps/details?id=com.microsoft.translator\"],\"removal\":\"replace\",\"suggestions\":\"translators\",\"type\":\"misc\"},{\"id\":\"com.monotype.android.font.applemint\",\"description\":\"Font\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.monotype.android.font.chococooky\",\"label\":\"ChocoEUKor font\",\"description\":\"Font\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.monotype.android.font.cooljazz\",\"label\":\"CoolEUKor font\",\"description\":\"Font\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.monotype.android.font.foundation\",\"label\":\"Foundation font\",\"description\":\"Font\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.monotype.android.font.rosemary\",\"label\":\"RoseEUKor font\",\"description\":\"Font\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.monotype.android.font.tinkerbell\",\"description\":\"Font\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.mtk.telephony\",\"description\":\"SimRecoveryTestTool\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.netflix.mediaclient\",\"label\":\"Netflix\",\"description\":\"Popular TV shows and movies streaming application\",\"web\":[\"https://play.google.com/store/apps/details?id=com.netflix.mediaclient\"],\"removal\":\"replace\",\"suggestions\":\"streaming_apps\",\"type\":\"misc\"},{\"id\":\"com.netflix.partner.activation\",\"label\":\"PartnerNetflixActivation\",\"description\":\"Apk file name: By_3rd_NetflixActivationOverSeas\\nSome form of activation of Netflix account, subscription or app? Might be what puts the Netflix app icon on the homescreen. Not sure.\\nNetflix app works without this.\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.nextradioapp.nextradio\",\"label\":\"NextRadio\",\"description\":\"Adware FM radio\\n3rd-party app which lets you experience live and local FM radio on your smartphone.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.nextradioapp.nextradio\"],\"removal\":\"replace\",\"suggestions\":\"radios\",\"type\":\"misc\"},{\"id\":\"com.niksoftware.snapseed\",\"label\":\"Snapseed\",\"description\":\"Google photo editor\",\"web\":[\"https://play.google.com/store/apps/details?id=com.niksoftware.snapseed\"],\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.nuance.swype.input\",\"label\":\"Swype\",\"description\":\"Swype keyboard by Nuance\",\"web\":[\"https://www.nuance.com/mobile/mobile-applications/swype/android.html\",\"https://en.wikipedia.org/wiki/Swype\"],\"removal\":\"replace\",\"suggestions\":\"keyboards\",\"type\":\"misc\"},{\"id\":\"com.oem.rftoolkit\",\"label\":\"RfToolkit\",\"description\":\"Testing things like Wi-Fi, lots of Chinese words\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.omusic.gPhone\",\"description\":\"friDay music\\nA treasure house of global music, thousands of situational playlists, complete classification of Chinese, Western, Japanese and Korean, classical, and original soundtracks, allowing you to easily travel the digital music world.\\nhttps://play.google.com/store/apps/details?id=com.omusic.gPhone\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.opera.branding\",\"label\":\"Opera Branding Provider\",\"description\":\"Don't know what it really does.\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.opera.branding.news\",\"label\":\"Opera News Branding Provider\",\"description\":\"Don't know what it really does.\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.opera.max.oem\",\"label\":\"Opera Max\",\"description\":\"System-wide data-saving proxy that funnell all app data through Opera’s servers to compress images and videos (discontinued)\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.opera.max.preinstall\",\"label\":\"Opera Max\",\"description\":\"System-wide data-saving proxy that funnell all app data through Opera’s servers to compress images and videos (discontinued)\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.opera.mini.native\",\"label\":\"Opera Mini\",\"description\":\"Tracks your online activities, which are linked to your unique ID.\\nIt has built-in VPN for 'free', which Restore Privacy describe as a 'data collection tool in disguise'.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.opera.mini.native\",\"https://www.opera.com/privacy\",\"https://restoreprivacy.com/vpn/reviews/opera-vpn/\",\"https://privacytests.org/android.html\"],\"removal\":\"replace\",\"suggestions\":\"browsers\",\"type\":\"misc\"},{\"id\":\"com.opera.preinstall\",\"label\":\"Opera Preinstall Data\",\"description\":\"Generates utm tracking stuff\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.opos.cs\",\"label\":\"com.opos.cs\",\"description\":\"Hot Apps\\nGenerate app folders on home screen that recommended sponsored apps and games.\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.pandora.android\",\"label\":\"Pandora\",\"description\":\"Very intrusive music and podcasts app.\\nExodus report: 17 permissions and 14 trackers\",\"web\":[\"https://play.google.com/store/apps/details?id=com.pandora.android\",\"https://reports.exodus-privacy.eu.org/reports/com.pandora.android/latest/\"],\"removal\":\"replace\",\"suggestions\":\"music_apps\",\"type\":\"misc\"},{\"id\":\"com.particlenews.newsbreak\",\"label\":\"NewsBreak\",\"description\":\"News provided by NewsBreak (https://www.newsbreak.com/)\",\"web\":[\"https://play.google.com/store/apps/details?id=com.particlenews.newsbreak\",\"https://reports.exodus-privacy.eu.org/en/reports/com.particlenews.newsbreak/latest/\"],\"removal\":\"replace\",\"suggestions\":\"rss_readers\",\"type\":\"misc\"},{\"id\":\"com.phonepe.app\",\"label\":\"PhonePe\",\"description\":\"PhonePe is a payment app that allows indian users to use BHIM UPI, your credit card and debit card or wallet to recharge your mobile phone.\\nPay your utility bills and also make instant payments at offline and online stores.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.phonepe.app\",\"https://en.wikipedia.org/wiki/PhonePe\"],\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.pinsight.dw\",\"label\":\"App Stack\",\"description\":\"Force-installed app by Sprint. Pinsight is an advertising company\\nNote: Sprint sold Pinsight to InMobi in 2018.\",\"web\":[\"https://pinsightmedia.com/\",\"https://www.fiercewireless.com/wireless/sprint-sells-mobile-ad-biz-pinsight-media-to-inmobi\"],\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.pinsight.v1\",\"label\":\"com.pinsight.v1\",\"description\":\"App Spotlight\\nMakes you discover new apps from the Google Play store. The selection criteria is unknown.\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.pivotmobile.android.metrics\",\"label\":\"com.pivotmobile.android.metrics\",\"description\":\"Pivot Mobile is a popular game developer famously known for its Swimmy Turtle game.\\nSub-downloaded by third-party apps; used for 'data consumption & ad' tracking.\\nCommonly found in Lenovo & Motorola devices.\",\"web\":[\"https://howtofixapp.com/com-pivotmobile-android-metrics/\",\"https://basicknowledgehub.com/com-pivotmobile-android-metrics/\",\"https://beta.pithus.org/report/dd41b027c2999fb9d5b023e4171c238b6f0b9edfb9087703e9d64c3f6148530d\"],\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.playphone.gamestore\",\"label\":\"com.playphone.gamestore\",\"description\":\"Playphone Gamestore (https://www.playphone.com/)\\n\\\"Helps\\\" you discover the \\\"best\\\" Android games and connects you to a global gaming community. Sounds Amazing !\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.playphone.gamestore.loot\",\"label\":\"com.playphone.gamestore.loot\",\"description\":\"Loot \\nPremium service from playphone ?\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.pure.indosat.care\",\"label\":\"myIM3\",\"description\":\"App provided by Indosat Ooredoo, an Internet provider from Indonesia.\\nEnables Indosat users to manage prepaid and postpaid numbers and check their credit and payments, purchase data packs, calls, SMS...\",\"web\":[\"https://play.google.com/store/apps/details?id=com.pure.indosat.care\"],\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.qti.confuridialer\",\"label\":\"Conference URI dialer\",\"description\":\"Conference call service for digital signal (SIP/VoIP).\\nIt's hidden and no apps use it.\",\"removal\":\"replace\",\"type\":\"misc\"},{\"id\":\"com.qti.dcf\",\"description\":\"I found only: DCF Allows an application to share content using Bluetooth.\\nThe application is only allowed to broadcast the content as it already has access to remote devices. These things are not available for users.\\nQualcomm only said these things, but where is the code?\\nThis app is without code so it's safe to remove.\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.qti.diagservices\",\"label\":\"com.qti.diagservices\",\"description\":\"Starts process when plugged into a PC (with debugging on, haven't tried off) and then runs until stopped.\\nDiagnostic services Presumably tests to collect hardware data.\\nsize of this package is 12 KB and have Diag_OnBoot, QTIDiagServices.\\nHas permission: RECEIVE_BOOT_COMPLETED.\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.qti.dpmserviceapp\",\"label\":\"com.qti.dpmserviceapp\",\"description\":\"Data Power Manager for the radio?\\nUsed to improve energy efficiency?\\nIn code I found something like this:\\ndpm hal server, read procid\\nit's still unknown.\",\"removal\":\"caution\",\"type\":\"misc\"},{\"id\":\"com.qti.ltebc\",\"label\":\"LTE Broadcast Manager\",\"description\":\"Runs on boot, but not in the background beyond that.\",\"removal\":\"caution\",\"type\":\"misc\"},{\"id\":\"com.qti.pasrservice\",\"description\":\"Has powersaving things, device idle mode changer to screen on/off.\",\"removal\":\"caution\",\"type\":\"misc\"},{\"id\":\"com.qti.phone\",\"description\":\"dialer, dialing service, for phone calls.\\nHas IMS things, optimizations?, its weird that calling works after remove, has code related to 'com.qualcomm.qcrilmsgtunnel',\\nChina Mobile Communications Corporation(China Mobile) SIM card things.\",\"removal\":\"caution\",\"type\":\"misc\"},{\"id\":\"com.qti.powermodule\",\"description\":\"it's for powersaving? have more debugging stuff than powersaving.\",\"removal\":\"caution\",\"type\":\"misc\"},{\"id\":\"com.qti.qcc\",\"description\":\"QCC\\nHave a lot of stuff about logs, testing framework for Android with Robolectric, LTE Broadcast.\\nIntroduced in android 13.\\nHave png file qdma = Qualcomm Device Management and Analytics.\\nSo it's only spyware.\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.qti.qualcomm.datastatusnotification\",\"label\":\"com.qti.qualcomm.datastatusnotification\",\"description\":\"Sends you a message when you reach a specified data limit?\\nContains a service, but I've never it run. But I've also never run out of data or used the Android data warning system.\",\"web\":[\"https://www.qualcomm.com/news/onq/2016/05/02/qualcomm-trupalette-brings-your-phones-display-life\"],\"removal\":\"caution\",\"warning\":\"On HyperOS, disabling this package results in the mobile networks section to break as well as SIMs showing no service.\",\"type\":\"misc\"},{\"id\":\"com.qti.qualcomm.deviceinfo\",\"label\":\"Device Info\",\"description\":\"Hidden device info activity not available for users.\\nIt's safe to remove and you will not loose device info in settings.\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.qti.qualcomm.mstatssystemservice\",\"description\":\"Useless network statistics, package usage.\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.qti.service.colorservice\",\"label\":\"com.qti.service.colorservice\",\"description\":\"Allows the application to directly affect the device's display paramter.\\nAFAIK no apps use it.\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.qti.slaservice\",\"description\":\"Service Level Agreement (SLA) protocol that analyzes network performance, quality of service, \\nand provides users with various parameters of network quality of service, \\nsuch as: jitter delay, file transfer rate, TCP latency. BUT it's placebo.\\nuses permission com.miui.analytics.onetrack.TRACK_EVENT also have a lot chinese stuff.\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.qti.snapdragon.qdcm_ff\",\"label\":\"QDCM-FF\",\"description\":\"Qualcomm Display Color Management tool\\nAttempts to \\\"make colors look vibrant and true to life\\\". No idea if it actually does something useful or if it's only some garbage dynamic color tuning (they tend to destroy colors).\\nContains a service, but I've never seen it run on my Oneplus 9. Could be tied to color \\\"improvement\\\" settings in Settings->Display (all of which are off for me).\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.qti.xdivert\",\"label\":\"Smart-Divert\",\"description\":\"If enabled, diverts your calls to another number.\\nYou can choose to divert all calls, divert on no reply or divert when the line is busy.\\nWhere can you enable/disable this feature?\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.qualcomm.atfwd\",\"label\":\"com.qualcomm.atfwd\",\"description\":\"Used to send AT command messages from/to the modem\\nAttention commands commands are a collection of short-string commands developed in the early 1980s \\nthat were designed to be transmitted via phone lines and control modems. Different AT command strings can be merged together \\nto tell a modem to dial, hang up, or change connection parameters. \\nSmartphones include a basic modem component inside them, which allows the smartphone to connect to the Internet \\nvia its telephony function.\\nThis can be abused. It's been known for many years that Android devices are vulnerable to attacks carried out via AT commands.\",\"web\":[\"https://www.bleepingcomputer.com/news/security/smartphones-from-11-oems-vulnerable-to-attacks-via-hidden-at-commands/\"],\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.qualcomm.atfwd2\",\"description\":\"This is the same app as the 'com.qualcomm.atfwd'.\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.qualcomm.cabl\",\"label\":\"Content Adaptive Backlight Settings\",\"description\":\"This app will try to adjust the image being displaye by changing the contrast/quality/image backlight depending on \\nthe content on the screen.\\nDownside to this is loss of dynamic range which results in some colors being washed out/clipped.\\nCABL != Auto brightness (which doesn't change the content of the screen, only the brightness)\\nNOTE: You may want to remove this. It does not work very well on many phones.\",\"web\":[\"https://mobileinternist.com/disable-adaptive-brightness-android\"],\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.qualcomm.embms\",\"label\":\"com.qualcomm.embms\",\"description\":\"Runs on boot, but not in the background beyond that?\\nAdds support for eMBMS(evolved Multimedia Broadcast Multicast Service), also known as: LTE Broadcast\\nEnables carriers to send content using multicast/broadcast (same content to many users at the same time) instead of unicast(to a single user).\\nIt's a more efficient use of network resources compared to users receiving the same content individually.\\nProbably safe to disable if you don't care about multi/broad-casts.\",\"web\":[\"https://en.wikipedia.org/wiki/Multimedia_Broadcast_Multicast_Service\"],\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.qualcomm.fastdormancy\",\"label\":\"com.qualcomm.fastdormancy\",\"description\":\"Provide Fast Dormancy feature/setting in the dialer (reduce battery consumption and network utilization during periods of data inactivity)\",\"web\":[\"https://en.wikipedia.org/wiki/Fast_Dormancy\"],\"removal\":\"replace\",\"type\":\"misc\"},{\"id\":\"com.qualcomm.location\",\"label\":\"LocationServices\",\"description\":\"Runs in the background as part of the system. Runs even if disabled, so probably pointless to disable.\\nPeriodically sends a unique software ID, location (lat, long, alt, and their uncertainty), nearby cellular towers and Wi-Fi hotspots and their signal strength to Qualcomm servers.\",\"web\":[\"https://www.qualcomm.com/site/privacy/services\"],\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.qualcomm.location.XT\",\"description\":\"Qualcomm IZat. it's hidden XT Activity. Location for Qualcomm. It's a bad idea to keep it.\\nPeriodically sends a unique software ID, location (lat, long, alt, and their uncertainty), nearby cellular towers and Wi-Fi hotspots and their signal strength to Qualcomm servers.\\nhttps://www.qualcomm.com/site/privacy/services\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.qualcomm.location.XT.setup\",\"description\":\"Qualcomm IZat\\nIts hidden Setup XT location for Qualcomm. It's a bad idea to keep it.\\nPeriodically sends a unique software ID, location (lat, long, alt, and their uncertainty), nearby cellular towers and Wi-Fi hotspots and their signal strength to Qualcomm servers.\\nhttps://www.qualcomm.com/site/privacy/services\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.qualcomm.qcom_qmi\",\"description\":\"qchat logo png founded also Hello World! and app_name Qchat_QMI\\nthis app has no code and no activities so safe to remove.\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.qualcomm.qcrilmsgtunnel\",\"label\":\"com.qualcomm.qcrilmsgtunnel\",\"description\":\"Message receiving channel (secondary card can't turn on 5g).\\nIf you don't use dual-sim it's safe to remove.\",\"removal\":\"caution\",\"warning\":\"Breaks calls after a reboot on some phones\",\"type\":\"misc\"},{\"id\":\"com.qualcomm.qti.accesscache\",\"description\":\"CarrierAccessCacheService\\nWell it's only name app and no code.\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.qualcomm.qti.auth.fidocryptoservice\",\"label\":\"FidoCryptoService\",\"description\":\"Qualcomm FIDO implementation.\\nFido is a set of open technical specifications for mechanisms of authenticating users to online services that do not depend on passwords.\",\"web\":[\"https://en.wikipedia.org/wiki/FIDO_Alliance\",\"https://fidoalliance.org/specs/u2f-specs-1.0-bt-nfc-id-amendment/fido-glossary.html\",\"https://fidoalliance.org/specs/fido-v2.0-rd-20170927/fido-overview-v2.0-rd-20170927.html\"],\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.qualcomm.qti.auth.sampleauthenticatorservice\",\"description\":\"it's only Sample,\\nnothing important found in the code\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.qualcomm.qti.auth.sampleextauthservice\",\"description\":\"it's only Sample,\\nnothing important found in the code\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.qualcomm.qti.auth.secureextauthservice\",\"description\":\"it's only Sample,\\nnothing important found in the code\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.qualcomm.qti.auth.securesampleauthservice\",\"description\":\"it's only Sample,\\nnothing important found in the code\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.qualcomm.qti.autoregistration\",\"label\":\"com.qualcomm.qti.autoregistration\",\"description\":\"Collects device activation data to remotely activate phone warranty.\\nIn 2019 this package sent private data (IMEI, CELLID, CCID) in clear-text to zzhc.vnet.cn (chinese server). According to HMD (Nokia) it was a mistake.\",\"web\":[\"https://www.androidauthority.com/nokia-7-plus-user-info-967901/\"],\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.qualcomm.qti.biometrics.fingerprint.service\",\"label\":\"com.qualcomm.qti.biometrics.fingerprint.service\",\"description\":\"Fingerprint authentication not used by any app, maybe only china.\\nTests temperature, debug, logs, fingerprint biometrics.\",\"removal\":\"caution\",\"type\":\"misc\"},{\"id\":\"com.qualcomm.qti.callenhancement\",\"label\":\"CallEnhancement\",\"description\":\"Supposed to enhance call quality (I'll let you test if it really does)\\nThis can record your phone calls. A vulnerability was found in 2019, allowing unauthorized microphone audio recording by 3rd-party apps.\",\"web\":[\"https://nvd.nist.gov/vuln/detail/CVE-2019-15472\"],\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.qualcomm.qti.callfeaturessetting\",\"label\":\"CallFeatureSetting\",\"description\":\"Hidden call forwarding, call waiting settings. Not available for users.\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.qualcomm.qti.cne\",\"label\":\"CneApp\",\"description\":\"Connectivity Engine that runs in the background as part of the System.\\nEnables seamless hand-off between mobile data and Wi-Fi networks. Can also dynamically measure network performance to prioritize using the best one (I think that's part of \\\"Intelligently select the best Wi-Fi\\\" in settings).\\nProbably worth keeping on; I noticed connection reliability getting worse when I disabled it.\",\"web\":[\"https://www.qualcomm.com/news/onq/2013/07/02/qualcomms-cne-bringing-smarts-3g4g-wi-fi-seamless-interworking\",\"https://programmersought.com/article/35091829299/\"],\"removal\":\"caution\",\"type\":\"misc\"},{\"id\":\"com.qualcomm.qti.confdialer\",\"label\":\"ConfDialer\",\"description\":\"LTE Conferencing Service.\",\"removal\":\"caution\",\"type\":\"misc\"},{\"id\":\"com.qualcomm.qti.devicestatisticsservice\",\"label\":\"com.qualcomm.qti.devicestatisticsservice\",\"description\":\"Device statistics service Statistics of the phone's usage: data, Wifi, battery, the use of various software, number of SMS and emails sent, etc.\\nIt's not very useful, can be removed.\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.qualcomm.qti.dynamicddsservice\",\"label\":\"com.qualcomm.qti.dynamicddsservice\",\"description\":\"Dynamic DDS Service\\nDDS = Direct Digital Synthesizer. Supposedly useful for testing, communication and frequency sweep applications. Some apps may use this for local communication between devices? I'm guessing this is related to sending data through audio(a bunch of rapid beeps outside of the range of human hearing), which I believe Google Home used(still uses?) at one point as an option to connect to a Chromecast.\",\"web\":[\"https://www.qualcomm.com/news/releases/1996/05/07/qualcomm-introduces-new-high-speed-dual-direct-digital-synthesizer\",\"https://www.allaboutcircuits.com/technical-articles/direct-digital-synthesis/\"],\"removal\":\"caution\",\"type\":\"misc\"},{\"id\":\"com.qualcomm.qti.gpudrivers.kalama.api33\",\"description\":\"Adreno Graphics Drivers\",\"removal\":\"unsafe\",\"type\":\"misc\"},{\"id\":\"com.qualcomm.qti.gpudrivers.kona.api30\",\"description\":\"Adreno Graphics Drivers\\nGPU drivers for Snapdragon 865 and 870.\",\"removal\":\"unsafe\",\"type\":\"misc\"},{\"id\":\"com.qualcomm.qti.gpudrivers.lahaina.api30\",\"description\":\"Adreno Graphics Drivers\\nGPU drivers for Snapdragon 888.\",\"removal\":\"unsafe\",\"type\":\"misc\"},{\"id\":\"com.qualcomm.qti.gpudrivers.lito.api30\",\"description\":\"Adreno Graphics Drivers\\nGPU drivers for Snapdragon 765G.\",\"removal\":\"unsafe\",\"type\":\"misc\"},{\"id\":\"com.qualcomm.qti.gpudrivers.sm6150.api30\",\"description\":\"Adreno Graphics Drivers\\nGPU drivers for Snapdragon 675.\\nBut actually I have Snapdragon 732G\\nit's weird but keep it.\",\"removal\":\"unsafe\",\"type\":\"misc\"},{\"id\":\"com.qualcomm.qti.gpudrivers.taro.api31\",\"description\":\"Adreno Graphics Drivers\\nGPU drivers\",\"removal\":\"unsafe\",\"type\":\"misc\"},{\"id\":\"com.qualcomm.qti.improvetouch.service\",\"label\":\"com.qualcomm.qti.improvetouch.service\",\"description\":\"A improve touch things was found in the code, but it is not available to users, only to developers.\\nThe size of the app is 36.40 KB, so why would this improve touch?\\nThis app does not exist on some xiaomi phones, and the touch works the same.\",\"removal\":\"caution\",\"type\":\"misc\"},{\"id\":\"com.qualcomm.qti.ims\",\"label\":\"com.qualcomm.qti.ims\",\"description\":\"Hidden IMS Settings activity not available for users.\\nIn this app, you can only turn on this option: Auto reject incoming calls.\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.qualcomm.qti.loadcarrier\",\"description\":\"CarrierLoadService\\nHave only things like a: Find carrier, carrier switch.\\nit's useless.\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.qualcomm.qti.lpa\",\"label\":\"com.qualcomm.qti.lpa\",\"description\":\"lpa = Local Profile Assistants\\nRuns on boot, but not in the background beyond that.\\nCode has a lot of references to UIM(User Identity Module, which is SIM-related)\\nOnly useful if you use an eSIM? (electronic SIM)\\nAllows users to choose and change their subscription data when switching between network operators/carriers.\",\"web\":[\"https://developer.qualcomm.com/blog/rise-esims-and-isims-and-their-impact-iot\\nhttps://source.android.com/devices/tech/connect/esim-overview\"],\"removal\":\"replace\",\"type\":\"misc\"},{\"id\":\"com.qualcomm.qti.modemtestmode\",\"description\":\"Modem test\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.qualcomm.qti.networksetting\",\"label\":\"Network operators\",\"description\":\"A hidden settings menu that lets you select network modes like GSM only, WCDMA only, LTE only etc, toggle VoLTE On/Off...\",\"removal\":\"caution\",\"type\":\"misc\"},{\"id\":\"com.qualcomm.qti.optinoverlay\",\"label\":\"com.qualcomm.qti.optinoverlay\",\"description\":\"Useless frameworks for com.qualcomm.location.XT it's probably dialogues.\\nAnyway it's only legal notices.\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.qualcomm.qti.perfdump\",\"label\":\"Perfdump\",\"description\":\"Performance dump (logging)\\nEnable a more accurate overview of the running services (and maybe how much power/RAM they take?)\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.qualcomm.qti.performancemode\",\"label\":\"Performance Mode\",\"description\":\"Hidden Performance Mode activity not available for users.\\nIt's on Xiaomi, OnePlus.\\nRemoval does not brick performance mode.\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.qualcomm.qti.poweroffalarm\",\"label\":\"PowerOffAlarm\",\"description\":\"Probably what enables alarms to start the device from an off state.\\nRuns on boot and when you open a clock app.\",\"removal\":\"caution\",\"type\":\"misc\"},{\"id\":\"com.qualcomm.qti.powersavemode\",\"description\":\"It have hidden power saving modes.\\nUsers cant use it.\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.qualcomm.qti.qccauthmgr\",\"label\":\"QCC-AUTHMGR\",\"description\":\"It has something to with (com.qualcomm.qti.smq).\\nFeedback stuff, something about key: blacklist, download or whatever. All of them look like telemetry, and it's all not available for users.\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.qualcomm.qti.qccnetstat\",\"description\":\"useless network statistics also QCC in name qualcomm app is for analytics.\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.qualcomm.qti.qcolor\",\"label\":\"QColor\",\"description\":\"QTI enhanced color mode? I found a png file, color service, it's not needed for any apps.\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.qualcomm.qti.qcom_accesslogkit\",\"description\":\"Theres nothing about logs. I only found in receivers (c Broadcast Receiver)\\nand some useless png, text files. Useless.\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.qualcomm.qti.qdcmtpg\",\"description\":\"layout but not sure for what. a lot useless code, and internet permission\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.qualcomm.qti.qdma\",\"label\":\"QDMA\",\"description\":\"QDMA = Qualcomm Device Management and Analytics.\\nA lot of data collections: logs, dropbox, network.\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.qualcomm.qti.qmmi\",\"label\":\"QMMI\",\"description\":\"QMMI is a test app made by Qualcomm. It is used by service center to test the working of the various device components.\",\"web\":[\"https://community.phones.nokia.com/discussion/52566/android-10-on-nokia-8-1/p19\\nUseless for end-users.\"],\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.qualcomm.qti.qms.service.connectionsecurity\",\"label\":\"com.qualcomm.qti.qms.service.connectionsecurity\",\"description\":\"Telemetry service\\nqms = quality management service\\nBackground-Connection to tls.telemetry.swe.quicinc.com (Host/Domain belongs to Qualcomm)\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.qualcomm.qti.qms.service.credentials\",\"description\":\"QMS = Quality Management Service. In code I found logs and QMS spying things.\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.qualcomm.qti.qms.service.telemetry\",\"label\":\"Qualcomm Mobile Security\",\"description\":\"Telemetry service. Obviously phones to Qualcomm.\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.qualcomm.qti.qms.service.trustzoneaccess\",\"description\":\"QMS always spying. Trust Zone in this app means nothing more than logs.\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.qualcomm.qti.qtisettings\",\"label\":\"com.qualcomm.qti.qtisettings\",\"description\":\"In code found getting info about device Ram Size, Rom Size, get Wifi Mac Address, is Settings Task Done.\\nAlso in app found qtisystemservice code.\\nIt looks like the app is for developers only, so it may be removed.\",\"removal\":\"caution\",\"type\":\"misc\"},{\"id\":\"com.qualcomm.qti.qtisystemservice\",\"label\":\"com.qualcomm.qti.qtisystemservice\",\"description\":\"Seems to only log stuff related to telephony?\\nA user removed this without noticing any issues.\",\"removal\":\"replace\",\"type\":\"misc\"},{\"id\":\"com.qualcomm.qti.qwes.AndroidService\",\"description\":\"qms, qwes it's used for collecting user data.\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.qualcomm.qti.rcsimsbootstraputil\",\"label\":\"com.qualcomm.qti.rcsimsbootstraputil\",\"description\":\"RCS Service\\nRCS = Rich Communication Services.\\nRCS is a communication protocol between mobile telephone carriers and between phone and carrier, aiming at replacing SMS.\\nUses IP protocol so it needs an internet connection.\\nIt's a hot mess right now. It aims at being universal but only exists in Samsung Messages and Google Messages, because Google hasn't released a public API yet, so 3rd-party apps can't support it.\\nIn a lot of countries messages go through Google's Jibe servers.\\nCan anybody check if this is needed for VolTE/VoWifi?\",\"web\":[\"https://en.wikipedia.org/wiki/Rich_Communication_Services\",\"https://jibe.google.com/policies/terms/\",\"https://pocketnow.com/why-you-should-probably-avoid-googles-rcs-text-messaging-chat-feature\"],\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.qualcomm.qti.remoteSimlockAuth\",\"label\":\"com.qualcomm.qti.remoteSimlockAuth\",\"description\":\"Enable you to lock/unlock your eSIM remotely.\\nSeems more of a security risk to me than anything else.\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.qualcomm.qti.ridemodeaudio\",\"description\":\"Ridemode Recording list\\nHidden app, not available for users that should be the audio playback of the drive mode.\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.qualcomm.qti.roamingsettings\",\"label\":\"Roaming Settings\",\"description\":\"Hidden settings menu for tweaking roaming settings? How exactly do you access this menu?\",\"removal\":\"caution\",\"type\":\"misc\"},{\"id\":\"com.qualcomm.qti.seccamservice\",\"label\":\"SecCamService\",\"description\":\"Only collects data about camera.\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.qualcomm.qti.seemp.service\",\"description\":\"Useless code and it's probably to verify packages.\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.qualcomm.qti.server.qtiwifi\",\"description\":\"it's made for analytics.\\nThis service can be used to have oem specific feature development. \\nCurrently this service is being used to collect CSI data from cfrtool \\nvia hidl and then pass the data to application(user level).\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.qualcomm.qti.server.wigig.tethering.rro\",\"description\":\"Only found dhcp range? Only the specified lists were found: 192.168. ...\\nIt have a lot random of this.\\nLooks very unused.\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.qualcomm.qti.services.secureui\",\"label\":\"Secure UI Service\",\"description\":\"It collects your data about screen:gravity, orientation, id, layout_width.\\nIt has a Wifi Display Service. QC_WFD\\nDoes not run in the background.\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.qualcomm.qti.services.systemhelper\",\"label\":\"System Helper Service\",\"description\":\"Runs \\\"SysHelperService\\\" in the background as part of the system.\\nPermissions: DEVICE_POWER, READ_PHONE_STATE, READ_PRIVILEGED_PHONE_STATE, RECEIVE_BOOT_COMPLETED, WRITE_SETTINGS, WAKE_LOCK and ACCESS_SURFACE_FLINGER.\\nAndroid simple network firewall utility service. On a RedMi Note 13 running HyperOS 2.6.0, no application is running after uninstalling this package.\",\"removal\":\"caution\",\"type\":\"misc\"},{\"id\":\"com.qualcomm.qti.simcontacts\",\"label\":\"SimContacts\",\"description\":\"Hidden Qualcomm sim contacts editor app.\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.qualcomm.qti.simsettings\",\"label\":\"com.qualcomm.qti.simsettings\",\"description\":\"Related to SIM settings? Exact nature is unclear.\",\"removal\":\"caution\",\"type\":\"misc\"},{\"id\":\"com.qualcomm.qti.smcinvokepkgmgr\",\"description\":\"This app have nothing.\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.qualcomm.qti.smq\",\"label\":\"com.qualcomm.qti.smq\",\"description\":\"QTR (Qualcomm Technology Reporting)\\nRuns on boot.\\nSeems like a telemetry package, supposedly sending hardware & software type, configuration and performance data.\\nContains a \\\"QtiFeedbackActivity\\\" called \\\"Hardware Feedback\\\". When that hidden activity is launched through Activity Launcher you get a screen showing just a checkbox and this text:\\n\\\"Collecting hardware and software type, configuration, and performance data helps Qualcomm improve next generation device battery life, security, and performance. Untick to disable.\\\"\\nUnticking isn't remembered; it's ticked again next time you enter. There's also a \\\"Learn More\\\" link that leads to: http://reporting.qti.qualcomm.com/learnmore_en.html which doesn't load for me.\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.qualcomm.qti.telephony.vodafonepack\",\"label\":\"com.qualcomm.qti.telephony.vodafonepack\",\"description\":\"Related to Vodafone Prepaid Recharge Plan\\nIf you're not a Vodafone client but still has this package on your phone you can delete it.\\nFor Vodafone client, I don't know what this package does.\",\"web\":[\"https://en.wikipedia.org/wiki/Vodafone\"],\"removal\":\"caution\",\"type\":\"misc\"},{\"id\":\"com.qualcomm.qti.telephonyservice\",\"description\":\"Sound processing during phonecalls.\\nRuns in the background.\\nVital package for making calls.\",\"removal\":\"unsafe\",\"type\":\"misc\"},{\"id\":\"com.qualcomm.qti.uceshimservice\",\"label\":\"uceShimService\",\"description\":\"UCE shim service\\nUCE = User Capability Exchange. A shim is basically a compatibility layer for an API, that makes sure anything that uses the API does so correctly.\\nUsed for RCS. Provides a discovery service for users to see the capabilities of other users.\\nUCE is based on SIP PUBLISH and SIP SUBSCRIBE/NOTIFY.\\nDevices PUBLISH their capabilities to a presence server, when another device wants to find out what the other party supports, the device sends a SUBSCRIBE to the presence server which then returns a NOTIFY of what the other party supports.\",\"web\":[\"https://fr.wikipedia.org/wiki/Session_Initiation_Protocol\"],\"removal\":\"replace\",\"type\":\"misc\"},{\"id\":\"com.qualcomm.qti.uim\",\"label\":\"com.qualcomm.qti.uim\",\"description\":\"Runs \\\"RemoteSimLockService\\\" in the background.\\nThis might be the only remote SIM lock service, just called UIM because R-UIM(Removeable-UserIdentityModule) is a variant of SIM commonly used in Asia.\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.qualcomm.qti.uimGbaApp\",\"label\":\"com.qualcomm.qti.uimGbaApp\",\"description\":\"Contains a \\\"GbaService\\\", related to uim card (R-UIM is a type of SIM card mainly used in Asia)\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.qualcomm.qti.workloadclassifier\",\"label\":\"com.qualcomm.qti.workloadclassifier\",\"description\":\"Runs \\\"WLCService\\\" in the background.\\nI assume this has to do with CPU scheduling. Probably important for efficiency, if not basic operation.\\nIt's for performance and security? It categorizes apps maybe for optimization.\\nit's named workloadclassifier so it should do that. Reads the list of installed applications, storage space.\\nit's still unknown.\",\"removal\":\"caution\",\"type\":\"misc\"},{\"id\":\"com.qualcomm.qti.xrcb\",\"description\":\"Receive xrcb network signals for radio side. \\nit's about emergency alerts, weather alerts, public announcements, and other information.\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.qualcomm.qti.xrvd.service\",\"label\":\"XRVD\",\"description\":\"The real name of this app is XRVDTest. It has accessibility testing,\\nCollects some data? It's something for developers probably.\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.qualcomm.qtil.aptxacu\",\"description\":\"Hidden aptxals Audio Bluetooth sample improvement. Useless 96kHz sample.\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.qualcomm.qtil.aptxals\",\"label\":\"com.qualcomm.qtil.aptxals\",\"description\":\"Hidden aptxals Audio Bluetooth sample improvement test.\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.qualcomm.qtil.aptxalsOverlay\",\"label\":\"com.qualcomm.qtil.aptxalsOverlay\",\"description\":\"Overlay for hidden aptxals Audio Bluetooth sample improvement. Useless 96kHz sample.\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.qualcomm.qtil.aptxui\",\"label\":\"Bluetooth\",\"description\":\"Hidden aptxals Audio Bluetooth sample improvement. Useless 96kHz sample.\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.qualcomm.qtil.btdsda\",\"description\":\"Hidden bluetooth: answering call, hanging up call, hanging up conference call.\\nIf you have dual-sim then you will lose these things? NOTE: disabling this causes audio to come from earpiece regardless of the option selected (Speaker, Earpiece, Bluetooth)\",\"removal\":\"replace\",\"type\":\"misc\"},{\"id\":\"com.qualcomm.shutdownlistner\",\"description\":\"uses library com.qualcomm.qcrilhook and logs shutdown phone but it's not needed.\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.qualcomm.simcontacts\",\"label\":\"Sim Contacts\",\"description\":\"Probably handles syncing(exporting/importing) contacts to/from the SIM card. Usually not a feature anybody cares about.\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.qualcomm.svi\",\"label\":\"Sunlight Visibility Improvement\",\"description\":\"SVI Settings. Hidden display enhancement colors not available to users.\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.qualcomm.timeservice\",\"label\":\"Qualcomm Time Service\",\"description\":\"Updates time-services user time offset when user changes time of the day and Android sends a TIME_CHANGED or DATE_CHANGED intents.\\nTime-services restores the time of the day after reboot.\",\"web\":[\"https://github.com/bcyj/android_tools_leeco_msm8996/blob/master/time-services/src/com/qualcomm/timeservice/TimeServiceBroadcastReceiver.java\"],\"removal\":\"caution\",\"type\":\"misc\"},{\"id\":\"com.qualcomm.uimremoteclient\",\"label\":\"com.qualcomm.uimremoteclient\",\"description\":\"Related to uim card (R-UIM is a type of SIM card mainly used in Asia)\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.qualcomm.uimremoteserver\",\"label\":\"com.qualcomm.uimremoteserver\",\"description\":\"Related to uim card (R-UIM is a type of SIM card mainly used in Asia)\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.qualcomm.wfd.service\",\"label\":\"Wfd Service\",\"description\":\"Provides a way to cast your screen to a TV (Miracast). Or is it WiFi Direct?\",\"web\":[\"https://en.wikipedia.org/wiki/Miracast\"],\"removal\":\"caution\",\"type\":\"misc\"},{\"id\":\"com.quicinc.cne.CNEService\",\"label\":\"com.quicinc.cne.CNEService\",\"description\":\"Qualcomm Connectivity Engine\\nEnables seamless hand-off between mobile data and Wi-Fi networks. Can also dynamically measure network performance to prioritize using the best one (I think that's part of \\\"Intelligently select the best Wi-Fi\\\" in settings).\\nProbably worth keeping on; I noticed connection reliability getting worse when I disabled it.\",\"web\":[\"https://www.qualcomm.com/news/onq/2013/07/02/qualcomms-cne-bringing-smarts-3g4g-wi-fi-seamless-interworking\",\"https://programmersought.com/article/35091829299/\"],\"removal\":\"caution\",\"type\":\"misc\"},{\"id\":\"com.quicinc.fmradio\",\"label\":\"FM Radio\",\"description\":\"FM Radio app by Qualcomm\\nquicinc = Qualcomm Innovation Center\",\"removal\":\"replace\",\"suggestions\":\"radios\",\"type\":\"misc\"},{\"id\":\"com.quicinc.voice.activation\",\"label\":\"Qualcomm Voice Assist\",\"description\":\"Always-on voice detection, so obviously always runs in the background.\\nProbably worth keeping enabled for battery savings if you use Google Assistant regularly while your screen is off.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.quicinc.voice.activation\"],\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.realvnc.android.remote\",\"label\":\"com.realvnc.android.remote\",\"description\":\"Remote controle service by Realvnc\\nNot sure having a remote control app installed as a system app is a good idea\\nNo longer maintained.\",\"web\":[\"https://en.wikipedia.org/wiki/RealVNC\",\"https://www.realvnc.com/en/legal/#privacy\"],\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.redteamobile.roaming\",\"label\":\"ORoaming\",\"dependencies\":[\"com.redteamobile.roaming.deamon\"],\"description\":\"Lets you buy RedTeaMobile data plan to access Internet in foreign country with a virtual SIM card\",\"web\":[\"https://support.oppo.com/uk/answer/?aid=neu9139\",\"https://beta.pithus.org/report/d017d4f6623bf8e71456e6bffe551ef6f3ff3095c62cef3df6d968354898c097\"],\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.redteamobile.roaming.deamon\",\"label\":\"ORoaming\",\"required_by\":[\"com.redteamobile.roaming\"],\"description\":\"Redtea Roaming service deamon for com.redteamobile.roaming\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.remotefairy4\",\"label\":\"AnyMote Universal Remote + Wifi Smart Home Control\",\"description\":\"IR Remote control app\\nIt has lots of trackers and permissions\",\"web\":[\"https://play.google.com/store/apps/details?id=com.remotefairy4\",\"https://reports.exodus-privacy.eu.org/en/reports/com.remotefairy4/latest/\"],\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.republicwireless.tel\",\"label\":\"Republic\",\"description\":\"Lets you manage your Republic wireless account.\\nRepublic Wireless is an american mobile virtual network operator\",\"web\":[\"https://play.google.com/store/apps/details?id=com.republicwireless.tel&hl\",\"https://en.wikipedia.org/wiki/Republic_Wireless\"],\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.rhapsody\",\"label\":\"Napster\",\"description\":\"Napster music streaming app\",\"web\":[\"https://play.google.com/store/apps/details?id=com.rhapsody\",\"https://en.wikipedia.org/wiki/Napster\",\"http://napster.com/privacy\"],\"removal\":\"replace\",\"suggestions\":\"music_apps\",\"type\":\"misc\"},{\"id\":\"com.rhapsody.vpl\",\"label\":\"Napster Music\",\"description\":\"Napster music streaming app\",\"web\":[\"https://play.google.com/store/apps/details?id=com.rhapsody\",\"https://en.wikipedia.org/wiki/Napster\",\"http://napster.com/privacy\"],\"removal\":\"replace\",\"suggestions\":\"music_apps\",\"type\":\"misc\"},{\"id\":\"com.rlk.weathers\",\"label\":\"Weather\",\"description\":\"Weather app with ads and trackers. Can access phone calls and SMS.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.rlk.weathers\",\"https://beta.pithus.org/report/c3fa30c66192c458f93456401421d3c74f9122191b561781af142c42c24fe603\"],\"removal\":\"replace\",\"type\":\"misc\"},{\"id\":\"com.roaming.android.gsimbase\",\"label\":\"com.roaming.android.gsimbase\",\"description\":\"gsim = Global SIM? (SIM = Subscriber Identity Module, as in SIM-card)\\nConsidering the \\\"roaming\\\" context that's my best guess.\",\"removal\":\"replace\",\"type\":\"misc\"},{\"id\":\"com.roaming.android.gsimcontentprovider\",\"label\":\"com.roaming.android.gsimcontentprovider\",\"description\":\"gsim = Global SIM? (SIM = Subscriber Identity Module, as in SIM-card)\\nConsidering the \\\"roaming\\\" context that's my best guess.\",\"removal\":\"replace\",\"type\":\"misc\"},{\"id\":\"com.s.antivirus\",\"label\":\"AVG Protection\",\"description\":\"AVG Antivirus for Sony Xperia.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.s.antivirus\"],\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.sec.app.samsungprintservice\",\"description\":\"Samsung Print Service Plugin.\\nPublished by HP, see:\\nhttps://play.google.com/store/apps/details?id=com.sec.app.samsungprintservice\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.sem.factoryapp\",\"label\":\"com.sem.factoryapp\",\"description\":\"SEMFactoryApp\\nCall home (172.217.168.14 --> Google IP). Needs NFC permission.\\nThis package is maybe used to test NFC.\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.servicemagic.consumer\",\"label\":\"Angi\",\"description\":\"HomeAdvisor: Contractors for Home Improvement\\nHelps you find local contractors from the service Home Advisor network\\nHomeAdvisor collects users data when a request is made and then sells that data to local contractors in exchange for money.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.servicemagic.consumer\",\"https://en.wikipedia.org/wiki/HomeAdvisor#Critism\"],\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.setk.widget\",\"label\":\"Bizz\",\"description\":\"Recommands you stuff to do/buy in your nearby area\",\"web\":[\"https://play.google.com/store/apps/details?id=com.setk.widget\"],\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.sharecare.askmd\",\"label\":\"AskMD\",\"description\":\"Symptom checker app provided by Sharecare [Discontinued]\\nLets you see what might be causing your symptoms and helps you find a nearby physician\",\"web\":[\"https://en.wikipedia.org/wiki/Sharecare#Criticisms\"],\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.shopee.br\",\"label\":\"Shopee\",\"description\":\"An e-commerce online shopping platform for Brazil.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.shopee.br\"],\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.shopee.id\",\"label\":\"Shopee\",\"description\":\"An e-commerce online shopping platform for Indonesia.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.shopee.id\"],\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.skype.m2\",\"label\":\"Skype Lite\",\"description\":\"Lite version of Skype\\nVoice & video calling app\",\"removal\":\"replace\",\"suggestions\":\"meeting_apps\",\"type\":\"misc\"},{\"id\":\"com.skype.raider\",\"label\":\"Skype\",\"description\":\"Voice & video calling app\",\"web\":[\"https://play.google.com/store/apps/details?id=com.skype.raider\"],\"removal\":\"replace\",\"suggestions\":\"meeting_apps\",\"type\":\"misc\"},{\"id\":\"com.slacker.radio\",\"label\":\"LiveOne\",\"description\":\"Music and Live Events streaming app\",\"web\":[\"https://play.google.com/store/apps/details?id=com.slacker.radio\",\"https://www.liveone.com/privacy\"],\"removal\":\"replace\",\"suggestions\":\"music_apps\",\"type\":\"misc\"},{\"id\":\"com.smithmicro.netwise.director.comcast.oem\",\"label\":\"XFINITY WiFi Settings\",\"description\":\"Auto-connects you to XFINITY WiFi hotspot.\\nXFINITY is a subsidiary of the Comcast Corporation\",\"web\":[\"https://play.google.com/store/apps/details?id=com.smithmicro.netwise.director.comcast.oem\",\"https://en.wikipedia.org/wiki/Xfinity\"],\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.snapchat.android\",\"label\":\"Snapchat\",\"description\":\"Snapchat is a social media app that allows users to share photos and videos that disappear after a short period of time.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.snapchat.android\"],\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.spotify.music\",\"label\":\"Spotify\",\"description\":\"Popular music streaming app\",\"web\":[\"https://play.google.com/store/apps/details?id=com.spotify.music\",\"https://www.spotify.com/privacy/\"],\"removal\":\"replace\",\"suggestions\":\"music_apps\",\"type\":\"misc\"},{\"id\":\"com.staplegames.blocksClassicSGGP\",\"label\":\"Blocks\",\"description\":\"Preinstalled game on some Samsung phones.\\nExodus report: 9 permissions, 26 trackers\",\"web\":[\"https://play.google.com/store/apps/details?id=com.staplegames.blocksClassicSGGP\",\"https://reports.exodus-privacy.eu.org/reports/com.staplegames.blocksClassicSGGP/latest/\"],\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.swiftkey.swiftkeyconfigurator\",\"label\":\"SwiftKey factory settings\",\"description\":\"Used by commercial swiftkey partners to configure the SwiftKey app.\\nSwiftkey is a keyboard developed by TouchType, a Microsoft subsidiary\",\"web\":[\"https://en.wikipedia.org/wiki/SwiftKey\"],\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.talpa.hibrowser\",\"label\":\"Hi Browser\",\"description\":\"Awful browser with embedded trackers and ads.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.talpa.hibrowser\",\"https://reports.exodus-privacy.eu.org/fr/reports/com.talpa.hibrowser/latest/\"],\"removal\":\"replace\",\"suggestions\":\"browsers\",\"type\":\"misc\"},{\"id\":\"com.talpa.share\",\"label\":\"XShare Mini\",\"description\":\"File Sharing App (via Bluetooth) with Google and Facebook trackers.\\nAsks for a lot of permissions including ACCESS_FINE_LOCATION, REQUEST_INSTALL_PACKAGES.\",\"web\":[\"https://beta.pithus.org/report/949bf802e335ad0db47b1551cde46af2b2ef13da4b38be969c60c9439b94f05b\"],\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.telenav.app.android.cingular\",\"label\":\"AT&T Navigator\",\"description\":\"Crappy GPS app provided by Telenav and rebranded by AT&T.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.telenav.app.android.cingular\",\"https://www.telenav.com/legal/policies-privacy-policy\"],\"removal\":\"replace\",\"suggestions\":\"maps\",\"type\":\"misc\"},{\"id\":\"com.telenav.app.android.scout_us\",\"label\":\"Scout\",\"description\":\"Bad GPS with on top of that bad chat features (USA only)\",\"web\":[\"https://play.google.com/store/apps/details?id=com.telenav.app.android.scout_us\",\"https://www.scoutgps.com/\"],\"removal\":\"replace\",\"suggestions\":\"maps\",\"type\":\"misc\"},{\"id\":\"com.til.timesnews\",\"label\":\"Newspoint\",\"description\":\"India specific news app\",\"web\":[\"https://play.google.com/store/apps/details?id=com.til.timesnews\",\"http://www.newspointapp.com/policy.cms\"],\"removal\":\"replace\",\"suggestions\":\"rss_readers\",\"type\":\"misc\"},{\"id\":\"com.tiqiaa.remote\",\"label\":\"Zaza Remote\",\"description\":\"A Universal infrared control app full of trackers and with unecessary permissions.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.tiqiaa.remote\",\"https://beta.pithus.org/report/93eed47a45c00998f2111907afc26b5697aaf7fb19c0efb6b42d46addf0e297c\"],\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.tmobile.echolocate\",\"label\":\"T-Mobile Diagnostics\",\"description\":\"More info needed\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.touchtype.swiftkey\",\"label\":\"Swiftkey\",\"description\":\"Keyboard app by TouchType, a Microsoft subsidiary.\\n4 Trackers + 11 Permissions\",\"web\":[\"https://en.wikipedia.org/wiki/SwiftKey\",\"https://play.google.com/store/apps/details?id=com.touchtype.swiftkey\",\"https://reports.exodus-privacy.eu.org/en/reports/com.touchtype.swiftkey/latest/\"],\"removal\":\"replace\",\"warning\":\"Default keyboard on some Nokia and Huawei phones. Make sure you have another keyboard app before disabling this.\",\"suggestions\":\"keyboards\",\"type\":\"misc\"},{\"id\":\"com.touchtype.swiftkey.res.overlay\",\"label\":\"com.touchtype.swiftkey.res.overlay\",\"description\":\"Some overlay for Swiftkey? Overlays are usually themes, but not sure about this one.\",\"removal\":\"caution\",\"type\":\"misc\"},{\"id\":\"com.tracker.t\",\"label\":\"com.tracker.t\",\"description\":\"Given its name I think you can take the risk to delete it.\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.tripadvisor.tripadvisor\",\"label\":\"Tripadvisor\",\"description\":\"Travel Guidance app\",\"web\":[\"https://play.google.com/store/apps/details?id=com.tripadvisor.tripadvisor\",\"https://en.wikipedia.org/wiki/Tripadvisor#Controversies\",\"https://nypost.com/2016/03/01/why-you-should-never-ever-trust-tripadvisor/\"],\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.tripledot.solitaire\",\"label\":\"Solitaire\",\"description\":\"Preinstalled game on some Samsung phones. 30 permissions, 23 trackers\",\"web\":[\"https://play.google.com/store/apps/details?id=com.tripledot.solitaire\",\"https://reports.exodus-privacy.eu.org/reports/com.tripledot.solitaire/latest/\"],\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.tripledot.woodoku\",\"label\":\"Woodoku\",\"description\":\"A wood block puzzle game\\nPreinstalled game on some Samsung phones. 28 permissions, 24 trackers\",\"web\":[\"https://play.google.com/store/apps/details?id=com.tripledot.woodoku\",\"https://reports.exodus-privacy.eu.org/reports/com.tripledot.woodoku/latest/\"],\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.trustonic.teeservice\",\"label\":\"TeeService\",\"description\":\"TEE = Trusted Execution Environment\",\"removal\":\"caution\",\"type\":\"misc\"},{\"id\":\"com.trustonic.tuiservice\",\"label\":\"Trusted User Interface\",\"description\":\"A security layer by Trustonic.\\nAllows a \\\"Trusted App\\\" to interact directly with the user, completely isolated from the device OS.\\nIt's closed source and normal devs can't use it for their apps.\\nMainly used by OEM apps like Samsung Pay and for DRM.\\nGoogle implemented their own TUI in Android Pie: https://android-developers.googleblog.com/search/label/Trusted%20User%20Interface\\nhttps://www.trustonic.com/news/blog/benefits-trusted-user-interface/\\nDisabling will break \\\"Trusted Apps\\\".\",\"web\":[\"https://stackoverflow.com/questions/16909576/how-to-make-use-of-arm-trust-zone-in-android-application\",\"https://en.wikipedia.org/wiki/Trusted_execution_environment\",\"https://en.wikipedia.org/wiki/ARM_architecture#Security_extensions\",\"https://googleprojectzero.blogspot.com/2017/07/trust-issues-exploiting-trustzone-tees.html\",\"https://medium.com/@nimronagy/arm-trustzone-on-android-975bfe7497d2\",\"https://www.synacktiv.com/posts/exploit/kinibi-tee-trusted-application-exploitation.html\",\"https://blog.quarkslab.com/introduction-to-trusted-execution-environment-arms-trustzone.html\",\"https://medium.com/taszksec/unbox-your-phone-part-i-331bbf44c30c\",\"nhttps://www.gsd.inesc-id.pt/~nsantos/papers/pinto_acsur19.pdf\"],\"removal\":\"caution\",\"type\":\"misc\"},{\"id\":\"com.turner.cnvideoapp\",\"label\":\"CN\",\"description\":\"Award winning Cartoon Network App\",\"web\":[\"https://play.google.com/store/apps/details?id=com.turner.cnvideoapp\",\"http://www.cartoonnetwork.com/legal/privacy/mobile.html\"],\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.ubercab\",\"label\":\"Uber\",\"description\":\"Uber does not protect personal user data and has a questionable ethic.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.ubercab\",\"https://en.wikipedia.org/wiki/Uber#Criticism\"],\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.ubercab.driver\",\"label\":\"Uber - Driver\",\"description\":\"Uber does not protect personal user data and has a questionable ethic.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.ubercab.driver\",\"https://en.wikipedia.org/wiki/Uber#Criticism\"],\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.ubercab.eats\",\"label\":\"Uber Eats\",\"description\":\"Uber does not protect personal user data and has a questionable ethic.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.ubercab.eats\",\"https://en.wikipedia.org/wiki/Uber#Criticism\"],\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.ume.browser.northamerica\",\"label\":\"UME Web Browser\",\"description\":\"It has trackers and a LOT of unnecessary permissions.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.ume.browser.northamerica\",\"https://reports.exodus-privacy.eu.org/en/reports/com.ume.browser.cust/latest/\"],\"removal\":\"replace\",\"suggestions\":\"browsers\",\"type\":\"misc\"},{\"id\":\"com.wb.goog.got.conquest\",\"label\":\"Game of Thrones: Conquest\",\"description\":\"Official GOT strategy building game\",\"web\":[\"https://play.google.com/store/apps/details?id=com.wb.goog.got.conquest\"],\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.whatsapp\",\"label\":\"WhatsApp\",\"description\":\"Popular messaging app from Meta. Requires Google Play Services to receive messages in the background.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.whatsapp\",\"https://en.wikipedia.org/wiki/WhatsApp#Controversies_and_criticism\"],\"removal\":\"replace\",\"type\":\"misc\"},{\"id\":\"com.wing.wtsarcontrol\",\"description\":\"Sar control, Chinese App, not available for normal users.\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.wingtech.sartest\",\"description\":\"SarTest\\nSecret code: 332.\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.yahoo.mobile.client.android.liveweather\",\"label\":\"Weather\",\"description\":\"All of their services are crappy so it's not so difficult to boycott\",\"web\":[\"https://play.google.com/store/apps/details?id=com.yahoo.mobile.client.android.weather\",\"https://en.wikipedia.org/wiki/Criticism_of_Yahoo!\"],\"removal\":\"replace\",\"type\":\"misc\"},{\"id\":\"com.yellowpages.android.ypmobile\",\"label\":\"Yellow Pages\",\"description\":\"Business related app\",\"web\":[\"https://play.google.com/store/apps/details?id=com.yellowpages.android.ypmobile\"],\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.yelp.android\",\"label\":\"Yelp\",\"description\":\"Yelp lets users post reviews and rate businesses.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.yelp.android\",\"https://en.wikipedia.org/wiki/Yelp#Controversy_and_litigation\"],\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"com.zaz.translate\",\"label\":\"Hi Translate\",\"description\":\"Bloated translation app with a lot of trackers and permissions\\nIt uses the Google Translate API for the translations.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.zaz.translate\",\"https://beta.pithus.org/report/fdd787d96c3e069f983320c84c32fc6b8cdf205df17244d190b181edf0c14f68\"],\"removal\":\"replace\",\"suggestions\":\"translators\",\"type\":\"misc\"},{\"id\":\"com.zhiliaoapp.musically\",\"label\":\"TikTok\",\"description\":\"The TikTok app\",\"web\":[\"https://play.google.com/store/apps/details?id=com.zhiliaoapp.musically\",\"https://en.wikipedia.org/wiki/TikTok#Privacy_and_security_concerns\"],\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"de.axelspringer.yana.zeropage\",\"label\":\"upday\",\"description\":\"News app preinstalled on some smartphones\",\"web\":[\"https://play.google.com/store/apps/details?id=de.axelspringer.yana.zeropage\"],\"removal\":\"replace\",\"suggestions\":\"rss_readers\",\"type\":\"misc\"},{\"id\":\"flipboard.app\",\"label\":\"Flipboard\",\"description\":\"Flipboard News App\",\"web\":[\"https://play.google.com/store/apps/details?id=flipboard.app\",\"https://about.flipboard.com/privacy-policy/\",\"https://privacy.commonsense.org/privacy-report/Flipboard\"],\"removal\":\"replace\",\"suggestions\":\"rss_readers\",\"type\":\"misc\"},{\"id\":\"flipboard.boxer.app\",\"label\":\"Briefing\",\"description\":\"Briefing app from Flipboard\",\"web\":[\"https://play.google.com/store/apps/details?id=flipboard.boxer.app\",\"https://about.flipboard.com/privacy-policy/\"],\"removal\":\"replace\",\"suggestions\":\"rss_readers\",\"type\":\"misc\"},{\"id\":\"id.co.babe\",\"label\":\"BaBe\",\"description\":\"Indonesian news app\",\"web\":[\"https://play.google.com/store/apps/details?id=id.co.babe\"],\"removal\":\"replace\",\"suggestions\":\"rss_readers\",\"type\":\"misc\"},{\"id\":\"in.amazon.mShop.android.shopping\",\"label\":\"Amazon\",\"description\":\"Amazon shopping app for India\",\"web\":[\"https://play.google.com/store/apps/details?id=in.amazon.mShop.android.shopping\"],\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"in.mohalla.sharechat\",\"label\":\"ShareChat\",\"description\":\"Multilingual India specific social media platform\",\"web\":[\"https://play.google.com/store/apps/details?id=in.mohalla.sharechat\",\"https://en.wikipedia.org/wiki/ShareChat\",\"https://help.sharechat.com/policies/privacy-policy/\"],\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"in.playsimple.tripcross\",\"label\":\"CrossWord Jam\",\"description\":\"Preinstalled game on some Samsung phones. 12 permissions, 25 trackers\",\"web\":[\"https://play.google.com/store/apps/details?id=in.playsimple.tripcross\",\"https://reports.exodus-privacy.eu.org/reports/in.playsimple.tripcross/latest/\"],\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"in.playsimple.wordtrip\",\"label\":\"Word Trip\",\"description\":\"Word Count & word streak puzzle game. 19 trackers, 11 permissions\",\"web\":[\"https://play.google.com/store/apps/details?id=in.playsimple.wordtrip\",\"https://reports.exodus-privacy.eu.org/en/reports/in.playsimple.wordtrip/latest/\"],\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"jp.co.omronsoft.openwnn\",\"label\":\"jp.co.omronsoft.openwnn\",\"description\":\"Japanese keyboard/IME (don't know why it's pre-installed on US/european devices)\\nNote : IME = input method editor\",\"removal\":\"replace\",\"warning\":\"Make sure you've another one installed before you disable.\",\"suggestions\":\"keyboards\",\"type\":\"misc\"},{\"id\":\"jp.gocro.smartnews.android\",\"label\":\"SmartNews\",\"description\":\"Delivers the top trending news stories from other publishers (NBC News, The Verges etc...)\\nIncludes 7 Trackers + 10 permissions\",\"web\":[\"https://play.google.com/store/apps/details?id=jp.gocro.smartnews.android\",\"https://reports.exodus-privacy.eu.org/en/reports/jp.gocro.smartnews.android/latest/\"],\"removal\":\"replace\",\"suggestions\":\"rss_readers\",\"type\":\"misc\"},{\"id\":\"msgplus.jibe.sca.vpl\",\"label\":\"Messaging Plus\",\"description\":\"Messings using the RCS protocol\\nRelated to Google Jibe (https://jibe.google.com/)\",\"web\":[\"https://en.wikipedia.org/wiki/Rich_Communication_Services\"],\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"net.bat.store\",\"label\":\"AHA Games\",\"description\":\"Mobile game store.\\nFull of trackers and has CAMERA and RECORD_AUDIO permissions. Displays intrusive game ads on HIOS launcher and random popups.\",\"web\":[\"https://beta.pithus.org/report/f5346d1388aff293bc84b481c3a9823cc3bf76ffc241fcf455754b86028f22b9\"],\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"net.fetnet.fetvod\",\"description\":\"Streaming service\\nRegistered members can watch the movies, dramas, variety shows and animations\\nhttps://play.google.com/store/apps/details?id=net.fetnet.fetvod\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"net.sharewire.parkmobilev2\",\"label\":\"ParkMobile\",\"description\":\"Smarter way to park and reserve your spot ahead of time\",\"web\":[\"https://play.google.com/store/apps/details?id=net.sharewire.parkmobilev2\"],\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"net.supertreat.solitaire\",\"label\":\"Solitaire\",\"description\":\"Preinstalled game on some Samsung phones. 8 permissions, 17 trackers\",\"web\":[\"https://play.google.com/store/apps/details?id=net.supertreat.solitaire\",\"https://reports.exodus-privacy.eu.org/reports/net.supertreat.solitaire/latest/\"],\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"org.codeaurora.bluetooth\",\"label\":\"Bluetooth extensions\",\"description\":\"More info needed\",\"web\":[\"https://source.codeaurora.org/quic/la/platform/vendor/qcom-opensource/bluetooth\"],\"removal\":\"caution\",\"type\":\"misc\"},{\"id\":\"org.codeaurora.gps.gpslogsave\",\"label\":\"org.codeaurora.gps.gpslogsave\",\"description\":\"More info needed\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"org.codeaurora.ims\",\"label\":\"org.codeaurora.ims\",\"description\":\"IMS(Ip Multimedia Subsystem) is an open industry standard for voice and multimedia communications over packet-based IP networks (VoLTE/VoIP/Wifi calling).\\nRuns in the background as part of the system, with Google's IMS(com.google.android.ims, \\\"Carrier Services\\\") disabled, I haven't checked if it'd run with Carrier Services enabled.\",\"removal\":\"caution\",\"type\":\"misc\"},{\"id\":\"org.simalliance.openmobileapi.service\",\"label\":\"SmartcardService\",\"description\":\"The SmartCard API is a reference implementation of the SIMalliance Open Mobile API specification that enables Android applications to communicate with Secure Elements, (SIM card, embedded Secure Elements, Mobile Security Card or others)\\nSafe to remove if you think you don't need this\",\"web\":[\"https://github.com/seek-for-android/pool/wiki/SmartcardAPI\"],\"removal\":\"caution\",\"type\":\"misc\"},{\"id\":\"org.simalliance.openmobileapi.uicc1terminal\",\"description\":\"Open Mobile API (\\\"interface\\\") to access UICC secure elements\\nUICC stands for Universal Integrated Circuit Card.\\nIt is a the physical and logical platform for the USIM and may contain additional USIMs and other applications.\\n(U)SIM is an application on the UICC.\\nhttps://bluesecblog.wordpress.com/2016/11/18/uicc-sim-usim/\\nGood read: https://arxiv.org/ftp/arxiv/papers/1601/1601.03027.pdf\\nNote2: The term SIM is widely used in the industry and especially with consumers to mean both SIMs and UICCs.\\nhttps://www.justaskgemalto.com/us/what-uicc-and-how-it-different-sim-card/\\n\",\"removal\":\"replace\",\"type\":\"misc\"},{\"id\":\"org.simalliance.openmobileapi.uicc2terminal\",\"label\":\"org.simalliance.openmobileapi.uicc2terminal\",\"description\":\"Open Mobile API (\\\"interface\\\") to access UICC secure elements.\\nUICC stands for Universal Integrated Circuit Card.\\nIt is the physical and logical platform for the USIM and may contain additional USIMs and other applications.\\n(U)SIM is an application on the UICC.\\nNote: The term SIM is widely used in the industry and especially with consumers to mean both SIMs and UICCs.\",\"web\":[\"https://bluesecblog.wordpress.com/2016/11/18/uicc-sim-usim/\",\"https://arxiv.org/ftp/arxiv/papers/1601/1601.03027.pdf\",\"https://www.justaskgemalto.com/us/what-uicc-and-how-it-different-sim-card/\"],\"removal\":\"caution\",\"type\":\"misc\"},{\"id\":\"pl.zdunex25.updater\",\"label\":\"pl.zdunex25.updater\",\"description\":\"Updater for the zdnex25's theme\",\"web\":[\"https://www.deviantart.com/zdunex25/gallery/26889741/themes\"],\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"tv.fubo.mobile.vpl\",\"label\":\"fuboTV\",\"description\":\"Lets you Watch live Sports, TV Shows, Movies & News\",\"web\":[\"https://play.google.com/store/apps/details?id=tv.fubo.mobile\"],\"removal\":\"replace\",\"suggestions\":\"streaming_apps\",\"type\":\"misc\"},{\"id\":\"tv.peel.app\",\"label\":\"Peel Universal Smart TV Remote Control\",\"description\":\"Lets you remotely control devices like your TV, DVD or Blu-ray player (Discontinued)\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"vendor.qti.data.txpwradmin\",\"description\":\"This app is from qualcomm, in androidmanifest.xml I found things like com.qualcomm.qti.qmsdataservices, qms is spyware,\\npermissions uses: access wifi state, quary all packages, package usage stats.\\nSo hidden network stats, more about it is this code is just logs, takes apm, wifi, bt status.\",\"removal\":\"replace\",\"type\":\"misc\"},{\"id\":\"vendor.qti.hardware.cacert.server\",\"label\":\"CACertApp\",\"description\":\"Occasionally runs in the background.\\nHandles CACert certificates?\\nCACert is a community-driven CA that issues certificates to the public at large for free. CA = Certificate Authority, an entity that certifies the ownership of a public key that can be used for secure communications.\",\"web\":[\"http://www.cacert.org/\",\"https://en.wikipedia.org/wiki/CAcert.org\"],\"removal\":\"unsafe\",\"warning\":\"Probably a bad idea to disable; could mess with device security.\",\"type\":\"misc\"},{\"id\":\"vendor.qti.imsdatachannel\",\"description\":\"Needed for IMS.\",\"removal\":\"replace\",\"type\":\"misc\"},{\"id\":\"vendor.qti.imsrcs\",\"description\":\"IMS(Ip Multimedia Subsystem) is an open industry standard for voice and multimedia communications over packet-based IP networks (VoLTE/VoIP/Wifi calling). Also have RCS.\",\"removal\":\"caution\",\"type\":\"misc\"},{\"id\":\"vendor.qti.iwlan\",\"description\":\"Used for VoLTE/VoWifi (Wifi-calling)\\nIwLAN = Interworking wLAN.\\nSupport for mobile data offloading (use of complementary network technologies for delivering data originally targeted for cellular networks)\\nIt means your phone will use the Wi-Fi connection instead of the cellular data connection.\\nhttps://en.wikipedia.org/wiki/Mobile_data_offloading\",\"removal\":\"caution\",\"type\":\"misc\"},{\"id\":\"vendor.qti.qesdk.sysservice\",\"description\":\"It's for debugging and logs. But in the code I see VDebug. Vivo probably uses Qualcomm for some features.\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"zpub.res\",\"label\":\"zpub.res\",\"description\":\"Third-party app pre-installed on ZTE phones.\",\"removal\":\"delete\",\"type\":\"misc\"},{\"id\":\"android.autoinstalls.config.Nothing.Pong\",\"description\":\"PlayAutoInstalls\\nAutoInstalls a set of OEM apps on device setup (first boot/factory reset).\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"android.autoinstalls.config.TCL.PAI\",\"description\":\"AutoInstalls a set of OEM apps on device setup (first boot/factory reset).\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"android.autoinstalls.config.Xiaomi.cactus\",\"description\":\"Cactus is the device codename.\\nAutoInstalls a set of OEM apps on device setup (first boot/factory reset).\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"android.autoinstalls.config.Xiaomi.cepheus\",\"description\":\"Cepheus is the device codename.\\nAutoInstalls a set of OEM apps on device setup (first boot/factory reset).\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"android.autoinstalls.config.Xiaomi.cereus\",\"description\":\"Cepheus is the device codename.\\nAutoInstalls a set of OEM apps on device setup (first boot/factory reset). For example, Personal Activity Intelligence.\\nAn algorithm that determines a personal activity index based on resting heart rate, heart condition during exercise, gender, weight, and age. Requires smart bracelet to work.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"android.autoinstalls.config.Xiaomi.daisy\",\"description\":\"Daisy is the device codename.\\nAutoInstalls a set of OEM apps on device setup (first boot/factory reset).\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"android.autoinstalls.config.Xiaomi.dipper\",\"description\":\"Dipper is the device codename.\\nAutoInstalls a set of OEM apps on device setup (first boot/factory reset).\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"android.autoinstalls.config.Xiaomi.land\",\"description\":\"land is the device codename.\\nAutoInstalls a set of OEM apps on device setup (first boot/factory reset).\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"android.autoinstalls.config.Xiaomi.model\",\"description\":\"PlayAutoInstalls\\nAutoInstalls a set of OEM apps on device setup (first boot/factory reset).\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"android.autoinstalls.config.Xiaomi.qssi\",\"description\":\"PlayAutoInstalls\\nAutoInstalls a set of OEM apps on device setup (first boot/factory reset).\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"android.autoinstalls.config.Xiaomi.willow\",\"description\":\"PlayAutoInstalls\\nAutoInstalls a set of OEM apps on device setup (first boot/factory reset).\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"android.autoinstalls.config.asus.pai\",\"description\":\"PlayAutoInstalls\\nAutoInstalls a set of OEM apps on device setup (first boot/factory reset).\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"android.autoinstalls.config.google.sabrina\",\"description\":\"AutoInstalls a set of OEM apps on device setup (first boot/factory reset).\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"android.autoinstalls.config.lge.device\",\"description\":\"PlayAutoInstalls\\nAutoInstalls a set of OEM apps on device setup (first boot/factory reset).\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"android.autoinstalls.config.motorola.layout\",\"label\":\"Device configuration\",\"description\":\"AutoInstalls a set of OEM apps on device setup (first boot/factory reset).\\nA layout?\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"android.autoinstalls.config.oneplus\",\"label\":\"Device configuration\",\"description\":\"Device configuration\\nAutoInstalls a set of OEM apps on device setup (first boot/factory reset).\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"android.autoinstalls.config.oppo\",\"description\":\"PlayAutoInstalls\\nAutoInstalls a set of OEM apps on device setup (first boot/factory reset).\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"android.autoinstalls.config.samsung\",\"description\":\"AutoInstalls a set of OEM apps on device setup (first boot/factory reset).\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"android.autoinstalls.config.transsion.device\",\"description\":\"PlayAutoInstalls\\nAutoInstalls a set of OEM apps on device setup (first boot/factory reset).\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"android.autoinstalls.config.vivo.devices\",\"description\":\"PlayAutoInstalls\\nAutoInstalls a set of OEM apps on device setup (first boot/factory reset).\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"android.autoinstalls.config.xioami.mibox3\",\"description\":\"AutoInstalls a set of OEM apps on device setup (first boot/factory reset).\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"android.connectivity.base.overlay\",\"description\":\"CaptivePortalLogin overlay.\\nOverlays work by mapping resources defined in the overlay package to resources defined in the target package. When an app attempts to resolve the value of a resource in the target package, the value of the overlay resource the target resource is mapped to is returned instead.\\nhttps://source.android.com/docs/core/runtime/rros\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"android.ext.services\",\"description\":\"Looks like useless BUT you risk bootloop phone.\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"android.framework.res.rro.oneplus\",\"description\":\"A runtime resource overlay (RRO) is a package that changes the resource values of a target package at runtime. For example, an app installed on the system image might change its behavior based upon the value of a resource. Rather than hardcoding the resource value at build time, an RRO installed on a different partition can change the values of the app's resources at runtime.\\nRROs can be enabled or disabled. You can programmatically set the enable/disable state to toggle an RRO's ability to change resource values. RROs are disabled by default (however, static RROs are enabled by default).\\nhttps://source.android.com/docs/core/runtime/rros\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"android.frameworkres.overlay.Network\",\"description\":\"Network overlay.\\nOverlays work by mapping resources defined in the overlay package to resources defined in the target package. When an app attempts to resolve the value of a resource in the target package, the value of the overlay resource the target resource is mapped to is returned instead.\\nhttps://source.android.com/docs/core/runtime/rros\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"android.frameworkres.overlay.display.product\",\"description\":\"A runtime resource overlay (RRO) is a package that changes the resource values of a target package at runtime. For example, an app installed on the system image might change its behavior based upon the value of a resource. Rather than hardcoding the resource value at build time, an RRO installed on a different partition can change the values of the app's resources at runtime.\\nRROs can be enabled or disabled. You can programmatically set the enable/disable state to toggle an RRO's ability to change resource values. RROs are disabled by default (however, static RROs are enabled by default).\\nhttps://source.android.com/docs/core/runtime/rros\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"android.miui.home.launcher.res\",\"description\":\"Config to default icons/placeholder widgets in MIUI launcher.\\nIt's used only first time run MIUI launcher app like com.mi.globallayout.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"android.miui.overlay\",\"description\":\"Refers to a specific package within the MIUI overlay,\\nThe package contains various resources and components that are used to customize the appearance and behavior of the MIUI interface.\\nhttps://source.android.com/docs/core/runtime/rros\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"android.miui.poco.launcher.res\",\"description\":\"Config to default icons/placeholder widgets in MIUI launcher.\\nIt's used only first time run MIUI launcher app like com.mi.globallayout.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"android.overlay.common.all_devices\",\"description\":\"This overlay has got useless configs (?)\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"android.overlay.common.pong\",\"description\":\"Brightness, screen configs. Better don't risk\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"android.overlay.common.spacewar\",\"description\":\"Brightness, screen configs. Better don't risk\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"android.overlay.dynamicNavBar\",\"description\":\"Found only in the bools.xml code, which shows the 'config Support dynamic Navigation Bar' 'true'.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"android.overlay.gms.region.all\",\"description\":\"Useless overlay to setupwizard things\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"android.overlay.gms.region.eea\",\"description\":\"Useless overlay to setupwizard things\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"android.overlay.gms.region.ind\",\"description\":\"Useless overlay to setupwizard things\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"android.overlay.gms.region.row\",\"description\":\"Useless overlay to setupwizard things\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"android.overlay.multiuser\",\"description\":\"Maximum multi user config.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"android.overlay.navbar\",\"description\":\"Show Navigation Bar Config.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"android.overlay.vivoresrro\",\"description\":\"This overlay has only: strings.xml: select_cancel.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"android.overlay.vrro\",\"description\":\"This overlay has display configs\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"android.romstats\",\"description\":\"Misleading package name. This is a Xiaomi-only package.\\nCan someone provide the .apk?\\nTelemetry stuff\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"android.rro_product\",\"description\":\"Better don't touch it.\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"android.telephony.overlay.cmcc\",\"description\":\"Likely overlay themes from China Mobile Communications Corporation(CMCC) or China Telecom(CT).\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"androidhwext\",\"description\":\"EMUI Graphical User Interface:\\nhttps://fixyourandroid.com/about/androidhwext\\nThe framework responsible for the themes (even the standard one) of EMUI to launch. Also, it's the core for the Themes app. REMOVING IT CAUSES A BOOTLOOP!\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"androidx.camera.extensions.impl\",\"description\":\"Camera extensions for Huawei like Tags,HDR effects\\nand other things to video, photos.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"aon.frameworkres.overlay.display.product\",\"description\":\"A runtime resource overlay (RRO) is a package that changes the resource values of a target package at runtime. For example, an app installed on the system image might change its behavior based upon the value of a resource. Rather than hardcoding the resource value at build time, an RRO installed on a different partition can change the values of the app's resources at runtime.\\nRROs can be enabled or disabled. You can programmatically set the enable/disable state to toggle an RRO's ability to change resource values. RROs are disabled by default (however, static RROs are enabled by default).\\nhttps://source.android.com/docs/core/runtime/rros\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"asusims.overlay.aosp.documentsui\",\"description\":\"Not needed overlay for hide documentsui icon. No effects after remove.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"asusims.overlay.common\",\"description\":\"It have important configs better dont risk.\\nImportant configs to android.\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"asusims.overlay.documentsui\",\"description\":\"Not needed overlay for hide documentsui icon. No effects after remove.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"blibli.mobile.commerce\",\"description\":\"Blibli Belanja Online Mall\\nChinese payment blipay\\nhttps://play.google.com/store/apps/details?id=blibli.mobile.commerce\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"cn.nubia.accounts\",\"description\":\"ZAccountService\\nIt's for Nubia Account.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"cn.nubia.advanced\",\"description\":\"Hidden advanced test bluetooth, WiFi\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"cn.nubia.aftersale\",\"description\":\"Has location permissions and it's for debugging, logs.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"cn.nubia.antivirus\",\"description\":\"We don't need antivirus if we have Play Protect.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"cn.nubia.applockmanager\",\"description\":\"App Lock, Add Eyeprint\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"cn.nubia.apptimelock\",\"description\":\"Healthy time management\\nApp time limit.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"cn.nubia.autoagingtest\",\"description\":\"Hidden camera, WiFi tests.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"cn.nubia.behaviordetection\",\"description\":\"Chinese useless frameworks.\\nUsed to collect application behavior data to understand users.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"cn.nubia.bluetooth.opp\",\"description\":\"Needed for Bluetooth\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"cn.nubia.bootanimationinfo\",\"description\":\"Boot Animation Info\\nProbably it's unsafe to remove.\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"cn.nubia.browser\",\"description\":\"Browser\\nStock Nubia Chinese browser.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"cn.nubia.calendar.preset\",\"description\":\"Calendar\\nStock Calendar app\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"cn.nubia.clock.widget.preset\",\"description\":\"ClockWidget\\nIt has more permissions than it should have and DaemonService\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"cn.nubia.cloud\",\"description\":\"Nubia Cloud Manager\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"cn.nubia.contacts\",\"description\":\"Contacts\\nStock Nubia Contacts\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"cn.nubia.controlcenter\",\"description\":\"control center\\nProvides a control panel for controlling the switching of\\nimportant functions in the system, such as data services, WiFi and other switches.\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"cn.nubia.contrycode\",\"description\":\"Useless logs. Useless frameworks.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"cn.nubia.databackup\",\"description\":\"Backup\\nIt's not the best choice for backup. Read Nubia privacy policy before.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"cn.nubia.deskclock.preset\",\"description\":\"Clock\\nStock Clock app for manage alarms.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"cn.nubia.diyaod\",\"description\":\"It can be found in settings\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"cn.nubia.doubleapp\",\"description\":\"App duplicator\\nit's duplicating app feature that can be found in settings\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"cn.nubia.dynamicwallpaper\",\"description\":\"Needed for video wallpapers\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"cn.nubia.edge\",\"description\":\"Smart Service Card\\nSmart Service Card, Smart sidebar.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"cn.nubia.entertainmenttoolbox\",\"description\":\"Useless logs, tracking. Useless frameworks.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"cn.nubia.error.dialog\",\"description\":\"It's just a system error dialog. It doesn't send data anywhere.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"cn.nubia.extcard\",\"description\":\"Nubia Chinese pay\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"cn.nubia.faceid\",\"description\":\"Face unlock lock screen.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"cn.nubia.factory\",\"description\":\"Hidden hardware tests.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"cn.nubia.fan\",\"description\":\"It has cooling fan activities.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"cn.nubia.fastpair\",\"description\":\"Ultra low latency? It's something for Nubia earphones.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"cn.nubia.filebrowser\",\"description\":\"File browser\\nIt's for file browser probably. Has Chinese components.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"cn.nubia.fileobserver\",\"description\":\"FileObserver\\nFileObserver? Has Chinese components.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"cn.nubia.forbid.selfstart.provider\",\"description\":\"Mainly used to manage application self-startup, convenient for users to adjust the policy of application self-startup.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"cn.nubia.gallery3d\",\"description\":\"Gallery\\nStock gallery with Chinese trackers.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"cn.nubia.gallerylockscreen\",\"description\":\"Wallpapers are displayed on the lock screen.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"cn.nubia.gamehelpmodule\",\"description\":\"It's a macro for the game. I think it's very useful if you're playing games.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"cn.nubia.gamehighlights\",\"description\":\"Red Magic Moment game recorder\\nI think it's very useful if you're playing games.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"cn.nubia.gamelauncher\",\"description\":\"Game Space Nubia\\nI think it's very useful if you're playing games.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"cn.nubia.gamenotes\",\"description\":\"Game Notes\\nGame Notes? Probably an optional thing.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"cn.nubia.gamepi\",\"description\":\"Needed for game optimization probably and also has something for Game Space\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"cn.nubia.garbagecleanwidget\",\"description\":\"Widget One-tap Cleanup\\nUseless Widget One-tap Cleanup. Useless frameworks.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"cn.nubia.gif\",\"description\":\"It's for creating GIFs\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"cn.nubia.gpu.drivers\",\"description\":\"It has GPU settings so better keep that.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"cn.nubia.harassintercept\",\"description\":\"Mainly used to intercept harassing and fraudulent phone calls and text messages,\\nwhile the user can also customize the way to intercept.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"cn.nubia.heartrate\",\"description\":\"Hidden? Heart Rate Detection\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"cn.nubia.hybrid\",\"description\":\"Quick Apps Preview for ads 3d. Has a lot of Chinese components.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"cn.nubia.identity\",\"description\":\"It's for personalized recommendations.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"cn.nubia.jobdispatcher\",\"description\":\"Mainly through the network to modify the basic data and functions of the self-developed application\\nmodule part of the cell phone system in the background. Also has neopush.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"cn.nubia.keymapcenter\",\"description\":\"It's for gaming right? Useless frameworks.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"cn.nubia.launcher\",\"description\":\"Launcher\\nStock Nubia Launcher.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"cn.nubia.monitor\",\"description\":\"Better keep this for gaming.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"cn.nubia.musicpicker.preset\",\"description\":\"Ringtones\\nMusic Picker for nubia phones.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"cn.nubia.myfile\",\"description\":\"File Manager\\nNubia File Manager.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"cn.nubia.neopush\",\"description\":\"Not needed for notifications. Has a lot of permissions.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"cn.nubia.neostore\",\"description\":\"App Store\\nNubia App Store\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"cn.nubia.owlsystem\",\"description\":\"Nubia data collection. It has a lot of permissions and it's spyware!\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"cn.nubia.packageoptimization\",\"description\":\"Nubia Package Optimization\\nNubia Package Optimization? Cleans cache and more\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"cn.nubia.paycomponent\",\"description\":\"Chinese pay Nubia\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"cn.nubia.persist\",\"description\":\"PersistService\\nPersistService? In code I found it's for logs.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"cn.nubia.phonemanualintegrate.preset\",\"description\":\"Useless User Guide\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"cn.nubia.photoeditor\",\"description\":\"Photo Editor\\nPhoto Editor. It has Baidu location so better turn off network for this app.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"cn.nubia.powersaving\",\"description\":\"Better keep this for power saving?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"cn.nubia.processmanager\",\"description\":\"Useless frameworks\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"cn.nubia.quickappwebserver\",\"description\":\"Another component of Quick Apps Preview for ads 3d.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"cn.nubia.quicksearchbox\",\"description\":\"Useless quick search box\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"cn.nubia.ramdisk\",\"description\":\"Probably it's for optimization\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"cn.nubia.sar\",\"description\":\"PersistService\\nPersistService? In code I found it's for logs.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"cn.nubia.security2\",\"description\":\"It's not only security but it has a lot of useful settings.\\nBetter keep this.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"cn.nubia.sensor\",\"description\":\"Hidden sensor calibration.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"cn.nubia.setupwizard\",\"description\":\"Setup Wizard\\nYou don't need it after first-boot setup.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"cn.nubia.share\",\"description\":\"share video\\nNubia share video. You can share video by this app probably.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"cn.nubia.smartrecognition\",\"description\":\"It's for smart things\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"cn.nubia.supersnap\",\"description\":\"Super Snap Shot, Screenshot\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"cn.nubia.systemupdate\",\"description\":\"System Update\\nProvides system updates for nubia\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"cn.nubia.theme.apply\",\"description\":\"Needed for theme apply\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"cn.nubia.thememanager\",\"description\":\"Theme Manager\\nStock Nubia Theme Manager\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"cn.nubia.touping\",\"description\":\"Needed for screen cast\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"cn.nubia.upgradeservice\",\"description\":\"Needed for upgrade service.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"cn.nubia.video\",\"description\":\"Video Player\\nNubia Video Player\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"cn.nubia.virtualgamehandle\",\"description\":\"Virtual joystick\\nVirtual joystick? Useless logs, tracking. Useless frameworks.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"cn.nubia.voiceassist\",\"description\":\"Nubia Voice\\nAssistant things.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"cn.nubia.woodpecker\",\"description\":\"Another tool for logs.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"cn.nubia.yulorepage\",\"description\":\"Yulorepage\\nHas only notifications thing.\\nNot very useful. It's something for China like yellow pages.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"cn.nubia.zappdatabackup\",\"description\":\"Backup App, Restore App\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"cn.nubia.ziconunity\",\"description\":\"Icon handling\\nIcon handling? It's for theme icons probably\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"cn.oneplus.nvbackup\",\"description\":\"NVBackupUI\\nRuns in the background on some phones.\\nHandles things related to OTA system updates?\\nSafe to disable, but might break OTA updates.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"cn.oneplus.oem_tcma\",\"description\":\"TCMA = Tiered Contention Multiple Access\\nRuns on boot.\\nA form of CSMA/CA, a cellular traffic management protocol. TCMA schedules transmission of different types of traffic based on urgency.\\nChina-only? (the \\\"cn\\\" in cn.oneplus is China's country code)\\nhttps://en.wikipedia.org/wiki/Carrier-sense_multiple_access_with_collision_avoidance\\nhttps://patents.google.com/patent/US20020163933A1\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"cn.oneplus.oemtcma\",\"description\":\"TCMA = Tiered Contention Multiple Access\\nRuns on boot.\\nA form of CSMA/CA, a cellular traffic management protocol. TCMA schedules transmission of different types of traffic based on urgency.\\nChina-only? (the \\\"cn\\\" in cn.oneplus is China's country code)\\nhttps://en.wikipedia.org/wiki/Carrier-sense_multiple_access_with_collision_avoidance\\nhttps://patents.google.com/patent/US20020163933A1\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"cn.oneplus.opmms\",\"label\":\"OPMmsLocation\",\"description\":\"Determines your location when sending SMS/MMS?\\nChina-only? (\\\"cn\\\" is China's country code)\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"cn.oneplus.photos\",\"label\":\"Shot On OnePlus\",\"description\":\"Accessible through the Wallpapers selection menu.\\nProvides photos uploaded by OnePlus users, allowing you to set them as your wallpaper.\\nEach day, one new photo appears within the application.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"cn.wps.moffice.lite.meizu\",\"description\":\"WPS Office\\nChinese WPS Office\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"cn.wps.moffice_eng\",\"description\":\"WPS Office\\nChinese WPS Office pre-installed on Xiaomi devices.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"cn.wps.moffice_eng.xiaomi.lite\",\"description\":\"Chinese WPS Office\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"cn.wps.xiaomi.abroad.lite\",\"label\":\"Mi Doc Viewer\",\"description\":\"Allows users to view various types of documents on their Android devices like documents (*.doc/docx, *.ppt/pptx, *.xls/xlsx, *.pdf, *.wps, and *.txt) and it's powered by WPS Office\\nFYI: WPS is a Chinese closed-source software. It's as bad as Microsoft Office (privacy-wise)\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"cn.zte.recorder\",\"description\":\"ZTE Voice Recorder with... 33 permissions and talking with Baidu servers. Pithus analysis: https://beta.pithus.org/report/bab47d32f5b93cdf4d3a3cb082d1d0e7ba3e323356391b2d46e63617c1d15324\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.Qunar\",\"description\":\"Chinese partner app 'Qunar Travel'.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.UCMobile\",\"description\":\"Chinese UC Mobile.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.achievo.vipshop\",\"description\":\"Chinese some shop, normal user can uninstall it.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.activate.activatephone\",\"description\":\"Useless frameworks.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.adaptivebrightnessgo\",\"description\":\"Not related to adaptive brightness in the sliding bar. The APK is called `CameraLightSensor`, so I guess it's for the camera.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.agui.app.imei\",\"description\":\"IMEI Tool: Change MEID's & IMEI's of both SIM's\\nEnter *#*#08#*#* in the dial pad to access\\n\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.agui.app.memtester\",\"description\":\"Memory tester\\nHidden test menu. Used in diagnostics, normally invoked by MMI(Man-Machine Interface) Codes\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.agui.appblock\",\"description\":\"App blocker\\nSettings > Intelligent assistance: App blocker\\n Unihertz power management service killing background apps to improve battery performance.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.agui.batterystatsdumper\",\"description\":\"Battery Stats Dumper\\nLets you check and clear battery usage statistics.\\nEnter *#*#010#*#* in the dial pad to access this hidden menu.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.agui.game\",\"label\":\"Game mode\",\"description\":\"Blocks calls & notifications when selected APP's are open\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.agui.newsos\",\"description\":\"SOS\\nNotify emergency contacts. When triggered, will also put the phone in a low comsumption mode\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.agui.nfc\",\"description\":\"NFC card emulation: simulates various types of unencrypted entrance cards.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.agui.providers.pedometer\",\"description\":\"Toolbox > \\\"Pedometer\\\" Pedometer/step counter.\\nBecause of a feature that integrates with the lock sceen the System UI crashes when removed.\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.agui.screenshot\",\"description\":\"Screenshot\\nScreenshot utility triggered when double tapping the Red Button\\n\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.agui.studentmodel\",\"label\":\"Student Mode\",\"description\":\"Locks down your phone to reduce distractions\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.agui.update\",\"description\":\"\\\"Wireless Update\\\" Settings > About Phone : Sytem update.\\nRemoving will prevent Automatic Wireless Updates\\n\",\"removal\":\"caution\",\"required_by\":[\"com.agui.update.overlay\"],\"type\":\"oem\"},{\"id\":\"com.agui.update.overlay\",\"description\":\"Overlay for com.agui.update. Overlay are usually themes.\\n\",\"removal\":\"caution\",\"dependencies\":[\"com.agui.update\"],\"type\":\"oem\"},{\"id\":\"com.agui.usbcamera\",\"description\":\"Toolbox > \\\"USB Camera\\\" Only usefull if you want to use a USB Camera\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.aiunit.aon\",\"description\":\"AONService. ColorOS Smart Features.\\nApp run with AI and phone sensors to recognize what best scenario for run privacy protection and the smart features OPPO offer.\\n 1. Smart Spying Prevention, 2. Smart Air Control, 3. Smart Rotation, 4. Smart Always On Display.\\nhttps://community.oppo.com/thread/1446120575440257025\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.alam.overlay.android\",\"description\":\"It looks like the unused stuff has been translated into Indonesian.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.alam.overlay.android.systemui\",\"description\":\"It looks like the unused stuff has been translated into Indonesian.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.alcatel.mcrm\",\"description\":\"enjoy.now\\nIt's an app for debugging and requires Google Play services.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.amap.android.location\",\"description\":\"Chinese location. Not needed for location.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.amazon.amazonvideo.livingroom\",\"description\":\"Prime video\\nhttps://play.google.com/store/apps/details?id=com.amazon.amazonvideo.livingroom&hl=en&gl=US\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.android.BBKClock\",\"description\":\"Clock\\nVivo clock app. App for manage alarms.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.android.BBKCrontab\",\"description\":\"Task timer\\nIt's for scheduling tasks.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.android.DeviceAsWebcam\",\"label\":\"Webcam Service\",\"description\":\"For using smartphone as a webcam. A dependency for Private space on Pixel devices.\",\"web\":[\"https://source.android.com/docs/security/features/private-space\"],\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.android.LGSetupWizard\",\"description\":\"The first time you turn your device on, a Welcome screen is displayed. It guides you through the basics of setting up your device.\\nIt's the setup for LG services.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.android.SystemUIResOverlay\",\"description\":\"Threekey volume guide pictures.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.android.VideoPlayer\",\"description\":\"i Video\\nVideo player app for vivo phones.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.android.WingFactoryCamera\",\"description\":\"MiCaliTool\\nCamera Calibration.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.android.angle\",\"description\":\"Have only empty main activity. it's not a joke.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.android.backup\",\"description\":\"Xiaomi Backup and Restore feature (mislead package name).\\nThis package was replaced by 'com.miui.backup' on newer models.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.android.bbk.lockscreen3\",\"description\":\"Lock\\nNeeded for lockscreen?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.android.bbklog\",\"description\":\"Log Collection\\nLogs everything.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.android.bbkmusic\",\"description\":\"i Music\\nMusic app with Chinese trackers.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.android.bips.auto_generated_rro_product__\",\"description\":\"Unused auto generated code: color icon code to print service.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.android.bips.overlay.pixel\",\"description\":\"it's overlay only to icon color.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.android.bluetooth.auto_generated_rro_product__\",\"description\":\"Random generated code app, in TECNO Phone found headphones images in the app to Settings.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.android.bluetooth.bthelper\",\"description\":\"BtHelper\\nit's only for Apple Air Pods. it's used to check the battery level of AirPods headphones.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.android.bluetooth.oplus.overlay\",\"description\":\"Overlay to 'com.android.bluetooth'.\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.android.bluetooth.overlay\",\"description\":\"Not a standard package provided by the Android framework.\\nIt seems to be a custom package specific to a particular Android device or custom ROM.\\nBased on the search results, there is no official documentation or information available about in the Android documentation or developer resources.\\nIt is possible that this package contains custom overlays or modifications related to the Bluetooth functionality on a specific device or ROM.\\nOverlays are used to customize the behavior or appearance of the Android system without modifying the core framework.\\nThese overlays can be provided by device manufacturers or custom ROM developers to add or modify features specific to their devices.\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.android.bluetooth.tempow\",\"description\":\"Implementation of a improved bluetooth protocol (developed by french company Tempow)\\nhttps://www.tempow.com/tap\\nNOTE: This is NOT an AOSP package. It is OEMs who choose to implement this procotol or not.\\nFor now, only TCL has this.\\n\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.android.camera.overlay\",\"description\":\"Unused? In code found some sounds to camera app\\nand random images that looks like a calibration.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.android.camera2\",\"description\":\"Xiaomi Camera (I don't know why they kept this package name. It's really confusing.)\\nIt's a proprietary app based on the AOSP sources:\\nhttps://android.googlesource.com/platform/packages/apps/Camera2/+/master/src/com/android/camera\\n\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.android.camerabigballconfig.overlay\",\"description\":\"Configures default Qr Code component\\ncom.google.android.gms .mlkit.barcode.ui.PlatformBarcodeScanningActivityProxy. Not needed to camera or scan QR Code.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.android.cameraextensions\",\"description\":\"CameraExtensionsProxy.\\nCamera-related third-party apps can call Android camera extensions such as Portrait, Night Mode, and HDR, which doesn't seem to work significantly on MIUI.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.android.captiveportallogin.overlay\",\"description\":\"it's overlay only to icon color.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.android.carrierconfig.overlay.product\",\"description\":\"Better keep this for LTE network.\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.android.cellbroadcast.overlay\",\"description\":\"Unused overlay without code. Only for Test message.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.android.cellbroadcastreceiver.overlay.base.s600ww\",\"description\":\"Nokia theme overlay for com.android.cellbroadcastreceiver\",\"removal\":\"caution\",\"dependencies\":[\"com.android.cellbroadcastreceiver\"],\"type\":\"oem\"},{\"id\":\"com.android.cellbroadcastreceiver.overlay.pixel\",\"description\":\"Useless code to cellbroadcastreceiver\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.android.cellbroadcastservice.overlay\",\"description\":\"Unused overlay. Cross-SIM duplicate detection false.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.android.cellbroadcastservice.overlay.pixel\",\"description\":\"Useless code to cellbroadcastservice\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.android.compos.payload\",\"description\":\"CompOS\\nHas something to 'com.android.compos'.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.android.connectivity.resources.nt.overlay\",\"description\":\"WiFi configs. Better don't risk\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.android.connectivity.resources.overlay\",\"description\":\"Cause bootloop?\\nFound in TECNO phone, in overlay there's a notification saying 'No Internet As Dialog When High Priority'.\\nCan someone test it?\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.android.dlna.service\",\"description\":\"Screen cast OPPO.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.android.dreams.overlay.basic\",\"description\":\"Overlay to 'com.android.dreams.basic' has icons png.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.android.dreams.overlay.phototable\",\"description\":\"Overlay to 'com.android.dreams.phototable' has icons png.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.android.email.partnerprovider.overlay\",\"description\":\"Theme overlay for partnerprovider?\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.android.fileexplorer\",\"description\":\"Xiaomi/Mi File Explorer (Again it's a really poor choice for a package name considering it is not the AOSP File explorer)\\nIt's a Closed-source app based on the AOSP version.\\n\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.android.flyme.bridge.softsim\",\"description\":\"it's for softsim? No activities, looks like a useless framework.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.android.frameworkhwext\",\"description\":\"There is not much info but others seem to have disabled this and similar, see:\\nhttps://forum.xda-developers.com/t/guide-list-of-bloatware-safe-to-remove-how-to-do-it.3866647.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.android.frameworkhwnext.honor\",\"description\":\"Framework necessary for Themes app to launch\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.android.gallery3d.refocus\",\"description\":\"\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.android.globalFileexplorer\",\"label\":\"File Manager\",\"description\":\"Xiaomi File Manager.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.android.hbmsvmanager\",\"description\":\"Its app for calibration screen and debugging.\\nHBM SV is unknown.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.android.hbmsvmanager.auto_generated_rro_product__\",\"description\":\"unused png files, calibration. it's from (com.android.hbmsvmanager)\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.android.huawei.HiMediaEngine\",\"description\":\"It's for debugging camera. Has all camera features and report.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.android.huawei.projectmenu\",\"description\":\"ProjectMenu\\nHidden settings not available for users. it's useless.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.android.hwmirror\",\"description\":\"Mirror\\nLets you use your phone as a mirror...\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.android.imedia.syncplay\",\"description\":\"Party Mode\\nParty Mode lets you sync music playback across multiple devices.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.android.imsserviceentitlement\",\"description\":\"It's needed for WiFi calling.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.android.incallui\",\"label\":\"Phone\",\"description\":\"Xiaomi (and OnePlus) Phone dialer.\\nFetches APN lists on some phones. Package name is highly misleading.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.android.incallui.overlay\",\"description\":\"App without code and safe to remove.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.android.inputmethod.pinyin\",\"description\":\"It is the built in software keyboard for LDPlayer. Getting rid of this breaks any keyboard input including from PC hardware keyboard.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.android.inputsettings.overlay.miui\",\"description\":\"Keyboard demo found. It's something to miinput unused Chinese!\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.android.keyguard\",\"label\":\"HUAWEI magazine unlock\",\"description\":\"It's a proprietary app based on the AOSP package called com.android.keyguard. Lets you customize your lock screen wallpapers.\\nIf you have EMUI 10 or older, check the AOSP file, as Huawei uses AOSP package name for their own app.\",\"web\":[\"https://consumer.huawei.com/en/support/content/en-us00206571/\",\"https://forum.xda-developers.com/honor-6x/how-to/guide-list-bloat-software-emui-safe-to-t3700814\",\"https://forum.xda-developers.com/huawei-p40-pro/how-to/adb-debloating-t4088633\",\"https://github.com/Universal-Debloater-Alliance/universal-android-debloater-next-generation/issues/330\"],\"removal\":\"caution\",\"warning\":\"Breaks home and recents button on Xiaomi Mi Pad.\",\"type\":\"oem\"},{\"id\":\"com.android.launcher\",\"description\":\"OPPO Launcher\\nBreaks swipe up gestures after remove.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.android.launcher3.tv\",\"description\":\"TV\\nNot sure if it's useless frameworks or for the launcher or TV launcher.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.android.managedprovisioning.overlay\",\"description\":\"Random useless code to com.android.managedprovisioning\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.android.mediacenter\",\"description\":\"Huawei music app. (Yeah they messed up with the package name)\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.android.messaging\",\"description\":\"Android default messaging app\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.android.microdroid.empty_payload\",\"description\":\"empty app that has permission to MANAGE VIRTUAL MACHINE.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.android.midrive\",\"description\":\"Mi Drive \\nMisleading package name. It is indeed a closed-source Xiaomi application.\\nAllow for cloud storage (on Mi Cloud) and syncing across multiple Android devices.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.android.mmi\",\"description\":\"Not an AOSP package at all\\nHidden MMI test app \\nMMI = Man Machine Interface ?\\n\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.android.mmifm\",\"description\":\"FM Radio_wrh\\nIt looks like unused FM Radio stuff without activity, adding favorite channels.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.android.mmisubtest\",\"description\":\"P-Sensor Calibration\\nIt's useless and hidden.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.android.mmitest\",\"description\":\"Hardware Testing\\nHidden testing hardware things.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.android.mms.overlay.cmcc\",\"description\":\"Likely overlay themes from China Mobile Communications Corporation(CMCC) or China Telecom(CT).\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.android.mms.overlay.ct\",\"description\":\"Likely overlay themes from China Mobile Communications Corporation(CMCC) or China Telecom(CT).\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.android.mms.service.plugin.UaProfUrl\",\"description\":\"Useless plugin for logs\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.android.mms.service.plugin.UserAgent\",\"description\":\"Useless plugin for logs. Collects data.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.android.modemnotifier\",\"description\":\"Modem Info\\nHidden Modem Info? Used for logs.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.android.networksettings.overlay.ct\",\"description\":\"Likely overlay themes from China Mobile Communications Corporation(CMCC) or China Telecom(CT).\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.android.nfc.auto_generated_rro_product__\",\"description\":\"Random useless code to com.android.nfc\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.android.nfc.auto_generated_rro_vendor__\",\"description\":\"Random useless code to com.android.nfc\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.android.omadm.service\",\"description\":\"Oma Device Management, There are carrier tools, no firmware update found.\\nThe code also includes Subscription Index and configures FOTA.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.android.omadm.service.auto_generated_rro_product__\",\"description\":\"Useless config metrics code\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.android.omadm.service.auto_generated_rro_vendor__\",\"description\":\"Useless devinfo model\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.android.opasuwintegrationsample\",\"description\":\"Optimized Setup Wizard Integration Sample code.\\nCan be used to create a custom setup wizard, such as one created by a manufacturer that runs after the initial Android Setup Wizard.\\nDoes not appear to actually run. It is sample code and should be able to be removed safely.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.android.overlay.calendar\",\"description\":\"Overlay to 'com.android.calendar' logo calendar icons.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.android.overlay.camera2\",\"description\":\"Overlay to 'com.android.camera2' png icons.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.android.overlay.contacts\",\"description\":\"Overlay to 'com.android.contacts' png icons.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.android.overlay.dialer\",\"description\":\"Overlay to 'com.android.dialer' png icons.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.android.overlay.dynamiciconconfig\",\"description\":\"Overlay to 'com.android.launcher3' calendar, clock component name.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.android.overlay.email\",\"description\":\"Overlay to 'com.android.email' icons png.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.android.overlay.emergency\",\"description\":\"Overlay to 'com.android.emergency' icons png.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.android.overlay.fmradio\",\"description\":\"Overlay to 'com.android.fmradio' icons png.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.android.overlay.gallery3d\",\"description\":\"Overlay to 'com.android.gallery3d' icons png.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.android.overlay.gmscontactprovider\",\"description\":\"Checked in miui 14.\\nIncorrect named thing to sync metadata contacts or gms?\\nmetadata_sync_pacakge com.google.android.gms\\nNo effects after remove.\\n(detected on miui 14 with android 13 phones)\\nit's an unused overlay.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.android.overlay.gmssettingprovider\",\"description\":\"Checked in miui 14.\\nHave some stuff about google gms: backup.BackupTransportService.\\nUseless backup things, without it backup and cloud work.\\nMaybe it's used for backup settings, but probably not, and if it is, I don't think you need it.\\n(detected on miui 14 with android 13 phones)\\nIt's an unused overlay.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.android.overlay.gmssettings\",\"description\":\"Unused overlay to 'com.google.android.apps.safetyhub'.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.android.overlay.gmstelecomm\",\"description\":\"Overlay app to 'com.google.android.dialer', 'com.android.incallui'.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.android.overlay.gmstelephony\",\"description\":\"Overlay app to 'com.google.android.dialer', 'com.google.android.gms'.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.android.overlay.launcher3\",\"description\":\"Overlay to 'com.android.launcher3' icons png.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.android.overlay.livepicker\",\"description\":\"Overlay to 'com.android.wallpaper.livepicker' icons png.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.android.overlay.logmanager\",\"description\":\"Overlay to 'com.android.logmanager' icons png.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.android.overlay.messaging\",\"description\":\"Overlay to 'com.android.messaging' icons png.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.android.overlay.music\",\"description\":\"Overlay to 'com.android.music' icons png.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.android.overlay.quicksearchbox\",\"description\":\"Overlay to 'com.android.quicksearchbox' icons png.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.android.overlay.settings\",\"description\":\"Overlay to 'com.android.settings' icons png.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.android.overlay.soundrecorder\",\"description\":\"Overlay to 'com.android.soundrecorder' icons png.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.android.overlay.stk\",\"description\":\"Overlay to 'com.android.stk' icons png.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.android.overlay.wallpaper\",\"description\":\"Overlay to 'com.android.wallpaper' icons png.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.android.partnerbrowsercustomizations.btl.s600ww.overlay\",\"description\":\"Theme overlay for some browser customization?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.android.pedometer\",\"description\":\"Pedometer\\nIt's for displaying steps probably.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.android.phone.auto_generated_rro_product__\",\"description\":\"Configs to phone auto generated but better keep.\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.android.phone.auto_generated_rro_vendor__\",\"description\":\"Configs to phone auto generated but better keep.\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.android.phone.injection\",\"description\":\"Possibly safe, or useless as removal doesn't seem to change anything.\\nIt's a very small APK, it's a single class which only assigns a constant numeric value to a variable called 'telephony_injection'\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.android.phone.overlay.carriersettings\",\"description\":\"Overlay to (com.google.android.carrier)\\nAnyway, this app doesn't exist on your phone I guess.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.android.phone.overlay.miui\",\"description\":\"Contains specific modifications and enhancements made by MIUI to the phone app's user interface and functionality.\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.android.phone.overlay.motcommon\",\"description\":\"Related to Motorola's custom overlay for Phone and other UI elements.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.android.poweroffhandlerapp\",\"description\":\"I found only lockDevice and Shutdown Phone Animation\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.android.powertouch\",\"description\":\"Moto Power Touch\\nlets you customize the double tap power button gesture to launch an app or shortcut of your choice.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.android.providers.calendar.overlay.base.s600ww\",\"description\":\"Some overlay for a content provider package. Overlays are usually themes.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.android.providers.contacts.auto_generated_rro_product__\",\"description\":\"Incorrect named thing to sync metadata gms?\\nmetadata_sync_pacakge com.google.android.gms\\nNo effects after remove.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.android.providers.contacts.overlay.pixel\",\"description\":\"in overlay found: metadata_sync_pacakge: com.google.android.gms. Not needed.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.android.providers.media.overlay.pixel\",\"description\":\"Useless code to photos cloudpicker.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.android.providers.privacyprotection\",\"description\":\"It has permission protect and logs.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.android.providers.settings.auto_generated_rro_product__\",\"description\":\"Useless overlay to Backup google. Backup works without it.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.android.providers.settings.auto_generated_rro_vendor__\",\"description\":\"rro = Runtime Resources Overlay.\\nChanges values of a package config, based in the overlay definitions (heavily used by OEMs to customize the look and feel of Android).\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.android.providers.settings.btl.s600ww.overlay\",\"description\":\"Some overlay for a content provider package. Overlays are usually themes.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.android.providers.settings.overlay.base.s600ww\",\"description\":\"Some overlay for a content provider package. Overlays are usually themes.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.android.providers.settings.overlay.common\",\"description\":\"Better keep this for acceleration? Better don't risk.\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.android.providers.tctdatahubprovider\",\"description\":\"\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.android.providers.telephony.auto_generated_rro_product__\",\"description\":\"Configs to providers telephony auto generated but better keep.\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.android.providers.telephony.overlay.carriersettings\",\"description\":\"Overlay to (com.google.android.carrier)\\nAnyway, this app doesn't exist on your phone I guess.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.android.providers.tv\",\"description\":\"TV Storage\\nProvides TV listings.\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.android.qns\",\"description\":\"Apn service, emergency calling, not sure how useful this app is.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.android.retaildemo.overlay.base.s600ww\",\"description\":\"Theme overlay for Retail demonstration mode?\\nhttps://en.wikipedia.org/wiki/Demo_mode\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.android.role.notes.enabled\",\"label\":\"Notes Role enabled\",\"description\":\"Unknown overlay, sets default notes.\",\"removal\":\"caution\",\"warning\":\"Removing the package breaks seamless disabling and enabling of the developer options on Google Pixels.\",\"type\":\"oem\"},{\"id\":\"com.android.safetycenter.resources.overlay\",\"description\":\"Safety Center overlay.\\nOverlays work by mapping resources defined in the overlay package to resources defined in the target package. When an app attempts to resolve the value of a resource in the target package, the value of the overlay resource the target resource is mapped to is returned instead.\\nSafety Center provides redirection entries so that users can access specific security and privacy settings. Safety Center also identifies issues that users can fix on their devices or accounts, by combining dynamic data received from multiple sources. This data provides users with a general safety status with specific recommendations.\\nhttps://source.android.com/docs/core/runtime/rros\\nhttps://source.android.com/docs/security/safety-center/overview\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.android.safetycenter.styles.overlay\",\"description\":\"Safety Center styles overlay.\\nOverlays work by mapping resources defined in the overlay package to resources defined in the target package. When an app attempts to resolve the value of a resource in the target package, the value of the overlay resource the target resource is mapped to is returned instead.\\nSafety Center provides redirection entries so that users can access specific security and privacy settings. Safety Center also identifies issues that users can fix on their devices or accounts, by combining dynamic data received from multiple sources. This data provides users with a general safety status with specific recommendations.\\nhttps://source.android.com/docs/core/runtime/rros\\nhttps://source.android.com/docs/security/safety-center/overview\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.android.safetyregulatoryinfo\",\"description\":\"Unused? This is what you can find probably in settings:\\nsetSavePassword, setSaveFormData, setBlockNetworkLoads, setJavaScriptEnabled.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.android.safetyregulatoryinfo.auto_generated_rro_product__\",\"description\":\"Useless unused Chinese images.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.android.screenshot\",\"description\":\"Default android screenshot tool\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.android.sdm.plugins.connmo\",\"description\":\"ConnMO\\nNotifications for video calling?\\nAlso Apn Service.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.android.sdm.plugins.dcmo\",\"description\":\"Carrier OMADM\\nAnother thing to VoLTE.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.android.sdm.plugins.diagmon\",\"description\":\"diagnostic plugin\\nit's app for hidden diagnostics.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.android.secretcode\",\"description\":\"SecretCode\\nHidden app shows some secret codes.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.android.server.deviceconfig.resources\",\"description\":\"DeviceConfigServiceResources (Server*?). Part of com.android.configinfrastructure. Resources for the device's default server config.\\nhttps://cs.android.com/android/platform/superproject/main/+/main:packages/modules/ConfigInfrastructure/service/ServiceResources/Android.bp\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.android.server.telecom.auto_generated_rro_product__\",\"description\":\"Configs to server telecom auto generated but better keep.\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.android.server.telecom.overlay.miui\",\"description\":\"Manage calls\\nit's used for manage calls ui.\\nit's important overlay to calling.\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.android.service.ims\",\"description\":\"It's for subscribing to the presence information using RCS.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.android.settingaccessibility\",\"description\":\"Accessibility settings\\nIt should be important for settings.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.android.settings.auto_generated_rro_product__\",\"description\":\"Configs to settings auto generated but better keep.\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.android.settings.auto_generated_rro_vendor__\",\"description\":\"Configs to settings auto generated but better keep.\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.android.settings.os.overlay\",\"description\":\"Looks unused, but not confirmed. Found in app 'icon file download', Vibration switch. Icon user found, overlay to 'com.android.settings'.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.android.settings.overlay.SettingsFuture\",\"description\":\"Configs to settings auto generated but better keep.\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.android.settings.overlay.cmcc\",\"description\":\"Likely overlay themes from China Mobile Communications Corporation(CMCC) or China Telecom(CT).\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.android.settings.overlay.common\",\"description\":\"Color mode config you can find it in settings\\nit's something about: natural, boosted, saturated, adaptive.\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.android.settings.overlay.ct\",\"description\":\"Likely overlay themes from China Mobile Communications Corporation(CMCC) or China Telecom(CT).\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.android.settings.overlay.filesgoogle\",\"description\":\"Useless overlay to Google Files.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.android.settings.overlay.g1azg\",\"description\":\"Configs to settings auto generated but better keep.\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.android.settings.overlay.gb17l\",\"description\":\"Configs to settings auto generated but better keep.\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.android.settings.overlay.gb62z\",\"description\":\"Configs to settings auto generated but better keep.\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.android.settings.overlay.gx7as\",\"description\":\"Configs to settings auto generated but better keep.\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.android.settings.overlay.miui\",\"description\":\"This app is without code and safe to remove.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.android.settings.overlay.personalsafety\",\"description\":\"Useless overlay to personalsafety, safetyhub\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.android.settings.overlay.pixel2021\",\"description\":\"Configs to settings auto generated but better keep.\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.android.settings.overlay.product\",\"description\":\"Useless overlay to images phone white and black, it's for camera MP info.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.android.settings.overlay.turbo\",\"description\":\"Useless overlay to smart battery images, videos. And it's probably unused.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.android.settings.resoverlay\",\"description\":\"Found in the code \\\"Declaration of Conformity\\\" on the TECNO phone, is probably unused, as it cannot be found in the Settings or anywhere else.\\nIt can be safely removed, the Settings still work without this app.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.android.settingsaccessibility\",\"description\":\"Accessibility settings (tools for vision, hearing and physical impairments)\\nSometimes, third-party apps may require special permissions in the accessibility settings in order to work properly.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.android.setupwizard.overlay\",\"description\":\"It's needed only on first-boot setup.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.android.setupwizard.overlay.ontim\",\"description\":\"Useless overlay to welcome image First-boot setup.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.android.simappdialog.auto_generated_rro_product__\",\"description\":\"Useless overlay to simappdialog.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.android.soundpicker.auto_generated_rro_product__\",\"description\":\"Has colors, dialog things, autogenerated code, but someone can confirm that app is safe to remove?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.android.stk.overlay.miui\",\"description\":\"'SIM Toolkit' name app only found.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.android.store\",\"description\":\"An app called TCL Mobile that you cannot disable and just opens up a link to the OEM in the browser.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.android.supl\",\"description\":\"SUPL20Service\\nGPS still works without it. Probably needed to location in China.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.android.systemui.auto_generated_rro_product__\",\"description\":\"Configs to systemui auto generated but better keep.\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.android.systemui.auto_generated_rro_vendor__\",\"description\":\"Configs to systemui auto generated but better keep.\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.android.systemui.feature_cover\",\"description\":\"It looks like a very important app.\\nImportant configs to android?\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.android.systemui.miui.optimization.overlay\",\"description\":\"In the code founded: navigationcolor to red.\\nUnused overlay.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.android.systemui.notch.overlay\",\"description\":\"It have something to Display Cutout. Better dont touch it.\\nImportant configs to display.\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.android.systemui.os.overlay\",\"description\":\"Icon user found, overlay to 'com.android.systemui'.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.android.systemui.overlay.charging.anim.alita_supervooc2\",\"description\":\"Charging phone animation from a lot of PNG files\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.android.systemui.overlay.charging.anim.siphon_wireless\",\"description\":\"Wireless charging animation for OnePlus phones.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.android.systemui.overlay.cmcc\",\"description\":\"Likely overlay themes from China Mobile Communications Corporation(CMCC) or China Telecom(CT).\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.android.systemui.overlay.ct\",\"description\":\"Likely overlay themes from China Mobile Communications Corporation(CMCC) or China Telecom(CT).\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.android.systemui.overlay.fingerprint.anim.ccyh\",\"description\":\"Fingerprint animation from a lot of PNG files\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.android.systemui.overlay.fingerprint.anim.cosmos\",\"description\":\"Fingerprint Animation Cosmos when unlocking phone.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.android.systemui.overlay.fingerprint.anim.fireworks\",\"description\":\"Fingerprint Animation Fireworks when unlocking phone.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.android.systemui.overlay.fingerprint.anim.fy\",\"description\":\"Fingerprint Animation Fy when unlocking phone.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.android.systemui.overlay.fingerprint.anim.jhsy\",\"description\":\"Fingerprint animation from a lot of PNG files\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.android.systemui.overlay.fingerprint.anim.jslz\",\"description\":\"Fingerprint animation from a lot of PNG files\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.android.systemui.overlay.fingerprint.anim.lgsy\",\"description\":\"Fingerprint animation from a lot of PNG files\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.android.systemui.overlay.fingerprint.anim.nlgs\",\"description\":\"Fingerprint animation from a lot of PNG files\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.android.systemui.overlay.fingerprint.anim.none\",\"description\":\"Fingerprint Animation None when unlocking phone.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.android.systemui.overlay.fingerprint.anim.ripple\",\"description\":\"Fingerprint Animation Ripple when unlocking phone.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.android.systemui.overlay.fingerprint.anim.stripe\",\"description\":\"Fingerprint Animation Stripe when unlocking phone.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.android.systemui.overlay.fingerprint.anim.sw\",\"description\":\"Fingerprint Animation Sw when unlocking phone.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.android.systemui.overlay.fingerprint.anim.tyjw\",\"description\":\"Fingerprint animation from a lot of PNG files\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.android.systemui.overlay.fingerprint.anim.xklc\",\"description\":\"Fingerprint animation from a lot of PNG files\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.android.systemui.overlay.gms\",\"description\":\"Useless overlay to systemui gms\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.android.systemui.overlay.miui\",\"description\":\"App without code and safe to remove.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.android.systemui.overlay.pong\",\"description\":\"Better keep this for config temperature? Better don't risk.\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.android.systemui.overlay.spacewar\",\"description\":\"Better keep this for config temperature? Better don't risk.\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.android.theme.color.amethyst\",\"description\":\"Android color accent only for Google Pixel or AOSP or Motorola\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.android.theme.color.aquamarine\",\"description\":\"Android color accent only for Google Pixel or AOSP or Motorola\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.android.theme.color.black\",\"description\":\"Android color accent only for google pixel or aosp or motorola\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.android.theme.color.cinnamon\",\"description\":\"Android color accent only for google pixel or aosp or motorola\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.android.theme.color.darklake\",\"description\":\"Android color accent only for Google Pixel or AOSP or Motorola\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.android.theme.color.dorange\",\"description\":\"Android color accent only for Google Pixel or AOSP or Motorola\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.android.theme.color.dpurple\",\"description\":\"Android color accent only for Google Pixel or AOSP or Motorola\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.android.theme.color.green\",\"description\":\"Android color accent only for google pixel or aosp or motorola\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.android.theme.color.lgreen\",\"description\":\"Android color accent only for Google Pixel or AOSP or Motorola\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.android.theme.color.ocean\",\"description\":\"Android color accent only for google pixel or aosp or motorola\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.android.theme.color.orchid\",\"description\":\"Android color accent only for google pixel or aosp or motorola\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.android.theme.color.parasailing\",\"description\":\"Android color accent only for Google Pixel or AOSP or Motorola\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.android.theme.color.purple\",\"description\":\"Android color accent only for google pixel or aosp or motorola\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.android.theme.color.saffron\",\"description\":\"Android color accent only for Google Pixel or AOSP or Motorola\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.android.theme.color.sand\",\"description\":\"Android color accent only for Google Pixel or AOSP or Motorola\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.android.theme.color.slate\",\"description\":\"Android color accent only for Google Pixel or AOSP or Motorola\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.android.theme.color.space\",\"description\":\"Android color accent only for google pixel or aosp or motorola\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.android.theme.color.tangerine\",\"description\":\"Android color accent only for Google Pixel or AOSP or Motorola\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.android.theme.font.ArchivoSemiBold\",\"description\":\"Font ArchivoSemiBold\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.android.theme.font.Exo2Regular\",\"description\":\"Font Exo2Regular\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.android.theme.font.RobotoSlabRegular\",\"description\":\"Font RobotoSlabRegular\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.android.theme.font.RookeryRegular\",\"description\":\"Font RookeryRegular\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.android.theme.icon.round\",\"description\":\"Android icon shape only for Google Pixel or AOSP or Motorola\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.android.theme.icon.roundedrect\",\"description\":\"Android color accent only for google pixel or aosp or motorola\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.android.theme.icon.squircle\",\"description\":\"Android color accent only for google pixel or aosp or motorola\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.android.theme.icon.teardrop\",\"description\":\"Android color accent only for google pixel or aosp or motorola\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.android.theme.icon_pack.circular.android\",\"description\":\"Android icon pack only for google pixel or aosp or motorola\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.android.theme.icon_pack.circular.launcher\",\"description\":\"Android icon pack only for google pixel or aosp or motorola\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.android.theme.icon_pack.circular.settings\",\"description\":\"Android icon pack only for google pixel or aosp or motorola\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.android.theme.icon_pack.circular.systemui\",\"description\":\"Android icon pack only for google pixel or aosp or motorola\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.android.theme.icon_pack.circular.themepicker\",\"description\":\"Android icon pack only for google pixel or aosp or motorola\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.android.theme.icon_pack.filled.android\",\"description\":\"Android icon pack only for google pixel or aosp or motorola\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.android.theme.icon_pack.filled.launcher\",\"description\":\"Android icon pack only for google pixel or aosp or motorola\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.android.theme.icon_pack.filled.settings\",\"description\":\"Android icon pack only for google pixel or aosp or motorola\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.android.theme.icon_pack.filled.systemui\",\"description\":\"Android icon pack only for google pixel or aosp or motorola\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.android.theme.icon_pack.filled.themepicker\",\"description\":\"Android icon pack only for google pixel or aosp or motorola\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.android.theme.icon_pack.kai.android\",\"description\":\"Android icon pack only for Google Pixel or AOSP or Motorola\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.android.theme.icon_pack.kai.launcher\",\"description\":\"Android icon pack only for Google Pixel or AOSP or Motorola\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.android.theme.icon_pack.kai.settings\",\"description\":\"Android icon pack only for Google Pixel or AOSP or Motorola\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.android.theme.icon_pack.kai.systemui\",\"description\":\"Android icon pack only for Google Pixel or AOSP or Motorola\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.android.theme.icon_pack.kai.themepicker\",\"description\":\"Android icon pack only for Google Pixel or AOSP or Motorola\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.android.theme.icon_pack.rounded.android\",\"description\":\"Android icon pack only for google pixel or aosp or motorola\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.android.theme.icon_pack.rounded.launcher\",\"description\":\"Android icon pack only for google pixel or aosp or motorola\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.android.theme.icon_pack.rounded.settings\",\"description\":\"Android icon pack only for google pixel or aosp or motorola\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.android.theme.icon_pack.sam.android\",\"description\":\"Android icon pack only for Google Pixel or AOSP or Motorola\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.android.theme.icon_pack.sam.launcher\",\"description\":\"Android icon pack only for Google Pixel or AOSP or Motorola\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.android.theme.icon_pack.sam.settings\",\"description\":\"Android icon pack only for Google Pixel or AOSP or Motorola\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.android.theme.icon_pack.sam.systemui\",\"description\":\"Android icon pack only for Google Pixel or AOSP or Motorola\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.android.theme.icon_pack.sam.themepicker\",\"description\":\"Android icon pack only for Google Pixel or AOSP or Motorola\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.android.theme.icon_pack.victor.android\",\"description\":\"Android icon pack only for Google Pixel or AOSP or Motorola\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.android.theme.icon_pack.victor.launcher\",\"description\":\"Android icon pack only for Google Pixel or AOSP or Motorola\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.android.theme.icon_pack.victor.settings\",\"description\":\"Android icon pack only for Google Pixel or AOSP or Motorola\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.android.theme.icon_pack.victor.systemui\",\"description\":\"Android icon pack only for Google Pixel or AOSP or Motorola\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.android.theme.icon_pack.victor.themepicker\",\"description\":\"Android icon pack only for Google Pixel or AOSP or Motorola\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.android.thememanager\",\"label\":\"Xioami Themes\",\"description\":\"Formerly, MIUI Themes.\\nXiaomi seems to love confusing package names.\\nLets you select and apply themes provided by Xiaomi.\\nHas a lot trackers. Running in the background.\",\"removal\":\"caution\",\"warning\":\"Disabling will break the ability to change the lock-screen wallpaper and ringtones in the OEM clock app.\",\"type\":\"oem\"},{\"id\":\"com.android.thememanager.gliobal_config.config.overlay\",\"description\":\"Blacklist of some wallpaper names. Useless.\\nThis app is not exist on miui china rom.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.android.thememanager.module\",\"description\":\"Something related to Xiaomi's theme manager?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.android.traceur.auto_generated_rro_product__\",\"description\":\"useless configs to traceur auto generated.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.android.traceur.auto_generated_rro_vendor__\",\"description\":\"useless configs to traceur auto generated.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.android.traceur.overlay.pixel\",\"description\":\"Unused colors to 5G\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.android.tv.frameworkpackagestubs\",\"description\":\"Activity Stub\\nHard to say by code, has browser provider and SQLite content.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.android.tv.settings\",\"description\":\"Needed for settings.\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.android.unisoc.telephony.server\",\"description\":\"Unisoc 4G and 5G drivers.\",\"web\":[\"https://xdaforums.com/t/oukitel-wp23-pro-unlocking-bootloader-rooting-gsi.4642483/#post-89239693\"],\"removal\":\"caution\",\"warning\":\"Removal will break incoming calls.\",\"type\":\"oem\"},{\"id\":\"com.android.updater\",\"description\":\"Mi Updater\\nProvides system updates\\nREMOVING THIS WILL BOOTLOOP YOUR DEVICE! Doesn't bootloop on MIUI 13 and above.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.android.vendors.bridge.softsim\",\"description\":\"Needed for virtual SIM.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.android.vivo.tws.vivotws\",\"description\":\"TWS\\nIt's for Vivo TWS earphones.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.android.voicemailomtp\",\"description\":\"Voicemail\\nVoicemail? I think no one uses that.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.android.wallpaper\",\"description\":\"Styles editor\\nNeeded for editing style UI\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.android.watermark\",\"description\":\"Hidden IMEI tests.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.android.wifi.resources.overlay.WifiRes6GhzEnable\",\"description\":\"Config to support wifi 6 Ghz? Any wifi have this?\\nIf you don't have 6 Ghz wifi then it's safe to disable.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.android.wifi.resources.overlay.WifiResDualStaApEnable\",\"description\":\"5 GHz WiFi support.\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.android.wifi.resources.overlay.WifiResSoftap80211axEnable\",\"description\":\"Important configs to wifi.\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.android.wifi.resources.overlay.common\",\"description\":\"System Wi-Fi resources Theme pack\\nGuessing it's a pack of themes for some Wi-Fi related system UI, based on the name.\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.android.wifi.resources.overlay.kalama\",\"description\":\"Needed for WiFi.\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.android.wifi.resources.overlay.motCommon\",\"description\":\"Related to Motorola's custom overlay for Wi-Fi connections.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.android.wifi.resources.overlay.oplus\",\"description\":\"Wi-Fi configs\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.android.wifi.resources.overlay.pineapple\",\"description\":\"A runtime resource overlay (RRO) is a package that changes the resource values of a target package at runtime. For example, an app installed on the system image might change its behavior based upon the value of a resource. Rather than hardcoding the resource value at build time, an RRO installed on a different partition can change the values of the app's resources at runtime.\\nRROs can be enabled or disabled. You can programmatically set the enable/disable state to toggle an RRO's ability to change resource values. RROs are disabled by default (however, static RROs are enabled by default).\\nhttps://source.android.com/docs/core/runtime/rros\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.android.wifi.resources.overlay.target\",\"description\":\"In code founded wifi configs.\\nImportant configs to WiFi.\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.android.wifi.resources.overlay.taro\",\"description\":\"Better keep this for config wifi? Better don't risk.\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.android.wifi.resources.xiaomi\",\"description\":\"Have some configs to network about: disconnected scan interval schedule\\nwifi11axsupportoverride, config_wifi_tcp_buffers\\nyou should keep this because it's maybe from settings.\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.android.wm.shell\",\"description\":\"Profile installer? App looks like a 'com.android.shell'.\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.android.yadayada\",\"description\":\"Disclaimer show to user, feedback, first boot setup.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.android.ztescreenshot\",\"description\":\"ScreenCapture\\nNeeded for screenshots.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.ape.cleanassist\",\"label\":\"Smart Assist\",\"description\":\"Provides junk cleaner feature for Wiko mobile\",\"removal\":\"replace\",\"suggestions\":\"cleaners\",\"type\":\"oem\"},{\"id\":\"com.ape.cleanassistoverlay\",\"description\":\"Overlay app for com.ape.cleanassist.\\nIf you uninstall it, this package should also be removed.\",\"required_by\":[\"com.ape.cleanassist\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.ape.easymode1\",\"label\":\"Simple Mode\",\"description\":\"Provides easy mode/quick access for Wiko mobile\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.ape.factory\",\"description\":\"Checks Build.SERIAL and ro.build.type\\nAll permissions and activities (camera, mic, battery, radio, led, sim, gps, nfc). Reads/writes to External Storage\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.ape.fmradio\",\"label\":\"FM Radio\",\"description\":\"FM Radio app for Wiko mobile\",\"removal\":\"replace\",\"suggestions\":\"radios\",\"type\":\"oem\"},{\"id\":\"com.ape.fmradiooverlay\",\"description\":\"Overlay app for com.ape.fmradio.\\nIf you uninstall it, this package should also be removed.\",\"required_by\":[\"com.ape.fmradio\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.ape.gamemode\",\"description\":\"Provides game mode feature for Wiko mobile.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.ape.massageexpress\",\"description\":\"Provides Wiko screen message feature\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.ape.mtbf\",\"description\":\"Named 'MTBF Tools'\\nDialer Code: 68238665. Uses SQLite Database. Reads/writes to External Storage. All sorts of permissions (camera, mic, battery, radio, led, sim, gps, nfc).\\nFound more details at https://twitter.com/dbauduin/status/940126704261099520 (archive: https://web.archive.org/web/20240330025312/https://twitter.com/dbauduin/status/940126704261099520)\\nHardcoded URLs (an api and a book): http://www.andykhan.com/jexcelapi\\nhttp://www.amazon.co.uk/exec/obidos/ASIN/0571058086/qid=1099836249/sr=1-3/ref=sr_1_11_3/202-6017285-1620664\\nhttps://www.amazon.co.uk/exec/obidos/ASIN/0571058086qid=1099836249/sr=1-3/ref=sr_1_11_3/202-6017285-1620664\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.ape.oneclean\",\"label\":\"Oneclean\",\"description\":\"Provides memory cleaner feature for Wiko mobile\",\"removal\":\"replace\",\"suggestions\":\"cleaners\",\"type\":\"oem\"},{\"id\":\"com.ape.smartgesture\",\"description\":\"Provide smart gesture feature for Wiko mobile\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.ape.soundrecorder\",\"description\":\"Sound recorder app for Wiko mobile\",\"removal\":\"replace\",\"suggestions\":\"audio_recorders\",\"type\":\"oem\"},{\"id\":\"com.ape.soundrecorderoverlay\",\"description\":\"Overlay app for com.ape.soundrecorder.\\nIf you uninstall it, this package should be removed also.\",\"required_by\":[\"com.ape.soundrecorder\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.ape.walkfit\",\"label\":\"Wiko Health\",\"description\":\"Walk counter and health for Wiko mobile\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.ape.weatherlive\",\"label\":\"Weather Live\",\"description\":\"Weather app for Wiko mobile\",\"removal\":\"replace\",\"suggestions\":\"weather_apps\",\"type\":\"oem\"},{\"id\":\"com.ape.weatherliveoverlay\",\"description\":\"Overlay app for com.ape.weatherlive. If you uninstall it, this package should also be removed.\",\"required_by\":[\"com.ape.weatherlive\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.ape.wikolegal\",\"description\":\"Provides legal for first time setup in Wiko mobile\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.ape.wikosetupwizard\",\"description\":\"Provides first time app install for Wiko mobile\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.apple.atve.sony.appletv\",\"description\":\"Apple Tv app on android Tv. Can be removed without any problem\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.arcsoft.app.humanavatar\",\"description\":\"My Avatar\\nAvatar activities useless.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.arcsoft.lg_avatar_resource\",\"description\":\"LGAvatarReource\\nIt's probably for arcamera and it's for avatars. People removed that.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.arcsoft.magicshotstudio\",\"description\":\"it's app for photos\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.asu\",\"description\":\"ZF10 Live Wallpaper\\nLive Wallpaper\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.asus.UpdateLauncher\",\"description\":\"Updater Launcher\\nRemove if you dont need it Launcher updates.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.asus.alwayson\",\"description\":\"Always-on Display\\nAOD will be not available after remove.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.asus.alwayson.res.overlay\",\"description\":\"Not needed gif to Always-on Display\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.asus.appupdater\",\"description\":\"ASUS Config Updater\\nIt may have something to do with app updater but no activities.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.asus.asusbacktap\",\"description\":\"Back tap\\nit's for Accessibility component feature.\\nBack tap will not be available in settings after remove.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.asus.asusoptiflex\",\"description\":\"ASUS Opti Flex\\nit's something for settings? Still unknown.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.asus.asussettingsbackuphelper\",\"description\":\"Settings ASUS Backup\\nCan be removed if ASUS Backup are not used.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.asus.atd.smmitest\",\"description\":\"SMMI TEST\\nTesting hardware things.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.asus.audiowizard\",\"description\":\"ASUS AudioWizard\\nNeeded for sound effects.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.asus.calculator\",\"description\":\"Calculator - unit converter (https://play.google.com/store/apps/details?id=com.asus.calculator)\\nHas more permissions than a Calculator app reasonably should have.\\nConnects to a few Google and currency exchange-rate servers.\\nhttps://beta.pithus.org/report/817514371bbdb76ec52da4c8456bbc116deec179603099deabbe6fcce6f6ccdb\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.asus.camera\",\"description\":\"Stock ASUS camera app. It has Google Analytics, so better disable internet for this app.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.asus.cellbroadcastreceiver.overlay\",\"description\":\"useless overlay for cellbroadcast\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.asus.cellbroadcastservice.overlay\",\"description\":\"useless overlay for cellbroadcast\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.asus.configupdater\",\"description\":\"ASUS Config Updater\\nSome people have removed this. Needed for ASUS autoupdate apps probably, also found debugging code.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.asus.contacts\",\"description\":\"ASUS Contacts\\nStock ASUS Contacts app. Contains Google trackers.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.asus.deskclock\",\"description\":\"ASUS Digital Clock & Widget\\nContains google analytics.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.asus.dialer\",\"description\":\"ASUS Dialer\\nContains Google trackers.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.asus.dm\",\"description\":\"System update\\nSystem updates for ASUS\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.asus.easylauncher\",\"description\":\"Asus Easy Mode (https://play.google.com/store/apps/details?id=com.asus.easylauncher)\\nAlternative launcher with bigger icons and simpler interface\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.asus.ephotoburst\",\"description\":\"ASUS Burst shot viewer\\nASUS Photo viewer, Trim Service. Contains Google Analytics.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.asus.faceunlockservice\",\"description\":\"ASUS Face Unlock Service\\nNeeded for face unlock.\\nFace unlock will not work after remove.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.asus.filemanager\",\"description\":\"File Manager\\nStock ASUS file manager app.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.asus.focusapplistener\",\"description\":\"Focus app\\nNeeded for optimization, probably.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.asus.gallery\",\"description\":\"Stock Gallery app. Contains Google Analytics.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.asus.gamewidget\",\"description\":\"Game genie\\nProbably useful for gaming.\\nhttps://play.google.com/store/apps/details?id=com.asus.gamewidget\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.asus.gamewidget.service\",\"description\":\"Game genie service\\nGame genie service needed for (`com.asus.gamewidget`)\\nIt's probably useful for gaming.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.asus.hardwarestub\",\"description\":\"HardwareStub Services\\nHas components for optimization game.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.asus.hbm\",\"description\":\"High Brightness Mode\\nIt can be found probably in settings. Still unknown.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.asus.ia.asusapp\",\"description\":\"My Asus (https://play.google.com/store/apps/details?id=com.asus.ia.asusapp)\\nAsus service center (support + store)\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.asus.imagesearch\",\"description\":\"Image search\\nit's so bloated.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.asus.ims.benchmarkblocker\",\"description\":\"Founded debugs and benchmark blocker.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.asus.ims.brightnessservice\",\"description\":\"Not needed, unused frameworks\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.asus.ims.configmanager\",\"description\":\"Not needed, unused frameworks\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.asus.ims.devicepolicymanager\",\"description\":\"Not needed, unused frameworks\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.asus.ims.evtlog\",\"description\":\"Not needed, unused frameworks\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.asus.ims.extdispctrl\",\"description\":\"Not needed, unused frameworks\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.asus.ims.forcedark\",\"description\":\"Not needed, unused frameworks\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.asus.ims.freeform\",\"description\":\"Not needed, unused frameworks\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.asus.ims.observer\",\"description\":\"Not needed, unused frameworks\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.asus.ims.packageinstallerproxy\",\"description\":\"Not needed, unused frameworks\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.asus.ims.phykeyctrl\",\"description\":\"Not needed, unused frameworks\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.asus.ims.pointerproxy\",\"description\":\"Not needed, unused frameworks\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.asus.ims.powerctrl\",\"description\":\"Not needed, unused frameworks\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.asus.ims.rogproxy\",\"description\":\"Not needed, unused frameworks\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.asus.ims.smartread\",\"description\":\"Not needed, unused frameworks\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.asus.ims.twinapps\",\"description\":\"Not needed, unused frameworks\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.asus.ims.watermark\",\"description\":\"Not needed, unused frameworks\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.asus.inadvertentTouch\",\"description\":\"Not needed 'Do not cover the top of the screen'\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.asus.key_status\",\"description\":\"KeyStatusTool\\nKeyStatusTool? All of this code means nothing.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.asus.launcher\",\"description\":\"ASUS Launcher\\nContains Google Firebase Analytics.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.asus.livedemoservice\",\"description\":\"Demo Mode\\nEnables retail demonstration mode. it's not a feature for normal users.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.asus.lockscreen2\",\"description\":\"Lockscreen\\nIt should be important for lockscreen.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.asus.loguploader\",\"description\":\"Log Tool\\nCaptured logs, Generate Log, Report Log.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.asus.loguploaderproxy\",\"description\":\"Bug Reporter Proxy\\nLogs without activity.\\nNot needed another logs from loguploader.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.asus.mlmodel\",\"description\":\"Unused frameworks? AI optimization?\\nResources have vision_model and something encrypted.\\nThis app is large (338MB).\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.asus.mobilemanager\",\"description\":\"Mobile Manager\\nNot sure to keep it or not.\\nhttps://play.google.com/store/apps/details?id=com.asus.mobilemanager\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.asus.mobilemanagerservice\",\"description\":\"Mobile Manager Service\\nLooks like a unused framework, but not sure.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.asus.nextapp\",\"description\":\"NextApp\\nUnused frameworks? It has something to training AI? everything is encrypted.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.asus.nextappcore\",\"description\":\"NextAppCore\\nUseless frameworks? It has something to training AI? everything is encrypted.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.asus.openbeta2\",\"description\":\"OpenBeta2\\nBeta program server that collects a lot of data.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.asus.powersaver\",\"description\":\"Power Master\\nIt's for power-saving and may be important.\\nImportant app to powersaving.\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.asus.sarprotection\",\"description\":\"SAR Protection\\nSecurity thing.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.asus.screenrecorder\",\"description\":\"Screen recorder\\nApp for screen recording.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.asus.setupwizard\",\"description\":\"Setup Wizard\\nIt's needed only for first-boot setup.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.asus.smartcover\",\"description\":\"SmartCover\\nUsed for smart features.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.asus.smartkey\",\"description\":\"Smart key\\nUsed for smart features.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.asus.smartreading\",\"description\":\"Smart Reading\\nIt's app for smart reading\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.asus.soundrecorder\",\"description\":\"ASUS Sound recorder (https://play.google.com/store/apps/details?id=com.asus.soundrecorder)\\nConnects to Google Analytics and some Asus servers, which is a bit sketchy for a sound recording app..\\nhttps://beta.pithus.org/report/f4cf38e1c35a04c3579fa198d2abd3ef1ff7be79633d6d3f2bc69c8a69164e1d\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.asus.splendid\",\"description\":\"Asus Splendid\\nOptional app for adjust your screen for your own viewing pleasure.\\nhttps://play.google.com/store/apps/details?id=com.asus.splendid\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.asus.stitchimage.service\",\"description\":\"Stitch image\\nIt's for the stock gallery app.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.asus.sysmonitor\",\"description\":\"Device Health\\nDevice Health? It collects your data.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.asus.system.api\",\"description\":\"AsusBoost\\nIt's probably an important app. It has booster services and memory cleaner service.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.asus.systemcolor\",\"description\":\"System color scheme\\nNeeded for changing wallpapers?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.asus.taskwidget\",\"description\":\"ASUS Task Manager widget\\nTask manager widget to System optimization\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.asus.teleserv.overlay.odm\",\"description\":\"overlay to default config ims.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.asus.theme.color.asusui\",\"description\":\"Theme AsusUI\\nStock System Theme\\nSystem may not work after removing it.\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.asus.theme.color.rog\",\"description\":\"Rog Theme\\nStock System Theme\\nSystem may not work after removing it.\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.asus.themeservice\",\"description\":\"Needed for change theme apps?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.asus.tips\",\"description\":\"Tips\\nTips for smart features and more.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.asus.twinapps\",\"description\":\"Twin Apps for duplicate apps.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.asus.twinappsservice\",\"description\":\"Twin Apps Service\\nNeeded for Twin Apps for duplicate apps.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.asus.userfeedback\",\"description\":\"ZenUI Help (https://play.google.com/store/apps/details?id=com.asus.userfeedback)\\nCustomer service app that provides FAQs, Mobile care service, user feedback, and public forums.\\nLots of telemetry (insecure on top of that):\\nhttps://beta.pithus.org/report/e80a1fa70adc097fc9817720b5c8c81cfd156a76e6d062759b2bc3d6937a97e7\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.asus.visualmaster\",\"description\":\"Tru2Life\\nit's app for color modes.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.asus.weathertime\",\"description\":\"ASUS Weather\\nit's for weather. Have Firebase Analytics.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.asus.wifi.resources.overlay\",\"description\":\"overlay to wifi configs better dont risk.\\nImportant configs to WiFi.\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.asus.zenmotion\",\"description\":\"Gestures\\nNeeded for Gestures.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.aura.oobe.kbdi\",\"description\":\"Appcloud\\nPersistent notification until you click on it and agree to install games. Sort of game cloud pre-installed in some Xiaomi phones\\nSafe to remove.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.autonavi.minimap\",\"description\":\"高德地图 (Yeah no english translation) (https://play.google.com/store/apps/details?id=com.autonavi.minimap)\\nXiaomi GPS\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.baidu.BaiduMap\",\"description\":\"Chinese Baidu Map.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.baidu.duersdk.opensdk\",\"description\":\"Duer stuff from Baidu \\nDuer is a virtual AI assistant.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.baidu.input_huawei\",\"description\":\"Woh! 51 permissions! \\nHuawei chinese stock input keyboard. You probably shouldn't trust this closed-source keyboard with this much permissions...NOTE: Make sure to have another keyboard installed before removing this package!\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.baidu.input_mi\",\"description\":\"Baidu IME (Baidu keyboard)\\nYOU SHOULD NEVER USE A CLOSED-SOURCE KEYBOARD ! \\nhttps://www.techrepublic.com/blog/asian-technology/japanese-government-warns-baidu-ime-is-spying-on-users/\\nArchive : https://web.archive.org/save/https://www.techrepublic.com/blog/asian-technology/japanese-government-warns-baidu-ime-is-spying-on-users/\\nNOTE: Make sure you have installed another keyboard before removing this package.\\n\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.baidu.input_vivo\",\"description\":\"Default keyboard (Baidu IME customized for Vivo devices).\\nThe number of requested permissions for this keyboard is terrifying. You really should use another keyboard. Pithus analysis: https://beta.pithus.org/report/d4cdf8fedcd94436ade720cb8df9b4ef32aca6c7822cae6c8698937d68e20363\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.baidu.location.fused\",\"description\":\"FusedLocation\\nChinese baidu location.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.baidu.map.location\",\"description\":\"Chinese Network location baidu. Only for China.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.baidu.searchbox\",\"description\":\"百度 (https://play.google.com/store/apps/details?id=com.baidu.searchbox)\\nBaidu App search engine.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.bbk.SuperPowerSave\",\"description\":\"Super Battery Saver\\nNot sure if it's useful or not. Super power save.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.bbk.account\",\"description\":\"Vivo account\\nVivo privacy policy is really bad: https://privacy.vivo.com/privacy\\nNote: Removing this will obviously break fuctions that require Vivo account authentication: accessibility, data backup etc.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.bbk.appstore\",\"description\":\"Vivo app store.\\nNote: apps from this store can still be upgraded with the built-in check upgrade feature even with this package removed\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.bbk.calendar\",\"description\":\"Default calendar app.\\n50 permissions for a calendar app. What could go wrong?\\n\\nPithus analysis: https://beta.pithus.org/report/db107cb828a1ec9b7cbcd9fd86542da877fdf4cf947c18c8a48a2b09e568ad10\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.bbk.cloud\",\"description\":\"vivoCloud\\nVivo cloud services.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.bbk.facewake\",\"description\":\"FaceWake\\nIt's used for face unlock.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.bbk.iqoo.logsystem\",\"description\":\"User experience service\\nTelemetry app.\\nNote:Disabling this will break trial version system upgrade feature.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.bbk.launcher2\",\"description\":\"Vivo launcher.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.bbk.photoframewidget\",\"description\":\"Photo frame\\nPhoto widget.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.bbk.scene.databaseprovider\",\"description\":\"May be needed for the launcher, not sure.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.bbk.scene.launcher.theme\",\"description\":\"SceneThemeLauncher\\nMay be needed for the launcher, not sure.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.bbk.theme\",\"description\":\"Vivo theme (https://play.google.com/store/apps/details?id=com.bbk.theme)\\nLets you add new themes, fonts and wallpapers.\\nIt has annoying notifications that cannot be disabled by going to the app settings. This app use 50 permissions and can install packages (REQUEST_INSTALL_PACKAGES)\\nNote: Removing this app will prevent you to change themes.\\n\\nPithus analysis: https://beta.pithus.org/report/0f15055131637d3dbc55d3a49b8e79b4f76ca09871abf9eb43b5f88afde11800\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.bbk.theme.resources\",\"description\":\"WallpaperRes\\nVivo wallpapers. A lot of PNG wallpapers. Safe to remove if you don't need theme resources.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.bbk.updater\",\"description\":\"System update\\nProvides system updates.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.bjbyhd.screenreader_huawei\",\"description\":\"An accessibility feature for visually impaired people\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.bluetooth.aptxmode\",\"description\":\"Hidden aptX ALS Audio Bluetooth sample improvement from Qualcomm. Useless 96kHz sample.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.bsp.catchlog\",\"description\":\"bsp = Board support package\\nUsed to catch log files obviously.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.casper.turkiye\",\"description\":\"Support app for Casper, see https://play.google.com/store/apps/details?id=com.casper.turkiye&hl=en\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.cdfinger.factorytest\",\"description\":\"Fingerprint Test App.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.chaozhuo.filemanager\",\"label\":\"File Manager\",\"description\":\"Adware file manager aka 'CZ File Manager' that mostly came preinstalled on Lenovo Tablets.\\nFile management is a basic necessity, make sure you install a third-party file manager for this purpose.\\n\",\"web\":[\"https://forums.lenovo.com/t5/Security-Malware/Tab4-Preinstalled-file-manager-has-Adware-trying-to-get-your/td-p/4355222\",\"https://beta.pithus.org/report/02b0b4c60941960d3ac82177df0e5e93f61ee0f5c181ba50668d4ab0dae8d508\"],\"removal\":\"replace\",\"warning\":\"You must allow 'location & phone calls' permission to run.\",\"suggestions\":\"file_managers\",\"type\":\"oem\"},{\"id\":\"com.chsc.semitouchtester\",\"description\":\"Semi touch test, debug.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.cleanmaster.sdk\",\"description\":\"(discontinued) old clean master app that cleans phone.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.cnn.mobile.android.phone.edgepanel\",\"description\":\"CNN Edge panel. Twitter trends, and news from CNN.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.codeaurora.fmradio\",\"label\":\"FM Radio\",\"description\":\"Default FM app for lenovo devices.\",\"removal\":\"replace\",\"suggestions\":\"radios\",\"type\":\"oem\"},{\"id\":\"com.color.uiengine\",\"description\":\"Needed for themes\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.coloros.accessibilityassistant\",\"description\":\"Another thing for smart assistant\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.coloros.activation\",\"label\":\"E-warranty card\",\"description\":\"Lets you check if your registered phone is still under warranty (will send your IMEI to 'esa-reg-eup.myoppo.com'). Has a lot of permissions and run at boot.\",\"web\":[\"https://beta.pithus.org/report/2a1dc5caedd2347fa009563e9b4d1c11b1cb42726f9046151934c456fdd77d88\"],\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.coloros.activation.overlay.common\",\"description\":\"E-warranty card\\nLets you check if your registered phone is still under warranty. Has a lot of permissions and runs at boot. Pithus analysis: https://beta.pithus.org/report/2a1dc5caedd2347fa009563e9b4d1c11b1cb42726f9046151934c456fdd77d88\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.coloros.alarmclock\",\"description\":\"Stock Clock app.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.coloros.appmanager\",\"label\":\"Permanent process management\",\"description\":\"Used to uninstall applications, but uninstalling apps works nonetheless, even after uninstalling this package.\",\"removal\":\"caution\",\"warning\":\"GameSpace's game assistant does not work after uninstalling this package.\",\"type\":\"oem\"},{\"id\":\"com.coloros.apprecover\",\"description\":\"Used for app recovery?\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.coloros.assistantscreen\",\"label\":\"Shelf\",\"description\":\"Previously Breeno, developed by HeyTap. ColorOS 'At a Glance'.\\nShelf provides a variety of widgets that let you access important information or services from apps with ease. Swipe down on the Home screen to enter Shelf.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.coloros.assistantscreen\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.coloros.athena\",\"description\":\"Memory management, maybe useful, maybe not\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.coloros.athena.config_plugin\",\"description\":\"Needed to configure com.coloros.athena. Memory management, maybe useful, maybe not.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.coloros.avastofferwall\",\"description\":\"Avast Offerwall\\nAvast anti-virus things.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.coloros.backuprestore\",\"label\":\"OPPO Clone Phone\",\"description\":\"Oppo backup/restore tool.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.coloros.backuprestore\"],\"removal\":\"replace\",\"suggestions\":\"backup_apps\",\"type\":\"oem\"},{\"id\":\"com.coloros.backuprestore.remoteservice\",\"description\":\"It has something to scan always Wi-Fi but it's probably unused.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.coloros.blacklistapp\",\"description\":\"Blacklist Contacts\\nBlack list contacts, blocking calling.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.coloros.bootreg\",\"description\":\"Setup Wizard\\nCause bootloop after uninstall app.\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.coloros.calculator\",\"description\":\"Calculator app\\nHas internet access because it can convert exchange rate, but I don't know whether it's used for other things as well or not.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.coloros.childrenspace\",\"label\":\"Kid Space\",\"description\":\"Limit time spending on apps for kids.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.coloros.cloud\",\"label\":\"OPPO Cloud\",\"description\":\"Oppo cloud storage?\",\"removal\":\"replace\",\"suggestions\":\"cloud_services\",\"type\":\"oem\"},{\"id\":\"com.coloros.codebook\",\"description\":\"Password manager\\nApp where you can keep passwords.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.coloros.colordirectservice\",\"description\":\"Screen Recognition (Breeno Touch).\\nThis app is used to recognize screen contents and provide quick access to relevant services (like Text Extraction, AI Summarizer). com.coloros.ocrscanner, com.coloros.ocrservice, com.oplus.ocs, com.oplus.aiunit, com.coloros.ocs.opencapabilityservice are also needed for this to work.\",\"dependencies\":[\"com.coloros.ocrscanner\",\"com.coloros.ocrservice\",\"com.oplus.ocs\",\"com.oplus.aiunit\",\"com.coloros.ocs.opencapabilityservice\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.coloros.colorfilestand\",\"description\":\"It has only Request permission activity. Probably useless framework also it has something to do with cloud.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.coloros.compass2\",\"label\":\"Compass\",\"description\":\"ColorOS default compass app\\nKeep in mind that by using this app you give your location to the weather Oppo servers.\",\"web\":[\"https://beta.pithus.org/report/9a965f5587fa6ee21c526612f3d72c50ef3cc53679b741260298387c44f5a3dc\"],\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.coloros.digitalwellbeing\",\"description\":\"App usage time that can be found in settings.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.coloros.directui\",\"label\":\"Breeno Touch\",\"description\":\"Smart things it can be found in settings.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.coloros.dirrecord\",\"description\":\"Security features, anti-trojan?\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.coloros.encryption\",\"description\":\"Private Safe\\nRemoving breaks the stock launcher? Private Safe (located in Privacy Settings)\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.coloros.exserviceui\",\"description\":\"Edge touch\\nGesture-related things. Edge touch\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.coloros.exsystemservice\",\"label\":\"OplusExSystemService\",\"description\":\"Responsible for gesture-based features, such as double tap to wake up and possibly other motion or gesture recognition services, essential for some display and wake/sleep functionalitiesResponsible for gesture-based features, such as double tap to wake up and possibly other motion or gesture recognition services, essential for some display and wake/sleep functionalities. The service is designed to auto-start and run persistently at boot, ensuring gesture features always work as expected. It also includes an accessibility activity, potentially to support features for users with disabilities or for system interaction enhancements\",\"removal\":\"caution\",\"warning\":\"Disabling or uninstalling this package may break core functions such as double-tap-to-wake or other gesture-based features.\",\"type\":\"oem\"},{\"id\":\"com.coloros.eyeprotect\",\"description\":\"It's the only eye protection option\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.coloros.feedback\",\"description\":\"Feedback service\\nFeedback for OPPO\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.coloros.filemanager\",\"label\":\"My Files\",\"description\":\"OPPO's official file management app\",\"removal\":\"replace\",\"suggestions\":\"file_managers\",\"type\":\"oem\"},{\"id\":\"com.coloros.findmyphone\",\"label\":\"Find My\",\"description\":\"Previously Find My Phone Service. Oppo's find my phone service. Logout from OPPO account before removing.\",\"removal\":\"replace\",\"suggestions\":\"locators\",\"type\":\"oem\"},{\"id\":\"com.coloros.findphone.client2\",\"description\":\"Find phone\\nFind phone, logout from oppo account before\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.coloros.floatassistant\",\"description\":\"GA ball, Assistive ball feature.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.coloros.focusmode\",\"description\":\"Focus mode\\nit's option that can be found in settings.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.coloros.gallery3d\",\"description\":\"Gallery\\nStock gallery app.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.coloros.gamespace\",\"label\":\"Game Space\",\"description\":\"Previously APP Enhancement Services. Hub for your Games + some performance optimizations\",\"web\":[\"https://community.coloros.com/thread-9962-1-1.html\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.coloros.gamespaceui\",\"label\":\"Game Space\",\"description\":\"Gaming utility aiming at 'optimizing your gaming experience'. Has a lot of permissions. For instance, it has internet access, will scans all the apps you have on your phones (to find games), can performs Bluetooth scan and has access to the metadata of your media files (e.g the place where you took a picture).\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.coloros.gesture\",\"description\":\"Gestures & Motions\\nSomatic gestures (double tap to light up the screen)\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.coloros.healthcheck\",\"label\":\"Diagnostics\",\"description\":\"Previously Quick Check. Health check? Probably hidden.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.coloros.healthservice\",\"description\":\"Health service\\nAnother thing related to health check\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.coloros.karaoke\",\"description\":\"Karaoke\\nKaraoke (Do not delete if you need Karaoke)\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.coloros.launcher.layout\",\"description\":\"Useless code that means nothing for the launcher\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.coloros.lockassistant\",\"description\":\"You can't remove this app using adb.\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.coloros.logkit\",\"description\":\"LogKit\\nLogs, Dial *#800# for running it\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.coloros.logkit.plugin.upload\",\"description\":\"Useless plugin for logs\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.coloros.mapcom.frame\",\"description\":\"Useless frameworks\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.coloros.mcs\",\"label\":\"System Messages\",\"description\":\"More info needed.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.coloros.musiclink\",\"description\":\"Music Party\\nThis app allows you to play music through different phones, synchronised.\\nhttps://www.youtube.com/watch?v=3Ak222Z79RY\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.coloros.notificationmanager\",\"description\":\"Needed for notification manager and scheduled do not disturb.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.coloros.ocrscanner\",\"label\":\"Breeno Scan\",\"description\":\"ColorOS Optical character recognition scanner\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.coloros.ocrservice\",\"description\":\"Extract text from images.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.coloros.ocs.opencapabilityservice\",\"description\":\"This service acts as a core system capability provider on Oppo, Realme, and related devices, enabling or mediating various inter-app or system-level features.\\nIt's also used for live alerts by front facing camera/status bar for iPhone-like style music widget (for Spotify), battery charge indicator, flashlight indicator, and more.\",\"removal\":\"caution\",\"warning\":\"If removed, live alerts will stop working.\",\"type\":\"oem\"},{\"id\":\"com.coloros.onekeylockscreen\",\"label\":\"Screen Lock\",\"description\":\"Lock your phone if you click on the app icon. Completely useless unless your physical power button is damaged.\\nThis app still has the permission to list all the apps installed on the phone.\",\"web\":[\"https://beta.pithus.org/report/ece4088357c0a47dffd96bdc46a7b535d448c1a3619d995f7032df3be6cb0a38\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.coloros.operationManual\",\"description\":\"Help & feedback\\nHelp (in Settings - Other Settings)\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.coloros.operationtips\",\"description\":\"Tips\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.coloros.oppoguardelf\",\"description\":\"Needed for power-saving and security\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.coloros.oppoguardelf.restrict_plugin\",\"description\":\"Needed components for com.coloros.oppoguardelf. Needed for power-saving and security. Also, the plugin is bloated with logs and statistics.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.coloros.oppoguardelf.secretplugin\",\"description\":\"Needed components for com.coloros.oppoguardelf. Needed for power-saving and security. Also, the plugin is bloated with logs and statistics.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.coloros.oppomultiapp\",\"label\":\"App Cloner\",\"description\":\"Needed for app clone feature.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.coloros.oshare\",\"label\":\"OnePlus Share\",\"description\":\"Previously OPPO Share. File sharing app to transfer data from/to Oppo devices only. Seems to use weak crypto (AES ECB mode) and has weird permissions (such as `READ_CONTACTS`).\",\"web\":[\"https://beta.pithus.org/report/170f4a14be24a2e2135cd956a038aae9e2f78c845f3161b84c5545dbec03fad9\"],\"removal\":\"caution\",\"warning\":\"Removing this app will break the functionality to share photos directly from ColorOS Photos app and break the 'share with' prompt after taking a screenshot.\",\"type\":\"oem\"},{\"id\":\"com.coloros.phonemanager\",\"label\":\"Phone Manager\",\"description\":\"Provides so called 'optimization tools' and various security scanning services.\\nThese virus scanning services may have privacy implications.\",\"web\":[\"https://beta.pithus.org/report/6b7d9e117ffb600b852f3785ede4f3773385fc291376e94a061bf7ed787dec48\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.coloros.phonenoareainquire\",\"label\":\"Number Origin\",\"description\":\"More info needed.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.coloros.pictorial\",\"description\":\"LockscreenMagazine\\nRemoval will result in no longer being able to access Lockscreen settings.\\n\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.coloros.prome.service\",\"description\":\"Useless frameworks. About feedback and smart touch.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.coloros.prome.smsservice\",\"description\":\"Useless SMS frameworks.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.coloros.recents\",\"description\":\"Recent apps. Provides navigation to alternate between multiple apps. Removal will result in no \\\"Recent App\\\" list and re-enablement will cause a soft reload.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.coloros.regservice\",\"description\":\"Mobile DM authentication related (recommended to be uninstalled)\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.coloros.remoteguardservice\",\"description\":\"Remote Guard Service\\nHave only useless statistics and depends on: com.coloros.mcs, com.heytap.mcs ONLY FOR CHINA.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.coloros.safecenter\",\"description\":\"Security Center\\nIt breaks 'display over other apps' permission!\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.coloros.safecenter.config_plugin\",\"description\":\"This plugin doesn't have any important things. It's safe to remove, useless logs code.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.coloros.safesdkproxy\",\"description\":\"It has cleaner and security things.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.coloros.sau\",\"description\":\"System Upgrade Services\\nNeeded to update ColorOS.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.coloros.sauhelper\",\"description\":\"SAUHelper\\nIt has only statistics and logs.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.coloros.scenemode\",\"description\":\"Scene mode and simple mode\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.coloros.sceneservice\",\"description\":\"Data Services Platform\\nData Services Platform (the entire Breeno option in the settings menu disappears after deletion)\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.coloros.screenrecorder\",\"description\":\"Screen recorder\\nStock screen recording app.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.coloros.screenshot\",\"description\":\"Screenshot\\nNeeded for screenshots. Very useful app.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.coloros.securepay\",\"label\":\"Payment Protection\",\"description\":\"Payment system from Oppo allowing you to pay with your phone.\",\"web\":[\"https://beta.pithus.org/report/65246664d3795a5ac1b402d28456903e1b3bd76176de8298b3ea96c6c592ae9a\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.coloros.securityguard\",\"description\":\"Security Events (located in Phone Manager - Security Tools, it is recommended to uninstall it).\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.coloros.securitykeyboard\",\"description\":\"Secure keyboard\\nNot needed if your keyboard is already good.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.coloros.securitypermission\",\"description\":\"Handles app permission management. DO NOT REMOVE THIS\\n\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.coloros.sharescreen\",\"description\":\"Shared screen assistance\\nShared screen assistance (nobody need it)\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.coloros.simsettings\",\"description\":\"Data usage\\nData usage and OTA updates\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.coloros.smartdrive\",\"label\":\"Driving mode\",\"description\":\"Previously Breeno Driving, and Smart Driving. It's for smart things.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.coloros.smartlock\",\"description\":\"\\\"Phone stays unlocked when using a wearable device\\\" feature support component.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.coloros.smartsidebar\",\"description\":\"Smart Sidebar\\nEdge panel settings\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.coloros.soundrecorder\",\"label\":\"Recorder\",\"description\":\"ColorOS default Sound Recorder\",\"removal\":\"replace\",\"suggestions\":\"audio_recorders\",\"type\":\"oem\"},{\"id\":\"com.coloros.speechassist\",\"description\":\"ColorOS default Speech Assistant\",\"removal\":\"replace\",\"suggestions\":\"tts\",\"type\":\"oem\"},{\"id\":\"com.coloros.systemclone\",\"label\":\"System Cloner\",\"description\":\"Creates multiple users on device\",\"removal\":\"replace\",\"suggestions\":\"sandboxing_apps\",\"type\":\"oem\"},{\"id\":\"com.coloros.trafficlimit\",\"description\":\"Useless frameworks\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.coloros.translate.engine\",\"description\":\"Used for translation?\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.coloros.uxdesign\",\"description\":\"Needed for themes\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.coloros.video\",\"label\":\"Video\",\"description\":\"Default Oppo video player with too much permissions (21) for a video player!\",\"web\":[\"https://beta.pithus.org/report/4ceb96c23ad0e26ee8eceab293d251f8b1bddaf4a901741ee467e0bb867db6e9\"],\"removal\":\"replace\",\"warning\":\"Using inbuilt screen recorder you won't be able to open the recorded video from the notification view.\",\"suggestions\":\"video_players\",\"type\":\"oem\"},{\"id\":\"com.coloros.wallet\",\"label\":\"com.coloros.wallet\",\"description\":\"Oppo default Wallet app.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.coloros.wallpapers\",\"description\":\"Wallpapers\\nNeeded for wallpapers\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.coloros.weather.service\",\"description\":\"Name indicates it's for the weather, but removing this causes the screen to flash and the phone will eventually become unresponsive.\\nhttps://github.com/Universal-Debloater-Alliance/universal-android-debloater-next-generation/issues/585\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.coloros.weather2\",\"label\":\"Weather\",\"description\":\"ColorOS weather app.You should try, several users removed this app without any trouble on Oppo/Realme device with Android 11+.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.coloros.weather2\",\"https://github.com/0x192/universal-android-debloater/issues/211\"],\"removal\":\"unsafe\",\"warning\":\"Removal seems to trigger a bootloop on some phones.\",\"suggestions\":\"weather_apps\",\"type\":\"oem\"},{\"id\":\"com.coloros.widget.smallweather\",\"label\":\"Clock\",\"description\":\"More info needed.\",\"removal\":\"replace\",\"suggestions\":\"weather_apps\",\"type\":\"oem\"},{\"id\":\"com.coloros.wifibackuprestore\",\"label\":\"WifiBackupRestore\",\"description\":\"Backs up Wi-Fi access points and credentials to the cloud\",\"removal\":\"caution\",\"warning\":\"Removal would cause the Backup and Restore to unable to backup locally-stored Wi-Fi access points and credentials.\",\"type\":\"oem\"},{\"id\":\"com.coloros.wifisecuredetect\",\"description\":\"Useless for Wi-Fi. Has captcha and mobile number verification.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.coloros.wirelesssettings\",\"description\":\"Wireless settings\\nProbably needed.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.coremobility.app.vnotes\",\"label\":\"Sprint Voicemail\",\"description\":\"More info needed.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.daemon.shelper\",\"description\":\"Shelper\\nTracking, monitoring, logs\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.data.overlay.base.s600ww\",\"label\":\"com.data.overlay.base.s600ww\",\"description\":\"Some kind of theme overlay for Nokia devices?\\nSome users claim to not see any differences when removed.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.detection.ts.noise_detection_apk\",\"description\":\"It's used by bsptest (com.vivo.bsptest) for noise detection test.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.detection.ts.touch_detection\",\"description\":\"It's used by bsptest (com.vivo.bsptest) for touch detection test.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.diotek.diodict4.EDictionary\",\"description\":\"Dictionary app, only for japanese and korea\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.dirac.acs\",\"description\":\"Dirac Control Service\\nFor audio control, not sure if it's useful.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.dragon.read\",\"description\":\"Chinese Unknown partner app from Miui China.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.droidlogic\",\"description\":\"DroidBtPair\\nLooks like an important app for the TV to work properly.\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.dropbox.android\",\"description\":\"dropbox app\\nhttps://play.google.com/store/apps/details?id=com.dropbox.android\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.dropboxchmod\",\"description\":\"I found logs in code. This app means nothing.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.dti.lenovo.tablet\",\"label\":\"Mobile Services\",\"description\":\"Silently installs unwanted packages without user permission.\\n\",\"web\":[\"https://www.andrewnile.co.uk/blog/lenovo-mobile-services/\",\"https://beta.pithus.org/report/4ebcc8b5a13851054d85153b0d4086e4b2b5adaee66eaea5843078c6134e9dd7\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.dts.dtsxultra\",\"description\":\"Audio Effect for car, headphones. You don't need that.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.duokan.phone.remotecontroller\",\"label\":\"Mi Remote\",\"description\":\"Control your electric appliances with your phone using Mi Remote.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.duokan.phone.remotecontroller\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.duokan.phone.remotecontroller.peel.plugin\",\"label\":\"Peel Mi Remote\",\"description\":\"Peel Mi Remote is a TV guide extension for Xiaomi Mi Remote by \\\"Peel Smart Remote\\\".\",\"web\":[\"https://play.google.com/store/apps/details?id=com.duokan.phone.remotecontroller.peel.plugin\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.duokan.reader\",\"description\":\"MIUIDuokanReader\\nChinese app that has too much tracking and ads.\\nMay be uninstalled without ADB.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.eg.android.AlipayGphone\",\"description\":\"Chinese Alipay app.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.elephanttek.faceunlock\",\"label\":\"com.elephanttek.faceunlock\",\"description\":\"Standard FaceUnlock functionality?\\nUnlock your device by simply looking at the display.\\nFace unlock is bad for security and privacy.\",\"web\":[\"https://www.ubergizmo.com/2017/03/galaxy-s8-facial-unlock-photograph/\",\"https://www.kaspersky.com/blog/face-unlock-insecurity/21618/\",\"https://www.freecodecamp.org/news/why-you-should-never-unlock-your-phone-with-your-face-79c07772a28/\"],\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.enhance.gameservice\",\"label\":\"Samsung Game Optimizing Service\",\"description\":\"Previously GameMode.\\nLegacy game Optimizing Service (is replaced by com.samsung.android.game.gos)\\nIs supposed to \\\"improve\\\" game performance.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.epicgames.portal\",\"description\":\"Epic Games for Android\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.evenwell.AprUploadService\",\"description\":\"Apr Upload Service ???? [MORE INFO NEEDED]\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.evenwell.AprUploadService.data.overlay.base\",\"description\":\"Theme overlay for Apr Upload Service?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.evenwell.AprUploadService.data.overlay.base.s600id\",\"description\":\"Theme overlay for Apr Upload Service?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.evenwell.AprUploadService.data.overlay.base.s600ww\",\"description\":\"Theme overlay for Apr Upload Service?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.evenwell.CPClient\",\"description\":\"CP = Client Provisioning.\\nSurely used to push new carrier internet/MMS settings automatically\\nMaybe it's useful if carriers change their APN... but you still can change it manually, it's not difficult.\\n\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.evenwell.CPClient.overlay.base\",\"description\":\"Theme overlay for CPClient?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.evenwell.CPClient.overlay.base.s600id\",\"description\":\"Theme overlay for CPClient?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.evenwell.CPClient.overlay.base.s600ww\",\"description\":\"Theme overlay for CPClient?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.evenwell.DbgCfgTool\",\"description\":\"Debug Config Tool?\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.evenwell.DbgCfgTool.overlay.base\",\"description\":\"Theme overlay for Debug Config Tool?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.evenwell.DbgCfgTool.overlay.base.s600id\",\"description\":\"Theme overlay for Debug Config Tool?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.evenwell.DbgCfgTool.overlay.base.s600ww\",\"description\":\"Theme overlay for Debug Config Tool?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.evenwell.DeviceMonitorControl\",\"description\":\"Some form of device monitoring?\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.evenwell.DeviceMonitorControl.data.overlay.base\",\"description\":\"Theme overlay for Device Monitor Control?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.evenwell.DeviceMonitorControl.data.overlay.base.s600id\",\"description\":\"Theme overlay for Device Monitor Control?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.evenwell.DeviceMonitorControl.data.overlay.base.s600ww\",\"description\":\"Theme overlay for Device Monitor Control?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.evenwell.OTAUpdate.overlay.base.s600ww\",\"description\":\"Theme overlay for OTA Update UI?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.evenwell.PowerMonitor\",\"description\":\"Drains more battery than it saves.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.evenwell.PowerMonitor.overlay.base\",\"description\":\"Theme overlay for Power Monitor?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.evenwell.PowerMonitor.overlay.base.s600id\",\"description\":\"Theme overlay for Power Monitor?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.evenwell.PowerMonitor.overlay.base.s600ww\",\"description\":\"Theme overlay for Power Monitor?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.evenwell.SettingsUtils\",\"description\":\"Settings utils\\n(crappy) Audio rendering. \\nSee https://gitlab.com/W1nst0n/universal-android-debloater/-/issues/9#note_369056538\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.evenwell.SettingsUtils.overlay.base.s600ww\",\"description\":\"Theme overlay for SettingsUtils?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.evenwell.SetupWizard\",\"description\":\"The first-boot device setup wizard for new/factory reset devices.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.evenwell.SetupWizard.overlay.base\",\"description\":\"Theme overlay for Setup Wizard?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.evenwell.SetupWizard.overlay.base.s600ww\",\"description\":\"Theme overlay for Setup Wizard?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.evenwell.SetupWizard.overlay.d.base.s600ww\",\"description\":\"Theme overlay for Setup Wizard?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.evenwell.UsageStatsLogReceiver\",\"description\":\"Logging stuff\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.evenwell.UsageStatsLogReceiver.data.overlay.back.s600id\",\"description\":\"Theme overlay for Usage Stats Log?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.evenwell.UsageStatsLogReceiver.data.overlay.base.s600ww\",\"description\":\"Theme overlay for Usage Stats Log?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.evenwell.apnwidget.overlay.base.s600ww\",\"description\":\"Some overlay for an APN widget. Overlays are usually themes.\\nAPN means Access Point Name and must be configured with carrier values in order for your device to acess the carrier's network.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.evenwell.autoregistration\",\"label\":\"AautoRegistration\",\"description\":\"Spyware app which sends warranty details to China.\",\"web\":[\"https://milankragujevic.com/the-trade-of-privacy-for-convenience\",\"https://archive.is/https://nitter.privacydev.net/drwetter/status/1108801189662130176\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.evenwell.autoregistration.overlay.base\",\"description\":\"Theme overlay for a Spyware app?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.evenwell.autoregistration.overlay.base.s600id\",\"description\":\"Theme overlay for a Spyware app?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.evenwell.autoregistration.overlay.base.s600ww\",\"description\":\"Theme overlay for a Spyware app?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.evenwell.autoregistration.overlay.d.base.s600id\",\"description\":\"Theme overlay for a Spyware app?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.evenwell.autoregistration.overlay.d.base.s600ww\",\"description\":\"Theme overlay for a Spyware app?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.evenwell.batteryprotect\",\"description\":\"Battery protect is advertised to improve battery performance, but in practice it drains your battery and kills apps aggressively.\\nhttps://dontkillmyapp.com/nokia\\nNokia decided to stop using this app-killer in the future:\\nhttps://www.androidpolice.com/2019/08/27/nokia-hmd-phones-disable-evenwell-background-process-app-killer/\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.evenwell.batteryprotect.overlay.base\",\"description\":\"Theme overlay for Battery Protect?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.evenwell.batteryprotect.overlay.base.s600id\",\"description\":\"Theme overlay for Battery Protect?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.evenwell.batteryprotect.overlay.base.s600ww\",\"description\":\"Theme overlay for Battery Protect?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.evenwell.batteryprotect.overlay.d.base.s600e0\",\"description\":\"Theme overlay for Battery Protect?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.evenwell.bboxsbox\",\"description\":\"??? [MORE INFO NEEDED]\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.evenwell.bboxsbox.app\",\"description\":\"????\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.evenwell.bokeheditor\",\"description\":\"Probably related to adding fake bokeh (a focus blur effect) to photos.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.evenwell.bokeheditor.overlay.base.s600ww\",\"description\":\"Theme overlay for Bokeh Editor?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.evenwell.camera2\",\"description\":\"Nokia camera by evenwell (https://play.google.com/store/apps/details?id=com.evenwell.camera2)\\n\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.evenwell.custmanager\",\"description\":\"Customer manager\\nGiven its name I'd say it is useless but I don't have more info.\\n\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.evenwell.custmanager.data.overlay.base\",\"description\":\"Theme overlay for Customer Manager?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.evenwell.custmanager.data.overlay.base.s600id\",\"description\":\"Theme overlay for Customer Manager?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.evenwell.custmanager.data.overlay.base.s600ww\",\"description\":\"Theme overlay for Customer Manager?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.evenwell.customerfeedback.overlay.base.s600ww\",\"description\":\"Theme overlay for Customer Feedback?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.evenwell.dataagent\",\"description\":\"Data agent\\nUsed for backup/restore? [MORE INFO NEEDED]\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.evenwell.dataagent.overlay.base\",\"description\":\"Theme overlay for Data Agent?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.evenwell.dataagent.overlay.base.s600id\",\"description\":\"Theme overlay for Data Agent?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.evenwell.dataagent.overlay.base.s600ww\",\"description\":\"Theme overlay for Data Agent?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.evenwell.defaultappconfigure.overlay.base.s600ww\",\"description\":\"A theme overlay for selecting default apps or something?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.evenwell.email.data.overlay.base.s600ww\",\"description\":\"Theme overlay for email app?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.evenwell.factorywizard\",\"description\":\"Likely part of the first-boot device setup (new/factory reset device).\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.evenwell.factorywizard.overlay.base\",\"description\":\"Theme overlay for setup wizard?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.evenwell.factorywizard.overlay.base.s600ww\",\"description\":\"Theme overlay for setup wizard?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.evenwell.fmradio.overlay.base.s600ww\",\"description\":\"Theme overlay for Nokia radio app?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.evenwell.foxlauncher.partner\",\"description\":\"Partner Launcher Customization\\nRelated to the Nokia launcher\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.evenwell.fqc\",\"description\":\"FQC is a secret test menu. It lets you test the hardware (touch screen, speakers, SD card, SIM card, camera...)\\nYou need to type *#*#372733#*#* in the Nokia dialer\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.evenwell.hdrservice\",\"description\":\"HDR Service (https://play.google.com/store/apps/details?id=com.evenwell.hdrservice)\\nEnhances contrast and sharpness for normal photos, games and videos dynamically.\\n\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.evenwell.legalterm\",\"description\":\"Provides terms and conditions (legal notice)\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.evenwell.legalterm.overlay.base.s600ww\",\"description\":\"Theme overlay for some terms and conditions?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.evenwell.managedprovisioning\",\"description\":\"Nokia implementation of com.android.managedprovisioning? If so it manages Android user accounts, allowing you to add extra accounts. The typical use-case is setting up a corporate profile that is controlled by the employer on an employee's personal device, to keep personal and work data separate.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.evenwell.managedprovisioning.overlay.base\",\"description\":\"Theme overlay for Managed Provisioning?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.evenwell.managedprovisioning.overlay.base.s600id\",\"description\":\"Theme overlay for Managed Provisioning?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.evenwell.managedprovisioning.overlay.base.s600ww\",\"description\":\"Theme overlay for Managed Provisioning?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.evenwell.mappartner\",\"description\":\"????\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.evenwell.nps\",\"description\":\"Net Promoter Score\\nPreinstalled survey.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.evenwell.nps.overlay.base\",\"description\":\"Theme overlay for Net Promoter Score?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.evenwell.nps.overlay.base.s600id\",\"description\":\"Theme overlay for Net Promoter Score?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.evenwell.nps.overlay.base.s600ww\",\"description\":\"Theme overlay for Net Promoter Score?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.evenwell.pandorasbox\",\"description\":\"WTF is this? [MORE INFO NEEDED]\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.evenwell.pandorasbox.app\",\"description\":\"WTF is this?\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.evenwell.partnerbrowsercustomizations\",\"description\":\"Adds something (Nokia-)partner-related to your browser? Probably adds bookmarks.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.evenwell.partnerbrowsercustomizations.overlay.base\",\"description\":\"Theme overlay for some browser customization?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.evenwell.partnerbrowsercustomizations.overlay.base.s600id\",\"description\":\"Theme overlay for some browser customization?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.evenwell.partnerbrowsercustomizations.overlay.base.s600ww\",\"description\":\"Theme overlay for some browser customization?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.evenwell.permissiondetection\",\"description\":\"???? [MORE INFO NEEDED]\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.evenwell.permissiondetection.overlay.base.s600ww\",\"description\":\"A theme overlay for some \\\"permissiondetection\\\" package?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.evenwell.phone.overlay.base\",\"description\":\"Some overlay for the dialer app? Overlays are usually themes.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.evenwell.phone.overlay.base.s600ww\",\"description\":\"Theme overlay for the dialer app?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.evenwell.powersaving.g3.overlay.d.base.s600e0\",\"description\":\"Theme overlay for Power Saving?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.evenwell.providers.downloads.overlay.base.s600ww\",\"description\":\"Theme overlay for the downloads app?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.evenwell.providers.downloads.ui.overlay.base.s600ww\",\"description\":\"Theme overlay for the downloads app?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.evenwell.providers.partnerbookmarks.overlay.base.s600ww\",\"description\":\"Theme overlay for Partner Bookmarks?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.evenwell.providers.weather\",\"description\":\"Provider for the Nokia weather app.\\nContent providers encapsulate data, providing centralized management of data shared between apps.\\nhttps://developer.android.com/guide/topics/providers/content-providers.html\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.evenwell.providers.weather.overlay.base.s600ww\",\"description\":\"Theme overlay for weather provider?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.evenwell.pushagent\",\"description\":\"Related to push notifications for Nokia apps?\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.evenwell.pushagent.overlay.base\",\"description\":\"Theme overlay for pushagent?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.evenwell.pushagent.overlay.base.s600id\",\"description\":\"Theme overlay for pushagent?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.evenwell.pushagent.overlay.base.s600ww\",\"description\":\"Theme overlay for pushagent?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.evenwell.retaildemoapp\",\"description\":\"Nokia retail demonstration mode\\nhttps://en.wikipedia.org/wiki/Demo_mode\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.evenwell.retaildemoapp.overlay.base\",\"description\":\"Theme overlay for Nokia retail demonstration mode?\\nhttps://en.wikipedia.org/wiki/Demo_mode\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.evenwell.retaildemoapp.overlay.base.s600id\",\"description\":\"Theme overlay for Nokia retail demonstration mode?\\nhttps://en.wikipedia.org/wiki/Demo_mode\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.evenwell.retaildemoapp.overlay.base.s600ww\",\"description\":\"Theme overlay for Nokia retail demonstration mode?\\nhttps://en.wikipedia.org/wiki/Demo_mode\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.evenwell.screenlock.overlay.base.s600ww\",\"description\":\"Theme overlay for the lock-screen?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.evenwell.settings.data.overlay.base\",\"description\":\"Overlay related to settings. Overlays are usually themes.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.evenwell.settings.data.overlay.base.s600ww\",\"description\":\"Theme overlay for settings?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.evenwell.setupwizard.btl.s600ww.overlay\",\"description\":\"Theme overlay for Setup Wizard?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.evenwell.stbmonitor\",\"description\":\"Apparently used to stabilize phone usage.\\nSeems to drain battery.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.evenwell.stbmonitor.data.overlay.base\",\"description\":\"Theme overlay for STB Monitor?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.evenwell.stbmonitor.data.overlay.base.s600id\",\"description\":\"Theme overlay for STB Monitor?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.evenwell.stbmonitor.data.overlay.base.s600ww\",\"description\":\"Theme overlay for STB Monitor?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.evenwell.telecom.data.overlay.base\",\"description\":\"Overlay related to Telecom data? Overlays are usually themes.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.evenwell.telecom.data.overlay.base.s600id\",\"description\":\"Theme overlay for something telecom-related?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.evenwell.telecom.data.overlay.base.s600ww\",\"description\":\"Theme overlay for something telecom-related?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.evenwell.weather.overlay.base.s600ww\",\"description\":\"Theme overlay for the Nokia weather app?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.evenwell.weatherservice\",\"description\":\"Service for the weather app\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.evenwell.weatherservice.overlay.base.s600ww\",\"description\":\"Theme overlay for weather service?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.evenwell.whitebalance\",\"description\":\"\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.evenwell.whitebalance.overlay.base\",\"description\":\"\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.example.alpha.chipsemitptest\",\"description\":\"ChipsemiTpTest\\nRawdata Value Test.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.example.calibrationmaster\",\"description\":\"Chinese hidden camera calibration.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.example.rftuner\",\"description\":\"Secret Code: 439. FTM/Custom Test, SAR test mode, OTA Test, ANT Switch/Select.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.example.wifirftest\",\"description\":\"Wifi Radio Frequency test\\nProbably used in factory. No hidden test menu to use it.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.facemoji.lite.transsion\",\"description\":\"Emoji Keyboard\\nHave ads and it's not good for privacy.\\nWARNING: On Infinix phones, this package is a hard dependency to show keyboard after initial reboot/startup. Without it, even if you have another keyboard installed, no keyboard will show.\\nDon't remove if you're using an Infinix phone and need to enter password after boot.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.facemoji.lite.xiaomi\",\"description\":\"Xiaomi keyboard\\nHave ads and analytics.\\nBetter alternative: https://f-droid.org/en/packages/dev.patrickgold.florisboard/\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.facemoji.lite.xiaomi.gp\",\"description\":\"Facemoji Keyboard Lite for Xiaomi - Emoji & Theme  (https://play.google.com/store/apps/details?id=com.facemoji.lite.xiaomi.gp)\\nEmoji keyboard\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.factory.mmigroup\",\"description\":\"Hidden super-menu accessible by dialing *#*#64633#*#*\\nThis menu lists all the others hidden test/debug apps.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.fairphone.activator\",\"description\":\"Fairphone activation service\\nhttps://forum.fairphone.com/t/telemetry-spyware-list-of-privacy-threats-on-fp3-android-9/55179/74\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.fairphone.myfairphone\",\"description\":\"My Fairphone app\\nhttps://www.fairphone.com/en/2021/12/20/my-fairphone-app/\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.fido.fido2client\",\"description\":\"FIDO UAF1.0 ASM\\nRelated to app fingerprint unlocking and payments. Safe to remove if you don't use passwordless authentication to access online services.\\n'com.fido.asm' is the same app.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.fido.xiaomi.uafclient\",\"label\":\"FIDO UAF1.0 Client\",\"description\":\"Fido is a set of open technical specifications for mechanisms of authenticating users to online services that do not depend on passwords.\\nThe UAF protocol is designed to enable online services to offer passwordless and multi-factor security by allowing users to register their device to the online service and using a local authentication mechanism such as iris or fingerprint recognition.\\nSafe to remove if you don't use password-less authentication to access online services.\",\"web\":[\"https://fidoalliance.org/specs/u2f-specs-1.0-bt-nfc-id-amendment/fido-glossary.html\",\"https://fidoalliance.org/specs/fido-v2.0-rd-20170927/fido-overview-v2.0-rd-20170927.html\",\"https://developers.google.com/identity/fido/android/native-apps\"],\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.fih.StatsdLogger\",\"description\":\"Foxconn stats logger\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.fih.infodisplay\",\"description\":\"Foxconn info display\\n????\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.fingerprints.extension.service\",\"description\":\"FingerprintExtensionService\\nNeeded for fingerprint sensor test.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.fingerprints.fingerprintsensortest\",\"description\":\"Sensor Test Tool\\nProvides hidden fingerprint test menu. Type *#806# in OnePlus dialer to open.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.fingerprints.fpctest\",\"description\":\"Fingerprint test\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.fingerprints.imagecollection\",\"description\":\"it's hidden image collection of fingerprint and sensor test.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.fingerprints.optical\",\"description\":\"Optical Test Tool\\nTesting things.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.fingerprints.sensortesttool\",\"description\":\"Sensor Test Tool\\nHidden test app used to test working of the fingerprint sensors.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.fingerprints.serviceext\",\"label\":\"com.fingerprints.serviceext\",\"description\":\"Fingerprint test, fingerprint authentication.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.finshell.wallet\",\"description\":\"Finshell wallet\\nWallet app by Finshell.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.flyme.aod\",\"description\":\"AlwaysOnDisplay\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.flyme.netadmin\",\"description\":\"Speedtest and security things.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.flyme.systemuiex\",\"description\":\"System UI Ext\\nLooks like an important app, has webview activity only.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.flyme.systemuitools\",\"description\":\"System UI Tools\\nLooks like an important app. It has gameassist, drivemode, windowmode things.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.flyme.telecom.usagedata.service\",\"description\":\"Phone services\\nIt's just Usage data and it will be sent to cloud probably.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.focaltech.fingerprint\",\"description\":\"Another fingerprint sensor test tool but Chinese.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.foxconn.ifaa\",\"description\":\"IFAA = (China’s) Internet Finance Authentication Alliance\\nProvides biometric authentication for Alipay. Probably safe to disable if you don't use it.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.fp.camera\",\"description\":\"Fairphone Camera app\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.fpsensor.fpSensorExtensionSvc2\",\"description\":\"Fingerprint sensor test tool\\nHidden testing Fingerprint not available for normal users.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.freemeimp.factory\",\"description\":\"aging test\\nHidden aging test.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.funbase.xradio\",\"description\":\"WOW FM\\nApp for FMRadio\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.funtouch.uiengine\",\"description\":\"FuntouchUIEngine\\nNeeded for themes probably\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.futuredial.asusdatatransfer\",\"description\":\"ASUS Phone Clone\\nit's app to move your data to new or old phone.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.futuredial.asuslocalbackup\",\"description\":\"ASUS Device backup\\nContains Google Analytics and numerous permissions.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.gallery20\",\"label\":\"AI Gallery\",\"description\":\"Stock gallery app with picture editing (filters, crop, add text, watermark, frame, blur). Sends analytics to api.meishesdk.com\",\"web\":[\"https://play.google.com/store/apps/details?id=com.gallery20\",\"https://beta.pithus.org/report/d9cf633450ed90d2c89c941c5c202845b2789ceffe6d6337ecf772d223d157de\"],\"removal\":\"replace\",\"suggestions\":\"gallery\",\"type\":\"oem\"},{\"id\":\"com.gameloft.android.ANMP.GloftA9HM\",\"description\":\"Asphalt 9: Legends\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.goodix\",\"description\":\"Hidden tests sensors, fingerprint.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.goodix.deltadiff\",\"description\":\"it's app for testing things.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.goodix.fingerprint\",\"description\":\"GFManager\\nFingerprint test? This app don't have any code.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.goodix.fingerprint.producttest\",\"description\":\"Fingerprint test\\nHidden Fingerprint testing not available for normal users.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.goodix.fingerprint.sampling\",\"description\":\"Fingerprint test\\nHidden Fingerprint testing not available for normal users.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.goodix.fingerprint.setting\",\"description\":\"In-Display Fingerprint test\\nHidden testing Fingerprint not available for normal users.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.goodix.gftest\",\"description\":\"Fingerprint test\\nHidden app that tests your fingerprint. Not available for users.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.goodix.rawdata\",\"description\":\"DrawLineTest, Raw Data Test.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.google.RilConfigService\",\"description\":\"May break calls after remove.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.google.SSRestartDetector\",\"description\":\"SubSystem Restart Service, Collects ram dump, crash count.\\nStill unknown.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.google.ambient.streaming\",\"description\":\"Access and use your Android phone's apps from your Chromebook\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.google.android.accessibility.switchaccess\",\"description\":\"Switch Access\\nhttps://play.google.com/store/apps/details?id=com.google.android.accessibility.switchaccess&hl=en_US\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.google.android.aicore\",\"description\":\"AI Core\\nLooks like AI things but code means nothing about AI or Performance.\\nhttps://developer.android.com/ml/aicore Android apps can access this package for Google Gemini.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.google.android.apps.accessibility.voiceaccess\",\"description\":\"Voice Access\\nHelps anyone who has difficulty manipulating a touch screen (e.g. due to paralysis, tremor, or temporary injury) use their Android device by voice.\\nhttps://play.google.com/store/apps/details?id=com.google.android.apps.accessibility.voiceaccess\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.google.android.apps.betterbug\",\"description\":\"Android Beta Feedback\\nAvailable on Beta Android Pixel Phones.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.google.android.apps.camera.services\",\"description\":\"Pixel Camera Services\\nExperimental stuff, Camera Calibration.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.google.android.apps.carrier.carrierwifi\",\"label\":\"Wi-Fi Provisioner\",\"description\":\"On the code I found only:\\nOpenRoaming is a network of free and secure Wi-Fi hotspots. Require google account and google play services.\\nIt can be also for wifi calling.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.google.android.apps.carrier.log\",\"description\":\"Carrier App Logging\\nRequire google play services\\nLogs everything.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.google.android.apps.cbrsnetworkmonitor\",\"description\":\"it's used for spying on you. (citizen broadband network monitor)\\nRequire google play services and have location permission.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.google.android.apps.customization.pixel\",\"description\":\"Basic 4 colors\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.google.android.apps.diagnostictool\",\"description\":\"DiagnosticTool\\nHidden testing components.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.google.android.apps.dreamliner\",\"description\":\"Pixel Stand, Google Pixel AI wallpaper.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.google.android.apps.healthdata\",\"description\":\"Useless frameworks and it's not needed for Health Connect.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.google.android.apps.helprtc\",\"description\":\"Google Support Services\\nAllows you to share your Android device screen with a Google customer support agent for a personalized support experience.\\nhttps://play.google.com/store/apps/details?id=com.google.android.apps.helprtc\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.google.android.apps.internal.betterbug\",\"description\":\"betterbug\\nbetterbug? All of these code means nothing.\\nalso have a lot of permissions and nexuslogger permission.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.google.android.apps.mediashell\",\"description\":\"Chromecast built-in\\nNeeded to support broadcast?\\nhttps://play.google.com/store/apps/details?id=com.google.android.apps.mediashell&hl=en&gl=US\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.google.android.apps.pixel.support\",\"description\":\"Pixel Troubleshooting\\nThere's Battery diagnostics also google, tiktok? account load.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.google.android.apps.pixelmigrate\",\"description\":\"Data Transfer Tool\\nIt's probably restore apps on setup wizard first-boot setup.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.google.android.apps.retaildemo.preload\",\"description\":\"Retail Demo Services\\nShould not be used for normal users.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.google.android.apps.tips\",\"description\":\"Pixel Tips\\na lot bloated.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.google.android.apps.tv.dreamx\",\"description\":\"Ambient Mode\\nRunning wallpapers from this app like a slideshow.\\nhttps://play.google.com/store/apps/details?id=com.google.android.apps.tv.dreamx&hl=en&gl=US\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.google.android.apps.tv.launcherx\",\"description\":\"Google TV\\nLauncher to TV, there's no replace probably.\\nhttps://play.google.com/store/apps/details?id=com.google.android.apps.tv.launcherx&hl=en&gl=US\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.google.android.apps.tv.netoscope\",\"description\":\"Connectivity Diagnostics\\nDiagnoses not only connectivity but also time, not needed.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.google.android.apps.wearable.retailattractloop\",\"description\":\"Demo mode - you see it in the stores (the video playing while idle).\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.google.android.apps.wearable.settings\",\"description\":\"WearOS settings\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.google.android.apps.wearables.maestro.companion\",\"description\":\"Google Pixel Buds\\nSet up and manage your Pixel Buds right from your Android 6.0+ device with the Google Pixel Buds app.\\nhttps://play.google.com/store/apps/details?id=com.google.android.apps.wearables.maestro.companion\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.google.android.apps.work.clouddpc\",\"description\":\"Device Policy\\nwork apps handling\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.google.android.apps.youtube.music.setupwizard\",\"description\":\"YT Music Setup Wizard\\nYT Music Setup Wizard?! Everything is possible.\\nI found only that they want to give you a free trial or premium.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.google.android.backdrop\",\"description\":\"Needed for screensaver.\\nhttps://play.google.com/store/apps/details?id=com.google.android.backdrop&hl=en&gl=US\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.google.android.carrier\",\"description\":\"Carrier Settings\\nGoogle Api Activity, requires GMS, totally random api's.\\nRequired for 4G, but does not cause bootloop after removal.\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.google.android.carrierlocation\",\"description\":\"Sharing location to carrier.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.google.android.carriersetup\",\"description\":\"it's only needed on first-boot setup\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.google.android.cellbroadcastreceiver.overlay\",\"description\":\"CellBroadcastReceiver overlay.\\nOverlays work by mapping resources defined in the overlay package to resources defined in the target package. When an app attempts to resolve the value of a resource in the target package, the value of the overlay resource the target resource is mapped to is returned instead.\\nThe CellBroadcastReceiver app is a default system app that handles emergency and nonemergency alerts (such as amber and presidential alerts) and presents the information to end users based on carrier and regional regulations.\\nhttps://source.android.com/docs/core/runtime/rros\\nhttps://source.android.com/docs/core/ota/modular-system/cellbroadcast\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.google.android.cellbroadcastreceiver.overlay.miui\",\"description\":\"Disable opt out dialog to cellbroadcastreceiver? I never seen that. Unused.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.google.android.cellbroadcastreceiver.rro_common\",\"description\":\"Useless overlay code for cellbroadcastreceiver\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.google.android.cellbroadcastservice.overlay\",\"description\":\"CellBroadcastService overlay.\\nOverlays work by mapping resources defined in the overlay package to resources defined in the target package. When an app attempts to resolve the value of a resource in the target package, the value of the overlay resource the target resource is mapped to is returned instead.\\nThe CellBroadcastService service supports CellBroadcast SMS decoding, geofencing for wireless emergency alert (WEA) 3.0, message duplication checks, and broadcasting messages to apps. It's a one-to-many geotargeted and geofenced messaging service designed to deliver messages to multiple mobile phone users, in a defined area, at the same time. The service is defined by the [ETSI](https://www.etsi.org/about) GSM committee, [3GPP](https://www.3gpp.org/about-3gpp), and is a part of the telecommunication standards.\\nhttps://source.android.com/docs/core/runtime/rros\\nhttps://source.android.com/docs/core/ota/modular-system/cellbroadcast\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.google.android.cellbroadcastservice.overlay.miui\",\"description\":\"cross sim duplicate detection disable? I never seen this. Unused.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.google.android.cellbroadcastservice.rro_common\",\"description\":\"Useless overlay code for cellbroadcastservice\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.google.android.chromecast.chromecastservice\",\"description\":\"Needed for broadcast support?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.google.android.chromecast.setupcustomization\",\"description\":\"Needed for Chromecast setup.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.google.android.clockwork.oemsetup\",\"description\":\"Installs carrier apps after the first time setup. Haven't noticed any consequences after uninstalling. I also saw some similar bloatware packages on the net, ending with clockwork.gestures.tutorial - first time use tutorial or clockwork.flashlight, clockwork.nfc, clockwork.brightness\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.google.android.connectivity.resources.overlay\",\"description\":\"Useless default configs (?)\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.google.android.connectivity.resources.overlay.oplus\",\"description\":\"Needed for network, may cause bootloop.\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.google.android.connectivitythermalpowermanager\",\"description\":\"powersaving?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.google.android.dialer.rro_common\",\"description\":\"Useless overlay code for Google Dialer\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.google.android.documentsui.icon_overlay\",\"description\":\"Another useless icon overlay.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.google.android.documentsui.theme.pixel\",\"description\":\"Useless code to documentsui.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.google.android.dreamlinerupdater\",\"description\":\"Dock Updater\\nUpdates to Dreamliner(Google Pixel AI wallpaper).\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.google.android.euicc\",\"label\":\"SIM Manager\",\"description\":\"eUICC (embedded UICC) refers to the architectural standards for eSIM, a device used to securely store one or more SIM card profiles, which are the unique identifiers and cryptographic keys used by cellular network service providers to uniquely identify and securely connect to mobile network devices.\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.google.android.euiccoverlay\",\"description\":\"Partner customization on first boot Setup, overlay.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.google.android.factoryota\",\"description\":\"Factory OTA Mode\\nit's for testing OTA.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.google.android.flipendo\",\"description\":\"Extreme Battery Saver\\nIt can be found in settings, lets you to choose which app are important to you to use when this feature is enabled.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.google.android.flipendo.auto_generated_rro_product__\",\"description\":\"Data connection 5G? it's for extreme battery saver.\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.google.android.flipendo.auto_generated_rro_vendor__\",\"description\":\"Data connection 5G? it's for extreme battery saver.\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.google.android.gmsintegration\",\"description\":\"it's Google Sample Home Screen. Useless.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.google.android.grilservice\",\"description\":\"Has too much random logging, metrics stuff.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.google.android.hardwareinfo\",\"description\":\"Has a lot statistics and takes info about device.\\nRequires Google Play Services, also assumes call notifications?\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.google.android.katniss\",\"description\":\"Google app, no replacement?\\nhttps://play.google.com/store/apps/details?id=com.google.android.katniss&hl=en&gl=US\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.google.android.networkstack.tethering.overlay2021\",\"description\":\"Useless hotspot configs (?)\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.google.android.odad\",\"description\":\"Google Play Protect Service\\nGoogle Play Protect Service?\\nit have only third party notices activity\\nand useless frameworks\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.google.android.overlay.flipendo\",\"description\":\"Unused colors to 5G\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.google.android.overlay.gmsconfig.healthconnect\",\"description\":\"Useless overlay gmsconfig to Health Connect\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.google.android.overlay.gmsconfig.nosafetycenter\",\"description\":\"Has no safety center in the code? Weird. Not needed.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.google.android.overlay.gmsconfig.tetheringentitlement\",\"description\":\"Useless overlay gmsconfig to tetheringentitlement. No effects after remove\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.google.android.overlay.gmsconfig.tier1\",\"description\":\"Has random set to default google apps and vivo gallery.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.google.android.overlay.gmsgsaconfig\",\"description\":\"Not needed overlay, only has code to set `googlequicksearchbox`(Google App) as default assistant\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.google.android.overlay.googleconfig\",\"description\":\"Once configs all default things to google. Bricks google login functionality.\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.google.android.overlay.googlewebview\",\"description\":\"Once configs webview default to google. Bricks google login functionality.\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.google.android.overlay.healthconnect\",\"description\":\"Overlay to 'com.google.android.apps.healthdata'.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.google.android.overlay.modules.modulemetadata.forframework\",\"label\":\"com.google.android.overlay.modules.modulemetadata.forframework\",\"description\":\"If you remove this package, your phone has an extremely large chance of bootlooping. Just don't mess around with this package. Tested on a Samsung A34 5G.\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.google.android.overlay.modules.packageinstaller\",\"description\":\"Package installer ui changes to the classic after uninstallation.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.google.android.overlay.pixelconfig2018\",\"description\":\"Useless default configs? You can lose some basic functionality so it's not worth touching it.\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.google.android.overlay.pixelconfig2019\",\"description\":\"Useless default configs? You can lose some basic functionality so it's not worth touching it.\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.google.android.overlay.pixelconfig2019midyear\",\"description\":\"Useless default configs? You can lose some basic functionality so it's not worth touching it.\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.google.android.overlay.pixelconfigcommon\",\"description\":\"Useless default configs? You can lose some basic functionality so it's not worth touching it.\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.google.android.overlay.settingsProvider\",\"description\":\"Have some stuff about google gms: backup.BackupTransportService.\\nUseless backup things, without it backup and cloud work.\\nMaybe it's used for backup settings, but probably not, and if it is, I don't think you need it.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.google.android.overlay.udfpsoverlay\",\"description\":\"Configs to fingerprints FRP auto generated.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.google.android.permissioncontroller.overlay.nothing\",\"description\":\"Better keep this for permissioncontroller. Better don't risk\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.google.android.permissioncontroller.overlay.oplus\",\"description\":\"Permission controller overlay.\\nOverlays work by mapping resources defined in the overlay package to resources defined in the target package. When an app attempts to resolve the value of a resource in the target package, the value of the overlay resource the target resource is mapped to is returned instead.\\nhttps://source.android.com/docs/core/runtime/rros\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.google.android.pixel.setupwizard.auto_generated_rro_product__\",\"description\":\"Useless first-boot setup configs\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.google.android.pixel.setupwizard.overlay\",\"description\":\"Useless first-boot setup configs\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.google.android.pixel.setupwizard.overlay2019\",\"description\":\"Useless first-boot setup configs\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.google.android.pixel.setupwizard.overlay2021\",\"description\":\"Useless first-boot setup configs\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.google.android.pixelnfc\",\"description\":\"Application that checks the SKU of a Pixel device to Region Lock the Felica chip (Japanese NFC technology used in E-money cards) of the phone to prevent non-Japanese people from using it.\\nRemoving it will make the Osaifu-Keitai crash upon start-up but will not cause any bootloop.\\nPatching it (ROOT), however allows people with a Felica Chip to add IC cards to their phone and use it to pay while in Japan.\",\"required_by\":[\"com.felicanetworks.mfm.main\"],\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.google.android.repairmode\",\"description\":\"Repair mode to Pixel, not sure how it works.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.google.android.settings.future.biometrics.faceenroll\",\"description\":\"Needed to face unlock.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.google.android.sss.authbridge\",\"description\":\"Second Screen Setup Auth Bridge\\nThere's google api's used on first boot setup.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.google.android.storagemanager.auto_generated_rro_product__\",\"description\":\"Configs to settings auto generated but better keep.\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.google.android.storagemanager.auto_generated_rro_vendor__\",\"description\":\"Configs to settings auto generated but better keep.\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.google.android.systemui.gxoverlay\",\"description\":\"Configs to systemui auto generated but better keep.\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.google.android.tungsten.setupwraith\",\"label\":\"TV Setup\",\"description\":\"First boot setup TV.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.google.android.tungsten.setupwraith\"],\"removal\":\"caution\",\"warning\":\"Removing it crashes sound related system settings and breaks volume control on Sony Bravia TV.\",\"type\":\"oem\"},{\"id\":\"com.google.android.tv\",\"description\":\"Live Channels\\nTV tuner and watching stuff, sadly has google analytics.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.google.android.tv.axel\",\"description\":\"Android TV Infrared Service\\nNeeded for volume setup.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.google.android.tv.bugreportsender\",\"description\":\"BugReportSender\\nBug reports app.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.google.android.tv.dfuservice\",\"description\":\"Remote Control Update Service.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.google.android.tv.frameworkpackagestubs\",\"description\":\"Activity Stub\\nWeird app that probably needed for SQLite, webview browser.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.google.android.tv.remote.service\",\"description\":\"Android TV Remote Service, pairing requests from your phone.\\nhttps://play.google.com/store/apps/details?id=com.google.android.tv.remote.service&hl=en&gl=US\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.google.android.tv.remotecontrol.logging\",\"description\":\"Needed for logging?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.google.android.tvlauncher\",\"description\":\"Android TV Home\\nhttps://play.google.com/store/apps/details?id=com.google.android.tvlauncher&hl=en&gl=US\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.google.android.tvrecommendations\",\"description\":\"Android TV Core Services\\nSometimes has only Notification to Android11UpgradeReceiver,\\nand on some TV's has a lot frameworks, it's weird.\\nhttps://play.google.com/store/apps/details?id=com.google.android.tvrecommendations&hl=en&gl=US\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.google.android.uvexposurereporter\",\"description\":\"UvExposureReporter, logs, VendorAtom.\\nUnknown.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.google.android.wearable.ambient\",\"description\":\"It's like doze on Android phones. Not recommended to disable, as this package reduces battery drain when idle.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.google.android.wearable.assistant\",\"description\":\"Google Assistant for Android wearables (https://play.google.com/store/apps/details?id=com.google.android.wearable.assistant)\\n\\nHas obviously all the dangerous permissions: https://beta.pithus.org/report/efccf27aa68d9c263e4288d38af76f855b5fd4156034ebdaabeb185d8c4f1411\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.google.android.wearable.batteryservices\",\"description\":\"It's used to manage battery-related things on Android smartwatches, like monitoring the battery level, managing power consumption (auto battery saving I think), and handling battery-related events (pop-up when battery at 15%, etc.). It is typically used by developers to create battery-aware applications for wearable devices.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.google.android.wearable.healthservices\",\"description\":\"Health Services by Google\\n (https://play.google.com/store/apps/details?id=com.google.android.wearable.healthservices)\\n\\nDisabling this on a Watch5 broke heart rate measuring and some workouts.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.google.android.wfcactivation\",\"description\":\"Carrier Setup\\nNeeded for IMS, WiFi calling and have emergency things.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.google.android.wifi.resources.pixel\",\"description\":\"WiFi configs\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.google.android.youtube.tv\",\"description\":\"YouTube app\\nhttps://play.google.com/store/apps/details?id=com.google.android.youtube.tv&hl=en_US\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.google.android.youtube.tvmusic\",\"description\":\"YouTube Music\\nhttps://play.google.com/store/apps/details?id=com.google.android.youtube.tvmusic&hl=en&gl=US\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.google.euiccpixel\",\"description\":\"NFC, eSE, eSIM firmware updater\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.google.euiccpixel.overlay.gs101\",\"description\":\"Overlay to (com.google.euiccpixel) NFC, eSE, eSIM firmware updater\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.google.pixel.camera.services\",\"label\":\"com.google.pixel.camera.services\",\"description\":\"CameraIDRemapper and a lot Debug stuff. A dependency for Private space on Pixel devices.\",\"web\":[\"https://source.android.com/docs/security/features/private-space\"],\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.google.pixel.digitalkey.timesync\",\"description\":\"CccDkTimeSyncService, IBluetoothCcc.\\nUnknown app to car connectivity.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.google.pixel.livewallpaper\",\"description\":\"Pixel live wallpaper\\nHave a lot of wallpapers.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.hancom.office.viewer\",\"description\":\"(discontinued) old Hancom Office Viewer\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.hawk.android.browser\",\"label\":\"Turbo Browser\",\"description\":\"Likely a WebView-based web browser. Last updated 2019. Not maintained anymore.\",\"web\":[\"https://www.apkmirror.com/apk/mie-alcatel-support/turbo-browser-private-adblocker-fast-download/\"],\"removal\":\"delete\",\"suggestions\":\"browsers\",\"type\":\"oem\"},{\"id\":\"com.heytap.appplatform\",\"description\":\"Needed for OTA Updates also causes bootloop on some phones after uninstall.\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.heytap.browser\",\"label\":\"Internet Browser\",\"description\":\"Rebranded HeyTap browser for Oppo. Full of ads and spams you in notifications. You should never use this browser.\",\"web\":[\"https://brand.heytap.com/eu/privacy.html\"],\"removal\":\"replace\",\"suggestions\":\"browsers\",\"type\":\"oem\"},{\"id\":\"com.heytap.cast\",\"description\":\"Screencast\\nPhone casting (casting phone screen to other devices).\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.heytap.cloud\",\"description\":\"HeyTap Cloud\\nBad privacy policy: https://muc.heytap.com/document/heytap/oversea/privacyPolicy/privacyPolicy_en-US.html\\nWhy does the app need `REQUEST_INSTALL_PACKAGES` (can install packages)?\\nPithus analysis: https://beta.pithus.org/report/dbf265db47f8632453bb83ef51ea1d921413c02a8d24c989345896de83704a75\",\"removal\":\"delete\",\"dependencies\":[\"com.heytap.mcs\"],\"type\":\"oem\"},{\"id\":\"com.heytap.colorfulengine\",\"description\":\"Useless frameworks for theming. Maybe needed for premium\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.heytap.datamigration\",\"description\":\"Some tools for stock browser (not Chrome), but it's Chinese and probably unused\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.heytap.habit.analysis\",\"description\":\"Most likely used to track your habits from IoT HeyTap devices [TO BE CONFIRMED]\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.heytap.headset\",\"description\":\"HeyTap Melody App used to manage Oppo Bluetooth Earphones.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.heytap.htms\",\"description\":\"Mobile Services\\nMobile services (removal may not be able to log in to OPPO account).\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.heytap.linker\",\"description\":\"DistUI\\nNeeded for broadcast\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.heytap.market\",\"description\":\"Heytap/Oppo app store.There is no benefit of using this app store and you should not keep a privileged app with as many permissions.\\n\\nhttps://developers.oppomobile.com/newservice/capability?pagename=app_store\\nPithus analysis: https://beta.pithus.org/report/3a2a10af9310411d814fd6dd252adec1ab0c06adf32a675b7534c3edc0e534bf\",\"removal\":\"delete\",\"dependencies\":[\"com.heytap.mcs\"],\"type\":\"oem\"},{\"id\":\"com.heytap.mcs\",\"label\":\"System Messages\",\"description\":\"System messages with trackers.\",\"web\":[\"https://beta.pithus.org/report/8920395af63782fca8dfce18715a10ca5a2d8236d525208ea347eff8f738731e\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.heytap.music\",\"label\":\"Music\",\"description\":\"Default Oppo Music App with insecure WebView Implementation (execution of user controlled code in WebView is an important security hole).\\nHas also weird permissions (QUERY_ALL_PACKAGES and BLUETOOTH ?).\",\"web\":[\"https://beta.pithus.org/report/befa0ec0616c553632379f069453b0ca74ee29fd1428b9fce19c1657e6f97d8b\"],\"removal\":\"replace\",\"suggestions\":\"music_apps\",\"type\":\"oem\"},{\"id\":\"com.heytap.mydevices\",\"description\":\"My devices\\nMy devices (showing headphones and such)\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.heytap.openid\",\"description\":\"OpenID\\nDevice logos and advertisements; uninstallation causes anomalies in cloud drive functionality\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.heytap.pictorial\",\"label\":\"Lock Screen Magazine\",\"description\":\"It provides high-quality wallpapers and allows users to customize their lock screens. Every time you wake your screen, the wallpaper automatically changes.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.heytap.pictorial\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.heytap.quicksearchbox\",\"description\":\"Global Search\\nRealme. This will remove the single swipe from top to bottom search that has lots of Chinese in it.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.heytap.speechassist\",\"description\":\"Breeno Voice\\nBreeno assistant.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.heytap.synergy\",\"description\":\"HeySynergy\\nAnother thing related to broadcast\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.heytap.themestore\",\"description\":\"Theme Store with 73 permissions! (including CAMERA, CALL_PHONE, READ_CONTACTS, REQUEST_INSTALL_PACKAGES...) and 2 trackers.\\n\\nPithus analysis: https://beta.pithus.org/report/e8c4fc2bae420cf5f094ce914f25accdede5152f9d801db6eb32a4020a7726b2\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.heytap.usercenter\",\"description\":\"Login service for various HeyTap related services like HeyTap Cloud etc.\\nNeeded if you want to join Early Access Testing for new ColorOS/RealmeUI\\n\\n[APK NEEDED]\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.heytap.usercenter.overlay\",\"description\":\"overlay needed to usercenter app has resources\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.heytap.yoli\",\"description\":\"Video player with Chinese tracking.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.hicloud.android.clone\",\"description\":\"Huawei Phone Clone (https://play.google.com/store/apps/details?id=com.hicloud.android.clone)\\n171 Permissions (https://reports.exodus-privacy.eu.org/fr/reports/144565/)\\nData migration application between Huawei phones.\\nKeep in mind that all your data will be synchronised in the Huawei cloud and collected by the company.\\nhttps://cloud.huawei.com/privacyStatementTransit\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.hilauncherconfig\",\"description\":\"Configures app icons and folders on first run HiOS Launcher.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.hisi.mapcon\",\"description\":\"Uses Location permissions for VoWifi Special, rtc wifi signal.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.hisi.supl\",\"description\":\"SUPL20Services\\nNot needed for location and dont have code.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.hiya.axolotl.tcl\",\"description\":\"\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.hiya.star\",\"description\":\"also called android-ss-service-lib (Samsung-exclusive)\\nThird-party that provides caller profile information to help consumers identify incoming calls and block unwanted ones.\\nhttps://en.wikipedia.org/wiki/Hiya_(company)\\nhttps://hiya.com/\\nNOTE : Never trust a company which promotes spam blocking features\\nhttps://itmunch.com/robocall-caught-sending-customers-confidential-data-without-consent/\\n\\nHave a look at their privacy policy. That's... pretty scary : https://hiya.com/fr/hiya-data-policy\\nNeeded for Samsung Smart Call (com.samsung.android.smartcallprovider)\",\"removal\":\"delete\",\"required_by\":[\"com.samsung.android.smartcallprovider\"],\"type\":\"oem\"},{\"id\":\"com.hmdglobal.camera2\",\"description\":\"Nokia camera (https://play.google.com/store/apps/details?id=com.hmdglobal.camera2)\\n\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.hmdglobal.datago\",\"description\":\"Sends diagnostic data to HMD (Company behind Nokia)?\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.hmdglobal.datago.overlay.base\",\"description\":\"Theme overlay for a Nokia telemetry package?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.hmdglobal.datago.overlay.base.s600ww\",\"description\":\"Theme overlay for a Nokia telemetry package?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.hmdglobal.enterprise.api\",\"description\":\"I can't find this app on the internet, but I heard it has telemetry.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.hmdglobal.support\",\"description\":\"My Phone (https://play.google.com/store/apps/details?id=com.hmdglobal.support)\\nLets you join the Nokia phones community, get app recommendations, explore your phone’s user guide and more.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.hoffnung\",\"description\":\"TPMS. Remote Config Test.\\n⚠️ WARNING: uninstalling might cause bootloops and screen flicker! Disabling this also may remove the ability to see notifications on your lock screen.\\nhttps://xdaforums.com/t/infinix-note-10-uninstall-tpms-com-hoffnung-package-causes-bootloop.4647456\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.htc.masthead\",\"description\":\"HTC Lockscreen Theme.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.htc.weather\",\"description\":\"HTC Weather\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.huaqin.btlogger\",\"description\":\"btlogger\\ncit bluetooth logging\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huaqin.diaglogger\",\"description\":\"Secret logging menu only accessible by dialing using a \\\"secret code\\\" (*#*#CODE#*#*)\\nYou can use any of these code : \\\"995995\\\", \\\"996996\\\", \\\"9434\\\", \\\"334334\\\", \\\"5959\\\", \\\"477477\\\"\\nUsed to log Bluetooth traffic and send them to com.miui.bugreport\\nWrite logs to \\\"/sdcard/diag_logs/\\\" | \\\"/sdcard/wlan_logs/\\\" | \\\"/sdcard/MIUI/debug_log/common/\\\"\\n#\\nFYI Huaqin is a Chinese mobile phone research and development company.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huaqin.factory\",\"description\":\"Hidden test app (dial *#*#64663#*#*)\\nUsed by technician in factory to test the hardware. Not intented to be run by end-users. \\nHas a huge amount of permissions.\\nA vulnerability was found in 2019 (CVE-2019-15340) allowing any app co-located on the device to \\nprogrammatically disable and enable Wi-Fi, Bluetooth, and GPS silently (and without the corresponding access permission)\\nhttps://nvd.nist.gov/vuln/detail/CVE-2019-15340\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huaqin.sar\",\"description\":\"SetTransmitPower\\nI can't access the apk but I'm pretty sure it is another hidden test app not meant to be used by end-user\\nGiven its name it could be used to adjust the transmit power of the cell phone antennas\\nSAR = Specific Absorption Rate (https://en.wikipedia.org/wiki/Specific_absorption_rate)\\nXDA users removed this without any issues. To be 100% sure it would be good to test the SAR without this package (just in case)\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.HwMultiScreenShot\",\"description\":\"Scrolling screenshot feature\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.KoBackup\",\"description\":\"As of writing this, Huawei phones cannot be rooted. \\nThis Backup application is probably able to backup more than any other 3rd party backup app.\\n\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.huawei.airlink\",\"description\":\"Air link service, it's probably needed for Wireless Projection.\\nNo activities, only more debugging stuff, location things, logs\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.huawei.android.FMRadio\",\"description\":\"FM-Radio\\nHuawei's stock radio player. Remove if FM isn't relevant for you.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.huawei.android.FloatTasks\",\"description\":\"Floating/Navigation dock (also called NaviDot).\\nhttps://consumer.huawei.com/en/support/how-to/detail-troubleshooting/en-us00310067/\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.android.airsharing\",\"description\":\"Wireless Projection\\nMiracast, Requires Huawei Mobile Services, also it's so bloated, also found unused frameworks HUAWEI GameCenter\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.huawei.android.chr\",\"description\":\"HwChrService\\nHuawei Call History Record. \\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.android.dsdscardmanager\",\"label\":\"Dual SIM settings\",\"description\":\"It's sim card management in Huawei settings.\",\"removal\":\"unsafe\",\"warning\":\"Upon removing, sim card management in settings will no longer work.\",\"type\":\"oem\"},{\"id\":\"com.huawei.android.findmyphone\",\"description\":\"Find Device is an app that lets you locate your device and protect your data remotely.\\nTo provide these features, this app needs to connect to the Internet during use.\",\"dependencies\":[\"com.huawei.hwid\"],\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.huawei.android.hsf\",\"description\":\"Huawei Services Framework\\n3 permissions : DELETE_PACKAGES, INSTALL_PACKAGES, PACKAGE_USAGE_STATS\\nSafe to remove according to huawei users\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.android.hwaps\",\"label\":\"HwAps\",\"description\":\"Manages Intelligent Resolution and changing screen resolution in settings.\",\"removal\":\"unsafe\",\"warning\":\"Upon removing, Intelligent Resolution will be not available, and screen resolution cannot be changed in settings.\",\"type\":\"oem\"},{\"id\":\"com.huawei.android.hwouc\",\"label\":\"System Update\",\"description\":\"OTA updates. Safe to remove if you have a very outdated device or flashed recovery.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.huawei.android.hwpay\",\"description\":\"Huawei Pay\\nMobile payment and e-wallet service for Huawei devices that offers the same services as Apple Pay, Samsung Pay etc...\\nhttps://consumer.huawei.com/en/mobileservices/huawei-wallet/\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.android.hwupgradeguide\",\"label\":\"HwUpgradeGuide\",\"description\":\"It's guide menu at first start AppGallery.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.android.instantonline\",\"label\":\"HwInstantOnline\",\"description\":\"No noticeable consequences.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.android.instantshare\",\"description\":\"Huawei Share features.\\nFile transfer tool between Huawei mobiles, using Bluetooth connection and WiFi Direct technology.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.android.internal.app\",\"label\":\"Android HwResolver\",\"description\":\"Component of Huawei sharing.\",\"removal\":\"caution\",\"warning\":\"This may break the sharing function in some apps causing them to crash.\",\"type\":\"oem\"},{\"id\":\"com.huawei.android.karaoke\",\"description\":\"Karaoke mode feature.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.android.launcher\",\"description\":\"Huawei launcher app.\\nIt's basically the home screen, the way icons apps are organized and displayed.\",\"removal\":\"replace\",\"warning\":\"Make sure you've another installed before you disable.\\nMaybe you'll need this package for the recent apps feature to work (even if you have another launcher installed)\",\"suggestions\":\"launchers\",\"type\":\"oem\"},{\"id\":\"com.huawei.android.mirrorshare\",\"description\":\"MirrorShare feature (Miracast rebranded by Huawei)\\nUsed to mirror screen of you smartphone on a TV.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.android.overlay.modules.modulemetadata\",\"description\":\"Module that contains metadata about the list of modules on the device and that's about it. I wouldn't advise you to mess with it as it could break important modules (see W1nst0n/universal-android-debloater#37 on GitLab).\\nGood explanation of what Android modules are: https://www.xda-developers.com/android-project-mainline-modules-explanation/\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.huawei.android.projectmenu\",\"label\":\"ProjectMenu\",\"description\":\"Hidden settings not available for users. ProjectMenu interface: phone *#*#2846579#*#*\",\"web\":[\"https://www.99mediasector.com/open-project-menu-huawei-device-huawei-code/\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.android.pushagent\",\"description\":\"push notification agent\\nSeems to only be used for Huawei apps\\nThe recompiled java code makes it look like it's once again mainly used for analytics.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.android.remotecontroller\",\"description\":\"Huawei Smart Controller app.\\nLets you you add, customize, and set up remote controls, allowing control of your electronic appliances through your phone. \\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.android.rftest\",\"description\":\"HwRFTest\\nMT Test Station.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.android.thememanager\",\"label\":\"Themes\",\"description\":\"Lets you download and use Huawei themes.\",\"removal\":\"caution\",\"warning\":\"After uninstalling the app, setting wallpapers directly will no longer work, but the wallpaper entry in the Settings app will still let you choose wallpapers. Without this package, you may no longer be able to change a notification sound.\",\"type\":\"oem\"},{\"id\":\"com.huawei.android.tips\",\"description\":\"HUAWEI Feature Advisor\\nPeriodically gives you notifications on how to use certain features on your phone.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.android.totemweather\",\"description\":\"Huawei Weather app (and its widget)\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.android.totemweatherapp\",\"description\":\"Huawei Weather app (and its widget)\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.android.totemweatherwidget\",\"description\":\"Huawei Weather app (and its widget)\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.android.wfdft\",\"description\":\"Wi-Fi Direct feature.\\nNote: Wifi direct enables devices to establish a direct Wi-Fi connection (without a router) over which the two can send and receive files.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.android.wfdirect\",\"description\":\"Wi-Fi Direct feature.\\nNote: Wifi direct enables devices to establish a direct Wi-Fi connection (without a router) over which the two can send and receive files. \\n\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.huawei.androidx\",\"description\":\"It have something to MediaPlayer but by name app it looks like important.\\nSomeone will need to check if it bootloop or not because this app dont have code.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.huawei.aod\",\"description\":\"Always On Display\\nWhen enabled in settings it shows clock and notifications when you raise the phone or touch the screen.\\nThis is basically a lower-power lock-screen. It could in theory reduce power draw if you check notifications/clock often as OLED screens draw minimal power showing a mostly black screen(black = pixel off), but in practice the number of times you'll unintentionally trigger it will likely eat up any potential power savings and more. And if your device doesn't have an OLED screen this will draw way more power.\\nMost of these power savings could be applied to your standard lock-screen simply by making your background image completely black.\\nRedSkull23 says it's unsafe to remove. Does it bootloop?\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.appmarket\",\"description\":\"Huawei app store (AppGallery)\\nhttps://www.xda-developers.com/appgallery-huawei-alternative-google-play-store-android/\\n\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.huawei.ar.measure\",\"description\":\"Ar Measure\\nMeasure length, depth, area and volume.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.arengine.service\",\"description\":\"Augmented reality service.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.assetsync\",\"description\":\"HwAssetSync\\nNeeded for HiCloud, Cloud syncing.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.assetsyncservice\",\"description\":\"It's for 'com.huawei.securityserver' for start this service app.\\nNeeded for HiCloud sync security.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.audioaccessorymanager\",\"description\":\"Audio Accessory Manager\\nA lot stuff: Huawei health, Huawei music, earphones.\\nProbably only useful when you got Huawei FreeBuds.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.autoinstallapkfrommcc\",\"label\":\"Information\",\"description\":\"Auto Install apk from mcc\\nAuto Install apk from mcc? it's only information and logs.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.bd\",\"description\":\"HwUE (Huawei UserExperience)\\nWhen a company call a something 'UserExperience' you know you don't need this.\\nAnalytics service, run at boot. Collect information about packages/apps usages.\\nHas a nice custom permission called com.huawei.permission.BIG_DATA\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.behaviorauth\",\"description\":\"It seems to be related to verifying the authenticity of user behavior and enhancing password security. User can disable it so it's safe to remove.\",\"web\":[\"https://www.android-hilfe.de/forum/huawei-p30-p30-pro-p30-lite.3510/was-ist-die-behaviorauth-app-fuer-das-p30.1008750.html\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.betaclub\",\"description\":\"BetaClub\\nIt's app for testing, collection logs and feedback.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.bluetooth\",\"description\":\"Lets you import your contacts via Bluetooth\\nBluetooth will still work if you remove this package.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.browser\",\"description\":\"Huawei Browser app. Don't expect privacy using it\\n\",\"removal\":\"replace\",\"suggestions\":\"browsers\",\"type\":\"oem\"},{\"id\":\"com.huawei.browserhomepage\",\"description\":\"Huawei Browser component.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.ca\",\"description\":\"CA\\nUses permissions: GET_TASKS, LOCATION_HARDWARE, etc.\\nThis app looks like a backdoor or logs.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.calculator\",\"description\":\"Calculator app\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.huawei.calendar\",\"description\":\"Huawei Calendar app.\\n\",\"removal\":\"replace\",\"suggestions\":\"calendars\",\"type\":\"oem\"},{\"id\":\"com.huawei.camera\",\"label\":\"HUAWEI Camera\",\"description\":\"Huawei's stock Camera app\",\"removal\":\"replace\",\"suggestions\":\"cameras\",\"type\":\"oem\"},{\"id\":\"com.huawei.camerakit.impl\",\"description\":\"HwCameraKit\\nIn the code it was found that it's for testing camera functions.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.cloud\",\"description\":\"Chinese only.\\nHuawei Cloud Computer provides you with basic services of online desktop.\",\"dependencies\":[\"com.huawei.hwid\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.coauthservice\",\"description\":\"HwCoAuthService\\nApplock, lockscreen password, face recognition things, fingerprint, not sure if it's worth removing it.\\nNeeded for manual apk installation.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.huawei.compass\",\"description\":\"Huawei Compass app.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.contacts\",\"description\":\"Huawei Contacts app\\n\",\"removal\":\"replace\",\"suggestions\":\"contacts\",\"type\":\"oem\"},{\"id\":\"com.huawei.contacts.sync\",\"description\":\"Huawei Contacts sync\\nMy guess (can't have the apk on hand) is this enables you to synchronise your contacts with your Huawei account.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.contactscamcard\",\"description\":\"CamCard is a business card reader app.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.contentsensor\",\"description\":\"ContentSensor\\nLooks like this app has a lot chinese code and collects a lot stuff about user like apps installed, app info, connects to huawei hivoice sites\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.controlcenter\",\"description\":\"Smart Collaboration\\nCollaboration between devices. Needed for Multi-Screen, Wireless Projection?\\nNeeded for Super Device or Device+, safe to remove if you don't use this, it will also declutter action center.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.huawei.cryptosms.service\",\"description\":\"SMS Encryption Service, looks made for China.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.def\",\"description\":\"DEF\\nUnused? message things:allows the app public keys on connected devices, getting status, access information\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.huawei.deskclock\",\"description\":\"Huawei Clock App.\\n\",\"removal\":\"replace\",\"suggestions\":\"clocks\",\"type\":\"oem\"},{\"id\":\"com.huawei.desktop.explorer\",\"description\":\"From XDA thread : \\\"Service that is been used when you wanna use your phone as an operative system on a PC.\\\"\\nI don't understand what does it mean.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.desktop.systemui\",\"description\":\"Huawei desktop mode switching\\nIt has also Take Screenshot Service.\\nRequire HMS, has a lot tracking.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.huawei.deviceauth\",\"description\":\"TrustedDeviceAuth\\nI guess it's for authentication keys\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.huawei.devicegroupmanage\",\"description\":\"(Unused?)HwGroupManager\\nIt's an app without activities, only device info things\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.huawei.devicemanager\",\"description\":\"Needed for Huawei account. I found only things: installing service?, Linked devices, Multi-Device management, connection code, metrics\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.distributed.kms\",\"description\":\"HwDistributedKeyManager\\nHas random frameworks, probably needed for huawei account, authentication\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.distributedpasteboard\",\"description\":\"SuperHub\\nHas something to History Clipboard and Drag Drop.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.huawei.dmsdp\",\"description\":\"Multi-Device management\\nThis service allows you to virtually expand your devices capabilities\\nby connecting to other devices and using them as an extension of this device.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.huawei.dsdscardmanager\",\"description\":\"Dual card management\\nIt's sim card management in Huawei settings.\\nAfter removing, sim card management in settings will not work.\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.huawei.dtmfanalyzer\",\"description\":\"Dtmf Analyzer\\nHas something to media player to ride mode for China.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.easygo\",\"description\":\"HwEasyGo\\nLooks like a backdoor for WeChat app?\\nEasyGoServer, error code things found, also EasyGoCallBack.\\nThese app is probably backdoor or for developers.\\nThis app has no permissions and no activities.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.email\",\"description\":\"Huawei Email app.\\n\",\"removal\":\"replace\",\"suggestions\":\"email_clients\",\"type\":\"oem\"},{\"id\":\"com.huawei.entitlement\",\"description\":\"Needed for messages Bluetooth, wifi, hotspot, Terms of Agreement, Authentication?\\nOn some phone's it has some features, and on some not.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.huawei.fans\",\"description\":\"Huawei Club is the official forum for Huawei users.\\nIt provides the latest news and information, FAQs, and tutorials about Huawei and Honor products.\",\"dependencies\":[\"com.huawei.hwid\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.fastapp\",\"description\":\"Quick App Center\\nComponent of AppGallery (Huawei's app store) providing Quick Apps support. Quick Apps are Javascript+CSS apps that don't need any installation. This technology has its uses but I'm personally not a huge fan on having to rely on a JS engine to run an application\\nThis system app has a lot of permissions (including SEND_SMS, CAMERA, READ_EXTERNAL_STORAGE, RECORD_AUDIO... why?)\\nMore information: https://www.xda-developers.com/huawei-quick-apps-alternative-google-instant-apps/\\n OW2 Quick App whitepaper: https://quick-app-initiative.ow2.io/docs/Quick_App_White_Paper.pdf\",\"removal\":\"replace\",\"dependencies\":[\"com.huawei.hwid\"],\"type\":\"oem\"},{\"id\":\"com.huawei.featurelayer.featureframework\",\"description\":\"FeatureFramework\\nAllows the app to check for feature updates.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.huawei.featurelayer.sharedfeature.map\",\"description\":\"Huawei Map Service\\nRequire FeatureFramework.\\nOnly uses Chinese AMap to get location.\\nUsed to show maps inside Calendar and Gallery, they will complain if you uninstall it, disable instead.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.fido.uafclient\",\"label\":\"FIDO UAF Client\",\"description\":\"Fido is a set of open technical specifications for mechanisms of authenticating users to online services that do not depend on passwords.\\nThe UAF protocol is designed to enable online services to offer passwordless and multi-factor security by allowing users to register their device to the online service and using a local authentication mechanism such as iris or fingerprint recognition.\\nSafe to remove if you don't use password-less authentification to access online servics.\",\"web\":[\"https://fidoalliance.org/specs/u2f-specs-1.0-bt-nfc-id-amendment/fido-glossary.html\",\"https://fidoalliance.org/specs/fido-v2.0-rd-20170927/fido-overview-v2.0-rd-20170927.html\",\"https://developers.google.com/identity/fido/android/native-apps\"],\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.huawei.filemanager\",\"label\":\"Files\",\"description\":\"Huawei file manager\\nProbably fine to remove as long as you have another file manager.\",\"removal\":\"replace\",\"suggestions\":\"file_managers\",\"type\":\"oem\"},{\"id\":\"com.huawei.firstbootinfo\",\"description\":\"Get city info service\\nGet city info service? Needed by your phone in order to sync with Huawei servers\\nand check for apps updates, software updates and other access for your phone.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.huawei.game.kitserver\",\"label\":\"HUAWEI Game KitServer\",\"description\":\"Probably safe to remove if you don't play games\\nHas window show, keybind set and more things.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.huawei.gameassistant\",\"description\":\"Huawei Game Suite (HiGame).\\nMobile game app store.\\nhttps://club.hihonor.com/in/topic/16341/detail.htm\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.gamebox\",\"description\":\"GameCenter\\nRequires HMS Core to run.\\nIt's app for installing games.\",\"dependencies\":[\"com.huawei.hwid\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.geofence\",\"description\":\"GeofenceService.\\nAllows you to do something when a user enters an area that has been defined as a trigger.\\nA geofence is a virtual perimeter set on a real geographic area. Combining a user position with a geofence perimeter, \\nit is possible to know if the user is inside or outside the geofence or even if he is exiting or entering the area.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.harmonyos.foundation\",\"description\":\"foundation\\nHas hwid, vehicle things, Aosp In Call Service permissions.\\nDisable app instead of uninstalling, because breaks calling.\\nSettings app and APK installation will become slow if you uninstall this.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.huawei.health\",\"label\":\"Huawei Health\",\"description\":\"Connect Huawei wearables to your phone and all sorts of stats like all fitness tracking apps.\",\"dependencies\":[\"com.huawei.hwid\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.hff\",\"description\":\"HFF\\nHFF? It has not any code.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.hiaction\",\"label\":\"HiAction\",\"description\":\"No noticable consequences\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.hiai\",\"label\":\"HUAWEI HiAI Engine\",\"description\":\"No noticable consequences\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.hiassistantoversea\",\"description\":\"HiVoice. Huawei's voice assistant to replace \\\"Hey Google\\\"\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.hicar\",\"description\":\"Huawei HiCar\\nTo connect to Huawei HiCar, press and hold the wireless button on the steering wheel or control panel.\\nMore useful in China.\",\"dependencies\":[\"com.huawei.hwid\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.hicard\",\"label\":\"HiCard\",\"description\":\"Huawei Cards. No noticable consequences\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.hicloud\",\"description\":\"Huawei cloud features\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.hidisk\",\"description\":\"Huawei File Manager app.\\n\",\"removal\":\"replace\",\"suggestions\":\"file_managers\",\"type\":\"oem\"},{\"id\":\"com.huawei.hifolder\",\"description\":\"Huawei Online Cloud folder service\\nhttps://consumer.huawei.com/en/mobileservices/mobilecloud/\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.hilink.framework\",\"description\":\"AI Life Service\\nUsed for smart devices and to run smart scenes.\\nIt's more useful in China.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.himovie\",\"label\":\"Huawei Video Player\",\"description\":\"Bloated on newer versions. Can be safely removed if you don't want it.\",\"removal\":\"replace\",\"suggestions\":\"video_players\",\"type\":\"oem\"},{\"id\":\"com.huawei.himovie.overseas\",\"label\":\"HUAWEI Video\",\"description\":\"Huawei stock video application. Has a lot of trackers.\",\"removal\":\"replace\",\"suggestions\":\"video_players\",\"type\":\"oem\"},{\"id\":\"com.huawei.himovie.partner1\",\"description\":\"HiMoviePlayerPlus\\nWeird app without any code and there's nothing in Main Activity.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.himovie.partner2\",\"description\":\"HiMoviePlayerPlus\\nWeird app without any code and there's nothing in Main Activity.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.hiskytone\",\"description\":\"SkyTone Overseas Data Service.\",\"dependencies\":[\"com.huawei.hwid\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.hisuite\",\"description\":\"Can be uninstalled via settings. App to connect with the desktop program to Backup/Restore, flash firmware, etc.\\nhttps://consumer.huawei.com/en/support/hisuite/\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.hitouch\",\"description\":\"Huawei HiTouch\\nAssistant capable to recognize the objects in a photo and to search them through various shopping sites.\\nhttps://consumer.huawei.com/uk/support/faq/have-you-tried-the-new-hitouch-assistant/\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.hiview\",\"label\":\"hiview\",\"description\":\"Provides info on exposure and so on in the gallery\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.hiviewtunnel\",\"label\":\"HiViewTunnel\",\"description\":\"This displays details/attributes of pictures in the gallery (ISO, exposure time, etc.).\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.hms5gkit.agentservice\",\"label\":\"HwModemKitAgentService\",\"description\":\"Something to do with 5G? For some reason, this is also installed on a non-5G device. Can be uninstalled from phone settings so should be safe if you don't have 5G.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.huawei.honorclub.android\",\"description\":\"Honor Club\\nHuawei's social media app. Safe to remove.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.hwasm\",\"label\":\"FIDO UAF ASM\",\"description\":\"FIDO UAF Autenthicator-Specific Module.\\nSee 'com.huawei.fido.uafclient' for FIDO explaination.\\nThe UAF Authenticator-Specific Module (ASM) is a software interface on top of UAF authenticators which gives a standardized way for FIDO UAF clients to detect and access the functionality of UAF authenticators and hides internal communication complexity from FIDO UAF Client.\",\"web\":[\"https://fidoalliance.org/specs/fido-uaf-v1.0-ps-20141208/fido-uaf-asm-api-v1.0-ps-20141208.html\"],\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.huawei.hwblockchain\",\"label\":\"HwBlockChain\",\"description\":\"Probably blockchain related. No noticable consequences when removed\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.hwddmp\",\"description\":\"HwDDMP\\nHas a lot frameworks.\\nUninstalling breaks calling app even if you disable.\\nIt does not cause bootloop but removing is highly not recommended.\\nNot only breaks the dialer app, but causes lag in whole system too.\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.huawei.hwdetectrepair\",\"label\":\"Smart diagnosis\",\"description\":\"(Discontinued?) Useless features and run in background.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.hwdiagnosis\",\"description\":\"HwDiagnosis\\nNo activities, only code about diagnosis and logs\\nAlso device info and is send to Huawei servers.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.hwdockbar\",\"label\":\"Multi-Window\",\"description\":\"Probably fine to remove if you're not using Huawei Multi-Window features.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.huawei.hwesimservice\",\"description\":\"HwESIMService\\nIf you use eSIM do not remove it.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.huawei.hwid\",\"label\":\"HMS Core\",\"description\":\"Huawei Mobile Services\\nHuawei’s alternative to Google Play Services. Needed to access advanced Huawei features.\\nA Huawei ID is required to access services, like Themes, Mobile Cloud, HiCare, Huawei Wear, Huawei Health.\",\"web\":[\"https://www.xda-developers.com/huawei-hms-core-android-alternative-google-play-services-gms/\",\"https://github.com/0x192/universal-android-debloater/issues/477\"],\"removal\":\"replace\",\"required_by\":[\"com.huawei.fastapp\"],\"warning\":\"This may break apps like InPost Mobile\",\"type\":\"oem\"},{\"id\":\"com.huawei.hwireader\",\"description\":\"App for adding by user 'Books'. This app has ads and bad privacy.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.hwpanpayservice\",\"label\":\"HwPanPayService\",\"description\":\"Payment related service.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.hwpolicyservice\",\"description\":\"HwPolicyService\\nAnother debugging, logs app.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.hwread.dz\",\"description\":\"App for adding by user 'Books'. This app has ads and bad privacy.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.hwsearch\",\"label\":\"Petal Search\",\"description\":\"Huawei search widget. Used for finding apps/apks on serveral online sources (introduced after Google Mobile Services Ban).\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.hwstartupguide\",\"description\":\"A one-time setup app that is no longer needed\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.hwusbearphoneupdate\",\"description\":\"Huawei digital earphones come with built-in software that can be updated regularly to enhance your audio experience.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.huawei.hwvoipservice\",\"label\":\"MeeTime Service\",\"description\":\"Voice over IP service for Huawei MeeTime (com.huawei.meetime). Only works with EMUI 9.1+ Huawei phones.\\nHuawei claims they use E2EE but this wasn't verified and there is no whitepaper, so don't trust them.\\nThey also collect metadata.\",\"web\":[\"https://consumer.huawei.com/en/support/content/en-us00956296/\"],\"removal\":\"replace\",\"required_by\":[\"com.huawei.meetime\"],\"suggestions\":\"instant_messaging_apps\",\"type\":\"oem\"},{\"id\":\"com.huawei.hwvplayer.youku\",\"description\":\"Video Youku\\nVideo Player on Chinese Huawei. Has some ads and bad privacy.\",\"dependencies\":[\"com.huawei.hwid\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.iaware\",\"description\":\"App Prioritizer. Prioritizes apps to avoid slowdown. Up to you but there is apparently no noticeable difference when deleted?\\nSystem will start lagging a little bit (you will notice it while scrolling and on some animations, for example scrolling installed apps), battery consumption will become slightly higher and battery stats will disappear soon. At the same time, logcat will be full of errors like: PowerKit: PG Server is not found. calling pid xxxx.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.huawei.iconnect\",\"label\":\"Device connection service\",\"description\":\"Hidden menu 'install PCAssistant' when connected to PC? I have never seen it. Safe to remove.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.ihealth\",\"description\":\"MotionService package, it's required for actions like shaking the phone to shut off the alarm, ecc.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.imedia.dolby\",\"description\":\"Dolby Atmos\\nOptimize sound automatically for exceptional audio quality.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.huawei.imedia.sws\",\"label\":\"HUAWEI Histen\",\"description\":\"Audio 3D effects found in the settings. Safe to remove if you don't use these settings.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.imonitor\",\"description\":\"imonitor\\nHidden logs founded in app.\\nDetects app launch anomaly and runs safe mode.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.ims\",\"description\":\"HwImsService\\nVoLTE(Voice over LTE) calls. IP multimedia subsystem.\\nhttps://en.wikipedia.org/wiki/Voice_over_LTE\\nUninstalling app breaks sim calling even if you disable.\\nIt does not cause bootloop but removing is highly not recommended.\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.huawei.indexsearch\",\"description\":\"Index search works without it.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.indexsearch.observer\",\"description\":\"Index search works without it.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.indiacalendar\",\"description\":\"Indian Calendar\\nHUAWEI Calendar\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.huawei.intelligent\",\"description\":\"Huawei Assistant. Shopping recommendations\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.internetaudioservice\",\"description\":\"Smart headset control\\nHas a lot logs and frameworks to mmitest.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.languagedownloader\",\"description\":\"Allows you to load the system languages when changing them\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.huawei.lbs\",\"description\":\"Location Based Services\\nLocation-based services (LBS) are applications or services that utilize location data from a user's device, such as a smartphone or GPS, to provide relevant information, directions, or recommendations tailored to their specific location. These services rely on a combination of technologies, including Global Positioning System (GPS), Wi-Fi, cellular networks, and sensors, to determine a user's position accurately.\\nNOTE: Can cause bootloops on some devices.\\nThe primary goal of LBS is to offer personalized and context-aware experiences based on a user's geographical location. This can include services like:\\n1. Navigation and Mapping, 2. Location-Based Advertising, 3. Social Networking, 4. Emergency Services, 5. IoT Asset Tracking\\nhttps://forum.huawei.com/enterprise/en/location-based-services/thread/703168442200375296-667213855346012160\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.huawei.lives\",\"description\":\"HiLives is jointly developed by Huawei and certified third-party service providers to provide lifestyle services for you.\",\"dependencies\":[\"com.huawei.hwid\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.livewallpaper.artflower\",\"description\":\"Live wallpapers\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.livewallpaper.flowersbloom\",\"description\":\"Live wallpapers\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.livewallpaper.mountaincloud\",\"description\":\"Live wallpapers\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.livewallpaper.naturalgarden\",\"description\":\"Live wallpapers\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.livewallpaper.paradise\",\"description\":\"Live wallpapers\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.livewallpaper.ripplestone\",\"description\":\"Live wallpapers\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.localbackup\",\"description\":\"Huawei Backup\\nhas a lot permissions and can backup your data\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.magazine\",\"description\":\"Magazine unlock. Downloads wallpapers for your lock screen.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.manufacture.wificonnect\",\"description\":\"Wifi Connect\\nNeeded for WiFi connection?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.huawei.maps.app\",\"label\":\"Petal Maps\",\"description\":\"Huawei map and navigation app with HMS (Huawei Mobile Services) trackers.\\n\",\"web\":[\"https://play.google.com/store/apps/details?id=com.huawei.maps.app\",\"https://beta.pithus.org/report/d15349e7a998306012462484f270f93794141113d6680fa8512931c270adf830\"],\"removal\":\"replace\",\"suggestions\":\"maps\",\"type\":\"oem\"},{\"id\":\"com.huawei.mediacontroller\",\"description\":\"Can be disabled via Settings. Will disable the media controls in quick settings. Won't remove them however.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.meetime\",\"description\":\"MeeTime (https://consumer.huawei.com/en/support/content/en-us00956296/). Voice and video calling application by Huawei. Only workds with EMUI 9.1+ Huawei phones. Huawei claims they use E2EE but this wasn't verified and there is not Whitepaper so don't trust them. They also collect metadata. There is no advantages to use this app instead of the reputed open-source Signal app.\",\"removal\":\"delete\",\"dependencies\":[\"com.huawei.hwvoipservice\"],\"type\":\"oem\"},{\"id\":\"com.huawei.mirror\",\"description\":\"Huawei Mirror app.\\nMirror like \\\"Glass\\\"\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.mirrorlink\",\"description\":\"Huawei Mirror app. \\nMirror like \\\"Glass\\\"\\n\\nHuawei mirrorlink implementation\\nUsed to connect your phone to a car (with https://mirrorlink.com/ support) in order to provide audio streaming, GPS navigation...\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.mmiautotest\",\"description\":\"MMIAutoTest\\nHidden testing hardware things.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.mmitest\",\"description\":\"MMITest\\nHidden hardware tests. Safe to remove.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.motionservice\",\"description\":\"Gesture Service\\nNot very useful gestures available in settings.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.huawei.msdp\",\"description\":\"Multimodal Sensor Data Platform\\nHas Device Status, Movement, Spatial Aware.\\nUses location, airlink permissions.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.multimedia.audioengine\",\"description\":\"Audio Engine, probably not needed.\\nhttps://developer.huawei.com/consumer/en/audioengine\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.multimedia.hivideoplayengine\",\"description\":\"hivideoplayengine\\nHwVideoKitImpl, sdk tools for developers.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.music\",\"description\":\"Huawei Music app. Fat music player developed by Huawei (137MB. Seriously?).\\n\",\"removal\":\"replace\",\"suggestions\":\"music_apps\",\"type\":\"oem\"},{\"id\":\"com.huawei.mycenter\",\"label\":\"My Center\",\"description\":\"Huawei Member Center\\nGives reward offers and news to Huawei users. Very intrusive app: 68 permissions inclusing CAMERA, ACCESS_FINE_LOCATION, REQUEST_INSTALL_PACKAGES. Can run in the background and just after boot even if you haven't unlock your phone yet. Phones home.\",\"web\":[\"https://beta.pithus.org/report/3af49c621aefeef0dca86a4f79b5f007d73698fa979d3ba1ac7d6f1ccaea9cdf\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.nb.service\",\"description\":\"Service for discovering nearby devices by GPS\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.huawei.nearby\",\"description\":\"HwNearby\\nNeeded for Huawei Share features. (com.huawei.android.instantshare)\\nHuawei Share features may not work after remove.\\nNeeded to show a preview of recently opened apps in task manager. I agree, makes no sense, but that's what it is.\",\"dependencies\":[\"com.huawei.android.instantshare\"],\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.huawei.notepad\",\"description\":\"Notepad\\nLooks so bloated with Hi Voice, Update using AppGallery, Location.\\nIt has a few tracking components, but not too many.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.numberidentity\",\"description\":\"Designed to block unwanted calls, but only works properly in China\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.ohos.collaborationcenter\",\"description\":\"Sometimes ohos apps is configuration app before building.\\nIn code I found it's for app cast transfer.\\nDisable instead of uninstalling if you don't want to lose the widget.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.ohos.famanager\",\"description\":\"Service Center\\nProvides a space for you to view and manage services.\\nThis app and its underlying services (which provide searches and AI-based services). A lot tracking.\\nDisable instead of uninstalling if you don't want to lose the widget.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.ohos.hiwindow\",\"description\":\"HiWindow\\nHave loading, waiting png files\\ncollaboration devices, hardware things, screen projection on activities shows Window Shell.\\nAfter remove you will lose animations and loading screen.\\nDisable instead of uninstalling if you don't want to lose the widget.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.ohos.inputmethod\",\"label\":\"Celia Keyboard\",\"description\":\"Huawei default Keyboard.\",\"removal\":\"replace\",\"warning\":\"Make sure to have another keyboard app installed before uninstalling it\",\"suggestions\":\"keyboards\",\"type\":\"oem\"},{\"id\":\"com.huawei.ohos.security.privacycenter\",\"description\":\"It's shell to app 'com.huawei.security.privacycenter'?\\nDisable instead of uninstalling if you don't want to lose the widget.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.omacp\",\"description\":\"Provisioning message\\nUsed for provisioning APN settings to devices via SMS. I think you shouldnt touch it if you want sms messages.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.huawei.onehopsvcclient\",\"description\":\"OneHopSvcClient\\nTagService, HarmonyTag.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.onehopsvchost\",\"description\":\"OneHopSvcHost\\nTriggerservice opens hardware things by secret code.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.parentcontrol\",\"description\":\"Parental controls functions.\\nIt seems Huawei can prevent to remove packages. Uninstalling (or even disabling) this package returns an error: Failure [DELETE_FAILED_INTERNAL_ERROR] (not allowed to disable this package).\\n See https://github.com/0x192/universal-android-debloater/issues/51\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.pcassistant\",\"description\":\"HiSuite service. Used by HiSuite PC software.\\nHiSuite enables you to backup your data and restore them from/to your phone.\\nhttps://consumer.huawei.com/en/support/hisuite/\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.pengine\",\"description\":\"HUAWEI Intelligent Suggestion will collect and analyze screens from selected apps to provide personalized services.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.permissioncontroller\",\"description\":\"Can be disabled via Settings as well\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.permissioncontroller.overlay\",\"description\":\"Found help app permissions - only link to Google site in code, overlay to permission things like buttons, dialogs, etc.\\nBut it's not needed?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.huawei.phoneservice\",\"label\":\"HiCare\",\"description\":\"Provides you common online services including customer services, issue feedback, user guides, service centers and self-service.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.photos\",\"label\":\"Gallery\",\"description\":\"Huawei Gallery app.\\nNote: The official camera app refuses to open photos in another gallery (you can't review your picture from the camera app)\\n\",\"removal\":\"replace\",\"suggestions\":\"gallery\",\"type\":\"oem\"},{\"id\":\"com.huawei.powergenie\",\"label\":\"Power Genius\",\"description\":\"Task killer app in EMUI 9+ (Android 9+).\\nTask killer apps tend to do more harm than help as they clear cached RAM for no good reason, removing the battery and time savings involved in caching. In addition to the obvious issues with background functionality like notifications. However, system may start lagging a little bit (you will notice it while scrolling and on some animations, for example scrolling installed apps), battery consumption will become slightly higher and battery stats will disappear soon. At the same time, logcat will be full of errors like: PowerKit: PG Server is not found. calling pid xxxx.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.huawei.printservice\",\"label\":\"Default Print Service\",\"description\":\"Print service for HUAWEI.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.huawei.privatespace\",\"description\":\"Privacy Space for files\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.huawei.profile\",\"description\":\"Profile Services\\nIt's an app needed for HUAWEI ID, depends on HMSCore, also has analytics and trackers.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.rcsserviceapplication\",\"label\":\"Huawei RCS\",\"description\":\"RCS = Rich Communication Service.\\nProvides sending messages to another Huawei phone.\\nHidden RCS Chats with 49 permissions.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.recsys\",\"description\":\"HwIntelligentRecSystem\\nis a smart app that provides personalized services on HiBoard? My phone dont have Hiboard. Safe to remove.\\nhttps://consumer.huawei.com/en/support/content/en-us00434788/\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.regservice\",\"description\":\"RegService\\nRegister for celluar network services, not needed.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.remotepassword\",\"description\":\"RemotePassword\\nremotepassword: errors, invalid, null, errors generally\\nalso subscribe info, device info. Better remove that.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.ridemode\",\"description\":\"Uses google maps website to track your ride when RideMode is Enabled.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.runningtestii\",\"description\":\"Testing hardware things like Audio, Camera, VideoPlayer, etc.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.sarlevel\",\"description\":\"Mobile phone SAR\\nHidden SAR Level Activity.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.scanner\",\"description\":\"AI Lens. Shop for objects that you take a picture of. This de-clutters the camera interface by removing the AI Lens button on the top left corner and does not break the AR Measure app.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.scenepack\",\"description\":\"Travel Assistant provides you with travel tips, voice guides, and other related services.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.screenrecorder\",\"description\":\"Stock screen recorder\\nUseful only in pre-Android Pie for having system audio recording without root\\nNot sure if it's an app, but I can't find it on my phone. Safe to remove.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.huawei.search\",\"label\":\"HUAWEI HiSearch\",\"description\":\"Allows you to search through settings, files, contacts and notes while keeping a record of your search history.\\nHi Search is really annonying because it's triggered as soon as you wipe down from the middle part of the home.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.searchservice\",\"description\":\"Fusion Search Service\\nNeeded for searching? Found out that it uses `com.huawei.hwddmp` this app is for debugging errors\\nalso found trackers components that connects to Huawei servers unnecessarily.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.secime\",\"description\":\"Huawei Secure IME\\nSecure keyboard.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.security.privacycenter\",\"description\":\"Protect your privacy by preventing apps from accessing sensitive data stored within images,\\nsuch as location info and time stamps. This restriction does not apply to system apps such as Gallery and Cloud.\\nI don't think this app values privacy a lot.\\nNeeded for Permission Manager to open.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.huawei.securitymgr\",\"label\":\"PrivateSpace\",\"description\":\"Lets you store private information in a hidden space within your device that can only be accessed with your fingerprint or password.\\nThis is the password vault or manager too.\",\"web\":[\"https://consumer.huawei.com/en/support/content/en-us00754246/\"],\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.huawei.securitypluginbase\",\"description\":\"HwSecurityPluginBase\\nAntivirus Service supports bad antiviruses, HwLog, not needed\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.securityserver\",\"description\":\"HwSecurityServer\\nNot needed app without code and useless assets to spying apps.\\nNeeded for face unlock, black screen will be shown if you remove this package (?). Doesn't apply to all devices\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.huawei.skytone\",\"description\":\"SkyTone Data Service. Frameworks to 'com.huawei.hiskytone' SkyTone Overseas Data Service.\",\"dependencies\":[\"com.huawei.hiskytone\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.smarthome\",\"description\":\"AI Life\\nRequire Logging in to your Huawei ID, HMSCore.\\nIt's app that lets your control and manage routers and audio accessories.\",\"dependencies\":[\"com.huawei.hwid\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.smartlocation\",\"description\":\"Huawei Indoor Positioning Services\\nChinese Tracking Location.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.smartshot\",\"description\":\"Smart screenshots\\nNeeded for screenshots.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.huawei.sos\",\"description\":\"SOS\\nEmergency things.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.soundrecorder\",\"description\":\"Sound Recorder app.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.huawei.spaceservice\",\"description\":\"Huawei Geofence Services\\nUses Chinese Location.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.stylus.floatmenu\",\"description\":\"AI Lens. Shop for objects that you take a picture of. This de-clutters the camera interface by removing the AI Lens button on the top left corner and does not break the AR Measure app.\\n \\nFloating menu with M-Pen feature.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.suggestion\",\"description\":\"HiSuggestion\\nHw intelligence permissions found and logs, also maybe has suggestions on widget.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.synergy\",\"description\":\"Huawei Cloud & Network Synergy.\\nSeems to be related to B2B (Business To Business) cloud stuff.\\nhttps://www.huawei.com/en/press-events/news/2016/10/Cloud-Network-Synergy-Whitepaper\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.systemdebug\",\"description\":\"SystemDebug\\nTesting system things.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.systemmanager\",\"description\":\"System Manager\\nHuawei's stock phone cleaner. Consumes a lot of battery power for useless 'security' checks.\\nSafe to remove unless you need any anti-virus (while there are better ones to be found). NOTE: breaks the functionality of closing and cleaning background apps.\\nThis is more than a phone cleaner, you will lose a lot of settings like battery and notifications management if you remove this.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.huawei.systemserver\",\"description\":\"Huawei System Services\\nIt depends on (com.huawei.systemmanager).\\nNeeded for navigation with a fingerprint reader that is on Mate 10, but fingerprint unlock will still work if you remove it.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.huawei.tips\",\"description\":\"HUAWEI Feature Advisor\\nPeriodically gives you notifications on how to use certain features on your phone.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.tipsove\",\"description\":\"Tips\\nHuawei Tips to HiCar, AI Life and more.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.tmecustomize\",\"description\":\"TME\\nTme Activity. Hidden carrier config sim.\\nI think it's useless but you need to test.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.huawei.trustagent\",\"description\":\"Smart unlock feature.\\nEnables you to unlock your phone with a Bluetooth device, like a smart band. \\nWhen a compatible Bluetooth device is detected, you can unlock your phone with a simple swipe (without a password).\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.trustcircle\",\"description\":\"Device authentication service\\nThe app's usage is unknown, but it can be removed if apps such as com.huawei.hwid, com.huawei.appmarket are also removed. This is what I found while exploring the APK: Huawei Mobile Services?, managing installation and updates of AppGallery.\\nHuawei HWID account may be inaccessible without this app.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.trustedthingsauth\",\"description\":\"HwTrustedThingsAuth\\nOnly name app found in code, has permissions:\\nBluetooth, execute_reg, use_auth.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.trustspace\",\"description\":\"TrustSpace useless security to payment. Settings > Security > TrustSpace\\nHas something to unrooting rooted phone.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.userguide\",\"description\":\"User Guide\\nRequire install a PDF reader app to work.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.vassistant\",\"description\":\"HiVoice app\\nHuawei voice assistant (like Siri or Google assistant)\\nHuge privacy risk. Keep in mind that the app keeps the microphone *on* non-stop.\\nIs now Celia (https://consumer.huawei.com/en/emui/celia/)\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.vdrive\",\"description\":\"Driving Mode uses HiVoice to provide voice services when you are driving.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.videoeditor\",\"description\":\"Huawei Video editor\\nIncludes 2 ads trackers. Interacts with Huawei cloud. Pithus analysis: https://beta.pithus.org/report/19ef8cfb02f3853128603a140b4602db57ddf729a728b1ea6998e8b20752138f\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.vrservice\",\"description\":\"Huawei VR Service used for Huawei VR.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.wallet\",\"label\":\"HUAWEI Wallet\",\"description\":\"Formerly, Huawei Pay, is a mobile payment and e-wallet service for Huawei devices that offers the same services as Apple Pay, Samsung Pay etc.\",\"web\":[\"https://consumer.huawei.com/en/mobileservices/huawei-wallet/\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.wallet.sdk.walletsdk\",\"label\":\"WalletSDK\",\"description\":\"SDK for HUAWEI Wallet\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.watch.sync\",\"description\":\"Huawei Watch sync function\\nIs it only used to sync Huawei watch ?\\nSafe to remove according to several users\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.waudio\",\"description\":\"waudio\\nWi-Fi Speaker, Speaker playback, WLAN speaker\\nThis app is only for Chinese users because I found a Chinese app list that supports it\\nand depends on AI Life app probably.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.webview\",\"label\":\"Huawei WebView\",\"description\":\"Allows Android apps to display web contents within the app itself, based on Chrome.\",\"removal\":\"caution\",\"warning\":\"Make sure to have another Webview before uninstalling it or some apps may not work properly and crash.\",\"suggestions\":\"webviews\",\"type\":\"oem\"},{\"id\":\"com.huawei.welinknow\",\"description\":\"Link Now\\nRequire login to Huawei ID Account.\\nSome features is not available for some countries.\\nIt's app for meeting and collects a lot data from users.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.huawei.wifieapsimplmn\",\"description\":\"PredefinedEapSim\\nNeeded for WiFi to work properly? WiFi may not work (?)\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.huawei.wifiprobqeservice\",\"label\":\"HwWifiproBqeService\",\"description\":\"Needed for WiFi to work properly? WiFi may not work (?)\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.hxy.ramtest\",\"description\":\"ram test\\nHidden ram test. Tests ram size.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.hy.system.fontserver\",\"description\":\"Font Server\\nNeeded for fonts?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.ibimuyu.lockscreen\",\"description\":\"Dynamic theme service lockscree\\nDynamic theme service lockscreen? Some people recommend removing that.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.idea.questionnaire\",\"description\":\"Qusetionnaire\\nLogs and testing things.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.iflytek.inputmethod.miui\",\"description\":\"Chinese Keyboard to Miui China, replace Keyboard before remove.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.iflytek.speechsuite\",\"description\":\"Default voice input method from iflytek, a big chinese company (https://en.wikipedia.org/wiki/IFlytek)\\nIFLytek was implicated in human rights violations : \\nhttps://asia.nikkei.com/Economy/Trade-war/US-sanctions-8-China-tech-companies-over-role-in-Xinjiang-abuses\\nArchive: https://web.archive.org/save/https://asia.nikkei.com/Economy/Trade-war/US-sanctions-8-China-tech-companies-over-role-in-Xinjiang-abuses\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.ims.dm\",\"description\":\"IMS DM\\nHidden network debugging\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.infinix\",\"description\":\"Only has something to launcher folders and has freeze png files.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.infinix.xshare\",\"description\":\"XShare\\nIts app for Transfer & Share files, also has ads.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.iqoo.aftersale.engineermode\",\"description\":\"Testing things. This app is for testing phone components.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.iqoo.engineermode\",\"description\":\"Factory test\\nTesting things, AT Commands - no one uses them.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.iqoo.powersaving\",\"description\":\"Battery\\nPower-saving app. May not be a good idea to remove it.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.iqoo.secure\",\"description\":\"i Manager\\nRemoving this removes the traffic speed indicator in the notification bar. Be cautious about removing it.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.iqoo.user.engineermode\",\"description\":\"Factory test\\nIt's for testing phone components.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.iqoo.website\",\"description\":\"iQOO.com\\nShows iQOO website.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.itc.autotest\",\"description\":\"ITC_Base\\nHidden camera testing, also its Chinese.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.itel.TWSService\",\"description\":\"This app is used for connection to TECNO Hipods.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.jrdcom.Elabel\",\"label\":\"Regulatory & safety\",\"description\":\"Useless data collection and security. Also Chinese things, PDF View.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.jrdcom.Elabel.a_overlay\",\"description\":\"Useless overlay code for this bloatware app\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.jrdcom.Elabel.overlay\",\"description\":\"\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.jrdcom.filemanager\",\"label\":\"File Manager\",\"description\":\"A file manager with ads\",\"web\":[\"https://play.google.com/store/apps/details?id=com.jrdcom.filemanager\"],\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.jrdcom.filemanager.a_overlay\",\"description\":\"\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.jrdcom.urlreservedapp1\",\"description\":\"TCL My Sites shortcut\\nStub for mysites.glance.com.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.kidoz.lenovo\",\"label\":\"Lenovo Kid's Account\",\"description\":\"Partnered with COPPA Certified (https://cert.privo.com/#/companies/kidoz18) KIDOZ Inc.\\nProvides kids friendly relevant services based on their 'usage behaviour'.\\nAccording to EFF sends device model, brand, country, timezone, screen size, view events, click events, logtime of events, and a unique “KID ID information to Kidoz.\",\"web\":[\"https://beta.pithus.org/report/af6c3674c3bdcacda3590eb657fef61c1b3b44100c7c6ae051309d5196104efa\",\"https://www.virustotal.com/gui/file/af6c3674c3bdcacda3590eb657fef61c1b3b44100c7c6ae051309d5196104efa/detection\",\"https://www.eff.org/deeplinks/2023/11/low-budget-should-not-mean-high-risk-kids-tablet-came-preloaded-sketchyware\",\"https://www.privo.com/kidoz-case-study\",\"https://kidoz.net/privacy-policies\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.kidsedu\",\"description\":\"Another Kids Mode.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.kikaoem.hw.qisiemoji.inputmethod\",\"description\":\"Kika Keyboard\\nThird party keyboard. Installs on some Huawei devices.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.knox.vpn.proxyhandler\",\"label\":\"KnoxVpnPacProcessor\",\"description\":\"Samsung Knox allows business and personal content to \\\"securely\\\" coexist on the same handset.\\nThis package handles proxies alongside KNOX.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.kyocera.ecomode\",\"description\":\"Custom power-saving mode\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.lbe.security.miui\",\"description\":\"Permission manager\\nLets you monitor apps permission requests.\\n\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.lbe.security.miui.customizedregion.overlay\",\"description\":\"Something about WiFi calling \\\"vowifi\\\", \\\"volte\\\", \\\"notification on keyguard\\\"\\nIt's unused.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.ldmnq.launcher3\",\"description\":\"Built in launcher\\nFull of ads but not safe to disable unless you have another launcher\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.lenovo.agent0\",\"label\":\"OCZ_ProvisionAgent\",\"description\":\"Not sure what it does.\",\"web\":[\"https://beta.pithus.org/report/9ebdba931604f90815b8014cbba12b91521811ac49a292dab438006\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.lenovo.csdkplatform\",\"label\":\"PlatformApk\",\"description\":\"CSDK = Commercial Software Development Kit (CSDK) for details see official video.\",\"web\":[\"https://videos.emea.lenovo.com/lenovo-commercial-software\",\"https://beta.pithus.org/report/130d7076019d7a4519a04c80dbd80fa3734542dc44ec1f5fba464569fb3f4adc\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.lenovo.dagent\",\"label\":\"OCZ_DeployAgent\",\"description\":\"Not sure what it does.\",\"web\":[\"https://beta.pithus.org/report/d5bd860fb7c42078618118213913ea6d58fec2a51904728f2f429840386d0c70\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.lenovo.dsa\",\"label\":\"OCZ_DeployServiceApp\",\"description\":\"Dynamic System Analysis (DSA) collects and analyzes system information to aid in diagnosing system problems.\",\"web\":[\"https://support.lenovo.com/us/en/solutions/LNVO-DSA\",\"https://beta.pithus.org/report/2e4a0b3fa9ea4fb56a7bd90d1d2c9eb4cd7fffe481943e0f6bfb8a23554cb921\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.lenovo.launcher\",\"label\":\"LenovoLauncher\",\"description\":\"Lenovo's default device launcher.\",\"web\":[\"https://beta.pithus.org/report/3cdd48fb6a9c94435fb1b46b41a19c553b96ae889aaa2d7285f28cd64d12363e\"],\"removal\":\"replace\",\"warning\":\"Make sure have installed another launcher before debloating this app\",\"suggestions\":\"launchers\",\"type\":\"oem\"},{\"id\":\"com.lenovo.launcher.provider\",\"label\":\"LenovoLauncherProvider\",\"description\":\"Related to lenovo launcher(com.lenovo.launcher)?\\nExactly not sure what it does.\",\"web\":[\"https://beta.pithus.org/report/c94afd8d85adb4c139ca6e78cd0fe643ebe0d0046480f2b12235e698eeccaa51\"],\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.lenovo.leos.appstore\",\"description\":\"Lenovo Application Center 应用中心\\nLenovo chinese app store\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.lenovo.leos.cloud.sync\",\"description\":\"SYNCit\\nLenovo cloud\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.lenovo.levoice.caption\",\"description\":\"AI Live Caption\\nCaption Settings.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.lenovo.levoice.trigger\",\"description\":\"Wake up with voice\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.lenovo.levoice_agent\",\"description\":\"Voice unlock screen\\nVoice unlock screen? Another chinese accessibility things.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.lenovo.levoice_notes\",\"description\":\"AI Notes\\nAnother AI things lenovo.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.lenovo.lsf\",\"label\":\"Lenovo ID\",\"description\":\"Lenovo ID adds an option in Settings>Accounts where you can login to a Lenovo ID account.\\nFeatures include \\\"exclusive features directly from Lenovo and our partners\\\" and \\\"syncing users information across devices\\\"\\nlsf = Lenovo Service Framework\",\"web\":[\"https://beta.pithus.org/report/f181581838c8898634160e5cceada5fd3e4032b6ad9eae39ff788e8cc2922db7\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.lenovo.lsf.device\",\"label\":\"Device Service\",\"description\":\"lsf = Lenovo Service Framework.\\nExactly not sure what it does.\",\"web\":[\"https://beta.pithus.org/report/1cbd510ef561561b3d850583e9467f16b9ae2d94280c9b2a50bcb8cfbad6ccf9\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.lenovo.lsf.user\",\"description\":\"Lenovo ID adds an option in Settings>Accounts where you can login to a Lenovo ID account.\\nFeatures include \\\"exclusive features directly from Lenovo and our partners\\\" and \\\"syncing users information across devices\\\"\\nlsf = Lenovo Service Framework.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.lenovo.ocpl\",\"label\":\"OCZ_ClientDownloader\",\"description\":\"Not sure what it does.\",\"web\":[\"https://forums.lenovo.com/t5/Lenovo-Android-based-Tablets-and-Phablets/OCZ-ClientDownloader/m-p/5090852?page=1#5396079\",\"https://beta.pithus.org/report/8a1884d7604d3c3ab7559d6dcffe88b77243e85bee38ff100f1331043b6d5e6f\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.lenovo.ota\",\"label\":\"System Update\",\"description\":\"App for your Over-The-Air (OTA) system update.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.lenovo.tab4_8plus\",\"label\":\"Lenovo TAB4 8 Plus\",\"description\":\"App that shows TAB4 8 Plus device specifications.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.lenovo.ue.device\",\"label\":\"UserExperience\",\"description\":\"User Experience Program\\nAnalytics stuff. Displays an annoying notification after every reboot prompting you to join this user experience program.\",\"web\":[\"https://beta.pithus.org/report/54cc80e774c0106e2b74b7b8d50981ad2108dad2f8d4b2c6a5115e14256807f6\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.lenovo.wallpaper\",\"label\":\"Wallpapers\",\"description\":\"Wallpaper manager app for lenovo devices.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.lenovo.weather.theme.dreamlandPad\",\"label\":\"Lenovo Weather\",\"description\":\"Adds widget for lenovo weather app(com.tblenovo.lewea)\",\"web\":[\"https://beta.pithus.org/report/aff85db4566c53f4b0668f603aa99dfcae13dd165835cca4d6d0b59265145f18\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.lenovo.weathercenter\",\"description\":\"Widget Weather\\nLenovo ZUI Weather center\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.lge.LGSetupView\",\"description\":\"Setup View\\nLG first setup (related to com.android.LGSetupWizard). \\nThe first time you turn your device on, a Welcome screen is displayed. It guides you through the basics of setting up your device.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.lge.NfcSettings\",\"description\":\"NFC settings\\nLikely in the settings.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.lge.android.atservice\",\"description\":\"Software Update\\nIt's probably the only component of software updates.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.lge.animal.resource\",\"description\":\"AnimalResource\\nAnother thing for avatars.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.lge.app.floating.res\",\"description\":\"Multitasking framework\\nAllows you to use multitasking features like multiple apps in one screen.\\nDoes not remove screen pinning feature.\\nI don't know if this removes the floating windows feature that you have to enable with ADB (to make it look more like a desktop)\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.lge.appbox.client\",\"description\":\"LG Application manager\\nInstalls/Updates LG related apps?\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.lge.appwidget.runningtaskbar\",\"description\":\"Recent Task App Widget.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.lge.arcamera\",\"description\":\"ARCamera\\nThis application requires google play services for ar. Not sure what for it is but probably for VR.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.lge.auto_generated_rro_product__\",\"description\":\"It has important configs. Better don't risk.\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.lge.bluetoothsetting\",\"description\":\"Needed for Bluetooth.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.lge.bnr\",\"description\":\"LG Backup\\nCan backup your mobile devices LG Home screen, device settings, apps, and contacts to your computer.\\nhttps://www.lg.com/us/support/help-library/lg-android-backup-CT10000025-20150104708841\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.lge.bnr.launcher\",\"description\":\"LG Mobile Switch Launcher\\nThis doesn't remove the default launchers.\\nIt is most likely to backup/restore the user's launcher configuration.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.lge.calligraphydictionary\",\"description\":\"Calligraphy dictionary\\nLooks useless.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.lge.camera\",\"description\":\"Camera\\nStock camera app.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.lge.camerasolution\",\"description\":\"Needed for Stock camera app.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.lge.cic.eden.service\",\"description\":\"Memories album\\nGallery automatically creates a Memories album with pictures and videos saved in the phone. \\nMemories is a virtual album of pictures saved in the phone or SD card.\\nSource : https://www.lg.com/hk_en/support/product-help/CT30019000-1433767985158-others\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.lge.cinemagraph\",\"description\":\"Cine shot\\nI think it's an optional app.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.lge.clock\",\"description\":\"LG Clock app\\n\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.lge.cmas\",\"description\":\"Emergency Alerts\\nit's only for alerts so it's safe to remove.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.lge.covertools\",\"description\":\"Dual Screen Tool\\nNeeded for dual-screen I guess.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.lge.displayfingerprint\",\"description\":\"It's fingerprint testing. Secret code 346437.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.lge.drmservice\",\"description\":\"DRM Service\\nProbably required for some forms of DRM; disabling might break things like Netflix streaming, which relies on DRM to function.\\nhttps://en.wikipedia.org/wiki/Digital_rights_management\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.lge.dsmanager\",\"description\":\"Dual Screen Updater\\nIf you dont use dual screen feature then it's safe to remove?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.lge.dualscreenfirmware\",\"description\":\"Shows error dialog for dual-screen firmware update.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.lge.easyhome\",\"description\":\"LG EasyHome\\nEasyHome is a more simplified version of the Home screen that you can choose to use on your phone.\\nIt displays the Home screen like a remote control device. T\\nSource : https://www.lg.com/us/mobile-phones/VS985/Userguide/048.html\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.lge.effect\",\"description\":\"It's for lock screen effect.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.lge.ellievision\",\"description\":\"Smart Cam & AI Tips\\nDelete if not using default camera.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.lge.eltest\",\"description\":\"ELTest\\nDevice hardware tests settings\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.lge.email\",\"description\":\"LG Email app\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.lge.entitlementcheckservice\",\"description\":\"It's for miracast and wifi hotspot probably.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.lge.equalizer\",\"description\":\"Equalizer settings.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.lge.eula\",\"label\":\"Terms of Use for LG apps\",\"description\":\"LG EULA (Terms of Use) accessible in the settings.\\nEULA = End User License Agreement.\\nNeeded by LG HD Audio Recorder or it will force close (maybe used by some other stock app?)\",\"web\":[\"https://en.wikipedia.org/wiki/End-user_license_agreement\"],\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.lge.eula.downloader\",\"label\":\"Privacy Policy Update\",\"description\":\"Not tested but probably safe to remove.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.lge.eulaprovider\",\"label\":\"License Provider\",\"description\":\"Needed by com.lge.eula.\\nNeeded by LG HD Audio Recorder or it will force close (maybe used by some other stock app?)\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.lge.exchange\",\"description\":\"It looks like the Microsoft outlook/email in the logo. Believe this is some sort of microsoft integration.\\nI don't 100% remember if I was able to add accounts to the phone still (eg. Nextcloud), I need to test that soon.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.lge.faceglance.trustagent\",\"description\":\"Face Recognition\\nRemove if you don't need it. If you want security I don't think this is a good idea to use it.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.lge.filemanager\",\"description\":\"Stock file manager\\n\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.lge.floatingbar\",\"description\":\"LG Floating bar\\nLets you put shortcuts to apps or features, as well as quick access to contacts and music player controls on a \\\"floating bar\\\" on the Home screen.\\nhttps://www.neowin.net/news/lg-v30-closer-look-floating-bar/\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.lge.fmradio\",\"description\":\"FM radio app\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.lge.friendsmanager\",\"description\":\"LG Friends Manager (https://play.google.com/store/apps/details?id=com.lge.friendsmanager)\\nWTF ? Completely useless app.\\nNot sure but I think it enables you to download an app for a friend LG user.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.lge.gallery.aodimagewidget\",\"description\":\"Always-on display image\\nLG Always-on display image\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.lge.gallery.collagewallpaper\",\"description\":\"LG Collage Wallpapers\\nAllows you to create patchwork wallpaper from several photos.\\nhttps://www.lg.com/uk/support/product-help/CT00008356-20150332136499-others\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.lge.gallery.studio\",\"description\":\"GalleryStudio\\nIt's needed for gallery app probably.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.lge.gallery.vr.wallpaper\",\"description\":\"LG 360 Image Wallpaper\\nProvides VR (360°) wallpapers.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.lge.gamepad\",\"description\":\"LG Game Pad\\nIt's probably for TV. Not useful for games.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.lge.gametools\",\"description\":\"GameTools\\nNot tested it's for probably useful for games.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.lge.gametools.gamerecorder\",\"description\":\"Screen recording\\nScreen recording for game tools.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.lge.gametuner\",\"description\":\"Settings/features for games, such as resolution and frame rate limiting.\\nA little side note, any games installed in the work profile can't use gametuner (maybe if you install this package into the work profile it'll work)\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.lge.gcuv\",\"description\":\"GCUV\\nNot 100% sure but @siraltus from XDA thinks it refers to \\\"Gauce Components\\\" which seems to be the LG's version of CSC \\n(carrier sales code - automatic carrier-specific customization).\\nIt gets run on first boot after factory reset, sets up the ROM features based on which carrier and country code is specified \\nin the build.prop, and then gets frozen so it doesn't reconfigure things on subsequent boots.\\nIt's basically the only person to mention \\\"Gauce components\\\" on the web (other than restricted LG webpages when using Google dorks).\\nhttps://forum.xda-developers.com/tmobile-lg-v10/development/rom-lg-v10-h901-10c-debranded-debloated-t3277305/page12/page12\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.lge.gdec.client\",\"description\":\"Another component of OTA Updates but here I found it's for App Updates.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.lge.gestureanswering\",\"description\":\"Answer me 2.0\\nAllows you to bring the phone to your ear to answer an incoming call automatically.\\nhttps://www.lg.com/us/mobile-phones/VS980/Userguide/109-1.html\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.lge.gnss.airtest\",\"description\":\"GNSS Air Test\\nGNSS test, used to test... GNSS. Not needed, and GPNSS will continue to work.\\nNOTE : GNSS = Global Navigation Satellite System and is the standard generic term for satellite navigation systems.\\nThis term includes e.g. the GPS, GLONASS, Galileo, Beidou and other regional systems.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.lge.gnsslogcat\",\"description\":\"GNSS Logcat\\nUsed to dump GNSS logs.  \\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.lge.gnsslogsetting\",\"description\":\"GNSS LOG LEVEL SETTING. It's for debug.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.lge.gnsspostest\",\"description\":\"GNSS Position test\\nGNSS test again.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.lge.gnsstest\",\"description\":\"GNSS Test\\nWoh ! Why does LG need so many GNSS test packages?! \\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.lge.hifirecorder\",\"description\":\"LG Audio Recorder\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.lge.homeselector\",\"description\":\"LG Home selector\\nThis is the settings menu for the home launcher (present in the settings app as \\\"Home launcher\\\")\\nIf you remove this app, the Home screen settings menu is gone from settings app. (not needed if you use external launcher)\\n    You can still switch between installed launchers, the package name is a bit misleading.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.lge.hotspotlauncher\",\"description\":\"LG Mobile Hotspot\\nProvides hotspot feature enabling you to share the phone’s 4G data connection with any Wi-Fi capable devices.\\n\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.lge.hotspotprovision\",\"description\":\"Needed for hotspot 3G?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.lge.ia.task.incalagent\",\"description\":\"InCalAgent\\nRelated to interface while you're in a call. Seems also related to tasks list stuff.\\nCan someone tell me what happens when you delete it ? I think it is safe.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.lge.ia.task.informant\",\"description\":\"I only found that it's for feed favorite contacts and this app uses Korean language. Hidden, useless.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.lge.ia.task.smartcare\",\"description\":\"LIA SmartDoctor Engine\\nNeeded by SmartDoctor (com.lge.phonemanagement) ?\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.lge.ia.task.smartsetting\",\"description\":\"SmartSetting\\nTurns on/off or changes features, settings and more according to where you are or what you do.\\nhttps://www.lg.com/us/support/help-library/lg-android-smart-settings-CT10000025-20150103623722\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.lge.icecontacts\",\"description\":\"Emergency and video calling things.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.lge.iftttmanager\",\"description\":\"LG Smart settings\\nIFTTT = “if this, then that.”. Smart Settings can be seens as IFTTT.\\nSome events automatically triggers actions.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.lge.ime\",\"description\":\"LG Stock Keyboard\\nDo not remove if you don't have an alternate keyboard available. Personally, I keep the stock keyboard just in case the keyboard app crash/fails (this happened to me once) locking me out of entering password.\\n\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.lge.ime.solution.handwriting\",\"description\":\"Handwriting feature on the LG keyboard\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.lge.ime.solution.text\",\"description\":\"XT9 \\nText predicting and correction for the LG keyboard.\\nFor your culture (if you're young) : https://en.wikipedia.org/wiki/XT9\\n\",\"removal\":\"replace\",\"warning\":\"On LG G6 (and maybe on other LG phones) removing this may cause the LG keyboard to stop inputing characters. Make sure to use another keyboard before removing this package.\",\"type\":\"oem\"},{\"id\":\"com.lge.ims\",\"description\":\"LG IMS\\nIt's not a good app because it has a lot of debugging stuff.\\nBreaks calls.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.lge.ims.chatbotinfoprovider\",\"description\":\"It's a component of (com.lge.ims), not very useful because it's for debugging app.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.lge.ims.rcsprovider\",\"description\":\"Needed for IMS, RCS but com.lge.ims = debugging app.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.lge.imsvt\",\"description\":\"Video Call, another component of com.lge.ims = debugging app.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.lge.launcher2\",\"description\":\"LG Home (v2)\\nStock launcher\\nIt's basically the home screen, the way icons apps are organized and displayed.\\nDON'T REMOVE THIS IF YOU DIDN'T INSTALL ANOTHER LAUNCHER!\\nNOTE : Yeah there is another package described as \\\"launcher\\\". Normally, you only have one of them on your phone. \\n\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.lge.launcher2.theme.optimus\",\"description\":\"\\\"Optimus\\\" theme for the LG launcher (v2)\\n\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.lge.launcher3\",\"description\":\"LG Home (v3)\\nStock launcher\\nIt's basically the home screen, the way icons apps are organized and displayed.\\nDON'T REMOVE THIS IF YOU DIDN'T INSTALL ANOTHER LAUNCHER!\\nNOTE : Yeah there is 3 packages described as \\\"launcher\\\". Normally, you only have one of them on your phone. \\n\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.lge.leccp\",\"label\":\"LG Connectivity Service\",\"description\":\"It has only Alert Dialogs.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.lge.lgaccount\",\"description\":\"LG Account\\nEnables you to create and manage your completely useless LG account.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.lge.lgbroadcastradioservice\",\"description\":\"Broadcast radio? No one needs that.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.lge.lgcontentsetting\",\"description\":\"Wallpaper & theme\\nNeeded for theme settings.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.lge.lgdataphone\",\"description\":\"It's for test and debug Data connection.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.lge.lgdmsclient\",\"description\":\"Actual \\\"Software Update\\\" App client\\nI think you won't receive updates without this.\\n\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.lge.lgdrm.permission\",\"description\":\"Handle permissions for LG DRM (com.lge.drmservice).\\nWhy does LG need a whole package for this?\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.lge.lgfmservice\",\"description\":\"Wifi Hotspot service\\nREMINDER : Hotspot enable you to share the phone’s 4G data connection with any Wi-Fi capable devices.\\nIt is not the Hotspot feature. Only the widget ! \\n\\nDual SIM status widget\\nProbably only present in dual sim LG phone variants. Does not remove the persistent notification or dual SIM functionality.\\n\\nService menus. I believe if you remove the last one the secret code you can dial doesn't work anymore (who needs it anyway..?)\\n\\nLG support App remote access\\nYou probably don't want that to happen\\n\\nLAOP test [MORE INFO NEEDED]\\nI don't know what LAOP is. I could not find information about it. It's a test so it's probably fine. I have removed it.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.lge.lgfota.permission\",\"description\":\"FOTA Test.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.lge.lginstallservies\",\"description\":\"LG Install Service\\nUsed by LG to install some of its apps on the phone. Not needed unless you use the LG apps manager.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.lge.lgmapui\",\"description\":\"LGMapUI\\nUser Interface (UI) for displaying location tracking reccord on the Health app (com.lge.lifetracker) ? \\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.lge.lgworld\",\"description\":\"LG SmartWorld\\nLG Store. Enables you to install LG apps, theme, keyboard layout, fonts...\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.lge.lifetracker\",\"description\":\"LG Health (https://play.google.com/store/apps/details?id=com.lge.lifetracker)\\nAccording to users reviews, it is a very bad activity tracking app. \\nPrivacy wise, you should never use this kind of thing obviously. \\nhttps://www.lg.com/us/support/help-library/lg-android-lg-health-CT30013120-20150103629401\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.lge.livemessage\",\"description\":\"Draw chat\\nNot needed for chats.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.lge.lms2\",\"description\":\"Needed for LG account.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.lge.lockscreensettings\",\"description\":\"LockScreenSettings\\nLock Screen Settings.\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.lge.mirrorlink\",\"description\":\"MirrorLink\\nEnables you to connect your phone to a car to provide audio streaming, GPS navigation...\\nhttps://www.lg.com/ca_en/support/product-help/CT30014940-1440413573040-others\\nhttps://mirrorlink.com/\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.lge.mlt\",\"description\":\"LG MLT\\nRun in background all the time and probably serves purpose to help LG remote support. The thing is this acts as a good spyware. \\nIt tries to track all your activity and logs GPS position together with the details gathered, and that includes calls, apps starting etc...\\nAll data is collected and placed on /mpt partition, it seems not to be per reboot, but actually kept during flash and upgrades.\\n#\\nhttps://forum.xda-developers.com/showthread.php?t=2187920\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.lge.mtalk.sf\",\"description\":\"Voice Mate Speech Pack\\nVoice Mate (now Q Vocie) is the LG Personal assistant (https://en.wikipedia.org/wiki/Voice_Mate)\\nThis package provides speech pack. Is it the main Q-voice package ? I don't think so but I need confirmation.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.lge.music\",\"description\":\"Stock music player\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.lge.musiccontroller\",\"description\":\"Music controller widget also Test activity.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.lge.musicpicker\",\"description\":\"Audio\\nIt has Drm Popup, Music Picker, Audio Preview.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.lge.musicshare\",\"description\":\"LG Audio Share \\nEnables you to connect two devices so that you can share the sound from music or video files with another LG devices.\\nhttps://www.lg.com/hk_en/support/product-help/CT30007700-20150123957406-others\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.lge.myplace\",\"description\":\"My Place\\nAnalyses the place you stay the most and recognises it as My Place (or your home) automatically.\\nhttps://www.lg.com/uk/support/product-help/CT00008356-1433767701724-setting\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.lge.myplace.engine\",\"description\":\"My Places Engine\\nNeeded by com.lge.myplace. See above.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.lge.networksettings\",\"description\":\"Sim network settings\\nIt can be found in settings.\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.lge.nextcapture\",\"description\":\"Needed for screenshots?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.lge.onehandcontroller\",\"description\":\"Needed for One-Handed Controller, Miniview.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.lge.operator.hiddenmenu\",\"description\":\"Operator HiddenMenu\\nHidden tests.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.lge.penprime\",\"description\":\"Pen settings\\nNo one using them.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.lge.phonemanagement\",\"description\":\"Smart Doctor App\\nEnables you to shut down idle apps and delete temporary files.\\nLets you also see phone battery, mobile data, apps, network status and usage patterns.\\nOn the paper it seems good but in practise, Android handle 8+ handles very well idles apps. \\nhttps://www.lg.com/ca_en/support/product-help/CT20098088-20150129256824-others\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.lge.pickme\",\"description\":\"PickMe\\nNeeded for camera app or face unlock?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.lge.privacylock\",\"description\":\"LG Content lock\\nYou can lock the LG Gallery with a password or pattern. When connected to a PC, Content Lock prevents file previews.\\nhttps://www.lg.com/us/support/help-library/lg-g4-content-lock-CT10000027-1432774759427\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.lge.provider.lockscreensettings\",\"description\":\"Needed for lock screen.\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.lge.provider.signboard\",\"description\":\"Needed for Always on display.\\nNOTE: May crash Settings app after removal.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.lge.provider.systemui\",\"description\":\"Not sure if iths important app.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.lge.qhelp\",\"description\":\"Quick Help\\nApp which provides you with support articles (FAQ section that walks you through most of the major features of the phone).\\nYou can request support via email or request a call from LG.\\nhttps://www.lg.com/us/support/help-library/lg-android-quick-help-CT10000026-20150103624836\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.lge.qhelp.application\",\"description\":\"Quick Help application\\nI think this package is the real Quick Help app. The package above only provides help contents IMO.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.lge.qmemoplus\",\"description\":\"LG QuickMemo+\\nAllows you to capture screen shots and use them to create memos. You can also insert a reminder, location information, image, video, and audio.\\nhttps://www.lg.com/us/support/help-library/lg-android-quickmemo-CT10000025-20150103629575\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.lge.quicktools\",\"description\":\"Quick Tools\\nQuick Tools widget configure.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.lge.rcs.sharedsketch\",\"description\":\"I have no idea what it is, maybe some drawing program related to rcs. I removed it.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.lge.remote.lgairdrive\",\"description\":\"LG AirDrive\\nLets you to control files in your device via a wireless connection. \\nTo use it, you need to sign in to your LG account on both the PC and mobile device.\\nhttps://www.lg.com/africa/support/product-help/CT20080025-1436354408798-others\\n \\nLG AirDrive settings\\nSee package below.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.lge.remote.setting\",\"description\":\"LG AirDrive\\nLets you to control files in your device via a wireless connection. \\nTo use it, you need to sign in to your LG account on both the PC and mobile device.\\nhttps://www.lg.com/africa/support/product-help/CT20080025-1436354408798-others\\n \\nLG AirDrive settings\\nSee package above.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.lge.screenplus.touchpad\",\"description\":\"Screen+\\nDesktop Touchpad.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.lge.screenplus.uiservice\",\"description\":\"Screen+\\nI don't know what Screen+ probably connects to PC screen.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.lge.sdencryption\",\"description\":\"Encryption devices like SD card.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.lge.seamlesswallpaper.circular.reactive.darkspace\",\"description\":\"Live wallpapers resources.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.lge.seamlesswallpaper.circular.reactive.space\",\"description\":\"Live wallpapers resources.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.lge.secondlauncher\",\"description\":\"It's needed for wallpaper choose and multi-app.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.lge.servicemenu\",\"description\":\"Hidden testing hardware things.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.lge.signboard\",\"description\":\"Always On Display.\\nProbably a battery killer without an OLED screen.\\nDisabling will remove the connected menu in the settings app.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.lge.sizechangable.weather\",\"label\":\"LG Weather\",\"description\":\"Not sure if it only manages Music widget for the launcher or also for the lockscreen.\\nWeather widget for the home screen.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.lge.sizechangable.weather.platform\",\"label\":\"LG Weather Service\",\"description\":\"Provide weather data for the weather app/widget.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.lge.sizechangable.weather.theme.optimus\",\"description\":\"\\\"Optimus\\\" theme for the weather app/widget.\\n\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.lge.smartdoctor.webview\",\"label\":\"SmartDoctorWebview\",\"description\":\"A WebView is acomponent that allows Android apps to display content from the web directly inside an application.\",\"removal\":\"caution\",\"warning\":\"Make sure to have another Webview before uninstalling it or some apps may not work properly and crash.\",\"suggestions\":\"webviews\",\"type\":\"oem\"},{\"id\":\"com.lge.smartenabler\",\"description\":\"It's for OTA Updates.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.lge.smartshare\",\"description\":\"SmartShare \\nFeature that uses DLNA technology to stream multimedia contents between DLNA devices.\\nDLNA is a non-profit trade organisation which defines standards that enable devices to share stuff with each other.\\nBasically LG provides a way to stream multimedia contents from your phone to your smart TV (or via a DLNA plugin)\\nhttps://www.lg.com/ca_en/support/product-help/CT31903570-1428542236040-file-media-transfer-pictures-music-etc\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.lge.smartshare.provider\",\"description\":\"Provider for Smart Share. \\nNeeded by com.lge.smartshare.\\nREMINDER : content providers help an application manage access to data stored by itself, stored by other apps, \\nand provide a way to share data with other apps. They encapsulate the data, and provide mechanisms for defining data security\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.lge.smartsharepush\",\"description\":\"Smart Share Push\\nObviously related to Smart Share but I don't know its exact purpose. \\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.lge.snappage\",\"description\":\"Snap Page\\nPart of the QuickMemo+ app, lets you capture the text/images/URL from a web page without grabbing ads.\\nIt’s much like instapaper or pocket app, but it works locally, like reading mode on some browsers, saving only the body of the article. \\nhttp://www.lg.com/us/mobile-phones/g4/display\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.lge.springcleaning\",\"description\":\"Smart cleaning\\nDisplays the space in use and free space in your phone and allows you to selectively clean up your files.\\nhttps://www.lg.com/us/mobile-phones/VS986/Userguide/339.html\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.lge.sui.widget\",\"description\":\"Removing this package causes the clock app to crash when trying to set an alarm for a specific date instead of a day of the week.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.lge.sync\",\"label\":\"LG Bridge Service\",\"description\":\"Used to backup, restore, update your LG phone, and transfer files wirelessly between computer and LG phone.\\nYou will need to install LG Bridge software on your PC.\\nNOTE: causes noticeable battery drain.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.lge.systemservice\",\"description\":\"System Server\\nNot sure if iths important app.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.lge.task\",\"label\":\"LG Tasks\",\"description\":\"Task storage for LG Calendar.\",\"removal\":\"replace\",\"warning\":\"Removing the package will cause LG Calendar to stop working.\",\"type\":\"oem\"},{\"id\":\"com.lge.theme.black\",\"description\":\"LG Black theme.\\nSafe to remove, but also probably pointless to do so as most theme packages are just data containers.\\nMake sure you don't delete the package for the theme you're currently using, I don't know what will happen then.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.lge.theme.highcontrast\",\"description\":\"LG High Contrast theme.\\nSafe to remove, but also probably pointless to do so as most theme packages are just data containers.\\nMake sure you don't delete the package for the theme you're currently using, I don't know what will happen then.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.lge.theme.titan\",\"description\":\"LG Titan theme (labelled 'Platinum' in the theming app).\\nSafe to remove, but also probably pointless to do so as most theme packages are just data containers.\\nMake sure you don't delete the package for the theme you're currently using. I don't know what will happen then.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.lge.theme.white\",\"description\":\"LG White theme.\\nSafe to remove, but also probably pointless to do so as most theme packages are just data containers.\\nMake sure you don't delete the package for the theme you're currently using, I don't know what will happen then.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.lge.themeinstaller\",\"description\":\"Needed to install themes.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.lge.themeservice\",\"description\":\"Needed to apply themes.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.lge.touchcontrol\",\"label\":\"Touch Control Areas\",\"description\":\"I have never seen this menu in the settings app. I say it's safe to remove. I can't think of any use case for this setting, it just allows you to change where you're allowed to touch the screen\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.lge.updatecenter\",\"description\":\"LG Update Center\\nProvide Android upgrade and LG updates (Settings --> System --> Update Center)\\nI believe you won't receive any updates if this packages is deleted.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.lge.video.vr.wallpaper\",\"description\":\"Video Wallpaper\\nLG 360° VR Wallpapers\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.lge.videoplayer\",\"label\":\"LG Video\",\"description\":\"LG Video Player\",\"removal\":\"replace\",\"suggestions\":\"video_players\",\"type\":\"oem\"},{\"id\":\"com.lge.videostudio\",\"label\":\"Quick Video Editor\",\"description\":\"Allows you to create and edit video files using the videos (and photos) stored on the phone.\",\"web\":[\"https://www.lg.com/us/mobile-phones/VS980/Userguide/281.html\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.lge.voicecare\",\"description\":\"LG Voice care\\nAllows you to use your device if the touch screen or display is damaged. \\nYou must agree to location-based information use and personal information collection to use Voice Care. \\nhttps://www.lg.com/hk_en/support/product-help/CT20136018-20150122834174-others\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.lge.vrplayer\",\"description\":\"LG VR player\\nEnables you to watch 360° pictures/videos.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.lge.wallpaperpicker\",\"description\":\"Wallpaper\\nNeeded for wallpaper preview.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.lge.wapservice\",\"description\":\"Icon looks like email configuration. I'd say it's safe to remove. Probably related to the stock email app.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.lge.wernicke\",\"description\":\"QVoice Engine\\nNeeded by Q-voice (the LG Q Voice voice assistant) to work.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.lge.wernicke.nlp\",\"description\":\"Natural-language processing for LG intelligent assistant.\\nUsed to understand what a human is saying when they speak.\\nNeeded by QVoice\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.lge.wfd.spmirroring.source\",\"description\":\"Provide wifi-direct feature\\nNote : Wifi-direct is Wi-Fi standard enabling devices to easily connect with each other without requiring a wireless access point.\\nIt allows allows two devices to establish a direct Wi-Fi connection without requiring a wireless router\\nhttps://en.wikipedia.org/wiki/Wi-Fi_Direct\\nspmirroring = ??? screen p... mirroring ?\\n\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.lge.wfds.service.v3\",\"description\":\"Wifi-direct service (v3)\\nSee above.\\n\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.lge.wifi.p2p\",\"description\":\"LG P2p Service \\nWifi-drect P2P allows the device to discover the services of nearby devices directly, without being connected to a network.\\nNeeded for LG Wifi-direct feature.\\nhttps://developer.android.com/training/connect-devices-wirelessly/nsd-wifi-direct\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.lge.wifisettings\",\"description\":\"WiFi settings\\nIt can be found in settings.\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.lmi.motorola.rescuesecurity\",\"description\":\"Rescue Security by LogMeIn (https://www.logmeinrescue.com/)\\nRemote support app. Motorola made a partnership with LogMeIn : https://www.logmeinrescue.com/customer-stories/motorola\\nIt enables motorola representatives to login and remotely control the device for technical support.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.longcheertel.AutoTest\",\"label\":\"Autotest\",\"description\":\"Hidden hardware tests.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.longcheertel.cit\",\"label\":\"cit test\",\"description\":\"Hidden hardware tests.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.longcheertel.midtest\",\"label\":\"Assemble test\",\"description\":\"Hidden hardware tests.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.longcheertel.modemlog\",\"label\":\"Modem log\",\"description\":\"Hidden app that includes TcardLog, modem log, Tcpdump.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.longcheertel.sarauth\",\"label\":\"SarUI\",\"description\":\"Hidden hardware tests.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.longcheertel.secretcode\",\"description\":\"Refers to the system package that handles secret codes.\\nSecret codes are special sequences of numbers and symbols that can be entered on a phone's keypad to access hidden features or information.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.mediatek.apmonitor\",\"description\":\"APM Service\\nhas only logs\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.mediatek.mt6853.gamedriver\",\"description\":\"Mediatek GPU Driver\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.mediatek.mt6886.gamedriver\",\"description\":\"Mediatek GPU Driver\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.mediatek.ppl\",\"description\":\"Mobile anti-theft\\nIt seems that people don't even have access to it, its app to remote phone lock, wipe data, fetch back anti-theft PIN.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.meizu.account\",\"description\":\"Flyme\\nLog out before remove\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.meizu.account.pay\",\"description\":\"Pay Center chinese payment.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.meizu.activeviewlivewallpaper\",\"description\":\"Needed for live wallpapers\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.meizu.alphame\",\"description\":\"for digital health work\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.meizu.assistant\",\"description\":\"Aicy Glance meizu assistant\\nProbably Chinese assistant.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.meizu.battery\",\"description\":\"Needed for Battery Manager.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.meizu.callsetting\",\"description\":\"Additional call settings.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.meizu.cloud\",\"description\":\"Useless push service\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.meizu.customizecenter\",\"description\":\"Needed for themes but it's so bloated.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.meizu.dataservice\",\"description\":\"A lot of permissions and collects user data.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.meizu.ems\",\"description\":\"Useless frameworks.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.meizu.facerecognition\",\"description\":\"Needed for face recognition, face unlock lock screen.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.meizu.flyme.easylauncher\",\"description\":\"Easy Mode\\nit's for launcher in easy mode.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.meizu.flyme.launcher\",\"description\":\"System launcher\\nNeeded for launcher.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.meizu.flyme.sdkstage\",\"description\":\"It's for Night Mode settings. Not sure if it's important.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.meizu.flyme.service.find\",\"description\":\"Phone locating service\\nThis app will probably help you find the device.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.meizu.flyme.update\",\"description\":\"System updates\\nProvides System updates.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.meizu.flymelab\",\"description\":\"Flyme Lab\\nit's something for video window or full screen.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.meizu.media.camera\",\"description\":\"Camera\\nStock Camera app meizu.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.meizu.media.gallery\",\"description\":\"Gallery\\nMeizu gallery app.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.meizu.media.imageservice\",\"description\":\"PhotoService\\nProbably needed for Photos app.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.meizu.media.music\",\"description\":\"Music\\nStock Music app.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.meizu.media.video\",\"description\":\"Video Player\\nStock Video Player app\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.meizu.mstore\",\"description\":\"App Store\\nA lot of ads components.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.meizu.mzbasestationsafe\",\"description\":\"Base Station Guard\\nUseless location things.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.meizu.mznfcpay\",\"description\":\"Meizu chinese payment.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.meizu.mzsyncservice\",\"description\":\"Flyme cloud service\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.meizu.net.nativelockscreen\",\"description\":\"NativeLockScreen\\nI guess it's needed for lockscreen.\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.meizu.net.search\",\"description\":\"Chinese Search\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.meizu.picker\",\"description\":\"Aicy Touch\\nAnother chinese payment.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.meizu.powersave\",\"description\":\"Power Saving Mode.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.meizu.pps\",\"description\":\"One Mind\\nDischarge schedule in the security annex.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.meizu.safe\",\"description\":\"Looks like an important app. It has more things than security.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.meizu.setup\",\"description\":\"It's needed only on first-boot setup.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.meizu.share\",\"description\":\"It's maybe useful for Bluetooth\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.meizu.suggestion\",\"description\":\"Aicy Suggestion\\nOnly suggestions.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.meizu.telephonyengineermode\",\"description\":\"SIM things testing also logs.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.meizu.voiceassist\",\"description\":\"Aicy Voice\\nAnother smart thing\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.meizu.wifiadmin\",\"description\":\"WLAN Assistant\\nAdditional WLAN things.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.mfashiongallery.emag\",\"description\":\"Wallpapers by Xiaomi\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.mi.AutoTest\",\"description\":\"Assemble test\\nHidden app used by the manufacturer to test various hardware components\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.mi.android.globalFileexplorer\",\"description\":\"Xiaomi Files Manager (https://play.google.com/store/apps/details?id=com.mi.android.globalFileexplorer)\\n\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.mi.android.globallauncher\",\"description\":\"Poco Launcher\\nSystem Launcher for POCO Phone, the way icons apps are organized and displayed.\\nIf you remove this package you will loose navigation gestures and recent apps view.\\nhttps://play.google.com/store/apps/details?id=com.mi.android.globallauncher\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.mi.android.globalminusscreen\",\"label\":\"App Vault\",\"description\":\"Default App Vault package\\nSends notifications and can't be uninstalled through the Apps tab. Can be downloaded back from Play Store if needed.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.mi.android.globalminusscreen\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.mi.android.globalpersonalassistant\",\"description\":\"MI Vault aka the \\\"assistant\\\" you open swiping left from MI Home\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.mi.emapal\",\"description\":\"GamePal\\nIn China language game mode tracing menu not available for users. Safe to remove.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.mi.global.bbs\",\"description\":\"Mi Community (https://play.google.com/store/apps/details?id=com.mi.global.bbs)\\nXiaomi Forum app\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.mi.global.pocobbs\",\"description\":\"Poco Community\\nIt's only a forum and community app for POCO phones.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.mi.global.pocostore\",\"description\":\"POCO Store\\nIt's an official POCO online store.\\nhttps://play.google.com/store/apps/details?id=com.mi.global.pocostore\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.mi.global.shop\",\"description\":\"Mi Store (https://play.google.com/store/apps/details?id=com.mi.global.shop)\\nXiaomi app store\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.mi.globalTrendNews\",\"description\":\"Can't find info about this package\\nProbably used for displaying (useless) news\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.mi.globalbrowser\",\"description\":\"Mi Browser\\nPrivacy nightmare. You really should use something else.\\nhttps://www.xda-developers.com/xiaomi-mi-web-browser-pro-mint-collecting-browsing-data-incognito-mode/\\n\\nNote: Since MIUI 12, you can no longer uninstall this app. Disabling it still works fine.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.mi.globallayout\",\"label\":\"HomeLayout\",\"description\":\"Sets the default MIUI launcher to global layout instead of Chinese (or HyperOS) when you first launch the app or when cleaning the launcher data.\\nAfter removing this app there are several replacement widgets and no phone/message at the bottom.\\nBecause Chinese MUI uses other apps and package names instead of just changing the default layout in the MIUI launcher code, they just threw the app in.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.mi.globalminusscreen\",\"description\":\"Xiaomi App Vault\\nhttps://play.google.com/store/apps/details?id=com.mi.android.globalminusscreen&gl=US\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.mi.health\",\"label\":\"Mi Fitness\",\"description\":\"Formerly, Heart Rate and Mi Health, is a health monitor app that can be synchronized in the cloud.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.mi.healthglobal\",\"description\":\"Mi Health. Xiaomi's health and fitness app. Tracks sleep, step count, BMI, and menstruation cycle. Includes heart rate monitoring support using the camera.\\nhttps://www.xda-developers.com/mi-health-xiaomi-fitness-app/\\nhttps://www.xda-developers.com/xiaomi-mi-health-app-gets-heart-rate-monitoring-support-using-camera/\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.mi.liveassistant\",\"description\":\"Mi Live Assistant\\nI don't really know what it is. Maybe an old name for \\\"com.mi.android.globalpersonalassistant\\\"\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.mi.setupwizardoverlay\",\"description\":\"Weird package related to the SetupWizard (the menu which assists you to setup your phone for the first time)\\nA user said he needed to remove this package to be able to properly apply a dark theme to the Settings app.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.mi.webkit.core\",\"label\":\"MiWebView\",\"description\":\"Discontinued. Xiaomi alternative to Google WebView\\nIt is a system component for the Android operating system that allows Android apps to display content from the web directly inside an application. It's based on Chrome.\",\"removal\":\"caution\",\"warning\":\"Make sure to have another Webview before uninstalling it or some apps may not work properly and crash.\",\"suggestions\":\"webviews\",\"type\":\"oem\"},{\"id\":\"com.microfountain.rcs.service\",\"description\":\"MicroFountain RCS Service\\nChinese RCS Chats.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.microsoft.deviceintegrationservice\",\"description\":\"Device Integration Service\\nMight be needed for Microsoft Link to Windows (com.microsoft.appmanager) which is preinstalled with OxygenOS 14.\\nAfter Uninstalling, no issues occurred.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.microsoftsdk.crossdeviceservicebroker\",\"description\":\"Cross Device Broker\\nMight be needed for Microsoft Link to Windows (com.microsoft.appmanager) which is preinstalled with OxygenOS 14.\\nAfter Uninstalling, no issues occurred.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.mifavor.callsetting\",\"description\":\"Additional call features and WiFi Calling.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.mig.play.games\",\"label\":\"Funmax\",\"description\":\"Some kind of third-party game center bundled by Xiaomi.\\nHas lots of permissions by default.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.milink.service\",\"label\":\"UniPlay Service\",\"description\":\"MIUI screen casting service.\\nIf removed, you'll have to use Android's native casting services which can be accessed through a 3rd party app.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.mipay.wallet\",\"description\":\"Mi Pay (https://play.google.com/store/apps/details?id=com.mipay.in.wallet)\\nContactless NFC-based mobile payment system that supports credit, debit and public transportation cards in China.\\nhttps://www.mi-pay.com/\\n#\\n.in = Mi Pay for India\\n.id = My Pay for Indonesia\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.mipay.wallet.id\",\"description\":\"Mi Pay (https://play.google.com/store/apps/details?id=com.mipay.in.wallet)\\nContactless NFC-based mobile payment system that supports credit, debit and public transportation cards in China.\\nhttps://www.mi-pay.com/\\n#\\n.in = Mi Pay for India\\n.id = My Pay for Indonesia\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.mipay.wallet.in\",\"label\":\"Mi Pay\",\"description\":\"Contactless NFC-based mobile payment system that supports credit, debit and public transportation cards in China.\\nhttps://www.mi-pay.com/\\n#\\n.in = Mi Pay for India\\n.id = My Pay for Indonesia\",\"web\":[\"https://play.google.com/store/apps/details?id=com.mipay.in.wallet\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.mitv.download.service\",\"description\":\"DownloadService\\nUnknown app that has many mitv frameworks.\\nBut safe to remove.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.mitv.milinkservice\",\"description\":\"MiLink\\nMiui screen casting service.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.mitv.tvhome.atv\",\"description\":\"PatchWall\\nIs it a spyware app? People recommend removing it.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.mitv.tvhome.michannel\",\"description\":\"Mi Channel\\nSame app like a PatchWall.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.mitv.videoplayer\",\"description\":\"Mi TV Video Player\\nIt's video player with google ads.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.miui.accessibility\",\"label\":\"Mi Ditto\",\"description\":\"Accesibility feature. Dictation (TTS) and speech output, \\nmaking mobile devices more convenient for people who have difficulties using conventionally designed smartphones.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.miui.analytics\",\"description\":\"Xiaomi Analytics\\nThis app is shady. According to a guy who tried to reverse engineer the app, Xiaomi Analytics can replace any (signed?) package \\nthey want silently on your device within 24 hours. Maybe that no longer the case now but... you don't want analytics anyway.\\nSource : http://blog.thijsbroenink.com/2016/09/xiaomis-analytics-app-reverse-engineered/\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.miui.android.fashiongallery\",\"description\":\"Mi Wallpaper Carousel (https://play.google.com/store/apps/details?id=com.miui.android.fashiongallery)\\nA lockscreen customization app. Displays a new photo every on your lock screen every time you turn ON your screen.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.miui.antispam\",\"description\":\"MIUI Antispam \\nspam phone numbers filter (blacklist).\\nSuspicious analytics inside and has access to internet. Cloud backup possible.\\nAt quick glance it is not a private antispam app.\\nCan someone check what data are collected/transfered?\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.miui.aod\",\"description\":\"Always-on display and Lock screen editor\\nSafe to remove if you don't use \\\"Always-on display\\\" and \\\"Lock screen editor\\\" features in settings.\\nRequired for the fingerprint scanner if you want without double-tapping or pressing the power button.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.miui.audioeffect\",\"description\":\"AudioEffect from Xiaomi (https://developer.android.com/reference/android/media/audiofx/AudioEffect)\\nUsed by the equalizer (to be confirmed)\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.miui.audiomonitor\",\"label\":\"karaoke\",\"description\":\"Voice Call Recorder (only in MIUI dialer app). Unused on Global, EEA MIUI\",\"removal\":\"replace\",\"suggestions\":\"call_recorders\",\"type\":\"oem\"},{\"id\":\"com.miui.backup\",\"label\":\"MIUI Backup\",\"description\":\"Local Backup/Restore feature (Settings > Additional Settings > Local backups)\\nIt seems this app can communicate with Mi Drop\\nThis app has 73 permissions and can obviously do everything it wants.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.miui.bugreport\",\"description\":\"Mi Feedback\\nUsed to send bug report to devs\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.miui.calculator\",\"label\":\"Calculator\",\"description\":\"MIUI Calculator\\n\",\"web\":[\"https://play.google.com/store/apps/details?id=com.miui.calculator\"],\"removal\":\"replace\",\"suggestions\":\"calculators\",\"type\":\"oem\"},{\"id\":\"com.miui.carlink\",\"label\":\"CarWith\",\"description\":\"Not supported for most cars and only Chinese.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.miui.catcherpatch\",\"description\":\"Needed for Application Extension Service (com.miui.contentcatcher).\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.miui.cit\",\"label\":\"CIT\",\"description\":\"Hardware tests\\nCan be launched via secret codes, lets you run hardware tests.\",\"web\":[\"https://web.archive.org/web/20220520051328/https://twitter.com/fs0c131y/status/933037531066785797\",\"https://c.mi.com/thread-1744085-1-0.html\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.miui.cleaner\",\"label\":\"Cleaner\",\"description\":\"Shady Xiaomi cleaner app developed by Cheetah mobile which has previously been caught in ad fraud and user data theft with this app in 2018 (previously called com.miui.cleanmaster and banned from the PlayStore). This \\\"new\\\" app is still full of trackers\\n\",\"web\":[\"https://play.google.com/store/apps/details?id=com.miui.cleaner\",\"https://www.gadgets360.com/apps/news/banned-security-app-clean-master-by-cheetah-mobile-collected-user-private-data-report-2189633\",\"https://beta.pithus.org/report/f7f7ee425a8dc928db75105bd8f52e9b02f11dec3b398aac9fef1d42809d8ec1\"],\"removal\":\"replace\",\"suggestions\":\"cleaners\",\"type\":\"oem\"},{\"id\":\"com.miui.cleanmaster\",\"label\":\"Mi Cleaner\",\"description\":\"Shady Xiaomi cleaner app developed by Cheetah mobile which has previously been caught in ad fraud and user data theft in 2018. The app has been banned from the PlayStore and then reintroduced under the package name 'com.miui.cleaner'.\\n\",\"web\":[\"https://www.gadgets360.com/apps/news/banned-security-app-clean-master-by-cheetah-mobile-collected-user-private-data-report-2189633\"],\"removal\":\"replace\",\"suggestions\":\"cleaners\",\"type\":\"oem\"},{\"id\":\"com.miui.cloudbackup\",\"description\":\"Mi Cloud backup\\nNeeded for Xiaomi cloud backup.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.miui.cloudservice\",\"label\":\"Mi Cloud\",\"description\":\"Dependency for synchronizing data with Xiaomi Cloud, including photos, contacts, messages, etc.\\nThis feature is essential for Xiaomi phone users in China, as Xiaomi Cloud is their primary cloud storage service.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.miui.cloudservice.sysbase\",\"description\":\"Another Mi Cloud dependency \\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.miui.compass\",\"description\":\"Mi Compass\\nI think you understand its purpose...\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.miui.contentcatcher\",\"label\":\"Application Extension Service\",\"description\":\"It's a password manager in settings, requires Mi Account to Autofill and it syncs to your account.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.miui.contentextension\",\"description\":\"Taplus\\nIt's disabled on default in settings.\\nIt allows you to analyze images and text by pressing and holding items on your screen to get contextual info.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.miui.core\",\"label\":\"MIUI SDK\",\"description\":\"It is obiously needed for MIUI to work correctly. FYI, it manages the MIUI Analytics service (`tracking.miui.com`), autoinstall MIUI apps updates (?). Related to GetApps 'com.xiaomi.market' China Mi App Store), DropboxManager where is temp clean code, a lot of logs. Found things related to Quick Apps 'com.miui.hybrid', DataUpdateManager (related to micloud?). Telocation update, app looks like tracking everything. Can be disabled and uninstalled with MIUI 13.0.6, MIUI 14\\nNOTE: uninstalling this package causes the Settings app to crash when searching in Settings, so better disable this app instead.\\nIf you want to test, disable this app and open an issue if anything isn't working. Another weird thing is normal user can disable this app using hidden Settings to manage app by in Google Play.\\nNo effects after disable, but not sure if its required for Miui updates or gestures.\",\"web\":[\"https://github.com/0x192/universal-android-debloater/issues/632\"],\"removal\":\"caution\",\"warning\":\"Removing this package causes the Settings app to crash when searching in Settings. May also cause bootloops in MIUI < 13.0.6\",\"type\":\"oem\"},{\"id\":\"com.miui.core.internal.assistant\",\"description\":\"Needed for Chinese Mi AI (com.miui.voiceassist).\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.miui.core.internal.editor.services\",\"description\":\"I only found: config_enableHapticTextHandle true\\nWhat is this mean? it's used to permission MIUIOP 10008 in some apps.\\nMIUIOP = miui optimization? it's useless or important?\\nNo effects after removing, it's probably a feature of Touch Assistant, but its used on 'com.miui.core'?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.miui.core.internal.services\",\"description\":\"I only found: array name= config_deviceSpecificSystemServices\\nitem: com.miui.me.server.auto_install.InstallService\\nWhat does this mean? I have to check com.miui.core what it does and it's for autoinstall miui apps updates from GetApps 'com.xiaomi.market'.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.miui.daemon\",\"label\":\"System Daemon\",\"description\":\"Previously, MiuiDaemon.\\nCollects a lot of data and sends them to China.\",\"web\":[\"https://web.archive.org/web/20210923050136/https://twitter.com/fs0c131y/status/938872347087564800\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.miui.easygo\",\"description\":\"For me, this app means nothing.\\nA lot of useless code that you can't use.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.miui.enbbs\",\"description\":\"Xiaomi Forums old package.\\nNow com.mi.global.bbs.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.miui.extraphoto\",\"description\":\"Bokeh\\nThe document mode of the Xiaomi camera (for taking IDs), deleting it doesn't affect the editing of albums.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.miui.face\",\"description\":\"MIUI Biometric\\nFace Unlock feature\\n\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.miui.face.overlay.miui\",\"description\":\"MiuiBiometricResOverlay\\nFace Unlock feature will be unavailable.\",\"dependencies\":[\"com.miui.face\"],\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.miui.fm\",\"description\":\"MIUI FM Radio app\\n\",\"removal\":\"replace\",\"suggestions\":\"radios\",\"type\":\"oem\"},{\"id\":\"com.miui.fmservice\",\"description\":\"FM Radio Service\\nNeeded by com.miui.fm to work correctly\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.miui.freeform\",\"label\":\"Floating windows\",\"description\":\"You can make apps appear above other applications.\",\"web\":[\"https://forum.xda-developers.com/android/miui/floating-windows-miui-12-t4125661\"],\"removal\":\"caution\",\"warning\":\"Removing the package may cause the floating windows to stop working on some devices.\",\"type\":\"oem\"},{\"id\":\"com.miui.gallery\",\"label\":\"Xiaomi Gallery\",\"description\":\"Previously, MIUI Gallery.\\nIt has several trackers and sometimes connects to Mi Cloud, even if an account is not added.\",\"removal\":\"replace\",\"warning\":\"Removing will break the send screenshot feature (swipe 3 fingers to show the screenshot preview)\",\"suggestions\":\"gallery\",\"type\":\"oem\"},{\"id\":\"com.miui.global.packageinstaller\",\"label\":\"Xiaomi Package Installer\",\"description\":\"The non-AOSP package installer present in the Xioami phones. It also checks the installed app for viruses.\\nThe AOSP package installer is also present in Xioami EU ROMs.\",\"removal\":\"unsafe\",\"warning\":\"Removal causes bootloop on Xiaomi EU ROMs.\",\"type\":\"oem\"},{\"id\":\"com.miui.greenguard\",\"label\":\"Security Guard Service\",\"description\":\"The app includes three different antivirus brands built in that the user can choose from to keep their phone protected: Avast, AVL, and Tencent. \\nUpon selecting the app, the user selects one of these providers as the default Anti-Virus engine to scan the device.\\nIt the app that scans an app before installing it\\nNOTE: A vulnerability was found in 2019\",\"web\":[\"https://research.checkpoint.com/2019/vulnerability-in-xiaomi-pre-installed-security-app/\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.miui.guardprovider\",\"label\":\"System security components\",\"description\":\"Guard Provider security app\\nThe app includes 3 different antivirus brands built in that the user can choose (Avast, AVL and Tencent). \\nThis app notably performs a virus scan of any apps you want to install. \\nA serious vulnerability was found in 2019.\\nYou may want to remove this app from a privacy stance.\",\"web\":[\"https://research.checkpoint.com/2019/vulnerability-in-xiaomi-pre-installed-security-app/\",\"https://beta.pithus.org/report/797a7e405bc8e767deebbbcab3e06a19b05156de44292c918b582dff3078d7b8\"],\"removal\":\"caution\",\"warning\":\"Removing this package will very likely break any app installation/update.\\nBefore removing, disable security things in MIUI security app.\\nOn HyperOS this module is responsible for showing the 'Install via USB' prompt when installing apps via ADB (enabled through developer options, requires Mi account the first time).\",\"type\":\"oem\"},{\"id\":\"com.miui.home\",\"label\":\"Xioami System Launcher\",\"description\":\"Formerly, MIUI System Launcher\\nIt's basically the home screen, the way icons and apps are organized and displayed.\",\"web\":[\"https://web.archive.org/web/20220926221620/https://libreddit.spike.codes/r/Xiaomi/comments/o6vk5z/miui_12125_and_android_11_gestures/\"],\"removal\":\"unsafe\",\"warning\":\"If you remove this package on devices based on MIUI 12+ with Android 11+, you will loose navigation gestures and recent apps view even with a 3rd party launcher.\\nMake sure you've installed another launcher before you disable\",\"suggestions\":\"launchers\",\"type\":\"oem\"},{\"id\":\"com.miui.huanji\",\"description\":\"Lets you transfer your contacts, messages, personal files, all the installed apps (but not it's data). Also all the settings (app + system) from an Android phone to a Xiaomi phone.\\nThe two phones will establish a direct Wi-Fi connection.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.miui.huanji\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.miui.hybrid\",\"description\":\"Quick Apps\\nIt's basically an app which shows you ads and tracks you...\\nFunny thing, Xiaomi's Quick Apps was reportedly being blocked by Google Play Protect.\\nhttps://www.androidpolice.com/2019/11/19/xiaomi-quick-apps-flagged-blocked-google-play-protect/\\n#\\nReverse engineering of the app : \\nhttps://medium.com/@gags.gk/reverse-engineering-quick-apps-from-xiaomi-a1c9131ae0b7\\nSpoiler : you really should delete this package.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.miui.hybrid.accessory\",\"description\":\"Xiaomi Hybrid Accessory\\nSmartphone accessories support for Quick Apps (com.miui.hybrid)\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.miui.klo.bugreport\",\"description\":\"KLO Bugreport\\nThis app registers system failures and Android applications errors and sends bugs to Xiaomi servers.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.miui.maintenancemode\",\"description\":\"Maintenance Mode\\nThe maintenance mode of the cell phone, the cell phone maintenance time into an empty user data system mode, to ensure the safety of cell phone data.\\nAlso has child mode. Not useful if you are not in China.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.miui.mediaeditor\",\"description\":\"Xiaomi Gallery Editor\\nExtension for MIUI Gallery that's used to edit photos and videos.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.miui.mediafeature\",\"description\":\"MediaFeature合集\\nIs this something for media? Unused app, probably for China.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.miui.mediaviewer\",\"description\":\"Media viewer\\nOld? Mi Video.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.miui.metoknlp\",\"description\":\"Network location provider\\nUseless, only for China, have analytics things.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.miui.micloudsync\",\"label\":\"MiCloudSync\",\"description\":\"Dependency for synchronizing data with Xiaomi Cloud, including photos, contacts, messages, etc.\\nThis feature is essential for Xiaomi phone users in China, as Xiaomi Cloud is their primary cloud storage service.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.miui.miinput\",\"description\":\"Removing this package breaks \\\"Gesture shortcuts\\\" under \\\"Additional settings\\\".\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.miui.miservice\",\"label\":\"Services & feedback\",\"description\":\"Used to send feedbacks (and data) to Xiaomi. Integration in Wechat\\nSeems to be able to launch 'Baidu location service'\\nHas too many permissions, runs in the background all the time and can be removed without issue.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.miui.mishare.connectivity\",\"description\":\"Mi Share\\nUnified file sharing service between Xiaomi, Oppo, Realme and Vivo devices using Wifi-direct\\nSettings -> Connection & sharing -> Mi Share\\nFYI : Wifi direct allows 2 devices to establish a direct Wi-Fi connection without requiring a wireless router.\\n\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.miui.misound\",\"label\":\"Earphones\",\"description\":\"Provides the sounds section in Settings and is needed for the equalizing\\nSome people removed this package but I personaly don't think it's worth it. This package isn't really an issue\\n(no dangerous permissions and does not run in the background all the time)\\nYou can still remove it. You'll be just fine if you really don't need it.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.miui.miwallpaper\",\"description\":\"Mi Wallpaper \\nRemoving this might make it impossible to set a lock or home wallpaper, resulting in a black solid wallpaper.\\nNote: it may also result in longer boot times (~15s) because the system try to call miwallpaper during boot\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.miui.miwallpaper.earth\",\"label\":\"Super wallpapers - Earth\",\"description\":\"Live/animated Xiaomi wallaper\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.miui.miwallpaper.geometry\",\"label\":\"SuperWallpaperGeometry\",\"description\":\"Live/animated Xiaomi wallaper\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.miui.miwallpaper.mars\",\"label\":\"SuperWallpaperMars\",\"description\":\"Live/animated Xiaomi wallaper\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.miui.miwallpaper.moon\",\"label\":\"The Moon Super wallpapers\",\"description\":\"Live/animated Xiaomi wallaper\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.miui.miwallpaper.saturn\",\"label\":\"SuperWallpaperSaturn\",\"description\":\"Live/animated Xiaomi wallaper\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.miui.miwallpaper.snowmountain\",\"label\":\"SuperWallpaperSnowmountain\",\"description\":\"Live/animated Xiaomi wallaper\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.miui.miwallpaper.overlay\",\"description\":\"App that doesn't do anything, no code. Safe to remove.\\n You will need to remove it twice.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.miui.miwallpaper.overlay.customize\",\"description\":\"App that doesn't do anything, no code. Safe to remove.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.miui.miwallpaper.overlay.lundun\",\"description\":\"app that doesnt do anything, no code. Safe to remove.\\n You will need remove it 2 times.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.miui.miwallpaper.overlay.qr\",\"description\":\"Useless app to default lock wallpaper path? Probably unused. Safe to remove.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.miui.miwallpaper.telcel.overlay\",\"description\":\"Useless app to telcel wallpaper? Probably unused. Safe to remove.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.miui.msa.global\",\"description\":\"Main System Ads\\nAnalyzation of user behaviors to show you ads. Yeah Xiaomi phones has ads...\\nhttps://www.theverge.com/2018/9/19/17877970/xiaomi-ads-settings-menu-android-phones\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.miui.newhome\",\"description\":\"Content Service\\nA lot bloated.\\nOnly useful in China.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.miui.newmidrive\",\"description\":\"Mi Drive (Chinese version)\\nLets you upload and sync your files on the (Mi) Cloud.\\nAlways run in background\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.miui.nextpay\",\"label\":\"Smart cards Web Extention\",\"description\":\"Only for Chinese users.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.miui.notes\",\"label\":\"MIUI Notes\",\"description\":\"MIUI's note-taking app.\",\"removal\":\"replace\",\"suggestions\":\"note_taking_apps\",\"type\":\"oem\"},{\"id\":\"com.miui.notification\",\"label\":\"Notifications\",\"description\":\"Notifications are working without this app.\\nIt is possible to access the app notification settings by long pressing on the notification without the app.\\nIt embeds a tracking statistics service\\n(usage tracking : `id`,`pkgName`,`latestSentTime`,`sentCount`,`avgSentDaily`,`avgSentWeekly)\",\"removal\":\"caution\",\"warning\":\"notification settings in the settings menu will be broken without this package. The app is mandatory to enable notifications of apps that have been disabled before.\",\"type\":\"oem\"},{\"id\":\"com.miui.otaprovision\",\"description\":\"OtaProvision\\nUseless, only for China, have analytics things.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.miui.packageinstaller\",\"description\":\"Package installer\\nHardcoded in Xiaomi China Rom.\\nCauses BOOTLOOP on Chinese ROM When remove.\\nIt's weird when after a month this app is gone from my phone for no reason and Android enabled stock package installer.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.miui.personalassistant\",\"description\":\"Seems to be App Vault on some phones (https://play.google.com/store/apps/details?id=com.mi.android.globalpersonalassistant)\\nhttps://c.mi.com/thread-1017547-1-0.html\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.miui.phone.carriers.customized.overlay\",\"description\":\"Something about WiFi calling \\\"vowifi\\\", \\\"volte\\\", \\\"notification on keyguard\\\"\\nIt's unused.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.miui.phone.carriers.overlay\",\"description\":\"Preferred network type to Vodafone 5G/4G/3G/2G auto.\\nIt's unused.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.miui.phone.carriers.overlay.h3g\",\"description\":\"Preferred network type to h3g 5G/4G/3G/2G auto.\\nIt's unused.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.miui.phone.carriers.overlay.vodafone\",\"description\":\"Preferred network type to Vodafone 5G/4G/3G/2G auto.\\nIt's unused.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.miui.phrase\",\"label\":\"Frequent phrases\",\"description\":\"MIUI context menu tool for pre-made text responses while chatting. It has access to the Internet, is linked to MiCloud and contains a weird CloudTelephonyManager class in its code.\",\"removal\":\"caution\",\"warning\":\"Disabling causes a crash when touching the \\\"Frequent phrases\\\" item. (The crash occurs in the application that invoked the context menu with this item)\",\"type\":\"oem\"},{\"id\":\"com.miui.player\",\"label\":\"Mi Music\",\"description\":\"Mi Music player\\n\",\"web\":[\"https://play.google.com/store/apps/details?id=com.miui.player\"],\"removal\":\"replace\",\"suggestions\":\"music_apps\",\"type\":\"oem\"},{\"id\":\"com.miui.powerkeeper\",\"description\":\"Battery and Performance\\n(aggressive) MIUI power management (https://dontkillmyapp.com/xiaomi)\\nThat's a weird app that also contains a DRM Manager and a service related to Cloud Backup\\nHas obviously a lot of dangerous permissions.\\nI guess removing this package will decrease the battery performance. Is it that noticeable? Can someone try?\\nNOTE: REMOVING THIS PACKAGE CAUSES A BOOTLOOP ON THE REDMI PAD.\\nTo not get bootloop, log out from Mi Account.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.miui.privacycomputing\",\"description\":\"MIUI Privacy Components\\nUnknown app from Miui China.\\nThere's something about keys, key status code.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.miui.providers.weather\",\"description\":\"Provider for MI Weather app (com.miui.weather)\\nContent providers encapsulate data, providing centralized management of data shared between apps.\\nhttps://developer.android.com/guide/topics/providers/content-providers.html\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.miui.qr\",\"description\":\"MUI Qr code scanner\\n\",\"removal\":\"replace\",\"suggestions\":\"barcode_scanners\",\"type\":\"oem\"},{\"id\":\"com.miui.rom\",\"description\":\"Core package of MIUI\\nDO NOT REMOVE THIS\\n\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.miui.screenrecorder\",\"description\":\"Mi Screen Recorder\\n\",\"removal\":\"replace\",\"suggestions\":\"screen_recorders\",\"type\":\"oem\"},{\"id\":\"com.miui.screenshot\",\"description\":\"MIUI Screenshot\\nScreenshots will not work.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.miui.securityadd\",\"label\":\"Xiaomi System Service Plugin\",\"description\":\"Related to the MIUI Security app\",\"web\":[\"https://github.com/0x192/universal-android-debloater/issues/641\"],\"removal\":\"caution\",\"warning\":\"Removing the app may cause bootloops in MIUI version below 13.\",\"type\":\"oem\"},{\"id\":\"com.miui.securitycenter\",\"label\":\"Xiaomi Security\",\"description\":\"Provides \\\"protection and optimization tools\\\": App lock, Data usage, Security scan, Cleaner, Battery saver, Blocklist and other features. It is mostly a front-end (UI).\",\"web\":[\"https://beta.pithus.org/report/f8c24ccfc526389ff9084505c60fba3d3463565f92e2015190e2974b370e7c4e\",\"https://github.com/0x192/universal-android-debloater/issues/641\"],\"removal\":\"caution\",\"warning\":\"Removing the app may cause bootloops. It does not cause bootloops in Redmi Pad or MIUI 13 onwards, but you will lose some functionality like the battery status/usage page, as well as the app usage/removal page.\",\"type\":\"oem\"},{\"id\":\"com.miui.securitycenter.securitycenter_phone_overlay.config.overlay\",\"description\":\"'Security tools' name app only found\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.miui.securitycore\",\"label\":\"Security Core Component\",\"description\":\"Core features of the \\\"com.miui.securitycenter\\\".\\nProvides Enterprise Mode, Dual App, Second Space, Fingerprint Add, Gesture Settings. It also shows annoying notifications when launching a new app.\",\"web\":[\"https://github.com/0x192/universal-android-debloater/issues/641\"],\"removal\":\"caution\",\"warning\":\"Removing the app may cause bootloops. On Miui 13 and above, it doesn't cause bootloops, and the performance appears very similar.\",\"type\":\"oem\"},{\"id\":\"com.miui.securityinputmethod\",\"label\":\"Mi Secure Keyboard\",\"description\":\"A useless keyboard used to secure your password when logging in.\",\"removal\":\"replace\",\"suggestions\":\"keyboards\",\"type\":\"oem\"},{\"id\":\"com.miui.settings.rro.device.hide.statusbar.overlay\",\"description\":\".webp files, and one config for me it means nothing. Only Chinese.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.miui.settings.rro.device.type.overlay\",\"description\":\"I found only PNG files and it's Chinese. Only Chinese.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.miui.smsextra\",\"label\":\"com.miui.smsextra\",\"description\":\"Dependency for MIUI Messaging (MIUI SMS app misleadingly called `com.android.mms`)\\nYou can remove it if you don't use the default SMS app (and you shouldn't). Run in the background once the phone is booted, has access to the internet and interact with Cloud Manager.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.miui.spock\",\"label\":\"Spock\",\"description\":\"Analytics app which constantly runs in the background.\\nSends identifiable data to Xiaomi servers.\\nIt leaks system version, device model, exact firmware build + some few mysterious IDs.\",\"web\":[\"https://www.virustotal.com/gui/file/70400d0055e1924966fb8367cafddc175dee914bbdc227342c9dd86fb3aa829f/details\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.miui.sysopt\",\"description\":\"SysoptApplication\\nStrange app with no permissions. By looking at the code it seems to be some kind of debug app.\\nThe app doesn't seem to do any interesting stuff.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.miui.system\",\"description\":\"Called 'MIUI System Launcher' but it's not the launcher itself (com.miui.home is)\\nThis package is another core MIUI app you can't remove. It centralizes a lot of default configuration values\\n\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.miui.system.overlay\",\"description\":\"App without code and safe to remove.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.miui.systemAdSolution\",\"description\":\"Spyware which analyses user behavior for targeted ads. Yeah Xiaomi phones has ads...\\nhttps://www.theverge.com/2018/9/19/17877970/xiaomi-ads-settings-menu-android-phones\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.miui.systemui.carriers.overlay\",\"description\":\"Important overlay to LTE connection.\",\"removal\":\"unsafe\",\"warning\":\"Removing the package breaks LTE connection.\",\"type\":\"oem\"},{\"id\":\"com.miui.systemui.devices.overlay\",\"description\":\"The empty space between the status bar and the edges of the screen\\nElements at edges ignore screen fillets and cutouts when removed.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.miui.systemui.overlay.devices.android\",\"description\":\"Config doze Component 'com.miui.aod' and ext media ready notification 'Tap to safely remove device'.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.miui.thirdappassistant\",\"description\":\"Third party app problems\\nIt's boring app.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.miui.touchassistant\",\"description\":\"Quick Ball/Touch Assistant\\nTouch assistant with a combination of five unique shortcuts which aimed to give easy and quick access to functions and apps you use frequently.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.miui.translation.kingsoft\",\"description\":\"Translation stuff by Kingsoft (https://en.wikipedia.org/wiki/Kingsoft)\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.miui.translation.xmcloud\",\"label\":\"com.miui.translation.xmcloud\",\"description\":\"Translation stuff. Does not impact global translation for non-chinese users.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.miui.translation.youdao\",\"description\":\"Translation stufff by Youdao (https://en.wikipedia.org/wiki/Youdao)\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.miui.translationservice\",\"label\":\"com.miui.translationservice\",\"description\":\"Translation stuff. Does not impact global translation for non-chinese users.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.miui.tsmclient\",\"description\":\"Smart cards\\nOnly for Chinese.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.miui.tv.analytics\",\"description\":\"Analytics\\nWeird analytics app with a lot random stuff found in resources.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.miui.uireporter\",\"description\":\"UIReporter\\nThis Chinese app has some secret code: 847, 1130.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.miui.userguide\",\"description\":\"Xiaomi User guide\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.miui.video\",\"label\":\"Mi Video\",\"description\":\"Mi Video with a different package name.\\nHas a lot of ads, tracking.\",\"removal\":\"replace\",\"suggestions\":\"video_players\",\"type\":\"oem\"},{\"id\":\"com.miui.videoplayer\",\"label\":\"Mi Video\",\"description\":\"Has a lot of ads, tracking.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.miui.videoplayer\"],\"removal\":\"replace\",\"suggestions\":\"video_players\",\"type\":\"oem\"},{\"id\":\"com.miui.videoplayer.overlay\",\"description\":\"Mi Video overlay\\nOverlays are usually themes.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.miui.vipservice\",\"description\":\"My services\\nCustomer support maybe not be available for users.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.miui.virtualsim\",\"description\":\"Mi Roaming\\nIt enables users to connect to roaming data on-demand via virtual SIM technology.\\nhttps://alertify.eu/xiaomi-mi-roaming/\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.miui.voiceassist\",\"label\":\"Mi AI\",\"description\":\"Chinese voice assist.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.miui.voiceassistoverlay\",\"description\":\"Overlay to Mi AI 'com.miui.voiceassist'.\\nThe overlay won't show up when you trigger it, which makes the voice-to-command features largely inaccessible.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.miui.voicetrigger\",\"label\":\"Wake with voice\",\"description\":\"Not needed if you removed Chinese Mi AI.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.miui.vpnsdkmanager\",\"description\":\"MiuiVpnSdkManager\\nVpn to game service?\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.miui.vsimcore\",\"description\":\"Virtual Sim core service\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.miui.wallpaper.overlay\",\"description\":\"App that doesnt do anything, no code. Safe to remove.\\n You will need remove it 2 times.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.miui.wallpaper.overlay.customize\",\"description\":\"App that doesnt do anything, no code. Safe to remove.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.miui.weather2\",\"label\":\"Weather\",\"description\":\"Weather app By Xiaomi.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.miui.weather2\"],\"removal\":\"replace\",\"suggestions\":\"weather_apps\",\"type\":\"oem\"},{\"id\":\"com.miui.wmsvc\",\"label\":\"WMService\",\"description\":\"Runs at boot and has access to internet + GPS\\nI quickly looked at the decompiled code and saw some unsanitized SQL inputs, which is BAD! (vulnerable to SQL injection)\\nTries to get your android unique Google advertising ID from Google Play Services.\\nFeeds and launches the spying/analytics app \\\"com.miui.hybrid\\\".\\nDoesn't seem to do anything important, only tracking.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.miui.yellowpage\",\"description\":\"Yellow Page from MIUI.\\nREMINDER : Yellow pages contain phone numbers of companies and services. They are provided by Xiaomi partners or businesses themselves.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.miui.zman\",\"description\":\"Mi Secure sharing\\nProvides an option in the settings of the Xiaomi Gallery to automatically remove location and metadata from images \\nyou want to share. This do not remove metadata of the picture in the gallery but only the shared copy.\\nThere's also a \\\"Secure sharing\\\" watermark that shows up when you share photos on WeChat without metadata.\\nThe question is does this really remove all EXIF tags? Can someone test?\\nThis is a useful app anyway but do not forget that all your photos/vidoes taken with the Xiaomi camera are still geo-tagged \\n(+ all others exif tags) by default. \\nWhat you can do is at least revoke the GPS permission to the camera.\\nFOSS alternative to this app : \\nhttps://f-droid.org/fr/packages/com.jarsilio.android.scrambledeggsif/\\nhttps://f-droid.org/fr/packages/de.kaffeemitkoffein.imagepipe/\\n\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.miuix.editor\",\"label\":\"textaction\",\"description\":\"This application is responsible for displaying the text action toolbar in MIUI. Some applications, such as Telegram, use a custom text action toolbar, but most applications this standard toolbar.\",\"removal\":\"delete\",\"warning\":\"If removed, it will fall back to the Android's standard text action toolbar.\",\"type\":\"oem\"},{\"id\":\"com.mmigroup.fmradio\",\"description\":\"App for Hardware Testing Things.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.mobeam.barcodeService\",\"description\":\"The Beaming Service enables your device to beam (relay) barcodes, as found on digital coupons, event tickets, library cards, loyalty \\ncards and membership cards to 1D red laser and Image based scanners prevalent at nearly every retail store and checkout stand around the world.\\nMobeam is a 3-party (https://mobeam.com/)\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.mobile.iroaming\",\"label\":\"Data Store\",\"description\":\"Only useful if you need roaming mobile data when travelling overseas. Has a lot of dangerous permissions and phone home to Vivo domains.\",\"web\":[\"https://beta.pithus.org/report/d7cfa53942159a0e9c1bf3643b5f38496daee4c0225e8155249db9fdc979187c\"],\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.mobiletools.systemhelper\",\"label\":\"SystemHelper\",\"description\":\"Not available for users, has something about dual sim, App Info.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.modemdebug\",\"description\":\"Hidden running in the background debugs for data traffic and all that, not useful for the average person.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.monotype.android.font.felbridge\",\"description\":\"Felbridge FlipFont\\nChanges the user interface font on your phone.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.monotype.android.font.manroperegular\",\"description\":\"ManropeRegular FlipFont\\nChanges the user interface font on your phone.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.monotype.android.font.mfinancehkbold\",\"description\":\"MfinancehkBold FlipFont\\nChanges the user interface font on your phone.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.monotype.android.font.myinghei18030m\",\"description\":\"Myinghei18030m FlipFont\\nChanges the user interface font on your phone.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.monotype.android.font.myuppymediumtc\",\"description\":\"Myuppymediumtc FlipFont\\nChanges the user interface font on your phone.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.monotype.android.font.oxaniumregular\",\"description\":\"OxaniumRegular FlipFont\\nChanges the user interface font on your phone.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.monotype.android.font.rajdhanimedium\",\"description\":\"RajdhaniMedium FlipFont\\nChanges the user interface font on your phone.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.monotype.android.font.samsungone\",\"description\":\"Samsung One font\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.monotype.android.font.samsungsans\",\"description\":\"SamsungSans font\\nFont\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.monotype.android.font.syndor\",\"description\":\"Syndor FlipFont\\nChanges the user interface font on your phone.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.motorola.VirtualUiccPayment\",\"label\":\"Virtual UICC Payment\",\"description\":\"SIM Card Payment also NFC. Only useful in China by hidden image files.\\nUICC stands for Universal Integrated Circuit Card.\\nIt is the physical and logical platform for the USIM and may contain additional USIMs and other applications.\\n(U)SIM is an application on the UICC.\\nI guess this package provides support for NFC payments.\\nNote: The term SIM is widely used to refer to both SIMs and UICCs in the industry and among consumers.\",\"web\":[\"https://bluesecblog.wordpress.com/2016/11/18/uicc-sim-usim/\",\"https://blog.velosiot.com/euicc-and-esim-are-they-the-same-thing\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.motorola.actions\",\"label\":\"Moto Actions & Gestures\",\"description\":\"Allows you to perform specific gestures to perform certain tasks. Frontend to change settings provided by \\\"com.motorola.moto\\\".\",\"web\":[\"https://play.google.com/store/apps/details?id=com.motorola.actions\",\"https://beta.pithus.org/report/5c26c2865ec9692efba4377598f8130c25f66706901144f49438230a11590f01\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.motorola.actions.overlay\",\"label\":\"com.motorola.actions.overlay\",\"description\":\"Overlay package for \\\"com.motorola.actions\\\".\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.motorola.aiservices\",\"label\":\"Moto AI Services\",\"description\":\"Service to supply artificial intelligence models to Motorola apps. Not sure where the AI services are integrated.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.motorola.aiservices\",\"https://beta.pithus.org/report/effeb339cfeb3d8fcbf2023b6ccdec77e012d9417ee0579cf998bcb090741362\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.motorola.android.connectivity.resources.overlay\",\"description\":\"Configs to bad wifi better keep it.\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.motorola.android.coresettingsext.overlay.avatrn\",\"description\":\"This package is part of Motorola's custom overlay for system settings, specifically tailored for the Motorola Edge 2024 (codename 'avatrn').\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.motorola.android.coresettingsext.overlay.doubletap\",\"description\":\"Double tap to put display to sleep\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.motorola.android.coresettingsext.overlay.dubai\",\"description\":\"Needed for support other refresh rate value?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.motorola.android.fmradio\",\"label\":\"FMRadioService\",\"dependencies\":[\"com.motorola.fmplayer\"],\"description\":\"Required for Motorola FM Radio\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.motorola.android.fota\",\"label\":\"Software update\",\"description\":\"Required for OTA updates which are ssential part of keeping your device secure and up to date with regular security patchs.\\nFOTA = firmware over the air\",\"removal\":\"caution\",\"warning\":\"Breaks OTA updates\",\"type\":\"oem\"},{\"id\":\"com.motorola.android.jvtcmd\",\"label\":\"JavaTcmdHelper\",\"description\":\"tcmd = commandes types. Seems to be a tools wich help find Java commands types.\\nUseless for normal user.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.motorola.android.launcher.overlay.animation.scale\",\"description\":\"Overlay to transition_anim_scale? Maybe unused, not sure.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.motorola.android.launcher.overlay.motolauncheroverlayna\",\"description\":\"This package is part of Motorola's custom launcher overlay, specifically tailored for their devices.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.motorola.android.launcher.overlay.retail.global\",\"description\":\"This package is part of Motorola's custom launcher overlay designed for retail or global versions of their devices.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.motorola.android.nativedropboxagent\",\"label\":\"NativeDropBoxAgent\",\"description\":\"It is not related to Cloud Dropbox company but to Android logging. It is used during development.\",\"web\":[\"https://stackoverflow.com/questions/4434192/dropboxmanager-use-cases\",\"https://beta.pithus.org/report/b7376e9ca607e856c9b39eb93e5aa420dab7f32424b61c5325f55faa03d2a97f\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.motorola.android.networkstack.overlay.mcc460\",\"description\":\"This package is part of Motorola's custom network stack overlay, specifically related to the network configuration for a particular Mobile Country Code (MCC), in this case, MCC 460 (which corresponds to China).\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.motorola.android.networkstack.tethering.overlay.motCommon\",\"description\":\"This package is part of Motorola's custom overlay for the network stack, specifically related to tethering and hotspot functionalities.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.motorola.android.overlay.common\",\"description\":\"It has some important configs. Better don't risk.\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.motorola.android.overlay.crystaltalkai\",\"description\":\"Enable crystal talk AI settings? I've never seen that.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.motorola.android.overlay.deviceconfig.manaus\",\"description\":\"Random configurations to basic things(powersaving, network, camera, etc.).\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.motorola.android.overlay.gabutton\",\"description\":\"\\\"Double press on power behavior\\\" 0\\nNot sure if useful, maybe it's another gesture.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.motorola.android.overlay.lhbm\",\"description\":\"Not sure if its for high brightness mode, still unknown\\n'config_udfps_local_hbm_supported' 'true'\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.motorola.android.overlay.lpptoga\",\"description\":\"This package is part of Motorola's custom overlay and is likely associated with specific visual or functional enhancements tailored for Motorola devices.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.motorola.android.overlay.payjoy\",\"label\":\"com.motorola.android.overlay.payjoy\",\"description\":\"Overlay for 'com.payjoy.access'\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.motorola.android.overlay.qcom.common\",\"description\":\"This package is part of Motorola’s custom overlay and is associated with Qualcomm (Qcom) related functionality or optimizations.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.motorola.android.overlay.wfd\",\"description\":\"It has config to enable wifi display.\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.motorola.android.providers.chromehomepage\",\"label\":\"com.motorola.android.providers.chromehomepage\",\"description\":\"Seems to provide the \\\"Home\\\"-button functionality in Chrome.\",\"web\":[\"https://forum.xda-developers.com/android/apps-games/app-chrome-homepage-t3695804\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.motorola.android.providers.settings\",\"label\":\"Settings storage\",\"description\":\"Seems to required for device settings.\",\"removal\":\"unsafe\",\"warning\":\"Some of the device settings will crash continuously.\",\"type\":\"oem\"},{\"id\":\"com.motorola.android.providers.settings.auto_generated_rro_product__\",\"label\":\"com.motorola.android.providers.settings.auto_generated_rro_product__\",\"description\":\"RRO = runtime resource overlay.\\nUsed for various system settings customizations.\",\"web\":[\"https://www.phonecheck.com/blog/what-is-android-auto-generated-rro\",\"https://beta.pithus.org/report/ecc311a58af6143697c69fba7d1387892f778386db96303ddf518411a7f41598\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.motorola.android.providers.settings.overlay.dppcamera\",\"description\":\"This package is part of Motorola's custom settings overlay, specifically related to settings for the camera application.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.motorola.android.providers.settings.overlay.dppnone\",\"description\":\"This package is part of Motorola's custom settings overlay, potentially dealing with settings or configurations that are applied when certain features or options are not in use.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.motorola.android.provisioning\",\"label\":\"OMA client provisioning\",\"description\":\"It is a protocol specified by the Open Mobile Alliance (OMA).\\nIt is used by carrier to send \\\"configuration SMS\\\" which can setup network settings (such as APN).\\nIn my case, it was automatic and I never needed configuration messages. I'm pretty sure that in France this package is useless.\\nMaybe it's useful if carriers change their APN... but you still can change it manually, it's not difficult.\\nNote : These special \\\"confirguration SMS\\\" can be abused.\",\"web\":[\"https://www.zdnet.fr/actualites/les-smartphones-samsung-huawei-lg-et-sony-vulnerables-a-des-attaques-par-provisioning-39890045.html\",\"https://www.csoonline.com/article/3435729/sms-based-provisioning-messages-enable-advanced-phishing-on-android-phones.html\"],\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.motorola.android.settings.diag_mdlog\",\"description\":\"Diag_mdlog is a small proprietary Qualcomm program which can store DIAG logs on the filesystem.\\nNo longer in Android 10 image\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.motorola.android.settings.modemdebug\",\"label\":\"Modem Debug Settings\",\"description\":\"Provide modem debug settings menu ?\\nNo longer in Android 10 image\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.motorola.android.settings.overlay.eqs\",\"description\":\"Overlay to refresh rate change in settings.\\nNot sure if it's unused.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.motorola.android.settings.overlay.fps.display\",\"description\":\"Overlay to fps display.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.motorola.android.settings.overlay.global\",\"description\":\"This package is part of Motorola's custom settings overlay and is designed for global settings that apply across different regions or device configurations.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.motorola.android.settings.overlay.lra\",\"description\":\"This package is part of Motorola’s custom settings overlay, likely related to specific regional or device configurations.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.motorola.android.settings.overlay.power.bottom\",\"description\":\"This package is part of Motorola’s custom settings overlay, specifically related to power management settings.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.motorola.android.systemui.overlay.att\",\"description\":\"This overlay needed for (com.motorola.attvowifi) I guess. It's for WiFi Calling.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.motorola.android.systemui.overlay.sprint\",\"description\":\"Needed for Moto Stats WiFi, it's useless.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.motorola.android.systemui.overlay.tmo\",\"description\":\"Needed for Moto Stats WiFi, it's useless.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.motorola.android.systemui.overlay.usc\",\"description\":\"Needed for Moto Stats WiFi, it's useless.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.motorola.android.systemui.overlay.vzw\",\"description\":\"Needed for Moto Stats WiFi, it's useless.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.motorola.appdirectedsmsproxy\",\"label\":\"Motorola Message Service\",\"description\":\"An Application directed SMS (or rather a Port directed SMS) is an SMS directed to a specific port.\\nApps need to listen to this port to get the SMS message.\\nI don't know if this package allows port directed SMS or if it just provide a proxy feature.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.motorola.appforecast\",\"label\":\"Performance\",\"description\":\"Seems to be always running in background.Not sure what it does.\",\"web\":[\"https://beta.pithus.org/report/54ae099575a10e12e59064e2999373332b0b6d2eb76b56964697f87700db1dbb\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.motorola.audiofx\",\"description\":\"/!\\\\ Removal causes bootloop on Moto G7 Power (Android 10)\\nAudio effects\\nProvide features like Equalizer, Surround sound...\\n\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.motorola.audiorecorder\",\"description\":\"Audio recorder\\nStock Audio recorder for Motorola\\nhttps://play.google.com/store/apps/details?id=com.motorola.audiorecorder\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.motorola.bach.modemstats\",\"label\":\"Modem Service\",\"description\":\"Statistics and events logs from the modem activity.\\nResponsible for opening the network services on your Verizon phone.\",\"web\":[\"https://internet-access-guide.com/what-is-motorola-modem-service/\"],\"removal\":\"caution\",\"warning\":\"It will adversely influence the data usage and connectivity if disabled.\",\"type\":\"oem\"},{\"id\":\"com.motorola.batterycare\",\"description\":\"This package is part of Motorola's battery management system, specifically related to features or optimizations for battery care.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.motorola.batterycare.overlay\",\"description\":\"This package is part of Motorola’s custom battery care overlay and is likely responsible for providing Motorola-specific enhancements or visual elements related to battery management.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.motorola.batterycare.overlay.appside\",\"description\":\"This package is part of Motorola's custom battery care overlay and is likely associated with specific enhancements or visual elements related to battery management on the app side of the user interface.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.motorola.blur.service.blur\",\"description\":\"MOTOBLUR service\\nAutomatically syncs messages, emails, social status updates, contacts and pictures from your accounts straight to your Home screen. It's a serious privacy concern:\\nhttps://www.beneaththewaves.net/Projects/Motorola_Is_Listening.html\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.motorola.brapps\",\"label\":\"App Box\",\"description\":\"Offers you a selection of applications developed by Brazilians and also apps selected for you.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.motorola.brapps\",\"https://beta.pithus.org/report/842d17e1944d748a7813ee8deb072224fd0665cf6c0504a0d90e46568d4c444d\"],\"removal\":\"replace\",\"suggestions\":\"app_stores\",\"type\":\"oem\"},{\"id\":\"com.motorola.bug2go\",\"label\":\"com.motorola.bug2go\",\"description\":\"Bugs reporting app that sends info about various crash reports and logs.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.motorola.callredirectionservice\",\"label\":\"com.motorola.callredirectionservice\",\"description\":\"Added in Android 10. Provide support for call redirection/cancellation if your Carrier supports it.\",\"web\":[\"https://motorola-global-portal.custhelp.com/app/answers/prod_answer_detail/a_id/140542\",\"https://en.wikipedia.org/wiki/Call_forwarding\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.motorola.camera2\",\"description\":\"Moto Camera 2 (https://play.google.com/store/apps/details?id=com.motorola.camera)\\n\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.motorola.camera3\",\"description\":\"Moto Camera 3\\nMoto camera app\\nhttps://play.google.com/store/apps/details?id=com.motorola.camera3\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.motorola.camera3.consent.ai\",\"description\":\"Camera consent AI\\nCamera consent AI? Artificial Intelligence models? Probably additonal features to camera app\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.motorola.camera3.content.ai\",\"description\":\"This package is related to Motorola's camera application, specifically focusing on AI (artificial intelligence) features.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.motorola.carriersettingsext\",\"description\":\"This is a WiFi calling app supported by AT&T, T-Mobile, Orange.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.motorola.ccc.devicemanagement\",\"label\":\"Device Management\",\"description\":\"Mobile Device Management (MDM) allows company’s IT department to reach inside your phone in the background, allowing them to ensure your device is secure, know where it is, and remotely erase your data if the phone is stolen.\",\"web\":[\"https://onezero.medium.com/dont-put-your-work-email-on-your-personal-phone-ef7fef956c2f\",\"https://blog.cdemi.io/never-accept-an-mdm-policy-on-your-personal-phone/\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.motorola.ccc.mainplm\",\"label\":\"Motorola Services Main\",\"description\":\"plm = Product Lifecycle Management ? No noticeable consequences after removal\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.motorola.ccc.notification\",\"label\":\"Motorola Notifications\",\"description\":\"If you opt-in, it sends periodic product-related information, including notifications on software updates, tips & tricks, survey and information about new Motorola products and services.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.motorola.ccc.notification\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.motorola.ccc.ota\",\"label\":\"Motorola software update\",\"description\":\"Provide OTA system updates.\\nOTA (Over-The-Air) updates allow manufacturers to remotely install new software updates, features and services.\",\"removal\":\"caution\",\"warning\":\"Breaks OTA updates\",\"type\":\"oem\"},{\"id\":\"com.motorola.comcast.settings.extensions\",\"description\":\"Most likely provides a special settings menu for Comcast stuff.\\nI think it's installed on Xfinity branded phones.\\nSafe to remove (tested only on non-Comcast phone).\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.motorola.comcastext\",\"label\":\"Activation\",\"description\":\"See above. Provides special features from Comcast? Probably safe to remove (tested only on non-Comcast phone).\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.motorola.config.wifi\",\"label\":\"com.motorola.config.wifi\",\"description\":\"Appears safe to remove.\\nWPA config App\\nWi-Fi not affected after removal.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.motorola.contacts.preloadcontacts\",\"label\":\"Preloaded Contacts Loader\",\"description\":\"Provides contacts preset by carriers.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.motorola.contacts.preloadcontacts.overlay.vzw\",\"description\":\"Useless icon to Verizon Wireless app.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.motorola.coresettingsext\",\"description\":\"Core Settings extension\\nSafe to remove (no bootloop) but its usefulness remains unkown.\\nIt's an app for random settings, but it's unused?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.motorola.dciservice\",\"description\":\"It's IMS Signal tests probably. Used for statistics. Code 3243.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.motorola.demo\",\"label\":\"Demo mode\",\"description\":\"Enable retail demonstration mode.\",\"web\":[\"https://source.android.com/devices/tech/display/retail-mode\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.motorola.demo.env\",\"label\":\"com.motorola.demo.env\",\"description\":\"Needed for Moto Demo Mode\\nenv = environment\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.motorola.discovery\",\"label\":\"Moto Discovery\",\"description\":\"Not sure what it does\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.motorola.dolby.dolbyui\",\"label\":\"Dolby Atmos\",\"description\":\"Dolby helps you rich and engaging sound.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.motorola.dynamicvolume\",\"label\":\"Adaptive volume\",\"description\":\"Used to control the Multi-Volume feature, where apps can have their own volume level set. It can also automatically mute apps that you always mute manually.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.motorola.easyprefix\",\"label\":\"Easy Prefix\",\"description\":\"Auto add CSP (Service Provider code) prefix to your phone when you're abroad.\\nhttps://en.wikipedia.org/wiki/List_of_country_calling_codes\\nThis seems to not work correctly and it's generally not a good idea to call home (via GSM) when you're abroad.\\nIt's better and cheaper to use chat apps like Signal/Wire\",\"web\":[\"https://play.google.com/store/apps/details?id=com.motorola.easyprefix\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.motorola.email\",\"label\":\"Moto Email\",\"description\":\"Auto add CSP (Service Provider code) prefix to your phone when you're abroad.\\nhttps://en.wikipedia.org/wiki/List_of_country_calling_codes\\nThis seems to not work correctly and it's generally not a good idea to call home (via GSM) when you're abroad.\\nIt's better and cheaper to use chat apps like Signal/Wire\",\"web\":[\"https://play.google.com/store/apps/details?id=com.motorola.email\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.motorola.enterprise.adapter.service\",\"description\":\"Moto Thinkshield\\nAdditional security frameworks.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.motorola.enterprise.service\",\"label\":\"Moto Thinkshield-MM\",\"description\":\"Provides various security to Moto devices. More info needed.\",\"web\":[\"https://www.motorola.com/business/thinkshield/\",\"https://beta.pithus.org/report/db140841cffe28643367bd1d595c885a02852d06136086b0ffc41aab79db5ff0\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.motorola.entitlement\",\"label\":\"Entitlement\",\"description\":\"Enable WiFi tethering/hotspot functionality.\\nWhat you can do is preventing the phone from notifying the carrier about when you use hotspot. It will bypass mobile carriers tethering restrictions.\\nFrom an ADB shell : settings put global tether_dun_required 0\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.motorola.faceunlock\",\"label\":\"Moto Face Unlock\",\"description\":\"Unlock your device by simply looking at the display.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.motorola.faceunlock\",\"https://www.ubergizmo.com/2017/03/galaxy-s8-facial-unlock-photograph/\",\"https://www.kaspersky.com/blog/face-unlock-insecurity/21618/\",\"https://www.freecodecamp.org/news/why-you-should-never-unlock-your-phone-with-your-face-79c07772a28/\"],\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.motorola.faceunlocktrustagent\",\"label\":\"Motorola Face Unlock Agent\",\"description\":\"Trust agent is a service that notifies the system about whether it believes the environment of the device is trusted.\\nThe meaning of 'trusted' is up to the trust agent to define.\\nThe system lockscreen listens for trust events, it can change its behaviour based on the trust state of the current user (e.g detection of a trusted face)\",\"web\":[\"https://nelenkov.blogspot.com/2014/12/dissecting-lollipops-smart-lock.html\"],\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.motorola.fmplayer\",\"label\":\"FM Radio\",\"required_by\":[\"com.motorola.android.fmradio\"],\"description\":\"FM Radio for Motorola devices\",\"web\":[\"https://play.google.com/store/apps/details?id=com.motorola.fmplayer\",\"https://beta.pithus.org/report/0113cb712cc43c94f904601120c9100640a65b3043a41b7efe63b340bdae4995\"],\"removal\":\"replace\",\"suggestions\":\"radios\",\"type\":\"oem\"},{\"id\":\"com.motorola.frameworks.singlehand\",\"label\":\"com.motorola.frameworks.singlehand\",\"description\":\"Provide the Single/One hand mode\\nI don't know why frameworks appears in the package name because it's not only the framework.\",\"web\":[\"https://support.motorola.com/us/en/documents/MS116403/\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.motorola.freeform\",\"description\":\"Freeform\\nRequired for window app mode.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.motorola.gamemode\",\"label\":\"Moto Gametime\",\"description\":\"Allows the user to block calls, quick screenshots, float social apps, etc when playing a game.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.motorola.gamemode\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.motorola.genie\",\"label\":\"Device Help\",\"description\":\"Previously Moto Help\\nAn app that checks hardware status and gives the user contacts for support.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.motorola.genie\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.motorola.gesture\",\"label\":\"Gesture navigation tutorial\",\"description\":\"Gesture navigation tutorial added in Android 10.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.motorola.handwritingcalculator\",\"description\":\"Handwriting calculator\\nit's not needed.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.motorola.help\",\"label\":\"Moto feedback\",\"description\":\"Lets you rate your device and share feedback with Motorola.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.motorola.help\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.motorola.help.extlog\",\"label\":\"Extended Log\",\"description\":\"Not sure what it does\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.motorola.hiddenmenuapp\",\"label\":\"HiddenMenu\",\"description\":\"Added in Android 10. Not sure what it does.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.motorola.imagertuning_V2\",\"label\":\"Camera Tuner\",\"description\":\"Applies improvements to the camera hardware so that any app that uses the camera will be improved.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.motorola.imagertuning_V2\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.motorola.imagertuning_lake\",\"label\":\"Imager Tuning\",\"description\":\"Naming convention: imagertuning_[PHONE CODENAME]\\nThis is the custom camera image processing stack on Motorola devices. It's generally important for improving image quality.\\nPlaystore reviews indicate that it slows down the camera app significantly for some users (probably a bug).\",\"web\":[\"https://play.google.com/store/apps/details?id=com.motorola.imagertuning_athene\"],\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.motorola.imagertuning_u\",\"description\":\"This package is associated with Motorola’s image tuning features, specifically designed to enhance or adjust image quality settings on Motorola devices.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.motorola.imagetuning_V2\",\"description\":\"Camera Tuner\\nIt's Camera tuning Chromatix Comparison. I think it's needed for camera app.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.motorola.installer\",\"description\":\"This package is used by Motorola for managing and installing system updates, custom apps, or other Motorola-specific applications.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.motorola.invisiblenet\",\"label\":\"Invisible Net\",\"description\":\"App for Alias ID, Shortcut Installer (most of the apps I have seen are Chinese apps).\\nIt's some kind of a stub application launcher, if you open any of it's activities it goes to the play store or to the browser.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.motorola.iqimotmetrics\",\"description\":\"Hidden privacy policy: network diagnostics data.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.motorola.launcher.secondarydisplay\",\"description\":\"Appears to enable support for a secondary display with Moto's launcher.\\nTrying to remove this packages returns \\\"Failure: package is non-disable\\\".\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.motorola.launcher3\",\"label\":\"Moto App Launcher\",\"description\":\"A default home screen app, provides a layout and display for app icons and listing.\\nWARNING: Do not remove this package if you did not switch to a 3rd-pary launcher.\\nKeep in mind that removing this package will break the `recent apps` button (even from another launcher).\",\"removal\":\"caution\",\"warning\":\"Uninstalling this breaks the Recents screen in across launchers\",\"type\":\"oem\"},{\"id\":\"com.motorola.launcherconfig\",\"label\":\"Google Launcher Config\",\"description\":\"It is a partner customization extension.\\nHas a lot wallpapers in resources.\",\"removal\":\"replace\",\"suggestions\":\"launchers\",\"type\":\"oem\"},{\"id\":\"com.motorola.leanbacklauncher\",\"description\":\"Moto Experience Hub\\nMost people hate this app.\\nhttps://play.google.com/store/apps/details?id=com.motorola.leanbacklauncher\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.motorola.lifetimedata\",\"description\":\"It's most likely the Total Call Timer or more generally it handles info like the date of manufacture of your device, usage time since first boot etc.\\nTotal Call Timer gives you the time you spent calling. I don't know how to access to these info. It may be a hidden menu and may be accessible through the dialer with a special code.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.motorola.livewallpaper3\",\"description\":\"Moto interactive wallpapers\\nResponds to your actions to bring your screen to life.\\nhttps://play.google.com/store/apps/details?id=com.motorola.livewallpaper3\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.motorola.livewallpaper3.prebuilt.chroma_plume\",\"description\":\"Motorola Prebuilt themes Chroma Plume\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.motorola.livewallpaper3.prebuilt.cool_bamboo\",\"description\":\"Motorola Prebuilt themes Cool Bamboo\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.motorola.livewallpaper3.prebuilt.lovely_peach\",\"description\":\"Motorola Prebuilt themes Lovely Peach\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.motorola.livewallpaper3.prebuilt.mysterious_amber\",\"description\":\"Motorola Prebuilt themes Mysterious Amber\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.motorola.livewallpaper3.prebuilt.romantic_wisteria\",\"description\":\"Motorola Prebuilt themes Romantic Wisteria\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.motorola.livewallpaper3.prebuilt.titan\",\"description\":\"Motorola Prebuilt themes Cosmic journey\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.motorola.livewallpaper3.prebuilt.tranquil_whale\",\"description\":\"Motorola Prebuilt themes Tranquil Whale\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.motorola.livewallpaper3.prebuilt.twilight_twist\",\"description\":\"Motorola Prebuilt themes Twilight twist\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.motorola.livewallpaper3.prebuilt.vibrant_sapling\",\"description\":\"Motorola Prebuilt themes Vibrant Sapling\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.motorola.mobiledesktop\",\"description\":\"Ready For\\nConnect to a PC to stream mobile apps and other things.\\nhttps://play.google.com/store/apps/details?id=com.motorola.mobiledesktop\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.motorola.mobiledesktop.core\",\"description\":\"Needed for Ready For (com.motorola.mobiledesktop)\\nConnect to a PC to stream mobile apps and other things.\\nDISABLE this app instead of Uninstall, because of anomalies with lockscreen and clock widget.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.motorola.motcameradesktop\",\"description\":\"Camera Desktop Settings\\nMoto Webcam, video call effects.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.motorola.moto\",\"description\":\"Moto (https://play.google.com/store/apps/details?id=com.motorola.moto)\\nApp providing Moto Actions, Moto Display, and other feature families that let you customize the way you interact with your device. \\nMoto Actions is another app (https://play.google.com/store/apps/details?id=com.motorola.actions). Gestures set with \\\"Moto\\\" prior will continue to work provided \\\"Moto Actions\\\" remains installed.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.motorola.motocare\",\"description\":\"Moto Care was renamed in \\\"Moto Help\\\" and then in \\\"Device Help\\\"\\nProvide support features.\\nhttps://mobile.softpedia.com/blog/Moto-Care-App-Gets-Updated-Now-Called-Motorola-Help-432827.shtml\\nHowever you can both have com.motorola.genie (Device Help) and this package so it's strange.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.motorola.motocare.internal\",\"description\":\"Core stuff for the package above I guess.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.motorola.motocit\",\"description\":\"CQATest\\nCQA = Custom Quality Assurance\\nHidden menu (accessible by typing *#*#2486#*#* in the Moto Dialer) which lets you run hardware tests.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.motorola.motodisplay\",\"label\":\"Moto Display\",\"description\":\"Displays notifications with the screen off (like the Always On Display feature from other OEMs)\",\"web\":[\"https://play.google.com/store/apps/details?id=com.motorola.motodisplay\",\"https://support.motorola.com/uk/en/solution/ms108519\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.motorola.motofpstouch\",\"description\":\"Moto Power Touch.\\nAllows the user to create custom actions depending on how the user presses the power button.\\nhttps://play.google.com/store/apps/details?id=com.motorola.motofpstouch&gl=US\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.motorola.motointelligence\",\"label\":\"Moto Intelligence\",\"description\":\"Not sure what it does\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.motorola.motointelligence.overlay\",\"label\":\"com.motorola.motointelligence.overlay\",\"description\":\"Overlay for 'com.motorola.motointelligence'\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.motorola.motolights\",\"description\":\"Moto Lights\\nPeople recommend to remove it:\\nhttps://xdaforums.com/t/debloat-instructions-for-edge-40-pro-rtwo.4590155/\\nMoto edge lights controller, hard to check this app but it has something to control display brightness in phone.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.motorola.motosignature.app\",\"label\":\"MotoSignatureApp\",\"description\":\"This app has permissions descriptions, lab, game mode launch permissions, audio monitor descriptions.\\nSo it's permissions to system apps?\\nGoogle search shows that it's on some lists that recommend removing this app.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.motorola.motosignature2.app\",\"description\":\"Uses library 'com.motorola.motosignature', perm info to start gif maker, permlab moto trusted apps overlay and permlab monitor input.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.motorola.mototour\",\"description\":\"Moto Tour\\nHelps you how to use motorola phone.\\nhttps://play.google.com/store/apps/details?id=com.motorola.mototour\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.motorola.msimsettings\",\"description\":\"Dual SIM Settings\\nProvides Dual SIM feature.\\n\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.motorola.msimsettings.overlay\",\"description\":\"In code found: 'channel_force_single_sim'. Looks very unused.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.motorola.mykey\",\"description\":\"This package is related to Motorola’s 'MyKey' feature, which is a tool designed to manage key settings and restrictions for device usage.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.motorola.nfc\",\"description\":\"Support for NFC protocol.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.motorola.nfwlocationattribution\",\"description\":\"Useless Carrier Location Access. You can find it in settings location but it's not very useful.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.motorola.odm.camera3\",\"description\":\"Moto camera app?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.motorola.om\",\"description\":\"The package 'com.motorola.om' is associated with Motorola's operational management or device management tools.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.motorola.omadm.service\",\"description\":\"Appears safe to remove.\\nCarrier Provisioning Service\\nProvisioning involves the process of preparing and equipping a network to allow it to provide new services to its users.\\nOMADM  = OMA Device Management\\nBasically, it handles configuration of the device (including first time use), enabling and disabling features provided by carriers.\\nhttps://en.wikipedia.org/wiki/OMA_Device_Management\\nUse case seems very limited : https://www.androidpolice.com/2015/03/10/android-5-1-includes-new-carrier-provisioning-api-allows-carriers-easier-methods-of-setting-up-services-on-devices-they-dont-control/\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.motorola.overlay.googleasi\",\"description\":\"Overlay to Android System Intelligence 'com.google.android.as',\\nremoval means that you cannot use the features of this app probably.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.motorola.overlay.launcher3\",\"description\":\"Useless overlay config default to Launcher3 default launcher Moto (com.motorola.launcher3)\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.motorola.paks\",\"description\":\"ADB: Package Protected.\\nMy Q Paks \\nThird-party application bundles\\nhttps://www.financialmirror.com/2007/10/31/motorola-packs-moto-q-9h-global-smart-device-with-third-party-applications/\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.motorola.paks.notification\",\"description\":\"Notifications from (com.motorola.paks)\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.motorola.paramupdater\",\"description\":\"I am not sure what this app is for.\\nCollects systeminfo, time, has notification about update.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.motorola.personalize\",\"label\":\"Personalise\",\"description\":\"Helps you personalise your themes, icons, fonts, sounds etc...\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.motorola.pgmsystem2\",\"description\":\"Appears safe to remove\\nPGM System\\nI didn't find info about this package. \\nFor Me PGM = Peak Gate Power (for MOSFET transistor) but I'm not convinced it has this meaning here.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.motorola.photoeditor\",\"label\":\"Moto Photo Editor\",\"description\":\"On Motorola phones that feature Cutout mode, you can replace the background of your photos and resize & move selected portions.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.motorola.photoeditor\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.motorola.programmenu\",\"label\":\"Programming Menu\",\"description\":\"Hidden menu (accessible by typing  ##7764726 in the dialer) providing additionnal features for developers.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.motorola.ptt.prip\",\"description\":\"Prip (https://play.google.com/store/apps/details?id=com.motorola.ptt.prip)\\nPush-To-Talk app. Allows to you send calls over any wireless carrier’s 3G or 4G networks or a WiFi connection.\\nIt offers unlimited calling between other users and Nextel phone owners, rather than universal calling credit, \\nand works on a monthly subscription basis.\\nhttps://prip.me/#get\\nNo longer in Android 10 image\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.motorola.rcsConfigService\",\"description\":\"RCS Config Service\\nNeeded for IMS, RCS. WiFi Calling.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.motorola.revoker.services\",\"description\":\"It's another component of setup wizard only used on first-boot setup.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.motorola.safetycenter.resources.overlay\",\"description\":\"Useless overlay to com.google.android.safetycenter.resources\\nNetwork protection, ThinkShield.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.motorola.screenshoteditor\",\"label\":\"Screenshot editor\",\"description\":\"Moto default screenshot app that supports longer screenshots & gif.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.motorola.screenshoteditor\"],\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.motorola.securevault\",\"description\":\"Secure Folder\\nUnnecessary tools to keep device secure.\\nhttps://play.google.com/store/apps/details?id=com.motorola.securevault\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.motorola.securityhub\",\"description\":\"Moto Secure\\nUnnecessary tools to keep device secure.\\nhttps://play.google.com/store/apps/details?id=com.motorola.securityhub\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.motorola.securityhubext\",\"description\":\"This package is related to Motorola's Security Hub, an extension or enhancement for the device’s security features.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.motorola.settings\",\"label\":\"System update\",\"description\":\"Exactly not sure what it does.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.motorola.setup\",\"label\":\"Setup\",\"description\":\"Related to Motorola Account setup (only during first boot?)\\nSafe to remove according to xda users.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.motorola.setup.auto_generated_rro_product__\",\"description\":\"This package is involved in Motorola's setup process, particularly handling automatically generated resources related to the setup of the device.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.motorola.setup.auto_generated_rro_vendor__\",\"description\":\"I found it's \\\"no sim anim\\\". It's another component of Motorola first-boot setup.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.motorola.setup.overlay.amx\",\"description\":\"Useless component of (com.motorola.setup)\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.motorola.setup.overlay.dataenable\",\"description\":\"This package is used during the Motorola device setup process, specifically for managing or presenting settings related to mobile data.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.motorola.setup.overlay.gabuttonrighttop\",\"description\":\"Useless component of (com.motorola.setup)\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.motorola.setup.overlay.pai\",\"description\":\"Useless component of (com.motorola.setup)\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.motorola.setup.overlay.tracfone\",\"description\":\"Useless component of (com.motorola.setup)\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.motorola.slpc_sys\",\"label\":\"Motorola Slpc System\",\"description\":\"Would be weird if it's not related to Motorola Modality Services (https://play.google.com/store/apps/details?id=com.motorola.slpc)\\nHelps your Motorola phone respond more intelligently to motion, phone orientation (e.g. face up/down) and stowed state (e.g in/out-of-pocket).\\nHas a noticeable impact on battery?\\nFYI : It uses location services.\",\"web\":[\"https://forum.xda-developers.com/moto-x-2014/help/location-modality-services-battery-t2982752\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.motorola.smart5g\",\"description\":\"Battery saving for 5G.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.motorola.spaces\",\"description\":\"Family Space\\nLimits time spending on app for kids.\\nhttps://play.google.com/store/apps/details?id=com.motorola.spaces\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.motorola.spectrum.setup.extensions\",\"description\":\"Spectrum Setup\\nSpectrum connectivity services. Useless and it's only setup.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.motorola.sstservice\",\"description\":\"Spatial Sound\\nProvides sst audio effects.\\nI am not sure how to use this app.\\nCode is too small, no activities only some frameworks in classes.dex\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.motorola.systemserver\",\"description\":\"Moto Service Experience, debugging app.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.motorola.systemui.desk\",\"description\":\"DesktopSystemUI\\nit's for desktop maybe when connect to screen phone.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.motorola.telprov\",\"description\":\"It's needed for carrier O2 so it's useless for others.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.motorola.thermalservice\",\"description\":\"Motorola Thermal Service\\nTurns off phone when it's too hot.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.motorola.timeweatherwidget\",\"label\":\"Moto Widget\",\"description\":\"Provides time/weather widget on the home screen.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.motorola.timezonedata\",\"description\":\"/!\\\\ Causes bootloop on Moto G7 Power (Android 9/10)\\nTime Zone Data (https://play.google.com/store/apps/details?id=com.motorola.timezonedata)\\nUpdate timezone when traveling to foreign countries.\\n\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.motorola.wifi.motowifimetrics\",\"description\":\"Useless Wi-Fi daily stats.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.mygalaxy\",\"label\":\"My Galaxy\",\"description\":\"Entertainment hub and life-services application.\\nLets you access videos, music and gaming and gives quick access to services such as cabs, movies, recharge, bill payment, food ordering, travel, hyper local deals and Samsung Care, among others.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.mygalaxy\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.nearme.atlas\",\"label\":\"Secure payment\",\"description\":\"More info needed.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.nearme.browser\",\"label\":\"Browser\",\"description\":\"Default web browser\",\"removal\":\"replace\",\"suggestions\":\"browsers\",\"type\":\"oem\"},{\"id\":\"com.nearme.deamon\",\"required_by\":[\"com.nearme.statistics.rom\"],\"description\":\"Package needed by com.nearme.statistics.rom to run service in background at every boot even though the app has been uninstalled\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.nearme.gamecenter\",\"description\":\"Game Center\\nActs like QooApp that has a game forum, news, etc. Contains trackers.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.nearme.instant.platform\",\"label\":\"Quick App\",\"description\":\"A lot of tracking for demo game ads\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.nearme.romupdate\",\"description\":\"Update Service\\nProbably it's only for notifications. Anyway, better remove it if you want to remove updates too.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.nearme.statistics.rom\",\"label\":\"User Experience Program\",\"description\":\"Collect user data and sends them to Oppo. Intrusive and starts at boot.\",\"web\":[\"https://support.oppo.com/uk/answer/?aid=neu105\",\"https://beta.pithus.org/report/5e06191ac6f8aefd39642f6341ee4897039815f5059dbe093a7bd2fe1e20c038\"],\"removal\":\"caution\",\"warning\":\"Removing it may break the search feature in the settings on some ColorOS versions.\",\"type\":\"oem\"},{\"id\":\"com.nearme.themespace\",\"description\":\"Theme store\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.nearme.themestore\",\"description\":\"Themes store\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.netflix.ninja\",\"description\":\"Netflix app\\nhttps://play.google.com/store/apps/details?id=com.netflix.ninja&hl=en_US\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.nothing.OfflineOTAUpgradeApp\",\"description\":\"Hidden offline OTA update. You can get it by typing in dialer: *#*#682*#*#\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.nothing.agreement\",\"description\":\"Nothing agreement privacy policy. I'm not sure when it will be needed.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.nothing.applocker\",\"description\":\"App locker\\nOptional app for locking apps.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.nothing.appservice\",\"description\":\"Nothing System Service\\nNot sure if you need this.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.nothing.bpf\",\"description\":\"Needed for connection?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.nothing.camera\",\"description\":\"Camera\\nNothing stock camera\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.nothing.cardservice\",\"description\":\"NothingCardService\\nWARNING: breaks Nothing Widgets when switching to dark or light mode.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.nothing.dirac\",\"description\":\"Audio EQ (equalizer). Some 3rd-party music apps can use it to provide you EQ features.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.nothing.dirac.DMP\",\"description\":\"Audio EQ (equalizer). Some 3rd-party music apps can use it to provide you EQ features.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.nothing.enginnerservice\",\"description\":\"Hidden diagnostics without activity frameworks with Qualcomm.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.nothing.experience\",\"description\":\"Useless frameworks and collection data.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.nothing.experimental\",\"description\":\"Experimental features like CONNECT TO TESLA\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.nothing.glyphnotification\",\"description\":\"Needed for glyph notifications?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.nothing.hearthstone\",\"description\":\"Nothing Widgets\\nWidgets that can be found in homescreen.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.nothing.launcher\",\"description\":\"Launcher\\nStock launcher\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.nothing.launcher.overlay.config\",\"description\":\"Useless overlay to recent activity\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.nothing.logkit\",\"description\":\"Hidden tool for logs.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.nothing.proxy\",\"description\":\"It's for battery optimization\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.nothing.smartcenter\",\"description\":\"Nothing X\\nIt's something for earphones and testing.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.nothing.soundrecorder\",\"description\":\"Sound recorder\\nSound recorder app.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.nothing.systemuitool\",\"description\":\"I think it's an important app\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.nothing.thirdparty\",\"description\":\"Breaks the Glyph API, Composer and other apps that rely on the Glyph feature will not work anymore.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.nothing.wallpapersstub\",\"description\":\"Needed for basic wallpapers\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.nothing.weather\",\"description\":\"Weather\\nNothing Weather\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.novatek.novavis\",\"description\":\"Debugs, broadcast id?\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.nt.android.overlay.gmsconfig.safetycenter\",\"description\":\"Useless overlay to nothing gmsconfig safetycenter\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.nt.android.overlay.gmsconfig.settings\",\"description\":\"Useless overlay to nothing gmsconfig settings\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.nt.android.overlay.gmsconfig.settingsprovider\",\"description\":\"Useless overlay to nothing gmsconfig settingsprovider\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.nt.diagswitch\",\"description\":\"Hidden USB Diag Switch, adb diagnostics.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.nt.facerecognition\",\"description\":\"Needed for face recognition.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.nt.grantpermission\",\"description\":\"Hidden grant permissions. You can get it by typing in dialer: *#*#3424*#*#\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.nt.ledlighttest\",\"description\":\"Led Light Test\\nYou can get it by typing in dialer: *#*#533*#*#\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.nt36xxxtouchscreen.deltadiff\",\"description\":\"Audio test frequency(KHz) to com.vivo.bsptest.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.nttdocomo.android.felicaremotelock\",\"description\":\"FeliCa Remote security things, not needed\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.nttouchscreen.getdata\",\"description\":\"Testing things to com.vivo.bsptest.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.nttouchscreen.mptest\",\"description\":\"Novatek MP selftest\\nTesting things to com.vivo.bsptest.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.nuance.swype.emui\",\"description\":\"Huawei Swype functions.\\nIs it the full Swype keyboard or only the Swype function on Huawei keyboard ? \\nNOTE : Nuance company said it would discontinue support of the Swype keyboard app.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oem.autotest\",\"description\":\"Auto Test Server\\nUsed to test the hardware of your device and change hidden settings.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oem.euiccpartnerapp.overlay.retca\",\"description\":\"This package is related to the eUICC (embedded Universal Integrated Circuit Card) partner application, specifically an OEM overlay that deals with eSIM functionality and management.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.oem.logkitsdservice\",\"description\":\"Used by com.oem.oemlogkit, a shady logging app.\\nDoesn't run by default, but can easily be triggered by system apps.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oem.nfc\",\"description\":\"OnePlus NFC tester\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oem.oemlogkit\",\"label\":\"OnePlusLogKit\",\"description\":\"Shady logging app that system apps can use to log WiFi traffic, Bluetooth traffic, NFC activity, GPS coordinates over time, power consumption, modem signal/data details, \\\"lag issues,\\\" and more.\",\"web\":[\"https://thehackernews.com/2017/11/oneplus-logkit-app.html\",\"https://www.bleepingcomputer.com/news/security/second-oneplus-factory-app-discovered-this-one-dumps-photos-wifi-and-gps-logs/\",\"https://web.archive.org/web/20210611122551/https://twitter.com/fs0c131y/status/930773795656396801\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oneplus\",\"description\":\"Oneplus System\\nHandles the Oneplus system framework? Possibly unsafe to disable, but please contribute information about what happens if you do.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.oneplus.accessory\",\"description\":\"Oneplus Link\\nI'm guessing this has to do with connecting to Oneplus accessories, like the Oneplus Buds (wireless earbuds). Might wanna keep it enabled if you use oneplus accessory devices.\\nNoticed no negative effects from disable after weeks of use.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oneplus.account\",\"label\":\"OnePlus Account\",\"description\":\"Enables Oneplus account login on device.\\nProbably handles authentication for Oneplus apps.\\n\",\"web\":[\"https://play.google.com/store/apps/details?id=com.oneplus.account\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oneplus.account.basiccolorblack.overlay\",\"description\":\"Dark theme for Oneplus Account?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.oneplus.account.basiccolorwhite.overlay\",\"description\":\"Light theme for Oneplus Account?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.oneplus.android.cellbroadcast.overlay\",\"description\":\"Wireless emergency alerts Theme pack\\nGuessing it's a pack of themes for the emergency alert UI, based on the name.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.oneplus.aod\",\"description\":\"Always On Display / Ambient Display\\nRuns in the background.\\nWhen enabled in settings it shows clock and notifications when you raise the phone or touch the screen.\\nThis is basically a lower-power lock-screen. It could in theory reduce power draw if you check notifications/clock often as OLED screens draw minimal power showing a mostly black screen(black = pixel off), but in practice the number of times you'll unintentionally trigger it will likely eat up any potential power savings and more. And if your device doesn't have an OLED screen this will draw way more power.\\nMost of these power savings could be applied to your standard lock-screen simply by making your background image completely black.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oneplus.aod.basiccolorblack.overlay\",\"description\":\"Theme overlay for AOD? (Always On Display)\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.oneplus.aod.basiccolorwhite.overlay\",\"description\":\"Theme overlay for AOD? (Always On Display)\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.oneplus.aodnotification.overlay.gold\",\"description\":\"AoD notification gold\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oneplus.aodnotification.overlay.purple\",\"description\":\"AoD notification purple\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oneplus.aodnotification.overlay.red\",\"description\":\"AoD notification red\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oneplus.applocker\",\"description\":\"Encrypts and locks apps behind password access.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.oneplus.appupgrader\",\"description\":\"Built-in App Updates\\nBased on the name I'm guessing it's an upater for built-in Oneplus apps?\\nSeems safe to disable, but only seems to run on boot, so there's little to be gained from disabling.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oneplus.asti\",\"label\":\"OPAI\",\"description\":\"App Prediction Service, SarahService, bindsarah\\nIts code is too difficult to understand, but it looks like AI training.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.oneplus.backuprestore\",\"label\":\"Clone Phone\",\"description\":\"Lets you migrate contacts, text messages, photos, and other data from one device to another.\\nCan also backup data as a compressed archive.\\n\",\"web\":[\"https://play.google.com/store/apps/details?id=com.oneplus.backuprestore\"],\"removal\":\"replace\",\"suggestions\":\"backup_apps\",\"type\":\"oem\"},{\"id\":\"com.oneplus.backuprestore.remoteservice\",\"description\":\"Likely a backend service for OnePlus Switch(com.oneplus.backuprestore).\\nI've never seen it run in the background.\\nProbably safe to disable.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oneplus.brickmode\",\"label\":\"OnePlus Zen Mode\",\"description\":\"Zen Mode helps you put down your phone and enjoy your life.\\nIn Zen Mode you will only be able to take photos and answer calls.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.oneplus.brickmode\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oneplus.bttestmode\",\"label\":\"OnePlus Bluetooth test mode\",\"description\":\"Type *#*#232339#*#* in the OnePlus dialer to access this hidden test menu.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oneplus.calculator\",\"label\":\"Calculator\",\"description\":\"Stock Oneplus Calculator app.\",\"removal\":\"replace\",\"suggestions\":\"calculators\",\"type\":\"oem\"},{\"id\":\"com.oneplus.calculator.basiccolorblack.overlay\",\"description\":\"Theme overlay for Oneplus Calculator app?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.oneplus.calendar.black.overlay\",\"description\":\"Theme overlay for stock Calendar app?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.oneplus.calendar.white.overlay\",\"description\":\"Theme overlay for stock Calendar app?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.oneplus.camera\",\"description\":\"Camera\\nThe stock Oneplus camera app.\\n\",\"removal\":\"replace\",\"suggestions\":\"cameras\",\"type\":\"oem\"},{\"id\":\"com.oneplus.camera.pictureprocessing\",\"description\":\"Is it for image processing?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.oneplus.camera.service\",\"label\":\"OnePlus Camera Service\",\"description\":\"Runs in the background on some phones.\\nNot sure what it does; camera functions fine without it. Could be related to photo backup?\",\"removal\":\"caution\",\"warning\":\"may cause a bootloop when using a custom ROM on Android 14 (in this case, Nameless AOSP). Does not affect users running OxygenOS.\",\"type\":\"oem\"},{\"id\":\"com.oneplus.card\",\"description\":\"Card Package\\nWidget which lets you add membership card in Shelf.\\nYou enter numbers for a club card or something and it'll store it and generate a barcode for you.\\nShelf is a page on your home screen that allows you to take memos, add widgets, gain access to your most-used apps, and get a quick glimpse of the weather. Swipe right (from the left edge of your home screen) to reveal it.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oneplus.card.black.overlay\",\"description\":\"Theme overlay for Oneplus Card package?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.oneplus.card.white.overlay\",\"description\":\"Theme overlay for Oneplus Card package?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.oneplus.carrierlocation\",\"description\":\"Carrier Location Access\\nRuns on boot, but not in the background beyond that.\\nNot sure what this does. Could be related to detecting region to determine which radio frequencies to use?\\nNoticed no ill effects from weeks of having it disabled.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.oneplus.chargingpilar\",\"label\":\"Nearby Charging Stations\",\"description\":\"Geolocates the phone to find OnePlus charging stations nearby. Connects to 'gateway.oneplus.net'.\",\"web\":[\"https://beta.pithus.org/report/8c157eeec2931d3d1140aa8c452d7afa570e04c9d51e6cd5987dbb3ec43df4f9\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oneplus.cloud.basiccolorblack.overlay\",\"description\":\"Theme overlay for some Oneplus Cloud thing?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.oneplus.cloud.basiccolorwhite.overlay\",\"description\":\"Theme overlay for some Oneplus Cloud thing?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.oneplus.collectiondata\",\"description\":\"Collection data to telephony?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.oneplus.commonoverlay.android\",\"description\":\"Needed for notifications? Status_bar?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.oneplus.commonoverlay.com.android.networkstack.inprocess\",\"description\":\"Needed for DHCP hostname?, captive portal HTTP URLs?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.oneplus.commonoverlay.com.android.networkstack.inprocess.cn\",\"description\":\"Needed for DHCP hostname?, captive portal HTTP URLs? Generate_204 Chinese Google?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.oneplus.commonoverlay.com.android.systemui\",\"description\":\"Needed for wellbeing or notifications?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.oneplus.commonoverlay.com.android.wifi.resources\",\"description\":\"Wi-Fi configs?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.oneplus.commonoverlay.com.google.android.networkstack\",\"description\":\"Needed for DHCP hostname?, captive portal HTTP URLs?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.oneplus.commonoverlay.com.google.android.networkstack.cn\",\"description\":\"Needed for DHCP hostname?, captive portal HTTP URLs? Generate_204 Chinese Google?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.oneplus.commonoverlay.com.oneplus\",\"description\":\"Testing things, debugging\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oneplus.communication.data\",\"description\":\"Oneplus call recorder service. Feature accessible from the stock dialer app.\\n\",\"removal\":\"replace\",\"suggestions\":\"call_recorders\",\"type\":\"oem\"},{\"id\":\"com.oneplus.config\",\"label\":\"OPConfig\",\"description\":\"Occasionally runs in the background.\\nGuessing it might handle communication certificates and general network config for Oneplus apps.\\nOnly has INTERNET and RECEIVE_BOOT_COMPLETED permissions.\\n'Tips & Support' will be removed from settings.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.oneplus.contacts\",\"label\":\"OnePlus Contacts\",\"description\":\"The default contacts app in OnePlus\",\"removal\":\"replace\",\"suggestions\":\"contacts\",\"type\":\"oem\"},{\"id\":\"com.oneplus.contacts.basiccolorblack.overlay\",\"description\":\"Theme overlay for Oneplus Contacts?\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.oneplus.contacts.basiccolorwhite.overlay\",\"description\":\"Theme overlay for Oneplus Contacts?\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.oneplus.coreservice\",\"description\":\"Android System\\nImportant system package for Oneplus phones?\\nRuns in the background as part of the system.\\nContains broadcast dispatch and theme handler services.\\nProbably unsafe to disable, but please contribute info about what happens if you do.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.oneplus.cota\",\"description\":\"Carrier Update\\nRuns in the background.\\ncota = Carrier OTA. Handles carrier-specific OTA updates? Probably safe to disable if you didn't get your phone from a carrier; the normal System Update(com.oneplus.opbackup) should handle the OTA updates. I can confirm that I got an OTA notification even with this disabled.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.oneplus.dataoptimization\",\"description\":\"OPDataOptimization\\nDoesn't contain any services and I've never seen it run.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.oneplus.deskclock\",\"label\":\"Clock\",\"description\":\"Clock\\nThe stock Oneplus clock app.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.oneplus.deskclock.black.overlay\",\"description\":\"Theme overlay for Oneplus Clock app?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.oneplus.deskclock.white.overlay\",\"description\":\"Theme overlay for Oneplus Clock app?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.oneplus.diagnosemanager\",\"description\":\"Logging app for diagnosis/troubleshooting when the SIM card state change. Only used on devices running OxygenOS 9 and lower. Runs at boot and triggers when SIM card state change.\\n\\nPithus analysis: https://beta.pithus.org/report/f4c76054795bf55012edf1f60e992b6e339085b9ca2cbe685917a62dd07492c0\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.oneplus.dialer\",\"description\":\"OnePlus Dialer used in OxygenOS 11 and lower.\\nNote: don't forget to download another phone dialer app before removing this package.\\n\",\"removal\":\"replace\",\"suggestions\":\"dialers\",\"type\":\"oem\"},{\"id\":\"com.oneplus.dirac.simplemanager\",\"description\":\"Runs in the background.\\nMain Dirac service.\\nAudio fidelity improvement from the Swedish company Dirac.\\nAttempts to achieve a flat frequency response curve(i.e: fidelity). Should mainly improve speaker fidelity as it can be pre-calculated and stored as a corrective EQ curve, something not possible for most devices connected through the 3.5mm jack; presets only exist for a very limited number of headphones. Change for non-preset 3.5mm jack devices is just a generic EQ curve that could decrease fidelity just as likely as it could increase it.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.oneplus.dirac.simplemanager.basiccolorblack.overlay\",\"description\":\"Theme overlay for Dirac?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.oneplus.dirac.simplemanager.basiccolorwhite.overlay\",\"description\":\"Theme overlay for Dirac?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.oneplus.dm\",\"description\":\"Subscriber Device Management\\nHas only privacy online agreement activity.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oneplus.engmode\",\"description\":\"Some kind of Engineer mode? I've no clue.\\nContains a bunch of activities with \\\"info\\\" in their names.\\nContains an \\\"OpFloatViewService\\\", but I've never seen it run.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.oneplus.faceunlock\",\"description\":\"Face Unlock\\nRuns in the background as part of the system.\\nUnlock your device by simply looking at the display.\\nFace unlock is bad for security and privacy:\\nhttps://www.ubergizmo.com/2017/03/galaxy-s8-facial-unlock-photograph/\\nhttps://www.kaspersky.com/blog/face-unlock-insecurity/21618/\\nhttps://www.freecodecamp.org/news/why-you-should-never-unlock-your-phone-with-your-face-79c07772a28/\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oneplus.factorymode\",\"label\":\"FactoryMode\",\"description\":\"Used in the factory to test devices.\\nType *#808# in the OnePlus dialer to access the hidden menu.\\nPotential security risk: It's possible for an app to enable root access on any device with the APK pre-installed.\\nFor now, this only works in ADB, which requires local access to the device.\",\"web\":[\"https://web.archive.org/web/20211103134620/https://twitter.com/fs0c131y/status/930115188988182531\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oneplus.factorymode.specialtest\",\"description\":\"Engineering Mode Special Test\\nUsed in the factory to test devices.\\nSee com.oneplus.factorymode\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oneplus.filemanager\",\"label\":\"OnePlus File Manager\",\"description\":\"Stock OnePlus file manager app.\\n\",\"web\":[\"https://play.google.com/store/apps/details?id=com.oneplus.filemanager\"],\"removal\":\"replace\",\"suggestions\":\"file_managers\",\"type\":\"oem\"},{\"id\":\"com.oneplus.filemanager.black.overlay\",\"description\":\"Theme overlay for Oneplus File manager app?\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oneplus.filemanager.white.overlay\",\"description\":\"Theme overlay for Oneplus File manager app?\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oneplus.gallery\",\"label\":\"OnePlus Gallery\",\"description\":\"Occasionally runs in the background. Some old versions of the app (like for Oneplus 3 on Android 9) don't run in the background.\\n\",\"web\":[\"https://play.google.com/store/apps/details?id=com.oneplus.gallery\"],\"removal\":\"replace\",\"suggestions\":\"gallery\",\"type\":\"oem\"},{\"id\":\"com.oneplus.gamespace\",\"label\":\"OnePlus Games\",\"dependencies\":[\"com.oplus.cosa\"],\"description\":\"Occasionally runs in the background as part of the system.\\nAllows you to launch your game library, check game stats(such as playtime), activate game overlay features, change performance settings to tweak game/battery performance during gaming.\\nThis is the only way to access the recording buffer functionality (records the last X seconds into RAM and saves them when you tap save), so keep enabled if you need that or any of the other features.\\n\",\"web\":[\"https://play.google.com/store/apps/details?id=com.oneplus.gamespace\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oneplus.gamespace.black.overlay\",\"description\":\"Theme overlay for Game Space?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.oneplus.gamespace.white.overlay\",\"description\":\"Theme overlay for Game Space?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.oneplus.geoiptime\",\"description\":\"Sets the Timezone (it is not an NTP client). Automatically starts at boot and connects to `checkip.amazonaws.com` and `gateway.oneplus.com`.\\n\\nPithus analysis: https://beta.pithus.org/report/5e375a6b8da588a1490e42266f4e33975ce73207d79755a109101bd5fb07cc7c\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.oneplus.iconpack.circle\",\"description\":\"OnePlus Icon Pack - Round (https://play.google.com/store/apps/details?id=com.oneplus.iconpack.circle)\\n\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.oneplus.iconpack.oneplus\",\"description\":\"OnePlus Icon Pack (https://play.google.com/store/apps/details?id=com.oneplus.iconpack.oneplus)\\n\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.oneplus.iconpack.oneplush2\",\"description\":\"OnePlus Hydrogen Icon Pack\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oneplus.iconpack.onepluso2\",\"description\":\"OnePlus Oxygen Icon Pack\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oneplus.iconpack.square\",\"description\":\"OnePlus Icon Pack - Square (https://play.google.com/store/apps/details?id=com.oneplus.iconpack.square)\\n\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.oneplus.ifaaservice\",\"description\":\"IFAA = (China’s) Internet Finance Authentication Alliance\\nProvides biometric authentication for Alipay. Safe to disable if you don't use it.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oneplus.membership\",\"description\":\"Red Cable Club\\nBattery drain if account added.\\nhttps://play.google.com/store/apps/details?id=com.oneplus.membership\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oneplus.minidumpoptimization\",\"description\":\"OPMinidumpOptimization\\nRuns in the background.\\nNot sure what it does, but haven't noticed any negative effects from weeks of having it disabled.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oneplus.mms\",\"label\":\"OnePlus Messages\",\"description\":\"Only used on OnePlus 8 / 8 Pro according to the description.\\n\",\"web\":[\"https://play.google.com/store/apps/details?id=com.oneplus.mms\"],\"removal\":\"replace\",\"warning\":\"Make sure to install another SMS app to not lose that functionality\",\"suggestions\":\"sms\",\"type\":\"oem\"},{\"id\":\"com.oneplus.mms.basiccolorblack.overlay\",\"description\":\"Dark theme overlay for Oneplus Messages app?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.oneplus.mms.basiccolorwhite.overlay\",\"description\":\"Light theme overlay for Oneplus Messages app?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.oneplus.note\",\"label\":\"OnePlus Notes\",\"description\":\"OnePlus Notes app\\n\",\"web\":[\"https://play.google.com/store/apps/details?id=com.oneplus.note\"],\"removal\":\"replace\",\"suggestions\":\"note_taking_apps\",\"type\":\"oem\"},{\"id\":\"com.oneplus.note.black.overlay\",\"description\":\"Dark theme overlay for Oneplus Notes app?\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oneplus.note.white.overlay\",\"description\":\"Light theme overlay for Oneplus Notes app?\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oneplus.nroptimization\",\"description\":\"Optimization telephony?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.oneplus.odmoverlay.android\",\"description\":\"Android System Theme pack\\nGuessing it's a pack of themes for some Oneplus-specific system components, based on the name.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.oneplus.odmoverlay.com.android.settings\",\"description\":\"Settings Theme pack\\nGuessing it's a pack of themes for the settings app, based on the name.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.oneplus.odmoverlay.com.android.systemui\",\"description\":\"System UI Theme pack\\nGuessing it's a pack of themes for some Oneplus-specific system component, based on the name.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.oneplus.odmoverlay.com.oneplus\",\"description\":\"Oneplus System Theme pack\\nGuessing it's a pack of themes for Oneplus-specific system components, based on the name.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.oneplus.opbackup\",\"description\":\"System Update\\nRuns in the background.\\nHandles things related to OTA system updates.\\nSafe to disable, but probably breaks system updates.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.oneplus.opbackup.black.overlay\",\"description\":\"Theme overlay for System Update?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.oneplus.opbackup.white.overlay\",\"description\":\"Theme overlay for System Update?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.oneplus.opbugreportlite\",\"label\":\"BugReportLite\",\"description\":\"Runs in the background. Runs as part of the system, even if disabled? Disabling does remove all RAM usage tho, and hopefully removes access to user data, as disable/uninstall should sever the connection to the Android user account.\\nSilently sends, every 6 hours, battery stats, kernel panics, watchdogs, ANRs and all crashes of your device to Singapore.\",\"web\":[\"https://www.androidpit.com/oneplus-opbugreportlite-data-collection\",\"https://web.archive.org/web/20220520051328/https://twitter.com/fs0c131y/status/933037531066785797\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oneplus.opshelf\",\"description\":\"OnePlus Shelf (https://play.google.com/store/apps/details?id=com.oneplus.opshelf)\\nWidget panel accessible from swiping down on the top-right side of the screen allowing quick access to apps, meteo, spotify, memos...\\n\\nPithus analysis: https://beta.pithus.org/report/a50f166c8c2fae1204650c7af1cb287e20ad5286a89b013ada787f4b1b90fc64.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oneplus.opsports\",\"description\":\"Cricket Scores (https://play.google.com/store/apps/details?id=com.oneplus.opsports)\\nLets you access and follow cricket teams and tournaments.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oneplus.opwlb\",\"description\":\"Work-Life Balance\\nNot present in most Oneplus phones? This functionality might have been superseded by other similar apps, like for example Zen Mode.\\nHaven't tested, but probably safe to disable.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oneplus.opwlb.black.overlay\",\"description\":\"Theme overlay for Oneplus Work-Life Balance?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.oneplus.opwlb.white.overlay\",\"description\":\"Theme overlay for Oneplus Work-Life Balance?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.oneplus.orm\",\"description\":\"Seems to be Oneplus' Memory Management System according to a press-kit/-release they made for Android 11 (multiple sites wrote \\\"ORM Memory Management System\\\" word-for-word).\\nRuns in the background as part of the system. Runs even if disabled? Doesn't use any RAM when disabled tho, vs ~50MB when enabled.\\nSeems safe to disable, haven't noticed any negative effects in weeks of use, but I assume it breaks the \\\"RAM Boost\\\" feature (which is pointless anyway IMO).\\nApk file name: OPOmm, mm = Memory Management?\\nHas 2 permissions: KILL_BACKGROUND_PROCESSES and SET_TIME_ZONE.\\nContains 2 services: OPManagerService and BackgroundCollectorService.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.oneplus.overlay\",\"description\":\"\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.oneplus.productoverlay.android\",\"description\":\"Android System Theme pack\\nGuessing it's a pack of themes for some Android System component, based on the name.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.oneplus.productoverlay.com.android.providers.settings\",\"description\":\"Settings Storage Theme pack\\nGuessing it's a pack of themes for Settings Storage, based on the name.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.oneplus.productoverlay.com.oneplus\",\"description\":\"Oneplus System Theme pack\\nGuessing it's a pack of themes for Oneplus-specific system components, based on the name.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.oneplus.providers.media\",\"description\":\"OnePlus Media Storage\\nRuns in the background.\\nSeems to just add recycle bin functionality to your file management (file browsers). Keep enabled if you like that function. But safe to disable if you don't want it.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oneplus.screenrecord\",\"description\":\"Screen Recorder\\nThe Android 11 screen recorder with some Oneplus modifications.\\nRuns the \\\"SystemUITileService\\\" when you have it as one of the quicksettings tiles, but doesn't seem to run in the background outside of that.\\nDoesn't have an app icon, but you can create a shortcut to it with the Activity Launcher app (to avoid the background service).\\nhttps://f-droid.org/en/packages/de.szalkowski.activitylauncher/\",\"removal\":\"replace\",\"suggestions\":\"screen_recorders\",\"type\":\"oem\"},{\"id\":\"com.oneplus.screenrecord.black.overlay\",\"description\":\"Theme overlay for Oneplus Screenrecord?\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oneplus.screenrecord.white.overlay\",\"description\":\"Theme overlay for Oneplus Screenrecord?\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oneplus.screenshot\",\"label\":\"Screenshot\",\"description\":\"Needed for Power + Volume Down screenshot.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.oneplus.sdcardservice\",\"description\":\"Needed for sdcard?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.oneplus.security\",\"description\":\"Dashboard\\nRuns \\\"WidgetViewService\\\" and \\\"SecureService\\\" in the background.\\nManages widget data access? Noticed no apparent ill effects on disable in Android 9.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.oneplus.security.black.overlay\",\"description\":\"Dark theme overlay for com.oneplus.security?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.oneplus.security.white.overlay\",\"description\":\"Light theme overlay for com.oneplus.security?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.oneplus.ses\",\"description\":\"OPSes\\nApk file name: OPSesAuthentication.\\nContains a \\\"SesService\\\", but I've never seen it run.\\nRelated to Amazon SES?(Simple Email Service) https://aws.amazon.com/ses/\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.oneplus.setupwizard\",\"description\":\"The Oneplus portion of the first-boot setup.\\nRuns on boot, but not in the background beyond that.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oneplus.simcontacts\",\"description\":\"SimContacts Manager\\nRuns in the background. Manages contacts and sync to SIM? Noticed no apparent ill effects on disable in Android 9.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oneplus.simcontacts.basiccolorblack.overlay\",\"description\":\"Dark theme overlay for Oneplus SimContacts Manager app?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.oneplus.simcontacts.basiccolorwhite.overlay\",\"description\":\"Light theme overlay for Oneplus SimContacts Manager app?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.oneplus.skin\",\"description\":\"\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.oneplus.sms.smscplugger\",\"description\":\"Probably related to SMS based on the name?\\nContains no services and I've never seen it run.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.oneplus.sound.tuner\",\"description\":\"Dolby Atmos\\nRuns in the background as part of the system. Runs even if disabled.\\nSound tuning for Atmos. Breaks the Dolby Atmos sound settings menu if disabled.\\nCould in theory increase loudspeaker fidelity as it can be pre-calculated and stored as a corrective EQ curve, something not possible for headphones (they'd need a unique preset for each pair of headphones).\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.oneplus.soundrecorder\",\"description\":\"Recorder\\nOnePlus sound recording app.\\nRequires turning on \\\"Allow modifying system settings\\\" to use for some reason? Probably tied to recording phone-calls.\",\"removal\":\"replace\",\"suggestions\":\"audio_recorders\",\"type\":\"oem\"},{\"id\":\"com.oneplus.soundrecorder.black.overlay\",\"description\":\"Theme overlay for Soundrecorder app?\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oneplus.soundrecorder.white.overlay\",\"description\":\"Theme overlay for Soundrecorder app?\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oneplus.store\",\"description\":\"OnePlus Store\\nOffers getting favorites OnePlus phones in good price.\\nhttps://play.google.com/store/apps/details?id=com.oneplus.store\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oneplus.telephonyoptimization\",\"description\":\"OPTelephonyOptimization\\nContains a service with the same name, but I've never seen it run.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.oneplus.twspods\",\"description\":\"OnePlus Buds (https://play.google.com/store/apps/details?id=com.oneplus.twspods)\\nCompanion app for Oneplus Buds. For updating firmware and changing settings.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oneplus.vendoroverlay.android\",\"description\":\"Overlay to extra kbytes adjust?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.oneplus.vendoroverlay.com.android.providers.settings\",\"description\":\"Default backup transport Google. Not needed for backup\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oneplus.vendoroverlay.com.android.systemui\",\"description\":\"It has nothing in the code.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.oneplus.vendoroverlay.com.oneplus\",\"description\":\"Config to overheat?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.oneplus.vendoroverlay.com.oneplus.wifiapsettings\",\"description\":\"OP_white_mode?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.oneplus.wallpaper\",\"description\":\"Pack of live wallpapers from Oneplus.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.oneplus.wifiapsettings\",\"description\":\"Wi-Fi Access Point Settings?\\nRuns on boot.\\nNoticed no change after disabling; Wi-Fi and related menus still seem fully functional.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.oneplus.wifiapsettings.basiccolorblack.overlay\",\"description\":\"Dark theme for Wi-Fi Access Point Settings?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.oneplus.wifiapsettings.basiccolorwhite.overlay\",\"description\":\"Light theme for Wi-Fi Access Point Settings?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.onyx.aiassistant\",\"description\":\"Onyx Boox AI Assistant. Safe to remove\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.onyx.android.ksync\",\"description\":\"Ksync app. UNSAFE to remove because it will crash the Onyx launcher but you can safely disable it\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.onyx.android.production.test\",\"description\":\"Test app enabled by clicking 5 times on the Onyx Version, it contains tests for screen quality\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.onyx.appmarket\",\"description\":\"The Onyx Store app, you will not have any other way to install app if you uninstall it\\nYou will need to install an alternative store via adb\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.onyx.calculator\",\"description\":\"The Onyx calculator app\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.onyx.clock\",\"description\":\"The Onyx Clock app\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.onyx.dict\",\"description\":\"The Onyx Dict app\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.onyx.easytransfer\",\"description\":\"Onyx Easy Transfer app\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.onyx.gallery\",\"description\":\"Onyx Gallery app\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.onyx.igetshop\",\"description\":\"Onyx iGetShot app, UNSAFE to remove because it will crash the Onyx Launcher but safe to DISABLE\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.onyx.kime\",\"description\":\"Onyx Kime app\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.onyx.kreader\",\"description\":\"Onyx KReader app, UNSAFE to remove because it will crash the Onyx Launcher can be safely disabled.\\nRemember to load another reader app\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.onyx.latinime\",\"description\":\"The Onyx Keyboard. Removing it will leave withe google STT keyboard.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.onyx.mail\",\"description\":\"Onyx Mail app\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.onyx.musicplayer\",\"description\":\"Onyx Music Player app\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.onyx.voicerecorder\",\"description\":\"Onyx Voice Recorder app\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oplus.account\",\"description\":\"Account Center. Required for most OnePlus features. Removal gets rid of Login with OnePlus Account notification.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.oplus.aiunit\",\"description\":\"AIUnit\\nSystem service related to the intelligence function. It's safe to remove but also breaks the Smart Cutout, AI Editor, and potentially other gallery features.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.oplus.android.overlay.gmsconfig.common\",\"description\":\"Overlay to vendor required apps?\\nTheres google apps and some not important oppo apps on the lists, not needed.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oplus.android.overlay.modules.documentsui\",\"description\":\"Useless overlay to documentsui bools.xml: is_launcher_enabled true\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oplus.aod\",\"label\":\"Aod\",\"description\":\"Multiple sources say that AOD doesnt work without tons of extra services, but on some devices it works without extra services\",\"web\":[\"https://droidwin.com/remove-bloatware-debloat-oneplus-10-pro-no-root/#OnePlus_10_Pro_List_of_Bloatware_Apps\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oplus.appdetail\",\"description\":\"Secure app installation\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oplus.appplatform\",\"label\":\"App Services\",\"description\":\"Might be renamed package of com.heytap.appplatform which is related to Oppo's Heytap account services. Provides a RomUpdateService. Probably not safe to remove.\",\"web\":[\"https://beta.pithus.org/report/2025ceb69d9379a01771de71ff00051eb0f0c7f44226a72c2066db9649b6dcd2\"],\"removal\":\"unsafe\",\"warning\":\"May cause a bootloop on some phones if removed.\",\"type\":\"oem\"},{\"id\":\"com.oplus.apprecover\",\"label\":\"Recover system apps\",\"description\":\"Provides the ability to restore system apps through settings.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oplus.athena\",\"label\":\"Athena\",\"description\":\"OnePlus background process manager. Removing it will solve the notification delay you can have but will disable the virtual ram expansion feature (swap RAM to disk) and the 'close all' button in the 'recent apps' page.\\nRemoving this app may deteriorate battery performance.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.oplus.atlas\",\"label\":\"atlasService\",\"description\":\"Separate app sound and individual app volumes.\",\"web\":[\"https://beta.pithus.org/report/6d0f9433431cd34a8e9aaef99b329b3623118a1699033be36032f64653dab3d0\"],\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.oplus.audio.effectcenter\",\"description\":\"AudioEffectCenter\\nDolby support for Chinese apps and some Google. It's so bloated.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oplus.battery\",\"description\":\"Battery\\nNeeded for power managment in settings?\\nhttps://xdaforums.com/t/how-to-fix-oneplus-11-thermal-throttling.4560085/post-89255314\\nBetter test it.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.oplus.batterywarning\",\"description\":\"Battery warning.\\nUses accessbility, GPS and Wi-Fi.\",\"required_by\":[\"com.oneplus.gamespace\"],\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.oplus.blacklistapp\",\"description\":\"Block & filter\\nCall blocking app that's tied with device caller app, contains fuction to look caller location on Google Maps, potentially untrusted.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.oplus.blur\",\"description\":\"All the blur effects in the system UI will be removed and replaced with completely transparent if you remove this package.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.oplus.bttestmode\",\"description\":\"BTtestmode\\nBluetooth SAR Signaling, Scene Test\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oplus.camera\",\"label\":\"Camera\",\"description\":\"Stock Oppo/Oneplus camera app\",\"removal\":\"replace\",\"suggestions\":\"cameras\",\"type\":\"oem\"},{\"id\":\"com.oplus.cast\",\"description\":\"Screencast\\nPhone casting (casting phone screen to other devices).\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.oplus.cosa\",\"label\":\"App Enhancement Services\",\"required_by\":[\"com.oneplus.gamespace\"],\"description\":\"If enabled, connects to OPPO servers (icosa-service-eu.allawnos.com) every time a new app is installed. Seems to be mostly focused on gaming performance optimisation according to the settings description:\\n'[...] a service that optimises phone performance for specific apps and game scenarios. [...] frame rates, battery usage, touch sensitivity, network connection, vibration and gameplay assistance features.'\\n\\nCan be disabled via hidden setting (Settings -> Search 'App Enhancement Services' -> App Enhancement Services).\\nCannot be uninstalled but it can be disabled.\",\"web\":[\"https://beta.pithus.org/report/f55e935357865f4647e59c98afb5a3a46aba22a48844d80d2819d122781e3fde\"],\"removal\":\"caution\",\"warning\":\"Removing this package prevents the OnePlus Game Center to detect games.\",\"type\":\"oem\"},{\"id\":\"com.oplus.cota\",\"description\":\"Carrier software updater?\\nLooks like software updater for carrier phones.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.oplus.crashbox\",\"label\":\"CrashBox\",\"description\":\"Sends system failure data to developers. Automatically runs at boot.\\n\\nPithus analysis: https://beta.pithus.org/report/6031048af7434e9cfe3435244dd105ac70e3bfe1f25ecdcca9b2a40b356590a2\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oplus.customize.coreapp\",\"description\":\"Useless frameworks\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oplus.deepthinker\",\"label\":\"Intelligent Services\",\"description\":\"Seems to open some common apps in the background, which may increase power consumption.\",\"removal\":\"caution\",\"warning\":\"Removing it on ColorOS 12.0 or above will cause the battery menu to not show the power consumption curve. This can cause a bootloop.\",\"type\":\"oem\"},{\"id\":\"com.oplus.dmp\",\"description\":\"Deactivate Traffic Management\\nFusion search service?\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oplus.eid\",\"description\":\"Eid-Service\\nIt's something about card chips or online identity? Useless. China.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oplus.encryption\",\"description\":\"Private Safe\\nAfter uninstalling, the option to use the file safe in the privacy settings disappears. There is also a section left in the settings that does nothing when clicked.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oplus.engineercamera\",\"description\":\"EngineerCamera\\nTesting camera things.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oplus.engineermode\",\"description\":\"EngineerMode\\nTesting phone things(like audio, bluetooth, etc.).\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oplus.engineermodeforflipkart\",\"description\":\"Engineermode2\\nThis is app for get flipkartAddress and ShowSarImeiReceiver.\\nI found some info: This phone is part of Flipkart Smart Plan and not eligible for release till any instant advance amount availed is repaid.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oplus.engineernetwork\",\"description\":\"EngineerNetwork\\nTesting network things.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oplus.exserviceui\",\"description\":\"Gesture Motion Services\\nIs related to gesture navigation 'com.oplus.gesture'.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.oplus.exsystemservice\",\"label\":\"System Service\",\"description\":\"Lots of permissions. The screenshot function will stop working when the app is disabled.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.oplus.eyeprotect\",\"description\":\"Eye protection mode\\nSafe to remove if you dont use this feature. It can be found in the settings.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oplus.framework.rro.oneplus\",\"description\":\"A runtime resource overlay (RRO) is a package that changes the resource values of a target package at runtime. For example, an app installed on the system image might change its behavior based upon the value of a resource. Rather than hardcoding the resource value at build time, an RRO installed on a different partition can change the values of the app's resources at runtime.\\nRROs can be enabled or disabled. You can programmatically set the enable/disable state to toggle an RRO's ability to change resource values. RROs are disabled by default (however, static RROs are enabled by default).\\nhttps://source.android.com/docs/core/runtime/rros\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.oplus.framework_bluetooth.overlay\",\"description\":\"Needed to bluetooth?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.oplus.games\",\"label\":\"Game Assistant\",\"description\":\"Games (https://play.google.com/store/apps/details?id=com.oplus.games)\\nOccasionally runs in the background as part of the system.\\nAllows you to launch your game library, check game stats(such as playtime), activate game overlay features and performance settings to tweak game/battery performance during gaming.\\nThis is the only way to access the recording buffer functionality (records the last X seconds into RAM and saves them when you tap save), so keep enabled if you need that or any of the other features.Note: new package name of com.oneplus.gamespace (since the merge between Oppo and OnePlus. Oplus = Oppo+OnePlus\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oplus.gesture\",\"description\":\"Always-on screen gestures.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.oplus.hamlet\",\"description\":\"Vision Enhance\\nUseless things about color maybe to wallpaper?\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oplus.healthservice\",\"description\":\"healthservice\\nSome health function, needed for correct work of fitness trackers and pedometer from realme. When deleted, it does not seem to affect the operation of the phone.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oplus.interconnectcollectkit\",\"description\":\"InterconnectCollectKit\\nIt may have something to do with the device's fast connection by name. BUT I see only it collects system logs and it has something to com.heytap.accessory.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oplus.kekepay\",\"description\":\"Chinese pay service? Safe to remove but no documentation found online\\n[APK NEEDED]\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oplus.keyguard.clock.base\",\"description\":\"The clock style available in the lock screen and the theme manager.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.oplus.keyguard.clock.gallery\",\"description\":\"The clock style available in the lock screen and the theme manager.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.oplus.keyguard.clock.graffiti\",\"description\":\"The clock style available in the lock screen and the theme manager.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.oplus.keyguard.clock.magazine\",\"description\":\"The clock style available in the lock screen and the theme manager.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.oplus.lfeh\",\"label\":\"OplusLFEHer\",\"description\":\"Seems to be related to the the logging suite.\\n\\nPithus analysis: https://beta.pithus.org/report/0542dbdbe10fd3a868ea497ec92670619670f574bbce37d949975dc109cd316f\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oplus.linker\",\"description\":\"OPSynergy\\nUsed for the Synergy app to link your phone to your PC (It doesn't work well beyond controlling your phone from your PC).\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oplus.location\",\"description\":\"Chinese location. Have China MCC. Useless\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oplus.locationproxy\",\"description\":\"Carrier Location Services\\nExtra location telemetry, not related to any GPS functions.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oplus.logkit\",\"label\":\"Feedback\",\"description\":\"Logs service and bug reporting app\\nSafe to remove if you don't report bugs to OEM\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oplus.mediacontroller\",\"description\":\"Media Controller.\\nResponsible for the Dynamic Island feature for music applications and showing the 'Now playing' notification on lockscreen.\",\"dependencies\":[\"com.oneplus.account\",\"com.oplus.ocs\",\"com.oplus.onet\",\"com.oplus.metis\",\"com.oplus.statistics.rom\",\"com.coloros.assistantscreen\",\"com.coloros.scenemode\"],\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.oplus.melody\",\"description\":\"Wireless Earphones\\nWireless headset advanced configuration related (after uninstallation some Bluetooth headset setting options will be missing items, if you do not have headset setting problems, it is recommended to uninstall)\\nhttps://play.google.com/store/apps/details?id=com.oplus.melody\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.oplus.metis\",\"label\":\"Metis\",\"description\":\"Provides system functions such as scene recognition, smart reminders, and device environment awareness. For example, it can identify nearby TVs for seamless connection or deliver contextually intelligent reminders. It operates quietly in the background.\",\"removal\":\"caution\",\"warning\":\"If removed, live alerts will only work when changing volume modes and personal hotspot.\",\"type\":\"oem\"},{\"id\":\"com.oplus.multiapp\",\"label\":\"App Cloner\",\"description\":\"App Cloner. Allows to clone an app. Have access to all installed apps. Is bundled with OnePlus analytics\\n\\nPithus analysis: https://beta.pithus.org/report/8a1d0783debb405ebadb3fc52507de5f69ecb55f499732b7331dac74ad69ffd7\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.oplus.nas\",\"description\":\"NetworkAssistSys\\nNeeded for network I guess by dialogs found in code. Has location & phone permission, can read your call logs. Runs in background. After disabling, no issues occured (OxygenOS 14, OnePlus 11).\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.oplus.ndsf\",\"description\":\"DSF\\nProvides the ability to authenticate your identity when you connect your device.\\nFor the 'Device Connection Security Service' to work properly, it needs to collect\\ninformation about your HeyTap account to support automatic connection to different\\ndevices with the same account and connect to the Internet to verify the security of your HeyTap account.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.oplus.nhs\",\"description\":\"NetworkHealthService\\n(Uninstallation may cause the power saving mode optimization option of turning off 5G to be disabled, only briefly, after which it will automatically return to 5G) needs more testing.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.oplus.notificationmanager\",\"description\":\"Notification management will not work when uninstalled/disabled.\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.oplus.nrMode\",\"description\":\"OplusNrModeControl\\nRequired for Smart 5G.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.oplus.obrain\",\"description\":\"OBrain\\nLog component, domestic special, the key to a MIDAS service, looking at the dex content is also to catch log.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oplus.oca\",\"description\":\"Has something related to wallet smart card\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oplus.ocar\",\"description\":\"Car+\\n Related to Oppo's car app [APK NEEDED]\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oplus.ocloud\",\"description\":\"Its not about cloud but a lot logs.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oplus.ocs\",\"description\":\"OpenCapabilityService\\nChinese unique identifier privacy hazard.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oplus.olc\",\"description\":\"Olc\\nLogger, a new appearance in F.05, the domestic special, and all say that they are log core.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oplus.omoji\",\"description\":\"Omoji\\nAvatar editing app.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oplus.onet\",\"description\":\"ONet\\nUseless frameworks. To secure keyboard, grant permissions. It's not needed.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oplus.onetrace\",\"description\":\"OneTrace\\nLogging component, may be used for feedback toolkit log capture, domestic specials.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oplus.oscenter\",\"description\":\"Useless frameworks security.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oplus.ota\",\"description\":\"Software update\\nProvides System Updates.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.oplus.ovoicemanager\",\"description\":\"Voice assistant related\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oplus.owkservice\",\"description\":\"Weird app that has time sync and start/stop Monitor Wifi Connectivity, also has oplus statistics component to tracking events.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.oplus.padconnect\",\"description\":\"It has pad settings and multi-screen connect.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.oplus.pantanal.ums\",\"description\":\"Ubiquitous Manager Service\\nA service required for Fluid Cloud (Dynamic Island clone) feature in OxygenOS/ColorOS/RealmeUI (Android 14). Runs in background. After disabling, no issues occurred but there's a little empty space between clock and recent notification icons on the right.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.oplus.pay\",\"label\":\"Secure payment\",\"description\":\"Lets you pay with your phone. Privacy issue aside, you should probably not trust their security.\\nSome users cannot uninstall this app.\",\"web\":[\"https://www.bitdefender.com/blog/hotforsecurity/hackers-attack-oneplus-again-this-time-stealing-customer-details\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oplus.phonenoareainquire\",\"description\":\"Number Origin\\nNot yet uninstalled but is related to phone calling function, need to check deeply...\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.oplus.portrait\",\"description\":\"Canvas\\nAn additional feature for AOD that allows you to further personalize the disabled screen. If not used, you can delete it.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oplus.postmanservice\",\"description\":\"Calibration, scan QR code test\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oplus.powermonitor\",\"description\":\"Power monitor\\nLogging component to upload temperature control logs.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oplus.pscanvas\",\"description\":\"Open Canvas\\nSplit-screen feature, see:\\nhttps://community.oneplus.com/thread/1484307668276346883.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.oplus.qualityprotect\",\"label\":\"QualityProtect\",\"description\":\"Probably Oppo/OnePlus analytics, no effects after disabling/deleting\",\"web\":[\"https://forum.xda-developers.com/t/list-of-applications-that-can-be-uninstalled-with-adb-commands.4392267/post-86573217\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oplus.romupdate\",\"description\":\"Update Service\\nIf you wanna remove it to keep ram, it's a bad idea. Better remove com.oplus.ota too if you don't plan to update system.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.oplus.safecenter\",\"label\":\"Security center\",\"description\":\"Enhances privacy features on Oneplus/Oppo devices\",\"web\":[\"https://forum.xda-developers.com/t/the-oneplus-10-pro-debloat-thread.4503969/page-2#post-87920315\"],\"removal\":\"caution\",\"warning\":\"Breaks app lock feature when disabled, all other features work. Uninstalling on OxygenOS 15 makes the phone unusable!\",\"type\":\"oem\"},{\"id\":\"com.oplus.sauhelper\",\"description\":\"SAUHelper\\nIt's very much a placeholder app with no real functionality, but it can't be uninstalled or deactivated, and it can be SUSPENDED.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oplus.screenrecorder\",\"description\":\"Screenrecorder\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.oplus.screenshot\",\"label\":\"Screenshot\",\"description\":\"Enables quick settings screenshot option, the power+volume down screenshot feature works without it\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oplus.securitykeyboard\",\"label\":\"Secure Keyboard\",\"description\":\"Secure Keyboard\\nKeyboard that appears only when typing a password on apps and webpages, if enabled on Keyboard and Input settings\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oplus.securitypermission\",\"description\":\"Permission manager\\nIf removed, in some players (and not only), it will not be possible to enable picture-in-picture capability due to lack of customization: Settings -> Manage apps -> Top of other apps.\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.oplus.smartengine\",\"description\":\"It appears to be an app used for testing, no internet access, very few intents, shouldn't have self-started, should run on demand. Some people have reported it as a support component for speedcards, some speedcards won't load after uninstalling.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.oplus.sos\",\"label\":\"Emergency SOS\",\"description\":\"Emergency Alert service by clicking power button 5 times. It will automatically call contacts (and/or send a SMS) you designated as emergency contacts\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.oplus.statistics.rom\",\"description\":\"User Experience Program\\nIntrusive telemetry. Runs at boot and constantly stays in background\\n\\nPithus analysis: https://beta.pithus.org/report/7720549a5b4bc305a15e19b3e17ba6857a52e6e12db94006677c59f2fad84331\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oplus.stdid\",\"label\":\"StdID\",\"description\":\"StdID\\nNeeded for tracking battery usage on per app basis. Dependency for GameSpace\\n\\n [MORE INFO NEEDED / APK NEEDED]\",\"removal\":\"replace\",\"required_by\":[\"com.oneplus.gamespace\",\"com.coloros.gamespace\"],\"type\":\"oem\"},{\"id\":\"com.oplus.stdsp\",\"description\":\"Device Security Service\\nit's a basic service module that helps users discover security risks in their devices and generate appropriate security policies. Detect xposed, and log suite related, needless to say, deactivate.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oplus.subsys\",\"description\":\"Its app for virtual communication. Depends on 'com.oplus.virtualcomm'.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.oplus.synergy\",\"label\":\"HeySynergy\",\"description\":\"HeySynergy\\nProvides the screencasting feature and OPPO's PC Connect (https://connect.oppo.com/). Don't bother downloading 'PC Connect Desktop' if the 'Phone Connect' Quick Settings tile isn't available on your phone.\\n\\nPithus analysis: https://beta.pithus.org/report/16d9ea536683291fbffe46dedd3c655379b5fcfdb473ec1cab5290cf5af27fba\",\"removal\":\"replace\",\"dependencies\":[\"com.heytap.mcs\",\"com.heytap.accessory\"],\"type\":\"oem\"},{\"id\":\"com.oplus.themestore\",\"description\":\"Theme Store\\nTo change fonts, wallpapers, etc. of your device. Note that you can download but you can't apply unless you have registered for/sign in with HeyTap account.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oplus.thirdkit\",\"description\":\"Compatibility problem solving\\nThird party related.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oplus.trafficmonitor\",\"label\":\"OnePlus Data usage\",\"description\":\"Oneplus traffic monitor (monthly data usage, etc).\",\"removal\":\"caution\",\"warning\":\"If removed, the 'Data Usage' option under 'Mobile network' will not work. App Info screen's 'Data usage' option will also disappear.\",\"type\":\"oem\"},{\"id\":\"com.oplus.uiengine\",\"description\":\"Needed for themes? I found a lot of gameloading things, Proguard?, lists of apps idk for what. Remove it not bricks anything probably.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.oplus.uxdesign\",\"description\":\"Wallpapers & style\\nNeeded for changing wallpaper.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.oplus.vdc\",\"description\":\"It's an app used to convert nearby devices into virtual hardware resources for the central device. Require internet to transfer data across devices.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.oplus.viewtalk\",\"description\":\"ViewTalk\\nApplication for recognizing text in an image and reading it out loud.\\nDid not figure out how it works.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.oplus.vip\",\"description\":\"My OPPO\\nhttps://play.google.com/store/apps/details?id=com.oplus.vip\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oplus.virtualcomm\",\"description\":\"It's probably virtual communications.\\nAlso about these it's in the code.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.oplus.wallpapers\",\"description\":\"Wallpapers\\nNeeded for wallpapers.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.oplus.wifibackuprestore\",\"label\":\"WifiBackupRestore\",\"description\":\"Lets you backup your wifi credentials to the cloud and possibly local wifi access point backups with local backup and restore feature. This app has obviously access to your wifi credential and have the INTERNET permission.\\n\",\"web\":[\"https://beta.pithus.org/report/76e43cf4dc55452f39d9b6117074f4072189d3c8ad9cb295a86e49438545f7aa\"],\"removal\":\"caution\",\"warning\":\"Removing this package may have similar effects of removing `com.coloros.wifibackuprestore` as this could also break local wifi credential backups functionality without it. However, it's effects is only tested with ColorOS devices with similar package before Oneplus merge.\",\"type\":\"oem\"},{\"id\":\"com.oplus.wifitest\",\"description\":\"wifitest\\nJust a testing mode accessed through phone dialing code.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oplus.wirelesssettings\",\"description\":\"DCSSDK\\nWireless settings.\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.opos.ads\",\"description\":\"Chinese ads click tracking\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oppo.atlas\",\"description\":\"Useless frameworks\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oppo.bttestmode\",\"description\":\"Test BLE Tx and Rx channel\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oppo.camera\",\"description\":\"Camera\\nOppo stock camera app\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.oppo.criticallog\",\"description\":\"I found logs in code. This app means nothing.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oppo.ctautoregist\",\"description\":\"Has something related to IMS SMS\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.oppo.customize\",\"description\":\"Only Hello world! found in app also things to com.orange.aura.oobe\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oppo.em5g\",\"description\":\"EM NR5G\\n5G Disable Mode, Probably needed for mobile data internet.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.oppo.engineermode\",\"description\":\"Engineer mode (hardware tests), uses a dialer code, safe to disable\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.oppo.engineermode.camera\",\"description\":\"Related to com.oppo.engineermode. This application likely doesn't work without that app.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.oppo.engineermode.network\",\"description\":\"Related to com.oppo.engineermode. This application likely doesn't work without that app.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.oppo.fingerprints.fingerprintsensortest\",\"description\":\"Fingerprint sensort test\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oppo.freefallingmonitor\",\"description\":\"I found only: Hello World!. This app means nothing.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oppo.gmail.overlay\",\"description\":\"I found in code only words Vodafone email, email setup wizard. Not needed overlay\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oppo.healthservice\",\"description\":\"Some health function, needed for the correct work of fitness trackers and pedometers from realme. When deleted, it does not seem to affect the operation of the phone.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oppo.instant.local.service\",\"description\":\"A lot of tracking for demo game ads\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oppo.launcher\",\"description\":\"OPPO Home\\nOppo stock launcher\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.oppo.lfeh\",\"description\":\"OppoLFEHer\\nDCS service, another thing related to scanning. Bloated\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oppo.localservice\",\"description\":\"It's an app without activities, and in the code, I found it's for Set Mode Daemon Point, but how can we use that? I guess it's for testing, so remove it.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oppo.locationpicker\",\"description\":\"Location works without.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oppo.logkit\",\"description\":\"Not sure what it does.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oppo.logkitsdservice\",\"description\":\"Hidden logs hardware without activities.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oppo.logkitservice\",\"description\":\"Probably same as \\\"com.oem.oemlogkit\\\", which is a shady logging package on Oneplus devices.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oppo.market\",\"description\":\"Oppo App Market\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oppo.mimosiso\",\"description\":\"Empty app. I only found: hello world!\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oppo.multimedia.dolby\",\"description\":\"Oppo Dolby service equalizer, but only for Chinese apps\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oppo.music\",\"label\":\"Music\",\"description\":\"Oppo Music app\",\"web\":[\"https://play.google.com/store/apps/details?id=com.oppo.music\"],\"removal\":\"replace\",\"suggestions\":\"music_apps\",\"type\":\"oem\"},{\"id\":\"com.oppo.nw\",\"description\":\"RadioInfo\\nOnly has radioinfo activity. Not needed\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oppo.operationManual\",\"description\":\"Oppo User Manual\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oppo.oppopowermonitor\",\"label\":\"Power monitor\",\"description\":\"Battery monitoring\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oppo.ota\",\"description\":\"Software update\\nSoftware update OTA\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.oppo.ovoicemanager\",\"description\":\"Voice wake-up manager?\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oppo.partnerbrowsercustomizations\",\"description\":\"Oppo Bookmarks\\nOppo default browser customization. Injects Oppo bookmarks\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oppo.qualityprotect\",\"description\":\"Useless logs\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oppo.quicksearchbox\",\"description\":\"Single swipe from top to bottom search that has lots of Chinese in it\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oppo.resmonitor\",\"description\":\"App has only icon and means nothing.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oppo.rftoolkit\",\"description\":\"Monitors the broadcast action events (BOOT_COMPLETED)\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.oppo.securepay\",\"description\":\"Payment Protection\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oppo.smartvolume\",\"description\":\"This app means nothing. There's only logs.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oppo.sos\",\"description\":\"Emergency Alert service by clicking power button 5 times. It will automatically call contacts (and/or send a SMS) you designated as emergency contacts\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.oppo.tzupdate\",\"description\":\"Useless time zone calibration\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oppo.usageDump\",\"description\":\"After-sales service assistance tools\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oppo.webview\",\"description\":\"Oppo WebView enables Android apps to display web content within the app itself, based on Chrome.\",\"removal\":\"replace\",\"warning\":\"Make to have another Webview before uninstalling it or some apps may not work properly.\",\"suggestions\":\"webviews\",\"type\":\"oem\"},{\"id\":\"com.oppo.wifirf\",\"description\":\"Wifi Rf Test\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oppo.wifitest\",\"description\":\"Wi-Fi RF, RX test\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.oppoex.afterservice\",\"description\":\"Have something to E-warranty card Chinese.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.osp.app.signin\",\"label\":\"Samsung account\",\"description\":\"Lots of trackers in this app.\\nHas a huge list of permissions. It is an essential app for a lot of Samsung apps (which will be removed with the default selection in this list)\",\"web\":[\"https://gitlab.com/W1nst0n/universal-android-debloater/-/issues/39\"],\"removal\":\"caution\",\"warning\":\"Settings app will crash on Android 11. Should work fine in other versions of Android.\",\"type\":\"oem\"},{\"id\":\"com.payjoy.access\",\"label\":\"PayJoy Access\",\"description\":\"Access is PayJoy's firmware product which OEMs optionally use to enable automatic setup (“provisioning”) and device management to enable PayJoy's Lock to work “out of the box” to minimize the number of steps for the user and store clerk to get started.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.payjoy.permission\",\"description\":\"It's for lock device and probably safe mode.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.policydm\",\"description\":\"Samsung security policy update (https://play.google.com/store/apps/details?id=com.policydm)\\nUpdatable policy files designed to increase android security and detect malicious behaviour.\\nHas nothing to do with OTA updates or Android Security patches.\\nCan be removed without issue (https://gitlab.com/W1nst0n/universal-android-debloater/-/issues/15)\\nSee \\\"com.samsung.android.spdclient\\\" for more information.\\n\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.preff.kb.xm\",\"description\":\"'Emoji & Font Keyboard' on Xiaomi.\\nXiaomi won't let me uninstall it. If it's same for you, consider disabling it instead.\\nMake sure to install an alternate keyboard app before doing so.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.qeexo.smartshot\",\"description\":\"Smart Screenshots\\nSmart Screenshots? Disable it doesnt affecting normal screenshots.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.qiyi.video\",\"description\":\"IQIYI (https://play.google.com/store/apps/details?id=com.qiyi.video)\\nOnline video platform from Baidu (https://en.wikipedia.org/wiki/IQiyi).\\nI didn't know this is currently one of the largest online video sites in the world, \\nwith nearly 6 billion hours spent on its service each month, and over 500 million monthly active users.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.qorvo.uwb.vendorservice\",\"description\":\"Unknown app that has something to .android.UwbApp and NFC_SET_CONTROLLER_ALWAYS_ON permission.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.qti.backupagent\",\"description\":\"Backup Agent\\nhidden app for chinese phones backups SMS,MMS,Contacts\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.qti.primarycardcontroller\",\"description\":\"Sim card things about detected or switching, some chinese phones uses qualcomm names apps instead of normal\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.qualcomm.qti.carrierconfigure\",\"description\":\"Carrier Configure, Configures carrier, only for some china phones uses qualcomm names\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.qualcomm.qti.extsettings\",\"description\":\"Needed for hotspot, some chinese phones uses qualcomm names apps\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.qualcomm.qti.gpudrivers.pineapple.api34\",\"description\":\"Qualcomm GPU Drivers\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.qualcomm.qti.notificationservice\",\"description\":\"High Battery Temperature\\nWrong named package, theres only high temperature notification.\\nit's app for some chinese phones\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.qualcomm.qti.qs\",\"description\":\"Quick settings to mobile data internet, some chinese phones uses qualcomm names apps instead of normal\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.qualcomm.qti.securemsm.mdtp\",\"description\":\"MdtpService\\nOnly logs found\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.qualcomm.qti.sva\",\"description\":\"Qualcomm Voice Activation\\nIt has a lot of things like training voice, tutorial, debug mode.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.qualcomm.qti.tetherservice\",\"description\":\"Needed for tethering, some chinese phones uses qualcomm names apps instead of normal\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.qualcomm.qti.tm\",\"description\":\"Task manager\\nhidden app for chinese phones\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.qualcomm.qti.trustedui\",\"description\":\"trusteduiservice\\nTrusted UI debugging.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.reallytek.wg\",\"description\":\"Calibration, Test Camera things.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.realme.as.music\",\"description\":\"Realme Music app\\nhttps://play.google.com/store/apps/details?id=com.realme.as.music\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.realme.findphone.client2\",\"description\":\"Find my phone client app\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.realme.link\",\"description\":\"RealMe Link (https://play.google.com/store/apps/details?id=com.realme.link)\\nCompanion app for various realme IoT devices. Useless if you don't have a realme watch/band\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.realme.logtool\",\"description\":\"Hidden Logs App\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.realme.movieshot\",\"description\":\"Combine captions\\nIt's for partial screenshot, SaveLongshot.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.realme.securitycheck\",\"label\":\"SecurityAnalysis\",\"description\":\"Have useless ads and security checks.\\nWhy do we need more security when Play Protect is already good?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.realme.wellbeing\",\"description\":\"Sleep capsule\\nFeature for your phone where apps are locked at night to help you get a good night's sleep.\\nNo one is probably using this.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.recognize.number\",\"label\":\"Identify unknown numbers\",\"description\":\"Checking the code, this app looks useful only in China.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.redteamobile.virtual.softsim\",\"description\":\"It's for vsim = virtual sim\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.ringclip\",\"description\":\"Ringtone editing.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.rongcard.eid\",\"label\":\"Eid-Service\",\"description\":\"EID probably means Electronic ID. This presumably handles something related to that.\\nUseful only in China.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.rongcard.eidapi\",\"label\":\"aidlserverdemo\",\"description\":\"EID probably means Electronic ID. This presumably handles something related to that.\\nUseful only in China.\\nHas a lot of logs in code.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.rsupport.rs.activity.lge.allinone\",\"description\":\"LG RemoteCall service app\\nUsed to get support from LG, safe to remove.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.rsupport.rsperm.ntt\",\"description\":\"Remote support service\\nI found only permissions and not explained buttons in the code this app.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sagereal.lcmtest\",\"description\":\"Secret code: 88. LCD, LCM Test.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.InputEventApp\",\"description\":\"Hidden testing things also no activities\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.SMT\",\"label\":\"Samsung TTS\",\"description\":\"Samsung Text-to-speech service.\\nWorks with applications such as S Voice; translation apps, GPS that require Text-To-Speech (TTS) functionality and reads back text.\\nWARNING: SOME VERSIONS OF THIS APP ARE VULNERABLE TO PRIVILEGE ESCALATION ATTACKS! It can allow arbitrary RCE as system (UID 1000). Identifier: CVE-2019-16253.\",\"web\":[\"https://galaxystore.samsung.com/detail/com.samsung.SMT\",\"https://github.com/flankerhqd/vendor-android-cves/tree/master/SMT-CVE-2019-16253\"],\"removal\":\"replace\",\"suggestions\":\"tts\",\"type\":\"oem\"},{\"id\":\"com.samsung.aasaservice\",\"description\":\"Sometimes, eat a LOT of battery (according to some reddit users)\\nSecurity policy apps (kind of things which prevents installation of applications)\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.accessibility\",\"description\":\"Accessibility settings (useful for apps creating virtual buttons such as a pie-menu)\\nWeirdly, removing this package can cause a bootloop if you set a lock code on your phone.\\n Also used for clearing system cache from apps such as SD-Maid.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.samsung.accessory\",\"description\":\"Samsung Accessory Service (https://play.google.com/store/apps/details?id=com.samsung.accessory)\\nLets you transfer data between your Samsung phone and Samsung accessories (GALAXY Gear/Watch...) \\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.accessory.beansmgr\",\"description\":\"Gear IconX Plugin (https://play.google.com/store/apps/details?id=com.samsung.accessory.beansmgr)\\nAllows you to use features such as device settings and status view when connected to a Samsung Gear IconX (2018) device.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.accessory.safiletransfer\",\"description\":\"SASystemProviders\\nNeeded for Samsung Accessory Service\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.adaptivebrightnessgo\",\"description\":\"CameraLightSensor\\nApp to test Adaptive Brightness.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.advancedcallservice\",\"description\":\"Advanced Calling feature on an Android is a feature that allows you to make calls while using other applications with the use of CELLULAR DATA. In order for this feature to work, HD Voice must be enabled in settings.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.samsung.advp.imssettings\",\"description\":\"Needed for VoLTE (Voice over LTE) https://en.wikipedia.org/wiki/Voice_over_LTE\\nIMS(Ip Multimedia Subsystem) is an open industry standard for voice and multimedia communications over packet-based IP networks (VoLTE/VoIP/Wifi calling).\\nNOTE: This package could be needed for messaging apps that send SMS/RCS code to verify your phone number.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.A10s.d01.wallpapermulti\",\"description\":\"App with wallpapers to Samsung A10s.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.ConnectivityOverlay\",\"description\":\"Needed for wifi\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.ConnectivityUxOverlay\",\"description\":\"Overlay to wifi icon\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.MtpApplication\",\"description\":\"Samsung overlay for MTP\\nTalks to com.android.mtp. Needed to access your phone from a computer for file transfer.\\n\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.SettingsReceiver\",\"description\":\"Samsung overlay of AOSP Settings. It has 39 permissions. Handles interactions with features controlled by the settings.\\n\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.accessibility.talkback\",\"label\":\"TalkBack\",\"description\":\"Samsung talkback in accessibility.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.activation\",\"description\":\"Activation phone in china.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.adaptivebrightnessgo\",\"description\":\"Samsung Adaptive Brightness\\nFeature of Samsung devices that, as the name suggests, automatically adjusts the brightness level of display based on environmental lighting.\\nThis feature is available even after uninstalling.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.aircommandmanager\",\"label\":\"AirCommandManager\",\"description\":\"AirCommandManager (FACM) gives you access to signature S Pen features. You can access Air command anytime you are using your phone by simply taking out the S Pen.\",\"web\":[\"https://www.samsung.com/global/galaxy/what-is/air-command/\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.airtel.stubapp\",\"description\":\"My Airtel Stub app\\nMy Airtel is a customer service app designed for Airtel subscribers in Sri Lanka\\nThis package isn't the app itself but only a stub\\nIt's basically a non-functional empty shell which often only redirect you to the PlayStore to download the full app\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.alive.service\",\"description\":\"Content suggestions service\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.aliveprivacy\",\"description\":\"Content Suggestions is an AI-based app inside the Secure Folder, and its on-device AI-powered engine automatically suggests users to move private images of pre-selected categories to the Secure Folder. For this to happen users have to simply select specific faces or a type of image they want to tag as private and keep them secured in the private gallery of the Secure Folder. Once the initial setup is complete, the AI engine kicks in and identifies relevant images from the entire gallery. As this is an on-device AI solution, no information or image ever leaves the smartphone.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.allshare.service.fileshare\",\"description\":\"Wi-Fi Direct\\nAllows two devices to establish a direct Wi-Fi connection without requiring a wireless router.\\nhttps://www.samsung.com/au/support/mobile-devices/connecting-devices-via-wifi-direct/\\nhttps://en.wikipedia.org/wiki/Wi-Fi_Direct\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.allshare.service.mediashare\",\"label\":\"Nearby Service/SmartView\",\"description\":\"Formerly, Samsung AllShare service.\\nUsed to stream content from your phone to a Samsung smart TV.\\n On devices where the display-name is 'Nearby Service', 'Smart View' will continue to work properly (it doesn't depend on Nearby Service).\",\"web\":[\"https://www.samsung.com/us/apps/smart-view-2/\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.app.accesscontrol\",\"description\":\"Samsung Interaction control\\nSettings > Accessibility > Dexterity and interaction (or vol. down + home key)\\nAllows you to restrict some functions of your phone (stop the phone from interacting with touch commands for instance)\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.app.advsounddetector\",\"description\":\"Samsung Sound detectors\\nUses microphone to identify recognizable sounds. For example, if it recognizes a baby's cry, it can alert you with flashing lights so \\nyou know to check on your baby. Or it can notify you if it hears the doorbell ring so you know to open the door.\\n#\\nadv maybe refers to 'Samsung Advanced Institute of Technology' (or simply means 'advanced')\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.app.amcagent\",\"description\":\"Advanced Management Console Agent\\nEntreprise feature I guess.\\n\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.app.aodservice\",\"description\":\"Always On Display\\nNOTE: This package handles the clock on the lockscreen, in addition to the AOD functionality.\\nWhen enabled in settings it shows clock and notifications when you raise the phone or touch the screen.\\nThis is basically a lower-power lock-screen. It could in theory reduce power draw if you check notifications/clock often as OLED screens draw minimal power showing a mostly black screen(black = pixel off), but in practice the number of times you'll unintentionally trigger it will likely eat up any potential power savings and more. And if your device doesn't have an OLED screen this will draw way more power.\\nMost of these power savings could be applied to your standard lock-screen simply by making your background image completely black.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.app.appsedge\",\"description\":\"Samsung apps edge (https://www.samsung.com/global/galaxy/what-is/apps-edge/)\\nDisplays your five most frequently used apps for you to access at a moment’s notice.\\nBreaks Split-Screen/Multi-Window according to issue#124.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.app.assistantmenu\",\"description\":\"Assistant menu\\nDesigned for individuals with motor control or other physical impairments. \\nBy using Assistant menu, you can access hardware buttons and all parts of the screen by simply tapping or swiping.\\nhttps://www.samsung.com/uk/accessibility/mobile-assistant-menu/\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.app.camera.sticker.facear.preload\",\"description\":\"Annoying Stickers/stamps of the Samsung camera app. C'mon it feels like Snapshat.\\nhttps://developer.samsung.com/galaxy/stickers\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.app.camera.sticker.facear3d.preload\",\"description\":\"Default 3D live stickers\\nAnnoying Stickers/stamps of the Samsung camera app. C'mon it feels like Snapshat.\\nhttps://developer.samsung.com/galaxy/stickers\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.app.camera.sticker.facearavatar.preload\",\"description\":\"Annoying Stickers/stamps of the Samsung camera app. C'mon it feels like Snapshat.\\nhttps://developer.samsung.com/galaxy/stickers\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.app.camera.sticker.facearframe.preload\",\"description\":\"Frames sticker? \\nI don't know what this sticker is and I don't have this package.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.app.camera.sticker.stamp.preload\",\"description\":\"Annoying Stickers/stamps of the Samsung camera app. C'mon it feels like Snapshat.\\nhttps://developer.samsung.com/galaxy/stickers\\nSafe to remove\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.app.clipboardedge\",\"description\":\"Clipboard edge panel\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.app.clockpack\",\"description\":\"Samsung Clock style\\nAffects video playback in full-screen mode, breaks it\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.app.cocktailbarservice\",\"label\":\"Samsung Edge screen\",\"description\":\"Enables you to open your five most used apps by simply swiping the edge of the screen.\\nSwipe one of the edges of the screen to bring up information even when your device is locked (with the screen off). \\nYou can also set it up to display the news or weather, for example.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.app.color\",\"description\":\"Color adjustment\\nSamsung's adaptive super AMOLED screen optimizes the color range, saturation, and sharpness of the picture depending on what you're watching or doing. \\nThis package lets you to manually customize the color settings to match your preferences.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.app.colorblind\",\"description\":\"This app provides colorblind accessibility features for Samsung devices, helping users with color vision deficiencies by adjusting display colors and improving visibility.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.app.contacts\",\"label\":\"Samsung Contacts\",\"description\":\"Safe to debloat if you use another contacts app.\",\"removal\":\"replace\",\"warning\":\"After removing the app, you will no longer be able to access Contacts from the Samsung dialer app.\\nThis will also prevent the user from modifying the Safety and emergency tab within the Samsung Android native settings app. Specifically the Medical info & Emergency contacts. This information is pulled on the lockscreen by first responders or in emergency sharing mode for emergency contacts.\",\"suggestions\":\"contacts\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.app.dofviewer\",\"description\":\"Live focus\\nAllows you to adjust the level of background blur in the camera app.\\nFrom the Samsung Gallery, you can also select from a range of background blur shapes to add characters and shapes to a photo.\\nhttps://www.samsung.com/global/galaxy/what-is/live-focus/\\n\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.app.dressroom\",\"label\":\"Samsung Wallpaper and style\",\"description\":\"Wallaper manager. Needed to pick up a wallpaper on Android 10+.\\nHas INTERNET permission and ACCESS_MEDIA_LOCATION\\nBefore Android 10, you should still be able to set a wallpaper from the Samsung gallery without this package.\",\"removal\":\"caution\",\"warning\":\"Removing this app will prevent you to set a new wallpaper on Android 10+ (even from the Gallery) or changing the Material You palette on Android 12+.\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.app.dtv.dmb\",\"description\":\"TV app on Samsung phones and it's only available on Japanese or Korean variants.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.app.earphonetypec\",\"label\":\"Samsung USB-C\",\"description\":\"Not required unless you have a Samsung DAC or Samsung Type-C earphones (for firmware updates)\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.app.episodes\",\"description\":\"Samsung story album (https://www.samsung.com/in/support/mobile-devices/what-is-story-album-application-in-samsung-galaxy-s4/)\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.app.filterinstaller\",\"description\":\"Filter installer\\nI have no clue about the usefulness of this package. Maybe it filters apps that are not compatible with the phone.\\nThis package is only triggered when you install an app (private class PackageIntentReceiver) \\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.app.galaxyfinder\",\"label\":\"Samsung Finder\",\"description\":\"a search application that allows you to find what you want in an instant by searching the content on your Galaxy smartphone and on the web as well.\",\"web\":[\"https://www.samsung.com/global/galaxy/what-is/s-finder/\"],\"removal\":\"replace\",\"warning\":\"Removing this will remove the search in the app drawer.\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.app.interactivepanoramaviewer\",\"description\":\"Visual. photo virt.\\nSamsung Virtual Shot Viewer enable sharing virtual shot\\nSafe to remove if you don't want virtual photos.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.app.interpreter\",\"description\":\"Samsung Interpreter app, enables Live translation of foreign languages\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.app.kfa\",\"description\":\"KFA\\nAnother app from knox, has something to decrypt.\\nName apk this app is: KnoxAIFrameworkApp.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.app.ledbackcover\",\"description\":\"I think it enables doing things with LEDs on the cover\\n\\nhttps://www.samsung.com/hk_en/mobile-accessories/led-cover-for-galaxy-s10/EF-KG973CBEGWW/\\nHOW IT WORKS : https://forum.xda-developers.com/galaxy-note-8/accessories/how-led-cover-t3686694\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.app.ledcoverdream\",\"description\":\"I think it enable doing things with LEDs on the cover\\nhttps://www.samsung.com/hk_en/mobile-accessories/led-cover-for-galaxy-s10/EF-KG973CBEGWW/\\nHOW IT WORKS : https://forum.xda-developers.com/galaxy-note-8/accessories/how-led-cover-t3686694\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.app.memo\",\"description\":\"Samsung Memo (was replaced by Samsung Notes app com.samsung.android.app.notes)\\n\",\"removal\":\"replace\",\"suggestions\":\"note_taking_apps\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.app.mhswrappertmo\",\"description\":\"Mobile Hotspot\\nIs it linked to T-Mobile ? (\\\"tmo\\\" at the end of the package)\\nYou can debloat this and still create hotspot.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.app.mirrorlink\",\"description\":\"Used to connect your phone to a car (with https://mirrorlink.com/ support) in order to provide audio streaming, GPS navigation...\\nhttps://www.samsung.com/us/support/answer/ANS00048972/\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.app.motionpanoramaviewer\",\"description\":\"Motion panorama viewer\\nLets you see the result of a motion panorama\\nhttps://www.samsung.com/global/galaxy/what-is/motion-panorama/\\n\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.app.multiwindow\",\"description\":\"Provides manifestly the ability to display multiple apps on the screen (at the same time)\\nCan someone test?\\n\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.app.news\",\"description\":\"News Samsung app\\nDoesn't exist anymore? \\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.app.notes\",\"label\":\"Samsung Notes\",\"description\":\"Samsung Notes app\\n\",\"web\":[\"https://play.google.com/store/apps/details?id=com.samsung.android.app.notes\"],\"removal\":\"replace\",\"suggestions\":\"note_taking_apps\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.app.notes.addons\",\"description\":\"Allows for marking up/drawing on notes in the Samsung Notes app (designed for use with S Pen).\\nRemoval likely breaks com.samsung.android.app.notes. Safe to remove otherwise.\\nMay reinstall itself automatically (removal has persisted for me this time around, and through multiple reboots).\\nhttps://galaxystore.samsung.com/prepost/000005769652?appId=com.samsung.android.app.notes.addons\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.app.omcagent\",\"label\":\"Samsung Configuration update\",\"description\":\"Open Market Customization Agent (AKA 'Recommended Apps')\\nInstalls more Samsung \\\"Recommended Apps\\\" after device setup.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.app.panel.naver.v\",\"description\":\"Naver V Panel\\nSpecial samsung panel for the very useless V LIVE (formerly Naver V) app (https://play.google.com/store/apps/details?id=com.naver.vapp)\\nV LIVE is an app that features personal video broadcasts of South Korean celebrities\\nThis panel also includes Naver Shopping (https://shopping.naver.com/)\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.app.parentalcare\",\"description\":\"Parental control to block apps on new samsung phones\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.app.pinboard\",\"description\":\"Samsung Scrapbook (discontinued)\\nhttps://www.samsung.com/za/support/mobile-devices/how-do-i-use-the-scrapbook-memo-feature-on-my-samsung-galaxy-note3/\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.app.reminder\",\"description\":\"Samsung bixby reminder (https://www.samsung.com/global/galaxy/apps/bixby/reminder/)\\nSet up smart reminders to get notified when and where you need to. You can even link websites, videos, photos and more.\\nUses wifi/data regularly.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.app.routines\",\"label\":\"Samsung Modes and Routines\",\"description\":\"Formerly, Bixby Routines.\\nAutomating actions triggered by context clues: location, time, or event.\",\"web\":[\"https://www.samsung.com/global/galaxy/what-is/bixby-routines/\"],\"removal\":\"caution\",\"suggestions\":\"automation_apps\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.app.sbrowseredge\",\"description\":\"Related to internet browser. For Galaxy Edge? \\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.app.selfmotionpanoramaviewer\",\"description\":\"Selfie panorama viewer\\nLets you see the result of a selfie motion panorama\\nhttps://www.samsung.com/global/galaxy/what-is/motion-panorama/\\n\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.app.settings.bixby\",\"description\":\"Bixby settings (Bixby = Samsung intelligence assistant)\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.app.sharelive\",\"label\":\"Quick Share\",\"description\":\"Samsung Quick Share (from the Galaxy Store)\",\"removal\":\"replace\",\"warning\":\"Removing the package breaks Quick Share.\",\"suggestions\":\"sharing_apps\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.app.simplesharing\",\"description\":\"Samsung Link Sharing\\nLets you share large size files by using the Samsung Cloud.\\nhttps://www.samsung.com/au/support/mobile-devices/what-is-link-sharing/\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.app.siofviewer\",\"description\":\"Live focus\\nNeeded for Live Focus in camera app.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.app.smartcapture\",\"label\":\"Samsung capture\",\"description\":\"Samsung's implementation of screenshot. Show the bottom toolbar after taking a screenshot.\\nLets you group widgets on OneUI 4 (?)\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.app.smartwidget\",\"description\":\"Samsung screenshot\\nYou will still be able to take screenshots without this package.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.app.social\",\"description\":\"I know this has been discontinued by Samsung but that it.\\nSurely a social app like Samsung Members (com.samsung.oh)\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.app.soundpicker\",\"description\":\"Lets you select a sound for alarm/ringtone\\n\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.app.spage\",\"description\":\"Samsung Free (previously known as 'Bixby Home') is a vertically scrolling list of information that Bixby can interact with for example weather, fitness activity and buttons\\nfor controlling their smart home gadgets.\\nhttps://galaxystore.samsung.com/prepost/000005445489?appId=com.samsung.android.app.spage\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.app.storyalbumwidget\",\"description\":\"The Story Album widget enables you to access the Story Album app and create digital picture albums that you can view and acess directly \\nfrom the widget on a Home screen.\\nOld feature (from Galaxy S4)\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.app.talkback\",\"description\":\"Voice assistant. Accessibility feature\\nScreen Reader to provide audible feedback to assist blind and low-vision users.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.app.taskedge\",\"description\":\"Handle task edge panel\\nThrough Tasks edge, you can quickly perform frequently used tasks, such as composing messages and creating events.\\nhttps://www.samsung.com/levant/support/mobile-devices/galaxy-s7-edge-how-do-i-add-tasks-edge/\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.app.telephonyui\",\"label\":\"Samsung Call settings\",\"description\":\"The phone call UI that offers the option to accept or reject calls, send a message, etc.\",\"removal\":\"unsafe\",\"warning\":\"Removing the package breaks phone app settings and SIM Manager.\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.app.telephonyui.esimclient\",\"label\":\"EsimClient\",\"description\":\"only has ESimClient Webview Activity\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.app.tips\",\"description\":\"Tips on how to use your phone\\\"\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.app.updatecenter\",\"description\":\"App update\\nInstalls app updates\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.app.vrsetupwizards\",\"description\":\"Samsung Gear VR (Virtual Reality) setup wizard (https://en.wikipedia.org/wiki/Samsung_Gear_VR)\\nhttps://360samsungvr.com/portal/content/about_samsung_vr\\nStub = https://stackoverflow.com/questions/10648280/what-is-stub-and-aidl-for-in-java\\nSetup wizard : The first time you turn your device on, a Welcome screen is displayed. It guides you through the basics of setting up your device.\\nIt's the setup for Samsung VR services.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.app.vrsetupwizardstub\",\"description\":\"Samsung Gear VR (Virtual Reality) setup wizard (https://en.wikipedia.org/wiki/Samsung_Gear_VR)\\nhttps://360samsungvr.com/portal/content/about_samsung_vr\\nStub = https://stackoverflow.com/questions/10648280/what-is-stub-and-aidl-for-in-java\\nSetup wizard : The first time you turn your device on, a Welcome screen is displayed. It guides you through the basics of setting up your device.\\nIt's the setup for Samsung VR services.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.app.watchmanager\",\"description\":\"Samsung Galaxy Wearable (Samsung Gear) (https://play.google.com/store/apps/details?id=com.samsung.android.app.watchmanager)\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.app.watchmanagerstub\",\"description\":\"Stub for the Galaxy Wearable app.\\nStub = https://stackoverflow.com/questions/10648280/what-is-stub-and-aidl-for-in-java\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.app.withtv\",\"description\":\"WitTV (replaced by com.sec.android.app.withtv)\\nUsed to stream content from your phone to a Samsung smart TV.\\nhttps://www.samsung.com/us/apps/smart-view-2/\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.applock\",\"description\":\"Samsung App Lock\\nLets you lock your app (Settings > Advanced functions > App lock)\\nYou should lock your apps storing private data (provides data at rest encryption when your phone is locked)\\n\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.appseparation\",\"label\":\"Separated Apps\",\"description\":\"Separated Apps isolates third-party apps in a sandboxed folder. The third-party apps cannot intercommunicate with work apps or access confidential work data. Keep in mind that Separated Apps does not provide the same privacy guarantees as the new work profile on company-owned devices. As such, it is not intended for personal apps and data.\",\"web\":[\"https://docs.samsungknox.com/admin/knox-platform-for-enterprise/separated-apps.htm\",\"https://beta.pithus.org/report/cae5798a835dc434037400436fba27f5eed960c6f476a7b7d17d85a1425530c0\"],\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.ardrawing\",\"label\":\"Samsung AR Doodle\",\"description\":\"Accessible through AR Zone.\\nLets you draw on your face using the front camera and uses AR Core for drawing on the environment with the rear camera.\\nOnly Sasmung AR app (afaik) that requests location access, and it refuses to run without it.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.aremoji\",\"description\":\"AR Emoji mode for Samsung camera \\nhttps://www.samsung.com/global/galaxy/what-is/ar-emoji/\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.aremojieditor\",\"description\":\"AR Emoji Editor\\nEdits those AR people emoji things\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.arzone\",\"description\":\"AR Zone\\nhttps://www.samsung.com/levant/support/mobile-devices/which-features-are-available-in-the-ar-zone-in-the-galaxy-z-flip/\\nLets you access other AR apps.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.asksmanager\",\"description\":\"Samsung device protection manager.\\nIt's anti-theft feature. I couldn't find exactly what does the samsung layer to the already existing android device protection : \\nhttps://www.greenbot.com/article/2904397/everything-you-need-to-know-about-device-protection-in-android-51.html\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.audiomirroring\",\"description\":\"AudioMirroring\\nAudio Mirroring to Cast other devices will not work after remove.\\nAlso this app running in the background.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.authfw\",\"description\":\"Used by Samsung Pass\\nBiometric authentication service that can be used to sign in to websites and apps in your mobile.\\nhttps://www.samsung.com/global/galaxy/apps/samsung-pass/\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.aware.service\",\"label\":\"Samsung Quick Share Agent\",\"description\":\"Formerly, Quick Share.\\nUse Wifi direct to share files between 2 Samsung Galaxy phones (it's only for Samsung Galaxy users).\",\"removal\":\"replace\",\"suggestions\":\"sharing_apps\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.bbc.bbcagent\",\"description\":\"BBCAgent (B. B. Container Agent?)\\nCollects device information and manages installation/uninstallation of trusted apps in KNOX containers\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.bbc.fileprovider\",\"description\":\"KNOX BBC Provider.\\nProvider for KNOX BBC\\nContent providers encapsulate data, providing centralized management of data shared between apps.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.beaconmanager\",\"description\":\"Replaced by Samsung Smart Things (com.samsung.android.ststub)\\nAllows users to control, automate, and monitor their home environment via mobile device. \\nhttps://en.wikipedia.org/wiki/SmartThings\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.bio.face.service\",\"label\":\"Face\",\"description\":\"Handles Face recognition unlock.\\nNOTE: Removing this package causes biometric prompts in apps to be delayed by 5-8 seconds before appearing. Selecting 'Biometrics and security' in the settings app also locks up the Settings app for about 5-8 seconds but eventually loads and functions as normal.\",\"web\":[\"https://kp-cdn.samsungknox.com/b60a7f0f59df8f466e8054f783fbbfe2.pdf\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.biometrics\",\"description\":\"Provide biometric support\\n\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.biometrics.app.setting\",\"description\":\"Biometric settings\\n\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.bixby.agent\",\"description\":\"Removing this will disable the bixby hardware key without breaking Bixby itself.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.bixby.agent.dummy\",\"description\":\"Bixby Voice Stub\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.bixby.es.globalaction\",\"description\":\"Bixby stuff [MORE INFO NEEDED]\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.bixby.plmsync\",\"description\":\"Bixby stuff [MORE INFO NEEDED]\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.bixby.service\",\"description\":\"Bixby Service\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.bixby.voiceinput\",\"description\":\"Bixby service needed for voice control\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.bixby.wakeup\",\"description\":\"Bixby voice wake-up\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.bixbyhelper\",\"description\":\"QQ music plugin\\nRequire QQ Music and it's Chinese.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.bixbytouch\",\"description\":\"Bixby Touch\\nApp for smart things, still only for China.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.bixbyvision.framework\",\"description\":\"BixbyVision Framework\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.bluelightfilter\",\"description\":\"Blue light filter\\nUsing the sunrise/sunset option uses the ACCESS_FINE_LOCATION permission. It's better to program the activation of the filter according to the time.\\nNote: reducing blue light can prevent eyestrain and other health issues. See https://www.webmd.com/eye-health/blue-light-reduce-effects\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.brightnessbackupservice\",\"label\":\"BrightnessBNR\",\"description\":\"Backup brightness configuration\\n May be used when reverting the brightness from a mode, routine, or powersaving mode.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.calendar\",\"description\":\"Samsung Calendar App\\n\",\"removal\":\"replace\",\"suggestions\":\"calendars\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.callassistant\",\"description\":\"Appears to handle a whole bunch of AI services related to Gallery and Phone. Can break stuff in OneUI 6.1+\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.callbgprovider\",\"label\":\"CallBGProvider\",\"description\":\"Call Background.\\nIt is customizing background theme of calling.\\nSCloud, backup things found in code.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.camerasdkservice\",\"label\":\"SCameraService\",\"description\":\"Camera SDK, probably used for the main camera app?\\nThere are a lot of features that I do not know if it is not only available to developers.\\nApp has many permissions like arcsoft, smartcamerascan, supernight, too many to write here.\\nA strange app with many things sometimes mentioned in the code that it is used for calibration.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.cameraxservice\",\"label\":\"SCameraXService\",\"description\":\"It's hidden app for testing camera things also it's camera calibration\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.carkey\",\"description\":\"Digital Key Framework\\nFrameworks to CarKey app, only China.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.carlink\",\"description\":\"CarLife app only for China.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.chnfileshare.kit\",\"description\":\"S Share\\nChinese app to Secure transfer files using bluetooth.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.cidmanager\",\"label\":\"Configuration update\",\"description\":\"Sets the CSC for the phone depending on the SIM card. This is responsible for forcing you to restart when to activate the so-called features when inserting new SIM card. It may also revert band settings after OTA update in some cases.\",\"removal\":\"caution\",\"warning\":\"It may be required for receiving OTA updates, currently unknown.\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.clipboarduiservice\",\"description\":\"User interface for clipboard\\n\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.cmfa.framework\",\"label\":\"CMFA Framework\",\"description\":\"Continous Multi-Factor Authentication Framework\\nSeems useless if you aren't logged-in to a Samsung Account.\",\"web\":[\"https://docs.samsungknox.com/dev/knox-sdk/appendix/additional-advanced-access-control-enhancements/\"],\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.coldwalletservice\",\"label\":\"Samsung Blockchain Keystore\",\"description\":\"Secure and convenient place to manage your private key used for cryptocurrency transactions.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.communicationservice\",\"description\":\"Message Service.\\nNeeded for SMS/MMS communication\\n\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.contacts\",\"description\":\"Samsung contacts app\",\"removal\":\"replace\",\"suggestions\":\"contacts\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.container\",\"label\":\"ContainerService\",\"description\":\"Creates container. Maybe not very useful. Someone can test?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.coreapps\",\"description\":\"Samsung Enhanced features\\nFiles and profiles sharing feature. It may be called \\\"Enhanced messaging\\\".\\nUsing this service lets Samsung to automatically collect your phone number, contact list and messages\\nhttps://forums.androidcentral.com/samsung-galaxy-s6-edge/523172-enhanced-features.html\\nhttps://www.samsung.com/za/support/mobile-devices/what-is-enhanced-messaging/\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.da.daagent\",\"description\":\"Samsung dual messenger (https://www.samsung.com/global/galaxy/what-is/dual-messenger/)\\nAllows you to use two separate accounts for the same app.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.dbsc\",\"description\":\"Galaxy Service Setup\\nDevice-Based Service Consent. Pairs with `com.sec.spp.push` to broadcast new service consent requests to your device.\\nReally slimey move by Samsung to name it this in the wake of Google announcing their own DBSC (Device Bound Session Credentials) which will phase out third-party cookies and help secure browsers against cookie theft.\\nhttps://blog.chromium.org/2024/04/fighting-cookie-theft-using-device.html\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.dck.timesync\",\"description\":\"DckTimeSyncService\\nOnly logs found\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.deviceidservice\",\"description\":\"DeviceIdService\\nCollects device id but it is not known what it is used for.\\nTake's OAID, VAID, AAID.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.dialer\",\"label\":\"Samsung Phone\",\"description\":\"Stock Samsung dialer\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.digitalkey\",\"label\":\"Digital Key\",\"description\":\"I found on this app only: Using your phone as a key to open doors. Coming soon! Useless. Not available digital key for users.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.dkey\",\"description\":\"Samsung Wallet Digital Key\\nUsed for cars, only China.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.dlp.service\",\"description\":\"SamsungDLPService (KNOX). Old feature. Was replaced by SDP (Sensitive Data Protection)\\nData Loss Prevention (DLP) feature\\nSDP is good because it allows to have encrypted data at rest (= decryption keys not in RAM) even when your phone is on.\\nhttps://docs.samsungknox.com/admin/whitepaper/kpe/sensitive-data-protection.htm \\nhttps://docs.samsungknox.com/knox-platform-for-enterprise/admin-guide/sensitive-data-protection.htm\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.dqagent\",\"label\":\"DQA\",\"description\":\"DQA = Samsung Device Quality Agent. Logging agent for diagnostic device information.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.drivelink.stub\",\"description\":\"Stub for car mode \\nREMINDER : Stub = https://stackoverflow.com/questions/10648280/what-is-stub-and-aidl-for-in-java\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.dsms\",\"label\":\"Dsms\",\"description\":\"Hidden diagmonagent logs components.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.dynamiclock\",\"label\":\"Samsung Wallpaper services\",\"description\":\"Formerly, Dynamic Lockscreen.\\nAutomatically changes your Lock screen's wallpaper every time your Galaxy phone wakes up (wallpapers update every 2 weeks).\",\"web\":[\"https://www.samsung.com/us/support/answer/ANS10001593\"],\"required_by\":[\"com.samsung.systemui.lockstar\"],\"removal\":\"caution\",\"warning\":\"Removing the app breaks LockStar customizations.\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.easysetup\",\"label\":\"Nearby device scanning\",\"description\":\"Previously, Samsung Connect Easy Setup, Samsung SmartThings.\\nRequires \\\"com.samsung.android.beaconmanager\\\" to be useful.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.email.composer\",\"description\":\"another app related to Email app, bad privacy\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.email.provider\",\"label\":\"Samsung Email\",\"description\":\"Samsung email app\",\"web\":[\"https://play.google.com/store/apps/details?id=com.samsung.android.email.provider\"],\"removal\":\"replace\",\"suggestions\":\"email_clients\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.email.sync\",\"description\":\"Sync to Email app, bad privacy\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.email.ui\",\"description\":\"Email app with bad privacy\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.email.widget\",\"description\":\"Email Widget on some old samsung phones like S6\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.emergency\",\"description\":\"Emergency SOS\\nHas a lot of permissions, lets you send SOS messages and calls.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.emojiupdater\",\"description\":\"AR Emoji updater\\nThis package has no permission so I wonder how it can update anything.\\nSee com.samsung.android.aremoji\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.fast\",\"description\":\"Samsung Secure Wi-Fi\\nSamsung VPN service powered by McAfee\\nhttps://www.pcmag.com/news/mcafee-samsung-partner-on-built-in-security-vpn-for-galaxy-s9\\nhttps://www.ctrl.blog/entry/what-is-samsung-secure-wi-fi.html\\nNote: If you need to use a VPN use something more trustworthy*\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.fingerprint.service\",\"description\":\"Fingerprint service\\n\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.fmm\",\"description\":\"Find My Mobile\\nTracks down your device when it gets lost. \\nLets you remotely lock your device, block access to Samsung Pay and wipe data from the entire device.\\nhttps://www.samsung.com/global/galaxy/what-is/find-my-mobile/\\nhttps://findmymobile.samsung.com/\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.forest\",\"description\":\"Digital Wellbeing (old version of com.samsung.android.wellbeing)\\nThat's an app for device and app usage tracking and limiting.\\nhttps://galaxystore.samsung.com/prepost/000004807357\\nNOTE for Dex users: uninstalling this package makes the UI unstable, in particular the taskbar is not loaded and UI continues to crash.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.framework.res\",\"description\":\"This package is part of Samsung’s custom system framework and manages various resources for Samsung-specific features and UI enhancements.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.galaxycontinuity\",\"description\":\"Samsung Flow (https://play.google.com/store/apps/details?id=com.samsung.android.galaxycontinuity)\\nIt's a service to 'seamlessly' connect your devices. You can authenticate your Tablet/PC with your smartphone, share content between devices, and sync notifications or view contents from your smartphone on your Tablet/PC.\\nYou can turn on the smartphone's Mobile Hotspot to keep your Tablet/PC connected. You can also log in to your Tablet/PC with your biometric data (Iris, Fingerprints) if you register with Samsung Pass.\\nhttps://www.samsung.com/levant/support/mobile-devices/what-is-the-samsung-flow-and-how-to-use-it/\\n\\nHas more than 81 permissions. Not the kind of app you want to keep installed if you don't use it. It increases the attack surface and can potentially compromise a lot of things (including your computer). FYI, 4 CVE has been discovered between 2021 and 2022: https://www.opencve.io/cve?vendor=samsung&product=samsung_flow\\n\\nPithus analysis: https://beta.pithus.org/report/77216cd6209c73d00332180319249ac6e4ef8479e68d2a21c97a52fdc5f3d62b\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.gallery.plugins\",\"description\":\"SamsungGallery Plugins\\nChinese mapcamera plugin.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.gallery.watch\",\"description\":\"Samsung Watch gallery app\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.game.gamehome\",\"description\":\"Samsung Game Launcher \\nhttps://www.samsung.com/global/galaxy/apps/game-launcher/\\nAll in one hub for mobiles games\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.game.gametools\",\"label\":\"Samsung Game Booster\",\"description\":\"Lets you record and share screenshots of your game-play.\",\"web\":[\"https://www.samsung.com/au/support/mobile-devices/how-to-use-game-tools/\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.game.gos\",\"label\":\"Samsung Game Optimizing Service\",\"description\":\"It's supposed to \\\"improve\\\" game performance.\\nHas a \\\"Game Intent Service\\\" that runs occasionally. If uninstalling fails, try disabling.\",\"web\":[\"https://pcgamer.com/samsungs-game-optimization-service-might-be-throttling-the-performance-of-over-10000-apps\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.gametuner.thin\",\"description\":\"Samsung Game Tuner (https://play.google.com/store/apps/details?id=com.samsung.android.gametuner.thin)\\nGame Tuner is advanced setting app. It enables you to change the resolution and frames per second settings\\nin mobile games that require tuning for different Android devices, and thereby control heat generation and battery drain.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.gearoplugin\",\"description\":\"Gear S Plugin (https://play.google.com/store/apps/details?id=com.samsung.android.gearoplugin)\\nPlugin for com.samsung.android.app.watchmanager\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.globalpostprocmgr\",\"description\":\"GlobalPostProcMgr\\nUnknown app, has Draft Recovery.\\nUninstalling breaks camera functionality.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.gru\",\"description\":\"Galaxy Resource Updater\\nNeeded for galaxy store probably and not sure but also for system updates?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.hdmapp\",\"label\":\"HdmApp\",\"description\":\"Hypervisor Device Manager App\",\"web\":[\"https://docs.samsungknox.com/devref/knox-sdk/reference/com/samsung/android/knox/hdm/HdmManager.html\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.hmt.vrshell\",\"description\":\"Gear VR Shell \\nGear VR : https://360samsungvr.com/portal/content/about_samsung_vr\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.hmt.vrsvc\",\"description\":\"Gear VR Service\\nSee above.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.homemode\",\"label\":\"Daily Board\",\"description\":\"Show a slideshow of your favourite pictures while your device is charging.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.samsung.android.homemode\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.honeyboard\",\"description\":\"Samsung keyboard\",\"web\":[\"https://developer.android.com/training/articles/direct-boot\"],\"removal\":\"caution\",\"warning\":\"Do NOT disable if you don't have another keyboard with direct boot mode support, or you'll be stuck at boot (no keyboard to unlock the phone).\\nDo NOT remove this package with root if it wasn't first uninstalled with the non-root method.\\nRemoving this package also breaks the Accessibility settings on Android 11.\",\"suggestions\":\"keyboards\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.icecone\",\"description\":\"Keyboard Content Center\\nLets you choose media content (e.g. stickers and music) from the Galaxy Keyboard.\\nThis app always runs in background.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.imagepp\",\"description\":\"Chat PP\\nOnly for China.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.incall.contentprovider\",\"label\":\"CallContentProvider\",\"description\":\"\",\"removal\":\"caution\",\"warning\":\"After removal, some features will not be available: face AR, AR emoji, filter, sticker.\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.incallui\",\"description\":\"UI when \\\"being called/in call\\\". It's basically the screen that shows you who is calling, lets you answer and hang up, switch to speaker, etc\\n\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.inputshare\",\"description\":\"Samsung Multi-Control, allows certain apps to be continued on multiple Galaxy devices (like Internet or Notes)\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.intelligenceservice2\",\"label\":\"IntelligenceService2\",\"description\":\"It seems that this package is a kind of spyware. Very difficult to find information about this.\\nSome people say it's linked to Carrier IQ (which is a carrier rootkit for the NSA).\\nThis package also have very stranges permissions: READ_PLACE / WRITE_PLACE. I couldn't find any explaination on the web.\\nSo either it's a useless samsung package or a spyware. I deleted it and I didn't notice anything bad.\",\"web\":[\"https://en.wikipedia.org/wiki/Carrier_IQ\",\"https://forum.xda-developers.com/showpost.php?s=c85df628dfc39c3a971e6f9cfa98cbb8&p=54071328&postcount=6\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.ipsgeofence\",\"description\":\"Samsung Visit In app\\n\\nIPSGeofence\\nIPS = Indoor Positioning System.\\nThe concept of Indoor Positioning System designates a network of connected devices within a building making it possible to trace the position of another device – and therefore potentially of a person – in environments where GPS systems are \\nnot efficient .\\nGeofencing is a technique which consists in activating preconfigured actions when a device enters a certain geographical area.\\nFor example, a user can use it to automatically turn on Wi-Fi and home lights when their smartphone is detected nearby.\\nIn short, if enabled, this app will track your location everywhere and all the time!\\nhttps://www.comparitech.com/blog/vpn-privacy/what-is-geofencing-privacy/\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.keycustomizationinfobackupservice\",\"description\":\"If you don't use backup service, it's safe to remove.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.keyguardwallpaperupdator\",\"description\":\"Lets you customize your Samsung device with different images (provided by Samsung) on the lock screen. \\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.kgclient\",\"description\":\"Samsung Payment Services\\nRemoving this package will LOCK YOU OUT of your device with a full-screen overlay message saying that Device Services was uninstalled in an unauthorised manner. This is persistent upon reboots until a factory data reset is initiated. Filesystem can still be accessed if ADB permissions were granted beforehand.\\nUnless you know what you're doing, you shouldn't uninstall this package.\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.kidsinstaller\",\"description\":\"Samsung Kids Home (https://www.samsung.com/global/galaxy/apps/samsung-kids-home/)\\nLets you shape a \\\"safe environment\\\" for your child.\\nNOTE : You shouldn't give your phone to a child. That bad ! \\nhttps://ifstudies.org/blog/a-smartphone-will-change-your-child-in-ways-you-might-not-expect-or-want\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.kmxservice\",\"description\":\"KmxService\\nKnox Matrix. Provides a feature to securely generate and store keys used for end-to-end encryption (E2EE).\\nIt encrypts/decrypts data on the user’s device and transmits it to the server.\\nThe user’s original data cannot be checked as decryption is impossible from the server, which only has encrypted data, and is safely protected from external attacks.\\nhttps://www.apkmirror.com/apk/samsung-electronics-co-ltd/kmxservice/\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.knox.analytics.uploader\",\"label\":\"Knox Analytics Uploader\",\"description\":\"Knox Analytics Uploader\\nSends analytics to Samsung.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.knox.app.networkfilter\",\"description\":\"knoxNwFilter\\nIs responsible for Bluetooth to work.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.knox.attestation\",\"description\":\"KNOX Attestation\\nLets you check the integrity of a Samsung Android device by connecting to a Samsung Attestation server.\\nhttps://docs.samsungknox.com/admin/whitepaper/kpe/attestation.htm\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.knox.containeragent\",\"label\":\"Work profile\",\"description\":\"Formerly, Workspace.\\nProvides an isolated environment to store data (see Secure Folder)\\n\\nNote: With Knox 3.4, Knox containers are now deprecated and replaced by Android work profiles.\\nComunicate with Samsung servers:\\n- https://vas.samsungapps.com (App updates)\\n- http://cn-ms.samsungapps.com (APK Server).\",\"web\":[\"https://support.samsungknox.com/hc/en-us/articles/115012547907-What-URLs-do-I-have-to-whitelist-to-make-Samsung-apps-work-with-an-authenticated-proxy-\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.knox.containercore\",\"label\":\"KnoxCore\",\"description\":\"Providess an isolated environment to store data (see Secure Folder)\\n\\nNote: With Knox 3.4, Knox containers are now deprecated and replaced by Android work profiles.\\nComunicate with Samsung servers:\\n- https://vas.samsungapps.com (App updates)\\n- http://cn-ms.samsungapps.com (APK Server).\",\"web\":[\"https://support.samsungknox.com/hc/en-us/articles/115012547907-What-URLs-do-I-have-to-whitelist-to-make-Samsung-apps-work-with-an-authenticated-proxy-\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.knox.containerdesktop\",\"description\":\"Knox Container Desktop\\nProvides UI for the work(space) container? \\nSee \\\"com.samsung.android.knox.containeragent\\\"\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.knox.kpecore\",\"description\":\"Samsung KPECore\\nKPE stands for 'Knox Platform for Enterprise'\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.knox.mpos\",\"description\":\"Knox mPOS Enabler offers a range of security/usability features, enabling secure and contactless payments on Samsung devices.\\nhttps://play.google.com/store/apps/details?id=com.samsung.android.knox.mpos\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.knox.pushmanager\",\"description\":\"KnoxPushManager\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.knox.zt.framework\",\"description\":\"KnoxZT Framework\\nTo learn how you type, Touch Dynamics\\nwill collect and analyze sensor data while typing.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.livestickers\",\"description\":\"Deco Pic (accessible through AR Zone)\\nCamera app with stickers and snapchat-like filters\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.localeoverlaymanager\",\"label\":\"Locale Overlay Manager\",\"description\":\"Has overlays about FOTA updates, Cleaning up files, checking setup complete\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.location\",\"label\":\"slocation\",\"description\":\"Handles GPS queries for some Samsung (Galaxy) apps, such as Camera location tagging. Apps exclusively using raw GPS and/or Google Location API are unaffected.\",\"web\":[\"https://github.com/Universal-Debloater-Alliance/universal-android-debloater-next-generation/issues/762#issuecomment-2567149732\"],\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.lool\",\"label\":\"Device Care\",\"description\":\"While this package was suspected previously to send lots of data to Chinese servers it has since been debunked - only connects to Chinese server to retrieve database, but still sends some very basic data about the phone like model number, storage capacity, and a randomly generated identifier.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.samsung.android.lool\",\"https://www.reddit.com/r/Android/comments/el99r0/samsung_members_koreas_official_reply_has_arrived/\"],\"removal\":\"caution\",\"warning\":\"Disabling/Removing this package may remove the option to manage Power Saving, Fast Charging & Battery Protection on some devices.\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.mapsagent\",\"label\":\"Application recommendations\",\"description\":\"A lot of spying code. I guess it's an app from first-boot setup.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.mateagent\",\"description\":\"Samsung Galaxy Friends is an accessory platform service that allows the user to enjoy a variety of content quickly \\nand easily by simply connecting an accessory, without having to install additional applications.\\nhttps://developer.samsung.com/codelab/SDC18-experiences/Galaxy-Friends\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.mcfds\",\"label\":\"Continuity Service\",\"description\":\"Chat with other peoples. This app is available on Galaxy Store.\",\"web\":[\"https://galaxystore.samsung.com/prepost/000006390343?appId=com.samsung.android.mcfds\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.mcfserver\",\"label\":\"Samsung Multi Connectivity\",\"description\":\"See https://gitlab.com/W1nst0n/universal-android-debloater/-/issues/12\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.mdagent\",\"description\":\"MdAgent\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.mdecservice\",\"label\":\"Call & Message Continuity\",\"description\":\"Not 100% sure, but by looking at the decompiled Java/Dalvik/A.R.T. code it seems the app provides a way to receive call and SMS on Samsung accessories.\\nIn any case it is only useful for Samsung IoT stuff.\\nEmbeded Google Firebase analytics.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.mdm\",\"description\":\"MDMApp (Mobile Device Management app)\\nUsed to monitor and manage remotely  mobile devices.\\nFor example locking split-screen, blocking safe mode boot, enabling branding logo in the lock screen, remotely configuring IMAP email...\\nMost likely related to KNOX \\nhttps://www.samsungknox.com/en/solutions/it-solutions/knox-manage\\nhttps://developer.samsung.com/tech-insights/knox/mobile-device-management\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.mdx\",\"description\":\"Link to Windows Service\\nWorks in conjunction with the Microsoft Your Phone app and activates a connection to your PC on Windows\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.mdx.kit\",\"label\":\"S Share Connectivity\",\"description\":\"Previously, Mdx Kit Service, MDE Service Framework.\\nMDE = Multi Devices Experience.\\nFramework for IoT stuff.\\nAsks for a LOT of dangerous permissions\\nInteracts with \\\"com.samsung.android.mobileservice\\\" and \\\"com.osp.app.signin\\\"\",\"web\":[\"https://www.samsung.com/levant/multi-device-experience/\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.mdx.quickboard\",\"label\":\"Media and devices\",\"description\":\"Kind of a hub for managing the media played on smart devices (e.g play music to 2 Bluetooth devices simultaneously with Dual audio).\\nHas a lot of permissions and asks for ACCESS_COARSE_LOCATION, QUERY_ALL_PACKAGES.\",\"web\":[\"https://www.samsung.com/latin_en/support/mobile-devices/media-and-device-feature/\"],\"removal\":\"caution\",\"warning\":\"Removing this package does not prevent you to connect your phones to smart devices, but oddly enough causes the brightness slider in the notification panel to not be displayed in landscape orientation (it's still shown in portrait) on some devices.\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.mediacontroller\",\"description\":\"Ability to controls phone's audio from your watch.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.messaging\",\"description\":\"Samsung Messaging app\\n\",\"removal\":\"replace\",\"suggestions\":\"sms\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.messaging.extension.chn\",\"description\":\"MessagingExtensionCh\\nHas too much spying things.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.mfi\",\"label\":\"Galaxy Widget\",\"description\":\"Just shows you ads of some of Samsung's services or other apps/games.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.samsung.android.mfi\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.mobileservice\",\"label\":\"Group Sharing\",\"description\":\"Previously, Samsung Experience Service. The legacy version was similar to Samsung Core Services (citation needed).\\nCan remove safely if you don't use any group sharing features (shared albums in gallery, etc.).\\nHandles your Samsung account and is needed to use some Samsung apps features.\\nIt allows you to use Samsung apps, such as Samsung Health, Samsung Pay, Galaxy Apps, Samsung Members, and SmartThings with your Samsung account credentials.\",\"web\":[\"https://techshift.net/what-is-samsung-group-sharing/\"],\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.mocca\",\"description\":\"MoccaMobile\\nRequire google play services.\\nDiagnostics, logs, car crash, better remove this app.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.motionphoto.viewer\",\"label\":\"Motion photo viewer\",\"description\":\"Can only watch videos on it, also found diagmonagent logs.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.mtp\",\"description\":\"MTP application\\nIt doesn't cause a bootloop, but its highly not recommended to remove it.\\nThis app is needed for transfer files to PC/Phone.\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.net.wifi.wifiguider\",\"label\":\"Wi-Fi Tips\",\"description\":\"Shows a question-mark button next to Wi-Fi networks that failed to connect for any reason, providing info to fix the specific issue. It also has a dedicated Settings activity that lists all possible help-tips, accessible via the \\\"More tips\\\" button when reading a tip.\\nUpon reinstalling a notification pops up saying \\\"Analyzing Wi-Fi\\\" for a few seconds, no idea what it's doing.\",\"removal\":\"caution\",\"warning\":\"Removing the app makes it impossible to connect to a Wi-Fi network without a detected internet connection\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.networkdiagnostic\",\"description\":\"Network Diagnostic\\nAutostart after boot. 9 permissions (including ACCESS_FINE_LOCATION : precise GPS location) + 1 unknown permission : SEC_FACTORY_PHONE\\nSeems to be telemetry.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.networkstack\",\"label\":\"NetworkStackOverlay\",\"description\":\"I guess it's needed for wifi and it can be important app\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.networkstack.tethering.overlay\",\"description\":\"Found only wifi configs\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.oneconnect\",\"description\":\"Samsung Smart Things (https://play.google.com/store/apps/details?id=com.samsung.android.oneconnect)\\nLets you manage all your Samsung and SmartThings-compatible devices.\\nhttps://www.samsung.com/global/galaxy/apps/smartthings/\\n\\nProbably needs com.samsung.android.beaconmanager\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.packageinstaller\",\"description\":\"Removing it is Unsafe if there is no alternative.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.peripheral.framework\",\"description\":\"Peripheral Framework\\nIt's knox analytics.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.personalpage.service\",\"description\":\"Private mode (was replaced by Secure Folder)\\nhttps://www.samsung.com/uk/support/mobile-devices/what-is-private-mode-and-how-do-i-use-it/\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.photoremasterservice\",\"description\":\"PhotoRemasterService\\nIf removed, Photo Remaster in the gallery won't work.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.privacydashboard\",\"description\":\"Privacy dashboard in settings:\\nhttps://insights.samsung.com/2023/08/17/what-is-privacy-dashboard-and-how-does-it-protect-my-data-2/\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.privateshare\",\"description\":\"Blockchain-powered file sharing system for Samsung phones.\\nWhy blockchain? Because it's a nice buzzword! The privacy policy of this Samsung service is really bad: https://libreddit.spike.codes/r/privacy/comments/rqbb9b/samsung_private_share_is_not_so_private/\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.provider.filterprovider\",\"label\":\"com.samsung.android.provider.filterprovider\",\"description\":\"FilterProvider dependency to Samsung Camera\\nProvides access to filters (when you swipe right from the camera app)\",\"removal\":\"caution\",\"warning\":\"Samsung camera will crash if this package is deleted.\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.provider.shootingmodeprovider\",\"label\":\"ShootingModeProvider\",\"description\":\"Provide camera modes (when you swipe left from the camera app)\\nSafe to remove (but it is quite useful)\",\"removal\":\"replace\",\"suggestions\":\"cameras\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.provider.stickerprovider\",\"description\":\"One more package related to camera stickers.\\nDO NOT REMOVE THIS IF YOU USE STOCK CAMERA (Samsung camera-app closes after about 4s!) \\nadb shell 'pm disable-user com.samsung.android.provider.stickerprovider' can be used as a workaround if you want to stop this running in the background.\\n\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.providers.carrier\",\"label\":\"Configuration update\",\"description\":\"App for installing updates in order to get latest features for your SIM card.\\nIt is hard to say how useful this app is.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.providers.contacts\",\"label\":\"Samsung Contacts Storage\",\"description\":\"Likely same as com.android.providers.contacts, but for Samsung phones.\",\"removal\":\"caution\",\"warning\":\"Breaks messaging and calling services, as well as contact functionality.\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.providers.context\",\"description\":\"Spyware\\nhttps://www.eteknix.com/samsungs-context-service-may-take-data-collection-surveillance-worrying-levels/\\nhttps://www.theinquirer.net/inquirer/news/2328363/samsung-context-service-will-collect-user-data-to-share-with-developers\\nContent providers encapsulate data, providing centralized management of data shared between apps.\\nhttps://developer.android.com/guide/topics/providers/content-providers.html\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.providers.factory\",\"label\":\"FactoryTestProvider\",\"description\":\"It's used for diagnostics and factory hardware testing.\",\"removal\":\"caution\",\"warning\":\"Removal breaks hwmoduletest.\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.providers.media\",\"label\":\"Samsung Media Storage\",\"description\":\"Likely same as com.android.providers.media; scans the device for media files and allows permitted apps access to them.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.providers.trash\",\"label\":\"SecTrashProvider\",\"description\":\"Trash feature for Galaxy phones since One UI 6.0.\\nAllows users to delete and restore files from My Files, Gallery, Voice Recordings, etc. directly from the Trash folder in My Files.\",\"removal\":\"caution\",\"warning\":\"Removal breaks apps that delete to Trash.\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.rajaampat\",\"label\":\"Samsung Pay\",\"web\":[\"https://play.google.com/store/apps/details?id=com.samsung.android.rajaampat\"],\"description\":\"Samsung Pay Services for Indonesia.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.rampart\",\"description\":\"Auto Blocker\\nUses for blocking unknown apps install, commands.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.rlc\",\"description\":\"Samsung Biz Service\\nRemote Lock Control? Remote Mobile Manager? It has not needed notification components.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.rubin.app\",\"label\":\"Customization Service\",\"description\":\"Collects a massive amount of data: basically everything you do on your phone for \\\"a better user experience\\\".\\nUsed to display customized advertisements about products and services that may be of interest to you.\",\"web\":[\"https://www.samsung.com/us/account/customization-service/\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.samsungpass\",\"description\":\"Samsung Pass app\\nhttps://www.samsung.com/global/galaxy/apps/samsung-pass/\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.samsungpassautofill\",\"description\":\"Auto Fill for Samsung Pass\\nOnce your account information is registered, you can use iris, fingerprint, or face recognition to sign in.\\nhttps://www.samsung.com/us/support/answer/ANS00082282/\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.samsungpositioning\",\"description\":\"Run at startup and ask for an unknown permission SEC_FACTORY_PHONE\\nThis package seems to be used for samsung apps needing location.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.scloud\",\"description\":\"Samsung Cloud (https://www.samsung.com/us/support/owners/app/samsung-cloud)\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.scloud.auth\",\"label\":\"Samsung Cloud Data Relay\",\"description\":\"Handle authentication for Samsung cloud\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.scloud.backup\",\"description\":\"Samsung Backup only for Samsung Cloud\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.scloud.sync\",\"description\":\"Samsung cloud synchronisation service\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.sconnect\",\"label\":\"Quick connect\",\"description\":\"(Discontinued) In theory, it lets you connect your phone to a variety of devices over Wifi that support multiple protocols — including Wifi Direct and Miracast — to display photos, video or audio.\",\"web\":[\"https://www.samsung.com/uk/support/tv-audio-video/what-is-screen-mirroring-and-how-do-i-use-it-with-my-samsung-tv-and-samsung-mobile-device/\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.scpm\",\"description\":\"Samsung Cloud Platform Manager\\nRelated to Samsung Cloud. Safe to remove if you don't use it.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.scs\",\"label\":\"Samsung Core Services\",\"description\":\"For quick and easy provision of the main features used by Samsung applications through application updates rather than through the distribution of software updates.\\nProvides improved search, extraction, and intelligence features based on text and images. Used in various Samsung applications such as Camera, Gallery, Messages, Contacts, Settings, and Finder.\",\"web\":[\"https://galaxystore.samsung.com/prepost/000005514204\"],\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.sdk.handwriting\",\"description\":\"Handwriting Service\\nOnly for Samsung Note? \\nhttps://www.samsung.com/sg/support/mobile-devices/how-do-you-convert-handwriting-to-text-and-other-formats-using-s-pen-and-samsung-notes/\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.sdk.ocr\",\"description\":\"It's for OCR (Optical Character Recognition), used among Samsung apps like the gallery, without this, you can't extract text from images.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.sdk.professionalaudio.app.audioconnectionservice\",\"description\":\"AudioConnectionService\\nI believe it allows to modulate an audio signal. I didn't find a lot of apps using this package.\\nNothing really worrying but safe to remove if you want.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.sdk.professionalaudio.utility.jammonitor\",\"description\":\"Professional Audio\\nAllows you to create virtual instrument applications with Android.\\nhttps://developer.samsung.com/html/techdoc/ProgrammingGuide_ProfessionalAudio.pdf\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.sdk.spenv10\",\"description\":\"Samsung Pen engine, Pen settings, SPen Engine Update.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.sdm.config\",\"description\":\"Configuration Update for Samsung Deskphone Manager (SDM)\\nSDM allows a user to synchronize your smartphone with a IP deskphone\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.secsoundpicker\",\"label\":\"SecSoundPicker\",\"description\":\"Ringtone picker\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.securitylogagent\",\"label\":\"SecurityLogAgent\",\"description\":\"Runs in the background and monitors your device for any change to the system partition. It also listens for use of permissions by 3rd-party apps. This is a feature found in Security settings, named 'permission monitor'\\nNOTE: When you root your phone, it will constantly tell you that your device is modified.\",\"web\":[\"https://www.androidexplained.com/galaxy-note-9-disable-security-log-agent/\",\"https://samsung.com/levant/support/mobile-devices/what-is-app-permission-monitor-feature-and-how-to-turn-it-off\",\"https://howtogeek.com/332816/how-to-stop-samsungs-app-permission-monitor-from-displaying-notifications\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.server.iris\",\"label\":\"Iris\",\"description\":\"Provides iris recognition feature.\\nNOTE: removing this package causes biometric prompts in apps to be delayed by 5-8 seconds before appearing. Selecting 'Biometrics and security' in the settings app also locks up the Settings app for about 5-8 seconds but eventually loads and functions as normal.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.server.wifi.mobilewips\",\"label\":\"MobileWips\",\"description\":\"Detects suspicious activities on Wi-Fi.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.server.wifi.mobilewips.client\",\"description\":\"MobileWips\\nDetects suspicious activity on Wi-Fi network.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.service.health\",\"description\":\"Health Platform (https://play.google.com/store/apps/details?id=com.samsung.android.service.health)\\n\\nIt is a data aggregator. You can use it to link multiple health apps (like Strava, google fit etc) together. This app will unify their collected data and store them all together.\\nConstantly phones to Samsung servers.\\n\\nPithus analysis: https://beta.pithus.org/report/968364daf4fbb1828dfe9d8dbcce6d5f7f9a79522a5267c4be5bba19e6cd88b0\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.service.livedrawing\",\"description\":\"Live Message enables you to draw your own animated GIFs or emojis.\\nhttps://www.samsung.com/global/galaxy/what-is/live-message/\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.service.peoplestripe\",\"label\":\"People Edge\",\"description\":\"Gives you immediate access to your favorite contacts from the edge of your phone.\",\"web\":[\"https://www.samsung.com/global/galaxy/what-is/people-edge/\",\"https://videotron.tmtx.ca/en/topic/samsung_galaxys9/using_people_edge.html\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.service.stplatform\",\"label\":\"SmartThings Framework\",\"description\":\"I guess it's app for installing sponsored apps. Useless Framework.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.service.tagservice\",\"label\":\"Tags\",\"description\":\"Tags in Samsung Gallery app.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.service.travel\",\"description\":\"Samsung Travel Wallpaper (discontinued)\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.setting.multisound\",\"label\":\"Separate app sound\",\"description\":\"Used to split audio different apps between phone speaker and bluetooth speaker. Pretty handy.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.setupindiaservicestnc\",\"description\":\"Samsung Services\\nResponsible for the persistent notification after every system update if you don't agree to data collection.\\nThe only way to dismiss it without agreeing to anything is to click the small text and uncheck all the items in a list. Then the 'Agree' button becomes a 'Skip' button. Removing this package doesn't have any known side effects.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.shealthmonitor\",\"description\":\"Samsung Health Monitor\\n\\nEnables you to record ECG and blood pressure.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.shortcutbackupservice\",\"description\":\"ShortcutBNR \\nRelated to smartSwitch Samsung Cloud features\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.singletake.service\",\"label\":\"Single Take\",\"description\":\"It's face unlock I guess.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.slinkcloud\",\"description\":\"Samsung Cloud Gateway\\nNEEDED FOR Scloud app\\nA cloud storage gateway is designed to provide interoperability between different data protocols used \\nin a client (Scloud app)/server cloud architecture. \\nMORE INFO : https://searchstorage.techtarget.com/definition/cloud-storage-gateway\\n#\\nNeeds a lot of permission (including the dangerous one : READ_PHONE_STATE)\\nIt means the app has the ability to read the device ID (e.g. IMEI or ESN) and phone number.\\nhttps://developer.android.com/reference/android/Manifest.permission#READ_PHONE_STATE\\n#\\nHardcoded Alibaba (chinese) server IP (42.120.153.17) \\nhttps://www.hybrid-analysis.com/sample/2ef5367f700d2644fc51d2cdd8dd0ce97e9a6594cb5b89052537037c5a7aac56?environmentId=200\\nhttps://web.archive.org/web/20200604093347/https://www.hybrid-analysis.com/sample/2ef5367f700d2644fc51d2cdd8dd0ce97e9a6594cb5b89052537037c5a7aac56?environmentId=200\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.sm\",\"label\":\"Samsung Smart Manager\",\"description\":\"Provides pretty useless optimizing features using Chinese company Qihoo database.\\nAutomatically scans and optimizes data usage to preserve battery levels, manage storage and RAM\",\"web\":[\"https://www.privateinternetaccess.com/blog/android-community-worried-about-presence-of-chinese-spyware-by-qihoo-360-in-samsung-smartphones-and-tablets/\",\"https://forum.xda-developers.com/galaxy-note-9/help/samsung-services-dialling-home-to-china-t3894033\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.sm.devicesecurity\",\"description\":\"Samsung Device security for the Smart Manager app using McAfee antivirus engine.\\nThis is the antivirus in Settings -> Device care -> Security\\nPrivacy nightmare(LOTS of permissions!) for a bit of security.\\nhttps://www.hybrid-analysis.com/sample/05dab93ee2102a2fb6edf16e85750eb1f0189d7b82703c6a00c92cd08d62bb28?environmentId=200\\nARCHIVE: https://web.archive.org/web/20200607140002/https://www.hybrid-analysis.com/sample/05dab93ee2102a2fb6edf16e85750eb1f0189d7b82703c6a00c92cd08d62bb28?environmentId=200\\n\\nSome people reported that without this package they weren't able to install apps anymore BUT I personally removed this and\\nI still can install apps.\\nI think(not sure) that you can remove this safely if you also remove com.samsung.aasaservice and com.samsung.android.sm\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.sm.devicesecurity.tcm\",\"description\":\"Device security\\nChinese scanning app for searching viruses.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.sm.policy\",\"description\":\"SCPM (Samsung Cloud Platform Manager) client.\\nAllows the app to read data from the Samsung Cloud Platform Manager in order to authenticate your phone and configure your apps and services. Surely linked to Smart Manager. On some devices, the app icon is cloud-shaped.\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.sm.provider\",\"description\":\"Smart Manager Provider\\nSCPM Client? A lot debugging stuff\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.sm_cn\",\"description\":\"Device care but in Chinese Samsung phones\\nIs different from global, could break some important functions if removed.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.smartcallprovider\",\"label\":\"Samsung Smart Call\",\"description\":\"Provides caller profile information to help consumers identify incoming calls and block unwanted ones.\\nAlso related to the 'local places' feature in Samsung dialer.\\nRelies on Hiya (see com.hiya.star)\\nTL;DR : really bad for your privacy.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.smartface\",\"label\":\"SmartFaceService\",\"description\":\"Used to automatically detect faces when using the Samsung camera. It might be related to \\\"Keep screen on while viewing\\\" under Motions and gestures in Settings.\\nNOTE: This package has nothing to do with face unlock (com.samsung.android.bio.face.service).\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.smartface.overlay\",\"description\":\"Not needed overlay to smartface\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.smartfitting\",\"description\":\"Smart Fitting Service\\nAdapts the size/ratio of the screen. Automatic mode is default but there is a manual mode\\nhttps://www.samsung.com/levant/support/mobile-devices/galaxy-s8-s8-plus-what-is-the-smart-fitting-display-for-vod-games/\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.smartmirroring\",\"label\":\"Samsung Smart View\",\"description\":\"Enables you to mirror screen your phone to a TV.\",\"web\":[\"https://www.samsung.com/us/apps/smart-view-2/\"],\"removal\":\"replace\",\"required_by\":[\"com.samsung.android.video\"],\"type\":\"oem\"},{\"id\":\"com.samsung.android.smartprovider\",\"description\":\"Samsung File Provider\\nProvides intelligent classification, search and image/video favorite when selecting images/videos to send to friends/Moments/Channels in WeChat app.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.smartsuggestions\",\"label\":\"Smart suggestions\",\"description\":\"\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.smartswitchassistant\",\"description\":\"Samsung SmartSwitch\\nLets you transfer your data from your old (Samsung) phone to your new one.\\nNeeded for com.sec.android.easyMover?\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.softsim\",\"description\":\"Softsim Service\\nInstalls softsim and it's full Chinese.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.spay\",\"label\":\"Samsung Wallet\",\"description\":\"Also known as, Samsung Pay.\\nSamsung Pay is a mobile payment and digital wallet service by Samsung that lets users make payments using compatible phones and other Samsung-produced devices. Any personal information including transactions may be sold to third-party.\\nNOTE: Samsung Wallet is KNOX dependant and will never work again if you root your phone.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.samsung.android.spay\",\"https://en.wikipedia.org/wiki/Samsung_Pay\",\"https://www.sammobile.com/news/samsung-pay-new-privacy-policy-your-data-sold/\"],\"removal\":\"delete\",\"dependencies\":[\"com.sec.android.app.samsungapps\",\"com.samsung.android.spayfw\"],\"type\":\"oem\"},{\"id\":\"com.samsung.android.spayfw\",\"label\":\"Samsung Pay Framework\",\"description\":\"Framework for Samsung Wallet.\\nSamsung Pay is a mobile payment and digital wallet service by Samsung that lets users make payments using compatible phones and other Samsung-produced devices.\",\"removal\":\"delete\",\"required_by\":[\"com.samsung.android.spay\"],\"type\":\"oem\"},{\"id\":\"com.samsung.android.spaymini\",\"label\":\"Samsung Pay mini\",\"description\":\"Same service as Samsung Wallet but for online payments only and is available on all compatible android devices (not just Samsung devices).\",\"web\":[\"https://www.samsung.com/in/samsung-pay/mini/\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.spdclient\",\"description\":\"Security policy updates (part of KNOX)\\nUpdates the SELinux policies according to Security Enhancements for Android (SE for Android)\\nThere are privacy implications to the data collected by Samsung\\nhttps://security.stackexchange.com/questions/161190/does-samsungs-security-enhancements-for-android-offer-anything-for-consumers\\nNot mandatory if you know what you are doing and if you don't install software from unknown sources.\\nNeeds confirmation but removing this package could change SELinux mode (enforcing by default)\\nhttps://source.android.com/security/selinux\\n\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.spdfnote\",\"description\":\"Write on PDF (https://play.google.com/store/apps/details?id=com.samsung.android.spdfnote)\\nPDF annotator\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.sskds\",\"description\":\"SoterSskdsService\\nThis app has something to 'com.tencent.soter.soterserver'.\\nOnly china.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.stextclassifier\",\"description\":\"From https://developer.android.com/reference/android/view/textclassifier/TextClassifier:\\nInterface for providing text classification related features.\\n\\nThe TextClassifier may be used to understand the meaning of text, as well as generating predicted next actions based on the text.\\n\\nSo it got something to do with text/spelling correction? But a samsung implementation of it. It needs some further testing, so far it doesn't affect even the auto-correct.\\nNote: this app has no permission and doesn't run in background when not in used\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.stickercenter\",\"description\":\"Sticker center. Used to retrieve stickers from the web in the camera app.\\nhttps://developer.samsung.com/galaxy/stickers\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.stickerplugin\",\"description\":\"StickerPlugin\\nNot sure if this package also provides stickers for camera. I don't have it so I can't test\\nhttps://developer.samsung.com/galaxy/stickers\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.storage.watchstoragemanager\",\"description\":\"Storage manager. DO NOT REMOVE THIS\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.ststub\",\"label\":\"SmartThings\",\"description\":\"Allows users to control, automate, and monitor their home environment via mobile device.\",\"web\":[\"https://en.wikipedia.org/wiki/SmartThings\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.sume.nn.service\",\"description\":\"Provides the photo remaster feature in the Gallery app. Has the camera permission and can access all your medias but performs its job locally on the device.\\n\\nhttps://www.samsung.com/au/support/mobile-devices/remastering-photos-on-samsung-phone/\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.svcagent\",\"label\":\"SVC Agent\",\"description\":\"The APK has various icons in it + DiagMon library (telemetry). It has full access to internet and occasionally runs a MainService for many consecutive hours.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.svoice\",\"description\":\"Samsung Voice (S Voice) was replaced by bixby on Samsung Galaxy S8(+) and newer phones.\\nVirtual mobile personal assistant capable of running a  basic tasks through voice command alone.\\nhttps://www.samsung.com/global/galaxy/what-is/s-voice/\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.svoiceime\",\"description\":\"Samsung voice input \\nVoice input powered by Bixby. See above.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.tadownloader\",\"label\":\"TADownloader\",\"description\":\"Seems to check if a trusted application needs an update and downloads it. \\nThis package probably does more than that. There is a LOT of lines of code (obfuscated obviously)\\nIt was used to push an update to fix a security issue with the fingerprint sensor in 2019.\\nSeems to be only used for biometrics stuff\\nThere is Samsung analytics inside. You may want to remove it if you don't use biometrics authentication.\\n\",\"web\":[\"https://libredd.it/r/galaxys10/comments/bcy93f/adb_how_to_get_the_fingerprint_update_pushed_to/\"],\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.tapack.authfw\",\"label\":\"AuthFw TaPack\",\"description\":\"Authentication Framework for Trusted Application? (don't know what 'Pack' could mean)\\nHard to know what this app really does. Seems to be an assets provider used by com.samsung.android.tadownloader.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.tencentwifisecurity\",\"description\":\"Chinese Tencent flags risky networks and prevent to connect to them.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.themecenter\",\"label\":\"Galaxy Themes Service\",\"description\":\"Runs at startup and allows you to apply themes from \\\"com.samsung.android.themestore\\\". On some devices, it provides the built-in wallpaper images to the Theme Store.\\nIt will enable itself if you disable it, so try uninstalling (may throw an error).\\nHas of lot of permissions (including INTERNET and INSTALL_PACKAGES) and connects to Samsung domains for analytics.\",\"web\":[\"https://beta.pithus.org/report/973ba78ddd74a13dcf5268e980010a64ba42a3d2a1c4c62df277ead5a17cd10c\"],\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.themestore\",\"label\":\"Galaxy Themes\",\"description\":\"Forces you to login to a Samsung Account if you want to download ANY content (icons, wallpapers, themes, etc.). If you already downloaded something, you can apply it \\\"freely\\\".\\nNot needed for Wallpaper API, so any app (Samsung or not) can set Home & Lock wallpapers. However, on some devices, this app is required to view/apply built-in wallpapers (in that case, it requires \\\"com.samsung.android.themecenter\\\" service).\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.timezone.autoupdate_N\",\"description\":\"This app handles automatic updates for time zone information on Samsung devices, ensuring accurate timekeeping across different regions.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.timezone.autoupdate_O\",\"description\":\"Samsung Time Zone Updater\\nUsed to automatically detect appropriate timezone\\nREMOVING THIS WILL BOOTLOOP YOUR DEVICE\\n\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.timezone.data.P\",\"description\":\"Samsung timezone data?\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.timezone.data.updater\",\"description\":\"Samsung Time Zone Updater\\nUsed to automatically detect appropriate timezone.\\nA similar Samsung package apparently bootloops the device if removed, so be careful.\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.timezone.data_Q\",\"description\":\"Stores timezone data?\\n\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.timezone.updater\",\"description\":\"Time Zone Updater\\nUsed to detect or set timezone.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.tncpage\",\"description\":\"TNCPageCN\\nIt's app for enhance lock screen.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.tripwidget\",\"description\":\"Discontinued package (used in Galaxy S4) handling trip wallpaper widget.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.tzdata.update_M\",\"description\":\"Samsung Timezone Data Updater\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.uds\",\"description\":\"Ultra data saving\\nHave boring notifications and theres no point of keeping this app.\\nhttps://play.google.com/store/apps/details?id=com.samsung.android.uds\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.unifiedprofile\",\"label\":\"My Profile\",\"description\":\"Related to Samsung Members?\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.universalswitch\",\"description\":\"Universal Switch lets you designate certain touches or gestures to control specific actions on your phone. \\nhttps://www.samsung.com/uk/accessibility/mobile-universal-switch/\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.uwb\",\"label\":\"UwbApplication\",\"description\":\"It's used for SmartThings and new Smart Tags. This app is bloated.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.vdc\",\"description\":\"Virtual Device Center\\nIt's Chinese app for Video calls.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.vdcservice\",\"description\":\"This app depends on Virtual Device Center app.\\nHas network connection frameworks.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.video\",\"label\":\"Samsung Video Player\",\"dependencies\":[\"com.samsung.android.smartmirroring\"],\"description\":\"Default video Player for Samsung devices.\",\"web\":[\"https://galaxystore.samsung.com/prepost/000003980724?appId=com.samsung.android.video\"],\"removal\":\"replace\",\"suggestions\":\"video_players\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.visionarapps\",\"description\":\"\\\"AR apps\\\"\\nNot really sure what this is, but the icon is Bixby as an eye so I assume it's for accessing AR stuff through Bixby.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.visioncloudagent\",\"description\":\"VisionCloudAgent\\nCloud Agent is a service which automatically upload on the cloud the photos you take on your phone. It connects to your \\\"Samsung account\\\".\\nIt is related to Dropbox.\\nGiven the Vision in the package name there is a link with Bixby.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.visionintelligence\",\"description\":\"Bixby Vision\\nAugmented reality camera that can identify objects in real-time and potentially offer the user\\nto purchase them online, translate text, read QR codes, and recognize landmarks. \\nhttps://www.samsung.com/global/galaxy/apps/bixby/vision/\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.visualars\",\"description\":\"Smart Touch Call.\\nIt allows the user to \\\"Get voice and Screen interactive service when you call a customer service\\\".\\nBloated with Google API stuff\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.voc\",\"label\":\"Samsung Members\",\"description\":\"The other version is \\\"com.samsung.oh\\\".\",\"web\":[\"https://play.google.com/store/apps/details?id=com.samsung.android.voc\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.voicewakeup\",\"description\":\"Voice wake-up for using Bixby\\nhttps://www.samsung.com/us/support/answer/ANS00080448/\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.vtcamerasettings\",\"label\":\"Video call effects\",\"description\":\"Keep the focus on you during video calls by blurring the background or covering it with an image or color.\\nUnfortunately, only supports a few apps (Google Meet, WhatsApp, Zoom).\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.wallpaper.res\",\"description\":\"Pre-installed wallpapers\\nRemoving this package causes the background to be transparent (black, but the system will see it as white unless you use a custom wallpaper).\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.watch.alarm\",\"description\":\"Samsung Alarm app.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.watch.cameracontroller\",\"description\":\"Mirrors phone's camera to your watch. I can't find a use case for my usage. Safe to remove.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.watch.compass\",\"description\":\"Samsung Compass app.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.watch.findmyphone\",\"description\":\"The phone will start ringing, if connected to watch via BT or WiFi, when pressing 'start ringing' on the watch.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.watch.findmywatch\",\"description\":\"The watch will start ringing, if connected to phone via BT or WiFi, when pressing 'start ringing' on the phone. Also fetches location and is able to lock or factory reset.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.watch.flashlight\",\"description\":\"Samsung Flashlight\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.watch.runestone.app\",\"description\":\"Customization Service from Samsung. Provides customized content and recommendations. Collects a lot of personal information.\\nSee: https://www.samsung.com/us/account/customization-service/\\n\\nPithus analysis: https://beta.pithus.org/report/0f26752e636a9689bf0603e6023939e23a8cbd7197dea7b44c7ac93e2a930c24\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.watch.screencapture\",\"description\":\"Provides the ability to take screenshots from the smart watch.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.watch.stopwatch\",\"description\":\"Samsung Stopwatch\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.watch.timer\",\"description\":\"Timer app from Samsung.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.watch.watchface.analogmodular\",\"description\":\"Preinstalled watchface.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.watch.watchface.analoguefont\",\"description\":\"Preinstalled watchface.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.watch.watchface.animal\",\"description\":\"Preinstalled watchface.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.watch.watchface.aremoji\",\"description\":\"Preinstalled watchface.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.watch.watchface.basicclock\",\"description\":\"Preinstalled watchface.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.watch.watchface.basicdashboard\",\"description\":\"Preinstalled watchface.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.watch.watchface.bespoke\",\"description\":\"Preinstalled watchface.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.watch.watchface.bitmoji\",\"description\":\"Preinstalled watchface.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.watch.watchface.boldindex\",\"description\":\"Preinstalled watchface.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.watch.watchface.companionhelper\",\"description\":\"Watchfaces fail to load without this. Removing it also breaks editing and changing watchfaces.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.watch.watchface.digitalfont\",\"description\":\"Preinstalled watchface.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.watch.watchface.digitalmodular\",\"description\":\"Preinstalled watchface.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.watch.watchface.dualwatch\",\"description\":\"Preinstalled watchface.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.watch.watchface.dynamicfont\",\"description\":\"Preinstalled watchface.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.watch.watchface.emergency\",\"description\":\"Watchface in the emergency launcher.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.watch.watchface.gradientfont\",\"description\":\"Preinstalled watchface.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.watch.watchface.healthmodular\",\"description\":\"Preinstalled watchface.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.watch.watchface.infomodular\",\"description\":\"Preinstalled watchface.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.watch.watchface.large\",\"description\":\"Preinstalled watchface.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.watch.watchface.livewallpaper\",\"description\":\"Preinstalled watchface.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.watch.watchface.mypebble\",\"description\":\"Preinstalled watchface.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.watch.watchface.myphoto\",\"description\":\"Preinstalled watchface.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.watch.watchface.mystyle\",\"description\":\"Preinstalled watchface.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.watch.watchface.premiumanalog\",\"description\":\"Preinstalled watchface.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.watch.watchface.simpleanalogue\",\"description\":\"Preinstalled watchface.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.watch.watchface.simpleclassic\",\"description\":\"Preinstalled watchface.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.watch.watchface.simplecomplication\",\"description\":\"Preinstalled watchface.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.watch.watchface.superfiction\",\"description\":\"Preinstalled watchface.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.watch.watchface.tickingsound\",\"description\":\"Ticking sound on watchfaces that support it.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.watch.watchface.together\",\"description\":\"Preinstalled watchface.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.watch.watchface.typography\",\"description\":\"Preinstalled watchface.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.watch.watchface.weather\",\"description\":\"Preinstalled watchface.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.watch.weather\",\"label\":\"Weather\",\"description\":\"Weather application from Samsung.\",\"removal\":\"replace\",\"suggestions\":\"weather_apps\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.watch.worldclock\",\"description\":\"Worldclock app. This also includes a widget, displaying time in different time zones.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.wcmurlsnetworkstack\",\"description\":\"China URL connection. generate_204 (it's only config, not sure if it's needed for checking wifi connection)\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.wcs.exstention\",\"description\":\"Samsung Internet Extensions\\nSamsung Internet for Android allows users to customize their browsing experience by installing extensions, which are additional software packages that add new features and functionality to the browser and help developers offer tailored services to users on mobile devices.\\n\\nNOTE: Disabling this broke the UI on my Watch5 for some reason so PROCEED WITH CAUTION.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.wear.blockednumber\",\"description\":\"Blocked number storage. Doesn't affect the dialer or contacts.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.wear.contacts.sync\",\"description\":\"Handles 'open on phone' events. Also, settings often crash when this is uninstalled.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.wear.musictransfer\",\"description\":\"Used to sync music with the watch.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.wear.shealth\",\"description\":\"Samsung Health app for WearOS.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.wearable.samsungaccount\",\"description\":\"Samsung account settings. Breaks settings app if uninstalled.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.wearable.setupwizard\",\"description\":\"Samsung Wearable Setup Wizard\\nThe first time you turn your device on, a Welcome screen is displayed. It guides you through the basics of setting up your device.\\nIt's the setup for Samsung services.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.weather\",\"label\":\"Samsung weather forecast\",\"description\":\"Unified Daemon app. Named \\\"Weather\\\" on some Samsung Galaxy devices.\\nProvides support for a number of different apps on your device. These include the Weather, Yahoo Finance and Yahoo News apps amongst others. The data is used by apps such as the Alarm, Calendar app and the Camera (including the \\\"Scan QR code\\\" Quick-Panel tile). If the display-name is \\\"Weather\\\", it doubles as the Samsung Weather app, which provides weather widgets.\",\"removal\":\"replace\",\"suggestions\":\"weather_apps\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.wellbeing\",\"description\":\"Digital Wellbeing\\nThat's an app for device and app usage tracking and limiting.\\nhttps://galaxystore.samsung.com/prepost/000004807357\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.widget.pictureframe\",\"description\":\"Samsung gallery widget, shows your selected photos as widget\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.widgetapp.yahooedge.finance\",\"description\":\"Special edge panel widget for Yahoo Finance\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.widgetapp.yahooedge.sport\",\"description\":\"Special edge panel widget for Yahoo Sport\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.wifi.ai\",\"description\":\"No activities, provides WiFi diagnostics, has several ai models that it is not clear how useful they are.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.wifi.decrease.scan.interval.resources\",\"description\":\"Needed for WiFi.\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.wifi.h2e.resources\",\"description\":\"needed for wifi, has config values for that\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.wifi.increase.scan.interval.resources\",\"description\":\"Needed for WiFi.\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.wifi.p2paware.resources\",\"description\":\"Related to WiFi Direct\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.wifi.resources\",\"description\":\"Needed for WiFi.\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.wifi.resources.qc\",\"description\":\"Needed for WiFi.\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.wifi.resources.wifilock\",\"description\":\"Needed for WiFi.\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.wifi.softap.resources\",\"description\":\"Needed for Wi-Fi.\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.wifi.softapwpathree.resources\",\"description\":\"\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.wifi.wapi.resources\",\"description\":\"Needed for WiFi.\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.samsung.android.wifinetworkdiagnostics\",\"description\":\"WifiNetworkDiagnostics\\nDiagnostics network connection.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.app.highlightplayer\",\"description\":\"Samsung Story Video Editor\\nLets you edit your videos stories \\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.app.jansky\",\"description\":\"Multi-lines settings\\nLets you have multiple virtual phone numbers.\\nThis feature is only available on some US carrier-locked devices\\nhttps://www.reddit.com/r/GalaxyS8/comments/6esiub/tmobile_s8s8_multiline_setting_is_awesome/did2pur/\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.app.newtrim\",\"label\":\"Editor Lite\",\"description\":\"Formerly, Samsung Video Trimmer.\\nLets you quickly trim video files (from the gallery “Edit -> Studio -> Video Trimmer”). This trimmer is both imprecise and inaccurate, ffmpeg is much better.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.samsung.app.slowmotion\",\"description\":\"Slowmotion mode in camera app\\n\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.samsung.attribution\",\"description\":\"Related to data collection (?):\\nhttps://developer.samsung.com/galaxy-store/galaxy-store-statistics/user-attribution.html\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.carrier.logcollector\",\"description\":\"it's the same like diagmonagent, collects dumplogs\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.chn.apps.devicemanagement\",\"description\":\"AutoLoginService\\nRegister device with China Telecom. Only for China.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.clipboardsaveservice\",\"description\":\"Clipboard Save service saves all the content you saved in the clipboard (clipboard history)\\nIf you remove this you will still be able to copy/cust/past but a new content in clipboard will replace the current content.\\nIn short : there will no longer be a history.\\n\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.samsung.cmfa.AuthTouch\",\"description\":\"Continuous Multi-Factor Authentication AuthTouchService\\nRelated to `com.samsung.android.cmfa.framework`.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.samsung.cmh\",\"description\":\"CMH Provider is a dependency for the the samsung gallery app. This package asks for a lot of permissions. \\nIt seems to be be used for cloud and story stuff in the gallery and also seems needed for content recognition.\\nHas the same shared user id as com.samsung.faceservice, com.samsung.mlp, com.samsung.mpl\\n \\nNOTE : On some phone models, deleting this package can also prevent to preview photos from the camera app.\\nSeems to trigger com.samsung.faceservice, com.samsung.mlp, com.samsung.mpl when needed.\\n\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.samsung.commonimsservice\",\"description\":\"Stat notify volte\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.samsung.crane\",\"description\":\"Call+ (https://support.vodafone.co.uk/Vodafone-apps/Call-and-Message/60900956/What-is-Call.htm)\\nCall+ features on Samsung dialer\\nNOTE: I have the feeling that these features are carrier/country dependant because I don't have them. But I have this package anyway.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.daydream.customization\",\"description\":\"Samsung customization for Google Daydream VR headset (https://arvr.google.com/daydream/)\\nNOTE : Google discontinued Daydream in 2019 and it no longer works on Android 10 Samsung devices\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.dcmservice\",\"description\":\"Hard to find what it really does but I do know what DCM is in telecommunication. It means Dual Carrier Modulation.\\nTo stay simple, we use signal modulation to transfer information. DCM can be seen as an enhancement to conventional QPSK modulation\\nthat expand the coverage and robustness of an outdoor hotspot.\\nhttps://www.ekahau.com/wp-content/uploads/2017/03/Webinar-slides-802.11ax-Sneak-Peek-%E2%80%93-The-Next-Generation-Wi-Fi.pdf\\nNot a good idea to remove this unless it only impacts samsung apps. Need testing.\\n\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.samsung.desktopsystemui\",\"label\":\"Samsung DeX System UI\",\"description\":\"Extends your smartphone into a \\\"desktop computing experience\\\".\",\"web\":[\"https://developer.samsung.com/samsung-dex/how-it-works\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.discover\",\"description\":\"It shows up as a pane on OneUI home and prompts you to install all sorts of random apps. OneUI works perfectly fine if you uninstall these and simply removes the discover pane.\",\"removal\":\"delete\",\"required_by\":[\"com.samsung.discover.sep\"],\"type\":\"oem\"},{\"id\":\"com.samsung.discover.sep\",\"description\":\"Related to `com.samsung.discover` but doesnt seem to do much on its own. Safe to remove without any effect.\",\"removal\":\"delete\",\"dependencies\":[\"com.samsung.discover\"],\"type\":\"oem\"},{\"id\":\"com.samsung.ecomm\",\"label\":\"Shop Samsung\",\"description\":\"App where you can buy all (and only) Samsung products.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.samsung.ecomm\",\"https://www.samsung.com/us/explore/shop-samsung-app/\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.ecomm.global.in\",\"description\":\"Samsung Shop (https://play.google.com/store/apps/details?id=com.samsung.ecomm)\\nApp where you can buy all (and only) Samsung products.\\nhttps://www.samsung.com/us/explore/shop-samsung-app/\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.emergencyreporthelper\",\"description\":\"Only for KOREA emergency report.\\nAlso no activities, only warn.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.enhanceservice\",\"description\":\"Enhanced service is the process for Samsung cloud messaging (equivalent to iMessage on iOS).\\nMessages on Samsung phones can be transmitted through either the network carrier or the non-archived Samsung service \\n(which is transmitted over wireless data).\\nThis features is available in stock samsung SMS app settings.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.euicc\",\"label\":\"SamsungEuiccService\",\"description\":\"eUICC refers to the architectural standards published by GSMA or implementations of those standard for eSIM, a device used to securely store one or more SIM card profiles, which are the unique identifiers and cryptographic keys used by service providers to uniquely identify and securely connect to mobile network devices.\",\"web\":[\"https://en.wikipedia.org/wiki/EUICC\"],\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.samsung.faceservice\",\"description\":\"Face service detection\\nAnalyzes all the photos in the Samsung Gallery to detect human faces using Samsung’s built-in face detection technology. Once FaceService identifies that the photo contains a face, it shows a button that allows users to add name tags to the photo and create a People Album of similar photos by selecting the name tag.\\n\\nSame shared user id as com.samsung.ipservice, com.samsung.mlp, com.samsung.cmh\\nNeeded for face recognition in the Gallery\\nNOTE : Removing this package does not break face unlock\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.felicalock\",\"description\":\"FeliCa Password NFC things, not needed\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.fresco.logging\",\"description\":\"Fresco Logging Service\\nFresco is an android library for managing images and the memory they use (https://github.com/facebook/fresco)\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.gamedriver.ex2100\",\"label\":\"Samsung Exynos2100 GameDriver\",\"description\":\"\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.samsung.gamedriver.sm8250\",\"label\":\"Samsung SM8250 GameDriver\",\"description\":\"\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.samsung.gamedriver.sm8550\",\"label\":\"Samsung SM8550 GameDriver.\",\"description\":\"\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.samsung.gpuwatchapp\",\"label\":\"GPUWatch\",\"description\":\"In this app, I only found GPU dumping mode, dev mode, game debugging. Useless.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.groupcast\",\"description\":\"Samsung Group Play (discontinued)\\nAllows you to share pictures , documents and music files with many people at same time  if everyone is connected to a Wi-Fi network. \\nhttps://www.samsung.com/in/support/mobile-devices/what-is-group-play-in-samsung-smartphones/\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.helphub\",\"description\":\"Not sure if this package still exist.\\nProvide help \\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.hidden.china\",\"description\":\"China Hidden Menu\\nLast call, secret code: 319712358.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.hiddennetworksetting\",\"description\":\"Set of hidden network settings (inlcuding frequency band choice).\\nHow to see these settings: https://forum.xda-developers.com/galaxy-note-8/help/q-hidden-network-settings-pie-t3914421/page4\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.samsung.hongbaoassistant\",\"description\":\"Hongbao Assistant\\nChinese app.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.hs20provider\",\"description\":\"only found useless hotspot logs\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.huxplatform\",\"description\":\"\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.samsung.ims.smk\",\"label\":\"SimMobilityKit\",\"description\":\"VoLTE calling, IMS.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.samsung.inputshare\",\"description\":\"MultiControl\\nIts use is to connect 2 devices and control one with the other.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.internal.systemui.navbar.gestural_no_hint\",\"description\":\"Gestural Navigation Bar\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.samsung.internal.systemui.navbar.gestural_no_hint_extra_wide_back\",\"description\":\"\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.samsung.internal.systemui.navbar.gestural_no_hint_narrow_back\",\"description\":\"\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.samsung.internal.systemui.navbar.gestural_no_hint_wide_back\",\"description\":\"\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.samsung.internal.systemui.navbar.sec_gestural\",\"description\":\"Gestural Navigation Bar\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.samsung.internal.systemui.navbar.sec_gestural_no_hint\",\"description\":\"Gestural Navigation Bar\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.samsung.ipservice\",\"description\":\"Set of hidden network settings (inlcuding frequency bands choice)\\nHow to see these settings : https://forum.xda-developers.com/galaxy-note-8/help/q-hidden-network-settings-pie-t3914421/page4\\n\\nSame shared user id as com.samsung.faceservice, com.samsung.mlp, com.samsung.cmh\\nUsed by Galaxy Finder & Galaxy Vision to access web data\\nDo removing this package break face/content recognition?  \\n#\\nName and permissions of this package suggest that it is used by Galaxy Finder to seek stuff on the web.\\nSame shared user id as com.samsung.faceservice, com.samsung.mlp, com.samsung.cmh\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.japan.initonce\",\"description\":\"InitOnce\\nI found in code only name app\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.klmsagent\",\"label\":\"KLMS Agent\",\"description\":\"Checks the validity of your KLM/KPE (Knox Licence Manager) license.\\nThis package is needed for Samsung Health (\\\"com.sec.android.app.shealth\\\") and probably all Knox-related apps (like Secure Folder, Samsung Pay...)\\n\\nNote: KLM licences are deprecated. Samsung now only supports KPE (Knox Platform for Enterprise) keys.\\nKPE keys are provided by Samsung and enable app's developers to access knox features.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.knox.appsupdateagent\",\"description\":\"This app is part of Samsung Knox, managing updates for apps within the Knox security framework.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.samsung.knox.keychain\",\"description\":\"Knox Key Chain\\nAllows apps to sign data using system-wide private key/certificate pairs. \\nSo, even though the Android Keystore provides per-app access to credentials, the Android KeyChain runs as a system user, \\nand hence, credentials stored through the Android KeyChain are associated with the system ID instead of a user ID.\\nhttps://docs.samsungknox.com/dev/knox-sdk/about-keystores.htm\\nThis is only useful for apps using the TIMA Keystore. The big question I'm trying to answer is:\\nWhich are using this except Samsung apps? Can an android dev help on this?\\n\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.samsung.knox.knoxtrustagent\",\"description\":\"Knox Quick Access allows users to access the Knox Workspace container using wearables such as the Galaxy Gear S2.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.knox.kss\",\"description\":\"Knox Keyguard. Not much more information\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.knox.rcp.components\",\"description\":\"Knox Content Mgr\\nSecurity-related. Knox Content Mgr\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.knox.securefolder\",\"label\":\"Secure Folder\",\"description\":\"Create a secure space on your device to encrypt and store your private data and apps.\\nNOTE: The key used to encrypt the files is not derived from the password you use to unlock the secure folder but rather from a key stored in the hardware that is set in the factory.\",\"web\":[\"https://www.samsungknox.com/en/solutions/personal-apps/secure-folder\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.knox.securefolder.setuppage\",\"description\":\"Provides the setup process when opening secure folder (com.samsung.knox.securefolder) for the first time\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.locationhistory\",\"description\":\"It's only location logs\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.logwriter\",\"description\":\"LogWriter\\nWrites data in a logs SQL database.\\nRuns at boot and is triggered when an download from an Iron Source (Iron Source is an Israeli advertising company)\\napp is completed (probably \\\"com.aura.oobe.samsung\\\")\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.mdl.radio\",\"description\":\"Samsung Milk Music (discontinued in 2016)\\nIt was a freemium online music streaming service, with music streams and a recommendation engine powered by Slacker Radio.\\nhttps://en.wikipedia.org/wiki/Milk_Music_(streaming_service)\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.mdl.radio.radiostub\",\"description\":\"Milk Music (shut down by Samsung)\\nIt was a music streaming app\\nhttps://en.wikipedia.org/wiki/Milk_Music_(streaming_service)\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.memorysaver\",\"description\":\"Helps you to free up space by letting you delete duplicates and move contents and apps on an SD card.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.samsung.mlp\",\"description\":\"Samsung content recognition.\\nmpl= Media Learning Platform. Has permissions linked to com.samsung.cmh and com.samsung.android.visionintelligence\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.mobiletv\",\"description\":\"Hidden testing mobiletv\\nhttps://apkcombo.com/pt/mobiletv/com.samsung.mobiletv/\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.networkui\",\"description\":\"User interface of the Mobile Network settings\\n\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.samsung.oda.service\",\"description\":\"SamsungOdaService\\nRequires google play services.\\nAnother spying app collects sim info and other things.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.oh\",\"description\":\"Samsung Members (https://play.google.com/store/apps/details?id=com.samsung.oh)\\nSamsung community. It's a kind of social media app for Samsung users.\\nhttps://www.samsung.com/global/galaxy/apps/samsung-members/\\nOOOPS ! https://bgr.com/2019/10/31/samsung-members-dong-pic-oops/\\nThe other version is \\\"com.samsung.android.voc\\\".\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.packageinstalleroverlay\",\"description\":\"Most likely the overlay that appears when you installed an application.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.samsung.phone.overlay.common\",\"description\":\"Possibly the incoming-call screen?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.samsung.pregpudriver.ex2100\",\"label\":\"Galaxy Pre GPUDriver\",\"description\":\"\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.samsung.preloadapp\",\"description\":\"Install app\\nInstalls recommended apps.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.qosindicator\",\"label\":\"QoSIndicator\",\"description\":\"QOS - quality of service, but it's only for diagnostics.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.rcs\",\"description\":\"RCS (Rich Communication Services)\\nHas permissions linked to com.samsung.cmh, and com.samsung.android.visionintelligence (and I don't understand why).\\nRCS is a communication protocol between mobile telephone carriers and between phone and carrier, aiming at replacing SMS.\\nhttps://en.wikipedia.org/wiki/Rich_Communication_Services\\nUses IP protocol, so it needs an internet connection.\\nIt's a hot mess right now. It aims at being universal but only exists in Samsung Messages and Google Messages, because Google hasn't released a public API yet, so 3rd-party apps can't support it.\\nIn a lot of countries messages go through Google's Jibe servers.\\nhttps://jibe.google.com/policies/terms/\\nhttps://pocketnow.com/why-you-should-probably-avoid-googles-rcs-text-messaging-chat-feature\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.safetyinformation\",\"label\":\"Safety Information\",\"description\":\"Safety information telling you to be careful with the usage of your phone.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.sait.sohservice\",\"label\":\"SoHService\",\"description\":\"FactoryApp\\nThis weird app collects battery data and probably others, who knows? Also to test battery things such as set voltage, Soc, temperature, status, timestamp.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.samsungpssdplus\",\"description\":\"Samsung Magician\\nhttps://play.google.com/store/apps/details?id=com.samsung.samsungpssdplus\\nAllows users to conveniently manage their Samsung Portable SSD settings.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.sdm\",\"description\":\"Handles OTA system Updates.\\n\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.samsung.sdm.sdmviewer\",\"description\":\"Lets you view installed updates?\\n\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.samsung.sec.android.application.csc\",\"description\":\"Do something related to Country Specific Code (CSC). Maybe it only let you change your CSC\\nEvery Android device from Samsung has a folder called CSC.\\nThis folder contains some XML files that keep the configuration codes for the country and carrier-based customization options.\\nMaybe it's safe to remove if you'll never change your CSC but it needs testing and I lack time for this.\\n(I already have plenty of other packages uninstallation to test)\\n\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.samsung.sec.android.teegris.tui_service\",\"label\":\"TEEgrisTuiService\",\"description\":\"Security-related, but not necessary.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.sec.mtv\",\"description\":\"Hidden testing mobiletv\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.slsi.audiologging\",\"label\":\"AudioLogging\",\"description\":\"It's hidden Audio logging.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.slsi.telephony.silentlogging\",\"description\":\"Hidden network logging. Safe to remove\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.ssu\",\"description\":\"Network Unlock\\nNetwork unlock? It's needed for SIM probably.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.samsung.storyservice\",\"description\":\"Samsung StoryService\\nCreate stories in the Gallery from your pictures and videos.\\nhttps://www.samsung.com/uk/support/mobile-devices/what-is-video-collage-and-how-do-i-use-it/\\nUse of content recognition (so may be related)\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.svoice.sync\",\"description\":\"Samsung Voice service\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.systemui.bixby\",\"description\":\"System UI for Bixby/Bixby2\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.systemui.bixby2\",\"description\":\"System UI for Bixby/Bixby2\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.tmovvm\",\"description\":\"Samsung Visual Voicemail (for T-mobile only)\\nAllows you to review and manage your voicemail directly from your smartphone, eliminating the need to dial into your mailbox.\\nhttps://mobile.spectrum.com/support/article/360001296667/samsung-visual-voicemail\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.tmowfc.wfcpref\",\"description\":\"Wifi Calling for T-mobile clients only! (tmowfc = t-mobile only wifi calling)\\nLets you call or text on Wi-Fi networks with your T-Mobile phone number\\nhttps://www.t-mobile.com/support/coverage/wi-fi-calling-from-t-mobile\\nVoLTE/IMS is needed for this to work (see com.sec.imsservice)\\n\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.samsung.ucs.agent.boot\",\"label\":\"bootagent\",\"description\":\"UCS is a company which has partnered with Samsung to provide licenses for Samsung Knox.\\nI don't have precise information about the package itself but there are chances that it verifies some files on boot. If these files are not verified then it may prevent the phone from booting.\",\"web\":[\"https://www.ucssolutions.com/blog/samsung-knox/\"],\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.samsung.ucs.agent.ese\",\"description\":\"eSE UCS Plugin is another package from UCS. It makes possible for apps to access eSE of Samsung mobile devices by using the UCM \\n(Universal Credential Management) APIs and framework.\\nhttps://docs.samsungknox.com/dev/knox-sdk/faqs/general/what-is-universal-credential-management_-ucm.htm\\nhttps://www.samsung.com/semiconductor/security/ese/\\nSee above\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.ucs.ucspinpad\",\"description\":\"UcsPinpad\\nIn this app u can setup pin,puk\\nUCS is a company which has partnered with Samsung to provide licenses for Samsung Knox\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.unifiedtp\",\"description\":\"Unified tethering provisioner. Tethering still works for me without it.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.samsung.upsmtheme\",\"description\":\"Handle the theme of UPSM (Ultra Power Saving Mode)\\nSafe to remove\\n\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.samsung.visionprovider\",\"label\":\"VisionProvider\",\"description\":\"Provider for Bixby Vision (com.samsung.android.visionintelligence)\\nManages access to data stored by itself, stored by other apps, and provide a way to share these data with other apps.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.vklayer.sm8250\",\"label\":\"Samsung SM8250 VKLayer\",\"description\":\"Vulkan GPU driver for SM8250\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.samsung.vklayer.sm8350\",\"label\":\"Samsung SM8350 VKLayer\",\"description\":\"Vulkan GPU Driver for SM8350\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.samsung.voiceserviceplatform\",\"description\":\"Samsung Voice (for Galaxy S7)\\nVirtual mobile personal assistant capable of running basic tasks through voice\\nhttps://www.samsung.com/global/galaxy/what-is/s-voice/\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.vvm\",\"description\":\"Samsung Verizon Voicemail\\nAllows you to review and manage your voicemail directly from your smartphone, eliminating the need to dial into your mailbox.\\nYou can scroll through your messages, pick the ones you want to listen to, and erase them right from your device's screen.\\nhttps://mobile.spectrum.com/support/article/360001296667/samsung-visual-voicemail\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.samsung.vvm.se\",\"description\":\"Samsung Verizon Voicemail \\nAllows you to review and manage your voicemail directly from your smartphone, eliminating the need to dial into your mailbox.\\nYou can scroll through your messages, pick the ones you want to listen to, and erase them right from your device's screen.\\nhttps://mobile.spectrum.com/support/article/360001296667/samsung-visual-voicemail\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.satispay.promotion\",\"label\":\"Satispay Promotion\",\"description\":\"Cashbacks and promotional related app\",\"web\":[\"https://beta.pithus.org/report/d2aced319e53ccf9de03b47be1bdb11bfb6b1ccd0cc15e5279e34697e23db338\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.scanning.agold.agoldscanning\",\"description\":\"\\\"Scan\\\" Settings > intelligent assistant: Scan. QR code & Bar code scanner.\\n\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.scee.psxandroid\",\"description\":\"PlayStation app\\nhttps://play.google.com/store/apps/details?id=com.scee.psxandroid\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.scorpio.securitycom\",\"description\":\"SecurityPlugin\\nIt cant be uninstalled.\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.sec.allsharecastplayer\",\"description\":\"Screen Mirroring (only in Galaxy S6)\\nCast your mobile screen to a TV.\\nhttps://www.samsung.com/us/2012-allshare-play/\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.android.AutoPreconfig\",\"description\":\"Auto Preconfig\\nTells you to format the device when sim from other country is used basically (won't let you use another one)\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.android.CcInfo\",\"description\":\"CcInfo\\nSamsung logs/analytics.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.android.Cdfs\",\"label\":\"CDFS MODE Launcher\",\"description\":\"It's CdfsService Probably needed for usb mtp\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.sec.android.GeoLookout\",\"description\":\"Geo News\\nfor korea or japanese\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.android.Preconfig\",\"description\":\"On some phones founded testing things menu and on some not found any hidden menu\\nbut it's app for secret codes to testing hardware things\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.android.RilServiceModeApp\",\"description\":\"Service mode RIL hidden app. Used for debug and diagnostics\\ndial *#0011# for modem connectivity info, *#9090# for diagnostics control\\n#\\nRIL means Radio Interface Layer. It's the bridge between Android phone framework services and the hardware.\\nhttps://wladimir-tm4pda.github.io/porting/telephony.html\\nhttps://stackoverflow.com/questions/11111067/how-does-modem-code-talk-to-android-code\\nSamsung RIL is a add on from Samsung : Modem <=> Linux kernel <=> libsamsung-ipc <=> Samsung-RIL <=> Android framework <=> Android applications\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.android.app.DataCreate\",\"description\":\"Automation Test\\nAnother hidden test app. A lot of mention of samsung note (memo). Has access to basically everything on the phone\\nRelated to these hidden menus (accessible by typing these codes in the samsung dialer) :\\n- *#3282*727336*# (Status of data usage) \\n- *#273283*255*3282*# (Data create menu) \\n- *#*#273283*255*663282*#*#* (Backup all media files)\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.android.app.SecSetupWizard\",\"label\":\"Samsung SetupWizard\",\"description\":\"The first time you turn your device on, a welcome screen is displayed. It guides you through the basics of setting up your device. It's the setup for Samsung services.\",\"removal\":\"caution\",\"warning\":\"Both \\\"com.sec.phone\\\" & \\\"com.sec.android.app.SecSetupWizard\\\" must be enabled to be able to add new eSIMs to device. Otherwise, the menu will spin indefinitely.\",\"type\":\"oem\"},{\"id\":\"com.sec.android.app.aftersalecamera\",\"description\":\"Calibration Camera app.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.android.app.apex\",\"label\":\"Samsung ApexService\",\"description\":\"Enables taking motion photos and provides a motion photos player/viewer, also does face recognition in the gallery app.\",\"web\":[\"https://www.samsung.com/global/galaxy/what-is/motion-photo/\"],\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.sec.android.app.applinker\",\"description\":\"Related to FeliCa Networks (https://en.wikipedia.org/wiki/FeliCa / https://www.felicanetworks.co.jp/en/).\\nFeliCa is contactless RFID smart card system mainly used for wallet function on mobile devices\\n#\\nHas the permission INSTALL_PACKAGES\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.android.app.bcocr\",\"description\":\"Business card recognition\\nSomething about business cards\\nnot very useful\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.android.app.billing\",\"description\":\"Samsung billing/Checkout\\nUsed to purchase apps through Samsung Store application that is delivered with Samsung phones. \\nActs as bridge between Samsung Store and payment servers.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.android.app.bluetoothagent\",\"description\":\"Bluetooth Agent\\nBluetooth test service.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.android.app.bluetoothtest\",\"label\":\"BluetoothTest\",\"description\":\"Hidden feature accessible by entering *#*#232331#*#* in the Samsung dialer.\\nIt was found to be calling home back in 2015.\",\"web\":[\"https://forum.xda-developers.com/galaxy-s5/help/bluetoothtest-apk-calling-home-t3035182\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.android.app.camera\",\"description\":\"Samsung camera app\\nSafe to remove (but not recommended)\\n\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.sec.android.app.camerasaver\",\"description\":\"Weird app that has BootCameraService. Probably you can't uninstall it.\\nIn the code found things: createCameraPreviewSession, generateTextureIds, openCamera, setUpCameraOutputs.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.sec.android.app.chromecustomizations\",\"description\":\"Samsung stuff on the homepage of Google Chrome\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.android.app.clockpackage\",\"description\":\"Samsung clock\\n\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.sec.android.app.desktoplauncher\",\"label\":\"Samsung DeX Home\",\"description\":\"DeX Enables users to extend their device into a desktop-like experience by connecting a keyboard, mouse, and monitor.\\n\\\"DeX\\\" is a contraction of \\\"Desktop eXperience\\\".\",\"web\":[\"https://en.wikipedia.org/wiki/Samsung_DeX\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.android.app.dexonpc\",\"description\":\"Samsung DeX\\nExtends your smartphone into a \\\"desktop computing experience\\\".\\nConcretely this lets you access all your mobile apps and content from a computer.\\nOnly works on Windows/MacOS. You will need to install the Samsung DeX app on your computer.\\nhttps://en.wikipedia.org/wiki/Samsung_DeX\\nhttps://www.samsung.com/global/galaxy/apps/samsung-dex/\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.android.app.dictionary\",\"description\":\"Samsung Dictionary is is an app that enables you to manage all the dictionaries stored on your Samsung device.\\n\",\"removal\":\"replace\",\"suggestions\":\"dictionaries\",\"type\":\"oem\"},{\"id\":\"com.sec.android.app.easysetup\",\"description\":\"Core of Samsung SmartThings (formerly Samsung Easy Setup)\\nSee com.samsung.android.easysetup\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.android.app.factorykeystring\",\"description\":\"DeviceKeyString : Dialable hidden diagnostic/debug app\\nDial *#0283# to open audio LoopbackTest control, dial *#2663# for TSP firmware update\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.android.app.felicatest\",\"description\":\"FeliCa Test, hidden debugs,logs HAL_Nfc\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.android.app.firewall\",\"description\":\"Blocked calls'msgs\\nChinese blocking calls and spam.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.android.app.fm\",\"description\":\"Samsung Radio\\nListen to FM radio stations\\n\",\"removal\":\"replace\",\"suggestions\":\"radios\",\"type\":\"oem\"},{\"id\":\"com.sec.android.app.gamehub\",\"description\":\"Samsung Game Hub\\nWas replaced by \\\"com.samsung.android.game.gamehome\\\"\\nhttps://www.techradar.com/news/phone-and-communications/mobile-phones/the-samsung-game-hub-explained-1143450\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.android.app.hwmoduletest\",\"label\":\"HwModuleTest\",\"description\":\"A hardware hidden test app (dial *#0*# to open it).\\nHas stuff to quickly check the phone's hardware. Removing it does not break anything, but no point in removing it. Note: opening this menu is required to change CSC with PC programs.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.android.app.kidshome\",\"description\":\"This app provides a child-friendly interface and controls on Samsung devices, designed to create a safe environment for children by restricting access to apps and content.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.android.app.launcher\",\"label\":\"Samsung One UI Home\",\"description\":\"Samsung One UI Home launcher (homescreen) which is also Samsung's TouchWiz default launcher.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.sec.android.app.launcher\"],\"removal\":\"caution\",\"warning\":\"Disabling this package breaks the multitasking navigation button on all newer versions of One UI, nothing would happen when pressing it.\",\"suggestions\":\"launchers\",\"type\":\"oem\"},{\"id\":\"com.sec.android.app.magnifier\",\"description\":\"Lets you use your device as a magnifying glass making it easier to read any small font or expand the details of any object, for example.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.android.app.minimode.res\",\"description\":\"Minimode will be not available when this app be removed\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.android.app.mt\",\"description\":\"Mobile tracker security feature. If someone inserts a new SIM card in your device the device will automatically \\nsends the SIM contact number to specified recipients to help you locate and recover you device.\\nhttps://www.samsung.com/nz/support/mobile-devices/what-is-mobile-tracker/\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.android.app.myfiles\",\"label\":\"Samsung My Files\",\"description\":\"Samsung file manager app\\n\",\"web\":[\"https://play.google.com/store/apps/details?id=com.sec.android.app.myfiles\"],\"removal\":\"replace\",\"warning\":\"If you remove this package on Android 10+, you will no longer be able to manage storage the same way as before. For example you will lose the ability to unmount or format the SD card from within the Settings app.\\n\",\"suggestions\":\"file_managers\",\"type\":\"oem\"},{\"id\":\"com.sec.android.app.ocr\",\"description\":\"Optical Read (feature replaced by Bixby Vision : com.samsung.android.visionintelligence)\\nLets you scan or extract text or data from images, documents, business cards, or QR codes.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.android.app.parser\",\"label\":\"DRParser Mode\",\"description\":\"Secret code parser\\nSupport for hidden samsung apps launched via secret codes.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.android.app.personalization\",\"description\":\"Has something to do with personalization?\\nHas 2 permissions: `READ_PHONE_STATE` and `CHANGE_PHONE_STATE`\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.sec.android.app.popupcalculator\",\"label\":\"Samsung Calculator\",\"description\":\"Samsung calculator app\\n\",\"web\":[\"https://play.google.com/store/apps/details?id=com.sec.android.app.popupcalculator\"],\"removal\":\"replace\",\"suggestions\":\"calculators\",\"type\":\"oem\"},{\"id\":\"com.sec.android.app.popupuireceiver\",\"description\":\"Not needed popupui with battery animation charging or other system notifications.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.android.app.qsfastpairoverlay\",\"description\":\"About half street overlay, has to gms.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.sec.android.app.quicktool\",\"description\":\"The Quick Tools panel includes a ruler, a compass and a torch. To add this to the Edge Panel (com.samsung.android.app.clipboardedge)\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.android.app.ringtoneBR\",\"description\":\"Samsung ringtone backup/restore feature\\nWhere is this feature? (available from Samsung Galaxy S9)\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.android.app.safetyassurance\",\"description\":\"Safety assurance is related to emergency features. It is especially used for SOS messages.\\nhttps://www.samsung.com/nz/support/mobile-devices/samsung-sos-smart-phone-emergency-message-guide/\\nHas obviously a huge amount of permissions.\\n\\nPithus analysis: https://beta.pithus.org/report/a06501fce61a39cb2b38df088eba4d0ce7ca3ed8fce3e8b672d8eb807538fb1f\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.sec.android.app.samsungapps\",\"label\":\"Galaxy Store\",\"required_by\":[\"com.samsung.android.spay\"],\"description\":\"The Samsung app store.\",\"web\":[\"https://en.wikipedia.org/wiki/Samsung_Galaxy_Store\",\"https://www.computerworld.com/article/3514999/samsung-selling-data.html\",\"https://www.reddit.com/r/Android/comments/xtq9pq/samsungs_privacy_policy_for_oct_1st_is_crazy/\"],\"removal\":\"replace\",\"warning\":\"Removing the app may break Samsung Pay features.\",\"suggestions\":\"app_stores\",\"type\":\"oem\"},{\"id\":\"com.sec.android.app.saspmodemailerprovider\",\"description\":\"docomo mail\\nno activities, looks like more useless frameworks also it's only for japanese\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.android.app.sbrowser\",\"label\":\"Samsung Internet\",\"description\":\"From their privacy policy: \\\"The information we obtain [..] include, identifiers associated with your devices, types of devices, web browser characteristics, device and operating system type and characteristics, language preferences, clickstream data, your interactions with Samsung Internet (such as the web pages you visit, links you click and features you use), dates and times of your use of Samsung Internet, and other information about your use of Samsung Internet.\\\"\",\"web\":[\"https://play.google.com/store/apps/details?id=com.sec.android.app.sbrowser\",\"https://developer.samsung.com/internet/privacy-policy-us.html\",\"https://privacytests.org/android.html\"],\"removal\":\"replace\",\"suggestions\":\"browsers\",\"type\":\"oem\"},{\"id\":\"com.sec.android.app.sbrowser.lite\",\"label\":\"Samsung Internet Lite/Go\",\"description\":\"Lite version of the Samsung browser (hah! Because the base one was too bloated?)\\nFrom their privacy policy: \\\"The information we obtain [..] include, identifiers associated with your devices, types of devices, web browser characteristics, device and operating system type and characteristics, language preferences, clickstream data, your interactions with Samsung Internet (such as the web pages you visit, links you click and features you use), dates and times of your use of Samsung Internet, and other information about your use of Samsung Internet.\\\"\",\"web\":[\"https://developer.samsung.com/internet/privacy-policy-us.html\",\"https://privacytests.org/android.html\"],\"removal\":\"replace\",\"suggestions\":\"browsers\",\"type\":\"oem\"},{\"id\":\"com.sec.android.app.scloud\",\"description\":\"I guess it's the core of Samsung Cloud.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.android.app.servicemodeapp\",\"description\":\"SysDump hidden app\\nLow-level debugging and diagnostics tools (dial *#9900# to open it)\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.android.app.setupwizard\",\"label\":\"Setup Wizard\",\"description\":\"The Welcome screen which guides you through the basics of setting up your device when you boot it for the first time (or after a factory reset). On some Verizon-carried devices, it can show an annoying \\\"SIM card not from Verizon Wireless\\\" notification, for each boot, and it can't be blocked unless you disable the app.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.android.app.setupwizardlegalprovider\",\"description\":\"SetupWizardLegalProvider\\nAll the legal terms you need to accept when you boot your phone for the first time. \\nThe Welcome screen which guides you through the basics of setting up your device is the android setup wizard.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.android.app.shealth\",\"label\":\"Samsung Health\",\"description\":\"Serves to track various aspects of daily life contributing to well being such as physical activity, diet, and sleep.\\nS Health data is stored in a Knox container (with HIPAA compliance).\",\"web\":[\"https://play.google.com/store/apps/details?id=com.sec.android.app.shealth\",\"https://en.wikipedia.org/wiki/Samsung_Health\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.android.app.simsettingmgr\",\"description\":\"SIM card manager.\\nContains configuration and settings for handling dual SIM (give a SIM an icon, a name, and so on)\\n\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.sec.android.app.sns3\",\"description\":\"Samsung Galaxy (Only installed on older phone before Galaxy S7)\\nDon't really know what this app does but majority of people deleted this.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.android.app.snsimagecache\",\"description\":\"SnsImageCache\\nA lot logs, probably it's for image cache. A lot samsung phones dont have it so it's safe to remove\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.android.app.soundalive\",\"label\":\"Samsung SoundAlive\",\"description\":\"Responsible for Dolby Atmos and other equalizer stuff (accessible from the Settings app).\\nNeeded by Adapt Sound (com.sec.hearingadjust) which is a pretty useful feature.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.android.app.suwscriptplayer\",\"description\":\"SuwScriptPlayer\\nSeems to be another test app which test some \\\"scripts\\\"\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.android.app.sysscope\",\"label\":\"SysScope\",\"description\":\"Checks after every boot if the ROM and kernel have been modified. This package is usually present on Verizon-locked phones.\\nVerizon has the ability to check if your device has root access (content://com.verizon.security/ROOT_STATUS).\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.android.app.taskmanager\",\"description\":\"Hidden app that shows uninstall unused apps(+boring notifications that may be disabled)\\nand button to (other, in the same app)task manager(shows ram and buttons kill user apps).\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.android.app.tourviewer\",\"description\":\"3d tour image, Virtual tour, Viewer used to view photos taken with the Galaxy S5 camera's Virtual Tour Shot mode.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.android.app.translator\",\"description\":\"Samsung Translater (S Translater)\\nhttps://www.samsung.com/africa_en/support/mobile-devices/what-is-s-translator-and-how-does-it-work/\\n\",\"removal\":\"replace\",\"suggestions\":\"translators\",\"type\":\"oem\"},{\"id\":\"com.sec.android.app.uwbtest\",\"label\":\"UwbTest\",\"description\":\"For testing UWB in the factory.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.android.app.ve.vebgm\",\"description\":\"Samsung Editing Assets (\\\"Video Editor BackGround Music\\\").\\nThis app lets you choose background music from the Video Editor app.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.android.app.vepreload\",\"description\":\"Samsung video editor\\nLets you add add transitions, music, stickers and text to your videos. You can also change the speed of the action, \\nor even add filters to switch up the mood of your videos.\\n\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.sec.android.app.voicenote\",\"label\":\"Samsung Voice Recorder\",\"description\":\"Samsung Voice recorder\\n\",\"web\":[\"https://play.google.com/store/apps/details?id=com.sec.android.app.voicenote\"],\"removal\":\"replace\",\"suggestions\":\"audio_recorders\",\"type\":\"oem\"},{\"id\":\"com.sec.android.app.volumemonitorprovider\",\"label\":\"VolumeMonitorProvider\",\"description\":\"Used in Digital Wellbeing to average the dB heard through earphones and display it.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.android.app.wallpaperchooser\",\"description\":\"This app provides the functionality to select and manage wallpapers on Samsung devices, including Samsung-specific wallpaper options.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.sec.android.app.wfdbroker\",\"description\":\"I found it's for connecting to tv also settings\\nbut app size is too small for doing these things.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.android.app.withtv\",\"description\":\"Samsung Smart View\\nAllows you to cast your phone screen to the TV.\\nhttps://www.samsung.com/us/apps/smart-view-2/\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.android.app.wlantest\",\"description\":\"wlan test\\nHidden test app responding to the #232339*# and *#232338*# secret codes\\nFYI : wlan = wireless LAN (https://en.wikipedia.org/wiki/Wireless_LAN)\\nNOTE: Disabling this test will rise the exclamation mark on the WI-Fi icon and will show the message \\\"Unable to connect to the host\\\" in Settings -> Connections -> More connections settings - Private DNS - provider hostname.\\nThe connection seems to work despite those esthetic errors.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.android.autodoodle.service\",\"label\":\"AutoDoodle\",\"description\":\"Samsung Auto Doodle for Photo Editor\",\"web\":[\"https://galaxystore.samsung.com/prepost/000005425352\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.android.automotive.drivelink\",\"description\":\"Car mode\\nit's hidden app and has a lot duplicate settings. Not needed\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.android.automotive.drivelinkremote\",\"description\":\"DriveLinkRemote\\nI found only Hello world!\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.android.casual2\",\"description\":\"Casual theme\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.sec.android.classic2\",\"description\":\"Classic theme\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.sec.android.cover.ledcover\",\"description\":\"Samsung LED cover service\\nDisplay stuff on the LED case.\\nhttps://www.samsung.com/us/support/troubleshooting/TSG01001489/\\nHOW IT WORKS : https://forum.xda-developers.com/galaxy-note-8/accessories/how-led-cover-t3686694\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.android.daemonapp\",\"description\":\"Unified Daemon app \\nprovides support for a number of different apps on your device. These include the Weather, Yahoo Finance and Yahoo News apps amongst others. \\nThe data is used by apps such as the Alarm, Calendar app and the camera.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.android.desktopcommunity\",\"description\":\"Samsung DeX panel\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.android.desktopmode.uiservice\",\"description\":\"Samsung DeX\\nExtends your smartphone into a \\\"desktop computing experience\\\".\\nConcretely this lets you access all your mobile apps and content from a computer.\\nOnly works on Windows/MacOS. You will need to install the Samsung DeX app on your computer.\\nhttps://en.wikipedia.org/wiki/Samsung_DeX\\nhttps://www.samsung.com/global/galaxy/apps/samsung-dex/\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.android.dexsystemui\",\"description\":\"Samsung DeX System UI\\nSafe to remove if not use connect phone for example to TV.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.sec.android.diagmonagent\",\"label\":\"DiagMonAgent\",\"description\":\"Diagnostic Monitoring Agent\\nUsed to send diagnostic data to Samsung\\nData collection from Settings > Biometrics and security > Send diagnostic data\\n\",\"removal\":\"caution\",\"warning\":\"Disabling this causes scheduled services to aggressively launch it every second, spamming the android crash log and overheating the device, thus draining battery. More info is needed on the dependencies that trigger this behavior. Version tested: 9.0.11.\",\"type\":\"oem\"},{\"id\":\"com.sec.android.easyMover\",\"description\":\"Samsung Smart Switch Mobile (https://play.google.com/store/apps/details?id=com.sec.android.easyMover)\\nAllows you to easily transfer content (contacts, photos, music, notes, etc.) to a new Samsung Galaxy device. \\nhttps://www.samsung.com/global/galaxy/apps/smart-switch/\\nhttps://fr.wikipedia.org/wiki/Smart_Switch\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.android.easyMover.Agent\",\"label\":\"Smart Switch Agent\",\"description\":\"Needed to use Smart Switch. See \\\"com.sec.android.easyMover\\\".\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.android.easyonehand\",\"description\":\"Samsung Easy One Hand mode\\nAllows you to temporarily scale down the display size of your screen for easier control of your phone with just one hand.\\nhttps://www.samsung.com/au/support/mobile-devices/using-one-handed-mode/\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.android.emergencylauncher\",\"description\":\"Samsung Launcher when in emergency(low battery) mode.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.sec.android.emergencymode.service\",\"description\":\"Emergency mode enables you to extend your device’s standby time when in an emergency situation and want your device to conserve power for as long as possible. When activated, screen brightness will decrease, some of functionality will be limited and the home screen is changed to a black theme, all to reduce battery drain (OLED screens draw less power when showing black, cuz black = pixel off).\\nNOT related to SOS messages/911.\\nhttps://www.samsung.com/uk/support/mobile-devices/what-is-emergency-mode/\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.sec.android.fido.uaf.asm\",\"label\":\"Fido ASM Data\",\"description\":\"Fido is a set of open technical specifications for mechanisms of authenticating users to online services that do not depend on passwords.\\nThe UAF protocol is designed to enable online services to offer passwordless and multi-factor security by allowing users to register their device to the online service and using a local authentication mechanism such as iris or fingerprint recognition.\\nThe UAF Authenticator-Specific Module (ASM) is a software interface on top of UAF authenticators which gives a standardized way for FIDO UAF clients to detect and access the functionality of UAF authenticators and hides internal communication complexity from FIDO UAF Client.\\nSafe to remove if you don't use password-less authentication to access online services.\",\"web\":[\"https://fidoalliance.org/specs/u2f-specs-1.0-bt-nfc-id-amendment/fido-glossary.html\",\"https://fidoalliance.org/specs/fido-v2.0-rd-20170927/fido-overview-v2.0-rd-20170927.html\",\"https://developers.google.com/identity/fido/android/native-apps\",\"https://fidoalliance.org/specs/fido-uaf-v1.0-ps-20141208/fido-uaf-asm-api-v1.0-ps-20141208.html\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.android.fido.uaf.client\",\"label\":\"FIDO UAF Client\",\"description\":\"It's a layer that connects authenticator and RP (the application owner) and ensures validity of the connection. It can be browser, desktop application, mobile application, platform(i.e. android/ios).\\nSafe to remove if you don't use password-less authentication to access online services.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.android.gallery3d\",\"description\":\"Samsung Gallery app (https://play.google.com/store/apps/details?id=com.sec.android.gallery3d)\\nNote: Samsung Gallery is a dependency for the camera so it's not a good idea to delete it.\\nNote : Good to know. When the original version of the image is deleted, the copy of it within the com.sec.android.gallery3d  folder is not removed.\\nhttps://athenaforensics.co.uk/com-sec-android-gallery3d-mobile-phone-forensics/\\nNOTE : Deleting this package will also prevent to preview photos from the camera app.\\n\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.sec.android.gallery3d.panorama360view\",\"description\":\"Let you see panoramic photos in the samsung Gallery.\\n\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.sec.android.game.gamehome\",\"description\":\"Samsung Game launcher\\nCentralizes all your android games. This app can track all your games, how many hours you've spent playing each one, and which genres you play the most.\\nRecommends games based on your profile.\\nhttps://galaxystore.samsung.com/prepost/000004906980?appId=com.samsung.android.game.gamehome \\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.android.iaft\",\"description\":\"iaft\\nHas permission dump, trace errors probably.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.android.inputmethod\",\"description\":\"Samsung Keyboard\\nSuperseded by `com.samsung.android.honeyboard`.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.sec.android.inputmethod.beta\",\"description\":\"Samsung Keyboard Neural Beta\\nSmarter Samsung Keyboard with better predictition/suggestion (using deep learning)\\nhttps://galaxystore.samsung.com/prepost/000004170688?appId=com.sec.android.inputmethod.beta\\n\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.sec.android.inputmethod.iwnnime.japan\",\"description\":\"Samsung Japanese keyboard\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.sec.android.kies\",\"description\":\"No activities, only useless frameworks in classes.dex\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.android.llmpolicy\",\"description\":\"LLMPolicyService\\nLow latency network to game? Looks unused.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.android.mimage.avatarstickers\",\"description\":\"Samsung My Emoji Stickers\\nLet you turn yourself into an emoji. Woah ! What an incredible feature...\\nhttps://www.samsung.com/us/support/answer/ANS00078920/\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.android.mimage.gear360editor\",\"description\":\"360 Photo Editor\\nLets you edit the 360-degree photos you took.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.android.mimage.photoretouching\",\"description\":\"Samsung Photo Editor\\nDisabling this will disable the inbuilt photo editor accessed via the stock gallery.\\nSafe to remove if you don't use Samsung gallery.\\n\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.sec.android.ofviewer\",\"description\":\"Samsung selective focus camera mode.\\nSafe to remove (but it's pretty useful)\\n\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.sec.android.omc\",\"description\":\"OM Customize\\nI found only things for Vodafone. It's not needed.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.android.pagebuddynotisvc\",\"description\":\"PageBuddyNotiSvc\\nI only found it's for notifications to car, earphones, pen. Not needed.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.android.preloadinstaller\",\"description\":\"Very shady apk. According to if you're chinese or not, Samsung mount an hidden partition during the first boot and install some apps.\",\"web\":[\"https://web.archive.org/web/20200107110205/https://nitter.net/fs0c131y/status/1046689524691218432\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.android.provider.badge\",\"label\":\"BadgeProvider\",\"description\":\"Provider for the notification badges (which are not very useful IMHO)\\nProvides a way for apps to use notifications badges.\",\"web\":[\"https://www.samsung.com/au/support/mobile-devices/what-is-app-icon-badge/\"],\"removal\":\"caution\",\"warning\":\"Emergency Power saving launcher does not start after removing.\",\"type\":\"oem\"},{\"id\":\"com.sec.android.provider.emergencymode\",\"description\":\"Provider for emergency mode (com.sec.android.emergencylauncher)\\nContent providers encapsulate data, providing centralized management of data shared between apps.\\nFor example: the Settings provider. It stores all the settings from your Settings app in a database, which apps can query for info on whether you for example have Dark Mode turned on or off.\\nhttps://developer.android.com/guide/topics/providers/content-providers.html\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.sec.android.provider.logsprovider\",\"description\":\"LogsProvider\\nIt's app used for logs.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.android.provider.snote\",\"description\":\"Content provider for S Note (https://www.samsung.com/global/galaxy/apps/samsung-notes/).\\nContent providers encapsulate data, providing centralized management of data shared between apps.\\nhttps://developer.android.com/guide/topics/providers/content-providers.html\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.android.providers.mapcon\",\"description\":\"Mapcon Provider\\nOnly name app founded.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.android.providers.security\",\"description\":\"Provider of password security policies?\\nContent providers encapsulate data, providing centralized management of data shared between apps.\\nhttps://developer.android.com/guide/topics/providers/content-providers.html\\nSeems to provide access to a password database but I don't know under what circumstances this database is used.\\nThis provider is only usable by Samsung apps.\\nI see a com.android.security.PASSWORD_EXPIRED intent filter in the AndroidManifest so my guess is it handles password policies.\\nFor example: A policy could force a user to change their password after a certain amount of time. That's a common policy in enterprise work.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.android.providers.tasks\",\"description\":\"Tasks provider\\nThis app have nothing in code, only name and useless permissions\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.android.romantic2\",\"description\":\"Sweet theme\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.sec.android.sdhms\",\"description\":\"Samsung Device Health Manager Service\\nBattery estimation service for Samsung Care/Device maintenance (com.samsung.android.lool)\\nThere is some weird stuff in the java code. I don't understand why there is a need to parse torrent files for instance\\nor why there is a string \\\"googleapis.com/drive\\\"\\nhttps://developers.google.com/drive/api/v3/reference\\n\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.sec.android.service.health\",\"description\":\"Samsung Health Service\\nNeeded for Samsung Health (com.sec.android.app.shealth)\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.android.settingsmaps\",\"description\":\"My places\\nI found Search location also theres other stuff about location but it's not needed I guess\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.android.sidesync30\",\"description\":\"SideSync (discontinued)\\nLets you share the screen and data between your PC and mobile device. \\nReceive alarms of your phone through PC and use various features of your phone on the computer.\\nhttps://www.samsung.com/levant/support/side-sync/\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.android.smartfpsadjuster\",\"label\":\"SmartFPSAdjuster\",\"description\":\"Adjusts FPS automatically in Samsung phones? Safe to delete.\",\"web\":[\"https://docs.samsungknox.com/CCMode/G985F_Q.pdf\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.android.soagent\",\"description\":\"System application that is responsible for checking and installing software updates.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.sec.android.splitsound\",\"description\":\"SplitSoundService\\nProvides ability to play music on the smartphone and an external speaker at the same time\\nhttps://www.samsung.com/nz/support/mobile-devices/samsung-separate-app-sound/\\n\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.sec.android.stub.paywithpaypal\",\"description\":\"Pay with PayPal\\nHidden app that wanna to install PayPal to your phone.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.android.systemupdate\",\"label\":\"SystemUpdate\",\"description\":\"System updater for Samsung phones.\",\"web\":[\"https://docs.samsungknox.com/CCMode/G985F_Q.pdf\"],\"removal\":\"caution\",\"warning\":\"Updates will stop working.\",\"type\":\"oem\"},{\"id\":\"com.sec.android.theme.natural\",\"description\":\"Natural theme\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.sec.android.uibcvirtualsoftkey\",\"description\":\"UIBC (User input back channel) \\nAllows users to experience the dual monitor function, with the keyboard and mouse having the ability to control your smartphone device.\\nEither discontinued (for the benefit of Smart View : com.samsung.android.smartmirroring) or related to Smart View. \\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.android.wallpapercropper2\",\"description\":\"Samsung Wallpaper. Needed to set a wallpaper on the launcher.\\nNote: it is possible to change the wallpaper and then disable this package.\\nUsed wallpapers are stored in /data/data/com.sec.android.wallpapercropper2/\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.sec.android.widgetapp.SPlannerAppWidget\",\"description\":\"Calendar Widget\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.android.widgetapp.ap.hero.accuweather\",\"description\":\"Weather app\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.android.widgetapp.ap.hero.weathernewsjp\",\"description\":\"japanese samsung weather app\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.android.widgetapp.digitalclock\",\"description\":\"Clock (digital) widget\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.android.widgetapp.digitalclockeasy\",\"description\":\"Clock (digital easy) widget\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.android.widgetapp.diotek.smemo\",\"description\":\"Samsung Memo widget (was replaced by Samsung Note : com.samsung.android.app.notes)\\nPartnership with 3-party DIOTEK : https://www.diotek.co.kr/\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.android.widgetapp.dualclockdigital\",\"description\":\"Dual Clock Widget\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.android.widgetapp.easymodecontactswidget\",\"description\":\"Favourite Contacts widget\\nLets you add favorite contacts to home screen\\nhttps://www.samsung.com/au/getstarted/advanced/create-favourite-contacts-on-your-home-screen/\\nIs it only usable when enabling the \\\"simple use\\\" senior mode?\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.android.widgetapp.samsungapps\",\"description\":\"Galaxy Essential widget\\nGalaxy Essentials is a collection of specially chosen applications available through Samsung Apps. \\nFrom the Galaxy Essentials widget you can access and download a collection of premium content, free of charge.\\nhttps://www.samsung.com/my/support/mobile-devices/what-is-galaxy-essentials-and-how-can-i-add-or-remove-it-from-my-smartphone-home-screen/\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.android.widgetapp.webmanual\",\"description\":\"User Manual\\nhttps://www.samsung.com/us/support/answer/ANS00077583/\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.android.yellowpage\",\"description\":\"Yellow Page\\nContain phone numbers of companies and services.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.app.RilErrorNotifier\",\"description\":\"RilNotifier\\nDebug app for the RIL\\nSee \\\"com.sec.android.RilServiceModeApp\\\"\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.app.TransmitPowerService\",\"description\":\"This app manages settings related to the transmit power of wireless communications on Samsung devices, such as Wi-Fi and Bluetooth.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.sec.automation\",\"description\":\"Tethering Automation enables sharing phone internet to the PC with a usb cable.\\nSafe to remove (but it's a useful feature)\\n\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.sec.bcservice\",\"description\":\"Broadcast Service\\nDiagnostic/debug hidden app. TCP dump.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.clocationservice\",\"description\":\"CLocationService\\nNetwork location provider only to Chinese.\\nBad privacy.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.downloadablekeystore\",\"description\":\"Keystore is a secure place provided by Android to store cryptographic keys and make it more difficult to extract from the device.\\nThis package is used by enterprise to update certificates on the device.\\nNOTE : It allows IT admins to install certificates while the device is still locked. \\nThis means certificates can be silently installed into a keystore without any interaction from the device-user.\\nIt uses the KNOX TIMA (Named Trust-zone-based Integrity Measurement Architecture) that allows storage of keys in the container for certificate signing using the TrustZone hardware platform.[16] \\nhttps://docs.samsungknox.com/dev/knox-sdk/about-keystores.htm\\nhttps://docs.samsungknox.com/dev/knox-sdk/faqs/general/what-is-the-knox-tima-ccm.htm\\nhttps://docs.samsungknox.com/admin/whitepaper/kpe/client-certificate-manager.htm\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.enterprise.knox.attestation\",\"description\":\"KNOX Attestation\\nLets you check the integrity of a Samsung Android device by connecting to a Samsung Attestation server.\\nhttps://docs.samsungknox.com/admin/whitepaper/kpe/attestation.htm\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.enterprise.knox.cloudmdm.smdms\",\"description\":\"Knox Enrollment Service\\nmdm = mobile device management = software used by an IT department to monitor employees' mobile devices.\\nUsed to enroll/register a large number of phones to the KNOX MDM service\\nhttps://docs.samsungknox.com/admin/knox-mobile-enrollment/enroll-your-devices.htm\\nFYI : https://blog.quarkslab.com/abusing-samsung-knox-to-remotely-install-a-malicious-application-story-of-a-half-patched-vulnerability.html\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.enterprise.knox.shareddevice.keyguard\",\"description\":\"KNOX shared device keyguard.\\nKnox Configure Shared Device feature enables multiple users to access the same device without sharing data across multiple devices.\\nhttps://docs.samsungknox.com/KC-Getting-Started/Content/about-shared-device.htm\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.enterprise.mdm.services.simpin\",\"label\":\"Enterprise Sim Pin Service\",\"description\":\"I couldn't find information about this package. No permissions asked. It's quite strange.\\nMobile device management (MDM) is a type of security software used by an IT department to monitor employees' mobile devices.\\nKNOX-dependent.\",\"web\":[\"https://developer.samsung.com/tech-insights/knox/mobile-device-management\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.enterprise.mdm.vpn\",\"label\":\"Enterprise VPN Services\",\"description\":\"I couldn't find information about this package. No permissions asked too.\\nSee above for MDM signification\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.epdg\",\"description\":\"Safe to remove if you're not using VoWifi.\\nYou need to know that:\\n3GPP is a standards organization for mobile telephony (2G/3G/4G/5G).\\nNon-3GPP RAT refers to wireless connection methods not specified by 3GPP, including Wi-Fi.\\nePDG (evolved Packet Data Gateway) secures connections over untrusted non-3GPP access, commonly used for VoWiFi (Voice over Wi-Fi).\",\"web\":[\"https://www.3gpp.org/technologies/keywords-acronyms/100-the-evolved-packet-core\",\"https://www.aptilo.com/solutions/mobile-data-offloading/3gpp-wifi-access/\",\"https://en.wikipedia.org/wiki/System_Architecture_Evolution#Evolved_Packet_Core_(EPC)\"],\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.sec.epdgtestapp\",\"description\":\"Test app for ePDG (see com.sec.epdg)\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.esdk.elm\",\"description\":\"ELM Agent\\nHidden ELM for Developers Logs\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.everglades\",\"description\":\"Samsung Hub (discontinued)\\nIt was a cloud-based music service launched by Samsung. It allowed users to listen to music from a variety of Samsung devices\\nhttps://en.wikipedia.org/wiki/Samsung_Music_Hub\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.everglades.update\",\"description\":\"SamsungHub Updater (discontinued - See above)\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.facatfunction\",\"description\":\"FacAtFunction\\nUI Display, Sensors Tests\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.factory\",\"description\":\"Device Test app\\nDiagnostic hidden app.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.factory.camera\",\"description\":\"Camera Test (dial *#34971539# to open CameraFirmware Standard)\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.factory.cameralyzer\",\"label\":\"Cameralyzer\",\"description\":\"A factory testing app that allows manufacturers to check for defects in the camera, had a security issue in the past\",\"web\":[\"https://techforesta.com/cameralyzer/\",\"https://docs.samsungknox.com/CCMode/G985F_Q.pdf\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.factory.iris.usercamera\",\"description\":\"Camera Iris User Test (by dialing *#0*#)\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.hearingadjust\",\"description\":\"Samsung Adapt Sound\\nConfigures a sound profile according to your ears.\\nImprove audio experience in the end (even with headphones)\\nhttps://www.howtogeek.com/316375/how-to-use-adapt-sound-on-the-galaxy-s7-and-s8-for-better-sound-quality/\\n#\\nSettings > Sound  and vibration > Sound Quality and effects > Adapt Sound\\nNOTE : com.sec.android.app.soundalive is needed\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.hiddenmenu\",\"description\":\"IOTHiddenMenu\\nHidden menu used to access other hidden debug apps (those accessible with a secret code)\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.ims\",\"description\":\"IMS(Ip Multimedia Subsystem) is an open industry standard for voice and multimedia communications over packet-based IP networks (VoLTE/VoIP/Wifi calling).\\nDon't know how this is different from com.sec.imsservice. Could they interact?\\nMay be unsafe to disable. Needs more testing.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.sec.ims.android\",\"description\":\"IMS Framework\\nNeeded for Wifi calling\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.sec.imslogger\",\"label\":\"ImsLogger\",\"description\":\"IMS Logger provides logging opt-ins. Has known security flaws.\",\"web\":[\"https://web.archive.org/web/20211209093408/https://twitter.com/fs0c131y/status/1115889065285562368\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.imsservice\",\"description\":\"IMS(Ip Multimedia Subsystem) is an open industry standard for voice and multimedia communications over packet-based IP networks (VoLTE/VoIP/Wifi calling).\\nVideo calling is also affected.\\nNote: Samsung Dialer will crash if you disable this package and have wifi-calling activated in the Dialer's settings.\\nMay be unsafe to disable. Needs more testing.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.sec.internal.vsim.VSimServiceApp\",\"description\":\"Non Sim Device Solution (NSDS) needed for VoLTE and VoWifi (Wifi Calling) if you have a virtual SIM. Enabled in devices without eSIMs for some reason. Not sure if there are non-esim virtual sims?\\nSee com.sec.vsimservice. Uses IMS service.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.sec.kidsplat.installer\",\"description\":\"Kids Mode (replaced by Kids Home : com.samsung.android.kidsinstaller)\\nSamsung Kids Home (https://www.samsung.com/global/galaxy/apps/kids-mode/)\\nLets you shape a safe environment for your child to happily explore and connect with the world.\\nNOTE : You shouldn't give your phone to a child. That's bad ! \\nhttps://ifstudies.org/blog/a-smartphone-will-change-your-child-in-ways-you-might-not-expect-or-want\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.knox.bluetooth\",\"description\":\"KNOX bluetooth\\nhttps://docs.samsungknox.com/knox-platform-for-enterprise/admin-guide/bluetooth.htm\\nNOTE : This does not affect regular bluetooth.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.knox.bridge\",\"description\":\"Debug Bridge ? \\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.knox.containeragent2\",\"description\":\"Samsung Knox Container (v2 ?)\\nhttps://docs.samsungknox.com/whitepapers/knox-platform/app-container.htm\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.knox.foldercontainer\",\"description\":\"Needed by KNOX Secure folder (com.samsung.knox.securefolder)\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.knox.knoxsetupwizardclient\",\"description\":\"KNOX SetupWizardClient\\nThe first time you turn your device on, a Welcome screen is displayed. It guides you through the basics of setting up your device.\\nIt's the setup for Samsung KNOX services.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.knox.packageverifier\",\"description\":\"KNOX Verifier\\nUsed to scan installed packages\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.knox.shortcutsms\",\"description\":\"Knox shortcut to switch to workspace \\nhttps://docs.samsungknox.com/knox-platform-for-enterprise/admin-guide/workspace-shortcuts.htm\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.knox.switcher\",\"description\":\"Knox Secure Folder\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.sec.knox.switchknox\",\"description\":\"Handles switches between KNOW/Work container and personal profile. \\nIt also manages data sharing between them.\\nhttps://docs.samsungknox.com/dev/knox-sdk/container-data-sharing-policies.htm\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.knox.switchknoxI\",\"description\":\"Handles switches between KNOW/Work container and personal profile. \\nIt also manages data sharing between them.\\nhttps://docs.samsungknox.com/dev/knox-sdk/container-data-sharing-policies.htm\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.knox.switchknoxII\",\"description\":\"Handles switches between KNOW/Work container and personal profile. \\nIt also manages data sharing between them.\\nhttps://docs.samsungknox.com/dev/knox-sdk/container-data-sharing-policies.htm\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.location.nfwlocationprivacy\",\"label\":\"Service provider location\",\"description\":\"Not needed for location, I found something like that:\\n(This app enables your carrier to access your location for network improvement or other reasons)\\nThis app is hidden so idk how useful it is.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.location.nsflp2\",\"label\":\"Samsung Location SDK\",\"description\":\"It seems to only be used by Samsung (Galaxy) apps\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.mhs.smarttethering\",\"label\":\"Auto Hotspot\",\"description\":\"Formerly, SmartTethering.\\nProbably needed for hotspots.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.sec.mldapchecker\",\"description\":\"MLDAP log\\nLDAP (Lightweight Directory Access Protocol; I don't know what the M means. Mobile?) is an open, vendor-neutral, industry standard application protocol for accessing and maintaining distributed directory information services over an IP network.\\nDirectory service refers to the collection of software, hardware, and processes that store and organize everyday items and network resources(folders, files, printers, users, groups, devices, telephone numbers...)\\nIt looks like a database but it's different.\\nDirectory services excel at fast lookups for rarely changing data (email, username etc...)\\nDifferences between database and Directory Service : https://www.c-sharpcorner.com/article/directory-services-vs-rdbms/\\nLDAP uses a relatively simple, string-based query to extract information from Active Directory. LDAP can store and extract objects such as usernames and passwords in Active Directory, and share that object data throughout a network. \\nExample of LDAP usage : https://stackoverflow.com/questions/239385/what-is-ldap-used-for/592339\\n\\nI don't know why and how Samsung uses LDAP. This package, according to its name only does logging.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.modem.settings\",\"description\":\"Name : SilentLogging\\nThis package runs at startup and logs things (related to the modem ?). Seems Pretty shady to me (I don't like its orwellian name).\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.omadmspr\",\"description\":\"OMADM\\nhas activation things and firmware updates\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.sec.phone\",\"description\":\"Another test/debug app used to test the proper functioning of phone calls.\",\"removal\":\"caution\",\"warning\":\"Both \\\"com.sec.phone\\\" & \\\"com.sec.android.app.SecSetupWizard\\\" must be enabled to be able to add new eSIMs to device. Otherwise, the menu will spin indefinitely.\",\"type\":\"oem\"},{\"id\":\"com.sec.providers.assisteddialing\",\"description\":\"Assisted Dialing\\nI found mcc countrycode OTA lookup, not needed\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.readershub\",\"description\":\"Samsung Books (discontinued)\\nAll-in-one e-Reading solution that offers instant access to thousands of e-reading contents.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.smartcard.manager\",\"description\":\"Smart Card Manager\\nSmart Card enables communication with Secure Elements (SIM card, embedded Secure Elements, Mobile Security Card...)\\nThese packages seem to be Samsung implementation.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.spp.push\",\"label\":\"Samsung Push Service\",\"description\":\"Provides updates and notifications for services exclusive to Samsung (more like Samsung ads).\",\"web\":[\"https://play.google.com/store/apps/details?id=com.sec.spp.push\",\"https://www.samsunggeeks.com/2015/10/25/what-is-the-samsung-push-service/\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.sve\",\"label\":\"SecVideoEngineService\",\"description\":\"Arguably a Samsung video engine service (handling enconding/decoding?) for displaying video through Samsung apps.\\n3 permissions: RECORD_AUDIO, CAMERA, INTERACT_ACROSS_USERS_FULL\",\"removal\":\"caution\",\"warning\":\"Removing it will break WiFi Calling.\",\"type\":\"oem\"},{\"id\":\"com.sec.svoice.lang.en_GB\",\"description\":\"Language Pack for S-voice, the Samsung assistant (com.samsung.android.svoice)\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.tcpdumpservice\",\"description\":\"only found app name tcpdumpservice\\ntheres no code\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.unifiedwfc\",\"label\":\"Samsung Wi-Fi Calling\",\"description\":\"Wi-Fi calling app for Samsung.\",\"removal\":\"caution\",\"warning\":\"Wi-Fi calling may not work without the app\",\"type\":\"oem\"},{\"id\":\"com.sec.usbsettings\",\"label\":\"USBSettings\",\"description\":\"Hidden settings. Lets you choose from ADB, MTP, RNDIS, ACM, DM (dial *#0808# to open)\\nRuns at startup.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.sec.vsim.ericssonnsds.webapp\",\"description\":\"NSDSWebApp.\\nVirtual SIM is an application-enabled service that requires you to install an app to use a number. \\nWith this technology, it is possible for one to have numbers of different countries. \\nNon Sim Device Solution (NSDS) is needed for VoLTE and VoWifi (Wifi Calling) if you have a virtual SIM. \\nNSDS allows connecting non sim devices to IMS core: https://uk.linkedin.com/in/hemant-kumar-dewnarain-2b779679\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sec.vsimservice\",\"description\":\"VSim Service \\nLets you use a virtual sim\\nhttps://www.quora.com/What-is-VSIM-virtual-SIM-technology\\nHas a LOT of permissions (and involving IMS service)\\nRun at startup.\\nFYI : https://security.stackexchange.com/questions/223290/esim-vs-sim-card-what-is-more-secure\\n\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.sec.yosemite.phone\",\"description\":\"Samsung WatchON (discontinued)\\nIt was a service allowing you to view programming information on the TV and choose programs directly from the phone.\\nhttps://en.wikipedia.org/wiki/Samsung_WatchON\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.ses.entitlement.o2\",\"description\":\"O2 carrier app.\\nUnknown.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.sgrl.fmradio\",\"description\":\"FM Radio\\nSafe to remove if unused.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.sgrl.pjj.factorymode\",\"description\":\"FactoryMode, Calibration, Testing hardware things.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sh.smart.caller\",\"description\":\"Bloated Phone caller app with a lot of features. These apps have telemetry on them and are completely replaceable.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.shannon.qualifiednetworksservice\",\"description\":\"Needed for RCS, IMS.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.silead.fingerprint\",\"description\":\"Fingerprint silead manager\\nHidden app for testing Fingerprint things. Not needed for normal users.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sina.weibo\",\"description\":\"Chinese Weibo app.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.skms.android.agent\",\"description\":\"Samsung KMS agent service a client application for Android devices to support eSE-based (embedded secure element) mobile-NFC Services.\\nhttps://developer.samsung.com/ese/overview.html\\nKMS = Key Management System\\nKNOX feature (https://en.wikipedia.org/wiki/Samsung_Knox)\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.smile.gifmaker\",\"description\":\"Chinese partner app 'Kuaishou'.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.snap.camerakit.plugin.v1\",\"description\":\"Camera Kit\\nit's used for effects.\\nhttps://play.google.com/store/apps/details?id=com.snap.camerakit.plugin.v1\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.softwinner.explore\",\"description\":\"File Manager of SoftWinner\\nCan be disabled via system settings.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.softwinner.service\",\"description\":\"Possibly related to the firmware updater, since the updater has a similar name\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.sohu.inputmethod.sogou.meizu\",\"description\":\"Chinese keyboard closed-source\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.sohu.inputmethod.sogou.nubia\",\"description\":\"Chinese keyboard Closed-source (install other keyboard before removing this)\\nBetter alternative: https://f-droid.org/en/packages/dev.patrickgold.florisboard/\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sohu.inputmethod.sogou.xiaomi\",\"description\":\"Sogou keyboard for chinese only.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sohu.inputmethod.sogouoem\",\"description\":\"Default keyboard\\n\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.sohu.sohuvideo.emplayer\",\"description\":\"HiMoviePlayerPlus\\nWeird app without any code and there's nothing in Main Activity.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sony.dtv.calibrationmonitor\",\"description\":\"Screen calibration app\\nhttps://play.google.com/store/apps/details/Calman%20for%20BRAVIA?id=com.sony.dtv.calibrationmonitor&hl=en_US\\nUseful app, but can be removed if you don't need it.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.sony.dtv.ecodashboard\",\"description\":\"Used to configure eco friendly settings. Breaks some options in the settings app if removed.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.sony.dtv.livingfit\",\"description\":\"Turns your tv into an accessory by showing pictures. This is different to the screensaver and won't affect it.\\nhttps://play.google.com/store/apps/details?id=com.sony.dtv.livingfit&hl=en_US\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sony.dtv.notificationcenter\",\"description\":\"Notification app which reminds you to use apps from Sony's ecosystem. Can be removed safely without breaking other notifications\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sony.dtv.osat.music\",\"description\":\"Music app which streams from your files.\\nhttps://play.google.com/store/apps/details?id=com.sonyericsson.music&hl=en_US\\nCan be removed if you don't need it.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sony.dtv.promos\",\"description\":\"Sony's promotion app with offers. You need an account to use it\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sony.dtv.recapp\",\"description\":\"Allows you to view your reminders and timers but not add them? Can be removed safely\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sony.dtv.seeds.iot\",\"description\":\"Allows you to control your TV with smart speaker e.g Alexa:\\nhttps://play.google.com/store/apps/details?id=com.sony.dtv.seeds.iot&hl=en_US\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sony.dtv.smarthelp\",\"description\":\"App with documentation of how to use a smart TV. Removing it has no effect\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sony.dtv.sonyselect\",\"description\":\"Shows you bunch of popular subscription services and apps and redirects you to the play store. Better to use play store itself\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sony.dtv.timers\",\"description\":\"Sony's clock app.\\n Can be removed safely but on some Android Tv launchers it makes the Timer button not function. Not a deal breaker as the feature is pretty useless.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sony.dtv.tvx\",\"description\":\"Handles input settings. HDMI stops working if this is removed.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.sony.tvsideview.phone\",\"label\":\"Video & TV SideView : Remote\",\"description\":\"Sony's TV remote control app\",\"web\":[\"https://play.google.com/store/apps/details?id=com.sony.tvsideview.phone\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sony.tvsideview.videoph\",\"label\":\"Video\",\"description\":\"Sony's Video & TV SideView (replaced by \\\"com.sony.tvsideview.phone\\\")\\nLets you use your smartphone or tablet as a TV remote control for the home.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sonyericsson.album\",\"description\":\"Sony gallery app (https://play.google.com/store/apps/details?id=com.sonyericsson.album)\\n\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.sonyericsson.android.addoncamera.artfilter\",\"description\":\"Sony Creative effect\\nGives options for various photographic toning effects in the Sony camera app.\\nI'm not 100% sure for this one. Can someone confirm ? \\n\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.sonyericsson.android.camera3d\",\"description\":\"Sony camera app (on older phones)\\n\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.sonyericsson.android.conversations\",\"label\":\"Messaging\",\"description\":\"Sony's default messages (SMS) app\",\"removal\":\"replace\",\"suggestions\":\"sms\",\"type\":\"oem\"},{\"id\":\"com.sonyericsson.android.drm.drmlicenseservice\",\"description\":\"Theres only Drm License Activity, only downloads license, also japanese\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sonyericsson.android.omacp\",\"description\":\"omacp = OMA Client Provisioning. It is a protocol specified by the Open Mobile Alliance (OMA).\\nIt is used by carrier to send \\\"configuration SMS\\\" which can setup network settings (such as APN).\\nIn my case, it was automatic and I never needed configuration messages. I'm pretty sure that in France this package is useless.\\nMaybe it's useful if carriers change their APN... but you still can change it manually, it's not difficult.\\nThese special \\\"configuration SMS\\\" can be abused : \\nhttps://www.zdnet.fr/actualites/les-smartphones-samsung-huawei-lg-et-sony-vulnerables-a-des-attaques-par-provisioning-39890045.htm\\nhttps://www.csoonline.com/article/3435729/sms-based-provisioning-messages-enable-advanced-phishing-on-android-phones.html\\n\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.sonyericsson.conversations.res.overlay\",\"description\":\"Used to display a overlay notification (= on top of others app) when you receive a SMS with Sony SMS app ?\\n\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.sonyericsson.conversations.res.overlay_305\",\"description\":\"Used to display a overlay notification (= on top of others app) when you receive a SMS with Sony SMS app ?\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sonyericsson.idd.agent\",\"label\":\"Anonymous Usage Stats\",\"description\":\"Used to send \\\"anonymous\\\" information about how you use your Sony Smartphone to Sony servers.\\nIt remains unclear exactly how this information is anonymized.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sonyericsson.mtp\",\"description\":\"MTP extension service\\nNeeded to transfer data from phone to PC through MTP? (Media Transfer Protocol)\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.sonyericsson.mtp.extension.backuprestore\",\"description\":\"Backup/Restore Sony feature.\\nEnables you to backup contacts, call logs, text messages, calendar, settings, bookmarks & media files.\\nNOTE: I don't think this feature can backup your messages or calendars for instance if you don't use the Sony stock app.\\nhttps://support.sonymobile.com/global-en/xperiaz2/userguide/backing-up-and-restoring-content-on-a-device/\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.sonyericsson.mtp.extension.update\",\"description\":\"Update service for MTP Extension.\\nUpdates something for the MTP extension?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.sonyericsson.music\",\"description\":\"Sony music player (https://play.google.com/store/apps/details?id=com.sonyericsson.music)\\n\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.sonyericsson.settings.res.overlay_305\",\"description\":\"Some overlay for settings? Overlays are usually themes.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.sonyericsson.startupflagservice\",\"description\":\"Startup Flag Service\\nUsed during the production of the phone to verify that the touch input works. \\nIt can be triggered when a specific TA-parameter is not set. This should never be triggered and if it does well it doesn't have any use for you.\\n\\nTA means Timing Advance and its value correspond to the length of time a signal takes to reach the base station from a mobile phone.\\nhttps://www.telecomhall.net/t/parameter-timing-advance-ta/6390\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sonyericsson.textinput.chinese\",\"description\":\"Sony chinese keyboard\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sonyericsson.trackid.res.overlay\",\"description\":\"Some overlay for TrackID. Overlays are usually themes.\\nTrackID was(now discontinued) a music and audio search engine (like Shazam).\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.sonyericsson.trackid.res.overlay_305\",\"description\":\"Overlay for TrackID. Overlays are usually themes.\\nTrackID was(now discontinued) a music and audio search engine (like Shazam).\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.sonyericsson.unsupportedheadsetnotifier\",\"label\":\"Unsupported Headset Notifier\",\"description\":\"Given its name, I think it displays a notification when you insert a headset not compatible with your phone.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.sonyericsson.wappush\",\"description\":\"WAP Push\\nUsed to display annoying WAP push.\\nWAP push is a type of text message that contains a direct link to a particular Web page. \\nWhen a user is sent a WAP-push message, he receives an alert, once clicked, directs him to the Web page via his browser.\\nPersonally, I don't like this. URLs are now recognized by the SMS instant messaging apps and you just have to click on it.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sonyericsson.warrantytime\",\"description\":\"Lets you see some info about your warranty and how long it will last.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sonyericsson.xhs\",\"description\":\"Sony Xperia Lounge (discontinued by Sony on August 2019)\\nThe Xperia Lounge app was meant to provide loyal fans with various rewards for their Xperia smartphones, \\nsuch as exclusive Xperia Themes and wallpapers, as well as competitions.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sonymobile.advancedlogging\",\"description\":\"Advanced Logging\\nSends logs to Sony Mobile. These logs contain a wide range of personal information such as unique device IDs, your location, \\ndetails regarding running applications, and events/input leading up to a crash.\\nLogging is only active for a short time and automatically disabled once logging has been completed. \\nLogs are uploaded when connected to Wi-Fi and automatically deleted when the upload is complete.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sonymobile.advancedwidget.topcontacts\",\"description\":\"Top Contacts widget\\nIt will show pictures of your most frequently used contacts right on your home screen.\\nREMINDER : Widgets are small applications that you can use directly on the window screen. They also function as shortcuts\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sonymobile.android.addoncamera.soundphoto\",\"description\":\"Sony Sound Photo\\nLets you record a background sound and take a photo at the same time with the Sound Photo app.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sonymobile.android.contacts\",\"description\":\"Sony contacts\\n\",\"removal\":\"replace\",\"suggestions\":\"contacts\",\"type\":\"oem\"},{\"id\":\"com.sonymobile.android.contacts.res.overlay_305\",\"description\":\"Overlay for Sony contacts. Overlays are usually themes.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sonymobile.android.externalkeyboard\",\"description\":\"International keyboard layouts\\nUseless if you use a latin keyboard\\n\",\"removal\":\"replace\",\"suggestions\":\"keyboards\",\"type\":\"oem\"},{\"id\":\"com.sonymobile.android.externalkeyboardjp\",\"description\":\"Japanese layout for Sony keyboard.\\n\",\"removal\":\"replace\",\"suggestions\":\"keyboards\",\"type\":\"oem\"},{\"id\":\"com.sonymobile.androidapp.cameraaddon.areffect\",\"description\":\"Old package for AR Effect (https://play.google.com/store/apps/details?id=com.sonymobile.androidapp.cameraaddon.areffect)\\nLets you add AR (Augmented Reality) effects to your pictures and videos.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sonymobile.anondata\",\"description\":\"Anonymous Usage Stats (yes just as com.sonyericsson.idd.agent but it's for other phones)\\nUsed to send \\\"anonymous\\\" information about how you use your Sony Smartphone to Sony servers.\\nIt remains unclear exactly how this information is anonymized.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sonymobile.apnupdater\",\"description\":\"Automatically updates APN settings if your carrier changes them? I thought that was the role of com.android.carrierconfig\\nAPN: https://tamingthedroid.com/what-apn-settings-mean\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.sonymobile.apnupdater.res.overlay_305\",\"description\":\"Overlay for APN Updater. Overlays are usually themes.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.sonymobile.aptx.notifier\",\"description\":\"Aptx Notifier\\naptX (formerly apt-X) is a family of proprietary audio codec compression algorithms owned by Qualcomm.\\nIf you don't mind closed source codec, aptX has lower latency and is less of a drain on your battery than default codec (AAC)\\nThis package is used to display a notification when a device using aptX (bluetooth headphone typically) is connected.\\nIts only use is to tell you that you use aptX bluetooth with the connected device.\\n\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.sonymobile.assist\",\"description\":\"Xperia Assist (https://play.google.com/store/apps/details?id=com.sonymobile.assist)\\nLearns how you use your phone.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sonymobile.assist.persistent\",\"description\":\"Related to Xperia Assist (see just above) but I don't know its purpose.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sonymobile.camera\",\"description\":\"Sony camera app\\n\",\"removal\":\"replace\",\"suggestions\":\"cameras\",\"type\":\"oem\"},{\"id\":\"com.sonymobile.cameracommon.wearablebridge\",\"description\":\"Camera Wearable bridge\\nLets you take pictures with your phone by using Sony SmartWatch.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sonymobile.cellbroadcast.notification\",\"description\":\"Cell information\\nCell broadcast is designed to deliver messages to multiple users in an area.\\nThis is notably used by ISP to send Emergency/Government alerts.\\nhttps://en.wikipedia.org/wiki/Cell_Broadcast\\nhttps://www.androidcentral.com/amber-alerts-and-android-what-you-need-know\\nI think this package only handles notifications for broadcasts, not the implementation.\\nIt seems like broadcast SMS use normal notifications so there is a chance this package provides special notification for Sony SMS app?\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.sonymobile.coverapp2\",\"description\":\"Style Cover\\nThemes for lockscreen.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sonymobile.demoappchecker\",\"description\":\"Demo app checker\\nLets you enter/exit (in) the demonstration mode.\\nhttps://en.wikipedia.org/wiki/Demo_mode\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sonymobile.deviceconfigtool\",\"description\":\"Configuration agent\\nSeems to do things cloud related but it's unclear.\\nhttps://knowledge.protektoid.com/apps/com.sonymobile.deviceconfigtool/91e44f1e19b364411776d758ff3b27f703bd4b60c9399c43c124f37d0c30df27\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sonymobile.devicesecurity.service\",\"label\":\"DeviceSecurityService\",\"description\":\"Not needed. Collects sim and network data.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sonymobile.dualshockmanager\",\"description\":\"DUALSHOCK\\nProvide PlayStation DualShock controller support for Android (Settings > Device connection > Dualshock)\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sonymobile.email\",\"label\":\"Sony Email\",\"description\":\"Sony Email app\",\"removal\":\"replace\",\"suggestions\":\"email_clients\",\"type\":\"oem\"},{\"id\":\"com.sonymobile.entrance\",\"description\":\"What's New (discontinued in 2014)\\nProvided news from Sony products through extremely annoying automated notifications.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sonymobile.getmore.client\",\"description\":\"Xperia Tips (https://play.google.com/store/apps/details?id=com.sonymobile.getmore.client)\\nGives you tips for your Xperia device.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sonymobile.getset\",\"description\":\"Xperia Actions (discontinued)\\nLets you automate some actions (only a few) \\nhttps://support.sonymobile.com/global-en/xperiaxz/userguide/xperia-actions/\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sonymobile.getset.priv\",\"description\":\"Xperia Actions System\\nSame thing as com.sonymobile.getset.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sonymobile.gettoknowit\",\"description\":\"Introduction to Xperia (discontinued)\\nIntroduces you the features of your phone.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sonymobile.glovemode\",\"description\":\"Sony Glove mode\\nLets you use your smart phone and touch the screen while wearing regular gloves.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sonymobile.googleanalyticsproxy\",\"description\":\"Google Analytics Proxy\\nAllows you to publicly share your Google Analytics reporting data\\nhttps://developers.google.com/analytics/solutions/google-analytics-super-proxy\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sonymobile.home.product.res.overlay\",\"description\":\"\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.sonymobile.indeviceintelligence\",\"description\":\"Xperia Intelligence Engine\\nThis app is supposed to understand how you use the phone, the apps you prefer, and will suggest tips \\nand options based on app usage, how often you use an app, what time of day...\\nFor me this just looks like a AI bullshit app who has a huge list of permissions and launch in background at boot\\nThis app performs geofencing (check if your are located in a certain perimeter, near your home for instance) \\nand this doesn't looks great privacy-wise (https://en.wikipedia.org/wiki/Geo-fence)\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sonymobile.intelligent.backlight\",\"description\":\"Smart backlight control\\nKeeps the screen on as long as the device is held in your hand. Once you put down the device, the screen turns off according to your sleep setting.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sonymobile.intelligent.gesture\",\"description\":\"Smart call handling\\nLets you handle incoming calls without touching the screen.\\nhttps://support.sonymobile.com/global-en/xperiaxz/userguide/smart-call-handling/\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sonymobile.intelligent.iengine\",\"description\":\"According to a Sony user it is part of Smart Screen rotation (auto screen rotation based on the gyroscope). Doesn't seem reliable.\\nDoes it break the screen-rotation if removed?\\nOn Xperia 10VI: doesn't break rotation.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sonymobile.intelligent.observer\",\"description\":\"IntelligentObserver\\n???? (but intelligent stuff are safe to remove)\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sonymobile.lifelog\",\"description\":\"Lifelog (https://play.google.com/store/apps/details?id=com.sonymobile.lifelog)\\nAnother activity tracker app.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sonymobile.moviecreator.rmm\",\"description\":\"Movie Creator (https://play.google.com/store/apps/details?id=com.sonymobile.moviecreator.rmm)\\nAutomatically creates short movies using your photos and videos.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sonymobile.mtp.extension.fotaupdate\",\"description\":\"fota update service\\nFOTA = Firmware Over-The-Air\\nFOTA allows manufacturers to remotely install new software updates, features and services.\\nGiven there is \\\"mtp.extension\\\" in the package name, I think it lets you update your phone via your PC.\\nWhat's weird is that it should be called SEUS then (https://www.mobilefun.co.uk/blog/2008/06/software-updates-sony-ericsson/)\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.sonymobile.music.googlelyricsplugin\",\"label\":\"Google lyrics extension\",\"description\":\"Provides lyrics from Google in the Sony music app.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sonymobile.music.wikipediaplugin\",\"description\":\"Wikipedia plugin for sony music app\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sonymobile.music.youtubekaraokeplugin\",\"description\":\"YouTube karaoke plugin for sony music app\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sonymobile.music.youtubeplugin\",\"description\":\"YouTube plugin for sony music app\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sonymobile.pip\",\"label\":\"pip\",\"description\":\"Sony's PiP (Picture in Picture)\\nAllows videos to shrink down to a small resizable window.\\nOnly useful bere Android Oreo which provide native support for PiP?\",\"web\":[\"https://developer.android.com/guide/topics/ui/picture-in-picture\",\"https://support.sonymobile.com/global-en/xperiaxz1compact/faq/apps-&-settings/8019307455ff6184015e92f63324005926/\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sonymobile.pobox\",\"label\":\"Xperia™ Japanese Keyboard\",\"description\":\"Package is named after POBox (Predictive Operation Based On eXample), a Japanese text entry technology and ambiguous retrieval, proposed in 1998 by Sony CSL fellow Toshiyuki Masuda.\",\"web\":[\"https://www.sonycsl.co.jp/project/402/\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sonymobile.prediction\",\"description\":\"Sony text prediction (for Sony keyboard) \\nIt's only a supposition. Can someone confirm ?\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sonymobile.retaildemo\",\"description\":\"Retail Demo\\nRetail demonstration mode.\\nhttps://en.wikipedia.org/wiki/Demo_mode\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sonymobile.scan3d\",\"description\":\"Sony 3D Creator (https://play.google.com/store/apps/details?id=com.sonymobile.scan3d)\\nLets you capture your stuff in 3D, from your smartphone, and turn people and objects into high-resolution 3D avatars.\\nhttps://www.sonymobile.com/global-en/apps-services/3d-creator/\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sonymobile.simlockunlockapp\",\"description\":\"Sim Lock\\nProvide menu (type *#*#7378423#*#* in dialer) to see if your device is locked to a network carrier\\nIt need confirmation because it also could be related to SIM network unlock code.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sonymobile.smartcharger\",\"label\":\"Battery Care\",\"description\":\"Detects your charging patterns and estimates the start and end time of your regular charging period. \\nThe rate of charging is controlled so that your battery reaches 100% just before you disconnect the charger.\\nhttps://support.sonymobile.com/gb/xperiaxz/userguide/battery-and-power-management/\\n\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.sonymobile.support\",\"description\":\"Sony Support (https://play.google.com/store/apps/details?id=com.sonymobile.support)\\nUseless support app. \\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sonymobile.swiqisystemservice\",\"description\":\"\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.sonymobile.synchub\",\"description\":\"Sony Backup & restore feature to/from Google drive ?\\nCan someone confirm ? Does it impact com.sonyericsson.mtp.extension.backuprestore ?\\nhttps://support.sonymobile.com/global-en/xperia10/faq/apps-&-settings/801930747866b72a016b307df3b6007faf/\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sonymobile.telephony.extension\",\"description\":\"I have uninstalled it for the user 0 on my phone, and since then I haven't noticed any functionality drop.\\nCell signal is similar as before, also calls, SMSs and mobile data. I think it is not worth having this package installed because it uses a lot of wakelock time, but I cannot see any cell signal drop since I uninstalled it.\\nIn the code found some things: omadm, wifi calling, IMS. Its app for dual SIM reachability? Not sure if its app for debugging.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.sonymobile.themes.sou.cid18.black\",\"description\":\"Sony themes\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.sonymobile.themes.sou.cid19.silver\",\"description\":\"Sony themes\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.sonymobile.themes.sou.cid20.blue\",\"description\":\"Sony themes\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.sonymobile.themes.sou.cid21.pink\",\"description\":\"Sony themes\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.sonymobile.themes.xperialoops2\",\"description\":\"Sony themes\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.sonymobile.xperialounge.services\",\"description\":\"Xperia™ Lounge Pass service (discontinued)\\nThe Xperia Lounge app was meant to provide loyal fans with various rewards for their Xperia smartphones, \\nsuch as exclusive Xperia Themes and wallpapers, as well as competitions.\\nhttps://www.phonearena.com/news/Sony-Xperia-Lounge-shutting-down_id118252\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sonymobile.xperiaservices\",\"description\":\"Xperia services\\nI guess it provides things for Sony apps but I don't know what.\\nSafe to remove but it would good be to know what Sony apps work without it.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sonymobile.xperiatransfermobile\",\"description\":\"Xperia Transfer Mobile (https://play.google.com/store/apps/details?id=com.sonymobile.xperiatransfermobile)\\nHelps you move your contacts, messages, photos, and much more from your old Android, iOS or Windows Phone device to your new Xperia from Sony.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sonymobile.xperiaweather\",\"label\":\"Weather\",\"description\":\"Sony weather app\\nNote : Not all location are supported.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.sonymobile.xperiaweather\"],\"removal\":\"replace\",\"suggestions\":\"weather_apps\",\"type\":\"oem\"},{\"id\":\"com.sonymobile.xperiaxlivewallpaper\",\"description\":\"Xperia Loops\\nUseless and ugly live wallaper from Sony.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sonymobile.xperiaxlivewallpaper.product.res.overlay\",\"description\":\"Some overlay for a live wallpaper from Sony? Overlays are usually themes, but not sure about this one as theming seems weird for live wallpapers. Could be that Sony automatically generates theme packages for all or most system apps, which might generate some unnecessary packages.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sprd.ImsConnectionManager\",\"description\":\"Needed for IMS, WiFi Calling.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.sprd.autoslt\",\"description\":\"AutoSLT\\nUseless camera tests.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sprd.cameracalibration\",\"description\":\"Camera calibration, tests.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sprd.cameraipcontrol\",\"description\":\"Secret code: 83785. CameraIPControl, has some camera features for testing.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sprd.camta\",\"description\":\"Hidden camera dump logs.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sprd.engineermode\",\"description\":\"Testing Hardware Components\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sprd.firewall\",\"description\":\"Blacklist Calls.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.sprd.flashcontrol\",\"description\":\"Flashlight Control, not sure how useful it is.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.sprd.linkturbo\",\"description\":\"For WiFi speed? Has useless logs. I ran a speed test with it enabled and disabled, I don't see anything different if not my internet is slightly better now along with other apps being disabled,\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sprd.logmanager\",\"description\":\"YLog\\nHidden logs\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sprd.omacp\",\"description\":\"OTA Config and Settings.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.sprd.overlay.sprdnote\",\"description\":\"Overlay to 'com.sprd.sprdnote' png icons.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.sprd.providers.photos\",\"description\":\"Photos Types Storage\\nBokeh, portrait, FDR, AI photo.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.sprd.quickcamera\",\"description\":\"camera agent\\nAnother app for testing camera things.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sprd.srmi\",\"description\":\"Hidden logs in code only.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sprd.uasetting\",\"description\":\"UserAgent Setting\\nUserAgent Setting? Useless frameworks.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sprd.uplmnsettings\",\"description\":\"Set UPLMN? Useless frameworks.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.sprd.validationtools\",\"description\":\"Hidden testing hardware and it has a lot of secret codes.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.spreadtrum.ims\",\"description\":\"Needed for WiFi calling, VoLTE, VoWifi.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.spreadtrum.proxy.nfwlocation\",\"description\":\"Carrier location\\nCarrier location? Sends location to carrier probably. Useless Map Collections, also probably it's for testing location.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.spreadtrum.sgps\",\"description\":\"Useless GPS Test.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.spreadtrum.vce\",\"description\":\"Useless logs (dialer google, volte)\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.spreadtrum.vowifi\",\"description\":\"WiFi Calling Test\\nHidden tests WiFi calling.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.spreadtrum.vowifi.conf\",\"description\":\"VoWifi config Secret Code: 869434234\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.srin.indramayu\",\"label\":\"Samsung Gift Indonesia\",\"description\":\"Special application from Samsung that provides special offers and privileges for Indonesian users\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.ss.android.article.news\",\"description\":\"Chinese app NEWS Toutiao.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.ss.android.ugc.aweme\",\"description\":\"Chinese TikTok.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.st.nfc.dta.mobile\",\"description\":\"STNFCDta\\nUnknown checking app (NFC UID gen mode, NFC CDL value, CR version, Extended RF frame size, T4AT priority over P2P).\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.stability.camerastability\",\"description\":\"CameraStability\\nHidden camera test\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.stevesoltys.seedvault\",\"description\":\"Seedvault\\nRunning in the background.\\nit's app for Backup, Restore your data.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.summit.motorola.rcs\",\"description\":\"Summit IMS Service\\nA lot of logs and it's only for RCS messages. Anyway, it's a bad idea to use this app.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.suntek.mway.rcs.app.service\",\"description\":\"RCS service, contains a lot of Chinese.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.svox.pico\",\"description\":\"Pico TTS\\nHidden sample voice data. Useless.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.swfp.factory\",\"description\":\"Fingerprint test\\nHidden app that tests your fingerprint not available for users.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.t2m.euiccoverlay\",\"description\":\"Possibly needed for eSIM (eUICC)\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.taboola.scoop\",\"description\":\"Random wallpaper on lock screen (as i saw it personalizes it too). You need to open this app to make it work and when you swipe from right to left, it opens a menu on the right where random news appears.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.talpa.hiservice\",\"description\":\"HiLanguageService\\nUseless frameworks.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.tblenovo.center\",\"description\":\"Useless dashboard related to the User Experience Program (com.lenovo.ue.device). Has 25 permissions (including ones you probably don't want to give to this kind of sketchy app\\n\\nPithus analysis: https://beta.pithus.org/report/dcb4acac003896077eaaeb8c7dc770d3171891784d98f7127f8495a3dec9954d\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.tblenovo.lenovotips\",\"description\":\"Useless Lenovo Tips app used by Lenovo to display un-dismissable and un-mutable ads in notifications.\\n\",\"web\":[\"https://news.ycombinator.com/item?id=28382081\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.tblenovo.lewea\",\"label\":\"Lenovo Weather\",\"description\":\"Lenovo weather application\",\"web\":[\"https://beta.pithus.org/report/96601b7ec8ced18bf3896946ab43edde94b14e09b95e7787ea941b25ca02164b\"],\"removal\":\"replace\",\"suggestions\":\"weather_apps\",\"type\":\"oem\"},{\"id\":\"com.tblenovo.setup\",\"label\":\"SetupWizardExt\",\"description\":\"Exactly not sure what it does.\\n\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.tblenovo.soundrecorder\",\"label\":\"Sound Recorder\",\"description\":\"Sound recorder for lenovo devices.\\n\",\"web\":[\"https://beta.pithus.org/report/94123a466486800a367ecbedd5bbded54886834e001c20871d95c2820a9ea172\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.tblenovo.whatsnewclient\",\"label\":\"Lenovo Feature Update\",\"description\":\"Exactly not sure what it does.\\n\",\"web\":[\"https://beta.pithus.org/report/c1bf1b6a7b0bc987a654d8832274658251ba448858b34ce3b0a013309f9f0ade\"],\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.tblenovo.whatsnewhost\",\"label\":\"Lenovo Feature Update Host\",\"description\":\"Exactly not sure what it does.\\n\",\"web\":[\"https://beta.pithus.org/report/e08b8712d07899653631f3a9ac12c0ed48ff7bdb699651724eba26871ac0ca2b\"],\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.tcl.android.launcher\",\"label\":\"Launcher\",\"description\":\"Stock Launcher app.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.tcl.android.launcher.a_overlay\",\"description\":\"Another useless Chinese bookmarks icon overlay.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.tcl.android.launchertheme.res\",\"label\":\"Launcher theme resources\",\"description\":\"It's needed for themes, probably. Not sure if it's an important app.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.tcl.android.launchertheme.res.overlay\",\"description\":\"\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.tcl.android.wallpaper.livepicker\",\"description\":\"\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.tcl.aota.a_overlay\",\"description\":\"\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.tcl.camera\",\"description\":\"\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.tcl.camera.a_overlay\",\"description\":\"\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.tcl.compass\",\"description\":\"\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.tcl.compass.a_overlay\",\"description\":\"\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.tcl.demopage\",\"description\":\"\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.tcl.entitlement\",\"description\":\"\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.tcl.faceunlock\",\"description\":\"Standard FaceUnlock functionality?\\nUnlock your device by simply looking at the display.\\nFace unlock is bad for security and privacy:\\nhttps://www.ubergizmo.com/2017/03/galaxy-s8-facial-unlock-photograph/\\nhttps://www.kaspersky.com/blog/face-unlock-insecurity/21618/\\nhttps://www.freecodecamp.org/news/why-you-should-never-unlock-your-phone-with-your-face-79c07772a28/\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.tcl.fmradio\",\"label\":\"Radio\",\"description\":\"Stock Radio app\",\"removal\":\"replace\",\"suggestions\":\"radios\",\"type\":\"oem\"},{\"id\":\"com.tcl.fmradio.a_overlay\",\"description\":\"Another useless icon overlay.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.tcl.fota.system\",\"label\":\"System Update\",\"description\":\"Provides System Updates.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.tcl.fota.system.a_overlay\",\"description\":\"\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.tcl.healthy\",\"description\":\"\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.tcl.keyguardcharginganimation\",\"description\":\"Useless frameworks.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.tcl.keyguardshortcut\",\"description\":\"Useless frameworks.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.tcl.kidsmode\",\"description\":\"Kids Mode\\nIt's an app for limiting spending time on apps for kids probably.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.tcl.logger.a_overlay\",\"description\":\"Another useless icon overlay.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.tcl.mibc.tclplus\",\"description\":\"\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.tcl.mibc.tclplus.a_overlay\",\"description\":\"\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.tcl.nfc.gsma.usermenu\",\"description\":\"\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.tcl.screenrecorder\",\"description\":\"\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.tcl.screenrecorder.a_overlay\",\"description\":\"\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.tcl.screenshotex\",\"description\":\"\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.tcl.sos\",\"description\":\"\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.tcl.tclswitch.a_overlay\",\"description\":\"\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.tcl.tct.filemanager\",\"description\":\"File Manager\\nStock File Manager app\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.tcl.tct.weather\",\"description\":\"Weather\\nStock Weather app for TCL Phones.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.tcl.token\",\"label\":\"Token\",\"description\":\"It's for ECID number but it's safe to remove. Secret code 7383243.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.tcl.usercare\",\"description\":\"Support Centre, alcatel support. Safe to remove.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.tcl.usercare.a_overlay\",\"description\":\"Another useless icon overlay.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.tclhz.gallery\",\"label\":\"Gallery\",\"description\":\"Stock Gallery app\",\"removal\":\"replace\",\"suggestions\":\"gallery\",\"type\":\"oem\"},{\"id\":\"com.tclhz.gallery.a_overlay\",\"description\":\"\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.tct\",\"description\":\"\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.tct.aio\",\"label\":\"TCT All in One Configuration\",\"description\":\"It probably collects some data and CheckForUpdateTask OTA.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.tct.android.SaleCalib\",\"description\":\"Hidden camera after sale calibration.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.tct.android.browser\",\"description\":\"Browser\\nBetter use other browser.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.tct.android.secureinput\",\"label\":\"SecureInput\",\"description\":\"Useless secure input for keycode.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.tct.android.video\",\"description\":\"Video Player\\nStock Video Player app for TCL phones.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.tct.applock\",\"label\":\"App lock\",\"description\":\"It's just app lock with password or pin.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.tct.batterywarning\",\"label\":\"Battery warning\",\"description\":\"Displays only messages about low battery or too high temperature.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.tct.calculator\",\"label\":\"Calculator\",\"description\":\"Stock Calculator app\",\"removal\":\"replace\",\"suggestions\":\"calculators\",\"type\":\"oem\"},{\"id\":\"com.tct.calculator.a_overlay\",\"description\":\"\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.tct.camera\",\"description\":\"Camera\\nStock Camera app\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.tct.camera.a_overlay\",\"description\":\"Useless overlay. It has only an icon and no code.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.tct.camera.verifytool\",\"description\":\"Another hidden camera calibration and DualCamVerifyTool.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.tct.cellular.arda\",\"description\":\"\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.tct.compass\",\"description\":\"Compass\\nStock Compass app\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.tct.contacts.transfer\",\"label\":\"Transfer To Phone Contacts\",\"description\":\"It's additional thing.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.tct.diagprotector\",\"description\":\"\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.tct.dialer\",\"label\":\"Phone\",\"description\":\"Stock Phone app\",\"removal\":\"replace\",\"suggestions\":\"dialers\",\"type\":\"oem\"},{\"id\":\"com.tct.dialer.a_overlay\",\"description\":\"\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.tct.endusertest\",\"description\":\"Unused device issue feedback app.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.tct.entitlement\",\"description\":\"Requires Google Play services and is probably for Wi-Fi calling for O2 Carrier.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.tct.faceunlock\",\"description\":\"Standard FaceUnlock functionality?\\nUnlock your device by simply looking at the display.\\nFace unlock is bad for security and privacy:\\nhttps://www.ubergizmo.com/2017/03/galaxy-s8-facial-unlock-photograph/\\nhttps://www.kaspersky.com/blog/face-unlock-insecurity/21618/\\nhttps://www.freecodecamp.org/news/why-you-should-never-unlock-your-phone-with-your-face-79c07772a28/\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.tct.gamemode\",\"label\":\"Game box\",\"description\":\"Game Turbo. Not sure if it's worth keeping or not.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.tct.gdpr\",\"description\":\"\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.tct.gpdr\",\"description\":\"GPDR\\nUser Experience Improvement Program.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.tct.iris\",\"description\":\"NXTVISION\\nIt's for reading mode and Display Enhancement.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.tct.logger\",\"description\":\"User Support\\nit's for logs.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.tct.multipleuser\",\"description\":\"Multiple User\\nI guess it's for multi-accounts.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.tct.music\",\"label\":\"Music\",\"description\":\"Stock Music app\",\"removal\":\"replace\",\"suggestions\":\"music_apps\",\"type\":\"oem\"},{\"id\":\"com.tct.onetouchbooster\",\"label\":\"Alcatel Smart Manager\",\"description\":\"For power saving.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.tct.onetouchbooster.a_overlay\",\"description\":\"\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.tct.phone\",\"description\":\"TCT Phone Services\\nSim card settings.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.tct.privacymode\",\"description\":\"\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.tct.privacyprotect\",\"description\":\"Privacy Protection\\nAnother Security thing.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.tct.privatespace\",\"label\":\"Private Space\",\"description\":\"Only password things.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.tct.reducesar\",\"description\":\"Hidden Modify the SAR mode.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.tct.retaildemo\",\"description\":\"Demo Mode is intended for use on shop demo devices only and it should never be activated on a normal user's device. Explained by TCL.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.tct.retaildemo.a_overlay\",\"description\":\"\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.tct.screenrecorder\",\"description\":\"Screen Recorder\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.tct.screenshotex\",\"description\":\"Screenshot\\nit's used for screenshots and editing them.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.tct.secretCode\",\"description\":\"This app has only logs.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.tct.setupwizard\",\"label\":\"Setup Wizard\",\"description\":\"It's needed only for first-boot setup.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.tct.sidebar\",\"description\":\"Edge Bar\\nSidebar\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.tct.simplelauncher\",\"label\":\"Simple Launcher\",\"description\":\"It's not needed for the Stock launcher and has SOS and other unnecessary stuff.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.tct.simplelauncher.a_overlay\",\"description\":\"\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.tct.simsettings\",\"description\":\"\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.tct.smart.account\",\"description\":\"\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.tct.smart.aikey\",\"description\":\"\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.tct.smart.aota\",\"description\":\"OTA Updates or OTA Updates test?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.tct.smart.cloud\",\"description\":\"\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.tct.smart.drivemode\",\"description\":\"\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.tct.smart.ircontrol\",\"description\":\"IR Remote\\nI think it's useless.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.tct.smart.lostmode\",\"description\":\"Remote Lock\\nIt's for lost mode.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.tct.smart.notes\",\"label\":\"Smart Notes\",\"description\":\"Stock Notes app\",\"removal\":\"replace\",\"suggestions\":\"note_taking_apps\",\"type\":\"oem\"},{\"id\":\"com.tct.smart.push\",\"description\":\"Smart Push\\nUseless frameworks.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.tct.smart.switchphone\",\"label\":\"Switch Phone\",\"description\":\"It's app for Move apps to new or old phone.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.tct.smart.switchphone.service\",\"description\":\"\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.tct.smart.tlink\",\"description\":\"Easy Link\\nIt has something to do with screen casting. Dlna Cast Activity.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.tct.soundrecorder\",\"label\":\"Sound Recorder\",\"description\":\"An audio and screen recorder, lets you change voice.\",\"removal\":\"replace\",\"suggestions\":\"audio_recorders\",\"type\":\"oem\"},{\"id\":\"com.tct.systemservice\",\"description\":\"It should be safe to remove. Only secret code to info about system but not sure.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.tct.tctsmartapprecommend\",\"description\":\"Smart App Recommend\\nUseless.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.tct.usercare\",\"description\":\"Support Center\\nit's for TCL users support center app.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.tct.video\",\"description\":\"\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.tct.weather\",\"label\":\"Weather Forecast\",\"description\":\"Weather forecasting app.\",\"removal\":\"replace\",\"suggestions\":\"weather_apps\",\"type\":\"oem\"},{\"id\":\"com.tct.weather.a_overlay\",\"label\":\"com.tct.weather.a_overlay\",\"description\":\"Overlay for com.tct.weather. Usage is not known.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.tct.wfcwebiew\",\"label\":\"WfcWebView\",\"description\":\"WebView app for TCL\",\"removal\":\"caution\",\"warning\":\"Make sure to have another WebView before removing it.\",\"suggestions\":\"webviews\",\"type\":\"oem\"},{\"id\":\"com.tct.wfcwebview\",\"description\":\"I found something like entitlementMode but app looks very empty and useless.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.ted.number\",\"description\":\"Identification of Unknown Numbers\\nApp for identify unknown numbers.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.teksun.factorytest\",\"description\":\"Hidden testing hardware things.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.telephony.service\",\"description\":\"Needed for WiFi Calling.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.tencent.android.location\",\"description\":\"Useless Tencent Chinese location\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.tencent.ngjp\",\"description\":\"Arena of Valor\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.tencent.qqlivehuawei\",\"description\":\"HiMoviePlayerPlus\\nWeird app without any code and there's nothing in Main Activity.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.tencent.soter.soterserver\",\"description\":\"Soter is a biometric authentication standard and platform by Tencent.\\nhttps://github.com/Tencent/soter\\nProvides biometric authentication for WeChat Pay. Safe to disable if you don't use it.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.test.LTEfunctionality\",\"description\":\"LTE, VoLTE testing app\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.theme.icondefaultshape\",\"description\":\"The shape of the icons can be uninstalled or left alone, it's just the look of the icon.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.thinkuem.motolc\",\"description\":\"ThinkIoT-UEM\\nIt has remote service but probably it's unused.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.thundercomm.ar.core\",\"description\":\"Looks like a debugging app.\\nIt's AR (Augmented Reality)?\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.tools.cit\",\"description\":\"Hidden testing hardware things.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.touchscreen.vtstouchscreencheck\",\"description\":\"VtsTouchscreenCheck\\nIt's testing things app.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.tran.netcon\",\"description\":\"Netcon\\nit's unneccessary\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.transsion\",\"description\":\"Needed for screen unlock? Has Packages, Bluetooth permission. Probably unsafe.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.transsion.XOSLauncher\",\"description\":\"Launcher with ads, tracking.\\nAfter remove you will lose recent apps.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.transsion.aftersalecalibrationtool\",\"description\":\"Hidden camera tests, calibration.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.transsion.agingfunction\",\"label\":\"AgingFunction\",\"description\":\"Another test mode, aging setting. secret code 2828, 2829, 2830.\",\"web\":[\"https://beta.pithus.org/report/02b71ec4be036fe87b5504b4f752a7c7cb45848b5d666c4307e59df754e164c9\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.transsion.aisettings\",\"description\":\"Adds a shortcut on the Settings app that lets you manage your Folax AI (com.transsion.aivoiceassistant) settings. If you have already removed that package, it just displays a blank page.\\nThis can also be safely removed without issues.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.transsion.aivoiceassistant\",\"description\":\"Very shady voice assistant called 'Folax' that comes preinstalled in Infinix phones, and is also packed with ads in the main ui. It needs every permission, and access to everything on your phone to run. It uses OpenAI as its backend.\\nIt constantly runs in the background after boot, and periodically phones home.\\nYou don't want this on your phone.\\nThis can be safely removed without issues.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.transsion.aiwallpaper\",\"description\":\"Mediocre AI Wallpaper Generator.\\nCan be accessed from (Settings > Personalization).\\nYou can safely remove this without any issues if you don't use it.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.transsion.aod\",\"description\":\"AlwaysOnDisplay\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.transsion.applock\",\"label\":\"AppLock\",\"description\":\"Provides the only way to hide files and lock apps when using Transsion launchers (which the Transsion devices require for certain functionality like multiapps not working with other launchers). These are the only apps that hide files and lock apps with them.\",\"removal\":\"caution\",\"warning\":\"Removal breaks the Recents feature.\",\"type\":\"oem\"},{\"id\":\"com.transsion.audioshare\",\"description\":\"Audio Share\\nAllows you to share your device’s Bluetooth audio with wireless headphones or bluetooth speakers, allowing to listen to the same music with multiple people\\nPithus analysis: https://beta.pithus.org/report/0f21ba3944663e53da1d37be3c4253c2e89c3685fbff841127fed2a98e0000ec\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.transsion.auto\",\"description\":\"Driving Mode\\nDriving Mode app.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.transsion.autotest.factory\",\"description\":\"Factory. Testing Hardware Things.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.transsion.avatar\",\"description\":\"Is this for T-moji avatar services? it's useless.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.transsion.batterylab\",\"description\":\"Supposed to improve battery life but logs especially lots of usage info and bind it to your unique android advertiser id...The app tries to send data to a server. The POST request URL and content is obfuscated and I don't have the time to dig deeper. According to a user, no battery impact after months of usage after uninstalling it.\\n\\nPithus analysis: https://beta.pithus.org/report/7ef2b186a74102828346f23b094ab2aaaad2c57806c7c18e7a23a494f3cc982c\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.transsion.batterylab.icon\",\"description\":\"Power Marathon\\nIt's only icon app.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.transsion.beezedit\",\"description\":\"Ringtone Maker\\nRequire Google Play Services.\\nRecord media sound and edit or set it as ringtone.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.transsion.bluetooth\",\"description\":\"Airlink\\nBluetooth still work without this.\\n(not sure if its needed for transfer files using bluetooth)\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.transsion.calculator\",\"description\":\"Calculator\\nStock Calculator app. Lot of telemetry and are completely replaceable.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.transsion.calendar\",\"description\":\"Calendar\\nStock Calendar app\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.transsion.camera\",\"description\":\"Camera\\nStock camera app\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.transsion.carlcare\",\"description\":\"Carlcare (https://play.google.com/store/apps/details?id=com.transsion.carlcare)\\nAfter-sales Service app. Lets you check spare parts price,warranty,repair status and nearest service center. Full of trackers. Talks with Facebook (https://reports.exodus-privacy.eu.org/fr/reports/com.transsion.carlcare/latest/)\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.transsion.childmode\",\"label\":\"Kids Mode\",\"description\":\"Phone monitoring app to control what the user the can do on the phone. Intrusive and use Firebase so it's sends data back to Google servers.\",\"web\":[\"https://beta.pithus.org/report/ca30c6d1d7c7625e0850c4114dfea5aab5118d391191d2c074cde1414bbccd8c\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.transsion.childmode.resoverlay\",\"description\":\"Unused overlay to childmode.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.transsion.chromecustomization\",\"description\":\"Chrome Assistant\\nCustomizes HomePage and uses Advertising ID.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.transsion.connectx.mirror.source\",\"description\":\"it's something for cast setting, file transfer setting, smart connect to pc by TCCP\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.transsion.datatransfer\",\"description\":\"Backup and Restore\\nBackup Contacts.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.transsion.deadcycletest\",\"description\":\"DeadCycleTest\\nHidden tests.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.transsion.deskclock\",\"description\":\"Clock\\nCan manage alarms by this app.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.transsion.dirac\",\"description\":\"Improves audio quality depending on your surrounding environment and your headphones.\\nHas the GET_TASKS/REAL_GET_TASKS permission which allows it to retrieve information about currently and recently running processes. Not sure why it needs this permission though.\\nhttps://www.dirac.com/\\nPithus analysis: https://beta.pithus.org/report/b2cf41f579c586468faa0270bf63699cca2b500887dba3a699ddd5e35507a1a9\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.transsion.dtsaudio\",\"description\":\"DTS Sound\\nVery safe to disable and just serves as a way to modify audio playing and runs in the background and has telemetry can be replaced by other better apps\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.transsion.dualapp\",\"description\":\"Dual App\\nNeeded for Dual Apps.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.transsion.faceid\",\"description\":\"Needed for Face Unlock lock screen.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.transsion.faceidsub\",\"description\":\"Face Unlock\\nSafe to remove if unused.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.transsion.filemanagerx\",\"label\":\"File Manager\",\"description\":\"Comes with 3 analytics/ads trackers.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.transsion.filemanagerx\",\"https://reports.exodus-privacy.eu.org/fr/reports/com.transsion.filemanagerx/latest/\"],\"removal\":\"replace\",\"suggestions\":\"file_managers\",\"type\":\"oem\"},{\"id\":\"com.transsion.fmradio\",\"description\":\"WOW FM\\nApp for FM RADIO.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.transsion.hamal\",\"description\":\"It seems to be an \\\"aftersales user experience logging app\\\". Really shady app with questionable code (judgeWhiteUser() function. See https://github.com/0x192/universal-android-debloater/pull/112).\\n\\nStart at boot and can access phone number and IMEI (READ_PHONE_STATE).\\n\\nPithus analysis: https://beta.pithus.org/report/35fd79ebbe51808196605146a62aaef13bc654477d917078a3ae5d3f06ba8836\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.transsion.health\",\"description\":\"Tecno health app. Sends your personal data to Firebase google servers and Tecno servers. Those data can be shared with TRANSSION affiliated companies (see https://cdn.shalltry.com/transsionholdings/en/policy.html)\\nPithus analysis: https://beta.pithus.org/report/2b7cd35081a9fbc82a1da1741cb476d1edaa3262d46a204ea8456c99c4e1b976\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.transsion.healthlife\",\"description\":\"My Health\\nProvides you with interesting and professional analyses of running, steps, weight management etc.\\nhttps://play.google.com/store/apps/details?id=com.transsion.healthlife\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.transsion.hilauncher\",\"description\":\"HiOS Launcher\\nIt have google analytics and it's so bloated.\\nThe recent apps button does not work after uninstallation.\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.transsion.hiparty\",\"description\":\"Hi Party\\nAllows you to synchronize and play the same song across multiple *supported* devices. The app creates a wifi hotspot. You can connect up to 6 devices via QR code to simultaneously broadcast music.\\n\\nNeeds permissions you probably doesn't want to give : READ_PHONE_STATE (can read phone number and IMEI) and ACCESS_FINE_LOCATION.\\nPithus analysis: https://beta.pithus.org/report/154ee6107d3f5bbb0819719fc7ce5fd17474135081f576f56c29bd26ed70ca14\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.transsion.infinix.xclub\",\"description\":\"Pre-installed social network app:\\nhttps://www.infinix.club/\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.transsion.iotservice\",\"description\":\"WelinkService\\nPC Connect unneccessary things\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.transsion.itel.manual\",\"description\":\"Manual Guide\\nHas guides to phone.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.transsion.kolun.aiservice\",\"description\":\"it's for testing things and debugging.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.transsion.kolun.assistant\",\"description\":\"Smart Assistant App\\nNearly no code in the APK I got. Weird\\nPithus analysis: https://beta.pithus.org/report/7fbf0abbb2c28de4c976a388e04d206a88db9e6a42a740914c9e893589fd493b\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.transsion.letswitch\",\"description\":\"Mobile Cloner\\nit's probably useful when you switch to other phone to move your apps.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.transsion.livewallpaper.volcano\",\"description\":\"Tranquil Blue live wallpaper\\nspecific live wallpaper\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.transsion.livewallpaper.wakeup_mirror\",\"description\":\"Specific Live Wallpaper.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.transsion.magazineservice.hios\",\"description\":\"Shows trending news, games and wallpapers on the lockscreen. Talks to ads services\\nPithus analysis: https://beta.pithus.org/report/fcda43fab1ed9cdc95281cdb96b77938afc8ca4b6e0ada418cac282a78f0cc9f\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.transsion.magazineservice.xos\",\"description\":\"Magazine Lockscreen XOS\\nResource-hog bloatware that uses a lot of telemetry. For lock screen to look at pictures... https://play.google.com/store/apps/details?id=com.transsion.magazineservice.xos\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.transsion.magicfont\",\"label\":\"Font Manager\",\"description\":\"Formerly, Magic Font.\\nFonts installer with a lot of trackers obviously.\\nFor Transsion devices I'm pretty sure this is the only way you can install fonts, even Zfont uses this app to install fonts.\",\"web\":[\"https://reports.exodus-privacy.eu.org/fr/reports/com.transsion.magicfont/latest/\"],\"removal\":\"caution\",\"warning\":\"Breaks the functionality of changing fonts if removed.\",\"type\":\"oem\"},{\"id\":\"com.transsion.magicshow\",\"label\":\"Video Player\",\"description\":\"(Bad) video Player with Ads and weak security (including an unsecured WebView implementation that can lead to XSS attacks.\",\"web\":[\"https://beta.pithus.org/report/33cd478cc18f3a2c0d5f7fd33c7350127ee2cff7acdf87f70641ca21dd2b2dcb\"],\"removal\":\"replace\",\"suggestions\":\"video_players\",\"type\":\"oem\"},{\"id\":\"com.transsion.manualguide\",\"description\":\"Digital version of your phone manual.\\nYou can view it from (Settings > System > Manual Guide)\\nCan be safely removed if you don't need it.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.transsion.microintelligence\",\"label\":\"Actions and Gestures\",\"description\":\"Formerly, Micro Intelligence.\\nProvides features like tap to awake, awake on device raise, etc.\\nPhones home.\",\"web\":[\"https://beta.pithus.org/report/f7358ad68b27d9fa75a8e742ad43c64f2710b4ba5378ee825215ebbd08549275\"],\"removal\":\"caution\",\"warning\":\"Disabling this app makes you unable to use specific settings like Gesture Navigation and Action & Gesture along with other phone features.\",\"type\":\"oem\"},{\"id\":\"com.transsion.mol\",\"description\":\"Ella Translate\\nUnknown translator.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.transsion.multiwindow\",\"description\":\"Multi Window\\nNeeded for multi window.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.transsion.nephilim\",\"description\":\"App provides custom quality settings to game: pubg, call of duty.\\nNot very useful.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.transsion.netphilim\",\"description\":\"Chinese useless frameworks.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.transsion.notebook\",\"description\":\"Notepad app\\nThese apps have telemetry on them and are completely replaceable.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.transsion.os.typeface\",\"description\":\"FontManager\\nNot sure if it's needed or not.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.transsion.ossettingsext\",\"description\":\"OSSettings\\nit's needed for some settings and probably it's important app.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.transsion.overlaysuw\",\"description\":\"it's needed only on first-boot setup.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.transsion.overlaysuw.resoverlay\",\"description\":\"Overlay to 'com.transsion.overlaysuw' safe to remove because it's for first-boot setup.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.transsion.phoenix\",\"description\":\"Phoenix Browser\\nhttps://play.google.com/store/apps/details?id=com.transsion.phoenix&hl=en\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.transsion.phonemanager\",\"description\":\"PhoneMaster Services\\nAnother useless frameworks.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.transsion.phonemaster\",\"description\":\"Phone Master.\\nProvides features like ram cleaning, storage optimisation, data usage analyser, etc. Has embedded Facebook and Google ads trackers. Has 45 permissions and makes request data to many different companies servers. There even is the usesCleartextTraffic=true flag in the Manifest meaning trafic may not even be encrypted\\n\\nPithus analysis: https://beta.pithus.org/report/a5346fb5ea4fba5b73a891eae064b2bdecefbc7de4f9a13e3dcf94b0a81a20af\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.transsion.plat.appupdate\",\"description\":\"App Update\\nUsed to update apps installed from the Palm Store. Uses insecure encryption algorithm.\\nNotables permissions: ACCESS_FINE_LOCATION and GET_TASKS (allows to see which apps are running on the phone). Useless background memory hogs if you don't use apps from the Palm Store\\n\\nPithus analysis: https://beta.pithus.org/report/2584e9529e0988c1c2f9d657c5e2c55d1770e451d4120c176b5a505f2ee1033d\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.transsion.powercenter\",\"description\":\"power\\nHas WhatsApp mode and ultra powersaving mode.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.transsion.quicktools\",\"description\":\"Launcher Activity Test\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.transsion.repaircard\",\"description\":\"E-warranty Card\\nFor Chinese users-only.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.transsion.scanningrecharger\",\"description\":\"Smart Scanner\\nApp contains telemetry and is completely replaceable.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.transsion.screencapture\",\"description\":\"Needed for screenshots.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.transsion.sk\",\"description\":\"Secure Keyboard\\nUseless Secure Keyboard.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.transsion.smartmessage\",\"description\":\"Bloated Messages app with a lot of features.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.transsion.smartpanel\",\"description\":\"Smart Panel (Settings -> Smart Assistant)\\nProvides \\\"easy\\\" access to your most used apps + features like gamemode and videoAssistant. Collects data and talks with the outside\\n\\nPithus analysis: https://beta.pithus.org/report/40d4b527fc650a9029e596d14aff7d640a6289e7aa50f471b142391b55eefe4a\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.transsion.soundrecorder\",\"description\":\"Sound Recorder\\nContains telemetry and is completely replaceable.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.transsion.stasticalsales\",\"description\":\"Sends after-sales telemetry data (including at least the phone number and the IMSI). You don't want this. This app can be launched from this secret dialer code: 862016\\n\\nPithus analysis: https://beta.pithus.org/report/35fa58c779ac80bcf44875e279cc4a6ba08678b0004e9c8f0816426cf0c584ab\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.transsion.statisticalsales\",\"description\":\"Sales Statistics\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.transsion.systemupdate\",\"description\":\"System Update\\nProvides System Updates\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.transsion.tabe\",\"description\":\"APPIOT\\nUnused frameworks to permissions app.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.transsion.tecnospot\",\"description\":\"TECNO SPOT (https://play.google.com/store/apps/details?id=com.transsion.tecnospot)\\nTecno official app to access the Tecno forum. Useless and full of trackers (https://reports.exodus-privacy.eu.org/fr/reports/com.transsion.tecnospot/latest/)\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.transsion.teop\",\"description\":\"it's app for testing and logs\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.transsion.theme.icon\",\"description\":\"Has basic apps icons, not sure if needed.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.transsion.thunderback\",\"description\":\"Lightning Multi-Window\\nMulti-Window feature for apps.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.transsion.tips\",\"description\":\"Tips\\nApp for tips.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.transsion.tower\",\"description\":\"ControlTower test\\nTesting things app.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.transsion.trancare\",\"description\":\"Telemetry. Makes requests (with weak crypto) to the Shalltry CDN (https://mi-test.shalltry.com). Collects IMEI, all the apps installed, localisation...\\nPithus analysis: https://beta.pithus.org/report/9be13b57bde5620d2ff1824782a2ccc1d6517d437543549c720bc70b6dd02aee\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.transsion.tranengine\",\"description\":\"Unused frameworks.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.transsion.uxdetector\",\"description\":\"AI things to trancare\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.transsion.videocallenhancer\",\"description\":\"Applies beauty effect in WhatsApp video calls. Lots of permissions. Talks to Google ads service.\\nPithus analysis: https://beta.pithus.org/report/47bebb911e9b5b9202030ce599805ebe3e47eb45054264f49cf85971e232bbce\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.transsion.vishaplayerhd\",\"description\":\"Visha Player\\nNeeded to run videos.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.transsion.wezone\",\"description\":\"Related to 'Gaming Mode' and 'Palm Store'\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.transsion.wifiplaytogether\",\"description\":\"Play music together over Wi-Fi\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.transsion.zahooc\",\"description\":\"Za-Hooc\\nit's for secure card and Theft Alert.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.transsnet.moreplus\",\"description\":\"More+ is a social app with massive videos, images, opinions and tribes, where you can post your personal blogs, share funny moments, chat and make friends.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.transsnet.store\",\"description\":\"Palm Store. App store with unsecure apps and probably malware. Has ads trackers and lot of intrusives permissions. Shows intrusive ads and popups.\\nPithus analysis: https://beta.pithus.org/report/35d762b27c9e16703adf1731b74bef2c53a753b6a7475c425bced53b553758e5\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.trassion.infinix.xclub\",\"description\":\"XClub\\nXStore to buy.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.ts.setupwizard.overlay.overlay\",\"description\":\"\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.uievolution.gguide.android\",\"description\":\"This hidden chinese app means nothing\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.unionpay.tsmservice\",\"description\":\"UnionPay\\nOnly for China.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.unionpay.tsmservice.mi\",\"description\":\"UnionPay\\nOnly for China.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.unisoc.launcher.customization\",\"description\":\"Unisoc Home Screen\\nPartner Customization launcher.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.unisoc.localeupdate\",\"description\":\"Local System Update\\nNeeded for system updates.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.unisoc.phone\",\"label\":\"LockAssistant\",\"description\":\"Runs before the user unlocks the device (direct-boot aware). Reads IMEI, SMS, call log, uses gps/wifi. Unisoc is a CPU manufacturer. Related to package `com.android.unisoc.telephony.server`.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.vendor.frameworkresoverlay\",\"description\":\"\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.vewd.core.integration.dia\",\"description\":\"Sony's browser app. Some apps redirect to the browser so it can be useful. You can use another browser as long as you have another one installed.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.visionobjects.resourcemanager\",\"description\":\"Handwriting DB Updater (discontinued?)\\nLanguage Updater from site http://samsungresources.visionobjects.com/\\nBut it's tracker. I guess it's to Handwriting Service but not needed.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.vivo.SmartKey\",\"description\":\"Quick action\\nChinese smart things.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.vivo.abe\",\"description\":\"Audio EQ(equalizer)\\nSome 3rd-party music apps can use it to provide you EQ features.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.vivo.alphacamera\",\"description\":\"AlphaCamera\\nEngineering Mode, Log, Debugging service camera.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.vivo.android.connectivity.common.resources.overlay\",\"description\":\"Better keep for connectivity.\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.vivo.android.connectivity.mainline.common.resources.overlay\",\"description\":\"Better keep for connectivity.\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.vivo.android.connectivity.mainline.manufacturer.resources.overlay\",\"description\":\"Better keep for connectivity.\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.vivo.android.connectivity.manufacturer.resources.overlay\",\"description\":\"Better keep for connectivity.\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.vivo.android.wifi.common.resources.overlay\",\"description\":\"Better keep for connectivity.\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.vivo.android.wifi.mainline.common.resources.overlay\",\"description\":\"Better keep for connectivity.\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.vivo.android.wifi.mainline.manufacturer.resources.overlay\",\"description\":\"Better keep for connectivity.\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.vivo.android.wifi.manufacturer.resources.overlay\",\"description\":\"Better keep for connectivity.\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.vivo.appfilter\",\"description\":\"AppFilter\\nHas something to powersaving like prevent autostart apps.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.vivo.appstore\",\"description\":\"V-Appstore\\nvivo app store.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.vivo.assistant\",\"description\":\"Vivo assistant\\nAssistant for vivo phones.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.vivo.assistantfunction\",\"description\":\"Steps\\nJovi Home kit. Record walk sport app.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.vivo.audiofx\",\"description\":\"Audio effect\\nNeeded for sound effects.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.vivo.browser\",\"description\":\"Vivo browser full of trackers (https://play.google.com/store/apps/details?id=com.vivo.browser)\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.vivo.bsptest\",\"description\":\"BSPTest\\nHidden app for testing things.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.vivo.calculator\",\"description\":\"Calculator\\nVivo calculator app\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.vivo.camera.action\",\"description\":\"Maybe it's needed for the camera app.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.vivo.card\",\"description\":\"Smart sidebar\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.vivo.compass\",\"description\":\"Compass\\nVivo compass app\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.vivo.contentcatcher\",\"description\":\"Unused frameworks.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.vivo.cota\",\"description\":\"COTA\\nUseless logs and ads. It's for recommendations.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.vivo.crontab\",\"description\":\"Task timer\\nIt's for scheduling tasks.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.vivo.daemonService\",\"description\":\"vivoService\\nSecurity thing.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.vivo.demovideo\",\"description\":\"Video Demo\\nDemo Video, Demo Switch, and have verify activity\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.vivo.desktopstickers\",\"description\":\"Stickers\\nCustomize widgets with favorite images.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.vivo.devicereg\",\"description\":\"Hidden debugging app ims.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.vivo.doubleinstance\",\"description\":\"App Clone\\nIt's for clone app.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.vivo.doubletimezoneclock\",\"description\":\"i Widget\\nDouble Timezone Clock Widget\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.vivo.dream.clock\",\"description\":\"Clock\\nScreensaver clock\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.vivo.dream.music\",\"description\":\"i Music\\nScreensaver music\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.vivo.dream.weather\",\"label\":\"Weather\",\"description\":\"Screensaver weather.\",\"removal\":\"replace\",\"suggestions\":\"weather_apps\",\"type\":\"oem\"},{\"id\":\"com.vivo.easyshare\",\"description\":\"Easy share\\nSharing apps to another phone.\\nhttps://play.google.com/store/apps/details?id=com.vivo.easyshare\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.vivo.email\",\"description\":\"Email\\nclosed-source Email app\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.vivo.engineercamera\",\"description\":\"EngineerCamera\\nTesting camera things.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.vivo.epm\",\"description\":\"EPM\\nUseless crash app notify.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.vivo.ewarranty\",\"description\":\"E-warranty card\\nOnly for China.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.vivo.faceui\",\"description\":\"FaceUI\\nIt's used for face unlock.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.vivo.faceunlock\",\"description\":\"Facial recognition\\nIt's used for face unlock.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.vivo.favorite\",\"description\":\"Favorites\\nIt's used to add text from the clipboard to favorites. Probably requires cloud. Contains untranslated Chinese things.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.vivo.feedback\",\"description\":\"Feedback\\nLets you rate your device and share feedback.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.vivo.findphone\",\"description\":\"Find\\nIt's used for finding the phone. Log out from account before removing.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.vivo.fingerprint\",\"description\":\"Fingerprints and passwords\\nNeeded for fingerprint settings.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.vivo.fingerprintengineer\",\"description\":\"Fingerprint test\\nHidden Fingerprint testing not available for normal users.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.vivo.fingerprintui\",\"description\":\"FingerprintUI\\nFingerprint test? Contains payment functionality for China. May be needed for fingerprint lockscreen.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.vivo.fingerprintvit\",\"description\":\"Fingerprint testing.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.vivo.floatingball\",\"description\":\"Floating ball\\nContains a lot of Chinese code.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.vivo.fuelsummary\",\"description\":\"FuelSummary\\nBattery testing.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.vivo.gallery\",\"description\":\"Gallery\\nVivo gallery app with Chinese trackers.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.vivo.game\",\"description\":\"Game Space. Not sure if its useful for gaming.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.vivo.gamecube\",\"description\":\"Ultra Game Mode\\nUsed for game optimization. Questionable if anyone is using this.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.vivo.gamewatch\",\"description\":\"GameWatch\\nContains a lot of Chinese code and it's hidden?\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.vivo.globalanimation\",\"description\":\"Global dynamic effects\\nThis is for effects and animations.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.vivo.globalanimation.resources\",\"description\":\"GlobalanmationResources\\nHas animation booting probably, safe to remove.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.vivo.globalsearch\",\"description\":\"Global Search\\nit's chinese searching.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.vivo.healthwidget\",\"description\":\"Health kit\\nit's only widgets.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.vivo.heduohao\",\"description\":\"Used for Chinese SIM.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.vivo.hiboard\",\"description\":\"Smart Launcher\\nKeyboard app with 62 permissions.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.vivo.hybrid\",\"description\":\"Quick App\\nProvides Quick App support. Quick Apps are Javascript+CSS apps that don't need any installation. This technology has its uses but I'm personally not a huge fan on having to rely on a JS engine to run an application\\nThis system app has a lot of permissions (including SEND_SMS, CAMERA, READ_EXTERNAL_STORAGE, RECORD_AUDIO... why?)\\nMore information: https://www.xda-developers.com/huawei-quick-apps-alternative-google-instant-apps/\\n OW2 Quick App whitepaper: https://quick-app-initiative.ow2.io/docs/Quick_App_White_Paper.pdf\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.vivo.imanager\",\"description\":\"iManager\\nA vivo app consists of Phone Management includes Space Cleanup, Security Scan, Data Traffic Management, Apps & Notifications & Utility Tools includes App encryption, Battery Management, App Clone, Network Management etc.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.vivo.iotserver\",\"description\":\"Related to Jovi Chinese.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.vivo.livewallpaper.behavior\",\"description\":\"Live Wallpaper Behavior.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.vivo.livewallpaper.behavior.resources\",\"description\":\"WallpaperResources\\nHas live wallpapers.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.vivo.livewallpaper.coffeetime\",\"description\":\"Specific Live wallpaper\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.vivo.livewallpaper.coralsea\",\"description\":\"Specific Live wallpaper\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.vivo.livewallpaper.floatingcloud\",\"description\":\"com.vivo.livewallpaper.coffeetime\\nSpecific Live wallpaper\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.vivo.livewallpaper.ocean\",\"description\":\"Live Wallpaper Ocean.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.vivo.livewallpaper.oceanvertical\",\"description\":\"Live Wallpaper Oceanvertical.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.vivo.livewallpaper.plant\",\"description\":\"Plant live wallpaper\\nSpecific live wallpaper.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.vivo.livewallpaper.silk\",\"description\":\"com.vivo.livewallpaper.coffeetime\\nSpecific Live wallpaper\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.vivo.magazine\",\"description\":\"Lockscreen Poster Service\\nUseless things to lockscreen also it has trackers\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.vivo.minscreen\",\"description\":\"Small screen mode\\nThis feature is available on settings.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.vivo.monochromeicons\",\"description\":\"MonochromeIcons\\nIn code found something to vivo icons.\\nIn Android 14.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.vivo.motionrecognition\",\"description\":\"Smart motion\\nGestures and smart things.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.vivo.multinlp\",\"description\":\"LocationServices\\nChinese and Google location. Not sure if it's useless or not.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.vivo.musicwidgetmix\",\"description\":\"Origin Player\\nMusic Widget Mix\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.vivo.networkimprove\",\"description\":\"NetworkImprove\\nMay be only for China because of non-English words. Also has logs.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.vivo.networkstate\",\"description\":\"NetworkState\\nVirtual sim things. Only for China.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.vivo.nightpearl\",\"description\":\"Always on Display\\nAlways on display, it's available in settings.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.vivo.notes\",\"description\":\"Notes\\nVivo notes\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.vivo.nps\",\"description\":\"iQOO, vivo experience assessment.\\nThis app has nothing necessary in the code.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.vivo.numbermark\",\"description\":\"Number mark\\nContains a lot of Chinese code.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.vivo.omacp\",\"description\":\"Configuration SMS\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.vivo.pem\",\"description\":\"Power guardian\\nFor power-saving, probably. Also has something to google.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.vivo.phoneinstructions\",\"description\":\"Phone Instructions\\nit's used to app clone for phone instructions.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.vivo.puresearch\",\"description\":\"Search Widget\\nDesktop search bar\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.vivo.pushservice\",\"description\":\"Push Notification Engine\\nNot needed for notifications. Requires Google Play Services, and it's for VPUSH. Contains trackers and permissions.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.vivo.quickpay\",\"description\":\"Quick Pay\\nChinese pay.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.vivo.safecenter\",\"description\":\"Security Center\\nUseless security.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.vivo.sdkplugin\",\"description\":\"Needed for Vivo account and Vivo payment. Everything is in Chinese, but not sure how much will not work after removal.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.vivo.secime.service\",\"description\":\"SecIME\\nTalkback Chinese.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.vivo.setupwizard\",\"description\":\"It's only for first-boot setup.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.vivo.share\",\"description\":\"Vivo share\\nTransfer data between vivo device & PC\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.vivo.simplelauncher\",\"description\":\"Simple launcher, Simple View.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.vivo.singularity\",\"description\":\"vivo system webview\\nMultidexapplication?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.vivo.smartLife\",\"description\":\"Jovi InLife service\\nhome devices and smart interconnectivity.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.vivo.smartanswer\",\"description\":\"smart answer\\nA lot of bloated smart answer.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.vivo.smartmultiwindow\",\"description\":\"Smart Split\\nSmart multiwindow.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.vivo.smartshot\",\"description\":\"S-capture\\nUsed for screenshots?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.vivo.smartunlock\",\"description\":\"smart unlock device\\nit's used for unlock device using bluetooth devices probably.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.vivo.soundrecorder\",\"description\":\"Recorder\\nVivo sound recorder\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.vivo.space\",\"description\":\"Open Vivo official website.\\nUseless app\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.vivo.sps\",\"description\":\"SuperProcessSystem\\nUseless app statistics, logs, crash handler, security, error memory management. Also have something to com.vivo.abe but some phones don't have com.vivo.sps installed. And where is the optimization code?\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.vivo.stepcount\",\"description\":\"Step Count Application\\nit's hard to say what app actually doing\\nlooks like a useless frameworks to widgets and swipe menu\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.vivo.systemblur.server\",\"description\":\"System blur render engine\\nSystem blur render engine, logs\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.vivo.timerwidget\",\"description\":\"Alarm widget\\nWidget clock in launcher, home screen.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.vivo.unionpay\",\"description\":\"Payment v-Coin\\nit's for china probably.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.vivo.upnpserver\",\"description\":\"Phone Mirroring\\nSmart things and needed for broadcast?\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.vivo.upslide\",\"description\":\"System navigation\\nNeeded for secure and smart things.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.vivo.vhome\",\"description\":\"Smart Remote\\nit's for smart things.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.vivo.vhomeguide\",\"description\":\"VHome\\nNot needed vhome guide suggestions.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.vivo.vibrator4d\",\"description\":\"vibrator4d\\nUsed for games? Contains a lot of feedback things.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.vivo.video.floating\",\"description\":\"Face beauty for video call\\nit's a features for video call vivo.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.vivo.videoeditor\",\"description\":\"Video Trim\\nVideo editor\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.vivo.virtuallight\",\"description\":\"Ambient light effect\\nIt's music light effect (Settings: Dynamic Effects: Ambient Light Effect)\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.vivo.vivo3rdalgoservice\",\"description\":\"ImageAlgoService\\nHDR and High contrast in the camera?\\nProbably safe to remove, so it's debugging app?\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.vivo.vivokaraoke\",\"description\":\"Mobile KTV\\nVivo karaoke.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.vivo.vms\",\"description\":\"Unused frameworks. Chinese.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.vivo.voicewakeup\",\"description\":\"Voice wake-up. Has a lot of permissions (REQUEST_INSTALL_PACKAGES, READ_EXTERNAL_STORAGE, RECORD_AUDIO...). Kind of a \\\"smart assistant\\\" ? It is constantly listening waiting for a trigger word [MORE INFO NEEDED]\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.vivo.vtouch\",\"description\":\"Smart Vision\\nSpying a lot. Smart things.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.vivo.wallet\",\"description\":\"Vivo wallet\\nEverything is in Chinese.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.vivo.weather\",\"description\":\"Weather\\nVivo weather app, have Chinese trackers.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.vivo.weather.provider\",\"description\":\"Weather storage\\nVivo weather app, has Chinese trackers.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.vivo.widget.cleanspeed\",\"description\":\"Clean up acceleration components\\nClean speed widget\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.vivo.widget.gallery\",\"description\":\"Album Highlights\\nGallery widget\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.vivo.widgetweather\",\"description\":\"Weather components\\nWeather widget\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.vivo.wifiengineermode\",\"description\":\"Needed for WiFi info? it's engineermode so probably not.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.vivotouchscreen.synadeltadiff\",\"description\":\"tests touch screen\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.vlife.vivo.wallpaper\",\"description\":\"live wallpaper\\nNeeded for live wallpapers.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.vlingo.midas\",\"description\":\"Speech recognition app for the Vlingo personal assistant\\nVlingo : https://en.wikipedia.org/wiki/Vlingo\\nFYI : In January 2012 AndroidPit discovered that Vlingo sent packets of information containing the users GPS co-ordinates,\\nIMEI (unique device identifier), contact list and the title of every song stored on the device back to Nuance without.\\nSource : https://www.androidpit.com/Vlingo-Privacy-Breach\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.vmall.client\",\"description\":\"Vmall is online platform of Huawei. It's online shopping app.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.volte.config\",\"description\":\"VoLTEconfig\\nVoLTE config. Probably hidden and not needed. Looks like a Chinese.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.vos.as.vit\",\"description\":\"App for testing things.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.vos.user.vit\",\"description\":\"App for testing things.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.wapi.wapicertmanage\",\"description\":\"WAPI certificate manager\\nWAPI = WLAN Authentication and Privacy Infrastructure.\\nA Chinese national standard for Wireless LAN within a limited area such as a home. Not very useful if you don't live in China.\\nhttps://en.wikipedia.org/wiki/WLAN_Authentication_and_Privacy_Infrastructure\\nDigital certificates identify devices and apps for security. Just like your driver’s license shows that you can legally drive, a digital certificate identifies your device and confirms that it should be able to access something.\\nhttps://security.stackexchange.com/questions/102550/what-are-wifi-certificates-used-for-what-are-they\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.wapi.wapicertmanager\",\"description\":\"WAPI Certificates Manager\\nWAPI = WLAN Authentication Privacy Infrastructure (https://en.wikipedia.org/wiki/WLAN_Authentication_and_Privacy_Infrastructure\\nIt was designed to replace WEP and become the new Standard but it was't rejected by the ISO (International Organization for Standardization)\\nIt is currently only used in China\\nThis app most likely manage certificates (they are used to make sure you're not connecting to a rogue Access Point)\\nNote: If you live in China, you most likely want to keep it.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.wdstechnology.android.kryten\",\"description\":\"OTA Access Point Configuration. It's only hidden configurations to OTA, it's not needed for updates.\\nIn the case of OTA updates, \\\"com.miui.core\\\" is responsible.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.westalgo.factorycamera\",\"description\":\"Hidden camera tests, calibration.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.wifi.rxsenstest\",\"description\":\"Wifi Rx Sens Test.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.wiko.packageinstaller\",\"description\":\"Provides first time app install for Wiko mobile\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.wiko.services\",\"label\":\"Wiko Support\",\"description\":\"Support app for Wiko mobile\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.wingtech.catchlog\",\"description\":\"Cit App to show Battery info, Secret Code:6485\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.wingtech.stability\",\"description\":\"Stability Test. Tests hardware things.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.wingtech.standard\",\"description\":\"WTStandardTest\\nWingtech is a chinese Original Design Manufacturer (ODM) involved in the manufacturing of Xiaomi devices.\\nThere is very high chances this app is only a hardware conformance test app used during production process\\nyou don't need as an end-user.\\nCan someone share the apk just to be 100% sure?\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.ws.dm\",\"description\":\"it's the same like com.wssyncmldm\\nSoftware update\\nFetch System OTA updates\\nWorks along with com.sec.android.soagent\\nRequired on Samsung Smartphones for OTA.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.wsomacp\",\"description\":\"omacp = OMA Client Provisioning. It is a protocol specified by the Open Mobile Alliance (OMA).\\nConfiguration messages parser. Used for provisioning APN settings to Samsung devices via SMS \\nIn my case, it was automatic and I never needed configuration messages.\\nMaybe it's useful if carriers change their APN. But you still can change the config manually, it's not difficult.\\nKeep in mind these special types of SMS can be abused (though you would need to select to apply the APN in the popup).\",\"web\":[\"https://research.checkpoint.com/2019/advanced-sms-phishing-attacks-against-modern-android-based-smartphones/\",\"https://www.zdnet.com/article/samsung-huawei-lg-and-sony-phones-vulnerable-to-rogue-provisioning-messages/\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.wssnps\",\"description\":\"Samsung Backup and restore Manager (on Samsung Galaxy S7)\\nWas replaced by \\\"com.sec.android.easyMover\\\" (Samsung Smart Switch Mover)\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.wssyncmldm\",\"description\":\"Software update\\nFetch System OTA updates\\nWorks along with com.sec.android.soagent\\nRequired on Samsung Smartphones for OTA.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.wt.secret_code_manager\",\"description\":\"Hidden app which associates an action (display logging info) to a secret code.\\nThis secret codes have to be dialed from the Xiaomi dialer.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.wt.version_query\",\"description\":\"theres something about updates but this apk size is too small\\nand includes some secret codes, founded in xiaomi.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.wtk.factory\",\"label\":\"FactoryMode\",\"description\":\"Hardware testing things.\",\"web\":[\"https://nvd.nist.gov/vuln/detail/CVE-2018-14999\"],\"removal\":\"delete\",\"warning\":\"On Leagoo P1 devices, triggering a certain broadcast receiver may factory reset the device.\",\"type\":\"oem\"},{\"id\":\"com.wtk.stresstest\",\"label\":\"StressTest\",\"description\":\"Testing Hardware things.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.xiaomi.NetworkBoost\",\"description\":\"Network Boost\\nNetwork acceleration not available in settings wifi?\\nPeople said it's placebo and it doesn't speed up the network.\\nIt has a lot of Chinese code and has permission to MIUI analytics.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.xiaomi.ab\",\"label\":\"Mi Store System Components\",\"description\":\"Formerly, mab.\\nSomething about login, paying in Mi Store China.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.xiaomi.account\",\"description\":\"Mi Account\\nHas a LOT of permissions + Facebook trackers. Collects many information, including your phone number, your unique International mobile subscriber identity (IMSI) and your clipboard).\\nYou should remove this if you don't have or don't want a Mi account.\\nWARNING: Make sure to log out of your Mi Account and unbind your phone from it. If you don't you could be locked out from your phone after removing this package.\\nRemove Mi Account: https://xiaomiui.net/how-to-remove-mi-account-7606/\\n\\nPithus analysis: https://beta.pithus.org/report/3f5abc9d7215dd0be5c3ac137b0cd528217640b5778e9f849a9beb0a34eda8dc\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.xiaomi.aiasst.service\",\"label\":\"AI Call Assistant\",\"description\":\"Useless Call settings.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.xiaomi.aiasst.vision\",\"label\":\"AiasstVision\",\"description\":\"Not needed if you removed AI Call Assistant.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.xiaomi.aicr\",\"label\":\"Mi AI Engine\",\"description\":\"Another app to Mi AI from MIUI China.\",\"web\":[\"https://hyperosupdates.com/apps/com.xiaomi.aicr/\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.xiaomi.aireco\",\"description\":\"XiaoaiRecommendation\\nThis app does nothing, totally random frameworks unused.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.xiaomi.android.tvsetup.partnercustomizer\",\"description\":\"SetupCustomizer\\nOn first boot setup installs bloatware.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.xiaomi.aon\",\"description\":\"'I always on' found in code and a lot statistics. Also Miui analytics permissions.\\nRegion of the tracking device, found things Mi Face, spy on your face and everything you do on your phone?\\nAONEventTracking uses and sends to 'com.miui.analytics'.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.xiaomi.barrage\",\"description\":\"Bullet screen notifications\\nPop-up notifications (feature inside the game service)\\nHave a lot of Chinese things in this code but it's for the game service, NOT gamespace.\\nSo it's for China only.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.xiaomi.bluetooth\",\"description\":\"MIUI Bluetooth Extension. Doesn't seem to affect bluetooth functionality. Tested on Poco M4 Pro 5G HyperOS 1.0.1.0. Note: If you deleted (com.xiaomi.xmsf) this package will likely send \\\"Bluetooth extension stopped working\\\" errors, uninstalling it removes them.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.xiaomi.bluetooth.overlay\",\"description\":\"It has only unused png files, webp.\\nImages in it: wireless headphones from all angles.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.xiaomi.bsp.gps.nps\",\"description\":\"GPS location\\nI think bsp = board system package (https://en.wikipedia.org/wiki/Board_support_package)\\nNot sure about nps (It might be Non-Permanent GPS station)\\nIt's a small package which seems to display a notification when an app is using GPS.\\nMore precisely, there is a receiver (GnssEventReceiver) which listen to com.xiaomi.bsp.gps.nps.GetEvent \\nThis event most likely happen when an app use the GPS and refers to the state of the communication with the GNSS:\\nFIX, LOSE, RECOVER, START, STOP\\nIt's safe to remove if you really want to.\\n\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.xiaomi.bttester\",\"description\":\"BTCIT\\nBluetooth Test Service\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.xiaomi.calendar\",\"description\":\"Mi Calendar. Google trackers inside and needs 48 permissions! Obviously talks to Xiaomi servers. The com.mi.health.provider.permission.read_menstruation permissions is really creepy... There are better alternatives.\\nPithus analysis: https://beta.pithus.org/report/6c68ddd1f9e2d1f9e1df2eab572c07f1e34c4a6490c0ba98554a7356ca2a351d\\n\\nNote: Since MIUI 12, you can no longer uninstall this app. Disabling it still works fine.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.xiaomi.cameratools\",\"description\":\"CameraTools\\nCamera calibration. Deleting it does not affect the camera.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.xiaomi.channel\",\"description\":\"Mi Talk \\nMi instant messaging app that lets you do practically the same thing as Whatsapp. \\nNOTE: You should use Signal or Wire instead Whatsapp/Mi Talk for more privacy.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.xiaomi.digitalkey\",\"label\":\"digitalkey\",\"description\":\"Smart door locks, can also be used as a car key. Only for China.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.xiaomi.discover\",\"description\":\"System Apps Updater\\nWARNING: Disable System app updates (but not firmware updates)\\n\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.xiaomi.entitlement.o2\",\"description\":\"Unknown, seems to be United Kingdom, Germany specific to the O2 carrier.\\nhttps://en.wikipedia.org/wiki/O2_(brand)\\nIf you don't use O2 carrier, it's safe to remove.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.xiaomi.finddevice\",\"label\":\"Mi Find Device\",\"description\":\"Find My Device feature (in the Settings)\\nEnables you to locate your lost phone and erase your data remotely.\\nYour phone needs to be connected to internet (Wifi/mobile data) for this feature to work.\",\"web\":[\"https://github.com/0x192/universal-android-debloater/issues/641\"],\"removal\":\"unsafe\",\"warning\":\"Depending on MIUI version, removing the app may cause bootloops.\",\"type\":\"oem\"},{\"id\":\"com.xiaomi.gamecenter\",\"description\":\"Games\\nAnother app with a lot tracking and not needed for gamespace.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.xiaomi.gamecenter.sdk.service\",\"label\":\"Game Service\",\"description\":\"It's not needed for gamespace, disabled by default. It has activities such as AliPay, login to account. I'm not sure what it's needed for.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.xiaomi.glgm\",\"description\":\"Xiaomi Games\\nNot sure if this app still exists.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.xiaomi.joyose\",\"label\":\"Joyose\",\"description\":\"GPU Tuner\\nOptimizes your game for gaming. Some people have noticed that it locks the fps at 60 after selecting 90.\",\"web\":[\"https://youtu.be/gavEuH3Ck5o?t=550\"],\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.xiaomi.jr\",\"description\":\"Help you getting loans when shopping.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.xiaomi.lens\",\"description\":\"Related to camera app ?\\nSafe to remove (according to a lot of users)\\nI'd like to have more info about it. Can a Xiaomi user help ? \\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.xiaomi.location.fused\",\"description\":\"It has china location, ads & analytics.\\nYou dont need it for location.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.xiaomi.macro\",\"description\":\"MiMacro is an automation task from Xiaomi like touch on MIUI Game Turbo.\\nHas INTERNET and READ_PHONE_STATE permission allowing access to the phone number, serial number, whether a call is active, the number that a call is connected to...\\nWhat is sure (from the code) is that the app collects the IMEI.\\n\\nPithus analysis: https://beta.pithus.org/report/2b056ed84fe500552a58184035b962ba68af29457c24930c0aa8c9eba4af7bcf\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.xiaomi.market\",\"label\":\"GetApps\",\"description\":\"China Mi App Store.\\nI used it only to install google play.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.xiaomi.mbnloader\",\"description\":\"Modem Config\\nHidden app for Choosing Country vowifi?\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.xiaomi.metoknlp\",\"description\":\"Network location provider\\nUseless, only for China, have analytics things.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.xiaomi.mi_connect_service\",\"description\":\"MiConnectService\\nHandles connection to IoT stuff\\nSeems to be linked to Mi Home (com.xiaomi.smarthome)\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.xiaomi.miaudiovisual\",\"description\":\"MiAudioVisual\\nSafe to remove if you not use audio visuals when screen is off.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.xiaomi.mibrain.speech\",\"description\":\"Mi AI Speech Engine\\nAnother app to Mi AI Chinese app.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.xiaomi.micloud.sdk\",\"label\":\"com.xiaomi.micloud.sdk\",\"description\":\"Mi Cloud sdk \\nsdk = Software development kit\\nSeems to be a dependency for \\\"com.miui.gallery\\\".\",\"removal\":\"unsafe\",\"warning\":\"MIUI auto reboots android after removing this package\",\"type\":\"oem\"},{\"id\":\"com.xiaomi.midrop\",\"description\":\"Share Me (Mi Drop) (https://play.google.com/store/apps/details?id=com.xiaomi.midrop)\\nP2P file transfer tool.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.xiaomi.midrop.overlay\",\"description\":\"Mi Drop overlay\\nOverlays are usually themes.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.xiaomi.migameservice\",\"label\":\"Mi Game Service\",\"description\":\"Chinese app made to test game service things.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.xiaomi.mipicks\",\"description\":\"Mi Picks (becomed Mi Apps Store and now Get Apps -- Xiaomi app store)\\nI believe this package is discontinued.\\nhttps://play.google.com/store/apps/details?id=com.mi.global.shop\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.xiaomi.miplay_client\",\"description\":\"MiPlay Client\\nProvides support for Miracast (https://en.wikipedia.org/wiki/Miracast).\\nIt provides the Wireless Display feature (Settings - Connection & sharing - Cast).\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.xiaomi.mircs\",\"description\":\"Mi RCS\\nHidden unused Xiaomi free web messaging.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.xiaomi.mirecycle\",\"description\":\"Mi Recycle \\nXiaomi has extended its partnership with Cashify to launch the 'Mi Recycle' feature through its MIUI Security app. \\nIt will let Xiaomi phone users check the health of their smartphone and get their resale value directly from Cashify, \\nthe online re-commerce company based out of New Delhi.\\nSource : https://gadgets.ndtv.com/mobiles/news/xiaomi-mi-recycle-cashify-miui-security-app-2018024\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.xiaomi.mirror\",\"label\":\"MIUI+ Beta\",\"description\":\"Transfer files, sync copy text to PC without USB.\",\"web\":[\"https://plus.miui.com\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.xiaomi.mis\",\"description\":\"Xiaomi Connected Car Service for China.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.xiaomi.misettings\",\"description\":\"Xiaomi Settings app\\n\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.xiaomi.mitv.res\",\"description\":\"MiUtilRes\\nLooks like mitv api.\\nProbably Unsafe to remove.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.xiaomi.mtb\",\"description\":\"Rueban(MTB)V2.4\\nHidden debugging baseband tools, not available for users.\\nhttps://i.postimg.cc/GpSxmNyj/Bez-n-zvu.png\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.xiaomi.o2o\",\"description\":\"o2o = online-to-offline\\n==> Describes systems enticing consumers within a digital environment to make purchases of goods or services from physical businesses.\\nhttps://en.wikipedia.org/wiki/Online_to_offline\\nNOTE: This package can make phone calls without user intervention.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.xiaomi.oobhelper\",\"description\":\"OOBHelper\\nUseless frameworks and logs.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.xiaomi.otrpbroker\",\"description\":\"TAMservice\\nOTRP Protocol Negotiation Program (Internet of Things)\\nOnly useful in China.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.xiaomi.oversea.ecom\",\"description\":\"Xiaomi ShopPlus.\\nGiven its name I think this package is useless.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.xiaomi.pass\",\"description\":\"Mi Pass is an App allows Xiaomi NFC phones to replace cards and keys in real life usage. \\nSupport NFC payment, bus card, key card, door and car lock features all together.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.xiaomi.payment\",\"description\":\"Old package name for Mi Credit (https://play.google.com/store/apps/details?id=com.micredit.in.gp)\\nMi Credit is a personal loan platform from Xiaomi.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.xiaomi.powerchecker\",\"label\":\"Power Detector\",\"description\":\"Located at Security> Battery> Activity Control.\\nDetects abnormal power usage by apps (not all. Some Xiaomi apps are whitelisted).\\nNeeded for 'com.miui.powerkeeper' to work.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.xiaomi.providers.appindex\",\"description\":\"Provider for app index?\\nI believe it is a provider for the settings but can't confirm (I don't have a Xiaomi device).\\nA lot of people debloat this but I'd like to know more about this one.\\nContent providers encapsulate data, providing centralized management of data shared between apps.\\nhttps://developer.android.com/guide/topics/providers/content-providers.html\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.xiaomi.scanner\",\"description\":\"Mi Scanner\\nQR code scanner with a lot of questionable permissions : `ACCESS_FINE_LOCATION`, `CALL_PHONE`, `READ_CONTACTS`, `REQUEST_INSTALL_PACKAGES`, `QUERY_ALL_PACKAGES`, `FOREGROUND_SERVICE`, `INTERNET`\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.xiaomi.security.onetrack\",\"description\":\"SecurityOnetrackService\\nOnly uses MIUI analytics.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.xiaomi.shop\",\"description\":\"Xiaomi app store (I thinks it's discontinued)\\nNow com.mi.global.shop (https://play.google.com/store/apps/details?id=com.mi.global.shop)\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.xiaomi.simactivate.service\",\"description\":\"Xiaomi SIM Activation Service\\nSIM authentication process to access exclusive features in certain MIUI applications.\\nFor the activation to work you need to send a international SMS to China.\\nYour carrier may block this by default and/or you'll probably need to pay extra for this.\\nAfter SIM activation, you can send text messages (Mi Messages) to other Mi users using internet connection (like i-messages).\\nYou will be able to synchronize your messages into Mi Cloud and this also enables the Mi Find Device feature which allows you to track your phone’s location from your online Mi account.\\n\\nNote: To enable/disable Mi Messages go to Settings -> System Apps -> Messaging and reboot\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.xiaomi.smarthome\",\"description\":\"Mi Home (https://play.google.com/store/apps/details?id=com.xiaomi.smarthome)\\nIoT. Lets you control with Xiaomi Smart Home Suite devices.\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.xiaomi.touchservice\",\"description\":\"No activities, uses miui analytics looks like a tracking touch.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.xiaomi.trustservice\",\"description\":\"MiTrustService\\nIFAASecCam, security things or 'Remote Control trust'.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.xiaomi.ugd\",\"description\":\"GPU Driver Updater\\nIt's weird when this app cameback on HyperOS(from MIUI 12).\\nUpdates GPU driver.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.xiaomi.upnp\",\"description\":\"UpnpService\\nUPnP = Universal Plug and Play\\nIt’s a protocol that lets UPnP-enabled devices on your network automatically discover and communicate with each other\\nFor example it works with the Xiaomi Network Speaker (and probably a lot more Xiaomi IoT stuff)\\nUPnP has a lot of security issues and you proably should disable it on your router.\\nhttps://nakedsecurity.sophos.com/2020/06/10/billions-of-devices-affected-by-upnp-vulnerability/\\nThis package is the Xiaomi implementation on Android (no AOSP support)\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.xiaomi.vipaccount\",\"description\":\"Xiaomi VIP account\\nhttps://www.mi.com/in/service/privilegefaq/\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.xiaomi.xaee\",\"description\":\"XiaoaiEdgeEngine\\nThis app has something to Mi AI.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.xiaomi.xmsf\",\"description\":\"Xiaomi Service Framework\\nContains a set of API's for Xiaomi apps. Expect widespread breakage of Xiaomi apps/functionality if disabled.\\nDisabling will mess with Alarm clock functionality(according to issue#136) and break Mi Cloud and Mi account (and all features that depend on them).\\nI don't know about now, but in 2016 this app constantly tried to establish tcp connections in the background.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.xiaomi.xmsfkeeper\",\"description\":\"Xiaomi Service Framework Keeper\\nLogger service for 'com.xiaomi.xmsf'\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.xiaomi.youpin\",\"description\":\"Xiaomi Yipin\\nMi Shop China.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.ximalaya.ting.android\",\"description\":\"Chinese Ximalaya.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.xingin.xhs\",\"description\":\"Chinese Little Red Book.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.xm.webcontent\",\"description\":\"WebContent\\nNeeded for messages like 'App installing'. Also WebView.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.xui.xhide\",\"description\":\"XHide\\nProvides the only way to hide files and lock apps when using Transsion launchers (which the Transsion devices require for certain functionality like multiapps not working with other launchers). These are the only apps that hide files and lock apps with them.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.xunmeng.pinduoduo\",\"description\":\"Chinese JD.com.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.xy.smartmmsplugin.remote\",\"description\":\"SmartMmsPlugin\\nConnects to Chinese maps.\\nLoads Flight, Train, Movie information.\\nIt's only for China.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.yandex.browser\",\"description\":\"Yandex' browser\\nMay be installed with Samsung firmware update to comply with http://publication.pravo.gov.ru/Document/View/0001202011230051 if you're Russian. Can be installed manually from Google Play.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.yha.engineersecret\",\"description\":\"Reads/writes to External Storage. Gets the IMEI, uses gps/wifi lots of activities (hardware tests?):\\nIMeiAndPcbCheck, DeviceListActivity, CheckSoftwareInfo, GpsActivity, BluetoothTest, BluetoothSearch, LteSarTest, NetworkSearch, DecryptionActivity\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.yha.factory\",\"description\":\"related to com.yha.runtime\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.yha.runtime\",\"description\":\"RunTimeTest\\nReads/writes to External Storage. Uses wifi, camera, sensors, mic, etc. Lots of activities (hardware tests?):\\nFlashTest, VibratorTest, WIFITest, Reboot, LCDTest, AudioLoop, VideoTest, CameraTest, Tester3dTeapot, FullMemTest, ScreenSaver.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.youku.phone\",\"description\":\"Chinese Youku video.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.youview.poa\",\"description\":\"Youview live tv app\\nhttps://play.google.com/store/apps/details?id=com.youview.poa&hl=en_US/\\nSometimes a remote on your button opens this but that can be changed in the settings. Safe to remove.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.yozo.vivo.office\",\"description\":\"Vivo document reader\\nA lot of permissions for a simple document reader. It can access to internet, can list all the apps you installed, can get your phone number, current cellular network information, the status of any ongoing calls and more!\\n\\nPithus analysis: https://beta.pithus.org/report/8902163722f5df1ae6228b80124cfa94c2b8a0210a8f6bbb3441e05d69a76d0b\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.yulore.framework\",\"description\":\"Chinese payment things.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.zhihu.android\",\"description\":\"Chinese know.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.zte.assistant\",\"description\":\"ZTE Voice Assistant\\n\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.zte.beautify\",\"description\":\"ZTE Theme\\nNeeded for themes\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.zte.burntest.camera\",\"description\":\"Possibly a hidden stress testing app for camera.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.zte.contacts.sub\",\"description\":\"Possibly related to contact sync.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.zte.easymode\",\"description\":\"Easy mode\\nEasy Mode settings\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.zte.emode\",\"description\":\"Testing Hardware Components\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.zte.emodeservice\",\"description\":\"Logs to emode Testing Hardware Components\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.zte.faceverify\",\"description\":\"Needed for face unlock screen\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.zte.fingerprints\",\"description\":\"Fingerprint service\\nFingerprint settings.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.zte.heartyservice.strategy\",\"description\":\"Process killer, unloads programs from memory.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.zte.mifavor.launcher\",\"description\":\"Stock ZTE Launcher\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.zte.mifavor.launcher.adapter\",\"description\":\"Needed for Stock ZTE Launcher\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.zte.mifavor.launcher.resource\",\"description\":\"Needed for Stock ZTE Launcher\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.zte.mifavor.theme.resource\",\"description\":\"Needed for themes?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.zte.onekeycp\",\"description\":\"Phone Switch\\nPC Connect things, not needed.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.zte.powersavemode\",\"description\":\"Has battery settings.\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.zte.privacypolicy\",\"description\":\"ZTE privacy policy app.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.zte.privacyzone\",\"description\":\"App Lock\\nApp Lock, Password Manager\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.zte.setupwizard\",\"description\":\"Setup Wizard\\nNeeded for first-boot setup\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.zte.videoplayer\",\"label\":\"Video Player\",\"description\":\"ZTE Video Player with INTERNET and ACCESS_NETWORK_STATE permissions.\",\"web\":[\"https://beta.pithus.org/report/caf2da956d33c5550e42d4250b0fa31dc605f39545c2eff36438fd88a0fc7c28\"],\"removal\":\"replace\",\"suggestions\":\"video_players\",\"type\":\"oem\"},{\"id\":\"com.zte.weather\",\"label\":\"Weather\",\"description\":\"ZTE Weather app.\",\"web\":[\"https://play.google.com/store/apps/details?id=com.zte.weather\"],\"removal\":\"replace\",\"suggestions\":\"weather_apps\",\"type\":\"oem\"},{\"id\":\"com.zte.zbackup.platservice\",\"description\":\"ZteBackupService\\nZteBackupService with a lot of permissions.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.zte.zdm.omacp\",\"description\":\"For configuring SMS settings.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.zte.zdmdaemon\",\"description\":\"Useless logs, data collection.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.zte.zdmdaemon.install\",\"description\":\"Useless logs, data collection.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.ztefingerprint.service\",\"description\":\"Probably needed for fingerprint.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.zui.android.overlay.common\",\"description\":\"Useless config to Chinese location.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.zui.android.overlay.product\",\"description\":\"Config to refresh rate 120? Better don't risk.\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"com.zui.antitheft\",\"description\":\"Find the phone\\nFind the phone. (Log out from account before remove)\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.zui.browser\",\"description\":\"Lenovo Browser\\nStock Lenovo Browser with Chinese trackers.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.zui.bugtogo\",\"description\":\"Hidden collecting user data.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.zui.callsettings\",\"description\":\"Additional Call Settings also WiFi calling.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.zui.camera\",\"description\":\"Lenovo ZUI Camera\\nLenovo Stock Camera App\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.zui.camera.assistant\",\"description\":\"It's for camera app or WiFi calling?\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.zui.camera.avatar\",\"description\":\"MakeAvatar\\nMakeAvatar? It's something for face recognition.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.zui.camera.plugin.dolphin\",\"description\":\"Needed for camera settings?\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.zui.contacts\",\"description\":\"Lenovo Contacts\\nStock Lenovo Contacts app\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.zui.continuity\",\"description\":\"Lenovo One\\nConnects phone to PC and more. Not needed.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.zui.cores\",\"description\":\"Removing will affect a lot of other ZUI functions like the game assistant, etc. so it's a bad idea.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.zui.davdroid\",\"description\":\"Login to iCloud and sync contacts, calendars.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.zui.deskclock\",\"description\":\"Lenovo ZUI Clock\\nStock Lenovo clock app.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.zui.deskclock.overlay.lime\",\"description\":\"Overlay to theme icon Clock app.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.zui.deskclock.overlay.mostbeautiful\",\"description\":\"Overlay to theme icon Clock app.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.zui.deskclock.overlay.phantom\",\"description\":\"Overlay to theme icon Clock app.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.zui.deskclock.overlay.redstorm\",\"description\":\"Overlay to theme icon Clock app.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.zui.deskclock.overlay.steellegion\",\"description\":\"Overlay to theme icon Clock app.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.zui.deskclock.overlay.thinarmor\",\"description\":\"Overlay to theme icon Clock app.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.zui.deviceidservice\",\"description\":\"Analytics and logs.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.zui.filemanager\",\"description\":\"File manager app\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.zui.freeform.sidebar\",\"description\":\"Unused frameworks? Probably split screen for apps will not work, not tested.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.zui.gallery\",\"description\":\"Gallery\\nStock Gallery app for lenovo phones.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.zui.game.service\",\"description\":\"A lot of login things and Chinese.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.zui.homesettings\",\"description\":\"Badges? It's Chinese, so not needed.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.zui.launcher\",\"description\":\"Lenovo Launcher ZUI HOME.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.zui.legalinfo\",\"description\":\"I found only hidden privacy policy activity.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.zui.mms\",\"description\":\"Stock Messaging App\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.zui.mms.overlay.mostbeautiful\",\"description\":\"Overlay to theme icon Messages app.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.zui.net.data.monitor\",\"description\":\"Needed for Network control\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.zui.networkaclr\",\"description\":\"Network manager?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.zui.oneime\",\"description\":\"Input method for Lenovo One\\nIt's input method for Lenovo One.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.zui.ota\",\"description\":\"Lenovo system update\\nProvides system updates.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.zui.radioinfo\",\"description\":\"Hidden testing hardware things.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.zui.safecenter\",\"description\":\"Security Center\\nUseless security app? You will lose optimization probably.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.zui.safecenter.overlay.lime\",\"description\":\"Overlay to theme icon Security app.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.zui.safecenter.overlay.mostbeautiful\",\"description\":\"Overlay to theme icon Security app.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.zui.safecenter.overlay.phantom\",\"description\":\"Overlay to theme icon Security app.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.zui.safecenter.overlay.redstorm\",\"description\":\"Overlay to theme icon Security app.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.zui.safecenter.overlay.steellegion\",\"description\":\"Overlay to theme icon Security app.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.zui.safecenter.overlay.thinarmor\",\"description\":\"Overlay to theme icon Security app.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.zui.sdac\",\"description\":\"Not needed for notifications and it's probably testing notification.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.zui.setupwizard\",\"description\":\"Setup Wizard\\nNeeded for first-boot setup.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.zui.simcontacts\",\"description\":\"It should be named com.qualcomm.simcontacts.\\nIt's hidden and not available for users.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.zui.tassistent\",\"description\":\"Assistant Tracking, Logs.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.zui.theme.overlay.lime\",\"description\":\"Wallpaper to Theme App.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.zui.theme.overlay.mostbeautiful\",\"description\":\"Wallpaper to Theme App.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.zui.theme.overlay.phantom\",\"description\":\"Wallpaper to Theme App.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.zui.theme.overlay.redstorm\",\"description\":\"Wallpaper to Theme App.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.zui.theme.overlay.steellegion\",\"description\":\"Wallpaper to Theme App.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.zui.theme.overlay.thinarmor\",\"description\":\"Wallpaper to Theme App.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.zui.theme.settings\",\"description\":\"Lenovo theme settings\\nNeeded for theme settings.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"com.zui.thirdparty.sdk\",\"description\":\"Third party useless frameworks.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.zui.tuface\",\"description\":\"It's for faceid and probably needed for face unlock lock screen.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.zui.udevice\",\"description\":\"Useless preview activity to earphones.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.zui.userexperience\",\"description\":\"It's for spying: app usage, device usage.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.zui.wallet\",\"description\":\"Chinese payment\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.zui.wallpapercropper\",\"description\":\"Crop wallpaper\\nWallpaper cropper.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.zui.wallpapersetting\",\"description\":\"Needed for wallpaper settings\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.zui.weather\",\"description\":\"Weather\\nStock weather app.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"com.zui.wifip2p\",\"description\":\"Lenovo One file transfer\\nAnother app for Lenovo One things.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"com.zui.xlog\",\"description\":\"Hidden logs, package usage collector.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"ctrip.android.view\",\"description\":\"Chinese Ctrip.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"eu.xiaomi.ext\",\"description\":\"Xiaomi.eu Extension\\nCalendar app things. Only for China.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"eu.xiaomi.module.inject\",\"description\":\"Inject fields\\nFields name of device info like which os version or security date.\\nNot sure if it's needed.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"fr.bouyguestelecom.agent.custo\",\"description\":\"This app wanna include ads to your gallery only.\\nFounded only ads and crashlytics components.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"huawei.android.widget\",\"description\":\"App that actually doesnt do anything? Remove it doesnt affect on your widgets.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"jp.co.omronsoft.mushroom.CommonPhrase\",\"description\":\"Japanese Phrases app\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"jp.co.radius.neplayer_asus\",\"description\":\"NePLAYER\\nJapanese NePLAYER Lite for ASUS\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"ma.android.com.mafactory\",\"label\":\"Factory Test\",\"description\":\"It's for hardware components testing.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"me.phh.treble.app\",\"description\":\"Used for settings GSI rom that based by Phh Treble. This should not be remove.\",\"removal\":\"unsafe\",\"type\":\"oem\"},{\"id\":\"mitv.service\",\"description\":\"TvService\\nHas shutdown delay.\\nSafe to remove.\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"miui.systemui.plugin\",\"label\":\"System UI Plug-in\",\"description\":\"When using HyperOS, removing this package breaks the iOS-style quick settings and Android will use the AOSP-version of the volume bar & reboot screen (AKA the option to power off/reboot your device). If your device is using MIUI, only the volume bar will change.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"miuix.stub\",\"description\":\"It has something to unknown miuix FrequentPhrase, Chinese things found.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"net.oneplus.commonlogtool\",\"description\":\"OnePlus Common Log Tool\\n9 permissions and given what we know about OnePlus logging apps, it's a good idea to disable this.\\nSee com.oneplus.opbugreportlite, com.oem.oemlogkit and net.oneplus.odm\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"net.oneplus.forums\",\"description\":\"OnePlus Community (https://play.google.com/store/apps/details?id=net.oneplus.forums)\\nLiterally just their forum... in an app.\\nJust use a Browser if you wanna access the forums.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"net.oneplus.launcher\",\"description\":\"Oneplus Launcher\\nRuns in the background as part of the system.\\nAside from obviously handling the default launcher itself, it also handles the Recents UI on Android 9, the home&recents gestures in Android 11, some submenus in the Settings app and possibly more that I'm unaware of.\\nProbably not a good idea to disable.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"net.oneplus.launcher.black.overlay\",\"description\":\"Theme overlay for the Oneplus Launcher?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"net.oneplus.launcher.white.overlay\",\"description\":\"Theme overlay for the Oneplus Launcher?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"net.oneplus.odm\",\"description\":\"\\\"OnePlus System Service\\\"\\nShady telemetry app.\\nSends loads of data to OnePlus' servers, including IMEI, phone number, MAC addresses, mobile network names and IMSI prefixes, Wi-Fi connection info, the phone's serial number and every time an app was opened.\\nSource: https://www.chrisdcmoore.co.uk/post/oneplus-analytics/\\nPress: https://www.androidpolice.com/2017/10/10/never-settle-oneplus-found-collecting-personally-identifiable-analytics-data-phone-owners/\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"net.oneplus.odm.provider\",\"description\":\"Insight Provider\\nProvider for net.oneplus.odm? (shady telemetry app)\\nContent providers encapsulate data, providing centralized management of data shared between apps.\\nhttps://developer.android.com/guide/topics/providers/content-providers.html\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"net.oneplus.provider.appcategoryprovider\",\"description\":\"AppCategoryProvider\\nRuns in the background.\\nI think this categorizes apps for use with system functionality, for example: automatically adding games to Game Mode.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"net.oneplus.push\",\"description\":\"Push\\nOnePlus push notifications.\\nOnly used by OnePlus' pre-installed apps. Pushes \\\"surveys and other junk\\\" according to a user.\\nhttps://forums.oneplus.com/threads/psa-non-root-root-stop-oneplus-push-notifications.580058/\\nOnePlus can remotely send push notifications:\\nhttps://www.androidpolice.com/2019/07/01/oneplus-accidentally-pushed-a-cryptic-notification-to-all-7-pro-users/\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"net.oneplus.wallpaperresources\",\"description\":\"Resources for some live wall papers? Not sure.\\nOnly contains a \\\"WallpaperResourceProvider\\\", no services, activities or receivers.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"net.oneplus.weather\",\"label\":\"Weather\",\"description\":\"Occasionally runs in the background; I think it runs every now and then to change the app icon to current weather conditions.\",\"web\":[\"https://play.google.com/store/apps/details?id=net.oneplus.weather\"],\"removal\":\"replace\",\"suggestions\":\"weather_apps\",\"type\":\"oem\"},{\"id\":\"net.oneplus.weather.basiccolorblack.overlay\",\"description\":\"Theme overlay for Oneplus Weather app?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"net.oneplus.weather.basiccolorwhite.overlay\",\"description\":\"Theme overlay for Oneplus Weather app?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"net.oneplus.widget\",\"label\":\"OnePlus Widget\",\"description\":\"Lets you use OnePlus widgets on the home screen.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"nubia.camera.dualcamtest\",\"description\":\"Dual Camera Test\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"ohos.media.medialibrary\",\"description\":\"MediaLibrary\\nhas hwddmp components `com.huawei.hwddmp` debugging errors, remote device manager that depends on Huawei account\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"om.xiaomi.gnss.polaris\",\"description\":\"Polaris\\nBeidou satellite navigation system. Only for China.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"om.zui.resolver\",\"description\":\"Lenovo Share\\nLenovo Share for Chinese\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"oplus.frameworkres.overlay.display.product\",\"description\":\"Display cutout.\\nA display cutout is an area on some devices that extends into the display surface. It allows for an edge-to-edge experience while providing space for important sensors on the front of the device.\\nhttps://developer.android.com/develop/ui/views/layout/display-cutout\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"org.codeaurora.btmultisim\",\"description\":\"it's app without code.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"org.codeaurora.qti.nrNetworkSettingApp\",\"description\":\"Needed for 5G?\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"org.dtx.aidl.manager\",\"description\":\"DtxService\\nAnt Dtx Service, unknown app, but safe to remove, probably useful in China.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"org.ifaa.aidl.manager\",\"label\":\"IfaaManagerService\",\"description\":\"IFAA = (China’s) Internet Finance Authentication Alliance\\nProvides biometric authentication for Alipay. Probably safe to disable if you don't use it.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"org.mipay.android.manager\",\"description\":\"MipayService\\nXiaomi Payment related services, not used!\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"product.lge.data.server.LgDataServiceMain\",\"description\":\"Needed for iwlan? Very unknown app.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"ru.yandex.disk\",\"description\":\"Yandex' file cloud storage\\nMay be installed with Samsung firmware update to comply with http://publication.pravo.gov.ru/Document/View/0001202011230051 if you're Russian. Can be installed manually from Google Play.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"ru.yandex.searchplugin\",\"description\":\"Yandex' search engine plugin\\nMay be installed with Samsung firmware update to comply with http://publication.pravo.gov.ru/Document/View/0001202011230051 if you're Russian. Can be installed manually from Google Play.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"ru.yandex.yandexmaps\",\"description\":\"Yandex' Maps\\nMay be installed with Samsung firmware update to comply with http://publication.pravo.gov.ru/Document/View/0001202011230051 if you're Russian. Can be installed manually from Google Play.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"screnmirroring.com\",\"description\":\"Sony's screen mirroring app. Can be removed as chromecasting still works without it\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"se.dirac.acs\",\"label\":\"Dirac Control Service\",\"description\":\"Sound-system backend?\\nRuns in the background as part of the system. Runs even if disabled.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"sg.gov.mnd.OneService\",\"description\":\"map app with a lot tracking\\nhttps://play.google.com/store/apps/details?id=sg.gov.mnd.OneService\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"tech.palm.id\",\"description\":\"TECNO ID\\nit's for account? A lot bloated.\\nInstead Uninstall better Disable app because Uninstalling cause Settings app crash\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"tv.alphonso.alphonso_eula\",\"description\":\"Alphonso Recommendations\\nEnhanced viewing, personalized experience of watching TV.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"tv.danmaku.bili\",\"description\":\"Chinese app 'bilibili'.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"tv.peel.samsung.app\",\"label\":\"Peel Smart Remote (WatchON)\",\"description\":\"It's an application that turns your smart phone or tablet into a TV remote.\\nThe app uses the IR Blaster of your device, so devices not equipped with that feature will not be able to use all of Peel Smart Remote's functions.\",\"web\":[\"https://www.samsung.com/za/support/mobile-devices/what-is-the-peel-smart-remote-application/\"],\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"udc.lenovo.com.udclient\",\"description\":\"Lenovo Universal Device Client\\nAnother Mobile Device Management (MDM) allows company’s IT department to reach inside your phone in the background, allowing them to ensure\\nyour device is secure, know where it is, and remotely erase your data if the phone is stolen.\\nIt's a way to ensure employees stay productive and do not breach corporate policies\\nYou should NEVER have a MDM tool on your personal phone.\",\"removal\":\"delete\",\"type\":\"oem\"},{\"id\":\"vendor.mediatek.iwlanservice\",\"description\":\"iWlan service, not sure if needed.\",\"removal\":\"caution\",\"type\":\"oem\"},{\"id\":\"zte.com.cn.alarmclock\",\"description\":\"Clock\\nStock ZTE Clock App\",\"removal\":\"replace\",\"type\":\"oem\"},{\"id\":\"zte.com.cn.filer\",\"description\":\"File Manager\\nStock File Manager\",\"removal\":\"replace\",\"type\":\"oem\"}]"
  },
  {
    "path": "app/src/main/assets/editor_themes/dark.tmTheme.json",
    "content": "{\n  \"name\": \"darcula\",\n  \"settings\": [\n    {\n      \"settings\": {\n        \"background\": \"#1F1A1B\",\n        \"foreground\": \"#cccccc\",\n        \"lineHighlight\": \"#2B2B2B\",\n        \"blockLineColor\": \"#575757\",\n        \"currentBlockLineColor\": \"#7a7a7a\",\n        \"selection\": \"#214283\",\n        \"completionWindowBackground\": \"#1F1A1B\",\n        \"completionWindowStroke\": \"#555555\"\n      }\n    },\n    {\n      \"name\": \"Package declaration\",\n      \"scope\": \"storage.modifier.package\",\n      \"settings\": {\n        \"foreground\": \"#CCCCCC\"\n      }\n    },\n    {\n      \"name\": \"Import declaration\",\n      \"scope\": \"storage.modifier.import\",\n      \"settings\": {\n        \"foreground\": \"#CCCCCC\"\n      }\n    },\n    {\n      \"name\": \"Class names (Identifiers starting with uppercase)\",\n      \"scope\": \"storage.type.java\",\n      \"settings\": {\n        \"foreground\": \"#CCCCCC\"\n      }\n    },\n    {\n      \"name\": \"Annotation\",\n      \"scope\": \"storage.type.annotation\",\n      \"settings\": {\n        \"foreground\": \"#BBB529\"\n      }\n    },\n    {\n      \"name\": \"Comment\",\n      \"scope\": \"comment\",\n      \"settings\": {\n        \"foreground\": \"#707070\"\n      }\n    },\n    {\n      \"name\": \"Operator Keywords\",\n      \"scope\": \"keyword.operator,keyword.operator.logical,keyword.operator.relational,keyword.operator.assignment,keyword.operator.comparison,keyword.operator.ternary,keyword.operator.arithmetic,keyword.operator.spread\",\n      \"settings\": {\n        \"foreground\": \"#CCCCCC\"\n      }\n    },\n    {\n      \"name\": \"Strings\",\n      \"scope\": \"string,string.character.escape,string.template.quoted,string.template.quoted.punctuation,string.template.quoted.punctuation.single,string.template.quoted.punctuation.double,string.type.declaration.annotation,string.template.quoted.punctuation.tag\",\n      \"settings\": {\n        \"foreground\": \"#6A8759\"\n      }\n    },\n    {\n      \"name\": \"String Interpolation Begin and End\",\n      \"scope\": \"punctuation.definition.template-expression.begin,punctuation.definition.template-expression.end\",\n      \"settings\": {\n        \"foreground\": \"#CC8242\"\n      }\n    },\n    {\n      \"name\": \"String Interpolation Body\",\n      \"scope\": \"expression.string,meta.template.expression\",\n      \"settings\": {\n        \"foreground\": \"#CCCCCC\"\n      }\n    },\n    {\n      \"name\": \"Number\",\n      \"scope\": \"constant.numeric\",\n      \"settings\": {\n        \"foreground\": \"#7A9EC2\"\n      }\n    },\n    {\n      \"name\": \"Built-in constant\",\n      \"scope\": \"constant.language,variable.language\",\n      \"settings\": {\n        \"foreground\": \"#CC8242\"\n      }\n    },\n    {\n      \"name\": \"User-defined constant\",\n      \"scope\": \"constant.character, constant.other\",\n      \"settings\": {\n        \"foreground\": \"#9E7BB0\"\n      }\n    },\n    {\n      \"name\": \"Keyword\",\n      \"scope\": \"keyword,keyword.operator.new,keyword.operator.delete,keyword.operator.static,keyword.operator.this,keyword.operator.expression\",\n      \"settings\": {\n        \"foreground\": \"#CC8242\"\n      }\n    },\n    {\n      \"name\": \"Method return type\",\n      \"scope\": \"meta.method.return-type\",\n      \"settings\": {\n        \"foreground\": \"#A9B7C6\"\n      }\n    },\n    {\n      \"name\": \"Method call identifier\",\n      \"scope\": \"meta.method-call\",\n      \"settings\": {\n        \"foreground\": \"#A9B7C6\"\n      }\n    },\n    {\n      \"name\": \"Types, Class Types\",\n      \"scope\": \"entity.name.type,meta.return.type,meta.type.annotation,meta.type.parameters,support.type.primitive\",\n      \"settings\": {\n        \"foreground\": \"#7A9EC2\"\n      }\n    },\n    {\n      \"name\": \"Storage type\",\n      \"scope\": \"storage,storage.type,storage.modifier,storage.arrow\",\n      \"settings\": {\n        \"foreground\": \"#CC8242\"\n      }\n    },\n    {\n      \"name\": \"Class constructor\",\n      \"scope\": \"class.instance.constructor,new.expr entity.name.type\",\n      \"settings\": {\n        \"foreground\": \"#FFC66D\"\n      }\n    },\n    {\n      \"name\": \"Function\",\n      \"scope\": \"support.function, entity.name.function\",\n      \"settings\": {\n        \"foreground\": \"#FFC66D\"\n      }\n    },\n    {\n      \"name\": \"Function Types\",\n      \"scope\": \"annotation.meta.ts, annotation.meta.tsx\",\n      \"settings\": {\n        \"foreground\": \"#CCCCCC\"\n      }\n    },\n    {\n      \"name\": \"Function Argument\",\n      \"scope\": \"variable.parameter, operator.rest.parameters\",\n      \"settings\": {\n        \"foreground\": \"#A9B7C6\"\n      }\n    },\n    {\n      \"name\": \"Variable, Property\",\n      \"scope\": \"variable.property,variable.other.property,variable.other.object.property,variable.object.property,support.variable.property\",\n      \"settings\": {\n        \"foreground\": \"#9E7BB0\"\n      }\n    },\n    {\n      \"name\": \"Variable name\",\n      \"scope\": \"entity.name.variable\",\n      \"settings\": {\n        \"foreground\": \"#A9B7C6\"\n      }\n    },\n    {\n      \"name\": \"CONSTANT\",\n      \"scope\": \"variable.other.constant\",\n      \"settings\": {\n        \"foreground\": \"#9876AA\"\n      }\n    },\n    {\n      \"name\": \"Module Name\",\n      \"scope\": \"quote.module\",\n      \"settings\": {\n        \"foreground\": \"#6A8759\"\n      }\n    },\n    {\n      \"name\": \"Markup Headings\",\n      \"scope\": \"markup.heading\",\n      \"settings\": {\n        \"foreground\": \"#CC8242\"\n      }\n    },\n    {\n      \"name\": \"Tag name\",\n      \"scope\": \"punctuation.definition.tag.html, punctuation.definition.tag.begin, punctuation.definition.tag.end, entity.name.tag\",\n      \"settings\": {\n        \"foreground\": \"#FFC66D\"\n      }\n    },\n    {\n      \"name\": \"Tag attribute\",\n      \"scope\": \"entity.other.attribute-name\",\n      \"settings\": {\n        \"foreground\": \"#CCCCCC\"\n      }\n    },\n    {\n      \"name\": \"Object Keys\",\n      \"scope\": \"meta.object-literal.key\",\n      \"settings\": {\n        \"foreground\": \"#9E7BB0\"\n      }\n    },\n    {\n      \"name\": \"TypeScript Class Modifiers\",\n      \"scope\": \"storage.modifier.ts\",\n      \"settings\": {\n        \"foreground\": \"#CC8242\"\n      }\n    },\n    {\n      \"name\": \"TypeScript Type Casting\",\n      \"scope\": \"ts.cast.expr,ts.meta.entity.class.method.new.expr.cast,ts.meta.entity.type.name.new.expr.cast,ts.meta.entity.type.name.var-single-variable.annotation,tsx.cast.expr,tsx.meta.entity.class.method.new.expr.cast,tsx.meta.entity.type.name.new.expr.cast,tsx.meta.entity.type.name.var-single-variable.annotation\",\n      \"settings\": {\n        \"foreground\": \"#7A9EC2\"\n      }\n    },\n    {\n      \"name\": \"TypeScript Type Declaration\",\n      \"scope\": \"ts.meta.type.support,ts.meta.type.entity.name,ts.meta.class.inherited-class,tsx.meta.type.support,tsx.meta.type.entity.name,tsx.meta.class.inherited-class,type-declaration,enum-declaration\",\n      \"settings\": {\n        \"foreground\": \"#7A9EC2\"\n      }\n    },\n    {\n      \"name\": \"TypeScript Method Declaration\",\n      \"scope\": \"function-declaration,method-declaration,method-overload-declaration,type-fn-type-parameters\",\n      \"settings\": {\n        \"foreground\": \"#FFC66D\"\n      }\n    },\n    {\n      \"name\": \"Documentation Block\",\n      \"scope\": \"comment.block.documentation\",\n      \"settings\": {\n        \"foreground\": \"#6A8759\"\n      }\n    },\n    {\n      \"name\": \"Documentation Highlight (JSDoc)\",\n      \"scope\": \"storage.type.class.jsdoc\",\n      \"settings\": {\n        \"foreground\": \"#CC8242\"\n      }\n    },\n    {\n      \"name\": \"Import-Export-All (*) Keyword\",\n      \"scope\": \"constant.language.import-export-all\",\n      \"settings\": {\n        \"foreground\": \"#CCCCCC\"\n      }\n    },\n    {\n      \"name\": \"Object Key Seperator\",\n      \"scope\": \"objectliteral.key.separator, punctuation.separator.key-value\",\n      \"settings\": {\n        \"foreground\": \"#CCCCCC\"\n      }\n    },\n    {\n      \"name\": \"Regex\",\n      \"scope\": \"regex\",\n      \"settings\": {\n        \"fontStyle\": \" italic\"\n      }\n    },\n    {\n      \"name\": \"Typescript Namespace\",\n      \"scope\": \"ts.meta.entity.name.namespace,tsx.meta.entity.name.namespace\",\n      \"settings\": {\n        \"foreground\": \"#CCCCCC\"\n      }\n    },\n    {\n      \"name\": \"Regex Character-class\",\n      \"scope\": \"regex.character-class\",\n      \"settings\": {\n        \"foreground\": \"#CCCCCC\"\n      }\n    },\n    {\n      \"name\": \"Class Name\",\n      \"scope\": \"entity.name.type.class\",\n      \"settings\": {\n        \"foreground\": \"#A9B7C6\"\n      }\n    },\n    {\n      \"name\": \"Class Inheritances\",\n      \"scope\": \"entity.other.inherited-class\",\n      \"settings\": {\n        \"foreground\": \"#7A9EC2\"\n      }\n    },\n    {\n      \"name\": \"Documentation Entity\",\n      \"scope\": \"entity.name.type.instance.jsdoc\",\n      \"settings\": {\n        \"foreground\": \"#FFC66D\"\n      }\n    },\n    {\n      \"name\": \"YAML entity\",\n      \"scope\": \"yaml.entity.name,yaml.string.entity.name\",\n      \"settings\": {\n        \"foreground\": \"#CC8242\"\n      }\n    },\n    {\n      \"name\": \"YAML string value\",\n      \"scope\": \"yaml.string.out\",\n      \"settings\": {\n        \"foreground\": \"#CCCCCC\"\n      }\n    },\n    {\n      \"name\": \"Ignored (Exceptions Rules)\",\n      \"scope\": \"meta.brace.square.ts,block.support.module,block.support.type.module,block.support.function.variable,punctuation.definition.typeparameters.begin,punctuation.definition.typeparameters.end\",\n      \"settings\": {\n        \"foreground\": \"#CCCCCC\"\n      }\n    },\n    {\n      \"name\": \"Regex\",\n      \"scope\": \"string.regexp\",\n      \"settings\": {\n        \"foreground\": \"#CC8242\"\n      }\n    },\n    {\n      \"name\": \"Regex Group/Set\",\n      \"scope\": \"punctuation.definition.group.regexp,punctuation.definition.character-class.regexp\",\n      \"settings\": {\n        \"foreground\": \"#FFC66D\"\n      }\n    },\n    {\n      \"name\": \"Regex Character Class\",\n      \"scope\": \"constant.other.character-class.regexp, constant.character.escape.ts\",\n      \"settings\": {\n        \"foreground\": \"#CCCCCC\"\n      }\n    },\n    {\n      \"name\": \"Regex Or Operator\",\n      \"scope\": \"expr.regex.or.operator\",\n      \"settings\": {\n        \"foreground\": \"#CCCCCC\"\n      }\n    },\n    {\n      \"name\": \"Tag string\",\n      \"scope\": \"string.template.tag,string.template.punctuation.tag,string.quoted.punctuation.tag,string.quoted.embedded.tag, string.quoted.double.tag\",\n      \"settings\": {\n        \"foreground\": \"#6A8759\"\n      }\n    },\n    {\n      \"name\": \"Tag function parenthesis\",\n      \"scope\": \"tag.punctuation.begin.arrow.parameters.embedded,tag.punctuation.end.arrow.parameters.embedded\",\n      \"settings\": {\n        \"foreground\": \"#CCCCCC\"\n      }\n    },\n    {\n      \"name\": \"Object-literal key class\",\n      \"scope\": \"object-literal.object.member.key.field.other,object-literal.object.member.key.accessor,object-literal.object.member.key.array.brace.square\",\n      \"settings\": {\n        \"foreground\": \"#CCCCCC\"\n      }\n    },\n    {\n      \"name\": \"CSS Property-value\",\n      \"scope\": \"property-list.property-value,property-list.constant\",\n      \"settings\": {\n        \"foreground\": \"#A5C261\"\n      }\n    },\n    {\n      \"name\": \"CSS Property variable\",\n      \"scope\": \"support.type.property-name.variable.css,support.type.property-name.variable.scss,variable.scss\",\n      \"settings\": {\n        \"foreground\": \"#7A9EC2\"\n      }\n    },\n    {\n      \"name\": \"CSS Property entity\",\n      \"scope\": \"entity.other.attribute-name.class.css,entity.other.attribute-name.class.scss,entity.other.attribute-name.parent-selector-suffix.css,entity.other.attribute-name.parent-selector-suffix.scss\",\n      \"settings\": {\n        \"foreground\": \"#FFC66D\"\n      }\n    },\n    {\n      \"name\": \"CSS Property-value\",\n      \"scope\": \"property-list.property-value.rgb-value, keyword.other.unit.css,keyword.other.unit.scss\",\n      \"settings\": {\n        \"foreground\": \"#7A9EC2\"\n      }\n    },\n    {\n      \"name\": \"CSS Property-value function\",\n      \"scope\": \"property-list.property-value.function\",\n      \"settings\": {\n        \"foreground\": \"#FFC66D\"\n      }\n    },\n    {\n      \"name\": \"CSS constant variables\",\n      \"scope\": \"support.constant.property-value.css,support.constant.property-value.scss\",\n      \"settings\": {\n        \"foreground\": \"#A5C261\"\n      }\n    },\n    {\n      \"name\": \"CSS Tag\",\n      \"scope\": \"css.entity.name.tag,scss.entity.name.tag\",\n      \"settings\": {\n        \"foreground\": \"#CC8242\"\n      }\n    },\n    {\n      \"name\": \"CSS ID, Selector\",\n      \"scope\": \"meta.selector.css, entity.attribute-name.id, entity.other.attribute-name.pseudo-class.css,entity.other.attribute-name.pseudo-element.css\",\n      \"settings\": {\n        \"foreground\": \"#FFC66D\"\n      }\n    },\n    {\n      \"name\": \"CSS Keyword\",\n      \"scope\": \"keyword.scss,keyword.css\",\n      \"settings\": {\n        \"foreground\": \"#CC8242\"\n      }\n    },\n    {\n      \"name\": \"Triple-slash Directive Tag\",\n      \"scope\": \"triple-slash.tag\",\n      \"settings\": {\n        \"foreground\": \"#CCCCCC\",\n        \"fontStyle\": \"italic\"\n      }\n    },\n    {\n      \"scope\": \"token.info-token\",\n      \"settings\": {\n        \"foreground\": \"#6796e6\"\n      }\n    },\n    {\n      \"scope\": \"token.warn-token\",\n      \"settings\": {\n        \"foreground\": \"#cd9731\"\n      }\n    },\n    {\n      \"scope\": \"token.error-token\",\n      \"settings\": {\n        \"foreground\": \"#f44747\"\n      }\n    },\n    {\n      \"scope\": \"token.debug-token\",\n      \"settings\": {\n        \"foreground\": \"#b267e6\"\n      }\n    },\n    {\n      \"name\": \"Python operators\",\n      \"scope\": \"keyword.operator.logical.python\",\n      \"settings\": {\n        \"foreground\": \"#CC8242\"\n      }\n    },\n    {\n      \"name\": \"Dart class type\",\n      \"scope\": \"support.class.dart\",\n      \"settings\": {\n        \"foreground\": \"#CC8242\"\n      }\n    },\n    {\n      \"name\": \"PHP variables\",\n      \"scope\": [\n        \"variable.language.php\",\n        \"variable.other.php\"\n      ],\n      \"settings\": {\n        \"foreground\": \"#9E7BB0\"\n      }\n    },\n    {\n      \"name\": \"Perl specific\",\n      \"scope\": [\n        \"variable.other.readwrite.perl\"\n      ],\n      \"settings\": {\n        \"foreground\": \"#9E7BB0\"\n      }\n    },\n    {\n      \"name\": \"PHP variables\",\n      \"scope\": [\n        \"variable.other.property.php\"\n      ],\n      \"settings\": {\n        \"foreground\": \"#CC8242\"\n      }\n    },\n    {\n      \"name\": \"PHP variables\",\n      \"scope\": [\n        \"support.variable.property.php\"\n      ],\n      \"settings\": {\n        \"foreground\": \"#FFC66D\"\n      }\n    },\n    {\n      \"name\": \"XML Namespace prefix\",\n      \"scope\": \"entity.name.tag.namesapce.xml\",\n      \"settings\": {\n        \"foreground\": \"#9876AA\"\n      }\n    }\n  ]\n}\n"
  },
  {
    "path": "app/src/main/assets/editor_themes/light.tmTheme",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!DOCTYPE plist PUBLIC \"-//Apple//DTD PLIST 1.0//EN\" \"http://www.apple.com/DTDs/PropertyList-1.0.dtd\">\n<plist version=\"1.0\">\n<dict>\n\t<key>author</key>\n\t<string>Martin Kühl</string>\n\t<key>comment</key>\n\t<string>Based on the Quiet Light theme for Espresso by Ian Beck.</string>\n\t<key>name</key>\n\t<string>Quiet Light</string>\n\t<key>settings</key>\n\t<array>\n\t\t<dict>\n\t\t\t<key>settings</key>\n\t\t\t<dict>\n\t\t\t\t<key>background</key>\n\t\t\t\t<string>#F5F5F5</string>\n\t\t\t\t<key>caret</key>\n\t\t\t\t<string>#000000</string>\n\t\t\t\t<key>foreground</key>\n\t\t\t\t<string>#333333</string>\n\t\t\t\t<key>invisibles</key>\n\t\t\t\t<string>#AAAAAA</string>\n\t\t\t\t<key>lineHighlight</key>\n\t\t\t\t<string>#E4F6D4</string>\n\t\t\t\t<key>selection</key>\n\t\t\t\t<string>#C9D0D9</string>\n\t\t\t</dict>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>name</key>\n\t\t\t<string>Comments</string>\n\t\t\t<key>scope</key>\n\t\t\t<string>comment, punctuation.definition.comment</string>\n\t\t\t<key>settings</key>\n\t\t\t<dict>\n\t\t\t\t<key>fontStyle</key>\n\t\t\t\t<string>italic</string>\n\t\t\t\t<key>foreground</key>\n\t\t\t\t<string>#AAAAAA</string>\n\t\t\t</dict>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>name</key>\n\t\t\t<string>Comments: Preprocessor</string>\n\t\t\t<key>scope</key>\n\t\t\t<string>comment.block.preprocessor</string>\n\t\t\t<key>settings</key>\n\t\t\t<dict>\n\t\t\t\t<key>fontStyle</key>\n\t\t\t\t<string></string>\n\t\t\t\t<key>foreground</key>\n\t\t\t\t<string>#AAAAAA</string>\n\t\t\t</dict>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>name</key>\n\t\t\t<string>Comments: Documentation</string>\n\t\t\t<key>scope</key>\n\t\t\t<string>comment.documentation, comment.block.documentation</string>\n\t\t\t<key>settings</key>\n\t\t\t<dict>\n\t\t\t\t<key>foreground</key>\n\t\t\t\t<string>#448C27</string>\n\t\t\t</dict>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>name</key>\n\t\t\t<string>Invalid - Deprecated</string>\n\t\t\t<key>scope</key>\n\t\t\t<string>invalid.deprecated</string>\n\t\t\t<key>settings</key>\n\t\t\t<dict>\n\t\t\t\t<key>background</key>\n\t\t\t\t<string>#96000014</string>\n\t\t\t</dict>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>name</key>\n\t\t\t<string>Invalid - Illegal</string>\n\t\t\t<key>scope</key>\n\t\t\t<string>invalid.illegal</string>\n\t\t\t<key>settings</key>\n\t\t\t<dict>\n\t\t\t\t<key>background</key>\n\t\t\t\t<string>#96000014</string>\n\t\t\t\t<key>foreground</key>\n\t\t\t\t<string>#660000</string>\n\t\t\t</dict>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>name</key>\n\t\t\t<string>Operators</string>\n\t\t\t<key>scope</key>\n\t\t\t<string>keyword.operator</string>\n\t\t\t<key>settings</key>\n\t\t\t<dict>\n\t\t\t\t<key>foreground</key>\n\t\t\t\t<string>#777777</string>\n\t\t\t</dict>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>name</key>\n\t\t\t<string>Keywords</string>\n\t\t\t<key>scope</key>\n\t\t\t<string>keyword, storage</string>\n\t\t\t<key>settings</key>\n\t\t\t<dict>\n\t\t\t\t<key>foreground</key>\n\t\t\t\t<string>#4B83CD</string>\n\t\t\t</dict>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>name</key>\n\t\t\t<string>Types</string>\n\t\t\t<key>scope</key>\n\t\t\t<string>storage.type, support.type</string>\n\t\t\t<key>settings</key>\n\t\t\t<dict>\n\t\t\t\t<key>foreground</key>\n\t\t\t\t<string>#7A3E9D</string>\n\t\t\t</dict>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>name</key>\n\t\t\t<string>Language Constants</string>\n\t\t\t<key>scope</key>\n\t\t\t<string>constant.language, support.constant, variable.language</string>\n\t\t\t<key>settings</key>\n\t\t\t<dict>\n\t\t\t\t<key>foreground</key>\n\t\t\t\t<string>#AB6526</string>\n\t\t\t</dict>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>name</key>\n\t\t\t<string>Variables</string>\n\t\t\t<key>scope</key>\n\t\t\t<string>variable, support.variable</string>\n\t\t\t<key>settings</key>\n\t\t\t<dict>\n\t\t\t\t<key>foreground</key>\n\t\t\t\t<string>#7A3E9D</string>\n\t\t\t</dict>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>name</key>\n\t\t\t<string>Functions</string>\n\t\t\t<key>scope</key>\n\t\t\t<string>entity.name.function, support.function</string>\n\t\t\t<key>settings</key>\n\t\t\t<dict>\n\t\t\t\t<key>fontStyle</key>\n\t\t\t\t<string>bold</string>\n\t\t\t\t<key>foreground</key>\n\t\t\t\t<string>#AA3731</string>\n\t\t\t</dict>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>name</key>\n\t\t\t<string>Classes</string>\n\t\t\t<key>scope</key>\n\t\t\t<string>entity.name.type, entity.other.inherited-class, support.class</string>\n\t\t\t<key>settings</key>\n\t\t\t<dict>\n\t\t\t\t<key>fontStyle</key>\n\t\t\t\t<string>bold</string>\n\t\t\t\t<key>foreground</key>\n\t\t\t\t<string>#7A3E9D</string>\n\t\t\t</dict>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>name</key>\n\t\t\t<string>Exceptions</string>\n\t\t\t<key>scope</key>\n\t\t\t<string>entity.name.exception</string>\n\t\t\t<key>settings</key>\n\t\t\t<dict>\n\t\t\t\t<key>foreground</key>\n\t\t\t\t<string>#660000</string>\n\t\t\t</dict>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>name</key>\n\t\t\t<string>Sections</string>\n\t\t\t<key>scope</key>\n\t\t\t<string>entity.name.section</string>\n\t\t\t<key>settings</key>\n\t\t\t<dict>\n\t\t\t\t<key>fontStyle</key>\n\t\t\t\t<string>bold</string>\n\t\t\t</dict>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>name</key>\n\t\t\t<string>Numbers, Characters</string>\n\t\t\t<key>scope</key>\n\t\t\t<string>constant.numeric, constant.character, constant</string>\n\t\t\t<key>settings</key>\n\t\t\t<dict>\n\t\t\t\t<key>foreground</key>\n\t\t\t\t<string>#AB6526</string>\n\t\t\t</dict>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>name</key>\n\t\t\t<string>Strings</string>\n\t\t\t<key>scope</key>\n\t\t\t<string>string</string>\n\t\t\t<key>settings</key>\n\t\t\t<dict>\n\t\t\t\t<key>foreground</key>\n\t\t\t\t<string>#448C27</string>\n\t\t\t</dict>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>name</key>\n\t\t\t<string>Strings: Escape Sequences</string>\n\t\t\t<key>scope</key>\n\t\t\t<string>constant.character.escape</string>\n\t\t\t<key>settings</key>\n\t\t\t<dict>\n\t\t\t\t<key>foreground</key>\n\t\t\t\t<string>#777777</string>\n\t\t\t</dict>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>name</key>\n\t\t\t<string>Strings: Regular Expressions</string>\n\t\t\t<key>scope</key>\n\t\t\t<string>string.regexp</string>\n\t\t\t<key>settings</key>\n\t\t\t<dict>\n\t\t\t\t<key>foreground</key>\n\t\t\t\t<string>#4B83CD</string>\n\t\t\t</dict>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>name</key>\n\t\t\t<string>Strings: Symbols</string>\n\t\t\t<key>scope</key>\n\t\t\t<string>constant.other.symbol</string>\n\t\t\t<key>settings</key>\n\t\t\t<dict>\n\t\t\t\t<key>foreground</key>\n\t\t\t\t<string>#AB6526</string>\n\t\t\t</dict>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>name</key>\n\t\t\t<string>Punctuation</string>\n\t\t\t<key>scope</key>\n\t\t\t<string>punctuation</string>\n\t\t\t<key>settings</key>\n\t\t\t<dict>\n\t\t\t\t<key>foreground</key>\n\t\t\t\t<string>#777777</string>\n\t\t\t</dict>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>name</key>\n\t\t\t<string>Embedded Source</string>\n\t\t\t<key>scope</key>\n\t\t\t<string>string source, text source</string>\n\t\t\t<key>settings</key>\n\t\t\t<dict>\n\t\t\t\t<key>background</key>\n\t\t\t\t<string>#EAEBE6</string>\n\t\t\t</dict>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>name</key>\n\t\t\t<string>-----------------------------------</string>\n\t\t\t<key>settings</key>\n\t\t\t<dict/>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>name</key>\n\t\t\t<string>HTML: Doctype Declaration</string>\n\t\t\t<key>scope</key>\n\t\t\t<string>meta.tag.sgml.doctype, meta.tag.sgml.doctype string, meta.tag.sgml.doctype entity.name.tag, meta.tag.sgml punctuation.definition.tag.html</string>\n\t\t\t<key>settings</key>\n\t\t\t<dict>\n\t\t\t\t<key>foreground</key>\n\t\t\t\t<string>#AAAAAA</string>\n\t\t\t</dict>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>name</key>\n\t\t\t<string>HTML: Tags</string>\n\t\t\t<key>scope</key>\n\t\t\t<string>meta.tag, punctuation.definition.tag.html, punctuation.definition.tag.begin.html, punctuation.definition.tag.end.html</string>\n\t\t\t<key>settings</key>\n\t\t\t<dict>\n\t\t\t\t<key>foreground</key>\n\t\t\t\t<string>#91B3E0</string>\n\t\t\t</dict>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>name</key>\n\t\t\t<string>HTML: Tag Names</string>\n\t\t\t<key>scope</key>\n\t\t\t<string>entity.name.tag</string>\n\t\t\t<key>settings</key>\n\t\t\t<dict>\n\t\t\t\t<key>foreground</key>\n\t\t\t\t<string>#4B83CD</string>\n\t\t\t</dict>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>name</key>\n\t\t\t<string>HTML: Attribute Names</string>\n\t\t\t<key>scope</key>\n\t\t\t<string>meta.tag entity.other.attribute-name, entity.other.attribute-name.html</string>\n\t\t\t<key>settings</key>\n\t\t\t<dict>\n\t\t\t\t<key>fontStyle</key>\n\t\t\t\t<string>italic</string>\n\t\t\t\t<key>foreground</key>\n\t\t\t\t<string>#91B3E0</string>\n\t\t\t</dict>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>name</key>\n\t\t\t<string>HTML: Entities</string>\n\t\t\t<key>scope</key>\n\t\t\t<string>constant.character.entity, punctuation.definition.entity</string>\n\t\t\t<key>settings</key>\n\t\t\t<dict>\n\t\t\t\t<key>foreground</key>\n\t\t\t\t<string>#AB6526</string>\n\t\t\t</dict>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>name</key>\n\t\t\t<string>-----------------------------------</string>\n\t\t\t<key>settings</key>\n\t\t\t<dict/>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>name</key>\n\t\t\t<string>CSS: Selectors</string>\n\t\t\t<key>scope</key>\n\t\t\t<string>meta.selector, meta.selector entity, meta.selector entity punctuation, entity.name.tag.css</string>\n\t\t\t<key>settings</key>\n\t\t\t<dict>\n\t\t\t\t<key>foreground</key>\n\t\t\t\t<string>#7A3E9D</string>\n\t\t\t</dict>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>name</key>\n\t\t\t<string>CSS: Property Names</string>\n\t\t\t<key>scope</key>\n\t\t\t<string>meta.property-name, support.type.property-name</string>\n\t\t\t<key>settings</key>\n\t\t\t<dict>\n\t\t\t\t<key>foreground</key>\n\t\t\t\t<string>#AB6526</string>\n\t\t\t</dict>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>name</key>\n\t\t\t<string>CSS: Property Values</string>\n\t\t\t<key>scope</key>\n\t\t\t<string>meta.property-value, meta.property-value constant.other, support.constant.property-value</string>\n\t\t\t<key>settings</key>\n\t\t\t<dict>\n\t\t\t\t<key>foreground</key>\n\t\t\t\t<string>#448C27</string>\n\t\t\t</dict>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>name</key>\n\t\t\t<string>CSS: Important Keyword</string>\n\t\t\t<key>scope</key>\n\t\t\t<string>keyword.other.important</string>\n\t\t\t<key>settings</key>\n\t\t\t<dict>\n\t\t\t\t<key>fontStyle</key>\n\t\t\t\t<string>bold</string>\n\t\t\t</dict>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>name</key>\n\t\t\t<string>-----------------------------------</string>\n\t\t\t<key>settings</key>\n\t\t\t<dict/>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>name</key>\n\t\t\t<string>Markup: Changed</string>\n\t\t\t<key>scope</key>\n\t\t\t<string>markup.changed</string>\n\t\t\t<key>settings</key>\n\t\t\t<dict>\n\t\t\t\t<key>background</key>\n\t\t\t\t<string>#FFFFDD</string>\n\t\t\t\t<key>foreground</key>\n\t\t\t\t<string>#000000</string>\n\t\t\t</dict>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>name</key>\n\t\t\t<string>Markup: Deletion</string>\n\t\t\t<key>scope</key>\n\t\t\t<string>markup.deleted</string>\n\t\t\t<key>settings</key>\n\t\t\t<dict>\n\t\t\t\t<key>background</key>\n\t\t\t\t<string>#FFDDDD</string>\n\t\t\t\t<key>foreground</key>\n\t\t\t\t<string>#000000</string>\n\t\t\t</dict>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>name</key>\n\t\t\t<string>Markup: Emphasis</string>\n\t\t\t<key>scope</key>\n\t\t\t<string>markup.italic</string>\n\t\t\t<key>settings</key>\n\t\t\t<dict>\n\t\t\t\t<key>fontStyle</key>\n\t\t\t\t<string>italic</string>\n\t\t\t</dict>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>name</key>\n\t\t\t<string>Markup: Error</string>\n\t\t\t<key>scope</key>\n\t\t\t<string>markup.error</string>\n\t\t\t<key>settings</key>\n\t\t\t<dict>\n\t\t\t\t<key>background</key>\n\t\t\t\t<string>#96000014</string>\n\t\t\t\t<key>foreground</key>\n\t\t\t\t<string>#660000</string>\n\t\t\t</dict>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>name</key>\n\t\t\t<string>Markup: Insertion</string>\n\t\t\t<key>scope</key>\n\t\t\t<string>markup.inserted</string>\n\t\t\t<key>settings</key>\n\t\t\t<dict>\n\t\t\t\t<key>background</key>\n\t\t\t\t<string>#DDFFDD</string>\n\t\t\t\t<key>foreground</key>\n\t\t\t\t<string>#000000</string>\n\t\t\t</dict>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>name</key>\n\t\t\t<string>Markup: Link</string>\n\t\t\t<key>scope</key>\n\t\t\t<string>meta.link</string>\n\t\t\t<key>settings</key>\n\t\t\t<dict>\n\t\t\t\t<key>foreground</key>\n\t\t\t\t<string>#4B83CD</string>\n\t\t\t</dict>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>name</key>\n\t\t\t<string>Markup: Output</string>\n\t\t\t<key>scope</key>\n\t\t\t<string>markup.output, markup.raw</string>\n\t\t\t<key>settings</key>\n\t\t\t<dict>\n\t\t\t\t<key>foreground</key>\n\t\t\t\t<string>#777777</string>\n\t\t\t</dict>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>name</key>\n\t\t\t<string>Markup: Prompt</string>\n\t\t\t<key>scope</key>\n\t\t\t<string>markup.prompt</string>\n\t\t\t<key>settings</key>\n\t\t\t<dict>\n\t\t\t\t<key>foreground</key>\n\t\t\t\t<string>#777777</string>\n\t\t\t</dict>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>name</key>\n\t\t\t<string>Markup: Heading</string>\n\t\t\t<key>scope</key>\n\t\t\t<string>markup.heading</string>\n\t\t\t<key>settings</key>\n\t\t\t<dict>\n\t\t\t\t<key>foreground</key>\n\t\t\t\t<string>#AA3731</string>\n\t\t\t</dict>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>name</key>\n\t\t\t<string>Markup: Strong</string>\n\t\t\t<key>scope</key>\n\t\t\t<string>markup.bold</string>\n\t\t\t<key>settings</key>\n\t\t\t<dict>\n\t\t\t\t<key>fontStyle</key>\n\t\t\t\t<string>bold</string>\n\t\t\t</dict>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>name</key>\n\t\t\t<string>Markup: Traceback</string>\n\t\t\t<key>scope</key>\n\t\t\t<string>markup.traceback</string>\n\t\t\t<key>settings</key>\n\t\t\t<dict>\n\t\t\t\t<key>foreground</key>\n\t\t\t\t<string>#660000</string>\n\t\t\t</dict>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>name</key>\n\t\t\t<string>Markup: Underline</string>\n\t\t\t<key>scope</key>\n\t\t\t<string>markup.underline</string>\n\t\t\t<key>settings</key>\n\t\t\t<dict>\n\t\t\t\t<key>fontStyle</key>\n\t\t\t\t<string>underline</string>\n\t\t\t</dict>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>name</key>\n\t\t\t<string>Markup Quote</string>\n\t\t\t<key>scope</key>\n\t\t\t<string>markup.quote</string>\n\t\t\t<key>settings</key>\n\t\t\t<dict>\n\t\t\t\t<key>foreground</key>\n\t\t\t\t<string>#7A3E9D</string>\n\t\t\t</dict>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>name</key>\n\t\t\t<string>Markup Lists</string>\n\t\t\t<key>scope</key>\n\t\t\t<string>markup.list</string>\n\t\t\t<key>settings</key>\n\t\t\t<dict>\n\t\t\t\t<key>foreground</key>\n\t\t\t\t<string>#4B83CD</string>\n\t\t\t</dict>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>name</key>\n\t\t\t<string>Markup Styling</string>\n\t\t\t<key>scope</key>\n\t\t\t<string>markup.bold, markup.italic</string>\n\t\t\t<key>settings</key>\n\t\t\t<dict>\n\t\t\t\t<key>foreground</key>\n\t\t\t\t<string>#448C27</string>\n\t\t\t</dict>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>name</key>\n\t\t\t<string>Markup Inline</string>\n\t\t\t<key>scope</key>\n\t\t\t<string>markup.inline.raw</string>\n\t\t\t<key>settings</key>\n\t\t\t<dict>\n\t\t\t\t<key>fontStyle</key>\n\t\t\t\t<string></string>\n\t\t\t\t<key>foreground</key>\n\t\t\t\t<string>#AB6526</string>\n\t\t\t</dict>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>name</key>\n\t\t\t<string>-----------------------------------</string>\n\t\t\t<key>settings</key>\n\t\t\t<dict/>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>name</key>\n\t\t\t<string>Extra: Diff Range</string>\n\t\t\t<key>scope</key>\n\t\t\t<string>meta.diff.range, meta.diff.index, meta.separator</string>\n\t\t\t<key>settings</key>\n\t\t\t<dict>\n\t\t\t\t<key>background</key>\n\t\t\t\t<string>#DDDDFF</string>\n\t\t\t\t<key>foreground</key>\n\t\t\t\t<string>#434343</string>\n\t\t\t</dict>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>name</key>\n\t\t\t<string>Extra: Diff From</string>\n\t\t\t<key>scope</key>\n\t\t\t<string>meta.diff.header.from-file</string>\n\t\t\t<key>settings</key>\n\t\t\t<dict>\n\t\t\t\t<key>background</key>\n\t\t\t\t<string>#FFDDDD</string>\n\t\t\t\t<key>foreground</key>\n\t\t\t\t<string>#434343</string>\n\t\t\t</dict>\n\t\t</dict>\n\t\t<dict>\n\t\t\t<key>name</key>\n\t\t\t<string>Extra: Diff To</string>\n\t\t\t<key>scope</key>\n\t\t\t<string>meta.diff.header.to-file</string>\n\t\t\t<key>settings</key>\n\t\t\t<dict>\n\t\t\t\t<key>background</key>\n\t\t\t\t<string>#DDFFDD</string>\n\t\t\t\t<key>foreground</key>\n\t\t\t\t<string>#434343</string>\n\t\t\t</dict>\n\t\t</dict>\n\t</array>\n\t<key>uuid</key>\n\t<string>231D6A91-5FD1-4CBE-BD2A-0F36C08693F1</string>\n</dict>\n</plist>\n"
  },
  {
    "path": "app/src/main/assets/languages/java/language-configuration.json",
    "content": "{\n  \"comments\": {\n    \"lineComment\": \"//\",\n    \"blockComment\": [ \"/*\", \"*/\" ]\n  },\n  \"brackets\": [\n    [\"{\", \"}\"],\n    [\"[\", \"]\"],\n    [\"(\", \")\"]\n  ],\n  \"autoClosingPairs\": [\n    [\"{\", \"}\"],\n    [\"[\", \"]\"],\n    [\"(\", \")\"],\n    { \"open\": \"\\\"\", \"close\": \"\\\"\", \"notIn\": [\"string\"] },\n    { \"open\": \"'\", \"close\": \"'\", \"notIn\": [\"string\"] },\n    { \"open\": \"/**\", \"close\": \" */\", \"notIn\": [\"string\"] }\n  ],\n  \"surroundingPairs\": [\n    [\"{\", \"}\"],\n    [\"[\", \"]\"],\n    [\"(\", \")\"],\n    [\"\\\"\", \"\\\"\"],\n    [\"'\", \"'\"],\n    [\"<\", \">\"]\n  ],\n  \"folding\": {\n    \"markers\": {\n      \"start\": \"^\\\\s*//\\\\s*(?:(?:#?region\\\\b)|(?:<editor-fold\\\\b))\",\n      \"end\": \"^\\\\s*//\\\\s*(?:(?:#?endregion\\\\b)|(?:</editor-fold>))\"\n    }\n  }\n}\n"
  },
  {
    "path": "app/src/main/assets/languages/java/tmLanguage.json",
    "content": "{\n  \"information_for_contributors\": [\n    \"This file has been converted from https://github.com/atom/language-java/blob/master/grammars/java.cson\",\n    \"If you want to provide a fix or improvement, please create a pull request against the original repository.\",\n    \"Once accepted there, we are happy to receive an update request.\"\n  ],\n  \"version\": \"https://github.com/atom/language-java/commit/29f977dc42a7e2568b39bb6fb34c4ef108eb59b3\",\n  \"name\": \"Java\",\n  \"scopeName\": \"lngpck.source.java\",\n  \"patterns\": [\n    {\n      \"begin\": \"\\\\b(package)\\\\b\\\\s*\",\n      \"beginCaptures\": {\n        \"1\": {\n          \"name\": \"keyword.other.package.java\"\n        }\n      },\n      \"end\": \"\\\\s*(;)\",\n      \"endCaptures\": {\n        \"1\": {\n          \"name\": \"punctuation.terminator.java\"\n        }\n      },\n      \"name\": \"meta.package.java\",\n      \"contentName\": \"storage.modifier.package.java\",\n      \"patterns\": [\n        {\n          \"include\": \"#comments\"\n        },\n        {\n          \"match\": \"(?<=\\\\.)\\\\s*\\\\.|\\\\.(?=\\\\s*;)\",\n          \"name\": \"invalid.illegal.character_not_allowed_here.java\"\n        },\n        {\n          \"match\": \"(?<!_)_(?=\\\\s*(\\\\.|;))|\\\\b\\\\d+|-+\",\n          \"name\": \"invalid.illegal.character_not_allowed_here.java\"\n        },\n        {\n          \"match\": \"[A-Z]+\",\n          \"name\": \"invalid.deprecated.package_name_not_lowercase.java\"\n        },\n        {\n          \"match\": \"(?x)\\\\b(?<!\\\\$)\\n(abstract|assert|boolean|break|byte|case|catch|char|class|\\nconst|continue|default|do|double|else|enum|extends|final|\\nfinally|float|for|goto|if|implements|import|instanceof|int|\\ninterface|long|native|new|non-sealed|package|permits|private|protected|public|\\nreturn|sealed|short|static|strictfp|super|switch|syncronized|this|\\nthrow|throws|transient|try|void|volatile|while|yield|\\ntrue|false|null)\\\\b\",\n          \"name\": \"invalid.illegal.character_not_allowed_here.java\"\n        },\n        {\n          \"match\": \"\\\\.\",\n          \"name\": \"punctuation.separator.java\"\n        }\n      ]\n    },\n    {\n      \"begin\": \"\\\\b(import)\\\\b\\\\s*\\\\b(static)?\\\\b\\\\s\",\n      \"beginCaptures\": {\n        \"1\": {\n          \"name\": \"keyword.other.import.java\"\n        },\n        \"2\": {\n          \"name\": \"storage.modifier.java\"\n        }\n      },\n      \"end\": \"\\\\s*(;)\",\n      \"endCaptures\": {\n        \"1\": {\n          \"name\": \"punctuation.terminator.java\"\n        }\n      },\n      \"name\": \"meta.import.java\",\n      \"contentName\": \"storage.modifier.import.java\",\n      \"patterns\": [\n        {\n          \"include\": \"#comments\"\n        },\n        {\n          \"match\": \"(?<=\\\\.)\\\\s*\\\\.|\\\\.(?=\\\\s*;)\",\n          \"name\": \"invalid.illegal.character_not_allowed_here.java\"\n        },\n        {\n          \"match\": \"(?<!\\\\.)\\\\s*\\\\*\",\n          \"name\": \"invalid.illegal.character_not_allowed_here.java\"\n        },\n        {\n          \"match\": \"(?<!_)_(?=\\\\s*(\\\\.|;))|\\\\b\\\\d+|-+\",\n          \"name\": \"invalid.illegal.character_not_allowed_here.java\"\n        },\n        {\n          \"match\": \"(?x)\\\\b(?<!\\\\$)\\n(abstract|assert|boolean|break|byte|case|catch|char|class|\\nconst|continue|default|do|double|else|enum|extends|final|\\nfinally|float|for|goto|if|implements|import|instanceof|int|\\ninterface|long|native|new|non-sealed|package|permits|private|protected|public|\\nreturn|sealed|short|static|strictfp|super|switch|syncronized|this|\\nthrow|throws|transient|try|void|volatile|while|yield|\\ntrue|false|null)\\\\b\",\n          \"name\": \"invalid.illegal.character_not_allowed_here.java\"\n        },\n        {\n          \"match\": \"\\\\.\",\n          \"name\": \"punctuation.separator.java\"\n        },\n        {\n          \"match\": \"\\\\*\",\n          \"name\": \"variable.language.wildcard.java\"\n        }\n      ]\n    },\n    {\n      \"include\": \"#comments-javadoc\"\n    },\n    {\n      \"include\": \"#code\"\n    },\n    {\n      \"include\": \"#module\"\n    }\n  ],\n  \"repository\": {\n    \"all-types\": {\n      \"patterns\": [\n        {\n          \"include\": \"#primitive-arrays\"\n        },\n        {\n          \"include\": \"#primitive-types\"\n        },\n        {\n          \"include\": \"#object-types\"\n        }\n      ]\n    },\n    \"annotations\": {\n      \"patterns\": [\n        {\n          \"begin\": \"((@)\\\\s*([^\\\\s(]+))(\\\\()\",\n          \"beginCaptures\": {\n            \"2\": {\n              \"name\": \"punctuation.definition.annotation.java\"\n            },\n            \"3\": {\n              \"name\": \"storage.type.annotation.java\"\n            },\n            \"4\": {\n              \"name\": \"punctuation.definition.annotation-arguments.begin.bracket.round.java\"\n            }\n          },\n          \"end\": \"\\\\)\",\n          \"endCaptures\": {\n            \"0\": {\n              \"name\": \"punctuation.definition.annotation-arguments.end.bracket.round.java\"\n            }\n          },\n          \"name\": \"meta.declaration.annotation.java\",\n          \"patterns\": [\n            {\n              \"captures\": {\n                \"1\": {\n                  \"name\": \"constant.other.key.java\"\n                },\n                \"2\": {\n                  \"name\": \"keyword.operator.assignment.java\"\n                }\n              },\n              \"match\": \"(\\\\w*)\\\\s*(=)\"\n            },\n            {\n              \"include\": \"#code\"\n            }\n          ]\n        },\n        {\n          \"match\": \"(@)(interface)\\\\s+(\\\\w*)|((@)\\\\s*(\\\\w+))\",\n          \"name\": \"meta.declaration.annotation.java\",\n          \"captures\": {\n            \"1\": {\n              \"name\": \"punctuation.definition.annotation.java\"\n            },\n            \"2\": {\n              \"name\": \"storage.modifier.java\"\n            },\n            \"3\": {\n              \"name\": \"storage.type.annotation.java\"\n            },\n            \"5\": {\n              \"name\": \"punctuation.definition.annotation.java\"\n            },\n            \"6\": {\n              \"name\": \"storage.type.annotation.java\"\n            }\n          }\n        }\n      ]\n    },\n    \"anonymous-block-and-instance-initializer\": {\n      \"begin\": \"{\",\n      \"beginCaptures\": {\n        \"0\": {\n          \"name\": \"punctuation.section.block.begin.bracket.curly.java\"\n        }\n      },\n      \"end\": \"}\",\n      \"endCaptures\": {\n        \"0\": {\n          \"name\": \"punctuation.section.block.end.bracket.curly.java\"\n        }\n      },\n      \"patterns\": [\n        {\n          \"include\": \"#code\"\n        }\n      ]\n    },\n    \"anonymous-classes-and-new\": {\n      \"begin\": \"\\\\bnew\\\\b\",\n      \"beginCaptures\": {\n        \"0\": {\n          \"name\": \"keyword.control.new.java\"\n        }\n      },\n      \"end\": \"(?=;|\\\\)|\\\\]|\\\\.|,|\\\\?|:|}|\\\\+|\\\\-|\\\\*|\\\\/(?!\\\\/|\\\\*)|%|!|&|\\\\||\\\\^|=)\",\n      \"patterns\": [\n        {\n          \"include\": \"#comments\"\n        },\n        {\n          \"include\": \"#function-call\"\n        },\n        {\n          \"include\": \"#all-types\"\n        },\n        {\n          \"begin\": \"(?<=\\\\))\",\n          \"end\": \"(?=;|\\\\)|\\\\]|\\\\.|,|\\\\?|:|}|\\\\+|\\\\-|\\\\*|\\\\/(?!\\\\/|\\\\*)|%|!|&|\\\\||\\\\^|=)\",\n          \"patterns\": [\n            {\n              \"include\": \"#comments\"\n            },\n            {\n              \"begin\": \"{\",\n              \"beginCaptures\": {\n                \"0\": {\n                  \"name\": \"punctuation.section.inner-class.begin.bracket.curly.java\"\n                }\n              },\n              \"end\": \"}\",\n              \"endCaptures\": {\n                \"0\": {\n                  \"name\": \"punctuation.section.inner-class.end.bracket.curly.java\"\n                }\n              },\n              \"name\": \"meta.inner-class.java\",\n              \"patterns\": [\n                {\n                  \"include\": \"#class-body\"\n                }\n              ]\n            }\n          ]\n        },\n        {\n          \"begin\": \"(?<=\\\\])\",\n          \"end\": \"(?=;|\\\\)|\\\\]|\\\\.|,|\\\\?|:|}|\\\\+|\\\\-|\\\\*|\\\\/(?!\\\\/|\\\\*)|%|!|&|\\\\||\\\\^|=)\",\n          \"patterns\": [\n            {\n              \"include\": \"#comments\"\n            },\n            {\n              \"begin\": \"{\",\n              \"beginCaptures\": {\n                \"0\": {\n                  \"name\": \"punctuation.section.array-initializer.begin.bracket.curly.java\"\n                }\n              },\n              \"end\": \"}\",\n              \"endCaptures\": {\n                \"0\": {\n                  \"name\": \"punctuation.section.array-initializer.end.bracket.curly.java\"\n                }\n              },\n              \"name\": \"meta.array-initializer.java\",\n              \"patterns\": [\n                {\n                  \"include\": \"#code\"\n                }\n              ]\n            }\n          ]\n        },\n        {\n          \"include\": \"#parens\"\n        }\n      ]\n    },\n    \"assertions\": {\n      \"patterns\": [\n        {\n          \"begin\": \"\\\\b(assert)\\\\s\",\n          \"beginCaptures\": {\n            \"1\": {\n              \"name\": \"keyword.control.assert.java\"\n            }\n          },\n          \"end\": \"$\",\n          \"name\": \"meta.declaration.assertion.java\",\n          \"patterns\": [\n            {\n              \"match\": \":\",\n              \"name\": \"keyword.operator.assert.expression-separator.java\"\n            },\n            {\n              \"include\": \"#code\"\n            }\n          ]\n        }\n      ]\n    },\n    \"class\": {\n      \"begin\": \"(?=\\\\w?[\\\\w\\\\s-]*\\\\b(?:class|(?<!@)interface|enum)\\\\s+[\\\\w$]+)\",\n      \"end\": \"}\",\n      \"endCaptures\": {\n        \"0\": {\n          \"name\": \"punctuation.section.class.end.bracket.curly.java\"\n        }\n      },\n      \"name\": \"meta.class.java\",\n      \"patterns\": [\n        {\n          \"include\": \"#storage-modifiers\"\n        },\n        {\n          \"include\": \"#generics\"\n        },\n        {\n          \"include\": \"#comments\"\n        },\n        {\n          \"captures\": {\n            \"1\": {\n              \"name\": \"storage.modifier.java\"\n            },\n            \"2\": {\n              \"name\": \"entity.name.type.class.java\"\n            }\n          },\n          \"match\": \"(class|(?<!@)interface|enum)\\\\s+([\\\\w$]+)\",\n          \"name\": \"meta.class.identifier.java\"\n        },\n        {\n          \"begin\": \"extends\",\n          \"beginCaptures\": {\n            \"0\": {\n              \"name\": \"storage.modifier.extends.java\"\n            }\n          },\n          \"end\": \"(?={|implements|permits)\",\n          \"name\": \"meta.definition.class.inherited.classes.java\",\n          \"patterns\": [\n            {\n              \"include\": \"#object-types-inherited\"\n            },\n            {\n              \"include\": \"#comments\"\n            }\n          ]\n        },\n        {\n          \"begin\": \"(implements)\\\\s\",\n          \"beginCaptures\": {\n            \"1\": {\n              \"name\": \"storage.modifier.implements.java\"\n            }\n          },\n          \"end\": \"(?=\\\\s*extends|permits|\\\\{)\",\n          \"name\": \"meta.definition.class.implemented.interfaces.java\",\n          \"patterns\": [\n            {\n              \"include\": \"#object-types-inherited\"\n            },\n            {\n              \"include\": \"#comments\"\n            }\n          ]\n        },\n        {\n          \"begin\": \"(permits)\\\\s\",\n          \"beginCaptures\": {\n            \"1\": {\n              \"name\": \"storage.modifier.permits.java\"\n            }\n          },\n          \"end\": \"(?=\\\\s*extends|implements|\\\\{)\",\n          \"name\": \"meta.definition.class.permits.classes.java\",\n          \"patterns\": [\n            {\n              \"include\": \"#object-types-inherited\"\n            },\n            {\n              \"include\": \"#comments\"\n            }\n          ]\n        },\n        {\n          \"begin\": \"{\",\n          \"beginCaptures\": {\n            \"0\": {\n              \"name\": \"punctuation.section.class.begin.bracket.curly.java\"\n            }\n          },\n          \"end\": \"(?=})\",\n          \"contentName\": \"meta.class.body.java\",\n          \"patterns\": [\n            {\n              \"include\": \"#class-body\"\n            }\n          ]\n        }\n      ]\n    },\n    \"class-body\": {\n      \"patterns\": [\n        {\n          \"include\": \"#comments-javadoc\"\n        },\n        {\n          \"include\": \"#comments\"\n        },\n        {\n          \"include\": \"#enums\"\n        },\n        {\n          \"include\": \"#class\"\n        },\n        {\n          \"include\": \"#generics\"\n        },\n        {\n          \"include\": \"#static-initializer\"\n        },\n        {\n          \"include\": \"#class-fields-and-methods\"\n        },\n        {\n          \"include\": \"#annotations\"\n        },\n        {\n          \"include\": \"#storage-modifiers\"\n        },\n        {\n          \"include\": \"#member-variables\"\n        },\n        {\n          \"include\": \"#code\"\n        }\n      ]\n    },\n    \"class-fields-and-methods\": {\n      \"patterns\": [\n        {\n          \"begin\": \"(?=\\\\=)\",\n          \"end\": \"(?=;)\",\n          \"patterns\": [\n            {\n              \"include\": \"#code\"\n            }\n          ]\n        },\n        {\n          \"include\": \"#methods\"\n        }\n      ]\n    },\n    \"code\": {\n      \"patterns\": [\n        {\n          \"include\": \"#annotations\"\n        },\n        {\n          \"include\": \"#comments\"\n        },\n        {\n          \"include\": \"#enums\"\n        },\n        {\n          \"include\": \"#class\"\n        },\n        {\n          \"include\": \"#record\"\n        },\n        {\n          \"include\": \"#anonymous-block-and-instance-initializer\"\n        },\n        {\n          \"include\": \"#try-catch-finally\"\n        },\n        {\n          \"include\": \"#assertions\"\n        },\n        {\n          \"include\": \"#parens\"\n        },\n        {\n          \"include\": \"#constants-and-special-vars\"\n        },\n        {\n          \"include\": \"#numbers\"\n        },\n        {\n          \"include\": \"#anonymous-classes-and-new\"\n        },\n        {\n          \"include\": \"#lambda-expression\"\n        },\n        {\n          \"include\": \"#keywords\"\n        },\n        {\n          \"include\": \"#storage-modifiers\"\n        },\n        {\n          \"include\": \"#method-call\"\n        },\n        {\n          \"include\": \"#function-call\"\n        },\n        {\n          \"include\": \"#variables\"\n        },\n        {\n          \"include\": \"#variables-local\"\n        },\n        {\n          \"include\": \"#objects\"\n        },\n        {\n          \"include\": \"#properties\"\n        },\n        {\n          \"include\": \"#strings\"\n        },\n        {\n          \"include\": \"#all-types\"\n        },\n        {\n          \"match\": \",\",\n          \"name\": \"punctuation.separator.delimiter.java\"\n        },\n        {\n          \"match\": \"\\\\.\",\n          \"name\": \"punctuation.separator.period.java\"\n        },\n        {\n          \"match\": \";\",\n          \"name\": \"punctuation.terminator.java\"\n        }\n      ]\n    },\n    \"comments\": {\n      \"patterns\": [\n        {\n          \"captures\": {\n            \"0\": {\n              \"name\": \"punctuation.definition.comment.java\"\n            }\n          },\n          \"match\": \"/\\\\*\\\\*/\",\n          \"name\": \"comment.block.empty.java\"\n        },\n        {\n          \"include\": \"#comments-inline\"\n        }\n      ]\n    },\n    \"comments-inline\": {\n      \"patterns\": [\n        {\n          \"begin\": \"/\\\\*\",\n          \"captures\": {\n            \"0\": {\n              \"name\": \"punctuation.definition.comment.java\"\n            }\n          },\n          \"end\": \"\\\\*/\",\n          \"name\": \"comment.block.java\"\n        },\n        {\n          \"begin\": \"(^[ \\\\t]+)?(?=//)\",\n          \"beginCaptures\": {\n            \"1\": {\n              \"name\": \"punctuation.whitespace.comment.leading.java\"\n            }\n          },\n          \"end\": \"(?!\\\\G)\",\n          \"patterns\": [\n            {\n              \"begin\": \"//\",\n              \"beginCaptures\": {\n                \"0\": {\n                  \"name\": \"punctuation.definition.comment.java\"\n                }\n              },\n              \"end\": \"\\\\n\",\n              \"name\": \"comment.line.double-slash.java\"\n            }\n          ]\n        }\n      ]\n    },\n    \"comments-javadoc\": {\n      \"patterns\": [\n        {\n          \"begin\": \"^\\\\s*(/\\\\*\\\\*)(?!/)\",\n          \"beginCaptures\": {\n            \"1\": {\n              \"name\": \"punctuation.definition.comment.java\"\n            }\n          },\n          \"end\": \"\\\\*/\",\n          \"endCaptures\": {\n            \"0\": {\n              \"name\": \"punctuation.definition.comment.java\"\n            }\n          },\n          \"name\": \"comment.block.javadoc.java\",\n          \"patterns\": [\n            {\n              \"match\": \"@(author|deprecated|return|see|serial|since|version)\\\\b\",\n              \"name\": \"keyword.other.documentation.javadoc.java\"\n            },\n            {\n              \"match\": \"(@param)\\\\s+(\\\\S+)\",\n              \"captures\": {\n                \"1\": {\n                  \"name\": \"keyword.other.documentation.javadoc.java\"\n                },\n                \"2\": {\n                  \"name\": \"variable.parameter.java\"\n                }\n              }\n            },\n            {\n              \"match\": \"(@(?:exception|throws))\\\\s+(\\\\S+)\",\n              \"captures\": {\n                \"1\": {\n                  \"name\": \"keyword.other.documentation.javadoc.java\"\n                },\n                \"2\": {\n                  \"name\": \"entity.name.type.class.java\"\n                }\n              }\n            },\n            {\n              \"match\": \"{(@link)\\\\s+(\\\\S+)?#([\\\\w$]+\\\\s*\\\\([^\\\\(\\\\)]*\\\\)).*?}\",\n              \"captures\": {\n                \"1\": {\n                  \"name\": \"keyword.other.documentation.javadoc.java\"\n                },\n                \"2\": {\n                  \"name\": \"entity.name.type.class.java\"\n                },\n                \"3\": {\n                  \"name\": \"variable.parameter.java\"\n                }\n              }\n            }\n          ]\n        }\n      ]\n    },\n    \"constants-and-special-vars\": {\n      \"patterns\": [\n        {\n          \"match\": \"\\\\b(true|false|null)\\\\b\",\n          \"name\": \"constant.language.java\"\n        },\n        {\n          \"match\": \"\\\\bthis\\\\b\",\n          \"name\": \"variable.language.this.java\"\n        },\n        {\n          \"match\": \"\\\\bsuper\\\\b\",\n          \"name\": \"variable.language.java\"\n        }\n      ]\n    },\n    \"enums\": {\n      \"begin\": \"^\\\\s*([\\\\w\\\\s]*)(enum)\\\\s+(\\\\w+)\",\n      \"beginCaptures\": {\n        \"1\": {\n          \"patterns\": [\n            {\n              \"include\": \"#storage-modifiers\"\n            }\n          ]\n        },\n        \"2\": {\n          \"name\": \"storage.modifier.java\"\n        },\n        \"3\": {\n          \"name\": \"entity.name.type.enum.java\"\n        }\n      },\n      \"end\": \"}\",\n      \"endCaptures\": {\n        \"0\": {\n          \"name\": \"punctuation.section.enum.end.bracket.curly.java\"\n        }\n      },\n      \"name\": \"meta.enum.java\",\n      \"patterns\": [\n        {\n          \"begin\": \"\\\\b(extends)\\\\b\",\n          \"beginCaptures\": {\n            \"1\": {\n              \"name\": \"storage.modifier.extends.java\"\n            }\n          },\n          \"end\": \"(?={|\\\\bimplements\\\\b)\",\n          \"name\": \"meta.definition.class.inherited.classes.java\",\n          \"patterns\": [\n            {\n              \"include\": \"#object-types-inherited\"\n            },\n            {\n              \"include\": \"#comments\"\n            }\n          ]\n        },\n        {\n          \"begin\": \"\\\\b(implements)\\\\b\",\n          \"beginCaptures\": {\n            \"1\": {\n              \"name\": \"storage.modifier.implements.java\"\n            }\n          },\n          \"end\": \"(?={|\\\\bextends\\\\b)\",\n          \"name\": \"meta.definition.class.implemented.interfaces.java\",\n          \"patterns\": [\n            {\n              \"include\": \"#object-types-inherited\"\n            },\n            {\n              \"include\": \"#comments\"\n            }\n          ]\n        },\n        {\n          \"begin\": \"{\",\n          \"beginCaptures\": {\n            \"0\": {\n              \"name\": \"punctuation.section.enum.begin.bracket.curly.java\"\n            }\n          },\n          \"end\": \"(?=})\",\n          \"patterns\": [\n            {\n              \"begin\": \"(?<={)\",\n              \"end\": \"(?=;|})\",\n              \"patterns\": [\n                {\n                  \"include\": \"#comments-javadoc\"\n                },\n                {\n                  \"include\": \"#comments\"\n                },\n                {\n                  \"begin\": \"\\\\b(\\\\w+)\\\\b\",\n                  \"beginCaptures\": {\n                    \"1\": {\n                      \"name\": \"constant.other.enum.java\"\n                    }\n                  },\n                  \"end\": \"(,)|(?=;|})\",\n                  \"endCaptures\": {\n                    \"1\": {\n                      \"name\": \"punctuation.separator.delimiter.java\"\n                    }\n                  },\n                  \"patterns\": [\n                    {\n                      \"include\": \"#comments-javadoc\"\n                    },\n                    {\n                      \"include\": \"#comments\"\n                    },\n                    {\n                      \"begin\": \"\\\\(\",\n                      \"beginCaptures\": {\n                        \"0\": {\n                          \"name\": \"punctuation.bracket.round.java\"\n                        }\n                      },\n                      \"end\": \"\\\\)\",\n                      \"endCaptures\": {\n                        \"0\": {\n                          \"name\": \"punctuation.bracket.round.java\"\n                        }\n                      },\n                      \"patterns\": [\n                        {\n                          \"include\": \"#code\"\n                        }\n                      ]\n                    },\n                    {\n                      \"begin\": \"{\",\n                      \"beginCaptures\": {\n                        \"0\": {\n                          \"name\": \"punctuation.bracket.curly.java\"\n                        }\n                      },\n                      \"end\": \"}\",\n                      \"endCaptures\": {\n                        \"0\": {\n                          \"name\": \"punctuation.bracket.curly.java\"\n                        }\n                      },\n                      \"patterns\": [\n                        {\n                          \"include\": \"#class-body\"\n                        }\n                      ]\n                    }\n                  ]\n                }\n              ]\n            },\n            {\n              \"include\": \"#class-body\"\n            }\n          ]\n        }\n      ]\n    },\n    \"function-call\": {\n      \"begin\": \"([A-Za-z_$][\\\\w$]*)\\\\s*(\\\\()\",\n      \"beginCaptures\": {\n        \"1\": {\n          \"name\": \"entity.name.function.java\"\n        },\n        \"2\": {\n          \"name\": \"punctuation.definition.parameters.begin.bracket.round.java\"\n        }\n      },\n      \"end\": \"\\\\)\",\n      \"endCaptures\": {\n        \"0\": {\n          \"name\": \"punctuation.definition.parameters.end.bracket.round.java\"\n        }\n      },\n      \"name\": \"meta.function-call.java\",\n      \"patterns\": [\n        {\n          \"include\": \"#code\"\n        }\n      ]\n    },\n    \"generics\": {\n      \"begin\": \"<\",\n      \"beginCaptures\": {\n        \"0\": {\n          \"name\": \"punctuation.bracket.angle.java\"\n        }\n      },\n      \"end\": \">\",\n      \"endCaptures\": {\n        \"0\": {\n          \"name\": \"punctuation.bracket.angle.java\"\n        }\n      },\n      \"patterns\": [\n        {\n          \"match\": \"\\\\b(extends|super)\\\\b\",\n          \"name\": \"storage.modifier.$1.java\"\n        },\n        {\n          \"match\": \"(?<!\\\\.)([a-zA-Z$_][a-zA-Z0-9$_]*)(?=\\\\s*<)\",\n          \"captures\": {\n            \"1\": {\n              \"name\": \"storage.type.java\"\n            }\n          }\n        },\n        {\n          \"include\": \"#primitive-arrays\"\n        },\n        {\n          \"match\": \"[a-zA-Z$_][a-zA-Z0-9$_]*\",\n          \"name\": \"storage.type.generic.java\"\n        },\n        {\n          \"match\": \"\\\\?\",\n          \"name\": \"storage.type.generic.wildcard.java\"\n        },\n        {\n          \"match\": \"&\",\n          \"name\": \"punctuation.separator.types.java\"\n        },\n        {\n          \"match\": \",\",\n          \"name\": \"punctuation.separator.delimiter.java\"\n        },\n        {\n          \"match\": \"\\\\.\",\n          \"name\": \"punctuation.separator.period.java\"\n        },\n        {\n          \"include\": \"#parens\"\n        },\n        {\n          \"include\": \"#generics\"\n        },\n        {\n          \"include\": \"#comments\"\n        }\n      ]\n    },\n    \"keywords\": {\n      \"patterns\": [\n        {\n          \"match\": \"\\\\bthrow\\\\b\",\n          \"name\": \"keyword.control.throw.java\"\n        },\n        {\n          \"match\": \"\\\\?|:\",\n          \"name\": \"keyword.control.ternary.java\"\n        },\n        {\n          \"match\": \"\\\\b(return|yield|break|case|continue|default|do|while|for|switch|if|else)\\\\b\",\n          \"name\": \"keyword.control.java\"\n        },\n        {\n          \"match\": \"\\\\b(instanceof)\\\\b\",\n          \"name\": \"keyword.operator.instanceof.java\"\n        },\n        {\n          \"match\": \"(<<|>>>?|~|\\\\^)\",\n          \"name\": \"keyword.operator.bitwise.java\"\n        },\n        {\n          \"match\": \"((&|\\\\^|\\\\||<<|>>>?)=)\",\n          \"name\": \"keyword.operator.assignment.bitwise.java\"\n        },\n        {\n          \"match\": \"(===?|!=|<=|>=|<>|<|>)\",\n          \"name\": \"keyword.operator.comparison.java\"\n        },\n        {\n          \"match\": \"([+*/%-]=)\",\n          \"name\": \"keyword.operator.assignment.arithmetic.java\"\n        },\n        {\n          \"match\": \"(=)\",\n          \"name\": \"keyword.operator.assignment.java\"\n        },\n        {\n          \"match\": \"(\\\\-\\\\-|\\\\+\\\\+)\",\n          \"name\": \"keyword.operator.increment-decrement.java\"\n        },\n        {\n          \"match\": \"(\\\\-|\\\\+|\\\\*|\\\\/|%)\",\n          \"name\": \"keyword.operator.arithmetic.java\"\n        },\n        {\n          \"match\": \"(!|&&|\\\\|\\\\|)\",\n          \"name\": \"keyword.operator.logical.java\"\n        },\n        {\n          \"match\": \"(\\\\||&)\",\n          \"name\": \"keyword.operator.bitwise.java\"\n        },\n        {\n          \"match\": \"\\\\b(const|goto)\\\\b\",\n          \"name\": \"keyword.reserved.java\"\n        }\n      ]\n    },\n    \"lambda-expression\": {\n      \"patterns\": [\n        {\n          \"match\": \"->\",\n          \"name\": \"storage.type.function.arrow.java\"\n        }\n      ]\n    },\n    \"member-variables\": {\n      \"begin\": \"(?=private|protected|public|native|synchronized|abstract|threadsafe|transient|static|final)\",\n      \"end\": \"(?=\\\\=|;)\",\n      \"patterns\": [\n        {\n          \"include\": \"#storage-modifiers\"\n        },\n        {\n          \"include\": \"#variables\"\n        },\n        {\n          \"include\": \"#primitive-arrays\"\n        },\n        {\n          \"include\": \"#object-types\"\n        }\n      ]\n    },\n    \"method-call\": {\n      \"begin\": \"(\\\\.)\\\\s*([A-Za-z_$][\\\\w$]*)\\\\s*(\\\\()\",\n      \"beginCaptures\": {\n        \"1\": {\n          \"name\": \"punctuation.separator.period.java\"\n        },\n        \"2\": {\n          \"name\": \"entity.name.function.java\"\n        },\n        \"3\": {\n          \"name\": \"punctuation.definition.parameters.begin.bracket.round.java\"\n        }\n      },\n      \"end\": \"\\\\)\",\n      \"endCaptures\": {\n        \"0\": {\n          \"name\": \"punctuation.definition.parameters.end.bracket.round.java\"\n        }\n      },\n      \"name\": \"meta.method-call.java\",\n      \"patterns\": [\n        {\n          \"include\": \"#code\"\n        }\n      ]\n    },\n    \"methods\": {\n      \"begin\": \"(?!new)(?=[\\\\w<].*\\\\s+)(?=([^=/]|/(?!/))+\\\\()\",\n      \"end\": \"(})|(?=;)\",\n      \"endCaptures\": {\n        \"1\": {\n          \"name\": \"punctuation.section.method.end.bracket.curly.java\"\n        }\n      },\n      \"name\": \"meta.method.java\",\n      \"patterns\": [\n        {\n          \"include\": \"#storage-modifiers\"\n        },\n        {\n          \"begin\": \"(\\\\w+)\\\\s*(\\\\()\",\n          \"beginCaptures\": {\n            \"1\": {\n              \"name\": \"entity.name.function.java\"\n            },\n            \"2\": {\n              \"name\": \"punctuation.definition.parameters.begin.bracket.round.java\"\n            }\n          },\n          \"end\": \"\\\\)\",\n          \"endCaptures\": {\n            \"0\": {\n              \"name\": \"punctuation.definition.parameters.end.bracket.round.java\"\n            }\n          },\n          \"name\": \"meta.method.identifier.java\",\n          \"patterns\": [\n            {\n              \"include\": \"#parameters\"\n            },\n            {\n              \"include\": \"#parens\"\n            },\n            {\n              \"include\": \"#comments\"\n            }\n          ]\n        },\n        {\n          \"include\": \"#generics\"\n        },\n        {\n          \"begin\": \"(?=\\\\w.*\\\\s+\\\\w+\\\\s*\\\\()\",\n          \"end\": \"(?=\\\\s+\\\\w+\\\\s*\\\\()\",\n          \"name\": \"meta.method.return-type.java\",\n          \"patterns\": [\n            {\n              \"include\": \"#all-types\"\n            },\n            {\n              \"include\": \"#parens\"\n            },\n            {\n              \"include\": \"#comments\"\n            }\n          ]\n        },\n        {\n          \"include\": \"#throws\"\n        },\n        {\n          \"begin\": \"{\",\n          \"beginCaptures\": {\n            \"0\": {\n              \"name\": \"punctuation.section.method.begin.bracket.curly.java\"\n            }\n          },\n          \"end\": \"(?=})\",\n          \"contentName\": \"meta.method.body.java\",\n          \"patterns\": [\n            {\n              \"include\": \"#code\"\n            }\n          ]\n        },\n        {\n          \"include\": \"#comments\"\n        }\n      ]\n    },\n    \"module\": {\n      \"begin\": \"((open)\\\\s)?(module)\\\\s+(\\\\w+)\",\n      \"end\": \"}\",\n      \"beginCaptures\": {\n        \"1\": {\n          \"name\": \"storage.modifier.java\"\n        },\n        \"3\": {\n          \"name\": \"storage.modifier.java\"\n        },\n        \"4\": {\n          \"name\": \"entity.name.type.module.java\"\n        }\n      },\n      \"endCaptures\": {\n        \"0\": {\n          \"name\": \"punctuation.section.module.end.bracket.curly.java\"\n        }\n      },\n      \"name\": \"meta.module.java\",\n      \"patterns\": [\n        {\n          \"begin\": \"{\",\n          \"beginCaptures\": {\n            \"0\": {\n              \"name\": \"punctuation.section.module.begin.bracket.curly.java\"\n            }\n          },\n          \"end\": \"(?=})\",\n          \"contentName\": \"meta.module.body.java\",\n          \"patterns\": [\n            {\n              \"include\": \"#comments\"\n            },\n            {\n              \"include\": \"#comments-javadoc\"\n            },\n            {\n              \"match\": \"\\\\b(requires|transitive|exports|opens|to|uses|provides|with)\\\\b\",\n              \"name\": \"keyword.module.java\"\n            }\n          ]\n        }\n      ]\n    },\n    \"numbers\": {\n      \"patterns\": [\n        {\n          \"match\": \"(?x)\\n\\\\b(?<!\\\\$)\\n0(x|X)\\n(\\n  (?<!\\\\.)[0-9a-fA-F]([0-9a-fA-F_]*[0-9a-fA-F])?[Ll]?(?!\\\\.)\\n  |\\n  (\\n    [0-9a-fA-F]([0-9a-fA-F_]*[0-9a-fA-F])?\\\\.?\\n    |\\n    ([0-9a-fA-F]([0-9a-fA-F_]*[0-9a-fA-F])?)?\\\\.[0-9a-fA-F]([0-9a-fA-F_]*[0-9a-fA-F])?\\n  )\\n  [Pp][+-]?[0-9]([0-9_]*[0-9])?[FfDd]?\\n)\\n\\\\b(?!\\\\$)\",\n          \"name\": \"constant.numeric.hex.java\"\n        },\n        {\n          \"match\": \"\\\\b(?<!\\\\$)0(b|B)[01]([01_]*[01])?[Ll]?\\\\b(?!\\\\$)\",\n          \"name\": \"constant.numeric.binary.java\"\n        },\n        {\n          \"match\": \"\\\\b(?<!\\\\$)0[0-7]([0-7_]*[0-7])?[Ll]?\\\\b(?!\\\\$)\",\n          \"name\": \"constant.numeric.octal.java\"\n        },\n        {\n          \"match\": \"(?x)\\n(?<!\\\\$)\\n(\\n  \\\\b[0-9]([0-9_]*[0-9])?\\\\.\\\\B(?!\\\\.)\\n  |\\n  \\\\b[0-9]([0-9_]*[0-9])?\\\\.([Ee][+-]?[0-9]([0-9_]*[0-9])?)[FfDd]?\\\\b\\n  |\\n  \\\\b[0-9]([0-9_]*[0-9])?\\\\.([Ee][+-]?[0-9]([0-9_]*[0-9])?)?[FfDd]\\\\b\\n  |\\n  \\\\b[0-9]([0-9_]*[0-9])?\\\\.([0-9]([0-9_]*[0-9])?)([Ee][+-]?[0-9]([0-9_]*[0-9])?)?[FfDd]?\\\\b\\n  |\\n  (?<!\\\\.)\\\\B\\\\.[0-9]([0-9_]*[0-9])?([Ee][+-]?[0-9]([0-9_]*[0-9])?)?[FfDd]?\\\\b\\n  |\\n  \\\\b[0-9]([0-9_]*[0-9])?([Ee][+-]?[0-9]([0-9_]*[0-9])?)[FfDd]?\\\\b\\n  |\\n  \\\\b[0-9]([0-9_]*[0-9])?([Ee][+-]?[0-9]([0-9_]*[0-9])?)?[FfDd]\\\\b\\n  |\\n  \\\\b(0|[1-9]([0-9_]*[0-9])?)(?!\\\\.)[Ll]?\\\\b\\n)\\n(?!\\\\$)\",\n          \"name\": \"constant.numeric.decimal.java\"\n        }\n      ]\n    },\n    \"object-types\": {\n      \"patterns\": [\n        {\n          \"include\": \"#generics\"\n        },\n        {\n          \"begin\": \"\\\\b((?:[A-Za-z_]\\\\w*\\\\s*\\\\.\\\\s*)*)([A-Z_]\\\\w*)\\\\s*(?=\\\\[)\",\n          \"beginCaptures\": {\n            \"1\": {\n              \"patterns\": [\n                {\n                  \"match\": \"[A-Za-z_]\\\\w*\",\n                  \"name\": \"storage.type.java\"\n                },\n                {\n                  \"match\": \"\\\\.\",\n                  \"name\": \"punctuation.separator.period.java\"\n                }\n              ]\n            },\n            \"2\": {\n              \"name\": \"storage.type.object.array.java\"\n            }\n          },\n          \"end\": \"(?!\\\\s*\\\\[)\",\n          \"patterns\": [\n            {\n              \"include\": \"#comments\"\n            },\n            {\n              \"include\": \"#parens\"\n            }\n          ]\n        },\n        {\n          \"match\": \"\\\\b((?:[A-Za-z_]\\\\w*\\\\s*\\\\.\\\\s*)*[A-Z_]\\\\w*)\\\\s*(?=<)\",\n          \"captures\": {\n            \"1\": {\n              \"patterns\": [\n                {\n                  \"match\": \"[A-Za-z_]\\\\w*\",\n                  \"name\": \"storage.type.java\"\n                },\n                {\n                  \"match\": \"\\\\.\",\n                  \"name\": \"punctuation.separator.period.java\"\n                }\n              ]\n            }\n          }\n        },\n        {\n          \"match\": \"\\\\b((?:[A-Za-z_]\\\\w*\\\\s*\\\\.\\\\s*)*[A-Z_]\\\\w*)\\\\b((?=\\\\s*[A-Za-z$_\\\\n])|(?=\\\\s*\\\\.\\\\.\\\\.))\",\n          \"captures\": {\n            \"1\": {\n              \"patterns\": [\n                {\n                  \"match\": \"[A-Za-z_]\\\\w*\",\n                  \"name\": \"storage.type.java\"\n                },\n                {\n                  \"match\": \"\\\\.\",\n                  \"name\": \"punctuation.separator.period.java\"\n                }\n              ]\n            }\n          }\n        }\n      ]\n    },\n    \"object-types-inherited\": {\n      \"patterns\": [\n        {\n          \"include\": \"#generics\"\n        },\n        {\n          \"match\": \"\\\\b(?:[A-Z]\\\\w*\\\\s*(\\\\.)\\\\s*)*[A-Z]\\\\w*\\\\b\",\n          \"name\": \"entity.other.inherited-class.java\",\n          \"captures\": {\n            \"1\": {\n              \"name\": \"punctuation.separator.period.java\"\n            }\n          }\n        },\n        {\n          \"match\": \",\",\n          \"name\": \"punctuation.separator.delimiter.java\"\n        }\n      ]\n    },\n    \"objects\": {\n      \"match\": \"(?<![\\\\w$])[a-zA-Z_$][\\\\w$]*(?=\\\\s*\\\\.\\\\s*[\\\\w$]+)\",\n      \"name\": \"variable.other.object.java\"\n    },\n    \"parameters\": {\n      \"patterns\": [\n        {\n          \"match\": \"\\\\bfinal\\\\b\",\n          \"name\": \"storage.modifier.java\"\n        },\n        {\n          \"include\": \"#annotations\"\n        },\n        {\n          \"include\": \"#all-types\"\n        },\n        {\n          \"include\": \"#strings\"\n        },\n        {\n          \"match\": \"\\\\w+\",\n          \"name\": \"variable.parameter.java\"\n        },\n        {\n          \"match\": \",\",\n          \"name\": \"punctuation.separator.delimiter.java\"\n        },\n        {\n          \"match\": \"\\\\.\\\\.\\\\.\",\n          \"name\": \"punctuation.definition.parameters.varargs.java\"\n        }\n      ]\n    },\n    \"parens\": {\n      \"patterns\": [\n        {\n          \"begin\": \"\\\\(\",\n          \"beginCaptures\": {\n            \"0\": {\n              \"name\": \"punctuation.bracket.round.java\"\n            }\n          },\n          \"end\": \"\\\\)\",\n          \"endCaptures\": {\n            \"0\": {\n              \"name\": \"punctuation.bracket.round.java\"\n            }\n          },\n          \"patterns\": [\n            {\n              \"include\": \"#code\"\n            }\n          ]\n        },\n        {\n          \"begin\": \"\\\\[\",\n          \"beginCaptures\": {\n            \"0\": {\n              \"name\": \"punctuation.bracket.square.java\"\n            }\n          },\n          \"end\": \"\\\\]\",\n          \"endCaptures\": {\n            \"0\": {\n              \"name\": \"punctuation.bracket.square.java\"\n            }\n          },\n          \"patterns\": [\n            {\n              \"include\": \"#code\"\n            }\n          ]\n        },\n        {\n          \"begin\": \"{\",\n          \"beginCaptures\": {\n            \"0\": {\n              \"name\": \"punctuation.bracket.curly.java\"\n            }\n          },\n          \"end\": \"}\",\n          \"endCaptures\": {\n            \"0\": {\n              \"name\": \"punctuation.bracket.curly.java\"\n            }\n          },\n          \"patterns\": [\n            {\n              \"include\": \"#code\"\n            }\n          ]\n        }\n      ]\n    },\n    \"primitive-arrays\": {\n      \"patterns\": [\n        {\n          \"begin\": \"\\\\b(void|boolean|byte|char|short|int|float|long|double)\\\\b\\\\s*(?=\\\\[)\",\n          \"beginCaptures\": {\n            \"1\": {\n              \"name\": \"storage.type.primitive.array.java\"\n            }\n          },\n          \"end\": \"(?!\\\\s*\\\\[)\",\n          \"patterns\": [\n            {\n              \"include\": \"#comments\"\n            },\n            {\n              \"include\": \"#parens\"\n            }\n          ]\n        }\n      ]\n    },\n    \"primitive-types\": {\n      \"match\": \"\\\\b(void|boolean|byte|char|short|int|float|long|double)\\\\b\",\n      \"name\": \"storage.type.primitive.java\"\n    },\n    \"properties\": {\n      \"patterns\": [\n        {\n          \"match\": \"(\\\\.)\\\\s*([a-zA-Z_$][\\\\w$]*)(?=\\\\s*\\\\.\\\\s*[a-zA-Z_$][\\\\w$]*)\",\n          \"captures\": {\n            \"1\": {\n              \"name\": \"punctuation.separator.period.java\"\n            },\n            \"2\": {\n              \"name\": \"variable.other.object.property.java\"\n            }\n          }\n        },\n        {\n          \"match\": \"(\\\\.)\\\\s*([a-zA-Z_$][\\\\w$]*)\",\n          \"captures\": {\n            \"1\": {\n              \"name\": \"punctuation.separator.period.java\"\n            },\n            \"2\": {\n              \"name\": \"variable.other.object.property.java\"\n            }\n          }\n        },\n        {\n          \"match\": \"(\\\\.)\\\\s*([0-9][\\\\w$]*)\",\n          \"captures\": {\n            \"1\": {\n              \"name\": \"punctuation.separator.period.java\"\n            },\n            \"2\": {\n              \"name\": \"invalid.illegal.identifier.java\"\n            }\n          }\n        }\n      ]\n    },\n    \"record\": {\n      \"begin\": \"(?=\\\\w?[\\\\w\\\\s]*\\\\b(?:record)\\\\s+[\\\\w$]+)\",\n      \"end\": \"}\",\n      \"endCaptures\": {\n        \"0\": {\n          \"name\": \"punctuation.section.class.end.bracket.curly.java\"\n        }\n      },\n      \"name\": \"meta.record.java\",\n      \"patterns\": [\n        {\n          \"include\": \"#storage-modifiers\"\n        },\n        {\n          \"include\": \"#generics\"\n        },\n        {\n          \"include\": \"#comments\"\n        },\n        {\n          \"begin\": \"(record)\\\\s+([\\\\w$]+)(<[\\\\w$]+>)?(\\\\()\",\n          \"beginCaptures\": {\n            \"1\": {\n              \"name\": \"storage.modifier.java\"\n            },\n            \"2\": {\n              \"name\": \"entity.name.type.record.java\"\n            },\n            \"3\": {\n              \"patterns\": [\n                {\n                  \"include\": \"#generics\"\n                }\n              ]\n            },\n            \"4\": {\n              \"name\": \"punctuation.definition.parameters.begin.bracket.round.java\"\n            }\n          },\n          \"end\": \"\\\\)\",\n          \"endCaptures\": {\n            \"0\": {\n              \"name\": \"punctuation.definition.parameters.end.bracket.round.java\"\n            }\n          },\n          \"name\": \"meta.record.identifier.java\",\n          \"patterns\": [\n            {\n              \"include\": \"#code\"\n            }\n          ]\n        },\n        {\n          \"begin\": \"(implements)\\\\s\",\n          \"beginCaptures\": {\n            \"1\": {\n              \"name\": \"storage.modifier.implements.java\"\n            }\n          },\n          \"end\": \"(?=\\\\s*\\\\{)\",\n          \"name\": \"meta.definition.class.implemented.interfaces.java\",\n          \"patterns\": [\n            {\n              \"include\": \"#object-types-inherited\"\n            },\n            {\n              \"include\": \"#comments\"\n            }\n          ]\n        },\n        {\n          \"include\": \"#record-body\"\n        }\n      ]\n    },\n    \"record-body\": {\n      \"begin\": \"{\",\n      \"beginCaptures\": {\n        \"0\": {\n          \"name\": \"punctuation.section.class.begin.bracket.curly.java\"\n        }\n      },\n      \"end\": \"(?=})\",\n      \"name\": \"meta.record.body.java\",\n      \"patterns\": [\n        {\n          \"include\": \"#record-constructor\"\n        },\n        {\n          \"include\": \"#class-body\"\n        }\n      ]\n    },\n    \"record-constructor\": {\n      \"begin\": \"(?!new)(?=[\\\\w<].*\\\\s+)(?=([^\\\\(=/]|/(?!/))+(?={))\",\n      \"end\": \"(})|(?=;)\",\n      \"endCaptures\": {\n        \"1\": {\n          \"name\": \"punctuation.section.method.end.bracket.curly.java\"\n        }\n      },\n      \"name\": \"meta.method.java\",\n      \"patterns\": [\n        {\n          \"include\": \"#storage-modifiers\"\n        },\n        {\n          \"begin\": \"(\\\\w+)\",\n          \"beginCaptures\": {\n            \"1\": {\n              \"name\": \"entity.name.function.java\"\n            }\n          },\n          \"end\": \"(?=\\\\s*{)\",\n          \"name\": \"meta.method.identifier.java\",\n          \"patterns\": [\n            {\n              \"include\": \"#comments\"\n            }\n          ]\n        },\n        {\n          \"include\": \"#comments\"\n        },\n        {\n          \"begin\": \"{\",\n          \"beginCaptures\": {\n            \"0\": {\n              \"name\": \"punctuation.section.method.begin.bracket.curly.java\"\n            }\n          },\n          \"end\": \"(?=})\",\n          \"contentName\": \"meta.method.body.java\",\n          \"patterns\": [\n            {\n              \"include\": \"#code\"\n            }\n          ]\n        }\n      ]\n    },\n    \"static-initializer\": {\n      \"patterns\": [\n        {\n          \"include\": \"#anonymous-block-and-instance-initializer\"\n        },\n        {\n          \"match\": \"static\",\n          \"name\": \"storage.modifier.java\"\n        }\n      ]\n    },\n    \"storage-modifiers\": {\n      \"match\": \"\\\\b(public|private|protected|static|final|native|synchronized|abstract|threadsafe|transient|volatile|default|strictfp|sealed|non-sealed)\\\\b\",\n      \"name\": \"storage.modifier.java\"\n    },\n    \"strings\": {\n      \"patterns\": [\n        {\n          \"begin\": \"\\\"\",\n          \"beginCaptures\": {\n            \"0\": {\n              \"name\": \"punctuation.definition.string.begin.java\"\n            }\n          },\n          \"end\": \"\\\"\",\n          \"endCaptures\": {\n            \"0\": {\n              \"name\": \"punctuation.definition.string.end.java\"\n            }\n          },\n          \"name\": \"string.quoted.double.java\",\n          \"patterns\": [\n            {\n              \"match\": \"\\\\\\\\.\",\n              \"name\": \"constant.character.escape.java\"\n            }\n          ]\n        },\n        {\n          \"begin\": \"'\",\n          \"beginCaptures\": {\n            \"0\": {\n              \"name\": \"punctuation.definition.string.begin.java\"\n            }\n          },\n          \"end\": \"'\",\n          \"endCaptures\": {\n            \"0\": {\n              \"name\": \"punctuation.definition.string.end.java\"\n            }\n          },\n          \"name\": \"string.quoted.single.java\",\n          \"patterns\": [\n            {\n              \"match\": \"\\\\\\\\.\",\n              \"name\": \"constant.character.escape.java\"\n            }\n          ]\n        }\n      ]\n    },\n    \"throws\": {\n      \"begin\": \"throws\",\n      \"beginCaptures\": {\n        \"0\": {\n          \"name\": \"storage.modifier.java\"\n        }\n      },\n      \"end\": \"(?={|;)\",\n      \"name\": \"meta.throwables.java\",\n      \"patterns\": [\n        {\n          \"match\": \",\",\n          \"name\": \"punctuation.separator.delimiter.java\"\n        },\n        {\n          \"match\": \"[a-zA-Z$_][\\\\.a-zA-Z0-9$_]*\",\n          \"name\": \"storage.type.java\"\n        }\n      ]\n    },\n    \"try-catch-finally\": {\n      \"patterns\": [\n        {\n          \"begin\": \"\\\\btry\\\\b\",\n          \"beginCaptures\": {\n            \"0\": {\n              \"name\": \"keyword.control.try.java\"\n            }\n          },\n          \"end\": \"}\",\n          \"endCaptures\": {\n            \"0\": {\n              \"name\": \"punctuation.section.try.end.bracket.curly.java\"\n            }\n          },\n          \"name\": \"meta.try.java\",\n          \"patterns\": [\n            {\n              \"begin\": \"\\\\(\",\n              \"beginCaptures\": {\n                \"0\": {\n                  \"name\": \"punctuation.section.try.resources.begin.bracket.round.java\"\n                }\n              },\n              \"end\": \"\\\\)\",\n              \"endCaptures\": {\n                \"0\": {\n                  \"name\": \"punctuation.section.try.resources.end.bracket.round.java\"\n                }\n              },\n              \"name\": \"meta.try.resources.java\",\n              \"patterns\": [\n                {\n                  \"include\": \"#code\"\n                }\n              ]\n            },\n            {\n              \"begin\": \"{\",\n              \"beginCaptures\": {\n                \"0\": {\n                  \"name\": \"punctuation.section.try.begin.bracket.curly.java\"\n                }\n              },\n              \"end\": \"(?=})\",\n              \"contentName\": \"meta.try.body.java\",\n              \"patterns\": [\n                {\n                  \"include\": \"#code\"\n                }\n              ]\n            }\n          ]\n        },\n        {\n          \"begin\": \"\\\\b(catch)\\\\b\",\n          \"beginCaptures\": {\n            \"1\": {\n              \"name\": \"keyword.control.catch.java\"\n            }\n          },\n          \"end\": \"}\",\n          \"endCaptures\": {\n            \"0\": {\n              \"name\": \"punctuation.section.catch.end.bracket.curly.java\"\n            }\n          },\n          \"name\": \"meta.catch.java\",\n          \"patterns\": [\n            {\n              \"include\": \"#comments\"\n            },\n            {\n              \"begin\": \"\\\\(\",\n              \"beginCaptures\": {\n                \"0\": {\n                  \"name\": \"punctuation.definition.parameters.begin.bracket.round.java\"\n                }\n              },\n              \"end\": \"\\\\)\",\n              \"endCaptures\": {\n                \"0\": {\n                  \"name\": \"punctuation.definition.parameters.end.bracket.round.java\"\n                }\n              },\n              \"contentName\": \"meta.catch.parameters.java\",\n              \"patterns\": [\n                {\n                  \"include\": \"#comments\"\n                },\n                {\n                  \"include\": \"#storage-modifiers\"\n                },\n                {\n                  \"begin\": \"[a-zA-Z$_][\\\\.a-zA-Z0-9$_]*\",\n                  \"beginCaptures\": {\n                    \"0\": {\n                      \"name\": \"storage.type.java\"\n                    }\n                  },\n                  \"end\": \"(\\\\|)|(?=\\\\))\",\n                  \"endCaptures\": {\n                    \"1\": {\n                      \"name\": \"punctuation.catch.separator.java\"\n                    }\n                  },\n                  \"patterns\": [\n                    {\n                      \"include\": \"#comments\"\n                    },\n                    {\n                      \"match\": \"\\\\w+\",\n                      \"captures\": {\n                        \"0\": {\n                          \"name\": \"variable.parameter.java\"\n                        }\n                      }\n                    }\n                  ]\n                }\n              ]\n            },\n            {\n              \"begin\": \"{\",\n              \"beginCaptures\": {\n                \"0\": {\n                  \"name\": \"punctuation.section.catch.begin.bracket.curly.java\"\n                }\n              },\n              \"end\": \"(?=})\",\n              \"contentName\": \"meta.catch.body.java\",\n              \"patterns\": [\n                {\n                  \"include\": \"#code\"\n                }\n              ]\n            }\n          ]\n        },\n        {\n          \"begin\": \"\\\\bfinally\\\\b\",\n          \"beginCaptures\": {\n            \"0\": {\n              \"name\": \"keyword.control.finally.java\"\n            }\n          },\n          \"end\": \"}\",\n          \"endCaptures\": {\n            \"0\": {\n              \"name\": \"punctuation.section.finally.end.bracket.curly.java\"\n            }\n          },\n          \"name\": \"meta.finally.java\",\n          \"patterns\": [\n            {\n              \"begin\": \"{\",\n              \"beginCaptures\": {\n                \"0\": {\n                  \"name\": \"punctuation.section.finally.begin.bracket.curly.java\"\n                }\n              },\n              \"end\": \"(?=})\",\n              \"contentName\": \"meta.finally.body.java\",\n              \"patterns\": [\n                {\n                  \"include\": \"#code\"\n                }\n              ]\n            }\n          ]\n        }\n      ]\n    },\n    \"variables\": {\n      \"begin\": \"(?x)\\n(?=\\n  \\\\b\\n  (\\n    (void|boolean|byte|char|short|int|float|long|double)\\n    |\\n    (?>(\\\\w+\\\\.)*[A-Z_]+\\\\w*) # e.g. `javax.ws.rs.Response`, or `String`\\n  )\\n  \\\\b\\n  \\\\s*\\n  (\\n    <[\\\\w<>,\\\\.?\\\\s\\\\[\\\\]]*> # e.g. `HashMap<Integer, String>`, or `List<java.lang.String>`\\n  )?\\n  \\\\s*\\n  (\\n    (\\\\[\\\\])* # int[][]\\n  )?\\n  \\\\s+\\n  [A-Za-z_$][\\\\w$]* # At least one identifier after space\\n  ([\\\\w\\\\[\\\\],$][\\\\w\\\\[\\\\],\\\\s]*)? # possibly primitive array or additional identifiers\\n  \\\\s*(=|:|;)\\n)\",\n      \"end\": \"(?=\\\\=|:|;)\",\n      \"name\": \"meta.definition.variable.java\",\n      \"patterns\": [\n        {\n          \"match\": \"([A-Za-z$_][\\\\w$]*)(?=\\\\s*(\\\\[\\\\])*\\\\s*(;|:|=|,))\",\n          \"captures\": {\n            \"1\": {\n              \"name\": \"variable.other.definition.java\"\n            }\n          }\n        },\n        {\n          \"include\": \"#all-types\"\n        },\n        {\n          \"include\": \"#code\"\n        }\n      ]\n    },\n    \"variables-local\": {\n      \"begin\": \"(?=\\\\b(var)\\\\b\\\\s+[A-Za-z_$][\\\\w$]*\\\\s*(=|:|;))\",\n      \"end\": \"(?=\\\\=|:|;)\",\n      \"name\": \"meta.definition.variable.local.java\",\n      \"patterns\": [\n        {\n          \"match\": \"\\\\bvar\\\\b\",\n          \"name\": \"storage.type.local.java\"\n        },\n        {\n          \"match\": \"([A-Za-z$_][\\\\w$]*)(?=\\\\s*(\\\\[\\\\])*\\\\s*(=|:|;))\",\n          \"captures\": {\n            \"1\": {\n              \"name\": \"variable.other.definition.java\"\n            }\n          }\n        },\n        {\n          \"include\": \"#code\"\n        }\n      ]\n    }\n  }\n}"
  },
  {
    "path": "app/src/main/assets/languages/json/language-configuration.json",
    "content": "{\n  \"brackets\": [\n    [\"{\", \"}\"],\n    [\"[\", \"]\"]\n  ],\n  \"autoClosingPairs\": [\n    [\"{\", \"}\"],\n    [\"[\", \"]\"],\n    { \"open\": \"\\\"\", \"close\": \"\\\"\", \"notIn\": [\"string\"] },\n    { \"open\": \"'\", \"close\": \"'\", \"notIn\": [\"string\"] },\n  ],\n  \"surroundingPairs\": [\n    [\"{\", \"}\"],\n    [\"[\", \"]\"],\n    [\"\\\"\", \"\\\"\"],\n  ],\n  \"folding\": {\n    \"markers\": {\n      \"start\": \"^\\\\s*//\\\\s*(?:(?:#?region\\\\b)|(?:<editor-fold\\\\b))\",\n      \"end\": \"^\\\\s*//\\\\s*(?:(?:#?endregion\\\\b)|(?:</editor-fold>))\"\n    }\n  }\n}\n"
  },
  {
    "path": "app/src/main/assets/languages/json/tmLanguage.json",
    "content": "{\n  \"scopeName\": \"source.json\",\n  \"name\": \"JSON\",\n  \"fileTypes\": [\n    \"avsc\",\n    \"babelrc\",\n    \"bowerrc\",\n    \"composer.lock\",\n    \"geojson\",\n    \"gltf\",\n    \"htmlhintrc\",\n    \"ipynb\",\n    \"jscsrc\",\n    \"jshintrc\",\n    \"jslintrc\",\n    \"json\",\n    \"jsonl\",\n    \"jsonld\",\n    \"languagebabel\",\n    \"ldj\",\n    \"ldjson\",\n    \"Pipfile.lock\",\n    \"schema\",\n    \"stylintrc\",\n    \"template\",\n    \"tern-config\",\n    \"tern-project\",\n    \"tfstate\",\n    \"tfstate.backup\",\n    \"topojson\",\n    \"webapp\",\n    \"webmanifest\"\n  ],\n  \"patterns\": [\n    {\n      \"include\": \"#value\"\n    }\n  ],\n  \"repository\": {\n    \"array\": {\n      \"begin\": \"\\\\[\",\n      \"beginCaptures\": {\n        \"0\": {\n          \"name\": \"punctuation.definition.array.begin.json\"\n        }\n      },\n      \"end\": \"(,)?[\\\\s\\\\n]*(\\\\])\",\n      \"endCaptures\": {\n        \"1\": {\n          \"name\": \"invalid.illegal.trailing-array-separator.json\"\n        },\n        \"2\": {\n          \"name\": \"punctuation.definition.array.end.json\"\n        }\n      },\n      \"name\": \"meta.structure.array.json\",\n      \"patterns\": [\n        {\n          \"include\": \"#value\"\n        },\n        {\n          \"match\": \",\",\n          \"name\": \"punctuation.separator.array.json\"\n        },\n        {\n          \"match\": \"[^\\\\s\\\\]]\",\n          \"name\": \"invalid.illegal.expected-array-separator.json\"\n        }\n      ]\n    },\n    \"constant\": {\n      \"match\": \"\\\\b(true|false|null)\\\\b\",\n      \"name\": \"constant.language.json\"\n    },\n    \"number\": {\n      \"match\": \"-?(?=[1-9]|0(?!\\\\d))\\\\d+(\\\\.\\\\d+)?([eE][+-]?\\\\d+)?\",\n      \"name\": \"constant.numeric.json\"\n    },\n    \"object\": {\n      \"begin\": \"{\",\n      \"beginCaptures\": {\n        \"0\": {\n          \"name\": \"punctuation.definition.dictionary.begin.json\"\n        }\n      },\n      \"end\": \"}\",\n      \"endCaptures\": {\n        \"0\": {\n          \"name\": \"punctuation.definition.dictionary.end.json\"\n        }\n      },\n      \"name\": \"meta.structure.dictionary.json\",\n      \"patterns\": [\n        {\n          \"begin\": \"(?=\\\")\",\n          \"end\": \"(?<=\\\")\",\n          \"name\": \"meta.structure.dictionary.key.json\",\n          \"patterns\": [\n            {\n              \"include\": \"#string\"\n            }\n          ]\n        },\n        {\n          \"begin\": \":\",\n          \"beginCaptures\": {\n            \"0\": {\n              \"name\": \"punctuation.separator.dictionary.key-value.json\"\n            }\n          },\n          \"end\": \"(,)(?=[\\\\s\\\\n]*})|(,)|(?=})\",\n          \"endCaptures\": {\n            \"1\": {\n              \"name\": \"invalid.illegal.trailing-dictionary-separator.json\"\n            },\n            \"2\": {\n              \"name\": \"punctuation.separator.dictionary.pair.json\"\n            }\n          },\n          \"name\": \"meta.structure.dictionary.value.json\",\n          \"patterns\": [\n            {\n              \"include\": \"#value\"\n            },\n            {\n              \"match\": \"[^\\\\s,]\",\n              \"name\": \"invalid.illegal.expected-dictionary-separator.json\"\n            }\n          ]\n        },\n        {\n          \"match\": \"[^\\\\s}]\",\n          \"name\": \"invalid.illegal.expected-dictionary-separator.json\"\n        }\n      ]\n    },\n    \"string\": {\n      \"begin\": \"\\\"\",\n      \"beginCaptures\": {\n        \"0\": {\n          \"name\": \"punctuation.definition.string.begin.json\"\n        }\n      },\n      \"end\": \"\\\"\",\n      \"endCaptures\": {\n        \"0\": {\n          \"name\": \"punctuation.definition.string.end.json\"\n        }\n      },\n      \"name\": \"string.quoted.double.json\",\n      \"patterns\": [\n        {\n          \"match\": \"(?x)\\n\\\\\\\\                # a literal backslash\\n(                   # followed by\\n  [\\\"\\\\\\\\/bfnrt]     # one of these characters\\n  |                 # or\\n  u[0-9a-fA-F]{4}   # a u and four hex digits\\n)\",\n          \"name\": \"constant.character.escape.json\"\n        },\n        {\n          \"match\": \"\\\\\\\\.\",\n          \"name\": \"invalid.illegal.unrecognized-string-escape.json\"\n        }\n      ]\n    },\n    \"value\": {\n      \"patterns\": [\n        {\n          \"include\": \"#constant\"\n        },\n        {\n          \"include\": \"#number\"\n        },\n        {\n          \"include\": \"#string\"\n        },\n        {\n          \"include\": \"#array\"\n        },\n        {\n          \"include\": \"#object\"\n        }\n      ]\n    }\n  }\n}\n"
  },
  {
    "path": "app/src/main/assets/languages/kotlin/language-configuration.json",
    "content": "{\n  \"comments\": {\n    \"lineComment\": \"//\",\n    \"blockComment\": [ \"/*\", \"*/\" ]\n  },\n  \"brackets\": [\n    [\"{\", \"}\"],\n    [\"[\", \"]\"],\n    [\"(\", \")\"],\n    [\"<\", \">\"]\n  ],\n  \"autoClosingPairs\": [\n    { \"open\": \"{\", \"close\": \"}\" },\n    { \"open\": \"[\", \"close\": \"]\" },\n    { \"open\": \"(\", \"close\": \")\" },\n    { \"open\": \"'\", \"close\": \"'\", \"notIn\": [\"string\", \"comment\"] },\n    { \"open\": \"\\\"\", \"close\": \"\\\"\", \"notIn\": [\"string\"] },\n    { \"open\": \"/*\", \"close\": \" */\", \"notIn\": [\"string\"] }\n  ],\n  \"surroundingPairs\": [\n    [\"{\", \"}\"],\n    [\"[\", \"]\"],\n    [\"(\", \")\"],\n    [\"<\", \">\"],\n    [\"'\", \"'\"],\n    [\"\\\"\", \"\\\"\"]\n  ],\n  \"folding\": {\n    \"offSide\": false,\n    \"markers\": {\n      \"start\": \"^\\\\s*//\\\\s*#region\",\n      \"end\": \"^\\\\s*//\\\\s*#endregion\"\n    }\n  }\n}"
  },
  {
    "path": "app/src/main/assets/languages/kotlin/tmLanguage.json",
    "content": "{\n  \"name\": \"Kotlin\",\n  \"scopeName\": \"source.kotlin\",\n  \"fileTypes\": [\n    \"kt\",\n    \"kts\"\n  ],\n  \"patterns\": [\n    {\n      \"include\": \"#comments\"\n    },\n    {\n      \"captures\": {\n        \"1\": {\n          \"name\": \"keyword.other.kotlin\"\n        },\n        \"2\": {\n          \"name\": \"entity.name.package.kotlin\"\n        }\n      },\n      \"match\": \"^\\\\s*(package)\\\\b(?:\\\\s*([^ ;$]+)\\\\s*)?\"\n    },\n    {\n      \"include\": \"#imports\"\n    },\n    {\n      \"include\": \"#statements\"\n    }\n  ],\n  \"repository\": {\n    \"statements\": {\n      \"patterns\": [\n        {\n          \"include\": \"#namespaces\"\n        },\n        {\n          \"include\": \"#typedefs\"\n        },\n        {\n          \"include\": \"#classes\"\n        },\n        {\n          \"include\": \"#functions\"\n        },\n        {\n          \"include\": \"#variables\"\n        },\n        {\n          \"include\": \"#getters-and-setters\"\n        },\n        {\n          \"include\": \"#expressions\"\n        }\n      ]\n    },\n    \"comments\": {\n      \"patterns\": [\n        {\n          \"begin\": \"/\\\\*\",\n          \"captures\": {\n            \"0\": {\n              \"name\": \"punctuation.definition.comment.kotlin\"\n            }\n          },\n          \"end\": \"\\\\*/\",\n          \"name\": \"comment.block.kotlin\",\n          \"patterns\": [\n            {\n              \"include\": \"#comments\"\n            }\n          ]\n        },\n        {\n          \"captures\": {\n            \"1\": {\n              \"name\": \"comment.line.double-slash.kotlin\"\n            },\n            \"2\": {\n              \"name\": \"punctuation.definition.comment.kotlin\"\n            }\n          },\n          \"match\": \"\\\\s*((//).*$\\\\n?)\"\n        }\n      ]\n    },\n    \"imports\": {\n      \"patterns\": [\n        {\n          \"captures\": {\n            \"1\": {\n              \"name\": \"keyword.other.kotlin\"\n            },\n            \"2\": {\n              \"name\": \"keyword.other.kotlin\"\n            }\n          },\n          \"match\": \"^\\\\s*(import)\\\\s+[^ $]+\\\\s+(as)?\"\n        }\n      ]\n    },\n    \"namespaces\": {\n      \"patterns\": [\n        {\n          \"match\": \"\\\\b(namespace)\\\\b\",\n          \"name\": \"keyword.other.kotlin\"\n        },\n        {\n          \"begin\": \"\\\\{\",\n          \"end\": \"\\\\}\",\n          \"patterns\": [\n            {\n              \"include\": \"#statements\"\n            }\n          ]\n        }\n      ]\n    },\n    \"types\": {\n      \"patterns\": [\n        {\n          \"match\": \"\\\\b(Any|Unit|String|Int|Boolean|Char|Long|Double|Float|Short|Byte|dynamic)\\\\b\",\n          \"name\": \"storage.type.buildin.kotlin\"\n        },\n        {\n          \"match\": \"\\\\b(IntArray|BooleanArray|CharArray|LongArray|DoubleArray|FloatArray|ShortArray|ByteArray)\\\\b\",\n          \"name\": \"storage.type.buildin.array.kotlin\"\n        },\n        {\n          \"begin\": \"\\\\b(Array|List|Map)<\\\\b\",\n          \"beginCaptures\": {\n            \"1\": {\n              \"name\": \"storage.type.buildin.collection.kotlin\"\n            }\n          },\n          \"end\": \">\",\n          \"patterns\": [\n            {\n              \"include\": \"#types\"\n            },\n            {\n              \"include\": \"#keywords\"\n            }\n          ]\n        },\n        {\n          \"begin\": \"\\\\w+<\",\n          \"end\": \">\",\n          \"patterns\": [\n            {\n              \"include\": \"#types\"\n            },\n            {\n              \"include\": \"#keywords\"\n            }\n          ]\n        },\n        {\n          \"begin\": \"(#)\\\\(\",\n          \"beginCaptures\": {\n            \"1\": {\n              \"name\": \"keyword.operator.tuple.kotlin\"\n            }\n          },\n          \"end\": \"\\\\)\",\n          \"patterns\": [\n            {\n              \"include\": \"#expressions\"\n            }\n          ]\n        },\n        {\n          \"begin\": \"\\\\{\",\n          \"end\": \"\\\\}\",\n          \"patterns\": [\n            {\n              \"include\": \"#statements\"\n            }\n          ]\n        },\n        {\n          \"begin\": \"\\\\(\",\n          \"end\": \"\\\\)\",\n          \"patterns\": [\n            {\n              \"include\": \"#types\"\n            }\n          ]\n        },\n        {\n          \"match\": \"(->)\",\n          \"name\": \"keyword.operator.declaration.kotlin\"\n        }\n      ]\n    },\n    \"generics\": {\n      \"patterns\": [\n        {\n          \"begin\": \"(:)\",\n          \"beginCaptures\": {\n            \"1\": {\n              \"name\": \"keyword.operator.declaration.kotlin\"\n            }\n          },\n          \"end\": \"(?=,|>)\",\n          \"patterns\": [\n            {\n              \"include\": \"#types\"\n            }\n          ]\n        },\n        {\n          \"include\": \"#keywords\"\n        },\n        {\n          \"match\": \"\\\\w+\",\n          \"name\": \"storage.type.generic.kotlin\"\n        }\n      ]\n    },\n    \"typedefs\": {\n      \"begin\": \"(?=\\\\s*(?:type))\",\n      \"end\": \"(?=$)\",\n      \"patterns\": [\n        {\n          \"match\": \"\\\\b(type)\\\\b\",\n          \"name\": \"keyword.other.kotlin\"\n        },\n        {\n          \"begin\": \"<\",\n          \"end\": \">\",\n          \"patterns\": [\n            {\n              \"include\": \"#generics\"\n            }\n          ]\n        },\n        {\n          \"include\": \"#expressions\"\n        }\n      ]\n    },\n    \"classes\": {\n      \"begin\": \"(?=\\\\s*(?:companion|class|object|interface))\",\n      \"end\": \"}|(?=$)\",\n      \"patterns\": [\n        {\n          \"begin\": \"\\\\b(companion\\\\s*)?(class|object|interface)\\\\b\",\n          \"beginCaptures\": {\n            \"1\": {\n              \"name\": \"keyword.other.kotlin\"\n            }\n          },\n          \"end\": \"(?=<|{|\\\\(|:)\",\n          \"patterns\": [\n            {\n              \"match\": \"\\\\b(object)\\\\b\",\n              \"name\": \"keyword.other.kotlin\"\n            },\n            {\n              \"match\": \"\\\\w+\",\n              \"name\": \"entity.name.type.class.kotlin\"\n            }\n          ]\n        },\n        {\n          \"begin\": \"<\",\n          \"end\": \">\",\n          \"patterns\": [\n            {\n              \"include\": \"#generics\"\n            }\n          ]\n        },\n        {\n          \"begin\": \"\\\\(\",\n          \"end\": \"\\\\)\",\n          \"patterns\": [\n            {\n              \"include\": \"#parameters\"\n            }\n          ]\n        },\n        {\n          \"begin\": \"(:)\",\n          \"beginCaptures\": {\n            \"1\": {\n              \"name\": \"keyword.operator.declaration.kotlin\"\n            }\n          },\n          \"end\": \"(?={|$)\",\n          \"patterns\": [\n            {\n              \"match\": \"\\\\w+\",\n              \"name\": \"entity.other.inherited-class.kotlin\"\n            },\n            {\n              \"begin\": \"\\\\(\",\n              \"end\": \"\\\\)\",\n              \"patterns\": [\n                {\n                  \"include\": \"#expressions\"\n                }\n              ]\n            }\n          ]\n        },\n        {\n          \"begin\": \"\\\\{\",\n          \"end\": \"\\\\}\",\n          \"patterns\": [\n            {\n              \"include\": \"#statements\"\n            }\n          ]\n        }\n      ]\n    },\n    \"variables\": {\n      \"begin\": \"(?=\\\\s*(?:var|val))\",\n      \"end\": \"(?=:|=|$)\",\n      \"patterns\": [\n        {\n          \"begin\": \"\\\\b(var|val)\\\\b\",\n          \"beginCaptures\": {\n            \"1\": {\n              \"name\": \"keyword.other.kotlin\"\n            }\n          },\n          \"end\": \"(?=:|=|$)\",\n          \"patterns\": [\n            {\n              \"begin\": \"<\",\n              \"end\": \">\",\n              \"patterns\": [\n                {\n                  \"include\": \"#generics\"\n                }\n              ]\n            },\n            {\n              \"captures\": {\n                \"2\": {\n                  \"name\": \"entity.name.variable.kotlin\"\n                }\n              },\n              \"match\": \"([\\\\.<\\\\?>\\\\w]+\\\\.)?(\\\\w+)\"\n            }\n          ]\n        },\n        {\n          \"begin\": \"(:)\",\n          \"beginCaptures\": {\n            \"1\": {\n              \"name\": \"keyword.operator.declaration.kotlin\"\n            }\n          },\n          \"end\": \"(?==|$)\",\n          \"patterns\": [\n            {\n              \"include\": \"#types\"\n            },\n            {\n              \"include\": \"#getters-and-setters\"\n            }\n          ]\n        },\n        {\n          \"begin\": \"(=)\",\n          \"beginCaptures\": {\n            \"1\": {\n              \"name\": \"keyword.operator.assignment.kotlin\"\n            }\n          },\n          \"end\": \"(?=$)\",\n          \"patterns\": [\n            {\n              \"include\": \"#expressions\"\n            },\n            {\n              \"include\": \"#getters-and-setters\"\n            }\n          ]\n        }\n      ]\n    },\n    \"getters-and-setters\": {\n      \"patterns\": [\n        {\n          \"begin\": \"\\\\b(get)\\\\b\\\\s*\\\\(\\\\s*\\\\)\",\n          \"beginCaptures\": {\n            \"1\": {\n              \"name\": \"entity.name.function.kotlin\"\n            }\n          },\n          \"end\": \"\\\\}|(?=\\\\bset\\\\b)|$\",\n          \"patterns\": [\n            {\n              \"begin\": \"(=)\",\n              \"beginCaptures\": {\n                \"1\": {\n                  \"name\": \"keyword.operator.assignment.kotlin\"\n                }\n              },\n              \"end\": \"(?=$|\\\\bset\\\\b)\",\n              \"patterns\": [\n                {\n                  \"include\": \"#expressions\"\n                }\n              ]\n            },\n            {\n              \"begin\": \"\\\\{\",\n              \"end\": \"\\\\}\",\n              \"patterns\": [\n                {\n                  \"include\": \"#expressions\"\n                }\n              ]\n            }\n          ]\n        },\n        {\n          \"begin\": \"\\\\b(set)\\\\b\\\\s*(?=\\\\()\",\n          \"beginCaptures\": {\n            \"1\": {\n              \"name\": \"entity.name.function.kotlin\"\n            }\n          },\n          \"end\": \"\\\\}|(?=\\\\bget\\\\b)|$\",\n          \"patterns\": [\n            {\n              \"begin\": \"\\\\(\",\n              \"end\": \"\\\\)\",\n              \"patterns\": [\n                {\n                  \"include\": \"#parameters\"\n                }\n              ]\n            },\n            {\n              \"begin\": \"(=)\",\n              \"beginCaptures\": {\n                \"1\": {\n                  \"name\": \"keyword.operator.assignment.kotlin\"\n                }\n              },\n              \"end\": \"(?=$|\\\\bset\\\\b)\",\n              \"patterns\": [\n                {\n                  \"include\": \"#expressions\"\n                }\n              ]\n            },\n            {\n              \"begin\": \"\\\\{\",\n              \"end\": \"\\\\}\",\n              \"patterns\": [\n                {\n                  \"include\": \"#expressions\"\n                }\n              ]\n            }\n          ]\n        }\n      ]\n    },\n    \"functions\": {\n      \"begin\": \"(?=\\\\s*(?:fun))\",\n      \"end\": \"}|(?=$)\",\n      \"patterns\": [\n        {\n          \"begin\": \"\\\\b(fun)\\\\b\",\n          \"beginCaptures\": {\n            \"1\": {\n              \"name\": \"keyword.other.kotlin\"\n            }\n          },\n          \"end\": \"(?=\\\\()\",\n          \"patterns\": [\n            {\n              \"begin\": \"<\",\n              \"end\": \">\",\n              \"patterns\": [\n                {\n                  \"include\": \"#generics\"\n                }\n              ]\n            },\n            {\n              \"captures\": {\n                \"2\": {\n                  \"name\": \"entity.name.function.kotlin\"\n                }\n              },\n              \"match\": \"([\\\\.<\\\\?>\\\\w]+\\\\.)?(\\\\w+)\"\n            }\n          ]\n        },\n        {\n          \"begin\": \"\\\\(\",\n          \"end\": \"\\\\)\",\n          \"patterns\": [\n            {\n              \"include\": \"#parameters\"\n            }\n          ]\n        },\n        {\n          \"begin\": \"(:)\",\n          \"beginCaptures\": {\n            \"1\": {\n              \"name\": \"keyword.operator.declaration.kotlin\"\n            }\n          },\n          \"end\": \"(?={|=|$)\",\n          \"patterns\": [\n            {\n              \"include\": \"#types\"\n            }\n          ]\n        },\n        {\n          \"begin\": \"\\\\{\",\n          \"end\": \"(?=\\\\})\",\n          \"patterns\": [\n            {\n              \"include\": \"#statements\"\n            }\n          ]\n        },\n        {\n          \"begin\": \"(=)\",\n          \"beginCaptures\": {\n            \"1\": {\n              \"name\": \"keyword.operator.assignment.kotlin\"\n            }\n          },\n          \"end\": \"(?=$)\",\n          \"patterns\": [\n            {\n              \"include\": \"#expressions\"\n            }\n          ]\n        }\n      ]\n    },\n    \"parameters\": {\n      \"patterns\": [\n        {\n          \"begin\": \"(:)\",\n          \"beginCaptures\": {\n            \"1\": {\n              \"name\": \"keyword.operator.declaration.kotlin\"\n            }\n          },\n          \"end\": \"(?=,|\\\\)|=)\",\n          \"patterns\": [\n            {\n              \"include\": \"#types\"\n            }\n          ]\n        },\n        {\n          \"begin\": \"(=)\",\n          \"beginCaptures\": {\n            \"1\": {\n              \"name\": \"keyword.operator.declaration.kotlin\"\n            }\n          },\n          \"end\": \"(?=,|\\\\))\",\n          \"patterns\": [\n            {\n              \"include\": \"#expressions\"\n            }\n          ]\n        },\n        {\n          \"include\": \"#keywords\"\n        },\n        {\n          \"match\": \"\\\\w+\",\n          \"name\": \"variable.parameter.function.kotlin\"\n        }\n      ]\n    },\n    \"expressions\": {\n      \"patterns\": [\n        {\n          \"begin\": \"\\\\(\",\n          \"end\": \"\\\\)\",\n          \"patterns\": [\n            {\n              \"include\": \"#expressions\"\n            }\n          ]\n        },\n        {\n          \"include\": \"#types\"\n        },\n        {\n          \"include\": \"#strings\"\n        },\n        {\n          \"include\": \"#constants\"\n        },\n        {\n          \"include\": \"#comments\"\n        },\n        {\n          \"include\": \"#keywords\"\n        }\n      ]\n    },\n    \"strings\": {\n      \"patterns\": [\n        {\n          \"begin\": \"\\\"\\\"\\\"\",\n          \"beginCaptures\": {\n            \"0\": {\n              \"name\": \"punctuation.definition.string.begin.kotlin\"\n            }\n          },\n          \"end\": \"\\\"\\\"\\\"\",\n          \"endCaptures\": {\n            \"0\": {\n              \"name\": \"punctuation.definition.string.end.kotlin\"\n            }\n          },\n          \"name\": \"string.quoted.third.kotlin\",\n          \"patterns\": [\n            {\n              \"match\": \"(\\\\$\\\\w+|\\\\$\\\\{[^\\\\}]+\\\\})\",\n              \"name\": \"variable.parameter.template.kotlin\"\n            },\n            {\n              \"match\": \"\\\\\\\\.\",\n              \"name\": \"constant.character.escape.kotlin\"\n            }\n          ]\n        },\n        {\n          \"begin\": \"\\\"\",\n          \"beginCaptures\": {\n            \"0\": {\n              \"name\": \"punctuation.definition.string.begin.kotlin\"\n            }\n          },\n          \"end\": \"\\\"\",\n          \"endCaptures\": {\n            \"0\": {\n              \"name\": \"punctuation.definition.string.end.kotlin\"\n            }\n          },\n          \"name\": \"string.quoted.double.kotlin\",\n          \"patterns\": [\n            {\n              \"match\": \"(\\\\$\\\\w+|\\\\$\\\\{[^\\\\}]+\\\\})\",\n              \"name\": \"variable.parameter.template.kotlin\"\n            },\n            {\n              \"match\": \"\\\\\\\\.\",\n              \"name\": \"constant.character.escape.kotlin\"\n            }\n          ]\n        },\n        {\n          \"begin\": \"'\",\n          \"beginCaptures\": {\n            \"0\": {\n              \"name\": \"punctuation.definition.string.begin.kotlin\"\n            }\n          },\n          \"end\": \"'\",\n          \"endCaptures\": {\n            \"0\": {\n              \"name\": \"punctuation.definition.string.end.kotlin\"\n            }\n          },\n          \"name\": \"string.quoted.single.kotlin\",\n          \"patterns\": [\n            {\n              \"match\": \"\\\\\\\\.\",\n              \"name\": \"constant.character.escape.kotlin\"\n            }\n          ]\n        },\n        {\n          \"begin\": \"`\",\n          \"beginCaptures\": {\n            \"0\": {\n              \"name\": \"punctuation.definition.string.begin.kotlin\"\n            }\n          },\n          \"end\": \"`\",\n          \"endCaptures\": {\n            \"0\": {\n              \"name\": \"punctuation.definition.string.end.kotlin\"\n            }\n          },\n          \"name\": \"string.quoted.single.kotlin\"\n        }\n      ]\n    },\n    \"constants\": {\n      \"patterns\": [\n        {\n          \"match\": \"\\\\b(true|false|null|this|super)\\\\b\",\n          \"name\": \"constant.language.kotlin\"\n        },\n        {\n          \"match\": \"\\\\b((0(x|X)[0-9a-fA-F]*)|(([0-9]+\\\\.?[0-9]*)|(\\\\.[0-9]+))((e|E)(\\\\+|-)?[0-9]+)?)([LlFfUuDd]|UL|ul)?\\\\b\",\n          \"name\": \"constant.numeric.kotlin\"\n        },\n        {\n          \"match\": \"\\\\b([A-Z][A-Z0-9_]+)\\\\b\",\n          \"name\": \"constant.other.kotlin\"\n        }\n      ]\n    },\n    \"keywords\": {\n      \"patterns\": [\n        {\n          \"match\": \"\\\\b(var|val|public|private|protected|abstract|final|enum|open|attribute|annotation|override|inline|var|val|vararg|lazy|in|out|internal|data|tailrec|operator|infix|const|yield|typealias|typeof)\\\\b\",\n          \"name\": \"storage.modifier.kotlin\"\n        },\n        {\n          \"match\": \"\\\\b(try|catch|finally|throw)\\\\b\",\n          \"name\": \"keyword.control.catch-exception.kotlin\"\n        },\n        {\n          \"match\": \"\\\\b(if|else|while|for|do|return|when|where|break|continue)\\\\b\",\n          \"name\": \"keyword.control.kotlin\"\n        },\n        {\n          \"match\": \"\\\\b(in|is|as|assert)\\\\b\",\n          \"name\": \"keyword.operator.kotlin\"\n        },\n        {\n          \"match\": \"(==|!=|===|!==|<=|>=|<|>)\",\n          \"name\": \"keyword.operator.comparison.kotlin\"\n        },\n        {\n          \"match\": \"(=)\",\n          \"name\": \"keyword.operator.assignment.kotlin\"\n        },\n        {\n          \"match\": \"(:)\",\n          \"name\": \"keyword.operator.declaration.kotlin\"\n        },\n        {\n          \"match\": \"(\\\\.)\",\n          \"name\": \"keyword.operator.dot.kotlin\"\n        },\n        {\n          \"match\": \"(\\\\-\\\\-|\\\\+\\\\+)\",\n          \"name\": \"keyword.operator.increment-decrement.kotlin\"\n        },\n        {\n          \"match\": \"(\\\\+=|\\\\-=|\\\\*=|\\\\/=)\",\n          \"name\": \"keyword.operator.arithmetic.assign.kotlin\"\n        },\n        {\n          \"match\": \"(\\\\.\\\\.)\",\n          \"name\": \"keyword.operator.range.kotlin\"\n        },\n        {\n          \"match\": \"(\\\\-|\\\\+|\\\\*|\\\\/|%)\",\n          \"name\": \"keyword.operator.arithmetic.kotlin\"\n        },\n        {\n          \"match\": \"(!|&&|\\\\|\\\\|)\",\n          \"name\": \"keyword.operator.logical.kotlin\"\n        },\n        {\n          \"match\": \"(;)\",\n          \"name\": \"punctuation.terminator.kotlin\"\n        }\n      ]\n    }\n  }\n}\n"
  },
  {
    "path": "app/src/main/assets/languages/properties/language-configuration.json",
    "content": "{\n  \"comments\": {\n    \"lineComment\": \"#\"\n  }\n}\n"
  },
  {
    "path": "app/src/main/assets/languages/properties/tmLanguage.json",
    "content": "{\n  \"fileTypes\": [\n    \"properties\"\n  ],\n  \"foldingStartMarker\": \"^[a-zA-Z0-9.-_]+=.*\\\\\\n\",\n  \"foldingStopMarker\": \"^(.*(?<!\\\\)\\n)\",\n  \"keyEquivalent\": \"^~J\",\n  \"name\": \"Java Properties\",\n  \"patterns\": [\n    {\n      \"comment\": \"Ignore blank lines\",\n      \"match\": \"^\\\\s*$\"\n    },\n    {\n      \"include\": \"#comment-line\"\n    },\n    {\n      \"include\": \"#property-name\"\n    },\n    {\n      \"include\": \"#property-definition\"\n    }\n  ],\n  \"repository\": {\n    \"comment-line\": {\n      \"captures\": {\n        \"1\": {\n          \"name\": \"punctuation.whitespace.comment.leading.java-properties\"\n        },\n        \"2\": {\n          \"name\": \"punctuation.definition.comment.java-properties\"\n        }\n      },\n      \"match\": \"^(\\\\s*)([#!])(.+)?$\\\\n?\",\n      \"name\": \"comment.line.java-properties\"\n    },\n    \"property-definition\": {\n      \"begin\": \"^(\\\\s*)((?:\\\\\\\\[ \\\\t]|\\\\\\\\:|\\\\\\\\=|[^:=\\\\s])+)(?:\\\\s*([:=]))?\\\\s*\",\n      \"beginCaptures\": {\n        \"1\": {\n          \"name\": \"punctuation.whitespace.leading.java-properties\"\n        },\n        \"2\": {\n          \"name\": \"support.constant.java-properties\",\n          \"patterns\": [\n            {\n              \"match\": \"\\\\\\\\(?:[ \\\\t:=\\\\\\\\ntfr\\\\\\\"']|u[0-9A-Fa-f]{4})\",\n              \"name\": \"constant.character.escape.java-properties\"\n            }\n          ]\n        },\n        \"3\": {\n          \"name\": \"punctuation.separator.key-value.java-properties\"\n        }\n      },\n      \"contentName\": \"string.unquoted.java-properties\",\n      \"end\": \"(?<!\\\\\\\\{1})$\\\\n\",\n      \"name\": \"meta.key-value.java-properties\",\n      \"patterns\": [\n        {\n          \"comment\": \"Leading space on a continued line is ignored\",\n          \"match\": \"^\\\\s*\",\n          \"name\": \"punctuation.whitespace.leading.java-properties\"\n        },\n        {\n          \"match\": \"(\\\\\\\\{1})(?=$\\\\n)\",\n          \"name\": \"punctuation.separator.continuation.java-properties\"\n        },\n        {\n          \"match\": \"\\\\\\\\(?:[\\\\\\\\ntfr\\\\\\\"']|u[0-9A-Fa-f]{4})\",\n          \"name\": \"constant.character.escape.java-properties\"\n        }\n      ]\n    },\n    \"property-name\": {\n      \"captures\": {\n        \"1\": {\n          \"name\": \"punctuation.whitespace.comment.leading.java-properties\"\n        },\n        \"2\": {\n          \"name\": \"support.constant.java-properties\",\n          \"patterns\": [\n            {\n              \"match\": \"\\\\\\\\(?:[ \\\\t:=\\\\\\\\ntfr\\\\\\\"']|u[0-9A-Fa-f]{4})\",\n              \"name\": \"constant.character.escape.java-properties\"\n            }\n          ]\n        }\n      },\n      \"comment\": \"A property name with no value\",\n      \"match\": \"^(\\\\s*)((?:\\\\\\\\[ \\\\t]|\\\\\\\\:|\\\\\\\\=|[^:=\\\\s])+)(?:\\\\s*([:=]))?\\\\s*$\\\\n\",\n      \"name\": \"meta.key-value.java-properties\"\n    }\n  },\n  \"scopeName\": \"source.java-properties\",\n  \"uuid\": \"D364E829-7643-4AFF-948D-3C0D6B4EA8A4\"\n}"
  },
  {
    "path": "app/src/main/assets/languages/sh/language-configuration.json",
    "content": "{\n  \"comments\": {\n    \"lineComment\": \"#\"\n  },\n  \"brackets\": [\n    [\"{\", \"}\"],\n    [\"[\", \"]\"],\n    [\"(\", \")\"]\n  ],\n  \"autoClosingPairs\": [\n    [\"{\", \"}\"],\n    [\"[\", \"]\"],\n    [\"(\", \")\"],\n    { \"open\": \"\\\"\", \"close\": \"\\\"\", \"notIn\": [\"string\"] },\n    { \"open\": \"'\", \"close\": \"'\", \"notIn\": [\"string\"] },\n    { \"open\": \"`\", \"close\": \"`\", \"notIn\": [\"string\"] }\n  ],\n  \"surroundingPairs\": [\n    [\"{\", \"}\"],\n    [\"[\", \"]\"],\n    [\"(\", \")\"],\n    [\"\\\"\", \"\\\"\"],\n    [\"'\", \"'\"],\n    [\"`\", \"`\"]\n  ],\n  \"folding\": {\n    \"markers\": {\n      \"start\": \"^\\\\s*#\\\\s*#?region\\\\b.*\",\n      \"end\": \"^\\\\s*#\\\\s*#?endregion\\\\b.*\"\n    }\n  }\n}"
  },
  {
    "path": "app/src/main/assets/languages/sh/tmLanguage.json",
    "content": "{\n  \"information_for_contributors\": [\n    \"This file has been converted from https://github.com/atom/language-shellscript/blob/master/grammars/shell-unix-bash.cson\",\n    \"If you want to provide a fix or improvement, please create a pull request against the original repository.\",\n    \"Once accepted there, we are happy to receive an update request.\"\n  ],\n  \"version\": \"https://github.com/atom/language-shellscript/commit/4f8d7bb5cc4d1643674551683df10fe552dd5a6f\",\n  \"name\": \"Shell Script\",\n  \"scopeName\": \"lngpck.source.shell\",\n  \"patterns\": [\n    {\n      \"include\": \"#comment\"\n    },\n    {\n      \"include\": \"#pipeline\"\n    },\n    {\n      \"include\": \"#list\"\n    },\n    {\n      \"include\": \"#compound-command\"\n    },\n    {\n      \"include\": \"#loop\"\n    },\n    {\n      \"include\": \"#string\"\n    },\n    {\n      \"include\": \"#function-definition\"\n    },\n    {\n      \"include\": \"#variable\"\n    },\n    {\n      \"include\": \"#interpolation\"\n    },\n    {\n      \"include\": \"#heredoc\"\n    },\n    {\n      \"include\": \"#herestring\"\n    },\n    {\n      \"include\": \"#redirection\"\n    },\n    {\n      \"include\": \"#pathname\"\n    },\n    {\n      \"include\": \"#keyword\"\n    },\n    {\n      \"include\": \"#support\"\n    }\n  ],\n  \"repository\": {\n    \"case-clause\": {\n      \"patterns\": [\n        {\n          \"begin\": \"(?=\\\\S)\",\n          \"end\": \";;\",\n          \"endCaptures\": {\n            \"0\": {\n              \"name\": \"punctuation.terminator.case-clause.shell\"\n            }\n          },\n          \"name\": \"meta.scope.case-clause.shell\",\n          \"patterns\": [\n            {\n              \"begin\": \"\\\\(|(?=\\\\S)\",\n              \"beginCaptures\": {\n                \"0\": {\n                  \"name\": \"punctuation.definition.case-pattern.shell\"\n                }\n              },\n              \"end\": \"\\\\)\",\n              \"endCaptures\": {\n                \"0\": {\n                  \"name\": \"punctuation.definition.case-pattern.shell\"\n                }\n              },\n              \"name\": \"meta.scope.case-pattern.shell\",\n              \"patterns\": [\n                {\n                  \"match\": \"\\\\|\",\n                  \"name\": \"punctuation.separator.pipe-sign.shell\"\n                },\n                {\n                  \"include\": \"#string\"\n                },\n                {\n                  \"include\": \"#variable\"\n                },\n                {\n                  \"include\": \"#interpolation\"\n                },\n                {\n                  \"include\": \"#pathname\"\n                }\n              ]\n            },\n            {\n              \"begin\": \"(?<=\\\\))\",\n              \"end\": \"(?=;;)\",\n              \"name\": \"meta.scope.case-clause-body.shell\",\n              \"patterns\": [\n                {\n                  \"include\": \"$self\"\n                }\n              ]\n            }\n          ]\n        }\n      ]\n    },\n    \"comment\": {\n      \"begin\": \"(^\\\\s+)?(?<=^|\\\\W)(?<!-)(?=#)(?!#{)\",\n      \"beginCaptures\": {\n        \"1\": {\n          \"name\": \"punctuation.whitespace.comment.leading.shell\"\n        }\n      },\n      \"end\": \"(?!\\\\G)\",\n      \"patterns\": [\n        {\n          \"begin\": \"#!\",\n          \"beginCaptures\": {\n            \"0\": {\n              \"name\": \"punctuation.definition.comment.shebang.shell\"\n            }\n          },\n          \"end\": \"$\",\n          \"name\": \"comment.line.number-sign.shebang.shell\"\n        },\n        {\n          \"begin\": \"#\",\n          \"beginCaptures\": {\n            \"0\": {\n              \"name\": \"punctuation.definition.comment.shell\"\n            }\n          },\n          \"end\": \"$\",\n          \"name\": \"comment.line.number-sign.shell\"\n        }\n      ]\n    },\n    \"compound-command\": {\n      \"patterns\": [\n        {\n          \"begin\": \"\\\\[{1,2}\",\n          \"beginCaptures\": {\n            \"0\": {\n              \"name\": \"punctuation.definition.logical-expression.shell\"\n            }\n          },\n          \"end\": \"\\\\]{1,2}\",\n          \"endCaptures\": {\n            \"0\": {\n              \"name\": \"punctuation.definition.logical-expression.shell\"\n            }\n          },\n          \"name\": \"meta.scope.logical-expression.shell\",\n          \"patterns\": [\n            {\n              \"include\": \"#logical-expression\"\n            },\n            {\n              \"include\": \"$self\"\n            }\n          ]\n        },\n        {\n          \"begin\": \"\\\\({2}\",\n          \"beginCaptures\": {\n            \"0\": {\n              \"name\": \"punctuation.definition.string.begin.shell\"\n            }\n          },\n          \"end\": \"\\\\){2}\",\n          \"endCaptures\": {\n            \"0\": {\n              \"name\": \"punctuation.definition.string.end.shell\"\n            }\n          },\n          \"name\": \"string.other.math.shell\",\n          \"patterns\": [\n            {\n              \"include\": \"#math\"\n            }\n          ]\n        },\n        {\n          \"begin\": \"\\\\(\",\n          \"beginCaptures\": {\n            \"0\": {\n              \"name\": \"punctuation.definition.subshell.shell\"\n            }\n          },\n          \"end\": \"\\\\)\",\n          \"endCaptures\": {\n            \"0\": {\n              \"name\": \"punctuation.definition.subshell.shell\"\n            }\n          },\n          \"name\": \"meta.scope.subshell.shell\",\n          \"patterns\": [\n            {\n              \"include\": \"$self\"\n            }\n          ]\n        },\n        {\n          \"begin\": \"(?<=\\\\s|^){(?=\\\\s|$)\",\n          \"beginCaptures\": {\n            \"0\": {\n              \"name\": \"punctuation.definition.group.shell\"\n            }\n          },\n          \"end\": \"(?<=^|;)\\\\s*(})\",\n          \"endCaptures\": {\n            \"1\": {\n              \"name\": \"punctuation.definition.group.shell\"\n            }\n          },\n          \"name\": \"meta.scope.group.shell\",\n          \"patterns\": [\n            {\n              \"include\": \"$self\"\n            }\n          ]\n        }\n      ]\n    },\n    \"function-definition\": {\n      \"patterns\": [\n        {\n          \"begin\": \"(?<=^|;|&|\\\\s)(function)\\\\s+([^\\\\s\\\\\\\\]+)(?:\\\\s*(\\\\(\\\\)))?\",\n          \"beginCaptures\": {\n            \"1\": {\n              \"name\": \"storage.type.function.shell\"\n            },\n            \"2\": {\n              \"name\": \"entity.name.function.shell\"\n            },\n            \"3\": {\n              \"name\": \"punctuation.definition.arguments.shell\"\n            }\n          },\n          \"end\": \";|&|$\",\n          \"endCaptures\": {\n            \"0\": {\n              \"name\": \"punctuation.definition.function.shell\"\n            }\n          },\n          \"name\": \"meta.function.shell\",\n          \"patterns\": [\n            {\n              \"include\": \"$self\"\n            }\n          ]\n        },\n        {\n          \"begin\": \"(?<=^|;|&|\\\\s)([^\\\\s\\\\\\\\=]+)\\\\s*(\\\\(\\\\))\",\n          \"beginCaptures\": {\n            \"1\": {\n              \"name\": \"entity.name.function.shell\"\n            },\n            \"2\": {\n              \"name\": \"punctuation.definition.arguments.shell\"\n            }\n          },\n          \"end\": \";|&|$\",\n          \"endCaptures\": {\n            \"0\": {\n              \"name\": \"punctuation.definition.function.shell\"\n            }\n          },\n          \"name\": \"meta.function.shell\",\n          \"patterns\": [\n            {\n              \"include\": \"$self\"\n            }\n          ]\n        }\n      ]\n    },\n    \"heredoc\": {\n      \"patterns\": [\n        {\n          \"begin\": \"(<<)-\\\\s*(\\\"|'|)\\\\s*(RUBY)(?=\\\\s|;|&|<|\\\"|')\\\\2\",\n          \"beginCaptures\": {\n            \"1\": {\n              \"name\": \"keyword.operator.heredoc.shell\"\n            },\n            \"3\": {\n              \"name\": \"keyword.control.heredoc-token.shell\"\n            }\n          },\n          \"end\": \"^\\\\t*(RUBY)(?=\\\\s|;|&|$)\",\n          \"endCaptures\": {\n            \"1\": {\n              \"name\": \"keyword.control.heredoc-token.shell\"\n            }\n          },\n          \"name\": \"string.unquoted.heredoc.no-indent.ruby.shell\",\n          \"contentName\": \"source.ruby.embedded.shell\",\n          \"patterns\": [\n            {\n              \"include\": \"lngpck.source.ruby\"\n            }\n          ]\n        },\n        {\n          \"begin\": \"(<<)\\\\s*(\\\"|'|)\\\\s*(RUBY)(?=\\\\s|;|&|<|\\\"|')\\\\2\",\n          \"beginCaptures\": {\n            \"1\": {\n              \"name\": \"keyword.operator.heredoc.shell\"\n            },\n            \"3\": {\n              \"name\": \"keyword.control.heredoc-token.shell\"\n            }\n          },\n          \"end\": \"^(RUBY)(?=\\\\s|;|&|$)\",\n          \"endCaptures\": {\n            \"1\": {\n              \"name\": \"keyword.control.heredoc-token.shell\"\n            }\n          },\n          \"name\": \"string.unquoted.heredoc.ruby.shell\",\n          \"contentName\": \"source.ruby.embedded.shell\",\n          \"patterns\": [\n            {\n              \"include\": \"lngpck.source.ruby\"\n            }\n          ]\n        },\n        {\n          \"begin\": \"(<<)-\\\\s*(\\\"|'|)\\\\s*(PYTHON)(?=\\\\s|;|&|<|\\\"|')\\\\2\",\n          \"beginCaptures\": {\n            \"1\": {\n              \"name\": \"keyword.operator.heredoc.shell\"\n            },\n            \"3\": {\n              \"name\": \"keyword.control.heredoc-token.shell\"\n            }\n          },\n          \"end\": \"^\\\\t*(PYTHON)(?=\\\\s|;|&|$)\",\n          \"endCaptures\": {\n            \"1\": {\n              \"name\": \"keyword.control.heredoc-token.shell\"\n            }\n          },\n          \"name\": \"string.unquoted.heredoc.no-indent.python.shell\",\n          \"contentName\": \"source.python.embedded.shell\",\n          \"patterns\": [\n            {\n              \"include\": \"lngpck.source.python\"\n            }\n          ]\n        },\n        {\n          \"begin\": \"(<<)\\\\s*(\\\"|'|)\\\\s*(PYTHON)(?=\\\\s|;|&|<|\\\"|')\\\\2\",\n          \"beginCaptures\": {\n            \"1\": {\n              \"name\": \"keyword.operator.heredoc.shell\"\n            },\n            \"3\": {\n              \"name\": \"keyword.control.heredoc-token.shell\"\n            }\n          },\n          \"end\": \"^(PYTHON)(?=\\\\s|;|&|$)\",\n          \"endCaptures\": {\n            \"1\": {\n              \"name\": \"keyword.control.heredoc-token.shell\"\n            }\n          },\n          \"name\": \"string.unquoted.heredoc.python.shell\",\n          \"contentName\": \"source.python.embedded.shell\",\n          \"patterns\": [\n            {\n              \"include\": \"lngpck.source.python\"\n            }\n          ]\n        },\n        {\n          \"begin\": \"(<<)-\\\\s*(\\\"|'|)\\\\s*(APPLESCRIPT)(?=\\\\s|;|&|<|\\\"|')\\\\2\",\n          \"beginCaptures\": {\n            \"1\": {\n              \"name\": \"keyword.operator.heredoc.shell\"\n            },\n            \"3\": {\n              \"name\": \"keyword.control.heredoc-token.shell\"\n            }\n          },\n          \"end\": \"^\\\\t*(APPLESCRIPT)(?=\\\\s|;|&|$)\",\n          \"endCaptures\": {\n            \"1\": {\n              \"name\": \"keyword.control.heredoc-token.shell\"\n            }\n          },\n          \"name\": \"string.unquoted.heredoc.no-indent.applescript.shell\",\n          \"contentName\": \"source.applescript.embedded.shell\",\n          \"patterns\": [\n            {\n              \"include\": \"lngpck.source.applescript\"\n            }\n          ]\n        },\n        {\n          \"begin\": \"(<<)\\\\s*(\\\"|'|)\\\\s*(APPLESCRIPT)(?=\\\\s|;|&|<|\\\"|')\\\\2\",\n          \"beginCaptures\": {\n            \"1\": {\n              \"name\": \"keyword.operator.heredoc.shell\"\n            },\n            \"3\": {\n              \"name\": \"keyword.control.heredoc-token.shell\"\n            }\n          },\n          \"end\": \"^(APPLESCRIPT)(?=\\\\s|;|&|$)\",\n          \"endCaptures\": {\n            \"1\": {\n              \"name\": \"keyword.control.heredoc-token.shell\"\n            }\n          },\n          \"name\": \"string.unquoted.heredoc.applescript.shell\",\n          \"contentName\": \"source.applescript.embedded.shell\",\n          \"patterns\": [\n            {\n              \"include\": \"lngpck.source.applescript\"\n            }\n          ]\n        },\n        {\n          \"begin\": \"(<<)-\\\\s*(\\\"|'|)\\\\s*(HTML)(?=\\\\s|;|&|<|\\\"|')\\\\2\",\n          \"beginCaptures\": {\n            \"1\": {\n              \"name\": \"keyword.operator.heredoc.shell\"\n            },\n            \"3\": {\n              \"name\": \"keyword.control.heredoc-token.shell\"\n            }\n          },\n          \"end\": \"^\\\\t*(HTML)(?=\\\\s|;|&|$)\",\n          \"endCaptures\": {\n            \"1\": {\n              \"name\": \"keyword.control.heredoc-token.shell\"\n            }\n          },\n          \"name\": \"string.unquoted.heredoc.no-indent.html.shell\",\n          \"contentName\": \"text.html.embedded.shell\",\n          \"patterns\": [\n            {\n              \"include\": \"lngpck.text.html.basic\"\n            }\n          ]\n        },\n        {\n          \"begin\": \"(<<)\\\\s*(\\\"|'|)\\\\s*(HTML)(?=\\\\s|;|&|<|\\\"|')\\\\2\",\n          \"beginCaptures\": {\n            \"1\": {\n              \"name\": \"keyword.operator.heredoc.shell\"\n            },\n            \"3\": {\n              \"name\": \"keyword.control.heredoc-token.shell\"\n            }\n          },\n          \"end\": \"^(HTML)(?=\\\\s|;|&|$)\",\n          \"endCaptures\": {\n            \"1\": {\n              \"name\": \"keyword.control.heredoc-token.shell\"\n            }\n          },\n          \"name\": \"string.unquoted.heredoc.html.shell\",\n          \"contentName\": \"text.html.embedded.shell\",\n          \"patterns\": [\n            {\n              \"include\": \"lngpck.text.html.basic\"\n            }\n          ]\n        },\n        {\n          \"begin\": \"(<<)-\\\\s*(\\\"|'|)\\\\s*(MARKDOWN)(?=\\\\s|;|&|<|\\\"|')\\\\2\",\n          \"beginCaptures\": {\n            \"1\": {\n              \"name\": \"keyword.operator.heredoc.shell\"\n            },\n            \"3\": {\n              \"name\": \"keyword.control.heredoc-token.shell\"\n            }\n          },\n          \"end\": \"^\\\\t*(MARKDOWN)(?=\\\\s|;|&|$)\",\n          \"endCaptures\": {\n            \"1\": {\n              \"name\": \"keyword.control.heredoc-token.shell\"\n            }\n          },\n          \"name\": \"string.unquoted.heredoc.no-indent.markdown.shell\",\n          \"contentName\": \"text.html.markdown.embedded.shell\",\n          \"patterns\": [\n            {\n              \"include\": \"lngpck.text.html.markdown\"\n            }\n          ]\n        },\n        {\n          \"begin\": \"(<<)\\\\s*(\\\"|'|)\\\\s*(MARKDOWN)(?=\\\\s|;|&|<|\\\"|')\\\\2\",\n          \"beginCaptures\": {\n            \"1\": {\n              \"name\": \"keyword.operator.heredoc.shell\"\n            },\n            \"3\": {\n              \"name\": \"keyword.control.heredoc-token.shell\"\n            }\n          },\n          \"end\": \"^(MARKDOWN)(?=\\\\s|;|&|$)\",\n          \"endCaptures\": {\n            \"1\": {\n              \"name\": \"keyword.control.heredoc-token.shell\"\n            }\n          },\n          \"name\": \"string.unquoted.heredoc.markdown.shell\",\n          \"contentName\": \"text.html.markdown.embedded.shell\",\n          \"patterns\": [\n            {\n              \"include\": \"lngpck.text.html.markdown\"\n            }\n          ]\n        },\n        {\n          \"begin\": \"(<<)-\\\\s*(\\\"|'|)\\\\s*(TEXTILE)(?=\\\\s|;|&|<|\\\"|')\\\\2\",\n          \"beginCaptures\": {\n            \"1\": {\n              \"name\": \"keyword.operator.heredoc.shell\"\n            },\n            \"3\": {\n              \"name\": \"keyword.control.heredoc-token.shell\"\n            }\n          },\n          \"end\": \"^\\\\t*(TEXTILE)(?=\\\\s|;|&|$)\",\n          \"endCaptures\": {\n            \"1\": {\n              \"name\": \"keyword.control.heredoc-token.shell\"\n            }\n          },\n          \"name\": \"string.unquoted.heredoc.no-indent.textile.shell\",\n          \"contentName\": \"text.html.textile.embedded.shell\",\n          \"patterns\": [\n            {\n              \"include\": \"lngpck.text.html.textile\"\n            }\n          ]\n        },\n        {\n          \"begin\": \"(<<)\\\\s*(\\\"|'|)\\\\s*(TEXTILE)(?=\\\\s|;|&|<|\\\"|')\\\\2\",\n          \"beginCaptures\": {\n            \"1\": {\n              \"name\": \"keyword.operator.heredoc.shell\"\n            },\n            \"3\": {\n              \"name\": \"keyword.control.heredoc-token.shell\"\n            }\n          },\n          \"end\": \"^(TEXTILE)(?=\\\\s|;|&|$)\",\n          \"endCaptures\": {\n            \"1\": {\n              \"name\": \"keyword.control.heredoc-token.shell\"\n            }\n          },\n          \"name\": \"string.unquoted.heredoc.textile.shell\",\n          \"contentName\": \"text.html.textile.embedded.shell\",\n          \"patterns\": [\n            {\n              \"include\": \"lngpck.text.html.textile\"\n            }\n          ]\n        },\n        {\n          \"begin\": \"(<<)-\\\\s*(\\\"|'|)\\\\s*(SHELL)(?=\\\\s|;|&|<|\\\"|')\\\\2\",\n          \"beginCaptures\": {\n            \"1\": {\n              \"name\": \"keyword.operator.heredoc.shell\"\n            },\n            \"3\": {\n              \"name\": \"keyword.control.heredoc-token.shell\"\n            }\n          },\n          \"end\": \"^\\\\t*(\\\\3)(?=\\\\s|;|&|$)\",\n          \"endCaptures\": {\n            \"1\": {\n              \"name\": \"keyword.control.heredoc-token.shell\"\n            }\n          },\n          \"contentName\": \"source.shell.embedded.shell\",\n          \"name\": \"string.unquoted.heredoc.no-indent.shell.shell\",\n          \"patterns\": [\n            {\n              \"include\": \"lngpck.source.shell\"\n            }\n          ]\n        },\n        {\n          \"begin\": \"(<<)\\\\s*(\\\"|'|)\\\\s*(SHELL)(?=\\\\s|;|&|<|\\\"|')\\\\2\",\n          \"beginCaptures\": {\n            \"1\": {\n              \"name\": \"keyword.operator.heredoc.shell\"\n            },\n            \"3\": {\n              \"name\": \"keyword.control.heredoc-token.shell\"\n            }\n          },\n          \"end\": \"^(\\\\3)(?=\\\\s|;|&|$)\",\n          \"endCaptures\": {\n            \"1\": {\n              \"name\": \"keyword.control.heredoc-token.shell\"\n            }\n          },\n          \"name\": \"string.unquoted.heredoc.shell.shell\",\n          \"contentName\": \"source.shell.embedded.shell\",\n          \"patterns\": [\n            {\n              \"include\": \"lngpck.source.shell\"\n            }\n          ]\n        },\n        {\n          \"begin\": \"(<<)-\\\\s*(\\\"|')\\\\s*\\\\\\\\?([^;&<\\\\s]+)\\\\2\",\n          \"beginCaptures\": {\n            \"1\": {\n              \"name\": \"keyword.operator.heredoc.shell\"\n            },\n            \"3\": {\n              \"name\": \"keyword.control.heredoc-token.shell\"\n            }\n          },\n          \"end\": \"^\\\\t*(\\\\3)(?=\\\\s|;|&|$)\",\n          \"endCaptures\": {\n            \"1\": {\n              \"name\": \"keyword.control.heredoc-token.shell\"\n            }\n          },\n          \"name\": \"string.unquoted.heredoc.no-indent.shell\"\n        },\n        {\n          \"begin\": \"(<<)\\\\s*(\\\"|')\\\\s*\\\\\\\\?([^;&<\\\\s]+)\\\\2\",\n          \"beginCaptures\": {\n            \"1\": {\n              \"name\": \"keyword.operator.heredoc.shell\"\n            },\n            \"3\": {\n              \"name\": \"keyword.control.heredoc-token.shell\"\n            }\n          },\n          \"end\": \"^(\\\\3)(?=\\\\s|;|&|$)\",\n          \"endCaptures\": {\n            \"1\": {\n              \"name\": \"keyword.control.heredoc-token.shell\"\n            }\n          },\n          \"name\": \"string.unquoted.heredoc.shell\"\n        },\n        {\n          \"begin\": \"(<<)-\\\\s*\\\\\\\\?([^;&<\\\\s]+)\",\n          \"beginCaptures\": {\n            \"1\": {\n              \"name\": \"keyword.operator.heredoc.shell\"\n            },\n            \"2\": {\n              \"name\": \"keyword.control.heredoc-token.shell\"\n            }\n          },\n          \"end\": \"^\\\\t*(\\\\2)(?=\\\\s|;|&|$)\",\n          \"endCaptures\": {\n            \"1\": {\n              \"name\": \"keyword.control.heredoc-token.shell\"\n            }\n          },\n          \"name\": \"string.unquoted.heredoc.expanded.no-indent.shell\",\n          \"patterns\": [\n            {\n              \"match\": \"\\\\\\\\[\\\\$`\\\\\\\\\\\\n]\",\n              \"name\": \"constant.character.escape.shell\"\n            },\n            {\n              \"include\": \"#variable\"\n            },\n            {\n              \"include\": \"#interpolation\"\n            }\n          ]\n        },\n        {\n          \"begin\": \"(<<)\\\\s*\\\\\\\\?([^;&<\\\\s]+)\",\n          \"beginCaptures\": {\n            \"1\": {\n              \"name\": \"keyword.operator.heredoc.shell\"\n            },\n            \"2\": {\n              \"name\": \"keyword.control.heredoc-token.shell\"\n            }\n          },\n          \"end\": \"^(\\\\2)(?=\\\\s|;|&|$)\",\n          \"endCaptures\": {\n            \"1\": {\n              \"name\": \"keyword.control.heredoc-token.shell\"\n            }\n          },\n          \"name\": \"string.unquoted.heredoc.expanded.shell\",\n          \"patterns\": [\n            {\n              \"match\": \"\\\\\\\\[\\\\$`\\\\\\\\\\\\n]\",\n              \"name\": \"constant.character.escape.shell\"\n            },\n            {\n              \"include\": \"#variable\"\n            },\n            {\n              \"include\": \"#interpolation\"\n            }\n          ]\n        }\n      ]\n    },\n    \"herestring\": {\n      \"patterns\": [\n        {\n          \"begin\": \"(<<<)\\\\s*(('))\",\n          \"beginCaptures\": {\n            \"1\": {\n              \"name\": \"keyword.operator.herestring.shell\"\n            },\n            \"2\": {\n              \"name\": \"string.quoted.single.shell\"\n            },\n            \"3\": {\n              \"name\": \"punctuation.definition.string.begin.shell\"\n            }\n          },\n          \"end\": \"(')\",\n          \"endCaptures\": {\n            \"0\": {\n              \"name\": \"string.quoted.single.shell\"\n            },\n            \"1\": {\n              \"name\": \"punctuation.definition.string.end.shell\"\n            }\n          },\n          \"name\": \"meta.herestring.shell\",\n          \"contentName\": \"string.quoted.single.shell\"\n        },\n        {\n          \"begin\": \"(<<<)\\\\s*((\\\"))\",\n          \"beginCaptures\": {\n            \"1\": {\n              \"name\": \"keyword.operator.herestring.shell\"\n            },\n            \"2\": {\n              \"name\": \"string.quoted.double.shell\"\n            },\n            \"3\": {\n              \"name\": \"punctuation.definition.string.begin.shell\"\n            }\n          },\n          \"end\": \"(\\\")\",\n          \"endCaptures\": {\n            \"0\": {\n              \"name\": \"string.quoted.double.shell\"\n            },\n            \"1\": {\n              \"name\": \"punctuation.definition.string.end.shell\"\n            }\n          },\n          \"name\": \"meta.herestring.shell\",\n          \"contentName\": \"string.quoted.double.shell\"\n        },\n        {\n          \"captures\": {\n            \"1\": {\n              \"name\": \"keyword.operator.herestring.shell\"\n            },\n            \"2\": {\n              \"name\": \"string.unquoted.herestring.shell\",\n              \"patterns\": [\n                {\n                  \"include\": \"$self\"\n                }\n              ]\n            }\n          },\n          \"match\": \"(<<<)\\\\s*(([^\\\\s)\\\\\\\\]|\\\\\\\\.)+)\",\n          \"name\": \"meta.herestring.shell\"\n        }\n      ]\n    },\n    \"interpolation\": {\n      \"patterns\": [\n        {\n          \"begin\": \"\\\\$\\\\({2}\",\n          \"beginCaptures\": {\n            \"0\": {\n              \"name\": \"punctuation.definition.string.begin.shell\"\n            }\n          },\n          \"end\": \"\\\\){2}\",\n          \"endCaptures\": {\n            \"0\": {\n              \"name\": \"punctuation.definition.string.end.shell\"\n            }\n          },\n          \"name\": \"string.other.math.shell\",\n          \"patterns\": [\n            {\n              \"include\": \"#math\"\n            }\n          ]\n        },\n        {\n          \"begin\": \"`\",\n          \"beginCaptures\": {\n            \"0\": {\n              \"name\": \"punctuation.definition.string.begin.shell\"\n            }\n          },\n          \"end\": \"`\",\n          \"endCaptures\": {\n            \"0\": {\n              \"name\": \"punctuation.definition.string.end.shell\"\n            }\n          },\n          \"name\": \"string.interpolated.backtick.shell\",\n          \"patterns\": [\n            {\n              \"match\": \"\\\\\\\\[`\\\\\\\\$]\",\n              \"name\": \"constant.character.escape.shell\"\n            },\n            {\n              \"begin\": \"(?<=\\\\W)(?=#)(?!#{)\",\n              \"beginCaptures\": {\n                \"1\": {\n                  \"name\": \"punctuation.whitespace.comment.leading.shell\"\n                }\n              },\n              \"end\": \"(?!\\\\G)\",\n              \"patterns\": [\n                {\n                  \"begin\": \"#\",\n                  \"beginCaptures\": {\n                    \"0\": {\n                      \"name\": \"punctuation.definition.comment.shell\"\n                    }\n                  },\n                  \"end\": \"(?=`)\",\n                  \"name\": \"comment.line.number-sign.shell\"\n                }\n              ]\n            },\n            {\n              \"include\": \"$self\"\n            }\n          ]\n        },\n        {\n          \"begin\": \"\\\\$\\\\(\",\n          \"beginCaptures\": {\n            \"0\": {\n              \"name\": \"punctuation.definition.string.begin.shell\"\n            }\n          },\n          \"end\": \"\\\\)\",\n          \"endCaptures\": {\n            \"0\": {\n              \"name\": \"punctuation.definition.string.end.shell\"\n            }\n          },\n          \"name\": \"string.interpolated.dollar.shell\",\n          \"patterns\": [\n            {\n              \"include\": \"$self\"\n            }\n          ]\n        }\n      ]\n    },\n    \"keyword\": {\n      \"patterns\": [\n        {\n          \"match\": \"(?<=^|;|&|\\\\s)(then|else|elif|fi|for|in|do|done|select|case|continue|esac|while|until|return)(?=\\\\s|;|&|$)\",\n          \"name\": \"keyword.control.shell\"\n        },\n        {\n          \"match\": \"(?<=^|;|&|\\\\s)(?:export|declare|typeset|local|readonly)(?=\\\\s|;|&|$)\",\n          \"name\": \"storage.modifier.shell\"\n        }\n      ]\n    },\n    \"list\": {\n      \"patterns\": [\n        {\n          \"match\": \";|&&|&|\\\\|\\\\|\",\n          \"name\": \"keyword.operator.list.shell\"\n        }\n      ]\n    },\n    \"logical-expression\": {\n      \"patterns\": [\n        {\n          \"comment\": \"do we want a special rule for ( expr )?\",\n          \"match\": \"=[=~]?|!=?|<|>|&&|\\\\|\\\\|\",\n          \"name\": \"keyword.operator.logical.shell\"\n        },\n        {\n          \"match\": \"(?<!\\\\S)-(nt|ot|ef|eq|ne|l[te]|g[te]|[a-hknoprstuwxzOGLSN])\",\n          \"name\": \"keyword.operator.logical.shell\"\n        }\n      ]\n    },\n    \"loop\": {\n      \"patterns\": [\n        {\n          \"begin\": \"(?<=^|;|&|\\\\s)(for)\\\\s+(?=\\\\({2})\",\n          \"beginCaptures\": {\n            \"1\": {\n              \"name\": \"keyword.control.shell\"\n            }\n          },\n          \"end\": \"(?<=^|;|&|\\\\s)done(?=\\\\s|;|&|$)\",\n          \"endCaptures\": {\n            \"0\": {\n              \"name\": \"keyword.control.shell\"\n            }\n          },\n          \"name\": \"meta.scope.for-loop.shell\",\n          \"patterns\": [\n            {\n              \"include\": \"$self\"\n            }\n          ]\n        },\n        {\n          \"begin\": \"(?<=^|;|&|\\\\s)(for)\\\\s+(.+?)\\\\s+(in)(?=\\\\s|;|&|$)\",\n          \"beginCaptures\": {\n            \"1\": {\n              \"name\": \"keyword.control.shell\"\n            },\n            \"2\": {\n              \"name\": \"variable.other.loop.shell\",\n              \"patterns\": [\n                {\n                  \"include\": \"#string\"\n                }\n              ]\n            },\n            \"3\": {\n              \"name\": \"keyword.control.shell\"\n            }\n          },\n          \"end\": \"(?<=^|;|&|\\\\s)done(?=\\\\s|;|&|$)\",\n          \"endCaptures\": {\n            \"0\": {\n              \"name\": \"keyword.control.shell\"\n            }\n          },\n          \"name\": \"meta.scope.for-in-loop.shell\",\n          \"patterns\": [\n            {\n              \"include\": \"$self\"\n            }\n          ]\n        },\n        {\n          \"begin\": \"(?<=^|;|&|\\\\s)(while|until)(?=\\\\s|;|&|$)\",\n          \"beginCaptures\": {\n            \"1\": {\n              \"name\": \"keyword.control.shell\"\n            }\n          },\n          \"end\": \"(?<=^|;|&|\\\\s)done(?=\\\\s|;|&|$)\",\n          \"endCaptures\": {\n            \"0\": {\n              \"name\": \"keyword.control.shell\"\n            }\n          },\n          \"name\": \"meta.scope.while-loop.shell\",\n          \"patterns\": [\n            {\n              \"include\": \"$self\"\n            }\n          ]\n        },\n        {\n          \"begin\": \"(?<=^|;|&|\\\\s)(select)\\\\s+((?:[^\\\\s\\\\\\\\]|\\\\\\\\.)+)(?=\\\\s|;|&|$)\",\n          \"beginCaptures\": {\n            \"1\": {\n              \"name\": \"keyword.control.shell\"\n            },\n            \"2\": {\n              \"name\": \"variable.other.loop.shell\"\n            }\n          },\n          \"end\": \"(?<=^|;|&|\\\\s)(done)(?=\\\\s|;|&|$)\",\n          \"endCaptures\": {\n            \"1\": {\n              \"name\": \"keyword.control.shell\"\n            }\n          },\n          \"name\": \"meta.scope.select-block.shell\",\n          \"patterns\": [\n            {\n              \"include\": \"$self\"\n            }\n          ]\n        },\n        {\n          \"begin\": \"(?<=^|;|&|\\\\s)case(?=\\\\s|;|&|$)\",\n          \"beginCaptures\": {\n            \"0\": {\n              \"name\": \"keyword.control.shell\"\n            }\n          },\n          \"end\": \"(?<=^|;|&|\\\\s)esac(?=\\\\s|;|&|$)\",\n          \"endCaptures\": {\n            \"0\": {\n              \"name\": \"keyword.control.shell\"\n            }\n          },\n          \"name\": \"meta.scope.case-block.shell\",\n          \"patterns\": [\n            {\n              \"begin\": \"(?<=^|;|&|\\\\s)in(?=\\\\s|;|&|$)\",\n              \"beginCaptures\": {\n                \"0\": {\n                  \"name\": \"keyword.control.shell\"\n                }\n              },\n              \"end\": \"(?<=^|;|&|\\\\s)(?=esac(\\\\s|;|&|$))\",\n              \"name\": \"meta.scope.case-body.shell\",\n              \"patterns\": [\n                {\n                  \"include\": \"#comment\"\n                },\n                {\n                  \"include\": \"#case-clause\"\n                },\n                {\n                  \"include\": \"$self\"\n                }\n              ]\n            },\n            {\n              \"include\": \"$self\"\n            }\n          ]\n        },\n        {\n          \"begin\": \"(?<=^|;|&|\\\\s)if(?=\\\\s|;|&|$)\",\n          \"beginCaptures\": {\n            \"0\": {\n              \"name\": \"keyword.control.shell\"\n            }\n          },\n          \"end\": \"(?<=^|;|&|\\\\s)fi(?=\\\\s|;|&|$)\",\n          \"endCaptures\": {\n            \"0\": {\n              \"name\": \"keyword.control.shell\"\n            }\n          },\n          \"name\": \"meta.scope.if-block.shell\",\n          \"patterns\": [\n            {\n              \"include\": \"$self\"\n            }\n          ]\n        }\n      ]\n    },\n    \"math\": {\n      \"patterns\": [\n        {\n          \"include\": \"#variable\"\n        },\n        {\n          \"match\": \"\\\\+{1,2}|-{1,2}|!|~|\\\\*{1,2}|/|%|<[<=]?|>[>=]?|==|!=|^|\\\\|{1,2}|&{1,2}|\\\\?|\\\\:|,|=|[*/%+\\\\-&^|]=|<<=|>>=\",\n          \"name\": \"keyword.operator.arithmetic.shell\"\n        },\n        {\n          \"match\": \"0[xX][0-9A-Fa-f]+\",\n          \"name\": \"constant.numeric.hex.shell\"\n        },\n        {\n          \"match\": \"0\\\\d+\",\n          \"name\": \"constant.numeric.octal.shell\"\n        },\n        {\n          \"match\": \"\\\\d{1,2}#[0-9a-zA-Z@_]+\",\n          \"name\": \"constant.numeric.other.shell\"\n        },\n        {\n          \"match\": \"\\\\d+\",\n          \"name\": \"constant.numeric.integer.shell\"\n        }\n      ]\n    },\n    \"pathname\": {\n      \"patterns\": [\n        {\n          \"match\": \"(?<=\\\\s|:|=|^)~\",\n          \"name\": \"keyword.operator.tilde.shell\"\n        },\n        {\n          \"match\": \"\\\\*|\\\\?\",\n          \"name\": \"keyword.operator.glob.shell\"\n        },\n        {\n          \"begin\": \"([?*+@!])(\\\\()\",\n          \"beginCaptures\": {\n            \"1\": {\n              \"name\": \"keyword.operator.extglob.shell\"\n            },\n            \"2\": {\n              \"name\": \"punctuation.definition.extglob.shell\"\n            }\n          },\n          \"end\": \"\\\\)\",\n          \"endCaptures\": {\n            \"0\": {\n              \"name\": \"punctuation.definition.extglob.shell\"\n            }\n          },\n          \"name\": \"meta.structure.extglob.shell\",\n          \"patterns\": [\n            {\n              \"include\": \"$self\"\n            }\n          ]\n        }\n      ]\n    },\n    \"pipeline\": {\n      \"patterns\": [\n        {\n          \"match\": \"(?<=^|;|&|\\\\s)(time)(?=\\\\s|;|&|$)\",\n          \"name\": \"keyword.other.shell\"\n        },\n        {\n          \"match\": \"[|!]\",\n          \"name\": \"keyword.operator.pipe.shell\"\n        }\n      ]\n    },\n    \"redirection\": {\n      \"patterns\": [\n        {\n          \"begin\": \"[><]\\\\(\",\n          \"beginCaptures\": {\n            \"0\": {\n              \"name\": \"punctuation.definition.string.begin.shell\"\n            }\n          },\n          \"end\": \"\\\\)\",\n          \"endCaptures\": {\n            \"0\": {\n              \"name\": \"punctuation.definition.string.end.shell\"\n            }\n          },\n          \"name\": \"string.interpolated.process-substitution.shell\",\n          \"patterns\": [\n            {\n              \"include\": \"$self\"\n            }\n          ]\n        },\n        {\n          \"match\": \"(?<![<>])(&>|\\\\d*>&\\\\d*|\\\\d*(>>|>|<)|\\\\d*<&|\\\\d*<>)(?![<>])\",\n          \"name\": \"keyword.operator.redirect.shell\"\n        }\n      ]\n    },\n    \"string\": {\n      \"patterns\": [\n        {\n          \"match\": \"\\\\\\\\.\",\n          \"name\": \"constant.character.escape.shell\"\n        },\n        {\n          \"begin\": \"'\",\n          \"beginCaptures\": {\n            \"0\": {\n              \"name\": \"punctuation.definition.string.begin.shell\"\n            }\n          },\n          \"end\": \"'\",\n          \"endCaptures\": {\n            \"0\": {\n              \"name\": \"punctuation.definition.string.end.shell\"\n            }\n          },\n          \"name\": \"string.quoted.single.shell\"\n        },\n        {\n          \"begin\": \"\\\\$?\\\"\",\n          \"beginCaptures\": {\n            \"0\": {\n              \"name\": \"punctuation.definition.string.begin.shell\"\n            }\n          },\n          \"end\": \"\\\"\",\n          \"endCaptures\": {\n            \"0\": {\n              \"name\": \"punctuation.definition.string.end.shell\"\n            }\n          },\n          \"name\": \"string.quoted.double.shell\",\n          \"patterns\": [\n            {\n              \"match\": \"\\\\\\\\[\\\\$`\\\"\\\\\\\\\\\\n]\",\n              \"name\": \"constant.character.escape.shell\"\n            },\n            {\n              \"include\": \"#variable\"\n            },\n            {\n              \"include\": \"#interpolation\"\n            }\n          ]\n        },\n        {\n          \"begin\": \"\\\\$'\",\n          \"beginCaptures\": {\n            \"0\": {\n              \"name\": \"punctuation.definition.string.begin.shell\"\n            }\n          },\n          \"end\": \"'\",\n          \"endCaptures\": {\n            \"0\": {\n              \"name\": \"punctuation.definition.string.end.shell\"\n            }\n          },\n          \"name\": \"string.quoted.single.dollar.shell\",\n          \"patterns\": [\n            {\n              \"match\": \"\\\\\\\\(a|b|e|f|n|r|t|v|\\\\\\\\|')\",\n              \"name\": \"constant.character.escape.ansi-c.shell\"\n            },\n            {\n              \"match\": \"\\\\\\\\[0-9]{3}\",\n              \"name\": \"constant.character.escape.octal.shell\"\n            },\n            {\n              \"match\": \"\\\\\\\\x[0-9a-fA-F]{2}\",\n              \"name\": \"constant.character.escape.hex.shell\"\n            },\n            {\n              \"match\": \"\\\\\\\\c.\",\n              \"name\": \"constant.character.escape.control-char.shell\"\n            }\n          ]\n        }\n      ]\n    },\n    \"support\": {\n      \"patterns\": [\n        {\n          \"match\": \"(?<=^|;|&|\\\\s)(?::|\\\\.)(?=\\\\s|;|&|$)\",\n          \"name\": \"support.function.builtin.shell\"\n        },\n        {\n          \"match\": \"(?<=^|;|&|\\\\s)(?:alias|bg|bind|break|builtin|caller|cd|command|compgen|complete|dirs|disown|echo|enable|eval|exec|exit|false|fc|fg|getopts|hash|help|history|jobs|kill|let|logout|popd|printf|pushd|pwd|read|readonly|set|shift|shopt|source|suspend|test|times|trap|true|type|ulimit|umask|unalias|unset|wait)(?=\\\\s|;|&|$)\",\n          \"name\": \"support.function.builtin.shell\"\n        }\n      ]\n    },\n    \"variable\": {\n      \"patterns\": [\n        {\n          \"captures\": {\n            \"1\": {\n              \"name\": \"punctuation.definition.variable.shell\"\n            }\n          },\n          \"match\": \"(\\\\$)[a-zA-Z_][a-zA-Z0-9_]*\",\n          \"name\": \"variable.other.normal.shell\"\n        },\n        {\n          \"captures\": {\n            \"1\": {\n              \"name\": \"punctuation.definition.variable.shell\"\n            }\n          },\n          \"match\": \"(\\\\$)[-*@#?$!0_]\",\n          \"name\": \"variable.other.special.shell\"\n        },\n        {\n          \"captures\": {\n            \"1\": {\n              \"name\": \"punctuation.definition.variable.shell\"\n            }\n          },\n          \"match\": \"(\\\\$)[1-9]\",\n          \"name\": \"variable.other.positional.shell\"\n        },\n        {\n          \"begin\": \"\\\\${\",\n          \"beginCaptures\": {\n            \"0\": {\n              \"name\": \"punctuation.definition.variable.shell\"\n            }\n          },\n          \"end\": \"}\",\n          \"endCaptures\": {\n            \"0\": {\n              \"name\": \"punctuation.definition.variable.shell\"\n            }\n          },\n          \"name\": \"variable.other.bracket.shell\",\n          \"patterns\": [\n            {\n              \"match\": \"!|:[-=?]?|\\\\*|@|#{1,2}|%{1,2}|/\",\n              \"name\": \"keyword.operator.expansion.shell\"\n            },\n            {\n              \"captures\": {\n                \"1\": {\n                  \"name\": \"punctuation.section.array.shell\"\n                },\n                \"3\": {\n                  \"name\": \"punctuation.section.array.shell\"\n                }\n              },\n              \"match\": \"(\\\\[)([^\\\\]]+)(\\\\])\"\n            },\n            {\n              \"include\": \"#variable\"\n            },\n            {\n              \"include\": \"#string\"\n            }\n          ]\n        }\n      ]\n    }\n  }\n}"
  },
  {
    "path": "app/src/main/assets/languages/smali/language-configuration.json",
    "content": "{\n  \"comments\": {\n    \"lineComment\": \"#\"\n  },\n  \"brackets\": [\n    [\"{\", \"}\"],\n    [\"(\", \")\"]\n  ],\n  \"autoClosingPairs\": [\n    [\"{\", \"}\"],\n    [\"(\", \")\"],\n    { \"open\": \"\\\"\", \"close\": \"\\\"\", \"notIn\": [\"string\"] }\n  ],\n  \"surroundingPairs\": [\n    [\"{\", \"}\"],\n    [\"(\", \")\"],\n    [\"\\\"\", \"\\\"\"],\n    [\"<\", \">\"]\n  ],\n  \"folding\": {\n    \"markers\": {\n      \"start\": \"^\\\\s*\\\\.method\",\n      \"end\": \"^\\\\s*\\\\.end method\"\n    }\n  }\n}\n"
  },
  {
    "path": "app/src/main/assets/languages/smali/tmLanguage.json",
    "content": "{\n  \"name\": \"Smali\",\n  \"version\": \"https://github.com/QuinnWilton/sublime-smali/commit/36add49df8c7d8dde1d5cf0d68c4098183b2714f\",\n  \"scopeName\": \"source.smali\",\n  \"fileTypes\": [\n    \"Smali\"\n  ],\n  \"foldingStartMarker\": \"[\\\\s\\\\t]*\\\\.method\",\n  \"foldingStopMarker\": \"[\\\\s\\\\t]*\\\\.end method\",\n  \"patterns\": [\n    { \"include\": \"#annotation\" },\n    { \"include\": \"#annotation-end\" },\n    { \"include\": \"#annotation-value_list\" },\n    { \"include\": \"#annotation-value\" },\n    { \"include\": \"#annotation-name\" },\n    { \"include\": \"#annotation-access\" },\n    { \"include\": \"#comment-alone\" },\n    { \"include\": \"#comment-inline\" },\n    { \"include\": \"#field\" },\n    { \"include\": \"#field-end\" },\n    {\n      \"comment\": \"Class name\",\n      \"match\": \"^[\\\\s\\\\t]*(\\\\.class)[\\\\s\\\\t]*((?:(?:interface|public|protected|private|abstract|static|final|synchronized|transient|volatile|native|strictfp|synthetic|enum|annotation)[\\\\s\\\\t]+)*)[\\\\s\\\\t]*(L)([\\\\p{L}_\\\\$][\\\\p{L}\\\\d_\\\\$]*(?:\\/[\\\\p{L}_\\\\$][\\\\p{L}\\\\d_\\\\$]*)*)(;)(?=[\\\\s\\\\t]*(#.*)?$)\",\n      \"captures\":{\n        \"1\": { \"name\": \"constant.language.smali\" },\n        \"2\": { \"name\": \"variable.parameter.smali\" },\n        \"3\": { \"name\": \"entity.name.tag.smali\" },\n        \"4\": { \"name\": \"string.quoted.double.smali\" },\n        \"5\": { \"name\": \"entity.name.tag.smali\" }\n      }\n    },\n    {\n      \"comment\": \"Super / implements class name\",\n      \"match\": \"^[\\\\s\\\\t]*(\\\\.(?:super|implements))[\\\\s\\\\t]+(L)([\\\\p{L}_\\\\$][\\\\p{L}\\\\d_\\\\$]*(?:\\/[\\\\p{L}_\\\\$][\\\\p{L}\\\\d_\\\\$]*)*)(;)(?=[\\\\s\\\\t]*(#.*)?$)\",\n      \"captures\":{\n        \"1\": { \"name\": \"constant.language.smali\" },\n        \"2\": { \"name\": \"entity.name.tag.smali\" },\n        \"3\": { \"name\": \"string.quoted.double.smali\" },\n        \"4\": { \"name\": \"entity.name.tag.smali\" }\n      }\n    },\n    {\n      \"comment\": \"Source file\",\n      \"match\": \"^[\\\\s\\\\t]*(\\\\.source)[\\\\s\\\\t]+(\\\")(.*?)((?<!\\\\\\\\)\\\")(?=[\\\\s\\\\t]*(#.*)?$)(?=[\\\\s\\\\t]*(#.*)?$)\",\n      \"captures\":{\n        \"1\": { \"name\": \"constant.language.smali\" },\n        \"2\": { \"name\": \"entity.name.tag.smali\" },\n        \"3\": { \"name\": \"string.quoted.double.smali\" },\n        \"4\": { \"name\": \"entity.name.tag.smali\" }\n      }\n    },\n    {\n      \"comment\": \"Method signature and body\",\n      \"begin\": \"^[\\\\s\\\\t]*(\\\\.method)[\\\\s\\\\t]*((?:(?:bridge|varargs|declared-synchronized|public|protected|private|abstract|static|final|synchronized|transient|volatile|native|strictfp|synthetic|enum)[\\\\s\\\\t]+)*)(constructor )?(<init>|<clinit>|(?:[\\\\$\\\\p{L}_\\\\-][\\\\p{L}\\\\d_\\\\$]*))\\\\(((?:[\\\\[]*(?:Z|B|S|C|I|J|F|D|L(?:[\\\\p{L}_\\\\$][\\\\p{L}\\\\d_\\\\$]*(?:\\/[\\\\p{L}_\\\\$][\\\\p{L}\\\\d_\\\\$]*)*);))*)\\\\)(?:(V)|[\\\\[]*(Z|B|S|C|I|J|F|D)|[\\\\[]*(?:(L)([\\\\p{L}_\\\\$][\\\\p{L}\\\\d_\\\\$]*(?:\\/[\\\\p{L}_\\\\$][\\\\p{L}\\\\d_\\\\$]*)*)(;)))(?=[\\\\s\\\\t]*(#.*)?$)\",\n      \"beginCaptures\": {\n        \"1\": { \"name\": \"constant.language.smali\" },\n        \"2\": { \"name\": \"variable.parameter.smali\" },\n        \"3\": { \"name\": \"variable.parameter.smali\" },\n        \"4\": { \"name\": \"entity.name.function.smali\" },\n        \"5\": { \"name\": \"constant.numeric.smali\" },\n        \"6\": { \"name\": \"constant.numeric.smali\" },\n        \"7\": { \"name\": \"constant.numeric.smali\" },\n        \"8\": { \"name\": \"entity.name.tag.smali\" },\n        \"9\": { \"name\": \"constant.numeric.smali\" },\n        \"10\": { \"name\": \"entity.name.tag.smali\" },\n        \"11\": { \"name\": \"constant.numeric.smali\" },\n        \"12\": { \"name\": \"entity.name.tag.smali\" }\n      },\n      \"end\": \"^[\\\\s\\\\t]*(\\\\.end method)(?=[\\\\s\\\\t]*(#.*)?$)\",\n      \"endCaptures\": {\n        \"1\": { \"name\": \"constant.language.smali\" }\n      },\n      \"patterns\": [\n        { \"include\": \"#comment-inline\" },\n        {\n          \"comment\": \"Prologue\",\n          \"name\": \"constant.language.smali\",\n          \"match\": \"^[\\\\s\\\\t]*(\\\\.prologue)(?=[\\\\s\\\\t]*(#.*)?$)\"\n        },\n        {\n          \"comment\": \"Local\",\n          \"match\": \"^[\\\\s\\\\t]*(\\\\.local)[\\\\s\\\\t]+([vp]\\\\d+),[\\\\s\\\\t]+(\\\"[\\\\p{L}_\\\\$][\\\\w\\\\$]*\\\"):[\\\\[]*(?:(?:(Z|B|S|C|I|J|F|D)|(?:(L)([\\\\p{L}_\\\\$][\\\\p{L}\\\\d_\\\\$]*(?:\\/[\\\\p{L}_\\\\$][\\\\p{L}\\\\d_\\\\$]*)*)(;))))(?:,(\\\")(.*?)((?<!\\\\\\\\)\\\"))?(?:,[\\\\s\\\\t]*(\\\")(.*?)((?<!\\\\\\\\)\\\"))?(?=[\\\\s\\\\t]*(#.*)?$)\",\n          \"captures\": {\n            \"1\": { \"name\": \"constant.language.smali\" },\n            \"2\": { \"name\": \"variable.parameter.smali\" },\n            \"3\": { \"name\": \"string.interpolated.smali\" },\n            \"4\": { \"name\": \"constant.numeric.smali\" },\n            \"5\": { \"name\": \"entity.name.tag.smali\" },\n            \"6\": { \"name\": \"constant.numeric.smali\" },\n            \"7\": { \"name\": \"entity.name.tag.smali\" },\n            \"8\": { \"name\": \"entity.name.tag.smali\" },\n            \"9\": { \"name\": \"string.interpolated.smali\" },\n            \"10\": { \"name\": \"entity.name.tag.smali\" },\n            \"11\": { \"name\": \"entity.name.tag.smali\" },\n            \"12\": { \"name\": \"string.interpolated.smali\" },\n            \"13\": { \"name\": \"entity.name.tag.smali\" }\n          }\n        },\n        {\n          \"comment\": \"Catch exceptions\",\n          \"match\": \"^[\\\\s\\\\t]*(\\\\.catch)[\\\\s\\\\t]+(?:(L)([\\\\p{L}_\\\\$][\\\\p{L}\\\\d_\\\\$]*(?:\\/[\\\\p{L}_\\\\$][\\\\p{L}\\\\d_\\\\$]*)*)(;))[\\\\s\\\\t]+{(:[A-Za-z_\\\\d]+)[\\\\s\\\\t]+\\\\.\\\\.[\\\\s\\\\t]+(:[A-Za-z_\\\\d]+)}[\\\\s\\\\t]+(:[A-Za-z_\\\\d]+)(?=[\\\\s\\\\t]*(#.*)?$)\",\n          \"captures\": {\n            \"1\": { \"name\": \"constant.language.smali\" },\n            \"2\": { \"name\": \"entity.name.tag.smali\" },\n            \"3\": { \"name\": \"constant.numeric.smali\" },\n            \"4\": { \"name\": \"entity.name.tag.smali\" },\n            \"5\": { \"name\": \"keyword.control.smali\" },\n            \"6\": { \"name\": \"keyword.control.smali\" },\n            \"7\": { \"name\": \"keyword.control.smali\" }\n          }\n        },\n        {\n          \"comment\": \"Gotta catch 'em all!\",\n          \"match\": \"^[\\\\s\\\\t]*(\\\\.catchall)[\\\\s\\\\t]+{(:[A-Za-z_\\\\d]+)[\\\\s\\\\t]+\\\\.\\\\.[\\\\s\\\\t]+(:[A-Za-z_\\\\d]+)}[\\\\s\\\\t]+(:[A-Za-z_\\\\d]+)(?=[\\\\s\\\\t]*(#.*)?$)\",\n          \"captures\": {\n            \"1\": { \"name\": \"constant.language.smali\" },\n            \"2\": { \"name\": \"keyword.control.smali\" },\n            \"3\": { \"name\": \"keyword.control.smali\" },\n            \"4\": { \"name\": \"keyword.control.smali\" }\n          }\n        },\n        {\n          \"comment\": \"End / Restart Local\",\n          \"name\": \"constant.language.smali\",\n          \"match\": \"^[\\\\s\\\\t]*(\\\\.(?:end|restart)[\\\\s\\\\t]+local)[\\\\s\\\\t]+[vp]\\\\d+(?=[\\\\s\\\\t]*(#.*)?$)\"\n        },\n        {\n          \"comment\": \"Sparse Switch\",\n          \"begin\": \"^[\\\\s\\\\t]*(\\\\.sparse-switch)(?=[\\\\s\\\\t]*(#.*)?$)\",\n          \"beginCaptures\": { \"1\": { \"name\": \"constant.language.smali\" } },\n          \"end\": \"^[\\\\s\\\\t]*(\\\\.end sparse-switch)(?=[\\\\s\\\\t]*(#.*)?$)\",\n          \"endCaptures\": { \"1\": { \"name\": \"constant.language.smali\" } },\n          \"patterns\": [\n            { \"include\": \"#comment-inline\" },\n            {\n              \"match\": \"^[\\\\s\\\\t]*(-?0x(?i:0|[1-9a-f][\\\\da-f]*))[\\\\s\\\\t]+->[\\\\s\\\\t]+(:[A-Za-z_\\\\d]+)(?=[\\\\s\\\\t]*(#.*)?$)\",\n              \"captures\": {\n                \"1\": { \"name\": \"variable.parameter.smali\" },\n                \"2\": { \"name\": \"keyword.control.smali\" }\n              }\n            }\n          ]\n        },\n        {\n          \"comment\": \"Begin Packed Switch, no idea what literal limit is for these. Have seen up to 0x7f090005\",\n          \"match\": \"^[\\\\s\\\\t]*(\\\\.packed-switch)[\\\\s\\\\t]+(-0x1|0x(?i:0|[1-9a-f][\\\\da-f]*))(?=[\\\\s\\\\t]*(#.*)?$)\",\n          \"captures\": {\n            \"1\": { \"name\": \"constant.language.smali\" },\n            \"2\": { \"name\": \"variable.parameter.smali\" }\n          }\n        },\n        {\n          \"comment\": \"End Packed Switch\",\n          \"name\": \"constant.language.smali\",\n          \"match\": \"^[\\\\s\\\\t]*(\\\\.end packed-switch)(?=[\\\\s\\\\t]*(#.*)?$)\"\n        },\n        {\n          \"comment\": \"Array data\",\n          \"begin\": \"^[\\\\s\\\\t]*(\\\\.array-data)[\\\\s\\\\t]+(1|2|4|8)(?=[\\\\s\\\\t]*(#.*)?$)\",\n          \"beginCaptures\": {\n            \"1\": { \"name\": \"constant.language.smali\" },\n            \"2\": { \"name\": \"variable.parameter.smali\" }\n          },\n          \"end\": \"^[\\\\s\\\\t]*(\\\\.end array-data)(?=[\\\\s\\\\t]*(#.*)?$)\",\n          \"endCaptures\": { \"1\": { \"name\": \"constant.language.smali\" } },\n          \"patterns\": [\n            { \"include\": \"#comment-inline\" },\n            {\n              \"match\": \"^[\\\\s\\\\t]*(?i:((?:-0x(?:0|[1-9a-f][\\\\da-f]{0,6}|[1-7][\\\\da-f]{7}|8[0]{7})|0x(?:0|[1-9a-f][\\\\da-f]{0,6}|[1-7][\\\\da-f]{7}))[st]?|(?:(?:-0x(?:0|[1-9a-f][\\\\da-f]{0,14}|[1-7][\\\\da-f]{15}|8[0]{15})|0x(?:0|[1-9a-f][\\\\da-f]{0,14}|[1-7][\\\\da-f]{15}))L))\\\\b)(?=[\\\\s\\\\t]*(#.*)?$)\",\n              \"captures\": { \"1\": { \"name\": \"variable.parameter.smali\" } }\n            }\n          ]\n        },\n        { \"include\": \"#field\" },\n        { \"include\": \"#field-end\" },\n        { \"include\": \"#annotation\" },\n        { \"include\": \"#annotation-end\" },\n        { \"include\": \"#annotation-value_list\" },\n        { \"include\": \"#annotation-value\" },\n        { \"include\": \"#annotation-name\" },\n        { \"include\": \"#annotation-access\" },\n        { \"include\": \"#comment-alone\" },\n        { \"include\": \"#directive-method-line\" },\n        { \"include\": \"#directive-method-registers_locals\" },\n        { \"include\": \"#directive-method-label\" },\n        { \"include\": \"#directive-method-parameter\" },\n        { \"include\": \"#directive-method-parameter-end\" },\n        { \"include\": \"#directives-method-relaxed\" },\n        { \"include\": \"#opcode-format-10x\" },\n        { \"include\": \"#opcode-format-10x-relaxed\" },\n        { \"include\": \"#opcode-format-11n\" },\n        { \"include\": \"#opcode-format-11n-relaxed\" },\n        { \"include\": \"#opcode-format-11x\" },\n        { \"include\": \"#opcode-format-11x-relaxed\" },\n        { \"include\": \"#opcode-format-22x\" },\n        { \"include\": \"#opcode-format-22x-relaxed\" },\n        { \"include\": \"#opcode-format-32x\" },\n        { \"include\": \"#opcode-format-32x-relaxed\" },\n        { \"include\": \"#opcode-format-12x\" },\n        { \"include\": \"#opcode-format-12x-relaxed\" },\n        { \"include\": \"#opcode-format-21c-string\" },\n        { \"include\": \"#opcode-format-21c-type\" },\n        { \"include\": \"#opcode-format-21c-field\" },\n        { \"include\": \"#opcode-format-21c-relaxed\" },\n        { \"include\": \"#opcode-format-21h\" },\n        { \"include\": \"#opcode-format-21h-relaxed\" },\n        { \"include\": \"#opcode-format-21s\" },\n        { \"include\": \"#opcode-format-21s-relaxed\" },\n        { \"include\": \"#opcode-format-21t\" },\n        { \"include\": \"#opcode-format-21t-relaxed\" },\n        { \"include\": \"#opcode-format-31t\" },\n        { \"include\": \"#opcode-format-31t-relaxed\" },\n        { \"include\": \"#opcode-format-22b\" },\n        { \"include\": \"#opcode-format-22b-relaxed\" },\n        { \"include\": \"#opcode-format-22c-type\" },\n        { \"include\": \"#opcode-format-22c-type_array\" },\n        { \"include\": \"#opcode-format-22c-field\" },\n        { \"include\": \"#opcode-format-22c-relaxed\" },\n        { \"include\": \"#opcode-format-22s\" },\n        { \"include\": \"#opcode-format-22s-relaxed\" },\n        { \"include\": \"#opcode-format-22t\" },\n        { \"include\": \"#opcode-format-22t-relaxed\" },\n        { \"include\": \"#opcode-format-23x\" },\n        { \"include\": \"#opcode-format-23x-relaxed\" },\n        { \"include\": \"#opcode-format-3rc-type\" },\n        { \"include\": \"#opcode-format-3rc-meth\" },\n        { \"include\": \"#opcode-format-3rc-relaxed\" },\n        { \"include\": \"#opcode-format-35c-type\" },\n        { \"include\": \"#opcode-format-35c-meth\" },\n        { \"include\": \"#opcode-format-35c-relaxed\" },\n        { \"include\": \"#opcode-format-51l\" },\n        { \"include\": \"#opcode-format-51l-relaxed\" },\n        { \"include\": \"#opcode-format-31i\" },\n        { \"include\": \"#opcode-format-31i-relaxed\" },\n        { \"include\": \"#opcode-format-10t-20t-30t\" },\n        { \"include\": \"#opcode-format-10t-20t-30t-relaxed\" }\n      ]\n    },\n    {\n      \"comment\": \"Method directives - relaxed\",\n      \"match\": \"^[\\\\s\\\\t]*(\\\\.(?:class|super|implements|method|(end )?(?:method|annotation|field)))\",\n      \"captures\": { \"1\": { \"name\": \"invalid.illegal.smali\" }}\n    }\n  ],\n  \"repository\": {\n    \"field\": {\n      \"comment\": \"Field\",\n      \"match\": \"^[\\\\s\\\\t]*(\\\\.field)[\\\\s\\\\t]+((?:(?:bridge|varargs|declared-synchronized|public|protected|private|abstract|static|final|synchronized|transient|volatile|native|strictfp|synthetic|enum)[\\\\s\\\\t]+)*)([\\\\p{L}_\\\\$\\\\-][\\\\w\\\\$]*):[\\\\[]*(?:(?:(Z|B|S|C|I|J|F|D)|(?:(L)([\\\\p{L}_\\\\$][\\\\p{L}\\\\d_\\\\$]*(?:\\/[\\\\p{L}_\\\\$][\\\\p{L}\\\\d_\\\\$]*)*)(;))))(?:[\\\\s\\\\t]+=[\\\\s\\\\t]+(?:(null|true|false)|(?i:(\\\\d+(?:\\\\.\\\\d+)?[fldst]?))|(?i:((?:-0x(?:0|[1-9a-f][\\\\da-f]{0,6}|[1-7][\\\\da-f]{7}|8[0]{7})|0x(?:0|[1-9a-f][\\\\da-f]{0,6}|[1-7][\\\\da-f]{7}))|(?:(?:-0x(?:0|[1-9a-f][\\\\da-f]{0,14}|[1-7][\\\\da-f]{15}|8[0]{15})|0x(?:0|[1-9a-f][\\\\da-f]{0,14}|[1-7][\\\\da-f]{15}))[fldst]?))\\\\b)|([\\\"'])(.*?)((?<!\\\\\\\\)[\\\"'])))?(?=[\\\\s\\\\t]*(#.*)?$)\",\n      \"captures\": {\n        \"1\": { \"name\": \"constant.language.smali\"},\n        \"2\": { \"name\": \"variable.parameter.smali\" },\n        \"3\": { \"name\": \"string.interpolated.smali\" },\n        \"4\": { \"name\": \"constant.numeric.smali\" },\n        \"5\": { \"name\": \"entity.name.tag.smali\" },\n        \"6\": { \"name\": \"constant.numeric.smali\" },\n        \"7\": { \"name\": \"entity.name.tag.smali\" },\n        \"8\": { \"name\": \"constant.language.smali\" },\n        \"9\": { \"name\": \"constant.numeric.smali\" },\n        \"10\": { \"name\": \"constant.numeric.smali\" },\n        \"11\": { \"name\": \"entity.name.tag.smali\" },\n        \"12\": { \"name\": \"string.quoted.double.smali\" },\n        \"13\": { \"name\": \"entity.name.tag.smali\" }\n      }\n    },\n    \"field-end\": {\n      \"comment\": \"Parsing this is hard to do right. This is Good Enough™.\",\n      \"match\": \"^[\\\\s\\\\t]*(\\\\.end field)(?=[\\\\s\\\\t]*(#.*)?$)\",\n      \"captures\": { \"1\": { \"name\": \"constant.language.smali\"} }\n    },\n    \"annotation\": {\n      \"match\": \"^[\\\\s\\\\t]*(\\\\.annotation)[\\\\s\\\\t]+(build|runtime|system)[\\\\s\\\\t]+(?:(L)([\\\\p{L}_\\\\$][\\\\p{L}\\\\d_\\\\$]*(?:\\/[\\\\p{L}_\\\\$][\\\\p{L}\\\\d_\\\\$]*)*)(;))(?=[\\\\s\\\\t]*(#.*)?$)\",\n      \"captures\": {\n        \"1\": { \"name\": \"constant.language.smali\"},\n        \"2\": { \"name\": \"storage.modifier.smali\" },\n        \"3\": { \"name\": \"entity.name.tag.smali\" },\n        \"4\": { \"name\": \"constant.numeric.smali\" },\n        \"5\": { \"name\": \"entity.name.tag.smali\" }\n      }\n    },\n    \"annotation-end\": {\n      \"comment\": \"Parsing this is hard to do right. This is Good Enough™.\",\n      \"match\": \"^[\\\\s\\\\t]*(\\\\.end annotation)(?=[\\\\s\\\\t]*(#.*)?$)\",\n      \"captures\": { \"1\": { \"name\": \"constant.language.smali\"} }\n    },\n    \"annotation-access\": {\n      \"comment\": \"accessFlags property in annotation. Haven't seen any of these go over 0x4019.\",\n      \"match\": \"^[\\\\s\\\\t]*(accessFlags)[\\\\s\\\\t]*=[\\\\s\\\\t]*(0x(?:0|[1-9a-f][\\\\da-f]{0,3}))(?=[\\\\s\\\\t]*(#.*)?$)\",\n      \"captures\": {\n        \"1\": { \"name\": \"support.function.smali\" },\n        \"2\": { \"name\": \"constant.numeric.smali\" }\n      }\n    },\n    \"annotation-name\": {\n      \"comment\": \"Name property in annotation\",\n      \"match\": \"^[\\\\s\\\\t]*(name)[\\\\s\\\\t]*=[\\\\s\\\\t]*(?:(null)|(\\\")(.*?)((?<!\\\\\\\\)\\\")?)(?=[\\\\s\\\\t]*(#.*)?$)\",\n      \"captures\": {\n        \"1\": { \"name\": \"support.function.smali\" },\n        \"2\": { \"name\": \"constant.language.smali\" },\n        \"3\": { \"name\": \"entity.name.tag.smali\" },\n        \"4\": { \"name\": \"string.quoted.double.smali\" },\n        \"5\": { \"name\": \"entity.name.tag.smali\" }\n      }\n    },\n    \"annotation-value\": {\n      \"comment\": \"This is another hack because sublime can't handle multi-line regex, particulaly for 'end'.\",\n      \"match\": \"^[\\\\s\\\\t]*(value)[\\\\s\\\\t]*=[\\\\s\\\\t]*(?:(\\\")(.*?)((?<!\\\\\\\\)\\\")?|(?:\\\\.(enum|subannotation)[\\\\s\\\\t]+)?(L)([\\\\p{L}_\\\\$][\\\\p{L}\\\\d_\\\\$]*(?:\\/[\\\\p{L}_\\\\$][\\\\p{L}\\\\d_\\\\$]*)*)(;))(?:->(?:([\\\\p{L}_\\\\$][\\\\w\\\\$]*):[\\\\[]*(?:(?:(Z|B|S|C|I|J|F|D)|(?:(L)([\\\\p{L}_\\\\$][\\\\p{L}\\\\d_\\\\$]*(?:\\/[\\\\p{L}_\\\\$][\\\\p{L}\\\\d_\\\\$]*)*)(;))))|(<init>|<clinit>|(?:[\\\\$\\\\p{L}_][\\\\p{L}\\\\d_\\\\$]*))\\\\(((?:[\\\\[]*(?:Z|B|S|C|I|J|F|D|L(?:[\\\\p{L}_\\\\$][\\\\p{L}\\\\d_\\\\$]*(?:\\/[\\\\p{L}_\\\\$][\\\\p{L}\\\\d_\\\\$]*)*);))*)\\\\)(?:(V)|[\\\\[]*(Z|B|S|C|I|J|F|D)|[\\\\[]*(?:(L)([\\\\p{L}_\\\\$][\\\\p{L}\\\\d_\\\\$]*(?:\\/[\\\\p{L}_\\\\$][\\\\p{L}\\\\d_\\\\$]*)*)(;)))))?(?=[\\\\s\\\\t]*(#.*)?$)\",\n      \"captures\": {\n        \"1\": { \"name\": \"support.function.smali\" },\n        \"2\": { \"name\": \"entity.name.tag.smali\" },\n        \"3\": { \"name\": \"string.quoted.double.smali\" },\n        \"4\": { \"name\": \"entity.name.tag.smali\" },\n        \"5\": { \"name\": \"entity.name.tag.smali\" },\n        \"6\": { \"name\": \"entity.name.tag.smali\" },\n        \"7\": { \"name\": \"constant.numeric.smali\" },\n        \"8\": { \"name\": \"entity.name.tag.smali\" },\n        \"9\": { \"name\": \"string.interpolated.smali\" },\n        \"10\": { \"name\": \"constant.numeric.smali\" },\n        \"11\": { \"name\": \"entity.name.tag.smali\" },\n        \"12\": { \"name\": \"constant.numeric.smali\" },\n        \"13\": { \"name\": \"entity.name.tag.smali\" },\n        \"14\": { \"name\": \"entity.name.function.smali\" },\n        \"15\": { \"name\": \"constant.numeric.smali\" },\n        \"16\": { \"name\": \"constant.numeric.smali\" },\n        \"17\": { \"name\": \"constant.numeric.smali\" },\n        \"18\": { \"name\": \"entity.name.tag.smali\" },\n        \"19\": { \"name\": \"constant.numeric.smali\" },\n        \"20\": { \"name\": \"entity.name.tag.smali\" },\n        \"21\": { \"name\": \"constant.numeric.smali\" },\n        \"22\": { \"name\": \"entity.name.tag.smali\" }\n      }\n    },\n    \"annotation-value_list\": {\n      \"comment\": \"This is another hack. Deals.\",\n      \"begin\": \"^[\\\\s\\\\t]*(value)[\\\\s\\\\t]*=[\\\\s\\\\t]*{(?=[\\\\s\\\\t]*(#.*)?$)\",\n      \"beginCaptures\": { \"1\": { \"name\": \"support.function.smali\" } },\n      \"end\": \"^[\\\\s\\\\t]*}(?=[\\\\s\\\\t]*(#.*)?$)\",\n      \"patterns\": [\n        { \"include\": \"#comment-inline\" },\n        {\n          \"match\": \"(?:(\\\")(.*?)((?<!\\\\\\\\)\\\")?|(L)([\\\\p{L}_\\\\$][\\\\p{L}\\\\d_\\\\$]*(?:\\/[\\\\p{L}_\\\\$][\\\\p{L}\\\\d_\\\\$]*)*)(;))(?:,)?(?=[\\\\s\\\\t]*(#.*)?$)\",\n          \"captures\": {\n            \"1\": { \"name\": \"entity.name.tag.smali\" },\n            \"2\": { \"name\": \"string.quoted.double.smali\" },\n            \"3\": { \"name\": \"entity.name.tag.smali\" },\n            \"4\": { \"name\": \"entity.name.tag.smali\" },\n            \"5\": { \"name\": \"constant.numeric.smali\" },\n            \"6\": { \"name\": \"entity.name.tag.smali\" }\n          }\n        }\n      ]\n    },\n    \"directive-method-registers_locals\": {\n      \"comment\": \"Registers / Locals\",\n      \"match\": \"[\\\\s\\\\t]*(\\\\.(?:registers|locals))[\\\\s\\\\t]+(\\\\d+)(?=[\\\\s\\\\t]*(#.*)?$)\",\n      \"captures\": {\n        \"1\": { \"name\": \"constant.language.smali\" },\n        \"2\": { \"name\": \"variable.parameter.smali\" }\n      }\n    },\n    \"directive-method-line\": {\n      \"comment\": \"Line\",\n      \"match\": \"[\\\\s\\\\t]*(\\\\.line)[\\\\s\\\\t]+(\\\\d+)(?=[\\\\s\\\\t]*(#.*)?$)\",\n      \"captures\": {\n        \"1\": { \"name\": \"constant.language.smali\" },\n        \"2\": { \"name\": \"variable.parameter.smali\" }\n      }\n    },\n    \"directive-method-parameter\": {\n      \"comment\": \"Parameter\",\n      \"match\": \"[\\\\s\\\\t]*(\\\\.param(?:eter)?)[\\\\s\\\\t]+(p(?:0|[1-9][\\\\d]?|[1-4][\\\\d]{2}|50[\\\\d]|51[0-2])\\\\b)(?:,[\\\\s\\\\t]*(\\\")(.*?)((?<!\\\\\\\\)\\\"))?(?=[\\\\s\\\\t]*(#.*)?$)\",\n      \"captures\": {\n        \"1\": { \"name\": \"support.function.smali\" },\n        \"2\": { \"name\": \"variable.parameter.smali\" },\n        \"3\": { \"name\": \"entity.name.tag.smali\" },\n        \"4\": { \"name\": \"string.quoted.double.smali\" },\n        \"5\": { \"name\": \"entity.name.tag.smali\" }\n      }\n    },\n    \"directive-method-parameter-end\": {\n      \"comment\": \"Parsing this is hard to do right. This is Good Enough™.\",\n      \"match\": \"^[\\\\s\\\\t]*(\\\\.end param)(?=[\\\\s\\\\t]*(#.*)?$)\",\n      \"captures\": { \"1\": { \"name\": \"constant.language.smali\"} }\n    },\n    \"directive-method-label\": {\n      \"comment\": \"Label\",\n      \"match\": \"^[\\\\s\\\\t]*(:[A-Za-z_\\\\d]+)(?=[\\\\s\\\\t]*(#.*)?$)\",\n      \"captures\":{ \"1\": { \"name\": \"keyword.control.smali\" } }\n    },\n    \"directives-method-relaxed\": {\n      \"match\": \"^[\\\\s\\\\t]*(:|\\\\.(?:parameter|line|registers|locals|(?:restart )?local|prologue|(?:end )?(annotation|(sparse|packed)-switch|local)|catch(?:all)?))\",\n      \"captures\": { \"1\": { \"name\": \"invalid.illegal.smali\" }}\n    },\n    \"comment-alone\": {\n      \"comment\": \"Single line, stand alone comment\",\n      \"match\": \"^[\\\\s\\\\t]*(#.*)$\",\n      \"captures\": { \"1\": { \"name\": \"comment.line.number-sign.smali\"} }\n    },\n    \"comment-inline\": {\n      \"comment\": \"In-line comment\",\n      \"match\": \"(#.*)$\",\n      \"captures\": { \"1\": { \"name\": \"comment.line.number-sign.smali\"} }\n    },\n    \"opcode-format-10x\": {\n      \"comment\": \"Format: op\",\n      \"match\": \"^[\\\\s\\\\t]*(nop|return-void)(?=[\\\\s\\\\t]*(#.*)?$)\",\n      \"captures\": { \"1\": { \"name\": \"support.function.smali\" } }\n    },\n    \"opcode-format-10x-relaxed\": {\n      \"match\": \"^[\\\\s\\\\t]*(nop|return-void)\",\n      \"captures\": { \"1\": { \"name\": \"invalid.illegal.smali\" }}\n    },\n    \"opcode-format-11n\": {\n      \"comment\": \"Format: op vA, #+B\",\n      \"match\": \"^[\\\\s\\\\t]*(const\\/4)[\\\\s\\\\t]+([vp](?:0|[1-9]|1[0-5])\\\\b),[\\\\s\\\\t]*(?i:(-0x[0-8]|0x[0-7]))(?=[\\\\s\\\\t]*(#.*)?$)\",\n      \"captures\":{\n        \"1\": { \"name\": \"support.function.smali\" },\n        \"2\": { \"name\": \"variable.parameter.smali\" },\n        \"3\": { \"name\": \"constant.numeric.smali\" }\n      }\n    },\n    \"opcode-format-11n-relaxed\": {\n      \"match\": \"^[\\\\s\\\\t]*(const\\/4)\",\n      \"captures\": { \"1\": { \"name\": \"invalid.illegal.smali\" }}\n    },\n    \"opcode-format-11x\": {\n      \"comment\": \"Format: op vAA\",\n      \"match\": \"^[\\\\s\\\\t]*(move-(?:result(?:-wide|-object)?|exception)|return(?:-wide|-object)?|monitor-(?:enter|exit)|throw)[\\\\s\\\\t]+([vp](?:0|[1-9][\\\\d]?|1[\\\\d]{2}|2[0-4][\\\\d]|25[0-5])\\\\b)(?=[\\\\s\\\\t]*(#.*)?$)\",\n      \"captures\":{\n        \"1\": { \"name\": \"support.function.smali\" },\n        \"2\": { \"name\": \"variable.parameter.smali\" }\n      }\n    },\n    \"opcode-format-11x-relaxed\": {\n      \"match\": \"^[\\\\s\\\\t]*(move-(?:result(?:-wide|-object)?|exception)|return(?:-wide|-object)?|monitor-(?:enter|exit)|throw)\",\n      \"captures\": { \"1\": { \"name\": \"invalid.illegal.smali\" }}\n    },\n    \"opcode-format-22x\": {\n      \"comment\": \"Format: op vAA, vBBBB\",\n      \"match\": \"^[\\\\s\\\\t]*(move(?:-wide|-object)?\\/from16)[\\\\s\\\\t]+([vp](?:0|[1-9][\\\\d]?|1[\\\\d]{2}|2[0-4][\\\\d]|25[0-5])\\\\b),[\\\\s\\\\t]*([vp](?:0|[1-9][\\\\d]{0,3}|[1-5][\\\\d]{4}|6[0-4][\\\\d]{3}|65[0-4][\\\\d]{2}|655[0-2][\\\\d]|6553[0-5])\\\\b)(?=[\\\\s\\\\t]*(#.*)?$)\",\n      \"captures\":{\n        \"1\": { \"name\": \"support.function.smali\" },\n        \"2\": { \"name\": \"variable.parameter.smali\" },\n        \"3\": { \"name\": \"variable.parameter.smali\" }\n      }\n    },\n    \"opcode-format-22x-relaxed\": {\n      \"match\": \"^[\\\\s\\\\t]*(move(?:-wide|-object)?\\/from16)\",\n      \"captures\": { \"1\": { \"name\": \"invalid.illegal.smali\" }}\n    },\n    \"opcode-format-32x\": {\n      \"comment\": \"Format: op vAAAA, vBBBB\",\n      \"match\": \"^[\\\\s\\\\t]*(move(?:-wide|-object)?\\/16)[\\\\s\\\\t]+([vp](?:0|[1-9][\\\\d]{0,3}|[1-5][\\\\d]{4}|6[0-4][\\\\d]{3}|65[0-4][\\\\d]{2}|655[0-2][\\\\d]|6553[0-5])\\\\b),[\\\\s\\\\t]*([vp](?:0|[1-9][\\\\d]{0,3}|[1-5][\\\\d]{4}|6[0-4][\\\\d]{3}|65[0-4][\\\\d]{2}|655[0-2][\\\\d]|6553[0-5])\\\\b)(?=[\\\\s\\\\t]*(#.*)?$)\",\n      \"captures\":{\n        \"1\": { \"name\": \"support.function.smali\" },\n        \"2\": { \"name\": \"variable.parameter.smali\" },\n        \"3\": { \"name\": \"variable.parameter.smali\" }\n      }\n    },\n    \"opcode-format-32x-relaxed\": {\n      \"match\": \"^[\\\\s\\\\t]*(move(?:-wide|-object)?\\/16)\",\n      \"captures\": { \"1\": { \"name\": \"invalid.illegal.smali\" }}\n    },\n    \"opcode-format-12x\": {\n      \"comment\": \"Format: op vA, vB\",\n      \"match\": \"^[\\\\s\\\\t]*(move(?:-wide|-object)?|array-length|neg-(?:int|long|float|double)|not-(?:int|long)|int-to-(?:long|float|double|byte|char|short)|long-to-(?:int|float|double)|float-to-(?:int|long|double)|double-to-(?:int|long|float)|(?:add|sub|mul|div|rem|and|or|xor|shl|shr|ushr)-(?:int|long)\\/2addr|(?:add|sub|mul|div|rem)-(?:float|double)\\/2addr)[\\\\s\\\\t]+([vp](?:0|[1-9]|1[0-5])\\\\b),[\\\\s\\\\t]*([vp](?:0|[1-9]|1[0-5])\\\\b)(?=[\\\\s\\\\t]*(#.*)?$)\",\n      \"captures\":{\n        \"1\": { \"name\": \"support.function.smali\" },\n        \"2\": { \"name\": \"variable.parameter.smali\" },\n        \"3\": { \"name\": \"variable.parameter.smali\" }\n      }\n    },\n    \"opcode-format-12x-relaxed\": {\n      \"match\": \"^[\\\\s\\\\t]*(move(?:-wide|-object)?|array-length|neg-(?:int|long|float|double)|not-(?:int|long)|int-to-(?:long|float|double|byte|char|short)|long-to-(?:int|float|double)|float-to-(?:int|long|double)|double-to-(?:int|long|float)|(?:add|sub|mul|div|rem|and|or|xor|shl|shr|ushr)-(?:int|long)\\/2addr|(?:add|sub|mul|div|rem)-(?:float|double)\\/2addr)\",\n      \"captures\": { \"1\": { \"name\": \"invalid.illegal.smali\" }}\n    },\n    \"opcode-format-21c-string\": {\n      \"comment\": \"Format: op vAA, string@BBBB\",\n      \"match\": \"^[\\\\s\\\\t]*(const-string(?:/jumbo)?)[\\\\s\\\\t]+([vp](?:0|[1-9][\\\\d]?|1[\\\\d]{2}|2[0-4][\\\\d]|25[0-5])\\\\b),[\\\\s\\\\t]*(\\\")(.*?)((?<!\\\\\\\\)\\\")(?=[\\\\s\\\\t]*(#.*)?$)\",\n      \"captures\":{\n        \"1\": { \"name\": \"support.function.smali\" },\n        \"2\": { \"name\": \"variable.parameter.smali\" },\n        \"3\": { \"name\": \"entity.name.tag.smali\" },\n        \"4\": { \"name\": \"string.quoted.double.smali\" },\n        \"5\": { \"name\": \"entity.name.tag.smali\" }\n      }\n    },\n    \"opcode-format-21c-type\": {\n      \"comment\": \"Format: op vAA, type@BBBB\",\n      \"match\": \"^[\\\\s\\\\t]*(const-class|check-cast|new-instance)[\\\\s\\\\t]+([vp](?:0|[1-9][\\\\d]?|1[\\\\d]{2}|2[0-4][\\\\d]|25[0-5])\\\\b),[\\\\s\\\\t]*[\\\\[]*(?:(?:(Z|B|S|C|I|J|F|D)|(?:(L)([\\\\p{L}_\\\\$][\\\\p{L}\\\\d_\\\\$]*(?:\\/[\\\\p{L}_\\\\$][\\\\p{L}\\\\d_\\\\$]*)*)(;))))(?=[\\\\s\\\\t]*(#.*)?$)\",\n      \"captures\":{\n        \"1\": { \"name\": \"support.function.smali\" },\n        \"2\": { \"name\": \"variable.parameter.smali\" },\n        \"3\": { \"name\": \"constant.numeric.smali\" },\n        \"4\": { \"name\": \"entity.name.tag.smali\" },\n        \"5\": { \"name\": \"constant.numeric.smali\" },\n        \"6\": { \"name\": \"entity.name.tag.smali\" }\n      }\n    },\n    \"opcode-format-21c-field\": {\n      \"comment\": \"Format: op vAA, field@BBBB\",\n      \"match\": \"^[\\\\s\\\\t]*((?:sget|sput)(?:-wide|-object|-boolean|-byte|-char|-short)?)[\\\\s\\\\t]+([vp](?:0|[1-9][\\\\d]?|1[\\\\d]{2}|2[0-4][\\\\d]|25[0-5])\\\\b),[\\\\s\\\\t]*(L)([\\\\p{L}_\\\\$][\\\\p{L}\\\\d_\\\\$]*(?:\\/[\\\\p{L}_\\\\$][\\\\p{L}\\\\d_\\\\$]*)*)(;)->([\\\\p{L}_\\\\$][\\\\w\\\\$]*):[\\\\[]*(?:(?:(Z|B|S|C|I|J|F|D)|(?:(L)([\\\\p{L}_\\\\$][\\\\p{L}\\\\d_\\\\$]*(?:\\/[\\\\p{L}_\\\\$][\\\\p{L}\\\\d_\\\\$]*)*)(;))))(?=[\\\\s\\\\t]*(#.*)?$)\",\n      \"captures\":{\n        \"1\": { \"name\": \"support.function.smali\" },\n        \"2\": { \"name\": \"variable.parameter.smali\" },\n        \"3\": { \"name\": \"entity.name.tag.smali\" },\n        \"4\": { \"name\": \"constant.numeric.smali\" },\n        \"5\": { \"name\": \"entity.name.tag.smali\" },\n        \"6\": { \"name\": \"string.interpolated.smali\" },\n        \"7\": { \"name\": \"constant.numeric.smali\" },\n        \"8\": { \"name\": \"entity.name.tag.smali\" },\n        \"9\": { \"name\": \"constant.numeric.smali\" },\n        \"10\": { \"name\": \"entity.name.tag.smali\" }\n      }\n    },\n    \"opcode-format-21c-relaxed\": {\n      \"match\": \"^[\\\\s\\\\t]*(const-string|const-class|check-cast|new-instance|(?:sget|sput)(?:-wide|-object|-boolean|-byte|-char|-short)?)\",\n      \"captures\": { \"1\": { \"name\": \"invalid.illegal.smali\" }}\n    },\n    \"opcode-format-21h\": {\n      \"comment\": \"Format: op vAA, #+BBBB0000(00000000)\",\n      \"match\": \"^[\\\\s\\\\t]*(const(?:-wide)?\\/high16)[\\\\s\\\\t]+([vp](?:0|[1-9][\\\\d]?|1[\\\\d]{2}|2[0-4][\\\\d]|25[0-5])\\\\b),[\\\\s\\\\t]*((?i:-?0x(?:0|[1-9a-f][\\\\da-f]{0,2}|[1-7][\\\\da-f]{3}|8000)[0]{0,12}L?))\\\\b(?=[\\\\s\\\\t]*(#.*)?$)\",\n      \"captures\":{\n        \"1\": { \"name\": \"support.function.smali\" },\n        \"2\": { \"name\": \"variable.parameter.smali\" },\n        \"3\": { \"name\": \"constant.numeric.smali\" }\n      }\n    },\n    \"opcode-format-21h-relaxed\": {\n      \"match\": \"^[\\\\s\\\\t]*(const(?:-wide)?\\/high16)\",\n      \"captures\": { \"1\": { \"name\": \"invalid.illegal.smali\" }}\n    },\n    \"opcode-format-21s\": {\n      \"comment\": \"Format: op vAA, #+BBBB\",\n      \"match\": \"^[\\\\s\\\\t]*(const(?:-wide)?\\/16)[\\\\s\\\\t]+([vp](?:0|[1-9][\\\\d]?|1[\\\\d]{2}|2[0-4][\\\\d]|25[0-5])\\\\b),[\\\\s\\\\t]*(?i:(-0x(?:0|[1-9a-f][\\\\da-f]{0,2}|[1-7][\\\\da-f]{3}|8000)|0x(?:0|[1-9a-f][\\\\da-f]{0,2}|[1-7][\\\\da-f]{3})))\\\\b(?=[\\\\s\\\\t]*(#.*)?$)\",\n      \"captures\":{\n        \"1\": { \"name\": \"support.function.smali\" },\n        \"2\": { \"name\": \"variable.parameter.smali\" },\n        \"3\": { \"name\": \"constant.numeric.smali\" }\n      }\n    },\n    \"opcode-format-21s-relaxed\": {\n      \"match\": \"^[\\\\s\\\\t]*(const(?:-wide)?\\/16)\",\n      \"captures\": { \"1\": { \"name\": \"invalid.illegal.smali\" }}\n    },\n    \"opcode-format-21t\": {\n      \"comment\": \"Format: op vAA, +BBBB\",\n      \"match\": \"^[\\\\s\\\\t]*(if-(?:eq|ne|lt|ge|gt|le)z)[\\\\s\\\\t]+([vp](?:0|[1-9][\\\\d]?|1[\\\\d]{2}|2[0-4][\\\\d]|25[0-5])\\\\b),[\\\\s\\\\t]*(:[A-Za-z_\\\\d]+)(?=[\\\\s\\\\t]*(#.*)?$)\",\n      \"captures\":{\n        \"1\": { \"name\": \"support.function.smali\" },\n        \"2\": { \"name\": \"variable.parameter.smali\" },\n        \"3\": { \"name\": \"keyword.control.smali\" }\n      }\n    },\n    \"opcode-format-21t-relaxed\": {\n      \"match\": \"^[\\\\s\\\\t]*(if-(?:eq|ne|lt|ge|gt|le)z)\",\n      \"captures\": { \"1\": { \"name\": \"invalid.illegal.smali\" }}\n    },\n    \"opcode-format-31t\": {\n      \"comment\": \"Format: op vAA, +BBBBBBBB\",\n      \"match\": \"^[\\\\s\\\\t]*(fill-array-data|(?:packed|sparse)-switch)[\\\\s\\\\t]+([vp](?:0|[1-9][\\\\d]?|1[\\\\d]{2}|2[0-4][\\\\d]|25[0-5])\\\\b),[\\\\s\\\\t]*(:[A-Za-z_\\\\d]+)(?=[\\\\s\\\\t]*(#.*)?$)\",\n      \"captures\":{\n        \"1\": { \"name\": \"support.function.smali\" },\n        \"2\": { \"name\": \"variable.parameter.smali\" },\n        \"3\": { \"name\": \"keyword.control\" }\n      }\n    },\n    \"opcode-format-31t-relaxed\": {\n      \"match\": \"^[\\\\s\\\\t]*(fill-array-data|(?:packed|sparse)-switch)\",\n      \"captures\": { \"1\": { \"name\": \"invalid.illegal.smali\" }}\n    },\n    \"opcode-format-22b\": {\n      \"comment\": \"Format: op vAA, vBB, #+CC\",\n      \"match\": \"^[\\\\s\\\\t]*((?:add|rsub|mul|div|rem|and|or|xor|shl|shr|ushr)-int\\/lit8)[\\\\s\\\\t]+([vp](?:0|[1-9][\\\\d]?|1[\\\\d]{2}|2[0-4][\\\\d]|25[0-5])\\\\b),[\\\\s\\\\t]*([vp](?:0|[1-9][\\\\d]?|1[\\\\d]{2}|2[0-4][\\\\d]|25[0-5])\\\\b),[\\\\s\\\\t]*(?i:(-0x(?:[\\\\da-f]|[1-7][\\\\da-f]|80)|0x(?:[\\\\da-f]|[1-7][\\\\da-f])))\\\\b(?=[\\\\s\\\\t]*(#.*)?$)\",\n      \"captures\":{\n        \"1\": { \"name\": \"support.function.smali\" },\n        \"2\": { \"name\": \"variable.parameter.smali\" },\n        \"3\": { \"name\": \"variable.parameter.smali\" },\n        \"4\": { \"name\": \"constant.numeric.smali\" }\n      }\n    },\n    \"opcode-format-22b-relaxed\": {\n      \"match\": \"^[\\\\s\\\\t]*((?:add|rsub|mul|div|rem|and|or|xor|shl|shr|ushr)-int\\/lit8)\",\n      \"captures\": { \"1\": { \"name\": \"invalid.illegal.smali\" }}\n    },\n    \"opcode-format-22c-type\": {\n      \"comment\": \"Format: op vA, vB, type@CCCC\",\n      \"match\": \"^[\\\\s\\\\t]*(instance-of)[\\\\s\\\\t]+([vp](?:0|[1-9]|1[0-5])\\\\b),[\\\\s\\\\t]*([vp](?:0|[1-9]|1[0-5])\\\\b),[\\\\s\\\\t]*[\\\\[]*(?:(Z|B|S|C|I|J|F|D)|(L)([\\\\p{L}_\\\\$][\\\\p{L}\\\\d_\\\\$]*(?:\\/[\\\\p{L}_\\\\$][\\\\p{L}\\\\d_\\\\$]*)*)(;))(?=[\\\\s\\\\t]*(#.*)?$)\",\n      \"captures\":{\n        \"1\": { \"name\": \"support.function.smali\" },\n        \"2\": { \"name\": \"variable.parameter.smali\" },\n        \"3\": { \"name\": \"variable.parameter.smali\" },\n        \"4\": { \"name\": \"constant.numeric.smali\" },\n        \"5\": { \"name\": \"entity.name.tag.smali\" },\n        \"6\": { \"name\": \"constant.numeric.smali\" },\n        \"7\": { \"name\": \"entity.name.tag.smali\" }\n      }\n    },\n    \"opcode-format-22c-type_array\": {\n      \"comment\": \"Format: op vA, vB, [type@CCCC\",\n      \"match\": \"^[\\\\s\\\\t]*(new-array)[\\\\s\\\\t]+([vp](?:0|[1-9]|1[0-5])\\\\b),[\\\\s\\\\t]*([vp](?:0|[1-9]|1[0-5])\\\\b),[\\\\s\\\\t]*[\\\\[]+(?:(Z|B|S|C|I|J|F|D)|(L)([\\\\p{L}_\\\\$][\\\\p{L}\\\\d_\\\\$]*(?:\\/[\\\\p{L}_\\\\$][\\\\p{L}\\\\d_\\\\$]*)*)(;))(?=[\\\\s\\\\t]*(#.*)?$)\",\n      \"captures\":{\n        \"1\": { \"name\": \"support.function.smali\" },\n        \"2\": { \"name\": \"variable.parameter.smali\" },\n        \"3\": { \"name\": \"variable.parameter.smali\" },\n        \"4\": { \"name\": \"constant.numeric.smali\" },\n        \"5\": { \"name\": \"entity.name.tag.smali\" },\n        \"6\": { \"name\": \"constant.numeric.smali\" },\n        \"7\": { \"name\": \"entity.name.tag.smali\" }\n      }\n    },\n    \"opcode-format-22c-field\": {\n      \"comment\": \"Format: op vA, vB, field@CCCC\",\n      \"match\": \"^[\\\\s\\\\t]*((?:iget|iput)(?:-wide|-object|-boolean|-byte|-char|-short)?)[\\\\s\\\\t]+([vp](?:0|[1-9]|1[0-5])\\\\b),[\\\\s\\\\t]*([vp](?:0|[1-9]|1[0-5])\\\\b),[\\\\s\\\\t]*(L)([\\\\p{L}_\\\\$][\\\\p{L}\\\\d_\\\\$]*(?:\\/[\\\\p{L}_\\\\$][\\\\p{L}\\\\d_\\\\$]*)*)(;)->([\\\\p{L}_\\\\$][\\\\w\\\\$]*):[\\\\[]*(?:(Z|B|S|C|I|J|F|D|(?:(L)([\\\\p{L}_\\\\$][\\\\p{L}\\\\d_\\\\$]*(?:\\/[\\\\p{L}_\\\\$][\\\\p{L}\\\\d_\\\\$]*)*)(;))))(?=[\\\\s\\\\t]*(#.*)?$)\",\n      \"captures\":{\n        \"1\": { \"name\": \"support.function.smali\" },\n        \"2\": { \"name\": \"variable.parameter.smali\" },\n        \"3\": { \"name\": \"variable.parameter.smali\" },\n        \"4\": { \"name\": \"entity.name.tag.smali\" },\n        \"5\": { \"name\": \"constant.numeric.smali\" },\n        \"6\": { \"name\": \"entity.name.tag.smali\" },\n        \"7\": { \"name\": \"string.interpolated.smali\" },\n        \"8\": { \"name\": \"constant.numeric.smali\" },\n        \"9\": { \"name\": \"entity.name.tag.smali\" },\n        \"10\": { \"name\": \"constant.numeric.smali\" },\n        \"11\": { \"name\": \"entity.name.tag.smali\" }\n      }\n    },\n    \"opcode-format-22c-relaxed\": {\n      \"match\": \"^[\\\\s\\\\t]*(instance-of|new-array|(?:iget|iput)(?:-wide|-object|-boolean|-byte|-char|-short)?)\",\n      \"captures\": { \"1\": { \"name\": \"invalid.illegal.smali\" }}\n    },\n    \"opcode-format-22s\": {\n      \"comment\": \"Format: op vA, vB, #+CCCC\",\n      \"match\": \"^[\\\\s\\\\t]*((?:(?:add|mul|div|rem|and|or|xor)-int\\/lit16)|rsub-int)[\\\\s\\\\t]+([vp](?:0|[1-9][\\\\d]?|1[\\\\d]{2}|2[0-4][\\\\d]|25[0-5])\\\\b),[\\\\s\\\\t]*([vp](?:0|[1-9][\\\\d]?|1[\\\\d]{2}|2[0-4][\\\\d]|25[0-5])\\\\b),[\\\\s\\\\t]*(?i:(-0x(?:0|[1-9a-f][\\\\da-f]{0,2}|[1-7][\\\\da-f]{3}|8000)|0x(?:0|[1-9a-f][\\\\da-f]{0,2}|[1-7][\\\\da-f]{3})))\\\\b(?=[\\\\s\\\\t]*(#.*)?$)\",\n      \"captures\":{\n        \"1\": { \"name\": \"support.function.smali\" },\n        \"2\": { \"name\": \"variable.parameter.smali\" },\n        \"3\": { \"name\": \"variable.parameter.smali\" },\n        \"4\": { \"name\": \"constant.numeric.smali\" }\n      }\n    },\n    \"opcode-format-22s-relaxed\": {\n      \"match\": \"^[\\\\s\\\\t]*((?:(?:add|mul|div|rem|and|or|xor)-int\\/lit16)|rsub-int)\",\n      \"captures\": { \"1\": { \"name\": \"invalid.illegal.smali\" }}\n    },\n    \"opcode-format-22t\": {\n      \"comment\": \"*Format: op vA, vB, +CCCC\",\n      \"match\": \"^[\\\\s\\\\t]*(if-(?:eq|ne|lt|ge|gt|le))[\\\\s\\\\t]+([vp](?:0|[1-9]|1[0-5])\\\\b),[\\\\s\\\\t]*([vp](?:0|[1-9]|1[0-5])\\\\b),[\\\\s\\\\t]*(:[A-Za-z_\\\\d]+)(?=[\\\\s\\\\t]*(#.*)?$)\",\n      \"captures\":{\n        \"1\": { \"name\": \"support.function.smali\" },\n        \"2\": { \"name\": \"variable.parameter.smali\" },\n        \"3\": { \"name\": \"variable.parameter.smali\" },\n        \"4\": { \"name\": \"keyword.control\" }\n      }\n    },\n    \"opcode-format-22t-relaxed\": {\n      \"match\": \"(if-(?:eq|ne|lt|ge|gt|le))\",\n      \"captures\": { \"1\": { \"name\": \"invalid.illegal.smali\" }}\n    },\n\n    \"opcode-format-23x\": {\n      \"comment\": \"Format: op vAA, vBB, vCC\",\n      \"match\": \"^[\\\\s\\\\t]*((?:cmpl|cmpg)-(?:float|double)|cmp-long|(?:aget|aput)(?:-wide|-object|-boolean|-byte|-char|-short)?|(?:add|sub|mul|div|rem|and|or|xor|shl|shr|ushr)-(?:int|long)|(?:add|sub|mul|div|rem)-(?:float|double))[\\\\s\\\\t]+([vp](?:0|[1-9][\\\\d]?|1[\\\\d]{2}|2[0-4][\\\\d]|25[0-5])\\\\b),[\\\\s\\\\t]*([vp](?:0|[1-9][\\\\d]?|1[\\\\d]{2}|2[0-4][\\\\d]|25[0-5])\\\\b),[\\\\s\\\\t]*([vp](?:0|[1-9][\\\\d]?|1[\\\\d]{2}|2[0-4][\\\\d]|25[0-5])\\\\b)(?=[\\\\s\\\\t]*(#.*)?$)\",\n      \"captures\":{\n        \"1\": { \"name\": \"support.function.smali\" },\n        \"2\": { \"name\": \"variable.parameter.smali\" },\n        \"3\": { \"name\": \"variable.parameter.smali\" },\n        \"4\": { \"name\": \"variable.parameter.smali\" }\n      }\n    },\n    \"opcode-format-23x-relaxed\": {\n      \"match\": \"^[\\\\s\\\\t]*((?:cmpl|cmpg)-(float|double)|cmp-long|(?:aget|aput)(?:-wide|-object|-boolean|-byte|-char|-short)?|(?:add|sub|mul|div|rem|and|or|xor|shl|shr|ushr)-(?:int|long)|(?:add|sub|mul|div|rem)-(?:float|double))\",\n      \"captures\": { \"1\": { \"name\": \"invalid.illegal.smali\" }}\n    },\n    \"opcode-format-3rc-type\": {\n      \"comment\": \"Format: op {vCCCC .. vNNNN}, type@BBBB\",\n      \"match\": \"^[\\\\s\\\\t]*(filled-new-array\\/range) {([vp](?:0|[1-9][\\\\d]{0,3}|[1-5][\\\\d]{4}|6[0-4][\\\\d]{3}|65[0-4][\\\\d]{2}|655[0-2][\\\\d]|6553[0-5])\\\\b) \\\\.\\\\. ([vp](?:0|[1-9][\\\\d]{0,3}|[1-5][\\\\d]{4}|6[0-4][\\\\d]{3}|65[0-4][\\\\d]{2}|655[0-2][\\\\d]|6553[0-5])\\\\b)},[\\\\s\\\\t]*[\\\\[]+(?:(Z|B|S|C|I|J|F|D)|(L)([\\\\p{L}_\\\\$][\\\\p{L}\\\\d_\\\\$]*(?:\\/[\\\\p{L}_\\\\$][\\\\p{L}\\\\d_\\\\$]*)*)(;))(?=[\\\\s\\\\t]*(#.*)?$)\",\n      \"captures\":{\n        \"1\": { \"name\": \"support.function.smali\" },\n        \"2\": { \"name\": \"variable.parameter.smali\" },\n        \"3\": { \"name\": \"variable.parameter.smali\" },\n        \"4\": { \"name\": \"constant.numeric.smali\" },\n        \"5\": { \"name\": \"entity.name.tag.smali\" },\n        \"6\": { \"name\": \"constant.numeric.smali\" },\n        \"7\": { \"name\": \"entity.name.tag.smali\" }\n      }\n    },\n    \"opcode-format-3rc-meth\": {\n      \"comment\": \"Format: op {vCCCC .. vNNNN}, meth@BBBB\",\n      \"match\": \"^[\\\\s\\\\t]*(invoke-(?:virtual|super|direct|static|interface)\\/range) {[\\\\s\\\\t]*([vp](?:0|[1-9][\\\\d]{0,3}|[1-5][\\\\d]{4}|6[0-4][\\\\d]{3}|65[0-4][\\\\d]{2}|655[0-2][\\\\d]|6553[0-5])\\\\b) \\\\.\\\\. ([vp](?:0|[1-9][\\\\d]{0,3}|[1-5][\\\\d]{4}|6[0-4][\\\\d]{3}|65[0-4][\\\\d]{2}|655[0-2][\\\\d]|6553[0-5])\\\\b)[\\\\s\\\\t]*},[\\\\s\\\\t]*[\\\\[]*(L)([\\\\p{L}_\\\\$][\\\\p{L}\\\\d_\\\\$]*(?:\\/[\\\\p{L}_\\\\$][\\\\p{L}\\\\d_\\\\$]*)*)(;)->(<init>|<clinit>|(?:[\\\\$\\\\p{L}_][\\\\p{L}\\\\d_\\\\$]*))\\\\(((?:[\\\\[]*(?:Z|B|S|C|I|J|F|D|L(?:[\\\\p{L}_\\\\$][\\\\p{L}\\\\d_\\\\$]*(?:\\/[\\\\p{L}_\\\\$][\\\\p{L}\\\\d_\\\\$]*)*);))*)\\\\)(?:(V)|[\\\\[]*(Z|B|S|C|I|J|F|D)|[\\\\[]*(?:(L)([\\\\p{L}_\\\\$][\\\\p{L}\\\\d_\\\\$]*(?:\\/[\\\\p{L}_\\\\$][\\\\p{L}\\\\d_\\\\$]*)*)(;)))(?=[\\\\s\\\\t]*(#.*)?$)\",\n      \"captures\":{\n        \"1\": { \"name\": \"support.function.smali\" },\n        \"2\": { \"name\": \"variable.parameter.smali\" },\n        \"3\": { \"name\": \"variable.parameter.smali\" },\n        \"4\": { \"name\": \"entity.name.tag.smali\" },\n        \"5\": { \"name\": \"constant.numeric.smali\" },\n        \"6\": { \"name\": \"entity.name.tag.smali\" },\n        \"7\": { \"name\": \"entity.name.function.smali\" },\n        \"8\": { \"name\": \"constant.numeric.smali\" },\n        \"9\": { \"name\": \"constant.numeric.smali\" },\n        \"10\": { \"name\": \"constant.numeric.smali\" },\n        \"11\": { \"name\": \"entity.name.tag.smali\" },\n        \"12\": { \"name\": \"constant.numeric.smali\" },\n        \"13\": { \"name\": \"entity.name.tag.smali\" },\n        \"14\": { \"name\": \"constant.numeric.smali\" },\n        \"15\": { \"name\": \"entity.name.tag.smali\" }\n      }\n    },\n    \"opcode-format-3rc-relaxed\": {\n      \"match\": \"^[\\\\s\\\\t]*((?:filled-new-array|invoke-(?:virtual|super|direct|static|interface))\\/range)\",\n      \"captures\": { \"1\": { \"name\": \"invalid.illegal.smali\" }}\n    },\n    \"opcode-format-35c-type\": {\n      \"comment\": \"Format: op {vC, vD, vE, vF, vG}, type@BBBB\",\n      \"match\": \"^[\\\\s\\\\t]*(filled-new-array) {([vp](?:0|[1-9]|1[0-5])\\\\b),[\\\\s\\\\t]*([vp](?:0|[1-9]|1[0-5])\\\\b)(?:,[\\\\s\\\\t]*([vp](?:0|[1-9]|1[0-5])\\\\b))?(?:,[\\\\s\\\\t]*([vp](?:0|[1-9]|1[0-5])\\\\b))?(?:,[\\\\s\\\\t]*([vp](?:0|[1-9]|1[0-5])\\\\b))?},[\\\\s\\\\t]*[\\\\[]+(?:(Z|B|S|C|I|J|F|D)|(L)([\\\\p{L}_\\\\$][\\\\p{L}\\\\d_\\\\$]*(?:\\/[\\\\p{L}_\\\\$][\\\\p{L}\\\\d_\\\\$]*)*)(;))(?=[\\\\s\\\\t]*(#.*)?$)\",\n      \"captures\":{\n        \"1\": { \"name\": \"support.function.smali\" },\n        \"2\": { \"name\": \"variable.parameter.smali\" },\n        \"3\": { \"name\": \"variable.parameter.smali\" },\n        \"4\": { \"name\": \"variable.parameter.smali\" },\n        \"5\": { \"name\": \"variable.parameter.smali\" },\n        \"6\": { \"name\": \"variable.parameter.smali\" },\n        \"7\": { \"name\": \"constant.numeric.smali\" },\n        \"8\": { \"name\": \"entity.name.tag.smali\" },\n        \"9\": { \"name\": \"constant.numeric.smali\" },\n        \"10\": { \"name\": \"entity.name.tag.smali\" },\n        \"11\": { \"name\": \"constant.numeric.smali\" }\n      }\n    },\n    \"opcode-format-35c-meth\": {\n      \"comment\": \"Format: op {vC, vD, vE, vF, vG}, meth@BBBB\",\n      \"match\": \"^[\\\\s\\\\t]*(invoke-(?:virtual|super|direct|static|interface)) {[\\\\s\\\\t]*([vp](?:0|[1-9]|1[0-5])\\\\b)?(?:,[\\\\s\\\\t]*([vp](?:0|[1-9]|1[0-5])\\\\b))?(?:,[\\\\s\\\\t]*([vp](?:0|[1-9]|1[0-5])\\\\b))?(?:,[\\\\s\\\\t]*([vp](?:0|[1-9]|1[0-5])\\\\b))?(?:,[\\\\s\\\\t]*([vp](?:0|[1-9]|1[0-5])\\\\b))?[\\\\s\\\\t]*},[\\\\s\\\\t]*[\\\\[]*(L)([\\\\p{L}_\\\\$][\\\\p{L}\\\\d_\\\\$]*(?:\\/[\\\\p{L}_\\\\$][\\\\p{L}\\\\d_\\\\$]*)*)(;)->(<init>|<clinit>|(?:[\\\\$\\\\p{L}_][\\\\p{L}\\\\d_\\\\$]*))\\\\((?:[\\\\[]*(Z|B|S|C|I|J|F|D)|(?:[\\\\[]*(L)([\\\\p{L}_\\\\$][\\\\p{L}\\\\d_\\\\$]*(?:\\/[\\\\p{L}_\\\\$][\\\\p{L}\\\\d_\\\\$]*)*)(;)))?(?:[\\\\[]*(Z|B|S|C|I|J|F|D)|(?:[\\\\[]*(L)([\\\\p{L}_\\\\$][\\\\p{L}\\\\d_\\\\$]*(?:\\/[\\\\p{L}_\\\\$][\\\\p{L}\\\\d_\\\\$]*)*)(;)))?(?:[\\\\[]*(Z|B|S|C|I|J|F|D)|(?:[\\\\[]*(L)([\\\\p{L}_\\\\$][\\\\p{L}\\\\d_\\\\$]*(?:\\/[\\\\p{L}_\\\\$][\\\\p{L}\\\\d_\\\\$]*)*)(;)))?(?:[\\\\[]*(Z|B|S|C|I|J|F|D)|(?:[\\\\[]*(L)([\\\\p{L}_\\\\$][\\\\p{L}\\\\d_\\\\$]*(?:\\/[\\\\p{L}_\\\\$][\\\\p{L}\\\\d_\\\\$]*)*)(;)))?(?:[\\\\[]*(Z|B|S|C|I|J|F|D)|(?:[\\\\[]*(L)([\\\\p{L}_\\\\$][\\\\p{L}\\\\d_\\\\$]*(?:\\/[\\\\p{L}_\\\\$][\\\\p{L}\\\\d_\\\\$]*)*)(;)))?\\\\)(?:(?:(V)|[\\\\[]*(Z|B|S|C|I|J|F|D))|(?:[\\\\[]*(L)([\\\\p{L}_\\\\$][\\\\p{L}\\\\d_\\\\$]*(?:\\/[\\\\p{L}_\\\\$][\\\\p{L}\\\\d_\\\\$]*)*)(;)))(?=[\\\\s\\\\t]*(#.*)?$)\",\n      \"captures\":{\n        \"1\": { \"name\": \"support.function.smali\" },\n        \"2\": { \"name\": \"variable.parameter.smali\" },\n        \"3\": { \"name\": \"variable.parameter.smali\" },\n        \"4\": { \"name\": \"variable.parameter.smali\" },\n        \"5\": { \"name\": \"variable.parameter.smali\" },\n        \"6\": { \"name\": \"variable.parameter.smali\" },\n        \"7\": { \"name\": \"entity.name.tag.smali\" },\n        \"8\": { \"name\": \"constant.numeric.smali\" },\n        \"9\": { \"name\": \"entity.name.tag.smali\" },\n        \"10\": { \"name\": \"entity.name.function.smali\" },\n        \"11\": { \"name\": \"constant.numeric.smali\" },\n        \"12\": { \"name\": \"entity.name.tag.smali\" },\n        \"13\": { \"name\": \"constant.numeric.smali\" },\n        \"14\": { \"name\": \"entity.name.tag.smali\" },\n        \"15\": { \"name\": \"constant.numeric.smali\" },\n        \"16\": { \"name\": \"entity.name.tag.smali\" },\n        \"17\": { \"name\": \"constant.numeric.smali\" },\n        \"18\": { \"name\": \"entity.name.tag.smali\" },\n        \"19\": { \"name\": \"constant.numeric.smali\" },\n        \"20\": { \"name\": \"entity.name.tag.smali\" },\n        \"21\": { \"name\": \"constant.numeric.smali\" },\n        \"22\": { \"name\": \"entity.name.tag.smali\" },\n        \"23\": { \"name\": \"constant.numeric.smali\" },\n        \"24\": { \"name\": \"entity.name.tag.smali\" },\n        \"25\": { \"name\": \"constant.numeric.smali\" },\n        \"26\": { \"name\": \"entity.name.tag.smali\" },\n        \"27\": { \"name\": \"constant.numeric.smali\" },\n        \"28\": { \"name\": \"entity.name.tag.smali\" },\n        \"29\": { \"name\": \"constant.numeric.smali\" },\n        \"30\": { \"name\": \"entity.name.tag.smali\" },\n        \"31\": { \"name\": \"constant.numeric.smali\" },\n        \"32\": { \"name\": \"constant.numeric.smali\" },\n        \"33\": { \"name\": \"entity.name.tag.smali\" },\n        \"34\": { \"name\": \"constant.numeric.smali\" },\n        \"35\": { \"name\": \"entity.name.tag.smali\" }\n      }\n    },\n    \"opcode-format-35c-relaxed\": {\n      \"match\": \"^[\\\\s\\\\t]*(filled-new-array|invoke-(?:virtual|super|direct|static|interface))\",\n      \"captures\": { \"1\": { \"name\": \"invalid.illegal.smali\" }}\n    },\n    \"opcode-format-51l\": {\n      \"comment\": \"Format: op vAA, #+BBBBBBBBBBBBBBBB\",\n      \"match\": \"^[\\\\s\\\\t]*(const-wide)(?!\\/32)[\\\\s\\\\t]+([vp](?:0|[1-9][\\\\d]?|1[\\\\d]{2}|2[0-4][\\\\d]|25[0-5])\\\\b),[\\\\s\\\\t]*(?i:((?:-0x(?:0|[1-9a-f][\\\\da-f]{0,6}|[1-7][\\\\da-f]{7}|8[0]{7})|0x(?:0|[1-9a-f][\\\\da-f]{0,6}|[1-7][\\\\da-f]{7}))|(?:(?:-0x(?:0|[1-9a-f][\\\\da-f]{0,14}|[1-7][\\\\da-f]{15}|8[0]{15})|0x(?:0|[1-9a-f][\\\\da-f]{0,14}|[1-7][\\\\da-f]{15}))L))\\\\b)(?=[\\\\s\\\\t]*(#.*)?$)\",\n      \"captures\":{\n        \"1\": { \"name\": \"support.function.smali\" },\n        \"2\": { \"name\": \"variable.parameter.smali\" },\n        \"3\": { \"name\": \"constant.numeric.smali\" }\n      }\n    },\n    \"opcode-format-51l-relaxed\": {\n      \"match\": \"^[\\\\s\\\\t]*(const-wide)(?!\\\\\\/32)\",\n      \"captures\": { \"1\": { \"name\": \"invalid.illegal.smali\" }}\n    },\n    \"opcode-format-31i\": {\n      \"comment\": \"Format: op vAA, #+BBBBBBBB\",\n      \"match\": \"^[\\\\s\\\\t]*(const(?:-wide\\/32)?)[\\\\s\\\\t]+([vp](?:0|[1-9][\\\\d]?|1[\\\\d]{2}|2[0-4][\\\\d]|25[0-5])\\\\b),[\\\\s\\\\t]*(?i:(-0x(?:0|[1-9a-f][\\\\da-f]{0,6}|[1-7][\\\\da-f]{7}|8[0]{7})|0x(?:0|[1-9a-f][\\\\da-f]{0,6}|[1-7][\\\\da-f]{7}))\\\\b)(?=[\\\\s\\\\t]*(#.*)?$)\",\n      \"captures\":{\n        \"1\": { \"name\": \"support.function.smali\" },\n        \"2\": { \"name\": \"variable.parameter.smali\" },\n        \"3\": { \"name\": \"constant.numeric.smali\" }\n      }\n    },\n    \"opcode-format-31i-relaxed\": {\n      \"match\": \"^[\\\\s\\\\t]*(const(?:-wide\\/32)?)\",\n      \"captures\": { \"1\": { \"name\": \"invalid.illegal.smali\" }}\n    },\n    \"opcode-format-10t-20t-30t\": {\n      \"comment\": \"Format: op +AA(AA(AAAA))\",\n      \"match\": \"^[\\\\s\\\\t]*(goto(?:\\/16|\\/32)?) (:[A-Za-z_\\\\d]+)(?=[\\\\s\\\\t]*(#.*)?$)\",\n      \"captures\":{\n        \"1\": { \"name\": \"support.function.smali\" },\n        \"2\": { \"name\": \"keyword.control\" }\n      }\n    },\n    \"opcode-format-10t-20t-30t-relaxed\": {\n      \"match\": \"^[\\\\s\\\\t]*(goto(?:\\/16|\\/32)?)\",\n      \"captures\": { \"1\": { \"name\": \"invalid.illegal.smali\" }}\n    }\n  },\n  \"uuid\": \"d6fe4632-f21a-4533-8908-723df0b58ac0\"\n}\n"
  },
  {
    "path": "app/src/main/assets/languages/xml/language-configuration.json",
    "content": "{\n  \"comments\": {\n    \"blockComment\": [ \"<!--\", \"-->\" ]\n  },\n  \"brackets\": [\n    [\"<!--\", \"-->\"],\n    [\"<\", \">\"],\n    [\"{\", \"}\"],\n    [\"(\", \")\"]\n  ],\n  \"autoClosingPairs\": [\n    { \"open\": \"{\", \"close\": \"}\"},\n    { \"open\": \"[\", \"close\": \"]\"},\n    { \"open\": \"(\", \"close\": \")\" },\n    { \"open\": \"\\\"\", \"close\": \"\\\"\", \"notIn\": [\"string\"] },\n    { \"open\": \"'\", \"close\": \"'\", \"notIn\": [\"string\"] },\n    { \"open\": \"<!--\", \"close\": \"-->\", \"notIn\": [ \"comment\", \"string\" ]},\n    { \"open\": \"<![CDATA[\", \"close\": \"]]>\", \"notIn\": [ \"comment\", \"string\" ]}\n  ],\n  \"surroundingPairs\": [\n    { \"open\": \"'\", \"close\": \"'\" },\n    { \"open\": \"\\\"\", \"close\": \"\\\"\" },\n    { \"open\": \"{\", \"close\": \"}\"},\n    { \"open\": \"[\", \"close\": \"]\"},\n    { \"open\": \"(\", \"close\": \")\" },\n    { \"open\": \"<\", \"close\": \">\" }\n  ],\n  \"colorizedBracketPairs\": [\n  ],\n  \"folding\": {\n    \"markers\": {\n      \"start\": \"^\\\\s*<!--\\\\s*#region\\\\b.*-->\",\n      \"end\": \"^\\\\s*<!--\\\\s*#endregion\\\\b.*-->\"\n    }\n  },\n  \"wordPattern\": \"[:A-Z_a-z\\\\u{C0}-\\\\u{D6}\\\\u{D8}-\\\\u{F6}\\\\u{F8}-\\\\u{2FF}\\\\u{370}-\\\\u{37D}\\\\u{37F}-\\\\u{1FFF}\\\\u{200C}-\\\\u{200D}\\\\u{2070}-\\\\u{218F}\\\\u{2C00}-\\\\u{2FEF}\\\\u{3001}-\\\\u{D7FF}\\\\u{F900}-\\\\u{FDCF}\\\\u{FDF0}-\\\\u{FFFD}\\\\u{10000}-\\\\u{EFFFF}][-:A-Z_a-z\\\\u{C0}-\\\\u{D6}\\\\u{D8}-\\\\u{F6}\\\\u{F8}-\\\\u{2FF}\\\\u{370}-\\\\u{37D}\\\\u{37F}-\\\\u{1FFF}\\\\u{200C}-\\\\u{200D}\\\\u{2070}-\\\\u{218F}\\\\u{2C00}-\\\\u{2FEF}\\\\u{3001}-\\\\u{D7FF}\\\\u{F900}-\\\\u{FDCF}\\\\u{FDF0}-\\\\u{FFFD}\\\\u{10000}-\\\\u{EFFFF}.0-9\\\\u{B7}\\\\u{0300}-\\\\u{036F}\\\\u{203F}-\\\\u{2040}]*\"\n}\n"
  },
  {
    "path": "app/src/main/assets/languages/xml/tmLanguage.json",
    "content": "{\n  \"scopeName\": \"text.xml\",\n  \"name\": \"XML\",\n  \"fileTypes\": [\n    \"aiml\",\n    \"atom\",\n    \"axml\",\n    \"bpmn\",\n    \"config\",\n    \"cpt\",\n    \"csl\",\n    \"csproj\",\n    \"csproj.user\",\n    \"dae\",\n    \"dia\",\n    \"dita\",\n    \"ditamap\",\n    \"dtml\",\n    \"fodg\",\n    \"fodp\",\n    \"fods\",\n    \"fodt\",\n    \"fsproj\",\n    \"fxml\",\n    \"gir\",\n    \"glade\",\n    \"gpx\",\n    \"graphml\",\n    \"icls\",\n    \"iml\",\n    \"isml\",\n    \"jmx\",\n    \"jsp\",\n    \"kml\",\n    \"kst\",\n    \"launch\",\n    \"menu\",\n    \"mxml\",\n    \"nunit\",\n    \"nuspec\",\n    \"opml\",\n    \"owl\",\n    \"pom\",\n    \"ppj\",\n    \"proj\",\n    \"pt\",\n    \"pubxml\",\n    \"pubxml.user\",\n    \"rdf\",\n    \"rng\",\n    \"rss\",\n    \"sdf\",\n    \"shproj\",\n    \"siml\",\n    \"sld\",\n    \"storyboard\",\n    \"StyleCop\",\n    \"svg\",\n    \"targets\",\n    \"tld\",\n    \"vbox\",\n    \"vbox-prev\",\n    \"vbproj\",\n    \"vbproj.user\",\n    \"vcproj\",\n    \"vcproj.filters\",\n    \"vcxproj\",\n    \"vcxproj.filters\",\n    \"wixmsp\",\n    \"wixmst\",\n    \"wixobj\",\n    \"wixout\",\n    \"wsdl\",\n    \"wxs\",\n    \"xaml\",\n    \"xbl\",\n    \"xib\",\n    \"xlf\",\n    \"xliff\",\n    \"xml\",\n    \"xpdl\",\n    \"xsd\",\n    \"xul\",\n    \"ui\"\n  ],\n  \"firstLineMatch\": \"(?x)\\n# XML declaration\\n(?:\\n  ^ <\\\\? xml\\n\\n  # VersionInfo\\n  \\\\s+ version\\n  \\\\s* = \\\\s*\\n  (['\\\"])\\n    1 \\\\. [0-9]+\\n  \\\\1\\n\\n  # EncodingDecl\\n  (?:\\n    \\\\s+ encoding\\n    \\\\s* = \\\\s*\\n\\n    # EncName\\n    (['\\\"])\\n      [A-Za-z]\\n      [-A-Za-z0-9._]*\\n    \\\\2\\n  )?\\n\\n  # SDDecl\\n  (?:\\n    \\\\s+ standalone\\n    \\\\s* = \\\\s*\\n    (['\\\"])\\n      (?:yes|no)\\n    \\\\3\\n  )?\\n\\n  \\\\s* \\\\?>\\n)\\n|\\n# Modeline\\n(?i:\\n  # Emacs\\n  -\\\\*-(?:\\\\s*(?=[^:;\\\\s]+\\\\s*-\\\\*-)|(?:.*?[;\\\\s]|(?<=-\\\\*-))mode\\\\s*:\\\\s*)\\n    xml\\n  (?=[\\\\s;]|(?<![-*])-\\\\*-).*?-\\\\*-\\n  |\\n  # Vim\\n  (?:(?:\\\\s|^)vi(?:m[<=>]?\\\\d+|m)?|\\\\sex)(?=:(?=\\\\s*set?\\\\s[^\\\\n:]+:)|:(?!\\\\s*set?\\\\s))(?:(?:\\\\s|\\\\s*:\\\\s*)\\\\w*(?:\\\\s*=(?:[^\\\\n\\\\\\\\\\\\s]|\\\\\\\\.)*)?)*[\\\\s:](?:filetype|ft|syntax)\\\\s*=\\n    xml\\n  (?=\\\\s|:|$)\\n)\",\n  \"patterns\": [\n    {\n      \"begin\": \"(<\\\\?)\\\\s*([-_a-zA-Z0-9]+)\",\n      \"captures\": {\n        \"1\": {\n          \"name\": \"punctuation.definition.tag.xml\"\n        },\n        \"2\": {\n          \"name\": \"entity.name.tag.xml\"\n        }\n      },\n      \"end\": \"(\\\\?>)\",\n      \"name\": \"meta.tag.preprocessor.xml\",\n      \"patterns\": [\n        {\n          \"match\": \" ([a-zA-Z-]+)\",\n          \"name\": \"entity.other.attribute-name.xml\"\n        },\n        {\n          \"include\": \"#doublequotedString\"\n        },\n        {\n          \"include\": \"#singlequotedString\"\n        }\n      ]\n    },\n    {\n      \"begin\": \"(<!)(DOCTYPE)\\\\s+([:a-zA-Z_][:a-zA-Z0-9_.-]*)\",\n      \"captures\": {\n        \"1\": {\n          \"name\": \"punctuation.definition.tag.xml\"\n        },\n        \"2\": {\n          \"name\": \"keyword.other.doctype.xml\"\n        },\n        \"3\": {\n          \"name\": \"variable.language.documentroot.xml\"\n        }\n      },\n      \"end\": \"\\\\s*(>)\",\n      \"name\": \"meta.tag.sgml.doctype.xml\",\n      \"patterns\": [\n        {\n          \"include\": \"#internalSubset\"\n        }\n      ]\n    },\n    {\n      \"include\": \"#comments\"\n    },\n    {\n      \"begin\": \"(<)((?:([-_a-zA-Z0-9]+)(:))?([-_a-zA-Z0-9:]+))(?=(\\\\s[^>]*)?></\\\\2>)\",\n      \"beginCaptures\": {\n        \"1\": {\n          \"name\": \"punctuation.definition.tag.xml\"\n        },\n        \"2\": {\n          \"name\": \"entity.name.tag.xml\"\n        },\n        \"3\": {\n          \"name\": \"entity.name.tag.namespace.xml\"\n        },\n        \"4\": {\n          \"name\": \"punctuation.separator.namespace.xml\"\n        },\n        \"5\": {\n          \"name\": \"entity.name.tag.localname.xml\"\n        }\n      },\n      \"end\": \"(>)(</)((?:([-_a-zA-Z0-9]+)(:))?([-_a-zA-Z0-9:]+))(>)\",\n      \"endCaptures\": {\n        \"1\": {\n          \"name\": \"punctuation.definition.tag.xml\"\n        },\n        \"2\": {\n          \"name\": \"punctuation.definition.tag.xml\"\n        },\n        \"3\": {\n          \"name\": \"entity.name.tag.xml\"\n        },\n        \"4\": {\n          \"name\": \"entity.name.tag.namespace.xml\"\n        },\n        \"5\": {\n          \"name\": \"punctuation.separator.namespace.xml\"\n        },\n        \"6\": {\n          \"name\": \"entity.name.tag.localname.xml\"\n        },\n        \"7\": {\n          \"name\": \"punctuation.definition.tag.xml\"\n        }\n      },\n      \"name\": \"meta.tag.no-content.xml\",\n      \"patterns\": [\n        {\n          \"include\": \"#tagStuff\"\n        }\n      ]\n    },\n    {\n      \"begin\": \"(</?)(?:([-\\\\w\\\\.]+)((:)))?([-\\\\w\\\\.:]+)\",\n      \"captures\": {\n        \"1\": {\n          \"name\": \"punctuation.definition.tag.xml\"\n        },\n        \"2\": {\n          \"name\": \"entity.name.tag.namespace.xml\"\n        },\n        \"3\": {\n          \"name\": \"entity.name.tag.xml\"\n        },\n        \"4\": {\n          \"name\": \"punctuation.separator.namespace.xml\"\n        },\n        \"5\": {\n          \"name\": \"entity.name.tag.localname.xml\"\n        }\n      },\n      \"end\": \"(/?>)\",\n      \"name\": \"meta.tag.xml\",\n      \"patterns\": [\n        {\n          \"include\": \"#tagStuff\"\n        }\n      ]\n    },\n    {\n      \"include\": \"#entity\"\n    },\n    {\n      \"include\": \"#bare-ampersand\"\n    },\n    {\n      \"begin\": \"<%@\",\n      \"beginCaptures\": {\n        \"0\": {\n          \"name\": \"punctuation.section.embedded.begin.xml\"\n        }\n      },\n      \"end\": \"%>\",\n      \"endCaptures\": {\n        \"0\": {\n          \"name\": \"punctuation.section.embedded.end.xml\"\n        }\n      },\n      \"name\": \"source.java-props.embedded.xml\",\n      \"patterns\": [\n        {\n          \"match\": \"page|include|taglib\",\n          \"name\": \"keyword.other.page-props.xml\"\n        }\n      ]\n    },\n    {\n      \"begin\": \"<%[!=]?(?!--)\",\n      \"beginCaptures\": {\n        \"0\": {\n          \"name\": \"punctuation.section.embedded.begin.xml\"\n        }\n      },\n      \"end\": \"(?!--)%>\",\n      \"endCaptures\": {\n        \"0\": {\n          \"name\": \"punctuation.section.embedded.end.xml\"\n        }\n      },\n      \"name\": \"source.java.embedded.xml\",\n      \"patterns\": [\n        {\n          \"include\": \"source.java\"\n        }\n      ]\n    },\n    {\n      \"begin\": \"<!\\\\[CDATA\\\\[\",\n      \"beginCaptures\": {\n        \"0\": {\n          \"name\": \"punctuation.definition.string.begin.xml\"\n        }\n      },\n      \"end\": \"]]>\",\n      \"endCaptures\": {\n        \"0\": {\n          \"name\": \"punctuation.definition.string.end.xml\"\n        }\n      },\n      \"name\": \"string.unquoted.cdata.xml\"\n    }\n  ],\n  \"repository\": {\n    \"EntityDecl\": {\n      \"begin\": \"(<!)(ENTITY)\\\\s+(%\\\\s+)?([:a-zA-Z_][:a-zA-Z0-9_.-]*)(\\\\s+(?:SYSTEM|PUBLIC)\\\\s+)?\",\n      \"captures\": {\n        \"1\": {\n          \"name\": \"punctuation.definition.tag.xml\"\n        },\n        \"2\": {\n          \"name\": \"keyword.other.entity.xml\"\n        },\n        \"3\": {\n          \"name\": \"punctuation.definition.entity.xml\"\n        },\n        \"4\": {\n          \"name\": \"variable.language.entity.xml\"\n        },\n        \"5\": {\n          \"name\": \"keyword.other.entitytype.xml\"\n        }\n      },\n      \"end\": \"(>)\",\n      \"patterns\": [\n        {\n          \"include\": \"#doublequotedString\"\n        },\n        {\n          \"include\": \"#singlequotedString\"\n        }\n      ]\n    },\n    \"bare-ampersand\": {\n      \"match\": \"&\",\n      \"name\": \"invalid.illegal.bad-ampersand.xml\"\n    },\n    \"doublequotedString\": {\n      \"begin\": \"\\\"\",\n      \"beginCaptures\": {\n        \"0\": {\n          \"name\": \"punctuation.definition.string.begin.xml\"\n        }\n      },\n      \"end\": \"\\\"\",\n      \"endCaptures\": {\n        \"0\": {\n          \"name\": \"punctuation.definition.string.end.xml\"\n        }\n      },\n      \"name\": \"string.quoted.double.xml\",\n      \"patterns\": [\n        {\n          \"include\": \"#entity\"\n        },\n        {\n          \"include\": \"#bare-ampersand\"\n        }\n      ]\n    },\n    \"entity\": {\n      \"captures\": {\n        \"1\": {\n          \"name\": \"punctuation.definition.constant.xml\"\n        },\n        \"3\": {\n          \"name\": \"punctuation.definition.constant.xml\"\n        }\n      },\n      \"match\": \"(&)([:a-zA-Z_][:a-zA-Z0-9_.-]*|#[0-9]+|#x[0-9a-fA-F]+)(;)\",\n      \"name\": \"constant.character.entity.xml\"\n    },\n    \"internalSubset\": {\n      \"begin\": \"(\\\\[)\",\n      \"captures\": {\n        \"1\": {\n          \"name\": \"punctuation.definition.constant.xml\"\n        }\n      },\n      \"end\": \"(\\\\])\",\n      \"name\": \"meta.internalsubset.xml\",\n      \"patterns\": [\n        {\n          \"include\": \"#EntityDecl\"\n        },\n        {\n          \"include\": \"#parameterEntity\"\n        },\n        {\n          \"include\": \"#comments\"\n        }\n      ]\n    },\n    \"parameterEntity\": {\n      \"captures\": {\n        \"1\": {\n          \"name\": \"punctuation.definition.constant.xml\"\n        },\n        \"3\": {\n          \"name\": \"punctuation.definition.constant.xml\"\n        }\n      },\n      \"match\": \"(%)([:a-zA-Z_][:a-zA-Z0-9_.-]*)(;)\",\n      \"name\": \"constant.character.parameter-entity.xml\"\n    },\n    \"singlequotedString\": {\n      \"begin\": \"'\",\n      \"beginCaptures\": {\n        \"0\": {\n          \"name\": \"punctuation.definition.string.begin.xml\"\n        }\n      },\n      \"end\": \"'\",\n      \"endCaptures\": {\n        \"0\": {\n          \"name\": \"punctuation.definition.string.end.xml\"\n        }\n      },\n      \"name\": \"string.quoted.single.xml\",\n      \"patterns\": [\n        {\n          \"include\": \"#entity\"\n        },\n        {\n          \"include\": \"#bare-ampersand\"\n        }\n      ]\n    },\n    \"tagStuff\": {\n      \"patterns\": [\n        {\n          \"captures\": {\n            \"1\": {\n              \"name\": \"entity.other.attribute-name.namespace.xml\"\n            },\n            \"2\": {\n              \"name\": \"entity.other.attribute-name.xml\"\n            },\n            \"3\": {\n              \"name\": \"punctuation.separator.namespace.xml\"\n            },\n            \"4\": {\n              \"name\": \"entity.other.attribute-name.localname.xml\"\n            }\n          },\n          \"match\": \"(?:^|\\\\s+)(?:([-\\\\w.]+)((:)))?([-\\\\w.:]+)\\\\s*=\"\n        },\n        {\n          \"include\": \"#doublequotedString\"\n        },\n        {\n          \"include\": \"#singlequotedString\"\n        }\n      ]\n    }\n  }\n}\n"
  },
  {
    "path": "app/src/main/assets/run_server.sh",
    "content": "#!/system/bin/sh\n# SPDX-License-Identifier: GPL-3.0-or-later\n\nif [ $# -lt 2 ]; then\n    echo \"USAGE: ./run_server.sh <path|port> <token>\"\n    exit 1\nfi\n\nSERVER_NAME=\nJAR_NAME=\nJAR_PATH=\n%ENV_VARS%\nPORT=\"path:$1\"\nTOKEN=\",token:$2\"\nARGS=\"${PORT}${ARGS}${TOKEN}\"\nJAR_PACKAGE_NAME=\"io.github.muntashirakon.AppManager\"\nJAR_MAIN_CLASS=\"${JAR_PACKAGE_NAME}.server.ServerRunner\"\nTMP_PATH=\"/data/local/tmp\"\nEXEC_JAR_PATH=${TMP_PATH}/${JAR_NAME}\n# Ideally, id -u could be used, but it's not supported on older platforms\n# neither are commands like awk or sed, we're only left with grep.\nUID=$(id | grep -oE \"uid=[0-9]+\" | grep -oE \"[0-9]+\")\nGID=$(id | grep -oE \"gid=[0-9]+\" | grep -oE \"[0-9]+\")\n\necho \"Starting $SERVER_NAME as $UID:$GID...\"\n# Copy am.jar to executable directory\ncp -f ${JAR_PATH} ${EXEC_JAR_PATH}\nif [ $? -ne 0 ]; then\n    # Copy failed\n    echo \"Error! Could not copy jar file to the executable directory.\"\n    exit 1\nfi\n# Fix permission\nchmod 755 ${EXEC_JAR_PATH}\nchown $UID:$GID ${EXEC_JAR_PATH}\n# Debug log\necho \"Jar path: $JAR_PATH\"\necho \"Args: $ARGS\"\n# Save jar path to environment variable\nexport CLASSPATH=${EXEC_JAR_PATH}\n# Execute local server\nexec app_process /system/bin --nice-name=${SERVER_NAME} ${JAR_MAIN_CLASS} \"$ARGS\" $@  &\nif [ $? -ne 0 ]; then\n    # Start failed\n    echo \"Error! Could not start local server.\"\n    exit 1\nelse\n    # Start success\n    echo \"Local server has started.\"\n    exit 0\nfi\n"
  },
  {
    "path": "app/src/main/assets/suggestions.json",
    "content": "[{\"id\":\"com.aurora.store\",\"label\":\"Aurora Store\",\"reason\":\"Alternative Google Play Store client with privacy in mind.\\nhttps:\\/\\/aurora-oss.vercel.app\\/faq\\/#aurora-store\",\"source\":\"f\",\"repo\":\"https:\\/\\/gitlab.com\\/AuroraOSS\\/AuroraStore\",\"_id\":\"app_stores\"},{\"id\":\"com.looker.droidify\",\"label\":\"Droid-ify\",\"source\":\"f\",\"repo\":\"https:\\/\\/github.com\\/Iamlooker\\/Droid-ify\",\"_id\":\"app_stores\"},{\"id\":\"com.dimowner.audiorecorder\",\"label\":\"Audio Recorder\",\"source\":\"fg\",\"repo\":\"https:\\/\\/github.com\\/Dimowner\\/AudioRecorder\",\"_id\":\"audio_recorders\"},{\"id\":\"com.beemdevelopment.aegis\",\"label\":\"Aegis\",\"source\":\"fg\",\"repo\":\"https:\\/\\/github.com\\/beemdevelopment\\/Aegis\",\"_id\":\"authenticators\"},{\"id\":\"com.jens.automation2\",\"label\":\"Automation\",\"source\":\"f\",\"repo\":\"https:\\/\\/git.server47.de\\/jens\\/Automation\",\"_id\":\"automation_apps\"},{\"id\":\"com.machiav3lli.backup\",\"label\":\"Neo Backup\",\"source\":\"f\",\"repo\":\"https:\\/\\/github.com\\/NeoApplications\\/Neo-Backup\",\"_id\":\"backup_apps\"},{\"id\":\"com.atharok.barcodescanner\",\"label\":\"Barcode Scanner\",\"source\":\"fga\",\"repo\":\"https:\\/\\/gitlab.com\\/Atharok\\/BarcodeScanner\",\"_id\":\"barcode_scanners\"},{\"id\":\"org.chromium.chrome\",\"label\":\"Vanadium\",\"repo\":\"https:\\/\\/github.com\\/GrapheneOS\\/Vanadium\",\"reason\":\"GrapheneOS only\",\"_id\":\"browsers\"},{\"id\":\"org.cromite.cromite\",\"label\":\"Cromite\",\"source\":\"f\",\"repo\":\"https:\\/\\/github.com\\/uazo\\/cromite\",\"_id\":\"browsers\"},{\"id\":\"org.solovyev.android.calculator\",\"label\":\"Calculator++\",\"source\":\"fg\",\"repo\":\"https:\\/\\/git.bubu1.eu\\/Bubu\\/android-calculatorpp\",\"_id\":\"calculators\"},{\"id\":\"ws.xsoh.etar\",\"label\":\"Etar\",\"source\":\"fg\",\"repo\":\"https:\\/\\/github.com\\/Etar-Group\\/Etar-Calendar\",\"_id\":\"calendars\"},{\"id\":\"app.grapheneos.camera\",\"label\":\"Camera\",\"repo\":\"https:\\/\\/github.com\\/GrapheneOS\\/Camera\",\"_id\":\"cameras\"},{\"id\":\"net.sourceforge.opencamera\",\"label\":\"Open Camera\",\"source\":\"fg\",\"reason\":\"A more advanced camera app\",\"repo\":\"https:\\/\\/sourceforge.net\\/projects\\/opencamera\\/\",\"_id\":\"cameras\"},{\"id\":\"eu.darken.sdmse\",\"label\":\"SD Maid SE\",\"source\":\"g\",\"repo\":\"https:\\/\\/github.com\\/d4rken-org\\/sdmaid-se\",\"_id\":\"cleaners\"},{\"id\":\"itkach.aard2\",\"label\":\"Aard 2\",\"reason\":\"Simple yet powerful dictionary reader that support multiple dictionaries with offline access.\\nSLOB files https:\\/\\/github.com\\/itkach\\/slob\\/wiki\\/Dictionaries\",\"source\":\"fg\",\"repo\":\"https:\\/\\/github.com\\/itkach\\/aard2-android\",\"_id\":\"dictionaries\"},{\"id\":\"com.foobnix.pro.pdf.reader\",\"label\":\"Librera\",\"source\":\"fg\",\"repo\":\"https:\\/\\/github.com\\/foobnix\\/LibreraReader\",\"_id\":\"ebook_readers\"},{\"id\":\"org.koreader.launcher.fdroid\",\"label\":\"KOReader\",\"source\":\"f\",\"repo\":\"https:\\/\\/github.com\\/koreader\\/koreader\",\"reason\":\"Optimized for e-ink displays\",\"_id\":\"ebook_readers\"},{\"id\":\"net.thunderbird.android\",\"label\":\"Thunderbird\",\"source\":\"fg\",\"reason\":\"https:\\/\\/blog.thunderbird.net\\/2023\\/07\\/k-9-mail-collaborates-with-ostif-and-7asecurity-security-audit\\/\",\"repo\":\"https:\\/\\/github.com\\/thunderbird\\/thunderbird-android\",\"_id\":\"email_clients\"},{\"id\":\"me.zhanghai.android.files\",\"label\":\"Material Files\",\"source\":\"fg\",\"repo\":\"https:\\/\\/github.com\\/zhanghai\\/MaterialFiles\",\"_id\":\"file_managers\"},{\"id\":\"org.fossify.gallery\",\"label\":\"Fossify Gallery\",\"source\":\"fg\",\"repo\":\"https:\\/\\/github.com\\/FossifyOrg\\/Gallery\",\"_id\":\"gallery\"},{\"id\":\"deckers.thibault.aves.libre\",\"label\":\"Aves Libre\",\"source\":\"f\",\"repo\":\"https:\\/\\/github.com\\/deckerst\\/aves\",\"_id\":\"gallery\"},{\"id\":\"dev.patrickgold.florisboard\",\"label\":\"FlorisBoard\",\"source\":\"f\",\"repo\":\"https:\\/\\/github.com\\/florisboard\\/florisboard\",\"_id\":\"keyboards\"},{\"id\":\"org.smc.inputmethod.indic\",\"label\":\"Indic Keyboard\",\"source\":\"fg\",\"reason\":\"Enhanced keyboard support for Indian languages\",\"repo\":\"https:\\/\\/gitlab.com\\/indicproject\\/Indic-Keyboard\",\"_id\":\"keyboards\"},{\"id\":\"app.organicmaps\",\"label\":\"Organic Maps\",\"source\":\"fg\",\"repo\":\"https:\\/\\/github.com\\/organicmaps\\/organicmaps\",\"_id\":\"maps\"},{\"id\":\"org.jitsi.meet\",\"label\":\"Jitsi Meet\",\"source\":\"fg\",\"repo\":\"https:\\/\\/github.com\\/jitsi\\/jitsi-meet\",\"_id\":\"meeting_apps\"},{\"id\":\"com.iven.musicplayergo\",\"label\":\"Music Player GO\",\"source\":\"fg\",\"repo\":\"https:\\/\\/github.com\\/enricocid\\/Music-Player-GO\",\"_id\":\"music_apps\"},{\"id\":\"com.shadow.blackhole\",\"label\":\"BlackHole\",\"reason\":\"Stream & download high quality 320kbps songs, also supports offline local music.\\nNo subscription or account login required.\\n\",\"source\":\"f\",\"repo\":\"https:\\/\\/github.com\\/Sangwan5688\\/BlackHole\",\"_id\":\"music_apps\"},{\"id\":\"com.streetwriters.notesnook\",\"label\":\"Notesnook\",\"reason\":\"Privacy friendy, encrypted note taking app.\\nRoadmap: https:\\/\\/notesnook.com\\/roadmap\\/\\n\",\"source\":\"g\",\"repo\":\"https:\\/\\/github.com\\/streetwriters\\/notesnook\",\"_id\":\"note_taking_apps\"},{\"id\":\"io.github.quillpad\",\"label\":\"Quillpad\",\"source\":\"fg\",\"repo\":\"https:\\/\\/github.com\\/quillpad\\/quillpad\",\"_id\":\"note_taking_apps\"},{\"id\":\"com.x8bit.bitwarden\",\"label\":\"Bitwarden\",\"reason\":\"Regular security audits https:\\/\\/bitwarden.com\\/help\\/is-bitwarden-audited\\/#third-party-security-audits.\\nRecommended to download from their official F-Droid repo https:\\/\\/mobileapp.bitwarden.com\\/fdroid\\/.\",\"source\":\"g\",\"repo\":\"https:\\/\\/github.com\\/bitwarden\\/mobile\",\"_id\":\"password_managers\"},{\"id\":\"de.danoeh.antennapod\",\"label\":\"AntennaPod\",\"source\":\"fg\",\"repo\":\"https:\\/\\/github.com\\/AntennaPod\\/AntennaPod\",\"_id\":\"podcasts\"},{\"id\":\"com.nononsenseapps.feeder\",\"label\":\"Feeder\",\"source\":\"fg\",\"repo\":\"https:\\/\\/gitlab.com\\/spacecowboy\\/Feeder\",\"_id\":\"rss_readers\"},{\"id\":\"com.oasisfeng.island.fdroid\",\"label\":\"Insular\",\"source\":\"f\",\"repo\":\"https:\\/\\/gitlab.com\\/secure-system\\/Insular\",\"_id\":\"sandboxing_apps\"},{\"id\":\"com.bnyro.recorder\",\"label\":\"Record You\",\"repo\":\"https:\\/\\/github.com\\/Bnyro\\/RecordYou\",\"_id\":\"screen_recorders\"},{\"id\":\"org.localsend.localsend_app\",\"label\":\"Local Send\",\"source\":\"fg\",\"repo\":\"https:\\/\\/github.com\\/localsend\\/localsend\",\"reason\":\"Supports every major operating systems\",\"_id\":\"sharing_apps\"},{\"id\":\"dev.octoshrimpy.quik\",\"label\":\"QUIK SMS\",\"source\":\"f\",\"repo\":\"https:\\/\\/github.com\\/octoshrimpy\\/quik\",\"_id\":\"sms\"},{\"id\":\"com.github.libretube\",\"label\":\"LibreTube\",\"source\":\"f\",\"repo\":\"https:\\/\\/github.com\\/libre-tube\\/LibreTube\",\"_id\":\"streaming_apps\"},{\"id\":\"com.odysee.floss\",\"label\":\"Odysee\",\"source\":\"f\",\"repo\":\"https:\\/\\/github.com\\/OdyseeTeam\\/odysee-android-floss\",\"_id\":\"streaming_apps\"},{\"id\":\"org.schabi.newpipe\",\"label\":\"NewPipe\",\"source\":\"f\",\"repo\":\"https:\\/\\/github.com\\/TeamNewPipe\\/NewPipe\",\"_id\":\"streaming_apps\"},{\"id\":\"org.tasks\",\"label\":\"Tasks\",\"source\":\"fg\",\"repo\":\"https:\\/\\/github.com\\/tasks\\/tasks\",\"_id\":\"task_managers\"},{\"id\":\"com.bnyro.translate\",\"label\":\"Translate You\",\"source\":\"f\",\"repo\":\"https:\\/\\/github.com\\/Bnyro\\/TranslateYou\",\"_id\":\"translators\"},{\"id\":\"com.github.olga_yakovleva.rhvoice.android\",\"label\":\"RHVoice\",\"source\":\"f\",\"repo\":\"https:\\/\\/github.com\\/RHVoice\\/RHVoice\",\"reason\":\"Good voice quality, but most voices are non-free as they prohibit commercial use.\",\"_id\":\"tts\"},{\"id\":\"com.reecedunn.espeak\",\"label\":\"eSpeak\",\"source\":\"fg\",\"repo\":\"https:\\/\\/github.com\\/espeak-ng\\/espeak-ng\",\"reason\":\"Speech quality is not very good and sounds more robotic.\",\"_id\":\"tts\"},{\"id\":\"org.videolan.vlc\",\"label\":\"VLC\",\"source\":\"fg\",\"repo\":\"https:\\/\\/code.videolan.org\\/videolan\\/vlc-android\",\"_id\":\"video_players\"},{\"id\":\"net.mullvad.mullvadvpn\",\"label\":\"Mullvad VPN\",\"reason\":\"https:\\/\\/mullvad.net\\/en\\/why-mullvad-vpn\",\"source\":\"fg\",\"repo\":\"https:\\/\\/github.com\\/mullvad\\/mullvadvpn-app\",\"_id\":\"vpn_services\"},{\"id\":\"org.breezyweather\",\"label\":\"Breezy Weather\",\"repo\":\"https:\\/\\/github.com\\/breezy-weather\\/breezy-weather\",\"_id\":\"weather_apps\"}]"
  },
  {
    "path": "app/src/main/cpp/AhoCorasick.cpp",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n#include <jni.h>\n#include <string>\n#include <vector>\n#include <queue>\n#include <unordered_map>\n#include <mutex>\n#include <atomic>\n#include <map>\n#include <stack>\n\n#include \"AhoCorasick.h\"\n\nvoid AhoCorasick::buildTrie(const std::vector<std::string> &patterns) {\n    for (int i = 0; i < (int) patterns.size(); ++i) {\n        const std::string &pat = patterns[i];\n        TrieNode *node = root;\n        for (char c: pat) {\n            if (!node->children.count(c)) node->children[c] = new TrieNode();\n            node = node->children[c];\n        }\n        node->output.push_back(i);\n    }\n}\n\nvoid AhoCorasick::buildFailureLinks() {\n    std::queue<TrieNode *> q;\n    root->fail = root;\n    for (auto &pair: root->children) {\n        pair.second->fail = root;\n        q.push(pair.second);\n    }\n    while (!q.empty()) {\n        TrieNode *current = q.front();\n        q.pop();\n        for (auto &pair: current->children) {\n            char c = pair.first;\n            TrieNode *child = pair.second;\n            TrieNode *f = current->fail;\n            while (f != root && !f->children.count(c)) {\n                f = f->fail;\n            }\n            if (f->children.count(c) && f->children[c] != child) {\n                child->fail = f->children[c];\n            } else {\n                child->fail = root;\n            }\n            child->output.insert(child->output.end(),\n                                 child->fail->output.begin(),\n                                 child->fail->output.end());\n            q.push(child);\n        }\n    }\n}\n\nstd::vector<int> AhoCorasick::search(const std::string &text) const {\n    std::vector<int> matches;\n    TrieNode *node = root;\n    for (char c: text) {\n        while (node != root && !node->children.count(c)) {\n            node = node->fail;\n        }\n        if (node->children.count(c)) {\n            node = node->children.at(c);\n        }\n        matches.insert(matches.end(), node->output.begin(), node->output.end());\n    }\n    return matches;\n}\n\nvoid AhoCorasick::freeNodes(TrieNode* node) {\n    if (!node) return;\n\n    std::stack<TrieNode*> stack;\n    stack.push(node);\n\n    while (!stack.empty()) {\n        TrieNode* tmpNode = stack.top();\n        stack.pop();\n\n        // Push children onto stack before deleting the current tmpNode\n        for (auto& pair : tmpNode->children) {\n            stack.push(pair.second);\n        }\n        delete tmpNode;\n    }\n}"
  },
  {
    "path": "app/src/main/cpp/AhoCorasick.h",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n#ifndef MUNTASHIRAKON_AHOCORASICK_H\n#define MUNTASHIRAKON_AHOCORASICK_H\n\n#include <vector>\n#include <map>\n\nstruct TrieNode {\n    std::unordered_map<char, TrieNode*> children;\n    TrieNode* fail;\n    std::vector<int> output;\n\n    TrieNode() : fail(nullptr) {}\n};\n\nclass AhoCorasick {\npublic:\n    AhoCorasick() : root(new TrieNode()) {}\n    ~AhoCorasick() { freeNodes(root); }\n\n    void buildTrie(const std::vector<std::string>& patterns);\n\n    void buildFailureLinks();\n\n    std::vector<int> search(const std::string& text) const;\n\nprivate:\n    TrieNode* root;\n    void freeNodes(TrieNode* node);\n};\n\n\n#endif //MUNTASHIRAKON_AHOCORASICK_H\n"
  },
  {
    "path": "app/src/main/cpp/CMakeLists.txt",
    "content": "cmake_minimum_required(VERSION 3.4.1)\n\nset(CMAKE_CXX_STANDARD 17)\n\nset(C_FLAGS \"-Werror=format -fdata-sections -ffunction-sections -fno-exceptions -fno-rtti -fno-threadsafe-statics\")\nset(LINKER_FLAGS \"-Wl,--hash-style=both -Wl,--build-id=none\")\n\nif (NOT CMAKE_BUILD_TYPE STREQUAL \"Debug\")\n    message(\"Builing Release...\")\n\n    set(C_FLAGS \"${C_FLAGS} -O2 -fvisibility=hidden -fvisibility-inlines-hidden\")\n    set(LINKER_FLAGS \"${LINKER_FLAGS} -Wl,-exclude-libs,ALL -Wl,--gc-sections\")\nelse()\n    message(\"Builing Debug...\")\n\n    add_definitions(-DDEBUG)\nendif ()\n\nset(CMAKE_C_FLAGS \"${CMAKE_C_FLAGS} ${C_FLAGS}\")\nset(CMAKE_CXX_FLAGS \"${CMAKE_CXX_FLAGS} ${C_FLAGS}\")\n\nset(CMAKE_SHARED_LINKER_FLAGS \"${CMAKE_SHARED_LINKER_FLAGS} ${LINKER_FLAGS}\")\nset(CMAKE_MODULE_LINKER_FLAGS \"${CMAKE_MODULE_LINKER_FLAGS} ${LINKER_FLAGS}\")\n\nfind_library(log-lib log)\n\nadd_library(am SHARED\n        AhoCorasick.cpp\n        io_github_muntashirakon_algo_AhoCorasick.cpp\n        io_github_muntashirakon_AppManager_utils_CpuUtils.cpp\n        io_github_muntashirakon_compat_system_OsCompat.cpp)\n\ntarget_link_libraries(am ${log-lib})\n\nif (NOT CMAKE_BUILD_TYPE STREQUAL \"Debug\")\n    add_custom_command(TARGET am POST_BUILD\n            COMMAND ${CMAKE_STRIP} --remove-section=.comment \"${CMAKE_LIBRARY_OUTPUT_DIRECTORY}/libam.so\")\nendif ()"
  },
  {
    "path": "app/src/main/cpp/io_github_muntashirakon_AppManager_utils_CpuUtils.cpp",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n#include <jni.h>\n#include <unistd.h>\n#include <cstring>\n\n#include \"io_github_muntashirakon_AppManager_utils_CpuUtils.h\"\n\nextern \"C\"\nJNIEXPORT jlong JNICALL\nJava_io_github_muntashirakon_AppManager_utils_CpuUtils_getClockTicksPerSecond\n        (JNIEnv *, jclass) {\n    return sysconf(_SC_CLK_TCK);\n}\n\nextern \"C\"\nJNIEXPORT jstring JNICALL\nJava_io_github_muntashirakon_AppManager_utils_CpuUtils_getCpuModel(JNIEnv *env, jclass) {\n#if defined(__x86_64__) || defined(__i386__)\n    unsigned int eax, ebx, ecx, edx;\n    char cpuModel[48];\n\n    // Call CPUID with EAX=0x80000002, 0x80000003, 0x80000004 to get the CPU model\n    for (int i = 0; i < 3; i++) {\n        asm volatile(\"cpuid\"\n                : \"=a\" (eax), \"=b\" (ebx), \"=c\" (ecx), \"=d\" (edx)\n                : \"a\" (0x80000002 + i));\n        memcpy(cpuModel + i * 16, &eax, 4);\n        memcpy(cpuModel + i * 16 + 4, &ebx, 4);\n        memcpy(cpuModel + i * 16 + 8, &ecx, 4);\n        memcpy(cpuModel + i * 16 + 12, &edx, 4);\n    }\n    return env->NewStringUTF(cpuModel);\n#else\n    return 0;\n#endif\n}"
  },
  {
    "path": "app/src/main/cpp/io_github_muntashirakon_AppManager_utils_CpuUtils.h",
    "content": "/* DO NOT EDIT THIS FILE - it is machine generated */\n#include <jni.h>\n/* Header for class io_github_muntashirakon_AppManager_utils_CpuUtils */\n\n#ifndef _Included_io_github_muntashirakon_AppManager_utils_CpuUtils\n#define _Included_io_github_muntashirakon_AppManager_utils_CpuUtils\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n/*\n * Class:     io_github_muntashirakon_AppManager_utils_CpuUtils\n * Method:    getClockTicksPerSecond\n * Signature: ()J\n */\nJNIEXPORT jlong JNICALL Java_io_github_muntashirakon_AppManager_utils_CpuUtils_getClockTicksPerSecond\n  (JNIEnv *, jclass);\n\n/*\n * Class:     io_github_muntashirakon_AppManager_utils_CpuUtils\n * Method:    getCpuModel\n * Signature: ()java/lang/String;\n */\nJNIEXPORT jstring JNICALL Java_io_github_muntashirakon_AppManager_utils_CpuUtils_getCpuModel\n        (JNIEnv *, jclass);\n\n#ifdef __cplusplus\n}\n#endif\n#endif\n"
  },
  {
    "path": "app/src/main/cpp/io_github_muntashirakon_algo_AhoCorasick.cpp",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n#include <jni.h>\n#include <string>\n#include <vector>\n#include <queue>\n#include <unordered_map>\n#include <mutex>\n#include <atomic>\n#include <map>\n\n#include \"AhoCorasick.h\"\n#include \"io_github_muntashirakon_algo_AhoCorasick.h\"\n\nstatic std::mutex mutex;\nstatic std::atomic<long long> lastId(0);\nstatic std::map<long long, AhoCorasick *> instances;\n\nextern \"C\"\nJNIEXPORT jlong JNICALL\nJava_io_github_muntashirakon_algo_AhoCorasick_createNative(JNIEnv *env, jobject,\n                                                           jobjectArray patternArray) {\n    jsize len = env->GetArrayLength(patternArray);\n    std::vector<std::string> patterns(len);\n    for (jsize i = 0; i < len; ++i) {\n        auto jstr = (jstring) env->GetObjectArrayElement(patternArray, i);\n        const char *chars = env->GetStringUTFChars(jstr, nullptr);\n        patterns[i] = chars;\n        env->ReleaseStringUTFChars(jstr, chars);\n        env->DeleteLocalRef(jstr);\n    }\n\n    auto ac = new AhoCorasick();\n    ac->buildTrie(patterns);\n    ac->buildFailureLinks();\n\n    long long id = ++lastId;\n    {\n        std::lock_guard<std::mutex> lock(mutex);\n        instances[id] = ac;\n    }\n    return (jlong) id;\n}\n\nextern \"C\"\nJNIEXPORT jintArray JNICALL\nJava_io_github_muntashirakon_algo_AhoCorasick_searchNative(JNIEnv *env, jobject,\n                                                           jlong instance_id, jstring text) {\n    AhoCorasick *ac = nullptr;\n    {\n        std::lock_guard<std::mutex> lock(mutex);\n        if (instances.count(instance_id) == 0) return nullptr;\n        ac = instances[instance_id];\n    }\n    const char *ctext = env->GetStringUTFChars(text, nullptr);\n    std::string input(ctext);\n    env->ReleaseStringUTFChars(text, ctext);\n\n    std::vector<int> matches = ac->search(input);\n    jintArray result = env->NewIntArray(matches.size());\n    if (!matches.empty()) {\n        env->SetIntArrayRegion(result, 0, matches.size(), matches.data());\n    }\n    return result;\n}\n\nextern \"C\"\nJNIEXPORT void JNICALL\nJava_io_github_muntashirakon_algo_AhoCorasick_destroyNative(JNIEnv *, jobject,\n                                                            jlong instance_id) {\n    std::lock_guard<std::mutex> lock(mutex);\n    auto it = instances.find(instance_id);\n    if (it != instances.end()) {\n        delete it->second;\n        instances.erase(it);\n    }\n}\n"
  },
  {
    "path": "app/src/main/cpp/io_github_muntashirakon_algo_AhoCorasick.h",
    "content": "/* DO NOT EDIT THIS FILE - it is machine generated */\n#include <jni.h>\n/* Header for class io_github_muntashirakon_algo_AhoCorasick */\n\n#ifndef _Included_io_github_muntashirakon_algo_AhoCorasick\n#define _Included_io_github_muntashirakon_algo_AhoCorasick\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n/*\n * Class:     io_github_muntashirakon_algo_AhoCorasick\n * Method:    createNative\n * Signature: ([Ljava/lang/String;)J\n */\nextern \"C\"\nJNIEXPORT jlong JNICALL Java_io_github_muntashirakon_algo_AhoCorasick_createNative\n  (JNIEnv *, jobject, jobjectArray);\n\n/*\n * Class:     io_github_muntashirakon_algo_AhoCorasick\n * Method:    searchNative\n * Signature: (JLjava/lang/String;)[I\n */\nextern \"C\"\nJNIEXPORT jintArray JNICALL Java_io_github_muntashirakon_algo_AhoCorasick_searchNative\n  (JNIEnv *, jobject, jlong, jstring);\n\n/*\n * Class:     io_github_muntashirakon_algo_AhoCorasick\n * Method:    searchNative\n * Signature: (J)V\n */\nextern \"C\"\nJNIEXPORT void JNICALL Java_io_github_muntashirakon_algo_AhoCorasick_destroyNative\n  (JNIEnv *, jobject, jlong);\n\n#ifdef __cplusplus\n}\n#endif\n#endif\n"
  },
  {
    "path": "app/src/main/cpp/io_github_muntashirakon_compat_system_OsCompat.cpp",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\n#include <jni.h>\n#include <errno.h>\n#include <pwd.h>\n#include <grp.h>\n#include <unistd.h>\n#include <stdlib.h>\n#include <fcntl.h>\n#include <sys/stat.h>\n\n#include \"io_github_muntashirakon_compat_system_OsCompat.h\"\n\n// Converted from https://github.com/zhanghai/MaterialFiles/blob/faf6c1fe526e0bae3048070a8d1b742ff62c8e6f/app/src/main/jni/syscalls.c\n// Copyright (c) 2018 Hai Zhang <dreaming.in.code.zh@gmail.com>\n\n// Checks errno when return value is NULL.\n#define TEMP_FAILURE_RETRY_N(exp) ({ \\\n    __typeof__(exp) _rc; \\\n    do { \\\n        errno = 0; \\\n        _rc = (exp); \\\n    } while (!_rc && errno == EINTR); \\\n    if (_rc) { \\\n        errno = 0; \\\n    } \\\n    _rc; })\n\n// Always checks errno and ignores return value.\n#define TEMP_FAILURE_RETRY_V(exp) ({ \\\n    do { \\\n        errno = 0; \\\n        (exp); \\\n    } while (errno == EINTR); })\n\n#define AID_APP_START 10000\n\n// API < 26 does not have the functions\n#if __ANDROID_API__ < __ANDROID_API_O__\n\nstatic __thread gid_t getgrentGid = AID_APP_START;\nstatic __thread uid_t getpwentUid = AID_APP_START;\n\nvoid setgrent() {\n    getgrentGid = 0;\n}\n\nstruct group *getgrent() {\n    while (getgrentGid < AID_APP_START) {\n        struct group *group = getgrgid(getgrentGid);\n        ++getgrentGid;\n        errno = 0;\n        if (group) {\n            return group;\n        }\n    }\n    return NULL;\n}\n\nvoid endgrent() {\n    setgrent();\n}\n\n\nvoid setpwent() {\n    getpwentUid = 0;\n}\n\nstruct passwd *getpwent() {\n    while (getpwentUid < AID_APP_START) {\n        struct passwd *passwd = getpwuid(getpwentUid);\n        ++getpwentUid;\n        errno = 0;\n        if (passwd) {\n            return passwd;\n        }\n    }\n    return NULL;\n}\n\nvoid endpwent() {\n    setpwent();\n}\n\n#endif\n\nstatic jclass findClass(JNIEnv *env, const char *name) {\n    jclass localClass = env->FindClass(name);\n    if (!localClass) {\n        abort();\n    }\n    jclass globalClass = reinterpret_cast<jclass>(env->NewGlobalRef(localClass));\n    env->DeleteLocalRef(localClass);\n    if (!globalClass) {\n        abort();\n    }\n    return globalClass;\n}\n\nstatic jclass getErrnoExceptionClass(JNIEnv *env) {\n    static jclass errnoExceptionClass = NULL;\n    if (!errnoExceptionClass) {\n        errnoExceptionClass = findClass(env, \"android/system/ErrnoException\");\n    }\n    return errnoExceptionClass;\n}\n\nstatic void throwException(JNIEnv *env, jclass exceptionClass, jmethodID constructor3,\n                           jmethodID constructor2, const char *functionName, int error) {\n    jthrowable cause = NULL;\n    if (env->ExceptionCheck()) {\n        cause = env->ExceptionOccurred();\n        env->ExceptionClear();\n    }\n    jstring detailMessage = env->NewStringUTF(functionName);\n    if (!detailMessage) {\n        env->ExceptionClear();\n    }\n    jobject exception;\n    if (cause) {\n        exception = env->NewObject(exceptionClass, constructor3, detailMessage, error,\n                cause);\n    } else {\n        exception = env->NewObject(exceptionClass, constructor2, detailMessage, error);\n    }\n    env->Throw((jthrowable) exception);\n    if (detailMessage) {\n        env->DeleteLocalRef(detailMessage);\n    }\n}\n\nstatic void throwErrnoException(JNIEnv* env, const char* functionName) {\n    int error = errno;\n    static jmethodID constructor3 = NULL;\n    if (!constructor3) {\n        constructor3 = env->GetMethodID(getErrnoExceptionClass(env), \"<init>\",\n                \"(Ljava/lang/String;ILjava/lang/Throwable;)V\");\n    }\n    static jmethodID constructor2 = NULL;\n    if (!constructor2) {\n        constructor2 = env->GetMethodID(getErrnoExceptionClass(env), \"<init>\", \"(Ljava/lang/String;I)V\");\n    }\n    throwException(env, getErrnoExceptionClass(env), constructor3, constructor2, functionName, error);\n}\n\nstatic jclass getStringClass(JNIEnv *env) {\n    static jclass stringClass = NULL;\n    if (!stringClass) {\n        stringClass = findClass(env, \"java/lang/String\");\n    }\n    return stringClass;\n}\n\nstatic jclass getStructGroupClass(JNIEnv *env) {\n    static jclass structGroupClass = NULL;\n    if (!structGroupClass) {\n        structGroupClass = findClass(env, \"io/github/muntashirakon/compat/system/StructGroup\");\n    }\n    return structGroupClass;\n}\n\nstatic jclass getStructPasswdClass(JNIEnv *env) {\n    static jclass structPasswdClass = NULL;\n    if (!structPasswdClass) {\n        structPasswdClass = findClass(env, \"android/system/StructPasswd\");\n    }\n    return structPasswdClass;\n}\n\nstatic jclass getStructTimespecClass(JNIEnv *env) {\n    static jclass structTimespecClass = NULL;\n    if (!structTimespecClass) {\n        structTimespecClass = findClass(env, \"io/github/muntashirakon/compat/system/StructTimespec\");\n    }\n    return structTimespecClass;\n}\n\nstatic jclass getOsCompatClass(JNIEnv *env) {\n    static jclass osCompatClass = NULL;\n    if (!osCompatClass) {\n        osCompatClass = findClass(env, \"io/github/muntashirakon/compat/system/OsCompat\");\n    }\n    return osCompatClass;\n}\n\n\nstatic jobject newStructGroup(JNIEnv *env, const struct group *group) {\n    static jmethodID constructor = NULL;\n    if (!constructor) {\n        constructor = env->GetMethodID(getStructGroupClass(env), \"<init>\",\n                \"(Ljava/lang/String;Ljava/lang/String;I[Ljava/lang/String;)V\");\n    }\n    jstring gr_name = env->NewStringUTF(group->gr_name);\n    jstring gr_passwd = env->NewStringUTF(group->gr_passwd);\n    jobjectArray gr_mem;\n    if (group->gr_mem) {\n        jsize gr_memLength = 0;\n        for (char **gr_memIterator = group->gr_mem; *gr_memIterator; ++gr_memIterator) {\n            ++gr_memLength;\n        }\n        gr_mem = env->NewObjectArray(gr_memLength, getStringClass(env), NULL);\n        if (!gr_mem) {\n            return NULL;\n        }\n        jsize gr_memIndex = 0;\n        for (char **gr_memIterator = group->gr_mem; *gr_memIterator; ++gr_memIterator,\n                ++gr_memIndex) {\n            jstring gr_memElement = env->NewStringUTF(*gr_memIterator);\n            if (!gr_memElement) {\n                return NULL;\n            }\n            env->SetObjectArrayElement(gr_mem, gr_memIndex, gr_memElement);\n            env->DeleteLocalRef(gr_memElement);\n        }\n    } else {\n        gr_mem = NULL;\n    }\n    jobject struct_passwd = env->NewObject(getStructGroupClass(env), constructor, gr_name, gr_passwd, group->gr_gid,\n            gr_mem);\n    if (gr_name) {\n        env->DeleteLocalRef(gr_name);\n    }\n    if (gr_passwd) {\n        env->DeleteLocalRef(gr_passwd);\n    }\n    return struct_passwd;\n}\n\nstatic jobject newStructPasswd(JNIEnv *env, const struct passwd *passwd) {\n    static jmethodID constructor = NULL;\n    if (!constructor) {\n        constructor = env->GetMethodID(getStructPasswdClass(env), \"<init>\",\n                \"(Ljava/lang/String;IILjava/lang/String;Ljava/lang/String;)V\");\n    }\n    jstring pw_name = env->NewStringUTF(passwd->pw_name);\n    jstring pw_dir = env->NewStringUTF(passwd->pw_dir);\n    jstring pw_shell = env->NewStringUTF(passwd->pw_shell);\n    jobject struct_passwd = env->NewObject(getStructPasswdClass(env), constructor, pw_name, passwd->pw_uid,\n            passwd->pw_gid, pw_dir, pw_shell);\n    if (pw_name) {\n        env->DeleteLocalRef(pw_name);\n    }\n    if (pw_dir) {\n        env->DeleteLocalRef(pw_dir);\n    }\n    if (pw_shell) {\n        env->DeleteLocalRef(pw_shell);\n    }\n    return struct_passwd;\n}\n\nstatic struct timespec javaStructTimespecToTimespec(JNIEnv *env, jobject obj) {\n    static jfieldID tv_sec = NULL;\n    static jfieldID tv_nsec = NULL;\n    if (!tv_sec) {\n        tv_sec = env->GetFieldID(getStructTimespecClass(env), \"tv_sec\", \"J\");\n    }\n    if (!tv_nsec) {\n        tv_nsec = env->GetFieldID(getStructTimespecClass(env), \"tv_nsec\", \"J\");\n    }\n    struct timespec time;\n    time.tv_sec = (time_t) env->GetLongField(obj, tv_sec);\n    time.tv_nsec = env->GetLongField(obj, tv_nsec);\n    return time;\n}\n\n/** OsCompat **/\n\nJNIEXPORT void JNICALL Java_io_github_muntashirakon_compat_system_OsCompat_setgrent\n  (JNIEnv *env, jclass clazz) {\n    TEMP_FAILURE_RETRY_V(setgrent());\n    if (errno) {\n        throwErrnoException(env, \"setgrent\");\n    }\n}\n\nJNIEXPORT void JNICALL Java_io_github_muntashirakon_compat_system_OsCompat_setpwent\n  (JNIEnv *env, jclass clazz) {\n    TEMP_FAILURE_RETRY_V(setpwent());\n    if (errno) {\n        throwErrnoException(env, \"setpwent\");\n    }\n}\n\nJNIEXPORT jobject JNICALL Java_io_github_muntashirakon_compat_system_OsCompat_getgrent\n  (JNIEnv *env, jclass clazz) {\n    while (true) {\n        struct group *group = TEMP_FAILURE_RETRY_N(getgrent());\n        if (errno) {\n            throwErrnoException(env, \"getgrent\");\n            return NULL;\n        }\n        if (!group) {\n            return NULL;\n        }\n        if (group->gr_name[0] == 'o' && group->gr_name[1] == 'e' && group->gr_name[2] == 'm'\n            && group->gr_name[3] == '_') {\n            continue;\n        }\n        if (group->gr_name[0] == 'u' && (group->gr_name[1] >= '0' && group->gr_name[1] <= '9')) {\n            return NULL;\n        }\n        if (group->gr_name[0] == 'a' && group->gr_name[1] == 'l' && group->gr_name[2] == 'l'\n            && group->gr_name[3] == '_' && group->gr_name[4] == 'a'\n            && (group->gr_name[5] >= '0' && group->gr_name[5] <= '9')) {\n            return NULL;\n        }\n        return newStructGroup(env, group);\n    }\n}\n\nJNIEXPORT jobject JNICALL Java_io_github_muntashirakon_compat_system_OsCompat_getpwent\n  (JNIEnv *env, jclass clazz) {\n    while (true) {\n        struct passwd *passwd = TEMP_FAILURE_RETRY_N(getpwent());\n        if (errno) {\n            throwErrnoException(env, \"getpwent\");\n            return NULL;\n        }\n        if (!passwd) {\n            return NULL;\n        }\n        if (passwd->pw_name[0] == 'o' && passwd->pw_name[1] == 'e' && passwd->pw_name[2] == 'm'\n            && passwd->pw_name[3] == '_') {\n            continue;\n        }\n        if (passwd->pw_name[0] == 'u' && passwd->pw_name[1] >= '0' && passwd->pw_name[1] <= '9') {\n            return NULL;\n        }\n        return newStructPasswd(env, passwd);\n    }\n}\n\nJNIEXPORT void JNICALL Java_io_github_muntashirakon_compat_system_OsCompat_endgrent\n  (JNIEnv *env, jclass clazz) {\n    TEMP_FAILURE_RETRY_V(endgrent());\n    if (errno) {\n        throwErrnoException(env, \"endgrent\");\n    }\n}\n\nJNIEXPORT void JNICALL Java_io_github_muntashirakon_compat_system_OsCompat_endpwent\n  (JNIEnv *env, jclass clazz) {\n    TEMP_FAILURE_RETRY_V(endpwent());\n    if (errno) {\n        throwErrnoException(env, \"endpwent\");\n    }\n}\n\nJNIEXPORT void JNICALL Java_io_github_muntashirakon_compat_system_OsCompat_utimensat\n  (JNIEnv *env, jclass clazz, jint dirfd, jstring pathname, jobject atime, jobject mtime, jint flags) {\n    const char *path = env->GetStringUTFChars(pathname, 0);\n    struct timespec times[2];\n    times[0] = javaStructTimespecToTimespec(env, atime);\n    times[1] = javaStructTimespecToTimespec(env, mtime);\n    TEMP_FAILURE_RETRY_V(utimensat(dirfd, path, times, flags));\n    env->ReleaseStringUTFChars(pathname, path);\n    if (errno) {\n        throwErrnoException(env, \"utimensat\");\n    }\n}\n\nJNIEXPORT void JNICALL Java_io_github_muntashirakon_compat_system_OsCompat_setNativeConstants\n  (JNIEnv *env, jclass clazz) {\n    jclass osCompatClass = getOsCompatClass(env);\n    jfieldID utime_now = env->GetStaticFieldID(osCompatClass, \"UTIME_NOW\", \"J\");\n    jfieldID utime_omit = env->GetStaticFieldID(osCompatClass, \"UTIME_OMIT\", \"J\");\n    jfieldID at_fdcwd = env->GetStaticFieldID(osCompatClass, \"AT_FDCWD\", \"I\");\n    jfieldID at_symlink_nofollow = env->GetStaticFieldID(osCompatClass, \"AT_SYMLINK_NOFOLLOW\", \"I\");\n    env->SetStaticLongField(osCompatClass, utime_now, UTIME_NOW);\n    env->SetStaticLongField(osCompatClass, utime_omit, UTIME_OMIT);\n    env->SetStaticIntField(osCompatClass, at_fdcwd, AT_FDCWD);\n    env->SetStaticIntField(osCompatClass, at_symlink_nofollow, AT_SYMLINK_NOFOLLOW);\n}\n"
  },
  {
    "path": "app/src/main/cpp/io_github_muntashirakon_compat_system_OsCompat.h",
    "content": "/* DO NOT EDIT THIS FILE - it is machine generated */\n#include <jni.h>\n/* Header for class io_github_muntashirakon_compat_system_OsCompat */\n\n#ifndef _Included_io_github_muntashirakon_compat_system_OsCompat\n#define _Included_io_github_muntashirakon_compat_system_OsCompat\n#ifdef __cplusplus\nextern \"C\" {\n#endif\n/*\n * Class:     io_github_muntashirakon_compat_system_OsCompat\n * Method:    setgrent\n * Signature: ()V\n */\nJNIEXPORT void JNICALL Java_io_github_muntashirakon_compat_system_OsCompat_setgrent\n  (JNIEnv *, jclass);\n\n/*\n * Class:     io_github_muntashirakon_compat_system_OsCompat\n * Method:    setpwent\n * Signature: ()V\n */\nJNIEXPORT void JNICALL Java_io_github_muntashirakon_compat_system_OsCompat_setpwent\n  (JNIEnv *, jclass);\n\n/*\n * Class:     io_github_muntashirakon_compat_system_OsCompat\n * Method:    getgrent\n * Signature: ()Lio/github/muntashirakon/AppManager/compat/StructGroup;\n */\nJNIEXPORT jobject JNICALL Java_io_github_muntashirakon_compat_system_OsCompat_getgrent\n  (JNIEnv *, jclass);\n\n/*\n * Class:     io_github_muntashirakon_compat_system_OsCompat\n * Method:    getpwent\n * Signature: ()Landroid/system/StructPasswd;\n */\nJNIEXPORT jobject JNICALL Java_io_github_muntashirakon_compat_system_OsCompat_getpwent\n  (JNIEnv *, jclass);\n\n/*\n * Class:     io_github_muntashirakon_compat_system_OsCompat\n * Method:    endgrent\n * Signature: ()V\n */\nJNIEXPORT void JNICALL Java_io_github_muntashirakon_compat_system_OsCompat_endgrent\n  (JNIEnv *, jclass);\n\n/*\n * Class:     io_github_muntashirakon_compat_system_OsCompat\n * Method:    endpwent\n * Signature: ()V\n */\nJNIEXPORT void JNICALL Java_io_github_muntashirakon_compat_system_OsCompat_endpwent\n  (JNIEnv *, jclass);\n\n/*\n * Class:     io_github_muntashirakon_compat_system_OsCompat\n * Method:    utimensat\n * Signature: (ILjava/lang/String;Lio/github/muntashirakon/compat/system/StructTimespec;Lio/github/muntashirakon/compat/system/StructTimespec;I)V\n */\nJNIEXPORT void JNICALL Java_io_github_muntashirakon_compat_system_OsCompat_utimensat\n  (JNIEnv *, jclass, jint, jstring, jobject, jobject, jint);\n\n/*\n * Class:     io_github_muntashirakon_compat_system_OsCompat\n * Method:    setNativeConstants\n * Signature: ()V\n */\nJNIEXPORT void JNICALL Java_io_github_muntashirakon_compat_system_OsCompat_setNativeConstants\n  (JNIEnv *, jclass);\n\n#ifdef __cplusplus\n}\n#endif\n#endif\n"
  },
  {
    "path": "app/src/main/java/androidx/appcompat/app/PublicTwilightManager.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage androidx.appcompat.app;\n\nimport android.content.Context;\n\nimport androidx.annotation.NonNull;\n\npublic class PublicTwilightManager {\n    public static boolean isNight(@NonNull Context context) {\n        return TwilightManager.getInstance(context).isNight();\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/androidx/documentfile/provider/DocumentFileUtils.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage androidx.documentfile.provider;\n\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.pm.PackageManager;\nimport android.content.pm.ResolveInfo;\nimport android.net.Uri;\nimport android.provider.DocumentsContract;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport java.io.File;\nimport java.util.List;\nimport java.util.Objects;\n\nimport io.github.muntashirakon.io.Paths;\n\npublic final class DocumentFileUtils {\n    @NonNull\n    public static DocumentFile newTreeDocumentFile(@Nullable DocumentFile parent, @NonNull Context context, @NonNull Uri uri) {\n        return new TreeDocumentFile(parent, context, uri);\n    }\n\n    public static boolean isSingleDocumentFile(@Nullable DocumentFile documentFile) {\n        return documentFile instanceof SingleDocumentFile;\n    }\n\n    public static boolean isTreeDocumentFile(@Nullable DocumentFile documentFile) {\n        return documentFile instanceof TreeDocumentFile;\n    }\n\n    @NonNull\n    public static String resolveAltNameForSaf(@NonNull DocumentFile documentFile) {\n        // For Document Uris, an invalid Uri can return no display name\n        if (DocumentFileUtils.isSingleDocumentFile(documentFile)) {\n            // It's impossible to figure out the correct display name, but since this path is incorrect,\n            // return the full last path segment\n            return documentFile.getUri().getLastPathSegment();\n        }\n        if (DocumentFileUtils.isTreeDocumentFile(documentFile)) {\n            // The last path segment of the last path segment is the real name\n            return resolveAltNameForTreeUri(documentFile.getUri());\n        }\n        throw new IllegalArgumentException(\"Invalid DocumentFile, expected a SAF document.\");\n    }\n\n    public static String resolveAltNameForTreeUri(@NonNull Uri treeUri) {\n        // The last path segment of the last path segment is the real name\n        List<String> segments = treeUri.getPathSegments();\n        String primaryName = segments.get(1);\n        if (segments.size() == 2) {\n            return primaryName;\n        }\n        String secondaryName = segments.get(3);\n        if (secondaryName.startsWith(primaryName + File.separator)) {\n            secondaryName = Paths.getLastPathSegment(secondaryName.substring(primaryName.length() + 1));\n        }\n        if (!secondaryName.isEmpty()) {\n            return secondaryName;\n        }\n        throw new IllegalArgumentException(\"Invalid Uri, expected a tree Uri.\");\n    }\n\n    @Nullable\n    public static ResolveInfo getUriSource(@NonNull Context context, @NonNull Uri uri) {\n        String authority = uri.getAuthority();\n        if (authority == null) {\n            return null;\n        }\n        PackageManager pm = context.getPackageManager();\n        Intent intent = new Intent(DocumentsContract.PROVIDER_INTERFACE);\n        List<ResolveInfo> infos = pm.queryIntentContentProviders(intent, 0);\n        for (ResolveInfo info : infos) {\n            if (Objects.equals(authority, info.providerInfo.authority)) {\n                return info;\n            }\n        }\n        return null;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/androidx/documentfile/provider/MediaDocumentFile.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage androidx.documentfile.provider;\n\nimport android.content.ContentResolver;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.pm.PackageManager;\nimport android.database.Cursor;\nimport android.net.Uri;\nimport android.os.Binder;\nimport android.os.Process;\nimport android.provider.MediaStore;\nimport android.util.Log;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport io.github.muntashirakon.io.Paths;\n\npublic class MediaDocumentFile extends SingleDocumentFile {\n    private final Context mContext;\n    private final Uri mUri;\n\n    public MediaDocumentFile(@Nullable DocumentFile parent, Context context, Uri uri) {\n        super(parent, context, uri);\n        mContext = context;\n        mUri = uri;\n    }\n\n    @Override\n    public boolean isVirtual() {\n        return false;\n    }\n\n    @Override\n    public boolean canWrite() {\n        boolean writable = super.canWrite();\n        if (writable) {\n            return true;\n        }\n        if (Binder.getCallingPid() == Process.myPid() || mContext.checkCallingUriPermission(mUri,\n                Intent.FLAG_GRANT_WRITE_URI_PERMISSION) == PackageManager.PERMISSION_GRANTED) {\n            // Writing is allowed\n            return true;\n        }\n        // TODO: 15/9/23 Handle actual path in case no write permission is granted\n//        // For media documents, also check if the underlying file is writable as a fallback\n//        String path = getRealPath(mContext, mUri);\n//        return path == null || Paths.get(path).canWrite();\n        return false;\n    }\n\n    @Override\n    public boolean exists() {\n        return true;\n    }\n\n//    @Nullable\n//    private static String getRealPath(@NonNull Context context, @NonNull Uri self) {\n//        final ContentResolver resolver = context.getContentResolver();\n//        try (Cursor c = resolver.query(self, new String[]{MediaStore.MediaColumns.DATA}, null, null, null)) {\n//            if (c != null && c.moveToFirst() && !c.isNull(0)) {\n//                return c.getString(0);\n//            } else {\n//                return null;\n//            }\n//        } catch (Exception e) {\n//            Log.w(TAG, \"Failed query: \" + e);\n//            return null;\n//        }\n//    }\n}\n"
  },
  {
    "path": "app/src/main/java/androidx/documentfile/provider/VirtualDocumentFile.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage androidx.documentfile.provider;\n\nimport android.net.Uri;\nimport android.os.ParcelFileDescriptor;\nimport android.system.OsConstants;\nimport android.webkit.MimeTypeMap;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.core.util.Pair;\n\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.nio.channels.FileChannel;\nimport java.util.Objects;\n\nimport io.github.muntashirakon.io.Paths;\nimport io.github.muntashirakon.io.UidGidPair;\nimport io.github.muntashirakon.io.fs.VirtualFileSystem;\n\n// Mother of all virtual documents\npublic class VirtualDocumentFile extends DocumentFile {\n    @Nullable\n    public static Pair<Integer, String> parseUri(@NonNull Uri uri) {\n        try {\n            return new Pair<>(Integer.decode(uri.getAuthority()), uri.getPath());\n        } catch (NumberFormatException e) {\n            return null;\n        }\n    }\n\n    @NonNull\n    private final VirtualFileSystem mFs;\n    @NonNull\n    private String mFullPath;\n\n    public VirtualDocumentFile(@Nullable DocumentFile parent, @NonNull VirtualFileSystem fs) {\n        super(parent);\n        mFs = fs;\n        mFullPath = File.separator;\n    }\n\n    protected VirtualDocumentFile(@NonNull VirtualDocumentFile parent, @NonNull String displayName) {\n        super(Objects.requireNonNull(parent));\n        if (displayName.contains(File.separator)) {\n            throw new IllegalArgumentException(\"displayName cannot contain a separator\");\n        }\n        mFs = parent.mFs;\n        mFullPath = Paths.appendPathSegment(parent.mFullPath, displayName);\n    }\n\n    @Nullable\n    @Override\n    public DocumentFile createFile(@NonNull String mimeType, @NonNull String displayName) {\n        if (displayName.contains(File.separator)) {\n            // displayName cannot contain a separator\n            return null;\n        }\n        // Tack on extension when valid MIME type provided\n        String extension = MimeTypeMap.getSingleton().getExtensionFromMimeType(mimeType);\n        if (extension != null) {\n            displayName += \".\" + extension;\n        }\n        String newFilePath = Paths.appendPathSegment(mFullPath, displayName);\n        return mFs.createNewFile(newFilePath) ? new VirtualDocumentFile(this, displayName) : null;\n    }\n\n    @Nullable\n    @Override\n    public DocumentFile createDirectory(@NonNull String displayName) {\n        if (displayName.contains(File.separator)) {\n            // displayName cannot contain a separator\n            return null;\n        }\n        String newFilePath = Paths.appendPathSegment(mFullPath, displayName);\n        return mFs.mkdir(newFilePath) ? new VirtualDocumentFile(this, displayName) : null;\n    }\n\n    @NonNull\n    public String getFullPath() {\n        return mFullPath;\n    }\n\n    @NonNull\n    public VirtualFileSystem getFileSystem() {\n        return mFs;\n    }\n\n    @NonNull\n    @Override\n    public String getName() {\n        if (mFullPath.equals(File.separator)) {\n            return File.separator;\n        }\n        return Paths.getLastPathSegment(mFullPath);\n    }\n\n    @Nullable\n    @Override\n    public String getType() {\n        if (mFs.isFile(mFullPath)) {\n            String extension = Paths.getPathExtension(getName());\n            if (extension == null) {\n                return null;\n            }\n            return MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);\n        } else if (mFs.isDirectory(mFullPath)) {\n            return \"resource/folder\";\n        }\n        return null;\n    }\n\n    @Override\n    public boolean isVirtual() {\n        return true;\n    }\n\n    @Override\n    public boolean isFile() {\n        return mFs.isFile(mFullPath);\n    }\n\n    @Override\n    public boolean isDirectory() {\n        return mFs.isDirectory(mFullPath);\n    }\n\n    @Override\n    public boolean exists() {\n        return mFs.checkAccess(mFullPath, OsConstants.F_OK);\n    }\n\n    @Override\n    public boolean canRead() {\n        return mFs.checkAccess(mFullPath, OsConstants.R_OK);\n    }\n\n    @Override\n    public boolean canWrite() {\n        return mFs.checkAccess(mFullPath, OsConstants.W_OK);\n    }\n\n    public int getMode() {\n        return mFs.getMode(mFullPath);\n    }\n\n    public boolean setMode(int mode) {\n        mFs.setMode(mFullPath, mode);\n        return true;\n    }\n\n    @Nullable\n    public UidGidPair getUidGid() {\n        return mFs.getUidGid(mFullPath);\n    }\n\n    public boolean setUidGid(@NonNull UidGidPair uidGidPair) {\n        mFs.setUidGid(mFullPath, uidGidPair.uid, uidGidPair.gid);\n        return true;\n    }\n\n    @Override\n    public boolean delete() {\n        return mFs.delete(mFullPath);\n    }\n\n    @NonNull\n    @Override\n    public Uri getUri() {\n        return VirtualFileSystem.getUri(mFs.getFsId(), mFullPath);\n    }\n\n    @NonNull\n    public FileInputStream openInputStream() throws IOException {\n        return mFs.newInputStream(mFullPath);\n    }\n\n    @NonNull\n    public FileOutputStream openOutputStream(boolean append) throws IOException {\n        return mFs.newOutputStream(mFullPath, append);\n    }\n\n    public FileChannel openChannel(int mode) throws IOException {\n        return mFs.openChannel(mFullPath, mode);\n    }\n\n    @NonNull\n    public ParcelFileDescriptor openFileDescriptor(int mode) throws IOException {\n        return mFs.openFileDescriptor(mFullPath, mode);\n    }\n\n    @Override\n    public long lastModified() {\n        return mFs.lastModified(mFullPath);\n    }\n\n    public boolean setLastModified(long millis) {\n        return mFs.setLastModified(mFullPath, millis);\n    }\n\n    public long lastAccess() {\n        return mFs.lastAccess(mFullPath);\n    }\n\n    public long creationTime() {\n        return mFs.creationTime(mFullPath);\n    }\n\n    @Override\n    public long length() {\n        return mFs.length(mFullPath);\n    }\n\n    @Nullable\n    @Override\n    public VirtualDocumentFile findFile(@NonNull String displayName) {\n        displayName =  Paths.sanitize(displayName, true);\n        if (displayName == null || displayName.contains(File.separator)) {\n            return null;\n        }\n        VirtualDocumentFile documentFile = new VirtualDocumentFile(this, displayName);\n        if (documentFile.exists()) {\n            return documentFile;\n        }\n        return null;\n    }\n\n    @NonNull\n    @Override\n    public VirtualDocumentFile[] listFiles() {\n        String[] children = mFs.list(mFullPath);\n        if (children == null) return new VirtualDocumentFile[0];\n        VirtualDocumentFile[] documentFiles = new VirtualDocumentFile[children.length];\n        for (int i = 0; i < children.length; ++i) {\n            documentFiles[i] = new VirtualDocumentFile(this, children[i]);\n        }\n        return documentFiles;\n    }\n\n    @Override\n    public boolean renameTo(@NonNull String displayName) {\n        if (displayName.contains(File.separator)) {\n            // displayName cannot contain a separator\n            return false;\n        }\n        String parent = Paths.removeLastPathSegment(mFullPath);\n        String newFile = Paths.appendPathSegment(parent, displayName);\n        if(mFs.renameTo(mFullPath, newFile)) {\n            mFullPath = newFile;\n            return true;\n        }\n        return false;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/aosp/libcore/util/EmptyArray.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage aosp.libcore.util;\n\n// Copyright 2006 The Android Open Source Project\npublic final class EmptyArray {\n    private EmptyArray() {}\n\n    public static final boolean[] BOOLEAN = new boolean[0];\n    public static final byte[] BYTE = new byte[0];\n    public static final char[] CHAR = new char[0];\n    public static final double[] DOUBLE = new double[0];\n    public static final float[] FLOAT = new float[0];\n    public static final int[] INT = new int[0];\n    public static final long[] LONG = new long[0];\n\n    public static final Class<?>[] CLASS = new Class[0];\n    public static final Object[] OBJECT = new Object[0];\n    public static final String[] STRING = new String[0];\n    public static final Throwable[] THROWABLE = new Throwable[0];\n    public static final StackTraceElement[] STACK_TRACE_ELEMENT = new StackTraceElement[0];\n    public static final java.lang.reflect.Type[] TYPE = new java.lang.reflect.Type[0];\n    @SuppressWarnings(\"rawtypes\")\n    public static final java.lang.reflect.TypeVariable[] TYPE_VARIABLE =\n            new java.lang.reflect.TypeVariable[0];\n}"
  },
  {
    "path": "app/src/main/java/aosp/libcore/util/HexEncoding.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage aosp.libcore.util;\n\n/**\n * Hexadecimal encoding where each byte is represented by two hexadecimal digits.\n */\n// Copyright 2006 The Android Open Source Project\npublic class HexEncoding {\n\n    private static final char[] LOWER_CASE_DIGITS = {\n            '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'\n    };\n\n    private static final char[] UPPER_CASE_DIGITS = {\n            '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'\n    };\n\n    /** Hidden constructor to prevent instantiation. */\n    private HexEncoding() {}\n\n    /**\n     * Encodes the provided byte as a two-digit hexadecimal String value.\n     */\n    public static String encodeToString(byte b, boolean upperCase) {\n        char[] digits = upperCase ? UPPER_CASE_DIGITS : LOWER_CASE_DIGITS;\n        char[] buf = new char[2]; // We always want two digits.\n        buf[0] = digits[(b >> 4) & 0xf];\n        buf[1] = digits[b & 0xf];\n        return new String(buf, 0, 2);\n    }\n\n    /**\n     * Encodes the provided data as a sequence of hexadecimal characters.\n     */\n    public static char[] encode(byte[] data) {\n        return encode(data, 0, data.length, true /* upperCase */);\n    }\n\n    /**\n     * Encodes the provided data as a sequence of hexadecimal characters.\n     */\n    public static char[] encode(byte[] data, boolean upperCase) {\n        return encode(data, 0, data.length, upperCase);\n    }\n\n    /**\n     * Encodes the provided data as a sequence of hexadecimal characters.\n     */\n    public static char[] encode(byte[] data, int offset, int len) {\n        return encode(data, offset, len, true /* upperCase */);\n    }\n\n    /**\n     * Encodes the provided data as a sequence of hexadecimal characters.\n     */\n    private static char[] encode(byte[] data, int offset, int len, boolean upperCase) {\n        char[] digits = upperCase ? UPPER_CASE_DIGITS : LOWER_CASE_DIGITS;\n        char[] result = new char[len * 2];\n        for (int i = 0; i < len; i++) {\n            byte b = data[offset + i];\n            int resultIndex = 2 * i;\n            result[resultIndex] = (digits[(b >> 4) & 0x0f]);\n            result[resultIndex + 1] = (digits[b & 0x0f]);\n        }\n\n        return result;\n    }\n\n    /**\n     * Encodes the provided data as a sequence of hexadecimal characters.\n     */\n    public static String encodeToString(byte[] data) {\n        return encodeToString(data, true /* upperCase */);\n    }\n\n    /**\n     * Encodes the provided data as a sequence of hexadecimal characters.\n     */\n    public static String encodeToString(byte[] data, boolean upperCase) {\n        return new String(encode(data, upperCase));\n    }\n\n    /**\n     * Decodes the provided hexadecimal string into a byte array.  Odd-length inputs\n     * are not allowed.\n     *\n     * Throws an {@code IllegalArgumentException} if the input is malformed.\n     */\n    public static byte[] decode(String encoded) throws IllegalArgumentException {\n        return decode(encoded.toCharArray());\n    }\n\n    /**\n     * Decodes the provided hexadecimal string into a byte array. If {@code allowSingleChar}\n     * is {@code true} odd-length inputs are allowed and the first character is interpreted\n     * as the lower bits of the first result byte.\n     *\n     * Throws an {@code IllegalArgumentException} if the input is malformed.\n     */\n    public static byte[] decode(String encoded, boolean allowSingleChar)\n            throws IllegalArgumentException {\n        return decode(encoded.toCharArray(), allowSingleChar);\n    }\n\n    /**\n     * Decodes the provided hexadecimal string into a byte array.  Odd-length inputs\n     * are not allowed.\n     *\n     * Throws an {@code IllegalArgumentException} if the input is malformed.\n     */\n    public static byte[] decode(char[] encoded) throws IllegalArgumentException {\n        return decode(encoded, false);\n    }\n\n    /**\n     * Decodes the provided hexadecimal string into a byte array. If {@code allowSingleChar}\n     * is {@code true} odd-length inputs are allowed and the first character is interpreted\n     * as the lower bits of the first result byte.\n     *\n     * Throws an {@code IllegalArgumentException} if the input is malformed.\n     */\n    public static byte[] decode(char[] encoded, boolean allowSingleChar)\n            throws IllegalArgumentException {\n        int encodedLength = encoded.length;\n        int resultLengthBytes = (encodedLength + 1) / 2;\n        byte[] result = new byte[resultLengthBytes];\n\n        int resultOffset = 0;\n        int i = 0;\n        if (allowSingleChar) {\n            if ((encodedLength % 2) != 0) {\n                // Odd number of digits -- the first digit is the lower 4 bits of the first result\n                // byte.\n                result[resultOffset++] = (byte) toDigit(encoded, i);\n                i++;\n            }\n        } else {\n            if ((encodedLength % 2) != 0) {\n                throw new IllegalArgumentException(\"Invalid input length: \" + encodedLength);\n            }\n        }\n\n        for (; i < encodedLength; i += 2) {\n            result[resultOffset++] = (byte) ((toDigit(encoded, i) << 4) | toDigit(encoded, i + 1));\n        }\n\n        return result;\n    }\n\n    private static int toDigit(char[] str, int offset) throws IllegalArgumentException {\n        // NOTE: that this isn't really a code point in the traditional sense, since we're\n        // just rejecting surrogate pairs outright.\n        int pseudoCodePoint = str[offset];\n\n        if ('0' <= pseudoCodePoint && pseudoCodePoint <= '9') {\n            return pseudoCodePoint - '0';\n        } else if ('a' <= pseudoCodePoint && pseudoCodePoint <= 'f') {\n            return 10 + (pseudoCodePoint - 'a');\n        } else if ('A' <= pseudoCodePoint && pseudoCodePoint <= 'F') {\n            return 10 + (pseudoCodePoint - 'A');\n        }\n\n        throw new IllegalArgumentException(\"Illegal char: \" + str[offset] + \" at offset \" + offset);\n    }\n}"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/AppManager.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager;\n\nimport android.app.Application;\nimport android.content.Context;\nimport android.os.Build;\nimport android.sun.security.provider.JavaKeyStoreProvider;\n\nimport androidx.annotation.Keep;\n\nimport com.topjohnwu.superuser.Shell;\n\nimport org.bouncycastle.jce.provider.BouncyCastleProvider;\nimport org.lsposed.hiddenapibypass.HiddenApiBypass;\n\nimport java.security.Security;\n\nimport dalvik.system.ZipPathValidator;\nimport io.github.muntashirakon.AppManager.misc.AMExceptionHandler;\nimport io.github.muntashirakon.AppManager.utils.Utils;\nimport io.github.muntashirakon.AppManager.utils.appearance.AppearanceUtils;\n\npublic class AppManager extends Application {\n    static {\n        Shell.enableVerboseLogging = BuildConfig.DEBUG;\n        Shell.setDefaultBuilder(Shell.Builder.create()\n                .setFlags(Shell.FLAG_MOUNT_MASTER)\n                .setTimeout(10));\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {\n            // We don't rely on the system to detect a zip slip attack\n            ZipPathValidator.clearCallback();\n        }\n    }\n\n    @Keep\n    @Override\n    public void onCreate() {\n        super.onCreate();\n        Thread.setDefaultUncaughtExceptionHandler(new AMExceptionHandler(this));\n        AppearanceUtils.init(this);\n        Security.removeProvider(BouncyCastleProvider.PROVIDER_NAME);\n        Security.addProvider(new JavaKeyStoreProvider());\n        Security.addProvider(new BouncyCastleProvider());\n    }\n\n    @Keep\n    @Override\n    protected void attachBaseContext(Context base) {\n        super.attachBaseContext(base);\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P && !Utils.isRoboUnitTest()) {\n            HiddenApiBypass.addHiddenApiExemptions(\"L\");\n        }\n    }\n\n    @Override\n    public void onTrimMemory(int level) {\n        super.onTrimMemory(level);\n        if (level >= TRIM_MEMORY_RUNNING_CRITICAL) {\n            StaticDataset.cleanup();\n        }\n    }\n\n    @Override\n    public void onLowMemory() {\n        super.onLowMemory();\n        StaticDataset.cleanup();\n    }\n\n    @Override\n    public void onTerminate() {\n        super.onTerminate();\n        StaticDataset.cleanup();\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/BaseActivity.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager;\n\nimport android.Manifest;\nimport android.app.KeyguardManager;\nimport android.content.Intent;\nimport android.os.Build;\nimport android.os.Bundle;\n\nimport androidx.activity.result.ActivityResultLauncher;\nimport androidx.activity.result.contract.ActivityResultContracts;\nimport androidx.annotation.CallSuper;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.appcompat.app.AlertDialog;\nimport androidx.biometric.BiometricPrompt;\nimport androidx.biometric.BiometricPrompt.AuthenticationResult;\nimport androidx.core.content.ContextCompat;\nimport androidx.lifecycle.ViewModelProvider;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\n\nimport io.github.muntashirakon.AppManager.compat.BiometricAuthenticatorsCompat;\nimport io.github.muntashirakon.AppManager.crypto.auth.AuthManager;\nimport io.github.muntashirakon.AppManager.crypto.ks.KeyStoreActivity;\nimport io.github.muntashirakon.AppManager.crypto.ks.KeyStoreManager;\nimport io.github.muntashirakon.AppManager.logs.Log;\nimport io.github.muntashirakon.AppManager.self.SelfPermissions;\nimport io.github.muntashirakon.AppManager.self.filecache.InternalCacheCleanerService;\nimport io.github.muntashirakon.AppManager.self.life.BuildExpiryChecker;\nimport io.github.muntashirakon.AppManager.settings.Ops;\nimport io.github.muntashirakon.AppManager.settings.Prefs;\nimport io.github.muntashirakon.AppManager.settings.SecurityAndOpsViewModel;\nimport io.github.muntashirakon.AppManager.utils.UIUtils;\n\npublic abstract class BaseActivity extends PerProcessActivity {\n    public static final String TAG = BaseActivity.class.getSimpleName();\n\n    public static final HashMap<String, Boolean> ASKED_PERMISSIONS = new HashMap<String, Boolean>() {{\n        // (permission, required) pairs\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {\n            put(Manifest.permission.POST_NOTIFICATIONS, false);\n        }\n    }};\n\n    public static final String EXTRA_AUTH = \"auth\";\n\n    @Nullable\n    private AlertDialog mAlertDialog;\n    @Nullable\n    private SecurityAndOpsViewModel mViewModel;\n    private boolean mDisplayLoader = true;\n    private BiometricPrompt mBiometricPrompt;\n    @Nullable\n    private Bundle mSavedInstanceState;\n\n    private final ActivityResultLauncher<Intent> mKeyStoreActivity = registerForActivityResult(\n            new ActivityResultContracts.StartActivityForResult(), result -> {\n                // Need authentication and/or verify mode of operation\n                ensureSecurityAndModeOfOp();\n            });\n    private final ActivityResultLauncher<String[]> mPermissionCheckActivity = registerForActivityResult(\n            new ActivityResultContracts.RequestMultiplePermissions(),\n            permissionStatusMap -> {\n                // Run authentication\n                doAuthenticate(mSavedInstanceState);\n                mSavedInstanceState = null;\n            });\n\n    @Override\n    protected final void onCreate(@Nullable Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        if (Ops.isAuthenticated()) {\n            Log.d(TAG, \"Already authenticated.\");\n            onAuthenticated(savedInstanceState);\n            initPermissionChecks(false);\n            return;\n        }\n        if (Boolean.TRUE.equals(BuildExpiryChecker.buildExpired())) {\n            // Build has expired\n            BuildExpiryChecker.getBuildExpiredDialog(this, (dialog, which) -> doAuthenticate(savedInstanceState)).show();\n            return;\n        }\n        // Init permission checks\n        mSavedInstanceState = savedInstanceState;\n        if (!initPermissionChecks(true)) {\n            mSavedInstanceState = null;\n            // Run authentication\n            doAuthenticate(savedInstanceState);\n        }\n    }\n\n    protected abstract void onAuthenticated(@Nullable Bundle savedInstanceState);\n\n    @CallSuper\n    @Override\n    protected void onStart() {\n        super.onStart();\n        if (mViewModel != null && mViewModel.isAuthenticating() && mAlertDialog != null) {\n            if (mDisplayLoader) {\n                mAlertDialog.show();\n            } else {\n                mAlertDialog.hide();\n            }\n        }\n    }\n\n    @CallSuper\n    @Override\n    protected void onStop() {\n        if (mAlertDialog != null) {\n            mAlertDialog.dismiss();\n        }\n        super.onStop();\n    }\n\n    private void doAuthenticate(@Nullable Bundle savedInstanceState) {\n        mViewModel = new ViewModelProvider(this).get(SecurityAndOpsViewModel.class);\n        mBiometricPrompt = new BiometricPrompt(this, ContextCompat.getMainExecutor(this),\n                new BiometricPrompt.AuthenticationCallback() {\n                    @Override\n                    public void onAuthenticationError(int errorCode, @NonNull CharSequence errString) {\n                        super.onAuthenticationError(errorCode, errString);\n                        finishAndRemoveTask();\n                    }\n\n                    @Override\n                    public void onAuthenticationSucceeded(@NonNull AuthenticationResult result) {\n                        super.onAuthenticationSucceeded(result);\n                        handleMigrationAndModeOfOp();\n                    }\n\n                    @Override\n                    public void onAuthenticationFailed() {\n                        super.onAuthenticationFailed();\n                    }\n                });\n        mAlertDialog = UIUtils.getProgressDialog(this, getString(R.string.initializing), true);\n        Log.d(TAG, \"Waiting to be authenticated.\");\n        mViewModel.authenticationStatus().observe(this, status -> {\n            switch (status) {\n                case Ops.STATUS_AUTO_CONNECT_WIRELESS_DEBUGGING:\n                    Log.d(TAG, \"Try auto-connecting to wireless debugging.\");\n                    mDisplayLoader = false;\n                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {\n                        mViewModel.autoConnectWirelessDebugging();\n                        return;\n                    } // fall-through\n                case Ops.STATUS_WIRELESS_DEBUGGING_CHOOSER_REQUIRED:\n                    Log.d(TAG, \"Display wireless debugging chooser (pair or connect)\");\n                    mDisplayLoader = false;\n                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {\n                        Ops.connectWirelessDebugging(this, mViewModel);\n                        return;\n                    } // fall-through\n                case Ops.STATUS_ADB_CONNECT_REQUIRED:\n                    Log.d(TAG, \"Display connect dialog.\");\n                    mDisplayLoader = false;\n                    Ops.connectAdbInput(this, mViewModel);\n                    return;\n                case Ops.STATUS_ADB_PAIRING_REQUIRED:\n                    Log.d(TAG, \"Display pairing dialog.\");\n                    mDisplayLoader = false;\n                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {\n                        Ops.pairAdbInput(this, mViewModel);\n                        return;\n                    } // fall-through\n                case Ops.STATUS_FAILURE_ADB_NEED_MORE_PERMS:\n                    Ops.displayIncompleteUsbDebuggingMessage(this);\n                case Ops.STATUS_SUCCESS:\n                case Ops.STATUS_FAILURE:\n                    Log.d(TAG, \"Authentication completed.\");\n                    mViewModel.setAuthenticating(false);\n                    if (mAlertDialog != null) mAlertDialog.dismiss();\n                    Ops.setAuthenticated(this, true);\n                    onAuthenticated(savedInstanceState);\n                    InternalCacheCleanerService.scheduleAlarm(getApplicationContext());\n            }\n        });\n        if (!mViewModel.isAuthenticating()) {\n            mViewModel.setAuthenticating(true);\n            // Check KeyStore\n            if (KeyStoreManager.hasKeyStorePassword()) {\n                // We already have a working keystore password.\n                // Only need authentication and/or verify mode of operation.\n                ensureSecurityAndModeOfOp();\n                return;\n            }\n            Intent keyStoreIntent = new Intent(this, KeyStoreActivity.class)\n                    .putExtra(KeyStoreActivity.EXTRA_KS, true);\n            mKeyStoreActivity.launch(keyStoreIntent);\n        }\n    }\n\n    private void ensureSecurityAndModeOfOp() {\n        if (!Prefs.Privacy.isScreenLockEnabled()) {\n            // No security enabled\n            handleMigrationAndModeOfOp();\n            return;\n        }\n        if (getIntent().hasExtra(EXTRA_AUTH)) {\n            Log.i(TAG, \"Screen lock-bypass enabled.\");\n            // Check for auth\n            String auth = getIntent().getStringExtra(EXTRA_AUTH);\n            if (AuthManager.getKey().equals(auth)) {\n                // Auth successful\n                handleMigrationAndModeOfOp();\n                return;\n            } // else // Invalid authorization key, fallback to security\n        }\n        Log.i(TAG, \"Screen lock enabled.\");\n        KeyguardManager keyguardManager = (KeyguardManager) getSystemService(KEYGUARD_SERVICE);\n        if (keyguardManager.isKeyguardSecure()) {\n            // Screen lock enabled\n            BiometricPrompt.PromptInfo promptInfo = new BiometricPrompt.PromptInfo.Builder()\n                    .setTitle(getString(R.string.unlock_app_manager))\n                    .setAllowedAuthenticators(new BiometricAuthenticatorsCompat.Builder().allowEverything(true).build())\n                    .build();\n            mBiometricPrompt.authenticate(promptInfo);\n        } else {\n            // Screen lock disabled\n            UIUtils.displayLongToast(R.string.screen_lock_not_enabled);\n            finishAndRemoveTask();\n        }\n    }\n\n    private void handleMigrationAndModeOfOp() {\n        // Authentication was successful\n        Log.d(TAG, \"Authenticated\");\n        // Set mode of operation\n        if (mViewModel != null) {\n            mViewModel.setModeOfOps();\n        }\n    }\n\n    private boolean initPermissionChecks(boolean checkAll) {\n        List<String> permissionsToBeAsked = new ArrayList<>(ASKED_PERMISSIONS.size());\n        for (String permission : ASKED_PERMISSIONS.keySet()) {\n            boolean required = Boolean.TRUE.equals(ASKED_PERMISSIONS.get(permission));\n            if (!SelfPermissions.checkSelfPermission(permission) && (required || checkAll)) {\n                permissionsToBeAsked.add(permission);\n            }\n        }\n        if (!permissionsToBeAsked.isEmpty()) {\n            // Ask required permissions\n            mPermissionCheckActivity.launch(permissionsToBeAsked.toArray(new String[0]));\n            return true;\n        }\n        return false;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/DummyActivity.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager;\n\nimport android.app.Activity;\nimport android.os.Bundle;\n\npublic class DummyActivity extends Activity {\n    @Override\n    public void onCreate(Bundle icicle) {\n        super.onCreate(icicle);\n        finish();\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/PerProcessActivity.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager;\n\nimport android.annotation.SuppressLint;\nimport android.os.Bundle;\nimport android.view.Menu;\n\nimport androidx.activity.EdgeToEdge;\nimport androidx.annotation.CallSuper;\nimport androidx.annotation.IdRes;\nimport androidx.annotation.Nullable;\nimport androidx.appcompat.app.AppCompatActivity;\nimport androidx.appcompat.view.menu.MenuBuilder;\nimport androidx.fragment.app.Fragment;\nimport androidx.fragment.app.FragmentManager;\n\npublic class PerProcessActivity extends AppCompatActivity {\n    @CallSuper\n    @Override\n    protected void onCreate(@Nullable Bundle savedInstanceState) {\n        EdgeToEdge.enable(this);\n        super.onCreate(savedInstanceState);\n    }\n\n    public boolean getTransparentBackground() {\n        return false;\n    }\n\n    @CallSuper\n    @SuppressLint(\"RestrictedApi\")\n    @Override\n    public boolean onCreateOptionsMenu(Menu menu) {\n        if (menu instanceof MenuBuilder) {\n            ((MenuBuilder) menu).setOptionalIconsVisible(true);\n        }\n        return super.onCreateOptionsMenu(menu);\n    }\n\n    protected void clearBackStack() {\n        FragmentManager fragmentManager = getSupportFragmentManager();\n        if (fragmentManager.getBackStackEntryCount() > 0) {\n            FragmentManager.BackStackEntry entry = fragmentManager.getBackStackEntryAt(0);\n            fragmentManager.popBackStackImmediate(entry.getId(), FragmentManager.POP_BACK_STACK_INCLUSIVE);\n        }\n    }\n\n    protected void removeCurrentFragment(@IdRes int id) {\n        Fragment fragment = getSupportFragmentManager().findFragmentById(id);\n        if (fragment != null) {\n            getSupportFragmentManager()\n                    .beginTransaction()\n                    .remove(fragment)\n                    .commit();\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/StaticDataset.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager;\n\nimport android.content.Context;\nimport android.content.res.Resources;\nimport android.util.DisplayMetrics;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.WorkerThread;\nimport androidx.collection.ArrayMap;\nimport androidx.core.os.ConfigurationCompat;\nimport androidx.core.os.LocaleListCompat;\n\nimport com.google.gson.Gson;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\n\nimport io.github.muntashirakon.AppManager.db.utils.AppDb;\nimport io.github.muntashirakon.AppManager.debloat.DebloatObject;\nimport io.github.muntashirakon.AppManager.debloat.SuggestionObject;\nimport io.github.muntashirakon.AppManager.misc.VMRuntime;\nimport io.github.muntashirakon.AppManager.utils.ContextUtils;\nimport io.github.muntashirakon.AppManager.utils.FileUtils;\nimport io.github.muntashirakon.algo.AhoCorasick;\n\npublic class StaticDataset {\n    @Nullable\n    private static AhoCorasick sAhoCorasickTrackerCache;\n    private static String[] sTrackerNames;\n    private static List<DebloatObject> sDebloatObjects;\n\n    public static final String ARMEABI_V7A = \"armeabi_v7a\";\n    public static final String ARM64_V8A = \"arm64_v8a\";\n    public static final String X86 = \"x86\";\n    public static final String X86_64 = \"x86_64\";\n\n    public static Map<String, String> ALL_ABIS = new HashMap<>();\n\n    static {\n        ALL_ABIS.put(ARMEABI_V7A, VMRuntime.ABI_ARMEABI_V7A);\n        ALL_ABIS.put(ARM64_V8A, VMRuntime.ABI_ARM64_V8A);\n        ALL_ABIS.put(X86, VMRuntime.ABI_X86);\n        ALL_ABIS.put(X86_64, VMRuntime.ABI_X86_64);\n    }\n\n    public static final String LDPI = \"ldpi\";\n    public static final String MDPI = \"mdpi\";\n    public static final String TVDPI = \"tvdpi\";\n    public static final String HDPI = \"hdpi\";\n    public static final String XHDPI = \"xhdpi\";\n    public static final String XXHDPI = \"xxhdpi\";\n    public static final String XXXHDPI = \"xxxhdpi\";\n\n    public static final ArrayMap<String, Integer> DENSITY_NAME_TO_DENSITY = new ArrayMap<String, Integer>(8) {\n        {\n            put(LDPI, DisplayMetrics.DENSITY_LOW);\n            put(MDPI, DisplayMetrics.DENSITY_MEDIUM);\n            put(TVDPI, DisplayMetrics.DENSITY_TV);\n            put(HDPI, DisplayMetrics.DENSITY_HIGH);\n            put(XHDPI, DisplayMetrics.DENSITY_XHIGH);\n            put(XXHDPI, DisplayMetrics.DENSITY_XXHIGH);\n            put(XXXHDPI, DisplayMetrics.DENSITY_XXXHIGH);\n        }\n    };\n    public static final int DEVICE_DENSITY;\n\n    static {\n        DEVICE_DENSITY = Resources.getSystem().getDisplayMetrics().densityDpi;\n    }\n\n    public static final Map<String, Integer> LOCALE_RANKING = new HashMap<>();\n\n    static {\n        LocaleListCompat localeList = ConfigurationCompat.getLocales(Resources.getSystem().getConfiguration());\n        for (int i = 0; i < localeList.size(); i++) {\n            LOCALE_RANKING.put(Objects.requireNonNull(localeList.get(i)).getLanguage(), i);\n        }\n    }\n\n    public static String[] getTrackerCodeSignatures() {\n        return ContextUtils.getContext().getResources().getStringArray(R.array.tracker_signatures);\n    }\n\n    public static AhoCorasick getSearchableTrackerSignatures() {\n        if (sAhoCorasickTrackerCache == null) {\n            sAhoCorasickTrackerCache = new AhoCorasick(getTrackerCodeSignatures());\n        }\n        return sAhoCorasickTrackerCache;\n    }\n\n    public static void cleanup() {\n        if (sAhoCorasickTrackerCache != null) {\n            sAhoCorasickTrackerCache.close();\n            sAhoCorasickTrackerCache = null;\n        }\n    }\n\n    public static String[] getTrackerNames() {\n        if (sTrackerNames == null) {\n            sTrackerNames = ContextUtils.getContext().getResources().getStringArray(R.array.tracker_names);\n        }\n        return sTrackerNames;\n    }\n\n    @WorkerThread\n    public static List<DebloatObject> getDebloatObjects() {\n        if (sDebloatObjects == null) {\n            sDebloatObjects = loadDebloatObjects(ContextUtils.getContext(), new Gson());\n        }\n        return sDebloatObjects;\n    }\n\n    @WorkerThread\n    public static List<DebloatObject> getDebloatObjectsWithInstalledInfo(@NonNull Context context) {\n        AppDb appDb = new AppDb();\n        if (sDebloatObjects == null) {\n            sDebloatObjects = loadDebloatObjects(context, new Gson());\n        }\n        for (DebloatObject debloatObject : sDebloatObjects) {\n            debloatObject.fillInstallInfo(context, appDb);\n        }\n        return sDebloatObjects;\n    }\n\n    @NonNull\n    @WorkerThread\n    private static List<DebloatObject> loadDebloatObjects(@NonNull Context context, @NonNull Gson gson) {\n        HashMap<String, List<SuggestionObject>> idSuggestionObjectsMap = loadSuggestions(context, gson);\n        String jsonContent = FileUtils.getContentFromAssets(context, \"debloat.json\");\n        try {\n            List<DebloatObject> debloatObjects = Arrays.asList(gson.fromJson(jsonContent, DebloatObject[].class));\n            int id = 0;\n            for (DebloatObject debloatObject : debloatObjects) {\n                List<SuggestionObject> suggestionObjects = idSuggestionObjectsMap.get(debloatObject.getSuggestionId());\n                debloatObject.setSuggestions(suggestionObjects);\n                debloatObject.setId(id++);\n            }\n            return debloatObjects;\n        } catch (Throwable e) {\n            e.printStackTrace();\n            return Collections.emptyList();\n        }\n    }\n\n    @NonNull\n    @WorkerThread\n    private static HashMap<String, List<SuggestionObject>> loadSuggestions(@NonNull Context context, @NonNull Gson gson) {\n        String jsonContent = FileUtils.getContentFromAssets(context, \"suggestions.json\");\n        HashMap<String, List<SuggestionObject>> idSuggestionObjectsMap = new HashMap<>();\n        try {\n            SuggestionObject[] suggestionObjects = gson.fromJson(jsonContent, SuggestionObject[].class);\n            if (suggestionObjects != null) {\n                for (SuggestionObject suggestionObject : suggestionObjects) {\n                    List<SuggestionObject> objects = idSuggestionObjectsMap.get(suggestionObject.suggestionId);\n                    if (objects == null) {\n                        objects = new ArrayList<>();\n                        idSuggestionObjectsMap.put(suggestionObject.suggestionId, objects);\n                    }\n                    objects.add(suggestionObject);\n                }\n            }\n        } catch (Throwable th) {\n            th.printStackTrace();\n        }\n        return idSuggestionObjectsMap;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/accessibility/AccessibilityMultiplexer.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.accessibility;\n\nimport android.os.Bundle;\n\nimport androidx.annotation.IntDef;\nimport androidx.annotation.Nullable;\n\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\n\npublic class AccessibilityMultiplexer {\n    private static final int M_INSTALL = 1;\n    private static final int M_UNINSTALL = 1 << 1;\n    private static final int M_CLEAR_CACHE = 1 << 2;\n    private static final int M_CLEAR_DATA = 1 << 3;\n    private static final int M_FORCE_STOP = 1 << 4;\n    private static final int M_NAVIGATE_TO_STORAGE_AND_CACHE = 1 << 5;\n    private static final int M_LEADING_ACTIVITY_TRACKER = 1 << 6;\n\n    @Retention(RetentionPolicy.SOURCE)\n    @IntDef(flag = true, value = {\n            M_INSTALL,\n            M_UNINSTALL,\n            M_CLEAR_CACHE,\n            M_CLEAR_DATA,\n            M_FORCE_STOP,\n            M_NAVIGATE_TO_STORAGE_AND_CACHE,\n            M_LEADING_ACTIVITY_TRACKER,\n    })\n    private @interface Flags {\n    }\n\n    private static final AccessibilityMultiplexer sInstance = new AccessibilityMultiplexer();\n\n    public static AccessibilityMultiplexer getInstance() {\n        return sInstance;\n    }\n\n    @Flags\n    private int mFlags = 0;\n    private final Bundle mArgs = new Bundle();\n\n    public boolean isInstallEnabled() {\n        return (mFlags & M_INSTALL) != 0;\n    }\n\n    public boolean isUninstallEnabled() {\n        return (mFlags & M_UNINSTALL) != 0;\n    }\n\n    public boolean isClearCacheEnabled() {\n        return (mFlags & M_CLEAR_CACHE) != 0;\n    }\n\n    public boolean isClearDataEnabled() {\n        return (mFlags & M_CLEAR_DATA) != 0;\n    }\n\n    public boolean isForceStopEnabled() {\n        return (mFlags & M_FORCE_STOP) != 0;\n    }\n\n    public boolean isNavigateToStorageAndCache() {\n        return (mFlags & M_NAVIGATE_TO_STORAGE_AND_CACHE) != 0;\n    }\n    public boolean isLeadingActivityTracker() {\n        return (mFlags & M_LEADING_ACTIVITY_TRACKER) != 0;\n    }\n\n    public void clearFlags() {\n        mFlags = 0;\n    }\n\n    public void enableInstall(boolean enable) {\n        addOrRemoveFlag(M_INSTALL, enable);\n    }\n\n    public void enableUninstall(boolean enable) {\n        addOrRemoveFlag(M_UNINSTALL, enable);\n    }\n\n    public void enableClearCache(boolean enable) {\n        addOrRemoveFlag(M_CLEAR_CACHE, enable);\n    }\n\n    public void enableClearData(boolean enable) {\n        addOrRemoveFlag(M_CLEAR_DATA, enable);\n    }\n\n    public void enableForceStop(boolean enable) {\n        addOrRemoveFlag(M_FORCE_STOP, enable);\n    }\n\n    public void enableNavigateToStorageAndCache(boolean enable) {\n        addOrRemoveFlag(M_NAVIGATE_TO_STORAGE_AND_CACHE, enable);\n    }\n\n    public void enableLeadingActivityTracker(boolean enable) {\n        addOrRemoveFlag(M_LEADING_ACTIVITY_TRACKER, enable);\n    }\n\n    @Nullable\n    public String getTitleText() {\n        return mArgs.getString(\"title\");\n    }\n\n    public void setTitleText(String title) {\n        mArgs.putString(\"title\", title);\n    }\n\n    private void addOrRemoveFlag(@Flags int flag, boolean add) {\n        if (add) addFlag(flag);\n        else removeFlag(flag);\n    }\n\n    private void addFlag(@Flags int flag) {\n        mFlags |= flag;\n    }\n\n    private void removeFlag(@Flags int flag) {\n        mFlags &= ~flag;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/accessibility/BaseAccessibilityService.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.accessibility;\n\nimport android.accessibilityservice.AccessibilityService;\nimport android.accessibilityservice.AccessibilityServiceInfo;\nimport android.content.ComponentName;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.os.SystemClock;\nimport android.provider.Settings;\nimport android.view.accessibility.AccessibilityManager;\nimport android.view.accessibility.AccessibilityNodeInfo;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport java.util.List;\n\npublic abstract class BaseAccessibilityService extends AccessibilityService {\n    private Context mContext;\n\n    public void init(Context context) {\n        mContext = context.getApplicationContext();\n    }\n\n    /**\n     * Check if the accessibility service is enabled\n     */\n    public static boolean isAccessibilityEnabled(@NonNull Context context) {\n        AccessibilityManager accessibilityManager = (AccessibilityManager)\n                context.getSystemService(Context.ACCESSIBILITY_SERVICE);\n        List<AccessibilityServiceInfo> accessibilityServices =\n                accessibilityManager.getEnabledAccessibilityServiceList(AccessibilityServiceInfo.FEEDBACK_ALL_MASK);\n        for (AccessibilityServiceInfo info : accessibilityServices) {\n            ComponentName componentName = ComponentName.unflattenFromString(info.getId());\n            if (componentName.getPackageName().equals(context.getPackageName())) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    public void openAccessibilitySettings() {\n        Intent intent = new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS);\n        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);\n        mContext.startActivity(intent);\n    }\n\n    /**\n     * Simulate click\n     *\n     * @param nodeInfo nodeInfo\n     */\n    public void performViewClick(@Nullable AccessibilityNodeInfo nodeInfo) {\n        if (nodeInfo == null) {\n            return;\n        }\n        while (nodeInfo != null) {\n            if (nodeInfo.isClickable()) {\n                nodeInfo.performAction(AccessibilityNodeInfo.ACTION_CLICK);\n                break;\n            }\n            nodeInfo = nodeInfo.getParent();\n        }\n    }\n\n    /**\n     * Simulate back/return operation\n     */\n    public void performBackClick() {\n        SystemClock.sleep(500);\n        performGlobalAction(GLOBAL_ACTION_BACK);\n    }\n\n    /**\n     * Simulate scroll down\n     */\n    public void performScrollBackward() {\n        SystemClock.sleep(500);\n        performGlobalAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD);\n    }\n\n    /**\n     * Simulate scroll up\n     */\n    public void performScrollForward() {\n        SystemClock.sleep(500);\n        performGlobalAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD);\n    }\n\n    /**\n     * Find a view by its text\n     *\n     * @param text text\n     * @return View\n     */\n    public AccessibilityNodeInfo findViewByText(String text) {\n        return findViewByText(text, false);\n    }\n\n    /**\n     * Find a view by its text\n     *\n     * @param text      text\n     * @param clickable Whether the view can be clicked\n     * @return View\n     */\n    @Nullable\n    public AccessibilityNodeInfo findViewByText(String text, boolean clickable) {\n        AccessibilityNodeInfo accessibilityNodeInfo = getRootInActiveWindow();\n        if (accessibilityNodeInfo == null) {\n            return null;\n        }\n        List<AccessibilityNodeInfo> nodeInfoList = accessibilityNodeInfo.findAccessibilityNodeInfosByText(text);\n        if (nodeInfoList != null) {\n            for (AccessibilityNodeInfo nodeInfo : nodeInfoList) {\n                if (nodeInfo.isClickable() == clickable) {\n                    return nodeInfo;\n                }\n                nodeInfo.recycle();\n            }\n        }\n        return null;\n    }\n\n    /**\n     * Find a view by its ID\n     *\n     * @param id ID in resource ID format i.e. package:id/id_name\n     * @return View\n     */\n    @Nullable\n    public AccessibilityNodeInfo findViewById(String id) {\n        AccessibilityNodeInfo accessibilityNodeInfo = getRootInActiveWindow();\n        if (accessibilityNodeInfo == null) {\n            return null;\n        }\n        List<AccessibilityNodeInfo> nodeInfoList = accessibilityNodeInfo.findAccessibilityNodeInfosByViewId(id);\n        if (nodeInfoList != null) {\n            for (AccessibilityNodeInfo nodeInfo : nodeInfoList) {\n                return nodeInfo;\n            }\n        }\n        return null;\n    }\n\n    public void clickTextViewByText(String text) {\n        AccessibilityNodeInfo accessibilityNodeInfo = getRootInActiveWindow();\n        if (accessibilityNodeInfo == null) {\n            return;\n        }\n        List<AccessibilityNodeInfo> nodeInfoList = accessibilityNodeInfo.findAccessibilityNodeInfosByText(text);\n        if (nodeInfoList != null && !nodeInfoList.isEmpty()) {\n            for (AccessibilityNodeInfo nodeInfo : nodeInfoList) {\n                performViewClick(nodeInfo);\n                nodeInfo.recycle();\n                break;\n            }\n        }\n    }\n\n    public void clickTextViewByID(String id) {\n        AccessibilityNodeInfo accessibilityNodeInfo = getRootInActiveWindow();\n        if (accessibilityNodeInfo == null) {\n            return;\n        }\n        List<AccessibilityNodeInfo> nodeInfoList = accessibilityNodeInfo.findAccessibilityNodeInfosByViewId(id);\n        if (nodeInfoList != null) {\n            for (AccessibilityNodeInfo nodeInfo : nodeInfoList) {\n                performViewClick(nodeInfo);\n                nodeInfo.recycle();\n                break;\n            }\n        }\n    }\n\n    /**\n     * Set input text\n     *\n     * @param nodeInfo nodeInfo\n     * @param text     text\n     */\n    public void inputText(AccessibilityNodeInfo nodeInfo, String text) {\n        Bundle arguments = new Bundle();\n        arguments.putCharSequence(AccessibilityNodeInfo.ACTION_ARGUMENT_SET_TEXT_CHARSEQUENCE, text);\n        nodeInfo.performAction(AccessibilityNodeInfo.ACTION_SET_TEXT, arguments);\n    }\n\n    @Nullable\n    protected static AccessibilityNodeInfo findViewByText(@Nullable AccessibilityNodeInfo accessibilityNodeInfo,\n                                                          @NonNull String text, boolean clickable) {\n        if (accessibilityNodeInfo == null) return null;\n        List<AccessibilityNodeInfo> nodeInfoList = accessibilityNodeInfo.findAccessibilityNodeInfosByText(text);\n        if (nodeInfoList != null) {\n            for (AccessibilityNodeInfo nodeInfo : nodeInfoList) {\n                if (nodeInfo.isClickable() == clickable) {\n                    return nodeInfo;\n                }\n                nodeInfo.recycle();\n            }\n        }\n        return null;\n    }\n\n    @Nullable\n    protected static AccessibilityNodeInfo findViewByTextRecursive(@Nullable AccessibilityNodeInfo accessibilityNodeInfo,\n                                                                   @NonNull String text) {\n        if (accessibilityNodeInfo == null) return null;\n        List<AccessibilityNodeInfo> nodeInfoList = accessibilityNodeInfo.findAccessibilityNodeInfosByText(text);\n        if (nodeInfoList != null) {\n            for (AccessibilityNodeInfo nodeInfo : nodeInfoList) {\n                return nodeInfo;\n            }\n        }\n        for (int i = 0; i < accessibilityNodeInfo.getChildCount(); ++i) {\n            AccessibilityNodeInfo nodeInfo = findViewByTextRecursive(accessibilityNodeInfo.getChild(i), text);\n            if (nodeInfo != null) {\n                return nodeInfo;\n            }\n        }\n        return null;\n    }\n\n    @Nullable\n    protected static AccessibilityNodeInfo findViewByClassName(@Nullable AccessibilityNodeInfo nodeInfo,\n                                                               @NonNull CharSequence className) {\n        if (nodeInfo == null) return null;\n        for (int i = 0; i < nodeInfo.getChildCount(); ++i) {\n            AccessibilityNodeInfo child = nodeInfo.getChild(i);\n            if (className.equals(child.getClassName())) {\n                return child;\n            }\n            child.recycle();\n        }\n        return null;\n    }\n\n    protected static void waitUntilEnabled(@NonNull AccessibilityNodeInfo nodeInfo, int timesWait) {\n        if (timesWait == 0) timesWait = 10; // Wait 5 seconds\n        while (!nodeInfo.isEnabled() && timesWait > 0) {\n            SystemClock.sleep(500);\n            --timesWait;\n        }\n    }\n}"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/accessibility/NoRootAccessibilityService.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.accessibility;\n\nimport android.content.Intent;\nimport android.content.pm.PackageManager;\nimport android.content.res.Resources;\nimport android.os.Build;\nimport android.os.SystemClock;\nimport android.text.TextUtils;\nimport android.view.accessibility.AccessibilityEvent;\nimport android.view.accessibility.AccessibilityNodeInfo;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport io.github.muntashirakon.AppManager.accessibility.activity.TrackerWindow;\nimport io.github.muntashirakon.AppManager.utils.ResourceUtil;\nimport io.github.muntashirakon.AppManager.utils.appearance.AppearanceUtils;\n\npublic class NoRootAccessibilityService extends BaseAccessibilityService {\n    private static final CharSequence SETTING_PACKAGE = \"com.android.settings\";\n    private static final CharSequence INSTALLER_PACKAGE = \"com.android.packageinstaller\";\n\n    private final AccessibilityMultiplexer mMultiplexer = AccessibilityMultiplexer.getInstance();\n    private PackageManager mPm;\n    private int mTries = 1;\n    @Nullable\n    private TrackerWindow mTrackerWindow;\n\n    @Override\n    public void onCreate() {\n        super.onCreate();\n        mPm = AppearanceUtils.getSystemContext(this).getPackageManager();\n    }\n\n    @Override\n    public void onAccessibilityEvent(AccessibilityEvent event) {\n        if (mMultiplexer.isLeadingActivityTracker()) {\n            if (mTrackerWindow == null) {\n                mTrackerWindow = new TrackerWindow(this);\n            }\n            mTrackerWindow.showOrUpdate(AccessibilityEvent.obtain(event));\n        } else if (mTrackerWindow != null) {\n            mTrackerWindow.dismiss();\n            mTrackerWindow = null;\n        }\n        if (event.getEventType() != AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) {\n            return;\n        }\n        CharSequence packageName = event.getPackageName();\n        if (INSTALLER_PACKAGE.equals(packageName)) {\n            automateInstallationUninstallation(event);\n            return;\n        }\n        if (SETTING_PACKAGE.equals(packageName)) {\n            // Clear data/cache, force-stop\n            if (event.getClassName().equals(\"com.android.settings.applications.InstalledAppDetailsTop\")) {\n                AccessibilityNodeInfo node = findViewByText(getString(event, \"force_stop\"), true);\n                if (mMultiplexer.isForceStopEnabled()) {\n                    if (node != null) {\n                        if (node.isEnabled()) {\n                            mTries = 0;\n                            performViewClick(node);\n                        } else if (mTries > 0 && navigateToStorageAndCache(event)) {\n                            // Hack to enable force-stop when it is disabled due to Android bug\n                            performBackClick();\n                            --mTries;\n                        } else performBackClick();\n                        node.recycle();\n                    } else performBackClick();\n                } else if (mMultiplexer.isNavigateToStorageAndCache()) {\n                    SystemClock.sleep(1000);\n                    navigateToStorageAndCache(event);\n                }\n            } else if (event.getClassName().equals(\"com.android.settings.SubSettings\")\n                    || getString(event, \"storage_settings\").equals(event.getText().toString())) {\n                if (mMultiplexer.isClearDataEnabled()) {\n                    performViewClick(findViewByText(getString(event, \"clear_user_data_text\"), true));\n                }\n                if (mMultiplexer.isClearCacheEnabled()) {\n                    mMultiplexer.enableClearCache(false);\n                    AccessibilityNodeInfo node = findViewByText(getString(event, \"clear_cache_btn_text\"), true);\n                    if (node != null) {\n                        if (node.isEnabled()) {\n                            performViewClick(node);\n                        }\n                        performBackClick();\n                        performBackClick();\n                        node.recycle();\n                    }\n                }\n            } else if (event.getClassName().equals(\"androidx.appcompat.app.AlertDialog\")) {\n                if (mMultiplexer.isForceStopEnabled() && findViewByText(getString(event, \"force_stop_dlg_title\")) != null) {\n                    mMultiplexer.enableForceStop(false);\n                    mTries = 1; // Restore tries\n                    performViewClick(findViewByText(getString(event, \"dlg_ok\"), true));\n                    performBackClick();\n                }\n                if (mMultiplexer.isClearDataEnabled() && findViewByText(getString(event, \"clear_data_dlg_title\")) != null) {\n                    mMultiplexer.enableClearData(false);\n                    performViewClick(findViewByText(getString(event, \"dlg_ok\"), true));\n                    performBackClick();\n                    performBackClick();\n                }\n            }\n        }\n    }\n\n    @Override\n    public void onInterrupt() {\n    }\n\n    @Override\n    public boolean onUnbind(Intent intent) {\n        if (mTrackerWindow != null) {\n            mTrackerWindow.dismiss();\n            mTrackerWindow = null;\n        }\n        return super.onUnbind(intent);\n    }\n\n    private void automateInstallationUninstallation(@NonNull AccessibilityEvent event) {\n        if (event.getClassName().equals(\"android.app.Dialog\")) {\n            if (mMultiplexer.isInstallEnabled()) {\n                // Install\n                performViewClick(findViewByText(getString(event, \"install\"), true)); // install_text\n            }\n        } else if (event.getClassName().equals(\"com.android.packageinstaller.UninstallerActivity\")) {\n            if (mMultiplexer.isUninstallEnabled()) {\n                // uninstall\n                performViewClick(findViewByText(getString(event, \"ok\"), true)); // dlg_ok\n            }\n        }\n    }\n\n    private boolean navigateToStorageAndCache(AccessibilityEvent event) {\n        String storageSettings;\n        try {\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {\n                storageSettings = getString(event, \"storage_settings_for_app\");\n            } else storageSettings = getString(event, \"storage_label\");\n        } catch (Resources.NotFoundException e) {\n            // Failed: non-AOSP device\n            return false;\n        }\n        SystemClock.sleep(500); // It may take a few moments to initialise the Recycler/List views\n        AccessibilityNodeInfo storageNode = findViewByTextRecursive(getRootInActiveWindow(), storageSettings);\n        if (storageNode != null) {\n            mMultiplexer.enableNavigateToStorageAndCache(false);  // prevent infinite loop\n            performViewClick(storageNode);\n            storageNode.recycle();\n            return true;\n        }\n        // Failed\n        performBackClick();\n        return false;\n    }\n\n    /**\n     * Return the string value associated with a particular resource ID. It will be stripped of any styled text information.\n     *\n     * @param stringRes The desired resource identifier.\n     * @return String The string data associated with the resource, stripped of styled text information.\n     * @throws Resources.NotFoundException Throws NotFoundException if the given ID or package does not exist.\n     */\n    private String getString(@NonNull AccessibilityEvent event, @NonNull String stringRes)\n            throws Resources.NotFoundException {\n        CharSequence packageName = event.getPackageName();\n        CharSequence className = event.getClassName();\n        if (TextUtils.isEmpty(packageName)) {\n            throw new Resources.NotFoundException(\"Empty package name\");\n        }\n        ResourceUtil resUtil = new ResourceUtil();\n        if (!TextUtils.isEmpty(className)) {\n            if (!resUtil.loadResources(mPm, packageName.toString(), className.toString())\n                    && !resUtil.loadResources(mPm, packageName.toString())\n                    && !resUtil.loadAndroidResources()) {\n                throw new Resources.NotFoundException(\"Couldn't load resources for package: \" + packageName\n                        + \", class: \" + className);\n            }\n        } else if (!resUtil.loadResources(mPm, packageName.toString()) && !resUtil.loadAndroidResources()) {\n            throw new Resources.NotFoundException(\"Couldn't load resources for package: \" + packageName);\n        }\n        return resUtil.getString(stringRes);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/accessibility/activity/LeadingActivityTrackerActivity.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.accessibility.activity;\n\nimport android.content.Intent;\nimport android.net.Uri;\nimport android.os.Build;\nimport android.os.Bundle;\nimport android.provider.Settings;\n\nimport androidx.activity.result.ActivityResultLauncher;\nimport androidx.activity.result.contract.ActivityResultContracts;\nimport androidx.annotation.Nullable;\n\nimport com.google.android.material.dialog.MaterialAlertDialogBuilder;\n\nimport io.github.muntashirakon.AppManager.BaseActivity;\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.accessibility.AccessibilityMultiplexer;\nimport io.github.muntashirakon.AppManager.accessibility.NoRootAccessibilityService;\nimport io.github.muntashirakon.AppManager.self.SelfPermissions;\nimport io.github.muntashirakon.AppManager.settings.FeatureController;\nimport io.github.muntashirakon.AppManager.utils.ThreadUtils;\n\npublic class LeadingActivityTrackerActivity extends BaseActivity {\n    private final ActivityResultLauncher<Intent> mSettingsLauncher = registerForActivityResult(\n            new ActivityResultContracts.StartActivityForResult(), result -> {\n                // Init again\n                init();\n            });\n    private final ActivityResultLauncher<Intent> mUsageAccessSettingsLauncher = registerForActivityResult(\n            new ActivityResultContracts.StartActivityForResult(), result -> {\n                // Init again\n                init();\n            });\n\n    @Override\n    protected void onAuthenticated(@Nullable Bundle savedInstanceState) {\n        init();\n    }\n\n    @Override\n    public boolean getTransparentBackground() {\n        return true;\n    }\n\n    private void init() {\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !Settings.canDrawOverlays(this)) {\n            new MaterialAlertDialogBuilder(this)\n                    .setTitle(R.string.grant_required_permission)\n                    .setMessage(R.string.grant_overlay_permission_message)\n                    .setCancelable(false)\n                    .setPositiveButton(R.string.ok, (dialog, which) -> {\n                        Intent intent = new Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION);\n                        intent.setData(Uri.parse(\"package:\" + getPackageName()));\n                        mSettingsLauncher.launch(intent);\n                    })\n                    .setNegativeButton(R.string.go_back, (dialog, which) -> finish())\n                    .show();\n            return;\n        }\n        if (!SelfPermissions.checkUsageStatsPermission()) {\n            ThreadUtils.postOnMainThread(() -> new MaterialAlertDialogBuilder(this)\n                    .setTitle(R.string.grant_usage_access)\n                    .setMessage(R.string.grant_usage_acess_message)\n                    .setCancelable(false)\n                    .setPositiveButton(R.string.go, (dialog, which) -> {\n                        mUsageAccessSettingsLauncher.launch(new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS));\n                    })\n                    .setNegativeButton(R.string.go_back, (dialog, which) -> finish())\n                    .show());\n            return;\n        }\n        if (!NoRootAccessibilityService.isAccessibilityEnabled(this)) {\n            new MaterialAlertDialogBuilder(this)\n                    .setTitle(R.string.grant_required_permission)\n                    .setMessage(R.string.grant_accessibility_permission_for_tracking_window_contents)\n                    .setCancelable(false)\n                    .setPositiveButton(R.string.ok, (dialog, which) ->\n                            mSettingsLauncher.launch(new Intent(Settings.ACTION_ACCESSIBILITY_SETTINGS)))\n                    .setNegativeButton(R.string.go_back, (dialog, which) -> finish())\n                    .show();\n            return;\n        }\n        AccessibilityMultiplexer.getInstance().enableLeadingActivityTracker(true);\n        finish();\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/accessibility/activity/TrackerWindow.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.accessibility.activity;\n\nimport android.annotation.SuppressLint;\nimport android.app.usage.UsageEvents;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.graphics.PixelFormat;\nimport android.graphics.Point;\nimport android.os.Build;\nimport android.os.UserHandleHidden;\nimport android.text.Editable;\nimport android.text.TextUtils;\nimport android.view.Display;\nimport android.view.Gravity;\nimport android.view.MotionEvent;\nimport android.view.View;\nimport android.view.WindowManager;\nimport android.view.accessibility.AccessibilityEvent;\nimport android.view.accessibility.AccessibilityNodeInfo;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport com.google.android.material.button.MaterialButton;\nimport com.google.android.material.card.MaterialCardView;\nimport com.google.android.material.imageview.ShapeableImageView;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Objects;\nimport java.util.concurrent.Future;\n\nimport io.github.muntashirakon.AppManager.BuildConfig;\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.accessibility.AccessibilityMultiplexer;\nimport io.github.muntashirakon.AppManager.compat.UsageStatsManagerCompat;\nimport io.github.muntashirakon.AppManager.details.AppDetailsActivity;\nimport io.github.muntashirakon.AppManager.utils.ThreadUtils;\nimport io.github.muntashirakon.AppManager.utils.UIUtils;\nimport io.github.muntashirakon.AppManager.utils.Utils;\nimport io.github.muntashirakon.AppManager.utils.appearance.AppearanceUtils;\nimport io.github.muntashirakon.widget.TextInputTextView;\n\npublic class TrackerWindow implements View.OnTouchListener {\n    public final WindowManager mWindowManager;\n    private final WindowManager.LayoutParams mWindowLayoutParams;\n    private final View mView;\n    private final ShapeableImageView mIconView;\n    private final MaterialCardView mContentView;\n    private final TextInputTextView mPackageNameView;\n    private final TextInputTextView mActivityNameView;\n    private final TextInputTextView mClassNameView;\n    private final TextInputTextView mClassHierarchyView;\n    private final MaterialButton mPlayPauseButton;\n    private final Point mWindowSize = new Point(0, 0);\n    private final Point mWindowPosition = new Point(0, 0);\n    private final Point mPressPosition = new Point(0, 0);\n    private final int mMaxWidth;\n    private boolean mPaused = false;\n    private boolean mIconified = false;\n    private boolean mViewAttached = false;\n    @Nullable\n    private Future<?> mClassHierarchyResult;\n\n    @SuppressLint(\"ClickableViewAccessibility\")\n    public TrackerWindow(@NonNull Context context) {\n        Context themedContext = AppearanceUtils.getThemedContext(context, true);\n        mWindowManager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);\n        int type = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O ? WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY\n                : WindowManager.LayoutParams.TYPE_PHONE;\n        Display display = mWindowManager.getDefaultDisplay();\n        int displayWidth = display.getWidth();\n        display.getRealSize(mWindowSize);\n        mMaxWidth = (displayWidth / 2) + 300; // FIXME: 5/2/23 Find a better way to represent a display\n        int flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;\n        mWindowLayoutParams = new WindowManager.LayoutParams(WindowManager.LayoutParams.WRAP_CONTENT,\n                WindowManager.LayoutParams.WRAP_CONTENT, type, flags, PixelFormat.TRANSLUCENT);\n        mWindowLayoutParams.gravity = Gravity.CENTER;\n        mWindowLayoutParams.width = mMaxWidth;\n        mWindowLayoutParams.windowAnimations = android.R.style.Animation_Toast;\n\n        mView = View.inflate(themedContext, R.layout.window_activity_tracker, null);\n        mIconView = mView.findViewById(R.id.icon);\n        mContentView = mView.findViewById(R.id.content);\n        mPackageNameView = mView.findViewById(R.id.package_name);\n        mActivityNameView = mView.findViewById(R.id.activity_name);\n        mClassNameView = mView.findViewById(R.id.class_name);\n        mClassHierarchyView = mView.findViewById(R.id.class_hierarchy);\n        mPlayPauseButton = mView.findViewById(R.id.action_play_pause);\n        mPackageNameView.setOnLongClickListener(v -> {\n            Editable packageName = mPackageNameView.getText();\n            if (TextUtils.isEmpty(packageName)) {\n                return false;\n            }\n            copyText(\"Package name\", packageName);\n            return true;\n        });\n        mActivityNameView.setOnLongClickListener(v -> {\n            Editable activityName = mActivityNameView.getText();\n            if (TextUtils.isEmpty(activityName)) {\n                return false;\n            }\n            copyText(\"Activity name\", activityName);\n            return true;\n        });\n        mClassNameView.setOnLongClickListener(v -> {\n            Editable className = mClassNameView.getText();\n            if (TextUtils.isEmpty(className)) {\n                return false;\n            }\n            copyText(\"Class name\", className);\n            return true;\n        });\n        mClassHierarchyView.setOnLongClickListener(v -> {\n            Editable hierarchy = mClassHierarchyView.getText();\n            if (TextUtils.isEmpty(hierarchy)) {\n                return false;\n            }\n            copyText(\"Class hierarchy\", hierarchy);\n            return true;\n        });\n        mView.findViewById(R.id.info).setOnClickListener(v -> {\n            Editable packageName = mPackageNameView.getText();\n            if (TextUtils.isEmpty(packageName)) {\n                return;\n            }\n            Intent appInfoIntent = AppDetailsActivity.getIntent(context, packageName.toString(), UserHandleHidden.myUserId(), true);\n            appInfoIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);\n            try {\n                context.startActivity(appInfoIntent);\n            } catch (Throwable th) {\n                UIUtils.displayLongToast(\"Error: \" + th.getMessage());\n            }\n        });\n        mView.findViewById(R.id.mini).setOnClickListener(v -> iconify());\n        mPlayPauseButton.setOnClickListener(v -> {\n            mPaused = !mPaused;\n            mPlayPauseButton.setIconResource(mPaused ? R.drawable.ic_play_arrow : R.drawable.ic_pause);\n        });\n        mView.findViewById(android.R.id.closeButton).setOnClickListener(v -> dismiss());\n        mIconView.setVisibility(View.GONE);\n        mIconView.setOnClickListener(v -> expand());\n        mView.findViewById(R.id.drag).setOnTouchListener(this);\n        mIconView.setOnTouchListener(this);\n    }\n\n    @SuppressLint(\"ClickableViewAccessibility\")\n    @Override\n    public boolean onTouch(View v, MotionEvent event) {\n        Point point;\n        int action = event.getAction();\n        if (action == MotionEvent.ACTION_DOWN) {\n            point = new Point((int) event.getRawX(), (int) event.getRawY());\n            mPressPosition.set(point.x, point.y);\n            mWindowPosition.set(mWindowLayoutParams.x, mWindowLayoutParams.y);\n            return true;\n        } else if (action == MotionEvent.ACTION_MOVE) {\n            point = new Point((int) event.getRawX(), (int) event.getRawY());\n            int delX = point.x - mPressPosition.x;\n            int delY = point.y - mPressPosition.y;\n            mWindowLayoutParams.x = mWindowPosition.x + delX;\n            mWindowLayoutParams.y = mWindowPosition.y + delY;\n            updateLayout();\n            return true;\n        }\n        if (v == mIconView && action == MotionEvent.ACTION_UP) {\n            point = new Point((int) event.getRawX(), (int) event.getRawY());\n            int delX = Math.abs(point.x - mPressPosition.x);\n            int delY = Math.abs(point.y - mPressPosition.y);\n            if (delX < 1 && delY < 1) {\n                v.performClick();\n                return true;\n            }\n        }\n        return false;\n    }\n\n    public void showOrUpdate(AccessibilityEvent event) {\n        if (!mViewAttached) {\n            mViewAttached = true;\n            mWindowManager.addView(mView, mWindowLayoutParams);\n        }\n        if (!mPaused) {\n            @Nullable\n            CharSequence packageName = event.getPackageName();\n            if (packageName != null && BuildConfig.APPLICATION_ID.contentEquals(packageName)) {\n                // On some devices, this window always gets the focus\n                CharSequence className = event.getClassName();\n                if (className != null && \"android.widget.EditText\".contentEquals(className)) {\n                    // For some reason, only this class is focused\n                    if (event.getSource() == null) {\n                        // No class hierarchy. This is the intended event\n                        return;\n                    }\n                }\n            }\n            if (mClassHierarchyResult != null) {\n                mClassHierarchyResult.cancel(true);\n            }\n            mPackageNameView.setText(packageName);\n            mClassNameView.setText(event.getClassName());\n            mClassHierarchyResult = ThreadUtils.postOnBackgroundThread(() -> {\n                CharSequence classHierarchy = TextUtils.join(\"\\n\", getClassHierarchy(event));\n                String activityName = getActivityName(event);\n                ThreadUtils.postOnMainThread(() -> {\n                    mActivityNameView.setText(activityName);\n                    mClassHierarchyView.setText(classHierarchy);\n                });\n            });\n        }\n    }\n\n    public void dismiss() {\n        AccessibilityMultiplexer.getInstance().enableLeadingActivityTracker(false);\n        mViewAttached = false;\n        if (mClassHierarchyResult != null) {\n            mClassHierarchyResult.cancel(true);\n        }\n        try {\n            mWindowManager.removeView(mView);\n        } catch (Exception ignore) {\n        }\n    }\n\n    private void iconify() {\n        mPaused = true;\n        mIconified = true;\n        // Window position may need to be adjusted to display the icon\n        // (0,0) is middle\n        int height = -mWindowSize.y / 2;\n        if (mWindowLayoutParams.y < height) {\n            mWindowPosition.y = height;\n            mWindowLayoutParams.y = height;\n        }\n        mIconView.setVisibility(View.VISIBLE);\n        mContentView.setVisibility(View.GONE);\n        updateLayout();\n    }\n\n    private void expand() {\n        mContentView.setVisibility(View.VISIBLE);\n        mIconView.setVisibility(View.GONE);\n        mPaused = false;\n        mIconified = false;\n        // Window position may need to be adjusted to display the drag handle\n        // (0,0) is middle\n        int width = (-mWindowSize.x + mMaxWidth) / 2;\n        if (mWindowLayoutParams.x < width) {\n            mWindowPosition.x = width;\n            mWindowLayoutParams.x = width;\n        }\n        updateLayout();\n    }\n\n    private void updateLayout() {\n        mWindowLayoutParams.width = mIconified ? WindowManager.LayoutParams.WRAP_CONTENT : mMaxWidth;\n        mWindowManager.updateViewLayout(mView, mWindowLayoutParams);\n    }\n\n    private void copyText(CharSequence label, CharSequence content) {\n        Utils.copyToClipboard(mView.getContext(), label, content);\n    }\n\n    @Nullable\n    public String getActivityName(@NonNull AccessibilityEvent event) {\n        if (event.getPackageName() == null) {\n            return null;\n        }\n        String packageName = event.getPackageName().toString();\n        UsageEvents.Event usageEvent = new UsageEvents.Event();\n        long currentTimeMillis = System.currentTimeMillis();\n        long timeDiff = 5_000;\n        int tries = 0;\n        do {\n            UsageEvents queryEvents = UsageStatsManagerCompat.queryEvents(currentTimeMillis - timeDiff,\n                    currentTimeMillis, UserHandleHidden.myUserId());\n            if (queryEvents == null) {\n                return null;\n            }\n            long lastTime = 0L;\n            String activityName = null;\n            while (queryEvents.hasNextEvent()) {\n                queryEvents.getNextEvent(usageEvent);\n                if (usageEvent.getEventType() == UsageEvents.Event.ACTIVITY_RESUMED\n                        && Objects.equals(packageName, usageEvent.getPackageName())\n                        && lastTime < usageEvent.getTimeStamp()) {\n                    lastTime = usageEvent.getTimeStamp();\n                    activityName = usageEvent.getClassName();\n                }\n            }\n            if (activityName != null) {\n                return activityName;\n            }\n            timeDiff *= 60;\n        } while ((++tries) != 3);\n        return null;\n    }\n\n    @NonNull\n    private static List<CharSequence> getClassHierarchy(@NonNull AccessibilityEvent event) {\n        List<CharSequence> classHierarchies = new ArrayList<>();\n        AccessibilityNodeInfo nodeInfo = event.getSource();\n        if (nodeInfo != null) {\n            classHierarchies.add(nodeInfo.getClassName());\n            int depth = 0;\n            while (depth < 20) { // Limit depth to avoid running forever\n                AccessibilityNodeInfo tmpNodeInfo = nodeInfo.getParent();\n                if (tmpNodeInfo != null) {\n                    nodeInfo.recycle();\n                    nodeInfo = tmpNodeInfo;\n                    classHierarchies.add(nodeInfo.getClassName());\n                } else {\n                    // Max depth reached\n                    break;\n                }\n                ++depth;\n                if (ThreadUtils.isInterrupted()) {\n                    return Collections.emptyList();\n                }\n            }\n            try {\n                if (depth == 20) {\n                    classHierarchies.add(\"...\");\n                }\n            } finally {\n                nodeInfo.recycle();\n            }\n        }\n        Collections.reverse(classHierarchies);\n        if (ThreadUtils.isInterrupted()) {\n            return Collections.emptyList();\n        }\n        int size = classHierarchies.size();\n        if (size <= 1) {\n            return classHierarchies;\n        }\n        classHierarchies.set(0, \"┬ \" + classHierarchies.get(0));\n        for (int i = 1; i < size; ++i) {\n            StringBuilder sb = new StringBuilder();\n            for (int j = 1; j < i; ++j) {\n                sb.append(' ');\n            }\n            if (i != (size - 1)) {\n                sb.append(\"└┬ \");\n            } else sb.append(\"└─ \");\n            sb.append(classHierarchies.get(i));\n            classHierarchies.set(i, sb.toString());\n            if (ThreadUtils.isInterrupted()) {\n                return Collections.emptyList();\n            }\n        }\n        return classHierarchies;\n    }\n}"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/adb/AdbConnectionManager.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.adb;\n\nimport android.os.Build;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.WorkerThread;\nimport androidx.lifecycle.LiveData;\nimport androidx.lifecycle.MutableLiveData;\n\nimport java.security.PrivateKey;\nimport java.security.cert.Certificate;\n\nimport io.github.muntashirakon.AppManager.crypto.ks.KeyPair;\nimport io.github.muntashirakon.AppManager.crypto.ks.KeyStoreManager;\nimport io.github.muntashirakon.AppManager.crypto.ks.KeyStoreUtils;\nimport io.github.muntashirakon.AppManager.logs.Log;\nimport io.github.muntashirakon.AppManager.utils.ThreadUtils;\nimport io.github.muntashirakon.adb.AbsAdbConnectionManager;\n\npublic class AdbConnectionManager extends AbsAdbConnectionManager {\n    public static final String TAG = AdbConnectionManager.class.getSimpleName();\n\n    public static final String ADB_KEY_ALIAS = \"adb_rsa\";\n\n    private static AdbConnectionManager sInstance;\n\n    public static AdbConnectionManager getInstance() throws Exception {\n        if (sInstance == null) {\n            sInstance = new AdbConnectionManager();\n        }\n        return sInstance;\n    }\n\n    @NonNull\n    private final KeyPair mKeyPair;\n    private final MutableLiveData<Exception> mPairingObserver = new MutableLiveData<>();\n\n    public AdbConnectionManager() throws Exception {\n        setApi(Build.VERSION.SDK_INT);\n        KeyStoreManager keyStoreManager = KeyStoreManager.getInstance();\n        KeyPair keyPair = keyStoreManager.getKeyPairNoThrow(ADB_KEY_ALIAS);\n        if (keyPair == null) {\n            String subject = \"CN=App Manager\";\n            keyPair = KeyStoreUtils.generateRSAKeyPair(subject, 2048, System.currentTimeMillis() + 86400000);\n            keyStoreManager.addKeyPair(ADB_KEY_ALIAS, keyPair, true);\n        }\n        mKeyPair = keyPair;\n    }\n\n    public LiveData<Exception> getPairingObserver() {\n        return mPairingObserver;\n    }\n\n    @WorkerThread\n    public void pairLiveData(@NonNull String host, int port, @NonNull String pairingCode) throws Exception {\n        try {\n            ThreadUtils.ensureWorkerThread();\n            pair(host, port, pairingCode);\n            mPairingObserver.postValue(null);\n        } catch (Exception e) {\n            Log.w(TAG, \"Pairing failed.\", e);\n            mPairingObserver.postValue(e);\n            throw e;\n        }\n    }\n\n    @NonNull\n    @Override\n    protected PrivateKey getPrivateKey() {\n        return mKeyPair.getPrivateKey();\n    }\n\n    @NonNull\n    @Override\n    protected Certificate getCertificate() {\n        return mKeyPair.getCertificate();\n    }\n\n    @NonNull\n    @Override\n    protected String getDeviceName() {\n        return \"AppManager\";\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/adb/AdbPairingService.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.adb;\n\nimport static io.github.muntashirakon.AppManager.types.ForegroundService.FOREGROUND_SERVICE_TYPE_DATA_SYNC;\nimport static io.github.muntashirakon.AppManager.types.ForegroundService.FOREGROUND_SERVICE_TYPE_SPECIAL_USE;\n\nimport android.Manifest;\nimport android.app.Notification;\nimport android.app.PendingIntent;\nimport android.app.Service;\nimport android.content.Intent;\nimport android.os.Build;\nimport android.os.Bundle;\nimport android.os.IBinder;\n\nimport androidx.annotation.MainThread;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.RequiresApi;\nimport androidx.core.app.NotificationChannelCompat;\nimport androidx.core.app.NotificationCompat;\nimport androidx.core.app.NotificationManagerCompat;\nimport androidx.core.app.PendingIntentCompat;\nimport androidx.core.app.RemoteInput;\nimport androidx.core.app.ServiceCompat;\nimport androidx.lifecycle.MutableLiveData;\nimport androidx.lifecycle.Observer;\n\nimport io.github.muntashirakon.AppManager.BuildConfig;\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.logs.Log;\nimport io.github.muntashirakon.AppManager.self.SelfPermissions;\nimport io.github.muntashirakon.AppManager.servermanager.ServerConfig;\nimport io.github.muntashirakon.AppManager.settings.Prefs;\nimport io.github.muntashirakon.AppManager.utils.ThreadUtils;\nimport io.github.muntashirakon.adb.android.AdbMdns;\n\n// This works as follows:\n// 1. Start searching for a pairing port\n// 2. A port is found, ask to enter a pairing code\n// 3. Start pairing\n// 4. Exit with result, or ask to retry\n@RequiresApi(Build.VERSION_CODES.R)\npublic class AdbPairingService extends Service {\n    public static final String TAG = AdbPairingService.class.getSimpleName();\n    public static final String CHANNEL_ID = BuildConfig.APPLICATION_ID + \".channel.ADB_PAIRING\";\n    public static final String ACTION_START_SEARCHING = BuildConfig.APPLICATION_ID + \".action.START_SEARCHING\";\n    public static final String ACTION_STOP_SEARCHING = BuildConfig.APPLICATION_ID + \".action.STOP_SEARCHING\";\n    public static final String ACTION_START_PAIRING = BuildConfig.APPLICATION_ID + \".action.ENTER_CODE\";\n    public static final String EXTRA_PORT = \"port\";\n    public static final String INPUT_CODE = \"code\";\n\n    private NotificationCompat.Builder mNotificationBuilder;\n    private boolean mStartedSearching = false;\n    private AdbMdns mAdbMdnsPairing;\n    private final MutableLiveData<Integer> mAdbPairingPort = new MutableLiveData<>();\n    private final Observer<Integer> mAdbPairingPortObserver = port -> {\n        Log.i(TAG, \"Found port %d\", port);\n        inputPairingCode(port);\n    };\n\n    @Override\n    public void onCreate() {\n        super.onCreate();\n        NotificationManagerCompat notificationManager = NotificationManagerCompat.from(this);\n        NotificationChannelCompat notificationChannel = new NotificationChannelCompat.Builder(CHANNEL_ID, NotificationManagerCompat.IMPORTANCE_HIGH)\n                .setName(\"ADB Pairing\")\n                .setSound(null, null)\n                .setShowBadge(false)\n                .build();\n        notificationManager.createNotificationChannel(notificationChannel);\n        mNotificationBuilder = new NotificationCompat.Builder(this, CHANNEL_ID)\n                .setDefaults(Notification.DEFAULT_ALL)\n                .setLocalOnly(!Prefs.Misc.sendNotificationsToConnectedDevices())\n                .setContentTitle(getString(R.string.wireless_debugging))\n                .setSubText(getText(R.string.wireless_debugging))\n                .setSmallIcon(R.drawable.ic_default_notification)\n                .setPriority(NotificationCompat.PRIORITY_HIGH);\n\n    }\n\n    @Override\n    public int onStartCommand(Intent intent, int flags, int startId) {\n        if (intent == null || intent.getAction() == null) {\n            // Invalid intent\n            return START_NOT_STICKY;\n        }\n        switch (intent.getAction()) {\n            case ACTION_START_SEARCHING:\n                startSearching();\n                return START_REDELIVER_INTENT;\n            case ACTION_START_PAIRING:\n                int port = intent.getIntExtra(EXTRA_PORT, -1);\n                Bundle remoteInputs = RemoteInput.getResultsFromIntent(intent);\n                if (port != -1 && remoteInputs != null) {\n                    String code = remoteInputs.getCharSequence(INPUT_CODE, \"\").toString().trim();\n                    startPairing(port, code);\n                } else {\n                    // Wrong inputs, continue searching\n                    startSearching();\n                }\n                return START_REDELIVER_INTENT;\n            case ACTION_STOP_SEARCHING:\n                ServiceCompat.stopForeground(this, ServiceCompat.STOP_FOREGROUND_REMOVE);\n                stopSelf();\n            default:\n                return START_NOT_STICKY;\n        }\n    }\n\n    @Nullable\n    @Override\n    public IBinder onBind(Intent intent) {\n        return null;\n    }\n\n    @Override\n    public void onDestroy() {\n        super.onDestroy();\n        if (mStartedSearching) {\n            // Still looking for a port, hence the pairing wasn't successful\n            // Fail intentionally to avoid looping forever\n            Log.i(TAG, \"Stop searching for an active port...\");\n            ThreadUtils.postOnBackgroundThread(() -> {\n                try {\n                    AdbConnectionManager.getInstance().pairLiveData(ServerConfig.getAdbHost(this), -1, \"\");\n                } catch (Exception ignore) {\n                }\n            });\n            stopSearching();\n        }\n    }\n\n    @MainThread\n    private void startSearching() {\n        if (mStartedSearching) {\n            return;\n        }\n        mStartedSearching = true;\n        if (mAdbMdnsPairing == null) {\n            mAdbMdnsPairing = new AdbMdns(getApplication(), AdbMdns.SERVICE_TYPE_TLS_PAIRING, (hostAddress, port) -> {\n                if (port != -1) {\n                    mAdbPairingPort.postValue(port);\n                }\n            });\n        }\n        mAdbPairingPort.observeForever(mAdbPairingPortObserver);\n        PendingIntent stopPendingIntent = getStopIntent();\n        NotificationCompat.Action stopAction = new NotificationCompat.Action.Builder(null, getString(R.string.adb_pairing_stop_searching), stopPendingIntent).build();\n        mNotificationBuilder.setContentText(getText(R.string.adb_pairing_searching_for_port))\n                .clearActions()\n                .addAction(stopAction);\n        ServiceCompat.startForeground(this, 1, mNotificationBuilder.build(), FOREGROUND_SERVICE_TYPE_DATA_SYNC | FOREGROUND_SERVICE_TYPE_SPECIAL_USE);\n        mAdbMdnsPairing.start();\n    }\n\n    @MainThread\n    private void inputPairingCode(int port) {\n        Intent inputIntent = new Intent(this, getClass())\n                .setAction(ACTION_START_PAIRING)\n                .putExtra(EXTRA_PORT, port);\n        PendingIntent inputPendingIntent = PendingIntentCompat.getForegroundService(this, 2, inputIntent, PendingIntent.FLAG_UPDATE_CURRENT, true);\n        RemoteInput pairingCodeInput = new RemoteInput.Builder(INPUT_CODE)\n                .setLabel(getString(R.string.adb_pairing_pairing_code))\n                .build();\n        NotificationCompat.Action inputAction = new NotificationCompat.Action.Builder(null, getString(R.string.adb_pairing_input_pairing_code), inputPendingIntent)\n                .addRemoteInput(pairingCodeInput)\n                .build();\n        mNotificationBuilder.setContentText(getString(R.string.adb_pairing_found_pairing_service_with_port, port))\n                .clearActions()\n                .addAction(inputAction);\n        if (SelfPermissions.checkSelfPermission(Manifest.permission.POST_NOTIFICATIONS)) {\n            NotificationManagerCompat.from(this).notify(1, mNotificationBuilder.build());\n        }\n    }\n\n    @MainThread\n    private void startPairing(int port, String code) {\n        mNotificationBuilder.setContentText(getString(R.string.adb_pairing_pairing_in_progress))\n                .clearActions();\n        ServiceCompat.startForeground(this, 1, mNotificationBuilder.build(), FOREGROUND_SERVICE_TYPE_DATA_SYNC | FOREGROUND_SERVICE_TYPE_SPECIAL_USE);\n        ThreadUtils.postOnBackgroundThread(() -> {\n            boolean isSuccess;\n            try {\n                AdbConnectionManager.getInstance().pairLiveData(ServerConfig.getAdbHost(this), port, code);\n                isSuccess = true;\n            } catch (Exception e) {\n                Log.w(TAG, \"Pairing failed.\", e);\n                isSuccess = false;\n            }\n            ThreadUtils.postOnMainThread(this::stopSearching);\n            if (isSuccess) {\n                mNotificationBuilder.setContentText(getString(R.string.paired_successfully)).clearActions();\n                stopSelf();\n            } else {\n                PendingIntent deleteIntent = getStopIntent();\n                Intent retryIntent = new Intent(this, getClass()).setAction(ACTION_START_SEARCHING);\n                PendingIntent retryPendingIntent = PendingIntentCompat.getForegroundService(this, 3, retryIntent, 0, false);\n                NotificationCompat.Action retryAction = new NotificationCompat.Action.Builder(null, getString(R.string.adb_pairing_retry_pairing), retryPendingIntent).build();\n                mNotificationBuilder.setContentText(getString(R.string.failed))\n                        .clearActions()\n                        .setDeleteIntent(deleteIntent)\n                        .addAction(retryAction);\n            }\n            if (SelfPermissions.checkSelfPermission(Manifest.permission.POST_NOTIFICATIONS)) {\n                NotificationManagerCompat.from(this).notify(1, mNotificationBuilder.build());\n            }\n        });\n    }\n\n    @MainThread\n    private void stopSearching() {\n        if (!mStartedSearching) {\n            return;\n        }\n        mStartedSearching = false;\n        mAdbMdnsPairing.stop();\n        mAdbPairingPort.removeObserver(mAdbPairingPortObserver);\n    }\n\n    @NonNull\n    private PendingIntent getStopIntent() {\n        Intent stopIntent = new Intent(this, getClass()).setAction(ACTION_STOP_SEARCHING);\n        return PendingIntentCompat.getForegroundService(this, 1, stopIntent, 0, false);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/adb/AdbUtils.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.adb;\n\nimport android.Manifest;\nimport android.content.ContentResolver;\nimport android.content.ContentValues;\nimport android.content.Context;\nimport android.net.Uri;\nimport android.os.Build;\nimport android.os.SystemClock;\nimport android.os.SystemProperties;\nimport android.provider.Settings;\nimport android.provider.SettingsHidden;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.RequiresApi;\nimport androidx.annotation.WorkerThread;\nimport androidx.core.util.Pair;\n\nimport java.io.IOException;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicInteger;\nimport java.util.concurrent.atomic.AtomicReference;\n\nimport io.github.muntashirakon.AppManager.runner.Runner;\nimport io.github.muntashirakon.AppManager.self.SelfPermissions;\nimport io.github.muntashirakon.AppManager.servermanager.ServerConfig;\nimport io.github.muntashirakon.adb.android.AdbMdns;\n\npublic class AdbUtils {\n    @WorkerThread\n    @NonNull\n    public static Pair<String, Integer> getLatestAdbDaemon(@NonNull Context context, long timeout, @NonNull TimeUnit unit)\n            throws InterruptedException, IOException {\n        if (!isAdbdRunning()) {\n            throw new IOException(\"ADB daemon not running.\");\n        }\n        AtomicInteger atomicPort = new AtomicInteger(-1);\n        AtomicReference<String> atomicHostAddress = new AtomicReference<>(null);\n        CountDownLatch resolveHostAndPort = new CountDownLatch(1);\n\n        AdbMdns adbMdnsTcp = new AdbMdns(context, AdbMdns.SERVICE_TYPE_ADB, (hostAddress, port) -> {\n            if (hostAddress != null) {\n                atomicHostAddress.set(hostAddress.getHostAddress());\n                atomicPort.set(port);\n            }\n            resolveHostAndPort.countDown();\n        });\n        adbMdnsTcp.start();\n\n        AdbMdns adbMdnsTls;\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {\n            adbMdnsTls = new AdbMdns(context, AdbMdns.SERVICE_TYPE_TLS_CONNECT, (hostAddress, port) -> {\n                if (hostAddress != null) {\n                    atomicHostAddress.set(hostAddress.getHostAddress());\n                    atomicPort.set(port);\n                }\n                resolveHostAndPort.countDown();\n            });\n            adbMdnsTls.start();\n        } else adbMdnsTls = null;\n\n        try {\n            if (!resolveHostAndPort.await(timeout, unit)) {\n                throw new InterruptedException(\"Timed out while trying to find a valid host address and port\");\n            }\n        } finally {\n            adbMdnsTcp.stop();\n            if (adbMdnsTls != null) {\n                adbMdnsTls.stop();\n            }\n        }\n\n        String host = atomicHostAddress.get();\n        int port = atomicPort.get();\n        if (host == null || port == -1) {\n            throw new IOException(\"Could not find any valid host address or port\");\n        }\n        return new Pair<>(host, port);\n    }\n\n    @RequiresApi(Build.VERSION_CODES.R)\n    public static boolean enableWirelessDebugging(@NonNull Context context) {\n        ContentResolver resolver = context.getContentResolver();\n        boolean wirelessDebuggingEnabled = Settings.Global.getInt(resolver, SettingsHidden.Global.ADB_WIFI_ENABLED, 0) != 0;\n        if (wirelessDebuggingEnabled && isAdbdRunning()) {\n            return true;\n        }\n        if (!SelfPermissions.checkSelfPermission(Manifest.permission.WRITE_SECURE_SETTINGS)) {\n            // No permission\n            return false;\n        }\n        try {\n            if (Settings.Global.getInt(resolver, Settings.Global.DEVELOPMENT_SETTINGS_ENABLED, 0) == 0) {\n                ContentValues contentValues = new ContentValues(2);\n                contentValues.put(\"name\", Settings.Global.DEVELOPMENT_SETTINGS_ENABLED);\n                contentValues.put(\"value\", 1);\n                resolver.insert(Uri.parse(\"content://settings/global\"), contentValues);\n            }\n            if (!wirelessDebuggingEnabled) {\n                ContentValues contentValues = new ContentValues(2);\n                contentValues.put(\"name\", SettingsHidden.Global.ADB_WIFI_ENABLED);\n                contentValues.put(\"value\", 1);\n                resolver.insert(Uri.parse(\"content://settings/global\"), contentValues);\n            }\n            // Try at most 3 times to figure out if something has altered\n            for (int i = 0; i < 5; ++i) {\n                if (isAdbdRunning()) {\n                    return true;\n                }\n                SystemClock.sleep(500);\n            }\n        } catch (Throwable th) {\n            th.printStackTrace();\n        }\n        return false;\n    }\n\n    public static boolean isAdbdRunning() {\n        // Default is set to “running” to avoid other issues\n        return \"running\".equals(SystemProperties.get(\"init.svc.adbd\", \"running\"));\n    }\n\n    public static int getAdbPortOrDefault() {\n        return SystemProperties.getInt(\"service.adb.tcp.port\", ServerConfig.DEFAULT_ADB_PORT);\n    }\n\n    public static boolean startAdb(int port) {\n        return Runner.runCommand(new String[]{\"setprop\", \"service.adb.tcp.port\", String.valueOf(port)}).isSuccessful()\n                && Runner.runCommand(new String[]{\"setprop\", \"ctl.restart\", \"adbd\"}).isSuccessful();\n    }\n\n    public static boolean stopAdb() {\n        return Runner.runCommand(new String[]{\"setprop\", \"service.adb.tcp.port\", \"-1\"}).isSuccessful()\n                && Runner.runCommand(new String[]{\"setprop\", \"ctl.restart\", \"adbd\"}).isSuccessful();\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/apk/ApkFile.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.apk;\n\nimport static io.github.muntashirakon.AppManager.apk.ApkUtils.getDensityFromName;\nimport static io.github.muntashirakon.AppManager.apk.ApkUtils.getManifestAttributes;\nimport static io.github.muntashirakon.AppManager.apk.ApkUtils.getManifestFromApk;\nimport static io.github.muntashirakon.AppManager.utils.UIUtils.getSmallerText;\n\nimport android.content.ContentResolver;\nimport android.content.Context;\nimport android.content.pm.ApplicationInfo;\nimport android.net.Uri;\nimport android.os.Build;\nimport android.os.ParcelFileDescriptor;\nimport android.os.RemoteException;\nimport android.text.SpannableStringBuilder;\nimport android.text.Spanned;\nimport android.text.TextUtils;\nimport android.text.format.Formatter;\nimport android.text.style.ForegroundColorSpan;\nimport android.util.DisplayMetrics;\nimport android.util.SparseIntArray;\n\nimport androidx.annotation.AnyThread;\nimport androidx.annotation.GuardedBy;\nimport androidx.annotation.IntDef;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.WorkerThread;\nimport androidx.collection.SparseArrayCompat;\n\nimport com.google.android.material.color.MaterialColors;\n\nimport org.json.JSONException;\n\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileNotFoundException;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.nio.ByteBuffer;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.Enumeration;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Objects;\nimport java.util.concurrent.ThreadLocalRandom;\nimport java.util.zip.ZipEntry;\nimport java.util.zip.ZipFile;\n\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.StaticDataset;\nimport io.github.muntashirakon.AppManager.apk.signing.SigSchemes;\nimport io.github.muntashirakon.AppManager.apk.signing.Signer;\nimport io.github.muntashirakon.AppManager.apk.splitapk.ApksMetadata;\nimport io.github.muntashirakon.AppManager.fm.FmProvider;\nimport io.github.muntashirakon.AppManager.logs.Log;\nimport io.github.muntashirakon.AppManager.misc.VMRuntime;\nimport io.github.muntashirakon.AppManager.self.filecache.FileCache;\nimport io.github.muntashirakon.AppManager.settings.Prefs;\nimport io.github.muntashirakon.AppManager.utils.ArrayUtils;\nimport io.github.muntashirakon.AppManager.utils.ContextUtils;\nimport io.github.muntashirakon.AppManager.utils.FileUtils;\nimport io.github.muntashirakon.AppManager.utils.LangUtils;\nimport io.github.muntashirakon.io.IoUtils;\nimport io.github.muntashirakon.io.Path;\nimport io.github.muntashirakon.io.Paths;\nimport io.github.muntashirakon.unapkm.api.UnApkm;\nimport io.github.muntashirakon.util.LocalizedString;\n\npublic final class ApkFile implements AutoCloseable {\n    public static final String TAG = \"ApkFile\";\n\n    private static final String ATTR_IS_FEATURE_SPLIT = \"android:isFeatureSplit\";\n    private static final String ATTR_IS_SPLIT_REQUIRED = \"android:isSplitRequired\";\n    private static final String ATTR_ISOLATED_SPLIT = \"android:isolatedSplits\";\n    private static final String ATTR_CONFIG_FOR_SPLIT = \"configForSplit\";\n    private static final String ATTR_SPLIT = \"split\";\n    private static final String ATTR_PACKAGE = \"package\";\n    private static final String CONFIG_PREFIX = \"config.\";\n\n    private static final String UN_APKM_PKG = \"io.github.muntashirakon.unapkm\";\n\n    // There's hardly any chance of using multiple instances of ApkFile but still kept for convenience\n    private static final SparseArrayCompat<ApkFile> sApkFiles = new SparseArrayCompat<>(3);\n    private static final SparseIntArray sInstanceCount = new SparseIntArray(3);\n\n    @AnyThread\n    @Nullable\n    static ApkFile getInstance(int sparseArrayKey) {\n        synchronized (sApkFiles) {\n            ApkFile apkFile = sApkFiles.get(sparseArrayKey);\n            if (apkFile == null) {\n                return null;\n            }\n            synchronized (sInstanceCount) {\n                // Increment the number of active instances\n                sInstanceCount.put(sparseArrayKey, sInstanceCount.get(sparseArrayKey) + 1);\n            }\n            return apkFile;\n        }\n    }\n\n    @AnyThread\n    static int createInstance(Uri apkUri, @Nullable String mimeType) throws ApkFileException {\n        synchronized (sApkFiles) {\n            int key = getUniqueKey();\n            ApkFile apkFile = new ApkFile(apkUri, mimeType, key);\n            sApkFiles.put(key, apkFile);\n            return key;\n        }\n    }\n\n    @AnyThread\n    static int createInstance(ApplicationInfo info) throws ApkFileException {\n        synchronized (sApkFiles) {\n            int key = getUniqueKey();\n            ApkFile apkFile = new ApkFile(info, key);\n            sApkFiles.put(key, apkFile);\n            return key;\n        }\n    }\n\n    @GuardedBy(\"sApkFiles\")\n    private static int getUniqueKey() {\n        int key;\n        do {\n            key = ThreadLocalRandom.current().nextInt();\n        } while (sApkFiles.containsKey(key));\n        return key;\n    }\n\n    @IntDef(value = {\n            APK_BASE,\n            APK_SPLIT_FEATURE,\n            APK_SPLIT_ABI,\n            APK_SPLIT_DENSITY,\n            APK_SPLIT_LOCALE,\n            APK_SPLIT_UNKNOWN,\n            APK_SPLIT,\n    })\n    @Retention(RetentionPolicy.SOURCE)\n    public @interface ApkType {\n    }\n\n    public static final int APK_BASE = 0;\n    public static final int APK_SPLIT_FEATURE = 1;\n    public static final int APK_SPLIT_ABI = 2;\n    public static final int APK_SPLIT_DENSITY = 3;\n    public static final int APK_SPLIT_LOCALE = 4;\n    public static final int APK_SPLIT_UNKNOWN = 5;\n    /**\n     * Generic split type. For internal uses only, never returned by {@link Entry#type}.\n     */\n    public static final int APK_SPLIT = 6;\n\n    public static List<String> SUPPORTED_EXTENSIONS = new ArrayList<>();\n    public static List<String> SUPPORTED_MIMES = new ArrayList<>();\n\n    static {\n        SUPPORTED_EXTENSIONS.add(\"apk\");\n        SUPPORTED_EXTENSIONS.add(\"apkm\");\n        SUPPORTED_EXTENSIONS.add(\"apks\");\n        SUPPORTED_EXTENSIONS.add(\"xapk\");\n        SUPPORTED_MIMES.add(\"application/x-apks\");\n        SUPPORTED_MIMES.add(\"application/vnd.android.package-archive\");\n        SUPPORTED_MIMES.add(\"application/vnd.apkm\");\n        SUPPORTED_MIMES.add(\"application/xapk-package-archive\");\n    }\n\n    private final int mSparseArrayKey;\n    @NonNull\n    private final List<Entry> mEntries = new ArrayList<>();\n    private Entry mBaseEntry;\n    @Nullable\n    private File mIdsigFile;\n    @Nullable\n    private ApksMetadata mApksMetadata;\n    @NonNull\n    private final String mPackageName;\n    @NonNull\n    private final List<ZipEntry> mObbFiles = new ArrayList<>();\n    private final FileCache mFileCache = new FileCache();\n    @NonNull\n    private final File mCacheFilePath;\n    @Nullable\n    private ParcelFileDescriptor mFd;\n    @Nullable\n    private ZipFile mZipFile;\n    private boolean mClosed;\n\n    private ApkFile(@NonNull Uri apkUri, @Nullable String mimeType, int sparseArrayKey) throws ApkFileException {\n        mSparseArrayKey = sparseArrayKey;\n        Context context = ContextUtils.getContext();\n        Path apkSource = Paths.get(apkUri);\n        @NonNull String extension;\n        // Check type\n        if (mimeType == null) mimeType = apkSource.getType();\n        if (!SUPPORTED_MIMES.contains(mimeType)) {\n            Log.e(TAG, \"Invalid mime: %s\", mimeType);\n            // Check extension\n            if (!SUPPORTED_EXTENSIONS.contains(apkSource.getExtension())) {\n                throw new ApkFileException(\"Invalid package extension.\");\n            }\n            extension = Objects.requireNonNull(apkSource.getExtension());\n        } else {\n            switch (mimeType) {\n                case \"application/x-apks\":\n                    extension = \"apks\";\n                    break;\n                case \"application/xapk-package-archive\":\n                    extension = \"xapk\";\n                    break;\n                case \"application/vnd.apkm\":\n                    extension = \"apkm\";\n                    break;\n                default:\n                    extension = \"apk\";\n                    break;\n            }\n        }\n        if (extension.equals(\"apkm\")) {\n            try {\n                if (FileUtils.isZip(apkSource)) {\n                    // DRM-free APKM file, mark it as APKS\n                    // FIXME(#227): Give it a special name and verify integrity\n                    extension = \"apks\";\n                }\n            } catch (IOException | SecurityException e) {\n                throw new ApkFileException(e);\n            }\n        }\n        // Cache the file or use file descriptor for non-APKM files\n        if (extension.equals(\"apkm\")) {\n            // Convert to APKS\n            try {\n                mCacheFilePath = mFileCache.createCachedFile(\"apks\");\n                try (ParcelFileDescriptor inputFD = FileUtils.getFdFromUri(context, apkUri, \"r\");\n                     OutputStream outputStream = new FileOutputStream(mCacheFilePath)) {\n                    UnApkm unApkm = new UnApkm(context, UN_APKM_PKG);\n                    unApkm.decryptFile(inputFD, outputStream);\n                }\n            } catch (IOException | RemoteException e) {\n                throw new ApkFileException(e);\n            }\n        } else {\n            // Open file descriptor if necessary\n            File cacheFilePath = null;\n            if (ContentResolver.SCHEME_FILE.equals(apkUri.getScheme())) {\n                // File scheme may not require an FD\n                cacheFilePath = new File(apkUri.getPath());\n            }\n            if (!FmProvider.AUTHORITY.equals(apkUri.getAuthority())) {\n                // Content scheme has a third-party authority\n                try {\n                    mFd = FileUtils.getFdFromUri(context, apkUri, \"r\");\n                    cacheFilePath = FileUtils.getFileFromFd(mFd);\n                } catch (FileNotFoundException e) {\n                    throw new ApkFileException(e);\n                } catch (SecurityException e) {\n                    Log.e(TAG, e);\n                }\n            }\n            if (cacheFilePath == null || !FileUtils.canReadUnprivileged(cacheFilePath)) {\n                // Cache manually\n                try {\n                    mCacheFilePath = mFileCache.getCachedFile(apkSource);\n                } catch (IOException | SecurityException e) {\n                    throw new ApkFileException(\"Could not cache the input file.\", e);\n                }\n            } else mCacheFilePath = cacheFilePath;\n        }\n        String packageName = null;\n        // Check for splits\n        if (extension.equals(\"apk\")) {\n            // Get manifest attributes\n            ByteBuffer manifest = getManifestFromApk(mCacheFilePath);\n            HashMap<String, String> manifestAttrs = getManifestAttributes(manifest);\n            if (!manifestAttrs.containsKey(ATTR_PACKAGE)) {\n                throw new IllegalArgumentException(\"Manifest doesn't contain any package name.\");\n            }\n            packageName = manifestAttrs.get(ATTR_PACKAGE);\n            mBaseEntry = new Entry(mCacheFilePath, manifest, manifestAttrs);\n            mEntries.add(mBaseEntry);\n        } else {\n            try {\n                mZipFile = new ZipFile(mCacheFilePath);\n            } catch (IOException e) {\n                throw new ApkFileException(e);\n            }\n            Enumeration<? extends ZipEntry> zipEntries = mZipFile.entries();\n            while (zipEntries.hasMoreElements()) {\n                ZipEntry zipEntry = zipEntries.nextElement();\n                if (zipEntry.isDirectory()) continue;\n                String fileName = FileUtils.getFilenameFromZipEntry(zipEntry);\n                if (fileName.endsWith(\".apk\")) { // APK is more likely to match\n                    try (InputStream zipInputStream = mZipFile.getInputStream(zipEntry)) {\n                        // Get manifest attributes\n                        ByteBuffer manifest = getManifestFromApk(zipInputStream);\n                        HashMap<String, String> manifestAttrs = getManifestAttributes(manifest);\n                        if (manifestAttrs.containsKey(\"split\")) {\n                            // TODO: check for duplicates\n                            Entry entry = new Entry(fileName, zipEntry, APK_SPLIT, manifest, manifestAttrs);\n                            mEntries.add(entry);\n                        } else {\n                            if (mBaseEntry != null) {\n                                throw new RuntimeException(\"Duplicate base apk found.\");\n                            }\n                            mBaseEntry = new Entry(fileName, zipEntry, APK_BASE, manifest, manifestAttrs);\n                            mEntries.add(mBaseEntry);\n                            if (manifestAttrs.containsKey(ATTR_PACKAGE)) {\n                                packageName = manifestAttrs.get(ATTR_PACKAGE);\n                            } else throw new RuntimeException(\"Package name not found.\");\n                        }\n                    } catch (IOException e) {\n                        throw new ApkFileException(e);\n                    }\n                } else if (fileName.equals(ApksMetadata.META_FILE)) {\n                    try {\n                        String jsonString = IoUtils.getInputStreamContent(mZipFile.getInputStream(zipEntry));\n                        mApksMetadata = new ApksMetadata();\n                        mApksMetadata.readMetadata(jsonString);\n                    } catch (IOException | JSONException e) {\n                        mApksMetadata = null;\n                        Log.w(TAG, \"The contents of info.json in the bundle is invalid\", e);\n                    }\n                } else if (fileName.endsWith(\".obb\")) {\n                    mObbFiles.add(zipEntry);\n                } else if (fileName.endsWith(\".idsig\")) {\n                    try {\n                        mIdsigFile = mFileCache.getCachedFile(mZipFile.getInputStream(zipEntry), \".idsig\");\n                    } catch (IOException e) {\n                        throw new ApkFileException(e);\n                    }\n                }\n            }\n            if (mBaseEntry == null) throw new ApkFileException(\"No base apk found.\");\n            // Sort the entries based on type and rank\n            Collections.sort(mEntries, (o1, o2) -> {\n                Integer int1 = o1.type;\n                int int2 = o2.type;\n                int typeCmp;\n                if ((typeCmp = int1.compareTo(int2)) != 0) return typeCmp;\n                int1 = o1.rank;\n                int2 = o2.rank;\n                return int1.compareTo(int2);\n            });\n        }\n        if (packageName == null) throw new ApkFileException(\"Package name not found.\");\n        mPackageName = packageName;\n    }\n\n    private ApkFile(@NonNull ApplicationInfo info, int sparseArrayKey) throws ApkFileException {\n        mSparseArrayKey = sparseArrayKey;\n        mPackageName = info.packageName;\n        mCacheFilePath = new File(info.publicSourceDir);\n        File sourceDir = mCacheFilePath.getParentFile();\n        if (sourceDir == null || \"/data/app\".equals(sourceDir.getAbsolutePath())) {\n            // Old file structure (storing APK files at /data/app)\n            mEntries.add(mBaseEntry = new Entry(mCacheFilePath, getManifestFromApk(mCacheFilePath), null));\n        } else {\n            File[] apks = sourceDir.listFiles((dir, name) -> name.endsWith(\".apk\"));\n            if (apks == null) {\n                // Directory might be inaccessible\n                Log.w(TAG, \"No apk files found in %s. Using default.\", sourceDir);\n                List<File> allApks = new ArrayList<>();\n                allApks.add(mCacheFilePath);\n                String[] splits = info.splitPublicSourceDirs;\n                if (splits != null) {\n                    for (String split : splits) {\n                        if (split != null) {\n                            allApks.add(new File(split));\n                        }\n                    }\n                }\n                apks = allApks.toArray(new File[0]);\n            }\n            String fileName;\n            for (File apk : apks) {\n                fileName = Paths.getLastPathSegment(apk.getAbsolutePath());\n                // Get manifest attributes\n                ByteBuffer manifest = getManifestFromApk(apk);\n                HashMap<String, String> manifestAttrs = getManifestAttributes(manifest);\n                if (manifestAttrs.containsKey(\"split\")) {\n                    Entry entry = new Entry(fileName, apk, APK_SPLIT, manifest, manifestAttrs);\n                    mEntries.add(entry);\n                } else {\n                    // Could be a base entry, check package name\n                    if (!manifestAttrs.containsKey(ATTR_PACKAGE)) {\n                        throw new IllegalArgumentException(\"Manifest doesn't contain any package name.\");\n                    }\n                    String newPackageName = manifestAttrs.get(ATTR_PACKAGE);\n                    if (mPackageName.equals(newPackageName)) {\n                        if (mBaseEntry != null) {\n                            throw new RuntimeException(\"Duplicate base apk found.\");\n                        }\n                        mBaseEntry = new Entry(fileName, apk, APK_BASE, manifest, manifestAttrs);\n                        mEntries.add(mBaseEntry);\n                    } // else continue;\n                }\n            }\n            if (mBaseEntry == null) throw new ApkFileException(\"No base apk found.\");\n            // Sort the entries based on type\n            Collections.sort(mEntries, (o1, o2) -> {\n                Integer int1 = o1.type;\n                int int2 = o2.type;\n                int typeCmp;\n                if ((typeCmp = int1.compareTo(int2)) != 0) return typeCmp;\n                int1 = o1.rank;\n                int2 = o2.rank;\n                return int1.compareTo(int2);\n            });\n        }\n    }\n\n    public Entry getBaseEntry() {\n        return mBaseEntry;\n    }\n\n    @NonNull\n    public List<Entry> getEntries() {\n        return mEntries;\n    }\n\n    @Nullable\n    public File getIdsigFile() {\n        if (mIdsigFile != null) {\n            return mIdsigFile;\n        }\n        return null;\n    }\n\n    @Nullable\n    public ApksMetadata getApksMetadata() {\n        return mApksMetadata;\n    }\n\n    @NonNull\n    public String getPackageName() {\n        return mPackageName;\n    }\n\n    public boolean isSplit() {\n        return mEntries.size() > 1;\n    }\n\n    public boolean hasObb() {\n        return !mObbFiles.isEmpty();\n    }\n\n    @WorkerThread\n    public void extractObb(Path writableObbDir) throws IOException {\n        if (!hasObb() || mZipFile == null) return;\n        for (ZipEntry obbEntry : mObbFiles) {\n            String fileName = FileUtils.getFilenameFromZipEntry(obbEntry);\n            Path obbDir = writableObbDir.findOrCreateFile(fileName, null);\n            // Extract obb file to the destination directory\n            try (InputStream zipInputStream = mZipFile.getInputStream(obbEntry);\n                 OutputStream outputStream = obbDir.openOutputStream()) {\n                IoUtils.copy(zipInputStream, outputStream);\n            }\n        }\n    }\n\n    public boolean isClosed() {\n        return mClosed;\n    }\n\n    @Override\n    public void close() {\n        synchronized (sInstanceCount) {\n            if (sInstanceCount.get(mSparseArrayKey) > 1) {\n                // This isn't the only instance, do not close yet\n                sInstanceCount.put(mSparseArrayKey, sInstanceCount.get(mSparseArrayKey) - 1);\n                return;\n            }\n            // Only this instance remained\n            sInstanceCount.delete(mSparseArrayKey);\n        }\n        mClosed = true;\n        sApkFiles.remove(mSparseArrayKey);\n        for (Entry entry : mEntries) {\n            entry.close();\n        }\n        IoUtils.closeQuietly(mZipFile);\n        IoUtils.closeQuietly(mFd);\n        IoUtils.closeQuietly(mFileCache);\n        FileUtils.deleteSilently(mIdsigFile);\n        // Ensure that entries are not accessible if accidentally accessed\n        mEntries.clear();\n        mBaseEntry = null;\n        mObbFiles.clear();\n    }\n\n    @Override\n    protected void finalize() {\n        if (!mClosed) {\n            close();\n        }\n    }\n\n    public class Entry implements AutoCloseable, LocalizedString {\n        /**\n         * Unique identifier capable of persisting across new instances. This is usually the file path (relative or\n         * absolute).\n         */\n        public final String id;\n        /**\n         * Name of the file, for split apk, name of the split instead\n         */\n        @NonNull\n        public final String name;\n        /**\n         * Type of the APK (base or split). One of {@link #APK_BASE}, {@link #APK_SPLIT_FEATURE},\n         * {@link #APK_SPLIT_ABI}, {@link #APK_SPLIT_DENSITY}, {@link #APK_SPLIT_LOCALE},  {@link #APK_SPLIT_UNKNOWN}.\n         */\n        @ApkType\n        public final int type;\n        /**\n         * The entire manifest file as {@link ByteBuffer}.\n         */\n        @NonNull\n        public final ByteBuffer manifest;\n\n        @Nullable\n        private String mSplitSuffix;\n        @Nullable\n        private String mForFeature = null;\n        @Nullable\n        private File mCachedFile;\n        @Nullable\n        private ZipEntry mZipEntry;\n        @Nullable\n        private File mSource;\n        @Nullable\n        private File mSignedFile;\n        @Nullable\n        private File mIdsigFile;\n        private final boolean mRequired;\n        private final boolean mIsolated;\n\n        /**\n         * Rank for a certain {@link #type} to create a priority list. This is applicable for\n         * {@link #APK_SPLIT_ABI}, {@link #APK_SPLIT_DENSITY} and {@link #APK_SPLIT_LOCALE}.\n         * Smallest rank number denotes highest rank.\n         */\n        public int rank = Integer.MAX_VALUE;\n\n        Entry(@NonNull File source, @NonNull ByteBuffer manifest, @Nullable HashMap<String, String> manifestAttrs) {\n            this(\"base-apk\", \"Base.apk\", APK_BASE, manifest, manifestAttrs);\n            mSource = Objects.requireNonNull(source);\n        }\n\n        Entry(@NonNull String name,\n              @NonNull ZipEntry zipEntry,\n              @ApkType int type,\n              @NonNull ByteBuffer manifest,\n              @Nullable HashMap<String, String> manifestAttrs) {\n            this(Objects.requireNonNull(zipEntry).getName(), name, type, manifest, manifestAttrs);\n            mZipEntry = Objects.requireNonNull(zipEntry);\n        }\n\n        Entry(@NonNull String name,\n              @NonNull File source,\n              @ApkType int type,\n              @NonNull ByteBuffer manifest,\n              @Nullable HashMap<String, String> manifestAttrs) {\n            this(Objects.requireNonNull(source).getAbsolutePath(), name, type, manifest, manifestAttrs);\n            mSource = source;\n        }\n\n        private Entry(@NonNull String id,\n                      @NonNull String name,\n                      @ApkType int type,\n                      @NonNull ByteBuffer manifest,\n                      @Nullable HashMap<String, String> manifestAttrs) {\n            Objects.requireNonNull(name);\n            Objects.requireNonNull(manifest);\n            this.id = id;\n            this.manifest = manifest;\n            if (type == APK_BASE) {\n                this.name = name;\n                mRequired = true;\n                mIsolated = false;\n                this.type = APK_BASE;\n            } else if (type == APK_SPLIT) {\n                Objects.requireNonNull(manifestAttrs);\n                String splitName = manifestAttrs.get(ATTR_SPLIT);\n                if (splitName == null) throw new RuntimeException(\"Split name is empty.\");\n                this.name = splitName;\n                // Check if required\n                if (manifestAttrs.containsKey(ATTR_IS_SPLIT_REQUIRED)) {\n                    String value = manifestAttrs.get(ATTR_IS_SPLIT_REQUIRED);\n                    mRequired = value != null && Boolean.parseBoolean(value);\n                } else mRequired = false;\n                // Check if isolated\n                if (manifestAttrs.containsKey(ATTR_ISOLATED_SPLIT)) {\n                    String value = manifestAttrs.get(ATTR_ISOLATED_SPLIT);\n                    mIsolated = value != null && Boolean.parseBoolean(value);\n                } else mIsolated = false;\n                // Infer types\n                if (manifestAttrs.containsKey(ATTR_IS_FEATURE_SPLIT)) {\n                    this.type = APK_SPLIT_FEATURE;\n                } else {\n                    if (manifestAttrs.containsKey(ATTR_CONFIG_FOR_SPLIT)) {\n                        mForFeature = manifestAttrs.get(ATTR_CONFIG_FOR_SPLIT);\n                        if (TextUtils.isEmpty(mForFeature)) mForFeature = null;\n                    }\n                    int configPartIndex = this.name.lastIndexOf(CONFIG_PREFIX);\n                    if (configPartIndex == -1 || (configPartIndex != 0 && this.name.charAt(configPartIndex - 1) != '.')) {\n                        this.type = APK_SPLIT_UNKNOWN;\n                        return;\n                    }\n                    mSplitSuffix = this.name.substring(configPartIndex + (CONFIG_PREFIX.length()));\n                    if (StaticDataset.ALL_ABIS.containsKey(mSplitSuffix)) {\n                        // This split is an ABI\n                        this.type = APK_SPLIT_ABI;\n                        String abi = StaticDataset.ALL_ABIS.get(mSplitSuffix);\n                        int index = ArrayUtils.indexOf(Build.SUPPORTED_ABIS, Objects.requireNonNull(abi));\n                        if (index != -1) {\n                            this.rank = index;\n                            if (mForFeature == null) {\n                                // Increment rank for base APK\n                                this.rank -= 1000;\n                            }\n                        }\n                    } else if (StaticDataset.DENSITY_NAME_TO_DENSITY.containsKey(mSplitSuffix)) {\n                        // This split is for Screen Density\n                        this.type = APK_SPLIT_DENSITY;\n                        this.rank = Math.abs(StaticDataset.DEVICE_DENSITY - getDensityFromName(mSplitSuffix));\n                        if (mForFeature == null) {\n                            // Increment rank for base APK\n                            this.rank -= 1000;\n                        }\n                    } else if (LangUtils.isValidLocale(mSplitSuffix)) {\n                        // This split is for Locale\n                        this.type = APK_SPLIT_LOCALE;\n                        Integer rank = StaticDataset.LOCALE_RANKING.get(mSplitSuffix);\n                        if (rank != null) {\n                            this.rank = rank;\n                            if (mForFeature == null) {\n                                // Increment rank for base APK\n                                this.rank -= 1000;\n                            }\n                        }\n                    } else this.type = APK_SPLIT_UNKNOWN;\n                }\n            } else {\n                this.name = name;\n                this.type = APK_SPLIT_UNKNOWN;\n                mRequired = mIsolated = false;\n            }\n        }\n\n        /**\n         * Get filename of the entry. This does not necessarily exist as a real file.\n         */\n        @NonNull\n        public String getFileName() {\n            if (Paths.exists(mCachedFile)) return mCachedFile.getName();\n            if (mZipEntry != null) return FileUtils.getFilenameFromZipEntry(mZipEntry);\n            if (Paths.exists(mSource)) return mSource.getName();\n            else throw new RuntimeException(\"Neither zipEntry nor source is defined.\");\n        }\n\n        /**\n         * Get size of the entry.\n         */\n        public long getFileSize() {\n            if (Paths.exists(mCachedFile)) return mCachedFile.length();\n            if (mZipEntry != null) return mZipEntry.getSize();\n            if (Paths.exists(mSource)) return mSource.length();\n            else throw new RuntimeException(\"Neither zipEntry nor source is defined.\");\n        }\n\n        /**\n         * Get size of the entry or {@code -1} if unavailable\n         */\n        @WorkerThread\n        public long getFileSize(boolean signed) {\n            try {\n                return (signed ? getSignedFile() : getRealCachedFile()).length();\n            } catch (IOException e) {\n                return -1;\n            }\n        }\n\n        @WorkerThread\n        public File getFile(boolean signed) throws IOException {\n            return signed ? getSignedFile() : getRealCachedFile();\n        }\n\n        @WorkerThread\n        public InputStream getInputStream(boolean signed) throws IOException {\n            return signed ? getSignedInputStream() : getRealInputStream();\n        }\n\n        /**\n         * Get signed APK file.\n         *\n         * @throws IOException If the APK cannot be signed or cached.\n         */\n        private File getSignedFile() throws IOException {\n            File realFile = getRealCachedFile();\n            if (Paths.exists(mSignedFile)) return mSignedFile;\n            mSignedFile = mFileCache.createCachedFile(\"apk\");\n            SigSchemes sigSchemes = Prefs.Signing.getSigSchemes();\n            boolean zipAlign = Prefs.Signing.zipAlign();\n            try {\n                Signer signer = Signer.getInstance(sigSchemes);\n                if (signer.isV4SchemeEnabled()) {\n                    mIdsigFile = mFileCache.createCachedFile(\"idsig\");\n                    signer.setIdsigFile(mIdsigFile);\n                }\n                if (signer.sign(realFile, mSignedFile, -1, zipAlign)\n                        && Signer.verify(sigSchemes, mSignedFile, mIdsigFile)) {\n                    return mSignedFile;\n                }\n                throw new IOException(\"Failed to sign \" + realFile);\n            } catch (IOException e) {\n                throw e;\n            } catch (Exception e) {\n                throw new IOException(e);\n            }\n        }\n\n        /**\n         * Same as {@link #getSignedFile()} except that it returns an {@link InputStream}.\n         *\n         * @throws IOException If the APK cannot be signed or cached.\n         */\n        private InputStream getSignedInputStream() throws IOException {\n            return new FileInputStream(getSignedFile());\n        }\n\n        /**\n         * Get the APK file source if it has a physical location.\n         *\n         * @return Absolute path to the APK file.\n         */\n        @Nullable\n        public String getApkSource() {\n            return mSource == null ? null : mSource.getAbsolutePath();\n        }\n\n        /**\n         * Close this entry i.e. delete the cached files. Called automatically if {@link ApkFile#close()} is called.\n         */\n        @Override\n        public void close() {\n            FileUtils.deleteSilently(mCachedFile);\n            FileUtils.deleteSilently(mIdsigFile);\n            FileUtils.deleteSilently(mSignedFile);\n            if (mSource != null && !mSource.getAbsolutePath().startsWith(\"/proc/self\")\n                    && !mSource.getAbsolutePath().startsWith(\"/data/app\")) {\n                FileUtils.deleteSilently(mSource);\n            }\n        }\n\n        /**\n         * Get input stream of the entry. It does not sign the APK based on user preferences. It also does not cache\n         * the APK file, but tries to reuse existing cache file.\n         *\n         * @throws IOException If I/O error occurs.\n         */\n        @NonNull\n        private InputStream getRealInputStream() throws IOException {\n            if (Paths.exists(mCachedFile)) return new FileInputStream(mCachedFile);\n            if (mZipEntry != null) return Objects.requireNonNull(mZipFile).getInputStream(mZipEntry);\n            if (Paths.exists(mSource)) return new FileInputStream(mSource);\n            else throw new IOException(\"Neither zipEntry nor source is defined.\");\n        }\n\n        /**\n         * Get a readable file of the entry, cached if necessary. It does not sign the APK based on user preferences.\n         *\n         * @throws IOException If an I/O error occurs while caching the APK.\n         */\n        @WorkerThread\n        private File getRealCachedFile() throws IOException {\n            if (mSource != null && mSource.canRead() && !mSource.getAbsolutePath().startsWith(\"/proc/self\")) {\n                return mSource;\n            }\n            if (mCachedFile != null) {\n                if (mCachedFile.canRead()) {\n                    return mCachedFile;\n                } else FileUtils.deleteSilently(mCachedFile);\n            }\n            try (InputStream is = getRealInputStream()) {\n                mCachedFile = mFileCache.getCachedFile(is, \"apk\");\n                return Objects.requireNonNull(mCachedFile);\n            }\n        }\n\n        /**\n         * Whether the entry is a required entry i.e. it must be installed along with the base APK.\n         */\n        public boolean isRequired() {\n            return mRequired;\n        }\n\n        /**\n         * Whether the entry is an isolated entry.\n         */\n        public boolean isIsolated() {\n            return mIsolated;\n        }\n\n        /**\n         * Get ABI if the split is an ABI split.\n         *\n         * @return One of {@link VMRuntime#ABI_ARMEABI_V7A}, {@link VMRuntime#ABI_ARM64_V8A}, {@link VMRuntime#ABI_X86},\n         * {@link VMRuntime#ABI_X86_64}.\n         * @throws RuntimeException     If split is not an ABI split.\n         * @throws NullPointerException If the ABI is not valid.\n         */\n        @NonNull\n        public String getAbi() {\n            if (type == APK_SPLIT_ABI) {\n                return Objects.requireNonNull(StaticDataset.ALL_ABIS.get(mSplitSuffix));\n            }\n            throw new RuntimeException(\"Attempt to fetch ABI for invalid apk\");\n        }\n\n        /**\n         * Get density if the split is a density split.\n         *\n         * @return One of {@link DisplayMetrics#DENSITY_LOW}, {@link DisplayMetrics#DENSITY_MEDIUM},\n         * {@link DisplayMetrics#DENSITY_TV}, {@link DisplayMetrics#DENSITY_HIGH}, {@link DisplayMetrics#DENSITY_XHIGH},\n         * {@link DisplayMetrics#DENSITY_XXHIGH}, {@link DisplayMetrics#DENSITY_XXXHIGH}.\n         * @throws RuntimeException If split is not a density split, or the density is not valid.\n         */\n        public int getDensity() {\n            if (type == APK_SPLIT_DENSITY) {\n                return getDensityFromName(mSplitSuffix);\n            }\n            throw new RuntimeException(\"Attempt to fetch Density for invalid apk\");\n        }\n\n        /**\n         * Get locale if the split is a locale split. Each locale can belong to multiple regions.\n         *\n         * @throws RuntimeException     If the split is not a locale split.\n         * @throws NullPointerException If the locale is not valid.\n         */\n        @NonNull\n        public Locale getLocale() {\n            if (type == APK_SPLIT_LOCALE) {\n                return new Locale.Builder().setLanguageTag(Objects.requireNonNull(mSplitSuffix)).build();\n            }\n            throw new RuntimeException(\"Attempt to fetch Locale for invalid apk\");\n        }\n\n        @Nullable\n        public String getFeature() {\n            if (type == APK_SPLIT_FEATURE) {\n                return name;\n            }\n            return mForFeature;\n        }\n\n        public boolean isForFeature() {\n            return mForFeature != null;\n        }\n\n        /**\n         * Whether the split supported by this platform\n         */\n        public boolean supported() {\n            if (type == APK_SPLIT_ABI) {\n                // Not all ABIs are supported by all platforms.\n                // This can be deduced by checking the rank of the ABI.\n                return rank != Integer.MAX_VALUE;\n            }\n            return true;\n        }\n\n        @Override\n        @NonNull\n        public CharSequence toLocalizedString(@NonNull Context context) {\n            CharSequence localizedString = toShortLocalizedString(context);\n            SpannableStringBuilder builder = new SpannableStringBuilder()\n                    .append(context.getString(R.string.size)).append(LangUtils.getSeparatorString())\n                    .append(Formatter.formatFileSize(context, getFileSize()));\n            if (isRequired()) {\n                builder.append(\", \").append(context.getString(R.string.required));\n            }\n            if (isIsolated()) {\n                builder.append(\", \").append(context.getString(R.string.isolated));\n            }\n            if (!supported()) {\n                builder.append(\", \");\n                int start = builder.length();\n                builder.append(context.getString(R.string.unsupported_split_apk));\n                builder.setSpan(new ForegroundColorSpan(MaterialColors.getColor(context, androidx.appcompat.R.attr.colorError, \"null\")),\n                        start, builder.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);\n            }\n            return new SpannableStringBuilder(localizedString).append(\"\\n\").append(getSmallerText(builder));\n        }\n\n        public CharSequence toShortLocalizedString(Context context) {\n            switch (type) {\n                case ApkFile.APK_BASE:\n                    return context.getString(R.string.base_apk);\n                case ApkFile.APK_SPLIT_DENSITY:\n                    if (mForFeature != null) {\n                        return context.getString(R.string.density_split_for_feature, mSplitSuffix, getDensity(), mForFeature);\n                    } else {\n                        return context.getString(R.string.density_split_for_base_apk, mSplitSuffix, getDensity());\n                    }\n                case ApkFile.APK_SPLIT_ABI:\n                    if (mForFeature != null) {\n                        return context.getString(R.string.abi_split_for_feature, getAbi(), mForFeature);\n                    } else {\n                        return context.getString(R.string.abi_split_for_base_apk, getAbi());\n                    }\n                case ApkFile.APK_SPLIT_LOCALE:\n                    if (mForFeature != null) {\n                        return context.getString(R.string.locale_split_for_feature, getLocale().getDisplayLanguage(), mForFeature);\n                    } else {\n                        return context.getString(R.string.locale_split_for_base_apk, getLocale().getDisplayLanguage());\n                    }\n                case ApkFile.APK_SPLIT_FEATURE:\n                    return context.getString(R.string.split_feature_name, name);\n                case ApkFile.APK_SPLIT_UNKNOWN:\n                case ApkFile.APK_SPLIT:\n                    if (mForFeature != null) {\n                        return context.getString(R.string.unknown_split_for_feature, name, mForFeature);\n                    } else {\n                        return context.getString(R.string.unknown_split_for_base_apk, name);\n                    }\n                default:\n                    throw new RuntimeException(\"Invalid split type.\");\n            }\n        }\n\n        @Override\n        public boolean equals(Object o) {\n            if (this == o) return true;\n            if (o instanceof String) return name.equals(o);\n            if (!(o instanceof Entry)) return false;\n            Entry entry = (Entry) o;\n            return name.equals(entry.name);\n        }\n\n        @Override\n        public int hashCode() {\n            return Objects.hash(name);\n        }\n    }\n\n    public static class ApkFileException extends Throwable {\n        public ApkFileException(@Nullable String message) {\n            super(message);\n        }\n\n        public ApkFileException(@Nullable String message, Throwable throwable) {\n            super(message, throwable);\n        }\n\n        public ApkFileException(Throwable throwable) {\n            super(throwable);\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/apk/ApkSource.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.apk;\n\nimport android.content.pm.ApplicationInfo;\nimport android.net.Uri;\nimport android.os.Parcelable;\n\nimport androidx.annotation.AnyThread;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport org.json.JSONException;\n\nimport io.github.muntashirakon.AppManager.history.IJsonSerializer;\nimport io.github.muntashirakon.AppManager.history.JsonDeserializer;\nimport io.github.muntashirakon.AppManager.utils.JSONUtils;\n\npublic abstract class ApkSource implements Parcelable, IJsonSerializer {\n    @NonNull\n    public static ApkSource getApkSource(@NonNull Uri uri, @Nullable String mimeType) {\n        return new UriApkSource(uri, mimeType);\n    }\n\n    @NonNull\n    public static ApkSource getCachedApkSource(@NonNull Uri uri, @Nullable String mimeType) {\n        return new CachedApkSource(uri, mimeType);\n    }\n\n    @NonNull\n    public static ApkSource getApkSource(@NonNull ApplicationInfo applicationInfo) {\n        return new ApplicationInfoApkSource(applicationInfo);\n    }\n\n    @AnyThread\n    @NonNull\n    public abstract ApkFile resolve() throws ApkFile.ApkFileException;\n\n    @AnyThread\n    @NonNull\n    public abstract ApkSource toCachedSource();\n\n    public static final JsonDeserializer.Creator<ApkSource> DESERIALIZER = jsonObject -> {\n        String tag = JSONUtils.getString(jsonObject, \"tag\");\n        if (ApplicationInfoApkSource.TAG.equals(tag)) {\n            return ApplicationInfoApkSource.DESERIALIZER.deserialize(jsonObject);\n        } else if (CachedApkSource.TAG.equals(tag)) {\n            return CachedApkSource.DESERIALIZER.deserialize(jsonObject);\n        } else if (UriApkSource.TAG.equals(tag)) {\n            return UriApkSource.DESERIALIZER.deserialize(jsonObject);\n        } else throw new JSONException(\"Invalid tag: \" + tag);\n    };\n}"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/apk/ApkUtils.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.apk;\n\nimport static io.github.muntashirakon.AppManager.compat.PackageManagerCompat.MATCH_UNINSTALLED_PACKAGES;\n\nimport android.annotation.UserIdInt;\nimport android.content.Context;\nimport android.content.pm.ApplicationInfo;\nimport android.content.pm.PackageInfo;\nimport android.content.pm.PackageManager;\nimport android.os.Build;\nimport android.os.RemoteException;\nimport android.os.UserHandleHidden;\nimport android.text.TextUtils;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.WorkerThread;\nimport androidx.core.content.pm.PackageInfoCompat;\n\nimport com.android.apksig.apk.ApkFormatException;\nimport com.android.apksig.internal.zip.CentralDirectoryRecord;\nimport com.android.apksig.internal.zip.LocalFileRecord;\nimport com.android.apksig.internal.zip.ZipUtils;\nimport com.android.apksig.util.DataSource;\nimport com.android.apksig.util.DataSources;\nimport com.android.apksig.zip.ZipFormatException;\nimport com.reandroid.arsc.chunk.xml.ResXmlAttribute;\nimport com.reandroid.arsc.chunk.xml.ResXmlDocument;\nimport com.reandroid.arsc.chunk.xml.ResXmlElement;\nimport com.reandroid.arsc.io.BlockReader;\n\nimport java.io.BufferedInputStream;\nimport java.io.ByteArrayOutputStream;\nimport java.io.File;\nimport java.io.FileNotFoundException;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.RandomAccessFile;\nimport java.nio.ByteBuffer;\nimport java.util.HashMap;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.Objects;\nimport java.util.zip.ZipEntry;\nimport java.util.zip.ZipInputStream;\n\nimport io.github.muntashirakon.AppManager.StaticDataset;\nimport io.github.muntashirakon.AppManager.apk.parser.AndroidBinXmlDecoder;\nimport io.github.muntashirakon.AppManager.apk.splitapk.SplitApkExporter;\nimport io.github.muntashirakon.AppManager.backup.BackupItems;\nimport io.github.muntashirakon.AppManager.compat.PackageManagerCompat;\nimport io.github.muntashirakon.AppManager.logs.Log;\nimport io.github.muntashirakon.AppManager.misc.OsEnvironment;\nimport io.github.muntashirakon.AppManager.self.filecache.FileCache;\nimport io.github.muntashirakon.AppManager.utils.AppPref;\nimport io.github.muntashirakon.AppManager.utils.ContextUtils;\nimport io.github.muntashirakon.AppManager.utils.DateUtils;\nimport io.github.muntashirakon.AppManager.utils.FileUtils;\nimport io.github.muntashirakon.io.IoUtils;\nimport io.github.muntashirakon.io.Path;\nimport io.github.muntashirakon.io.Paths;\n\npublic final class ApkUtils {\n    public static final String TAG = ApkUtils.class.getSimpleName();\n\n    public static final String EXT_APK = \".apk\";\n    public static final String EXT_APKS = \".apks\";\n\n    private static final Object sLock = new Object();\n    private static final String MANIFEST_FILE = \"AndroidManifest.xml\";\n\n    @WorkerThread\n    @NonNull\n    public static Path getSharableApkFile(@NonNull Context ctx, @NonNull PackageInfo packageInfo) throws IOException {\n        synchronized (sLock) {\n            PackageManager pm = ctx.getPackageManager();\n            ApplicationInfo info = packageInfo.applicationInfo;\n            String outputName = Paths.sanitizeFilename(getFormattedApkFilename(ctx, packageInfo, pm), \"_\",\n                    Paths.SANITIZE_FLAG_FAT_ILLEGAL_CHARS | Paths.SANITIZE_FLAG_UNIX_RESERVED);\n            if (outputName == null) outputName = info.packageName;\n            Path tmpPublicSource;\n            if (isSplitApk(info) || hasObbFiles(info.packageName, UserHandleHidden.getUserId(info.uid))) {\n                // Split apk\n                tmpPublicSource = Paths.get(new File(FileUtils.getExternalCachePath(ContextUtils.getContext()), outputName + EXT_APKS));\n                SplitApkExporter.saveApks(packageInfo, tmpPublicSource);\n            } else {\n                // Regular apk\n                tmpPublicSource = Paths.get(new File(FileUtils.getExternalCachePath(ContextUtils.getContext()), outputName + EXT_APK));\n                IoUtils.copy(Paths.get(info.publicSourceDir), tmpPublicSource);\n            }\n            return tmpPublicSource;\n        }\n    }\n\n    /**\n     * Backup the given apk (both root and no-root). This is similar to apk sharing feature except\n     * that these are saved at /sdcard/AppManager/apks\n     */\n    @WorkerThread\n    public static void backupApk(@NonNull Context ctx, @NonNull String packageName, @UserIdInt int userId)\n            throws IOException, PackageManager.NameNotFoundException, RemoteException {\n        Path backupPath = BackupItems.getApkBackupDirectory();\n        // Fetch package info\n        PackageManager pm = ctx.getPackageManager();\n        PackageInfo packageInfo = PackageManagerCompat.getPackageInfo(packageName,\n                MATCH_UNINSTALLED_PACKAGES | PackageManager.GET_SHARED_LIBRARY_FILES\n                        | PackageManagerCompat.MATCH_STATIC_SHARED_AND_SDK_LIBRARIES, userId);\n        ApplicationInfo info = packageInfo.applicationInfo;\n        String outputName = Paths.sanitizeFilename(getFormattedApkFilename(ctx, packageInfo, pm), \"_\",\n                Paths.SANITIZE_FLAG_FAT_ILLEGAL_CHARS | Paths.SANITIZE_FLAG_UNIX_RESERVED);\n        if (outputName == null) outputName = packageName;\n        Path apkFile;\n        if (isSplitApk(info) || hasObbFiles(packageName, userId)) {\n            // Split apk\n            apkFile = backupPath.createNewFile(outputName + EXT_APKS, null);\n            SplitApkExporter.saveApks(packageInfo, apkFile);\n        } else {\n            // Regular apk\n            apkFile = backupPath.createNewFile(outputName + EXT_APK, null);\n            IoUtils.copy(Paths.get(info.publicSourceDir), apkFile);\n        }\n    }\n\n    @NonNull\n    private static String getFormattedApkFilename(@NonNull Context context, @NonNull PackageInfo packageInfo,\n                                                  @NonNull PackageManager pm) {\n        // TODO: 15/3/22 Optimize this\n        String apkName = AppPref.getString(AppPref.PrefKey.PREF_SAVED_APK_FORMAT_STR)\n                .replaceAll(\"%label%\", packageInfo.applicationInfo.loadLabel(pm).toString())\n                .replaceAll(\"%package_name%\", packageInfo.packageName)\n                .replaceAll(\"%version%\", packageInfo.versionName)\n                .replaceAll(\"%version_code%\", String.valueOf(PackageInfoCompat.getLongVersionCode(packageInfo)))\n                .replaceAll(\"%target_sdk%\", String.valueOf(packageInfo.applicationInfo.targetSdkVersion))\n                .replaceAll(\"%datetime%\", DateUtils.formatDateTime(context, System.currentTimeMillis()));\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {\n            return apkName.replaceAll(\"%min_sdk%\", String.valueOf(packageInfo.applicationInfo.minSdkVersion));\n        }\n        return apkName;\n    }\n\n    public static boolean isSplitApk(@NonNull ApplicationInfo info) {\n        return info.splitPublicSourceDirs != null && info.splitPublicSourceDirs.length > 0;\n    }\n\n    @NonNull\n    public static ByteBuffer getManifestFromApk(File apkFile) throws ApkFile.ApkFileException {\n        try (RandomAccessFile in = new RandomAccessFile(apkFile, \"r\")) {\n            DataSource apk = DataSources.asDataSource(in);\n            com.android.apksig.apk.ApkUtils.ZipSections apkSections;\n            try {\n                apkSections = com.android.apksig.apk.ApkUtils.findZipSections(apk);\n            } catch (ZipFormatException e) {\n                throw new ApkFile.ApkFileException(\"Malformed APK: not a ZIP archive\", e);\n            }\n            List<CentralDirectoryRecord> cdRecords;\n            try {\n                cdRecords = ZipUtils.parseZipCentralDirectory(apk, apkSections);\n            } catch (ApkFormatException e) {\n                throw new ApkFile.ApkFileException(e.getMessage(), e);\n            }\n            try {\n                return getAndroidManifestFromApk(\n                        cdRecords,\n                        apk.slice(0, apkSections.getZipCentralDirectoryOffset()));\n            } catch (ApkFormatException e) {\n                throw new ApkFile.ApkFileException(e.getMessage(), e);\n            } catch (ZipFormatException e) {\n                throw new ApkFile.ApkFileException(\"Failed to read \" + MANIFEST_FILE, e);\n            }\n        } catch (IOException e) {\n            throw new ApkFile.ApkFileException(e.getMessage(), e);\n        }\n    }\n\n    @NonNull\n    public static ByteBuffer getManifestFromApk(InputStream apkInputStream) throws ApkFile.ApkFileException {\n        try (ZipInputStream zipInputStream = new ZipInputStream(new BufferedInputStream(apkInputStream))) {\n            ZipEntry zipEntry;\n            while ((zipEntry = zipInputStream.getNextEntry()) != null) {\n                if (!zipEntry.getName().equals(MANIFEST_FILE)) {\n                    continue;\n                }\n                ByteArrayOutputStream buffer = new ByteArrayOutputStream();\n                byte[] buf = new byte[IoUtils.DEFAULT_BUFFER_SIZE];\n                int n;\n                while (-1 != (n = zipInputStream.read(buf))) {\n                    buffer.write(buf, 0, n);\n                }\n                return ByteBuffer.wrap(buffer.toByteArray());\n            }\n        } catch (IOException e) {\n            Log.w(TAG, \"Could not fetch AndroidManifest.xml from APK stream, trying an alternative...\", e);\n        }\n        // This could be due to a Zip error, try caching the APK\n        File cachedApk;\n        try {\n            cachedApk = FileCache.getGlobalFileCache().getCachedFile(apkInputStream, \"apk\");\n        } catch (IOException e) {\n            throw new ApkFile.ApkFileException(\"Could not cache the APK file\", e);\n        }\n        ByteBuffer byteBuffer;\n        try {\n            byteBuffer = getManifestFromApk(cachedApk);\n        } finally {\n            FileCache.getGlobalFileCache().delete(cachedApk);\n        }\n        return byteBuffer;\n    }\n\n    @NonNull\n    public static HashMap<String, String> getManifestAttributes(@NonNull ByteBuffer manifestBytes)\n            throws ApkFile.ApkFileException {\n        try (BlockReader reader = new BlockReader(manifestBytes.array())) {\n            HashMap<String, String> manifestAttrs = new HashMap<>();\n            ResXmlDocument xmlBlock = new ResXmlDocument();\n            try {\n                xmlBlock.readBytes(reader);\n            } catch (IOException e) {\n                throw new ApkFile.ApkFileException(e);\n            }\n            xmlBlock.setPackageBlock(AndroidBinXmlDecoder.getFrameworkPackageBlock());\n            ResXmlElement resManifestElement = xmlBlock.getDocumentElement();\n            // manifest\n            if (!\"manifest\".equals(resManifestElement.getName())) {\n                throw new ApkFile.ApkFileException(\"No manifest found.\");\n            }\n            Iterator<ResXmlAttribute> attrIt = resManifestElement.getAttributes();\n            ResXmlAttribute attr;\n            String attrName;\n            while (attrIt.hasNext()) {\n                attr = attrIt.next();\n                attrName = attr.getName();\n                if (TextUtils.isEmpty(attrName)) {\n                    continue;\n                }\n                manifestAttrs.put(attrName, attr.getValueAsString());\n            }\n            // application\n            ResXmlElement resApplicationElement = null;\n            Iterator<ResXmlElement> resXmlElementIt = resManifestElement.getElements(\"application\");\n            if (resXmlElementIt.hasNext()) {\n                resApplicationElement = resXmlElementIt.next();\n            }\n            if (resXmlElementIt.hasNext()) {\n                throw new ApkFile.ApkFileException(\"\\\"manifest\\\" has duplicate \\\"application\\\" tags.\");\n            }\n            if (resApplicationElement == null) {\n                Log.w(TAG, \"No application tag found while parsing APK.\");\n                return manifestAttrs;\n            }\n            attrIt = resApplicationElement.getAttributes();\n            while (attrIt.hasNext()) {\n                attr = attrIt.next();\n                attrName = attr.getName();\n                if (TextUtils.isEmpty(attrName)) {\n                    continue;\n                }\n                if (manifestAttrs.containsKey(attrName)) {\n                    Log.w(TAG, \"Ignoring invalid attribute in the application tag: \" + attrName);\n                    continue;\n                }\n                manifestAttrs.put(attrName, attr.getValueAsString());\n            }\n            return manifestAttrs;\n        }\n    }\n\n    public static boolean hasObbFiles(@NonNull String packageName, @UserIdInt int userId) {\n        try {\n            return getObbDir(packageName, userId).listFiles().length > 0;\n        } catch (FileNotFoundException e) {\n            e.printStackTrace();\n            return false;\n        }\n    }\n\n    @NonNull\n    public static Path getObbDir(@NonNull String packageName, @UserIdInt int userId) throws FileNotFoundException {\n        // Get writable OBB directory\n        Path obbDir = getWritableExternalDirectory(userId)\n                .findFile(\"Android\")\n                .findFile(\"obb\")\n                .findFile(packageName);\n        return Paths.get(obbDir.getUri());\n    }\n\n    @NonNull\n    public static Path getOrCreateObbDir(@NonNull String packageName, @UserIdInt int userId) throws IOException {\n        // Get writable OBB directory\n        Path obbDir = getWritableExternalDirectory(userId)\n                .findOrCreateDirectory(\"Android\")\n                .findOrCreateDirectory(\"obb\")\n                .findOrCreateDirectory(packageName);\n        return Paths.get(obbDir.getUri());\n    }\n\n    @NonNull\n    public static Path getWritableExternalDirectory(@UserIdInt int userId) throws FileNotFoundException {\n        // Get the first writable external storage directory\n        OsEnvironment.UserEnvironment userEnvironment = OsEnvironment.getUserEnvironment(userId);\n        Path[] extDirs = userEnvironment.getExternalDirs();\n        Path writableExtDir = null;\n        for (Path extDir : extDirs) {\n            if (extDir.canWrite() || Objects.requireNonNull(extDir.getFilePath()).startsWith(\"/storage/emulated\")) {\n                writableExtDir = extDir;\n                break;\n            }\n        }\n        if (writableExtDir == null) {\n            throw new FileNotFoundException(\"Couldn't find any writable Obb dir\");\n        }\n        return writableExtDir;\n    }\n\n    public static int getDensityFromName(@Nullable String densityName) {\n        Integer density = StaticDataset.DENSITY_NAME_TO_DENSITY.get(densityName);\n        if (density == null) {\n            throw new IllegalArgumentException(\"Unknown density \" + densityName);\n        }\n        return density;\n    }\n\n    @NonNull\n    private static ByteBuffer getAndroidManifestFromApk(\n            @NonNull List<CentralDirectoryRecord> cdRecords, @NonNull DataSource lhfSection)\n            throws IOException, ApkFormatException, ZipFormatException {\n        CentralDirectoryRecord androidManifestCdRecord = findCdRecord(cdRecords, MANIFEST_FILE);\n        if (androidManifestCdRecord == null) {\n            throw new ApkFormatException(\"Missing \" + MANIFEST_FILE);\n        }\n        return ByteBuffer.wrap(LocalFileRecord.getUncompressedData(\n                lhfSection, androidManifestCdRecord, lhfSection.size()));\n    }\n\n    @Nullable\n    private static CentralDirectoryRecord findCdRecord(\n            @NonNull List<CentralDirectoryRecord> cdRecords, @NonNull String name) {\n        for (CentralDirectoryRecord cdRecord : cdRecords) {\n            if (name.equals(cdRecord.getName())) {\n                return cdRecord;\n            }\n        }\n        return null;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/apk/ApplicationInfoApkSource.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.apk;\n\nimport android.content.pm.ApplicationInfo;\nimport android.content.pm.PackageInfo;\nimport android.content.pm.PackageManager;\nimport android.net.Uri;\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\nimport androidx.core.os.ParcelCompat;\n\nimport org.json.JSONException;\nimport org.json.JSONObject;\n\nimport java.io.File;\nimport java.util.Objects;\n\nimport io.github.muntashirakon.AppManager.history.JsonDeserializer;\nimport io.github.muntashirakon.AppManager.utils.ContextUtils;\n\npublic class ApplicationInfoApkSource extends ApkSource {\n    public static final String TAG = ApplicationInfoApkSource.class.getSimpleName();\n\n    @NonNull\n    private final ApplicationInfo mApplicationInfo;\n\n    private int mApkFileKey;\n\n    ApplicationInfoApkSource(@NonNull ApplicationInfo applicationInfo) {\n        mApplicationInfo = Objects.requireNonNull(applicationInfo);\n    }\n\n    @NonNull\n    @Override\n    public ApkFile resolve() throws ApkFile.ApkFileException {\n        ApkFile apkFile = ApkFile.getInstance(mApkFileKey);\n        if (apkFile != null && !apkFile.isClosed()) {\n            // Usable past instance\n            return apkFile;\n        }\n        mApkFileKey = ApkFile.createInstance(mApplicationInfo);\n        return Objects.requireNonNull(ApkFile.getInstance(mApkFileKey));\n    }\n\n    @NonNull\n    @Override\n    public ApkSource toCachedSource() {\n        return new CachedApkSource(Uri.fromFile(new File(mApplicationInfo.publicSourceDir)),\n                \"application/vnd.android.package-archive\");\n    }\n\n    protected ApplicationInfoApkSource(@NonNull Parcel in) {\n        mApplicationInfo = Objects.requireNonNull(ParcelCompat.readParcelable(in,\n                ApplicationInfo.class.getClassLoader(), ApplicationInfo.class));\n        mApkFileKey = in.readInt();\n    }\n\n    @Override\n    public int describeContents() {\n        return 0;\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        dest.writeParcelable(mApplicationInfo, flags);\n        dest.writeInt(mApkFileKey);\n    }\n\n    protected ApplicationInfoApkSource(@NonNull JSONObject jsonObject) throws JSONException {\n        PackageManager pm = ContextUtils.getContext().getPackageManager();\n        String file = jsonObject.getString(\"file\");\n        PackageInfo packageInfo = Objects.requireNonNull(pm.getPackageArchiveInfo(file, 0));\n        mApplicationInfo = Objects.requireNonNull(packageInfo.applicationInfo);\n        mApplicationInfo.publicSourceDir = mApplicationInfo.sourceDir = file;\n        mApkFileKey = jsonObject.getInt(\"apk_file_key\");\n    }\n\n    @NonNull\n    @Override\n    public JSONObject serializeToJson() throws JSONException {\n        JSONObject jsonObject = new JSONObject();\n        jsonObject.put(\"tag\", TAG);\n        jsonObject.put(\"file\", mApplicationInfo.publicSourceDir);\n        jsonObject.put(\"apk_file_key\", mApkFileKey);\n        return jsonObject;\n    }\n\n    public static final JsonDeserializer.Creator<ApplicationInfoApkSource> DESERIALIZER = ApplicationInfoApkSource::new;\n\n    public static final Creator<ApplicationInfoApkSource> CREATOR = new Creator<ApplicationInfoApkSource>() {\n        @Override\n        public ApplicationInfoApkSource createFromParcel(Parcel source) {\n            return new ApplicationInfoApkSource(source);\n        }\n\n        @Override\n        public ApplicationInfoApkSource[] newArray(int size) {\n            return new ApplicationInfoApkSource[size];\n        }\n    };\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/apk/CachedApkSource.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.apk;\n\nimport android.content.ContentResolver;\nimport android.net.Uri;\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.core.os.ParcelCompat;\n\nimport org.json.JSONException;\nimport org.json.JSONObject;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.util.Objects;\n\nimport io.github.muntashirakon.AppManager.fm.FmProvider;\nimport io.github.muntashirakon.AppManager.history.JsonDeserializer;\nimport io.github.muntashirakon.AppManager.self.filecache.FileCache;\nimport io.github.muntashirakon.AppManager.utils.FileUtils;\nimport io.github.muntashirakon.AppManager.utils.JSONUtils;\nimport io.github.muntashirakon.io.Paths;\n\npublic class CachedApkSource extends ApkSource {\n    public static final String TAG = CachedApkSource.class.getSimpleName();\n\n    @NonNull\n    private final Uri mUri;\n    @Nullable\n    private final String mMimeType;\n\n    private int mApkFileKey;\n    @Nullable\n    private File mCachedFile;\n\n    CachedApkSource(@NonNull Uri uri, @Nullable String mimeType) {\n        mUri = Objects.requireNonNull(uri);\n        mMimeType = mimeType;\n    }\n\n    @NonNull\n    @Override\n    public ApkFile resolve() throws ApkFile.ApkFileException {\n        ApkFile apkFile = ApkFile.getInstance(mApkFileKey);\n        if (apkFile != null && !apkFile.isClosed()) {\n            // Usable past instance\n            return apkFile;\n        }\n        // May need to cache the APK if it's not from our own content provider\n        if (mCachedFile != null && mCachedFile.exists()) {\n            mApkFileKey = ApkFile.createInstance(Uri.fromFile(mCachedFile), mMimeType);\n        } else if (ContentResolver.SCHEME_FILE.equals(mUri.getScheme())) {\n            mApkFileKey = ApkFile.createInstance(mUri, mMimeType);\n        } else if (ContentResolver.SCHEME_CONTENT.equals(mUri.getScheme())\n                && FmProvider.AUTHORITY.equals(mUri.getAuthority())) {\n            mApkFileKey = ApkFile.createInstance(mUri, mMimeType);\n        } else {\n            // Need caching\n            try {\n                mCachedFile = FileCache.getGlobalFileCache().getCachedFile(Paths.get(mUri));\n                mApkFileKey = ApkFile.createInstance(Uri.fromFile(mCachedFile), mMimeType);\n            } catch (IOException | SecurityException e) {\n                throw new ApkFile.ApkFileException(e);\n            }\n        }\n        return Objects.requireNonNull(ApkFile.getInstance(mApkFileKey));\n    }\n\n    @NonNull\n    @Override\n    public ApkSource toCachedSource() {\n        Uri uri;\n        if (mCachedFile != null && mCachedFile.exists()) {\n            uri = Uri.fromFile(mCachedFile);\n        } else uri = mUri;\n        return new CachedApkSource(uri, mMimeType);\n    }\n\n    public void cleanup() {\n        FileUtils.deleteSilently(mCachedFile);\n        mCachedFile = null;\n    }\n\n    protected CachedApkSource(@NonNull Parcel in) {\n        mUri = Objects.requireNonNull(ParcelCompat.readParcelable(in, Uri.class.getClassLoader(), Uri.class));\n        mMimeType = in.readString();\n        mApkFileKey = in.readInt();\n        String file = in.readString();\n        if (file != null) {\n            mCachedFile = new File(file);\n        }\n    }\n\n    @Override\n    public int describeContents() {\n        return 0;\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        dest.writeParcelable(mUri, flags);\n        dest.writeString(mMimeType);\n        dest.writeInt(mApkFileKey);\n        String file = mCachedFile != null ? mCachedFile.getAbsolutePath() : null;\n        dest.writeString(file);\n    }\n\n    protected CachedApkSource(@NonNull JSONObject jsonObject) throws JSONException {\n        mUri = Uri.parse(jsonObject.getString(\"uri\"));\n        mMimeType = jsonObject.getString(\"mime_type\");\n        mApkFileKey = jsonObject.getInt(\"apk_file_key\");\n        String cachedFile = JSONUtils.optString(jsonObject, \"cached_file\", null);\n        mCachedFile = cachedFile != null ? new File(cachedFile) : null;\n    }\n\n    @NonNull\n    @Override\n    public JSONObject serializeToJson() throws JSONException {\n        JSONObject jsonObject = new JSONObject();\n        jsonObject.put(\"tag\", TAG);\n        jsonObject.put(\"uri\", mUri.toString());\n        jsonObject.put(\"mime_type\", mMimeType);\n        jsonObject.put(\"apk_file_key\", mApkFileKey);\n        jsonObject.put(\"cached_file\", mCachedFile != null ? mCachedFile.getAbsolutePath() : null);\n        return jsonObject;\n    }\n\n    public static final JsonDeserializer.Creator<CachedApkSource> DESERIALIZER = CachedApkSource::new;\n\n    public static final Creator<CachedApkSource> CREATOR = new Creator<CachedApkSource>() {\n        @Override\n        public CachedApkSource createFromParcel(Parcel source) {\n            return new CachedApkSource(source);\n        }\n\n        @Override\n        public CachedApkSource[] newArray(int size) {\n            return new CachedApkSource[size];\n        }\n    };\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/apk/UriApkSource.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.apk;\n\nimport android.net.Uri;\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.core.os.ParcelCompat;\n\nimport org.json.JSONException;\nimport org.json.JSONObject;\n\nimport java.util.Objects;\n\nimport io.github.muntashirakon.AppManager.history.JsonDeserializer;\n\npublic class UriApkSource extends ApkSource {\n    public static final String TAG = UriApkSource.class.getSimpleName();\n\n    @NonNull\n    private final Uri mUri;\n    @Nullable\n    private final String mMimeType;\n\n    private int mApkFileKey;\n\n    public UriApkSource(@NonNull Uri uri, @Nullable String mimeType) {\n        mUri = Objects.requireNonNull(uri);\n        mMimeType = mimeType;\n    }\n\n    @NonNull\n    @Override\n    public ApkFile resolve() throws ApkFile.ApkFileException {\n        ApkFile apkFile = ApkFile.getInstance(mApkFileKey);\n        if (apkFile != null && !apkFile.isClosed()) {\n            // Usable past instance\n            return apkFile;\n        }\n        mApkFileKey = ApkFile.createInstance(mUri, mMimeType);\n        return Objects.requireNonNull(ApkFile.getInstance(mApkFileKey));\n    }\n\n    @NonNull\n    @Override\n    public ApkSource toCachedSource() {\n        return new CachedApkSource(mUri, mMimeType);\n    }\n\n    protected UriApkSource(@NonNull Parcel in) {\n        mUri = Objects.requireNonNull(ParcelCompat.readParcelable(in, Uri.class.getClassLoader(), Uri.class));\n        mMimeType = in.readString();\n        mApkFileKey = in.readInt();\n    }\n\n    @Override\n    public int describeContents() {\n        return 0;\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        dest.writeParcelable(mUri, flags);\n        dest.writeString(mMimeType);\n        dest.writeInt(mApkFileKey);\n    }\n\n    protected UriApkSource(@NonNull JSONObject jsonObject) throws JSONException {\n        mUri = Uri.parse(jsonObject.getString(\"uri\"));\n        mMimeType = jsonObject.getString(\"mime_type\");\n        mApkFileKey = jsonObject.getInt(\"apk_file_key\");\n    }\n\n    @NonNull\n    @Override\n    public JSONObject serializeToJson() throws JSONException {\n        JSONObject jsonObject = new JSONObject();\n        jsonObject.put(\"tag\", TAG);\n        jsonObject.put(\"uri\", mUri.toString());\n        jsonObject.put(\"mime_type\", mMimeType);\n        jsonObject.put(\"apk_file_key\", mApkFileKey);\n        return jsonObject;\n    }\n\n    public static final JsonDeserializer.Creator<UriApkSource> DESERIALIZER = UriApkSource::new;\n\n    public static final Creator<UriApkSource> CREATOR = new Creator<UriApkSource>() {\n        @Override\n        public UriApkSource createFromParcel(Parcel source) {\n            return new UriApkSource(source);\n        }\n\n        @Override\n        public UriApkSource[] newArray(int size) {\n            return new UriApkSource[size];\n        }\n    };\n}"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/apk/behavior/FreezeUnfreeze.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.apk.behavior;\n\nimport android.annotation.UserIdInt;\nimport android.app.Notification;\nimport android.app.PendingIntent;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.os.UserHandleHidden;\nimport android.text.SpannableStringBuilder;\n\nimport androidx.annotation.IntDef;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.core.app.PendingIntentCompat;\nimport androidx.core.content.ContextCompat;\nimport androidx.fragment.app.FragmentActivity;\n\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\n\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.compat.PackageManagerCompat;\nimport io.github.muntashirakon.AppManager.utils.ArrayUtils;\nimport io.github.muntashirakon.AppManager.utils.FreezeUtils;\nimport io.github.muntashirakon.AppManager.utils.NotificationUtils;\nimport io.github.muntashirakon.AppManager.utils.UIUtils;\nimport io.github.muntashirakon.dialog.SearchableSingleChoiceDialogBuilder;\n\npublic final class FreezeUnfreeze {\n    @IntDef(flag = true, value = {\n            FLAG_ON_UNFREEZE_OPEN_APP,\n            FLAG_ON_OPEN_APP_NO_TASK,\n            FLAG_FREEZE_ON_PHONE_LOCKED,\n    })\n    @Retention(RetentionPolicy.SOURCE)\n    public @interface FreezeFlags {\n    }\n\n    public static final int FLAG_ON_UNFREEZE_OPEN_APP = 1 << 0;\n    public static final int FLAG_ON_OPEN_APP_NO_TASK = 1 << 1;\n    public static final int FLAG_FREEZE_ON_PHONE_LOCKED = 1 << 2;\n\n    public static final int PRIVATE_FLAG_FREEZE_FORCE = 1 << 0;\n\n    private static final String EXTRA_PACKAGE_NAME = \"pkg\";\n    private static final String EXTRA_USER_ID = \"user\";\n    private static final String EXTRA_FLAGS = \"flags\";\n    private static final String EXTRA_FORCE_FREEZE = \"force\";\n\n    @NonNull\n    public static Intent getShortcutIntent(@NonNull Context context, @NonNull FreezeUnfreezeShortcutInfo shortcutInfo) {\n        Intent intent = new Intent(context, FreezeUnfreezeActivity.class);\n        intent.putExtra(EXTRA_PACKAGE_NAME, shortcutInfo.packageName);\n        intent.putExtra(EXTRA_USER_ID, shortcutInfo.userId);\n        intent.putExtra(EXTRA_FLAGS, shortcutInfo.flags);\n        intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY | Intent.FLAG_ACTIVITY_NEW_TASK);\n        return intent;\n    }\n\n    @NonNull\n    public static Intent getShortcutIntent(@NonNull Context context, @NonNull String packageName, @UserIdInt int userId, int flags) {\n        Intent intent = new Intent(context, FreezeUnfreezeActivity.class);\n        intent.putExtra(EXTRA_PACKAGE_NAME, packageName);\n        intent.putExtra(EXTRA_USER_ID, userId);\n        intent.putExtra(EXTRA_FLAGS, flags);\n        intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY | Intent.FLAG_ACTIVITY_NEW_TASK);\n        return intent;\n    }\n\n    @Nullable\n    public static FreezeUnfreezeShortcutInfo getShortcutInfo(@NonNull Intent intent) {\n        String packageName = intent.getStringExtra(EXTRA_PACKAGE_NAME);\n        if (packageName == null) {\n            return null;\n        }\n        int userId = intent.getIntExtra(EXTRA_USER_ID, UserHandleHidden.myUserId());\n        int flags = intent.getIntExtra(EXTRA_FLAGS, 0);\n        boolean force = intent.getBooleanExtra(EXTRA_FORCE_FREEZE, false);\n        FreezeUnfreezeShortcutInfo shortcutInfo = new FreezeUnfreezeShortcutInfo(packageName, userId, flags);\n        if (force) {\n            shortcutInfo.addPrivateFlags(PRIVATE_FLAG_FREEZE_FORCE);\n        }\n        return shortcutInfo;\n    }\n\n    private static final Integer[] FREEZING_METHODS = new Integer[]{\n            FreezeUtils.FREEZE_SUSPEND,\n            FreezeUtils.FREEZE_ADV_SUSPEND,\n            FreezeUtils.FREEZE_DISABLE,\n            FreezeUtils.FREEZE_HIDE\n    };\n\n    private static final Integer[] FREEZING_METHOD_TITLES = new Integer[]{\n            R.string.suspend_app,\n            R.string.advanced_suspend_app,\n            R.string.disable,\n            R.string.hide_app\n    };\n\n    private static final Integer[] FREEZING_METHOD_DESCRIPTIONS = new Integer[]{\n            R.string.suspend_app_description,\n            R.string.advanced_suspend_app_description,\n            R.string.disable_app_description,\n            R.string.hide_app_description\n    };\n\n    @NonNull\n    public static SearchableSingleChoiceDialogBuilder<Integer> getFreezeDialog(\n            @NonNull Context context,\n            @FreezeUtils.FreezeMethod int selectedType) {\n        CharSequence[] itemDescription = new CharSequence[FREEZING_METHODS.length];\n        for (int i = 0; i < FREEZING_METHODS.length; ++i) {\n            itemDescription[i] = new SpannableStringBuilder()\n                    .append(context.getString(FREEZING_METHOD_TITLES[i]))\n                    .append(\"\\n\")\n                    .append(UIUtils.getSmallerText(context.getString(FREEZING_METHOD_DESCRIPTIONS[i])));\n        }\n        return new SearchableSingleChoiceDialogBuilder<>(context, FREEZING_METHODS, itemDescription)\n                .setSelectionIndex(ArrayUtils.indexOf(FREEZING_METHODS, selectedType));\n    }\n\n    static void launchApp(@NonNull FragmentActivity activity, @NonNull FreezeUnfreezeShortcutInfo shortcutInfo) {\n        Intent launchIntent = PackageManagerCompat.getLaunchIntentForPackage(shortcutInfo.packageName, shortcutInfo.userId);\n        if (launchIntent == null) {\n            // No launch intent found\n            return;\n        }\n        // launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_TASK_ON_HOME | Intent.FLAG_ACTIVITY_NEW_DOCUMENT);\n        if ((shortcutInfo.flags & FLAG_ON_OPEN_APP_NO_TASK) != 0) {\n            launchIntent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);\n        }\n        try {\n            activity.startActivity(launchIntent);\n            Intent intent = getShortcutIntent(activity, shortcutInfo);\n            intent.putExtra(EXTRA_FORCE_FREEZE, true);\n            int requestCode = shortcutInfo.hashCode();\n            PendingIntent pendingIntent = PendingIntentCompat.getActivity(activity, requestCode,\n                    intent, PendingIntent.FLAG_ONE_SHOT, false);\n            // There's a small chance that the notification by shortcutInfo.hasCode() already exists, in that case,\n            // find the next one. This will cause trouble with dismissing the notification, but this is a viable\n            // trade-off.\n            String notificationTag = String.valueOf(requestCode);\n            NotificationUtils.displayFreezeUnfreezeNotification(activity, notificationTag, builder -> builder\n                    .setDefaults(Notification.DEFAULT_ALL)\n                    .setWhen(System.currentTimeMillis())\n                    .setSmallIcon(R.drawable.ic_default_notification)\n                    .setTicker(activity.getText(R.string.freeze))\n                    .setContentTitle(shortcutInfo.getName())\n                    .setContentText(activity.getString(R.string.tap_to_freeze_app))\n                    .setContentIntent(pendingIntent)\n                    .build());\n            if ((shortcutInfo.flags & FLAG_FREEZE_ON_PHONE_LOCKED) != 0) {\n                Intent service = new Intent(intent)\n                        .setClassName(activity, FreezeUnfreezeService.class.getName());\n                ContextCompat.startForegroundService(activity, service);\n            }\n        } catch (Throwable th) {\n            UIUtils.displayLongToast(th.getLocalizedMessage());\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/apk/behavior/FreezeUnfreezeActivity.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.apk.behavior;\n\nimport static io.github.muntashirakon.AppManager.compat.PackageManagerCompat.MATCH_DISABLED_COMPONENTS;\nimport static io.github.muntashirakon.AppManager.compat.PackageManagerCompat.MATCH_UNINSTALLED_PACKAGES;\nimport static io.github.muntashirakon.AppManager.utils.UIUtils.getBitmapFromDrawable;\nimport static io.github.muntashirakon.AppManager.utils.UIUtils.getDimmedBitmap;\n\nimport android.app.Application;\nimport android.content.Intent;\nimport android.content.pm.ApplicationInfo;\nimport android.content.pm.PackageManager;\nimport android.graphics.Bitmap;\nimport android.os.Bundle;\nimport android.os.RemoteException;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.core.content.pm.ShortcutInfoCompat;\nimport androidx.core.content.pm.ShortcutManagerCompat;\nimport androidx.core.graphics.drawable.IconCompat;\nimport androidx.core.util.Pair;\nimport androidx.lifecycle.AndroidViewModel;\nimport androidx.lifecycle.MutableLiveData;\nimport androidx.lifecycle.ViewModelProvider;\n\nimport com.google.android.material.dialog.MaterialAlertDialogBuilder;\n\nimport java.util.Collections;\nimport java.util.LinkedList;\nimport java.util.Optional;\nimport java.util.Queue;\n\nimport io.github.muntashirakon.AppManager.BaseActivity;\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.compat.PackageManagerCompat;\nimport io.github.muntashirakon.AppManager.self.SelfPermissions;\nimport io.github.muntashirakon.AppManager.settings.Prefs;\nimport io.github.muntashirakon.AppManager.utils.FreezeUtils;\nimport io.github.muntashirakon.AppManager.utils.NotificationUtils;\nimport io.github.muntashirakon.AppManager.utils.ThreadUtils;\nimport io.github.muntashirakon.AppManager.utils.UIUtils;\n\npublic class FreezeUnfreezeActivity extends BaseActivity {\n    private FreezeUnfreezeViewModel mViewModel;\n\n    @Override\n    protected void onAuthenticated(@Nullable Bundle savedInstanceState) {\n        mViewModel = new ViewModelProvider(this).get(FreezeUnfreezeViewModel.class);\n        if (!SelfPermissions.canFreezeUnfreezePackages()) {\n            UIUtils.displayShortToast(R.string.only_works_in_root_or_adb_mode);\n            finish();\n            return;\n        }\n        FreezeUnfreezeShortcutInfo i = FreezeUnfreeze.getShortcutInfo(getIntent());\n        if (i != null) {\n            hideNotification(i);\n            mViewModel.addToPendingShortcuts(i);\n            mViewModel.checkNextFrozen();\n        } else {\n            finish();\n            return;\n        }\n        mViewModel.mIsFrozenLiveData.observe(this, shortcutInfoBooleanPair -> {\n            if (shortcutInfoBooleanPair == null) {\n                // End of queue reached\n                finish();\n                return;\n            }\n            FreezeUnfreezeShortcutInfo shortcutInfo = shortcutInfoBooleanPair.first;\n            Intent intent = FreezeUnfreeze.getShortcutIntent(this, shortcutInfo);\n            // Set action for shortcut\n            intent.setAction(Intent.ACTION_CREATE_SHORTCUT);\n            ShortcutInfoCompat shortcutInfoCompat = new ShortcutInfoCompat.Builder(this, shortcutInfo.getId())\n                    .setShortLabel(shortcutInfo.getName())\n                    .setLongLabel(shortcutInfo.getName())\n                    .setIcon(IconCompat.createWithBitmap(shortcutInfo.getIcon()))\n                    .setIntent(intent)\n                    .build();\n            ShortcutManagerCompat.updateShortcuts(this, Collections.singletonList(shortcutInfoCompat));\n            // Launch app if requested\n            if (!shortcutInfoBooleanPair.second && (shortcutInfo.flags & FreezeUnfreeze.FLAG_ON_UNFREEZE_OPEN_APP) != 0) {\n                FreezeUnfreeze.launchApp(this, shortcutInfo);\n            }\n            mViewModel.checkNextFrozen();\n        });\n        mViewModel.mOpenAppOrFreeze.observe(this, shortcutInfo -> new MaterialAlertDialogBuilder(this)\n                .setTitle(R.string.freeze_unfreeze)\n                .setMessage(R.string.choose_what_to_do)\n                .setPositiveButton(R.string.open, (dialog, which) -> FreezeUnfreeze.launchApp(this, shortcutInfo))\n                .setNegativeButton(R.string.freeze, (dialog, which) -> mViewModel.freezeFinal(shortcutInfo))\n                .setOnDismissListener(v -> mViewModel.checkNextFrozen())\n                .show());\n    }\n\n    @Override\n    public boolean getTransparentBackground() {\n        return true;\n    }\n\n    @Override\n    protected void onNewIntent(@NonNull Intent intent) {\n        super.onNewIntent(intent);\n        if (!SelfPermissions.canFreezeUnfreezePackages()) {\n            UIUtils.displayShortToast(R.string.only_works_in_root_or_adb_mode);\n            finish();\n            return;\n        }\n        FreezeUnfreezeShortcutInfo shortcutInfo = FreezeUnfreeze.getShortcutInfo(getIntent());\n        if (mViewModel != null && shortcutInfo != null) {\n            hideNotification(shortcutInfo);\n            mViewModel.addToPendingShortcuts(shortcutInfo);\n        }\n    }\n\n    private void hideNotification(@Nullable FreezeUnfreezeShortcutInfo shortcutInfo) {\n        if (shortcutInfo == null) return;\n        String notificationTag = String.valueOf(shortcutInfo.hashCode());\n        NotificationUtils.getFreezeUnfreezeNotificationManager(this).cancel(notificationTag, 1);\n    }\n\n    public static class FreezeUnfreezeViewModel extends AndroidViewModel {\n        private final MutableLiveData<Pair<FreezeUnfreezeShortcutInfo, Boolean>> mIsFrozenLiveData = new MutableLiveData<>();\n        private final MutableLiveData<FreezeUnfreezeShortcutInfo> mOpenAppOrFreeze = new MutableLiveData<>();\n        private final Queue<FreezeUnfreezeShortcutInfo> mPendingShortcuts = new LinkedList<>();\n\n        public FreezeUnfreezeViewModel(@NonNull Application application) {\n            super(application);\n        }\n\n        public void addToPendingShortcuts(@NonNull FreezeUnfreezeShortcutInfo shortcutInfo) {\n            synchronized (mPendingShortcuts) {\n                mPendingShortcuts.add(shortcutInfo);\n            }\n        }\n\n        public void checkNextFrozen() {\n            ThreadUtils.postOnBackgroundThread(() -> {\n                FreezeUnfreezeShortcutInfo shortcutInfo;\n                synchronized (mPendingShortcuts) {\n                    shortcutInfo = mPendingShortcuts.poll();\n                }\n                if (shortcutInfo == null) {\n                    mIsFrozenLiveData.postValue(null);\n                    return;\n                }\n                boolean forceFreeze = (shortcutInfo.getPrivateFlags() & FreezeUnfreeze.PRIVATE_FLAG_FREEZE_FORCE) != 0;\n                try {\n                    ApplicationInfo applicationInfo = PackageManagerCompat.getApplicationInfo(shortcutInfo.packageName,\n                            MATCH_UNINSTALLED_PACKAGES | MATCH_DISABLED_COMPONENTS\n                                    | PackageManagerCompat.MATCH_STATIC_SHARED_AND_SDK_LIBRARIES, shortcutInfo.userId);\n                    Bitmap icon = getBitmapFromDrawable(applicationInfo.loadIcon(getApplication().getPackageManager()));\n                    shortcutInfo.setName(applicationInfo.loadLabel(getApplication().getPackageManager()));\n                    boolean isFrozen = !forceFreeze && FreezeUtils.isFrozen(applicationInfo);\n                    if (isFrozen) {\n                        FreezeUtils.unfreeze(shortcutInfo.packageName, shortcutInfo.userId);\n                        shortcutInfo.setIcon(icon);\n                    } else {\n                        shortcutInfo.setIcon(getDimmedBitmap(icon));\n                        if (!forceFreeze && (shortcutInfo.flags & FreezeUnfreeze.FLAG_ON_UNFREEZE_OPEN_APP) != 0) {\n                            // Ask whether to open or freeze the app\n                            mOpenAppOrFreeze.postValue(shortcutInfo);\n                            return;\n                        }\n                        int freezeType = Optional.ofNullable(FreezeUtils.loadFreezeMethod(shortcutInfo.packageName))\n                                        .orElse(Prefs.Blocking.getDefaultFreezingMethod());\n                        FreezeUtils.freeze(shortcutInfo.packageName, shortcutInfo.userId, freezeType);\n                    }\n                    mIsFrozenLiveData.postValue(new Pair<>(shortcutInfo, !isFrozen));\n                } catch (RemoteException | PackageManager.NameNotFoundException e) {\n                    e.printStackTrace();\n                }\n            });\n        }\n\n        public void freezeFinal(FreezeUnfreezeShortcutInfo shortcutInfo) {\n            ThreadUtils.postOnBackgroundThread(() -> {\n                try {\n                    int freezeType = Optional.ofNullable(FreezeUtils.loadFreezeMethod(shortcutInfo.packageName))\n                            .orElse(Prefs.Blocking.getDefaultFreezingMethod());\n                    FreezeUtils.freeze(shortcutInfo.packageName, shortcutInfo.userId, freezeType);\n                    mIsFrozenLiveData.postValue(new Pair<>(shortcutInfo, true));\n                } catch (RemoteException e) {\n                    e.printStackTrace();\n                }\n            });\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/apk/behavior/FreezeUnfreezeService.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.apk.behavior;\n\nimport static io.github.muntashirakon.AppManager.compat.PackageManagerCompat.MATCH_DISABLED_COMPONENTS;\nimport static io.github.muntashirakon.AppManager.compat.PackageManagerCompat.MATCH_UNINSTALLED_PACKAGES;\nimport static io.github.muntashirakon.AppManager.utils.UIUtils.getBitmapFromDrawable;\nimport static io.github.muntashirakon.AppManager.utils.UIUtils.getDimmedBitmap;\n\nimport android.app.PendingIntent;\nimport android.app.Service;\nimport android.content.BroadcastReceiver;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.IntentFilter;\nimport android.content.pm.ApplicationInfo;\nimport android.content.pm.PackageManager;\nimport android.graphics.Bitmap;\nimport android.os.IBinder;\nimport android.os.PowerManager;\nimport android.os.RemoteException;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.WorkerThread;\nimport androidx.core.app.NotificationCompat;\nimport androidx.core.app.NotificationManagerCompat;\nimport androidx.core.app.PendingIntentCompat;\nimport androidx.core.app.ServiceCompat;\nimport androidx.core.content.ContextCompat;\nimport androidx.core.content.pm.ShortcutInfoCompat;\nimport androidx.core.content.pm.ShortcutManagerCompat;\nimport androidx.core.graphics.drawable.IconCompat;\n\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Optional;\nimport java.util.concurrent.Future;\n\nimport io.github.muntashirakon.AppManager.BuildConfig;\nimport io.github.muntashirakon.AppManager.DummyActivity;\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.compat.PackageManagerCompat;\nimport io.github.muntashirakon.AppManager.misc.ScreenLockChecker;\nimport io.github.muntashirakon.AppManager.settings.Prefs;\nimport io.github.muntashirakon.AppManager.types.ForegroundService;\nimport io.github.muntashirakon.AppManager.utils.CpuUtils;\nimport io.github.muntashirakon.AppManager.utils.FreezeUtils;\nimport io.github.muntashirakon.AppManager.utils.NotificationUtils;\nimport io.github.muntashirakon.AppManager.utils.ThreadUtils;\n\npublic class FreezeUnfreezeService extends Service {\n    public static final String TAG = FreezeUnfreezeService.class.getSimpleName();\n\n    public static final String CHANNEL_ID = BuildConfig.APPLICATION_ID + \".channel.FREEZE_UNFREEZE_MONITOR\";\n\n    private static final String STOP_ACTION = BuildConfig.APPLICATION_ID + \".action.STOP_FREEZE_UNFREEZE_MONITOR\";\n\n    private final Map<String, FreezeUnfreezeShortcutInfo> mPackagesToShortcut = new HashMap<>();\n    private final Map<String, String> mPackagesToNotificationTag = new HashMap<>();\n    private ScreenLockChecker mScreenLockChecker;\n    private final BroadcastReceiver mScreenLockedReceiver = new BroadcastReceiver() {\n        @Override\n        public void onReceive(Context context, Intent intent) {\n            try {\n                if (mCheckLockResult != null) {\n                    mCheckLockResult.cancel(true);\n                }\n                mCheckLockResult = ThreadUtils.postOnBackgroundThread(() -> {\n                    if (mScreenLockChecker == null) {\n                        mScreenLockChecker = new ScreenLockChecker(FreezeUnfreezeService.this, () -> freezeAllPackages());\n                    }\n                    mScreenLockChecker.checkLock();\n                });\n            } catch (Throwable th) {\n                th.printStackTrace();\n            }\n        }\n    };\n\n    private boolean mIsWorking;\n    @Nullable\n    private Future<?> mCheckLockResult;\n    private PowerManager.WakeLock mWakeLock;\n\n    @Override\n    public void onCreate() {\n        super.onCreate();\n        mWakeLock = CpuUtils.getPartialWakeLock(\"freeze_unfreeze\");\n    }\n\n    @Override\n    public int onStartCommand(@Nullable Intent intent, int flags, int startId) {\n        if (intent != null && STOP_ACTION.equals(intent.getAction())) {\n            stopSelf();\n            return START_NOT_STICKY;\n        }\n        onHandleIntent(intent);\n        if (mIsWorking) {\n            return START_NOT_STICKY;\n        }\n        mIsWorking = true;\n        NotificationUtils.getNewNotificationManager(this, CHANNEL_ID, \"Freeze/unfreeze Monitor\",\n                NotificationManagerCompat.IMPORTANCE_LOW);\n        Intent stopIntent = new Intent(this, FreezeUnfreezeService.class).setAction(STOP_ACTION);\n        PendingIntent pendingIntent = PendingIntentCompat.getService(this, 0, stopIntent, PendingIntent.FLAG_ONE_SHOT, false);\n        NotificationCompat.Action stopServiceAction = new NotificationCompat.Action.Builder(null,\n                getString(R.string.action_stop_service), pendingIntent)\n                .setAuthenticationRequired(true)\n                .build();\n        NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID)\n                .setLocalOnly(true)\n                .setOngoing(true)\n                .setContentTitle(null)\n                .setContentText(getString(R.string.waiting_for_the_phone_to_be_locked))\n                .setSmallIcon(R.drawable.ic_default_notification)\n                .setSubText(getText(R.string.freeze_unfreeze))\n                .setPriority(NotificationCompat.PRIORITY_LOW)\n                .addAction(stopServiceAction);\n        ForegroundService.start(this, NotificationUtils.nextNotificationId(null), builder.build(),\n                ForegroundService.FOREGROUND_SERVICE_TYPE_DATA_SYNC\n                        | ForegroundService.FOREGROUND_SERVICE_TYPE_SPECIAL_USE);\n        IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_ON);\n        filter.addAction(Intent.ACTION_SCREEN_OFF);\n        filter.addAction(Intent.ACTION_USER_PRESENT);\n        ContextCompat.registerReceiver(this, mScreenLockedReceiver, filter, ContextCompat.RECEIVER_EXPORTED);\n        return START_NOT_STICKY;\n    }\n\n    @Override\n    public void onTaskRemoved(Intent rootIntent) {\n        // https://issuetracker.google.com/issues/36967794\n        Intent intent = new Intent(this, DummyActivity.class);\n        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);\n        startActivity(intent);\n    }\n\n    @Override\n    public void onDestroy() {\n        unregisterReceiver(mScreenLockedReceiver);\n        ServiceCompat.stopForeground(this, ServiceCompat.STOP_FOREGROUND_REMOVE);\n        if (mCheckLockResult != null) {\n            mCheckLockResult.cancel(true);\n        }\n        CpuUtils.releaseWakeLock(mWakeLock);\n        super.onDestroy();\n    }\n\n    @Nullable\n    @Override\n    public IBinder onBind(Intent intent) {\n        return null;\n    }\n\n    private void onHandleIntent(@Nullable Intent intent) {\n        if (intent == null) return;\n        FreezeUnfreezeShortcutInfo shortcutInfo = FreezeUnfreeze.getShortcutInfo(intent);\n        if (shortcutInfo == null) return;\n        mPackagesToShortcut.put(shortcutInfo.packageName, shortcutInfo);\n        String notificationTag = String.valueOf(shortcutInfo.hashCode());\n        mPackagesToNotificationTag.put(shortcutInfo.packageName, notificationTag);\n    }\n\n    @WorkerThread\n    private void freezeAllPackages() {\n        for (String packageName : mPackagesToShortcut.keySet()) {\n            FreezeUnfreezeShortcutInfo shortcutInfo = mPackagesToShortcut.get(packageName);\n            String notificationTag = mPackagesToNotificationTag.get(packageName);\n            if (shortcutInfo != null) {\n                try {\n                    ApplicationInfo applicationInfo = PackageManagerCompat.getApplicationInfo(shortcutInfo.packageName,\n                            MATCH_UNINSTALLED_PACKAGES | MATCH_DISABLED_COMPONENTS\n                                    | PackageManagerCompat.MATCH_STATIC_SHARED_AND_SDK_LIBRARIES, shortcutInfo.userId);\n                    Bitmap icon = getBitmapFromDrawable(applicationInfo.loadIcon(getApplication().getPackageManager()));\n                    shortcutInfo.setName(applicationInfo.loadLabel(getApplication().getPackageManager()));\n                    int freezeType = Optional.ofNullable(FreezeUtils.loadFreezeMethod(shortcutInfo.packageName))\n                            .orElse(Prefs.Blocking.getDefaultFreezingMethod());\n                    FreezeUtils.freeze(shortcutInfo.packageName, shortcutInfo.userId, freezeType);\n                    shortcutInfo.setIcon(getDimmedBitmap(icon));\n                    updateShortcuts(shortcutInfo);\n                } catch (RemoteException | PackageManager.NameNotFoundException e) {\n                    e.printStackTrace();\n                }\n            }\n            if (notificationTag != null) {\n                NotificationUtils.getFreezeUnfreezeNotificationManager(this).cancel(notificationTag, 1);\n            }\n        }\n        stopSelf();\n    }\n\n    private void updateShortcuts(@NonNull FreezeUnfreezeShortcutInfo shortcutInfo) {\n        Intent intent = FreezeUnfreeze.getShortcutIntent(this, shortcutInfo);\n        // Set action for shortcut\n        intent.setAction(Intent.ACTION_CREATE_SHORTCUT);\n        ShortcutInfoCompat shortcutInfoCompat = new ShortcutInfoCompat.Builder(this, shortcutInfo.getId())\n                .setShortLabel(shortcutInfo.getName())\n                .setLongLabel(shortcutInfo.getName())\n                .setIcon(IconCompat.createWithBitmap(shortcutInfo.getIcon()))\n                .setIntent(intent)\n                .build();\n        ShortcutManagerCompat.updateShortcuts(this, Collections.singletonList(shortcutInfoCompat));\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/apk/behavior/FreezeUnfreezeShortcutInfo.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.apk.behavior;\n\nimport android.annotation.UserIdInt;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport java.util.Objects;\n\nimport io.github.muntashirakon.AppManager.shortcut.ShortcutInfo;\n\npublic class FreezeUnfreezeShortcutInfo extends ShortcutInfo {\n    @NonNull\n    public final String packageName;\n    @UserIdInt\n    public final int userId;\n    @FreezeUnfreeze.FreezeFlags\n    public final int flags;\n\n    private int mPrivateFlags;\n\n    public FreezeUnfreezeShortcutInfo(@NonNull String packageName, int userId, int flags) {\n        setId(\"freeze:u=\" + userId + \",p=\" + packageName);\n        this.packageName = packageName;\n        this.userId = userId;\n        this.flags = flags;\n    }\n\n    protected FreezeUnfreezeShortcutInfo(Parcel in) {\n        super(in);\n        packageName = in.readString();\n        userId = in.readInt();\n        flags = in.readInt();\n        mPrivateFlags = in.readInt();\n    }\n\n    public int getPrivateFlags() {\n        return mPrivateFlags;\n    }\n\n    public void setPrivateFlags(int privateFlags) {\n        mPrivateFlags = privateFlags;\n    }\n\n    public void addPrivateFlags(int privateFlags) {\n        mPrivateFlags |= privateFlags;\n    }\n\n    public void removePrivateFlags(int privateFlags) {\n        mPrivateFlags &= ~privateFlags;\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        super.writeToParcel(dest, flags);\n        dest.writeString(packageName);\n        dest.writeInt(userId);\n        dest.writeInt(flags);\n        dest.writeInt(mPrivateFlags);\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hash(packageName, userId);\n    }\n\n    @Override\n    public Intent toShortcutIntent(@NonNull Context context) {\n        return FreezeUnfreeze.getShortcutIntent(context, this);\n    }\n\n    public static final Creator<FreezeUnfreezeShortcutInfo> CREATOR = new Creator<FreezeUnfreezeShortcutInfo>() {\n        @Override\n        public FreezeUnfreezeShortcutInfo createFromParcel(Parcel source) {\n            return new FreezeUnfreezeShortcutInfo(source);\n        }\n\n        @Override\n        public FreezeUnfreezeShortcutInfo[] newArray(int size) {\n            return new FreezeUnfreezeShortcutInfo[size];\n        }\n    };\n}"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/apk/dexopt/DexOptDialog.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.apk.dexopt;\n\nimport android.app.Dialog;\nimport android.content.Intent;\nimport android.os.Build;\nimport android.os.Bundle;\nimport android.text.Editable;\nimport android.text.TextUtils;\nimport android.view.View;\nimport android.widget.AutoCompleteTextView;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.core.content.ContextCompat;\nimport androidx.fragment.app.DialogFragment;\n\nimport com.google.android.material.checkbox.MaterialCheckBox;\nimport com.google.android.material.dialog.MaterialAlertDialogBuilder;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.batchops.BatchOpsManager;\nimport io.github.muntashirakon.AppManager.batchops.BatchOpsService;\nimport io.github.muntashirakon.AppManager.batchops.BatchQueueItem;\nimport io.github.muntashirakon.AppManager.batchops.struct.BatchDexOptOptions;\nimport io.github.muntashirakon.AppManager.settings.Ops;\nimport io.github.muntashirakon.AppManager.users.Users;\nimport io.github.muntashirakon.adapters.AnyFilterArrayAdapter;\n\npublic class DexOptDialog extends DialogFragment {\n    public static final String TAG = DexOptDialog.class.getSimpleName();\n\n    private static final String ARG_PACKAGES = \"pkg\";\n\n    @NonNull\n    public static DexOptDialog getInstance(@Nullable String[] packages) {\n        DexOptDialog dialog = new DexOptDialog();\n        Bundle args = new Bundle();\n        args.putStringArray(ARG_PACKAGES, packages);\n        dialog.setArguments(args);\n        return dialog;\n    }\n\n    private static final List<String> COMPILER_FILTERS = new ArrayList<String>() {{\n        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {\n            add(\"verify-none\"); // = assume-verified\n            add(\"verify-at-runtime\"); // = extract\n            add(\"verify-profile\"); // = verify\n            add(\"interpret-only\"); // = quicken\n            add(\"time\"); // = space\n            add(\"balanced\"); // speed\n        } else {\n            add(\"assume-verified\");\n            add(\"extract\");\n            add(\"verify\");\n            add(\"quicken\");\n        }\n        add(\"space\");\n        add(\"space-profile\");\n        add(\"speed\");\n        add(\"speed-profile\");\n        add(\"everything\");\n        add(\"everything-profile\");\n    }};\n\n    private final DexOptOptions mOptions = DexOptOptions.getDefault();\n\n    @NonNull\n    @Override\n    public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {\n        mOptions.packages = requireArguments().getStringArray(ARG_PACKAGES);\n        int uid = Users.getSelfOrRemoteUid();\n        boolean isRootOrSystem = uid == Ops.SYSTEM_UID || uid == Ops.ROOT_UID;\n        // Inflate view\n        View view = View.inflate(requireContext(), R.layout.dialog_dexopt, null);\n        AutoCompleteTextView compilerFilterSelectionView = view.findViewById(R.id.compiler_filter);\n        MaterialCheckBox compileLayoutsCheck = view.findViewById(R.id.compile_layouts);\n        MaterialCheckBox clearProfileDataCheck = view.findViewById(R.id.clear_profile_data);\n        MaterialCheckBox checkProfilesCheck = view.findViewById(R.id.check_profiles);\n        MaterialCheckBox forceCompilationCheck = view.findViewById(R.id.force_compilation);\n        MaterialCheckBox forceDexOptCheck = view.findViewById(R.id.force_dexopt);\n        compilerFilterSelectionView.setText(mOptions.compilerFiler);\n        checkProfilesCheck.setChecked(mOptions.checkProfiles);\n        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q || Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {\n            // Compile layout options was introduced in Android 10 and removed in Android 12\n            compileLayoutsCheck.setVisibility(View.GONE);\n        }\n        if (!isRootOrSystem) {\n            // clearProfileData and forceDexOpt can only be run as root/system\n            clearProfileDataCheck.setVisibility(View.GONE);\n            forceDexOptCheck.setVisibility(View.GONE);\n        }\n\n        // Set listeners\n        compilerFilterSelectionView.setAdapter(new AnyFilterArrayAdapter<>(requireContext(), io.github.muntashirakon.ui.R.layout.auto_complete_dropdown_item,\n                COMPILER_FILTERS));\n        compileLayoutsCheck.setOnCheckedChangeListener((buttonView, isChecked) -> mOptions.compileLayouts = isChecked);\n        clearProfileDataCheck.setOnCheckedChangeListener((buttonView, isChecked) -> mOptions.clearProfileData = isChecked);\n        checkProfilesCheck.setOnCheckedChangeListener((buttonView, isChecked) -> mOptions.checkProfiles = isChecked);\n        forceCompilationCheck.setOnCheckedChangeListener((buttonView, isChecked) -> mOptions.forceCompilation = isChecked);\n        forceDexOptCheck.setOnCheckedChangeListener((buttonView, isChecked) -> mOptions.forceDexOpt = isChecked);\n        if (isRootOrSystem) {\n            forceDexOptCheck.setChecked(true);\n        }\n\n        return new MaterialAlertDialogBuilder(requireContext())\n                .setTitle(R.string.title_perform_runtime_optimization_to_apps)\n                .setView(view)\n                .setPositiveButton(R.string.action_run, (dialog, which) -> {\n                    Editable compilerFilterRaw = compilerFilterSelectionView.getText();\n                    if (TextUtils.isEmpty(compilerFilterRaw)) {\n                        return;\n                    }\n                    String compilerFiler = compilerFilterRaw.toString().trim();\n                    if (!COMPILER_FILTERS.contains(compilerFiler)) {\n                        // Invalid compiler filter\n                        return;\n                    }\n                    mOptions.compilerFiler = compilerFiler;\n                    launchOp();\n                })\n                .setNegativeButton(R.string.cancel, null)\n                .setNeutralButton(R.string.reset_to_default, (dialog, which) -> {\n                    mOptions.compilerFiler = DexOptOptions.getDefaultCompilerFilterForInstallation();\n                    mOptions.forceCompilation = true;\n                    mOptions.clearProfileData = true;\n                    launchOp();\n                })\n                .create();\n    }\n\n    private void launchOp() {\n        BatchDexOptOptions options = new BatchDexOptOptions(mOptions);\n        BatchQueueItem queueItem = BatchQueueItem.getBatchOpQueue(\n                BatchOpsManager.OP_DEXOPT, null, null, options);\n        Intent intent = BatchOpsService.getServiceIntent(requireContext(), queueItem);\n        ContextCompat.startForegroundService(requireContext(), intent);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/apk/dexopt/DexOptOptions.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.apk.dexopt;\n\nimport android.os.Parcel;\nimport android.os.Parcelable;\nimport android.os.SystemProperties;\nimport android.text.TextUtils;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport org.json.JSONException;\nimport org.json.JSONObject;\n\nimport io.github.muntashirakon.AppManager.history.IJsonSerializer;\nimport io.github.muntashirakon.AppManager.history.JsonDeserializer;\nimport io.github.muntashirakon.AppManager.utils.JSONUtils;\n\npublic class DexOptOptions implements Parcelable, IJsonSerializer {\n    @NonNull\n    public static DexOptOptions getDefault() {\n        DexOptOptions options = new DexOptOptions();\n        options.compilerFiler = getDefaultCompilerFilterForInstallation();\n        options.checkProfiles = SystemProperties.getBoolean(\"dalvik.vm.usejitprofiles\", false);\n        options.bootComplete = true;\n        return options;\n    }\n\n    @Nullable\n    public String[] packages;\n    @Nullable\n    public String compilerFiler;\n    public boolean compileLayouts;\n    public boolean clearProfileData;\n    public boolean checkProfiles;\n    public boolean bootComplete;\n    public boolean forceCompilation;\n    public boolean forceDexOpt;\n\n    private DexOptOptions() {\n    }\n\n    protected DexOptOptions(@NonNull Parcel in) {\n        packages = in.createStringArray();\n        compilerFiler = in.readString();\n        compileLayouts = in.readByte() != 0;\n        clearProfileData = in.readByte() != 0;\n        checkProfiles = in.readByte() != 0;\n        bootComplete = in.readByte() != 0;\n        forceCompilation = in.readByte() != 0;\n        forceDexOpt = in.readByte() != 0;\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        dest.writeStringArray(packages);\n        dest.writeString(compilerFiler);\n        dest.writeByte((byte) (compileLayouts ? 1 : 0));\n        dest.writeByte((byte) (clearProfileData ? 1 : 0));\n        dest.writeByte((byte) (checkProfiles ? 1 : 0));\n        dest.writeByte((byte) (bootComplete ? 1 : 0));\n        dest.writeByte((byte) (forceCompilation ? 1 : 0));\n        dest.writeByte((byte) (forceDexOpt ? 1 : 0));\n    }\n\n    protected DexOptOptions(@NonNull JSONObject jsonObject) throws JSONException {\n        packages = JSONUtils.getArray(String.class, jsonObject.optJSONArray(\"packages\"));\n        compilerFiler = jsonObject.getString(\"compiler_filter\");\n        compileLayouts = jsonObject.getBoolean(\"compile_layouts\");\n        clearProfileData = jsonObject.getBoolean(\"clear_profile_data\");\n        checkProfiles = jsonObject.getBoolean(\"check_profiles\");\n        bootComplete = jsonObject.getBoolean(\"boot_complete\");\n        forceCompilation = jsonObject.getBoolean(\"force_compilation\");\n        forceDexOpt = jsonObject.getBoolean(\"force_dex_opt\");\n    }\n\n    public static final JsonDeserializer.Creator<DexOptOptions> DESERIALIZER = DexOptOptions::new;\n\n    @NonNull\n    @Override\n    public JSONObject serializeToJson() throws JSONException {\n        JSONObject jsonObject = new JSONObject();\n        jsonObject.put(\"packages\", JSONUtils.getJSONArray(packages));\n        jsonObject.put(\"compiler_filer\", compilerFiler);\n        jsonObject.put(\"compile_layouts\", compileLayouts);\n        jsonObject.put(\"clear_profile_data\", clearProfileData);\n        jsonObject.put(\"check_profiles\", checkProfiles);\n        jsonObject.put(\"boot_complete\", bootComplete);\n        jsonObject.put(\"force_compilation\", forceCompilation);\n        jsonObject.put(\"force_dex_opt\", forceDexOpt);\n        return jsonObject;\n    }\n\n    @Override\n    public int describeContents() {\n        return 0;\n    }\n\n    public static final Creator<DexOptOptions> CREATOR = new Creator<DexOptOptions>() {\n        @NonNull\n        @Override\n        public DexOptOptions createFromParcel(@NonNull Parcel in) {\n            return new DexOptOptions(in);\n        }\n\n        @NonNull\n        @Override\n        public DexOptOptions[] newArray(int size) {\n            return new DexOptOptions[size];\n        }\n    };\n\n    @NonNull\n    static String getDefaultCompilerFilterForInstallation() {\n        String profile = SystemProperties.get(\"pm.dexopt.install\");\n        if (TextUtils.isEmpty(profile)) {\n            return \"speed\";\n        }\n        return profile;\n    }\n\n    @NonNull\n    static String getDefaultCompilerFilter() {\n        String profile = SystemProperties.get(\"dalvik.vm.dex2oat-filter\");\n        if (TextUtils.isEmpty(profile)) {\n            return \"speed\";\n        }\n        return profile;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/apk/dexopt/DexOptimizer.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.apk.dexopt;\n\nimport android.content.pm.IPackageManager;\nimport android.os.Build;\nimport android.os.RemoteException;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.RequiresApi;\n\nimport java.util.Objects;\n\nimport io.github.muntashirakon.AppManager.self.SelfPermissions;\n\n@RequiresApi(Build.VERSION_CODES.N)\npublic class DexOptimizer {\n    @NonNull\n    private final IPackageManager mPm;\n    private final String mPackageName;\n\n    @Nullable\n    private Exception mLastError;\n\n    public DexOptimizer(@NonNull IPackageManager pm, @NonNull String packageName) {\n        mPm = pm;\n        mPackageName = packageName;\n    }\n\n    @Nullable\n    public Exception getLastError() {\n        try {\n            return mLastError;\n        } finally {\n            mLastError = null;\n        }\n    }\n\n    @SuppressWarnings(\"deprecation\")\n    public boolean performDexOptMode(boolean checkProfiles, @NonNull String targetCompilerFilter, boolean force,\n                                     boolean bootComplete, @Nullable String splitName) {\n        try {\n            // Allowed for root/system/shell and installer app\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) {\n                return mPm.performDexOptMode(mPackageName, checkProfiles, targetCompilerFilter, force, bootComplete, splitName);\n            } else {\n                return mPm.performDexOptMode(mPackageName, checkProfiles, targetCompilerFilter, force);\n            }\n        } catch (RemoteException | SecurityException e) {\n            mLastError = e;\n        }\n        return false;\n    }\n\n    public boolean clearApplicationProfileData() {\n        try {\n            // Allowed for only root/system\n            mPm.clearApplicationProfileData(mPackageName);\n            return true;\n        } catch (RemoteException | SecurityException e) {\n            mLastError = e;\n        }\n        return false;\n    }\n\n    @SuppressWarnings(\"deprecation\")\n    @RequiresApi(Build.VERSION_CODES.Q)\n    public boolean compileLayouts() {\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {\n            // Removed again\n            return false;\n        }\n        try {\n            return mPm.compileLayouts(mPackageName);\n        } catch (RemoteException | SecurityException e) {\n            mLastError = e;\n        }\n        return false;\n    }\n\n    public boolean forceDexOpt() {\n        try {\n            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.UPSIDE_DOWN_CAKE\n                    && SelfPermissions.isSystemOrRoot()) {\n                // Allowed for only root/system\n                try {\n                    mPm.forceDexOpt(mPackageName);\n                    return true;\n                } catch (IllegalArgumentException e) {\n                    if (Objects.equals(e.getMessage(), \"reason -1 invalid\")) {\n                        // AOSP bug: https://github.com/MuntashirAkon/AppManager/issues/1131\n                        return forceDexOptUnprivileged();\n                    }\n                    // Other valid error\n                    throw e;\n                }\n            }\n            return forceDexOptUnprivileged();\n        } catch (RemoteException | SecurityException | IllegalArgumentException e) {\n            mLastError = e;\n        } catch (IllegalStateException e) {\n            String message = e.getMessage();\n            if (message != null && message.startsWith(\"Failed to dexopt: 0\")) {\n                // Skipped. This could be due to many reasons:\n                // 1. Package is android and does not need optimization\n                // 2. Package does not have code\n                return true;\n            }\n            mLastError = e;\n        }\n        return false;\n    }\n\n    private boolean forceDexOptUnprivileged() {\n        // forceDexOpt only applies certain set of configurations with performDexOptMode. So, it's possible to\n        // do the same using performDexOptMode in unprivileged mode\n        // https://android.googlesource.com/platform/frameworks/base/+/eb4af72f526c8351ad22322a635507a54c9ad1b8/services/core/java/com/android/server/pm/DexOptHelper.java#495\n        return performDexOptMode(false, DexOptOptions.getDefaultCompilerFilter(), true, true, null);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/apk/installer/ApkQueueItem.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.apk.installer;\n\nimport static io.github.muntashirakon.AppManager.apk.installer.SupportedAppStores.isAppStoreSupported;\n\nimport android.content.ContentResolver;\nimport android.content.Intent;\nimport android.content.pm.PackageInstaller;\nimport android.net.Uri;\nimport android.os.Build;\nimport android.os.Parcel;\nimport android.os.Parcelable;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.core.os.ParcelCompat;\n\nimport org.json.JSONException;\nimport org.json.JSONObject;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Objects;\n\nimport io.github.muntashirakon.AppManager.apk.ApkSource;\nimport io.github.muntashirakon.AppManager.history.IJsonSerializer;\nimport io.github.muntashirakon.AppManager.history.JsonDeserializer;\nimport io.github.muntashirakon.AppManager.intercept.IntentCompat;\nimport io.github.muntashirakon.AppManager.utils.ContextUtils;\nimport io.github.muntashirakon.AppManager.utils.ExUtils;\nimport io.github.muntashirakon.AppManager.utils.JSONUtils;\n\npublic class ApkQueueItem implements Parcelable, IJsonSerializer {\n    @NonNull\n    static List<ApkQueueItem> fromIntent(@NonNull Intent intent,\n                                         @Nullable String originatingPackage) {\n        List<ApkQueueItem> apkQueueItems = new ArrayList<>();\n        List<Uri> uris = IntentCompat.getDataUris(intent);\n        if (uris == null) {\n            return apkQueueItems;\n        }\n        ContentResolver cr = ContextUtils.getContext().getContentResolver();\n        String mimeType = intent.getType();\n        Uri originatingUri = IntentCompat.getParcelableExtra(intent, Intent.EXTRA_ORIGINATING_URI, Uri.class);\n        int takeFlags = intent.getFlags() & (Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);\n        for (Uri uri : uris) {\n            ApkQueueItem item;\n            if (\"package\".equals(uri.getScheme())) {\n                item = new ApkQueueItem(uri.getSchemeSpecificPart(), true);\n            } else { // file, content\n                item = new ApkQueueItem(ApkSource.getCachedApkSource(uri, mimeType));\n                item.mOriginatingUri = originatingUri;\n                item.mOriginatingPackage = originatingPackage;\n                if (takeFlags > 0) {\n                    ExUtils.exceptionAsIgnored(() -> cr.takePersistableUriPermission(uri, takeFlags));\n                }\n            }\n            apkQueueItems.add(item);\n        }\n        return apkQueueItems;\n    }\n\n    @NonNull\n    public static ApkQueueItem fromApkSource(@NonNull ApkSource apkSource) {\n        return new ApkQueueItem(apkSource.toCachedSource());\n    }\n\n    @Nullable\n    private String mPackageName;\n    @Nullable\n    private String mAppLabel;\n    private final boolean mInstallExisting;\n    @Nullable\n    private String mOriginatingPackage;\n    @Nullable\n    private Uri mOriginatingUri;\n    @Nullable\n    private ApkSource mApkSource;\n    @Nullable\n    private InstallerOptions mInstallerOptions;\n    @Nullable\n    private ArrayList<String> mSelectedSplits;\n\n    private ApkQueueItem(@NonNull String packageName, boolean installExisting) {\n        mPackageName = Objects.requireNonNull(packageName);\n        mInstallExisting = installExisting;\n        assert installExisting;\n    }\n\n    private ApkQueueItem(@NonNull ApkSource apkSource) {\n        mApkSource = Objects.requireNonNull(apkSource);\n        mInstallExisting = false;\n    }\n\n    protected ApkQueueItem(@NonNull Parcel in) {\n        mPackageName = in.readString();\n        mAppLabel = in.readString();\n        mInstallExisting = in.readByte() != 0;\n        mOriginatingPackage = in.readString();\n        mOriginatingUri = ParcelCompat.readParcelable(in, Uri.class.getClassLoader(), Uri.class);\n        mApkSource = ParcelCompat.readParcelable(in, ApkSource.class.getClassLoader(), ApkSource.class);\n        mInstallerOptions = ParcelCompat.readParcelable(in, InstallerOptions.class.getClassLoader(), InstallerOptions.class);\n        mSelectedSplits = new ArrayList<>();\n        in.readStringList(mSelectedSplits);\n    }\n\n    @Nullable\n    public String getPackageName() {\n        return mPackageName;\n    }\n\n    public void setPackageName(@Nullable String packageName) {\n        mPackageName = packageName;\n    }\n\n    public boolean isInstallExisting() {\n        return mInstallExisting;\n    }\n\n    @Nullable\n    public ApkSource getApkSource() {\n        return mApkSource;\n    }\n\n    public void setApkSource(@Nullable ApkSource apkSource) {\n        mApkSource = apkSource;\n    }\n\n    @Nullable\n    public InstallerOptions getInstallerOptions() {\n        return mInstallerOptions;\n    }\n\n    public void setInstallerOptions(@Nullable InstallerOptions installerOptions) {\n        if (installerOptions != null) {\n            installerOptions.setOriginatingPackage(mOriginatingPackage);\n            installerOptions.setOriginatingUri(mOriginatingUri);\n            // Set package source to PACKAGE_SOURCE_STORE if it's supported\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU\n                    && mOriginatingPackage != null\n                    && isAppStoreSupported(mOriginatingPackage)) {\n                installerOptions.setPackageSource(PackageInstaller.PACKAGE_SOURCE_STORE);\n            }\n        }\n        mInstallerOptions = installerOptions;\n    }\n\n    public void setSelectedSplits(@NonNull ArrayList<String> selectedSplits) {\n        mSelectedSplits = selectedSplits;\n    }\n\n    @Nullable\n    public ArrayList<String> getSelectedSplits() {\n        return mSelectedSplits;\n    }\n\n    @Nullable\n    public String getAppLabel() {\n        return mAppLabel;\n    }\n\n    public void setAppLabel(@Nullable String appLabel) {\n        mAppLabel = appLabel;\n    }\n\n    @Override\n    public int describeContents() {\n        return 0;\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        dest.writeString(mPackageName);\n        dest.writeString(mAppLabel);\n        dest.writeByte((byte) (mInstallExisting ? 1 : 0));\n        dest.writeString(mOriginatingPackage);\n        dest.writeParcelable(mOriginatingUri, flags);\n        dest.writeParcelable(mApkSource, flags);\n        dest.writeParcelable(mInstallerOptions, flags);\n        dest.writeStringList(mSelectedSplits);\n    }\n\n    protected ApkQueueItem(@NonNull JSONObject jsonObject) throws JSONException {\n        mPackageName = JSONUtils.optString(jsonObject, \"package_name\", null);\n        mAppLabel = JSONUtils.optString(jsonObject, \"app_label\", null);\n        mInstallExisting = jsonObject.optBoolean(\"install_existing\", false);\n        mOriginatingPackage = JSONUtils.optString(jsonObject, \"originating_package\", null);\n        String originatingUri = JSONUtils.optString(jsonObject, \"originating_uri\", null);\n        mOriginatingUri = originatingUri != null ? Uri.parse(originatingUri) : null;\n        JSONObject apkSource = jsonObject.optJSONObject(\"apk_source\");\n        mApkSource = apkSource != null ? ApkSource.DESERIALIZER.deserialize(apkSource) : null;\n        JSONObject installerOptions = jsonObject.optJSONObject(\"installer_options\");\n        mInstallerOptions = installerOptions != null ? InstallerOptions.DESERIALIZER.deserialize(installerOptions) : null;\n        mSelectedSplits = JSONUtils.getArray(jsonObject.optJSONArray(\"selected_splits\"));\n    }\n\n    @NonNull\n    @Override\n    public JSONObject serializeToJson() throws JSONException {\n        JSONObject jsonObject = new JSONObject();\n        jsonObject.put(\"package_name\", mPackageName);\n        jsonObject.put(\"app_label\", mAppLabel);\n        jsonObject.put(\"install_existing\", mInstallExisting);\n        jsonObject.put(\"originating_package\", mOriginatingPackage);\n        jsonObject.put(\"originating_uri\", mOriginatingUri != null ? mOriginatingUri.toString() : null);\n        jsonObject.put(\"apk_source\", mApkSource != null ? mApkSource.serializeToJson() : null);\n        jsonObject.put(\"installer_options\", mInstallerOptions != null ? mInstallerOptions.serializeToJson() : null);\n        jsonObject.put(\"selected_splits\", JSONUtils.getJSONArray(mSelectedSplits));\n        return jsonObject;\n    }\n\n    public static final JsonDeserializer.Creator<ApkQueueItem> DESERIALIZER = ApkQueueItem::new;\n\n    public static final Creator<ApkQueueItem> CREATOR = new Creator<ApkQueueItem>() {\n        @Override\n        @NonNull\n        public ApkQueueItem createFromParcel(@NonNull Parcel in) {\n            return new ApkQueueItem(in);\n        }\n\n        @Override\n        @NonNull\n        public ApkQueueItem[] newArray(int size) {\n            return new ApkQueueItem[size];\n        }\n    };\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/apk/installer/InstallerDialogFragment.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.apk.installer;\n\nimport android.app.Dialog;\nimport android.os.Bundle;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.appcompat.app.AlertDialog;\nimport androidx.fragment.app.DialogFragment;\n\nimport com.google.android.material.dialog.MaterialAlertDialogBuilder;\n\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.dialog.DialogTitleBuilder;\n\npublic class InstallerDialogFragment extends DialogFragment {\n    public static final String TAG = InstallerDialogFragment.class.getSimpleName();\n\n    public interface FragmentStartedCallback {\n        void onStart(@NonNull InstallerDialogFragment fragment, @NonNull AlertDialog dialog);\n    }\n\n    private FragmentStartedCallback mFragmentStartedCallback;\n    private View mDialogView;\n    private DialogTitleBuilder mTitleBuilder;\n\n    public void setFragmentStartedCallback(FragmentStartedCallback fragmentStartedCallback) {\n        mFragmentStartedCallback = fragmentStartedCallback;\n    }\n\n    @NonNull\n    @Override\n    public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {\n        mDialogView = View.inflate(requireContext(), R.layout.dialog_installer, null);\n        mTitleBuilder = new DialogTitleBuilder(requireContext());\n        View titleView = mTitleBuilder.build();\n        return new MaterialAlertDialogBuilder(requireContext())\n                .setCustomTitle(titleView)\n                .setView(mDialogView)\n                .setPositiveButton(\" \", null)\n                .setNegativeButton(\" \", null)\n                .setNeutralButton(\" \", null)\n                .setCancelable(false)\n                .create();\n    }\n\n    @Nullable\n    @Override\n    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {\n        return mDialogView;\n    }\n\n    @Override\n    public void onStart() {\n        super.onStart();\n        if (mFragmentStartedCallback != null) {\n            mFragmentStartedCallback.onStart(this, (AlertDialog) requireDialog());\n        }\n    }\n\n    public View getDialogView() {\n        return mDialogView;\n    }\n\n    public DialogTitleBuilder getTitleBuilder() {\n        return mTitleBuilder;\n    }\n}"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/apk/installer/InstallerDialogHelper.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.apk.installer;\n\nimport android.content.Context;\nimport android.graphics.drawable.Drawable;\nimport android.view.View;\nimport android.widget.Button;\nimport android.widget.TextView;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.StringRes;\nimport androidx.appcompat.app.AlertDialog;\nimport androidx.appcompat.widget.LinearLayoutCompat;\nimport androidx.fragment.app.Fragment;\nimport androidx.fragment.app.FragmentContainerView;\n\nimport com.google.android.material.textview.MaterialTextView;\n\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.dialog.DialogTitleBuilder;\n\npublic final class InstallerDialogHelper {\n    public interface OnClickButtonsListener {\n        void triggerInstall();\n\n        void triggerCancel();\n    }\n\n    private final Context mContext;\n    private final InstallerDialogFragment mFragment;\n    private final DialogTitleBuilder mTitleBuilder;\n    private final FragmentContainerView mFragmentContainer;\n    private final MaterialTextView mMessage;\n    private final LinearLayoutCompat mLayout;\n    private final int mFragmentId = R.id.fragment_container_view_tag;\n    private final AlertDialog mDialog;\n    private final Button mPositiveBtn;\n    private final Button mNegativeBtn;\n    private final Button mNeutralBtn;\n\n    public InstallerDialogHelper(@NonNull InstallerDialogFragment fragment, AlertDialog dialog) {\n        mContext = fragment.requireContext();\n        mFragment = fragment;\n        mDialog = dialog;\n        View view = mFragment.getDialogView();\n        mTitleBuilder = mFragment.getTitleBuilder();\n        mFragmentContainer = view.findViewById(mFragmentId);\n        mMessage = view.findViewById(R.id.message);\n        mLayout = view.findViewById(R.id.layout);\n        mPositiveBtn = mDialog.getButton(AlertDialog.BUTTON_POSITIVE);\n        mNegativeBtn = mDialog.getButton(AlertDialog.BUTTON_NEGATIVE);\n        mNeutralBtn = mDialog.getButton(AlertDialog.BUTTON_NEUTRAL);\n    }\n\n    public void initProgress(View.OnClickListener cancelListener) {\n        // Title section\n        mTitleBuilder.setTitle(R.string._undefined)\n                .setStartIcon(R.drawable.ic_get_app)\n                .setSubtitle(null)\n                .setEndIcon(null, null);\n        // Buttons\n        mPositiveBtn.setVisibility(View.GONE);\n        mNeutralBtn.setVisibility(View.GONE);\n        mNegativeBtn.setVisibility(View.VISIBLE);\n        mNegativeBtn.setText(R.string.cancel);\n        mNegativeBtn.setOnClickListener(cancelListener);\n        // Body\n        View v = View.inflate(mContext, R.layout.dialog_progress2, null);\n        TextView tv = v.findViewById(android.R.id.text1);\n        tv.setText(R.string.staging_apk_files);\n        mLayout.setVisibility(View.VISIBLE);\n        mLayout.removeAllViews();\n        mLayout.addView(v);\n        mMessage.setVisibility(View.GONE);\n        mFragmentContainer.setVisibility(View.GONE);\n    }\n\n    public void showParseFailedDialog(View.OnClickListener closeListener) {\n        // Title section\n        mTitleBuilder.setTitle(R.string._undefined)\n                .setStartIcon(R.drawable.ic_get_app)\n                .setSubtitle(null)\n                .setEndIcon(null, null);\n        // Buttons\n        mPositiveBtn.setVisibility(View.GONE);\n        mNeutralBtn.setVisibility(View.GONE);\n        mNegativeBtn.setVisibility(View.VISIBLE);\n        mNegativeBtn.setText(R.string.close);\n        mNegativeBtn.setOnClickListener(closeListener);\n        // Body\n        mLayout.setVisibility(View.GONE);\n        mMessage.setVisibility(View.VISIBLE);\n        mMessage.setText(R.string.failed_to_fetch_package_info);\n        mFragmentContainer.setVisibility(View.GONE);\n    }\n\n    public void onParseSuccess(CharSequence title, CharSequence subtitle, Drawable icon,\n                               @Nullable View.OnClickListener optionsClickListener) {\n        mTitleBuilder.setTitle(title)\n                .setStartIcon(icon)\n                .setSubtitle(subtitle);\n        if (optionsClickListener != null) {\n            mTitleBuilder.setEndIcon(R.drawable.ic_settings, optionsClickListener)\n                    .setEndIconContentDescription(R.string.installer_options);\n        } else mTitleBuilder.setEndIcon(null, null);\n    }\n\n    public void showWhatsNewDialog(@StringRes int installButtonRes, Fragment fragment,\n                                   @NonNull OnClickButtonsListener onClickButtonsListener,\n                                   @NonNull View.OnClickListener appInfoButtonListener) {\n        // Buttons\n        mNeutralBtn.setVisibility(View.VISIBLE);\n        mNeutralBtn.setText(R.string.app_info);\n        mNeutralBtn.setOnClickListener(appInfoButtonListener);\n        mPositiveBtn.setVisibility(View.VISIBLE);\n        mPositiveBtn.setText(installButtonRes);\n        mPositiveBtn.setOnClickListener(v -> onClickButtonsListener.triggerInstall());\n        mNegativeBtn.setVisibility(View.VISIBLE);\n        mNegativeBtn.setText(R.string.cancel);\n        mNegativeBtn.setOnClickListener(v -> onClickButtonsListener.triggerCancel());\n        // Body\n        mLayout.setVisibility(View.GONE);\n        mMessage.setVisibility(View.GONE);\n        mFragmentContainer.setVisibility(View.VISIBLE);\n        mFragment.getChildFragmentManager().beginTransaction().replace(mFragmentId, fragment).commit();\n    }\n\n    public void showInstallConfirmationDialog(@StringRes int installButtonRes,\n                                              @NonNull OnClickButtonsListener onClickButtonsListener,\n                                              @NonNull View.OnClickListener appInfoButtonListener) {\n        // Buttons\n        mNeutralBtn.setVisibility(View.VISIBLE);\n        mNeutralBtn.setText(R.string.app_info);\n        mNeutralBtn.setOnClickListener(appInfoButtonListener);\n        mPositiveBtn.setVisibility(View.VISIBLE);\n        mPositiveBtn.setText(installButtonRes);\n        mPositiveBtn.setOnClickListener(v -> onClickButtonsListener.triggerInstall());\n        mNegativeBtn.setVisibility(View.VISIBLE);\n        mNegativeBtn.setText(R.string.cancel);\n        mNegativeBtn.setOnClickListener(v -> onClickButtonsListener.triggerCancel());\n        // Body\n        mLayout.setVisibility(View.GONE);\n        mMessage.setVisibility(View.VISIBLE);\n        mMessage.setText(R.string.install_app_message);\n        mFragmentContainer.setVisibility(View.GONE);\n    }\n\n    public void showApkChooserDialog(@StringRes int installButtonRes, Fragment fragment,\n                                     @NonNull OnClickButtonsListener onClickButtonsListener,\n                                     @NonNull View.OnClickListener appInfoButtonListener) {\n        // Buttons\n        mNeutralBtn.setVisibility(View.VISIBLE);\n        mNeutralBtn.setText(R.string.app_info);\n        mNeutralBtn.setOnClickListener(appInfoButtonListener);\n        mPositiveBtn.setVisibility(View.VISIBLE);\n        mPositiveBtn.setText(installButtonRes);\n        mPositiveBtn.setOnClickListener(v -> onClickButtonsListener.triggerInstall());\n        mNegativeBtn.setVisibility(View.VISIBLE);\n        mNegativeBtn.setText(R.string.cancel);\n        mNegativeBtn.setOnClickListener(v -> onClickButtonsListener.triggerCancel());\n        // Body\n        mLayout.setVisibility(View.GONE);\n        mMessage.setVisibility(View.GONE);\n        mFragmentContainer.setVisibility(View.VISIBLE);\n        mFragment.getChildFragmentManager().beginTransaction().replace(mFragmentId, fragment).commit();\n    }\n\n    public void showDowngradeReinstallWarning(CharSequence msg,\n                                              @NonNull OnClickButtonsListener onClickButtonsListener,\n                                              @NonNull View.OnClickListener appInfoButtonListener) {\n        // Buttons\n        mNeutralBtn.setVisibility(View.VISIBLE);\n        mNeutralBtn.setText(R.string.app_info);\n        mNeutralBtn.setOnClickListener(appInfoButtonListener);\n        mPositiveBtn.setVisibility(View.VISIBLE);\n        mPositiveBtn.setText(R.string.yes);\n        mPositiveBtn.setOnClickListener(v -> onClickButtonsListener.triggerInstall());\n        mNegativeBtn.setVisibility(View.VISIBLE);\n        mNegativeBtn.setText(R.string.cancel);\n        mNegativeBtn.setOnClickListener(v -> onClickButtonsListener.triggerCancel());\n        // Body\n        mLayout.setVisibility(View.GONE);\n        mMessage.setVisibility(View.VISIBLE);\n        mMessage.setText(msg);\n        mFragmentContainer.setVisibility(View.GONE);\n    }\n\n    public void showSignatureMismatchReinstallWarning(CharSequence msg,\n                                                      @NonNull OnClickButtonsListener onClickButtonsListener,\n                                                      @NonNull View.OnClickListener installOnlyButtonListener,\n                                                      boolean isSystem) {\n        // Buttons\n        mNeutralBtn.setVisibility(View.VISIBLE);\n        mNeutralBtn.setText(R.string.only_install);\n        mNeutralBtn.setOnClickListener(installOnlyButtonListener);\n        mPositiveBtn.setVisibility(isSystem ? View.GONE : View.VISIBLE);\n        mPositiveBtn.setText(R.string.yes);\n        mPositiveBtn.setOnClickListener(v -> onClickButtonsListener.triggerInstall());\n        mNegativeBtn.setVisibility(View.VISIBLE);\n        mNegativeBtn.setText(R.string.cancel);\n        mNegativeBtn.setOnClickListener(v -> onClickButtonsListener.triggerCancel());\n        // Body\n        mLayout.setVisibility(View.GONE);\n        mMessage.setVisibility(View.VISIBLE);\n        mMessage.setText(msg);\n        mFragmentContainer.setVisibility(View.GONE);\n    }\n\n    public void showInstallProgressDialog(@Nullable View.OnClickListener backgroundButtonListener) {\n        // Disable installer options\n        mTitleBuilder.setEndIcon(null, null);\n        // Buttons\n        mNeutralBtn.setVisibility(View.GONE);\n        if (backgroundButtonListener != null) {\n            mPositiveBtn.setVisibility(View.VISIBLE);\n            mPositiveBtn.setText(R.string.background);\n            mPositiveBtn.setOnClickListener(backgroundButtonListener);\n        } else {\n            mPositiveBtn.setVisibility(View.GONE);\n        }\n        mNegativeBtn.setVisibility(View.GONE);\n        // Body\n        mLayout.setVisibility(View.VISIBLE);\n        View v = View.inflate(mContext, R.layout.dialog_progress2, null);\n        TextView tv = v.findViewById(android.R.id.text1);\n        tv.setText(R.string.install_in_progress);\n        mLayout.removeAllViews();\n        mLayout.addView(v);\n        mMessage.setVisibility(View.GONE);\n        mFragmentContainer.setVisibility(View.GONE);\n    }\n\n    public void showInstallFinishedDialog(CharSequence msg, @StringRes int cancelOrNextRes,\n                                          @NonNull View.OnClickListener cancelClickListener,\n                                          @Nullable View.OnClickListener openButtonClickListener,\n                                          @Nullable View.OnClickListener appInfoButtonClickListener) {\n        // Buttons\n        if (appInfoButtonClickListener != null) {\n            mNeutralBtn.setVisibility(View.VISIBLE);\n            mNeutralBtn.setText(R.string.app_info);\n            mNeutralBtn.setOnClickListener(appInfoButtonClickListener);\n        } else mNeutralBtn.setVisibility(View.GONE);\n        if (openButtonClickListener != null) {\n            mPositiveBtn.setVisibility(View.VISIBLE);\n            mPositiveBtn.setText(R.string.open);\n            mPositiveBtn.setOnClickListener(openButtonClickListener);\n        } else mPositiveBtn.setVisibility(View.GONE);\n        mNegativeBtn.setVisibility(View.VISIBLE);\n        mNegativeBtn.setText(cancelOrNextRes);\n        mNegativeBtn.setOnClickListener(cancelClickListener);\n        // Body\n        mLayout.setVisibility(View.GONE);\n        mMessage.setVisibility(View.VISIBLE);\n        mMessage.setText(msg);\n        mFragmentContainer.setVisibility(View.GONE);\n    }\n\n    public void dismiss() {\n        mDialog.dismiss();\n    }\n}"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/apk/installer/InstallerOptions.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.apk.installer;\n\nimport android.annotation.UserIdInt;\nimport android.content.pm.PackageManager;\nimport android.net.Uri;\nimport android.os.Build;\nimport android.os.Parcel;\nimport android.os.Parcelable;\nimport android.os.UserHandleHidden;\nimport android.text.TextUtils;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.core.os.ParcelCompat;\n\nimport org.json.JSONException;\nimport org.json.JSONObject;\n\nimport io.github.muntashirakon.AppManager.BuildConfig;\nimport io.github.muntashirakon.AppManager.history.IJsonSerializer;\nimport io.github.muntashirakon.AppManager.history.JsonDeserializer;\nimport io.github.muntashirakon.AppManager.settings.Prefs;\nimport io.github.muntashirakon.AppManager.utils.JSONUtils;\n\npublic class InstallerOptions implements Parcelable, IJsonSerializer {\n    @NonNull\n    public static InstallerOptions getDefault() {\n        return new InstallerOptions();\n    }\n\n    @UserIdInt\n    private int mUserId;\n    private int mInstallLocation;\n    @Nullable\n    private String mInstallerName;\n    @Nullable\n    private String mOriginatingPackage;\n    @Nullable\n    private Uri mOriginatingUri;\n    private boolean mSetOriginatingPackage;\n    private int mPackageSource;\n    private int mInstallScenario;\n    private boolean mRequestUpdateOwnership;\n    private boolean mDisableApkVerification;\n    private boolean mSignApkFiles;\n    private boolean mForceDexOpt;\n    private boolean mBlockTrackers;\n\n    private InstallerOptions() {\n        mUserId = UserHandleHidden.myUserId();\n        mInstallLocation = Prefs.Installer.getInstallLocation();\n        mInstallerName = Prefs.Installer.getInstallerPackageName();\n        mOriginatingPackage = null;\n        mOriginatingUri = null;\n        mSetOriginatingPackage = Prefs.Installer.isSetOriginatingPackage();\n        mPackageSource = Prefs.Installer.getPackageSource();\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {\n            // If the user is always installing apps in the background, we expect that the user does\n            // want to install an app quite fast.\n            mInstallScenario = Prefs.Installer.installInBackground()\n                    ? PackageManager.INSTALL_SCENARIO_BULK\n                    : PackageManager.INSTALL_SCENARIO_FAST;\n        }\n        mRequestUpdateOwnership = Prefs.Installer.requestUpdateOwnership();\n        mDisableApkVerification = Prefs.Installer.isDisableApkVerification();\n        mSignApkFiles = Prefs.Installer.canSignApk();\n        mForceDexOpt = Prefs.Installer.forceDexOpt();\n        mBlockTrackers = Prefs.Installer.blockTrackers();\n    }\n\n    protected InstallerOptions(@NonNull Parcel in) {\n        mUserId = in.readInt();\n        mInstallLocation = in.readInt();\n        mInstallerName = in.readString();\n        mOriginatingPackage = in.readString();\n        mOriginatingUri = ParcelCompat.readParcelable(in, Uri.class.getClassLoader(), Uri.class);\n        mSetOriginatingPackage = ParcelCompat.readBoolean(in);\n        mPackageSource = in.readInt();\n        mInstallScenario = in.readInt();\n        mRequestUpdateOwnership = ParcelCompat.readBoolean(in);\n        mDisableApkVerification = ParcelCompat.readBoolean(in);\n        mSignApkFiles = ParcelCompat.readBoolean(in);\n        mForceDexOpt = ParcelCompat.readBoolean(in);\n        mBlockTrackers = ParcelCompat.readBoolean(in);\n    }\n\n    public void copy(@NonNull InstallerOptions options) {\n        mUserId = options.mUserId;\n        mInstallLocation = options.mInstallLocation;\n        mInstallerName = options.mInstallerName;\n        mOriginatingPackage = options.mOriginatingPackage;\n        mOriginatingUri = options.mOriginatingUri;\n        mSetOriginatingPackage = options.mSetOriginatingPackage;\n        mPackageSource = options.mPackageSource;\n        mInstallScenario = options.mInstallScenario;\n        mRequestUpdateOwnership = options.mRequestUpdateOwnership;\n        mDisableApkVerification = options.mDisableApkVerification;\n        mSignApkFiles = options.mSignApkFiles;\n        mForceDexOpt = options.mForceDexOpt;\n        mBlockTrackers = options.mBlockTrackers;\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        dest.writeInt(mUserId);\n        dest.writeInt(mInstallLocation);\n        dest.writeString(mInstallerName);\n        dest.writeString(mOriginatingPackage);\n        dest.writeParcelable(mOriginatingUri, flags);\n        ParcelCompat.writeBoolean(dest, mSetOriginatingPackage);\n        dest.writeInt(mPackageSource);\n        dest.writeInt(mInstallScenario);\n        ParcelCompat.writeBoolean(dest, mRequestUpdateOwnership);\n        ParcelCompat.writeBoolean(dest, mDisableApkVerification);\n        ParcelCompat.writeBoolean(dest, mSignApkFiles);\n        ParcelCompat.writeBoolean(dest, mForceDexOpt);\n        ParcelCompat.writeBoolean(dest, mBlockTrackers);\n    }\n\n    protected InstallerOptions(@NonNull JSONObject jsonObject) throws JSONException {\n        mUserId = jsonObject.getInt(\"user_id\");\n        mInstallLocation = jsonObject.getInt(\"install_location\");\n        mInstallerName = JSONUtils.optString(jsonObject, \"installer_name\", null);\n        mOriginatingPackage = JSONUtils.optString(jsonObject, \"originating_package\");\n        String originatingUri = JSONUtils.optString(jsonObject, \"originating_uri\", null);\n        mOriginatingUri = originatingUri != null ? Uri.parse(originatingUri) : null;\n        mSetOriginatingPackage = jsonObject.optBoolean(\"set_originating_package\", Prefs.Installer.isSetOriginatingPackage());\n        mPackageSource = jsonObject.getInt(\"package_source\");\n        mInstallScenario = jsonObject.getInt(\"install_scenario\");\n        mRequestUpdateOwnership = jsonObject.getBoolean(\"request_update_ownership\");\n        mDisableApkVerification = jsonObject.getBoolean(\"disable_apk_verification\");\n        mSignApkFiles = jsonObject.getBoolean(\"sign_apk_files\");\n        mForceDexOpt = jsonObject.getBoolean(\"force_dex_opt\");\n        mBlockTrackers = jsonObject.getBoolean(\"block_trackers\");\n    }\n\n    @NonNull\n    @Override\n    public JSONObject serializeToJson() throws JSONException {\n        JSONObject jsonObject = new JSONObject();\n        jsonObject.put(\"user_id\", mUserId);\n        jsonObject.put(\"install_location\", mInstallLocation);\n        jsonObject.put(\"installer_name\", mInstallerName);\n        jsonObject.put(\"originating_package\", mOriginatingPackage);\n        jsonObject.put(\"originating_uri\", mOriginatingUri != null ? mOriginatingUri.toString() : null);\n        jsonObject.put(\"set_originating_package\", mSetOriginatingPackage);\n        jsonObject.put(\"package_source\", mPackageSource);\n        jsonObject.put(\"install_scenario\", mInstallScenario);\n        jsonObject.put(\"request_update_ownership\", mRequestUpdateOwnership);\n        jsonObject.put(\"disable_apk_verification\", mDisableApkVerification);\n        jsonObject.put(\"sign_apk_files\", mSignApkFiles);\n        jsonObject.put(\"force_dex_opt\", mForceDexOpt);\n        jsonObject.put(\"block_trackers\", mBlockTrackers);\n        return jsonObject;\n    }\n\n    public static final JsonDeserializer.Creator<InstallerOptions> DESERIALIZER = InstallerOptions::new;\n\n    @Override\n    public int describeContents() {\n        return 0;\n    }\n\n    public static final Creator<InstallerOptions> CREATOR = new Creator<InstallerOptions>() {\n        @Override\n        public InstallerOptions createFromParcel(@NonNull Parcel in) {\n            return new InstallerOptions(in);\n        }\n\n        @Override\n        @NonNull\n        public InstallerOptions[] newArray(int size) {\n            return new InstallerOptions[size];\n        }\n    };\n\n    @UserIdInt\n    public int getUserId() {\n        return mUserId;\n    }\n\n    public void setUserId(@UserIdInt int userId) {\n        mUserId = userId;\n    }\n\n    public int getInstallLocation() {\n        return mInstallLocation;\n    }\n\n    public void setInstallLocation(int installLocation) {\n        mInstallLocation = installLocation;\n    }\n\n    @NonNull\n    public String getInstallerName() {\n        return !TextUtils.isEmpty(mInstallerName) ? mInstallerName : BuildConfig.APPLICATION_ID;\n    }\n\n    public void setInstallerName(@Nullable String installerName) {\n        mInstallerName = installerName;\n    }\n\n    @Nullable\n    public String getOriginatingPackage() {\n        return mOriginatingPackage;\n    }\n\n    public void setOriginatingPackage(@Nullable String originatingPackage) {\n        mOriginatingPackage = originatingPackage;\n    }\n\n    @Nullable\n    public Uri getOriginatingUri() {\n        return mOriginatingUri;\n    }\n\n    public void setOriginatingUri(@Nullable Uri originatingUri) {\n        mOriginatingUri = originatingUri;\n    }\n\n    public boolean isSetOriginatingPackage() {\n        return mSetOriginatingPackage;\n    }\n\n    public void setSetOriginatingPackage(boolean setOriginatingPackage) {\n        mSetOriginatingPackage = setOriginatingPackage;\n    }\n\n    public int getPackageSource() {\n        return mPackageSource;\n    }\n\n    public void setPackageSource(int packageSource) {\n        mPackageSource = packageSource;\n    }\n\n    public int getInstallScenario() {\n        return mInstallScenario;\n    }\n\n    public void setInstallScenario(int installScenario) {\n        mInstallScenario = installScenario;\n    }\n\n    public boolean requestUpdateOwnership() {\n        return mRequestUpdateOwnership;\n    }\n\n    public void requestUpdateOwnership(boolean update) {\n        mRequestUpdateOwnership = update;\n    }\n\n    public boolean isDisableApkVerification() {\n        return mDisableApkVerification;\n    }\n\n    public void setDisableApkVerification(boolean disableApkVerification) {\n        mDisableApkVerification = disableApkVerification;\n    }\n\n    public boolean isSignApkFiles() {\n        return mSignApkFiles;\n    }\n\n    public void setSignApkFiles(boolean signApkFiles) {\n        mSignApkFiles = signApkFiles;\n    }\n\n    public boolean isForceDexOpt() {\n        return mForceDexOpt;\n    }\n\n    public void setForceDexOpt(boolean forceDexOpt) {\n        mForceDexOpt = forceDexOpt;\n    }\n\n    public boolean isBlockTrackers() {\n        return mBlockTrackers;\n    }\n\n    public void setBlockTrackers(boolean blockTrackers) {\n        mBlockTrackers = blockTrackers;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/apk/installer/InstallerOptionsFragment.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.apk.installer;\n\nimport static io.github.muntashirakon.AppManager.settings.InstallerPreferences.INSTALL_LOCATIONS;\nimport static io.github.muntashirakon.AppManager.settings.InstallerPreferences.INSTALL_LOCATION_NAMES;\nimport static io.github.muntashirakon.AppManager.settings.InstallerPreferences.PKG_SOURCES;\nimport static io.github.muntashirakon.AppManager.settings.InstallerPreferences.PKG_SOURCES_NAMES;\nimport static io.github.muntashirakon.AppManager.utils.UIUtils.getSecondaryText;\nimport static io.github.muntashirakon.AppManager.utils.UIUtils.getSmallerText;\n\nimport android.Manifest;\nimport android.app.Application;\nimport android.app.Dialog;\nimport android.content.DialogInterface;\nimport android.content.pm.PackageManager;\nimport android.os.Build;\nimport android.os.Bundle;\nimport android.os.UserHandleHidden;\nimport android.text.SpannableStringBuilder;\nimport android.text.TextUtils;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.ArrayAdapter;\nimport android.widget.EditText;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.core.os.BundleCompat;\nimport androidx.core.util.Pair;\nimport androidx.fragment.app.DialogFragment;\nimport androidx.lifecycle.AndroidViewModel;\nimport androidx.lifecycle.LiveData;\nimport androidx.lifecycle.MutableLiveData;\nimport androidx.lifecycle.ViewModelProvider;\n\nimport com.google.android.material.dialog.MaterialAlertDialogBuilder;\nimport com.google.android.material.materialswitch.MaterialSwitch;\nimport com.google.android.material.textfield.TextInputLayout;\n\nimport java.text.Collator;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\n\nimport io.github.muntashirakon.AppManager.BuildConfig;\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.compat.ManifestCompat;\nimport io.github.muntashirakon.AppManager.db.entity.App;\nimport io.github.muntashirakon.AppManager.db.utils.AppDb;\nimport io.github.muntashirakon.AppManager.self.SelfPermissions;\nimport io.github.muntashirakon.AppManager.settings.Prefs;\nimport io.github.muntashirakon.AppManager.users.UserInfo;\nimport io.github.muntashirakon.AppManager.users.Users;\nimport io.github.muntashirakon.AppManager.utils.PackageUtils;\nimport io.github.muntashirakon.AppManager.utils.ThreadUtils;\nimport io.github.muntashirakon.adapters.SelectedArrayAdapter;\nimport io.github.muntashirakon.dialog.SearchableSingleChoiceDialogBuilder;\nimport io.github.muntashirakon.dialog.TextInputDialogBuilder;\nimport io.github.muntashirakon.lifecycle.SingleLiveEvent;\nimport io.github.muntashirakon.view.TextInputLayoutCompat;\nimport io.github.muntashirakon.widget.MaterialSpinner;\n\npublic class InstallerOptionsFragment extends DialogFragment {\n    public static final String TAG = InstallerOptionsFragment.class.getSimpleName();\n\n    private static final String ARG_PACKAGE_NAME = \"pkg\";\n    private static final String ARG_TEST_ONLY_APP = \"test_only\";\n    private static final String ARG_REF_INSTALLER_OPTIONS = \"ref_opt\";\n\n    public interface OnClickListener {\n        void onClick(DialogInterface dialog, int which, @Nullable InstallerOptions options);\n    }\n\n    @NonNull\n    public static InstallerOptionsFragment getInstance(@Nullable String packageName,\n                                                       @Nullable Boolean isTestOnly,\n                                                       @NonNull InstallerOptions options,\n                                                       @Nullable OnClickListener clickListener) {\n        InstallerOptionsFragment dialog = new InstallerOptionsFragment();\n        Bundle args = new Bundle();\n        args.putString(ARG_PACKAGE_NAME, packageName);\n        if (isTestOnly != null) {\n            args.putBoolean(ARG_TEST_ONLY_APP, isTestOnly);\n        }\n        args.putParcelable(ARG_REF_INSTALLER_OPTIONS, options);\n        dialog.setArguments(args);\n        dialog.setOnClickListener(clickListener);\n        return dialog;\n    }\n\n    private InstallerOptionsViewModel mModel;\n    private View mDialogView;\n    private MaterialSpinner mUserSelectionSpinner;\n    private MaterialSpinner mInstallLocationSpinner;\n    private MaterialSpinner mPackageSourceSpinner;\n    private TextInputLayout mInstallerAppLayout;\n    private EditText mInstallerAppField;\n    private MaterialSwitch mBlockTrackersSwitch;\n    @Nullable\n    private OnClickListener mClickListener;\n    private String mPackageName;\n    private boolean mIsTestOnly;\n    private InstallerOptions mOptions;\n    private PackageManager mPm;\n\n    public void setOnClickListener(@Nullable OnClickListener clickListener) {\n        this.mClickListener = clickListener;\n    }\n\n    @Override\n    public void onCreate(@Nullable Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        mModel = new ViewModelProvider(this).get(InstallerOptionsViewModel.class);\n    }\n\n    @NonNull\n    @Override\n    public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {\n        mPackageName = requireArguments().getString(ARG_PACKAGE_NAME);\n        mIsTestOnly = requireArguments().getBoolean(ARG_TEST_ONLY_APP, true);\n        mOptions = Objects.requireNonNull(BundleCompat.getParcelable(requireArguments(), ARG_REF_INSTALLER_OPTIONS, InstallerOptions.class));\n        mDialogView = View.inflate(requireActivity(), R.layout.dialog_installer_options, null);\n        mUserSelectionSpinner = mDialogView.findViewById(R.id.user);\n        mInstallLocationSpinner = mDialogView.findViewById(R.id.install_location);\n        mPackageSourceSpinner = mDialogView.findViewById(R.id.package_source);\n        mInstallerAppLayout = mDialogView.findViewById(R.id.installer);\n        mInstallerAppField = Objects.requireNonNull(mInstallerAppLayout.getEditText());\n        MaterialSwitch disableVerificationSwitch = mDialogView.findViewById(R.id.action_disable_verification);\n        MaterialSwitch setOriginSwitch = mDialogView.findViewById(R.id.action_set_origin);\n        MaterialSwitch reqUpdateOwnershipSwitch = mDialogView.findViewById(R.id.action_update_ownership);\n        MaterialSwitch signApkSwitch = mDialogView.findViewById(R.id.action_sign_apk);\n        MaterialSwitch forceDexOptSwitch = mDialogView.findViewById(R.id.action_optimize);\n        mBlockTrackersSwitch = mDialogView.findViewById(R.id.action_block_trackers);\n        // Set values and defaults\n        mPm = requireContext().getPackageManager();\n        boolean canInstallForOtherUsers = SelfPermissions.checkSelfOrRemotePermission(ManifestCompat.permission.INTERACT_ACROSS_USERS_FULL);\n        int selectedUser = getSelectedUserId(canInstallForOtherUsers);\n        boolean canBlockTrackers = SelfPermissions.canModifyAppComponentStates(selectedUser, mPackageName, mIsTestOnly);\n        initUserSpinner(canInstallForOtherUsers);\n        initInstallLocationSpinner();\n        initPackageSourceSpinner();\n        initInstallerAppSpinner();\n        disableVerificationSwitch.setEnabled(SelfPermissions.isSystemOrRootOrShell());\n        disableVerificationSwitch.setChecked(mOptions.isDisableApkVerification());\n        disableVerificationSwitch.setOnCheckedChangeListener((buttonView, isChecked) -> mOptions.setDisableApkVerification(isChecked));\n        setOriginSwitch.setChecked(mOptions.isSetOriginatingPackage());\n        setOriginSwitch.setOnCheckedChangeListener((buttonView, isChecked) -> mOptions.setSetOriginatingPackage(isChecked));\n        reqUpdateOwnershipSwitch.setVisibility(Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE ? View.VISIBLE : View.GONE);\n        reqUpdateOwnershipSwitch.setChecked(mOptions.requestUpdateOwnership());\n        reqUpdateOwnershipSwitch.setOnCheckedChangeListener((buttonView, isChecked) -> mOptions.requestUpdateOwnership(isChecked));\n        signApkSwitch.setChecked(mOptions.isSignApkFiles());\n        signApkSwitch.setOnCheckedChangeListener((buttonView, isChecked) -> mOptions.setSignApkFiles(isChecked));\n        forceDexOptSwitch.setVisibility(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N ? View.VISIBLE : View.GONE);\n        forceDexOptSwitch.setChecked(mOptions.isForceDexOpt());\n        forceDexOptSwitch.setOnCheckedChangeListener((buttonView, isChecked) -> mOptions.setForceDexOpt(isChecked));\n        mBlockTrackersSwitch.setChecked(canBlockTrackers && mOptions.isBlockTrackers());\n        mBlockTrackersSwitch.setEnabled(canBlockTrackers);\n        mBlockTrackersSwitch.setOnCheckedChangeListener((buttonView, isChecked) -> mOptions.setBlockTrackers(isChecked));\n        return new MaterialAlertDialogBuilder(requireActivity())\n                .setTitle(R.string.installer_options)\n                .setView(mDialogView)\n                .setCancelable(false)\n                .setPositiveButton(R.string.ok, (dialog, which) -> {\n                    if (mClickListener != null) {\n                        mClickListener.onClick(dialog, which, mOptions);\n                    }\n                })\n                .setNegativeButton(R.string.cancel, (dialog, which) -> {\n                    if (mClickListener != null) {\n                        mClickListener.onClick(dialog, which, null);\n                    }\n                })\n                .create();\n    }\n\n    @Nullable\n    @Override\n    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {\n        return mDialogView;\n    }\n\n    @Override\n    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {\n        super.onViewCreated(view, savedInstanceState);\n        mModel.getPackageNameLabelPairLiveData().observe(getViewLifecycleOwner(), this::displayInstallerAppSelectionDialog);\n    }\n\n    private int getSelectedUserId(boolean canInstallForOtherUsers) {\n        return canInstallForOtherUsers ? mOptions.getUserId() : UserHandleHidden.myUserId();\n    }\n\n    private void initUserSpinner(boolean canInstallForOtherUsers) {\n        int selectedUser = getSelectedUserId(canInstallForOtherUsers);\n        List<UserInfo> userInfoList = Users.getUsers();\n        CharSequence[] userNames = new String[userInfoList.size() + 1];\n        Integer[] userIds = new Integer[userInfoList.size() + 1];\n        userNames[0] = getString(R.string.backup_all_users);\n        userIds[0] = UserHandleHidden.USER_ALL;\n        int i = 1;\n        int selectedUserPosition = 0;\n        for (UserInfo info : userInfoList) {\n            userNames[i] = info.toLocalizedString(requireContext());\n            userIds[i] = info.id;\n            if (selectedUser == info.id) {\n                selectedUserPosition = i;\n            }\n            ++i;\n        }\n        ArrayAdapter<CharSequence> userAdapter = new SelectedArrayAdapter<>(requireContext(),\n                io.github.muntashirakon.ui.R.layout.auto_complete_dropdown_item_small, userNames);\n        mUserSelectionSpinner.setAdapter(userAdapter);\n        mUserSelectionSpinner.setSelection(selectedUserPosition);\n        mUserSelectionSpinner.setOnItemClickListener((parent, view, position, id) -> {\n            mOptions.setUserId(userIds[position]);\n            // Update block trackers option\n            boolean canBlockTrackers = SelfPermissions.canModifyAppComponentStates(selectedUser, mPackageName, mIsTestOnly);\n            mBlockTrackersSwitch.setChecked(canBlockTrackers && mOptions.isBlockTrackers());\n            mBlockTrackersSwitch.setEnabled(canBlockTrackers);\n        });\n        mUserSelectionSpinner.setEnabled(canInstallForOtherUsers);\n    }\n\n    private void initInstallLocationSpinner() {\n        int installLocation = mOptions.getInstallLocation();\n        int installLocationPosition = installLocation;\n        CharSequence[] installLocationNames = new CharSequence[INSTALL_LOCATIONS.length];\n        for (int i = 0; i < INSTALL_LOCATIONS.length; ++i) {\n            installLocationNames[i] = getString(INSTALL_LOCATION_NAMES[i]);\n            if (INSTALL_LOCATIONS[i] == installLocation) {\n                installLocationPosition = i;\n            }\n        }\n        ArrayAdapter<CharSequence> installerLocationAdapter = new SelectedArrayAdapter<>(requireContext(),\n                io.github.muntashirakon.ui.R.layout.auto_complete_dropdown_item_small, installLocationNames);\n        mInstallLocationSpinner.setAdapter(installerLocationAdapter);\n        mInstallLocationSpinner.setSelection(installLocationPosition);\n        mInstallLocationSpinner.setOnItemClickListener((parent, view, position, id) ->\n                mOptions.setInstallLocation(INSTALL_LOCATIONS[position]));\n    }\n\n    private void initPackageSourceSpinner() {\n        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {\n            mPackageSourceSpinner.setVisibility(View.GONE);\n            return;\n        }\n        int pkgSource = mOptions.getPackageSource();\n        CharSequence[] pkgSourceTexts = new CharSequence[PKG_SOURCES_NAMES.length];\n        for (int i = 0; i < PKG_SOURCES_NAMES.length; ++i) {\n            pkgSourceTexts[i] = getString(PKG_SOURCES_NAMES[i]);\n        }\n        ArrayAdapter<CharSequence> pkgSourceAdapter = new SelectedArrayAdapter<>(requireContext(),\n                io.github.muntashirakon.ui.R.layout.auto_complete_dropdown_item_small, pkgSourceTexts);\n        mPackageSourceSpinner.setAdapter(pkgSourceAdapter);\n        mPackageSourceSpinner.setSelection(pkgSource);\n        mPackageSourceSpinner.setOnItemClickListener((parent, view, position, id) ->\n                mOptions.setInstallLocation(PKG_SOURCES[position]));\n    }\n\n    private void initInstallerAppSpinner() {\n        boolean canInstallApps = SelfPermissions.checkSelfOrRemotePermission(Manifest.permission.INSTALL_PACKAGES);\n        String installer = canInstallApps ? mOptions.getInstallerName() : BuildConfig.APPLICATION_ID;\n        mInstallerAppField.setText(PackageUtils.getPackageLabel(mPm, installer));\n        TextInputLayoutCompat.fixEndIcon(mInstallerAppLayout);\n        mInstallerAppLayout.setEnabled(canInstallApps);\n        mInstallerAppLayout.setEndIconOnClickListener(view -> new MaterialAlertDialogBuilder(requireActivity())\n                .setTitle(R.string.installer_app)\n                .setMessage(R.string.installer_app_message)\n                .setPositiveButton(R.string.choose, (dialog1, which1) -> mModel.loadPackageNameLabelPair())\n                .setNegativeButton(R.string.specify_custom_name, (dialog, which) ->\n                        new TextInputDialogBuilder(requireActivity(), R.string.installer_app)\n                                .setTitle(R.string.installer_app)\n                                .setInputText(mOptions.getInstallerName())\n                                .setPositiveButton(R.string.ok, (dialog1, which1, inputText, isChecked) -> {\n                                    if (inputText == null) return;\n                                    String installerApp = inputText.toString().trim();\n                                    if (!TextUtils.isEmpty(installerApp)) {\n                                        mOptions.setInstallerName(installerApp);\n                                        mInstallerAppField.setText(PackageUtils.getPackageLabel(mPm, installerApp));\n                                    }\n                                })\n                                .setNegativeButton(R.string.cancel, null)\n                                .show())\n                .setNeutralButton(R.string.reset_to_default, (dialog, which) -> {\n                    String installerApp = Prefs.Installer.getInstallerPackageName();\n                    mOptions.setInstallerName(installerApp);\n                    mInstallerAppField.setText(PackageUtils.getPackageLabel(mPm, installerApp));\n                })\n                .show());\n    }\n\n    public void displayInstallerAppSelectionDialog(@NonNull List<Pair<String, CharSequence>> appInfo) {\n        ArrayList<String> items = new ArrayList<>(appInfo.size());\n        ArrayList<CharSequence> itemNames = new ArrayList<>(appInfo.size());\n        for (Pair<String, CharSequence> pair : appInfo) {\n            items.add(pair.first);\n            itemNames.add(new SpannableStringBuilder(pair.second)\n                    .append(\"\\n\")\n                    .append(getSecondaryText(requireContext(), getSmallerText(pair.first))));\n        }\n        new SearchableSingleChoiceDialogBuilder<>(requireActivity(), items, itemNames)\n                .setTitle(R.string.installer_app)\n                .setSelection(mOptions.getInstallerName())\n                .setPositiveButton(R.string.save, (dialog, which, selectedInstallerApp) -> {\n                    if (selectedInstallerApp != null) {\n                        String installerApp = selectedInstallerApp.trim();\n                        if (!TextUtils.isEmpty(installerApp)) {\n                            mOptions.setInstallerName(installerApp);\n                            mInstallerAppField.setText(PackageUtils.getPackageLabel(mPm, installerApp));\n                        }\n                    }\n                })\n                .setNegativeButton(R.string.cancel, null)\n                .show();\n    }\n\n    public static class InstallerOptionsViewModel extends AndroidViewModel {\n        private final MutableLiveData<List<Pair<String, CharSequence>>> mPackageNameLabelPairLiveData = new SingleLiveEvent<>();\n\n        public InstallerOptionsViewModel(@NonNull Application application) {\n            super(application);\n        }\n\n        public LiveData<List<Pair<String, CharSequence>>> getPackageNameLabelPairLiveData() {\n            return mPackageNameLabelPairLiveData;\n        }\n\n        public void loadPackageNameLabelPair() {\n            ThreadUtils.postOnBackgroundThread(() -> {\n                List<App> appList = new AppDb().getAllApplications();\n                Map<String, CharSequence> packageNameLabelMap = new HashMap<>(appList.size());\n                for (App app : appList) {\n                    packageNameLabelMap.put(app.packageName, app.packageLabel);\n                }\n                List<Pair<String, CharSequence>> appInfo = new ArrayList<>();\n                for (String packageName : packageNameLabelMap.keySet()) {\n                    appInfo.add(new Pair<>(packageName, packageNameLabelMap.get(packageName)));\n                }\n                Collator collator = Collator.getInstance();\n                Collections.sort(appInfo, (o1, o2) -> collator.compare(o1.second.toString(), o2.second.toString()));\n                mPackageNameLabelPairLiveData.postValue(appInfo);\n            });\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/apk/installer/PackageInstallerActivity.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.apk.installer;\n\nimport static io.github.muntashirakon.AppManager.apk.installer.PackageInstallerCompat.STATUS_FAILURE_ABORTED;\nimport static io.github.muntashirakon.AppManager.apk.installer.PackageInstallerCompat.STATUS_FAILURE_BLOCKED;\nimport static io.github.muntashirakon.AppManager.apk.installer.PackageInstallerCompat.STATUS_FAILURE_CONFLICT;\nimport static io.github.muntashirakon.AppManager.apk.installer.PackageInstallerCompat.STATUS_FAILURE_INCOMPATIBLE;\nimport static io.github.muntashirakon.AppManager.apk.installer.PackageInstallerCompat.STATUS_FAILURE_INCOMPATIBLE_ROM;\nimport static io.github.muntashirakon.AppManager.apk.installer.PackageInstallerCompat.STATUS_FAILURE_INVALID;\nimport static io.github.muntashirakon.AppManager.apk.installer.PackageInstallerCompat.STATUS_FAILURE_SECURITY;\nimport static io.github.muntashirakon.AppManager.apk.installer.PackageInstallerCompat.STATUS_FAILURE_SESSION_ABANDON;\nimport static io.github.muntashirakon.AppManager.apk.installer.PackageInstallerCompat.STATUS_FAILURE_SESSION_COMMIT;\nimport static io.github.muntashirakon.AppManager.apk.installer.PackageInstallerCompat.STATUS_FAILURE_SESSION_CREATE;\nimport static io.github.muntashirakon.AppManager.apk.installer.PackageInstallerCompat.STATUS_FAILURE_SESSION_WRITE;\nimport static io.github.muntashirakon.AppManager.apk.installer.PackageInstallerCompat.STATUS_FAILURE_STORAGE;\nimport static io.github.muntashirakon.AppManager.apk.installer.PackageInstallerCompat.STATUS_SUCCESS;\n\nimport android.Manifest;\nimport android.annotation.UserIdInt;\nimport android.content.ComponentName;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.ServiceConnection;\nimport android.content.pm.ApplicationInfo;\nimport android.content.pm.PackageInfo;\nimport android.content.pm.PackageInstaller;\nimport android.content.res.Resources;\nimport android.net.Uri;\nimport android.os.Bundle;\nimport android.os.IBinder;\nimport android.os.UserHandleHidden;\nimport android.text.SpannableStringBuilder;\nimport android.text.Spanned;\nimport android.text.style.RelativeSizeSpan;\nimport android.view.View;\n\nimport androidx.activity.result.ActivityResultLauncher;\nimport androidx.activity.result.contract.ActivityResultContracts;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.UiThread;\nimport androidx.appcompat.app.AlertDialog;\nimport androidx.core.content.ContextCompat;\nimport androidx.core.content.pm.PackageInfoCompat;\nimport androidx.lifecycle.ViewModelProvider;\n\nimport java.util.LinkedList;\nimport java.util.Objects;\nimport java.util.Queue;\n\nimport io.github.muntashirakon.AppManager.BaseActivity;\nimport io.github.muntashirakon.AppManager.BuildConfig;\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.accessibility.AccessibilityMultiplexer;\nimport io.github.muntashirakon.AppManager.apk.ApkSource;\nimport io.github.muntashirakon.AppManager.apk.CachedApkSource;\nimport io.github.muntashirakon.AppManager.apk.splitapk.SplitApkChooser;\nimport io.github.muntashirakon.AppManager.apk.whatsnew.WhatsNewFragment;\nimport io.github.muntashirakon.AppManager.compat.ApplicationInfoCompat;\nimport io.github.muntashirakon.AppManager.compat.PackageManagerCompat;\nimport io.github.muntashirakon.AppManager.details.AppDetailsActivity;\nimport io.github.muntashirakon.AppManager.intercept.IntentCompat;\nimport io.github.muntashirakon.AppManager.logs.Log;\nimport io.github.muntashirakon.AppManager.self.SelfPermissions;\nimport io.github.muntashirakon.AppManager.settings.Prefs;\nimport io.github.muntashirakon.AppManager.types.ForegroundService;\nimport io.github.muntashirakon.AppManager.utils.PackageUtils;\nimport io.github.muntashirakon.AppManager.utils.StoragePermission;\nimport io.github.muntashirakon.AppManager.utils.UIUtils;\nimport io.github.muntashirakon.AppManager.utils.Utils;\n\n/**\n * Activity that manages installing and confirming package installation. Actual installation is done by\n * {@link PackageInstallerService}.\n * <p>\n * How the installer works:\n * <ol>\n * <li>When the installation of a package is requested, it is either stored in queue or loaded directly if the queue is\n * empty.\n * <li>Then, it is checked whether there's an already installed package by the same name. If there exists any, the user\n * is offered to reinstall, upgrade or downgrade the package depending on the features supported by the present mode of\n * operation. Otherwise, the user is asked to confirm installation. Before doing so, however, a changelog may be\n * listed if it is enabled in settings.\n * <li>Next, if it is a split app, the user is asked to choose the splits to be installed. Otherwise, the installer\n * proceeds to the next phase directly.\n * <li>If display options is enabled, the options are displayed so that the user can tweak the present installer.\n * Otherwise, the installed proceeds to the next phase.\n * <li>Installer takes necessary steps to launch a installer service to initiate the installation.\n * </ol>\n */\npublic class PackageInstallerActivity extends BaseActivity implements InstallerDialogHelper.OnClickButtonsListener {\n    public static final String TAG = PackageInstallerActivity.class.getSimpleName();\n\n    @NonNull\n    public static Intent getLaunchableInstance(@NonNull Context context, @NonNull Uri uri) {\n        Intent intent = new Intent(context, PackageInstallerActivity.class);\n        intent.setData(uri);\n        return intent;\n    }\n\n    @NonNull\n    public static Intent getLaunchableInstance(@NonNull Context context, ApkSource apkSource) {\n        Intent intent = new Intent(context, PackageInstallerActivity.class);\n        IntentCompat.putWrappedParcelableExtra(intent, EXTRA_APK_FILE_LINK, apkSource);\n        return intent;\n    }\n\n    @NonNull\n    public static Intent getLaunchableInstance(@NonNull Context context, @NonNull String packageName) {\n        Intent intent = new Intent(context, PackageInstallerActivity.class);\n        intent.setData(Uri.parse(\"package:\" + packageName));\n        return intent;\n    }\n\n    private static final String EXTRA_APK_FILE_LINK = \"link\";\n    public static final String ACTION_PACKAGE_INSTALLED = BuildConfig.APPLICATION_ID + \".action.PACKAGE_INSTALLED\";\n\n    private int mSessionId = -1;\n    @Nullable\n    private ApkQueueItem mCurrentItem;\n    private String mPackageName;\n    /**\n     * Whether this activity is currently dealing with an apk\n     */\n    private boolean mIsDealingWithApk = false;\n    @UserIdInt\n    private int mLastUserId;\n    private InstallerDialogHelper mDialogHelper;\n    private PackageInstallerViewModel mModel;\n    @Nullable\n    private PackageInstallerService mService;\n    private InstallerDialogFragment mInstallerDialogFragment;\n    private boolean initiated = false;\n    private final View.OnClickListener mAppInfoClickListener = v -> {\n        assert mCurrentItem != null;\n        try {\n            ApkSource apkSource = mCurrentItem.getApkSource();\n            if (apkSource == null) {\n                apkSource = mModel.getApkSource();\n            }\n            Intent appDetailsIntent = AppDetailsActivity.getIntent(this, apkSource, true);\n            appDetailsIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);\n            startActivity(appDetailsIntent);\n        } finally {\n            // We cannot trigger cancel here because the cached file will be deleted\n            goToNext();\n        }\n    };\n    private final InstallerOptions mInstallerOptions = InstallerOptions.getDefault();\n    private final Queue<ApkQueueItem> mApkQueue = new LinkedList<>();\n    private final ActivityResultLauncher<Intent> mConfirmIntentLauncher = registerForActivityResult(\n            new ActivityResultContracts.StartActivityForResult(), result -> {\n                // User did some interaction and the installer screen is closed now\n                Intent broadcastIntent = new Intent(PackageInstallerCompat.ACTION_INSTALL_INTERACTION_END);\n                broadcastIntent.setPackage(getPackageName());\n                broadcastIntent.putExtra(PackageInstaller.EXTRA_PACKAGE_NAME, mPackageName);\n                broadcastIntent.putExtra(PackageInstaller.EXTRA_SESSION_ID, mSessionId);\n                getApplicationContext().sendBroadcast(broadcastIntent);\n                if (!hasNext() && !mIsDealingWithApk) {\n                    // No APKs left, this maybe a solo call\n                    finish();\n                } // else let the original activity decide what to do\n            });\n\n    private final AccessibilityMultiplexer mMultiplexer = AccessibilityMultiplexer.getInstance();\n    private final StoragePermission mStoragePermission = StoragePermission.init(this);\n    private final ServiceConnection mServiceConnection = new ServiceConnection() {\n        @Override\n        public void onServiceConnected(ComponentName name, IBinder service) {\n            mService = ((ForegroundService.Binder) service).getService();\n        }\n\n        @Override\n        public void onServiceDisconnected(ComponentName name) {\n            mService = null;\n        }\n    };\n\n    @Override\n    public boolean getTransparentBackground() {\n        return true;\n    }\n\n    @Override\n    protected void onAuthenticated(@Nullable Bundle savedInstanceState) {\n        final Intent intent = getIntent();\n        if (intent == null) {\n            triggerCancel();\n            return;\n        }\n        Log.d(TAG, \"On create, intent: %s\", intent);\n        if (ACTION_PACKAGE_INSTALLED.equals(intent.getAction())) {\n            onNewIntent(intent);\n            return;\n        }\n        mModel = new ViewModelProvider(this).get(PackageInstallerViewModel.class);\n        if (!bindService(\n                new Intent(this, PackageInstallerService.class), mServiceConnection, BIND_AUTO_CREATE)) {\n            throw new RuntimeException(\"Unable to bind PackageInstallerService\");\n        }\n        synchronized (mApkQueue) {\n            mApkQueue.addAll(ApkQueueItem.fromIntent(intent, Utils.getRealReferrer(this)));\n\n        }\n        ApkSource apkSource = IntentCompat.getUnwrappedParcelableExtra(intent, EXTRA_APK_FILE_LINK, ApkSource.class);\n        if (apkSource != null) {\n            synchronized (mApkQueue) {\n                mApkQueue.add(ApkQueueItem.fromApkSource(apkSource));\n            }\n        }\n        mModel.packageInfoLiveData().observe(this, newPackageInfo -> {\n            if (newPackageInfo == null) {\n                mDialogHelper.showParseFailedDialog(v -> triggerCancel());\n                return;\n            }\n            // TODO: Resolve dependencies\n            mDialogHelper.onParseSuccess(mModel.getAppLabel(), getVersionInfoWithTrackers(newPackageInfo),\n                    mModel.getAppIcon(), v -> displayInstallerOptions((dialog1, which, options) -> {\n                        if (options != null) {\n                            mInstallerOptions.copy(options);\n                        }\n                    }));\n            displayChangesOrInstallationPrompt();\n        });\n        mModel.packageUninstalledLiveData().observe(this, success -> {\n            if (success) {\n                install();\n            } else {\n                showInstallationFinishedDialog(mModel.getPackageName(), getString(R.string.failed_to_uninstall_app),\n                        null, false);\n            }\n        });\n        // Init fragment\n        mInstallerDialogFragment = new InstallerDialogFragment();\n        mInstallerDialogFragment.setCancelable(false);\n        mInstallerDialogFragment.setFragmentStartedCallback(this::init);\n        mInstallerDialogFragment.showNow(getSupportFragmentManager(), InstallerDialogFragment.TAG);\n    }\n\n    @Override\n    protected void onDestroy() {\n        if (mService != null) {\n            unbindService(mServiceConnection);\n        }\n        unsetInstallFinishedListener();\n        // Delete remaining cached file\n        if (mCurrentItem != null && (mCurrentItem.getApkSource() instanceof CachedApkSource)) {\n            ((CachedApkSource) mCurrentItem.getApkSource()).cleanup();\n        }\n        super.onDestroy();\n    }\n\n    private void init(@NonNull InstallerDialogFragment fragment, @NonNull AlertDialog dialog) {\n        // Make sure that it's only initiated once\n        if (initiated) {\n            return;\n        }\n        initiated = true;\n        mDialogHelper = new InstallerDialogHelper(fragment, dialog);\n        mDialogHelper.initProgress(v -> triggerCancel());\n        goToNext();\n    }\n\n    @UiThread\n    private void displayChangesOrInstallationPrompt() {\n        // This dialog either calls triggerInstall() or triggerCancel()\n        boolean displayChanges;\n        PackageInfo installedPackageInfo = mModel.getInstalledPackageInfo();\n        int actionRes;\n        if (installedPackageInfo == null) {\n            // App not installed or data not cleared\n            displayChanges = false;\n            actionRes = R.string.install;\n        } else {\n            // App is installed or the app is uninstalled without clearing data, or the app is uninstalled,\n            // but it's a system app\n            long installedVersionCode = PackageInfoCompat.getLongVersionCode(installedPackageInfo);\n            long thisVersionCode = PackageInfoCompat.getLongVersionCode(mModel.getNewPackageInfo());\n            displayChanges = Prefs.Installer.displayChanges();\n            if (installedVersionCode < thisVersionCode) {\n                // Needs update\n                actionRes = R.string.update;\n            } else if (installedVersionCode == thisVersionCode) {\n                // Issue reinstall\n                actionRes = R.string.reinstall;\n            } else {\n                // Downgrade\n                actionRes = R.string.downgrade;\n            }\n        }\n        if (displayChanges) {\n            WhatsNewFragment dialogFragment = WhatsNewFragment.getInstance(mModel.getNewPackageInfo(),\n                    mModel.getInstalledPackageInfo());\n            mDialogHelper.showWhatsNewDialog(actionRes, dialogFragment, new InstallerDialogHelper.OnClickButtonsListener() {\n                @Override\n                public void triggerInstall() {\n                    displayInstallationPrompt(actionRes, true);\n                }\n\n                @Override\n                public void triggerCancel() {\n                    PackageInstallerActivity.this.triggerCancel();\n                }\n            }, mAppInfoClickListener);\n            return;\n        }\n        displayInstallationPrompt(actionRes, false);\n    }\n\n    private void displayInstallationPrompt(int actionRes, boolean splitOnly) {\n        if (mModel.getApkFile().isSplit()) {\n            SplitApkChooser fragment = SplitApkChooser.getNewInstance(getVersionInfoWithTrackers(\n                    mModel.getNewPackageInfo()), getString(actionRes));\n            mDialogHelper.showApkChooserDialog(actionRes, fragment, this, mAppInfoClickListener);\n            return;\n        }\n        if (!splitOnly) {\n            // In unprivileged mode, a dialog is generated by the system. But we need to display it nonetheless in order\n            // to provide additional features.\n            mDialogHelper.showInstallConfirmationDialog(actionRes, this, mAppInfoClickListener);\n        } else triggerInstall();\n    }\n\n    private void displayInstallerOptions(InstallerOptionsFragment.OnClickListener clickListener) {\n        PackageInfo packageInfo = mModel.getNewPackageInfo();\n        InstallerOptionsFragment dialog = InstallerOptionsFragment.getInstance(packageInfo.packageName,\n                ApplicationInfoCompat.isTestOnly(packageInfo.applicationInfo), mInstallerOptions, clickListener);\n        dialog.show(getSupportFragmentManager(), InstallerOptionsFragment.TAG);\n    }\n\n    @Override\n    protected void onSaveInstanceState(@NonNull Bundle outState) {\n        outState.clear();\n        super.onSaveInstanceState(outState);\n    }\n\n    @UiThread\n    private void install() {\n        if (mModel.getApkFile().hasObb() && !SelfPermissions.checkSelfOrRemotePermission(Manifest.permission.INSTALL_PACKAGES)) {\n            // Need to request permissions if not given\n            mStoragePermission.request(granted -> {\n                if (granted) launchInstallerService();\n            });\n        } else launchInstallerService();\n    }\n\n    @UiThread\n    private void launchInstallerService() {\n        assert mCurrentItem != null;\n        int userId = mInstallerOptions.getUserId();\n        mCurrentItem.setInstallerOptions(mInstallerOptions);\n        mCurrentItem.setSelectedSplits(mModel.getSelectedSplitsForInstallation());\n        mLastUserId = userId == UserHandleHidden.USER_ALL ? UserHandleHidden.myUserId() : userId;\n        boolean canDisplayNotification = Utils.canDisplayNotification(this);\n        boolean alwaysOnBackground = canDisplayNotification && Prefs.Installer.installInBackground();\n        Intent intent = new Intent(this, PackageInstallerService.class);\n        IntentCompat.putWrappedParcelableExtra(intent, PackageInstallerService.EXTRA_QUEUE_ITEM, mCurrentItem);\n        if (!SelfPermissions.checkSelfOrRemotePermission(Manifest.permission.INSTALL_PACKAGES)) {\n            // For unprivileged mode, use accessibility service if enabled\n            mMultiplexer.enableInstall(true);\n        }\n        ContextCompat.startForegroundService(this, intent);\n        if (!alwaysOnBackground && mService != null) {\n            setInstallFinishedListener();\n            mDialogHelper.showInstallProgressDialog(canDisplayNotification ? v -> {\n                unsetInstallFinishedListener();\n                goToNext();\n            } : null);\n        } else {\n            unsetInstallFinishedListener();\n            // For some reason, the service is empty\n            // Install next app instead\n            goToNext();\n        }\n    }\n\n    @Override\n    protected void onNewIntent(Intent intent) {\n        super.onNewIntent(intent);\n        Log.d(TAG, \"New intent called: %s\", intent);\n        setIntent(intent);\n        // Check for action first\n        if (ACTION_PACKAGE_INSTALLED.equals(intent.getAction())) {\n            mSessionId = intent.getIntExtra(PackageInstaller.EXTRA_SESSION_ID, -1);\n            mPackageName = intent.getStringExtra(PackageInstaller.EXTRA_PACKAGE_NAME);\n            Intent confirmIntent = IntentCompat.getParcelableExtra(intent, Intent.EXTRA_INTENT, Intent.class);\n            try {\n                if (mPackageName == null || confirmIntent == null) throw new Exception(\"Empty confirmation intent.\");\n                Log.d(TAG, \"Requesting user confirmation for package %s\", mPackageName);\n                mConfirmIntentLauncher.launch(confirmIntent);\n            } catch (Exception e) {\n                e.printStackTrace();\n                PackageInstallerCompat.sendCompletedBroadcast(this, mPackageName, PackageInstallerCompat.STATUS_FAILURE_INCOMPATIBLE_ROM, mSessionId);\n                if (!hasNext() && !mIsDealingWithApk) {\n                    // No APKs left, this maybe a solo call\n                    finish();\n                } // else let the original activity decide what to do\n            }\n            return;\n        }\n        // New APK files added\n        synchronized (mApkQueue) {\n            mApkQueue.addAll(ApkQueueItem.fromIntent(intent, Utils.getRealReferrer(this)));\n        }\n        UIUtils.displayShortToast(R.string.added_to_queue);\n    }\n\n    @UiThread\n    @Override\n    public void triggerInstall() {\n        // Calls install(), reinstall() (which in terms called install()) and triggerCancel()\n        if (mModel.getInstalledPackageInfo() == null) {\n            // App not installed\n            install();\n            return;\n        }\n        InstallerDialogHelper.OnClickButtonsListener reinstallListener = new InstallerDialogHelper.OnClickButtonsListener() {\n            @Override\n            public void triggerInstall() {\n                // Uninstall and then install again\n                reinstall();\n            }\n\n            @Override\n            public void triggerCancel() {\n                PackageInstallerActivity.this.triggerCancel();\n            }\n        };\n        long installedVersionCode = PackageInfoCompat.getLongVersionCode(mModel.getInstalledPackageInfo());\n        long thisVersionCode = PackageInfoCompat.getLongVersionCode(mModel.getNewPackageInfo());\n        if (installedVersionCode > thisVersionCode && !SelfPermissions.checkSelfOrRemotePermission(Manifest.permission.INSTALL_PACKAGES)) {\n            // Need to uninstall and install again\n            SpannableStringBuilder builder = new SpannableStringBuilder()\n                    .append(getString(R.string.do_you_want_to_uninstall_and_install)).append(\" \")\n                    .append(UIUtils.getItalicString(getString(R.string.app_data_will_be_lost)))\n                    .append(\"\\n\\n\");\n            mDialogHelper.showDowngradeReinstallWarning(builder, reinstallListener, mAppInfoClickListener);\n            return;\n        }\n        if (!mModel.isSignatureDifferent()) {\n            // Signature is either matched or the app isn't installed\n            install();\n            return;\n        }\n        // Signature is different\n        ApplicationInfo info = mModel.getInstalledPackageInfo().applicationInfo;  // Installed package info is never null here.\n        boolean isSystem = ApplicationInfoCompat.isSystemApp(info);\n        SpannableStringBuilder builder = new SpannableStringBuilder();\n        if (isSystem) {\n            // Cannot reinstall a system app with a different signature\n            builder.append(getString(R.string.app_signing_signature_mismatch_for_system_apps));\n        } else {\n            // Offer user to uninstall and then install the app again\n            builder.append(getString(R.string.do_you_want_to_uninstall_and_install)).append(\" \")\n                    .append(UIUtils.getItalicString(getString(R.string.app_data_will_be_lost)));\n        }\n        builder.append(\"\\n\\n\");\n        int start = builder.length();\n        builder.append(getText(R.string.app_signing_install_without_data_loss));\n        builder.setSpan(new RelativeSizeSpan(0.8f), start, builder.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE);\n        mDialogHelper.showSignatureMismatchReinstallWarning(builder, reinstallListener, v -> install(), isSystem);\n    }\n\n    @Override\n    public void triggerCancel() {\n        // Run cleanup\n        if (mCurrentItem != null && mCurrentItem.getApkSource() instanceof CachedApkSource) {\n            ((CachedApkSource) mCurrentItem.getApkSource()).cleanup();\n        }\n        goToNext();\n    }\n\n    private void reinstall() {\n        if (!SelfPermissions.checkSelfOrRemotePermission(Manifest.permission.DELETE_PACKAGES)) {\n            mMultiplexer.enableUninstall(true);\n        }\n        mModel.uninstallPackage();\n    }\n\n    /**\n     * Closes the current APK and start the next\n     */\n    private void goToNext() {\n        mCurrentItem = null;\n        mMultiplexer.enableInstall(false);\n        mMultiplexer.enableUninstall(false);\n        if (hasNext()) {\n            mIsDealingWithApk = true;\n            mDialogHelper.initProgress(v -> goToNext());\n            synchronized (mApkQueue) {\n                mCurrentItem = Objects.requireNonNull(mApkQueue.poll());\n                mModel.getPackageInfo(mCurrentItem);\n            }\n        } else {\n            mIsDealingWithApk = false;\n            mDialogHelper.dismiss();\n            finish();\n        }\n    }\n\n    private boolean hasNext() {\n        synchronized (mApkQueue) {\n            return !mApkQueue.isEmpty();\n        }\n    }\n\n    @NonNull\n    private String getVersionInfoWithTrackers(@NonNull final PackageInfo newPackageInfo) {\n        Resources res = getApplication().getResources();\n        long newVersionCode = PackageInfoCompat.getLongVersionCode(newPackageInfo);\n        String newVersionName = newPackageInfo.versionName;\n        int trackers = mModel.getTrackerCount();\n        StringBuilder sb = new StringBuilder(res.getString(R.string.version_name_with_code, newVersionName, newVersionCode));\n        if (trackers > 0) {\n            sb.append(\", \").append(res.getQuantityString(R.plurals.no_of_trackers, trackers, trackers));\n        }\n        return sb.toString();\n    }\n\n    public void showInstallationFinishedDialog(String packageName, int result, @Nullable String blockingPackage,\n                                               @Nullable String statusMessage) {\n        showInstallationFinishedDialog(packageName, getStringFromStatus(result, blockingPackage), statusMessage,\n                result == STATUS_SUCCESS);\n    }\n\n    public void showInstallationFinishedDialog(String packageName, CharSequence message,\n                                               @Nullable String statusMessage, boolean displayOpenAndAppInfo) {\n        SpannableStringBuilder ssb = new SpannableStringBuilder(message);\n        if (statusMessage != null) {\n            ssb.append(\"\\n\\n\").append(UIUtils.getItalicString(statusMessage));\n        }\n        Intent intent = PackageManagerCompat.getLaunchIntentForPackage(packageName, UserHandleHidden.myUserId());\n        mDialogHelper.showInstallFinishedDialog(ssb, hasNext() ? R.string.next : R.string.close, v -> goToNext(),\n                displayOpenAndAppInfo && intent != null ? v -> {\n                    try {\n                        startActivity(intent);\n                    } catch (Throwable th) {\n                        UIUtils.displayLongToast(th.getMessage());\n                    } finally {\n                        goToNext();\n                    }\n                } : null, displayOpenAndAppInfo ? v -> {\n                    try {\n                        Intent appDetailsIntent = AppDetailsActivity.getIntent(this, packageName, mLastUserId, true);\n                        appDetailsIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);\n                        startActivity(appDetailsIntent);\n                    } finally {\n                        goToNext();\n                    }\n                } : null);\n    }\n\n    @NonNull\n    private String getStringFromStatus(@PackageInstallerCompat.Status int status,\n                                       @Nullable String blockingPackage) {\n        switch (status) {\n            case STATUS_SUCCESS:\n                return getString(R.string.installer_app_installed);\n            case STATUS_FAILURE_ABORTED:\n                return getString(R.string.installer_error_aborted);\n            case STATUS_FAILURE_BLOCKED:\n                String blocker = getString(R.string.installer_error_blocked_device);\n                if (blockingPackage != null) {\n                    blocker = PackageUtils.getPackageLabel(getPackageManager(), blockingPackage);\n                }\n                return getString(R.string.installer_error_blocked, blocker);\n            case STATUS_FAILURE_CONFLICT:\n                return getString(R.string.installer_error_conflict);\n            case STATUS_FAILURE_INCOMPATIBLE:\n                return getString(R.string.installer_error_incompatible);\n            case STATUS_FAILURE_INVALID:\n                return getString(R.string.installer_error_bad_apks);\n            case STATUS_FAILURE_STORAGE:\n                return getString(R.string.installer_error_storage);\n            case STATUS_FAILURE_SECURITY:\n                return getString(R.string.installer_error_security);\n            case STATUS_FAILURE_SESSION_CREATE:\n                return getString(R.string.installer_error_session_create);\n            case STATUS_FAILURE_SESSION_WRITE:\n                return getString(R.string.installer_error_session_write);\n            case STATUS_FAILURE_SESSION_COMMIT:\n                return getString(R.string.installer_error_session_commit);\n            case STATUS_FAILURE_SESSION_ABANDON:\n                return getString(R.string.installer_error_session_abandon);\n            case STATUS_FAILURE_INCOMPATIBLE_ROM:\n                return getString(R.string.installer_error_lidl_rom);\n        }\n        return getString(R.string.installer_error_generic);\n    }\n\n    public void setInstallFinishedListener() {\n        if (mService != null) {\n            mService.setOnInstallFinished((packageName, status, blockingPackage, statusMessage) -> {\n                if (isFinishing()) return;\n                showInstallationFinishedDialog(packageName, status, blockingPackage, statusMessage);\n            });\n        }\n    }\n\n    public void unsetInstallFinishedListener() {\n        if (mService != null) {\n            mService.setOnInstallFinished(null);\n        }\n    }\n}\n\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/apk/installer/PackageInstallerBroadcastReceiver.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.apk.installer;\n\nimport android.app.Notification;\nimport android.app.PendingIntent;\nimport android.content.BroadcastReceiver;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.pm.PackageInstaller;\n\nimport androidx.annotation.NonNull;\nimport androidx.core.app.PendingIntentCompat;\n\nimport io.github.muntashirakon.AppManager.BuildConfig;\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.intercept.IntentCompat;\nimport io.github.muntashirakon.AppManager.logs.Log;\nimport io.github.muntashirakon.AppManager.utils.ContextUtils;\nimport io.github.muntashirakon.AppManager.utils.NotificationUtils;\nimport io.github.muntashirakon.AppManager.utils.Utils;\n\nclass PackageInstallerBroadcastReceiver extends BroadcastReceiver {\n    public static final String TAG = PackageInstallerBroadcastReceiver.class.getSimpleName();\n    public static final String ACTION_PI_RECEIVER = BuildConfig.APPLICATION_ID + \".action.PI_RECEIVER\";\n\n    private String mPackageName;\n    private CharSequence mAppLabel;\n    private int mConfirmNotificationId = 0;\n\n    public void setPackageName(String packageName) {\n        mPackageName = packageName;\n    }\n\n    public void setAppLabel(CharSequence appLabel) {\n        mAppLabel = appLabel;\n    }\n\n    @Override\n    public void onReceive(Context nullableContext, @NonNull Intent intent) {\n        Context context = nullableContext != null ? nullableContext : ContextUtils.getContext();\n        int status = intent.getIntExtra(PackageInstaller.EXTRA_STATUS, -1);\n        int sessionId = intent.getIntExtra(PackageInstaller.EXTRA_SESSION_ID, -1);\n        Log.d(TAG, \"Session ID: %d\", sessionId);\n        switch (status) {\n            case PackageInstaller.STATUS_PENDING_USER_ACTION:\n                Log.d(TAG, \"Requesting user confirmation...\");\n                // Send broadcast first\n                Intent broadcastIntent2 = new Intent(PackageInstallerCompat.ACTION_INSTALL_INTERACTION_BEGIN);\n                broadcastIntent2.setPackage(context.getPackageName());\n                broadcastIntent2.putExtra(PackageInstaller.EXTRA_PACKAGE_NAME, mPackageName);\n                broadcastIntent2.putExtra(PackageInstaller.EXTRA_SESSION_ID, sessionId);\n                context.sendBroadcast(broadcastIntent2);\n                // Open confirmIntent using the PackageInstallerActivity.\n                // If the confirmIntent isn't open via an activity, it will fail for large apk files\n                Intent confirmIntent = IntentCompat.getParcelableExtra(intent, Intent.EXTRA_INTENT, Intent.class);\n                Intent intent2 = new Intent(context, PackageInstallerActivity.class);\n                intent2.setAction(PackageInstallerActivity.ACTION_PACKAGE_INSTALLED);\n                intent2.putExtra(Intent.EXTRA_INTENT, confirmIntent);\n                intent2.putExtra(PackageInstaller.EXTRA_PACKAGE_NAME, mPackageName);\n                intent2.putExtra(PackageInstaller.EXTRA_SESSION_ID, sessionId);\n                intent2.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);\n                boolean appInForeground = Utils.isAppInForeground();\n                if (appInForeground) {\n                    // Open activity directly and issue a silent notification\n                    context.startActivity(intent2);\n                }\n                // Delete intent: aborts the operation\n                Intent broadcastCancel = new Intent(PackageInstallerCompat.ACTION_INSTALL_COMPLETED);\n                broadcastCancel.setPackage(context.getPackageName());\n                broadcastCancel.putExtra(PackageInstaller.EXTRA_PACKAGE_NAME, mPackageName);\n                broadcastCancel.putExtra(PackageInstaller.EXTRA_STATUS, PackageInstallerCompat.STATUS_FAILURE_ABORTED);\n                broadcastCancel.putExtra(PackageInstaller.EXTRA_SESSION_ID, sessionId);\n                // Ask user for permission\n                mConfirmNotificationId = NotificationUtils.displayInstallConfirmNotification(context, builder -> builder\n                        .setAutoCancel(false)\n                        .setSilent(appInForeground)\n                        .setDefaults(Notification.DEFAULT_ALL)\n                        .setWhen(System.currentTimeMillis())\n                        .setSmallIcon(R.drawable.ic_default_notification)\n                        .setTicker(mAppLabel)\n                        .setContentTitle(mAppLabel)\n                        .setSubText(context.getString(R.string.package_installer))\n                        // A neat way to find the title is to check for sessionId\n                        .setContentText(context.getString(sessionId == -1 ? R.string.confirm_uninstallation : R.string.confirm_installation))\n                        .setContentIntent(PendingIntentCompat.getActivity(context, 0, intent2,\n                                PendingIntent.FLAG_UPDATE_CURRENT, false))\n                        .setDeleteIntent(PendingIntentCompat.getBroadcast(context, 0, broadcastCancel,\n                                PendingIntent.FLAG_UPDATE_CURRENT, false))\n                        .build());\n                break;\n            case PackageInstaller.STATUS_SUCCESS:\n                Log.d(TAG, \"Install success!\");\n                NotificationUtils.cancelInstallConfirmNotification(context, mConfirmNotificationId);\n                PackageInstallerCompat.sendCompletedBroadcast(context, mPackageName, PackageInstallerCompat.STATUS_SUCCESS, sessionId);\n                break;\n            default:\n                NotificationUtils.cancelInstallConfirmNotification(context, mConfirmNotificationId);\n                Intent broadcastError = new Intent(PackageInstallerCompat.ACTION_INSTALL_COMPLETED);\n                broadcastError.setPackage(context.getPackageName());\n                String statusMessage = intent.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE);\n                broadcastError.putExtra(PackageInstaller.EXTRA_STATUS_MESSAGE, statusMessage);\n                broadcastError.putExtra(PackageInstaller.EXTRA_PACKAGE_NAME, mPackageName);\n                broadcastError.putExtra(PackageInstaller.EXTRA_OTHER_PACKAGE_NAME, intent.getStringExtra(PackageInstaller.EXTRA_OTHER_PACKAGE_NAME));\n                broadcastError.putExtra(PackageInstaller.EXTRA_STATUS, status);\n                broadcastError.putExtra(PackageInstaller.EXTRA_SESSION_ID, sessionId);\n                context.sendBroadcast(broadcastError);\n                Log.d(TAG, \"Install failed! %s\", statusMessage);\n                break;\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/apk/installer/PackageInstallerCompat.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.apk.installer;\n\nimport static io.github.muntashirakon.AppManager.compat.PackageManagerCompat.MATCH_UNINSTALLED_PACKAGES;\n\nimport android.Manifest;\nimport android.annotation.SuppressLint;\nimport android.annotation.UserIdInt;\nimport android.app.PendingIntent;\nimport android.content.BroadcastReceiver;\nimport android.content.Context;\nimport android.content.IIntentReceiver;\nimport android.content.IIntentSender;\nimport android.content.Intent;\nimport android.content.IntentFilter;\nimport android.content.IntentSender;\nimport android.content.pm.ApplicationInfo;\nimport android.content.pm.IPackageInstaller;\nimport android.content.pm.IPackageInstallerSession;\nimport android.content.pm.PackageInfo;\nimport android.content.pm.PackageInstaller;\nimport android.content.pm.PackageInstaller.SessionParams;\nimport android.content.pm.PackageInstallerHidden;\nimport android.content.pm.PackageManager;\nimport android.content.pm.VersionedPackage;\nimport android.net.Uri;\nimport android.os.Build;\nimport android.os.Bundle;\nimport android.os.IBinder;\nimport android.os.Process;\nimport android.os.RemoteException;\nimport android.os.UserHandleHidden;\nimport android.provider.Settings;\n\nimport androidx.annotation.IntDef;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.RequiresApi;\nimport androidx.annotation.WorkerThread;\nimport androidx.core.app.PendingIntentCompat;\nimport androidx.core.content.ContextCompat;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.Objects;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.LinkedBlockingQueue;\nimport java.util.concurrent.TimeUnit;\n\nimport aosp.libcore.util.EmptyArray;\nimport dev.rikka.tools.refine.Refine;\nimport io.github.muntashirakon.AppManager.BuildConfig;\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.apk.ApkFile;\nimport io.github.muntashirakon.AppManager.apk.ApkUtils;\nimport io.github.muntashirakon.AppManager.compat.ManifestCompat;\nimport io.github.muntashirakon.AppManager.compat.PackageManagerCompat;\nimport io.github.muntashirakon.AppManager.ipc.ProxyBinder;\nimport io.github.muntashirakon.AppManager.logs.Log;\nimport io.github.muntashirakon.AppManager.progress.ProgressHandler;\nimport io.github.muntashirakon.AppManager.self.SelfPermissions;\nimport io.github.muntashirakon.AppManager.settings.Ops;\nimport io.github.muntashirakon.AppManager.types.UserPackagePair;\nimport io.github.muntashirakon.AppManager.users.Users;\nimport io.github.muntashirakon.AppManager.utils.BroadcastUtils;\nimport io.github.muntashirakon.AppManager.utils.ContextUtils;\nimport io.github.muntashirakon.AppManager.utils.ExUtils;\nimport io.github.muntashirakon.AppManager.utils.FileUtils;\nimport io.github.muntashirakon.AppManager.utils.HuaweiUtils;\nimport io.github.muntashirakon.AppManager.utils.MiuiUtils;\nimport io.github.muntashirakon.AppManager.utils.PackageUtils;\nimport io.github.muntashirakon.AppManager.utils.ThreadUtils;\nimport io.github.muntashirakon.AppManager.utils.UIUtils;\nimport io.github.muntashirakon.io.Path;\n\n@SuppressLint(\"ShiftFlags\")\npublic final class PackageInstallerCompat {\n    public static final String TAG = PackageInstallerCompat.class.getSimpleName();\n\n    public static final String ACTION_INSTALL_STARTED = BuildConfig.APPLICATION_ID + \".action.INSTALL_STARTED\";\n    public static final String ACTION_INSTALL_COMPLETED = BuildConfig.APPLICATION_ID + \".action.INSTALL_COMPLETED\";\n    // For rootless installer to prevent PackageInstallerService from hanging\n    public static final String ACTION_INSTALL_INTERACTION_BEGIN = BuildConfig.APPLICATION_ID + \".action.INSTALL_INTERACTION_BEGIN\";\n    public static final String ACTION_INSTALL_INTERACTION_END = BuildConfig.APPLICATION_ID + \".action.INSTALL_INTERACTION_END\";\n\n    @IntDef({\n            STATUS_SUCCESS,\n            STATUS_FAILURE_ABORTED,\n            STATUS_FAILURE_BLOCKED,\n            STATUS_FAILURE_CONFLICT,\n            STATUS_FAILURE_INCOMPATIBLE,\n            STATUS_FAILURE_INVALID,\n            STATUS_FAILURE_STORAGE,\n            // Custom\n            STATUS_FAILURE_SECURITY,\n            STATUS_FAILURE_SESSION_CREATE,\n            STATUS_FAILURE_SESSION_WRITE,\n            STATUS_FAILURE_SESSION_COMMIT,\n            STATUS_FAILURE_SESSION_ABANDON,\n            STATUS_FAILURE_INCOMPATIBLE_ROM,\n    })\n    @Retention(RetentionPolicy.SOURCE)\n    public @interface Status {\n    }\n\n    /**\n     * See {@link PackageInstaller#STATUS_SUCCESS}\n     */\n    public static final int STATUS_SUCCESS = PackageInstaller.STATUS_SUCCESS;\n    /**\n     * See {@link PackageInstaller#STATUS_FAILURE_ABORTED}\n     */\n    public static final int STATUS_FAILURE_ABORTED = PackageInstaller.STATUS_FAILURE_ABORTED;\n    /**\n     * See {@link PackageInstaller#STATUS_FAILURE_BLOCKED}\n     */\n    public static final int STATUS_FAILURE_BLOCKED = PackageInstaller.STATUS_FAILURE_BLOCKED;\n    /**\n     * See {@link PackageInstaller#STATUS_FAILURE_CONFLICT}\n     */\n    public static final int STATUS_FAILURE_CONFLICT = PackageInstaller.STATUS_FAILURE_CONFLICT;\n    /**\n     * See {@link PackageInstaller#STATUS_FAILURE_INCOMPATIBLE}\n     */\n    public static final int STATUS_FAILURE_INCOMPATIBLE = PackageInstaller.STATUS_FAILURE_INCOMPATIBLE;\n    /**\n     * See {@link PackageInstaller#STATUS_FAILURE_INVALID}\n     */\n    public static final int STATUS_FAILURE_INVALID = PackageInstaller.STATUS_FAILURE_INVALID;\n    /**\n     * See {@link PackageInstaller#STATUS_FAILURE_STORAGE}\n     */\n    public static final int STATUS_FAILURE_STORAGE = PackageInstaller.STATUS_FAILURE_STORAGE;\n    // Custom status\n    /**\n     * The operation failed because the apk file(s) are not accessible.\n     */\n    public static final int STATUS_FAILURE_SECURITY = -2;\n    /**\n     * The operation failed because it failed to create an installer session.\n     */\n    public static final int STATUS_FAILURE_SESSION_CREATE = -3;\n    /**\n     * The operation failed because it failed to write apk files to session.\n     */\n    public static final int STATUS_FAILURE_SESSION_WRITE = -4;\n    /**\n     * The operation failed because it could not commit the installer session.\n     */\n    public static final int STATUS_FAILURE_SESSION_COMMIT = -5;\n    /**\n     * The operation failed because it could not abandon the installer session. This is a redundant\n     * failure.\n     */\n    public static final int STATUS_FAILURE_SESSION_ABANDON = -6;\n    /**\n     * The operation failed because the current ROM is incompatible with PackageInstaller\n     */\n    public static final int STATUS_FAILURE_INCOMPATIBLE_ROM = -7;\n\n    @SuppressLint({\"NewApi\", \"UniqueConstants\", \"InlinedApi\"})\n    @IntDef(flag = true, value = {\n            INSTALL_REPLACE_EXISTING,\n            INSTALL_ALLOW_TEST,\n            INSTALL_EXTERNAL,\n            INSTALL_INTERNAL,\n            INSTALL_FROM_ADB,\n            INSTALL_ALL_USERS,\n            INSTALL_REQUEST_DOWNGRADE,\n            INSTALL_GRANT_ALL_REQUESTED_PERMISSIONS,\n            INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS,\n            INSTALL_FORCE_VOLUME_UUID,\n            INSTALL_FORCE_PERMISSION_PROMPT,\n            INSTALL_INSTANT_APP,\n            INSTALL_DONT_KILL_APP,\n            INSTALL_FULL_APP,\n            INSTALL_ALLOCATE_AGGRESSIVE,\n            INSTALL_VIRTUAL_PRELOAD,\n            INSTALL_APEX,\n            INSTALL_ENABLE_ROLLBACK,\n            INSTALL_DISABLE_VERIFICATION,\n            INSTALL_ALLOW_DOWNGRADE,\n            INSTALL_ALLOW_DOWNGRADE_API29,\n            INSTALL_STAGED,\n            INSTALL_DRY_RUN,\n            INSTALL_BYPASS_LOW_TARGET_SDK_BLOCK,\n            INSTALL_REQUEST_UPDATE_OWNERSHIP,\n            INSTALL_FROM_MANAGED_USER_OR_PROFILE,\n            INSTALL_IGNORE_DEXOPT_PROFILE,\n    })\n    @Retention(RetentionPolicy.SOURCE)\n    public @interface InstallFlags {\n    }\n\n    /**\n     * Flag parameter for {@code #installPackage} to indicate that you want to replace an already\n     * installed package, if one exists.\n     */\n    public static final int INSTALL_REPLACE_EXISTING = 0x00000002;\n\n    /**\n     * Flag parameter for {@code #installPackage} to indicate that you want to\n     * allow test packages (those that have set android:testOnly in their\n     * manifest) to be installed.\n     */\n    public static final int INSTALL_ALLOW_TEST = 0x00000004;\n\n    /**\n     * Flag parameter for {@code #installPackage} to indicate that this\n     * package has to be installed on the sdcard.\n     *\n     * @deprecated Removed in API 29 (Android 10)\n     */\n    @SuppressWarnings(\"DeprecatedIsStillUsed\")\n    @Deprecated\n    public static final int INSTALL_EXTERNAL = 0x00000008;\n\n    /**\n     * Flag parameter for {@code #installPackage} to indicate that this package\n     * has to be installed on the sdcard.\n     */\n    public static final int INSTALL_INTERNAL = 0x00000010;\n\n    /**\n     * Flag parameter for {@code #installPackage} to indicate that this install\n     * was initiated via ADB.\n     */\n    public static final int INSTALL_FROM_ADB = 0x00000020;\n\n    /**\n     * Flag parameter for {@code #installPackage} to indicate that this install\n     * should immediately be visible to all users.\n     */\n    public static final int INSTALL_ALL_USERS = 0x00000040;\n\n    /**\n     * Flag parameter for {@code #installPackage} to indicate that an upgrade to a lower version\n     * of a package than currently installed has been requested.\n     *\n     * <p>Note that this flag doesn't guarantee that downgrade will be performed. That decision\n     * depends\n     * on whenever:\n     * <ul>\n     * <li>An app is debuggable.\n     * <li>Or a build is debuggable.\n     * <li>Or {@link #INSTALL_ALLOW_DOWNGRADE} is set.\n     * </ul>\n     */\n    @RequiresApi(Build.VERSION_CODES.Q)\n    public static final int INSTALL_REQUEST_DOWNGRADE = 0x00000080;\n\n    /**\n     * Flag parameter for {@code #installPackage} to indicate that all runtime\n     * permissions should be granted to the package. If {@link #INSTALL_ALL_USERS}\n     * is set the runtime permissions will be granted to all users, otherwise\n     * only to the owner.\n     * <p>\n     * Previously called {@code #INSTALL_GRANT_RUNTIME_PERMISSIONS}\n     */\n    @RequiresApi(Build.VERSION_CODES.M)\n    public static final int INSTALL_GRANT_ALL_REQUESTED_PERMISSIONS = 0x00000100;\n\n    /**\n     * Flag parameter for {@code #installPackage} to indicate that all restricted\n     * permissions should be whitelisted. If {@link #INSTALL_ALL_USERS}\n     * is set the restricted permissions will be whitelisted for all users, otherwise\n     * only to the owner.\n     */\n    @RequiresApi(Build.VERSION_CODES.Q)\n    public static final int INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS = 0x00400000;\n\n    @RequiresApi(Build.VERSION_CODES.M)\n    public static final int INSTALL_FORCE_VOLUME_UUID = 0x00000200;\n\n    /**\n     * Flag parameter for {@code #installPackage} to indicate that we always want to force\n     * the prompt for permission approval. This overrides any special behaviour for internal\n     * components.\n     */\n    @RequiresApi(Build.VERSION_CODES.N)\n    public static final int INSTALL_FORCE_PERMISSION_PROMPT = 0x00000400;\n\n    /**\n     * Flag parameter for {@code #installPackage} to indicate that this package is\n     * to be installed as a lightweight \"ephemeral\" app.\n     * <p>\n     * Previously known as {@code #INSTALL_EPHEMERAL}\n     */\n    @RequiresApi(Build.VERSION_CODES.N)\n    public static final int INSTALL_INSTANT_APP = 0x00000800;\n\n    /**\n     * Flag parameter for {@code #installPackage} to indicate that this package contains\n     * a feature split to an existing application and the existing application should not\n     * be killed during the installation process.\n     */\n    @RequiresApi(Build.VERSION_CODES.N)\n    public static final int INSTALL_DONT_KILL_APP = 0x00001000;\n\n    /**\n     * Flag parameter for {@code #installPackage} to indicate that this package is an\n     * upgrade to a package that refers to the SDK via release letter.\n     *\n     * @deprecated Removed in API 29 (Android 10)\n     */\n    @Deprecated\n    @RequiresApi(Build.VERSION_CODES.N)\n    public static final int INSTALL_FORCE_SDK = 0x00002000;\n\n    /**\n     * Flag parameter for {@code #installPackage} to indicate that this package is\n     * to be installed as a heavy weight app. This is fundamentally the opposite of\n     * {@link #INSTALL_INSTANT_APP}.\n     */\n    @RequiresApi(Build.VERSION_CODES.O)\n    public static final int INSTALL_FULL_APP = 0x00004000;\n\n    /**\n     * Flag parameter for {@code #installPackage} to indicate that this package\n     * is critical to system health or security, meaning the system should use\n     * {@code StorageManager#FLAG_ALLOCATE_AGGRESSIVE} internally.\n     */\n    @RequiresApi(Build.VERSION_CODES.O)\n    public static final int INSTALL_ALLOCATE_AGGRESSIVE = 0x00008000;\n\n    /**\n     * Flag parameter for {@code #installPackage} to indicate that this package\n     * is a virtual preload.\n     */\n    @RequiresApi(Build.VERSION_CODES.O_MR1)\n    public static final int INSTALL_VIRTUAL_PRELOAD = 0x00010000;\n\n    /**\n     * Flag parameter for {@code #installPackage} to indicate that this package\n     * is an APEX package\n     */\n    @RequiresApi(Build.VERSION_CODES.Q)\n    public static final int INSTALL_APEX = 0x00020000;\n\n    /**\n     * Flag parameter for {@code #installPackage} to indicate that rollback\n     * should be enabled for this install.\n     */\n    @RequiresApi(Build.VERSION_CODES.Q)\n    public static final int INSTALL_ENABLE_ROLLBACK = 0x00040000;\n\n    /**\n     * Flag parameter for {@code #installPackage} to indicate that package verification should be\n     * disabled for this package.\n     */\n    @RequiresApi(Build.VERSION_CODES.Q)\n    public static final int INSTALL_DISABLE_VERIFICATION = 0x00080000;\n\n    /**\n     * Flag parameter for {@code #installPackage} to indicate that\n     * {@link #INSTALL_REQUEST_DOWNGRADE} should be allowed.\n     */\n    @RequiresApi(Build.VERSION_CODES.Q)\n    public static final int INSTALL_ALLOW_DOWNGRADE_API29 = 0x00100000;\n\n    /**\n     * Flag parameter for {@code #installPackage} to indicate that this package\n     * is being installed as part of a staged install.\n     */\n    @RequiresApi(Build.VERSION_CODES.Q)\n    public static final int INSTALL_STAGED = 0x00200000;\n\n    /**\n     * Flag parameter for {@code #installPackage} to indicate that package should only be verified\n     * but not installed.\n     *\n     * @deprecated Removed in API 30 (Android 11)\n     */\n    @SuppressWarnings(\"DeprecatedIsStillUsed\")\n    @RequiresApi(Build.VERSION_CODES.Q)\n    @Deprecated\n    public static final int INSTALL_DRY_RUN = 0x00800000;\n\n    /**\n     * Flag parameter for {@code #installPackage} to indicate that it is okay\n     * to install an update to an app where the newly installed app has a lower\n     * version code than the currently installed app.\n     *\n     * @deprecated Replaced by {@link #INSTALL_ALLOW_DOWNGRADE_API29} in Android 10\n     */\n    @SuppressWarnings(\"DeprecatedIsStillUsed\")\n    @Deprecated\n    public static final int INSTALL_ALLOW_DOWNGRADE = 0x00000080;\n\n    /**\n     * Flag parameter for {@code #installPackage} to bypass the low targer sdk version block\n     * for this install.\n     */\n    @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)\n    public static final int INSTALL_BYPASS_LOW_TARGET_SDK_BLOCK = 0x01000000;\n\n    /**\n     * Flag parameter for {@link SessionParams} to indicate that the\n     * update ownership enforcement is requested.\n     */\n    @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)\n    public static final int INSTALL_REQUEST_UPDATE_OWNERSHIP = 1 << 25;\n\n    /**\n     * Flag parameter for {@link SessionParams} to indicate that this\n     * session is from a managed user or profile.\n     */\n    @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)\n    public static final int INSTALL_FROM_MANAGED_USER_OR_PROFILE = 1 << 26;\n\n    /**\n     * If set, all dexopt profiles are ignored by dexopt during the installation, including the\n     * profile in the DM file and the profile embedded in the APK file. If an invalid profile is\n     * provided during installation, no warning will be reported by {@code adb install}.\n     * <p>\n     * This option does not affect later dexopt operations (e.g., background dexopt and manual `pm\n     * compile` invocations).\n     */\n    @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)\n    public static final int INSTALL_IGNORE_DEXOPT_PROFILE = 1 << 28;\n\n    @SuppressLint({\"NewApi\", \"InlinedApi\"})\n    @IntDef(flag = true, value = {\n            DELETE_KEEP_DATA,\n            DELETE_ALL_USERS,\n            DELETE_SYSTEM_APP,\n            DELETE_DONT_KILL_APP,\n            DELETE_CHATTY,\n    })\n    @Retention(RetentionPolicy.SOURCE)\n    public @interface DeleteFlags {\n    }\n\n    /**\n     * Flag parameter for {@code #deletePackage} to indicate that you don't want to delete the\n     * package's data directory.\n     */\n    public static final int DELETE_KEEP_DATA = 0x00000001;\n\n    /**\n     * Flag parameter for {@code #deletePackage} to indicate that you want the\n     * package deleted for all users.\n     */\n    public static final int DELETE_ALL_USERS = 0x00000002;\n\n    /**\n     * Flag parameter for {@code #deletePackage} to indicate that, if you are calling\n     * uninstall on a system that has been updated, then don't do the normal process\n     * of uninstalling the update and rolling back to the older system version (which\n     * needs to happen for all users); instead, just mark the app as uninstalled for\n     * the current user.\n     */\n    public static final int DELETE_SYSTEM_APP = 0x00000004;\n\n    /**\n     * Flag parameter for {@code #deletePackage} to indicate that, if you are calling\n     * uninstall on a package that is replaced to provide new feature splits, the\n     * existing application should not be killed during the removal process.\n     */\n    @RequiresApi(Build.VERSION_CODES.N)\n    public static final int DELETE_DONT_KILL_APP = 0x00000008;\n\n    /**\n     * Flag parameter for {@code #deletePackage} to indicate that package deletion\n     * should be chatty.\n     */\n    @RequiresApi(Build.VERSION_CODES.P)\n    public static final int DELETE_CHATTY = 0x80000000;\n\n    public static final String SETTINGS_VERIFIER_VERIFY_ADB_INSTALLS = \"verifier_verify_adb_installs\";\n\n    public interface OnInstallListener {\n        @WorkerThread\n        void onStartInstall(int sessionId, String packageName);\n\n        // MIUI-begin: MIUI 12.5+ workaround\n\n        /**\n         * MIUI 12.5+ may require more than one tries in order to have successful installations.\n         * This is only needed during APK installations, not APK uninstallations or install-existing\n         * attempts.\n         *\n         * @param apkFile Underlying APK file if available.\n         */\n        @WorkerThread\n        default void onAnotherAttemptInMiui(@Nullable ApkFile apkFile) {\n        }\n        // MIUI-end\n\n        // HyperOS-begin: HyperOS 2.0+ workaround\n\n        /**\n         * In HyperOS 2.0+, the installer for the system apps must be another system app. The\n         * overridden method must set the package installer to a valid system app. This is only\n         * needed during APK installations, not APK uninstallations or install-existing attempts.\n         *\n         * @param apkFile Underlying APK file if available.\n         */\n        @WorkerThread\n        default void onSecondAttemptInHyperOsWithoutInstaller(@Nullable ApkFile apkFile) {\n        }\n        // HyperOS-end\n\n        @WorkerThread\n        void onFinishedInstall(int sessionId, String packageName, int result, @Nullable String blockingPackage,\n                               @Nullable String statusMessage);\n    }\n\n    @NonNull\n    public static PackageInstallerCompat getNewInstance() {\n        return new PackageInstallerCompat();\n    }\n\n    private CountDownLatch mInstallWatcher;\n    private CountDownLatch mInteractionWatcher;\n\n    private boolean mCloseApkFile = true;\n    private boolean mInstallCompleted = false;\n    @Nullable\n    private ApkFile mApkFile;\n    private String mPackageName;\n    @Nullable\n    private CharSequence mAppLabel;\n    private int mSessionId = -1;\n    @Status\n    private int mFinalStatus = STATUS_FAILURE_INVALID;\n    @Nullable\n    private String mStatusMessage;\n    private PackageInstallerBroadcastReceiver mPkgInstallerReceiver;\n    private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {\n        @Override\n        public void onReceive(Context context, @NonNull Intent intent) {\n            if (intent.getAction() == null) return;\n            int sessionId = intent.getIntExtra(PackageInstaller.EXTRA_SESSION_ID, -1);\n            Log.d(TAG, \"Action: %s\", intent.getAction());\n            Log.d(TAG, \"Session ID: %d\", sessionId);\n            switch (intent.getAction()) {\n                case ACTION_INSTALL_STARTED:\n                    // Session successfully created\n                    if (mOnInstallListener != null) {\n                        mOnInstallListener.onStartInstall(sessionId, mPackageName);\n                    }\n                    break;\n                case ACTION_INSTALL_INTERACTION_BEGIN:\n                    // An installation prompt is being shown to the user\n                    // Run indefinitely until user finally decides to do something about it\n                    break;\n                case ACTION_INSTALL_INTERACTION_END:\n                    // The installation prompt is hidden by the user, either by clicking cancel or install,\n                    // or just clicking on some place else (latter is our main focus)\n                    if (mSessionId == sessionId) {\n                        // The user interaction is done, it doesn't take more than 1 minute now\n                        mInteractionWatcher.countDown();\n                    }\n                    break;\n                case ACTION_INSTALL_COMPLETED:\n                    // Either it failed to create a session or the installation was completed,\n                    // regardless of the status: success or failure\n                    mFinalStatus = intent.getIntExtra(PackageInstaller.EXTRA_STATUS, STATUS_FAILURE_INVALID);\n                    String blockingPackage = intent.getStringExtra(PackageInstaller.EXTRA_OTHER_PACKAGE_NAME);\n                    mStatusMessage = intent.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE);\n                    // Run install completed\n                    mInstallCompleted = true;\n                    ThreadUtils.postOnBackgroundThread(() ->\n                            installCompleted(sessionId, mFinalStatus, blockingPackage, mStatusMessage));\n                    break;\n            }\n        }\n    };\n\n    @Nullable\n    private OnInstallListener mOnInstallListener;\n    private IPackageInstaller mPackageInstaller;\n    private PackageInstaller.Session mSession;\n    // MIUI-added: Multiple attempts may be required\n    int mAttempts = 1;\n    private final Context mContext;\n    private final boolean mHasInstallPackagePermission;\n    private int mLastVerifyAdbInstallsResult;\n\n    private PackageInstallerCompat() {\n        mContext = ContextUtils.getContext();\n        mHasInstallPackagePermission = SelfPermissions.checkSelfOrRemotePermission(Manifest.permission.INSTALL_PACKAGES);\n        mLastVerifyAdbInstallsResult = -1;\n    }\n\n    public void setOnInstallListener(@Nullable OnInstallListener onInstallListener) {\n        mOnInstallListener = onInstallListener;\n    }\n\n    public void setAppLabel(@Nullable CharSequence appLabel) {\n        mAppLabel = appLabel;\n    }\n\n    @NonNull\n    private static int[] getAllRequestedUsers(int userId) {\n        switch (userId) {\n            case UserHandleHidden.USER_ALL:\n                return Users.getAllUserIds();\n            case UserHandleHidden.USER_NULL:\n                return EmptyArray.INT;\n            default:\n                return new int[]{userId};\n        }\n    }\n\n    public boolean install(@NonNull ApkFile apkFile, @NonNull List<String> selectedSplitIds,\n                           @NonNull InstallerOptions options, @Nullable ProgressHandler progressHandler) {\n        ThreadUtils.ensureWorkerThread();\n        try {\n            mApkFile = apkFile;\n            mPackageName = Objects.requireNonNull(apkFile.getPackageName());\n            initBroadcastReceiver();\n            int userId = options.getUserId();\n            int installFlags = getInstallFlags(userId);\n            int[] allRequestedUsers = getAllRequestedUsers(userId);\n            if (allRequestedUsers.length == 0) {\n                Log.d(TAG, \"Install: no users.\");\n                callFinish(STATUS_FAILURE_INVALID);\n                return false;\n            }\n            Log.d(TAG, \"Installing for users: %s\", Arrays.toString(allRequestedUsers));\n            for (int u : allRequestedUsers) {\n                if (!SelfPermissions.checkCrossUserPermission(u, true)) {\n                    installCompleted(mSessionId, STATUS_FAILURE_BLOCKED, \"android\", \"STATUS_FAILURE_BLOCKED: Insufficient permission.\");\n                    Log.d(TAG, \"Install: Requires INTERACT_ACROSS_USERS and INTERACT_ACROSS_USERS_FULL permissions.\");\n                    return false;\n                }\n            }\n            ThreadUtils.postOnBackgroundThread(() -> {\n                // TODO: 6/6/23 Wait for this task to finish before returning\n                // FIXME: 16/6/23 Needed only for one user?\n                for (int u : allRequestedUsers) {\n                    copyObb(apkFile, u);\n                }\n            });\n            userId = allRequestedUsers[0];\n            String originatingPackage = options.isSetOriginatingPackage() ? options.getOriginatingPackage() : null;\n            Uri originatingUri = options.isSetOriginatingPackage() ? options.getOriginatingUri() : null;\n            Log.d(TAG, \"Install: opening session...\");\n            if (!openSession(userId, installFlags, options.getInstallerName(),\n                    options.getInstallLocation(), originatingPackage, originatingUri,\n                    options.getInstallScenario(), options.getPackageSource(),\n                    options.requestUpdateOwnership(), options.isDisableApkVerification())) {\n                return false;\n            }\n            List<ApkFile.Entry> selectedEntries = new ArrayList<>();\n            long totalSize = 0;\n            for (ApkFile.Entry entry : apkFile.getEntries()) {\n                if (selectedSplitIds.contains(entry.id)) {\n                    selectedEntries.add(entry);\n                    try {\n                        totalSize += entry.getFile(options.isSignApkFiles()).length();\n                    } catch (IOException e) {\n                        callFinish(STATUS_FAILURE_INVALID);\n                        Log.e(TAG, \"Install: Cannot retrieve the selected APK files.\", e);\n                        return abandon();\n                    }\n                }\n            }\n            Log.d(TAG, \"Install: selected entries: %s\", selectedSplitIds);\n            // Write apk files\n            for (ApkFile.Entry entry : selectedEntries) {\n                long entrySize = entry.getFileSize(options.isSignApkFiles());\n                try (InputStream apkInputStream = entry.getInputStream(options.isSignApkFiles());\n                     OutputStream apkOutputStream = mSession.openWrite(entry.getFileName(), 0, entrySize)) {\n                    FileUtils.copy(apkInputStream, apkOutputStream, totalSize, progressHandler);\n                    mSession.fsync(apkOutputStream);\n                    Log.d(TAG, \"Install: copied entry %s\", entry.name);\n                } catch (IOException e) {\n                    callFinish(STATUS_FAILURE_SESSION_WRITE);\n                    Log.e(TAG, \"Install: Cannot copy files to session.\", e);\n                    return abandon();\n                } catch (SecurityException e) {\n                    callFinish(STATUS_FAILURE_SECURITY);\n                    Log.e(TAG, \"Install: Cannot access apk files.\", e);\n                    return abandon();\n                }\n            }\n            Log.d(TAG, \"Install: Running installation...\");\n            // Commit\n            return commit(userId);\n        } finally {\n            unregisterReceiver();\n            restoreVerifySettings();\n        }\n    }\n\n    public boolean install(@NonNull Path[] apkFiles, @NonNull String packageName, @NonNull InstallerOptions options) {\n        return install(apkFiles, packageName, options, null);\n    }\n\n    public boolean install(@NonNull Path[] apkFiles, @NonNull String packageName, @NonNull InstallerOptions options,\n                           @Nullable ProgressHandler progressHandler) {\n        ThreadUtils.ensureWorkerThread();\n        try {\n            mApkFile = null;\n            mPackageName = Objects.requireNonNull(packageName);\n            initBroadcastReceiver();\n            int userId = options.getUserId();\n            int installFlags = getInstallFlags(userId);\n            int[] allRequestedUsers = getAllRequestedUsers(userId);\n            if (allRequestedUsers.length == 0) {\n                Log.d(TAG, \"Install: no users.\");\n                callFinish(STATUS_FAILURE_INVALID);\n                return false;\n            }\n            Log.d(TAG, \"Installing for users: %s\", Arrays.toString(allRequestedUsers));\n            for (int u : allRequestedUsers) {\n                if (!SelfPermissions.checkCrossUserPermission(u, true)) {\n                    installCompleted(mSessionId, STATUS_FAILURE_BLOCKED, \"android\", \"STATUS_FAILURE_BLOCKED: Insufficient permission.\");\n                    Log.d(TAG, \"Install: Requires INTERACT_ACROSS_USERS and INTERACT_ACROSS_USERS_FULL permissions.\");\n                    return false;\n                }\n            }\n            userId = allRequestedUsers[0];\n            String originatingPackage = options.isSetOriginatingPackage() ? options.getOriginatingPackage() : null;\n            Uri originatingUri = options.isSetOriginatingPackage() ? options.getOriginatingUri() : null;\n            if (!openSession(userId, installFlags, options.getInstallerName(),\n                    options.getInstallLocation(), originatingPackage, originatingUri,\n                    options.getInstallScenario(), options.getPackageSource(),\n                    options.requestUpdateOwnership(), options.isDisableApkVerification())) {\n                return false;\n            }\n            long totalSize = 0;\n            for (Path apkFile : apkFiles) {\n                totalSize += apkFile.length();\n            }\n            // Write apk files\n            for (Path apkFile : apkFiles) {\n                try (InputStream apkInputStream = apkFile.openInputStream();\n                     OutputStream apkOutputStream = mSession.openWrite(apkFile.getName(), 0, apkFile.length())) {\n                    FileUtils.copy(apkInputStream, apkOutputStream, totalSize, progressHandler);\n                    mSession.fsync(apkOutputStream);\n                } catch (IOException e) {\n                    callFinish(STATUS_FAILURE_SESSION_WRITE);\n                    Log.e(TAG, \"Install: Cannot copy files to session.\", e);\n                    return abandon();\n                } catch (SecurityException e) {\n                    callFinish(STATUS_FAILURE_SECURITY);\n                    Log.e(TAG, \"Install: Cannot access apk files.\", e);\n                    return abandon();\n                }\n            }\n            // Commit\n            return commit(userId);\n        } finally {\n            unregisterReceiver();\n            restoreVerifySettings();\n        }\n    }\n\n    private boolean commit(int userId) {\n        IntentSender sender;\n        LocalIntentReceiver intentReceiver;\n        if (mHasInstallPackagePermission) {\n            Log.d(TAG, \"Commit: Commit via LocalIntentReceiver...\");\n            try {\n                intentReceiver = new LocalIntentReceiver();\n                sender = intentReceiver.getIntentSender();\n            } catch (Exception e) {\n                callFinish(STATUS_FAILURE_SESSION_COMMIT);\n                Log.e(TAG, \"Commit: Could not commit session.\", e);\n                return false;\n            }\n        } else {\n            Log.d(TAG, \"Commit: Calling activity to request permission...\");\n            intentReceiver = null;\n            Intent callbackIntent = new Intent(PackageInstallerBroadcastReceiver.ACTION_PI_RECEIVER);\n            callbackIntent.setPackage(BuildConfig.APPLICATION_ID);\n            PendingIntent pendingIntent = PendingIntentCompat.getBroadcast(mContext, 0, callbackIntent, 0, true);\n            sender = pendingIntent.getIntentSender();\n        }\n        Log.d(TAG, \"Commit: Committing...\");\n        try {\n            mSession.commit(sender);\n        } catch (Throwable e) {  // primarily RemoteException\n            callFinish(STATUS_FAILURE_SESSION_COMMIT);\n            Log.e(TAG, \"Commit: Could not commit session.\", e);\n            return false;\n        }\n        if (intentReceiver == null) {\n            Log.d(TAG, \"Commit: Waiting for user interaction...\");\n            // Wait for user interaction (if needed)\n            try {\n                // Wait for user interaction\n                mInteractionWatcher.await();\n                // Wait for the installation to complete\n                mInstallWatcher.await(1, TimeUnit.MINUTES);\n            } catch (InterruptedException e) {\n                Log.e(TAG, \"Installation interrupted.\", e);\n            }\n        } else {\n            Intent resultIntent = intentReceiver.getResult();\n            mFinalStatus = resultIntent.getIntExtra(PackageInstaller.EXTRA_STATUS, 0);\n            mStatusMessage = resultIntent.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE);\n        }\n        Log.d(TAG, \"Commit: Finishing...\");\n        // We might want to use {@code callFinish(finalStatus);} here, but it doesn't always work\n        // since the object is garbage collected almost immediately.\n        if (!mInstallCompleted) {\n            installCompleted(mSessionId, mFinalStatus, null, mStatusMessage);\n        }\n        if (mFinalStatus == PackageInstaller.STATUS_SUCCESS && userId != UserHandleHidden.myUserId()) {\n            BroadcastUtils.sendPackageAltered(ContextUtils.getContext(), new String[]{mPackageName});\n        }\n        return mFinalStatus == PackageInstaller.STATUS_SUCCESS;\n    }\n\n    @SuppressWarnings(\"BooleanMethodIsAlwaysInverted\")\n    private boolean openSession(@UserIdInt int userId, @InstallFlags int installFlags,\n                                String installerName, int installLocation,\n                                @Nullable String originatingPackage, @Nullable Uri originatingUri,\n                                int installScenario, int packageSource,\n                                boolean requestUpdateOwnership, boolean disableVerification) {\n        // Changing package installer in stock Huawei with UID 2000 does not work\n        boolean canChangeInstaller = mHasInstallPackagePermission && (!HuaweiUtils.isStockHuawei() || Users.getSelfOrRemoteUid() != Ops.SHELL_UID);\n        String requestedInstallerPackageName = canChangeInstaller ? installerName : null;\n        String installerPackageName = Build.VERSION.SDK_INT < Build.VERSION_CODES.P && canChangeInstaller\n                ? installerName : BuildConfig.APPLICATION_ID;\n        try {\n            mPackageInstaller = PackageManagerCompat.getPackageInstaller();\n        } catch (RemoteException e) {\n            callFinish(STATUS_FAILURE_SESSION_CREATE);\n            Log.e(TAG, \"OpenSession: Could not get PackageInstaller.\", e);\n            return false;\n        }\n        // Clean old sessions\n        cleanOldSessions();\n        // Create install session\n        SessionParams sessionParams = new SessionParams(SessionParams.MODE_FULL_INSTALL);\n        if (disableVerification) {\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE\n                    && SelfPermissions.isSystemOrRootOrShell()) {\n                // This disables verification for this UID temporarily\n                ExUtils.exceptionAsIgnored(() ->\n                        mPackageInstaller.disableVerificationForUid(Users.getSelfOrRemoteUid()));\n            }\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {\n                installFlags |= INSTALL_DISABLE_VERIFICATION;\n            }\n            // In addition, we may also want to use the traditional methods\n            if (SelfPermissions.isShell()) {\n                mLastVerifyAdbInstallsResult = Settings.Global.getInt(mContext.getContentResolver(), SETTINGS_VERIFIER_VERIFY_ADB_INSTALLS, 1);\n                if (mLastVerifyAdbInstallsResult != 0) {\n                    Settings.Global.putInt(mContext.getContentResolver(), SETTINGS_VERIFIER_VERIFY_ADB_INSTALLS, 0);\n                }\n            }\n        }\n        Refine.<PackageInstallerHidden.SessionParams>unsafeCast(sessionParams).installFlags |= installFlags;\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {\n            Refine.<PackageInstallerHidden.SessionParams>unsafeCast(sessionParams).installerPackageName = requestedInstallerPackageName;\n        }\n        // Set installation location\n        sessionParams.setInstallLocation(installLocation);\n        // Set origin\n        if (originatingUri != null) {\n            sessionParams.setOriginatingUri(originatingUri);\n        }\n        if (originatingPackage != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {\n            int uid = PackageUtils.getAppUid(new UserPackagePair(originatingPackage,\n                    UserHandleHidden.myUserId()));\n            if (uid >= 0) {\n                sessionParams.setOriginatingUid(uid);\n                Log.d(TAG, \"Setting originating uid: %d for %s\", uid, originatingPackage);\n            }\n        }\n        // Set install reason\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {\n            sessionParams.setInstallReason(PackageManager.INSTALL_REASON_USER);\n        }\n        // Set install user action and install scenario\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {\n            // We hope system will not prompt an install confirmation\n            sessionParams.setRequireUserAction(SessionParams.USER_ACTION_NOT_REQUIRED);\n            sessionParams.setInstallScenario(installScenario);\n        }\n        // Set package source (shell uses PACKAGE_SOURCE_OTHER)\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {\n            sessionParams.setPackageSource(packageSource);\n        }\n        // Set ownership (disable by default in shell)\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {\n            sessionParams.setApplicationEnabledSettingPersistent();\n            sessionParams.setRequestUpdateOwnership(requestUpdateOwnership);\n        }\n        try {\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {\n                mSessionId = mPackageInstaller.createSession(sessionParams, installerPackageName, null, userId);\n            } else {\n                //noinspection deprecation\n                mSessionId = mPackageInstaller.createSession(sessionParams, installerPackageName, userId);\n            }\n            Log.d(TAG, \"OpenSession: session id %d\", mSessionId);\n        } catch (RemoteException e) {\n            callFinish(STATUS_FAILURE_SESSION_CREATE);\n            Log.e(TAG, \"OpenSession: Failed to create install session.\", e);\n            return false;\n        }\n        try {\n            mSession = Refine.unsafeCast(new PackageInstallerHidden.Session(IPackageInstallerSession.Stub.asInterface(\n                    new ProxyBinder(mPackageInstaller.openSession(mSessionId).asBinder()))));\n            Log.d(TAG, \"OpenSession: session opened.\");\n        } catch (RemoteException e) {\n            callFinish(STATUS_FAILURE_SESSION_CREATE);\n            Log.e(TAG, \"OpenSession: Failed to open install session.\", e);\n            return false;\n        }\n        sendStartedBroadcast(mPackageName, mSessionId);\n        return true;\n    }\n\n    private void restoreVerifySettings() {\n        if (mLastVerifyAdbInstallsResult == 1) {\n            int val = Settings.Global.getInt(mContext.getContentResolver(), SETTINGS_VERIFIER_VERIFY_ADB_INSTALLS, 1);\n            if (val != 1) {\n                // Restore value\n                Settings.Global.putInt(mContext.getContentResolver(), SETTINGS_VERIFIER_VERIFY_ADB_INSTALLS, 1);\n            }\n        }\n    }\n\n    @InstallFlags\n    private static int getInstallFlags(@UserIdInt int userId) {\n        int flags = INSTALL_FROM_ADB | INSTALL_ALLOW_TEST | INSTALL_REPLACE_EXISTING;\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {\n            flags |= INSTALL_FULL_APP;\n        }\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {\n            flags |= INSTALL_REQUEST_DOWNGRADE | INSTALL_ALLOW_DOWNGRADE_API29;\n        } else flags |= INSTALL_ALLOW_DOWNGRADE;\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {\n            flags |= INSTALL_BYPASS_LOW_TARGET_SDK_BLOCK;\n        }\n        if (userId == UserHandleHidden.USER_ALL) {\n            flags |= INSTALL_ALL_USERS;\n        }\n        return flags;\n    }\n\n    public boolean installExisting(@NonNull String packageName, @UserIdInt int userId) {\n        ThreadUtils.ensureWorkerThread();\n        mPackageName = Objects.requireNonNull(packageName);\n        if (mOnInstallListener != null) {\n            mOnInstallListener.onStartInstall(mSessionId, packageName);\n        }\n        mInstallWatcher = new CountDownLatch(0);\n        mInteractionWatcher = new CountDownLatch(0);\n        if (!SelfPermissions.canInstallExistingPackages()) {\n            installCompleted(mSessionId, STATUS_FAILURE_BLOCKED, \"android\", \"STATUS_FAILURE_BLOCKED: Insufficient permission.\");\n            Log.d(TAG, \"InstallExisting: Requires INSTALL_PACKAGES permission.\");\n            return false;\n        }\n        // User ID must be a real user\n        List<Integer> userIdWithoutInstalledPkg = new ArrayList<>();\n        switch (userId) {\n            case UserHandleHidden.USER_ALL: {\n                int[] userIds = Users.getUsersIds();\n                for (int u : userIds) {\n                    try {\n                        PackageManagerCompat.getPackageInfo(packageName,\n                                PackageManagerCompat.MATCH_STATIC_SHARED_AND_SDK_LIBRARIES, u);\n                    } catch (Throwable th) {\n                        userIdWithoutInstalledPkg.add(u);\n                    }\n                }\n                break;\n            }\n            case UserHandleHidden.USER_NULL:\n                installCompleted(mSessionId, STATUS_FAILURE_INVALID, null, \"STATUS_FAILURE_INVALID: No user is selected.\");\n                Log.d(TAG, \"InstallExisting: No user is selected.\");\n                return false;\n            default:\n                try {\n                    PackageManagerCompat.getPackageInfo(packageName,\n                            PackageManagerCompat.MATCH_STATIC_SHARED_AND_SDK_LIBRARIES, userId);\n                    installCompleted(mSessionId, STATUS_FAILURE_ABORTED, null, \"STATUS_FAILURE_ABORTED: Already installed.\");\n                    Log.d(TAG, \"InstallExisting: Already installed.\");\n                    return false;\n                } catch (Throwable th) {\n                    userIdWithoutInstalledPkg.add(userId);\n                }\n        }\n        if (userIdWithoutInstalledPkg.isEmpty()) {\n            installCompleted(mSessionId, STATUS_FAILURE_INVALID, null, \"STATUS_FAILURE_INVALID: Could not find a valid user to perform install-existing.\");\n            Log.d(TAG, \"InstallExisting: Could not find any valid user.\");\n            return false;\n        }\n        int installFlags = 0;\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {\n            installFlags |= INSTALL_ALL_WHITELIST_RESTRICTED_PERMISSIONS;\n        }\n        int installReason;\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {\n            installReason = PackageManager.INSTALL_REASON_USER;\n        } else installReason = 0;\n        for (int u : userIdWithoutInstalledPkg) {\n            if (!SelfPermissions.checkCrossUserPermission(u, true)) {\n                installCompleted(mSessionId, STATUS_FAILURE_BLOCKED, \"android\", \"STATUS_FAILURE_BLOCKED: Insufficient permission.\");\n                Log.d(TAG, \"InstallExisting: Requires INTERACT_ACROSS_USERS and INTERACT_ACROSS_USERS_FULL permissions.\");\n                return false;\n            }\n            try {\n                int res = PackageManagerCompat.installExistingPackageAsUser(packageName, u, installFlags, installReason, null);\n                if (res != 1 /* INSTALL_SUCCEEDED */) {\n                    installCompleted(mSessionId, res, null, null);\n                    Log.e(TAG, \"InstallExisting: Install failed with code %d\", res);\n                    return false;\n                }\n                if (u != UserHandleHidden.myUserId()) {\n                    BroadcastUtils.sendPackageAdded(ContextUtils.getContext(), new String[]{packageName});\n                }\n            } catch (Throwable th) {\n                installCompleted(mSessionId, STATUS_FAILURE_ABORTED, null, \"STATUS_FAILURE_ABORTED: \" + th.getMessage());\n                Log.e(TAG, \"InstallExisting: Could not install package for user %s\", th, u);\n                return false;\n            }\n        }\n        installCompleted(mSessionId, STATUS_SUCCESS, null, null);\n        return true;\n    }\n\n    @WorkerThread\n    private void copyObb(@NonNull ApkFile apkFile, @UserIdInt int userId) {\n        if (!apkFile.hasObb()) return;\n        boolean tmpCloseApkFile = mCloseApkFile;\n        // Disable closing apk file in case the installation is finished already.\n        mCloseApkFile = false;\n        try {\n            // Get writable OBB directory\n            Path writableObbDir = ApkUtils.getOrCreateObbDir(mPackageName, userId);\n            // Delete old files\n            for (Path oldFile : writableObbDir.listFiles()) {\n                oldFile.delete();\n            }\n            apkFile.extractObb(writableObbDir);\n            ThreadUtils.postOnMainThread(() -> UIUtils.displayLongToast(R.string.obb_files_extracted_successfully));\n        } catch (Exception e) {\n            Log.e(TAG, e);\n            ThreadUtils.postOnMainThread(() -> UIUtils.displayLongToast(R.string.failed_to_extract_obb_files));\n        } finally {\n            if (mInstallWatcher.getCount() != 0) {\n                // Reset close apk file if the installation isn't completed\n                mCloseApkFile = tmpCloseApkFile;\n            } else {\n                // Install completed, close apk file if requested\n                if (tmpCloseApkFile) apkFile.close();\n            }\n        }\n    }\n\n    private void cleanOldSessions() {\n        if (Users.getSelfOrRemoteUid() != Process.myUid()) {\n            // Only clean sessions for this UID\n            return;\n        }\n        List<PackageInstaller.SessionInfo> sessionInfoList;\n        try {\n            sessionInfoList = mPackageInstaller.getMySessions(mContext.getPackageName(), UserHandleHidden.myUserId()).getList();\n        } catch (Throwable e) {\n            Log.w(TAG, \"CleanOldSessions: Could not get previous sessions.\", e);\n            return;\n        }\n        for (PackageInstaller.SessionInfo sessionInfo : sessionInfoList) {\n            try {\n                mPackageInstaller.abandonSession(sessionInfo.getSessionId());\n            } catch (Throwable e) {\n                Log.w(TAG, \"CleanOldSessions: Unable to abandon session\", e);\n            }\n        }\n    }\n\n    private boolean abandon() {\n        if (mSession != null) {\n            try {\n                mSession.close();\n            } catch (Exception e) {  // RemoteException\n                Log.e(TAG, \"Abandon: Failed to abandon session.\");\n            }\n        }\n        return false;\n    }\n\n    private void callFinish(int result) {\n        sendCompletedBroadcast(mContext, mPackageName, result, mSessionId);\n    }\n\n    private void installCompleted(int sessionId,\n                                  int finalStatus,\n                                  @Nullable String blockingPackage,\n                                  @Nullable String statusMessage) {\n        ThreadUtils.ensureWorkerThread();\n        if (finalStatus == STATUS_FAILURE_ABORTED\n                && mSessionId == sessionId\n                && mOnInstallListener != null) {\n            boolean privileged = SelfPermissions.checkSelfPermission(Manifest.permission.INSTALL_PACKAGES);\n            // MIUI-begin: In MIUI 12.5 and 20.2.0, it might be required to try installing the APK files more than once.\n            if (!privileged\n                    && MiuiUtils.isActualMiuiVersionAtLeast(\"12.5\", \"20.2.0\")\n                    && Objects.equals(statusMessage, \"INSTALL_FAILED_ABORTED: Permission denied\")\n                    && mAttempts <= 3) {\n                // Try once more\n                ++mAttempts;\n                Log.i(TAG, \"MIUI: Installation attempt no %d for package %s\", mAttempts, mPackageName);\n                mInteractionWatcher.countDown();\n                mInstallWatcher.countDown();\n                // Remove old broadcast receivers\n                unregisterReceiver();\n                mOnInstallListener.onAnotherAttemptInMiui(mApkFile);\n                return;\n            }\n            // MIUI-end\n            // HyperOS-begin: In HyperOS 2.0, installer package needs to be altered\n            if (privileged\n                    // TODO: 1/10/25 Check for HyperOS?\n                    && statusMessage != null\n                    && statusMessage.startsWith(\"INSTALL_FAILED_HYPEROS_ISOLATION_VIOLATION: \")\n                    && mAttempts <= 2) {\n                // Try a second time with installer set to shell\n                ++mAttempts;\n                Log.i(TAG, \"HyperOS: %s\", statusMessage);\n                Log.i(TAG, \"HyperOS: Second attempt for %s\", mPackageName);\n                mInteractionWatcher.countDown();\n                mInstallWatcher.countDown();\n                // Remove old broadcast receivers\n                unregisterReceiver();\n                mOnInstallListener.onSecondAttemptInHyperOsWithoutInstaller(mApkFile);\n                return;\n            }\n            // HyperOS-end\n        }\n        // No need to check package name since it's been checked before\n        if (finalStatus == STATUS_FAILURE_SESSION_CREATE || (mSessionId == sessionId)) {\n            if (mOnInstallListener != null) {\n                mOnInstallListener.onFinishedInstall(sessionId, mPackageName, finalStatus,\n                        blockingPackage, statusMessage);\n            }\n            if (mCloseApkFile && mApkFile != null) {\n                mApkFile.close();\n            }\n            mInteractionWatcher.countDown();\n            mInstallWatcher.countDown();\n        }\n    }\n\n    @SuppressWarnings(\"deprecation\")\n    public boolean uninstall(String packageName, @UserIdInt int userId, boolean keepData) {\n        ThreadUtils.ensureWorkerThread();\n        boolean hasDeletePackagesPermission = SelfPermissions.checkSelfOrRemotePermission(Manifest.permission.DELETE_PACKAGES);\n        mPackageName = Objects.requireNonNull(packageName);\n        String callerPackageName = SelfPermissions.getCallingPackage(Users.getSelfOrRemoteUid());\n        initBroadcastReceiver();\n        try {\n            if (userId == UserHandleHidden.USER_ALL && Users.getAllUserIds().length > 1\n                    && !SelfPermissions.checkSelfOrRemotePermission(ManifestCompat.permission.INTERACT_ACROSS_USERS_FULL)) {\n                installCompleted(mSessionId, STATUS_FAILURE_BLOCKED, \"android\", \"STATUS_FAILURE_BLOCKED: Insufficient permission.\");\n                Log.d(TAG, \"Uninstall: Requires INTERACT_ACROSS_USERS and INTERACT_ACROSS_USERS_FULL permissions.\");\n                return false;\n            }\n            int flags;\n            try {\n                flags = getDeleteFlags(packageName, userId, keepData);\n            } catch (Exception e) {\n                callFinish(STATUS_FAILURE_SESSION_CREATE);\n                Log.e(TAG, \"Uninstall: Could not get PackageInstaller.\", e);\n                return false;\n            }\n            userId = getCorrectUserIdForUninstallation(packageName, userId);\n            try {\n                mPackageInstaller = PackageManagerCompat.getPackageInstaller();\n            } catch (RemoteException e) {\n                callFinish(STATUS_FAILURE_SESSION_CREATE);\n                Log.e(TAG, \"Uninstall: Could not get PackageInstaller.\", e);\n                return false;\n            }\n\n            // Perform uninstallation\n            IntentSender sender;\n            LocalIntentReceiver intentReceiver;\n            if (hasDeletePackagesPermission) {\n                Log.d(TAG, \"Uninstall: Uninstall via LocalIntentReceiver...\");\n                try {\n                    intentReceiver = new LocalIntentReceiver();\n                    sender = intentReceiver.getIntentSender();\n                } catch (Exception e) {\n                    callFinish(STATUS_FAILURE_SESSION_COMMIT);\n                    Log.e(TAG, \"Uninstall: Could not uninstall %s\", e, packageName);\n                    return false;\n                }\n            } else {\n                Log.d(TAG, \"Uninstall: Calling activity to request permission...\");\n                intentReceiver = null;\n                Intent callbackIntent = new Intent(PackageInstallerBroadcastReceiver.ACTION_PI_RECEIVER);\n                callbackIntent.setPackage(BuildConfig.APPLICATION_ID);\n                PendingIntent pendingIntent = PendingIntentCompat.getBroadcast(mContext, 0, callbackIntent, 0, true);\n                sender = pendingIntent.getIntentSender();\n            }\n            Log.d(TAG, \"Uninstall: Uninstalling...\");\n            try {\n                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {\n                    mPackageInstaller.uninstall(new VersionedPackage(packageName, PackageManager.VERSION_CODE_HIGHEST),\n                            callerPackageName, flags, sender, userId);\n                } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {\n                    mPackageInstaller.uninstall(packageName, callerPackageName, flags, sender, userId);\n                } else mPackageInstaller.uninstall(packageName, flags, sender, userId);\n            } catch (Throwable th) { // primarily RemoteException\n                callFinish(STATUS_FAILURE_SESSION_COMMIT);\n                Log.e(TAG, \"Uninstall: Could not uninstall %s\", th, packageName);\n                return false;\n            }\n            if (intentReceiver == null) {\n                Log.d(TAG, \"Uninstall: Waiting for user interaction...\");\n                // Wait for user interaction (if needed)\n                try {\n                    // Wait for user interaction\n                    mInteractionWatcher.await();\n                    // Wait for the installation to complete\n                    mInstallWatcher.await(1, TimeUnit.MINUTES);\n                } catch (InterruptedException e) {\n                    Log.e(TAG, \"Installation interrupted.\", e);\n                }\n            } else {\n                Intent resultIntent = intentReceiver.getResult();\n                mFinalStatus = resultIntent.getIntExtra(PackageInstaller.EXTRA_STATUS, PackageInstaller.STATUS_FAILURE);\n                mStatusMessage = resultIntent.getStringExtra(PackageInstaller.EXTRA_STATUS_MESSAGE);\n            }\n            Log.d(TAG, \"Uninstall: Finished with status %d\", mFinalStatus);\n            if (!mInstallCompleted) {\n                installCompleted(mSessionId, mFinalStatus, null, mStatusMessage);\n            }\n            if (mFinalStatus == PackageInstaller.STATUS_SUCCESS && userId != UserHandleHidden.myUserId()) {\n                BroadcastUtils.sendPackageAltered(ContextUtils.getContext(), new String[]{packageName});\n            }\n            return mFinalStatus == PackageInstaller.STATUS_SUCCESS;\n        } finally {\n            unregisterReceiver();\n        }\n    }\n\n    @DeleteFlags\n    private static int getDeleteFlags(@NonNull String packageName, @UserIdInt int userId, boolean keepData)\n            throws PackageManager.NameNotFoundException, RemoteException {\n        int flags = 0;\n        if (userId != UserHandleHidden.USER_ALL) {\n            PackageInfo info = PackageManagerCompat.getPackageInfo(packageName, MATCH_UNINSTALLED_PACKAGES\n                    | PackageManagerCompat.MATCH_STATIC_SHARED_AND_SDK_LIBRARIES, userId);\n            final boolean isSystem = (info.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;\n            // If we are being asked to delete a system app for just one\n            // user set flag so it disables rather than reverting to system\n            // version of the app.\n            if (isSystem) {\n                flags |= DELETE_SYSTEM_APP;\n            }\n        } else {\n            flags |= DELETE_ALL_USERS;\n        }\n        if (keepData) {\n            flags |= DELETE_KEEP_DATA;\n        }\n        return flags;\n    }\n\n    private static int getCorrectUserIdForUninstallation(@NonNull String packageName, @UserIdInt int userId) {\n        if (userId == UserHandleHidden.USER_ALL) {\n            int[] users = Users.getAllUserIds();\n            for (int user : users) {\n                try {\n                    PackageManagerCompat.getPackageInfo(packageName, MATCH_UNINSTALLED_PACKAGES\n                            | PackageManagerCompat.MATCH_STATIC_SHARED_AND_SDK_LIBRARIES, user);\n                    return user;\n                } catch (Throwable ignore) {\n                }\n            }\n        }\n        return userId;\n    }\n\n    // https://cs.android.com/android/platform/superproject/+/master:frameworks/base/services/core/java/com/android/server/pm/PackageManagerShellCommand.java;l=3855;drc=d31ee388115d17c2fd337f2806b37390c7d29834\n    private static class LocalIntentReceiver {\n        private final LinkedBlockingQueue<Intent> mResult = new LinkedBlockingQueue<>();\n\n        private final IIntentSender.Stub mLocalSender = new IIntentSender.Stub() {\n            @Override\n            public int send(int code, Intent intent, String resolvedType, IIntentReceiver finishedReceiver, String requiredPermission) {\n                send(intent);\n                return 0;\n            }\n\n            @Override\n            public int send(int code, Intent intent, String resolvedType, IIntentReceiver finishedReceiver, String requiredPermission, Bundle options) {\n                send(intent);\n                return 0;\n            }\n\n            @Override\n            public void send(int code, Intent intent, String resolvedType, IBinder whitelistToken, IIntentReceiver finishedReceiver, String requiredPermission, Bundle options) {\n                send(intent);\n            }\n\n            public void send(Intent intent) {\n                try {\n                    mResult.offer(intent, 5, TimeUnit.SECONDS);\n                } catch (InterruptedException e) {\n                    throw new RuntimeException(e);\n                }\n            }\n        };\n\n        @SuppressWarnings(\"JavaReflectionMemberAccess\")\n        public IntentSender getIntentSender() throws Exception {\n            return IntentSender.class.getConstructor(IBinder.class)\n                    .newInstance(mLocalSender.asBinder());\n        }\n\n        public Intent getResult() {\n            try {\n                return mResult.take();\n            } catch (InterruptedException e) {\n                throw new RuntimeException(e);\n            }\n        }\n    }\n\n    private void unregisterReceiver() {\n        if (mPkgInstallerReceiver != null) {\n            ContextUtils.unregisterReceiver(mContext, mPkgInstallerReceiver);\n        }\n        ContextUtils.unregisterReceiver(mContext, mBroadcastReceiver);\n    }\n\n    private void initBroadcastReceiver() {\n        mInstallWatcher = new CountDownLatch(1);\n        mInteractionWatcher = new CountDownLatch(1);\n        mPkgInstallerReceiver = new PackageInstallerBroadcastReceiver();\n        mPkgInstallerReceiver.setAppLabel(mAppLabel);\n        mPkgInstallerReceiver.setPackageName(mPackageName);\n        ContextCompat.registerReceiver(mContext, mPkgInstallerReceiver,\n                new IntentFilter(PackageInstallerBroadcastReceiver.ACTION_PI_RECEIVER),\n                ContextCompat.RECEIVER_NOT_EXPORTED);\n        // Add receivers\n        IntentFilter intentFilter = new IntentFilter();\n        intentFilter.addAction(ACTION_INSTALL_COMPLETED);\n        intentFilter.addAction(ACTION_INSTALL_STARTED);\n        intentFilter.addAction(ACTION_INSTALL_INTERACTION_BEGIN);\n        intentFilter.addAction(ACTION_INSTALL_INTERACTION_END);\n        ContextCompat.registerReceiver(mContext, mBroadcastReceiver, intentFilter, ContextCompat.RECEIVER_NOT_EXPORTED);\n    }\n\n    private void sendStartedBroadcast(@NonNull String packageName, int sessionId) {\n        Intent broadcastIntent = new Intent(ACTION_INSTALL_STARTED);\n        broadcastIntent.setPackage(mContext.getPackageName());\n        broadcastIntent.putExtra(PackageInstaller.EXTRA_PACKAGE_NAME, packageName);\n        broadcastIntent.putExtra(PackageInstaller.EXTRA_SESSION_ID, sessionId);\n        mContext.sendBroadcast(broadcastIntent);\n    }\n\n    static void sendCompletedBroadcast(@NonNull Context context, @NonNull String packageName, @Status int status,\n                                       int sessionId) {\n        Intent broadcastIntent = new Intent(ACTION_INSTALL_COMPLETED);\n        broadcastIntent.setPackage(context.getPackageName());\n        broadcastIntent.putExtra(PackageInstaller.EXTRA_PACKAGE_NAME, packageName);\n        broadcastIntent.putExtra(PackageInstaller.EXTRA_STATUS, status);\n        broadcastIntent.putExtra(PackageInstaller.EXTRA_SESSION_ID, sessionId);\n        context.sendBroadcast(broadcastIntent);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/apk/installer/PackageInstallerService.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.apk.installer;\n\nimport static io.github.muntashirakon.AppManager.apk.installer.PackageInstallerCompat.STATUS_FAILURE_ABORTED;\nimport static io.github.muntashirakon.AppManager.apk.installer.PackageInstallerCompat.STATUS_FAILURE_BLOCKED;\nimport static io.github.muntashirakon.AppManager.apk.installer.PackageInstallerCompat.STATUS_FAILURE_CONFLICT;\nimport static io.github.muntashirakon.AppManager.apk.installer.PackageInstallerCompat.STATUS_FAILURE_INCOMPATIBLE;\nimport static io.github.muntashirakon.AppManager.apk.installer.PackageInstallerCompat.STATUS_FAILURE_INCOMPATIBLE_ROM;\nimport static io.github.muntashirakon.AppManager.apk.installer.PackageInstallerCompat.STATUS_FAILURE_INVALID;\nimport static io.github.muntashirakon.AppManager.apk.installer.PackageInstallerCompat.STATUS_FAILURE_SECURITY;\nimport static io.github.muntashirakon.AppManager.apk.installer.PackageInstallerCompat.STATUS_FAILURE_SESSION_ABANDON;\nimport static io.github.muntashirakon.AppManager.apk.installer.PackageInstallerCompat.STATUS_FAILURE_SESSION_COMMIT;\nimport static io.github.muntashirakon.AppManager.apk.installer.PackageInstallerCompat.STATUS_FAILURE_SESSION_CREATE;\nimport static io.github.muntashirakon.AppManager.apk.installer.PackageInstallerCompat.STATUS_FAILURE_SESSION_WRITE;\nimport static io.github.muntashirakon.AppManager.apk.installer.PackageInstallerCompat.STATUS_FAILURE_STORAGE;\nimport static io.github.muntashirakon.AppManager.apk.installer.PackageInstallerCompat.STATUS_SUCCESS;\nimport static io.github.muntashirakon.AppManager.history.ops.OpHistoryManager.HISTORY_TYPE_INSTALLER;\n\nimport android.app.PendingIntent;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.os.Build;\nimport android.os.PowerManager;\nimport android.os.UserHandleHidden;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.UiThread;\nimport androidx.core.app.NotificationCompat;\nimport androidx.core.app.NotificationManagerCompat;\nimport androidx.core.app.PendingIntentCompat;\nimport androidx.core.app.ServiceCompat;\n\nimport java.util.List;\nimport java.util.Objects;\n\nimport io.github.muntashirakon.AppManager.BuildConfig;\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.apk.ApkFile;\nimport io.github.muntashirakon.AppManager.apk.ApkSource;\nimport io.github.muntashirakon.AppManager.apk.CachedApkSource;\nimport io.github.muntashirakon.AppManager.apk.dexopt.DexOptimizer;\nimport io.github.muntashirakon.AppManager.compat.PackageManagerCompat;\nimport io.github.muntashirakon.AppManager.history.ops.OpHistoryManager;\nimport io.github.muntashirakon.AppManager.intercept.IntentCompat;\nimport io.github.muntashirakon.AppManager.logs.Log;\nimport io.github.muntashirakon.AppManager.main.MainActivity;\nimport io.github.muntashirakon.AppManager.progress.NotificationProgressHandler;\nimport io.github.muntashirakon.AppManager.progress.NotificationProgressHandler.NotificationInfo;\nimport io.github.muntashirakon.AppManager.progress.ProgressHandler;\nimport io.github.muntashirakon.AppManager.progress.QueuedProgressHandler;\nimport io.github.muntashirakon.AppManager.rules.compontents.ComponentUtils;\nimport io.github.muntashirakon.AppManager.types.ForegroundService;\nimport io.github.muntashirakon.AppManager.types.UserPackagePair;\nimport io.github.muntashirakon.AppManager.utils.CpuUtils;\nimport io.github.muntashirakon.AppManager.utils.NotificationUtils;\nimport io.github.muntashirakon.AppManager.utils.PackageUtils;\nimport io.github.muntashirakon.AppManager.utils.ThreadUtils;\n\npublic class PackageInstallerService extends ForegroundService {\n    public static final String TAG = PackageInstallerService.class.getSimpleName();\n\n    public static final String EXTRA_QUEUE_ITEM = \"queue_item\";\n    public static final String CHANNEL_ID = BuildConfig.APPLICATION_ID + \".channel.INSTALL\";\n\n    public interface OnInstallFinished {\n        @UiThread\n        void onFinished(String packageName, int status, @Nullable String blockingPackage,\n                        @Nullable String statusMessage);\n    }\n\n    public PackageInstallerService() {\n        super(TAG);\n    }\n\n    @Nullable\n    private OnInstallFinished mOnInstallFinished;\n    private QueuedProgressHandler mProgressHandler;\n    private NotificationInfo mNotificationInfo;\n    private PowerManager.WakeLock mWakeLock;\n\n    @Override\n    public void onCreate() {\n        super.onCreate();\n        mWakeLock = CpuUtils.getPartialWakeLock(\"installer\");\n        mWakeLock.acquire();\n    }\n\n    @Override\n    public int onStartCommand(@Nullable Intent intent, int flags, int startId) {\n        if (isWorking()) {\n            return super.onStartCommand(intent, flags, startId);\n        }\n        mProgressHandler = new NotificationProgressHandler(\n                this,\n                new NotificationProgressHandler.NotificationManagerInfo(CHANNEL_ID, \"Install Progress\", NotificationManagerCompat.IMPORTANCE_LOW),\n                NotificationUtils.HIGH_PRIORITY_NOTIFICATION_INFO,\n                NotificationUtils.HIGH_PRIORITY_NOTIFICATION_INFO\n        );\n        mProgressHandler.setProgressTextInterface(ProgressHandler.PROGRESS_PERCENT);\n        Intent notificationIntent = new Intent(this, MainActivity.class);\n        PendingIntent pendingIntent = PendingIntentCompat.getActivity(this, 0, notificationIntent, 0, false);\n        mNotificationInfo = new NotificationInfo()\n                .setBody(getString(R.string.install_in_progress))\n                .setOperationName(getText(R.string.package_installer))\n                .setDefaultAction(pendingIntent);\n        mProgressHandler.onAttach(this, mNotificationInfo);\n        return super.onStartCommand(intent, flags, startId);\n    }\n\n    @Override\n    protected void onHandleIntent(@Nullable Intent intent) {\n        ApkQueueItem apkQueueItem = getQueueItem(intent);\n        if (apkQueueItem == null) {\n            return;\n        }\n        InstallerOptions options = apkQueueItem.getInstallerOptions() != null\n                ? apkQueueItem.getInstallerOptions()\n                : InstallerOptions.getDefault();\n        List<String> selectedSplitIds = Objects.requireNonNull(apkQueueItem.getSelectedSplits());\n        // Install package\n        PackageInstallerCompat installer = PackageInstallerCompat.getNewInstance();\n        installer.setAppLabel(apkQueueItem.getAppLabel());\n        installer.setOnInstallListener(new PackageInstallerCompat.OnInstallListener() {\n            @Override\n            public void onStartInstall(int sessionId, String packageName) {\n            }\n\n            // MIUI-begin: MIUI 12.5+ workaround\n            @Override\n            public void onAnotherAttemptInMiui(@Nullable ApkFile apkFile) {\n                if (apkFile != null) {\n                    installer.install(apkFile, selectedSplitIds, options, mProgressHandler);\n                }\n            }\n            // MIUI-end\n\n            // HyperOS-begin: HyperOS 2.0+ workaround\n            @Override\n            public void onSecondAttemptInHyperOsWithoutInstaller(@Nullable ApkFile apkFile) {\n                if (apkFile != null) {\n                    options.setInstallerName(\"com.android.shell\");\n                    installer.install(apkFile, selectedSplitIds, options, mProgressHandler);\n                }\n            }\n            // HyerOS-end\n\n            @Override\n            public void onFinishedInstall(int sessionId, String packageName, int result,\n                                          @Nullable String blockingPackage, @Nullable String statusMessage) {\n                boolean success = result == STATUS_SUCCESS;\n                OpHistoryManager.addHistoryItem(HISTORY_TYPE_INSTALLER, apkQueueItem, success);\n                if (success) {\n                    // Block trackers if requested\n                    if (options.isBlockTrackers()) {\n                        ComponentUtils.blockTrackingComponents(new UserPackagePair(packageName, options.getUserId()));\n                    }\n                    // Perform force dex optimization if requested\n                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && options.isForceDexOpt()) {\n                        // Ignore the result because it's irrelevant\n                        new DexOptimizer(PackageManagerCompat.getPackageManager(), packageName).forceDexOpt();\n                    }\n                }\n                finishInstallation(packageName, result, apkQueueItem.getAppLabel(), blockingPackage, statusMessage);\n            }\n        });\n        // Two possibilities: 1. Install-existing, 2. ApkFile/Uri\n        if (apkQueueItem.isInstallExisting()) {\n            // Install existing (need no progress)\n            String packageName = apkQueueItem.getPackageName();\n            if (packageName == null) {\n                // No package name supplied, abort\n                return;\n            }\n            installer.installExisting(packageName, options.getUserId());\n        } else {\n            // ApkFile/Uri\n            ApkSource apkSource = apkQueueItem.getApkSource();\n            if (apkSource == null) {\n                // No apk file, abort\n                return;\n            }\n            ApkFile apkFile;\n            try {\n                try {\n                    apkFile = apkSource.resolve();\n                } catch (Throwable th) {\n                    Log.w(TAG, \"Could not get ApkFile\", th);\n                    OpHistoryManager.addHistoryItem(HISTORY_TYPE_INSTALLER, apkQueueItem, false);\n                    String packageName = apkQueueItem.getPackageName();\n                    finishInstallation(packageName != null ? packageName : \"Unknown Package\", STATUS_FAILURE_INVALID, apkQueueItem.getAppLabel(), null, null);\n                    return;\n                }\n                installer.install(apkFile, selectedSplitIds, options, mProgressHandler);\n            } finally {\n                // Delete the cached file\n                if (apkSource instanceof CachedApkSource) {\n                    ((CachedApkSource) apkSource).cleanup();\n                }\n            }\n        }\n    }\n\n    @Override\n    protected void onQueued(@Nullable Intent intent) {\n        ApkQueueItem apkQueueItem = getQueueItem(intent);\n        String appLabel = apkQueueItem != null ? apkQueueItem.getAppLabel() : null;\n        Object notificationInfo = new NotificationInfo()\n                .setAutoCancel(true)\n                .setOperationName(getString(R.string.package_installer))\n                .setTitle(appLabel)\n                .setBody(getString(R.string.added_to_queue))\n                .setTime(System.currentTimeMillis());\n        mProgressHandler.onQueue(notificationInfo);\n    }\n\n    @Override\n    protected void onStartIntent(@Nullable Intent intent) {\n        // Set app name in the ongoing notification\n        ApkQueueItem apkQueueItem = getQueueItem(intent);\n        String appName;\n        if (apkQueueItem != null) {\n            String appLabel = apkQueueItem.getAppLabel();\n            appName = appLabel != null ? appLabel : apkQueueItem.getPackageName();\n        } else appName = null;\n        CharSequence title;\n        if (appName != null) {\n            title = getString(R.string.installing_package, appName);\n        } else {\n            title = getString(R.string.install_in_progress);\n        }\n        mNotificationInfo.setTitle(title);\n        mProgressHandler.onProgressStart(-1, 0, mNotificationInfo);\n    }\n\n    @Override\n    public void onDestroy() {\n        ServiceCompat.stopForeground(this, ServiceCompat.STOP_FOREGROUND_REMOVE);\n        if (mProgressHandler != null) {\n            mProgressHandler.onDetach(this);\n        }\n        CpuUtils.releaseWakeLock(mWakeLock);\n        super.onDestroy();\n    }\n\n    public void setOnInstallFinished(@Nullable OnInstallFinished onInstallFinished) {\n        this.mOnInstallFinished = onInstallFinished;\n    }\n\n    @Nullable\n    private ApkQueueItem getQueueItem(@Nullable Intent intent) {\n        if (intent == null) {\n            return null;\n        }\n        return IntentCompat.getUnwrappedParcelableExtra(intent, EXTRA_QUEUE_ITEM, ApkQueueItem.class);\n    }\n\n    private void finishInstallation(@NonNull String packageName, int status,\n                                    @Nullable String appLabel, @Nullable String blockingPackage,\n                                    @Nullable String statusMessage) {\n        if (mOnInstallFinished != null) {\n            ThreadUtils.postOnMainThread(() -> {\n                if (mOnInstallFinished != null) {\n                    mOnInstallFinished.onFinished(packageName, status, blockingPackage, statusMessage);\n                }\n            });\n        } else {\n            sendNotification(packageName, status, appLabel, blockingPackage, statusMessage);\n        }\n    }\n\n    private void sendNotification(@NonNull String packageName,\n                                  @PackageInstallerCompat.Status int status,\n                                  @Nullable String appLabel,\n                                  @Nullable String blockingPackage,\n                                  @Nullable String statusMessage) {\n        Intent intent = PackageManagerCompat.getLaunchIntentForPackage(packageName, UserHandleHidden.myUserId());\n        PendingIntent defaultAction = intent != null ? PendingIntentCompat.getActivity(this, 0, intent,\n                PendingIntent.FLAG_ONE_SHOT, false) : null;\n        String subject = getStringFromStatus(this, status, appLabel, blockingPackage);\n        NotificationCompat.Style content = statusMessage != null ? new NotificationCompat.BigTextStyle()\n                .bigText(subject + \"\\n\\n\" + statusMessage) : null;\n        Object notificationInfo = new NotificationInfo()\n                .setAutoCancel(true)\n                .setTime(System.currentTimeMillis())\n                .setOperationName(getText(R.string.package_installer))\n                .setTitle(appLabel)\n                .setBody(subject)\n                .setStyle(content)\n                .setDefaultAction(defaultAction);\n        NotificationInfo progressNotificationInfo = (NotificationInfo) mProgressHandler.getLastMessage();\n        if (progressNotificationInfo != null) {\n            progressNotificationInfo.setBody(getString(R.string.done));\n        }\n        mProgressHandler.setProgressTextInterface(null);\n        ThreadUtils.postOnMainThread(() -> mProgressHandler.onResult(notificationInfo));\n    }\n\n    @NonNull\n    public static String getStringFromStatus(@NonNull Context context,\n                                             @PackageInstallerCompat.Status int status,\n                                             @Nullable CharSequence appLabel,\n                                             @Nullable String blockingPackage) {\n        switch (status) {\n            case STATUS_SUCCESS:\n                return context.getString(R.string.package_name_is_installed_successfully, appLabel);\n            case STATUS_FAILURE_ABORTED:\n                return context.getString(R.string.installer_error_aborted);\n            case STATUS_FAILURE_BLOCKED:\n                String blocker = context.getString(R.string.installer_error_blocked_device);\n                if (blockingPackage != null) {\n                    blocker = PackageUtils.getPackageLabel(context.getPackageManager(), blockingPackage);\n                }\n                return context.getString(R.string.installer_error_blocked, blocker);\n            case STATUS_FAILURE_CONFLICT:\n                return context.getString(R.string.installer_error_conflict);\n            case STATUS_FAILURE_INCOMPATIBLE:\n                return context.getString(R.string.installer_error_incompatible);\n            case STATUS_FAILURE_INVALID:\n                return context.getString(R.string.installer_error_bad_apks);\n            case STATUS_FAILURE_STORAGE:\n                return context.getString(R.string.installer_error_storage);\n            case STATUS_FAILURE_SECURITY:\n                return context.getString(R.string.installer_error_security);\n            case STATUS_FAILURE_SESSION_CREATE:\n                return context.getString(R.string.installer_error_session_create);\n            case STATUS_FAILURE_SESSION_WRITE:\n                return context.getString(R.string.installer_error_session_write);\n            case STATUS_FAILURE_SESSION_COMMIT:\n                return context.getString(R.string.installer_error_session_commit);\n            case STATUS_FAILURE_SESSION_ABANDON:\n                return context.getString(R.string.installer_error_session_abandon);\n            case STATUS_FAILURE_INCOMPATIBLE_ROM:\n                return context.getString(R.string.installer_error_lidl_rom);\n        }\n        return context.getString(R.string.installer_error_generic);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/apk/installer/PackageInstallerViewModel.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.apk.installer;\n\nimport static io.github.muntashirakon.AppManager.compat.PackageManagerCompat.GET_SIGNING_CERTIFICATES;\nimport static io.github.muntashirakon.AppManager.compat.PackageManagerCompat.GET_SIGNING_CERTIFICATES_APK;\nimport static io.github.muntashirakon.AppManager.compat.PackageManagerCompat.MATCH_DISABLED_COMPONENTS;\nimport static io.github.muntashirakon.AppManager.compat.PackageManagerCompat.MATCH_UNINSTALLED_PACKAGES;\n\nimport android.annotation.SuppressLint;\nimport android.app.Application;\nimport android.content.pm.PackageInfo;\nimport android.content.pm.PackageManager;\nimport android.graphics.drawable.Drawable;\nimport android.os.UserHandleHidden;\n\nimport androidx.annotation.AnyThread;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.WorkerThread;\nimport androidx.lifecycle.AndroidViewModel;\nimport androidx.lifecycle.LiveData;\nimport androidx.lifecycle.MutableLiveData;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashSet;\nimport java.util.Set;\nimport java.util.concurrent.Future;\n\nimport io.github.muntashirakon.AppManager.apk.ApkFile;\nimport io.github.muntashirakon.AppManager.apk.ApkSource;\nimport io.github.muntashirakon.AppManager.logs.Log;\nimport io.github.muntashirakon.AppManager.rules.compontents.ComponentUtils;\nimport io.github.muntashirakon.AppManager.utils.PackageUtils;\nimport io.github.muntashirakon.AppManager.utils.ThreadUtils;\nimport io.github.muntashirakon.io.IoUtils;\n\npublic class PackageInstallerViewModel extends AndroidViewModel {\n    private final PackageManager mPm;\n    private PackageInfo mNewPackageInfo;\n    private PackageInfo mInstalledPackageInfo;\n    private ApkSource mApkSource;\n    private ApkFile mApkFile;\n    private String mPackageName;\n    private String mAppLabel;\n    private Drawable mAppIcon;\n    private boolean mIsSignatureDifferent = false;\n    private int mTrackerCount;\n    @Nullable\n    private Future<?> mPackageInfoResult;\n    private final MutableLiveData<PackageInfo> mPackageInfoLiveData = new MutableLiveData<>();\n    private final MutableLiveData<Boolean> mPackageUninstalledLiveData = new MutableLiveData<>();\n    private final Set<String> mSelectedSplits = new HashSet<>();\n\n    public PackageInstallerViewModel(@NonNull Application application) {\n        super(application);\n        mPm = application.getPackageManager();\n    }\n\n    @Override\n    protected void onCleared() {\n        IoUtils.closeQuietly(mApkFile);\n        if (mPackageInfoResult != null) {\n            mPackageInfoResult.cancel(true);\n        }\n        super.onCleared();\n    }\n\n    public LiveData<PackageInfo> packageInfoLiveData() {\n        return mPackageInfoLiveData;\n    }\n\n    public LiveData<Boolean> packageUninstalledLiveData() {\n        return mPackageUninstalledLiveData;\n    }\n\n    @AnyThread\n    public void getPackageInfo(ApkQueueItem apkQueueItem) {\n        if (mPackageInfoResult != null) {\n            mPackageInfoResult.cancel(true);\n        }\n        mSelectedSplits.clear();\n        mPackageInfoResult = ThreadUtils.postOnBackgroundThread(() -> {\n            try {\n                // Three possibilities: 1. Install-existing, 2. ApkFile, 3. Uri\n                if (apkQueueItem.isInstallExisting()) {\n                    if (apkQueueItem.getPackageName() == null) {\n                        throw new IllegalArgumentException(\"Package name not set for install-existing.\");\n                    }\n                    getExistingPackageInfoInternal(apkQueueItem.getPackageName());\n                } else if (apkQueueItem.getApkSource() != null) {\n                    mApkSource = apkQueueItem.getApkSource();\n                    getPackageInfoInternal();\n                } else {\n                    throw new IllegalArgumentException(\"Invalid queue item.\");\n                }\n                apkQueueItem.setApkSource(mApkSource);\n                apkQueueItem.setPackageName(mPackageName);\n                apkQueueItem.setAppLabel(mAppLabel);\n            } catch (Throwable th) {\n                Log.e(\"PIVM\", \"Couldn't fetch package info\", th);\n                mPackageInfoLiveData.postValue(null);\n            }\n        });\n    }\n\n    public void uninstallPackage() {\n        ThreadUtils.postOnBackgroundThread(() -> {\n            PackageInstallerCompat installer = PackageInstallerCompat.getNewInstance();\n            installer.setAppLabel(mAppLabel);\n            mPackageUninstalledLiveData.postValue(installer.uninstall(mPackageName, UserHandleHidden.USER_ALL, false));\n        });\n    }\n\n    public PackageInfo getNewPackageInfo() {\n        return mNewPackageInfo;\n    }\n\n    @Nullable\n    public PackageInfo getInstalledPackageInfo() {\n        return mInstalledPackageInfo;\n    }\n\n    public String getAppLabel() {\n        return mAppLabel;\n    }\n\n    public Drawable getAppIcon() {\n        return mAppIcon;\n    }\n\n    public String getPackageName() {\n        return mPackageName;\n    }\n\n    public ApkFile getApkFile() {\n        return mApkFile;\n    }\n\n    public ApkSource getApkSource() {\n        return mApkSource;\n    }\n\n    public int getTrackerCount() {\n        return mTrackerCount;\n    }\n\n    public boolean isSignatureDifferent() {\n        return mIsSignatureDifferent;\n    }\n\n    public Set<String> getSelectedSplits() {\n        return mSelectedSplits;\n    }\n\n    @NonNull\n    public ArrayList<String> getSelectedSplitsForInstallation() {\n        if (mApkFile.isSplit()) {\n            if (mSelectedSplits.isEmpty()) {\n                throw new IllegalArgumentException(\"No splits selected.\");\n            }\n            return new ArrayList<>(mSelectedSplits);\n        }\n        return new ArrayList<>(Collections.singletonList(mApkFile.getBaseEntry().id));\n    }\n\n    private void getPackageInfoInternal() throws PackageManager.NameNotFoundException, IOException, ApkFile.ApkFileException {\n        mApkFile = mApkSource.resolve();\n        mNewPackageInfo = loadNewPackageInfo();\n        mPackageName = mNewPackageInfo.packageName;\n        if (ThreadUtils.isInterrupted()) {\n            return;\n        }\n        try {\n            mInstalledPackageInfo = loadInstalledPackageInfo(mPackageName);\n            if (ThreadUtils.isInterrupted()) {\n                return;\n            }\n        } catch (PackageManager.NameNotFoundException ignore) {\n        }\n        mAppLabel = mPm.getApplicationLabel(mNewPackageInfo.applicationInfo).toString();\n        mAppIcon = mPm.getApplicationIcon(mNewPackageInfo.applicationInfo);\n        mTrackerCount = ComponentUtils.getTrackerComponentsCountForPackage(mNewPackageInfo);\n        if (ThreadUtils.isInterrupted()) {\n            return;\n        }\n        if (mNewPackageInfo != null && mInstalledPackageInfo != null) {\n            mIsSignatureDifferent = PackageUtils.isSignatureDifferent(mNewPackageInfo, mInstalledPackageInfo);\n        }\n        mPackageInfoLiveData.postValue(mNewPackageInfo);\n    }\n\n    private void getExistingPackageInfoInternal(@NonNull String packageName) throws PackageManager.NameNotFoundException, IOException, ApkFile.ApkFileException {\n        mPackageName = packageName;\n        mInstalledPackageInfo = loadInstalledPackageInfo(packageName);\n        mApkSource = ApkSource.getApkSource(mInstalledPackageInfo.applicationInfo);\n        mApkFile = mApkSource.resolve();\n        mNewPackageInfo = loadNewPackageInfo();\n        mAppLabel = mPm.getApplicationLabel(mNewPackageInfo.applicationInfo).toString();\n        mAppIcon = mPm.getApplicationIcon(mNewPackageInfo.applicationInfo);\n        mTrackerCount = ComponentUtils.getTrackerComponentsCountForPackage(mNewPackageInfo);\n        if (mNewPackageInfo != null && mInstalledPackageInfo != null) {\n            mIsSignatureDifferent = PackageUtils.isSignatureDifferent(mNewPackageInfo, mInstalledPackageInfo);\n        }\n        mPackageInfoLiveData.postValue(mNewPackageInfo);\n    }\n\n    @WorkerThread\n    @NonNull\n    private PackageInfo loadNewPackageInfo() throws PackageManager.NameNotFoundException, IOException {\n        String apkPath = mApkFile.getBaseEntry().getFile(false).getAbsolutePath();\n        int flags = PackageManager.GET_PERMISSIONS\n                | PackageManager.GET_ACTIVITIES | PackageManager.GET_RECEIVERS | PackageManager.GET_PROVIDERS\n                | PackageManager.GET_SERVICES | MATCH_DISABLED_COMPONENTS | GET_SIGNING_CERTIFICATES_APK\n                | PackageManager.GET_CONFIGURATIONS | PackageManager.GET_SHARED_LIBRARY_FILES;\n        PackageInfo packageInfo = mPm.getPackageArchiveInfo(apkPath, flags);\n        if (packageInfo == null) {\n            // Previous method could return null if the APK isn't signed. So, try without it.\n            packageInfo = mPm.getPackageArchiveInfo(apkPath, flags & ~GET_SIGNING_CERTIFICATES_APK);\n        }\n        if (packageInfo == null) {\n            throw new PackageManager.NameNotFoundException(\"Package cannot be parsed.\");\n        }\n        packageInfo.applicationInfo.sourceDir = apkPath;\n        packageInfo.applicationInfo.publicSourceDir = apkPath;\n        return packageInfo;\n    }\n\n    @WorkerThread\n    @NonNull\n    private PackageInfo loadInstalledPackageInfo(String packageName) throws PackageManager.NameNotFoundException {\n        @SuppressLint(\"WrongConstant\")\n        PackageInfo packageInfo = mPm.getPackageInfo(packageName, PackageManager.GET_PERMISSIONS\n                | PackageManager.GET_ACTIVITIES | PackageManager.GET_RECEIVERS | PackageManager.GET_PROVIDERS\n                | PackageManager.GET_SERVICES | MATCH_DISABLED_COMPONENTS | GET_SIGNING_CERTIFICATES | MATCH_UNINSTALLED_PACKAGES\n                | PackageManager.GET_CONFIGURATIONS | PackageManager.GET_SHARED_LIBRARY_FILES);\n        if (packageInfo == null) throw new PackageManager.NameNotFoundException(\"Package not found.\");\n        return packageInfo;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/apk/installer/SupportedAppStores.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.apk.installer;\n\nimport androidx.annotation.NonNull;\n\nimport java.util.HashMap;\n\npublic final class SupportedAppStores {\n    public static HashMap<String, CharSequence> SUPPORTED_APP_STORES =\n            new HashMap<String, CharSequence>() {{\n                // Sorted by app label\n                put(\"com.aurora.store\", \"Aurora Store\");\n                put(\"com.looker.droidify\", \"Droid-ify\");\n                put(\"org.fdroid.fdroid\", \"F-Droid\");\n                put(\"org.fdroid.basic\", \"F-Droid Basic\");\n                put(\"eu.bubu1.fdroidclassic\", \"F-Droid Classic\");\n                put(\"com.machiav3lli.fdroid\", \"Neo Store\");\n            }};\n\n    public static boolean isAppStoreSupported(@NonNull String packageName) {\n        return SUPPORTED_APP_STORES.containsKey(packageName);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/apk/list/AppListItem.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.apk.list;\n\nimport android.graphics.Bitmap;\n\npublic class AppListItem {\n    public final String packageName;\n    private Bitmap mIcon;\n    private String mPackageLabel;\n    private long mVersionCode;\n    private String mVersionName;\n    private int mMinSdk;\n    private int mTargetSdk;\n    private String mSignatureSha256;\n    private long mFirstInstallTime;\n    private long mLastUpdateTime;\n    private String mInstallerPackageName;\n    private String mInstallerPackageLabel;\n\n    public AppListItem(String packageName) {\n        this.packageName = packageName;\n    }\n\n    public Bitmap getIcon() {\n        return mIcon;\n    }\n\n    public void setIcon(Bitmap icon) {\n        mIcon = icon;\n    }\n\n    public String getPackageLabel() {\n        return mPackageLabel;\n    }\n\n    public void setPackageLabel(String packageLabel) {\n        mPackageLabel = packageLabel;\n    }\n\n    public long getVersionCode() {\n        return mVersionCode;\n    }\n\n    public void setVersionCode(long versionCode) {\n        mVersionCode = versionCode;\n    }\n\n    public String getVersionName() {\n        return mVersionName;\n    }\n\n    public void setVersionName(String versionName) {\n        mVersionName = versionName;\n    }\n\n    public int getMinSdk() {\n        return mMinSdk;\n    }\n\n    public void setMinSdk(int minSdk) {\n        mMinSdk = minSdk;\n    }\n\n    public int getTargetSdk() {\n        return mTargetSdk;\n    }\n\n    public void setTargetSdk(int targetSdk) {\n        mTargetSdk = targetSdk;\n    }\n\n    public String getSignatureSha256() {\n        return mSignatureSha256;\n    }\n\n    public void setSignatureSha256(String signatureSha256) {\n        mSignatureSha256 = signatureSha256;\n    }\n\n    public long getFirstInstallTime() {\n        return mFirstInstallTime;\n    }\n\n    public void setFirstInstallTime(long firstInstallTime) {\n        mFirstInstallTime = firstInstallTime;\n    }\n\n    public long getLastUpdateTime() {\n        return mLastUpdateTime;\n    }\n\n    public void setLastUpdateTime(long lastUpdateTime) {\n        mLastUpdateTime = lastUpdateTime;\n    }\n\n    public String getInstallerPackageName() {\n        return mInstallerPackageName;\n    }\n\n    public void setInstallerPackageName(String installerPackageName) {\n        mInstallerPackageName = installerPackageName;\n    }\n\n    public String getInstallerPackageLabel() {\n        return mInstallerPackageLabel;\n    }\n\n    public void setInstallerPackageLabel(String installerPackageLabel) {\n        mInstallerPackageLabel = installerPackageLabel;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/apk/list/ListExporter.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.apk.list;\n\nimport android.content.Context;\nimport android.content.pm.ApplicationInfo;\nimport android.content.pm.PackageInfo;\nimport android.content.pm.PackageManager;\nimport android.os.Build;\nimport android.os.UserHandleHidden;\nimport android.text.TextUtils;\nimport android.util.Xml;\n\nimport androidx.annotation.IntDef;\nimport androidx.annotation.NonNull;\nimport androidx.core.content.pm.PackageInfoCompat;\n\nimport org.json.JSONArray;\nimport org.json.JSONException;\nimport org.json.JSONObject;\nimport org.xmlpull.v1.XmlSerializer;\n\nimport java.io.IOException;\nimport java.io.Writer;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport io.github.muntashirakon.AppManager.compat.PackageManagerCompat;\nimport io.github.muntashirakon.AppManager.utils.DateUtils;\nimport io.github.muntashirakon.AppManager.utils.ExUtils;\nimport io.github.muntashirakon.AppManager.utils.PackageUtils;\nimport io.github.muntashirakon.AppManager.utils.UIUtils;\nimport io.github.muntashirakon.csv.CsvWriter;\n\npublic final class ListExporter {\n    public static final int EXPORT_TYPE_CSV = 0;\n    public static final int EXPORT_TYPE_JSON = 1;\n    public static final int EXPORT_TYPE_XML = 2;\n    public static final int EXPORT_TYPE_MARKDOWN = 3;\n\n    @IntDef({EXPORT_TYPE_CSV, EXPORT_TYPE_JSON, EXPORT_TYPE_XML, EXPORT_TYPE_MARKDOWN})\n    @Retention(RetentionPolicy.SOURCE)\n    public @interface ExportType {\n    }\n\n    public static void export(@NonNull Context context,\n                              @NonNull Writer writer,\n                              @ExportType int exportType,\n                              @NonNull List<PackageInfo> packageInfoList) throws IOException {\n        List<AppListItem> appListItems = getAppListItems(context, packageInfoList);\n        switch (exportType) {\n            case EXPORT_TYPE_CSV:\n                exportCsv(writer, appListItems);\n                return;\n            case EXPORT_TYPE_JSON:\n                try {\n                    exportJson(writer, appListItems);\n                } catch (JSONException e) {\n                    ExUtils.rethrowAsIOException(e);\n                }\n                return;\n            case EXPORT_TYPE_XML:\n                exportXml(writer, appListItems);\n                return;\n            case EXPORT_TYPE_MARKDOWN:\n                exportMarkdown(context, writer, appListItems);\n                return;\n        }\n        throw new IllegalArgumentException(\"Invalid export type: \" + exportType);\n    }\n\n    private static void exportXml(@NonNull Writer writer,\n                                  @NonNull List<AppListItem> appListItems) throws IOException {\n        XmlSerializer xmlSerializer = Xml.newSerializer();\n        xmlSerializer.setOutput(writer);\n        xmlSerializer.startDocument(\"UTF-8\", true);\n        xmlSerializer.docdecl(\"packages SYSTEM \\\"https://raw.githubusercontent.com/MuntashirAkon/AppManager/master/schema/packages.dtd\\\"\");\n        xmlSerializer.startTag(\"\", \"packages\");\n        xmlSerializer.attribute(\"\", \"version\", String.valueOf(1));\n        for (AppListItem appListItem : appListItems) {\n            xmlSerializer.startTag(\"\", \"package\");\n            xmlSerializer.attribute(\"\", \"name\", appListItem.packageName);\n            xmlSerializer.attribute(\"\", \"label\", appListItem.getPackageLabel());\n            xmlSerializer.attribute(\"\", \"versionCode\", String.valueOf(appListItem.getVersionCode()));\n            xmlSerializer.attribute(\"\", \"versionName\", appListItem.getVersionName());\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {\n                xmlSerializer.attribute(\"\", \"minSdk\", String.valueOf(appListItem.getMinSdk()));\n            }\n            xmlSerializer.attribute(\"\", \"targetSdk\", String.valueOf(appListItem.getTargetSdk()));\n            xmlSerializer.attribute(\"\", \"signature\", appListItem.getSignatureSha256());\n            xmlSerializer.attribute(\"\", \"firstInstallTime\", String.valueOf(appListItem.getFirstInstallTime()));\n            xmlSerializer.attribute(\"\", \"lastUpdateTime\", String.valueOf(appListItem.getLastUpdateTime()));\n            if (appListItem.getInstallerPackageName() != null) {\n                xmlSerializer.attribute(\"\", \"installerPackageName\", appListItem.getInstallerPackageName());\n                if (appListItem.getInstallerPackageLabel() != null) {\n                    xmlSerializer.attribute(\"\", \"installerPackageLabel\", appListItem.getInstallerPackageLabel());\n                }\n            }\n            xmlSerializer.endTag(\"\", \"package\");\n        }\n        xmlSerializer.endTag(\"\", \"packages\");\n        xmlSerializer.endDocument();\n        xmlSerializer.flush();\n    }\n\n    private static void exportCsv(@NonNull Writer writer,\n                                  @NonNull List<AppListItem> appListItems) throws IOException {\n        CsvWriter csvWriter = new CsvWriter(writer);\n        // Add header\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {\n            csvWriter.addLine(new String[]{\"name\", \"label\", \"versionCode\", \"versionName\", \"minSdk\",\n                    \"targetSdk\", \"signature\", \"firstInstallTime\", \"lastUpdateTime\",\n                    \"installerPackageName\", \"installerPackageLabel\"});\n        } else {\n            csvWriter.addLine(new String[]{\"name\", \"label\", \"versionCode\", \"versionName\",\n                    \"targetSdk\", \"signature\", \"firstInstallTime\", \"lastUpdateTime\",\n                    \"installerPackageName\", \"installerPackageLabel\"});\n        }\n        for (AppListItem item : appListItems) {\n            String installerPackage = item.getInstallerPackageName() != null ? item.getInstallerPackageName() : \"\";\n            String installerLabel = item.getInstallerPackageLabel() != null ? item.getInstallerPackageLabel() : \"\";\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {\n                csvWriter.addLine(new String[]{item.packageName, item.getPackageLabel(),\n                        String.valueOf(item.getVersionCode()), item.getVersionName(),\n                        String.valueOf(item.getMinSdk()), String.valueOf(item.getTargetSdk()),\n                        item.getSignatureSha256(), String.valueOf(item.getFirstInstallTime()),\n                        String.valueOf(item.getLastUpdateTime()),\n                        installerPackage, installerLabel});\n            } else {\n                csvWriter.addLine(new String[]{item.packageName, item.getPackageLabel(),\n                        String.valueOf(item.getVersionCode()), item.getVersionName(),\n                        String.valueOf(item.getTargetSdk()), item.getSignatureSha256(),\n                        String.valueOf(item.getFirstInstallTime()),\n                        String.valueOf(item.getLastUpdateTime()),\n                        installerPackage, installerLabel});\n            }\n        }\n    }\n\n    private static void exportJson(@NonNull Writer writer,\n                                   @NonNull List<AppListItem> appListItems)\n            throws JSONException, IOException {\n        // Should reflect packages.dtd\n        JSONArray array = new JSONArray();\n        for (AppListItem item : appListItems) {\n            JSONObject object = new JSONObject();\n            object.put(\"name\", item.packageName);\n            object.put(\"label\", item.getPackageLabel());\n            object.put(\"versionCode\", item.getVersionCode());\n            object.put(\"versionName\", item.getVersionName());\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {\n                object.put(\"minSdk\", item.getMinSdk());\n            }\n            object.put(\"targetSdk\", item.getTargetSdk());\n            object.put(\"signature\", item.getSignatureSha256());\n            object.put(\"firstInstallTime\", item.getFirstInstallTime());\n            object.put(\"lastUpdateTime\", item.getLastUpdateTime());\n            if (item.getInstallerPackageName() != null) {\n                object.put(\"installerPackageName\", item.getInstallerPackageName());\n                if (item.getInstallerPackageLabel() != null) {\n                    object.put(\"installerPackageLabel\", item.getInstallerPackageLabel());\n                }\n            }\n            array.put(object);\n        }\n        writer.write(array.toString(4));\n    }\n\n    private static void exportMarkdown(@NonNull Context context, @NonNull Writer writer,\n                                       @NonNull List<AppListItem> appListItems) throws IOException {\n        writer.write(\"# Package Info\\n\\n\");\n        for (AppListItem appListItem : appListItems) {\n            writer.append(\"## \").append(appListItem.getPackageLabel()).append(\"\\n\\n\")\n                    .append(\"**Package name:** \").append(appListItem.packageName).append(\"\\n\")\n                    .append(\"**Version:** \").append(appListItem.getVersionName()).append(\" (\")\n                    .append(String.valueOf(appListItem.getVersionCode())).append(\")\\n\");\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {\n                writer.append(\"**Min SDK:** \").append(String.valueOf(appListItem.getMinSdk()))\n                        .append(\", \");\n            }\n            writer.append(\"**Target SDK:** \").append(String.valueOf(appListItem.getTargetSdk()))\n                    .append(\"\\n\")\n                    .append(\"**Date installed:** \")\n                    .append(DateUtils.formatDateTime(context, appListItem.getFirstInstallTime()))\n                    .append(\", **Date updated:** \")\n                    .append(DateUtils.formatDateTime(context, appListItem.getLastUpdateTime()))\n                    .append(\"\\n\");\n            if (appListItem.getInstallerPackageName() != null) {\n                writer.append(\"**Installer:** \");\n                if (appListItem.getInstallerPackageLabel() != null) {\n                    writer.append(appListItem.getInstallerPackageLabel()).append(\" (\");\n                }\n                writer.append(appListItem.getInstallerPackageName());\n                if (appListItem.getInstallerPackageLabel() != null) {\n                    writer.append(\")\");\n                }\n            }\n            writer.append(\"\\n\\n\");\n        }\n    }\n\n    @NonNull\n    private static List<AppListItem> getAppListItems(@NonNull Context context,\n                                                     @NonNull List<PackageInfo> packageInfoList) {\n        List<AppListItem> appListItems = new ArrayList<>(packageInfoList.size());\n        PackageManager pm = context.getPackageManager();\n        for (PackageInfo packageInfo : packageInfoList) {\n            ApplicationInfo applicationInfo = packageInfo.applicationInfo;\n            AppListItem item = new AppListItem(packageInfo.packageName);\n            appListItems.add(item);\n            item.setIcon(UIUtils.getBitmapFromDrawable(applicationInfo.loadIcon(pm)));\n            item.setPackageLabel(applicationInfo.loadLabel(pm).toString());\n            item.setVersionCode(PackageInfoCompat.getLongVersionCode(packageInfo));\n            item.setVersionName(packageInfo.versionName);\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {\n                item.setMinSdk(applicationInfo.minSdkVersion);\n            }\n            item.setTargetSdk(applicationInfo.targetSdkVersion);\n            String[] signatureSha256 = PackageUtils.getSigningCertSha256Checksum(packageInfo, false);\n            item.setSignatureSha256(TextUtils.join(\",\", signatureSha256));\n            item.setFirstInstallTime(packageInfo.firstInstallTime);\n            item.setLastUpdateTime(packageInfo.lastUpdateTime);\n            String installerPackageName = PackageManagerCompat.getInstallerPackageName(\n                    packageInfo.packageName, UserHandleHidden.getUserId(applicationInfo.uid));\n            if (installerPackageName != null) {\n                item.setInstallerPackageName(installerPackageName);\n                String installerPackageLabel;\n                try {\n                    installerPackageLabel = pm.getApplicationInfo(installerPackageName, 0)\n                            .loadLabel(pm).toString();\n                    if (!installerPackageLabel.equals(installerPackageName)) {\n                        item.setInstallerPackageLabel(installerPackageLabel);\n                    }\n                } catch (PackageManager.NameNotFoundException ignore) {\n                }\n            }\n        }\n        return appListItems;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/apk/parser/AndroidBinXmlDecoder.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.apk.parser;\n\nimport static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;\nimport static org.xmlpull.v1.XmlPullParser.END_TAG;\nimport static org.xmlpull.v1.XmlPullParser.START_DOCUMENT;\nimport static org.xmlpull.v1.XmlPullParser.START_TAG;\n\nimport android.text.TextUtils;\n\nimport androidx.annotation.NonNull;\n\nimport com.reandroid.apk.AndroidFrameworks;\nimport com.reandroid.arsc.chunk.PackageBlock;\nimport com.reandroid.arsc.chunk.xml.ResXmlDocument;\nimport com.reandroid.arsc.chunk.xml.ResXmlPullParser;\nimport com.reandroid.arsc.io.BlockReader;\n\nimport org.xmlpull.v1.XmlPullParserException;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.io.PrintStream;\nimport java.nio.ByteBuffer;\nimport java.nio.ByteOrder;\nimport java.nio.charset.StandardCharsets;\n\nimport io.github.muntashirakon.AppManager.utils.IntegerUtils;\nimport io.github.muntashirakon.io.IoUtils;\n\npublic class AndroidBinXmlDecoder {\n    public static boolean isBinaryXml(@NonNull ByteBuffer buffer) {\n        buffer.order(ByteOrder.LITTLE_ENDIAN);\n        buffer.mark();\n        int version = IntegerUtils.getUInt16(buffer);\n        int header = IntegerUtils.getUInt16(buffer);\n        buffer.reset();\n        // 0x0000 is NULL header. The only example of application using a NULL header is NP Manager\n        return (version == 0x0003 || version == 0x0000) && header == 0x0008;\n    }\n\n    @NonNull\n    public static String decode(@NonNull byte[] data) throws IOException {\n        return decode(ByteBuffer.wrap(data));\n    }\n\n    @NonNull\n    public static String decode(@NonNull InputStream is) throws IOException {\n        ByteArrayOutputStream buffer = new ByteArrayOutputStream();\n        byte[] buf = new byte[IoUtils.DEFAULT_BUFFER_SIZE];\n        int n;\n        while (-1 != (n = is.read(buf))) {\n            buffer.write(buf, 0, n);\n        }\n        return decode(buffer.toByteArray());\n    }\n\n    @NonNull\n    public static String decode(@NonNull ByteBuffer byteBuffer) throws IOException {\n        try (ByteArrayOutputStream bos = new ByteArrayOutputStream()) {\n            decode(byteBuffer, bos);\n            byte[] bs = bos.toByteArray();\n            return new String(bs, StandardCharsets.UTF_8);\n        }\n    }\n\n    public static void decode(@NonNull ByteBuffer byteBuffer, @NonNull OutputStream os) throws IOException {\n        try (BlockReader reader = new BlockReader(byteBuffer.array());\n             PrintStream out = new PrintStream(os)) {\n            ResXmlDocument resXmlDocument = new ResXmlDocument();\n            resXmlDocument.readBytes(reader);\n            resXmlDocument.setPackageBlock(getFrameworkPackageBlock());\n            try (ResXmlPullParser parser = new ResXmlPullParser(resXmlDocument)) {\n                StringBuilder indent = new StringBuilder(10);\n                final String indentStep = \"  \";\n                out.println(\"<?xml version=\\\"1.0\\\" encoding=\\\"utf-8\\\"?>\");\n                XML_BUILDER:\n                while (true) {\n                    int type = parser.next();\n                    switch (type) {\n                        case START_TAG: {\n                            out.printf(\"%s<%s%s\", indent, getNamespacePrefix(parser.getPrefix()), parser.getName());\n                            indent.append(indentStep);\n\n                            int nsStart = parser.getNamespaceCount(parser.getDepth() - 1);\n                            int nsEnd = parser.getNamespaceCount(parser.getDepth());\n                            for (int i = nsStart; i < nsEnd; ++i) {\n                                out.printf(\"\\n%sxmlns:%s=\\\"%s\\\"\", indent,\n                                        parser.getNamespacePrefix(i),\n                                        parser.getNamespaceUri(i));\n                            }\n\n                            for (int i = 0; i != parser.getAttributeCount(); ++i) {\n                                out.printf(\"\\n%s%s%s=\\\"%s\\\"\",\n                                        indent,\n                                        getNamespacePrefix(parser.getAttributePrefix(i)),\n                                        parser.getAttributeName(i),\n                                        parser.getAttributeValue(i));\n                            }\n                            out.println(\">\");\n                            break;\n                        }\n                        case END_TAG: {\n                            indent.setLength(indent.length() - indentStep.length());\n                            out.printf(\"%s</%s%s>%n\", indent, getNamespacePrefix(parser.getPrefix()), parser.getName());\n                            break;\n                        }\n                        case END_DOCUMENT:\n                            break XML_BUILDER;\n                        case START_DOCUMENT:\n                            // Unreachable statement\n                            break;\n                    }\n                }\n            }\n        } catch (XmlPullParserException e) {\n            throw new IOException(e);\n        }\n    }\n\n    @NonNull\n    private static String getNamespacePrefix(String prefix) {\n        if (TextUtils.isEmpty(prefix)) {\n            return \"\";\n        }\n        return prefix + \":\";\n    }\n\n    @NonNull\n    public static PackageBlock getFrameworkPackageBlock() {\n        if (sFrameworkPackageBlock != null) {\n            return sFrameworkPackageBlock;\n        }\n        sFrameworkPackageBlock = AndroidFrameworks.getLatest().getTableBlock().getAllPackages().next();\n        return sFrameworkPackageBlock;\n    }\n\n    private static PackageBlock sFrameworkPackageBlock;\n}"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/apk/parser/AndroidBinXmlEncoder.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.apk.parser;\n\nimport androidx.annotation.NonNull;\n\nimport com.reandroid.apk.xmlencoder.XMLEncodeSource;\nimport com.reandroid.xml.source.XMLFileParserSource;\nimport com.reandroid.xml.source.XMLParserSource;\nimport com.reandroid.xml.source.XMLStringParserSource;\n\nimport java.io.File;\nimport java.io.IOException;\n\npublic class AndroidBinXmlEncoder {\n    @NonNull\n    public static byte[] encodeFile(@NonNull File file) throws IOException {\n        return encode(new XMLFileParserSource(file.getName(), file));\n    }\n\n    @NonNull\n    public static byte[] encodeString(@NonNull String xml) throws IOException {\n        return encode(new XMLStringParserSource(\"String.xml\", xml));\n    }\n\n    @NonNull\n    private static byte[] encode(@NonNull XMLParserSource xmlSource) throws IOException {\n        XMLEncodeSource xmlEncodeSource = new XMLEncodeSource(AndroidBinXmlDecoder.getFrameworkPackageBlock(), xmlSource);\n        return xmlEncodeSource.getBytes();\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/apk/parser/ManifestComponent.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.apk.parser;\n\nimport android.content.ComponentName;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class ManifestComponent {\n    public final ComponentName cn;\n    public final List<ManifestIntentFilter> intentFilters;\n\n    public ManifestComponent(ComponentName cn) {\n        this.cn = cn;\n        intentFilters = new ArrayList<>();\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/apk/parser/ManifestIntentFilter.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.apk.parser;\n\nimport androidx.collection.ArraySet;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Set;\n\npublic class ManifestIntentFilter {\n    public final Set<String> actions = new ArraySet<>();\n    public final Set<String> categories = new ArraySet<>();\n    public final List<ManifestData> data = new ArrayList<>();\n    public int priority;\n\n    public static class ManifestData {\n        public String scheme;\n        public String host;\n        public String port;\n        public String path;\n        public String pathPattern;\n        public String pathPrefix;\n        public String pathSuffix;\n        public String pathAdvancedPattern;\n        public String mimeType;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/apk/parser/ManifestParser.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.apk.parser;\n\nimport android.content.ComponentName;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport com.reandroid.arsc.chunk.xml.ResXmlAttribute;\nimport com.reandroid.arsc.chunk.xml.ResXmlDocument;\nimport com.reandroid.arsc.chunk.xml.ResXmlElement;\nimport com.reandroid.arsc.io.BlockReader;\n\nimport java.io.IOException;\nimport java.nio.ByteBuffer;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.Objects;\n\nimport io.github.muntashirakon.AppManager.logs.Log;\n\npublic class ManifestParser {\n    public static final String TAG = ManifestParser.class.getSimpleName();\n\n    // manifest\n    private static final String TAG_MANIFEST = \"manifest\";\n    private static final String ATTR_MANIFEST_PACKAGE = \"package\";\n    // manifest -> application\n    private static final String TAG_APPLICATION = \"application\";\n    // manifest -> application -> activity|activity-alias|service|receiver|provider\n    private static final String TAG_ACTIVITY = \"activity\";\n    private static final String TAG_ACTIVITY_ALIAS = \"activity-alias\";\n    private static final String TAG_SERVICE = \"service\";\n    private static final String TAG_RECEIVER = \"receiver\";\n    private static final String TAG_PROVIDER = \"provider\";\n    private static final String ATTR_NAME = \"name\"; // android:name\n    // manifest -> application -> (component) -> intent-filter\n    private static final String TAG_INTENT_FILTER = \"intent-filter\";\n    private static final String ATTR_PRIORITY = \"priority\"; // android:priority\n    // manifest -> application -> (component) -> intent-filter -> action|category|data\n    private static final String TAG_ACTION = \"action\";\n    private static final String TAG_CATEGORY = \"category\";\n    private static final String TAG_DATA = \"data\";\n\n    private final @NonNull ByteBuffer mManifestBytes;\n    private String mPackageName;\n\n    public ManifestParser(@NonNull byte[] manifestBytes) {\n        this(ByteBuffer.wrap(manifestBytes));\n    }\n\n    public ManifestParser(@NonNull ByteBuffer manifestBytes) {\n        mManifestBytes = manifestBytes;\n    }\n\n    public List<ManifestComponent> parseComponents() throws IOException {\n        try (BlockReader reader = new BlockReader(mManifestBytes.array())) {\n            ResXmlDocument xmlBlock = new ResXmlDocument();\n            xmlBlock.readBytes(reader);\n            xmlBlock.setPackageBlock(AndroidBinXmlDecoder.getFrameworkPackageBlock());\n            ResXmlElement resManifestElement = xmlBlock.getDocumentElement();\n            // manifest\n            if (!TAG_MANIFEST.equals(resManifestElement.getName())) {\n                throw new IOException(\"\\\"manifest\\\" tag not found.\");\n            }\n            String packageName = getAttributeValue(resManifestElement, ATTR_MANIFEST_PACKAGE);\n            if (packageName == null) {\n                throw new IOException(\"\\\"manifest\\\" does not have required attribute \\\"package\\\".\");\n            }\n            mPackageName = packageName;\n            // manifest -> application\n            ResXmlElement resApplicationElement = null;\n            Iterator<ResXmlElement> resXmlElementIt = resManifestElement.getElements(TAG_APPLICATION);\n            if (resXmlElementIt.hasNext()) {\n                resApplicationElement = resXmlElementIt.next();\n            }\n            if (resXmlElementIt.hasNext()) {\n                throw new IOException(\"\\\"manifest\\\" has duplicate \\\"application\\\" tags.\");\n            }\n            if (resApplicationElement == null) {\n                Log.i(TAG, \"package %s does not have \\\"application\\\" tag.\", mPackageName);\n                return Collections.emptyList();\n            }\n            // manifest -> application -> component\n            List<ManifestComponent> componentIfList = new ArrayList<>(resApplicationElement.getElementsCount());\n            String tagName;\n            resXmlElementIt = resApplicationElement.getElements();\n            while (resXmlElementIt.hasNext()) {\n                ResXmlElement elem = resXmlElementIt.next();\n                tagName = elem.getName();\n                if (tagName != null) {\n                    switch (tagName) {\n                        case TAG_ACTIVITY:\n                        case TAG_ACTIVITY_ALIAS:\n                        case TAG_SERVICE:\n                        case TAG_RECEIVER:\n                        case TAG_PROVIDER:\n                            componentIfList.add(parseComponentInfo(elem));\n                            break;\n                    }\n                }\n            }\n            return componentIfList;\n        }\n    }\n\n    @NonNull\n    private ManifestComponent parseComponentInfo(@NonNull ResXmlElement componentElement) throws IOException {\n        String componentName = getAttributeValue(componentElement, ATTR_NAME);\n        if (componentName == null) {\n            throw new IOException(\"\\\"\" + componentElement.getName() + \"\\\" does not have  required attribute \\\"android:name\\\".\");\n        }\n        ManifestComponent componentIf = new ManifestComponent(new ComponentName(mPackageName, componentName));\n        // manifest -> application -> component -> intent-filter\n        Iterator<ResXmlElement> resXmlElementIt = componentElement.getElements(TAG_INTENT_FILTER);\n        while (resXmlElementIt.hasNext()) {\n            ResXmlElement elem = resXmlElementIt.next();\n            componentIf.intentFilters.add(parseIntentFilter(elem));\n        }\n        return componentIf;\n    }\n\n    @NonNull\n    private ManifestIntentFilter parseIntentFilter(@NonNull ResXmlElement intentFilterElement) {\n        ManifestIntentFilter intentFilter = new ManifestIntentFilter();\n        String priorityString = getAttributeValue(intentFilterElement, ATTR_PRIORITY);\n        if (priorityString != null) {\n            intentFilter.priority = Integer.parseInt(priorityString);\n        }\n        // manifest -> application -> component -> intent-filter -> action|category|data\n        Iterator<ResXmlElement> resXmlElementIt = intentFilterElement.getElements();\n        String tagName;\n        while (resXmlElementIt.hasNext()) {\n            ResXmlElement elem = resXmlElementIt.next();\n            tagName = elem.getName();\n            if (tagName != null) {\n                switch (tagName) {\n                    case TAG_ACTION:\n                        intentFilter.actions.add(Objects.requireNonNull(getAttributeValue(elem, ATTR_NAME)));\n                        break;\n                    case TAG_CATEGORY:\n                        intentFilter.categories.add(Objects.requireNonNull(getAttributeValue(elem, ATTR_NAME)));\n                        break;\n                    case TAG_DATA:\n                        intentFilter.data.add(parseData(elem));\n                        break;\n                }\n            }\n        }\n        return intentFilter;\n    }\n\n    @NonNull\n    private ManifestIntentFilter.ManifestData parseData(@NonNull ResXmlElement dataElement) {\n        ManifestIntentFilter.ManifestData data = new ManifestIntentFilter.ManifestData();\n        ResXmlAttribute attribute;\n        for (int i = 0; i < dataElement.getAttributeCount(); ++i) {\n            attribute = dataElement.getAttributeAt(i);\n            if (attribute.equalsName(\"scheme\")) {\n                data.scheme = attribute.getValueAsString();\n            } else if (attribute.equalsName(\"host\")) {\n                data.host = attribute.getValueAsString();\n            } else if (attribute.equalsName(\"port\")) {\n                data.port = attribute.getValueAsString();\n            } else if (attribute.equalsName(\"path\")) {\n                data.path = attribute.getValueAsString();\n            } else if (attribute.equalsName(\"pathPrefix\")) {\n                data.pathPrefix = attribute.getValueAsString();\n            } else if (attribute.equalsName(\"pathSuffix\")) {\n                data.pathSuffix = attribute.getValueAsString();\n            } else if (attribute.equalsName(\"pathPattern\")) {\n                data.pathPattern = attribute.getValueAsString();\n            } else if (attribute.equalsName(\"pathAdvancedPattern\")) {\n                data.pathAdvancedPattern = attribute.getValueAsString();\n            } else if (attribute.equalsName(\"mimeType\")) {\n                data.mimeType = attribute.getValueAsString();\n            } else {\n                Log.i(TAG, \"Unknown intent-filter > data attribute %s\", attribute.getName());\n            }\n        }\n        return data;\n    }\n\n    @Nullable\n    private String getAttributeValue(@NonNull ResXmlElement element, @NonNull String attrName) {\n        ResXmlAttribute attribute;\n        for (int i = 0; i < element.getAttributeCount(); ++i) {\n            attribute = element.getAttributeAt(i);\n            if (attribute.equalsName(attrName)) {\n                return attribute.getValueAsString();\n            }\n        }\n        return null;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/apk/signing/SigSchemes.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.apk.signing;\n\nimport androidx.annotation.IntDef;\nimport androidx.annotation.NonNull;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class SigSchemes {\n    @IntDef(flag = true, value = {\n            SIG_SCHEME_V1,\n            SIG_SCHEME_V2,\n            SIG_SCHEME_V3,\n            SIG_SCHEME_V4,\n    })\n    public @interface SignatureScheme {\n    }\n\n    public static final int SIG_SCHEME_V1 = 1 << 0;\n    public static final int SIG_SCHEME_V2 = 1 << 1;\n    public static final int SIG_SCHEME_V3 = 1 << 2;\n    public static final int SIG_SCHEME_V4 = 1 << 3;\n\n    public static final int TOTAL_SIG_SCHEME = 4;\n\n    public static final int DEFAULT_SCHEMES = SIG_SCHEME_V1 | SIG_SCHEME_V2;\n\n    @SignatureScheme\n    private int mFlags;\n\n    public SigSchemes(@SignatureScheme int flags) {\n        this.mFlags = flags;\n    }\n\n    public boolean isEmpty() {\n        return mFlags == 0;\n    }\n\n    public int getFlags() {\n        return mFlags;\n    }\n\n    public void setFlags(int flags) {\n        this.mFlags = flags;\n    }\n\n    @NonNull\n    public List<Integer> getAllItems() {\n        List<Integer> allItems = new ArrayList<>();\n        for (int i = 0; i < TOTAL_SIG_SCHEME; ++i) {\n            allItems.add(1 << i);\n        }\n        return allItems;\n    }\n\n    public boolean v1SchemeEnabled() {\n        return (mFlags & SIG_SCHEME_V1) != 0;\n    }\n    public boolean v2SchemeEnabled() {\n        return (mFlags & SIG_SCHEME_V2) != 0;\n    }\n    public boolean v3SchemeEnabled() {\n        return (mFlags & SIG_SCHEME_V3) != 0;\n    }\n    public boolean v4SchemeEnabled() {\n        return (mFlags & SIG_SCHEME_V4) != 0;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/apk/signing/Signer.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.apk.signing;\n\nimport android.os.Build;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport com.android.apksig.ApkSigner;\nimport com.android.apksig.ApkVerifier;\n\nimport java.io.File;\nimport java.security.KeyStoreException;\nimport java.security.Principal;\nimport java.security.PrivateKey;\nimport java.security.PublicKey;\nimport java.security.SignatureException;\nimport java.security.cert.CertificateEncodingException;\nimport java.security.cert.X509Certificate;\nimport java.security.interfaces.DSAKey;\nimport java.security.interfaces.DSAParams;\nimport java.security.interfaces.ECKey;\nimport java.security.interfaces.RSAKey;\nimport java.util.Collections;\nimport java.util.List;\n\nimport aosp.libcore.util.HexEncoding;\nimport io.github.muntashirakon.AppManager.crypto.ks.KeyPair;\nimport io.github.muntashirakon.AppManager.crypto.ks.KeyStoreManager;\nimport io.github.muntashirakon.AppManager.logs.Log;\nimport io.github.muntashirakon.AppManager.utils.DigestUtils;\nimport io.github.muntashirakon.AppManager.utils.ExUtils;\n\npublic class Signer {\n    public static final String TAG = \"Signer\";\n    public static final String SIGNING_KEY_ALIAS = \"signing_key\";\n\n    public static boolean canSign() {\n        try {\n            // In order to sign an APK, a signing key must be inserted\n            return KeyStoreManager.getInstance().containsKey(Signer.SIGNING_KEY_ALIAS);\n        } catch (Exception e) {\n            // Signing not configured\n            return false;\n        }\n    }\n\n    @NonNull\n    public static Signer getInstance(SigSchemes sigSchemes) throws SignatureException {\n        try {\n            KeyStoreManager manager = KeyStoreManager.getInstance();\n            KeyPair signingKey = manager.getKeyPair(SIGNING_KEY_ALIAS);\n            if (signingKey == null) {\n                throw new KeyStoreException(\"Alias \" + SIGNING_KEY_ALIAS + \" does not exist in KeyStore.\");\n            }\n            return new Signer(sigSchemes, signingKey.getPrivateKey(), (X509Certificate) signingKey.getCertificate());\n        } catch (Exception e) {\n            throw new SignatureException(e);\n        }\n    }\n\n    @NonNull\n    private final PrivateKey mPrivateKey;\n    @NonNull\n    private final X509Certificate mCertificate;\n    @NonNull\n    private final SigSchemes mSigSchemes;\n    @Nullable\n    private File mIdsigFile;\n\n    private Signer(@NonNull SigSchemes sigSchemes, @NonNull PrivateKey privateKey, @NonNull X509Certificate certificate) {\n        mSigSchemes = sigSchemes;\n        mPrivateKey = privateKey;\n        mCertificate = certificate;\n    }\n\n    public boolean isV4SchemeEnabled() {\n        return mSigSchemes.v4SchemeEnabled();\n    }\n\n    public void setIdsigFile(@Nullable File idsigFile) {\n        mIdsigFile = idsigFile;\n    }\n\n    public boolean sign(File in, File out, int minSdk, boolean alignFileSize) {\n        ApkSigner.SignerConfig signerConfig = new ApkSigner.SignerConfig.Builder(\"CERT\",\n                mPrivateKey, Collections.singletonList(mCertificate)).build();\n        ApkSigner.Builder builder = new ApkSigner.Builder(Collections.singletonList(signerConfig));\n        builder.setInputApk(in);\n        builder.setOutputApk(out);\n        builder.setCreatedBy(\"AppManager\");\n        builder.setAlignFileSize(alignFileSize);\n        if (minSdk != -1) builder.setMinSdkVersion(minSdk);\n        builder.setV1SigningEnabled(mSigSchemes.v1SchemeEnabled());\n        builder.setV2SigningEnabled(mSigSchemes.v2SchemeEnabled());\n        builder.setV3SigningEnabled(mSigSchemes.v3SchemeEnabled());\n        if (mSigSchemes.v4SchemeEnabled()) {\n            if (mIdsigFile == null) {\n                throw new RuntimeException(\"idsig file is mandatory for v4 signature scheme.\");\n            }\n            builder.setV4SigningEnabled(true);\n            builder.setV4SignatureOutputFile(mIdsigFile);\n        } else {\n            builder.setV4SigningEnabled(false);\n        }\n        ApkSigner signer = builder.build();\n        Log.i(TAG, \"SignApk: %s\", in);\n        try {\n            if (alignFileSize && !ZipAlign.verify(in, ZipAlign.ALIGNMENT_4, true)) {\n                ZipAlign.align(in, ZipAlign.ALIGNMENT_4, true);\n            }\n            signer.sign();\n            Log.i(TAG, \"The signature is complete and the output file is %s\", out);\n            return true;\n        } catch (Exception e) {\n            Log.w(TAG, e);\n            return false;\n        }\n    }\n\n    public static boolean verify(@NonNull SigSchemes sigSchemes, @NonNull File apk, @Nullable File idsig) {\n        ApkVerifier.Builder builder = new ApkVerifier.Builder(apk)\n                .setMaxCheckedPlatformVersion(Build.VERSION.SDK_INT);\n        if (sigSchemes.v4SchemeEnabled()) {\n            if (idsig == null) {\n                throw new RuntimeException(\"idsig file is mandatory for v4 signature scheme.\");\n            }\n            builder.setV4SignatureFile(idsig);\n        }\n        ApkVerifier verifier = builder.build();\n        try {\n            ApkVerifier.Result result = verifier.verify();\n            Log.i(TAG, \"%s\", apk);\n            boolean isVerify = result.isVerified();\n            if (isVerify) {\n                if (sigSchemes.v1SchemeEnabled() && result.isVerifiedUsingV1Scheme()) {\n                    Log.i(TAG, \"V1 signature verified.\");\n                } else Log.w(TAG, \"V1 signature verification failed/disabled.\");\n                if (sigSchemes.v2SchemeEnabled() && result.isVerifiedUsingV2Scheme()) {\n                    Log.i(TAG, \"V2 signature verified.\");\n                } else Log.w(TAG, \"V2 signature verification failed/disabled.\");\n                if (sigSchemes.v3SchemeEnabled()) {\n                    if (result.isVerifiedUsingV3Scheme()) {\n                        Log.i(TAG, \"V3 signature verified.\");\n                    } else Log.w(TAG, \"V3 signature verification failed.\");\n                    if (result.isVerifiedUsingV31Scheme()) {\n                        Log.i(TAG, \"V3.1 signature verified.\");\n                    } else Log.w(TAG, \"V3.1 signature verification failed.\");\n                } else Log.w(TAG, \"V3 signature verification disabled.\");\n                if (sigSchemes.v4SchemeEnabled() && result.isVerifiedUsingV4Scheme()) {\n                    Log.i(TAG, \"V4 signature verified.\");\n                } else Log.w(TAG, \"V4 signature verification failed/disabled.\");\n                if (result.isSourceStampVerified()) {\n                    Log.i(TAG, \"SourceStamp verified.\");\n                } else Log.w(TAG, \"SourceStamp not verified/unavailable.\");\n                int i = 0;\n                List<X509Certificate> signerCertificates = result.getSignerCertificates();\n                Log.i(TAG, \"Number of signatures: %d\", signerCertificates.size());\n                for (X509Certificate logCert : signerCertificates) {\n                    i++;\n                    logCert(logCert, \"Signature\" + i);\n                }\n            }\n            for (ApkVerifier.IssueWithParams warn : result.getWarnings()) {\n                Log.w(TAG, \"%s\", warn);\n            }\n            for (ApkVerifier.IssueWithParams err : result.getErrors()) {\n                Log.e(TAG, \"%s\", err);\n            }\n            if (sigSchemes.v1SchemeEnabled()) {\n                for (ApkVerifier.Result.V1SchemeSignerInfo signer : result.getV1SchemeIgnoredSigners()) {\n                    String name = signer.getName();\n                    for (ApkVerifier.IssueWithParams err : signer.getErrors()) {\n                        Log.e(TAG, \"%s: %s\", name, err);\n                    }\n                    for (ApkVerifier.IssueWithParams err : signer.getWarnings()) {\n                        Log.w(TAG, \"%s: %s\", name, err);\n                    }\n                }\n            }\n            return isVerify;\n        } catch (Exception e) {\n            Log.w(TAG, \"Verification failed.\", e);\n            return false;\n        }\n    }\n\n    @Nullable\n    public static String getSourceStampSource(@NonNull ApkVerifier.Result.SourceStampInfo sourceStampInfo) {\n        byte[] certBytes = ExUtils.exceptionAsNull(() -> sourceStampInfo.getCertificate().getEncoded());\n        if (certBytes == null) {\n            return null;\n        }\n        String sourceStampHash = DigestUtils.getHexDigest(DigestUtils.SHA_256, certBytes);\n        if (sourceStampHash.equals(\"3257d599a49d2c961a471ca9843f59d341a405884583fc087df4237b733bbd6d\")) {\n            return \"Google Play\";\n        }\n        return null;\n    }\n\n    private static void logCert(@NonNull X509Certificate x509Certificate, CharSequence charSequence) throws CertificateEncodingException {\n        int bitLength;\n        Principal subjectDN = x509Certificate.getSubjectDN();\n        Log.i(TAG, \"%s - Unique distinguished name: %s\", charSequence, subjectDN);\n        logEncoded(charSequence, x509Certificate.getEncoded());\n        PublicKey publicKey = x509Certificate.getPublicKey();\n        if (publicKey instanceof RSAKey) {\n            bitLength = ((RSAKey) publicKey).getModulus().bitLength();\n        } else if (publicKey instanceof ECKey) {\n            bitLength = ((ECKey) publicKey).getParams().getOrder().bitLength();\n        } else if (publicKey instanceof DSAKey) {\n            DSAParams params = ((DSAKey) publicKey).getParams();\n            if (params != null) {\n                bitLength = params.getP().bitLength();\n            } else bitLength = -1;\n        } else {\n            bitLength = -1;\n        }\n        Log.i(TAG, \"%s - key size: %s\", charSequence, (bitLength != -1 ? String.valueOf(bitLength) : \"Unknown\"));\n        String algorithm = publicKey.getAlgorithm();\n        Log.i(TAG, \"%s - key algorithm: %s\", charSequence, algorithm);\n        logEncoded(charSequence, publicKey.getEncoded());\n    }\n\n    private static void logEncoded(CharSequence charSequence, byte[] bArr) {\n        log(charSequence + \" - SHA-256: \", DigestUtils.getDigest(DigestUtils.SHA_256, bArr));\n        log(charSequence + \" - SHA-1: \", DigestUtils.getDigest(DigestUtils.SHA_1, bArr));\n        log(charSequence + \" - MD5: \", DigestUtils.getDigest(DigestUtils.MD5, bArr));\n    }\n\n    private static void log(String str, byte[] bArr) {\n        Log.i(TAG, str);\n        Log.w(TAG, HexEncoding.encodeToString(bArr));\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/apk/signing/SignerInfo.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.apk.signing;\n\nimport android.content.pm.Signature;\nimport android.content.pm.SigningInfo;\nimport android.os.Build;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.RequiresApi;\n\nimport com.android.apksig.ApkVerifier;\nimport com.android.apksig.SigningCertificateLineage;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.security.cert.CertificateException;\nimport java.security.cert.CertificateFactory;\nimport java.security.cert.X509Certificate;\nimport java.util.List;\n\npublic class SignerInfo {\n    @Nullable\n    private final X509Certificate[] mCurrentSignerCerts;\n    @Nullable\n    private final X509Certificate[] mSignerCertsInLineage;\n    @Nullable\n    private final X509Certificate[] mAllSignerCerts;\n    @Nullable\n    private final X509Certificate mSourceStampCert;\n\n    public SignerInfo(@NonNull ApkVerifier.Result apkVerifierResult) {\n        List<X509Certificate> certificates = apkVerifierResult.getSignerCertificates();\n        if (certificates == null || certificates.isEmpty()) {\n            mCurrentSignerCerts = null;\n        } else {\n            mCurrentSignerCerts = new X509Certificate[certificates.size()];\n            int i = 0;\n            for (X509Certificate certificate : certificates) {\n                mCurrentSignerCerts[i++] = certificate;\n            }\n        }\n        // Collect source stamp certificate\n        ApkVerifier.Result.SourceStampInfo sourceStampInfo = apkVerifierResult.getSourceStampInfo();\n        mSourceStampCert = sourceStampInfo != null ? sourceStampInfo.getCertificate() : null;\n        if (mCurrentSignerCerts == null || mCurrentSignerCerts.length > 1) {\n            // Skip checking rotation because the app has multiple signers or no signer at all\n            mAllSignerCerts = mCurrentSignerCerts;\n            mSignerCertsInLineage = null;\n            return;\n        }\n        SigningCertificateLineage lineage = apkVerifierResult.getSigningCertificateLineage();\n        if (lineage == null) {\n            // There is no SigningCertificateLineage block\n            mAllSignerCerts = mCurrentSignerCerts;\n            mSignerCertsInLineage = null;\n            return;\n        }\n        List<X509Certificate> certificatesInLineage = lineage.getCertificatesInLineage();\n        if (certificatesInLineage == null || certificatesInLineage.isEmpty()) {\n            // There is no certificate in the SigningCertificateLineage block\n            mAllSignerCerts = mCurrentSignerCerts;\n            mSignerCertsInLineage = null;\n            return;\n        }\n        // At this point, currentSignatures is a singleton array\n        mSignerCertsInLineage = certificatesInLineage.toArray(new X509Certificate[0]);\n        mAllSignerCerts = new X509Certificate[mCurrentSignerCerts.length + certificatesInLineage.size()];\n        int i = 0;\n        // Add the current signature on top\n        for (X509Certificate signature : mCurrentSignerCerts) {\n            mAllSignerCerts[i++] = signature;\n        }\n        for (X509Certificate certificate : certificatesInLineage) {\n            mAllSignerCerts[i++] = certificate;\n        }\n    }\n\n    @RequiresApi(Build.VERSION_CODES.P)\n    public SignerInfo(@Nullable SigningInfo signingInfo) {\n        mSourceStampCert = null;\n        if (signingInfo == null) {\n            mCurrentSignerCerts = null;\n            mSignerCertsInLineage = null;\n            mAllSignerCerts = null;\n            return;\n        }\n        Signature[] currentSignatures = signingInfo.getApkContentsSigners();\n        Signature[] lineageSignatures = signingInfo.getSigningCertificateHistory();\n        boolean isLineage = !signingInfo.hasMultipleSigners() && signingInfo.hasPastSigningCertificates();\n        // Validation\n        if (currentSignatures == null || currentSignatures.length == 0) {\n            // Invalid signatures\n            mCurrentSignerCerts = null;\n            mSignerCertsInLineage = null;\n            mAllSignerCerts = null;\n            return;\n        }\n        if (isLineage && (lineageSignatures == null || lineageSignatures.length == 0)) {\n            // Invalid lineage signatures\n            mCurrentSignerCerts = null;\n            mSignerCertsInLineage = null;\n            mAllSignerCerts = null;\n            return;\n        }\n        int totalSigner = currentSignatures.length + (isLineage ? lineageSignatures.length : 0);\n        mCurrentSignerCerts = new X509Certificate[currentSignatures.length];\n        mAllSignerCerts = new X509Certificate[totalSigner];\n        for (int i = 0; i < currentSignatures.length; ++i) {\n            X509Certificate cert = generateCertificateOrFail(currentSignatures[i]);\n            mCurrentSignerCerts[i] = cert;\n            mAllSignerCerts[i] = cert;\n        }\n        if (isLineage) {\n            mSignerCertsInLineage = new X509Certificate[lineageSignatures.length];\n            for (int i = currentSignatures.length, j = 0; i < totalSigner; ++i, ++j) {\n                X509Certificate cert = generateCertificateOrFail(lineageSignatures[j]);\n                mSignerCertsInLineage[j] = cert;\n                mAllSignerCerts[i] = cert;\n            }\n        } else mSignerCertsInLineage = null;\n    }\n\n    public SignerInfo(@Nullable Signature[] signatures) {\n        mSourceStampCert = null;\n        mSignerCertsInLineage = null;\n        if (signatures != null && signatures.length > 0) {\n            mAllSignerCerts = new X509Certificate[signatures.length];\n            mCurrentSignerCerts = new X509Certificate[signatures.length];\n            for (int i = 0; i < signatures.length; ++i) {\n                X509Certificate cert = generateCertificateOrFail(signatures[i]);\n                mAllSignerCerts[i] = cert;\n                mCurrentSignerCerts[i] = cert;\n            }\n        } else {\n            mCurrentSignerCerts = null;\n            mAllSignerCerts = null;\n        }\n    }\n\n    public boolean hasMultipleSigners() {\n        return mCurrentSignerCerts != null && mCurrentSignerCerts.length > 1;\n    }\n\n    public boolean hasProofOfRotation() {\n        return !hasMultipleSigners() && mSignerCertsInLineage != null;\n    }\n\n    @Nullable\n    public X509Certificate[] getCurrentSignerCerts() {\n        return mCurrentSignerCerts;\n    }\n\n    @Nullable\n    public X509Certificate getSourceStampCert() {\n        return mSourceStampCert;\n    }\n\n    @Nullable\n    public X509Certificate[] getSignerCertsInLineage() {\n        return mSignerCertsInLineage;\n    }\n\n    /**\n     * Retrieve all signatures, including the lineage ones. The current signature(s) are on top of the array.\n     *\n     * <p>If the APK has multiple signers, all signatures are the current signatures, and if the APK has only one\n     * signer, the first signature is the current signature and rests are the lineage signature.\n     */\n    @Nullable\n    public X509Certificate[] getAllSignerCerts() {\n        return mAllSignerCerts;\n    }\n\n    private static X509Certificate generateCertificateOrFail(Signature signature) {\n        try (InputStream is = new ByteArrayInputStream(signature.toByteArray())) {\n            return (X509Certificate) CertificateFactory.getInstance(\"X.509\").generateCertificate(is);\n        } catch (IOException | CertificateException e) {\n            throw new RuntimeException(\"Invalid signature\", e);\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/apk/signing/ZipAlign.java",
    "content": "// SPDX-License-Identifier: Apache-2.0 OR GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.apk.signing;\n\nimport androidx.annotation.NonNull;\n\nimport com.reandroid.archive.ArchiveEntry;\nimport com.reandroid.archive.ArchiveFile;\nimport com.reandroid.archive.writer.ApkFileWriter;\nimport com.reandroid.archive.writer.ZipAligner;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.util.Iterator;\nimport java.util.regex.Pattern;\nimport java.util.zip.ZipEntry;\n\nimport io.github.muntashirakon.AppManager.logs.Log;\nimport io.github.muntashirakon.io.Paths;\n\npublic class ZipAlign {\n    public static final String TAG = ZipAlign.class.getSimpleName();\n\n    public static final int ALIGNMENT_4 = 4;\n\n    private static final int ALIGNMENT_PAGE = 4096;\n\n    public static void align(@NonNull File input, @NonNull File output, int alignment, boolean pageAlignSharedLibs)\n            throws IOException {\n        File dir = output.getParentFile();\n        if (!Paths.exists(dir)) {\n            dir.mkdirs();\n        }\n\n        try (ArchiveFile archive = new ArchiveFile(input);\n             ApkFileWriter apkWriter = new ApkFileWriter(output, archive.getInputSources())) {\n            apkWriter.setZipAligner(getZipAligner(alignment, pageAlignSharedLibs));\n            apkWriter.write();\n        }\n        if (!verify(output, alignment, pageAlignSharedLibs)) {\n            throw new IOException(\"Could not verify aligned APK file.\");\n        }\n    }\n\n    public static void align(@NonNull File inFile, int alignment, boolean pageAlignSharedLibs) throws IOException {\n        File tmp = toTmpFile(inFile);\n        tmp.delete();\n        try {\n            align(inFile, tmp, alignment, pageAlignSharedLibs);\n            inFile.delete();\n            tmp.renameTo(inFile);\n        } catch (IOException e) {\n            tmp.delete();\n            throw e;\n        }\n    }\n\n    public static boolean verify(@NonNull File file, int alignment, boolean pageAlignSharedLibs) {\n        ArchiveFile zipFile;\n        boolean foundBad = false;\n        Log.d(TAG, \"Verifying alignment of %s...\", file);\n\n        try {\n            zipFile = new ArchiveFile(file);\n        } catch (IOException e) {\n            Log.e(TAG, \"Unable to open '%s' for verification\", e, file);\n            return false;\n        }\n        Iterator<ArchiveEntry> entryIterator = zipFile.iterator();\n        while (entryIterator.hasNext()) {\n            ArchiveEntry pEntry = entryIterator.next();\n            String name = pEntry.getName();\n            long fileOffset = pEntry.getFileOffset();\n            if (pEntry.getMethod() == ZipEntry.DEFLATED) {\n                Log.d(TAG, \"%8d %s (OK - compressed)\", fileOffset, name);\n            } else if (pEntry.isDirectory()) {\n                // Directory entries do not need to be aligned.\n                Log.d(TAG, \"%8d %s (OK - directory)\", fileOffset, name);\n            } else {\n                int alignTo = getAlignment(pEntry, alignment, pageAlignSharedLibs);\n                if ((fileOffset % alignTo) != 0) {\n                    Log.w(TAG, \"%8d %s (BAD - %d)\\n\", fileOffset, name, (fileOffset % alignTo));\n                    foundBad = true;\n                    break;\n                } else {\n                    Log.d(TAG, \"%8d %s (OK)\\n\", fileOffset, name);\n                }\n            }\n        }\n\n        Log.d(TAG, \"Verification %s\\n\", foundBad ? \"FAILED\" : \"successful\");\n        try {\n            zipFile.close();\n        } catch (IOException e) {\n            Log.w(TAG, \"Unable to close '%s'\", e, file);\n        }\n        return !foundBad;\n    }\n\n    private static int getAlignment(@NonNull ArchiveEntry entry, int defaultAlignment, boolean pageAlignSharedLibs) {\n        if (!pageAlignSharedLibs) {\n            return defaultAlignment;\n        }\n        String name = entry.getName();\n        if (name.startsWith(\"lib/\") && name.endsWith(\".so\")) {\n            return ALIGNMENT_PAGE;\n        } else {\n            return defaultAlignment;\n        }\n    }\n\n    @NonNull\n    public static ZipAligner getZipAligner(int defaultAlignment, boolean pageAlignSharedLibs) {\n        ZipAligner zipAligner = new ZipAligner();\n        zipAligner.setDefaultAlignment(defaultAlignment);\n        if (pageAlignSharedLibs) {\n            Pattern patternNativeLib = Pattern.compile(\"^lib/.+\\\\.so$\");\n            zipAligner.setFileAlignment(patternNativeLib, ALIGNMENT_PAGE);\n        }\n        return zipAligner;\n    }\n\n    @NonNull\n    private static File toTmpFile(@NonNull File file) {\n        String name = file.getName() + \".align.tmp\";\n        File dir = file.getParentFile();\n        if (dir == null) {\n            return new File(name);\n        }\n        return new File(dir, name);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/apk/splitapk/ApksMetadata.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.apk.splitapk;\n\nimport android.content.pm.ApplicationInfo;\nimport android.content.pm.PackageInfo;\nimport android.content.pm.PackageManager;\nimport android.os.Build;\nimport android.text.TextUtils;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.StringDef;\nimport androidx.core.content.pm.PackageInfoCompat;\n\nimport org.json.JSONArray;\nimport org.json.JSONException;\nimport org.json.JSONObject;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.nio.charset.StandardCharsets;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.zip.ZipOutputStream;\n\nimport io.github.muntashirakon.AppManager.BuildConfig;\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.apk.ApkUtils;\nimport io.github.muntashirakon.AppManager.logs.Log;\nimport io.github.muntashirakon.AppManager.self.filecache.FileCache;\nimport io.github.muntashirakon.AppManager.utils.ContextUtils;\nimport io.github.muntashirakon.AppManager.utils.JSONUtils;\nimport io.github.muntashirakon.io.Path;\nimport io.github.muntashirakon.io.Paths;\n\npublic class ApksMetadata {\n    public static final String TAG = ApksMetadata.class.getSimpleName();\n\n    public static final String META_FILE = \"info.json\";\n    public static final String ICON_FILE = \"icon.png\";\n\n    public static class Dependency {\n        public static final String DEPENDENCY_MATCH_EXACT = \"exact\";\n        public static final String DEPENDENCY_MATCH_GREATER = \"greater\";\n        public static final String DEPENDENCY_MATCH_LESS = \"less\";\n\n        @StringDef({DEPENDENCY_MATCH_EXACT, DEPENDENCY_MATCH_GREATER, DEPENDENCY_MATCH_LESS})\n        @Retention(RetentionPolicy.SOURCE)\n        public @interface DependencyMatch {\n        }\n\n        public String packageName;\n        public String displayName;\n        public String versionName;\n        public long versionCode;\n        @Nullable\n        public String[] signatures;\n        @DependencyMatch\n        public String match;\n        public boolean required;\n        @Nullable\n        public String path;\n    }\n\n    public static class BuildInfo {\n        public final long timestamp;\n        public final String builderId;\n        public final String builderLabel;\n        public final String builderVersion;\n        public final String platform;\n\n        public BuildInfo() {\n            timestamp = System.currentTimeMillis();\n            builderId = BuildConfig.APPLICATION_ID;\n            builderLabel = ContextUtils.getContext().getString(R.string.app_name);\n            builderVersion = BuildConfig.VERSION_NAME;\n            platform = \"android\";\n        }\n\n        public BuildInfo(long timestamp, String builderId, String builderLabel, String builderVersion, String platform) {\n            this.timestamp = timestamp;\n            this.builderId = builderId;\n            this.builderLabel = builderLabel;\n            this.builderVersion = builderVersion;\n            this.platform = platform;\n        }\n    }\n\n    public long exportTimestamp;\n    public long metaVersion = 1L;\n    public String packageName;\n    public String displayName;\n    public String versionName;\n    public long versionCode;\n    public long minSdk = 0L;\n    public long targetSdk;\n    public BuildInfo buildInfo;\n    public final List<Dependency> dependencies = new ArrayList<>();\n\n    private final PackageInfo mPackageInfo;\n\n    public ApksMetadata() {\n        mPackageInfo = null;\n    }\n\n    public ApksMetadata(PackageInfo packageInfo) {\n        mPackageInfo = packageInfo;\n    }\n\n    public void readMetadata(String jsonString) throws JSONException {\n        JSONObject jsonObject = new JSONObject(jsonString);\n        metaVersion = jsonObject.getLong(\"info_version\");\n        packageName = jsonObject.getString(\"package_name\");\n        displayName = jsonObject.getString(\"display_name\");\n        versionName = jsonObject.getString(\"version_name\");\n        versionCode = jsonObject.getLong(\"version_code\");\n        minSdk = jsonObject.optLong(\"min_sdk\", 0);\n        targetSdk = jsonObject.getLong(\"target_sdk\");\n        // Build info\n        JSONObject buildInfoObject = jsonObject.optJSONObject(\"build_info\");\n        if (buildInfoObject != null) {\n            buildInfo = new BuildInfo(buildInfoObject.getLong(\"timestamp\"),\n                    buildInfoObject.getString(\"builder_id\"),\n                    buildInfoObject.getString(\"builder_label\"),\n                    buildInfoObject.getString(\"builder_version\"),\n                    buildInfoObject.getString(\"platform\"));\n        }\n        // Dependencies\n        JSONArray dependencyInfoArray = jsonObject.optJSONArray(\"dependencies\");\n        if (dependencyInfoArray != null) {\n            for (int i = 0; i < dependencyInfoArray.length(); ++i) {\n                JSONObject dependencyInfoObject = dependencyInfoArray.getJSONObject(i);\n                Dependency dependency = new Dependency();\n                dependency.packageName = dependencyInfoObject.getString(\"package_name\");\n                dependency.displayName = dependencyInfoObject.getString(\"display_name\");\n                dependency.versionName = dependencyInfoObject.getString(\"version_name\");\n                dependency.versionCode = dependencyInfoObject.getLong(\"version_code\");\n                String signatures = JSONUtils.getString(dependencyInfoObject, \"signature\", null);\n                if (signatures != null) {\n                    dependency.signatures = signatures.split(\",\");\n                }\n                dependency.match = dependencyInfoObject.getString(\"match\");\n                dependency.required = dependencyInfoObject.getBoolean(\"required\");\n                dependency.path = JSONUtils.getString(dependencyInfoObject, \"path\", null);\n                dependencies.add(dependency);\n            }\n        }\n    }\n\n    public void writeMetadata(@NonNull ZipOutputStream zipOutputStream) throws IOException {\n        // Fetch meta\n        PackageManager pm = ContextUtils.getContext().getPackageManager();\n        ApplicationInfo applicationInfo = mPackageInfo.applicationInfo;\n        packageName = mPackageInfo.packageName;\n        displayName = applicationInfo.loadLabel(pm).toString();\n        versionName = mPackageInfo.versionName;\n        versionCode = PackageInfoCompat.getLongVersionCode(mPackageInfo);\n        exportTimestamp = 946684800000L;  // Fake time\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {\n            minSdk = applicationInfo.minSdkVersion;\n        }\n        targetSdk = applicationInfo.targetSdkVersion;\n        String[] sharedLibraries = applicationInfo.sharedLibraryFiles;\n        if (sharedLibraries != null) {\n            for (String file : sharedLibraries) {\n                if (!file.endsWith(\".apk\")) {\n                    continue;\n                }\n                PackageInfo packageInfo = pm.getPackageArchiveInfo(file, PackageManager.GET_SHARED_LIBRARY_FILES);\n                if (packageInfo == null) {\n                    Log.w(TAG, \"Could not fetch package info for file %s\", file);\n                    continue;\n                }\n                if (packageInfo.applicationInfo.sourceDir == null) {\n                    packageInfo.applicationInfo.sourceDir = file;\n                }\n                if (packageInfo.applicationInfo.publicSourceDir == null) {\n                    packageInfo.applicationInfo.publicSourceDir = file;\n                }\n                // Save as APKS first\n                File tempFile = FileCache.getGlobalFileCache().createCachedFile(\"apks\");\n                try {\n                    Path tempPath = Paths.get(tempFile);\n                    SplitApkExporter.saveApks(packageInfo, tempPath);\n                    String path = packageInfo.packageName + ApkUtils.EXT_APKS;\n                    SplitApkExporter.addFile(zipOutputStream, tempPath, path, exportTimestamp);\n                    // Add as dependency\n                    Dependency dependency = new Dependency();\n                    dependency.packageName = packageInfo.packageName;\n                    dependency.displayName = packageInfo.applicationInfo.loadLabel(pm).toString();\n                    dependency.versionName = packageInfo.versionName;\n                    dependency.versionCode = PackageInfoCompat.getLongVersionCode(packageInfo);\n                    dependency.required = true;\n                    dependency.signatures = null;\n                    dependency.match = Dependency.DEPENDENCY_MATCH_EXACT;\n                    dependency.path = path;\n                    dependencies.add(dependency);\n                } finally {\n                    FileCache.getGlobalFileCache().delete(tempFile);\n                }\n            }\n        }\n        // Write meta\n        byte[] meta = getMetadataAsJson().getBytes(StandardCharsets.UTF_8);\n        SplitApkExporter.addBytes(zipOutputStream, meta, ApksMetadata.META_FILE, exportTimestamp);\n    }\n\n    @NonNull\n    public String getMetadataAsJson() {\n        JSONObject jsonObject = new JSONObject();\n        try {\n            jsonObject.put(\"info_version\", metaVersion);\n            jsonObject.put(\"package_name\", packageName);\n            jsonObject.put(\"display_name\", displayName);\n            jsonObject.put(\"version_name\", versionName);\n            jsonObject.put(\"version_code\", versionCode);\n            jsonObject.put(\"min_sdk\", minSdk);\n            jsonObject.put(\"target_sdk\", targetSdk);\n            // Skip build info for privacy\n            // Put dependencies\n            JSONArray dependenciesArray = new JSONArray();\n            for (Dependency dependency : dependencies) {\n                JSONObject dependencyObject = new JSONObject();\n                dependencyObject.put(\"package_name\", dependency.packageName);\n                dependencyObject.put(\"display_name\", dependency.displayName);\n                dependencyObject.put(\"version_name\", dependency.versionName);\n                dependencyObject.put(\"version_code\", dependency.versionCode);\n                if (dependency.signatures != null) {\n                    dependencyObject.put(\"signature\", TextUtils.join(\",\", dependency.signatures));\n                }\n                dependencyObject.put(\"match\", dependency.match);\n                dependencyObject.put(\"required\", dependency.required);\n                if (dependency.path != null) {\n                    dependencyObject.put(\"path\", dependency.path);\n                }\n                dependenciesArray.put(dependencyObject);\n            }\n            if (dependenciesArray.length() > 0) {\n                jsonObject.put(\"dependencies\", dependenciesArray);\n            }\n        } catch (JSONException e) {\n            e.printStackTrace();\n        }\n        return jsonObject.toString();\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/apk/splitapk/SplitApkChooser.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.apk.splitapk;\n\nimport android.content.pm.ApplicationInfo;\nimport android.os.Bundle;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.fragment.app.Fragment;\nimport androidx.lifecycle.ViewModelProvider;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Objects;\nimport java.util.Set;\n\nimport aosp.libcore.util.EmptyArray;\nimport io.github.muntashirakon.AppManager.apk.ApkFile;\nimport io.github.muntashirakon.AppManager.apk.ApkSource;\nimport io.github.muntashirakon.AppManager.apk.installer.PackageInstallerViewModel;\nimport io.github.muntashirakon.AppManager.utils.ArrayUtils;\nimport io.github.muntashirakon.dialog.SearchableMultiChoiceDialogBuilder;\n\npublic class SplitApkChooser extends Fragment {\n    public static final String TAG = SplitApkChooser.class.getSimpleName();\n\n    private static final String EXTRA_ACTION_NAME = \"name\";\n    private static final String EXTRA_VERSION_INFO = \"version\";\n\n    @NonNull\n    public static SplitApkChooser getNewInstance(@NonNull String versionInfo, @Nullable String actionName) {\n        SplitApkChooser splitApkChooser = new SplitApkChooser();\n        Bundle args = new Bundle();\n        args.putString(EXTRA_ACTION_NAME, actionName);\n        args.putString(EXTRA_VERSION_INFO, versionInfo);\n        splitApkChooser.setArguments(args);\n        return splitApkChooser;\n    }\n\n    private PackageInstallerViewModel mViewModel;\n    private List<ApkFile.Entry> mApkEntries;\n    private SearchableMultiChoiceDialogBuilder<String> mViewBuilder;\n    private Set<String> mSelectedSplits;\n    private final HashMap<String /* feature */, HashSet<Integer> /* seen types */> mSeenSplits = new HashMap<>();\n\n    @Override\n    public void onCreate(@Nullable Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        mViewModel = new ViewModelProvider(requireActivity()).get(PackageInstallerViewModel.class);\n        mSelectedSplits = mViewModel.getSelectedSplits();\n    }\n\n    @Nullable\n    @Override\n    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {\n        ApkFile apkFile = mViewModel.getApkFile();\n        if (apkFile == null) {\n            throw new IllegalArgumentException(\"ApkFile cannot be empty.\");\n        }\n        if (!apkFile.isSplit()) {\n            throw new RuntimeException(\"Apk file does not contain any split.\");\n        }\n        mApkEntries = apkFile.getEntries();\n        String[] entryIds = new String[mApkEntries.size()];\n        CharSequence[] entryNames = new CharSequence[mApkEntries.size()];\n        for (int i = 0; i < mApkEntries.size(); ++i) {\n            ApkFile.Entry entry = mApkEntries.get(i);\n            entryIds[i] = entry.id;\n            entryNames[i] = entry.toLocalizedString(requireActivity());\n        }\n        mViewBuilder = new SearchableMultiChoiceDialogBuilder<>(requireActivity(), entryIds, entryNames)\n                .showSelectAll(false)\n                .addDisabledItems(getUnsupportedOrRequiredSplitIds());\n        mViewBuilder.create(); // Necessary to trigger multichoice dialog\n        return mViewBuilder.getView();\n    }\n\n    @Override\n    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {\n        mViewBuilder.addSelections(getInitialSelections())\n                .setOnMultiChoiceClickListener((dialog, which, item, isChecked) -> {\n                    if (isChecked) {\n                        mViewBuilder.addSelections(select(which));\n                    } else {\n                        int[] itemsToDeselect = deselect(which);\n                        if (itemsToDeselect == null) {\n                            // This item can't be deselected, reselect the item\n                            mViewBuilder.addSelections(new int[]{which});\n                        } else {\n                            mViewBuilder.removeSelections(itemsToDeselect);\n                        }\n                    }\n                    mViewBuilder.reloadListUi();\n                });\n    }\n\n    @NonNull\n    public int[] getInitialSelections() {\n        List<Integer> selections = new ArrayList<>();\n        try {\n            HashSet<String> splitNames = new HashSet<>();\n            // See if the app has been installed\n            if (mViewModel.getInstalledPackageInfo() != null) {\n                ApplicationInfo info = mViewModel.getInstalledPackageInfo().applicationInfo;\n                try (ApkFile installedApkFile = ApkSource.getApkSource(info).resolve()) {\n                    for (ApkFile.Entry apkEntry : installedApkFile.getEntries()) {\n                        splitNames.add(apkEntry.name);\n                    }\n                }\n            }\n            if (splitNames.size() > 0) {\n                for (ApkFile.Entry apkEntry : mApkEntries) {\n                    if (!splitNames.contains(apkEntry.name)) {\n                        // Ignore splits that weren't selected in the previous installation\n                        continue;\n                    }\n                    mSelectedSplits.add(apkEntry.id);\n                    HashSet<Integer> types = mSeenSplits.get(apkEntry.getFeature());\n                    if (types == null) {\n                        types = new HashSet<>();\n                        mSeenSplits.put(apkEntry.getFeature(), types);\n                    }\n                    types.add(apkEntry.type);\n                }\n                // Fall-through deliberately to see if there are any new requirements\n            }\n        } catch (ApkFile.ApkFileException ignored) {\n        }\n        // Set up features\n        for (int i = 0; i < mApkEntries.size(); ++i) {\n            ApkFile.Entry apkEntry = mApkEntries.get(i);\n            if (mSelectedSplits.contains(apkEntry.id)) {\n                // Features already set\n                selections.add(i);\n                continue;\n            }\n            if (apkEntry.isRequired()) {\n                // Required splits are selected by default\n                mSelectedSplits.add(apkEntry.id);\n                selections.add(i);\n                HashSet<Integer> types = mSeenSplits.get(apkEntry.getFeature());\n                if (types == null) {\n                    types = new HashSet<>();\n                    mSeenSplits.put(apkEntry.getFeature(), types);\n                }\n                types.add(apkEntry.type);\n            }\n        }\n        // Select feature-dependencies based on the items selected above.\n        // Only selecting the first item works because the splits are already ranked.\n        for (int i = 0; i < mApkEntries.size(); ++i) {\n            ApkFile.Entry apkEntry = mApkEntries.get(i);\n            if (mSelectedSplits.contains(apkEntry.id)) {\n                // Already selected\n                continue;\n            }\n            HashSet<Integer> types = mSeenSplits.get(apkEntry.getFeature());\n            if (types == null) {\n                // This feature was not selected earlier\n                continue;\n            }\n            switch (apkEntry.type) {\n                case ApkFile.APK_BASE:\n                case ApkFile.APK_SPLIT_FEATURE:\n                case ApkFile.APK_SPLIT_UNKNOWN:\n                case ApkFile.APK_SPLIT:\n                    // Never reached.\n                    break;\n                case ApkFile.APK_SPLIT_DENSITY:\n                    if (!types.contains(ApkFile.APK_SPLIT_DENSITY)) {\n                        types.add(ApkFile.APK_SPLIT_DENSITY);\n                        selections.add(i);\n                        mSelectedSplits.add(apkEntry.id);\n                    }\n                    break;\n                case ApkFile.APK_SPLIT_ABI:\n                    if (!types.contains(ApkFile.APK_SPLIT_ABI)) {\n                        types.add(ApkFile.APK_SPLIT_ABI);\n                        selections.add(i);\n                        mSelectedSplits.add(apkEntry.id);\n                    }\n                    break;\n                case ApkFile.APK_SPLIT_LOCALE:\n                    if (!types.contains(ApkFile.APK_SPLIT_LOCALE)) {\n                        types.add(ApkFile.APK_SPLIT_LOCALE);\n                        selections.add(i);\n                        mSelectedSplits.add(apkEntry.id);\n                    }\n                    break;\n                default:\n                    throw new RuntimeException(\"Invalid split type.\");\n            }\n        }\n        return ArrayUtils.convertToIntArray(selections);\n    }\n\n    @NonNull\n    private List<String> getUnsupportedOrRequiredSplitIds() {\n        List<String> unsupportedOrRequiredSplits = new ArrayList<>();\n        for (ApkFile.Entry apkEntry : mApkEntries) {\n            if (!apkEntry.supported() || apkEntry.isRequired()) {\n                unsupportedOrRequiredSplits.add(apkEntry.id);\n            }\n        }\n        return unsupportedOrRequiredSplits;\n    }\n\n    @NonNull\n    private int[] select(int index) {\n        List<Integer> selections = new ArrayList<>();\n        ApkFile.Entry selectedEntry = mApkEntries.get(index);\n        String feature = selectedEntry.getFeature();\n        HashSet<Integer> types = mSeenSplits.get(feature);\n        if (types == null) {\n            types = new HashSet<>();\n            mSeenSplits.put(feature, types);\n        }\n        mSelectedSplits.add(selectedEntry.id); // We don't need to add it to selections because it's already checked\n        for (int i = 0; i < mApkEntries.size(); ++i) {\n            ApkFile.Entry apkEntry = mApkEntries.get(i);\n            if (Objects.equals(apkEntry.getFeature(), feature) && apkEntry.type != selectedEntry.type) {\n                // Match only the entries with the same feature and select at least one item for each required type.\n                switch (apkEntry.type) {\n                    case ApkFile.APK_BASE:\n                    case ApkFile.APK_SPLIT_FEATURE:\n                        // FIXME: 7/7/23 Never reached?\n                        selections.add(i);\n                        mSelectedSplits.add(apkEntry.id);\n                        break;\n                    case ApkFile.APK_SPLIT_UNKNOWN:\n                    case ApkFile.APK_SPLIT:\n                        break;\n                    case ApkFile.APK_SPLIT_DENSITY:\n                        if (!types.contains(ApkFile.APK_SPLIT_DENSITY)) {\n                            types.add(ApkFile.APK_SPLIT_DENSITY);\n                            selections.add(i);\n                            mSelectedSplits.add(apkEntry.id);\n                        }\n                        break;\n                    case ApkFile.APK_SPLIT_ABI:\n                        if (!types.contains(ApkFile.APK_SPLIT_ABI)) {\n                            types.add(ApkFile.APK_SPLIT_ABI);\n                            selections.add(i);\n                            mSelectedSplits.add(apkEntry.id);\n                        }\n                        break;\n                    case ApkFile.APK_SPLIT_LOCALE:\n                        if (!types.contains(ApkFile.APK_SPLIT_LOCALE)) {\n                            types.add(ApkFile.APK_SPLIT_LOCALE);\n                            selections.add(i);\n                            mSelectedSplits.add(apkEntry.id);\n                        }\n                        break;\n                    default:\n                        throw new RuntimeException(\"Invalid split type.\");\n                }\n            }\n        }\n        return ArrayUtils.convertToIntArray(selections);\n    }\n\n    @Nullable\n    private int[] deselect(int index) {\n        ApkFile.Entry deselectedEntry = mApkEntries.get(index);\n        if (deselectedEntry.isRequired()) {\n            // 1. This is a required split, can't be deselected\n            return null;\n        }\n        boolean featureSplit = deselectedEntry.type == ApkFile.APK_SPLIT_FEATURE;\n        String deselectedFeature = deselectedEntry.getFeature();\n        if (featureSplit) {\n            // 2. If this is a feature split (base.apk is always a required split), deselect all the associated splits\n            List<Integer> deselectedSplits = new ArrayList<>();\n            mSeenSplits.remove(deselectedFeature);\n            for (int i = 0; i < mApkEntries.size(); ++i) {\n                ApkFile.Entry apkEntry = mApkEntries.get(i);\n                if (Objects.equals(apkEntry.getFeature(), deselectedFeature)) {\n                    // Split has the same feature\n                    if (mSelectedSplits.contains(apkEntry.id)) {\n                        deselectedSplits.add(i);\n                        mSelectedSplits.remove(apkEntry.id);\n                    }\n                }\n            }\n            return ArrayUtils.convertToIntArray(deselectedSplits);\n        }\n        // 3. This isn't a feature split. Find all the splits by the same type and see if at least one split is\n        // selected. If not, this split can't be deselected.\n        boolean selectedAnySplits = false;\n        for (int i = 0; i < mApkEntries.size(); ++i) {\n            ApkFile.Entry apkEntry = mApkEntries.get(i);\n            if (i != index\n                    && deselectedEntry.type == apkEntry.type\n                    && Objects.equals(apkEntry.getFeature(), deselectedFeature)\n                    && mSelectedSplits.contains(apkEntry.id)) {\n                // Split has the same type and is selected\n                selectedAnySplits = true;\n                break;\n            }\n        }\n        if (selectedAnySplits) {\n            // At least one item is selected, deselect the current one\n            mSelectedSplits.remove(deselectedEntry.id);\n            return EmptyArray.INT;\n        }\n        // This entry can't be deselected\n        return null;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/apk/splitapk/SplitApkExporter.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.apk.splitapk;\n\nimport android.content.pm.ApplicationInfo;\nimport android.content.pm.PackageInfo;\nimport android.graphics.Bitmap;\nimport android.os.UserHandleHidden;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.WorkerThread;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.zip.Deflater;\nimport java.util.zip.ZipEntry;\nimport java.util.zip.ZipOutputStream;\n\nimport io.github.muntashirakon.AppManager.apk.ApkUtils;\nimport io.github.muntashirakon.AppManager.utils.ContextUtils;\nimport io.github.muntashirakon.AppManager.utils.DigestUtils;\nimport io.github.muntashirakon.AppManager.utils.UIUtils;\nimport io.github.muntashirakon.io.IoUtils;\nimport io.github.muntashirakon.io.Path;\nimport io.github.muntashirakon.io.Paths;\n\n/**\n * Used to generate app bundle with .apks extension. This file has all the apks as well as 3 other\n * file, such as icon.png, meta.sai_v1.json, meta.sai_v2.json.<br />\n * meta.sai_v1.json contains the following properties: export_timestamp (long), label (string),\n * package (string), version_code (long) and version_name (string).<br />\n * meta.sai_v2.json contains the following properties: export_timestamp (long), split_apk (boolean),\n * label (string), meta_version (long), min_sdk (long), package (string), target_sdk (long),\n * version_code (long), version_name (string), backup_components [ size (long), type (string) ]\n */\npublic final class SplitApkExporter {\n    @WorkerThread\n    public static void saveApks(@NonNull PackageInfo packageInfo, @NonNull Path apksFile) throws IOException {\n        try (OutputStream outputStream = apksFile.openOutputStream();\n             ZipOutputStream zipOutputStream = new ZipOutputStream(outputStream)) {\n            zipOutputStream.setMethod(ZipOutputStream.DEFLATED);\n            zipOutputStream.setLevel(Deflater.BEST_COMPRESSION);\n\n            saveApkInternal(zipOutputStream, packageInfo);\n        }\n    }\n\n    static void saveApkInternal(@NonNull ZipOutputStream zipOutputStream, @NonNull PackageInfo packageInfo) throws IOException {\n        ApplicationInfo applicationInfo = packageInfo.applicationInfo;\n        List<Path> apkFiles = getAllApkFiles(applicationInfo);\n        Collections.sort(apkFiles);\n\n        // Metadata\n        ApksMetadata apksMetadata = new ApksMetadata(packageInfo);\n        apksMetadata.writeMetadata(zipOutputStream);\n        \n        // Add icon\n        Bitmap bitmap = UIUtils.getBitmapFromDrawable(applicationInfo.loadIcon(ContextUtils.getContext().getPackageManager()));\n        ByteArrayOutputStream pngOutputStream = new ByteArrayOutputStream();\n        bitmap.compress(Bitmap.CompressFormat.PNG, 100, pngOutputStream);\n        addBytes(zipOutputStream, pngOutputStream.toByteArray(), ApksMetadata.ICON_FILE, apksMetadata.exportTimestamp);\n\n        // Add apk files\n        for (Path apkFile : apkFiles) {\n            addFile(zipOutputStream, apkFile, apkFile.getName(), apksMetadata.exportTimestamp);\n        }\n\n        // Add OBB files if possible\n        Path obbDir = null;\n        try {\n            obbDir = ApkUtils.getObbDir(packageInfo.packageName, UserHandleHidden.getUserId(applicationInfo.uid));\n        } catch (IOException ignore) {\n        }\n        if (obbDir != null) {\n            Path[] obbFiles = obbDir.listFiles();\n            for (Path obbFile : obbFiles) {\n                addFile(zipOutputStream, obbFile, obbFile.getName(), apksMetadata.exportTimestamp);\n            }\n        }\n    }\n\n    static void addFile(@NonNull ZipOutputStream zipOutputStream, @NonNull Path filePath, @NonNull String name,\n                               long timestamp) throws IOException {\n        ZipEntry zipEntry = new ZipEntry(name);\n        zipEntry.setMethod(ZipEntry.DEFLATED);\n        zipEntry.setSize(filePath.length());\n        zipEntry.setCrc(DigestUtils.calculateCrc32(filePath));\n        zipEntry.setTime(timestamp);\n        zipOutputStream.putNextEntry(zipEntry);\n        try (InputStream apkInputStream = filePath.openInputStream()) {\n            IoUtils.copy(apkInputStream, zipOutputStream);\n        }\n        zipOutputStream.closeEntry();\n    }\n\n    static void addBytes(@NonNull ZipOutputStream zipOutputStream, @NonNull byte[] bytes, @NonNull String name,\n                               long timestamp) throws IOException {\n        ZipEntry zipEntry = new ZipEntry(name);\n        zipEntry.setMethod(ZipEntry.DEFLATED);\n        zipEntry.setSize(bytes.length);\n        zipEntry.setCrc(DigestUtils.calculateCrc32(bytes));\n        zipEntry.setTime(timestamp);\n        zipOutputStream.putNextEntry(zipEntry);\n        zipOutputStream.write(bytes);\n        zipOutputStream.closeEntry();\n    }\n\n    @NonNull\n    private static List<Path> getAllApkFiles(@NonNull ApplicationInfo applicationInfo) {\n        List<Path> apkFiles = new ArrayList<>();\n        apkFiles.add(Paths.get(applicationInfo.publicSourceDir));\n        if (applicationInfo.splitPublicSourceDirs != null) {\n            // FIXME: 8/5/22 This does not work for disabled apps\n            for (String splitPath : applicationInfo.splitPublicSourceDirs)\n                apkFiles.add(Paths.get(splitPath));\n        }\n        return apkFiles;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/apk/whatsnew/ApkWhatsNewFinder.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.apk.whatsnew;\n\nimport android.content.Context;\nimport android.content.pm.ApplicationInfo;\nimport android.content.pm.FeatureInfo;\nimport android.content.pm.PackageInfo;\nimport android.content.pm.PackageManager;\nimport android.content.pm.PermissionInfo;\nimport android.os.Build;\n\nimport androidx.annotation.IntDef;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.WorkerThread;\nimport androidx.core.content.pm.PackageInfoCompat;\n\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Set;\n\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.rules.RuleType;\nimport io.github.muntashirakon.AppManager.rules.compontents.ComponentUtils;\nimport io.github.muntashirakon.AppManager.utils.ArrayUtils;\nimport io.github.muntashirakon.AppManager.utils.LangUtils;\nimport io.github.muntashirakon.AppManager.utils.PackageUtils;\nimport io.github.muntashirakon.AppManager.utils.ThreadUtils;\nimport io.github.muntashirakon.AppManager.utils.Utils;\n\npublic class ApkWhatsNewFinder {\n    @IntDef(value = {\n            CHANGE_ADD,\n            CHANGE_REMOVED,\n            CHANGE_INFO\n    })\n    @Retention(RetentionPolicy.SOURCE)\n    public @interface ChangeType {\n    }\n\n    public static final int CHANGE_ADD = 1;\n    public static final int CHANGE_REMOVED = 2;\n    public static final int CHANGE_INFO = 3;\n\n    public static final int VERSION_INFO = 0;\n    public static final int TRACKER_INFO = 1;\n    public static final int SIGNING_CERT_SHA256 = 2;\n    public static final int PERMISSION_INFO = 3;\n    public static final int COMPONENT_INFO = 4;\n    public static final int FEATURE_INFO = 5;\n    public static final int SDK_INFO = 6;\n\n    private static final int INFO_COUNT = 7;\n\n    private static ApkWhatsNewFinder sInstance;\n\n    public static ApkWhatsNewFinder getInstance() {\n        if (sInstance == null) sInstance = new ApkWhatsNewFinder();\n        return sInstance;\n    }\n\n    private final Set<String> mTmpInfo = new HashSet<>();\n\n    /**\n     * Get changes between two packages: one is the apk file and other is the installed app\n     *\n     * @param newPkgInfo Package info fetched with {@link PackageManager#getPackageArchiveInfo(String, int)}\n     *                   with the following flags: {@link PackageManager#GET_META_DATA}, {@link PackageManager#GET_SIGNATURES}\n     *                   {@link PackageManager#GET_PERMISSIONS}, {@link PackageManager#GET_CONFIGURATIONS},\n     *                   {@link PackageManager#GET_SHARED_LIBRARY_FILES}\n     * @param oldPkgInfo Package info fetched with {@link PackageManager#getPackageInfo(String, int)}\n     *                   with the following flags: {@link PackageManager#GET_META_DATA}, {@link PackageManager#GET_SIGNATURES} or\n     *                   {@link PackageManager#GET_SIGNING_CERTIFICATES}, {@link PackageManager#GET_PERMISSIONS},\n     *                   {@link PackageManager#GET_CONFIGURATIONS}, {@link PackageManager#GET_SHARED_LIBRARY_FILES}\n     * @return Changes\n     */\n    @WorkerThread\n    @NonNull\n    public Change[][] getWhatsNew(@NonNull Context context, @NonNull PackageInfo newPkgInfo,\n                                  @NonNull PackageInfo oldPkgInfo) {\n        ApplicationInfo newAppInfo = newPkgInfo.applicationInfo;\n        ApplicationInfo oldAppInfo = oldPkgInfo.applicationInfo;\n        Change[][] changes = new Change[INFO_COUNT][];\n        String[] componentInfo = context.getResources().getStringArray(R.array.whats_new_titles);\n        // Version info\n        long newVersionCode = PackageInfoCompat.getLongVersionCode(newPkgInfo);\n        long oldVersionCode = PackageInfoCompat.getLongVersionCode(oldPkgInfo);\n        if (newVersionCode != oldVersionCode) {\n            String newVersionInfo = newPkgInfo.versionName + \" (\" + newVersionCode + ')';\n            String oldVersionInfo = oldPkgInfo.versionName + \" (\" + oldVersionCode + ')';\n            changes[VERSION_INFO] = new Change[]{\n                    new Change(CHANGE_INFO, componentInfo[VERSION_INFO]),\n                    new Change(CHANGE_ADD, newVersionInfo),\n                    new Change(CHANGE_REMOVED, oldVersionInfo)\n            };\n        } else changes[VERSION_INFO] = ArrayUtils.emptyArray(Change.class);\n        if (ThreadUtils.isInterrupted()) {\n            return changes;\n        }\n        // Tracker info\n        HashMap<String, RuleType> newPkgComponents = PackageUtils.collectComponentClassNames(newPkgInfo);\n        HashMap<String, RuleType> oldPkgComponents = PackageUtils.collectComponentClassNames(oldPkgInfo);\n        List<Change> componentChanges = new ArrayList<>();\n        componentChanges.add(new Change(CHANGE_INFO, componentInfo[COMPONENT_INFO]));\n        componentChanges.addAll(findChanges(newPkgComponents.keySet(), oldPkgComponents.keySet()));\n        int newTrackerCount = 0;\n        int oldTrackerCount = 0;\n        for (Change component : componentChanges) {\n            if (ComponentUtils.isTracker(component.value)) {\n                if (component.changeType == CHANGE_ADD) ++newTrackerCount;\n                else if (component.changeType == CHANGE_REMOVED) ++oldTrackerCount;\n            }\n        }\n        if (newTrackerCount == 0 && oldTrackerCount == 0) {\n            changes[TRACKER_INFO] = ArrayUtils.emptyArray(Change.class);\n        } else {\n            Change newTrackers = new Change(CHANGE_ADD, context.getResources()\n                    .getQuantityString(R.plurals.no_of_trackers, newTrackerCount, newTrackerCount));\n            Change oldTrackers = new Change(CHANGE_REMOVED, context.getResources()\n                    .getQuantityString(R.plurals.no_of_trackers, oldTrackerCount, oldTrackerCount));\n            changes[TRACKER_INFO] = new Change[]{new Change(CHANGE_INFO, componentInfo[TRACKER_INFO]), newTrackers, oldTrackers};\n        }\n        if (ThreadUtils.isInterrupted()) {\n            return changes;\n        }\n        // Sha256 of signing certificates\n        Set<String> newCertSha256 = new HashSet<>(Arrays.asList(PackageUtils.getSigningCertSha256Checksum(newPkgInfo, true)));\n        Set<String> oldCertSha256 = new HashSet<>(Arrays.asList(PackageUtils.getSigningCertSha256Checksum(oldPkgInfo)));\n        List<Change> certSha256Changes = new ArrayList<>();\n        certSha256Changes.add(new Change(CHANGE_INFO, componentInfo[SIGNING_CERT_SHA256]));\n        certSha256Changes.addAll(findChanges(newCertSha256, oldCertSha256));\n        changes[SIGNING_CERT_SHA256] = certSha256Changes.size() == 1 ? ArrayUtils.emptyArray(Change.class) : certSha256Changes.toArray(new Change[0]);\n        if (ThreadUtils.isInterrupted()) {\n            return changes;\n        }\n        // Permissions\n        Set<String> newPermissions = new HashSet<>();\n        Set<String> oldPermissions = new HashSet<>();\n        if (newPkgInfo.permissions != null)\n            for (PermissionInfo permissionInfo : newPkgInfo.permissions)\n                newPermissions.add(permissionInfo.name);\n        if (newPkgInfo.requestedPermissions != null)\n            newPermissions.addAll(Arrays.asList(newPkgInfo.requestedPermissions));\n        if (oldPkgInfo.permissions != null)\n            for (PermissionInfo permissionInfo : oldPkgInfo.permissions)\n                oldPermissions.add(permissionInfo.name);\n        if (oldPkgInfo.requestedPermissions != null)\n            oldPermissions.addAll(Arrays.asList(oldPkgInfo.requestedPermissions));\n        List<Change> permissionChanges = new ArrayList<>();\n        permissionChanges.add(new Change(CHANGE_INFO, componentInfo[PERMISSION_INFO]));\n        permissionChanges.addAll(findChanges(newPermissions, oldPermissions));\n        changes[PERMISSION_INFO] = permissionChanges.size() == 1 ? ArrayUtils.emptyArray(Change.class) : permissionChanges.toArray(new Change[0]);\n        // Component info\n        changes[COMPONENT_INFO] = componentChanges.size() == 1 ? ArrayUtils.emptyArray(Change.class) : componentChanges.toArray(new Change[0]);\n        if (ThreadUtils.isInterrupted()) {\n            return changes;\n        }\n        // Feature info\n        Set<String> newFeatures = new HashSet<>();\n        Set<String> oldFeatures = new HashSet<>();\n        if (newPkgInfo.reqFeatures != null)\n            for (FeatureInfo featureInfo : newPkgInfo.reqFeatures)\n                if (featureInfo.name != null) newFeatures.add(featureInfo.name);\n                else newFeatures.add(\"OpenGL ES v\" + Utils.getGlEsVersion(featureInfo.reqGlEsVersion));\n        if (oldPkgInfo.reqFeatures != null)\n            for (FeatureInfo featureInfo : oldPkgInfo.reqFeatures)\n                if (featureInfo.name != null) oldFeatures.add(featureInfo.name);\n                else oldFeatures.add(\"OpenGL ES v\" + Utils.getGlEsVersion(featureInfo.reqGlEsVersion));\n        List<Change> featureChanges = new ArrayList<>();\n        featureChanges.add(new Change(CHANGE_INFO, componentInfo[FEATURE_INFO]));\n        featureChanges.addAll(findChanges(newFeatures, oldFeatures));\n        changes[FEATURE_INFO] = featureChanges.size() == 1 ? ArrayUtils.emptyArray(Change.class) : featureChanges.toArray(new Change[0]);\n        if (ThreadUtils.isInterrupted()) {\n            return changes;\n        }\n        // SDK\n        final StringBuilder newSdk = new StringBuilder(context.getString(R.string.sdk_max))\n                .append(LangUtils.getSeparatorString()).append(newAppInfo.targetSdkVersion);\n        final StringBuilder oldSdk = new StringBuilder(context.getString(R.string.sdk_max))\n                .append(LangUtils.getSeparatorString()).append(oldAppInfo.targetSdkVersion);\n        if (Build.VERSION.SDK_INT > Build.VERSION_CODES.M) {\n            newSdk.append(\", \").append(context.getString(R.string.sdk_min))\n                    .append(LangUtils.getSeparatorString()).append(newAppInfo.minSdkVersion);\n            oldSdk.append(\", \").append(context.getString(R.string.sdk_min))\n                    .append(LangUtils.getSeparatorString()).append(oldAppInfo.minSdkVersion);\n        }\n        if (!newSdk.toString().equals(oldSdk.toString())) {\n            changes[SDK_INFO] = new Change[]{\n                    new Change(CHANGE_INFO, componentInfo[SDK_INFO]),\n                    new Change(CHANGE_ADD, newSdk.toString()),\n                    new Change(CHANGE_REMOVED, oldSdk.toString())\n            };\n        } else changes[SDK_INFO] = ArrayUtils.emptyArray(Change.class);\n        return changes;\n    }\n\n    @NonNull\n    private List<Change> findChanges(Set<String> newInfo, Set<String> oldInfo) {\n        List<Change> changeList = new ArrayList<>();\n        mTmpInfo.clear();\n        mTmpInfo.addAll(newInfo);\n        newInfo.removeAll(oldInfo);\n        for (String info : newInfo) changeList.add(new Change(CHANGE_ADD, info));\n        oldInfo.removeAll(mTmpInfo);\n        for (String info : oldInfo) changeList.add(new Change(CHANGE_REMOVED, info));\n        return changeList;\n    }\n\n    public static class Change {\n        @ChangeType\n        public int changeType;\n        @NonNull\n        public String value;\n\n        public Change(int changeType, @NonNull String value) {\n            this.changeType = changeType;\n            this.value = value;\n        }\n\n        @NonNull\n        @Override\n        public String toString() {\n            return \"Change{\" +\n                    \"changeType=\" + changeType +\n                    \", value='\" + value + '\\'' +\n                    '}';\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/apk/whatsnew/WhatsNewDialogFragment.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.apk.whatsnew;\n\nimport android.app.Dialog;\nimport android.content.pm.PackageInfo;\nimport android.os.Bundle;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.core.os.BundleCompat;\nimport androidx.fragment.app.DialogFragment;\nimport androidx.fragment.app.FragmentManager;\nimport androidx.fragment.app.FragmentTransaction;\nimport androidx.lifecycle.ViewModelProvider;\nimport androidx.recyclerview.widget.LinearLayoutManager;\nimport androidx.recyclerview.widget.RecyclerView;\n\nimport com.google.android.material.dialog.MaterialAlertDialogBuilder;\n\nimport java.util.Objects;\n\nimport io.github.muntashirakon.AppManager.R;\n\npublic class WhatsNewDialogFragment extends DialogFragment {\n    public static final String TAG = WhatsNewDialogFragment.class.getSimpleName();\n    private static final String ARG_NEW_PKG_INFO = \"new_pkg\";\n    private static final String ARG_OLD_PKG_INFO = \"old_pkg\";\n\n    @NonNull\n    public static WhatsNewDialogFragment getInstance(@NonNull PackageInfo newPkgInfo, @NonNull PackageInfo oldPkgInfo) {\n        WhatsNewDialogFragment dialog = new WhatsNewDialogFragment();\n        Bundle args = new Bundle();\n        args.putParcelable(ARG_NEW_PKG_INFO, newPkgInfo);\n        args.putParcelable(ARG_OLD_PKG_INFO, oldPkgInfo);\n        dialog.setArguments(args);\n        return dialog;\n    }\n\n    private WhatsNewRecyclerAdapter mAdapter;\n    private PackageInfo mNewPkgInfo;\n    private PackageInfo mOldPkgInfo;\n    private View mDialogView;\n\n    @NonNull\n    @Override\n    public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {\n        mDialogView = View.inflate(requireContext(), R.layout.dialog_whats_new, null);\n        return new MaterialAlertDialogBuilder(requireContext())\n                .setTitle(R.string.whats_new)\n                .setView(mDialogView)\n                .setNegativeButton(R.string.ok, null)\n                .create();\n    }\n\n    @Nullable\n    @Override\n    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {\n        return mDialogView;\n    }\n\n    @Override\n    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {\n        WhatsNewDialogViewModel viewModel = new ViewModelProvider(this).get(WhatsNewDialogViewModel.class);\n        mNewPkgInfo = Objects.requireNonNull(BundleCompat.getParcelable(requireArguments(), ARG_NEW_PKG_INFO, PackageInfo.class));\n        mOldPkgInfo = Objects.requireNonNull(BundleCompat.getParcelable(requireArguments(), ARG_OLD_PKG_INFO, PackageInfo.class));\n        RecyclerView recyclerView = mDialogView.findViewById(android.R.id.list);\n        recyclerView.setLayoutManager(new LinearLayoutManager(requireContext()));\n        mAdapter = new WhatsNewRecyclerAdapter(requireContext(), mNewPkgInfo.packageName);\n        recyclerView.setAdapter(mAdapter);\n        viewModel.getChangesLiveData().observe(this, mAdapter::setAdapterList);\n        viewModel.loadChanges(mNewPkgInfo, mOldPkgInfo);\n    }\n\n    @Override\n    public void show(@NonNull FragmentManager manager, @Nullable String tag) {\n        FragmentTransaction ft = manager.beginTransaction();\n        ft.add(this, tag);\n        ft.commitAllowingStateLoss();\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/apk/whatsnew/WhatsNewDialogViewModel.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.apk.whatsnew;\n\nimport android.app.Application;\nimport android.content.pm.PackageInfo;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.lifecycle.AndroidViewModel;\nimport androidx.lifecycle.LiveData;\nimport androidx.lifecycle.MutableLiveData;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.concurrent.Future;\n\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.utils.ThreadUtils;\n\npublic class WhatsNewDialogViewModel extends AndroidViewModel {\n    private final MutableLiveData<List<ApkWhatsNewFinder.Change>> mChangesLiveData = new MutableLiveData<>();\n    @Nullable\n    private Future<?> mWhatsNewResult;\n\n    public WhatsNewDialogViewModel(@NonNull Application application) {\n        super(application);\n    }\n\n    @Override\n    protected void onCleared() {\n        if (mWhatsNewResult != null) {\n            mWhatsNewResult.cancel(true);\n        }\n        super.onCleared();\n    }\n\n    public LiveData<List<ApkWhatsNewFinder.Change>> getChangesLiveData() {\n        return mChangesLiveData;\n    }\n\n    public void loadChanges(PackageInfo newPkgInfo, PackageInfo oldPkgInfo) {\n        mWhatsNewResult = ThreadUtils.postOnBackgroundThread(() -> {\n            ApkWhatsNewFinder.Change[][] changes = ApkWhatsNewFinder.getInstance().getWhatsNew(getApplication(),\n                    newPkgInfo, oldPkgInfo);\n            List<ApkWhatsNewFinder.Change> changeList = new ArrayList<>();\n            for (ApkWhatsNewFinder.Change[] changes1 : changes) {\n                if (changes1.length > 0) {\n                    Collections.addAll(changeList, changes1);\n                }\n            }\n            if (changeList.size() == 0) {\n                changeList.add(new ApkWhatsNewFinder.Change(ApkWhatsNewFinder.CHANGE_INFO,\n                        getApplication().getString(R.string.no_changes)));\n            }\n            mChangesLiveData.postValue(changeList);\n        });\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/apk/whatsnew/WhatsNewFragment.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.apk.whatsnew;\n\nimport android.content.pm.PackageInfo;\nimport android.os.Bundle;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.core.os.BundleCompat;\nimport androidx.fragment.app.Fragment;\nimport androidx.lifecycle.ViewModelProvider;\nimport androidx.recyclerview.widget.LinearLayoutManager;\nimport androidx.recyclerview.widget.RecyclerView;\n\nimport java.util.Objects;\n\nimport io.github.muntashirakon.AppManager.R;\n\npublic class WhatsNewFragment extends Fragment {\n    public static final String TAG = WhatsNewFragment.class.getSimpleName();\n    private static final String ARG_NEW_PKG_INFO = \"new_pkg\";\n    private static final String ARG_OLD_PKG_INFO = \"old_pkg\";\n\n    @NonNull\n    public static WhatsNewFragment getInstance(@NonNull PackageInfo newPkgInfo, @NonNull PackageInfo oldPkgInfo) {\n        WhatsNewFragment dialog = new WhatsNewFragment();\n        Bundle args = new Bundle();\n        args.putParcelable(ARG_NEW_PKG_INFO, newPkgInfo);\n        args.putParcelable(ARG_OLD_PKG_INFO, oldPkgInfo);\n        dialog.setArguments(args);\n        return dialog;\n    }\n\n    @Nullable\n    @Override\n    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {\n        return View.inflate(requireContext(), R.layout.dialog_whats_new, null);\n    }\n\n    @Override\n    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {\n        WhatsNewDialogViewModel viewModel = new ViewModelProvider(this).get(WhatsNewDialogViewModel.class);\n        PackageInfo newPkgInfo = Objects.requireNonNull(BundleCompat.getParcelable(requireArguments(), ARG_NEW_PKG_INFO, PackageInfo.class));\n        PackageInfo oldPkgInfo = Objects.requireNonNull(BundleCompat.getParcelable(requireArguments(), ARG_OLD_PKG_INFO, PackageInfo.class));\n        RecyclerView recyclerView = view.findViewById(android.R.id.list);\n        recyclerView.setLayoutManager(new LinearLayoutManager(requireContext()));\n        WhatsNewRecyclerAdapter adapter = new WhatsNewRecyclerAdapter(requireContext(), newPkgInfo.packageName);\n        recyclerView.setAdapter(adapter);\n        viewModel.getChangesLiveData().observe(getViewLifecycleOwner(), adapter::setAdapterList);\n        viewModel.loadChanges(newPkgInfo, oldPkgInfo);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/apk/whatsnew/WhatsNewRecyclerAdapter.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.apk.whatsnew;\n\nimport android.content.Context;\nimport android.graphics.Typeface;\nimport android.util.TypedValue;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\n\nimport androidx.annotation.NonNull;\n\nimport com.google.android.material.textview.MaterialTextView;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.util.AdapterUtils;\nimport io.github.muntashirakon.AppManager.utils.UIUtils;\nimport io.github.muntashirakon.AppManager.utils.appearance.ColorCodes;\nimport io.github.muntashirakon.widget.RecyclerView;\n\nclass WhatsNewRecyclerAdapter extends RecyclerView.Adapter<WhatsNewRecyclerAdapter.ViewHolder> {\n    private final List<ApkWhatsNewFinder.Change> mAdapterList = new ArrayList<>();\n    private final int mColorAdd;\n    private final int mColorRemove;\n    private final int mColorNeutral;\n    private final Typeface mTypefaceNormal;\n    private final Typeface mTypefaceMedium;\n    private final String mPackageName;\n\n    WhatsNewRecyclerAdapter(Context context, @NonNull String packageName) {\n        mPackageName = packageName;\n        mColorAdd = ColorCodes.getWhatsNewPlusIndicatorColor(context);\n        mColorRemove = ColorCodes.getWhatsNewMinusIndicatorColor(context);\n        mColorNeutral = UIUtils.getTextColorPrimary(context);\n        mTypefaceNormal = Typeface.create(\"sans-serif\", Typeface.NORMAL);\n        mTypefaceMedium = Typeface.create(\"sans-serif-medium\", Typeface.NORMAL);\n    }\n\n    void setAdapterList(List<ApkWhatsNewFinder.Change> list) {\n        AdapterUtils.notifyDataSetChanged(this, mAdapterList, list);\n    }\n\n    @NonNull\n    @Override\n    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {\n        int layoutId;\n        if (viewType == ApkWhatsNewFinder.CHANGE_INFO) {\n            layoutId = R.layout.item_text_view;\n        } else {\n            layoutId = R.layout.item_whats_new;\n        }\n        View view = LayoutInflater.from(parent.getContext()).inflate(layoutId, parent, false);\n        return new ViewHolder(view);\n    }\n\n    @Override\n    public void onBindViewHolder(@NonNull ViewHolder holder, int position) {\n        ApkWhatsNewFinder.Change change = mAdapterList.get(position);\n        if (change.value.startsWith(mPackageName)) {\n            change.value = change.value.replaceFirst(mPackageName, \"\");\n        }\n        switch (change.changeType) {\n            case ApkWhatsNewFinder.CHANGE_ADD:\n                holder.changeSign.setText(\"+\");\n                holder.changeSign.setTextColor(mColorAdd);\n                holder.textView.setText(change.value);\n                holder.textView.setTextColor(mColorAdd);\n                break;\n            case ApkWhatsNewFinder.CHANGE_INFO:\n                holder.textView.setText(change.value);\n                holder.textView.setTextColor(mColorNeutral);\n                holder.textView.setTypeface(mTypefaceMedium);\n                holder.textView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 16);\n                break;\n            case ApkWhatsNewFinder.CHANGE_REMOVED:\n                holder.changeSign.setText(\"-\");\n                holder.changeSign.setTextColor(mColorRemove);\n                holder.textView.setText(change.value);\n                holder.textView.setTextColor(mColorRemove);\n                break;\n        }\n    }\n\n    @Override\n    public int getItemCount() {\n        return mAdapterList.size();\n    }\n\n    @Override\n    public int getItemViewType(int position) {\n        return mAdapterList.get(position).changeType;\n    }\n\n    static class ViewHolder extends RecyclerView.ViewHolder {\n        final MaterialTextView changeSign;\n        final MaterialTextView textView;\n\n        public ViewHolder(@NonNull View itemView) {\n            super(itemView);\n            changeSign = itemView.findViewById(android.R.id.text2);\n            textView = itemView.findViewById(android.R.id.text1);\n        }\n    }\n}"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/app/AndroidFragment.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.app;\n\nimport android.content.Context;\n\nimport androidx.annotation.NonNull;\nimport androidx.appcompat.app.ActionBar;\nimport androidx.appcompat.app.AppCompatActivity;\nimport androidx.fragment.app.Fragment;\nimport androidx.fragment.app.FragmentActivity;\n\nimport java.util.Optional;\n\npublic class AndroidFragment extends Fragment {\n    @NonNull\n    protected Optional<Context> getFragmentContext() {\n        return Optional.ofNullable(getContext());\n    }\n\n    @NonNull\n    protected Optional<FragmentActivity> getFragmentActivity() {\n        return Optional.ofNullable(getActivity());\n    }\n\n    @NonNull\n    protected Optional<ActionBar> getActionBar() {\n        FragmentActivity activity = getActivity();\n        if (activity instanceof AppCompatActivity) {\n            return Optional.ofNullable(((AppCompatActivity) activity).getSupportActionBar());\n        }\n        return Optional.empty();\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/backup/BackupCryptSetupHelper.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.backup;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport io.github.muntashirakon.AppManager.crypto.AESCrypto;\nimport io.github.muntashirakon.AppManager.crypto.Crypto;\nimport io.github.muntashirakon.AppManager.crypto.CryptoException;\nimport io.github.muntashirakon.AppManager.crypto.DummyCrypto;\nimport io.github.muntashirakon.AppManager.crypto.ECCCrypto;\nimport io.github.muntashirakon.AppManager.crypto.OpenPGPCrypto;\nimport io.github.muntashirakon.AppManager.crypto.RSACrypto;\nimport io.github.muntashirakon.AppManager.crypto.ks.CompatUtil;\nimport io.github.muntashirakon.AppManager.settings.Prefs;\nimport io.github.muntashirakon.AppManager.utils.ContextUtils;\n\npublic class BackupCryptSetupHelper {\n    @NonNull\n    @CryptoUtils.Mode\n    public final String mode;\n    public final int version;\n    @NonNull\n    public final Crypto crypto;\n    private String keyIds;\n    private byte[] aes;\n    private byte[] iv;\n\n    public BackupCryptSetupHelper(@NonNull String mode, int version) throws CryptoException {\n        this.mode = mode;\n        this.version = version;\n        this.crypto = setup();\n    }\n\n    @Nullable\n    public String getKeyIds() {\n        return keyIds;\n    }\n\n    @Nullable\n    public byte[] getAes() {\n        return aes;\n    }\n\n    @Nullable\n    public byte[] getIv() {\n        return iv;\n    }\n\n    @NonNull\n    private Crypto setup() throws CryptoException {\n        switch (mode) {\n            case CryptoUtils.MODE_OPEN_PGP:\n                keyIds = Prefs.Encryption.getOpenPgpKeyIds();\n                return new OpenPGPCrypto(ContextUtils.getContext(), keyIds);\n            case CryptoUtils.MODE_AES: {\n                iv = generateIv();\n                AESCrypto aesCrypto = new AESCrypto(iv);\n                if (version < 4) {\n                    // Old backups use 32 bit MAC\n                    aesCrypto.setMacSizeBits(AESCrypto.MAC_SIZE_BITS_OLD);\n                }\n                return aesCrypto;\n            }\n            case CryptoUtils.MODE_RSA: {\n                iv = generateIv();\n                RSACrypto rsaCrypto = new RSACrypto(iv, null);\n                if (version < 4) {\n                    // Old backups use 32 bit MAC\n                    rsaCrypto.setMacSizeBits(AESCrypto.MAC_SIZE_BITS_OLD);\n                }\n                aes = rsaCrypto.getEncryptedAesKey();\n                return rsaCrypto;\n            }\n            case CryptoUtils.MODE_ECC: {\n                iv = generateIv();\n                ECCCrypto eccCrypto = new ECCCrypto(iv, null);\n                if (version < 4) {\n                    // Old backups use 32 bit MAC\n                    eccCrypto.setMacSizeBits(AESCrypto.MAC_SIZE_BITS_OLD);\n                }\n                aes = eccCrypto.getEncryptedAesKey();\n                return eccCrypto;\n            }\n            case CryptoUtils.MODE_NO_ENCRYPTION:\n            default:\n                return new DummyCrypto();\n        }\n    }\n\n    @NonNull\n    private static byte[] generateIv() {\n        byte[] iv = new byte[AESCrypto.GCM_IV_SIZE_BYTES];\n        CompatUtil.getPrng().nextBytes(iv);\n        return iv;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/backup/BackupDataDirectoryInfo.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.backup;\n\nimport android.annotation.SuppressLint;\nimport android.annotation.UserIdInt;\n\nimport androidx.annotation.IntDef;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.VisibleForTesting;\n\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.util.Locale;\n\nimport io.github.muntashirakon.AppManager.logs.Log;\nimport io.github.muntashirakon.io.Path;\nimport io.github.muntashirakon.io.Paths;\n\npublic class BackupDataDirectoryInfo {\n    public static final String TAG = BackupDataDirectoryInfo.class.getSimpleName();\n\n    @SuppressLint(\"SdCardPath\")\n    @NonNull\n    public static BackupDataDirectoryInfo getInfo(@NonNull String dataDir, @UserIdInt int userId) {\n        String storageCe = String.format(Locale.ROOT, \"/data/user/%d/\", userId);\n        if (dataDir.startsWith(\"/data/data/\") || dataDir.startsWith(storageCe)) {\n            return new BackupDataDirectoryInfo(dataDir, true, TYPE_INTERNAL, TYPE_CREDENTIAL_PROTECTED);\n        }\n        String storageDe = String.format(Locale.ROOT, \"/data/user_de/%d/\", userId);\n        if (dataDir.startsWith(storageDe)) {\n            return new BackupDataDirectoryInfo(dataDir, true, TYPE_INTERNAL, TYPE_DEVICE_PROTECTED);\n        }\n        if (dataDir.startsWith(\"/sdcard/\")) {\n            return getExternalInfo(dataDir, \"/sdcard/\");\n        }\n        if (dataDir.startsWith(\"/storage/sdcard/\")) {\n            return getExternalInfo(dataDir, \"/storage/sdcard/\");\n        }\n        if (dataDir.startsWith(\"/storage/sdcard0/\")) {\n            return getExternalInfo(dataDir, \"/storage/sdcard0/\");\n        }\n        String storageEmulatedDir = String.format(Locale.ROOT, \"/storage/emulated/%d/\", userId);\n        if (dataDir.startsWith(storageEmulatedDir)) {\n            return getExternalInfo(dataDir, storageEmulatedDir);\n        }\n        String dataMediaDir = String.format(Locale.ROOT, \"/data/media/%d/\", userId);\n        if (dataDir.startsWith(dataMediaDir)) {\n            return getExternalInfo(dataDir, dataMediaDir);\n        }\n        Log.i(TAG, \"getInfo: Unrecognized path %s, returning true as fallback.\", dataDir);\n        return new BackupDataDirectoryInfo(dataDir, true, TYPE_UNKNOWN, TYPE_CUSTOM);\n    }\n\n    @NonNull\n    private static BackupDataDirectoryInfo getExternalInfo(@NonNull String dataDir, @NonNull String baseDir) {\n        String relativeDir = dataDir.substring(baseDir.length()); // No starting separator\n        int subType;\n        if (relativeDir.startsWith(\"Android/data/\")) {\n            subType = TYPE_ANDROID_DATA;\n        } else if (relativeDir.startsWith(\"Android/obb/\")) {\n            subType = TYPE_ANDROID_OBB;\n        } else if (relativeDir.startsWith(\"Android/media/\")) {\n            subType = TYPE_ANDROID_MEDIA;\n        } else subType = TYPE_CUSTOM;\n        return new BackupDataDirectoryInfo(dataDir, Paths.get(baseDir).isDirectory(), TYPE_EXTERNAL, subType);\n    }\n\n    @IntDef(value = {\n            TYPE_INTERNAL,\n            TYPE_EXTERNAL,\n            TYPE_UNKNOWN,\n    })\n    @Retention(RetentionPolicy.SOURCE)\n    public @interface Type {\n    }\n\n    @IntDef(value = {\n            TYPE_CUSTOM,\n            TYPE_ANDROID_DATA,\n            TYPE_ANDROID_MEDIA,\n            TYPE_ANDROID_OBB,\n            TYPE_CREDENTIAL_PROTECTED,\n            TYPE_DEVICE_PROTECTED,\n    })\n    @Retention(RetentionPolicy.SOURCE)\n    public @interface SubType {\n    }\n\n    public static final int TYPE_CUSTOM = 0;\n    public static final int TYPE_ANDROID_DATA = 1;\n    public static final int TYPE_ANDROID_MEDIA = 2;\n    public static final int TYPE_ANDROID_OBB = 3;\n    public static final int TYPE_CREDENTIAL_PROTECTED = 4;\n    public static final int TYPE_DEVICE_PROTECTED = 5;\n\n    public static final int TYPE_INTERNAL = 1;\n    public static final int TYPE_EXTERNAL = 2;\n    public static final int TYPE_UNKNOWN = 3;\n\n    @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)\n    public final String rawPath;\n    @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)\n    public final Path path;\n    public final boolean isMounted;\n    @Type\n    public final int type;\n    @SubType\n    public final int subtype;\n\n    private BackupDataDirectoryInfo(String path, boolean isMounted, @Type int type, @SubType int subtype) {\n        this.rawPath = path;\n        this.path = Paths.get(path);\n        this.isMounted = isMounted;\n        this.type = type;\n        this.subtype = subtype;\n    }\n\n    public Path getDirectory() {\n        return path;\n    }\n\n    public boolean isExternal() {\n        return type == TYPE_EXTERNAL;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/backup/BackupException.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.backup;\n\nimport androidx.annotation.NonNull;\n\npublic class BackupException extends Throwable {\n    @NonNull\n    private final String mDetailMessage;\n\n    public BackupException(@NonNull String message) {\n        super(message);\n        mDetailMessage = message;\n    }\n\n    public BackupException(@NonNull String message, @NonNull Throwable cause) {\n        super(message, cause);\n        mDetailMessage = message;\n    }\n\n    @NonNull\n    @Override\n    public String getMessage() {\n        return mDetailMessage;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/backup/BackupFlags.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.backup;\n\nimport static io.github.muntashirakon.AppManager.utils.UIUtils.getSmallerText;\n\nimport android.content.Context;\nimport android.text.SpannableStringBuilder;\n\nimport androidx.annotation.IntDef;\nimport androidx.annotation.NonNull;\nimport androidx.core.util.Pair;\n\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.util.ArrayList;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Objects;\n\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.compat.ManifestCompat;\nimport io.github.muntashirakon.AppManager.self.SelfPermissions;\nimport io.github.muntashirakon.AppManager.settings.Prefs;\nimport io.github.muntashirakon.AppManager.users.Users;\nimport io.github.muntashirakon.AppManager.utils.ArrayUtils;\n\npublic final class BackupFlags {\n    @IntDef(flag = true, value = {\n            BACKUP_NOTHING,\n            BACKUP_CUSTOM_USERS,\n            BACKUP_SOURCE,\n            BACKUP_APK_FILES,\n            BACKUP_INT_DATA,\n            BACKUP_EXT_DATA,\n            BACKUP_ADB_DATA,\n            BACKUP_EXT_OBB_MEDIA,\n            BACKUP_EXCLUDE_CACHE,\n            BACKUP_EXTRAS,\n            BACKUP_CACHE,\n            BACKUP_MULTIPLE,\n            BACKUP_RULES,\n            BACKUP_NO_SIGNATURE_CHECK,\n    })\n    @Retention(RetentionPolicy.SOURCE)\n    public @interface BackupFlag {\n    }\n\n    public static final int BACKUP_NOTHING = 0;\n    @SuppressWarnings(\"PointlessBitwiseExpression\")\n    @Deprecated\n    private static final int BACKUP_SOURCE = 1 << 0;\n    public static final int BACKUP_INT_DATA = 1 << 1;\n    public static final int BACKUP_EXT_DATA = 1 << 2;\n    @Deprecated\n    private static final int BACKUP_EXCLUDE_CACHE = 1 << 3;\n    public static final int BACKUP_RULES = 1 << 4;\n    public static final int BACKUP_NO_SIGNATURE_CHECK = 1 << 5;\n    public static final int BACKUP_APK_FILES = 1 << 6;\n    public static final int BACKUP_EXT_OBB_MEDIA = 1 << 7;\n    public static final int BACKUP_CUSTOM_USERS = 1 << 8;\n    public static final int BACKUP_MULTIPLE = 1 << 9;\n    public static final int BACKUP_EXTRAS = 1 << 10;\n    public static final int BACKUP_CACHE = 1 << 11;\n    public static final int BACKUP_ADB_DATA = 1 << 12;\n\n    private static final LinkedHashMap<Integer, Pair<Integer, Integer>> sBackupFlagsMap = new LinkedHashMap<Integer, Pair<Integer, Integer>>() {{\n        put(BACKUP_APK_FILES, new Pair<>(R.string.backup_apk_files, R.string.backup_apk_files_description));\n        put(BACKUP_INT_DATA, new Pair<>(R.string.internal_data, R.string.backup_internal_data_description));\n        put(BACKUP_EXT_DATA, new Pair<>(R.string.external_data, R.string.backup_external_data_description));\n        put(BACKUP_ADB_DATA, new Pair<>(R.string.adb_data, R.string.adb_data_description));\n        put(BACKUP_EXT_OBB_MEDIA, new Pair<>(R.string.backup_obb_media, R.string.backup_obb_media_description));\n        put(BACKUP_CACHE, new Pair<>(R.string.backup_cache, R.string.backup_cache_description));\n        put(BACKUP_EXTRAS, new Pair<>(R.string.backup_extras, R.string.backup_extras_description));\n        put(BACKUP_RULES, new Pair<>(R.string.rules, R.string.backup_rules_description));\n        put(BACKUP_MULTIPLE, new Pair<>(R.string.backup_multiple, R.string.backup_multiple_description));\n        put(BACKUP_CUSTOM_USERS, new Pair<>(R.string.backup_custom_users, R.string.backup_custom_users_description));\n        put(BACKUP_NO_SIGNATURE_CHECK, new Pair<>(R.string.skip_signature_checks, R.string.backup_skip_signature_checks_description));\n    }};\n\n    @BackupFlag\n    public static int getSupportedBackupFlags() {\n        List<Integer> backupFlags = getSupportedBackupFlagsAsArray();\n        int flags = 0;\n        for (int flag : backupFlags) {\n            flags |= flag;\n        }\n        return flags;\n    }\n\n    @NonNull\n    public static List<Integer> getSupportedBackupFlagsAsArray() {\n        List<Integer> backupFlags = new ArrayList<>();\n        backupFlags.add(BACKUP_APK_FILES);\n        if (SelfPermissions.canWriteToDataData()) {\n            backupFlags.add(BACKUP_INT_DATA);\n        }\n        backupFlags.add(BACKUP_EXT_DATA);\n        if (SelfPermissions.checkSelfOrRemotePermission(ManifestCompat.permission.BACKUP)) {\n            backupFlags.add(BACKUP_ADB_DATA);\n        }\n        backupFlags.add(BACKUP_EXT_OBB_MEDIA);\n        backupFlags.add(BACKUP_CACHE);\n        backupFlags.add(BACKUP_EXTRAS);\n        backupFlags.add(BACKUP_RULES);\n        backupFlags.add(BACKUP_MULTIPLE);\n        if (Users.getUsersIds().length > 1) {\n            // Display custom users only if multiple users present\n            backupFlags.add(BACKUP_CUSTOM_USERS);\n        }\n        backupFlags.add(BACKUP_NO_SIGNATURE_CHECK);\n        return backupFlags;\n    }\n\n    @NonNull\n    public static List<Integer> getBackupFlagsAsArray(@BackupFlag int flags) {\n        flags = migrate(flags);\n        List<Integer> backupFlags = new ArrayList<>();\n        if ((flags & BACKUP_APK_FILES) != 0) {\n            backupFlags.add(BACKUP_APK_FILES);\n        }\n        if ((flags & BACKUP_INT_DATA) != 0) {\n            backupFlags.add(BACKUP_INT_DATA);\n        }\n        if ((flags & BACKUP_EXT_DATA) != 0) {\n            backupFlags.add(BACKUP_EXT_DATA);\n        }\n        if ((flags & BACKUP_ADB_DATA) != 0) {\n            backupFlags.add(BACKUP_ADB_DATA);\n        }\n        if ((flags & BACKUP_EXT_OBB_MEDIA) != 0) {\n            backupFlags.add(BACKUP_EXT_OBB_MEDIA);\n        }\n        if ((flags & BACKUP_CACHE) != 0) {\n            backupFlags.add(BACKUP_CACHE);\n        }\n        if ((flags & BACKUP_EXTRAS) != 0) {\n            backupFlags.add(BACKUP_EXTRAS);\n        }\n        if ((flags & BACKUP_RULES) != 0) {\n            backupFlags.add(BACKUP_RULES);\n        }\n        if ((flags & BACKUP_MULTIPLE) != 0) {\n            backupFlags.add(BACKUP_MULTIPLE);\n        }\n        if ((flags & BACKUP_CUSTOM_USERS) != 0) {\n            backupFlags.add(BACKUP_CUSTOM_USERS);\n        }\n        if ((flags & BACKUP_NO_SIGNATURE_CHECK) != 0) {\n            backupFlags.add(BACKUP_NO_SIGNATURE_CHECK);\n        }\n        return backupFlags;\n    }\n\n    @NonNull\n    public static CharSequence[] getFormattedFlagNames(@NonNull Context context, List<Integer> backupFlags) {\n        // Reset backup flags\n        CharSequence[] flagNames = new CharSequence[backupFlags.size()];\n        for (int i = 0; i < flagNames.length; ++i) {\n            Pair<Integer, Integer> flagNamePair = Objects.requireNonNull(sBackupFlagsMap.get(backupFlags.get(i)));\n            flagNames[i] = new SpannableStringBuilder()\n                    .append(context.getText(flagNamePair.first))\n                    .append(\"\\n\")\n                    .append(getSmallerText(context.getText(flagNamePair.second)));\n        }\n        return flagNames;\n    }\n\n    @BackupFlag\n    private int mFlags;\n\n    @NonNull\n    public static BackupFlags fromPref() {\n        return new BackupFlags(getSanitizedFlags(Prefs.BackupRestore.getBackupFlags()));\n    }\n\n    public BackupFlags(@BackupFlag int flags) {\n        mFlags = flags;\n    }\n\n    @BackupFlag\n    public int getFlags() {\n        return mFlags;\n    }\n\n    public void addFlag(@BackupFlag int flag) {\n        mFlags |= flag;\n    }\n\n    public void removeFlag(@BackupFlag int flag) {\n        mFlags &= ~flag;\n    }\n\n    public void setFlags(int flags) {\n        mFlags = flags;\n    }\n\n    @NonNull\n    public int[] flagsToCheckedIndexes(@NonNull List<Integer> enabledFlags) {\n        List<Integer> indexes = new ArrayList<>();\n        for (int i = 0; i < enabledFlags.size(); ++i) {\n            int flag = enabledFlags.get(i);\n            if ((mFlags & flag) != 0) {\n                indexes.add(i);\n            }\n        }\n        return ArrayUtils.convertToIntArray(indexes);\n    }\n\n    public boolean isEmpty() {\n        return mFlags == 0;\n    }\n\n    public boolean backupApkFiles() {\n        return (mFlags & BACKUP_APK_FILES) != 0;\n    }\n\n    public boolean backupInternalData() {\n        return (mFlags & BACKUP_INT_DATA) != 0;\n    }\n\n    public boolean backupExternalData() {\n        return (mFlags & BACKUP_EXT_DATA) != 0;\n    }\n\n    public boolean backupAdbData() {\n        return (mFlags & BACKUP_ADB_DATA) != 0;\n    }\n\n    public boolean backupMediaObb() {\n        return (mFlags & BACKUP_EXT_OBB_MEDIA) != 0;\n    }\n\n    public boolean backupData() {\n        return backupInternalData() || backupExternalData() || backupAdbData() || backupMediaObb();\n    }\n\n    public boolean backupRules() {\n        return (mFlags & BACKUP_RULES) != 0;\n    }\n\n    public boolean backupExtras() {\n        return (mFlags & BACKUP_EXTRAS) != 0;\n    }\n\n    public boolean backupCache() {\n        return (mFlags & BACKUP_CACHE) != 0;\n    }\n\n    @SuppressWarnings(\"BooleanMethodIsAlwaysInverted\")\n    public boolean skipSignatureCheck() {\n        return (mFlags & BACKUP_NO_SIGNATURE_CHECK) != 0;\n    }\n\n    public boolean backupMultiple() {\n        return (mFlags & BACKUP_MULTIPLE) != 0;\n    }\n\n    public boolean backupCustomUsers() {\n        return (mFlags & BACKUP_CUSTOM_USERS) != 0;\n    }\n\n    @NonNull\n    public CharSequence toLocalisedString(Context context) {\n        StringBuilder sb = new StringBuilder();\n        boolean append = false;\n        if (backupApkFiles()) {\n            sb.append(\"APK\");\n            append = true;\n        }\n        if (backupInternalData()) {\n            sb.append(append ? \"+\" : \"\").append(\"Int\");\n            append = true;\n        }\n        if (backupExternalData()) {\n            sb.append(append ? \"+\" : \"\").append(\"Ext\");\n            append = true;\n        }\n        if (backupAdbData()) {\n            sb.append(append ? \"+\" : \"\").append(\"ADB\");\n            append = true;\n        }\n        if (backupMediaObb()) {\n            sb.append(append ? \"+\" : \"\").append(\"OBB\");\n            append = true;\n        }\n        if (backupRules()) {\n            sb.append(append ? \"+\" : \"\").append(\"Rules\");\n            append = true;\n        }\n        if (backupExtras()) {\n            sb.append(append ? \"+\" : \"\").append(\"Extras\");\n            append = true;\n        }\n        if (backupCache()) {\n            sb.append(append ? \"+\" : \"\").append(\"Caches\");\n        }\n        return sb;\n    }\n\n    /**\n     * Remove unsupported flags from the given list of flags\n     */\n    private static int getSanitizedFlags(int flags) {\n        if (!SelfPermissions.canWriteToDataData()) {\n            flags &= ~BACKUP_INT_DATA;\n        }\n        if (Users.getUsersIds().length == 1) {\n            flags &= ~BACKUP_CUSTOM_USERS;\n        }\n        return migrate(flags);\n    }\n\n    private static int migrate(int flags) {\n        if ((flags & BACKUP_SOURCE) != 0) {\n            // BACKUP_SOURCE is replaced with BACKUP_APK_FILES\n            flags &= ~BACKUP_SOURCE;\n            flags |= BACKUP_APK_FILES;\n        }\n        if ((flags & BACKUP_EXCLUDE_CACHE) != 0) {\n            // BACKUP_EXCLUDE_CACHE is inversely replaced with BACKUP_CACHE\n            flags &= ~BACKUP_EXCLUDE_CACHE;\n            flags &= ~BACKUP_CACHE;\n        }\n        return flags;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/backup/BackupItems.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.backup;\n\nimport static io.github.muntashirakon.AppManager.backup.BackupManager.KEYSTORE_PREFIX;\n\nimport android.annotation.UserIdInt;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport java.io.BufferedReader;\nimport java.io.BufferedWriter;\nimport java.io.Closeable;\nimport java.io.FileNotFoundException;\nimport java.io.IOException;\nimport java.io.PrintWriter;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.UUID;\nimport java.util.stream.Collectors;\n\nimport io.github.muntashirakon.AppManager.backup.struct.BackupMetadataV5;\nimport io.github.muntashirakon.AppManager.crypto.Crypto;\nimport io.github.muntashirakon.AppManager.crypto.DummyCrypto;\nimport io.github.muntashirakon.AppManager.db.entity.Backup;\nimport io.github.muntashirakon.AppManager.logcat.helper.SaveLogHelper;\nimport io.github.muntashirakon.AppManager.logs.Log;\nimport io.github.muntashirakon.AppManager.settings.Prefs;\nimport io.github.muntashirakon.io.Path;\nimport io.github.muntashirakon.io.PathReader;\nimport io.github.muntashirakon.io.PathWriter;\nimport io.github.muntashirakon.io.Paths;\n\npublic class BackupItems {\n    public static final String BACKUP_DIRECTORY = \"backups\";\n    private static final String APK_SAVING_DIRECTORY = \"apks\";\n\n    private static final String ICON_FILE = \"icon.png\";\n    private static final String RULES_TSV = \"rules.am.tsv\";\n    private static final String MISC_TSV = \"misc.am.tsv\";\n    private static final String CHECKSUMS_TXT = \"checksums.txt\";\n    private static final String FREEZE = \".freeze\";\n    private static final String NO_MEDIA = \".nomedia\";\n\n    @NonNull\n    private static Path getBaseDirectory() {\n        return Prefs.Storage.getAppManagerDirectory();\n    }\n\n    @NonNull\n    public static BackupItem findBackupItem(@NonNull String relativeDir) throws FileNotFoundException {\n        return new BackupItem(getBaseDirectory().findFile(relativeDir));\n    }\n\n    @NonNull\n    public static BackupItem findOrCreateBackupItem(@UserIdInt int userId, @Nullable String backupName, @NonNull String packageName) throws IOException {\n        Path backupPath;\n        List<BackupItem> previousBackupItems = null;\n        if (MetadataManager.getCurrentBackupMetaVersion() >= 5) {\n            List<Backup> previousBackups = BackupUtils.retrieveBackupFromDb(userId, backupName, packageName);\n            if (!previousBackups.isEmpty()) {\n                previousBackupItems = new ArrayList<>(previousBackups.size());\n                for (Backup backup : previousBackups) {\n                    previousBackupItems.add(backup.getItem());\n                }\n            }\n            String backupUuid = UUID.randomUUID().toString();\n            backupPath = getBaseDirectory()\n                    .findOrCreateDirectory(BACKUP_DIRECTORY)\n                    .findOrCreateDirectory(backupUuid);\n        } else {\n            backupPath = getBaseDirectory()\n                    .findOrCreateDirectory(packageName)\n                    .findOrCreateDirectory(BackupUtils.getV4BackupName(userId, backupName));\n        }\n        BackupItem backupItem = new BackupItem(backupPath, true);\n        backupItem.setBackupName(BackupUtils.getCompatBackupName(backupName));\n        backupItem.setPreviousBackups(previousBackupItems);\n        return backupItem;\n    }\n\n    @NonNull\n    public static BackupItem createBackupItemGracefully(@UserIdInt int userId, @Nullable String backupName, @NonNull String packageName) throws IOException {\n        Path backupPath;\n        if (MetadataManager.getCurrentBackupMetaVersion() >= 5) {\n            String backupUuid = UUID.randomUUID().toString();\n            backupPath = getBaseDirectory()\n                    .findOrCreateDirectory(BACKUP_DIRECTORY)\n                    .findOrCreateDirectory(backupUuid);\n        } else {\n            Path baseDir = getBaseDirectory().findOrCreateDirectory(packageName);\n            String backupItemName = BackupUtils.getV4BackupName(userId, backupName);\n            String newBackupName = backupItemName;\n            int i = 0;\n            while (baseDir.hasFile(newBackupName)) {\n                newBackupName = backupItemName + \"_\" + (++i);\n            }\n            backupPath = baseDir.createNewDirectory(newBackupName);\n        }\n        BackupItem backupItem = new BackupItem(backupPath, true);\n        backupItem.setBackupName(BackupUtils.getCompatBackupName(backupName));\n        return backupItem;\n    }\n\n    @NonNull\n    public static List<BackupItem> findAllBackupItems() {\n        Path baseDirectory = getBaseDirectory();\n        Path[] paths = baseDirectory.listFiles(Path::isDirectory);\n        List<BackupItem> backupItems = new ArrayList<>(paths.length);\n        for (Path path : paths) {\n            if (SaveLogHelper.SAVED_LOGS_DIR.equals(path.getName())) {\n                continue;\n            }\n            if (APK_SAVING_DIRECTORY.equals(path.getName())) {\n                continue;\n            }\n            if (\".tmp\".equals(path.getName())) {\n                continue;\n            }\n            // Other backups can store multiple backups per folder\n            backupItems.addAll(Arrays.stream(path.listFiles(Path::isDirectory))\n                    .map(BackupItem::new)\n                    .collect(Collectors.toList()));\n        }\n        // We don't need to check further at this stage.\n        // It's the caller's job to check the contents if needed.\n        return backupItems;\n    }\n\n    @NonNull\n    private static synchronized Path getTemporaryUnencryptedPath(@NonNull String backupName) throws IOException {\n        Path tmpDir = Prefs.Storage.getTempPath();\n        String newFilename = backupName;\n        int i = 0;\n        while (tmpDir.hasFile(newFilename)) {\n            newFilename = backupName + \"_\" + (++i);\n        }\n        return tmpDir.findOrCreateDirectory(newFilename);\n    }\n\n    @NonNull\n    private static synchronized Path getTemporaryBackupPath(@NonNull Path originalBackupPath) throws IOException {\n        Path tmpDir = originalBackupPath.requireParent();\n        String tmpFilename = \".\" + originalBackupPath.getName();\n        String newFilename = tmpFilename;\n        int i = 0;\n        while (tmpDir.hasFile(newFilename)) {\n            newFilename = tmpFilename + \"_\" + (++i);\n        }\n        return tmpDir.findOrCreateDirectory(newFilename);\n    }\n\n    @NonNull\n    public static Path getApkBackupDirectory() throws IOException {\n        return getBaseDirectory().findOrCreateDirectory(APK_SAVING_DIRECTORY);\n    }\n\n    public static void createNoMediaIfNotExists() throws IOException {\n        Path backupDirectory = getBaseDirectory();\n        if (!backupDirectory.hasFile(NO_MEDIA)) {\n            backupDirectory.createNewFile(NO_MEDIA, null);\n        }\n    }\n\n    public static class BackupItem {\n        public static final String TAG = BackupItem.class.getSimpleName();\n\n        @NonNull\n        private final Path mBackupPath;\n        @NonNull\n        private final Path mTempBackupPath;\n        private final Object mCryptoGuard = new Object();\n        @Nullable\n        private Crypto mCrypto;\n        @CryptoUtils.Mode\n        private String mCryptoMode = CryptoUtils.MODE_NO_ENCRYPTION;\n        @Nullable\n        private String mBackupName;\n        private boolean mBackupNameSet = false;\n        private boolean mBackupMode;\n        private boolean mBackupSuccess = false;\n        private final List<Path> mTemporaryFiles = new ArrayList<>();\n        private Path mTempUnencyptedPath;\n        @Nullable\n        private List<BackupItem> mPreviousBackups;\n\n        private BackupItem(@NonNull Path backupPath, boolean backupMode) throws IOException {\n            mBackupPath = backupPath;\n            mBackupMode = backupMode;\n            if (mBackupMode) {\n                mBackupPath.mkdirs();  // Create backup path if not exists\n                mTempBackupPath = getTemporaryBackupPath(mBackupPath);\n            } else mTempBackupPath = mBackupPath;\n        }\n\n        // Read-only instance: the point is not to throw IOException\n        private BackupItem(@NonNull Path backupPath) {\n            mBackupPath = backupPath;\n            mBackupMode = false;\n            mTempBackupPath = mBackupPath;\n        }\n\n        public void setCrypto(@Nullable Crypto crypto) {\n            if (crypto == null || crypto instanceof DummyCrypto) {\n                mCrypto = null;\n                mCryptoMode = CryptoUtils.MODE_NO_ENCRYPTION;\n            } else {\n                mCrypto = crypto;\n                mCryptoMode = crypto.getModeName();\n            }\n        }\n\n        public void setBackupName(@Nullable String backupName) {\n            mBackupName = backupName;\n            mBackupNameSet = true;\n        }\n\n        @Nullable\n        public String getBackupName() {\n            if (mBackupNameSet) {\n                return mBackupName;\n            }\n            if (mBackupMode) {\n                throw new IllegalStateException(\"mBackupName must be set in backup mode.\");\n            }\n            if (isV5AndUp()) {\n                throw new IllegalStateException(\"getBackupName() is unavailable in backup v5 and up unless set manually.\");\n            }\n            // For v4 or earlier backups, fallback to filename\n            return BackupUtils.getRealBackupName(4, mBackupPath.getName());\n        }\n\n        public void setPreviousBackups(@Nullable List<BackupItem> previousBackups) {\n            mPreviousBackups = previousBackups;\n        }\n\n        public String getRelativeDir() {\n            if (isV5AndUp()) {\n                // {AppManagerDir}/backups/{UUID}/\n                return BackupUtils.getV5RelativeDir(mBackupPath.getName());\n            } else {\n                // {AppManagerDir}/{packagename}/{userid}[_{backup_name}]\n                String userIdBackupName = mBackupPath.getName();\n                String packageName = mBackupPath.requireParent().getName();\n                return BackupUtils.getV4RelativeDir(userIdBackupName, packageName);\n            }\n        }\n\n        public boolean isBackupMode() {\n            return mBackupMode;\n        }\n\n        @NonNull\n        public Path getBackupPath() {\n            return mBackupMode ? mTempBackupPath : mBackupPath;\n        }\n\n        public Path getUnencryptedBackupPath() throws IOException {\n            if (mCrypto == null) {\n                // Use real path for unencrypted backups\n                return getBackupPath();\n            } else {\n                return requireUnencryptedBackupPath();\n            }\n        }\n\n        public Path requireUnencryptedBackupPath() throws IOException {\n            if (mTempUnencyptedPath == null) {\n                // We can only do this once for each BackupItem\n                mTempUnencyptedPath = getTemporaryUnencryptedPath(getBackupPath().getName());\n            }\n            return mTempUnencyptedPath;\n        }\n\n        @NonNull\n        public Path[] encrypt(@NonNull Path[] files) throws IOException {\n            // Encrypt the files and delete the originals\n            synchronized (mCryptoGuard) {\n                if (mCrypto == null) {\n                    // No encryption enabled\n                    return files;\n                }\n                List<Path> newFileList = new ArrayList<>();\n                // Get desired extension\n                String ext = CryptoUtils.getExtension(mCryptoMode);\n                // Create necessary files (1-1 correspondence)\n                for (Path inputFile : files) {\n                    Path parent = getBackupPath();\n                    String outputFilename = inputFile.getName() + ext;\n                    Path outputPath = parent.createNewFile(outputFilename, null);\n                    newFileList.add(outputPath);\n                    Log.i(TAG, \"Input: %s\\nOutput: %s\", inputFile, outputPath);\n                }\n                Path[] newFiles = newFileList.toArray(new Path[0]);\n                // Perform actual encryption\n                mCrypto.encrypt(files, newFiles);\n                // Delete unencrypted files\n                for (Path inputFile : files) {\n                    if (!inputFile.delete()) {\n                        throw new IOException(\"Couldn't delete old file \" + inputFile);\n                    }\n                }\n                return newFiles;\n            }\n        }\n\n        @NonNull\n        public Path[] decrypt(@NonNull Path[] files) throws IOException {\n            // Decrypt the files but do NOT delete the originals\n            synchronized (mCryptoGuard) {\n                if (mCrypto == null) {\n                    // No encryption enabled\n                    return files;\n                }\n                List<Path> newFileList = new ArrayList<>();\n                // Get desired extension\n                String ext = CryptoUtils.getExtension(mCryptoMode);\n                // Create necessary files (1-1 correspondence)\n                for (Path inputFile : files) {\n                    Path parent = getUnencryptedBackupPath();\n                    String filename = inputFile.getName();\n                    String outputFilename = filename.substring(0, filename.lastIndexOf(ext));\n                    Path outputPath = parent.createNewFile(outputFilename, null);\n                    newFileList.add(outputPath);\n                    Log.i(TAG, \"Input: %s\\nOutput: %s\", inputFile, outputPath);\n                }\n                Path[] newFiles = newFileList.toArray(new Path[0]);\n                // Perform actual decryption\n                mCrypto.decrypt(files, newFiles);\n                mTemporaryFiles.addAll(newFileList);\n                return newFiles;\n            }\n        }\n\n        @NonNull\n        public Path getIconFile() throws IOException {\n            // Icon is never encrypted\n            if (mBackupMode) {\n                return getBackupPath().findOrCreateFile(ICON_FILE, null);\n            } else return getBackupPath().findFile(ICON_FILE);\n        }\n\n        public boolean isV5AndUp() {\n            return getBackupPath().hasFile(MetadataManager.INFO_V5_FILE);\n        }\n\n        public Path getInfoFile() throws IOException {\n            // info_v5.am.json is never encrypted\n            if (mBackupMode) {\n                return getBackupPath().findOrCreateFile(MetadataManager.INFO_V5_FILE, null);\n            } else return getBackupPath().findFile(MetadataManager.INFO_V5_FILE);\n        }\n\n        public Path getMetadataV5File(boolean decryptIfRequired) throws IOException {\n            if (mBackupMode) {\n                // Needs to be encrypted in backup mode\n                return getBackupPath().findOrCreateFile(MetadataManager.META_V5_FILE, null);\n            } else {\n                // Needs to be decrypted in restore mode\n                Path file = getBackupPath().findFile(MetadataManager.META_V5_FILE + CryptoUtils.getExtension(mCryptoMode));\n                return decryptIfRequired ? decrypt(new Path[]{file})[0] : file;\n            }\n        }\n\n        @NonNull\n        public Path getMetadataV2File() throws IOException {\n            // meta_v2.am.json is never encrypted\n            if (mBackupMode) {\n                return getBackupPath().findOrCreateFile(MetadataManager.META_V2_FILE, null);\n            } else return getBackupPath().findFile(MetadataManager.META_V2_FILE);\n        }\n\n        public BackupMetadataV5.Info getInfo() throws IOException {\n            return MetadataManager.readInfo(this);\n        }\n\n        public BackupMetadataV5 getMetadata() throws IOException {\n            return MetadataManager.readMetadata(this);\n        }\n\n        public BackupMetadataV5 getMetadata(BackupMetadataV5.Info backupInfo) throws IOException {\n            return MetadataManager.readMetadata(this, backupInfo);\n        }\n\n        @NonNull\n        private Path getChecksumFile() throws IOException {\n            if (mBackupMode) {\n                // Needs to be encrypted in backup mode\n                return getUnencryptedBackupPath().findOrCreateFile(CHECKSUMS_TXT, null);\n            } else {\n                // Needs to be decrypted in restore mode\n                Path file = getBackupPath().findFile(CHECKSUMS_TXT + CryptoUtils.getExtension(mCryptoMode));\n                return decrypt(new Path[]{file})[0];\n            }\n        }\n\n        @NonNull\n        public Checksum getChecksum() throws IOException {\n            return new Checksum(getChecksumFile(), mBackupMode ? \"w\" : \"r\");\n        }\n\n        @NonNull\n        public Path getMiscFile() throws IOException {\n            if (mBackupMode) {\n                // Needs to be encrypted in backup mode\n                return getUnencryptedBackupPath().findOrCreateFile(MISC_TSV, null);\n            } else {\n                // Needs to be decrypted in restore mode\n                return getBackupPath().findFile(MISC_TSV + CryptoUtils.getExtension(mCryptoMode));\n            }\n        }\n\n        @NonNull\n        public Path getRulesFile() throws IOException {\n            if (mBackupMode) {\n                // Needs to be encrypted in backup mode\n                return getUnencryptedBackupPath().findOrCreateFile(RULES_TSV, null);\n            } else {\n                // Needs to be decrypted in restore mode\n                return getBackupPath().findFile(RULES_TSV + CryptoUtils.getExtension(mCryptoMode));\n            }\n        }\n\n        @NonNull\n        public Path[] getSourceFiles() {\n            String ext = CryptoUtils.getExtension(mCryptoMode);\n            final String sourcePrefix = BackupUtils.getSourceFilePrefix(null);\n            Path[] paths = getBackupPath().listFiles((dir, name) -> name.startsWith(sourcePrefix) && name.endsWith(ext));\n            return Paths.getSortedPaths(paths);\n        }\n\n        @NonNull\n        public Path[] getDataFiles(int index) {\n            String ext = CryptoUtils.getExtension(mCryptoMode);\n            final String dataPrefix = BackupUtils.getDataFilePrefix(index, null); // extension can be anything\n            Path[] paths = getBackupPath().listFiles((dir, name) -> name.startsWith(dataPrefix) && name.endsWith(ext));\n            return Paths.getSortedPaths(paths);\n        }\n\n        @NonNull\n        public Path[] getKeyStoreFiles() {\n            String ext = CryptoUtils.getExtension(mCryptoMode);\n            Path[] paths = getBackupPath().listFiles((dir, name) -> name.startsWith(KEYSTORE_PREFIX) && name.endsWith(ext));\n            return Paths.getSortedPaths(paths);\n        }\n\n        public void freeze() throws IOException {\n            getBackupPath().createNewFile(FREEZE, null);\n        }\n\n        public void unfreeze() throws FileNotFoundException {\n            getFreezeFile().delete();\n        }\n\n        public boolean isFrozen() {\n            try {\n                return getFreezeFile().exists();\n            } catch (IOException e) {\n                return false;\n            }\n        }\n\n        public void commit() throws IOException {\n            if (mBackupMode) {\n                if (mBackupSuccess) {\n                    // Backup already done\n                    return;\n                }\n                if (!delete()) {\n                    throw new IOException(\"Could not delete \" + mBackupPath);\n                }\n                if (!mTempBackupPath.moveTo(mBackupPath)) {\n                    throw new IOException(\"Could not move \" + mTempBackupPath + \" to \" + mBackupPath);\n                }\n                if (mPreviousBackups != null) {\n                    for (BackupItem previousBackup : mPreviousBackups) {\n                        if (!previousBackup.delete()) {\n                            Log.w(TAG, \"Could not delete %s\", previousBackup.mBackupPath);\n                        }\n                    }\n                }\n                mBackupSuccess = true;\n                // Set backup mode to false to make it read-only\n                mBackupMode = false;\n            }\n        }\n\n        public void cleanup() {\n            if (mBackupMode) {\n                if (!mBackupSuccess) {\n                    // Backup wasn't successful, delete the directory\n                    mTempBackupPath.delete();\n                }\n            }\n            for (Path file : mTemporaryFiles) {\n                Log.d(TAG, \"Deleting %s\", file);\n                file.delete();\n            }\n            if (mTempUnencyptedPath != null) {\n                mTempUnencyptedPath.delete();\n            }\n            if (mCrypto != null) {\n                mCrypto.close();\n            }\n        }\n\n        public boolean exists() {\n            return mBackupPath.exists();\n        }\n\n        public boolean delete() {\n            if (mBackupPath.exists()) {\n                if (!isV5AndUp()) {\n                    // For v4 and earlier, delete parent if it's the last one.\n                    Path parent = mBackupPath.requireParent();\n                    if (parent.listFiles().length == 1) {\n                        // Also deletes children\n                        return parent.delete();\n                    }\n                }\n                return mBackupPath.delete();\n            }\n            return true;  // The backup path doesn't exist anyway\n        }\n\n        @NonNull\n        private Path getFreezeFile() throws FileNotFoundException {\n            return getBackupPath().findFile(FREEZE);\n        }\n    }\n\n    public static class Checksum implements Closeable {\n        private PrintWriter mWriter;\n        private final HashMap<String, String> mChecksums = new HashMap<>();\n        private final String mMode;\n        private final Path mFile;\n\n        @NonNull\n        public static String[] getCertChecksums(@NonNull Checksum checksum) {\n            List<String> certChecksums = new ArrayList<>();\n            synchronized (checksum.mChecksums) {\n                for (String name : checksum.mChecksums.keySet()) {\n                    if (name.startsWith(BackupManager.CERT_PREFIX)) {\n                        certChecksums.add(checksum.mChecksums.get(name));\n                    }\n                }\n            }\n            return certChecksums.toArray(new String[0]);\n        }\n\n        Checksum(@NonNull Path checksumFile, String mode) throws IOException {\n            mFile = checksumFile;\n            mMode = mode;\n            if (\"w\".equals(mode)) {\n                mWriter = new PrintWriter(new BufferedWriter(new PathWriter(checksumFile)));\n            } else if (\"r\".equals(mode)) {\n                synchronized (mChecksums) {\n                    BufferedReader reader = new BufferedReader(new PathReader(checksumFile));\n                    // Get checksums\n                    String line;\n                    String[] lineSplits;\n                    while ((line = reader.readLine()) != null) {\n                        lineSplits = line.split(\"\\t\", 2);\n                        if (lineSplits.length != 2) {\n                            throw new RuntimeException(\"Illegal lines found in the checksum file.\");\n                        }\n                        mChecksums.put(lineSplits[1], lineSplits[0]);\n                    }\n                    reader.close();\n                }\n            } else throw new IOException(\"Unknown mode: \" + mode);\n        }\n\n        public Path getFile() {\n            return mFile;\n        }\n\n        public void add(@NonNull String fileName, @NonNull String checksum) {\n            synchronized (mChecksums) {\n                if (!\"w\".equals(mMode)) {\n                    throw new IllegalStateException(\"add is inaccessible in mode \" + mMode);\n                }\n                mWriter.println(String.format(\"%s\\t%s\", checksum, fileName));\n                mChecksums.put(fileName, checksum);\n                mWriter.flush();\n            }\n        }\n\n        @Nullable\n        String get(String fileName) {\n            synchronized (mChecksums) {\n                return mChecksums.get(fileName);\n            }\n        }\n\n        @Override\n        public void close() {\n            synchronized (mChecksums) {\n                if (mWriter != null) {\n                    mWriter.close();\n                    mWriter = null;\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/backup/BackupManager.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.backup;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\n\nimport io.github.muntashirakon.AppManager.backup.struct.BackupMetadataV5;\nimport io.github.muntashirakon.AppManager.backup.struct.BackupOpOptions;\nimport io.github.muntashirakon.AppManager.backup.struct.DeleteOpOptions;\nimport io.github.muntashirakon.AppManager.backup.struct.RestoreOpOptions;\nimport io.github.muntashirakon.AppManager.db.entity.Backup;\nimport io.github.muntashirakon.AppManager.progress.ProgressHandler;\nimport io.github.muntashirakon.AppManager.utils.ContextUtils;\nimport io.github.muntashirakon.AppManager.utils.ExUtils;\nimport io.github.muntashirakon.AppManager.utils.TarUtils;\n\n/**\n * Manage backups for individual package belong to individual user.\n */\npublic class BackupManager {\n    public static final String TAG = BackupManager.class.getSimpleName();\n\n    /* language=regexp */\n    static final String[] CACHE_DIRS = new String[]{\"cache/.*\", \"code_cache/.*\", \"no_backup/.*\"};\n    /* language=regexp */\n    static final String[] LIB_DIR = new String[]{\"lib/\"};\n    public static final String SOURCE_PREFIX = \"source\";\n    public static final String DATA_PREFIX = \"data\";\n    static final String KEYSTORE_PREFIX = \"keystore\";\n    static final int KEYSTORE_PLACEHOLDER = -1000;\n    static final String DATA_BACKUP_SPECIAL_PREFIX = \"special:\";\n    static final String DATA_BACKUP_SPECIAL_ADB = DATA_BACKUP_SPECIAL_PREFIX + \"adb\";\n\n    public static final String CERT_PREFIX = \"cert_\";\n    static final String MASTER_KEY = \".masterkey\";\n\n    @NonNull\n    public static String getExt(@TarUtils.TarType String tarType) {\n        if (TarUtils.TAR_BZIP2.equals(tarType)) {\n            return \".tar.bz2\";\n        } else if (TarUtils.TAR_ZSTD.equals(tarType)) {\n            return \".tar.zst\";\n        } else return \".tar.gz\";\n    }\n\n    private boolean mRequiresRestart;\n\n    public BackupManager() {\n        ExUtils.exceptionAsIgnored(BackupItems::createNoMediaIfNotExists);\n    }\n\n    public boolean requiresRestart() {\n        return mRequiresRestart;\n    }\n\n    public void backup(@NonNull BackupOpOptions options, @Nullable ProgressHandler progressHandler)\n            throws BackupException {\n        if (options.packageName.equals(\"android\")) {\n            throw new BackupException(\"Android System (android) cannot be backed up.\");\n        }\n        if (options.flags.isEmpty()) {\n            throw new BackupException(\"Backup is requested without any flags.\");\n        }\n        BackupItems.BackupItem backupItem;\n        try {\n            if (options.override) {\n                backupItem = BackupItems.findOrCreateBackupItem(options.userId, options.backupName, options.packageName);\n            } else {\n                backupItem = BackupItems.createBackupItemGracefully(options.userId, options.backupName, options.packageName);\n            }\n        } catch (IOException e) {\n            throw new BackupException(\"Could not create BackupItem.\", e);\n        }\n        if (progressHandler != null) {\n            int max = calculateMaxProgress(options.flags);\n            progressHandler.setProgressTextInterface(ProgressHandler.PROGRESS_PERCENT);\n            progressHandler.postUpdate(max, 0f);\n        }\n        try (BackupOp backupOp = new BackupOp(options.packageName, options.flags, backupItem, options.userId)) {\n            backupOp.runBackup(progressHandler);\n            BackupUtils.putBackupToDbAndBroadcast(ContextUtils.getContext(), backupOp.getMetadata());\n        }\n    }\n\n    /**\n     * Restore a single backup for a given package belonging to the given package\n     */\n    public void restore(@NonNull RestoreOpOptions options, @Nullable ProgressHandler progressHandler)\n            throws BackupException {\n        if (options.packageName.equals(\"android\")) {\n            throw new BackupException(\"Android System (android) cannot be restored.\");\n        }\n        if (options.flags.isEmpty()) {\n            throw new BackupException(\"Restore is requested without any flags.\");\n        }\n        BackupItems.BackupItem backupItem;\n        try {\n            if (options.relativeDir != null) {\n                backupItem = BackupItems.findBackupItem(options.relativeDir);\n            } else {\n                // Use base backup\n                Backup baseBackup = BackupUtils.retrieveBaseBackupFromDb(options.userId, options.packageName);\n                if (baseBackup != null) {\n                    backupItem = baseBackup.getItem();\n                } else {\n                    throw new BackupException(\"No base backup found.\");\n                }\n            }\n        } catch (IOException e) {\n            throw new BackupException(\"Could not get backup files.\", e);\n        }\n        if (progressHandler != null) {\n            int max = calculateMaxProgress(options.flags);\n            progressHandler.setProgressTextInterface(ProgressHandler.PROGRESS_PERCENT);\n            progressHandler.postUpdate(max, 0f);\n        }\n        try (RestoreOp restoreOp = new RestoreOp(options.packageName, options.flags, backupItem, options.userId)) {\n            restoreOp.runRestore(progressHandler);\n            mRequiresRestart |= restoreOp.requiresRestart();\n        }\n    }\n\n    public void deleteBackup(@NonNull DeleteOpOptions options) throws BackupException {\n        List<BackupItems.BackupItem> backupItemList;\n        if (options.relativeDirs == null) {\n            // Delete base backup\n            Backup baseBackup = BackupUtils.retrieveBaseBackupFromDb(options.userId, options.packageName);\n            if (baseBackup != null) {\n                try {\n                    backupItemList = Collections.singletonList(baseBackup.getItem());\n                } catch (IOException e) {\n                    throw new BackupException(\"Could not get backup files.\", e);\n                }\n            } else backupItemList = Collections.emptyList();\n        } else {\n            backupItemList = new ArrayList<>(options.relativeDirs.length);\n            for (String relativeDir : options.relativeDirs) {\n                try {\n                    backupItemList.add(BackupItems.findBackupItem(relativeDir));\n                } catch (IOException e) {\n                    throw new BackupException(\"Could not get backup files.\", e);\n                }\n            }\n        }\n        for (BackupItems.BackupItem backupItem : backupItemList) {\n            BackupMetadataV5 metadata;\n            try {\n                metadata = backupItem.getMetadata();\n            } catch (IOException e) {\n                throw new BackupException(\"Could not retrieve metadata from backup.\", e);\n            }\n            if (!backupItem.isFrozen() && !backupItem.delete()) {\n                throw new BackupException(\"Could not delete the selected backups\");\n            }\n            BackupUtils.deleteBackupToDbAndBroadcast(ContextUtils.getContext(), metadata);\n        }\n    }\n\n    public void verify(@NonNull String relativeDir) throws BackupException {\n        BackupItems.BackupItem backupItem;\n        try {\n            backupItem = BackupItems.findBackupItem(relativeDir);\n        } catch (IOException e) {\n            throw new BackupException(\"Could not get backup files.\", e);\n        }\n        try (VerifyOp restoreOp = new VerifyOp(backupItem)) {\n            restoreOp.verify();\n        }\n    }\n\n    private static int calculateMaxProgress(@NonNull BackupFlags backupFlags) {\n        int tasks = 1;\n        if (backupFlags.backupApkFiles()) ++tasks;\n        if (backupFlags.backupData()) ++tasks;\n        if (backupFlags.backupExtras()) ++tasks;\n        if (backupFlags.backupRules()) ++tasks;\n        return tasks;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/backup/BackupOp.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.backup;\n\nimport static io.github.muntashirakon.AppManager.backup.BackupManager.CERT_PREFIX;\nimport static io.github.muntashirakon.AppManager.backup.BackupManager.KEYSTORE_PLACEHOLDER;\nimport static io.github.muntashirakon.AppManager.backup.BackupManager.KEYSTORE_PREFIX;\nimport static io.github.muntashirakon.AppManager.backup.BackupManager.MASTER_KEY;\nimport static io.github.muntashirakon.AppManager.backup.BackupManager.getExt;\nimport static io.github.muntashirakon.AppManager.backup.BackupUtils.TAR_TYPES;\nimport static io.github.muntashirakon.AppManager.compat.PackageManagerCompat.GET_SIGNING_CERTIFICATES;\n\nimport android.annotation.UserIdInt;\nimport android.app.INotificationManager;\nimport android.content.ComponentName;\nimport android.content.Context;\nimport android.content.pm.ApplicationInfo;\nimport android.content.pm.PackageInfo;\nimport android.content.pm.PackageManager;\nimport android.content.pm.PermissionInfo;\nimport android.graphics.Bitmap;\nimport android.os.Build;\nimport android.os.ParcelFileDescriptor;\nimport android.os.RemoteException;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.WorkerThread;\nimport androidx.core.content.pm.PackageInfoCompat;\nimport androidx.core.content.pm.PermissionInfoCompat;\n\nimport java.io.Closeable;\nimport java.io.File;\nimport java.io.FileNotFoundException;\nimport java.io.IOException;\nimport java.io.OutputStream;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.regex.Pattern;\n\nimport io.github.muntashirakon.AppManager.apk.ApkFile;\nimport io.github.muntashirakon.AppManager.apk.ApkSource;\nimport io.github.muntashirakon.AppManager.backup.struct.BackupMetadataV5;\nimport io.github.muntashirakon.AppManager.compat.AppOpsManagerCompat;\nimport io.github.muntashirakon.AppManager.compat.BackupCompat;\nimport io.github.muntashirakon.AppManager.compat.DeviceIdleManagerCompat;\nimport io.github.muntashirakon.AppManager.compat.ManifestCompat;\nimport io.github.muntashirakon.AppManager.compat.NetworkPolicyManagerCompat;\nimport io.github.muntashirakon.AppManager.compat.PackageManagerCompat;\nimport io.github.muntashirakon.AppManager.compat.PermissionCompat;\nimport io.github.muntashirakon.AppManager.crypto.CryptoException;\nimport io.github.muntashirakon.AppManager.ipc.ProxyBinder;\nimport io.github.muntashirakon.AppManager.logs.Log;\nimport io.github.muntashirakon.AppManager.magisk.MagiskDenyList;\nimport io.github.muntashirakon.AppManager.magisk.MagiskHide;\nimport io.github.muntashirakon.AppManager.magisk.MagiskProcess;\nimport io.github.muntashirakon.AppManager.misc.OsEnvironment;\nimport io.github.muntashirakon.AppManager.progress.ProgressHandler;\nimport io.github.muntashirakon.AppManager.rules.PseudoRules;\nimport io.github.muntashirakon.AppManager.rules.compontents.ComponentUtils;\nimport io.github.muntashirakon.AppManager.rules.compontents.ComponentsBlocker;\nimport io.github.muntashirakon.AppManager.self.SelfPermissions;\nimport io.github.muntashirakon.AppManager.settings.Prefs;\nimport io.github.muntashirakon.AppManager.ssaid.SsaidSettings;\nimport io.github.muntashirakon.AppManager.uri.UriManager;\nimport io.github.muntashirakon.AppManager.utils.ArrayUtils;\nimport io.github.muntashirakon.AppManager.utils.BitmapRandomizer;\nimport io.github.muntashirakon.AppManager.utils.ContextUtils;\nimport io.github.muntashirakon.AppManager.utils.DigestUtils;\nimport io.github.muntashirakon.AppManager.utils.ExUtils;\nimport io.github.muntashirakon.AppManager.utils.FileUtils;\nimport io.github.muntashirakon.AppManager.utils.FreezeUtils;\nimport io.github.muntashirakon.AppManager.utils.KeyStoreUtils;\nimport io.github.muntashirakon.AppManager.utils.PackageUtils;\nimport io.github.muntashirakon.AppManager.utils.ParcelFileDescriptorUtil;\nimport io.github.muntashirakon.AppManager.utils.TarUtils;\nimport io.github.muntashirakon.AppManager.utils.UIUtils;\nimport io.github.muntashirakon.AppManager.utils.Utils;\nimport io.github.muntashirakon.io.IoUtils;\nimport io.github.muntashirakon.io.Path;\nimport io.github.muntashirakon.io.Paths;\n\n@WorkerThread\nclass BackupOp implements Closeable {\n    static final String TAG = BackupOp.class.getSimpleName();\n\n    @NonNull\n    private final String mPackageName;\n    @NonNull\n    private final BackupItems.BackupItem mBackupItem;\n    @NonNull\n    private final BackupFlags mBackupFlags;\n    @NonNull\n    private final BackupMetadataV5 mMetadata;\n    @NonNull\n    private final PackageInfo mPackageInfo;\n    @NonNull\n    private final ApplicationInfo mApplicationInfo;\n    @UserIdInt\n    private final int mUserId;\n    @NonNull\n    private final BackupItems.Checksum mChecksum;\n    // We don't need privileged package manager here\n    @NonNull\n    private final PackageManager mPm;\n\n    BackupOp(@NonNull String packageName, @NonNull BackupFlags backupFlags,\n             @NonNull BackupItems.BackupItem backupItem, @UserIdInt int userId)\n            throws BackupException {\n        mPackageName = packageName;\n        mBackupItem = backupItem;\n        mUserId = userId;\n        mBackupFlags = backupFlags;\n        mPm = ContextUtils.getContext().getPackageManager();\n        try {\n            mPackageInfo = PackageManagerCompat.getPackageInfo(mPackageName,\n                    PackageManager.GET_META_DATA | GET_SIGNING_CERTIFICATES | PackageManager.GET_PERMISSIONS\n                            | PackageManagerCompat.MATCH_STATIC_SHARED_AND_SDK_LIBRARIES, userId);\n            Objects.requireNonNull(mPackageInfo);\n            mApplicationInfo = Objects.requireNonNull(mPackageInfo.applicationInfo);\n            // Override existing metadata\n            mMetadata = setupMetadataAndCrypto();\n        } catch (Throwable e) {\n            mBackupItem.cleanup();\n            throw new BackupException(\"Failed to setup metadata.\", e);\n        }\n        try {\n            mChecksum = mBackupItem.getChecksum();\n            String[] certChecksums = PackageUtils.getSigningCertChecksums(mMetadata.info.checksumAlgo, mPackageInfo, false);\n            for (int i = 0; i < certChecksums.length; ++i) {\n                mChecksum.add(CERT_PREFIX + i, certChecksums[i]);\n            }\n        } catch (Throwable e) {\n            mBackupItem.cleanup();\n            throw new BackupException(\"Failed to create checksum file.\", e);\n        }\n    }\n\n    @Override\n    public void close() {\n        mBackupItem.cleanup();\n    }\n\n    @NonNull\n    public BackupMetadataV5 getMetadata() {\n        return mMetadata;\n    }\n\n    void runBackup(@Nullable ProgressHandler progressHandler) throws BackupException {\n        try {\n            // Fail backup if the app has items in Android KeyStore and backup isn't enabled\n            if (mBackupFlags.backupData() && mMetadata.metadata.keyStore && !Prefs.BackupRestore.backupAppsWithKeyStore()) {\n                throw new BackupException(\"The app has keystore items and KeyStore backup isn't enabled.\");\n            }\n            incrementProgress(progressHandler);\n            // Backup icon\n            backupIcon();\n            // Backup source\n            if (mBackupFlags.backupApkFiles()) {\n                backupApkFiles();\n                incrementProgress(progressHandler);\n            }\n            // Backup data\n            if (mBackupFlags.backupData()) {\n                backupData();\n                // Backup KeyStore\n                if (mMetadata.metadata.keyStore) {\n                    backupKeyStore();\n                }\n                incrementProgress(progressHandler);\n            }\n            // Backup extras\n            if (mBackupFlags.backupExtras()) {\n                backupExtras();\n                incrementProgress(progressHandler);\n            }\n            // Export rules\n            if (mMetadata.metadata.hasRules) {\n                backupRules();\n                incrementProgress(progressHandler);\n            }\n            // Write modified metadata\n            try {\n                Map<String, String> filenameChecksumMap = MetadataManager.writeMetadata(mMetadata, mBackupItem);\n                for (Map.Entry<String, String> entry : filenameChecksumMap.entrySet()) {\n                    mChecksum.add(entry.getKey(), entry.getValue());\n                }\n            } catch (IOException e) {\n                throw new BackupException(\"Failed to write metadata.\", e);\n            }\n            mChecksum.close();\n            // Encrypt checksum\n            try {\n                mBackupItem.encrypt(new Path[]{mChecksum.getFile()});\n            } catch (IOException e) {\n                throw new BackupException(\"Failed to write checksums.txt\", e);\n            }\n            // Replace current backup\n            try {\n                mBackupItem.commit();\n            } catch (IOException e) {\n                throw new BackupException(\"Could not finalise backup.\", e);\n            }\n        } catch (BackupException e) {\n            throw e;\n        } catch (Throwable th) {\n            throw new BackupException(\"Unknown error occurred.\", th);\n        }\n    }\n\n    private static void incrementProgress(@Nullable ProgressHandler progressHandler) {\n        if (progressHandler == null) {\n            return;\n        }\n        float current = progressHandler.getLastProgress() + 1;\n        progressHandler.postUpdate(current);\n    }\n\n    public BackupMetadataV5 setupMetadataAndCrypto() throws CryptoException {\n        // We don't need to backup custom users or multiple backup flags\n        mBackupFlags.removeFlag(BackupFlags.BACKUP_CUSTOM_USERS | BackupFlags.BACKUP_MULTIPLE);\n        String backupName = mBackupItem.getBackupName();\n        long backupTime = System.currentTimeMillis();\n        String tarType = Prefs.BackupRestore.getCompressionMethod();\n        // Verify tar type\n        if (ArrayUtils.indexOf(TAR_TYPES, tarType) == -1) {\n            // Unknown tar type, set default\n            tarType = TarUtils.TAR_GZIP;\n        }\n        String crypto = CryptoUtils.getMode();\n        BackupCryptSetupHelper cryptoHelper = new BackupCryptSetupHelper(crypto, MetadataManager.getCurrentBackupMetaVersion());\n        mBackupItem.setCrypto(cryptoHelper.crypto);\n        BackupMetadataV5.Info backupInfo = new BackupMetadataV5.Info(backupTime, mBackupFlags,\n                mUserId, tarType, DigestUtils.SHA_256, crypto, cryptoHelper.getIv(),\n                cryptoHelper.getAes(), cryptoHelper.getKeyIds());\n        backupInfo.setBackupItem(mBackupItem);\n        BackupMetadataV5.Metadata metadata = new BackupMetadataV5.Metadata(backupName);\n        metadata.keyStore = KeyStoreUtils.hasKeyStore(mApplicationInfo.uid);\n        metadata.label = mApplicationInfo.loadLabel(mPm).toString();\n        metadata.packageName = mPackageName;\n        metadata.versionName = mPackageInfo.versionName;\n        metadata.versionCode = PackageInfoCompat.getLongVersionCode(mPackageInfo);\n        metadata.apkName = new File(mApplicationInfo.sourceDir).getName();\n        String[] dataDirs = null;\n        if (mBackupFlags.backupAdbData()) {\n            if (BackupCompat.isAppEligibleForBackupForUser(mUserId, mPackageName)) {\n                mBackupFlags.removeFlag(BackupFlags.BACKUP_INT_DATA);\n                mBackupFlags.removeFlag(BackupFlags.BACKUP_EXT_DATA);\n                List<String> defaultDirs = BackupUtils.getDataDirectories(mApplicationInfo, false,\n                        false, mBackupFlags.backupMediaObb());\n                dataDirs = new String[defaultDirs.size() + 1];\n                for (int i = 0; i < defaultDirs.size(); ++i) {\n                    dataDirs[i] = defaultDirs.get(i);\n                }\n                dataDirs[defaultDirs.size()] = BackupManager.DATA_BACKUP_SPECIAL_ADB;\n            } else {\n                // ADB backup cannot be used.\n                mBackupFlags.removeFlag(BackupFlags.BACKUP_ADB_DATA);\n                mBackupFlags.addFlag(BackupFlags.BACKUP_INT_DATA);\n                mBackupFlags.addFlag(BackupFlags.BACKUP_EXT_DATA);\n            }\n        }\n        if (dataDirs == null) {\n            // Non-ADB backup: default\n            dataDirs = BackupUtils.getDataDirectories(mApplicationInfo, mBackupFlags.backupInternalData(),\n                    mBackupFlags.backupExternalData(), mBackupFlags.backupMediaObb()).toArray(new String[0]);\n        }\n        metadata.dataDirs = dataDirs;\n        metadata.isSystem = (mApplicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;\n        metadata.isSplitApk = false;\n        try (ApkFile apkFile = ApkSource.getApkSource(mApplicationInfo).resolve()) {\n            if (apkFile.isSplit()) {\n                List<ApkFile.Entry> apkEntries = apkFile.getEntries();\n                int splitCount = apkEntries.size() - 1;\n                metadata.isSplitApk = splitCount > 0;\n                metadata.splitConfigs = new String[splitCount];\n                for (int i = 0; i < splitCount; ++i) {\n                    metadata.splitConfigs[i] = apkEntries.get(i + 1).getFileName();\n                }\n            }\n        } catch (ApkFile.ApkFileException e) {\n            e.printStackTrace();\n        }\n        metadata.splitConfigs = ArrayUtils.defeatNullable(metadata.splitConfigs);\n        metadata.hasRules = false;\n        if (mBackupFlags.backupRules()) {\n            try (ComponentsBlocker cb = ComponentsBlocker.getInstance(mPackageInfo.packageName, mUserId, false)) {\n                metadata.hasRules = cb.entryCount() > 0;\n            }\n        }\n        metadata.installer = PackageManagerCompat.getInstallerPackageName(mPackageInfo.packageName, mUserId);\n        return new BackupMetadataV5(backupInfo, metadata);\n    }\n\n    private void backupIcon() {\n        try {\n            Path iconFile = mBackupItem.getIconFile();\n            try (OutputStream outputStream = iconFile.openOutputStream()) {\n                Bitmap bitmap = UIUtils.getMutableBitmapFromDrawable(mApplicationInfo.loadIcon(mPm));\n                BitmapRandomizer.randomizePixel(bitmap);\n                bitmap.compress(Bitmap.CompressFormat.PNG, 100, outputStream);\n            }\n        } catch (IOException e) {\n            Log.w(TAG, \"Could not back up icon.\");\n        }\n    }\n\n    private void backupApkFiles() throws BackupException {\n        Path dataAppPath = OsEnvironment.getDataAppDirectory();\n        final String sourceBackupFilePrefix = BackupUtils.getSourceFilePrefix(getExt(mMetadata.info.tarType));\n        Path sourceDir = Paths.get(PackageUtils.getSourceDir(mApplicationInfo));\n        if (dataAppPath.equals(sourceDir)) {\n            // APK located inside /data/app directory\n            // Backup only the apk file (no split apk support for this type of apk)\n            try {\n                sourceDir = sourceDir.findFile(mMetadata.metadata.apkName);\n            } catch (FileNotFoundException e) {\n                throw new BackupException(mMetadata.metadata.apkName + \" not found at \" + sourceDir);\n            }\n        }\n        Path[] sourceFiles;\n        try {\n            sourceFiles = TarUtils.create(mMetadata.info.tarType, sourceDir, mBackupItem.getUnencryptedBackupPath(), sourceBackupFilePrefix,\n                    /* language=regexp */ new String[]{\".*\\\\.apk\"}, null, null, false).toArray(new Path[0]);\n        } catch (Throwable th) {\n            throw new BackupException(\"APK files backup is requested but no source directory has been backed up.\", th);\n        }\n        try {\n            sourceFiles = mBackupItem.encrypt(sourceFiles);\n        } catch (IOException e) {\n            throw new BackupException(\"Failed to encrypt \" + Arrays.toString(sourceFiles), e);\n        }\n        for (Path file : sourceFiles) {\n            mChecksum.add(file.getName(), DigestUtils.getHexDigest(mMetadata.info.checksumAlgo, file));\n        }\n    }\n\n    private void backupData() throws BackupException {\n        for (int i = 0; i < mMetadata.metadata.dataDirs.length; ++i) {\n            Path[] dataFiles;\n            String backupDataDir = mMetadata.metadata.dataDirs[i];\n            if (backupDataDir.equals(BackupManager.DATA_BACKUP_SPECIAL_ADB)) {\n                // ADB backup\n                dataFiles = backupAdb(i);\n            } else {\n                // Regular directory backup\n                dataFiles = backupDirectory(backupDataDir, i);\n            }\n            try {\n                dataFiles = mBackupItem.encrypt(dataFiles);\n            } catch (IOException e) {\n                throw new BackupException(\"Failed to encrypt \" + Arrays.toString(dataFiles));\n            }\n            for (Path file : dataFiles) {\n                mChecksum.add(file.getName(), DigestUtils.getHexDigest(mMetadata.info.checksumAlgo, file));\n            }\n        }\n    }\n\n    @NonNull\n    private Path[] backupDirectory(@NonNull String dir, int index) throws BackupException {\n        String filePrefix = BackupUtils.getDataFilePrefix(index, getExt(mMetadata.info.tarType));\n        try {\n            return TarUtils.create(mMetadata.info.tarType, Paths.get(dir),\n                            mBackupItem.getUnencryptedBackupPath(),\n                            filePrefix, null, null,\n                            BackupUtils.getExcludeDirs(!mBackupFlags.backupCache()), false)\n                    .toArray(new Path[0]);\n        } catch (Throwable th) {\n            throw new BackupException(\"Failed to backup data directory at \" + dir, th);\n        }\n    }\n\n    @NonNull\n    private Path[] backupAdb(int index) throws BackupException {\n        try {\n            String filePrefix = BackupUtils.getDataFilePrefix(index, \".ab\");\n            Path abFile = mBackupItem.getUnencryptedBackupPath().createNewFile(filePrefix, null);\n            try (OutputStream os = abFile.openOutputStream()) {\n                ParcelFileDescriptor fd = ParcelFileDescriptorUtil.pipeTo(os);\n                BackupCompat.adbBackup(mUserId, fd, false, false, false,\n                        false, false, false, false, true,\n                        new String[]{mPackageName});\n            }\n            return new Path[]{abFile};\n        } catch (Throwable th) {\n            throw new BackupException(\"Failed to backup ADB data.\", th);\n        }\n    }\n\n    private void backupKeyStore() throws BackupException {  // Called only when the app has an keystore item\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {\n            // keystore v2 is not supported.\n            Log.w(TAG, \"Ignoring KeyStore backups for %s\", mPackageName);\n            return;\n        }\n        Path keyStorePath = KeyStoreUtils.getKeyStorePath(mUserId);\n        try {\n            Path masterKeyFile = KeyStoreUtils.getMasterKey(mUserId);\n            // Master key exists, so take its checksum to verify it during the restore\n            mChecksum.add(MASTER_KEY, DigestUtils.getHexDigest(mMetadata.info.checksumAlgo,\n                    masterKeyFile.getContentAsString().getBytes()));\n        } catch (FileNotFoundException ignore) {\n        }\n        // Store the KeyStore files\n        Path cachePath = Paths.get(FileUtils.getCachePath());\n        List<String> cachedKeyStoreFileNames = new ArrayList<>();\n        List<String> keyStoreFilters = new ArrayList<>();\n        for (String keyStoreFileName : KeyStoreUtils.getKeyStoreFiles(mApplicationInfo.uid, mUserId)) {\n            try {\n                String newFileName = Utils.replaceOnce(keyStoreFileName, String.valueOf(mApplicationInfo.uid),\n                        String.valueOf(KEYSTORE_PLACEHOLDER));\n                IoUtils.copy(keyStorePath.findFile(keyStoreFileName), cachePath.findOrCreateFile(newFileName, null));\n                cachedKeyStoreFileNames.add(newFileName);\n                keyStoreFilters.add(Pattern.quote(newFileName));\n            } catch (Throwable e) {\n                throw new BackupException(\"Could not cache \" + keyStoreFileName, e);\n            }\n        }\n        if (cachedKeyStoreFileNames.isEmpty()) {\n            throw new BackupException(\"There were some KeyStore items but they couldn't be cached before taking a backup.\");\n        }\n        String keyStorePrefix = KEYSTORE_PREFIX + getExt(mMetadata.info.tarType);\n        Path[] backedUpKeyStoreFiles;\n        try {\n            backedUpKeyStoreFiles = TarUtils.create(mMetadata.info.tarType, cachePath, mBackupItem.getUnencryptedBackupPath(), keyStorePrefix,\n                            keyStoreFilters.toArray(new String[0]), null, null, false)\n                    .toArray(new Path[0]);\n        } catch (Throwable th) {\n            throw new BackupException(\"Could not backup KeyStore item.\", th);\n        }\n        // Remove cache\n        for (String name : cachedKeyStoreFileNames) {\n            try {\n                cachePath.findFile(name).delete();\n            } catch (FileNotFoundException ignore) {\n            }\n        }\n        try {\n            backedUpKeyStoreFiles = mBackupItem.encrypt(backedUpKeyStoreFiles);\n        } catch (IOException e) {\n            throw new BackupException(\"Failed to encrypt \" + Arrays.toString(backedUpKeyStoreFiles), e);\n        }\n        for (Path file : backedUpKeyStoreFiles) {\n            mChecksum.add(file.getName(), DigestUtils.getHexDigest(mMetadata.info.checksumAlgo, file));\n        }\n    }\n\n    private void backupExtras() throws BackupException {\n        PseudoRules rules = new PseudoRules(mPackageName, mUserId);\n        Path miscFile;\n        try {\n            miscFile = mBackupItem.getMiscFile();\n        } catch (IOException e) {\n            throw new BackupException(\"Couldn't get misc.am.tsv\", e);\n        }\n        // Backup permissions\n        @NonNull String[] permissions = ArrayUtils.defeatNullable(mPackageInfo.requestedPermissions);\n        int[] permissionFlags = ArrayUtils.defeatNullable(mPackageInfo.requestedPermissionsFlags);\n        List<AppOpsManagerCompat.OpEntry> opEntries = new ArrayList<>();\n        try {\n            List<AppOpsManagerCompat.PackageOps> packageOpsList = new AppOpsManagerCompat()\n                    .getOpsForPackage(mApplicationInfo.uid, mPackageName, null);\n            if (packageOpsList.size() == 1) opEntries.addAll(packageOpsList.get(0).getOps());\n        } catch (Exception ignore) {\n        }\n        PermissionInfo info;\n        int basePermissionType;\n        int protectionLevels;\n        for (int i = 0; i < permissions.length; ++i) {\n            try {\n                info = mPm.getPermissionInfo(permissions[i], 0);\n                basePermissionType = PermissionInfoCompat.getProtection(info);\n                protectionLevels = PermissionInfoCompat.getProtectionFlags(info);\n                if (basePermissionType != PermissionInfo.PROTECTION_DANGEROUS\n                        && (protectionLevels & PermissionInfo.PROTECTION_FLAG_DEVELOPMENT) == 0) {\n                    // Don't include permissions that are neither dangerous nor development\n                    continue;\n                }\n                boolean isGranted = (permissionFlags[i] & PackageInfo.REQUESTED_PERMISSION_GRANTED) != 0;\n                int permFlags;\n                if (SelfPermissions.checkGetGrantRevokeRuntimePermissions()) {\n                    permFlags = PermissionCompat.getPermissionFlags(info.name, mPackageName, mUserId);\n                } else permFlags = PermissionCompat.FLAG_PERMISSION_NONE;\n                rules.setPermission(permissions[i], isGranted, permFlags);\n            } catch (PackageManager.NameNotFoundException ignore) {\n            }\n        }\n        // Backup app ops\n        for (AppOpsManagerCompat.OpEntry entry : opEntries) {\n            rules.setAppOp(entry.getOp(), entry.getMode());\n        }\n        // Backup MagiskHide data\n        Collection<MagiskProcess> magiskHiddenProcesses = MagiskHide.getProcesses(mPackageInfo);\n        for (MagiskProcess magiskProcess : magiskHiddenProcesses) {\n            if (magiskProcess.isEnabled()) {\n                rules.setMagiskHide(magiskProcess);\n            }\n        }\n        // Backup Magisk DenyList data\n        Collection<MagiskProcess> magiskDeniedProcesses = MagiskDenyList.getProcesses(mPackageInfo);\n        for (MagiskProcess magiskProcess : magiskDeniedProcesses) {\n            if (magiskProcess.isEnabled()) {\n                rules.setMagiskDenyList(magiskProcess);\n            }\n        }\n        // Backup allowed notification listeners aka BIND_NOTIFICATION_LISTENER_SERVICE\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1 && SelfPermissions.checkNotificationListenerAccess()) {\n            try {\n                INotificationManager notificationManager = INotificationManager.Stub.asInterface(ProxyBinder.getService(Context.NOTIFICATION_SERVICE));\n                List<ComponentName> notificationComponents = notificationManager.getEnabledNotificationListeners(mUserId);\n                List<String> componentsForThisPkg = new ArrayList<>();\n                for (ComponentName componentName : notificationComponents) {\n                    if (mPackageName.equals(componentName.getPackageName())) {\n                        componentsForThisPkg.add(componentName.getClassName());\n                    }\n                }\n                for (String component : componentsForThisPkg) {\n                    rules.setNotificationListener(component, true);\n                }\n            } catch (RemoteException e) {\n                e.printStackTrace();\n            }\n        }\n        // Backup battery optimization\n        boolean batteryOptimized = DeviceIdleManagerCompat.isBatteryOptimizedApp(mPackageName);\n        if (!batteryOptimized) {\n            rules.setBatteryOptimization(false);\n        }\n        // Backup net policy\n        if (SelfPermissions.checkSelfOrRemotePermission(ManifestCompat.permission.MANAGE_NETWORK_POLICY)) {\n            int policies = ExUtils.requireNonNullElse(() -> NetworkPolicyManagerCompat.getUidPolicy(mApplicationInfo.uid), 0);\n            if (policies > 0) {\n                // Store only if there is a policy\n                rules.setNetPolicy(policies);\n            }\n        }\n        // Backup URI grants\n        List<UriManager.UriGrant> uriGrants = new UriManager().getGrantedUris(mPackageName);\n        if (uriGrants != null) {\n            for (UriManager.UriGrant uriGrant : uriGrants) {\n                if (uriGrant.targetUserId == mUserId) {\n                    rules.setUriGrant(uriGrant);\n                }\n            }\n        }\n        // Backup SSAID\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {\n            try {\n                String ssaid = new SsaidSettings(mUserId).getSsaid(mPackageName, mApplicationInfo.uid);\n                if (ssaid != null) rules.setSsaid(ssaid);\n            } catch (IOException e) {\n                // Ignore exception\n                Log.e(TAG, e);\n            }\n        }\n        // Backup freezeType\n        Integer freezeType = FreezeUtils.loadFreezeMethod(mPackageName);\n        if (freezeType != null) {\n            rules.setFreezeType(freezeType);\n        }\n        // Commit\n        rules.commitExternal(miscFile);\n        if (!miscFile.exists()) return;\n        try {\n            miscFile = mBackupItem.encrypt(new Path[]{miscFile})[0];\n            // Store checksum\n            mChecksum.add(miscFile.getName(), DigestUtils.getHexDigest(mMetadata.info.checksumAlgo, miscFile));\n        } catch (IOException | IndexOutOfBoundsException e) {\n            throw new BackupException(\"Couldn't get misc.am.tsv for generating checksum\", e);\n        }\n    }\n\n    private void backupRules() throws BackupException {\n        try {\n            Path rulesFile = mBackupItem.getRulesFile();\n            try (OutputStream outputStream = rulesFile.openOutputStream();\n                 ComponentsBlocker cb = ComponentsBlocker.getInstance(mPackageName, mUserId)) {\n                ComponentUtils.storeRules(outputStream, cb.getAll(), true);\n            }\n            if (!rulesFile.exists()) return;\n            rulesFile = mBackupItem.encrypt(new Path[]{rulesFile})[0];\n            // Store checksum\n            mChecksum.add(rulesFile.getName(), DigestUtils.getHexDigest(mMetadata.info.checksumAlgo, rulesFile));\n        } catch (IOException | IndexOutOfBoundsException e) {\n            throw new BackupException(\"Rules backup is requested but encountered an error during fetching rules.\", e);\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/backup/BackupUtils.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.backup;\n\nimport android.annotation.SuppressLint;\nimport android.annotation.UserIdInt;\nimport android.content.Context;\nimport android.content.pm.ApplicationInfo;\nimport android.os.Build;\nimport android.os.UserHandleHidden;\nimport android.text.TextUtils;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.VisibleForTesting;\nimport androidx.annotation.WorkerThread;\n\nimport org.jetbrains.annotations.Contract;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Objects;\nimport java.util.regex.Pattern;\n\nimport io.github.muntashirakon.AppManager.backup.struct.BackupMetadataV5;\nimport io.github.muntashirakon.AppManager.db.entity.Backup;\nimport io.github.muntashirakon.AppManager.db.utils.AppDb;\nimport io.github.muntashirakon.AppManager.logs.Log;\nimport io.github.muntashirakon.AppManager.misc.OsEnvironment;\nimport io.github.muntashirakon.AppManager.users.Users;\nimport io.github.muntashirakon.AppManager.utils.ArrayUtils;\nimport io.github.muntashirakon.AppManager.utils.BroadcastUtils;\nimport io.github.muntashirakon.AppManager.utils.TarUtils;\nimport io.github.muntashirakon.AppManager.utils.Utils;\nimport io.github.muntashirakon.io.Path;\nimport io.github.muntashirakon.io.Paths;\n\npublic final class BackupUtils {\n    public static final String TAG = BackupUtils.class.getSimpleName();\n\n    public static final String[] TAR_TYPES = new String[]{TarUtils.TAR_GZIP, TarUtils.TAR_BZIP2, TarUtils.TAR_ZSTD};\n    public static final String[] TAR_TYPES_READABLE = new String[]{\"GZip\", \"BZip2\", \"Zstandard\"};\n\n    private static final Pattern UUID_PATTERN = Pattern.compile(\"[a-f\\\\d]{8}(-[a-f\\\\d]{4}){3}-[a-f\\\\d]{12}\");\n\n    public static boolean isUuid(@NonNull String name) {\n        return UUID_PATTERN.matcher(name).matches();\n    }\n\n    @Nullable\n    @Contract(\"!null -> !null\")\n    public static String getCompatBackupName(@Nullable String backupName) {\n        if (MetadataManager.getCurrentBackupMetaVersion() >= 5) {\n            return backupName;\n        }\n        return getV4SanitizedBackupName(backupName);\n    }\n\n    @NonNull\n    public static String getV4BackupName(@UserIdInt int userId, @Nullable String backupName) {\n        if (backupName == null) {\n            return String.valueOf(userId);\n        }\n        // For v4 and earlier, backup name is used as a filename. So, necessary sanitization may be\n        // required.\n        return userId + \"_\" + getV4SanitizedBackupName(backupName);\n    }\n\n    @Nullable\n    @Contract(\"!null -> !null\")\n    public static String getV4SanitizedBackupName(@Nullable String backupName) {\n        if (backupName == null) {\n            return null;\n        }\n        // [\\\\/:?\"<>|\\s]\n        return backupName.trim().replaceAll(\"[\\\\\\\\/:?\\\"<>|\\\\s]+\", \"_\");\n    }\n\n    @NonNull\n    public static String getV5RelativeDir(@NonNull String backupUuid) {\n        // backups/{backupUuid}\n        return BackupItems.BACKUP_DIRECTORY + File.separator + backupUuid;\n    }\n\n    @NonNull\n    public static String getV4RelativeDir(@NonNull String backupNameWithUser, @NonNull String packageName) {\n        // Relative directory needs to be inferred: {packageName}/{backupNameWithUser}\n        // where backupNameWithUser = {userid}[_{backup_name}]\n        return packageName + File.separator + backupNameWithUser;\n    }\n\n    @NonNull\n    public static String getV4RelativeDir(@UserIdInt int userId, @Nullable String backupName, @NonNull String packageName) {\n        // Relative directory needs to be inferred: {packageName}/{backupName}\n        // where backupName = {userid}[_{backup_name}]\n        return packageName + File.separator + getV4BackupName(userId, backupName);\n    }\n\n    @Nullable\n    public static String getRealBackupName(int backupVersion, @Nullable String backupNameWithUserId) {\n        if (backupVersion >= 5) {\n            return backupNameWithUserId;\n        } else {\n            // v4 or earlier backup: {userid}[_{backup_name}]\n            if (backupNameWithUserId == null || TextUtils.isDigitsOnly(backupNameWithUserId)) {\n                // It's only a user ID\n                return null;\n            } else {\n                int firstUnderscore = backupNameWithUserId.indexOf('_');\n                if (firstUnderscore != -1) {\n                    // Found an underscore\n                    String userHandle = backupNameWithUserId.substring(0, firstUnderscore);\n                    if (TextUtils.isDigitsOnly(userHandle)) {\n                        return backupNameWithUserId.substring(firstUnderscore + 1);\n                    }\n                }\n                throw new IllegalArgumentException(\"Invalid backup name \" + backupNameWithUserId);\n            }\n        }\n    }\n\n    public static String getReadableTarType(@TarUtils.TarType String tarType) {\n        int i = ArrayUtils.indexOf(TAR_TYPES, tarType);\n        if (i == -1) {\n            return \"GZip\";\n        }\n        return TAR_TYPES_READABLE[i];\n    }\n\n    @WorkerThread\n    @NonNull\n    public static HashMap<String, Backup> storeAllAndGetLatestBackupMetadata() {\n        AppDb appDb = new AppDb();\n        HashMap<String, Backup> backupMetadata = new HashMap<>();\n        HashMap<String, List<BackupMetadataV5>> allBackupMetadata = getAllMetadata();\n        List<Backup> backups = new ArrayList<>();\n        for (List<BackupMetadataV5> metadataList : allBackupMetadata.values()) {\n            if (metadataList.isEmpty()) continue;\n            Backup latestBackup = null;\n            Backup backup;\n            for (BackupMetadataV5 metadataV5 : metadataList) {\n                backup = Backup.fromBackupMetadataV5(metadataV5);\n                backups.add(backup);\n                if (latestBackup == null || backup.backupTime > latestBackup.backupTime) {\n                    latestBackup = backup;\n                }\n            }\n            backupMetadata.put(latestBackup.packageName, latestBackup);\n        }\n        appDb.deleteAllBackups();\n        appDb.insertBackups(backups);\n        return backupMetadata;\n    }\n\n    @WorkerThread\n    @NonNull\n    public static HashMap<String, Backup> getAllLatestBackupMetadataFromDb() {\n        HashMap<String, Backup> backupMetadata = new HashMap<>();\n        for (Backup backup : new AppDb().getAllBackups()) {\n            Backup latestBackup = backupMetadata.get(backup.packageName);\n            if (latestBackup == null || backup.backupTime > latestBackup.backupTime) {\n                backupMetadata.put(backup.packageName, backup);\n            }\n        }\n        return backupMetadata;\n    }\n\n    public static void putBackupToDbAndBroadcast(@NonNull Context context, @NonNull BackupMetadataV5 metadata) {\n        if (Utils.isRoboUnitTest()) {\n            return;\n        }\n        AppDb appDb = new AppDb();\n        appDb.insert(Backup.fromBackupMetadataV5(metadata));\n        appDb.updateApplication(context, metadata.metadata.packageName);\n        BroadcastUtils.sendDbPackageAltered(context, new String[]{metadata.metadata.packageName});\n    }\n\n    public static void deleteBackupToDbAndBroadcast(@NonNull Context context, @NonNull BackupMetadataV5 metadata) {\n        AppDb appDb = new AppDb();\n        appDb.deleteBackup(Backup.fromBackupMetadataV5(metadata));\n        appDb.updateApplication(context, metadata.metadata.packageName);\n        BroadcastUtils.sendDbPackageAltered(context, new String[]{metadata.metadata.packageName});\n    }\n\n    @WorkerThread\n    @NonNull\n    public static List<Backup> getBackupMetadataFromDbNoLockValidate(@NonNull String packageName) {\n        List<Backup> backups = new AppDb().getAllBackupsNoLock(packageName);\n        List<Backup> validatedBackups = new ArrayList<>(backups.size());\n        for (Backup backup : backups) {\n            try {\n                if (backup.getItem().exists()) {\n                    validatedBackups.add(backup);\n                }\n            } catch (IOException e) {\n                e.printStackTrace();\n            }\n        }\n        return validatedBackups;\n    }\n\n    @NonNull\n    public static List<Backup> retrieveBackupFromDb(@UserIdInt int userId,\n                                                    @Nullable String backupName,\n                                                    @NonNull String packageName) {\n        List<Backup> backups = getBackupMetadataFromDbNoLockValidate(packageName);\n        if (backupName == null) {\n            backupName = \"\";\n        }\n        backupName = getV4SanitizedBackupName(backupName);\n        List<Backup> backupList = new ArrayList<>();\n        for (Backup backup : backups) {\n            if (backup.userId != userId) {\n                continue;\n            }\n            if (!Objects.equals(backupName, getV4SanitizedBackupName(backup.backupName))) {\n                continue;\n            }\n            backupList.add(backup);\n        }\n        return backupList;\n    }\n\n    @Nullable\n    public static Backup retrieveLatestBackupFromDb(@UserIdInt int userId,\n                                                    @Nullable String backupName,\n                                                    @NonNull String packageName) {\n        List<Backup> backups = getBackupMetadataFromDbNoLockValidate(packageName);\n        if (backupName == null) {\n            backupName = \"\";\n        }\n        backupName = getV4SanitizedBackupName(backupName);\n        for (Backup backup : backups) {\n            if (backup.userId == userId && Objects.equals(backupName, getV4SanitizedBackupName(backup.backupName))) {\n                return backup;\n            }\n        }\n        return null;\n    }\n\n    @Nullable\n    public static Backup retrieveBaseBackupFromDb(@UserIdInt int userId,\n                                                  @NonNull String packageName) {\n        List<Backup> backups = getBackupMetadataFromDbNoLockValidate(packageName);\n        for (Backup backup : backups) {\n            if (backup.userId == userId && TextUtils.isEmpty(backup.backupName)) {\n                return backup;\n            }\n        }\n        return null;\n    }\n\n    @WorkerThread\n    @Nullable\n    public static Backup getLatestBackupMetadataFromDbNoLockValidate(@NonNull String packageName) {\n        List<Backup> backups = getBackupMetadataFromDbNoLockValidate(packageName);\n        Backup latestBackup = null;\n        for (Backup backup : backups) {\n            if (latestBackup == null || backup.backupTime > latestBackup.backupTime) {\n                latestBackup = backup;\n            }\n        }\n        return latestBackup;\n    }\n\n    /**\n     * Retrieves all metadata for all packages\n     */\n    @WorkerThread\n    @NonNull\n    private static HashMap<String, List<BackupMetadataV5>> getAllMetadata() {\n        HashMap<String, List<BackupMetadataV5>> backupMetadata = new HashMap<>();\n        List<BackupItems.BackupItem> backupPaths = BackupItems.findAllBackupItems();\n        for (BackupItems.BackupItem backupItem : backupPaths) {\n            try {\n                BackupMetadataV5 metadataV5 = backupItem.getMetadata();\n                BackupMetadataV5.Metadata metadata = metadataV5.metadata;\n                if (!backupMetadata.containsKey(metadata.packageName)) {\n                    backupMetadata.put(metadata.packageName, new ArrayList<>());\n                }\n                //noinspection ConstantConditions\n                backupMetadata.get(metadata.packageName).add(metadataV5);\n            } catch (IOException e) {\n                Log.w(TAG, \"Invalid backup: %s\", e, backupItem.getRelativeDir());\n            }\n        }\n        return backupMetadata;\n    }\n\n    @NonNull\n    public static String getSourceFilePrefix(@Nullable String fullExtension) {\n        if (fullExtension == null) {\n            return BackupManager.SOURCE_PREFIX;\n        }\n        return BackupManager.SOURCE_PREFIX + fullExtension;\n    }\n\n    @NonNull\n    public static String getDataFilePrefix(int index, @Nullable String fullExtension) {\n        if (fullExtension == null) {\n            return BackupManager.DATA_PREFIX + index;\n        }\n        return BackupManager.DATA_PREFIX + index + fullExtension;\n    }\n\n    @NonNull\n    static String[] getExcludeDirs(boolean includeCache, @Nullable String... others) {\n        // Lib dirs has to be ignored by default\n        List<String> excludeDirs = new ArrayList<>(Arrays.asList(BackupManager.LIB_DIR));\n        if (includeCache) {\n            excludeDirs.addAll(Arrays.asList(BackupManager.CACHE_DIRS));\n        }\n        if (others != null) {\n            excludeDirs.addAll(Arrays.asList(others));\n        }\n        return excludeDirs.toArray(new String[0]);\n    }\n\n    @SuppressLint(\"SdCardPath\")\n    @NonNull\n    static List<String> getDataDirectories(@NonNull ApplicationInfo applicationInfo, boolean loadInternal,\n                                       boolean loadExternal, boolean loadMediaObb) {\n        // Data directories *must* be readable and non-empty\n        ArrayList<String> dataDirs = new ArrayList<>();\n        if (applicationInfo.dataDir == null) {\n            throw new IllegalArgumentException(\"Data directory cannot be empty.\");\n        }\n        int userId = UserHandleHidden.getUserId(applicationInfo.uid);\n        if (loadInternal) {\n            String dataDir = applicationInfo.dataDir;\n            if (dataDir.startsWith(\"/data/data/\")) {\n                dataDir = Utils.replaceOnce(dataDir, \"/data/data/\", String.format(Locale.ROOT, \"/data/user/%d/\", userId));\n            }\n            dataDirs.add(dataDir);\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && applicationInfo.deviceProtectedDataDir != null) {\n                // /data/user_de/{userId}\n                dataDirs.add(applicationInfo.deviceProtectedDataDir);\n            }\n        }\n        // External directories could be /sdcard, /storage/sdcard, /storage/emulated/{userId}\n        OsEnvironment.UserEnvironment ue = OsEnvironment.getUserEnvironment(userId);\n        if (loadExternal) {\n            Path[] externalFiles = ue.buildExternalStorageAppDataDirs(applicationInfo.packageName);\n            for (Path externalFile : externalFiles) {\n                // Replace /storage/emulated/{!myUserId} with /data/media/{!myUserId}\n                externalFile = Paths.getAccessiblePath(externalFile);\n                if (externalFile.listFiles().length > 0) {\n                    dataDirs.add(externalFile.getFilePath());\n                }\n            }\n        }\n        if (loadMediaObb) {\n            List<Path> externalFiles = new ArrayList<>();\n            externalFiles.addAll(Arrays.asList(ue.buildExternalStorageAppMediaDirs(applicationInfo.packageName)));\n            externalFiles.addAll(Arrays.asList(ue.buildExternalStorageAppObbDirs(applicationInfo.packageName)));\n            for (Path externalFile : externalFiles) {\n                // Replace /storage/emulated/{!myUserId} with /data/media/{!myUserId}\n                externalFile = Paths.getAccessiblePath(externalFile);\n                if (externalFile.listFiles().length > 0) {\n                    dataDirs.add(externalFile.getFilePath());\n                }\n            }\n        }\n        return dataDirs;\n    }\n\n    /**\n     * Get a writable data directory from the given directory. This is useful for restoring a backup.\n     */\n    @VisibleForTesting(otherwise = VisibleForTesting.PROTECTED)\n    @SuppressLint(\"SdCardPath\")\n    static String getWritableDataDirectory(@NonNull String dataDir, @UserIdInt int oldUserId, @UserIdInt int newUserId) {\n        if (dataDir.startsWith(\"/data/data/\")) {\n            // /data/data/ -> /data/user/{newUserId}/\n            return Utils.replaceOnce(dataDir, \"/data/data/\", String.format(Locale.ROOT, \"/data/user/%d/\", newUserId));\n        }\n        String dataUserDir = String.format(Locale.ROOT, \"/data/user/%d/\", oldUserId);\n        if (dataDir.startsWith(dataUserDir)) {\n            // /data/user/{oldUserId} -> /data/user/{newUserId}/\n            return Utils.replaceOnce(dataDir, dataUserDir, String.format(Locale.ROOT, \"/data/user/%d/\", newUserId));\n        }\n        String dataUserDeDir = String.format(Locale.ROOT, \"/data/user_de/%d/\", oldUserId);\n        if (dataDir.startsWith(dataUserDeDir)) {\n            // /data/user_de/{oldUserId} -> /data/user_de/{newUserId}/\n            return Utils.replaceOnce(dataDir, dataUserDeDir, String.format(Locale.ROOT, \"/data/user_de/%d/\", newUserId));\n        }\n        if (dataDir.startsWith(\"/sdcard/\")) {\n            // /sdcard/ -> /storage/emulated/{newUserId}/ or /data/media/{newUserId}/ in a multiuser system\n            return getExternalStorage(dataDir, \"/sdcard/\", newUserId);\n        }\n        if (dataDir.startsWith(\"/storage/sdcard/\")) {\n            // /storage/sdcard/ -> /storage/emulated/{newUserId}/ or /data/media/{newUserId}/ in a multiuser system, otherwise /sdcard/\n            return getExternalStorage(dataDir, \"/storage/sdcard/\", newUserId);\n        }\n        if (dataDir.startsWith(\"/storage/sdcard0/\")) {\n            // /storage/sdcard0/ -> /storage/emulated/{newUserId}/ or /data/media/{newUserId}/ in a multiuser system, otherwise /sdcard/\n            return getExternalStorage(dataDir, \"/storage/sdcard0/\", newUserId);\n        }\n        String oldStorageEmulatedDir = String.format(Locale.ROOT, \"/storage/emulated/%d/\", oldUserId);\n        if (dataDir.startsWith(oldStorageEmulatedDir)) {\n            // /storage/emulated/{oldUserId}/ -> /storage/emulated/{newUserId}/ or /data/media/{newUserId}/ in a multiuser system, otherwise /sdcard/\n            return getExternalStorage(dataDir, oldStorageEmulatedDir, newUserId);\n        }\n        String oldDataMediaDir = String.format(Locale.ROOT, \"/data/media/%d/\", oldUserId);\n        if (dataDir.startsWith(oldDataMediaDir)) {\n            // /data/media/{oldUserId}/ -> /storage/emulated/{newUserId}/ or /data/media/{newUserId}/ in a multiuser system, otherwise /sdcard/\n            return getExternalStorage(dataDir, oldDataMediaDir, newUserId);\n        }\n        Log.i(TAG, \"getWritableDataDirectory: Unrecognized path %s, using as is.\", dataDir);\n        return dataDir;\n    }\n\n    @SuppressLint(\"SdCardPath\")\n    @NonNull\n    private static String getExternalStorage(@NonNull String dataDir, @NonNull String match, @UserIdInt int userId) {\n        if (Users.getAllUsers().size() > 1) {\n            // Multiuser system, use either /storage/emulated/{userId} or /data/media/{userId}\n            String storageEmulatedDir = String.format(Locale.ROOT, \"/storage/emulated/%d/\", userId);\n            if (userId == UserHandleHidden.myUserId() && Paths.get(storageEmulatedDir).canRead()) {\n                return Utils.replaceOnce(dataDir, match, storageEmulatedDir);\n            }\n            return Utils.replaceOnce(dataDir, match, String.format(Locale.ROOT, \"/data/media/%d/\", userId));\n        }\n        // Otherwise, use /sdcard\n        return Utils.replaceOnce(dataDir, match, \"/sdcard/\");\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/backup/CryptoUtils.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.backup;\n\n\nimport android.text.TextUtils;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.StringDef;\nimport androidx.annotation.WorkerThread;\n\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\n\nimport io.github.muntashirakon.AppManager.backup.struct.BackupMetadataV2;\nimport io.github.muntashirakon.AppManager.crypto.AESCrypto;\nimport io.github.muntashirakon.AppManager.crypto.Crypto;\nimport io.github.muntashirakon.AppManager.crypto.CryptoException;\nimport io.github.muntashirakon.AppManager.crypto.ECCCrypto;\nimport io.github.muntashirakon.AppManager.crypto.OpenPGPCrypto;\nimport io.github.muntashirakon.AppManager.crypto.RSACrypto;\nimport io.github.muntashirakon.AppManager.crypto.ks.KeyStoreManager;\nimport io.github.muntashirakon.AppManager.settings.Prefs;\n\npublic class CryptoUtils {\n    @StringDef(value = {\n            MODE_NO_ENCRYPTION,\n            MODE_AES,\n            MODE_RSA,\n            MODE_ECC,\n            MODE_OPEN_PGP,\n    })\n    @Retention(RetentionPolicy.SOURCE)\n    public @interface Mode {\n    }\n\n    public static final String MODE_NO_ENCRYPTION = \"none\";\n    public static final String MODE_AES = \"aes\";\n    public static final String MODE_RSA = \"rsa\";\n    public static final String MODE_ECC = \"ecc\";\n    public static final String MODE_OPEN_PGP = \"pgp\";\n    @Mode\n    public static String getMode() {\n        String currentMode = Prefs.Encryption.getEncryptionMode();\n        if (isAvailable(currentMode)) return currentMode;\n        // Fallback to no encryption if none of the modes are available.\n        return MODE_NO_ENCRYPTION;\n    }\n\n    public static String getExtension(@NonNull @Mode String mode) {\n        switch (mode) {\n            case MODE_OPEN_PGP:\n                return OpenPGPCrypto.GPG_EXT;\n            case MODE_AES:\n                return AESCrypto.AES_EXT;\n            case MODE_RSA:\n                return RSACrypto.RSA_EXT;\n            case MODE_ECC:\n                return ECCCrypto.ECC_EXT;\n            case MODE_NO_ENCRYPTION:\n            default:\n                return \"\";\n        }\n    }\n\n    /**\n     * Get file name with appropriate extension\n     */\n    @NonNull\n    public static String getAppropriateFilename(String filename, @NonNull @Mode String mode) {\n        return filename + getExtension(mode);\n    }\n\n    @WorkerThread\n    public static Crypto setupCrypto(@NonNull BackupMetadataV2 metadata) throws CryptoException {\n        BackupCryptSetupHelper cryptoHelper = new BackupCryptSetupHelper(metadata.crypto, metadata.version);\n        metadata.keyIds = cryptoHelper.getKeyIds();\n        metadata.aes = cryptoHelper.getAes();\n        metadata.iv = cryptoHelper.getIv();\n        return cryptoHelper.crypto;\n    }\n\n    @WorkerThread\n    public static boolean isAvailable(@NonNull @Mode String mode) {\n        switch (mode) {\n            case MODE_OPEN_PGP:\n                String keyIds = Prefs.Encryption.getOpenPgpKeyIds();\n                // FIXME(1/10/20): Check for the availability of the provider\n                return !TextUtils.isEmpty(keyIds);\n            case MODE_AES:\n                try {\n                    return KeyStoreManager.getInstance().containsKey(AESCrypto.AES_KEY_ALIAS);\n                } catch (Exception e) {\n                    return false;\n                }\n            case MODE_RSA:\n                try {\n                    return KeyStoreManager.getInstance().containsKey(RSACrypto.RSA_KEY_ALIAS);\n                } catch (Exception e) {\n                    return false;\n                }\n            case MODE_ECC:\n                try {\n                    return KeyStoreManager.getInstance().containsKey(ECCCrypto.ECC_KEY_ALIAS);\n                } catch (Exception e) {\n                    return false;\n                }\n            case MODE_NO_ENCRYPTION:\n                return true;\n            default:\n                return false;\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/backup/MetadataManager.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.backup;\n\nimport android.text.TextUtils;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.VisibleForTesting;\nimport androidx.annotation.WorkerThread;\n\nimport org.json.JSONException;\nimport org.json.JSONObject;\n\nimport java.io.IOException;\nimport java.io.OutputStream;\nimport java.util.Collections;\nimport java.util.LinkedHashMap;\nimport java.util.Map;\n\nimport io.github.muntashirakon.AppManager.backup.struct.BackupMetadataV5;\nimport io.github.muntashirakon.AppManager.crypto.CryptoException;\nimport io.github.muntashirakon.AppManager.utils.DigestUtils;\nimport io.github.muntashirakon.AppManager.utils.JSONUtils;\nimport io.github.muntashirakon.io.Path;\n\npublic final class MetadataManager {\n    public static final String TAG = MetadataManager.class.getSimpleName();\n    private static int currentBackupMetaVersion = 5;\n\n    public static final String META_V2_FILE = \"meta_v2.am.json\";\n    // New scheme\n    public static final String INFO_V5_FILE = \"info_v5.am.json\"; // unencrypted\n    public static final String META_V5_FILE = \"meta_v5.am.json\"; // encrypted\n\n    private MetadataManager() {\n    }\n\n    @VisibleForTesting\n    public static void setCurrentBackupMetaVersion(int version) {\n        currentBackupMetaVersion = version;\n    }\n\n    public static int getCurrentBackupMetaVersion() {\n        return currentBackupMetaVersion;\n    }\n\n    @NonNull\n    @WorkerThread\n    public static BackupMetadataV5.Info readInfo(@NonNull BackupItems.BackupItem backupItem) throws IOException {\n        boolean v5AndUp = backupItem.isV5AndUp();\n        Path infoFile = v5AndUp ? backupItem.getInfoFile() : backupItem.getMetadataV2File();\n        String infoString = infoFile.getContentAsString();\n        JSONObject jsonObject;\n        if (TextUtils.isEmpty(infoString)) {\n            throw new IOException(\"Empty JSON string for path \" + infoFile);\n        }\n        try {\n            jsonObject = new JSONObject(infoString);\n            BackupMetadataV5.Info info = new BackupMetadataV5.Info(jsonObject);\n            info.setBackupItem(backupItem);\n            return info;\n        } catch (JSONException e) {\n            throw new IOException(e.getMessage() + \" for path \" + infoFile, e);\n        }\n    }\n\n    @NonNull\n    @WorkerThread\n    public static BackupMetadataV5 readMetadata(@NonNull BackupItems.BackupItem backupItem) throws IOException {\n        BackupMetadataV5.Info info = readInfo(backupItem);\n        return readMetadata(backupItem, info);\n    }\n\n    @NonNull\n    @WorkerThread\n    public static BackupMetadataV5 readMetadata(@NonNull BackupItems.BackupItem backupItem,\n                                                @NonNull BackupMetadataV5.Info backupInfo)\n            throws IOException {\n        boolean v5AndUp = backupItem.isV5AndUp();\n        if (v5AndUp) {\n            // Need to setup crypto in order to decrypt meta_v5.am.json\n            setCrypto(backupItem, backupInfo);\n        }\n        Path metadataFile = v5AndUp ? backupItem.getMetadataV5File(true) : backupItem.getMetadataV2File();\n        String metadataString = metadataFile.getContentAsString();\n        JSONObject jsonObject;\n        if (TextUtils.isEmpty(metadataString)) {\n            throw new IOException(\"Empty JSON string for path \" + metadataFile);\n        }\n        try {\n            jsonObject = new JSONObject(metadataString);\n            if (!v5AndUp) {\n                // Meta is a subset of meta_v2.am.json except for backup_name\n                jsonObject.put(\"backup_name\", backupItem.getBackupName());\n            }\n            BackupMetadataV5.Metadata metadata = new BackupMetadataV5.Metadata(jsonObject);\n            return new BackupMetadataV5(backupInfo, metadata);\n        } catch (JSONException e) {\n            throw new IOException(e.getMessage() + \" for path \" + metadataFile, e);\n        }\n    }\n\n    @WorkerThread\n    @NonNull\n    public static Map<String, String> writeMetadata(@NonNull BackupMetadataV5 metadata, @NonNull BackupItems.BackupItem backupFile) throws IOException {\n        if (!backupFile.isBackupMode()) {\n            throw new IOException(\"Backup is in read-only mode.\");\n        }\n        if (metadata.info.version >= 5) {\n            // v5 and up\n            return writeMetadataV5(metadata, backupFile);\n        } else {\n            // Old style backup\n            return writeMetadataV2(metadata, backupFile);\n        }\n    }\n\n    @WorkerThread\n    @NonNull\n    private static Map<String, String> writeMetadataV2(@NonNull BackupMetadataV5 metadata, @NonNull BackupItems.BackupItem backupFile) throws IOException {\n        Path metadataFile = backupFile.getMetadataV2File();\n        try (OutputStream outputStream = metadataFile.openOutputStream()) {\n            JSONObject metadataObject = metadata.info.serializeToJson();\n            JSONUtils.putAll(metadataObject, metadata.metadata.serializeToJson());\n            // Info is a subset of meta_v2.am.json except for backup_name\n            metadataObject.remove(\"backup_name\");\n            outputStream.write(metadataObject.toString(4).getBytes());\n            return Collections.singletonMap(metadataFile.getName(), DigestUtils.getHexDigest(\n                    metadata.info.checksumAlgo, metadataFile));\n        } catch (JSONException e) {\n            throw new IOException(e.getMessage() + \" for path \" + backupFile.getBackupPath(), e);\n        }\n    }\n\n    @WorkerThread\n    @NonNull\n    private static Map<String, String> writeMetadataV5(@NonNull BackupMetadataV5 metadata, @NonNull BackupItems.BackupItem backupFile) throws IOException {\n        Map<String, String> filenameChecksumMap = new LinkedHashMap<>(2);\n        Path metadataFile = backupFile.getMetadataV5File(true);\n        try (OutputStream outputStream = metadataFile.openOutputStream()) {\n            outputStream.write(metadata.metadata.serializeToJson().toString(4).getBytes());\n        } catch (JSONException e) {\n            throw new IOException(e.getMessage() + \" for file \" + metadataFile, e);\n        }\n        // Encrypt the metadata\n        Path encryptedMetadataFile = backupFile.encrypt(new Path[]{metadataFile})[0];\n        filenameChecksumMap.put(encryptedMetadataFile.getName(), DigestUtils.getHexDigest(\n                metadata.info.checksumAlgo, encryptedMetadataFile));\n        Path infoFile = backupFile.getInfoFile();\n        try (OutputStream outputStream = infoFile.openOutputStream()) {\n            outputStream.write(metadata.info.serializeToJson().toString(4).getBytes());\n            filenameChecksumMap.put(infoFile.getName(), DigestUtils.getHexDigest(\n                    metadata.info.checksumAlgo, infoFile));\n        } catch (JSONException e) {\n            throw new IOException(e.getMessage() + \" for file \" + infoFile, e);\n        }\n        return filenameChecksumMap;\n    }\n\n    private static void setCrypto(@NonNull BackupItems.BackupItem backupItem, @NonNull BackupMetadataV5.Info backupInfo) throws IOException {\n        if (!CryptoUtils.isAvailable(backupInfo.crypto)) {\n            throw new IOException(\"Mode \" + backupInfo.crypto + \" is currently unavailable.\");\n        }\n        try {\n            backupItem.setCrypto(backupInfo.getCrypto());\n        } catch (CryptoException e) {\n            throw new IOException(\"Failed to get crypto \" + backupInfo.crypto, e);\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/backup/RestoreOp.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.backup;\n\nimport static io.github.muntashirakon.AppManager.backup.BackupManager.KEYSTORE_PLACEHOLDER;\nimport static io.github.muntashirakon.AppManager.backup.BackupManager.MASTER_KEY;\nimport static io.github.muntashirakon.AppManager.compat.PackageManagerCompat.GET_SIGNING_CERTIFICATES;\n\nimport android.app.AppOpsManager;\nimport android.app.INotificationManager;\nimport android.content.ComponentName;\nimport android.content.Context;\nimport android.content.pm.PackageInfo;\nimport android.content.pm.PackageManager;\nimport android.os.Build;\nimport android.os.ParcelFileDescriptor;\nimport android.system.ErrnoException;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.WorkerThread;\n\nimport java.io.Closeable;\nimport java.io.File;\nimport java.io.FileNotFoundException;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Objects;\nimport java.util.concurrent.atomic.AtomicReference;\n\nimport io.github.muntashirakon.AppManager.apk.ApkFile;\nimport io.github.muntashirakon.AppManager.apk.installer.InstallerOptions;\nimport io.github.muntashirakon.AppManager.apk.installer.PackageInstallerCompat;\nimport io.github.muntashirakon.AppManager.backup.struct.BackupMetadataV5;\nimport io.github.muntashirakon.AppManager.compat.AppOpsManagerCompat;\nimport io.github.muntashirakon.AppManager.compat.BackupCompat;\nimport io.github.muntashirakon.AppManager.compat.DeviceIdleManagerCompat;\nimport io.github.muntashirakon.AppManager.compat.ManifestCompat;\nimport io.github.muntashirakon.AppManager.compat.NetworkPolicyManagerCompat;\nimport io.github.muntashirakon.AppManager.compat.PackageManagerCompat;\nimport io.github.muntashirakon.AppManager.crypto.CryptoException;\nimport io.github.muntashirakon.AppManager.ipc.ProxyBinder;\nimport io.github.muntashirakon.AppManager.logs.Log;\nimport io.github.muntashirakon.AppManager.magisk.MagiskDenyList;\nimport io.github.muntashirakon.AppManager.magisk.MagiskHide;\nimport io.github.muntashirakon.AppManager.permission.PermUtils;\nimport io.github.muntashirakon.AppManager.permission.Permission;\nimport io.github.muntashirakon.AppManager.progress.ProgressHandler;\nimport io.github.muntashirakon.AppManager.rules.PseudoRules;\nimport io.github.muntashirakon.AppManager.rules.RuleType;\nimport io.github.muntashirakon.AppManager.rules.RulesImporter;\nimport io.github.muntashirakon.AppManager.rules.struct.AppOpRule;\nimport io.github.muntashirakon.AppManager.rules.struct.FreezeRule;\nimport io.github.muntashirakon.AppManager.rules.struct.MagiskDenyListRule;\nimport io.github.muntashirakon.AppManager.rules.struct.MagiskHideRule;\nimport io.github.muntashirakon.AppManager.rules.struct.NetPolicyRule;\nimport io.github.muntashirakon.AppManager.rules.struct.PermissionRule;\nimport io.github.muntashirakon.AppManager.rules.struct.RuleEntry;\nimport io.github.muntashirakon.AppManager.rules.struct.SsaidRule;\nimport io.github.muntashirakon.AppManager.rules.struct.UriGrantRule;\nimport io.github.muntashirakon.AppManager.runner.Runner;\nimport io.github.muntashirakon.AppManager.self.SelfPermissions;\nimport io.github.muntashirakon.AppManager.ssaid.SsaidSettings;\nimport io.github.muntashirakon.AppManager.uri.UriManager;\nimport io.github.muntashirakon.AppManager.utils.DigestUtils;\nimport io.github.muntashirakon.AppManager.utils.FreezeUtils;\nimport io.github.muntashirakon.AppManager.utils.KeyStoreUtils;\nimport io.github.muntashirakon.AppManager.utils.PackageUtils;\nimport io.github.muntashirakon.AppManager.utils.ParcelFileDescriptorUtil;\nimport io.github.muntashirakon.AppManager.utils.TarUtils;\nimport io.github.muntashirakon.AppManager.utils.Utils;\nimport io.github.muntashirakon.io.Path;\nimport io.github.muntashirakon.io.Paths;\nimport io.github.muntashirakon.io.UidGidPair;\n\n@WorkerThread\nclass RestoreOp implements Closeable {\n    static final String TAG = RestoreOp.class.getSimpleName();\n    private static final Object sLock = new Object();\n\n    @NonNull\n    private final String mPackageName;\n    @NonNull\n    private final BackupFlags mBackupFlags;\n    @NonNull\n    private final BackupFlags mRequestedFlags;\n    @NonNull\n    private final BackupMetadataV5.Info mBackupInfo;\n    @NonNull\n    private final BackupMetadataV5.Metadata mBackupMetadata;\n    @NonNull\n    private final BackupItems.BackupItem mBackupItem;\n    @Nullable\n    private PackageInfo mPackageInfo;\n    private int mUid;\n    @NonNull\n    private final BackupItems.Checksum mChecksum;\n    private final int mUserId;\n    private boolean mIsInstalled;\n    private boolean mRequiresRestart;\n\n    RestoreOp(@NonNull String packageName, @NonNull BackupFlags requestedFlags,\n              @NonNull BackupItems.BackupItem backupItem, int userId) throws BackupException {\n        mPackageName = packageName;\n        mRequestedFlags = requestedFlags;\n        mBackupItem = backupItem;\n        mUserId = userId;\n        try {\n            mBackupInfo = mBackupItem.getInfo();\n            mBackupFlags = mBackupInfo.flags;\n        } catch (IOException e) {\n            mBackupItem.cleanup();\n            throw new BackupException(\"Could not read backup info. Possibly due to a malformed json file.\", e);\n        }\n        // Setup crypto\n        if (!CryptoUtils.isAvailable(mBackupInfo.crypto)) {\n            mBackupItem.cleanup();\n            throw new BackupException(\"Mode \" + mBackupInfo.crypto + \" is currently unavailable.\");\n        }\n        try {\n            mBackupItem.setCrypto(mBackupInfo.getCrypto());\n        } catch (CryptoException e) {\n            mBackupItem.cleanup();\n            throw new BackupException(\"Could not get crypto \" + mBackupInfo.crypto, e);\n        }\n        try {\n            mBackupMetadata = mBackupItem.getMetadata(mBackupInfo).metadata;\n        } catch (IOException e) {\n            mBackupItem.cleanup();\n            throw new BackupException(\"Could not read backup metadata. Possibly due to a malformed json file.\", e);\n        }\n        // Get checksums\n        try {\n            mChecksum = mBackupItem.getChecksum();\n        } catch (Throwable e) {\n            mBackupItem.cleanup();\n            throw new BackupException(\"Failed to get checksums.\", e);\n        }\n        // Verify metadata\n        if (!requestedFlags.skipSignatureCheck()) {\n            try {\n                verifyMetadata();\n            } catch (BackupException e) {\n                mBackupItem.cleanup();\n                throw e;\n            }\n        }\n        // Check user handle\n        if (mBackupInfo.userId != userId) {\n            Log.w(TAG, \"Using different user handle.\");\n        }\n        // Get package info\n        mPackageInfo = null;\n        try {\n            mPackageInfo = PackageManagerCompat.getPackageInfo(packageName, GET_SIGNING_CERTIFICATES\n                    | PackageManagerCompat.MATCH_STATIC_SHARED_AND_SDK_LIBRARIES, userId);\n            mUid = Objects.requireNonNull(mPackageInfo.applicationInfo).uid;\n        } catch (Exception ignore) {\n        }\n        mIsInstalled = mPackageInfo != null;\n    }\n\n    @Override\n    public void close() {\n        Log.d(TAG, \"Close called\");\n        mChecksum.close();\n        mBackupItem.cleanup();\n    }\n\n    void runRestore(@Nullable ProgressHandler progressHandler) throws BackupException {\n        try {\n            if (mRequestedFlags.backupData() && mBackupMetadata.keyStore && !mRequestedFlags.skipSignatureCheck()) {\n                // Check checksum of master key first\n                checkMasterKey();\n            }\n            incrementProgress(progressHandler);\n            if (mRequestedFlags.backupApkFiles()) {\n                restoreApkFiles();\n                incrementProgress(progressHandler);\n            }\n            if (mRequestedFlags.backupData()) {\n                restoreData();\n                if (mBackupMetadata.keyStore) {\n                    restoreKeyStore();\n                }\n                incrementProgress(progressHandler);\n            }\n            if (mRequestedFlags.backupExtras()) {\n                restoreExtras();\n                incrementProgress(progressHandler);\n            }\n            if (mRequestedFlags.backupRules()) {\n                restoreRules();\n                incrementProgress(progressHandler);\n            }\n        } catch (BackupException e) {\n            throw e;\n        } catch (Throwable th) {\n            throw new BackupException(\"Unknown error occurred\", th);\n        }\n    }\n\n    private static void incrementProgress(@Nullable ProgressHandler progressHandler) {\n        if (progressHandler == null) {\n            return;\n        }\n        float current = progressHandler.getLastProgress() + 1;\n        progressHandler.postUpdate(current);\n    }\n\n    public boolean requiresRestart() {\n        return mRequiresRestart;\n    }\n\n    private void verifyMetadata() throws BackupException {\n        boolean isV5AndUp = mBackupItem.isV5AndUp();\n        if (isV5AndUp) {\n            Path infoFile;\n            try {\n                infoFile = mBackupItem.getInfoFile();\n            } catch (IOException e) {\n                throw new BackupException(\"Could not get metadata file.\", e);\n            }\n            String checksum = DigestUtils.getHexDigest(mBackupInfo.checksumAlgo, infoFile);\n            if (!checksum.equals(mChecksum.get(infoFile.getName()))) {\n                throw new BackupException(\"Couldn't verify metadata file.\" +\n                        \"\\nFile: \" + infoFile +\n                        \"\\nFound: \" + checksum +\n                        \"\\nRequired: \" + mChecksum.get(infoFile.getName()));\n            }\n        }\n        Path metadataFile;\n        try {\n            metadataFile = isV5AndUp ? mBackupItem.getMetadataV5File(false) : mBackupItem.getMetadataV2File();\n        } catch (IOException e) {\n            throw new BackupException(\"Could not get metadata file.\", e);\n        }\n        String checksum = DigestUtils.getHexDigest(mBackupInfo.checksumAlgo, metadataFile);\n        if (!checksum.equals(mChecksum.get(metadataFile.getName()))) {\n            throw new BackupException(\"Couldn't verify metadata file.\" +\n                    \"\\nFile: \" + metadataFile +\n                    \"\\nFound: \" + checksum +\n                    \"\\nRequired: \" + mChecksum.get(metadataFile.getName()));\n        }\n    }\n\n    private void checkMasterKey() throws BackupException {\n        if (true) {\n            // TODO: 6/2/22 MasterKey may not actually be necessary.\n            return;\n        }\n        String oldChecksum = mChecksum.get(MASTER_KEY);\n        Path masterKey;\n        try {\n            masterKey = KeyStoreUtils.getMasterKey(mUserId);\n        } catch (FileNotFoundException e) {\n            if (oldChecksum == null) return;\n            else\n                throw new BackupException(\"Master key existed when the checksum was made but now it doesn't.\");\n        }\n        if (oldChecksum == null) {\n            throw new BackupException(\"Master key exists but it didn't exist when the backup was made.\");\n        }\n        String newChecksum = DigestUtils.getHexDigest(mBackupInfo.checksumAlgo, masterKey.getContentAsString().getBytes());\n        if (!newChecksum.equals(oldChecksum)) {\n            throw new BackupException(\"Checksums for master key did not match.\");\n        }\n    }\n\n    private void restoreApkFiles() throws BackupException {\n        if (!mBackupFlags.backupApkFiles()) {\n            throw new BackupException(\"APK restore is requested but backup doesn't contain any source files.\");\n        }\n        Path[] backupSourceFiles = mBackupItem.getSourceFiles();\n        if (backupSourceFiles.length == 0) {\n            // No source backup found\n            throw new BackupException(\"Source restore is requested but there are no source files.\");\n        }\n        boolean isVerified = true;\n        if (mPackageInfo != null) {\n            // Check signature of the installed app\n            List<String> certChecksumList = Arrays.asList(PackageUtils.getSigningCertChecksums(mBackupInfo.checksumAlgo, mPackageInfo, false));\n            String[] certChecksums = BackupItems.Checksum.getCertChecksums(mChecksum);\n            for (String checksum : certChecksums) {\n                if (certChecksumList.contains(checksum)) continue;\n                isVerified = false;\n                if (!mRequestedFlags.skipSignatureCheck()) {\n                    throw new BackupException(\"Signing info verification failed.\" +\n                            \"\\nInstalled: \" + certChecksumList +\n                            \"\\nBackup: \" + Arrays.toString(certChecksums));\n                }\n            }\n        }\n        if (!mRequestedFlags.skipSignatureCheck()) {\n            String checksum;\n            for (Path file : backupSourceFiles) {\n                checksum = DigestUtils.getHexDigest(mBackupInfo.checksumAlgo, file);\n                if (!checksum.equals(mChecksum.get(file.getName()))) {\n                    throw new BackupException(\"Source file verification failed.\" +\n                            \"\\nFile: \" + file +\n                            \"\\nFound: \" + checksum +\n                            \"\\nRequired: \" + mChecksum.get(file.getName()));\n                }\n            }\n        }\n        if (!isVerified) {\n            // Signature verification failed but still here because signature check is disabled.\n            // The only way to restore is to reinstall the app\n            synchronized (sLock) {\n                PackageInstallerCompat installer = PackageInstallerCompat.getNewInstance();\n                if (installer.uninstall(mPackageName, mUserId, false)) {\n                    throw new BackupException(\"An uninstallation was necessary but couldn't perform it.\");\n                }\n            }\n        }\n        // Setup package staging directory\n        Path packageStagingDirectory = Paths.get(PackageUtils.PACKAGE_STAGING_DIRECTORY);\n        try {\n            synchronized (sLock) {\n                PackageUtils.ensurePackageStagingDirectoryPrivileged();\n            }\n        } catch (Exception ignore) {\n        }\n        try {\n            if (!packageStagingDirectory.canWrite()) {\n                packageStagingDirectory = mBackupItem.getUnencryptedBackupPath();\n            }\n        } catch (IOException e) {\n            throw new BackupException(\"Could not create package staging directory\", e);\n        }\n        synchronized (sLock) {\n            // Setup apk files, including split apk\n            final int splitCount = mBackupMetadata.splitConfigs.length;\n            String[] allApkNames = new String[splitCount + 1];\n            Path[] allApks = new Path[splitCount + 1];\n            try {\n                Path baseApk = packageStagingDirectory.createNewFile(mBackupMetadata.apkName, null);\n                allApks[0] = baseApk;\n                allApkNames[0] = mBackupMetadata.apkName;\n                for (int i = 1; i < allApkNames.length; ++i) {\n                    allApkNames[i] = mBackupMetadata.splitConfigs[i - 1];\n                    allApks[i] = packageStagingDirectory.createNewFile(allApkNames[i], null);\n                }\n            } catch (IOException e) {\n                throw new BackupException(\"Could not create staging files\", e);\n            }\n            // Decrypt sources\n            try {\n                backupSourceFiles = mBackupItem.decrypt(backupSourceFiles);\n            } catch (IOException e) {\n                throw new BackupException(\"Failed to decrypt \" + Arrays.toString(backupSourceFiles), e);\n            }\n            // Extract apk files to the package staging directory\n            try {\n                TarUtils.extract(mBackupInfo.tarType, backupSourceFiles, packageStagingDirectory, allApkNames, null, null);\n            } catch (Throwable th) {\n                throw new BackupException(\"Failed to extract the apk file(s).\", th);\n            }\n            // A normal update will do it now\n            InstallerOptions options = InstallerOptions.getDefault();\n            options.setInstallerName(mBackupMetadata.installer);\n            options.setUserId(mUserId);\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {\n                options.setInstallScenario(PackageManager.INSTALL_SCENARIO_BULK);\n            }\n            AtomicReference<String> status = new AtomicReference<>();\n            PackageInstallerCompat packageInstaller = PackageInstallerCompat.getNewInstance();\n            packageInstaller.setOnInstallListener(new PackageInstallerCompat.OnInstallListener() {\n                @Override\n                public void onStartInstall(int sessionId, String packageName) {\n                }\n\n                // MIUI-begin: MIUI 12.5+ workaround\n                @Override\n                public void onAnotherAttemptInMiui(@Nullable ApkFile apkFile) {\n                    // This works because the parent install method still remains active until a final status is\n                    // received after all the attempts are finished, which is, then, returned to the parent.\n                    packageInstaller.install(allApks, mPackageName, options);\n                }\n                // MIUI-end\n\n                // HyperOS-begin: HyperOS 2.0+ workaround\n                @Override\n                public void onSecondAttemptInHyperOsWithoutInstaller(@Nullable ApkFile apkFile) {\n                    // This works because the parent install method still remains active until a final status is\n                    // received after all the attempts are finished, which is, then, returned to the parent.\n                    options.setInstallerName(\"com.android.shell\");\n                    packageInstaller.install(allApks, mPackageName, options);\n                }\n                // HyperOS-end\n\n                @Override\n                public void onFinishedInstall(int sessionId, String packageName, int result, @Nullable String blockingPackage, @Nullable String statusMessage) {\n                    status.set(statusMessage);\n                }\n            });\n            try {\n                if (!packageInstaller.install(allApks, mPackageName, options)) {\n                    String statusMessage;\n                    if (!isVerified) {\n                        // Previously installed app was uninstalled.\n                        statusMessage = \"Couldn't perform a re-installation\";\n                    } else {\n                        statusMessage = \"Couldn't perform an installation\";\n                    }\n                    if (status.get() != null) {\n                        statusMessage += \": \" + status.get();\n                    } else statusMessage += \".\";\n                    throw new BackupException(statusMessage);\n                }\n            } finally {\n                deleteFiles(allApks);  // Clean up apk files\n            }\n            // Get package info, again\n            try {\n                mPackageInfo = PackageManagerCompat.getPackageInfo(mPackageName, GET_SIGNING_CERTIFICATES\n                        | PackageManagerCompat.MATCH_STATIC_SHARED_AND_SDK_LIBRARIES, mUserId);\n                mUid = Objects.requireNonNull(mPackageInfo.applicationInfo).uid;\n                mIsInstalled = true;\n            } catch (Exception e) {\n                throw new BackupException(\"Apparently the install wasn't complete in the previous section.\", e);\n            }\n        }\n    }\n\n    private void restoreKeyStore() throws BackupException {\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {\n            // keystore v2 is not supported.\n            Log.w(TAG, \"Ignoring KeyStore backups for %s\", mPackageName);\n            return;\n        }\n        if (mPackageInfo == null) {\n            throw new BackupException(\"KeyStore restore is requested but the app isn't installed.\");\n        }\n        Path[] keyStoreFiles = mBackupItem.getKeyStoreFiles();\n        if (keyStoreFiles.length == 0) {\n            throw new BackupException(\"KeyStore files should've existed but they didn't\");\n        }\n        if (!mRequestedFlags.skipSignatureCheck()) {\n            String checksum;\n            for (Path file : keyStoreFiles) {\n                checksum = DigestUtils.getHexDigest(mBackupInfo.checksumAlgo, file);\n                if (!checksum.equals(mChecksum.get(file.getName()))) {\n                    throw new BackupException(\"KeyStore file verification failed.\" +\n                            \"\\nFile: \" + file +\n                            \"\\nFound: \" + checksum +\n                            \"\\nRequired: \" + mChecksum.get(file.getName()));\n                }\n            }\n        }\n        // Decrypt sources\n        try {\n            keyStoreFiles = mBackupItem.decrypt(keyStoreFiles);\n        } catch (IOException e) {\n            throw new BackupException(\"Failed to decrypt \" + Arrays.toString(keyStoreFiles), e);\n        }\n        // Restore KeyStore files to the /data/misc/keystore folder\n        Path keyStorePath = KeyStoreUtils.getKeyStorePath(mUserId);\n        // Note down UID/GID\n        UidGidPair uidGidPair;\n        int mode;\n        try {\n            uidGidPair = Objects.requireNonNull(keyStorePath.getFile()).getUidGid();\n            mode = keyStorePath.getFile().getMode();\n        } catch (ErrnoException e) {\n            throw new BackupException(\"Failed to access properties of the KeyStore folder.\", e);\n        }\n        try {\n            TarUtils.extract(mBackupInfo.tarType, keyStoreFiles, keyStorePath, null, null, null);\n            // Restore folder permission\n            Paths.chown(keyStorePath, uidGidPair.uid, uidGidPair.gid);\n            //noinspection OctalInteger\n            Paths.chmod(keyStorePath, mode & 0777);\n        } catch (Throwable th) {\n            throw new BackupException(\"Failed to restore the KeyStore files.\", th);\n        }\n        // Rename files\n        List<String> keyStoreFileNames = KeyStoreUtils.getKeyStoreFiles(KEYSTORE_PLACEHOLDER, mUserId);\n        for (String keyStoreFileName : keyStoreFileNames) {\n            try {\n                String newFilename = Utils.replaceOnce(keyStoreFileName, String.valueOf(KEYSTORE_PLACEHOLDER), String.valueOf(mUid));\n                keyStorePath.findFile(keyStoreFileName).renameTo(newFilename);\n                Path targetFile = keyStorePath.findFile(newFilename);\n                // Restore file permission\n                Paths.chown(targetFile, uidGidPair.uid, uidGidPair.gid);\n                //noinspection OctalInteger\n                Paths.chmod(targetFile, 0600);\n            } catch (IOException | ErrnoException e) {\n                throw new BackupException(\"Failed to rename KeyStore files\", e);\n            }\n        }\n        Runner.runCommand(new String[]{\"restorecon\", \"-R\", keyStorePath.getFilePath()});\n    }\n\n    private void restoreData() throws BackupException {\n        // Data restore is requested: Data restore is only possible if the app is actually\n        // installed. So, check if it's installed first.\n        if (mPackageInfo == null) {\n            throw new BackupException(\"Data restore is requested but the app isn't installed.\");\n        }\n        if (!mRequestedFlags.skipSignatureCheck()) {\n            // Verify integrity of the data backups\n            String checksum;\n            for (int i = 0; i < mBackupMetadata.dataDirs.length; ++i) {\n                Path[] dataFiles = mBackupItem.getDataFiles(i);\n                if (dataFiles.length == 0) {\n                    throw new BackupException(\"Data restore is requested but there are no data files for index \" + i + \".\");\n                }\n                for (Path file : dataFiles) {\n                    checksum = DigestUtils.getHexDigest(mBackupInfo.checksumAlgo, file);\n                    if (!checksum.equals(mChecksum.get(file.getName()))) {\n                        throw new BackupException(\"Data file verification failed for index \" + i + \".\" +\n                                \"\\nFile: \" + file +\n                                \"\\nFound: \" + checksum +\n                                \"\\nRequired: \" + mChecksum.get(file.getName()));\n                    }\n                }\n            }\n        }\n        // Force-stop and clear app data\n        PackageManagerCompat.clearApplicationUserData(mPackageName, mUserId);\n        // Restore backups\n        for (int i = 0; i < mBackupMetadata.dataDirs.length; ++i) {\n            String backupDataDir = mBackupMetadata.dataDirs[i];\n            if (backupDataDir.equals(BackupManager.DATA_BACKUP_SPECIAL_ADB)) {\n                // Adb backup restore\n                restoreAdb(i);\n            } else {\n                // Regular directory restore\n                restoreDirectory(mBackupMetadata.dataDirs[i], i);\n            }\n        }\n    }\n\n    private void restoreDirectory(@NonNull String dir, int index) throws BackupException {\n        String dataSource = BackupUtils.getWritableDataDirectory(dir, mBackupInfo.userId, mUserId);\n        BackupDataDirectoryInfo dataDirectoryInfo = BackupDataDirectoryInfo.getInfo(dataSource, mUserId);\n        Path dataSourceFile = dataDirectoryInfo.getDirectory();\n\n        Path[] dataFiles = mBackupItem.getDataFiles(index);\n        if (dataFiles.length == 0) {\n            throw new BackupException(\"Data restore is requested but there are no data files for index \" + index + \".\");\n        }\n        UidGidPair uidGidPair = dataSourceFile.getUidGid();\n        if (uidGidPair == null) {\n            // Fallback to app UID\n            uidGidPair = new UidGidPair(mUid, mUid);\n        }\n        if (dataDirectoryInfo.isExternal()) {\n            // Skip if external data restore is not requested\n            switch (dataDirectoryInfo.subtype) {\n                case BackupDataDirectoryInfo.TYPE_ANDROID_DATA:\n                    // Skip restoring Android/data directory if not requested\n                    if (!mRequestedFlags.backupExternalData()) {\n                        return;\n                    }\n                    break;\n                case BackupDataDirectoryInfo.TYPE_ANDROID_OBB:\n                case BackupDataDirectoryInfo.TYPE_ANDROID_MEDIA:\n                    // Skip restoring Android/data or Android/media if media/obb restore not requested\n                    if (!mRequestedFlags.backupMediaObb()) {\n                        return;\n                    }\n                    break;\n                case BackupDataDirectoryInfo.TYPE_CREDENTIAL_PROTECTED:\n                case BackupDataDirectoryInfo.TYPE_CUSTOM:\n                case BackupDataDirectoryInfo.TYPE_DEVICE_PROTECTED:\n                    // NOP\n                    break;\n            }\n        } else {\n            // Skip if internal data restore is not requested.\n            if (!mRequestedFlags.backupInternalData()) {\n                return;\n            }\n        }\n        // Create data folder if not exists\n        if (!dataSourceFile.exists()) {\n            if (dataDirectoryInfo.isExternal() && !dataDirectoryInfo.isMounted) {\n                if (!Utils.isRoboUnitTest()) {\n                    throw new BackupException(\"External directory containing \" + dataSource + \" is not mounted.\");\n                } // else Skip checking for mounted partition for robolectric tests\n            }\n            if (!dataSourceFile.mkdirs()) {\n                throw new BackupException(\"Could not create directory \" + dataSourceFile);\n            }\n            if (!dataDirectoryInfo.isExternal()) {\n                // Restore UID, GID\n                dataSourceFile.setUidGid(uidGidPair);\n            }\n        }\n        // Decrypt data\n        try {\n            dataFiles = mBackupItem.decrypt(dataFiles);\n        } catch (IOException e) {\n            throw new BackupException(\"Failed to decrypt \" + Arrays.toString(dataFiles), e);\n        }\n        // Extract data to the data directory\n        try {\n            String publicSourceDir = new File(Objects.requireNonNull(mPackageInfo.applicationInfo).publicSourceDir).getParent();\n            TarUtils.extract(mBackupInfo.tarType, dataFiles, dataSourceFile, null, BackupUtils\n                    .getExcludeDirs(!mRequestedFlags.backupCache(), null), publicSourceDir);\n        } catch (Throwable th) {\n            throw new BackupException(\"Failed to restore data files for index \" + index + \".\", th);\n        }\n        // Restore UID and GID\n        if (!Runner.runCommand(String.format(Locale.ROOT, \"chown -R %d:%d \\\"%s\\\"\", uidGidPair.uid, uidGidPair.gid, dataSourceFile.getFilePath())).isSuccessful()) {\n            if (!Utils.isRoboUnitTest()) {\n                throw new BackupException(\"Failed to restore ownership info for index \" + index + \".\");\n            } // else Don't care about permissions\n        }\n        // Restore context\n        if (!dataDirectoryInfo.isExternal()) {\n            Runner.runCommand(new String[]{\"restorecon\", \"-R\", dataSourceFile.getFilePath()});\n        }\n    }\n\n    private void restoreAdb(int index) throws BackupException {\n        Path[] dataFiles = mBackupItem.getDataFiles(index);\n        if (dataFiles.length != 1) {\n            throw new BackupException(\"ADB restore is requested but there are no .ab files.\");\n        }\n        // Decrypt data\n        try {\n            dataFiles = mBackupItem.decrypt(dataFiles);\n        } catch (IOException e) {\n            throw new BackupException(\"Failed to decrypt \" + Arrays.toString(dataFiles), e);\n        }\n        // Restore data\n        try (InputStream is = dataFiles[0].openInputStream()) {\n            ParcelFileDescriptor fd = ParcelFileDescriptorUtil.pipeFrom(is);\n            BackupCompat.adbRestore(mUserId, fd);\n        } catch (Throwable th) {\n            throw new BackupException(\"Failed to restore ADB data\", th);\n        }\n    }\n\n    private synchronized void restoreExtras() throws BackupException {\n        if (!mIsInstalled) {\n            throw new BackupException(\"Misc restore is requested but the app isn't installed.\");\n        }\n        PseudoRules rules = new PseudoRules(mPackageName, mUserId);\n        // Backward compatibility for restoring permissions\n        loadMiscRules(rules);\n        // Apply rules\n        List<RuleEntry> entries = rules.getAll();\n        AppOpsManagerCompat appOpsManager = new AppOpsManagerCompat();\n        INotificationManager notificationManager = INotificationManager.Stub.asInterface(ProxyBinder.getService(Context.NOTIFICATION_SERVICE));\n        boolean magiskHideAvailable = MagiskHide.available();\n        boolean canModifyAppOpMode = SelfPermissions.canModifyAppOpMode();\n        boolean canChangeNetPolicy = SelfPermissions.checkSelfOrRemotePermission(ManifestCompat.permission.MANAGE_NETWORK_POLICY);\n        for (RuleEntry entry : entries) {\n            try {\n                switch (entry.type) {\n                    case APP_OP:\n                        if (canModifyAppOpMode) {\n                            appOpsManager.setMode(Integer.parseInt(entry.name), mUid, mPackageName,\n                                    ((AppOpRule) entry).getMode());\n                        }\n                        break;\n                    case NET_POLICY:\n                        if (canChangeNetPolicy) {\n                            NetworkPolicyManagerCompat.setUidPolicy(mUid,\n                                    ((NetPolicyRule) entry).getPolicies());\n                        }\n                        break;\n                    case PERMISSION: {\n                        PermissionRule permissionRule = (PermissionRule) entry;\n                        Permission permission = permissionRule.getPermission(true);\n                        permission.setAppOpAllowed(permission.getAppOp() != AppOpsManagerCompat.OP_NONE && appOpsManager\n                                .checkOperation(permission.getAppOp(), mUid, mPackageName) == AppOpsManager.MODE_ALLOWED);\n                        if (permissionRule.isGranted()) {\n                            PermUtils.grantPermission(mPackageInfo, permission, appOpsManager, true, true);\n                        } else {\n                            PermUtils.revokePermission(mPackageInfo, permission, appOpsManager, true);\n                        }\n                        break;\n                    }\n                    case BATTERY_OPT:\n                        if (SelfPermissions.checkSelfOrRemotePermission(ManifestCompat.permission.DEVICE_POWER)) {\n                            DeviceIdleManagerCompat.disableBatteryOptimization(mPackageName);\n                        }\n                        break;\n                    case MAGISK_HIDE: {\n                        MagiskHideRule magiskHideRule = (MagiskHideRule) entry;\n                        if (magiskHideAvailable) {\n                            MagiskHide.apply(magiskHideRule.getMagiskProcess(), false);\n                        } else {\n                            // Fall-back to Magisk DenyList\n                            MagiskDenyList.apply(magiskHideRule.getMagiskProcess(), false);\n                        }\n                        break;\n                    }\n                    case MAGISK_DENY_LIST: {\n                        MagiskDenyList.apply(((MagiskDenyListRule) entry).getMagiskProcess(), false);\n                        break;\n                    }\n                    case NOTIFICATION:\n                        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1\n                                && SelfPermissions.checkNotificationListenerAccess()) {\n                            notificationManager.setNotificationListenerAccessGrantedForUser(\n                                    new ComponentName(mPackageName, entry.name), mUserId, true);\n                        }\n                        break;\n                    case URI_GRANT:\n                        UriManager.UriGrant uriGrant = ((UriGrantRule) entry).getUriGrant();\n                        UriManager.UriGrant newUriGrant = new UriManager.UriGrant(\n                                uriGrant.sourceUserId, mUserId, uriGrant.userHandle,\n                                uriGrant.sourcePkg, uriGrant.targetPkg, uriGrant.uri,\n                                uriGrant.prefix, uriGrant.modeFlags, uriGrant.createdTime);\n                        UriManager uriManager = new UriManager();\n                        uriManager.grantUri(newUriGrant);\n                        uriManager.writeGrantedUriPermissions();\n                        mRequiresRestart = true;\n                        break;\n                    case SSAID:\n                        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {\n                            new SsaidSettings(mUserId).setSsaid(mPackageName, mUid,\n                                    ((SsaidRule) entry).getSsaid());\n                            mRequiresRestart = true;\n                        }\n                        break;\n                    case FREEZE:\n                        int freezeType = ((FreezeRule) entry).getFreezeType();\n                        FreezeUtils.storeFreezeMethod(mPackageName, freezeType);\n                        break;\n                }\n            } catch (Throwable e) {\n                // There are several reason restoring these things go wrong, especially when\n                // downgrading from an Android to another. It's better to simply suppress these\n                // exceptions instead of causing a failure or worse, a crash\n                Log.e(TAG, e);\n            }\n        }\n    }\n\n    private void loadMiscRules(final PseudoRules rules) throws BackupException {\n        Path miscFile;\n        try {\n            miscFile = mBackupItem.getMiscFile();\n        } catch (IOException e) {\n            // There are no permissions, just skip\n            return;\n        }\n        if (!mRequestedFlags.skipSignatureCheck()) {\n            String checksum = DigestUtils.getHexDigest(mBackupInfo.checksumAlgo, miscFile);\n            if (!checksum.equals(mChecksum.get(miscFile.getName()))) {\n                throw new BackupException(\"Couldn't verify misc file.\" +\n                        \"\\nFile: \" + miscFile +\n                        \"\\nFound: \" + checksum +\n                        \"\\nRequired: \" + mChecksum.get(miscFile.getName()));\n            }\n        }\n        // Decrypt permission file\n        try {\n            miscFile = mBackupItem.decrypt(new Path[]{miscFile})[0];\n        } catch (IOException | IndexOutOfBoundsException e) {\n            throw new BackupException(\"Failed to decrypt \" + miscFile.getName(), e);\n        }\n        try {\n            rules.loadExternalEntries(miscFile);\n        } catch (Throwable e) {\n            throw new BackupException(\"Failed to load rules from misc.\", e);\n        }\n    }\n\n    private void restoreRules() throws BackupException {\n        // Apply rules\n        if (!mIsInstalled) {\n            throw new BackupException(\"Rules restore is requested but the app isn't installed.\");\n        }\n        Path rulesFile;\n        try {\n            rulesFile = mBackupItem.getRulesFile();\n        } catch (IOException e) {\n            if (mBackupMetadata.hasRules) {\n                throw new BackupException(\"Rules file is missing.\", e);\n            } else {\n                // There are no rules, just skip\n                return;\n            }\n        }\n        if (!mRequestedFlags.skipSignatureCheck()) {\n            String checksum = DigestUtils.getHexDigest(mBackupInfo.checksumAlgo, rulesFile);\n            if (!checksum.equals(mChecksum.get(rulesFile.getName()))) {\n                throw new BackupException(\"Couldn't verify permission file.\" +\n                        \"\\nFile: \" + rulesFile +\n                        \"\\nFound: \" + checksum +\n                        \"\\nRequired: \" + mChecksum.get(rulesFile.getName()));\n            }\n        }\n        // Decrypt rules file\n        try {\n            rulesFile = mBackupItem.decrypt(new Path[]{rulesFile})[0];\n        } catch (IOException | IndexOutOfBoundsException e) {\n            throw new BackupException(\"Failed to decrypt \" + rulesFile.getName(), e);\n        }\n        try (RulesImporter importer = new RulesImporter(Arrays.asList(RuleType.values()), new int[]{mUserId})) {\n            importer.addRulesFromPath(rulesFile);\n            importer.setPackagesToImport(Collections.singletonList(mPackageName));\n            importer.applyRules(true);\n        } catch (IOException e) {\n            throw new BackupException(\"Failed to restore rules file.\", e);\n        }\n    }\n\n    private void deleteFiles(@NonNull Path[] files) {\n        for (Path file : files) {\n            file.delete();\n        }\n    }\n}"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/backup/VerifyOp.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.backup;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.WorkerThread;\n\nimport java.io.Closeable;\nimport java.io.IOException;\n\nimport io.github.muntashirakon.AppManager.backup.struct.BackupMetadataV5;\nimport io.github.muntashirakon.AppManager.crypto.CryptoException;\nimport io.github.muntashirakon.AppManager.logs.Log;\nimport io.github.muntashirakon.AppManager.utils.DigestUtils;\nimport io.github.muntashirakon.io.Path;\n\n@WorkerThread\nclass VerifyOp implements Closeable {\n    static final String TAG = VerifyOp.class.getSimpleName();\n\n    @NonNull\n    private final BackupFlags mBackupFlags;\n    @NonNull\n    private final BackupMetadataV5.Info mBackupInfo;\n    @NonNull\n    private final BackupMetadataV5.Metadata mBackupMetadata;\n    @NonNull\n    private final BackupItems.BackupItem mBackupItem;\n    @NonNull\n    private final BackupItems.Checksum mChecksum;\n\n    VerifyOp(@NonNull BackupItems.BackupItem backupItem) throws BackupException {\n        mBackupItem = backupItem;\n        try {\n            mBackupInfo = mBackupItem.getInfo();\n            mBackupFlags = mBackupInfo.flags;\n        } catch (IOException e) {\n            mBackupItem.cleanup();\n            throw new BackupException(\"Could not read backup info. Possibly due to a malformed json file.\", e);\n        }\n        // Setup crypto\n        if (!CryptoUtils.isAvailable(mBackupInfo.crypto)) {\n            mBackupItem.cleanup();\n            throw new BackupException(\"Mode \" + mBackupInfo.crypto + \" is currently unavailable.\");\n        }\n        try {\n            mBackupItem.setCrypto(mBackupInfo.getCrypto());\n        } catch (CryptoException e) {\n            mBackupItem.cleanup();\n            throw new BackupException(\"Could not get crypto \" + mBackupInfo.crypto, e);\n        }\n        try {\n            mBackupMetadata = mBackupItem.getMetadata(mBackupInfo).metadata;\n        } catch (IOException e) {\n            mBackupItem.cleanup();\n            throw new BackupException(\"Could not read backup metadata. Possibly due to a malformed json file.\", e);\n        }\n        // Get checksums\n        try {\n            mChecksum = mBackupItem.getChecksum();\n        } catch (Throwable e) {\n            mBackupItem.cleanup();\n            throw new BackupException(\"Could not get checksums.\", e);\n        }\n        // Verify metadata\n        try {\n            verifyMetadata();\n        } catch (BackupException e) {\n            mBackupItem.cleanup();\n            throw e;\n        }\n    }\n\n    @Override\n    public void close() {\n        Log.d(TAG, \"Close called\");\n        mChecksum.close();\n        mBackupItem.cleanup();\n    }\n\n    void verify() throws BackupException {\n        try {\n            // No need to check master key as it varies from device to device and APK signing key checksum as it would\n            // remain intact if the APK files are not modified.\n            if (mBackupFlags.backupApkFiles()) {\n                verifyApkFiles();\n            }\n            if (mBackupFlags.backupData()) {\n                verifyData();\n                if (mBackupMetadata.keyStore) {\n                    verifyKeyStore();\n                }\n            }\n            if (mBackupFlags.backupExtras()) {\n                verifyExtras();\n            }\n            if (mBackupFlags.backupRules()) {\n                verifyRules();\n            }\n        } catch (BackupException e) {\n            throw e;\n        } catch (Throwable th) {\n            throw new BackupException(\"Unknown error occurred\", th);\n        }\n    }\n\n    private void verifyMetadata() throws BackupException {\n        boolean isV5AndUp = mBackupItem.isV5AndUp();\n        if (isV5AndUp) {\n            Path infoFile;\n            try {\n                infoFile = mBackupItem.getInfoFile();\n            } catch (IOException e) {\n                throw new BackupException(\"Could not get metadata file.\", e);\n            }\n            String checksum = DigestUtils.getHexDigest(mBackupInfo.checksumAlgo, infoFile);\n            if (!checksum.equals(mChecksum.get(infoFile.getName()))) {\n                throw new BackupException(\"Couldn't verify metadata file.\" +\n                        \"\\nFile: \" + infoFile +\n                        \"\\nFound: \" + checksum +\n                        \"\\nRequired: \" + mChecksum.get(infoFile.getName()));\n            }\n        }\n        Path metadataFile;\n        try {\n            metadataFile = isV5AndUp ? mBackupItem.getMetadataV5File(false) : mBackupItem.getMetadataV2File();\n        } catch (IOException e) {\n            throw new BackupException(\"Could not get metadata file.\", e);\n        }\n        String checksum = DigestUtils.getHexDigest(mBackupInfo.checksumAlgo, metadataFile);\n        if (!checksum.equals(mChecksum.get(metadataFile.getName()))) {\n            throw new BackupException(\"Couldn't verify metadata file.\" +\n                    \"\\nFile: \" + metadataFile +\n                    \"\\nFound: \" + checksum +\n                    \"\\nRequired: \" + mChecksum.get(metadataFile.getName()));\n        }\n    }\n\n    private void verifyApkFiles() throws BackupException {\n        Path[] backupSourceFiles = mBackupItem.getSourceFiles();\n        if (backupSourceFiles.length == 0) {\n            // No APK files found\n            throw new BackupException(\"Backup does not contain any APK files.\");\n        }\n        String checksum;\n        for (Path file : backupSourceFiles) {\n            checksum = DigestUtils.getHexDigest(mBackupInfo.checksumAlgo, file);\n            if (!checksum.equals(mChecksum.get(file.getName()))) {\n                throw new BackupException(\"Could not verify APK files.\" +\n                        \"\\nFile: \" + file.getName() +\n                        \"\\nFound: \" + checksum +\n                        \"\\nRequired: \" + mChecksum.get(file.getName()));\n            }\n        }\n    }\n\n    private void verifyKeyStore() throws BackupException {\n        Path[] keyStoreFiles = mBackupItem.getKeyStoreFiles();\n        if (keyStoreFiles.length == 0) {\n            // Not having KeyStore backups is fine.\n            return;\n        }\n        String checksum;\n        for (Path file : keyStoreFiles) {\n            checksum = DigestUtils.getHexDigest(mBackupInfo.checksumAlgo, file);\n            if (!checksum.equals(mChecksum.get(file.getName()))) {\n                throw new BackupException(\"Could not verify KeyStore files.\" +\n                        \"\\nFile: \" + file.getName() +\n                        \"\\nFound: \" + checksum +\n                        \"\\nRequired: \" + mChecksum.get(file.getName()));\n            }\n        }\n    }\n\n    private void verifyData() throws BackupException {\n        Path[] dataFiles;\n        String checksum;\n        for (int i = 0; i < mBackupMetadata.dataDirs.length; ++i) {\n            dataFiles = mBackupItem.getDataFiles(i);\n            if (dataFiles.length == 0) {\n                throw new BackupException(\"No data files at index \" + i + \".\");\n            }\n            for (Path file : dataFiles) {\n                checksum = DigestUtils.getHexDigest(mBackupInfo.checksumAlgo, file);\n                if (!checksum.equals(mChecksum.get(file.getName()))) {\n                    throw new BackupException(\"Could not verify data files at index \" + i + \".\" +\n                            \"\\nFile: \" + file.getName() +\n                            \"\\nFound: \" + checksum +\n                            \"\\nRequired: \" + mChecksum.get(file.getName()));\n                }\n            }\n        }\n    }\n\n    private void verifyExtras() throws BackupException {\n        Path miscFile;\n        try {\n            miscFile = mBackupItem.getMiscFile();\n        } catch (IOException ignore) {\n            // There are no permissions, just skip\n            return;\n        }\n        String checksum = DigestUtils.getHexDigest(mBackupInfo.checksumAlgo, miscFile);\n        if (!checksum.equals(mChecksum.get(miscFile.getName()))) {\n            throw new BackupException(\"Could not verify extras.\" +\n                    \"\\nFile: \" + miscFile.getName() +\n                    \"\\nFound: \" + checksum +\n                    \"\\nRequired: \" + mChecksum.get(miscFile.getName()));\n        }\n    }\n\n    private void verifyRules() throws BackupException {\n        Path rulesFile;\n        try {\n            rulesFile = mBackupItem.getRulesFile();\n        } catch (IOException e) {\n            if (mBackupMetadata.hasRules) {\n                throw new BackupException(\"Rules file is missing.\", e);\n            } else {\n                // There are no rules, just skip\n                return;\n            }\n        }\n        String checksum = DigestUtils.getHexDigest(mBackupInfo.checksumAlgo, rulesFile);\n        if (!checksum.equals(mChecksum.get(rulesFile.getName()))) {\n            throw new BackupException(\"Could not verify rules file.\" +\n                    \"\\nFile: \" + rulesFile.getName() +\n                    \"\\nFound: \" + checksum +\n                    \"\\nRequired: \" + mChecksum.get(rulesFile.getName()));\n        }\n    }\n}"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/backup/adb/AndroidBackupCreator.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.backup.adb;\n\nimport static io.github.muntashirakon.AppManager.backup.adb.BackupCategories.CAT_EXT;\nimport static io.github.muntashirakon.AppManager.backup.adb.BackupCategories.CAT_INT_CE;\nimport static io.github.muntashirakon.AppManager.backup.adb.BackupCategories.CAT_INT_DE;\nimport static io.github.muntashirakon.AppManager.backup.adb.BackupCategories.CAT_OBB;\nimport static io.github.muntashirakon.AppManager.backup.adb.BackupCategories.CAT_SRC;\n\nimport android.content.pm.PackageInfo;\nimport android.content.pm.Signature;\nimport android.os.Build;\nimport android.util.StringBuilderPrinter;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.core.content.pm.PackageInfoCompat;\n\nimport org.apache.commons.compress.archivers.tar.TarArchiveEntry;\nimport org.apache.commons.compress.archivers.tar.TarArchiveInputStream;\nimport org.apache.commons.compress.archivers.tar.TarArchiveOutputStream;\nimport org.apache.commons.compress.archivers.tar.TarConstants;\n\nimport java.io.BufferedInputStream;\nimport java.io.BufferedOutputStream;\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.security.cert.CertificateEncodingException;\nimport java.security.cert.X509Certificate;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport io.github.muntashirakon.AppManager.apk.signing.SignerInfo;\nimport io.github.muntashirakon.AppManager.backup.BackupUtils;\nimport io.github.muntashirakon.AppManager.utils.ExUtils;\nimport io.github.muntashirakon.AppManager.utils.PackageUtils;\nimport io.github.muntashirakon.AppManager.utils.TarUtils;\nimport io.github.muntashirakon.io.IoUtils;\nimport io.github.muntashirakon.io.Path;\nimport io.github.muntashirakon.io.SplitInputStream;\n\npublic class AndroidBackupCreator implements AutoCloseable {\n    public static final String TAG = AndroidBackupCreator.class.getSimpleName();\n\n    public static void fromTar(@NonNull Path tarSource, @NonNull Path abDest, @Nullable char[] password, int api,\n                               boolean compress)\n            throws IOException {\n        int backupFileVersion = Constants.getBackupFileVersionFromApi(api);\n        AndroidBackupHeader header = new AndroidBackupHeader(backupFileVersion, compress, password);\n        try (InputStream is = tarSource.openInputStream();\n             OutputStream realOs = header.write(abDest.openOutputStream())) {\n            IoUtils.copy(is, realOs);\n        } catch (IOException e) {\n            throw e;\n        } catch (Exception e) {\n            ExUtils.rethrowAsIOException(e);\n        }\n    }\n\n    @NonNull\n    private final Path mWorkingDir;\n    @NonNull\n    private final String mPackageName;\n    @NonNull\n    private final PackageInfo mPackageInfo;\n    @Nullable\n    private final String mInstallerPackage;\n    private final Map<Integer, List<Path>> mCategoryFilesMap;\n    @NonNull\n    @TarUtils.TarType\n    private final String mTarType;\n    private final List<Path> mFilesToBeDeleted = new ArrayList<>();\n\n    public AndroidBackupCreator(@NonNull Map<Integer, List<Path>> categoryFilesMap,\n                                @NonNull Path temporaryDir,\n                                @NonNull PackageInfo packageInfo,\n                                @Nullable String installerPackage,\n                                @NonNull @TarUtils.TarType String tarType) {\n        mCategoryFilesMap = new HashMap<>(categoryFilesMap);\n        mWorkingDir = temporaryDir;\n        mPackageInfo = packageInfo;\n        mPackageName = packageInfo.packageName;\n        mInstallerPackage = installerPackage;\n        mTarType = tarType;\n    }\n\n    @Override\n    public void close() {\n        for (Path file : mFilesToBeDeleted) {\n            file.delete();\n        }\n    }\n\n    public Path getBackupFile(int dataIndex) throws IOException {\n        // Create temporary merged TAR file\n        String backupFilename = BackupUtils.getDataFilePrefix(dataIndex, null);\n        Path tempTarFile = mWorkingDir.createNewFile(backupFilename + \".tar\", null);\n        mFilesToBeDeleted.add(tempTarFile);\n        Path backupFile = mWorkingDir.createNewFile(backupFilename + \".ab\", null);\n\n        // Merge all category files into a single TAR\n        mergeCategoryFilesIntoTar(tempTarFile);\n\n        // Convert to AB file\n        fromTar(tempTarFile, backupFile, null, Build.VERSION.SDK_INT, true);\n        return backupFile;\n    }\n\n    private void mergeCategoryFilesIntoTar(@NonNull Path outputTarFile) throws IOException {\n        try (OutputStream fos = outputTarFile.openOutputStream();\n             BufferedOutputStream bos = new BufferedOutputStream(fos);\n             TarArchiveOutputStream taos = new TarArchiveOutputStream(bos)) {\n            taos.setLongFileMode(TarArchiveOutputStream.LONGFILE_POSIX);\n            taos.setBigNumberMode(TarArchiveOutputStream.BIGNUMBER_POSIX);\n\n            // Add manifest file first\n            addManifestEntry(taos);\n\n            // Process each category\n            for (Map.Entry<Integer, List<Path>> entry : mCategoryFilesMap.entrySet()) {\n                int category = entry.getKey();\n                List<Path> files = entry.getValue();\n                if (files != null && !files.isEmpty()) {\n                    processCategoryFiles(taos, category, files);\n                }\n            }\n\n            taos.finish();\n        }\n    }\n\n    private void addManifestEntry(@NonNull TarArchiveOutputStream taos) throws IOException {\n        String manifestPath = Constants.APPS_PREFIX + mPackageName + File.separator + Constants.BACKUP_MANIFEST_FILENAME;\n        byte[] manifestContent = getManifestBytes(mCategoryFilesMap.get(CAT_SRC) != null);\n\n        TarArchiveEntry manifestEntry = new TarArchiveEntry(manifestPath);\n        manifestEntry.setSize(manifestContent.length);\n        manifestEntry.setMode(0600); // rw-------\n        manifestEntry.setModTime(0); // See AppMetadataBackupWriter.java\n\n        taos.putArchiveEntry(manifestEntry);\n        taos.write(manifestContent);\n        taos.closeArchiveEntry();\n    }\n\n    // See AppMetadataBackupWriter#getManifestBytes(PackageInfo, boolean)\n    @NonNull\n    private byte[] getManifestBytes(boolean withApk) {\n        StringBuilder builder = new StringBuilder(4096);\n        StringBuilderPrinter printer = new StringBuilderPrinter(builder);\n        printer.println(Integer.toString(Constants.BACKUP_MANIFEST_VERSION));\n        printer.println(mPackageName);\n        printer.println(Long.toString(PackageInfoCompat.getLongVersionCode(mPackageInfo)));\n        printer.println(Integer.toString(Build.VERSION.SDK_INT));\n        printer.println((mInstallerPackage != null) ? mInstallerPackage : \"\");\n        printer.println(withApk ? \"1\" : \"0\");\n\n        // Write the signature block.\n        SignerInfo signerInfo = PackageUtils.getSignerInfo(mPackageInfo, true);\n        if (signerInfo == null || signerInfo.getCurrentSignerCerts() == null) {\n            printer.println(\"0\");\n        } else {\n            // Retrieve the newest signatures to write.\n            try {\n                X509Certificate[] signerCerts = signerInfo.getCurrentSignerCerts();\n                Signature[] signatures = new Signature[signerCerts.length];\n                for (int i = 0; i < signatures.length; ++i) {\n                    signatures[i] = new Signature(signerCerts[i].getEncoded());\n                }\n                printer.println(Integer.toString(signerCerts.length));\n                for (Signature sig : signatures) {\n                    printer.println(sig.toCharsString());\n                }\n            } catch (CertificateEncodingException e) {\n                // Fall back to 0\n                printer.println(\"0\");\n            }\n        }\n        return builder.toString().getBytes();\n    }\n\n    private void processCategoryFiles(@NonNull TarArchiveOutputStream taos,\n                                      int category,\n                                      @NonNull List<Path> files) throws IOException {\n        try (SplitInputStream sis = new SplitInputStream(files);\n             BufferedInputStream bis = new BufferedInputStream(sis);\n             InputStream decompressedStream = TarUtils.createDecompressedStream(bis, mTarType);\n             TarArchiveInputStream tis = new TarArchiveInputStream(decompressedStream)) {\n            TarArchiveEntry entry;\n            while ((entry = tis.getNextTarEntry()) != null) {\n                String transformedPath = transformEntryPath(entry.getName(), category);\n                byte linkFlag;\n                if (entry.isSymbolicLink()) {\n                    linkFlag = TarConstants.LF_SYMLINK;\n                } else if (entry.isDirectory()) {\n                    linkFlag = TarConstants.LF_DIR;\n                } else linkFlag = TarConstants.LF_NORMAL;\n                // Create new entry with transformed path\n                TarArchiveEntry newEntry = new TarArchiveEntry(transformedPath, linkFlag);\n                newEntry.setSize(entry.getSize());\n                newEntry.setMode(entry.getMode());\n                newEntry.setModTime(entry.getModTime());\n                newEntry.setUserId(entry.getUserId());\n                newEntry.setGroupId(entry.getGroupId());\n                newEntry.setUserName(entry.getUserName());\n                newEntry.setGroupName(entry.getGroupName());\n                if (entry.isSymbolicLink()) {\n                    newEntry.setLinkName(entry.getLinkName());\n                }\n                taos.putArchiveEntry(newEntry);\n                if (linkFlag == TarConstants.LF_NORMAL) {\n                    IoUtils.copy(tis, taos);\n                }\n                taos.closeArchiveEntry();\n            }\n        }\n    }\n\n    @NonNull\n    private String transformEntryPath(@NonNull String originalPath, int category) {\n        String basePath = Constants.APPS_PREFIX + mPackageName + File.separator;\n        if (originalPath.endsWith(File.separator)) {\n            // AB expects no trailing slashes\n            originalPath = originalPath.substring(0, originalPath.length() - 1);\n        }\n        switch (category) {\n            case CAT_SRC:\n                return basePath + Constants.APK_TREE_TOKEN + File.separator + originalPath;\n            case CAT_INT_CE:\n                return transformInternalPath(basePath, originalPath, false);\n            case CAT_INT_DE:\n                return transformInternalPath(basePath, originalPath, true);\n            case CAT_EXT:\n                return basePath + Constants.MANAGED_EXTERNAL_TREE_TOKEN + File.separator + originalPath;\n            case CAT_OBB:\n                return basePath + Constants.OBB_TREE_TOKEN + File.separator + originalPath;\n            default:\n                throw new IllegalArgumentException(\"Invalid category: \" + category);\n        }\n    }\n\n    @NonNull\n    private String transformInternalPath(@NonNull String basePath,\n                                         @NonNull String path,\n                                         boolean isDE) {\n        String prefix;\n        if (path.startsWith(\"files/\")) {\n            prefix = isDE ? Constants.DEVICE_FILES_TREE_TOKEN : Constants.FILES_TREE_TOKEN;\n            path = path.substring(6); // Remove \"files/\"\n        } else if (path.startsWith(\"databases/\")) {\n            prefix = isDE ? Constants.DEVICE_DATABASE_TREE_TOKEN : Constants.DATABASE_TREE_TOKEN;\n            path = path.substring(10); // Remove \"databases/\"\n        } else if (path.startsWith(\"shared_prefs/\")) {\n            prefix = isDE ? Constants.DEVICE_SHAREDPREFS_TREE_TOKEN : Constants.SHAREDPREFS_TREE_TOKEN;\n            path = path.substring(13); // Remove \"shared_prefs/\"\n        } else if (path.startsWith(\"no_backup/\")) {\n            prefix = isDE ? Constants.DEVICE_NO_BACKUP_TREE_TOKEN : Constants.NO_BACKUP_TREE_TOKEN;\n            path = path.substring(10); // Remove \"no_backup/\"\n        } else if (path.startsWith(\"caches/\")) {\n            prefix = isDE ? Constants.DEVICE_CACHE_TREE_TOKEN : Constants.CACHE_TREE_TOKEN;\n            path = path.substring(7); // Remove \"caches/\"\n        } else prefix = isDE ? Constants.DEVICE_ROOT_TREE_TOKEN : Constants.ROOT_TREE_TOKEN;\n        return basePath + prefix + File.separator + path;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/backup/adb/AndroidBackupExtractor.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.backup.adb;\n\nimport static io.github.muntashirakon.AppManager.backup.adb.BackupCategories.CAT_EXT;\nimport static io.github.muntashirakon.AppManager.backup.adb.BackupCategories.CAT_INT_CE;\nimport static io.github.muntashirakon.AppManager.backup.adb.BackupCategories.CAT_INT_DE;\nimport static io.github.muntashirakon.AppManager.backup.adb.BackupCategories.CAT_OBB;\nimport static io.github.muntashirakon.AppManager.backup.adb.BackupCategories.CAT_SRC;\nimport static io.github.muntashirakon.AppManager.backup.adb.BackupCategories.CAT_UNK;\nimport static io.github.muntashirakon.AppManager.utils.TarUtils.DEFAULT_SPLIT_SIZE;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport org.apache.commons.compress.archivers.tar.TarArchiveEntry;\nimport org.apache.commons.compress.archivers.tar.TarArchiveInputStream;\nimport org.apache.commons.compress.archivers.tar.TarArchiveOutputStream;\nimport org.apache.commons.compress.archivers.tar.TarConstants;\n\nimport java.io.BufferedOutputStream;\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport io.github.muntashirakon.AppManager.backup.BackupUtils;\nimport io.github.muntashirakon.AppManager.logs.Log;\nimport io.github.muntashirakon.AppManager.utils.ExUtils;\nimport io.github.muntashirakon.AppManager.utils.TarUtils;\nimport io.github.muntashirakon.io.IoUtils;\nimport io.github.muntashirakon.io.Path;\nimport io.github.muntashirakon.io.Paths;\nimport io.github.muntashirakon.io.SplitOutputStream;\n\npublic class AndroidBackupExtractor implements AutoCloseable {\n    public static final String TAG = AndroidBackupExtractor.class.getSimpleName();\n\n    public static void toTar(@NonNull Path abSource, @NonNull Path tarDest, @Nullable char[] password)\n            throws IOException {\n        AndroidBackupHeader header = new AndroidBackupHeader(password);\n        try (OutputStream os = tarDest.openOutputStream();\n             InputStream realIs = header.read(abSource.openInputStream())) {\n            IoUtils.copy(realIs, os);\n        } catch (Exception e) {\n            ExUtils.rethrowAsIOException(e);\n        }\n    }\n\n    private final Path mWorkingDir;\n    private final Map<Integer, List<TargetTarEntry>> mCategoryTargetEntriesMap = new HashMap<>();\n    private final List<Path> mFilesToBeDeleted = new ArrayList<>();\n\n    public AndroidBackupExtractor(@NonNull Path abFile, @NonNull Path temporaryDir, @NonNull String packageName) throws IOException {\n        mWorkingDir = temporaryDir;\n        String relativeDirInAb = Constants.APPS_PREFIX + packageName + File.separator;\n        String abFilename = Paths.trimPathExtension(abFile.getName());\n        Path tarFile = temporaryDir.createNewFile(abFilename + \".tar\", null);\n        mFilesToBeDeleted.add(tarFile);\n        Path dest = temporaryDir.createNewDirectory(abFilename);\n        mFilesToBeDeleted.add(dest);\n        toTar(abFile, tarFile, null);\n        try (InputStream fis = tarFile.openInputStream();\n             TarArchiveInputStream tis = new TarArchiveInputStream(fis)) {\n            String realDestPath = dest.getRealFilePath();\n            int relDirSize = relativeDirInAb.length();\n            TarArchiveEntry entry;\n            while ((entry = tis.getNextTarEntry()) != null) {\n                String filename = Paths.normalize(entry.getName());\n                // Early zip slip vulnerability check to avoid creating any files at all\n                if (filename == null || filename.startsWith(\"../\")) {\n                    throw new IOException(\"Zip slip vulnerability detected!\" +\n                            \"\\nExpected dest: \" + new File(realDestPath, entry.getName()) +\n                            \"\\nActual path: \" + (filename != null ? new File(realDestPath, filename) : realDestPath));\n                }\n                if (!filename.startsWith(relativeDirInAb)) {\n                    throw new IOException(\"Unsupported file in AB: \" + filename);\n                }\n                // Remove apps/{packageName}/ part\n                filename = filename.substring(relDirSize);\n                Path file;\n                if (entry.isDirectory()) {\n                    file = dest.createDirectoriesIfRequired(filename);\n                } else file = dest.createNewArbitraryFile(filename, null);\n                // Check if the given entry is a link.\n                if (entry.isSymbolicLink() && file.getFilePath() != null) {\n                    String linkName = entry.getLinkName();\n                    file.delete();\n                    file.createNewSymbolicLink(linkName);\n                } else {\n                    // Zip slip vulnerability might still be present\n                    String realFilePath = file.getRealFilePath();\n                    if (realDestPath != null && realFilePath != null && !realFilePath.startsWith(realDestPath)) {\n                        throw new IOException(\"Zip slip vulnerability detected!\" +\n                                \"\\nExpected dest: \" + new File(realDestPath, entry.getName()) +\n                                \"\\nActual path: \" + realFilePath);\n                    }\n                    if (!entry.isDirectory()) {\n                        try (OutputStream os = file.openOutputStream()) {\n                            IoUtils.copy(tis, os);\n                        }\n                    }\n                }\n\n                // Categorize and build TarArchiveEntry\n                int category = getCategory(filename);\n                if (category == CAT_UNK && filename.equals(Constants.BACKUP_MANIFEST_FILENAME)) {\n                    // Ignore manifest file\n                    continue;\n                }\n                TarArchiveEntry targetEntry = getTargetArchiveEntry(entry, filename);\n                List<TargetTarEntry> targetTarEntries = mCategoryTargetEntriesMap.get(category);\n                if (targetTarEntries == null) {\n                    targetTarEntries = new ArrayList<>();\n                    mCategoryTargetEntriesMap.put(category, targetTarEntries);\n                }\n                targetTarEntries.add(new TargetTarEntry(file, filename, category, targetEntry));\n            }\n        }\n        // Validate UNK entries\n        if (mCategoryTargetEntriesMap.get(CAT_UNK) != null) {\n            Log.w(TAG, \"Unknown entries: \" + mCategoryTargetEntriesMap.get(CAT_UNK));\n            throw new IOException(\"Unknown/unsupported entries detected.\");\n        }\n    }\n\n    @Override\n    public void close() {\n        for (Path file : mFilesToBeDeleted) {\n            file.delete();\n        }\n    }\n\n    @Nullable\n    public Path[] getSourceFiles(@NonNull String extension, @TarUtils.TarType String tarType)\n            throws IOException {\n        return getFiles(CAT_SRC, 0, extension, tarType);\n    }\n\n    @Nullable\n    public Path[] getInternalCeDataFiles(int dataIndex, @NonNull String extension,\n                                         @TarUtils.TarType String tarType) throws IOException {\n        return getFiles(CAT_INT_CE, dataIndex, extension, tarType);\n    }\n\n    @Nullable\n    public Path[] getInternalDeDataFiles(int dataIndex, @NonNull String extension,\n                                         @TarUtils.TarType String tarType) throws IOException {\n        return getFiles(CAT_INT_DE, dataIndex, extension, tarType);\n    }\n\n    @Nullable\n    public Path[] getExternalDataFiles(int dataIndex, @NonNull String extension,\n                                       @TarUtils.TarType String tarType) throws IOException {\n        return getFiles(CAT_EXT, dataIndex, extension, tarType);\n    }\n\n    @Nullable\n    public Path[] getObbFiles(int dataIndex, @NonNull String extension,\n                              @TarUtils.TarType String tarType) throws IOException {\n        return getFiles(CAT_OBB, dataIndex, extension, tarType);\n    }\n\n    @Nullable\n    public Path[] getFiles(int category,\n                           int dataIndex,\n                           @NonNull String extension,\n                           @TarUtils.TarType String tarType) throws IOException {\n        if (category >= CAT_UNK) {\n            throw new IllegalArgumentException(\"Invalid category: \" + category);\n        }\n        List<TargetTarEntry> targetTarEntries = mCategoryTargetEntriesMap.get(category);\n        if (targetTarEntries == null) {\n            return null;\n        }\n        String filePrefix = category == CAT_SRC ? BackupUtils.getSourceFilePrefix(extension) :\n                BackupUtils.getDataFilePrefix(dataIndex, extension);\n        try (SplitOutputStream sos = new SplitOutputStream(mWorkingDir, filePrefix, DEFAULT_SPLIT_SIZE);\n             BufferedOutputStream bos = new BufferedOutputStream(sos);\n             OutputStream os = TarUtils.createCompressedStream(bos, tarType)) {\n            try (TarArchiveOutputStream tos = new TarArchiveOutputStream(os)) {\n                tos.setLongFileMode(TarArchiveOutputStream.LONGFILE_POSIX);\n                tos.setBigNumberMode(TarArchiveOutputStream.BIGNUMBER_POSIX);\n                for (TargetTarEntry entry : targetTarEntries) {\n                    if (entry.targetEntry.isSymbolicLink()) {\n                        // Add the link as is\n                        tos.putArchiveEntry(entry.targetEntry);\n                    } else {\n                        tos.putArchiveEntry(entry.targetEntry);\n                        if (!entry.targetEntry.isDirectory()) {\n                            try (InputStream is = entry.sourceFile.openInputStream()) {\n                                IoUtils.copy(is, tos);\n                            }\n                        }\n                    }\n                    tos.closeArchiveEntry();\n                }\n                tos.finish();\n            } finally {\n                os.close();\n            }\n            return Paths.getSortedPaths(sos.getFiles().toArray(new Path[0]));\n        }\n    }\n\n    private int getCategory(@NonNull String filename) {\n        //noinspection SuspiciousRegexArgument Not on Windows\n        String firstPart = filename.split(File.separator, 2)[0];\n        switch (firstPart) {\n            case Constants.APK_TREE_TOKEN:\n                return CAT_SRC;\n            case Constants.OBB_TREE_TOKEN:\n                return CAT_OBB;\n            case Constants.MANAGED_EXTERNAL_TREE_TOKEN:\n                return CAT_EXT;\n            case Constants.ROOT_TREE_TOKEN:\n            case Constants.FILES_TREE_TOKEN:\n            case Constants.NO_BACKUP_TREE_TOKEN:\n            case Constants.DATABASE_TREE_TOKEN:\n            case Constants.SHAREDPREFS_TREE_TOKEN:\n            case Constants.CACHE_TREE_TOKEN:\n                return CAT_INT_CE;\n            case Constants.DEVICE_ROOT_TREE_TOKEN:\n            case Constants.DEVICE_FILES_TREE_TOKEN:\n            case Constants.DEVICE_NO_BACKUP_TREE_TOKEN:\n            case Constants.DEVICE_DATABASE_TREE_TOKEN:\n            case Constants.DEVICE_SHAREDPREFS_TREE_TOKEN:\n            case Constants.DEVICE_CACHE_TREE_TOKEN:\n                return CAT_INT_DE;\n            default:\n                return CAT_UNK;\n        }\n    }\n\n    @NonNull\n    private TarArchiveEntry getTargetArchiveEntry(@NonNull TarArchiveEntry src, @NonNull String filename) {\n        String realFilename = getRealFilename(filename);\n        if (src.isSymbolicLink()) {\n            TarArchiveEntry dst = new TarArchiveEntry(realFilename, TarConstants.LF_SYMLINK);\n            dst.setLinkName(src.getLinkName());\n            return dst;\n        }\n        // Regular file/folder\n        byte flag = src.isDirectory() ? TarConstants.LF_DIR : TarConstants.LF_NORMAL;\n        TarArchiveEntry dst = new TarArchiveEntry(realFilename, flag);\n        dst.setSize(src.getSize());\n        dst.setMode(src.getMode());\n        dst.setModTime(src.getModTime());\n        dst.setUserId(src.getUserId());\n        dst.setGroupId(src.getGroupId());\n        dst.setUserName(src.getUserName());\n        dst.setGroupName(src.getGroupName());\n        return dst;\n    }\n\n    @NonNull\n    private String getRealFilename(@NonNull String filename) {\n        //noinspection SuspiciousRegexArgument Not on Windows\n        String[] parts = filename.split(File.separator, 2);\n        String firstPart = parts[0];\n        String secondPart = parts[1];\n        switch (firstPart) {\n            case Constants.FILES_TREE_TOKEN:\n            case Constants.DEVICE_FILES_TREE_TOKEN:\n                return \"files/\" + secondPart;\n            case Constants.NO_BACKUP_TREE_TOKEN:\n            case Constants.DEVICE_NO_BACKUP_TREE_TOKEN:\n                return \"no_backup/\" + secondPart;\n            case Constants.DATABASE_TREE_TOKEN:\n            case Constants.DEVICE_DATABASE_TREE_TOKEN:\n                return \"databases/\" + secondPart;\n            case Constants.SHAREDPREFS_TREE_TOKEN:\n            case Constants.DEVICE_SHAREDPREFS_TREE_TOKEN:\n                return \"shared_prefs/\" + secondPart;\n            case Constants.CACHE_TREE_TOKEN:\n            case Constants.DEVICE_CACHE_TREE_TOKEN:\n                return \"caches/\" + secondPart;\n            default:\n                return secondPart;\n        }\n    }\n\n    private static class TargetTarEntry {\n        @NonNull\n        public final Path sourceFile;\n        @NonNull\n        public final String sourceFilename;\n        public final int category;\n        @NonNull\n        public final TarArchiveEntry targetEntry;\n\n        private TargetTarEntry(@NonNull Path sourceFile, @NonNull String sourceFilename,\n                               int category, @NonNull TarArchiveEntry targetEntry) {\n            this.sourceFile = sourceFile;\n            this.sourceFilename = sourceFilename;\n            this.category = category;\n            this.targetEntry = targetEntry;\n        }\n\n        @NonNull\n        @Override\n        public String toString() {\n            return sourceFilename;\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/backup/adb/AndroidBackupHeader.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.backup.adb;\n\nimport static io.github.muntashirakon.AppManager.backup.adb.Constants.BACKUP_FILE_HEADER_MAGIC;\nimport static io.github.muntashirakon.AppManager.backup.adb.Constants.BACKUP_FILE_VERSION;\nimport static io.github.muntashirakon.AppManager.backup.adb.Constants.ENCRYPTION_ALGORITHM_NAME;\nimport static io.github.muntashirakon.AppManager.backup.adb.Constants.PBKDF2_HASH_ROUNDS;\nimport static io.github.muntashirakon.AppManager.backup.adb.Constants.PBKDF2_KEY_SIZE;\nimport static io.github.muntashirakon.AppManager.backup.adb.Constants.PBKDF2_SALT_SIZE;\nimport static io.github.muntashirakon.AppManager.backup.adb.Constants.PBKDF_CURRENT;\nimport static io.github.muntashirakon.AppManager.backup.adb.Constants.PBKDF_FALLBACK;\n\nimport android.os.Build;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.DataOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.nio.charset.StandardCharsets;\nimport java.security.Key;\nimport java.security.MessageDigest;\nimport java.security.SecureRandom;\nimport java.security.spec.KeySpec;\nimport java.util.Arrays;\nimport java.util.zip.Deflater;\nimport java.util.zip.DeflaterOutputStream;\nimport java.util.zip.InflaterInputStream;\n\nimport javax.crypto.Cipher;\nimport javax.crypto.CipherInputStream;\nimport javax.crypto.CipherOutputStream;\nimport javax.crypto.SecretKey;\nimport javax.crypto.SecretKeyFactory;\nimport javax.crypto.spec.IvParameterSpec;\nimport javax.crypto.spec.PBEKeySpec;\nimport javax.crypto.spec.SecretKeySpec;\n\nimport aosp.libcore.util.HexEncoding;\n\nfinal class AndroidBackupHeader {\n    // NOTE: (CWE-326) Vulnerable to padding oracle attacks, but there's no way to fix it as it's used by Android.\n    private static final String TRANSFORMATION = \"AES/CBC/PKCS5Padding\";\n\n    private final SecureRandom mRng = new SecureRandom();\n    private int mBackupFileVersion;\n    private boolean mCompress;\n    @Nullable\n    private final char[] mPassword;\n\n    public AndroidBackupHeader(int backupFileVersion, boolean compress, @Nullable char[] password) {\n        mBackupFileVersion = backupFileVersion;\n        mCompress = compress;\n        mPassword = password;\n    }\n\n    public AndroidBackupHeader(@Nullable char[] password) {\n        mBackupFileVersion = Constants.getBackupFileVersionFromApi(Build.VERSION.SDK_INT);\n        mCompress = true;\n        mPassword = password;\n    }\n\n    @NonNull\n    public InputStream read(@NonNull InputStream backupStream) throws Exception {\n        // First, parse out the unencrypted/uncompressed header\n        InputStream preCompressStream = backupStream;\n\n        final int headerLen = BACKUP_FILE_HEADER_MAGIC.length();\n        byte[] streamHeader = new byte[headerLen];\n        readFullyOrThrow(backupStream, streamHeader);\n        byte[] magicBytes = BACKUP_FILE_HEADER_MAGIC.getBytes(StandardCharsets.UTF_8);\n        if (Arrays.equals(magicBytes, streamHeader)) {\n            // okay, header looks good.  now parse out the rest of the fields.\n            String s = readHeaderLine(backupStream);\n            mBackupFileVersion = Integer.parseInt(s);\n            if (mBackupFileVersion <= BACKUP_FILE_VERSION) {\n                // okay, it's a version we recognize.  if it's version 1, we may need\n                // to try two different PBKDF2 regimes to compare checksums.\n                final boolean pbkdf2Fallback = (mBackupFileVersion == 1);\n\n                s = readHeaderLine(backupStream);\n                mCompress = (Integer.parseInt(s) != 0);\n                s = readHeaderLine(backupStream);\n                if (s.equals(\"none\")) {\n                    // no more header to parse; we're good to go\n                } else if (mPassword != null && mPassword.length > 0) { // AES-256\n                    preCompressStream = decodeAesHeaderAndInitialize(mPassword, s, pbkdf2Fallback, backupStream);\n                } else {\n                    throw new IOException(\"Archive is encrypted but no password given\");\n                }\n            } else {\n                throw new IOException(\"Wrong header version: \" + s);\n            }\n        } else {\n            throw new IOException(\"Didn't read the right header magic\");\n        }\n\n        // okay, use the right stream layer based on compression\n        return mCompress ? new InflaterInputStream(preCompressStream) : preCompressStream;\n    }\n\n    @NonNull\n    public OutputStream write(@NonNull OutputStream backupStream) throws Exception {\n        // Write the global file header.  All strings are UTF-8 encoded; lines end\n        // with a '\\n' byte.  Actual backup data begins immediately following the\n        // final '\\n'.\n        //\n        // line 1: \"ANDROID BACKUP\"\n        // line 2: backup file format version, currently \"5\"\n        // line 3: compressed?  \"0\" if not compressed, \"1\" if compressed.\n        // line 4: name of encryption algorithm [currently only \"none\" or \"AES-256\"]\n        //\n        // When line 4 is not \"none\", then additional header data follows:\n        //\n        // line 5: user password salt [hex]\n        // line 6: encryption key checksum salt [hex]\n        // line 7: number of PBKDF2 rounds to use (same for user & encryption key) [decimal]\n        // line 8: IV of the user key [hex]\n        // line 9: encryption key blob [hex]\n        //     IV of the encryption key, encryption key itself, encryption key checksum hash\n        //\n        // The encryption key checksum is the encryption key plus its checksum salt, run through\n        // 10k rounds of PBKDF2.  This is used to verify that the user has supplied the\n        // correct password for decrypting the archive:  the encryption key decrypted from\n        // the archive using the user-supplied password is also run through PBKDF2 in\n        // this way, and if the result does not match the checksum as stored in the\n        // archive, then we know that the user-supplied password does not match the\n        // archive's.\n        StringBuilder headerbuf = new StringBuilder(1024);\n\n        headerbuf.append(BACKUP_FILE_HEADER_MAGIC);\n        headerbuf.append(mBackupFileVersion); // integer, no trailing \\n\n        headerbuf.append(mCompress ? \"\\n1\\n\" : \"\\n0\\n\");\n\n        OutputStream finalOutput = backupStream;\n        // Set up the encryption stage if appropriate, and emit the correct header\n        if (mPassword != null) {\n            finalOutput = emitAesBackupHeader(headerbuf, backupStream);\n        } else {\n            headerbuf.append(\"none\\n\");\n        }\n\n        byte[] header = headerbuf.toString().getBytes(StandardCharsets.UTF_8);\n        backupStream.write(header);\n\n        // Set up the compression stage feeding into the encryption stage (if any)\n        if (mCompress) {\n            Deflater deflater = new Deflater(Deflater.BEST_COMPRESSION);\n            finalOutput = new DeflaterOutputStream(finalOutput, deflater, true);\n        }\n\n        return finalOutput;\n    }\n\n    @NonNull\n    private OutputStream emitAesBackupHeader(@NonNull StringBuilder headerbuf,\n                                             @NonNull OutputStream ofstream) throws Exception {\n        // User key will be used to encrypt the encryption key.\n        byte[] newUserSalt = randomBytes(PBKDF2_SALT_SIZE);\n        SecretKey userKey = buildCharArrayKey(PBKDF_CURRENT, mPassword, newUserSalt, PBKDF2_HASH_ROUNDS);\n\n        // the encryption key is random for each backup\n        byte[] encryptionKey = new byte[256 / 8];\n        mRng.nextBytes(encryptionKey);\n        byte[] checksumSalt = randomBytes(PBKDF2_SALT_SIZE);\n\n        // primary encryption of the datastream with the encryption key\n        Cipher c = Cipher.getInstance(TRANSFORMATION);\n        SecretKeySpec encryptionKeySpec = new SecretKeySpec(encryptionKey, \"AES\");\n        c.init(Cipher.ENCRYPT_MODE, encryptionKeySpec);\n        OutputStream finalOutput = new CipherOutputStream(ofstream, c);\n\n        // line 4: name of encryption algorithm\n        headerbuf.append(ENCRYPTION_ALGORITHM_NAME);\n        headerbuf.append('\\n');\n        // line 5: user password salt [hex]\n        headerbuf.append(byteArrayToHex(newUserSalt));\n        headerbuf.append('\\n');\n        // line 6: encryption key checksum salt [hex]\n        headerbuf.append(byteArrayToHex(checksumSalt));\n        headerbuf.append('\\n');\n        // line 7: number of PBKDF2 rounds used [decimal]\n        headerbuf.append(PBKDF2_HASH_ROUNDS);\n        headerbuf.append('\\n');\n\n        // line 8: IV of the user key [hex]\n        Cipher mkC = Cipher.getInstance(TRANSFORMATION);\n        mkC.init(Cipher.ENCRYPT_MODE, userKey);\n\n        byte[] IV = mkC.getIV();\n        headerbuf.append(byteArrayToHex(IV));\n        headerbuf.append('\\n');\n\n        // line 9: encryption IV + key blob, encrypted by the user key [hex].  Blob format:\n        //    [byte] IV length = Niv\n        //    [array of Niv bytes] IV itself\n        //    [byte] encryption key length = Nek\n        //    [array of Nek bytes] encryption key itself\n        //    [byte] encryption key checksum hash length = Nck\n        //    [array of Nck bytes] encryption key checksum hash\n        //\n        // The checksum is the (encryption key + checksum salt), run through the\n        // stated number of PBKDF2 rounds\n        IV = c.getIV();\n        byte[] mk = encryptionKeySpec.getEncoded();\n        byte[] checksum = makeKeyChecksum(PBKDF_CURRENT,\n                encryptionKeySpec.getEncoded(),\n                checksumSalt, PBKDF2_HASH_ROUNDS);\n\n        ByteArrayOutputStream blob = new ByteArrayOutputStream(IV.length + mk.length\n                + checksum.length + 3);\n        DataOutputStream mkOut = new DataOutputStream(blob);\n        mkOut.writeByte(IV.length);\n        mkOut.write(IV);\n        mkOut.writeByte(mk.length);\n        mkOut.write(mk);\n        mkOut.writeByte(checksum.length);\n        mkOut.write(checksum);\n        mkOut.flush();\n        byte[] encryptedMk = mkC.doFinal(blob.toByteArray());\n        headerbuf.append(byteArrayToHex(encryptedMk));\n        headerbuf.append('\\n');\n\n        return finalOutput;\n    }\n\n    @NonNull\n    private static InputStream decodeAesHeaderAndInitialize(char[] decryptPassword,\n                                                            @NonNull String encryptionName,\n                                                            boolean pbkdf2Fallback,\n                                                            @NonNull InputStream rawInStream) throws Exception {\n        if (!encryptionName.equals(ENCRYPTION_ALGORITHM_NAME)) {\n            throw new IOException(\"Unsupported encryption method: \" + encryptionName);\n        }\n\n        String userSaltHex = readHeaderLine(rawInStream); // 5\n        byte[] userSalt = hexToByteArray(userSaltHex);\n\n        String ckSaltHex = readHeaderLine(rawInStream); // 6\n        byte[] ckSalt = hexToByteArray(ckSaltHex);\n\n        int rounds = Integer.parseInt(readHeaderLine(rawInStream)); // 7\n        String userIvHex = readHeaderLine(rawInStream); // 8\n\n        String encryptionKeyBlobHex = readHeaderLine(rawInStream); // 9\n\n        // decrypt the encryption key blob\n        try {\n            return attemptEncryptionKeyDecryption(decryptPassword, PBKDF_CURRENT, userSalt,\n                    ckSalt, rounds, userIvHex, encryptionKeyBlobHex, rawInStream);\n        } catch (Exception e) {\n            if (pbkdf2Fallback) {\n                return attemptEncryptionKeyDecryption(decryptPassword, PBKDF_FALLBACK, userSalt,\n                        ckSalt, rounds, userIvHex, encryptionKeyBlobHex, rawInStream);\n            }\n            throw e;\n        }\n    }\n\n    @NonNull\n    private static InputStream attemptEncryptionKeyDecryption(char[] decryptPassword, String algorithm, byte[] userSalt,\n                                                              byte[] ckSalt, int rounds, String userIvHex,\n                                                              String encryptionKeyBlobHex, InputStream rawInStream)\n            throws Exception {\n        InputStream result;\n        Cipher c = Cipher.getInstance(TRANSFORMATION);\n        SecretKey userKey = buildCharArrayKey(algorithm, decryptPassword, userSalt,\n                rounds);\n        byte[] IV = hexToByteArray(userIvHex);\n        IvParameterSpec ivSpec = new IvParameterSpec(IV);\n        c.init(Cipher.DECRYPT_MODE,\n                new SecretKeySpec(userKey.getEncoded(), \"AES\"),\n                ivSpec);\n        byte[] mkCipher = hexToByteArray(encryptionKeyBlobHex);\n        byte[] mkBlob = c.doFinal(mkCipher);\n\n        // first, the encryption key IV\n        int offset = 0;\n        int len = mkBlob[offset++];\n        IV = Arrays.copyOfRange(mkBlob, offset, offset + len);\n        offset += len;\n        // then the encryption key itself\n        len = mkBlob[offset++];\n        byte[] encryptionKey = Arrays.copyOfRange(mkBlob,\n                offset, offset + len);\n        offset += len;\n        // and finally the encryption key checksum hash\n        len = mkBlob[offset++];\n        byte[] mkChecksum = Arrays.copyOfRange(mkBlob,\n                offset, offset + len);\n\n        // now validate the decrypted encryption key against the checksum\n        byte[] calculatedCk = makeKeyChecksum(algorithm, encryptionKey, ckSalt,\n                rounds);\n        if (MessageDigest.isEqual(calculatedCk, mkChecksum)) {\n            ivSpec = new IvParameterSpec(IV);\n            c.init(Cipher.DECRYPT_MODE,\n                    new SecretKeySpec(encryptionKey, \"AES\"),\n                    ivSpec);\n            // Only if all of the above worked properly will 'result' be assigned\n            result = new CipherInputStream(rawInStream, c);\n        } else {\n            throw new IOException(\"Incorrect password\");\n        }\n\n        return result;\n    }\n\n    /**\n     * Used for generating random salts or passwords.\n     */\n    public byte[] randomBytes(int bits) {\n        byte[] array = new byte[bits / 8];\n        mRng.nextBytes(array);\n        return array;\n    }\n\n    @NonNull\n    private static String readHeaderLine(@NonNull InputStream in) throws IOException {\n        int c;\n        StringBuilder buffer = new StringBuilder(80);\n        while ((c = in.read()) >= 0) {\n            if (c == '\\n') {\n                break;   // consume and discard the newlines\n            }\n            buffer.append((char) c);\n        }\n        return buffer.toString();\n    }\n\n    private static void readFullyOrThrow(InputStream in, byte[] buffer) throws IOException {\n        int offset = 0;\n        while (offset < buffer.length) {\n            int bytesRead = in.read(buffer, offset, buffer.length - offset);\n            if (bytesRead <= 0) {\n                throw new IOException(\"Couldn't fully read data\");\n            }\n            offset += bytesRead;\n        }\n    }\n\n    /**\n     * Generates {@link SecretKey} instance from given parameters and returns it's checksum.\n     * <p>\n     * Current implementation returns the key in its primary encoding format.\n     *\n     * @param algorithm - key generation algorithm.\n     * @param pwBytes   - password.\n     * @param salt      - salt.\n     * @param rounds    - number of rounds to run in key generation.\n     * @return Hex representation of the generated key, or null if generation failed.\n     */\n    @NonNull\n    public static byte[] makeKeyChecksum(String algorithm, byte[] pwBytes, byte[] salt, int rounds)\n            throws Exception {\n        char[] mkAsChar = new char[pwBytes.length];\n        for (int i = 0; i < pwBytes.length; i++) {\n            mkAsChar[i] = (char) pwBytes[i];\n        }\n\n        Key checksum = buildCharArrayKey(algorithm, mkAsChar, salt, rounds);\n        return checksum.getEncoded();\n    }\n\n    /**\n     * Creates {@link SecretKey} instance from given parameters.\n     *\n     * @param algorithm key generation algorithm.\n     * @param pwArray   password.\n     * @param salt      salt.\n     * @param rounds    number of rounds to run in key generation.\n     * @return {@link SecretKey} instance or null in case of an error.\n     */\n    @NonNull\n    private static SecretKey buildCharArrayKey(String algorithm, char[] pwArray, byte[] salt, int rounds)\n            throws Exception {\n        // FIXME: 18/2/23 May not work for backup file version 1\n        SecretKeyFactory keyFactory = SecretKeyFactory.getInstance(algorithm);\n        KeySpec ks = new PBEKeySpec(pwArray, salt, rounds, PBKDF2_KEY_SIZE);\n        return keyFactory.generateSecret(ks);\n    }\n\n    /**\n     * Creates hex string representation of the byte array.\n     */\n    public static String byteArrayToHex(byte[] data) {\n        return HexEncoding.encodeToString(data, true);\n    }\n\n    /**\n     * Creates byte array from it's hex string representation.\n     */\n    public static byte[] hexToByteArray(String digits) {\n        final int bytes = digits.length() / 2;\n        if (2 * bytes != digits.length()) {\n            throw new IllegalArgumentException(\"Hex string must have an even number of digits\");\n        }\n\n        byte[] result = new byte[bytes];\n        for (int i = 0; i < digits.length(); i += 2) {\n            result[i / 2] = (byte) Integer.parseInt(digits.substring(i, i + 2), 16);\n        }\n        return result;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/backup/adb/BackupCategories.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.backup.adb;\n\nimport androidx.annotation.IntDef;\n\n@IntDef({BackupCategories.CAT_SRC, BackupCategories.CAT_INT_CE, BackupCategories.CAT_INT_DE,\n        BackupCategories.CAT_EXT, BackupCategories.CAT_OBB, BackupCategories.CAT_UNK})\npublic @interface BackupCategories {\n    int CAT_SRC = 0;\n    int CAT_INT_CE = 1;\n    int CAT_INT_DE = 2;\n    int CAT_EXT = 3;\n    int CAT_OBB = 4;\n    int CAT_UNK = 5;\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/backup/adb/Constants.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.backup.adb;\n\nimport android.app.backup.BackupAgent;\nimport android.os.Build;\n\n/**\n * Constants taken from {@code android.app.backup.FullBackup}, {@code com.android.server.backup.BackupManagerService},\n * {@code com.android.server.backup.utils.PasswordUtils}, {@code com.android.server.backup.BackupPasswordManager}\n */\nfinal class Constants {\n    /**\n     * Path containing APK files i.e. /apps/{package}/a\n     */\n    public static final String APK_TREE_TOKEN = \"a\";\n    /**\n     * Path containing OBB files i.e. /apps/{package}/obb\n     */\n    public static final String OBB_TREE_TOKEN = \"obb\";\n    /**\n     * Path containing key-value data. Maximum 5 MB.\n     */\n    public static final String KEY_VALUE_DATA_TOKEN = \"k\";\n\n\n    /**\n     * Path containing internal data from CE context i.e. /apps/{package}/r excluding files, no_backup, cache,\n     * code_cache and shared_prefs directories. This corresponds to /data/user/{userId}/{package}.\n     */\n    public static final String ROOT_TREE_TOKEN = \"r\";\n    /**\n     * Path containing files data from CE context i.e. /apps/{package}/f. This corresponds to /data/user/{userId}/{package}/files.\n     * But this is not always correct. {@link BackupAgent} is capable of fetching the exact location since it runs in\n     * the app's context.\n     */\n    public static final String FILES_TREE_TOKEN = \"f\";\n    /**\n     * Path containing no_backup data from CE context i.e. /apps/{package}/nb. This path is never used as of Android 13.\n     */\n    public static final String NO_BACKUP_TREE_TOKEN = \"nb\";\n    /**\n     * Path containing databases from CE context i.e. /apps/{package}/db. This corresponds to /data/user/{userId}/{package}/databases.\n     * But this is not always correct. {@link BackupAgent} is capable of fetching the exact location since it runs in\n     * the app's context.\n     */\n    public static final String DATABASE_TREE_TOKEN = \"db\";\n    /**\n     * Path containing shared preferences from CE context i.e. /apps/{package}/db. This corresponds to /data/user/{userId}/{package}/shared_prefs.\n     * But this is not always correct. {@link BackupAgent} is capable of fetching the exact location since it runs in\n     * the app's context.\n     */\n    public static final String SHAREDPREFS_TREE_TOKEN = \"sp\";\n    /**\n     * Path containing caches data from CE context i.e. /apps/{package}/c. This path is never used as of Android 13.\n     */\n    public static final String CACHE_TREE_TOKEN = \"c\";\n\n    /**\n     * Same as {@link #ROOT_TREE_TOKEN} but for DE context.\n     */\n    public static final String DEVICE_ROOT_TREE_TOKEN = \"d_r\";\n    /**\n     * Same as {@link #FILES_TREE_TOKEN} but for DE context.\n     */\n    public static final String DEVICE_FILES_TREE_TOKEN = \"d_f\";\n    /**\n     * Same as {@link #NO_BACKUP_TREE_TOKEN} but for DE context. This path is never used as of Android 13.\n     */\n    public static final String DEVICE_NO_BACKUP_TREE_TOKEN = \"d_nb\";\n    /**\n     * Same as {@link #DATABASE_TREE_TOKEN} but for DE context.\n     */\n    public static final String DEVICE_DATABASE_TREE_TOKEN = \"d_db\";\n    /**\n     * Same as {@link #SHAREDPREFS_TREE_TOKEN} but for DE context.\n     */\n    public static final String DEVICE_SHAREDPREFS_TREE_TOKEN = \"d_sp\";\n    /**\n     * Same as {@link #CACHE_TREE_TOKEN} but for DE context. This path is never used as of Android 13.\n     */\n    public static final String DEVICE_CACHE_TREE_TOKEN = \"d_c\";\n\n    /**\n     * Files containing in the external storage directory returned by {@link android.content.Context#getExternalFilesDir(String)}.\n     * {@link BackupAgent} is capable of fetching this directory as it runs in the app's context. Location is /apps/{package}/ef.\n     */\n    public static final String MANAGED_EXTERNAL_TREE_TOKEN = \"ef\";\n    /**\n     * Path containing files from the external storages. This path is never used as of Android 13.\n     */\n    public static final String SHARED_STORAGE_TOKEN = \"shared\";\n\n    /**\n     * All apps are stored inside this directory in the backup file. The immediate children are the package names.\n     */\n    public static final String APPS_PREFIX = \"apps/\";\n    /**\n     * Shared storages are stored in this directory in the backup file. The immediate children are the volume names.\n     * This is never really used as of Android 13.\n     */\n    public static final String SHARED_PREFIX = SHARED_STORAGE_TOKEN + \"/\";\n\n    // Name and current contents version of the full-backup manifest file\n    //\n    // Manifest version history:\n    //\n    // 1 : initial release\n    public static final String BACKUP_MANIFEST_FILENAME = \"_manifest\";\n    public static final int BACKUP_MANIFEST_VERSION = 1;\n\n    // External archive format version history:\n    //\n    // 1 : initial release (4+)\n    // 2 : no format change per se; version bump to facilitate PBKDF2 version skew detection (unused)\n    // 3 : introduced \"_meta\" metadata file; no other format change per se (5+)\n    // 4 : added support for new device-encrypted storage locations (7+)\n    // 5 : added support for key-value packages (8+)\n    public static final int BACKUP_FILE_VERSION = 5;\n    public static final String BACKUP_FILE_HEADER_MAGIC = \"ANDROID BACKUP\\n\";\n    public static final String BACKUP_METADATA_FILENAME = \"_meta\";\n    public static final int BACKUP_METADATA_VERSION = 1;\n    public static final int BACKUP_WIDGET_METADATA_TOKEN = 0x01FFED01;\n\n    // Configuration of PBKDF2 that we use for generating pw hashes and intermediate keys\n    public static final int PBKDF2_HASH_ROUNDS = 10000;\n    public static final int PBKDF2_KEY_SIZE = 256;     // bits\n    public static final int PBKDF2_SALT_SIZE = 512;    // bits\n    public static final String ENCRYPTION_ALGORITHM_NAME = \"AES-256\";\n\n    public static final String PBKDF_CURRENT = \"PBKDF2WithHmacSHA1\";\n    public static final String PBKDF_FALLBACK = \"PBKDF2WithHmacSHA1And8bit\";\n\n    private Constants() {\n    }\n\n    public static int getBackupFileVersionFromApi(int api) {\n        if (api <= 0) {\n            api = Build.VERSION.SDK_INT;\n        }\n        if (api >= Build.VERSION_CODES.O) {\n            return BACKUP_FILE_VERSION;\n        }\n        if (api >= Build.VERSION_CODES.N) {\n            return 4;\n        }\n        if (api >= Build.VERSION_CODES.LOLLIPOP) {\n            return 3;\n        }\n        if (api >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {\n            return 1;\n        }\n        throw new IllegalArgumentException(\"Invalid/unsupported api \" + api);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/backup/convert/ConvertUtils.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.backup.convert;\n\nimport android.annotation.SuppressLint;\nimport android.os.Build;\n\nimport androidx.annotation.NonNull;\n\nimport com.android.apksig.ApkVerifier;\nimport com.android.apksig.apk.ApkFormatException;\nimport com.android.apksig.util.DataSource;\nimport com.android.apksig.util.DataSources;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.RandomAccessFile;\nimport java.nio.channels.FileChannel;\nimport java.security.NoSuchAlgorithmException;\nimport java.security.cert.CertificateEncodingException;\nimport java.security.cert.X509Certificate;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport io.github.muntashirakon.AppManager.backup.BackupCryptSetupHelper;\nimport io.github.muntashirakon.AppManager.backup.BackupItems;\nimport io.github.muntashirakon.AppManager.backup.CryptoUtils;\nimport io.github.muntashirakon.AppManager.backup.MetadataManager;\nimport io.github.muntashirakon.AppManager.backup.struct.BackupMetadataV2;\nimport io.github.muntashirakon.AppManager.backup.struct.BackupMetadataV5;\nimport io.github.muntashirakon.AppManager.crypto.Crypto;\nimport io.github.muntashirakon.AppManager.crypto.CryptoException;\nimport io.github.muntashirakon.AppManager.crypto.DummyCrypto;\nimport io.github.muntashirakon.AppManager.logs.Log;\nimport io.github.muntashirakon.AppManager.self.filecache.FileCache;\nimport io.github.muntashirakon.AppManager.settings.Prefs;\nimport io.github.muntashirakon.AppManager.utils.DigestUtils;\nimport io.github.muntashirakon.io.FileSystemManager;\nimport io.github.muntashirakon.io.Path;\n\npublic final class ConvertUtils {\n    public static final String TAG = ConvertUtils.class.getSimpleName();\n\n    @NonNull\n    public static BackupMetadataV5 getV5Metadata(@NonNull BackupMetadataV2 metadataV2,\n                                                 @NonNull BackupItems.BackupItem backupItem)\n            throws CryptoException {\n        // Here we don't care about the crypto we had for metdataV2, because the crypto that the\n        // imported backups use may be different from the one configured for this app\n        String compressionMethod = Prefs.BackupRestore.getCompressionMethod();\n        String crypto = CryptoUtils.getMode();\n        BackupCryptSetupHelper cryptoHelper = new BackupCryptSetupHelper(crypto, MetadataManager.getCurrentBackupMetaVersion());\n        BackupMetadataV5.Info info = new BackupMetadataV5.Info(metadataV2.backupTime,\n                metadataV2.flags, metadataV2.userId, compressionMethod, DigestUtils.SHA_256, crypto,\n                cryptoHelper.getIv(), cryptoHelper.getAes(), cryptoHelper.getKeyIds());\n        info.setBackupItem(backupItem);\n        BackupMetadataV5.Metadata metadata = new BackupMetadataV5.Metadata(backupItem.getBackupName());\n        metadata.hasRules = metadataV2.hasRules;\n        metadata.label = metadataV2.label;\n        metadata.packageName = metadataV2.packageName;\n        metadata.versionName = metadataV2.versionName;\n        metadata.versionCode = metadataV2.versionCode;\n        if (metadataV2.dataDirs != null) {\n            metadata.dataDirs = metadataV2.dataDirs.clone();\n        }\n        metadata.isSystem = metadataV2.isSystem;\n        metadata.isSplitApk = metadataV2.isSplitApk;\n        if (metadataV2.splitConfigs != null) {\n            metadata.splitConfigs = metadataV2.splitConfigs.clone();\n        }\n        metadata.apkName = metadataV2.apkName;\n        metadata.instructionSet = metadataV2.instructionSet;\n        metadata.keyStore = metadataV2.keyStore;\n        metadata.installer = metadataV2.installer;\n        return new BackupMetadataV5(info, metadata);\n    }\n\n    @NonNull\n    public static Path[] decryptSourceFiles(@NonNull Path[] files,\n                                            @NonNull Crypto crypto,\n                                            @NonNull String cryptoMode,\n                                            @NonNull BackupItems.BackupItem backupItem)\n            throws IOException {\n        if (crypto instanceof DummyCrypto) {\n            return files;\n        }\n        List<Path> newFileList = new ArrayList<>();\n        // Get desired extension\n        String ext = CryptoUtils.getExtension(cryptoMode);\n        // Create necessary files (1-1 correspondence)\n        for (Path inputFile : files) {\n            Path parent = backupItem.requireUnencryptedBackupPath();\n            String filename = inputFile.getName();\n            String outputFilename = filename.substring(0, filename.lastIndexOf(ext));\n            Path outputPath = parent.createNewFile(outputFilename, null);\n            newFileList.add(outputPath);\n            Log.i(TAG, \"Input: %s\\nOutput: %s\", inputFile, outputPath);\n        }\n        Path[] newFiles = newFileList.toArray(new Path[0]);\n        // Perform actual decryption\n        crypto.decrypt(files, newFiles);\n        return newFiles;\n    }\n\n    @NonNull\n    public static Converter getConversionUtil(@ImportType int backupType, Path file) {\n        switch (backupType) {\n            case ImportType.OAndBackup:\n                return new OABConverter(file);\n            case ImportType.TitaniumBackup:\n                return new TBConverter(file);\n            case ImportType.SwiftBackup:\n                return new SBConverter(file);\n            default:\n                throw new IllegalArgumentException(\"Unsupported import type \" + backupType);\n        }\n    }\n\n    @NonNull\n    public static Path[] getRelevantImportFiles(@NonNull Path baseLocation, @ImportType int backupType) {\n        switch (backupType) {\n            case ImportType.OAndBackup:\n                // Package directories\n                return baseLocation.listFiles(Path::isDirectory);\n            case ImportType.TitaniumBackup:\n                // Properties files\n                return baseLocation.listFiles((dir, name) -> name.endsWith(\".properties\"));\n            case ImportType.SwiftBackup:\n                // XML files\n                return baseLocation.listFiles((dir, name) -> name.endsWith(\".xml\"));\n            default:\n                throw new IllegalArgumentException(\"Unsupported import type \" + backupType);\n        }\n    }\n\n    @SuppressLint(\"SdCardPath\")\n    @NonNull\n    static String[] getDataDirs(String packageName, int userHandle, boolean hasInternal, boolean hasExternal, boolean hasObb) {\n        List<String> dataDirs = new ArrayList<>(2);\n        if (hasInternal) {\n            dataDirs.add(\"/data/user/\" + userHandle + \"/\" + packageName);\n        }\n        if (hasExternal) {\n            dataDirs.add(\"/storage/emulated/\" + userHandle + \"/Android/data/\" + packageName);\n        }\n        if (hasObb) {\n            dataDirs.add(\"/storage/emulated/\" + userHandle + \"/Android/obb/\" + packageName);\n        }\n        return dataDirs.toArray(new String[0]);\n    }\n\n    @NonNull\n    static String[] getChecksumsFromApk(@NonNull Path apkFile, @DigestUtils.Algorithm String algo)\n            throws IOException, ApkFormatException, NoSuchAlgorithmException, CertificateEncodingException {\n        // Since we can't directly work with ProxyFile, we need to cache it and read the signature\n        FileChannel fileChannel;\n        try {\n            fileChannel = apkFile.openFileChannel(FileSystemManager.MODE_READ_ONLY);\n        } catch (IOException e) {\n            File cachedFile = FileCache.getGlobalFileCache().getCachedFile(apkFile);\n            fileChannel = new RandomAccessFile(cachedFile, \"r\").getChannel();\n        }\n        DataSource dataSource = DataSources.asDataSource(fileChannel);\n        List<String> checksums = new ArrayList<>(1);\n        ApkVerifier verifier = new ApkVerifier.Builder(dataSource)\n                .setMaxCheckedPlatformVersion(Build.VERSION.SDK_INT)\n                .build();\n        ApkVerifier.Result apkVerifierResult = verifier.verify();\n        // Get signer certificates\n        List<X509Certificate> certificates = apkVerifierResult.getSignerCertificates();\n        if (certificates != null && !certificates.isEmpty()) {\n            for (X509Certificate certificate : certificates) {\n                checksums.add(DigestUtils.getHexDigest(algo, certificate.getEncoded()));\n            }\n        }\n        return checksums.toArray(new String[0]);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/backup/convert/Converter.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.backup.convert;\n\nimport io.github.muntashirakon.AppManager.backup.BackupException;\n\npublic abstract class Converter {\n    public abstract void convert() throws BackupException;\n\n    public abstract void cleanup();\n\n    public abstract String getPackageName();\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/backup/convert/ImportType.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.backup.convert;\n\npublic @interface ImportType {\n    int OAndBackup = 0;\n    int TitaniumBackup = 1;\n    int SwiftBackup = 2;\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/backup/convert/OABConverter.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.backup.convert;\n\nimport static io.github.muntashirakon.AppManager.backup.BackupManager.CERT_PREFIX;\nimport static io.github.muntashirakon.AppManager.backup.BackupManager.getExt;\nimport static io.github.muntashirakon.AppManager.utils.TarUtils.DEFAULT_SPLIT_SIZE;\n\nimport android.annotation.UserIdInt;\nimport android.os.UserHandleHidden;\nimport android.text.TextUtils;\n\nimport androidx.annotation.NonNull;\n\nimport org.apache.commons.compress.archivers.tar.TarArchiveEntry;\nimport org.apache.commons.compress.archivers.tar.TarArchiveOutputStream;\nimport org.json.JSONException;\nimport org.json.JSONObject;\n\nimport java.io.BufferedInputStream;\nimport java.io.BufferedOutputStream;\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileNotFoundException;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.OutputStream;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.regex.Pattern;\nimport java.util.zip.ZipEntry;\nimport java.util.zip.ZipInputStream;\n\nimport io.github.muntashirakon.AppManager.backup.BackupException;\nimport io.github.muntashirakon.AppManager.backup.BackupItems;\nimport io.github.muntashirakon.AppManager.backup.BackupFlags;\nimport io.github.muntashirakon.AppManager.backup.BackupUtils;\nimport io.github.muntashirakon.AppManager.backup.CryptoUtils;\nimport io.github.muntashirakon.AppManager.backup.MetadataManager;\nimport io.github.muntashirakon.AppManager.backup.struct.BackupMetadataV2;\nimport io.github.muntashirakon.AppManager.backup.struct.BackupMetadataV5;\nimport io.github.muntashirakon.AppManager.crypto.Crypto;\nimport io.github.muntashirakon.AppManager.crypto.CryptoException;\nimport io.github.muntashirakon.AppManager.self.filecache.FileCache;\nimport io.github.muntashirakon.AppManager.settings.Prefs;\nimport io.github.muntashirakon.AppManager.utils.ArrayUtils;\nimport io.github.muntashirakon.AppManager.utils.ContextUtils;\nimport io.github.muntashirakon.AppManager.utils.DigestUtils;\nimport io.github.muntashirakon.AppManager.utils.ExUtils;\nimport io.github.muntashirakon.AppManager.utils.TarUtils;\nimport io.github.muntashirakon.io.IoUtils;\nimport io.github.muntashirakon.io.Path;\nimport io.github.muntashirakon.io.SplitOutputStream;\n\n/**\n * A documentation about OAndBackup is located at\n * <a href=https://github.com/MuntashirAkon/AppManager/issues/371#issuecomment-818429082>GH#371</a>.\n */\npublic class OABConverter extends Converter {\n    public static final String TAG = OABConverter.class.getSimpleName();\n\n    public static final String PATH_SUFFIX = \"oandbackups\";\n\n    private static final List<String> SPECIAL_BACKUPS = new ArrayList<String>() {\n        {\n            add(\"accounts\");\n            add(\"appwidgets\");\n            add(\"bluetooth\");\n            add(\"data.usage.policy\");\n            add(\"wallpaper\");\n            add(\"wifi.access.points\");\n        }\n    };\n\n    private static final int MODE_UNSET = 0;\n    private static final int MODE_APK = 1;\n    private static final int MODE_DATA = 2;\n    private static final int MODE_BOTH = 3;\n\n    private static final String EXTERNAL_FILES = \"external_files\";\n\n    private final Path mBackupLocation;\n    private final String mPackageName;\n    @UserIdInt\n    private final int mUserId;\n\n    private BackupItems.Checksum mChecksum;\n    private BackupMetadataV2 mSourceMetadata;\n    private String mSourceCryptoMode;\n    private Crypto mSourceCrypto;\n    private BackupMetadataV5 mDestMetadata;\n    private BackupItems.BackupItem mBackupItem;\n\n    /**\n     * @param backupLocation E.g. {@code /sdcard/oandbackups/package.name}\n     */\n    public OABConverter(@NonNull Path backupLocation) {\n        mBackupLocation = backupLocation;\n        // Last path component is the package name\n        mPackageName = backupLocation.getName();\n        mUserId = UserHandleHidden.myUserId();\n    }\n\n    @Override\n    public void convert() throws BackupException {\n        if (SPECIAL_BACKUPS.contains(mPackageName)) {\n            throw new BackupException(\"Cannot convert special backup \" + mPackageName);\n        }\n        // Source metadata\n        mSourceMetadata = readLogFile();\n        // Simulate a backup creation\n        try {\n            mBackupItem = BackupItems.createBackupItemGracefully(mUserId, \"OAndBackup\", mPackageName);\n        } catch (IOException e) {\n            throw new BackupException(\"Could not get backup files.\", e);\n        }\n        boolean backupSuccess = false;\n        try {\n            try {\n                // Destination metadata\n                mDestMetadata = ConvertUtils.getV5Metadata(mSourceMetadata, mBackupItem);\n            } catch (CryptoException e) {\n                throw new BackupException(\"Failed to get crypto \" + mDestMetadata.info.crypto, e);\n            }\n            try {\n                mChecksum = mBackupItem.getChecksum();\n            } catch (IOException e) {\n                throw new BackupException(\"Failed to create checksum file.\", e);\n            }\n            if (mDestMetadata.info.flags.backupApkFiles()) {\n                backupApkFile();\n            }\n            if (mDestMetadata.info.flags.backupData()) {\n                backupData();\n            }\n            // Write modified metadata\n            try {\n                Map<String, String> filenameChecksumMap = MetadataManager.writeMetadata(mDestMetadata, mBackupItem);\n                for (Map.Entry<String, String> filenameChecksumPair : filenameChecksumMap.entrySet()) {\n                    mChecksum.add(filenameChecksumPair.getKey(), filenameChecksumPair.getValue());\n                }\n            } catch (IOException e) {\n                throw new BackupException(\"Failed to write metadata.\", e);\n            }\n            // Store checksum for metadata\n            mChecksum.close();\n            // Encrypt checksum\n            try {\n                mBackupItem.encrypt(new Path[]{mChecksum.getFile()});\n            } catch (IOException e) {\n                throw new BackupException(\"Failed to encrypt checksums.txt\", e);\n            }\n            // Replace current backup\n            try {\n                mBackupItem.commit();\n            } catch (IOException e) {\n                throw new BackupException(\"Could not finalise backup.\", e);\n            }\n            backupSuccess = true;\n        } catch (BackupException e) {\n            throw e;\n        } catch (Throwable th) {\n            throw new BackupException(\"Unknown error occurred.\", th);\n        } finally {\n            mBackupItem.cleanup();\n            if (backupSuccess) {\n                BackupUtils.putBackupToDbAndBroadcast(ContextUtils.getContext(), mDestMetadata);\n            }\n        }\n    }\n\n    @Override\n    public void cleanup() {\n        mSourceCrypto.close();\n        mBackupLocation.delete();\n    }\n\n    @Override\n    public String getPackageName() {\n        return mPackageName;\n    }\n\n    private BackupMetadataV2 readLogFile() throws BackupException {\n        try {\n            BackupMetadataV2 metadataV2 = new BackupMetadataV2();\n            Path logFile = mBackupLocation.findFile(mPackageName + \".log\");\n            String jsonString = logFile.getContentAsString();\n            if (TextUtils.isEmpty(jsonString)) throw new JSONException(\"Empty JSON string.\");\n            JSONObject jsonObject = new JSONObject(jsonString);\n            metadataV2.label = jsonObject.getString(\"label\");\n            metadataV2.packageName = jsonObject.getString(\"packageName\");\n            metadataV2.versionName = jsonObject.getString(\"versionName\");\n            metadataV2.versionCode = jsonObject.getInt(\"versionCode\");\n            metadataV2.isSystem = jsonObject.optBoolean(\"isSystem\");\n            metadataV2.isSplitApk = false;\n            metadataV2.splitConfigs = ArrayUtils.emptyArray(String.class);\n            metadataV2.hasRules = false;\n            metadataV2.backupTime = jsonObject.getLong(\"lastBackupMillis\");\n            metadataV2.crypto = jsonObject.optBoolean(\"isEncrypted\") ? CryptoUtils.MODE_OPEN_PGP : CryptoUtils.MODE_NO_ENCRYPTION;\n            mSourceCryptoMode = metadataV2.crypto;\n            mSourceCrypto = CryptoUtils.setupCrypto(metadataV2);\n            metadataV2.apkName = new File(jsonObject.getString(\"sourceDir\")).getName();\n            // Flags\n            metadataV2.flags = new BackupFlags(BackupFlags.BACKUP_MULTIPLE);\n            int backupMode = jsonObject.optInt(\"backupMode\", MODE_UNSET);\n            if (backupMode == MODE_UNSET) {\n                throw new BackupException(\"Destination doesn't contain any backup.\");\n            }\n            if (backupMode == MODE_APK || backupMode == MODE_BOTH) {\n                if (mBackupLocation.hasFile(CryptoUtils.getAppropriateFilename(metadataV2.apkName,\n                        mSourceCryptoMode))) {\n                    metadataV2.flags.addFlag(BackupFlags.BACKUP_APK_FILES);\n                } else {\n                    throw new BackupException(\"Destination doesn't contain any APK files.\");\n                }\n            }\n            if (backupMode == MODE_DATA || backupMode == MODE_BOTH) {\n                boolean hasBackup = false;\n                if (mBackupLocation.hasFile(CryptoUtils.getAppropriateFilename(mPackageName + \".zip\",\n                        mSourceCryptoMode))) {\n                    metadataV2.flags.addFlag(BackupFlags.BACKUP_INT_DATA);\n                    hasBackup = true;\n                }\n                if (mBackupLocation.hasFile(EXTERNAL_FILES) && mBackupLocation.findFile(EXTERNAL_FILES).hasFile(\n                        CryptoUtils.getAppropriateFilename(mPackageName + \".zip\", mSourceCryptoMode))) {\n                    metadataV2.flags.addFlag(BackupFlags.BACKUP_EXT_DATA);\n                    hasBackup = true;\n                }\n                if (!hasBackup) {\n                    throw new BackupException(\"Destination doesn't contain any data files.\");\n                }\n                metadataV2.flags.addFlag(BackupFlags.BACKUP_CACHE);\n            }\n            metadataV2.userId = UserHandleHidden.myUserId();\n            metadataV2.dataDirs = ConvertUtils.getDataDirs(mPackageName, mUserId, metadataV2.flags\n                    .backupInternalData(), metadataV2.flags.backupExternalData(), false);\n            metadataV2.tarType = Prefs.BackupRestore.getCompressionMethod();\n            metadataV2.keyStore = false;\n            metadataV2.installer = Prefs.Installer.getInstallerPackageName();\n            metadataV2.version = 2;  // Old version is used so that we know that it needs permission fixes\n            return metadataV2;\n        } catch (JSONException | IOException | CryptoException e) {\n            return ExUtils.rethrowAsBackupException(\"Could not parse JSON file.\", e);\n        }\n    }\n\n    private void backupApkFile() throws BackupException {\n        Path[] baseApkFiles;\n        try {\n            baseApkFiles = new Path[]{mBackupLocation.findFile(CryptoUtils.getAppropriateFilename(\n                    mSourceMetadata.apkName, mSourceCryptoMode))};\n        } catch (FileNotFoundException e) {\n            throw new BackupException(\"Could not get base.apk file.\", e);\n        }\n        // Decrypt APK file if needed\n        try {\n            baseApkFiles = ConvertUtils.decryptSourceFiles(baseApkFiles, mSourceCrypto, mSourceCryptoMode, mBackupItem);\n        } catch (IOException e) {\n            throw new BackupException(\"Failed to decrypt \" + Arrays.toString(baseApkFiles), e);\n        }\n        // baseApkFiles should be a singleton array\n        if (baseApkFiles.length != 1) {\n            throw new BackupException(\"Incorrect number of APK files: \" + baseApkFiles.length);\n        }\n        Path baseApkFile = baseApkFiles[0];\n        // Get certificate checksums\n        try {\n            String[] checksums = ConvertUtils.getChecksumsFromApk(baseApkFile, mDestMetadata.info.checksumAlgo);\n            for (int i = 0; i < checksums.length; ++i) {\n                mChecksum.add(CERT_PREFIX + i, checksums[i]);\n            }\n        } catch (Exception ignore) {\n        }\n        // Backup APK file\n        String sourceBackupFilePrefix = BackupUtils.getSourceFilePrefix(getExt(mDestMetadata.info.tarType));\n        Path[] sourceFiles;\n        try {\n            sourceFiles = TarUtils.create(mDestMetadata.info.tarType, baseApkFile, mBackupItem.getUnencryptedBackupPath(), sourceBackupFilePrefix,\n                            /* language=regexp */ new String[]{\".*\\\\.apk\"}, null, null, false)\n                    .toArray(new Path[0]);\n        } catch (Throwable th) {\n            throw new BackupException(\"APK files backup is requested but no APK files have been backed up.\", th);\n        }\n        // Overwrite with the new files\n        try {\n            sourceFiles = mBackupItem.encrypt(sourceFiles);\n        } catch (IOException e) {\n            throw new BackupException(\"Failed to encrypt \" + Arrays.toString(sourceFiles), e);\n        }\n        for (Path file : sourceFiles) {\n            mChecksum.add(file.getName(), DigestUtils.getHexDigest(mDestMetadata.info.checksumAlgo, file));\n        }\n    }\n\n    private void backupData() throws BackupException {\n        List<Path> dataFiles = new ArrayList<>(2);\n        if (mDestMetadata.info.flags.backupInternalData()) {\n            try {\n                dataFiles.add(mBackupLocation.findFile(CryptoUtils.getAppropriateFilename(mPackageName + \".zip\",\n                        mSourceCryptoMode)));\n            } catch (FileNotFoundException e) {\n                throw new BackupException(\"Could not get internal data backup.\", e);\n            }\n        }\n        if (mDestMetadata.info.flags.backupExternalData()) {\n            try {\n                dataFiles.add(mBackupLocation.findFile(EXTERNAL_FILES).findFile(CryptoUtils.getAppropriateFilename(\n                        mPackageName + \".zip\", mSourceCryptoMode)));\n            } catch (FileNotFoundException e) {\n                throw new BackupException(\"Could not get external data backup.\", e);\n            }\n        }\n        String tarType = mDestMetadata.info.tarType;\n        int i = 0;\n        Path[] files;\n        for (Path dataFile : dataFiles) {\n            files = new Path[]{dataFile};\n            // Decrypt APK file if needed\n            try {\n                files = ConvertUtils.decryptSourceFiles(files, mSourceCrypto, mSourceCryptoMode, mBackupItem);\n            } catch (IOException e) {\n                throw new BackupException(\"Failed to decrypt \" + Arrays.toString(files), e);\n            }\n            // baseApkFiles should be a singleton array\n            if (files.length != 1) {\n                throw new BackupException(\"Incorrect number of APK files: \" + files.length);\n            }\n            String dataBackupFilePrefix = BackupUtils.getDataFilePrefix(i++, getExt(tarType));\n            try (ZipInputStream zis = new ZipInputStream(new BufferedInputStream(files[0].openInputStream()));\n                 SplitOutputStream sos = new SplitOutputStream(mBackupItem.getUnencryptedBackupPath(), dataBackupFilePrefix, DEFAULT_SPLIT_SIZE);\n                 BufferedOutputStream bos = new BufferedOutputStream(sos);\n                 OutputStream os = TarUtils.createCompressedStream(bos, tarType)) {\n                try (TarArchiveOutputStream tos = new TarArchiveOutputStream(os)) {\n                    tos.setLongFileMode(TarArchiveOutputStream.LONGFILE_POSIX);\n                    tos.setBigNumberMode(TarArchiveOutputStream.BIGNUMBER_POSIX);\n                    ZipEntry zipEntry;\n                    while ((zipEntry = zis.getNextEntry()) != null) {\n                        File tmpFile = null;\n                        if (!zipEntry.isDirectory()) {\n                            // We need to use a temporary file\n                            tmpFile = FileCache.getGlobalFileCache().createCachedFile(files[0].getExtension());\n                            try (OutputStream fos = new FileOutputStream(tmpFile)) {\n                                IoUtils.copy(zis, fos);\n                            }\n                        }\n                        String fileName = zipEntry.getName().replaceFirst(Pattern.quote(mPackageName + \"/\"), \"\");\n                        if (fileName.isEmpty()) continue;\n                        // New tar entry\n                        TarArchiveEntry tarArchiveEntry = new TarArchiveEntry(fileName);\n                        if (tmpFile != null) {\n                            tarArchiveEntry.setSize(tmpFile.length());\n                        }\n                        tos.putArchiveEntry(tarArchiveEntry);\n                        if (tmpFile != null) {\n                            // Copy from the temporary file\n                            try (FileInputStream fis = new FileInputStream(tmpFile)) {\n                                IoUtils.copy(fis, tos);\n                            } finally {\n                                FileCache.getGlobalFileCache().delete(tmpFile);\n                            }\n                        }\n                        tos.closeArchiveEntry();\n                    }\n                    tos.finish();\n                }\n                // Encrypt backups\n                Path[] newBackupFiles = mBackupItem.encrypt(sos.getFiles().toArray(new Path[0]));\n                for (Path file : newBackupFiles) {\n                    mChecksum.add(file.getName(), DigestUtils.getHexDigest(mDestMetadata.info.checksumAlgo, file));\n                }\n            } catch (IOException e) {\n                throw new BackupException(\"Backup failed for \" + dataFile, e);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/backup/convert/SBConverter.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.backup.convert;\n\nimport static io.github.muntashirakon.AppManager.backup.BackupManager.CERT_PREFIX;\nimport static io.github.muntashirakon.AppManager.backup.BackupManager.getExt;\nimport static io.github.muntashirakon.AppManager.utils.TarUtils.DEFAULT_SPLIT_SIZE;\n\nimport android.annotation.SuppressLint;\nimport android.annotation.UserIdInt;\nimport android.content.pm.ApplicationInfo;\nimport android.content.pm.PackageInfo;\nimport android.content.pm.PackageManager;\nimport android.graphics.Bitmap;\nimport android.os.RemoteException;\nimport android.os.UserHandleHidden;\n\nimport androidx.annotation.NonNull;\nimport androidx.core.content.pm.PackageInfoCompat;\n\nimport org.apache.commons.compress.archivers.tar.TarArchiveEntry;\nimport org.apache.commons.compress.archivers.tar.TarArchiveOutputStream;\n\nimport java.io.BufferedInputStream;\nimport java.io.BufferedOutputStream;\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileNotFoundException;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.regex.Pattern;\nimport java.util.zip.ZipEntry;\nimport java.util.zip.ZipInputStream;\n\nimport io.github.muntashirakon.AppManager.backup.BackupException;\nimport io.github.muntashirakon.AppManager.backup.BackupItems;\nimport io.github.muntashirakon.AppManager.backup.BackupFlags;\nimport io.github.muntashirakon.AppManager.backup.BackupUtils;\nimport io.github.muntashirakon.AppManager.backup.CryptoUtils;\nimport io.github.muntashirakon.AppManager.backup.MetadataManager;\nimport io.github.muntashirakon.AppManager.backup.struct.BackupMetadataV2;\nimport io.github.muntashirakon.AppManager.backup.struct.BackupMetadataV5;\nimport io.github.muntashirakon.AppManager.crypto.CryptoException;\nimport io.github.muntashirakon.AppManager.logs.Log;\nimport io.github.muntashirakon.AppManager.self.filecache.FileCache;\nimport io.github.muntashirakon.AppManager.settings.Prefs;\nimport io.github.muntashirakon.AppManager.utils.ArrayUtils;\nimport io.github.muntashirakon.AppManager.utils.ContextUtils;\nimport io.github.muntashirakon.AppManager.utils.DigestUtils;\nimport io.github.muntashirakon.AppManager.utils.FileUtils;\nimport io.github.muntashirakon.AppManager.utils.TarUtils;\nimport io.github.muntashirakon.AppManager.utils.UIUtils;\nimport io.github.muntashirakon.io.IoUtils;\nimport io.github.muntashirakon.io.Path;\nimport io.github.muntashirakon.io.Paths;\nimport io.github.muntashirakon.io.SplitOutputStream;\n\npublic class SBConverter extends Converter {\n    public static final String TAG = SBConverter.class.getSimpleName();\n\n    private final Path mBackupLocation;\n    @UserIdInt\n    private final int mUserId;\n    private final String mPackageName;\n    private final long mBackupTime;\n    private final PackageManager mPm;\n    private final List<Path> mFilesToBeDeleted = new ArrayList<>();\n\n    private BackupItems.Checksum mChecksum;\n    private BackupMetadataV5 mDestMetadata;\n    private BackupItems.BackupItem mBackupItem;\n    private PackageInfo mPackageInfo;\n    private Path mCachedApk;\n\n    public SBConverter(@NonNull Path xmlFile) {\n        mBackupLocation = xmlFile.getParent();\n        mPackageName = Paths.trimPathExtension(xmlFile.getName());\n        mBackupTime = xmlFile.lastModified();\n        mUserId = UserHandleHidden.myUserId();\n        mPm = ContextUtils.getContext().getPackageManager();\n        mFilesToBeDeleted.add(xmlFile);\n    }\n\n    @Override\n    public String getPackageName() {\n        return mPackageName;\n    }\n\n    @Override\n    public void convert() throws BackupException {\n        // Source metadata\n        BackupMetadataV2 sourceMetadata = generateMetadata();\n        // Simulate a backup creation\n        try {\n            mBackupItem = BackupItems.createBackupItemGracefully(mUserId, \"SB\", mPackageName);\n        } catch (IOException e) {\n            throw new BackupException(\"Could not get backup files.\", e);\n        }\n        boolean backupSuccess = false;\n        try {\n            try {\n                // Destination metadata\n                mDestMetadata = ConvertUtils.getV5Metadata(sourceMetadata, mBackupItem);\n            } catch (CryptoException e) {\n                throw new BackupException(\"Failed to get crypto \" + mDestMetadata.info.crypto, e);\n            }\n            try {\n                mChecksum = mBackupItem.getChecksum();\n            } catch (IOException e) {\n                throw new BackupException(\"Failed to create checksum file.\", e);\n            }\n            // Backup icon\n            backupIcon();\n            if (mDestMetadata.info.flags.backupApkFiles()) {\n                backupApkFile();\n            }\n            if (mDestMetadata.info.flags.backupData()) {\n                backupData();\n            }\n            // Write modified metadata\n            try {\n                Map<String, String> filenameChecksumMap = MetadataManager.writeMetadata(mDestMetadata, mBackupItem);\n                for (Map.Entry<String, String> filenameChecksumPair : filenameChecksumMap.entrySet()) {\n                    mChecksum.add(filenameChecksumPair.getKey(), filenameChecksumPair.getValue());\n                }\n            } catch (IOException e) {\n                throw new BackupException(\"Failed to write metadata.\");\n            }\n            mChecksum.close();\n            // Encrypt checksum\n            try {\n                mBackupItem.encrypt(new Path[]{mChecksum.getFile()});\n            } catch (IOException e) {\n                throw new BackupException(\"Failed to encrypt checksums.txt\");\n            }\n            // Replace current backup\n            try {\n                mBackupItem.commit();\n            } catch (IOException e) {\n                throw new BackupException(\"Could not finalise backup.\", e);\n            }\n            backupSuccess = true;\n        } catch (BackupException e) {\n            throw e;\n        } catch (Throwable th) {\n            throw new BackupException(\"Unknown error occurred.\", th);\n        } finally {\n            mBackupItem.cleanup();\n            mCachedApk.requireParent().delete();\n            if (backupSuccess) {\n                BackupUtils.putBackupToDbAndBroadcast(ContextUtils.getContext(), mDestMetadata);\n            }\n        }\n    }\n\n    @Override\n    public void cleanup() {\n        for (Path file : mFilesToBeDeleted) {\n            file.delete();\n        }\n    }\n\n    private void backupApkFile() throws BackupException {\n        Path sourceDir = mCachedApk.requireParent();\n        // Get certificate checksums\n        try {\n            String[] checksums = ConvertUtils.getChecksumsFromApk(mCachedApk, mDestMetadata.info.checksumAlgo);\n            for (int i = 0; i < checksums.length; ++i) {\n                mChecksum.add(CERT_PREFIX + i, checksums[i]);\n            }\n        } catch (Exception ignore) {\n        }\n        // Backup APK files\n        String[] apkFiles = ArrayUtils.appendElement(String.class, mDestMetadata.metadata.splitConfigs, mDestMetadata.metadata.apkName);\n        String sourceBackupFilePrefix = BackupUtils.getSourceFilePrefix(getExt(mDestMetadata.info.tarType));\n        Path[] sourceFiles;\n        try {\n            // We have to specify APK files because the folder may contain many\n            sourceFiles = TarUtils.create(mDestMetadata.info.tarType, sourceDir, mBackupItem.getUnencryptedBackupPath(), sourceBackupFilePrefix,\n                    apkFiles, null, null, false).toArray(new Path[0]);\n        } catch (Throwable th) {\n            throw new BackupException(\"APK files backup is requested but no APK files have been backed up.\", th);\n        }\n        try {\n            sourceFiles = mBackupItem.encrypt(sourceFiles);\n        } catch (IOException e) {\n            throw new BackupException(\"Failed to encrypt \" + Arrays.toString(sourceFiles));\n        }\n        for (Path file : sourceFiles) {\n            mChecksum.add(file.getName(), DigestUtils.getHexDigest(mDestMetadata.info.checksumAlgo, file));\n        }\n    }\n\n    private void backupData() throws BackupException {\n        List<Path> dataFiles = new ArrayList<>(3);\n        try {\n            if (mDestMetadata.info.flags.backupInternalData()) {\n                dataFiles.add(getIntDataFile());\n            }\n            if (mDestMetadata.info.flags.backupExternalData()) {\n                dataFiles.add(getExtDataFile());\n            }\n            if (mDestMetadata.info.flags.backupMediaObb()) {\n                dataFiles.add(getObbFile());\n            }\n        } catch (FileNotFoundException e) {\n            throw new BackupException(\"Could not get data files\", e);\n        }\n        String tarType = mDestMetadata.info.tarType;\n        int i = 0;\n        for (Path dataFile : dataFiles) {\n            String dataBackupFilePrefix = BackupUtils.getDataFilePrefix(i++, getExt(tarType));\n            try (ZipInputStream zis = new ZipInputStream(new BufferedInputStream(dataFile.openInputStream()));\n                 SplitOutputStream sos = new SplitOutputStream(mBackupItem.getUnencryptedBackupPath(), dataBackupFilePrefix, DEFAULT_SPLIT_SIZE);\n                 BufferedOutputStream bos = new BufferedOutputStream(sos);\n                 OutputStream os = TarUtils.createCompressedStream(bos, tarType)) {\n                // TODO: 31/5/21 Check backup format (each zip file has a comment section which can be parsed as JSON)\n                try (TarArchiveOutputStream tos = new TarArchiveOutputStream(os)) {\n                    tos.setLongFileMode(TarArchiveOutputStream.LONGFILE_POSIX);\n                    tos.setBigNumberMode(TarArchiveOutputStream.BIGNUMBER_POSIX);\n                    ZipEntry zipEntry;\n                    while ((zipEntry = zis.getNextEntry()) != null) {\n                        File tmpFile = null;\n                        if (!zipEntry.isDirectory()) {\n                            // We need to use a temporary file\n                            tmpFile = FileCache.getGlobalFileCache().createCachedFile(dataFile.getExtension());\n                            try (OutputStream fos = new FileOutputStream(tmpFile)) {\n                                IoUtils.copy(zis, fos);\n                            }\n                        }\n                        String fileName = zipEntry.getName().replaceFirst(Pattern.quote(mPackageName + \"/\"), \"\");\n                        if (fileName.isEmpty()) continue;\n                        // New tar entry\n                        TarArchiveEntry tarArchiveEntry = new TarArchiveEntry(fileName);\n                        if (tmpFile != null) {\n                            tarArchiveEntry.setSize(tmpFile.length());\n                        }\n                        tos.putArchiveEntry(tarArchiveEntry);\n                        if (tmpFile != null) {\n                            // Copy from the temporary file\n                            try (FileInputStream fis = new FileInputStream(tmpFile)) {\n                                IoUtils.copy(fis, tos);\n                            } finally {\n                                FileCache.getGlobalFileCache().delete(tmpFile);\n                            }\n                        }\n                        tos.closeArchiveEntry();\n                    }\n                    tos.finish();\n                }\n                // Encrypt backups\n                Path[] newBackupFiles = mBackupItem.encrypt(sos.getFiles().toArray(new Path[0]));\n                for (Path file : newBackupFiles) {\n                    mChecksum.add(file.getName(), DigestUtils.getHexDigest(mDestMetadata.info.checksumAlgo, file));\n                }\n            } catch (IOException e) {\n                throw new BackupException(\"Backup failed for \" + dataFile, e);\n            }\n        }\n    }\n\n    @SuppressLint(\"WrongConstant\")\n    @NonNull\n    private BackupMetadataV2 generateMetadata() throws BackupException {\n        BackupMetadataV2 metadataV2 = new BackupMetadataV2();\n        mCachedApk = FileUtils.getTempPath(mPackageName, \"base.apk\");\n        try (InputStream pis = getApkFile().openInputStream()) {\n            try (OutputStream fos = mCachedApk.openOutputStream()) {\n                IoUtils.copy(pis, fos);\n            }\n            mFilesToBeDeleted.add(getApkFile());\n        } catch (IOException e) {\n            throw new BackupException(\"Could not cache APK file\", e);\n        }\n        String filePath = Objects.requireNonNull(mCachedApk.getFilePath());\n        PackageInfo packageInfo = mPm.getPackageArchiveInfo(filePath, 0);\n        if (packageInfo == null) {\n            throw new BackupException(\"Could not fetch package info\");\n        }\n        mPackageInfo = packageInfo;\n        Objects.requireNonNull(mPackageInfo.applicationInfo);\n        mPackageInfo.applicationInfo.publicSourceDir = filePath;\n        mPackageInfo.applicationInfo.sourceDir = filePath;\n        ApplicationInfo applicationInfo = mPackageInfo.applicationInfo;\n\n        if (!mPackageInfo.packageName.equals(mPackageName)) {\n            throw new BackupException(\"Package name mismatch: Expected=\" + mPackageName + \", Actual=\" + mPackageInfo.packageName);\n        }\n\n        metadataV2.label = applicationInfo.loadLabel(mPm).toString();\n        metadataV2.packageName = mPackageName;\n        metadataV2.versionName = mPackageInfo.versionName;\n        metadataV2.versionCode = PackageInfoCompat.getLongVersionCode(mPackageInfo);\n        metadataV2.isSystem = false;\n        metadataV2.hasRules = false;\n        metadataV2.backupTime = mBackupTime;\n        metadataV2.crypto = CryptoUtils.MODE_NO_ENCRYPTION;\n        metadataV2.apkName = \"base.apk\";\n        // Backup flags\n        BackupFlags flags = new BackupFlags(BackupFlags.BACKUP_APK_FILES);\n        try {\n            mFilesToBeDeleted.add(getObbFile());\n            flags.addFlag(BackupFlags.BACKUP_EXT_OBB_MEDIA);\n        } catch (FileNotFoundException ignore) {\n        }\n        try {\n            mFilesToBeDeleted.add(getIntDataFile());\n            flags.addFlag(BackupFlags.BACKUP_INT_DATA);\n            flags.addFlag(BackupFlags.BACKUP_CACHE);\n        } catch (FileNotFoundException ignore) {\n        }\n        try {\n            mFilesToBeDeleted.add(getExtDataFile());\n            flags.addFlag(BackupFlags.BACKUP_EXT_DATA);\n            flags.addFlag(BackupFlags.BACKUP_CACHE);\n        } catch (FileNotFoundException ignore) {\n        }\n        metadataV2.flags = flags;\n        metadataV2.dataDirs = ConvertUtils.getDataDirs(mPackageName, mUserId, flags.backupInternalData(),\n                flags.backupExternalData(), flags.backupMediaObb());\n        try {\n            mFilesToBeDeleted.add(getSplitFile());\n            metadataV2.isSplitApk = true;\n        } catch (FileNotFoundException e) {\n            metadataV2.isSplitApk = false;\n        }\n        try {\n            metadataV2.splitConfigs = cacheAndGetSplitConfigs();\n        } catch (IOException | RemoteException e) {\n            throw new BackupException(\"Could not cache splits\", e);\n        }\n        metadataV2.userId = mUserId;\n        metadataV2.tarType = Prefs.BackupRestore.getCompressionMethod();\n        metadataV2.keyStore = false;\n        metadataV2.installer = Prefs.Installer.getInstallerPackageName();\n        return metadataV2;\n    }\n\n    @NonNull\n    private Path getApkFile() throws FileNotFoundException {\n        return mBackupLocation.findFile(mPackageName + \".app\");\n    }\n\n    @NonNull\n    private Path getSplitFile() throws FileNotFoundException {\n        return mBackupLocation.findFile(mPackageName + \".splits\");\n    }\n\n    @NonNull\n    private Path getObbFile() throws FileNotFoundException {\n        return mBackupLocation.findFile(mPackageName + \".exp\");\n    }\n\n    @NonNull\n    private Path getIntDataFile() throws FileNotFoundException {\n        return mBackupLocation.findFile(mPackageName + \".dat\");\n    }\n\n    @NonNull\n    private Path getExtDataFile() throws FileNotFoundException {\n        return mBackupLocation.findFile(mPackageName + \".extdat\");\n    }\n\n    private String[] cacheAndGetSplitConfigs() throws IOException, RemoteException {\n        List<String> splits = new ArrayList<>();\n        Path splitFile;\n        try {\n            splitFile = getSplitFile();\n        } catch (FileNotFoundException e) {\n            return ArrayUtils.emptyArray(String.class);\n        }\n        try (BufferedInputStream bis = new BufferedInputStream(splitFile.openInputStream());\n             ZipInputStream zis = new ZipInputStream(bis)) {\n            ZipEntry zipEntry;\n            while ((zipEntry = zis.getNextEntry()) != null) {\n                if (zipEntry.isDirectory()) continue;\n                String splitName = FileUtils.getFilenameFromZipEntry(zipEntry);\n                splits.add(splitName);\n                Path file = mCachedApk.requireParent().findOrCreateFile(splitName, null);\n                try (OutputStream fos = file.openOutputStream()) {\n                    IoUtils.copy(zis, fos);\n                } catch (IOException e) {\n                    file.delete();\n                    throw e;\n                }\n            }\n        }\n        return splits.toArray(new String[0]);\n    }\n\n    private void backupIcon() {\n        try {\n            Path iconFile = mBackupItem.getIconFile();\n            try (OutputStream outputStream = iconFile.openOutputStream()) {\n                Bitmap bitmap = UIUtils.getBitmapFromDrawable(mPackageInfo.applicationInfo.loadIcon(mPm));\n                bitmap.compress(Bitmap.CompressFormat.PNG, 100, outputStream);\n                outputStream.flush();\n            }\n        } catch (Throwable th) {\n            Log.w(TAG, \"Could not back up icon.\", th);\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/backup/convert/TBConverter.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.backup.convert;\n\nimport static io.github.muntashirakon.AppManager.backup.BackupManager.CERT_PREFIX;\nimport static io.github.muntashirakon.AppManager.backup.BackupManager.getExt;\nimport static io.github.muntashirakon.AppManager.utils.TarUtils.DEFAULT_SPLIT_SIZE;\nimport static io.github.muntashirakon.AppManager.utils.TarUtils.TAR_BZIP2;\nimport static io.github.muntashirakon.AppManager.utils.TarUtils.TAR_GZIP;\nimport static io.github.muntashirakon.AppManager.utils.TarUtils.TAR_ZSTD;\n\nimport android.annotation.UserIdInt;\nimport android.graphics.Bitmap;\nimport android.graphics.BitmapFactory;\nimport android.os.UserHandleHidden;\nimport android.util.Base64;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport org.apache.commons.compress.archivers.tar.TarArchiveEntry;\nimport org.apache.commons.compress.archivers.tar.TarArchiveInputStream;\nimport org.apache.commons.compress.archivers.tar.TarArchiveOutputStream;\nimport org.apache.commons.compress.compressors.CompressorInputStream;\nimport org.apache.commons.compress.compressors.bzip2.BZip2CompressorInputStream;\nimport org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream;\n\nimport java.io.BufferedInputStream;\nimport java.io.BufferedOutputStream;\nimport java.io.FileNotFoundException;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Properties;\nimport java.util.regex.Pattern;\n\nimport io.github.muntashirakon.AppManager.backup.BackupException;\nimport io.github.muntashirakon.AppManager.backup.BackupItems;\nimport io.github.muntashirakon.AppManager.backup.BackupFlags;\nimport io.github.muntashirakon.AppManager.backup.BackupUtils;\nimport io.github.muntashirakon.AppManager.backup.CryptoUtils;\nimport io.github.muntashirakon.AppManager.backup.MetadataManager;\nimport io.github.muntashirakon.AppManager.backup.struct.BackupMetadataV2;\nimport io.github.muntashirakon.AppManager.backup.struct.BackupMetadataV5;\nimport io.github.muntashirakon.AppManager.crypto.CryptoException;\nimport io.github.muntashirakon.AppManager.logs.Log;\nimport io.github.muntashirakon.AppManager.settings.Prefs;\nimport io.github.muntashirakon.AppManager.utils.ArrayUtils;\nimport io.github.muntashirakon.AppManager.utils.ContextUtils;\nimport io.github.muntashirakon.AppManager.utils.DigestUtils;\nimport io.github.muntashirakon.AppManager.utils.FileUtils;\nimport io.github.muntashirakon.AppManager.utils.TarUtils;\nimport io.github.muntashirakon.io.IoUtils;\nimport io.github.muntashirakon.io.Path;\nimport io.github.muntashirakon.io.Paths;\nimport io.github.muntashirakon.io.SplitOutputStream;\n\npublic class TBConverter extends Converter {\n    public static final String TAG = TBConverter.class.getSimpleName();\n\n    public static final String PATH_SUFFIX = \"TitaniumBackup\";\n\n    private static final String INTERNAL_PREFIX = \"data/data/\";\n    private static final String EXTERNAL_PREFIX = \"data/data/.external.\";\n\n    private final Path mBackupLocation;\n    @UserIdInt\n    private final int mUserId;\n    private final Path mPropFile;\n    private final String mPackageName;\n    private final long mBackupTime;\n    private final List<Path> mFilesToBeDeleted = new ArrayList<>();\n\n    private BackupItems.Checksum mChecksum;\n    private BackupMetadataV2 mSourceMetadata;\n    private BackupMetadataV5 mDestMetadata;\n    private BackupItems.BackupItem mBackupItem;\n    @Nullable\n    private Bitmap mIcon;\n\n    /**\n     * A documentation about Titanium Backup is located at\n     * <a href=https://github.com/MuntashirAkon/AppManager/issues/371#issuecomment-818491126>GH#371</a>.\n     *\n     * @param propFile Location to the properties file e.g. {@code /sdcard/TitaniumBackup/package.name-YYYYMMDD-HHMMSS.properties}\n     */\n    public TBConverter(@NonNull Path propFile) {\n        mPropFile = propFile;\n        mBackupLocation = propFile.getParent();\n        mUserId = UserHandleHidden.myUserId();\n        String dirtyName = propFile.getName();\n        int idx = dirtyName.indexOf('-');\n        if (idx == -1) mPackageName = null;\n        else mPackageName = dirtyName.substring(0, idx);\n        mBackupTime = propFile.lastModified();  // TODO: Grab from the file name\n        mFilesToBeDeleted.add(propFile);\n    }\n\n    @Override\n    public void convert() throws BackupException {\n        if (mPackageName == null) {\n            throw new BackupException(\"Could not read package name.\");\n        }\n        // Source metadata\n        mSourceMetadata = readPropFile();\n        // Simulate a backup creation\n        try {\n            mBackupItem = BackupItems.createBackupItemGracefully(mUserId, \"TB\", mPackageName);\n        } catch (IOException e) {\n            throw new BackupException(\"Could not get backup files\", e);\n        }\n        boolean backupSuccess = false;\n        try {\n            try {\n                // Destination metadata\n                mDestMetadata = ConvertUtils.getV5Metadata(mSourceMetadata, mBackupItem);\n                // Destination APK will be renamed\n                mDestMetadata.metadata.apkName = \"base.apk\";\n            } catch (CryptoException e) {\n                throw new BackupException(\"Failed to get crypto \" + mDestMetadata.info.crypto, e);\n            }\n            try {\n                mChecksum = mBackupItem.getChecksum();\n            } catch (IOException e) {\n                throw new BackupException(\"Failed to create checksum file.\", e);\n            }\n            // Backup icon\n            backupIcon();\n            if (mDestMetadata.info.flags.backupApkFiles()) {\n                backupApkFile();\n            }\n            if (mDestMetadata.info.flags.backupData()) {\n                backupData();\n            }\n            // Write modified metadata\n            try {\n                Map<String, String> filenameChecksumMap = MetadataManager.writeMetadata(mDestMetadata, mBackupItem);\n                for (Map.Entry<String, String> filenameChecksumPair : filenameChecksumMap.entrySet()) {\n                    mChecksum.add(filenameChecksumPair.getKey(), filenameChecksumPair.getValue());\n                }\n            } catch (IOException e) {\n                throw new BackupException(\"Failed to write metadata.\", e);\n            }\n            mChecksum.close();\n            // Encrypt checksum\n            try {\n                mBackupItem.encrypt(new Path[]{mChecksum.getFile()});\n            } catch (IOException e) {\n                throw new BackupException(\"Failed to encrypt checksums.txt\");\n            }\n            // Replace current backup:\n            // There's hardly any chance of getting a false here but checks are done anyway.\n            try {\n                mBackupItem.commit();\n            } catch (Exception e) {\n                throw new BackupException(\"Could not finalise backup.\", e);\n            }\n            backupSuccess = true;\n        } catch (BackupException e) {\n            throw e;\n        } catch (Throwable th) {\n            throw new BackupException(\"Unknown error occurred.\", th);\n        } finally {\n            mBackupItem.cleanup();\n            if (backupSuccess) {\n                BackupUtils.putBackupToDbAndBroadcast(ContextUtils.getContext(), mDestMetadata);\n            }\n        }\n    }\n\n    @Override\n    public String getPackageName() {\n        return mPackageName;\n    }\n\n    @Override\n    public void cleanup() {\n        for (Path file : mFilesToBeDeleted) {\n            file.delete();\n        }\n    }\n\n    private void backupApkFile() throws BackupException {\n        // Decompress APK file\n        Path baseApkFile = FileUtils.getTempPath(mPackageName, mDestMetadata.metadata.apkName);\n        try (InputStream pis = getApkFile(mSourceMetadata.apkName, mSourceMetadata.tarType).openInputStream();\n             BufferedInputStream bis = new BufferedInputStream(pis)) {\n            CompressorInputStream is;\n            if (TAR_GZIP.equals(mSourceMetadata.tarType)) {\n                is = new GzipCompressorInputStream(bis, true);\n            } else if (TAR_BZIP2.equals(mSourceMetadata.tarType)) {\n                is = new BZip2CompressorInputStream(bis, true);\n            } else {\n                baseApkFile.requireParent().delete();\n                throw new BackupException(\"Invalid source compression type: \" + mSourceMetadata.tarType);\n            }\n            try (OutputStream fos = baseApkFile.openOutputStream()) {\n                // The whole file is the APK\n                IoUtils.copy(is, fos);\n            } finally {\n                is.close();\n            }\n        } catch (IOException e) {\n            baseApkFile.requireParent().delete();\n            throw new BackupException(\"Couldn't decompress \" + mSourceMetadata.apkName, e);\n        }\n        // Get certificate checksums\n        try {\n            String[] checksums = ConvertUtils.getChecksumsFromApk(baseApkFile, mDestMetadata.info.checksumAlgo);\n            for (int i = 0; i < checksums.length; ++i) {\n                mChecksum.add(CERT_PREFIX + i, checksums[i]);\n            }\n        } catch (Exception ignore) {\n        }\n        // Backup APK file\n        String sourceBackupFilePrefix = BackupUtils.getSourceFilePrefix(getExt(mDestMetadata.info.tarType));\n        Path[] sourceFiles;\n        try {\n            sourceFiles = TarUtils.create(mDestMetadata.info.tarType, baseApkFile, mBackupItem.getUnencryptedBackupPath(), sourceBackupFilePrefix,\n                            /* language=regexp */new String[]{\".*\\\\.apk\"}, null, null, false)\n                    .toArray(new Path[0]);\n        } catch (Throwable th) {\n            throw new BackupException(\"APK files backup is requested but no APK files have been backed up.\", th);\n        } finally {\n            baseApkFile.requireParent().delete();\n        }\n        // Overwrite with the new files\n        try {\n            sourceFiles = mBackupItem.encrypt(sourceFiles);\n        } catch (IOException e) {\n            throw new BackupException(\"Failed to encrypt \" + Arrays.toString(sourceFiles));\n        }\n        for (Path file : sourceFiles) {\n            mChecksum.add(file.getName(), DigestUtils.getHexDigest(mDestMetadata.info.checksumAlgo, file));\n        }\n    }\n\n    private void backupData() throws BackupException {\n        Path dataFile;\n        try {\n            dataFile = getDataFile(Paths.trimPathExtension(mPropFile.getName()), mSourceMetadata.tarType);\n        } catch (FileNotFoundException e) {\n            throw new BackupException(\"Could not get data file\", e);\n        }\n        String tarType = mDestMetadata.info.tarType;\n        int i = 0;\n        String intBackupFilePrefix = null;\n        String extBackupFilePrefix = null;\n        if (mDestMetadata.info.flags.backupInternalData()) {\n            intBackupFilePrefix = BackupUtils.getDataFilePrefix(i++, getExt(tarType));\n        }\n        if (mDestMetadata.info.flags.backupExternalData()) {\n            extBackupFilePrefix = BackupUtils.getDataFilePrefix(i, getExt(tarType));\n        }\n        try (BufferedInputStream bis = new BufferedInputStream(dataFile.openInputStream())) {\n            CompressorInputStream cis;\n            if (TAR_GZIP.equals(mSourceMetadata.tarType)) {\n                cis = new GzipCompressorInputStream(bis);\n            } else if (TAR_BZIP2.equals(mSourceMetadata.tarType)) {\n                cis = new BZip2CompressorInputStream(bis);\n            } else {\n                throw new BackupException(\"Invalid compression type: \" + tarType);\n            }\n            TarArchiveInputStream tis = new TarArchiveInputStream(cis);\n            SplitOutputStream intSos = null, extSos = null;\n            TarArchiveOutputStream intTos = null, extTos = null;\n            if (intBackupFilePrefix != null) {\n                intSos = new SplitOutputStream(mBackupItem.getUnencryptedBackupPath(), intBackupFilePrefix, DEFAULT_SPLIT_SIZE);\n                BufferedOutputStream bos = new BufferedOutputStream(intSos);\n                OutputStream cos = TarUtils.createCompressedStream(bos, tarType);\n                intTos = new TarArchiveOutputStream(cos);\n                intTos.setLongFileMode(TarArchiveOutputStream.LONGFILE_POSIX);\n                intTos.setBigNumberMode(TarArchiveOutputStream.BIGNUMBER_POSIX);\n            }\n            if (extBackupFilePrefix != null) {\n                extSos = new SplitOutputStream(mBackupItem.getUnencryptedBackupPath(), extBackupFilePrefix, DEFAULT_SPLIT_SIZE);\n                BufferedOutputStream bos = new BufferedOutputStream(extSos);\n                OutputStream cos = TarUtils.createCompressedStream(bos, tarType);\n                extTos = new TarArchiveOutputStream(cos);\n                extTos.setLongFileMode(TarArchiveOutputStream.LONGFILE_POSIX);\n                extTos.setBigNumberMode(TarArchiveOutputStream.BIGNUMBER_POSIX);\n            }\n\n            // Add files\n            TarArchiveEntry inTarEntry;\n            while ((inTarEntry = tis.getNextEntry()) != null) {\n                String fileName = inTarEntry.getName();\n                boolean isExternal = fileName.startsWith(EXTERNAL_PREFIX);\n                // Get new file name\n                fileName = fileName.replaceFirst((isExternal ? EXTERNAL_PREFIX : INTERNAL_PREFIX) + Pattern.quote(mPackageName + \"/\") + \"\\\\./\", \"\");\n                if (fileName.isEmpty()) continue;\n                // New tar entry\n                TarArchiveEntry outTarEntry = new TarArchiveEntry(fileName);\n                outTarEntry.setMode(inTarEntry.getMode());\n                outTarEntry.setUserId(inTarEntry.getUserId());\n                outTarEntry.setGroupId(inTarEntry.getGroupId());\n                outTarEntry.setSize(inTarEntry.getSize());\n                if (isExternal) {\n                    if (extTos != null) {\n                        extTos.putArchiveEntry(outTarEntry);\n                    }\n                } else {\n                    if (intTos != null) {\n                        intTos.putArchiveEntry(outTarEntry);\n                    }\n                }\n                if (!inTarEntry.isDirectory() && !inTarEntry.isSymbolicLink()) {\n                    if (isExternal) {\n                        if (extTos != null) {\n                            IoUtils.copy(tis, extTos);\n                        }\n                    } else {\n                        if (intTos != null) {\n                            IoUtils.copy(tis, intTos);\n                        }\n                    }\n                }\n                if (isExternal) {\n                    if (extTos != null) {\n                        extTos.closeArchiveEntry();\n                    }\n                } else {\n                    if (intTos != null) {\n                        intTos.closeArchiveEntry();\n                    }\n                }\n            }\n            // Archiving finished\n            try {\n                tis.close();\n            } catch (Exception ignore) {\n            }\n            if (intTos != null) {\n                intTos.finish();\n                try {\n                    intTos.close();\n                } catch (Exception ignore) {\n                }\n            }\n            if (extTos != null) {\n                extTos.finish();\n                try {\n                    extTos.close();\n                } catch (Exception ignore) {\n                }\n            }\n\n            // Encrypt created backups and generate checksum\n            if (intSos != null) {\n                // Encrypt backups\n                Path[] newBackupFiles = mBackupItem.encrypt(intSos.getFiles().toArray(new Path[0]));\n                for (Path file : newBackupFiles) {\n                    mChecksum.add(file.getName(), DigestUtils.getHexDigest(mDestMetadata.info.checksumAlgo, file));\n                }\n            }\n            if (extSos != null) {\n                // Encrypt backups\n                Path[] newBackupFiles = mBackupItem.encrypt(extSos.getFiles().toArray(new Path[0]));\n                for (Path file : newBackupFiles) {\n                    mChecksum.add(file.getName(), DigestUtils.getHexDigest(mDestMetadata.info.checksumAlgo, file));\n                }\n            }\n        } catch (IOException e) {\n            throw new BackupException(\"Could not backup data\", e);\n        }\n    }\n\n    private BackupMetadataV2 readPropFile() throws BackupException {\n        try (InputStream is = mPropFile.openInputStream()) {\n            BackupMetadataV2 metadataV2 = new BackupMetadataV2();\n            Properties prop = new Properties();\n            prop.load(is);\n            metadataV2.label = prop.getProperty(\"app_label\");\n            metadataV2.packageName = mPackageName;\n            metadataV2.versionName = prop.getProperty(\"app_version_name\");\n            metadataV2.versionCode = Integer.parseInt(prop.getProperty(\"app_version_code\"));\n            metadataV2.isSystem = \"1\".equals(prop.getProperty(\"app_is_system\"));\n            metadataV2.isSplitApk = false;\n            metadataV2.splitConfigs = ArrayUtils.emptyArray(String.class);\n            metadataV2.hasRules = false;\n            metadataV2.backupTime = mBackupTime;\n            metadataV2.crypto = CryptoUtils.MODE_NO_ENCRYPTION;  // We only support no encryption mode for TB backups\n            metadataV2.apkName = mPackageName + \"-\" + prop.getProperty(\"app_apk_md5\") + \".apk\";\n            metadataV2.userId = UserHandleHidden.myUserId();\n            // Compression type\n            String compressionType = prop.getProperty(\"app_apk_codec\");\n            if (\"GZIP\".equals(compressionType)) {\n                metadataV2.tarType = TAR_GZIP;\n            } else if (\"BZIP2\".equals(compressionType)) {\n                metadataV2.tarType = TAR_BZIP2;\n            } else throw new BackupException(\"Unsupported compression type: \" + compressionType);\n            // Flags\n            metadataV2.flags = new BackupFlags(BackupFlags.BACKUP_MULTIPLE);\n            try {\n                mFilesToBeDeleted.add(getDataFile(Paths.trimPathExtension(mPropFile.getName()), metadataV2.tarType));\n                // No error = data file exists\n                metadataV2.flags.addFlag(BackupFlags.BACKUP_INT_DATA);\n                if (\"1\".equals(prop.getProperty(\"has_external_data\"))) {\n                    metadataV2.flags.addFlag(BackupFlags.BACKUP_EXT_DATA);\n                }\n                metadataV2.flags.addFlag(BackupFlags.BACKUP_CACHE);\n            } catch (FileNotFoundException ignore) {\n            }\n            try {\n                mFilesToBeDeleted.add(getApkFile(metadataV2.apkName, metadataV2.tarType));\n                // No error = APK file exists\n                metadataV2.flags.addFlag(BackupFlags.BACKUP_APK_FILES);\n            } catch (FileNotFoundException ignore) {\n            }\n            metadataV2.dataDirs = ConvertUtils.getDataDirs(mPackageName, mUserId, metadataV2.flags\n                    .backupInternalData(), metadataV2.flags.backupExternalData(), false);\n            metadataV2.keyStore = false;\n            metadataV2.installer = Prefs.Installer.getInstallerPackageName();\n            String base64Icon = prop.getProperty(\"app_gui_icon\");\n            if (base64Icon != null) {\n                byte[] decodedBytes = Base64.decode(base64Icon, 0);\n                mIcon = BitmapFactory.decodeByteArray(decodedBytes, 0, decodedBytes.length);\n            }\n            return metadataV2;\n        } catch (IOException e) {\n            throw new BackupException(\"Could not read the prop file\", e);\n        }\n    }\n\n    @NonNull\n    private Path getDataFile(String filePrefix, @TarUtils.TarType String tarType) throws FileNotFoundException {\n        String filename = filePrefix + \".tar\";\n        if (TAR_BZIP2.equals(tarType)) filename += \".bz2\";\n        else if (TAR_ZSTD.equals(tarType)) filename += \".zst\";\n        else filename += \".gz\";\n        return mBackupLocation.findFile(filename);\n    }\n\n    @NonNull\n    private Path getApkFile(String apkName, @TarUtils.TarType String tarType) throws FileNotFoundException {\n        if (TAR_BZIP2.equals(tarType)) apkName += \".bz2\";\n        else if (TAR_ZSTD.equals(tarType)) apkName += \".zst\";\n        else apkName += \".gz\";\n        return mBackupLocation.findFile(apkName);\n    }\n\n    private void backupIcon() {\n        if (mIcon == null) return;\n        try {\n            Path iconFile = mBackupItem.getIconFile();\n            try (OutputStream outputStream = iconFile.openOutputStream()) {\n                mIcon.compress(Bitmap.CompressFormat.PNG, 100, outputStream);\n                outputStream.flush();\n            }\n        } catch (IOException e) {\n            Log.w(TAG, \"Could not back up icon.\");\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/backup/dialog/BackupFragment.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.backup.dialog;\n\nimport android.content.Context;\nimport android.os.Bundle;\nimport android.text.SpannableStringBuilder;\nimport android.text.TextUtils;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.fragment.app.Fragment;\nimport androidx.lifecycle.ViewModelProvider;\nimport androidx.recyclerview.widget.LinearLayoutManager;\nimport androidx.recyclerview.widget.RecyclerView;\n\nimport com.google.android.material.dialog.MaterialAlertDialogBuilder;\n\nimport java.util.Set;\n\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.backup.BackupFlags;\nimport io.github.muntashirakon.AppManager.batchops.BatchOpsManager;\nimport io.github.muntashirakon.AppManager.utils.DateUtils;\nimport io.github.muntashirakon.dialog.TextInputDialogBuilder;\nimport io.github.muntashirakon.widget.MaterialAlertView;\n\npublic class BackupFragment extends Fragment {\n    public static final String ARG_ALLOW_CUSTOM_USERS = \"allow_custom\";\n\n    @NonNull\n    public static BackupFragment getInstance(boolean allowCustomUsers) {\n        BackupFragment fragment = new BackupFragment();\n        Bundle args = new Bundle();\n        args.putBoolean(ARG_ALLOW_CUSTOM_USERS, allowCustomUsers);\n        fragment.setArguments(args);\n        return fragment;\n    }\n\n    private BackupRestoreDialogViewModel mViewModel;\n    private Context mContext;\n\n    @Nullable\n    @Override\n    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {\n        return inflater.inflate(R.layout.fragment_dialog_backup, container, false);\n    }\n\n    @Override\n    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {\n        mViewModel = new ViewModelProvider(requireParentFragment()).get(BackupRestoreDialogViewModel.class);\n        mContext = requireContext();\n        boolean allowCustomUsers = requireArguments().getBoolean(ARG_ALLOW_CUSTOM_USERS);\n\n        MaterialAlertView messageView = view.findViewById(R.id.message);\n        RecyclerView recyclerView = view.findViewById(android.R.id.list);\n        recyclerView.setLayoutManager(new LinearLayoutManager(mContext, LinearLayoutManager.VERTICAL, false));\n        int supportedFlags = BackupFlags.getSupportedBackupFlags();\n        // Remove unsupported flags\n        supportedFlags &= ~BackupFlags.BACKUP_NO_SIGNATURE_CHECK;\n        if (!allowCustomUsers) {\n            supportedFlags &= ~BackupFlags.BACKUP_CUSTOM_USERS;\n        }\n        FlagsAdapter adapter = new FlagsAdapter(mContext, BackupFlags.fromPref().getFlags(), supportedFlags);\n        recyclerView.setAdapter(adapter);\n\n        Set<CharSequence> uninstalledApps = mViewModel.getUninstalledApps();\n        if (!uninstalledApps.isEmpty()) {\n            SpannableStringBuilder sb = new SpannableStringBuilder(getString(R.string.backup_apps_cannot_be_backed_up));\n            for (CharSequence appLabel : uninstalledApps) {\n                sb.append(\"\\n● \").append(appLabel);\n            }\n            messageView.setText(sb);\n            messageView.setVisibility(View.VISIBLE);\n        }\n        view.findViewById(R.id.action_backup).setOnClickListener(v -> {\n            BackupFlags newFlags = new BackupFlags(adapter.getSelectedFlags());\n            handleBackup(newFlags);\n        });\n    }\n\n    private void handleBackup(@NonNull BackupFlags flags) {\n        BackupRestoreDialogViewModel.OperationInfo operationInfo = new BackupRestoreDialogViewModel.OperationInfo();\n        operationInfo.mode = BackupRestoreDialogFragment.MODE_BACKUP;\n        operationInfo.flags = flags.getFlags();\n        operationInfo.op = BatchOpsManager.OP_BACKUP;\n        if (flags.backupMultiple()) {\n            // Multiple backup is requested, no need to warn users about backups since the\n            // user has a choice between overwriting the existing backup or create a new one\n            // TODO(18/9/20): Add overwrite option\n            new TextInputDialogBuilder(mContext, R.string.input_backup_name)\n                    .setTitle(R.string.backup)\n                    .setHelperText(R.string.input_backup_name_description)\n                    .setPositiveButton(R.string.ok, (dialog, which, input, isChecked) -> {\n                        String backupName;\n                        if (TextUtils.isEmpty(input)) {\n                            backupName = DateUtils.formatMediumDateTime(mContext, System.currentTimeMillis());\n                        } else {\n                            backupName = input.toString();\n                        }\n                        operationInfo.backupNames = new String[]{backupName};\n                        mViewModel.prepareForOperation(operationInfo);\n                    })\n                    .show();\n        } else {\n            // Base backup requested\n            int baseBackupCount = mViewModel.getBackupInfoList().size() - mViewModel.getAppsWithoutBackups().size();\n            if (baseBackupCount > 0) {\n                // One or more app has backups, warn users\n                new MaterialAlertDialogBuilder(mContext)\n                        .setTitle(R.string.backup)\n                        .setMessage(getResources().getQuantityString(R.plurals.backup_exists_are_you_sure, baseBackupCount))\n                        .setPositiveButton(R.string.yes, (dialog, which) -> mViewModel.prepareForOperation(operationInfo))\n                        .setNegativeButton(R.string.no, null)\n                        .show();\n            } else {\n                // No need to warn users, proceed to back up\n                mViewModel.prepareForOperation(operationInfo);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/backup/dialog/BackupInfo.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.backup.dialog;\n\nimport androidx.annotation.NonNull;\nimport androidx.collection.ArraySet;\n\nimport java.util.Collections;\nimport java.util.List;\n\nimport io.github.muntashirakon.AppManager.backup.struct.BackupMetadataV5;\n\npublic class BackupInfo {\n    @NonNull\n    public final String packageName;\n    @NonNull\n    public final ArraySet<Integer> userIds = new ArraySet<>();\n\n    private CharSequence mAppLabel;\n    @NonNull\n    private List<BackupMetadataV5> mBackupMetadataList = Collections.emptyList();\n    private boolean mInstalled;\n    private boolean mHasBaseBackup;\n\n    BackupInfo(@NonNull String packageName, int userId) {\n        this.packageName = packageName;\n        this.userIds.add(userId);\n        mAppLabel = packageName;\n    }\n\n    @NonNull\n    public CharSequence getAppLabel() {\n        return mAppLabel;\n    }\n\n    public void setAppLabel(@NonNull CharSequence appLabel) {\n        mAppLabel = appLabel;\n    }\n\n    @NonNull\n    public List<BackupMetadataV5> getBackupMetadataList() {\n        return mBackupMetadataList;\n    }\n\n    public void setBackupMetadataList(@NonNull List<BackupMetadataV5> backupMetadataList) {\n        mBackupMetadataList = backupMetadataList;\n    }\n\n    public boolean hasBaseBackup() {\n        return mHasBaseBackup;\n    }\n\n    public void setHasBaseBackup(boolean hasBaseBackup) {\n        mHasBaseBackup = hasBaseBackup;\n    }\n\n    public boolean isInstalled() {\n        return mInstalled;\n    }\n\n    public void setInstalled(boolean installed) {\n        mInstalled = installed;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/backup/dialog/BackupInfoState.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.backup.dialog;\n\nimport androidx.annotation.IntDef;\n\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\n\n@IntDef({\n        BackupInfoState.NONE,\n        BackupInfoState.BACKUP_MULTIPLE,\n        BackupInfoState.RESTORE_MULTIPLE,\n        BackupInfoState.BOTH_MULTIPLE,\n        BackupInfoState.BACKUP_SINGLE,\n        BackupInfoState.RESTORE_SINGLE,\n        BackupInfoState.BOTH_SINGLE,\n})\n@Retention(RetentionPolicy.SOURCE)\npublic @interface BackupInfoState {\n    /**\n     * None of the selected apps have backups nor any of them is installed.\n     */\n    int NONE = 0;\n    /**\n     * None of the selected apps have backups but some of them are installed.\n     */\n    int BACKUP_MULTIPLE = 1;\n    /**\n     * None of the apps are installed but a few have (base) backups.\n     */\n    int RESTORE_MULTIPLE = 2;\n    /**\n     * Some apps are installed and some apps have (base) backups.\n     */\n    int BOTH_MULTIPLE = 3;\n    /**\n     * The app is installed but has no backups\n     */\n    int BACKUP_SINGLE = 4;\n    /**\n     * The apps is uninstalled but has backups\n     */\n    int RESTORE_SINGLE = 5;\n    /**\n     * Some apps are installed and some apps have (base) backups.\n     */\n    int BOTH_SINGLE = 6;\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/backup/dialog/BackupRestoreDialogFragment.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.backup.dialog;\n\nimport android.annotation.UserIdInt;\nimport android.content.BroadcastReceiver;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.IntentFilter;\nimport android.content.res.TypedArray;\nimport android.os.Bundle;\nimport android.os.UserHandleHidden;\nimport android.util.Log;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.FrameLayout;\n\nimport androidx.annotation.IntDef;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.UiThread;\nimport androidx.core.content.ContextCompat;\nimport androidx.fragment.app.Fragment;\nimport androidx.fragment.app.FragmentActivity;\nimport androidx.lifecycle.ViewModelProvider;\nimport androidx.viewpager2.adapter.FragmentStateAdapter;\nimport androidx.viewpager2.widget.ViewPager2;\n\nimport com.google.android.material.dialog.MaterialAlertDialogBuilder;\nimport com.google.android.material.tabs.TabLayout;\nimport com.google.android.material.tabs.TabLayoutMediator;\n\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Objects;\n\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.batchops.BatchOpsManager;\nimport io.github.muntashirakon.AppManager.batchops.BatchOpsService;\nimport io.github.muntashirakon.AppManager.batchops.BatchQueueItem;\nimport io.github.muntashirakon.AppManager.batchops.struct.BatchBackupOptions;\nimport io.github.muntashirakon.AppManager.types.UserPackagePair;\nimport io.github.muntashirakon.AppManager.users.UserInfo;\nimport io.github.muntashirakon.AppManager.utils.ArrayUtils;\nimport io.github.muntashirakon.AppManager.utils.StoragePermission;\nimport io.github.muntashirakon.dialog.BottomSheetBehavior;\nimport io.github.muntashirakon.dialog.CapsuleBottomSheetDialogFragment;\nimport io.github.muntashirakon.dialog.DialogTitleBuilder;\nimport io.github.muntashirakon.dialog.SearchableMultiChoiceDialogBuilder;\n\npublic class BackupRestoreDialogFragment extends CapsuleBottomSheetDialogFragment {\n    public static final String TAG = BackupRestoreDialogFragment.class.getSimpleName();\n\n    private static final String ARG_PACKAGE_PAIRS = \"pkg_pairs\";\n    private static final String ARG_CUSTOM_MODE = \"custom_mode\";\n    private static final String ARG_PREFERRED_USER_FOR_RESTORE = \"pref_user_restore\";\n\n    @NonNull\n    public static BackupRestoreDialogFragment getInstance(@NonNull List<UserPackagePair> userPackagePairs) {\n        BackupRestoreDialogFragment fragment = new BackupRestoreDialogFragment();\n        Bundle args = new Bundle();\n        args.putParcelableArrayList(ARG_PACKAGE_PAIRS, new ArrayList<>(userPackagePairs));\n        fragment.setArguments(args);\n        return fragment;\n    }\n\n    @NonNull\n    public static BackupRestoreDialogFragment getInstanceWithPref(@NonNull List<UserPackagePair> userPackagePairs, @UserIdInt int preferredUserForRestore) {\n        BackupRestoreDialogFragment fragment = new BackupRestoreDialogFragment();\n        Bundle args = new Bundle();\n        args.putParcelableArrayList(ARG_PACKAGE_PAIRS, new ArrayList<>(userPackagePairs));\n        args.putInt(ARG_PREFERRED_USER_FOR_RESTORE, preferredUserForRestore);\n        fragment.setArguments(args);\n        return fragment;\n    }\n\n    @NonNull\n    public static BackupRestoreDialogFragment getInstance(@NonNull List<UserPackagePair> userPackagePairs, @ActionMode int mode) {\n        BackupRestoreDialogFragment fragment = new BackupRestoreDialogFragment();\n        Bundle args = new Bundle();\n        args.putParcelableArrayList(ARG_PACKAGE_PAIRS, new ArrayList<>(userPackagePairs));\n        args.putInt(ARG_CUSTOM_MODE, mode);\n        fragment.setArguments(args);\n        return fragment;\n    }\n\n    @IntDef(flag = true, value = {\n            MODE_BACKUP,\n            MODE_RESTORE,\n            MODE_DELETE\n    })\n    @Retention(RetentionPolicy.SOURCE)\n    public @interface ActionMode {\n    }\n\n    public static final int MODE_BACKUP = 1;\n    public static final int MODE_RESTORE = 1 << 1;\n    public static final int MODE_DELETE = 1 << 2;\n\n    public interface ActionCompleteInterface {\n        void onActionComplete(@ActionMode int mode, @NonNull String[] failedPackages);\n    }\n\n    public interface ActionBeginInterface {\n        void onActionBegin(@ActionMode int mode);\n    }\n\n    @Nullable\n    private ActionCompleteInterface mActionCompleteInterface;\n    @Nullable\n    private ActionBeginInterface mActionBeginInterface;\n    @ActionMode\n    private int mMode = MODE_BACKUP;\n    private FragmentActivity mActivity;\n    private BackupRestoreDialogViewModel mViewModel;\n    private Fragment[] mTabFragments;\n    private TypedArray mTabTitles;\n    private DialogTitleBuilder mDialogTitleBuilder;\n    private int mCustomModes;\n\n    private final StoragePermission mStoragePermission = StoragePermission.init(this);\n    private final BroadcastReceiver mBatchOpsBroadCastReceiver = new BroadcastReceiver() {\n        @Override\n        public void onReceive(Context context, Intent intent) {\n            if (mActionCompleteInterface != null) {\n                ArrayList<String> failedPackages = intent.getStringArrayListExtra(BatchOpsService.EXTRA_FAILED_PKG);\n                mActionCompleteInterface.onActionComplete(mMode, failedPackages != null ? failedPackages.toArray(new String[0]) : new String[0]);\n            }\n            mActivity.unregisterReceiver(mBatchOpsBroadCastReceiver);\n        }\n    };\n\n    public void setOnActionCompleteListener(@NonNull ActionCompleteInterface actionCompleteInterface) {\n        mActionCompleteInterface = actionCompleteInterface;\n    }\n\n    public void setOnActionBeginListener(@NonNull ActionBeginInterface actionBeginInterface) {\n        mActionBeginInterface = actionBeginInterface;\n    }\n\n    @NonNull\n    @Override\n    public View initRootView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {\n        return inflater.inflate(R.layout.dialog_backup_restore, container, false);\n    }\n\n    @Override\n    public boolean displayLoaderByDefault() {\n        return true;\n    }\n\n    @Override\n    public void onAttach(@NonNull Context context) {\n        super.onAttach(context);\n        mActivity = requireActivity();\n        mStoragePermission.request();\n    }\n\n    @Override\n    public void onBodyInitialized(@NonNull View bodyView, @Nullable Bundle savedInstanceState) {\n        mViewModel = new ViewModelProvider(this).get(BackupRestoreDialogViewModel.class);\n        mActivity = requireActivity();\n        Bundle args = requireArguments();\n        List<UserPackagePair> targetPackages = args.getParcelableArrayList(ARG_PACKAGE_PAIRS);\n        mCustomModes = args.getInt(ARG_CUSTOM_MODE, MODE_BACKUP | MODE_RESTORE | MODE_DELETE);\n        int preferredUserForRestore = args.getInt(ARG_PREFERRED_USER_FOR_RESTORE, -1);\n        if (preferredUserForRestore >= 0) {\n            mViewModel.setPreferredUserForRestore(preferredUserForRestore);\n        }\n\n        mDialogTitleBuilder = new DialogTitleBuilder(requireContext())\n                .setTitle(R.string.backup_restore)\n                .setStartIcon(R.drawable.ic_backup_restore);\n        setHeader(mDialogTitleBuilder.build());\n\n        mViewModel.getBackupInfoStateLiveData().observe(this, this::loadBody);\n        mViewModel.getBackupOperationLiveData().observe(this, this::startOperation);\n        mViewModel.getUserSelectionLiveData().observe(this, this::handleCustomUsers);\n        mViewModel.processPackages(targetPackages);\n    }\n\n    private void loadBody(@BackupInfoState int state) {\n        state = getRealState(state);\n        Log.d(TAG, \"Backup dialog state: \" + state);\n        switch (state) {\n            default:\n            case BackupInfoState.NONE:\n                showBackupOptionsUnavailable();\n                break;\n            case BackupInfoState.BACKUP_MULTIPLE:\n                loadMultipleBackupFragment();\n                break;\n            case BackupInfoState.RESTORE_MULTIPLE:\n                loadMultipleRestoreFragment();\n                break;\n            case BackupInfoState.BOTH_MULTIPLE:\n                loadMultipleBackupRestoreViewPager();\n                break;\n            case BackupInfoState.BACKUP_SINGLE:\n                loadSingleBackupFragment();\n                break;\n            case BackupInfoState.RESTORE_SINGLE:\n                loadSingleRestoreFragment();\n                break;\n            case BackupInfoState.BOTH_SINGLE:\n                loadSingleBackupRestoreViewPager();\n                break;\n        }\n    }\n\n    @BackupInfoState\n    private int getRealState(@BackupInfoState int state) {\n        boolean singleMode = state == BackupInfoState.BACKUP_SINGLE || state == BackupInfoState.RESTORE_SINGLE ||\n                state == BackupInfoState.BOTH_SINGLE;\n        switch (state) {\n            default:\n            case BackupInfoState.NONE:\n                return state;\n            case BackupInfoState.BACKUP_MULTIPLE:\n            case BackupInfoState.BACKUP_SINGLE:\n                if ((mCustomModes & MODE_BACKUP) == 0) {\n                    return BackupInfoState.NONE;\n                }\n                break;\n            case BackupInfoState.BOTH_MULTIPLE:\n            case BackupInfoState.BOTH_SINGLE:\n                boolean canBackup = (mCustomModes & MODE_BACKUP) != 0;\n                boolean canRestore = (mCustomModes & MODE_RESTORE) != 0;\n                if (!canBackup && !canRestore) {\n                    return BackupInfoState.NONE;\n                }\n                if (!canRestore) {\n                    return singleMode ? BackupInfoState.BACKUP_SINGLE : BackupInfoState.BACKUP_MULTIPLE;\n                }\n                if (!canBackup) {\n                    return singleMode ? BackupInfoState.RESTORE_SINGLE : BackupInfoState.RESTORE_MULTIPLE;\n                }\n                break;\n            case BackupInfoState.RESTORE_MULTIPLE:\n            case BackupInfoState.RESTORE_SINGLE:\n                if ((mCustomModes & MODE_RESTORE) == 0) {\n                    return BackupInfoState.NONE;\n                }\n                break;\n        }\n        return state;\n    }\n\n    private void showBackupOptionsUnavailable() {\n        getBody().findViewById(R.id.message).setVisibility(View.VISIBLE);\n        getBody().findViewById(R.id.fragment_container_view_tag).setVisibility(View.GONE);\n        finishLoading();\n    }\n\n    public BackupFragment getBackupFragment() {\n        return BackupFragment.getInstance(mViewModel.allowCustomUsersInBackup());\n    }\n\n    private void loadMultipleBackupFragment() {\n        mDialogTitleBuilder.setTitle(R.string.backup);\n        setHeader(mDialogTitleBuilder.build());\n        finishLoading();\n        getChildFragmentManager()\n                .beginTransaction()\n                .replace(R.id.fragment_container_view_tag, getBackupFragment())\n                .commit();\n    }\n\n    private void loadMultipleRestoreFragment() {\n        mDialogTitleBuilder.setTitle(R.string.restore);\n        updateMultipleRestoreHeader();\n        finishLoading();\n        getChildFragmentManager()\n                .beginTransaction()\n                .replace(R.id.fragment_container_view_tag, RestoreMultipleFragment.getInstance())\n                .commit();\n    }\n\n    private void loadMultipleBackupRestoreViewPager() {\n        updateMultipleRestoreHeader();\n\n        mTabTitles = getResources().obtainTypedArray(R.array.backup_restore_tabs_multiple);\n        mTabFragments = new Fragment[mTabTitles.length()];\n        mTabFragments[0] = getBackupFragment();\n        mTabFragments[1] = RestoreMultipleFragment.getInstance();\n        getBody().findViewById(R.id.container).setVisibility(View.VISIBLE);\n        ViewPager2 viewPager = getBody().findViewById(R.id.pager);\n        TabLayout tabLayout = getBody().findViewById(R.id.tab_layout);\n        viewPager.setOffscreenPageLimit(1);\n        viewPager.registerOnPageChangeCallback(new ViewPagerUpdateScrollingChildListener(viewPager, getBehavior()));\n        finishLoading();\n        viewPager.setAdapter(new BackupDialogFragmentPagerAdapter(this));\n        new TabLayoutMediator(tabLayout, viewPager, (tab, position) -> tab.setText(mTabTitles.getString(position)))\n                .attach();\n    }\n\n    public void updateMultipleRestoreHeader() {\n        // Display delete button\n        mDialogTitleBuilder.setEndIcon(R.drawable.ic_trash_can, v -> handleDeleteBaseBackup())\n                .setEndIconContentDescription(R.string.delete_backup);\n        setHeader(mDialogTitleBuilder.build());\n    }\n\n    private void loadSingleBackupFragment() {\n        mDialogTitleBuilder.setTitle(R.string.backup);\n        updateSingleBackupHeader();\n        finishLoading();\n        getChildFragmentManager()\n                .beginTransaction()\n                .replace(R.id.fragment_container_view_tag, getBackupFragment())\n                .commit();\n    }\n\n    private void loadSingleRestoreFragment() {\n        mDialogTitleBuilder.setTitle(R.string.restore_dots);\n        updateSingleBackupHeader();\n        finishLoading();\n        getChildFragmentManager()\n                .beginTransaction()\n                .replace(R.id.fragment_container_view_tag, RestoreSingleFragment.getInstance())\n                .commit();\n    }\n\n    private void loadSingleBackupRestoreViewPager() {\n        updateSingleBackupHeader();\n\n        mTabTitles = getResources().obtainTypedArray(R.array.backup_restore_tabs_single);\n        mTabFragments = new Fragment[mTabTitles.length()];\n        mTabFragments[0] = getBackupFragment();\n        mTabFragments[1] = RestoreSingleFragment.getInstance();\n        getBody().findViewById(R.id.container).setVisibility(View.VISIBLE);\n        ViewPager2 viewPager = getBody().findViewById(R.id.pager);\n        TabLayout tabLayout = getBody().findViewById(R.id.tab_layout);\n        viewPager.setOffscreenPageLimit(1);\n        viewPager.registerOnPageChangeCallback(new ViewPagerUpdateScrollingChildListener(viewPager, getBehavior()));\n        finishLoading();\n        viewPager.setAdapter(new BackupDialogFragmentPagerAdapter(this));\n        new TabLayoutMediator(tabLayout, viewPager, (tab, position) -> tab.setText(mTabTitles.getString(position)))\n                .attach();\n    }\n\n    private void updateSingleBackupHeader() {\n        mDialogTitleBuilder.setSubtitle(mViewModel.getBackupInfo().getAppLabel());\n        setHeader(mDialogTitleBuilder.build());\n    }\n\n    public void handleCustomUsers(@NonNull BackupRestoreDialogViewModel.OperationInfo operationInfo) {\n        // NonNull check is added because we are only here when there are more than one users\n        List<UserInfo> users = Objects.requireNonNull(operationInfo.userInfoList);\n        CharSequence[] userNames = new String[users.size()];\n        List<Integer> userHandles = new ArrayList<>(users.size());\n        int i = 0;\n        for (UserInfo info : users) {\n            userNames[i] = info.toLocalizedString(requireContext());\n            userHandles.add(info.id);\n            ++i;\n        }\n\n        new SearchableMultiChoiceDialogBuilder<>(mActivity, userHandles, userNames)\n                .setTitle(R.string.select_user)\n                .addSelections(Collections.singletonList(UserHandleHidden.myUserId()))\n                .showSelectAll(false)\n                .setPositiveButton(R.string.ok, (dialog, which, selectedUsers) -> {\n                    if (!selectedUsers.isEmpty()) {\n                        operationInfo.selectedUsers = ArrayUtils.convertToIntArray(selectedUsers);\n                    }\n                    mViewModel.prepareForOperation(operationInfo);\n                })\n                .setNegativeButton(R.string.cancel, null)\n                .show();\n    }\n\n    private void handleDeleteBaseBackup() {\n        // TODO: 5/7/22 Clarify the message by including base backup in the message.\n        // TODO: 5/7/22 Display a check box that will include all the backups instead of only base backups.\n        new MaterialAlertDialogBuilder(mActivity)\n                .setTitle(R.string.delete_backup)\n                .setMessage(R.string.are_you_sure)\n                .setPositiveButton(R.string.yes, (dialog, which) -> {\n                    BackupRestoreDialogViewModel.OperationInfo operationInfo = new BackupRestoreDialogViewModel.OperationInfo();\n                    operationInfo.mode = BackupRestoreDialogFragment.MODE_DELETE;\n                    operationInfo.op = BatchOpsManager.OP_DELETE_BACKUP;\n                    mViewModel.prepareForOperation(operationInfo);\n                })\n                .setNegativeButton(R.string.no, null)\n                .show();\n    }\n\n    @UiThread\n    private void startOperation(@NonNull BackupRestoreDialogViewModel.OperationInfo operationInfo) {\n        mMode = operationInfo.mode;\n        if (mActionBeginInterface != null) {\n            mActionBeginInterface.onActionBegin(operationInfo.mode);\n        }\n        ContextCompat.registerReceiver(mActivity, mBatchOpsBroadCastReceiver,\n                new IntentFilter(BatchOpsService.ACTION_BATCH_OPS_COMPLETED), ContextCompat.RECEIVER_NOT_EXPORTED);\n        // Start batch ops service\n        BatchBackupOptions options = new BatchBackupOptions(operationInfo.flags, operationInfo.backupNames, operationInfo.relativeDirs);\n        BatchQueueItem queueItem = BatchQueueItem.getBatchOpQueue(operationInfo.op,\n                operationInfo.packageList, operationInfo.userIdListMappedToPackageList, options);\n        Intent intent = BatchOpsService.getServiceIntent(mActivity, queueItem);\n        ContextCompat.startForegroundService(mActivity, intent);\n        dismiss();\n    }\n\n    private class BackupDialogFragmentPagerAdapter extends FragmentStateAdapter {\n        public BackupDialogFragmentPagerAdapter(@NonNull Fragment fragment) {\n            super(fragment);\n        }\n\n        @NonNull\n        @Override\n        public Fragment createFragment(int position) {\n            return mTabFragments[position];\n        }\n\n        @Override\n        public int getItemCount() {\n            return mTabTitles.length();\n        }\n    }\n\n    private static class ViewPagerUpdateScrollingChildListener extends ViewPager2.OnPageChangeCallback {\n        private final ViewPager2 mViewPager;\n        private final BottomSheetBehavior<FrameLayout> mBehavior;\n\n        private ViewPagerUpdateScrollingChildListener(ViewPager2 viewPager, BottomSheetBehavior<FrameLayout> behavior) {\n            mViewPager = viewPager;\n            mBehavior = behavior;\n        }\n\n        @Override\n        public void onPageSelected(int position) {\n            mViewPager.post(mBehavior::updateScrollingChild);\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/backup/dialog/BackupRestoreDialogViewModel.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.backup.dialog;\n\nimport android.annotation.UserIdInt;\nimport android.app.Application;\nimport android.os.PowerManager;\nimport android.os.UserHandleHidden;\n\nimport androidx.annotation.AnyThread;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.WorkerThread;\nimport androidx.lifecycle.AndroidViewModel;\nimport androidx.lifecycle.LiveData;\nimport androidx.lifecycle.MutableLiveData;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.Set;\nimport java.util.concurrent.Future;\n\nimport io.github.muntashirakon.AppManager.backup.BackupFlags;\nimport io.github.muntashirakon.AppManager.backup.struct.BackupMetadataV5;\nimport io.github.muntashirakon.AppManager.batchops.BatchOpsManager;\nimport io.github.muntashirakon.AppManager.db.entity.App;\nimport io.github.muntashirakon.AppManager.db.entity.Backup;\nimport io.github.muntashirakon.AppManager.db.utils.AppDb;\nimport io.github.muntashirakon.AppManager.types.UserPackagePair;\nimport io.github.muntashirakon.AppManager.users.UserInfo;\nimport io.github.muntashirakon.AppManager.users.Users;\nimport io.github.muntashirakon.AppManager.utils.CpuUtils;\nimport io.github.muntashirakon.AppManager.utils.ThreadUtils;\n\npublic class BackupRestoreDialogViewModel extends AndroidViewModel {\n    public static class OperationInfo {\n        @BackupRestoreDialogFragment.ActionMode\n        public int mode;\n        @BatchOpsManager.OpType\n        public int op;\n        @BackupFlags.BackupFlag\n        public int flags;\n        @Nullable\n        public String[] backupNames;\n        @Nullable\n        public String[] relativeDirs;\n        @Nullable\n        public int[] selectedUsers;\n\n        // Others\n        public boolean handleMultipleUsers = true;\n        @Nullable\n        public List<UserInfo> userInfoList;\n\n        public ArrayList<String> packageList;\n        public ArrayList<Integer> userIdListMappedToPackageList;\n    }\n\n    private int mWorstBackupFlag;\n    private int[] mPreferredUsersForBackup;\n    private int[] mPreferredUsersForRestore;\n    private boolean mAllowCustomUsersInBackup = true;\n    private Future<?> mProcessPackageFuture;\n    private Future<?> mHandleUsersFuture;\n\n    @NonNull\n    private final List<BackupInfo> mBackupInfoList = new ArrayList<>();\n    private final Set<CharSequence> mAppsWithoutBackups = new HashSet<>();\n    private final Set<CharSequence> mUninstalledApps = new HashSet<>();\n    private final MutableLiveData<OperationInfo> mUserSelectionLiveData = new MutableLiveData<>();\n    private final MutableLiveData<OperationInfo> mBackupOperationLiveData = new MutableLiveData<>();\n    private final MutableLiveData<Integer> mBackupInfoStateLiveData = new MutableLiveData<>();\n\n    public BackupRestoreDialogViewModel(@NonNull Application application) {\n        super(application);\n    }\n\n    @Override\n    protected void onCleared() {\n        if (mProcessPackageFuture != null) {\n            mProcessPackageFuture.cancel(true);\n        }\n        if (mHandleUsersFuture != null) {\n            mHandleUsersFuture.cancel(true);\n        }\n        super.onCleared();\n    }\n\n    public LiveData<Integer> getBackupInfoStateLiveData() {\n        return mBackupInfoStateLiveData;\n    }\n\n    public LiveData<OperationInfo> getBackupOperationLiveData() {\n        return mBackupOperationLiveData;\n    }\n\n    public MutableLiveData<OperationInfo> getUserSelectionLiveData() {\n        return mUserSelectionLiveData;\n    }\n\n    @NonNull\n    public List<BackupInfo> getBackupInfoList() {\n        return mBackupInfoList;\n    }\n\n    public Set<CharSequence> getAppsWithoutBackups() {\n        return mAppsWithoutBackups;\n    }\n\n    public Set<CharSequence> getUninstalledApps() {\n        return mUninstalledApps;\n    }\n\n    @NonNull\n    public BackupInfo getBackupInfo() {\n        return mBackupInfoList.get(0);\n    }\n\n    @BackupFlags.BackupFlag\n    public int getWorstBackupFlag() {\n        return mWorstBackupFlag;\n    }\n\n    public boolean allowCustomUsersInBackup() {\n        return mAllowCustomUsersInBackup;\n    }\n\n    public void setPreferredUserForRestore(@UserIdInt int preferredUserForRestore) {\n        mPreferredUsersForRestore = new int[]{preferredUserForRestore};\n    }\n\n    @AnyThread\n    public void processPackages(@Nullable List<UserPackagePair> userPackagePairs) {\n        mProcessPackageFuture = ThreadUtils.postOnBackgroundThread(() -> {\n            if (userPackagePairs == null) {\n                mBackupInfoStateLiveData.postValue(BackupInfoState.NONE);\n                mWorstBackupFlag = 0;\n                return;\n            }\n            PowerManager.WakeLock wakeLock = CpuUtils.getPartialWakeLock(\"backup_dialog_process\");\n            wakeLock.acquire();\n            try {\n                processPackagesInternal(userPackagePairs);\n            } finally {\n                CpuUtils.releaseWakeLock(wakeLock);\n            }\n        });\n    }\n\n    @AnyThread\n    public void prepareForOperation(@NonNull OperationInfo operationInfo) {\n        mHandleUsersFuture = ThreadUtils.postOnBackgroundThread(() -> {\n            if (operationInfo.handleMultipleUsers\n                    && operationInfo.mode != BackupRestoreDialogFragment.MODE_DELETE\n                    && (operationInfo.flags & BackupFlags.BACKUP_CUSTOM_USERS) != 0) {\n                // Handle custom users for backup/restore operations if requested\n                handleCustomUsers(operationInfo);\n                return;\n            }\n            operationInfo.handleMultipleUsers = false;\n            generatePackageUserIdLists(operationInfo);\n            mBackupOperationLiveData.postValue(operationInfo);\n        });\n    }\n\n    private void processPackagesInternal(@NonNull List<UserPackagePair> userPackagePairs) {\n        Map<String, BackupInfo> backupInfoMap = new HashMap<>();\n        AppDb appDb = new AppDb();\n        // Fetch info\n        for (UserPackagePair userPackagePair : userPackagePairs) {\n            if (ThreadUtils.isInterrupted()) {\n                return;\n            }\n            if (userPackagePair.getPackageName().equals(\"android\")) {\n                // Skip checking android package because it can't be backed up or restored.\n                continue;\n            }\n            BackupInfo backupInfo = backupInfoMap.get(userPackagePair.getPackageName());\n            if (backupInfo != null) {\n                // Entry exists, add user ID only\n                backupInfo.userIds.add(userPackagePair.getUserId());\n                continue;\n            }\n            // Add new entry\n            backupInfo = new BackupInfo(userPackagePair.getPackageName(), userPackagePair.getUserId());\n            List<App> apps = appDb.getAllApplications(userPackagePair.getPackageName(), userPackagePair.getUserId());\n            List<Backup> backups = appDb.getAllBackups(userPackagePair.getPackageName());\n            if (ThreadUtils.isInterrupted()) {\n                return;\n            }\n            // Fetch backup info\n            List<BackupMetadataV5> metadataList = new ArrayList<>();\n            for (Backup backup : backups) {\n                BackupMetadataV5 metadata;\n                try {\n                    metadata = backup.getItem().getMetadata();\n                    metadataList.add(metadata);\n                } catch (IOException e) {\n                    // Not found\n                    continue;\n                }\n                if (metadata.isBaseBackup()) {\n                    backupInfo.setHasBaseBackup(true);\n                }\n            }\n            if (ThreadUtils.isInterrupted()) {\n                return;\n            }\n            backupInfo.setBackupMetadataList(metadataList);\n            if (apps.isEmpty()) {\n                backupInfo.setInstalled(false);\n            } else {\n                for (App app : apps) {\n                    backupInfo.setAppLabel(app.packageLabel);\n                    // Installation gets higher priority\n                    backupInfo.setInstalled(backupInfo.isInstalled() | app.isInstalled);\n                }\n            }\n            if (!backupInfo.isInstalled() && backupInfo.getBackupMetadataList().isEmpty()) {\n                // App cannot be backed up or restored\n                continue;\n            }\n            backupInfoMap.put(userPackagePair.getPackageName(), backupInfo);\n        }\n        if (ThreadUtils.isInterrupted()) {\n            return;\n        }\n        mBackupInfoList.clear();\n        mBackupInfoList.addAll(backupInfoMap.values());\n        mAppsWithoutBackups.clear();\n        mUninstalledApps.clear();\n        // Check if mBackupInfoList is singleton\n        if (mBackupInfoList.size() == 1) {\n            // Singleton list\n            BackupInfo backupInfo = mBackupInfoList.get(0);\n            if (backupInfo.isInstalled() && backupInfo.userIds.size() == 1) {\n                // A special case where we need to check if we can allow custom users for backups\n                mPreferredUsersForBackup = new int[]{Objects.requireNonNull(backupInfo.userIds.valueAt(0))};\n                List<App> apps = appDb.getAllApplications(backupInfo.packageName);\n                int userCount = 0;\n                for (App app : apps) {\n                    if (app.isInstalled) {\n                        ++userCount;\n                    }\n                }\n                mAllowCustomUsersInBackup = userCount > 1;\n            }\n        }\n        if (mPreferredUsersForBackup == null) {\n            mPreferredUsersForBackup = new int[]{UserHandleHidden.myUserId()};\n        }\n        if (mPreferredUsersForRestore == null) {\n            mPreferredUsersForRestore = new int[]{UserHandleHidden.myUserId()};\n        }\n        // Find status\n        int status;\n        mWorstBackupFlag = 0xffff_ffff;\n        if (mBackupInfoList.size() == 1) {\n            // Single backup\n            BackupInfo backupInfo = mBackupInfoList.get(0);\n            for (BackupMetadataV5 metadata : backupInfo.getBackupMetadataList()) {\n                mWorstBackupFlag &= metadata.info.flags.getFlags();\n            }\n            if (backupInfo.getBackupMetadataList().isEmpty()) {\n                mAppsWithoutBackups.add(backupInfo.getAppLabel());\n            }\n            if (!backupInfo.isInstalled()) {\n                mUninstalledApps.add(backupInfo.getAppLabel());\n            }\n            if (backupInfo.isInstalled() && !backupInfo.getBackupMetadataList().isEmpty()) {\n                status = BackupInfoState.BOTH_SINGLE;\n            } else if (backupInfo.isInstalled()) {\n                status = BackupInfoState.BACKUP_SINGLE;\n            } else if (!backupInfo.getBackupMetadataList().isEmpty()) {\n                status = BackupInfoState.RESTORE_SINGLE;\n            } else status = BackupInfoState.NONE;\n        } else {\n            // Multiple backup\n            boolean hasInstalled = false;\n            boolean hasBaseBackup = false;\n            for (BackupInfo backupInfo : mBackupInfoList) {\n                if (ThreadUtils.isInterrupted()) {\n                    return;\n                }\n                if (backupInfo.isInstalled()) {\n                    hasInstalled = true;\n                } else {\n                    mUninstalledApps.add(backupInfo.getAppLabel());\n                }\n                if (backupInfo.hasBaseBackup()) {\n                    hasBaseBackup = true;\n                    for (BackupMetadataV5 metadata : backupInfo.getBackupMetadataList()) {\n                        if (metadata.isBaseBackup()) {\n                            mWorstBackupFlag &= metadata.info.flags.getFlags();\n                        }\n                    }\n                } else {\n                    mAppsWithoutBackups.add(backupInfo.getAppLabel());\n                }\n            }\n            // Remove irrelevant flags\n            int worstBackupFlag = mWorstBackupFlag & ~(BackupFlags.BACKUP_MULTIPLE | BackupFlags.BACKUP_CUSTOM_USERS\n                    | BackupFlags.BACKUP_NO_SIGNATURE_CHECK);\n            hasBaseBackup = hasBaseBackup && worstBackupFlag > 0;\n            if (hasInstalled && hasBaseBackup) {\n                status = BackupInfoState.BOTH_MULTIPLE;\n            } else if (hasInstalled) {\n                status = BackupInfoState.BACKUP_MULTIPLE;\n            } else if (hasBaseBackup) {\n                status = BackupInfoState.RESTORE_MULTIPLE;\n            } else status = BackupInfoState.NONE;\n        }\n        if (ThreadUtils.isInterrupted()) {\n            return;\n        }\n        // Send status\n        mBackupInfoStateLiveData.postValue(status);\n    }\n\n    @WorkerThread\n    private void handleCustomUsers(@NonNull OperationInfo operationInfo) {\n        operationInfo.handleMultipleUsers = false;\n        List<UserInfo> users = Users.getUsers();\n        if (users.size() <= 1) {\n            // There's only one user (which should not happen because the flag should be hidden)\n            // Strip custom users flag and start the operation\n            operationInfo.flags &= ~BackupFlags.BACKUP_CUSTOM_USERS;\n            generatePackageUserIdLists(operationInfo);\n            mBackupOperationLiveData.postValue(operationInfo);\n            return;\n        }\n        operationInfo.userInfoList = users;\n        mUserSelectionLiveData.postValue(operationInfo);\n    }\n\n    @WorkerThread\n    private void generatePackageUserIdLists(@NonNull OperationInfo operationInfo) {\n        int[] userIds;\n        if (operationInfo.selectedUsers != null) {\n            userIds = operationInfo.selectedUsers;\n        } else if (operationInfo.mode == BackupRestoreDialogFragment.MODE_BACKUP) {\n            userIds = mPreferredUsersForBackup;\n        } else { // restore/delete mode\n            userIds = mPreferredUsersForRestore;\n        }\n        operationInfo.packageList = new ArrayList<>();\n        operationInfo.userIdListMappedToPackageList = new ArrayList<>();\n        // For singleton restore, cross user restore is supported. So, we need to handle that here.\n        if (operationInfo.mode == BackupRestoreDialogFragment.MODE_RESTORE && mBackupInfoList.size() == 1) {\n            BackupInfo backupInfo = mBackupInfoList.get(0);\n            if (!backupInfo.getBackupMetadataList().isEmpty() && backupInfo.userIds.size() == 1) {\n                // Singleton restore\n                for (int userId : userIds) {\n                    // Same backup can be restored for multiple users\n                    operationInfo.packageList.add(backupInfo.packageName);\n                    operationInfo.userIdListMappedToPackageList.add(userId);\n                }\n            }\n        }\n        // Otherwise, user checks are mandatory.\n        for (BackupInfo backupInfo : mBackupInfoList) {\n            if (ThreadUtils.isInterrupted()) {\n                return;\n            }\n            for (int userId : userIds) {\n                if (backupInfo.userIds.contains(userId)) {\n                    operationInfo.packageList.add(backupInfo.packageName);\n                    operationInfo.userIdListMappedToPackageList.add(userId);\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/backup/dialog/FlagsAdapter.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.backup.dialog;\n\nimport android.annotation.SuppressLint;\nimport android.content.Context;\nimport android.util.TypedValue;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.CheckedTextView;\n\nimport androidx.annotation.NonNull;\nimport androidx.recyclerview.widget.RecyclerView;\n\nimport com.google.android.material.resources.MaterialAttributes;\n\nimport java.util.List;\n\nimport io.github.muntashirakon.AppManager.backup.BackupFlags;\nimport io.github.muntashirakon.AppManager.utils.UIUtils;\nimport io.github.muntashirakon.util.AdapterUtils;\n\nclass FlagsAdapter extends RecyclerView.Adapter<FlagsAdapter.ViewHolder> {\n    private final int mLayoutId;\n    private final List<Integer> mSupportedBackupFlags;\n    private final CharSequence[] mSupportedBackupFlagNames;\n    @BackupFlags.BackupFlag\n    private final int mDisabledFlags;\n\n    @BackupFlags.BackupFlag\n    private int mSelectedFlags;\n\n    @SuppressLint(\"RestrictedApi\")\n    public FlagsAdapter(@NonNull Context context, @BackupFlags.BackupFlag int flags,\n                        @BackupFlags.BackupFlag int supportedFlags) {\n        this(context, flags, supportedFlags, 0);\n    }\n\n    @SuppressLint(\"RestrictedApi\")\n    public FlagsAdapter(@NonNull Context context, @BackupFlags.BackupFlag int flags,\n                        @BackupFlags.BackupFlag int supportedFlags, @BackupFlags.BackupFlag int disabledFlags) {\n        mLayoutId = MaterialAttributes.resolveInteger(context, androidx.appcompat.R.attr.multiChoiceItemLayout,\n                com.google.android.material.R.layout.mtrl_alert_select_dialog_multichoice);\n        // We list |supportedFlags| and select |flags| by default\n        mSupportedBackupFlags = BackupFlags.getBackupFlagsAsArray(supportedFlags);\n        mSupportedBackupFlagNames = BackupFlags.getFormattedFlagNames(context, mSupportedBackupFlags);\n        mSelectedFlags = flags;\n        mDisabledFlags = disabledFlags;\n        notifyItemRangeInserted(0, mSupportedBackupFlags.size());\n    }\n\n    public int getSelectedFlags() {\n        return mSelectedFlags;\n    }\n\n    @NonNull\n    @Override\n    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {\n        View view = LayoutInflater.from(parent.getContext()).inflate(mLayoutId, parent, false);\n        return new ViewHolder(view);\n    }\n\n    @Override\n    public void onBindViewHolder(@NonNull ViewHolder holder, int position) {\n        int flag = mSupportedBackupFlags.get(position);\n        boolean isSelected = (mSelectedFlags & flag) != 0;\n        boolean isDisabled = (mDisabledFlags & flag) != 0;\n        holder.item.setChecked(isSelected);\n        holder.item.setEnabled(!isDisabled);\n        holder.item.setText(mSupportedBackupFlagNames[position]);\n        holder.item.setOnClickListener(v -> {\n            if (isSelected) {\n                // Now unselected\n                mSelectedFlags &= ~flag;\n            } else {\n                // Now selected\n                mSelectedFlags |= flag;\n            }\n            notifyItemChanged(position, AdapterUtils.STUB);\n        });\n    }\n\n    @Override\n    public int getItemCount() {\n        return mSupportedBackupFlags.size();\n    }\n\n    static class ViewHolder extends RecyclerView.ViewHolder {\n        CheckedTextView item;\n\n        public ViewHolder(@NonNull View itemView) {\n            super(itemView);\n            item = itemView.findViewById(android.R.id.text1);\n            // textAppearanceBodyLarge\n            item.setTextSize(TypedValue.COMPLEX_UNIT_SP, 16);\n            item.setTextColor(UIUtils.getTextColorSecondary(item.getContext()));\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/backup/dialog/RestoreMultipleFragment.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.backup.dialog;\n\nimport android.content.Context;\nimport android.os.Bundle;\nimport android.text.SpannableStringBuilder;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.fragment.app.Fragment;\nimport androidx.lifecycle.ViewModelProvider;\nimport androidx.recyclerview.widget.LinearLayoutManager;\nimport androidx.recyclerview.widget.RecyclerView;\n\nimport com.google.android.material.dialog.MaterialAlertDialogBuilder;\n\nimport java.util.Set;\n\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.backup.BackupFlags;\nimport io.github.muntashirakon.AppManager.batchops.BatchOpsManager;\nimport io.github.muntashirakon.widget.MaterialAlertView;\n\npublic class RestoreMultipleFragment extends Fragment {\n    @NonNull\n    public static RestoreMultipleFragment getInstance() {\n        return new RestoreMultipleFragment();\n    }\n\n    private BackupRestoreDialogViewModel mViewModel;\n    private Context mContext;\n\n    @Nullable\n    @Override\n    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {\n        return inflater.inflate(R.layout.fragment_dialog_restore_multiple, container, false);\n    }\n\n    @Override\n    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {\n        mViewModel = new ViewModelProvider(requireParentFragment()).get(BackupRestoreDialogViewModel.class);\n        mContext = requireContext();\n\n        MaterialAlertView messageView = view.findViewById(R.id.message);\n        RecyclerView recyclerView = view.findViewById(android.R.id.list);\n        recyclerView.setLayoutManager(new LinearLayoutManager(mContext, LinearLayoutManager.VERTICAL, false));\n        int supportedFlags = mViewModel.getWorstBackupFlag();\n        // Inject no signatures\n        supportedFlags |= BackupFlags.BACKUP_NO_SIGNATURE_CHECK;\n        supportedFlags |= BackupFlags.BACKUP_CUSTOM_USERS;\n        int checkedFlags = BackupFlags.fromPref().getFlags() & supportedFlags;\n        int disabledFlags = 0;\n        if (!mViewModel.getUninstalledApps().isEmpty()) {\n            checkedFlags |= BackupFlags.BACKUP_APK_FILES;\n            disabledFlags |= BackupFlags.BACKUP_APK_FILES;\n        }\n        FlagsAdapter adapter = new FlagsAdapter(mContext, checkedFlags, supportedFlags, disabledFlags);\n        recyclerView.setAdapter(adapter);\n\n        Set<CharSequence> appsWithoutBackups = mViewModel.getAppsWithoutBackups();\n        if (!appsWithoutBackups.isEmpty()) {\n            SpannableStringBuilder sb = new SpannableStringBuilder(getString(R.string.backup_apps_cannot_be_restored));\n            for (CharSequence appLabel : appsWithoutBackups) {\n                sb.append(\"\\n● \").append(appLabel);\n            }\n            messageView.setText(sb);\n            messageView.setVisibility(View.VISIBLE);\n        }\n        view.findViewById(R.id.action_restore).setOnClickListener(v -> {\n            int newFlags = adapter.getSelectedFlags();\n            handleRestore(newFlags);\n        });\n    }\n\n    private void handleRestore(int flags) {\n        new MaterialAlertDialogBuilder(mContext)\n                .setTitle(R.string.restore)\n                .setMessage(R.string.are_you_sure)\n                .setPositiveButton(R.string.yes, (dialog, which) -> {\n                    BackupRestoreDialogViewModel.OperationInfo operationInfo = new BackupRestoreDialogViewModel.OperationInfo();\n                    operationInfo.mode = BackupRestoreDialogFragment.MODE_RESTORE;\n                    operationInfo.op = BatchOpsManager.OP_RESTORE_BACKUP;\n                    operationInfo.flags = flags;\n                    mViewModel.prepareForOperation(operationInfo);\n                })\n                .setNegativeButton(R.string.no, null)\n                .show();\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/backup/dialog/RestoreSingleFragment.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.backup.dialog;\n\nimport android.annotation.SuppressLint;\nimport android.content.Context;\nimport android.os.Bundle;\nimport android.util.TypedValue;\nimport android.view.LayoutInflater;\nimport android.view.Menu;\nimport android.view.MenuItem;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.CheckedTextView;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.appcompat.widget.PopupMenu;\nimport androidx.fragment.app.Fragment;\nimport androidx.lifecycle.ViewModelProvider;\nimport androidx.recyclerview.widget.LinearLayoutManager;\nimport androidx.recyclerview.widget.RecyclerView;\n\nimport com.google.android.material.button.MaterialButton;\nimport com.google.android.material.dialog.MaterialAlertDialogBuilder;\nimport com.google.android.material.resources.MaterialAttributes;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.backup.BackupFlags;\nimport io.github.muntashirakon.AppManager.backup.struct.BackupMetadataV5;\nimport io.github.muntashirakon.AppManager.batchops.BatchOpsManager;\nimport io.github.muntashirakon.AppManager.utils.UIUtils;\nimport io.github.muntashirakon.dialog.SearchableFlagsDialogBuilder;\nimport io.github.muntashirakon.util.AdapterUtils;\n\npublic class RestoreSingleFragment extends Fragment {\n    public static RestoreSingleFragment getInstance() {\n        return new RestoreSingleFragment();\n    }\n\n    private BackupRestoreDialogViewModel mViewModel;\n    private Context mContext;\n\n    @Nullable\n    @Override\n    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {\n        return inflater.inflate(R.layout.fragment_dialog_restore_single, container, false);\n    }\n\n    @Override\n    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {\n        mViewModel = new ViewModelProvider(requireParentFragment()).get(BackupRestoreDialogViewModel.class);\n        mContext = requireContext();\n\n        RecyclerView recyclerView = view.findViewById(android.R.id.list);\n        MaterialButton restoreButton = view.findViewById(R.id.action_restore);\n        MaterialButton deleteButton = view.findViewById(R.id.action_delete);\n        MaterialButton moreButton = view.findViewById(R.id.more);\n\n        recyclerView.setLayoutManager(new LinearLayoutManager(mContext, LinearLayoutManager.VERTICAL, false));\n        BackupAdapter adapter = new BackupAdapter(mContext, mViewModel.getBackupInfo().getBackupMetadataList(),\n                (metadata, selectionCount, added) -> {\n                    restoreButton.setEnabled(selectionCount == 1);\n                    deleteButton.setEnabled(selectionCount > 0);\n                });\n        recyclerView.setAdapter(adapter);\n\n        restoreButton.setOnClickListener(v -> handleRestore(adapter.getSelectedBackups().get(0)));\n        deleteButton.setOnClickListener(v -> handleDelete(adapter.getSelectedBackups()));\n        moreButton.setOnClickListener(v -> {\n            int total = adapter.selectionCount();\n            int frozenCount = adapter.getFrozenBackupSelectionCount();\n\n            PopupMenu popupMenu = new PopupMenu(mContext, v);\n            Menu menu = popupMenu.getMenu();\n            MenuItem freezeMenuItem = menu.add(R.string.freeze);\n            MenuItem unfreezeMenuItem = menu.add(R.string.unfreeze);\n\n            freezeMenuItem.setEnabled((total - frozenCount) > 0);\n            unfreezeMenuItem.setEnabled(frozenCount > 0);\n\n            freezeMenuItem.setOnMenuItemClickListener(item -> {\n                List<BackupMetadataV5> selectedBackups = adapter.getSelectedBackups();\n                for (BackupMetadataV5 metadata : selectedBackups) {\n                    try {\n                        metadata.info.getBackupItem().freeze();\n                        ++adapter.mFrozenBackupSelectionCount;\n                    } catch (IOException ignore) {\n                    }\n                }\n                adapter.notifyItemRangeChanged(0, adapter.getItemCount(), AdapterUtils.STUB);\n                return true;\n            });\n            unfreezeMenuItem.setOnMenuItemClickListener(item -> {\n                List<BackupMetadataV5> selectedBackups = adapter.getSelectedBackups();\n                for (BackupMetadataV5 metadata : selectedBackups) {\n                    try {\n                        metadata.info.getBackupItem().unfreeze();\n                        --adapter.mFrozenBackupSelectionCount;\n                    } catch (IOException ignore) {\n                    }\n                }\n                adapter.notifyItemRangeChanged(0, adapter.getItemCount(), AdapterUtils.STUB);\n                return true;\n            });\n            popupMenu.show();\n        });\n    }\n\n    private void handleRestore(@NonNull BackupMetadataV5 selectedBackup) {\n        BackupFlags flags = selectedBackup.info.flags;\n        BackupFlags enabledFlags = BackupFlags.fromPref();\n        enabledFlags.setFlags(flags.getFlags() & enabledFlags.getFlags());\n        List<Integer> supportedBackupFlags = BackupFlags.getBackupFlagsAsArray(flags.getFlags());\n        // Inject no signatures\n        supportedBackupFlags.add(BackupFlags.BACKUP_NO_SIGNATURE_CHECK);\n        supportedBackupFlags.add(BackupFlags.BACKUP_CUSTOM_USERS);\n        List<Integer> disabledFlags = new ArrayList<>();\n        if (!mViewModel.getBackupInfo().isInstalled()) {\n            enabledFlags.addFlag(BackupFlags.BACKUP_APK_FILES);\n            disabledFlags.add(BackupFlags.BACKUP_APK_FILES);\n        }\n        new SearchableFlagsDialogBuilder<>(mContext, supportedBackupFlags, BackupFlags.getFormattedFlagNames(mContext, supportedBackupFlags), enabledFlags.getFlags())\n                .setTitle(R.string.backup_options)\n                .addDisabledItems(disabledFlags)\n                .setPositiveButton(R.string.restore, (dialog, which, selections) -> {\n                    int newFlags = 0;\n                    for (int flag : selections) {\n                        newFlags |= flag;\n                    }\n                    enabledFlags.setFlags(newFlags);\n\n                    BackupRestoreDialogViewModel.OperationInfo operationInfo = new BackupRestoreDialogViewModel.OperationInfo();\n                    operationInfo.mode = BackupRestoreDialogFragment.MODE_RESTORE;\n                    operationInfo.op = BatchOpsManager.OP_RESTORE_BACKUP;\n                    operationInfo.flags = enabledFlags.getFlags();\n                    operationInfo.relativeDirs = new String[]{selectedBackup.info.getRelativeDir()};\n                    mViewModel.prepareForOperation(operationInfo);\n                })\n                .setNegativeButton(R.string.cancel, null)\n                .show();\n    }\n\n    private void handleDelete(List<BackupMetadataV5> selectedBackups) {\n        new MaterialAlertDialogBuilder(mContext)\n                .setTitle(R.string.delete_backup)\n                .setMessage(R.string.are_you_sure)\n                .setNegativeButton(R.string.no, null)\n                .setPositiveButton(R.string.yes, (dialog, which) -> {\n                    List<String> relativeDirs = new ArrayList<>(selectedBackups.size());\n                    for (BackupMetadataV5 backup : selectedBackups) {\n                        relativeDirs.add(backup.info.getRelativeDir());\n                    }\n                    BackupRestoreDialogViewModel.OperationInfo operationInfo = new BackupRestoreDialogViewModel.OperationInfo();\n                    operationInfo.mode = BackupRestoreDialogFragment.MODE_DELETE;\n                    operationInfo.op = BatchOpsManager.OP_DELETE_BACKUP;\n                    operationInfo.relativeDirs = relativeDirs.toArray(new String[0]);\n                    mViewModel.prepareForOperation(operationInfo);\n                })\n                .show();\n    }\n\n    private static class BackupAdapter extends RecyclerView.Adapter<BackupAdapter.ViewHolder> {\n        public interface OnSelectionListener {\n            void onSelectionChanged(@Nullable BackupMetadataV5 metadata, int selectionCount, boolean added);\n        }\n\n        private final int mLayoutId;\n        @NonNull\n        private final List<BackupMetadataV5> mBackups = new ArrayList<>();\n        @NonNull\n        private final List<Integer> mSelectedPositions = new ArrayList<>();\n        @NonNull\n        private final OnSelectionListener mSelectionListener;\n\n        private int mFrozenBackupSelectionCount = 0;\n\n        @SuppressLint(\"RestrictedApi\")\n        public BackupAdapter(@NonNull Context context, @NonNull List<BackupMetadataV5> backups,\n                             @NonNull OnSelectionListener selectionListener) {\n            mSelectionListener = selectionListener;\n            mLayoutId = MaterialAttributes.resolveInteger(context, androidx.appcompat.R.attr.multiChoiceItemLayout,\n                    com.google.android.material.R.layout.mtrl_alert_select_dialog_multichoice);\n            mSelectionListener.onSelectionChanged(null, mSelectedPositions.size(), false);\n            for (int i = 0; i < backups.size(); ++i) {\n                BackupMetadataV5 backup = backups.get(i);\n                mBackups.add(backup);\n                if (backup.isBaseBackup()) {\n                    mSelectedPositions.add(i);\n                    if (backup.info.isFrozen()) {\n                        ++mFrozenBackupSelectionCount;\n                    }\n                    mSelectionListener.onSelectionChanged(backup, mSelectedPositions.size(), true);\n                }\n            }\n            notifyItemRangeInserted(0, mBackups.size());\n        }\n\n        public int selectionCount() {\n            return mSelectedPositions.size();\n        }\n\n        public int getFrozenBackupSelectionCount() {\n            return mFrozenBackupSelectionCount;\n        }\n\n        @NonNull\n        public List<BackupMetadataV5> getSelectedBackups() {\n            List<BackupMetadataV5> selectedBackups = new ArrayList<>();\n            for (int position : mSelectedPositions) {\n                selectedBackups.add(mBackups.get(position));\n            }\n            return selectedBackups;\n        }\n\n        @NonNull\n        @Override\n        public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {\n            View view = LayoutInflater.from(parent.getContext()).inflate(mLayoutId, parent, false);\n            return new ViewHolder(view);\n        }\n\n        @Override\n        public void onBindViewHolder(@NonNull ViewHolder holder, int position) {\n            BackupMetadataV5 metadata = mBackups.get(position);\n            boolean isSelected = mSelectedPositions.contains(position);\n            holder.item.setChecked(isSelected);\n            holder.item.setText(metadata.toLocalizedString(holder.item.getContext()));\n            holder.item.setOnClickListener(v -> {\n                if (isSelected) {\n                    // Now unselected\n                    mSelectedPositions.remove((Integer) position);\n                    if (metadata.info.isFrozen()) {\n                        --mFrozenBackupSelectionCount;\n                    }\n                    mSelectionListener.onSelectionChanged(metadata, mSelectedPositions.size(), false);\n                } else {\n                    // Now selected\n                    mSelectedPositions.add(position);\n                    if (metadata.info.isFrozen()) {\n                        ++mFrozenBackupSelectionCount;\n                    }\n                    mSelectionListener.onSelectionChanged(metadata, mSelectedPositions.size(), true);\n                }\n                notifyItemChanged(position, AdapterUtils.STUB);\n            });\n        }\n\n        @Override\n        public int getItemCount() {\n            return mBackups.size();\n        }\n\n        static class ViewHolder extends RecyclerView.ViewHolder {\n            CheckedTextView item;\n\n            public ViewHolder(@NonNull View itemView) {\n                super(itemView);\n                item = itemView.findViewById(android.R.id.text1);\n                // textAppearanceBodyLarge\n                item.setTextSize(TypedValue.COMPLEX_UNIT_SP, 16);\n                item.setTextColor(UIUtils.getTextColorSecondary(item.getContext()));\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/backup/struct/BackupMetadataV2.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.backup.struct;\n\nimport android.os.Build;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport org.json.JSONException;\nimport org.json.JSONObject;\n\nimport aosp.libcore.util.HexEncoding;\nimport io.github.muntashirakon.AppManager.backup.BackupFlags;\nimport io.github.muntashirakon.AppManager.backup.BackupItems;\nimport io.github.muntashirakon.AppManager.backup.CryptoUtils;\nimport io.github.muntashirakon.AppManager.backup.MetadataManager;\nimport io.github.muntashirakon.AppManager.history.IJsonSerializer;\nimport io.github.muntashirakon.AppManager.misc.VMRuntime;\nimport io.github.muntashirakon.AppManager.utils.DigestUtils;\nimport io.github.muntashirakon.AppManager.utils.JSONUtils;\nimport io.github.muntashirakon.AppManager.utils.TarUtils;\n\n// For an extended documentation, see https://github.com/MuntashirAkon/AppManager/issues/30\n// All the attributes must be non-null\npublic class BackupMetadataV2 implements IJsonSerializer {\n    @Nullable\n    public String backupName;  // This isn't part of the json file and for internal use only\n    public BackupItems.BackupItem backupItem; // This isn't part of the json file and for internal use only\n\n    public String label;  // label\n    public String packageName;  // package_name\n    public String versionName;  // version_name\n    public long versionCode;  // version_code\n    public String[] dataDirs;  // data_dirs\n    public boolean isSystem;  // is_system\n    public boolean isSplitApk;  // is_split_apk\n    public String[] splitConfigs;  // split_configs\n    public boolean hasRules;  // has_rules\n    public long backupTime;  // backup_time\n    @DigestUtils.Algorithm\n    public String checksumAlgo = DigestUtils.SHA_256;  // checksum_algo\n    @CryptoUtils.Mode\n    public String crypto;  // crypto\n    @Nullable\n    public byte[] iv;  // iv\n    @Nullable\n    public byte[] aes;  // aes (encrypted using RSA/ECC, for RSA/ECC only)\n    @Nullable\n    public String keyIds;  // key_ids\n    /**\n     * Metadata version.\n     * <ul>\n     *     <li>{@code 1} - Alpha version, no longer supported</li>\n     *     <li>{@code 2} - Beta version (v2.5.2x), permissions aren't preserved (special action needed)</li>\n     *     <li>{@code 3} - From v2.6.x to v3.0.2 and v3.1.0-alpha01, permissions are preserved, AES GCM MAC size is 32 bits</li>\n     *     <li>{@code 4} - Since v3.0.3 and v3.1.0-alpha02, AES GCM MAC size is 128 bits</li>\n     * </ul>\n     */\n    public int version;  // version\n    public String apkName;  // apk_name\n    public String instructionSet = VMRuntime.getInstructionSet(Build.SUPPORTED_ABIS[0]);  // instruction_set\n    public BackupFlags flags;  // flags\n    public int userId;  // user_handle\n    @TarUtils.TarType\n    public String tarType;  // tar_type\n    public boolean keyStore;  // key_store\n    public String installer;  // installer\n\n    public BackupMetadataV2() {\n        version = MetadataManager.getCurrentBackupMetaVersion();\n    }\n\n    public BackupMetadataV2(@NonNull BackupMetadataV2 metadata) {\n        backupName = metadata.backupName;\n        backupItem = metadata.backupItem;\n\n        label = metadata.label;\n        packageName = metadata.packageName;\n        versionName = metadata.versionName;\n        versionCode = metadata.versionCode;\n        if (metadata.dataDirs != null) {\n            dataDirs = metadata.dataDirs.clone();\n        }\n        isSystem = metadata.isSystem;\n        isSplitApk = metadata.isSplitApk;\n        if (metadata.splitConfigs != null) {\n            splitConfigs = metadata.splitConfigs.clone();\n        }\n        hasRules = metadata.hasRules;\n        backupTime = metadata.backupTime;\n        checksumAlgo = metadata.checksumAlgo;\n        crypto = metadata.crypto;\n        if (metadata.iv != null) {\n            iv = metadata.iv.clone();\n        }\n        if (metadata.aes != null) {\n            aes = metadata.aes.clone();\n        }\n        keyIds = metadata.keyIds;\n        version = metadata.version;\n        apkName = metadata.apkName;\n        instructionSet = metadata.instructionSet;\n        flags = new BackupFlags(metadata.flags.getFlags());\n        userId = metadata.userId;\n        tarType = metadata.tarType;\n        keyStore = metadata.keyStore;\n        installer = metadata.installer;\n    }\n\n    @NonNull\n    @Override\n    public JSONObject serializeToJson() throws JSONException {\n        JSONObject rootObject = new JSONObject();\n        rootObject.put(\"label\", label);\n        rootObject.put(\"package_name\", packageName);\n        rootObject.put(\"version_name\", versionName);\n        rootObject.put(\"version_code\", versionCode);\n        rootObject.put(\"data_dirs\", JSONUtils.getJSONArray(dataDirs));\n        rootObject.put(\"is_system\", isSystem);\n        rootObject.put(\"is_split_apk\", isSplitApk);\n        rootObject.put(\"split_configs\", JSONUtils.getJSONArray(splitConfigs));\n        rootObject.put(\"has_rules\", hasRules);\n        rootObject.put(\"backup_time\", backupTime);\n        rootObject.put(\"checksum_algo\", checksumAlgo);\n        rootObject.put(\"crypto\", crypto);\n        rootObject.put(\"key_ids\", keyIds);\n        rootObject.put(\"iv\", iv == null ? null : HexEncoding.encodeToString(iv));\n        rootObject.put(\"aes\", aes == null ? null : HexEncoding.encodeToString(aes));\n        rootObject.put(\"version\", version);\n        rootObject.put(\"apk_name\", apkName);\n        rootObject.put(\"instruction_set\", instructionSet);\n        rootObject.put(\"flags\", flags.getFlags());\n        rootObject.put(\"user_handle\", userId);\n        rootObject.put(\"tar_type\", tarType);\n        rootObject.put(\"key_store\", keyStore);\n        rootObject.put(\"installer\", installer);\n        return rootObject;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/backup/struct/BackupMetadataV5.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.backup.struct;\n\nimport static io.github.muntashirakon.AppManager.backup.BackupUtils.getReadableTarType;\nimport static io.github.muntashirakon.AppManager.utils.UIUtils.getSecondaryText;\nimport static io.github.muntashirakon.AppManager.utils.UIUtils.getSmallerText;\nimport static io.github.muntashirakon.AppManager.utils.UIUtils.getTitleText;\n\nimport android.annotation.UserIdInt;\nimport android.content.Context;\nimport android.os.Build;\nimport android.text.SpannableStringBuilder;\nimport android.text.TextUtils;\nimport android.text.format.Formatter;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.WorkerThread;\n\nimport org.json.JSONException;\nimport org.json.JSONObject;\n\nimport java.util.Locale;\nimport java.util.Objects;\n\nimport aosp.libcore.util.HexEncoding;\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.backup.BackupFlags;\nimport io.github.muntashirakon.AppManager.backup.BackupItems;\nimport io.github.muntashirakon.AppManager.backup.CryptoUtils;\nimport io.github.muntashirakon.AppManager.backup.MetadataManager;\nimport io.github.muntashirakon.AppManager.crypto.AESCrypto;\nimport io.github.muntashirakon.AppManager.crypto.Crypto;\nimport io.github.muntashirakon.AppManager.crypto.CryptoException;\nimport io.github.muntashirakon.AppManager.crypto.DummyCrypto;\nimport io.github.muntashirakon.AppManager.crypto.ECCCrypto;\nimport io.github.muntashirakon.AppManager.crypto.OpenPGPCrypto;\nimport io.github.muntashirakon.AppManager.crypto.RSACrypto;\nimport io.github.muntashirakon.AppManager.history.IJsonSerializer;\nimport io.github.muntashirakon.AppManager.misc.VMRuntime;\nimport io.github.muntashirakon.AppManager.utils.ContextUtils;\nimport io.github.muntashirakon.AppManager.utils.DateUtils;\nimport io.github.muntashirakon.AppManager.utils.DigestUtils;\nimport io.github.muntashirakon.AppManager.utils.JSONUtils;\nimport io.github.muntashirakon.AppManager.utils.LangUtils;\nimport io.github.muntashirakon.AppManager.utils.TarUtils;\nimport io.github.muntashirakon.io.Paths;\nimport io.github.muntashirakon.util.LocalizedString;\n\npublic class BackupMetadataV5 implements LocalizedString {\n    public static class Info implements IJsonSerializer {\n        /**\n         * Relative location of the backup from the AppManager directory, internal use only.\n         */\n        private String mRelativeDir;\n        public BackupItems.BackupItem mBackupItem; // This isn't part of the json file and for internal use only\n\n        /**\n         * Metadata version.\n         *\n         * <ul>\n         *     <li>{@code 1} - Alpha version, no longer supported</li>\n         *     <li>{@code 2} - Beta version (v2.5.2x), permissions aren't preserved (special action needed)</li>\n         *     <li>{@code 3} - From v2.6.x to v3.0.2 and v3.1.0-alpha01, permissions are preserved, AES GCM MAC size is 32 bits</li>\n         *     <li>{@code 4} - Since v3.0.3 and v3.1.0-alpha02, AES GCM MAC size is 128 bits</li>\n         *     <li>{@code 5} - Since v4.0.6, meta.json, info.json, privacy-friendly backup</li>\n         * </ul>\n         */\n        public final int version;  // version\n        public final long backupTime;  // backup_time\n        @NonNull\n        public final BackupFlags flags;  // flags\n        @UserIdInt\n        public final int userId;  // user_handle\n        @NonNull\n        @TarUtils.TarType\n        public final String tarType;  // tar_type\n        @NonNull\n        @DigestUtils.Algorithm\n        public final String checksumAlgo;  // checksum_algo\n        @NonNull\n        @CryptoUtils.Mode\n        public final String crypto;  // crypto\n        @Nullable\n        public final byte[] iv;  // iv\n        @Nullable\n        public final byte[] aes;  // aes (encrypted using RSA, for RSA only)\n        @Nullable\n        public final String keyIds;  // key_ids\n\n        @Nullable\n        private Crypto mCrypto;\n\n        public Info(long backupTime,\n                    @NonNull BackupFlags flags,\n                    @UserIdInt int userId,\n                    @TarUtils.TarType @NonNull String tarType,\n                    @DigestUtils.Algorithm @NonNull String checksumAlgo,\n                    @CryptoUtils.Mode @NonNull String crypto,\n                    @Nullable byte[] iv,\n                    @Nullable byte[] aes,\n                    @Nullable String keyIds) {\n            this.version = MetadataManager.getCurrentBackupMetaVersion();\n            this.backupTime = backupTime;\n            this.flags = flags;\n            this.userId = userId;\n            this.tarType = tarType;\n            this.checksumAlgo = checksumAlgo;\n            this.crypto = crypto;\n            this.iv = iv;\n            this.aes = aes;\n            this.keyIds = keyIds;\n            verifyCrypto();\n        }\n\n        public Info(@NonNull JSONObject rootObject) throws JSONException {\n            this.version = rootObject.getInt(\"version\");\n            this.backupTime = rootObject.getLong(\"backup_time\");\n            this.flags = new BackupFlags(rootObject.getInt(\"flags\"));\n            this.userId = rootObject.getInt(\"user_handle\");\n            this.tarType = rootObject.getString(\"tar_type\");\n            this.checksumAlgo = rootObject.getString(\"checksum_algo\");\n            this.crypto = rootObject.getString(\"crypto\");\n            this.keyIds = JSONUtils.optString(rootObject, \"key_ids\");\n            String aesKey = JSONUtils.optString(rootObject, \"aes\");\n            this.aes = aesKey != null ? HexEncoding.decode(aesKey) : null;\n            String iv = JSONUtils.optString(rootObject, \"iv\");\n            this.iv = iv != null ? HexEncoding.decode(iv) : null;\n            verifyCrypto();\n        }\n\n        public void setBackupItem(@NonNull BackupItems.BackupItem backupItem) {\n            mBackupItem = backupItem;\n            mRelativeDir = backupItem.getRelativeDir();\n        }\n\n        public BackupItems.BackupItem getBackupItem() {\n            return mBackupItem;\n        }\n\n        public String getRelativeDir() {\n            return mRelativeDir;\n        }\n\n        // Get crypto only works when crypto is already setup.\n        public Crypto getCrypto() throws CryptoException {\n            if (mCrypto == null) {\n                mCrypto = getCryptoInternal();\n            }\n            return mCrypto;\n        }\n\n        public long getBackupSize() {\n            if (mBackupItem == null) return 0L;\n            return Paths.size(mBackupItem.getBackupPath());\n        }\n\n        public boolean isFrozen() {\n            return mBackupItem != null && mBackupItem.isFrozen();\n        }\n\n        private void verifyCrypto() {\n            switch (crypto) {\n                case CryptoUtils.MODE_OPEN_PGP:\n                    Objects.requireNonNull(keyIds);\n                    assert !keyIds.isEmpty();\n                    break;\n                case CryptoUtils.MODE_RSA:\n                case CryptoUtils.MODE_ECC:\n                    Objects.requireNonNull(aes);\n                    assert aes.length > 0;\n                    // Deliberate fallthrough\n                case CryptoUtils.MODE_AES:\n                    Objects.requireNonNull(iv);\n                    assert iv.length > 0;\n                    break;\n                case CryptoUtils.MODE_NO_ENCRYPTION:\n                default:\n            }\n        }\n\n        @NonNull\n        private Crypto getCryptoInternal() throws CryptoException {\n            switch (crypto) {\n                case CryptoUtils.MODE_OPEN_PGP:\n                    Objects.requireNonNull(keyIds);\n                    return new OpenPGPCrypto(ContextUtils.getContext(), keyIds);\n                case CryptoUtils.MODE_AES: {\n                    Objects.requireNonNull(iv);\n                    AESCrypto aesCrypto = new AESCrypto(iv);\n                    if (version < 4) {\n                        // Old backups use 32 bit MAC\n                        aesCrypto.setMacSizeBits(AESCrypto.MAC_SIZE_BITS_OLD);\n                    }\n                    return aesCrypto;\n                }\n                case CryptoUtils.MODE_RSA: {\n                    Objects.requireNonNull(iv);\n                    Objects.requireNonNull(aes);\n                    RSACrypto rsaCrypto = new RSACrypto(iv, aes);\n                    if (version < 4) {\n                        // Old backups use 32 bit MAC\n                        rsaCrypto.setMacSizeBits(AESCrypto.MAC_SIZE_BITS_OLD);\n                    }\n                    return rsaCrypto;\n                }\n                case CryptoUtils.MODE_ECC: {\n                    Objects.requireNonNull(iv);\n                    Objects.requireNonNull(aes);\n                    ECCCrypto eccCrypto = new ECCCrypto(iv, aes);\n                    if (version < 4) {\n                        // Old backups use 32 bit MAC\n                        eccCrypto.setMacSizeBits(AESCrypto.MAC_SIZE_BITS_OLD);\n                    }\n                    return eccCrypto;\n                }\n                case CryptoUtils.MODE_NO_ENCRYPTION:\n                default:\n                    // Dummy crypto to generalise and return nonNull\n                    return new DummyCrypto();\n            }\n        }\n\n        @NonNull\n        @Override\n        public JSONObject serializeToJson() throws JSONException {\n            JSONObject rootObject = new JSONObject();\n            rootObject.put(\"backup_time\", backupTime);\n            rootObject.put(\"checksum_algo\", checksumAlgo);\n            rootObject.put(\"crypto\", crypto);\n            rootObject.put(\"key_ids\", keyIds);\n            rootObject.put(\"iv\", iv == null ? null : HexEncoding.encodeToString(iv));\n            rootObject.put(\"aes\", aes == null ? null : HexEncoding.encodeToString(aes));\n            rootObject.put(\"version\", version);\n            rootObject.put(\"flags\", flags.getFlags());\n            rootObject.put(\"user_handle\", userId);\n            rootObject.put(\"tar_type\", tarType);\n            return rootObject;\n        }\n\n\n    }\n\n    public static class Metadata implements IJsonSerializer {\n        // For backward compatibility only\n        public final int version;  // version\n        @Nullable\n        public final String backupName;  // backup_name\n        public boolean hasRules;  // has_rules\n        public String label;  // label\n        public String packageName;  // package_name\n        public String versionName;  // version_name\n        public long versionCode;  // version_code\n        public String[] dataDirs;  // data_dirs\n        public boolean isSystem;  // is_system\n        public boolean isSplitApk;  // is_split_apk\n        public String[] splitConfigs;  // split_configs\n        public String apkName;  // apk_name\n        public String instructionSet = VMRuntime.getInstructionSet(Build.SUPPORTED_ABIS[0]);  // instruction_set\n        public boolean keyStore;  // key_store\n        @Nullable\n        public String installer;  // installer\n\n        public Metadata(@Nullable String backupName) {\n            this.version = MetadataManager.getCurrentBackupMetaVersion();\n            this.backupName = backupName;\n        }\n\n        public Metadata(@NonNull Metadata metadata) {\n            version = metadata.version;\n            backupName = metadata.backupName;\n            label = metadata.label;\n            packageName = metadata.packageName;\n            versionName = metadata.versionName;\n            versionCode = metadata.versionCode;\n            if (metadata.dataDirs != null) {\n                dataDirs = metadata.dataDirs.clone();\n            }\n            isSystem = metadata.isSystem;\n            isSplitApk = metadata.isSplitApk;\n            if (metadata.splitConfigs != null) {\n                splitConfigs = metadata.splitConfigs.clone();\n            }\n            hasRules = metadata.hasRules;\n            apkName = metadata.apkName;\n            instructionSet = metadata.instructionSet;\n            keyStore = metadata.keyStore;\n            installer = metadata.installer;\n        }\n\n        public Metadata(@NonNull JSONObject rootObject) throws JSONException {\n            version = rootObject.getInt(\"version\");\n            backupName = JSONUtils.optString(rootObject, \"backup_name\");\n            label = rootObject.getString(\"label\");\n            packageName = rootObject.getString(\"package_name\");\n            versionName = rootObject.getString(\"version_name\");\n            versionCode = rootObject.getLong(\"version_code\");\n            dataDirs = JSONUtils.getArray(String.class, rootObject.getJSONArray(\"data_dirs\"));\n            isSystem = rootObject.getBoolean(\"is_system\");\n            isSplitApk = rootObject.getBoolean(\"is_split_apk\");\n            splitConfigs = JSONUtils.getArray(String.class, rootObject.getJSONArray(\"split_configs\"));\n            hasRules = rootObject.getBoolean(\"has_rules\");\n            apkName = rootObject.getString(\"apk_name\");\n            instructionSet = rootObject.getString(\"instruction_set\");\n            keyStore = rootObject.getBoolean(\"key_store\");\n            installer = JSONUtils.optString(rootObject, \"installer\");\n        }\n\n        @NonNull\n        @Override\n        public JSONObject serializeToJson() throws JSONException {\n            JSONObject rootObject = new JSONObject();\n            rootObject.put(\"version\", version);\n            rootObject.put(\"backup_name\", backupName);\n            rootObject.put(\"label\", label);\n            rootObject.put(\"package_name\", packageName);\n            rootObject.put(\"version_name\", versionName);\n            rootObject.put(\"version_code\", versionCode);\n            rootObject.put(\"data_dirs\", JSONUtils.getJSONArray(dataDirs));\n            rootObject.put(\"is_system\", isSystem);\n            rootObject.put(\"is_split_apk\", isSplitApk);\n            rootObject.put(\"split_configs\", JSONUtils.getJSONArray(splitConfigs));\n            rootObject.put(\"has_rules\", hasRules);\n            rootObject.put(\"apk_name\", apkName);\n            rootObject.put(\"instruction_set\", instructionSet);\n            rootObject.put(\"key_store\", keyStore);\n            rootObject.put(\"installer\", installer);\n            return rootObject;\n        }\n    }\n\n    @NonNull\n    public final Info info;\n    @NonNull\n    public final Metadata metadata;\n\n    public BackupMetadataV5(@NonNull Info info, @NonNull Metadata metadata) {\n        this.info = info;\n        this.metadata = metadata;\n    }\n\n    public boolean isBaseBackup() {\n        return TextUtils.isEmpty(metadata.backupName);\n    }\n\n    @Override\n    @NonNull\n    @WorkerThread\n    public CharSequence toLocalizedString(@NonNull Context context) {\n        CharSequence titleText = isBaseBackup() ? context.getText(R.string.base_backup) : Objects.requireNonNull(metadata.backupName);\n\n        StringBuilder subtitleText = new StringBuilder()\n                .append(DateUtils.formatDateTime(context, info.backupTime))\n                .append(\", \")\n                .append(info.flags.toLocalisedString(context))\n                .append(\", \")\n                .append(context.getString(R.string.version)).append(LangUtils.getSeparatorString()).append(metadata.versionName)\n                .append(\", \")\n                .append(context.getString(R.string.user_id)).append(LangUtils.getSeparatorString()).append(info.userId);\n        if (info.crypto.equals(CryptoUtils.MODE_NO_ENCRYPTION)) {\n            subtitleText.append(\", \").append(context.getString(R.string.no_encryption));\n        } else {\n            subtitleText.append(\", \").append(context.getString(R.string.pgp_aes_rsa_encrypted,\n                    info.crypto.toUpperCase(Locale.ROOT)));\n        }\n        subtitleText.append(\", \").append(context.getString(R.string.gz_bz2_compressed, getReadableTarType(info.tarType)));\n        subtitleText.append(\", \")\n                .append(context.getString(R.string.size)).append(LangUtils.getSeparatorString()).append(Formatter\n                        .formatFileSize(context, info.getBackupSize()));\n\n        if (info.isFrozen()) {\n            subtitleText.append(\", \").append(context.getText(R.string.frozen));\n        }\n\n        return new SpannableStringBuilder(getTitleText(context, titleText)).append(\"\\n\")\n                .append(getSmallerText(getSecondaryText(context, subtitleText)));\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/backup/struct/BackupOpOptions.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.backup.struct;\n\nimport android.annotation.UserIdInt;\nimport android.os.Parcel;\nimport android.os.Parcelable;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.core.os.ParcelCompat;\n\nimport org.json.JSONException;\nimport org.json.JSONObject;\n\nimport java.util.Objects;\n\nimport io.github.muntashirakon.AppManager.backup.BackupFlags;\nimport io.github.muntashirakon.AppManager.history.IJsonSerializer;\nimport io.github.muntashirakon.AppManager.utils.JSONUtils;\n\npublic class BackupOpOptions implements Parcelable, IJsonSerializer {\n    @NonNull\n    public final String packageName;\n    @UserIdInt\n    public final int userId;\n    public final BackupFlags flags;\n    @Nullable\n    public final String backupName;\n    public final boolean override;\n\n    public BackupOpOptions(@NonNull String packageName, int userId, int flags, @Nullable String backupName, boolean override) {\n        this.packageName = packageName;\n        this.userId = userId;\n        this.flags = new BackupFlags(flags);\n        this.backupName = backupName;\n        this.override = override;\n    }\n\n    protected BackupOpOptions(@NonNull Parcel in) {\n        packageName = Objects.requireNonNull(in.readString());\n        userId = in.readInt();\n        flags = new BackupFlags(in.readInt());\n        backupName = in.readString();\n        override = ParcelCompat.readBoolean(in);\n    }\n\n    public static final Creator<BackupOpOptions> CREATOR = new Creator<BackupOpOptions>() {\n        @Override\n        @NonNull\n        public BackupOpOptions createFromParcel(@NonNull Parcel in) {\n            return new BackupOpOptions(in);\n        }\n\n        @Override\n        @NonNull\n        public BackupOpOptions[] newArray(int size) {\n            return new BackupOpOptions[size];\n        }\n    };\n\n    @Override\n    public int describeContents() {\n        return 0;\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        dest.writeString(packageName);\n        dest.writeInt(userId);\n        dest.writeInt(this.flags.getFlags());\n        dest.writeString(backupName);\n        ParcelCompat.writeBoolean(dest, override);\n    }\n\n    public BackupOpOptions(@NonNull JSONObject jsonObject) throws JSONException {\n        packageName = jsonObject.getString(\"package_name\");\n        userId = jsonObject.getInt(\"user_id\");\n        flags = new BackupFlags(jsonObject.getInt(\"flags\"));\n        backupName = JSONUtils.optString(jsonObject, \"backup_name\");\n        override = jsonObject.getBoolean(\"override\");\n    }\n\n    @NonNull\n    @Override\n    public JSONObject serializeToJson() throws JSONException {\n        JSONObject jsonObject = new JSONObject();\n        jsonObject.put(\"package_name\", packageName);\n        jsonObject.put(\"user_id\", userId);\n        jsonObject.put(\"flags\", flags.getFlags());\n        jsonObject.put(\"backup_name\", backupName);\n        jsonObject.put(\"override\", override);\n        return jsonObject;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/backup/struct/DeleteOpOptions.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.backup.struct;\n\nimport android.annotation.UserIdInt;\nimport android.os.Parcel;\nimport android.os.Parcelable;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport org.json.JSONException;\nimport org.json.JSONObject;\n\nimport java.util.Objects;\n\nimport io.github.muntashirakon.AppManager.history.IJsonSerializer;\nimport io.github.muntashirakon.AppManager.utils.JSONUtils;\n\npublic class DeleteOpOptions implements Parcelable, IJsonSerializer {\n    @NonNull\n    public final String packageName;\n    @UserIdInt\n    public final int userId;\n    @Nullable\n    public final String[] relativeDirs;\n\n    public DeleteOpOptions(@NonNull String packageName, @UserIdInt int userId, @Nullable String[] relativeDirs) {\n        this.packageName = packageName;\n        this.userId = userId;\n        this.relativeDirs = relativeDirs;\n    }\n\n    protected DeleteOpOptions(@NonNull Parcel in) {\n        packageName = Objects.requireNonNull(in.readString());\n        userId = in.readInt();\n        relativeDirs = Objects.requireNonNull(in.createStringArray());\n    }\n\n    public static final Creator<DeleteOpOptions> CREATOR = new Creator<DeleteOpOptions>() {\n        @Override\n        @NonNull\n        public DeleteOpOptions createFromParcel(@NonNull Parcel in) {\n            return new DeleteOpOptions(in);\n        }\n\n        @Override\n        @NonNull\n        public DeleteOpOptions[] newArray(int size) {\n            return new DeleteOpOptions[size];\n        }\n    };\n\n    @Override\n    public int describeContents() {\n        return 0;\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        dest.writeString(packageName);\n        dest.writeInt(userId);\n        dest.writeStringArray(relativeDirs);\n    }\n\n    public DeleteOpOptions(@NonNull JSONObject jsonObject) throws JSONException {\n        packageName = jsonObject.getString(\"package_name\");\n        userId = jsonObject.getInt(\"user_id\");\n        relativeDirs = JSONUtils.getArray(String.class, jsonObject.optJSONArray(\"relative_dirs\"));\n    }\n\n    @NonNull\n    @Override\n    public JSONObject serializeToJson() throws JSONException {\n        JSONObject jsonObject = new JSONObject();\n        jsonObject.put(\"package_name\", packageName);\n        jsonObject.put(\"user_id\", userId);\n        jsonObject.put(\"relative_dirs\", JSONUtils.getJSONArray(relativeDirs));\n        return jsonObject;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/backup/struct/RestoreOpOptions.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.backup.struct;\n\nimport android.annotation.UserIdInt;\nimport android.os.Parcel;\nimport android.os.Parcelable;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport org.json.JSONException;\nimport org.json.JSONObject;\n\nimport java.util.Objects;\n\nimport io.github.muntashirakon.AppManager.backup.BackupFlags;\nimport io.github.muntashirakon.AppManager.history.IJsonSerializer;\nimport io.github.muntashirakon.AppManager.utils.JSONUtils;\n\npublic class RestoreOpOptions implements Parcelable, IJsonSerializer {\n    @NonNull\n    public final String packageName;\n    @UserIdInt\n    public final int userId;\n    @Nullable\n    public final String relativeDir;\n    public final BackupFlags flags;\n\n    public RestoreOpOptions(@NonNull String packageName, int userId, @Nullable String relativeDir, int flags) {\n        this.packageName = packageName;\n        this.userId = userId;\n        this.relativeDir = relativeDir;\n        this.flags = new BackupFlags(flags);\n    }\n\n    protected RestoreOpOptions(@NonNull Parcel in) {\n        packageName = Objects.requireNonNull(in.readString());\n        userId = in.readInt();\n        relativeDir = in.readString();\n        flags = new BackupFlags(in.readInt());\n    }\n\n    public static final Creator<RestoreOpOptions> CREATOR = new Creator<RestoreOpOptions>() {\n        @Override\n        @NonNull\n        public RestoreOpOptions createFromParcel(@NonNull Parcel in) {\n            return new RestoreOpOptions(in);\n        }\n\n        @Override\n        @NonNull\n        public RestoreOpOptions[] newArray(int size) {\n            return new RestoreOpOptions[size];\n        }\n    };\n\n    @Override\n    public int describeContents() {\n        return 0;\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        dest.writeString(packageName);\n        dest.writeInt(userId);\n        dest.writeString(relativeDir);\n        dest.writeInt(this.flags.getFlags());\n    }\n\n    public RestoreOpOptions(@NonNull JSONObject jsonObject) throws JSONException {\n        packageName = jsonObject.getString(\"package_name\");\n        userId = jsonObject.getInt(\"user_id\");\n        relativeDir = JSONUtils.optString(jsonObject, \"relative_dir\");\n        flags = new BackupFlags(jsonObject.getInt(\"flags\"));\n    }\n\n    @NonNull\n    @Override\n    public JSONObject serializeToJson() throws JSONException {\n        JSONObject jsonObject = new JSONObject();\n        jsonObject.put(\"package_name\", packageName);\n        jsonObject.put(\"user_id\", userId);\n        jsonObject.put(\"relative_dir\", relativeDir);\n        jsonObject.put(\"flags\", flags.getFlags());\n        return jsonObject;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/batchops/BatchOpsLogger.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.batchops;\n\nimport androidx.annotation.NonNull;\n\nimport java.io.File;\nimport java.io.IOException;\n\nimport io.github.muntashirakon.AppManager.logs.Logger;\nimport io.github.muntashirakon.io.Paths;\n\npublic class BatchOpsLogger extends Logger {\n    private static final File LOG_FILE = new File(getLoggingDirectory(), \"batch_ops.log\");\n\n    protected BatchOpsLogger() throws IOException {\n        super(LOG_FILE, false);\n    }\n\n    @NonNull\n    public static String getAllLogs() {\n        return Paths.get(LOG_FILE).getContentAsString();\n    }\n\n    public static void clearLogs() {\n        LOG_FILE.delete();\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/batchops/BatchOpsManager.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.batchops;\n\nimport android.Manifest;\nimport android.annotation.UserIdInt;\nimport android.app.AppOpsManager;\nimport android.content.Context;\nimport android.content.pm.ApplicationInfo;\nimport android.content.pm.IPackageManager;\nimport android.content.pm.PackageManager;\nimport android.net.Uri;\nimport android.os.Build;\nimport android.os.RemoteException;\nimport android.os.UserHandleHidden;\n\nimport androidx.annotation.CheckResult;\nimport androidx.annotation.IntDef;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.RequiresApi;\nimport androidx.annotation.WorkerThread;\n\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Objects;\nimport java.util.Optional;\nimport java.util.Set;\nimport java.util.concurrent.atomic.AtomicBoolean;\nimport java.util.concurrent.atomic.AtomicInteger;\n\nimport io.github.muntashirakon.AppManager.BuildConfig;\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.accessibility.AccessibilityMultiplexer;\nimport io.github.muntashirakon.AppManager.apk.ApkUtils;\nimport io.github.muntashirakon.AppManager.apk.dexopt.DexOptOptions;\nimport io.github.muntashirakon.AppManager.apk.dexopt.DexOptimizer;\nimport io.github.muntashirakon.AppManager.apk.installer.PackageInstallerCompat;\nimport io.github.muntashirakon.AppManager.backup.BackupException;\nimport io.github.muntashirakon.AppManager.backup.BackupManager;\nimport io.github.muntashirakon.AppManager.backup.convert.ConvertUtils;\nimport io.github.muntashirakon.AppManager.backup.convert.Converter;\nimport io.github.muntashirakon.AppManager.backup.dialog.BackupRestoreDialogFragment;\nimport io.github.muntashirakon.AppManager.batchops.struct.BatchAppOpsOptions;\nimport io.github.muntashirakon.AppManager.batchops.struct.BatchBackupImportOptions;\nimport io.github.muntashirakon.AppManager.batchops.struct.BatchBackupOptions;\nimport io.github.muntashirakon.AppManager.batchops.struct.BatchComponentOptions;\nimport io.github.muntashirakon.AppManager.batchops.struct.BatchDexOptOptions;\nimport io.github.muntashirakon.AppManager.batchops.struct.BatchFreezeOptions;\nimport io.github.muntashirakon.AppManager.batchops.struct.BatchNetPolicyOptions;\nimport io.github.muntashirakon.AppManager.batchops.struct.BatchPermissionOptions;\nimport io.github.muntashirakon.AppManager.batchops.struct.IBatchOpOptions;\nimport io.github.muntashirakon.AppManager.compat.AppOpsManagerCompat;\nimport io.github.muntashirakon.AppManager.compat.NetworkPolicyManagerCompat;\nimport io.github.muntashirakon.AppManager.compat.PackageManagerCompat;\nimport io.github.muntashirakon.AppManager.compat.PermissionCompat;\nimport io.github.muntashirakon.AppManager.compat.StorageManagerCompat;\nimport io.github.muntashirakon.AppManager.logs.Logger;\nimport io.github.muntashirakon.AppManager.progress.NotificationProgressHandler;\nimport io.github.muntashirakon.AppManager.progress.NotificationProgressHandler.NotificationInfo;\nimport io.github.muntashirakon.AppManager.progress.ProgressHandler;\nimport io.github.muntashirakon.AppManager.rules.compontents.ComponentUtils;\nimport io.github.muntashirakon.AppManager.rules.compontents.ComponentsBlocker;\nimport io.github.muntashirakon.AppManager.rules.compontents.ExternalComponentsImporter;\nimport io.github.muntashirakon.AppManager.self.SelfPermissions;\nimport io.github.muntashirakon.AppManager.types.UserPackagePair;\nimport io.github.muntashirakon.AppManager.utils.ArrayUtils;\nimport io.github.muntashirakon.AppManager.utils.ContextUtils;\nimport io.github.muntashirakon.AppManager.utils.ExUtils;\nimport io.github.muntashirakon.AppManager.utils.FreezeUtils;\nimport io.github.muntashirakon.AppManager.utils.MultithreadedExecutor;\nimport io.github.muntashirakon.AppManager.utils.PackageUtils;\nimport io.github.muntashirakon.AppManager.utils.ThreadUtils;\nimport io.github.muntashirakon.io.Path;\nimport io.github.muntashirakon.io.Paths;\n\n@WorkerThread\npublic class BatchOpsManager {\n    public static final String TAG = \"BatchOpsManager\";\n\n    @IntDef(value = {\n            OP_NONE,\n            OP_ADVANCED_FREEZE,\n            OP_BACKUP_APK,\n            OP_BACKUP,\n            OP_BLOCK_COMPONENTS,\n            OP_BLOCK_TRACKERS,\n            OP_CLEAR_CACHE,\n            OP_CLEAR_DATA,\n            OP_DELETE_BACKUP,\n            OP_DEXOPT,\n            OP_DISABLE_BACKGROUND,\n            OP_EXPORT_RULES,\n            OP_FORCE_STOP,\n            OP_FREEZE,\n            OP_GRANT_PERMISSIONS,\n            OP_IMPORT_BACKUPS,\n            OP_NET_POLICY,\n            OP_REVOKE_PERMISSIONS,\n            OP_RESTORE_BACKUP,\n            OP_SET_APP_OPS,\n            OP_UNBLOCK_COMPONENTS,\n            OP_UNBLOCK_TRACKERS,\n            OP_UNINSTALL,\n            OP_UNFREEZE,\n    })\n    @Retention(RetentionPolicy.SOURCE)\n    public @interface OpType {\n    }\n\n    public static final int OP_NONE = -1;\n    public static final int OP_BACKUP_APK = 0;\n    public static final int OP_BACKUP = 1;\n    public static final int OP_BLOCK_TRACKERS = 2;\n    public static final int OP_CLEAR_DATA = 3;\n    public static final int OP_DELETE_BACKUP = 4;\n    public static final int OP_FREEZE = 5;\n    public static final int OP_DISABLE_BACKGROUND = 6;\n    public static final int OP_EXPORT_RULES = 7;\n    public static final int OP_FORCE_STOP = 8;\n    public static final int OP_RESTORE_BACKUP = 9;\n    public static final int OP_UNBLOCK_TRACKERS = 10;\n    public static final int OP_UNINSTALL = 11;\n    public static final int OP_BLOCK_COMPONENTS = 12;\n    public static final int OP_SET_APP_OPS = 13;\n    public static final int OP_UNFREEZE = 14;\n    public static final int OP_UNBLOCK_COMPONENTS = 15;\n    public static final int OP_CLEAR_CACHE = 16;\n    public static final int OP_GRANT_PERMISSIONS = 17;\n    public static final int OP_REVOKE_PERMISSIONS = 18;\n    public static final int OP_IMPORT_BACKUPS = 19;\n    public static final int OP_NET_POLICY = 20;\n    public static final int OP_DEXOPT = 21;\n    public static final int OP_ADVANCED_FREEZE = 22;\n\n    private static final String GROUP_ID = BuildConfig.APPLICATION_ID + \".notification_group.BATCH_OPS\";\n\n    public static class BatchOpsInfo {\n        @NonNull\n        public static BatchOpsInfo fromQueue(@NonNull BatchQueueItem queueItem) {\n            return new BatchOpsInfo(queueItem.getOp(), queueItem.getPackages(),\n                    queueItem.getUsers(), queueItem.getOptions());\n        }\n\n        @NonNull\n        public static BatchOpsInfo fromUserPackagePair(@OpType int op,\n                                                       @NonNull List<UserPackagePair> pairs,\n                                                       @Nullable IBatchOpOptions options) {\n            Result result = new Result(pairs);\n            return new BatchOpsInfo(op, result.getFailedPackages(), result.getAssociatedUsers(),\n                    options);\n        }\n\n        @NonNull\n        public static BatchOpsInfo getInstance(@OpType int op,\n                                               @NonNull List<String> packages,\n                                               @NonNull List<Integer> users,\n                                               @Nullable IBatchOpOptions options) {\n            return new BatchOpsInfo(op, packages, users, options);\n        }\n\n        @OpType\n        public final int op;\n        @NonNull\n        public final List<String> packages;\n        @NonNull\n        public final List<Integer> users;\n        @Nullable\n        public final IBatchOpOptions options;\n\n        private BatchOpsInfo(\n                @OpType int op,\n                @NonNull List<String> packages,\n                @NonNull List<Integer> users,\n                @Nullable IBatchOpOptions options) {\n            this.op = op;\n            this.packages = Collections.unmodifiableList(packages);\n            this.users = Collections.unmodifiableList(users);\n            this.options = options;\n\n            assert packages.size() == users.size();\n        }\n\n        public int size() {\n            return packages.size();\n        }\n\n        @NonNull\n        public UserPackagePair getPair(int index) {\n            return new UserPackagePair(packages.get(index), users.get(index));\n        }\n\n        public List<UserPackagePair> getPairList() {\n            List<UserPackagePair> userPackagePairs = new ArrayList<>(packages.size());\n            int size = size();\n            for (int i = 0; i < size; ++i) {\n                userPackagePairs.add(getPair(i));\n            }\n            return Collections.unmodifiableList(userPackagePairs);\n        }\n    }\n\n    @Nullable\n    public Logger mLogger;\n    public final boolean mCustomLogger;\n\n    @Nullable\n    private ProgressHandler mProgressHandler;\n\n    public BatchOpsManager() {\n        mCustomLogger = false;\n        mLogger = ExUtils.exceptionAsNull(BatchOpsLogger::new);\n    }\n\n    public BatchOpsManager(@Nullable Logger logger) {\n        mLogger = logger;\n        mCustomLogger = true;\n    }\n\n    public Result performOp(@NonNull BatchOpsInfo info, @Nullable ProgressHandler progressHandler) {\n        mProgressHandler = progressHandler;\n        return performOp(info);\n    }\n\n    @CheckResult\n    @NonNull\n    private Result performOp(@NonNull BatchOpsInfo info) {\n        switch (info.op) {\n            case OP_ADVANCED_FREEZE:\n                return opFreeze(info);\n            case OP_BACKUP_APK:\n                return opBackupApk(info);\n            case OP_BACKUP:\n                return opBackupRestore(info, BackupRestoreDialogFragment.MODE_BACKUP);\n            case OP_BLOCK_TRACKERS:\n                return opBlockTrackers(info);\n            case OP_CLEAR_DATA:\n                return opClearData(info);\n            case OP_DELETE_BACKUP:\n                return opBackupRestore(info, BackupRestoreDialogFragment.MODE_DELETE);\n            case OP_FREEZE:\n                return opFreezeUnfreeze(info, true);\n            case OP_DISABLE_BACKGROUND:\n                return opDisableBackground(info);\n            case OP_UNFREEZE:\n                return opFreezeUnfreeze(info, false);\n            case OP_EXPORT_RULES:\n                break;  // Done in the main activity\n            case OP_FORCE_STOP:\n                return opForceStop(info);\n            case OP_RESTORE_BACKUP:\n                return opBackupRestore(info, BackupRestoreDialogFragment.MODE_RESTORE);\n            case OP_UNINSTALL:\n                return opUninstall(info);\n            case OP_UNBLOCK_TRACKERS:\n                return opUnblockTrackers(info);\n            case OP_BLOCK_COMPONENTS:\n                return opBlockComponents(info);\n            case OP_SET_APP_OPS:\n                return opSetAppOps(info);\n            case OP_UNBLOCK_COMPONENTS:\n                return opUnblockComponents(info);\n            case OP_CLEAR_CACHE:\n                return opClearCache(info);\n            case OP_GRANT_PERMISSIONS:\n                return opGrantOrRevokePermissions(info, true);\n            case OP_REVOKE_PERMISSIONS:\n                return opGrantOrRevokePermissions(info, false);\n            case OP_IMPORT_BACKUPS:\n                return opImportBackups(info);\n            case OP_NET_POLICY:\n                return opNetPolicy(info);\n            case OP_DEXOPT:\n                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {\n                    return opPerformDexOpt(info);\n                }\n                return new Result(Collections.emptyList(), false);\n            case OP_NONE:\n                break;\n        }\n        return new Result(info.getPairList());\n    }\n\n    public void conclude() {\n        if (!mCustomLogger && mLogger != null) {\n            mLogger.close();\n        }\n    }\n\n    @NonNull\n    private Result opBackupApk(@NonNull BatchOpsInfo info) {\n        List<UserPackagePair> failedPackages = new ArrayList<>();\n        int max = info.size();\n        // Initial progress\n        float lastProgress = mProgressHandler != null ? mProgressHandler.getLastProgress() : 0;\n        Context context = ContextUtils.getContext();\n        UserPackagePair pair;\n        for (int i = 0; i < max; ++i) {\n            pair = info.getPair(i);\n            updateProgress(lastProgress, i + 1);\n            // Do operation\n            try {\n                ApkUtils.backupApk(context, pair.getPackageName(), pair.getUserId());\n            } catch (Exception e) {\n                failedPackages.add(pair);\n                log(\"====> op=BACKUP_APK, pkg=\" + pair, e);\n            }\n        }\n        return new Result(failedPackages);\n    }\n\n    @NonNull\n    private Result opBackupRestore(@NonNull BatchOpsInfo info, @BackupRestoreDialogFragment.ActionMode int mode) {\n        switch (mode) {\n            case BackupRestoreDialogFragment.MODE_BACKUP:\n                return backup(info);\n            case BackupRestoreDialogFragment.MODE_RESTORE:\n                return restoreBackups(info);\n            case BackupRestoreDialogFragment.MODE_DELETE:\n                return deleteBackups(info);\n        }\n        return new Result(info.getPairList());\n    }\n\n    @NonNull\n    private Result backup(@NonNull BatchOpsInfo info) {\n        List<UserPackagePair> failedPackages = Collections.synchronizedList(new ArrayList<>());\n        Context context = ContextUtils.getContext();\n        PackageManager pm = context.getPackageManager();\n        CharSequence operationName = context.getString(R.string.backup_restore);\n        MultithreadedExecutor executor = MultithreadedExecutor.getNewInstance();\n        AtomicInteger counter = new AtomicInteger(0);\n        float lastProgress = mProgressHandler != null ? mProgressHandler.getLastProgress() : 0;\n        try {\n            BatchBackupOptions options = Objects.requireNonNull((BatchBackupOptions) info.options);\n            int max = info.size();\n            BackupManager backupManager = new BackupManager();\n            for (int i = 0; i < max; ++i) {\n                UserPackagePair pair = info.getPair(i);\n                executor.submit(() -> {\n                    synchronized (counter) {\n                        counter.set(counter.get() + 1);\n                        updateProgress(lastProgress, counter.get());\n                    }\n                    CharSequence appLabel = PackageUtils.getPackageLabel(pm, pair.getPackageName(), pair.getUserId());\n                    CharSequence title = context.getString(R.string.backing_up_app, appLabel);\n                    ProgressHandler subProgressHandler = newSubProgress(operationName, title);\n                    try {\n                        backupManager.backup(options.getBackupOpOptions(pair.getPackageName(), pair.getUserId()), subProgressHandler);\n                    } catch (BackupException e) {\n                        log(\"====> op=BACKUP_RESTORE, mode=BACKUP pkg=\" + pair, e);\n                        failedPackages.add(pair);\n                    }\n                    if (subProgressHandler != null) {\n                        ThreadUtils.postOnMainThread(() -> subProgressHandler.onResult(null));\n                    }\n                });\n            }\n        } catch (Throwable th) {\n            log(\"====> op=BACKUP_RESTORE, mode=BACKUP\", th);\n        }\n        executor.awaitCompletion();\n        return new Result(failedPackages);\n    }\n\n    @NonNull\n    private Result restoreBackups(@NonNull BatchOpsInfo info) {\n        List<UserPackagePair> failedPackages = Collections.synchronizedList(new ArrayList<>());\n        Context context = ContextUtils.getContext();\n        PackageManager pm = context.getPackageManager();\n        CharSequence operationName = context.getString(R.string.backup_restore);\n        MultithreadedExecutor executor = MultithreadedExecutor.getNewInstance();\n        AtomicBoolean requiresRestart = new AtomicBoolean();\n        AtomicInteger count = new AtomicInteger(0);\n        float lastProgress = mProgressHandler != null ? mProgressHandler.getLastProgress() : 0;\n        try {\n            BatchBackupOptions options = Objects.requireNonNull((BatchBackupOptions) info.options);\n            int max = info.size();\n            BackupManager backupManager = new BackupManager();\n            for (int i = 0; i < max; ++i) {\n                UserPackagePair pair = info.getPair(i);\n                executor.submit(() -> {\n                    synchronized (count) {\n                        count.set(count.get() + 1);\n                        updateProgress(lastProgress, count.get());\n                    }\n                    CharSequence appLabel = PackageUtils.getPackageLabel(pm, pair.getPackageName(), pair.getUserId());\n                    CharSequence title = context.getString(R.string.restoring_app, appLabel);\n                    ProgressHandler subProgressHandler = newSubProgress(operationName, title);\n                    try {\n                        backupManager.restore(options.getRestoreOpOptions(pair.getPackageName(), pair.getUserId()), subProgressHandler);\n                        requiresRestart.set(requiresRestart.get() | backupManager.requiresRestart());\n                    } catch (Throwable e) {\n                        log(\"====> op=BACKUP_RESTORE, mode=RESTORE pkg=\" + pair, e);\n                        failedPackages.add(pair);\n                    }\n                    if (subProgressHandler != null) {\n                        ThreadUtils.postOnMainThread(() -> subProgressHandler.onResult(null));\n                    }\n                });\n            }\n        } catch (Throwable th) {\n            log(\"====> op=BACKUP_RESTORE, mode=RESTORE\", th);\n        }\n        executor.awaitCompletion();\n        Result result = new Result(failedPackages);\n        result.setRequiresRestart(requiresRestart.get());\n        return result;\n    }\n\n    @NonNull\n    private Result deleteBackups(@NonNull BatchOpsInfo info) {\n        List<UserPackagePair> failedPackages = new ArrayList<>();\n        float lastProgress = mProgressHandler != null ? mProgressHandler.getLastProgress() : 0;\n        try {\n            BatchBackupOptions options = Objects.requireNonNull((BatchBackupOptions) info.options);\n            int max = info.size();\n            BackupManager backupManager = new BackupManager();\n            UserPackagePair pair;\n            for (int i = 0; i < max; ++i) {\n                updateProgress(lastProgress, i + 1);\n                pair = info.getPair(i);\n                try {\n                    backupManager.deleteBackup(options.getDeleteOpOptions(pair.getPackageName(), pair.getUserId()));\n                } catch (BackupException e) {\n                    log(\"====> op=BACKUP_RESTORE, mode=DELETE pkg=\" + pair, e);\n                    failedPackages.add(pair);\n                }\n            }\n        } catch (Throwable th) {\n            log(\"====> op=BACKUP_RESTORE, mode=DELETE\", th);\n        }\n        return new Result(failedPackages);\n    }\n\n    @NonNull\n    private Result opImportBackups(@NonNull BatchOpsInfo info) {\n        final List<UserPackagePair> failedPkgList = Collections.synchronizedList(new ArrayList<>());\n        MultithreadedExecutor executor = MultithreadedExecutor.getNewInstance();\n        try {\n            int userId = UserHandleHidden.myUserId();\n            BatchBackupImportOptions options = (BatchBackupImportOptions) Objects.requireNonNull(info.options);\n            Uri uri = options.getDirectory();\n            Path backupPath = Paths.get(uri);\n            if (!backupPath.isDirectory()) {\n                log(\"====> op=IMPORT_BACKUP, Not a directory.\");\n                return new Result(Collections.emptyList(), false);\n            }\n            Path[] files = ConvertUtils.getRelevantImportFiles(backupPath, options.getImportType());\n            fixProgress(files.length);\n            float lastProgress = mProgressHandler != null ? mProgressHandler.getLastProgress() : 0;\n            AtomicInteger i = new AtomicInteger(0);\n            for (Path file : files) {\n                executor.submit(() -> {\n                    synchronized (i) {\n                        i.set(i.get() + 1);\n                        updateProgress(lastProgress, i.get());\n                    }\n                    Converter converter = ConvertUtils.getConversionUtil(options.getImportType(), file);\n                    try {\n                        converter.convert();\n                        if (options.isRemoveImportedDirectory()) {\n                            // Since the conversion was successful, remove the files for it.\n                            converter.cleanup();\n                        }\n                    } catch (BackupException e) {\n                        log(\"====> op=IMPORT_BACKUP, pkg=\" + converter.getPackageName(), e);\n                        failedPkgList.add(new UserPackagePair(converter.getPackageName(), userId));\n                    }\n                });\n            }\n        } catch (Throwable th) {\n            log(\"====> op=IMPORT_BACKUP\", th);\n        }\n        executor.awaitCompletion();\n        return new Result(failedPkgList);\n    }\n\n    @NonNull\n    private Result opBlockComponents(@NonNull BatchOpsInfo info) {\n        BatchComponentOptions options = (BatchComponentOptions) Objects.requireNonNull(info.options);\n        List<UserPackagePair> failedPackages = new ArrayList<>();\n        float lastProgress = mProgressHandler != null ? mProgressHandler.getLastProgress() : 0;\n        int max = info.size();\n        UserPackagePair pair;\n        for (int i = 0; i < max; ++i) {\n            updateProgress(lastProgress, i + 1);\n            pair = info.getPair(i);\n            try {\n                ComponentUtils.blockFilteredComponents(pair, options.getSignatures());\n            } catch (Exception e) {\n                log(\"====> op=BLOCK_COMPONENTS, pkg=\" + pair, e);\n                failedPackages.add(pair);\n            }\n        }\n        return new Result(failedPackages);\n    }\n\n    @NonNull\n    private Result opBlockTrackers(@NonNull BatchOpsInfo info) {\n        List<UserPackagePair> failedPackages = new ArrayList<>();\n        float lastProgress = mProgressHandler != null ? mProgressHandler.getLastProgress() : 0;\n        int max = info.size();\n        UserPackagePair pair;\n        for (int i = 0; i < max; ++i) {\n            updateProgress(lastProgress, i + 1);\n            pair = info.getPair(i);\n            try {\n                ComponentUtils.blockTrackingComponents(pair);\n            } catch (Exception e) {\n                log(\"====> op=BLOCK_TRACKERS, pkg=\" + pair, e);\n                failedPackages.add(pair);\n            }\n        }\n        return new Result(failedPackages);\n    }\n\n    @NonNull\n    private Result opClearCache(@NonNull BatchOpsInfo info) {\n        if (info.size() == 0) {\n            // No packages supplied means trim all caches\n            return opTrimCaches();\n        }\n        List<UserPackagePair> failedPackages = new ArrayList<>();\n        float lastProgress = mProgressHandler != null ? mProgressHandler.getLastProgress() : 0;\n        int max = info.size();\n        UserPackagePair pair;\n        for (int i = 0; i < max; ++i) {\n            updateProgress(lastProgress, i + 1);\n            pair = info.getPair(i);\n            try {\n                PackageManagerCompat.deleteApplicationCacheFilesAsUser(pair);\n            } catch (Exception e) {\n                log(\"====> op=CLEAR_CACHE, pkg=\" + pair, e);\n                failedPackages.add(pair);\n            }\n        }\n        return new Result(failedPackages);\n    }\n\n    @NonNull\n    private Result opTrimCaches() {\n        long size = 1024L * 1024L * 1024L * 1024L;  // 1 TB\n        boolean isSuccessful;\n        try {\n            // TODO: 30/8/21 Iterate all volumes?\n            PackageManagerCompat.freeStorageAndNotify(null /* internal */, size,\n                    StorageManagerCompat.FLAG_ALLOCATE_DEFY_ALL_RESERVED);\n            isSuccessful = true;\n        } catch (Throwable e) {\n            log(\"====> op=TRIM_CACHES\", e);\n            isSuccessful = false;\n        }\n        return new Result(Collections.emptyList(), isSuccessful);\n    }\n\n    @NonNull\n    private Result opClearData(@NonNull BatchOpsInfo info) {\n        List<UserPackagePair> failedPackages = new ArrayList<>();\n        float lastProgress = mProgressHandler != null ? mProgressHandler.getLastProgress() : 0;\n        int max = info.size();\n        UserPackagePair pair;\n        for (int i = 0; i < max; ++i) {\n            updateProgress(lastProgress, i + 1);\n            pair = info.getPair(i);\n            try {\n                PackageManagerCompat.clearApplicationUserData(pair);\n            } catch (Exception e) {\n                log(\"====> op=CLEAR_DATA, pkg=\" + pair, e);\n                failedPackages.add(pair);\n            }\n        }\n        return new Result(failedPackages);\n    }\n\n    @NonNull\n    private Result opFreeze(@NonNull BatchOpsInfo info) {\n        BatchFreezeOptions options = (BatchFreezeOptions) Objects.requireNonNull(info.options);\n        List<UserPackagePair> failedPackages = new ArrayList<>();\n        float lastProgress = mProgressHandler != null ? mProgressHandler.getLastProgress() : 0;\n        int max = info.size();\n        UserPackagePair pair;\n        for (int i = 0; i < max; ++i) {\n            updateProgress(lastProgress, i + 1);\n            pair = info.getPair(i);\n            int type;\n            if (options.isPreferCustom()) {\n                type = Optional.ofNullable(FreezeUtils.loadFreezeMethod(pair.getPackageName()))\n                        .orElse(options.getType());\n            } else type = options.getType();\n            try {\n                FreezeUtils.freeze(pair.getPackageName(), pair.getUserId(), type);\n            } catch (Throwable e) {\n                log(\"====> op=ADVANCED_FREEZE, pkg=\" + pair + \", type = \" + type, e);\n                failedPackages.add(pair);\n            }\n        }\n        return new Result(failedPackages);\n    }\n\n    @NonNull\n    private Result opFreezeUnfreeze(@NonNull BatchOpsInfo info, boolean freeze) {\n        List<UserPackagePair> failedPackages = new ArrayList<>();\n        float lastProgress = mProgressHandler != null ? mProgressHandler.getLastProgress() : 0;\n        int max = info.size();\n        UserPackagePair pair;\n        for (int i = 0; i < max; ++i) {\n            updateProgress(lastProgress, i + 1);\n            pair = info.getPair(i);\n            try {\n                if (freeze) {\n                    FreezeUtils.freeze(pair.getPackageName(), pair.getUserId());\n                } else {\n                    FreezeUtils.unfreeze(pair.getPackageName(), pair.getUserId());\n                }\n            } catch (Throwable e) {\n                log(\"====> op=APP_FREEZE, pkg=\" + pair + \", freeze = \" + freeze, e);\n                failedPackages.add(pair);\n            }\n        }\n        return new Result(failedPackages);\n    }\n\n    @NonNull\n    private Result opDisableBackground(@NonNull BatchOpsInfo info) {\n        List<UserPackagePair> failedPackages = new ArrayList<>();\n        float lastProgress = mProgressHandler != null ? mProgressHandler.getLastProgress() : 0;\n        AppOpsManagerCompat appOpsManager = new AppOpsManagerCompat();\n        int max = info.size();\n        UserPackagePair pair;\n        for (int i = 0; i < max; ++i) {\n            updateProgress(lastProgress, i + 1);\n            pair = info.getPair(i);\n            int uid = PackageUtils.getAppUid(pair);\n            if (uid == -1) {\n                failedPackages.add(pair);\n                continue;\n            }\n            try {\n                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {\n                    appOpsManager.setMode(AppOpsManagerCompat.OP_RUN_IN_BACKGROUND, uid,\n                            pair.getPackageName(), AppOpsManager.MODE_IGNORED);\n                }\n                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {\n                    appOpsManager.setMode(AppOpsManagerCompat.OP_RUN_ANY_IN_BACKGROUND, uid,\n                            pair.getPackageName(), AppOpsManager.MODE_IGNORED);\n                }\n                try (ComponentsBlocker cb = ComponentsBlocker.getMutableInstance(pair.getPackageName(), pair.getUserId())) {\n                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {\n                        cb.setAppOp(AppOpsManagerCompat.OP_RUN_IN_BACKGROUND, AppOpsManager.MODE_IGNORED);\n                    }\n                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {\n                        cb.setAppOp(AppOpsManagerCompat.OP_RUN_ANY_IN_BACKGROUND, AppOpsManager.MODE_IGNORED);\n                    }\n                }\n            } catch (Throwable e) {\n                log(\"====> op=DISABLE_BACKGROUND, pkg=\" + pair, e);\n                failedPackages.add(pair);\n            }\n        }\n        return new Result(failedPackages);\n    }\n\n    @NonNull\n    private Result opGrantOrRevokePermissions(@NonNull BatchOpsInfo info, boolean isGrant) {\n        BatchPermissionOptions options = (BatchPermissionOptions) Objects.requireNonNull(info.options);\n        String[] permissions = options.getPermissions();\n        List<UserPackagePair> failedPackages = new ArrayList<>();\n        float lastProgress = mProgressHandler != null ? mProgressHandler.getLastProgress() : 0;\n        int max = info.size();\n        UserPackagePair pair;\n        if (permissions.length == 1 && permissions[0].equals(\"*\")) {\n            // Wildcard detected\n            for (int i = 0; i < max; ++i) {\n                updateProgress(lastProgress, i + 1);\n                pair = info.getPair(i);\n                try {\n                    permissions = PackageUtils.getPermissionsForPackage(pair.getPackageName(), pair.getUserId());\n                    if (permissions == null) continue;\n                    for (String permission : permissions) {\n                        if (isGrant) {\n                            PermissionCompat.grantPermission(pair.getPackageName(), permission, pair.getUserId());\n                        } else {\n                            PermissionCompat.revokePermission(pair.getPackageName(), permission, pair.getUserId());\n                        }\n                    }\n                } catch (Throwable e) {\n                    log(\"====> op=GRANT_OR_REVOKE_PERMISSIONS, pkg=\" + pair, e);\n                    failedPackages.add(pair);\n                }\n            }\n        } else {\n            for (int i = 0; i < max; ++i) {\n                updateProgress(lastProgress, i + 1);\n                pair = info.getPair(i);\n                for (String permission : permissions) {\n                    try {\n                        if (isGrant) {\n                            PermissionCompat.grantPermission(pair.getPackageName(), permission, pair.getUserId());\n                        } else {\n                            PermissionCompat.revokePermission(pair.getPackageName(), permission, pair.getUserId());\n                        }\n                    } catch (Throwable e) {\n                        log(\"====> op=GRANT_OR_REVOKE_PERMISSIONS, pkg=\" + pair, e);\n                        failedPackages.add(pair);\n                    }\n                }\n            }\n        }\n        return new Result(failedPackages);\n    }\n\n    @NonNull\n    private Result opForceStop(@NonNull BatchOpsInfo info) {\n        List<UserPackagePair> failedPackages = new ArrayList<>();\n        float lastProgress = mProgressHandler != null ? mProgressHandler.getLastProgress() : 0;\n        int max = info.size();\n        UserPackagePair pair;\n        for (int i = 0; i < max; ++i) {\n            updateProgress(lastProgress, i + 1);\n            pair = info.getPair(i);\n            try {\n                PackageManagerCompat.forceStopPackage(pair.getPackageName(), pair.getUserId());\n            } catch (Throwable e) {\n                log(\"====> op=FORCE_STOP, pkg=\" + pair, e);\n                failedPackages.add(pair);\n            }\n        }\n        return new Result(failedPackages);\n    }\n\n    @NonNull\n    private Result opNetPolicy(@NonNull BatchOpsInfo info) {\n        List<UserPackagePair> failedPackages = new ArrayList<>();\n        float lastProgress = mProgressHandler != null ? mProgressHandler.getLastProgress() : 0;\n        BatchNetPolicyOptions options = (BatchNetPolicyOptions) Objects.requireNonNull(info.options);\n        int max = info.size();\n        UserPackagePair pair;\n        for (int i = 0; i < max; ++i) {\n            updateProgress(lastProgress, i + 1);\n            pair = info.getPair(i);\n            try {\n                int uid = PackageUtils.getAppUid(pair);\n                NetworkPolicyManagerCompat.setUidPolicy(uid, options.getPolicies());\n            } catch (Throwable e) {\n                log(\"====> op=NET_POLICY, pkg=\" + pair, e);\n                failedPackages.add(pair);\n            }\n        }\n        return new Result(failedPackages);\n    }\n\n    @NonNull\n    private Result opSetAppOps(@NonNull BatchOpsInfo info) {\n        List<UserPackagePair> failedPkgList = new ArrayList<>();\n        float lastProgress = mProgressHandler != null ? mProgressHandler.getLastProgress() : 0;\n        AppOpsManagerCompat appOpsManager = new AppOpsManagerCompat();\n        BatchAppOpsOptions options = (BatchAppOpsOptions) Objects.requireNonNull(info.options);\n        int[] appOps = options.getAppOps();\n        int max = info.size();\n        UserPackagePair pair;\n        if (appOps.length == 1 && appOps[0] == AppOpsManagerCompat.OP_NONE) {\n            // Wildcard detected\n            for (int i = 0; i < max; ++i) {\n                updateProgress(lastProgress, i + 1);\n                pair = info.getPair(i);\n                try {\n                    List<Integer> appOpList = new ArrayList<>();\n                    ApplicationInfo applicationInfo = PackageManagerCompat.getApplicationInfo(pair.getPackageName(),\n                            PackageManagerCompat.MATCH_STATIC_SHARED_AND_SDK_LIBRARIES, pair.getUserId());\n                    List<AppOpsManagerCompat.OpEntry> entries = AppOpsManagerCompat.getConfiguredOpsForPackage(\n                            appOpsManager, applicationInfo.packageName, applicationInfo.uid);\n                    for (AppOpsManagerCompat.OpEntry entry : entries) {\n                        appOpList.add(entry.getOp());\n                    }\n                    ExternalComponentsImporter.setModeToFilteredAppOps(appOpsManager, pair,\n                            ArrayUtils.convertToIntArray(appOpList), options.getMode());\n                } catch (Exception e) {\n                    log(\"====> op=SET_APP_OPS, pkg=\" + pair, e);\n                    failedPkgList.add(pair);\n                }\n            }\n        } else {\n            for (int i = 0; i < max; ++i) {\n                updateProgress(lastProgress, i + 1);\n                pair = info.getPair(i);\n                try {\n                    ExternalComponentsImporter.setModeToFilteredAppOps(appOpsManager, pair, appOps, options.getMode());\n                } catch (RemoteException e) {\n                    log(\"====> op=SET_APP_OPS, pkg=\" + pair, e);\n                    failedPkgList.add(pair);\n                }\n            }\n        }\n        return new Result(failedPkgList);\n    }\n\n    @NonNull\n    private Result opUnblockComponents(@NonNull BatchOpsInfo info) {\n        List<UserPackagePair> failedPackages = new ArrayList<>();\n        float lastProgress = mProgressHandler != null ? mProgressHandler.getLastProgress() : 0;\n        BatchComponentOptions options = (BatchComponentOptions) Objects.requireNonNull(info.options);\n        int max = info.size();\n        UserPackagePair pair;\n        for (int i = 0; i < max; ++i) {\n            updateProgress(lastProgress, i + 1);\n            pair = info.getPair(i);\n            try {\n                ComponentUtils.unblockFilteredComponents(pair, options.getSignatures());\n            } catch (Throwable th) {\n                log(\"====> op=UNBLOCK_COMPONENTS, pkg=\" + pair, th);\n                failedPackages.add(pair);\n            }\n        }\n        return new Result(failedPackages);\n    }\n\n    @NonNull\n    private Result opUnblockTrackers(@NonNull BatchOpsInfo info) {\n        List<UserPackagePair> failedPackages = new ArrayList<>();\n        float lastProgress = mProgressHandler != null ? mProgressHandler.getLastProgress() : 0;\n        int max = info.size();\n        UserPackagePair pair;\n        for (int i = 0; i < max; ++i) {\n            updateProgress(lastProgress, i + 1);\n            pair = info.getPair(i);\n            try {\n                ComponentUtils.unblockTrackingComponents(pair);\n            } catch (Throwable th) {\n                log(\"====> op=UNBLOCK_TRACKERS, pkg=\" + pair, th);\n                failedPackages.add(pair);\n            }\n        }\n        return new Result(failedPackages);\n    }\n\n    @NonNull\n    private Result opUninstall(@NonNull BatchOpsInfo info) {\n        List<UserPackagePair> failedPackages = new ArrayList<>();\n        float lastProgress = mProgressHandler != null ? mProgressHandler.getLastProgress() : 0;\n        AccessibilityMultiplexer accessibility = AccessibilityMultiplexer.getInstance();\n        if (!SelfPermissions.checkSelfOrRemotePermission(Manifest.permission.DELETE_PACKAGES)) {\n            // Try to use accessibility in unprivileged mode\n            accessibility.enableUninstall(true);\n        }\n        int max = info.size();\n        UserPackagePair pair;\n        for (int i = 0; i < max; ++i) {\n            updateProgress(lastProgress, i + 1);\n            pair = info.getPair(i);\n            PackageInstallerCompat installer = PackageInstallerCompat.getNewInstance();\n            if (!installer.uninstall(pair.getPackageName(), pair.getUserId(), false)) {\n                log(\"====> op=UNINSTALL, pkg=\" + pair);\n                failedPackages.add(pair);\n            }\n        }\n        accessibility.enableUninstall(false);\n        return new Result(failedPackages);\n    }\n\n    @RequiresApi(Build.VERSION_CODES.N)\n    @NonNull\n    private Result opPerformDexOpt(@NonNull BatchOpsInfo info) {\n        List<UserPackagePair> failedPackages = new ArrayList<>();\n        IPackageManager pm = PackageManagerCompat.getPackageManager();\n        DexOptOptions options = ((BatchDexOptOptions) Objects.requireNonNull(info.options)).getDexOptOptions();\n        if (info.size() > 0) {\n            // Override options.packages with this list\n            Set<String> packages = new HashSet<>(info.size());\n            packages.addAll(info.packages);\n            options.packages = packages.toArray(new String[0]);\n        } else if (options.packages == null) {\n            // Include all packages\n            try {\n                options.packages = pm.getAllPackages().toArray(new String[0]);\n            } catch (RemoteException e) {\n                log(\"====> op=DEXOPT\", e);\n                return new Result(failedPackages, false);\n            }\n        }\n        fixProgress(options.packages.length);\n        float lastProgress = mProgressHandler != null ? mProgressHandler.getLastProgress() : 0;\n        int i = 0;\n        for (String packageName : options.packages) {\n            updateProgress(lastProgress, ++i);\n            if (packageName.equals(BuildConfig.APPLICATION_ID)) {\n                // Ignore App Manager\n                continue;\n            }\n            DexOptimizer dexOptimizer = new DexOptimizer(pm, packageName);\n            if (options.compilerFiler != null) {\n                boolean result = true;\n                if (options.clearProfileData) {\n                    result &= dexOptimizer.clearApplicationProfileData();\n                }\n                result &= dexOptimizer.performDexOptMode(options.checkProfiles, options.compilerFiler,\n                        options.forceCompilation, options.bootComplete, null);\n                if (!result) {\n                    log(\"====> op=DEXOPT, pkg=\" + packageName + \", failed=dexopt-mode\", dexOptimizer.getLastError());\n                    failedPackages.add(new UserPackagePair(packageName, 0));\n                    continue;\n                }\n            }\n            if (options.compileLayouts && Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {\n                boolean result = true;\n                if (options.clearProfileData) {\n                    result &= dexOptimizer.clearApplicationProfileData();\n                }\n                result &= dexOptimizer.compileLayouts();\n                if (!result) {\n                    log(\"====> op=DEXOPT, pkg=\" + packageName + \", failed=compile-layouts\", dexOptimizer.getLastError());\n                    failedPackages.add(new UserPackagePair(packageName, 0));\n                    continue;\n                }\n            }\n            if (options.forceDexOpt) {\n                if (!dexOptimizer.forceDexOpt()) {\n                    log(\"====> op=DEXOPT, pkg=\" + packageName + \", failed=force-dexopt\", dexOptimizer.getLastError());\n                    failedPackages.add(new UserPackagePair(packageName, 0));\n                }\n            }\n        }\n        return new Result(failedPackages);\n    }\n\n    private void log(@Nullable String message, @Nullable Throwable th) {\n        if (mLogger != null) {\n            mLogger.println(message, th);\n        }\n    }\n\n    private void log(@Nullable String message) {\n        if (mLogger != null) {\n            mLogger.println(message);\n        }\n    }\n\n    private void updateProgress(float last, int current) {\n        if (mProgressHandler == null) {\n            return;\n        }\n        // Current progress = last progress + current\n        mProgressHandler.postUpdate(last + current);\n    }\n\n    private void fixProgress(int appendMax) {\n        if (mProgressHandler == null) {\n            return;\n        }\n        int max = Math.max(mProgressHandler.getLastMax(), 0) + appendMax;\n        float current = mProgressHandler.getLastProgress();\n        mProgressHandler.postUpdate(max, current);\n    }\n\n    @Nullable\n    private ProgressHandler newSubProgress(@Nullable CharSequence operationName, @Nullable CharSequence title) {\n        if (mProgressHandler == null) {\n            return null;\n        }\n        Object message = mProgressHandler.getLastMessage();\n        if (message == null) {\n            return null;\n        }\n        ProgressHandler p = mProgressHandler.newSubProgressHandler();\n        if (p instanceof NotificationProgressHandler) {\n            NotificationInfo parentNotificationInfo = (NotificationInfo) message;\n            NotificationInfo notificationInfo = new NotificationInfo(parentNotificationInfo)\n                    .setOperationName(operationName)\n                    .setTitle(title);\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {\n                notificationInfo.setGroupId(GROUP_ID);\n            }\n            ThreadUtils.postOnMainThread(() -> p.onProgressStart(-1, 0, notificationInfo));\n        }\n        return p;\n    }\n\n    public static class Result {\n        @NonNull\n        private final ArrayList<String> mFailedPackages;\n        @NonNull\n        private final ArrayList<Integer> mAssociatedUsers;\n        private final boolean mIsSuccessful;\n\n        private boolean mRequiresRestart;\n\n        public Result(@NonNull List<UserPackagePair> failedUserPackagePairs) {\n            this(failedUserPackagePairs, failedUserPackagePairs.isEmpty());\n        }\n\n        public Result(@NonNull List<UserPackagePair> failedUserPackagePairs, boolean isSuccessful) {\n            mFailedPackages = new ArrayList<>();\n            mAssociatedUsers = new ArrayList<>();\n            for (UserPackagePair userPackagePair : failedUserPackagePairs) {\n                mFailedPackages.add(userPackagePair.getPackageName());\n                mAssociatedUsers.add(userPackagePair.getUserId());\n            }\n            mIsSuccessful = isSuccessful;\n        }\n\n        public boolean requiresRestart() {\n            return mRequiresRestart;\n        }\n\n        public void setRequiresRestart(boolean requiresRestart) {\n            mRequiresRestart = requiresRestart;\n        }\n\n        public boolean isSuccessful() {\n            return mIsSuccessful;\n        }\n\n        @NonNull\n        public ArrayList<String> getFailedPackages() {\n            return mFailedPackages;\n        }\n\n        @NonNull\n        @UserIdInt\n        public ArrayList<Integer> getAssociatedUsers() {\n            return mAssociatedUsers;\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/batchops/BatchOpsResultsActivity.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.batchops;\n\nimport android.content.Intent;\nimport android.graphics.Typeface;\nimport android.os.Bundle;\nimport android.text.SpannableString;\nimport android.text.Spanned;\nimport android.text.style.StyleSpan;\nimport android.view.LayoutInflater;\nimport android.view.Menu;\nimport android.view.MenuItem;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.TextView;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.appcompat.widget.AppCompatEditText;\nimport androidx.core.content.ContextCompat;\nimport androidx.recyclerview.widget.RecyclerView;\n\nimport com.google.android.material.button.MaterialButton;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\n\nimport io.github.muntashirakon.AppManager.BaseActivity;\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.intercept.IntentCompat;\nimport io.github.muntashirakon.AppManager.utils.PackageUtils;\nimport io.github.muntashirakon.AppManager.utils.RestartUtils;\nimport io.github.muntashirakon.AppManager.utils.UIUtils;\nimport io.github.muntashirakon.util.AccessibilityUtils;\n\npublic class BatchOpsResultsActivity extends BaseActivity {\n    private RecyclerView mRecyclerView;\n    private AppCompatEditText mLogViewer;\n\n    @Nullable\n    private BatchQueueItem mBatchQueueItem;\n\n    @Override\n    protected void onAuthenticated(@Nullable Bundle savedInstanceState) {\n        if (getIntent() == null) {\n            finish();\n            return;\n        }\n        if (restartIfNeeded(getIntent())) {\n            return;\n        }\n        setContentView(R.layout.activity_batch_ops_results);\n        setSupportActionBar(findViewById(R.id.toolbar));\n        findViewById(R.id.progress_linear).setVisibility(View.GONE);\n        mRecyclerView = findViewById(R.id.list);\n        mRecyclerView.setLayoutManager(UIUtils.getGridLayoutAt450Dp(this));\n        MaterialButton logToggler = findViewById(R.id.action_view_logs);\n        mLogViewer = findViewById(R.id.text);\n        mLogViewer.setKeyListener(null);\n        logToggler.setOnClickListener(v -> {\n            mLogViewer.setVisibility(View.VISIBLE);\n            AccessibilityUtils.requestAccessibilityFocus(mLogViewer);\n        });\n        handleIntent(getIntent());\n    }\n\n    @Override\n    protected void onSaveInstanceState(@NonNull Bundle outState) {\n        outState.clear();\n        super.onSaveInstanceState(outState);\n    }\n\n    @Override\n    protected void onNewIntent(@NonNull Intent intent) {\n        super.onNewIntent(intent);\n        if (restartIfNeeded(getIntent())) {\n            return;\n        }\n        handleIntent(intent);\n    }\n\n    private void handleIntent(@NonNull Intent intent) {\n        mBatchQueueItem = IntentCompat.getUnwrappedParcelableExtra(intent, BatchOpsService.EXTRA_QUEUE_ITEM, BatchQueueItem.class);\n        if (mBatchQueueItem == null) {\n            finish();\n            return;\n        }\n        setTitle(intent.getStringExtra(BatchOpsService.EXTRA_FAILURE_MESSAGE));\n        ArrayList<CharSequence> packageLabels = PackageUtils.packagesToAppLabels(getPackageManager(),\n                mBatchQueueItem.getPackages(), mBatchQueueItem.getUsers());\n        RecyclerAdapter adapter = new RecyclerAdapter(packageLabels);\n        mRecyclerView.setAdapter(adapter);\n        if (packageLabels != null) {\n            adapter.notifyItemRangeInserted(0, packageLabels.size());\n        }\n        mLogViewer.setText(getFormattedLogs(BatchOpsLogger.getAllLogs()));\n        intent.removeExtra(BatchOpsService.EXTRA_QUEUE_ITEM);\n    }\n\n    private static boolean restartIfNeeded(@NonNull Intent intent) {\n        if (intent.getBooleanExtra(BatchOpsService.EXTRA_REQUIRES_RESTART, false)) {\n            RestartUtils.restart(RestartUtils.RESTART_NORMAL);\n            return true;\n        }\n        return false;\n    }\n\n    @Override\n    public boolean onCreateOptionsMenu(Menu menu) {\n        getMenuInflater().inflate(R.menu.activity_batch_ops_results_actions, menu);\n        return super.onCreateOptionsMenu(menu);\n    }\n\n    @Override\n    public boolean onOptionsItemSelected(@NonNull MenuItem item) {\n        int id = item.getItemId();\n        if (id == android.R.id.home) {\n            finish();\n            return true;\n        } else if (id == R.id.action_retry) {\n            if (mBatchQueueItem != null) {\n                Intent BatchOpsIntent = BatchOpsService.getServiceIntent(this, mBatchQueueItem);\n                ContextCompat.startForegroundService(this, BatchOpsIntent);\n            }\n        }\n        return super.onOptionsItemSelected(item);\n    }\n\n    @Override\n    protected void onDestroy() {\n        BatchOpsLogger.clearLogs();\n        super.onDestroy();\n    }\n\n    public CharSequence getFormattedLogs(String logs) {\n        SpannableString str = new SpannableString(logs);\n        int fIndex = 0;\n        while(true) {\n            fIndex = logs.indexOf(\"====> \", fIndex);\n            if (fIndex == -1) {\n                return str;\n            }\n            int lIndex = logs.indexOf('\\n', fIndex);\n            str.setSpan(new StyleSpan(Typeface.BOLD), fIndex, lIndex, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);\n            fIndex = lIndex;\n        }\n    }\n\n    static class RecyclerAdapter extends RecyclerView.Adapter<RecyclerAdapter.ViewHolder> {\n        @NonNull\n        private final List<CharSequence> mAppLabels;\n\n        public RecyclerAdapter(@Nullable List<CharSequence> appLabels) {\n            mAppLabels = appLabels == null ? Collections.emptyList() : appLabels;\n        }\n\n        @NonNull\n        @Override\n        public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {\n            View view = LayoutInflater.from(parent.getContext()).inflate(android.R.layout.simple_list_item_1, parent, false);\n            return new ViewHolder(view);\n        }\n\n        @Override\n        public void onBindViewHolder(@NonNull ViewHolder holder, int position) {\n            holder.itemView.setText(mAppLabels.get(position));\n        }\n\n        @Override\n        public int getItemCount() {\n            return mAppLabels.size();\n        }\n\n        static class ViewHolder extends RecyclerView.ViewHolder {\n            TextView itemView;\n\n            public ViewHolder(@NonNull View itemView) {\n                super(itemView);\n                this.itemView = (TextView) itemView;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/batchops/BatchOpsService.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.batchops;\n\nimport static io.github.muntashirakon.AppManager.history.ops.OpHistoryManager.HISTORY_TYPE_BATCH_OPS;\n\nimport android.app.Activity;\nimport android.app.PendingIntent;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.os.Build;\nimport android.os.PowerManager;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.core.app.NotificationManagerCompat;\nimport androidx.core.app.PendingIntentCompat;\nimport androidx.core.app.ServiceCompat;\n\nimport java.util.ArrayList;\nimport java.util.Objects;\n\nimport io.github.muntashirakon.AppManager.BuildConfig;\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.batchops.BatchOpsManager.BatchOpsInfo;\nimport io.github.muntashirakon.AppManager.history.ops.OpHistoryManager;\nimport io.github.muntashirakon.AppManager.intercept.IntentCompat;\nimport io.github.muntashirakon.AppManager.main.MainActivity;\nimport io.github.muntashirakon.AppManager.progress.NotificationProgressHandler;\nimport io.github.muntashirakon.AppManager.progress.NotificationProgressHandler.NotificationManagerInfo;\nimport io.github.muntashirakon.AppManager.progress.ProgressHandler;\nimport io.github.muntashirakon.AppManager.progress.QueuedProgressHandler;\nimport io.github.muntashirakon.AppManager.types.ForegroundService;\nimport io.github.muntashirakon.AppManager.utils.CpuUtils;\nimport io.github.muntashirakon.AppManager.utils.NotificationUtils;\n\npublic class BatchOpsService extends ForegroundService {\n    public static final String EXTRA_QUEUE_ITEM = \"queue_item\";\n\n    /**\n     * Name of the batch operation, {@link Integer} value. One of the {@link BatchOpsManager.OpType}.\n     */\n    public static final String EXTRA_OP = \"EXTRA_OP\";\n    /**\n     * An {@link ArrayList} of package names (string value) on which operations will be carried out.\n     */\n    public static final String EXTRA_OP_PKG = \"EXTRA_OP_PKG\";\n    /**\n     * An {@link ArrayList} of package name (string value) which are failed after the batch\n     * operation is complete.\n     */\n    public static final String EXTRA_FAILED_PKG = \"EXTRA_FAILED_PKG_ARR\";\n    /**\n     * The failure message.\n     */\n    public static final String EXTRA_FAILURE_MESSAGE = \"EXTRA_FAILURE_MESSAGE\";\n    /**\n     * Boolean value to describe whether a reboot is required.\n     */\n    public static final String EXTRA_REQUIRES_RESTART = \"requires_restart\";\n\n    /**\n     * Send to the appropriate broadcast receiver denoting that the batch operation is completed. It\n     * includes the following extras:\n     * <ul>\n     *     <li>\n     *         {@link #EXTRA_OP} is the integer value denoting the type of operation.\n     *     </li>\n     *     <li>\n     *         {@link #EXTRA_OP_PKG} is the array of packages on which operations were carried out. Never null.\n     *     </li>\n     *     <li>\n     *         {@link #EXTRA_FAILED_PKG} is the array of failed packages. Never null.\n     *     </li>\n     * </ul>\n     */\n    public static final String ACTION_BATCH_OPS_COMPLETED = BuildConfig.APPLICATION_ID + \".action.BATCH_OPS_COMPLETED\";\n    public static final String ACTION_BATCH_OPS_STARTED = BuildConfig.APPLICATION_ID + \".action.BATCH_OPS_STARTED\";\n\n    /**\n     * Notification channel ID\n     */\n    public static final String CHANNEL_ID = BuildConfig.APPLICATION_ID + \".channel.BATCH_OPS\";\n\n    @NonNull\n    public static Intent getServiceIntent(@NonNull Context context, @NonNull BatchQueueItem queueItem) {\n        Intent intent = new Intent(context, BatchOpsService.class);\n        IntentCompat.putWrappedParcelableExtra(intent, EXTRA_QUEUE_ITEM, queueItem);\n        return intent;\n    }\n\n    private QueuedProgressHandler mProgressHandler;\n    private NotificationProgressHandler.NotificationInfo mNotificationInfo;\n    private PowerManager.WakeLock mWakeLock;\n\n    public BatchOpsService() {\n        super(\"BatchOpsService\");\n    }\n\n    @Override\n    public void onCreate() {\n        super.onCreate();\n        mWakeLock = CpuUtils.getPartialWakeLock(\"batch_ops\");\n        mWakeLock.acquire();\n    }\n\n    @Override\n    public int onStartCommand(@Nullable Intent intent, int flags, int startId) {\n        if (isWorking()) return super.onStartCommand(intent, flags, startId);\n        BatchQueueItem item = getQueueItem(intent);\n        NotificationManagerInfo notificationManagerInfo = new NotificationManagerInfo(CHANNEL_ID,\n                \"Batch Ops Progress\", NotificationManagerCompat.IMPORTANCE_LOW);\n        mProgressHandler = new NotificationProgressHandler(this,\n                notificationManagerInfo,\n                NotificationUtils.HIGH_PRIORITY_NOTIFICATION_INFO,\n                NotificationUtils.HIGH_PRIORITY_NOTIFICATION_INFO);\n        mProgressHandler.setProgressTextInterface(ProgressHandler.PROGRESS_REGULAR);\n        Intent notificationIntent = new Intent(this, MainActivity.class);\n        PendingIntent pendingIntent = PendingIntentCompat.getActivity(this, 0, notificationIntent, 0, false);\n        mNotificationInfo = new NotificationProgressHandler.NotificationInfo()\n                .setOperationName(getHeader(item))\n                .setBody(getString(R.string.operation_running))\n                .setDefaultAction(pendingIntent);\n        mProgressHandler.onAttach(this, mNotificationInfo);\n        return super.onStartCommand(intent, flags, startId);\n    }\n\n    @Override\n    protected void onHandleIntent(@Nullable Intent intent) {\n        BatchQueueItem item = getQueueItem(intent);\n        if (item == null || item.getOp() == BatchOpsManager.OP_NONE) {\n            sendResults(Activity.RESULT_CANCELED, item, null);\n            return;\n        }\n        sendStarted(item);\n        // Update progress\n        if (mProgressHandler != null) {\n            mProgressHandler.postUpdate(item.getPackages().size(), 0);\n        }\n        BatchOpsManager batchOpsManager = new BatchOpsManager();\n        BatchOpsManager.Result result = batchOpsManager.performOp(BatchOpsInfo.fromQueue(item), mProgressHandler);\n        batchOpsManager.conclude();\n        OpHistoryManager.addHistoryItem(HISTORY_TYPE_BATCH_OPS, item, result.isSuccessful());\n        if (result.isSuccessful()) {\n            sendResults(Activity.RESULT_OK, item, result);\n        } else {\n            sendResults(Activity.RESULT_FIRST_USER, item, result);\n        }\n    }\n\n    @Override\n    protected void onQueued(@Nullable Intent intent) {\n        BatchQueueItem item = getQueueItem(intent);\n        if (item == null) {\n            return;\n        }\n        String opTitle = getDesiredOpTitle(this, item.getOp());\n        Object notificationInfo = new NotificationProgressHandler.NotificationInfo()\n                .setAutoCancel(true)\n                .setTime(System.currentTimeMillis())\n                .setOperationName(getHeader(item))\n                .setTitle(opTitle)\n                .setBody(getString(R.string.added_to_queue));\n        mProgressHandler.onQueue(notificationInfo);\n    }\n\n    @Override\n    protected void onStartIntent(@Nullable Intent intent) {\n        BatchQueueItem item = getQueueItem(intent);\n        int op = item != null ? item.getOp() : BatchOpsManager.OP_NONE;\n        mNotificationInfo.setTitle(getDesiredOpTitle(this, op)).setOperationName(getHeader(item));\n        mProgressHandler.onProgressStart(-1, 0, mNotificationInfo);\n    }\n\n    @Override\n    public void onDestroy() {\n        ServiceCompat.stopForeground(this, ServiceCompat.STOP_FOREGROUND_REMOVE);\n        if (mProgressHandler != null) {\n            mProgressHandler.onDetach(this);\n        }\n        CpuUtils.releaseWakeLock(mWakeLock);\n        super.onDestroy();\n    }\n\n    @Nullable\n    private BatchQueueItem getQueueItem(@Nullable Intent intent) {\n        if (intent == null) {\n            return null;\n        }\n        return IntentCompat.getUnwrappedParcelableExtra(intent, EXTRA_QUEUE_ITEM, BatchQueueItem.class);\n    }\n\n    private void sendStarted(@NonNull BatchQueueItem queueItem) {\n        Intent broadcastIntent = new Intent(ACTION_BATCH_OPS_STARTED);\n        broadcastIntent.setPackage(getPackageName());\n        broadcastIntent.putExtra(EXTRA_OP, queueItem.getOp());\n        broadcastIntent.putExtra(EXTRA_OP_PKG, queueItem.getPackages().toArray(new String[0]));\n        sendBroadcast(broadcastIntent);\n    }\n\n    private void sendResults(int result, @Nullable BatchQueueItem queueItem, @Nullable BatchOpsManager.Result opResult) {\n        Intent broadcastIntent = new Intent(ACTION_BATCH_OPS_COMPLETED);\n        broadcastIntent.setPackage(getPackageName());\n        broadcastIntent.putExtra(EXTRA_OP, queueItem != null ? queueItem.getOp() : BatchOpsManager.OP_NONE);\n        broadcastIntent.putExtra(EXTRA_OP_PKG, queueItem != null ? queueItem.getPackages().toArray(new String[0]) : new String[0]);\n        broadcastIntent.putStringArrayListExtra(EXTRA_FAILED_PKG, opResult != null ? opResult.getFailedPackages() : null);\n        sendBroadcast(broadcastIntent);\n        sendNotification(result, queueItem, opResult);\n    }\n\n    private void sendNotification(int result, @Nullable BatchQueueItem queueItem, @Nullable BatchOpsManager.Result opResult) {\n        String contentTitle = getDesiredOpTitle(this, queueItem != null ? queueItem.getOp() : BatchOpsManager.OP_NONE);\n        NotificationProgressHandler.NotificationInfo notificationInfo = new NotificationProgressHandler.NotificationInfo()\n                .setAutoCancel(true)\n                .setTime(System.currentTimeMillis())\n                .setOperationName(getHeader(queueItem))\n                .setTitle(contentTitle);\n        switch (result) {\n            case Activity.RESULT_CANCELED:  // Cancelled\n                break;\n            case Activity.RESULT_OK:  // Successful\n                notificationInfo.setBody(getString(R.string.the_operation_was_successful));\n                break;\n            case Activity.RESULT_FIRST_USER:  // Failed\n                Objects.requireNonNull(opResult);\n                Objects.requireNonNull(queueItem);\n                queueItem.setPackages(opResult.getFailedPackages());\n                queueItem.setUsers(opResult.getAssociatedUsers());\n                String detailsMessage = getString(R.string.full_stop_tap_to_see_details);\n                String message = getDesiredErrorString(queueItem.getOp(), opResult.getFailedPackages().size());\n                Intent intent = new Intent(this, BatchOpsResultsActivity.class);\n                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {\n                    intent.setIdentifier(String.valueOf(System.currentTimeMillis()));\n                }\n                intent.putExtra(EXTRA_FAILURE_MESSAGE, message);\n                IntentCompat.putWrappedParcelableExtra(intent, EXTRA_QUEUE_ITEM, queueItem);\n                PendingIntent pendingIntent = PendingIntentCompat.getActivity(this, 0, intent,\n                        PendingIntent.FLAG_ONE_SHOT, false);\n                notificationInfo.setDefaultAction(pendingIntent);\n                notificationInfo.setBody(message + detailsMessage);\n        }\n        if (opResult != null && opResult.requiresRestart()) {\n            Intent intent = new Intent(this, BatchOpsResultsActivity.class);\n            intent.putExtra(EXTRA_REQUIRES_RESTART, true);\n            PendingIntent pendingIntent = PendingIntentCompat.getActivity(this, 0, intent,\n                    PendingIntent.FLAG_ONE_SHOT, false);\n            notificationInfo.addAction(0, getString(R.string.restart_device), pendingIntent);\n        }\n        mProgressHandler.onResult(notificationInfo);\n    }\n\n    @NonNull\n    public String getHeader(@Nullable BatchQueueItem item) {\n        if (item != null) {\n            String title = item.getTitle();\n            if (title != null) {\n                return title;\n            }\n        }\n        return getString(R.string.batch_ops);\n    }\n\n    @NonNull\n    public static String getDesiredOpTitle(@NonNull Context context,\n                                           @BatchOpsManager.OpType int op) {\n        switch (op) {\n            case BatchOpsManager.OP_BACKUP:\n            case BatchOpsManager.OP_DELETE_BACKUP:\n            case BatchOpsManager.OP_RESTORE_BACKUP:\n                return context.getString(R.string.backup_restore);\n            case BatchOpsManager.OP_BACKUP_APK:\n                return context.getString(R.string.save_apk);\n            case BatchOpsManager.OP_BLOCK_TRACKERS:\n                return context.getString(R.string.block_trackers);\n            case BatchOpsManager.OP_CLEAR_DATA:\n                return context.getString(R.string.clear_data);\n            case BatchOpsManager.OP_CLEAR_CACHE:\n                return context.getString(R.string.clear_cache);\n            case BatchOpsManager.OP_FREEZE:\n            case BatchOpsManager.OP_ADVANCED_FREEZE:\n                return context.getString(R.string.freeze);\n            case BatchOpsManager.OP_DISABLE_BACKGROUND:\n                return context.getString(R.string.disable_background);\n            case BatchOpsManager.OP_UNFREEZE:\n                return context.getString(R.string.unfreeze);\n            case BatchOpsManager.OP_EXPORT_RULES:\n                return context.getString(R.string.export_blocking_rules);\n            case BatchOpsManager.OP_FORCE_STOP:\n                return context.getString(R.string.force_stop);\n            case BatchOpsManager.OP_NET_POLICY:\n                return context.getString(R.string.net_policy);\n            case BatchOpsManager.OP_UNINSTALL:\n                return context.getString(R.string.uninstall);\n            case BatchOpsManager.OP_UNBLOCK_TRACKERS:\n                return context.getString(R.string.unblock_trackers);\n            case BatchOpsManager.OP_BLOCK_COMPONENTS:\n                return context.getString(R.string.block_components_dots);\n            case BatchOpsManager.OP_UNBLOCK_COMPONENTS:\n                return context.getString(R.string.unblock_components_dots);\n            case BatchOpsManager.OP_SET_APP_OPS:\n                return context.getString(R.string.set_mode_for_app_ops_dots);\n            case BatchOpsManager.OP_IMPORT_BACKUPS:\n                return context.getString(R.string.pref_import_backups);\n            case BatchOpsManager.OP_DEXOPT:\n                return context.getString(R.string.batch_ops_runtime_optimization);\n            case BatchOpsManager.OP_NONE:\n                break;\n        }\n        return context.getString(R.string.batch_ops);\n    }\n\n    private String getDesiredErrorString(int op, int failedCount) {\n        switch (op) {\n            case BatchOpsManager.OP_BACKUP:\n                return getResources().getQuantityString(R.plurals.alert_failed_to_backup, failedCount, failedCount);\n            case BatchOpsManager.OP_DELETE_BACKUP:\n                return getResources().getQuantityString(R.plurals.alert_failed_to_delete_backup, failedCount, failedCount);\n            case BatchOpsManager.OP_RESTORE_BACKUP:\n                return getResources().getQuantityString(R.plurals.alert_failed_to_restore, failedCount, failedCount);\n            case BatchOpsManager.OP_EXPORT_RULES:\n            case BatchOpsManager.OP_NONE:\n                break;\n            case BatchOpsManager.OP_BACKUP_APK:\n                return getResources().getQuantityString(R.plurals.failed_to_backup_some_apk_files, failedCount, failedCount);\n            case BatchOpsManager.OP_BLOCK_TRACKERS:\n                return getResources().getQuantityString(R.plurals.alert_failed_to_disable_trackers, failedCount, failedCount);\n            case BatchOpsManager.OP_CLEAR_DATA:\n                return getResources().getQuantityString(R.plurals.alert_failed_to_clear_data, failedCount, failedCount);\n            case BatchOpsManager.OP_FREEZE:\n            case BatchOpsManager.OP_ADVANCED_FREEZE:\n                return getResources().getQuantityString(R.plurals.alert_failed_to_freeze, failedCount, failedCount);\n            case BatchOpsManager.OP_UNFREEZE:\n                return getResources().getQuantityString(R.plurals.alert_failed_to_unfreeze, failedCount, failedCount);\n            case BatchOpsManager.OP_DISABLE_BACKGROUND:\n                return getResources().getQuantityString(R.plurals.alert_failed_to_disable_background, failedCount, failedCount);\n            case BatchOpsManager.OP_FORCE_STOP:\n                return getResources().getQuantityString(R.plurals.alert_failed_to_force_stop, failedCount, failedCount);\n            case BatchOpsManager.OP_UNINSTALL:\n                return getResources().getQuantityString(R.plurals.alert_failed_to_uninstall, failedCount, failedCount);\n            case BatchOpsManager.OP_UNBLOCK_TRACKERS:\n                return getResources().getQuantityString(R.plurals.alert_failed_to_unblock_trackers, failedCount, failedCount);\n            case BatchOpsManager.OP_BLOCK_COMPONENTS:\n                return getResources().getQuantityString(R.plurals.alert_failed_to_block_components, failedCount, failedCount);\n            case BatchOpsManager.OP_UNBLOCK_COMPONENTS:\n                return getResources().getQuantityString(R.plurals.alert_failed_to_unblock_components, failedCount, failedCount);\n            case BatchOpsManager.OP_SET_APP_OPS:\n                return getResources().getQuantityString(R.plurals.alert_failed_to_set_app_ops, failedCount, failedCount);\n            case BatchOpsManager.OP_IMPORT_BACKUPS:\n                return getResources().getQuantityString(R.plurals.alert_failed_to_import_backups, failedCount, failedCount);\n            case BatchOpsManager.OP_DEXOPT:\n                return getResources().getQuantityString(R.plurals.alert_failed_to_optimize_apps, failedCount, failedCount);\n        }\n        return getString(R.string.error);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/batchops/BatchQueueItem.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.batchops;\n\nimport android.content.res.Resources;\nimport android.os.Parcel;\nimport android.os.Parcelable;\nimport android.os.UserHandleHidden;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.StringRes;\nimport androidx.core.os.ParcelCompat;\n\nimport org.json.JSONException;\nimport org.json.JSONObject;\n\nimport java.util.ArrayList;\nimport java.util.Objects;\n\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.batchops.BatchOpsManager.OpType;\nimport io.github.muntashirakon.AppManager.batchops.struct.IBatchOpOptions;\nimport io.github.muntashirakon.AppManager.history.IJsonSerializer;\nimport io.github.muntashirakon.AppManager.history.JsonDeserializer;\nimport io.github.muntashirakon.AppManager.utils.ContextUtils;\nimport io.github.muntashirakon.AppManager.utils.JSONUtils;\nimport io.github.muntashirakon.util.ParcelUtils;\n\npublic class BatchQueueItem implements Parcelable, IJsonSerializer {\n    @NonNull\n    public static BatchQueueItem getBatchOpQueue(@OpType int op,\n                                                 @Nullable ArrayList<String> packages,\n                                                 @Nullable ArrayList<Integer> users,\n                                                 @Nullable IBatchOpOptions options) {\n        return new BatchQueueItem(R.string.batch_ops, op, packages, users, options);\n    }\n\n    @NonNull\n    public static BatchQueueItem getOneClickQueue(@OpType int op,\n                                                  @Nullable ArrayList<String> packages,\n                                                  @Nullable ArrayList<Integer> users,\n                                                  @Nullable IBatchOpOptions args) {\n        return new BatchQueueItem(R.string.one_click_ops, op, packages, users, args);\n    }\n\n    @StringRes\n    private final int mTitleRes;\n    @OpType\n    private final int mOp;\n    @NonNull\n    private ArrayList<String> mPackages;\n    @Nullable\n    private ArrayList<Integer> mUsers;\n    @Nullable\n    private final IBatchOpOptions mOptions;\n\n    private BatchQueueItem(@StringRes int titleRes,\n                           @OpType int op,\n                           @Nullable ArrayList<String> packages,\n                           @Nullable ArrayList<Integer> users,\n                           @Nullable IBatchOpOptions options) {\n        mTitleRes = titleRes;\n        mOp = op;\n        mPackages = packages != null ? packages : new ArrayList<>(0);\n        mUsers = users;\n        mOptions = options;\n    }\n\n    @StringRes\n    public int getTitleRes() {\n        return mTitleRes;\n    }\n\n    @Nullable\n    public String getTitle() {\n        try {\n            return ContextUtils.getContext().getString(mTitleRes);\n        } catch (Resources.NotFoundException e) {\n            // This resource may not always be found\n            return null;\n        }\n    }\n\n    public int getOp() {\n        return mOp;\n    }\n\n    @NonNull\n    public ArrayList<String> getPackages() {\n        return mPackages;\n    }\n\n    public void setPackages(@NonNull ArrayList<String> packages) {\n        mPackages = packages;\n    }\n\n    @NonNull\n    public ArrayList<Integer> getUsers() {\n        if (mUsers == null) {\n            int size = mPackages.size();\n            int userId = UserHandleHidden.myUserId();\n            mUsers = new ArrayList<>(size);\n            for (int i = 0; i < size; ++i) {\n                mUsers.add(userId);\n            }\n        } else {\n            assert mPackages.size() == mUsers.size();\n        }\n        return mUsers;\n    }\n\n    public void setUsers(@Nullable ArrayList<Integer> users) {\n        mUsers = users;\n    }\n\n    @Nullable\n    public IBatchOpOptions getOptions() {\n        return mOptions;\n    }\n\n    @Override\n    public int describeContents() {\n        return 0;\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        dest.writeInt(mTitleRes);\n        dest.writeInt(mOp);\n        dest.writeStringList(mPackages);\n        ParcelUtils.writeArrayList(mUsers, dest);\n        dest.writeParcelable(mOptions, flags);\n    }\n\n    protected BatchQueueItem(@NonNull JSONObject jsonObject) throws JSONException {\n        mTitleRes = jsonObject.getInt(\"title_res\");\n        mOp = jsonObject.getInt(\"op\");\n        mPackages = JSONUtils.getArray(jsonObject.getJSONArray(\"packages\"));\n        mUsers = JSONUtils.getArray(jsonObject.getJSONArray(\"users\"));\n        JSONObject options = jsonObject.optJSONObject(\"options\");\n        mOptions = options != null ? IBatchOpOptions.DESERIALIZER.deserialize(options) : null;\n    }\n\n    @NonNull\n    @Override\n    public JSONObject serializeToJson() throws JSONException {\n        JSONObject jsonObject = new JSONObject();\n        jsonObject.put(\"title_res\", mTitleRes);\n        jsonObject.put(\"op\", mOp);\n        jsonObject.put(\"packages\", JSONUtils.getJSONArray(mPackages));\n        jsonObject.put(\"users\", JSONUtils.getJSONArray(mUsers));\n        jsonObject.put(\"options\", mOptions != null ? mOptions.serializeToJson() : null);\n        return jsonObject;\n    }\n\n    protected BatchQueueItem(@NonNull Parcel in) {\n        mTitleRes = in.readInt();\n        mOp = in.readInt();\n        mPackages = Objects.requireNonNull(in.createStringArrayList());\n        mUsers = ParcelUtils.readArrayList(in, Integer.class.getClassLoader());\n        mOptions = ParcelCompat.readParcelable(in, IBatchOpOptions.class.getClassLoader(), IBatchOpOptions.class);\n    }\n\n    public static final JsonDeserializer.Creator<BatchQueueItem> DESERIALIZER = BatchQueueItem::new;\n\n    public static final Creator<BatchQueueItem> CREATOR = new Creator<BatchQueueItem>() {\n        @NonNull\n        @Override\n        public BatchQueueItem createFromParcel(@NonNull Parcel in) {\n            return new BatchQueueItem(in);\n        }\n\n        @NonNull\n        @Override\n        public BatchQueueItem[] newArray(int size) {\n            return new BatchQueueItem[size];\n        }\n    };\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/batchops/struct/BatchAppOpsOptions.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.batchops.struct;\n\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport org.json.JSONException;\nimport org.json.JSONObject;\n\nimport java.util.Objects;\n\nimport io.github.muntashirakon.AppManager.history.JsonDeserializer;\nimport io.github.muntashirakon.AppManager.utils.JSONUtils;\n\npublic class BatchAppOpsOptions implements IBatchOpOptions {\n    public static final String TAG = BatchAppOpsOptions.class.getSimpleName();\n\n    @NonNull\n    private int[] mAppOps;\n    private int mMode;\n\n    public BatchAppOpsOptions(@NonNull int[] appOps, int mode) {\n        mAppOps = appOps;\n        mMode = mode;\n    }\n\n    @NonNull\n    public int[] getAppOps() {\n        return mAppOps;\n    }\n\n    public int getMode() {\n        return mMode;\n    }\n\n    protected BatchAppOpsOptions(@NonNull Parcel in) {\n        mAppOps = Objects.requireNonNull(in.createIntArray());\n        mMode = in.readInt();\n    }\n\n    public static final Creator<BatchAppOpsOptions> CREATOR = new Creator<BatchAppOpsOptions>() {\n        @Override\n        @NonNull\n        public BatchAppOpsOptions createFromParcel(@NonNull Parcel in) {\n            return new BatchAppOpsOptions(in);\n        }\n\n        @Override\n        @NonNull\n        public BatchAppOpsOptions[] newArray(int size) {\n            return new BatchAppOpsOptions[size];\n        }\n    };\n\n    @Override\n    public int describeContents() {\n        return 0;\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        dest.writeIntArray(mAppOps);\n        dest.writeInt(mMode);\n    }\n\n    protected BatchAppOpsOptions(@NonNull JSONObject jsonObject) throws JSONException {\n        assert jsonObject.getString(\"tag\").equals(TAG);\n        mAppOps = JSONUtils.getIntArray(jsonObject.getJSONArray(\"app_ops\"));\n        mMode = jsonObject.getInt(\"mode\");\n    }\n\n    public static final JsonDeserializer.Creator<BatchAppOpsOptions> DESERIALIZER\n            = BatchAppOpsOptions::new;\n\n    @NonNull\n    @Override\n    public JSONObject serializeToJson() throws JSONException {\n        JSONObject jsonObject = new JSONObject();\n        jsonObject.put(\"tag\", TAG);\n        jsonObject.put(\"app_ops\", JSONUtils.getJSONArray(mAppOps));\n        jsonObject.put(\"mode\", mMode);\n        return jsonObject;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/batchops/struct/BatchBackupImportOptions.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.batchops.struct;\n\nimport android.net.Uri;\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\nimport androidx.core.os.ParcelCompat;\n\nimport org.json.JSONException;\nimport org.json.JSONObject;\n\nimport java.util.Objects;\n\nimport io.github.muntashirakon.AppManager.backup.convert.ImportType;\nimport io.github.muntashirakon.AppManager.history.JsonDeserializer;\n\npublic class BatchBackupImportOptions implements IBatchOpOptions {\n    public static final String TAG = BatchBackupImportOptions.class.getSimpleName();\n\n    @ImportType\n    private int mImportType;\n    @NonNull\n    private Uri mDirectory;\n    private boolean mRemoveImportedDirectory;\n\n    public BatchBackupImportOptions(@ImportType int importType, @NonNull Uri directory,\n                                    boolean removeImportedDirectory) {\n        mImportType = importType;\n        mDirectory = directory;\n        mRemoveImportedDirectory = removeImportedDirectory;\n    }\n\n    @ImportType\n    public int getImportType() {\n        return mImportType;\n    }\n\n    @NonNull\n    public Uri getDirectory() {\n        return mDirectory;\n    }\n\n    public boolean isRemoveImportedDirectory() {\n        return mRemoveImportedDirectory;\n    }\n\n    protected BatchBackupImportOptions(@NonNull Parcel in) {\n        mImportType = in.readInt();\n        mDirectory = Objects.requireNonNull(ParcelCompat.readParcelable(in,\n                Uri.class.getClassLoader(), Uri.class));\n        mRemoveImportedDirectory = in.readByte() != 0;\n    }\n\n    public static final Creator<BatchBackupImportOptions> CREATOR = new Creator<BatchBackupImportOptions>() {\n        @Override\n        @NonNull\n        public BatchBackupImportOptions createFromParcel(@NonNull Parcel in) {\n            return new BatchBackupImportOptions(in);\n        }\n\n        @Override\n        @NonNull\n        public BatchBackupImportOptions[] newArray(int size) {\n            return new BatchBackupImportOptions[size];\n        }\n    };\n\n    @Override\n    public int describeContents() {\n        return 0;\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        dest.writeInt(mImportType);\n        dest.writeParcelable(mDirectory, flags);\n        dest.writeByte((byte) (mRemoveImportedDirectory ? 1 : 0));\n    }\n\n    protected BatchBackupImportOptions(@NonNull JSONObject jsonObject) throws JSONException {\n        assert jsonObject.getString(\"tag\").equals(TAG);\n        mImportType = jsonObject.getInt(\"import_type\");\n        mDirectory = Uri.parse(jsonObject.getString(\"directory\"));\n        mRemoveImportedDirectory = jsonObject.getBoolean(\"remove_imported_directory\");\n    }\n\n    public static final JsonDeserializer.Creator<BatchBackupImportOptions> DESERIALIZER\n            = BatchBackupImportOptions::new;\n\n    @NonNull\n    @Override\n    public JSONObject serializeToJson() throws JSONException {\n        JSONObject jsonObject = new JSONObject();\n        jsonObject.put(\"tag\", TAG);\n        jsonObject.put(\"import_type\", mImportType);\n        jsonObject.put(\"directory\", mDirectory.toString());\n        jsonObject.put(\"remove_imported_directory\", mRemoveImportedDirectory);\n        return jsonObject;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/batchops/struct/BatchBackupOptions.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.batchops.struct;\n\nimport android.annotation.UserIdInt;\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport org.json.JSONException;\nimport org.json.JSONObject;\n\nimport io.github.muntashirakon.AppManager.backup.BackupFlags;\nimport io.github.muntashirakon.AppManager.backup.BackupUtils;\nimport io.github.muntashirakon.AppManager.backup.struct.BackupOpOptions;\nimport io.github.muntashirakon.AppManager.backup.struct.DeleteOpOptions;\nimport io.github.muntashirakon.AppManager.backup.struct.RestoreOpOptions;\nimport io.github.muntashirakon.AppManager.db.entity.Backup;\nimport io.github.muntashirakon.AppManager.history.JsonDeserializer;\nimport io.github.muntashirakon.AppManager.utils.ContextUtils;\nimport io.github.muntashirakon.AppManager.utils.DateUtils;\nimport io.github.muntashirakon.AppManager.utils.JSONUtils;\n\npublic class BatchBackupOptions implements IBatchOpOptions {\n    public static final String TAG = BatchBackupOptions.class.getSimpleName();\n\n    @BackupFlags.BackupFlag\n    private final int mFlags;\n    @Nullable\n    private final String[] mBackupNames;\n    @Nullable\n    private final String[] mRelativeDirs;\n\n    public BatchBackupOptions(@BackupFlags.BackupFlag int flags,\n                              @Nullable String[] backupNames,\n                              @Nullable String[] relativeDirs) {\n        mFlags = flags;\n        mBackupNames = backupNames;\n        mRelativeDirs = relativeDirs;\n    }\n\n    public BackupOpOptions getBackupOpOptions(@NonNull String packageName, @UserIdInt int userId) {\n        String backupName;\n        boolean customBackup = (mFlags & BackupFlags.BACKUP_MULTIPLE) != 0;\n        if (mBackupNames != null && mBackupNames.length > 0) {\n            backupName = mBackupNames[0];\n        } else {\n            backupName = customBackup ? DateUtils.formatMediumDateTime(ContextUtils.getContext(), System.currentTimeMillis()) : null;\n        }\n        return new BackupOpOptions(packageName, userId, mFlags, backupName, !customBackup);\n    }\n\n    public RestoreOpOptions getRestoreOpOptions(@NonNull String packageName, @UserIdInt int userId) {\n        // For restore operation, backup names (v4) and relative dirs are only set for single\n        // package backups. In all other cases, it only uses base backups.\n        String relativeDir;\n        if (mRelativeDirs != null && mRelativeDirs.length > 0) {\n            relativeDir = mRelativeDirs[0];\n        } else {\n            if (mBackupNames == null || mBackupNames.length == 0) {\n                // Base backup\n                relativeDir = null;\n            } else {\n                // Generate relative directories\n                Backup backup = BackupUtils.retrieveLatestBackupFromDb(userId, mBackupNames[0], packageName);\n                if (backup == null) {\n                    throw new IllegalArgumentException(\"Backup with name \" + mBackupNames[0] + \" doesn't exist.\");\n                }\n                relativeDir = backup.relativeDir;\n            }\n        }\n        return new RestoreOpOptions(packageName, userId, relativeDir, mFlags);\n    }\n\n    public DeleteOpOptions getDeleteOpOptions(@NonNull String packageName, @UserIdInt int userId) {\n        // For delete operation, backup names (v4) and relative dirs are only set for single\n        // package backups. In all other cases, it only uses base backups.\n        String[] relativeDirs;\n        if (mRelativeDirs != null) {\n            relativeDirs = mRelativeDirs;\n        } else {\n            if (mBackupNames == null || mBackupNames.length == 0) {\n                // Base backup\n                relativeDirs = null;\n            } else {\n                // Generate relative directories\n                relativeDirs = new String[mBackupNames.length];\n                for (int i = 0; i < relativeDirs.length; ++i) {\n                    Backup backup = BackupUtils.retrieveLatestBackupFromDb(userId, mBackupNames[i], packageName);\n                    if (backup == null) {\n                        throw new IllegalArgumentException(\"Backup with name \" + mBackupNames[i] + \" doesn't exist.\");\n                    }\n                    relativeDirs[i] = backup.relativeDir;\n                }\n            }\n        }\n        return new DeleteOpOptions(packageName, userId, relativeDirs);\n    }\n\n    protected BatchBackupOptions(@NonNull Parcel in) {\n        mFlags = in.readInt();\n        mBackupNames = in.createStringArray();\n        mRelativeDirs = in.createStringArray();\n    }\n\n    public static final Creator<BatchBackupOptions> CREATOR = new Creator<BatchBackupOptions>() {\n        @Override\n        @NonNull\n        public BatchBackupOptions createFromParcel(@NonNull Parcel in) {\n            return new BatchBackupOptions(in);\n        }\n\n        @Override\n        @NonNull\n        public BatchBackupOptions[] newArray(int size) {\n            return new BatchBackupOptions[size];\n        }\n    };\n\n    @Override\n    public int describeContents() {\n        return 0;\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        dest.writeInt(mFlags);\n        dest.writeStringArray(mBackupNames);\n        dest.writeStringArray(mRelativeDirs);\n    }\n\n    public BatchBackupOptions(@NonNull JSONObject jsonObject) throws JSONException {\n        assert jsonObject.getString(\"tag\").equals(TAG);\n        mFlags = jsonObject.getInt(\"flags\");\n        mBackupNames = JSONUtils.getArray(String.class, jsonObject.optJSONArray(\"backup_names\"));\n        mRelativeDirs = JSONUtils.getArray(String.class, jsonObject.optJSONArray(\"relative_dirs\"));\n    }\n\n    public static final JsonDeserializer.Creator<BatchBackupOptions> DESERIALIZER\n            = BatchBackupOptions::new;\n\n    @NonNull\n    @Override\n    public JSONObject serializeToJson() throws JSONException {\n        JSONObject jsonObject = new JSONObject();\n        jsonObject.put(\"tag\", TAG);\n        jsonObject.put(\"flags\", mFlags);\n        jsonObject.put(\"backup_names\", JSONUtils.getJSONArray(mBackupNames));\n        jsonObject.put(\"relative_dirs\", JSONUtils.getJSONArray(mRelativeDirs));\n        return jsonObject;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/batchops/struct/BatchComponentOptions.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.batchops.struct;\n\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport org.json.JSONException;\nimport org.json.JSONObject;\n\nimport java.util.Objects;\n\nimport io.github.muntashirakon.AppManager.history.JsonDeserializer;\nimport io.github.muntashirakon.AppManager.utils.JSONUtils;\n\npublic class BatchComponentOptions implements IBatchOpOptions {\n    public static final String TAG = BatchComponentOptions.class.getSimpleName();\n\n    @NonNull\n    private String[] mSignatures;\n\n    public BatchComponentOptions(@NonNull String[] signatures) {\n        mSignatures = signatures;\n    }\n\n    @NonNull\n    public String[] getSignatures() {\n        return mSignatures;\n    }\n\n    protected BatchComponentOptions(@NonNull Parcel in) {\n        mSignatures = Objects.requireNonNull(in.createStringArray());\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        dest.writeStringArray(mSignatures);\n    }\n\n    protected BatchComponentOptions(@NonNull JSONObject jsonObject) throws JSONException {\n        assert jsonObject.getString(\"tag\").equals(TAG);\n        mSignatures = JSONUtils.getArray(String.class, jsonObject.getJSONArray(\"signatures\"));\n    }\n\n    public static final JsonDeserializer.Creator<BatchComponentOptions> DESERIALIZER\n            = BatchComponentOptions::new;\n\n    @NonNull\n    @Override\n    public JSONObject serializeToJson() throws JSONException {\n        JSONObject jsonObject = new JSONObject();\n        jsonObject.put(\"tag\", TAG);\n        jsonObject.put(\"signatures\", JSONUtils.getJSONArray(mSignatures));\n        return jsonObject;\n    }\n\n    @Override\n    public int describeContents() {\n        return 0;\n    }\n\n    public static final Creator<BatchComponentOptions> CREATOR = new Creator<BatchComponentOptions>() {\n        @Override\n        @NonNull\n        public BatchComponentOptions createFromParcel(@NonNull Parcel in) {\n            return new BatchComponentOptions(in);\n        }\n\n        @Override\n        @NonNull\n        public BatchComponentOptions[] newArray(int size) {\n            return new BatchComponentOptions[size];\n        }\n    };\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/batchops/struct/BatchDexOptOptions.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.batchops.struct;\n\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\nimport androidx.core.os.ParcelCompat;\n\nimport org.json.JSONException;\nimport org.json.JSONObject;\n\nimport java.util.Objects;\n\nimport io.github.muntashirakon.AppManager.apk.dexopt.DexOptOptions;\nimport io.github.muntashirakon.AppManager.history.JsonDeserializer;\n\npublic class BatchDexOptOptions implements IBatchOpOptions {\n    public static final String TAG = BatchDexOptOptions.class.getSimpleName();\n    private DexOptOptions mDexOptOptions;\n\n    public BatchDexOptOptions(@NonNull DexOptOptions dexOptOptions) {\n        mDexOptOptions = dexOptOptions;\n    }\n\n    public DexOptOptions getDexOptOptions() {\n        return mDexOptOptions;\n    }\n\n    protected BatchDexOptOptions(@NonNull Parcel in) {\n        mDexOptOptions = Objects.requireNonNull(ParcelCompat.readParcelable(in,\n                DexOptOptions.class.getClassLoader(), DexOptOptions.class));\n    }\n\n    public static final Creator<BatchDexOptOptions> CREATOR = new Creator<BatchDexOptOptions>() {\n        @Override\n        @NonNull\n        public BatchDexOptOptions createFromParcel(@NonNull Parcel in) {\n            return new BatchDexOptOptions(in);\n        }\n\n        @Override\n        @NonNull\n        public BatchDexOptOptions[] newArray(int size) {\n            return new BatchDexOptOptions[size];\n        }\n    };\n\n    @Override\n    public int describeContents() {\n        return 0;\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        dest.writeParcelable(mDexOptOptions, flags);\n    }\n\n    protected BatchDexOptOptions(@NonNull JSONObject jsonObject) throws JSONException {\n        assert jsonObject.getString(\"tag\").equals(TAG);\n        mDexOptOptions = DexOptOptions.DESERIALIZER.deserialize(jsonObject.getJSONObject(\"dex_opt_options\"));\n    }\n\n    public static final JsonDeserializer.Creator<BatchDexOptOptions> DESERIALIZER\n            = BatchDexOptOptions::new;\n\n    @NonNull\n    @Override\n    public JSONObject serializeToJson() throws JSONException {\n        JSONObject jsonObject = new JSONObject();\n        jsonObject.put(\"tag\", TAG);\n        jsonObject.put(\"dex_opt_options\", mDexOptOptions.serializeToJson());\n        return jsonObject;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/batchops/struct/BatchFreezeOptions.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.batchops.struct;\n\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport org.json.JSONException;\nimport org.json.JSONObject;\n\nimport io.github.muntashirakon.AppManager.history.JsonDeserializer;\nimport io.github.muntashirakon.AppManager.utils.FreezeUtils;\n\npublic class BatchFreezeOptions implements IBatchOpOptions {\n    public static final String TAG = BatchFreezeOptions.class.getSimpleName();\n\n    @FreezeUtils.FreezeMethod\n    private int mType;\n    private boolean mPreferCustom;\n\n    public BatchFreezeOptions(@FreezeUtils.FreezeMethod int type, boolean preferCustom) {\n        mType = type;\n        mPreferCustom = preferCustom;\n    }\n\n    public int getType() {\n        return mType;\n    }\n\n    public boolean isPreferCustom() {\n        return mPreferCustom;\n    }\n\n    @Override\n    public int describeContents() {\n        return 0;\n    }\n\n    protected BatchFreezeOptions(@NonNull JSONObject jsonObject) throws JSONException {\n        assert jsonObject.getString(\"tag\").equals(TAG);\n        mType = jsonObject.getInt(\"type\");\n        mPreferCustom = jsonObject.getBoolean(\"prefer_custom\");\n    }\n\n\n    public static final JsonDeserializer.Creator<BatchFreezeOptions> DESERIALIZER\n            = BatchFreezeOptions::new;\n\n    protected BatchFreezeOptions(@NonNull Parcel in) {\n        mType = in.readInt();\n        mPreferCustom = in.readByte() != 0;\n    }\n\n    public static final Creator<BatchFreezeOptions> CREATOR = new Creator<BatchFreezeOptions>() {\n        @NonNull\n        @Override\n        public BatchFreezeOptions createFromParcel(@NonNull Parcel in) {\n            return new BatchFreezeOptions(in);\n        }\n\n        @NonNull\n        @Override\n        public BatchFreezeOptions[] newArray(int size) {\n            return new BatchFreezeOptions[size];\n        }\n    };\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        dest.writeInt(mType);\n        dest.writeByte((byte) (mPreferCustom ? 1 : 0));\n    }\n\n    @NonNull\n    @Override\n    public JSONObject serializeToJson() throws JSONException {\n        JSONObject jsonObject = new JSONObject();\n        jsonObject.put(\"tag\", TAG);\n        jsonObject.put(\"type\", mType);\n        jsonObject.put(\"prefer_custom\", mPreferCustom);\n        return jsonObject;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/batchops/struct/BatchNetPolicyOptions.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.batchops.struct;\n\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport org.json.JSONException;\nimport org.json.JSONObject;\n\nimport io.github.muntashirakon.AppManager.compat.NetworkPolicyManagerCompat.NetPolicy;\nimport io.github.muntashirakon.AppManager.history.JsonDeserializer;\n\npublic class BatchNetPolicyOptions implements IBatchOpOptions {\n    public static final String TAG = BatchNetPolicyOptions.class.getSimpleName();\n    @NetPolicy\n    private int mPolicies;\n\n    public BatchNetPolicyOptions(@NetPolicy int policies) {\n        mPolicies = policies;\n    }\n\n    @NetPolicy\n    public int getPolicies() {\n        return mPolicies;\n    }\n\n    protected BatchNetPolicyOptions(@NonNull Parcel in) {\n        mPolicies = in.readInt();\n    }\n\n    public static final Creator<BatchNetPolicyOptions> CREATOR = new Creator<BatchNetPolicyOptions>() {\n        @Override\n        @NonNull\n        public BatchNetPolicyOptions createFromParcel(@NonNull Parcel in) {\n            return new BatchNetPolicyOptions(in);\n        }\n\n        @Override\n        @NonNull\n        public BatchNetPolicyOptions[] newArray(int size) {\n            return new BatchNetPolicyOptions[size];\n        }\n    };\n\n    @Override\n    public int describeContents() {\n        return 0;\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        dest.writeInt(mPolicies);\n    }\n\n    protected BatchNetPolicyOptions(@NonNull JSONObject jsonObject) throws JSONException {\n        assert jsonObject.getString(\"tag\").equals(TAG);\n        mPolicies = jsonObject.getInt(\"policies\");\n    }\n\n    public static final JsonDeserializer.Creator<BatchNetPolicyOptions> DESERIALIZER\n            = BatchNetPolicyOptions::new;\n\n    @NonNull\n    @Override\n    public JSONObject serializeToJson() throws JSONException {\n        JSONObject jsonObject = new JSONObject();\n        jsonObject.put(\"tag\", TAG);\n        jsonObject.put(\"policies\", mPolicies);\n        return jsonObject;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/batchops/struct/BatchPermissionOptions.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.batchops.struct;\n\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\nimport org.json.JSONException;\nimport org.json.JSONObject;\n\nimport java.util.Objects;\n\nimport io.github.muntashirakon.AppManager.history.JsonDeserializer;\nimport io.github.muntashirakon.AppManager.utils.JSONUtils;\n\npublic class BatchPermissionOptions implements IBatchOpOptions {\n    public static final String TAG = BatchPermissionOptions.class.getSimpleName();\n    @NonNull\n    private String[] mPermissions;\n\n    public BatchPermissionOptions(@NonNull String[] permissions) {\n        mPermissions = permissions;\n    }\n\n    @NonNull\n    public String[] getPermissions() {\n        return mPermissions;\n    }\n\n    protected BatchPermissionOptions(@NonNull Parcel in) {\n        mPermissions = Objects.requireNonNull(in.createStringArray());\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        dest.writeStringArray(mPermissions);\n    }\n\n    protected BatchPermissionOptions(@NonNull JSONObject jsonObject) throws JSONException {\n        assert jsonObject.getString(\"tag\").equals(TAG);\n        mPermissions = JSONUtils.getArray(String.class, jsonObject.getJSONArray(\"permissions\"));\n    }\n\n    public static final JsonDeserializer.Creator<BatchPermissionOptions> DESERIALIZER\n            = BatchPermissionOptions::new;\n\n    @NonNull\n    @Override\n    public JSONObject serializeToJson() throws JSONException {\n        JSONObject jsonObject = new JSONObject();\n        jsonObject.put(\"tag\", TAG);\n        jsonObject.put(\"permissions\", JSONUtils.getJSONArray(mPermissions));\n        return jsonObject;\n    }\n\n    @Override\n    public int describeContents() {\n        return 0;\n    }\n\n    public static final Creator<BatchPermissionOptions> CREATOR = new Creator<BatchPermissionOptions>() {\n        @Override\n        @NonNull\n        public BatchPermissionOptions createFromParcel(@NonNull Parcel in) {\n            return new BatchPermissionOptions(in);\n        }\n\n        @Override\n        @NonNull\n        public BatchPermissionOptions[] newArray(int size) {\n            return new BatchPermissionOptions[size];\n        }\n    };\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/batchops/struct/IBatchOpOptions.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.batchops.struct;\n\nimport android.os.Parcelable;\n\nimport org.json.JSONException;\n\nimport io.github.muntashirakon.AppManager.history.IJsonSerializer;\nimport io.github.muntashirakon.AppManager.history.JsonDeserializer;\nimport io.github.muntashirakon.AppManager.utils.JSONUtils;\n\npublic interface IBatchOpOptions extends Parcelable, IJsonSerializer {\n    JsonDeserializer.Creator<IBatchOpOptions> DESERIALIZER = jsonObject -> {\n        String tag = JSONUtils.getString(jsonObject, \"tag\");\n        if (BatchAppOpsOptions.TAG.equals(tag)) {\n            return BatchAppOpsOptions.DESERIALIZER.deserialize(jsonObject);\n        } else if (BatchBackupImportOptions.TAG.equals(tag)) {\n            return BatchBackupImportOptions.DESERIALIZER.deserialize(jsonObject);\n        } else if (BatchBackupOptions.TAG.equals(tag)) {\n            return BatchBackupOptions.DESERIALIZER.deserialize(jsonObject);\n        } else if (BatchComponentOptions.TAG.equals(tag)) {\n            return BatchComponentOptions.DESERIALIZER.deserialize(jsonObject);\n        } else if (BatchDexOptOptions.TAG.equals(tag)) {\n            return BatchDexOptOptions.DESERIALIZER.deserialize(jsonObject);\n        }  else if (BatchFreezeOptions.TAG.equals(tag)) {\n            return BatchFreezeOptions.DESERIALIZER.deserialize(jsonObject);\n        } else if (BatchNetPolicyOptions.TAG.equals(tag)) {\n            return BatchNetPolicyOptions.DESERIALIZER.deserialize(jsonObject);\n        } else if (BatchPermissionOptions.TAG.equals(tag)) {\n            return BatchPermissionOptions.DESERIALIZER.deserialize(jsonObject);\n        } else throw new JSONException(\"Invalid tag: \" + tag);\n    };\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/changelog/Changelog.java",
    "content": "// SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.changelog;\n\nimport androidx.annotation.NonNull;\n\nimport java.util.LinkedList;\n\n// Copyright 2013 Gabriele Mariotti <gabri.mariotti@gmail.com>\n// Copyright 2022 Muntashir Al-Islam\npublic class Changelog {\n    @NonNull\n    private final LinkedList<ChangelogItem> mChangelogItems;\n\n    private boolean mBulletedList;\n\n    public Changelog() {\n        mChangelogItems = new LinkedList<>();\n    }\n\n    public void addItem(@NonNull ChangelogItem row) {\n        mChangelogItems.add(row);\n    }\n\n    /**\n     * Clear all rows\n     */\n    public void clearAllRows() {\n        mChangelogItems.clear();\n    }\n\n    public boolean isBulletedList() {\n        return mBulletedList;\n    }\n\n    public void setBulletedList(boolean bulletedList) {\n        mBulletedList = bulletedList;\n    }\n\n    public LinkedList<ChangelogItem> getChangelogItems() {\n        return mChangelogItems;\n    }\n}"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/changelog/ChangelogHeader.java",
    "content": "// SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.changelog;\n\nimport androidx.annotation.NonNull;\n\nimport java.util.Locale;\n\n// Copyright 2013 Gabriele Mariotti <gabri.mariotti@gmail.com>\n// Copyright 2022 Muntashir Al-Islam\npublic class ChangelogHeader extends ChangelogItem {\n    @NonNull\n    private final String mVersionName;\n    private final long mVersionCode;\n    @NonNull\n    private final String mReleaseType;\n    @NonNull\n    private final String mReleaseDate;\n\n    public ChangelogHeader(@NonNull String versionName, long versionCode, @NonNull String releaseType, @NonNull String releaseDate) {\n        super(parseHeaderText(versionName, versionCode), HEADER);\n        mVersionName = versionName;\n        mVersionCode = versionCode;\n        mReleaseType = releaseType;\n        mReleaseDate = releaseDate;\n        setBulletedList(false);\n    }\n\n    @NonNull\n    public String getVersionName() {\n        return mVersionName;\n    }\n\n    public long getVersionCode() {\n        return mVersionCode;\n    }\n\n    @NonNull\n    public String getReleaseType() {\n        return mReleaseType;\n    }\n\n    @NonNull\n    public String getReleaseDate() {\n        return mReleaseDate;\n    }\n\n    @NonNull\n    private static CharSequence parseHeaderText(@NonNull String versionName, long versionCode) {\n        return String.format(Locale.getDefault(), \"Version %s (%d)\", versionName, versionCode);\n    }\n}"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/changelog/ChangelogItem.java",
    "content": "// SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.changelog;\n\nimport androidx.annotation.IntDef;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.core.text.HtmlCompat;\n\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\n\n// Copyright 2013 Gabriele Mariotti <gabri.mariotti@gmail.com>\n// Copyright 2022 Muntashir Al-Islam\npublic class ChangelogItem {\n    @IntDef({HEADER, TITLE, NOTE, NEW, IMPROVE, FIX})\n    @Retention(RetentionPolicy.SOURCE)\n    public @interface ChangelogType {\n    }\n\n    public static final int HEADER = -1;\n    public static final int TITLE = 0;\n    public static final int NOTE = 1;\n    public static final int NEW = 2;\n    public static final int IMPROVE = 3;\n    public static final int FIX = 4;\n\n    @IntDef({TEXT_SMALL, TEXT_MEDIUM, TEXT_LARGE})\n    @Retention(RetentionPolicy.SOURCE)\n    public @interface ChangeTextType {\n    }\n\n    public static final int TEXT_SMALL = 0;\n    public static final int TEXT_MEDIUM = 1;\n    public static final int TEXT_LARGE = 2;\n\n    @ChangelogType\n    public final int type;\n\n    @NonNull\n    private final CharSequence mChangeText;\n\n    private boolean mBulletedList;\n    private boolean mSubtext;\n    @Nullable\n    private String mChangeTitle;\n    @ChangeTextType\n    private int mChangeTextType;\n\n    public ChangelogItem(@ChangelogType int type) {\n        mChangeText = \"\";\n        this.type = type;\n    }\n\n    public ChangelogItem(@NonNull CharSequence changeText, @ChangelogType int type) {\n        mChangeText = changeText;\n        this.type = type;\n    }\n\n    public ChangelogItem(@NonNull String changeText, @ChangelogType int type) {\n        mChangeText = parseChangeText(changeText);\n        this.type = type;\n    }\n\n    public boolean isBulletedList() {\n        return mBulletedList;\n    }\n\n    public void setBulletedList(boolean bulletedList) {\n        mBulletedList = bulletedList;\n    }\n\n    public boolean isSubtext() {\n        return mSubtext;\n    }\n\n    public void setSubtext(boolean subtext) {\n        mSubtext = subtext;\n        mChangeTextType = subtext ? TEXT_SMALL : TEXT_MEDIUM;\n    }\n\n    @NonNull\n    public CharSequence getChangeText() {\n        return mChangeText;\n    }\n\n    @Nullable\n    public String getChangeTitle() {\n        return mChangeTitle;\n    }\n\n    void setChangeTitle(@Nullable String changeTitle) {\n        mChangeTitle = changeTitle;\n    }\n\n    @ChangeTextType\n    public int getChangeTextType() {\n        return mChangeTextType;\n    }\n\n    public void setChangeTextType(@ChangeTextType int changeTextType) {\n        mChangeTextType = changeTextType;\n    }\n\n    @NonNull\n    public static CharSequence parseChangeText(@NonNull String changeText) {\n        // TODO: Supported markups **Bold**, __Italic__, `Monospace`, ~~Strikethrough~~, [Link](link_name)\n        changeText = changeText.replaceAll(\"\\\\[\", \"<\").replaceAll(\"\\\\]\", \">\");\n        return HtmlCompat.fromHtml(changeText, HtmlCompat.FROM_HTML_MODE_COMPACT);\n    }\n}"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/changelog/ChangelogParser.java",
    "content": "// SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.changelog;\n\nimport android.content.Context;\nimport android.util.Log;\nimport android.util.Xml;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.RawRes;\n\nimport org.xmlpull.v1.XmlPullParser;\nimport org.xmlpull.v1.XmlPullParserException;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Objects;\n\n/**\n * Read and parse res/raw/changelog.xml.\n */\n// Copyright 2013 Gabriele Mariotti <gabri.mariotti@gmail.com>\n// Copyright 2022 Muntashir Al-Islam\npublic class ChangelogParser {\n    private static final String TAG = ChangelogParser.class.getSimpleName();\n\n    private static final String TAG_CHANGELOG = \"changelog\";\n    private static final String TAG_RELEASE = \"release\";\n    private static final String TAG_TITLE = \"title\";\n    private static final String TAG_NEW = \"new\";\n    private static final String TAG_IMPROVE = \"improve\";\n    private static final String TAG_FIX = \"fix\";\n    private static final String TAG_NOTE = \"note\";\n\n    private static final String ATTR_RELEASE_TYPE = \"type\";\n    private static final String ATTR_RELEASE_VERSION = \"version\";\n    private static final String ATTR_RELEASE_CODE = \"code\";\n    private static final String ATTR_RELEASE_DATE = \"date\";\n\n    private static final String ATTR_TYPE = \"type\";\n\n    private static final String ATTR_TITLE = \"title\";\n    private static final String ATTR_BULLET = \"bullet\";\n    private static final String ATTR_SUBTEXT = \"subtext\";\n\n    private static final List<String> CHANGE_LOG_TAGS = new ArrayList<String>() {{\n        add(TAG_TITLE);\n        add(TAG_NEW);\n        add(TAG_IMPROVE);\n        add(TAG_FIX);\n        add(TAG_NOTE);\n    }};\n\n    protected Context mContext;\n\n    @RawRes\n    private final int mChangeLogFileResourceId;\n    private final long mStartVersion;\n\n    /**\n     * Create a new instance for a context and for a custom changelog file.\n     * <p>\n     * You have to use file in res/raw folder.\n     *\n     * @param context                 current Context\n     * @param changeLogFileResourceId reference for a custom xml file\n     */\n    public ChangelogParser(@NonNull Context context, @RawRes int changeLogFileResourceId) {\n        this(context, changeLogFileResourceId, 0);\n    }\n\n    /**\n     * Create a new instance for a context and for a custom changelog file.\n     * <p>\n     * You have to use file in res/raw folder.\n     *\n     * @param context                 current Context\n     * @param changeLogFileResourceId reference for a custom xml file\n     */\n    public ChangelogParser(@NonNull Context context, @RawRes int changeLogFileResourceId, long startVersion) {\n        mContext = context;\n        mChangeLogFileResourceId = changeLogFileResourceId;\n        mStartVersion = startVersion;\n    }\n\n    /**\n     * Read and parse res/raw/changelog.xml\n     *\n     * @return {@link Changelog} obj with all data\n     * @throws IOException            if changelog.xml is not found\n     * @throws XmlPullParserException if there are errors during parsing\n     */\n    @NonNull\n    public Changelog parse() throws IOException, XmlPullParserException {\n        try (InputStream is = mContext.getResources().openRawResource(mChangeLogFileResourceId)) {\n            Changelog changelog = new Changelog();\n            XmlPullParser parser = Xml.newPullParser();\n            parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false);\n            parser.setInput(is, \"UTF-8\");\n            parser.nextTag();\n            // Read changelog tag\n            readChangelogTag(parser, changelog);\n            return changelog;\n        }\n    }\n\n\n    /**\n     * Parse changelog node\n     */\n    protected void readChangelogTag(@NonNull XmlPullParser parser, @NonNull Changelog changeLog) throws IOException, XmlPullParserException {\n        // changelog is the root\n        if (parser.getDepth() != 1) {\n            Log.e(TAG, String.format(Locale.ROOT, \"Invalid depth %d, expecting depth 1.\", parser.getDepth()));\n            return;\n        }\n        parser.require(XmlPullParser.START_TAG, null, TAG_CHANGELOG);\n\n        // Read attributes\n        String showBullet = parser.getAttributeValue(null, ATTR_BULLET);\n        changeLog.setBulletedList(\"true\".equals(showBullet));\n\n        // Parse nested nodes\n        while (parser.next() != XmlPullParser.END_TAG) {\n            if (parser.getEventType() != XmlPullParser.START_TAG || parser.getDepth() != 2) {\n                continue;\n            }\n            if (TAG_RELEASE.equals(parser.getName())) {\n                // Parse new, improve, fix, note\n                readReleaseTag(parser, changeLog);\n            } else {\n                Log.w(TAG, String.format(Locale.ROOT, \"Unknown tag (%s) at depth 2.\" + parser.getName()));\n            }\n        }\n    }\n\n    /**\n     * Parse changeLogVersion node\n     */\n    private void readReleaseTag(@NonNull XmlPullParser parser, @NonNull Changelog changeLog) throws IOException, XmlPullParserException {\n        // Ensure release tag\n        if (parser.getDepth() != 2) {\n            Log.e(TAG, String.format(Locale.ROOT, \"Invalid depth %d, expecting depth 2.\", parser.getDepth()));\n            return;\n        }\n        parser.require(XmlPullParser.START_TAG, null, TAG_RELEASE);\n\n        // Read attributes\n        String versionName = Objects.requireNonNull(parser.getAttributeValue(null, ATTR_RELEASE_VERSION));\n        String versionCodeStr = Objects.requireNonNull(parser.getAttributeValue(null, ATTR_RELEASE_CODE));\n        long versionCode = 0;\n        try {\n            versionCode = Integer.parseInt(versionCodeStr);\n        } catch (NumberFormatException e) {\n            Log.w(TAG, \"Error while parsing versionCode.\");\n        }\n        String releaseDate = Objects.requireNonNull(parser.getAttributeValue(null, ATTR_RELEASE_DATE));\n        String releaseType = Objects.requireNonNull(parser.getAttributeValue(null, ATTR_RELEASE_TYPE));\n\n        // Skip parsing this node if versionCode < startVersionCode\n        if (versionCode < mStartVersion) {\n            while (parser.next() != XmlPullParser.END_TAG) {\n                // Continue parsing until end is reached\n            }\n            return;\n        }\n\n        // Set release meta\n        changeLog.addItem(new ChangelogHeader(versionName, versionCode, releaseType, releaseDate));\n\n        // Parse nested nodes\n        while (parser.next() != XmlPullParser.END_TAG) {\n            if (parser.getEventType() != XmlPullParser.START_TAG || parser.getDepth() != 3) {\n                continue;\n            }\n            if (CHANGE_LOG_TAGS.contains(parser.getName())) {\n                readChangelogItemTags(parser, changeLog);\n            } else {\n                Log.w(TAG, String.format(Locale.ROOT, \"Unknown tag (%s) at depth 3.\" + parser.getName()));\n            }\n        }\n    }\n\n    /**\n     * Parse changeLogText node\n     */\n    private void readChangelogItemTags(@NonNull XmlPullParser parser, @NonNull Changelog changeLog) throws XmlPullParserException, IOException {\n        if (parser.getDepth() != 3) {\n            Log.e(TAG, String.format(Locale.ROOT, \"Invalid depth %d, expecting depth 3.\", parser.getDepth()));\n            return;\n        }\n\n        String tag = parser.getName();\n\n        // Read attributes\n        String changeTextType = parser.getAttributeValue(null, ATTR_TYPE);\n        String title = parser.getAttributeValue(null, ATTR_TITLE);\n        String showBullet = parser.getAttributeValue(null, ATTR_BULLET);\n        String subtext = parser.getAttributeValue(null, ATTR_SUBTEXT);\n\n        // Read text\n        String changeText = null;\n        if (parser.next() == XmlPullParser.TEXT) {\n            changeText = parser.getText();\n            parser.nextTag();\n        }\n\n        // Set type\n        int type;\n        switch (tag) {\n            default:\n            case TAG_NOTE:\n                type = ChangelogItem.NOTE;\n                break;\n            case TAG_TITLE:\n                type = ChangelogItem.TITLE;\n                break;\n            case TAG_NEW:\n                type = ChangelogItem.NEW;\n                break;\n            case TAG_IMPROVE:\n                type = ChangelogItem.IMPROVE;\n                break;\n            case TAG_FIX:\n                type = ChangelogItem.FIX;\n                break;\n        }\n\n        ChangelogItem changelogItem = changeText == null ? new ChangelogItem(type) : new ChangelogItem(changeText, type);\n        changelogItem.setChangeTitle(title);\n        changelogItem.setBulletedList(\"true\".equals(showBullet) || changeLog.isBulletedList());\n        changelogItem.setChangeTextType(getChangeTextType(changeTextType));\n        changelogItem.setSubtext(\"true\".equals(subtext));\n        changeLog.addItem(changelogItem);\n    }\n\n    @ChangelogItem.ChangeTextType\n    private static int getChangeTextType(@Nullable String rawText) {\n        if (rawText == null) {\n            return ChangelogItem.TEXT_MEDIUM;\n        }\n        switch (rawText) {\n            default:\n            case \"medium\":\n                return ChangelogItem.TEXT_MEDIUM;\n            case \"large\":\n                return ChangelogItem.TEXT_LARGE;\n            case \"small\":\n                return ChangelogItem.TEXT_SMALL;\n        }\n    }\n}"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/changelog/ChangelogRecyclerAdapter.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.changelog;\n\nimport android.content.Context;\nimport android.graphics.Color;\nimport android.text.SpannableStringBuilder;\nimport android.text.Spanned;\nimport android.text.method.LinkMovementMethod;\nimport android.text.style.ImageSpan;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.TextView;\n\nimport androidx.annotation.ColorInt;\nimport androidx.annotation.ColorRes;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.StringRes;\nimport androidx.annotation.StyleRes;\nimport androidx.core.widget.TextViewCompat;\nimport androidx.recyclerview.widget.RecyclerView;\n\nimport com.google.android.material.chip.ChipDrawable;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.util.AdapterUtils;\nimport io.github.muntashirakon.util.UiUtils;\n\n\npublic class ChangelogRecyclerAdapter extends RecyclerView.Adapter<ChangelogRecyclerAdapter.ViewHolder> {\n    private final List<ChangelogItem> mAdapterList = new ArrayList<>();\n\n    public ChangelogRecyclerAdapter() {\n    }\n\n    public void setAdapterList(@NonNull List<ChangelogItem> list) {\n        synchronized (mAdapterList) {\n            AdapterUtils.notifyDataSetChanged(this, mAdapterList, list);\n        }\n    }\n\n    @ChangelogItem.ChangelogType\n    @Override\n    public int getItemViewType(int position) {\n        synchronized (mAdapterList) {\n            return mAdapterList.get(position).type;\n        }\n    }\n\n    @NonNull\n    @Override\n    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, @ChangelogItem.ChangelogType int viewType) {\n        View v;\n        if (viewType == ChangelogItem.HEADER) {\n            v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_changelog_header, parent, false);\n        } else {\n            v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_changelog_item, parent, false);\n        }\n        return new ViewHolder(v, viewType);\n    }\n\n    @Override\n    public void onBindViewHolder(@NonNull ViewHolder holder, int position) {\n        ChangelogItem changelogItem;\n        synchronized (mAdapterList) {\n            changelogItem = mAdapterList.get(position);\n        }\n        Context context = holder.itemView.getContext();\n        switch (changelogItem.type) {\n            case ChangelogItem.HEADER:\n                holder.label.setText(((ChangelogHeader) changelogItem).getReleaseType());\n                holder.title.setText(changelogItem.getChangeText());\n                holder.subtitle.setText(((ChangelogHeader) changelogItem).getReleaseDate());\n                break;\n            default:\n            case ChangelogItem.TITLE:\n                TextViewCompat.setTextAppearance(holder.subtitle, getTitleTextAppearance(changelogItem.getChangeTextType()));\n                holder.subtitle.setText(getChangeText(context, changelogItem));\n                break;\n            case ChangelogItem.FIX:\n            case ChangelogItem.IMPROVE:\n            case ChangelogItem.NEW:\n            case ChangelogItem.NOTE:\n                TextViewCompat.setTextAppearance(holder.subtitle, getChangeTextAppearance(changelogItem.getChangeTextType()));\n                holder.subtitle.setText(getChangeText(context, changelogItem));\n                break;\n        }\n    }\n\n    @Override\n    public int getItemCount() {\n        synchronized (mAdapterList) {\n            return mAdapterList.size();\n        }\n    }\n\n    @NonNull\n    private CharSequence getChangeText(@NonNull Context context, @NonNull ChangelogItem item) {\n        SpannableStringBuilder sb = new SpannableStringBuilder();\n        if (item.isBulletedList()) {\n            if (item.isSubtext()) {\n                sb.append(\"    \");\n            }\n            sb.append(\"• \");\n        } else {\n            // Display tag\n            @StringRes\n            int tagNameRes;\n            @ColorInt\n            int color;\n            @ColorRes\n            int backgroundColorRes;\n            switch (item.type) {\n                case ChangelogItem.FIX:\n                    tagNameRes = R.string.changelog_type_fix;\n                    backgroundColorRes = io.github.muntashirakon.ui.R.color.changelog_fix;\n                    color = Color.BLACK;\n                    break;\n                case ChangelogItem.IMPROVE:\n                    tagNameRes = R.string.changelog_type_improve;\n                    backgroundColorRes = io.github.muntashirakon.ui.R.color.changelog_improve;\n                    color = Color.WHITE;\n                    break;\n                case ChangelogItem.NEW:\n                    tagNameRes = R.string.changelog_type_new;\n                    backgroundColorRes = io.github.muntashirakon.ui.R.color.changelog_new;\n                    color = Color.WHITE;\n                    break;\n                case ChangelogItem.HEADER:\n                case ChangelogItem.TITLE:\n                case ChangelogItem.NOTE:\n                default:\n                    tagNameRes = 0;\n                    backgroundColorRes = 0;\n                    color = 0;\n                    break;\n            }\n\n            if (tagNameRes != 0) {\n                ChipDrawable chip = ChipDrawable.createFromAttributes(context, null,\n                        com.google.android.material.R.attr.chipStandaloneStyle,\n                        com.google.android.material.R.style.Widget_Material3_Chip_Assist_Elevated);\n                chip.setTextResource(tagNameRes);\n                chip.setTextColor(color);\n                chip.setTextSize(UiUtils.spToPx(context, 10));\n                chip.setChipBackgroundColorResource(backgroundColorRes);\n                chip.setCloseIconVisible(false);\n                chip.setChipStartPadding(0);\n                chip.setChipEndPadding(0);\n                chip.setBounds(0, 0, chip.getIntrinsicWidth(), UiUtils.dpToPx(context, 20));\n                ImageSpan span = new ImageSpan(chip);\n                sb.append(\" \");\n                sb.setSpan(span, sb.length() - 1, sb.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);\n                sb.append(\" \");\n            }\n        }\n        if (item.getChangeTitle() != null) {\n            sb.append('[').append(item.getChangeTitle()).append(\"] \");\n        }\n        return sb.append(item.getChangeText());\n    }\n\n    @StyleRes\n    public static int getChangeTextAppearance(@ChangelogItem.ChangeTextType int type) {\n        switch(type) {\n            default:\n            case ChangelogItem.TEXT_MEDIUM:\n                return com.google.android.material.R.style.TextAppearance_Material3_BodyMedium;\n            case ChangelogItem.TEXT_LARGE:\n                return com.google.android.material.R.style.TextAppearance_Material3_BodyLarge;\n            case ChangelogItem.TEXT_SMALL:\n                return com.google.android.material.R.style.TextAppearance_Material3_BodySmall;\n        }\n    }\n\n    @StyleRes\n    public static int getTitleTextAppearance(@ChangelogItem.ChangeTextType int type) {\n        switch(type) {\n            default:\n            case ChangelogItem.TEXT_MEDIUM:\n                return com.google.android.material.R.style.TextAppearance_Material3_TitleMedium;\n            case ChangelogItem.TEXT_LARGE:\n                return com.google.android.material.R.style.TextAppearance_Material3_TitleLarge;\n            case ChangelogItem.TEXT_SMALL:\n                return com.google.android.material.R.style.TextAppearance_Material3_TitleSmall;\n        }\n    }\n\n    public static class ViewHolder extends RecyclerView.ViewHolder {\n        public final TextView label;\n        public final TextView title;\n        public final TextView subtitle;\n\n        public ViewHolder(@NonNull View itemView, @ChangelogItem.ChangelogType int viewType) {\n            super(itemView);\n            label = itemView.findViewById(R.id.item_label);\n            title = itemView.findViewById(R.id.item_title);\n            subtitle = itemView.findViewById(R.id.item_subtitle);\n            subtitle.setMovementMethod(LinkMovementMethod.getInstance());\n            if (viewType == ChangelogItem.HEADER) {\n                title.setMovementMethod(LinkMovementMethod.getInstance());\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/compat/ActivityManagerCompat.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.compat;\n\nimport android.Manifest;\nimport android.annotation.UserIdInt;\nimport android.app.ActivityManager;\nimport android.app.ActivityManagerNative;\nimport android.app.IActivityManager;\nimport android.content.ComponentName;\nimport android.content.ContentResolver;\nimport android.content.Context;\nimport android.content.IContentProvider;\nimport android.content.IIntentReceiver;\nimport android.content.Intent;\nimport android.os.Build;\nimport android.os.Bundle;\nimport android.os.IBinder;\nimport android.os.RemoteException;\nimport android.os.SystemClock;\nimport android.os.UserHandleHidden;\nimport android.provider.Settings;\nimport android.text.TextUtils;\nimport android.view.KeyEvent;\n\nimport androidx.annotation.MainThread;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.RequiresApi;\nimport androidx.annotation.RequiresPermission;\nimport androidx.annotation.VisibleForTesting;\nimport androidx.annotation.WorkerThread;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.ListIterator;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\nimport io.github.muntashirakon.AppManager.BuildConfig;\nimport io.github.muntashirakon.AppManager.fm.FmProvider;\nimport io.github.muntashirakon.AppManager.ipc.ProxyBinder;\nimport io.github.muntashirakon.AppManager.logs.Log;\nimport io.github.muntashirakon.AppManager.runner.Runner;\nimport io.github.muntashirakon.AppManager.self.SelfPermissions;\nimport io.github.muntashirakon.AppManager.users.Users;\nimport io.github.muntashirakon.AppManager.utils.ExUtils;\nimport io.github.muntashirakon.AppManager.utils.ThreadUtils;\n\npublic final class ActivityManagerCompat {\n    public interface ActivityLaunchUserInteractionRequiredCallback {\n        @WorkerThread\n        void onInteraction();\n    }\n\n    @RequiresPermission(allOf = {\n            Manifest.permission.WRITE_SECURE_SETTINGS,\n            ManifestCompat.permission.INJECT_EVENTS\n    })\n    @MainThread\n    public static boolean startActivityViaAssist(@NonNull Context context, @NonNull ComponentName activity,\n                                              @Nullable ActivityLaunchUserInteractionRequiredCallback callback)\n            throws SecurityException {\n        // Need two permissions: WRITE_SECURE_SETTINGS and INJECT_EVENTS\n        SelfPermissions.requireSelfPermission(Manifest.permission.WRITE_SECURE_SETTINGS);\n        boolean canInjectEvents = SelfPermissions.checkSelfOrRemotePermission(ManifestCompat.permission.INJECT_EVENTS);\n        ContentResolver resolver = context.getContentResolver();\n        // Backup assistant value\n        String assistantComponent = Settings.Secure.getString(resolver, \"assistant\");\n        if (canInjectEvents) {\n            ThreadUtils.postOnBackgroundThread(() -> {\n                try {\n                    // Set assistant value to the target activity component\n                    Settings.Secure.putString(resolver, \"assistant\", activity.flattenToShortString());\n                    // Run it as an assistant by injecting KEYCODE_ASSIST (219)\n                    InputManagerCompat.sendKeyEvent(KeyEvent.KEYCODE_ASSIST, false);\n                    // Wait until system opens the new assistant (i.e., activity), this is an empirical value\n                    SystemClock.sleep(500);\n                } finally {\n                    // Restore assistant value\n                    Settings.Secure.putString(resolver, \"assistant\", assistantComponent);\n                }\n            });\n        } else if (callback != null) {\n            // Cannot launch event by default, use callback\n            ThreadUtils.postOnBackgroundThread(() -> {\n                try {\n                    // Set assistant value to the target activity component\n                    Settings.Secure.putString(resolver, \"assistant\", activity.flattenToShortString());\n                    // Trigger callback\n                    callback.onInteraction();\n                } finally {\n                    // Restore assistant value\n                    Settings.Secure.putString(resolver, \"assistant\", assistantComponent);\n                }\n            });\n        } // else do nothing\n        return canInjectEvents;\n    }\n\n    @SuppressWarnings(\"deprecation\")\n    public static int startActivity(@NonNull Intent intent, @UserIdInt int userHandle) throws SecurityException {\n        IActivityManager am;\n        String callingPackage;\n        if (intent.getData() != null && FmProvider.AUTHORITY.equals(intent.getData().getAuthority())) {\n            // We need unprivileged authority for this\n            am = getActivityManagerUnprivileged();\n            callingPackage = BuildConfig.APPLICATION_ID;\n        } else {\n            am = getActivityManager();\n            callingPackage = SelfPermissions.getCallingPackage(Users.getSelfOrRemoteUid());\n        }\n        try {\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {\n                return am.startActivityAsUserWithFeature(null, callingPackage,\n                        null, intent, intent.getType(), null, null,\n                        0, 0, null, null, userHandle);\n            } else {\n                return am.startActivityAsUser(null, callingPackage, intent, intent.getType(),\n                        null, null, 0, 0, null,\n                        null, userHandle);\n            }\n        } catch (RemoteException e) {\n            return ExUtils.rethrowFromSystemServer(e);\n        }\n    }\n\n    @SuppressWarnings(\"deprecation\")\n    public static ComponentName startService(Intent intent, @UserIdInt int userHandle, boolean asForeground)\n            throws RemoteException {\n        IActivityManager am = getActivityManager();\n        String callingPackage = SelfPermissions.getCallingPackage(Users.getSelfOrRemoteUid());\n        ComponentName cn;\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {\n            cn = am.startService(null, intent, intent.getType(), asForeground, callingPackage, null, userHandle);\n        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {\n            cn = am.startService(null, intent, intent.getType(), asForeground, callingPackage, userHandle);\n        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {\n            cn = am.startService(null, intent, intent.getType(), callingPackage, userHandle);\n        } else cn = am.startService(null, intent, intent.getType(), userHandle);\n        return cn;\n    }\n\n    public static int sendBroadcast(Intent intent, @UserIdInt int userHandle)\n            throws RemoteException {\n        IActivityManager am = getActivityManager();\n        int res;\n        IIntentReceiver receiver = new IntentReceiver();\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {\n            res = am.broadcastIntentWithFeature(null, null, intent, null, receiver, 0, null, null, null, AppOpsManagerCompat.OP_NONE, null, true, false, userHandle);\n        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {\n            res = am.broadcastIntent(null, intent, null, null, 0, null, null, null, AppOpsManagerCompat.OP_NONE, null, true, false, userHandle);\n        } else {\n            res = am.broadcastIntent(null, intent, null, null, 0, null, null, null, AppOpsManagerCompat.OP_NONE, true, false, userHandle);\n        }\n        return res;\n    }\n\n    @Nullable\n    public static IContentProvider getContentProviderExternal(String name, int userId, IBinder token, String tag)\n            throws RemoteException {\n        IActivityManager am = getActivityManager();\n        try {\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {\n                return am.getContentProviderExternal(name, userId, token, tag).provider;\n            } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {\n                return ((android.app.ContentProviderHolder) am.getContentProviderExternal(name, userId, token)).provider;\n            } else {\n                return ((IActivityManager.ContentProviderHolder) am.getContentProviderExternal(name, userId, token)).provider;\n            }\n        } catch (NullPointerException e) {\n            return null;\n        }\n    }\n\n    @NonNull\n    public static List<ActivityManager.RunningServiceInfo> getRunningServices(String packageName, @UserIdInt int userId) {\n        List<ActivityManager.RunningServiceInfo> runningServices;\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N_MR1\n                && !SelfPermissions.checkSelfOrRemotePermission(ManifestCompat.permission.REAL_GET_TASKS)\n                && canDumpRunningServices()) {\n            // Fetch running services by parsing dumpsys output\n            runningServices = getRunningServicesUsingDumpSys(packageName);\n        } else {\n            // For no-root, this returns services running in the current UID since Android Oreo\n            try {\n                runningServices = getActivityManager().getServices(100, 0);\n            } catch (RemoteException e) {\n                return Collections.emptyList();\n            }\n        }\n        List<ActivityManager.RunningServiceInfo> res = new ArrayList<>();\n        for (ActivityManager.RunningServiceInfo info : runningServices) {\n            if (info.service.getPackageName().equals(packageName) && userId == UserHandleHidden.getUserId(info.uid)) {\n                res.add(info);\n            }\n        }\n        return res;\n    }\n\n    @NonNull\n    public static List<ActivityManager.RunningAppProcessInfo> getRunningAppProcesses() {\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M\n                && !SelfPermissions.checkSelfOrRemotePermission(ManifestCompat.permission.REAL_GET_TASKS)\n                && canDumpRunningServices()) {\n            // Fetch running app processes by parsing dumpsys output if root/ADB is disabled\n            // and android.permission.DUMP is granted\n            return getRunningAppProcessesUsingDumpSys();\n        } else {\n            // For no-root, this returns app processes running in the current UID since Android M\n            return ExUtils.requireNonNullElse(() -> getActivityManager().getRunningAppProcesses(), Collections.emptyList());\n        }\n    }\n\n    @RequiresPermission(\"android.permission.KILL_UID\")\n    public static void killUid(int uid, String reason) throws RemoteException {\n        getActivityManager().killUid(UserHandleHidden.getAppId(uid), UserHandleHidden.getUserId(uid), reason);\n    }\n\n    @SuppressWarnings(\"deprecation\")\n    public static IActivityManager getActivityManager() {\n        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {\n            return IActivityManager.Stub.asInterface(ProxyBinder.getService(Context.ACTIVITY_SERVICE));\n        } else {\n            return ActivityManagerNative.asInterface(ProxyBinder.getService(Context.ACTIVITY_SERVICE));\n        }\n    }\n\n    public static IActivityManager getActivityManagerUnprivileged() {\n        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {\n            return IActivityManager.Stub.asInterface(ProxyBinder.getUnprivilegedService(Context.ACTIVITY_SERVICE));\n        } else {\n            return ActivityManagerNative.asInterface(ProxyBinder.getUnprivilegedService(Context.ACTIVITY_SERVICE));\n        }\n    }\n\n    @SuppressWarnings(\"RegExpRedundantEscape\")\n    private static final Pattern APP_PROCESS_REGEX = Pattern.compile(\"\\\\*[A-Z]+\\\\* UID (\\\\d+) ProcessRecord\\\\{[0-9a-f]+ (\\\\d+):([^/]+)/[^\\\\}]+\\\\}\");\n    @SuppressWarnings(\"RegExpRedundantEscape\")\n    private static final Pattern PKG_LIST_REGEX = Pattern.compile(\"packageList=\\\\{([^/]+)\\\\}\");\n\n    @NonNull\n    private static List<ActivityManager.RunningAppProcessInfo> getRunningAppProcessesUsingDumpSys() {\n        List<ActivityManager.RunningAppProcessInfo> runningAppProcessInfos = new ArrayList<>();\n        Runner.Result result = Runner.runCommand(new String[]{\"dumpsys\", \"activity\", \"processes\"});\n        if (!result.isSuccessful()) return runningAppProcessInfos;\n        List<String> appProcessDump = result.getOutputAsList(1);\n        return parseRunningAppProcesses(appProcessDump);\n    }\n\n    @VisibleForTesting\n    @NonNull\n    static List<ActivityManager.RunningAppProcessInfo> parseRunningAppProcesses(@NonNull List<String> appProcessesDump) {\n        List<ActivityManager.RunningAppProcessInfo> runningAppProcessInfos = new ArrayList<>();\n        Matcher aprMatcher;\n        Matcher pkgrMatcher;\n        String line;\n        ListIterator<String> it = appProcessesDump.listIterator();\n        if (!it.hasNext()) return runningAppProcessInfos;\n        aprMatcher = APP_PROCESS_REGEX.matcher(it.next());\n        while (it.hasNext()) {\n            if (!aprMatcher.find(0)) {\n                // No matches found, check the next line\n                aprMatcher = APP_PROCESS_REGEX.matcher(it.next());\n                continue;\n            }\n            // Matches found\n            String uid = aprMatcher.group(1);\n            String pid = aprMatcher.group(2);\n            String processName = aprMatcher.group(3);\n            if (uid == null || pid == null || processName == null) {\n                // Criteria didn't match\n                aprMatcher = APP_PROCESS_REGEX.matcher(it.next());\n                continue;\n            }\n            line = it.next();\n            aprMatcher = APP_PROCESS_REGEX.matcher(line);\n            while (it.hasNext()) {\n                if (aprMatcher.find(0)) {\n                    // found next ProcessRecord, no need to continue the search for pkgList\n                    break;\n                }\n                pkgrMatcher = PKG_LIST_REGEX.matcher(line);\n                if (!pkgrMatcher.find(0)) {\n                    // Process didn't match, find next line\n                    line = it.next();\n                    aprMatcher = APP_PROCESS_REGEX.matcher(line);\n                    continue;\n                }\n                // Found a pkgList\n                String pkgList = pkgrMatcher.group(1);\n                if (pkgList != null) {\n                    ActivityManager.RunningAppProcessInfo info = new ActivityManager.RunningAppProcessInfo();\n                    info.uid = Integer.decode(uid);\n                    info.pid = Integer.decode(pid);\n                    info.processName = processName;\n                    String[] split = pkgList.split(\", \");\n                    info.pkgList = new String[split.length];\n                    System.arraycopy(split, 0, info.pkgList, 0, split.length);\n                    runningAppProcessInfos.add(info);\n                }\n                line = it.next();\n                aprMatcher = APP_PROCESS_REGEX.matcher(line);\n            }\n        }\n        return runningAppProcessInfos;\n    }\n\n    @SuppressWarnings(\"RegExpRedundantEscape\")\n    private static final Pattern SERVICE_RECORD_REGEX = Pattern.compile(\"\\\\* ServiceRecord\\\\{[0-9a-f]+ u(\\\\d+) ([^\\\\}]+)\\\\}\");\n    @SuppressWarnings(\"RegExpRedundantEscape\")\n    private static final Pattern PROCESS_RECORD_REGEX = Pattern.compile(\"app=ProcessRecord\\\\{[0-9a-f]+ (\\\\d+):([^/]+)/([^\\\\}]+)\\\\}\");\n\n    @NonNull\n    private static List<ActivityManager.RunningServiceInfo> getRunningServicesUsingDumpSys(String packageName) {\n        List<ActivityManager.RunningServiceInfo> runningServices = new ArrayList<>();\n        Runner.Result result = Runner.runCommand(new String[]{\"dumpsys\", \"activity\", \"services\", \"-p\", packageName});\n        if (!result.isSuccessful()) return runningServices;\n        List<String> serviceDump = result.getOutputAsList(1);\n        return parseRunningServices(serviceDump);\n    }\n\n    @VisibleForTesting\n    @NonNull\n    static List<ActivityManager.RunningServiceInfo> parseRunningServices(@NonNull List<String> serviceDump) {\n        List<ActivityManager.RunningServiceInfo> runningServices = new ArrayList<>();\n        Matcher srMatcher;\n        Matcher prMatcher;\n        ComponentName service;\n        String line;\n        ListIterator<String> it = serviceDump.listIterator();\n        if (!it.hasNext()) return runningServices;\n        srMatcher = SERVICE_RECORD_REGEX.matcher(it.next());\n        while (it.hasNext()) { // hasNext check doesn't omit anything since we'd still have to check for ProcessRecord\n            if (!srMatcher.find(0)) {\n                // No matches found, check the next line\n                srMatcher = SERVICE_RECORD_REGEX.matcher(it.next());\n                continue;\n            }\n            // Matches found\n            String userId = srMatcher.group(1);\n            String serviceName = srMatcher.group(2);\n            if (userId == null || serviceName == null) {\n                // Criteria didn't match\n                srMatcher = SERVICE_RECORD_REGEX.matcher(it.next());\n                continue;\n            }\n            // This is actually the short process name, original service name is under intent (in the next line)\n            int i = serviceName.indexOf(':');\n            service = ComponentName.unflattenFromString(i == -1 ? serviceName : serviceName.substring(0, i));\n            line = it.next();\n            srMatcher = SERVICE_RECORD_REGEX.matcher(line);\n            while (it.hasNext()) {\n                if (srMatcher.find(0)) {\n                    // found next ServiceRecord, no need to continue the search for ProcessRecord\n                    break;\n                }\n                prMatcher = PROCESS_RECORD_REGEX.matcher(line);\n                if (!prMatcher.find(0)) {\n                    // Process didn't match, find next line\n                    line = it.next();\n                    srMatcher = SERVICE_RECORD_REGEX.matcher(line);\n                    continue;\n                }\n                // Found a ProcessRecord\n                String pid = prMatcher.group(1);\n                String processName = prMatcher.group(2);\n                String userInfo = prMatcher.group(3);\n                if (pid != null && processName != null && userInfo != null) {\n                    ActivityManager.RunningServiceInfo info = new ActivityManager.RunningServiceInfo();\n                    info.pid = Integer.decode(pid);\n                    info.process = processName;\n                    info.service = service;\n                    // UID\n                    if (TextUtils.isDigitsOnly(userInfo)) {  // UID < 10000\n                        info.uid = Integer.decode(userInfo);\n                    } else if (userInfo.startsWith(\"u\")) {  // u<USER_ID>(a|s)<APP_ID>[i<ISOLATION_ID>]\n                        userInfo = userInfo.substring((\"u\" + userId).length()); // u<USER_ID> removed\n                        int iIdx = userInfo.indexOf('i');\n                        int iIndex = iIdx == -1 ? userInfo.length() : iIdx;\n                        if (userInfo.startsWith(\"a\")) {\n                            // User app\n                            info.uid = UserHandleHidden.getUid(Integer.decode(userId), 10_000 + Integer.decode(userInfo.substring(1, iIndex)));\n                        } else if (userInfo.startsWith(\"s\")) {\n                            // System app\n                            info.uid = UserHandleHidden.getUid(Integer.decode(userId), Integer.decode(userInfo.substring(1, iIndex)));\n                        } else throw new IllegalStateException(\"No valid UID info found in ProcessRecord\");\n                    } else throw new IllegalStateException(\"Invalid user info section in ProcessRecord\");\n                    // TODO: 1/9/21 Parse others\n                    runningServices.add(info);\n                }\n                line = it.next();\n                srMatcher = SERVICE_RECORD_REGEX.matcher(line);\n            }\n        }\n        return runningServices;\n    }\n\n    @RequiresApi(Build.VERSION_CODES.M)\n    private static boolean canDumpRunningServices() {\n        return SelfPermissions.checkSelfPermission(Manifest.permission.DUMP)\n                && SelfPermissions.checkSelfPermission(Manifest.permission.PACKAGE_USAGE_STATS);\n    }\n\n    final static class IntentReceiver extends IIntentReceiver.Stub {\n        private boolean mFinished = false;\n\n        public void performReceive(Intent intent, int resultCode, String data, Bundle extras,\n                                   boolean ordered, boolean sticky, int sendingUser) {\n            String line = \"Broadcast completed: result=\" + resultCode;\n            if (data != null) line = line + \", data=\\\"\" + data + \"\\\"\";\n            if (extras != null) line = line + \", extras: \" + extras;\n            Log.e(\"AM\", line);\n            synchronized (this) {\n                mFinished = true;\n                notifyAll();\n            }\n        }\n\n        public synchronized void waitForFinish() {\n            try {\n                while (!mFinished) wait();\n            } catch (InterruptedException e) {\n                throw new IllegalStateException(e);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/compat/AppOpsManagerCompat.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.compat;\n\nimport android.annotation.SuppressLint;\nimport android.annotation.UserIdInt;\nimport android.app.AppOpsManager;\nimport android.app.AppOpsManagerHidden;\nimport android.content.Context;\nimport android.os.Build;\nimport android.os.Parcel;\nimport android.os.Parcelable;\nimport android.os.RemoteException;\n\nimport androidx.annotation.IntRange;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.RequiresApi;\nimport androidx.annotation.RequiresPermission;\nimport androidx.collection.SparseArrayCompat;\nimport androidx.core.os.ParcelCompat;\n\nimport com.android.internal.app.IAppOpsService;\n\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.reflect.Field;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Locale;\n\nimport aosp.libcore.util.EmptyArray;\nimport dev.rikka.tools.refine.Refine;\nimport io.github.muntashirakon.AppManager.ipc.ProxyBinder;\nimport io.github.muntashirakon.AppManager.logs.Log;\nimport io.github.muntashirakon.AppManager.utils.ExUtils;\nimport io.github.muntashirakon.AppManager.utils.MiuiUtils;\n\n@SuppressLint(\"SoonBlockedPrivateApi\")\npublic class AppOpsManagerCompat {\n    @IntRange(from = -1, to = 5)\n    @Retention(RetentionPolicy.SOURCE)\n    public @interface Mode {\n    }\n\n    public static final int OP_FLAG_SELF;\n    public static final int OP_FLAG_TRUSTED_PROXY;\n    public static final int OP_FLAG_UNTRUSTED_PROXY;\n    public static final int OP_FLAG_TRUSTED_PROXIED;\n    public static final int OP_FLAG_UNTRUSTED_PROXIED;\n    public static final int OP_FLAGS_ALL;\n    public static final int OP_FLAGS_ALL_TRUSTED;\n\n    static {\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {\n            OP_FLAG_SELF = AppOpsManagerHidden.OP_FLAG_SELF;\n            OP_FLAG_TRUSTED_PROXY = AppOpsManagerHidden.OP_FLAG_TRUSTED_PROXY;\n            OP_FLAG_UNTRUSTED_PROXY = AppOpsManagerHidden.OP_FLAG_UNTRUSTED_PROXY;\n            OP_FLAG_TRUSTED_PROXIED = AppOpsManagerHidden.OP_FLAG_TRUSTED_PROXIED;\n            OP_FLAG_UNTRUSTED_PROXIED = AppOpsManagerHidden.OP_FLAG_UNTRUSTED_PROXIED;\n            OP_FLAGS_ALL = AppOpsManagerHidden.OP_FLAGS_ALL;\n            OP_FLAGS_ALL_TRUSTED = AppOpsManagerHidden.OP_FLAGS_ALL_TRUSTED;\n        } else {\n            OP_FLAG_SELF = 0;\n            OP_FLAG_TRUSTED_PROXY = 0;\n            OP_FLAG_UNTRUSTED_PROXY = 0;\n            OP_FLAG_TRUSTED_PROXIED = 0;\n            OP_FLAG_UNTRUSTED_PROXIED = 0;\n            OP_FLAGS_ALL = 0;\n            OP_FLAGS_ALL_TRUSTED = 0;\n        }\n    }\n\n    @Retention(RetentionPolicy.SOURCE)\n    public @interface OpFlags {\n    }\n\n    public static final int UID_STATE_PERSISTENT;\n    public static final int UID_STATE_TOP;\n    public static final int UID_STATE_FOREGROUND_SERVICE_LOCATION;\n    public static final int UID_STATE_FOREGROUND_SERVICE;\n    public static final int UID_STATE_FOREGROUND;\n    public static final int UID_STATE_BACKGROUND;\n    public static final int UID_STATE_CACHED;\n\n    public static final int MAX_PRIORITY_UID_STATE;\n    public static final int MIN_PRIORITY_UID_STATE;\n\n    static {\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {\n            UID_STATE_PERSISTENT = AppOpsManagerHidden.UID_STATE_PERSISTENT;\n            UID_STATE_TOP = AppOpsManagerHidden.UID_STATE_TOP;\n            UID_STATE_FOREGROUND_SERVICE = AppOpsManagerHidden.UID_STATE_FOREGROUND_SERVICE;\n            UID_STATE_FOREGROUND = AppOpsManagerHidden.UID_STATE_FOREGROUND;\n            UID_STATE_BACKGROUND = AppOpsManagerHidden.UID_STATE_BACKGROUND;\n            UID_STATE_CACHED = AppOpsManagerHidden.UID_STATE_CACHED;\n        } else {\n            UID_STATE_PERSISTENT = 0;\n            UID_STATE_TOP = 0;\n            UID_STATE_FOREGROUND_SERVICE = 0;\n            UID_STATE_FOREGROUND = 0;\n            UID_STATE_BACKGROUND = 0;\n            UID_STATE_CACHED = 0;\n        }\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {\n            UID_STATE_FOREGROUND_SERVICE_LOCATION = AppOpsManagerHidden.UID_STATE_FOREGROUND_SERVICE_LOCATION;\n            MAX_PRIORITY_UID_STATE = AppOpsManagerHidden.MAX_PRIORITY_UID_STATE;\n            MIN_PRIORITY_UID_STATE = AppOpsManagerHidden.MIN_PRIORITY_UID_STATE;\n        } else if (Build.VERSION.SDK_INT == Build.VERSION_CODES.P) {\n            UID_STATE_FOREGROUND_SERVICE_LOCATION = 0;\n            MAX_PRIORITY_UID_STATE = UID_STATE_PERSISTENT;\n            MIN_PRIORITY_UID_STATE = UID_STATE_CACHED;\n        } else {\n            UID_STATE_FOREGROUND_SERVICE_LOCATION = 0;\n            MAX_PRIORITY_UID_STATE = 0;\n            MIN_PRIORITY_UID_STATE = 0;\n        }\n    }\n\n    @Retention(RetentionPolicy.SOURCE)\n    public @interface UidState {\n    }\n\n    private static final SparseArrayCompat<String> sModes = new SparseArrayCompat<>();\n    private static final String[] sOpToString;\n\n    public static final int OP_NONE = AppOpsManagerHidden.OP_NONE;\n    /**\n     * Control whether an application is allowed to run in the background.\n     */\n    @RequiresApi(Build.VERSION_CODES.N)\n    public static final int OP_RUN_IN_BACKGROUND;\n    /**\n     * Run jobs when in background\n     */\n    @RequiresApi(Build.VERSION_CODES.P)\n    public static final int OP_RUN_ANY_IN_BACKGROUND;\n    public static final int _NUM_OP = AppOpsManagerHidden._NUM_OP;\n\n    static {\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {\n            OP_RUN_IN_BACKGROUND = AppOpsManagerHidden.OP_RUN_IN_BACKGROUND;\n        } else {\n            //noinspection NewApi\n            OP_RUN_IN_BACKGROUND = 0;\n        }\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {\n            OP_RUN_ANY_IN_BACKGROUND = AppOpsManagerHidden.OP_RUN_ANY_IN_BACKGROUND;\n        } else {\n            //noinspection NewApi\n            OP_RUN_ANY_IN_BACKGROUND = 0;\n        }\n    }\n\n    /**\n     * Mapping from a permission to the corresponding app op.\n     */\n    private static final HashMap<String, Integer> sPermToOp = new HashMap<>();\n    /**\n     * Some ops don't have any permissions associated with them and are enabled by default.\n     * We are interested in the parents of these ops.\n     */\n    public static List<Integer> sOpWithoutPerms;\n\n    static {\n        String[] opToString = EmptyArray.STRING;\n        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {\n            // Only needed for API 22 and earlier\n            try {\n                Field sOpToStringField = AppOpsManagerHidden.class.getDeclaredField(\"sOpToString\");\n                sOpToStringField.setAccessible(true);\n                opToString = (String[]) sOpToStringField.get(null);\n            } catch (NoSuchFieldException | IllegalAccessException e) {\n                e.printStackTrace();\n            }\n        }\n        sOpToString = opToString;\n\n        for (Field field : AppOpsManager.class.getDeclaredFields()) {\n            field.setAccessible(true);\n            if (field.getType() == int.class && field.getName().startsWith(\"MODE_\")) {\n                try {\n                    sModes.put(field.getInt(null), field.getName());\n                } catch (IllegalAccessException ignore) {\n                }\n            }\n        }\n\n        HashSet<Integer> opWithoutPerms = new HashSet<>();\n        for (int i = 0; i < _NUM_OP; i++) {\n            String permission = AppOpsManagerHidden.opToPermission(i);\n            if (permission != null) {\n                if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {\n                    // Only needed for API 22 and earlier\n                    sPermToOp.put(permission, i);\n                }\n            } else {\n                // No permission\n                opWithoutPerms.add(AppOpsManagerHidden.opToSwitch(i));\n            }\n        }\n        sOpWithoutPerms = new ArrayList<>(opWithoutPerms);\n    }\n\n    public static boolean isMiuiOp(int op) {\n        try {\n            return MiuiUtils.isMiui() && op > AppOpsManagerHidden.MIUI_OP_START;\n        } catch (Throwable e) {\n            return false;\n        }\n    }\n\n    @NonNull\n    public static List<Integer> getAllOps() {\n        List<Integer> appOps = new ArrayList<>();\n        for (int i = 0; i < _NUM_OP; ++i) {\n            appOps.add(i);\n        }\n        if (MiuiUtils.isMiui()) {\n            try {\n                for (int op = AppOpsManagerHidden.MIUI_OP_START + 1; op < AppOpsManagerHidden.MIUI_OP_END; ++op) {\n                    appOps.add(op);\n                }\n            } catch (Exception ignore) {\n            }\n        }\n        return appOps;\n    }\n\n    @NonNull\n    public static List<Integer> getOpsWithoutPermissions() {\n        return sOpWithoutPerms;\n    }\n\n    @NonNull\n    public static List<Integer> getModeConstants() {\n        return new ArrayList<Integer>(sModes.size()) {{\n            for (int i = 0; i < sModes.size(); ++i) {\n                add(sModes.keyAt(i));\n            }\n        }};\n    }\n\n    @NonNull\n    public static String modeToName(@IntRange(from = -1) int mode) {\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {\n            return AppOpsManagerHidden.modeToName(mode);\n        }\n        // Fallback for pre28\n        String fieldName = sModes.get(mode);\n        if (fieldName == null) {\n            return \"mode=\" + mode;\n        }\n        switch (mode) {\n            case AppOpsManager.MODE_ALLOWED:\n                return \"allow\";\n            case AppOpsManager.MODE_IGNORED:\n                return \"ignore\";\n            case AppOpsManager.MODE_ERRORED:\n                return \"deny\";\n            // Rests have the same name as the constant name in lower case minus the MODE_ prefix\n        }\n        return fieldName.substring(5).toLowerCase(Locale.ROOT);\n    }\n\n    /**\n     * Retrieve the op switch that controls the given operation.\n     */\n    public static int opToSwitch(int op) {\n        return AppOpsManagerHidden.opToSwitch(op);\n    }\n\n    @NonNull\n    public static String opToName(int op) {\n        return AppOpsManagerHidden.opToName(op);\n    }\n\n    /**\n     * Retrieve the permission associated with an operation, or null if there is not one.\n     */\n    @Nullable\n    public static String opToPermission(int op) {\n        return AppOpsManagerHidden.opToPermission(op);\n    }\n\n    /**\n     * Retrieve the default mode for the operation.\n     */\n    public static int opToDefaultMode(int op) {\n        try {\n            return AppOpsManagerHidden.opToDefaultMode(op);\n        } catch (NoSuchMethodError e) {\n            return AppOpsManagerHidden.opToDefaultMode(op, false);\n        }\n    }\n\n    /**\n     * Retrieve the app op code for a permission, or {@link #OP_NONE} if there is not one.\n     * This API is intended to be used for mapping runtime or appop permissions\n     * to the corresponding app op.\n     */\n    public static int permissionToOpCode(String permission) {\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {\n            return AppOpsManagerHidden.permissionToOpCode(permission);\n        }\n        // Fallback for Lollipop\n        Integer boxedOpCode = sPermToOp.get(permission);\n        if (boxedOpCode == null || boxedOpCode >= _NUM_OP) {\n            return OP_NONE;\n        }\n        return boxedOpCode;\n    }\n\n    /**\n     * Gets the app op name associated with a given permission.\n     * The app op name is one of the public constants defined\n     * in this class such as {@code #OPSTR_COARSE_LOCATION}.\n     * This API is intended to be used for mapping runtime\n     * permissions to the corresponding app op.\n     *\n     * @param permission The permission.\n     * @return The app op associated with the permission or null.\n     */\n    @Nullable\n    public static String permissionToOp(String permission) {\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {\n            return AppOpsManagerHidden.permissionToOp(permission);\n        }\n        // Fallback for Lollipop\n        final int opCode = permissionToOpCode(permission);\n        if (opCode == OP_NONE) {\n            return null;\n        }\n        return sOpToString[opCode];\n    }\n\n    public static class PackageOps implements Parcelable {\n        private final String mPackageName;\n        private final int mUid;\n        private final List<OpEntry> mEntries;\n\n        public PackageOps(String packageName, int uid, List<OpEntry> entries) {\n            mPackageName = packageName;\n            mUid = uid;\n            mEntries = entries;\n        }\n\n        public String getPackageName() {\n            return mPackageName;\n        }\n\n        public int getUid() {\n            return mUid;\n        }\n\n        public List<OpEntry> getOps() {\n            return mEntries;\n        }\n\n        @NonNull\n        @Override\n        public String toString() {\n            return \"PackageOps{\" +\n                    \"mPackageName='\" + mPackageName + '\\'' +\n                    \", mUid=\" + mUid +\n                    \", mEntries=\" + mEntries +\n                    '}';\n        }\n\n        @Override\n        public int describeContents() {\n            return 0;\n        }\n\n        @Override\n        public void writeToParcel(@NonNull Parcel dest, int flags) {\n            dest.writeString(mPackageName);\n            dest.writeInt(mUid);\n            dest.writeTypedList(mEntries);\n        }\n\n        protected PackageOps(@NonNull Parcel in) {\n            mPackageName = in.readString();\n            mUid = in.readInt();\n            mEntries = new ArrayList<>();\n            in.readTypedList(mEntries, OpEntry.CREATOR);\n        }\n\n        public static final Parcelable.Creator<PackageOps> CREATOR = new Parcelable.Creator<PackageOps>() {\n            @NonNull\n            @Override\n            public PackageOps createFromParcel(Parcel source) {\n                return new PackageOps(source);\n            }\n\n            @NonNull\n            @Override\n            public PackageOps[] newArray(int size) {\n                return new PackageOps[size];\n            }\n        };\n    }\n\n    public static class OpEntry implements Parcelable {\n        private final AppOpsManagerHidden.OpEntry mOpEntry;\n\n        public OpEntry(Parcelable opEntry) {\n            mOpEntry = Refine.unsafeCast(opEntry);\n        }\n\n        protected OpEntry(Parcel in) {\n            mOpEntry = ParcelCompat.readParcelable(in,\n                    AppOpsManagerHidden.OpEntry.class.getClassLoader(),\n                    AppOpsManagerHidden.OpEntry.class);\n        }\n\n        public static final Creator<OpEntry> CREATOR = new Creator<OpEntry>() {\n            @NonNull\n            @Override\n            public OpEntry createFromParcel(Parcel in) {\n                return new OpEntry(in);\n            }\n\n            @NonNull\n            @Override\n            public OpEntry[] newArray(int size) {\n                return new OpEntry[size];\n            }\n        };\n\n        public int getOp() {\n            return mOpEntry.getOp();\n        }\n\n        @NonNull\n        public String getName() {\n            return opToName(getOp());\n        }\n\n        @Nullable\n        public String getPermission() {\n            return opToPermission(getOp());\n        }\n\n        @Mode\n        public int getMode() {\n            return mOpEntry.getMode();\n        }\n\n        @Mode\n        public int getDefaultMode() {\n            return opToDefaultMode(getOp());\n        }\n\n        public long getTime() {\n            return getLastAccessTime(OP_FLAGS_ALL);\n        }\n\n        public long getLastAccessTime(@OpFlags int flags) {\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {\n                return mOpEntry.getLastAccessTime(flags);\n            } else if (Build.VERSION.SDK_INT == Build.VERSION_CODES.P) {\n                return mOpEntry.getLastAccessTime();\n            }\n            return mOpEntry.getTime();\n        }\n\n        public long getLastAccessForegroundTime(@OpFlags int flags) {\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {\n                return mOpEntry.getLastAccessForegroundTime(flags);\n            } else if (Build.VERSION.SDK_INT == Build.VERSION_CODES.P) {\n                return mOpEntry.getLastAccessForegroundTime();\n            } else return mOpEntry.getTime();\n        }\n\n        public long getLastAccessBackgroundTime(@OpFlags int flags) {\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {\n                return mOpEntry.getLastAccessBackgroundTime(flags);\n            } else if (Build.VERSION.SDK_INT == Build.VERSION_CODES.P) {\n                return mOpEntry.getLastAccessBackgroundTime();\n            } else return mOpEntry.getTime();\n        }\n\n        public long getLastAccessTime(@UidState int fromUidState,\n                                      @UidState int toUidState,\n                                      @OpFlags int flags) {\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {\n                return mOpEntry.getLastAccessTime(fromUidState, toUidState, flags);\n            } else if (Build.VERSION.SDK_INT == Build.VERSION_CODES.P) {\n                return mOpEntry.getLastTimeFor(fromUidState);\n            } else return mOpEntry.getTime();\n        }\n\n        public long getRejectTime() {\n            return getLastRejectTime(OP_FLAGS_ALL);\n        }\n\n        public long getLastRejectTime(@OpFlags int flags) {\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {\n                return mOpEntry.getLastRejectTime(flags);\n            } else if (Build.VERSION.SDK_INT == Build.VERSION_CODES.P) {\n                return mOpEntry.getLastRejectTime();\n            } else return mOpEntry.getRejectTime();\n        }\n\n        public long getLastRejectForegroundTime(@OpFlags int flags) {\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {\n                return mOpEntry.getLastRejectForegroundTime(flags);\n            } else if (Build.VERSION.SDK_INT == Build.VERSION_CODES.P) {\n                return mOpEntry.getLastRejectForegroundTime();\n            } else return mOpEntry.getRejectTime();\n        }\n\n        public long getLastRejectBackgroundTime(@OpFlags int flags) {\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {\n                return mOpEntry.getLastRejectBackgroundTime(flags);\n            } else if (Build.VERSION.SDK_INT == Build.VERSION_CODES.P) {\n                return mOpEntry.getLastRejectBackgroundTime();\n            } else return mOpEntry.getRejectTime();\n        }\n\n        public long getLastRejectTime(@UidState int fromUidState,\n                                      @UidState int toUidState,\n                                      @OpFlags int flags) {\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {\n                return mOpEntry.getLastRejectTime(fromUidState, toUidState, flags);\n            } else if (Build.VERSION.SDK_INT == Build.VERSION_CODES.P) {\n                return mOpEntry.getLastRejectTimeFor(fromUidState);\n            } else return mOpEntry.getRejectTime();\n        }\n\n        public boolean isRunning() {\n            return mOpEntry.isRunning();\n        }\n\n        public long getDuration() {\n            return getLastDuration(MAX_PRIORITY_UID_STATE, MIN_PRIORITY_UID_STATE, OP_FLAGS_ALL);\n        }\n\n        @RequiresApi(Build.VERSION_CODES.R)\n        public long getLastDuration(@OpFlags int flags) {\n            return mOpEntry.getLastDuration(flags);\n        }\n\n        public long getLastForegroundDuration(@OpFlags int flags) {\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {\n                return mOpEntry.getLastForegroundDuration(flags);\n            } else return mOpEntry.getDuration();\n        }\n\n        public long getLastBackgroundDuration(@OpFlags int flags) {\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {\n                return mOpEntry.getLastBackgroundDuration(flags);\n            } else return mOpEntry.getDuration();\n        }\n\n        public long getLastDuration(@UidState int fromUidState,\n                                    @UidState int toUidState,\n                                    @OpFlags int flags) {\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {\n                return mOpEntry.getLastDuration(fromUidState, toUidState, flags);\n            } else return mOpEntry.getDuration();\n        }\n\n        // Deprecated in R\n        @Deprecated\n        @RequiresApi(Build.VERSION_CODES.M)\n        public int getProxyUid() {\n            return mOpEntry.getProxyUid();\n        }\n\n        // Deprecated in R\n        @Deprecated\n        public int getProxyUid(@UidState int uidState, @OpFlags int flags) {\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {\n                return mOpEntry.getProxyUid(uidState, flags);\n            } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {\n                return mOpEntry.getProxyUid();\n            }\n            return 0;\n        }\n\n        @Deprecated\n        @RequiresApi(Build.VERSION_CODES.M)\n        @Nullable\n        public String getProxyPackageName() {\n            return mOpEntry.getProxyPackageName();\n        }\n\n        // Deprecated in R\n        @Deprecated\n        @Nullable\n        public String getProxyPackageName(@UidState int uidState, @OpFlags int flags) {\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {\n                return mOpEntry.getProxyPackageName(uidState, flags);\n            } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {\n                return mOpEntry.getProxyPackageName();\n            }\n            return null;\n        }\n\n        // TODO(24/12/20): Get proxy info (From API 30)\n\n\n        @Override\n        public int describeContents() {\n            return 0;\n        }\n\n        @Override\n        public void writeToParcel(@NonNull Parcel dest, int flags) {\n            dest.writeParcelable(mOpEntry, flags);\n        }\n    }\n\n    public static int getModeFromOpEntriesOrDefault(int op, @Nullable List<OpEntry> opEntries) {\n        if (op <= OP_NONE || op >= _NUM_OP || opEntries == null) {\n            return AppOpsManager.MODE_IGNORED;\n        }\n        for (OpEntry opEntry : opEntries) {\n            if (opEntry.getOp() == op) {\n                return opEntry.getMode();\n            }\n        }\n        return opToDefaultMode(op);\n    }\n\n    @NonNull\n    public static List<OpEntry> getConfiguredOpsForPackage(@NonNull AppOpsManagerCompat appOpsManager,\n                                                           @NonNull String packageName, int uid)\n            throws RemoteException {\n        List<PackageOps> packageOpsList = appOpsManager.getOpsForPackage(uid, packageName, null);\n        if (packageOpsList.size() == 1) {\n            return packageOpsList.get(0).getOps();\n        }\n        return Collections.emptyList();\n    }\n\n    private final IAppOpsService mAppOpsService;\n\n    public AppOpsManagerCompat() {\n        mAppOpsService = IAppOpsService.Stub.asInterface(ProxyBinder.getService(Context.APP_OPS_SERVICE));\n    }\n\n    /**\n     * Get the mode of operation of the given package or uid. This denotes the actual working state which is not\n     * necessarily the same mode set using {@link #setMode(int, int, String, int)}.\n     *\n     * @param op          One of the OP_*\n     * @param uid         User ID for the package(s)\n     * @param packageName Name of the package\n     * @return One of the MODE_*\n     */\n    @AppOpsManagerCompat.Mode\n    public int checkOperation(int op, int uid, String packageName) throws RemoteException {\n        return mAppOpsService.checkOperation(op, uid, packageName);\n    }\n\n    /**\n     * Same as {@link AppOpsManager#checkOpNoThrow(String, int, String)}. To be used with App Manager itself.\n     */\n    @AppOpsManagerCompat.Mode\n    public int checkOpNoThrow(int op, int uid, String packageName) {\n        try {\n            int mode = mAppOpsService.checkOperation(op, uid, packageName);\n            return mode == AppOpsManager.MODE_FOREGROUND ? AppOpsManager.MODE_ALLOWED : mode;\n        } catch (RemoteException e) {\n            return ExUtils.rethrowFromSystemServer(e);\n        }\n    }\n\n    @RequiresPermission(ManifestCompat.permission.GET_APP_OPS_STATS)\n    public List<AppOpsManagerCompat.PackageOps> getOpsForPackage(int uid, String packageName, @Nullable int[] ops)\n            throws RemoteException {\n        // Check using uid mode and package mode, override ops in package mode from uid mode\n        List<AppOpsManagerCompat.OpEntry> opEntries = new ArrayList<>();\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {\n            try {\n                addAllRelevantOpEntriesWithNoOverride(opEntries, mAppOpsService.getUidOps(uid, ops));\n            } catch (NullPointerException e) {\n                Log.e(\"AppOpsManagerCompat\", \"Could not get app ops for UID %d\", e, uid);\n            }\n        }\n        addAllRelevantOpEntriesWithNoOverride(opEntries, mAppOpsService.getOpsForPackage(uid, packageName, ops));\n        return Collections.singletonList(new AppOpsManagerCompat.PackageOps(packageName, uid, opEntries));\n    }\n\n    @RequiresPermission(ManifestCompat.permission.GET_APP_OPS_STATS)\n    @NonNull\n    public List<AppOpsManagerCompat.PackageOps> getPackagesForOps(int[] ops) throws RemoteException {\n        List<Parcelable> opsForPackage = mAppOpsService.getPackagesForOps(ops);\n        List<AppOpsManagerCompat.PackageOps> packageOpsList = new ArrayList<>();\n        if (opsForPackage != null) {\n            for (Parcelable o : opsForPackage) {\n                AppOpsManagerCompat.PackageOps packageOps = opsConvert(Refine.unsafeCast(o));\n                packageOpsList.add(packageOps);\n            }\n        }\n        return packageOpsList;\n    }\n\n    @RequiresPermission(\"android.permission.MANAGE_APP_OPS_MODES\")\n    public void setMode(int op, int uid, String packageName, @AppOpsManagerCompat.Mode int mode)\n            throws RemoteException {\n        if (AppOpsManagerCompat.isMiuiOp(op) || Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {\n            // Only package mode works in MIUI-only app ops and before Android M\n            mAppOpsService.setMode(op, uid, packageName, mode);\n        } else {\n            // Set UID mode\n            mAppOpsService.setUidMode(op, uid, mode);\n        }\n    }\n\n    @RequiresPermission(\"android.permission.MANAGE_APP_OPS_MODES\")\n    public void resetAllModes(@UserIdInt int reqUserId, @NonNull String reqPackageName) throws RemoteException {\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) {\n            mAppOpsService.resetAllModes(reqUserId, reqPackageName);\n        }\n    }\n\n    private static void addAllRelevantOpEntriesWithNoOverride(final List<AppOpsManagerCompat.OpEntry> opEntries,\n                                                              @Nullable final List<Parcelable> opsForPackage) {\n        if (opsForPackage != null) {\n            for (Parcelable o : opsForPackage) {\n                AppOpsManagerCompat.PackageOps packageOps = opsConvert(Refine.unsafeCast(o));\n                for (AppOpsManagerCompat.OpEntry opEntry : packageOps.getOps()) {\n                    if (!opEntries.contains(opEntry)) {\n                        opEntries.add(opEntry);\n                    }\n                }\n            }\n        }\n    }\n\n    @NonNull\n    private static AppOpsManagerCompat.PackageOps opsConvert(@NonNull AppOpsManagerHidden.PackageOps packageOps) {\n        String packageName = packageOps.getPackageName();\n        int uid = packageOps.getUid();\n        List<AppOpsManagerCompat.OpEntry> opEntries = new ArrayList<>();\n        for (Parcelable opEntry : packageOps.getOps()) {\n            opEntries.add(new AppOpsManagerCompat.OpEntry(opEntry));\n        }\n        return new AppOpsManagerCompat.PackageOps(packageName, uid, opEntries);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/compat/ApplicationInfoCompat.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.compat;\n\nimport android.content.pm.ApplicationInfo;\nimport android.content.pm.ApplicationInfoHidden;\nimport android.content.pm.PackageManager;\nimport android.os.Build;\n\nimport androidx.annotation.IntDef;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\n\nimport dev.rikka.tools.refine.Refine;\nimport io.github.muntashirakon.io.Paths;\n\npublic final class ApplicationInfoCompat {\n    /**\n     * Value for {@code #privateFlags}: true if the application is hidden via restrictions and for\n     * most purposes is considered as not installed.\n     */\n    public static final int PRIVATE_FLAG_HIDDEN = 1;\n\n    /**\n     * Value for {@code #privateFlags}: set to <code>true</code> if the application\n     * has reported that it is heavy-weight, and thus can not participate in\n     * the normal application lifecycle.\n     *\n     * <p>Comes from the\n     * android.R.styleable#AndroidManifestApplication_cantSaveState\n     * attribute of the &lt;application&gt; tag.\n     */\n    public static final int PRIVATE_FLAG_CANT_SAVE_STATE = 1 << 1;\n\n    /**\n     * Value for {@code #privateFlags}: set to {@code true} if the application\n     * is permitted to hold privileged permissions.\n     */\n    public static final int PRIVATE_FLAG_PRIVILEGED = 1 << 3;\n\n    /**\n     * Value for {@code #privateFlags}: {@code true} if the application has any IntentFiler\n     * with some data URI using HTTP or HTTPS with an associated VIEW action.\n     */\n    public static final int PRIVATE_FLAG_HAS_DOMAIN_URLS = 1 << 4;\n\n    /**\n     * When set, the default data storage directory for this app is pointed at\n     * the device-protected location.\n     */\n    public static final int PRIVATE_FLAG_DEFAULT_TO_DEVICE_PROTECTED_STORAGE = 1 << 5;\n\n    /**\n     * When set, assume that all components under the given app are direct boot\n     * aware, unless otherwise specified.\n     */\n    public static final int PRIVATE_FLAG_DIRECT_BOOT_AWARE = 1 << 6;\n\n    /**\n     * Value for {@code #privateFlags}: {@code true} if the application is installed\n     * as instant app.\n     */\n    public static final int PRIVATE_FLAG_INSTANT = 1 << 7;\n\n    /**\n     * When set, at least one component inside this application is direct boot\n     * aware.\n     */\n    public static final int PRIVATE_FLAG_PARTIALLY_DIRECT_BOOT_AWARE = 1 << 8;\n\n\n    /**\n     * When set, signals that the application is required for the system user and should not be\n     * uninstalled.\n     */\n    public static final int PRIVATE_FLAG_REQUIRED_FOR_SYSTEM_USER = 1 << 9;\n\n    /**\n     * When set, the application explicitly requested that its activities be resizeable by default.\n     * {@code android.R.styleable#AndroidManifestActivity_resizeableActivity}\n     */\n    public static final int PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE = 1 << 10;\n\n    /**\n     * When set, the application explicitly requested that its activities *not* be resizeable by\n     * default.\n     * {@code android.R.styleable#AndroidManifestActivity_resizeableActivity}\n     */\n    public static final int PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_UNRESIZEABLE = 1 << 11;\n\n    /**\n     * The application isn't requesting explicitly requesting for its activities to be resizeable or\n     * non-resizeable by default. So, we are making it activities resizeable by default based on the\n     * target SDK version of the app.\n     * {@code android.R.styleable#AndroidManifestActivity_resizeableActivity}\n     * <p>\n     * NOTE: This only affects apps with target SDK >= N where the resizeableActivity attribute was\n     * introduced. It shouldn't be confused with {@code ActivityInfo#RESIZE_MODE_FORCE_RESIZEABLE}\n     * where certain pre-N apps are forced to the resizeable.\n     */\n    public static final int PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION = 1 << 12;\n\n    /**\n     * Value for {@code #privateFlags}: {@code true} means the OS should go ahead and\n     * run full-data backup operations for the app even when it is in a\n     * foreground-equivalent run state.  Defaults to {@code false} if unspecified.\n     */\n    public static final int PRIVATE_FLAG_BACKUP_IN_FOREGROUND = 1 << 13;\n\n    /**\n     * Value for {@code #privateFlags}: {@code true} means this application\n     * contains a static shared library. Defaults to {@code false} if unspecified.\n     */\n    public static final int PRIVATE_FLAG_STATIC_SHARED_LIBRARY = 1 << 14;\n\n    /**\n     * Value for {@code #privateFlags}: When set, the application will only have its splits loaded\n     * if they are required to load a component. Splits can be loaded on demand using the\n     * {@code Context#createContextForSplit(String)} API.\n     */\n    public static final int PRIVATE_FLAG_ISOLATED_SPLIT_LOADING = 1 << 15;\n\n    /**\n     * Value for {@code #privateFlags}: When set, the application was installed as\n     * a virtual preload.\n     */\n    public static final int PRIVATE_FLAG_VIRTUAL_PRELOAD = 1 << 16;\n\n    /**\n     * Value for {@code #privateFlags}: whether this app is pre-installed on the\n     * OEM partition of the system image.\n     */\n    public static final int PRIVATE_FLAG_OEM = 1 << 17;\n\n    /**\n     * Value for {@code #privateFlags}: whether this app is pre-installed on the\n     * vendor partition of the system image.\n     */\n    public static final int PRIVATE_FLAG_VENDOR = 1 << 18;\n\n    /**\n     * Value for {@code #privateFlags}: whether this app is pre-installed on the\n     * product partition of the system image.\n     */\n    public static final int PRIVATE_FLAG_PRODUCT = 1 << 19;\n\n    /**\n     * Value for {@code #privateFlags}: whether this app is signed with the\n     * platform key.\n     */\n    public static final int PRIVATE_FLAG_SIGNED_WITH_PLATFORM_KEY = 1 << 20;\n\n    /**\n     * Value for {@code #privateFlags}: whether this app is pre-installed on the\n     * system_ext partition of the system image.\n     */\n    public static final int PRIVATE_FLAG_SYSTEM_EXT = 1 << 21;\n\n    /**\n     * Indicates whether this package requires access to non-SDK APIs.\n     * Only system apps and tests are allowed to use this property.\n     */\n    public static final int PRIVATE_FLAG_USES_NON_SDK_API = 1 << 22;\n\n    /**\n     * Indicates whether this application can be profiled by the shell user,\n     * even when running on a device that is running in user mode.\n     */\n    public static final int PRIVATE_FLAG_PROFILEABLE_BY_SHELL = 1 << 23;\n\n    /**\n     * Indicates whether this package requires access to non-SDK APIs.\n     * Only system apps and tests are allowed to use this property.\n     */\n    public static final int PRIVATE_FLAG_HAS_FRAGILE_USER_DATA = 1 << 24;\n\n    /**\n     * Indicates whether this application wants to use the embedded dex in the APK, rather than\n     * extracted or locally compiled variants. This keeps the dex code protected by the APK\n     * signature. Such apps will always run in JIT mode (same when they are first installed), and\n     * the system will never generate ahead-of-time compiled code for them. Depending on the app's\n     * workload, there may be some run time performance change, noteably the cold start time.\n     */\n    public static final int PRIVATE_FLAG_USE_EMBEDDED_DEX = 1 << 25;\n\n    /**\n     * Value for {@code #privateFlags}: indicates whether this application's data will be cleared\n     * on a failed restore.\n     *\n     * <p>Comes from the\n     * android.R.styleable#AndroidManifestApplication_allowClearUserDataOnFailedRestore attribute\n     * of the &lt;application&gt; tag.\n     */\n    public static final int PRIVATE_FLAG_ALLOW_CLEAR_USER_DATA_ON_FAILED_RESTORE = 1 << 26;\n\n    /**\n     * Value for {@code #privateFlags}: true if the application allows its audio playback\n     * to be captured by other apps.\n     */\n    public static final int PRIVATE_FLAG_ALLOW_AUDIO_PLAYBACK_CAPTURE = 1 << 27;\n\n    /**\n     * Indicates whether this package is in fact a runtime resource overlay.\n     */\n    public static final int PRIVATE_FLAG_IS_RESOURCE_OVERLAY = 1 << 28;\n\n    /**\n     * Value for {@code #privateFlags}: If {@code true} this app requests\n     * full external storage access. The request may not be honored due to\n     * policy or other reasons.\n     */\n    public static final int PRIVATE_FLAG_REQUEST_LEGACY_EXTERNAL_STORAGE = 1 << 29;\n\n    /**\n     * Value for {@code #privateFlags}: whether this app is pre-installed on the\n     * ODM partition of the system image.\n     */\n    public static final int PRIVATE_FLAG_ODM = 1 << 30;\n\n    /**\n     * Value for {@code #privateFlags}: If {@code true} this app allows heap tagging.\n     * {@code com.android.server.am.ProcessList#NATIVE_HEAP_POINTER_TAGGING}\n     */\n    public static final int PRIVATE_FLAG_ALLOW_NATIVE_HEAP_POINTER_TAGGING = 1 << 31;\n\n    @IntDef(flag = true, value = {\n            PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE,\n            PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_RESIZEABLE_VIA_SDK_VERSION,\n            PRIVATE_FLAG_ACTIVITIES_RESIZE_MODE_UNRESIZEABLE,\n            PRIVATE_FLAG_BACKUP_IN_FOREGROUND,\n            PRIVATE_FLAG_CANT_SAVE_STATE,\n            PRIVATE_FLAG_DEFAULT_TO_DEVICE_PROTECTED_STORAGE,\n            PRIVATE_FLAG_DIRECT_BOOT_AWARE,\n            PRIVATE_FLAG_HAS_DOMAIN_URLS,\n            PRIVATE_FLAG_HIDDEN,\n            PRIVATE_FLAG_INSTANT,\n            PRIVATE_FLAG_IS_RESOURCE_OVERLAY,\n            PRIVATE_FLAG_ISOLATED_SPLIT_LOADING,\n            PRIVATE_FLAG_OEM,\n            PRIVATE_FLAG_PARTIALLY_DIRECT_BOOT_AWARE,\n            PRIVATE_FLAG_USE_EMBEDDED_DEX,\n            PRIVATE_FLAG_PRIVILEGED,\n            PRIVATE_FLAG_PRODUCT,\n            PRIVATE_FLAG_SYSTEM_EXT,\n            PRIVATE_FLAG_PROFILEABLE_BY_SHELL,\n            PRIVATE_FLAG_REQUIRED_FOR_SYSTEM_USER,\n            PRIVATE_FLAG_SIGNED_WITH_PLATFORM_KEY,\n            PRIVATE_FLAG_STATIC_SHARED_LIBRARY,\n            PRIVATE_FLAG_VENDOR,\n            PRIVATE_FLAG_VIRTUAL_PRELOAD,\n            PRIVATE_FLAG_HAS_FRAGILE_USER_DATA,\n            PRIVATE_FLAG_ALLOW_CLEAR_USER_DATA_ON_FAILED_RESTORE,\n            PRIVATE_FLAG_ALLOW_AUDIO_PLAYBACK_CAPTURE,\n            PRIVATE_FLAG_REQUEST_LEGACY_EXTERNAL_STORAGE,\n            PRIVATE_FLAG_ODM,\n            PRIVATE_FLAG_ALLOW_NATIVE_HEAP_POINTER_TAGGING,\n    })\n    @Retention(RetentionPolicy.SOURCE)\n    public @interface ApplicationInfoPrivateFlags {\n    }\n\n    /**\n     * Represents the default policy. The actual policy used will depend on other properties of\n     * the application, e.g. the target SDK version.\n     */\n    public static final int HIDDEN_API_ENFORCEMENT_DEFAULT = -1;\n    /**\n     * No API enforcement; the app can access the entire internal private API. Only for use by\n     * system apps.\n     */\n    public static final int HIDDEN_API_ENFORCEMENT_DISABLED = 0;\n    /**\n     * No API enforcement, but enable the detection logic and warnings. Observed behaviour is the\n     * same as {@link #HIDDEN_API_ENFORCEMENT_DISABLED} but you may see warnings in the log when\n     * APIs are accessed.\n     */\n    public static final int HIDDEN_API_ENFORCEMENT_JUST_WARN = 1;\n    /**\n     * Dark grey list enforcement. Enforces the dark grey and black lists\n     */\n    public static final int HIDDEN_API_ENFORCEMENT_ENABLED = 2;\n    /**\n     * Blacklist enforcement only.\n     */\n    public static final int HIDDEN_API_ENFORCEMENT_BLACK = 3;\n\n    @ApplicationInfoPrivateFlags\n    public static int getPrivateFlags(@NonNull ApplicationInfo info) {\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {\n            return Refine.<ApplicationInfoHidden>unsafeCast(info).privateFlags;\n        }\n        return 0;\n    }\n\n    @SuppressWarnings(\"deprecation\")\n    public static String getSeInfo(@NonNull ApplicationInfo info) {\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {\n            return Refine.<ApplicationInfoHidden>unsafeCast(info).seInfo + Refine.<ApplicationInfoHidden>unsafeCast(info).seInfoUser;\n        } else return Refine.<ApplicationInfoHidden>unsafeCast(info).seinfo;\n    }\n\n    @Nullable\n    public static String getPrimaryCpuAbi(@NonNull ApplicationInfo info) {\n        return Refine.<ApplicationInfoHidden>unsafeCast(info).primaryCpuAbi;\n    }\n\n    @Nullable\n    public static String getZygotePreloadName(@NonNull ApplicationInfo info) {\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {\n            return Refine.<ApplicationInfoHidden>unsafeCast(info).zygotePreloadName;\n        }\n        return null;\n    }\n\n    public static int getHiddenApiEnforcementPolicy(@NonNull ApplicationInfo info) {\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {\n            return Refine.<ApplicationInfoHidden>unsafeCast(info).getHiddenApiEnforcementPolicy();\n        }\n        return HIDDEN_API_ENFORCEMENT_DISABLED;\n    }\n\n    public static boolean isSystemApp(@NonNull ApplicationInfo info) {\n        return (info.flags & ApplicationInfo.FLAG_SYSTEM) != 0;\n    }\n\n    public static boolean isStopped(@NonNull ApplicationInfo info) {\n        return (info.flags & ApplicationInfo.FLAG_STOPPED) != 0;\n    }\n\n    public static boolean isInstalled(@NonNull ApplicationInfo info) {\n        return (info.flags & ApplicationInfo.FLAG_INSTALLED) != 0\n                && info.processName != null\n                && Paths.exists(info.publicSourceDir);\n    }\n\n    public static boolean isOnlyDataInstalled(@NonNull ApplicationInfo info) {\n        return (info.flags & ApplicationInfo.FLAG_INSTALLED) == 0\n                && !(info.processName != null\n                && Paths.exists(info.publicSourceDir));\n    }\n\n    public static boolean isTestOnly(@NonNull ApplicationInfo info) {\n        return (info.flags & ApplicationInfo.FLAG_TEST_ONLY) != 0;\n    }\n\n    public static boolean isSuspended(@NonNull ApplicationInfo info) {\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {\n            return (info.flags & ApplicationInfo.FLAG_SUSPENDED) != 0;\n        }\n        // Not supported\n        return false;\n    }\n\n    public static boolean isHidden(@NonNull ApplicationInfo info) {\n        return (getPrivateFlags(info) & PRIVATE_FLAG_HIDDEN) != 0;\n    }\n\n    public static boolean isStaticSharedLibrary(@NonNull ApplicationInfo info) {\n        // Android 8+\n        return (getPrivateFlags(info) & PRIVATE_FLAG_STATIC_SHARED_LIBRARY) != 0;\n    }\n\n    public static boolean isPrivileged(@NonNull ApplicationInfo info) {\n        return (getPrivateFlags(info) & PRIVATE_FLAG_PRIVILEGED) != 0;\n    }\n\n    public static boolean hasDomainUrls(@NonNull ApplicationInfo info) {\n        return (getPrivateFlags(info) & PRIVATE_FLAG_HAS_DOMAIN_URLS) != 0;\n    }\n\n    /**\n     * {@link ApplicationInfo#loadLabel(PackageManager)} can throw NPE for uninstalled apps in unprivileged mode.\n     *\n     * @return App label or package name if an error is occurred.\n     */\n    @NonNull\n    public static CharSequence loadLabelSafe(@NonNull ApplicationInfo info, @NonNull PackageManager pm) {\n        if (Paths.exists(info.publicSourceDir)) {\n            return info.loadLabel(pm);\n        }\n        return info.packageName;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/compat/BackupCompat.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.compat;\n\nimport android.annotation.UserIdInt;\nimport android.app.backup.IBackupManager;\nimport android.os.Build;\nimport android.os.ParcelFileDescriptor;\nimport android.os.RemoteException;\nimport android.os.UserHandleHidden;\n\nimport androidx.annotation.NonNull;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport aosp.libcore.util.EmptyArray;\nimport io.github.muntashirakon.AppManager.ipc.ProxyBinder;\nimport io.github.muntashirakon.AppManager.utils.ArrayUtils;\nimport io.github.muntashirakon.AppManager.utils.ExUtils;\n\n/**\n * A complete recreation of the `bu` command (i.e. com.android.commands.bu.Backup class) with support for setting a\n * file location. Although the help page of the command include an -f switch for file, it actually does not work with\n * the command and only intended for ADB itself.\n */\npublic final class BackupCompat {\n\n    private BackupCompat() {\n    }\n\n    /**\n     * @see IBackupManager#setBackupEnabledForUser(int, boolean)\n     */\n    public static void setBackupEnabledForUser(@UserIdInt int userId, boolean isEnabled) {\n        try {\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {\n                getBackupManager().setBackupEnabledForUser(userId, isEnabled);\n            } else {\n                getBackupManager().setBackupEnabled(isEnabled);\n            }\n        } catch (RemoteException e) {\n            ExUtils.rethrowFromSystemServer(e);\n        }\n    }\n\n    /**\n     * @see IBackupManager#isBackupEnabledForUser(int)\n     */\n    public static boolean isBackupEnabledForUser(@UserIdInt int userId) {\n        try {\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {\n                return getBackupManager().isBackupEnabledForUser(userId);\n            }\n            if (UserHandleHidden.myUserId() == userId) {\n                return getBackupManager().isBackupEnabled();\n            }\n            // Multiuser backup only available since Android 10\n            return false;\n        } catch (RemoteException e) {\n            return ExUtils.rethrowFromSystemServer(e);\n        }\n    }\n\n    public static boolean setBackupPassword(String currentPw, String newPw) {\n        try {\n            return getBackupManager().setBackupPassword(currentPw, newPw);\n        } catch (RemoteException e) {\n            return ExUtils.rethrowFromSystemServer(e);\n        }\n    }\n\n    public static boolean hasBackupPassword() {\n        try {\n            return getBackupManager().hasBackupPassword();\n        } catch (RemoteException e) {\n            return ExUtils.rethrowFromSystemServer(e);\n        }\n    }\n\n    @SuppressWarnings(\"deprecation\")\n    public static void adbBackup(@UserIdInt int userId, ParcelFileDescriptor fd, boolean includeApks, boolean includeObbs,\n                                 boolean includeShared, boolean doWidgets, boolean allApps, boolean allIncludesSystem,\n                                 boolean doCompress, boolean doKeyValue, String[] packageNames) throws RemoteException {\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {\n            getBackupManager().adbBackup(userId, fd, includeApks, includeObbs, includeShared, doWidgets, allApps, allIncludesSystem, doCompress, doKeyValue, packageNames);\n        } else {\n            if (UserHandleHidden.myUserId() != userId) {\n                throw new RemoteException(\"Backup only allowed for current user\");\n            }\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {\n                getBackupManager().adbBackup(fd, includeApks, includeObbs, includeShared, doWidgets, allApps, allIncludesSystem, doCompress, doKeyValue, packageNames);\n            } else {\n                getBackupManager().fullBackup(fd, includeApks, includeObbs, includeShared, doWidgets, allApps, allIncludesSystem, doCompress, packageNames);\n            }\n        }\n    }\n\n    @SuppressWarnings(\"deprecation\")\n    public static void adbRestore(@UserIdInt int userId, ParcelFileDescriptor fd) throws RemoteException {\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {\n            getBackupManager().adbRestore(userId, fd);\n        } else {\n            if (UserHandleHidden.myUserId() != userId) {\n                throw new RemoteException(\"Backup only allowed for current user\");\n            }\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {\n                getBackupManager().adbRestore(fd);\n            } else getBackupManager().fullRestore(fd);\n        }\n    }\n\n    @SuppressWarnings(\"deprecation\")\n    public static boolean isAppEligibleForBackupForUser(@UserIdInt int userId, String packageName) {\n        try {\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {\n                return getBackupManager().isAppEligibleForBackupForUser(userId, packageName);\n            } else {\n                if (UserHandleHidden.myUserId() != userId) {\n                    // Multiuser support unavailable\n                    return false;\n                }\n                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {\n                    return getBackupManager().isAppEligibleForBackup(packageName);\n                }\n                // In API 23 and earlier, set it to eligible by default\n                return true;\n            }\n        } catch (RemoteException e) {\n            return ExUtils.rethrowFromSystemServer(e);\n        }\n    }\n\n    @SuppressWarnings(\"deprecation\")\n    @NonNull\n    public static String[] filterAppsEligibleForBackupForUser(@UserIdInt int userId, @NonNull String[] packages) {\n        IBackupManager backupManager = getBackupManager();\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {\n            return ArrayUtils.defeatNullable(ExUtils.<String[]>exceptionAsNull(() -> {\n                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {\n                    backupManager.filterAppsEligibleForBackupForUser(userId, packages);\n                } else {\n                    backupManager.filterAppsEligibleForBackup(packages);\n                }\n                return null;\n            }));\n        }\n        if (UserHandleHidden.myUserId() != userId) {\n            // Multiuser support unavailable\n            return EmptyArray.STRING;\n        }\n        // Check individually\n        List<String> eligibleApps = new ArrayList<>(packages.length);\n        for (String packageName : packages) {\n            boolean isEligible;\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {\n                isEligible = Boolean.TRUE.equals(ExUtils.exceptionAsNull(() ->\n                        backupManager.isAppEligibleForBackup(packageName)));\n            } else isEligible = true;\n            if (isEligible) {\n                eligibleApps.add(packageName);\n            }\n        }\n        return eligibleApps.toArray(new String[0]);\n    }\n\n    public static IBackupManager getBackupManager() {\n        return IBackupManager.Stub.asInterface(ProxyBinder.getService(\"backup\"));\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/compat/BinderCompat.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.compat;\n\nimport android.os.Build;\nimport android.os.IBinder;\nimport android.os.IBinderHidden;\nimport android.os.RemoteException;\nimport android.os.ResultReceiver;\nimport android.os.ShellCallback;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.RequiresApi;\n\nimport java.io.FileDescriptor;\n\nimport dev.rikka.tools.refine.Refine;\n\npublic final class BinderCompat {\n\n    /**\n     * Execute a shell command on this object.  This may be performed asynchrously from the caller;\n     * the implementation must always call resultReceiver when finished.\n     *\n     * @param in             The raw file descriptor that an input data stream can be read from.\n     * @param out            The raw file descriptor that normal command messages should be written to.\n     * @param err            The raw file descriptor that command error messages should be written to.\n     * @param args           Command-line arguments.\n     * @param shellCallback  Optional callback to the caller's shell to perform operations in it.\n     * @param resultReceiver Called when the command has finished executing, with the result code.\n     */\n    @SuppressWarnings(\"deprecation\")\n    @RequiresApi(Build.VERSION_CODES.N)\n    public static void shellCommand(@NonNull IBinder binder,\n                                    @NonNull FileDescriptor in, @NonNull FileDescriptor out,\n                                    @NonNull FileDescriptor err,\n                                    @NonNull String[] args, @Nullable ShellCallback shellCallback,\n                                    @NonNull ResultReceiver resultReceiver) throws RemoteException {\n        IBinderHidden binderHidden = Refine.unsafeCast(binder);\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {\n            binderHidden.shellCommand(in, out, err, args, shellCallback, resultReceiver);\n        } else binderHidden.shellCommand(in, out, err, args, resultReceiver);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/compat/BiometricAuthenticatorsCompat.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.compat;\n\nimport android.os.Build;\n\nimport androidx.biometric.BiometricManager.Authenticators;\n\npublic class BiometricAuthenticatorsCompat {\n    public static final class Builder {\n        private boolean mAllowWeak = false;\n        private boolean mAllowStrong = false;\n        private boolean mAllowDeviceCredential = false;\n        private boolean mDeviceCredentialOnly = false;\n\n        public Builder() {\n        }\n\n        public Builder allowEverything(boolean allow) {\n            mAllowWeak = allow;\n            mAllowDeviceCredential = allow;\n            return this;\n        }\n\n        public Builder allowWeakBiometric(boolean allow) {\n            mAllowWeak = allow;\n            return this;\n        }\n\n        public Builder allowStrongBiometric(boolean allow) {\n            mAllowStrong = allow;\n            return this;\n        }\n\n        public Builder allowDeviceCredential(boolean allow) {\n            mAllowDeviceCredential = allow;\n            return this;\n        }\n\n        public Builder deviceCredentialOnly(boolean only) {\n            mDeviceCredentialOnly = only;\n            return this;\n        }\n\n        public int build() {\n            if (mDeviceCredentialOnly) {\n                return getDeviceCredentialOnlyFlags();\n            }\n            int flags;\n            if (mAllowWeak) {\n                flags = Authenticators.BIOMETRIC_WEAK;\n            } else if (mAllowStrong) {\n                flags = Authenticators.BIOMETRIC_STRONG;\n            } else flags = 0;\n            if (mAllowDeviceCredential) {\n                if (flags == 0) {\n                    return getDeviceCredentialOnlyFlags();\n                }\n                if (flags == Authenticators.BIOMETRIC_STRONG && (\n                        Build.VERSION.SDK_INT < Build.VERSION_CODES.P\n                        || Build.VERSION.SDK_INT > Build.VERSION_CODES.Q)) {\n                    flags = Authenticators.BIOMETRIC_WEAK;\n                }\n                return flags | Authenticators.DEVICE_CREDENTIAL;\n            }\n            return flags;\n        }\n\n        private int getDeviceCredentialOnlyFlags() {\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {\n                return Authenticators.DEVICE_CREDENTIAL;\n            }\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {\n                return Authenticators.BIOMETRIC_WEAK | Authenticators.DEVICE_CREDENTIAL;\n            }\n            return Authenticators.BIOMETRIC_STRONG | Authenticators.DEVICE_CREDENTIAL;\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/compat/ClearDataObserver.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.compat;\n\nimport android.content.pm.IPackageDataObserver;\n\npublic class ClearDataObserver extends IPackageDataObserver.Stub {\n    private boolean mCompleted;\n    private boolean mSuccessful;\n\n    @Override\n    public void onRemoveCompleted(String packageName, boolean succeeded) {\n        synchronized (this) {\n            mCompleted = true;\n            mSuccessful = succeeded;\n            notifyAll();\n        }\n    }\n\n    public boolean isCompleted() {\n        return mCompleted;\n    }\n\n    public boolean isSuccessful() {\n        return mSuccessful;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/compat/ConnectivityManagerCompat.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.compat;\n\nimport android.annotation.SuppressLint;\nimport android.content.Context;\nimport android.net.ConnectivityManagerHidden;\nimport android.net.IConnectivityManager;\nimport android.os.Build;\nimport android.os.RemoteException;\n\nimport androidx.annotation.IntDef;\nimport androidx.annotation.RequiresApi;\n\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\n\nimport io.github.muntashirakon.AppManager.ipc.ProxyBinder;\n\npublic class ConnectivityManagerCompat {\n    @SuppressLint(\"UniqueConstants\")\n    @Retention(RetentionPolicy.SOURCE)\n    @IntDef(value = {\n            ConnectivityManagerHidden.FIREWALL_CHAIN_DOZABLE,\n            ConnectivityManagerHidden.FIREWALL_CHAIN_STANDBY,\n            ConnectivityManagerHidden.FIREWALL_CHAIN_POWERSAVE,\n            ConnectivityManagerHidden.FIREWALL_CHAIN_RESTRICTED,\n            ConnectivityManagerHidden.FIREWALL_CHAIN_LOW_POWER_STANDBY,\n            ConnectivityManagerHidden.FIREWALL_CHAIN_LOCKDOWN_VPN,\n            ConnectivityManagerHidden.FIREWALL_CHAIN_BACKGROUND,\n            ConnectivityManagerHidden.FIREWALL_CHAIN_OEM_DENY_1,\n            ConnectivityManagerHidden.FIREWALL_CHAIN_OEM_DENY_2,\n            ConnectivityManagerHidden.FIREWALL_CHAIN_OEM_DENY_3,\n    })\n    @RequiresApi(Build.VERSION_CODES.TIRAMISU)\n    public @interface FirewallChain {\n    }\n\n    @Retention(RetentionPolicy.SOURCE)\n    @IntDef(value = {\n            ConnectivityManagerHidden.FIREWALL_RULE_DEFAULT,\n            ConnectivityManagerHidden.FIREWALL_RULE_ALLOW,\n            ConnectivityManagerHidden.FIREWALL_RULE_DENY\n    })\n    @RequiresApi(Build.VERSION_CODES.TIRAMISU)\n    public @interface FirewallRule {\n    }\n\n    @RequiresApi(Build.VERSION_CODES.TIRAMISU)\n    public static void setUidFirewallRule(@FirewallChain int chain, int uid,  @FirewallRule int rule) throws RemoteException {\n        getConnectivityManager().setUidFirewallRule(chain, uid, rule);\n    }\n\n    @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)\n    @FirewallRule\n    public static int getUidFirewallRule(@FirewallChain int chain, int uid) throws RemoteException {\n        return getConnectivityManager().getUidFirewallRule(chain, uid);\n    }\n\n    @RequiresApi(Build.VERSION_CODES.TIRAMISU)\n    public static void setFirewallChainEnabled(@FirewallChain int chain, boolean enable) throws RemoteException {\n        getConnectivityManager().setFirewallChainEnabled(chain, enable);\n    }\n\n    @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)\n    public static boolean getFirewallChainEnabled(@FirewallChain int chain) throws RemoteException {\n        return getConnectivityManager().getFirewallChainEnabled(chain);\n    }\n\n    @RequiresApi(Build.VERSION_CODES.TIRAMISU)\n    public static void replaceFirewallChain(@FirewallChain int chain, int[] uids) throws RemoteException {\n        getConnectivityManager().replaceFirewallChain(chain, uids);\n    }\n\n    private static IConnectivityManager getConnectivityManager() {\n        return IConnectivityManager.Stub.asInterface(ProxyBinder.getService(Context.CONNECTIVITY_SERVICE));\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/compat/DeviceIdleManagerCompat.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.compat;\n\nimport android.os.Build;\nimport android.os.IDeviceIdleController;\nimport android.os.RemoteException;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.RequiresApi;\nimport androidx.annotation.RequiresPermission;\n\nimport io.github.muntashirakon.AppManager.ipc.ProxyBinder;\nimport io.github.muntashirakon.AppManager.utils.ExUtils;\n\npublic final class DeviceIdleManagerCompat {\n    @RequiresPermission(ManifestCompat.permission.DEVICE_POWER)\n    public static boolean disableBatteryOptimization(@NonNull String packageName) {\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {\n            try {\n                getDeviceIdleController().addPowerSaveWhitelistApp(packageName);\n                return true; // returns true when the package isn't installed\n            } catch (RemoteException e) {\n                ExUtils.rethrowFromSystemServer(e);\n            }\n        }\n        return false;\n    }\n\n    @RequiresPermission(ManifestCompat.permission.DEVICE_POWER)\n    public static boolean enableBatteryOptimization(@NonNull String packageName) {\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {\n            try {\n                getDeviceIdleController().removePowerSaveWhitelistApp(packageName);\n                return true;\n            } catch (RemoteException e) {\n                ExUtils.rethrowFromSystemServer(e);\n            } catch (UnsupportedOperationException e) {\n                // System whitelisted app\n                e.printStackTrace();\n            }\n        }\n        return false;\n    }\n\n    public static boolean isBatteryOptimizedApp(@NonNull String packageName) {\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {\n            try {\n                IDeviceIdleController controller = getDeviceIdleController();\n                return !controller.isPowerSaveWhitelistExceptIdleApp(packageName) &&\n                        !controller.isPowerSaveWhitelistApp(packageName);\n            } catch (RemoteException e) {\n                ExUtils.rethrowFromSystemServer(e);\n            }\n        }\n        // Not supported\n        return true;\n    }\n\n    @RequiresApi(Build.VERSION_CODES.M)\n    private static IDeviceIdleController getDeviceIdleController() {\n        return IDeviceIdleController.Stub.asInterface(ProxyBinder.getService(\"deviceidle\"));\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/compat/DomainVerificationManagerCompat.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.compat;\n\nimport android.content.Context;\nimport android.content.pm.PackageManager;\nimport android.content.pm.verify.domain.DomainVerificationUserState;\nimport android.content.pm.verify.domain.IDomainVerificationManager;\nimport android.os.Build;\nimport android.os.RemoteException;\nimport android.os.ServiceSpecificException;\n\nimport androidx.annotation.Nullable;\nimport androidx.annotation.RequiresApi;\nimport androidx.annotation.RequiresPermission;\n\nimport io.github.muntashirakon.AppManager.ipc.ProxyBinder;\n\n@RequiresApi(Build.VERSION_CODES.S)\npublic class DomainVerificationManagerCompat {\n    @Nullable\n    public static DomainVerificationUserState getDomainVerificationUserState(String packageName, int userId) {\n        try {\n            return getDomainVerificationManager().getDomainVerificationUserState(packageName, userId);\n        } catch (Throwable ignore) {\n        }\n        return null;\n    }\n\n    @RequiresPermission(ManifestCompat.permission.UPDATE_DOMAIN_VERIFICATION_USER_SELECTION)\n    public static void setDomainVerificationLinkHandlingAllowed(String packageName, boolean allowed, int userId)\n            throws RemoteException, PackageManager.NameNotFoundException {\n        try {\n            getDomainVerificationManager().setDomainVerificationLinkHandlingAllowed(packageName, allowed, userId);\n        } catch (ServiceSpecificException e) {\n            int serviceSpecificErrorCode = e.errorCode;\n            if (packageName == null) {\n                packageName = e.getMessage();\n            }\n\n            if (serviceSpecificErrorCode == 1) {\n                throw new PackageManager.NameNotFoundException(packageName);\n            }\n            throw e;\n        }\n    }\n\n    public static IDomainVerificationManager getDomainVerificationManager() {\n        return IDomainVerificationManager.Stub.asInterface(ProxyBinder.getService(Context.DOMAIN_VERIFICATION_SERVICE));\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/compat/InputManagerCompat.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.compat;\n\nimport android.content.Context;\nimport android.hardware.input.IInputManager;\nimport android.hardware.input.InputManagerHidden;\nimport android.os.Build;\nimport android.os.RemoteException;\nimport android.os.SystemClock;\nimport android.view.InputDevice;\nimport android.view.InputEvent;\nimport android.view.KeyCharacterMap;\nimport android.view.KeyEvent;\nimport android.view.ViewConfiguration;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.RequiresPermission;\n\nimport io.github.muntashirakon.AppManager.ipc.ProxyBinder;\n\n// Based on https://cs.android.com/android/platform/superproject/main/+/main:frameworks/base/services/core/java/com/android/server/input/InputShellCommand.java;l=350;drc=0b80090e02814093f2187c2ce7e64f87cb917edc\npublic class InputManagerCompat {\n    @RequiresPermission(ManifestCompat.permission.INJECT_EVENTS)\n    public static boolean sendKeyEvent(int keyCode, boolean longpress) {\n        long now = SystemClock.uptimeMillis();\n        KeyEvent event = new KeyEvent(now, now, KeyEvent.ACTION_DOWN, keyCode, 0, 0,\n                KeyCharacterMap.VIRTUAL_KEYBOARD, 0, 0, InputDevice.SOURCE_UNKNOWN);\n        boolean success = true;\n\n        success &= injectKeyEvent(event);\n        if (longpress) {\n            sleep(ViewConfiguration.getLongPressTimeout());\n            // Some long press behavior would check the event time, we set a new event time here.\n            long nextEventTime = now + ViewConfiguration.getLongPressTimeout();\n            success &=injectKeyEvent(KeyEvent.changeTimeRepeat(event, nextEventTime, 1,\n                    KeyEvent.FLAG_LONG_PRESS));\n        }\n        success &= injectKeyEvent(KeyEvent.changeAction(event, KeyEvent.ACTION_UP));\n        return success;\n    }\n\n    @RequiresPermission(ManifestCompat.permission.INJECT_EVENTS)\n    public static boolean injectKeyEvent(KeyEvent event) {\n        return injectInputEvent(event, InputManagerHidden.INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH, -1);\n    }\n\n    @RequiresPermission(ManifestCompat.permission.INJECT_EVENTS)\n    public static boolean injectInputEvent(@NonNull InputEvent event, int mode, int targetUid) {\n        IInputManager inputManager = getInputManager();\n        try {\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {\n                return inputManager.injectInputEventToTarget(event, mode, targetUid);\n            } else return inputManager.injectInputEvent(event, mode);\n        } catch (RemoteException e) {\n            return false;\n        }\n    }\n\n    /**\n     * Puts the thread to sleep for the provided time.\n     *\n     * @param milliseconds The time to sleep in milliseconds.\n     */\n    private static void sleep(long milliseconds) {\n        try {\n            Thread.sleep(milliseconds);\n        } catch (InterruptedException e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    private static IInputManager getInputManager() {\n        return IInputManager.Stub.asInterface(ProxyBinder.getService(Context.INPUT_SERVICE));\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/compat/InstallSourceInfoCompat.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.compat;\n\nimport android.content.pm.InstallSourceInfo;\nimport android.content.pm.PackageManager;\nimport android.content.pm.SigningInfo;\nimport android.os.Build;\nimport android.os.Parcel;\nimport android.os.Parcelable;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.RequiresApi;\nimport androidx.core.os.ParcelCompat;\n\npublic class InstallSourceInfoCompat implements Parcelable {\n\n    @Nullable\n    private final String mInitiatingPackageName;\n\n    @RequiresApi(Build.VERSION_CODES.P)\n    @Nullable\n    private SigningInfo mInitiatingPackageSigningInfo;\n\n    @Nullable\n    private final String mOriginatingPackageName;\n\n    @Nullable\n    private final String mInstallingPackageName;\n\n    @Nullable\n    private CharSequence mInitiatingPackageLabel;\n    @Nullable\n    private CharSequence mOriginatingPackageLabel;\n    @Nullable\n    private CharSequence mInstallingPackageLabel;\n\n    @RequiresApi(Build.VERSION_CODES.R)\n    public InstallSourceInfoCompat(@Nullable InstallSourceInfo installSourceInfo) {\n        if (installSourceInfo != null) {\n            mInitiatingPackageName = installSourceInfo.getInitiatingPackageName();\n            mInitiatingPackageSigningInfo = installSourceInfo.getInitiatingPackageSigningInfo();\n            mOriginatingPackageName = installSourceInfo.getOriginatingPackageName();\n            mInstallingPackageName = installSourceInfo.getInstallingPackageName();\n        } else {\n            mInitiatingPackageName = null;\n            mOriginatingPackageName = null;\n            mInstallingPackageName = null;\n        }\n    }\n\n    public InstallSourceInfoCompat(@Nullable String installingPackageName) {\n        mInitiatingPackageName = null;\n        mOriginatingPackageName = null;\n        mInstallingPackageName = installingPackageName;\n    }\n\n    @Override\n    public int describeContents() {\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P && mInitiatingPackageSigningInfo != null) {\n            return mInitiatingPackageSigningInfo.describeContents();\n        }\n        return 0;\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        dest.writeString(mInitiatingPackageName);\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {\n            dest.writeParcelable(mInitiatingPackageSigningInfo, flags);\n        }\n        dest.writeString(mOriginatingPackageName);\n        dest.writeString(mInstallingPackageName);\n    }\n\n    private InstallSourceInfoCompat(Parcel source) {\n        mInitiatingPackageName = source.readString();\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {\n            mInitiatingPackageSigningInfo = ParcelCompat.readParcelable(source, SigningInfo.class.getClassLoader(), SigningInfo.class);\n        }\n        mOriginatingPackageName = source.readString();\n        mInstallingPackageName = source.readString();\n    }\n\n    public void setInitiatingPackageLabel(@Nullable CharSequence label) {\n        mInitiatingPackageLabel = label;\n    }\n\n    @Nullable\n    public CharSequence getInitiatingPackageLabel() {\n        return mInitiatingPackageLabel;\n    }\n\n    public void setOriginatingPackageLabel(@Nullable CharSequence label) {\n        mOriginatingPackageLabel = label;\n    }\n\n    @Nullable\n    public CharSequence getOriginatingPackageLabel() {\n        return mOriginatingPackageLabel;\n    }\n\n    public void setInstallingPackageLabel(@Nullable CharSequence label) {\n        mInstallingPackageLabel = label;\n    }\n\n    @Nullable\n    public CharSequence getInstallingPackageLabel() {\n        return mInstallingPackageLabel;\n    }\n\n    /**\n     * The name of the package that requested the installation, or null if not available.\n     * <p>\n     * This is normally the same as the installing package name. If the installing package name\n     * is changed, for example by calling\n     * {@link PackageManager#setInstallerPackageName(String, String)}, the initiating package name\n     * remains unchanged. It continues to identify the actual package that performed the install\n     * or update.\n     * <p>\n     * Null may be returned if the app was not installed by a package (e.g. a system app or an app\n     * installed via adb) or if the initiating package has itself been uninstalled.\n     */\n    @Nullable\n    public String getInitiatingPackageName() {\n        return mInitiatingPackageName;\n    }\n\n    /**\n     * Information about the signing certificates used to sign the initiating package, if available.\n     */\n    @RequiresApi(Build.VERSION_CODES.P)\n    @Nullable\n    public SigningInfo getInitiatingPackageSigningInfo() {\n        return mInitiatingPackageSigningInfo;\n    }\n\n    /**\n     * The name of the package on behalf of which the initiating package requested the installation,\n     * or null if not available.\n     * <p>\n     * For example if a downloaded APK is installed via the Package Installer this could be the\n     * app that performed the download. This value is provided by the initiating package and not\n     * verified by the framework.\n     * <p>\n     * Note that the {@code InstallSourceInfo} returned by\n     * {@link PackageManager#getInstallSourceInfo(String)} will not have this information\n     * available unless the calling application holds the INSTALL_PACKAGES permission.\n     */\n    @Nullable\n    public String getOriginatingPackageName() {\n        return mOriginatingPackageName;\n    }\n\n    /**\n     * The name of the package responsible for the installation (the installer of record), or null\n     * if not available.\n     * Note that this may differ from the initiating package name and can be modified via\n     * {@link PackageManager#setInstallerPackageName(String, String)}.\n     * <p>\n     * Null may be returned if the app was not installed by a package (e.g. a system app or an app\n     * installed via adb) or if the installing package has itself been uninstalled.\n     */\n    @Nullable\n    public String getInstallingPackageName() {\n        return mInstallingPackageName;\n    }\n\n    @NonNull\n    public static final Parcelable.Creator<InstallSourceInfoCompat> CREATOR = new Creator<InstallSourceInfoCompat>() {\n        @Override\n        public InstallSourceInfoCompat createFromParcel(Parcel source) {\n            return new InstallSourceInfoCompat(source);\n        }\n\n        @Override\n        public InstallSourceInfoCompat[] newArray(int size) {\n            return new InstallSourceInfoCompat[size];\n        }\n    };\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/compat/IntegerCompat.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.compat;\n\nimport androidx.annotation.NonNull;\n\npublic class IntegerCompat {\n    /**\n     * Return a 0x prefixed signed hex.\n     */\n    @NonNull\n    public static String toSignedHex(int signedInt) {\n        StringBuilder sb = new StringBuilder();\n        sb.append(Integer.toString(signedInt, 16));\n        sb.insert(sb.charAt(0) == '-' ? 1 : 0, \"0x\");\n        return sb.toString();\n    }\n\n    /**\n     * Return a 0x prefixed unsigned hex.\n     */\n    @NonNull\n    public static String toUnsignedHex(int signedInt) {\n        return \"0x\" + Integer.toHexString(signedInt);\n    }\n\n    /**\n     * Same as {@link Integer#decode(String)} except it allows decoding both signed and unsigned values\n     */\n    public static int decode(@NonNull String nm) throws NumberFormatException {\n        int radix = 10;\n        int index = 0;\n\n        if (nm.length() == 0) {\n            throw new NumberFormatException(\"Zero length string\");\n        }\n        char firstChar = nm.charAt(0);\n        // Handle sign, if present\n        if (firstChar == '-') {\n            // First character is a signed character, use regular decoding\n            return Integer.decode(nm);\n        } else if (firstChar == '+') {\n            index++;\n        }\n\n        // Handle radix specifier, if present\n        if (nm.startsWith(\"0x\", index) || nm.startsWith(\"0X\", index)) {\n            index += 2;\n            radix = 16;\n        } else if (nm.startsWith(\"#\", index)) {\n            index++;\n            radix = 16;\n        } else if (nm.startsWith(\"0\", index) && nm.length() > 1 + index) {\n            index++;\n            radix = 8;\n        }\n\n        if (nm.startsWith(\"-\", index) || nm.startsWith(\"+\", index)) {\n            throw new NumberFormatException(\"Sign character in wrong position\");\n        }\n\n        return Integer.parseUnsignedInt(nm.substring(index), radix);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/compat/ManifestCompat.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.compat;\n\nimport android.os.Build;\n\nimport androidx.annotation.RequiresApi;\n\npublic final class ManifestCompat {\n    public static final class permission {\n        public static final String TERMUX_RUN_COMMAND = \"com.termux.permission.RUN_COMMAND\";\n\n        @RequiresApi(Build.VERSION_CODES.Q)\n        public static final String ADJUST_RUNTIME_PERMISSIONS_POLICY = \"android.permission.ADJUST_RUNTIME_PERMISSIONS_POLICY\";\n        public static final String BACKUP = \"android.permission.BACKUP\";\n        @RequiresApi(Build.VERSION_CODES.O)\n        public static final String CHANGE_OVERLAY_PACKAGES = \"android.permission.CHANGE_OVERLAY_PACKAGES\";\n        public static final String CLEAR_APP_USER_DATA = \"android.permission.CLEAR_APP_USER_DATA\";\n        @RequiresApi(Build.VERSION_CODES.N)\n        public static final String CREATE_USERS = \"android.permission.CREATE_USERS\";\n        public static final String DEVICE_POWER = \"android.permission.DEVICE_POWER\";\n        public static final String FORCE_STOP_PACKAGES = \"android.permission.FORCE_STOP_PACKAGES\";\n        public static final String GET_APP_OPS_STATS = \"android.permission.GET_APP_OPS_STATS\";\n        @RequiresApi(Build.VERSION_CODES.TIRAMISU)\n        public static final String GET_HISTORICAL_APP_OPS_STATS = \"android.permission.GET_HISTORICAL_APP_OPS_STATS\";\n        public static final String GET_RUNTIME_PERMISSIONS = \"android.permission.GET_RUNTIME_PERMISSIONS\";\n        public static final String GRANT_RUNTIME_PERMISSIONS = \"android.permission.GRANT_RUNTIME_PERMISSIONS\";\n        public static final String INJECT_EVENTS = \"android.permission.INJECT_EVENTS\";\n        @RequiresApi(Build.VERSION_CODES.Q)\n        public static final String INSTALL_EXISTING_PACKAGES = \"com.android.permission.INSTALL_EXISTING_PACKAGES\";\n        public static final String INTERACT_ACROSS_USERS = \"android.permission.INTERACT_ACROSS_USERS\";\n        public static final String INTERACT_ACROSS_USERS_FULL = \"android.permission.INTERACT_ACROSS_USERS_FULL\";\n        @RequiresApi(Build.VERSION_CODES.P)\n        public static final String INTERNAL_DELETE_CACHE_FILES = \"android.permission.INTERNAL_DELETE_CACHE_FILES\";\n        @RequiresApi(Build.VERSION_CODES.M)\n        public static final String KILL_UID = \"android.permission.KILL_UID\";\n        @RequiresApi(Build.VERSION_CODES.N)\n        public static final String MANAGE_APP_OPS_RESTRICTIONS = \"android.permission.MANAGE_APP_OPS_RESTRICTIONS\";\n        @RequiresApi(Build.VERSION_CODES.P)\n        public static final String MANAGE_APP_OPS_MODES = \"android.permission.MANAGE_APP_OPS_MODES\";\n        @RequiresApi(Build.VERSION_CODES.Q)\n        public static final String MANAGE_APPOPS = \"android.permission.MANAGE_APPOPS\";\n        public static final String MANAGE_NETWORK_POLICY = \"android.permission.MANAGE_NETWORK_POLICY\";\n        @RequiresApi(Build.VERSION_CODES.S)\n        public static final String MANAGE_NOTIFICATION_LISTENERS = \"android.permission.MANAGE_NOTIFICATION_LISTENERS\";\n        @RequiresApi(Build.VERSION_CODES.P)\n        public static final String MANAGE_SENSORS = \"android.permission.MANAGE_SENSORS\";\n        public static final String MANAGE_USERS = \"android.permission.MANAGE_USERS\";\n        public static final String READ_PRIVILEGED_PHONE_STATE = \"android.permission.READ_PRIVILEGED_PHONE_STATE\";\n        public static final String REAL_GET_TASKS = \"android.permission.REAL_GET_TASKS\";\n        public static final String REVOKE_RUNTIME_PERMISSIONS = \"android.permission.REVOKE_RUNTIME_PERMISSIONS\";\n        public static final String START_ANY_ACTIVITY = \"android.permission.START_ANY_ACTIVITY\";\n        @RequiresApi(Build.VERSION_CODES.P)\n        public static final String SUSPEND_APPS = \"android.permission.SUSPEND_APPS\";\n        public static final String UPDATE_APP_OPS_STATS = \"android.permission.UPDATE_APP_OPS_STATS\";\n        @RequiresApi(Build.VERSION_CODES.S)\n        public static final String UPDATE_DOMAIN_VERIFICATION_USER_SELECTION = \"android.permission.UPDATE_DOMAIN_VERIFICATION_USER_SELECTION\";\n        @RequiresApi(Build.VERSION_CODES.P)\n        public static final String WATCH_APPOPS = \"android.permission.WATCH_APPOPS\";\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/compat/NetworkPolicyManagerCompat.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.compat;\n\nimport android.content.Context;\nimport android.net.INetworkPolicyManager;\nimport android.net.NetworkPolicyManager;\nimport android.os.RemoteException;\nimport android.os.UserHandleHidden;\n\nimport androidx.annotation.IntDef;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.RequiresPermission;\nimport androidx.collection.ArrayMap;\n\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.reflect.Field;\n\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.ipc.ProxyBinder;\nimport io.github.muntashirakon.AppManager.logs.Log;\nimport io.github.muntashirakon.AppManager.utils.ExUtils;\n\npublic final class NetworkPolicyManagerCompat {\n    public static final String TAG = NetworkPolicyManagerCompat.class.getSimpleName();\n\n    /*\n     * The policies below are taken from LineageOS\n     * Source: https://github.com/LineageOS/android_frameworks_base/blob/lineage-18.1/core/java/android/net/NetworkPolicyManager.java\n     */\n    /**\n     * Reject network usage on Wi-Fi network. {@code POLICY_REJECT_ON_WLAN} up to Lineage 17.1 (Android 10)\n     */\n    public static final int POLICY_LOS_REJECT_WIFI = 1 << 15;\n    /**\n     * Reject network usage on cellular network. {@code POLICY_REJECT_ON_DATA} up to Lineage 17.1 (Android 10)\n     */\n    public static final int POLICY_LOS_REJECT_CELLULAR = 1 << 16;\n    /**\n     * Reject network usage on virtual private network. {@code POLICY_REJECT_ON_VPN} up to Lineage 17.1 (Android 10)\n     */\n    public static final int POLICY_LOS_REJECT_VPN = 1 << 17;\n    /**\n     * Reject network usage on all networks. {@code POLICY_NETWORK_ISOLATED} up to Lineage 17.1 (Android 10)\n     */\n    public static final int POLICY_LOS_REJECT_ALL = 1 << 18;\n    // The following are taken from Motorola device (Android 12)\n    public static final int POLICY_MOTO_REJECT_METERED = 1 << 1;\n    public static final int POLICY_MOTO_REJECT_BACKGROUND = 1 << 5;\n    public static final int POLICY_MOTO_REJECT_ALL = 1 << 6;\n    // The following are taken from Samsung device (Android 10)\n    public static final int POLICY_ONE_UI_ALLOW_METERED_IN_ROAMING = 1001;\n    public static final int POLICY_ONE_UI_ALLOW_WHITELIST_IN_ROAMING = 1002;\n\n    @IntDef(flag = true, value = {\n            NetworkPolicyManager.POLICY_NONE,\n            NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND,\n            NetworkPolicyManager.POLICY_ALLOW_METERED_BACKGROUND,\n            // Lineage OS\n            POLICY_LOS_REJECT_WIFI,\n            POLICY_LOS_REJECT_CELLULAR,\n            POLICY_LOS_REJECT_VPN,\n            POLICY_LOS_REJECT_ALL,\n            // Motorola\n            POLICY_MOTO_REJECT_METERED,\n            POLICY_MOTO_REJECT_BACKGROUND,\n            POLICY_MOTO_REJECT_ALL,\n            // Samsung\n            POLICY_ONE_UI_ALLOW_METERED_IN_ROAMING,\n            POLICY_ONE_UI_ALLOW_WHITELIST_IN_ROAMING,\n    })\n    @Retention(RetentionPolicy.SOURCE)\n    public @interface NetPolicy {\n    }\n\n    private static final ArrayMap<Integer, String> sNetworkPolicies = new ArrayMap<Integer, String>() {\n        {\n            for (Field field : NetworkPolicyManager.class.getFields()) {\n                if (field.getName().startsWith(\"POLICY_\")) {\n                    try {\n                        put(field.getInt(null), field.getName());\n                    } catch (IllegalAccessException ignore) {\n                    }\n                }\n            }\n        }\n    };\n\n    @NetPolicy\n    @RequiresPermission(ManifestCompat.permission.MANAGE_NETWORK_POLICY)\n    public static int getUidPolicy(int uid) {\n        try {\n            return getNetPolicyManager().getUidPolicy(uid);\n        } catch (RemoteException e) {\n            return ExUtils.rethrowFromSystemServer(e);\n        }\n    }\n\n    @RequiresPermission(ManifestCompat.permission.MANAGE_NETWORK_POLICY)\n    public static void setUidPolicy(int uid, int policies) {\n        if (UserHandleHidden.isApp(uid)) {\n            try {\n                getNetPolicyManager().setUidPolicy(uid, policies);\n            } catch (RemoteException e) {\n                ExUtils.rethrowFromSystemServer(e);\n            }\n        } else {\n            Log.w(TAG, \"Cannot set policy %d to uid %d\", policies, uid);\n        }\n    }\n\n    @NonNull\n    public static ArrayMap<Integer, String> getReadablePolicies(@NonNull Context context, int policies) {\n        ArrayMap<Integer, String> readablePolicies = new ArrayMap<>();\n        if (policies == 0) {\n            readablePolicies.put(NetworkPolicyManager.POLICY_NONE, context.getString(R.string.none));\n            return readablePolicies;\n        }\n        for (int i = 0; i < sNetworkPolicies.size(); ++i) {\n            int policy = sNetworkPolicies.keyAt(i);\n            if (!hasPolicy(policies, policy)) {\n                continue;\n            }\n            String policyName = sNetworkPolicies.valueAt(i);\n            String readablePolicyName = getReadablePolicyName(context, policy, policyName);\n            readablePolicies.put(policy, readablePolicyName);\n        }\n        return readablePolicies;\n    }\n\n    @NonNull\n    public static ArrayMap<Integer, String> getAllReadablePolicies(@NonNull Context context) {\n        ArrayMap<Integer, String> readablePolicies = new ArrayMap<>();\n        for (int i = 0; i < sNetworkPolicies.size(); ++i) {\n            int policy = sNetworkPolicies.keyAt(i);\n            String policyName = sNetworkPolicies.valueAt(i);\n            String readablePolicyName = getReadablePolicyName(context, policy, policyName);\n            readablePolicies.put(policy, readablePolicyName);\n        }\n        return readablePolicies;\n    }\n\n    private static INetworkPolicyManager getNetPolicyManager() {\n        return INetworkPolicyManager.Stub.asInterface(ProxyBinder.getService(\"netpolicy\"));\n    }\n\n    private static boolean hasPolicy(int policies, int policy) {\n        return (policies & policy) != 0;\n    }\n\n    private static String getReadablePolicyName(@NonNull Context context, int policy, @NonNull String policyName) {\n        switch (policy) {\n            case NetworkPolicyManager.POLICY_NONE:\n                return context.getString(R.string.none);\n            case NetworkPolicyManager.POLICY_REJECT_METERED_BACKGROUND:\n                return context.getString(R.string.netpolicy_reject_metered_background_data);\n            case NetworkPolicyManager.POLICY_ALLOW_METERED_BACKGROUND:\n                return context.getString(R.string.netpolicy_allow_metered_background_data);\n            case POLICY_LOS_REJECT_WIFI:\n                if (policyName.equals(\"POLICY_REJECT_ON_WLAN\") || policyName.equals(\"POLICY_REJECT_WIFI\")) {\n                    return context.getString(R.string.netpolicy_reject_wifi_data);\n                }\n                break;\n            case POLICY_LOS_REJECT_CELLULAR:\n                if (policyName.equals(\"POLICY_REJECT_ON_DATA\") || policyName.equals(\"POLICY_REJECT_CELLULAR\")) {\n                    return context.getString(R.string.netpolicy_reject_cellular_data);\n                }\n                break;\n            case POLICY_LOS_REJECT_VPN:\n                if (policyName.equals(\"POLICY_REJECT_ON_VPN\") || policyName.equals(\"POLICY_REJECT_VPN\")) {\n                    return context.getString(R.string.netpolicy_reject_vpn_data);\n                }\n                break;\n            case POLICY_LOS_REJECT_ALL:\n                if (policyName.equals(\"POLICY_NETWORK_ISOLATED\") || policyName.equals(\"POLICY_REJECT_ALL\")) {\n                    return context.getString(R.string.netpolicy_disable_network_access);\n                }\n                break;\n            case POLICY_MOTO_REJECT_METERED:\n                if (policyName.equals(\"POLICY_REJECT_METERED\")) {\n                    return context.getString(R.string.netpolicy_reject_metered_data);\n                }\n                break;\n            case POLICY_MOTO_REJECT_BACKGROUND:\n                if (policyName.equals(\"POLICY_REJECT_BACKGROUND\")) {\n                    return context.getString(R.string.netpolicy_reject_background_data);\n                }\n                break;\n            case POLICY_MOTO_REJECT_ALL:\n                if (policyName.equals(\"POLICY_REJECT_ALL\")) {\n                    return context.getString(R.string.netpolicy_disable_network_access);\n                }\n                break;\n        }\n        return context.getString(R.string.unknown_net_policy, policyName, policy);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/compat/NetworkStatsCompat.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.compat;\n\nimport android.net.INetworkStatsService;\nimport android.net.INetworkStatsSession;\nimport android.net.NetworkStats;\nimport android.net.NetworkTemplate;\nimport android.os.Build;\nimport android.os.RemoteException;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport io.github.muntashirakon.AppManager.self.SelfPermissions;\nimport io.github.muntashirakon.AppManager.settings.Ops;\nimport io.github.muntashirakon.AppManager.users.Users;\n\npublic class NetworkStatsCompat implements AutoCloseable {\n    private final NetworkTemplate mTemplate;\n    private final long mStartTime;\n    private final long mEndTime;\n\n    @Nullable\n    private INetworkStatsSession mSession;\n    private int mIndex;\n    @Nullable\n    private NetworkStats mSummary;\n    @Nullable\n    private NetworkStats.Entry mSummaryEntry;\n\n    NetworkStatsCompat(@NonNull NetworkTemplate template, int flags, long startTime, long endTime,\n                       @NonNull INetworkStatsService statsService) throws RemoteException, SecurityException {\n        mTemplate = template;\n        mStartTime = startTime;\n        mEndTime = endTime;\n        int callingUid = Users.getSelfOrRemoteUid();\n        String callingPackage = SelfPermissions.getCallingPackage(callingUid);\n        if (callingUid == Ops.ROOT_UID) {\n            mSession = statsService.openSession();\n        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) {\n            mSession = statsService.openSessionForUsageStats(flags, callingPackage);\n        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {\n            mSession = statsService.openSessionForUsageStats(callingPackage);\n        } else mSession = statsService.openSession();\n    }\n\n    public boolean hasNextEntry() {\n        return mSummary != null && mIndex < mSummary.size();\n    }\n\n    @Nullable\n    public NetworkStats.Entry getNextEntry(boolean recycle) {\n        if (mSummary == null) {\n            return null;\n        }\n        mSummaryEntry = mSummary.getValues(mIndex, recycle ? mSummaryEntry : null);\n        ++mIndex;\n        return mSummaryEntry;\n    }\n\n    void startSummaryEnumeration() throws RemoteException {\n        if (mSession != null) {\n            mSummary = mSession.getSummaryForAllUid(mTemplate, mStartTime, mEndTime, false);\n        }\n        mIndex = 0;\n    }\n\n    @Override\n    public void close() {\n        if (mSession != null) {\n            try {\n                mSession.close();\n            } catch (RemoteException e) {\n                e.printStackTrace();\n                // Otherwise, meh\n            }\n        }\n        mSession = null;\n    }\n\n    @Override\n    protected void finalize() throws Throwable {\n        try {\n            close();\n        } finally {\n            super.finalize();\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/compat/NetworkStatsManagerCompat.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.compat;\n\nimport android.Manifest;\nimport android.content.Context;\nimport android.net.INetworkStatsService;\nimport android.net.NetworkCapabilities;\nimport android.net.NetworkTemplate;\nimport android.os.Build;\nimport android.os.RemoteException;\nimport android.text.TextUtils;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.RequiresApi;\nimport androidx.annotation.RequiresPermission;\n\nimport io.github.muntashirakon.AppManager.ipc.ProxyBinder;\n\npublic class NetworkStatsManagerCompat {\n    @NonNull\n    @RequiresApi(Build.VERSION_CODES.M)\n    @RequiresPermission(Manifest.permission.PACKAGE_USAGE_STATS)\n    public static NetworkStatsCompat querySummary(int networkType, @Nullable String subscriberId, long startTime, long endTime)\n            throws RemoteException, SecurityException {\n        INetworkStatsService statsService = INetworkStatsService.Stub.asInterface(ProxyBinder.getService(Context.NETWORK_STATS_SERVICE));\n        NetworkTemplate template = createTemplate(networkType, subscriberId);\n        NetworkStatsCompat networkStats = new NetworkStatsCompat(template, 0, startTime, endTime, statsService);\n        networkStats.startSummaryEnumeration();\n        return networkStats;\n    }\n\n    @NonNull\n    private static NetworkTemplate createTemplate(int networkType, @Nullable String subscriberId) {\n        final NetworkTemplate template;\n        switch (networkType) {\n            case NetworkCapabilities.TRANSPORT_CELLULAR:\n                template = subscriberId == null\n                        ? NetworkTemplate.buildTemplateMobileWildcard()\n                        : NetworkTemplate.buildTemplateMobileAll(subscriberId);\n                break;\n            case NetworkCapabilities.TRANSPORT_WIFI:\n                template = TextUtils.isEmpty(subscriberId)\n                        ? NetworkTemplate.buildTemplateWifiWildcard()\n                        : new NetworkTemplate(NetworkTemplate.MATCH_WIFI, subscriberId, null);\n                break;\n            default:\n                throw new IllegalArgumentException(\"Cannot create template for network type \" + networkType + \"'.\");\n        }\n        return template;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/compat/OverlayManagerCompact.java",
    "content": "package io.github.muntashirakon.AppManager.compat;\n\nimport android.content.om.IOverlayManager;\nimport android.os.Build;\n\nimport androidx.annotation.RequiresApi;\nimport androidx.annotation.RequiresPermission;\n\nimport io.github.muntashirakon.AppManager.ipc.ProxyBinder;\n\n@RequiresApi(Build.VERSION_CODES.O)\npublic class OverlayManagerCompact {\n    @RequiresPermission(ManifestCompat.permission.CHANGE_OVERLAY_PACKAGES)\n    public static IOverlayManager getOverlayManager() {\n        return IOverlayManager.Stub.asInterface(ProxyBinder.getService(\"overlay\"));\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/compat/PackageInfoCompat2.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.compat;\n\nimport android.content.pm.PackageInfo;\nimport android.content.pm.PackageInfoHidden;\nimport android.os.Build;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport java.util.Optional;\n\nimport dev.rikka.tools.refine.Refine;\nimport io.github.muntashirakon.AppManager.utils.ExUtils;\n\npublic class PackageInfoCompat2 {\n    @Nullable\n    public static String getOverlayTarget(@NonNull PackageInfo packageInfo) {\n        return Refine.<PackageInfoHidden>unsafeCast(packageInfo).overlayTarget;\n    }\n\n    @Nullable\n    public static String getTargetOverlayableName(@NonNull PackageInfo packageInfo) {\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {\n            return Refine.<PackageInfoHidden>unsafeCast(packageInfo).targetOverlayableName;\n        }\n        return null;\n    }\n\n    @Nullable\n    public static String getOverlayCategory(@NonNull PackageInfo packageInfo) {\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {\n            return Refine.<PackageInfoHidden>unsafeCast(packageInfo).overlayCategory;\n        }\n        return null;\n    }\n\n    public static int getOverlayPriority(@NonNull PackageInfo packageInfo) {\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {\n            return Refine.<PackageInfoHidden>unsafeCast(packageInfo).overlayPriority;\n        }\n        return 0; // MAX priority\n    }\n\n    public static boolean isStaticOverlayPackage(@NonNull PackageInfo packageInfo) {\n        PackageInfoHidden info = Refine.unsafeCast(packageInfo);\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {\n            return info.isStaticOverlayPackage();\n        }\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {\n            return Optional.ofNullable(ExUtils.exceptionAsNull(() -> info.isStaticOverlay))\n                    .orElse((info.overlayFlags & PackageInfoHidden.FLAG_OVERLAY_STATIC) != 0);\n        }\n        // Static is by default\n        return true;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/compat/PackageManagerCompat.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.compat;\n\nimport static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;\nimport static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED;\nimport static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED;\nimport static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER;\nimport static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;\nimport static android.content.pm.PackageManager.DONT_KILL_APP;\nimport static android.content.pm.PackageManager.SYNCHRONOUS;\n\nimport android.Manifest;\nimport android.annotation.SuppressLint;\nimport android.annotation.UserIdInt;\nimport android.content.ComponentName;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.pm.ActivityInfo;\nimport android.content.pm.ApplicationInfo;\nimport android.content.pm.IPackageInstaller;\nimport android.content.pm.IPackageManager;\nimport android.content.pm.IPackageManagerN;\nimport android.content.pm.LauncherActivityInfo;\nimport android.content.pm.LauncherApps;\nimport android.content.pm.PackageInfo;\nimport android.content.pm.PackageManager;\nimport android.content.pm.ParceledListSlice;\nimport android.content.pm.PermissionInfo;\nimport android.content.pm.ProviderInfo;\nimport android.content.pm.ResolveInfo;\nimport android.content.pm.ServiceInfo;\nimport android.content.pm.SuspendDialogInfo;\nimport android.os.BadParcelableException;\nimport android.os.Build;\nimport android.os.DeadObjectException;\nimport android.os.RemoteException;\nimport android.os.SystemClock;\nimport android.os.UserHandle;\nimport android.os.UserHandleHidden;\nimport android.util.AndroidException;\n\nimport androidx.annotation.IntDef;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.RequiresApi;\nimport androidx.annotation.RequiresPermission;\nimport androidx.annotation.WorkerThread;\n\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Objects;\nimport java.util.Set;\n\nimport dev.rikka.tools.refine.Refine;\nimport io.github.muntashirakon.AppManager.ipc.ProxyBinder;\nimport io.github.muntashirakon.AppManager.logs.Log;\nimport io.github.muntashirakon.AppManager.self.SelfPermissions;\nimport io.github.muntashirakon.AppManager.types.UserPackagePair;\nimport io.github.muntashirakon.AppManager.users.Users;\nimport io.github.muntashirakon.AppManager.utils.BroadcastUtils;\nimport io.github.muntashirakon.AppManager.utils.ContextUtils;\nimport io.github.muntashirakon.AppManager.utils.ExUtils;\nimport io.github.muntashirakon.AppManager.utils.ThreadUtils;\nimport io.github.muntashirakon.AppManager.utils.Utils;\n\npublic final class PackageManagerCompat {\n    public static final String TAG = PackageManagerCompat.class.getSimpleName();\n\n    public static final int MATCH_STATIC_SHARED_AND_SDK_LIBRARIES = 0x04000000;\n    public static final int GET_SIGNING_CERTIFICATES;\n    public static final int GET_SIGNING_CERTIFICATES_APK;\n    public static final int MATCH_DISABLED_COMPONENTS;\n    public static final int MATCH_UNINSTALLED_PACKAGES;\n\n    static {\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {\n            GET_SIGNING_CERTIFICATES = PackageManager.GET_SIGNING_CERTIFICATES;\n        } else {\n            //noinspection deprecation\n            GET_SIGNING_CERTIFICATES = PackageManager.GET_SIGNATURES;\n        }\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {\n            GET_SIGNING_CERTIFICATES_APK = PackageManager.GET_SIGNING_CERTIFICATES;\n        } else {\n            //noinspection deprecation\n            GET_SIGNING_CERTIFICATES_APK = PackageManager.GET_SIGNATURES;\n        }\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {\n            MATCH_DISABLED_COMPONENTS = PackageManager.MATCH_DISABLED_COMPONENTS;\n            MATCH_UNINSTALLED_PACKAGES = PackageManager.MATCH_UNINSTALLED_PACKAGES;\n        } else {\n            //noinspection deprecation\n            MATCH_DISABLED_COMPONENTS = PackageManager.GET_DISABLED_COMPONENTS;\n            //noinspection deprecation\n            MATCH_UNINSTALLED_PACKAGES = PackageManager.GET_UNINSTALLED_PACKAGES;\n        }\n    }\n\n    @IntDef({\n            COMPONENT_ENABLED_STATE_DEFAULT,\n            COMPONENT_ENABLED_STATE_ENABLED,\n            COMPONENT_ENABLED_STATE_DISABLED,\n            COMPONENT_ENABLED_STATE_DISABLED_USER,\n            COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED,\n    })\n    @Retention(RetentionPolicy.SOURCE)\n    public @interface EnabledState {\n    }\n\n    @IntDef(flag = true, value = {\n            DONT_KILL_APP,\n            SYNCHRONOUS\n    })\n    @Retention(RetentionPolicy.SOURCE)\n    public @interface EnabledFlags {\n    }\n\n    private static final int NEEDED_FLAGS = MATCH_UNINSTALLED_PACKAGES | MATCH_STATIC_SHARED_AND_SDK_LIBRARIES;\n\n    @WorkerThread\n    @NonNull\n    public static List<PackageInfo> getInstalledPackages(int flags, @UserIdInt int userId) {\n        IPackageManager pm = getPackageManager();\n        // Here we've compromised performance to fix issues in some devices where Binder transaction limit is too small.\n        List<PackageInfo> refPackages = getInstalledPackagesInternal(pm, flags & NEEDED_FLAGS, userId);\n        List<PackageInfo> packageInfoList = getInstalledPackagesInternal(pm, flags, userId);\n        if (packageInfoList.size() == refPackages.size()) {\n            // Everything's loaded correctly\n            return packageInfoList;\n        }\n        if (packageInfoList.size() > refPackages.size()) {\n            // Should never happen\n            Set<String> pkgsFromPkgInfo = new HashSet<>(packageInfoList.size());\n            Set<String> pkgsFromAppInfo = new HashSet<>(refPackages.size());\n            for (PackageInfo info : packageInfoList) pkgsFromPkgInfo.add(info.packageName);\n            for (PackageInfo info : refPackages) pkgsFromAppInfo.add(info.packageName);\n            pkgsFromPkgInfo.removeAll(pkgsFromAppInfo);\n            Log.i(TAG, \"Loaded extra packages: \" + pkgsFromPkgInfo.toString());\n            throw new IllegalStateException(\"Retrieved \" + packageInfoList.size() + \" packages out of \"\n                    + refPackages.size() + \" applications which is impossible\");\n        }\n        Log.w(TAG, \"Could not fetch installed packages for user %d using getInstalledPackages(), using workaround\",\n                userId);\n        packageInfoList = new ArrayList<>(refPackages.size());\n        for (int i = 0; i < refPackages.size(); ++i) {\n            if (ThreadUtils.isInterrupted()) {\n                break;\n            }\n            String packageName = refPackages.get(i).packageName;\n            try {\n                packageInfoList.add(getPackageInfo(pm, packageName, flags, userId));\n            } catch (Exception ex) {\n                Log.e(TAG, \"Could not retrieve package info for \" + packageName + \" and user \" + userId);\n                continue;\n            }\n            if (i % 100 == 0) {\n                // Prevent DeadObjectException\n                SystemClock.sleep(300);\n            }\n        }\n        return packageInfoList;\n    }\n\n    @SuppressWarnings(\"deprecation\")\n    private static List<PackageInfo> getInstalledPackagesInternal(@NonNull IPackageManager pm,\n                                                                  int flags,\n                                                                  @UserIdInt int userId) {\n        try {\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {\n                return pm.getInstalledPackages((long) flags, userId).getList();\n            }\n            return pm.getInstalledPackages(flags, userId).getList();\n        } catch (RemoteException e) {\n            return ExUtils.rethrowFromSystemServer(e);\n        } catch (BadParcelableException e) {\n            Log.w(TAG, \"Could not retrieve all packages for user \" + userId, e);\n            return Collections.emptyList();\n        }\n    }\n\n    @WorkerThread\n    public static List<ApplicationInfo> getInstalledApplications(int flags, @UserIdInt int userId)\n            throws RemoteException {\n        return getInstalledApplications(getPackageManager(), flags, userId);\n    }\n\n    @SuppressLint(\"NewApi\")\n    @SuppressWarnings(\"deprecation\")\n    @WorkerThread\n    public static List<ApplicationInfo> getInstalledApplications(@NonNull IPackageManager pm, int flags,\n                                                                 @UserIdInt int userId) throws RemoteException {\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {\n            return pm.getInstalledApplications((long) flags, userId).getList();\n        }\n        return pm.getInstalledApplications(flags, userId).getList();\n    }\n\n    @NonNull\n    public static PackageInfo getPackageInfo(@NonNull String packageName, int flags, @UserIdInt int userId)\n            throws RemoteException, PackageManager.NameNotFoundException {\n        return getPackageInfo(getPackageManager(), packageName, flags, userId);\n    }\n\n    @NonNull\n    private static PackageInfo getPackageInfo(@NonNull IPackageManager pm, @NonNull String packageName, int flags,\n                                             @UserIdInt int userId)\n            throws RemoteException, PackageManager.NameNotFoundException {\n        PackageInfo info = null;\n        try {\n            info = getPackageInfoInternal(pm, packageName, flags, userId);\n        } catch (DeadObjectException e) {\n            Log.w(TAG, \"Could not fetch info for package %s and user %d with flags 0x%X, using workaround\",\n                    e, packageName, userId, flags);\n        }\n        if (info == null) {\n            // The app might not be loaded properly due parcel size limit, try to load components separately.\n            // first check the existence of the package\n            int strippedFlags = flags & ~(PackageManager.GET_ACTIVITIES | PackageManager.GET_SERVICES\n                    | PackageManager.GET_PROVIDERS | PackageManager.GET_RECEIVERS | PackageManager.GET_PERMISSIONS);\n            info = getPackageInfoInternal(pm, packageName, strippedFlags, userId);\n            if (info == null) {\n                // At this point, it should return package info.\n                // Returning null denotes that it failed again even after the major flags have been stripped.\n                throw new PackageManager.NameNotFoundException(String.format(\"Could not retrieve info for package %s with flags 0x%X for user %d\",\n                        packageName, strippedFlags, userId));\n            }\n            // Load info for major flags\n            ActivityInfo[] activities = null;\n            if ((flags & PackageManager.GET_ACTIVITIES) != 0) {\n                int newFlags = flags & ~(PackageManager.GET_SERVICES | PackageManager.GET_PROVIDERS\n                        | PackageManager.GET_RECEIVERS | PackageManager.GET_PERMISSIONS);\n                PackageInfo info1 = getPackageInfoInternal(pm, packageName, newFlags, userId);\n                if (info1 != null) activities = info1.activities;\n            }\n            ServiceInfo[] services = null;\n            if ((flags & PackageManager.GET_SERVICES) != 0) {\n                int newFlags = flags & ~(PackageManager.GET_ACTIVITIES | PackageManager.GET_PROVIDERS\n                        | PackageManager.GET_RECEIVERS | PackageManager.GET_PERMISSIONS);\n                PackageInfo info1 = getPackageInfoInternal(pm, packageName, newFlags, userId);\n                if (info1 != null) services = info1.services;\n            }\n            ProviderInfo[] providers = null;\n            if ((flags & PackageManager.GET_PROVIDERS) != 0) {\n                int newFlags = flags & ~(PackageManager.GET_ACTIVITIES | PackageManager.GET_SERVICES\n                        | PackageManager.GET_RECEIVERS | PackageManager.GET_PERMISSIONS);\n                PackageInfo info1 = getPackageInfoInternal(pm, packageName, newFlags, userId);\n                if (info1 != null) providers = info1.providers;\n            }\n            ActivityInfo[] receivers = null;\n            if ((flags & PackageManager.GET_RECEIVERS) != 0) {\n                int newFlags = flags & ~(PackageManager.GET_ACTIVITIES | PackageManager.GET_SERVICES\n                        | PackageManager.GET_PROVIDERS | PackageManager.GET_PERMISSIONS);\n                PackageInfo info1 = getPackageInfoInternal(pm, packageName, newFlags, userId);\n                if (info1 != null) receivers = info1.receivers;\n            }\n            PermissionInfo[] permissions = null;\n            if ((flags & PackageManager.GET_PERMISSIONS) != 0) {\n                int newFlags = flags & ~(PackageManager.GET_ACTIVITIES | PackageManager.GET_SERVICES\n                        | PackageManager.GET_PROVIDERS | PackageManager.GET_RECEIVERS);\n                PackageInfo info1 = getPackageInfoInternal(pm, packageName, newFlags, userId);\n                if (info1 != null) permissions = info1.permissions;\n            }\n            info.activities = activities;\n            info.services = services;\n            info.providers = providers;\n            info.receivers = receivers;\n            info.permissions = permissions;\n        }\n        // Info should never be null here, but it's checked anyway.\n        return Objects.requireNonNull(info);\n    }\n\n    @SuppressWarnings(\"deprecation\")\n    @NonNull\n    public static ApplicationInfo getApplicationInfo(String packageName, int flags, @UserIdInt int userId)\n            throws RemoteException, PackageManager.NameNotFoundException {\n        IPackageManager pm = getPackageManager();\n        ApplicationInfo applicationInfo;\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {\n            applicationInfo = pm.getApplicationInfo(packageName, (long) flags, userId);\n        } else applicationInfo = pm.getApplicationInfo(packageName, flags, userId);\n        if (applicationInfo == null) {\n            throw new PackageManager.NameNotFoundException(\"Package \" + packageName + \" not found.\");\n        }\n        return applicationInfo;\n    }\n\n    @Nullable\n    public static String getInstallerPackageName(@NonNull String packageName, @UserIdInt int userId) {\n        try {\n            InstallSourceInfoCompat installSource = getInstallSourceInfo(packageName, userId);\n            if (installSource.getInstallingPackageName() != null) {\n                return installSource.getInstallingPackageName();\n            }\n            return installSource.getInitiatingPackageName();\n        } catch (RemoteException | SecurityException e) {\n            return null;\n        }\n    }\n\n    @SuppressWarnings(\"deprecation\")\n    @NonNull\n    public static InstallSourceInfoCompat getInstallSourceInfo(@NonNull String packageName, @UserIdInt int userId)\n            throws RemoteException {\n        IPackageManager pm = getPackageManager();\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {\n            return new InstallSourceInfoCompat(pm.getInstallSourceInfo(packageName, userId));\n        }\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {\n            return new InstallSourceInfoCompat(pm.getInstallSourceInfo(packageName));\n        }\n        String installerPackageName = null;\n        try {\n            installerPackageName = getPackageManager().getInstallerPackageName(packageName);\n        } catch (IllegalArgumentException e) {\n            String message = e.getMessage();\n            if (message != null && message.startsWith(\"Unknown package:\")) {\n                throw new RemoteException(message);\n            }\n        }\n        return new InstallSourceInfoCompat(installerPackageName);\n    }\n\n    @Nullable\n    public static Intent getLaunchIntentForPackage(@NonNull String packageName, @UserIdInt int userId) {\n        Context context = ContextUtils.getContext();\n        if (userId == UserHandleHidden.myUserId()) {\n            PackageManager pm = context.getPackageManager();\n            return Utils.isTv(context)\n                    ? pm.getLeanbackLaunchIntentForPackage(packageName)\n                    : pm.getLaunchIntentForPackage(packageName);\n        }\n        UserHandle userHandle = Users.getUserHandle(userId);\n        if (userHandle == null) {\n            // No supported user present\n            return null;\n        }\n        LauncherApps launcherApps = (LauncherApps) context.getSystemService(Context.LAUNCHER_APPS_SERVICE);\n        try {\n            if (!launcherApps.isPackageEnabled(packageName, userHandle)) {\n                // Package not enabled\n                return null;\n            }\n        } catch (SecurityException e) {\n            Log.w(TAG, \"Could not retrieve enable state of \" + packageName + \" for user \"  + userHandle, e);\n            return null;\n        }\n        List<LauncherActivityInfo> activityInfoList = launcherApps.getActivityList(packageName, userHandle);\n        if (activityInfoList.isEmpty()) {\n            // No activities\n            return null;\n        }\n        // Return the first openable activity\n        LauncherActivityInfo info = activityInfoList.get(0);\n        return new Intent(Intent.ACTION_MAIN)\n                .addCategory(Intent.CATEGORY_LAUNCHER)\n                .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED)\n                .setComponent(info.getComponentName());\n    }\n\n    @SuppressLint(\"NewApi\")\n    @SuppressWarnings(\"deprecation\")\n    @NonNull\n    public static List<ResolveInfo> queryIntentActivities(@NonNull Context context, @NonNull Intent intent, int flags,\n                                                          @UserIdInt int userId)\n            throws RemoteException {\n        IPackageManager pm = getPackageManager();\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {\n            IPackageManagerN pmN = Refine.unsafeCast(pm);\n            ParceledListSlice<ResolveInfo> resolveInfoList;\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {\n                resolveInfoList = pmN.queryIntentActivities(intent,\n                        intent.resolveTypeIfNeeded(context.getContentResolver()), (long) flags, userId);\n            } else {\n                resolveInfoList = pmN.queryIntentActivities(intent,\n                        intent.resolveTypeIfNeeded(context.getContentResolver()), flags, userId);\n            }\n            return resolveInfoList.getList();\n        } else {\n            return pm.queryIntentActivities(intent, intent.resolveTypeIfNeeded(context.getContentResolver()), flags,\n                    userId);\n        }\n    }\n\n    @EnabledState\n    public static int getComponentEnabledSetting(ComponentName componentName, @UserIdInt int userId)\n            throws SecurityException, IllegalArgumentException {\n        try {\n            return getPackageManager().getComponentEnabledSetting(componentName, userId);\n        } catch (RemoteException e) {\n            return ExUtils.rethrowFromSystemServer(e);\n        }\n    }\n\n    @SuppressWarnings(\"deprecation\")\n    @RequiresPermission(value = Manifest.permission.CHANGE_COMPONENT_ENABLED_STATE)\n    public static void setComponentEnabledSetting(ComponentName componentName,\n                                                  @EnabledState int newState,\n                                                  @EnabledFlags int flags,\n                                                  @UserIdInt int userId)\n            throws RemoteException {\n        IPackageManager pm = getPackageManager();\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {\n            String callingPackage = SelfPermissions.getCallingPackage(Users.getSelfOrRemoteUid());\n            pm.setComponentEnabledSetting(componentName, newState, flags, userId, callingPackage);\n        } else pm.setComponentEnabledSetting(componentName, newState, flags, userId);\n        if (userId != UserHandleHidden.myUserId()) {\n            BroadcastUtils.sendPackageAltered(ContextUtils.getContext(), new String[]{componentName.getPackageName()});\n        }\n    }\n\n    @RequiresPermission(value = Manifest.permission.CHANGE_COMPONENT_ENABLED_STATE)\n    public static void setApplicationEnabledSetting(String packageName, @EnabledState int newState,\n                                                    @EnabledFlags int flags, @UserIdInt int userId)\n            throws SecurityException, IllegalArgumentException {\n        try {\n            getPackageManager().setApplicationEnabledSetting(packageName, newState, flags, userId, null);\n            if (userId != UserHandleHidden.myUserId()) {\n                BroadcastUtils.sendPackageAltered(ContextUtils.getContext(), new String[]{packageName});\n            }\n        } catch (RemoteException e) {\n            ExUtils.rethrowFromSystemServer(e);\n        }\n    }\n\n    public static int getApplicationEnabledSetting(String packageName, @UserIdInt int userId)\n            throws SecurityException, IllegalArgumentException {\n        try {\n            return getPackageManager().getApplicationEnabledSetting(packageName, userId);\n        } catch (RemoteException e) {\n            return ExUtils.rethrowFromSystemServer(e);\n        }\n    }\n\n    @SuppressWarnings(\"deprecation\")\n    @RequiresApi(Build.VERSION_CODES.N)\n    @RequiresPermission(allOf = {\"android.permission.SUSPEND_APPS\", ManifestCompat.permission.MANAGE_USERS})\n    public static void suspendPackages(String[] packageNames, @UserIdInt int userId, boolean suspend) throws RemoteException {\n        String callingPackage = SelfPermissions.getCallingPackage(Users.getSelfOrRemoteUid());\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {\n            try {\n                getPackageManager().setPackagesSuspendedAsUser(packageNames, suspend, null, null, null, 0, callingPackage, 0, userId);\n            } catch (NoSuchMethodError e) {\n                getPackageManager().setPackagesSuspendedAsUser(packageNames, suspend, null, null, (SuspendDialogInfo) null, callingPackage, userId);\n            }\n        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {\n            getPackageManager().setPackagesSuspendedAsUser(packageNames, suspend, null, null, (SuspendDialogInfo) null, callingPackage, userId);\n        } else if (Build.VERSION.SDK_INT == Build.VERSION_CODES.P) {\n            getPackageManager().setPackagesSuspendedAsUser(packageNames, suspend, null, null, (String) null, callingPackage, userId);\n        } else {\n            getPackageManager().setPackagesSuspendedAsUser(packageNames, suspend, userId);\n        }\n        if (userId != UserHandleHidden.myUserId()) {\n            BroadcastUtils.sendPackageAltered(ContextUtils.getContext(), packageNames);\n        }\n    }\n\n    public static boolean isPackageSuspended(String packageName, @UserIdInt int userId) throws RemoteException {\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {\n            return getPackageManager().isPackageSuspendedForUser(packageName, userId);\n        }\n        return false;\n    }\n\n    @RequiresPermission(ManifestCompat.permission.MANAGE_USERS)\n    public static void hidePackage(String packageName, @UserIdInt int userId, boolean hide) throws RemoteException {\n        if (SelfPermissions.checkSelfOrRemotePermission(ManifestCompat.permission.MANAGE_USERS)) {\n            boolean hidden = getPackageManager().setApplicationHiddenSettingAsUser(packageName, hide, userId);\n            if (userId != UserHandleHidden.myUserId()) {\n                if (hidden) {\n                    if (hide) {\n                        BroadcastUtils.sendPackageRemoved(ContextUtils.getContext(), new String[]{packageName});\n                    } else {\n                        BroadcastUtils.sendPackageAdded(ContextUtils.getContext(), new String[]{packageName});\n                    }\n                }\n            }\n        } else {\n            throw new RemoteException(\"Missing required permission: android.permission.MANAGE_USERS.\");\n        }\n    }\n\n    public static boolean isPackageHidden(String packageName, @UserIdInt int userId) throws RemoteException {\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {\n            try {\n                // Find using private flags\n                ApplicationInfo info = getApplicationInfo(packageName,\n                        PackageManagerCompat.MATCH_STATIC_SHARED_AND_SDK_LIBRARIES, userId);\n                return ApplicationInfoCompat.isHidden(info);\n            } catch (PackageManager.NameNotFoundException ignore) {\n            }\n        }\n        if (SelfPermissions.checkSelfOrRemotePermission(ManifestCompat.permission.MANAGE_USERS)) {\n            return getPackageManager().getApplicationHiddenSettingAsUser(packageName, userId);\n        }\n        // Otherwise, there is no way to detect if the package is hidden\n        return false;\n    }\n\n    @SuppressWarnings(\"deprecation\")\n    @RequiresPermission(anyOf = {\n            Manifest.permission.INSTALL_PACKAGES,\n            \"com.android.permission.INSTALL_EXISTING_PACKAGES\"\n    })\n    public static int installExistingPackageAsUser(@NonNull String packageName, @UserIdInt int userId, int installFlags,\n                                                   int installReason, @Nullable List<String> whiteListedPermissions)\n            throws RemoteException {\n        int returnCode;\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {\n            returnCode = getPackageManager().installExistingPackageAsUser(packageName, userId, installFlags, installReason, whiteListedPermissions);\n        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {\n            returnCode = getPackageManager().installExistingPackageAsUser(packageName, userId, installFlags, installReason);\n        } else returnCode = getPackageManager().installExistingPackageAsUser(packageName, userId);\n        if (userId != UserHandleHidden.myUserId()) {\n            BroadcastUtils.sendPackageAdded(ContextUtils.getContext(), new String[]{packageName});\n        }\n        return returnCode;\n    }\n\n    @RequiresPermission(ManifestCompat.permission.CLEAR_APP_USER_DATA)\n    public static void clearApplicationUserData(@NonNull UserPackagePair pair) throws AndroidException {\n        IPackageManager pm = getPackageManager();\n        ClearDataObserver obs = new ClearDataObserver();\n        pm.clearApplicationUserData(pair.getPackageName(), obs, pair.getUserId());\n        //noinspection SynchronizationOnLocalVariableOrMethodParameter\n        synchronized (obs) {\n            while (!obs.isCompleted()) {\n                try {\n                    obs.wait(500);\n                } catch (InterruptedException ignore) {\n                }\n            }\n        }\n        if (!obs.isSuccessful()) {\n            throw new AndroidException(\"Could not clear data of package \" + pair);\n        }\n        BroadcastUtils.sendPackageAltered(ContextUtils.getContext(), new String[]{pair.getPackageName()});\n    }\n\n    @RequiresPermission(ManifestCompat.permission.CLEAR_APP_USER_DATA)\n    public static boolean clearApplicationUserData(@NonNull String packageName, @UserIdInt int userId) {\n        try {\n            clearApplicationUserData(new UserPackagePair(packageName, userId));\n            return true;\n        } catch (AndroidException | SecurityException e) {\n            e.printStackTrace();\n            return false;\n        }\n    }\n\n    @RequiresPermission(allOf = {\n            Manifest.permission.DELETE_CACHE_FILES,\n            \"android.permission.INTERNAL_DELETE_CACHE_FILES\"\n    })\n    public static void deleteApplicationCacheFilesAsUser(UserPackagePair pair) throws AndroidException {\n        IPackageManager pm = getPackageManager();\n        ClearDataObserver obs = new ClearDataObserver();\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {\n            pm.deleteApplicationCacheFilesAsUser(pair.getPackageName(), pair.getUserId(), obs);\n        } else pm.deleteApplicationCacheFiles(pair.getPackageName(), obs);\n        //noinspection SynchronizationOnLocalVariableOrMethodParameter\n        synchronized (obs) {\n            while (!obs.isCompleted()) {\n                try {\n                    obs.wait(500);\n                } catch (InterruptedException ignore) {\n                }\n            }\n        }\n        if (!obs.isSuccessful()) {\n            throw new AndroidException(\"Could not clear cache of package \" + pair);\n        }\n        BroadcastUtils.sendPackageAltered(ContextUtils.getContext(), new String[]{pair.getPackageName()});\n    }\n\n    @RequiresPermission(allOf = {\n            Manifest.permission.DELETE_CACHE_FILES,\n            \"android.permission.INTERNAL_DELETE_CACHE_FILES\"\n    })\n    public static boolean deleteApplicationCacheFilesAsUser(String packageName, int userId) {\n        try {\n            deleteApplicationCacheFilesAsUser(new UserPackagePair(packageName, userId));\n            return true;\n        } catch (AndroidException | SecurityException e) {\n            e.printStackTrace();\n            return false;\n        }\n    }\n\n    @RequiresPermission(ManifestCompat.permission.FORCE_STOP_PACKAGES)\n    public static void forceStopPackage(String packageName, int userId) throws SecurityException {\n        try {\n            ActivityManagerCompat.getActivityManager().forceStopPackage(packageName, userId);\n            BroadcastUtils.sendPackageAltered(ContextUtils.getContext(), new String[]{packageName});\n        } catch (RemoteException e) {\n            ExUtils.rethrowFromSystemServer(e);\n        }\n    }\n\n    @NonNull\n    public static IPackageInstaller getPackageInstaller() throws RemoteException {\n        return IPackageInstaller.Stub.asInterface(new ProxyBinder(getPackageManager().getPackageInstaller().asBinder()));\n    }\n\n    @SuppressWarnings(\"deprecation\")\n    @RequiresPermission(Manifest.permission.CLEAR_APP_CACHE)\n    public static void freeStorageAndNotify(@Nullable String volumeUuid,\n                                            long freeStorageSize,\n                                            @StorageManagerCompat.AllocateFlags int storageFlags)\n            throws RemoteException {\n        IPackageManager pm;\n        ClearDataObserver obs = new ClearDataObserver();\n        if (SelfPermissions.checkSelfPermission(Manifest.permission.CLEAR_APP_CACHE)) {\n            // Clear cache using unprivileged method: Special case for Android Lollipop\n            pm = getUnprivilegedPackageManager();\n        } else if (SelfPermissions.checkSelfOrRemotePermission(Manifest.permission.CLEAR_APP_CACHE)) { // Use privileged mode\n            pm = getPackageManager();\n        } else { // Clear one by one\n            // Special case: IPackageManager#freeStorageAndNotify cannot be used before Android Oreo because Shell does\n            // not have the permission android.permission.CLEAR_APP_CACHE\n            boolean hasPermission;\n            if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.P) {\n                hasPermission = SelfPermissions.checkSelfOrRemotePermission(ManifestCompat.permission.INTERNAL_DELETE_CACHE_FILES);\n            } else {\n                hasPermission = SelfPermissions.checkSelfOrRemotePermission(Manifest.permission.DELETE_CACHE_FILES);\n            }\n            if (!hasPermission) {\n                // Does not have enough permission\n                return;\n            }\n            if (!SelfPermissions.checkSelfOrRemotePermission(ManifestCompat.permission.INTERACT_ACROSS_USERS_FULL)) {\n                int userId = UserHandleHidden.myUserId();\n                for (ApplicationInfo info : getInstalledApplications(MATCH_STATIC_SHARED_AND_SDK_LIBRARIES, userId)) {\n                    deleteApplicationCacheFilesAsUser(info.packageName, userId);\n                }\n                return;\n            }\n            for (int userId : Users.getUsersIds()) {\n                for (ApplicationInfo info : getInstalledApplications(MATCH_STATIC_SHARED_AND_SDK_LIBRARIES, userId)) {\n                    deleteApplicationCacheFilesAsUser(info.packageName, userId);\n                }\n            }\n            return;\n        }\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {\n            pm.freeStorageAndNotify(volumeUuid, freeStorageSize, storageFlags, obs);\n        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {\n            pm.freeStorageAndNotify(volumeUuid, freeStorageSize, obs);\n        } else {\n            pm.freeStorageAndNotify(freeStorageSize, obs);\n        }\n        //noinspection SynchronizationOnLocalVariableOrMethodParameter\n        synchronized (obs) {\n            while (!obs.isCompleted()) {\n                try {\n                    obs.wait(1_000);\n                } catch (InterruptedException ignore) {\n                }\n            }\n        }\n    }\n\n    @SuppressLint(\"NewApi\")\n    @SuppressWarnings(\"deprecation\")\n    private static PackageInfo getPackageInfoInternal(IPackageManager pm, String packageName, int flags, @UserIdInt int userId)\n            throws RemoteException {\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {\n            return pm.getPackageInfo(packageName, (long) flags, userId);\n        }\n        return pm.getPackageInfo(packageName, flags, userId);\n    }\n\n    public static IPackageManager getPackageManager() {\n        return IPackageManager.Stub.asInterface(ProxyBinder.getService(\"package\"));\n    }\n\n    public static IPackageManager getUnprivilegedPackageManager() {\n        return IPackageManager.Stub.asInterface(ProxyBinder.getUnprivilegedService(\"package\"));\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/compat/PermissionCompat.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.compat;\n\nimport static io.github.muntashirakon.AppManager.compat.VirtualDeviceManagerCompat.PERSISTENT_DEVICE_ID_DEFAULT;\n\nimport android.annotation.SuppressLint;\nimport android.annotation.UserIdInt;\nimport android.content.pm.ApplicationInfo;\nimport android.content.pm.IPackageManager;\nimport android.content.pm.IPackageManagerN;\nimport android.content.pm.PermissionGroupInfo;\nimport android.content.pm.PermissionInfo;\nimport android.content.pm.permission.SplitPermissionInfoParcelable;\nimport android.os.Build;\nimport android.os.RemoteException;\nimport android.permission.IPermissionManager;\nimport android.util.SparseArray;\n\nimport androidx.annotation.IntDef;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.RequiresApi;\nimport androidx.annotation.RequiresPermission;\n\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.util.Collections;\nimport java.util.List;\n\nimport dev.rikka.tools.refine.Refine;\nimport io.github.muntashirakon.AppManager.ipc.ProxyBinder;\nimport io.github.muntashirakon.AppManager.utils.ContextUtils;\nimport io.github.muntashirakon.AppManager.utils.ExUtils;\n\npublic final class PermissionCompat {\n    public static final int FLAG_PERMISSION_NONE = 0;\n\n    /**\n     * Permission flag: The permission is set in its current state\n     * by the user and apps can still request it at runtime.\n     */\n    @RequiresApi(Build.VERSION_CODES.M)\n    public static final int FLAG_PERMISSION_USER_SET = 1;\n\n    /**\n     * Permission flag: The permission is set in its current state\n     * by the user and it is fixed, i.e. apps can no longer request\n     * this permission.\n     */\n    @RequiresApi(Build.VERSION_CODES.M)\n    public static final int FLAG_PERMISSION_USER_FIXED = 1 << 1;\n\n    /**\n     * Permission flag: The permission is set in its current state\n     * by device policy and neither apps nor the user can change\n     * its state.\n     */\n    @RequiresApi(Build.VERSION_CODES.M)\n    public static final int FLAG_PERMISSION_POLICY_FIXED = 1 << 2;\n\n    /**\n     * Permission flag: The permission is set in a granted state but\n     * access to resources it guards is restricted by other means to\n     * enable revoking a permission on legacy apps that do not support\n     * runtime permissions. If this permission is upgraded to runtime\n     * because the app was updated to support runtime permissions, the\n     * the permission will be revoked in the upgrade process.\n     *\n     * @deprecated Renamed to {@link #FLAG_PERMISSION_REVOKED_COMPAT}.\n     */\n    @Deprecated\n    @RequiresApi(Build.VERSION_CODES.M)\n    public static final int FLAG_PERMISSION_REVOKE_ON_UPGRADE = 1 << 3;\n\n    /**\n     * Permission flag: The permission is set in its current state\n     * because the app is a component that is a part of the system.\n     */\n    @RequiresApi(Build.VERSION_CODES.M)\n    public static final int FLAG_PERMISSION_SYSTEM_FIXED = 1 << 4;\n\n    /**\n     * Permission flag: The permission is granted by default because it\n     * enables app functionality that is expected to work out-of-the-box\n     * for providing a smooth user experience. For example, the phone app\n     * is expected to have the phone permission.\n     */\n    @RequiresApi(Build.VERSION_CODES.M)\n    public static final int FLAG_PERMISSION_GRANTED_BY_DEFAULT = 1 << 5;\n\n    /**\n     * Permission flag: The permission has to be reviewed before any of\n     * the app components can run.\n     */\n    @RequiresApi(Build.VERSION_CODES.N)\n    public static final int FLAG_PERMISSION_REVIEW_REQUIRED = 1 << 6;\n\n    /**\n     * Permission flag: The permission has not been explicitly requested by\n     * the app but has been added automatically by the system. Revoke once\n     * the app does explicitly request it.\n     */\n    @RequiresApi(Build.VERSION_CODES.Q)\n    public static final int FLAG_PERMISSION_REVOKE_WHEN_REQUESTED = 1 << 7;\n\n    /**\n     * Permission flag: The permission's usage should be made highly visible to the user\n     * when granted.\n     */\n    @RequiresApi(Build.VERSION_CODES.Q)\n    public static final int FLAG_PERMISSION_USER_SENSITIVE_WHEN_GRANTED = 1 << 8;\n\n    /**\n     * Permission flag: The permission's usage should be made highly visible to the user\n     * when denied.\n     */\n    @RequiresApi(Build.VERSION_CODES.Q)\n    public static final int FLAG_PERMISSION_USER_SENSITIVE_WHEN_DENIED = 1 << 9;\n\n    /**\n     * Permission flag: The permission is restricted but the app is exempt\n     * from the restriction and is allowed to hold this permission in its\n     * full form and the exemption is provided by the installer on record.\n     */\n    @RequiresApi(Build.VERSION_CODES.Q)\n    public static final int FLAG_PERMISSION_RESTRICTION_INSTALLER_EXEMPT = 1 << 11;\n\n    /**\n     * Permission flag: The permission is restricted but the app is exempt\n     * from the restriction and is allowed to hold this permission in its\n     * full form and the exemption is provided by the system due to its\n     * permission policy.\n     */\n    @RequiresApi(Build.VERSION_CODES.Q)\n    public static final int FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT = 1 << 12;\n\n    /**\n     * Permission flag: The permission is restricted but the app is exempt\n     * from the restriction and is allowed to hold this permission and the\n     * exemption is provided by the system when upgrading from an OS version\n     * where the permission was not restricted to an OS version where the\n     * permission is restricted.\n     */\n    @RequiresApi(Build.VERSION_CODES.Q)\n    public static final int FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT = 1 << 13;\n\n\n    /**\n     * Permission flag: The permission is disabled but may be granted. If\n     * disabled the data protected by the permission should be protected\n     * by a no-op (empty list, default error, etc) instead of crashing the\n     * client.\n     */\n    @RequiresApi(Build.VERSION_CODES.Q)\n    public static final int FLAG_PERMISSION_APPLY_RESTRICTION = 1 << 14;\n\n    /**\n     * Permission flag: The permission is granted because the application holds a role.\n     */\n    @RequiresApi(Build.VERSION_CODES.Q)\n    public static final int FLAG_PERMISSION_GRANTED_BY_ROLE = 1 << 15;\n\n    /**\n     * Permission flag: The permission should have been revoked but is kept granted for\n     * compatibility. The data protected by the permission should be protected by a no-op (empty\n     * list, default error, etc) instead of crashing the client. The permission will be revoked if\n     * the app is upgraded to supports it.\n     */\n    @RequiresApi(Build.VERSION_CODES.R)\n    public static final int FLAG_PERMISSION_REVOKED_COMPAT = FLAG_PERMISSION_REVOKE_ON_UPGRADE;\n\n    /**\n     * Permission flag: The permission is one-time and should be revoked automatically on app\n     * inactivity\n     */\n    @RequiresApi(Build.VERSION_CODES.R)\n    public static final int FLAG_PERMISSION_ONE_TIME = 1 << 16;\n\n    /**\n     * Permission flag: Whether permission was revoked by auto-revoke.\n     */\n    @RequiresApi(Build.VERSION_CODES.R)\n    public static final int FLAG_PERMISSION_AUTO_REVOKED = 1 << 17;\n\n    /**\n     * Permission flags: Reserved for use by the permission controller. The platform and any\n     * packages besides the permission controller should not assume any definition about these\n     * flags.\n     */\n    @RequiresApi(Build.VERSION_CODES.R)\n    public static final int FLAGS_PERMISSION_RESERVED_PERMISSION_CONTROLLER = 1 << 28 | 1 << 29\n            | 1 << 30 | 1 << 31;\n\n    /**\n     * Permission flags: Bitwise or of all permission flags allowing an\n     * exemption for a restricted permission.\n     */\n    @RequiresApi(Build.VERSION_CODES.Q)\n    public static final int FLAGS_PERMISSION_RESTRICTION_ANY_EXEMPT = FLAG_PERMISSION_RESTRICTION_INSTALLER_EXEMPT\n            | FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT\n            | FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT;\n\n    /**\n     * Mask for all permission flags.\n     */\n    @PermissionFlags\n    public static final int MASK_PERMISSION_FLAGS_ALL;\n\n    static {\n        int allPerms = FLAG_PERMISSION_NONE;\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {\n            allPerms |= FLAG_PERMISSION_USER_SET\n                    | FLAG_PERMISSION_USER_FIXED\n                    | FLAG_PERMISSION_POLICY_FIXED\n                    | FLAG_PERMISSION_REVOKE_ON_UPGRADE\n                    | FLAG_PERMISSION_SYSTEM_FIXED\n                    | FLAG_PERMISSION_GRANTED_BY_DEFAULT;\n        }\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {\n            allPerms |= FLAG_PERMISSION_REVIEW_REQUIRED;\n        }\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {\n            allPerms |= FLAG_PERMISSION_REVOKE_WHEN_REQUESTED\n                    | FLAG_PERMISSION_USER_SENSITIVE_WHEN_GRANTED\n                    | FLAG_PERMISSION_USER_SENSITIVE_WHEN_DENIED\n                    | FLAG_PERMISSION_RESTRICTION_INSTALLER_EXEMPT\n                    | FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT\n                    | FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT\n                    | FLAG_PERMISSION_APPLY_RESTRICTION\n                    | FLAG_PERMISSION_GRANTED_BY_ROLE;\n        }\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {\n            allPerms |= FLAG_PERMISSION_REVOKED_COMPAT\n                    | FLAG_PERMISSION_ONE_TIME\n                    | FLAG_PERMISSION_AUTO_REVOKED;\n        }\n        MASK_PERMISSION_FLAGS_ALL = allPerms;\n    }\n\n    /**\n     * Permission flags set when granting or revoking a permission.\n     */\n    @SuppressLint(\"NewApi\")\n    @RequiresApi(Build.VERSION_CODES.M)\n    @IntDef(flag = true, value = {\n            FLAG_PERMISSION_NONE,\n            FLAG_PERMISSION_USER_SET,\n            FLAG_PERMISSION_USER_FIXED,\n            FLAG_PERMISSION_POLICY_FIXED,\n//            FLAG_PERMISSION_REVOKE_ON_UPGRADE,\n            FLAG_PERMISSION_SYSTEM_FIXED,\n            FLAG_PERMISSION_GRANTED_BY_DEFAULT,\n            FLAG_PERMISSION_REVIEW_REQUIRED,\n            FLAG_PERMISSION_USER_SENSITIVE_WHEN_GRANTED,\n            FLAG_PERMISSION_USER_SENSITIVE_WHEN_DENIED,\n            FLAG_PERMISSION_REVOKE_WHEN_REQUESTED,\n            FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT,\n            FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT,\n            FLAG_PERMISSION_RESTRICTION_INSTALLER_EXEMPT,\n            FLAG_PERMISSION_APPLY_RESTRICTION,\n            FLAG_PERMISSION_GRANTED_BY_ROLE,\n            FLAG_PERMISSION_REVOKED_COMPAT,\n            FLAG_PERMISSION_ONE_TIME,\n            FLAG_PERMISSION_AUTO_REVOKED\n    })\n    @Retention(RetentionPolicy.SOURCE)\n    public @interface PermissionFlags {\n    }\n\n    @SuppressWarnings(\"deprecation\")\n    @RequiresPermission(anyOf = {\n            ManifestCompat.permission.GET_RUNTIME_PERMISSIONS,\n            ManifestCompat.permission.GRANT_RUNTIME_PERMISSIONS,\n            ManifestCompat.permission.REVOKE_RUNTIME_PERMISSIONS,\n    })\n    @PermissionFlags\n    public static int getPermissionFlags(@NonNull String permissionName,\n                                         @NonNull String packageName,\n                                         @UserIdInt int userId) throws SecurityException {\n        try {\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {\n                IPermissionManager permissionManager = getPermissionManager();\n                try {\n                    return permissionManager.getPermissionFlags(packageName, permissionName, userId);\n                } catch (NoSuchMethodError e) {\n                    try {\n                        return permissionManager.getPermissionFlags(packageName, permissionName,\n                                ContextUtils.getContext().getDeviceId(), userId);\n                    } catch (NoSuchMethodError e2) {\n                        return permissionManager.getPermissionFlags(packageName, permissionName,\n                                PERSISTENT_DEVICE_ID_DEFAULT, userId);\n                    }\n                }\n            } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {\n                return getPermissionManager().getPermissionFlags(packageName, permissionName, userId);\n            } else if (Build.VERSION.SDK_INT == Build.VERSION_CODES.R) {\n                return getPermissionManager().getPermissionFlags(permissionName, packageName, userId);\n            } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {\n                return PackageManagerCompat.getPackageManager().getPermissionFlags(permissionName, packageName, userId);\n            }\n        } catch (RemoteException e) {\n            return ExUtils.rethrowFromSystemServer(e);\n        }\n        return FLAG_PERMISSION_NONE;\n    }\n\n    /**\n     * Replace a set of flags with another or {@code 0}. Requires {@link ManifestCompat.permission#ADJUST_RUNTIME_PERMISSIONS_POLICY}\n     * when checkAdjustPolicyFlagPermission is {@code true} and flagMask has {@link #FLAG_PERMISSION_POLICY_FIXED}.\n     *\n     * @param flagMask   The flags to be replaced\n     * @param flagValues The new flags to set (is a subset of flagMask)\n     * @see <a href=\"https://cs.android.com/android/platform/superproject/+/master:cts/tests/tests/permission/src/android/permission/cts/PermissionFlagsTest.java\">PermissionFlagsTest.java</a>\n     */\n    @SuppressWarnings(\"deprecation\")\n    @RequiresPermission(anyOf = {\n            ManifestCompat.permission.GET_RUNTIME_PERMISSIONS,\n            ManifestCompat.permission.GRANT_RUNTIME_PERMISSIONS,\n            ManifestCompat.permission.REVOKE_RUNTIME_PERMISSIONS,\n    })\n    public static void updatePermissionFlags(@NonNull String permissionName,\n                                             @NonNull String packageName,\n                                             @PermissionFlags int flagMask,\n                                             @PermissionFlags int flagValues,\n                                             boolean checkAdjustPolicyFlagPermission,\n                                             @UserIdInt int userId) throws RemoteException {\n        IPackageManager pm = PackageManagerCompat.getPackageManager();\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {\n            IPermissionManager permissionManager = getPermissionManager();\n            try {\n                permissionManager.updatePermissionFlags(packageName, permissionName, flagMask, flagValues,\n                        checkAdjustPolicyFlagPermission, userId);\n            } catch (NoSuchMethodError e) {\n                try {\n                    permissionManager.updatePermissionFlags(packageName, permissionName, flagMask, flagValues,\n                            checkAdjustPolicyFlagPermission, ContextUtils.getContext().getDeviceId(), userId);\n                } catch (NoSuchMethodError e2) {\n                    permissionManager.updatePermissionFlags(packageName, permissionName, flagMask, flagValues,\n                            checkAdjustPolicyFlagPermission, PERSISTENT_DEVICE_ID_DEFAULT, userId);\n                }\n            }\n        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {\n            getPermissionManager().updatePermissionFlags(packageName, permissionName, flagMask, flagValues,\n                    checkAdjustPolicyFlagPermission, userId);\n        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {\n            getPermissionManager().updatePermissionFlags(permissionName, packageName, flagMask, flagValues,\n                    checkAdjustPolicyFlagPermission, userId);\n        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {\n            pm.updatePermissionFlags(permissionName, packageName, flagMask, flagValues,\n                    checkAdjustPolicyFlagPermission, userId);\n        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {\n            pm.updatePermissionFlags(permissionName, packageName, flagMask, flagValues, userId);\n        }\n    }\n\n    /**\n     * Grant a permission. May also require {@link ManifestCompat.permission#ADJUST_RUNTIME_PERMISSIONS_POLICY}.\n     */\n    @SuppressWarnings(\"deprecation\")\n    @RequiresPermission(ManifestCompat.permission.GRANT_RUNTIME_PERMISSIONS)\n    public static void grantPermission(@NonNull String packageName,\n                                       @NonNull String permissionName,\n                                       @UserIdInt int userId)\n            throws RemoteException {\n        IPackageManager pm = PackageManagerCompat.getPackageManager();\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {\n            IPermissionManager permissionManager = getPermissionManager();\n            try {\n                permissionManager.grantRuntimePermission(packageName, permissionName, userId);\n            } catch (NoSuchMethodError e) {\n                try {\n                    permissionManager.grantRuntimePermission(packageName, permissionName,\n                            ContextUtils.getContext().getDeviceId(), userId);\n                } catch (NoSuchMethodError e2) {\n                    permissionManager.grantRuntimePermission(packageName, permissionName,\n                            PERSISTENT_DEVICE_ID_DEFAULT, userId);\n                }\n            }\n        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {\n            getPermissionManager().grantRuntimePermission(packageName, permissionName, userId);\n        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {\n            pm.grantRuntimePermission(packageName, permissionName, userId);\n        } else {\n            pm.grantPermission(packageName, permissionName);\n        }\n    }\n\n    /**\n     * Revoke a permission. May also require {@link ManifestCompat.permission#ADJUST_RUNTIME_PERMISSIONS_POLICY}.\n     */\n    @RequiresPermission(ManifestCompat.permission.REVOKE_RUNTIME_PERMISSIONS)\n    public static void revokePermission(@NonNull String packageName,\n                                        @NonNull String permissionName,\n                                        @UserIdInt int userId) throws RemoteException {\n        revokePermission(packageName, permissionName, userId, null);\n    }\n\n    /**\n     * Revoke a permission. May also require {@link ManifestCompat.permission#ADJUST_RUNTIME_PERMISSIONS_POLICY}.\n     */\n    @SuppressWarnings(\"deprecation\")\n    @RequiresPermission(ManifestCompat.permission.REVOKE_RUNTIME_PERMISSIONS)\n    public static void revokePermission(@NonNull String packageName,\n                                        @NonNull String permissionName,\n                                        @UserIdInt int userId,\n                                        @Nullable String reason) throws RemoteException {\n        IPackageManager pm = PackageManagerCompat.getPackageManager();\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {\n            IPermissionManager permissionManager = getPermissionManager();\n            try {\n                permissionManager.revokeRuntimePermission(packageName, permissionName, userId, reason);\n            } catch (NoSuchMethodError e) {\n                try {\n                    permissionManager.revokeRuntimePermission(packageName, permissionName,\n                            ContextUtils.getContext().getDeviceId(), userId, reason);\n                } catch (NoSuchMethodError e2) {\n                    permissionManager.revokeRuntimePermission(packageName, permissionName,\n                            PERSISTENT_DEVICE_ID_DEFAULT, userId, reason);\n                }\n            }\n        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {\n            getPermissionManager().revokeRuntimePermission(packageName, permissionName, userId, reason);\n        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {\n            pm.revokeRuntimePermission(packageName, permissionName, userId);\n        } else {\n            pm.revokePermission(packageName, permissionName);\n        }\n    }\n\n    @SuppressWarnings(\"deprecation\")\n    public static int checkPermission(@NonNull String permissionName,\n                                      @NonNull String packageName,\n                                      @UserIdInt int userId) {\n        IPackageManager pm = PackageManagerCompat.getPackageManager();\n        try {\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {\n                return pm.checkPermission(permissionName, packageName, userId);\n            } else {\n                return pm.checkPermission(permissionName, packageName);\n            }\n        } catch (RemoteException e) {\n            return ExUtils.rethrowFromSystemServer(e);\n        }\n    }\n\n    @SuppressWarnings({\"deprecation\", \"ConstantConditions\"})\n    @Nullable\n    public static PermissionInfo getPermissionInfo(String permissionName, String packageName, int flags)\n            throws RemoteException {\n        IPackageManager pm = PackageManagerCompat.getPackageManager();\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {\n            return getPermissionManager().getPermissionInfo(permissionName, packageName, flags);\n        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {\n            return pm.getPermissionInfo(permissionName, packageName, flags);\n        } else return pm.getPermissionInfo(permissionName, flags);\n    }\n\n    @SuppressWarnings(\"deprecation\")\n    @NonNull\n    public static PermissionGroupInfo getPermissionGroupInfo(String groupName, int flags) throws RemoteException {\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {\n            return getPermissionManager().getPermissionGroupInfo(groupName, flags);\n        } else return PackageManagerCompat.getPackageManager().getPermissionGroupInfo(groupName, flags);\n    }\n\n    @SuppressWarnings(\"deprecation\")\n    public static List<PermissionInfo> queryPermissionsByGroup(String groupName, int flags) throws RemoteException {\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {\n            return getPermissionManager().queryPermissionsByGroup(groupName, flags).getList();\n        } else {\n            IPackageManager pm = PackageManagerCompat.getPackageManager();\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {\n                IPackageManagerN pmN = Refine.unsafeCast(pm);\n                return pmN.queryPermissionsByGroup(groupName, flags).getList();\n            } else return pm.queryPermissionsByGroup(groupName, flags);\n        }\n    }\n\n    public static List<SplitPermissionInfoParcelable> getSplitPermissions() throws RemoteException {\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {\n            return getPermissionManager().getSplitPermissions();\n        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {\n            return PackageManagerCompat.getPackageManager().getSplitPermissions();\n        }\n        return Collections.emptyList();\n    }\n\n    public static boolean getCheckAdjustPolicyFlagPermission(@NonNull ApplicationInfo info) {\n        return info.targetSdkVersion >= Build.VERSION_CODES.Q;\n    }\n\n    @NonNull\n    public static IPermissionManager getPermissionManager() {\n        return IPermissionManager.Stub.asInterface(ProxyBinder.getService(\"permissionmgr\"));\n    }\n\n    @SuppressLint(\"WrongConstant\")\n    @NonNull\n    public static SparseArray<String> getPermissionFlagsWithString(@PermissionFlags int flags) {\n        SparseArray<String> permissionFlagsWithString = new SparseArray<>();\n        for (int i = 0; i < 18; ++i) {\n            if ((flags & (1 << i)) != 0) {\n                permissionFlagsWithString.put(1 << i, permissionFlagToString((1 << i)));\n            }\n        }\n        return permissionFlagsWithString;\n    }\n\n    @SuppressLint(\"NewApi\")\n    @NonNull\n    public static String permissionFlagToString(@PermissionFlags int flag) {\n        switch (flag) {\n            case FLAG_PERMISSION_GRANTED_BY_DEFAULT:\n                return \"GRANTED_BY_DEFAULT\";\n            case FLAG_PERMISSION_POLICY_FIXED:\n                return \"POLICY_FIXED\";\n            case FLAG_PERMISSION_SYSTEM_FIXED:\n                return \"SYSTEM_FIXED\";\n            case FLAG_PERMISSION_USER_SET:\n                return \"USER_SET\";\n            case FLAG_PERMISSION_USER_FIXED:\n                return \"USER_FIXED\";\n            case FLAG_PERMISSION_REVIEW_REQUIRED:\n                return \"REVIEW_REQUIRED\";\n            case FLAG_PERMISSION_REVOKE_WHEN_REQUESTED:\n                return \"REVOKE_WHEN_REQUESTED\";\n            case FLAG_PERMISSION_USER_SENSITIVE_WHEN_GRANTED:\n                return \"USER_SENSITIVE_WHEN_GRANTED\";\n            case FLAG_PERMISSION_USER_SENSITIVE_WHEN_DENIED:\n                return \"USER_SENSITIVE_WHEN_DENIED\";\n            case FLAG_PERMISSION_RESTRICTION_INSTALLER_EXEMPT:\n                return \"RESTRICTION_INSTALLER_EXEMPT\";\n            case FLAG_PERMISSION_RESTRICTION_SYSTEM_EXEMPT:\n                return \"RESTRICTION_SYSTEM_EXEMPT\";\n            case FLAG_PERMISSION_RESTRICTION_UPGRADE_EXEMPT:\n                return \"RESTRICTION_UPGRADE_EXEMPT\";\n            case FLAG_PERMISSION_APPLY_RESTRICTION:\n                return \"APPLY_RESTRICTION\";\n            case FLAG_PERMISSION_GRANTED_BY_ROLE:\n                return \"GRANTED_BY_ROLE\";\n            case FLAG_PERMISSION_REVOKED_COMPAT:\n                return \"REVOKED_COMPAT\";\n            case FLAG_PERMISSION_ONE_TIME:\n                return \"ONE_TIME\";\n            case FLAG_PERMISSION_AUTO_REVOKED:\n                return \"AUTO_REVOKED\";\n            case FLAG_PERMISSION_NONE:\n            default:\n                return Integer.toString(flag);\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/compat/ProcessCompat.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.compat;\n\nimport android.os.RemoteException;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport java.io.File;\nimport java.io.IOException;\n\nimport io.github.muntashirakon.AppManager.ipc.LocalServices;\nimport io.github.muntashirakon.AppManager.ipc.RemoteProcess;\nimport io.github.muntashirakon.AppManager.ipc.RemoteProcessImpl;\n\npublic final class ProcessCompat {\n    /**\n     * Defines the start of a range of UIDs (and GIDs), going from this\n     * number to {@link #LAST_APPLICATION_UID} that are reserved for assigning\n     * to applications.\n     */\n    public static final int FIRST_APPLICATION_UID = android.os.Process.FIRST_APPLICATION_UID;\n\n    /**\n     * Last of application-specific UIDs starting at\n     * {@link #FIRST_APPLICATION_UID}.\n     */\n    public static final int LAST_APPLICATION_UID = android.os.Process.LAST_APPLICATION_UID;\n\n    /**\n     * First uid used for fully isolated sandboxed processes spawned from an app zygote\n     */\n    public static final int FIRST_APP_ZYGOTE_ISOLATED_UID = 90000;\n\n    /**\n     * Last uid used for fully isolated sandboxed processes spawned from an app zygote\n     */\n    public static final int LAST_APP_ZYGOTE_ISOLATED_UID = 98999;\n\n    /**\n     * First uid used for fully isolated sandboxed processes (with no permissions of their own)\n     */\n    public static final int FIRST_ISOLATED_UID = 99000;\n\n    /**\n     * Last uid used for fully isolated sandboxed processes (with no permissions of their own)\n     */\n    public static final int LAST_ISOLATED_UID = 99999;\n\n    public static Process exec(@Nullable String[] cmd, @Nullable String[] env, @Nullable File dir) throws IOException {\n        if (LocalServices.alive()) {\n            try {\n                return new RemoteProcess(LocalServices.getAmService().newProcess(cmd, env, dir == null ? null :\n                        dir.getAbsolutePath()));\n            } catch (RemoteException e) {\n                throw new IOException(e);\n            }\n        }\n        return new RemoteProcess(new RemoteProcessImpl(Runtime.getRuntime().exec(cmd, env, dir)));\n    }\n\n    public static Process exec(String[] cmd, String[] env) throws IOException {\n        return exec(cmd, env, null);\n    }\n\n    public static Process exec(String[] cmd) throws IOException {\n        return exec(cmd, null, null);\n    }\n\n    public static boolean isAlive(@NonNull Process process) {\n        try {\n            process.exitValue();\n            return false;\n        } catch (IllegalArgumentException e) {\n            return true;\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/compat/SensorServiceCompat.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.compat;\n\nimport android.annotation.UserIdInt;\nimport android.os.Build;\nimport android.os.IBinder;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.RequiresApi;\nimport androidx.annotation.RequiresPermission;\n\nimport java.io.IOException;\n\nimport io.github.muntashirakon.AppManager.ipc.ProxyBinder;\nimport io.github.muntashirakon.AppManager.utils.BinderShellExecutor;\n\n@RequiresApi(Build.VERSION_CODES.P)\npublic final class SensorServiceCompat {\n    @RequiresPermission(ManifestCompat.permission.MANAGE_SENSORS)\n    public static boolean isSensorEnabled(@NonNull String packageName, @UserIdInt int userId) {\n        String[] command;\n        if (Build.VERSION.SDK_INT > Build.VERSION_CODES.Q) {\n            command = new String[]{\"get-uid-state\", packageName, \"--user\", String.valueOf(userId)};\n        } else command = new String[]{\"get-uid-state\", packageName};\n        try {\n            BinderShellExecutor.ShellResult result = BinderShellExecutor.execute(getSensorService(), command);\n            return \"active\".equals(result.getStdout().trim());\n        } catch (IOException e) {\n            e.printStackTrace();\n        }\n        return true;\n    }\n\n    @RequiresPermission(ManifestCompat.permission.MANAGE_SENSORS)\n    public static void enableSensor(@NonNull String packageName, @UserIdInt int userId, boolean enable) throws IOException {\n        String state = enable ? \"active\" : \"idle\";\n        String[] command;\n        if (Build.VERSION.SDK_INT > Build.VERSION_CODES.Q) {\n            command = new String[]{\"set-uid-state\", packageName, state, \"--user\", String.valueOf(userId)};\n        } else command = new String[]{\"set-uid-state\", packageName, state};\n        BinderShellExecutor.ShellResult result = BinderShellExecutor.execute(getSensorService(), command);\n        if (result.getResultCode() != 0) {\n            throw new IOException(\"Could not \" + (enable ? \"enable\" : \"disable\") + \" sensor.\");\n        }\n    }\n\n    @RequiresPermission(ManifestCompat.permission.MANAGE_SENSORS)\n    public static void resetSensor(@NonNull String packageName, @UserIdInt int userId) throws IOException {\n        String[] command;\n        if (Build.VERSION.SDK_INT > Build.VERSION_CODES.Q) {\n            command = new String[]{\"reset-uid-state\", packageName, \"--user\", String.valueOf(userId)};\n        } else command = new String[]{\"reset-uid-state\", packageName};\n        BinderShellExecutor.ShellResult result = BinderShellExecutor.execute(getSensorService(), command);\n        if (result.getResultCode() != 0) {\n            throw new IOException(\"Could not reset sensor.\");\n        }\n    }\n\n    @NonNull\n    private static IBinder getSensorService() {\n        return ProxyBinder.getService(\"sensorservice\");\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/compat/StorageManagerCompat.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.compat;\n\nimport static io.github.muntashirakon.io.IoUtils.DEFAULT_BUFFER_SIZE;\n\nimport android.content.Context;\nimport android.os.Build;\nimport android.os.Handler;\nimport android.os.ParcelFileDescriptor;\nimport android.os.Process;\nimport android.os.storage.StorageManager;\nimport android.os.storage.StorageManagerHidden;\nimport android.os.storage.StorageVolume;\nimport android.system.ErrnoException;\nimport android.system.OsConstants;\nimport android.util.Log;\n\nimport androidx.annotation.IntDef;\nimport androidx.annotation.NonNull;\n\nimport java.io.IOException;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.util.Locale;\n\nimport dev.rikka.tools.refine.Refine;\nimport io.github.muntashirakon.AppManager.self.SelfPermissions;\n\n// Copyright 2018 Fung Gwo <fythonx@gmail.com>\n// Copyright 2021 Muntashir Al-Islam\n// Modified from https://gist.github.com/fython/924f8d9019bca75d22de116bb69a54a1\npublic final class StorageManagerCompat {\n    private static final String TAG = StorageManagerCompat.class.getSimpleName();\n\n    /**\n     * Flag indicating that a disk space allocation request should be allowed to\n     * clear up to all reserved disk space.\n     */\n    public static final int FLAG_ALLOCATE_DEFY_ALL_RESERVED = 1 << 1;\n\n    /**\n     * Flag indicating that a disk space allocation request should be allowed to\n     * clear up to half of all reserved disk space.\n     */\n    public static final int FLAG_ALLOCATE_DEFY_HALF_RESERVED = 1 << 2;\n\n    @IntDef(flag = true, value = {\n            FLAG_ALLOCATE_DEFY_ALL_RESERVED,\n            FLAG_ALLOCATE_DEFY_HALF_RESERVED,\n    })\n    @Retention(RetentionPolicy.SOURCE)\n    public @interface AllocateFlags {\n    }\n\n    @NonNull\n    public static StorageManager from(@NonNull Context context) {\n        return (StorageManager) context.getSystemService(Context.STORAGE_SERVICE);\n    }\n\n    private StorageManagerCompat() {\n    }\n\n    @NonNull\n    public static StorageVolume[] getVolumeList(@NonNull Context context, int userId, int flags)\n            throws SecurityException {\n        if (!SelfPermissions.checkCrossUserPermission(userId, false, Process.myUid())) {\n            return new StorageVolume[0];\n        }\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {\n            return StorageManagerHidden.getVolumeList(userId, flags);\n        } else {\n            StorageVolume[] volumes = Refine.<StorageManagerHidden>unsafeCast(from(context)).getVolumeList();\n            if (volumes != null) {\n                return volumes;\n            }\n        }\n        return new StorageVolume[0];\n    }\n\n    @NonNull\n    public static ParcelFileDescriptor openProxyFileDescriptor(int mode, @NonNull ProxyFileDescriptorCallbackCompat callback)\n            throws IOException, UnsupportedOperationException {\n        // We cannot use StorageManager#openProxyFileDescriptor directly due to its limitation on how callbacks are handled\n        ParcelFileDescriptor[] pipe = ParcelFileDescriptor.createReliablePipe();\n        if ((mode & ParcelFileDescriptor.MODE_READ_ONLY) != 0) {\n            // Reading requested i.e. we have to read from our side and write it to the target\n            callback.mHandler.post(() -> {\n                try (ParcelFileDescriptor.AutoCloseOutputStream os = new ParcelFileDescriptor.AutoCloseOutputStream(pipe[1])) {\n                    long totalSize = callback.onGetSize();\n                    long currOffset = 0;\n                    byte[] buf = new byte[DEFAULT_BUFFER_SIZE];\n                    int size;\n                    while ((size = callback.onRead(currOffset, DEFAULT_BUFFER_SIZE, buf)) > 0) {\n                        os.write(buf, 0, size);\n                        currOffset += size;\n                    }\n                    if (totalSize > 0 && currOffset != totalSize) {\n                        throw new IOException(String.format(Locale.ROOT, \"Could not read the whole resource (total = %d, read = %d)\", totalSize, currOffset));\n                    }\n                } catch (IOException | ErrnoException e) {\n                    Log.e(TAG, \"Failed to read file.\", e);\n                    try {\n                        pipe[1].closeWithError(e.getMessage());\n                    } catch (IOException exc) {\n                        Log.e(TAG, \"Can't even close PFD with error.\", exc);\n                    }\n                } finally {\n                    callback.onRelease();\n                }\n            });\n            return pipe[0];\n        } else if ((mode & ParcelFileDescriptor.MODE_WRITE_ONLY) != 0) {\n            // Writing requested i.e. we have to read from the target and write it to our side\n            callback.mHandler.post(() -> {\n                try (ParcelFileDescriptor.AutoCloseInputStream is = new ParcelFileDescriptor.AutoCloseInputStream(pipe[0])) {\n                    long currOffset = 0;\n                    byte[] buf = new byte[DEFAULT_BUFFER_SIZE];\n                    int size;\n                    while ((size = is.read(buf)) != -1) {\n                        callback.onWrite(currOffset, size, buf);\n                        currOffset += size;\n                    }\n                    long totalSize = callback.onGetSize();\n                    if (totalSize > 0 && currOffset != totalSize) {\n                        throw new IOException(String.format(Locale.ROOT, \"Could not write the whole resource (total = %d, read = %d)\", totalSize, currOffset));\n                    }\n                } catch (IOException | ErrnoException e) {\n                    Log.e(TAG, \"Failed to write file.\", e);\n                    try {\n                        pipe[0].closeWithError(e.getMessage());\n                    } catch (IOException exc) {\n                        Log.e(TAG, \"Can't even close PFD with error.\", exc);\n                    }\n                } finally {\n                    callback.onRelease();\n                }\n            });\n            return pipe[1];\n        } else {\n            // Should never happen.\n            pipe[0].close();\n            pipe[1].close();\n            Log.e(TAG, \"Mode \" + mode + \" is not supported.\");\n            throw new UnsupportedOperationException(\"Mode \" + mode + \" is not supported.\");\n        }\n    }\n\n    public static abstract class ProxyFileDescriptorCallbackCompat {\n        private final Handler mHandler;\n\n        public ProxyFileDescriptorCallbackCompat(@NonNull Handler callbackHandler) {\n            mHandler = callbackHandler;\n        }\n\n        /**\n         * Returns size of bytes provided by the file descriptor.\n         *\n         * @return Size of bytes.\n         * @throws ErrnoException Containing E constants in OsConstants.\n         */\n        public long onGetSize() throws ErrnoException {\n            throw new ErrnoException(\"onGetSize\", OsConstants.EBADF);\n        }\n\n        /**\n         * Provides bytes read from file descriptor.\n         * It needs to return exact requested size of bytes unless it reaches file end.\n         *\n         * @param offset Offset in bytes from the file head specifying where to read bytes. If a seek\n         *               operation is conducted on the file descriptor, then a read operation is requested, the\n         *               offset refrects the proper position of requested bytes.\n         * @param size   Size for read bytes.\n         * @param data   Byte array to store read bytes.\n         * @return Size of bytes returned by the function.\n         * @throws ErrnoException Containing E constants in OsConstants.\n         */\n        public int onRead(long offset, int size, byte[] data) throws ErrnoException {\n            throw new ErrnoException(\"onRead\", OsConstants.EBADF);\n        }\n\n        /**\n         * Handles bytes written to file descriptor.\n         *\n         * @param offset Offset in bytes from the file head specifying where to write bytes. If a seek\n         *               operation is conducted on the file descriptor, then a write operation is requested, the\n         *               offset refrects the proper position of requested bytes.\n         * @param size   Size for write bytes.\n         * @param data   Byte array to be written to somewhere.\n         * @return Size of bytes processed by the function.\n         * @throws ErrnoException Containing E constants in OsConstants.\n         */\n        public int onWrite(long offset, int size, byte[] data) throws ErrnoException {\n            throw new ErrnoException(\"onWrite\", OsConstants.EBADF);\n        }\n\n        /**\n         * Ensures all the written data are stored in permanent storage device.\n         * For example, if it has data stored in on memory cache, it needs to flush data to storage\n         * device.\n         *\n         * @throws ErrnoException Containing E constants in OsConstants.\n         */\n        public void onFsync() throws ErrnoException {\n            throw new ErrnoException(\"onFsync\", OsConstants.EINVAL);\n        }\n\n        /**\n         * Invoked after the file is closed.\n         */\n        protected void onRelease() {\n        }\n    }\n}"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/compat/SubscriptionManagerCompat.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.compat;\n\nimport android.os.Build;\nimport android.os.RemoteException;\nimport android.telephony.SubscriptionInfo;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.RequiresApi;\n\nimport com.android.internal.telephony.IPhoneSubInfo;\nimport com.android.internal.telephony.ISub;\n\nimport java.util.List;\n\nimport io.github.muntashirakon.AppManager.ipc.ProxyBinder;\nimport io.github.muntashirakon.AppManager.self.SelfPermissions;\nimport io.github.muntashirakon.AppManager.users.Users;\nimport io.github.muntashirakon.AppManager.utils.ExUtils;\n\npublic class SubscriptionManagerCompat {\n    public static final String TAG = SubscriptionManagerCompat.class.getSimpleName();\n\n    @SuppressWarnings(\"deprecation\")\n    @RequiresApi(Build.VERSION_CODES.LOLLIPOP_MR1)\n    @Nullable\n    public static List<SubscriptionInfo> getActiveSubscriptionInfoList() {\n        try {\n            ISub sub = getSub();\n            int uid = Users.getSelfOrRemoteUid();\n            String callingPackage = SelfPermissions.getCallingPackage(uid);\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {\n                try {\n                    return sub.getActiveSubscriptionInfoList(callingPackage, null);\n                } catch (NoSuchMethodError e) {\n                    // Google Pixel\n                    return sub.getActiveSubscriptionInfoList(callingPackage, null, true);\n                }\n            } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {\n                return sub.getActiveSubscriptionInfoList(callingPackage, null);\n            } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {\n                return sub.getActiveSubscriptionInfoList(callingPackage);\n            }\n            return sub.getActiveSubscriptionInfoList();\n        } catch (RemoteException e) {\n            return ExUtils.rethrowFromSystemServer(e);\n        }\n    }\n\n    @SuppressWarnings(\"deprecation\")\n    @Nullable\n    public static String getSubscriberIdForSubscriber(long subId) {\n        try {\n            IPhoneSubInfo sub = getPhoneSubInfo();\n            int uid = Users.getSelfOrRemoteUid();\n            String callingPackage = SelfPermissions.getCallingPackage(uid);\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {\n                return sub.getSubscriberIdForSubscriber((int) subId, callingPackage, null);\n            } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {\n                return sub.getSubscriberIdForSubscriber((int) subId, callingPackage);\n            } else if (Build.VERSION.SDK_INT == Build.VERSION_CODES.LOLLIPOP_MR1) {\n                return sub.getSubscriberIdForSubscriber((int) subId);\n            }\n            return sub.getSubscriberIdForSubscriber(subId);\n        } catch (RemoteException e) {\n            return ExUtils.rethrowFromSystemServer(e);\n        } catch (NullPointerException ignore) {\n        }\n        return null;\n    }\n\n    @NonNull\n    private static ISub getSub() {\n        return ISub.Stub.asInterface(ProxyBinder.getService(\"isub\"));\n    }\n\n    @NonNull\n    private static IPhoneSubInfo getPhoneSubInfo() {\n        return IPhoneSubInfo.Stub.asInterface(ProxyBinder.getService(\"iphonesubinfo\"));\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/compat/ThumbnailUtilsCompat.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.compat;\n\nimport static android.media.MediaMetadataRetriever.METADATA_KEY_DURATION;\nimport static android.media.MediaMetadataRetriever.OPTION_CLOSEST_SYNC;\n\nimport android.content.ContentResolver;\nimport android.content.Context;\nimport android.graphics.Bitmap;\nimport android.graphics.BitmapFactory;\nimport android.media.MediaMetadataRetriever;\nimport android.media.ThumbnailUtils;\nimport android.net.Uri;\nimport android.os.Build;\nimport android.os.CancellationSignal;\nimport android.util.Size;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport java.io.IOException;\nimport java.util.Objects;\n\npublic class ThumbnailUtilsCompat {\n    /**\n     * Create a thumbnail for given audio file.\n     * <p>\n     * This method should only be used for files that you have direct access to;\n     * if you'd like to work with media hosted outside your app, consider using\n     * {@link ContentResolver#loadThumbnail(Uri, Size, CancellationSignal)}\n     * which enables remote providers to efficiently cache and invalidate\n     * thumbnails.\n     *\n     * @param context The Context to use when resolving the audio Uri.\n     * @param uri     The audio Uri.\n     * @param size    The desired thumbnail size.\n     * @throws IOException If any trouble was encountered while generating or loading the thumbnail, or if\n     *                     {@link CancellationSignal#cancel()} was invoked.\n     */\n    public static @NonNull Bitmap createAudioThumbnail(@NonNull Context context, @NonNull Uri uri, @NonNull Size size,\n                                                       @Nullable CancellationSignal signal) throws IOException {\n        // Checkpoint before going deeper\n        if (signal != null) signal.throwIfCanceled();\n\n        try (MediaMetadataRetriever retriever = new MediaMetadataRetriever()) {\n            retriever.setDataSource(context, uri);\n            final byte[] raw = retriever.getEmbeddedPicture();\n            if (raw != null) {\n                Bitmap bitmap = BitmapFactory.decodeByteArray(raw, 0, raw.length);\n                return getThumbnail(bitmap, size, true);\n            }\n        } catch (RuntimeException e) {\n            throw new IOException(\"Failed to create thumbnail\", e);\n        }\n        throw new IOException(\"No album art found\");\n    }\n\n    /**\n     * Create a thumbnail for given video file.\n     * <p>\n     * This method should only be used for files that you have direct access to;\n     * if you'd like to work with media hosted outside your app, consider using\n     * {@link ContentResolver#loadThumbnail(Uri, Size, CancellationSignal)}\n     * which enables remote providers to efficiently cache and invalidate\n     * thumbnails.\n     *\n     * @param context The Context to use when resolving the video Uri.\n     * @param uri     The video file.\n     * @param size    The desired thumbnail size.\n     * @throws IOException If any trouble was encountered while generating or\n     *                     loading the thumbnail, or if\n     *                     {@link CancellationSignal#cancel()} was invoked.\n     */\n    public static @NonNull Bitmap createVideoThumbnail(@NonNull Context context, @NonNull Uri uri, @NonNull Size size,\n                                                       @Nullable CancellationSignal signal) throws IOException {\n        // Checkpoint before going deeper\n        if (signal != null) signal.throwIfCanceled();\n\n        try (MediaMetadataRetriever mmr = new MediaMetadataRetriever()) {\n            mmr.setDataSource(context, uri);\n\n            // Try to retrieve thumbnail from metadata\n            final byte[] raw = mmr.getEmbeddedPicture();\n            if (raw != null) {\n                Bitmap bitmap = BitmapFactory.decodeByteArray(raw, 0, raw.length);\n                return getThumbnail(bitmap, size, true);\n            }\n\n            final MediaMetadataRetriever.BitmapParams params;\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {\n                params = new MediaMetadataRetriever.BitmapParams();\n                params.setPreferredConfig(Bitmap.Config.ARGB_8888);\n            } else params = null;\n\n            // Fall back to middle of video\n            // Note: METADATA_KEY_DURATION unit is in ms, not us.\n            final long thumbnailTimeUs = Long.parseLong(mmr.extractMetadata(METADATA_KEY_DURATION)) * 1000 / 2;\n\n            // If we're okay with something larger than native format, just\n            // return a frame without up-scaling it\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {\n                return getThumbnail(mmr.getFrameAtTime(thumbnailTimeUs, OPTION_CLOSEST_SYNC, params), size, false);\n            } else {\n                return getThumbnail(mmr.getFrameAtTime(thumbnailTimeUs, OPTION_CLOSEST_SYNC), size, false);\n            }\n        } catch (RuntimeException e) {\n            throw new IOException(\"Failed to create thumbnail\", e);\n        }\n    }\n\n    private static Bitmap getThumbnail(@NonNull Bitmap bitmap, @NonNull Size size, boolean recycle) {\n        return ThumbnailUtils.extractThumbnail(Objects.requireNonNull(bitmap), size.getWidth(), size.getHeight(),\n                recycle ? ThumbnailUtils.OPTIONS_RECYCLE_INPUT : 0);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/compat/UriCompat.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.compat;\n\nimport android.net.Uri;\n\nimport androidx.annotation.Nullable;\n\npublic final class UriCompat {\n    /**\n     * Index of a component which was not found.\n     */\n    private final static int NOT_FOUND = -1;\n\n    /**\n     * Encodes a value it wasn't already encoded.\n     *\n     * @param value string to encode\n     * @param allow characters to allow\n     * @return encoded value\n     */\n    @Nullable\n    public static String encodeIfNotEncoded(@Nullable String value, @Nullable String allow) {\n        if (value == null) return null;\n        if (isEncoded(value, allow)) return value;\n        return Uri.encode(value, allow);\n    }\n\n    /**\n     * Returns true if the given string is already encoded to safe characters.\n     *\n     * @param value string to check\n     * @param allow characters to allow\n     * @return true if the string is already encoded or false if it should be encoded\n     */\n    private static boolean isEncoded(@Nullable String value, @Nullable String allow) {\n        if (value == null) return true;\n        for (int index = 0; index < value.length(); index++) {\n            char c = value.charAt(index);\n\n            // Allow % because that's the prefix for an encoded character. This method will fail\n            // for decoded strings whose onlyinvalid character is %, but it's assumed that % alone\n            // cannot cause malicious behavior in the framework.\n            if (!isAllowed(c, allow) && c != '%') {\n                return false;\n            }\n        }\n        return true;\n    }\n\n\n    /**\n     * Returns true if the given character is allowed.\n     *\n     * @param c     character to check\n     * @param allow characters to allow\n     * @return true if the character is allowed or false if it should be\n     * encoded\n     */\n    private static boolean isAllowed(char c, @Nullable String allow) {\n        return (c >= 'A' && c <= 'Z')\n                || (c >= 'a' && c <= 'z')\n                || (c >= '0' && c <= '9')\n                || \"_-!.~'()*\".indexOf(c) != NOT_FOUND\n                || (allow != null && allow.indexOf(c) != NOT_FOUND);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/compat/UsageStatsManagerCompat.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.compat;\n\nimport android.annotation.UserIdInt;\nimport android.app.usage.IUsageStatsManager;\nimport android.app.usage.UsageEvents;\nimport android.content.Context;\nimport android.os.Build;\nimport android.os.RemoteException;\nimport android.os.UserHandleHidden;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.RequiresPermission;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\n\nimport io.github.muntashirakon.AppManager.ipc.ProxyBinder;\nimport io.github.muntashirakon.AppManager.self.SelfPermissions;\nimport io.github.muntashirakon.AppManager.users.Users;\nimport io.github.muntashirakon.AppManager.utils.ArrayUtils;\nimport io.github.muntashirakon.AppManager.utils.BroadcastUtils;\nimport io.github.muntashirakon.AppManager.utils.ContextUtils;\nimport io.github.muntashirakon.AppManager.utils.ExUtils;\n\npublic final class UsageStatsManagerCompat {\n    private static final String SYS_USAGE_STATS_SERVICE = \"usagestats\";\n\n    private static final String USAGE_STATS_SERVICE_NAME;\n\n    static {\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) {\n            USAGE_STATS_SERVICE_NAME = Context.USAGE_STATS_SERVICE;\n        } else {\n            USAGE_STATS_SERVICE_NAME = SYS_USAGE_STATS_SERVICE;\n        }\n    }\n\n    @RequiresPermission(\"android.permission.PACKAGE_USAGE_STATS\")\n    @Nullable\n    public static UsageEvents queryEvents(long beginTime, long endTime, int userId) {\n        try {\n            IUsageStatsManager usm = getUsageStatsManager();\n            String callingPackage = SelfPermissions.getCallingPackage(Users.getSelfOrRemoteUid());\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {\n                return usm.queryEventsForUser(beginTime, endTime, userId, callingPackage);\n            }\n            return usm.queryEvents(beginTime, endTime, callingPackage);\n        } catch (RemoteException e) {\n            return ExUtils.rethrowFromSystemServer(e);\n        }\n    }\n\n    /**\n     * Note: This method should only be used when sorted entries are required as the operations done\n     * here are expensive.\n     */\n    @RequiresPermission(\"android.permission.PACKAGE_USAGE_STATS\")\n    @NonNull\n    public static List<UsageEvents.Event> queryEventsSorted(long beginTime, long endTime, int userId, int[] filterEvents) {\n        List<UsageEvents.Event> filteredEvents = new ArrayList<>();\n        UsageEvents events = queryEvents(beginTime, endTime, userId);\n        if (events != null) {\n            while (events.hasNextEvent()) {\n                UsageEvents.Event event = new UsageEvents.Event();\n                events.getNextEvent(event);\n                if (ArrayUtils.contains(filterEvents, event.getEventType())) {\n                    filteredEvents.add(event);\n                }\n            }\n            Collections.sort(filteredEvents, (o1, o2) -> -Long.compare(o1.getTimeStamp(), o2.getTimeStamp()));\n        }\n        return filteredEvents;\n    }\n\n    public static void setAppInactive(String packageName, @UserIdInt int userId, boolean inactive) {\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {\n            try {\n                getUsageStatsManager().setAppInactive(packageName, inactive, userId);\n                if (userId != UserHandleHidden.myUserId()) {\n                    BroadcastUtils.sendPackageAltered(ContextUtils.getContext(), new String[]{packageName});\n                }\n            } catch (RemoteException e) {\n                ExUtils.rethrowFromSystemServer(e);\n            }\n        }\n    }\n\n    @SuppressWarnings(\"deprecation\")\n    public static boolean isAppInactive(String packageName, @UserIdInt int userId) {\n        IUsageStatsManager usm = getUsageStatsManager();\n        try {\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {\n                String callingPackage = SelfPermissions.getCallingPackage(Users.getSelfOrRemoteUid());\n                return usm.isAppInactive(packageName, userId, callingPackage);\n            } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {\n                return usm.isAppInactive(packageName, userId);\n            }\n        } catch (RemoteException e) {\n            return ExUtils.rethrowFromSystemServer(e);\n        }\n        // Unsupported Android version: return false\n        return false;\n    }\n\n    public static IUsageStatsManager getUsageStatsManager() {\n        return IUsageStatsManager.Stub.asInterface(ProxyBinder.getService(USAGE_STATS_SERVICE_NAME));\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/compat/VirtualDeviceManagerCompat.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.compat;\n\nimport android.content.Context;\nimport android.os.Build;\n\nimport androidx.annotation.RequiresApi;\n\n@RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)\npublic final class VirtualDeviceManagerCompat {\n    public static final String PERSISTENT_DEVICE_ID_DEFAULT = \"default:\" + Context.DEVICE_ID_DEFAULT;\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/crypto/AESCrypto.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.crypto;\n\nimport androidx.annotation.CallSuper;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.WorkerThread;\n\nimport org.bouncycastle.crypto.engines.AESEngine;\nimport org.bouncycastle.crypto.io.CipherInputStream;\nimport org.bouncycastle.crypto.io.CipherOutputStream;\nimport org.bouncycastle.crypto.modes.GCMBlockCipher;\nimport org.bouncycastle.crypto.modes.GCMModeCipher;\nimport org.bouncycastle.crypto.params.AEADParameters;\nimport org.bouncycastle.crypto.params.KeyParameter;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\n\nimport javax.crypto.SecretKey;\nimport javax.security.auth.DestroyFailedException;\n\nimport io.github.muntashirakon.AppManager.backup.CryptoUtils;\nimport io.github.muntashirakon.AppManager.crypto.ks.KeyStoreManager;\nimport io.github.muntashirakon.AppManager.crypto.ks.SecretKeyCompat;\nimport io.github.muntashirakon.AppManager.logs.Log;\nimport io.github.muntashirakon.io.IoUtils;\nimport io.github.muntashirakon.io.Path;\n\npublic class AESCrypto implements Crypto {\n    public static final String TAG = \"AESCrypto\";\n\n    public static final String AES_EXT = \".aes\";\n    public static final String AES_KEY_ALIAS = \"backup_aes\";\n    public static final int GCM_IV_SIZE_BYTES = 12;\n    public static final int MAC_SIZE_BITS_OLD = 32;\n    public static final int MAC_SIZE_BITS = 128;\n\n    private final SecretKey mSecretKey;\n    private final byte[] mIv;\n    @CryptoUtils.Mode\n    private final String mParentMode;\n\n    private int mMacSizeBits = MAC_SIZE_BITS;\n\n    public AESCrypto(@NonNull byte[] iv) throws CryptoException {\n        this(iv, CryptoUtils.MODE_AES, null);\n    }\n\n    @NonNull\n    @Override\n    public String getModeName() {\n        return mParentMode;\n    }\n\n    protected AESCrypto(@NonNull byte[] iv, @NonNull @CryptoUtils.Mode String mode, @Nullable byte[] encryptedAesKey)\n            throws CryptoException {\n        mIv = iv;\n        mParentMode = mode;\n        switch (mParentMode) {\n            case CryptoUtils.MODE_AES:\n                try {\n                    KeyStoreManager keyStoreManager = KeyStoreManager.getInstance();\n                    mSecretKey = keyStoreManager.getSecretKey(AES_KEY_ALIAS);\n                    if (mSecretKey == null) {\n                        throw new CryptoException(\"No SecretKey with alias \" + AES_KEY_ALIAS);\n                    }\n                } catch (Exception e) {\n                    throw new CryptoException(e);\n                }\n                break;\n            case CryptoUtils.MODE_RSA:\n                // Hybrid encryption using RSA\n                if (encryptedAesKey == null) {\n                    // No encryption key provided, generate one\n                    mSecretKey = RSACrypto.generateAesKey();\n                } else {\n                    // Encryption key provided\n                    mSecretKey = RSACrypto.decryptAesKey(encryptedAesKey);\n                }\n                break;\n            case CryptoUtils.MODE_ECC:\n                // Hybrid encryption using ECC\n                if (encryptedAesKey == null) {\n                    // No encryption key provided, generate one\n                    mSecretKey = ECCCrypto.generateAesKey();\n                } else {\n                    // Encryption key provided\n                    mSecretKey = ECCCrypto.decryptAesKey(encryptedAesKey);\n                }\n                break;\n            default:\n                throw new CryptoException(\"Unsupported mode \" + mParentMode);\n        }\n    }\n\n    public void setMacSizeBits(int macSizeBits) {\n        if (macSizeBits == MAC_SIZE_BITS || macSizeBits == MAC_SIZE_BITS_OLD) {\n            mMacSizeBits = macSizeBits;\n        }\n    }\n\n    @NonNull\n    private AEADParameters getParams() {\n        // We need to generate it dynamically due to MAC size issues\n        return new AEADParameters(new KeyParameter(mSecretKey.getEncoded()), mMacSizeBits, mIv);\n    }\n\n    @CallSuper\n    @NonNull\n    protected byte[] getEncryptedAesKey() throws CryptoException {\n        if (mParentMode.equals(CryptoUtils.MODE_RSA)) {\n            return RSACrypto.encryptAesKey(mSecretKey);\n        }\n        if (mParentMode.equals(CryptoUtils.MODE_ECC)) {\n            return ECCCrypto.encryptAesKey(mSecretKey);\n        }\n        // Invalid mode\n        throw new CryptoException(\"Not in RSA or ECC mode\");\n    }\n\n    @WorkerThread\n    @Override\n    public void encrypt(@NonNull Path[] inputFiles, @NonNull Path[] outputFiles) throws IOException {\n        handleFiles(true, inputFiles, outputFiles);\n    }\n\n    @Override\n    public void encrypt(@NonNull InputStream unencryptedStream, @NonNull OutputStream encryptedStream)\n            throws IOException {\n        // Init cipher\n        GCMModeCipher cipher = GCMBlockCipher.newInstance(AESEngine.newInstance());\n        cipher.init(true, getParams());\n        // Convert unencrypted stream to encrypted stream\n        try (OutputStream cipherOS = new CipherOutputStream(encryptedStream, cipher)) {\n            IoUtils.copy(unencryptedStream, cipherOS);\n        }\n    }\n\n    @WorkerThread\n    @Override\n    public void decrypt(@NonNull Path[] inputFiles, @NonNull Path[] outputFiles) throws IOException {\n        handleFiles(false, inputFiles, outputFiles);\n    }\n\n    @Override\n    public void decrypt(@NonNull InputStream encryptedStream, @NonNull OutputStream unencryptedStream)\n            throws IOException {\n        // Init cipher\n        GCMModeCipher cipher = GCMBlockCipher.newInstance(AESEngine.newInstance());\n        cipher.init(false, getParams());\n        // Convert encrypted stream to unencrypted stream\n        try (InputStream cipherIS = new CipherInputStream(encryptedStream, cipher)) {\n            IoUtils.copy(cipherIS, unencryptedStream);\n        }\n    }\n\n    @WorkerThread\n    private void handleFiles(boolean forEncryption, @NonNull Path[] inputFiles, @NonNull Path[] outputFiles) throws IOException {\n        // `files` is never null here\n        if (inputFiles.length == 0) {\n            Log.d(TAG, \"No files to de/encrypt\");\n            return;\n        }\n        if (inputFiles.length != outputFiles.length) {\n            throw new IOException(\"The number of input and output files are not the same.\");\n        }\n        // Init cipher\n        GCMModeCipher cipher = GCMBlockCipher.newInstance(AESEngine.newInstance());\n        cipher.init(forEncryption, getParams());\n        // Encrypt/decrypt files\n        for (int i = 0; i < inputFiles.length; i++) {\n            Path inputPath = inputFiles[i];\n            Path outputPath = outputFiles[i];\n            Log.i(TAG, \"Input: %s\\nOutput: %s\", inputPath, outputPath);\n            try (InputStream is = inputPath.openInputStream();\n                 OutputStream os = outputPath.openOutputStream()) {\n                if (forEncryption) {\n                    try (OutputStream cipherOS = new CipherOutputStream(os, cipher)) {\n                        IoUtils.copy(is, cipherOS);\n                    }\n                } else {  // Cipher.DECRYPT_MODE\n                    try (InputStream cipherIS = new CipherInputStream(is, cipher)) {\n                        IoUtils.copy(cipherIS, os);\n                    }\n                }\n            }\n        }\n        // Total success\n    }\n\n    @Override\n    public void close() {\n        try {\n            SecretKeyCompat.destroy(mSecretKey);\n        } catch (DestroyFailedException e) {\n            e.printStackTrace();\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/crypto/Crypto.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.crypto;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.WorkerThread;\n\nimport java.io.Closeable;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\n\nimport io.github.muntashirakon.AppManager.backup.CryptoUtils;\nimport io.github.muntashirakon.io.Path;\n\npublic interface Crypto extends Closeable {\n    @NonNull\n    @CryptoUtils.Mode\n    String getModeName();\n\n    @WorkerThread\n    void encrypt(@NonNull Path[] inputFiles, @NonNull Path[] outputFiles) throws IOException;\n\n    @WorkerThread\n    void encrypt(@NonNull InputStream unencryptedStream, @NonNull OutputStream encryptedStream) throws IOException;\n\n    @WorkerThread\n    void decrypt(@NonNull Path[] inputFiles, @NonNull Path[] outputFiles) throws IOException;\n\n    @WorkerThread\n    void decrypt(@NonNull InputStream encryptedStream, @NonNull OutputStream unencryptedStream) throws IOException;\n\n    @Override\n    void close();\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/crypto/CryptoException.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.crypto;\n\npublic class CryptoException extends Throwable {\n    public CryptoException() {\n        super();\n    }\n\n    public CryptoException(String message) {\n        super(message);\n    }\n\n    public CryptoException(String message, Throwable cause) {\n        super(message, cause);\n    }\n\n    public CryptoException(Throwable cause) {\n        super(cause);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/crypto/DummyCrypto.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.crypto;\n\nimport androidx.annotation.NonNull;\n\nimport java.io.InputStream;\nimport java.io.OutputStream;\n\nimport io.github.muntashirakon.AppManager.backup.CryptoUtils;\nimport io.github.muntashirakon.io.Path;\n\npublic class DummyCrypto implements Crypto {\n    @NonNull\n    @Override\n    public String getModeName() {\n        return CryptoUtils.MODE_NO_ENCRYPTION;\n    }\n\n    @Override\n    public void encrypt(@NonNull Path[] inputFiles, @NonNull Path[] outputFiles) {\n        // Do nothing since both are the same set of files\n    }\n\n    @Override\n    public void encrypt(@NonNull InputStream unencryptedStream, @NonNull OutputStream encryptedStream) {\n        // Do nothing since both are the same stream\n    }\n\n    @Override\n    public void decrypt(@NonNull Path[] inputFiles, @NonNull Path[] outputFiles) {\n        // Do nothing since both are the same set of files\n    }\n\n    @Override\n    public void decrypt(@NonNull InputStream encryptedStream, @NonNull OutputStream unencryptedStream) {\n        // Do nothing since both are the same stream\n    }\n\n    @Override\n    public void close() {\n        // Nothing to close\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/crypto/ECCCrypto.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.crypto;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport org.bouncycastle.jce.provider.BouncyCastleProvider;\n\nimport java.security.InvalidKeyException;\nimport java.security.NoSuchAlgorithmException;\nimport java.security.SecureRandom;\n\nimport javax.crypto.BadPaddingException;\nimport javax.crypto.Cipher;\nimport javax.crypto.IllegalBlockSizeException;\nimport javax.crypto.NoSuchPaddingException;\nimport javax.crypto.SecretKey;\nimport javax.crypto.spec.SecretKeySpec;\n\nimport io.github.muntashirakon.AppManager.backup.CryptoUtils;\nimport io.github.muntashirakon.AppManager.crypto.ks.KeyPair;\nimport io.github.muntashirakon.AppManager.crypto.ks.KeyStoreManager;\n\npublic class ECCCrypto extends AESCrypto {\n    public static final String TAG = \"ECCCrypto\";\n\n    public static final String ECC_EXT = \".ecc\";\n    public static final String ECC_KEY_ALIAS = \"backup_ecc\";\n\n    private static final String ECC_CIPHER_TYPE = \"ECIES\";\n    private static final int AES_KEY_SIZE_BITS = 256;\n\n    public ECCCrypto(@NonNull byte[] iv, @Nullable byte[] encryptedAesKey) throws CryptoException {\n        super(iv, CryptoUtils.MODE_ECC, encryptedAesKey);\n    }\n\n    @NonNull\n    @Override\n    public byte[] getEncryptedAesKey() throws CryptoException {\n        return super.getEncryptedAesKey();\n    }\n\n    @NonNull\n    static SecretKey generateAesKey() {\n        SecureRandom random = new SecureRandom();\n        byte[] key = new byte[AES_KEY_SIZE_BITS/8];\n        random.nextBytes(key);\n        return new SecretKeySpec(key, \"AES\");\n    }\n\n    @NonNull\n    static SecretKey decryptAesKey(@NonNull byte[] encryptedAesKey) throws CryptoException {\n        KeyPair keyPair;\n        try {\n            KeyStoreManager keyStoreManager = KeyStoreManager.getInstance();\n            keyPair = keyStoreManager.getKeyPair(ECC_KEY_ALIAS);\n            if (keyPair == null) {\n                throw new CryptoException(\"No KeyPair with alias \" + ECC_KEY_ALIAS);\n            }\n        } catch (Exception e) {\n            throw new CryptoException(e);\n        }\n        try {\n            Cipher cipher = Cipher.getInstance(ECC_CIPHER_TYPE, new BouncyCastleProvider());\n            cipher.init(Cipher.DECRYPT_MODE, keyPair.getPrivateKey());\n            return new SecretKeySpec(cipher.doFinal(encryptedAesKey), \"AES\");\n        } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | BadPaddingException\n                | IllegalBlockSizeException e) {\n            throw new CryptoException(e);\n        }\n    }\n\n    @NonNull\n    static byte[] encryptAesKey(@NonNull SecretKey key) throws CryptoException {\n        KeyPair keyPair;\n        try {\n            KeyStoreManager keyStoreManager = KeyStoreManager.getInstance();\n            keyPair = keyStoreManager.getKeyPair(ECC_KEY_ALIAS);\n            if (keyPair == null) {\n                throw new CryptoException(\"No KeyPair with alias \" + ECC_KEY_ALIAS);\n            }\n        } catch (Exception e) {\n            throw new CryptoException(e);\n        }\n        try {\n            Cipher cipher = Cipher.getInstance(ECC_CIPHER_TYPE, new BouncyCastleProvider());\n            cipher.init(Cipher.ENCRYPT_MODE, keyPair.getPublicKey());\n            return cipher.doFinal(key.getEncoded());\n        } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | BadPaddingException\n                | IllegalBlockSizeException e) {\n            throw new CryptoException(e);\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/crypto/OpenPGPCrypto.java",
    "content": "// SPDX-License-Identifier: MIT AND GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.crypto;\n\nimport android.app.Notification;\nimport android.app.PendingIntent;\nimport android.content.BroadcastReceiver;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.IntentFilter;\nimport android.os.Handler;\nimport android.os.Looper;\nimport android.os.SystemClock;\n\nimport androidx.annotation.AnyThread;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.UiThread;\nimport androidx.annotation.WorkerThread;\nimport androidx.core.app.NotificationCompat;\nimport androidx.core.app.PendingIntentCompat;\nimport androidx.core.content.ContextCompat;\n\nimport org.openintents.openpgp.IOpenPgpService2;\nimport org.openintents.openpgp.OpenPgpError;\nimport org.openintents.openpgp.util.OpenPgpApi;\nimport org.openintents.openpgp.util.OpenPgpServiceConnection;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\n\nimport io.github.muntashirakon.AppManager.BuildConfig;\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.backup.CryptoUtils;\nimport io.github.muntashirakon.AppManager.intercept.IntentCompat;\nimport io.github.muntashirakon.AppManager.logs.Log;\nimport io.github.muntashirakon.AppManager.settings.Prefs;\nimport io.github.muntashirakon.AppManager.utils.NotificationUtils;\nimport io.github.muntashirakon.io.Path;\n\n// Copyright 2018 jensstein\npublic class OpenPGPCrypto implements Crypto {\n    public static final String TAG = \"OpenPGPCrypto\";\n\n    public static final String ACTION_OPEN_PGP_INTERACTION_BEGIN = BuildConfig.APPLICATION_ID + \".action.OPEN_PGP_INTERACTION_BEGIN\";\n    public static final String ACTION_OPEN_PGP_INTERACTION_END = BuildConfig.APPLICATION_ID + \".action.OPEN_PGP_INTERACTION_END\";\n\n    public static final String GPG_EXT = \".gpg\";\n\n    private OpenPgpServiceConnection mService;\n    private boolean mSuccessFlag;\n    private boolean mErrorFlag;\n    private Path[] mInputFiles;\n    private Path[] mOutputFiles;\n    private InputStream mIs;\n    private OutputStream mOs;\n    @NonNull\n    private final long[] mKeyIds;\n    private final String mProvider;\n    private Intent mLastIntent;\n    private final Context mContext;\n    private final Handler mHandler;\n    private boolean mIsFileMode;  // Whether to en/decrypt a file than an stream\n    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {\n        @Override\n        public void onReceive(Context context, @NonNull Intent intent) {\n            if (intent.getAction() == null) return;\n            switch (intent.getAction()) {\n                case ACTION_OPEN_PGP_INTERACTION_BEGIN:\n                    break;\n                case ACTION_OPEN_PGP_INTERACTION_END:\n                    // TODO: 17/12/21 Handle this better by using CountdownLatch\n                    new Thread(() -> {\n                        try {\n                            doAction(mLastIntent, false);\n                        } catch (IOException e) {\n                            e.printStackTrace();\n                        }\n                    }).start();\n                    break;\n            }\n        }\n    };\n\n    @AnyThread\n    public OpenPGPCrypto(@NonNull Context context, @NonNull String keyIdsStr) throws CryptoException {\n        mContext = context;\n        try {\n            String[] keyIds = keyIdsStr.split(\",\");\n            mKeyIds = new long[keyIds.length];\n            for (int i = 0; i < keyIds.length; ++i) mKeyIds[i] = Long.parseLong(keyIds[i]);\n        } catch (NumberFormatException e) {\n            throw new CryptoException(e);\n        }\n        mProvider = Prefs.Encryption.getOpenPgpProvider();\n        mHandler = new Handler(Looper.getMainLooper());\n        bind();\n    }\n\n    @NonNull\n    @Override\n    public String getModeName() {\n        return CryptoUtils.MODE_OPEN_PGP;\n    }\n\n    @Override\n    public void close() {\n        // Unbind service\n        if (mService != null) mService.unbindFromService();\n        // Unregister receiver\n        mContext.unregisterReceiver(mReceiver);\n    }\n\n    @WorkerThread\n    @Override\n    public void decrypt(@NonNull Path[] inputFiles, @NonNull Path[] outputFiles) throws IOException {\n        Intent intent = new Intent(OpenPgpApi.ACTION_DECRYPT_VERIFY);\n        handleFiles(intent, inputFiles, outputFiles);\n    }\n\n    @Override\n    public void decrypt(@NonNull InputStream encryptedStream, @NonNull OutputStream unencryptedStream)\n            throws IOException {\n        Intent intent = new Intent(OpenPgpApi.ACTION_DECRYPT_VERIFY);\n        handleStreams(intent, encryptedStream, unencryptedStream);\n    }\n\n    @WorkerThread\n    @Override\n    public void encrypt(@NonNull Path[] inputFiles, @NonNull Path[] outputFiles) throws IOException {\n        Intent intent = new Intent(OpenPgpApi.ACTION_ENCRYPT);\n        intent.putExtra(OpenPgpApi.EXTRA_KEY_IDS, mKeyIds);\n        handleFiles(intent, inputFiles, outputFiles);\n    }\n\n    @Override\n    public void encrypt(@NonNull InputStream unencryptedStream, @NonNull OutputStream encryptedStream)\n            throws IOException {\n        Intent intent = new Intent(OpenPgpApi.ACTION_ENCRYPT);\n        intent.putExtra(OpenPgpApi.EXTRA_KEY_IDS, mKeyIds);\n        handleStreams(intent, unencryptedStream, encryptedStream);\n    }\n\n    @WorkerThread\n    private void handleFiles(Intent intent, @NonNull Path[] inputFiles, @NonNull Path[] outputFiles) throws IOException {\n        mIsFileMode = true;\n        waitForServiceBound();\n        mIs = null;\n        mOs = null;\n        mInputFiles = inputFiles;\n        mOutputFiles = outputFiles;\n        mLastIntent = intent;\n        doAction(intent, true);\n    }\n\n    @WorkerThread\n    private void handleStreams(Intent intent, @NonNull InputStream is, @NonNull OutputStream os)\n            throws IOException {\n        mIsFileMode = false;\n        waitForServiceBound();\n        mIs = is;\n        mOs = os;\n        mInputFiles = new Path[0];\n        mOutputFiles = new Path[0];\n        mLastIntent = intent;\n        doAction(intent, true);\n    }\n\n    @WorkerThread\n    private void doAction(Intent intent, boolean waitForResult) throws IOException {\n        if (mIsFileMode) {\n            doActionForFiles(intent, waitForResult);\n        } else {\n            doActionForStream(intent, waitForResult);\n        }\n    }\n\n    @WorkerThread\n    private void doActionForFiles(Intent intent, boolean waitForResult) throws IOException {\n        mErrorFlag = false;\n        // `files` is never null here\n        if (mInputFiles.length == 0) {\n            Log.d(TAG, \"No files to de/encrypt\");\n            return;\n        }\n        if (mInputFiles.length != mOutputFiles.length) {\n            throw new IOException(\"The number of input and output files are not the same.\");\n        }\n        for (int i = 0; i < mInputFiles.length; i++) {\n            Path inputPath = mInputFiles[i];\n            Path outputPath = mOutputFiles[i];\n            Log.i(TAG, \"Input: %s\\nOutput: %s\", inputPath, outputPath);\n            InputStream is = inputPath.openInputStream();\n            OutputStream os = outputPath.openOutputStream();\n            OpenPgpApi api = new OpenPgpApi(mContext, mService.getService());\n            Intent result = api.executeApi(intent, is, os);\n            mHandler.post(() -> handleResult(result));\n            if (waitForResult) waitForResult();\n            if (mErrorFlag) {\n                outputPath.delete();\n                throw new IOException(\"Error occurred during en/decryption process\");\n            }\n        }\n        // Total success\n    }\n\n    @WorkerThread\n    private void doActionForStream(Intent intent, boolean waitForResult) throws IOException {\n        mErrorFlag = false;\n        OpenPgpApi api = new OpenPgpApi(mContext, mService.getService());\n        Intent result = api.executeApi(intent, mIs, mOs);\n        mHandler.post(() -> handleResult(result));\n        if (waitForResult) waitForResult();\n        if (mErrorFlag) {\n            throw new IOException(\"Error occurred during en/decryption process\");\n        }\n    }\n\n    private void bind() {\n        mService = new OpenPgpServiceConnection(mContext, mProvider,\n                new OpenPgpServiceConnection.OnBound() {\n                    @Override\n                    public void onBound(IOpenPgpService2 service) {\n                        Log.i(OpenPgpApi.TAG, \"Service bound.\");\n                    }\n\n                    @Override\n                    public void onError(Exception e) {\n                        Log.e(OpenPgpApi.TAG, \"Exception on binding.\", e);\n                    }\n                }\n        );\n        mService.bindToService();\n        // Start broadcast receiver\n        IntentFilter filter = new IntentFilter(ACTION_OPEN_PGP_INTERACTION_BEGIN);\n        filter.addAction(ACTION_OPEN_PGP_INTERACTION_END);\n        ContextCompat.registerReceiver(mContext, mReceiver, filter, ContextCompat.RECEIVER_NOT_EXPORTED);\n    }\n\n    @WorkerThread\n    private void waitForServiceBound() throws IOException {\n        int i = 0;\n        while (mService.getService() == null) {\n            if (i % 20 == 0) {\n                Log.i(TAG, \"Waiting for openpgp-api service to be bound\");\n            }\n            SystemClock.sleep(100);\n            if (i > 1000)\n                break;\n            i++;\n        }\n        if (mService.getService() == null) {\n            throw new IOException(\"OpenPGPService could not be bound.\");\n        }\n    }\n\n    @WorkerThread\n    private void waitForResult() {\n        int i = 0;\n        while (!mSuccessFlag && !mErrorFlag) {\n            if (i % 200 == 0) Log.i(TAG, \"Waiting for user interaction\");\n            SystemClock.sleep(100);\n            if (i > 1000)\n                break;\n            i++;\n        }\n    }\n\n    @UiThread\n    private void handleResult(@NonNull Intent result) {\n        mSuccessFlag = false;\n        switch (result.getIntExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR)) {\n            case OpenPgpApi.RESULT_CODE_SUCCESS:\n                Log.i(TAG, \"en/decryption successful.\");\n                mSuccessFlag = true;\n                break;\n            case OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED: {\n                Log.i(TAG, \"User interaction required. Sending intent...\");\n                Intent broadcastIntent = new Intent(OpenPGPCrypto.ACTION_OPEN_PGP_INTERACTION_BEGIN);\n                broadcastIntent.setPackage(mContext.getPackageName());\n                mContext.sendBroadcast(broadcastIntent);\n                // Intent wrapper\n                Intent intent = new Intent(mContext, OpenPGPCryptoActivity.class);\n                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);\n                intent.putExtra(OpenPgpApi.RESULT_INTENT, IntentCompat.getParcelableExtra(result, OpenPgpApi.RESULT_INTENT, PendingIntent.class));\n                String openPGP = \"Open PGP\";\n                // We don't need a DELETE intent since the time will be expired anyway\n                NotificationCompat.Builder builder = NotificationUtils.getHighPriorityNotificationBuilder(mContext)\n                        .setAutoCancel(true)\n                        .setDefaults(Notification.DEFAULT_ALL)\n                        .setWhen(System.currentTimeMillis())\n                        .setSmallIcon(R.drawable.ic_default_notification)\n                        .setTicker(openPGP)\n                        .setContentTitle(openPGP)\n                        .setSubText(openPGP)\n                        .setContentText(mContext.getString(R.string.allow_open_pgp_operation));\n                builder.setContentIntent(PendingIntentCompat.getActivity(mContext, 0, intent,\n                        PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_UPDATE_CURRENT, false));\n                NotificationUtils.displayHighPriorityNotification(mContext, builder.build());\n                break;\n            }\n            case OpenPgpApi.RESULT_CODE_ERROR:\n                mErrorFlag = true;\n                OpenPgpError error = IntentCompat.getParcelableExtra(result, OpenPgpApi.RESULT_ERROR, OpenPgpError.class);\n                if (error != null) {\n                    Log.e(TAG, \"handleResult: (%d) %s\", error.getErrorId(), error.getMessage());\n                } else Log.e(TAG, \"handleResult: Error occurred during en/decryption process\");\n                break;\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/crypto/OpenPGPCryptoActivity.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.crypto;\n\nimport android.app.PendingIntent;\nimport android.content.Intent;\nimport android.os.Bundle;\n\nimport androidx.activity.result.ActivityResultLauncher;\nimport androidx.activity.result.IntentSenderRequest;\nimport androidx.activity.result.contract.ActivityResultContracts;\nimport androidx.annotation.Nullable;\n\nimport org.openintents.openpgp.util.OpenPgpApi;\n\nimport java.util.Objects;\n\nimport io.github.muntashirakon.AppManager.BaseActivity;\nimport io.github.muntashirakon.AppManager.intercept.IntentCompat;\n\npublic class OpenPGPCryptoActivity extends BaseActivity {\n    private final ActivityResultLauncher<IntentSenderRequest> mConfirmationLauncher = registerForActivityResult(\n            new ActivityResultContracts.StartIntentSenderForResult(), result -> {\n                Intent broadcastIntent = new Intent(OpenPGPCrypto.ACTION_OPEN_PGP_INTERACTION_END);\n                broadcastIntent.setPackage(getPackageName());\n                sendBroadcast(broadcastIntent);\n                finish();\n            });\n\n    @Override\n    public boolean getTransparentBackground() {\n        return true;\n    }\n\n    @Override\n    protected void onAuthenticated(@Nullable Bundle savedInstanceState) {\n        if (getIntent() != null) onNewIntent(getIntent());\n        else finish();\n    }\n\n    @Override\n    protected void onNewIntent(Intent intent) {\n        super.onNewIntent(intent);\n        PendingIntent pi = Objects.requireNonNull(IntentCompat.getParcelableExtra(intent, OpenPgpApi.RESULT_INTENT, PendingIntent.class));\n        mConfirmationLauncher.launch(new IntentSenderRequest.Builder(pi).build());\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/crypto/RSACrypto.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.crypto;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport java.security.InvalidKeyException;\nimport java.security.NoSuchAlgorithmException;\nimport java.security.SecureRandom;\n\nimport javax.crypto.BadPaddingException;\nimport javax.crypto.Cipher;\nimport javax.crypto.IllegalBlockSizeException;\nimport javax.crypto.NoSuchPaddingException;\nimport javax.crypto.SecretKey;\nimport javax.crypto.spec.SecretKeySpec;\n\nimport io.github.muntashirakon.AppManager.backup.CryptoUtils;\nimport io.github.muntashirakon.AppManager.crypto.ks.KeyPair;\nimport io.github.muntashirakon.AppManager.crypto.ks.KeyStoreManager;\n\npublic class RSACrypto extends AESCrypto {\n    public static final String TAG = \"RSACrypto\";\n\n    public static final String RSA_EXT = \".rsa\";\n    public static final String RSA_KEY_ALIAS = \"backup_rsa\";\n\n    private static final String RSA_CIPHER_TYPE = \"RSA/NONE/OAEPPadding\";  // 42 bytes padding\n    private static final int AES_KEY_SIZE_BITS = 256;\n\n    public RSACrypto(@NonNull byte[] iv, @Nullable byte[] encryptedAesKey) throws CryptoException {\n        // This class extends AES crypto as RSA uses hybrid encryption\n        super(iv, CryptoUtils.MODE_RSA, encryptedAesKey);\n    }\n\n    @NonNull\n    @Override\n    public byte[] getEncryptedAesKey() throws CryptoException {\n        return super.getEncryptedAesKey();\n    }\n\n    @NonNull\n    static SecretKey generateAesKey() {\n        SecureRandom random = new SecureRandom();\n        byte[] key = new byte[AES_KEY_SIZE_BITS/8];\n        random.nextBytes(key);\n        return new SecretKeySpec(key, \"AES\");\n    }\n\n    @NonNull\n    static SecretKey decryptAesKey(@NonNull byte[] encryptedAesKey) throws CryptoException {\n        // We only have 32/64 bytes AES key with either 256 or 512 bytes minus 42 bytes of data,\n        // so it should work without issues\n        KeyPair keyPair;\n        try {\n            KeyStoreManager keyStoreManager = KeyStoreManager.getInstance();\n            keyPair = keyStoreManager.getKeyPair(RSA_KEY_ALIAS);\n            if (keyPair == null) {\n                throw new CryptoException(\"No KeyPair with alias \" + RSA_KEY_ALIAS);\n            }\n        } catch (Exception e) {\n            throw new CryptoException(e);\n        }\n        try {\n            Cipher cipher = Cipher.getInstance(RSA_CIPHER_TYPE);\n            cipher.init(Cipher.DECRYPT_MODE, keyPair.getPrivateKey());\n            return new SecretKeySpec(cipher.doFinal(encryptedAesKey), \"AES\");\n        } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | BadPaddingException\n                | IllegalBlockSizeException e) {\n            throw new CryptoException(e);\n        }\n    }\n\n    @NonNull\n    static byte[] encryptAesKey(@NonNull SecretKey key) throws CryptoException {\n        // We only have 32/64 bytes AES key with either 256 or 512 bytes minus 42 bytes of data,\n        // so it should work without issues\n        KeyPair keyPair;\n        try {\n            KeyStoreManager keyStoreManager = KeyStoreManager.getInstance();\n            keyPair = keyStoreManager.getKeyPair(RSA_KEY_ALIAS);\n            if (keyPair == null) {\n                throw new CryptoException(\"No KeyPair with alias \" + RSA_KEY_ALIAS);\n            }\n        } catch (Exception e) {\n            throw new CryptoException(e);\n        }\n        try {\n            Cipher cipher = Cipher.getInstance(RSA_CIPHER_TYPE);\n            cipher.init(Cipher.ENCRYPT_MODE, keyPair.getPublicKey());\n            return cipher.doFinal(key.getEncoded());\n        } catch (NoSuchAlgorithmException | NoSuchPaddingException | InvalidKeyException | BadPaddingException\n                | IllegalBlockSizeException e) {\n            throw new CryptoException(e);\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/crypto/RandomChar.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.crypto;\n\nimport androidx.annotation.NonNull;\n\nimport java.security.SecureRandom;\nimport java.util.Locale;\nimport java.util.Objects;\nimport java.util.Random;\n\npublic class RandomChar {\n    public static final String UPPERCASE = \"ABCDEFGHIJKLMNOPQRSTUVWXYZ\";\n    public static final String LOWERCASE = UPPERCASE.toLowerCase(Locale.ROOT);\n    public static final String DIGITS = \"0123456789\";\n    public static final String ALPHA_NUMERIC = UPPERCASE + LOWERCASE + DIGITS;\n\n    private final Random mRandom;\n    private final char[] mSymbols;\n\n    public RandomChar() {\n        this(new SecureRandom());\n    }\n\n    public RandomChar(@NonNull Random random) {\n        this(random, ALPHA_NUMERIC);\n    }\n\n    public RandomChar(@NonNull Random random, @NonNull String symbols) {\n        if (symbols.length() < 2) throw new IllegalArgumentException();\n        mRandom = Objects.requireNonNull(random);\n        mSymbols = symbols.toCharArray();\n    }\n\n    public void nextChars(@NonNull char[] chars) {\n        for (int idx = 0; idx < chars.length; ++idx) {\n            chars[idx] = mSymbols[mRandom.nextInt(mSymbols.length)];\n        }\n    }\n\n    public char nextChar() {\n        return mSymbols[mRandom.nextInt(mSymbols.length)];\n    }\n}"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/crypto/auth/AuthFeatureDemultiplexer.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.crypto.auth;\n\nimport android.content.Intent;\nimport android.os.Bundle;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport java.util.Objects;\n\nimport io.github.muntashirakon.AppManager.BaseActivity;\nimport io.github.muntashirakon.AppManager.profiles.ProfileApplierActivity;\n\npublic class AuthFeatureDemultiplexer extends BaseActivity {\n    public static final String EXTRA_FEATURE = \"feature\";\n\n    @Override\n    protected void onAuthenticated(@Nullable Bundle savedInstanceState) {\n        Intent intent = getIntent();\n        if (!intent.hasExtra(EXTRA_AUTH) || !intent.hasExtra(EXTRA_FEATURE)) {\n            // It does not have the required extras, ignore the request\n            finishAndRemoveTask();\n            return;\n        }\n        handleRequest(intent);\n    }\n\n    @Override\n    public boolean getTransparentBackground() {\n        return true;\n    }\n\n    private void handleRequest(@NonNull Intent intent) {\n        String auth = intent.getStringExtra(EXTRA_AUTH);\n        String feature = intent.getStringExtra(EXTRA_FEATURE);\n\n        intent.removeExtra(EXTRA_AUTH);\n        intent.removeExtra(EXTRA_FEATURE);\n\n        if (!AuthManager.getKey().equals(auth)) {\n            // Invalid authorization key\n            // TODO: 16/3/22 Display a nice error message\n            finishAndRemoveTask();\n            return;\n        }\n\n        switch (Objects.requireNonNull(feature)) {\n            case \"profile\":\n                launchProfile(intent);\n                break;\n            default:\n                throw new RuntimeException(\"Invalid feature: \" + feature);\n        }\n        finish();\n    }\n\n    public void launchProfile(@NonNull Intent intent) {\n        String profileId = intent.getStringExtra(ProfileApplierActivity.EXTRA_PROFILE_ID);\n        String state = intent.getStringExtra(ProfileApplierActivity.EXTRA_STATE);\n        startActivity(ProfileApplierActivity.getAutomationIntent(getApplicationContext(), profileId, state));\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/crypto/auth/AuthManager.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.crypto.auth;\n\nimport androidx.annotation.NonNull;\n\nimport io.github.muntashirakon.AppManager.crypto.RandomChar;\nimport io.github.muntashirakon.AppManager.utils.AppPref;\n\npublic final class AuthManager {\n    public static final int AUTH_KEY_SIZE = 24;\n\n    @NonNull\n    public static String getKey() {\n        return AppPref.getString(AppPref.PrefKey.PREF_AUTHORIZATION_KEY_STR);\n    }\n\n    public static void setKey(@NonNull String key) {\n        AppPref.set(AppPref.PrefKey.PREF_AUTHORIZATION_KEY_STR, key);\n    }\n\n    @NonNull\n    public static String generateKey() {\n        char[] authKey = new char[AUTH_KEY_SIZE];\n        new RandomChar().nextChars(authKey);\n        return new String(authKey);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/crypto/auth/AuthManagerActivity.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.crypto.auth;\n\nimport android.os.Bundle;\nimport android.view.MenuItem;\nimport android.view.View;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport com.google.android.material.dialog.MaterialAlertDialogBuilder;\nimport com.google.android.material.textfield.TextInputEditText;\nimport com.google.android.material.textfield.TextInputLayout;\n\nimport io.github.muntashirakon.AppManager.BaseActivity;\nimport io.github.muntashirakon.AppManager.R;\n\npublic class AuthManagerActivity extends BaseActivity {\n    private TextInputLayout mAuthKeyLayout;\n    private TextInputEditText mAuthKeyField;\n\n    @Override\n    protected void onAuthenticated(@Nullable Bundle savedInstanceState) {\n        setContentView(R.layout.activity_auth_management);\n        setSupportActionBar(findViewById(R.id.toolbar));\n        findViewById(R.id.progress_linear).setVisibility(View.GONE);\n        mAuthKeyLayout = findViewById(R.id.auth_field);\n        mAuthKeyField = findViewById(android.R.id.text1);\n        mAuthKeyField.setText(AuthManager.getKey());\n        mAuthKeyLayout.setEndIconOnClickListener(v -> new MaterialAlertDialogBuilder(this)\n                .setTitle(R.string.regenerate_auth_key)\n                .setMessage(R.string.regenerate_auth_key_warning)\n                .setNegativeButton(R.string.no, null)\n                .setPositiveButton(R.string.yes, (dialog, which) -> {\n                    String authKey = AuthManager.generateKey();\n                    AuthManager.setKey(authKey);\n                    mAuthKeyField.setText(authKey);\n                })\n                .show());\n    }\n\n    @Override\n    public boolean onOptionsItemSelected(@NonNull MenuItem item) {\n        if (item.getItemId() == android.R.id.home) {\n            finish();\n            return true;\n        }\n        return super.onOptionsItemSelected(item);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/crypto/ks/AesEncryptedData.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.crypto.ks;\n\nimport androidx.core.util.Pair;\n\nclass AesEncryptedData extends Pair<byte[], byte[]> {\n    /**\n     * Constructor for a Pair.\n     *\n     * @param iv            the iv object in the Pair\n     * @param encryptedData the encryptedData object in the pair\n     */\n    public AesEncryptedData(byte[] iv, byte[] encryptedData) {\n        super(iv, encryptedData);\n    }\n\n    public byte[] getIv() {\n        return first;\n    }\n\n    public byte[] getEncryptedData() {\n        return second;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/crypto/ks/CompatUtil.java",
    "content": "// SPDX-License-Identifier: Apache-2.0 AND GPL-3-or-later\n\npackage io.github.muntashirakon.AppManager.crypto.ks;\n\nimport android.content.Context;\nimport android.content.SharedPreferences;\nimport android.os.Build;\nimport android.security.keystore.KeyGenParameterSpec;\nimport android.security.keystore.KeyProperties;\nimport android.util.Base64;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport java.io.IOException;\nimport java.math.BigInteger;\nimport java.nio.ByteBuffer;\nimport java.security.InvalidAlgorithmParameterException;\nimport java.security.InvalidKeyException;\nimport java.security.KeyPair;\nimport java.security.KeyPairGenerator;\nimport java.security.KeyStore;\nimport java.security.KeyStoreException;\nimport java.security.NoSuchAlgorithmException;\nimport java.security.NoSuchProviderException;\nimport java.security.PrivateKey;\nimport java.security.SecureRandom;\nimport java.security.UnrecoverableKeyException;\nimport java.security.cert.CertificateException;\nimport java.security.spec.AlgorithmParameterSpec;\nimport java.security.spec.RSAKeyGenParameterSpec;\nimport java.util.Calendar;\n\nimport javax.crypto.BadPaddingException;\nimport javax.crypto.Cipher;\nimport javax.crypto.IllegalBlockSizeException;\nimport javax.crypto.KeyGenerator;\nimport javax.crypto.NoSuchPaddingException;\nimport javax.crypto.SecretKey;\nimport javax.crypto.ShortBufferException;\nimport javax.crypto.spec.GCMParameterSpec;\nimport javax.crypto.spec.IvParameterSpec;\nimport javax.crypto.spec.SecretKeySpec;\nimport javax.security.auth.DestroyFailedException;\nimport javax.security.auth.x500.X500Principal;\n\nimport io.github.muntashirakon.AppManager.logs.Log;\n\n// Copyright 2021 Muntashir Al-Islam\n// Copyright 2018 New Vector Ltd\npublic class CompatUtil {\n    private static final String TAG = CompatUtil.class.getSimpleName();\n    private static final String ANDROID_KEY_STORE_PROVIDER = \"AndroidKeyStore\";\n    private static final String AES_GCM_CIPHER_TYPE = \"AES/GCM/NoPadding\";\n    private static final int AES_GCM_KEY_SIZE_IN_BITS = 128;\n    private static final int AES_GCM_IV_LENGTH = 12;\n    private static final String AES_LOCAL_PROTECTION_KEY_ALIAS = \"aes_local_protection\";\n\n    private static final String RSA_WRAP_LOCAL_PROTECTION_KEY_ALIAS = \"rsa_wrap_local_protection\";\n    private static final String RSA_WRAP_CIPHER_TYPE = \"RSA/NONE/PKCS1Padding\";\n    private static final String AES_WRAPPED_PROTECTION_KEY_SHARED_PREFERENCE = \"aes_wrapped_local_protection\";\n\n    private static final String SHARED_KEY_ANDROID_VERSION_WHEN_KEY_HAS_BEEN_GENERATED =\n            \"android_version_when_key_has_been_generated\";\n\n    private static SecureRandom sPrng;\n\n    /**\n     * Returns the AES key used for local storage encryption/decryption with AES/GCM.\n     * The key is created if it does not exist already in the keystore.\n     * From Marshmallow, this key is generated and operated directly from the android keystore.\n     * From KitKat and before Marshmallow, this key is stored in the application shared preferences\n     * wrapped by a RSA key generated and operated directly from the android keystore.\n     *\n     * @param context the context holding the application shared preferences\n     */\n    @SuppressWarnings({\"deprecation\", \"InlinedApi\"})\n    @NonNull\n    private static synchronized SecretKeyAndVersion getAesGcmLocalProtectionKey(@NonNull Context context)\n            throws KeyStoreException, CertificateException, NoSuchAlgorithmException, IOException,\n            NoSuchProviderException, InvalidAlgorithmParameterException, NoSuchPaddingException,\n            InvalidKeyException, IllegalBlockSizeException, UnrecoverableKeyException {\n        KeyStore keyStore = KeyStore.getInstance(ANDROID_KEY_STORE_PROVIDER);\n        keyStore.load(null);\n\n        Log.i(TAG, \"Loading local protection key\");\n        SharedPreferences sharedPreferences = context.getSharedPreferences(\"keystore\", Context.MODE_PRIVATE);\n        // Get the version of Android when the key has been generated, default to the current version of the system.\n        // In the latter case, the key will be generated.\n        int androidVersionWhenTheKeyHasBeenGenerated = sharedPreferences.getInt(\n                SHARED_KEY_ANDROID_VERSION_WHEN_KEY_HAS_BEEN_GENERATED, Build.VERSION.SDK_INT);\n\n        // Check if there's a key in the Android keystore (M and later)\n        if (keyStore.containsAlias(AES_LOCAL_PROTECTION_KEY_ALIAS)) {\n            Log.i(TAG, \"AES local protection key found in keystore\");\n            SecretKey secretKey = (SecretKey) keyStore.getKey(AES_LOCAL_PROTECTION_KEY_ALIAS, null);\n            if (secretKey == null) {\n                throw new KeyStoreException(\"Could not load AES local protection key from keystore\");\n            }\n            return new SecretKeyAndVersion(secretKey, androidVersionWhenTheKeyHasBeenGenerated);\n        }\n\n        // Check if a key has been created on version < M (such as, in case of an OS upgrade)\n        SecretKey secretKey = readKeyApiL(sharedPreferences, keyStore);\n        if (secretKey != null) {\n            return new SecretKeyAndVersion(secretKey, androidVersionWhenTheKeyHasBeenGenerated);\n        }\n\n        // Otherwise generate key\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {\n            Log.i(TAG, \"Generating AES key with keystore\");\n            KeyGenerator generator = KeyGenerator.getInstance(KeyProperties.KEY_ALGORITHM_AES,\n                    ANDROID_KEY_STORE_PROVIDER);\n            generator.init(new KeyGenParameterSpec.Builder(AES_LOCAL_PROTECTION_KEY_ALIAS,\n                    KeyProperties.PURPOSE_ENCRYPT | KeyProperties.PURPOSE_DECRYPT)\n                    .setBlockModes(KeyProperties.BLOCK_MODE_GCM)\n                    .setKeySize(AES_GCM_KEY_SIZE_IN_BITS)\n                    .setEncryptionPaddings(KeyProperties.ENCRYPTION_PADDING_NONE)\n                    .build());\n            secretKey = generator.generateKey();\n\n            sharedPreferences.edit()\n                    .putInt(SHARED_KEY_ANDROID_VERSION_WHEN_KEY_HAS_BEEN_GENERATED, Build.VERSION.SDK_INT)\n                    .apply();\n            return new SecretKeyAndVersion(secretKey, androidVersionWhenTheKeyHasBeenGenerated);\n        }\n\n        Log.i(TAG, \"Generating RSA key pair with keystore\");\n        KeyPairGenerator generator = KeyPairGenerator.getInstance(\"RSA\", ANDROID_KEY_STORE_PROVIDER);\n        Calendar start = Calendar.getInstance();\n        Calendar end = Calendar.getInstance();\n        end.add(Calendar.YEAR, 10);\n\n        generator.initialize(new android.security.KeyPairGeneratorSpec.Builder(context)\n                .setAlgorithmParameterSpec(new RSAKeyGenParameterSpec(2048,\n                        RSAKeyGenParameterSpec.F4))\n                .setAlias(RSA_WRAP_LOCAL_PROTECTION_KEY_ALIAS)\n                .setSubject(new X500Principal(\"CN=App Manager\"))\n                .setStartDate(start.getTime())\n                .setEndDate(end.getTime())\n                .setSerialNumber(BigInteger.ONE)\n                .build());\n        KeyPair keyPair = generator.generateKeyPair();\n\n        Log.i(TAG, \"Generating wrapped AES key\");\n\n        byte[] aesKeyRaw = new byte[AES_GCM_KEY_SIZE_IN_BITS / Byte.SIZE];\n        getPrng().nextBytes(aesKeyRaw);\n        secretKey = new SecretKeySpec(aesKeyRaw, \"AES\");\n\n        Cipher cipher = Cipher.getInstance(RSA_WRAP_CIPHER_TYPE);\n        cipher.init(Cipher.WRAP_MODE, keyPair.getPublic());\n        byte[] wrappedAesKey = cipher.wrap(secretKey);\n\n        sharedPreferences.edit()\n                .putString(AES_WRAPPED_PROTECTION_KEY_SHARED_PREFERENCE,\n                        Base64.encodeToString(wrappedAesKey, 0))\n                .putInt(SHARED_KEY_ANDROID_VERSION_WHEN_KEY_HAS_BEEN_GENERATED, Build.VERSION.SDK_INT)\n                .apply();\n\n        return new SecretKeyAndVersion(secretKey, androidVersionWhenTheKeyHasBeenGenerated);\n    }\n\n    /**\n     * Read the key, which may have been stored when the OS was < M\n     *\n     * @param sharedPreferences shared pref\n     * @param keyStore          key store\n     * @return the key if it exists or null\n     */\n    @Nullable\n    private static SecretKey readKeyApiL(@NonNull SharedPreferences sharedPreferences, @NonNull KeyStore keyStore)\n            throws KeyStoreException, NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException,\n            UnrecoverableKeyException {\n        String wrappedAesKeyString = sharedPreferences.getString(AES_WRAPPED_PROTECTION_KEY_SHARED_PREFERENCE, null);\n        if (wrappedAesKeyString != null && keyStore.containsAlias(RSA_WRAP_LOCAL_PROTECTION_KEY_ALIAS)) {\n            Log.i(TAG, \"RSA + wrapped AES local protection keys found in keystore\");\n            PrivateKey privateKey = (PrivateKey) keyStore.getKey(RSA_WRAP_LOCAL_PROTECTION_KEY_ALIAS, null);\n            byte[] wrappedAesKey = Base64.decode(wrappedAesKeyString, 0);\n            Cipher cipher = Cipher.getInstance(RSA_WRAP_CIPHER_TYPE);\n            cipher.init(Cipher.UNWRAP_MODE, privateKey);\n            return (SecretKey) cipher.unwrap(wrappedAesKey, \"AES\", Cipher.SECRET_KEY);\n        }\n        // Key does not exist\n        return null;\n    }\n\n    /**\n     * Returns the unique SecureRandom instance shared for all local storage encryption operations.\n     */\n    @NonNull\n    public static SecureRandom getPrng() {\n        if (sPrng == null) {\n            sPrng = new SecureRandom();\n        }\n        return sPrng;\n    }\n\n    /**\n     * Encrypt the given data\n     *\n     * @param unencryptedData The data to be encrypted\n     * @param context         The context holding the application shared preferences\n     */\n    @NonNull\n    public static AesEncryptedData getEncryptedData(@NonNull byte[] unencryptedData, @NonNull Context context)\n            throws InvalidAlgorithmParameterException, UnrecoverableKeyException, NoSuchPaddingException,\n            IllegalBlockSizeException, CertificateException, KeyStoreException, NoSuchAlgorithmException,\n            IOException, NoSuchProviderException, InvalidKeyException, BadPaddingException, DestroyFailedException {\n        SecretKeyAndVersion keyAndVersion = getAesGcmLocalProtectionKey(context);\n\n        Cipher cipher = Cipher.getInstance(AES_GCM_CIPHER_TYPE);\n        byte[] iv;\n\n        if (keyAndVersion.getAndroidVersionWhenTheKeyHasBeenGenerated() >= Build.VERSION_CODES.M) {\n            cipher.init(Cipher.ENCRYPT_MODE, keyAndVersion.getSecretKey(), getPrng());\n            iv = cipher.getIV();\n        } else {\n            iv = new byte[AES_GCM_IV_LENGTH];\n            getPrng().nextBytes(iv);\n            cipher.init(Cipher.ENCRYPT_MODE, keyAndVersion.getSecretKey(), new IvParameterSpec(iv));\n        }\n\n        if (iv.length != AES_GCM_IV_LENGTH) {\n            throw new InvalidAlgorithmParameterException(\"Invalid IV length \" + iv.length);\n        }\n\n        byte[] encryptedData = cipher.doFinal(unencryptedData);\n        SecretKeyCompat.destroy(keyAndVersion.getSecretKey());\n        return new AesEncryptedData(iv, encryptedData);\n    }\n\n    /**\n     * Decrypt given data.\n     *\n     * @param context       The context holding the application shared preferences\n     * @param encryptedData Data to be decrypted\n     * @return Decrypted data.\n     */\n    @NonNull\n    public static byte[] decryptData(@NonNull Context context, @NonNull byte[] encryptedData)\n            throws NoSuchPaddingException, NoSuchAlgorithmException, CertificateException,\n            InvalidKeyException, KeyStoreException, UnrecoverableKeyException, IllegalBlockSizeException,\n            NoSuchProviderException, InvalidAlgorithmParameterException, IOException, ShortBufferException, BadPaddingException {\n        ByteBuffer encryptedBuffer = ByteBuffer.wrap(encryptedData);\n        int iv_len = encryptedBuffer.get();\n        if (iv_len != AES_GCM_IV_LENGTH) {\n            throw new InvalidAlgorithmParameterException(\"Invalid IV length \" + iv_len);\n        }\n\n        byte[] iv = new byte[AES_GCM_IV_LENGTH];\n        encryptedBuffer.get(iv);\n\n        Cipher cipher = Cipher.getInstance(AES_GCM_CIPHER_TYPE);\n\n        SecretKeyAndVersion keyAndVersion = getAesGcmLocalProtectionKey(context);\n\n        AlgorithmParameterSpec spec;\n\n        if (keyAndVersion.getAndroidVersionWhenTheKeyHasBeenGenerated() >= Build.VERSION_CODES.M) {\n            spec = new GCMParameterSpec(AES_GCM_KEY_SIZE_IN_BITS, iv);\n        } else {\n            spec = new IvParameterSpec(iv);\n        }\n\n        cipher.init(Cipher.DECRYPT_MODE, keyAndVersion.getSecretKey(), spec);\n\n        ByteBuffer decryptedBuffer = ByteBuffer.allocate(cipher.getOutputSize(encryptedBuffer.remaining()));\n        cipher.doFinal(encryptedBuffer, decryptedBuffer);\n        return decryptedBuffer.array();\n    }\n}"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/crypto/ks/KeyPair.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.crypto.ks;\n\nimport androidx.core.util.Pair;\n\nimport java.security.PrivateKey;\nimport java.security.PublicKey;\nimport java.security.cert.Certificate;\n\nimport javax.security.auth.DestroyFailedException;\n\npublic class KeyPair extends Pair<PrivateKey, Certificate> {\n    public KeyPair(PrivateKey first, Certificate second) {\n        super(first, second);\n    }\n\n    public PrivateKey getPrivateKey() {\n        return first;\n    }\n\n    public PublicKey getPublicKey() {\n        return second.getPublicKey();\n    }\n\n    public Certificate getCertificate() {\n        return second;\n    }\n\n    public void destroy() throws DestroyFailedException {\n        try {\n            first.destroy();\n        } catch (NoSuchMethodError ignore) {\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/crypto/ks/KeyStoreActivity.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.crypto.ks;\n\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.text.Editable;\nimport android.text.TextUtils;\n\nimport androidx.activity.EdgeToEdge;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.appcompat.app.AlertDialog;\nimport androidx.appcompat.app.AppCompatActivity;\n\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.logs.Log;\nimport io.github.muntashirakon.AppManager.self.life.BuildExpiryChecker;\nimport io.github.muntashirakon.AppManager.settings.Prefs;\nimport io.github.muntashirakon.AppManager.utils.Utils;\nimport io.github.muntashirakon.dialog.TextInputDialogBuilder;\n\npublic class KeyStoreActivity extends AppCompatActivity {\n    public static final String EXTRA_ALIAS = \"key\";\n    public static final String EXTRA_KS = \"ks\";\n\n    @Override\n    protected void onCreate(@Nullable Bundle savedInstanceState) {\n        setTheme(Prefs.Appearance.getTransparentAppTheme());\n        EdgeToEdge.enable(this);\n        super.onCreate(savedInstanceState);\n        if (Boolean.TRUE.equals(BuildExpiryChecker.buildExpired())) {\n            // Build has expired\n            BuildExpiryChecker.getBuildExpiredDialog(this, (dialog, which) -> processIntentAndFinish(getIntent())).show();\n            return;\n        }\n        processIntentAndFinish(getIntent());\n    }\n\n    @Override\n    protected void onNewIntent(@NonNull Intent intent) {\n        super.onNewIntent(intent);\n        processIntentAndFinish(intent);\n    }\n\n    private void processIntentAndFinish(@Nullable Intent intent) {\n        if (intent == null) {\n            finish();\n            return;\n        }\n        String alias = intent.getStringExtra(EXTRA_ALIAS);\n        if (alias != null) {\n            displayInputKeyStoreAliasPassword(alias);\n            return;\n        }\n        if (intent.hasExtra(EXTRA_KS)) {\n            AlertDialog ksDialog;\n            if (KeyStoreManager.hasKeyStore()) {\n                // We have a keystore but not a working password, input a password (probably due to system restore)\n                ksDialog = KeyStoreManager.inputKeyStorePassword(this, this::finish);\n            } else {\n                // We neither have a KeyStore nor a password. Create a password (not necessarily a keystore)\n                ksDialog = KeyStoreManager.generateAndDisplayKeyStorePassword(this, this::finish);\n            }\n            ksDialog.show();\n            return;\n        }\n        finish();\n    }\n\n    /**\n     * @deprecated Kept for migratory purposes only, deprecated since v2.6.3. To be removed in v3.0.0.\n     */\n    @Deprecated\n    private void displayInputKeyStoreAliasPassword(@NonNull String alias) {\n        new TextInputDialogBuilder(this, getString(R.string.input_keystore_alias_pass, alias))\n                .setTitle(getString(R.string.input_keystore_alias_pass, alias))\n                .setHelperText(getString(R.string.input_keystore_alias_pass_description, alias))\n                .setPositiveButton(R.string.ok, (dialog, which, inputText, isChecked) ->\n                        savePass(KeyStoreManager.getPrefAlias(alias), inputText)\n                )\n                .setCancelable(false)\n                .setOnDismissListener(dialog -> finish())\n                .show();\n    }\n\n    private void savePass(@NonNull String prefKey, @Nullable Editable rawPassword) {\n        char[] password;\n        if (TextUtils.isEmpty(rawPassword)) {\n            try {\n                password = KeyStoreManager.getInstance().getAmKeyStorePassword();\n            } catch (Exception e) {\n                Log.e(KeyStoreManager.TAG, \"Could not get KeyStore password\", e);\n                Intent broadcastIntent = new Intent(KeyStoreManager.ACTION_KS_INTERACTION_END);\n                broadcastIntent.setPackage(getPackageName());\n                sendBroadcast(broadcastIntent);\n                return;\n            }\n        } else {\n            password = new char[rawPassword.length()];\n            rawPassword.getChars(0, rawPassword.length(), password, 0);\n        }\n        KeyStoreManager.savePass(this, prefKey, password);\n        Utils.clearChars(password);\n        Intent broadcastIntent = new Intent(KeyStoreManager.ACTION_KS_INTERACTION_END);\n        broadcastIntent.setPackage(getPackageName());\n        sendBroadcast(broadcastIntent);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/crypto/ks/KeyStoreManager.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.crypto.ks;\n\nimport android.annotation.SuppressLint;\nimport android.app.Notification;\nimport android.app.PendingIntent;\nimport android.content.BroadcastReceiver;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.IntentFilter;\nimport android.content.SharedPreferences;\nimport android.text.Editable;\nimport android.text.TextUtils;\nimport android.util.Base64;\nimport android.view.View;\nimport android.widget.Button;\n\nimport androidx.annotation.CheckResult;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.WorkerThread;\nimport androidx.appcompat.app.AlertDialog;\nimport androidx.core.app.NotificationCompat;\nimport androidx.core.app.PendingIntentCompat;\nimport androidx.core.content.ContextCompat;\nimport androidx.fragment.app.FragmentActivity;\n\nimport com.google.android.material.dialog.MaterialAlertDialogBuilder;\nimport com.google.android.material.textfield.TextInputEditText;\nimport com.google.android.material.textfield.TextInputLayout;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.security.Key;\nimport java.security.KeyStore;\nimport java.security.KeyStoreException;\nimport java.security.NoSuchAlgorithmException;\nimport java.security.PrivateKey;\nimport java.security.UnrecoverableKeyException;\nimport java.security.cert.Certificate;\nimport java.security.cert.CertificateException;\nimport java.security.cert.X509Certificate;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicBoolean;\n\nimport javax.crypto.SecretKey;\n\nimport io.github.muntashirakon.AppManager.BuildConfig;\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.adb.AdbConnectionManager;\nimport io.github.muntashirakon.AppManager.apk.signing.Signer;\nimport io.github.muntashirakon.AppManager.crypto.AESCrypto;\nimport io.github.muntashirakon.AppManager.crypto.RSACrypto;\nimport io.github.muntashirakon.AppManager.crypto.RandomChar;\nimport io.github.muntashirakon.AppManager.logs.Log;\nimport io.github.muntashirakon.AppManager.utils.ContextUtils;\nimport io.github.muntashirakon.AppManager.utils.NotificationUtils;\nimport io.github.muntashirakon.AppManager.utils.Utils;\n\npublic class KeyStoreManager {\n    public static final String TAG = \"KSManager\";\n\n    public static final String AM_KEYSTORE_FILE_NAME = \"am_keystore.bks\";  // Java KeyStore\n    public static final File AM_KEYSTORE_FILE;\n\n    private static final String AM_KEYSTORE = \"BKS\";  // KeyStore.getDefaultType() == JKS\n    private static final String PREF_AM_KEYSTORE_PREFIX = \"ks_\";\n    private static final String PREF_AM_KEYSTORE_PASS = \"kspass\";\n    private static final SharedPreferences sSharedPreferences;\n\n    public static final String ACTION_KS_INTERACTION_BEGIN = BuildConfig.APPLICATION_ID + \".action.KS_INTERACTION_BEGIN\";\n    public static final String ACTION_KS_INTERACTION_END = BuildConfig.APPLICATION_ID + \".action.KS_INTERACTION_END\";\n\n    static {\n        Context ctx = ContextUtils.getContext();\n        AM_KEYSTORE_FILE = new File(ctx.getFilesDir(), AM_KEYSTORE_FILE_NAME);\n        sSharedPreferences = ctx.getSharedPreferences(\"keystore\", Context.MODE_PRIVATE);\n    }\n\n    @SuppressLint(\"StaticFieldLeak\")\n    private static KeyStoreManager sInstance;\n\n    public static KeyStoreManager getInstance() throws Exception {\n        if (sInstance == null) {\n            sInstance = new KeyStoreManager();\n        }\n        return sInstance;\n    }\n\n    public static void reloadKeyStore() throws Exception {\n        sInstance = new KeyStoreManager();\n    }\n\n    @NonNull\n    public static AlertDialog generateAndDisplayKeyStorePassword(@NonNull FragmentActivity activity,\n                                                                 @Nullable Runnable dismissListener) {\n        char[] password = new char[30];\n        RandomChar randomChar = new RandomChar();\n        randomChar.nextChars(password);\n        savePass(activity, PREF_AM_KEYSTORE_PASS, password);\n        return displayKeyStorePassword(activity, password, dismissListener);\n    }\n\n    @NonNull\n    public static AlertDialog displayKeyStorePassword(@NonNull FragmentActivity activity,\n                                                      @NonNull char[] password,\n                                                      @Nullable Runnable dismissListener) {\n        View view = activity.getLayoutInflater().inflate(R.layout.dialog_keystore_password, null);\n        TextInputEditText editText = view.findViewById(R.id.ks_pass);\n        editText.setText(password, 0, password.length);\n        return new MaterialAlertDialogBuilder(activity)\n                .setTitle(R.string.keystore)\n                .setView(view)\n                .setNegativeButton(R.string.close, null)\n                .setCancelable(false)\n                .setOnDismissListener(dialog -> {\n                    Utils.clearChars(password);\n                    if (dismissListener != null) {\n                        dismissListener.run();\n                    }\n                })\n                .create();\n    }\n\n    @NonNull\n    public static AlertDialog inputKeyStorePassword(@NonNull FragmentActivity activity,\n                                                    @Nullable Runnable dismissListener) {\n        AtomicBoolean dismiss = new AtomicBoolean(true);\n        View view = activity.getLayoutInflater().inflate(R.layout.dialog_keystore_password, null);\n        TextInputEditText editText = view.findViewById(R.id.ks_pass);\n        editText.setCursorVisible(true);\n        view.findViewById(android.R.id.text1).setVisibility(View.GONE);\n        TextInputLayout tv = view.findViewById(android.R.id.text2);\n        tv.setHint(R.string.input_keystore_pass);\n        AlertDialog alertDialog = new MaterialAlertDialogBuilder(activity)\n                .setTitle(R.string.keystore)\n                .setView(view)\n                .setPositiveButton(R.string.ok, null)\n                .setNegativeButton(R.string.delete, null)\n                .setCancelable(false)\n                .setOnDismissListener(dialog -> {\n                    if (dismissListener != null && dismiss.get()) {\n                        dismissListener.run();\n                    }\n                })\n                .create();\n        alertDialog.setOnShowListener(dialog -> {\n            AlertDialog d = (AlertDialog) dialog;\n            Button okButton = d.getButton(AlertDialog.BUTTON_POSITIVE);\n            Button deleteButton = d.getButton(AlertDialog.BUTTON_NEGATIVE);\n            okButton.setOnClickListener(v -> {\n                Editable editable = editText.getText();\n                if (TextUtils.isEmpty(editable)) {\n                    editText.setError(activity.getString(R.string.keystore_pass_cannot_be_empty));\n                    return;\n                }\n                //noinspection ConstantConditions\n                char[] password = new char[editable.length()];\n                editable.getChars(0, editable.length(), password, 0);\n                savePass(activity, PREF_AM_KEYSTORE_PASS, password);\n                Utils.clearChars(password);\n                try {\n                    getInstance();\n                } catch (Exception e) {\n                    // Couldn't use the password.\n                    editText.setError(activity.getString(R.string.invalid_password));\n                    return;\n                }\n                d.dismiss();\n            });\n            deleteButton.setOnClickListener(v -> {\n                AM_KEYSTORE_FILE.delete();\n                if (sSharedPreferences.contains(PREF_AM_KEYSTORE_PASS)) {\n                    sSharedPreferences.edit().remove(PREF_AM_KEYSTORE_PASS).apply();\n                }\n                dismiss.set(false);\n                generateAndDisplayKeyStorePassword(activity, dismissListener).show();\n                d.dismiss();\n            });\n        });\n        return alertDialog;\n    }\n\n    public static boolean hasKeyStore() {\n        return AM_KEYSTORE_FILE.exists();\n    }\n\n    public static boolean hasKeyStorePassword() {\n        try {\n            reloadKeyStore();\n            return true;\n        } catch (Exception e) {\n            return false;\n        }\n    }\n\n    @Deprecated // To be removed in v3.0.0\n    @WorkerThread\n    public static void migrateKeyStore() throws Exception {\n        // Reset all alias password\n        String[] aliases = new String[]{\n                AdbConnectionManager.ADB_KEY_ALIAS,\n                Signer.SIGNING_KEY_ALIAS,\n                RSACrypto.AES_KEY_ALIAS,\n                AESCrypto.AES_KEY_ALIAS,\n        };\n        KeyStoreManager ksm = KeyStoreManager.getInstance();\n        Key key;\n        for (String alias : aliases) {\n            try {\n                if (!ksm.containsKey(alias)) continue;\n                key = ksm.getKey(alias, null);\n                ksm.removeItem(alias);\n                if (key instanceof SecretKey) {\n                    ksm.addSecretKey(alias, (SecretKey) key, false);\n                    SecretKeyCompat.destroy((SecretKey) key);\n                } else if (key instanceof PrivateKey) {\n                    KeyPair keyPair = new KeyPair((PrivateKey) key, ksm.getCertificate(alias));\n                    ksm.addKeyPair(alias, keyPair, false);\n                    keyPair.destroy();\n                } else throw new NoSuchAlgorithmException();\n            } catch (Exception ignore) {\n            }\n        }\n    }\n\n    private final Context mContext;\n    private final KeyStore mAmKeyStore;\n    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {\n        @Override\n        public void onReceive(Context context, @NonNull Intent intent) {\n            if (intent.getAction() == null) return;\n            switch (intent.getAction()) {\n                case ACTION_KS_INTERACTION_BEGIN:\n                    break;\n                case ACTION_KS_INTERACTION_END:\n                    releaseLock();\n                    break;\n            }\n        }\n    };\n\n    private KeyStoreManager()\n            throws CertificateException, NoSuchAlgorithmException, KeyStoreException, IOException {\n        mContext = ContextUtils.getContext();\n        mAmKeyStore = getAmKeyStore();\n    }\n\n    public void addKeyPair(String alias, @NonNull KeyPair keyPair, boolean isOverride)\n            throws KeyStoreException, IOException, CertificateException, NoSuchAlgorithmException {\n        // Check existence of this alias in system preferences, this should be unique\n        String prefAlias = getPrefAlias(alias);\n        if (sSharedPreferences.contains(prefAlias) && mAmKeyStore.containsAlias(alias)) {\n            Log.w(TAG, \"Alias %s exists.\", alias);\n            if (isOverride) removeItemInternal(alias);\n            else return;\n        }\n        char[] password = getAmKeyStorePassword();\n        PrivateKey privateKey = keyPair.getPrivateKey();\n        Certificate certificate = keyPair.getCertificate();\n        mAmKeyStore.setKeyEntry(alias, privateKey, password, new Certificate[]{certificate});\n        String encryptedPass = getEncryptedPassword(mContext, password);\n        if (encryptedPass == null) {\n            mAmKeyStore.deleteEntry(alias);\n            throw new KeyStoreException(\"Password for \" + alias + \" could not be saved.\");\n        }\n        sSharedPreferences.edit().putString(prefAlias, encryptedPass).apply();\n        try (OutputStream is = new FileOutputStream(AM_KEYSTORE_FILE)) {\n            mAmKeyStore.store(is, password);\n            Utils.clearChars(password);\n            Utils.clearChars(password);\n        }\n    }\n\n    public void addSecretKey(String alias, @NonNull SecretKey secretKey, boolean isOverride)\n            throws KeyStoreException, IOException, CertificateException, NoSuchAlgorithmException {\n        // Check existence of this alias in system preferences, this should be unique\n        String prefAlias = getPrefAlias(alias);\n        if (sSharedPreferences.contains(prefAlias) && mAmKeyStore.containsAlias(alias)) {\n            if (!isOverride) throw new KeyStoreException(\"Alias \" + alias + \" exists.\");\n            else Log.w(TAG, \"Alias %s exists.\", alias);\n        }\n        char[] password = getAmKeyStorePassword();\n        mAmKeyStore.setEntry(alias, new KeyStore.SecretKeyEntry(secretKey), new KeyStore.PasswordProtection(password));\n        String encryptedPass = getEncryptedPassword(mContext, password);\n        if (encryptedPass == null) {\n            mAmKeyStore.deleteEntry(alias);\n            throw new KeyStoreException(\"Password for \" + alias + \" could not be saved.\");\n        }\n        sSharedPreferences.edit().putString(prefAlias, encryptedPass).apply();\n        try (OutputStream is = new FileOutputStream(AM_KEYSTORE_FILE)) {\n            mAmKeyStore.store(is, password);\n        } finally {\n            Utils.clearChars(password);\n            Utils.clearChars(password);\n        }\n    }\n\n    public void removeItem(String alias)\n            throws KeyStoreException, IOException, CertificateException, NoSuchAlgorithmException {\n        removeItemInternal(alias);\n        char[] realPassword = getAmKeyStorePassword();\n        try (OutputStream is = new FileOutputStream(AM_KEYSTORE_FILE)) {\n            mAmKeyStore.store(is, realPassword);\n        } finally {\n            Utils.clearChars(realPassword);\n        }\n    }\n\n    private void removeItemInternal(String alias) throws KeyStoreException {\n        mAmKeyStore.deleteEntry(alias);\n        String prefAlias = getPrefAlias(alias);\n        if (sSharedPreferences.contains(prefAlias)) {\n            sSharedPreferences.edit().remove(prefAlias).apply();\n        }\n    }\n\n    @Nullable\n    private Key getKey(String alias)\n            throws UnrecoverableKeyException, NoSuchAlgorithmException, KeyStoreException {\n        char[] password = getAmKeyStorePassword();\n        Key key = mAmKeyStore.getKey(alias, password);\n        Utils.clearChars(password);\n        return key;\n    }\n\n    /**\n     * @deprecated Kept for migratory purposes only, deprecated since v2.6.3. To be removed in v3.0.0.\n     */\n    @Deprecated\n    @Nullable\n    private Key getKey(String alias, @Nullable char[] password)\n            throws UnrecoverableKeyException, NoSuchAlgorithmException, KeyStoreException {\n        if (password == null) {\n            password = getAliasPassword(alias);\n        }\n        Key key = mAmKeyStore.getKey(alias, password);\n        Utils.clearChars(password);\n        return key;\n    }\n\n    @Nullable\n    public SecretKey getSecretKey(String alias)\n            throws UnrecoverableKeyException, NoSuchAlgorithmException, KeyStoreException {\n        Key key = getKey(alias);\n        if (key instanceof SecretKey) {\n            return (SecretKey) key;\n        }\n        throw new KeyStoreException(\"The alias \" + alias + \" does not have a KeyPair.\");\n    }\n\n    @Nullable\n    public KeyPair getKeyPair(String alias)\n            throws UnrecoverableKeyException, NoSuchAlgorithmException, KeyStoreException {\n        Key key = getKey(alias);\n        if (key instanceof PrivateKey) {\n            return new KeyPair((PrivateKey) key, getCertificate(alias));\n        }\n        throw new KeyStoreException(\"The alias \" + alias + \" does not have a KeyPair.\");\n    }\n\n    @Nullable\n    public KeyPair getKeyPairNoThrow(String alias) {\n        try {\n            return getKeyPair(alias);\n        } catch (Exception e) {\n            return null;\n        }\n    }\n\n    public boolean containsKey(String alias) throws KeyStoreException {\n        return mAmKeyStore.containsAlias(alias);\n    }\n\n    /**\n     * Get the certificate associated with the alias\n     *\n     * @param alias The given KeyStore alias\n     * @return Certificate associated with the alias, usually {@link X509Certificate}\n     */\n    private Certificate getCertificate(String alias) throws KeyStoreException {\n        return mAmKeyStore.getCertificate(alias);\n    }\n\n    /**\n     * Save password in the Shared Preferences in encrypted form.\n     *\n     * @param prefAlias The alias after running {@link #getPrefAlias(String)}\n     * @param password  The password for the alias. {@link Utils#clearChars(char[])} must be called when done.\n     */\n    static void savePass(@NonNull Context context, String prefAlias, char[] password) {\n        sSharedPreferences.edit().putString(prefAlias, getEncryptedPassword(context, password)).apply();\n    }\n\n    /**\n     * Get the password decrypted by Android KeyStore.\n     *\n     * @param encryptedPass Encrypted password (IV length + IV + password) in base 64 format\n     * @return The password in decrypted form. {@link Utils#clearChars(char[])} must be called when done.\n     */\n    @CheckResult\n    @Nullable\n    private static char[] getDecryptedPassword(@NonNull Context context, @NonNull String encryptedPass) {\n        try {\n            byte[] encryptedBytes = Base64.decode(encryptedPass, Base64.NO_WRAP);\n            return Utils.bytesToChars(CompatUtil.decryptData(context, encryptedBytes));\n        } catch (Exception e) {\n            Log.e(\"KS\", \"Could not get decrypted password for %s\", e, encryptedPass);\n        }\n        return null;\n    }\n\n    /**\n     * Get the password to be encrypted using Android KeyStore.\n     *\n     * @param realPass The password to be encrypted. {@link Utils#clearChars(char[])} must be called when done.\n     * @return Encrypted password (IV length + IV + password) in base 64 format\n     */\n    @Nullable\n    private static String getEncryptedPassword(@NonNull Context context, @NonNull char[] realPass) {\n        try (ByteArrayOutputStream bos = new ByteArrayOutputStream()) {\n            AesEncryptedData encryptedData = CompatUtil.getEncryptedData(Utils.charsToBytes(realPass), context);\n            bos.write((byte) encryptedData.getIv().length);\n            bos.write(encryptedData.getIv());\n            bos.write(encryptedData.getEncryptedData());\n            return Base64.encodeToString(bos.toByteArray(), Base64.NO_WRAP);\n        } catch (Exception e) {\n            Log.e(\"KS\", \"Could not get encrypted password\", e);\n        }\n        return null;\n    }\n\n    /**\n     * Get App Manager's KeyStore. The user will be asked for a password if the KeyStore password\n     * does not exist. If the KeyStore itself doesn't exist, it will initialize an empty KeyStore.\n     *\n     * @return App Manager's KeyStore\n     */\n    private KeyStore getAmKeyStore() throws KeyStoreException, IOException, CertificateException, NoSuchAlgorithmException {\n        KeyStore keyStore = KeyStore.getInstance(AM_KEYSTORE);\n        Log.w(TAG, \"Using keystore %s\", AM_KEYSTORE);\n        char[] realPassword = getAmKeyStorePassword();\n        try {\n            if (AM_KEYSTORE_FILE.exists()) {\n                try (InputStream is = new FileInputStream(AM_KEYSTORE_FILE)) {\n                    keyStore.load(is, realPassword);\n                }\n            } else {\n                keyStore.load(null);\n            }\n        } finally {\n            Utils.clearChars(realPassword);\n        }\n        return keyStore;\n    }\n\n    /**\n     * Get App Manager's KeyStore password. The password is stored in the shared preferences in an\n     * encrypted format (the encryption/decryption is performed via AndroidKeyStore). In case the\n     * user restores from the cache or accidentally deletes all entries from the shared pref, App\n     * Manager will ask for KeyStore password again.\n     *\n     * @return KeyStore password in decrypted format. {@link Utils#clearChars(char[])} must be called when done.\n     */\n    @CheckResult\n    @NonNull\n    public char[] getAmKeyStorePassword() throws KeyStoreException {\n        String encryptedPass = sSharedPreferences.getString(PREF_AM_KEYSTORE_PASS, null);\n        if (encryptedPass == null) {\n            throw new KeyStoreException(\"No saved password for KeyStore.\");\n        }\n        char[] realPassword = getDecryptedPassword(mContext, encryptedPass);\n        if (realPassword == null) {\n            throw new KeyStoreException(\"Could not decrypt encrypted password.\");\n        }\n        return realPassword;\n    }\n\n    /**\n     * @return Password for the given alias. {@link Utils#clearChars(char[])} must be called when done.\n     * @deprecated Kept for migratory purposes only, deprecated since v2.6.3. To be removed in v3.0.0.\n     */\n    @Deprecated\n    @CheckResult\n    @NonNull\n    private char[] getAliasPassword(@NonNull String alias) throws KeyStoreException {\n        char[] password;\n        String prefAlias = getPrefAlias(alias);\n        if (sSharedPreferences.contains(prefAlias)) {\n            String encryptedPass = sSharedPreferences.getString(prefAlias, null);\n            if (encryptedPass == null) {\n                throw new KeyStoreException(\"Stored pass is empty for alias \" + alias);\n            }\n            password = getDecryptedPassword(mContext, encryptedPass);\n            if (password == null) {\n                throw new KeyStoreException(\"Decrypted pass is empty for alias \" + alias);\n            }\n            return password;\n        } else {\n            IntentFilter filter = new IntentFilter(ACTION_KS_INTERACTION_BEGIN);\n            filter.addAction(ACTION_KS_INTERACTION_END);\n            ContextCompat.registerReceiver(mContext, mReceiver, filter, ContextCompat.RECEIVER_NOT_EXPORTED);\n            Intent broadcastIntent = new Intent(ACTION_KS_INTERACTION_BEGIN);\n            broadcastIntent.setPackage(mContext.getPackageName());\n            mContext.sendBroadcast(broadcastIntent);\n            // Intent wrapper\n            Intent intent = new Intent(mContext, KeyStoreActivity.class);\n            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);\n            intent.putExtra(KeyStoreActivity.EXTRA_ALIAS, alias);\n            String ks = \"AM KeyStore\";\n            // We don't need a delete intent since the time will be expired anyway\n            NotificationCompat.Builder builder = NotificationUtils.getHighPriorityNotificationBuilder(mContext)\n                    .setAutoCancel(true)\n                    .setDefaults(Notification.DEFAULT_ALL)\n                    .setWhen(System.currentTimeMillis())\n                    .setSmallIcon(R.drawable.ic_default_notification)\n                    .setTicker(ks)\n                    .setContentTitle(ks)\n                    .setSubText(ks)\n                    .setContentText(mContext.getString(R.string.input_keystore_alias_pass_msg, alias));\n            builder.setContentIntent(PendingIntentCompat.getActivity(mContext, 0, intent,\n                    PendingIntent.FLAG_ONE_SHOT | PendingIntent.FLAG_UPDATE_CURRENT, false));\n            NotificationUtils.displayHighPriorityNotification(mContext, builder.build());\n            acquireLock();\n            mContext.unregisterReceiver(mReceiver);\n            return getAliasPassword(alias);\n        }\n    }\n\n    /**\n     * Get the formatted alias stored in the shared pref. Normally, a prefix {@link #PREF_AM_KEYSTORE_PREFIX}\n     * is added to the alias.\n     *\n     * @param alias The given alias\n     * @return Alias with {@link #PREF_AM_KEYSTORE_PREFIX}\n     */\n    @NonNull\n    static String getPrefAlias(@NonNull String alias) {\n        return PREF_AM_KEYSTORE_PREFIX + alias;\n    }\n\n    private CountDownLatch mInteractionWatcher;\n\n    private void releaseLock() {\n        if (mInteractionWatcher != null) mInteractionWatcher.countDown();\n    }\n\n    private void acquireLock() {\n        mInteractionWatcher = new CountDownLatch(1);\n        try {\n            mInteractionWatcher.await(100, TimeUnit.SECONDS);\n        } catch (InterruptedException e) {\n            Log.e(TAG, \"waitForResult: interrupted\", e);\n            Thread.currentThread().interrupt();\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/crypto/ks/KeyStoreUtils.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.crypto.ks;\n\nimport android.content.ContentResolver;\nimport android.content.Context;\nimport android.net.Uri;\nimport android.sun.misc.BASE64Decoder;\nimport android.sun.misc.BASE64Encoder;\nimport android.sun.security.provider.JavaKeyStoreProvider;\nimport android.sun.security.provider.X509Factory;\nimport android.sun.security.x509.AlgorithmId;\nimport android.sun.security.x509.CertificateAlgorithmId;\nimport android.sun.security.x509.CertificateExtensions;\nimport android.sun.security.x509.CertificateIssuerName;\nimport android.sun.security.x509.CertificateSerialNumber;\nimport android.sun.security.x509.CertificateSubjectName;\nimport android.sun.security.x509.CertificateValidity;\nimport android.sun.security.x509.CertificateVersion;\nimport android.sun.security.x509.CertificateX509Key;\nimport android.sun.security.x509.KeyIdentifier;\nimport android.sun.security.x509.PrivateKeyUsageExtension;\nimport android.sun.security.x509.SubjectKeyIdentifierExtension;\nimport android.sun.security.x509.X500Name;\nimport android.sun.security.x509.X509CertImpl;\nimport android.sun.security.x509.X509CertInfo;\nimport android.text.TextUtils;\n\nimport androidx.annotation.IntDef;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;\nimport org.bouncycastle.asn1.x9.X9ECParameters;\nimport org.bouncycastle.cert.X509v3CertificateBuilder;\nimport org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;\nimport org.bouncycastle.crypto.ec.CustomNamedCurves;\nimport org.bouncycastle.jce.provider.BouncyCastleProvider;\nimport org.bouncycastle.jce.spec.ECParameterSpec;\nimport org.bouncycastle.operator.OperatorCreationException;\nimport org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;\n\nimport java.io.BufferedReader;\nimport java.io.ByteArrayOutputStream;\nimport java.io.FileNotFoundException;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.InputStreamReader;\nimport java.math.BigInteger;\nimport java.nio.charset.StandardCharsets;\nimport java.security.GeneralSecurityException;\nimport java.security.InvalidKeyException;\nimport java.security.Key;\nimport java.security.KeyException;\nimport java.security.KeyFactory;\nimport java.security.KeyPairGenerator;\nimport java.security.KeyStore;\nimport java.security.KeyStoreException;\nimport java.security.NoSuchAlgorithmException;\nimport java.security.PrivateKey;\nimport java.security.Provider;\nimport java.security.PublicKey;\nimport java.security.SecureRandom;\nimport java.security.cert.Certificate;\nimport java.security.cert.CertificateEncodingException;\nimport java.security.cert.CertificateException;\nimport java.security.cert.CertificateFactory;\nimport java.security.cert.X509Certificate;\nimport java.security.spec.DSAPrivateKeySpec;\nimport java.security.spec.KeySpec;\nimport java.security.spec.PKCS8EncodedKeySpec;\nimport java.security.spec.RSAPrivateCrtKeySpec;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.Date;\nimport java.util.List;\n\nimport io.github.muntashirakon.AppManager.logs.Log;\nimport io.github.muntashirakon.io.IoUtils;\n\npublic class KeyStoreUtils {\n    public static final String TAG = KeyStoreUtils.class.getSimpleName();\n\n    /**\n     * Must be kept in sync with {@link #TYPES}.\n     */\n    @IntDef({KeyType.JKS, KeyType.PKCS12, KeyType.BKS, KeyType.PK8})\n    public @interface KeyType {\n        int JKS = 0;\n        int PKCS12 = 1;\n        int BKS = 2;\n        int PK8 = 3;\n    }\n\n    public static final String KEY_STORE_TYPE_JKS = \"JKS\";\n    public static final String KEY_STORE_TYPE_PKCS12 = \"PKCS12\";\n    public static final String KEY_STORE_TYPE_BKS = \"BKS\";\n\n    private static final String[] TYPES = {KEY_STORE_TYPE_JKS, KEY_STORE_TYPE_PKCS12, KEY_STORE_TYPE_BKS};\n\n    @NonNull\n    public static ArrayList<String> listAliases(@NonNull Context context,\n                                                @NonNull Uri ksUri,\n                                                @KeyType int ksType,\n                                                @Nullable char[] ksPass)\n            throws IOException, GeneralSecurityException {\n        String keyType = TYPES[ksType];\n        Log.d(TAG, \"Loading keystore %s\", keyType);\n        final KeyStore ks = KeyStore.getInstance(keyType, getKeyStoreProvider(keyType));\n        try (InputStream is = context.getContentResolver().openInputStream(ksUri)) {\n            if (is == null) throw new FileNotFoundException(ksUri + \" does not exist.\");\n            ks.load(is, ksPass);\n        }\n        return Collections.list(ks.aliases());\n    }\n\n    @NonNull\n    public static KeyPair getKeyPair(@NonNull Context context, @NonNull Uri ksUri, @KeyType int ksType,\n                                     @Nullable String ksAlias, @Nullable char[] ksPass,\n                                     @Nullable char[] aliasPass)\n            throws GeneralSecurityException, IOException {\n        String keyType = TYPES[ksType];\n        Log.d(TAG, \"Loading keystore %s\", keyType);\n        final KeyStore ks = KeyStore.getInstance(keyType, getKeyStoreProvider(keyType));\n        try (InputStream is = context.getContentResolver().openInputStream(ksUri)) {\n            if (is == null) throw new FileNotFoundException(ksUri + \" does not exist.\");\n            ks.load(is, ksPass);\n        }\n        if (TextUtils.isEmpty(ksAlias)) {\n            ksAlias = ks.aliases().nextElement();\n        }\n        Key key = ks.getKey(ksAlias, aliasPass);\n        if (key instanceof PrivateKey) {\n            X509Certificate cert = (X509Certificate) ks.getCertificate(ksAlias);\n            return new KeyPair((PrivateKey) key, cert);\n        }\n        throw new KeyStoreException(\"The provided alias \" + ksAlias + \" does not exist.\");\n    }\n\n    @NonNull\n    public static KeyPair getKeyPair(@NonNull Context context, @NonNull Uri keyPath, @NonNull Uri certPath)\n            throws GeneralSecurityException, IOException {\n        ContentResolver cr = context.getContentResolver();\n        PKCS8EncodedKeySpec spec;\n        PrivateKey privateKey;\n        X509Certificate cert;\n        try (InputStream pk = cr.openInputStream(keyPath)) {\n            byte[] data = IoUtils.readFully(pk, -1, true);\n            spec = new PKCS8EncodedKeySpec(data);\n        }\n        try (InputStream cer = cr.openInputStream(certPath)) {\n            cert = (X509Certificate) CertificateFactory.getInstance(\"X.509\").generateCertificate(cer);\n            // TODO: 22/5/21 Check algorithm type: We only support RSA and EC\n            privateKey = KeyFactory.getInstance(cert.getPublicKey().getAlgorithm()).generatePrivate(spec);\n        }\n        return new KeyPair(privateKey, cert);\n    }\n\n    @NonNull\n    public static KeyPair generateRSAKeyPair(@NonNull String formattedSubject, int keySize, long expiryDate)\n            throws GeneralSecurityException, IOException {\n        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(\"RSA\");\n        keyPairGenerator.initialize(keySize, SecureRandom.getInstance(\"SHA1PRNG\"));\n        java.security.KeyPair generateKeyPair = keyPairGenerator.generateKeyPair();\n        PublicKey publicKey = generateKeyPair.getPublic();\n        PrivateKey privateKey = generateKeyPair.getPrivate();\n        return new KeyPair(privateKey, generateRSACert(privateKey, publicKey, formattedSubject, expiryDate));\n    }\n\n    @NonNull\n    private static Provider getKeyStoreProvider(String keyStoreType) {\n        switch (keyStoreType) {\n            default:\n            case KEY_STORE_TYPE_JKS:\n                return new JavaKeyStoreProvider();\n            case KEY_STORE_TYPE_PKCS12:\n            case KEY_STORE_TYPE_BKS:\n                return new BouncyCastleProvider();\n        }\n    }\n\n    @NonNull\n    public static KeyPair generateECCKeyPair(@NonNull String formattedSubject, long expiryDate)\n            throws GeneralSecurityException, OperatorCreationException {\n        X9ECParameters curve25519 = CustomNamedCurves.getByName(\"curve25519\");\n        ECParameterSpec parameterSpec = new ECParameterSpec(curve25519.getCurve(), curve25519.getG(), curve25519.getN(), curve25519.getH());\n        KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance(\"ECDH\", new BouncyCastleProvider());\n        keyPairGenerator.initialize(parameterSpec, SecureRandom.getInstance(\"SHA1PRNG\"));\n        java.security.KeyPair generateKeyPair = keyPairGenerator.generateKeyPair();\n        PublicKey publicKey = generateKeyPair.getPublic();\n        PrivateKey privateKey = generateKeyPair.getPrivate();\n        return new KeyPair(privateKey, generateECDSACert(privateKey, publicKey, formattedSubject, expiryDate));\n    }\n\n    /**\n     * Read a PKCS #8, Base64-encrypted file as a Key instance. This is similar to\n     * {@link CertificateFactory#generateCertificate(InputStream)} except that it generates a private key.\n     */\n    public static PrivateKey generatePrivateKey(InputStream inputStream) throws IOException, GeneralSecurityException {\n        try (BufferedReader in = new BufferedReader(new InputStreamReader(inputStream))) {\n            String line;\n            boolean readingKey = false;\n            boolean pkcs8Format = false;\n            boolean rsaFormat = false;\n            boolean dsaFormat = false;\n            // FIXME: Read securely using char[]\n            StringBuilder base64EncodedKey = new StringBuilder();\n            while ((line = in.readLine()) != null) {\n                line = line.trim();\n                if (readingKey) {\n                    switch (line) {\n                        case RSA_END_HEADER:\n                        case DSA_END_HEADER:\n                        case PKCS8_END_HEADER:\n                            readingKey = false;\n                            break;\n                        default:\n                            base64EncodedKey.append(line);\n                            break;\n                    }\n                } else {\n                    switch (line) {\n                        case RSA_BEGIN_HEADER:\n                            readingKey = true;\n                            rsaFormat = true;\n                            break;\n                        case DSA_BEGIN_HEADER:\n                            readingKey = true;\n                            dsaFormat = true;\n                            break;\n                        case PKCS8_BEGIN_HEADER:\n                            readingKey = true;\n                            pkcs8Format = true;\n                            break;\n                    }\n                }\n            }\n            if (base64EncodedKey.length() == 0) {\n                throw new IOException(\"Stream does not contain an unencrypted private key.\");\n            }\n\n            BASE64Decoder decoder = new BASE64Decoder();\n            byte[] bytes = decoder.decodeBuffer(base64EncodedKey.toString());\n\n            KeyFactory kf;\n            KeySpec spec;\n            if (pkcs8Format) {\n                kf = KeyFactory.getInstance(\"RSA\");\n                spec = new PKCS8EncodedKeySpec(bytes);\n            } else if (rsaFormat) {\n                // PKCS#1 format\n                kf = KeyFactory.getInstance(\"RSA\");\n                List<BigInteger> rsaIntegers = new ArrayList<>();\n                ASN1Parse(bytes, rsaIntegers);\n                if (rsaIntegers.size() < 8) {\n                    throw new InvalidKeyException(\"Stream does not appear to be a properly formatted RSA key.\");\n                }\n                BigInteger publicExponent = rsaIntegers.get(2);\n                BigInteger privateExponent = rsaIntegers.get(3);\n                BigInteger modulus = rsaIntegers.get(1);\n                BigInteger primeP = rsaIntegers.get(4);\n                BigInteger primeQ = rsaIntegers.get(5);\n                BigInteger primeExponentP = rsaIntegers.get(6);\n                BigInteger primeExponentQ = rsaIntegers.get(7);\n                BigInteger crtCoefficient = rsaIntegers.get(8);\n                //spec = new RSAPrivateKeySpec(modulus, privateExponent);\n                spec = new RSAPrivateCrtKeySpec(modulus, publicExponent, privateExponent,\n                        primeP, primeQ, primeExponentP, primeExponentQ, crtCoefficient);\n            } else if (dsaFormat) {\n                kf = KeyFactory.getInstance(\"DSA\");\n                List<BigInteger> dsaIntegers = new ArrayList<>();\n                ASN1Parse(bytes, dsaIntegers);\n                if (dsaIntegers.size() < 5) {\n                    throw new InvalidKeyException(\"Stream does not appear to be a properly formatted DSA key\");\n                }\n                BigInteger privateExponent = dsaIntegers.get(1);\n                BigInteger publicExponent = dsaIntegers.get(2);\n                BigInteger P = dsaIntegers.get(3);\n                BigInteger Q = dsaIntegers.get(4);\n                BigInteger G = dsaIntegers.get(5);\n                spec = new DSAPrivateKeySpec(privateExponent, P, Q, G);\n            } else {\n                throw new NoSuchAlgorithmException(\"Couldn't find any suitable algorithm\");\n            }\n            return kf.generatePrivate(spec);\n        }\n    }\n\n    public static byte[] getPemCertificate(@NonNull Certificate certificate)\n            throws CertificateEncodingException, IOException {\n        BASE64Encoder encoder = new BASE64Encoder();\n        try (ByteArrayOutputStream os = new ByteArrayOutputStream(X509Factory.BEGIN_CERT.length() +\n                X509Factory.BEGIN_CERT.length() + certificate.getEncoded().length + 2)) {\n            os.write(X509Factory.BEGIN_CERT.getBytes(StandardCharsets.UTF_8));\n            os.write('\\n');\n            encoder.encode(certificate.getEncoded(), os);\n            os.write('\\n');\n            os.write(X509Factory.END_CERT.getBytes(StandardCharsets.UTF_8));\n            return os.toByteArray();\n        }\n    }\n\n    private static final String RSA_BEGIN_HEADER = \"-----BEGIN RSA PRIVATE KEY-----\";\n    private static final String RSA_END_HEADER = \"-----END RSA PRIVATE KEY-----\";\n    private static final String PKCS8_BEGIN_HEADER = \"-----BEGIN PRIVATE KEY-----\";\n    private static final String PKCS8_END_HEADER = \"-----END PRIVATE KEY-----\";\n    private static final String DSA_BEGIN_HEADER = \"-----BEGIN DSA PRIVATE KEY-----\";\n    private static final String DSA_END_HEADER = \"-----END DSA PRIVATE KEY-----\";\n\n    /**\n     * Bare-bones ASN.1 parser that can only deal with a structure that contains integers\n     * (as I expect for the RSA private key format given in PKCS #1 and RFC 3447).\n     *\n     * @param b        the bytes to be parsed as ASN.1 DER\n     * @param integers an output array to which all integers encountered during the parse\n     *                 will be appended in the order they're encountered.  It's up to the caller to determine\n     *                 which is which.\n     */\n    private static void ASN1Parse(@NonNull byte[] b, List<BigInteger> integers) throws KeyException {\n        int pos = 0;\n        while (pos < b.length) {\n            byte tag = b[pos++];\n            int length = b[pos++];\n            if ((length & 0x80) != 0) {\n                int extLen = 0;\n                for (int i = 0; i < (length & 0x7F); i++) {\n                    extLen = (extLen << 8) | (b[pos++] & 0xFF);\n                }\n                length = extLen;\n            }\n            byte[] contents = new byte[length];\n            System.arraycopy(b, pos, contents, 0, length);\n            pos += length;\n\n            if (tag == 0x30) {  // sequence\n                ASN1Parse(contents, integers);\n            } else if (tag == 0x02) {  // Integer\n                BigInteger i = new BigInteger(contents);\n                integers.add(i);\n            } else {\n                throw new KeyException(\"Unsupported ASN.1 tag \" + tag + \" encountered.  Is this a \" + \"valid RSA key?\");\n            }\n        }\n    }\n\n    private static X509Certificate generateECDSACert(@NonNull PrivateKey privateKey, @NonNull PublicKey publicKey,\n                                                     @NonNull String formattedSubject, long expiryDate)\n            throws OperatorCreationException, CertificateException {\n        Date notBefore = new Date();\n        Date notAfter = new Date(expiryDate);\n        org.bouncycastle.asn1.x500.X500Name x500Name = new org.bouncycastle.asn1.x500.X500Name(formattedSubject);\n        JcaContentSignerBuilder signerBuilder = new JcaContentSignerBuilder(\"SHA512withECDSA\");\n        signerBuilder.setProvider(new BouncyCastleProvider());\n        SubjectPublicKeyInfo spki = SubjectPublicKeyInfo.getInstance(publicKey.getEncoded());\n        X509v3CertificateBuilder v3CertGen = new X509v3CertificateBuilder(x500Name,\n                BigInteger.valueOf(new SecureRandom().nextInt() & Integer.MAX_VALUE), notBefore, notAfter, x500Name, spki);\n        return new JcaX509CertificateConverter().getCertificate(v3CertGen.build(signerBuilder.build(privateKey)));\n    }\n\n    @NonNull\n    private static X509Certificate generateRSACert(@NonNull PrivateKey privateKey, @NonNull PublicKey publicKey,\n                                                   @NonNull String formattedSubject, long expiryDate)\n            throws GeneralSecurityException, IOException {\n        String algorithmName = \"SHA512withRSA\";\n        CertificateExtensions certificateExtensions = new CertificateExtensions();\n        certificateExtensions.set(SubjectKeyIdentifierExtension.NAME, new SubjectKeyIdentifierExtension(\n                new KeyIdentifier(publicKey).getIdentifier()));\n        X500Name x500Name = new X500Name(formattedSubject);\n        Date notBefore = new Date();\n        Date notAfter = new Date(expiryDate);\n        certificateExtensions.set(PrivateKeyUsageExtension.NAME, new PrivateKeyUsageExtension(notBefore, notAfter));\n        CertificateValidity certificateValidity = new CertificateValidity(notBefore, notAfter);\n        X509CertInfo x509CertInfo = new X509CertInfo();\n        x509CertInfo.set(X509CertInfo.VERSION, new CertificateVersion(CertificateVersion.V3));\n        x509CertInfo.set(X509CertInfo.SERIAL_NUMBER, new CertificateSerialNumber(new SecureRandom().nextInt() & Integer.MAX_VALUE));\n        x509CertInfo.set(X509CertInfo.ALGORITHM_ID, new CertificateAlgorithmId(AlgorithmId.get(algorithmName)));\n        x509CertInfo.set(X509CertInfo.SUBJECT, new CertificateSubjectName(x500Name));\n        x509CertInfo.set(X509CertInfo.KEY, new CertificateX509Key(publicKey));\n        x509CertInfo.set(X509CertInfo.VALIDITY, certificateValidity);\n        x509CertInfo.set(X509CertInfo.ISSUER, new CertificateIssuerName(x500Name));\n        x509CertInfo.set(X509CertInfo.EXTENSIONS, certificateExtensions);\n        X509CertImpl x509CertImpl = new X509CertImpl(x509CertInfo);\n        x509CertImpl.sign(privateKey, algorithmName);\n        return x509CertImpl;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/crypto/ks/SecretKeyAndVersion.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage io.github.muntashirakon.AppManager.crypto.ks;\n\nimport androidx.annotation.NonNull;\nimport androidx.core.util.Pair;\n\nimport java.util.Objects;\n\nimport javax.crypto.SecretKey;\n\n/**\n * Tuple which contains the secret key and the version of Android when the key has been generated\n */\n// Copyright 2018 New Vector Ltd\npublic class SecretKeyAndVersion extends Pair<SecretKey, Integer> {\n    /**\n     * @param secretKey                                The key\n     * @param androidVersionWhenTheKeyHasBeenGenerated The android version when the key has been generated\n     */\n    public SecretKeyAndVersion(@NonNull SecretKey secretKey, int androidVersionWhenTheKeyHasBeenGenerated) {\n        super(Objects.requireNonNull(secretKey), androidVersionWhenTheKeyHasBeenGenerated);\n    }\n\n    /**\n     * Get the key\n     *\n     * @return The key\n     */\n    @NonNull\n    public SecretKey getSecretKey() {\n        return first;\n    }\n\n    /**\n     * Get the android version when the key has been generated\n     *\n     * @return The android version when the key has been generated\n     */\n    public int getAndroidVersionWhenTheKeyHasBeenGenerated() {\n        return second;\n    }\n}"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/crypto/ks/SecretKeyCompat.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.crypto.ks;\n\nimport android.annotation.SuppressLint;\n\nimport androidx.annotation.NonNull;\n\nimport java.lang.reflect.Field;\n\nimport javax.crypto.SecretKey;\nimport javax.crypto.spec.SecretKeySpec;\nimport javax.security.auth.DestroyFailedException;\n\nimport io.github.muntashirakon.AppManager.utils.Utils;\n\n@SuppressLint(\"SoonBlockedPrivateApi\")\npublic final class SecretKeyCompat {\n    static final Field KEY;\n\n    static {\n        Field key = null;\n        try {\n            //noinspection JavaReflectionMemberAccess\n            key = SecretKeySpec.class.getDeclaredField(\"key\");\n            key.setAccessible(true);\n        } catch (NoSuchFieldException | SecurityException ignored) {\n        }\n\n        KEY = key;\n    }\n\n    public static void destroy(@NonNull SecretKey secretKey) throws DestroyFailedException {\n        // We might want to use the SecretKeySpec#destroy() but it doesn't work either\n        if (KEY != null && secretKey instanceof SecretKeySpec) {\n            try {\n                byte[] key = (byte[]) KEY.get(secretKey);\n                if (key != null) {\n                    Utils.clearBytes(key);\n                }\n                KEY.set(secretKey, null);\n            } catch (IllegalAccessException | IllegalArgumentException e) {\n                DestroyFailedException dfe = new DestroyFailedException(e.toString());\n                dfe.setStackTrace(e.getStackTrace());\n                throw dfe;\n            }\n        }\n    }\n}"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/db/AppsDb.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.db;\n\nimport androidx.annotation.NonNull;\nimport androidx.room.Database;\nimport androidx.room.Room;\nimport androidx.room.RoomDatabase;\nimport androidx.room.migration.Migration;\nimport androidx.sqlite.db.SupportSQLiteDatabase;\n\nimport io.github.muntashirakon.AppManager.db.dao.AppDao;\nimport io.github.muntashirakon.AppManager.db.dao.BackupDao;\nimport io.github.muntashirakon.AppManager.db.dao.FmFavoriteDao;\nimport io.github.muntashirakon.AppManager.db.dao.FreezeTypeDao;\nimport io.github.muntashirakon.AppManager.db.dao.LogFilterDao;\nimport io.github.muntashirakon.AppManager.db.dao.OpHistoryDao;\nimport io.github.muntashirakon.AppManager.db.entity.App;\nimport io.github.muntashirakon.AppManager.db.entity.Backup;\nimport io.github.muntashirakon.AppManager.db.entity.FmFavorite;\nimport io.github.muntashirakon.AppManager.db.entity.FreezeType;\nimport io.github.muntashirakon.AppManager.db.entity.LogFilter;\nimport io.github.muntashirakon.AppManager.db.entity.OpHistory;\nimport io.github.muntashirakon.AppManager.utils.ContextUtils;\n\n@Database(entities = {App.class, LogFilter.class, Backup.class, OpHistory.class, FmFavorite.class, FreezeType.class}, version = 7)\npublic abstract class AppsDb extends RoomDatabase {\n    private static AppsDb sAppsDb;\n\n    public static final Migration M_2_3 = new Migration(2, 3) {\n        @Override\n        public void migrate(@NonNull SupportSQLiteDatabase db) {\n            db.execSQL(\"CREATE TABLE IF NOT EXISTS `op_history` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `type` TEXT NOT NULL, `time` INTEGER NOT NULL, `data` TEXT NOT NULL, `status` TEXT NOT NULL, `extra` TEXT)\");\n        }\n    };\n    public static final Migration M_3_4 = new Migration(3, 4) {\n        @Override\n        public void migrate(@NonNull SupportSQLiteDatabase db) {\n            db.execSQL(\"CREATE TABLE IF NOT EXISTS `fm_favorite` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `name` TEXT NOT NULL, `uri` TEXT NOT NULL, `init_uri` TEXT, `options` INTEGER NOT NULL, `order` INTEGER NOT NULL, `type` INTEGER NOT NULL)\");\n        }\n    };\n    public static final Migration M_4_5 = new Migration(4, 5) {\n        @Override\n        public void migrate(@NonNull SupportSQLiteDatabase db) {\n            db.execSQL(\"CREATE TABLE IF NOT EXISTS `freeze_type` (`package_name` TEXT NOT NULL, `type` INTEGER NOT NULL, PRIMARY KEY(`package_name`))\");\n        }\n    };\n    public static final Migration M_5_6 = new Migration(5, 6) {\n        @Override\n        public void migrate(@NonNull SupportSQLiteDatabase db) {\n            db.execSQL(\"ALTER TABLE `app` ADD COLUMN `is_only_data_installed` INTEGER NOT NULL DEFAULT 0\");\n        }\n    };\n    public static final Migration M_6_7 = new Migration(6, 7) {\n        @Override\n        public void migrate(@NonNull SupportSQLiteDatabase db) {\n            db.execSQL(\"DROP TABLE IF EXISTS `file_hash`\");\n        }\n    };\n\n    public static AppsDb getInstance() {\n        if (sAppsDb == null) {\n            sAppsDb = Room.databaseBuilder(ContextUtils.getContext(), AppsDb.class, \"apps.db\")\n                    .addMigrations(M_2_3, M_3_4, M_4_5, M_5_6, M_6_7)\n                    .fallbackToDestructiveMigrationOnDowngrade()\n                    .build();\n            try {\n                sAppsDb.appDao().getAll();\n            } catch (Throwable th) {\n                th.printStackTrace();\n            }\n        }\n        return sAppsDb;\n    }\n\n    public abstract AppDao appDao();\n\n    public abstract BackupDao backupDao();\n\n    public abstract LogFilterDao logFilterDao();\n\n    public abstract OpHistoryDao opHistoryDao();\n\n    public abstract FmFavoriteDao fmFavoriteDao();\n\n    public abstract FreezeTypeDao freezeTypeDao();\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/db/dao/AppDao.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.db.dao;\n\nimport androidx.room.Dao;\nimport androidx.room.Delete;\nimport androidx.room.Insert;\nimport androidx.room.OnConflictStrategy;\nimport androidx.room.Query;\nimport androidx.room.Update;\n\nimport java.util.List;\n\nimport io.github.muntashirakon.AppManager.db.entity.App;\n\n@Dao\npublic interface AppDao {\n    @Query(\"SELECT * FROM app\")\n    List<App> getAll();\n\n    @Query(\"SELECT * FROM app WHERE is_installed = 1\")\n    List<App> getAllInstalled();\n\n    @Query(\"SELECT * FROM app WHERE package_name = :packageName\")\n    List<App> getAll(String packageName);\n\n    @Query(\"SELECT * FROM app WHERE package_name = :packageName AND user_id = :userId\")\n    List<App> getAll(String packageName, int userId);\n\n    @Insert(onConflict = OnConflictStrategy.REPLACE)\n    void insert(List<App> apps);\n\n    @Insert(onConflict = OnConflictStrategy.REPLACE)\n    void insert(App app);\n\n    @Update\n    void update(App app);\n\n    @Query(\"DELETE FROM app WHERE 1\")\n    void deleteAll();\n\n    @Delete\n    void delete(App app);\n\n    @Delete\n    void delete(List<App> apps);\n\n    @Query(\"DELETE FROM app WHERE package_name = :packageName AND user_id = :userId\")\n    void delete(String packageName, int userId);\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/db/dao/BackupDao.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.db.dao;\n\nimport androidx.room.Dao;\nimport androidx.room.Delete;\nimport androidx.room.Insert;\nimport androidx.room.OnConflictStrategy;\nimport androidx.room.Query;\nimport androidx.room.Update;\n\nimport java.util.List;\n\nimport io.github.muntashirakon.AppManager.db.entity.Backup;\n\n@Dao\npublic interface BackupDao {\n    @Query(\"SELECT * FROM backup\")\n    List<Backup> getAll();\n\n    @Query(\"SELECT * FROM backup WHERE package_name = :packageName\")\n    List<Backup> get(String packageName);\n\n    @Insert(onConflict = OnConflictStrategy.REPLACE)\n    void insert(List<Backup> backups);\n\n    @Insert(onConflict = OnConflictStrategy.REPLACE)\n    void insert(Backup backup);\n\n    @Update\n    void update(Backup backup);\n\n    @Delete\n    void delete(Backup backup);\n\n    @Delete\n    void delete(List<Backup> backups);\n\n    @Query(\"DELETE FROM backup WHERE package_name = :packageName AND backup_name = :backupName\")\n    void delete(String packageName, String backupName);\n\n    @Query(\"DELETE FROM backup WHERE 1\")\n    void deleteAll();\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/db/dao/FmFavoriteDao.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.db.dao;\n\nimport androidx.annotation.NonNull;\nimport androidx.room.Dao;\nimport androidx.room.Insert;\nimport androidx.room.OnConflictStrategy;\nimport androidx.room.Query;\n\nimport java.util.List;\n\nimport io.github.muntashirakon.AppManager.db.entity.FmFavorite;\n\n@Dao\npublic interface FmFavoriteDao {\n    @Query(\"SELECT * FROM fm_favorite\")\n    List<FmFavorite> getAll();\n\n    @Insert(onConflict = OnConflictStrategy.REPLACE)\n    long insert(@NonNull FmFavorite fmFavorite);\n\n    @Query(\"UPDATE fm_favorite SET name = :newName WHERE id = :id\")\n    void rename(long id, @NonNull String newName);\n\n    @Query(\"DELETE FROM fm_favorite WHERE id = :id\")\n    void delete(long id);\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/db/dao/FreezeTypeDao.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.db.dao;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.room.Dao;\nimport androidx.room.Delete;\nimport androidx.room.Insert;\nimport androidx.room.OnConflictStrategy;\nimport androidx.room.Query;\n\nimport io.github.muntashirakon.AppManager.db.entity.FreezeType;\nimport io.github.muntashirakon.AppManager.utils.FreezeUtils;\n\n@Dao\npublic interface FreezeTypeDao {\n    @Nullable\n    @Query(\"SELECT * FROM freeze_type WHERE package_name = :packageName LIMIT 1\")\n    FreezeType get(String packageName);\n\n    @Insert(onConflict = OnConflictStrategy.REPLACE)\n    void insert(FreezeType freezeType);\n\n    @Query(\"DELETE FROM freeze_type WHERE package_name = :packageName\")\n    void delete(String packageName);\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/db/dao/LogFilterDao.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.db.dao;\n\nimport androidx.room.Dao;\nimport androidx.room.Delete;\nimport androidx.room.Insert;\nimport androidx.room.OnConflictStrategy;\nimport androidx.room.Query;\n\nimport java.util.List;\n\nimport io.github.muntashirakon.AppManager.db.entity.LogFilter;\n\n@Dao\npublic interface LogFilterDao {\n    @Query(\"SELECT * FROM log_filter\")\n    List<LogFilter> getAll();\n\n    @Query(\"SELECT * FROM log_filter WHERE id = :id LIMIT 1\")\n    LogFilter get(long id);\n\n    @Query(\"INSERT INTO log_filter (name) VALUES(:filterName)\")\n    long insert(String filterName);\n\n    @Insert(onConflict = OnConflictStrategy.REPLACE)\n    void insert(LogFilter logFilter);\n\n    @Delete\n    void delete(LogFilter logFilter);\n\n    @Query(\"DELETE FROM log_filter WHERE id = :id\")\n    void delete(int id);\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/db/dao/OpHistoryDao.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.db.dao;\n\nimport androidx.room.Dao;\nimport androidx.room.Insert;\nimport androidx.room.OnConflictStrategy;\nimport androidx.room.Query;\n\nimport java.util.List;\n\nimport io.github.muntashirakon.AppManager.db.entity.OpHistory;\n\n@Dao\npublic interface OpHistoryDao {\n    @Query(\"SELECT * FROM op_history\")\n    List<OpHistory> getAll();\n\n    @Insert(onConflict = OnConflictStrategy.REPLACE)\n    long insert(OpHistory opHistory);\n\n    @Query(\"DELETE FROM op_history WHERE id = :id\")\n    void delete(long id);\n\n    @Query(\"DELETE FROM op_history WHERE 1\")\n    void deleteAll();\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/db/entity/App.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.db.entity;\n\nimport android.content.Context;\nimport android.content.pm.ApplicationInfo;\nimport android.content.pm.PackageInfo;\nimport android.os.UserHandleHidden;\nimport android.util.Pair;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.core.content.pm.PackageInfoCompat;\nimport androidx.room.ColumnInfo;\nimport androidx.room.Entity;\n\nimport java.io.Serializable;\nimport java.util.Objects;\n\nimport io.github.muntashirakon.AppManager.compat.ApplicationInfoCompat;\nimport io.github.muntashirakon.AppManager.rules.compontents.ComponentUtils;\nimport io.github.muntashirakon.AppManager.utils.FreezeUtils;\nimport io.github.muntashirakon.AppManager.utils.Utils;\n\n@SuppressWarnings(\"NotNullFieldNotInitialized\")\n@Entity(tableName = \"app\", primaryKeys = {\"package_name\", \"user_id\"})\npublic class App implements Serializable {\n    @ColumnInfo(name = \"package_name\")\n    @NonNull\n    public String packageName;\n\n    @ColumnInfo(name = \"user_id\", defaultValue = \"\" + UserHandleHidden.USER_NULL)\n    public int userId;\n\n    @ColumnInfo(name = \"label\")\n    public String packageLabel;\n\n    @ColumnInfo(name = \"version_name\")\n    public String versionName;\n\n    @ColumnInfo(name = \"version_code\")\n    public long versionCode;\n\n    @ColumnInfo(name = \"flags\", defaultValue = \"0\")\n    public int flags;\n\n    @ColumnInfo(name = \"uid\", defaultValue = \"0\")\n    public int uid;\n\n    @ColumnInfo(name = \"shared_uid\", defaultValue = \"NULL\")\n    @Nullable\n    public String sharedUserId;\n\n    @ColumnInfo(name = \"first_install_time\", defaultValue = \"0\")\n    public long firstInstallTime;\n\n    @ColumnInfo(name = \"last_update_time\", defaultValue = \"0\")\n    public long lastUpdateTime;\n\n    @ColumnInfo(name = \"target_sdk\", defaultValue = \"0\")\n    public int sdk;\n\n    @ColumnInfo(name = \"cert_name\", defaultValue = \"''\")\n    public String certName;\n\n    @ColumnInfo(name = \"cert_algo\", defaultValue = \"''\")\n    public String certAlgo;\n\n    @ColumnInfo(name = \"is_installed\", defaultValue = \"true\")\n    public boolean isInstalled;\n\n    @ColumnInfo(name = \"is_only_data_installed\", defaultValue = \"0\")\n    public boolean isOnlyDataInstalled;\n\n    @ColumnInfo(name = \"is_enabled\", defaultValue = \"false\")\n    public boolean isEnabled;\n\n    @ColumnInfo(name = \"has_activities\", defaultValue = \"false\")\n    public boolean hasActivities;\n\n    @ColumnInfo(name = \"has_splits\", defaultValue = \"false\")\n    public boolean hasSplits;\n\n    @ColumnInfo(name = \"has_keystore\", defaultValue = \"false\")\n    public boolean hasKeystore;\n\n    @ColumnInfo(name = \"uses_saf\", defaultValue = \"false\")\n    public boolean usesSaf;\n\n    @ColumnInfo(name = \"ssaid\", defaultValue = \"\")\n    public String ssaid;\n\n    @ColumnInfo(name = \"code_size\", defaultValue = \"0\")\n    public long codeSize;\n\n    @ColumnInfo(name = \"data_size\", defaultValue = \"0\")\n    public long dataSize;\n\n    @ColumnInfo(name = \"mobile_data\", defaultValue = \"0\")\n    public long mobileDataUsage;\n\n    @ColumnInfo(name = \"wifi_data\", defaultValue = \"0\")\n    public long wifiDataUsage;\n\n    @ColumnInfo(name = \"rules_count\", defaultValue = \"0\")\n    public int rulesCount;\n\n    @ColumnInfo(name = \"tracker_count\", defaultValue = \"0\")\n    public int trackerCount;\n\n    @ColumnInfo(name = \"open_count\", defaultValue = \"0\")\n    public int openCount;\n\n    @ColumnInfo(name = \"screen_time\", defaultValue = \"0\")\n    public long screenTime;\n\n    @ColumnInfo(name = \"last_usage_time\", defaultValue = \"0\")\n    public long lastUsageTime;\n\n    @ColumnInfo(name = \"last_action_time\", defaultValue = \"0\")\n    public long lastActionTime;\n\n    public boolean isSystemApp() {\n        return (flags & ApplicationInfo.FLAG_SYSTEM) != 0;\n    }\n\n    public boolean isDebuggable() {\n        return (flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;\n    }\n\n    @NonNull\n    public static App fromPackageInfo(@NonNull Context context, @NonNull PackageInfo packageInfo) {\n        App app = new App();\n        ApplicationInfo applicationInfo = packageInfo.applicationInfo;\n        app.packageName = applicationInfo.packageName;\n        app.uid = applicationInfo.uid;\n        app.userId = UserHandleHidden.getUserId(app.uid);\n        app.isInstalled = ApplicationInfoCompat.isInstalled(applicationInfo);\n        app.isOnlyDataInstalled = ApplicationInfoCompat.isOnlyDataInstalled(applicationInfo);\n        app.flags = applicationInfo.flags;\n        app.isEnabled = !FreezeUtils.isFrozen(applicationInfo);\n        app.packageLabel = ApplicationInfoCompat.loadLabelSafe(applicationInfo, context.getPackageManager()).toString();\n        app.sdk = applicationInfo.targetSdkVersion;\n        app.versionName = packageInfo.versionName;\n        app.versionCode = PackageInfoCompat.getLongVersionCode(packageInfo);\n        app.sharedUserId = packageInfo.sharedUserId;\n        Pair<String, String> issuerAndAlgoPair = Utils.getIssuerAndAlg(packageInfo);\n        app.certName = issuerAndAlgoPair.first;\n        app.certAlgo = issuerAndAlgoPair.second;\n        app.firstInstallTime = packageInfo.firstInstallTime;\n        app.lastUpdateTime = packageInfo.lastUpdateTime;\n        app.hasActivities = packageInfo.activities != null;\n        app.hasSplits = applicationInfo.splitSourceDirs != null;\n        app.rulesCount = 0;\n        app.trackerCount = ComponentUtils.getTrackerComponentsCountForPackage(packageInfo);\n        app.lastActionTime = System.currentTimeMillis();\n        return app;\n    }\n\n    @NonNull\n    public static App fromBackup(@NonNull Backup backup) {\n        App app = new App();\n        app.packageName = backup.packageName;\n        app.uid = 0;\n        app.userId = backup.userId;\n        app.isInstalled = false;\n        app.isOnlyDataInstalled = false;\n        if (backup.isSystem) {\n            app.flags |= ApplicationInfo.FLAG_SYSTEM;\n        }\n        app.isEnabled = true;\n        app.packageLabel = backup.label;\n        app.sdk = 0;\n        app.versionName = backup.versionName;\n        app.versionCode = backup.versionCode;\n        app.sharedUserId = null;\n        app.certName = \"\";\n        app.certAlgo = \"\";\n        app.firstInstallTime = backup.backupTime;\n        app.lastUpdateTime = backup.backupTime;\n        app.hasActivities = false;\n        app.hasSplits = backup.hasSplits;\n        app.rulesCount = 0;\n        app.trackerCount = 0;\n        app.lastActionTime = backup.backupTime;\n        app.hasKeystore = backup.hasKeyStore;\n        return app;\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) return true;\n        if (!(o instanceof App)) return false;\n        App app = (App) o;\n        return userId == app.userId && packageName.equals(app.packageName);\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hash(packageName, userId);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/db/entity/Backup.java",
    "content": "//SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.db.entity;\n\nimport android.text.TextUtils;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.room.ColumnInfo;\nimport androidx.room.Entity;\n\nimport java.io.IOException;\nimport java.util.Objects;\n\nimport io.github.muntashirakon.AppManager.backup.BackupItems;\nimport io.github.muntashirakon.AppManager.backup.BackupFlags;\nimport io.github.muntashirakon.AppManager.backup.BackupUtils;\nimport io.github.muntashirakon.AppManager.backup.CryptoUtils;\nimport io.github.muntashirakon.AppManager.backup.struct.BackupMetadataV2;\nimport io.github.muntashirakon.AppManager.backup.struct.BackupMetadataV5;\nimport io.github.muntashirakon.AppManager.utils.TarUtils;\n\n@SuppressWarnings(\"NotNullFieldNotInitialized\")\n@Entity(tableName = \"backup\", primaryKeys = {\"backup_name\", \"package_name\"})\npublic class Backup {\n    @ColumnInfo(name = \"package_name\")\n    @NonNull\n    public String packageName;\n\n    @ColumnInfo(name = \"backup_name\")\n    @NonNull\n    public String backupName;\n\n    @ColumnInfo(name = \"label\")\n    public String label;\n\n    @ColumnInfo(name = \"version_name\")\n    public String versionName;\n\n    @ColumnInfo(name = \"version_code\")\n    public long versionCode;\n\n    @ColumnInfo(name = \"is_system\")\n    public boolean isSystem;\n\n    @ColumnInfo(name = \"has_splits\")\n    public boolean hasSplits;\n\n    @ColumnInfo(name = \"has_rules\")\n    public boolean hasRules;\n\n    @ColumnInfo(name = \"backup_time\")\n    public long backupTime;\n\n    @ColumnInfo(name = \"crypto\")\n    @CryptoUtils.Mode\n    public String crypto;\n\n    @ColumnInfo(name = \"meta_version\")\n    public int version;\n\n    @ColumnInfo(name = \"flags\")\n    public int flags;\n\n    @ColumnInfo(name = \"user_id\")\n    public int userId;\n\n    @ColumnInfo(name = \"tar_type\")\n    @TarUtils.TarType\n    public String tarType;\n\n    @ColumnInfo(name = \"has_key_store\")\n    public boolean hasKeyStore;\n\n    @ColumnInfo(name = \"installer_app\")\n    @Nullable\n    public String installer;\n\n    @ColumnInfo(name = \"info_hash\")\n    public String relativeDir;\n\n    public BackupFlags getFlags() {\n        return new BackupFlags(flags);\n    }\n\n    @NonNull\n    public BackupItems.BackupItem getItem() throws IOException {\n        String relativeDir;\n        if (TextUtils.isEmpty(this.relativeDir)) {\n            if (version >= 5) {\n                // In backup v5 onwards, relativeDir must be set\n                throw new IOException(\"relativeDir not set.\");\n            }\n            // Relative directory needs to be inferred.\n            relativeDir = BackupUtils.getV4RelativeDir(userId, backupName, packageName);\n        } else relativeDir = this.relativeDir;\n        return BackupItems.findBackupItem(relativeDir);\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) return true;\n        if (!(o instanceof Backup)) return false;\n        Backup backup = (Backup) o;\n        return packageName.equals(backup.packageName)\n                && userId == backup.userId\n                && backupName.equals(backup.backupName);\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hash(packageName, userId, backupName);\n    }\n\n    @NonNull\n    public static Backup fromBackupMetadata(@NonNull BackupMetadataV2 metadata) {\n        Backup backup = new Backup();\n        backup.packageName = metadata.packageName;\n        backup.backupName = metadata.backupName != null ? metadata.backupName : \"\";\n        backup.label = metadata.label;\n        backup.versionName = metadata.versionName;\n        backup.versionCode = metadata.versionCode;\n        backup.isSystem = metadata.isSystem;\n        backup.hasSplits = metadata.isSplitApk;\n        backup.hasRules = metadata.hasRules;\n        backup.backupTime = metadata.backupTime;\n        backup.crypto = metadata.crypto;\n        backup.version = metadata.version;\n        backup.flags = metadata.flags.getFlags();\n        backup.userId = metadata.userId;\n        backup.tarType = metadata.tarType;\n        backup.hasKeyStore = metadata.keyStore;\n        backup.installer = metadata.installer;\n        backup.relativeDir = metadata.backupItem.getRelativeDir();\n        return backup;\n    }\n\n    @NonNull\n    public static Backup fromBackupMetadataV5(@NonNull BackupMetadataV5 metadata) {\n        return fromBackupInfoAndMeta(metadata.info, metadata.metadata);\n    }\n\n    @NonNull\n    public static Backup fromBackupInfoAndMeta(@NonNull BackupMetadataV5.Info info, @NonNull BackupMetadataV5.Metadata metadata) {\n        Backup backup = new Backup();\n        backup.packageName = metadata.packageName;\n        backup.backupName = metadata.backupName != null ? metadata.backupName : \"\";\n        backup.label = metadata.label;\n        backup.versionName = metadata.versionName;\n        backup.versionCode = metadata.versionCode;\n        backup.isSystem = metadata.isSystem;\n        backup.hasSplits = metadata.isSplitApk;\n        backup.hasRules = metadata.hasRules;\n        backup.backupTime = info.backupTime;\n        backup.crypto = info.crypto;\n        backup.version = metadata.version;\n        backup.flags = info.flags.getFlags();\n        backup.userId = info.userId;\n        backup.tarType = info.tarType;\n        backup.hasKeyStore = metadata.keyStore;\n        backup.installer = metadata.installer;\n        backup.relativeDir = info.getRelativeDir();\n        return backup;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/db/entity/FmFavorite.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.db.entity;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.room.ColumnInfo;\nimport androidx.room.Entity;\nimport androidx.room.PrimaryKey;\n\n@Entity(tableName = \"fm_favorite\")\npublic class FmFavorite {\n    @ColumnInfo(name = \"id\")\n    @PrimaryKey(autoGenerate = true)\n    public long id;\n    @ColumnInfo(name = \"name\")\n    @NonNull\n    public String name;\n    @ColumnInfo(name = \"uri\")\n    @NonNull\n    public String uri;\n    @ColumnInfo(name = \"init_uri\")\n    @Nullable\n    public String initUri;\n    @ColumnInfo(name = \"options\")\n    public int options;\n    @ColumnInfo(name = \"order\")\n    public long order;\n    @ColumnInfo(name = \"type\")\n    public int type;\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/db/entity/FreezeType.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.db.entity;\n\nimport androidx.annotation.NonNull;\nimport androidx.room.ColumnInfo;\nimport androidx.room.Entity;\nimport androidx.room.PrimaryKey;\n\nimport io.github.muntashirakon.AppManager.utils.FreezeUtils;\n\n@Entity(tableName = \"freeze_type\")\npublic class FreezeType {\n    @PrimaryKey\n    @ColumnInfo(name = \"package_name\")\n    @NonNull\n    public String packageName;\n\n    @ColumnInfo(name = \"type\")\n    @FreezeUtils.FreezeMethod\n    public int type;\n\n    public FreezeType() {}\n\n    public FreezeType(@NonNull String packageName, @FreezeUtils.FreezeMethod int type) {\n        this.packageName = packageName;\n        this.type = type;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/db/entity/LogFilter.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.db.entity;\n\nimport androidx.annotation.NonNull;\nimport androidx.room.ColumnInfo;\nimport androidx.room.Entity;\nimport androidx.room.Index;\nimport androidx.room.PrimaryKey;\n\nimport java.util.Comparator;\n\nimport io.github.muntashirakon.AppManager.utils.AlphanumComparator;\n\n@Entity(tableName = \"log_filter\", indices = {@Index(name = \"index_name\", value = {\"name\"}, unique = true)})\npublic class LogFilter implements Comparable<LogFilter> {\n    public static final Comparator<LogFilter> COMPARATOR = (o1, o2) ->\n            AlphanumComparator.compareStringIgnoreCase(o1.name, o2.name);\n\n    @ColumnInfo(name = \"id\")\n    @PrimaryKey(autoGenerate = true)\n    public long id;\n\n    @ColumnInfo(name = \"name\")\n    public String name;\n\n    @Override\n    public int compareTo(@NonNull LogFilter o) {\n        return COMPARATOR.compare(this, o);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/db/entity/OpHistory.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.db.entity;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.room.ColumnInfo;\nimport androidx.room.Entity;\nimport androidx.room.PrimaryKey;\n\n@Entity(tableName = \"op_history\")\npublic class OpHistory {\n    @ColumnInfo(name = \"id\")\n    @PrimaryKey(autoGenerate = true)\n    public long id;\n\n    @ColumnInfo(name = \"type\")\n    @NonNull\n    public String type;\n\n    @ColumnInfo(name = \"time\")\n    public long execTime;\n\n    @ColumnInfo(name = \"data\")\n    @NonNull\n    public String serializedData;\n\n    @ColumnInfo(name = \"status\")\n    @NonNull\n    public String status;\n\n    @ColumnInfo(name = \"extra\")\n    @Nullable\n    public String serializedExtra;\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/db/utils/AppDb.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.db.utils;\n\nimport static io.github.muntashirakon.AppManager.compat.PackageManagerCompat.GET_SIGNING_CERTIFICATES;\nimport static io.github.muntashirakon.AppManager.compat.PackageManagerCompat.MATCH_DISABLED_COMPONENTS;\nimport static io.github.muntashirakon.AppManager.compat.PackageManagerCompat.MATCH_STATIC_SHARED_AND_SDK_LIBRARIES;\nimport static io.github.muntashirakon.AppManager.compat.PackageManagerCompat.MATCH_UNINSTALLED_PACKAGES;\n\nimport android.annotation.UserIdInt;\nimport android.content.Context;\nimport android.content.pm.PackageInfo;\nimport android.content.pm.PackageManager;\nimport android.os.Build;\nimport android.os.RemoteException;\nimport android.os.UserHandleHidden;\nimport android.text.TextUtils;\nimport android.util.ArrayMap;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.WorkerThread;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.ListIterator;\nimport java.util.Map;\nimport java.util.Set;\n\nimport io.github.muntashirakon.AppManager.backup.BackupUtils;\nimport io.github.muntashirakon.AppManager.compat.PackageManagerCompat;\nimport io.github.muntashirakon.AppManager.db.AppsDb;\nimport io.github.muntashirakon.AppManager.db.dao.AppDao;\nimport io.github.muntashirakon.AppManager.db.dao.BackupDao;\nimport io.github.muntashirakon.AppManager.db.entity.App;\nimport io.github.muntashirakon.AppManager.db.entity.Backup;\nimport io.github.muntashirakon.AppManager.logs.Log;\nimport io.github.muntashirakon.AppManager.rules.compontents.ComponentsBlocker;\nimport io.github.muntashirakon.AppManager.self.SelfPermissions;\nimport io.github.muntashirakon.AppManager.settings.FeatureController;\nimport io.github.muntashirakon.AppManager.ssaid.SsaidSettings;\nimport io.github.muntashirakon.AppManager.types.PackageSizeInfo;\nimport io.github.muntashirakon.AppManager.uri.UriManager;\nimport io.github.muntashirakon.AppManager.usage.AppUsageStatsManager;\nimport io.github.muntashirakon.AppManager.usage.PackageUsageInfo;\nimport io.github.muntashirakon.AppManager.usage.TimeInterval;\nimport io.github.muntashirakon.AppManager.usage.UsageUtils;\nimport io.github.muntashirakon.AppManager.users.Users;\nimport io.github.muntashirakon.AppManager.utils.BroadcastUtils;\nimport io.github.muntashirakon.AppManager.utils.ExUtils;\nimport io.github.muntashirakon.AppManager.utils.KeyStoreUtils;\nimport io.github.muntashirakon.AppManager.utils.PackageUtils;\nimport io.github.muntashirakon.AppManager.utils.ThreadUtils;\n\npublic class AppDb {\n    public static final String TAG = AppDb.class.getSimpleName();\n\n    private static final Object sLock = new Object();\n\n    private final AppDao mAppDao;\n    private final BackupDao mBackupDao;\n\n    public AppDb() {\n        mAppDao = AppsDb.getInstance().appDao();\n        mBackupDao = AppsDb.getInstance().backupDao();\n    }\n\n    public List<App> getAllApplications() {\n        synchronized (sLock) {\n            return mAppDao.getAll();\n        }\n    }\n\n    public List<App> getAllInstalledApplications() {\n        synchronized (sLock) {\n            return mAppDao.getAllInstalled();\n        }\n    }\n\n    public List<App> getAllApplications(String packageName) {\n        synchronized (sLock) {\n            return mAppDao.getAll(packageName);\n        }\n    }\n\n    public List<App> getAllApplications(String packageName, @UserIdInt int userId) {\n        synchronized (sLock) {\n            return mAppDao.getAll(packageName, userId);\n        }\n    }\n\n    public List<Backup> getAllBackups() {\n        synchronized (sLock) {\n            return mBackupDao.getAll();\n        }\n    }\n\n    public List<Backup> getAllBackups(String packageName) {\n        synchronized (sLock) {\n            return mBackupDao.get(packageName);\n        }\n    }\n\n    /**\n     * Fetch backups without a lock file. Necessary checks must be done to ensure that the backups actually exist.\n     */\n    public List<Backup> getAllBackupsNoLock(String packageName) {\n        return mBackupDao.get(packageName);\n    }\n\n    public void insert(App app) {\n        synchronized (sLock) {\n            mAppDao.insert(app);\n        }\n    }\n\n    public void insert(Backup backup) {\n        synchronized (sLock) {\n            mBackupDao.insert(backup);\n        }\n    }\n\n    public void insertBackups(List<Backup> backups) {\n        synchronized (sLock) {\n            mBackupDao.insert(backups);\n        }\n    }\n\n    public void deleteApplication(String packageName, int userId) {\n        synchronized (sLock) {\n            mAppDao.delete(packageName, userId);\n        }\n    }\n\n    public void deleteAllApplications() {\n        synchronized (sLock) {\n            mAppDao.deleteAll();\n        }\n    }\n\n    public void deleteAllBackups() {\n        synchronized (sLock) {\n            mBackupDao.deleteAll();\n        }\n    }\n\n    public void deleteBackup(Backup backup) {\n        synchronized (sLock) {\n            mBackupDao.delete(backup);\n        }\n    }\n\n    @WorkerThread\n    public void loadInstalledOrBackedUpApplications(@NonNull Context context) {\n        getBackups(true);\n        updateApplications(context);\n    }\n\n    @WorkerThread\n    public List<App> updateApplications(@NonNull Context context, @NonNull String[] packageNames) {\n        synchronized (sLock) {\n            List<App> appList = new ArrayList<>();\n            for (String packageName : packageNames) {\n                appList.addAll(updateApplicationInternal(context, packageName));\n            }\n            // Update usage and others\n            updateVariableData(context, appList);\n            mAppDao.insert(appList);\n            return appList;\n        }\n    }\n\n    @WorkerThread\n    public List<App> updateApplication(@NonNull Context context, @NonNull String packageName) {\n        synchronized (sLock) {\n            List<App> appList = updateApplicationInternal(context, packageName);\n            // Update usage and others\n            updateVariableData(context, appList);\n            mAppDao.insert(appList);\n            return appList;\n        }\n    }\n\n    @WorkerThread\n    @NonNull\n    private List<App> updateApplicationInternal(@NonNull Context context, @NonNull String packageName) {\n        int[] userIds = Users.getUsersIds();\n        List<App> oldApps = new ArrayList<>(mAppDao.getAll(packageName));\n        List<App> appList = new ArrayList<>(userIds.length);\n        List<Backup> backups = new ArrayList<>(mBackupDao.get(packageName));\n        for (int userId : userIds) {\n            int oldAppIndex = findIndexOfApp(oldApps, packageName, userId);\n            PackageInfo packageInfo = null;\n            Backup backup = null;\n            ListIterator<Backup> backupListIterator = backups.listIterator();\n            while (backupListIterator.hasNext()) {\n                Backup b = backupListIterator.next();\n                if (b.userId == userId) {\n                    backup = b;\n                    backupListIterator.remove();\n                    break;\n                }\n            }\n            try {\n                packageInfo = PackageManagerCompat.getPackageInfo(packageName,\n                        PackageManager.GET_META_DATA | GET_SIGNING_CERTIFICATES | PackageManager.GET_ACTIVITIES\n                                | PackageManager.GET_RECEIVERS | PackageManager.GET_PROVIDERS\n                                | PackageManager.GET_SERVICES | MATCH_DISABLED_COMPONENTS | MATCH_UNINSTALLED_PACKAGES\n                                | MATCH_STATIC_SHARED_AND_SDK_LIBRARIES, userId);\n            } catch (RemoteException | PackageManager.NameNotFoundException | SecurityException e) {\n                // Package does not exist\n            }\n            if (backup == null && packageInfo == null) {\n                // Neither backup nor package exist\n                if (oldAppIndex >= 0) {\n                    // Delete existing backup\n                    mAppDao.delete(oldApps.get(oldAppIndex));\n                }\n                continue;\n            }\n            if (oldAppIndex >= 0) {\n                // There's already existing app\n                App oldApp = oldApps.get(oldAppIndex);\n                mAppDao.delete(oldApp);\n                if ((packageInfo != null && isUpToDate(oldApp, packageInfo))\n                        || (backup != null && isUpToDate(oldApp, backup))) {\n                    // Up-to-date app\n                    appList.add(oldApp);\n                    oldApp.lastActionTime = System.currentTimeMillis();\n                    continue;\n                }\n            }\n            // New app\n            App app = packageInfo != null ? App.fromPackageInfo(context, packageInfo) : App.fromBackup(backup);\n            appList.add(app);\n        }\n\n        // Add the rest of the backups if any\n        for (Backup backup : backups) {\n            appList.add(App.fromBackup(backup));\n        }\n\n        // Return the list instead of triggering broadcast\n        return appList;\n    }\n\n    @WorkerThread\n    public void updateApplications(@NonNull Context context) {\n        synchronized (sLock) {\n            Map<String, Backup> backups = getBackups(false);\n            List<App> oldApps = new ArrayList<>(mAppDao.getAll());\n            List<App> modifiedApps = new ArrayList<>();\n            Set<String> newApps = new HashSet<>();\n            Set<String> updatedApps = new HashSet<>();\n\n            // Interrupt thread on request\n            if (ThreadUtils.isInterrupted()) return;\n\n            for (int userId : Users.getUsersIds()) {\n                // Interrupt thread on request\n                if (ThreadUtils.isInterrupted()) return;\n\n                if (!SelfPermissions.checkCrossUserPermission(userId, false)) {\n                    // No support for cross user\n                    continue;\n                }\n\n                List<PackageInfo> packageInfoList = PackageManagerCompat.getInstalledPackages(\n                        GET_SIGNING_CERTIFICATES | PackageManager.GET_ACTIVITIES\n                                | PackageManager.GET_RECEIVERS | PackageManager.GET_PROVIDERS\n                                | PackageManager.GET_SERVICES | MATCH_DISABLED_COMPONENTS\n                                | MATCH_UNINSTALLED_PACKAGES | MATCH_STATIC_SHARED_AND_SDK_LIBRARIES, userId);\n\n                for (PackageInfo packageInfo : packageInfoList) {\n                    // Interrupt thread on request\n                    if (ThreadUtils.isInterrupted()) return;\n\n                    int oldAppIndex = findIndexOfApp(oldApps, packageInfo.packageName, UserHandleHidden.getUserId(packageInfo.applicationInfo.uid));\n                    if (oldAppIndex >= 0) {\n                        // There's already existing app\n                        App oldApp = oldApps.remove(oldAppIndex);\n                        if (isUpToDate(oldApp, packageInfo)) {\n                            // Up-to-date app\n                            updatedApps.add(oldApp.packageName);\n                            modifiedApps.add(oldApp);\n                            backups.remove(packageInfo.packageName);\n                            oldApp.lastActionTime = System.currentTimeMillis();\n                            continue;\n                        }\n                    }\n                    // New app\n                    App app = App.fromPackageInfo(context, packageInfo);\n                    backups.remove(packageInfo.packageName);\n                    newApps.add(app.packageName);\n                    modifiedApps.add(app);\n                }\n            }\n\n            // Update usage and others\n            updateVariableData(context, modifiedApps);\n\n            // Add rest of the backup items, i.e., items that aren't installed\n            for (Backup backup : backups.values()) {\n                if (backup == null) continue;\n                // Interrupt thread on request\n                if (ThreadUtils.isInterrupted()) return;\n\n                int oldAppIndex = findIndexOfApp(oldApps, backup.packageName, backup.userId);\n                if (oldAppIndex >= 0) {\n                    // There's already existing app\n                    App oldApp = oldApps.remove(oldAppIndex);\n                    if (isUpToDate(oldApp, backup)) {\n                        // Up-to-date app\n                        updatedApps.add(oldApp.packageName);\n                        modifiedApps.add(oldApp);\n                        continue;\n                    }\n                }\n                // New app\n                App app = App.fromBackup(backup);\n                newApps.add(app.packageName);\n                modifiedApps.add(app);\n            }\n            // Add new data\n            mAppDao.delete(oldApps);\n            mAppDao.insert(modifiedApps);\n            if (!oldApps.isEmpty()) {\n                // Delete broadcast\n                BroadcastUtils.sendDbPackageRemoved(context, getPackageNamesFromApps(oldApps));\n            }\n            if (!newApps.isEmpty()) {\n                // New apps\n                BroadcastUtils.sendDbPackageAdded(context, newApps.toArray(new String[0]));\n            }\n            if (!updatedApps.isEmpty()) {\n                // Altered apps\n                BroadcastUtils.sendDbPackageAltered(context, updatedApps.toArray(new String[0]));\n            }\n        }\n\n    }\n\n    @WorkerThread\n    @NonNull\n    public Map<String, Backup> getBackups(boolean loadBackups) {\n        if (loadBackups) {\n            // Very long operation\n            return BackupUtils.storeAllAndGetLatestBackupMetadata();\n        } else {\n            return BackupUtils.getAllLatestBackupMetadataFromDb();\n        }\n    }\n\n    private static void updateVariableData(@NonNull Context context, @NonNull List<App> modifiedApps) {\n        UriManager uriManager = new UriManager();\n        ArrayMap<Integer, SsaidSettings> userIdSsaidSettingsMap = new ArrayMap<>();\n        List<PackageUsageInfo> packageUsageInfoList = new ArrayList<>();\n        boolean hasUsageAccess = FeatureController.isUsageAccessEnabled() && SelfPermissions.checkUsageStatsPermission();\n        for (int userId : Users.getUsersIds()) {\n            // Interrupt thread on request\n            if (ThreadUtils.isInterrupted()) return;\n            if (hasUsageAccess) {\n                TimeInterval interval = UsageUtils.getLastWeek();\n                List<PackageUsageInfo> usageInfoList = ExUtils.exceptionAsNull(() ->\n                        AppUsageStatsManager.getInstance().getUsageStats(interval, userId));\n                if (usageInfoList != null) {\n                    packageUsageInfoList.addAll(usageInfoList);\n                }\n            }\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {\n                try {\n                    userIdSsaidSettingsMap.put(userId, new SsaidSettings(userId));\n                } catch (IOException e) {\n                    Log.w(TAG, \"Error: \" + e.getMessage());\n                }\n            }\n        }\n        for (App app : modifiedApps) {\n            if (!app.isInstalled && !app.isSystemApp()) {\n                continue;\n            }\n            int userId = app.userId;\n            try (ComponentsBlocker cb = ComponentsBlocker.getInstance(app.packageName, userId, false)) {\n                app.rulesCount = cb.entryCount();\n            }\n            app.codeSize = app.dataSize = 0;\n            if (hasUsageAccess) {\n                PackageSizeInfo sizeInfo = PackageUtils.getPackageSizeInfo(context, app.packageName, userId, null);\n                if (sizeInfo != null) {\n                    app.codeSize = sizeInfo.codeSize + sizeInfo.obbSize;\n                    app.dataSize = sizeInfo.dataSize + sizeInfo.mediaSize + sizeInfo.cacheSize;\n                }\n            }\n            // Interrupt thread on request\n            if (ThreadUtils.isInterrupted()) return;\n            if (!app.isInstalled) {\n                continue;\n            }\n            app.hasKeystore = KeyStoreUtils.hasKeyStore(app.uid);\n            app.usesSaf = uriManager.getGrantedUris(app.packageName) != null;\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {\n                SsaidSettings ssaidSettings = userIdSsaidSettingsMap.get(userId);\n                if (ssaidSettings != null) {\n                    String ssaid = ssaidSettings.getSsaid(app.packageName, app.uid);\n                    app.ssaid = TextUtils.isEmpty(ssaid) ? null : ssaid;\n                } else {\n                    app.ssaid = null;\n                }\n            }\n            PackageUsageInfo usageInfo = findUsage(packageUsageInfoList, app.packageName, userId);\n            if (usageInfo != null) {\n                app.mobileDataUsage = usageInfo.mobileData != null ? usageInfo.mobileData.getTotal() : 0;\n                app.wifiDataUsage = usageInfo.wifiData != null ? usageInfo.wifiData.getTotal() : 0;\n                app.openCount = usageInfo.timesOpened;\n                app.screenTime = usageInfo.screenTime;\n                app.lastUsageTime = usageInfo.lastUsageTime;\n            } else {\n                app.mobileDataUsage = app.wifiDataUsage = app.screenTime = app.lastUsageTime = 0;\n                app.openCount = 0;\n            }\n        }\n    }\n\n    private static int findIndexOfApp(@NonNull List<App> appList, @NonNull String packageName, @UserIdInt int userId) {\n        for (int i = 0; i < appList.size(); ++i) {\n            App app = appList.get(i);\n            if (app.userId == userId && app.packageName.equals(packageName)) {\n                return i;\n            }\n        }\n        return -1;\n    }\n\n    @Nullable\n    private static PackageUsageInfo findUsage(@NonNull List<PackageUsageInfo> usageInfoList, @NonNull String packageName, @UserIdInt int userId) {\n        for (PackageUsageInfo usageInfo : usageInfoList) {\n            if (usageInfo.userId == userId && usageInfo.packageName.equals(packageName)) {\n                return usageInfo;\n            }\n        }\n        return null;\n    }\n\n    private static boolean isUpToDate(@NonNull App currentApp, @NonNull PackageInfo installedPackageInfo) {\n        if (!currentApp.isInstalled) {\n            // The app was not installed earlier\n            return false;\n        }\n        // App was installed\n        return currentApp.lastUpdateTime == installedPackageInfo.lastUpdateTime\n                && currentApp.flags == installedPackageInfo.applicationInfo.flags;\n    }\n\n    private static boolean isUpToDate(@NonNull App currentApp, @NonNull Backup backup) {\n        if (currentApp.isInstalled) {\n            // The app was installed earlier\n            return false;\n        }\n        // App was not installed\n        if (currentApp.sdk != 0) {\n            // The app is a system app\n            return true;\n        }\n        // The app is a backed up app\n        return currentApp.lastUpdateTime == backup.backupTime;\n    }\n\n    @NonNull\n    private static String[] getPackageNamesFromApps(@NonNull List<App> apps) {\n        HashSet<String> packages = new HashSet<>(apps.size());\n        for (App app : apps) {\n            packages.add(app.packageName);\n        }\n        return packages.toArray(new String[0]);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/debloat/BloatwareDetailsDialog.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.debloat;\n\nimport android.app.Application;\nimport android.content.Intent;\nimport android.content.res.ColorStateList;\nimport android.graphics.Color;\nimport android.graphics.drawable.Drawable;\nimport android.os.Bundle;\nimport android.text.SpannableStringBuilder;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.ImageView;\nimport android.widget.TextView;\n\nimport androidx.annotation.ColorInt;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.StringRes;\nimport androidx.appcompat.widget.LinearLayoutCompat;\nimport androidx.core.graphics.ColorUtils;\nimport androidx.lifecycle.AndroidViewModel;\nimport androidx.lifecycle.MutableLiveData;\nimport androidx.lifecycle.ViewModelProvider;\nimport androidx.recyclerview.widget.LinearLayoutManager;\n\nimport com.google.android.material.button.MaterialButton;\nimport com.google.android.material.chip.Chip;\nimport com.google.android.material.textview.MaterialTextView;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\n\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.StaticDataset;\nimport io.github.muntashirakon.AppManager.db.utils.AppDb;\nimport io.github.muntashirakon.AppManager.details.AppDetailsActivity;\nimport io.github.muntashirakon.util.AdapterUtils;\nimport io.github.muntashirakon.AppManager.utils.ThreadUtils;\nimport io.github.muntashirakon.AppManager.utils.UIUtils;\nimport io.github.muntashirakon.AppManager.utils.appearance.ColorCodes;\nimport io.github.muntashirakon.dialog.CapsuleBottomSheetDialogFragment;\nimport io.github.muntashirakon.util.UiUtils;\nimport io.github.muntashirakon.widget.FlowLayout;\nimport io.github.muntashirakon.widget.MaterialAlertView;\nimport io.github.muntashirakon.widget.RecyclerView;\n\n\npublic class BloatwareDetailsDialog extends CapsuleBottomSheetDialogFragment {\n    public static final String TAG = BloatwareDetailsDialog.class.getSimpleName();\n\n    public static final String ARG_PACKAGE_NAME = \"pkg\";\n\n    @NonNull\n    public static BloatwareDetailsDialog getInstance(@NonNull String packageName) {\n        BloatwareDetailsDialog fragment = new BloatwareDetailsDialog();\n        Bundle args = new Bundle();\n        args.putString(ARG_PACKAGE_NAME, packageName);\n        fragment.setArguments(args);\n        return fragment;\n    }\n\n    private ImageView mAppIconView;\n    private MaterialButton mOpenAppInfoButton;\n    private TextView mAppLabelView;\n    private TextView mPackageNameView;\n    private FlowLayout mFlowLayout;\n    private MaterialAlertView mWarningView;\n    private MaterialTextView mDescriptionView;\n    private LinearLayoutCompat mSuggestionContainer;\n    private RecyclerView mSuggestionView;\n    private SuggestionsAdapter mAdapter;\n\n    @Override\n    public boolean displayLoaderByDefault() {\n        return true;\n    }\n\n    @NonNull\n    @Override\n    public View initRootView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {\n        View view = inflater.inflate(R.layout.dialog_bloatware_details, container, false);\n        mAppIconView = view.findViewById(R.id.icon);\n        mOpenAppInfoButton = view.findViewById(R.id.info);\n        mAppLabelView = view.findViewById(R.id.name);\n        mPackageNameView = view.findViewById(R.id.package_name);\n        mFlowLayout = view.findViewById(R.id.tag_cloud);\n        mWarningView = view.findViewById(R.id.alert_text);\n        mDescriptionView = view.findViewById(R.id.apk_description);\n        mSuggestionContainer = view.findViewById(R.id.container);\n        mSuggestionView = view.findViewById(R.id.recycler_view);\n        mSuggestionView.setLayoutManager(new LinearLayoutManager(requireContext()));\n        mAdapter = new SuggestionsAdapter();\n        mSuggestionView.setAdapter(mAdapter);\n        return view;\n    }\n\n    @Override\n    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {\n        super.onViewCreated(view, savedInstanceState);\n        String packageName = requireArguments().getString(ARG_PACKAGE_NAME);\n        if (packageName == null) {\n            dismiss();\n            return;\n        }\n        BloatwareDetailsViewModel viewModel = new ViewModelProvider(requireActivity()).get(BloatwareDetailsViewModel.class);\n        viewModel.debloatObjectLiveData.observe(getViewLifecycleOwner(), debloatObject -> {\n            if (debloatObject == null) {\n                dismiss();\n                return;\n            }\n            finishLoading();\n            updateDialog(debloatObject);\n            updateDialog(debloatObject.getSuggestions());\n        });\n        viewModel.findDebloatObject(packageName);\n    }\n\n    private void updateDialog(@NonNull DebloatObject debloatObject) {\n        Drawable icon = debloatObject.getIcon();\n        mAppIconView.setImageDrawable(icon != null ? icon : requireActivity().getPackageManager().getDefaultActivityIcon());\n        int[] users = debloatObject.getUsers();\n        if (users != null && users.length > 0) {\n            mOpenAppInfoButton.setVisibility(View.VISIBLE);\n            mOpenAppInfoButton.setOnClickListener(v -> {\n                Intent appDetailsIntent = AppDetailsActivity.getIntent(requireContext(), debloatObject.packageName,\n                        users[0]);\n                startActivity(appDetailsIntent);\n                dismiss();\n            });\n        } else {\n            mOpenAppInfoButton.setVisibility(View.GONE);\n        }\n        mAppLabelView.setText(debloatObject.getLabelOrPackageName());\n        mPackageNameView.setText(debloatObject.packageName);\n        String warning = debloatObject.getWarning();\n        if (warning != null) {\n            mWarningView.setVisibility(View.VISIBLE);\n            mWarningView.setText(warning);\n            if (debloatObject.getRemoval() >= DebloatObject.REMOVAL_CAUTION) {\n                mWarningView.setAlertType(MaterialAlertView.ALERT_TYPE_INFO);\n            } else mWarningView.setAlertType(MaterialAlertView.ALERT_TYPE_WARN);\n        } else mWarningView.setVisibility(View.GONE);\n        mDescriptionView.setText(getDescription(debloatObject));\n        // Add tags\n        int removalColor;\n        @StringRes\n        int removalRes;\n        switch (debloatObject.getRemoval()) {\n            case DebloatObject.REMOVAL_SAFE:\n                removalColor = ColorCodes.getRemovalSafeIndicatorColor(requireContext());\n                removalRes = R.string.debloat_removal_safe_short_description;\n                break;\n            default:\n            case DebloatObject.REMOVAL_CAUTION:\n                removalColor = ColorCodes.getRemovalCautionIndicatorColor(requireContext());\n                removalRes = R.string.debloat_removal_caution_short_description;\n                break;\n            case DebloatObject.REMOVAL_REPLACE:\n                removalColor = ColorCodes.getRemovalReplaceIndicatorColor(requireContext());\n                removalRes = R.string.debloat_removal_replace_short_description;\n                break;\n            case DebloatObject.REMOVAL_UNSAFE:\n                removalColor = ColorCodes.getRemovalUnsafeIndicatorColor(requireContext());\n                removalRes = R.string.debloat_removal_unsafe;\n                break;\n        }\n        mFlowLayout.removeAllViews();\n        addTag(mFlowLayout, debloatObject.type);\n        addTag(mFlowLayout, removalRes, removalColor);\n    }\n\n    private void updateDialog(@Nullable List<SuggestionObject> suggestionObjects) {\n        if (suggestionObjects == null || suggestionObjects.isEmpty()) {\n            mSuggestionContainer.setVisibility(View.GONE);\n            return;\n        }\n        mSuggestionContainer.setVisibility(View.VISIBLE);\n        mAdapter.setList(suggestionObjects);\n    }\n\n    @NonNull\n    private CharSequence getDescription(@NonNull DebloatObject debloatObject) {\n        String description = debloatObject.getDescription();\n        String[] refSites = debloatObject.getWebRefs();\n        String[] dependencies = debloatObject.getDependencies();\n        String[] requiredBy = debloatObject.getRequiredBy();\n        SpannableStringBuilder sb = new SpannableStringBuilder();\n        sb.append(description.trim());\n        if (dependencies.length > 0) {\n            // Add dependencies\n            if (dependencies.length == 1) {\n                sb.append(UIUtils.getBoldString(\"\\n\\nDependency: \")).append(dependencies[0]);\n            } else {\n                sb.append(UIUtils.getBoldString(\"\\n\\nDependencies\\n\"))\n                        .append(UiUtils.getOrderedList(Arrays.asList(dependencies)));\n            }\n        }\n        if (requiredBy.length > 0) {\n            // Add dependencies\n            if (requiredBy.length == 1) {\n                sb.append(UIUtils.getBoldString(\"\\n\\nRequired by: \")).append(requiredBy[0]);\n            } else {\n                sb.append(UIUtils.getBoldString(\"\\n\\nRequired by\\n\"))\n                        .append(UiUtils.getOrderedList(Arrays.asList(requiredBy)));\n            }\n        }\n        if (refSites.length > 0) {\n            // Add references\n            sb.append(UIUtils.getBoldString(\"\\n\\nReferences\\n\"))\n                    .append(UiUtils.getOrderedList(Arrays.asList(refSites)));\n        }\n        return sb;\n    }\n\n    private void addTag(@NonNull ViewGroup parent, @StringRes int titleRes, @ColorInt int background) {\n        Chip chip = (Chip) LayoutInflater.from(requireContext()).inflate(R.layout.item_chip, parent, false);\n        chip.setText(titleRes);\n        chip.setChipBackgroundColor(ColorStateList.valueOf(background));\n        double luminance = ColorUtils.calculateLuminance(background);\n        chip.setTextColor(luminance < 0.5 ? Color.WHITE : Color.BLACK);\n        parent.addView(chip);\n    }\n\n    private void addTag(@NonNull ViewGroup parent, @NonNull CharSequence title) {\n        Chip chip = (Chip) LayoutInflater.from(requireContext()).inflate(R.layout.item_chip, parent, false);\n        chip.setText(title);\n        parent.addView(chip);\n    }\n\n    public static class BloatwareDetailsViewModel extends AndroidViewModel {\n        public final MutableLiveData<DebloatObject> debloatObjectLiveData = new MutableLiveData<>();\n\n        public BloatwareDetailsViewModel(@NonNull Application application) {\n            super(application);\n        }\n\n        public void findDebloatObject(@NonNull String packageName) {\n            ThreadUtils.postOnBackgroundThread(() -> {\n                List<DebloatObject> debloatObjects = StaticDataset.getDebloatObjects();\n                for (DebloatObject debloatObject : debloatObjects) {\n                    if (packageName.equals(debloatObject.packageName)) {\n                        debloatObject.fillInstallInfo(getApplication(), new AppDb());\n                        debloatObjectLiveData.postValue(debloatObject);\n                        return;\n                    }\n                }\n                debloatObjectLiveData.postValue(null);\n            });\n        }\n    }\n\n    private class SuggestionsAdapter extends RecyclerView.Adapter<SuggestionsAdapter.SuggestionViewHolder> {\n        private final List<SuggestionObject> mSuggestions = Collections.synchronizedList(new ArrayList<>());\n\n        public SuggestionsAdapter() {\n        }\n\n        public void setList(@NonNull List<SuggestionObject> suggestions) {\n            AdapterUtils.notifyDataSetChanged(this, mSuggestions, suggestions);\n        }\n\n        @NonNull\n        @Override\n        public SuggestionViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {\n            View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_bloatware_details, parent, false);\n            return new SuggestionViewHolder(v);\n        }\n\n        @Override\n        public void onBindViewHolder(@NonNull SuggestionViewHolder holder, int position) {\n            SuggestionObject suggestion = mSuggestions.get(position);\n            holder.labelView.setText(suggestion.getLabel());\n            holder.packageNameView.setText(suggestion.packageName);\n            int[] users = suggestion.getUsers();\n            if (users != null && users.length > 0) {\n                MaterialButton appInfoButton = holder.marketOrAppInfoButton;\n                appInfoButton.setIconResource(io.github.muntashirakon.ui.R.drawable.ic_information);\n                appInfoButton.setOnClickListener(v -> {\n                    Intent appDetailsIntent = AppDetailsActivity.getIntent(requireContext(), suggestion.packageName,\n                            users[0]);\n                    startActivity(appDetailsIntent);\n                });\n            } else {\n                MaterialButton marketButton = holder.marketOrAppInfoButton;\n                marketButton.setIconResource(suggestion.isInFDroidMarket() ? R.drawable.ic_frost_fdroid : R.drawable.ic_frost_aurorastore);\n                marketButton.setOnClickListener(v -> {\n                    Intent appDetailsIntent = suggestion.getMarketLink();\n                    appDetailsIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);\n                    try {\n                        startActivity(appDetailsIntent);\n                    } catch (Throwable th) {\n                        UIUtils.displayLongToast(\"Error: \" + th.getMessage());\n                    }\n                });\n            }\n            String reason = suggestion.getReason();\n            StringBuilder sb = new StringBuilder();\n            if (reason != null) sb.append(reason).append(\"\\n\");\n            sb.append(suggestion.getRepo());\n            holder.repoView.setText(sb);\n        }\n\n        @Override\n        public int getItemCount() {\n            return mSuggestions.size();\n        }\n\n        @Override\n        public long getItemId(int position) {\n            return mSuggestions.get(position).hashCode();\n        }\n\n        private class SuggestionViewHolder extends RecyclerView.ViewHolder {\n            final TextView labelView;\n            final TextView packageNameView;\n            final TextView repoView;\n            final MaterialButton marketOrAppInfoButton;\n\n            public SuggestionViewHolder(@NonNull View itemView) {\n                super(itemView);\n                labelView = itemView.findViewById(R.id.name);\n                packageNameView = itemView.findViewById(R.id.package_name);\n                repoView = itemView.findViewById(R.id.message);\n                marketOrAppInfoButton = itemView.findViewById(R.id.info);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/debloat/DebloatObject.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.debloat;\n\nimport static io.github.muntashirakon.AppManager.compat.PackageManagerCompat.MATCH_STATIC_SHARED_AND_SDK_LIBRARIES;\nimport static io.github.muntashirakon.AppManager.compat.PackageManagerCompat.MATCH_UNINSTALLED_PACKAGES;\n\nimport android.content.Context;\nimport android.content.pm.ApplicationInfo;\nimport android.content.pm.PackageManager;\nimport android.graphics.drawable.Drawable;\nimport android.os.RemoteException;\n\nimport androidx.annotation.IntDef;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport com.google.gson.annotations.SerializedName;\n\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.util.List;\n\nimport io.github.muntashirakon.AppManager.compat.ApplicationInfoCompat;\nimport io.github.muntashirakon.AppManager.compat.PackageManagerCompat;\nimport io.github.muntashirakon.AppManager.db.entity.App;\nimport io.github.muntashirakon.AppManager.db.utils.AppDb;\nimport io.github.muntashirakon.AppManager.utils.ArrayUtils;\nimport io.github.muntashirakon.AppManager.utils.FreezeUtils;\n\npublic class DebloatObject {\n    @IntDef({REMOVAL_SAFE, REMOVAL_REPLACE, REMOVAL_CAUTION, REMOVAL_UNSAFE})\n    @Retention(RetentionPolicy.SOURCE)\n    public @interface Removal {\n    }\n\n    public static final int REMOVAL_SAFE = 1;\n    public static final int REMOVAL_REPLACE = 1 << 1;\n    public static final int REMOVAL_CAUTION = 1 << 2;\n    public static final int REMOVAL_UNSAFE = 1 << 3;\n\n    @SerializedName(\"id\")\n    public String packageName;\n    @SerializedName(\"label\")\n    @Nullable\n    private String mInternalLabel;\n    @SerializedName(\"tags\")\n    @Nullable\n    private String[] mTags;\n    @SerializedName(\"dependencies\")\n    @Nullable\n    private String[] mDependencies;\n    @SerializedName(\"required_by\")\n    @Nullable\n    private String[] mRequiredBy;\n    // Possible values: aosp, carrier, google, misc, oem, pending\n    @SerializedName(\"type\")\n    public String type;\n    @SerializedName(\"description\")\n    private String mDescription;\n    @SerializedName(\"web\")\n    @Nullable\n    private String[] mWebRefs;\n    @SerializedName(\"removal\")\n    private String mRemoval;\n    @SerializedName(\"warning\")\n    @Nullable\n    private String mWarning;\n    @SerializedName(\"suggestions\")\n    @Nullable\n    private String mSuggestionId;\n\n    private int mId;\n\n    @Nullable\n    private Drawable mIcon;\n    @Nullable\n    private CharSequence mLabel;\n    @Nullable\n    private int[] mUsers;\n    private boolean mInstalled;\n    @Nullable\n    private Boolean mSystemApp = null;\n    @Nullable\n    private Boolean mFrozen = null;\n    @Nullable\n    private List<SuggestionObject> mSuggestions;\n\n    public void setId(int id) {\n        mId = id;\n    }\n\n    public int getId() {\n        return mId;\n    }\n\n    @NonNull\n    public String[] getDependencies() {\n        return ArrayUtils.defeatNullable(mDependencies);\n    }\n\n    @NonNull\n    public String[] getRequiredBy() {\n        return ArrayUtils.defeatNullable(mRequiredBy);\n    }\n\n    @Removal\n    public int getRemoval() {\n        switch (mRemoval) {\n            default:\n            case \"safe\":\n                return REMOVAL_SAFE;\n            case \"replace\":\n                return REMOVAL_REPLACE;\n            case \"caution\":\n                return REMOVAL_CAUTION;\n            case \"unsafe\":\n                return REMOVAL_UNSAFE;\n        }\n    }\n\n    @Nullable\n    public String getWarning() {\n        return mWarning;\n    }\n\n    public String getDescription() {\n        return mDescription;\n    }\n\n    @NonNull\n    public String[] getWebRefs() {\n        return ArrayUtils.defeatNullable(mWebRefs);\n    }\n\n    @Nullable\n    public String getSuggestionId() {\n        return mSuggestionId;\n    }\n\n    @Nullable\n    public List<SuggestionObject> getSuggestions() {\n        return mSuggestions;\n    }\n\n    public void setSuggestions(@Nullable List<SuggestionObject> suggestions) {\n        mSuggestions = suggestions;\n    }\n\n    @Nullable\n    public CharSequence getLabel() {\n        return mLabel != null ? mLabel : mInternalLabel;\n    }\n    @NonNull\n    public CharSequence getLabelOrPackageName() {\n        CharSequence label = mLabel != null ? mLabel : mInternalLabel;\n        return label != null ? label : packageName;\n    }\n\n    @Nullable\n    public Drawable getIcon() {\n        return mIcon;\n    }\n\n    @Nullable\n    public int[] getUsers() {\n        return mUsers;\n    }\n\n    private void addUser(int userId) {\n        if (mUsers == null) {\n            mUsers = new int[]{userId};\n        } else {\n            mUsers = ArrayUtils.appendInt(mUsers, userId);\n        }\n    }\n\n    public boolean isInstalled() {\n        return mInstalled;\n    }\n\n    public boolean isSystemApp() {\n        return Boolean.TRUE.equals(mSystemApp);\n    }\n\n    public boolean isUserApp() {\n        return Boolean.FALSE.equals(mSystemApp);\n    }\n\n    public boolean isFrozen() {\n        return Boolean.TRUE.equals(mFrozen);\n    }\n\n    public void fillInstallInfo(@NonNull Context context, @NonNull AppDb appDb) {\n        PackageManager pm = context.getPackageManager();\n        List<SuggestionObject> suggestionObjects = getSuggestions();\n        if (suggestionObjects != null) {\n            for (SuggestionObject suggestionObject : suggestionObjects) {\n                List<App> apps = appDb.getAllApplications(suggestionObject.packageName);\n                for (App app : apps) {\n                    if (app.isInstalled) {\n                        suggestionObject.addUser(app.userId);\n                    }\n                }\n            }\n        }\n        // Update application data\n        mInstalled = false;\n        mUsers = null;\n        mSystemApp = null;\n        mFrozen = null;\n        List<App> apps = appDb.getAllApplications(packageName);\n        for (App app : apps) {\n            if (!app.isInstalled) {\n                continue;\n            }\n            mInstalled = true;\n            addUser(app.userId);\n            mSystemApp = app.isSystemApp();\n            mFrozen = !app.isEnabled;\n            mLabel = app.packageLabel;\n            if (getIcon() == null) {\n                try {\n                    ApplicationInfo ai = PackageManagerCompat.getApplicationInfo(packageName,\n                            MATCH_UNINSTALLED_PACKAGES | MATCH_STATIC_SHARED_AND_SDK_LIBRARIES, app.userId);\n                    mInstalled = (ai.flags & ApplicationInfo.FLAG_INSTALLED) != 0;\n                    mSystemApp = ApplicationInfoCompat.isSystemApp(ai);\n                    mLabel = ai.loadLabel(pm);\n                    mIcon = ai.loadIcon(pm);\n                    mFrozen = FreezeUtils.isFrozen(ai);\n                } catch (RemoteException | PackageManager.NameNotFoundException ignore) {\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/debloat/DebloaterActivity.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.debloat;\n\nimport android.content.BroadcastReceiver;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.IntentFilter;\nimport android.os.Bundle;\nimport android.view.Menu;\nimport android.view.MenuItem;\nimport android.view.View;\n\nimport androidx.activity.OnBackPressedCallback;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.appcompat.app.ActionBar;\nimport androidx.core.content.ContextCompat;\nimport androidx.lifecycle.ViewModelProvider;\n\nimport com.google.android.material.checkbox.MaterialCheckBox;\nimport com.google.android.material.dialog.MaterialAlertDialogBuilder;\nimport com.google.android.material.progressindicator.LinearProgressIndicator;\n\nimport io.github.muntashirakon.AppManager.BaseActivity;\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.apk.behavior.FreezeUnfreeze;\nimport io.github.muntashirakon.AppManager.batchops.BatchOpsManager;\nimport io.github.muntashirakon.AppManager.batchops.BatchOpsService;\nimport io.github.muntashirakon.AppManager.batchops.BatchQueueItem;\nimport io.github.muntashirakon.AppManager.batchops.struct.BatchFreezeOptions;\nimport io.github.muntashirakon.AppManager.batchops.struct.IBatchOpOptions;\nimport io.github.muntashirakon.AppManager.misc.AdvancedSearchView;\nimport io.github.muntashirakon.AppManager.profiles.AddToProfileDialogFragment;\nimport io.github.muntashirakon.AppManager.settings.Prefs;\nimport io.github.muntashirakon.AppManager.utils.StoragePermission;\nimport io.github.muntashirakon.AppManager.utils.UIUtils;\nimport io.github.muntashirakon.multiselection.MultiSelectionActionsView;\nimport io.github.muntashirakon.widget.MultiSelectionView;\nimport io.github.muntashirakon.widget.RecyclerView;\n\npublic class DebloaterActivity extends BaseActivity implements MultiSelectionView.OnSelectionChangeListener,\n        MultiSelectionActionsView.OnItemSelectedListener, AdvancedSearchView.OnQueryTextListener,\n        MultiSelectionView.OnSelectionModeChangeListener {\n    DebloaterViewModel viewModel;\n\n    private LinearProgressIndicator mProgressIndicator;\n    private MultiSelectionView mMultiSelectionView;\n    private DebloaterRecyclerViewAdapter mAdapter;\n\n    private final StoragePermission mStoragePermission = StoragePermission.init(this);\n    private final BroadcastReceiver mBatchOpsBroadCastReceiver = new BroadcastReceiver() {\n        @Override\n        public void onReceive(Context context, Intent intent) {\n            if (mProgressIndicator != null) {\n                mProgressIndicator.hide();\n            }\n        }\n    };\n    private final OnBackPressedCallback mOnBackPressedCallback = new OnBackPressedCallback(false) {\n        @Override\n        public void handleOnBackPressed() {\n            if (mAdapter != null && mMultiSelectionView != null && mAdapter.isInSelectionMode()) {\n                mMultiSelectionView.cancel();\n                return;\n            }\n            setEnabled(false);\n            getOnBackPressedDispatcher().onBackPressed();\n        }\n    };\n\n    @Override\n    protected void onAuthenticated(@Nullable Bundle savedInstanceState) {\n        setContentView(R.layout.activity_debloater);\n        setSupportActionBar(findViewById(R.id.toolbar));\n        getOnBackPressedDispatcher().addCallback(this, mOnBackPressedCallback);\n        ActionBar actionBar = getSupportActionBar();\n        if (actionBar != null) {\n            actionBar.setDisplayHomeAsUpEnabled(true);\n            actionBar.setDisplayShowCustomEnabled(true);\n            UIUtils.setupAdvancedSearchView(actionBar, this);\n        }\n        viewModel = new ViewModelProvider(this).get(DebloaterViewModel.class);\n\n        mProgressIndicator = findViewById(R.id.progress_linear);\n        mProgressIndicator.show();\n\n        RecyclerView recyclerView = findViewById(R.id.recycler_view);\n        recyclerView.setLayoutManager(UIUtils.getGridLayoutAt450Dp(this));\n        mAdapter = new DebloaterRecyclerViewAdapter(this);\n        recyclerView.setAdapter(mAdapter);\n        mMultiSelectionView = findViewById(R.id.selection_view);\n        mMultiSelectionView.setAdapter(mAdapter);\n        mMultiSelectionView.hide();\n        mMultiSelectionView.setOnItemSelectedListener(this);\n        mMultiSelectionView.setOnSelectionModeChangeListener(this);\n        mMultiSelectionView.setOnSelectionChangeListener(this);\n\n        viewModel.getDebloatObjectListLiveData().observe(this, debloatObjects -> {\n            mProgressIndicator.hide();\n            mAdapter.setAdapterList(debloatObjects);\n        });\n        viewModel.loadPackages();\n    }\n\n    @Override\n    protected void onResume() {\n        super.onResume();\n        ContextCompat.registerReceiver(this, mBatchOpsBroadCastReceiver,\n                new IntentFilter(BatchOpsService.ACTION_BATCH_OPS_COMPLETED), ContextCompat.RECEIVER_NOT_EXPORTED);\n    }\n\n    @Override\n    protected void onPause() {\n        super.onPause();\n        unregisterReceiver(mBatchOpsBroadCastReceiver);\n    }\n\n    @Override\n    public boolean onCreateOptionsMenu(Menu menu) {\n        getMenuInflater().inflate(R.menu.activity_debloater_actions, menu);\n        return super.onCreateOptionsMenu(menu);\n    }\n\n    @Override\n    public boolean onOptionsItemSelected(@NonNull MenuItem item) {\n        int id = item.getItemId();\n        if (id == android.R.id.home) {\n            finish();\n            return true;\n        } else if (id == R.id.action_list_options) {\n            DebloaterListOptions dialog = new DebloaterListOptions();\n            dialog.show(getSupportFragmentManager(), DebloaterListOptions.TAG);\n            return true;\n        }\n        return super.onOptionsItemSelected(item);\n    }\n\n    @Override\n    public void onSelectionModeEnabled() {\n        mOnBackPressedCallback.setEnabled(true);\n    }\n\n    @Override\n    public void onSelectionModeDisabled() {\n        mOnBackPressedCallback.setEnabled(false);\n    }\n\n    @Override\n    public boolean onSelectionChange(int selectionCount) {\n        // TODO: 7/8/22\n        return false;\n    }\n\n    @Override\n    public boolean onNavigationItemSelected(@NonNull MenuItem item) {\n        int id = item.getItemId();\n        if (id == R.id.action_uninstall) {\n            handleBatchOpWithWarning(BatchOpsManager.OP_UNINSTALL);\n        } else if (id == R.id.action_put_back) {\n            // TODO: 8/8/22\n        } else if (id == R.id.action_freeze_unfreeze) {\n            showFreezeUnfreezeDialog(Prefs.Blocking.getDefaultFreezingMethod());\n        } else if (id == R.id.action_save_apk) {\n            mStoragePermission.request(granted -> {\n                if (granted) handleBatchOp(BatchOpsManager.OP_BACKUP_APK);\n            });\n        } else if (id == R.id.action_block_unblock_trackers) {\n            new MaterialAlertDialogBuilder(this)\n                    .setTitle(R.string.block_unblock_trackers)\n                    .setMessage(R.string.choose_what_to_do)\n                    .setPositiveButton(R.string.block, (dialog, which) ->\n                            handleBatchOp(BatchOpsManager.OP_BLOCK_TRACKERS))\n                    .setNegativeButton(R.string.cancel, null)\n                    .setNeutralButton(R.string.unblock, (dialog, which) ->\n                            handleBatchOp(BatchOpsManager.OP_UNBLOCK_TRACKERS))\n                    .show();\n        } else if (id == R.id.action_add_to_profile) {\n            AddToProfileDialogFragment dialog = AddToProfileDialogFragment.getInstance(viewModel.getSelectedPackages()\n                    .keySet().toArray(new String[0]));\n            dialog.show(getSupportFragmentManager(), AddToProfileDialogFragment.TAG);\n        } else return false;\n        return true;\n    }\n\n    @Override\n    public boolean onQueryTextChange(String newText, int type) {\n        viewModel.setQuery(newText, type);\n        return true;\n    }\n\n    @Override\n    public boolean onQueryTextSubmit(String query, int type) {\n        return false;\n    }\n\n    private void showFreezeUnfreezeDialog(int freezeType) {\n        View view = View.inflate(this, R.layout.item_checkbox, null);\n        MaterialCheckBox checkBox = view.findViewById(R.id.checkbox);\n        checkBox.setText(R.string.freeze_prefer_per_app_option);\n        FreezeUnfreeze.getFreezeDialog(this, freezeType)\n                .setIcon(R.drawable.ic_snowflake)\n                .setTitle(R.string.freeze_unfreeze)\n                .setView(view)\n                .setPositiveButton(R.string.freeze, (dialog, which, selectedItem) -> {\n                    if (selectedItem == null) {\n                        return;\n                    }\n                    BatchFreezeOptions options = new BatchFreezeOptions(selectedItem, checkBox.isChecked());\n                    handleBatchOp(BatchOpsManager.OP_ADVANCED_FREEZE, options);\n                })\n                .setNegativeButton(R.string.cancel, null)\n                .setNeutralButton(R.string.unfreeze, (dialog, which, selectedItem) ->\n                        handleBatchOp(BatchOpsManager.OP_UNFREEZE))\n                .show();\n    }\n\n    private void handleBatchOpWithWarning(@BatchOpsManager.OpType int op) {\n        new MaterialAlertDialogBuilder(this)\n                .setTitle(R.string.are_you_sure)\n                .setMessage(R.string.this_action_cannot_be_undone)\n                .setPositiveButton(R.string.yes, (dialog, which) -> handleBatchOp(op))\n                .setNegativeButton(R.string.no, null)\n                .show();\n    }\n\n    private void handleBatchOp(@BatchOpsManager.OpType int op) {\n        handleBatchOp(op, null);\n    }\n\n    private void handleBatchOp(@BatchOpsManager.OpType int op, @Nullable IBatchOpOptions options) {\n        if (viewModel == null) return;\n        if (mProgressIndicator != null) {\n            mProgressIndicator.show();\n        }\n        BatchOpsManager.Result input = new BatchOpsManager.Result(viewModel.getSelectedPackagesWithUsers());\n        BatchQueueItem item = BatchQueueItem.getBatchOpQueue(op, input.getFailedPackages(), input.getAssociatedUsers(), options);\n        ContextCompat.startForegroundService(this, BatchOpsService.getServiceIntent(this, item));\n        mMultiSelectionView.cancel();\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/debloat/DebloaterListOptions.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.debloat;\n\nimport android.content.Context;\nimport android.os.Bundle;\nimport android.util.SparseIntArray;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\n\nimport androidx.annotation.IntDef;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.StringRes;\n\nimport com.google.android.material.chip.Chip;\n\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\n\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.dialog.CapsuleBottomSheetDialogFragment;\n\npublic class DebloaterListOptions extends CapsuleBottomSheetDialogFragment {\n    public static final String TAG = DebloaterListOptions.class.getSimpleName();\n\n    @IntDef(flag = true, value = {\n            FILTER_NO_FILTER,\n\n            FILTER_LIST_AOSP,\n            FILTER_LIST_OEM,\n            FILTER_LIST_CARRIER,\n            FILTER_LIST_GOOGLE,\n            FILTER_LIST_MISC,\n\n            FILTER_REMOVAL_SAFE,\n            FILTER_REMOVAL_REPLACE,\n            FILTER_REMOVAL_CAUTION,\n            FILTER_REMOVAL_UNSAFE,\n\n            FILTER_USER_APPS,\n            FILTER_SYSTEM_APPS,\n            FILTER_INSTALLED_APPS,\n            FILTER_UNINSTALLED_APPS,\n            FILTER_FROZEN_APPS,\n            FILTER_UNFROZEN_APPS,\n    })\n    @Retention(RetentionPolicy.SOURCE)\n    public @interface Filter {\n    }\n\n    public static final int FILTER_NO_FILTER = 0;\n\n    public static final int FILTER_LIST_AOSP = 1;\n    public static final int FILTER_LIST_OEM = 1 << 1;\n    public static final int FILTER_LIST_CARRIER = 1 << 2;\n    public static final int FILTER_LIST_GOOGLE = 1 << 3;\n    public static final int FILTER_LIST_MISC = 1 << 4;\n\n    public static final int FILTER_REMOVAL_SAFE = 1 << 6;\n    public static final int FILTER_REMOVAL_REPLACE = 1 << 7;\n    public static final int FILTER_REMOVAL_CAUTION = 1 << 8;\n     public static final int FILTER_REMOVAL_UNSAFE = 1 << 9;\n\n    public static final int FILTER_USER_APPS = 1 << 10;\n    public static final int FILTER_SYSTEM_APPS = 1 << 11;\n    public static final int FILTER_INSTALLED_APPS = 1 << 12;\n    public static final int FILTER_UNINSTALLED_APPS = 1 << 13;\n    public static final int FILTER_FROZEN_APPS = 1 << 14;\n    public static final int FILTER_UNFROZEN_APPS = 1 << 15;\n\n    private static final SparseIntArray LIST_FILTER_MAP = new SparseIntArray() {{\n        put(FILTER_LIST_AOSP, R.string.debloat_list_aosp);\n        put(FILTER_LIST_OEM, R.string.debloat_list_oem);\n        put(FILTER_LIST_CARRIER, R.string.debloat_list_carrier);\n        put(FILTER_LIST_GOOGLE, R.string.debloat_list_google);\n        put(FILTER_LIST_MISC, R.string.debloat_list_misc);\n    }};\n\n    private static final SparseIntArray REMOVAL_FILTER_MAP = new SparseIntArray() {{\n        put(FILTER_REMOVAL_SAFE, R.string.debloat_removal_safe);\n        put(FILTER_REMOVAL_REPLACE, R.string.debloat_removal_replace);\n        put(FILTER_REMOVAL_CAUTION, R.string.debloat_removal_caution);\n        put(FILTER_REMOVAL_UNSAFE, R.string.debloat_removal_unsafe);\n    }};\n\n    private static final SparseIntArray NORMAL_FILTER_MAP = new SparseIntArray() {{\n        put(FILTER_USER_APPS, R.string.filter_user_apps);\n        put(FILTER_SYSTEM_APPS, R.string.filter_system_apps);\n        put(FILTER_INSTALLED_APPS, R.string.installed_apps);\n        put(FILTER_UNINSTALLED_APPS, R.string.uninstalled_apps);\n        put(FILTER_FROZEN_APPS, R.string.filter_frozen_apps);\n        put(FILTER_UNFROZEN_APPS, R.string.filter_unfrozen_apps);\n    }};\n\n    @Filter\n    public static int getDefaultFilterFlags() {\n       return FILTER_LIST_AOSP | FILTER_LIST_OEM | FILTER_LIST_CARRIER | FILTER_LIST_GOOGLE\n               | FILTER_LIST_MISC | FILTER_REMOVAL_SAFE | FILTER_REMOVAL_REPLACE\n               | FILTER_REMOVAL_CAUTION | FILTER_INSTALLED_APPS | FILTER_SYSTEM_APPS;\n    }\n\n    private DebloaterViewModel mModel;\n\n    @NonNull\n    @Override\n    public View initRootView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {\n        return inflater.inflate(R.layout.dialog_debloater_list_options, container, false);\n    }\n\n    @Override\n    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {\n        super.onViewCreated(view, savedInstanceState);\n        DebloaterActivity activity = (DebloaterActivity) requireActivity();\n        mModel = activity.viewModel;\n        ViewGroup listTypes = view.findViewById(R.id.list_types);\n        for (int i = 0; i < LIST_FILTER_MAP.size(); ++i) {\n            listTypes.addView(getFilterChip(listTypes.getContext(), LIST_FILTER_MAP.keyAt(i), LIST_FILTER_MAP.valueAt(i)));\n        }\n        ViewGroup removalTypes = view.findViewById(R.id.removal_types);\n        for (int i = 0; i < REMOVAL_FILTER_MAP.size(); ++i) {\n            removalTypes.addView(getFilterChip(removalTypes.getContext(), REMOVAL_FILTER_MAP.keyAt(i), REMOVAL_FILTER_MAP.valueAt(i)));\n        }\n        ViewGroup filterView = view.findViewById(R.id.filter_options);\n        for (int i = 0; i < NORMAL_FILTER_MAP.size(); ++i) {\n            filterView.addView(getFilterChip(filterView.getContext(), NORMAL_FILTER_MAP.keyAt(i), NORMAL_FILTER_MAP.valueAt(i)));\n        }\n    }\n\n    public Chip getFilterChip(@NonNull Context context, @Filter int flag, @StringRes int strRes) {\n        Chip chip = new Chip(context);\n        chip.setFocusable(true);\n        chip.setCloseIconVisible(false);\n        chip.setText(strRes);\n        chip.setChecked(mModel.hasFilterFlag(flag));\n        chip.setOnCheckedChangeListener((buttonView, isChecked) -> {\n            if (isChecked) mModel.addFilterFlag(flag);\n            else mModel.removeFilterFlag(flag);\n        });\n        return chip;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/debloat/DebloaterRecyclerViewAdapter.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.debloat;\n\nimport static io.github.muntashirakon.AppManager.utils.UIUtils.getColoredText;\n\nimport android.content.Context;\nimport android.graphics.drawable.Drawable;\nimport android.text.SpannableStringBuilder;\nimport android.text.TextUtils;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\n\nimport androidx.annotation.ColorInt;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.StringRes;\nimport androidx.appcompat.widget.AppCompatImageView;\nimport androidx.fragment.app.FragmentActivity;\n\nimport com.google.android.material.card.MaterialCardView;\nimport com.google.android.material.color.MaterialColors;\nimport com.google.android.material.textview.MaterialTextView;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.utils.appearance.ColorCodes;\nimport io.github.muntashirakon.util.AccessibilityUtils;\nimport io.github.muntashirakon.util.AdapterUtils;\nimport io.github.muntashirakon.widget.MultiSelectionView;\n\npublic class DebloaterRecyclerViewAdapter extends MultiSelectionView.Adapter<DebloaterRecyclerViewAdapter.ViewHolder> {\n    private final List<DebloatObject> mAdapterList = new ArrayList<>();\n\n    private final FragmentActivity mActivity;\n    @ColorInt\n    private final int mRemovalSafeColor;\n    @ColorInt\n    private final int mRemovalReplaceColor;\n    @ColorInt\n    private final int mRemovalUnsafeColor;\n    @ColorInt\n    private final int mRemovalCautionColor;\n    @ColorInt\n    private final int mColorSurface;\n    private final Object mLock = new Object();\n    @NonNull\n    private final DebloaterViewModel mViewModel;\n    @NonNull\n    private final Drawable mDefaultIcon;\n\n    public DebloaterRecyclerViewAdapter(DebloaterActivity activity) {\n        mActivity = activity;\n        mRemovalSafeColor = ColorCodes.getRemovalSafeIndicatorColor(activity);\n        mRemovalReplaceColor = ColorCodes.getRemovalReplaceIndicatorColor(activity);\n        mRemovalCautionColor = ColorCodes.getRemovalCautionIndicatorColor(activity);\n        mRemovalUnsafeColor = ColorCodes.getRemovalUnsafeIndicatorColor(activity);\n        mColorSurface = MaterialColors.getColor(activity, com.google.android.material.R.attr.colorSurface,\n                DebloaterRecyclerViewAdapter.class.getCanonicalName());\n        mViewModel = activity.viewModel;\n        mDefaultIcon = activity.getPackageManager().getDefaultActivityIcon();\n    }\n\n    public void setAdapterList(List<DebloatObject> adapterList) {\n        synchronized (mLock) {\n            AdapterUtils.notifyDataSetChanged(this, mAdapterList, adapterList);\n        }\n    }\n\n    @NonNull\n    @Override\n    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {\n        View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_debloater, parent, false);\n        return new ViewHolder(v);\n    }\n\n    @Override\n    public void onBindViewHolder(@NonNull ViewHolder holder, int position) {\n        DebloatObject debloatObject;\n        synchronized (mLock) {\n            debloatObject = mAdapterList.get(position);\n        }\n        Context context = holder.itemView.getContext();\n        Drawable icon = debloatObject.getIcon() != null ? debloatObject.getIcon() : mDefaultIcon;\n        String warning = debloatObject.getWarning();\n        SpannableStringBuilder sb = new SpannableStringBuilder();\n        int removalColor;\n        @StringRes\n        int removalRes;\n        switch (debloatObject.getRemoval()) {\n            case DebloatObject.REMOVAL_SAFE:\n                removalColor = mRemovalSafeColor;\n                removalRes = R.string.debloat_removal_safe_short_description;\n                break;\n            default:\n            case DebloatObject.REMOVAL_CAUTION:\n                removalColor = mRemovalCautionColor;\n                removalRes = R.string.debloat_removal_caution_short_description;\n                break;\n            case DebloatObject.REMOVAL_REPLACE:\n                removalColor = mRemovalReplaceColor;\n                removalRes = R.string.debloat_removal_replace_short_description;\n                break;\n            case DebloatObject.REMOVAL_UNSAFE:\n                removalColor = mRemovalUnsafeColor;\n                removalRes = R.string.debloat_removal_unsafe;\n                break;\n        }\n        sb.append(getColoredText(context.getString(removalRes), removalColor));\n        if (!TextUtils.isEmpty(warning)) {\n            sb.append(\" — \").append(warning);\n        }\n        CharSequence label = debloatObject.getLabelOrPackageName();\n        holder.iconView.setImageDrawable(icon);\n        holder.listTypeView.setText(debloatObject.type);\n        holder.packageNameView.setText(debloatObject.packageName);\n        holder.descriptionView.setText(sb);\n        holder.itemView.setStrokeColor(removalColor);\n        holder.labelView.setText(label);\n        holder.itemView.setOnLongClickListener(v -> {\n            toggleSelection(position);\n            AccessibilityUtils.requestAccessibilityFocus(holder.itemView);\n            return true;\n        });\n        holder.iconView.setOnClickListener(v -> {\n            toggleSelection(position);\n            AccessibilityUtils.requestAccessibilityFocus(holder.itemView);\n        });\n        holder.itemView.setOnClickListener(v -> {\n            if (isInSelectionMode()) {\n                toggleSelection(position);\n                AccessibilityUtils.requestAccessibilityFocus(holder.itemView);\n            } else {\n                BloatwareDetailsDialog dialog = BloatwareDetailsDialog.getInstance(debloatObject.packageName);\n                dialog.show(mActivity.getSupportFragmentManager(), BloatwareDetailsDialog.TAG);\n            }\n        });\n        super.onBindViewHolder(holder, position);\n    }\n\n    @Override\n    public long getItemId(int position) {\n        synchronized (mLock) {\n            return mAdapterList.get(position).getId();\n        }\n    }\n\n    @Override\n    public int getItemCount() {\n        synchronized (mLock) {\n            return mAdapterList.size();\n        }\n    }\n\n    @Override\n    protected boolean select(int position) {\n        synchronized (mLock) {\n            mViewModel.select(mAdapterList.get(position));\n            return true;\n        }\n    }\n\n    @Override\n    protected boolean deselect(int position) {\n        synchronized (mLock) {\n            mViewModel.deselect(mAdapterList.get(position));\n            return true;\n        }\n    }\n\n    @Override\n    protected void cancelSelection() {\n        super.cancelSelection();\n        mViewModel.deselectAll();\n    }\n\n    @Override\n    protected boolean isSelected(int position) {\n        synchronized (mLock) {\n            return mViewModel.isSelected(mAdapterList.get(position));\n        }\n    }\n\n    @Override\n    protected int getSelectedItemCount() {\n        return mViewModel.getSelectedItemCount();\n    }\n\n    @Override\n    protected int getTotalItemCount() {\n        return mViewModel.getTotalItemCount();\n    }\n\n    public static class ViewHolder extends MultiSelectionView.ViewHolder {\n        public final MaterialCardView itemView;\n        public final AppCompatImageView iconView;\n        public final MaterialTextView listTypeView;\n        public final MaterialTextView labelView;\n        public final MaterialTextView packageNameView;\n        public final MaterialTextView descriptionView;\n\n        public ViewHolder(@NonNull View itemView) {\n            super(itemView);\n            this.itemView = (MaterialCardView) itemView;\n            iconView = itemView.findViewById(R.id.icon);\n            listTypeView = itemView.findViewById(R.id.list_type);\n            labelView = itemView.findViewById(R.id.label);\n            packageNameView = itemView.findViewById(R.id.package_name);\n            descriptionView = itemView.findViewById(R.id.apk_description);\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/debloat/DebloaterViewModel.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.debloat;\n\nimport android.app.Application;\nimport android.os.UserHandleHidden;\nimport android.text.TextUtils;\n\nimport androidx.annotation.AnyThread;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.WorkerThread;\nimport androidx.lifecycle.AndroidViewModel;\nimport androidx.lifecycle.LiveData;\nimport androidx.lifecycle.MutableLiveData;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Map;\nimport java.util.concurrent.ExecutorService;\n\nimport io.github.muntashirakon.AppManager.StaticDataset;\nimport io.github.muntashirakon.AppManager.misc.AdvancedSearchView;\nimport io.github.muntashirakon.AppManager.types.UserPackagePair;\nimport io.github.muntashirakon.AppManager.users.Users;\nimport io.github.muntashirakon.AppManager.utils.AppPref;\nimport io.github.muntashirakon.AppManager.utils.ArrayUtils;\nimport io.github.muntashirakon.AppManager.utils.MultithreadedExecutor;\n\npublic class DebloaterViewModel extends AndroidViewModel {\n    @DebloaterListOptions.Filter\n    private int mFilterFlags;\n    private String mQueryString = null;\n    @AdvancedSearchView.SearchType\n    private int mQueryType;\n    @NonNull\n    private final List<DebloatObject> mDebloatObjects = new ArrayList<>();\n\n    private final Map<String, int[]> mSelectedPackages = new HashMap<>();\n    private final MutableLiveData<List<DebloatObject>> mDebloatObjectListLiveData = new MutableLiveData<>();\n    private final ExecutorService mExecutor = MultithreadedExecutor.getNewInstance();\n\n    public DebloaterViewModel(@NonNull Application application) {\n        super(application);\n        mFilterFlags = AppPref.getInt(AppPref.PrefKey.PREF_DEBLOATER_FILTER_FLAGS_INT);\n    }\n\n    public boolean hasFilterFlag(@DebloaterListOptions.Filter int flag) {\n        return (mFilterFlags & flag) != 0;\n    }\n\n    public void addFilterFlag(@DebloaterListOptions.Filter int flag) {\n        mFilterFlags |= flag;\n        AppPref.set(AppPref.PrefKey.PREF_DEBLOATER_FILTER_FLAGS_INT, mFilterFlags);\n        loadPackages();\n    }\n\n    public void removeFilterFlag(@DebloaterListOptions.Filter int flag) {\n        mFilterFlags &= ~flag;\n        AppPref.set(AppPref.PrefKey.PREF_DEBLOATER_FILTER_FLAGS_INT, mFilterFlags);\n        loadPackages();\n    }\n\n    public void setQuery(String queryString, @AdvancedSearchView.SearchType int searchType) {\n        mQueryString = queryString;\n        mQueryType = searchType;\n        loadPackages();\n    }\n\n    public LiveData<List<DebloatObject>> getDebloatObjectListLiveData() {\n        return mDebloatObjectListLiveData;\n    }\n\n    public int getTotalItemCount() {\n        return mDebloatObjects.size();\n    }\n\n    public int getSelectedItemCount() {\n        return mSelectedPackages.size();\n    }\n\n    public void select(@NonNull DebloatObject debloatObject) {\n        mSelectedPackages.put(debloatObject.packageName, debloatObject.getUsers());\n    }\n\n    public void deselect(@NonNull DebloatObject debloatObject) {\n        mSelectedPackages.remove(debloatObject.packageName);\n    }\n\n    public void deselectAll() {\n        mSelectedPackages.clear();\n    }\n\n    public boolean isSelected(@NonNull DebloatObject debloatObject) {\n        return mSelectedPackages.containsKey(debloatObject.packageName);\n    }\n\n    public Map<String, int[]> getSelectedPackages() {\n        return mSelectedPackages;\n    }\n\n    @NonNull\n    public ArrayList<UserPackagePair> getSelectedPackagesWithUsers() {\n        ArrayList<UserPackagePair> userPackagePairs = new ArrayList<>();\n        int myUserId = UserHandleHidden.myUserId();\n        int[] userIds = Users.getUsersIds();\n        for (String packageName : mSelectedPackages.keySet()) {\n            int[] userHandles = mSelectedPackages.get(packageName);\n            if (userHandles == null || userHandles.length == 0) {\n                // Assign current user in it\n                userPackagePairs.add(new UserPackagePair(packageName, myUserId));\n            } else {\n                for (int userHandle : userHandles) {\n                    if (!ArrayUtils.contains(userIds, userHandle)) continue;\n                    userPackagePairs.add(new UserPackagePair(packageName, userHandle));\n                }\n            }\n        }\n        return userPackagePairs;\n    }\n\n    @AnyThread\n    public void loadPackages() {\n        mExecutor.submit(() -> {\n            loadDebloatObjects();\n            List<DebloatObject> debloatObjects = new ArrayList<>();\n            if (mFilterFlags != DebloaterListOptions.FILTER_NO_FILTER) {\n                for (DebloatObject debloatObject : mDebloatObjects) {\n                    // List\n                    if ((mFilterFlags & DebloaterListOptions.FILTER_LIST_AOSP) == 0 && debloatObject.type.equals(\"aosp\")) {\n                        continue;\n                    }\n                    if ((mFilterFlags & DebloaterListOptions.FILTER_LIST_CARRIER) == 0 && debloatObject.type.equals(\"carrier\")) {\n                        continue;\n                    }\n                    if ((mFilterFlags & DebloaterListOptions.FILTER_LIST_GOOGLE) == 0 && debloatObject.type.equals(\"google\")) {\n                        continue;\n                    }\n                    if ((mFilterFlags & DebloaterListOptions.FILTER_LIST_MISC) == 0 && debloatObject.type.equals(\"misc\")) {\n                        continue;\n                    }\n                    if ((mFilterFlags & DebloaterListOptions.FILTER_LIST_OEM) == 0 && debloatObject.type.equals(\"oem\")) {\n                        continue;\n                    }\n                    // Removal\n                    int removalType = debloatObject.getRemoval();\n                    if ((mFilterFlags & DebloaterListOptions.FILTER_REMOVAL_SAFE) == 0 && removalType == DebloatObject.REMOVAL_SAFE) {\n                        continue;\n                    }\n                    if ((mFilterFlags & DebloaterListOptions.FILTER_REMOVAL_REPLACE) == 0 && removalType == DebloatObject.REMOVAL_REPLACE) {\n                        continue;\n                    }\n                    if ((mFilterFlags & DebloaterListOptions.FILTER_REMOVAL_CAUTION) == 0 && removalType == DebloatObject.REMOVAL_CAUTION) {\n                        continue;\n                    }\n                    if ((mFilterFlags & DebloaterListOptions.FILTER_REMOVAL_UNSAFE) == 0 && removalType == DebloatObject.REMOVAL_UNSAFE) {\n                        continue;\n                    }\n                    // Filter others\n                    if ((mFilterFlags & DebloaterListOptions.FILTER_INSTALLED_APPS) != 0 && !debloatObject.isInstalled()) {\n                        continue;\n                    }\n                    if ((mFilterFlags & DebloaterListOptions.FILTER_UNINSTALLED_APPS) != 0 && debloatObject.isInstalled()) {\n                        continue;\n                    }\n                    if ((mFilterFlags & DebloaterListOptions.FILTER_USER_APPS) != 0 && !debloatObject.isUserApp()) {\n                        continue;\n                    }\n                    if ((mFilterFlags & DebloaterListOptions.FILTER_SYSTEM_APPS) != 0 && !debloatObject.isSystemApp()) {\n                        continue;\n                    }\n                    if ((mFilterFlags & DebloaterListOptions.FILTER_FROZEN_APPS) != 0 && !debloatObject.isFrozen()) {\n                        continue;\n                    }\n                    if ((mFilterFlags & DebloaterListOptions.FILTER_UNFROZEN_APPS) != 0 && debloatObject.isFrozen()) {\n                        continue;\n                    }\n                    debloatObjects.add(debloatObject);\n                }\n            }\n            if (TextUtils.isEmpty(mQueryString)) {\n                mDebloatObjectListLiveData.postValue(debloatObjects);\n                return;\n            }\n            // Apply searching\n            List<DebloatObject> newList = AdvancedSearchView.matches(mQueryString, debloatObjects,\n                    (AdvancedSearchView.ChoicesGenerator<DebloatObject>) item -> {\n                        CharSequence label = item.getLabel();\n                        if (label != null) {\n                            return Arrays.asList(item.packageName, label.toString().toLowerCase(Locale.getDefault()));\n                        } else {\n                            return Collections.singletonList(item.packageName);\n                        }\n                    },\n                    mQueryType);\n            mDebloatObjectListLiveData.postValue(newList);\n        });\n    }\n\n    @WorkerThread\n    private void loadDebloatObjects() {\n        if (!mDebloatObjects.isEmpty()) {\n            return;\n        }\n        mDebloatObjects.addAll(StaticDataset.getDebloatObjectsWithInstalledInfo(getApplication()));\n        Collections.sort(mDebloatObjects, (o1, o2) -> CharSequence.compare(o1.getLabelOrPackageName(), o2.getLabelOrPackageName()));\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/debloat/SuggestionObject.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.debloat;\n\nimport android.content.Intent;\nimport android.net.Uri;\n\nimport androidx.annotation.Nullable;\n\nimport com.google.gson.annotations.SerializedName;\n\nimport io.github.muntashirakon.AppManager.utils.ArrayUtils;\n\npublic class SuggestionObject {\n    @SerializedName(\"_id\")\n    public String suggestionId;\n    @SerializedName(\"id\")\n    public String packageName;\n\n    @SerializedName(\"label\")\n    private String mLabel;\n    @SerializedName(\"reason\")\n    @Nullable\n    private String mReason;\n    @SerializedName(\"source\")\n    private String mSource;\n    @SerializedName(\"repo\")\n    private String mRepo;\n\n    private int[] mUsers;\n\n    public String getLabel() {\n        return mLabel;\n    }\n\n    public String getRepo() {\n        return mRepo;\n    }\n\n    @Nullable\n    public String getReason() {\n        return mReason;\n    }\n\n    public boolean isInFDroidMarket() {\n        return mSource != null && mSource.contains(\"f\");\n    }\n\n    public Intent getMarketLink() {\n        // Not supported by most app stores\n        // return new Intent(Intent.ACTION_VIEW, Uri.parse(\"market://search?q=pname:\" + packageName + \" \" + mLabel));\n        Uri uri;\n        if (isInFDroidMarket()) {\n            uri = Uri.parse(\"https://f-droid.org/packages/\" + packageName);\n        } else uri = Uri.parse(\"https://play.google.com/store/apps/details?id=\" + packageName);\n        return new Intent(Intent.ACTION_VIEW, uri);\n    }\n\n    public int[] getUsers() {\n        return mUsers;\n    }\n\n    public void addUser(int userId) {\n        if (mUsers == null) {\n            mUsers = new int[]{userId};\n        } else if (!ArrayUtils.contains(mUsers, userId)) {\n            mUsers = ArrayUtils.appendInt(mUsers, userId);\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/details/ActivityLauncherShortcutActivity.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.details;\n\nimport android.Manifest;\nimport android.annotation.UserIdInt;\nimport android.content.ComponentName;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.pm.ApplicationInfo;\nimport android.os.Bundle;\nimport android.os.UserHandleHidden;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.core.content.ContextCompat;\n\nimport com.google.android.material.dialog.MaterialAlertDialogBuilder;\n\nimport java.util.Objects;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.TimeUnit;\n\nimport io.github.muntashirakon.AppManager.BaseActivity;\nimport io.github.muntashirakon.AppManager.BuildConfig;\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.apk.behavior.FreezeUnfreeze;\nimport io.github.muntashirakon.AppManager.apk.behavior.FreezeUnfreezeService;\nimport io.github.muntashirakon.AppManager.compat.ActivityManagerCompat;\nimport io.github.muntashirakon.AppManager.compat.ManifestCompat;\nimport io.github.muntashirakon.AppManager.compat.PackageManagerCompat;\nimport io.github.muntashirakon.AppManager.self.SelfPermissions;\nimport io.github.muntashirakon.AppManager.utils.ContextUtils;\nimport io.github.muntashirakon.AppManager.utils.ExUtils;\nimport io.github.muntashirakon.AppManager.utils.FreezeUtils;\nimport io.github.muntashirakon.AppManager.utils.ThreadUtils;\nimport io.github.muntashirakon.AppManager.utils.UIUtils;\n\npublic class ActivityLauncherShortcutActivity extends BaseActivity {\n    private static final String EXTRA_PKG = BuildConfig.APPLICATION_ID + \".intent.EXTRA.shortcut.pkg\";\n    private static final String EXTRA_CLS = BuildConfig.APPLICATION_ID + \".intent.EXTRA.shortcut.cls\";\n    private static final String EXTRA_AST = BuildConfig.APPLICATION_ID + \".intent.EXTRA.shortcut.ast\";\n    private static final String EXTRA_USR = BuildConfig.APPLICATION_ID + \".intent.EXTRA.shortcut.usr\";\n\n    @NonNull\n    public static Intent getShortcutIntent(@NonNull Context context, @NonNull String pkg, @NonNull String clazz,\n                                           @UserIdInt int userId, boolean launchViaAssist) {\n        return new Intent()\n                .setClass(context, ActivityLauncherShortcutActivity.class)\n                .putExtra(EXTRA_PKG, pkg)\n                .putExtra(EXTRA_CLS, clazz)\n                .putExtra(EXTRA_USR, userId)\n                .putExtra(EXTRA_AST, launchViaAssist)\n                .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)\n                .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);\n    }\n\n    private Intent mIntent;\n    private String mPackageName;\n    private ComponentName mComponentName;\n    private int mUserId;\n    private boolean mCanLaunchViaAssist;\n    private boolean mIsLaunchViaAssist;\n\n    @Override\n    protected void onAuthenticated(@Nullable Bundle savedInstanceState) {\n        Intent intent = getIntent();\n        if (!Intent.ACTION_CREATE_SHORTCUT.equals(intent.getAction()) || !intent.hasExtra(EXTRA_PKG) || !intent.hasExtra(EXTRA_CLS)) {\n            // Invalid intent\n            finishActivity(0);\n            return;\n        }\n        unfreezeAndLaunchActivity(intent);\n    }\n\n    @Override\n    protected void onNewIntent(@NonNull Intent intent) {\n        super.onNewIntent(intent);\n        unfreezeAndLaunchActivity(intent);\n    }\n\n    @Override\n    public boolean getTransparentBackground() {\n        return true;\n    }\n\n    private void unfreezeAndLaunchActivity(@NonNull Intent intent) {\n        mIntent = new Intent(intent);\n        mPackageName = Objects.requireNonNull(mIntent.getStringExtra(EXTRA_PKG));\n        String className = Objects.requireNonNull(mIntent.getStringExtra(EXTRA_CLS));\n        mComponentName = new ComponentName(mPackageName, className);\n        mIntent.setAction(null);\n        mIntent.setComponent(mComponentName);\n        mUserId = mIntent.getIntExtra(EXTRA_USR, UserHandleHidden.myUserId());\n        mCanLaunchViaAssist = SelfPermissions.checkSelfPermission(Manifest.permission.WRITE_SECURE_SETTINGS);\n        mIsLaunchViaAssist = mIntent.getBooleanExtra(EXTRA_AST, false) && mCanLaunchViaAssist;\n        mIntent.removeExtra(EXTRA_PKG);\n        mIntent.removeExtra(EXTRA_CLS);\n        mIntent.removeExtra(EXTRA_AST);\n        mIntent.removeExtra(EXTRA_USR);\n        // Check for frozen\n        ApplicationInfo info = ExUtils.exceptionAsNull(() -> PackageManagerCompat.getApplicationInfo(mPackageName, 0, mUserId));\n        if (info != null && FreezeUtils.isFrozen(info)) {\n            // Ask to unfreeze\n            new MaterialAlertDialogBuilder(this)\n                    .setTitle(R.string.title_shortcut_for_frozen_app)\n                    .setMessage(R.string.message_shortcut_for_frozen_app)\n                    .setCancelable(false)\n                    .setPositiveButton(R.string.yes, (dialog, which) -> ThreadUtils.postOnBackgroundThread(() -> {\n                        try {\n                            FreezeUtils.unfreeze(mPackageName, mUserId);\n                            ThreadUtils.postOnMainThread(() -> {\n                                Intent service = new Intent(FreezeUnfreeze.getShortcutIntent(this, mPackageName, mUserId, 0))\n                                        .setClassName(this, FreezeUnfreezeService.class.getName());\n                                ContextCompat.startForegroundService(this, service);\n                                launchActivity();\n                            });\n                        } catch (Throwable e) {\n                            ThreadUtils.postOnMainThread(() -> {\n                                UIUtils.displayShortToast(R.string.failed);\n                                finishActivity(0);\n                            });\n                        }\n                    }))\n                    .setNegativeButton(R.string.cancel, (dialog, which) -> finishActivity(0))\n                    .show();\n        } else {\n            // Try launching it anyway (we don't care about failure)\n            launchActivity();\n        }\n    }\n\n    private void launchActivity() {\n        if (mIsLaunchViaAssist && !SelfPermissions.checkSelfOrRemotePermission(ManifestCompat.permission.START_ANY_ACTIVITY)) {\n            launchActivityViaAssist();\n        } else {\n            try {\n                finishActivity(0);\n                ActivityManagerCompat.startActivity(mIntent, mUserId);\n            } catch (Throwable e) {\n                e.printStackTrace();\n                UIUtils.displayLongToast(\"Error: \" + e.getMessage());\n                // Try assist instead\n                if (mCanLaunchViaAssist) {\n                    launchActivityViaAssist();\n                } else finishActivity(0);\n            }\n        }\n    }\n\n    private void launchActivityViaAssist() {\n        boolean launched = ActivityManagerCompat.startActivityViaAssist(ContextUtils.getContext(), mComponentName, () -> {\n            CountDownLatch waitForInteraction = new CountDownLatch(1);\n            ThreadUtils.postOnMainThread(() -> new MaterialAlertDialogBuilder(this)\n                    .setTitle(R.string.launch_activity_dialog_title)\n                    .setMessage(R.string.launch_activity_dialog_message)\n                    .setCancelable(false)\n                    .setOnDismissListener((dialog) -> {\n                        waitForInteraction.countDown();\n                        finishActivity(0);\n                    })\n                    .setNegativeButton(R.string.close, null)\n                    .show());\n            try {\n                waitForInteraction.await(10, TimeUnit.MINUTES);\n            } catch (InterruptedException ignore) {\n            }\n        });\n        if (launched) {\n            finishActivity(0);\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/details/AppDetailsActivity.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.details;\n\nimport android.annotation.UserIdInt;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.pm.ApplicationInfo;\nimport android.content.res.TypedArray;\nimport android.net.Uri;\nimport android.os.Bundle;\nimport android.os.Parcel;\nimport android.os.Parcelable;\nimport android.os.UserHandleHidden;\nimport android.view.MenuItem;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.appcompat.app.ActionBar;\nimport androidx.appcompat.app.AlertDialog;\nimport androidx.core.os.BundleCompat;\nimport androidx.core.os.ParcelCompat;\nimport androidx.fragment.app.Fragment;\nimport androidx.fragment.app.FragmentActivity;\nimport androidx.lifecycle.ViewModelProvider;\nimport androidx.viewpager2.adapter.FragmentStateAdapter;\nimport androidx.viewpager2.widget.ViewPager2;\n\nimport com.google.android.material.tabs.TabLayout;\nimport com.google.android.material.tabs.TabLayoutMediator;\n\nimport java.util.Objects;\n\nimport io.github.muntashirakon.AppManager.BaseActivity;\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.apk.ApkSource;\nimport io.github.muntashirakon.AppManager.details.info.AppInfoFragment;\nimport io.github.muntashirakon.AppManager.intercept.IntentCompat;\nimport io.github.muntashirakon.AppManager.logs.Log;\nimport io.github.muntashirakon.AppManager.main.MainActivity;\nimport io.github.muntashirakon.AppManager.misc.AdvancedSearchView;\nimport io.github.muntashirakon.AppManager.self.SelfUriManager;\nimport io.github.muntashirakon.AppManager.types.UserPackagePair;\nimport io.github.muntashirakon.AppManager.utils.UIUtils;\nimport io.github.muntashirakon.io.Path;\nimport io.github.muntashirakon.io.Paths;\nimport io.github.muntashirakon.util.UiUtils;\n\npublic class AppDetailsActivity extends BaseActivity {\n    public static final String ALIAS_APP_INFO = \"io.github.muntashirakon.AppManager.details.AppInfoActivity\";\n\n    private static final String EXTRA_PACKAGE_NAME = \"android.intent.extra.PACKAGE_NAME\"; // Intent.EXTRA_PACKAGE_NAME\n    private static final String EXTRA_APK_SOURCE = \"src\";\n    private static final String EXTRA_USER_HANDLE = \"user\";\n    private static final String EXTRA_BACK_TO_MAIN = \"main\";\n\n    @NonNull\n    public static Intent getIntent(@NonNull Context context, @NonNull String packageName, @UserIdInt int userId) {\n        Intent intent = new Intent(context, AppDetailsActivity.class);\n        intent.putExtra(EXTRA_PACKAGE_NAME, packageName);\n        intent.putExtra(EXTRA_USER_HANDLE, userId);\n        return intent;\n    }\n\n    @NonNull\n    public static Intent getIntent(@NonNull Context context, @NonNull String packageName, @UserIdInt int userId,\n                                   boolean backToMainPage) {\n        Intent intent = new Intent(context, AppDetailsActivity.class);\n        intent.putExtra(EXTRA_PACKAGE_NAME, packageName);\n        intent.putExtra(EXTRA_USER_HANDLE, userId);\n        intent.putExtra(EXTRA_BACK_TO_MAIN, backToMainPage);\n        return intent;\n    }\n\n    @NonNull\n    public static Intent getIntent(@NonNull Context context, @NonNull ApkSource apkSource, boolean backToMainPage) {\n        Intent intent = new Intent(context, AppDetailsActivity.class);\n        IntentCompat.putWrappedParcelableExtra(intent, EXTRA_APK_SOURCE, apkSource);\n        intent.putExtra(EXTRA_BACK_TO_MAIN, backToMainPage);\n        return intent;\n    }\n\n    @NonNull\n    public static Intent getIntent(@NonNull Context context, @NonNull Path apkPath, boolean backToMainPage) {\n        return getIntent(context, apkPath.getUri(), apkPath.getType(), backToMainPage);\n    }\n\n    @NonNull\n    public static Intent getIntent(@NonNull Context context, @NonNull Uri apkPath, @Nullable String mimeType, boolean backToMainPage) {\n        Intent intent = new Intent(context, AppDetailsActivity.class);\n        if (mimeType != null) {\n            intent.setDataAndType(apkPath, mimeType);\n        } else {\n            intent.setData(apkPath);\n        }\n        intent.putExtra(EXTRA_BACK_TO_MAIN, backToMainPage);\n        return intent;\n    }\n\n    public AppDetailsViewModel model;\n    public AdvancedSearchView searchView;\n\n    private ViewPager2 mViewPager;\n    private TypedArray mTabTitleIds;\n    private Fragment[] mTabFragments;\n\n    private boolean mBackToMainPage;\n    @Nullable\n    private String mPackageName;\n    @Nullable\n    private ApkSource mApkSource;\n    @Nullable\n    private String mApkType;\n    @UserIdInt\n    private int mUserId;\n\n    @Override\n    protected void onAuthenticated(@Nullable Bundle savedInstanceState) {\n        setContentView(R.layout.activity_app_details);\n        setSupportActionBar(findViewById(R.id.toolbar));\n        setTitle(\"…\");\n        model = new ViewModelProvider(this).get(AppDetailsViewModel.class);\n        // Restore instance state\n        SavedState ss = savedInstanceState != null ? BundleCompat.getParcelable(savedInstanceState, \"ss\", SavedState.class) : null;\n        if (ss != null) {\n            mBackToMainPage = ss.mBackToMainPage;\n            mPackageName = ss.mPackageName;\n            mApkSource = ss.mApkSource;\n            mApkType = ss.mApkType;\n            mUserId = ss.mUserId;\n        } else {\n            Intent intent = getIntent();\n            mBackToMainPage = intent.getBooleanExtra(EXTRA_BACK_TO_MAIN, mBackToMainPage);\n            UserPackagePair pair = SelfUriManager.getUserPackagePairFromUri(intent.getData());\n            if (pair != null) {\n                mPackageName = pair.getPackageName();\n                mApkSource = null;\n                mUserId = pair.getUserId();\n            } else {\n                mPackageName = getPackageNameFromExtras(intent);\n                mApkSource = getApkSource(intent);\n                mUserId = intent.getIntExtra(EXTRA_USER_HANDLE, UserHandleHidden.myUserId());\n            }\n            mApkType = intent.getType();\n        }\n        model.setUserId(mUserId);\n        // Initialize tabs\n        mTabTitleIds = getResources().obtainTypedArray(R.array.TAB_TITLES);\n        mTabFragments = new Fragment[mTabTitleIds.length()];\n        if (mPackageName == null && mApkSource == null) {\n            UIUtils.displayLongToast(R.string.empty_package_name);\n            finish();\n            return;\n        }\n        // Set search\n        ActionBar actionBar = getSupportActionBar();\n        if (actionBar != null) {\n            actionBar.setDisplayShowCustomEnabled(true);\n            searchView = UIUtils.setupAdvancedSearchView(actionBar, null);\n        }\n        mViewPager = findViewById(R.id.pager);\n        TabLayout tabLayout = findViewById(R.id.tab_layout);\n        UiUtils.applyWindowInsetsAsPadding(tabLayout, false, true);\n        final AlertDialog progressDialog = UIUtils.getProgressDialog(this, getText(R.string.loading), true);\n        if (mPackageName == null) {\n            // Display progress dialog only for external apk files\n            progressDialog.show();\n        }\n        // Set tabs\n        mViewPager.setOffscreenPageLimit(4);\n        mViewPager.setAdapter(new AppDetailsFragmentPagerAdapter(this));\n        new TabLayoutMediator(tabLayout, mViewPager, (tab, position) -> tab.setText(mTabTitleIds.getString(position)))\n                .attach();\n        // Load package info\n        (mPackageName != null\n                ? model.setPackage(mPackageName)\n                : model.setPackage(Objects.requireNonNull(mApkSource))\n        ).observe(this, packageInfo -> {\n            progressDialog.dismiss();\n            if (packageInfo == null) {\n                UIUtils.displayShortToast(R.string.failed_to_fetch_package_info);\n                if (!isDestroyed()) {\n                    finish();\n                }\n                return;\n            }\n            // Set title\n            ApplicationInfo applicationInfo = packageInfo.applicationInfo;\n            // Set title as the package label\n            setTitle(applicationInfo.loadLabel(getPackageManager()));\n        });\n        // Check for the existence of package\n        model.getIsPackageExistLiveData().observe(this, isPackageExist -> {\n            if (!isPackageExist) {\n                if (!model.isExternalApk()) {\n                    UIUtils.displayShortToast(R.string.app_not_installed);\n                }\n                finish();\n            }\n        });\n        // Set subtitle as the username if more than one user exists\n        model.getUserInfo().observe(this, userInfo -> getSupportActionBar()\n                .setSubtitle(getString(R.string.user_profile_with_id, userInfo.name, userInfo.id)));\n        // Check for package changes\n        model.isPackageChanged().observe(this, isPackageChanged -> {\n            if (isPackageChanged && model.isPackageExist()) {\n                loadTabs();\n            }\n        });\n    }\n\n    @Nullable\n    private String getPackageNameFromExtras(@NonNull Intent intent) {\n        String pkg = intent.getStringExtra(EXTRA_PACKAGE_NAME);\n        if (pkg == null) {\n            // Legacy argument, kept for compatibility\n            pkg = intent.getStringExtra(\"pkg\");\n        }\n        if (pkg != null) {\n            // Package name needs to be sanitized since it's also a file\n            return Paths.sanitizeFilename(pkg);\n        }\n        return null;\n    }\n\n    @Nullable\n    private ApkSource getApkSource(@NonNull Intent intent) {\n        Uri uri = intent.getData();\n        if (uri != null) {\n            return ApkSource.getApkSource(uri, intent.getType());\n        }\n        return IntentCompat.getUnwrappedParcelableExtra(intent, EXTRA_APK_SOURCE, ApkSource.class);\n    }\n\n    static class SavedState implements Parcelable {\n        private boolean mBackToMainPage;\n        @Nullable\n        private String mPackageName;\n        @Nullable\n        private ApkSource mApkSource;\n        @Nullable\n        private String mApkType;\n        private int mUserId;\n\n        protected SavedState() {\n        }\n\n        public SavedState(Parcel source) {\n            mBackToMainPage = ParcelCompat.readBoolean(source);\n            mPackageName = source.readString();\n            mApkSource = ParcelCompat.readParcelable(source, ApkSource.class.getClassLoader(), ApkSource.class);\n            mApkType = source.readString();\n            mUserId = source.readInt();\n        }\n\n        @Override\n        public int describeContents() {\n            return 0;\n        }\n\n        @Override\n        public void writeToParcel(Parcel dest, int flags) {\n            ParcelCompat.writeBoolean(dest, mBackToMainPage);\n            dest.writeString(mPackageName);\n            dest.writeParcelable(mApkSource, flags);\n            dest.writeString(mApkType);\n            dest.writeInt(mUserId);\n        }\n\n        public static final Creator<SavedState> CREATOR = new ClassLoaderCreator<SavedState>() {\n            @Override\n            public SavedState createFromParcel(Parcel in, ClassLoader loader) {\n                return new SavedState(in);\n            }\n\n            @Override\n            public SavedState createFromParcel(Parcel in) {\n                return new SavedState(in);\n            }\n\n            @Override\n            public SavedState[] newArray(int size) {\n                return new SavedState[size];\n            }\n        };\n    }\n\n    @Override\n    protected void onSaveInstanceState(@NonNull Bundle outState) {\n        if (mApkSource != null || mPackageName != null) {\n            SavedState ss = new SavedState();\n            ss.mBackToMainPage = mBackToMainPage;\n            ss.mPackageName = mPackageName;\n            ss.mApkSource = mApkSource;\n            ss.mApkType = mApkType;\n            ss.mUserId = mUserId;\n            outState.putParcelable(\"ss\", ss);\n        }\n        super.onSaveInstanceState(outState);\n    }\n\n    @Override\n    public boolean onOptionsItemSelected(@NonNull MenuItem item) {\n        final int id = item.getItemId();\n        if (id == android.R.id.home) {\n            if (mBackToMainPage) {\n                Intent intent = new Intent(this, MainActivity.class);\n                startActivity(intent);\n            }\n            finish();\n            return true;\n        }\n        return super.onOptionsItemSelected(item);\n    }\n\n    private void loadTabs() {\n        @AppDetailsFragment.Property int id = mViewPager.getCurrentItem();\n        Log.d(\"ADA - \" + mTabTitleIds.getText(id), \"isPackageChanged called\");\n        for (int i = 0; i < mTabTitleIds.length(); ++i) model.load(i);\n    }\n\n    // For tab layout\n    private class AppDetailsFragmentPagerAdapter extends FragmentStateAdapter {\n        AppDetailsFragmentPagerAdapter(@NonNull FragmentActivity fragmentActivity) {\n            super(fragmentActivity);\n        }\n\n        @NonNull\n        @Override\n        public Fragment createFragment(@AppDetailsFragment.Property int position) {\n            if (mTabFragments[position] != null) {\n                return mTabFragments[position];\n            }\n            switch (position) {\n                case AppDetailsFragment.APP_INFO:\n                    return mTabFragments[position] = new AppInfoFragment();\n                case AppDetailsFragment.ACTIVITIES:\n                case AppDetailsFragment.SERVICES:\n                case AppDetailsFragment.RECEIVERS:\n                case AppDetailsFragment.PROVIDERS: {\n                    AppDetailsComponentsFragment fragment = new AppDetailsComponentsFragment();\n                    Bundle args = new Bundle();\n                    args.putInt(AppDetailsFragment.ARG_TYPE, position);\n                    fragment.setArguments(args);\n                    return mTabFragments[position] = fragment;\n                }\n                case AppDetailsFragment.APP_OPS:\n                case AppDetailsFragment.PERMISSIONS:\n                case AppDetailsFragment.USES_PERMISSIONS: {\n                    AppDetailsPermissionsFragment fragment = new AppDetailsPermissionsFragment();\n                    Bundle args = new Bundle();\n                    args.putInt(AppDetailsFragment.ARG_TYPE, position);\n                    fragment.setArguments(args);\n                    return mTabFragments[position] = fragment;\n                }\n                case AppDetailsFragment.CONFIGURATIONS:\n                case AppDetailsFragment.FEATURES:\n                case AppDetailsFragment.SHARED_LIBRARIES:\n                case AppDetailsFragment.SIGNATURES: {\n                    AppDetailsOtherFragment fragment = new AppDetailsOtherFragment();\n                    Bundle args = new Bundle();\n                    args.putInt(AppDetailsFragment.ARG_TYPE, position);\n                    fragment.setArguments(args);\n                    return mTabFragments[position] = fragment;\n                }\n                case AppDetailsFragment.OVERLAYS:\n                    AppDetailsOverlaysFragment fragment = new AppDetailsOverlaysFragment();\n                    Bundle args = new Bundle();\n                    args.putInt(AppDetailsFragment.ARG_TYPE, position);\n                    fragment.setArguments(args);\n                    return mTabFragments[position] = fragment;\n            }\n            return mTabFragments[position];\n        }\n\n        @Override\n        public int getItemCount() {\n            return mTabTitleIds.length();\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/details/AppDetailsComponentsFragment.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.details;\n\nimport android.content.ComponentName;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.pm.ActivityInfo;\nimport android.content.pm.PathPermission;\nimport android.content.pm.ProviderInfo;\nimport android.content.pm.ServiceInfo;\nimport android.graphics.Color;\nimport android.os.Bundle;\nimport android.os.PatternMatcher;\nimport android.os.UserHandleHidden;\nimport android.view.LayoutInflater;\nimport android.view.Menu;\nimport android.view.MenuInflater;\nimport android.view.MenuItem;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.Button;\nimport android.widget.ImageView;\nimport android.widget.TextView;\n\nimport androidx.annotation.IntDef;\nimport androidx.annotation.MainThread;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.UiThread;\nimport androidx.appcompat.widget.PopupMenu;\n\nimport com.google.android.material.button.MaterialButton;\nimport com.google.android.material.card.MaterialCardView;\nimport com.google.android.material.chip.Chip;\nimport com.google.android.material.dialog.MaterialAlertDialogBuilder;\nimport com.google.android.material.materialswitch.MaterialSwitch;\n\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Objects;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.TimeUnit;\n\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.compat.ActivityManagerCompat;\nimport io.github.muntashirakon.AppManager.compat.ManifestCompat;\nimport io.github.muntashirakon.AppManager.details.struct.AppDetailsActivityItem;\nimport io.github.muntashirakon.AppManager.details.struct.AppDetailsComponentItem;\nimport io.github.muntashirakon.AppManager.details.struct.AppDetailsItem;\nimport io.github.muntashirakon.AppManager.details.struct.AppDetailsServiceItem;\nimport io.github.muntashirakon.AppManager.intercept.ActivityInterceptor;\nimport io.github.muntashirakon.AppManager.rules.RuleType;\nimport io.github.muntashirakon.AppManager.rules.compontents.ComponentUtils;\nimport io.github.muntashirakon.AppManager.rules.struct.ComponentRule;\nimport io.github.muntashirakon.AppManager.self.SelfPermissions;\nimport io.github.muntashirakon.AppManager.self.imagecache.ImageLoader;\nimport io.github.muntashirakon.AppManager.settings.FeatureController;\nimport io.github.muntashirakon.AppManager.settings.Prefs;\nimport io.github.muntashirakon.AppManager.shortcut.CreateShortcutDialogFragment;\nimport io.github.muntashirakon.AppManager.types.UserPackagePair;\nimport io.github.muntashirakon.AppManager.utils.ContextUtils;\nimport io.github.muntashirakon.AppManager.utils.ThreadUtils;\nimport io.github.muntashirakon.AppManager.utils.UIUtils;\nimport io.github.muntashirakon.AppManager.utils.Utils;\nimport io.github.muntashirakon.AppManager.utils.appearance.ColorCodes;\nimport io.github.muntashirakon.util.AdapterUtils;\nimport io.github.muntashirakon.view.ProgressIndicatorCompat;\nimport io.github.muntashirakon.widget.MaterialAlertView;\nimport io.github.muntashirakon.widget.RecyclerView;\n\npublic class AppDetailsComponentsFragment extends AppDetailsFragment {\n    @IntDef(value = {\n            ACTIVITIES,\n            SERVICES,\n            RECEIVERS,\n            PROVIDERS,\n    })\n    @Retention(RetentionPolicy.SOURCE)\n    public @interface ComponentProperty {\n    }\n\n    private String mPackageName;\n    private AppDetailsRecyclerAdapter mAdapter;\n    private MenuItem mBlockingToggler;\n    private boolean mIsExternalApk;\n    @ComponentProperty\n    private int mNeededProperty;\n    private int mSortOrder;\n    private String mSearchQuery;\n\n    @Override\n    public void onCreate(@Nullable Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        mNeededProperty = requireArguments().getInt(ARG_TYPE);\n    }\n\n    @Override\n    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {\n        super.onViewCreated(view, savedInstanceState);\n        emptyView.setText(getNotFoundString(mNeededProperty));\n        mAdapter = new AppDetailsRecyclerAdapter();\n        recyclerView.setAdapter(mAdapter);\n        alertView.setEndIconOnClickListener(v -> alertView.hide());\n        int helpStringRes = R.string.rules_not_applied;\n        alertView.setText(helpStringRes);\n        alertView.setVisibility(View.GONE);\n        if (viewModel == null) return;\n        mSortOrder = viewModel.getSortOrder(mNeededProperty);\n        mSearchQuery = viewModel.getSearchQuery();\n        mPackageName = viewModel.getPackageName();\n        viewModel.get(mNeededProperty).observe(getViewLifecycleOwner(), appDetailsItems -> {\n            if (appDetailsItems != null && mAdapter != null && viewModel.isPackageExist()) {\n                mPackageName = viewModel.getPackageName();\n                mIsExternalApk = viewModel.isExternalApk();\n                mAdapter.setDefaultList(appDetailsItems);\n            } else ProgressIndicatorCompat.setVisibility(progressIndicator, false);\n        });\n        viewModel.getRuleApplicationStatus().observe(getViewLifecycleOwner(), status -> {\n            alertView.setAlertType(MaterialAlertView.ALERT_TYPE_WARN);\n            if (status == AppDetailsViewModel.RULE_NOT_APPLIED) {\n                alertView.show();\n            } else alertView.hide();\n            updateBlockMenuItem(status);\n        });\n    }\n\n    @Override\n    public void onRefresh() {\n        refreshDetails();\n        swipeRefresh.setRefreshing(false);\n    }\n\n    @Override\n    public void onCreateMenu(@NonNull Menu menu, @NonNull MenuInflater menuInflater) {\n        if (viewModel != null && !viewModel.isExternalApk() && SelfPermissions.canModifyAppComponentStates(\n                viewModel.getUserId(), viewModel.getPackageName(), viewModel.isTestOnlyApp())) {\n            menuInflater.inflate(R.menu.fragment_app_details_components_actions, menu);\n            mBlockingToggler = menu.findItem(R.id.action_toggle_blocking);\n        } else menuInflater.inflate(R.menu.fragment_app_details_refresh_actions, menu);\n    }\n\n    @Override\n    public void onPrepareMenu(@NonNull Menu menu) {\n        if (viewModel == null || viewModel.isExternalApk()) {\n            return;\n        }\n        MenuItem sortItem = menu.findItem(AppDetailsFragment.sSortMenuItemIdsMap[viewModel.getSortOrder(mNeededProperty)]);\n        if (sortItem != null) {\n            sortItem.setChecked(true);\n        }\n        Integer status = viewModel.getRuleApplicationStatus().getValue();\n        if (status != null) {\n            updateBlockMenuItem(status);\n        }\n    }\n\n    @Override\n    public boolean onMenuItemSelected(@NonNull MenuItem item) {\n        int id = item.getItemId();\n        if (id == R.id.action_refresh_details) {\n            refreshDetails();\n        } else if (id == R.id.action_toggle_blocking) {  // Components\n            if (viewModel != null) {\n                viewModel.applyRules();\n            }\n        } else if (id == R.id.action_block_unblock_trackers) {  // Components\n            new MaterialAlertDialogBuilder(activity)\n                    .setTitle(R.string.block_unblock_trackers)\n                    .setMessage(R.string.choose_what_to_do)\n                    .setPositiveButton(R.string.block, (dialog, which) -> blockUnblockTrackers(true))\n                    .setNegativeButton(R.string.cancel, null)\n                    .setNeutralButton(R.string.unblock, (dialog, which) -> blockUnblockTrackers(false))\n                    .show();\n        } else if (id == R.id.action_sort_by_name) {  // All\n            setSortBy(AppDetailsFragment.SORT_BY_NAME);\n            item.setChecked(true);\n        } else if (id == R.id.action_sort_by_blocked_components) {  // Components\n            setSortBy(AppDetailsFragment.SORT_BY_BLOCKED);\n            item.setChecked(true);\n        } else if (id == R.id.action_sort_by_tracker_components) {  // Components\n            setSortBy(AppDetailsFragment.SORT_BY_TRACKERS);\n            item.setChecked(true);\n        } else return false;\n        return true;\n    }\n\n    @Override\n    public void onPause() {\n        super.onPause();\n        if (viewModel != null) {\n            mSortOrder = viewModel.getSortOrder(mNeededProperty);\n            mSearchQuery = viewModel.getSearchQuery();\n        }\n    }\n\n    @Override\n    public void onResume() {\n        super.onResume();\n        if (activity.searchView != null) {\n            if (!activity.searchView.isShown()) {\n                activity.searchView.setVisibility(View.VISIBLE);\n            }\n            activity.searchView.setOnQueryTextListener(this);\n            if (viewModel != null) {\n                int sortOrder = viewModel.getSortOrder(mNeededProperty);\n                String searchQuery = viewModel.getSearchQuery();\n                if (sortOrder != mSortOrder || !Objects.equals(searchQuery, mSearchQuery)) {\n                    viewModel.filterAndSortItems(mNeededProperty);\n                }\n            }\n        }\n    }\n\n    @Override\n    public boolean onQueryTextChange(String searchQuery, int type) {\n        if (viewModel != null) {\n            viewModel.setSearchQuery(searchQuery, type, mNeededProperty);\n        }\n        return true;\n    }\n\n    private void updateBlockMenuItem(int status) {\n        if (mBlockingToggler != null) {\n            switch (status) {\n                case AppDetailsViewModel.RULE_APPLIED:\n                    mBlockingToggler.setVisible(!Prefs.Blocking.globalBlockingEnabled());\n                    mBlockingToggler.setTitle(R.string.menu_remove_rules);\n                    break;\n                case AppDetailsViewModel.RULE_NOT_APPLIED:\n                    mBlockingToggler.setVisible(!Prefs.Blocking.globalBlockingEnabled());\n                    mBlockingToggler.setTitle(R.string.menu_apply_rules);\n                    break;\n                case AppDetailsViewModel.RULE_NO_RULE:\n                    mBlockingToggler.setVisible(false);\n            }\n        }\n    }\n\n    private void blockUnblockTrackers(boolean block) {\n        if (viewModel == null) return;\n        // TODO: 19/3/23 Do it via ViewModel\n        List<UserPackagePair> userPackagePairs = Collections.singletonList(new UserPackagePair(mPackageName,\n                UserHandleHidden.myUserId()));\n        ThreadUtils.postOnBackgroundThread(() -> {\n            List<UserPackagePair> failedPkgList = block ? ComponentUtils.blockTrackingComponents(userPackagePairs)\n                    : ComponentUtils.unblockTrackingComponents(userPackagePairs);\n            if (!failedPkgList.isEmpty()) {\n                ThreadUtils.postOnMainThread(() -> UIUtils.displayShortToast(block ? R.string.failed_to_block_trackers\n                        : R.string.failed_to_unblock_trackers));\n            } else {\n                ThreadUtils.postOnMainThread(() -> {\n                    UIUtils.displayShortToast(block ? R.string.trackers_blocked_successfully\n                            : R.string.trackers_unblocked_successfully);\n                    if (!isDetached()) {\n                        refreshDetails();\n                    }\n                });\n            }\n            viewModel.setRuleApplicationStatus();\n        });\n    }\n\n    private int getNotFoundString(@ComponentProperty int index) {\n        switch (index) {\n            case SERVICES:\n                return R.string.no_service;\n            case RECEIVERS:\n                return R.string.no_receivers;\n            case PROVIDERS:\n                return R.string.no_providers;\n            case ACTIVITIES:\n            default:\n                return R.string.no_activities;\n        }\n    }\n\n    private void setSortBy(@SortOrder int sortBy) {\n        ProgressIndicatorCompat.setVisibility(progressIndicator, true);\n        if (viewModel == null) return;\n        viewModel.setSortOrder(sortBy, mNeededProperty);\n    }\n\n    @MainThread\n    private void refreshDetails() {\n        if (viewModel == null || mIsExternalApk) return;\n        ProgressIndicatorCompat.setVisibility(progressIndicator, true);\n        viewModel.triggerPackageChange();\n    }\n\n    private void applyRules(@NonNull AppDetailsComponentItem componentItem, @NonNull RuleType type,\n                            @NonNull @ComponentRule.ComponentStatus String componentStatus) {\n        if (viewModel != null) {\n            viewModel.updateRulesForComponent(componentItem, type, componentStatus);\n        }\n    }\n\n    @UiThread\n    private class AppDetailsRecyclerAdapter extends RecyclerView.Adapter<AppDetailsRecyclerAdapter.ViewHolder> {\n        @NonNull\n        private final List<AppDetailsItem<?>> mAdapterList;\n        @ComponentProperty\n        private int mRequestedProperty;\n        @Nullable\n        private String mConstraint;\n        private int mUserId;\n        private boolean mCanModifyComponentStates;\n        private boolean mCanStartAnyActivity;\n        private final int mBlockedIndicatorColor;\n        private final int mBlockedExternallyIndicatorColor;\n        private final int mTrackerIndicatorColor;\n        private final int mRunningIndicatorColor;\n\n        AppDetailsRecyclerAdapter() {\n            mAdapterList = new ArrayList<>();\n            mBlockedIndicatorColor = ColorCodes.getComponentBlockedIndicatorColor(activity);\n            mBlockedExternallyIndicatorColor = ColorCodes.getComponentExternallyBlockedIndicatorColor(activity);\n            mTrackerIndicatorColor = ColorCodes.getComponentTrackerIndicatorColor(activity);\n            mRunningIndicatorColor = ColorCodes.getComponentRunningIndicatorColor(activity);\n        }\n\n        @UiThread\n        void setDefaultList(@NonNull List<AppDetailsItem<?>> list) {\n            ThreadUtils.postOnBackgroundThread(() -> {\n                mRequestedProperty = mNeededProperty;\n                mCanStartAnyActivity = SelfPermissions.checkSelfOrRemotePermission(ManifestCompat.permission.START_ANY_ACTIVITY);\n                if (viewModel != null) {\n                    mCanModifyComponentStates = !mIsExternalApk && SelfPermissions.canModifyAppComponentStates(mUserId, viewModel.getPackageName(), viewModel.isTestOnlyApp());\n                    mConstraint = viewModel.getSearchQuery();\n                    mUserId = viewModel.getUserId();\n                } else {\n                    mCanModifyComponentStates = false;\n                    mConstraint = null;\n                    mUserId = UserHandleHidden.myUserId();\n                }\n                ThreadUtils.postOnMainThread(() -> {\n                    if (isDetached()) return;\n                    ProgressIndicatorCompat.setVisibility(progressIndicator, false);\n                    synchronized (mAdapterList) {\n                        AdapterUtils.notifyDataSetChanged(this, mAdapterList, list);\n                    }\n                });\n            });\n        }\n\n        /**\n         * ViewHolder to use recycled views efficiently. Fields names are not expressive because we use\n         * the same holder for any kind of view, and view are not all sames.\n         */\n        class ViewHolder extends RecyclerView.ViewHolder {\n            MaterialCardView itemView;\n            TextView labelView;\n            TextView nameView;\n            TextView textView1;\n            TextView textView2;\n            TextView textView3;\n            TextView textView4;\n            TextView processNameView;\n            ImageView imageView;\n            Button shortcutBtn;\n            MaterialButton launchBtn;\n            MaterialSwitch toggleSwitch;\n            TextView blockingMethod;\n            Chip chipType;\n\n            public ViewHolder(@NonNull View itemView) {\n                super(itemView);\n                this.itemView = (MaterialCardView) itemView;\n                imageView = itemView.findViewById(R.id.icon);\n                imageView.setContentDescription(itemView.getContext().getString(R.string.icon));\n                labelView = itemView.findViewById(R.id.label);\n                nameView = itemView.findViewById(R.id.name);\n                processNameView = itemView.findViewById(R.id.process_name);\n\n                shortcutBtn = itemView.findViewById(R.id.edit_shortcut_btn);\n                toggleSwitch = itemView.findViewById(R.id.toggle_button);\n                blockingMethod = itemView.findViewById(R.id.method);\n                chipType = itemView.findViewById(R.id.type);\n                launchBtn = itemView.findViewById(R.id.launch);\n\n                if (mRequestedProperty == ACTIVITIES) {\n                    textView1 = itemView.findViewById(R.id.taskAffinity);\n                    textView2 = itemView.findViewById(R.id.launchMode);\n                    textView3 = itemView.findViewById(R.id.orientation);\n                    textView4 = itemView.findViewById(R.id.softInput);\n                } else if (mRequestedProperty == SERVICES) {\n                    textView1 = itemView.findViewById(R.id.orientation);\n                    itemView.findViewById(R.id.taskAffinity).setVisibility(View.GONE);\n                    itemView.findViewById(R.id.launchMode).setVisibility(View.GONE);\n                    itemView.findViewById(R.id.softInput).setVisibility(View.GONE);\n                    shortcutBtn.setVisibility(View.GONE);\n                } else if (mRequestedProperty == RECEIVERS) {\n                    textView1 = itemView.findViewById(R.id.taskAffinity);\n                    textView2 = itemView.findViewById(R.id.launchMode);\n                    textView3 = itemView.findViewById(R.id.orientation);\n                    textView4 = itemView.findViewById(R.id.softInput);\n                    launchBtn.setVisibility(View.GONE);\n                    shortcutBtn.setVisibility(View.GONE);\n                } else if (mRequestedProperty == PROVIDERS) {\n                    textView1 = itemView.findViewById(R.id.launchMode);\n                    textView2 = itemView.findViewById(R.id.orientation);\n                    textView3 = itemView.findViewById(R.id.softInput);\n                    textView4 = itemView.findViewById(R.id.taskAffinity);\n                    launchBtn.setVisibility(View.GONE);\n                    shortcutBtn.setVisibility(View.GONE);\n                }\n            }\n        }\n\n        @NonNull\n        @Override\n        public AppDetailsRecyclerAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {\n            View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_app_details_primary, parent, false);\n            return new AppDetailsRecyclerAdapter.ViewHolder(view);\n        }\n\n        @Override\n        public void onBindViewHolder(@NonNull AppDetailsRecyclerAdapter.ViewHolder holder, int position) {\n            Context context = holder.itemView.getContext();\n            if (mRequestedProperty == SERVICES) {\n                getServicesView(context, holder, position);\n            } else if (mRequestedProperty == RECEIVERS) {\n                getReceiverView(holder, position);\n            } else if (mRequestedProperty == PROVIDERS) {\n                getProviderView(holder, position);\n            } else if (mRequestedProperty == ACTIVITIES) {\n                getActivityView(holder, position);\n            }\n        }\n\n        @Override\n        public long getItemId(int position) {\n            return position;\n        }\n\n        @Override\n        public int getItemCount() {\n            synchronized (mAdapterList) {\n                return mAdapterList.size();\n            }\n        }\n\n        private void handleBlock(@NonNull ViewHolder holder, @NonNull AppDetailsComponentItem item, RuleType ruleType) {\n            ComponentRule rule = item.getRule();\n            boolean isBlocked = item.isBlocked();\n            if (isBlocked) {\n                Objects.requireNonNull(rule);\n                holder.blockingMethod.setVisibility(View.VISIBLE);\n                String method;\n                if (rule.isIfw()) {\n                    if (item.isDisabled()) {\n                        method = \"IFW+Dis\";\n                    } else method = \"IFW\";\n                } else {\n                    method = \"Dis\";\n                }\n                holder.blockingMethod.setText(method);\n            } else {\n                holder.blockingMethod.setVisibility(View.GONE);\n            }\n            holder.toggleSwitch.setChecked(!isBlocked);\n            holder.toggleSwitch.setVisibility(View.VISIBLE);\n            holder.toggleSwitch.setOnClickListener(buttonView -> {\n                String componentStatus = item.isBlocked()\n                        ? ComponentRule.COMPONENT_TO_BE_DEFAULTED\n                        : Prefs.Blocking.getDefaultBlockingMethod();\n                applyRules(item, ruleType, componentStatus);\n            });\n            holder.toggleSwitch.setOnLongClickListener(v -> {\n                PopupMenu popupMenu = new PopupMenu(activity, holder.toggleSwitch);\n                Menu menu = popupMenu.getMenu();\n                boolean canBlockByIfw = !(item.item instanceof ProviderInfo) && SelfPermissions.canBlockByIFW();\n                popupMenu.inflate(R.menu.fragment_app_details_components_selection_actions);\n                menu.findItem(R.id.action_ifw_and_disable).setEnabled(canBlockByIfw);\n                menu.findItem(R.id.action_ifw).setEnabled(canBlockByIfw);\n                popupMenu.setOnMenuItemClickListener(item1 -> {\n                    int id = item1.getItemId();\n                    String componentStatus;\n                    if (id == R.id.action_ifw_and_disable) {\n                        componentStatus = ComponentRule.COMPONENT_TO_BE_BLOCKED_IFW_DISABLE;\n                    } else if (id == R.id.action_ifw) {\n                        componentStatus = ComponentRule.COMPONENT_TO_BE_BLOCKED_IFW;\n                    } else if (id == R.id.action_disable) {\n                        componentStatus = ComponentRule.COMPONENT_TO_BE_DISABLED;\n                    } else if (id == R.id.action_enable) {\n                        componentStatus = ComponentRule.COMPONENT_TO_BE_ENABLED;\n                    } else if (id == R.id.action_default) {\n                        componentStatus = ComponentRule.COMPONENT_TO_BE_DEFAULTED;\n                    } else {\n                        componentStatus = ComponentRule.COMPONENT_TO_BE_BLOCKED_IFW_DISABLE;\n                    }\n                    applyRules(item, ruleType, componentStatus);\n                    return true;\n                });\n                popupMenu.show();\n                return true;\n            });\n        }\n\n        private void getActivityView(@NonNull ViewHolder holder, int index) {\n            final AppDetailsActivityItem componentItem;\n            synchronized (mAdapterList) {\n                componentItem = (AppDetailsActivityItem) mAdapterList.get(index);\n            }\n            final ActivityInfo activityInfo = (ActivityInfo) componentItem.item;\n            final String activityName = componentItem.name;\n            final boolean isDisabled = !mIsExternalApk && componentItem.isDisabled();\n            // Background color: regular < tracker < disabled < blocked\n            if (!mIsExternalApk && componentItem.isBlocked()) {\n                holder.itemView.setStrokeColor(mBlockedIndicatorColor);\n            } else if (isDisabled) {\n                holder.itemView.setStrokeColor(mBlockedExternallyIndicatorColor);\n            } else if (componentItem.isTracker()) {\n                holder.itemView.setStrokeColor(mTrackerIndicatorColor);\n            } else {\n                holder.itemView.setStrokeColor(Color.TRANSPARENT);\n            }\n            if (componentItem.isTracker()) {\n                holder.chipType.setText(R.string.tracker);\n                holder.chipType.setVisibility(View.VISIBLE);\n            } else holder.chipType.setVisibility(View.GONE);\n            // Name\n            if (mConstraint != null && activityName.toLowerCase(Locale.ROOT).contains(mConstraint)) {\n                // Highlight searched query\n                holder.nameView.setText(UIUtils.getHighlightedText(activityName, mConstraint, colorQueryStringHighlight));\n            } else {\n                holder.nameView.setText(activityName.startsWith(mPackageName) ?\n                        activityName.replaceFirst(mPackageName, \"\") : activityName);\n            }\n            // Icon\n            String tag = mPackageName + \"_\" + activityName;\n            holder.imageView.setTag(tag);\n            ImageLoader.getInstance().displayImage(tag, activityInfo, holder.imageView);\n            // TaskAffinity\n            holder.textView1.setText(String.format(Locale.ROOT, \"%s: %s\",\n                    getString(R.string.task_affinity), activityInfo.taskAffinity));\n            // LaunchMode\n            holder.textView2.setText(String.format(Locale.ROOT, \"%s: %s | %s: %s\",\n                    getString(R.string.launch_mode), getString(Utils.getLaunchMode(activityInfo.launchMode)),\n                    getString(R.string.orientation), getString(Utils.getOrientationString(activityInfo.screenOrientation))));\n            // Orientation\n            holder.textView3.setText(Utils.getActivitiesFlagsString(activityInfo.flags));\n            // SoftInput\n            holder.textView4.setText(String.format(Locale.ROOT, \"%s: %s | %s\",\n                    getString(R.string.soft_input), Utils.getSoftInputString(activityInfo.softInputMode),\n                    (activityInfo.permission == null ? getString(R.string.require_no_permission) : activityInfo.permission)));\n            // Label\n            holder.labelView.setText(componentItem.label);\n            // Process name\n            String processName = activityInfo.processName;\n            if (processName != null && !processName.equals(mPackageName)) {\n                holder.processNameView.setVisibility(View.VISIBLE);\n                holder.processNameView.setText(String.format(Locale.ROOT, \"%s: %s\",\n                        getString(R.string.process_name), processName));\n            } else holder.processNameView.setVisibility(View.GONE);\n            boolean isExported = activityInfo.exported;\n            if (componentItem.canLaunch || componentItem.canLaunchAssist) {\n                holder.launchBtn.setOnClickListener(v -> {\n                    ComponentName cn = new ComponentName(mPackageName, activityName);\n                    if (componentItem.canLaunch) {\n                        Intent intent = new Intent();\n                        intent.setComponent(cn);\n                        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);\n                        try {\n                            ActivityManagerCompat.startActivity(intent, mUserId);\n                        } catch (Throwable e) {\n                            UIUtils.displayLongToast(e.getLocalizedMessage());\n                        }\n                    } else if (componentItem.canLaunchAssist) {\n                        ActivityManagerCompat.startActivityViaAssist(ContextUtils.getContext(), cn, () -> {\n                            CountDownLatch waitForInteraction = new CountDownLatch(1);\n                            ThreadUtils.postOnMainThread(() -> new MaterialAlertDialogBuilder(holder.itemView.getContext())\n                                    .setTitle(R.string.launch_activity_dialog_title)\n                                    .setMessage(R.string.launch_activity_dialog_message)\n                                    .setCancelable(false)\n                                    .setOnDismissListener((dialog) -> waitForInteraction.countDown())\n                                    .setNegativeButton(R.string.close, null)\n                                    .show());\n                            try {\n                                waitForInteraction.await(10, TimeUnit.MINUTES);\n                            } catch (InterruptedException ignore) {\n                            }\n                        });\n                    }\n                });\n                if (FeatureController.isInterceptorEnabled()) {\n                    holder.launchBtn.setOnLongClickListener(v -> {\n                        boolean needRoot = mCanStartAnyActivity && (!isExported || !SelfPermissions.checkSelfOrRemotePermission(activityInfo.permission));\n                        Intent intent = new Intent(activity, ActivityInterceptor.class);\n                        intent.putExtra(ActivityInterceptor.EXTRA_PACKAGE_NAME, mPackageName);\n                        intent.putExtra(ActivityInterceptor.EXTRA_CLASS_NAME, activityName);\n                        intent.putExtra(ActivityInterceptor.EXTRA_USER_HANDLE, mUserId);\n                        intent.putExtra(ActivityInterceptor.EXTRA_ROOT, needRoot);\n                        startActivity(intent);\n                        return true;\n                    });\n                }\n                holder.shortcutBtn.setOnClickListener(v -> {\n                    PackageItemShortcutInfo<ActivityInfo> shortcutInfo = new PackageItemShortcutInfo<>(activityInfo, ActivityInfo.class, mUserId, componentItem.canLaunchAssist);\n                    shortcutInfo.setName(componentItem.label);\n                    shortcutInfo.setIcon(UIUtils.getBitmapFromDrawable(activityInfo.loadIcon(packageManager)));\n                    CreateShortcutDialogFragment dialog = CreateShortcutDialogFragment.getInstance(shortcutInfo);\n                    dialog.show(getParentFragmentManager(), CreateShortcutDialogFragment.TAG);\n                });\n                holder.shortcutBtn.setVisibility(View.VISIBLE);\n                holder.launchBtn.setVisibility(View.VISIBLE);\n            } else {\n                holder.shortcutBtn.setVisibility(View.GONE);\n                holder.launchBtn.setVisibility(View.GONE);\n            }\n            // Blocking\n            if (mCanModifyComponentStates) {\n                handleBlock(holder, componentItem, RuleType.ACTIVITY);\n            } else {\n                holder.toggleSwitch.setVisibility(View.GONE);\n                holder.blockingMethod.setVisibility(View.GONE);\n            }\n        }\n\n        private void getServicesView(@NonNull Context context, @NonNull ViewHolder holder, int index) {\n            final AppDetailsServiceItem serviceItem;\n            synchronized (mAdapterList) {\n                serviceItem = (AppDetailsServiceItem) mAdapterList.get(index);\n            }\n            final ServiceInfo serviceInfo = (ServiceInfo) serviceItem.item;\n            final boolean isDisabled = !mIsExternalApk && serviceItem.isDisabled();\n            // Background color: regular < tracker < disabled < blocked < running\n            if (serviceItem.isRunning()) {\n                holder.itemView.setStrokeColor(mRunningIndicatorColor);\n            } else if (!mIsExternalApk && serviceItem.isBlocked()) {\n                holder.itemView.setStrokeColor(mBlockedIndicatorColor);\n            } else if (isDisabled) {\n                holder.itemView.setStrokeColor(mBlockedExternallyIndicatorColor);\n            } else if (serviceItem.isTracker()) {\n                holder.itemView.setStrokeColor(mTrackerIndicatorColor);\n            } else {\n                holder.itemView.setStrokeColor(Color.TRANSPARENT);\n            }\n            if (serviceItem.isTracker()) {\n                holder.chipType.setText(R.string.tracker);\n                holder.chipType.setVisibility(View.VISIBLE);\n            } else holder.chipType.setVisibility(View.GONE);\n            // Label\n            holder.labelView.setText(serviceItem.label);\n            // Name\n            if (mConstraint != null && serviceInfo.name.toLowerCase(Locale.ROOT).contains(mConstraint)) {\n                // Highlight searched query\n                holder.nameView.setText(UIUtils.getHighlightedText(serviceInfo.name, mConstraint, colorQueryStringHighlight));\n            } else {\n                holder.nameView.setText(serviceInfo.name.startsWith(mPackageName) ?\n                        serviceInfo.name.replaceFirst(mPackageName, \"\") : serviceInfo.name);\n            }\n            // Icon\n            String tag = mPackageName + \"_\" + serviceInfo.name;\n            holder.imageView.setTag(tag);\n            ImageLoader.getInstance().displayImage(tag, serviceInfo, holder.imageView);\n            // Flags and Permission\n            StringBuilder flagsAndPermission = new StringBuilder(Utils.getServiceFlagsString(serviceInfo.flags));\n            if (flagsAndPermission.length() != 0) {\n                flagsAndPermission.append(\"\\n\");\n            }\n            flagsAndPermission.append(serviceInfo.permission != null ? serviceInfo.permission : getString(R.string.require_no_permission));\n            holder.textView1.setText(flagsAndPermission);\n            // Process name\n            String processName = serviceInfo.processName;\n            if (processName != null && !processName.equals(mPackageName)) {\n                holder.processNameView.setVisibility(View.VISIBLE);\n                holder.processNameView.setText(String.format(Locale.ROOT, \"%s: %s\",\n                        getString(R.string.process_name), processName));\n            } else holder.processNameView.setVisibility(View.GONE);\n            if (serviceItem.canLaunch) {\n                holder.launchBtn.setOnClickListener(v -> {\n                    Intent intent = new Intent();\n                    intent.setClassName(mPackageName, serviceInfo.name);\n                    try {\n                        ActivityManagerCompat.startService(intent, mUserId, true);\n                    } catch (Throwable th) {\n                        th.printStackTrace();\n                        UIUtils.displayShortToast(th.toString());\n                    }\n                });\n                holder.launchBtn.setVisibility(View.VISIBLE);\n            } else {\n                holder.launchBtn.setVisibility(View.GONE);\n            }\n            // Blocking\n            if (mCanModifyComponentStates) {\n                handleBlock(holder, serviceItem, RuleType.SERVICE);\n            } else {\n                holder.toggleSwitch.setVisibility(View.GONE);\n                holder.blockingMethod.setVisibility(View.GONE);\n            }\n        }\n\n        private void getReceiverView(@NonNull ViewHolder holder, int index) {\n            final AppDetailsComponentItem componentItem;\n            synchronized (mAdapterList) {\n                componentItem = (AppDetailsComponentItem) mAdapterList.get(index);\n            }\n            final ActivityInfo activityInfo = (ActivityInfo) componentItem.item;\n            // Background color: regular < tracker < disabled < blocked\n            if (!mIsExternalApk && componentItem.isBlocked()) {\n                holder.itemView.setStrokeColor(mBlockedIndicatorColor);\n            } else if (!mIsExternalApk && componentItem.isDisabled()) {\n                holder.itemView.setStrokeColor(mBlockedExternallyIndicatorColor);\n            } else if (componentItem.isTracker()) {\n                holder.itemView.setStrokeColor(mTrackerIndicatorColor);\n            } else {\n                holder.itemView.setStrokeColor(Color.TRANSPARENT);\n            }\n            if (componentItem.isTracker()) {\n                holder.chipType.setText(R.string.tracker);\n                holder.chipType.setVisibility(View.VISIBLE);\n            } else holder.chipType.setVisibility(View.GONE);\n            // Label\n            holder.labelView.setText(componentItem.label);\n            // Name\n            if (mConstraint != null && activityInfo.name.toLowerCase(Locale.ROOT).contains(mConstraint)) {\n                // Highlight searched query\n                holder.nameView.setText(UIUtils.getHighlightedText(activityInfo.name, mConstraint, colorQueryStringHighlight));\n            } else {\n                holder.nameView.setText(activityInfo.name.startsWith(mPackageName) ?\n                        activityInfo.name.replaceFirst(mPackageName, \"\")\n                        : activityInfo.name);\n            }\n            // Icon\n            String tag = mPackageName + \"_\" + activityInfo.name;\n            holder.imageView.setTag(tag);\n            ImageLoader.getInstance().displayImage(tag, activityInfo, holder.imageView);\n            // TaskAffinity\n            holder.textView1.setText(String.format(Locale.ROOT, \"%s: %s\",\n                    getString(R.string.task_affinity), activityInfo.taskAffinity));\n            // LaunchMode\n            holder.textView2.setText(String.format(Locale.ROOT, \"%s: %s | %s: %s\",\n                    getString(R.string.launch_mode), getString(Utils.getLaunchMode(activityInfo.launchMode)),\n                    getString(R.string.orientation), getString(Utils.getOrientationString(activityInfo.screenOrientation))));\n            // Orientation\n            holder.textView3.setText(activityInfo.permission == null ? getString(R.string.require_no_permission) : activityInfo.permission);\n            // SoftInput\n            holder.textView4.setText(String.format(Locale.ROOT, \"%s: %s\",\n                    getString(R.string.soft_input), Utils.getSoftInputString(activityInfo.softInputMode)));\n            // Process name\n            String processName = activityInfo.processName;\n            if (processName != null && !processName.equals(mPackageName)) {\n                holder.processNameView.setVisibility(View.VISIBLE);\n                holder.processNameView.setText(String.format(Locale.ROOT, \"%s: %s\",\n                        getString(R.string.process_name), processName));\n            } else holder.processNameView.setVisibility(View.GONE);\n            // Blocking\n            if (mCanModifyComponentStates) {\n                handleBlock(holder, componentItem, RuleType.RECEIVER);\n            } else {\n                holder.toggleSwitch.setVisibility(View.GONE);\n                holder.blockingMethod.setVisibility(View.GONE);\n            }\n        }\n\n        private void getProviderView(@NonNull ViewHolder holder, int index) {\n            final AppDetailsComponentItem componentItem;\n            synchronized (mAdapterList) {\n                componentItem = (AppDetailsComponentItem) mAdapterList.get(index);\n            }\n            final ProviderInfo providerInfo = (ProviderInfo) componentItem.item;\n            final String providerName = providerInfo.name;\n            // Background color: regular < tracker < disabled < blocked\n            if (!mIsExternalApk && componentItem.isBlocked()) {\n                holder.itemView.setStrokeColor(mBlockedIndicatorColor);\n            } else if (!mIsExternalApk && componentItem.isDisabled()) {\n                holder.itemView.setStrokeColor(mBlockedExternallyIndicatorColor);\n            } else if (componentItem.isTracker()) {\n                holder.itemView.setStrokeColor(mTrackerIndicatorColor);\n            } else {\n                holder.itemView.setStrokeColor(Color.TRANSPARENT);\n            }\n            if (componentItem.isTracker()) {\n                holder.chipType.setText(R.string.tracker);\n                holder.chipType.setVisibility(View.VISIBLE);\n            } else holder.chipType.setVisibility(View.GONE);\n            // Label\n            holder.labelView.setText(componentItem.label);\n            // Icon\n            String tag = mPackageName + \"_\" + providerName;\n            holder.imageView.setTag(tag);\n            ImageLoader.getInstance().displayImage(tag, providerInfo, holder.imageView);\n            // Uri permission\n            holder.textView1.setText(String.format(Locale.ROOT, \"%s: %s\", getString(R.string.grant_uri_permission), providerInfo.grantUriPermissions));\n            // Path permissions\n            PathPermission[] pathPermissions = providerInfo.pathPermissions;\n            String finalString;\n            if (pathPermissions != null) {\n                StringBuilder builder = new StringBuilder();\n                String read = getString(R.string.read);\n                String write = getString(R.string.write);\n                for (PathPermission permission : pathPermissions) {\n                    builder.append(read).append(\": \").append(permission.getReadPermission());\n                    builder.append(\"/\");\n                    builder.append(write).append(\": \").append(permission.getWritePermission());\n                    builder.append(\", \");\n                }\n                Utils.checkStringBuilderEnd(builder);\n                finalString = builder.toString();\n            } else finalString = \"null\";\n            holder.textView2.setText(String.format(Locale.ROOT, \"%s: %s\", getString(R.string.path_permissions), finalString)); // +\"\\n\"+providerInfo.readPermission +\"\\n\"+providerInfo.writePermission);\n            // Pattern matchers\n            PatternMatcher[] patternMatchers = providerInfo.uriPermissionPatterns;\n            String finalString1;\n            if (patternMatchers != null) {\n                StringBuilder builder = new StringBuilder();\n                for (PatternMatcher patternMatcher : patternMatchers) {\n                    builder.append(patternMatcher.toString());\n                    builder.append(\", \");\n                }\n                Utils.checkStringBuilderEnd(builder);\n                finalString1 = builder.toString();\n            } else\n                finalString1 = \"null\";\n            holder.textView3.setText(String.format(Locale.ROOT, \"%s: %s\", getString(R.string.patterns_allowed), finalString1));\n            // Authority\n            holder.textView4.setText(String.format(Locale.ROOT, \"%s: %s\", getString(R.string.authority), providerInfo.authority));\n            // Name\n            if (mConstraint != null && providerName.toLowerCase(Locale.ROOT).contains(mConstraint)) {\n                // Highlight searched query\n                holder.nameView.setText(UIUtils.getHighlightedText(providerName, mConstraint, colorQueryStringHighlight));\n            } else {\n                holder.nameView.setText(providerName.startsWith(mPackageName) ?\n                        providerName.replaceFirst(mPackageName, \"\") : providerName);\n            }\n            // Process name\n            String processName = providerInfo.processName;\n            if (processName != null && !processName.equals(mPackageName)) {\n                holder.processNameView.setVisibility(View.VISIBLE);\n                holder.processNameView.setText(String.format(Locale.ROOT, \"%s: %s\",\n                        getString(R.string.process_name), processName));\n            } else holder.processNameView.setVisibility(View.GONE);\n            // Blocking\n            if (mCanModifyComponentStates) {\n                handleBlock(holder, componentItem, RuleType.PROVIDER);\n            } else {\n                holder.toggleSwitch.setVisibility(View.GONE);\n                holder.blockingMethod.setVisibility(View.GONE);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/details/AppDetailsFragment.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.details;\n\nimport android.content.pm.PackageManager;\nimport android.os.Bundle;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.TextView;\n\nimport androidx.annotation.CallSuper;\nimport androidx.annotation.IntDef;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.core.view.MenuProvider;\nimport androidx.fragment.app.Fragment;\nimport androidx.lifecycle.Lifecycle;\nimport androidx.lifecycle.ViewModelProvider;\n\nimport com.google.android.material.progressindicator.LinearProgressIndicator;\n\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\n\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.misc.AdvancedSearchView;\nimport io.github.muntashirakon.AppManager.utils.UIUtils;\nimport io.github.muntashirakon.AppManager.utils.appearance.ColorCodes;\nimport io.github.muntashirakon.view.ProgressIndicatorCompat;\nimport io.github.muntashirakon.widget.MaterialAlertView;\nimport io.github.muntashirakon.widget.RecyclerView;\nimport io.github.muntashirakon.widget.SwipeRefreshLayout;\n\npublic abstract class AppDetailsFragment extends Fragment implements AdvancedSearchView.OnQueryTextListener,\n        SwipeRefreshLayout.OnRefreshListener, MenuProvider {\n    @IntDef(value = {\n            APP_INFO,\n            ACTIVITIES,\n            SERVICES,\n            RECEIVERS,\n            PROVIDERS,\n            APP_OPS,\n            USES_PERMISSIONS,\n            PERMISSIONS,\n            FEATURES,\n            CONFIGURATIONS,\n            SIGNATURES,\n            SHARED_LIBRARIES,\n            OVERLAYS,\n    })\n    @Retention(RetentionPolicy.SOURCE)\n    public @interface Property {\n    }\n\n    public static final int APP_INFO = 0;\n    public static final int ACTIVITIES = 1;\n    public static final int SERVICES = 2;\n    public static final int RECEIVERS = 3;\n    public static final int PROVIDERS = 4;\n    public static final int APP_OPS = 5;\n    public static final int USES_PERMISSIONS = 6;\n    public static final int PERMISSIONS = 7;\n    public static final int FEATURES = 8;\n    public static final int CONFIGURATIONS = 9;\n    public static final int SIGNATURES = 10;\n    public static final int SHARED_LIBRARIES = 11;\n    public static final int OVERLAYS = 12;\n\n    @IntDef(value = {\n            SORT_BY_NAME,\n            SORT_BY_BLOCKED,\n            SORT_BY_TRACKERS,\n            SORT_BY_APP_OP_VALUES,\n            SORT_BY_DENIED_APP_OPS,\n            SORT_BY_DANGEROUS_PERMS,\n            SORT_BY_DENIED_PERMS,\n            SORT_BY_PRIORITY,\n    })\n    @Retention(RetentionPolicy.SOURCE)\n    public @interface SortOrder {\n    }\n\n    public static final int SORT_BY_NAME = 0;\n    public static final int SORT_BY_BLOCKED = 1;\n    public static final int SORT_BY_TRACKERS = 2;\n    public static final int SORT_BY_APP_OP_VALUES = 3;\n    public static final int SORT_BY_DENIED_APP_OPS = 4;\n    public static final int SORT_BY_DANGEROUS_PERMS = 5;\n    public static final int SORT_BY_DENIED_PERMS = 6;\n    public static final int SORT_BY_PRIORITY = 7;\n\n    public static final int[] sSortMenuItemIdsMap = {\n            R.id.action_sort_by_name, R.id.action_sort_by_blocked_components,\n            R.id.action_sort_by_tracker_components, R.id.action_sort_by_app_ops_values,\n            R.id.action_sort_by_denied_app_ops, R.id.action_sort_by_dangerous_permissions,\n            R.id.action_sort_by_denied_permissions, R.id.action_sort_by_priority};\n\n    public static final String ARG_TYPE = \"type\";\n\n    protected PackageManager packageManager;\n    protected AppDetailsActivity activity;\n    protected MaterialAlertView alertView;\n\n    protected SwipeRefreshLayout swipeRefresh;\n    protected LinearProgressIndicator progressIndicator;\n    protected RecyclerView recyclerView;\n    protected TextView emptyView;\n    @Nullable\n    protected AppDetailsViewModel viewModel;\n\n    protected int colorQueryStringHighlight;\n\n    @CallSuper\n    @Override\n    public void onCreate(@Nullable Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        activity = (AppDetailsActivity) requireActivity();\n        viewModel = new ViewModelProvider(activity).get(AppDetailsViewModel.class);\n        packageManager = activity.getPackageManager();\n        colorQueryStringHighlight = ColorCodes.getQueryStringHighlightColor(activity);\n    }\n\n    @Nullable\n    @Override\n    public final View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {\n        return inflater.inflate(R.layout.pager_app_details, container, false);\n    }\n\n    @CallSuper\n    @Override\n    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {\n        // Swipe refresh\n        swipeRefresh = view.findViewById(R.id.swipe_refresh);\n        swipeRefresh.setOnRefreshListener(this);\n        recyclerView = view.findViewById(R.id.scrollView);\n        recyclerView.setLayoutManager(UIUtils.getGridLayoutAt450Dp(activity));\n        emptyView = view.findViewById(android.R.id.empty);\n        recyclerView.setEmptyView(emptyView);\n        progressIndicator = view.findViewById(R.id.progress_linear);\n        progressIndicator.setVisibilityAfterHide(View.GONE);\n        ProgressIndicatorCompat.setVisibility(progressIndicator, true);\n        alertView = view.findViewById(R.id.alert_text);\n        alertView.setEndIconMode(MaterialAlertView.END_ICON_CUSTOM);\n        alertView.setEndIconDrawable(com.google.android.material.R.drawable.mtrl_ic_cancel);\n        alertView.setEndIconContentDescription(R.string.close);\n        swipeRefresh.setOnChildScrollUpCallback((parent, child) -> recyclerView.canScrollVertically(-1));\n        requireActivity().addMenuProvider(this, getViewLifecycleOwner(), Lifecycle.State.RESUMED);\n    }\n\n    @CallSuper\n    @Override\n    public void onResume() {\n        super.onResume();\n        swipeRefresh.setEnabled(true);\n    }\n\n    @CallSuper\n    @Override\n    public void onPause() {\n        super.onPause();\n        swipeRefresh.setEnabled(false);\n    }\n\n    @CallSuper\n    @Override\n    public void onDestroyView() {\n        swipeRefresh.setRefreshing(false);\n        swipeRefresh.clearAnimation();\n        super.onDestroyView();\n    }\n\n    @Override\n    public boolean onQueryTextSubmit(String query, int type) {\n        return false;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/details/AppDetailsOtherFragment.java",
    "content": "// SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.details;\n\nimport static io.github.muntashirakon.AppManager.utils.Utils.openAsFolderInFM;\n\nimport android.annotation.SuppressLint;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.pm.ConfigurationInfo;\nimport android.content.pm.FeatureInfo;\nimport android.content.pm.PackageInfo;\nimport android.graphics.Color;\nimport android.os.Build;\nimport android.os.Bundle;\nimport android.text.SpannableStringBuilder;\nimport android.text.TextUtils;\nimport android.text.format.Formatter;\nimport android.view.LayoutInflater;\nimport android.view.Menu;\nimport android.view.MenuInflater;\nimport android.view.MenuItem;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.TextView;\n\nimport androidx.annotation.IntDef;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.UiThread;\nimport androidx.core.content.ContextCompat;\nimport androidx.core.content.pm.PackageInfoCompat;\n\nimport com.google.android.material.button.MaterialButton;\nimport com.google.android.material.card.MaterialCardView;\nimport com.google.android.material.chip.Chip;\n\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.security.cert.CertificateEncodingException;\nimport java.security.cert.X509Certificate;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Objects;\n\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.details.struct.AppDetailsFeatureItem;\nimport io.github.muntashirakon.AppManager.details.struct.AppDetailsItem;\nimport io.github.muntashirakon.AppManager.details.struct.AppDetailsLibraryItem;\nimport io.github.muntashirakon.AppManager.utils.PackageUtils;\nimport io.github.muntashirakon.AppManager.utils.ThreadUtils;\nimport io.github.muntashirakon.AppManager.utils.UIUtils;\nimport io.github.muntashirakon.AppManager.utils.Utils;\nimport io.github.muntashirakon.io.Paths;\nimport io.github.muntashirakon.util.AdapterUtils;\nimport io.github.muntashirakon.util.LocalizedString;\nimport io.github.muntashirakon.view.ProgressIndicatorCompat;\nimport io.github.muntashirakon.widget.RecyclerView;\n\npublic class AppDetailsOtherFragment extends AppDetailsFragment {\n    @IntDef(value = {\n            FEATURES,\n            CONFIGURATIONS,\n            SIGNATURES,\n            SHARED_LIBRARIES\n    })\n    @Retention(RetentionPolicy.SOURCE)\n    public @interface OtherProperty {\n    }\n\n    private AppDetailsRecyclerAdapter mAdapter;\n    private boolean mIsExternalApk;\n    @OtherProperty\n    private int mNeededProperty;\n\n    @Override\n    public void onCreate(@Nullable Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        mNeededProperty = requireArguments().getInt(ARG_TYPE);\n    }\n\n    @Override\n    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {\n        super.onViewCreated(view, savedInstanceState);\n        emptyView.setText(getNotFoundString(mNeededProperty));\n        mAdapter = new AppDetailsRecyclerAdapter();\n        recyclerView.setAdapter(mAdapter);\n        alertView.setVisibility(View.GONE);\n        if (viewModel == null) return;\n        viewModel.get(mNeededProperty).observe(getViewLifecycleOwner(), appDetailsItems -> {\n            if (appDetailsItems != null && mAdapter != null && viewModel.isPackageExist()) {\n                mIsExternalApk = viewModel.isExternalApk();\n                mAdapter.setDefaultList(appDetailsItems);\n            } else ProgressIndicatorCompat.setVisibility(progressIndicator, false);\n        });\n    }\n\n    @Override\n    public void onRefresh() {\n        refreshDetails();\n        swipeRefresh.setRefreshing(false);\n    }\n\n    @Override\n    public void onCreateMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) {\n        inflater.inflate(R.menu.fragment_app_details_refresh_actions, menu);\n    }\n\n    @Override\n    public boolean onMenuItemSelected(@NonNull MenuItem item) {\n        int id = item.getItemId();\n        if (id == R.id.action_refresh_details) {\n            refreshDetails();\n            return true;\n        }\n        return false;\n    }\n\n    @Override\n    public void onResume() {\n        super.onResume();\n        if (activity.searchView != null) {\n            activity.searchView.setVisibility(View.GONE);\n        }\n    }\n\n    @Override\n    public boolean onQueryTextChange(String searchQuery, int type) {\n        if (viewModel != null) {\n            viewModel.setSearchQuery(searchQuery, type, mNeededProperty);\n        }\n        return true;\n    }\n\n    private void refreshDetails() {\n        if (viewModel == null || mIsExternalApk) return;\n        ProgressIndicatorCompat.setVisibility(progressIndicator, true);\n        viewModel.triggerPackageChange();\n    }\n\n    /**\n     * Return corresponding section's array\n     */\n    private int getNotFoundString(@OtherProperty int index) {\n        switch (index) {\n            case FEATURES:\n                return R.string.no_feature;\n            case CONFIGURATIONS:\n                return R.string.no_configurations;\n            case SIGNATURES:\n                return R.string.app_signing_no_signatures;\n            case SHARED_LIBRARIES:\n                return R.string.no_shared_libs;\n            default:\n                return 0;\n        }\n    }\n\n    @UiThread\n    private class AppDetailsRecyclerAdapter extends RecyclerView.Adapter<AppDetailsRecyclerAdapter.ViewHolder> {\n        @NonNull\n        private final List<AppDetailsItem<?>> mAdapterList;\n        @OtherProperty\n        private int mRequestedProperty;\n\n        AppDetailsRecyclerAdapter() {\n            mAdapterList = new ArrayList<>();\n        }\n\n        @UiThread\n        void setDefaultList(@NonNull List<AppDetailsItem<?>> list) {\n            ThreadUtils.postOnBackgroundThread(() -> {\n                mRequestedProperty = mNeededProperty;\n                ThreadUtils.postOnMainThread(() -> {\n                    if (isDetached()) return;\n                    ProgressIndicatorCompat.setVisibility(progressIndicator, false);\n                    synchronized (mAdapterList) {\n                        AdapterUtils.notifyDataSetChanged(this, mAdapterList, list);\n                    }\n                });\n            });\n        }\n\n        /**\n         * ViewHolder to use recycled views efficiently. Fields names are not expressive because we use\n         * the same holder for any kind of view, and view are not all sames.\n         */\n        class ViewHolder extends RecyclerView.ViewHolder {\n            MaterialCardView itemView;\n            TextView textView1;\n            TextView textView2;\n            TextView textView3;\n            TextView textView4;\n            TextView textView5;\n            MaterialButton launchBtn;\n            Chip chipType;\n\n            public ViewHolder(@NonNull View itemView) {\n                super(itemView);\n                this.itemView = (MaterialCardView) itemView;\n                switch (mRequestedProperty) {\n                    case FEATURES:\n                        textView1 = itemView.findViewById(R.id.name);\n                        textView3 = itemView.findViewById(R.id.gles_ver);\n                        break;\n                    case CONFIGURATIONS:\n                        textView1 = itemView.findViewById(R.id.reqgles);\n                        textView2 = itemView.findViewById(R.id.reqfea);\n                        textView3 = itemView.findViewById(R.id.reqkey);\n                        textView4 = itemView.findViewById(R.id.reqnav);\n                        textView5 = itemView.findViewById(R.id.reqtouch);\n                        break;\n                    case SHARED_LIBRARIES:\n                        textView1 = itemView.findViewById(R.id.item_title);\n                        textView2 = itemView.findViewById(R.id.item_subtitle);\n                        launchBtn = itemView.findViewById(R.id.item_open);\n                        chipType = itemView.findViewById(R.id.lib_type);\n                        textView1.setTextIsSelectable(true);\n                        textView2.setTextIsSelectable(true);\n                        break;\n                    case SIGNATURES:\n                        textView1 = itemView.findViewById(R.id.checksum_description);\n                    default:\n                        break;\n                }\n            }\n        }\n\n        @NonNull\n        @Override\n        public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {\n            @SuppressLint(\"InflateParams\") final View view;\n            switch (mRequestedProperty) {\n                default:\n                    view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_app_details_primary, parent, false);\n                    break;\n                case FEATURES:\n                    view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_app_details_secondary, parent, false);\n                    break;\n                case CONFIGURATIONS:\n                    view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_app_details_tertiary, parent, false);\n                    break;\n                case SIGNATURES:\n                    view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_app_details_signature, parent, false);\n                    break;\n                case SHARED_LIBRARIES:\n                    view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_shared_lib, parent, false);\n                    break;\n            }\n            return new ViewHolder(view);\n        }\n\n        @Override\n        public void onBindViewHolder(@NonNull ViewHolder holder, int position) {\n            Context context = holder.itemView.getContext();\n            switch (mRequestedProperty) {\n                case FEATURES:\n                    getFeaturesView(context, holder, position);\n                    break;\n                case CONFIGURATIONS:\n                    getConfigurationView(holder, position);\n                    break;\n                case SIGNATURES:\n                    getSignatureView(context, holder, position);\n                    break;\n                case SHARED_LIBRARIES:\n                    getSharedLibsView(context, holder, position);\n                    break;\n                default:\n                    break;\n            }\n        }\n\n        @Override\n        public long getItemId(int position) {\n            return position;\n        }\n\n        @Override\n        public int getItemCount() {\n            synchronized (mAdapterList) {\n                return mAdapterList.size();\n            }\n        }\n\n        private void getSharedLibsView(@NonNull Context context, @NonNull ViewHolder holder, int index) {\n            AppDetailsLibraryItem<?> item;\n            synchronized (mAdapterList) {\n                item = (AppDetailsLibraryItem<?>) mAdapterList.get(index);\n            }\n            holder.textView1.setText(item.name);\n            holder.chipType.setText(item.type);\n            switch (item.type) {\n                case \"APK\": {\n                    PackageInfo packageInfo = (PackageInfo) item.item;\n                    StringBuilder sb = new StringBuilder()\n                            .append(packageInfo.packageName)\n                            .append(\"\\n\");\n                    if (item.path != null) {\n                        sb.append(Formatter.formatFileSize(context, item.size)).append(\", \");\n                    }\n                    sb.append(getString(R.string.version_name_with_code, packageInfo.versionName,\n                            PackageInfoCompat.getLongVersionCode(packageInfo)));\n                    if (item.path != null) {\n                        sb.append(\"\\n\").append(item.path);\n                        holder.launchBtn.setVisibility(View.VISIBLE);\n                        holder.launchBtn.setIconResource(io.github.muntashirakon.ui.R.drawable.ic_information);\n                        holder.launchBtn.setContentDescription(holder.itemView.getContext().getString(R.string.app_info));\n                        holder.launchBtn.setOnClickListener(v -> {\n                            Intent intent = AppDetailsActivity.getIntent(context, Paths.get(item.path), false);\n                            startActivity(intent);\n                        });\n                    } else holder.launchBtn.setVisibility(View.GONE);\n                    holder.textView2.setText(sb);\n                    break;\n                }\n                case \"⚠️\":\n                case \"SHARED\":\n                case \"EXEC\":\n                case \"SO\": {\n                    if (item.path == null) {\n                        // Native lib\n                        holder.textView2.setText(((LocalizedString) item.item).toLocalizedString(context));\n                        holder.launchBtn.setVisibility(View.GONE);\n                        break;\n                    } // else shared lib, fallthrough\n                }\n                case \"JAR\": {\n                    StringBuilder sb = new StringBuilder(Formatter.formatFileSize(context, item.size))\n                            .append(\"\\n\").append(item.path);\n                    holder.textView2.setText(sb);\n                    holder.launchBtn.setVisibility(View.VISIBLE);\n                    holder.launchBtn.setIconResource(R.drawable.ic_open_in_new);\n                    holder.launchBtn.setContentDescription(holder.itemView.getContext().getString(R.string.open));\n                    holder.launchBtn.setOnClickListener(openAsFolderInFM(context, item.path.getParent()));\n                    break;\n                }\n            }\n            holder.itemView.setStrokeColor(Color.TRANSPARENT);\n        }\n\n        private void getFeaturesView(@NonNull Context context, @NonNull ViewHolder holder, int index) {\n            MaterialCardView view = holder.itemView;\n            final AppDetailsFeatureItem item;\n            synchronized (mAdapterList) {\n                item = (AppDetailsFeatureItem) mAdapterList.get(index);\n            }\n            FeatureInfo featureInfo = item.item;\n            // Set background\n            if (item.required && !item.available) {\n                view.setStrokeColor(ContextCompat.getColor(context, io.github.muntashirakon.ui.R.color.red));\n            } else if (!item.available) {\n                view.setStrokeColor(ContextCompat.getColor(context, io.github.muntashirakon.ui.R.color.disabled_user));\n            } else {\n                view.setStrokeColor(Color.TRANSPARENT);\n            }\n            // Set feature name\n            if (featureInfo.name == null) {\n                // OpenGL ES\n                if (featureInfo.reqGlEsVersion == FeatureInfo.GL_ES_VERSION_UNDEFINED) {\n                    holder.textView1.setText(item.name);\n                } else {\n                    // GL ES version\n                    holder.textView1.setText(String.format(Locale.ROOT, \"%s %s\",\n                            getString(R.string.gles_version), Utils.getGlEsVersion(featureInfo.reqGlEsVersion)));\n                }\n                holder.textView3.setVisibility(View.GONE);\n                return;\n            } else holder.textView1.setText(item.name);\n            // Feature version: 0 means any version\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && featureInfo.version != 0) {\n                holder.textView3.setVisibility(View.VISIBLE);\n                holder.textView3.setText(getString(R.string.minimum_version, featureInfo.version));\n            } else holder.textView3.setVisibility(View.GONE);\n        }\n\n        private void getConfigurationView(@NonNull ViewHolder holder, int index) {\n            MaterialCardView view = holder.itemView;\n            final ConfigurationInfo configurationInfo;\n            synchronized (mAdapterList) {\n                configurationInfo = (ConfigurationInfo) mAdapterList.get(index).item;\n            }\n            view.setStrokeColor(Color.TRANSPARENT);\n            // GL ES version\n            holder.textView1.setText(String.format(Locale.ROOT, \"%s %s\",\n                    getString(R.string.gles_version), Utils.getGlEsVersion(configurationInfo.reqGlEsVersion)));\n            // Flag & others\n            holder.textView2.setText(String.format(Locale.ROOT, \"%s: %s\", getString(R.string.input_features),\n                    Utils.getInputFeaturesString(configurationInfo.reqInputFeatures)));\n            holder.textView3.setText(String.format(Locale.ROOT, \"%s: %s\", getString(R.string.keyboard_type),\n                    getString(Utils.getKeyboardType(configurationInfo.reqKeyboardType))));\n            holder.textView4.setText(String.format(Locale.ROOT, \"%s: %s\", getString(R.string.navigation),\n                    getString(Utils.getNavigation(configurationInfo.reqNavigation))));\n            holder.textView5.setText(String.format(Locale.ROOT, \"%s: %s\", getString(R.string.touchscreen),\n                    getString(Utils.getTouchScreen(configurationInfo.reqTouchScreen))));\n        }\n\n        private void getSignatureView(@NonNull Context context, @NonNull ViewHolder holder, int index) {\n            TextView textView = holder.textView1;\n            AppDetailsItem<?> item;\n            synchronized (mAdapterList) {\n                item = mAdapterList.get(index);\n            }\n            final X509Certificate signature = (X509Certificate) item.item;\n            final SpannableStringBuilder builder = new SpannableStringBuilder();\n            if (index == 0) {\n                // Display verifier info\n                builder.append(PackageUtils.getApkVerifierInfo(Objects.requireNonNull(viewModel).getApkVerifierResult(), context));\n            }\n            if (!TextUtils.isEmpty(item.name)) {\n                builder.append(UIUtils.getTitleText(context, item.name)).append(\"\\n\");\n            }\n            try {\n                builder.append(PackageUtils.getSigningCertificateInfo(context, signature));\n            } catch (CertificateEncodingException ignore) {\n            }\n            textView.setText(builder);\n            textView.setTextIsSelectable(true);\n            holder.itemView.setStrokeColor(Color.TRANSPARENT);\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/details/AppDetailsOverlaysFragment.java",
    "content": "package io.github.muntashirakon.AppManager.details;\n\nimport android.content.om.IOverlayManager;\nimport android.graphics.Color;\nimport android.os.Build;\nimport android.os.Bundle;\nimport android.view.LayoutInflater;\nimport android.view.Menu;\nimport android.view.MenuInflater;\nimport android.view.MenuItem;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.TextView;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.RequiresApi;\nimport androidx.annotation.UiThread;\n\nimport com.google.android.material.card.MaterialCardView;\nimport com.google.android.material.materialswitch.MaterialSwitch;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Locale;\n\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.compat.ManifestCompat;\nimport io.github.muntashirakon.AppManager.compat.OverlayManagerCompact;\nimport io.github.muntashirakon.AppManager.details.struct.AppDetailsItem;\nimport io.github.muntashirakon.AppManager.details.struct.AppDetailsOverlayItem;\nimport io.github.muntashirakon.AppManager.logs.Log;\nimport io.github.muntashirakon.AppManager.self.SelfPermissions;\nimport io.github.muntashirakon.AppManager.self.pref.TipsPrefs;\nimport io.github.muntashirakon.AppManager.utils.LangUtils;\nimport io.github.muntashirakon.AppManager.utils.ThreadUtils;\nimport io.github.muntashirakon.AppManager.utils.UIUtils;\nimport io.github.muntashirakon.AppManager.utils.appearance.ColorCodes;\nimport io.github.muntashirakon.util.AdapterUtils;\nimport io.github.muntashirakon.view.ProgressIndicatorCompat;\nimport io.github.muntashirakon.widget.MaterialAlertView;\nimport io.github.muntashirakon.widget.RecyclerView;\n\npublic class AppDetailsOverlaysFragment extends AppDetailsFragment {\n\n    private static final String TAG = AppDetailsOverlaysFragment.class.getSimpleName();\n    private AppDetailsRecyclerAdapter mAdapter;\n    private IOverlayManager overlayManager;\n\n    @Override\n    public void onCreate(@Nullable Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O\n                && SelfPermissions.checkSelfOrRemotePermission(ManifestCompat.permission.CHANGE_OVERLAY_PACKAGES)) {\n            overlayManager = OverlayManagerCompact.getOverlayManager();\n        }\n    }\n\n    @Override\n    public void onCreateMenu(@NonNull Menu menu, @NonNull MenuInflater menuInflater) {\n        menuInflater.inflate(R.menu.fragment_app_details_overlay_actions, menu);\n    }\n\n\n    @Override\n    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {\n        super.onViewCreated(view, savedInstanceState);\n        String emptyStringText;\n        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {\n            emptyStringText = getString(R.string.overlay_sdk_version_too_low);\n        } else if (!SelfPermissions.checkSelfOrRemotePermission(ManifestCompat.permission.CHANGE_OVERLAY_PACKAGES)) {\n            emptyStringText = getString(R.string.no_overlay_permission);\n        } else {\n            emptyStringText = getString(R.string.no_overlays);\n        }\n        emptyView.setText(emptyStringText);\n\n        mAdapter = new AppDetailsRecyclerAdapter();\n        recyclerView.setAdapter(mAdapter);\n        alertView.setEndIconOnClickListener(v -> {\n            alertView.hide();\n            TipsPrefs.getInstance().setDisplayInOverlaysTab(false);\n        });\n        if (TipsPrefs.getInstance().displayInOverlaysTab()) {\n            alertView.postDelayed(() -> alertView.hide(), 15_000);\n        } else {\n            alertView.setVisibility(View.GONE);\n        }\n        if (viewModel == null) return;\n        viewModel.get(AppDetailsFragment.OVERLAYS).observe(getViewLifecycleOwner(), appDetailsItems -> {\n            if (appDetailsItems != null && mAdapter != null && viewModel.isPackageExist()) {\n                mAdapter.setDefaultList(appDetailsItems);\n            } else ProgressIndicatorCompat.setVisibility(progressIndicator, false);\n        });\n        viewModel.getRuleApplicationStatus().observe(getViewLifecycleOwner(), status -> {\n            alertView.setAlertType(MaterialAlertView.ALERT_TYPE_WARN);\n            if (status == AppDetailsViewModel.RULE_NOT_APPLIED) {\n                alertView.show();\n            } else alertView.hide();\n        });\n\n    }\n\n    @Override\n    public boolean onMenuItemSelected(@NonNull MenuItem menuItem) {\n        int id = menuItem.getItemId();\n        if (id == R.id.action_refresh_details) {\n            refreshDetails();\n        } else if (id == R.id.action_sort_by_name) {\n            setSortBy(SORT_BY_NAME);\n            menuItem.setChecked(true);\n        } else if (id == R.id.action_sort_by_priority) {\n            setSortBy(SORT_BY_PRIORITY);\n            menuItem.setChecked(true);\n        } else return false;\n        return true;\n    }\n\n    private void setSortBy(@SortOrder int sortBy) {\n        ProgressIndicatorCompat.setVisibility(progressIndicator, true);\n        if (viewModel == null) return;\n        viewModel.setSortOrder(sortBy, OVERLAYS);\n    }\n\n    private void refreshDetails() {\n        if (viewModel == null || overlayManager == null) return;\n        ProgressIndicatorCompat.setVisibility(progressIndicator, true);\n        viewModel.triggerPackageChange();\n    }\n\n    @Override\n    public void onRefresh() {\n        swipeRefresh.setRefreshing(false);\n    }\n\n    @Override\n    public boolean onQueryTextChange(String newText, int type) {\n        if (viewModel != null) {\n            viewModel.setSearchQuery(newText, type, OVERLAYS);\n        }\n        return true;\n    }\n\n    private class AppDetailsRecyclerAdapter extends RecyclerView.Adapter<AppDetailsRecyclerAdapter.ViewHolder> {\n\n        @NonNull\n        private final List<AppDetailsItem<?>> mAdapterList;\n        @Nullable\n        private String mConstraint;\n\n        @UiThread\n        void setDefaultList(List<AppDetailsItem<?>> list) {\n            ThreadUtils.postOnBackgroundThread(() -> {\n                mConstraint = viewModel == null ? null : viewModel.getSearchQuery();\n                ThreadUtils.postOnMainThread(() -> {\n                    if (isDetached()) return;\n                    ProgressIndicatorCompat.setVisibility(progressIndicator, false);\n                    synchronized (mAdapterList) {\n                        AdapterUtils.notifyDataSetChanged(this, mAdapterList, list);\n                    }\n                });\n            });\n        }\n\n        AppDetailsRecyclerAdapter() {\n            mAdapterList = new ArrayList<>();\n        }\n\n        @NonNull\n        @Override\n        public ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {\n            return new ViewHolder(\n                    LayoutInflater.from(viewGroup.getContext())\n                            .inflate(R.layout.item_app_details_overlay, viewGroup, false)\n            );\n        }\n\n        @Override\n        @RequiresApi(Build.VERSION_CODES.O)\n        public void onBindViewHolder(@NonNull ViewHolder holder, int index) {\n            AppDetailsOverlayItem overlayItem;\n            synchronized (mAdapterList) {\n                overlayItem = (AppDetailsOverlayItem) mAdapterList.get(index);\n            }\n            String overlayName = overlayItem.name;\n\n            if (mConstraint != null && overlayName.toLowerCase(Locale.ROOT).contains(mConstraint)) {\n                // Highlight searched query\n                holder.overlayName.setText(UIUtils.getHighlightedText(overlayName, mConstraint, colorQueryStringHighlight));\n            } else holder.overlayName.setText(overlayName);\n            holder.packageName.setText(overlayItem.getPackageName());\n            if (overlayItem.getCategory() != null) {\n                holder.overlayCategory.setVisibility(View.VISIBLE);\n                String category = getString(R.string.overlay_category) + LangUtils.getSeparatorString() + overlayItem.getCategory();\n                holder.overlayCategory.setText(category);\n            } else {\n                holder.overlayCategory.setVisibility(View.GONE);\n            }\n            holder.toggleSwitch.setEnabled(overlayItem.isMutable());\n            holder.toggleSwitch.setClickable(true);\n            holder.toggleSwitch.setChecked(overlayItem.isEnabled());\n\n            StringBuilder sb = new StringBuilder(getString(R.string.state))\n                    .append(LangUtils.getSeparatorString())\n                    .append(overlayItem.getReadableState());\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {\n                sb.append(\" | \")\n                        .append(getString(R.string.priority))\n                        .append(LangUtils.getSeparatorString())\n                        .append(overlayItem.getPriority());\n            }\n            holder.overlayState.setText(sb);\n            holder.itemView.setClickable(false);\n            if (overlayItem.isMutable()) {\n                holder.toggleSwitch.setClickable(true);\n                holder.toggleSwitch.setOnClickListener((v) -> ThreadUtils.postOnBackgroundThread(() -> {\n                    try {\n                        // TODO: 2/18/25 Move to ViewModel\n                        if (overlayItem.setEnabled(overlayManager, !overlayItem.isEnabled())) {\n                            ThreadUtils.postOnMainThread(() -> notifyItemChanged(index, AdapterUtils.STUB));\n                        } else throw new Exception(\"Error Changing Overlay State \" + overlayItem);\n                    } catch (Exception e) {\n                        Log.e(TAG, \"Couldn't Change Overlay State\", e);\n                        ThreadUtils.postOnMainThread(() -> UIUtils.displayShortToast(R.string.failed));\n                    }\n                }));\n                holder.toggleSwitch.setVisibility(View.VISIBLE);\n            } else {\n                holder.toggleSwitch.setOnClickListener(null);\n                holder.toggleSwitch.setClickable(false);\n                holder.toggleSwitch.setVisibility(View.GONE);\n            }\n\n\n            if (overlayItem.isFabricated()) {\n                holder.itemView.setStrokeColor(ColorCodes.getPermissionDangerousIndicatorColor(requireContext()));\n            }\n            holder.itemView.setStrokeColor(Color.TRANSPARENT);\n\n        }\n\n        @Override\n        public long getItemId(int position) {\n            return position;\n        }\n\n        @Override\n        public int getItemCount() {\n            synchronized (mAdapterList) {\n                return mAdapterList.size();\n            }\n        }\n\n        class ViewHolder extends RecyclerView.ViewHolder {\n            MaterialCardView itemView;\n            TextView overlayName;\n            TextView packageName;\n            TextView overlayCategory;\n            TextView overlayState;\n            MaterialSwitch toggleSwitch;\n\n            public ViewHolder(@NonNull View itemView) {\n                super(itemView);\n                this.itemView = (MaterialCardView) itemView;\n                overlayName = itemView.findViewById(R.id.overlay_name);\n                packageName = itemView.findViewById(R.id.overlay_package_name);\n                overlayCategory = itemView.findViewById(R.id.overlay_category);\n                overlayState = itemView.findViewById(R.id.overlay_state);\n                toggleSwitch = itemView.findViewById(R.id.overlay_toggle_btn);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/details/AppDetailsPermissionsFragment.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.details;\n\nimport static io.github.muntashirakon.AppManager.utils.PackageUtils.getAppOpModeNames;\nimport static io.github.muntashirakon.AppManager.utils.PackageUtils.getAppOpNames;\n\nimport android.annotation.SuppressLint;\nimport android.content.Context;\nimport android.content.pm.PermissionInfo;\nimport android.graphics.Color;\nimport android.os.Bundle;\nimport android.text.SpannableStringBuilder;\nimport android.util.SparseArray;\nimport android.view.LayoutInflater;\nimport android.view.Menu;\nimport android.view.MenuInflater;\nimport android.view.MenuItem;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.ImageView;\nimport android.widget.TextView;\n\nimport androidx.annotation.IntDef;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.UiThread;\n\nimport com.google.android.material.button.MaterialButton;\nimport com.google.android.material.card.MaterialCardView;\nimport com.google.android.material.chip.Chip;\nimport com.google.android.material.materialswitch.MaterialSwitch;\n\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Objects;\n\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.compat.AppOpsManagerCompat;\nimport io.github.muntashirakon.AppManager.compat.ManifestCompat;\nimport io.github.muntashirakon.AppManager.compat.PermissionCompat;\nimport io.github.muntashirakon.AppManager.details.struct.AppDetailsAppOpItem;\nimport io.github.muntashirakon.AppManager.details.struct.AppDetailsDefinedPermissionItem;\nimport io.github.muntashirakon.AppManager.details.struct.AppDetailsItem;\nimport io.github.muntashirakon.AppManager.details.struct.AppDetailsPermissionItem;\nimport io.github.muntashirakon.AppManager.self.SelfPermissions;\nimport io.github.muntashirakon.AppManager.self.imagecache.ImageLoader;\nimport io.github.muntashirakon.AppManager.self.pref.TipsPrefs;\nimport io.github.muntashirakon.AppManager.settings.Prefs;\nimport io.github.muntashirakon.AppManager.utils.DateUtils;\nimport io.github.muntashirakon.AppManager.utils.ExUtils;\nimport io.github.muntashirakon.AppManager.utils.LangUtils;\nimport io.github.muntashirakon.AppManager.utils.ThreadUtils;\nimport io.github.muntashirakon.AppManager.utils.UIUtils;\nimport io.github.muntashirakon.AppManager.utils.Utils;\nimport io.github.muntashirakon.AppManager.utils.appearance.ColorCodes;\nimport io.github.muntashirakon.dialog.SearchableItemsDialogBuilder;\nimport io.github.muntashirakon.dialog.SearchableSingleChoiceDialogBuilder;\nimport io.github.muntashirakon.dialog.TextInputDropdownDialogBuilder;\nimport io.github.muntashirakon.util.AdapterUtils;\nimport io.github.muntashirakon.view.ProgressIndicatorCompat;\nimport io.github.muntashirakon.widget.MaterialAlertView;\nimport io.github.muntashirakon.widget.RecyclerView;\n\npublic class AppDetailsPermissionsFragment extends AppDetailsFragment {\n    @IntDef(value = {\n            APP_OPS,\n            USES_PERMISSIONS,\n            PERMISSIONS,\n    })\n    @Retention(RetentionPolicy.SOURCE)\n    public @interface PermissionProperty {\n    }\n\n    private String mPackageName;\n    private AppDetailsRecyclerAdapter mAdapter;\n    private boolean mIsExternalApk;\n    @PermissionProperty\n    private int mNeededProperty;\n    private int mSortOrder;\n    private String mSearchQuery;\n\n    @Override\n    public void onCreate(@Nullable Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        mNeededProperty = requireArguments().getInt(ARG_TYPE);\n    }\n\n    @Override\n    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {\n        super.onViewCreated(view, savedInstanceState);\n        emptyView.setText(getNotFoundString(mNeededProperty));\n        mAdapter = new AppDetailsRecyclerAdapter();\n        recyclerView.setAdapter(mAdapter);\n        alertView.setEndIconOnClickListener(v -> {\n            alertView.hide();\n            // Check tips\n            if (mNeededProperty == APP_OPS) {\n                TipsPrefs.getInstance().setDisplayInAppOpsTab(false);\n            }\n            if (mNeededProperty == USES_PERMISSIONS) {\n                TipsPrefs.getInstance().setDisplayInUsesPermissionsTab(false);\n            }\n            if (mNeededProperty == PERMISSIONS) {\n                TipsPrefs.getInstance().setDisplayInPermissionsTab(false);\n            }\n        });\n        int helpStringRes = getHelpString(mNeededProperty);\n        if (helpStringRes != 0) alertView.setText(helpStringRes);\n        if (helpStringRes == 0) {\n            alertView.setVisibility(View.GONE);\n        } else {\n            alertView.postDelayed(() -> alertView.hide(), 15_000);\n        }\n        if (viewModel == null) return;\n        mSortOrder = viewModel.getSortOrder(mNeededProperty);\n        mSearchQuery = viewModel.getSearchQuery();\n        mPackageName = viewModel.getPackageName();\n        viewModel.get(mNeededProperty).observe(getViewLifecycleOwner(), appDetailsItems -> {\n            if (appDetailsItems != null && mAdapter != null && viewModel.isPackageExist()) {\n                mPackageName = viewModel.getPackageName();\n                mIsExternalApk = viewModel.isExternalApk();\n                mAdapter.setDefaultList(appDetailsItems);\n            } else ProgressIndicatorCompat.setVisibility(progressIndicator, false);\n        });\n        viewModel.getRuleApplicationStatus().observe(getViewLifecycleOwner(), status -> {\n            alertView.setAlertType(MaterialAlertView.ALERT_TYPE_WARN);\n            if (status == AppDetailsViewModel.RULE_NOT_APPLIED) {\n                alertView.show();\n            } else alertView.hide();\n        });\n    }\n\n    @Override\n    public void onRefresh() {\n        refreshDetails();\n        swipeRefresh.setRefreshing(false);\n    }\n\n    @Override\n    public void onCreateMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) {\n        switch (mNeededProperty) {\n            case APP_OPS:\n                inflater.inflate(R.menu.fragment_app_details_app_ops_actions, menu);\n                break;\n            case USES_PERMISSIONS:\n                if (viewModel != null && !viewModel.isExternalApk()) {\n                    inflater.inflate(R.menu.fragment_app_details_permissions_actions, menu);\n                    break;\n                } // else fallthrough\n            case PERMISSIONS:\n                inflater.inflate(R.menu.fragment_app_details_refresh_actions, menu);\n                break;\n        }\n    }\n\n    @Override\n    public void onPrepareMenu(@NonNull Menu menu) {\n        if (viewModel == null || viewModel.isExternalApk()) {\n            return;\n        }\n        MenuItem sortItem = menu.findItem(sSortMenuItemIdsMap[viewModel.getSortOrder(mNeededProperty)]);\n        if (sortItem != null) {\n            sortItem.setChecked(true);\n        }\n    }\n\n    @Override\n    public boolean onMenuItemSelected(@NonNull MenuItem item) {\n        int id = item.getItemId();\n        if (id == R.id.action_refresh_details) {\n            refreshDetails();\n        } else if (id == R.id.action_reset_to_default) {  // App ops\n            ProgressIndicatorCompat.setVisibility(progressIndicator, true);\n            // TODO: 19/3/23 Perform using a ViewModel\n            ThreadUtils.postOnBackgroundThread(() -> {\n                if (viewModel == null || !viewModel.resetAppOps()) {\n                    ThreadUtils.postOnMainThread(() -> UIUtils.displayShortToast(R.string.failed_to_reset_app_ops));\n                } else {\n                    ThreadUtils.postOnMainThread(() -> {\n                        if (!isDetached()) {\n                            refreshDetails();\n                        }\n                    });\n                }\n            });\n        } else if (id == R.id.action_deny_dangerous_app_ops) {  // App ops\n            ProgressIndicatorCompat.setVisibility(progressIndicator, true);\n            // TODO: 19/3/23 Perform using a ViewModel\n            ThreadUtils.postOnBackgroundThread(() -> {\n                boolean isSuccessful = ExUtils.requireNonNullElse(() -> viewModel != null\n                        && viewModel.ignoreDangerousAppOps(), false);\n                if (isSuccessful) {\n                    ThreadUtils.postOnMainThread(() -> {\n                        if (!isDetached()) {\n                            refreshDetails();\n                        }\n                    });\n                } else {\n                    ThreadUtils.postOnMainThread(() -> UIUtils.displayShortToast(\n                            R.string.failed_to_deny_dangerous_app_ops));\n                }\n            });\n        } else if (id == R.id.action_toggle_default_app_ops) {  // App ops\n            ProgressIndicatorCompat.setVisibility(progressIndicator, true);\n            // Turn filter on/off\n            boolean curr = Prefs.AppDetailsPage.displayDefaultAppOps();\n            Prefs.AppDetailsPage.setDisplayDefaultAppOps(!curr);\n            refreshDetails();\n        } else if (id == R.id.action_custom_app_op) {\n            List<Integer> modes = AppOpsManagerCompat.getModeConstants();\n            List<Integer> appOps = AppOpsManagerCompat.getAllOps();\n            List<CharSequence> modeNames = Arrays.asList(getAppOpModeNames(modes));\n            List<CharSequence> appOpNames = Arrays.asList(getAppOpNames(appOps));\n            TextInputDropdownDialogBuilder builder = new TextInputDropdownDialogBuilder(activity, R.string.set_custom_app_op);\n            builder.setTitle(R.string.set_custom_app_op)\n                    .setDropdownItems(appOpNames, -1, true)\n                    .setAuxiliaryInput(R.string.mode, null, null, modeNames, true)\n                    .setPositiveButton(R.string.apply, (dialog, which, inputText, isChecked) -> {\n                        // Get mode\n                        int mode;\n                        try {\n                            mode = Utils.getIntegerFromString(builder.getAuxiliaryInput(), modeNames, modes);\n                        } catch (IllegalArgumentException e) {\n                            return;\n                        }\n                        // Get op\n                        int op;\n                        try {\n                            op = Utils.getIntegerFromString(inputText, appOpNames, appOps);\n                        } catch (IllegalArgumentException e) {\n                            return;\n                        }\n                        // TODO: 22/5/23 Perform using a ViewModel\n                        ThreadUtils.postOnBackgroundThread(() -> {\n                            if (viewModel != null && viewModel.setAppOp(op, mode)) {\n                                ThreadUtils.postOnMainThread(() -> {\n                                    if (!isDetached()) {\n                                        refreshDetails();\n                                    }\n                                });\n                            } else {\n                                ThreadUtils.postOnMainThread(() -> UIUtils.displayShortToast(\n                                        R.string.failed_to_enable_op));\n                            }\n                        });\n                    })\n                    .setNegativeButton(R.string.cancel, null)\n                    .show();\n        } else if (id == R.id.action_deny_dangerous_permissions) {  // permissions\n            ProgressIndicatorCompat.setVisibility(progressIndicator, true);\n            // TODO: 22/5/23 Perform using a ViewModel\n            ThreadUtils.postOnBackgroundThread(() -> {\n                if (viewModel == null || !viewModel.revokeDangerousPermissions()) {\n                    ThreadUtils.postOnMainThread(() -> UIUtils.displayShortToast(\n                            R.string.failed_to_deny_dangerous_perms));\n                }\n                ThreadUtils.postOnMainThread(() -> {\n                    if (!isDetached()) {\n                        refreshDetails();\n                    }\n                });\n            });\n            // Sorting\n        } else if (id == R.id.action_sort_by_name) {  // All\n            setSortBy(SORT_BY_NAME);\n            item.setChecked(true);\n        } else if (id == R.id.action_sort_by_app_ops_values) {  // App ops\n            setSortBy(SORT_BY_APP_OP_VALUES);\n            item.setChecked(true);\n        } else if (id == R.id.action_sort_by_denied_app_ops) {  // App ops\n            setSortBy(SORT_BY_DENIED_APP_OPS);\n            item.setChecked(true);\n        } else if (id == R.id.action_sort_by_dangerous_permissions) {  // App ops\n            setSortBy(SORT_BY_DANGEROUS_PERMS);\n            item.setChecked(true);\n        } else if (id == R.id.action_sort_by_denied_permissions) {\n            setSortBy(SORT_BY_DENIED_PERMS);\n            item.setChecked(true);\n        } else return false;\n        return true;\n    }\n\n    @Override\n    public void onPause() {\n        super.onPause();\n        if (viewModel != null) {\n            mSortOrder = viewModel.getSortOrder(mNeededProperty);\n            mSearchQuery = viewModel.getSearchQuery();\n        }\n    }\n\n    @Override\n    public void onResume() {\n        super.onResume();\n        if (activity.searchView != null) {\n            if (!activity.searchView.isShown()) {\n                activity.searchView.setVisibility(View.VISIBLE);\n            }\n            activity.searchView.setOnQueryTextListener(this);\n            if (viewModel != null) {\n                int sortOrder = viewModel.getSortOrder(mNeededProperty);\n                String searchQuery = viewModel.getSearchQuery();\n                if (sortOrder != mSortOrder || !Objects.equals(searchQuery, mSearchQuery)) {\n                    viewModel.filterAndSortItems(mNeededProperty);\n                }\n            }\n        }\n    }\n\n    @Override\n    public boolean onQueryTextChange(String searchQuery, int type) {\n        if (viewModel != null) {\n            viewModel.setSearchQuery(searchQuery, type, mNeededProperty);\n        }\n        return true;\n    }\n\n    private int getNotFoundString(@PermissionProperty int index) {\n        switch (index) {\n            case APP_OPS:\n                if (mIsExternalApk) {\n                    return R.string.external_apk_no_app_op;\n                } else if (SelfPermissions.checkSelfOrRemotePermission(ManifestCompat.permission.GET_APP_OPS_STATS)) {\n                    return R.string.no_app_ops;\n                } else return R.string.no_app_ops_permission;\n            case USES_PERMISSIONS:\n            case PERMISSIONS:\n            default:\n                return R.string.require_no_permission;\n        }\n    }\n\n    private int getHelpString(@PermissionProperty int index) {\n        switch (index) {\n            default:\n                return 0;\n            case APP_OPS:\n                if (!TipsPrefs.getInstance().displayInAppOpsTab()) {\n                    return 0;\n                }\n                if (SelfPermissions.canModifyAppOpMode()) {\n                    return R.string.help_app_ops_tab;\n                } else return 0;\n            case USES_PERMISSIONS:\n                if (!TipsPrefs.getInstance().displayInUsesPermissionsTab()) {\n                    return 0;\n                }\n                if (SelfPermissions.canModifyPermissions()) {\n                    return R.string.help_uses_permissions_tab;\n                } else return 0;\n            case PERMISSIONS:\n                if (!TipsPrefs.getInstance().displayInPermissionsTab()) {\n                    return 0;\n                }\n                return R.string.help_permissions_tab;\n        }\n    }\n\n    private void setSortBy(@SortOrder int sortBy) {\n        ProgressIndicatorCompat.setVisibility(progressIndicator, true);\n        if (viewModel == null) return;\n        viewModel.setSortOrder(sortBy, mNeededProperty);\n    }\n\n    private void refreshDetails() {\n        if (viewModel == null || mIsExternalApk) return;\n        ProgressIndicatorCompat.setVisibility(progressIndicator, true);\n        viewModel.triggerPackageChange();\n    }\n\n    @UiThread\n    private class AppDetailsRecyclerAdapter extends RecyclerView.Adapter<AppDetailsRecyclerAdapter.ViewHolder> {\n        @NonNull\n        private final List<AppDetailsItem<?>> mAdapterList;\n        @PermissionProperty\n        private int mRequestedProperty;\n        @Nullable\n        private String mConstraint;\n        private boolean mCanModifyAppOpMode;\n\n        AppDetailsRecyclerAdapter() {\n            mAdapterList = new ArrayList<>();\n        }\n\n        @UiThread\n        void setDefaultList(@NonNull List<AppDetailsItem<?>> list) {\n            ThreadUtils.postOnBackgroundThread(() -> {\n                mRequestedProperty = mNeededProperty;\n                mConstraint = viewModel == null ? null : viewModel.getSearchQuery();\n                mCanModifyAppOpMode = SelfPermissions.canModifyAppOpMode();\n                ThreadUtils.postOnMainThread(() -> {\n                    if (isDetached()) return;\n                    ProgressIndicatorCompat.setVisibility(progressIndicator, false);\n                    synchronized (mAdapterList) {\n                        AdapterUtils.notifyDataSetChanged(this, mAdapterList, list);\n                    }\n                });\n            });\n        }\n\n        /**\n         * ViewHolder to use recycled views efficiently. Fields names are not expressive because we use\n         * the same holder for any kind of view, and view are not all sames.\n         */\n        class ViewHolder extends RecyclerView.ViewHolder {\n            MaterialCardView itemView;\n            TextView textView1;\n            TextView textView2;\n            TextView textView3;\n            TextView textView4;\n            TextView textView5;\n            TextView textView6;\n            TextView textView7;\n            TextView textView8;\n            ImageView imageView;\n            MaterialSwitch toggleSwitch;\n            MaterialButton settingButton;\n            Chip chipType;\n\n            public ViewHolder(@NonNull View itemView) {\n                super(itemView);\n                this.itemView = (MaterialCardView) itemView;\n                switch (mRequestedProperty) {\n                    case PERMISSIONS:\n                        imageView = itemView.findViewById(R.id.icon);\n                        imageView.setContentDescription(itemView.getContext().getString(R.string.icon));\n                        textView1 = itemView.findViewById(R.id.label);\n                        textView2 = itemView.findViewById(R.id.name);\n                        textView3 = itemView.findViewById(R.id.taskAffinity);\n                        textView4 = itemView.findViewById(R.id.orientation);\n                        textView5 = itemView.findViewById(R.id.launchMode);\n                        chipType = itemView.findViewById(R.id.type);\n                        itemView.findViewById(R.id.softInput).setVisibility(View.GONE);\n                        itemView.findViewById(R.id.launch).setVisibility(View.GONE);\n                        itemView.findViewById(R.id.edit_shortcut_btn).setVisibility(View.GONE);\n                        itemView.findViewById(R.id.toggle_button).setVisibility(View.GONE);\n                        break;\n                    case APP_OPS:\n                        textView1 = itemView.findViewById(R.id.op_name);\n                        textView2 = itemView.findViewById(R.id.perm_description);\n                        textView3 = itemView.findViewById(R.id.perm_protection_level);\n                        textView4 = itemView.findViewById(R.id.perm_package_name);\n                        textView5 = itemView.findViewById(R.id.perm_group);\n                        textView6 = itemView.findViewById(R.id.perm_name);\n                        textView7 = itemView.findViewById(R.id.op_mode_running_duration);\n                        textView8 = itemView.findViewById(R.id.op_accept_reject_time);\n                        toggleSwitch = itemView.findViewById(R.id.perm_toggle_btn);\n                        break;\n                    case USES_PERMISSIONS:\n                        textView1 = itemView.findViewById(R.id.perm_name);\n                        textView2 = itemView.findViewById(R.id.perm_description);\n                        textView3 = itemView.findViewById(R.id.perm_protection_level);\n                        textView4 = itemView.findViewById(R.id.perm_package_name);\n                        textView5 = itemView.findViewById(R.id.perm_group);\n                        toggleSwitch = itemView.findViewById(R.id.perm_toggle_btn);\n                        settingButton = itemView.findViewById(R.id.action_settings);\n                        break;\n                    default:\n                        break;\n                }\n            }\n        }\n\n        @NonNull\n        @Override\n        public AppDetailsRecyclerAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {\n            @SuppressLint(\"InflateParams\") final View view;\n            switch (mRequestedProperty) {\n                case PERMISSIONS:\n                default:\n                    view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_app_details_primary, parent, false);\n                    break;\n                case APP_OPS:\n                    view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_app_details_appop, parent, false);\n                    break;\n                case USES_PERMISSIONS:\n                    view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_app_details_perm, parent, false);\n                    break;\n            }\n            return new AppDetailsRecyclerAdapter.ViewHolder(view);\n        }\n\n        @Override\n        public void onBindViewHolder(@NonNull AppDetailsRecyclerAdapter.ViewHolder holder, int position) {\n            Context context = holder.itemView.getContext();\n            switch (mRequestedProperty) {\n                case APP_OPS:\n                    getAppOpsView(context, holder, position);\n                    break;\n                case USES_PERMISSIONS:\n                    getUsesPermissionsView(context, holder, position);\n                    break;\n                case PERMISSIONS:\n                    getPermissionsView(context, holder, position);\n                    break;\n                default:\n                    break;\n            }\n        }\n\n        @Override\n        public long getItemId(int position) {\n            return position;\n        }\n\n        @Override\n        public int getItemCount() {\n            synchronized (mAdapterList) {\n                return mAdapterList.size();\n            }\n        }\n\n        private void getAppOpsView(@NonNull Context context, @NonNull ViewHolder holder, int index) {\n            AppDetailsAppOpItem item;\n            synchronized (mAdapterList) {\n                item = (AppDetailsAppOpItem) mAdapterList.get(index);\n            }\n            final String opStr = item.name;\n            PermissionInfo permissionInfo = item.permissionInfo;\n            // Set op name\n            SpannableStringBuilder opName = new SpannableStringBuilder(item.getOp() + \" - \");\n            if (item.name.equals(String.valueOf(item.getOp()))) {\n                opName.append(getString(R.string.unknown_op));\n            } else if (mConstraint != null && opStr.toLowerCase(Locale.ROOT).contains(mConstraint)) {\n                // Highlight searched query\n                opName.append(UIUtils.getHighlightedText(opStr, mConstraint, colorQueryStringHighlight));\n            } else opName.append(opStr);\n            holder.textView1.setText(opName);\n            // Set op mode, running and duration\n            StringBuilder opRunningInfo = new StringBuilder()\n                    .append(context.getString(R.string.mode))\n                    .append(LangUtils.getSeparatorString())\n                    .append(AppOpsManagerCompat.modeToName(item.getMode()));\n            if (item.isRunning()) {\n                opRunningInfo.append(\", \").append(context.getString(R.string.running));\n            }\n            if (item.getDuration() != 0) {\n                opRunningInfo.append(\", \").append(context.getString(R.string.duration))\n                        .append(LangUtils.getSeparatorString())\n                        .append(DateUtils.getFormattedDuration(context, item.getDuration(), true));\n            }\n            holder.textView7.setText(opRunningInfo);\n            // Set accept-time and/or reject-time\n            long currentTime = System.currentTimeMillis();\n            boolean hasAcceptTime = item.getTime() != 0 && item.getTime() != -1;\n            boolean hasRejectTime = item.getRejectTime() != 0 && item.getRejectTime() != -1;\n            if (hasAcceptTime || hasRejectTime) {\n                StringBuilder opTime = new StringBuilder();\n                if (hasAcceptTime) {\n                    opTime.append(context.getString(R.string.accept_time))\n                            .append(LangUtils.getSeparatorString())\n                            .append(DateUtils.getFormattedDuration(context, currentTime - item.getTime()))\n                            .append(\" \").append(context.getString(R.string.ago));\n                }\n                if (hasRejectTime) {\n                    opTime.append(opTime.length() == 0 ? \"\" : \"\\n\")\n                            .append(context.getString(R.string.reject_time))\n                            .append(LangUtils.getSeparatorString())\n                            .append(DateUtils.getFormattedDuration(context, currentTime - item.getRejectTime()))\n                            .append(\" \").append(context.getString(R.string.ago));\n                }\n                holder.textView8.setVisibility(View.VISIBLE);\n                holder.textView8.setText(opTime);\n            } else holder.textView8.setVisibility(View.GONE);\n            // Set others\n            if (permissionInfo != null) {\n                // Set permission name\n                holder.textView6.setVisibility(View.VISIBLE);\n                holder.textView6.setText(String.format(Locale.ROOT, \"%s%s%s\",\n                        context.getString(R.string.permission_name),\n                        LangUtils.getSeparatorString(),\n                        permissionInfo.name));\n                // Description\n                CharSequence description = permissionInfo.loadDescription(packageManager);\n                if (description != null) {\n                    holder.textView2.setVisibility(View.VISIBLE);\n                    holder.textView2.setText(description);\n                } else holder.textView2.setVisibility(View.GONE);\n                // Protection level\n                String protectionLevel = Utils.getProtectionLevelString(permissionInfo);\n                protectionLevel += '|' + (Objects.requireNonNull(item.permission).isGranted() ? \"granted\" : \"revoked\");\n                holder.textView3.setVisibility(View.VISIBLE);\n                holder.textView3.setText(String.format(Locale.ROOT, \"⚑ %s\", protectionLevel));\n                // Set package name\n                if (permissionInfo.packageName != null) {\n                    holder.textView4.setVisibility(View.VISIBLE);\n                    holder.textView4.setText(String.format(Locale.ROOT, \"%s%s%s\",\n                            context.getString(R.string.package_name), LangUtils.getSeparatorString(),\n                            permissionInfo.packageName));\n                } else holder.textView4.setVisibility(View.GONE);\n                // Set group name\n                if (permissionInfo.group != null) {\n                    holder.textView5.setVisibility(View.VISIBLE);\n                    holder.textView5.setText(String.format(Locale.ROOT, \"%s%s%s\",\n                            context.getString(R.string.group), LangUtils.getSeparatorString(), permissionInfo.group));\n                } else {\n                    holder.textView5.setVisibility(View.GONE);\n                }\n            } else {\n                holder.textView2.setVisibility(View.GONE);\n                holder.textView3.setVisibility(View.GONE);\n                holder.textView4.setVisibility(View.GONE);\n                holder.textView5.setVisibility(View.GONE);\n                holder.textView6.setVisibility(View.GONE);\n            }\n            // Set background\n            if (item.isDangerous) {\n                holder.itemView.setStrokeColor(ColorCodes.getPermissionDangerousIndicatorColor(context));\n            } else {\n                holder.itemView.setStrokeColor(Color.TRANSPARENT);\n            }\n            // Op Switch\n            holder.toggleSwitch.setVisibility(mCanModifyAppOpMode ? View.VISIBLE : View.GONE);\n            // op granted\n            holder.toggleSwitch.setChecked(item.isAllowed());\n            holder.itemView.setOnClickListener(v -> {\n                boolean isAllowed = !item.isAllowed();\n                // TODO: 22/5/23 Perform using a ViewModel\n                ThreadUtils.postOnBackgroundThread(() -> {\n                    if (viewModel != null && viewModel.setAppOpMode(item)) {\n                        ThreadUtils.postOnMainThread(() -> notifyItemChanged(index, AdapterUtils.STUB));\n                    } else {\n                        ThreadUtils.postOnMainThread(() -> UIUtils.displayLongToast(isAllowed\n                                ? R.string.failed_to_enable_op : R.string.failed_to_disable_op));\n                    }\n                });\n            });\n            holder.itemView.setOnLongClickListener(v -> {\n                List<Integer> modes = AppOpsManagerCompat.getModeConstants();\n                new SearchableSingleChoiceDialogBuilder<>(activity, modes, getAppOpModeNames(modes))\n                        .setTitle(R.string.set_app_op_mode)\n                        .setSelection(item.getMode())\n                        .setOnSingleChoiceClickListener((dialog, which, item1, isChecked) -> {\n                            int opMode = modes.get(which);\n                            // TODO: 22/5/23 Perform using a ViewModel\n                            ThreadUtils.postOnBackgroundThread(() -> {\n                                if (viewModel != null && viewModel.setAppOpMode(item, opMode)) {\n                                    ThreadUtils.postOnMainThread(() -> notifyItemChanged(index, AdapterUtils.STUB));\n                                } else {\n                                    ThreadUtils.postOnMainThread(() -> UIUtils.displayLongToast(\n                                            R.string.failed_to_change_app_op_mode));\n                                }\n                            });\n                            dialog.dismiss();\n                        })\n                        .show();\n                return true;\n            });\n        }\n\n        private void getUsesPermissionsView(@NonNull Context context, @NonNull ViewHolder holder, int index) {\n            AppDetailsPermissionItem permissionItem;\n            synchronized (mAdapterList) {\n                permissionItem = (AppDetailsPermissionItem) mAdapterList.get(index);\n            }\n            @NonNull PermissionInfo permissionInfo = permissionItem.item;\n            final String permName = permissionInfo.name;\n            // Set permission name\n            if (mConstraint != null && permName.toLowerCase(Locale.ROOT).contains(mConstraint)) {\n                // Highlight searched query\n                holder.textView1.setText(UIUtils.getHighlightedText(permName, mConstraint, colorQueryStringHighlight));\n            } else holder.textView1.setText(permName);\n            // Set others\n            // Description\n            CharSequence description = permissionInfo.loadDescription(packageManager);\n            if (description != null) {\n                holder.textView2.setVisibility(View.VISIBLE);\n                holder.textView2.setText(description);\n            } else holder.textView2.setVisibility(View.GONE);\n            // Protection level\n            String protectionLevel = Utils.getProtectionLevelString(permissionInfo);\n            protectionLevel += '|' + (permissionItem.permission.isGranted() ? \"granted\" : \"revoked\");\n            holder.textView3.setText(String.format(Locale.ROOT, \"⚑ %s\", protectionLevel));\n            // Set background color\n            if (permissionItem.isDangerous) {\n                holder.itemView.setStrokeColor(ColorCodes.getPermissionDangerousIndicatorColor(context));\n            } else {\n                holder.itemView.setStrokeColor(Color.TRANSPARENT);\n            }\n            // Set package name\n            if (permissionInfo.packageName != null) {\n                holder.textView4.setVisibility(View.VISIBLE);\n                holder.textView4.setText(String.format(\"%s%s%s\", context.getString(R.string.package_name),\n                        LangUtils.getSeparatorString(), permissionInfo.packageName));\n            } else holder.textView4.setVisibility(View.GONE);\n            // Set group name\n            if (permissionInfo.group != null) {\n                holder.textView5.setVisibility(View.VISIBLE);\n                holder.textView5.setText(String.format(\"%s%s%s\", context.getString(R.string.group),\n                        LangUtils.getSeparatorString(), permissionInfo.group));\n            } else holder.textView5.setVisibility(View.GONE);\n            // Permission Switch\n            boolean canGrantOrRevokePermission = permissionItem.modifiable && !mIsExternalApk;\n            if (canGrantOrRevokePermission) {\n                holder.toggleSwitch.setVisibility(View.VISIBLE);\n                holder.toggleSwitch.setChecked(permissionItem.isGranted());\n                // TODO: 22/5/23 Perform using a ViewModel\n                holder.itemView.setOnClickListener(v -> ThreadUtils.postOnBackgroundThread(() -> {\n                    try {\n                        if (Objects.requireNonNull(viewModel).togglePermission(permissionItem)) {\n                            ThreadUtils.postOnMainThread(() -> notifyItemChanged(index, AdapterUtils.STUB));\n                        } else throw new Exception(\"Couldn't grant permission: \" + permName);\n                    } catch (Exception e) {\n                        e.printStackTrace();\n                        ThreadUtils.postOnMainThread(() -> UIUtils.displayShortToast(permissionItem.isGranted()\n                                ? R.string.failed_to_grant_permission\n                                : R.string.failed_to_revoke_permission));\n                    }\n                }));\n            } else {\n                holder.toggleSwitch.setVisibility(View.GONE);\n                holder.itemView.setOnClickListener(null);\n                holder.itemView.setClickable(false);\n                if (permissionItem.settingItem != null) {\n                    holder.settingButton.setVisibility(View.VISIBLE);\n                    holder.settingButton.setOnClickListener(v -> {\n                        try {\n                            String packageName = Objects.requireNonNull(viewModel).getPackageName();\n                            startActivity(permissionItem.settingItem.toIntent(Objects.requireNonNull(packageName)));\n                        } catch (Throwable th) {\n                            th.printStackTrace();\n                            if (th.getLocalizedMessage() != null) {\n                                UIUtils.displayLongToast(th.getLocalizedMessage());\n                            }\n                        }\n                    });\n                } else {\n                    holder.settingButton.setVisibility(View.GONE);\n                }\n            }\n            int flags = permissionItem.permission.getFlags();\n            holder.itemView.setOnLongClickListener(flags == 0 ? null : v -> {\n                // TODO: 12/1/22 Use ViewModel\n                SparseArray<String> permissionFlags = PermissionCompat.getPermissionFlagsWithString(flags);\n                String[] flagStrings = new String[permissionFlags.size()];\n                for (int i = 0; i < flagStrings.length; ++i) {\n                    flagStrings[i] = permissionFlags.valueAt(i);\n                }\n                new SearchableItemsDialogBuilder<>(activity, flagStrings)\n                        .setTitle(R.string.permission_flags)\n                        .setNegativeButton(R.string.close, null)\n                        .show();\n                return true;\n            });\n            holder.itemView.setLongClickable(flags != 0);\n        }\n\n        private void getPermissionsView(@NonNull Context context, @NonNull ViewHolder holder, int index) {\n            AppDetailsDefinedPermissionItem permissionItem;\n            synchronized (mAdapterList) {\n                permissionItem = (AppDetailsDefinedPermissionItem) mAdapterList.get(index);\n            }\n            PermissionInfo permissionInfo = permissionItem.item;\n            // Internal or external\n            holder.chipType.setText(permissionItem.isExternal ? R.string.external : R.string.internal);\n            // Label\n            holder.textView1.setText(permissionInfo.loadLabel(packageManager));\n            // Name\n            if (mConstraint != null && permissionInfo.name.toLowerCase(Locale.ROOT).contains(mConstraint)) {\n                // Highlight searched query\n                holder.textView2.setText(UIUtils.getHighlightedText(permissionInfo.name, mConstraint, colorQueryStringHighlight));\n            } else {\n                holder.textView2.setText(permissionInfo.name.startsWith(mPackageName) ?\n                        permissionInfo.name.replaceFirst(mPackageName, \"\") : permissionInfo.name);\n            }\n            // Icon\n            String tag = mPackageName + \"_\" + permissionInfo.name;\n            holder.imageView.setTag(tag);\n            ImageLoader.getInstance().displayImage(tag, permissionInfo, holder.imageView);\n            // Description\n            CharSequence description = permissionInfo.loadDescription(packageManager);\n            if (description != null) {\n                holder.textView3.setVisibility(View.VISIBLE);\n                holder.textView3.setText(description);\n            } else {\n                holder.textView3.setVisibility(View.GONE);\n            }\n            // LaunchMode\n            holder.textView4.setText(String.format(Locale.ROOT, \"%s: %s\",\n                    getString(R.string.group), permissionInfo.group + permAppOp(permissionInfo.name)));\n            // Protection level\n            String protectionLevel = Utils.getProtectionLevelString(permissionInfo);\n            holder.textView5.setText(String.format(Locale.ROOT, \"⚑ %s\", protectionLevel));\n            // Set border color\n            if (protectionLevel.contains(\"dangerous\")) {\n                holder.itemView.setStrokeColor(ColorCodes.getPermissionDangerousIndicatorColor(context));\n            } else {\n                holder.itemView.setStrokeColor(Color.TRANSPARENT);\n            }\n        }\n\n        @NonNull\n        private String permAppOp(String s) {\n            String opStr = AppOpsManagerCompat.permissionToOp(s);\n            return opStr != null ? \"\\nAppOp: \" + opStr : \"\";\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/details/AppDetailsViewModel.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.details;\n\nimport static io.github.muntashirakon.AppManager.compat.PackageManagerCompat.GET_SIGNING_CERTIFICATES;\nimport static io.github.muntashirakon.AppManager.compat.PackageManagerCompat.MATCH_DISABLED_COMPONENTS;\nimport static io.github.muntashirakon.AppManager.compat.PackageManagerCompat.MATCH_UNINSTALLED_PACKAGES;\n\nimport android.Manifest;\nimport android.annotation.SuppressLint;\nimport android.annotation.UserIdInt;\nimport android.app.ActivityManager;\nimport android.app.AppOpsManager;\nimport android.app.Application;\nimport android.content.ComponentName;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.om.OverlayInfo;\nimport android.content.pm.ActivityInfo;\nimport android.content.pm.ApplicationInfo;\nimport android.content.pm.ComponentInfo;\nimport android.content.pm.ConfigurationInfo;\nimport android.content.pm.FeatureInfo;\nimport android.content.pm.PackageInfo;\nimport android.content.pm.PackageManager;\nimport android.content.pm.PermissionInfo;\nimport android.content.pm.ProviderInfo;\nimport android.content.pm.ServiceInfo;\nimport android.os.Build;\nimport android.os.RemoteException;\nimport android.os.UserHandleHidden;\nimport android.text.TextUtils;\n\nimport androidx.annotation.AnyThread;\nimport androidx.annotation.GuardedBy;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.UiThread;\nimport androidx.annotation.WorkerThread;\nimport androidx.core.content.pm.PermissionInfoCompat;\nimport androidx.lifecycle.AndroidViewModel;\nimport androidx.lifecycle.LiveData;\nimport androidx.lifecycle.MutableLiveData;\n\nimport com.android.apksig.ApkVerifier;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.security.cert.X509Certificate;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Optional;\nimport java.util.Set;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.atomic.AtomicInteger;\n\nimport io.github.muntashirakon.AppManager.apk.ApkFile;\nimport io.github.muntashirakon.AppManager.apk.ApkSource;\nimport io.github.muntashirakon.AppManager.apk.CachedApkSource;\nimport io.github.muntashirakon.AppManager.apk.signing.SignerInfo;\nimport io.github.muntashirakon.AppManager.compat.ActivityManagerCompat;\nimport io.github.muntashirakon.AppManager.compat.AppOpsManagerCompat;\nimport io.github.muntashirakon.AppManager.compat.ApplicationInfoCompat;\nimport io.github.muntashirakon.AppManager.compat.ManifestCompat;\nimport io.github.muntashirakon.AppManager.compat.OverlayManagerCompact;\nimport io.github.muntashirakon.AppManager.compat.PackageManagerCompat;\nimport io.github.muntashirakon.AppManager.compat.PermissionCompat;\nimport io.github.muntashirakon.AppManager.details.struct.AppDetailsActivityItem;\nimport io.github.muntashirakon.AppManager.details.struct.AppDetailsAppOpItem;\nimport io.github.muntashirakon.AppManager.details.struct.AppDetailsComponentItem;\nimport io.github.muntashirakon.AppManager.details.struct.AppDetailsDefinedPermissionItem;\nimport io.github.muntashirakon.AppManager.details.struct.AppDetailsFeatureItem;\nimport io.github.muntashirakon.AppManager.details.struct.AppDetailsItem;\nimport io.github.muntashirakon.AppManager.details.struct.AppDetailsLibraryItem;\nimport io.github.muntashirakon.AppManager.details.struct.AppDetailsOverlayItem;\nimport io.github.muntashirakon.AppManager.details.struct.AppDetailsPermissionItem;\nimport io.github.muntashirakon.AppManager.details.struct.AppDetailsServiceItem;\nimport io.github.muntashirakon.AppManager.logs.Log;\nimport io.github.muntashirakon.AppManager.misc.AdvancedSearchView;\nimport io.github.muntashirakon.AppManager.misc.AdvancedSearchView.ChoiceGenerator;\nimport io.github.muntashirakon.AppManager.permission.DevelopmentPermission;\nimport io.github.muntashirakon.AppManager.permission.PermUtils;\nimport io.github.muntashirakon.AppManager.permission.Permission;\nimport io.github.muntashirakon.AppManager.permission.PermissionException;\nimport io.github.muntashirakon.AppManager.permission.ReadOnlyPermission;\nimport io.github.muntashirakon.AppManager.permission.RuntimePermission;\nimport io.github.muntashirakon.AppManager.rules.RuleType;\nimport io.github.muntashirakon.AppManager.rules.compontents.ComponentUtils;\nimport io.github.muntashirakon.AppManager.rules.compontents.ComponentsBlocker;\nimport io.github.muntashirakon.AppManager.rules.struct.AppOpRule;\nimport io.github.muntashirakon.AppManager.rules.struct.ComponentRule;\nimport io.github.muntashirakon.AppManager.rules.struct.RuleEntry;\nimport io.github.muntashirakon.AppManager.scanner.NativeLibraries;\nimport io.github.muntashirakon.AppManager.self.SelfPermissions;\nimport io.github.muntashirakon.AppManager.settings.Ops;\nimport io.github.muntashirakon.AppManager.settings.Prefs;\nimport io.github.muntashirakon.AppManager.types.PackageChangeReceiver;\nimport io.github.muntashirakon.AppManager.users.UserInfo;\nimport io.github.muntashirakon.AppManager.users.Users;\nimport io.github.muntashirakon.AppManager.utils.ExUtils;\nimport io.github.muntashirakon.AppManager.utils.FreezeUtils;\nimport io.github.muntashirakon.AppManager.utils.Utils;\nimport io.github.muntashirakon.io.IoUtils;\n\npublic class AppDetailsViewModel extends AndroidViewModel {\n    public static final String TAG = AppDetailsViewModel.class.getSimpleName();\n\n    private final PackageManager mPackageManager;\n    private final Object mBlockerLocker = new Object();\n    private final ExecutorService mExecutor = Executors.newFixedThreadPool(4);\n    private final CountDownLatch mPackageInfoWatcher = new CountDownLatch(1);\n    private final MutableLiveData<PackageInfo> mPackageInfoLiveData = new MutableLiveData<>();\n    private final MutableLiveData<Boolean> mTagsAlteredLiveData = new MutableLiveData<>();\n    private final MutableLiveData<Integer> mFreezeTypeLiveData = new MutableLiveData<>();\n    private final MutableLiveData<AppDetailsComponentItem> mComponentChangedLiveData = new MutableLiveData<>();\n\n    @Nullable\n    private PackageInfo mPackageInfo;\n    @Nullable\n    private PackageInfo mInstalledPackageInfo;\n    @Nullable\n    private String mPackageName;\n    @GuardedBy(\"blockerLocker\")\n    private ComponentsBlocker mBlocker;\n    @Nullable\n    private PackageIntentReceiver mReceiver;\n    @Nullable\n    private String mApkPath;\n    @Nullable\n    private ApkSource mApkSource;\n    @Nullable\n    private ApkFile mApkFile;\n    private int mUserId;\n    @AppDetailsFragment.SortOrder\n    private int mSortOrderComponents = Prefs.AppDetailsPage.getComponentsSortOrder();\n    @AppDetailsFragment.SortOrder\n    private int mSortOrderAppOps = Prefs.AppDetailsPage.getAppOpsSortOrder();\n    @AppDetailsFragment.SortOrder\n    private int mSortOrderPermissions = Prefs.AppDetailsPage.getPermissionsSortOrder();\n    @AppDetailsFragment.SortOrder\n    private int mSortOrderOverlays = Prefs.AppDetailsPage.getOverlaysSortOrder();\n    private String mSearchQuery;\n    @AdvancedSearchView.SearchType\n    private int mSearchType;\n    private boolean mWaitForBlocker;\n    private boolean mExternalApk = false;\n\n    public AppDetailsViewModel(@NonNull Application application) {\n        super(application);\n        mPackageManager = application.getPackageManager();\n        mReceiver = new PackageIntentReceiver(this);\n        mWaitForBlocker = true;\n    }\n\n    @GuardedBy(\"blockerLocker\")\n    @Override\n    public void onCleared() {\n        Log.d(TAG, \"On Clear called for %s\", mPackageName);\n        super.onCleared();\n        mExecutor.submit(() -> {\n            synchronized (mBlockerLocker) {\n                if (mBlocker != null) {\n                    // To prevent commit if a mutable instance was created in the middle,\n                    // set the instance read only again\n                    mBlocker.setReadOnly();\n                    mBlocker.close();\n                }\n            }\n        });\n        if (mReceiver != null) {\n            getApplication().unregisterReceiver(mReceiver);\n        }\n        mReceiver = null;\n        IoUtils.closeQuietly(mApkFile);\n        if (mApkSource instanceof CachedApkSource) {\n            ((CachedApkSource) mApkSource).cleanup();\n        }\n        mExecutor.shutdownNow();\n    }\n\n    public LiveData<Integer> getFreezeTypeLiveData() {\n        return mFreezeTypeLiveData;\n    }\n\n    public void loadFreezeType() {\n        mExecutor.submit(() -> {\n            Integer freezeType = FreezeUtils.loadFreezeMethod(mPackageName);\n            mFreezeTypeLiveData.postValue(freezeType);\n        });\n    }\n\n    public MutableLiveData<Boolean> getTagsAlteredLiveData() {\n        return mTagsAlteredLiveData;\n    }\n\n    @UiThread\n    @NonNull\n    public LiveData<PackageInfo> setPackage(@NonNull ApkSource apkSource) {\n        mApkSource = apkSource;\n        mExternalApk = true;\n        mExecutor.submit(() -> {\n            try {\n                Log.d(TAG, \"Package Uri is being set\");\n                mApkFile = mApkSource.resolve();\n                setPackageName(mApkFile.getPackageName());\n                File cachedApkFile = mApkFile.getBaseEntry().getFile(false);\n                if (!cachedApkFile.canRead()) throw new Exception(\"Cannot read \" + cachedApkFile);\n                mApkPath = cachedApkFile.getAbsolutePath();\n                setPackageInfo(false);\n                mPackageInfoLiveData.postValue(getPackageInfo());\n            } catch (Throwable th) {\n                Log.e(TAG, \"Could not fetch package info.\", th);\n                mPackageInfoLiveData.postValue(null);\n            } finally {\n                mPackageInfoWatcher.countDown();\n            }\n        });\n        return mPackageInfoLiveData;\n    }\n\n    @UiThread\n    @NonNull\n    public LiveData<PackageInfo> setPackage(@NonNull String packageName) {\n        mExternalApk = false;\n        mExecutor.submit(() -> {\n            try {\n                Log.d(TAG, \"Package name is being set\");\n                setPackageName(packageName);\n                // TODO: 23/5/21 The app could be “data only”\n                setPackageInfo(false);\n                PackageInfo pi = getPackageInfo();\n                if (pi == null) throw new ApkFile.ApkFileException(\"Package not installed.\");\n                mApkSource = ApkSource.getApkSource(pi.applicationInfo);\n                mApkFile = mApkSource.resolve();\n                mPackageInfoLiveData.postValue(pi);\n            } catch (Throwable th) {\n                Log.e(TAG, \"Could not fetch package info.\", th);\n                mPackageInfoLiveData.postValue(null);\n            } finally {\n                mPackageInfoWatcher.countDown();\n            }\n        });\n        return mPackageInfoLiveData;\n    }\n\n    @AnyThread\n    public void setUserId(@UserIdInt int userId) {\n        mUserId = userId;\n    }\n\n    @AnyThread\n    public int getUserId() {\n        return mUserId;\n    }\n\n    @AnyThread\n    @GuardedBy(\"blockerLocker\")\n    private void setPackageName(String packageName) {\n        if (mPackageName != null) return;\n        Log.d(TAG, \"Package name is being set for %s\", packageName);\n        mPackageName = packageName;\n        if (mExternalApk) return;\n        mExecutor.submit(() -> {\n            synchronized (mBlockerLocker) {\n                try {\n                    mWaitForBlocker = true;\n                    if (mBlocker != null) {\n                        // To prevent commit if a mutable instance was created in the middle,\n                        // set the instance read only again\n                        mBlocker.setReadOnly();\n                        mBlocker.close();\n                    }\n                    mBlocker = ComponentsBlocker.getInstance(packageName, mUserId);\n                } finally {\n                    mWaitForBlocker = false;\n                    mBlockerLocker.notifyAll();\n                }\n            }\n        });\n    }\n\n    @AnyThread\n    public String getPackageName() {\n        return mPackageName;\n    }\n\n    @Nullable\n    public ApkFile getApkFile() {\n        return mApkFile;\n    }\n\n    @AnyThread\n    @Nullable\n    public ApkSource getApkSource() {\n        return mApkSource;\n    }\n\n    public boolean isTestOnlyApp() {\n        return mPackageInfo != null && ApplicationInfoCompat.isTestOnly(mPackageInfo.applicationInfo);\n    }\n\n    @AnyThread\n    @SuppressLint(\"SwitchIntDef\")\n    public void setSortOrder(@AppDetailsFragment.SortOrder int sortOrder, @AppDetailsFragment.Property int property) {\n        switch (property) {\n            case AppDetailsFragment.ACTIVITIES:\n            case AppDetailsFragment.SERVICES:\n            case AppDetailsFragment.RECEIVERS:\n            case AppDetailsFragment.PROVIDERS:\n                mSortOrderComponents = sortOrder;\n                Prefs.AppDetailsPage.setComponentsSortOrder(sortOrder);\n                break;\n            case AppDetailsFragment.APP_OPS:\n                mSortOrderAppOps = sortOrder;\n                Prefs.AppDetailsPage.setAppOpsSortOrder(sortOrder);\n                break;\n            case AppDetailsFragment.USES_PERMISSIONS:\n                mSortOrderPermissions = sortOrder;\n                Prefs.AppDetailsPage.setPermissionsSortOrder(sortOrder);\n                break;\n            case AppDetailsFragment.OVERLAYS:\n                mSortOrderOverlays = sortOrder;\n                Prefs.AppDetailsPage.setOverlaysSortOrder(sortOrder);\n        }\n        mExecutor.submit(() -> filterAndSortItemsInternal(property));\n    }\n\n    @AnyThread\n    @SuppressLint(\"SwitchIntDef\")\n    @AppDetailsFragment.SortOrder\n    public int getSortOrder(@AppDetailsFragment.Property int property) {\n        switch (property) {\n            case AppDetailsFragment.ACTIVITIES:\n            case AppDetailsFragment.SERVICES:\n            case AppDetailsFragment.RECEIVERS:\n            case AppDetailsFragment.PROVIDERS:\n                return mSortOrderComponents;\n            case AppDetailsFragment.APP_OPS:\n                return mSortOrderAppOps;\n            case AppDetailsFragment.USES_PERMISSIONS:\n                return mSortOrderPermissions;\n            case AppDetailsFragment.OVERLAYS:\n                return mSortOrderOverlays;\n        }\n        return AppDetailsFragment.SORT_BY_NAME;\n    }\n\n    @AnyThread\n    public void setSearchQuery(String searchQuery, int searchType, @AppDetailsFragment.Property int property) {\n        mSearchQuery = searchType == AdvancedSearchView.SEARCH_TYPE_REGEX ? searchQuery\n                : searchQuery.toLowerCase(Locale.ROOT);\n        mSearchType = searchType;\n        mExecutor.submit(() -> filterAndSortItemsInternal(property));\n    }\n\n    @AnyThread\n    public String getSearchQuery() {\n        return mSearchQuery;\n    }\n\n    public void filterAndSortItems(@AppDetailsFragment.Property int property) {\n        mExecutor.submit(() -> filterAndSortItemsInternal(property));\n    }\n\n    @SuppressLint({\"SwitchIntDef\", \"NewApi\"})\n    @WorkerThread\n    private void filterAndSortItemsInternal(@AppDetailsFragment.Property int property) {\n        switch (property) {\n            case AppDetailsFragment.ACTIVITIES:\n                synchronized (mActivityItems) {\n                    mActivities.postValue(filterAndSortComponents(mActivityItems));\n                }\n                break;\n            case AppDetailsFragment.PROVIDERS:\n                synchronized (mProviderItems) {\n                    mProviders.postValue(filterAndSortComponents(mProviderItems));\n                }\n                break;\n            case AppDetailsFragment.RECEIVERS:\n                synchronized (mReceiverItems) {\n                    mReceivers.postValue(filterAndSortComponents(mReceiverItems));\n                }\n                break;\n            case AppDetailsFragment.SERVICES:\n                synchronized (mServiceItems) {\n                    mServices.postValue(filterAndSortComponents(mServiceItems));\n                }\n                break;\n            case AppDetailsFragment.APP_OPS: {\n                List<AppDetailsAppOpItem> appDetailsItems;\n                synchronized (mAppOpItems) {\n                    if (!TextUtils.isEmpty(mSearchQuery)) {\n                        appDetailsItems = AdvancedSearchView.matches(mSearchQuery, mAppOpItems,\n                                (ChoiceGenerator<AppDetailsAppOpItem>) item ->\n                                        lowercaseIfNotRegex(item.name, mSearchType),\n                                mSearchType);\n                    } else appDetailsItems = mAppOpItems;\n                }\n                Collections.sort(appDetailsItems, (o1, o2) -> {\n                    switch (mSortOrderAppOps) {\n                        case AppDetailsFragment.SORT_BY_NAME:\n                            return o1.name.compareToIgnoreCase(o2.name);\n                        case AppDetailsFragment.SORT_BY_APP_OP_VALUES:\n                            Integer o1Op = o1.getOp();\n                            Integer o2Op = o2.getOp();\n                            return o1Op.compareTo(o2Op);\n                        case AppDetailsFragment.SORT_BY_DENIED_APP_OPS:\n                            // A slight hack to sort it this way: ignore > foreground > deny > default[ > ask] > allow\n                            Integer o1Mode = o1.getMode();\n                            Integer o2Mode = o2.getMode();\n                            return -o1Mode.compareTo(o2Mode);\n                    }\n                    return 0;\n                });\n                mAppOps.postValue(appDetailsItems);\n                break;\n            }\n            case AppDetailsFragment.USES_PERMISSIONS: {\n                List<AppDetailsPermissionItem> appDetailsItems;\n                synchronized (mUsesPermissionItems) {\n                    if (!TextUtils.isEmpty(mSearchQuery)) {\n                        appDetailsItems = AdvancedSearchView.matches(mSearchQuery, mUsesPermissionItems,\n                                (ChoiceGenerator<AppDetailsPermissionItem>) item -> lowercaseIfNotRegex(item.name,\n                                        mSearchType), mSearchType);\n                    } else appDetailsItems = mUsesPermissionItems;\n                }\n                Collections.sort(appDetailsItems, (o1, o2) -> {\n                    switch (mSortOrderPermissions) {\n                        case AppDetailsFragment.SORT_BY_NAME:\n                            return o1.name.compareToIgnoreCase(o2.name);\n                        case AppDetailsFragment.SORT_BY_DANGEROUS_PERMS:\n                            return -Boolean.compare(o1.isDangerous, o2.isDangerous);\n                        case AppDetailsFragment.SORT_BY_DENIED_PERMS:\n                            return Boolean.compare(o1.permission.isGranted(), o2.permission.isGranted());\n                    }\n                    return 0;\n                });\n                mUsesPermissions.postValue(new ArrayList<>(appDetailsItems));\n                break;\n            }\n            case AppDetailsFragment.PERMISSIONS:\n                synchronized (mPermissionItems) {\n                    mPermissions.postValue(filterAndSortPermissions(mPermissionItems));\n                }\n                break;\n            case AppDetailsFragment.OVERLAYS: {\n                List<AppDetailsOverlayItem> appDetailsItems;\n                synchronized (mOverlays) {\n                    if (!TextUtils.isEmpty(mSearchQuery)) {\n                        appDetailsItems = AdvancedSearchView.matches(mSearchQuery, mOverlays.getValue(),\n                                (ChoiceGenerator<AppDetailsOverlayItem>) item -> lowercaseIfNotRegex(item.name,\n                                        mSearchType), mSearchType);\n                    } else appDetailsItems = mOverlays.getValue();\n                }\n                Collections.sort(appDetailsItems, (o1, o2) -> {\n                    switch (mSortOrderOverlays) {\n                        case AppDetailsFragment.SORT_BY_NAME:\n                            return o1.name.compareToIgnoreCase(o2.name);\n                        case AppDetailsFragment.SORT_BY_PRIORITY:\n                            return Integer.compare(o1.getPriority(), o2.getPriority());\n                    }\n                    return 0;\n                });\n                mOverlays.postValue(new ArrayList<>(appDetailsItems));\n                break;\n            }\n            case AppDetailsFragment.APP_INFO:\n            case AppDetailsFragment.CONFIGURATIONS:\n            case AppDetailsFragment.FEATURES:\n            case AppDetailsFragment.SHARED_LIBRARIES:\n            case AppDetailsFragment.SIGNATURES:\n                // do nothing\n                break;\n        }\n    }\n\n    @WorkerThread\n    @Nullable\n    private List<AppDetailsItem<ComponentInfo>> filterAndSortComponents(\n            @Nullable List<AppDetailsItem<ComponentInfo>> appDetailsItems) {\n        if (appDetailsItems == null) return null;\n        if (TextUtils.isEmpty(mSearchQuery)) {\n            sortComponents(appDetailsItems);\n            return appDetailsItems;\n        }\n        List<AppDetailsItem<ComponentInfo>> appDetailsItemsInt = AdvancedSearchView.matches(mSearchQuery, appDetailsItems,\n                (ChoiceGenerator<AppDetailsItem<ComponentInfo>>) item -> lowercaseIfNotRegex(item.name, mSearchType), mSearchType);\n        sortComponents(appDetailsItemsInt);\n        return appDetailsItemsInt;\n    }\n\n    @WorkerThread\n    @Nullable\n    private List<AppDetailsItem<PermissionInfo>> filterAndSortPermissions(\n            @Nullable List<AppDetailsItem<PermissionInfo>> appDetailsItems) {\n        if (appDetailsItems == null) return null;\n        if (TextUtils.isEmpty(mSearchQuery)) {\n            Collections.sort(appDetailsItems, (o1, o2) -> o1.name.compareToIgnoreCase(o2.name));\n            return appDetailsItems;\n        }\n        List<AppDetailsItem<PermissionInfo>> appDetailsItemsInt = AdvancedSearchView.matches(mSearchQuery,\n                appDetailsItems, (ChoiceGenerator<AppDetailsItem<PermissionInfo>>) item ->\n                        lowercaseIfNotRegex(item.name, mSearchType), mSearchType);\n        Collections.sort(appDetailsItemsInt, (o1, o2) -> o1.name.compareToIgnoreCase(o2.name));\n        return appDetailsItemsInt;\n    }\n\n    /**\n     * Return lowercase string if regex isn't enabled (among the search types, only regex is case-sensitive).\n     */\n    private String lowercaseIfNotRegex(String s, @AdvancedSearchView.SearchType int filterType) {\n        return filterType == AdvancedSearchView.SEARCH_TYPE_REGEX ? s : s.toLowerCase(Locale.ROOT);\n    }\n\n    public static final int RULE_APPLIED = 0;\n    public static final int RULE_NOT_APPLIED = 1;\n    public static final int RULE_NO_RULE = 2;\n\n    @NonNull\n    private final MutableLiveData<Integer> mRuleApplicationStatus = new MutableLiveData<>();\n\n    @UiThread\n    public LiveData<Integer> getRuleApplicationStatus() {\n        if (mRuleApplicationStatus.getValue() == null) {\n            mExecutor.submit(this::setRuleApplicationStatus);\n        }\n        return mRuleApplicationStatus;\n    }\n\n    @WorkerThread\n    @GuardedBy(\"blockerLocker\")\n    public void setRuleApplicationStatus() {\n        if (mPackageName == null || mExternalApk) {\n            mRuleApplicationStatus.postValue(RULE_NO_RULE);\n            return;\n        }\n        synchronized (mBlockerLocker) {\n            waitForBlockerOrExit();\n            final AtomicInteger newRuleApplicationStatus = new AtomicInteger();\n            newRuleApplicationStatus.set(mBlocker.isRulesApplied() ? RULE_APPLIED : RULE_NOT_APPLIED);\n            if (mBlocker.componentCount() == 0) newRuleApplicationStatus.set(RULE_NO_RULE);\n            mRuleApplicationStatus.postValue(newRuleApplicationStatus.get());\n        }\n    }\n\n    @AnyThread\n    @GuardedBy(\"blockerLocker\")\n    public void updateRulesForComponent(@NonNull AppDetailsComponentItem componentItem, @NonNull RuleType type,\n                                        @ComponentRule.ComponentStatus String componentStatus) {\n        if (mExternalApk) return;\n        mExecutor.submit(() -> {\n            Optional.ofNullable(mReceiver).ifPresent(PackageIntentReceiver::pauseWatcher);\n            String componentName = componentItem.name;\n            synchronized (mBlockerLocker) {\n                waitForBlockerOrExit();\n                mBlocker.setMutable();\n                if (mBlocker.hasComponentName(componentName)) {\n                    // Simply delete it\n                    mBlocker.deleteComponent(componentName);\n                }\n                // Add to the list\n                mBlocker.addComponent(componentName, type, componentStatus);\n                // Apply rules if global blocking enable or already applied\n                if (Prefs.Blocking.globalBlockingEnabled()\n                        || (mRuleApplicationStatus.getValue() != null && RULE_APPLIED == mRuleApplicationStatus.getValue())) {\n                    mBlocker.applyRules(true);\n                }\n                // Set new status\n                setRuleApplicationStatus();\n                // Commit changes\n                mBlocker.commit();\n                mBlocker.setReadOnly();\n                Optional.ofNullable(mReceiver).ifPresent(PackageIntentReceiver::resumeWatcher);\n            }\n        });\n    }\n\n    @Nullable\n    public ComponentRule getComponentRule(String componentName) {\n        synchronized (mBlockerLocker) {\n            if (mBlocker != null) {\n                return mBlocker.getComponent(componentName);\n            }\n            return null;\n        }\n    }\n\n    @WorkerThread\n    @GuardedBy(\"blockerLocker\")\n    public void addRules(List<? extends RuleEntry> entries, boolean forceApply) {\n        if (mExternalApk) return;\n        synchronized (mBlockerLocker) {\n            waitForBlockerOrExit();\n            mBlocker.setMutable();\n            for (RuleEntry entry : entries) {\n                String componentName = entry.name;\n                if (mBlocker.hasComponentName(componentName)) {\n                    // Remove from the list\n                    mBlocker.removeComponent(componentName);\n                }\n                // Add to the list (again)\n                mBlocker.addComponent(componentName, entry.type);\n            }\n            // Apply rules if global blocking enable or already applied\n            if (forceApply || Prefs.Blocking.globalBlockingEnabled()\n                    || (mRuleApplicationStatus.getValue() != null && RULE_APPLIED == mRuleApplicationStatus.getValue())) {\n                mBlocker.applyRules(true);\n            }\n            // Set new status\n            setRuleApplicationStatus();\n            // Commit changes\n            mBlocker.commit();\n            mBlocker.setReadOnly();\n            // Update UI\n            reloadComponents();\n        }\n    }\n\n    @WorkerThread\n    @GuardedBy(\"blockerLocker\")\n    public void removeRules(List<? extends RuleEntry> entries, boolean forceApply) {\n        if (mExternalApk) return;\n        synchronized (mBlockerLocker) {\n            waitForBlockerOrExit();\n            mBlocker.setMutable();\n            for (RuleEntry entry : entries) {\n                String componentName = entry.name;\n                if (mBlocker.hasComponentName(componentName)) {\n                    // Remove from the list\n                    mBlocker.removeComponent(componentName);\n                }\n            }\n            // Apply rules if global blocking enable or already applied\n            if (forceApply || Prefs.Blocking.globalBlockingEnabled()\n                    || (mRuleApplicationStatus.getValue() != null && RULE_APPLIED == mRuleApplicationStatus.getValue())) {\n                mBlocker.applyRules(true);\n            }\n            // Set new status\n            setRuleApplicationStatus();\n            // Commit changes\n            mBlocker.commit();\n            mBlocker.setReadOnly();\n            // Update UI\n            reloadComponents();\n        }\n    }\n\n    @WorkerThread\n    @GuardedBy(\"blockerLocker\")\n    public boolean togglePermission(final AppDetailsPermissionItem permissionItem) {\n        if (mExternalApk) return false;\n        PackageInfo packageInfo = getPackageInfoInternal();\n        if (packageInfo == null) return false;\n        try {\n            if (!permissionItem.isGranted()) {\n                Log.d(TAG, \"Granting permission: %s\", permissionItem.name);\n                permissionItem.grantPermission(packageInfo, mAppOpsManager);\n            } else {\n                Log.d(TAG, \"Revoking permission: %s\", permissionItem.name);\n                permissionItem.revokePermission(packageInfo, mAppOpsManager);\n            }\n        } catch (RemoteException | PermissionException e) {\n            e.printStackTrace();\n            return false;\n        }\n        mExecutor.submit(() -> {\n            synchronized (mBlockerLocker) {\n                waitForBlockerOrExit();\n                mBlocker.setMutable();\n                mBlocker.setPermission(permissionItem.name, permissionItem.permission.isGranted(),\n                        permissionItem.permission.getFlags());\n                mBlocker.commit();\n                mBlocker.setReadOnly();\n                mBlockerLocker.notifyAll();\n            }\n        });\n        setUsesPermission(permissionItem);\n        return true;\n    }\n\n    @WorkerThread\n    @GuardedBy(\"blockerLocker\")\n    public boolean revokeDangerousPermissions() {\n        if (mExternalApk) return false;\n        PackageInfo packageInfo = getPackageInfoInternal();\n        if (packageInfo == null) return false;\n        List<AppDetailsPermissionItem> revokedPermissions = new ArrayList<>();\n        boolean isSuccessful = true;\n        synchronized (mUsesPermissionItems) {\n            for (AppDetailsPermissionItem permissionItem : mUsesPermissionItems) {\n                if (!permissionItem.isDangerous || !permissionItem.permission.isGranted()) continue;\n                try {\n                    permissionItem.revokePermission(packageInfo, mAppOpsManager);\n                    revokedPermissions.add(permissionItem);\n                } catch (RemoteException | PermissionException e) {\n                    e.printStackTrace();\n                    isSuccessful = false;\n                }\n            }\n        }\n        // Save values to the blocking rules\n        mExecutor.submit(() -> {\n            synchronized (mBlockerLocker) {\n                waitForBlockerOrExit();\n                mBlocker.setMutable();\n                for (AppDetailsPermissionItem permItem : revokedPermissions) {\n                    mBlocker.setPermission(permItem.name, permItem.permission.isGranted(), permItem.permission.getFlags());\n                }\n                mBlocker.commit();\n                mBlocker.setReadOnly();\n                mBlockerLocker.notifyAll();\n            }\n        });\n        return isSuccessful;\n    }\n\n    @NonNull\n    private final AppOpsManagerCompat mAppOpsManager = new AppOpsManagerCompat();\n\n    @WorkerThread\n    @GuardedBy(\"blockerLocker\")\n    public boolean setAppOp(int op, int mode) {\n        if (mExternalApk) return false;\n        PackageInfo packageInfo = getPackageInfoInternal();\n        if (packageInfo == null) return false;\n        try {\n            // Set mode\n            PermUtils.setAppOpMode(mAppOpsManager, op, mPackageName, packageInfo.applicationInfo.uid, mode);\n            mExecutor.submit(() -> {\n                synchronized (mBlockerLocker) {\n                    waitForBlockerOrExit();\n                    mBlocker.setMutable();\n                    mBlocker.setAppOp(op, mode);\n                    mBlocker.commit();\n                    mBlocker.setReadOnly();\n                    mBlockerLocker.notifyAll();\n                }\n            });\n        } catch (PermissionException e) {\n            e.printStackTrace();\n            return false;\n        }\n        return true;\n    }\n\n    @WorkerThread\n    @GuardedBy(\"blockerLocker\")\n    public boolean setAppOpMode(AppDetailsAppOpItem appOpItem) {\n        if (mExternalApk) return false;\n        PackageInfo packageInfo = getPackageInfoInternal();\n        if (packageInfo == null) return false;\n        try {\n            if (appOpItem.isAllowed()) {\n                appOpItem.disallowAppOp(packageInfo, mAppOpsManager);\n            } else {\n                appOpItem.allowAppOp(packageInfo, mAppOpsManager);\n            }\n            setAppOp(appOpItem);\n            mExecutor.submit(() -> {\n                synchronized (mBlockerLocker) {\n                    waitForBlockerOrExit();\n                    mBlocker.setMutable();\n                    mBlocker.setAppOp(appOpItem.getOp(), appOpItem.getMode());\n                    mBlocker.commit();\n                    mBlocker.setReadOnly();\n                    mBlockerLocker.notifyAll();\n                }\n            });\n            return true;\n        } catch (PermissionException e) {\n            e.printStackTrace();\n            return false;\n        }\n    }\n\n    @WorkerThread\n    @GuardedBy(\"blockerLocker\")\n    public boolean setAppOpMode(AppDetailsAppOpItem appOpItem, @AppOpsManagerCompat.Mode int mode) {\n        if (mExternalApk) return false;\n        PackageInfo packageInfo = getPackageInfoInternal();\n        if (packageInfo == null) return false;\n        try {\n            appOpItem.setAppOp(packageInfo, mAppOpsManager, mode);\n            setAppOp(appOpItem);\n            mExecutor.submit(() -> {\n                synchronized (mBlockerLocker) {\n                    waitForBlockerOrExit();\n                    mBlocker.setMutable();\n                    mBlocker.setAppOp(appOpItem.getOp(), appOpItem.getMode());\n                    mBlocker.commit();\n                    mBlocker.setReadOnly();\n                    mBlockerLocker.notifyAll();\n                }\n            });\n            return true;\n        } catch (PermissionException e) {\n            e.printStackTrace();\n            return false;\n        }\n    }\n\n    @WorkerThread\n    @GuardedBy(\"blockerLocker\")\n    public boolean resetAppOps() {\n        if (mExternalApk) return false;\n        if (getPackageInfoInternal() == null || mPackageName == null) return false;\n        try {\n            mAppOpsManager.resetAllModes(mUserId, mPackageName);\n            mExecutor.submit(this::loadAppOps);\n            // Save values to the blocking rules\n            mExecutor.submit(() -> {\n                synchronized (mBlockerLocker) {\n                    waitForBlockerOrExit();\n                    List<AppOpRule> appOpEntries = mBlocker.getAll(AppOpRule.class);\n                    mBlocker.setMutable();\n                    for (AppOpRule entry : appOpEntries)\n                        mBlocker.removeEntry(entry);\n                    mBlocker.commit();\n                    mBlocker.setReadOnly();\n                    mBlockerLocker.notifyAll();\n                }\n            });\n            return true;\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n        return false;\n    }\n\n    @WorkerThread\n    @GuardedBy(\"blockerLocker\")\n    public boolean ignoreDangerousAppOps() {\n        if (mExternalApk) return false;\n        PackageInfo packageInfo = getPackageInfoInternal();\n        if (packageInfo == null) return false;\n        String permName;\n        final List<Integer> opItems = new ArrayList<>();\n        boolean isSuccessful = true;\n        synchronized (mAppOpItems) {\n            for (AppDetailsAppOpItem mAppOpItem : mAppOpItems) {\n                try {\n                    permName = AppOpsManagerCompat.opToPermission(mAppOpItem.getOp());\n                    if (permName != null) {\n                        PermissionInfo permissionInfo = mPackageManager.getPermissionInfo(permName,\n                                PackageManager.GET_META_DATA);\n                        int basePermissionType = PermissionInfoCompat.getProtection(permissionInfo);\n                        if (basePermissionType == PermissionInfo.PROTECTION_DANGEROUS) {\n                            // Set mode\n                            try {\n                                PermUtils.setAppOpMode(mAppOpsManager, mAppOpItem.getOp(), mPackageName,\n                                        packageInfo.applicationInfo.uid, AppOpsManager.MODE_IGNORED);\n                                opItems.add(mAppOpItem.getOp());\n                                mAppOpItem.invalidate(mAppOpsManager, packageInfo);\n                            } catch (PermissionException e) {\n                                e.printStackTrace();\n                                isSuccessful = false;\n                                break;\n                            }\n                        }\n                    }\n                } catch (PackageManager.NameNotFoundException | IllegalArgumentException |\n                         IndexOutOfBoundsException ignore) {\n                }\n            }\n        }\n        // Save values to the blocking rules\n        mExecutor.submit(() -> {\n            synchronized (mBlockerLocker) {\n                waitForBlockerOrExit();\n                mBlocker.setMutable();\n                for (int op : opItems)\n                    mBlocker.setAppOp(op, AppOpsManager.MODE_IGNORED);\n                mBlocker.commit();\n                mBlocker.setReadOnly();\n                mBlockerLocker.notifyAll();\n            }\n        });\n        return isSuccessful;\n    }\n\n    @AnyThread\n    @GuardedBy(\"blockerLocker\")\n    public void applyRules() {\n        if (mExternalApk) return;\n        mExecutor.submit(() -> {\n            synchronized (mBlockerLocker) {\n                waitForBlockerOrExit();\n                boolean oldIsRulesApplied = mBlocker.isRulesApplied();\n                mBlocker.setMutable();\n                mBlocker.applyRules(!oldIsRulesApplied);\n                mBlocker.commit();\n                mBlocker.setReadOnly();\n                reloadComponents();\n                setRuleApplicationStatus();\n                mBlockerLocker.notifyAll();\n            }\n        });\n    }\n\n    @UiThread\n    public LiveData<List<AppDetailsItem<?>>> get(@AppDetailsFragment.Property int property) {\n        switch (property) {\n            case AppDetailsFragment.ACTIVITIES:\n                return observeInternal(mActivities);\n            case AppDetailsFragment.SERVICES:\n                return observeInternal(mServices);\n            case AppDetailsFragment.RECEIVERS:\n                return observeInternal(mReceivers);\n            case AppDetailsFragment.PROVIDERS:\n                return observeInternal(mProviders);\n            case AppDetailsFragment.APP_OPS:\n                return observeInternal(mAppOps);\n            case AppDetailsFragment.USES_PERMISSIONS:\n                return observeInternal(mUsesPermissions);\n            case AppDetailsFragment.PERMISSIONS:\n                return observeInternal(mPermissions);\n            case AppDetailsFragment.FEATURES:\n                return observeInternal(mFeatures);\n            case AppDetailsFragment.CONFIGURATIONS:\n                return observeInternal(mConfigurations);\n            case AppDetailsFragment.SIGNATURES:\n                return observeInternal(mSignatures);\n            case AppDetailsFragment.SHARED_LIBRARIES:\n                return observeInternal(mSharedLibraries);\n            case AppDetailsFragment.OVERLAYS:\n                return observeInternal(mOverlays);\n            case AppDetailsFragment.APP_INFO:\n                return observeInternal(mAppInfo);\n            default:\n                throw new IllegalArgumentException(\"Invalid property: \" + property);\n        }\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    @AnyThread\n    @NonNull\n    private MutableLiveData<List<AppDetailsItem<?>>> observeInternal(@NonNull MutableLiveData<?> liveData) {\n        return (MutableLiveData<List<AppDetailsItem<?>>>) liveData;\n    }\n\n    @AnyThread\n    public void load(@AppDetailsFragment.Property int property) {\n        mExecutor.submit(() -> {\n            Optional.ofNullable(mReceiver).ifPresent(PackageIntentReceiver::pauseWatcher);\n            switch (property) {\n                case AppDetailsFragment.ACTIVITIES:\n                    loadActivities();\n                    break;\n                case AppDetailsFragment.SERVICES:\n                    loadServices();\n                    break;\n                case AppDetailsFragment.RECEIVERS:\n                    loadReceivers();\n                    break;\n                case AppDetailsFragment.PROVIDERS:\n                    loadProviders();\n                    break;\n                case AppDetailsFragment.APP_OPS:\n                    loadAppOps();\n                    break;\n                case AppDetailsFragment.USES_PERMISSIONS:\n                    loadUsesPermissions();\n                    break;\n                case AppDetailsFragment.PERMISSIONS:\n                    loadPermissions();\n                    break;\n                case AppDetailsFragment.FEATURES:\n                    loadFeatures();\n                    break;\n                case AppDetailsFragment.CONFIGURATIONS:\n                    loadConfigurations();\n                    break;\n                case AppDetailsFragment.SIGNATURES:\n                    loadSignatures();\n                    break;\n                case AppDetailsFragment.SHARED_LIBRARIES:\n                    loadSharedLibraries();\n                    break;\n                case AppDetailsFragment.OVERLAYS:\n                    loadOverlays();\n                    break;\n                case AppDetailsFragment.APP_INFO:\n                    loadAppInfo();\n                    break;\n            }\n            Optional.ofNullable(mReceiver).ifPresent(PackageIntentReceiver::resumeWatcher);\n        });\n    }\n\n\n    private final MutableLiveData<Boolean> mIsPackageExistLiveData = new MutableLiveData<>();\n    private boolean mIsPackageExist = true;\n\n    @UiThread\n    public LiveData<Boolean> getIsPackageExistLiveData() {\n        if (mIsPackageExistLiveData.getValue() == null)\n            mIsPackageExistLiveData.setValue(mIsPackageExist);\n        return mIsPackageExistLiveData;\n    }\n\n    @AnyThread\n    public boolean isPackageExist() {\n        return mIsPackageExist;\n    }\n\n    @NonNull\n    private final MutableLiveData<Boolean> mPackageChanged = new MutableLiveData<>();\n\n    @UiThread\n    public LiveData<Boolean> isPackageChanged() {\n        if (mPackageChanged.getValue() == null) {\n            mPackageChanged.setValue(false);\n        }\n        return mPackageChanged;\n    }\n\n    @AnyThread\n    public void triggerPackageChange() {\n        mExecutor.submit(this::setPackageChanged);\n    }\n\n    @WorkerThread\n    @GuardedBy(\"blockerLocker\")\n    public void setPackageChanged() {\n        // TODO: 16/3/23 Synchronization is needed somewhere\n        setPackageInfo(true);\n        if (mExternalApk || mExecutor.isShutdown() || mExecutor.isTerminated()) return;\n        mExecutor.submit(() -> {\n            synchronized (mBlockerLocker) {\n                try {\n                    waitForBlockerOrExit();\n                    // Reload app components\n                    mBlocker.reloadComponents();\n                } finally {\n                    mBlockerLocker.notifyAll();\n                }\n            }\n        });\n    }\n\n    @AnyThread\n    public boolean isExternalApk() {\n        return mExternalApk;\n    }\n\n    @AnyThread\n    public int getSplitCount() {\n        if (mApkFile != null && mApkFile.isSplit()) {\n            return mApkFile.getEntries().size() - 1;\n        }\n        return 0;\n    }\n\n    @WorkerThread\n    @GuardedBy(\"blockerLocker\")\n    private void waitForBlockerOrExit() {\n        if (mExternalApk) return;\n        if (mBlocker == null) {\n            try {\n                while (mWaitForBlocker) mBlockerLocker.wait();\n            } catch (InterruptedException e) {\n                e.printStackTrace();\n                Thread.currentThread().interrupt();\n            }\n        }\n    }\n\n    @WorkerThread\n    private void reloadComponents() {\n        mExecutor.submit(() -> {\n            Optional.ofNullable(mReceiver).ifPresent(PackageIntentReceiver::pauseWatcher);\n            loadActivities();\n            loadServices();\n            loadReceivers();\n            loadProviders();\n            loadOverlays();\n            Optional.ofNullable(mReceiver).ifPresent(PackageIntentReceiver::resumeWatcher);\n        });\n    }\n\n    @SuppressLint(\"WrongConstant\")\n    @WorkerThread\n    private void setPackageInfo(boolean reload) {\n        // Package name cannot be null\n        if (mPackageName == null) return;\n        // Wait for component blocker to appear\n        synchronized (mBlockerLocker) {\n            waitForBlockerOrExit();\n        }\n        if (!reload && mPackageInfo != null) return;\n        try {\n            try {\n                mInstalledPackageInfo = PackageManagerCompat.getPackageInfo(mPackageName, PackageManager.GET_META_DATA\n                                | PackageManager.GET_PERMISSIONS | PackageManager.GET_ACTIVITIES | MATCH_DISABLED_COMPONENTS\n                                | PackageManager.GET_RECEIVERS | PackageManager.GET_PROVIDERS | MATCH_UNINSTALLED_PACKAGES\n                                | PackageManager.GET_SERVICES | PackageManager.GET_CONFIGURATIONS | GET_SIGNING_CERTIFICATES\n                                | PackageManager.GET_SHARED_LIBRARY_FILES | PackageManager.GET_URI_PERMISSION_PATTERNS\n                                | PackageManagerCompat.MATCH_STATIC_SHARED_AND_SDK_LIBRARIES,\n                        mUserId);\n                if (!ApplicationInfoCompat.isInstalled(mInstalledPackageInfo.applicationInfo)) {\n                    throw new ApkFile.ApkFileException(\"App not installed. It only has data.\");\n                }\n            } catch (Throwable e) {\n                Log.e(TAG, e);\n                mInstalledPackageInfo = null;\n            }\n            if (mExternalApk) {\n                // Do not get signatures via Android framework as it will simply return NULL without any clarifications.\n                // All signatures are fetched using PackageUtils where a fallback method is used in case the PackageInfo\n                // didn't load any signature. So, we should be safe from any harm.\n                mPackageInfo = mPackageManager.getPackageArchiveInfo(mApkPath, PackageManager.GET_PERMISSIONS\n                        | PackageManager.GET_ACTIVITIES | PackageManager.GET_RECEIVERS | PackageManager.GET_PROVIDERS\n                        | PackageManager.GET_SERVICES | MATCH_DISABLED_COMPONENTS | PackageManager.GET_CONFIGURATIONS\n                        | PackageManager.GET_SHARED_LIBRARY_FILES | PackageManager.GET_URI_PERMISSION_PATTERNS\n                        | PackageManager.GET_META_DATA);\n                if (mPackageInfo == null) {\n                    throw new PackageManager.NameNotFoundException(\"Package cannot be parsed\");\n                }\n                if (mInstalledPackageInfo == null) {\n                    Log.d(TAG, \"%s not installed for user %d\", mPackageName, mUserId);\n                }\n                mPackageInfo.applicationInfo.sourceDir = mApkPath;\n                mPackageInfo.applicationInfo.publicSourceDir = mApkPath;\n            } else {\n                mPackageInfo = mInstalledPackageInfo;\n                if (mPackageInfo == null) {\n                    throw new PackageManager.NameNotFoundException(\"Package not installed\");\n                }\n            }\n            mIsPackageExistLiveData.postValue(mIsPackageExist = true);\n        } catch (PackageManager.NameNotFoundException e) {\n            Log.e(TAG, e);\n            mIsPackageExistLiveData.postValue(mIsPackageExist = false);\n        } catch (Throwable e) {\n            Log.e(TAG, e);\n        } finally {\n            mPackageChanged.postValue(true);\n        }\n    }\n\n    @WorkerThread\n    @Nullable\n    private PackageInfo getPackageInfoInternal() {\n        try {\n            mPackageInfoWatcher.await();\n        } catch (InterruptedException e) {\n            return null;\n        }\n        return mPackageInfo;\n    }\n\n    @AnyThread\n    @Nullable\n    public PackageInfo getPackageInfo() {\n        return mPackageInfo;\n    }\n\n    @AnyThread\n    @Nullable\n    public PackageInfo getInstalledPackageInfo() {\n        return mInstalledPackageInfo;\n    }\n\n    @NonNull\n    public LiveData<UserInfo> getUserInfo() {\n        MutableLiveData<UserInfo> userInfoMutableLiveData = new MutableLiveData<>();\n        mExecutor.submit(() -> {\n            if (mExternalApk) {\n                return;\n            }\n            final List<UserInfo> userInfoList = Users.getUsers();\n            if (userInfoList.size() > 1) {\n                for (UserInfo userInfo : userInfoList) {\n                    if (userInfo.id == mUserId) {\n                        userInfoMutableLiveData.postValue(userInfo);\n                        break;\n                    }\n                }\n            }\n        });\n        return userInfoMutableLiveData;\n    }\n\n    @NonNull\n    private final MutableLiveData<List<AppDetailsItem<PackageInfo>>> mAppInfo = new MutableLiveData<>();\n\n    @WorkerThread\n    private void loadAppInfo() {\n        PackageInfo packageInfo = getPackageInfoInternal();\n        if (packageInfo == null) {\n            mAppInfo.postValue(null);\n            return;\n        }\n        AppDetailsItem<PackageInfo> appDetailsItem = new AppDetailsItem<>(packageInfo);\n        appDetailsItem.name = packageInfo.packageName;\n        List<AppDetailsItem<PackageInfo>> appDetailsItems = Collections.singletonList(appDetailsItem);\n        mAppInfo.postValue(appDetailsItems);\n    }\n\n    @NonNull\n    private final MutableLiveData<List<AppDetailsItem<ComponentInfo>>> mActivities = new MutableLiveData<>();\n    @NonNull\n    private final List<AppDetailsItem<ComponentInfo>> mActivityItems = new ArrayList<>();\n\n    @WorkerThread\n    @GuardedBy(\"blockerLocker\")\n    private void loadActivities() {\n        synchronized (mActivityItems) {\n            mActivityItems.clear();\n            PackageInfo packageInfo = getPackageInfoInternal();\n            if (packageInfo == null || packageInfo.activities == null) {\n                mActivities.postValue(mActivityItems);\n                return;\n            }\n            CharSequence appLabel = packageInfo.applicationInfo.loadLabel(mPackageManager);\n            boolean canStartAnyActivity = SelfPermissions.checkSelfOrRemotePermission(ManifestCompat.permission.START_ANY_ACTIVITY);\n            boolean canStartViaAssist = UserHandleHidden.myUserId() == mUserId &&\n                    SelfPermissions.checkSelfPermission(Manifest.permission.WRITE_SECURE_SETTINGS);\n            for (ActivityInfo activityInfo : packageInfo.activities) {\n                AppDetailsActivityItem componentItem = new AppDetailsActivityItem(activityInfo);\n                componentItem.label = getComponentLabel(activityInfo, appLabel);\n                synchronized (mBlockerLocker) {\n                    if (!mExternalApk) {\n                        componentItem.setRule(mBlocker.getComponent(activityInfo.name));\n                    }\n                }\n                componentItem.setTracker(ComponentUtils.isTracker(activityInfo.name));\n                componentItem.setDisabled(isComponentDisabled(activityInfo));\n                // An activity is allowed to launch only if it's\n                // 1) Not from an external APK\n                // 2) Root enabled or the activity is exportable\n                // 3) App or the activity is not disabled and/or blocked\n                componentItem.canLaunch = !mExternalApk && (canStartAnyActivity || activityInfo.exported)\n                        && !componentItem.isDisabled() && !componentItem.isBlocked();\n                componentItem.canLaunchAssist = !mExternalApk && canStartViaAssist && !componentItem.isDisabled()\n                        && !componentItem.isBlocked();\n                mActivityItems.add(componentItem);\n            }\n            mActivities.postValue(filterAndSortComponents(mActivityItems));\n        }\n    }\n\n    @NonNull\n    private final MutableLiveData<List<AppDetailsItem<ComponentInfo>>> mServices = new MutableLiveData<>();\n    @NonNull\n    private final List<AppDetailsItem<ComponentInfo>> mServiceItems = new ArrayList<>();\n\n    @WorkerThread\n    @GuardedBy(\"blockerLocker\")\n    private void loadServices() {\n        synchronized (mServiceItems) {\n            mServiceItems.clear();\n            PackageInfo packageInfo = getPackageInfoInternal();\n            if (packageInfo == null || packageInfo.services == null) {\n                // There are no services\n                mServices.postValue(Collections.emptyList());\n                return;\n            }\n            List<ActivityManager.RunningServiceInfo> runningServiceInfoList;\n            runningServiceInfoList = ActivityManagerCompat.getRunningServices(mPackageName, mUserId);\n            CharSequence appLabel = packageInfo.applicationInfo.loadLabel(mPackageManager);\n            for (ServiceInfo serviceInfo : packageInfo.services) {\n                AppDetailsServiceItem serviceItem = new AppDetailsServiceItem(serviceInfo);\n                serviceItem.label = getComponentLabel(serviceInfo, appLabel);\n                synchronized (mBlockerLocker) {\n                    if (!mExternalApk) {\n                        serviceItem.setRule(mBlocker.getComponent(serviceInfo.name));\n                    }\n                }\n                serviceItem.setTracker(ComponentUtils.isTracker(serviceInfo.name));\n                serviceItem.setDisabled(isComponentDisabled(serviceInfo));\n                for (ActivityManager.RunningServiceInfo runningServiceInfo : runningServiceInfoList) {\n                    if (runningServiceInfo.service.getClassName().equals(serviceInfo.name)) {\n                        serviceItem.setRunningServiceInfo(runningServiceInfo);\n                    }\n                }\n                // A service is allowed to launch only if it's\n                // 1) Not from an external APK\n                // 2) Root enabled or the service is exportable without any permission\n                // 3) App or the service is not disabled and/or blocked\n                serviceItem.canLaunch = !mExternalApk && canLaunchService(serviceInfo) && !serviceItem.isDisabled()\n                        && !serviceItem.isBlocked();\n                mServiceItems.add(serviceItem);\n            }\n            mServices.postValue(filterAndSortComponents(mServiceItems));\n        }\n    }\n\n    @NonNull\n    private final MutableLiveData<List<AppDetailsItem<ComponentInfo>>> mReceivers = new MutableLiveData<>();\n    @NonNull\n    private final List<AppDetailsItem<ComponentInfo>> mReceiverItems = new ArrayList<>();\n\n    @WorkerThread\n    @GuardedBy(\"blockerLocker\")\n    private void loadReceivers() {\n        synchronized (mReceiverItems) {\n            mReceiverItems.clear();\n            PackageInfo packageInfo = getPackageInfoInternal();\n            if (packageInfo == null || packageInfo.receivers == null) {\n                // There are no receivers\n                mReceivers.postValue(Collections.emptyList());\n                return;\n            }\n            CharSequence appLabel = packageInfo.applicationInfo.loadLabel(mPackageManager);\n            for (ActivityInfo activityInfo : packageInfo.receivers) {\n                AppDetailsComponentItem componentItem = new AppDetailsComponentItem(activityInfo);\n                componentItem.label = getComponentLabel(activityInfo, appLabel);\n                synchronized (mBlockerLocker) {\n                    if (!mExternalApk) {\n                        componentItem.setRule(mBlocker.getComponent(activityInfo.name));\n                    }\n                }\n                componentItem.setTracker(ComponentUtils.isTracker(activityInfo.name));\n                componentItem.setDisabled(isComponentDisabled(activityInfo));\n                mReceiverItems.add(componentItem);\n            }\n            mReceivers.postValue(filterAndSortComponents(mReceiverItems));\n        }\n    }\n\n    @NonNull\n    private final MutableLiveData<List<AppDetailsItem<ComponentInfo>>> mProviders = new MutableLiveData<>();\n    @NonNull\n    private final List<AppDetailsItem<ComponentInfo>> mProviderItems = new ArrayList<>();\n\n    @WorkerThread\n    @GuardedBy(\"blockerLocker\")\n    private void loadProviders() {\n        synchronized (mProviderItems) {\n            mProviderItems.clear();\n            PackageInfo packageInfo = getPackageInfoInternal();\n            if (packageInfo == null || packageInfo.providers == null) {\n                // There are no providers\n                mProviders.postValue(Collections.emptyList());\n                return;\n            }\n            CharSequence appLabel = packageInfo.applicationInfo.loadLabel(mPackageManager);\n            for (ProviderInfo providerInfo : packageInfo.providers) {\n                AppDetailsComponentItem componentItem = new AppDetailsComponentItem(providerInfo);\n                componentItem.label = getComponentLabel(providerInfo, appLabel);\n                synchronized (mBlockerLocker) {\n                    if (!mExternalApk) {\n                        componentItem.setRule(mBlocker.getComponent(providerInfo.name));\n                    }\n                }\n                componentItem.setTracker(ComponentUtils.isTracker(providerInfo.name));\n                componentItem.setDisabled(isComponentDisabled(providerInfo));\n                mProviderItems.add(componentItem);\n            }\n            mProviders.postValue(filterAndSortComponents(mProviderItems));\n        }\n    }\n\n    @NonNull\n    private CharSequence getComponentLabel(@NonNull ComponentInfo componentInfo, @NonNull CharSequence appLabel) {\n        CharSequence componentLabel = componentInfo.loadLabel(mPackageManager);\n        if (componentLabel.equals(componentInfo.name) || componentLabel.equals(appLabel)) {\n            // Component label is as good as null\n            componentLabel = null;\n        }\n        return componentLabel != null ? componentLabel : Utils.camelCaseToSpaceSeparatedString(\n                Utils.getLastComponent(componentInfo.name));\n    }\n\n    @SuppressLint(\"SwitchIntDef\")\n    @WorkerThread\n    private void sortComponents(List<AppDetailsItem<ComponentInfo>> appDetailsItems) {\n        // First sort by name\n        Collections.sort(appDetailsItems, (o1, o2) -> o1.name.compareToIgnoreCase(o2.name));\n        if (mSortOrderComponents == AppDetailsFragment.SORT_BY_NAME) return;\n        Collections.sort(appDetailsItems, (o1, o2) -> {\n            switch (mSortOrderComponents) {\n                // No need to sort by name since we've already done it\n                case AppDetailsFragment.SORT_BY_BLOCKED:\n                    return -Boolean.compare(\n                            ((AppDetailsComponentItem) o1).isBlocked(),\n                            ((AppDetailsComponentItem) o2).isBlocked());\n                case AppDetailsFragment.SORT_BY_TRACKERS:\n                    return -Boolean.compare(\n                            ((AppDetailsComponentItem) o1).isTracker(),\n                            ((AppDetailsComponentItem) o2).isTracker());\n            }\n            return 0;\n        });\n    }\n\n    public boolean isComponentDisabled(@NonNull ComponentInfo componentInfo) {\n        if (mInstalledPackageInfo == null || FreezeUtils.isFrozen(mInstalledPackageInfo.applicationInfo)) {\n            return true;\n        }\n        ComponentName componentName = new ComponentName(componentInfo.packageName, componentInfo.name);\n        try {\n            int componentEnabledSetting = PackageManagerCompat.getComponentEnabledSetting(componentName, mUserId);\n            switch (componentEnabledSetting) {\n                case PackageManager.COMPONENT_ENABLED_STATE_DISABLED:\n                case PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED:\n                case PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER:\n                    return true;\n                case PackageManager.COMPONENT_ENABLED_STATE_ENABLED:\n                    return false;\n                case PackageManager.COMPONENT_ENABLED_STATE_DEFAULT:\n                default:\n            }\n        } catch (Throwable ignore) {\n        }\n        return !componentInfo.isEnabled();\n    }\n\n    private static boolean canLaunchService(@NonNull ServiceInfo info) {\n        if (info.exported && info.permission == null) {\n            return true;\n        }\n        int uid = Users.getSelfOrRemoteUid();\n        if (uid == Ops.ROOT_UID || (uid == Ops.SYSTEM_UID && info.permission == null)) {\n            return true;\n        }\n        if (info.permission == null) {\n            return false;\n        }\n        return SelfPermissions.checkSelfOrRemotePermission(info.permission, uid);\n    }\n\n    @NonNull\n    private final MutableLiveData<List<AppDetailsAppOpItem>> mAppOps = new MutableLiveData<>();\n    @NonNull\n    private final List<AppDetailsAppOpItem> mAppOpItems = new ArrayList<>();\n\n    @WorkerThread\n    public void setAppOp(AppDetailsAppOpItem appDetailsItem) {\n        synchronized (mAppOpItems) {\n            for (int i = 0; i < mAppOpItems.size(); ++i) {\n                if (mAppOpItems.get(i).name.equals(appDetailsItem.name)) {\n                    mAppOpItems.set(i, appDetailsItem);\n                    break;\n                }\n            }\n        }\n    }\n\n    @WorkerThread\n    private void loadAppOps() {\n        PackageInfo packageInfo = getPackageInfoInternal();\n        if (packageInfo == null || mExternalApk || !SelfPermissions.checkSelfOrRemotePermission(ManifestCompat.permission.GET_APP_OPS_STATS)) {\n            mAppOps.postValue(Collections.emptyList());\n            return;\n        }\n        boolean canGetGrantRevokeRuntimePermissions = SelfPermissions.checkGetGrantRevokeRuntimePermissions();\n        synchronized (mAppOpItems) {\n            mAppOpItems.clear();\n            try {\n                int uid = packageInfo.applicationInfo.uid;\n                String packageName = packageInfo.packageName;\n                HashMap<Integer, AppOpsManagerCompat.OpEntry> opToOpEntryMap = new HashMap<>(AppOpsManagerCompat._NUM_OP);\n                for (AppOpsManagerCompat.OpEntry opEntry : AppOpsManagerCompat\n                        .getConfiguredOpsForPackage(mAppOpsManager, packageName, uid)) {\n                    if (opToOpEntryMap.get(opEntry.getOp()) == null) {\n                        opToOpEntryMap.put(opEntry.getOp(), opEntry);\n                    }\n                }\n                // Include from permissions\n                List<String> permissions = getRawPermissions();\n                HashSet<Integer> otherOps = new HashSet<>(AppOpsManagerCompat._NUM_OP);\n                for (String permission : permissions) {\n                    int op = AppOpsManagerCompat.permissionToOpCode(permission);\n                    if (op == AppOpsManagerCompat.OP_NONE\n                            || op >= AppOpsManagerCompat._NUM_OP\n                            || opToOpEntryMap.get(op) != null) {\n                        // Invalid/unsupported app operation\n                        continue;\n                    }\n                    otherOps.add(op);\n                }\n                // Include defaults i.e. app ops without any associated permissions if requested\n                if (Prefs.AppDetailsPage.displayDefaultAppOps()) {\n                    for (int op : AppOpsManagerCompat.getOpsWithoutPermissions()) {\n                        if (op == AppOpsManagerCompat.OP_NONE\n                                || op >= AppOpsManagerCompat._NUM_OP\n                                || opToOpEntryMap.get(op) != null) {\n                            // Invalid/unsupported app operation\n                            continue;\n                        }\n                        otherOps.add(op);\n                    }\n                }\n                for (AppOpsManagerCompat.OpEntry entry : opToOpEntryMap.values()) {\n                    AppDetailsAppOpItem appDetailsItem;\n                    String permissionName = AppOpsManagerCompat.opToPermission(entry.getOp());\n                    if (permissionName != null) {\n                        boolean isGranted = PermissionCompat.checkPermission(permissionName, packageName, mUserId)\n                                == PackageManager.PERMISSION_GRANTED;\n                        int permissionFlags = canGetGrantRevokeRuntimePermissions\n                                ? PermissionCompat.getPermissionFlags(permissionName, packageName, mUserId)\n                                : PermissionCompat.FLAG_PERMISSION_NONE;\n                        PermissionInfo permissionInfo = PermissionCompat.getPermissionInfo(permissionName, packageName, 0);\n                        if (permissionInfo == null) {\n                            permissionInfo = new PermissionInfo();\n                            permissionInfo.name = permissionName;\n                        }\n                        appDetailsItem = new AppDetailsAppOpItem(entry, permissionInfo, isGranted, permissionFlags,\n                                permissions.contains(permissionName));\n                    } else {\n                        appDetailsItem = new AppDetailsAppOpItem(entry);\n                    }\n                    mAppOpItems.add(appDetailsItem);\n                }\n                // Add other ops\n                for (int op : otherOps) {\n                    AppDetailsAppOpItem appDetailsItem;\n                    String permissionName = AppOpsManagerCompat.opToPermission(op);\n                    if (permissionName != null) {\n                        boolean isGranted = PermissionCompat.checkPermission(permissionName, packageName, mUserId)\n                                == PackageManager.PERMISSION_GRANTED;\n                        int permissionFlags = canGetGrantRevokeRuntimePermissions\n                                ? PermissionCompat.getPermissionFlags(permissionName, packageName, mUserId)\n                                : PermissionCompat.FLAG_PERMISSION_NONE;\n                        PermissionInfo permissionInfo = PermissionCompat.getPermissionInfo(permissionName, packageName, 0);\n                        if (permissionInfo == null) {\n                            permissionInfo = new PermissionInfo();\n                            permissionInfo.name = permissionName;\n                        }\n                        appDetailsItem = new AppDetailsAppOpItem(op, permissionInfo, isGranted, permissionFlags,\n                                permissions.contains(permissionName));\n                    } else {\n                        appDetailsItem = new AppDetailsAppOpItem(op);\n                    }\n                    mAppOpItems.add(appDetailsItem);\n                }\n            } catch (Throwable e) {\n                e.printStackTrace();\n            }\n        }\n        filterAndSortItemsInternal(AppDetailsFragment.APP_OPS);\n    }\n\n    @NonNull\n    private final MutableLiveData<List<AppDetailsItem<PermissionInfo>>> mUsesPermissions = new MutableLiveData<>();\n    private final List<AppDetailsPermissionItem> mUsesPermissionItems = new ArrayList<>();\n\n    @WorkerThread\n    public void setUsesPermission(AppDetailsPermissionItem appDetailsPermissionItem) {\n        AppDetailsPermissionItem permissionItem;\n        synchronized (mUsesPermissionItems) {\n            for (int i = 0; i < mUsesPermissionItems.size(); ++i) {\n                permissionItem = mUsesPermissionItems.get(i);\n                if (permissionItem.name.equals(appDetailsPermissionItem.name)) {\n                    mUsesPermissionItems.set(i, appDetailsPermissionItem);\n                    break;\n                }\n            }\n        }\n    }\n\n    @SuppressLint(\"SwitchIntDef\")\n    @WorkerThread\n    private void loadUsesPermissions() {\n        synchronized (mUsesPermissionItems) {\n            mUsesPermissionItems.clear();\n            PackageInfo packageInfo = getPackageInfoInternal();\n            if (packageInfo == null || packageInfo.requestedPermissions == null) {\n                // No requested permissions\n                mUsesPermissions.postValue(Collections.emptyList());\n                return;\n            }\n            List<AppOpsManagerCompat.OpEntry> opEntries = ExUtils.requireNonNullElse(() -> AppOpsManagerCompat\n                            .getConfiguredOpsForPackage(mAppOpsManager, packageInfo.packageName, packageInfo.applicationInfo.uid),\n                    Collections.emptyList());\n            for (int i = 0; i < packageInfo.requestedPermissions.length; ++i) {\n                AppDetailsPermissionItem permissionItem = getPermissionItem(packageInfo.requestedPermissions[i],\n                        (packageInfo.requestedPermissionsFlags[i] & PackageInfo.REQUESTED_PERMISSION_GRANTED) != 0,\n                        opEntries);\n                if (permissionItem != null) {\n                    mUsesPermissionItems.add(permissionItem);\n                }\n            }\n        }\n        filterAndSortItemsInternal(AppDetailsFragment.USES_PERMISSIONS);\n    }\n\n    @WorkerThread\n    public List<String> getRawPermissions() {\n        List<String> rawPermissions = new ArrayList<>();\n        PackageInfo packageInfo = getPackageInfoInternal();\n        if (packageInfo != null && packageInfo.requestedPermissions != null) {\n            rawPermissions.addAll(Arrays.asList(packageInfo.requestedPermissions));\n        }\n        return rawPermissions;\n    }\n\n    @Nullable\n    private AppDetailsPermissionItem getPermissionItem(@NonNull String permissionName, boolean isGranted,\n                                                       @NonNull List<AppOpsManagerCompat.OpEntry> opEntries) {\n        PackageInfo packageInfo = getPackageInfoInternal();\n        if (packageInfo == null) return null;\n        try {\n            PermissionInfo permissionInfo = PermissionCompat.getPermissionInfo(permissionName,\n                    packageInfo.packageName, PackageManager.GET_META_DATA);\n            if (permissionInfo == null) {\n                Log.d(TAG, \"Couldn't fetch info for permission %s\", permissionName);\n                permissionInfo = new PermissionInfo();\n                permissionInfo.name = permissionName;\n            }\n            int flags = permissionInfo.flags;\n            int appOp = AppOpsManagerCompat.permissionToOpCode(permissionName);\n            int permissionFlags;\n            boolean appOpAllowed = false;\n            if (!mExternalApk && SelfPermissions.checkGetGrantRevokeRuntimePermissions()) {\n                permissionFlags = PermissionCompat.getPermissionFlags(\n                        permissionName, packageInfo.packageName, mUserId);\n            } else permissionFlags = PermissionCompat.FLAG_PERMISSION_NONE;\n            if (!mExternalApk && appOp != AppOpsManagerCompat.OP_NONE) {\n                int mode = AppOpsManagerCompat.getModeFromOpEntriesOrDefault(appOp, opEntries);\n                appOpAllowed = mode == AppOpsManager.MODE_ALLOWED;\n                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {\n                    appOpAllowed |= mode == AppOpsManager.MODE_FOREGROUND;\n                }\n            }\n            int protection = PermissionInfoCompat.getProtection(permissionInfo);\n            int protectionFlags = PermissionInfoCompat.getProtectionFlags(permissionInfo);\n            Permission permission;\n            if (protection == PermissionInfo.PROTECTION_DANGEROUS && PermUtils.systemSupportsRuntimePermissions()) {\n                permission = new RuntimePermission(permissionName, isGranted, appOp, appOpAllowed, permissionFlags);\n            } else if ((protectionFlags & PermissionInfo.PROTECTION_FLAG_DEVELOPMENT) != 0) {\n                permission = new DevelopmentPermission(permissionName, isGranted, appOp, appOpAllowed, permissionFlags);\n            } else {\n                permission = new ReadOnlyPermission(permissionName, isGranted, appOp, appOpAllowed, permissionFlags);\n            }\n            AppDetailsPermissionItem appDetailsItem = new AppDetailsPermissionItem(permissionInfo, permission, flags);\n            appDetailsItem.name = permissionName;\n            return appDetailsItem;\n        } catch (Throwable th) {\n            th.printStackTrace();\n            return null;\n        }\n    }\n\n    @NonNull\n    private final MutableLiveData<List<AppDetailsItem<PermissionInfo>>> mPermissions = new MutableLiveData<>();\n    private final List<AppDetailsItem<PermissionInfo>> mPermissionItems = new ArrayList<>();\n\n    @WorkerThread\n    private void loadPermissions() {\n        synchronized (mPermissionItems) {\n            mPermissionItems.clear();\n            PackageInfo packageInfo = getPackageInfoInternal();\n            if (packageInfo == null) {\n                // No custom permissions\n                mPermissions.postValue(mPermissionItems);\n                return;\n            }\n            Set<String> visitedPerms = new HashSet<>();\n            if (packageInfo.permissions != null) {\n                for (PermissionInfo permissionInfo : packageInfo.permissions) {\n                    AppDetailsDefinedPermissionItem appDetailsItem = new AppDetailsDefinedPermissionItem(permissionInfo, false);\n                    mPermissionItems.add(appDetailsItem);\n                    visitedPerms.add(permissionInfo.name);\n                }\n            }\n            if (packageInfo.activities != null) {\n                for (ActivityInfo activityInfo : packageInfo.activities) {\n                    if (activityInfo.permission != null && !visitedPerms.contains(activityInfo.permission)) {\n                        try {\n                            PermissionInfo permissionInfo = PermissionCompat.getPermissionInfo(activityInfo.permission,\n                                    packageInfo.packageName, PackageManager.GET_META_DATA);\n                            if (permissionInfo == null) {\n                                Log.d(TAG, \"Couldn't fetch info for permission %s\", activityInfo.permission);\n                                permissionInfo = new PermissionInfo();\n                                permissionInfo.name = activityInfo.permission;\n                            }\n                            AppDetailsDefinedPermissionItem appDetailsItem = new AppDetailsDefinedPermissionItem(permissionInfo, true);\n                            mPermissionItems.add(appDetailsItem);\n                            visitedPerms.add(permissionInfo.name);\n                        } catch (RemoteException e) {\n                            e.printStackTrace();\n                        }\n                    }\n                }\n            }\n            if (packageInfo.services != null) {\n                for (ServiceInfo serviceInfo : packageInfo.services) {\n                    if (serviceInfo.permission != null && !visitedPerms.contains(serviceInfo.permission)) {\n                        try {\n                            PermissionInfo permissionInfo = PermissionCompat.getPermissionInfo(serviceInfo.permission,\n                                    packageInfo.packageName, PackageManager.GET_META_DATA);\n                            if (permissionInfo == null) {\n                                Log.d(TAG, \"Couldn't fetch info for permission %s\", serviceInfo.permission);\n                                permissionInfo = new PermissionInfo();\n                                permissionInfo.name = serviceInfo.permission;\n                            }\n                            AppDetailsDefinedPermissionItem appDetailsItem = new AppDetailsDefinedPermissionItem(permissionInfo, true);\n                            mPermissionItems.add(appDetailsItem);\n                            visitedPerms.add(permissionInfo.name);\n                        } catch (RemoteException e) {\n                            e.printStackTrace();\n                        }\n                    }\n                }\n            }\n            if (packageInfo.providers != null) {\n                for (ProviderInfo providerInfo : packageInfo.providers) {\n                    if (providerInfo.readPermission != null && !visitedPerms.contains(providerInfo.readPermission)) {\n                        try {\n                            PermissionInfo permissionInfo = PermissionCompat.getPermissionInfo(providerInfo.readPermission,\n                                    packageInfo.packageName, PackageManager.GET_META_DATA);\n                            if (permissionInfo == null) {\n                                Log.d(TAG, \"Couldn't fetch info for permission %s\", providerInfo.readPermission);\n                                permissionInfo = new PermissionInfo();\n                                permissionInfo.name = providerInfo.readPermission;\n                            }\n                            AppDetailsDefinedPermissionItem appDetailsItem = new AppDetailsDefinedPermissionItem(permissionInfo, true);\n                            mPermissionItems.add(appDetailsItem);\n                            visitedPerms.add(permissionInfo.name);\n                        } catch (RemoteException e) {\n                            e.printStackTrace();\n                        }\n                    }\n                    if (providerInfo.writePermission != null && !visitedPerms.contains(providerInfo.writePermission)) {\n                        try {\n                            PermissionInfo permissionInfo = PermissionCompat.getPermissionInfo(providerInfo.writePermission,\n                                    packageInfo.packageName, PackageManager.GET_META_DATA);\n                            if (permissionInfo == null) {\n                                Log.d(TAG, \"Couldn't fetch info for permission %s\", providerInfo.writePermission);\n                                permissionInfo = new PermissionInfo();\n                                permissionInfo.name = providerInfo.writePermission;\n                            }\n                            AppDetailsDefinedPermissionItem appDetailsItem = new AppDetailsDefinedPermissionItem(permissionInfo, true);\n                            mPermissionItems.add(appDetailsItem);\n                            visitedPerms.add(permissionInfo.name);\n                        } catch (RemoteException e) {\n                            e.printStackTrace();\n                        }\n                    }\n                }\n            }\n            if (packageInfo.receivers != null) {\n                for (ActivityInfo activityInfo : packageInfo.receivers) {\n                    if (activityInfo.permission != null && !visitedPerms.contains(activityInfo.permission)) {\n                        try {\n                            PermissionInfo permissionInfo = PermissionCompat.getPermissionInfo(activityInfo.permission,\n                                    packageInfo.packageName, PackageManager.GET_META_DATA);\n                            if (permissionInfo == null) {\n                                Log.d(TAG, \"Couldn't fetch info for permission %s\", activityInfo.permission);\n                                permissionInfo = new PermissionInfo();\n                                permissionInfo.name = activityInfo.permission;\n                            }\n                            AppDetailsDefinedPermissionItem appDetailsItem = new AppDetailsDefinedPermissionItem(permissionInfo, true);\n                            mPermissionItems.add(appDetailsItem);\n                            visitedPerms.add(permissionInfo.name);\n                        } catch (RemoteException e) {\n                            e.printStackTrace();\n                        }\n                    }\n                }\n            }\n            mPermissions.postValue(filterAndSortPermissions(mPermissionItems));\n        }\n    }\n\n    @NonNull\n    private final MutableLiveData<List<AppDetailsFeatureItem>> mFeatures = new MutableLiveData<>();\n\n    @WorkerThread\n    private void loadFeatures() {\n        List<AppDetailsFeatureItem> appDetailsItems = new ArrayList<>();\n        PackageInfo packageInfo = getPackageInfoInternal();\n        if (packageInfo == null || packageInfo.reqFeatures == null) {\n            // No required features\n            mFeatures.postValue(appDetailsItems);\n            return;\n        }\n        for (FeatureInfo fi : packageInfo.reqFeatures) {\n            if (fi.name == null) fi.name = AppDetailsFeatureItem.OPEN_GL_ES;\n        }\n        for (FeatureInfo featureInfo : packageInfo.reqFeatures) {\n            String name = featureInfo.name;\n            boolean isAvailable;\n            if (name == null) {\n                // At most, only one name could be null\n                name = AppDetailsFeatureItem.OPEN_GL_ES;\n                ActivityManager activityManager = (ActivityManager) getApplication().getSystemService(Context.ACTIVITY_SERVICE);\n                int glEsVersion = activityManager.getDeviceConfigurationInfo().reqGlEsVersion;\n                isAvailable = featureInfo.reqGlEsVersion <= glEsVersion;\n            } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {\n                isAvailable = mPackageManager.hasSystemFeature(featureInfo.name, featureInfo.version);\n            } else {\n                isAvailable = mPackageManager.hasSystemFeature(featureInfo.name);\n            }\n            AppDetailsFeatureItem appDetailsItem = new AppDetailsFeatureItem(featureInfo, isAvailable);\n            appDetailsItems.add(appDetailsItem);\n            appDetailsItem.name = name;\n        }\n        Collections.sort(appDetailsItems, (o1, o2) -> o1.name.compareToIgnoreCase(o2.name));\n        mFeatures.postValue(appDetailsItems);\n    }\n\n    @NonNull\n    private final MutableLiveData<List<AppDetailsItem<ConfigurationInfo>>> mConfigurations = new MutableLiveData<>();\n\n    @WorkerThread\n    private void loadConfigurations() {\n        List<AppDetailsItem<ConfigurationInfo>> appDetailsItems = new ArrayList<>();\n        PackageInfo packageInfo = getPackageInfoInternal();\n        if (packageInfo != null && packageInfo.configPreferences != null) {\n            for (ConfigurationInfo configurationInfo : packageInfo.configPreferences) {\n                AppDetailsItem<ConfigurationInfo> appDetailsItem = new AppDetailsItem<>(configurationInfo);\n                appDetailsItems.add(appDetailsItem);\n            }\n        }\n        mConfigurations.postValue(appDetailsItems);\n    }\n\n    @NonNull\n    private final MutableLiveData<List<AppDetailsItem<X509Certificate>>> mSignatures = new MutableLiveData<>();\n    private ApkVerifier.Result mApkVerifierResult;\n\n    @AnyThread\n    public ApkVerifier.Result getApkVerifierResult() {\n        return mApkVerifierResult;\n    }\n\n    @WorkerThread\n    private void loadSignatures() {\n        List<AppDetailsItem<X509Certificate>> appDetailsItems = new ArrayList<>();\n        PackageInfo packageInfo = getPackageInfoInternal();\n        if (packageInfo == null || mApkFile == null) {\n            mSignatures.postValue(appDetailsItems);\n            return;\n        }\n        try {\n            File idsigFile = mApkFile.getIdsigFile();\n            ApkVerifier.Builder builder = new ApkVerifier.Builder(mApkFile.getBaseEntry().getFile(false))\n                    .setMaxCheckedPlatformVersion(Build.VERSION.SDK_INT);\n            if (idsigFile != null) {\n                builder.setV4SignatureFile(idsigFile);\n            }\n            ApkVerifier apkVerifier = builder.build();\n            mApkVerifierResult = apkVerifier.verify();\n            SignerInfo signerInfo = new SignerInfo(mApkVerifierResult);\n            // Get signer certificates\n            X509Certificate[] certificates = signerInfo.getCurrentSignerCerts();\n            if (certificates != null) {\n                for (X509Certificate certificate : certificates) {\n                    AppDetailsItem<X509Certificate> item = new AppDetailsItem<>(certificate);\n                    item.name = \"Signer Certificate\";\n                    appDetailsItems.add(item);\n                }\n            } else {\n                //noinspection ConstantConditions Null is deliberately set here to get at least one row\n                appDetailsItems.add(new AppDetailsItem<>(null));\n            }\n            // Get source stamp certificate\n            if (mApkVerifierResult.isSourceStampVerified()) {\n                X509Certificate certificate = signerInfo.getSourceStampCert();\n                if (certificate != null) {\n                    AppDetailsItem<X509Certificate> item = new AppDetailsItem<>(certificate);\n                    item.name = \"SourceStamp Certificate\";\n                    appDetailsItems.add(item);\n                }\n            }\n            // Get source lineage certificates\n            certificates = signerInfo.getSignerCertsInLineage();\n            if (certificates != null) {\n                for (X509Certificate certificate : certificates) {\n                    AppDetailsItem<X509Certificate> item = new AppDetailsItem<>(certificate);\n                    item.name = \"Certificate for Lineage\";\n                    appDetailsItems.add(item);\n                }\n            }\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n        mSignatures.postValue(appDetailsItems);\n    }\n\n    @NonNull\n    private final MutableLiveData<List<AppDetailsLibraryItem<?>>> mSharedLibraries = new MutableLiveData<>();\n\n    @WorkerThread\n    private void loadSharedLibraries() {\n        List<AppDetailsLibraryItem<?>> appDetailsItems = new ArrayList<>();\n        PackageInfo packageInfo = getPackageInfoInternal();\n        if (packageInfo == null || mApkFile == null) {\n            mSharedLibraries.postValue(appDetailsItems);\n            return;\n        }\n        // Add shared libraries including the static shared libraries (which are basically APK files)\n        ApplicationInfo info = packageInfo.applicationInfo;\n        if (info.sharedLibraryFiles != null) {\n            for (String sharedLibrary : info.sharedLibraryFiles) {\n                File sharedLib = new File(sharedLibrary);\n                AppDetailsLibraryItem<?> appDetailsItem = null;\n                if (sharedLib.exists() && sharedLib.getName().endsWith(\".apk\")) {\n                    // APK file\n                    PackageInfo packageArchiveInfo = mPackageManager.getPackageArchiveInfo(sharedLibrary, 0);\n                    if (packageArchiveInfo != null) {\n                        appDetailsItem = new AppDetailsLibraryItem<>(packageArchiveInfo);\n                        appDetailsItem.name = packageArchiveInfo.applicationInfo.loadLabel(mPackageManager).toString();\n                        appDetailsItem.type = \"APK\";\n                    }\n                }\n                if (appDetailsItem == null) {\n                    appDetailsItem = new AppDetailsLibraryItem<>(sharedLib);\n                    appDetailsItem.name = sharedLib.getName();\n                    appDetailsItem.type = sharedLibrary.endsWith(\".so\") ? \"SO\" : \"JAR\";\n                }\n                appDetailsItem.path = sharedLib;\n                appDetailsItem.size = sharedLib.length();\n                appDetailsItems.add(appDetailsItem);\n            }\n        }\n        // Add native libraries (shared objects)\n        List<ApkFile.Entry> entries = mApkFile.getEntries();\n        for (ApkFile.Entry entry : entries) {\n            if (entry.type == ApkFile.APK_BASE\n                    || entry.type == ApkFile.APK_SPLIT_FEATURE\n                    || entry.type == ApkFile.APK_SPLIT_ABI\n                    || entry.type == ApkFile.APK_SPLIT_UNKNOWN) {\n                // Scan for .so files\n                NativeLibraries nativeLibraries;\n                try (InputStream is = entry.getInputStream(false)) {\n                    try {\n                        nativeLibraries = new NativeLibraries(is);\n                    } catch (IOException e) {\n                        // Maybe zip error, Try without InputStream\n                        nativeLibraries = new NativeLibraries(entry.getFile(false));\n                    }\n                    for (NativeLibraries.NativeLib nativeLib : nativeLibraries.getLibs()) {\n                        AppDetailsLibraryItem<?> appDetailsItem = new AppDetailsLibraryItem<>(nativeLib);\n                        appDetailsItem.name = nativeLib.getName();\n                        if (nativeLib instanceof NativeLibraries.ElfLib) {\n                            switch (((NativeLibraries.ElfLib) nativeLib).getType()) {\n                                case NativeLibraries.ElfLib.TYPE_DYN:\n                                    appDetailsItem.type = \"SHARED\";\n                                    break;\n                                case NativeLibraries.ElfLib.TYPE_EXEC:\n                                    appDetailsItem.type = \"EXEC\";\n                                    break;\n                                default:\n                                    appDetailsItem.type = \"SO\";\n                            }\n                        } else appDetailsItem.type = \"⚠️\";\n                        appDetailsItems.add(appDetailsItem);\n                    }\n                } catch (Throwable th) {\n                    Log.e(TAG, th);\n                }\n            }\n        }\n        Collections.sort(appDetailsItems, (o1, o2) -> o1.name.compareToIgnoreCase(o2.name));\n        mSharedLibraries.postValue(appDetailsItems);\n    }\n\n    @NonNull\n    private final MutableLiveData<List<AppDetailsOverlayItem>> mOverlays = new MutableLiveData<>();\n\n    @WorkerThread\n    private void loadOverlays() {\n        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O || mPackageName == null || mExternalApk\n                || !SelfPermissions.checkSelfOrRemotePermission(ManifestCompat.permission.CHANGE_OVERLAY_PACKAGES)) {\n            mOverlays.postValue(Collections.emptyList());\n            return;\n        }\n        final List<OverlayInfo> overlays = ExUtils.requireNonNullElse(() -> OverlayManagerCompact\n                        .getOverlayManager().getOverlayInfosForTarget(mPackageName, mUserId),\n                Collections.emptyList());\n        List<AppDetailsOverlayItem> overlayItems = new ArrayList<>(overlays.size());\n        for (OverlayInfo overlay : overlays) {\n            overlayItems.add(new AppDetailsOverlayItem(overlay));\n        }\n        mOverlays.postValue(overlayItems);\n    }\n\n    /**\n     * Helper class to look for interesting changes to the installed apps\n     * so that the loader can be updated.\n     */\n    public static class PackageIntentReceiver extends PackageChangeReceiver {\n        final AppDetailsViewModel mModel;\n        volatile boolean mPauseWatcher = false;\n        int mChangeCount = 0;\n\n        public PackageIntentReceiver(@NonNull AppDetailsViewModel model) {\n            super(model.getApplication());\n            mModel = model;\n        }\n\n        public void resumeWatcher() {\n            if (mChangeCount > 0) {\n                mChangeCount = 0;\n                mModel.setPackageChanged();\n            }\n            mPauseWatcher = false;\n        }\n\n        public void pauseWatcher() {\n            mChangeCount = 0;\n            mPauseWatcher = true;\n        }\n\n        @Override\n        @WorkerThread\n        protected void onPackageChanged(Intent intent, @Nullable Integer uid, @Nullable String[] packages) {\n            boolean packageChanged = false;\n            if (uid != null) {\n                if (mModel.mPackageInfo != null && mModel.mPackageInfo.applicationInfo.uid == uid) {\n                    Log.d(TAG, \"Package is changed.\");\n                    packageChanged = true;\n                }\n            } else if (packages != null) {\n                for (String packageName : packages) {\n                    if (packageName.equals(mModel.mPackageName)) {\n                        Log.d(TAG, \"Package availability changed.\");\n                        packageChanged = true;\n                        break;\n                    }\n                }\n            }\n            if (packageChanged) {\n                if (mPauseWatcher) {\n                    ++mChangeCount;\n                } else mModel.setPackageChanged();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/details/IconPickerDialogFragment.java",
    "content": "// SPDX-License-Identifier: ISC AND GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.details;\n\nimport android.app.Application;\nimport android.app.Dialog;\nimport android.content.Context;\nimport android.content.pm.PackageInfo;\nimport android.content.pm.PackageItemInfo;\nimport android.content.pm.PackageManager;\nimport android.graphics.drawable.Drawable;\nimport android.os.Bundle;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.AbsListView;\nimport android.widget.BaseAdapter;\nimport android.widget.GridView;\nimport android.widget.ImageView;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.appcompat.widget.AppCompatImageView;\nimport androidx.fragment.app.DialogFragment;\nimport androidx.fragment.app.FragmentActivity;\nimport androidx.lifecycle.AndroidViewModel;\nimport androidx.lifecycle.LiveData;\nimport androidx.lifecycle.MutableLiveData;\nimport androidx.lifecycle.ViewModelProvider;\n\nimport com.google.android.material.dialog.MaterialAlertDialogBuilder;\n\nimport java.util.List;\nimport java.util.TreeSet;\nimport java.util.concurrent.Future;\n\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.self.imagecache.ImageLoader;\nimport io.github.muntashirakon.AppManager.utils.ResourceUtil;\nimport io.github.muntashirakon.AppManager.utils.ThreadUtils;\n\n// Copyright 2017 Adam M. Szalkowski\npublic class IconPickerDialogFragment extends DialogFragment {\n    public static final String TAG = \"IconPickerDialogFragment\";\n\n    private IconPickerListener mListener;\n    private IconListingAdapter mAdapter;\n    private IconPickerViewModel mModel;\n\n    public void attachIconPickerListener(IconPickerListener listener) {\n        mListener = listener;\n    }\n\n    @Override\n    public void onCreate(@Nullable Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        mModel = new ViewModelProvider(this).get(IconPickerViewModel.class);\n        mModel.getIconsLiveData().observe(this, icons -> {\n            if (mAdapter == null) return;\n            mAdapter.mIcons = icons;\n            mAdapter.notifyDataSetChanged();\n        });\n    }\n\n    @NonNull\n    @Override\n    public Dialog onCreateDialog(Bundle savedInstanceState) {\n        mAdapter = new IconListingAdapter(requireActivity());\n        GridView grid = (GridView) View.inflate(requireActivity(), R.layout.dialog_icon_picker, null);\n        grid.setAdapter(mAdapter);\n        grid.setOnItemClickListener((view, item, index, id) -> {\n            if (mListener != null) {\n                mListener.iconPicked((IconItemInfo) view.getAdapter().getItem(index));\n                if (getDialog() != null) getDialog().dismiss();\n            }\n        });\n        mModel.resolveIcons();\n        return new MaterialAlertDialogBuilder(requireActivity())\n                .setTitle(R.string.icon_picker)\n                .setView(grid)\n                .setNegativeButton(R.string.cancel, null).create();\n    }\n\n    public interface IconPickerListener {\n        void iconPicked(PackageItemInfo icon);\n    }\n\n    static class IconListingAdapter extends BaseAdapter {\n        private IconItemInfo[] mIcons;\n        private final FragmentActivity mActivity;\n\n        public IconListingAdapter(@NonNull FragmentActivity activity) {\n            mActivity = activity;\n        }\n\n        @Override\n        public int getCount() {\n            return mIcons == null ? 0 : mIcons.length;\n        }\n\n        @Override\n        public Object getItem(int position) {\n            return mIcons[position];\n        }\n\n        @Override\n        public long getItemId(int position) {\n            return 0;\n        }\n\n        @Override\n        public View getView(int position, View convertView, ViewGroup parent) {\n            ImageView view;\n            if (convertView == null) {\n                view = (ImageView) (convertView = new AppCompatImageView(mActivity));\n                int size = mActivity.getResources().getDimensionPixelSize(R.dimen.icon_size);\n                convertView.setLayoutParams(new AbsListView.LayoutParams(size, size));\n            } else {\n                view = (ImageView) convertView;\n            }\n            IconItemInfo info = mIcons[position];\n            view.setTag(info.packageName);\n            ImageLoader.getInstance().displayImage(info.packageName, info, view);\n            return convertView;\n        }\n    }\n\n    public static class IconPickerViewModel extends AndroidViewModel {\n        private final PackageManager mPm;\n        private final MutableLiveData<IconItemInfo[]> mIconsLiveData = new MutableLiveData<>();\n\n        @Nullable\n        private Future<?> mIconLoaderResult;\n\n        public IconPickerViewModel(@NonNull Application application) {\n            super(application);\n            mPm = application.getPackageManager();\n        }\n\n        @Override\n        protected void onCleared() {\n            if (mIconLoaderResult != null) {\n                mIconLoaderResult.cancel(true);\n            }\n            super.onCleared();\n        }\n\n        public LiveData<IconItemInfo[]> getIconsLiveData() {\n            return mIconsLiveData;\n        }\n\n        public void resolveIcons() {\n            if (mIconLoaderResult != null) {\n                mIconLoaderResult.cancel(true);\n            }\n            mIconLoaderResult = ThreadUtils.postOnBackgroundThread(() -> {\n                TreeSet<IconItemInfo> icons = new TreeSet<>();\n                List<PackageInfo> installedPackages = mPm.getInstalledPackages(0);\n\n                for (PackageInfo pack : installedPackages) {\n                    try {\n                        String iconResourceName = mPm.getResourcesForApplication(pack.packageName)\n                                .getResourceName(pack.applicationInfo.icon);\n                        if (iconResourceName != null) {\n                            icons.add(new IconItemInfo(getApplication(), pack.packageName, iconResourceName));\n                        }\n                    } catch (PackageManager.NameNotFoundException | RuntimeException ignored) {\n                    }\n                    if (ThreadUtils.isInterrupted()) {\n                        return;\n                    }\n                }\n                mIconsLiveData.postValue(icons.toArray(new IconItemInfo[0]));\n            });\n        }\n    }\n\n    private static class IconItemInfo extends PackageItemInfo implements Comparable<IconItemInfo> {\n        private final String mIconResourceString;\n        private final Context mContext;\n\n        public IconItemInfo(Context context, String packageName, String iconResourceString) {\n            mContext = context;\n            this.packageName = packageName;\n            this.name = mIconResourceString = iconResourceString;\n        }\n\n        @Override\n        public Drawable loadIcon(@NonNull PackageManager pm) {\n            try {\n                Drawable drawable = ResourceUtil.getResourceFromName(pm, mIconResourceString).getDrawable(mContext.getTheme());\n                if (drawable != null) {\n                    return drawable;\n                }\n            } catch (Exception ignore) {\n            }\n            return pm.getDefaultActivityIcon();\n        }\n\n        @Override\n        public int compareTo(@NonNull IconItemInfo o) {\n            return mIconResourceString.compareTo(o.mIconResourceString);\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/details/PackageItemShortcutInfo.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.details;\n\nimport android.annotation.UserIdInt;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.pm.ActivityInfo;\nimport android.content.pm.PackageItemInfo;\nimport android.os.Parcel;\nimport android.os.Parcelable;\nimport android.os.UserHandleHidden;\n\nimport androidx.annotation.NonNull;\nimport androidx.core.os.ParcelCompat;\n\nimport java.util.Objects;\n\nimport io.github.muntashirakon.AppManager.BuildConfig;\nimport io.github.muntashirakon.AppManager.shortcut.ShortcutInfo;\n\n@SuppressWarnings(\"rawtypes\")\npublic class PackageItemShortcutInfo<T extends PackageItemInfo & Parcelable> extends ShortcutInfo {\n    private final T mPackageItemInfo;\n    private final Class<T> mClazz;\n    @UserIdInt\n    private final int mUserId;\n    private final boolean mLaunchViaAssist;\n\n    public PackageItemShortcutInfo(@NonNull T packageItemInfo, @NonNull Class<T> clazz, @UserIdInt int userId) {\n        this(packageItemInfo, clazz, userId, false);\n    }\n\n    public PackageItemShortcutInfo(@NonNull T packageItemInfo, @NonNull Class<T> clazz, @UserIdInt int userId, boolean launchViaAssist) {\n        mPackageItemInfo = packageItemInfo;\n        mClazz = clazz;\n        mUserId = userId;\n        if (packageItemInfo instanceof ActivityInfo) {\n            mLaunchViaAssist = launchViaAssist;\n        } else mLaunchViaAssist = false;\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public PackageItemShortcutInfo(Parcel in) {\n        super(in);\n        mClazz = (Class<T>) Objects.requireNonNull(ParcelCompat.readSerializable(in, Class.class.getClassLoader(), Class.class));\n        mPackageItemInfo = ParcelCompat.readParcelable(in, mClazz.getClassLoader(), mClazz);\n        mUserId = in.readInt();\n        mLaunchViaAssist = ParcelCompat.readBoolean(in);\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        super.writeToParcel(dest, flags);\n        dest.writeSerializable(mClazz);\n        dest.writeParcelable(mPackageItemInfo, flags);\n        dest.writeInt(mUserId);\n        ParcelCompat.writeBoolean(dest, mLaunchViaAssist);\n    }\n\n    @Override\n    public Intent toShortcutIntent(@NonNull Context context) {\n        return requireProxy() ? getProxyIntent(context) : getIntent();\n    }\n\n    public static final Creator<PackageItemShortcutInfo> CREATOR = new Creator<PackageItemShortcutInfo>() {\n        @Override\n        public PackageItemShortcutInfo createFromParcel(Parcel source) {\n            return new PackageItemShortcutInfo(source);\n        }\n\n        @Override\n        public PackageItemShortcutInfo[] newArray(int size) {\n            return new PackageItemShortcutInfo[size];\n        }\n    };\n\n\n    @NonNull\n    private Intent getIntent() {\n        Intent intent = new Intent();\n        intent.setClassName(mPackageItemInfo.packageName, mPackageItemInfo.name);\n        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);\n        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);\n        return intent;\n    }\n\n    @NonNull\n    private Intent getProxyIntent(@NonNull Context context) {\n        return ActivityLauncherShortcutActivity.getShortcutIntent(context, mPackageItemInfo.packageName,\n                mPackageItemInfo.name, mUserId, mLaunchViaAssist);\n    }\n\n    private boolean requireProxy() {\n        return !BuildConfig.APPLICATION_ID.equals(mPackageItemInfo.packageName) || mUserId != UserHandleHidden.myUserId();\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/details/info/ActionItem.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.details.info;\n\nimport android.content.Context;\nimport android.content.res.ColorStateList;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\n\nimport androidx.annotation.DrawableRes;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.StringRes;\n\nimport com.google.android.material.button.MaterialButton;\n\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.utils.appearance.ColorCodes;\n\nclass ActionItem {\n    @StringRes\n    private final int mTitleRes;\n    @DrawableRes\n    private final int mIconRes;\n    private View.OnClickListener mOnClickListener;\n    private View.OnLongClickListener mOnLongClickListener;\n\n    public ActionItem(@StringRes int titleRes, @DrawableRes int iconRes) {\n        mTitleRes = titleRes;\n        mIconRes = iconRes;\n    }\n\n    public ActionItem setOnClickListener(View.OnClickListener clickListener) {\n        mOnClickListener = clickListener;\n        return this;\n    }\n\n    public ActionItem setOnLongClickListener(View.OnLongClickListener longClickListener) {\n        mOnLongClickListener = longClickListener;\n        return this;\n    }\n\n    public MaterialButton toActionButton(@NonNull Context context, @NonNull ViewGroup parent) {\n        MaterialButton button = (MaterialButton) LayoutInflater.from(context).inflate(R.layout.item_app_info_action, parent, false);\n        button.setBackgroundTintList(ColorStateList.valueOf(ColorCodes.getListItemColor1(context)));\n        button.setText(mTitleRes);\n        button.setIconResource(mIconRes);\n        if (mOnClickListener != null) {\n            button.setOnClickListener(mOnClickListener);\n        }\n        if (mOnLongClickListener != null) {\n            button.setOnLongClickListener(mOnLongClickListener);\n        }\n        return button;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/details/info/AppInfoFragment.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.details.info;\n\nimport static io.github.muntashirakon.AppManager.compat.ApplicationInfoCompat.HIDDEN_API_ENFORCEMENT_BLACK;\nimport static io.github.muntashirakon.AppManager.compat.ApplicationInfoCompat.HIDDEN_API_ENFORCEMENT_DEFAULT;\nimport static io.github.muntashirakon.AppManager.compat.ApplicationInfoCompat.HIDDEN_API_ENFORCEMENT_DISABLED;\nimport static io.github.muntashirakon.AppManager.compat.ApplicationInfoCompat.HIDDEN_API_ENFORCEMENT_ENABLED;\nimport static io.github.muntashirakon.AppManager.compat.ApplicationInfoCompat.HIDDEN_API_ENFORCEMENT_JUST_WARN;\nimport static io.github.muntashirakon.AppManager.compat.ManifestCompat.permission.TERMUX_RUN_COMMAND;\nimport static io.github.muntashirakon.AppManager.utils.UIUtils.displayLongToast;\nimport static io.github.muntashirakon.AppManager.utils.UIUtils.displayShortToast;\nimport static io.github.muntashirakon.AppManager.utils.UIUtils.getBitmapFromDrawable;\nimport static io.github.muntashirakon.AppManager.utils.UIUtils.getColoredText;\nimport static io.github.muntashirakon.AppManager.utils.UIUtils.getDimmedBitmap;\nimport static io.github.muntashirakon.AppManager.utils.UIUtils.getSmallerText;\nimport static io.github.muntashirakon.AppManager.utils.UIUtils.getStyledKeyValue;\nimport static io.github.muntashirakon.AppManager.utils.UIUtils.getTitleText;\nimport static io.github.muntashirakon.AppManager.utils.Utils.openAsFolderInFM;\n\nimport android.Manifest;\nimport android.app.ActivityManager;\nimport android.content.ComponentName;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.pm.ApplicationInfo;\nimport android.content.pm.PackageInfo;\nimport android.content.pm.PackageManager;\nimport android.content.pm.ResolveInfo;\nimport android.graphics.Bitmap;\nimport android.net.Uri;\nimport android.os.Build;\nimport android.os.Bundle;\nimport android.os.UserHandleHidden;\nimport android.provider.Settings;\nimport android.text.Spannable;\nimport android.text.SpannableStringBuilder;\nimport android.text.format.Formatter;\nimport android.util.Pair;\nimport android.view.LayoutInflater;\nimport android.view.Menu;\nimport android.view.MenuInflater;\nimport android.view.MenuItem;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.webkit.MimeTypeMap;\nimport android.widget.ImageView;\nimport android.widget.TextView;\n\nimport androidx.activity.result.ActivityResult;\nimport androidx.activity.result.contract.ActivityResultContracts;\nimport androidx.annotation.GuardedBy;\nimport androidx.annotation.MainThread;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.UiThread;\nimport androidx.annotation.WorkerThread;\nimport androidx.collection.ArrayMap;\nimport androidx.core.app.ActivityCompat;\nimport androidx.core.content.ContextCompat;\nimport androidx.core.content.pm.PackageInfoCompat;\nimport androidx.core.view.MenuProvider;\nimport androidx.fragment.app.Fragment;\nimport androidx.lifecycle.Lifecycle;\nimport androidx.lifecycle.ViewModelProvider;\nimport androidx.recyclerview.widget.LinearLayoutManager;\nimport androidx.recyclerview.widget.RecyclerView;\n\nimport com.google.android.material.checkbox.MaterialCheckBox;\nimport com.google.android.material.dialog.MaterialAlertDialogBuilder;\nimport com.google.android.material.progressindicator.LinearProgressIndicator;\n\nimport java.io.File;\nimport java.io.FileNotFoundException;\nimport java.io.IOException;\nimport java.io.OutputStream;\nimport java.security.cert.CertificateEncodingException;\nimport java.security.cert.X509Certificate;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Objects;\nimport java.util.Optional;\nimport java.util.concurrent.Future;\n\nimport io.github.muntashirakon.AppManager.BuildConfig;\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.accessibility.AccessibilityMultiplexer;\nimport io.github.muntashirakon.AppManager.accessibility.NoRootAccessibilityService;\nimport io.github.muntashirakon.AppManager.apk.ApkFile;\nimport io.github.muntashirakon.AppManager.apk.ApkSource;\nimport io.github.muntashirakon.AppManager.apk.ApkUtils;\nimport io.github.muntashirakon.AppManager.apk.behavior.FreezeUnfreeze;\nimport io.github.muntashirakon.AppManager.apk.dexopt.DexOptDialog;\nimport io.github.muntashirakon.AppManager.apk.behavior.FreezeUnfreezeShortcutInfo;\nimport io.github.muntashirakon.AppManager.apk.installer.PackageInstallerActivity;\nimport io.github.muntashirakon.AppManager.apk.installer.PackageInstallerCompat;\nimport io.github.muntashirakon.AppManager.apk.signing.SignerInfo;\nimport io.github.muntashirakon.AppManager.apk.whatsnew.WhatsNewDialogFragment;\nimport io.github.muntashirakon.AppManager.backup.dialog.BackupRestoreDialogFragment;\nimport io.github.muntashirakon.AppManager.batchops.BatchOpsManager;\nimport io.github.muntashirakon.AppManager.batchops.BatchOpsService;\nimport io.github.muntashirakon.AppManager.batchops.BatchQueueItem;\nimport io.github.muntashirakon.AppManager.compat.ActivityManagerCompat;\nimport io.github.muntashirakon.AppManager.compat.ApplicationInfoCompat;\nimport io.github.muntashirakon.AppManager.compat.DeviceIdleManagerCompat;\nimport io.github.muntashirakon.AppManager.compat.DomainVerificationManagerCompat;\nimport io.github.muntashirakon.AppManager.compat.InstallSourceInfoCompat;\nimport io.github.muntashirakon.AppManager.compat.ManifestCompat;\nimport io.github.muntashirakon.AppManager.compat.NetworkPolicyManagerCompat;\nimport io.github.muntashirakon.AppManager.compat.PackageInfoCompat2;\nimport io.github.muntashirakon.AppManager.compat.PackageManagerCompat;\nimport io.github.muntashirakon.AppManager.compat.SensorServiceCompat;\nimport io.github.muntashirakon.AppManager.debloat.BloatwareDetailsDialog;\nimport io.github.muntashirakon.AppManager.details.AppDetailsActivity;\nimport io.github.muntashirakon.AppManager.details.AppDetailsFragment;\nimport io.github.muntashirakon.AppManager.details.AppDetailsViewModel;\nimport io.github.muntashirakon.AppManager.details.manifest.ManifestViewerActivity;\nimport io.github.muntashirakon.AppManager.details.struct.AppDetailsItem;\nimport io.github.muntashirakon.AppManager.fm.FmProvider;\nimport io.github.muntashirakon.AppManager.fm.dialogs.OpenWithDialogFragment;\nimport io.github.muntashirakon.AppManager.logcat.LogViewerActivity;\nimport io.github.muntashirakon.AppManager.logcat.helper.ServiceHelper;\nimport io.github.muntashirakon.AppManager.logcat.struct.SearchCriteria;\nimport io.github.muntashirakon.AppManager.logs.Log;\nimport io.github.muntashirakon.AppManager.magisk.MagiskDenyList;\nimport io.github.muntashirakon.AppManager.magisk.MagiskHide;\nimport io.github.muntashirakon.AppManager.magisk.MagiskProcess;\nimport io.github.muntashirakon.AppManager.profiles.AddToProfileDialogFragment;\nimport io.github.muntashirakon.AppManager.rules.RulesTypeSelectionDialogFragment;\nimport io.github.muntashirakon.AppManager.rules.compontents.ComponentsBlocker;\nimport io.github.muntashirakon.AppManager.rules.struct.ComponentRule;\nimport io.github.muntashirakon.AppManager.runner.Runner;\nimport io.github.muntashirakon.AppManager.runner.RunnerUtils;\nimport io.github.muntashirakon.AppManager.scanner.ScannerActivity;\nimport io.github.muntashirakon.AppManager.self.SelfPermissions;\nimport io.github.muntashirakon.AppManager.self.imagecache.ImageLoader;\nimport io.github.muntashirakon.AppManager.settings.FeatureController;\nimport io.github.muntashirakon.AppManager.settings.Prefs;\nimport io.github.muntashirakon.AppManager.sharedpref.SharedPrefsActivity;\nimport io.github.muntashirakon.AppManager.shortcut.CreateShortcutDialogFragment;\nimport io.github.muntashirakon.AppManager.ssaid.ChangeSsaidDialog;\nimport io.github.muntashirakon.AppManager.types.PackageSizeInfo;\nimport io.github.muntashirakon.AppManager.types.UserPackagePair;\nimport io.github.muntashirakon.AppManager.uri.GrantUriUtils;\nimport io.github.muntashirakon.AppManager.usage.AppUsageStatsManager;\nimport io.github.muntashirakon.AppManager.users.UserInfo;\nimport io.github.muntashirakon.AppManager.users.Users;\nimport io.github.muntashirakon.AppManager.utils.ArrayUtils;\nimport io.github.muntashirakon.AppManager.utils.BetterActivityResult;\nimport io.github.muntashirakon.AppManager.utils.ClipboardUtils;\nimport io.github.muntashirakon.AppManager.utils.ContextUtils;\nimport io.github.muntashirakon.AppManager.utils.DateUtils;\nimport io.github.muntashirakon.AppManager.utils.DigestUtils;\nimport io.github.muntashirakon.AppManager.utils.ExUtils;\nimport io.github.muntashirakon.AppManager.utils.FreezeUtils;\nimport io.github.muntashirakon.AppManager.utils.IntentUtils;\nimport io.github.muntashirakon.AppManager.utils.KeyStoreUtils;\nimport io.github.muntashirakon.AppManager.utils.LangUtils;\nimport io.github.muntashirakon.AppManager.utils.PackageUtils;\nimport io.github.muntashirakon.AppManager.utils.ThreadUtils;\nimport io.github.muntashirakon.AppManager.utils.UIUtils;\nimport io.github.muntashirakon.AppManager.utils.Utils;\nimport io.github.muntashirakon.AppManager.utils.appearance.ColorCodes;\nimport io.github.muntashirakon.dialog.DialogTitleBuilder;\nimport io.github.muntashirakon.dialog.ScrollableDialogBuilder;\nimport io.github.muntashirakon.dialog.SearchableFlagsDialogBuilder;\nimport io.github.muntashirakon.dialog.SearchableItemsDialogBuilder;\nimport io.github.muntashirakon.dialog.SearchableMultiChoiceDialogBuilder;\nimport io.github.muntashirakon.io.Path;\nimport io.github.muntashirakon.io.Paths;\nimport io.github.muntashirakon.widget.SwipeRefreshLayout;\n\npublic class AppInfoFragment extends Fragment implements SwipeRefreshLayout.OnRefreshListener, MenuProvider {\n    public static final String TAG = \"AppInfoFragment\";\n\n    private static final String PACKAGE_NAME_AURORA_STORE = \"com.aurora.store\";\n\n    private PackageManager mPackageManager;\n    private String mPackageName;\n    private int mUserId;\n    @Nullable\n    private String mInstallerPackageName;\n    private PackageInfo mPackageInfo;\n    @Nullable\n    private PackageInfo mInstalledPackageInfo;\n    private AppDetailsActivity mActivity;\n    private ApplicationInfo mApplicationInfo;\n    private ViewGroup mHorizontalLayout;\n    private ViewGroup mTagCloud;\n    private SwipeRefreshLayout mSwipeRefresh;\n    private CharSequence mAppLabel;\n    private LinearProgressIndicator mProgressIndicator;\n    private AppDetailsViewModel mMainModel;\n    private AppInfoViewModel mAppInfoModel;\n    private AppInfoRecyclerAdapter mAdapter;\n    // Headers\n    private TextView mLabelView;\n    private TextView mPackageNameView;\n    private TextView mVersionView;\n    private ImageView mIconView;\n    private List<MagiskProcess> mMagiskHiddenProcesses;\n    private List<MagiskProcess> mMagiskDeniedProcesses;\n    private Future<?> mTagCloudFuture;\n    private Future<?> mActionsFuture;\n    private Future<?> mListFuture;\n    private Future<?> mMenuPreparationResult;\n\n    private boolean mIsExternalApk;\n    private int mLoadedItemCount;\n\n    @GuardedBy(\"mListItems\")\n    private final List<ListItem> mListItems = new ArrayList<>();\n    private final BetterActivityResult<String, Uri> mExport = BetterActivityResult\n            .registerForActivityResult(this, new ActivityResultContracts.CreateDocument(\"*/*\"));\n    private final BetterActivityResult<String, Boolean> mRequestPerm = BetterActivityResult\n            .registerForActivityResult(this, new ActivityResultContracts.RequestPermission());\n    private final BetterActivityResult<Intent, ActivityResult> mActivityLauncher = BetterActivityResult\n            .registerActivityForResult(this);\n\n    @Override\n    public void onCreate(@Nullable Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        mAppInfoModel = new ViewModelProvider(this).get(AppInfoViewModel.class);\n        mMainModel = new ViewModelProvider(requireActivity()).get(AppDetailsViewModel.class);\n    }\n\n    @Nullable\n    @Override\n    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {\n        return inflater.inflate(R.layout.pager_app_info, container, false);\n    }\n\n    @Override\n    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {\n        super.onViewCreated(view, savedInstanceState);\n        mActivity = (AppDetailsActivity) requireActivity();\n        mAppInfoModel.setMainModel(mMainModel);\n        mPackageManager = mActivity.getPackageManager();\n        // Swipe refresh\n        mSwipeRefresh = view.findViewById(R.id.swipe_refresh);\n        mSwipeRefresh.setOnRefreshListener(this);\n        // Recycler view\n        RecyclerView recyclerView = view.findViewById(android.R.id.list);\n        recyclerView.setLayoutManager(new LinearLayoutManager(mActivity));\n        // Horizontal view\n        mHorizontalLayout = view.findViewById(R.id.horizontal_layout);\n        // Progress indicator\n        mProgressIndicator = view.findViewById(R.id.progress_linear);\n        mProgressIndicator.setVisibilityAfterHide(View.GONE);\n        showProgressIndicator(true);\n        // Header\n        mTagCloud = view.findViewById(R.id.tag_cloud);\n        mLabelView = view.findViewById(R.id.label);\n        mPackageNameView = view.findViewById(R.id.packageName);\n        mIconView = view.findViewById(R.id.icon);\n        mVersionView = view.findViewById(R.id.version);\n        mAdapter = new AppInfoRecyclerAdapter(requireContext());\n        recyclerView.setAdapter(mAdapter);\n        mActivity.addMenuProvider(this, getViewLifecycleOwner(), Lifecycle.State.RESUMED);\n        // Set observer\n        mMainModel.get(AppDetailsFragment.APP_INFO).observe(getViewLifecycleOwner(), appDetailsItems -> {\n            mLoadedItemCount = 0;\n            if (appDetailsItems == null || appDetailsItems.isEmpty() || !mMainModel.isPackageExist()) {\n                showProgressIndicator(false);\n                return;\n            }\n            ++mLoadedItemCount;\n            AppDetailsItem<?> appDetailsItem = appDetailsItems.get(0);\n            mPackageInfo = (PackageInfo) appDetailsItem.item;\n            mApplicationInfo = mPackageInfo.applicationInfo;\n            mPackageName = appDetailsItem.name;\n            mUserId = mMainModel.getUserId();\n            mInstalledPackageInfo = mMainModel.getInstalledPackageInfo();\n            mIsExternalApk = mMainModel.isExternalApk();\n            if (!mIsExternalApk) {\n                mInstallerPackageName = PackageManagerCompat.getInstallerPackageName(mPackageName, mUserId);\n            }\n            // Set icon\n            ImageLoader.getInstance().displayImage(mPackageName, mApplicationInfo, mIconView);\n            // Set package name\n            mPackageNameView.setText(mPackageName);\n            mPackageNameView.setOnClickListener(v ->\n                    Utils.copyToClipboard(ContextUtils.getContext(), \"Package name\", mPackageName));\n            // Set App Version\n            CharSequence version = getString(R.string.version_name_with_code, mPackageInfo.versionName, PackageInfoCompat.getLongVersionCode(mPackageInfo));\n            mVersionView.setText(version);\n            // Load app label\n            mAppInfoModel.loadAppLabel(mApplicationInfo);\n            // Load tag cloud\n            mAppInfoModel.loadTagCloud(mPackageInfo, mIsExternalApk);\n            // Load horizontal actions\n            setupHorizontalActions();\n            // Load other info\n            mAppInfoModel.loadAppInfo(mPackageInfo, mIsExternalApk);\n        });\n        mAppInfoModel.getAppLabel().observe(getViewLifecycleOwner(), appLabel -> {\n            ++mLoadedItemCount;\n            if (mLoadedItemCount >= 4) {\n                showProgressIndicator(false);\n            }\n            mAppLabel = appLabel;\n            // Set Application Name, aka Label\n            mLabelView.setText(mAppLabel);\n        });\n        mMainModel.getFreezeTypeLiveData().observe(getViewLifecycleOwner(), freezeType -> {\n            int freezeTypeN = Optional.ofNullable(freezeType)\n                    .orElse(Prefs.Blocking.getDefaultFreezingMethod());\n            showFreezeDialog(freezeTypeN, freezeType != null);\n        });\n        mIconView.setOnClickListener(v -> {\n            ThreadUtils.postOnBackgroundThread(() -> {\n                String data = ClipboardUtils.readHashValueFromClipboard(ContextUtils.getContext());\n                if (data != null) {\n                    SignerInfo signerInfo = PackageUtils.getSignerInfo(mPackageInfo, mIsExternalApk);\n                    if (signerInfo != null) {\n                        X509Certificate[] certs = signerInfo.getCurrentSignerCerts();\n                        if (certs != null && certs.length == 1) {\n                            try {\n                                Pair<String, String>[] digests = DigestUtils.getDigests(certs[0].getEncoded());\n                                for (Pair<String, String> digest : digests) {\n                                    if (digest.second.equals(data)) {\n                                        if (digest.first.equals(DigestUtils.MD5) || digest.first.equals(DigestUtils.SHA_1)) {\n                                            ThreadUtils.postOnMainThread(() -> displayLongToast(R.string.verified_using_unreliable_hash));\n                                        } else\n                                            ThreadUtils.postOnMainThread(() -> displayLongToast(R.string.verified));\n                                        return;\n                                    }\n                                }\n                            } catch (CertificateEncodingException ignore) {\n                            }\n                        }\n                    }\n                    ThreadUtils.postOnMainThread(() -> displayLongToast(R.string.not_verified));\n                }\n            });\n        });\n        mAppInfoModel.getTagCloud().observe(getViewLifecycleOwner(), this::setupTagCloud);\n        mAppInfoModel.getAppInfo().observe(getViewLifecycleOwner(), this::setupVerticalView);\n        mAppInfoModel.getInstallExistingResult().observe(getViewLifecycleOwner(), statusMessagePair ->\n                new MaterialAlertDialogBuilder(requireActivity())\n                        .setTitle(mAppLabel)\n                        .setIcon(mApplicationInfo.loadIcon(mPackageManager))\n                        .setMessage(statusMessagePair.second)\n                        .setNegativeButton(R.string.close, null)\n                        .show());\n        mMainModel.getTagsAlteredLiveData().observe(getViewLifecycleOwner(), altered -> {\n            // Reload tag cloud\n            mAppInfoModel.loadTagCloud(mPackageInfo, mIsExternalApk);\n        });\n    }\n\n    @Override\n    public void onCreateMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) {\n        if (mMainModel != null && !mMainModel.isExternalApk()) {\n            inflater.inflate(R.menu.fragment_app_info_actions, menu);\n        }\n    }\n\n    @Override\n    public void onPrepareMenu(@NonNull Menu menu) {\n        if (mIsExternalApk) return;\n        MenuItem magiskHideMenu = menu.findItem(R.id.action_magisk_hide);\n        MenuItem magiskDenyListMenu = menu.findItem(R.id.action_magisk_denylist);\n        MenuItem openInTermuxMenu = menu.findItem(R.id.action_open_in_termux);\n        MenuItem runInTermuxMenu = menu.findItem(R.id.action_run_in_termux);\n        MenuItem batteryOptMenu = menu.findItem(R.id.action_battery_opt);\n        MenuItem sensorsMenu = menu.findItem(R.id.action_sensor);\n        MenuItem netPolicyMenu = menu.findItem(R.id.action_net_policy);\n        MenuItem installMenu = menu.findItem(R.id.action_install);\n        MenuItem optimizeMenu = menu.findItem(R.id.action_optimize);\n        mMenuPreparationResult = ThreadUtils.postOnBackgroundThread(() -> {\n            boolean magiskHideAvailable = MagiskHide.available();\n            boolean magiskDenyListAvailable = MagiskDenyList.available();\n            boolean rootAvailable = RunnerUtils.isRootAvailable();\n            if (ThreadUtils.isInterrupted()) {\n                return;\n            }\n            ThreadUtils.postOnMainThread(() -> {\n                if (magiskHideMenu != null) {\n                    magiskHideMenu.setVisible(magiskHideAvailable);\n                }\n                if (magiskDenyListMenu != null) {\n                    magiskDenyListMenu.setVisible(magiskDenyListAvailable);\n                }\n                if (openInTermuxMenu != null) {\n                    openInTermuxMenu.setVisible(rootAvailable);\n                }\n            });\n        });\n        boolean isDebuggable;\n        if (mApplicationInfo != null) {\n            isDebuggable = (mApplicationInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;\n        } else isDebuggable = false;\n        if (runInTermuxMenu != null) {\n            runInTermuxMenu.setVisible(isDebuggable);\n        }\n        if (batteryOptMenu != null) {\n            batteryOptMenu.setVisible(Build.VERSION.SDK_INT >= Build.VERSION_CODES.M);\n        }\n        if (sensorsMenu != null) {\n            sensorsMenu.setVisible(Build.VERSION.SDK_INT >= Build.VERSION_CODES.P\n                    && SelfPermissions.checkSelfOrRemotePermission(ManifestCompat.permission.MANAGE_SENSORS));\n        }\n        if (netPolicyMenu != null) {\n            netPolicyMenu.setVisible(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N);\n        }\n        if (installMenu != null) {\n            installMenu.setVisible(Users.getUsersIds().length > 1 && SelfPermissions.canInstallExistingPackages());\n        }\n        if (optimizeMenu != null) {\n            optimizeMenu.setVisible(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N\n                    && (SelfPermissions.isSystemOrRootOrShell() || BuildConfig.APPLICATION_ID.equals(mInstallerPackageName)));\n        }\n    }\n\n    @Override\n    public boolean onMenuItemSelected(@NonNull MenuItem item) {\n        int itemId = item.getItemId();\n        if (itemId == R.id.action_refresh_detail) {\n            refreshDetails();\n        } else if (itemId == R.id.action_share_apk) {\n            showProgressIndicator(true);\n            ThreadUtils.postOnBackgroundThread(() -> {\n                try {\n                    Path tmpApkSource = ApkUtils.getSharableApkFile(requireContext(), mPackageInfo);\n                    ThreadUtils.postOnMainThread(() -> {\n                        showProgressIndicator(false);\n                        Context ctx = ContextUtils.getContext();\n                        Intent intent = new Intent(Intent.ACTION_SEND)\n                                .setType(\"application/*\")\n                                .putExtra(Intent.EXTRA_STREAM, FmProvider.getContentUri(tmpApkSource))\n                                .addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);\n                        ctx.startActivity(Intent.createChooser(intent, ctx.getString(R.string.share_apk))\n                                .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));\n                    });\n                } catch (Exception e) {\n                    Log.e(TAG, e);\n                    displayLongToast(R.string.failed_to_extract_apk_file);\n                }\n            });\n        } else if (itemId == R.id.action_backup) {\n            if (mMainModel == null) return true;\n            BackupRestoreDialogFragment fragment = BackupRestoreDialogFragment.getInstanceWithPref(\n                    Collections.singletonList(new UserPackagePair(mPackageName, mUserId)), mUserId);\n            fragment.setOnActionBeginListener(mode -> showProgressIndicator(true));\n            fragment.setOnActionCompleteListener((mode, failedPackages) -> {\n                showProgressIndicator(false);\n                mMainModel.getTagsAlteredLiveData().setValue(true);\n            });\n            fragment.show(getParentFragmentManager(), BackupRestoreDialogFragment.TAG);\n        } else if (itemId == R.id.action_view_settings) {\n            try {\n                ActivityManagerCompat.startActivity(IntentUtils.getAppDetailsSettings(mPackageName), mUserId);\n            } catch (Throwable th) {\n                UIUtils.displayLongToast(\"Error: \" + th.getLocalizedMessage());\n            }\n        } else if (itemId == R.id.action_export_blocking_rules) {\n            final String fileName = \"app_manager_rules_export-\" + DateUtils.formatDateTime(mActivity, System.currentTimeMillis()) + \".am.tsv\";\n            mExport.launch(fileName, uri -> {\n                if (uri == null || mMainModel == null) {\n                    // Back button pressed.\n                    return;\n                }\n                RulesTypeSelectionDialogFragment dialogFragment = new RulesTypeSelectionDialogFragment();\n                Bundle exportArgs = new Bundle();\n                ArrayList<String> packages = new ArrayList<>();\n                packages.add(mPackageName);\n                exportArgs.putInt(RulesTypeSelectionDialogFragment.ARG_MODE, RulesTypeSelectionDialogFragment.MODE_EXPORT);\n                exportArgs.putParcelable(RulesTypeSelectionDialogFragment.ARG_URI, uri);\n                exportArgs.putStringArrayList(RulesTypeSelectionDialogFragment.ARG_PKG, packages);\n                exportArgs.putIntArray(RulesTypeSelectionDialogFragment.ARG_USERS, new int[]{mUserId});\n                dialogFragment.setArguments(exportArgs);\n                dialogFragment.show(mActivity.getSupportFragmentManager(), RulesTypeSelectionDialogFragment.TAG);\n            });\n        } else if (itemId == R.id.action_open_in_termux) {\n            if (SelfPermissions.checkSelfPermission(TERMUX_RUN_COMMAND)) {\n                openInTermux();\n            } else {\n                mRequestPerm.launch(TERMUX_RUN_COMMAND, granted -> {\n                    if (granted) openInTermux();\n                });\n            }\n        } else if (itemId == R.id.action_run_in_termux) {\n            if (SelfPermissions.checkSelfPermission(TERMUX_RUN_COMMAND)) {\n                runInTermux();\n            } else {\n                mRequestPerm.launch(TERMUX_RUN_COMMAND, granted -> {\n                    if (granted) runInTermux();\n                });\n            }\n        } else if (itemId == R.id.action_magisk_hide) {\n            displayMagiskHideDialog();\n        } else if (itemId == R.id.action_magisk_denylist) {\n            displayMagiskDenyListDialog();\n        } else if (itemId == R.id.action_battery_opt) {\n            if (SelfPermissions.checkSelfOrRemotePermission(ManifestCompat.permission.DEVICE_POWER)) {\n                new MaterialAlertDialogBuilder(requireContext())\n                        .setTitle(R.string.battery_optimization)\n                        .setMessage(R.string.choose_what_to_do)\n                        .setPositiveButton(R.string.enable, (dialog, which) -> {\n                            if (DeviceIdleManagerCompat.enableBatteryOptimization(mPackageName)) {\n                                UIUtils.displayShortToast(R.string.done);\n                                mMainModel.getTagsAlteredLiveData().setValue(true);\n                            } else {\n                                UIUtils.displayShortToast(R.string.failed);\n                            }\n                        })\n                        .setNegativeButton(R.string.disable, (dialog, which) -> {\n                            if (DeviceIdleManagerCompat.disableBatteryOptimization(mPackageName)) {\n                                UIUtils.displayShortToast(R.string.done);\n                                mMainModel.getTagsAlteredLiveData().setValue(true);\n                            } else {\n                                UIUtils.displayShortToast(R.string.failed);\n                            }\n                        })\n                        .show();\n            } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {\n                try {\n                    startActivity(IntentUtils.getBatteryOptSettings(mPackageName));\n                } catch (Throwable th) {\n                    UIUtils.displayShortToast(\"No DEVICE_POWER permission.\");\n                }\n            }\n        } else if (itemId == R.id.action_sensor) {\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P && SelfPermissions.checkSelfOrRemotePermission(ManifestCompat.permission.MANAGE_SENSORS)) {\n                new MaterialAlertDialogBuilder(requireContext())\n                        .setTitle(R.string.sensors)\n                        .setMessage(R.string.choose_what_to_do)\n                        .setPositiveButton(R.string.enable, (dialog, which) -> ThreadUtils.postOnBackgroundThread(() -> {\n                            try {\n                                SensorServiceCompat.enableSensor(mPackageName, mUserId, true);\n                                mMainModel.getTagsAlteredLiveData().postValue(true);\n                                ThreadUtils.postOnMainThread(() ->\n                                        UIUtils.displayShortToast(R.string.done));\n                            } catch (IOException e) {\n                                ThreadUtils.postOnMainThread(() -> UIUtils.displayLongToast(\n                                        getString(R.string.failed)\n                                                + LangUtils.getSeparatorString()\n                                                + e.getMessage()));\n                            }\n                        }))\n                        .setNegativeButton(R.string.disable, (dialog, which) -> ThreadUtils.postOnBackgroundThread(() -> {\n                            try {\n                                SensorServiceCompat.enableSensor(mPackageName, mUserId, false);\n                                mMainModel.getTagsAlteredLiveData().postValue(true);\n                                ThreadUtils.postOnMainThread(() ->\n                                        UIUtils.displayShortToast(R.string.done));\n                            } catch (IOException e) {\n                                ThreadUtils.postOnMainThread(() -> UIUtils.displayLongToast(\n                                        getString(R.string.failed)\n                                                + LangUtils.getSeparatorString()\n                                                + e.getMessage()));\n                            }\n                        }))\n                        .show();\n            } else {\n                Log.e(TAG, \"No sensor permission.\");\n            }\n        } else if (itemId == R.id.action_net_policy) {\n            if (!UserHandleHidden.isApp(mApplicationInfo.uid)) {\n                UIUtils.displayLongToast(R.string.netpolicy_cannot_be_modified_for_core_apps);\n                return true;\n            }\n            if (!SelfPermissions.checkSelfOrRemotePermission(ManifestCompat.permission.MANAGE_NETWORK_POLICY)) {\n                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {\n                    try {\n                        startActivity(IntentUtils.getNetPolicySettings(mPackageName));\n                    } catch (Throwable th) {\n                        UIUtils.displayShortToast(\"No MANAGE_NETWORK_POLICY permission.\");\n                    }\n                }\n                return true;\n            }\n            ArrayMap<Integer, String> netPolicyMap = NetworkPolicyManagerCompat.getAllReadablePolicies(ContextUtils.getContext());\n            Integer[] polices = new Integer[netPolicyMap.size()];\n            CharSequence[] policyStrings = new String[netPolicyMap.size()];\n            int selectedPolicies = NetworkPolicyManagerCompat.getUidPolicy(mApplicationInfo.uid);\n            for (int i = 0; i < netPolicyMap.size(); ++i) {\n                polices[i] = netPolicyMap.keyAt(i);\n                policyStrings[i] = netPolicyMap.valueAt(i);\n            }\n            new SearchableFlagsDialogBuilder<>(mActivity, polices, policyStrings, selectedPolicies)\n                    .setTitle(R.string.net_policy)\n                    .showSelectAll(false)\n                    .setNegativeButton(R.string.cancel, null)\n                    .setPositiveButton(R.string.save, (dialog, which, selections) -> {\n                        int flags = 0;\n                        for (int flag : selections) {\n                            flags |= flag;\n                        }\n                        NetworkPolicyManagerCompat.setUidPolicy(mApplicationInfo.uid, flags);\n                        mMainModel.getTagsAlteredLiveData().setValue(true);\n                    })\n                    .show();\n        } else if (itemId == R.id.action_extract_icon) {\n            String iconName = mAppLabel + \"_icon.png\";\n            mExport.launch(iconName, uri -> {\n                if (uri == null) {\n                    // Back button pressed.\n                    return;\n                }\n                ThreadUtils.postOnBackgroundThread(() -> {\n                    try (OutputStream outputStream = Paths.get(uri).openOutputStream()) {\n                        if (outputStream == null) {\n                            throw new IOException(\"Unable to open output stream.\");\n                        }\n                        Bitmap bitmap = getBitmapFromDrawable(mApplicationInfo.loadIcon(mPackageManager));\n                        bitmap.compress(Bitmap.CompressFormat.PNG, 100, outputStream);\n                        outputStream.flush();\n                        ThreadUtils.postOnMainThread(() -> displayShortToast(R.string.saved_successfully));\n                    } catch (IOException e) {\n                        Log.e(TAG, e);\n                        ThreadUtils.postOnMainThread(() -> displayShortToast(R.string.saving_failed));\n                    }\n                });\n            });\n        } else if (itemId == R.id.action_install) {\n            List<UserInfo> users = Users.getUsers();\n            CharSequence[] userNames = new String[users.size()];\n            int i = 0;\n            for (UserInfo info : users) {\n                userNames[i++] = info.toLocalizedString(requireContext());\n            }\n            new SearchableItemsDialogBuilder<>(mActivity, userNames)\n                    .setTitle(R.string.select_user)\n                    .setOnItemClickListener((dialog, which, item1) -> {\n                        mAppInfoModel.installExisting(mPackageName, users.get(which).id);\n                        dialog.dismiss();\n                    })\n                    .setNegativeButton(R.string.cancel, null)\n                    .show();\n        } else if (itemId == R.id.action_add_to_profile) {\n            AddToProfileDialogFragment dialog = AddToProfileDialogFragment.getInstance(new String[]{mPackageName});\n            dialog.show(getChildFragmentManager(), AddToProfileDialogFragment.TAG);\n        } else if (itemId == R.id.action_optimize) {\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N\n                    && (SelfPermissions.isSystemOrRootOrShell() || BuildConfig.APPLICATION_ID.equals(mInstallerPackageName))) {\n                DexOptDialog dialog = DexOptDialog.getInstance(new String[]{mPackageName});\n                dialog.show(getChildFragmentManager(), DexOptDialog.TAG);\n            } else UIUtils.displayShortToast(R.string.only_works_in_root_or_adb_mode);\n        } else return false;\n        return true;\n    }\n\n    @Override\n    public void onMenuClosed(@NonNull Menu menu) {\n        if (mMenuPreparationResult != null) {\n            mMenuPreparationResult.cancel(true);\n        }\n    }\n\n    @Override\n    public void onStart() {\n        super.onStart();\n        if (mActivity.searchView != null) mActivity.searchView.setVisibility(View.GONE);\n    }\n\n    @Override\n    public void onRefresh() {\n        mSwipeRefresh.setRefreshing(false);\n        refreshDetails();\n    }\n\n    @Override\n    public void onResume() {\n        super.onResume();\n        if (mActivity.searchView != null) mActivity.searchView.setVisibility(View.GONE);\n    }\n\n    @Override\n    public void onDetach() {\n        if (mTagCloudFuture != null) mTagCloudFuture.cancel(true);\n        if (mActionsFuture != null) mActionsFuture.cancel(true);\n        if (mListFuture != null) mListFuture.cancel(true);\n        super.onDetach();\n    }\n\n    private void openInTermux() {\n        runWithTermux(new String[]{\"su\", \"-\", String.valueOf(mApplicationInfo.uid)});\n    }\n\n    private void runInTermux() {\n        runWithTermux(new String[]{\"su\", \"-c\", \"run-as\", mPackageName});\n    }\n\n    private void runWithTermux(String[] command) {\n        Intent intent = new Intent();\n        intent.setClassName(\"com.termux\", \"com.termux.app.RunCommandService\");\n        intent.setAction(\"com.termux.RUN_COMMAND\");\n        intent.putExtra(\"com.termux.RUN_COMMAND_PATH\", Utils.TERMUX_LOGIN_PATH);\n        intent.putExtra(\"com.termux.RUN_COMMAND_ARGUMENTS\", command);\n        intent.putExtra(\"com.termux.RUN_COMMAND_BACKGROUND\", false);\n        try {\n            ActivityCompat.startForegroundService(mActivity, intent);\n        } catch (Exception e) {\n            UIUtils.displayLongToast(\"Error: \" + e.getMessage());\n        }\n    }\n\n    private void install() {\n        ApkSource apkSource = mMainModel != null ? mMainModel.getApkSource() : null;\n        if (apkSource == null) return;\n        try {\n            startActivity(PackageInstallerActivity.getLaunchableInstance(requireContext(), apkSource));\n        } catch (Exception e) {\n            UIUtils.displayLongToast(\"Error: \" + e.getMessage());\n        }\n    }\n\n    @UiThread\n    private void refreshDetails() {\n        if (mMainModel == null || isDetached()) return;\n        showProgressIndicator(true);\n        mMainModel.triggerPackageChange();\n    }\n\n    @MainThread\n    private void setupTagCloud(@NonNull AppInfoViewModel.TagCloud tagCloud) {\n        if (mTagCloudFuture != null) mTagCloudFuture.cancel(true);\n        mTagCloudFuture = ThreadUtils.postOnBackgroundThread(() -> {\n            List<TagItem> tagItems = getTagCloudItems(tagCloud);\n            ThreadUtils.postOnMainThread(() -> {\n                if (isDetached()) return;\n                ++mLoadedItemCount;\n                if (mLoadedItemCount >= 4) {\n                    showProgressIndicator(false);\n                }\n                mTagCloud.removeAllViews();\n                for (TagItem tagItem : tagItems) {\n                    if (isDetached()) return;\n                    mTagCloud.addView(tagItem.toChip(mTagCloud.getContext(), mTagCloud));\n                }\n            });\n        });\n    }\n\n    @WorkerThread\n    @NonNull\n    private List<TagItem> getTagCloudItems(@NonNull AppInfoViewModel.TagCloud tagCloud) {\n        Objects.requireNonNull(mMainModel);\n        Context context = mTagCloud.getContext();\n        List<TagItem> tagItems = new LinkedList<>();\n        // Add tracker chip\n        if (!tagCloud.trackerComponents.isEmpty()) {\n            CharSequence[] trackerComponentNames = new CharSequence[tagCloud.trackerComponents.size()];\n            int blockedColor = ColorCodes.getComponentTrackerBlockedIndicatorColor(context);\n            for (int i = 0; i < trackerComponentNames.length; ++i) {\n                ComponentRule rule = tagCloud.trackerComponents.get(i);\n                trackerComponentNames[i] = rule.isBlocked() ? getColoredText(rule.name, blockedColor) : rule.name;\n            }\n            TagItem trackerTag = new TagItem();\n            tagItems.add(trackerTag);\n            trackerTag.setText(getResources().getQuantityString(R.plurals.no_of_trackers,\n                            tagCloud.trackerComponents.size(), tagCloud.trackerComponents.size()))\n                    .setColor(tagCloud.areAllTrackersBlocked\n                            ? ColorCodes.getComponentTrackerBlockedIndicatorColor(context)\n                            : ColorCodes.getComponentTrackerIndicatorColor(context))\n                    .setOnClickListener(v -> {\n                        if (!mIsExternalApk && SelfPermissions.canModifyAppComponentStates(mUserId, mPackageName, mMainModel.isTestOnlyApp())) {\n                            new SearchableMultiChoiceDialogBuilder<>(v.getContext(), tagCloud.trackerComponents, trackerComponentNames)\n                                    .setTitle(R.string.trackers)\n                                    .addSelections(tagCloud.trackerComponents)\n                                    .setNegativeButton(R.string.cancel, null)\n                                    .setPositiveButton(R.string.block, (dialog, which, selectedItems) -> {\n                                        showProgressIndicator(true);\n                                        ThreadUtils.postOnBackgroundThread(() -> {\n                                            mMainModel.addRules(selectedItems, true);\n                                            ThreadUtils.postOnMainThread(() -> {\n                                                if (!isDetached()) {\n                                                    showProgressIndicator(false);\n                                                }\n                                                displayShortToast(R.string.done);\n                                            });\n                                        });\n                                    })\n                                    .setNeutralButton(R.string.unblock, (dialog, which, selectedItems) -> {\n                                        showProgressIndicator(true);\n                                        ThreadUtils.postOnBackgroundThread(() -> {\n                                            mMainModel.removeRules(selectedItems, true);\n                                            ThreadUtils.postOnMainThread(() -> {\n                                                if (!isDetached()) {\n                                                    showProgressIndicator(false);\n                                                }\n                                                displayShortToast(R.string.done);\n                                            });\n                                        });\n                                    })\n                                    .show();\n                        } else {\n                            new SearchableItemsDialogBuilder<>(v.getContext(), trackerComponentNames)\n                                    .setTitle(R.string.trackers)\n                                    .setNegativeButton(R.string.close, null)\n                                    .show();\n                        }\n                    });\n        }\n        if (tagCloud.isSystemApp) {\n            tagItems.add(new TagItem()\n                    .setTextRes(tagCloud.isSystemlessPath ? R.string.systemless_app : R.string.system_app));\n            if (tagCloud.isUpdatedSystemApp) {\n                tagItems.add(new TagItem().setTextRes(R.string.updated_app));\n            }\n        } else if (!mIsExternalApk) {\n            tagItems.add(new TagItem().setTextRes(R.string.user_app));\n        }\n        if (tagCloud.splitCount > 0) {\n            TagItem splitTag = new TagItem();\n            tagItems.add(splitTag);\n            splitTag.setText(getResources().getQuantityString(R.plurals.no_of_splits, tagCloud.splitCount,\n                            tagCloud.splitCount))\n                    .setOnClickListener(v -> {\n                        ApkFile apkFile = mMainModel.getApkFile();\n                        if (apkFile == null) {\n                            return;\n                        }\n                        // Display a list of apks\n                        List<ApkFile.Entry> apkEntries = apkFile.getEntries();\n                        CharSequence[] entryNames = new CharSequence[tagCloud.splitCount];\n                        for (int i = 0; i < tagCloud.splitCount; ++i) {\n                            entryNames[i] = apkEntries.get(i + 1).toLocalizedString(v.getContext());\n                        }\n                        new SearchableItemsDialogBuilder<>(v.getContext(), entryNames)\n                                .setTitle(R.string.splits)\n                                .setNegativeButton(R.string.close, null)\n                                .show();\n                    });\n        }\n        if (tagCloud.isDebuggable) {\n            tagItems.add(new TagItem().setTextRes(R.string.debuggable));\n        }\n        if (tagCloud.isTestOnly) {\n            tagItems.add(new TagItem().setTextRes(R.string.test_only));\n        }\n        if (!tagCloud.hasCode) {\n            tagItems.add(new TagItem().setTextRes(R.string.no_code));\n        }\n        if (tagCloud.isOverlay) {\n            TagItem overlayTag = new TagItem();\n            tagItems.add(overlayTag);\n            overlayTag.setTextRes(R.string.title_overlay)\n                    .setOnClickListener(v -> {\n                        Context ctx = v.getContext();\n                        String target = Objects.requireNonNull(PackageInfoCompat2.getOverlayTarget(mPackageInfo));\n                        String targetName = PackageInfoCompat2.getTargetOverlayableName(mPackageInfo);\n                        String category = PackageInfoCompat2.getOverlayCategory(mPackageInfo);\n                        int priority = PackageInfoCompat2.getOverlayPriority(mPackageInfo);\n                        boolean isStatic = PackageInfoCompat2.isStaticOverlayPackage(mPackageInfo);\n                        SpannableStringBuilder spannable = new SpannableStringBuilder();\n                        if (targetName != null) {\n                            spannable.append(getStyledKeyValue(ctx, R.string.overlay_target, targetName))\n                                    .append(\"\\n\")\n                                    .append(getSmallerText(target));\n                        } else {\n                            spannable.append(getStyledKeyValue(ctx, R.string.overlay_target, target));\n                        }\n                        if (category != null) {\n                            spannable.append(\"\\n\")\n                                    .append(getSmallerText(getStyledKeyValue(ctx, R.string.overlay_category, category)));\n                        }\n                        if (!isStatic) {\n                            spannable.append(\"\\n\")\n                                    .append(getSmallerText(getStyledKeyValue(ctx, R.string.priority, String.valueOf(priority))));\n                        } // else static overlays have the highest priority\n                        new MaterialAlertDialogBuilder(ctx)\n                                .setTitle(R.string.title_overlay)\n                                .setMessage(spannable)\n                                .setNeutralButton(R.string.app_info, (dialog, which) -> {\n                                    Intent appDetailsIntent = AppDetailsActivity.getIntent(ctx, target, mUserId);\n                                    startActivity(appDetailsIntent);\n                                })\n                                .setNegativeButton(R.string.close, null)\n                                .show();\n                    });\n        }\n        if (tagCloud.hasRequestedLargeHeap) {\n            tagItems.add(new TagItem().setTextRes(R.string.requested_large_heap));\n        }\n        if (tagCloud.hostsToOpen != null) {\n            TagItem openLinksTag = new TagItem();\n            tagItems.add(openLinksTag);\n            openLinksTag.setTextRes(R.string.app_info_tag_open_links)\n                    .setColor(tagCloud.canOpenLinks ? ColorCodes.getFailureColor(context)\n                            : ColorCodes.getSuccessColor(context))\n                    .setOnClickListener(v -> {\n                        SearchableItemsDialogBuilder<String> builder = new SearchableItemsDialogBuilder<>(v.getContext(), new ArrayList<>(tagCloud.hostsToOpen.keySet()))\n                                .setTitle(R.string.title_domains_supported_by_the_app)\n                                .setNegativeButton(R.string.close, null);\n                        if (SelfPermissions.checkSelfOrRemotePermission(ManifestCompat.permission.UPDATE_DOMAIN_VERIFICATION_USER_SELECTION)) {\n                            // Enable/disable directly from the app\n                            builder.setPositiveButton(tagCloud.canOpenLinks ? R.string.disable : R.string.enable,\n                                    (dialog, which) -> ThreadUtils.postOnBackgroundThread(() -> {\n                                        try {\n                                            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {\n                                                DomainVerificationManagerCompat.setDomainVerificationLinkHandlingAllowed(\n                                                        mPackageName, !tagCloud.canOpenLinks, mUserId);\n                                            }\n                                            mMainModel.getTagsAlteredLiveData().postValue(true);\n                                            ThreadUtils.postOnMainThread(() ->\n                                                    UIUtils.displayShortToast(R.string.done));\n                                        } catch (Throwable th) {\n                                            th.printStackTrace();\n                                            ThreadUtils.postOnMainThread(() -> UIUtils.displayShortToast(R.string.failed));\n                                        }\n                                    }));\n                        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {\n                            builder.setPositiveButton(R.string.app_settings, (dialog, which) -> {\n                                try {\n                                    startActivity(IntentUtils.getSettings(Settings.ACTION_APP_OPEN_BY_DEFAULT_SETTINGS, mPackageName));\n                                } catch (Throwable th) {\n                                    ExUtils.exceptionAsIgnored(() -> startActivity(IntentUtils.getAppDetailsSettings(mPackageName)));\n                                }\n                            });\n                        }\n                        builder.show();\n                    });\n        }\n        if (!tagCloud.runningServices.isEmpty()) {\n            TagItem runningTag = new TagItem();\n            tagItems.add(runningTag);\n            runningTag.setTextRes(R.string.running)\n                    .setColor(ColorCodes.getComponentRunningIndicatorColor(context))\n                    .setOnClickListener(v ->\n                            displayRunningServices(tagCloud.runningServices, v.getContext()));\n        } else if (tagCloud.isRunning) {\n            TagItem runningTag = new TagItem();\n            tagItems.add(runningTag);\n            runningTag.setTextRes(R.string.running)\n                    .setColor(ColorCodes.getComponentRunningIndicatorColor(context));\n        }\n        if (tagCloud.isForceStopped) {\n            tagItems.add(new TagItem()\n                    .setTextRes(R.string.stopped)\n                    .setColor(ColorCodes.getAppForceStoppedIndicatorColor(context)));\n        }\n        if (!tagCloud.isAppEnabled) {\n            tagItems.add(new TagItem()\n                    .setTextRes(R.string.disabled_app)\n                    .setColor(ColorCodes.getAppDisabledIndicatorColor(context)));\n        }\n        if (tagCloud.isAppSuspended) {\n            tagItems.add(new TagItem()\n                    .setTextRes(R.string.suspended)\n                    .setColor(ColorCodes.getAppSuspendedIndicatorColor(context)));\n        }\n        if (tagCloud.isAppHidden) {\n            tagItems.add(new TagItem()\n                    .setTextRes(R.string.hidden)\n                    .setColor(ColorCodes.getAppHiddenIndicatorColor(context)));\n        }\n        mMagiskHiddenProcesses = tagCloud.magiskHiddenProcesses;\n        if (tagCloud.isMagiskHideEnabled) {\n            tagItems.add(new TagItem()\n                    .setTextRes(R.string.magisk_hide_enabled)\n                    .setOnClickListener(v -> displayMagiskHideDialog()));\n        }\n        mMagiskDeniedProcesses = tagCloud.magiskDeniedProcesses;\n        if (tagCloud.isMagiskDenyListEnabled) {\n            tagItems.add(new TagItem()\n                    .setTextRes(R.string.magisk_denylist)\n                    .setOnClickListener(v -> displayMagiskDenyListDialog()));\n        }\n        if (tagCloud.canWriteAndExecute) {\n            TagItem wxItem = new TagItem();\n            tagItems.add(wxItem);\n            wxItem.setText(\"WX\")\n                    .setColor(ColorCodes.getAppWriteAndExecuteIndicatorColor(context))\n                    .setOnClickListener(v ->\n                            new ScrollableDialogBuilder(v.getContext())\n                                    .setTitle(\"WX\")\n                                    .setMessage(R.string.app_can_write_and_execute_in_same_place)\n                                    .enableAnchors()\n                                    .setNegativeButton(R.string.close, null)\n                                    .show());\n        }\n        if (tagCloud.bloatwareRemovalType != 0) {\n            TagItem bloatwareTag = new TagItem();\n            tagItems.add(bloatwareTag);\n            bloatwareTag.setText(\"Bloatware\")\n                    .setColor(ColorCodes.getBloatwareIndicatorColor(context, tagCloud.bloatwareRemovalType))\n                    .setOnClickListener(v -> {\n                        BloatwareDetailsDialog dialog = BloatwareDetailsDialog.getInstance(mPackageName);\n                        dialog.show(getChildFragmentManager(), BloatwareDetailsDialog.TAG);\n                    });\n        }\n        if (tagCloud.hasKeyStoreItems) {\n            TagItem keyStoreTag = new TagItem();\n            tagItems.add(keyStoreTag);\n            keyStoreTag.setTextRes(R.string.keystore)\n                    .setOnClickListener(view -> new SearchableItemsDialogBuilder<>(view.getContext(), KeyStoreUtils\n                            .getKeyStoreFiles(mApplicationInfo.uid, mUserId))\n                            .setTitle(R.string.keystore)\n                            .setNegativeButton(R.string.close, null)\n                            .show());\n            if (tagCloud.hasMasterKeyInKeyStore) {\n                keyStoreTag.setColor(ColorCodes.getAppKeystoreIndicatorColor(context));\n            }\n        }\n        if (!tagCloud.backups.isEmpty()) {\n            TagItem backupTag = new TagItem();\n            tagItems.add(backupTag);\n            backupTag.setTextRes(R.string.backup)\n                    .setOnClickListener(v -> {\n                        BackupRestoreDialogFragment fragment = BackupRestoreDialogFragment.getInstance(\n                                Collections.singletonList(new UserPackagePair(mPackageName, mUserId)),\n                                BackupRestoreDialogFragment.MODE_RESTORE | BackupRestoreDialogFragment.MODE_DELETE);\n                        fragment.setOnActionBeginListener(mode -> showProgressIndicator(true));\n                        fragment.setOnActionCompleteListener((mode, failedPackages) -> showProgressIndicator(false));\n                        fragment.show(getParentFragmentManager(), BackupRestoreDialogFragment.TAG);\n                    });\n        }\n        if (!tagCloud.isBatteryOptimized) {\n            TagItem batteryOptTag = new TagItem();\n            tagItems.add(batteryOptTag);\n            batteryOptTag.setTextRes(R.string.no_battery_optimization)\n                    .setColor(ColorCodes.getAppNoBatteryOptimizationIndicatorColor(context));\n            if (SelfPermissions.checkSelfOrRemotePermission(ManifestCompat.permission.DEVICE_POWER)) {\n                batteryOptTag.setOnClickListener(v -> new MaterialAlertDialogBuilder(v.getContext())\n                        .setTitle(R.string.battery_optimization)\n                        .setMessage(R.string.enable_battery_optimization)\n                        .setNegativeButton(R.string.no, null)\n                        .setPositiveButton(R.string.yes, (dialog, which) -> {\n                            if (DeviceIdleManagerCompat.enableBatteryOptimization(mPackageName)) {\n                                UIUtils.displayShortToast(R.string.done);\n                                mMainModel.getTagsAlteredLiveData().setValue(true);\n                            } else {\n                                UIUtils.displayShortToast(R.string.failed);\n                            }\n                        })\n                        .show());\n            } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {\n                batteryOptTag.setOnClickListener(v -> ExUtils.exceptionAsIgnored(() ->\n                        startActivity(IntentUtils.getBatteryOptSettings(mPackageName))));\n            }\n        }\n        if (!tagCloud.sensorsEnabled) {\n            TagItem sensorsTag = new TagItem();\n            tagItems.add(sensorsTag);\n            sensorsTag.setTextRes(R.string.tag_sensors_disabled);\n        }\n        if (tagCloud.netPolicies > 0) {\n            String[] readablePolicies = NetworkPolicyManagerCompat.getReadablePolicies(context, tagCloud.netPolicies)\n                    .values().toArray(new String[0]);\n            TagItem netPolicyTag = new TagItem();\n            tagItems.add(netPolicyTag);\n            netPolicyTag.setTextRes(R.string.has_net_policy)\n                    .setOnClickListener(v -> new SearchableItemsDialogBuilder<>(v.getContext(), readablePolicies)\n                            .setTitle(R.string.net_policy)\n                            .setNegativeButton(R.string.ok, null)\n                            .show());\n        }\n        if (tagCloud.ssaid != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {\n            TagItem ssaidTag = new TagItem();\n            tagItems.add(ssaidTag);\n            ssaidTag.setTextRes(R.string.ssaid)\n                    .setColor(ColorCodes.getAppSsaidIndicatorColor(context))\n                    .setOnClickListener(v -> {\n                        ChangeSsaidDialog changeSsaidDialog = ChangeSsaidDialog.getInstance(mPackageName, mApplicationInfo.uid,\n                                tagCloud.ssaid);\n                        changeSsaidDialog.setSsaidChangedInterface((newSsaid, isSuccessful) -> {\n                            displayLongToast(isSuccessful ? R.string.restart_to_reflect_changes : R.string.failed_to_change_ssaid);\n                            if (isSuccessful) tagCloud.ssaid = newSsaid;\n                        });\n                        changeSsaidDialog.show(getChildFragmentManager(), ChangeSsaidDialog.TAG);\n                    });\n        }\n        if (tagCloud.uriGrants != null) {\n            TagItem safTag = new TagItem();\n            tagItems.add(safTag);\n            safTag.setTextRes(R.string.saf)\n                    .setOnClickListener(v -> {\n                        CharSequence[] uriGrants = new CharSequence[tagCloud.uriGrants.size()];\n                        for (int i = 0; i < tagCloud.uriGrants.size(); ++i) {\n                            uriGrants[i] = GrantUriUtils.toLocalisedString(v.getContext(), tagCloud.uriGrants.get(i).uri);\n                        }\n                        new SearchableItemsDialogBuilder<>(v.getContext(), uriGrants)\n                                .setTitle(R.string.saf)\n                                .setTextSelectable(true)\n                                .setListBackgroundColorOdd(ColorCodes.getListItemColor0(mActivity))\n                                .setListBackgroundColorEven(ColorCodes.getListItemColor1(mActivity))\n                                .setNegativeButton(R.string.close, null)\n                                .show();\n                    });\n        }\n        if (tagCloud.usesPlayAppSigning) {\n            TagItem playAppSigningTag = new TagItem();\n            tagItems.add(playAppSigningTag);\n            playAppSigningTag.setTextRes(R.string.uses_play_app_signing)\n                    .setColor(ColorCodes.getAppPlayAppSigningIndicatorColor(context))\n                    .setOnClickListener(v ->\n                            new ScrollableDialogBuilder(mActivity)\n                                    .setTitle(R.string.uses_play_app_signing)\n                                    .setMessage(R.string.uses_play_app_signing_description)\n                                    .setNegativeButton(R.string.close, null)\n                                    .show());\n        }\n        if (tagCloud.xposedModuleInfo != null) {\n            TagItem xposedItem = new TagItem();\n            tagItems.add(xposedItem);\n            xposedItem.setText(\"Xposed\")\n                    .setOnClickListener(v -> new ScrollableDialogBuilder(v.getContext())\n                            .setTitle(R.string.xposed_module_info)\n                            .setMessage(tagCloud.xposedModuleInfo.toLocalizedString(v.getContext()))\n                            .setNegativeButton(R.string.close, null)\n                            .show());\n        }\n        if (tagCloud.staticSharedLibraryNames != null) {\n            TagItem staticSharedLibraryTag = new TagItem();\n            tagItems.add(staticSharedLibraryTag);\n            staticSharedLibraryTag.setTextRes(R.string.static_shared_library)\n                    .setOnClickListener(v -> new SearchableMultiChoiceDialogBuilder<>(v.getContext(), tagCloud.staticSharedLibraryNames, tagCloud.staticSharedLibraryNames)\n                            .setTitle(R.string.shared_libs)\n                            .setPositiveButton(R.string.close, null)\n                            .setNeutralButton(R.string.uninstall, (dialog, which, selectedItems) -> {\n                                int userId = mUserId;\n                                final boolean isSystemApp = ApplicationInfoCompat.isSystemApp(mApplicationInfo);\n                                new ScrollableDialogBuilder(mActivity,\n                                        isSystemApp ? R.string.uninstall_system_app_message : R.string.uninstall_app_message)\n                                        .setTitle(mAppLabel)\n                                        .setPositiveButton(R.string.uninstall, (dialog1, which1, keepData) -> {\n                                            if (selectedItems.size() == 1) {\n                                                ThreadUtils.postOnBackgroundThread(() -> {\n                                                    PackageInstallerCompat installer = PackageInstallerCompat.getNewInstance();\n                                                    installer.setAppLabel(mAppLabel);\n                                                    boolean uninstalled = installer.uninstall(selectedItems.get(0), userId, false);\n                                                    ThreadUtils.postOnMainThread(() -> {\n                                                        if (uninstalled) {\n                                                            displayLongToast(R.string.uninstalled_successfully, mAppLabel);\n                                                            mActivity.finish();\n                                                        } else {\n                                                            displayLongToast(R.string.failed_to_uninstall, mAppLabel);\n                                                        }\n                                                    });\n                                                });\n                                            } else {\n                                                ArrayList<Integer> userIds = new ArrayList<>(selectedItems.size());\n                                                for (int i = 0; i < selectedItems.size(); ++i) {\n                                                    userIds.add(userId);\n                                                }\n                                                BatchQueueItem item = BatchQueueItem.getBatchOpQueue(\n                                                        BatchOpsManager.OP_UNINSTALL, selectedItems, userIds, null);\n                                                Intent intent = BatchOpsService.getServiceIntent(mActivity, item);\n                                                ContextCompat.startForegroundService(mActivity, intent);\n                                            }\n                                        })\n                                        .setNegativeButton(R.string.cancel, (dialog1, which1, keepData) -> {\n                                            if (dialog != null) dialog.cancel();\n                                        })\n                                        .show();\n                            })\n                            .show());\n        }\n        return tagItems;\n    }\n\n    private void displayRunningServices(\n            @NonNull List<ActivityManager.RunningServiceInfo> runningServices,\n            @NonNull Context ctx) {\n        showProgressIndicator(true);\n        ThreadUtils.postOnBackgroundThread(() -> {\n            CharSequence[] runningServiceNames = new CharSequence[runningServices.size()];\n            for (int i = 0; i < runningServiceNames.length; ++i) {\n                ActivityManager.RunningServiceInfo serviceInfo = runningServices.get(i);\n                String title = serviceInfo.service.getShortClassName();\n                Spannable description = new SpannableStringBuilder()\n                        .append(getStyledKeyValue(ctx, R.string.process_name, serviceInfo.process))\n                        .append(\"\\n\")\n                        .append(getStyledKeyValue(ctx, R.string.pid, String.valueOf(serviceInfo.pid)));\n                runningServiceNames[i] = new SpannableStringBuilder()\n                        .append(title)\n                        .append(\"\\n\")\n                        .append(getSmallerText(description));\n            }\n            boolean logViewerAvailable = FeatureController.isLogViewerEnabled()\n                    && SelfPermissions.checkSelfOrRemotePermission(Manifest.permission.DUMP);\n            DialogTitleBuilder titleBuilder = new DialogTitleBuilder(ctx)\n                    .setTitle(R.string.running_services);\n            if (logViewerAvailable) {\n                titleBuilder.setSubtitle(R.string.running_services_logcat_hint);\n            }\n            ThreadUtils.postOnMainThread(() -> {\n                if (isDetached()) return;\n                showProgressIndicator(false);\n                SearchableItemsDialogBuilder<CharSequence> builder = new SearchableItemsDialogBuilder<>(mActivity, runningServiceNames)\n                        .setTitle(titleBuilder.build());\n                if (logViewerAvailable) {\n                    builder.setOnItemClickListener((dialog, which, item) -> {\n                        Intent logViewerIntent = new Intent(mActivity.getApplicationContext(), LogViewerActivity.class)\n                                .putExtra(LogViewerActivity.EXTRA_FILTER, SearchCriteria.PID_KEYWORD + runningServices.get(which).pid)\n                                .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);\n                        mActivity.startActivity(logViewerIntent);\n                    });\n                }\n                if (SelfPermissions.checkSelfOrRemotePermission(ManifestCompat.permission.FORCE_STOP_PACKAGES)) {\n                    builder.setNeutralButton(R.string.force_stop, (dialog, which) -> ThreadUtils.postOnBackgroundThread(() -> {\n                        try {\n                            PackageManagerCompat.forceStopPackage(mPackageName, mUserId);\n                        } catch (SecurityException e) {\n                            Log.e(TAG, e);\n                            ThreadUtils.postOnMainThread(() -> displayLongToast(R.string.failed_to_stop, mAppLabel));\n                        }\n                    }));\n                }\n                builder.setNegativeButton(R.string.close, null);\n                if (isDetached()) return;\n                builder.show();\n            });\n        });\n    }\n\n    @UiThread\n    private void displayMagiskHideDialog() {\n        SearchableMultiChoiceDialogBuilder<MagiskProcess> builder;\n        builder = getMagiskProcessDialog(mMagiskHiddenProcesses, (dialog, which, mp, isChecked) ->\n                ThreadUtils.postOnBackgroundThread(() -> {\n                    mp.setEnabled(isChecked);\n                    if (MagiskHide.apply(mp, true)) {\n                        try (ComponentsBlocker cb = ComponentsBlocker.getMutableInstance(mPackageName, mUserId)) {\n                            cb.setMagiskHide(mp);\n                            mMainModel.getTagsAlteredLiveData().postValue(true);\n                        }\n                    } else {\n                        mp.setEnabled(!isChecked);\n                        ThreadUtils.postOnMainThread(() -> displayLongToast(isChecked ? R.string.failed_to_enable_magisk_hide\n                                : R.string.failed_to_disable_magisk_hide));\n                    }\n                }));\n        if (builder != null) {\n            builder.setTitle(R.string.magisk_hide_enabled).show();\n        }\n    }\n\n    @UiThread\n    private void displayMagiskDenyListDialog() {\n        SearchableMultiChoiceDialogBuilder<MagiskProcess> builder;\n        builder = getMagiskProcessDialog(mMagiskDeniedProcesses, (dialog, which, mp, isChecked) ->\n                ThreadUtils.postOnBackgroundThread(() -> {\n                    mp.setEnabled(isChecked);\n                    if (MagiskDenyList.apply(mp, true)) {\n                        try (ComponentsBlocker cb = ComponentsBlocker.getMutableInstance(mPackageName, mUserId)) {\n                            cb.setMagiskDenyList(mp);\n                            mMainModel.getTagsAlteredLiveData().postValue(true);\n                        }\n                    } else {\n                        mp.setEnabled(!isChecked);\n                        ThreadUtils.postOnMainThread(() -> displayLongToast(isChecked\n                                ? R.string.failed_to_enable_magisk_deny_list\n                                : R.string.failed_to_disable_magisk_deny_list));\n                    }\n                }));\n        if (builder != null) {\n            builder.setTitle(R.string.magisk_denylist).show();\n        }\n    }\n\n    @Nullable\n    public SearchableMultiChoiceDialogBuilder<MagiskProcess> getMagiskProcessDialog(\n            @Nullable List<MagiskProcess> magiskProcesses,\n            SearchableMultiChoiceDialogBuilder.OnMultiChoiceClickListener<MagiskProcess> multiChoiceClickListener) {\n        if (magiskProcesses == null || magiskProcesses.isEmpty()) {\n            return null;\n        }\n        List<Integer> selectedIndexes = new ArrayList<>();\n        CharSequence[] processes = new CharSequence[magiskProcesses.size()];\n        int i = 0;\n        for (MagiskProcess mp : magiskProcesses) {\n            SpannableStringBuilder sb = new SpannableStringBuilder();\n            if (mp.isIsolatedProcess()) {\n                sb.append(\"\\n\").append(UIUtils.getSecondaryText(mActivity, getString(R.string.isolated)));\n                if (mp.isRunning()) {\n                    sb.append(\", \").append(UIUtils.getSecondaryText(mActivity, getString(R.string.running)));\n                }\n            } else if (mp.isRunning()) {\n                sb.append(\"\\n\").append(UIUtils.getSecondaryText(mActivity, getString(R.string.running)));\n            }\n            processes[i] = new SpannableStringBuilder(mp.name).append(UIUtils.getSmallerText(sb));\n            if (mp.isEnabled()) {\n                selectedIndexes.add(i);\n            }\n            i++;\n        }\n        return new SearchableMultiChoiceDialogBuilder<>(mActivity, magiskProcesses, processes)\n                .addSelections(ArrayUtils.convertToIntArray(selectedIndexes))\n                .setTextSelectable(true)\n                .setOnMultiChoiceClickListener(multiChoiceClickListener)\n                .setNegativeButton(R.string.close, null);\n    }\n\n    @MainThread\n    private void setupHorizontalActions() {\n        if (mActionsFuture != null) {\n            mActionsFuture.cancel(true);\n        }\n        mActionsFuture = ThreadUtils.postOnBackgroundThread(() -> {\n            List<ActionItem> actionItems = getHorizontalActions();\n            ThreadUtils.postOnMainThread(() -> {\n                if (isDetached()) return;\n                ++mLoadedItemCount;\n                if (mLoadedItemCount >= 4) {\n                    showProgressIndicator(false);\n                }\n                mHorizontalLayout.removeAllViews();\n                for (ActionItem actionItem : actionItems) {\n                    if (isDetached()) return;\n                    mHorizontalLayout.addView(actionItem.toActionButton(mHorizontalLayout.getContext(), mHorizontalLayout));\n                }\n                if (isDetached()) return;\n                View v = mHorizontalLayout.getChildAt(0);\n                if (v != null) v.requestFocus();\n            });\n        });\n    }\n\n    @WorkerThread\n    private List<ActionItem> getHorizontalActions() {\n        Objects.requireNonNull(mMainModel);\n        List<ActionItem> actionItems = new LinkedList<>();\n        if (!mIsExternalApk) {\n            boolean isStaticSharedLib = ApplicationInfoCompat.isStaticSharedLibrary(mApplicationInfo);\n            boolean isFrozen = FreezeUtils.isFrozen(mApplicationInfo);\n            boolean canFreeze = !isStaticSharedLib && SelfPermissions.canFreezeUnfreezePackages();\n            // Set open\n            Intent launchIntent = PackageManagerCompat.getLaunchIntentForPackage(mPackageName, mUserId);\n            if (launchIntent != null && !isFrozen) {\n                ActionItem launchAction = new ActionItem(R.string.launch_app, R.drawable.ic_open_in_new);\n                actionItems.add(launchAction);\n                launchAction.setOnClickListener(v -> {\n                    try {\n                        ActivityManagerCompat.startActivity(launchIntent, mUserId);\n                    } catch (Throwable th) {\n                        UIUtils.displayLongToast(\"Error: \" + th.getLocalizedMessage());\n                    }\n                });\n            }\n            // Set freeze/unfreeze\n            if (canFreeze && !isFrozen) {\n                ActionItem freezeAction = new ActionItem(R.string.freeze, R.drawable.ic_snowflake);\n                actionItems.add(freezeAction);\n                freezeAction.setOnClickListener(v -> {\n                            if (BuildConfig.APPLICATION_ID.equals(mPackageName)) {\n                                new MaterialAlertDialogBuilder(mActivity)\n                                        .setMessage(R.string.are_you_sure)\n                                        .setPositiveButton(R.string.yes, (d, w) -> freeze(true))\n                                        .setNegativeButton(R.string.no, null)\n                                        .show();\n                            } else freeze(true);\n                        })\n                        .setOnLongClickListener(v -> {\n                            createFreezeShortcut(false);\n                            return true;\n                        });\n            }\n            // Set uninstall\n            ActionItem uninstallAction = new ActionItem(R.string.uninstall, R.drawable.ic_trash_can);\n            actionItems.add(uninstallAction);\n            uninstallAction.setOnClickListener(v -> {\n                if (mUserId != UserHandleHidden.myUserId() && !SelfPermissions.checkSelfOrRemotePermission(Manifest.permission.DELETE_PACKAGES)) {\n                    // Could be for work profile\n                    try {\n                        Intent uninstallIntent = new Intent(Intent.ACTION_DELETE);\n                        uninstallIntent.setData(Uri.parse(\"package:\" + mPackageName));\n                        ActivityManagerCompat.startActivity(uninstallIntent, mUserId);\n                        // TODO: 19/8/24 Watch for uninstallation\n                    } catch (Throwable th) {\n                        UIUtils.displayLongToast(\"Error: \" + th.getLocalizedMessage());\n                    }\n                    return;\n                }\n                final boolean isSystemApp = (mApplicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0;\n                ScrollableDialogBuilder builder = new ScrollableDialogBuilder(mActivity,\n                        isSystemApp ? R.string.uninstall_system_app_message : R.string.uninstall_app_message)\n                        .setTitle(mAppLabel)\n                        // FIXME: 16/6/23 Does it even work without INSTALL_PACKAGES?\n                        .setCheckboxLabel(R.string.keep_data_and_app_signing_signatures)\n                        .setPositiveButton(R.string.uninstall, (dialog, which, keepData) -> ThreadUtils.postOnBackgroundThread(() -> {\n                            PackageInstallerCompat installer = PackageInstallerCompat.getNewInstance();\n                            installer.setAppLabel(mAppLabel);\n                            boolean uninstalled = installer.uninstall(mPackageName, mUserId, keepData);\n                            ThreadUtils.postOnMainThread(() -> {\n                                if (uninstalled) {\n                                    displayLongToast(R.string.uninstalled_successfully, mAppLabel);\n                                    mActivity.finish();\n                                } else {\n                                    displayLongToast(R.string.failed_to_uninstall, mAppLabel);\n                                }\n                            });\n                        }))\n                        .setNegativeButton(R.string.cancel, (dialog, which, keepData) -> {\n                            if (dialog != null) dialog.cancel();\n                        });\n                if ((mApplicationInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0) {\n                    builder.setNeutralButton(R.string.uninstall_updates, (dialog, which, keepData) ->\n                            ThreadUtils.postOnBackgroundThread(() -> {\n                                PackageInstallerCompat installer = PackageInstallerCompat.getNewInstance();\n                                installer.setAppLabel(mAppLabel);\n                                boolean isSuccessful = installer.uninstall(mPackageName, UserHandleHidden.USER_ALL, keepData);\n                                if (isSuccessful) {\n                                    ThreadUtils.postOnMainThread(() -> displayLongToast(R.string.update_uninstalled_successfully, mAppLabel));\n                                } else {\n                                    ThreadUtils.postOnMainThread(() -> displayLongToast(R.string.failed_to_uninstall_updates, mAppLabel));\n                                }\n                            }));\n                }\n                builder.show();\n            });\n            // Enable/disable app (root/ADB only)\n            if (canFreeze && isFrozen) {\n                // Enable app\n                ActionItem unfreezeAction = new ActionItem(R.string.unfreeze, R.drawable.ic_snowflake_off);\n                actionItems.add(unfreezeAction);\n                unfreezeAction.setOnClickListener(v -> freeze(false))\n                        .setOnLongClickListener(v -> {\n                            createFreezeShortcut(true);\n                            return true;\n                        });\n            }\n            boolean accessibilityServiceRunning = UserHandleHidden.myUserId() == mUserId && ServiceHelper\n                    .checkIfServiceIsRunning(mActivity, NoRootAccessibilityService.class);\n            if (!isStaticSharedLib && (SelfPermissions.checkSelfOrRemotePermission(ManifestCompat.permission.FORCE_STOP_PACKAGES)\n                    || accessibilityServiceRunning)) {\n                // Force stop\n                if (!ApplicationInfoCompat.isStopped(mApplicationInfo) &&\n                        (SelfPermissions.checkSelfOrRemotePermission(ManifestCompat.permission.FORCE_STOP_PACKAGES)\n                                || accessibilityServiceRunning)) {\n                    ActionItem forceStopAction = new ActionItem(R.string.force_stop, R.drawable.ic_power_settings);\n                    actionItems.add(forceStopAction);\n                    forceStopAction.setOnClickListener(v -> {\n                        if (SelfPermissions.checkSelfOrRemotePermission(ManifestCompat.permission.FORCE_STOP_PACKAGES)) {\n                            ThreadUtils.postOnBackgroundThread(() -> {\n                                try {\n                                    PackageManagerCompat.forceStopPackage(mPackageName, mUserId);\n                                } catch (SecurityException e) {\n                                    Log.e(TAG, e);\n                                    displayLongToast(R.string.failed_to_stop, mAppLabel);\n                                }\n                            });\n                        } else {\n                            // Use accessibility\n                            AccessibilityMultiplexer.getInstance().enableForceStop(true);\n                            mActivityLauncher.launch(IntentUtils.getAppDetailsSettings(mPackageName),\n                                    result -> {\n                                        AccessibilityMultiplexer.getInstance().enableForceStop(false);\n                                        refreshDetails();\n                                    });\n                        }\n                    });\n                }\n            }\n            if (!isStaticSharedLib && (SelfPermissions.checkSelfOrRemotePermission(ManifestCompat.permission.CLEAR_APP_USER_DATA)\n                    || accessibilityServiceRunning)) {\n                // Clear data\n                ActionItem clearDataAction = new ActionItem(R.string.clear_data, R.drawable.ic_clear_data);\n                actionItems.add(clearDataAction);\n                clearDataAction.setOnClickListener(v -> new MaterialAlertDialogBuilder(mActivity)\n                        .setTitle(mAppLabel)\n                        .setMessage(R.string.clear_data_message)\n                        .setPositiveButton(R.string.clear, (dialog, which) -> {\n                            if (SelfPermissions.checkSelfOrRemotePermission(ManifestCompat.permission.CLEAR_APP_USER_DATA)) {\n                                ThreadUtils.postOnBackgroundThread(() -> {\n                                    boolean success = PackageManagerCompat\n                                            .clearApplicationUserData(mPackageName, mUserId);\n                                    ThreadUtils.postOnMainThread(() -> {\n                                        if (success) {\n                                            UIUtils.displayShortToast(R.string.done);\n                                        } else UIUtils.displayShortToast(R.string.failed);\n                                    });\n                                });\n                            } else {\n                                // Use accessibility\n                                AccessibilityMultiplexer.getInstance().enableNavigateToStorageAndCache(true);\n                                AccessibilityMultiplexer.getInstance().enableClearData(true);\n                                mActivityLauncher.launch(IntentUtils.getAppDetailsSettings(mPackageName),\n                                        result -> {\n                                            AccessibilityMultiplexer.getInstance().enableNavigateToStorageAndCache(true);\n                                            AccessibilityMultiplexer.getInstance().enableClearData(false);\n                                            refreshDetails();\n                                        });\n                            }\n                        })\n                        .setNegativeButton(R.string.cancel, null)\n                        .show());\n            }\n            if (!isStaticSharedLib && (SelfPermissions.canClearAppCache() || accessibilityServiceRunning)) {\n                // Clear cache\n                ActionItem clearCacheAction = new ActionItem(R.string.clear_cache, R.drawable.ic_clear_cache);\n                actionItems.add(clearCacheAction);\n                clearCacheAction.setOnClickListener(v -> {\n                    if (SelfPermissions.canClearAppCache()) {\n                        ThreadUtils.postOnBackgroundThread(() -> {\n                            boolean success = PackageManagerCompat\n                                    .deleteApplicationCacheFilesAsUser(mPackageName, mUserId);\n                            ThreadUtils.postOnMainThread(() -> {\n                                if (success) {\n                                    UIUtils.displayShortToast(R.string.done);\n                                } else UIUtils.displayShortToast(R.string.failed);\n                            });\n                        });\n                    } else {\n                        // Use accessibility\n                        AccessibilityMultiplexer.getInstance().enableNavigateToStorageAndCache(true);\n                        AccessibilityMultiplexer.getInstance().enableClearCache(true);\n                        mActivityLauncher.launch(IntentUtils.getAppDetailsSettings(mPackageName),\n                                result -> {\n                                    AccessibilityMultiplexer.getInstance().enableNavigateToStorageAndCache(false);\n                                    AccessibilityMultiplexer.getInstance().enableClearCache(false);\n                                    refreshDetails();\n                                });\n                    }\n                });\n            } else {\n                // Display Android settings button\n                ActionItem settingAction = new ActionItem(R.string.view_in_settings, R.drawable.ic_settings);\n                actionItems.add(settingAction);\n                settingAction.setOnClickListener(v -> {\n                    try {\n                        ActivityManagerCompat.startActivity(IntentUtils.getAppDetailsSettings(mPackageName), mUserId);\n                    } catch (Throwable th) {\n                        UIUtils.displayLongToast(\"Error: \" + th.getLocalizedMessage());\n                    }\n                });\n            }\n        } else if (FeatureController.isInstallerEnabled()) {\n            if (mInstalledPackageInfo == null) {\n                // App not installed\n                ActionItem installAction = new ActionItem(R.string.install, R.drawable.ic_get_app);\n                actionItems.add(installAction);\n                installAction.setOnClickListener(v -> install());\n            } else {\n                // App is installed\n                long installedVersionCode = PackageInfoCompat.getLongVersionCode(mInstalledPackageInfo);\n                long thisVersionCode = PackageInfoCompat.getLongVersionCode(mPackageInfo);\n                if (installedVersionCode < thisVersionCode) {\n                    // Needs update\n                    ActionItem whatsNewAction = new ActionItem(R.string.whats_new, io.github.muntashirakon.ui.R.drawable.ic_information);\n                    actionItems.add(whatsNewAction);\n                    whatsNewAction.setOnClickListener(v -> {\n                        WhatsNewDialogFragment dialogFragment = WhatsNewDialogFragment\n                                .getInstance(mPackageInfo, mInstalledPackageInfo);\n                        dialogFragment.show(getChildFragmentManager(), WhatsNewDialogFragment.TAG);\n                    });\n                    ActionItem updateAction = new ActionItem(R.string.update, R.drawable.ic_get_app);\n                    actionItems.add(updateAction);\n                    updateAction.setOnClickListener(v -> install());\n                } else if (installedVersionCode == thisVersionCode) {\n                    // Needs reinstall\n                    ActionItem reinstallAction = new ActionItem(R.string.reinstall, R.drawable.ic_get_app);\n                    actionItems.add(reinstallAction);\n                    reinstallAction.setOnClickListener(v -> install());\n                } else if (SelfPermissions.checkSelfOrRemotePermission(Manifest.permission.INSTALL_PACKAGES)) {\n                    // Needs downgrade\n                    ActionItem downgradeAction = new ActionItem(R.string.downgrade, R.drawable.ic_get_app);\n                    actionItems.add(downgradeAction);\n                    downgradeAction.setOnClickListener(v -> install());\n                }\n            }\n        }\n        // Set manifest\n        if (FeatureController.isManifestEnabled()) {\n            ActionItem manifestAction = new ActionItem(R.string.manifest, R.drawable.ic_package);\n            actionItems.add(manifestAction);\n            manifestAction.setOnClickListener(v -> {\n                Intent intent = new Intent(mActivity, ManifestViewerActivity.class);\n                startActivityForSplit(intent);\n            });\n        }\n        // Set scanner\n        if (FeatureController.isScannerEnabled()) {\n            ActionItem scannerAction = new ActionItem(R.string.scanner, R.drawable.ic_security);\n            actionItems.add(scannerAction);\n            scannerAction.setOnClickListener(v -> {\n                Intent intent = new Intent(mActivity, ScannerActivity.class);\n                intent.putExtra(ScannerActivity.EXTRA_IS_EXTERNAL, mIsExternalApk);\n                startActivityForSplit(intent);\n            });\n        }\n        // Root only features\n        if (!mIsExternalApk) {\n            // Shared prefs (root only)\n            final List<Path> sharedPrefs = new ArrayList<>();\n            Path[] tmpPaths = getSharedPrefs(mApplicationInfo.dataDir);\n            if (tmpPaths != null) sharedPrefs.addAll(Arrays.asList(tmpPaths));\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {\n                tmpPaths = getSharedPrefs(mApplicationInfo.deviceProtectedDataDir);\n                if (tmpPaths != null) sharedPrefs.addAll(Arrays.asList(tmpPaths));\n            }\n            if (!sharedPrefs.isEmpty()) {\n                CharSequence[] sharedPrefNames = new CharSequence[sharedPrefs.size()];\n                for (int i = 0; i < sharedPrefs.size(); ++i) {\n                    sharedPrefNames[i] = sharedPrefs.get(i).getName();\n                }\n                ActionItem sharedPrefsAction = new ActionItem(R.string.shared_prefs, R.drawable.ic_view_list);\n                actionItems.add(sharedPrefsAction);\n                sharedPrefsAction.setOnClickListener(v -> new SearchableItemsDialogBuilder<>(mActivity, sharedPrefNames)\n                        .setTitle(R.string.shared_prefs)\n                        .setOnItemClickListener((dialog, which, item) -> {\n                            Intent intent = new Intent(mActivity, SharedPrefsActivity.class);\n                            intent.putExtra(SharedPrefsActivity.EXTRA_PREF_LOCATION, sharedPrefs.get(which).getUri());\n                            intent.putExtra(SharedPrefsActivity.EXTRA_PREF_LABEL, mAppLabel);\n                            startActivity(intent);\n                        })\n                        .setNegativeButton(R.string.ok, null)\n                        .show());\n            }\n            // Databases (root only)\n            final List<Path> databases = new ArrayList<>();\n            tmpPaths = getDatabases(mApplicationInfo.dataDir);\n            if (tmpPaths != null) databases.addAll(Arrays.asList(tmpPaths));\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {\n                tmpPaths = getDatabases(mApplicationInfo.deviceProtectedDataDir);\n                if (tmpPaths != null) databases.addAll(Arrays.asList(tmpPaths));\n            }\n            if (!databases.isEmpty()) {\n                CharSequence[] databases2 = new CharSequence[databases.size()];\n                for (int i = 0; i < databases.size(); ++i) {\n                    databases2[i] = databases.get(i).getName();\n                }\n                ActionItem dbAction = new ActionItem(R.string.databases, R.drawable.ic_database);\n                actionItems.add(dbAction);\n                dbAction.setOnClickListener(v -> new SearchableItemsDialogBuilder<>(v.getContext(), databases2)\n                        .setTitle(R.string.databases)\n                        .setOnItemClickListener((dialog, which, item) -> ThreadUtils.postOnBackgroundThread(() -> {\n                            // Vacuum database\n                            Runner.runCommand(new String[]{\"sqlite3\", databases.get(which).getFilePath(), \"vacuum\"});\n                            ThreadUtils.postOnMainThread(() -> {\n                                OpenWithDialogFragment fragment = OpenWithDialogFragment.getInstance(databases.get(which), \"application/vnd.sqlite3\");\n                                if (isDetached()) return;\n                                fragment.show(getChildFragmentManager(), OpenWithDialogFragment.TAG);\n                            });\n                        }))\n                        .setNegativeButton(R.string.close, null)\n                        .show());\n            }\n        }  // End root only features\n        // Set F-Droid\n        Intent fdroidIntent = new Intent(Intent.ACTION_VIEW);\n        fdroidIntent.setData(Uri.parse(\"https://f-droid.org/packages/\" + mPackageName));\n        List<ResolveInfo> resolvedActivities = mPackageManager.queryIntentActivities(fdroidIntent, 0);\n        if (!resolvedActivities.isEmpty()) {\n            ActionItem fdroidItem = new ActionItem(R.string.fdroid, R.drawable.ic_frost_fdroid);\n            actionItems.add(fdroidItem);\n            fdroidItem.setOnClickListener(v -> {\n                try {\n                    startActivity(fdroidIntent);\n                } catch (Exception ignored) {\n                }\n            });\n        }\n        // Set Aurora Store\n        try {\n            PackageInfo auroraInfo = mPackageManager.getPackageInfo(PACKAGE_NAME_AURORA_STORE, 0);\n            if (PackageInfoCompat.getLongVersionCode(auroraInfo) == 36L || !auroraInfo.applicationInfo.enabled) {\n                // Aurora Store is disabled or the installed version has promotional apps\n                throw new PackageManager.NameNotFoundException();\n            }\n            ActionItem auroraStoreAction = new ActionItem(R.string.open_in_aurora_store, R.drawable.ic_frost_aurorastore);\n            actionItems.add(auroraStoreAction);\n            auroraStoreAction.setOnClickListener(v -> {\n                Intent intent = new Intent(Intent.ACTION_VIEW);\n                intent.setPackage(PACKAGE_NAME_AURORA_STORE);\n                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);\n                intent.setData(Uri.parse(\"https://play.google.com/store/apps/details?id=\" + mPackageName));\n                try {\n                    startActivity(intent);\n                } catch (Exception ignored) {\n                }\n            });\n        } catch (PackageManager.NameNotFoundException ignored) {\n        }\n        return actionItems;\n    }\n\n    @UiThread\n    private void startActivityForSplit(Intent intent) {\n        if (mMainModel == null) return;\n        ApkFile apkFile = mMainModel.getApkFile();\n        if (apkFile != null && apkFile.isSplit()) {\n            // Display a list of apks\n            List<ApkFile.Entry> apkEntries = apkFile.getEntries();\n            CharSequence[] entryNames = new CharSequence[apkEntries.size()];\n            for (int i = 0; i < apkEntries.size(); ++i) {\n                entryNames[i] = apkEntries.get(i).toShortLocalizedString(requireActivity());\n            }\n            new SearchableItemsDialogBuilder<>(mActivity, entryNames)\n                    .setTitle(R.string.select_apk)\n                    .setOnItemClickListener((dialog, which, item) -> ThreadUtils.postOnBackgroundThread(() -> {\n                        try {\n                            File file = apkEntries.get(which).getFile(false);\n                            intent.setDataAndType(Uri.fromFile(file), MimeTypeMap.getSingleton()\n                                    .getMimeTypeFromExtension(\"apk\"));\n                            ThreadUtils.postOnMainThread(() -> {\n                                if (isDetached()) return;\n                                startActivity(intent);\n                            });\n                        } catch (IOException e) {\n                            UIUtils.displayLongToast(\"Error: \" + e.getMessage());\n                        }\n                    }))\n                    .setNegativeButton(R.string.cancel, null)\n                    .show();\n        } else {\n            // Open directly\n            File file = new File(mApplicationInfo.publicSourceDir);\n            intent.setDataAndType(Uri.fromFile(file), MimeTypeMap.getSingleton().getMimeTypeFromExtension(\"apk\"));\n            startActivity(intent);\n        }\n    }\n\n    @GuardedBy(\"mListItems\")\n    private void setPathsAndDirectories(@NonNull AppInfoViewModel.AppInfo appInfo) {\n        synchronized (mListItems) {\n            // Paths and directories\n            mListItems.add(ListItem.newGroupStart(getString(R.string.paths_and_directories)));\n            // Source directory (apk path)\n            if (appInfo.sourceDir != null) {\n                ListItem listItem = ListItem.newSelectableRegularItem(getString(R.string.source_dir),\n                        appInfo.sourceDir, openAsFolderInFM(requireContext(), appInfo.sourceDir));\n                listItem.setActionContentDescription(R.string.open);\n                mListItems.add(listItem);\n            }\n            // Data dir\n            if (appInfo.dataDir != null) {\n                ListItem listItem = ListItem.newSelectableRegularItem(getString(R.string.data_dir),\n                        appInfo.dataDir, openAsFolderInFM(requireContext(), appInfo.dataDir));\n                listItem.setActionContentDescription(R.string.open);\n                mListItems.add(listItem);\n            }\n            // Device-protected data dir\n            if (appInfo.dataDeDir != null) {\n                ListItem listItem = ListItem.newSelectableRegularItem(getString(R.string.dev_protected_data_dir),\n                        appInfo.dataDeDir, openAsFolderInFM(requireContext(), appInfo.dataDeDir));\n                listItem.setActionContentDescription(R.string.open);\n                mListItems.add(listItem);\n            }\n            // External data dirs\n            if (appInfo.extDataDirs.size() == 1) {\n                ListItem listItem = ListItem.newSelectableRegularItem(getString(R.string.external_data_dir),\n                        appInfo.extDataDirs.get(0), openAsFolderInFM(requireContext(),\n                                appInfo.extDataDirs.get(0)));\n                listItem.setActionContentDescription(R.string.open);\n                mListItems.add(listItem);\n            } else {\n                for (int i = 0; i < appInfo.extDataDirs.size(); ++i) {\n                    ListItem listItem = ListItem.newSelectableRegularItem(getString(R.string.external_multiple_data_dir, i),\n                            appInfo.extDataDirs.get(i), openAsFolderInFM(requireContext(),\n                                    appInfo.extDataDirs.get(i)));\n                    listItem.setActionContentDescription(R.string.open);\n                    mListItems.add(listItem);\n                }\n            }\n            // Native JNI library dir\n            if (appInfo.jniDir != null) {\n                ListItem listItem = ListItem.newSelectableRegularItem(getString(R.string.native_library_dir), appInfo.jniDir,\n                        openAsFolderInFM(requireContext(), appInfo.jniDir));\n                listItem.setActionContentDescription(R.string.open);\n                mListItems.add(listItem);\n            }\n        }\n    }\n\n    @GuardedBy(\"mListItems\")\n    private void setMoreInfo(AppInfoViewModel.AppInfo appInfo) {\n        synchronized (mListItems) {\n            // Set more info\n            mListItems.add(ListItem.newGroupStart(getString(R.string.more_info)));\n\n            // Set installed version info\n            if (mIsExternalApk && mInstalledPackageInfo != null) {\n                ListItem listItem = ListItem.newSelectableRegularItem(getString(R.string.installed_version),\n                        getString(R.string.version_name_with_code, mInstalledPackageInfo.versionName,\n                                PackageInfoCompat.getLongVersionCode(mInstalledPackageInfo)), v -> {\n                            Intent intent = AppDetailsActivity.getIntent(mActivity, mPackageName,\n                                    UserHandleHidden.myUserId());\n                            mActivity.startActivity(intent);\n                        });\n                listItem.setActionIcon(io.github.muntashirakon.ui.R.drawable.ic_information);\n                listItem.setActionContentDescription(R.string.app_info);\n                mListItems.add(listItem);\n            }\n\n            // SDK\n            final StringBuilder sdk = new StringBuilder();\n            sdk.append(getString(R.string.sdk_max)).append(LangUtils.getSeparatorString()).append(String.format(Locale.getDefault(), \"%d\",\n                    mApplicationInfo.targetSdkVersion));\n            if (Build.VERSION.SDK_INT > Build.VERSION_CODES.M) {\n                sdk.append(\", \").append(getString(R.string.sdk_min)).append(LangUtils.getSeparatorString())\n                        .append(String.format(Locale.getDefault(), \"%d\", mApplicationInfo.minSdkVersion));\n            }\n            mListItems.add(ListItem.newSelectableRegularItem(getString(R.string.sdk), sdk.toString()));\n\n            // Set Flags\n            final StringBuilder flags = new StringBuilder();\n            if ((mPackageInfo.applicationInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0)\n                flags.append(\"FLAG_DEBUGGABLE\");\n            if ((mPackageInfo.applicationInfo.flags & ApplicationInfo.FLAG_TEST_ONLY) != 0)\n                flags.append(flags.length() == 0 ? \"\" : \"|\").append(\"FLAG_TEST_ONLY\");\n            if ((mPackageInfo.applicationInfo.flags & ApplicationInfo.FLAG_MULTIARCH) != 0)\n                flags.append(flags.length() == 0 ? \"\" : \"|\").append(\"FLAG_MULTIARCH\");\n            if ((mPackageInfo.applicationInfo.flags & ApplicationInfo.FLAG_HARDWARE_ACCELERATED) != 0)\n                flags.append(flags.length() == 0 ? \"\" : \"|\").append(\"FLAG_HARDWARE_ACCELERATED\");\n\n            if (flags.length() != 0) {\n                ListItem flagsItem = ListItem.newSelectableRegularItem(getString(R.string.sdk_flags), flags.toString());\n                flagsItem.setMonospace(true);\n                mListItems.add(flagsItem);\n            }\n            if (mIsExternalApk) return;\n\n            mListItems.add(ListItem.newRegularItem(getString(R.string.date_installed), getTime(mPackageInfo.firstInstallTime)));\n            mListItems.add(ListItem.newRegularItem(getString(R.string.date_updated), getTime(mPackageInfo.lastUpdateTime)));\n            if (!mPackageName.equals(mApplicationInfo.processName)) {\n                mListItems.add(ListItem.newSelectableRegularItem(getString(R.string.process_name), mApplicationInfo.processName));\n            }\n            if (appInfo.installerApp != null) {\n                ListItem installerItem = ListItem.newSelectableRegularItem(\n                        getString(R.string.installer_app), appInfo.installerApp,\n                        v -> displayInstallerDialog(Objects.requireNonNull(appInfo.installSource)));\n                installerItem.setActionIcon(R.drawable.ic_information_circle);\n                installerItem.setActionContentDescription(R.string.more_info);\n                mListItems.add(installerItem);\n            }\n            mListItems.add(ListItem.newSelectableRegularItem(getString(R.string.user_id), String.format(Locale.getDefault(), \"%d\",\n                    mApplicationInfo.uid)));\n            if (mPackageInfo.sharedUserId != null)\n                mListItems.add(ListItem.newSelectableRegularItem(getString(R.string.shared_user_id), mPackageInfo.sharedUserId));\n            if (appInfo.primaryCpuAbi != null) {\n                mListItems.add(ListItem.newSelectableRegularItem(getString(R.string.primary_abi),\n                        appInfo.primaryCpuAbi));\n            }\n            if (appInfo.zygotePreloadName != null) {\n                mListItems.add(ListItem.newSelectableRegularItem(getString(R.string.zygote_preload_name),\n                        appInfo.zygotePreloadName));\n            }\n            if (!mIsExternalApk) {\n                mListItems.add(ListItem.newRegularItem(getString(R.string.hidden_api_enforcement_policy),\n                        getHiddenApiEnforcementPolicy(appInfo.hiddenApiEnforcementPolicy)));\n            }\n            if (appInfo.seInfo != null) {\n                mListItems.add(ListItem.newSelectableRegularItem(getString(R.string.selinux), appInfo.seInfo));\n            }\n            // Main activity\n            if (appInfo.mainActivity != null) {\n                final ComponentName launchComponentName = appInfo.mainActivity.getComponent();\n                if (launchComponentName != null) {\n                    final String mainActivity = launchComponentName.getClassName();\n                    ListItem listItem = ListItem.newSelectableRegularItem(getString(R.string.main_activity),\n                            mainActivity, view -> startActivity(appInfo.mainActivity));\n                    listItem.setActionContentDescription(R.string.open);\n                    mListItems.add(listItem);\n                }\n            }\n        }\n    }\n\n    @NonNull\n    private String getHiddenApiEnforcementPolicy(int policy) {\n        switch (policy) {\n            case HIDDEN_API_ENFORCEMENT_DEFAULT:\n                return getString(R.string.hidden_api_enf_default_policy);\n            default:\n            case HIDDEN_API_ENFORCEMENT_DISABLED:\n                return getString(R.string.hidden_api_enf_policy_none);\n            case HIDDEN_API_ENFORCEMENT_JUST_WARN:\n                return getString(R.string.hidden_api_enf_policy_warn);\n            case HIDDEN_API_ENFORCEMENT_ENABLED:\n                return getString(R.string.hidden_api_enf_policy_dark_grey_and_black);\n            case HIDDEN_API_ENFORCEMENT_BLACK:\n                return getString(R.string.hidden_api_enf_policy_black);\n        }\n    }\n\n    private void setDataUsage(@NonNull AppInfoViewModel.AppInfo appInfo) {\n        AppUsageStatsManager.DataUsage dataUsage = appInfo.dataUsage;\n        if (dataUsage == null) {\n            // No permission\n            return;\n        }\n        // Hide data usage if:\n        // 1. OS is Android 6.0 onwards, AND\n        // 2. The user is not the current user, AND\n        // 3. Remote UID is not system UID\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M\n                && mUserId != UserHandleHidden.myUserId()\n                && !SelfPermissions.isSystem()) {\n            return;\n        }\n        synchronized (mListItems) {\n            if (isDetached()) return;\n            mListItems.add(ListItem.newGroupStart(getString(R.string.data_usage_msg)));\n            mListItems.add(ListItem.newInlineItem(getString(R.string.data_transmitted), getReadableSize(dataUsage.getTx())));\n            mListItems.add(ListItem.newInlineItem(getString(R.string.data_received), getReadableSize(dataUsage.getRx())));\n        }\n    }\n\n    @MainThread\n    @GuardedBy(\"mListItems\")\n    private void setupVerticalView(AppInfoViewModel.AppInfo appInfo) {\n        if (mListFuture != null) mListFuture.cancel(true);\n        mListFuture = ThreadUtils.postOnBackgroundThread(() -> {\n            synchronized (mListItems) {\n                mListItems.clear();\n                if (!mIsExternalApk) {\n                    setPathsAndDirectories(appInfo);\n                    setDataUsage(appInfo);\n                    // Storage and Cache\n                    if (FeatureController.isUsageAccessEnabled()) {\n                        setStorageAndCache(appInfo);\n                    }\n                }\n                setMoreInfo(appInfo);\n                ThreadUtils.postOnMainThread(() -> {\n                    if (isDetached()) return;\n                    ++mLoadedItemCount;\n                    if (mLoadedItemCount >= 4) {\n                        showProgressIndicator(false);\n                    }\n                    if (isDetached()) return;\n                    mAdapter.setAdapterList(mListItems);\n                });\n            }\n        });\n    }\n\n    @Nullable\n    private Path[] getSharedPrefs(@Nullable String sourceDir) {\n        if (sourceDir == null) return null;\n        try {\n            Path sharedPath = Paths.get(sourceDir).findFile(\"shared_prefs\");\n            return sharedPath.listFiles();\n        } catch (FileNotFoundException e) {\n            return null;\n        }\n\n    }\n\n    @Nullable\n    private Path[] getDatabases(@Nullable String sourceDir) {\n        if (sourceDir == null) return null;\n        try {\n            Path sharedPath = Paths.get(sourceDir).findFile(\"databases\");\n            return sharedPath.listFiles((dir, name) -> !(name.endsWith(\"-journal\")\n                    || name.endsWith(\"-wal\") || name.endsWith(\"-shm\")));\n        } catch (FileNotFoundException e) {\n            return null;\n        }\n    }\n\n    @GuardedBy(\"mListItems\")\n    private void setStorageAndCache(AppInfoViewModel.AppInfo appInfo) {\n        if (FeatureController.isUsageAccessEnabled()) {\n            // Grant optional READ_PHONE_STATE permission\n            if (AppUsageStatsManager.requireReadPhoneStatePermission()) {\n                ThreadUtils.postOnMainThread(() -> mRequestPerm.launch(Manifest.permission.READ_PHONE_STATE, granted -> {\n                    if (granted) {\n                        mAppInfoModel.loadAppInfo(mPackageInfo, mIsExternalApk);\n                    }\n                }));\n            }\n        }\n        if (!SelfPermissions.checkUsageStatsPermission()) {\n            ThreadUtils.postOnMainThread(() -> new MaterialAlertDialogBuilder(mActivity)\n                    .setTitle(R.string.grant_usage_access)\n                    .setMessage(R.string.grant_usage_acess_message)\n                    .setPositiveButton(R.string.go, (dialog, which) -> {\n                        try {\n                            mActivityLauncher.launch(new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS), result -> {\n                                if (SelfPermissions.checkUsageStatsPermission()) {\n                                    FeatureController.getInstance().modifyState(FeatureController\n                                            .FEAT_USAGE_ACCESS, true);\n                                    // Reload app info\n                                    mAppInfoModel.loadAppInfo(mPackageInfo, mIsExternalApk);\n                                }\n                            });\n                        } catch (SecurityException ignore) {\n                        }\n                    })\n                    .setNegativeButton(R.string.cancel, null)\n                    .setNeutralButton(R.string.never_ask, (dialog, which) -> FeatureController.getInstance().modifyState(\n                            FeatureController.FEAT_USAGE_ACCESS, false))\n                    .setCancelable(false)\n                    .show());\n            return;\n        }\n        PackageSizeInfo sizeInfo = appInfo.sizeInfo;\n        if (sizeInfo == null) return;\n        synchronized (mListItems) {\n            mListItems.add(ListItem.newGroupStart(getString(R.string.storage_and_cache)));\n            mListItems.add(ListItem.newInlineItem(getString(R.string.app_size), getReadableSize(sizeInfo.codeSize)));\n            mListItems.add(ListItem.newInlineItem(getString(R.string.data_size), getReadableSize(sizeInfo.dataSize)));\n            mListItems.add(ListItem.newInlineItem(getString(R.string.cache_size), getReadableSize(sizeInfo.cacheSize)));\n            if (sizeInfo.obbSize != 0) {\n                mListItems.add(ListItem.newInlineItem(getString(R.string.obb_size), getReadableSize(sizeInfo.obbSize)));\n            }\n            if (sizeInfo.mediaSize != 0) {\n                mListItems.add(ListItem.newInlineItem(getString(R.string.media_size), getReadableSize(sizeInfo.mediaSize)));\n            }\n            mListItems.add(ListItem.newInlineItem(getString(R.string.total_size), getReadableSize(sizeInfo.getTotalSize())));\n        }\n    }\n\n    @MainThread\n    private void freeze(boolean freeze) {\n        if (mMainModel == null) return;\n        if (freeze) {\n            mMainModel.loadFreezeType();\n        } else {\n            // Unfreeze\n            ThreadUtils.postOnBackgroundThread(this::doUnfreeze);\n        }\n    }\n\n    private void showFreezeDialog(int freezeType, boolean isCustom) {\n        View view = View.inflate(mActivity, R.layout.item_checkbox, null);\n        MaterialCheckBox checkBox = view.findViewById(R.id.checkbox);\n        checkBox.setText(R.string.remember_option_for_this_app);\n        checkBox.setChecked(isCustom);\n        FreezeUnfreeze.getFreezeDialog(mActivity, freezeType)\n                .setIcon(R.drawable.ic_snowflake)\n                .setTitle(R.string.freeze)\n                .setView(view)\n                .setPositiveButton(R.string.freeze, (dialog, which, selectedItem) -> {\n                    if (selectedItem == null) {\n                        return;\n                    }\n                    ThreadUtils.postOnBackgroundThread(() -> doFreeze(selectedItem, checkBox.isChecked()));\n                })\n                .setNegativeButton(R.string.cancel, null)\n                .show();\n    }\n\n    @WorkerThread\n    private void doFreeze(@FreezeUtils.FreezeMethod int freezeType, boolean remember) {\n        try {\n            if (remember) {\n                FreezeUtils.storeFreezeMethod(mPackageName, freezeType);\n            } else {\n                FreezeUtils.deleteFreezeMethod(mPackageName);\n            }\n            FreezeUtils.freeze(mPackageName, mUserId, freezeType);\n        } catch (Throwable th) {\n            Log.e(TAG, th);\n            ThreadUtils.postOnMainThread(() -> displayLongToast(R.string.failed_to_freeze, mAppLabel));\n        }\n    }\n\n    @WorkerThread\n    private void doUnfreeze() {\n        try {\n            FreezeUtils.unfreeze(mPackageName, mUserId);\n        } catch (Throwable th) {\n            Log.e(TAG, th);\n            ThreadUtils.postOnMainThread(() -> displayLongToast(R.string.failed_to_unfreeze, mAppLabel));\n        }\n    }\n\n    private void createFreezeShortcut(boolean isFrozen) {\n        if (mMainModel == null) return;\n        List<Integer> allFlags = new ArrayList<>(3);\n        for (int i = 0; i < 3; ++i) {\n            allFlags.add(1 << i);\n        }\n        new SearchableMultiChoiceDialogBuilder<>(mActivity, allFlags, R.array.freeze_unfreeze_flags)\n                .setTitle(R.string.freeze_unfreeze)\n                .setPositiveButton(R.string.create_shortcut, (dialog, which, selections) -> {\n                    int flags = 0;\n                    for (int flag : selections) {\n                        flags |= flag;\n                    }\n                    Bitmap icon = getBitmapFromDrawable(mIconView.getDrawable());\n                    FreezeUnfreezeShortcutInfo shortcutInfo = new FreezeUnfreezeShortcutInfo(mPackageName, mUserId, flags);\n                    shortcutInfo.setName(mAppLabel);\n                    shortcutInfo.setIcon(isFrozen ? getDimmedBitmap(icon) : icon);\n                    CreateShortcutDialogFragment dialog1 = CreateShortcutDialogFragment.getInstance(shortcutInfo);\n                    dialog1.show(getChildFragmentManager(), CreateShortcutDialogFragment.TAG);\n                })\n                .show();\n    }\n\n    private void displayInstallerDialog(@NonNull InstallSourceInfoCompat installSource) {\n        List<CharSequence> installerInfoList = new ArrayList<>(3);\n        List<String> packageNames = new ArrayList<>(3);\n        if (installSource.getInstallingPackageLabel() != null) {\n            CharSequence info = new SpannableStringBuilder(getSmallerText(getString(R.string.installer)))\n                    .append(\"\\n\")\n                    .append(getTitleText(requireContext(), installSource.getInstallingPackageLabel()))\n                    .append(\"\\n\")\n                    .append(installSource.getInstallingPackageName());\n            installerInfoList.add(info);\n            packageNames.add(installSource.getInstallingPackageName());\n        }\n        if (installSource.getInitiatingPackageLabel() != null) {\n            CharSequence info = new SpannableStringBuilder(getSmallerText(getString(R.string.actual_installer)))\n                    .append(\"\\n\")\n                    .append(getTitleText(requireContext(), installSource.getInitiatingPackageLabel()))\n                    .append(\"\\n\")\n                    .append(installSource.getInitiatingPackageName());\n            installerInfoList.add(info);\n            packageNames.add(installSource.getInitiatingPackageName());\n        }\n        if (installSource.getOriginatingPackageLabel() != null) {\n            CharSequence info = new SpannableStringBuilder(getSmallerText(getString(R.string.apk_source)))\n                    .append(\"\\n\")\n                    .append(getTitleText(requireContext(), installSource.getOriginatingPackageLabel()))\n                    .append(\"\\n\")\n                    .append(installSource.getOriginatingPackageName());\n            installerInfoList.add(info);\n            packageNames.add(installSource.getOriginatingPackageName());\n        }\n        new SearchableItemsDialogBuilder<>(requireContext(), installerInfoList)\n                .setTitle(R.string.installer)\n                .setOnItemClickListener((dialog, which, item) -> {\n                    String packageName = packageNames.get(which);\n                    Intent intent = AppDetailsActivity.getIntent(requireContext(), packageName, mUserId);\n                    startActivity(intent);\n                })\n                .setNegativeButton(R.string.close, null)\n                .show();\n    }\n\n    /**\n     * Get Unix time to formatted time.\n     *\n     * @param time Unix time\n     * @return Formatted time\n     */\n    @NonNull\n    private String getTime(long time) {\n        return DateUtils.formatLongDateTime(requireContext(), time);\n    }\n\n    /**\n     * Format sizes (bytes to B, KB, MB etc.).\n     *\n     * @param size Size in Bytes\n     * @return Formatted size\n     */\n    private String getReadableSize(long size) {\n        return Formatter.formatFileSize(mActivity, size);\n    }\n\n    private void showProgressIndicator(boolean show) {\n        if (mProgressIndicator == null) return;\n        if (show) mProgressIndicator.show();\n        else mProgressIndicator.hide();\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/details/info/AppInfoRecyclerAdapter.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.details.info;\n\nimport android.content.Context;\nimport android.graphics.Typeface;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.TextView;\n\nimport androidx.annotation.NonNull;\nimport androidx.appcompat.widget.LinearLayoutCompat;\nimport androidx.recyclerview.widget.RecyclerView;\n\nimport com.google.android.material.button.MaterialButton;\nimport com.google.android.material.divider.MaterialDivider;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.util.AdapterUtils;\n\nimport static io.github.muntashirakon.AppManager.details.info.ListItem.LIST_ITEM_GROUP_BEGIN;\nimport static io.github.muntashirakon.AppManager.details.info.ListItem.LIST_ITEM_INLINE;\nimport static io.github.muntashirakon.AppManager.details.info.ListItem.LIST_ITEM_REGULAR;\nimport static io.github.muntashirakon.AppManager.details.info.ListItem.LIST_ITEM_REGULAR_ACTION;\n\nclass AppInfoRecyclerAdapter extends RecyclerView.Adapter<AppInfoRecyclerAdapter.ViewHolder> {\n    private final Context mContext;\n    private final List<ListItem> mAdapterList;\n\n    AppInfoRecyclerAdapter(Context context) {\n        mContext = context;\n        mAdapterList = new ArrayList<>();\n    }\n\n    void setAdapterList(@NonNull List<ListItem> list) {\n        AdapterUtils.notifyDataSetChanged(this, mAdapterList, list);\n    }\n\n    @Override\n    @ListItem.ListItemType\n    public int getItemViewType(int position) {\n        return mAdapterList.get(position).type;\n    }\n\n    @NonNull\n    @Override\n    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, @ListItem.ListItemType int viewType) {\n        final View view;\n        switch (viewType) {\n            case LIST_ITEM_GROUP_BEGIN:\n                view = LayoutInflater.from(parent.getContext()).inflate(io.github.muntashirakon.ui.R.layout.m3_preference_category, parent, false);\n                break;\n            default:\n            case LIST_ITEM_REGULAR:\n                view = LayoutInflater.from(parent.getContext()).inflate(io.github.muntashirakon.ui.R.layout.m3_preference, parent, false);\n                break;\n            case LIST_ITEM_REGULAR_ACTION: {\n                view = LayoutInflater.from(parent.getContext()).inflate(io.github.muntashirakon.ui.R.layout.m3_preference, parent, false);\n                View action = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_right_standalone_action, parent, false);\n                LinearLayoutCompat layoutCompat = view.findViewById(android.R.id.widget_frame);\n                layoutCompat.addView(action);\n                break;\n            }\n            case LIST_ITEM_INLINE: {\n                view = LayoutInflater.from(parent.getContext()).inflate(io.github.muntashirakon.ui.R.layout.m3_preference, parent, false);\n                View action = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_right_summary, parent, false);\n                LinearLayoutCompat layoutCompat = view.findViewById(android.R.id.widget_frame);\n                layoutCompat.addView(action);\n                break;\n            }\n        }\n        return new ViewHolder(view, viewType);\n    }\n\n    @Override\n    public void onBindViewHolder(@NonNull ViewHolder holder, int position) {\n        ListItem listItem = mAdapterList.get(position);\n        // Set title\n        holder.title.setText(listItem.getTitle());\n        if (listItem.type == LIST_ITEM_GROUP_BEGIN) {\n            return;\n        }\n        // Set common properties\n        holder.subtitle.setText(listItem.getSubtitle());\n        holder.subtitle.setTextIsSelectable(listItem.isSelectable());\n        holder.subtitle.setTypeface(listItem.isMonospace() ? Typeface.MONOSPACE : Typeface.DEFAULT);\n        if (listItem.type == LIST_ITEM_INLINE) {\n            return;\n        }\n        if (listItem.type == LIST_ITEM_REGULAR_ACTION) {\n            holder.actionDivider.setVisibility(listItem.getOnActionClickListener() != null ? View.VISIBLE : View.GONE);\n            if (listItem.getActionIconRes() != 0) {\n                holder.actionIcon.setIconResource(listItem.getActionIconRes());\n            }\n            if (listItem.getActionContentDescription() != null) {\n                holder.actionIcon.setContentDescription(listItem.getActionContentDescription());\n            } else if (listItem.getActionContentDescriptionRes() != 0) {\n                holder.actionIcon.setContentDescription(mContext.getString(listItem.getActionContentDescriptionRes()));\n            }\n            if (listItem.getOnActionClickListener() != null) {\n                holder.actionIcon.setVisibility(View.VISIBLE);\n                holder.actionIcon.setOnClickListener(listItem.getOnActionClickListener());\n            } else holder.actionIcon.setVisibility(View.GONE);\n        }\n    }\n\n    @Override\n    public int getItemCount() {\n        return mAdapterList.size();\n    }\n\n    static class ViewHolder extends RecyclerView.ViewHolder {\n        TextView title;\n        TextView subtitle;\n        MaterialButton actionIcon;\n        MaterialDivider actionDivider;\n\n        public ViewHolder(@NonNull View itemView, @ListItem.ListItemType int viewType) {\n            super(itemView);\n            itemView.findViewById(R.id.icon_frame).setVisibility(View.GONE);\n            switch (viewType) {\n                case LIST_ITEM_GROUP_BEGIN: {\n                    title = itemView.findViewById(android.R.id.title);\n                    itemView.findViewById(android.R.id.summary).setVisibility(View.GONE);\n                    break;\n                }\n                case LIST_ITEM_REGULAR:\n                case LIST_ITEM_REGULAR_ACTION:\n                    title = itemView.findViewById(android.R.id.title);\n                    subtitle = itemView.findViewById(android.R.id.summary);\n                    actionDivider = itemView.findViewById(R.id.divider);\n                    actionIcon = itemView.findViewById(android.R.id.button1);\n                    break;\n                default:\n                    break;\n                case LIST_ITEM_INLINE:\n                    title = itemView.findViewById(android.R.id.title);\n                    subtitle = itemView.findViewById(android.R.id.text1);\n                    itemView.findViewById(android.R.id.summary).setVisibility(View.GONE);\n                    break;\n            }\n        }\n    }\n}"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/details/info/AppInfoViewModel.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.details.info;\n\nimport android.Manifest;\nimport android.annotation.UserIdInt;\nimport android.app.ActivityManager;\nimport android.app.Application;\nimport android.content.Intent;\nimport android.content.pm.ApplicationInfo;\nimport android.content.pm.PackageInfo;\nimport android.content.pm.PackageManager;\nimport android.content.pm.verify.domain.DomainVerificationUserState;\nimport android.os.Build;\nimport android.os.UserHandleHidden;\nimport android.text.TextUtils;\n\nimport androidx.annotation.AnyThread;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.WorkerThread;\nimport androidx.core.util.Pair;\nimport androidx.lifecycle.AndroidViewModel;\nimport androidx.lifecycle.LiveData;\nimport androidx.lifecycle.MutableLiveData;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.Future;\nimport java.util.zip.ZipFile;\n\nimport io.github.muntashirakon.AppManager.StaticDataset;\nimport io.github.muntashirakon.AppManager.apk.installer.PackageInstallerCompat;\nimport io.github.muntashirakon.AppManager.apk.installer.PackageInstallerService;\nimport io.github.muntashirakon.AppManager.backup.BackupUtils;\nimport io.github.muntashirakon.AppManager.compat.ActivityManagerCompat;\nimport io.github.muntashirakon.AppManager.compat.ApplicationInfoCompat;\nimport io.github.muntashirakon.AppManager.compat.DeviceIdleManagerCompat;\nimport io.github.muntashirakon.AppManager.compat.DomainVerificationManagerCompat;\nimport io.github.muntashirakon.AppManager.compat.InstallSourceInfoCompat;\nimport io.github.muntashirakon.AppManager.compat.ManifestCompat;\nimport io.github.muntashirakon.AppManager.compat.NetworkPolicyManagerCompat;\nimport io.github.muntashirakon.AppManager.compat.PackageInfoCompat2;\nimport io.github.muntashirakon.AppManager.compat.PackageManagerCompat;\nimport io.github.muntashirakon.AppManager.compat.SensorServiceCompat;\nimport io.github.muntashirakon.AppManager.db.entity.Backup;\nimport io.github.muntashirakon.AppManager.debloat.DebloatObject;\nimport io.github.muntashirakon.AppManager.details.AppDetailsViewModel;\nimport io.github.muntashirakon.AppManager.magisk.MagiskDenyList;\nimport io.github.muntashirakon.AppManager.magisk.MagiskHide;\nimport io.github.muntashirakon.AppManager.magisk.MagiskProcess;\nimport io.github.muntashirakon.AppManager.magisk.MagiskUtils;\nimport io.github.muntashirakon.AppManager.misc.OsEnvironment;\nimport io.github.muntashirakon.AppManager.misc.XposedModuleInfo;\nimport io.github.muntashirakon.AppManager.rules.RuleType;\nimport io.github.muntashirakon.AppManager.rules.compontents.ComponentUtils;\nimport io.github.muntashirakon.AppManager.rules.struct.ComponentRule;\nimport io.github.muntashirakon.AppManager.self.SelfPermissions;\nimport io.github.muntashirakon.AppManager.settings.FeatureController;\nimport io.github.muntashirakon.AppManager.settings.Prefs;\nimport io.github.muntashirakon.AppManager.ssaid.SsaidSettings;\nimport io.github.muntashirakon.AppManager.types.PackageSizeInfo;\nimport io.github.muntashirakon.AppManager.uri.UriManager;\nimport io.github.muntashirakon.AppManager.usage.AppUsageStatsManager;\nimport io.github.muntashirakon.AppManager.usage.TimeInterval;\nimport io.github.muntashirakon.AppManager.usage.UsageUtils;\nimport io.github.muntashirakon.AppManager.utils.ArrayUtils;\nimport io.github.muntashirakon.AppManager.utils.ExUtils;\nimport io.github.muntashirakon.AppManager.utils.KeyStoreUtils;\nimport io.github.muntashirakon.AppManager.utils.PackageUtils;\nimport io.github.muntashirakon.AppManager.utils.ThreadUtils;\nimport io.github.muntashirakon.io.Path;\nimport io.github.muntashirakon.io.Paths;\n\npublic class AppInfoViewModel extends AndroidViewModel {\n    private final MutableLiveData<CharSequence> mAppLabel = new MutableLiveData<>();\n    private final MutableLiveData<TagCloud> mTagCloud = new MutableLiveData<>();\n    private final MutableLiveData<AppInfo> mAppInfo = new MutableLiveData<>();\n    private final MutableLiveData<Pair<Integer, CharSequence>> mInstallExistingResult = new MutableLiveData<>();\n    private final ExecutorService mExecutor = Executors.newFixedThreadPool(4);\n    private Future<?> mTagCloudFuture;\n    private Future<?> mAppInfoFuture;\n    @Nullable\n    private AppDetailsViewModel mMainModel;\n\n    public AppInfoViewModel(@NonNull Application application) {\n        super(application);\n    }\n\n    @Override\n    protected void onCleared() {\n        if (mTagCloudFuture != null) {\n            mTagCloudFuture.cancel(true);\n        }\n        if (mAppInfoFuture != null) {\n            mAppInfoFuture.cancel(true);\n        }\n        super.onCleared();\n    }\n\n    public void setMainModel(@NonNull AppDetailsViewModel mainModel) {\n        mMainModel = mainModel;\n    }\n\n    public LiveData<CharSequence> getAppLabel() {\n        return mAppLabel;\n    }\n\n    public LiveData<TagCloud> getTagCloud() {\n        return mTagCloud;\n    }\n\n    public LiveData<AppInfo> getAppInfo() {\n        return mAppInfo;\n    }\n\n    public LiveData<Pair<Integer, CharSequence>> getInstallExistingResult() {\n        return mInstallExistingResult;\n    }\n\n    @AnyThread\n    public void loadAppLabel(@NonNull ApplicationInfo applicationInfo) {\n        ThreadUtils.postOnBackgroundThread(() -> {\n            CharSequence appLabel = applicationInfo.loadLabel(getApplication().getPackageManager());\n            mAppLabel.postValue(appLabel);\n        });\n    }\n\n    @AnyThread\n    public void loadTagCloud(@NonNull PackageInfo packageInfo, boolean isExternalApk) {\n        if (mTagCloudFuture != null) {\n            mTagCloudFuture.cancel(true);\n        }\n        mTagCloudFuture = ThreadUtils.postOnBackgroundThread(() -> loadTagCloudInternal(packageInfo, isExternalApk));\n    }\n\n    @WorkerThread\n    private void loadTagCloudInternal(@NonNull PackageInfo packageInfo, boolean isExternalApk) {\n        if (mMainModel == null) return;\n        String packageName = packageInfo.packageName;\n        int userId = mMainModel.getUserId();\n        ApplicationInfo applicationInfo = packageInfo.applicationInfo;\n        TagCloud tagCloud = new TagCloud();\n        try {\n            Map<String, RuleType> trackerComponents = ComponentUtils.getTrackerComponentsForPackage(packageInfo);\n            tagCloud.trackerComponents = new ArrayList<>(trackerComponents.size());\n            for (String component : trackerComponents.keySet()) {\n                ComponentRule componentRule = mMainModel.getComponentRule(component);\n                if (componentRule == null) {\n                    componentRule = new ComponentRule(packageName, component, trackerComponents.get(component),\n                            Prefs.Blocking.getDefaultBlockingMethod());\n                }\n                tagCloud.trackerComponents.add(componentRule);\n                tagCloud.areAllTrackersBlocked &= componentRule.isBlocked();\n            }\n            if (ThreadUtils.isInterrupted()) {\n                return;\n            }\n            tagCloud.isSystemApp = ApplicationInfoCompat.isSystemApp(applicationInfo);\n            tagCloud.isUpdatedSystemApp = (applicationInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0;\n            String codePath = PackageUtils.getHiddenCodePathOrDefault(packageName, applicationInfo.publicSourceDir);\n            tagCloud.isSystemlessPath = !isExternalApk && MagiskUtils.isSystemlessPath(codePath);\n            if (!isExternalApk && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {\n                DomainVerificationUserState userState = DomainVerificationManagerCompat\n                        .getDomainVerificationUserState(packageName, userId);\n                if (userState != null) {\n                    tagCloud.canOpenLinks = userState.isLinkHandlingAllowed();\n                    if (!userState.getHostToStateMap().isEmpty()) {\n                        tagCloud.hostsToOpen = userState.getHostToStateMap();\n                    }\n                }\n            }\n            tagCloud.splitCount = mMainModel.getSplitCount();\n            tagCloud.isDebuggable = (applicationInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;\n            tagCloud.isTestOnly = ApplicationInfoCompat.isTestOnly(applicationInfo);\n            tagCloud.hasCode = (applicationInfo.flags & ApplicationInfo.FLAG_HAS_CODE) != 0;\n            tagCloud.isOverlay = PackageInfoCompat2.getOverlayTarget(packageInfo) != null;\n            tagCloud.hasRequestedLargeHeap = (applicationInfo.flags & ApplicationInfo.FLAG_LARGE_HEAP) != 0;\n            if (ThreadUtils.isInterrupted()) {\n                return;\n            }\n            tagCloud.isRunning = false;\n            for (ActivityManager.RunningAppProcessInfo info : ActivityManagerCompat.getRunningAppProcesses()) {\n                if (ArrayUtils.contains(info.pkgList, packageName)) {\n                    tagCloud.isRunning = true;\n                    break;\n                }\n            }\n            tagCloud.runningServices = ActivityManagerCompat.getRunningServices(packageName, userId);\n            tagCloud.isForceStopped = ApplicationInfoCompat.isStopped(applicationInfo);\n            tagCloud.isAppEnabled = applicationInfo.enabled;\n            tagCloud.isAppSuspended = ApplicationInfoCompat.isSuspended(applicationInfo);\n            tagCloud.isAppHidden = ApplicationInfoCompat.isHidden(applicationInfo);\n            if (ThreadUtils.isInterrupted()) {\n                return;\n            }\n            tagCloud.magiskHiddenProcesses = MagiskHide.getProcesses(packageInfo);\n            boolean magiskHideEnabled = false;\n            for (MagiskProcess magiskProcess : tagCloud.magiskHiddenProcesses) {\n                magiskHideEnabled |= magiskProcess.isEnabled();\n                for (ActivityManager.RunningServiceInfo info : tagCloud.runningServices) {\n                    if (info.process.startsWith(magiskProcess.name)) {\n                        magiskProcess.setRunning(true);\n                    }\n                }\n            }\n            tagCloud.isMagiskHideEnabled = !isExternalApk && magiskHideEnabled;\n            tagCloud.magiskDeniedProcesses = MagiskDenyList.getProcesses(packageInfo);\n            boolean magiskDenyListEnabled = false;\n            for (MagiskProcess magiskProcess : tagCloud.magiskDeniedProcesses) {\n                magiskDenyListEnabled |= magiskProcess.isEnabled();\n                for (ActivityManager.RunningServiceInfo info : tagCloud.runningServices) {\n                    if (info.process.startsWith(magiskProcess.name)) {\n                        magiskProcess.setRunning(true);\n                    }\n                }\n            }\n            tagCloud.isMagiskDenyListEnabled = !isExternalApk && magiskDenyListEnabled;\n            if (ThreadUtils.isInterrupted()) {\n                return;\n            }\n            List<DebloatObject> debloatObjects = StaticDataset.getDebloatObjects();\n            for (DebloatObject debloatObject : debloatObjects) {\n                if (packageName.equals(debloatObject.packageName)) {\n                    tagCloud.bloatwareRemovalType = debloatObject.getRemoval();\n                    break;\n                }\n            }\n            if (ThreadUtils.isInterrupted()) {\n                return;\n            }\n            if (!isExternalApk && Build.VERSION.SDK_INT >= Build.VERSION_CODES.P\n                    && SelfPermissions.checkSelfOrRemotePermission(ManifestCompat.permission.MANAGE_SENSORS)) {\n                tagCloud.sensorsEnabled = SensorServiceCompat.isSensorEnabled(packageName, userId);\n            } else tagCloud.sensorsEnabled = true;\n            try (ZipFile zipFile = new ZipFile(applicationInfo.publicSourceDir)) {\n                Boolean isXposedModule = XposedModuleInfo.isXposedModule(applicationInfo, zipFile);\n                if (!Boolean.FALSE.equals(isXposedModule)) {\n                    tagCloud.xposedModuleInfo = new XposedModuleInfo(applicationInfo, isXposedModule == null ? null : zipFile);\n                }\n            } catch (Throwable th) {\n                th.printStackTrace();\n            }\n            tagCloud.canWriteAndExecute = Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q\n                    && applicationInfo.targetSdkVersion < Build.VERSION_CODES.Q;\n            tagCloud.hasKeyStoreItems = KeyStoreUtils.hasKeyStore(applicationInfo.uid);\n            tagCloud.hasMasterKeyInKeyStore = KeyStoreUtils.hasMasterKey(applicationInfo.uid);\n            tagCloud.usesPlayAppSigning = PackageUtils.usesPlayAppSigning(applicationInfo);\n            if (ThreadUtils.isInterrupted()) {\n                return;\n            }\n            tagCloud.backups = BackupUtils.getBackupMetadataFromDbNoLockValidate(packageName);\n            if (!isExternalApk) {\n                tagCloud.isBatteryOptimized = DeviceIdleManagerCompat.isBatteryOptimizedApp(packageName);\n            } else {\n                tagCloud.isBatteryOptimized = true;\n            }\n            if (!isExternalApk && SelfPermissions.checkSelfOrRemotePermission(ManifestCompat.permission.MANAGE_NETWORK_POLICY)) {\n                tagCloud.netPolicies = NetworkPolicyManagerCompat.getUidPolicy(applicationInfo.uid);\n            } else {\n                tagCloud.netPolicies = 0;\n            }\n            if (!isExternalApk && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {\n                try {\n                    tagCloud.ssaid = new SsaidSettings(userId)\n                            .getSsaid(packageName, applicationInfo.uid);\n                    if (TextUtils.isEmpty(tagCloud.ssaid)) tagCloud.ssaid = null;\n                } catch (IOException ignore) {\n                }\n            }\n            if (!isExternalApk) {\n                if (ThreadUtils.isInterrupted()) {\n                    return;\n                }\n                List<UriManager.UriGrant> uriGrants = new UriManager().getGrantedUris(packageName);\n                if (uriGrants != null) {\n                    Iterator<UriManager.UriGrant> uriGrantIterator = uriGrants.listIterator();\n                    UriManager.UriGrant uriGrant;\n                    while (uriGrantIterator.hasNext()) {\n                        uriGrant = uriGrantIterator.next();\n                        if (uriGrant.targetUserId != userId) {\n                            uriGrantIterator.remove();\n                        }\n                    }\n                    tagCloud.uriGrants = uriGrants;\n                }\n            }\n            if (ApplicationInfoCompat.isStaticSharedLibrary(applicationInfo)) {\n                if (ThreadUtils.isInterrupted()) {\n                    return;\n                }\n                List<String> staticSharedLibraryNames = new ArrayList<>();\n                // Check for packages by the same packagename\n                List<ApplicationInfo> appList;\n                try {\n                    appList = PackageManagerCompat.getInstalledApplications(PackageManagerCompat.MATCH_STATIC_SHARED_AND_SDK_LIBRARIES, userId);\n                    for (ApplicationInfo info : appList) {\n                        if (info.packageName.equals(packageName)) {\n                            staticSharedLibraryNames.add(info.processName);\n                        }\n                    }\n                } catch (Throwable ignore) {\n                    staticSharedLibraryNames.add(applicationInfo.processName);\n                }\n                tagCloud.staticSharedLibraryNames = staticSharedLibraryNames.toArray(new String[0]);\n            }\n            if (ThreadUtils.isInterrupted()) {\n                return;\n            }\n            mTagCloud.postValue(tagCloud);\n        } catch (Throwable th) {\n            // Unknown behaviour\n            ThreadUtils.postOnMainThread(() -> {\n                // Throw Runtime exception in main thread to crash the app\n                throw new RuntimeException(th);\n            });\n        }\n    }\n\n    @AnyThread\n    public void loadAppInfo(@NonNull PackageInfo packageInfo, boolean isExternalApk) {\n        if (mAppInfoFuture != null) {\n            mAppInfoFuture.cancel(true);\n        }\n        mAppInfoFuture = ThreadUtils.postOnBackgroundThread(() -> loadAppInfoInternal(packageInfo, isExternalApk));\n    }\n\n    @WorkerThread\n    private void loadAppInfoInternal(@NonNull PackageInfo packageInfo, boolean isExternalApk) {\n        String packageName = packageInfo.packageName;\n        ApplicationInfo applicationInfo = packageInfo.applicationInfo;\n        int userId = UserHandleHidden.getUserId(applicationInfo.uid);\n        PackageManager pm = getApplication().getPackageManager();\n        AppInfo appInfo = new AppInfo();\n        try {\n            if (!isExternalApk) {\n                // Set source dir\n                appInfo.sourceDir = new File(applicationInfo.publicSourceDir).getParent();\n                // Set data dirs\n                appInfo.dataDir = applicationInfo.dataDir;\n                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {\n                    appInfo.dataDeDir = applicationInfo.deviceProtectedDataDir;\n                }\n                // Set directories\n                appInfo.extDataDirs = new ArrayList<>();\n                OsEnvironment.UserEnvironment ue = OsEnvironment.getUserEnvironment(userId);\n                Path[] externalDataDirs = ue.buildExternalStorageAppDataDirs(packageName);\n                for (Path externalDataDir : externalDataDirs) {\n                    Path accessiblePath = Paths.getAccessiblePath(externalDataDir);\n                    if (accessiblePath.exists()) {\n                        appInfo.extDataDirs.add(Objects.requireNonNull(accessiblePath.getFilePath()));\n                    }\n                }\n                // Set JNI dir\n                if (Paths.exists(applicationInfo.nativeLibraryDir)) {\n                    appInfo.jniDir = applicationInfo.nativeLibraryDir;\n                }\n                boolean hasUsageAccess = FeatureController.isUsageAccessEnabled() && SelfPermissions.checkUsageStatsPermission();\n                if (hasUsageAccess) {\n                    // Net statistics\n                    AppUsageStatsManager.DataUsage dataUsage;\n                    TimeInterval interval = UsageUtils.getLastWeek();\n                    dataUsage = AppUsageStatsManager.getDataUsageForPackage(applicationInfo.uid, interval);\n                    if (dataUsage.getTotal() == 0 && !ArrayUtils.contains(\n                            packageInfo.requestedPermissions, Manifest.permission.INTERNET)) {\n                        appInfo.dataUsage = null;\n                    } else appInfo.dataUsage = dataUsage;\n                    // Set sizes\n                    appInfo.sizeInfo = PackageUtils.getPackageSizeInfo(getApplication(), packageName, userId,\n                            Build.VERSION.SDK_INT >= Build.VERSION_CODES.O ? applicationInfo.storageUuid : null);\n                }\n                // Set installer app\n                InstallSourceInfoCompat installSourceInfo = ExUtils.exceptionAsNull(() ->\n                        PackageManagerCompat.getInstallSourceInfo(packageName, userId));\n                if (installSourceInfo != null) {\n                    if (installSourceInfo.getInstallingPackageName() != null) {\n                        CharSequence label = PackageUtils.getPackageLabel(pm,\n                                installSourceInfo.getInstallingPackageName(), userId);\n                        appInfo.installerApp = label;\n                        installSourceInfo.setInstallingPackageLabel(label);\n                    }\n                    if (installSourceInfo.getInitiatingPackageName() != null) {\n                        CharSequence label = PackageUtils.getPackageLabel(pm,\n                                installSourceInfo.getInitiatingPackageName(), userId);\n                        if (appInfo.installerApp == null) {\n                            appInfo.installerApp = label;\n                        }\n                        installSourceInfo.setInitiatingPackageLabel(label);\n                    }\n                    if (installSourceInfo.getOriginatingPackageName() != null) {\n                        installSourceInfo.setOriginatingPackageLabel(PackageUtils.getPackageLabel(pm,\n                                installSourceInfo.getOriginatingPackageName(), userId));\n                    }\n                    appInfo.installSource = installSourceInfo;\n                }\n                // Set main activity\n                appInfo.mainActivity = PackageManagerCompat.getLaunchIntentForPackage(packageName, userId);\n                // SELinux\n                appInfo.seInfo = ApplicationInfoCompat.getSeInfo(applicationInfo);\n                // Primary ABI\n                appInfo.primaryCpuAbi = ApplicationInfoCompat.getPrimaryCpuAbi(applicationInfo);\n                // zygotePreloadName\n                appInfo.zygotePreloadName = ApplicationInfoCompat.getZygotePreloadName(applicationInfo);\n                // hiddenApiEnforcementPolicy\n                appInfo.hiddenApiEnforcementPolicy = ApplicationInfoCompat.getHiddenApiEnforcementPolicy(applicationInfo);\n            }\n            mAppInfo.postValue(appInfo);\n        } catch (Throwable th) {\n            // Unknown behaviour\n            ThreadUtils.postOnMainThread(() -> {\n                // Throw Runtime exception in main thread to crash the app\n                throw new RuntimeException(th);\n            });\n        }\n    }\n\n    public void installExisting(@NonNull String packageName, @UserIdInt int userId) {\n        mExecutor.submit(() -> {\n            PackageInstallerCompat installer = PackageInstallerCompat.getNewInstance();\n            installer.setOnInstallListener(new PackageInstallerCompat.OnInstallListener() {\n                @Override\n                public void onStartInstall(int sessionId, String packageName) {\n                }\n\n                @Override\n                public void onFinishedInstall(int sessionId, String packageName, int result,\n                                              @Nullable String blockingPackage, @Nullable String statusMessage) {\n                    StringBuilder sb = new StringBuilder();\n                    sb.append(PackageInstallerService.getStringFromStatus(getApplication(), result,\n                            getAppLabel().getValue(), blockingPackage));\n                    if (statusMessage != null) {\n                        sb.append(\"\\n\\n\").append(statusMessage);\n                    }\n                    mInstallExistingResult.postValue(new Pair<>(result, sb));\n                }\n            });\n            installer.installExisting(packageName, userId);\n        });\n    }\n\n    public static class TagCloud {\n        public List<ComponentRule> trackerComponents;\n        public boolean areAllTrackersBlocked = true;\n        public boolean isSystemApp;\n        public boolean isSystemlessPath;\n        public boolean isUpdatedSystemApp;\n        public boolean canOpenLinks;\n        /**\n         * Hosts that can be opened by the app (Android 12+). State is one of {@link DomainVerificationUserState#DOMAIN_STATE_NONE},\n         * {@link DomainVerificationUserState#DOMAIN_STATE_SELECTED}, {@link DomainVerificationUserState#DOMAIN_STATE_VERIFIED}.\n         */\n        public Map<String, Integer> hostsToOpen;\n        public int splitCount;\n        public boolean isDebuggable;\n        public boolean isTestOnly;\n        public boolean hasCode;\n        public boolean isOverlay;\n        public boolean hasRequestedLargeHeap;\n        public boolean isRunning;\n        public List<ActivityManager.RunningServiceInfo> runningServices;\n        public List<MagiskProcess> magiskHiddenProcesses;\n        public List<MagiskProcess> magiskDeniedProcesses;\n        public boolean isForceStopped;\n        public boolean isAppEnabled;\n        public boolean isAppHidden;\n        public boolean isAppSuspended;\n        public boolean isMagiskHideEnabled;\n        public boolean isMagiskDenyListEnabled;\n        @DebloatObject.Removal\n        public int bloatwareRemovalType;\n        public boolean sensorsEnabled;\n        @Nullable\n        public XposedModuleInfo xposedModuleInfo;\n        public boolean canWriteAndExecute;\n        public boolean hasKeyStoreItems;\n        public boolean hasMasterKeyInKeyStore;\n        public boolean usesPlayAppSigning;\n        public List<Backup> backups;\n        public boolean isBatteryOptimized;\n        public int netPolicies;\n        @Nullable\n        public String ssaid;\n        @Nullable\n        public List<UriManager.UriGrant> uriGrants;\n        @Nullable\n        public String[] staticSharedLibraryNames;\n    }\n\n    public static class AppInfo {\n        // Paths & dirs\n        @Nullable\n        public String sourceDir;\n        @Nullable\n        public String dataDir;\n        @Nullable\n        public String dataDeDir;\n        public List<String> extDataDirs = Collections.emptyList();\n        @Nullable\n        public String jniDir;\n        // Data usage\n        @Nullable\n        public AppUsageStatsManager.DataUsage dataUsage;\n        @Nullable\n        public PackageSizeInfo sizeInfo;\n        // More info\n        @Nullable\n        public InstallSourceInfoCompat installSource;\n        @Nullable\n        public CharSequence installerApp;\n        @Nullable\n        public Intent mainActivity;\n        @Nullable\n        public String seInfo;\n        @Nullable\n        public String primaryCpuAbi;\n        @Nullable\n        public String zygotePreloadName;\n        public int hiddenApiEnforcementPolicy;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/details/info/ListItem.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.details.info;\n\nimport android.view.View;\n\nimport androidx.annotation.DrawableRes;\nimport androidx.annotation.IntDef;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.StringRes;\n\nimport io.github.muntashirakon.AppManager.R;\n\nclass ListItem {\n    @IntDef(value = {\n            LIST_ITEM_GROUP_BEGIN,\n            LIST_ITEM_REGULAR,\n            LIST_ITEM_REGULAR_ACTION,\n            LIST_ITEM_INLINE\n    })\n    @interface ListItemType {\n    }\n\n    static final int LIST_ITEM_GROUP_BEGIN = 0;  // Group header\n    static final int LIST_ITEM_REGULAR = 1;\n    static final int LIST_ITEM_REGULAR_ACTION = 2;\n    static final int LIST_ITEM_INLINE = 3;\n\n    @ListItemType\n    public final int type;\n\n    @Nullable\n    private CharSequence mTitle;\n    @Nullable\n    private CharSequence mSubtitle;\n    @DrawableRes\n    private int mActionIconRes;\n    @StringRes\n    private int mActionContentDescriptionRes;\n    @Nullable\n    private CharSequence mActionContentDescription;\n    @Nullable\n    private View.OnClickListener mOnActionClickListener;\n    private boolean mIsSelectable;\n    private boolean mIsMonospace;\n\n    @NonNull\n    public static ListItem newGroupStart(@Nullable CharSequence header) {\n        ListItem listItem = new ListItem(LIST_ITEM_GROUP_BEGIN);\n        listItem.mTitle = header;\n        return listItem;\n    }\n\n    @NonNull\n    public static ListItem newInlineItem(@Nullable CharSequence title, @Nullable CharSequence subtitle) {\n        ListItem listItem = new ListItem(LIST_ITEM_INLINE);\n        listItem.mTitle = title;\n        listItem.mSubtitle = subtitle;\n        return listItem;\n    }\n\n    @NonNull\n    public static ListItem newRegularItem(@Nullable CharSequence title, @Nullable CharSequence subtitle) {\n        ListItem listItem = new ListItem(LIST_ITEM_REGULAR);\n        listItem.mTitle = title;\n        listItem.mSubtitle = subtitle;\n        return listItem;\n    }\n\n    @NonNull\n    public static ListItem newSelectableRegularItem(@Nullable CharSequence title, @Nullable CharSequence subtitle) {\n        ListItem listItem = new ListItem(LIST_ITEM_REGULAR);\n        listItem.mIsSelectable = true;\n        listItem.mTitle = title;\n        listItem.mSubtitle = subtitle;\n        return listItem;\n    }\n\n    @NonNull\n    public static ListItem newSelectableRegularItem(@Nullable CharSequence title,\n                                                    @Nullable CharSequence subtitle,\n                                                    @Nullable View.OnClickListener actionListener) {\n        ListItem listItem = new ListItem(LIST_ITEM_REGULAR_ACTION);\n        listItem.mIsSelectable = true;\n        listItem.mTitle = title;\n        listItem.mSubtitle = subtitle;\n        listItem.mActionIconRes = R.drawable.ic_open_in_new;\n        listItem.mOnActionClickListener = actionListener;\n        return listItem;\n    }\n\n    public ListItem(int listType) {\n        this.type = listType;\n    }\n\n    @Nullable\n    public CharSequence getTitle() {\n        return mTitle;\n    }\n\n    public void setTitle(@Nullable CharSequence title) {\n        this.mTitle = title;\n    }\n\n    @Nullable\n    public CharSequence getSubtitle() {\n        return mSubtitle;\n    }\n\n    public void setSubtitle(@Nullable CharSequence subtitle) {\n        this.mSubtitle = subtitle;\n    }\n\n    @DrawableRes\n    public int getActionIconRes() {\n        return mActionIconRes;\n    }\n\n    public void setActionIcon(@DrawableRes int actionIcon) {\n        this.mActionIconRes = actionIcon;\n    }\n\n    @Nullable\n    public View.OnClickListener getOnActionClickListener() {\n        return mOnActionClickListener;\n    }\n\n    public void setOnActionClickListener(@Nullable View.OnClickListener onActionClickListener) {\n        this.mOnActionClickListener = onActionClickListener;\n    }\n\n    @StringRes\n    public int getActionContentDescriptionRes() {\n        return mActionContentDescriptionRes;\n    }\n\n    @Nullable\n    public CharSequence getActionContentDescription() {\n        return mActionContentDescription;\n    }\n\n    public void setActionContentDescription(@StringRes int contentDescriptionRes) {\n        this.mActionContentDescriptionRes = contentDescriptionRes;\n    }\n\n    public void setActionContentDescription(@Nullable CharSequence contentDescription) {\n        this.mActionContentDescription = contentDescription;\n    }\n\n    public boolean isMonospace() {\n        return mIsMonospace;\n    }\n\n    public void setMonospace(boolean monospace) {\n        mIsMonospace = monospace;\n    }\n\n    public boolean isSelectable() {\n        return mIsSelectable;\n    }\n\n    public void setSelectable(boolean selectable) {\n        mIsSelectable = selectable;\n    }\n\n    @NonNull\n    @Override\n    public String toString() {\n        return \"ListItem{\" +\n                \"type=\" + type +\n                \", title='\" + mTitle + '\\'' +\n                \", subtitle='\" + mSubtitle + '\\'' +\n                '}';\n    }\n}"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/details/info/TagItem.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.details.info;\n\nimport android.content.Context;\nimport android.content.res.ColorStateList;\nimport android.graphics.Color;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\n\nimport androidx.annotation.ColorInt;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.StringRes;\nimport androidx.core.graphics.ColorUtils;\n\nimport com.google.android.material.chip.Chip;\n\nimport io.github.muntashirakon.AppManager.R;\n\nclass TagItem {\n    @StringRes\n    private int mTextRes;\n    @Nullable\n    private CharSequence mText;\n    @ColorInt\n    private int mColor;\n    private boolean mColorSet = false;\n    private View.OnClickListener mOnClickListener;\n\n    public TagItem setTextRes(@StringRes int textRes) {\n        mTextRes = textRes;\n        return this;\n    }\n\n    public TagItem setText(@Nullable CharSequence text) {\n        mText = text;\n        return this;\n    }\n\n    public TagItem setColor(@ColorInt int color) {\n        mColor = color;\n        mColorSet = true;\n        return this;\n    }\n\n    public TagItem setOnClickListener(View.OnClickListener clickListener) {\n        mOnClickListener = clickListener;\n        return this;\n    }\n\n    public Chip toChip(@NonNull Context context, @NonNull ViewGroup parent) {\n        Chip chip = (Chip) LayoutInflater.from(context).inflate(R.layout.item_chip, parent, false);\n        if (mTextRes != 0) {\n            chip.setText(mTextRes);\n        } else chip.setText(mText);\n        if (mColorSet) {\n            chip.setChipBackgroundColor(ColorStateList.valueOf(mColor));\n            double luminance = ColorUtils.calculateLuminance(mColor);\n            chip.setTextColor(luminance < 0.5 ? Color.WHITE : Color.BLACK);\n        }\n        if (mOnClickListener != null) {\n            chip.setOnClickListener(mOnClickListener);\n        }\n        return chip;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/details/manifest/ManifestViewerActivity.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.details.manifest;\n\nimport android.annotation.SuppressLint;\nimport android.content.Intent;\nimport android.net.Uri;\nimport android.os.Bundle;\nimport android.view.MenuItem;\nimport android.view.View;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.UiThread;\nimport androidx.lifecycle.ViewModelProvider;\n\nimport com.google.android.material.progressindicator.LinearProgressIndicator;\n\nimport io.github.muntashirakon.AppManager.BaseActivity;\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.apk.ApkSource;\nimport io.github.muntashirakon.AppManager.editor.CodeEditorFragment;\nimport io.github.muntashirakon.AppManager.intercept.IntentCompat;\nimport io.github.muntashirakon.AppManager.utils.UIUtils;\n\npublic class ManifestViewerActivity extends BaseActivity {\n    public static final String EXTRA_PACKAGE_NAME = \"pkg\";\n\n    private ManifestViewerViewModel mModel;\n\n    @SuppressLint(\"WrongConstant\")\n    @Override\n    protected void onAuthenticated(Bundle savedInstanceState) {\n        setContentView(R.layout.activity_code_editor);\n        setSupportActionBar(findViewById(R.id.toolbar));\n        mModel = new ViewModelProvider(this).get(ManifestViewerViewModel.class);\n        LinearProgressIndicator progressIndicator = findViewById(R.id.progress_linear);\n        progressIndicator.setVisibilityAfterHide(View.GONE);\n        final Intent intent = getIntent();\n        final Uri packageUri = IntentCompat.getDataUri(intent);\n        String packageName = intent.getStringExtra(EXTRA_PACKAGE_NAME);\n        if (packageUri == null && packageName == null) {\n            showErrorAndFinish();\n            return;\n        }\n        final ApkSource apkSource = packageUri != null ? ApkSource.getApkSource(packageUri, intent.getType()) : null;\n        mModel.getManifestLiveData().observe(this, manifest -> {\n            CodeEditorFragment.Options options = new CodeEditorFragment.Options.Builder()\n                    .setTitle(getString(R.string.manifest_viewer))\n                    .setSubtitle(\"AndroidManifest.xml\")\n                    .setReadOnly(true)\n                    .setUri(manifest)\n                    .setJavaSmaliToggle(false)\n                    .setEnableSharing(true)\n                    .build();\n            CodeEditorFragment fragment = new CodeEditorFragment();\n            Bundle args = new Bundle();\n            args.putParcelable(CodeEditorFragment.ARG_OPTIONS, options);\n            fragment.setArguments(args);\n            getSupportFragmentManager()\n                    .beginTransaction()\n                    .replace(R.id.container, fragment)\n                    .commit();\n        });\n        mModel.loadApkFile(apkSource, packageName);\n    }\n\n    @UiThread\n    private void showErrorAndFinish() {\n        UIUtils.displayShortToast(R.string.error);\n        finish();\n    }\n\n    @Override\n    public boolean onOptionsItemSelected(@NonNull MenuItem item) {\n        int id = item.getItemId();\n        if (id == android.R.id.home) {\n            finish();\n            return true;\n        }\n        return super.onOptionsItemSelected(item);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/details/manifest/ManifestViewerViewModel.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.details.manifest;\n\nimport android.app.Application;\nimport android.content.pm.ApplicationInfo;\nimport android.content.pm.PackageManager;\nimport android.net.Uri;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.lifecycle.AndroidViewModel;\nimport androidx.lifecycle.LiveData;\nimport androidx.lifecycle.MutableLiveData;\n\nimport java.io.File;\nimport java.io.PrintStream;\nimport java.nio.ByteBuffer;\nimport java.nio.ByteOrder;\nimport java.util.concurrent.Future;\n\nimport io.github.muntashirakon.AppManager.apk.ApkFile;\nimport io.github.muntashirakon.AppManager.apk.ApkSource;\nimport io.github.muntashirakon.AppManager.apk.parser.AndroidBinXmlDecoder;\nimport io.github.muntashirakon.AppManager.logs.Log;\nimport io.github.muntashirakon.AppManager.self.filecache.FileCache;\nimport io.github.muntashirakon.AppManager.utils.ThreadUtils;\nimport io.github.muntashirakon.io.IoUtils;\n\npublic class ManifestViewerViewModel extends AndroidViewModel {\n    public static final String TAG = ManifestViewerViewModel.class.getSimpleName();\n\n    private ApkFile mApkFile;\n    @Nullable\n    private Future<?> mManifestLoaderResult;\n\n    private final FileCache mFileCache = new FileCache();\n    private final MutableLiveData<Uri> mManifestLiveData = new MutableLiveData<>();\n\n    public ManifestViewerViewModel(@NonNull Application application) {\n        super(application);\n    }\n\n    @Override\n    protected void onCleared() {\n        if (mManifestLoaderResult != null) {\n            mManifestLoaderResult.cancel(true);\n        }\n        IoUtils.closeQuietly(mApkFile);\n        IoUtils.closeQuietly(mFileCache);\n        super.onCleared();\n    }\n\n    public LiveData<Uri> getManifestLiveData() {\n        return mManifestLiveData;\n    }\n\n    public void loadApkFile(@Nullable ApkSource apkSource, @Nullable String packageName) {\n        mManifestLoaderResult = ThreadUtils.postOnBackgroundThread(() -> {\n            final PackageManager pm = getApplication().getPackageManager();\n            ApkSource realApkSource;\n            if (apkSource != null) {\n                realApkSource = apkSource;\n            } else {\n                try {\n                    ApplicationInfo applicationInfo = pm.getApplicationInfo(packageName, 0);\n                    realApkSource = ApkSource.getApkSource(applicationInfo);\n                } catch (PackageManager.NameNotFoundException e) {\n                    Log.e(TAG, \"Error: \", e);\n                    return;\n                }\n            }\n            try {\n                mApkFile = realApkSource.resolve();\n            } catch (ApkFile.ApkFileException e) {\n                Log.e(TAG, \"Error: \", e);\n                return;\n            }\n            if (ThreadUtils.isInterrupted()) {\n                return;\n            }\n            if (mApkFile != null) {\n                ByteBuffer byteBuffer = mApkFile.getBaseEntry().manifest;\n                // Reset properties\n                byteBuffer.position(0);\n                byteBuffer.order(ByteOrder.LITTLE_ENDIAN);\n                try {\n                    File cachedFile = mFileCache.createCachedFile(\"xml\");\n                    try (PrintStream ps = new PrintStream(cachedFile)) {\n                        AndroidBinXmlDecoder.decode(byteBuffer, ps);\n                    }\n                    mManifestLiveData.postValue(Uri.fromFile(cachedFile));\n                } catch (Throwable e) {\n                    Log.e(TAG, \"Could not parse APK\", e);\n                }\n            }\n        });\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/details/struct/AppDetailsActivityItem.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.details.struct;\n\nimport android.content.pm.ActivityInfo;\n\nimport androidx.annotation.NonNull;\n\npublic class AppDetailsActivityItem extends AppDetailsComponentItem {\n    public boolean canLaunchAssist;\n\n    public AppDetailsActivityItem(@NonNull ActivityInfo componentInfo) {\n        super(componentInfo);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/details/struct/AppDetailsAppOpItem.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.details.struct;\n\nimport android.app.AppOpsManager;\nimport android.content.pm.PackageInfo;\nimport android.content.pm.PermissionInfo;\nimport android.os.Build;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.RequiresPermission;\nimport androidx.annotation.WorkerThread;\nimport androidx.core.content.pm.PermissionInfoCompat;\n\nimport java.util.List;\nimport java.util.Objects;\n\nimport io.github.muntashirakon.AppManager.compat.AppOpsManagerCompat;\nimport io.github.muntashirakon.AppManager.compat.ManifestCompat;\nimport io.github.muntashirakon.AppManager.permission.DevelopmentPermission;\nimport io.github.muntashirakon.AppManager.permission.PermUtils;\nimport io.github.muntashirakon.AppManager.permission.Permission;\nimport io.github.muntashirakon.AppManager.permission.PermissionException;\nimport io.github.muntashirakon.AppManager.permission.ReadOnlyPermission;\nimport io.github.muntashirakon.AppManager.permission.RuntimePermission;\n\npublic class AppDetailsAppOpItem extends AppDetailsItem<Integer> {\n    @Nullable\n    public final Permission permission;\n    @Nullable\n    public final PermissionInfo permissionInfo;\n    public final boolean isDangerous;\n    public final boolean hasModifiablePermission;\n    /**\n     * Whether the permission is part of the app.\n     */\n    public final boolean appContainsPermission;\n\n    @Nullable\n    private AppOpsManagerCompat.OpEntry mOpEntry;\n\n    public AppDetailsAppOpItem(@NonNull AppOpsManagerCompat.OpEntry opEntry) {\n        this(opEntry.getOp());\n        name = opEntry.getName();\n        mOpEntry = opEntry;\n    }\n\n    public AppDetailsAppOpItem(int op) {\n        super(op);\n        name = AppOpsManagerCompat.opToName(op);\n        mOpEntry = null;\n        permissionInfo = null;\n        permission = null;\n        isDangerous = false;\n        hasModifiablePermission = false;\n        appContainsPermission = false;\n    }\n\n    public AppDetailsAppOpItem(@NonNull AppOpsManagerCompat.OpEntry opEntry, @NonNull PermissionInfo permissionInfo,\n                               boolean isGranted, int permissionFlags, boolean appContainsPermission) {\n        super(opEntry.getOp());\n        name = opEntry.getName();\n        mOpEntry = opEntry;\n        this.permissionInfo = permissionInfo;\n        this.appContainsPermission = appContainsPermission;\n        isDangerous = PermissionInfoCompat.getProtection(permissionInfo) == PermissionInfo.PROTECTION_DANGEROUS;\n        int protectionFlags = PermissionInfoCompat.getProtectionFlags(permissionInfo);\n        if (isDangerous && PermUtils.systemSupportsRuntimePermissions()) {\n            permission = new RuntimePermission(permissionInfo.name, isGranted, opEntry.getOp(), isAllowed(), permissionFlags);\n        } else if ((protectionFlags & PermissionInfo.PROTECTION_FLAG_DEVELOPMENT) != 0) {\n            permission = new DevelopmentPermission(permissionInfo.name, isGranted, opEntry.getOp(), isAllowed(), permissionFlags);\n        } else {\n            permission = new ReadOnlyPermission(permissionInfo.name, isGranted, opEntry.getOp(), isAllowed(), permissionFlags);\n        }\n        hasModifiablePermission = PermUtils.isModifiable(permission);\n    }\n\n    public AppDetailsAppOpItem(int op, @NonNull PermissionInfo permissionInfo,\n                               boolean isGranted, int permissionFlags, boolean appContainsPermission) {\n        super(op);\n        name = AppOpsManagerCompat.opToName(op);\n        mOpEntry = null;\n        this.permissionInfo = permissionInfo;\n        this.appContainsPermission = appContainsPermission;\n        isDangerous = PermissionInfoCompat.getProtection(permissionInfo) == PermissionInfo.PROTECTION_DANGEROUS;\n        int protectionFlags = PermissionInfoCompat.getProtectionFlags(permissionInfo);\n        if (isDangerous && PermUtils.systemSupportsRuntimePermissions()) {\n            permission = new RuntimePermission(permissionInfo.name, isGranted, op, isAllowed(), permissionFlags);\n        } else if ((protectionFlags & PermissionInfo.PROTECTION_FLAG_DEVELOPMENT) != 0) {\n            permission = new DevelopmentPermission(permissionInfo.name, isGranted, op, isAllowed(), permissionFlags);\n        } else {\n            permission = new ReadOnlyPermission(permissionInfo.name, isGranted, op, isAllowed(), permissionFlags);\n        }\n        hasModifiablePermission = PermUtils.isModifiable(permission);\n    }\n\n    public int getOp() {\n        return item;\n    }\n\n    @AppOpsManagerCompat.Mode\n    public int getMode() {\n        if (mOpEntry != null) {\n            return mOpEntry.getMode();\n        }\n        return AppOpsManagerCompat.opToDefaultMode(getOp());\n    }\n\n    public long getDuration() {\n        if (mOpEntry != null) {\n            return mOpEntry.getDuration();\n        }\n        return 0L;\n    }\n\n    public long getTime() {\n        if (mOpEntry != null) {\n            return mOpEntry.getTime();\n        }\n        return 0L;\n    }\n\n    public long getRejectTime() {\n        if (mOpEntry != null) {\n            return mOpEntry.getRejectTime();\n        }\n        return 0L;\n    }\n\n    public boolean isRunning() {\n        return mOpEntry != null && mOpEntry.isRunning();\n    }\n\n    public boolean isAllowed() {\n        boolean isAllowed = false;\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {\n            isAllowed = getMode() == AppOpsManager.MODE_FOREGROUND;\n        }\n        isAllowed |= getMode() == AppOpsManager.MODE_ALLOWED;\n        // Special case for default\n        if (getMode() == AppOpsManager.MODE_DEFAULT) {\n            isAllowed |= (permission != null && permission.isGranted());\n        }\n        return isAllowed;\n    }\n\n    /**\n     * Allow the app op.\n     *\n     * <p>This also automatically grants the permission associated with the app op.\n     */\n    @RequiresPermission(allOf = {\n            \"android.permission.MANAGE_APP_OPS_MODES\",\n            ManifestCompat.permission.GRANT_RUNTIME_PERMISSIONS,\n    })\n    @WorkerThread\n    public void allowAppOp(@NonNull PackageInfo packageInfo, @NonNull AppOpsManagerCompat appOpsManager)\n            throws PermissionException {\n        if (hasModifiablePermission && permission != null) {\n            PermUtils.grantPermission(packageInfo, permission, appOpsManager, true, true);\n        } else {\n            PermUtils.allowAppOp(appOpsManager, getOp(), packageInfo.packageName, packageInfo.applicationInfo.uid);\n        }\n        invalidate(appOpsManager, packageInfo);\n    }\n\n    /**\n     * Disallow the app op.\n     *\n     * <p>This also revokes the permission associated with the app op.\n     */\n    @RequiresPermission(allOf = {\n            \"android.permission.MANAGE_APP_OPS_MODES\",\n            ManifestCompat.permission.REVOKE_RUNTIME_PERMISSIONS,\n    })\n    @WorkerThread\n    public void disallowAppOp(@NonNull PackageInfo packageInfo, @NonNull AppOpsManagerCompat appOpsManager)\n            throws PermissionException {\n        if (hasModifiablePermission && permission != null) {\n            PermUtils.revokePermission(packageInfo, permission, appOpsManager, true);\n        } else {\n            PermUtils.disallowAppOp(appOpsManager, getOp(), packageInfo.packageName, packageInfo.applicationInfo.uid);\n        }\n        invalidate(appOpsManager, packageInfo);\n    }\n\n    /**\n     * Set mode for app op.\n     *\n     * <p>This also grants/revoke the permission associated with the app op.\n     */\n    @RequiresPermission(allOf = {\n            \"android.permission.MANAGE_APP_OPS_MODES\",\n            ManifestCompat.permission.GRANT_RUNTIME_PERMISSIONS,\n            ManifestCompat.permission.REVOKE_RUNTIME_PERMISSIONS,\n    })\n    @WorkerThread\n    public void setAppOp(@NonNull PackageInfo packageInfo, @NonNull AppOpsManagerCompat appOpsManager,\n                         @AppOpsManagerCompat.Mode int mode) throws PermissionException {\n        if (hasModifiablePermission && permission != null) {\n            boolean isAllowed = false;\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {\n                isAllowed = getMode() == AppOpsManager.MODE_FOREGROUND;\n            }\n            isAllowed |= getMode() == AppOpsManager.MODE_ALLOWED;\n            if (isAllowed) {\n                PermUtils.grantPermission(packageInfo, permission, appOpsManager, true, true);\n            } else {\n                PermUtils.revokePermission(packageInfo, permission, appOpsManager, true);\n            }\n        }\n        PermUtils.setAppOpMode(appOpsManager, getOp(), packageInfo.packageName, packageInfo.applicationInfo.uid, mode);\n        invalidate(appOpsManager, packageInfo);\n    }\n\n    @RequiresPermission(\"android.permission.MANAGE_APP_OPS_MODES\")\n    public void invalidate(@NonNull AppOpsManagerCompat appOpsManager, @NonNull PackageInfo packageInfo)\n            throws PermissionException {\n        try {\n            List<AppOpsManagerCompat.OpEntry> opEntryList = appOpsManager.getOpsForPackage(packageInfo.applicationInfo.uid,\n                    packageInfo.packageName, new int[]{getOp()}).get(0).getOps();\n            mOpEntry = !opEntryList.isEmpty() ? opEntryList.get(0) : null;\n        } catch (Exception e) {\n            throw new PermissionException(e);\n        }\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) return true;\n        if (!(o instanceof AppDetailsAppOpItem)) return false;\n        if (!super.equals(o)) return false;\n        AppDetailsAppOpItem that = (AppDetailsAppOpItem) o;\n        return Objects.equals(item, that.item);\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hash(item);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/details/struct/AppDetailsComponentItem.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.details.struct;\n\nimport android.content.pm.ComponentInfo;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport io.github.muntashirakon.AppManager.rules.struct.ComponentRule;\n\n/**\n * Stores individual app details component item\n */\npublic class AppDetailsComponentItem extends AppDetailsItem<ComponentInfo> {\n    public CharSequence label;\n    public boolean canLaunch;\n\n    private boolean mIsTracker;\n    @Nullable\n    private ComponentRule mRule;\n    private boolean mIsDisabled;\n\n    public AppDetailsComponentItem(@NonNull ComponentInfo componentInfo) {\n        super(componentInfo);\n        name = componentInfo.name;\n        mIsDisabled = !componentInfo.isEnabled();\n    }\n\n    public boolean isTracker() {\n        return mIsTracker;\n    }\n\n    public void setTracker(boolean tracker) {\n        mIsTracker = tracker;\n    }\n\n    public boolean isBlocked() {\n        if (mRule == null) {\n            return false;\n        }\n        return mRule.isBlocked() && (mRule.isIfw() || isDisabled());\n    }\n\n    @Nullable\n    public ComponentRule getRule() {\n        return mRule;\n    }\n\n    public void setRule(@Nullable ComponentRule rule) {\n        mRule = rule;\n    }\n\n    public boolean isDisabled() {\n        return mIsDisabled;\n    }\n\n    public void setDisabled(boolean disabled) {\n        mIsDisabled = disabled;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/details/struct/AppDetailsDefinedPermissionItem.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.details.struct;\n\nimport android.content.pm.PermissionInfo;\n\nimport androidx.annotation.NonNull;\n\npublic class AppDetailsDefinedPermissionItem extends AppDetailsItem<PermissionInfo> {\n    public final boolean isExternal;\n\n    public AppDetailsDefinedPermissionItem(@NonNull PermissionInfo permissionInfo, boolean isExternal) {\n        super(permissionInfo);\n        name = permissionInfo.name;\n        this.isExternal = isExternal;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/details/struct/AppDetailsFeatureItem.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.details.struct;\n\nimport android.content.pm.FeatureInfo;\n\nimport androidx.annotation.NonNull;\n\npublic class AppDetailsFeatureItem extends AppDetailsItem<FeatureInfo> {\n    public static final String OPEN_GL_ES = \"OpenGL ES\";\n\n    public final boolean required;\n    public final boolean available;\n\n    public AppDetailsFeatureItem(@NonNull FeatureInfo featureInfo, boolean available) {\n        super(featureInfo);\n        // Currently, feature only has a single flag, which specifies whether the feature is required.\n        this.required = (featureInfo.flags & FeatureInfo.FLAG_REQUIRED) != 0;\n        this.available = available;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/details/struct/AppDetailsItem.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.details.struct;\n\nimport androidx.annotation.NonNull;\n\nimport java.util.Objects;\n\n/**\n * Stores individual app details item\n */\npublic class AppDetailsItem<T> {\n    @NonNull\n    public T item;\n    @NonNull\n    public String name = \"\";\n\n    public AppDetailsItem(@NonNull T object) {\n        item = object;\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) return true;\n        if (!(o instanceof AppDetailsItem)) return false;\n        AppDetailsItem<?> that = (AppDetailsItem<?>) o;\n        return name.equals(that.name);\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hash(name);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/details/struct/AppDetailsLibraryItem.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.details.struct;\n\nimport java.io.File;\n\npublic class AppDetailsLibraryItem<T> extends AppDetailsItem<T> {\n    public long size;\n    public String type;\n    public File path;\n\n    public AppDetailsLibraryItem(T item) {\n        super(item);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/details/struct/AppDetailsOverlayItem.java",
    "content": "package io.github.muntashirakon.AppManager.details.struct;\n\nimport android.annotation.UserIdInt;\nimport android.content.om.IOverlayManager;\nimport android.content.om.OverlayInfo;\nimport android.content.om.OverlayInfoHidden;\nimport android.os.Build;\nimport android.os.RemoteException;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.RequiresApi;\n\nimport dev.rikka.tools.refine.Refine;\n\n@RequiresApi(Build.VERSION_CODES.O)\npublic class AppDetailsOverlayItem extends AppDetailsItem<OverlayInfoHidden> {\n\n    @SuppressWarnings(\"NewApi\")\n    // Required due to sdk lying about the real api version requirement for overlay info\n    public AppDetailsOverlayItem(@NonNull OverlayInfo overlayInfo) {\n        super(Refine.unsafeCast(overlayInfo));\n        if (overlayInfo.getOverlayName() != null) {\n            name = overlayInfo.getOverlayName();\n        } else {\n            name = overlayInfo.getOverlayIdentifier().toString();\n        }\n    }\n\n\n    public String getPackageName() {\n        return item.packageName;\n    }\n\n    @Nullable\n    public String getCategory() {\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {\n            return item.category;\n        }\n        return null;\n    }\n\n    public boolean isEnabled() {\n        return item.isEnabled();\n    }\n\n\n    @SuppressWarnings(\"deprecation\")\n    public boolean isMutable() {\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {\n            return item.isMutable;\n        }\n        if (Build.VERSION.SDK_INT == Build.VERSION_CODES.P) {\n            return getState() != OverlayInfoHidden.STATE_ENABLED_IMMUTABLE;\n        }\n        return true;\n    }\n\n    public String getReadableState() {\n        return stateToString(item.state);\n    }\n\n    public int getState() {\n        return item.state;\n    }\n\n    @RequiresApi(Build.VERSION_CODES.P)\n    public int getPriority() {\n        return item.priority;\n    }\n\n\n    public boolean setEnabled(@NonNull IOverlayManager mgr, boolean enabled) throws RemoteException {\n        return mgr.setEnabled(getPackageName(), enabled, item.userId);\n    }\n\n    public boolean setPriority(@NonNull IOverlayManager mgr, String newParentPackageName) throws RemoteException {\n        return mgr.setPriority(getPackageName(), newParentPackageName, item.userId);\n    }\n\n    public boolean setHighestPriority(@NonNull IOverlayManager mgr) throws RemoteException {\n        return mgr.setHighestPriority(item.packageName, item.userId);\n    }\n\n    public boolean setLowestPriority(@NonNull IOverlayManager mgr) throws RemoteException {\n        return mgr.setLowestPriority(item.packageName, item.userId);\n    }\n\n    public static String stateToString(@OverlayInfoHidden.State int state) {\n        return OverlayInfoHidden.stateToString(state);\n    }\n\n    @Nullable\n    public String getOverlayName() {\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {\n            return item.overlayName;\n        }\n        return null;\n    }\n\n    public String getBaseCodePath() {\n        return item.baseCodePath;\n    }\n\n    @UserIdInt\n    public int getUserId() {\n        return item.userId;\n    }\n\n    public boolean isFabricated() {\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {\n            return item.isFabricated;\n        }\n        return false;\n    }\n\n    @NonNull\n    @Override\n    public String toString() {\n        return \"AppDetailsOverlayItem: { \" + item + \" }\";\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/details/struct/AppDetailsPermissionItem.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.details.struct;\n\nimport android.content.pm.PackageInfo;\nimport android.content.pm.PermissionInfo;\nimport android.os.RemoteException;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.WorkerThread;\nimport androidx.core.content.pm.PermissionInfoCompat;\n\nimport io.github.muntashirakon.AppManager.compat.AppOpsManagerCompat;\nimport io.github.muntashirakon.AppManager.permission.PermUtils;\nimport io.github.muntashirakon.AppManager.permission.Permission;\nimport io.github.muntashirakon.AppManager.permission.PermissionException;\n\n/**\n * Stores individual app details item\n */\npublic class AppDetailsPermissionItem extends AppDetailsItem<PermissionInfo> {\n    @NonNull\n    public final Permission permission;\n    public final boolean isDangerous; // AKA Runtime\n    public final boolean modifiable;\n    public final int flags;\n    public final int protectionFlags;\n    @Nullable\n    public final PermUtils.SettingItem settingItem;\n\n    public AppDetailsPermissionItem(@NonNull PermissionInfo permissionInfo, @NonNull Permission permission, int flags) {\n        super(permissionInfo);\n        this.permission = permission;\n        this.isDangerous = PermissionInfoCompat.getProtection(permissionInfo) == PermissionInfo.PROTECTION_DANGEROUS;\n        this.protectionFlags = PermissionInfoCompat.getProtectionFlags(permissionInfo);\n        this.modifiable = PermUtils.isModifiable(permission);\n        this.flags = flags;\n        this.settingItem = PermUtils.permissionNameToSettingItem.get(permissionInfo.name);\n    }\n\n    public boolean isGranted() {\n        if (!permission.isReadOnly()) {\n            return permission.isGrantedIncludingAppOp();\n        }\n        if (permission.affectsAppOp()) {\n            return permission.isAppOpAllowed();\n        }\n        return permission.isGranted();\n    }\n\n    /**\n     * Grant the permission.\n     *\n     * <p>This also automatically grants app op if it has app op.\n     */\n    @WorkerThread\n    public void grantPermission(@NonNull PackageInfo packageInfo, @NonNull AppOpsManagerCompat appOpsManager)\n            throws RemoteException, PermissionException {\n        PermUtils.grantPermission(packageInfo, permission, appOpsManager, true, true);\n    }\n\n    /**\n     * Revoke the permission.\n     *\n     * <p>This also disallows the app op for the permission if it has app op.\n     */\n    @WorkerThread\n    public void revokePermission(@NonNull PackageInfo packageInfo, AppOpsManagerCompat appOpsManager)\n            throws RemoteException, PermissionException {\n        PermUtils.revokePermission(packageInfo, permission, appOpsManager, true);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/details/struct/AppDetailsServiceItem.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.details.struct;\n\nimport android.app.ActivityManager;\nimport android.content.pm.ServiceInfo;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\npublic class AppDetailsServiceItem extends AppDetailsComponentItem {\n    @Nullable\n    private ActivityManager.RunningServiceInfo mRunningServiceInfo;\n\n    public AppDetailsServiceItem(@NonNull ServiceInfo serviceInfo) {\n        super(serviceInfo);\n    }\n\n    public void setRunningServiceInfo(@Nullable ActivityManager.RunningServiceInfo runningServiceInfo) {\n        mRunningServiceInfo = runningServiceInfo;\n    }\n\n    @Nullable\n    public ActivityManager.RunningServiceInfo getRunningServiceInfo() {\n        return mRunningServiceInfo;\n    }\n\n    public boolean isRunning() {\n        return mRunningServiceInfo != null;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/dex/DexClasses.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.dex;\n\nimport androidx.annotation.IntRange;\nimport androidx.annotation.NonNull;\n\nimport com.android.tools.smali.baksmali.Adaptors.ClassDefinition;\nimport com.android.tools.smali.baksmali.BaksmaliOptions;\nimport com.android.tools.smali.baksmali.formatter.BaksmaliFormatter;\nimport com.android.tools.smali.baksmali.formatter.BaksmaliWriter;\nimport com.android.tools.smali.dexlib2.Opcodes;\nimport com.android.tools.smali.dexlib2.analysis.InlineMethodResolver;\nimport com.android.tools.smali.dexlib2.dexbacked.DexBackedDexFile;\nimport com.android.tools.smali.dexlib2.dexbacked.DexBackedOdexFile;\nimport com.android.tools.smali.dexlib2.iface.ClassDef;\nimport com.android.tools.smali.dexlib2.iface.MultiDexContainer;\n\nimport java.io.BufferedInputStream;\nimport java.io.Closeable;\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.StringWriter;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Objects;\n\nimport io.github.muntashirakon.AppManager.BuildConfig;\n\n// FIXME: 8/2/22 Add support for lower SDKs by fixing Smali/Baksmali\npublic class DexClasses implements Closeable {\n    private final HashMap<String, ClassDef> mClassNameClassDefMap = new HashMap<>();\n    private final HashMap<String, List<String>> mBaseClassNestedClassMap = new HashMap<>();\n    // TODO: 18/10/21 Load frameworks.jar and add its dex files as options.classPath\n    private final BaksmaliOptions mOptions;\n    private final Opcodes mOpcodes;\n\n    public DexClasses(@NonNull File apkFile, @IntRange(from = -1) int apiLevel) throws IOException {\n        mOpcodes = apiLevel < 0 ? Opcodes.getDefault() : Opcodes.forApi(apiLevel);\n        mOptions = new BaksmaliOptions();\n        // options\n        mOptions.deodex = false;\n        mOptions.implicitReferences = false;\n        mOptions.parameterRegisters = true;\n        mOptions.localsDirective = true;\n        mOptions.sequentialLabels = true;\n        mOptions.debugInfo = BuildConfig.DEBUG;\n        mOptions.codeOffsets = false;\n        mOptions.accessorComments = false;\n        mOptions.registerInfo = 0;\n        mOptions.inlineResolver = null;\n        BaksmaliFormatter formatter = new BaksmaliFormatter();\n        MultiDexContainer<? extends DexBackedDexFile> container = DexUtils.loadApk(apkFile, apiLevel);\n        List<String> dexEntryNames = container.getDexEntryNames();\n        for (String dexEntryName : dexEntryNames) {\n            MultiDexContainer.DexEntry<? extends DexBackedDexFile> dexEntry =\n                    Objects.requireNonNull(container.getEntry(dexEntryName));\n            DexBackedDexFile dexFile = dexEntry.getDexFile();\n            // Store list of classes\n            for (ClassDef classDef : dexFile.getClasses()) {\n                String name = formatter.getType(classDef.getType());\n                if (name.endsWith(\";\")) name = name.substring(0, name.length() - 1);\n                if (name.startsWith(\"L\")) {\n                    name = name.substring(1).replace('/', '.');\n                }\n                mClassNameClassDefMap.put(name, classDef);\n                String baseClass = DexUtils.getClassNameWithoutInnerClasses(name);\n                List<String> classes = mBaseClassNestedClassMap.get(baseClass);\n                if (classes == null) {\n                    classes = new ArrayList<>();\n                    mBaseClassNestedClassMap.put(baseClass, classes);\n                }\n                classes.add(name);\n            }\n            if (dexFile.supportsOptimizedOpcodes()) {\n                throw new IOException(\"ODEX isn't supported.\");\n            }\n            if (dexFile instanceof DexBackedOdexFile) {\n                mOptions.inlineResolver = InlineMethodResolver.createInlineMethodResolver(\n                        ((DexBackedOdexFile) dexFile).getOdexVersion());\n            }\n        }\n    }\n\n    public DexClasses(@NonNull InputStream inputStream, @IntRange(from = -1) int apiLevel) throws IOException {\n        mOpcodes = apiLevel < 0 ? Opcodes.getDefault() : Opcodes.forApi(apiLevel);\n        mOptions = new BaksmaliOptions();\n        // options\n        mOptions.deodex = false;\n        mOptions.implicitReferences = false;\n        mOptions.parameterRegisters = true;\n        mOptions.localsDirective = true;\n        mOptions.sequentialLabels = true;\n        mOptions.debugInfo = BuildConfig.DEBUG;\n        mOptions.codeOffsets = false;\n        mOptions.accessorComments = false;\n        mOptions.registerInfo = 0;\n        mOptions.inlineResolver = null;\n        BaksmaliFormatter formatter = new BaksmaliFormatter();\n        InputStream is = new BufferedInputStream(inputStream);\n        DexBackedDexFile dexFile = DexUtils.loadDexContainer(is, apiLevel);\n        // Store list of classes\n        for (ClassDef classDef : dexFile.getClasses()) {\n            String name = formatter.getType(classDef.getType());\n            if (name.endsWith(\";\")) name = name.substring(0, name.length() - 1);\n            if (name.startsWith(\"L\")) {\n                name = name.substring(1).replace('/', '.');\n            }\n            mClassNameClassDefMap.put(name, classDef);\n            String baseClass = DexUtils.getClassNameWithoutInnerClasses(name);\n            List<String> classes = mBaseClassNestedClassMap.get(baseClass);\n            if (classes == null) {\n                classes = new ArrayList<>();\n                mBaseClassNestedClassMap.put(baseClass, classes);\n            }\n            classes.add(name);\n        }\n        if (dexFile.supportsOptimizedOpcodes()) {\n            throw new IOException(\"ODEX isn't supported.\");\n        }\n        if (dexFile instanceof DexBackedOdexFile) {\n            mOptions.inlineResolver = InlineMethodResolver.createInlineMethodResolver(\n                    ((DexBackedOdexFile) dexFile).getOdexVersion());\n        }\n    }\n\n    @NonNull\n    public List<String> getClassNames() {\n        return new ArrayList<>(mClassNameClassDefMap.keySet());\n    }\n\n    @NonNull\n    public List<String> getBaseClassNames() {\n        return new ArrayList<>(mBaseClassNestedClassMap.keySet());\n    }\n\n    @NonNull\n    public ClassDef getClassDef(@NonNull String className) throws ClassNotFoundException {\n        ClassDef classDef = mClassNameClassDefMap.get(className);\n        if (classDef == null) throw new ClassNotFoundException(className + \" could not be found.\");\n        return classDef;\n    }\n\n    @NonNull\n    public String getJavaCode(@NonNull String className) throws ClassNotFoundException {\n        try {\n            String baseClass = DexUtils.getClassNameWithoutInnerClasses(className);\n            List<String> classes = mBaseClassNestedClassMap.get(baseClass);\n            if (classes == null || classes.isEmpty() || !classes.contains(className)) {\n                throw new ClassNotFoundException();\n            }\n            List<ClassDef> classDefs = new ArrayList<>(classes.size());\n            for (String cls : classes) {\n                classDefs.add(getClassDef(cls));\n            }\n            return DexUtils.toJavaCode(classDefs, mOpcodes);\n        } catch (IOException e) {\n            throw new ClassNotFoundException(e.getMessage(), e);\n        }\n    }\n\n    @NonNull\n    public String getClassContents(@NonNull String className) throws ClassNotFoundException {\n        return getClassContents(getClassDef(className));\n    }\n\n    @NonNull\n    public String getClassContents(@NonNull ClassDef classdef) throws ClassNotFoundException {\n        StringWriter stringWriter = new StringWriter();\n        try (BaksmaliWriter baksmaliWriter = new BaksmaliWriter(stringWriter)) {\n            ClassDefinition classDefinition = new ClassDefinition(mOptions, classdef);\n            classDefinition.writeTo(baksmaliWriter);\n            return stringWriter.toString();\n        } catch (IOException e) {\n            throw new ClassNotFoundException(e.getMessage(), e);\n        }\n    }\n\n    @Override\n    public void close() throws IOException {\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/dex/DexUtils.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.dex;\n\nimport androidx.annotation.AnyThread;\nimport androidx.annotation.NonNull;\n\nimport com.android.tools.smali.dexlib2.DexFileFactory;\nimport com.android.tools.smali.dexlib2.Opcodes;\nimport com.android.tools.smali.dexlib2.dexbacked.DexBackedDexFile;\nimport com.android.tools.smali.dexlib2.dexbacked.DexBackedOdexFile;\nimport com.android.tools.smali.dexlib2.iface.ClassDef;\nimport com.android.tools.smali.dexlib2.iface.MultiDexContainer;\nimport com.android.tools.smali.dexlib2.writer.builder.DexBuilder;\nimport com.android.tools.smali.dexlib2.writer.io.DexDataStore;\nimport com.android.tools.smali.dexlib2.writer.io.FileDataStore;\nimport com.android.tools.smali.dexlib2.writer.pool.DexPool;\nimport com.android.tools.smali.smali.smaliFlexLexer;\nimport com.android.tools.smali.smali.smaliParser;\nimport com.android.tools.smali.smali.smaliTreeWalker;\n\nimport org.antlr.runtime.CommonTokenStream;\nimport org.antlr.runtime.RecognitionException;\nimport org.antlr.runtime.tree.CommonTree;\nimport org.antlr.runtime.tree.CommonTreeNodeStream;\n\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.InputStreamReader;\nimport java.io.Reader;\nimport java.io.StringReader;\nimport java.math.BigInteger;\nimport java.nio.charset.StandardCharsets;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport io.github.muntashirakon.AppManager.BuildConfig;\nimport io.github.muntashirakon.io.Path;\nimport jadx.api.JadxArgs;\nimport jadx.api.JadxDecompiler;\nimport jadx.api.JavaClass;\nimport jadx.core.utils.files.FileUtils;\n\npublic final class DexUtils {\n    @NonNull\n    public static String getClassNameWithoutInnerClasses(@NonNull String className) {\n        int idxOfDollar = findFirstInnerClassIndex(className);\n        return idxOfDollar >= 0 ? className.substring(0, idxOfDollar) : className;\n    }\n\n    public static int findFirstInnerClassIndex(@NonNull String className) {\n        // Find first $ but without matching any .\n        // This is better than String#indexOf(char) because it stops searching as soon as it finds a .\n        int validDollarIndex = -1;\n        for (int i = className.length() - 1; i >= 0; --i) {\n            int ch = className.charAt(i);\n            if (ch == '.') {\n                // Found a ., no need to look any further\n                return validDollarIndex;\n            }\n            if (ch == '$') {\n                // Found a valid index\n                validDollarIndex = i;\n                // But there can be many, so look again\n            }\n        }\n        return validDollarIndex;\n    }\n\n    @AnyThread\n    public static boolean isDex(@NonNull Path path) throws IOException {\n        int header;\n        try (InputStream is = path.openInputStream()) {\n            byte[] headerBytes = new byte[4];\n            is.read(headerBytes);\n            header = new BigInteger(headerBytes).intValue();\n        }\n        return header == 0x6465780A;\n    }\n\n    public static MultiDexContainer<? extends DexBackedDexFile> loadApk(File apkFile, int apiLevel) throws IOException {\n        return DexFileFactory.loadDexContainer(apkFile, apiLevel < 0 ? Opcodes.getDefault() : Opcodes.forApi(apiLevel));\n    }\n\n    public static void storeDex(@NonNull List<ClassDef> classDefList, @NonNull DexDataStore dataStore, int apiLevel)\n            throws IOException {\n        Opcodes opcodes = apiLevel < 0 ? Opcodes.getDefault() : Opcodes.forApi(apiLevel);\n        DexPool dexPool = new DexPool(opcodes);\n        for (ClassDef classDef : classDefList) {\n            dexPool.internClass(classDef);\n        }\n        dexPool.writeTo(dataStore);\n    }\n\n    @NonNull\n    public static ClassDef toClassDef(@NonNull File smaliFile, int apiLevel) throws IOException, RecognitionException {\n        try (InputStreamReader sr = new InputStreamReader(new FileInputStream(smaliFile), StandardCharsets.UTF_8)) {\n            return toClassDef(sr, apiLevel);\n        }\n    }\n\n    @NonNull\n    public static ClassDef toClassDef(@NonNull String smaliContents, int apiLevel)\n            throws IOException, RecognitionException {\n        try (StringReader sr = new StringReader(smaliContents)) {\n            return toClassDef(sr, apiLevel);\n        }\n    }\n\n    @NonNull\n    public static ClassDef toClassDef(@NonNull Reader smaliReader, int apiLevel)\n            throws IOException, RecognitionException {\n        Opcodes opcodes = apiLevel < 0 ? Opcodes.getDefault() : Opcodes.forApi(apiLevel);\n        smaliFlexLexer lexer = new smaliFlexLexer(smaliReader, opcodes.api);\n        CommonTokenStream tokens = new CommonTokenStream(lexer);\n        smaliParser parser = new smaliParser(tokens);\n        parser.setVerboseErrors(false);\n        parser.setAllowOdex(false);\n        parser.setApiLevel(opcodes.api);\n        smaliParser.smali_file_return result = parser.smali_file();\n        if (parser.getNumberOfSyntaxErrors() > 0 || lexer.getNumberOfSyntaxErrors() > 0) {\n            throw new IOException((parser.getNumberOfSyntaxErrors() + lexer.getNumberOfSyntaxErrors())\n                    + \" syntax errors during parsing and/or lexing.\");\n        }\n\n        CommonTree t = result.getTree();\n        CommonTreeNodeStream treeStream = new CommonTreeNodeStream(t);\n        treeStream.setTokenStream(tokens);\n\n        DexBuilder dexBuilder = new DexBuilder(opcodes);\n        smaliTreeWalker dexGen = new smaliTreeWalker(treeStream);\n        dexGen.setApiLevel(opcodes.api);\n        dexGen.setVerboseErrors(false);\n        dexGen.setDexBuilder(dexBuilder);\n        ClassDef classDef = dexGen.smali_file();\n\n        if (dexGen.getNumberOfSyntaxErrors() > 0) {\n            throw new IOException(dexGen.getNumberOfSyntaxErrors() + \" syntax errors during dex creation\");\n        }\n\n        if (classDef == null) {\n            throw new IOException(\"Could not generate class from smali.\");\n        }\n        return classDef;\n    }\n\n    @NonNull\n    public static String toJavaCode(@NonNull List<ClassDef> classDefs, @NonNull Opcodes opcodes) throws IOException {\n        File tmp = FileUtils.createTempFile(\".dex\");\n        try {\n            DexPool pool = new DexPool(opcodes);\n            for (ClassDef classDef : classDefs) {\n                pool.internClass(classDef);\n            }\n            pool.writeTo(new FileDataStore(tmp));\n            return toJavaCode(tmp);\n        } finally {\n            tmp.delete();\n        }\n    }\n\n    @NonNull\n    public static String toJavaCode(@NonNull ClassDef classDef, @NonNull Opcodes opcodes) throws IOException {\n        File tmp = FileUtils.createTempFile(\".dex\");\n        try {\n            DexPool pool = new DexPool(opcodes);\n            pool.internClass(classDef);\n            pool.writeTo(new FileDataStore(tmp));\n            return toJavaCode(tmp);\n        } finally {\n            tmp.delete();\n        }\n    }\n\n    @NonNull\n    public static String toJavaCode(@NonNull List<String> smaliContents, int api) throws IOException {\n        Opcodes opcodes = api < 0 ? Opcodes.getDefault() : Opcodes.forApi(api);\n        try {\n            List<ClassDef> classDefs = new ArrayList<>(smaliContents.size());\n            for (String smaliContent : smaliContents) {\n                classDefs.add(toClassDef(smaliContent, api));\n            }\n            return toJavaCode(classDefs, opcodes);\n        } catch (RecognitionException e) {\n            throw new IOException(e);\n        }\n    }\n\n    @NonNull\n    public static String toJavaCode(@NonNull String smaliContent, int api) throws IOException {\n        Opcodes opcodes = api < 0 ? Opcodes.getDefault() : Opcodes.forApi(api);\n        try {\n            return toJavaCode(toClassDef(smaliContent, api), opcodes);\n        } catch (RecognitionException e) {\n            throw new IOException(e);\n        }\n    }\n\n    @NonNull\n    public static String toJavaCode(@NonNull File dexFile) {\n        JadxArgs args = new JadxArgs();\n        args.setInputFile(dexFile);\n        args.setSkipResources(true);\n        args.setShowInconsistentCode(true);\n        args.setDebugInfo(BuildConfig.DEBUG);\n        try (JadxDecompiler decompiler = new JadxDecompiler(args)) {\n            decompiler.load();\n            JavaClass javaClass = decompiler.getClasses().iterator().next();\n            javaClass.decompile();\n            return javaClass.getCode();\n        }\n    }\n\n    @NonNull\n    public static DexBackedDexFile loadDexContainer(@NonNull InputStream inputStream, int api) throws IOException {\n        Opcodes opcodes = api < 0 ? Opcodes.getDefault() : Opcodes.forApi(api);\n        try {\n            return DexBackedDexFile.fromInputStream(opcodes, inputStream);\n        } catch (DexBackedDexFile.NotADexFile ex) {\n            // just eat it\n        }\n        try {\n            return DexBackedOdexFile.fromInputStream(opcodes, inputStream);\n        } catch (DexBackedOdexFile.NotAnOdexFile ex) {\n            // just eat it\n        }\n        throw new DexFileFactory.UnsupportedFileTypeException(\"InputStream is not a dex, odex file.\");\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/editor/CodeEditorActivity.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.editor;\n\nimport android.content.Context;\nimport android.content.Intent;\nimport android.net.Uri;\nimport android.os.Bundle;\nimport android.view.MenuItem;\nimport android.view.View;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.appcompat.app.ActionBar;\n\nimport com.google.android.material.progressindicator.LinearProgressIndicator;\n\nimport io.github.muntashirakon.AppManager.BaseActivity;\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.intercept.IntentCompat;\nimport io.github.muntashirakon.io.Paths;\n\npublic class CodeEditorActivity extends BaseActivity {\n    public static final String ALIAS_EDITOR = \"io.github.muntashirakon.AppManager.editor.EditorActivity\";\n\n    private static final String EXTRA_READ_ONLY = \"read_only\";\n\n    public static Intent getIntent(@NonNull Context context, @NonNull Uri uri, @Nullable String title, @Nullable String subtitle, boolean readOnly) {\n        return new Intent(context, CodeEditorActivity.class)\n                .setData(uri)\n                .putExtra(EXTRA_READ_ONLY, readOnly)\n                .putExtra(Intent.EXTRA_TITLE, title)\n                .putExtra(Intent.EXTRA_SUBJECT, subtitle);\n    }\n\n    public static Intent getIntent(@NonNull Context context, @NonNull Uri uri, @Nullable String title, @Nullable String subtitle) {\n        return new Intent(context, CodeEditorActivity.class)\n                .setData(uri)\n                .putExtra(Intent.EXTRA_TITLE, title)\n                .putExtra(Intent.EXTRA_SUBJECT, subtitle);\n    }\n\n    @Override\n    protected void onAuthenticated(@Nullable Bundle savedInstanceState) {\n        setContentView(R.layout.activity_code_editor);\n        setSupportActionBar(findViewById(R.id.toolbar));\n        LinearProgressIndicator progressIndicator = findViewById(R.id.progress_linear);\n        progressIndicator.setVisibilityAfterHide(View.GONE);\n        String title = getIntent().getStringExtra(Intent.EXTRA_TITLE);\n        if (title == null) {\n            title = getString(R.string.title_code_editor);\n        }\n        String subtitle = getIntent().getStringExtra(Intent.EXTRA_SUBJECT);\n        Uri fileUri = IntentCompat.getDataUri(getIntent());\n        boolean readOnly = getIntent().getBooleanExtra(EXTRA_READ_ONLY, false);\n        if (subtitle == null) {\n            if (fileUri != null) {\n                subtitle = Paths.trimPathExtension(fileUri.getLastPathSegment());\n            } else {\n                subtitle = \"Untitled.txt\";\n            }\n        }\n        if (fileUri == null) {\n            progressIndicator.hide();\n        }\n        CodeEditorFragment.Options options = new CodeEditorFragment.Options.Builder()\n                .setUri(fileUri)\n                .setTitle(title)\n                .setSubtitle(subtitle)\n                .setEnableSharing(false)\n                .setJavaSmaliToggle(false)\n                .setReadOnly(readOnly)\n                .build();\n        CodeEditorFragment fragment = new CodeEditorFragment();\n        Bundle args = new Bundle();\n        args.putParcelable(CodeEditorFragment.ARG_OPTIONS, options);\n        fragment.setArguments(args);\n        getSupportFragmentManager()\n                .beginTransaction()\n                .replace(R.id.container, fragment)\n                .commit();\n        ActionBar actionBar = getSupportActionBar();\n        if (actionBar != null) {\n            actionBar.setTitle(title);\n            actionBar.setSubtitle(subtitle);\n        }\n    }\n\n    @Override\n    public boolean onOptionsItemSelected(@NonNull MenuItem item) {\n        if (item.getItemId() == android.R.id.home) {\n            getOnBackPressedDispatcher().onBackPressed();\n            return true;\n        }\n        return super.onOptionsItemSelected(item);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/editor/CodeEditorFragment.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.editor;\n\nimport android.app.Activity;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.graphics.Typeface;\nimport android.net.Uri;\nimport android.os.Bundle;\nimport android.os.Parcel;\nimport android.os.Parcelable;\nimport android.text.Editable;\nimport android.text.TextUtils;\nimport android.text.TextWatcher;\nimport android.view.LayoutInflater;\nimport android.view.Menu;\nimport android.view.MenuInflater;\nimport android.view.MenuItem;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.HorizontalScrollView;\nimport android.widget.TextView;\n\nimport androidx.activity.OnBackPressedCallback;\nimport androidx.activity.result.ActivityResultLauncher;\nimport androidx.activity.result.contract.ActivityResultContracts;\nimport androidx.annotation.MainThread;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.appcompat.widget.LinearLayoutCompat;\nimport androidx.appcompat.widget.PopupMenu;\nimport androidx.core.os.BundleCompat;\nimport androidx.core.os.ParcelCompat;\nimport androidx.core.view.MenuProvider;\nimport androidx.lifecycle.Lifecycle;\nimport androidx.lifecycle.ViewModelProvider;\nimport androidx.transition.Transition;\nimport androidx.transition.TransitionManager;\n\nimport com.google.android.material.button.MaterialButton;\nimport com.google.android.material.color.MaterialColors;\nimport com.google.android.material.dialog.MaterialAlertDialogBuilder;\nimport com.google.android.material.elevation.SurfaceColors;\nimport com.google.android.material.progressindicator.LinearProgressIndicator;\nimport com.google.android.material.textfield.TextInputEditText;\nimport com.google.android.material.textfield.TextInputLayout;\nimport com.google.android.material.transition.MaterialSharedAxis;\n\nimport java.util.Objects;\nimport java.util.regex.PatternSyntaxException;\n\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.app.AndroidFragment;\nimport io.github.muntashirakon.AppManager.fm.FmProvider;\nimport io.github.muntashirakon.AppManager.intercept.IntentCompat;\nimport io.github.muntashirakon.AppManager.utils.UIUtils;\nimport io.github.muntashirakon.io.Path;\nimport io.github.muntashirakon.io.Paths;\nimport io.github.muntashirakon.util.UiUtils;\nimport io.github.rosemoe.sora.event.ContentChangeEvent;\nimport io.github.rosemoe.sora.event.PublishSearchResultEvent;\nimport io.github.rosemoe.sora.event.SelectionChangeEvent;\nimport io.github.rosemoe.sora.lang.EmptyLanguage;\nimport io.github.rosemoe.sora.lang.Language;\nimport io.github.rosemoe.sora.langs.textmate.TextMateColorScheme;\nimport io.github.rosemoe.sora.text.Content;\nimport io.github.rosemoe.sora.text.Cursor;\nimport io.github.rosemoe.sora.text.LineSeparator;\nimport io.github.rosemoe.sora.widget.CodeEditor;\nimport io.github.rosemoe.sora.widget.DirectAccessProps;\nimport io.github.rosemoe.sora.widget.EditorSearcher.SearchOptions;\nimport io.github.rosemoe.sora.widget.SymbolInputView;\nimport io.github.rosemoe.sora.widget.schemes.EditorColorScheme;\n\npublic class CodeEditorFragment extends AndroidFragment implements MenuProvider {\n    public static final String ARG_OPTIONS = \"options\";\n\n    public static class Options implements Parcelable {\n        @Nullable\n        public final Uri uri;\n        @Nullable\n        public final String title;\n        @Nullable\n        public final String subtitle;\n        public final boolean readOnly;\n        public final boolean javaSmaliToggle;\n        public final boolean enableSharing;\n\n        private Options(@Nullable Uri uri, @Nullable String title, @Nullable String subtitle, boolean readOnly,\n                        boolean javaSmaliToggle, boolean enableSharing) {\n            this.uri = uri;\n            this.title = title;\n            this.subtitle = subtitle;\n            this.readOnly = readOnly;\n            this.javaSmaliToggle = javaSmaliToggle;\n            this.enableSharing = enableSharing;\n        }\n\n        protected Options(@NonNull Parcel in) {\n            uri = ParcelCompat.readParcelable(in, Uri.class.getClassLoader(), Uri.class);\n            title = in.readString();\n            subtitle = in.readString();\n            readOnly = in.readByte() != 0;\n            javaSmaliToggle = in.readByte() != 0;\n            enableSharing = in.readByte() != 0;\n        }\n\n        public static final Creator<Options> CREATOR = new Creator<Options>() {\n            @Override\n            public Options createFromParcel(Parcel in) {\n                return new Options(in);\n            }\n\n            @Override\n            public Options[] newArray(int size) {\n                return new Options[size];\n            }\n        };\n\n        @Override\n        public int describeContents() {\n            return 0;\n        }\n\n        @Override\n        public void writeToParcel(@NonNull Parcel dest, int flags) {\n            dest.writeParcelable(uri, flags);\n            dest.writeString(title);\n            dest.writeString(subtitle);\n            dest.writeByte((byte) (readOnly ? 1 : 0));\n            dest.writeByte((byte) (javaSmaliToggle ? 1 : 0));\n            dest.writeByte((byte) (enableSharing ? 1 : 0));\n        }\n\n        public static class Builder {\n            @Nullable\n            private Uri uri;\n            @Nullable\n            private String title;\n            @Nullable\n            private String subtitle;\n            private boolean readOnly = false;\n            private boolean javaSmaliToggle = false;\n            private boolean enableSharing = true;\n\n            public Builder() {\n            }\n\n            public Builder(@NonNull Options options) {\n                uri = options.uri;\n                title = options.title;\n                subtitle = options.subtitle;\n                readOnly = options.readOnly;\n                javaSmaliToggle = options.javaSmaliToggle;\n                enableSharing = options.enableSharing;\n            }\n\n            public Builder setUri(@Nullable Uri uri) {\n                this.uri = uri;\n                return this;\n            }\n\n            public Builder setTitle(@Nullable String title) {\n                this.title = title;\n                return this;\n            }\n\n            public Builder setSubtitle(@Nullable String subtitle) {\n                this.subtitle = subtitle;\n                return this;\n            }\n\n            public Builder setReadOnly(boolean readOnly) {\n                this.readOnly = readOnly;\n                return this;\n            }\n\n            public Builder setJavaSmaliToggle(boolean javaSmaliToggle) {\n                this.javaSmaliToggle = javaSmaliToggle;\n                return this;\n            }\n\n            public Builder setEnableSharing(boolean enableSharing) {\n                this.enableSharing = enableSharing;\n                return this;\n            }\n\n            public Options build() {\n                return new Options(uri, title, subtitle, readOnly, javaSmaliToggle, enableSharing);\n            }\n        }\n    }\n\n    private EditorColorScheme mColorScheme;\n    private CodeEditor mEditor;\n    private SymbolInputView mSymbolInputView;\n    private TextView mPositionButton;\n    private MaterialButton mLockButton;\n    private LinearLayoutCompat mSearchWidget;\n    private TextInputEditText mSearchView;\n    private TextInputEditText mReplaceView;\n    private TextInputLayout mReplaceViewContainer;\n    private MaterialButton mReplaceButton;\n    private MaterialButton mReplaceAllButton;\n    private TextView mSearchResultCount;\n    private Options mOptions;\n    private SearchOptions mSearchOptions = new SearchOptions(false, false);\n    private MenuItem mSaveMenu;\n    private MenuItem mUndoMenu;\n    private MenuItem mRedoMenu;\n    private MenuItem mJavaSmaliToggleMenu;\n    private MenuItem mShareMenu;\n    private CodeEditorViewModel mViewModel;\n    private boolean mTextModified = false;\n    private final ActivityResultLauncher<Intent> mSaveOpenedFile = registerForActivityResult(\n            new ActivityResultContracts.StartActivityForResult(),\n            result -> {\n                try {\n                    if (result.getResultCode() != Activity.RESULT_OK) {\n                        return;\n                    }\n                    Intent data = result.getData();\n                    Uri uri = IntentCompat.getDataUri(data);\n                    if (uri == null) return;\n                    int takeFlags = data.getFlags() & (Intent.FLAG_GRANT_READ_URI_PERMISSION\n                            | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);\n                    saveFile(mEditor.getText(), uri);\n                    if (takeFlags != 0) {\n                        // Make this URI the current URI\n                        mOptions = new Options.Builder(mOptions)\n                                .setUri(uri)\n                                .setSubtitle(Paths.get(uri).getName())\n                                .build();\n                        mViewModel.setOptions(mOptions);\n                    }\n                } finally {\n                    showProgressIndicator(false);\n                    unlockEditor();\n                }\n            });\n    private final OnBackPressedCallback mExitSearchBackPressedCallback = new OnBackPressedCallback(false) {\n        @Override\n        public void handleOnBackPressed() {\n            if (mSearchWidget != null && mSearchWidget.getVisibility() == View.VISIBLE) {\n                hideSearchWidget();\n                return;\n            }\n            setEnabled(false);\n            requireActivity().getOnBackPressedDispatcher().onBackPressed();\n        }\n    };\n    private final OnBackPressedCallback mTextModifiedBackPressedCallback = new OnBackPressedCallback(false) {\n        @Override\n        public void handleOnBackPressed() {\n            if (mTextModified) {\n                new MaterialAlertDialogBuilder(requireContext())\n                        .setTitle(R.string.exit_confirmation)\n                        .setMessage(R.string.file_modified_are_you_sure)\n                        .setPositiveButton(R.string.no, null)\n                        .setNegativeButton(R.string.yes, (dialog, which) -> {\n                            setEnabled(false);\n                            requireActivity().getOnBackPressedDispatcher().onBackPressed();\n                        })\n                        .setNeutralButton(R.string.save_and_exit, (dialog, which) -> {\n                            saveFile();\n                            setEnabled(false);\n                            requireActivity().getOnBackPressedDispatcher().onBackPressed();\n                        })\n                        .show();\n                return;\n            }\n            setEnabled(false);\n            requireActivity().getOnBackPressedDispatcher().onBackPressed();\n        }\n    };\n\n    @Nullable\n    @Override\n    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {\n        return inflater.inflate(R.layout.fragment_code_editor, container, false);\n    }\n\n    @Override\n    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {\n        mViewModel = new ViewModelProvider(this).get(CodeEditorViewModel.class);\n        mOptions = Objects.requireNonNull(BundleCompat.getParcelable(requireArguments(), ARG_OPTIONS, Options.class));\n        mViewModel.setOptions(mOptions);\n        mColorScheme = EditorThemes.getColorScheme(requireContext());\n        mEditor = view.findViewById(R.id.editor);\n        mEditor.setColorScheme(mColorScheme);\n        mEditor.setTypefaceText(Typeface.MONOSPACE);\n        mEditor.setTextSize(14);\n        mEditor.setLineSpacing(2f, 1.1f);\n        mEditor.subscribeEvent(ContentChangeEvent.class, (event, unsubscribe) -> {\n            if (!mTextModified && event.getAction() != ContentChangeEvent.ACTION_SET_NEW_TEXT) {\n                mTextModified = true;\n                mTextModifiedBackPressedCallback.setEnabled(true);\n                getActionBar().ifPresent(actionBar -> actionBar.setSubtitle(\"* \" + mOptions.subtitle));\n            }\n            mEditor.postDelayed(this::updateLiveButtons, 50);\n        });\n        mEditor.subscribeEvent(SelectionChangeEvent.class, (event, unsubscribe) -> getFragmentActivity()\n                .ifPresent(activity -> updatePositionText()));\n        mEditor.subscribeEvent(PublishSearchResultEvent.class, (event, unsubscribe) -> getFragmentActivity()\n                .ifPresent(activity -> {\n                    updatePositionText();\n                    updateSearchResult();\n                }));\n        DirectAccessProps props = mEditor.getProps();\n        props.useICULibToSelectWords = false;\n        props.symbolPairAutoCompletion = false;\n        props.deleteMultiSpaces = -1;\n        props.deleteEmptyLineFast = false;\n        mSymbolInputView = view.findViewById(R.id.symbol_input);\n        mSymbolInputView.addSymbols(\n                new String[]{\"⇥\", \"{\", \"}\", \"(\", \")\", \",\", \".\", \";\", \"\\\"\", \"?\", \"+\", \"-\", \"*\", \"/\"},\n                new String[]{\"\\t\", \"{\", \"}\", \"(\", \")\", \",\", \".\", \";\", \"\\\"\", \"?\", \"+\", \"-\", \"*\", \"/\"});\n        mSymbolInputView.setTextColor(MaterialColors.getColor(mSymbolInputView, com.google.android.material.R.attr.colorOnSurface));\n        mSymbolInputView.setBackground(null);\n        ((HorizontalScrollView) mSymbolInputView.getParent()).setBackgroundColor(SurfaceColors.SURFACE_2.getColor(requireContext()));\n        mSymbolInputView.bindEditor(mEditor);\n        if (mOptions.readOnly) {\n            mSymbolInputView.setVisibility(View.GONE);\n        }\n        // Setup search widget\n        mSearchWidget = view.findViewById(R.id.search_container);\n        mSearchView = view.findViewById(R.id.search_bar);\n        mSearchView.addTextChangedListener(new TextWatcher() {\n            @Override\n            public void beforeTextChanged(CharSequence s, int start, int count, int after) {\n            }\n\n            @Override\n            public void onTextChanged(CharSequence s, int start, int before, int count) {\n            }\n\n            @Override\n            public void afterTextChanged(Editable s) {\n                if (TextUtils.isEmpty(s)) {\n                    mEditor.getSearcher().stopSearch();\n                } else {\n                    try {\n                        mEditor.getSearcher().search(s.toString(), mSearchOptions);\n                    } catch (PatternSyntaxException ignore) {\n                    }\n                }\n            }\n        });\n        TextInputLayout searchViewContainer = view.findViewById(R.id.search_bar_container);\n        searchViewContainer.setEndIconOnClickListener(v -> {\n            PopupMenu popupMenu = new PopupMenu(v.getContext(), v);\n            Menu menu = popupMenu.getMenu();\n            menu.add(R.string.search_option_match_case)\n                    .setCheckable(true)\n                    .setChecked(!mSearchOptions.ignoreCase)\n                    .setOnMenuItemClickListener(item -> {\n                        boolean ignoreCase = item.isChecked();\n                        item.setChecked(ignoreCase);\n                        mSearchOptions = new SearchOptions(mSearchOptions.type, ignoreCase);\n                        search(mSearchView.getText());\n                        return true;\n                    });\n            menu.add(R.string.search_option_regex)\n                    .setCheckable(true)\n                    .setChecked(mSearchOptions.type == SearchOptions.TYPE_REGULAR_EXPRESSION)\n                    .setOnMenuItemClickListener(item -> {\n                        boolean regex = !item.isChecked();\n                        item.setChecked(regex);\n                        int type = regex ? SearchOptions.TYPE_REGULAR_EXPRESSION : SearchOptions.TYPE_NORMAL;\n                        mSearchOptions = new SearchOptions(type, mSearchOptions.ignoreCase);\n                        search(mSearchView.getText());\n                        return true;\n                    });\n            menu.add(R.string.search_option_whole_word)\n                    .setCheckable(true)\n                    .setChecked(mSearchOptions.type == SearchOptions.TYPE_WHOLE_WORD)\n                    .setOnMenuItemClickListener(item -> {\n                        boolean wholeWord = !item.isChecked();\n                        item.setChecked(wholeWord);\n                        int type = wholeWord ? SearchOptions.TYPE_WHOLE_WORD : SearchOptions.TYPE_NORMAL;\n                        mSearchOptions = new SearchOptions(type, mSearchOptions.ignoreCase);\n                        search(mSearchView.getText());\n                        return true;\n                    });\n            popupMenu.show();\n        });\n        mSearchResultCount = view.findViewById(R.id.search_result_count);\n        view.findViewById(R.id.previous_button).setOnClickListener(v -> {\n            if (!mEditor.getSearcher().hasQuery()) {\n                return;\n            }\n            mEditor.getSearcher().gotoPrevious();\n        });\n        view.findViewById(R.id.next_button).setOnClickListener(v -> {\n            if (!mEditor.getSearcher().hasQuery()) {\n                return;\n            }\n            mEditor.getSearcher().gotoNext();\n        });\n        mReplaceView = view.findViewById(R.id.replace_bar);\n        mReplaceViewContainer = view.findViewById(R.id.replace_bar_container);\n        mReplaceButton = view.findViewById(R.id.replace_button);\n        mReplaceAllButton = view.findViewById(R.id.replace_all_button);\n        mReplaceButton.setOnClickListener(v -> {\n            if (!mEditor.getSearcher().hasQuery()) {\n                return;\n            }\n            CharSequence query = mReplaceView.getText();\n            if (!TextUtils.isEmpty(query)) {\n                mEditor.getSearcher().replaceThis(query.toString());\n            }\n        });\n        mReplaceAllButton.setOnClickListener(v -> {\n            if (!mEditor.getSearcher().hasQuery()) {\n                return;\n            }\n            CharSequence query = mReplaceView.getText();\n            if (!TextUtils.isEmpty(query)) {\n                mEditor.getSearcher().replaceAll(query.toString());\n            }\n        });\n        // Setup status bar\n        mLockButton = view.findViewById(R.id.lock);\n        mLockButton.setOnClickListener(v -> {\n            // Toggle lock\n            if (mEditor.isEditable()) {\n                lockEditor();\n            } else {\n                unlockEditor();\n            }\n        });\n        TextView languageButton = view.findViewById(R.id.language);\n        languageButton.setOnClickListener(v -> {\n            // TODO: 13/9/22 Display all the supported languages\n        });\n        // TODO: 13/9/22 Enable setting custom tab size if possible (e.g. Makefile requires tab)\n        TextView indentSizeButton = view.findViewById(R.id.tab_size);\n        TextView lineSeparatorButton = view.findViewById(R.id.line_separator);\n        lineSeparatorButton.setOnClickListener(v -> {\n            PopupMenu popupMenu = new PopupMenu(requireContext(), v);\n            Menu menu = popupMenu.getMenu();\n            menu.add(R.string.line_separator).setEnabled(false);\n            if (!mEditor.getLineSeparator().equals(LineSeparator.CRLF)) {\n                menu.add(\"CRLF - Windows (\\\\r\\\\n)\").setOnMenuItemClickListener(menuItem -> {\n                    mEditor.setLineSeparator(LineSeparator.CRLF);\n                    // TODO: 18/9/22 Update line separator for existing texts\n                    lineSeparatorButton.setText(mEditor.getLineSeparator().name());\n                    return true;\n                });\n            }\n            if (!mEditor.getLineSeparator().equals(LineSeparator.CR)) {\n                menu.add(\"CR - Classic Mac OS (\\\\r)\").setOnMenuItemClickListener(menuItem -> {\n                    mEditor.setLineSeparator(LineSeparator.CR);\n                    lineSeparatorButton.setText(mEditor.getLineSeparator().name());\n                    return true;\n                });\n            }\n            if (!mEditor.getLineSeparator().equals(LineSeparator.LF)) {\n                menu.add(\"LF - Unix & Mac OS (\\\\n)\").setOnMenuItemClickListener(menuItem -> {\n                    mEditor.setLineSeparator(LineSeparator.LF);\n                    lineSeparatorButton.setText(mEditor.getLineSeparator().name());\n                    return true;\n                });\n            }\n            popupMenu.show();\n        });\n        mPositionButton = view.findViewById(R.id.position);\n        mPositionButton.setOnClickListener(v -> {\n            // TODO: 13/9/22 Enable going to custom places\n        });\n        requireActivity().addMenuProvider(this, getViewLifecycleOwner(), Lifecycle.State.RESUMED);\n\n        // Update live buttons at the start\n        updateLiveButtons();\n        updateStartupMenu();\n        UiUtils.applyWindowInsetsAsPaddingNoTop(view.findViewById(R.id.editor_container));\n\n        mViewModel.getContentLiveData().observe(getViewLifecycleOwner(), content -> {\n            showProgressIndicator(false);\n            if (content == null) {\n                UIUtils.displayLongToast(R.string.failed);\n                return;\n            }\n            mEditor.setEditorLanguage(getLanguage(mViewModel.getLanguage()));\n            if (mViewModel.isReadOnly()) {\n                mLockButton.setIconResource(R.drawable.ic_lock);\n                mLockButton.setEnabled(false);\n                mEditor.setEditable(false);\n            } else {\n                mLockButton.setEnabled(true);\n            }\n            languageButton.setText(mViewModel.getLanguage());\n            languageButton.setEnabled(!mViewModel.isReadOnly());\n            indentSizeButton.setEnabled(!mViewModel.isReadOnly());\n            // TODO: 13/9/22 Use localization\n            CharSequence tabSize = mEditor.getTabWidth() + \" \" + (mEditor.getEditorLanguage().useTab() ? \"tabs\" : \"spaces\");\n            indentSizeButton.setText(tabSize);\n            lineSeparatorButton.setEnabled(!mViewModel.isReadOnly());\n            mEditor.setText(content);\n            lineSeparatorButton.setText(mEditor.getLineSeparator().name());\n            updatePositionText();\n        });\n        mViewModel.getSaveFileLiveData().observe(getViewLifecycleOwner(), successful -> {\n            if (successful) {\n                UIUtils.displayShortToast(R.string.saved_successfully);\n                mTextModified = false;\n                mTextModifiedBackPressedCallback.setEnabled(false);\n                getActionBar().ifPresent(actionBar -> actionBar.setSubtitle(mOptions.subtitle));\n            } else {\n                UIUtils.displayLongToast(R.string.saving_failed);\n            }\n        });\n        mViewModel.getJavaFileLiveData().observe(getViewLifecycleOwner(), uri -> {\n            CodeEditorFragment.Options options = new CodeEditorFragment.Options.Builder()\n                    .setUri(uri)\n                    .setTitle(mOptions.title)\n                    .setSubtitle(mOptions.subtitle)\n                    .setEnableSharing(true)\n                    .setJavaSmaliToggle(false)\n                    .setReadOnly(true)\n                    .build();\n            CodeEditorFragment fragment = new CodeEditorFragment();\n            Bundle args = new Bundle();\n            args.putParcelable(CodeEditorFragment.ARG_OPTIONS, options);\n            fragment.setArguments(args);\n            getFragmentActivity().ifPresent(activity -> activity\n                    .getSupportFragmentManager()\n                    .beginTransaction()\n                    .replace(((ViewGroup) requireView().getParent()).getId(), fragment)\n                    .addToBackStack(null)\n                    .commit());\n        });\n        mViewModel.loadFileContentIfAvailable();\n    }\n\n    @Override\n    public void onAttach(@NonNull Context context) {\n        super.onAttach(context);\n        // Handle back press: The order MUST be kept same\n        requireActivity().getOnBackPressedDispatcher().addCallback(this, mTextModifiedBackPressedCallback);\n        requireActivity().getOnBackPressedDispatcher().addCallback(this, mExitSearchBackPressedCallback);\n    }\n\n    @Override\n    public void onResume() {\n        super.onResume();\n        getActionBar().ifPresent(actionBar -> {\n            actionBar.setTitle(mOptions.title);\n            actionBar.setSubtitle((mTextModified ? \"* \" : \"\") + mOptions.subtitle);\n        });\n    }\n\n    @Override\n    public void onCreateMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) {\n        inflater.inflate(R.menu.activity_code_editor_actions, menu);\n        mSaveMenu = menu.findItem(R.id.action_save);\n        mUndoMenu = menu.findItem(R.id.action_undo);\n        mRedoMenu = menu.findItem(R.id.action_redo);\n        mJavaSmaliToggleMenu = menu.findItem(R.id.action_java_smali_toggle);\n        mShareMenu = menu.findItem(R.id.action_share);\n        updateStartupMenu();\n    }\n\n    @Override\n    public boolean onMenuItemSelected(@NonNull MenuItem item) {\n        int id = item.getItemId();\n        if (id == R.id.action_undo) {\n            if (mEditor != null && mEditor.canUndo()) {\n                mEditor.undo();\n                return true;\n            }\n        } else if (id == R.id.action_redo) {\n            if (mEditor != null && mEditor.canRedo()) {\n                mEditor.redo();\n                return true;\n            }\n        } else if (id == R.id.action_wrap) {\n            if (mEditor != null) {\n                mEditor.setWordwrap(!mEditor.isWordwrap());\n                return true;\n            }\n        } else if (id == R.id.action_save) {\n            saveFile();\n            return true;\n        } else if (id == R.id.action_save_as) {\n            launchIntentSaver();\n            return true;\n        } else if (id == R.id.action_share) {\n            Path filePath = mViewModel.getSourceFile();\n            if (filePath != null) {\n                Intent intent = new Intent(Intent.ACTION_SEND)\n                        .setType(filePath.getType())\n                        .putExtra(Intent.EXTRA_STREAM, FmProvider.getContentUri(filePath))\n                        .addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_ACTIVITY_NEW_TASK);\n                startActivity(Intent.createChooser(intent, getString(R.string.share)));\n            }\n            return true;\n        } else if (id == R.id.action_java_smali_toggle) {\n            mViewModel.generateJava(mEditor.getText());\n            return true;\n        } else if (id == R.id.action_search) {\n            if (mSearchWidget != null) {\n                // FIXME: 21/4/23 Ideally, search widget should have cross button to close it.\n                if (mSearchWidget.getVisibility() == View.VISIBLE) {\n                    hideSearchWidget();\n                } else showSearchWidget();\n                return true;\n            }\n        }\n        return false;\n    }\n\n    private void showProgressIndicator(boolean show) {\n        LinearProgressIndicator progressIndicator = requireActivity().findViewById(R.id.progress_linear);\n        if (progressIndicator != null) {\n            if (show) {\n                progressIndicator.show();\n            } else {\n                progressIndicator.hide();\n            }\n        }\n    }\n\n    private void updateLiveButtons() {\n        boolean readOnly = mViewModel.isReadOnly();\n        if (mSaveMenu != null) {\n            mSaveMenu.setEnabled(mTextModified && !readOnly);\n        }\n        if (mUndoMenu != null) {\n            mUndoMenu.setEnabled(mEditor != null && mEditor.canUndo() && !readOnly);\n        }\n        if (mRedoMenu != null) {\n            mRedoMenu.setEnabled(mEditor != null && mEditor.canRedo() && !readOnly);\n        }\n        if (mReplaceViewContainer != null) {\n            mReplaceViewContainer.setVisibility(readOnly ? View.GONE : View.VISIBLE);\n        }\n        if (mReplaceButton != null) {\n            mReplaceButton.setVisibility(readOnly ? View.GONE : View.VISIBLE);\n        }\n        if (mReplaceAllButton != null) {\n            mReplaceAllButton.setVisibility(readOnly ? View.GONE : View.VISIBLE);\n        }\n    }\n\n    private void updateStartupMenu() {\n        if (mViewModel == null) return;\n        if (mJavaSmaliToggleMenu != null) {\n            mJavaSmaliToggleMenu.setVisible(mViewModel.canGenerateJava());\n            mJavaSmaliToggleMenu.setEnabled(mViewModel.canGenerateJava());\n        }\n        if (mShareMenu != null) {\n            mShareMenu.setEnabled(mViewModel.isBackedByAFile());\n        }\n    }\n\n    @MainThread\n    private void updatePositionText() {\n        Cursor cursor = mEditor.getCursor();\n        StringBuilder text = new StringBuilder()\n                .append(1 + cursor.getLeftLine())\n                .append(\":\")\n                .append(cursor.getLeftColumn());\n        if (cursor.isSelected()) {\n            text.append(\" (\")\n                    .append(cursor.getRight() - cursor.getLeft())\n                    .append(\" chars)\");\n        }\n        mPositionButton.setText(text);\n    }\n\n    @MainThread\n    private void updateSearchResult() {\n        int count = mEditor.getSearcher().hasQuery() ? mEditor.getSearcher().getMatchedPositionCount() : 0;\n        mSearchResultCount.setText(getResources().getQuantityString(R.plurals.search_results, count, count));\n    }\n\n    private void saveFile() {\n        if (!mViewModel.isBackedByAFile()) {\n            launchIntentSaver();\n        } else if (mViewModel.canWrite()) {\n            saveFile(mEditor.getText(), null);\n        } else {\n            new MaterialAlertDialogBuilder(requireContext())\n                    .setTitle(R.string.read_only_file)\n                    .setMessage(R.string.read_only_file_warning)\n                    .setPositiveButton(R.string.yes, (dialog, which) -> launchIntentSaver())\n                    .setNegativeButton(R.string.no, null)\n                    .show();\n        }\n    }\n\n    private void saveFile(Content content, @Nullable Uri uri) {\n        if (mViewModel == null) return;\n        mViewModel.saveFile(content, uri == null ? null : Paths.get(uri));\n    }\n\n    @NonNull\n    public Language getLanguage(@Nullable String language) {\n        if (language == null || !(mColorScheme instanceof TextMateColorScheme)) {\n            return new EmptyLanguage();\n        }\n        return Languages.getLanguage(requireContext(), language, ((TextMateColorScheme) mColorScheme).getThemeSource());\n    }\n\n    public void showSearchWidget() {\n        if (mSearchWidget != null) {\n            mExitSearchBackPressedCallback.setEnabled(true);\n            Transition sharedAxis = new MaterialSharedAxis(MaterialSharedAxis.Y, true);\n            TransitionManager.beginDelayedTransition(mSearchWidget, sharedAxis);\n            mSearchWidget.setVisibility(View.VISIBLE);\n            mSearchView.requestFocus();\n        }\n    }\n\n    public void hideSearchWidget() {\n        if (mSearchWidget != null) {\n            Transition sharedAxis = new MaterialSharedAxis(MaterialSharedAxis.Y, false);\n            TransitionManager.beginDelayedTransition(mSearchWidget, sharedAxis);\n            mSearchWidget.setVisibility(View.GONE);\n            mEditor.getSearcher().stopSearch();\n            mExitSearchBackPressedCallback.setEnabled(false);\n        }\n    }\n\n    private void search(@Nullable CharSequence s) {\n        if (TextUtils.isEmpty(s)) {\n            mEditor.getSearcher().stopSearch();\n        } else {\n            try {\n                mEditor.getSearcher().search(s.toString(), mSearchOptions);\n            } catch (PatternSyntaxException ignore) {\n            }\n        }\n    }\n\n    private void lockEditor() {\n        if (mViewModel.isReadOnly()) {\n            return;\n        }\n        if (mEditor.isEditable()) {\n            mEditor.setEditable(false);\n            mSymbolInputView.setVisibility(View.GONE);\n            mLockButton.setIconResource(R.drawable.ic_lock);\n        }\n    }\n\n    private void unlockEditor() {\n        if (mViewModel.isReadOnly()) {\n            return;\n        }\n        if (!mEditor.isEditable()) {\n            mEditor.setEditable(true);\n            mSymbolInputView.setVisibility(View.VISIBLE);\n            mLockButton.setIconResource(R.drawable.ic_unlock);\n        }\n    }\n\n    private void launchIntentSaver() {\n        showProgressIndicator(true);\n        lockEditor();\n        mSaveOpenedFile.launch(getSaveIntent());\n    }\n\n    private Intent getSaveIntent() {\n        return new Intent(Intent.ACTION_CREATE_DOCUMENT)\n                .setType(\"*/*\")\n                .putExtra(Intent.EXTRA_TITLE, mViewModel.getFilename());\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/editor/CodeEditorViewModel.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.editor;\n\nimport static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;\nimport static org.xmlpull.v1.XmlPullParser.END_TAG;\nimport static org.xmlpull.v1.XmlPullParser.IGNORABLE_WHITESPACE;\nimport static org.xmlpull.v1.XmlPullParser.START_TAG;\nimport static org.xmlpull.v1.XmlPullParser.TEXT;\n\nimport android.app.Application;\nimport android.net.Uri;\n\nimport androidx.annotation.IntDef;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.lifecycle.AndroidViewModel;\nimport androidx.lifecycle.LiveData;\nimport androidx.lifecycle.MutableLiveData;\n\nimport org.jetbrains.annotations.Contract;\nimport org.xmlpull.v1.XmlPullParserException;\n\nimport java.io.BufferedInputStream;\nimport java.io.ByteArrayInputStream;\nimport java.io.ByteArrayOutputStream;\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.InputStreamReader;\nimport java.io.OutputStream;\nimport java.io.PrintStream;\nimport java.io.Reader;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.nio.ByteBuffer;\nimport java.nio.charset.StandardCharsets;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.Future;\n\nimport io.github.muntashirakon.AppManager.apk.parser.AndroidBinXmlDecoder;\nimport io.github.muntashirakon.AppManager.apk.parser.AndroidBinXmlEncoder;\nimport io.github.muntashirakon.AppManager.dex.DexUtils;\nimport io.github.muntashirakon.AppManager.logs.Log;\nimport io.github.muntashirakon.AppManager.self.filecache.FileCache;\nimport io.github.muntashirakon.AppManager.utils.ExUtils;\nimport io.github.muntashirakon.AppManager.utils.ThreadUtils;\nimport io.github.muntashirakon.compat.xml.TypedXmlPullParser;\nimport io.github.muntashirakon.compat.xml.TypedXmlSerializer;\nimport io.github.muntashirakon.compat.xml.Xml;\nimport io.github.muntashirakon.io.CharSequenceInputStream;\nimport io.github.muntashirakon.io.IoUtils;\nimport io.github.muntashirakon.io.Path;\nimport io.github.muntashirakon.io.Paths;\nimport io.github.muntashirakon.lifecycle.SingleLiveEvent;\nimport io.github.rosemoe.sora.text.Content;\nimport io.github.rosemoe.sora.text.ContentIO;\n\npublic class CodeEditorViewModel extends AndroidViewModel {\n    public static final String TAG = CodeEditorViewModel.class.getSimpleName();\n\n    // TODO: 12/9/22 Another option is to store them as assets/resources\n    private static final Map<String, String> EXT_TO_LANGUAGE_MAP = new HashMap<String, String>() {{\n        // We skip the default ones\n        put(\"cmd\", \"sh\");\n        put(\"htm\", \"xml\");\n        put(\"html\", \"xml\");\n        put(\"kt\", \"kotlin\");\n        put(\"prop\", \"properties\");\n        put(\"tokens\", \"properties\");\n        put(\"xhtml\", \"xml\");\n    }};\n\n    @IntDef({XML_TYPE_NONE, XML_TYPE_AXML, XML_TYPE_ABX})\n    @Retention(RetentionPolicy.SOURCE)\n    private @interface XmlType {\n    }\n\n    public static final int XML_TYPE_NONE = 0;\n    public static final int XML_TYPE_AXML = 1;\n    public static final int XML_TYPE_ABX = 2;\n\n    @Nullable\n    private String mLanguage;\n    private boolean mCanGenerateJava;\n    @XmlType\n    private int mXmlType = XML_TYPE_NONE;\n    @Nullable\n    private Path mSourceFile;\n    private CodeEditorFragment.Options mOptions;\n    @Nullable\n    private Future<?> mContentLoaderResult;\n    @Nullable\n    private Future<?> mJavaConverterResult;\n\n    private final FileCache mFileCache = new FileCache();\n    private final MutableLiveData<Content> mContentLiveData = new MutableLiveData<>();\n    // Only for smali\n    private final SingleLiveEvent<Uri> mJavaFileLiveData = new SingleLiveEvent<>();\n    private final MutableLiveData<Boolean> mSaveFileLiveData = new MutableLiveData<>();\n\n    public CodeEditorViewModel(@NonNull Application application) {\n        super(application);\n    }\n\n    @Override\n    protected void onCleared() {\n        if (mContentLoaderResult != null) {\n            mContentLoaderResult.cancel(true);\n        }\n        if (mJavaConverterResult != null) {\n            mJavaConverterResult.cancel(true);\n        }\n        IoUtils.closeQuietly(mFileCache);\n        super.onCleared();\n    }\n\n    public LiveData<Content> getContentLiveData() {\n        return mContentLiveData;\n    }\n\n    public LiveData<Uri> getJavaFileLiveData() {\n        return mJavaFileLiveData;\n    }\n\n    public LiveData<Boolean> getSaveFileLiveData() {\n        return mSaveFileLiveData;\n    }\n\n    public void setOptions(@NonNull CodeEditorFragment.Options options) {\n        mOptions = options;\n        mSourceFile = options.uri != null ? Paths.get(options.uri) : null;\n        String extension = mSourceFile != null ? mSourceFile.getExtension() : null;\n        mLanguage = getLanguageFromExt(extension);\n        mCanGenerateJava = options.javaSmaliToggle || \"smali\".equals(mLanguage);\n    }\n\n    @Nullable\n    public Path getSourceFile() {\n        return mSourceFile;\n    }\n\n    public void loadFileContentIfAvailable() {\n        if (mSourceFile == null) return;\n        if (mContentLoaderResult != null) {\n            mContentLoaderResult.cancel(true);\n        }\n        mContentLoaderResult = ThreadUtils.postOnBackgroundThread(() -> {\n            Content content = null;\n            if (\"xml\".equals(mLanguage)) {\n                byte[] bytes = mSourceFile.getContentAsBinary();\n                ByteBuffer buffer = ByteBuffer.wrap(bytes);\n                try {\n                    if (AndroidBinXmlDecoder.isBinaryXml(buffer)) {\n                        content = new Content(AndroidBinXmlDecoder.decode(bytes));\n                        mXmlType = XML_TYPE_AXML;\n                    } else if (Xml.isBinaryXml(buffer)) {\n                        // FIXME: 19/5/23 Unfortunately, converting ABX to XML is lossy. Find a way to fix this.\n                        //  Until then, the feature is disabled.\n                        // content = getXmlFromAbx(bytes);\n                        // xmlType = XML_TYPE_ABX;\n                    }\n                } catch (IOException e) {\n                    Log.e(TAG, \"Unable to convert XML bytes to plain text.\", e);\n                }\n            }\n            if (content == null) {\n                try (InputStream is = mSourceFile.openInputStream()) {\n                    content = ContentIO.createFrom(is);\n                    mXmlType = XML_TYPE_NONE;\n                }catch (IOException e) {\n                    Log.e(TAG, \"Could not read file %s\", e, mSourceFile);\n                }\n            }\n            mContentLiveData.postValue(content);\n        });\n    }\n\n    public void saveFile(@NonNull Content content, @Nullable Path alternativeFile) {\n        ThreadUtils.postOnBackgroundThread(() -> {\n            if (mSourceFile == null && alternativeFile == null) {\n                mSaveFileLiveData.postValue(false);\n                return;\n            }\n            // Important: Alternative file gets the top priority\n            Path savingPath = alternativeFile != null ? alternativeFile : mSourceFile;\n            try (OutputStream os = savingPath.openOutputStream()) {\n                switch (mXmlType) {\n                    case XML_TYPE_AXML: {\n                        // TODO: Use serializer from the latest update\n                        byte[] realContent = AndroidBinXmlEncoder.encodeString(content.toString());\n                        os.write(realContent);\n                        break;\n                    }\n                    case XML_TYPE_ABX: {\n                        try (InputStream is = new CharSequenceInputStream(content, StandardCharsets.UTF_8)) {\n                            copyAbxFromXml(is, os);\n                        }\n                        break;\n                    }\n                    default:\n                    case XML_TYPE_NONE:\n                        ContentIO.writeTo(content, os, false);\n                }\n                mSaveFileLiveData.postValue(true);\n            } catch (IOException e) {\n                Log.e(TAG, \"Could not write to file %s\", e, savingPath);\n                mSaveFileLiveData.postValue(false);\n            }\n        });\n    }\n\n    public boolean isReadOnly() {\n        return mOptions == null || mOptions.readOnly;\n    }\n\n    public boolean canWrite() {\n        return !isReadOnly() && mSourceFile != null && mSourceFile.canWrite();\n    }\n\n    public boolean isBackedByAFile() {\n        return mSourceFile != null;\n    }\n\n    @NonNull\n    public String getFilename() {\n        if (mSourceFile == null) {\n            return \"untitled.txt\";\n        }\n        return mSourceFile.getName();\n    }\n\n    public boolean canGenerateJava() {\n        return mCanGenerateJava;\n    }\n\n    @Nullable\n    public String getLanguage() {\n        return mLanguage;\n    }\n\n    public void generateJava(Content smaliContent) {\n        if (!mCanGenerateJava) {\n            return;\n        }\n        if (mJavaConverterResult != null) {\n            mJavaConverterResult.cancel(true);\n        }\n        mJavaConverterResult = ThreadUtils.postOnBackgroundThread(() -> {\n            List<String> smaliContents;\n            if (mSourceFile != null) {\n                Path parent = mSourceFile.getParent();\n                String baseName = DexUtils.getClassNameWithoutInnerClasses(Paths.trimPathExtension(mSourceFile.getName()));\n                String baseSmali = baseName + \".smali\";\n                String baseStartWith = baseName + \"$\";\n                Path[] paths = parent != null ? parent.listFiles((dir, name) -> name.equals(baseSmali) || name.startsWith(baseStartWith))\n                        : new Path[0];\n                smaliContents = new ArrayList<>(paths.length + 1);\n                smaliContents.add(smaliContent.toString());\n                for (Path path : paths) {\n                    if (path.equals(mSourceFile)) {\n                        // We already have this file\n                        continue;\n                    }\n                    String content = path.getContentAsString(null);\n                    if (content != null) {\n                        smaliContents.add(content);\n                    } else {\n                        mJavaFileLiveData.postValue(null);\n                        return;\n                    }\n                }\n            } else {\n                smaliContents = Collections.singletonList(smaliContent.toString());\n            }\n            if (ThreadUtils.isInterrupted()) {\n                return;\n            }\n            try {\n                File cachedFile = mFileCache.createCachedFile(\"java\");\n                try (PrintStream ps = new PrintStream(cachedFile)) {\n                    ps.print(DexUtils.toJavaCode(smaliContents, -1));\n                }\n                mJavaFileLiveData.postValue(Uri.fromFile(cachedFile));\n            } catch (Throwable e) {\n                e.printStackTrace();\n                mJavaFileLiveData.postValue(null);\n            }\n        });\n    }\n\n    @Contract(\"!null -> !null\")\n    @Nullable\n    private static String getLanguageFromExt(@Nullable String ext) {\n        String lang = EXT_TO_LANGUAGE_MAP.get(ext);\n        if (lang != null) return lang;\n        return ext;\n    }\n\n    private static String getXmlFromAbx(@NonNull byte[] data) throws IOException {\n        try (InputStream is = new BufferedInputStream(new ByteArrayInputStream(data));\n             ByteArrayOutputStream os = new ByteArrayOutputStream()) {\n            TypedXmlPullParser parser = Xml.newBinaryPullParser();\n            parser.setInput(is, StandardCharsets.UTF_8.name());\n            TypedXmlSerializer serializer = Xml.newFastSerializer();\n            serializer.setOutput(os, StandardCharsets.UTF_8.name());\n            copyXml(parser, serializer);\n            return os.toString();\n        } catch (XmlPullParserException e) {\n            return ExUtils.rethrowAsIOException(e);\n        }\n    }\n\n    private static void copyAbxFromXml(@NonNull InputStream in, @NonNull OutputStream out) throws IOException {\n        try (Reader is = new InputStreamReader(in)) {\n            TypedXmlPullParser parser = Xml.newFastPullParser();\n            parser.setInput(is);\n            TypedXmlSerializer serializer = Xml.newBinarySerializer();\n            serializer.setOutput(out, StandardCharsets.UTF_8.name());\n            copyXml(parser, serializer);\n        } catch (XmlPullParserException e) {\n            ExUtils.rethrowAsIOException(e);\n        }\n    }\n\n    public static void copyXml(@NonNull TypedXmlPullParser parser, @NonNull TypedXmlSerializer serializer)\n            throws IOException, XmlPullParserException {\n        serializer.startDocument(null, null);\n        int event;\n        do {\n            event = parser.nextToken();\n            switch (event) {\n                case START_TAG:\n                    serializer.startTag(null, parser.getName());\n                    for (int i = 0; i < parser.getAttributeCount(); i++) {\n                        String attributeName = parser.getAttributeName(i);\n                        serializer.attribute(null, attributeName, parser.getAttributeValue(i));\n                    }\n                    break;\n                case END_TAG:\n                    serializer.endTag(null, parser.getName());\n                    break;\n                case TEXT:\n                    serializer.text(parser.getText());\n                    break;\n                case IGNORABLE_WHITESPACE:\n                    serializer.ignorableWhitespace(parser.getText());\n                    break;\n                case END_DOCUMENT:\n                    serializer.endDocument();\n                    break;\n                default:\n                    throw new UnsupportedOperationException();\n            }\n        } while (event != END_DOCUMENT);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/editor/CodeEditorWidget.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.editor;\n\nimport android.content.Context;\nimport android.util.AttributeSet;\nimport android.util.Log;\nimport android.view.inputmethod.BaseInputConnection;\nimport android.widget.Toast;\n\nimport java.lang.reflect.Field;\n\nimport io.github.muntashirakon.AppManager.utils.ClipboardUtils;\nimport io.github.muntashirakon.AppManager.utils.Utils;\nimport io.github.rosemoe.sora.text.Cursor;\nimport io.github.rosemoe.sora.text.TextRange;\nimport io.github.rosemoe.sora.widget.CodeEditor;\nimport io.github.rosemoe.sora.widget.DirectAccessProps;\n\npublic class CodeEditorWidget extends CodeEditor {\n    public static final String TAG = CodeEditorWidget.class.getSimpleName();\n\n    public CodeEditorWidget(Context context) {\n        super(context);\n    }\n\n    public CodeEditorWidget(Context context, AttributeSet attrs) {\n        super(context, attrs);\n    }\n\n    public CodeEditorWidget(Context context, AttributeSet attrs, int defStyleAttr) {\n        super(context, attrs, defStyleAttr);\n    }\n\n    public CodeEditorWidget(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {\n        super(context, attrs, defStyleAttr, defStyleRes);\n    }\n\n    public void pasteText() {\n        try {\n            CharSequence data = ClipboardUtils.readClipboard(getContext());\n            BaseInputConnection inputConnection = getInputConnection();\n            TextRange lastInsertion = getLastInsertion();\n            if (data != null && inputConnection != null) {\n                String text = data.toString();\n                inputConnection.commitText(text, 1);\n                if (getProps().formatPastedText) {\n                    formatCodeAsync(lastInsertion.getStart(), lastInsertion.getEnd());\n                }\n                notifyIMEExternalCursorChange();\n            }\n        } catch (Exception e) {\n            Log.w(TAG, e);\n            Toast.makeText(getContext(), e.toString(), Toast.LENGTH_SHORT).show();\n        }\n    }\n\n    public void copyText() {\n        copyText(true);\n    }\n\n    public void copyText(boolean shouldCopyLine) {\n        Cursor cursor = getCursor();\n        if (cursor.isSelected()) {\n            String clip = getText().substring(cursor.getLeft(), cursor.getRight());\n            Utils.copyToClipboard(getContext(), \"text\", clip);\n        } else if (shouldCopyLine) {\n            copyLine();\n        }\n    }\n\n    private void copyLine() {\n        final Cursor cursor = getCursor();\n        if (cursor.isSelected()) {\n            copyText();\n            return;\n        }\n        final int line = cursor.left().line;\n        setSelectionRegion(line, 0, line, getText().getColumnCount(line));\n        copyText(false);\n    }\n\n    public BaseInputConnection getInputConnection() {\n        try {\n            // Get the Class object of the superclass\n            Class<?> superClass = this.getClass().getSuperclass();\n\n            // Get the private field from the superclass\n            Field field = superClass.getDeclaredField(\"inputConnection\");\n\n            // Make the field accessible\n            field.setAccessible(true);\n\n            // Read the value of the private field for this object\n            return (BaseInputConnection) field.get(this);\n        } catch (Exception e) {\n            e.printStackTrace();\n            return null;\n        }\n    }\n\n    public TextRange getLastInsertion() {\n        try {\n            // Get the Class object of the superclass\n            Class<?> superClass = this.getClass().getSuperclass();\n\n            // Get the private field from the superclass\n            Field field = superClass.getDeclaredField(\"lastInsertion\");\n\n            // Make the field accessible\n            field.setAccessible(true);\n\n            // Read the value of the private field for this object\n            return (TextRange) field.get(this);\n        } catch (Exception e) {\n            e.printStackTrace();\n            return null;\n        }\n    }\n\n    public DirectAccessProps getProps() {\n        try {\n            // Get the Class object of the superclass\n            Class<?> superClass = this.getClass().getSuperclass();\n\n            // Get the private field from the superclass\n            Field field = superClass.getDeclaredField(\"props\");\n\n            // Make the field accessible\n            field.setAccessible(true);\n\n            // Read the value of the private field for this object\n            return (DirectAccessProps) field.get(this);\n        } catch (Exception e) {\n            e.printStackTrace();\n            return null;\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/editor/EditorThemes.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.editor;\n\nimport android.content.Context;\nimport android.graphics.Color;\n\nimport androidx.annotation.NonNull;\nimport androidx.core.graphics.ColorUtils;\n\nimport com.google.android.material.color.MaterialColors;\nimport com.google.android.material.elevation.SurfaceColors;\n\nimport org.eclipse.tm4e.core.registry.IThemeSource;\n\nimport io.github.muntashirakon.AppManager.logs.Log;\nimport io.github.muntashirakon.util.UiUtils;\nimport io.github.rosemoe.sora.lang.styling.color.EditorColor;\nimport io.github.rosemoe.sora.langs.textmate.TextMateColorScheme;\nimport io.github.rosemoe.sora.langs.textmate.registry.ThemeRegistry;\nimport io.github.rosemoe.sora.langs.textmate.registry.model.ThemeModel;\nimport io.github.rosemoe.sora.widget.CodeEditor;\nimport io.github.rosemoe.sora.widget.schemes.EditorColorScheme;\n\npublic final class EditorThemes {\n    public static final String TAG = EditorThemes.class.getSimpleName();\n\n    @NonNull\n    public static EditorColorScheme getColorScheme(@NonNull Context context) {\n        return UiUtils.isDarkMode(context) ? getDarkScheme(context) : getLightScheme(context);\n    }\n\n    @NonNull\n    private static EditorColorScheme getLightScheme(@NonNull Context context) {\n        EditorColorScheme scheme;\n        try {\n            scheme = new TextMateColorSchemeFixed(IThemeSource.fromInputStream(\n                    context.getAssets().open(\"editor_themes/light.tmTheme\"),\n                    \"light.tmTheme\",\n                    null)\n            );\n        } catch (Exception e) {\n            Log.e(TAG, \"Could not create light scheme for TM language\", e);\n            scheme = new LightScheme();\n            fixColor(context, scheme);\n        }\n        return scheme;\n    }\n\n    @NonNull\n    private static EditorColorScheme getDarkScheme(@NonNull Context context) {\n        EditorColorScheme scheme;\n        try {\n            scheme = new TextMateColorSchemeFixed(\n                    IThemeSource.fromInputStream(context.getAssets().open(\"editor_themes/dark.tmTheme.json\"),\n                            \"dark.tmTheme.json\",\n                            null)\n            );\n        } catch (Exception e) {\n            Log.e(TAG, \"Could not create dark scheme for TM language\", e);\n            scheme = new DarkScheme();\n            fixColor(context, scheme);\n        }\n        return scheme;\n    }\n\n    private static void fixColor(@NonNull Context context, @NonNull EditorColorScheme scheme) {\n        scheme.setColor(EditorColorScheme.WHOLE_BACKGROUND, SurfaceColors.SURFACE_0.getColor(context));\n        scheme.setColor(EditorColorScheme.LINE_NUMBER_BACKGROUND, SurfaceColors.SURFACE_2.getColor(context));\n        scheme.setColor(EditorColorScheme.COMPLETION_WND_BACKGROUND, SurfaceColors.SURFACE_1.getColor(context));\n        scheme.setColor(EditorColorScheme.HIGHLIGHTED_DELIMITERS_FOREGROUND, Color.RED);\n        int thumbColor = MaterialColors.getColor(context, androidx.appcompat.R.attr.colorControlActivated, EditorColor.class.getSimpleName());\n        scheme.setColor(EditorColorScheme.SCROLL_BAR_THUMB, thumbColor);\n        scheme.setColor(EditorColorScheme.SCROLL_BAR_THUMB_PRESSED, thumbColor);\n        int trackColor = ColorUtils.setAlphaComponent(MaterialColors.getColor(context, androidx.appcompat.R.attr.colorControlNormal, EditorColor.class.getSimpleName()), 0x39);\n        scheme.setColor(EditorColorScheme.SCROLL_BAR_TRACK, trackColor);\n    }\n\n    private static class TextMateColorSchemeFixed extends TextMateColorScheme {\n        public TextMateColorSchemeFixed(IThemeSource themeSource) throws Exception {\n            super(ThemeRegistry.getInstance(), new ThemeModel(themeSource));\n        }\n\n        @Override\n        public void attachEditor(CodeEditor editor) {\n            super.attachEditor(editor);\n            fixColor(editor.getContext(), this);\n        }\n    }\n\n    // Copyright 2022 Raival\n    private static class LightScheme extends EditorColorScheme {\n        @Override\n        public void applyDefault() {\n            super.applyDefault();\n            setColor(ANNOTATION, -0x9b9b9c);\n            setColor(FUNCTION_NAME, -0x1000000);\n            setColor(IDENTIFIER_NAME, -0x1000000);\n            setColor(IDENTIFIER_VAR, -0x479cc2);\n            setColor(LITERAL, -0xd5ff01);\n            setColor(OPERATOR, -0xc60000);\n            setColor(COMMENT, -0xc080a1);\n            setColor(KEYWORD, -0x80ff8c);\n            setColor(WHOLE_BACKGROUND, -0x1);\n            setColor(TEXT_NORMAL, -0x1000000);\n            setColor(LINE_NUMBER_BACKGROUND, -0x1);\n            setColor(LINE_NUMBER, -0x878788);\n            setColor(SELECTED_TEXT_BACKGROUND, -0xcc6601);\n            setColor(MATCHED_TEXT_BACKGROUND, -0x2b2b2c);\n            setColor(CURRENT_LINE, -0x170d02);\n            setColor(SELECTION_INSERT, -0xfc1415);\n            setColor(SELECTION_HANDLE, -0xfc1415);\n            setColor(BLOCK_LINE, -0x272728);\n            setColor(BLOCK_LINE_CURRENT, 0);\n            setColor(TEXT_SELECTED, -0x1);\n        }\n    }\n\n    // Copyright 2022 Raival\n    private static class DarkScheme extends EditorColorScheme {\n        @Override\n        public void applyDefault() {\n            super.applyDefault();\n            setColor(ANNOTATION, -0x444ad7);\n            setColor(FUNCTION_NAME, -0x332f27);\n            setColor(IDENTIFIER_NAME, -0x332f27);\n            setColor(IDENTIFIER_VAR, -0x678956);\n            setColor(LITERAL, -0x9578a7);\n            setColor(OPERATOR, -0x332f27);\n            setColor(COMMENT, -0x7f7f80);\n            setColor(KEYWORD, -0x3387ce);\n            setColor(WHOLE_BACKGROUND, -0xd4d4d5);\n            setColor(TEXT_NORMAL, -0x332f27);\n            setColor(LINE_NUMBER_BACKGROUND, -0xcecccb);\n            setColor(LINE_NUMBER, -0x9f9c9a);\n            setColor(LINE_DIVIDER, -0x9f9c9a);\n            setColor(SCROLL_BAR_THUMB, -0x59595a);\n            setColor(SCROLL_BAR_THUMB_PRESSED, -0xa9a9aa);\n            setColor(SELECTED_TEXT_BACKGROUND, -0xc98948);\n            setColor(MATCHED_TEXT_BACKGROUND, -0xcda6c3);\n            setColor(CURRENT_LINE, -0xcdcdce);\n            setColor(SELECTION_INSERT, -0x332f27);\n            setColor(SELECTION_HANDLE, -0x332f27);\n            setColor(BLOCK_LINE, -0xa8a8a9);\n            setColor(BLOCK_LINE_CURRENT, -0x22a8a8a9);\n            setColor(NON_PRINTABLE_CHAR, -0x222223);\n            setColor(TEXT_SELECTED, -0x332f27);\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/editor/Languages.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.editor;\n\nimport android.content.Context;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport org.eclipse.tm4e.core.registry.IGrammarSource;\nimport org.eclipse.tm4e.core.registry.IThemeSource;\n\nimport java.io.FileNotFoundException;\nimport java.io.IOException;\nimport java.io.InputStreamReader;\nimport java.io.Reader;\nimport java.nio.charset.StandardCharsets;\n\nimport io.github.muntashirakon.AppManager.logs.Log;\nimport io.github.rosemoe.sora.lang.EmptyLanguage;\nimport io.github.rosemoe.sora.lang.Language;\nimport io.github.rosemoe.sora.langs.textmate.TextMateLanguage;\n\npublic final class Languages {\n    @NonNull\n    public static Language getLanguage(@NonNull Context context, @NonNull String language, @Nullable IThemeSource themeSource) {\n        try {\n            IGrammarSource grammarSource = IGrammarSource.fromInputStream(context.getAssets().open(\"languages/\" + language + \"/tmLanguage.json\"), \"tmLanguage.json\", StandardCharsets.UTF_8);\n            Reader languageConfiguration = new InputStreamReader(context.getAssets().open(\"languages/\" + language + \"/language-configuration.json\"));\n            if (themeSource == null) {\n                throw new FileNotFoundException(\"Invalid theme source\");\n            }\n            return TextMateLanguage.create(grammarSource, languageConfiguration, themeSource);\n        } catch (IOException e) {\n            Log.w(\"CodeEditor\", \"Could not load resources for language %s\", e, language);\n            return new EmptyLanguage();\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/filters/AbsExpressionEvaluator.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.filters;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\npublic abstract class AbsExpressionEvaluator {\n    protected CharSequence lastError;\n\n    @Nullable\n    public CharSequence getLastError() {\n        return lastError;\n    }\n\n    protected abstract boolean evalId(@NonNull String id);\n\n    public boolean evaluate(@NonNull String expr) {\n        lastError = null;\n        // Process parentheses first\n        while (expr.contains(\"(\")) {\n            int start = expr.lastIndexOf('(');\n            int end = expr.indexOf(')', start);\n            if (end == -1) {\n                lastError = \"Expected ')'.\";\n                return false;\n            }\n            // Get expression without parenthesis\n            String subExpr = expr.substring(start + 1, end);\n            boolean subResult = evalOrExpr(subExpr);\n            expr = expr.substring(0, start) + subResult + expr.substring(end + 1);\n        }\n        // Evaluate the final expression without parentheses\n        return evalOrExpr(expr);\n    }\n\n    private boolean evalOrExpr(@NonNull String expr) {\n        String[] orParts = expr.split(\" \\\\| \");\n        for (String part : orParts) {\n            if (evalAndExpr(part)) {\n                // No need to evaluate any further\n                return true;\n            }\n        }\n        // None of the parts returned true\n        return false;\n    }\n\n    private boolean evalAndExpr(@NonNull String expr) {\n        String[] andParts = expr.split(\" & \");\n        for (String andPart : andParts) {\n            andPart = andPart.trim();\n            if (andPart.equals(\"true\")) {\n                continue;\n            }\n            if (andPart.equals(\"false\") || !evalId(andPart)) {\n                // No need to evaluate any further\n                return false;\n            }\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/filters/EditFilterOptionFragment.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.filters;\n\nimport static io.github.muntashirakon.AppManager.filters.options.FilterOption.TYPE_DURATION_MILLIS;\nimport static io.github.muntashirakon.AppManager.filters.options.FilterOption.TYPE_INT;\nimport static io.github.muntashirakon.AppManager.filters.options.FilterOption.TYPE_INT_FLAGS;\nimport static io.github.muntashirakon.AppManager.filters.options.FilterOption.TYPE_LONG;\nimport static io.github.muntashirakon.AppManager.filters.options.FilterOption.TYPE_NONE;\nimport static io.github.muntashirakon.AppManager.filters.options.FilterOption.TYPE_REGEX;\nimport static io.github.muntashirakon.AppManager.filters.options.FilterOption.TYPE_SIZE_BYTES;\nimport static io.github.muntashirakon.AppManager.filters.options.FilterOption.TYPE_STR_MULTIPLE;\nimport static io.github.muntashirakon.AppManager.filters.options.FilterOption.TYPE_STR_SINGLE;\nimport static io.github.muntashirakon.AppManager.filters.options.FilterOption.TYPE_TIME_MILLIS;\n\nimport android.annotation.SuppressLint;\nimport android.app.Dialog;\nimport android.os.Bundle;\nimport android.text.Editable;\nimport android.text.InputType;\nimport android.text.TextUtils;\nimport android.text.TextWatcher;\nimport android.util.TypedValue;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.ArrayAdapter;\nimport android.widget.CheckedTextView;\n\nimport androidx.annotation.LayoutRes;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.core.os.BundleCompat;\nimport androidx.core.widget.TextViewCompat;\nimport androidx.fragment.app.DialogFragment;\nimport androidx.fragment.app.FragmentActivity;\nimport androidx.recyclerview.widget.LinearLayoutManager;\n\nimport com.google.android.material.color.MaterialColors;\nimport com.google.android.material.datepicker.MaterialDatePicker;\nimport com.google.android.material.dialog.MaterialAlertDialogBuilder;\nimport com.google.android.material.resources.MaterialAttributes;\nimport com.google.android.material.textfield.TextInputEditText;\nimport com.google.android.material.textfield.TextInputLayout;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.regex.Pattern;\nimport java.util.regex.PatternSyntaxException;\n\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.filters.options.FilterOption;\nimport io.github.muntashirakon.AppManager.filters.options.FilterOptions;\nimport io.github.muntashirakon.AppManager.utils.ContextUtils;\nimport io.github.muntashirakon.AppManager.utils.DateUtils;\nimport io.github.muntashirakon.AppManager.utils.UIUtils;\nimport io.github.muntashirakon.adapters.SelectedArrayAdapter;\nimport io.github.muntashirakon.util.AdapterUtils;\nimport io.github.muntashirakon.view.TextInputLayoutCompat;\nimport io.github.muntashirakon.widget.MaterialSpinner;\nimport io.github.muntashirakon.widget.RecyclerView;\nimport mobi.upod.timedurationpicker.TimeDurationPickerDialog;\n\npublic class EditFilterOptionFragment extends DialogFragment {\n    public static final String TAG = EditFilterOptionFragment.class.getSimpleName();\n    public static final String ARG_OPTION = \"opt\";\n    public static final String ARG_POSITION = \"pos\";\n\n    public interface OnClickDialogButtonInterface {\n        void onDeleteItem(int position, int id);\n\n        void onUpdateItem(int position, @NonNull FilterOption item);\n\n        void onAddItem(@NonNull FilterOption item);\n    }\n\n    private MaterialSpinner mKeySpinner;\n    private TextInputLayout mGenericTextInputLayout;\n    private TextInputEditText mGenericEditText;\n    private TextInputLayout mDateTextInputLayout;\n    private TextInputEditText mDateEditText;\n    private RecyclerView mFlagsRecyclerView;\n    @Nullable\n    private FilterOption mFilterOption;\n    @Nullable\n    private FilterOption mCurrentFilterOption;\n    @Nullable\n    private String mCurrentKey;\n    @FilterOption.KeyType\n    private int mCurrentKeyType;\n    @Nullable\n    private ArrayAdapter<String> mKeyAdapter;\n    private FilterOptionFlagsAdapter mFilterOptionFlagsAdapter;\n    private OnClickDialogButtonInterface mOnClickDialogButtonInterface;\n    private int mPosition;\n    private long mDate;\n    private final TextWatcher mGenericEditTextWatcher = new TextWatcher() {\n        @Override\n        public void beforeTextChanged(CharSequence s, int start, int count, int after) {\n\n        }\n\n        @Override\n        public void onTextChanged(CharSequence s, int start, int before, int count) {\n\n        }\n\n        @Override\n        public void afterTextChanged(Editable s) {\n            if (mCurrentKeyType != TYPE_NONE && TextUtils.isEmpty(s)) {\n                mGenericTextInputLayout.setErrorEnabled(true);\n                mGenericTextInputLayout.setError(getString(R.string.value_cannot_be_empty));\n                return;\n            }\n            if (mCurrentKeyType == TYPE_REGEX) {\n                try {\n                    Pattern.compile(s.toString());\n                } catch (PatternSyntaxException e) {\n                    mGenericTextInputLayout.setErrorEnabled(true);\n                    mGenericTextInputLayout.setError(getString(R.string.invalid_regex));\n                    return;\n                }\n            } else if (mCurrentKeyType == TYPE_DURATION_MILLIS) {\n                try {\n                    mDate = Long.parseLong(s.toString());\n                    mDateEditText.setText(DateUtils.getFormattedDuration(ContextUtils.getContext(), mDate));\n                } catch (NumberFormatException ignore) {\n                }\n            } else if (mCurrentKeyType == TYPE_TIME_MILLIS) {\n                try {\n                    mDate = Long.parseLong(s.toString());\n                    mDateEditText.setText(DateUtils.formatDate(ContextUtils.getContext(), mDate));\n                } catch (NumberFormatException ignore) {\n                }\n            } else if (mCurrentKeyType == TYPE_INT_FLAGS) {\n                try {\n                    mFilterOptionFlagsAdapter.setFlag(Integer.parseInt(s.toString()));\n                } catch (NumberFormatException ignore) {\n                }\n            }\n            mGenericTextInputLayout.setErrorEnabled(false);\n        }\n    };\n\n    public void setOnClickDialogButtonInterface(OnClickDialogButtonInterface onClickDialogButtonInterface) {\n        mOnClickDialogButtonInterface = onClickDialogButtonInterface;\n    }\n\n    @NonNull\n    @Override\n    public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {\n        FragmentActivity activity = requireActivity();\n        Bundle args = requireArguments();\n        mFilterOption = BundleCompat.getParcelable(args, ARG_OPTION, FilterOption.class);\n        mPosition = args.getInt(ARG_POSITION, -1);\n        boolean editMode = mFilterOption != null;\n        View view = View.inflate(activity, R.layout.dialog_edit_filter_option, null);\n        MaterialSpinner filterSpinner = view.findViewById(R.id.filter_selector_spinner);\n        ArrayAdapter<CharSequence> filters = SelectedArrayAdapter.createFromResource(activity, R.array.finder_filters, io.github.muntashirakon.ui.R.layout.auto_complete_dropdown_item);\n        filterSpinner.setAdapter(filters);\n        mKeySpinner = view.findViewById(R.id.type_selector_spinner);\n        mKeyAdapter = new SelectedArrayAdapter<>(requireActivity(), io.github.muntashirakon.ui.R.layout.auto_complete_dropdown_item);\n        mKeySpinner.setAdapter(mKeyAdapter);\n        mGenericEditText = view.findViewById(R.id.input_string);\n        mGenericEditText.addTextChangedListener(mGenericEditTextWatcher);\n        mGenericTextInputLayout = TextInputLayoutCompat.fromTextInputEditText(mGenericEditText);\n        mDateEditText = view.findViewById(android.R.id.input);\n        mDateEditText.setKeyListener(null);\n        mDateTextInputLayout = TextInputLayoutCompat.fromTextInputEditText(mDateEditText);\n        mFlagsRecyclerView = view.findViewById(R.id.recycler_view);\n        mFlagsRecyclerView.setLayoutManager(new LinearLayoutManager(requireContext()));\n        @SuppressLint({\"RestrictedApi\", \"PrivateResource\"})\n        int layoutId = MaterialAttributes.resolveInteger(requireContext(), androidx.appcompat.R.attr.multiChoiceItemLayout,\n                com.google.android.material.R.layout.mtrl_alert_select_dialog_multichoice);\n        mFilterOptionFlagsAdapter = new FilterOptionFlagsAdapter(layoutId, v ->\n                mGenericEditText.setText(String.valueOf(mFilterOptionFlagsAdapter.getFlag())));\n        mFlagsRecyclerView.setAdapter(mFilterOptionFlagsAdapter);\n        if (mFilterOption != null) {\n            mCurrentFilterOption = mFilterOption;\n            filterSpinner.setSelection(filters.getPosition(mCurrentFilterOption.type));\n            updateUiForFilter(mCurrentFilterOption);\n        } else {\n            filterSpinner.setSelection(-1);\n        }\n        // Setup listeners\n        filterSpinner.setOnItemClickListener((parent, v, position, id) -> {\n            mCurrentFilterOption = FilterOptions.create(filters.getItem(position).toString());\n            updateUiForFilter(mCurrentFilterOption);\n        });\n        mKeySpinner.setOnItemClickListener((parent, view1, position, id) -> {\n            if (mKeyAdapter == null || mCurrentFilterOption == null) {\n                return;\n            }\n            mCurrentKey = mKeyAdapter.getItem(position);\n            int lastKeyType = mCurrentKeyType;\n            mCurrentKeyType = Objects.requireNonNull(mCurrentFilterOption.getKeysWithType().get(mCurrentKey));\n            // Reset value if the data is not of the same type\n            if (lastKeyType != mCurrentKeyType) {\n                mGenericEditText.setText(\"\");\n            }\n            updateUiForType(mCurrentKeyType);\n        });\n        Objects.requireNonNull(mOnClickDialogButtonInterface);\n        MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(activity);\n        builder.setView(view)\n                .setPositiveButton(editMode ? R.string.update : R.string.add, (dialog, which) -> {\n                    if (mCurrentFilterOption == null) {\n                        UIUtils.displayLongToast(R.string.key_name_cannot_be_null);\n                        return;\n                    }\n                    Editable editable = mGenericEditText.getText();\n                    try {\n                        Objects.requireNonNull(mCurrentKey);\n                        mCurrentFilterOption.setKeyValue(mCurrentKey, TextUtils.isEmpty(editable) ? null : editable.toString());\n                    } catch (Exception e) {\n                        e.printStackTrace();\n                        UIUtils.displayLongToast(R.string.error_evaluating_input);\n                        return;\n                    }\n                    if (editMode) {\n                        mOnClickDialogButtonInterface.onUpdateItem(mPosition, mCurrentFilterOption);\n                    } else {\n                        mOnClickDialogButtonInterface.onAddItem(mCurrentFilterOption);\n                    }\n                })\n                .setNegativeButton(R.string.cancel, (dialog, which) -> {\n                    if (getDialog() != null) getDialog().cancel();\n                });\n        if (editMode) {\n            builder.setNeutralButton(R.string.delete, (dialog, which) -> mOnClickDialogButtonInterface.onDeleteItem(mPosition, mFilterOption.id));\n        }\n        return builder.create();\n    }\n\n    private void updateUiForFilter(@NonNull FilterOption filterOption) {\n        if (mKeyAdapter == null) {\n            return;\n        }\n        // List all keys\n        mKeyAdapter.clear();\n        mKeyAdapter.addAll(filterOption.getKeysWithType().keySet());\n        // Set default or previously set key as the current key\n        mCurrentKey = filterOption.getKey();\n        mCurrentKeyType = filterOption.getKeyType();\n        mKeySpinner.setSelection(mKeyAdapter.getPosition(mCurrentKey));\n        // Update the text field\n        mGenericEditText.setText(filterOption.getValue());\n        updateUiForType(mCurrentKeyType);\n    }\n\n    private void updateUiForType(@FilterOption.KeyType int type) {\n        // Update visibility\n        if (type == TYPE_NONE || type == TYPE_INT_FLAGS) {\n            mGenericTextInputLayout.setVisibility(View.GONE);\n            mDateTextInputLayout.setVisibility(View.GONE);\n        } else if (type == TYPE_DURATION_MILLIS || type == TYPE_TIME_MILLIS) {\n            mGenericTextInputLayout.setVisibility(View.GONE);\n            mDateTextInputLayout.setVisibility(View.VISIBLE);\n        } else {\n            mGenericTextInputLayout.setVisibility(View.VISIBLE);\n            mDateTextInputLayout.setVisibility(View.GONE);\n        }\n        if (type == TYPE_INT_FLAGS) {\n            mFlagsRecyclerView.setVisibility(View.VISIBLE);\n        } else mFlagsRecyclerView.setVisibility(View.GONE);\n        // Update single-line\n        mGenericEditText.setSingleLine(type != TYPE_STR_MULTIPLE);\n        // Update hint, input-type\n        switch (type) {\n            case TYPE_NONE:\n                break;\n            case TYPE_INT_FLAGS:\n                mGenericEditText.setInputType(InputType.TYPE_CLASS_NUMBER);\n                Objects.requireNonNull(mCurrentFilterOption);\n                mFilterOptionFlagsAdapter.setFlagMap(mCurrentFilterOption.getFlags(Objects.requireNonNull(mCurrentKey)));\n                break;\n            case TYPE_DURATION_MILLIS:\n                mDateTextInputLayout.setHint(R.string.duration);\n                mGenericEditText.setInputType(InputType.TYPE_CLASS_NUMBER);\n                mDateEditText.setOnClickListener(v -> openDurationPicker());\n                break;\n            case TYPE_INT:\n                mGenericTextInputLayout.setHint(R.string.integer_value);\n                mGenericEditText.setInputType(InputType.TYPE_CLASS_NUMBER);\n                break;\n            case TYPE_LONG:\n                mGenericTextInputLayout.setHint(R.string.long_integer_value);\n                mGenericEditText.setInputType(InputType.TYPE_CLASS_NUMBER);\n                break;\n            case TYPE_REGEX:\n                mGenericTextInputLayout.setHint(R.string.search_option_regex);\n                mGenericEditText.setInputType(InputType.TYPE_CLASS_TEXT);\n                break;\n            case TYPE_SIZE_BYTES:\n                mGenericTextInputLayout.setHint(R.string.size_in_bytes);\n                mGenericEditText.setInputType(InputType.TYPE_CLASS_NUMBER);\n                break;\n            case TYPE_STR_MULTIPLE:\n                mGenericTextInputLayout.setHint(R.string.string_value); // newlines\n                mGenericEditText.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_MULTI_LINE);\n                break;\n            case TYPE_STR_SINGLE:\n                mGenericTextInputLayout.setHint(R.string.string_value);\n                mGenericEditText.setInputType(InputType.TYPE_CLASS_TEXT);\n                break;\n            case TYPE_TIME_MILLIS:\n                mDateTextInputLayout.setHint(R.string.date);\n                mGenericEditText.setInputType(InputType.TYPE_CLASS_NUMBER);\n                mDateEditText.setOnClickListener(v -> openDatePicker());\n                break;\n        }\n    }\n\n    public void openDatePicker() {\n        MaterialDatePicker<Long> datePicker = MaterialDatePicker.Builder.datePicker()\n                .setTitleText(R.string.date)\n                .setSelection(mDate <= 0 ? MaterialDatePicker.todayInUtcMilliseconds() : mDate)\n                .build();\n        datePicker.addOnPositiveButtonClickListener(selection -> mGenericEditText.setText(String.valueOf(selection)));\n        datePicker.show(getChildFragmentManager(), \"DatePicker\");\n    }\n\n    public void openDurationPicker() {\n        new TimeDurationPickerDialog(requireContext(), (picker, duration) ->\n                mGenericEditText.setText(String.valueOf(duration)), mDate)\n                .show();\n    }\n\n    private static class FilterOptionFlagsAdapter extends RecyclerView.Adapter<FilterOptionFlagsAdapter.ViewHolder> {\n        @LayoutRes\n        private final int mLayoutId;\n        private final View.OnClickListener mItemClickListener;\n        private final List<Integer> mFlags = Collections.synchronizedList(new ArrayList<>());\n        private Map<Integer, CharSequence> mFlagMap;\n        private int mFlag;\n\n        public FilterOptionFlagsAdapter(@LayoutRes int layoutId, View.OnClickListener itemClickListener) {\n            mLayoutId = layoutId;\n            mFlagMap = Collections.emptyMap();\n            mItemClickListener = itemClickListener;\n        }\n\n        public void setFlagMap(@NonNull Map<Integer, CharSequence> flagMap) {\n            mFlagMap = flagMap;\n            AdapterUtils.notifyDataSetChanged(this, mFlags, new ArrayList<>(flagMap.keySet()));\n        }\n\n        public void setFlag(int flag) {\n            mFlag = flag;\n            notifyItemRangeChanged(0, mFlags.size(), AdapterUtils.STUB);\n        }\n\n        public int getFlag() {\n            return mFlag;\n        }\n\n        @NonNull\n        @Override\n        public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {\n            View v = LayoutInflater.from(parent.getContext()).inflate(mLayoutId, parent, false);\n            return new ViewHolder(v);\n        }\n\n        @Override\n        public void onBindViewHolder(@NonNull ViewHolder holder, int position) {\n            int flag = mFlags.get(position);\n            CharSequence flagName = mFlagMap.get(flag);\n            holder.item.setText(flagName);\n            holder.item.setChecked((mFlag & flag) != 0);\n            holder.item.setOnClickListener(v -> {\n                if ((mFlag & flag) != 0) {\n                    // Already selected, deselect\n                    mFlag &= ~flag;\n                    holder.item.setChecked(false);\n                } else {\n                    // Not yet selected, select\n                    mFlag |= flag;\n                    holder.item.setChecked(true);\n                }\n                mItemClickListener.onClick(v);\n            });\n        }\n\n        @Override\n        public int getItemCount() {\n            return mFlags.size();\n        }\n\n        static class ViewHolder extends RecyclerView.ViewHolder {\n            CheckedTextView item;\n\n            @SuppressLint(\"RestrictedApi\")\n            public ViewHolder(@NonNull View itemView) {\n                super(itemView);\n                item = itemView.findViewById(android.R.id.text1);\n                int textAppearanceBodyLarge = MaterialAttributes.resolveInteger(item.getContext(), com.google.android.material.R.attr.textAppearanceBodyLarge, 0);\n                TextViewCompat.setTextAppearance(item, textAppearanceBodyLarge);\n                item.setTextSize(TypedValue.COMPLEX_UNIT_SP, 16);\n                item.setTextColor(MaterialColors.getColor(item.getContext(), com.google.android.material.R.attr.colorOnSurfaceVariant, -1));\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/filters/EditFiltersDialogFragment.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.filters;\n\nimport android.app.Dialog;\nimport android.graphics.Color;\nimport android.os.Bundle;\nimport android.text.Editable;\nimport android.text.Spanned;\nimport android.text.TextUtils;\nimport android.text.TextWatcher;\nimport android.text.style.ForegroundColorSpan;\nimport android.view.View;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.fragment.app.DialogFragment;\nimport androidx.fragment.app.FragmentActivity;\nimport androidx.recyclerview.widget.LinearLayoutManager;\n\nimport com.google.android.material.dialog.MaterialAlertDialogBuilder;\nimport com.google.android.material.textfield.TextInputEditText;\nimport com.google.android.material.textfield.TextInputLayout;\n\nimport java.util.HashMap;\nimport java.util.Map;\nimport java.util.Objects;\n\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.filters.options.FilterOption;\nimport io.github.muntashirakon.dialog.DialogTitleBuilder;\nimport io.github.muntashirakon.view.TextInputLayoutCompat;\nimport io.github.muntashirakon.widget.RecyclerView;\n\npublic class EditFiltersDialogFragment extends DialogFragment implements EditFilterOptionFragment.OnClickDialogButtonInterface {\n    public static final String TAG = EditFiltersDialogFragment.class.getSimpleName();\n\n    public interface OnSaveDialogButtonInterface {\n        @NonNull\n        FilterItem getFilterItem();\n\n        void onItemAltered(@NonNull FilterItem item);\n    }\n\n    private static final Map<String, Integer> HIGHLIGHT_MAP = new HashMap<String, Integer>() {{\n        put(\"&\", Color.RED);\n        put(\"|\", Color.RED);\n        put(\"(\", Color.RED);\n        put(\")\", Color.RED);\n        put(\"true\", Color.BLUE);\n        put(\"false\", Color.BLUE);\n    }};\n\n    private static class ExprTester extends AbsExpressionEvaluator {\n        private final FilterItem mFilterItem;\n\n        public ExprTester(FilterItem filterItem) {\n            mFilterItem = filterItem;\n        }\n\n        @Override\n        protected boolean evalId(@NonNull String id) {\n            if (TextUtils.isEmpty(id)) {\n                return false;\n            }\n            // Extract ID\n            int idx = id.lastIndexOf('_');\n            int intId;\n            if (idx >= 0 && id.length() > (idx + 1)) {\n                String part2 = id.substring(idx + 1);\n                if (TextUtils.isDigitsOnly(part2)) {\n                    intId = Integer.parseInt(part2);\n                } else intId = 0;\n            } else intId = 0;\n            FilterOption option = mFilterItem.getFilterOptionForId(intId);\n            if (option == null) {\n                lastError = \"Invalid ID '\" + id + \"'\";\n            }\n            return option != null;\n        }\n    }\n\n    private FinderFilterAdapter mFinderFilterAdapter;\n    private TextInputLayout mFinderFilterEditorLayout;\n    private TextInputEditText mFinderFilterEditor;\n    private FilterItem mFilterItem;\n    private OnSaveDialogButtonInterface mOnSaveDialogButtonInterface;\n    private boolean mFilterEditorModified = false;\n    private ExprTester mExprTester;\n    private final TextWatcher mFinderFilterEditorWatcher = new TextWatcher() {\n\n        @Override\n        public void beforeTextChanged(CharSequence s, int start, int count, int after) {\n        }\n\n        @Override\n        public void onTextChanged(CharSequence s, int start, int before, int count) {\n        }\n\n        @Override\n        public void afterTextChanged(Editable s) {\n            updateEditorColors(s);\n            mFilterEditorModified = true;\n        }\n    };\n\n    public void setOnSaveDialogButtonInterface(OnSaveDialogButtonInterface onSaveDialogButtonInterface) {\n        mOnSaveDialogButtonInterface = onSaveDialogButtonInterface;\n    }\n\n    @NonNull\n    @Override\n    public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {\n        FragmentActivity activity = requireActivity();\n        mFilterItem = Objects.requireNonNull(mOnSaveDialogButtonInterface).getFilterItem();\n        mFinderFilterAdapter = new FinderFilterAdapter(mFilterItem);\n        View view = View.inflate(activity, R.layout.dialog_edit_filter_item, null);\n        RecyclerView recyclerView = view.findViewById(android.R.id.list);\n        recyclerView.setLayoutManager(new LinearLayoutManager(activity));\n        recyclerView.setAdapter(mFinderFilterAdapter);\n        mFinderFilterEditor = view.findViewById(R.id.editor);\n        mFinderFilterEditor.setText(mFilterItem.getExpr());\n        mFinderFilterEditor.addTextChangedListener(mFinderFilterEditorWatcher);\n        mFinderFilterEditorLayout = TextInputLayoutCompat.fromTextInputEditText(mFinderFilterEditor);\n        DialogTitleBuilder builder = new DialogTitleBuilder(activity)\n                .setTitle(R.string.filters)\n                .setEndIcon(R.drawable.ic_add, v -> {\n                    EditFilterOptionFragment dialogFragment = new EditFilterOptionFragment();\n                    Bundle args = new Bundle();\n                    dialogFragment.setArguments(args);\n                    dialogFragment.setOnClickDialogButtonInterface(this);\n                    dialogFragment.show(getChildFragmentManager(), EditFilterOptionFragment.TAG);\n                })\n                .setEndIconContentDescription(R.string.add_filter_ellipsis);\n        mFinderFilterAdapter.setOnItemClickListener(new FinderFilterAdapter.OnClickListener() {\n            @Override\n            public void onEdit(View view, int position, FilterOption filterOption) {\n                displayEditor(position, filterOption);\n            }\n\n            @Override\n            public void onRemove(View view, int position, FilterOption filterOption) {\n                onDeleteItem(position, filterOption.id);\n            }\n        });\n        return new MaterialAlertDialogBuilder(activity)\n                .setCustomTitle(builder.build())\n                .setView(view)\n                .setNegativeButton(R.string.cancel, null)\n                .setPositiveButton(R.string.apply, (dialog, which) -> {\n                    if (mFilterEditorModified && mFinderFilterEditorLayout.getError() == null) {\n                        mFilterItem.setExpr(mFinderFilterEditor.getText().toString());\n                    }\n                    mOnSaveDialogButtonInterface.onItemAltered(mFilterItem);\n                })\n                .show();\n    }\n\n    private void displayEditor(int position, @NonNull FilterOption filterOption) {\n        EditFilterOptionFragment dialogFragment = new EditFilterOptionFragment();\n        Bundle args = new Bundle();\n        args.putParcelable(EditFilterOptionFragment.ARG_OPTION, filterOption);\n        args.putInt(EditFilterOptionFragment.ARG_POSITION, position);\n        dialogFragment.setArguments(args);\n        dialogFragment.setOnClickDialogButtonInterface(this);\n        dialogFragment.show(getChildFragmentManager(), EditFilterOptionFragment.TAG);\n    }\n\n    @Override\n    public void onAddItem(@NonNull FilterOption item) {\n        mFinderFilterAdapter.add(item);\n        mFinderFilterEditor.removeTextChangedListener(mFinderFilterEditorWatcher);\n        mFinderFilterEditor.setText(mFilterItem.getExpr());\n        updateEditorColors(mFinderFilterEditor.getText());\n        mFinderFilterEditor.addTextChangedListener(mFinderFilterEditorWatcher);\n    }\n\n    @Override\n    public void onUpdateItem(int position, @NonNull FilterOption item) {\n        mFinderFilterAdapter.update(position, item);\n        mFinderFilterEditor.removeTextChangedListener(mFinderFilterEditorWatcher);\n        mFinderFilterEditor.setText(mFilterItem.getExpr());\n        updateEditorColors(mFinderFilterEditor.getText());\n        mFinderFilterEditor.addTextChangedListener(mFinderFilterEditorWatcher);\n    }\n\n    @Override\n    public void onDeleteItem(int position, int id) {\n        mFinderFilterAdapter.remove(position, id);\n        mFinderFilterEditor.removeTextChangedListener(mFinderFilterEditorWatcher);\n        mFinderFilterEditor.setText(mFilterItem.getExpr());\n        updateEditorColors(mFinderFilterEditor.getText());\n        mFinderFilterEditor.addTextChangedListener(mFinderFilterEditorWatcher);\n    }\n\n    private void updateEditorColors(@Nullable Editable s) {\n        if (mExprTester == null) {\n            mExprTester = new ExprTester(mFilterItem);\n        }\n        if (s == null) {\n            return;\n        }\n        String text = s.toString();\n        for (Map.Entry<String, Integer> entry : HIGHLIGHT_MAP.entrySet()) {\n            String keyword = entry.getKey();\n            int color = entry.getValue();\n            int index = text.indexOf(keyword);\n            while (index >= 0) {\n                s.setSpan(new ForegroundColorSpan(color), index, index + keyword.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);\n                index = text.indexOf(keyword, index + keyword.length());\n            }\n        }\n        if (!mExprTester.evaluate(s.toString())) {\n            CharSequence error = mExprTester.getLastError();\n            mFinderFilterEditorLayout.setError(error);\n        } else {\n            mFinderFilterEditorLayout.setError(null);\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/filters/FilterItem.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.filters;\n\nimport android.os.Parcel;\nimport android.os.Parcelable;\nimport android.text.TextUtils;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.collection.ArrayMap;\nimport androidx.core.os.ParcelCompat;\n\nimport org.json.JSONArray;\nimport org.json.JSONException;\nimport org.json.JSONObject;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Objects;\n\nimport io.github.muntashirakon.AppManager.filters.options.DataUsageOption;\nimport io.github.muntashirakon.AppManager.filters.options.FilterOption;\nimport io.github.muntashirakon.AppManager.filters.options.RunningAppsOption;\nimport io.github.muntashirakon.AppManager.filters.options.ScreenTimeOption;\nimport io.github.muntashirakon.AppManager.filters.options.TimesOpenedOption;\nimport io.github.muntashirakon.AppManager.history.IJsonSerializer;\nimport io.github.muntashirakon.AppManager.history.JsonDeserializer;\nimport io.github.muntashirakon.util.ParcelUtils;\n\npublic class FilterItem implements IJsonSerializer, Parcelable {\n    private static class ExprEvaluator extends AbsExpressionEvaluator {\n        private final ArrayMap<Integer, FilterOption> mFilterOptions;\n        @Nullable\n        private IFilterableAppInfo mInfo;\n        @Nullable\n        private FilterOption.TestResult mResult;\n\n        public ExprEvaluator(ArrayMap<Integer, FilterOption> filterOptions) {\n            mFilterOptions = filterOptions;\n        }\n\n        public void setInfo(@Nullable IFilterableAppInfo info) {\n            mInfo = info;\n            mResult = new FilterOption.TestResult();\n        }\n\n        @Nullable\n        public FilterOption.TestResult getResult() {\n            return mResult;\n        }\n\n        @Override\n        protected boolean evalId(@NonNull String id) {\n            if (mResult == null) {\n                mResult = new FilterOption.TestResult();\n            }\n            // Extract ID\n            int idx = id.lastIndexOf('_');\n            int intId;\n            if (idx >= 0 && id.length() > (idx + 1)) {\n                intId = Integer.parseInt(id.substring(idx + 1));\n            } else intId = 0;\n            FilterOption option = mFilterOptions.get(intId);\n            if (option == null || mInfo == null) {\n                return false;\n            }\n            return option.test(mInfo, mResult).isMatched();\n        }\n    }\n\n    @NonNull\n    private String mName;\n    private final ArrayMap<Integer, FilterOption> mFilterOptions;\n    private String mExpr = \"\";\n    private boolean mCustomExpr = false;\n    // Assign this id to the next filter option (starts with 1)\n    private int mNextId = 1;\n    // Counters for special cases\n    private int mTimesUsageInfoUsed = 0;\n    private int mTimesRunningOptionUsed = 0;\n\n    public FilterItem() {\n        this(\"Untitled\");\n    }\n\n    private FilterItem(@NonNull String name) {\n        mName = name;\n        mFilterOptions = new ArrayMap<>();\n    }\n\n    @NonNull\n    public String getName() {\n        return mName;\n    }\n\n    public void setName(@NonNull String name) {\n        mName = name;\n    }\n\n    @NonNull\n    public String getExpr() {\n        return mExpr;\n    }\n\n    public void setExpr(@NonNull String expr) {\n        mExpr = expr;\n        mCustomExpr = true;\n    }\n\n    public int addFilterOption(@NonNull FilterOption filterOption) {\n        filterOption.id = getNextId();\n        if (!mCustomExpr) {\n            String id = filterOption.getFullId();\n            // Add this to expr\n            if (TextUtils.isEmpty(mExpr)) {\n                mExpr = id;\n            } else mExpr += \" & \" + id;\n        }\n        incrementUsage(filterOption, true);\n        if (mFilterOptions.put(filterOption.id, filterOption) == null) {\n            return mFilterOptions.indexOfKey(filterOption.id);\n        }\n        return -1;\n    }\n\n    public void updateFilterOptionAt(int i, @NonNull FilterOption filterOption) {\n        FilterOption oldFilterOption = mFilterOptions.valueAt(i);\n        if (oldFilterOption == null) {\n            throw new IllegalArgumentException(\"Invalid index \" + i);\n        }\n        filterOption.id = oldFilterOption.id;\n        mFilterOptions.setValueAt(i, filterOption);\n        if (!mCustomExpr) {\n            String idStr = oldFilterOption.getFullId();\n            // Default expression is just all the filters &'ed together\n            String[] ops = mExpr.split(\" & \");\n            StringBuilder sb = new StringBuilder();\n            for (String op : ops) {\n                if (sb.length() > 0) {\n                    sb.append(\" & \");\n                }\n                if (idStr.equals(op)) {\n                    sb.append(filterOption.getFullId());\n                } else sb.append(op);\n            }\n            mExpr = sb.toString();\n        }\n        incrementUsage(oldFilterOption, false);\n        incrementUsage(filterOption, true);\n    }\n\n    public boolean removeFilterOptionAt(int i) {\n        FilterOption filterOption = mFilterOptions.removeAt(i);\n        if (filterOption == null) {\n            return false;\n        }\n        mNextId = filterOption.id;\n        if (!mCustomExpr) {\n            String idStr = filterOption.getFullId();\n            // Default expression is just all the filters &'ed together\n            String[] ops = mExpr.split(\" & \");\n            StringBuilder sb = new StringBuilder();\n            for (String op : ops) {\n                if (!idStr.equals(op)) {\n                    if (sb.length() > 0) {\n                        sb.append(\" & \");\n                    }\n                    sb.append(op);\n                }\n            }\n            mExpr = sb.toString();\n        }\n        incrementUsage(filterOption, false);\n        return true;\n    }\n\n    public int getSize() {\n        return mFilterOptions.size();\n    }\n\n    public FilterOption getFilterOptionAt(int i) {\n        return mFilterOptions.valueAt(i);\n    }\n\n    @Nullable\n    public FilterOption getFilterOptionForId(int id) {\n        return mFilterOptions.get(id);\n    }\n\n    public int getTimesUsageInfoUsed() {\n        return mTimesUsageInfoUsed;\n    }\n\n    public int getTimesRunningOptionUsed() {\n        return mTimesRunningOptionUsed;\n    }\n\n    public <T extends IFilterableAppInfo> List<FilteredItemInfo<T>> getFilteredList(@NonNull List<T> allFilterableAppInfo) {\n        List<FilteredItemInfo<T>> filteredFilterableAppInfo = new ArrayList<>();\n        ExprEvaluator evaluator = new ExprEvaluator(mFilterOptions);\n        String expr = TextUtils.isEmpty(mExpr) ? \"true\" : mExpr;\n        for (T info : allFilterableAppInfo) {\n            evaluator.setInfo(info);\n            boolean eval = evaluator.evaluate(expr);\n            FilterOption.TestResult result = Objects.requireNonNull(evaluator.getResult());\n            if (eval) {\n                filteredFilterableAppInfo.add(new FilteredItemInfo<>(info, result));\n            }\n        }\n        return filteredFilterableAppInfo;\n    }\n\n    private void incrementUsage(FilterOption filterOption, boolean increment) {\n        boolean requireCountUpdate;\n        if (filterOption instanceof DataUsageOption) {\n            requireCountUpdate = true;\n        } else if (filterOption instanceof TimesOpenedOption) {\n            requireCountUpdate = true;\n        } else if (filterOption instanceof ScreenTimeOption) {\n            requireCountUpdate = true;\n        } else requireCountUpdate = false;\n        if (requireCountUpdate) {\n            if (increment) ++mTimesUsageInfoUsed;\n            else --mTimesUsageInfoUsed;\n            return;\n        }\n        if (filterOption instanceof RunningAppsOption) {\n            if (increment) ++mTimesRunningOptionUsed;\n            else --mTimesRunningOptionUsed;\n        }\n    }\n\n    public FilterItem(@NonNull Parcel in) {\n        mName = Objects.requireNonNull(in.readString());\n        mExpr = Objects.requireNonNull(in.readString());\n        mCustomExpr = ParcelCompat.readBoolean(in);\n        mFilterOptions = ParcelUtils.readArrayMap(in, Integer.class.getClassLoader(), FilterOption.class.getClassLoader());\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        dest.writeString(mName);\n        dest.writeString(mExpr);\n        ParcelCompat.writeBoolean(dest, mCustomExpr);\n        ParcelUtils.writeMap(mFilterOptions, dest);\n    }\n\n    @Override\n    public int describeContents() {\n        return 0;\n    }\n\n    public static final Creator<FilterItem> CREATOR = new Creator<FilterItem>() {\n        @Override\n        @NonNull\n        public FilterItem createFromParcel(@NonNull Parcel in) {\n            return new FilterItem(in);\n        }\n\n        @Override\n        @NonNull\n        public FilterItem[] newArray(int size) {\n            return new FilterItem[size];\n        }\n    };\n\n    @NonNull\n    @Override\n    public JSONObject serializeToJson() throws JSONException {\n        JSONObject object = new JSONObject();\n        JSONArray array = new JSONArray();\n        for (FilterOption filterOption : mFilterOptions.values()) {\n            array.put(filterOption.toJson());\n        }\n        object.put(\"name\", mName);\n        object.put(\"expr\", mExpr);\n        object.put(\"custom_expr\", mCustomExpr);\n        object.put(\"options\", array);\n        return object;\n    }\n\n    public FilterItem(@NonNull JSONObject object) throws JSONException {\n        mName = object.getString(\"name\");\n        mExpr = object.getString(\"expr\");\n        mCustomExpr = object.getBoolean(\"custom_expr\");\n        mFilterOptions = new ArrayMap<>();\n        JSONArray array = object.getJSONArray(\"options\");\n        for (int i = 0; i < array.length(); ++i) {\n            FilterOption option = FilterOption.fromJson(array.getJSONObject(i));\n            mFilterOptions.put(option.id, option);\n        }\n    }\n\n    public static final JsonDeserializer.Creator<FilterItem> DESERIALIZER = FilterItem::new;\n\n    private int getNextId() {\n        // Find next ID\n        while (mFilterOptions.containsKey(mNextId)) {\n            ++mNextId;\n        }\n        return mNextId;\n    }\n\n    public static class FilteredItemInfo<T extends IFilterableAppInfo> {\n        public final T info;\n        public final FilterOption.TestResult result;\n\n        FilteredItemInfo(T info, FilterOption.TestResult result) {\n            this.info = info;\n            this.result = result;\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/filters/FilterableAppInfo.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.filters;\n\nimport android.app.ActivityManager;\nimport android.content.pm.ActivityInfo;\nimport android.content.pm.ApplicationInfo;\nimport android.content.pm.ComponentInfo;\nimport android.content.pm.FeatureInfo;\nimport android.content.pm.PackageInfo;\nimport android.content.pm.PackageManager;\nimport android.content.pm.PermissionInfo;\nimport android.content.pm.ProviderInfo;\nimport android.content.pm.ServiceInfo;\nimport android.graphics.drawable.Drawable;\nimport android.os.Build;\nimport android.os.RemoteException;\nimport android.os.UserHandleHidden;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.RequiresApi;\nimport androidx.core.content.pm.PackageInfoCompat;\n\nimport java.io.IOException;\nimport java.security.cert.CertificateEncodingException;\nimport java.security.cert.X509Certificate;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashSet;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.Set;\n\nimport aosp.libcore.util.EmptyArray;\nimport io.github.muntashirakon.AppManager.StaticDataset;\nimport io.github.muntashirakon.AppManager.apk.signing.SignerInfo;\nimport io.github.muntashirakon.AppManager.backup.BackupUtils;\nimport io.github.muntashirakon.AppManager.compat.ActivityManagerCompat;\nimport io.github.muntashirakon.AppManager.compat.AppOpsManagerCompat;\nimport io.github.muntashirakon.AppManager.compat.ApplicationInfoCompat;\nimport io.github.muntashirakon.AppManager.compat.DeviceIdleManagerCompat;\nimport io.github.muntashirakon.AppManager.compat.InstallSourceInfoCompat;\nimport io.github.muntashirakon.AppManager.compat.ManifestCompat;\nimport io.github.muntashirakon.AppManager.compat.PackageManagerCompat;\nimport io.github.muntashirakon.AppManager.compat.SensorServiceCompat;\nimport io.github.muntashirakon.AppManager.db.entity.Backup;\nimport io.github.muntashirakon.AppManager.debloat.DebloatObject;\nimport io.github.muntashirakon.AppManager.filters.options.ComponentsOption;\nimport io.github.muntashirakon.AppManager.filters.options.FreezeOption;\nimport io.github.muntashirakon.AppManager.rules.compontents.ComponentUtils;\nimport io.github.muntashirakon.AppManager.rules.compontents.ComponentsBlocker;\nimport io.github.muntashirakon.AppManager.self.SelfPermissions;\nimport io.github.muntashirakon.AppManager.ssaid.SsaidSettings;\nimport io.github.muntashirakon.AppManager.types.PackageSizeInfo;\nimport io.github.muntashirakon.AppManager.usage.AppUsageStatsManager;\nimport io.github.muntashirakon.AppManager.usage.PackageUsageInfo;\nimport io.github.muntashirakon.AppManager.utils.ArrayUtils;\nimport io.github.muntashirakon.AppManager.utils.ContextUtils;\nimport io.github.muntashirakon.AppManager.utils.DigestUtils;\nimport io.github.muntashirakon.AppManager.utils.ExUtils;\nimport io.github.muntashirakon.AppManager.utils.KeyStoreUtils;\nimport io.github.muntashirakon.AppManager.utils.PackageUtils;\n\npublic class FilterableAppInfo implements IFilterableAppInfo {\n    private final PackageInfo mPackageInfo;\n    @Nullable\n    private final PackageUsageInfo mPackageUsageInfo;\n    private final ApplicationInfo mApplicationInfo;\n    private final int mUserId;\n    private final PackageManager mPm;\n\n    private String mAppLabel;\n    @Nullable\n    private String mSsaid;\n    private InstallSourceInfoCompat mInstallerInfo;\n    @Nullable\n    private SignerInfo mSignerInfo;\n    private String[] mSignatureSubjectLines;\n    private String[] mSignatureSha256Checksums;\n    private Map<ComponentInfo, Integer> mAllComponents;\n    private Map<ComponentInfo, Integer> mTrackerComponents;\n    private List<String> mUsedPermissions;\n    private Backup[] mBackups;\n    private List<AppOpsManagerCompat.OpEntry> mAppOpEntries;\n    @Nullable\n    private PackageSizeInfo mPackageSizeInfo;\n    @Nullable\n    private AppUsageStatsManager.DataUsage mDataUsage;\n    @Nullable\n    private DebloatObject mBloatwareInfo;\n    private Integer mFreezeFlags = null;\n    private Boolean mUsesSensors = null;\n    private Boolean mBatteryOptEnabled = null;\n    private Boolean mHasKeystoreItems = null;\n    private Integer mRulesCount = null;\n\n    public FilterableAppInfo(@NonNull PackageInfo packageInfo, @Nullable PackageUsageInfo packageUsageInfo) {\n        mPackageInfo = packageInfo;\n        mPackageUsageInfo = packageUsageInfo;\n        mApplicationInfo = Objects.requireNonNull(packageInfo.applicationInfo);\n        mUserId = UserHandleHidden.getUserId(mApplicationInfo.uid);\n        mPm = ContextUtils.getContext().getPackageManager();\n    }\n\n    @NonNull\n    public PackageInfo getPackageInfo() {\n        return mPackageInfo;\n    }\n\n    @NonNull\n    public ApplicationInfo getApplicationInfo() {\n        return mApplicationInfo;\n    }\n\n    @Override\n    @NonNull\n    public String getPackageName() {\n        return mPackageInfo.packageName;\n    }\n\n    @Override\n    public int getUserId() {\n        return mUserId;\n    }\n\n    @Override\n    public int getUid() {\n        return mApplicationInfo.uid;\n    }\n\n    @Override\n    @NonNull\n    public String getAppLabel() {\n        if (mAppLabel == null) {\n            mAppLabel = mApplicationInfo.loadLabel(mPm).toString();\n        }\n        return mAppLabel;\n    }\n\n    @NonNull\n    @Override\n    public Drawable getAppIcon() {\n        return mApplicationInfo.loadIcon(mPm);\n    }\n\n    @Override\n    @Nullable\n    public String getVersionName() {\n        return mPackageInfo.versionName;\n    }\n\n    @Override\n    public long getVersionCode() {\n        return PackageInfoCompat.getLongVersionCode(mPackageInfo);\n    }\n\n    @Override\n    public long getFirstInstallTime() {\n        return mPackageInfo.firstInstallTime;\n    }\n\n    @Override\n    public long getLastUpdateTime() {\n        return mPackageInfo.lastUpdateTime;\n    }\n\n    @Override\n    public int getTargetSdk() {\n        return mApplicationInfo.targetSdkVersion;\n    }\n\n    @Override\n    @RequiresApi(Build.VERSION_CODES.S)\n    public int getCompileSdk() {\n        return mApplicationInfo.compileSdkVersion;\n    }\n\n    @Override\n    @RequiresApi(Build.VERSION_CODES.N)\n    public int getMinSdk() {\n        return mApplicationInfo.minSdkVersion;\n    }\n\n    @Override\n    @NonNull\n    public Backup[] getBackups() {\n        if (mBackups == null) {\n            mBackups = BackupUtils.getBackupMetadataFromDbNoLockValidate(getPackageName()).toArray(new Backup[0]);\n        }\n        return mBackups;\n    }\n\n    @Override\n    public boolean isRunning() {\n        for (ActivityManager.RunningAppProcessInfo info : ActivityManagerCompat.getRunningAppProcesses()) {\n            if (ArrayUtils.contains(info.pkgList, mPackageInfo.packageName)) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    @Override\n    @NonNull\n    public Map<ComponentInfo, Integer> getTrackerComponents() {\n        if (mTrackerComponents == null) {\n            Map<ComponentInfo, Integer> allComponents = getAllComponents();\n            Map<ComponentInfo, Integer> trackerComponents = new LinkedHashMap<>();\n            for (ComponentInfo itemInfo : allComponents.keySet()) {\n                if (ComponentUtils.isTracker(itemInfo.name)) {\n                    trackerComponents.put(itemInfo, allComponents.get(itemInfo));\n                }\n            }\n            mTrackerComponents = trackerComponents;\n        }\n        return mTrackerComponents;\n    }\n\n    @Override\n    @NonNull\n    public List<AppOpsManagerCompat.OpEntry> getAppOps() {\n        if (mAppOpEntries == null && isInstalled()) {\n            List<AppOpsManagerCompat.PackageOps> packageOps = ExUtils.exceptionAsNull(() -> new AppOpsManagerCompat().getOpsForPackage(mApplicationInfo.uid, getPackageName(), null));\n            if (packageOps != null && packageOps.size() == 1) {\n                mAppOpEntries = packageOps.get(0).getOps();\n            }\n        } else mAppOpEntries = Collections.emptyList();\n        return mAppOpEntries;\n    }\n\n    @Override\n    @NonNull\n    public Map<ComponentInfo, Integer> getAllComponents() {\n        if (mAllComponents == null) {\n            Map<ComponentInfo, Integer> components = new LinkedHashMap<>();\n            if (mPackageInfo.activities != null) {\n                for (ActivityInfo info : mPackageInfo.activities) {\n                    components.put(info, ComponentsOption.COMPONENT_TYPE_ACTIVITY);\n                }\n            }\n            if (mPackageInfo.services != null) {\n                for (ServiceInfo info : mPackageInfo.services) {\n                    components.put(info, ComponentsOption.COMPONENT_TYPE_SERVICE);\n                }\n            }\n            if (mPackageInfo.receivers != null) {\n                for (ActivityInfo info : mPackageInfo.receivers) {\n                    components.put(info, ComponentsOption.COMPONENT_TYPE_RECEIVER);\n                }\n            }\n            if (mPackageInfo.providers != null) {\n                for (ProviderInfo info : mPackageInfo.providers) {\n                    components.put(info, ComponentsOption.COMPONENT_TYPE_PROVIDER);\n                }\n            }\n            mAllComponents = components;\n        }\n        return mAllComponents;\n    }\n\n    @Override\n    @NonNull\n    public List<String> getAllPermissions() {\n        if (mUsedPermissions == null) {\n            Set<String> usedPermissions = new HashSet<>();\n            if (mPackageInfo.requestedPermissions != null) {\n                Collections.addAll(usedPermissions, mPackageInfo.requestedPermissions);\n            }\n            if (mPackageInfo.permissions != null) {\n                for (PermissionInfo perm : mPackageInfo.permissions) {\n                    usedPermissions.add(perm.name);\n                }\n            }\n            if (mPackageInfo.activities != null) {\n                for (ActivityInfo info : mPackageInfo.activities) {\n                    if (info.permission != null) {\n                        usedPermissions.add(info.permission);\n                    }\n                }\n            }\n            if (mPackageInfo.services != null) {\n                for (ServiceInfo info : mPackageInfo.services) {\n                    if (info.permission != null) {\n                        usedPermissions.add(info.permission);\n                    }\n                }\n            }\n            if (mPackageInfo.receivers != null) {\n                for (ActivityInfo info : mPackageInfo.receivers) {\n                    if (info.permission != null) {\n                        usedPermissions.add(info.permission);\n                    }\n                }\n            }\n            mUsedPermissions = new ArrayList<>(usedPermissions);\n        }\n        return mUsedPermissions;\n    }\n\n    @Override\n    @NonNull\n    public FeatureInfo[] getAllRequestedFeatures() {\n        return ArrayUtils.defeatNullable(FeatureInfo.class, mPackageInfo.reqFeatures);\n    }\n\n    @Override\n    public boolean isInstalled() {\n        return ApplicationInfoCompat.isInstalled(mApplicationInfo);\n    }\n\n    @Override\n    public boolean isFrozen() {\n        return !isEnabled() || isSuspended() || isHidden();\n    }\n\n    @Override\n    public int getFreezeFlags() {\n        if (mFreezeFlags != null) {\n            return mFreezeFlags;\n        }\n        mFreezeFlags = 0;\n        if (!isEnabled()) {\n            mFreezeFlags |= FreezeOption.FREEZE_TYPE_DISABLED;\n        }\n        if (isHidden()) {\n            mFreezeFlags |= FreezeOption.FREEZE_TYPE_HIDDEN;\n        }\n        if (isSuspended()) {\n            mFreezeFlags |= FreezeOption.FREEZE_TYPE_SUSPENDED;\n        }\n        return mFreezeFlags;\n    }\n\n    @Override\n    public boolean isStopped() {\n        return ApplicationInfoCompat.isStopped(mApplicationInfo);\n    }\n\n    @Override\n    public boolean isTestOnly() {\n        return ApplicationInfoCompat.isTestOnly(mApplicationInfo);\n    }\n\n    @Override\n    public boolean isDebuggable() {\n        return (mApplicationInfo.flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0;\n    }\n\n    @Override\n    public boolean isSystemApp() {\n        return ApplicationInfoCompat.isSystemApp(mApplicationInfo);\n    }\n\n    @Override\n    public boolean hasCode() {\n        return (mApplicationInfo.flags & ApplicationInfo.FLAG_HAS_CODE) != 0;\n    }\n\n    @Override\n    public boolean isPersistent() {\n        return (mApplicationInfo.flags & ApplicationInfo.FLAG_PERSISTENT) != 0;\n    }\n\n    @Override\n    public boolean isUpdatedSystemApp() {\n        return (mApplicationInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0;\n    }\n\n    @Override\n    public boolean backupAllowed() {\n        return (mApplicationInfo.flags & ApplicationInfo.FLAG_ALLOW_BACKUP) != 0;\n    }\n\n    @Override\n    public boolean installedInExternalStorage() {\n        return (mApplicationInfo.flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0;\n    }\n\n    @Override\n    public boolean requestedLargeHeap() {\n        return (mApplicationInfo.flags & ApplicationInfo.FLAG_LARGE_HEAP) != 0;\n    }\n\n    @Override\n    public boolean supportsRTL() {\n        return (mApplicationInfo.flags & ApplicationInfo.FLAG_SUPPORTS_RTL) != 0;\n    }\n\n    @Override\n    public boolean dataOnlyApp() {\n        return (mApplicationInfo.flags & ApplicationInfo.FLAG_IS_DATA_ONLY) != 0;\n    }\n\n    @Override\n    @RequiresApi(Build.VERSION_CODES.M)\n    public boolean usesHttp() {\n        return (mApplicationInfo.flags & ApplicationInfo.FLAG_USES_CLEARTEXT_TRAFFIC) != 0;\n    }\n\n    @Override\n    public boolean isPrivileged() {\n        return ApplicationInfoCompat.isPrivileged(mApplicationInfo);\n    }\n\n    @RequiresApi(Build.VERSION_CODES.P)\n    public boolean usesSensors() {\n        if (!isInstalled()) {\n            return false;\n        }\n        if (mUsesSensors == null) {\n            if (SelfPermissions.checkSelfOrRemotePermission(ManifestCompat.permission.MANAGE_SENSORS)) {\n                mUsesSensors = SensorServiceCompat.isSensorEnabled(getPackageName(), getUserId());\n            } else mUsesSensors = true; // Worse case: always true\n        }\n        return mUsesSensors;\n    }\n\n    @Override\n    public boolean isBatteryOptEnabled() {\n        if (!isInstalled()) {\n            return true;\n        }\n        if (mBatteryOptEnabled == null) {\n            mBatteryOptEnabled = DeviceIdleManagerCompat.isBatteryOptimizedApp(getPackageName());\n        }\n        return mBatteryOptEnabled;\n    }\n\n    @Override\n    public boolean hasKeyStoreItems() {\n        if (!isInstalled()) {\n            return false;\n        }\n        if (mHasKeystoreItems == null) {\n            mHasKeystoreItems = KeyStoreUtils.hasKeyStore(mApplicationInfo.uid);\n        }\n        return mHasKeystoreItems;\n    }\n\n    @Override\n    public int getRuleCount() {\n        if (mRulesCount == null) {\n            try (ComponentsBlocker cb = ComponentsBlocker.getInstance(getPackageName(), getUserId(), false)) {\n                mRulesCount = cb.entryCount();\n            }\n        }\n        return mRulesCount;\n    }\n\n    @Override\n    @NonNull\n    public String getSsaid() {\n        if (mSsaid == null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {\n            try {\n                mSsaid = new SsaidSettings(mUserId).getSsaid(getPackageName(), mApplicationInfo.uid);\n            } catch (IOException ignore) {\n            }\n        }\n        if (mSsaid == null) {\n            mSsaid = \"\";\n        }\n        return mSsaid;\n    }\n\n    @Override\n    public boolean hasDomainUrls() {\n        return ApplicationInfoCompat.hasDomainUrls(mApplicationInfo);\n    }\n\n    @Override\n    public boolean hasStaticSharedLibrary() {\n        return ApplicationInfoCompat.isStaticSharedLibrary(mApplicationInfo);\n    }\n\n    @Override\n    public boolean isHidden() {\n        return ApplicationInfoCompat.isHidden(mApplicationInfo);\n    }\n\n    @Override\n    public boolean isSuspended() {\n        return ApplicationInfoCompat.isSuspended(mApplicationInfo);\n    }\n\n    @Override\n    public boolean isEnabled() {\n        return mApplicationInfo.enabled;\n    }\n\n    @Override\n    @Nullable\n    public String getSharedUserId() {\n        return mPackageInfo.sharedUserId;\n    }\n\n    private void fetchPackageSizeInfo() {\n        if (mPackageSizeInfo == null && isInstalled()) {\n            mPackageSizeInfo = PackageUtils.getPackageSizeInfo(ContextUtils.getContext(), getPackageName(), mUserId, null);\n        }\n    }\n\n    @Override\n    public long getTotalSize() {\n        fetchPackageSizeInfo();\n        return mPackageSizeInfo != null ? mPackageSizeInfo.getTotalSize() : 0;\n    }\n\n    @Override\n    public long getApkSize() {\n        fetchPackageSizeInfo();\n        return mPackageSizeInfo != null ? (mPackageSizeInfo.codeSize + mPackageSizeInfo.obbSize) : 0;\n    }\n\n    @Override\n    public long getCacheSize() {\n        fetchPackageSizeInfo();\n        return mPackageSizeInfo != null ? mPackageSizeInfo.cacheSize : 0;\n    }\n\n    @Override\n    public long getDataSize() {\n        fetchPackageSizeInfo();\n        return mPackageSizeInfo != null ? (mPackageSizeInfo.dataSize + mPackageSizeInfo.mediaSize + mPackageSizeInfo.cacheSize) : 0;\n    }\n\n    @Override\n    @NonNull\n    public AppUsageStatsManager.DataUsage getDataUsage() {\n        if (mDataUsage == null && isInstalled()) {\n            if (mPackageUsageInfo != null) {\n                mDataUsage = AppUsageStatsManager.DataUsage.fromDataUsage(mPackageUsageInfo.mobileData, mPackageUsageInfo.wifiData);\n            }\n        }\n        if (mDataUsage == null) {\n            mDataUsage = AppUsageStatsManager.DataUsage.EMPTY;\n        }\n        return mDataUsage;\n    }\n\n    @Override\n    public int getTimesOpened() {\n        return mPackageUsageInfo != null ? mPackageUsageInfo.timesOpened : 0;\n    }\n\n    @Override\n    public long getTotalScreenTime() {\n        return mPackageUsageInfo != null ? mPackageUsageInfo.screenTime : 0L;\n    }\n\n    @Override\n    public long getLastUsedTime() {\n        return mPackageUsageInfo != null ? mPackageUsageInfo.lastUsageTime : 0L;\n    }\n\n    @Override\n    @Nullable\n    public SignerInfo fetchSignerInfo() {\n        if (mSignerInfo == null) {\n            mSignerInfo = PackageUtils.getSignerInfo(mPackageInfo, !isInstalled());\n        }\n        return mSignerInfo;\n    }\n\n    @Override\n    @NonNull\n    public String[] getSignatureSubjectLines() {\n        fetchSignerInfo();\n        if (mSignerInfo != null && mSignatureSubjectLines == null) {\n            X509Certificate[] signatures = mSignerInfo.getAllSignerCerts();\n            if (signatures != null) {\n                mSignatureSubjectLines = new String[signatures.length];\n                for (int i = 0; i < signatures.length; ++i) {\n                    mSignatureSubjectLines[i] = signatures[i].getSubjectX500Principal().getName();\n                }\n            }\n        }\n        return mSignatureSubjectLines != null ? mSignatureSubjectLines : EmptyArray.STRING;\n    }\n\n    @Override\n    @NonNull\n    public String[] getSignatureSha256Checksums() {\n        fetchSignerInfo();\n        if (mSignerInfo != null && mSignatureSha256Checksums == null) {\n            X509Certificate[] signatures = mSignerInfo.getAllSignerCerts();\n            if (signatures != null) {\n                mSignatureSha256Checksums = new String[signatures.length];\n                for (int i = 0; i < signatures.length; ++i) {\n                    try {\n                        mSignatureSha256Checksums[i] = DigestUtils.getHexDigest(DigestUtils.SHA_256, signatures[i].getEncoded());\n                    } catch (CertificateEncodingException e) {\n                        mSignatureSha256Checksums[i] = \"\";\n                    }\n                }\n            }\n        }\n        return mSignatureSha256Checksums != null ? mSignatureSha256Checksums : EmptyArray.STRING;\n    }\n\n    @Override\n    @Nullable\n    public InstallSourceInfoCompat getInstallerInfo() {\n        if (mInstallerInfo == null && isInstalled()) {\n            try {\n                mInstallerInfo = PackageManagerCompat.getInstallSourceInfo(getPackageName(), mUserId);\n            } catch (RemoteException ignore) {\n            }\n        }\n        return mInstallerInfo;\n    }\n\n    @Override\n    @Nullable\n    public DebloatObject getBloatwareInfo() {\n        if (mBloatwareInfo == null) {\n            for (DebloatObject debloatObject : StaticDataset.getDebloatObjects()) {\n                if (getPackageName().equals(debloatObject.packageName)) {\n                    mBloatwareInfo = debloatObject;\n                    break;\n                }\n            }\n        }\n        return mBloatwareInfo;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/filters/FilteringUtils.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.filters;\n\nimport static io.github.muntashirakon.AppManager.compat.PackageManagerCompat.GET_SIGNING_CERTIFICATES;\nimport static io.github.muntashirakon.AppManager.compat.PackageManagerCompat.MATCH_DISABLED_COMPONENTS;\nimport static io.github.muntashirakon.AppManager.compat.PackageManagerCompat.MATCH_STATIC_SHARED_AND_SDK_LIBRARIES;\nimport static io.github.muntashirakon.AppManager.compat.PackageManagerCompat.MATCH_UNINSTALLED_PACKAGES;\n\nimport android.content.pm.PackageInfo;\nimport android.content.pm.PackageManager;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.WorkerThread;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport io.github.muntashirakon.AppManager.compat.PackageManagerCompat;\nimport io.github.muntashirakon.AppManager.self.SelfPermissions;\nimport io.github.muntashirakon.AppManager.settings.FeatureController;\nimport io.github.muntashirakon.AppManager.usage.AppUsageStatsManager;\nimport io.github.muntashirakon.AppManager.usage.PackageUsageInfo;\nimport io.github.muntashirakon.AppManager.usage.TimeInterval;\nimport io.github.muntashirakon.AppManager.usage.UsageUtils;\nimport io.github.muntashirakon.AppManager.utils.ExUtils;\nimport io.github.muntashirakon.AppManager.utils.ThreadUtils;\n\npublic final class FilteringUtils {\n    @NonNull\n    @WorkerThread\n    public static List<FilterableAppInfo> loadFilterableAppInfo(@NonNull int[] userIds) {\n        List<FilterableAppInfo> filterableAppInfoList = new ArrayList<>();\n        boolean hasUsageAccess = FeatureController.isUsageAccessEnabled() && SelfPermissions.checkUsageStatsPermission();\n        for (int userId : userIds) {\n            if (ThreadUtils.isInterrupted()) return Collections.emptyList();\n\n            if (!SelfPermissions.checkCrossUserPermission(userId, false)) {\n                // No support for cross user\n                continue;\n            }\n\n            // List packages\n            List<PackageInfo> packageInfoList = PackageManagerCompat.getInstalledPackages(\n                    PackageManager.GET_META_DATA | GET_SIGNING_CERTIFICATES\n                            | PackageManager.GET_ACTIVITIES | PackageManager.GET_RECEIVERS\n                            | PackageManager.GET_PROVIDERS | PackageManager.GET_SERVICES\n                            | PackageManager.GET_CONFIGURATIONS | PackageManager.GET_PERMISSIONS\n                            | PackageManager.GET_URI_PERMISSION_PATTERNS\n                            | MATCH_DISABLED_COMPONENTS | MATCH_UNINSTALLED_PACKAGES\n                            | MATCH_STATIC_SHARED_AND_SDK_LIBRARIES, userId);\n            // List usages\n            Map<String, PackageUsageInfo> packageUsageInfoList = new HashMap<>();\n            if (hasUsageAccess) {\n                TimeInterval interval = UsageUtils.getLastWeek();\n                List<PackageUsageInfo> usageInfoList = ExUtils.exceptionAsNull(() ->\n                        AppUsageStatsManager.getInstance().getUsageStats(interval, userId));\n                if (usageInfoList != null) {\n                    for (PackageUsageInfo info : usageInfoList) {\n                        if (ThreadUtils.isInterrupted()) return Collections.emptyList();\n                        packageUsageInfoList.put(info.packageName, info);\n                    }\n                }\n            }\n            for (PackageInfo packageInfo : packageInfoList) {\n                // Interrupt thread on request\n                if (ThreadUtils.isInterrupted()) return Collections.emptyList();\n                filterableAppInfoList.add(new FilterableAppInfo(packageInfo, packageUsageInfoList.get(packageInfo.packageName)));\n            }\n        }\n        return filterableAppInfoList;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/filters/FinderActivity.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.filters;\n\nimport android.os.Bundle;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.lifecycle.ViewModelProvider;\n\nimport com.google.android.material.floatingactionbutton.FloatingActionButton;\nimport com.google.android.material.progressindicator.LinearProgressIndicator;\n\nimport java.util.Optional;\n\nimport io.github.muntashirakon.AppManager.BaseActivity;\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.utils.DateUtils;\nimport io.github.muntashirakon.AppManager.utils.UIUtils;\nimport io.github.muntashirakon.util.UiUtils;\nimport io.github.muntashirakon.view.ProgressIndicatorCompat;\nimport io.github.muntashirakon.widget.MultiSelectionView;\nimport io.github.muntashirakon.widget.RecyclerView;\n\npublic class FinderActivity extends BaseActivity implements EditFiltersDialogFragment.OnSaveDialogButtonInterface {\n    private FinderViewModel mViewModel;\n    private LinearProgressIndicator mProgress;\n    private RecyclerView mRecyclerView;\n    private FinderAdapter mAdapter;\n    private FloatingActionButton mFilterBtn;\n    private MultiSelectionView mMultiSelectionView;\n\n    @Override\n    protected void onAuthenticated(@Nullable Bundle savedInstanceState) {\n        setContentView(R.layout.activity_finder);\n        setSupportActionBar(findViewById(R.id.toolbar));\n        mViewModel = new ViewModelProvider(this).get(FinderViewModel.class);\n        mProgress = findViewById(R.id.progress_linear);\n        mRecyclerView = findViewById(R.id.item_list);\n        mFilterBtn = findViewById(R.id.floatingActionButton);\n        mMultiSelectionView = findViewById(R.id.selection_view);\n        UiUtils.applyWindowInsetsAsMargin(mFilterBtn);\n        mAdapter = new FinderAdapter();\n        mRecyclerView.setLayoutManager(UIUtils.getGridLayoutAt450Dp(this));\n        mRecyclerView.setAdapter(mAdapter);\n        mMultiSelectionView.hide();\n        mFilterBtn.setOnClickListener(v -> showFiltersDialog());\n        // Watch livedata\n        mViewModel.getFilteredAppListLiveData().observe(this, list -> {\n            ProgressIndicatorCompat.setVisibility(mProgress, false);\n            mAdapter.setDefaultList(list);\n        });\n        mViewModel.getLastUpdateTimeLiveData().observe(this, time -> {\n            CharSequence subtitle;\n            // TODO: 8/2/24 Set subtitle to \"Loaded at: {time}\" localised\n            if (time < 0) {\n                subtitle = getString(R.string.loading);\n            } else subtitle = \"Loaded at: \" + DateUtils.formatDateTime(this, time);\n            Optional.ofNullable(getSupportActionBar()).ifPresent(actionBar -> actionBar.setSubtitle(subtitle));\n        });\n        mViewModel.loadFilteredAppList(true);\n    }\n\n    private void showFiltersDialog() {\n        EditFiltersDialogFragment dialog = new EditFiltersDialogFragment();\n        dialog.setOnSaveDialogButtonInterface(this);\n        dialog.show(getSupportFragmentManager(), EditFiltersDialogFragment.TAG);\n    }\n\n    @NonNull\n    @Override\n    public FilterItem getFilterItem() {\n        return mViewModel.getFilterItem();\n    }\n\n    @Override\n    public void onItemAltered(@NonNull FilterItem item) {\n        mViewModel.loadFilteredAppList(false);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/filters/FinderAdapter.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.filters;\n\nimport android.graphics.Color;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.UiThread;\nimport androidx.appcompat.widget.AppCompatImageView;\nimport androidx.recyclerview.widget.RecyclerView;\n\nimport com.google.android.material.card.MaterialCardView;\nimport com.google.android.material.materialswitch.MaterialSwitch;\nimport com.google.android.material.textview.MaterialTextView;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.self.imagecache.ImageLoader;\nimport io.github.muntashirakon.util.AdapterUtils;\n\npublic class FinderAdapter extends RecyclerView.Adapter<FinderAdapter.ViewHolder> {\n    private final List<FilterItem.FilteredItemInfo<FilterableAppInfo>> mAdapterList = new ArrayList<>();\n\n    @UiThread\n    public void setDefaultList(List<FilterItem.FilteredItemInfo<FilterableAppInfo>> list) {\n        synchronized (mAdapterList) {\n            AdapterUtils.notifyDataSetChanged(this, mAdapterList, list);\n        }\n    }\n\n    @NonNull\n    @Override\n    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {\n        View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_finder, parent, false);\n        return new ViewHolder(v);\n    }\n\n    @Override\n    public void onBindViewHolder(@NonNull ViewHolder holder, int position) {\n        FilterItem.FilteredItemInfo<FilterableAppInfo> itemInfo;\n        synchronized (mAdapterList) {\n            itemInfo = mAdapterList.get(position);\n        }\n        FilterableAppInfo appInfo = itemInfo.info;\n        ImageLoader.getInstance().displayImage(appInfo.getPackageName(), appInfo.getApplicationInfo(), holder.icon);\n        holder.label.setText(appInfo.getAppLabel());\n        holder.pkg.setText(appInfo.getPackageName());\n        // TODO: 8/2/24 Add highlighted extras\n        holder.item1.setVisibility(View.GONE);\n        holder.item2.setVisibility(View.GONE);\n        holder.item3.setVisibility(View.GONE);\n        holder.toggleBtn.setVisibility(View.GONE);\n        holder.itemView.setStrokeColor(Color.TRANSPARENT);\n    }\n\n    @Override\n    public int getItemCount() {\n        synchronized (mAdapterList) {\n            return mAdapterList.size();\n        }\n    }\n\n    public static class ViewHolder extends RecyclerView.ViewHolder {\n        public MaterialCardView itemView;\n        public AppCompatImageView icon;\n        public MaterialTextView label;\n        public MaterialTextView pkg;\n        public MaterialTextView item1;\n        public MaterialTextView item2;\n        public MaterialTextView item3;\n        public MaterialSwitch toggleBtn;\n\n        public ViewHolder(@NonNull View itemView) {\n            super(itemView);\n            this.itemView = (MaterialCardView) itemView;\n            icon = itemView.findViewById(R.id.icon);\n            label = itemView.findViewById(R.id.label);\n            pkg = itemView.findViewById(R.id.package_name);\n            item1 = itemView.findViewById(R.id.item1);\n            item2 = itemView.findViewById(R.id.item2);\n            item3 = itemView.findViewById(R.id.item3);\n            toggleBtn = itemView.findViewById(R.id.toggle_button);\n        }\n    }\n\n\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/filters/FinderFilterAdapter.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.filters;\n\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.TextView;\n\nimport androidx.annotation.NonNull;\nimport androidx.core.content.ContextCompat;\nimport androidx.recyclerview.widget.RecyclerView;\n\nimport com.google.android.material.button.MaterialButton;\n\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.filters.options.FilterOption;\nimport io.github.muntashirakon.util.AdapterUtils;\n\n// Copyright 2012 Nolan Lawson\npublic class FinderFilterAdapter extends RecyclerView.Adapter<FinderFilterAdapter.ViewHolder> {\n    private OnClickListener mClickListener;\n    @NonNull\n    private final FilterItem mFilterItem;\n\n    public void setOnItemClickListener(OnClickListener listener) {\n        mClickListener = listener;\n    }\n\n    public FinderFilterAdapter(@NonNull FilterItem filterItem) {\n        mFilterItem = filterItem;\n    }\n\n    public void add(@NonNull FilterOption filter) {\n        int position = mFilterItem.addFilterOption(filter);\n        if (position >= 0) {\n            notifyItemInserted(position);\n        }\n    }\n\n    public void update(int position, @NonNull FilterOption filter) {\n        mFilterItem.updateFilterOptionAt(position, filter);\n        notifyItemChanged(position, AdapterUtils.STUB);\n    }\n\n    public void remove(int position, int id) {\n        FilterOption filterOption = mFilterItem.getFilterOptionAt(position);\n        if (filterOption.id == id && mFilterItem.removeFilterOptionAt(position)) {\n            notifyItemRemoved(position);\n        }\n    }\n\n    @NonNull\n    @Override\n    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {\n        View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_icon_title_subtitle, parent, false);\n        return new ViewHolder(v);\n    }\n\n    @Override\n    public void onBindViewHolder(@NonNull ViewHolder holder, int position) {\n        final FilterOption filterOption = mFilterItem.getFilterOptionAt(position);\n        holder.titleView.setText(filterOption.getFullId());\n        holder.subtitleView.setText(filterOption.toLocalizedString(holder.itemView.getContext()));\n        holder.itemView.setOnClickListener(v -> {\n            if (mClickListener != null) {\n                mClickListener.onEdit(holder.itemView, holder.getAbsoluteAdapterPosition(), filterOption);\n            }\n        });\n        holder.actionButton.setOnClickListener(v -> {\n            if (mClickListener != null) {\n                mClickListener.onRemove(holder.itemView, holder.getAbsoluteAdapterPosition(), filterOption);\n            }\n        });\n    }\n\n    @Override\n    public int getItemCount() {\n        return mFilterItem.getSize();\n    }\n\n    public interface OnClickListener {\n        void onEdit(View view, int position, FilterOption filterOption);\n        void onRemove(View view, int position, FilterOption filterOption);\n    }\n\n    public static class ViewHolder extends RecyclerView.ViewHolder {\n        TextView titleView;\n        TextView subtitleView;\n        MaterialButton actionButton;\n\n        public ViewHolder(View itemView) {\n            super(itemView);\n            itemView.findViewById(R.id.item_icon).setVisibility(View.GONE);\n            titleView = itemView.findViewById(R.id.item_title);\n            subtitleView = itemView.findViewById(R.id.item_subtitle);\n            actionButton = itemView.findViewById(R.id.item_open);\n            actionButton.setIcon(ContextCompat.getDrawable(itemView.getContext(), io.github.muntashirakon.ui.R.drawable.ic_clear));\n            actionButton.setContentDescription(itemView.getContext().getString(R.string.item_remove));\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/filters/FinderViewModel.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.filters;\n\nimport android.app.Application;\nimport android.os.UserHandleHidden;\n\nimport androidx.annotation.WorkerThread;\nimport androidx.lifecycle.AndroidViewModel;\nimport androidx.lifecycle.MutableLiveData;\n\nimport org.jetbrains.annotations.NotNull;\nimport org.jetbrains.annotations.Nullable;\n\nimport java.util.List;\nimport java.util.concurrent.Future;\n\nimport io.github.muntashirakon.AppManager.utils.ThreadUtils;\n\npublic class FinderViewModel extends AndroidViewModel {\n    public static final String TAG = FinderViewModel.class.getSimpleName();\n\n    private final MutableLiveData<Long> mLastUpdateTimeLiveData = new MutableLiveData<>();\n    private final MutableLiveData<List<FilterItem.FilteredItemInfo<FilterableAppInfo>>> mFilteredAppListLiveData = new MutableLiveData<>();\n    private Future<?> mAppListLoaderFuture;\n    @Nullable\n    private List<FilterableAppInfo> mFilterableAppInfoList;\n    @NotNull\n    private final FilterItem mFilterItem = new FilterItem();\n\n    public FinderViewModel(@NotNull Application application) {\n        super(application);\n    }\n\n    @Override\n    protected void onCleared() {\n        super.onCleared();\n    }\n\n    public MutableLiveData<Long> getLastUpdateTimeLiveData() {\n        return mLastUpdateTimeLiveData;\n    }\n\n    public MutableLiveData<List<FilterItem.FilteredItemInfo<FilterableAppInfo>>> getFilteredAppListLiveData() {\n        return mFilteredAppListLiveData;\n    }\n\n    public FilterItem getFilterItem() {\n        return mFilterItem;\n    }\n\n    public void loadFilteredAppList(boolean refresh) {\n        if (mAppListLoaderFuture != null) {\n            mAppListLoaderFuture.cancel(true);\n        }\n        mAppListLoaderFuture = ThreadUtils.postOnBackgroundThread(() -> {\n            mLastUpdateTimeLiveData.postValue(-1L);\n            if (mFilterableAppInfoList == null || refresh) {\n                loadAppList();\n            }\n            if (ThreadUtils.isInterrupted() || mFilterableAppInfoList == null) return;\n            mFilteredAppListLiveData.postValue(mFilterItem.getFilteredList(mFilterableAppInfoList));\n            mLastUpdateTimeLiveData.postValue(System.currentTimeMillis());\n        });\n    }\n\n    @WorkerThread\n    private void loadAppList() {\n        // TODO: 8/2/24 Allow multiple users\n        // TODO: 8/2/24 Include backups for uninstalled apps\n        int[] userIds = new int[]{UserHandleHidden.myUserId()}; //Users.getUsersIds();\n        mFilterableAppInfoList = FilteringUtils.loadFilterableAppInfo(userIds);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/filters/IFilterableAppInfo.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.filters;\n\nimport android.content.pm.ComponentInfo;\nimport android.content.pm.FeatureInfo;\nimport android.graphics.drawable.Drawable;\nimport android.os.Build;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.RequiresApi;\n\nimport java.util.List;\nimport java.util.Map;\n\nimport io.github.muntashirakon.AppManager.apk.signing.SignerInfo;\nimport io.github.muntashirakon.AppManager.compat.AppOpsManagerCompat;\nimport io.github.muntashirakon.AppManager.compat.InstallSourceInfoCompat;\nimport io.github.muntashirakon.AppManager.db.entity.Backup;\nimport io.github.muntashirakon.AppManager.debloat.DebloatObject;\nimport io.github.muntashirakon.AppManager.usage.AppUsageStatsManager;\n\npublic interface IFilterableAppInfo {\n    @NonNull\n    String getPackageName();\n\n    int getUserId();\n\n    int getUid();\n\n    @NonNull\n    String getAppLabel();\n\n    @NonNull\n    Drawable getAppIcon();\n\n    @Nullable\n    String getVersionName();\n\n    long getVersionCode();\n\n    long getFirstInstallTime();\n\n    long getLastUpdateTime();\n\n    int getTargetSdk();\n\n    @RequiresApi(Build.VERSION_CODES.S)\n    int getCompileSdk();\n\n    @RequiresApi(Build.VERSION_CODES.N)\n    int getMinSdk();\n\n    @NonNull\n    Backup[] getBackups();\n\n    boolean isRunning();\n\n    @NonNull\n    Map<ComponentInfo, Integer> getTrackerComponents();\n\n    @NonNull\n    List<AppOpsManagerCompat.OpEntry> getAppOps();\n\n    @NonNull\n    Map<ComponentInfo, Integer> getAllComponents();\n\n    @NonNull\n    List<String> getAllPermissions();\n\n    @NonNull\n    FeatureInfo[] getAllRequestedFeatures();\n\n    boolean isInstalled();\n\n    boolean isFrozen();\n\n    int getFreezeFlags();\n\n    boolean isStopped();\n\n    boolean isTestOnly();\n\n    boolean isDebuggable();\n\n    boolean isSystemApp();\n\n    boolean hasCode();\n\n    boolean isPersistent();\n\n    boolean isUpdatedSystemApp();\n\n    boolean backupAllowed();\n\n    boolean installedInExternalStorage();\n\n    boolean requestedLargeHeap();\n\n    boolean supportsRTL();\n\n    boolean dataOnlyApp();\n\n    @RequiresApi(Build.VERSION_CODES.M)\n    boolean usesHttp();\n\n    boolean isPrivileged();\n\n    @RequiresApi(Build.VERSION_CODES.P)\n    boolean usesSensors();\n\n    @RequiresApi(Build.VERSION_CODES.M)\n    boolean isBatteryOptEnabled();\n\n    boolean hasKeyStoreItems();\n\n    int getRuleCount();\n\n    @Nullable\n    String getSsaid();\n\n    boolean hasDomainUrls();\n\n    boolean hasStaticSharedLibrary();\n\n    boolean isHidden();\n\n    boolean isSuspended();\n\n    boolean isEnabled();\n\n    @Nullable\n    String getSharedUserId();\n\n    long getTotalSize();\n\n    long getApkSize();\n\n    long getCacheSize();\n\n    long getDataSize();\n\n    @NonNull\n    AppUsageStatsManager.DataUsage getDataUsage();\n\n    int getTimesOpened();\n\n    long getTotalScreenTime();\n\n    long getLastUsedTime();\n\n    @Nullable\n    SignerInfo fetchSignerInfo();\n\n    @NonNull\n    String[] getSignatureSubjectLines();\n\n    @NonNull\n    String[] getSignatureSha256Checksums();\n\n    @Nullable\n    InstallSourceInfoCompat getInstallerInfo();\n\n    @Nullable\n    DebloatObject getBloatwareInfo();\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/filters/options/ApkSizeOption.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.filters.options;\n\nimport android.content.Context;\nimport android.text.SpannableStringBuilder;\nimport android.text.format.Formatter;\n\nimport androidx.annotation.NonNull;\n\nimport java.util.LinkedHashMap;\nimport java.util.Map;\n\nimport io.github.muntashirakon.AppManager.filters.IFilterableAppInfo;\nimport io.github.muntashirakon.AppManager.utils.LangUtils;\n\npublic class ApkSizeOption extends FilterOption {\n    private final Map<String, Integer> mKeysWithType = new LinkedHashMap<String, Integer>() {{\n        put(KEY_ALL, TYPE_NONE);\n        put(\"eq\", TYPE_SIZE_BYTES);\n        put(\"le\", TYPE_SIZE_BYTES);\n        put(\"ge\", TYPE_SIZE_BYTES);\n    }};\n\n    public ApkSizeOption() {\n        super(\"apk_size\");\n    }\n\n    @NonNull\n    @Override\n    public Map<String, Integer> getKeysWithType() {\n        return mKeysWithType;\n    }\n\n    @NonNull\n    @Override\n    public TestResult test(@NonNull IFilterableAppInfo info, @NonNull TestResult result) {\n        switch (key) {\n            case KEY_ALL:\n                return result.setMatched(true);\n            case \"eq\":\n                return result.setMatched(info.getApkSize() == longValue);\n            case \"le\":\n                return result.setMatched(info.getApkSize() <= longValue);\n            case \"ge\":\n                return result.setMatched(info.getApkSize() >= longValue);\n            default:\n                throw new UnsupportedOperationException(\"Invalid key \" + key);\n        }\n    }\n\n    @NonNull\n    @Override\n    public CharSequence toLocalizedString(@NonNull Context context) {\n        SpannableStringBuilder sb = new SpannableStringBuilder(\"APK size\");\n        switch (key) {\n            case KEY_ALL:\n                return sb.append(LangUtils.getSeparatorString()).append(\"any\");\n            case \"eq\":\n                return sb.append(\" = \").append(Formatter.formatFileSize(context, longValue));\n            case \"le\":\n                return sb.append(\" ≤ \").append(Formatter.formatFileSize(context, longValue));\n            case \"ge\":\n                return sb.append(\" ≥ \").append(Formatter.formatFileSize(context, longValue));\n            default:\n                throw new UnsupportedOperationException(\"Invalid key \" + key);\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/filters/options/AppLabelOption.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.filters.options;\n\nimport android.content.Context;\nimport android.text.SpannableStringBuilder;\n\nimport androidx.annotation.NonNull;\n\nimport java.util.LinkedHashMap;\nimport java.util.Map;\nimport java.util.Objects;\n\nimport io.github.muntashirakon.AppManager.filters.IFilterableAppInfo;\nimport io.github.muntashirakon.AppManager.utils.LangUtils;\n\npublic class AppLabelOption extends FilterOption {\n    private final Map<String, Integer> mKeysWithType = new LinkedHashMap<String, Integer>() {{\n        put(KEY_ALL, TYPE_NONE);\n        put(\"eq\", TYPE_STR_SINGLE);\n        put(\"contains\", TYPE_STR_SINGLE);\n        put(\"starts_with\", TYPE_STR_SINGLE);\n        put(\"ends_with\", TYPE_STR_SINGLE);\n        put(\"regex\", TYPE_REGEX);\n    }};\n\n    public AppLabelOption() {\n        super(\"app_label\");\n    }\n\n    @NonNull\n    @Override\n    public Map<String, Integer> getKeysWithType() {\n        return mKeysWithType;\n    }\n\n    @NonNull\n    @Override\n    public TestResult test(@NonNull IFilterableAppInfo info, @NonNull TestResult result) {\n        switch (key) {\n            case KEY_ALL:\n                return result.setMatched(true);\n            case \"eq\":\n                return result.setMatched(info.getAppLabel().equals(Objects.requireNonNull(value)));\n            case \"contains\":\n                return result.setMatched(info.getAppLabel().contains(Objects.requireNonNull(value)));\n            case \"starts_with\":\n                return result.setMatched(info.getAppLabel().startsWith(Objects.requireNonNull(value)));\n            case \"ends_with\":\n                return result.setMatched(info.getAppLabel().endsWith(Objects.requireNonNull(value)));\n            case \"regex\":\n                return result.setMatched(regexValue.matcher(info.getAppLabel()).matches());\n            default:\n                throw new UnsupportedOperationException(\"Invalid key \" + key);\n        }\n    }\n\n    @NonNull\n    @Override\n    public CharSequence toLocalizedString(@NonNull Context context) {\n        SpannableStringBuilder sb = new SpannableStringBuilder(\"App label\");\n        switch (key) {\n            case KEY_ALL:\n                return sb.append(LangUtils.getSeparatorString()).append(\"any\");\n            case \"eq\":\n                return sb.append(\" = '\").append(value).append(\"'\");\n            case \"contains\":\n                return sb.append(\" contains '\").append(value).append(\"'\");\n            case \"starts_with\":\n                return sb.append(\" starts with '\").append(value).append(\"'\");\n            case \"ends_with\":\n                return sb.append(\" ends with '\").append(value).append(\"'\");\n            case \"regex\":\n                return sb.append(\" matches '\").append(value).append(\"'\");\n            default:\n                throw new UnsupportedOperationException(\"Invalid key \" + key);\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/filters/options/AppTypeOption.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.filters.options;\n\nimport android.content.Context;\nimport android.os.Build;\nimport android.text.SpannableStringBuilder;\nimport android.text.TextUtils;\n\nimport androidx.annotation.NonNull;\n\nimport java.util.LinkedHashMap;\nimport java.util.Map;\n\nimport io.github.muntashirakon.AppManager.compat.ManifestCompat;\nimport io.github.muntashirakon.AppManager.filters.IFilterableAppInfo;\nimport io.github.muntashirakon.AppManager.self.SelfPermissions;\nimport io.github.muntashirakon.AppManager.utils.LangUtils;\n\npublic class AppTypeOption extends FilterOption {\n    public static final int APP_TYPE_USER = 1 << 0;\n    public static final int APP_TYPE_SYSTEM = 1 << 1;\n    public static final int APP_TYPE_UPDATED_SYSTEM = 1 << 2;\n    public static final int APP_TYPE_PRIVILEGED = 1 << 3;\n    public static final int APP_TYPE_DATA_ONLY = 1 << 4;\n    public static final int APP_TYPE_STOPPED = 1 << 5;\n    public static final int APP_TYPE_SENSORS = 1 << 6;\n    public static final int APP_TYPE_LARGE_HEAP = 1 << 7;\n    public static final int APP_TYPE_DEBUGGABLE = 1 << 8;\n    public static final int APP_TYPE_TEST_ONLY = 1 << 9;\n    public static final int APP_TYPE_HAS_CODE = 1 << 10;\n    public static final int APP_TYPE_PERSISTENT = 1 << 11;\n    public static final int APP_TYPE_ALLOW_BACKUP = 1 << 12;\n    public static final int APP_TYPE_INSTALLED_IN_EXTERNAL = 1 << 13;\n    public static final int APP_TYPE_HTTP_ONLY = 1 << 14;\n    public static final int APP_TYPE_BATTERY_OPT_ENABLED = 1 << 15;\n    public static final int APP_TYPE_PLAY_APP_SIGNING = 1 << 16;\n    public static final int APP_TYPE_SSAID = 1 << 17;\n    public static final int APP_TYPE_KEYSTORE = 1 << 18;\n    public static final int APP_TYPE_WITH_RULES = 1 << 19;\n    public static final int APP_TYPE_PWA = 1 << 20;\n    public static final int APP_TYPE_SHORT_CODE = 1 << 21;\n    public static final int APP_TYPE_OVERLAY = 1 << 22;\n\n    private final Map<String, Integer> mKeysWithType = new LinkedHashMap<String, Integer>() {{\n        put(KEY_ALL, TYPE_NONE);\n        put(\"with_flags\", TYPE_INT_FLAGS);\n        put(\"without_flags\", TYPE_INT_FLAGS);\n    }};\n\n    private final Map<Integer, CharSequence> mFrozenFlags = new LinkedHashMap<Integer, CharSequence>() {{\n        put(APP_TYPE_USER, \"User app\");\n        put(APP_TYPE_SYSTEM, \"System app\");\n        put(APP_TYPE_UPDATED_SYSTEM, \"Updated system app\");\n        put(APP_TYPE_PRIVILEGED, \"Privileged app\");\n        put(APP_TYPE_DATA_ONLY, \"Data-only app\");\n        put(APP_TYPE_STOPPED, \"Force-stopped app\");\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P\n                && SelfPermissions.checkSelfOrRemotePermission(ManifestCompat.permission.MANAGE_SENSORS)) {\n            put(APP_TYPE_SENSORS, \"Uses sensors\");\n        }\n        put(APP_TYPE_LARGE_HEAP, \"Requests large heap\");\n        put(APP_TYPE_DEBUGGABLE, \"Debuggable app\");\n        put(APP_TYPE_TEST_ONLY, \"Test-only app\");\n        put(APP_TYPE_HAS_CODE, \"Has code\");\n        put(APP_TYPE_PERSISTENT, \"Persistent app\");\n        put(APP_TYPE_ALLOW_BACKUP, \"Backup allowed\");\n        put(APP_TYPE_INSTALLED_IN_EXTERNAL, \"Installed in external storage\");\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {\n            put(APP_TYPE_HTTP_ONLY, \"Uses cleartext (HTTP) traffic\");\n            put(APP_TYPE_BATTERY_OPT_ENABLED, \"Battery optimized\");\n        }\n//        put(APP_TYPE_PLAY_APP_SIGNING, \"Uses Play App Signing\"); // TODO: 11/21/24\n        put(APP_TYPE_SSAID, \"Has SSAID\");\n        put(APP_TYPE_KEYSTORE, \"Uses Android KeyStore\");\n        put(APP_TYPE_WITH_RULES, \"Has rules\");\n//        put(APP_TYPE_PWA, \"Progressive web app (PWA)\"); // TODO: 11/21/24\n//        put(APP_TYPE_SHORT_CODE, \"Uses short code\"); // TODO: 11/21/24\n//        put(APP_TYPE_OVERLAY, \"Overlay app\"); // TODO: 11/21/24\n    }};\n\n    public AppTypeOption() {\n        super(\"app_type\");\n    }\n\n    @NonNull\n    @Override\n    public Map<String, Integer> getKeysWithType() {\n        return mKeysWithType;\n    }\n\n    @Override\n    public Map<Integer, CharSequence> getFlags(@NonNull String key) {\n        if (key.equals(\"with_flags\") || key.equals(\"without_flags\")) {\n            return mFrozenFlags;\n        }\n        return super.getFlags(key);\n    }\n\n    @NonNull\n    @Override\n    public TestResult test(@NonNull IFilterableAppInfo info, @NonNull TestResult result) {\n        switch (key) {\n            case KEY_ALL:\n                return result.setMatched(true);\n            case \"with_flags\":\n                return result.setMatched(withFlagsCheck(info, intValue));\n            case \"without_flags\":\n                return result.setMatched(withoutFlagsCheck(info, intValue));\n            default:\n                throw new UnsupportedOperationException(\"Invalid key \" + key);\n        }\n    }\n\n    @NonNull\n    @Override\n    public CharSequence toLocalizedString(@NonNull Context context) {\n        SpannableStringBuilder sb = new SpannableStringBuilder(\"Apps\");\n        switch (key) {\n            case KEY_ALL:\n                return sb.append(LangUtils.getSeparatorString()).append(\"any\");\n            case \"with_flags\":\n                return sb.append(\" with flags: \").append(flagsToString(\"with_flags\", intValue));\n            case \"without_flags\":\n                return sb.append(\" without flags: \").append(flagsToString(\"without_flags\", intValue));\n            default:\n                throw new UnsupportedOperationException(\"Invalid key \" + key);\n        }\n    }\n\n    /**\n     * Returns true if the given info matches all the flags in 'flag'.\n     * Only checks those flags that are set in 'flag' to minimize expensive calls.\n     */\n    public static boolean withFlagsCheck(IFilterableAppInfo info, int flag) {\n        if ((flag & AppTypeOption.APP_TYPE_SYSTEM) != 0) {\n            if (!info.isSystemApp()) return false;\n        }\n        if ((flag & AppTypeOption.APP_TYPE_USER) != 0) {\n            if (info.isSystemApp()) return false;\n        }\n        if ((flag & AppTypeOption.APP_TYPE_UPDATED_SYSTEM) != 0) {\n            if (!info.isUpdatedSystemApp()) return false;\n        }\n        if ((flag & AppTypeOption.APP_TYPE_PRIVILEGED) != 0) {\n            if (!info.isPrivileged()) return false;\n        }\n        if ((flag & AppTypeOption.APP_TYPE_DATA_ONLY) != 0) {\n            if (!info.dataOnlyApp()) return false;\n        }\n        if ((flag & AppTypeOption.APP_TYPE_STOPPED) != 0) {\n            if (!info.isStopped()) return false;\n        }\n        if ((flag & AppTypeOption.APP_TYPE_LARGE_HEAP) != 0) {\n            if (!info.requestedLargeHeap()) return false;\n        }\n        if ((flag & AppTypeOption.APP_TYPE_DEBUGGABLE) != 0) {\n            if (!info.isDebuggable()) return false;\n        }\n        if ((flag & AppTypeOption.APP_TYPE_TEST_ONLY) != 0) {\n            if (!info.isTestOnly()) return false;\n        }\n        if ((flag & AppTypeOption.APP_TYPE_HAS_CODE) != 0) {\n            if (!info.hasCode()) return false;\n        }\n        if ((flag & AppTypeOption.APP_TYPE_PERSISTENT) != 0) {\n            if (!info.isPersistent()) return false;\n        }\n        if ((flag & AppTypeOption.APP_TYPE_ALLOW_BACKUP) != 0) {\n            if (!info.backupAllowed()) return false;\n        }\n        if ((flag & AppTypeOption.APP_TYPE_INSTALLED_IN_EXTERNAL) != 0) {\n            if (!info.installedInExternalStorage()) return false;\n        }\n        if ((flag & AppTypeOption.APP_TYPE_HTTP_ONLY) != 0) {\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {\n                if (!info.usesHttp()) return false;\n            }\n            // On older versions, this is always true\n        }\n        if ((flag & AppTypeOption.APP_TYPE_BATTERY_OPT_ENABLED) != 0) {\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {\n                if (!info.isBatteryOptEnabled()) return false;\n            }\n            // On older versions, this is always true\n        }\n        if ((flag & AppTypeOption.APP_TYPE_SENSORS) != 0) {\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {\n                if (!info.usesSensors()) return false;\n            }\n            // On older versions, this is always true\n        }\n        if ((flag & AppTypeOption.APP_TYPE_WITH_RULES) != 0) {\n            if (info.getRuleCount() == 0) return false;\n        }\n        if ((flag & AppTypeOption.APP_TYPE_KEYSTORE) != 0) {\n            if (!info.hasKeyStoreItems()) return false;\n        }\n        if ((flag & AppTypeOption.APP_TYPE_SSAID) != 0) {\n            if (TextUtils.isEmpty(info.getSsaid())) return false;\n        }\n        // All requested flags are matched\n        return true;\n    }\n\n    public static boolean withoutFlagsCheck(IFilterableAppInfo info, int flag) {\n        if ((flag & AppTypeOption.APP_TYPE_SYSTEM) != 0) {\n            if (!info.isSystemApp()) return true;\n        }\n        if ((flag & AppTypeOption.APP_TYPE_USER) != 0) {\n            if (info.isSystemApp()) return true;\n        }\n        if ((flag & AppTypeOption.APP_TYPE_UPDATED_SYSTEM) != 0) {\n            if (!info.isUpdatedSystemApp()) return true;\n        }\n        if ((flag & AppTypeOption.APP_TYPE_PRIVILEGED) != 0) {\n            if (!info.isPrivileged()) return true;\n        }\n        if ((flag & AppTypeOption.APP_TYPE_DATA_ONLY) != 0) {\n            if (!info.dataOnlyApp()) return true;\n        }\n        if ((flag & AppTypeOption.APP_TYPE_STOPPED) != 0) {\n            if (!info.isStopped()) return true;\n        }\n        if ((flag & AppTypeOption.APP_TYPE_LARGE_HEAP) != 0) {\n            if (!info.requestedLargeHeap()) return true;\n        }\n        if ((flag & AppTypeOption.APP_TYPE_DEBUGGABLE) != 0) {\n            if (!info.isDebuggable()) return true;\n        }\n        if ((flag & AppTypeOption.APP_TYPE_TEST_ONLY) != 0) {\n            if (!info.isTestOnly()) return true;\n        }\n        if ((flag & AppTypeOption.APP_TYPE_HAS_CODE) != 0) {\n            if (!info.hasCode()) return true;\n        }\n        if ((flag & AppTypeOption.APP_TYPE_PERSISTENT) != 0) {\n            if (!info.isPersistent()) return true;\n        }\n        if ((flag & AppTypeOption.APP_TYPE_ALLOW_BACKUP) != 0) {\n            if (!info.backupAllowed()) return true;\n        }\n        if ((flag & AppTypeOption.APP_TYPE_INSTALLED_IN_EXTERNAL) != 0) {\n            if (!info.installedInExternalStorage()) return true;\n        }\n        if ((flag & AppTypeOption.APP_TYPE_HTTP_ONLY) != 0) {\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {\n                if (!info.usesHttp()) return true;\n            }\n            // On older versions, this is always false\n        }\n        if ((flag & AppTypeOption.APP_TYPE_BATTERY_OPT_ENABLED) != 0) {\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {\n                if (!info.isBatteryOptEnabled()) return true;\n            }\n            // On older versions, this is always false\n        }\n        if ((flag & AppTypeOption.APP_TYPE_SENSORS) != 0) {\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {\n                if (!info.usesSensors()) return true;\n            }\n            // On older versions, this is always false\n        }\n        if ((flag & AppTypeOption.APP_TYPE_WITH_RULES) != 0) {\n            if (info.getRuleCount() == 0) return true;\n        }\n        if ((flag & AppTypeOption.APP_TYPE_KEYSTORE) != 0) {\n            if (!info.hasKeyStoreItems()) return true;\n        }\n        if ((flag & AppTypeOption.APP_TYPE_SSAID) != 0) {\n            if (TextUtils.isEmpty(info.getSsaid())) return true;\n        }\n        // All requested flags are present, so \"not all flags missing\"\n        return false;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/filters/options/BackupOption.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.filters.options;\n\nimport static io.github.muntashirakon.AppManager.backup.BackupFlags.BACKUP_ADB_DATA;\nimport static io.github.muntashirakon.AppManager.backup.BackupFlags.BACKUP_APK_FILES;\nimport static io.github.muntashirakon.AppManager.backup.BackupFlags.BACKUP_CACHE;\nimport static io.github.muntashirakon.AppManager.backup.BackupFlags.BACKUP_EXTRAS;\nimport static io.github.muntashirakon.AppManager.backup.BackupFlags.BACKUP_EXT_DATA;\nimport static io.github.muntashirakon.AppManager.backup.BackupFlags.BACKUP_EXT_OBB_MEDIA;\nimport static io.github.muntashirakon.AppManager.backup.BackupFlags.BACKUP_INT_DATA;\nimport static io.github.muntashirakon.AppManager.backup.BackupFlags.BACKUP_RULES;\n\nimport android.content.Context;\nimport android.text.SpannableStringBuilder;\n\nimport androidx.annotation.NonNull;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport io.github.muntashirakon.AppManager.db.entity.Backup;\nimport io.github.muntashirakon.AppManager.filters.IFilterableAppInfo;\nimport io.github.muntashirakon.AppManager.utils.DateUtils;\n\npublic class BackupOption extends FilterOption {\n    private final Map<String, Integer> mKeysWithType = new LinkedHashMap<String, Integer>() {{\n        put(KEY_ALL, TYPE_NONE);\n        put(\"backups\", TYPE_NONE);\n        put(\"no_backups\", TYPE_NONE);\n        put(\"latest_backup\", TYPE_NONE);\n        put(\"outdated_backup\", TYPE_NONE);\n        put(\"made_before\", TYPE_TIME_MILLIS);\n        put(\"made_after\", TYPE_TIME_MILLIS);\n        put(\"with_flags\", TYPE_INT_FLAGS);\n        put(\"without_flags\", TYPE_INT_FLAGS);\n    }};\n\n    private final Map<Integer, CharSequence> mBackupFlags = new LinkedHashMap<Integer, CharSequence>() {{\n        put(BACKUP_APK_FILES, \"Apk files\");\n        put(BACKUP_INT_DATA, \"Internal data\");\n        put(BACKUP_EXT_DATA, \"External data\");\n        put(BACKUP_ADB_DATA, \"ADB data\");\n        put(BACKUP_EXT_OBB_MEDIA, \"OBB and media\");\n        put(BACKUP_CACHE, \"Cache\");\n        put(BACKUP_EXTRAS, \"Extras\");\n        put(BACKUP_RULES, \"Rules\");\n    }};\n\n    public BackupOption() {\n        super(\"backup\");\n    }\n\n    @NonNull\n    @Override\n    public Map<String, Integer> getKeysWithType() {\n        return mKeysWithType;\n    }\n\n    @Override\n    public Map<Integer, CharSequence> getFlags(@NonNull String key) {\n        if (key.equals(\"with_flags\") || key.equals(\"without_flags\")) {\n            return mBackupFlags;\n        }\n        return super.getFlags(key);\n    }\n\n    @NonNull\n    @Override\n    public TestResult test(@NonNull IFilterableAppInfo info, @NonNull TestResult result) {\n        List<Backup> backups = result.getMatchedBackups() != null\n                ? result.getMatchedBackups()\n                : Arrays.asList(info.getBackups());\n        switch (key) {\n            case KEY_ALL:\n                return result.setMatched(true).setMatchedBackups(backups);\n            case \"backups\": {\n                if (!backups.isEmpty()) {\n                    return result.setMatched(true).setMatchedBackups(backups);\n                } else return result.setMatched(false).setMatchedBackups(Collections.emptyList());\n            }\n            case \"no_backups\": {\n                if (backups.isEmpty()) {\n                    return result.setMatched(true).setMatchedBackups(Collections.emptyList());\n                } else return result.setMatched(false).setMatchedBackups(backups);\n            }\n            case \"latest_backup\": {\n                if (!info.isInstalled()) {\n                    // If the app isn't install, all backups are latest\n                    return result.setMatched(true).setMatchedBackups(backups);\n                }\n                List<Backup> matchedBackups = new ArrayList<>();\n                long versionCode = info.getVersionCode();\n                for (Backup backup : backups) {\n                    if (backup.versionCode >= versionCode) {\n                        matchedBackups.add(backup);\n                    }\n                }\n                return result.setMatched(!matchedBackups.isEmpty())\n                        .setMatchedBackups(matchedBackups);\n            }\n            case \"outdated_backup\": {\n                if (!info.isInstalled()) {\n                    // If the app isn't install, no backups are outdated\n                    return result.setMatched(false);\n                }\n                List<Backup> matchedBackups = new ArrayList<>();\n                long versionCode = info.getVersionCode();\n                for (Backup backup : backups) {\n                    if (backup.versionCode < versionCode) {\n                        matchedBackups.add(backup);\n                    }\n                }\n                return result.setMatched(!matchedBackups.isEmpty())\n                        .setMatchedBackups(matchedBackups);\n            }\n            case \"made_before\": {\n                List<Backup> matchedBackups = new ArrayList<>();\n                for (Backup backup : backups) {\n                    if (backup.backupTime <= longValue) {\n                        matchedBackups.add(backup);\n                    }\n                }\n                return result.setMatched(!matchedBackups.isEmpty())\n                        .setMatchedBackups(matchedBackups);\n            }\n            case \"made_after\": {\n                List<Backup> matchedBackups = new ArrayList<>();\n                for (Backup backup : backups) {\n                    if (backup.backupTime >= longValue) {\n                        matchedBackups.add(backup);\n                    }\n                }\n                return result.setMatched(!matchedBackups.isEmpty())\n                        .setMatchedBackups(matchedBackups);\n            }\n            case \"with_flags\": {\n                List<Backup> matchedBackups = new ArrayList<>();\n                for (Backup backup : backups) {\n                    if ((backup.flags & intValue) == intValue) {\n                        matchedBackups.add(backup);\n                    }\n                }\n                return result.setMatched(!matchedBackups.isEmpty())\n                        .setMatchedBackups(matchedBackups);\n            }\n            case \"without_flags\": {\n                List<Backup> matchedBackups = new ArrayList<>();\n                for (Backup backup : backups) {\n                    if ((backup.flags & intValue) != intValue) {\n                        matchedBackups.add(backup);\n                    }\n                }\n                return result.setMatched(!matchedBackups.isEmpty())\n                        .setMatchedBackups(matchedBackups);\n            }\n            default:\n                throw new UnsupportedOperationException(\"Invalid key \" + key);\n        }\n    }\n\n\n    @NonNull\n    @Override\n    public CharSequence toLocalizedString(@NonNull Context context) {\n        SpannableStringBuilder sb = new SpannableStringBuilder();\n        switch (key) {\n            case KEY_ALL:\n                return \"Apps with or without backups\";\n            case \"backups\":\n                return \"Only the apps with backups\";\n            case \"no_backups\":\n                return \"only the apps without backups\";\n            case \"latest_backup\":\n                return \"Only the apps having the latest backups\";\n            case \"outdated_backup\":\n                return \"Only the apps having some outdated backups\";\n            case \"made_before\":\n                return sb.append(\"Only the apps with backups made before \").append(DateUtils.formatDate(context, longValue));\n            case \"made_after\":\n                return sb.append(\"Only the apps with backups made after \").append(DateUtils.formatDate(context, longValue));\n            case \"with_flags\":\n                return sb.append(\"Only the apps having backups with the flags \").append(flagsToString(\"with_flags\", intValue));\n            case \"without_flags\":\n                return sb.append(\"Only the apps having backups without the flags \").append(flagsToString(\"without_flags\", intValue));\n            default:\n                throw new UnsupportedOperationException(\"Invalid key \" + key);\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/filters/options/BloatwareOption.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.filters.options;\n\nimport static io.github.muntashirakon.AppManager.debloat.DebloatObject.REMOVAL_CAUTION;\nimport static io.github.muntashirakon.AppManager.debloat.DebloatObject.REMOVAL_REPLACE;\nimport static io.github.muntashirakon.AppManager.debloat.DebloatObject.REMOVAL_SAFE;\nimport static io.github.muntashirakon.AppManager.debloat.DebloatObject.REMOVAL_UNSAFE;\nimport static io.github.muntashirakon.AppManager.debloat.DebloaterListOptions.FILTER_LIST_AOSP;\nimport static io.github.muntashirakon.AppManager.debloat.DebloaterListOptions.FILTER_LIST_CARRIER;\nimport static io.github.muntashirakon.AppManager.debloat.DebloaterListOptions.FILTER_LIST_GOOGLE;\nimport static io.github.muntashirakon.AppManager.debloat.DebloaterListOptions.FILTER_LIST_MISC;\nimport static io.github.muntashirakon.AppManager.debloat.DebloaterListOptions.FILTER_LIST_OEM;\n\nimport android.content.Context;\nimport android.text.SpannableStringBuilder;\n\nimport androidx.annotation.NonNull;\n\nimport java.util.LinkedHashMap;\nimport java.util.Map;\n\nimport io.github.muntashirakon.AppManager.debloat.DebloatObject;\nimport io.github.muntashirakon.AppManager.filters.IFilterableAppInfo;\nimport io.github.muntashirakon.AppManager.utils.LangUtils;\n\npublic class BloatwareOption extends FilterOption {\n    private final Map<String, Integer> mKeysWithType = new LinkedHashMap<String, Integer>() {{\n        put(KEY_ALL, TYPE_NONE);\n        put(\"type\", TYPE_INT_FLAGS);\n        put(\"removal\", TYPE_INT_FLAGS);\n    }};\n\n    private final Map<Integer, CharSequence> mBloatwareTypeFlags = new LinkedHashMap<Integer, CharSequence>() {{\n        put(FILTER_LIST_AOSP, \"AOSP\");\n        put(FILTER_LIST_CARRIER, \"Carrier\");\n        put(FILTER_LIST_GOOGLE, \"Google\");\n        put(FILTER_LIST_MISC, \"Misc\");\n        put(FILTER_LIST_OEM, \"OEM\");\n    }};\n\n    private final Map<Integer, CharSequence> mRemovalFlags = new LinkedHashMap<Integer, CharSequence>() {{\n        put(REMOVAL_SAFE, \"Safe\");\n        put(REMOVAL_REPLACE, \"Replace\");\n        put(REMOVAL_CAUTION, \"Caution\");\n        put(REMOVAL_UNSAFE, \"Unsafe\");\n    }};\n\n    public BloatwareOption() {\n        super(\"bloatware\");\n    }\n\n    @NonNull\n    @Override\n    public Map<String, Integer> getKeysWithType() {\n        return mKeysWithType;\n    }\n\n    @Override\n    public Map<Integer, CharSequence> getFlags(@NonNull String key) {\n        if (key.equals(\"type\")) {\n            return mBloatwareTypeFlags;\n        } else if (key.equals(\"removal\")) {\n            return mRemovalFlags;\n        }\n        return super.getFlags(key);\n    }\n\n    @NonNull\n    @Override\n    public TestResult test(@NonNull IFilterableAppInfo info, @NonNull TestResult result) {\n        DebloatObject object = info.getBloatwareInfo();\n        if (object == null) {\n            return result.setMatched(false);\n        }\n        // Must be a bloatware\n        switch (key) {\n            case KEY_ALL:\n                return result.setMatched(true);\n            case \"type\":\n                return result.setMatched((typeToFlag(object.type) & intValue) != 0);\n            case \"removal\":\n                return result.setMatched((object.getRemoval() & intValue) != 0);\n            default:\n                throw new UnsupportedOperationException(\"Invalid key \" + key);\n        }\n    }\n\n    public int typeToFlag(@NonNull String type) {\n        switch (type) {\n            case \"aosp\":\n                return FILTER_LIST_AOSP;\n            case \"carrier\":\n                return FILTER_LIST_CARRIER;\n            case \"google\":\n                return FILTER_LIST_GOOGLE;\n            case \"misc\":\n                return FILTER_LIST_MISC;\n            case \"oem\":\n                return FILTER_LIST_OEM;\n            default:\n                throw new IllegalArgumentException(\"Unknown type: \" + type);\n        }\n    }\n\n    @NonNull\n    @Override\n    public CharSequence toLocalizedString(@NonNull Context context) {\n        SpannableStringBuilder sb = new SpannableStringBuilder(\"Bloatware\");\n        switch (key) {\n            case KEY_ALL:\n                return sb.append(LangUtils.getSeparatorString()).append(\"any\");\n            case \"type\":\n                return sb.append(\" with type: \").append(flagsToString(\"type\", intValue));\n            case \"removal\":\n                return sb.append(\" with removal: \").append(flagsToString(\"removal\", intValue));\n            default:\n                throw new UnsupportedOperationException(\"Invalid key \" + key);\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/filters/options/CacheSizeOption.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.filters.options;\n\nimport android.content.Context;\nimport android.text.SpannableStringBuilder;\nimport android.text.format.Formatter;\n\nimport androidx.annotation.NonNull;\n\nimport java.util.LinkedHashMap;\nimport java.util.Map;\n\nimport io.github.muntashirakon.AppManager.filters.IFilterableAppInfo;\nimport io.github.muntashirakon.AppManager.utils.LangUtils;\n\npublic class CacheSizeOption extends FilterOption {\n    private final Map<String, Integer> mKeysWithType = new LinkedHashMap<String, Integer>() {{\n        put(KEY_ALL, TYPE_NONE);\n        put(\"eq\", TYPE_SIZE_BYTES);\n        put(\"le\", TYPE_SIZE_BYTES);\n        put(\"ge\", TYPE_SIZE_BYTES);\n    }};\n\n    public CacheSizeOption() {\n        super(\"cache_size\");\n    }\n\n    @NonNull\n    @Override\n    public Map<String, Integer> getKeysWithType() {\n        return mKeysWithType;\n    }\n\n    @NonNull\n    @Override\n    public TestResult test(@NonNull IFilterableAppInfo info, @NonNull TestResult result) {\n        switch (key) {\n            case KEY_ALL:\n                return result.setMatched(true);\n            case \"eq\":\n                return result.setMatched(info.getCacheSize() == longValue);\n            case \"le\":\n                return result.setMatched(info.getCacheSize() <= longValue);\n            case \"ge\":\n                return result.setMatched(info.getCacheSize() >= longValue);\n            default:\n                throw new UnsupportedOperationException(\"Invalid key \" + key);\n        }\n    }\n\n    @NonNull\n    @Override\n    public CharSequence toLocalizedString(@NonNull Context context) {\n        SpannableStringBuilder sb = new SpannableStringBuilder(\"Cache size\");\n        switch (key) {\n            case KEY_ALL:\n                return sb.append(LangUtils.getSeparatorString()).append(\"any\");\n            case \"eq\":\n                return sb.append(\" = \").append(Formatter.formatFileSize(context, longValue));\n            case \"le\":\n                return sb.append(\" ≤ \").append(Formatter.formatFileSize(context, longValue));\n            case \"ge\":\n                return sb.append(\" ≥ \").append(Formatter.formatFileSize(context, longValue));\n            default:\n                throw new UnsupportedOperationException(\"Invalid key \" + key);\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/filters/options/CompileSdkOption.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.filters.options;\n\nimport android.content.Context;\nimport android.os.Build;\nimport android.text.SpannableStringBuilder;\n\nimport androidx.annotation.NonNull;\n\nimport java.util.LinkedHashMap;\nimport java.util.Map;\n\nimport io.github.muntashirakon.AppManager.filters.IFilterableAppInfo;\nimport io.github.muntashirakon.AppManager.utils.LangUtils;\n\npublic class CompileSdkOption extends FilterOption {\n    private final Map<String, Integer> mKeysWithType = new LinkedHashMap<String, Integer>() {{\n        put(KEY_ALL, TYPE_NONE);\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {\n            put(\"eq\", TYPE_INT);\n            put(\"le\", TYPE_INT);\n            put(\"ge\", TYPE_INT);\n        }\n    }};\n\n    public CompileSdkOption() {\n        super(\"compile_sdk\");\n    }\n\n    @NonNull\n    @Override\n    public Map<String, Integer> getKeysWithType() {\n        return mKeysWithType;\n    }\n\n    @NonNull\n    @Override\n    public TestResult test(@NonNull IFilterableAppInfo info, @NonNull TestResult result) {\n        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) {\n            return result.setMatched(true);\n        }\n        switch (key) {\n            case KEY_ALL:\n                return result.setMatched(true);\n            case \"eq\":\n                return result.setMatched(info.getCompileSdk() == intValue);\n            case \"le\":\n                return result.setMatched(info.getCompileSdk() <= intValue);\n            case \"ge\":\n                return result.setMatched(info.getCompileSdk() >= intValue);\n            default:\n                throw new UnsupportedOperationException(\"Invalid key \" + key);\n        }\n    }\n\n    @NonNull\n    @Override\n    public CharSequence toLocalizedString(@NonNull Context context) {\n        SpannableStringBuilder sb = new SpannableStringBuilder(\"Compile SDK\");\n        switch (key) {\n            case KEY_ALL:\n                return sb.append(LangUtils.getSeparatorString()).append(\"any\");\n            case \"eq\":\n                return sb.append(\" = \").append(Integer.toString(intValue));\n            case \"le\":\n                return sb.append(\" ≤ \").append(Integer.toString(intValue));\n            case \"ge\":\n                return sb.append(\" ≥ \").append(Integer.toString(intValue));\n            default:\n                throw new UnsupportedOperationException(\"Invalid key \" + key);\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/filters/options/ComponentsOption.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.filters.options;\n\nimport android.content.Context;\nimport android.content.pm.ComponentInfo;\nimport android.text.SpannableStringBuilder;\n\nimport androidx.annotation.NonNull;\n\nimport java.util.LinkedHashMap;\nimport java.util.Map;\nimport java.util.Objects;\n\nimport io.github.muntashirakon.AppManager.filters.IFilterableAppInfo;\nimport io.github.muntashirakon.AppManager.utils.LangUtils;\n\npublic class ComponentsOption extends FilterOption {\n    public static final int COMPONENT_TYPE_ACTIVITY = 1 << 0;\n    public static final int COMPONENT_TYPE_SERVICE = 1 << 1;\n    public static final int COMPONENT_TYPE_RECEIVER = 1 << 2;\n    public static final int COMPONENT_TYPE_PROVIDER = 1 << 3;\n\n    private final Map<String, Integer> mKeysWithType = new LinkedHashMap<String, Integer>() {{\n        put(KEY_ALL, TYPE_NONE);\n        put(\"with_type\", TYPE_INT_FLAGS);\n        put(\"without_type\", TYPE_INT_FLAGS);\n        put(\"eq\", TYPE_STR_SINGLE);\n        put(\"contains\", TYPE_STR_SINGLE);\n        put(\"starts_with\", TYPE_STR_SINGLE);\n        put(\"ends_with\", TYPE_STR_SINGLE);\n        put(\"regex\", TYPE_REGEX);\n        put(\"count_eq\", TYPE_INT);\n        put(\"count_le\", TYPE_INT);\n        put(\"count_ge\", TYPE_INT);\n    }};\n\n    private final Map<Integer, CharSequence> mComponentTypeFlags = new LinkedHashMap<Integer, CharSequence>() {{\n        put(COMPONENT_TYPE_ACTIVITY, \"Activities\");\n        put(COMPONENT_TYPE_SERVICE, \"Services\");\n        put(COMPONENT_TYPE_RECEIVER, \"Receivers\");\n        put(COMPONENT_TYPE_PROVIDER, \"Providers\");\n    }};\n\n    public ComponentsOption() {\n        super(\"components\");\n    }\n\n    @NonNull\n    @Override\n    public Map<String, Integer> getKeysWithType() {\n        return mKeysWithType;\n    }\n\n    @Override\n    public Map<Integer, CharSequence> getFlags(@NonNull String key) {\n        if (key.equals(\"with_type\") || key.equals(\"without_type\")) {\n            return mComponentTypeFlags;\n        }\n        return super.getFlags(key);\n    }\n\n    @NonNull\n    @Override\n    public TestResult test(@NonNull IFilterableAppInfo info, @NonNull TestResult result) {\n        Map<ComponentInfo, Integer> components = result.getMatchedComponents() != null\n                ? result.getMatchedComponents()\n                : info.getAllComponents();\n        switch (key) {\n            case KEY_ALL:\n                return result.setMatched(true).setMatchedComponents(components);\n            case \"with_type\": {\n                Map<ComponentInfo, Integer> filteredComponents = new LinkedHashMap<>();\n                for (ComponentInfo component : components.keySet()) {\n                    int type = Objects.requireNonNull(components.get(component));\n                    if ((intValue & type) != 0) {\n                        filteredComponents.put(component, type);\n                    }\n                }\n                return result.setMatched(!filteredComponents.isEmpty())\n                        .setMatchedComponents(filteredComponents);\n            }\n            case \"without_type\": {\n                Map<ComponentInfo, Integer> filteredComponents = new LinkedHashMap<>();\n                for (ComponentInfo component : components.keySet()) {\n                    int type = Objects.requireNonNull(components.get(component));\n                    if ((intValue & type) == 0) {\n                        filteredComponents.put(component, type);\n                    }\n                }\n                return result.setMatched(filteredComponents.size() == components.size())\n                        .setMatchedComponents(filteredComponents);\n            }\n            case \"eq\": {\n                Map<ComponentInfo, Integer> filteredComponents = new LinkedHashMap<>();\n                for (ComponentInfo component : components.keySet()) {\n                    if (component.name.equals(value)) {\n                        filteredComponents.put(component, components.get(component));\n                    }\n                }\n                return result.setMatched(!filteredComponents.isEmpty())\n                        .setMatchedComponents(filteredComponents);\n            }\n            case \"contains\": {\n                Objects.requireNonNull(value);\n                Map<ComponentInfo, Integer> filteredComponents = new LinkedHashMap<>();\n                for (ComponentInfo component : components.keySet()) {\n                    if (component.name.contains(value)) {\n                        filteredComponents.put(component, components.get(component));\n                    }\n                }\n                return result.setMatched(!filteredComponents.isEmpty())\n                        .setMatchedComponents(filteredComponents);\n            }\n            case \"starts_with\": {\n                Objects.requireNonNull(value);\n                Map<ComponentInfo, Integer> filteredComponents = new LinkedHashMap<>();\n                for (ComponentInfo component : components.keySet()) {\n                    if (component.name.startsWith(value)) {\n                        filteredComponents.put(component, components.get(component));\n                    }\n                }\n                return result.setMatched(!filteredComponents.isEmpty())\n                        .setMatchedComponents(filteredComponents);\n            }\n            case \"ends_with\": {\n                Objects.requireNonNull(value);\n                Map<ComponentInfo, Integer> filteredComponents = new LinkedHashMap<>();\n                for (ComponentInfo component : components.keySet()) {\n                    if (component.name.endsWith(value)) {\n                        filteredComponents.put(component, components.get(component));\n                    }\n                }\n                return result.setMatched(!filteredComponents.isEmpty())\n                        .setMatchedComponents(filteredComponents);\n            }\n            case \"regex\": {\n                Objects.requireNonNull(value);\n                Map<ComponentInfo, Integer> filteredComponents = new LinkedHashMap<>();\n                for (ComponentInfo component : components.keySet()) {\n                    if (regexValue.matcher(component.name).matches()) {\n                        filteredComponents.put(component, components.get(component));\n                    }\n                }\n                return result.setMatched(!filteredComponents.isEmpty())\n                        .setMatchedComponents(filteredComponents);\n            }\n            case \"count_eq\": {\n                return result.setMatched(components.size() == intValue)\n                        .setMatchedComponents(components);\n            }\n            case \"count_le\": {\n                return result.setMatched(components.size() <= intValue)\n                        .setMatchedComponents(components);\n            }\n            case \"count_ge\": {\n                return result.setMatched(components.size() >= intValue)\n                        .setMatchedComponents(components);\n            }\n            default:\n                throw new UnsupportedOperationException(\"Invalid key \" + key);\n        }\n    }\n\n    @NonNull\n    @Override\n    public CharSequence toLocalizedString(@NonNull Context context) {\n        SpannableStringBuilder sb = new SpannableStringBuilder(\"App components\");\n        switch (key) {\n            case KEY_ALL:\n                return sb.append(LangUtils.getSeparatorString()).append(\"any\");\n            case \"with_type\":\n                return sb.append(\" with types \").append(flagsToString(\"with_type\", intValue));\n            case \"without_type\":\n                return sb.append(\" without types \").append(flagsToString(\"without_type\", intValue));\n            case \"eq\":\n                return sb.append(\" = '\").append(value).append(\"'\");\n            case \"contains\":\n                return sb.append(\" contains '\").append(value).append(\"'\");\n            case \"starts_with\":\n                return sb.append(\" starts with '\").append(value).append(\"'\");\n            case \"ends_with\":\n                return sb.append(\" ends with '\").append(value).append(\"'\");\n            case \"regex\":\n                return sb.append(\" matches '\").append(value).append(\"'\");\n            case \"count_eq\":\n                return sb.append(\" count = \").append(Integer.toString(intValue));\n            case \"count_le\":\n                return sb.append(\" count ≤ \").append(Integer.toString(intValue));\n            case \"count_ge\":\n                return sb.append(\" count ≥ \").append(Integer.toString(intValue));\n            default:\n                throw new UnsupportedOperationException(\"Invalid key \" + key);\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/filters/options/DataSizeOption.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.filters.options;\n\nimport android.content.Context;\nimport android.text.SpannableStringBuilder;\nimport android.text.format.Formatter;\n\nimport androidx.annotation.NonNull;\n\nimport java.util.LinkedHashMap;\nimport java.util.Map;\n\nimport io.github.muntashirakon.AppManager.filters.IFilterableAppInfo;\nimport io.github.muntashirakon.AppManager.utils.LangUtils;\n\npublic class DataSizeOption extends FilterOption {\n    private final Map<String, Integer> mKeysWithType = new LinkedHashMap<String, Integer>() {{\n        put(KEY_ALL, TYPE_NONE);\n        put(\"eq\", TYPE_SIZE_BYTES);\n        put(\"le\", TYPE_SIZE_BYTES);\n        put(\"ge\", TYPE_SIZE_BYTES);\n    }};\n\n    public DataSizeOption() {\n        super(\"data_size\");\n    }\n\n    @NonNull\n    @Override\n    public Map<String, Integer> getKeysWithType() {\n        return mKeysWithType;\n    }\n\n    @NonNull\n    @Override\n    public TestResult test(@NonNull IFilterableAppInfo info, @NonNull TestResult result) {\n        switch (key) {\n            case KEY_ALL:\n                return result.setMatched(true);\n            case \"eq\":\n                return result.setMatched(info.getDataSize() == longValue);\n            case \"le\":\n                return result.setMatched(info.getDataSize() <= longValue);\n            case \"ge\":\n                return result.setMatched(info.getDataSize() >= longValue);\n            default:\n                throw new UnsupportedOperationException(\"Invalid key \" + key);\n        }\n    }\n\n    @NonNull\n    @Override\n    public CharSequence toLocalizedString(@NonNull Context context) {\n        SpannableStringBuilder sb = new SpannableStringBuilder(\"Data size\");\n        switch (key) {\n            case KEY_ALL:\n                return sb.append(LangUtils.getSeparatorString()).append(\"any\");\n            case \"eq\":\n                return sb.append(\" = \").append(Formatter.formatFileSize(context, longValue));\n            case \"le\":\n                return sb.append(\" ≤ \").append(Formatter.formatFileSize(context, longValue));\n            case \"ge\":\n                return sb.append(\" ≥ \").append(Formatter.formatFileSize(context, longValue));\n            default:\n                throw new UnsupportedOperationException(\"Invalid key \" + key);\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/filters/options/DataUsageOption.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.filters.options;\n\nimport android.content.Context;\nimport android.text.SpannableStringBuilder;\nimport android.text.format.Formatter;\n\nimport androidx.annotation.NonNull;\n\nimport java.util.LinkedHashMap;\nimport java.util.Map;\n\nimport io.github.muntashirakon.AppManager.filters.IFilterableAppInfo;\nimport io.github.muntashirakon.AppManager.utils.LangUtils;\n\npublic class DataUsageOption extends FilterOption {\n    private final Map<String, Integer> mKeysWithType = new LinkedHashMap<String, Integer>() {{\n        put(KEY_ALL, TYPE_NONE);\n        put(\"eq\", TYPE_SIZE_BYTES);\n        put(\"le\", TYPE_SIZE_BYTES);\n        put(\"ge\", TYPE_SIZE_BYTES);\n        // TODO: 11/19/24 Add more curated options, e.g., mobile and wifi\n    }};\n\n    public DataUsageOption() {\n        super(\"data_usage\");\n    }\n\n    @NonNull\n    @Override\n    public Map<String, Integer> getKeysWithType() {\n        return mKeysWithType;\n    }\n\n    @NonNull\n    @Override\n    public TestResult test(@NonNull IFilterableAppInfo info, @NonNull TestResult result) {\n        switch (key) {\n            case KEY_ALL:\n                return result.setMatched(true);\n            case \"eq\":\n                return result.setMatched(info.getDataUsage().getTotal() == longValue);\n            case \"le\":\n                return result.setMatched(info.getDataUsage().getTotal() <= longValue);\n            case \"ge\":\n                return result.setMatched(info.getDataUsage().getTotal() >= longValue);\n            default:\n                throw new UnsupportedOperationException(\"Invalid key \" + key);\n        }\n    }\n\n    @NonNull\n    @Override\n    public CharSequence toLocalizedString(@NonNull Context context) {\n        SpannableStringBuilder sb = new SpannableStringBuilder(\"Data usage\");\n        switch (key) {\n            case KEY_ALL:\n                return sb.append(LangUtils.getSeparatorString()).append(\"any\");\n            case \"eq\":\n                return sb.append(\" = \").append(Formatter.formatFileSize(context, longValue));\n            case \"le\":\n                return sb.append(\" ≤ \").append(Formatter.formatFileSize(context, longValue));\n            case \"ge\":\n                return sb.append(\" ≥ \").append(Formatter.formatFileSize(context, longValue));\n            default:\n                throw new UnsupportedOperationException(\"Invalid key \" + key);\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/filters/options/FilterOption.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.filters.options;\n\nimport android.content.pm.ComponentInfo;\nimport android.os.Parcel;\nimport android.os.Parcelable;\n\nimport androidx.annotation.CallSuper;\nimport androidx.annotation.IntDef;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport org.json.JSONException;\nimport org.json.JSONObject;\n\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.regex.Pattern;\n\nimport io.github.muntashirakon.AppManager.db.entity.Backup;\nimport io.github.muntashirakon.AppManager.filters.IFilterableAppInfo;\nimport io.github.muntashirakon.AppManager.utils.JSONUtils;\nimport io.github.muntashirakon.util.LocalizedString;\n\npublic abstract class FilterOption implements LocalizedString, Parcelable {\n    public static final int TYPE_NONE = 0;\n    public static final int TYPE_STR_SINGLE = 1;\n    public static final int TYPE_STR_MULTIPLE = 2;\n    public static final int TYPE_INT = 3;\n    public static final int TYPE_LONG = 4;\n    public static final int TYPE_REGEX = 5;\n    public static final int TYPE_INT_FLAGS = 6;\n    public static final int TYPE_TIME_MILLIS = 7;\n    public static final int TYPE_DURATION_MILLIS = 8;\n    public static final int TYPE_SIZE_BYTES = 9;\n\n    @IntDef(value = {\n            TYPE_NONE,\n            TYPE_STR_SINGLE,\n            TYPE_STR_MULTIPLE,\n            TYPE_INT,\n            TYPE_LONG,\n            TYPE_REGEX,\n            TYPE_INT_FLAGS,\n            TYPE_TIME_MILLIS,\n            TYPE_DURATION_MILLIS,\n            TYPE_SIZE_BYTES,\n    })\n    @Retention(RetentionPolicy.SOURCE)\n    public @interface KeyType {\n    }\n\n    public static final String KEY_ALL = \"all\";\n\n    /**\n     * Option type (e.g., target_sdk, last_update)\n     */\n    public final String type;\n\n    public int id;\n    /**\n     * A key under the option (e.g., for target_sdk: eq, le, ge, all; for last_update: before, after, all)\n     */\n    @NonNull\n    protected String key;\n    /**\n     * Type of the key (e.g., for target_sdk: eq, le, ge => int, all => none, for last_update: before, after => date, all => none)\n     */\n    @KeyType\n    protected int keyType;\n    /**\n     * Value for the key if keyType is anything but TYPE_NONE\n     */\n    @Nullable\n    protected String value;\n\n    protected int intValue;\n    protected long longValue;\n    protected Pattern regexValue;\n    protected String[] stringValues;\n\n    public FilterOption(String type) {\n        this.type = type;\n        this.key = KEY_ALL;\n        this.keyType = TYPE_NONE;\n    }\n\n    public String getFullId() {\n        return type + \"_\" + id;\n    }\n\n    @NonNull\n    public String getKey() {\n        return key;\n    }\n\n    @KeyType\n    public int getKeyType() {\n        return keyType;\n    }\n\n    @Nullable\n    public String getValue() {\n        return value;\n    }\n\n    @CallSuper\n    public void setKeyValue(@NonNull String key, @Nullable String value) {\n        Integer keyType = getKeysWithType().get(key);\n        if (keyType == null) {\n            throw new IllegalArgumentException(\"Invalid key: \" + key + \" for type: \" + type);\n        }\n        this.key = key;\n        this.keyType = keyType;\n        if (keyType != TYPE_NONE) {\n            this.value = Objects.requireNonNull(value);\n            switch (keyType) {\n                case TYPE_INT:\n                case TYPE_INT_FLAGS:\n                    this.intValue = Integer.parseInt(value);\n                    break;\n                case TYPE_LONG:\n                case TYPE_TIME_MILLIS:\n                case TYPE_DURATION_MILLIS:\n                case TYPE_SIZE_BYTES:\n                    this.longValue = Long.parseLong(value);\n                    break;\n                case TYPE_REGEX:\n                    this.regexValue = Pattern.compile(Pattern.quote(value));\n                case TYPE_STR_MULTIPLE:\n                    this.stringValues = value.split(\"\\\\n\");\n            }\n        }\n    }\n\n    @NonNull\n    public abstract Map<String, Integer> getKeysWithType();\n\n    public Map<Integer, CharSequence> getFlags(String key) {\n        throw new UnsupportedOperationException(\"Flags must be returned by the corresponding subclasses. key: \" + key);\n    }\n\n    @NonNull\n    public abstract TestResult test(@NonNull IFilterableAppInfo info, @NonNull TestResult result);\n\n    @NonNull\n    @Override\n    public String toString() {\n        return \"FilterOption{\" +\n                \"type='\" + type + '\\'' +\n                \", id=\" + id +\n                \", key='\" + key + '\\'' +\n                \", keyType=\" + keyType +\n                \", value='\" + value + '\\'' +\n                '}';\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        dest.writeString(type);\n        dest.writeInt(id);\n        dest.writeString(key);\n        dest.writeString(value);\n    }\n\n    @Override\n    public int describeContents() {\n        return 0;\n    }\n\n    public static final Creator<FilterOption> CREATOR = new Creator<FilterOption>() {\n        @Override\n        @NonNull\n        public FilterOption createFromParcel(@NonNull Parcel in) {\n            String type = Objects.requireNonNull(in.readString());\n            FilterOption filterOption = FilterOptions.create(type);\n            filterOption.id = in.readInt();\n            String key = Objects.requireNonNull(in.readString());\n            String value = in.readString();\n            filterOption.setKeyValue(key, value);\n            return filterOption;\n        }\n\n        @Override\n        @NonNull\n        public FilterOption[] newArray(int size) {\n            return new FilterOption[size];\n        }\n    };\n\n    @Nullable\n    public JSONObject toJson() throws JSONException {\n        JSONObject object = new JSONObject();\n        object.put(\"type\", type);\n        object.put(\"id\", id);\n        object.put(\"key\", key);\n        object.put(\"key_type\", keyType);\n        if (value != null) {\n            object.put(\"value\", value);\n        }\n        return object;\n    }\n\n    @NonNull\n    public static FilterOption fromJson(@NonNull JSONObject object) throws JSONException {\n        FilterOption option = FilterOptions.create(object.getString(\"type\"));\n        option.id = object.getInt(\"id\");\n        // int keyType = object.getInt(\"key_type\");\n        String key = object.getString(\"key\");\n        String value = JSONUtils.optString(object, \"value\");\n        option.setKeyValue(key, value);\n        return option;\n    }\n\n    protected String flagsToString(String key, int flags) {\n        List<CharSequence> result = new ArrayList<>();\n        for (Map.Entry<Integer, CharSequence> entry : getFlags(key).entrySet()) {\n            int flag = entry.getKey();\n            if ((flags & flag) != 0) {\n                result.add(entry.getValue());\n            }\n        }\n        return String.join(\", \", result);\n    }\n\n\n    public static class TestResult {\n        private boolean mMatched = true;\n        private List<Backup> mMatchedBackups;\n        private Map<ComponentInfo, Integer> mMatchedComponents;\n        private Map<ComponentInfo, Integer> mMatchedTrackers;\n        private List<String> mMatchedPermissions;\n        private List<String> mMatchedSubjectLines;\n\n        public TestResult setMatched(boolean matched) {\n            mMatched = matched;\n            return this;\n        }\n\n        public boolean isMatched() {\n            return mMatched;\n        }\n\n        public TestResult setMatchedBackups(List<Backup> matchedBackups) {\n            mMatchedBackups = matchedBackups;\n            return this;\n        }\n\n        @Nullable\n        public List<Backup> getMatchedBackups() {\n            return mMatchedBackups;\n        }\n\n        public TestResult setMatchedComponents(Map<ComponentInfo, Integer> matchedComponents) {\n            mMatchedComponents = matchedComponents;\n            return this;\n        }\n\n        @Nullable\n        public Map<ComponentInfo, Integer> getMatchedComponents() {\n            return mMatchedComponents;\n        }\n\n        public TestResult setMatchedTrackers(Map<ComponentInfo, Integer> matchedTrackers) {\n            mMatchedTrackers = matchedTrackers;\n            return this;\n        }\n\n        @Nullable\n        public Map<ComponentInfo, Integer> getMatchedTrackers() {\n            return mMatchedTrackers;\n        }\n\n        public TestResult setMatchedPermissions(List<String> matchedPermissions) {\n            mMatchedPermissions = matchedPermissions;\n            return this;\n        }\n\n        @Nullable\n        public List<String> getMatchedPermissions() {\n            return mMatchedPermissions;\n        }\n\n        public TestResult setMatchedSubjectLines(List<String> matchedSubjectLines) {\n            mMatchedSubjectLines = matchedSubjectLines;\n            return this;\n        }\n\n        @Nullable\n        public List<String> getMatchedSubjectLines() {\n            return mMatchedSubjectLines;\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/filters/options/FilterOptions.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.filters.options;\n\nimport androidx.annotation.NonNull;\n\npublic final class FilterOptions {\n    @NonNull\n    public static FilterOption create(@NonNull String filterName) {\n        switch (filterName) {\n            case \"apk_size\": return new ApkSizeOption();\n            case \"app_label\": return new AppLabelOption();\n            case \"app_type\": return new AppTypeOption();\n            case \"backup\": return new BackupOption();\n            case \"bloatware\": return new BloatwareOption();\n            case \"cache_size\": return new CacheSizeOption();\n            case \"compile_sdk\": return new CompileSdkOption();\n            case \"components\": return new ComponentsOption();\n            case \"data_size\": return new DataSizeOption();\n            case \"data_usage\": return new DataUsageOption();\n            case \"freeze_unfreeze\": return new FreezeOption();\n            case \"installed\": return new InstalledOption();\n            case \"installer\": return new InstallerOption();\n            case \"last_update\": return new LastUpdateOption();\n            case \"min_sdk\": return new MinSdkOption();\n            case \"permissions\": return new PermissionsOption();\n            case \"pkg_name\": return new PackageNameOption();\n            case \"running_apps\": return new RunningAppsOption();\n            case \"screen_time\": return new ScreenTimeOption();\n            case \"signature\": return new SignatureOption();\n            case \"target_sdk\": return new TargetSdkOption();\n            case \"times_opened\": return new TimesOpenedOption();\n            case \"total_size\": return new TotalSizeOption();\n            case \"trackers\": return new TrackersOption();\n            case \"uid\": return new UidOption();\n            case \"version_name\": return new VersionNameOption();\n        }\n        throw new IllegalArgumentException(\"Invalid filter: \" + filterName);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/filters/options/FreezeOption.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.filters.options;\n\nimport static io.github.muntashirakon.AppManager.utils.LangUtils.getSeparatorString;\n\nimport android.content.Context;\nimport android.os.Build;\n\nimport androidx.annotation.NonNull;\n\nimport java.util.LinkedHashMap;\nimport java.util.Map;\n\nimport io.github.muntashirakon.AppManager.filters.IFilterableAppInfo;\n\npublic class FreezeOption extends FilterOption {\n    public static final int FREEZE_TYPE_DISABLED = 1 << 0;\n    public static final int FREEZE_TYPE_HIDDEN = 1 << 1;\n    public static final int FREEZE_TYPE_SUSPENDED = 1 << 2;\n\n    private final Map<String, Integer> mKeysWithType = new LinkedHashMap<String, Integer>() {{\n        put(KEY_ALL, TYPE_NONE);\n        put(\"frozen\", TYPE_NONE);\n        put(\"unfrozen\", TYPE_NONE);\n        put(\"with_flags\", TYPE_INT_FLAGS);\n        put(\"without_flags\", TYPE_INT_FLAGS);\n    }};\n\n    private final Map<Integer, CharSequence> mFrozenFlags = new LinkedHashMap<Integer, CharSequence>() {{\n        put(FREEZE_TYPE_DISABLED, \"Disabled\");\n        put(FREEZE_TYPE_HIDDEN, \"Hidden\");\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {\n            put(FREEZE_TYPE_SUSPENDED, \"Suspended\");\n        }\n    }};\n\n    public FreezeOption() {\n        super(\"freeze_unfreeze\");\n    }\n\n    @NonNull\n    @Override\n    public Map<String, Integer> getKeysWithType() {\n        return mKeysWithType;\n    }\n\n    @Override\n    public Map<Integer, CharSequence> getFlags(@NonNull String key) {\n        if (key.equals(\"with_flags\") || key.equals(\"without_flags\")) {\n            return mFrozenFlags;\n        }\n        return super.getFlags(key);\n    }\n\n    @NonNull\n    @Override\n    public TestResult test(@NonNull IFilterableAppInfo info, @NonNull TestResult result) {\n        int freezeFlags = info.getFreezeFlags();\n        switch (key) {\n            case KEY_ALL:\n                return result.setMatched(true);\n            case \"frozen\":\n                return result.setMatched(freezeFlags != 0);\n            case \"unfrozen\":\n                return result.setMatched(freezeFlags == 0);\n            case \"with_flags\":\n                return result.setMatched((freezeFlags & intValue) == intValue);\n            case \"without_flags\":\n                return result.setMatched((freezeFlags & intValue) != intValue);\n            default:\n                throw new UnsupportedOperationException(\"Invalid key \" + key);\n        }\n    }\n\n    @NonNull\n    @Override\n    public CharSequence toLocalizedString(@NonNull Context context) {\n        switch (key) {\n            case KEY_ALL:\n                return \"Frozen\" + getSeparatorString() + \" any\";\n            case \"frozen\":\n                return \"Frozen apps only\";\n            case \"unfrozen\":\n                return \"Unfrozen apps only\";\n            case \"with_flags\":\n                return \"Frozen apps with types \" + flagsToString(\"with_flags\", intValue);\n            case \"without_flags\":\n                return \"Frozen apps without types \" + flagsToString(\"without_flags\", intValue);\n            default:\n                throw new UnsupportedOperationException(\"Invalid key \" + key);\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/filters/options/InstalledOption.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.filters.options;\n\nimport android.content.Context;\nimport android.text.SpannableStringBuilder;\n\nimport androidx.annotation.NonNull;\n\nimport java.util.LinkedHashMap;\nimport java.util.Map;\n\nimport io.github.muntashirakon.AppManager.filters.IFilterableAppInfo;\nimport io.github.muntashirakon.AppManager.utils.DateUtils;\nimport io.github.muntashirakon.AppManager.utils.LangUtils;\n\npublic class InstalledOption extends FilterOption {\n    private final Map<String, Integer> mKeysWithType = new LinkedHashMap<String, Integer>() {{\n        put(KEY_ALL, TYPE_NONE);\n        put(\"installed\", TYPE_NONE);\n        put(\"uninstalled\", TYPE_NONE);\n        put(\"installed_before\", TYPE_TIME_MILLIS);\n        put(\"installed_after\", TYPE_TIME_MILLIS);\n    }};\n\n    public InstalledOption() {\n        super(\"installed\");\n    }\n\n    @NonNull\n    @Override\n    public Map<String, Integer> getKeysWithType() {\n        return mKeysWithType;\n    }\n\n    @NonNull\n    @Override\n    public TestResult test(@NonNull IFilterableAppInfo info, @NonNull TestResult result) {\n        boolean installed = info.isInstalled();\n        switch (key) {\n            case KEY_ALL:\n                return result.setMatched(true);\n            case \"installed\":\n                return result.setMatched(installed);\n            case \"uninstalled\":\n                return result.setMatched(!installed);\n            case \"installed_before\":\n                return result.setMatched(installed && info.getFirstInstallTime() <= longValue);\n            case \"installed_after\":\n                return result.setMatched(installed && info.getFirstInstallTime() >= longValue);\n            default:\n                throw new UnsupportedOperationException(\"Invalid key \" + key);\n        }\n    }\n\n    @NonNull\n    @Override\n    public CharSequence toLocalizedString(@NonNull Context context) {\n        SpannableStringBuilder sb = new SpannableStringBuilder(\"Installed\");\n        switch (key) {\n            case KEY_ALL:\n                return sb.append(LangUtils.getSeparatorString()).append(\"any\");\n            case \"installed\":\n                return \"Installed apps\";\n            case \"uninstalled\":\n                return \"Uninstalled apps\";\n            case \"installed_before\":\n                return sb.append(\" before \").append(DateUtils.formatDateTime(context, longValue));\n            case \"installed_after\":\n                return sb.append(\" after \").append(DateUtils.formatDateTime(context, longValue));\n            default:\n                throw new UnsupportedOperationException(\"Invalid key \" + key);\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/filters/options/InstallerOption.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.filters.options;\n\nimport android.content.Context;\nimport android.text.SpannableStringBuilder;\n\nimport androidx.annotation.NonNull;\n\nimport java.util.LinkedHashMap;\nimport java.util.LinkedHashSet;\nimport java.util.Map;\nimport java.util.Set;\n\nimport io.github.muntashirakon.AppManager.compat.InstallSourceInfoCompat;\nimport io.github.muntashirakon.AppManager.filters.IFilterableAppInfo;\nimport io.github.muntashirakon.AppManager.utils.LangUtils;\n\npublic class InstallerOption extends FilterOption {\n    private final Map<String, Integer> mKeysWithType = new LinkedHashMap<String, Integer>() {{\n        put(KEY_ALL, TYPE_NONE);\n        put(\"installer\", TYPE_STR_SINGLE);\n        put(\"installer_any\", TYPE_STR_MULTIPLE);\n        put(\"installer_none\", TYPE_STR_MULTIPLE);\n        put(\"regex\", TYPE_REGEX);\n    }};\n\n    public InstallerOption() {\n        super(\"installer\");\n    }\n\n    @NonNull\n    @Override\n    public Map<String, Integer> getKeysWithType() {\n        return mKeysWithType;\n    }\n\n    @NonNull\n    @Override\n    public TestResult test(@NonNull IFilterableAppInfo info, @NonNull TestResult result) {\n        InstallSourceInfoCompat installSourceInfo = info.getInstallerInfo();\n        if (installSourceInfo == null) {\n            return result.setMatched(key.equals(KEY_ALL));\n        }\n        // There's at least one installer at this point\n        Set<String> installers = getInstallers(installSourceInfo);\n        switch (key) {\n            case KEY_ALL:\n                return result.setMatched(false);\n            case \"installer\":\n                return result.setMatched(installers.contains(value));\n            case \"installer_any\":\n                for (String installer: stringValues) {\n                    if (installers.contains(installer)) {\n                        return result.setMatched(true);\n                    }\n                }\n                return result.setMatched(false);\n            case \"installer_none\":\n                for (String installer: stringValues) {\n                    if (installers.contains(installer)) {\n                        return result.setMatched(false);\n                    }\n                }\n                return result.setMatched(true);\n            case \"regex\":\n                for (String installer : installers) {\n                    if (regexValue.matcher(installer).matches()) {\n                        return result.setMatched(true);\n                    }\n                }\n                return result.setMatched(false);\n            default:\n                throw new UnsupportedOperationException(\"Invalid key \" + key);\n        }\n    }\n\n    @NonNull\n    private static Set<String> getInstallers(@NonNull InstallSourceInfoCompat installSourceInfo) {\n        Set<String> installers = new LinkedHashSet<>();\n        if (installSourceInfo.getInstallingPackageName() != null) {\n            installers.add(installSourceInfo.getInstallingPackageName());\n        }\n        if (installSourceInfo.getInitiatingPackageName() != null) {\n            installers.add(installSourceInfo.getInitiatingPackageName());\n        }\n        if (installSourceInfo.getOriginatingPackageName() != null) {\n            installers.add(installSourceInfo.getOriginatingPackageName());\n        }\n        return installers;\n    }\n\n    @NonNull\n    @Override\n    public CharSequence toLocalizedString(@NonNull Context context) {\n        SpannableStringBuilder sb = new SpannableStringBuilder(\"Only the apps with installer\");\n        switch (key) {\n            case KEY_ALL:\n                return sb.append(LangUtils.getSeparatorString()).append(\"any\");\n            case \"installer\":\n                return sb.append(\" \").append(value);\n            case \"installer_any\":\n                return sb.append(\" matching any of \").append(String.join(\", \", stringValues));\n            case \"installer_none\":\n                return sb.append(\" matching none of \").append(String.join(\", \", stringValues));\n            case \"regex\":\n                return sb.append(\" that matches '\").append(value).append(\"'\");\n            default:\n                throw new UnsupportedOperationException(\"Invalid key \" + key);\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/filters/options/LastUpdateOption.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.filters.options;\n\nimport android.content.Context;\nimport android.text.SpannableStringBuilder;\n\nimport androidx.annotation.NonNull;\n\nimport java.util.LinkedHashMap;\nimport java.util.Map;\n\nimport io.github.muntashirakon.AppManager.filters.IFilterableAppInfo;\nimport io.github.muntashirakon.AppManager.utils.DateUtils;\nimport io.github.muntashirakon.AppManager.utils.LangUtils;\n\npublic class LastUpdateOption extends FilterOption {\n    private final Map<String, Integer> mKeysWithType = new LinkedHashMap<String, Integer>() {{\n        put(KEY_ALL, TYPE_NONE);\n        put(\"before\", TYPE_TIME_MILLIS);\n        put(\"after\", TYPE_TIME_MILLIS);\n    }};\n\n    public LastUpdateOption() {\n        super(\"last_update\");\n    }\n\n    @NonNull\n    @Override\n    public Map<String, Integer> getKeysWithType() {\n        return mKeysWithType;\n    }\n\n    @NonNull\n    @Override\n    public TestResult test(@NonNull IFilterableAppInfo info, @NonNull TestResult result) {\n        boolean installed = info.isInstalled();\n        switch (key) {\n            case KEY_ALL:\n                return result.setMatched(true);\n            case \"before\":\n                return result.setMatched(installed && info.getLastUpdateTime() <= longValue);\n            case \"after\":\n                return result.setMatched(installed && info.getLastUpdateTime() >= longValue);\n            default:\n                throw new UnsupportedOperationException(\"Invalid key \" + key);\n        }\n    }\n\n    @NonNull\n    @Override\n    public CharSequence toLocalizedString(@NonNull Context context) {\n        SpannableStringBuilder sb = new SpannableStringBuilder(\"Last update\");\n        switch (key) {\n            case KEY_ALL:\n                return sb.append(LangUtils.getSeparatorString()).append(\"any\");\n            case \"before\":\n                return sb.append(\" before \").append(DateUtils.formatDateTime(context, longValue));\n            case \"after\":\n                return sb.append(\" after \").append(DateUtils.formatDateTime(context, longValue));\n            default:\n                throw new UnsupportedOperationException(\"Invalid key \" + key);\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/filters/options/MinSdkOption.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.filters.options;\n\nimport android.content.Context;\nimport android.os.Build;\nimport android.text.SpannableStringBuilder;\n\nimport androidx.annotation.NonNull;\n\nimport java.util.LinkedHashMap;\nimport java.util.Map;\n\nimport io.github.muntashirakon.AppManager.filters.IFilterableAppInfo;\nimport io.github.muntashirakon.AppManager.utils.LangUtils;\n\npublic class MinSdkOption extends FilterOption {\n    private final Map<String, Integer> mKeysWithType = new LinkedHashMap<String, Integer>() {{\n        put(KEY_ALL, TYPE_NONE);\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {\n            put(\"eq\", TYPE_INT);\n            put(\"le\", TYPE_INT);\n            put(\"ge\", TYPE_INT);\n        }\n    }};\n\n    public MinSdkOption() {\n        super(\"min_sdk\");\n    }\n\n    @NonNull\n    @Override\n    public Map<String, Integer> getKeysWithType() {\n        return mKeysWithType;\n    }\n\n    @NonNull\n    @Override\n    public TestResult test(@NonNull IFilterableAppInfo info, @NonNull TestResult result) {\n        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {\n            return result.setMatched(true);\n        }\n        switch (key) {\n            case KEY_ALL:\n                return result.setMatched(true);\n            case \"eq\":\n                return result.setMatched(info.getMinSdk() == intValue);\n            case \"le\":\n                return result.setMatched(info.getMinSdk() <= intValue);\n            case \"ge\":\n                return result.setMatched(info.getMinSdk() >= intValue);\n            default:\n                throw new UnsupportedOperationException(\"Invalid key \" + key);\n        }\n    }\n\n    @NonNull\n    @Override\n    public CharSequence toLocalizedString(@NonNull Context context) {\n        SpannableStringBuilder sb = new SpannableStringBuilder(\"Minimum SDK\");\n        switch (key) {\n            case KEY_ALL:\n                return sb.append(LangUtils.getSeparatorString()).append(\"any\");\n            case \"eq\":\n                return sb.append(\" = \").append(Integer.toString(intValue));\n            case \"le\":\n                return sb.append(\" ≤ \").append(Integer.toString(intValue));\n            case \"ge\":\n                return sb.append(\" ≥ \").append(Integer.toString(intValue));\n            default:\n                throw new UnsupportedOperationException(\"Invalid key \" + key);\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/filters/options/PackageNameOption.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.filters.options;\n\nimport android.content.Context;\nimport android.text.SpannableStringBuilder;\n\nimport androidx.annotation.NonNull;\n\nimport java.util.LinkedHashMap;\nimport java.util.Map;\nimport java.util.Objects;\n\nimport io.github.muntashirakon.AppManager.filters.IFilterableAppInfo;\nimport io.github.muntashirakon.AppManager.utils.LangUtils;\n\npublic class PackageNameOption extends FilterOption {\n    private final Map<String, Integer> mKeysWithType = new LinkedHashMap<String, Integer>() {{\n        put(KEY_ALL, TYPE_NONE);\n        put(\"eq\", TYPE_STR_SINGLE);\n        put(\"eq_any\", TYPE_STR_MULTIPLE);\n        put(\"eq_none\", TYPE_STR_MULTIPLE);\n        put(\"contains\", TYPE_STR_SINGLE);\n        put(\"starts_with\", TYPE_STR_SINGLE);\n        put(\"ends_with\", TYPE_STR_SINGLE);\n        put(\"regex\", TYPE_REGEX);\n    }};\n\n    public PackageNameOption() {\n        super(\"pkg_name\");\n    }\n\n    @NonNull\n    @Override\n    public Map<String, Integer> getKeysWithType() {\n        return mKeysWithType;\n    }\n\n    @NonNull\n    @Override\n    public TestResult test(@NonNull IFilterableAppInfo info, @NonNull TestResult result) {\n        switch (key) {\n            case KEY_ALL:\n                return result.setMatched(true);\n            case \"eq\":\n                return result.setMatched(info.getPackageName().equals(Objects.requireNonNull(value)));\n            case \"eq_any\":\n                for (String packageName: stringValues) {\n                    if (info.getPackageName().equals(packageName)) {\n                        return result.setMatched(true);\n                    }\n                }\n                return result.setMatched(false);\n            case \"eq_none\":\n                for (String packageName: stringValues) {\n                    if (info.getPackageName().equals(packageName)) {\n                        return result.setMatched(false);\n                    }\n                }\n                return result.setMatched(true);\n            case \"contains\":\n                return result.setMatched(info.getPackageName().contains(Objects.requireNonNull(value)));\n            case \"starts_with\":\n                return result.setMatched(info.getPackageName().startsWith(Objects.requireNonNull(value)));\n            case \"ends_with\":\n                return result.setMatched(info.getPackageName().endsWith(Objects.requireNonNull(value)));\n            case \"regex\":\n                return result.setMatched(regexValue.matcher(info.getPackageName()).matches());\n            default:\n                throw new UnsupportedOperationException(\"Invalid key \" + key);\n        }\n    }\n\n    @NonNull\n    @Override\n    public CharSequence toLocalizedString(@NonNull Context context) {\n        SpannableStringBuilder sb = new SpannableStringBuilder(\"Package name\");\n        switch (key) {\n            case KEY_ALL:\n                return sb.append(LangUtils.getSeparatorString()).append(\"any\");\n            case \"eq\":\n                return sb.append(\" = '\").append(value).append(\"'\");\n            case \"eq_any\":\n                return sb.append(\" matching any of \").append(String.join(\", \", stringValues));\n            case \"eq_none\":\n                return sb.append(\" matching none of \").append(String.join(\", \", stringValues));\n            case \"contains\":\n                return sb.append(\" contains '\").append(value).append(\"'\");\n            case \"starts_with\":\n                return sb.append(\" starts with '\").append(value).append(\"'\");\n            case \"ends_with\":\n                return sb.append(\" ends with '\").append(value).append(\"'\");\n            case \"regex\":\n                return sb.append(\" matches '\").append(value).append(\"'\");\n            default:\n                throw new UnsupportedOperationException(\"Invalid key \" + key);\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/filters/options/PermissionsOption.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.filters.options;\n\nimport android.content.Context;\nimport android.text.SpannableStringBuilder;\n\nimport androidx.annotation.NonNull;\n\nimport java.util.ArrayList;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\n\nimport io.github.muntashirakon.AppManager.filters.IFilterableAppInfo;\nimport io.github.muntashirakon.AppManager.utils.LangUtils;\n\npublic class PermissionsOption extends FilterOption {\n    private final Map<String, Integer> mKeysWithType = new LinkedHashMap<String, Integer>() {{\n        put(KEY_ALL, TYPE_NONE);\n        put(\"eq\", TYPE_STR_SINGLE);\n        put(\"contains\", TYPE_STR_SINGLE);\n        put(\"starts_with\", TYPE_STR_SINGLE);\n        put(\"ends_with\", TYPE_STR_SINGLE);\n        put(\"regex\", TYPE_REGEX);\n        // TODO: 11/19/24 Add more curated options such as permission flags, private flags, grant\n    }};\n\n    public PermissionsOption() {\n        super(\"permissions\");\n    }\n\n    @NonNull\n    @Override\n    public Map<String, Integer> getKeysWithType() {\n        return mKeysWithType;\n    }\n\n    @NonNull\n    @Override\n    public TestResult test(@NonNull IFilterableAppInfo info, @NonNull TestResult result) {\n        List<String> permissions = result.getMatchedPermissions() != null\n                ? result.getMatchedPermissions()\n                : info.getAllPermissions();\n        switch (key) {\n            case KEY_ALL:\n                return result.setMatched(true).setMatchedPermissions(permissions);\n            case \"eq\": {\n                List<String> filteredPermissions = new ArrayList<>();\n                for (String permission : permissions) {\n                    if (permission.equals(value)) {\n                        filteredPermissions.add(permission);\n                    }\n                }\n                return result.setMatched(!filteredPermissions.isEmpty())\n                        .setMatchedPermissions(filteredPermissions);\n            }\n            case \"contains\": {\n                Objects.requireNonNull(value);\n                List<String> filteredPermissions = new ArrayList<>();\n                for (String permission : permissions) {\n                    if (permission.contains(value)) {\n                        filteredPermissions.add(permission);\n                    }\n                }\n                return result.setMatched(!filteredPermissions.isEmpty())\n                        .setMatchedPermissions(filteredPermissions);\n            }\n            case \"starts_with\": {\n                Objects.requireNonNull(value);\n                List<String> filteredPermissions = new ArrayList<>();\n                for (String permission : permissions) {\n                    if (permission.startsWith(value)) {\n                        filteredPermissions.add(permission);\n                    }\n                }\n                return result.setMatched(!filteredPermissions.isEmpty())\n                        .setMatchedPermissions(filteredPermissions);\n            }\n            case \"ends_with\": {\n                Objects.requireNonNull(value);\n                List<String> filteredPermissions = new ArrayList<>();\n                for (String permission : permissions) {\n                    if (permission.endsWith(value)) {\n                        filteredPermissions.add(permission);\n                    }\n                }\n                return result.setMatched(!filteredPermissions.isEmpty())\n                        .setMatchedPermissions(filteredPermissions);\n            }\n            case \"regex\": {\n                Objects.requireNonNull(value);\n                List<String> filteredPermissions = new ArrayList<>();\n                for (String permission : permissions) {\n                    if (regexValue.matcher(permission).matches()) {\n                        filteredPermissions.add(permission);\n                    }\n                }\n                return result.setMatched(!filteredPermissions.isEmpty())\n                        .setMatchedPermissions(filteredPermissions);\n            }\n            default:\n                throw new UnsupportedOperationException(\"Invalid key \" + key);\n        }\n    }\n\n    @NonNull\n    @Override\n    public CharSequence toLocalizedString(@NonNull Context context) {\n        SpannableStringBuilder sb = new SpannableStringBuilder(\"Permissions\");\n        switch (key) {\n            case KEY_ALL:\n                return sb.append(LangUtils.getSeparatorString()).append(\"any\");\n            case \"eq\":\n                return sb.append(\" = '\").append(value).append(\"'\");\n            case \"contains\":\n                return sb.append(\" contains '\").append(value).append(\"'\");\n            case \"starts_with\":\n                return sb.append(\" starts with '\").append(value).append(\"'\");\n            case \"ends_with\":\n                return sb.append(\" ends with '\").append(value).append(\"'\");\n            case \"regex\":\n                return sb.append(\" matches '\").append(value).append(\"'\");\n            default:\n                throw new UnsupportedOperationException(\"Invalid key \" + key);\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/filters/options/RunningAppsOption.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.filters.options;\n\nimport android.content.Context;\nimport android.text.SpannableStringBuilder;\n\nimport androidx.annotation.NonNull;\n\nimport java.util.LinkedHashMap;\nimport java.util.Map;\n\nimport io.github.muntashirakon.AppManager.filters.IFilterableAppInfo;\n\npublic class RunningAppsOption extends FilterOption {\n    private final Map<String, Integer> mKeysWithType = new LinkedHashMap<String, Integer>() {{\n        put(KEY_ALL, TYPE_NONE);\n        put(\"running\", TYPE_NONE);\n        put(\"not_running\", TYPE_NONE);\n    }};\n\n    public RunningAppsOption() {\n        super(\"running_apps\");\n    }\n\n    @NonNull\n    @Override\n    public Map<String, Integer> getKeysWithType() {\n        return mKeysWithType;\n    }\n\n    @NonNull\n    @Override\n    public TestResult test(@NonNull IFilterableAppInfo info, @NonNull TestResult result) {\n        switch (key) {\n            case KEY_ALL:\n                return result.setMatched(true);\n            case \"running\":\n                return result.setMatched(info.isRunning());\n            case \"not_running\":\n                return result.setMatched(!info.isRunning());\n            default:\n                throw new UnsupportedOperationException(\"Invalid key \" + key);\n        }\n    }\n\n    @NonNull\n    @Override\n    public CharSequence toLocalizedString(@NonNull Context context) {\n        SpannableStringBuilder sb = new SpannableStringBuilder(\"App label\");\n        switch (key) {\n            case KEY_ALL:\n                return \"Both running and not running apps\";\n            case \"running\":\n                return \"Only the running apps\";\n            case \"not_running\":\n                return \"Only the not running apps\";\n            default:\n                throw new UnsupportedOperationException(\"Invalid key \" + key);\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/filters/options/ScreenTimeOption.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.filters.options;\n\nimport android.content.Context;\nimport android.text.SpannableStringBuilder;\n\nimport androidx.annotation.NonNull;\n\nimport java.util.LinkedHashMap;\nimport java.util.Map;\n\nimport io.github.muntashirakon.AppManager.filters.IFilterableAppInfo;\nimport io.github.muntashirakon.AppManager.utils.DateUtils;\nimport io.github.muntashirakon.AppManager.utils.LangUtils;\n\npublic class ScreenTimeOption extends FilterOption {\n    private final Map<String, Integer> mKeysWithType = new LinkedHashMap<String, Integer>() {{\n        put(KEY_ALL, TYPE_NONE);\n        put(\"eq\", TYPE_DURATION_MILLIS);\n        put(\"le\", TYPE_DURATION_MILLIS);\n        put(\"ge\", TYPE_DURATION_MILLIS);\n    }};\n\n    public ScreenTimeOption() {\n        super(\"screen_time\");\n    }\n\n    @NonNull\n    @Override\n    public Map<String, Integer> getKeysWithType() {\n        return mKeysWithType;\n    }\n\n    @NonNull\n    @Override\n    public TestResult test(@NonNull IFilterableAppInfo info, @NonNull TestResult result) {\n        switch (key) {\n            case KEY_ALL:\n                return result.setMatched(true);\n            case \"eq\":\n                return result.setMatched(info.getTotalScreenTime() == longValue);\n            case \"le\":\n                return result.setMatched(info.getTotalScreenTime() <= longValue);\n            case \"ge\":\n                return result.setMatched(info.getTotalScreenTime() >= longValue);\n            default:\n                throw new UnsupportedOperationException(\"Invalid key \" + key);\n        }\n    }\n\n    @NonNull\n    @Override\n    public CharSequence toLocalizedString(@NonNull Context context) {\n        SpannableStringBuilder sb = new SpannableStringBuilder(\"Screentime\");\n        switch (key) {\n            case KEY_ALL:\n                return sb.append(LangUtils.getSeparatorString()).append(\"any\");\n            case \"eq\":\n                return sb.append(\" = \").append(DateUtils.getFormattedDuration(context, longValue, false, true));\n            case \"le\":\n                return sb.append(\" ≤ \").append(DateUtils.getFormattedDuration(context, longValue, false, true));\n            case \"ge\":\n                return sb.append(\" ≥ \").append(DateUtils.getFormattedDuration(context, longValue, false, true));\n            default:\n                throw new UnsupportedOperationException(\"Invalid key \" + key);\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/filters/options/SignatureOption.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.filters.options;\n\nimport android.content.Context;\nimport android.text.SpannableStringBuilder;\n\nimport androidx.annotation.NonNull;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\n\nimport io.github.muntashirakon.AppManager.apk.signing.SignerInfo;\nimport io.github.muntashirakon.AppManager.filters.IFilterableAppInfo;\nimport io.github.muntashirakon.AppManager.utils.LangUtils;\n\npublic class SignatureOption extends FilterOption {\n    private final Map<String, Integer> mKeysWithType = new LinkedHashMap<String, Integer>() {{\n        put(KEY_ALL, TYPE_NONE);\n        put(\"no_signer\", TYPE_NONE);\n        put(\"with_lineage\", TYPE_NONE);\n        put(\"with_source_stamp\", TYPE_NONE);\n        put(\"without_lineage\", TYPE_NONE);\n        put(\"without_source_stamp\", TYPE_NONE);\n        put(\"sub_eq\", TYPE_STR_SINGLE);\n        put(\"sub_contains\", TYPE_STR_SINGLE);\n        put(\"sub_starts_with\", TYPE_STR_SINGLE);\n        put(\"sub_ends_with\", TYPE_STR_SINGLE);\n        put(\"sub_regex\", TYPE_REGEX);\n        put(\"sha256\", TYPE_STR_SINGLE);\n    }};\n\n    public SignatureOption() {\n        super(\"signature\");\n    }\n\n    @NonNull\n    @Override\n    public Map<String, Integer> getKeysWithType() {\n        return mKeysWithType;\n    }\n\n    @NonNull\n    @Override\n    public TestResult test(@NonNull IFilterableAppInfo info, @NonNull TestResult result) {\n        SignerInfo signerInfo = info.fetchSignerInfo();\n        if (signerInfo == null || signerInfo.getCurrentSignerCerts() == null) {\n            // No singer\n            return result.setMatched(key.equals(\"no_signer\")).setMatchedSubjectLines(Collections.emptyList());\n        }\n        List<String> subjectLines = result.getMatchedSubjectLines() != null\n                ? result.getMatchedSubjectLines() : Arrays.asList(info.getSignatureSubjectLines());\n        switch (key) {\n            case KEY_ALL:\n                return result.setMatched(true).setMatchedSubjectLines(subjectLines);\n            case \"no_signer\":\n                // Signer exists at this point\n                return result.setMatched(false).setMatchedSubjectLines(subjectLines);\n            case \"with_source_stamp\":\n                return result.setMatched(signerInfo.getSourceStampCert() != null).setMatchedSubjectLines(subjectLines);\n            case \"with_lineage\":\n                return result.setMatched(signerInfo.getSignerCertsInLineage() != null).setMatchedSubjectLines(subjectLines);\n            case \"without_source_stamp\":\n                return result.setMatched(signerInfo.getSourceStampCert() == null).setMatchedSubjectLines(subjectLines);\n            case \"without_lineage\":\n                return result.setMatched(signerInfo.getSignerCertsInLineage() == null).setMatchedSubjectLines(subjectLines);\n            case \"sub_eq\": {\n                List<String> matchedSubjectLines = new ArrayList<>();\n                for (String subject : subjectLines) {\n                    if (subject.equals(value)) {\n                        matchedSubjectLines.add(subject);\n                    }\n                }\n                return result.setMatched(!matchedSubjectLines.isEmpty())\n                        .setMatchedSubjectLines(matchedSubjectLines);\n            }\n            case \"sub_contains\": {\n                Objects.requireNonNull(value);\n                List<String> matchedSubjectLines = new ArrayList<>();\n                for (String subject : subjectLines) {\n                    if (subject.contains(value)) {\n                        matchedSubjectLines.add(subject);\n                    }\n                }\n                return result.setMatched(!matchedSubjectLines.isEmpty())\n                        .setMatchedSubjectLines(matchedSubjectLines);\n            }\n            case \"sub_starts_with\": {\n                Objects.requireNonNull(value);\n                List<String> matchedSubjectLines = new ArrayList<>();\n                for (String subject : subjectLines) {\n                    if (subject.startsWith(value)) {\n                        matchedSubjectLines.add(subject);\n                    }\n                }\n                return result.setMatched(!matchedSubjectLines.isEmpty())\n                        .setMatchedSubjectLines(matchedSubjectLines);\n            }\n            case \"sub_ends_with\": {\n                Objects.requireNonNull(value);\n                List<String> matchedSubjectLines = new ArrayList<>();\n                for (String subject : subjectLines) {\n                    if (subject.endsWith(value)) {\n                        matchedSubjectLines.add(subject);\n                    }\n                }\n                return result.setMatched(!matchedSubjectLines.isEmpty())\n                        .setMatchedSubjectLines(matchedSubjectLines);\n            }\n            case \"sub_regex\": {\n                Objects.requireNonNull(value);\n                List<String> matchedSubjectLines = new ArrayList<>();\n                for (String subject : subjectLines) {\n                    if (regexValue.matcher(subject).matches()) {\n                        matchedSubjectLines.add(subject);\n                    }\n                }\n                return result.setMatched(!matchedSubjectLines.isEmpty())\n                        .setMatchedSubjectLines(matchedSubjectLines);\n            }\n            case \"sha256\": {\n                String[] sha256sums = info.getSignatureSha256Checksums();\n                for (int i = 0; i < sha256sums.length; ++i) {\n                    if (sha256sums[i].equals(value)) {\n                        return result.setMatched(true)\n                                .setMatchedSubjectLines(Collections.singletonList(info.getSignatureSubjectLines()[i]));\n                    }\n                }\n                return result.setMatched(false).setMatchedSubjectLines(Collections.emptyList());\n            }\n            default:\n                throw new UnsupportedOperationException(\"Invalid key \" + key);\n        }\n    }\n\n    @NonNull\n    @Override\n    public CharSequence toLocalizedString(@NonNull Context context) {\n        SpannableStringBuilder sb = new SpannableStringBuilder(\"Signatures\");\n        switch (key) {\n            case KEY_ALL:\n                return sb.append(LangUtils.getSeparatorString()).append(\"any\");\n            case \"no_signer\":\n                return sb.append(LangUtils.getSeparatorString()).append(\"none\");\n            case \"with_lineage\":\n                return sb.append(\" with lineages\");\n            case \"without_lineage\":\n                return sb.append(\" without lineages\");\n            case \"with_source_stamp\":\n                return sb.append(\" with source stamps\");\n            case \"without_source_stamp\":\n                return sb.append(\" without source stamps\");\n            case \"sub_eq\":\n                return sb.append(\"' subject = '\").append(value).append(\"'\");\n            case \"sub_contains\":\n                return sb.append(\"' subject contains '\").append(value).append(\"'\");\n            case \"sub_starts_with\":\n                return sb.append(\"' subject starts with '\").append(value).append(\"'\");\n            case \"sub_ends_with\":\n                return sb.append(\"' subject ends with '\").append(value).append(\"'\");\n            case \"sub_regex\":\n                return sb.append(\"' subject matches '\").append(value).append(\"'\");\n            case \"sha256\":\n                return sb.append(\"' SHA-256 = '\").append(value).append(\"'\");\n            default:\n                throw new UnsupportedOperationException(\"Invalid key \" + key);\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/filters/options/TargetSdkOption.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.filters.options;\n\nimport android.content.Context;\nimport android.text.SpannableStringBuilder;\n\nimport androidx.annotation.NonNull;\n\nimport java.util.LinkedHashMap;\nimport java.util.Map;\n\nimport io.github.muntashirakon.AppManager.filters.IFilterableAppInfo;\nimport io.github.muntashirakon.AppManager.utils.LangUtils;\n\npublic class TargetSdkOption extends FilterOption {\n    private final Map<String, Integer> mKeysWithType = new LinkedHashMap<String, Integer>() {{\n        put(KEY_ALL, TYPE_NONE);\n        put(\"eq\", TYPE_INT);\n        put(\"le\", TYPE_INT);\n        put(\"ge\", TYPE_INT);\n    }};\n\n    public TargetSdkOption() {\n        super(\"target_sdk\");\n    }\n\n    @NonNull\n    @Override\n    public Map<String, Integer> getKeysWithType() {\n        return mKeysWithType;\n    }\n\n    @NonNull\n    @Override\n    public TestResult test(@NonNull IFilterableAppInfo info, @NonNull TestResult result) {\n        switch (key) {\n            case KEY_ALL:\n                return result.setMatched(true);\n            case \"eq\":\n                return result.setMatched(info.getTargetSdk() == intValue);\n            case \"le\":\n                return result.setMatched(info.getTargetSdk() <= intValue);\n            case \"ge\":\n                return result.setMatched(info.getTargetSdk() >= intValue);\n            default:\n                throw new UnsupportedOperationException(\"Invalid key \" + key);\n        }\n    }\n\n    @NonNull\n    @Override\n    public CharSequence toLocalizedString(@NonNull Context context) {\n        SpannableStringBuilder sb = new SpannableStringBuilder(\"Target SDK\");\n        switch (key) {\n            case KEY_ALL:\n                return sb.append(LangUtils.getSeparatorString()).append(\"any\");\n            case \"eq\":\n                return sb.append(\" = \").append(Integer.toString(intValue));\n            case \"le\":\n                return sb.append(\" ≤ \").append(Integer.toString(intValue));\n            case \"ge\":\n                return sb.append(\" ≥ \").append(Integer.toString(intValue));\n            default:\n                throw new UnsupportedOperationException(\"Invalid key \" + key);\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/filters/options/TimesOpenedOption.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.filters.options;\n\nimport android.content.Context;\nimport android.text.SpannableStringBuilder;\n\nimport androidx.annotation.NonNull;\n\nimport java.util.LinkedHashMap;\nimport java.util.Map;\n\nimport io.github.muntashirakon.AppManager.filters.IFilterableAppInfo;\nimport io.github.muntashirakon.AppManager.utils.LangUtils;\n\npublic class TimesOpenedOption extends FilterOption {\n    private final Map<String, Integer> mKeysWithType = new LinkedHashMap<String, Integer>() {{\n        put(KEY_ALL, TYPE_NONE);\n        put(\"eq\", TYPE_INT);\n        put(\"le\", TYPE_INT);\n        put(\"ge\", TYPE_INT);\n    }};\n\n    public TimesOpenedOption() {\n        super(\"times_opened\");\n    }\n\n    @NonNull\n    @Override\n    public Map<String, Integer> getKeysWithType() {\n        return mKeysWithType;\n    }\n\n    @NonNull\n    @Override\n    public TestResult test(@NonNull IFilterableAppInfo info, @NonNull TestResult result) {\n        switch (key) {\n            case KEY_ALL:\n                return result.setMatched(true);\n            case \"eq\":\n                return result.setMatched(info.getTimesOpened() == intValue);\n            case \"le\":\n                return result.setMatched(info.getTimesOpened() <= intValue);\n            case \"ge\":\n                return result.setMatched(info.getTimesOpened() >= intValue);\n            default:\n                throw new UnsupportedOperationException(\"Invalid key \" + key);\n        }\n    }\n\n    @NonNull\n    @Override\n    public CharSequence toLocalizedString(@NonNull Context context) {\n        SpannableStringBuilder sb = new SpannableStringBuilder(\"Times opened\");\n        switch (key) {\n            case KEY_ALL:\n                return sb.append(LangUtils.getSeparatorString()).append(\"any\");\n            case \"eq\":\n                return sb.append(\" = \").append(Integer.toString(intValue));\n            case \"le\":\n                return sb.append(\" ≤ \").append(Integer.toString(intValue));\n            case \"ge\":\n                return sb.append(\" ≥ \").append(Integer.toString(intValue));\n            default:\n                throw new UnsupportedOperationException(\"Invalid key \" + key);\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/filters/options/TotalSizeOption.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.filters.options;\n\nimport android.content.Context;\nimport android.text.SpannableStringBuilder;\nimport android.text.format.Formatter;\n\nimport androidx.annotation.NonNull;\n\nimport java.util.LinkedHashMap;\nimport java.util.Map;\n\nimport io.github.muntashirakon.AppManager.filters.IFilterableAppInfo;\nimport io.github.muntashirakon.AppManager.utils.LangUtils;\n\npublic class TotalSizeOption extends FilterOption {\n    private final Map<String, Integer> mKeysWithType = new LinkedHashMap<String, Integer>() {{\n        put(KEY_ALL, TYPE_NONE);\n        put(\"eq\", TYPE_SIZE_BYTES);\n        put(\"le\", TYPE_SIZE_BYTES);\n        put(\"ge\", TYPE_SIZE_BYTES);\n    }};\n\n    public TotalSizeOption() {\n        super(\"total_size\");\n    }\n\n    @NonNull\n    @Override\n    public Map<String, Integer> getKeysWithType() {\n        return mKeysWithType;\n    }\n\n    @NonNull\n    @Override\n    public TestResult test(@NonNull IFilterableAppInfo info, @NonNull TestResult result) {\n        switch (key) {\n            case KEY_ALL:\n                return result.setMatched(true);\n            case \"eq\":\n                return result.setMatched(info.getTotalSize() == longValue);\n            case \"le\":\n                return result.setMatched(info.getTotalSize() <= longValue);\n            case \"ge\":\n                return result.setMatched(info.getTotalSize() >= longValue);\n            default:\n                throw new UnsupportedOperationException(\"Invalid key \" + key);\n        }\n    }\n\n    @NonNull\n    @Override\n    public CharSequence toLocalizedString(@NonNull Context context) {\n        SpannableStringBuilder sb = new SpannableStringBuilder(\"Total size\");\n        switch (key) {\n            case KEY_ALL:\n                return sb.append(LangUtils.getSeparatorString()).append(\"any\");\n            case \"eq\":\n                return sb.append(\" = \").append(Formatter.formatFileSize(context, longValue));\n            case \"le\":\n                return sb.append(\" ≤ \").append(Formatter.formatFileSize(context, longValue));\n            case \"ge\":\n                return sb.append(\" ≥ \").append(Formatter.formatFileSize(context, longValue));\n            default:\n                throw new UnsupportedOperationException(\"Invalid key \" + key);\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/filters/options/TrackersOption.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.filters.options;\n\nimport android.content.Context;\nimport android.text.SpannableStringBuilder;\n\nimport androidx.annotation.NonNull;\n\nimport java.util.LinkedHashMap;\nimport java.util.Map;\n\nimport io.github.muntashirakon.AppManager.filters.IFilterableAppInfo;\nimport io.github.muntashirakon.AppManager.utils.LangUtils;\n\npublic class TrackersOption extends FilterOption {\n    private final Map<String, Integer> mKeysWithType = new LinkedHashMap<String, Integer>() {{\n        put(KEY_ALL, TYPE_NONE);\n        put(\"eq\", TYPE_INT);\n        put(\"le\", TYPE_INT);\n        put(\"ge\", TYPE_INT);\n        // TODO: 7/2/24 Enhance this to include more curated options such as regex and find by tracker name\n    }};\n\n    public TrackersOption() {\n        super(\"trackers\");\n    }\n\n    @NonNull\n    @Override\n    public Map<String, Integer> getKeysWithType() {\n        return mKeysWithType;\n    }\n\n    @NonNull\n    @Override\n    public TestResult test(@NonNull IFilterableAppInfo info, @NonNull TestResult result) {\n        switch (key) {\n            case KEY_ALL:\n                return result.setMatched(true);\n            case \"eq\":\n                return result.setMatched(info.getTrackerComponents().size() == intValue);\n            case \"le\":\n                return result.setMatched(info.getTrackerComponents().size() <= intValue);\n            case \"ge\":\n                return result.setMatched(info.getTrackerComponents().size() >= intValue);\n            default:\n                throw new UnsupportedOperationException(\"Invalid key \" + key);\n        }\n    }\n\n    @NonNull\n    @Override\n    public CharSequence toLocalizedString(@NonNull Context context) {\n        SpannableStringBuilder sb = new SpannableStringBuilder(\"Trackers\");\n        switch (key) {\n            case KEY_ALL:\n                return sb.append(LangUtils.getSeparatorString()).append(\"any\");\n            case \"eq\":\n                return sb.append(\" = \").append(Integer.toString(intValue));\n            case \"le\":\n                return sb.append(\" ≤ \").append(Integer.toString(intValue));\n            case \"ge\":\n                return sb.append(\" ≥ \").append(Integer.toString(intValue));\n            default:\n                throw new UnsupportedOperationException(\"Invalid key \" + key);\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/filters/options/UidOption.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.filters.options;\n\nimport android.content.Context;\nimport android.text.SpannableStringBuilder;\n\nimport androidx.annotation.NonNull;\n\nimport java.util.LinkedHashMap;\nimport java.util.Map;\nimport java.util.Objects;\n\nimport io.github.muntashirakon.AppManager.filters.IFilterableAppInfo;\nimport io.github.muntashirakon.AppManager.utils.ArrayUtils;\nimport io.github.muntashirakon.AppManager.utils.LangUtils;\n\npublic class UidOption extends FilterOption {\n    private final Map<String, Integer> mKeysWithType = new LinkedHashMap<String, Integer>() {{\n        put(KEY_ALL, TYPE_NONE);\n        put(\"uid_eq\", TYPE_INT);\n        put(\"uid_le\", TYPE_INT);\n        put(\"uid_ge\", TYPE_INT);\n        put(\"with_shared\", TYPE_NONE);\n        put(\"without_shared\", TYPE_NONE);\n        put(\"shared_uid_name\", TYPE_STR_SINGLE);\n        put(\"shared_uid_names\", TYPE_STR_MULTIPLE);\n        put(\"shared_uid_name_regex\", TYPE_REGEX);\n    }};\n\n    public UidOption() {\n        super(\"uid\");\n    }\n\n    @NonNull\n    @Override\n    public Map<String, Integer> getKeysWithType() {\n        return mKeysWithType;\n    }\n\n    @NonNull\n    @Override\n    public TestResult test(@NonNull IFilterableAppInfo info, @NonNull TestResult result) {\n        switch (key) {\n            case KEY_ALL:\n                return result.setMatched(false);\n            case \"uid_eq\":\n                return result.setMatched(info.getUid() == intValue);\n            case \"uid_le\":\n                return result.setMatched(info.getUid() <= intValue);\n            case \"uid_ge\":\n                return result.setMatched(info.getUid() >= intValue);\n            case \"with_shared\":\n                return result.setMatched(info.getSharedUserId() != null);\n            case \"without_shared\":\n                return result.setMatched(info.getSharedUserId() == null);\n            case \"shared_uid_name\":\n                return result.setMatched(Objects.equals(info.getSharedUserId(), value));\n            case \"shared_uid_names\":\n                return result.setMatched(ArrayUtils.contains(stringValues, info.getSharedUserId()));\n            case \"shared_uid_name_regex\":\n                return result.setMatched(regexValue.matcher(info.getSharedUserId()).matches());\n            default:\n                throw new UnsupportedOperationException(\"Invalid key \" + key);\n        }\n    }\n\n    @NonNull\n    @Override\n    public CharSequence toLocalizedString(@NonNull Context context) {\n        SpannableStringBuilder sb = new SpannableStringBuilder(\"UID\");\n        switch (key) {\n            case KEY_ALL:\n                return sb.append(LangUtils.getSeparatorString()).append(\"any\");\n            case \"uid_eq\":\n                return sb.append(\" = \").append(Integer.toString(intValue));\n            case \"uid_le\":\n                return sb.append(\" ≤ \").append(Integer.toString(intValue));\n            case \"uid_ge\":\n                return sb.append(\" ≥ \").append(Integer.toString(intValue));\n            case \"with_shared\":\n                return \"Only the apps with a shared UID\";\n            case \"without_shared\":\n                return \"Only the apps without a shared UID\";\n            case \"shared_uid_name\":\n                return \"Only the apps with the shared UID \" + value;\n            case \"shared_uid_names\":\n                return \"Only the apps with the shared UID (exclusive) \" + String.join(\", \", stringValues);\n            case \"shared_uid_name_regex\":\n                return \"Only the apps with the shared UID that matches '\" + value + \"'\";\n            default:\n                throw new UnsupportedOperationException(\"Invalid key \" + key);\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/filters/options/VersionNameOption.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.filters.options;\n\nimport android.content.Context;\nimport android.text.SpannableStringBuilder;\n\nimport androidx.annotation.NonNull;\n\nimport java.util.LinkedHashMap;\nimport java.util.Map;\nimport java.util.Objects;\n\nimport io.github.muntashirakon.AppManager.filters.IFilterableAppInfo;\nimport io.github.muntashirakon.AppManager.utils.LangUtils;\n\npublic class VersionNameOption extends FilterOption {\n    private final Map<String, Integer> mKeysWithType = new LinkedHashMap<String, Integer>() {{\n        put(KEY_ALL, TYPE_NONE);\n        put(\"eq\", TYPE_STR_SINGLE);\n        put(\"contains\", TYPE_STR_SINGLE);\n        put(\"starts_with\", TYPE_STR_SINGLE);\n        put(\"ends_with\", TYPE_STR_SINGLE);\n        put(\"regex\", TYPE_REGEX);\n    }};\n\n    public VersionNameOption() {\n        super(\"version_name\");\n    }\n\n    @NonNull\n    @Override\n    public Map<String, Integer> getKeysWithType() {\n        return mKeysWithType;\n    }\n\n    @NonNull\n    @Override\n    public TestResult test(@NonNull IFilterableAppInfo info, @NonNull TestResult result) {\n        if (info.getVersionName() == null) {\n            return result.setMatched(key.equals(KEY_ALL));\n        }\n        switch (key) {\n            case KEY_ALL:\n                return result.setMatched(true);\n            case \"eq\":\n                return result.setMatched(info.getVersionName().equals(Objects.requireNonNull(value)));\n            case \"contains\":\n                return result.setMatched(info.getVersionName().contains(Objects.requireNonNull(value)));\n            case \"starts_with\":\n                return result.setMatched(info.getVersionName().startsWith(Objects.requireNonNull(value)));\n            case \"ends_with\":\n                return result.setMatched(info.getVersionName().endsWith(Objects.requireNonNull(value)));\n            case \"regex\":\n                return result.setMatched(regexValue.matcher(info.getVersionName()).matches());\n            default:\n                throw new UnsupportedOperationException(\"Invalid key \" + key);\n        }\n    }\n\n    @NonNull\n    @Override\n    public CharSequence toLocalizedString(@NonNull Context context) {\n        SpannableStringBuilder sb = new SpannableStringBuilder(\"Version name\");\n        switch (key) {\n            case KEY_ALL:\n                return sb.append(LangUtils.getSeparatorString()).append(\"any\");\n            case \"eq\":\n                return sb.append(\" = '\").append(value).append(\"'\");\n            case \"contains\":\n                return sb.append(\" contains '\").append(value).append(\"'\");\n            case \"starts_with\":\n                return sb.append(\" starts with '\").append(value).append(\"'\");\n            case \"ends_with\":\n                return sb.append(\" ends with '\").append(value).append(\"'\");\n            case \"regex\":\n                return sb.append(\" matches '\").append(value).append(\"'\");\n            default:\n                throw new UnsupportedOperationException(\"Invalid key \" + key);\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/fm/ContentType2.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.fm;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport com.j256.simplemagic.entries.IanaEntries;\nimport com.j256.simplemagic.entries.IanaEntry;\n\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Map;\n\npublic enum ContentType2 {\n    APKM(\"application/vnd.apkm\", \"apkm\", \"apkm\"),\n    APKS(\"application/x-apks\", \"apks\", \"apks\"),\n    CONFIGURATION(\"text/plain\", \"configuration\", \"cnf\", \"conf\", \"cfg\", \"cf\", \"ini\", \"rc\", \"sys\"),\n    DEX(\"application/x-dex\", \"dex\", \"dex\"),\n    KOTLIN(\"text/x-kotlin\", \"kotlin\", \"kt\"),\n    LOG(\"text/plain\", \"log\", \"log\"),\n    LUA(\"text/x-lua\", \"lua\", \"lua\"),\n    M4A(\"audio/mp4a-latm\", \"mp4a-latm\", \"m4a\"),\n    MARKDOWN(\"text/markdown\", \"markdown\", \"md\", \"markdown\"),\n    PEM(\"application/pem-certificate-chain\", \"pem\", \"pem\"),\n    PK8(\"application/pkcs8\", \"pkcs8\", \"pk8\"),\n    PLIST(\"application/x-plist\", \"property-list\", \"plist\"),\n    PROPERTIES(\"text/plain\", \"properties\", \"prop\", \"properties\"),\n    SMALI(\"text/x-smali\", \"smali\", \"smali\"),\n    SQLITE3(\"application/vnd.sqlite3\", \"sqlite\", \"db\", \"db3\", \"s3db\", \"sl3\", \"sqlite\", \"sqlite3\"),\n    TOML(\"application/toml\", \"toml\", \"toml\"),\n    XAPK(\"application/xapk-package-archive\", \"xapk\", \"xapk\"),\n    YAML(\"text/plain\", \"yaml\", \"yml\", \"yaml\"),\n    /** default if no specific match to the mime-type */\n    OTHER(\"application/octet-stream\", \"other\"),\n    ;\n\n    private final static Map<String, ContentType2> sMimeTypeMap = new HashMap<>();\n    private final static Map<String, ContentType2> sFileExtensionMap = new HashMap<>();\n    private static IanaEntries sIanaEntries;\n\n    static {\n        for (ContentType2 type : values()) {\n            // NOTE: this may overwrite this mapping\n            sMimeTypeMap.put(type.mMimeType.toLowerCase(Locale.ROOT), type);\n            if (type.mFileExtensions != null) {\n                for (String fileExtension : type.mFileExtensions) {\n                    // NOTE: this may overwrite this mapping\n                    sFileExtensionMap.put(fileExtension, type);\n                }\n            }\n        }\n    }\n\n    @NonNull\n    private final String mMimeType;\n    @NonNull\n    private final String mSimpleName;\n    @Nullable\n    private final String[] mFileExtensions;\n    @Nullable\n    private final IanaEntry mIanaEntry;\n\n    ContentType2(@NonNull String mimeType, @NonNull String simpleName, @Nullable String... fileExtensions) {\n        mMimeType = mimeType;\n        mSimpleName = simpleName;\n        mFileExtensions = fileExtensions;\n        mIanaEntry = findIanaEntryByMimeType(mimeType);\n    }\n\n    /**\n     * Get simple name of the type.\n     */\n    @NonNull\n    public String getSimpleName() {\n        return mSimpleName;\n    }\n\n    @NonNull\n    public String getMimeType() {\n        return mMimeType;\n    }\n\n    @Nullable\n    public String[] getFileExtensions() {\n        return mFileExtensions;\n    }\n\n    /**\n     * Return the type associated with the mime-type string or {@link #OTHER} if not found.\n     */\n    @NonNull\n    public static ContentType2 fromMimeType(String mimeType) {\n        // NOTE: mimeType can be null\n        if (mimeType != null) {\n            mimeType = mimeType.toLowerCase(Locale.ROOT);\n        }\n        ContentType2 type = sMimeTypeMap.get(mimeType);\n        if (type == null) {\n            return OTHER;\n        } else {\n            return type;\n        }\n\n    }\n\n    /**\n     * Return the type associated with the file-extension string or {@code null} if not found.\n     */\n    @Nullable\n    public static ContentType2 fromFileExtension(@NonNull String fileExtension) {\n        return sFileExtensionMap.get(fileExtension.toLowerCase(Locale.ROOT));\n    }\n\n    /**\n     * Returns the references of the mime type or null if none.\n     */\n    @Nullable\n    public List<String> getReferences() {\n        if (mIanaEntry == null) {\n            return null;\n        } else {\n            return mIanaEntry.getReferences();\n        }\n    }\n\n    /**\n     * Returns the URL of the references or null if none.\n     */\n    @Nullable\n    public List<String> getReferenceUrls() {\n        if (mIanaEntry == null) {\n            return null;\n        } else {\n            return mIanaEntry.getReferenceUrls();\n        }\n    }\n\n    @Nullable\n    private static IanaEntry findIanaEntryByMimeType(String mimeType) {\n        if (sIanaEntries == null) {\n            sIanaEntries = new IanaEntries();\n        }\n        return sIanaEntries.lookupByMimeType(mimeType);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/fm/FmActivity.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.fm;\n\nimport android.app.Activity;\nimport android.app.Application;\nimport android.content.ContentResolver;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.pm.PackageManager;\nimport android.content.pm.ResolveInfo;\nimport android.graphics.drawable.Drawable;\nimport android.net.Uri;\nimport android.os.Bundle;\nimport android.os.Environment;\nimport android.os.Parcel;\nimport android.os.Parcelable;\nimport android.provider.DocumentsContract;\nimport android.text.TextUtils;\nimport android.view.LayoutInflater;\nimport android.view.Menu;\nimport android.view.MenuItem;\nimport android.view.View;\nimport android.view.ViewGroup;\n\nimport androidx.activity.result.ActivityResultLauncher;\nimport androidx.activity.result.contract.ActivityResultContracts;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.appcompat.app.ActionBar;\nimport androidx.appcompat.widget.AppCompatImageView;\nimport androidx.appcompat.widget.AppCompatTextView;\nimport androidx.appcompat.widget.PopupMenu;\nimport androidx.collection.ArrayMap;\nimport androidx.core.os.BundleCompat;\nimport androidx.core.os.ParcelCompat;\nimport androidx.core.util.Pair;\nimport androidx.documentfile.provider.DocumentFileUtils;\nimport androidx.drawerlayout.widget.DrawerLayout;\nimport androidx.fragment.app.Fragment;\nimport androidx.lifecycle.AndroidViewModel;\nimport androidx.lifecycle.LiveData;\nimport androidx.lifecycle.MutableLiveData;\nimport androidx.lifecycle.ViewModelProvider;\nimport androidx.recyclerview.widget.LinearLayoutManager;\nimport androidx.recyclerview.widget.RecyclerView;\n\nimport com.google.android.material.button.MaterialButton;\nimport com.google.android.material.dialog.MaterialAlertDialogBuilder;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Objects;\n\nimport io.github.muntashirakon.AppManager.BaseActivity;\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.db.entity.FmFavorite;\nimport io.github.muntashirakon.AppManager.fm.dialogs.FilePropertiesDialogFragment;\nimport io.github.muntashirakon.AppManager.fm.dialogs.RenameDialogFragment;\nimport io.github.muntashirakon.AppManager.settings.Prefs;\nimport io.github.muntashirakon.AppManager.utils.ExUtils;\nimport io.github.muntashirakon.AppManager.utils.StoragePermission;\nimport io.github.muntashirakon.AppManager.utils.StorageUtils;\nimport io.github.muntashirakon.AppManager.utils.ThreadUtils;\nimport io.github.muntashirakon.AppManager.utils.Utils;\nimport io.github.muntashirakon.io.Paths;\nimport io.github.muntashirakon.util.AdapterUtils;\n\npublic class FmActivity extends BaseActivity {\n    public static class Options implements Parcelable {\n        public static final int OPTION_VFS = 1 << 0;\n        public static final int OPTION_RO = 1 << 1; // read-only\n        public static final int OPTION_MOUNT_DEX = 1 << 2;\n\n        @NonNull\n        public final Uri uri;\n        public final int options;\n\n        @Nullable\n        private Uri mInitUriForVfs;\n\n        public Options(@NonNull Uri uri) {\n            this(uri, false, false, false);\n        }\n\n        protected Options(@NonNull Uri uri, int options) {\n            this.uri = uri;\n            this.options = options;\n        }\n\n        public Options(@NonNull Uri uri, boolean isVfs, boolean readOnly, boolean mountDexFiles) {\n            this.uri = uri;\n            int options = 0;\n            if (isVfs) {\n                options |= OPTION_VFS;\n            }\n            if (readOnly) {\n                options |= OPTION_RO;\n            }\n            if (mountDexFiles) {\n                options |= OPTION_MOUNT_DEX;\n            }\n            this.options = options;\n        }\n\n        public void setInitUriForVfs(@Nullable Uri initUriForVfs) {\n            if (!isVfs() && initUriForVfs != null) {\n                throw new IllegalArgumentException(\"initUri can only be set when the file system is virtual.\");\n            }\n            this.mInitUriForVfs = initUriForVfs;\n        }\n\n        @Nullable\n        public Uri getInitUriForVfs() {\n            return mInitUriForVfs;\n        }\n\n        public boolean isVfs() {\n            return (options & OPTION_VFS) != 0;\n        }\n\n        public boolean isMountDex() {\n            return (options & OPTION_MOUNT_DEX) != 0;\n        }\n\n        protected Options(Parcel in) {\n            uri = Objects.requireNonNull(ParcelCompat.readParcelable(in, Uri.class.getClassLoader(), Uri.class));\n            options = in.readInt();\n            mInitUriForVfs = ParcelCompat.readParcelable(in, Uri.class.getClassLoader(), Uri.class);\n        }\n\n        public static final Creator<Options> CREATOR = new Creator<Options>() {\n            @NonNull\n            @Override\n            public Options createFromParcel(@NonNull Parcel in) {\n                return new Options(in);\n            }\n\n            @NonNull\n            @Override\n            public Options[] newArray(int size) {\n                return new Options[size];\n            }\n        };\n\n        @Override\n        public int describeContents() {\n            return 0;\n        }\n\n        @Override\n        public void writeToParcel(@NonNull Parcel dest, int flags) {\n            dest.writeParcelable(uri, flags);\n            dest.writeInt(options);\n            dest.writeParcelable(mInitUriForVfs, flags);\n        }\n    }\n\n    public static final String LAUNCHER_ALIAS = \"io.github.muntashirakon.AppManager.fm.FilesActivity\";\n\n    public static final String EXTRA_OPTIONS = \"opt\";\n\n    private DrawerLayout mDrawerLayout;\n    private RecyclerView mDrawerRecyclerView;\n    private DrawerRecyclerViewAdapter mDrawerAdapter;\n    private FmDrawerViewModel mViewModel;\n    private final ActivityResultLauncher<Intent> mAddDocumentProvider = registerForActivityResult(\n            new ActivityResultContracts.StartActivityForResult(),\n            result -> {\n                try {\n                    if (result.getResultCode() != Activity.RESULT_OK) return;\n                    Intent data = result.getData();\n                    if (data == null) return;\n                    Uri treeUri = data.getData();\n                    if (treeUri == null) return;\n                    int takeFlags = data.getFlags() & (Intent.FLAG_GRANT_READ_URI_PERMISSION\n                            | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);\n                    getContentResolver().takePersistableUriPermission(treeUri, takeFlags);\n                } finally {\n                    // Display backup volumes again\n                    mViewModel.loadDrawerItems();\n                }\n            });\n    private final StoragePermission mStoragePermission = StoragePermission.init(this);\n\n    @Override\n    protected void onAuthenticated(@Nullable Bundle savedInstanceState) {\n        setContentView(R.layout.activity_fm);\n        setSupportActionBar(findViewById(R.id.toolbar));\n        findViewById(R.id.progress_linear).setVisibility(View.GONE);\n        mViewModel = new ViewModelProvider(this).get(FmDrawerViewModel.class);\n        mDrawerLayout = findViewById(R.id.drawer_layout);\n        mDrawerRecyclerView = findViewById(R.id.recycler_view);\n        mDrawerRecyclerView.setLayoutManager(new LinearLayoutManager(this));\n        mDrawerAdapter = new DrawerRecyclerViewAdapter(this);\n        mDrawerRecyclerView.setAdapter(mDrawerAdapter);\n        ActionBar actionBar = getSupportActionBar();\n        if (actionBar != null) {\n            actionBar.setHomeAsUpIndicator(R.drawable.ic_menu);\n        }\n        mViewModel.getDrawerItemsLiveData().observe(this, drawerItems ->\n                mDrawerAdapter.setAdapterItems(drawerItems));\n        FmFavoritesManager.getFavoriteAddedLiveData().observe(this, fmFavorite -> {\n            // Reload drawer\n            mViewModel.loadDrawerItems();\n        });\n        mViewModel.loadDrawerItems();\n        Uri uri = getIntent().getData();\n        if (uri != null && uri.getScheme() == null) {\n            // file:// URI can have no schema. So, fix it by adding file://\n            if (uri.getPath() != null && uri.getAuthority() == null) {\n                uri = uri.buildUpon().scheme(ContentResolver.SCHEME_FILE).build();\n            } else {\n                // Avoid loading invalid paths\n                uri = null;\n            }\n        }\n        uri = FmUtils.sanitizeContentInput(uri);\n        if (savedInstanceState == null) {\n            Options options = getIntent().getExtras() != null ? BundleCompat.getParcelable(getIntent().getExtras(), EXTRA_OPTIONS, Options.class) : null;\n            Integer position = null;\n            if (options == null) {\n                if (uri != null) {\n                    options = new Options(uri);\n                } else if (Prefs.FileManager.isRememberLastOpenedPath()) {\n                    Pair<FmActivity.Options, Pair<Uri, Integer>> optionsUriPostionPair = Prefs.FileManager.getLastOpenedPath();\n                    if (optionsUriPostionPair != null) {\n                        options = optionsUriPostionPair.first;\n                        if (options.isVfs()) {\n                            uri = optionsUriPostionPair.second.first;\n                        }\n                        position = optionsUriPostionPair.second.second;\n                    }\n                }\n                if (options == null) {\n                    // Use home\n                    options = new Options(Prefs.FileManager.getHome());\n                }\n            }\n            Uri uncheckedUri = options.uri;\n            Uri checkedUri = ExUtils.exceptionAsNull(() -> Paths.getStrict(uncheckedUri).exists() ? uncheckedUri : null);\n            if (checkedUri == null) {\n                // Use default directory\n                options = new Options(Uri.fromFile(Environment.getExternalStorageDirectory()));\n            }\n            if (options.isVfs()) {\n                options.setInitUriForVfs(uri);\n            }\n            loadFragment(options, position);\n        }\n    }\n\n    @Override\n    protected void onNewIntent(@NonNull Intent intent) {\n        super.onNewIntent(intent);\n        Uri uri = intent.getData();\n        Options options = intent.getExtras() != null ? BundleCompat.getParcelable(intent.getExtras(), EXTRA_OPTIONS, Options.class) : null;\n        if (options != null) {\n            Intent intent2 = new Intent(this, FmActivity.class);\n            if (uri != null) {\n                intent2.setDataAndType(uri, DocumentsContract.Document.MIME_TYPE_DIR);\n            }\n            intent2.putExtra(EXTRA_OPTIONS, options);\n            intent2.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT | Intent.FLAG_ACTIVITY_MULTIPLE_TASK);\n            startActivity(intent2);\n            return;\n        }\n        if (uri != null) {\n            Intent intent2 = new Intent(this, FmActivity.class);\n            intent2.setDataAndType(uri, DocumentsContract.Document.MIME_TYPE_DIR);\n            intent2.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT | Intent.FLAG_ACTIVITY_MULTIPLE_TASK);\n            startActivity(intent2);\n        }\n    }\n\n    @Override\n    public boolean onOptionsItemSelected(@NonNull MenuItem item) {\n        if (item.getItemId() == android.R.id.home) {\n            mDrawerLayout.open();\n            return true;\n        }\n        return super.onOptionsItemSelected(item);\n    }\n\n    private void loadFragment(@NonNull Options options, @Nullable Integer position) {\n        if (ContentResolver.SCHEME_FILE.equals(options.uri.getScheme())) {\n            mStoragePermission.request(granted -> {\n                // Return value does not matter\n                doLoadFragment(options, position);\n            });\n        } else doLoadFragment(options, position);\n    }\n\n    private void doLoadFragment(@NonNull Options options, @Nullable Integer position) {\n        Fragment fragment = FmFragment.getNewInstance(options, position);\n        getSupportFragmentManager()\n                .beginTransaction()\n                .replace(R.id.main_layout, fragment, FmFragment.TAG)\n                .commit();\n    }\n\n    public static class FmDrawerViewModel extends AndroidViewModel {\n        private final MutableLiveData<List<FmDrawerItem>> mDrawerItemsLiveData = new MutableLiveData<>();\n\n        public FmDrawerViewModel(@NonNull Application application) {\n            super(application);\n        }\n\n        public void removeFavorite(long id) {\n            ThreadUtils.postOnBackgroundThread(() -> FmFavoritesManager.removeFromFavorite(id));\n        }\n\n        public void renameFavorite(long id, @NonNull String newName) {\n            ThreadUtils.postOnBackgroundThread(() -> FmFavoritesManager.renameFavorite(id, newName));\n        }\n\n        public void releaseUri(@NonNull Uri uri) {\n            try {\n                getApplication()\n                        .getContentResolver()\n                        .releasePersistableUriPermission(uri,\n                                Intent.FLAG_GRANT_READ_URI_PERMISSION\n                                        | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);\n                loadDrawerItems();\n            } catch (SecurityException e) {\n                e.printStackTrace();\n            }\n        }\n\n        public LiveData<List<FmDrawerItem>> getDrawerItemsLiveData() {\n            return mDrawerItemsLiveData;\n        }\n\n        public void loadDrawerItems() {\n            ThreadUtils.postOnBackgroundThread(() -> {\n                List<FmDrawerItem> drawerItems = new ArrayList<>();\n                Context context = getApplication();\n                // Favorites\n                drawerItems.add(new FmDrawerItem(-1, context.getString(R.string.favorites), null, FmDrawerItem.ITEM_TYPE_LABEL));\n                List<FmFavorite> fmFavorites = FmFavoritesManager.getAllFavorites();\n                for (FmFavorite fmFavorite : fmFavorites) {\n                    Options options = new Options(Uri.parse(fmFavorite.uri), fmFavorite.options);\n                    options.mInitUriForVfs = fmFavorite.initUri != null ? Uri.parse(fmFavorite.initUri) : null;\n                    FmDrawerItem drawerItem = new FmDrawerItem(fmFavorite.id, fmFavorite.name, options, FmDrawerItem.ITEM_TYPE_FAVORITE);\n                    drawerItem.iconRes = getIconResFromName(fmFavorite.name);\n                    drawerItems.add(drawerItem);\n                }\n                // Locations\n                drawerItems.add(new FmDrawerItem(-2, context.getString(R.string.storage), null, FmDrawerItem.ITEM_TYPE_LABEL));\n                ArrayMap<String, Uri> storageLocations = StorageUtils.getAllStorageLocations(getApplication());\n                for (int i = 0; i < storageLocations.size(); ++i) {\n                    Uri uri = storageLocations.valueAt(i);\n                    Options options = new Options(uri);\n                    PackageManager pm = getApplication().getPackageManager();\n                    ResolveInfo resolveInfo = DocumentFileUtils.getUriSource(getApplication(), uri);\n                    String name = resolveInfo != null ? resolveInfo.loadLabel(pm).toString() : storageLocations.keyAt(i);\n                    Drawable icon = resolveInfo != null ? resolveInfo.loadIcon(pm) : null;\n                    FmDrawerItem drawerItem = new FmDrawerItem(-4, name, options, FmDrawerItem.ITEM_TYPE_LOCATION);\n                    drawerItem.iconRes = R.drawable.ic_content_save;\n                    drawerItem.icon = icon;\n                    drawerItems.add(drawerItem);\n                }\n                mDrawerItemsLiveData.postValue(drawerItems);\n            });\n        }\n\n        private static int getIconResFromName(@NonNull String filename) {\n            switch (filename) {\n                case \"Documents\":\n                    return R.drawable.ic_file_document;\n                case \"Download\":\n                case \"Downloads\":\n                    return R.drawable.ic_get_app;\n                case \"Pictures\":\n                case \"DCIM\":\n                    return R.drawable.ic_image;\n                case \"Movies\":\n                case \"Music\":\n                case \"Podcasts\":\n                case \"Recordings\":\n                case \"Ringtones\":\n                    return R.drawable.ic_audio_file;\n                default:\n                    return R.drawable.ic_folder;\n            }\n        }\n    }\n\n    public static class DrawerRecyclerViewAdapter extends RecyclerView.Adapter<DrawerRecyclerViewAdapter.ViewHolder> {\n        private final List<FmDrawerItem> mAdapterItems = new ArrayList<>();\n        private final FmActivity mFmActivity;\n\n        public DrawerRecyclerViewAdapter(@NonNull FmActivity activity) {\n            mFmActivity = activity;\n        }\n\n        public void setAdapterItems(@NonNull List<FmDrawerItem> adapterItems) {\n            AdapterUtils.notifyDataSetChanged(this, mAdapterItems, adapterItems);\n        }\n\n        @NonNull\n        @Override\n        public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, @FmDrawerItem.DrawerItemType int viewType) {\n            int layoutId;\n            if (viewType == FmDrawerItem.ITEM_TYPE_LABEL) {\n                layoutId = R.layout.item_title_action;\n            } else layoutId = R.layout.item_fm_drawer;\n            View v = LayoutInflater.from(parent.getContext()).inflate(layoutId, parent, false);\n            return new ViewHolder(v);\n        }\n\n        @Override\n        public void onBindViewHolder(@NonNull ViewHolder holder, int position) {\n            FmDrawerItem item = mAdapterItems.get(position);\n            holder.labelView.setText(item.name);\n            if (item.type == FmDrawerItem.ITEM_TYPE_LABEL) {\n                getLabelView(holder, item);\n            } else {\n                getView(holder, item);\n            }\n        }\n\n        public void getLabelView(@NonNull ViewHolder holder, FmDrawerItem item) {\n            if (holder.actionView == null) {\n                return;\n            }\n            if (item.id == -1) {\n                // Favorites\n                holder.actionView.setVisibility(View.GONE);\n            } else if (item.id == -2) {\n                // Locations\n                holder.actionView.setVisibility(View.VISIBLE);\n                holder.actionView.setIconResource(R.drawable.ic_add);\n                holder.actionView.setContentDescription(holder.itemView.getContext().getString(R.string.add));\n                holder.actionView.setOnClickListener(v -> {\n                    Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)\n                            .putExtra(\"android.provider.extra.SHOW_ADVANCED\", true);\n                    mFmActivity.mAddDocumentProvider.launch(intent);\n                });\n            } else holder.actionView.setVisibility(View.GONE);\n        }\n\n        public void getView(@NonNull ViewHolder holder, @NonNull FmDrawerItem item) {\n            Objects.requireNonNull(item.options);\n            if (holder.iconView != null) {\n                if (item.icon != null) {\n                    holder.iconView.setImageDrawable(item.icon);\n                } else holder.iconView.setImageResource(item.iconRes);\n            }\n            holder.itemView.setOnClickListener(v -> {\n                Options options = item.options;\n                mFmActivity.mDrawerLayout.close();\n                mFmActivity.loadFragment(options, null);\n            });\n            holder.itemView.setOnLongClickListener(v -> {\n                Context context = v.getContext();\n                PopupMenu popupMenu = new PopupMenu(context, v);\n                Menu menu = popupMenu.getMenu();\n                // Copy path\n                menu.add(R.string.copy_this_path).setOnMenuItemClickListener(menuItem -> {\n                    Uri uri = item.options.getInitUriForVfs() != null\n                            ? item.options.getInitUriForVfs() : item.options.uri;\n                    String path = FmUtils.getDisplayablePath(uri);\n                    Utils.copyToClipboard(context, \"Path\", path);\n                    return true;\n                });\n                // Remove item\n                Uri uri = item.options.uri;\n                boolean removable = item.type != FmDrawerItem.ITEM_TYPE_LOCATION\n                        || ContentResolver.SCHEME_CONTENT.equals(uri.getScheme());\n                if (removable) {\n                    menu.add(R.string.item_remove).setOnMenuItemClickListener(menuItem -> {\n                        new MaterialAlertDialogBuilder(mFmActivity)\n                                .setTitle(context.getString(R.string.remove_filename, item.name))\n                                .setMessage(R.string.are_you_sure)\n                                .setNegativeButton(R.string.no, null)\n                                .setPositiveButton(R.string.yes, (dialog, which) -> {\n                                    if (item.type == FmDrawerItem.ITEM_TYPE_LOCATION) {\n                                        mFmActivity.mViewModel.releaseUri(uri);\n                                    } else if (item.type == FmDrawerItem.ITEM_TYPE_FAVORITE) {\n                                        mFmActivity.mViewModel.removeFavorite(item.id);\n                                    }\n                                })\n                                .show();\n                        return true;\n                    });\n                }\n                // Edit item\n                if (item.type == FmDrawerItem.ITEM_TYPE_FAVORITE) {\n                    menu.add(R.string.item_edit).setOnMenuItemClickListener(menuItem -> {\n                        RenameDialogFragment dialog = RenameDialogFragment.getInstance(item.name, (prefix, extension) -> {\n                            String displayName;\n                            if (!TextUtils.isEmpty(extension)) {\n                                displayName = prefix + \".\" + extension;\n                            } else {\n                                displayName = prefix;\n                            }\n                            mFmActivity.mViewModel.renameFavorite(item.id, displayName);\n                        });\n                        dialog.show(mFmActivity.getSupportFragmentManager(), RenameDialogFragment.TAG);\n                        return true;\n                    });\n                }\n                // Properties\n                if (!item.options.isVfs()) {\n                    menu.add(R.string.file_properties).setOnMenuItemClickListener(menuItem -> {\n                        FilePropertiesDialogFragment dialogFragment = FilePropertiesDialogFragment.getInstance(item.options.uri);\n                        dialogFragment.show(mFmActivity.getSupportFragmentManager(), FilePropertiesDialogFragment.TAG);\n                        return true;\n                    });\n                }\n                popupMenu.show();\n                return true;\n            });\n        }\n\n        @Override\n        public int getItemCount() {\n            return mAdapterItems.size();\n        }\n\n        @FmDrawerItem.DrawerItemType\n        @Override\n        public int getItemViewType(int position) {\n            return mAdapterItems.get(position).type;\n        }\n\n        public static class ViewHolder extends RecyclerView.ViewHolder {\n            @Nullable\n            private final AppCompatImageView iconView;\n            private final AppCompatTextView labelView;\n            @Nullable\n            private final MaterialButton actionView;\n\n            public ViewHolder(@NonNull View itemView) {\n                super(itemView);\n                iconView = itemView.findViewById(R.id.item_icon);\n                labelView = itemView.findViewById(R.id.item_title);\n                actionView = itemView.findViewById(R.id.item_action);\n\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/fm/FmAdapter.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.fm;\n\nimport android.text.TextUtils;\nimport android.text.format.Formatter;\nimport android.view.LayoutInflater;\nimport android.view.Menu;\nimport android.view.MenuItem;\nimport android.view.View;\nimport android.view.ViewGroup;\n\nimport androidx.annotation.MainThread;\nimport androidx.annotation.NonNull;\nimport androidx.appcompat.widget.AppCompatTextView;\nimport androidx.appcompat.widget.LinearLayoutCompat;\nimport androidx.appcompat.widget.PopupMenu;\nimport androidx.core.content.ContextCompat;\n\nimport com.google.android.material.button.MaterialButton;\nimport com.google.android.material.card.MaterialCardView;\nimport com.google.android.material.dialog.MaterialAlertDialogBuilder;\nimport com.google.android.material.imageview.ShapeableImageView;\n\nimport java.lang.ref.WeakReference;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Objects;\n\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.fm.dialogs.OpenWithDialogFragment;\nimport io.github.muntashirakon.AppManager.fm.dialogs.RenameDialogFragment;\nimport io.github.muntashirakon.AppManager.fm.icons.FmIconFetcher;\nimport io.github.muntashirakon.AppManager.self.imagecache.ImageLoader;\nimport io.github.muntashirakon.AppManager.utils.DateUtils;\nimport io.github.muntashirakon.AppManager.utils.ThreadUtils;\nimport io.github.muntashirakon.AppManager.utils.UIUtils;\nimport io.github.muntashirakon.AppManager.utils.Utils;\nimport io.github.muntashirakon.io.Path;\nimport io.github.muntashirakon.util.AccessibilityUtils;\nimport io.github.muntashirakon.util.AdapterUtils;\nimport io.github.muntashirakon.widget.MultiSelectionView;\n\nclass FmAdapter extends MultiSelectionView.Adapter<FmAdapter.ViewHolder> {\n    private static final List<String> DEX_EXTENSIONS = Arrays.asList(\"dex\", \"jar\");\n\n    private final List<FmItem> mAdapterList = Collections.synchronizedList(new ArrayList<>());\n    private final FmViewModel mViewModel;\n    private final FmActivity mFmActivity;\n\n    public FmAdapter(FmViewModel viewModel, FmActivity activity) {\n        mViewModel = viewModel;\n        mFmActivity = activity;\n    }\n\n    public void setFmList(List<FmItem> list) {\n        AdapterUtils.notifyDataSetChanged(this, mAdapterList, list);\n        notifySelectionChange();\n    }\n\n    @NonNull\n    @Override\n    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {\n        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_fm, parent, false);\n        View actionView = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_right_standalone_action, parent, false);\n        LinearLayoutCompat layout = view.findViewById(android.R.id.widget_frame);\n        layout.addView(actionView);\n        return new ViewHolder(view);\n    }\n\n    @Override\n    public void onBindViewHolder(@NonNull ViewHolder holder, int position) {\n        FmItem item = mAdapterList.get(position);\n        holder.itemView.setTag(item.path);\n        holder.title.setText(item.getName());\n        // Load attributes\n        cacheAndLoadAttributes(holder, item);\n        if (item.isDirectory) {\n            holder.itemView.setOnClickListener(v -> {\n                if (isInSelectionMode()) {\n                    toggleSelection(position);\n                    AccessibilityUtils.requestAccessibilityFocus(holder.itemView);\n                    return;\n                }\n                mViewModel.loadFiles(item.path.getUri());\n            });\n        } else {\n            holder.itemView.setOnClickListener(v -> {\n                if (isInSelectionMode()) {\n                    toggleSelection(position);\n                    AccessibilityUtils.requestAccessibilityFocus(holder.itemView);\n                    return;\n                }\n                // TODO: 16/11/22 Retrieve default open with from DB and open the file with it\n                OpenWithDialogFragment fragment = OpenWithDialogFragment.getInstance(item.path);\n                fragment.show(mFmActivity.getSupportFragmentManager(), OpenWithDialogFragment.TAG);\n            });\n        }\n        // Symbolic link\n        holder.symbolicLinkIcon.setVisibility(item.path.isSymbolicLink() ? View.VISIBLE : View.GONE);\n        // Set background colors\n        holder.itemView.setCardBackgroundColor(ContextCompat.getColor(holder.itemView.getContext(), android.R.color.transparent));\n        // Set selections\n        holder.icon.setOnClickListener(v -> {\n            toggleSelection(position);\n            AccessibilityUtils.requestAccessibilityFocus(holder.itemView);\n        });\n        // Set actions\n        PopupMenu popupMenu = getPopupMenu(holder.action, item, position);\n        holder.action.setOnClickListener(v -> popupMenu.show());\n        holder.itemView.setOnLongClickListener(v -> {\n            // Long click listener: Select/deselect an app.\n            // 1) Turn selection mode on if this is the first item in the selection list\n            // 2) Select between last selection position and this position (inclusive) if selection mode is on\n            Path lastSelectedItem = mViewModel.getLastSelectedItem();\n            int lastSelectedItemPosition = -1;\n            if (lastSelectedItem != null) {\n                int i = 0;\n                for (FmItem fmItem : mAdapterList) {\n                    if (fmItem.path.equals(lastSelectedItem)) {\n                        lastSelectedItemPosition = i;\n                        break;\n                    }\n                    ++i;\n                }\n            }\n            if (lastSelectedItemPosition >= 0) {\n                // Select from last selection to this selection\n                selectRange(lastSelectedItemPosition, position);\n            } else {\n                toggleSelection(position);\n                AccessibilityUtils.requestAccessibilityFocus(holder.itemView);\n            }\n            return true;\n        });\n        super.onBindViewHolder(holder, position);\n    }\n\n    private void cacheAndLoadAttributes(@NonNull ViewHolder holder, @NonNull FmItem item) {\n        if (item.isCached()) {\n            loadAttributes(holder, item);\n        } else {\n            // TODO: 9/9/23 Store these threads in a list and cancel them when not needed\n            ThreadUtils.postOnBackgroundThread(() -> {\n                WeakReference<ViewHolder> holderRef = new WeakReference<>(holder);\n                WeakReference<FmItem> itemRef = new WeakReference<>(item);\n                item.cache();\n                ThreadUtils.postOnMainThread(() -> {\n                    ViewHolder h = holderRef.get();\n                    FmItem i = itemRef.get();\n                    if (h != null && i != null && Objects.equals(h.itemView.getTag(), i.path)) {\n                        loadAttributes(h, i);\n                    }\n                });\n            });\n        }\n    }\n\n    @MainThread\n    private void loadAttributes(@NonNull ViewHolder holder, @NonNull FmItem item) {\n        // Set icon\n        String tag = item.getTag();\n        holder.icon.setTag(tag);\n        ImageLoader.getInstance().displayImage(tag, holder.icon, new FmIconFetcher(item));\n        // Set sub-icon\n        // TODO: 24/5/23 Set sub-icon if needed\n        // Attrs\n        String modificationDate = DateUtils.formatDateTime(mFmActivity, item.getLastModified());\n        if (item.isDirectory) {\n            holder.subtitle.setText(String.format(Locale.getDefault(), \"%d • %s\", item.getChildCount(),\n                    modificationDate));\n        } else {\n            holder.subtitle.setText(String.format(Locale.getDefault(), \"%s • %s\",\n                    Formatter.formatShortFileSize(mFmActivity, item.getSize()), modificationDate));\n        }\n    }\n\n    @Override\n    public long getItemId(int position) {\n        return mAdapterList.get(position).hashCode();\n    }\n\n    @Override\n    public int getItemCount() {\n        return mAdapterList.size();\n    }\n\n    @Override\n    protected boolean select(int position) {\n        mViewModel.setSelectedItem(mAdapterList.get(position).path, true);\n        return true;\n    }\n\n    @Override\n    protected boolean deselect(int position) {\n        mViewModel.setSelectedItem(mAdapterList.get(position).path, false);\n        return true;\n    }\n\n    @Override\n    protected boolean isSelected(int position) {\n        return mViewModel.isSelected(mAdapterList.get(position).path);\n    }\n\n    @Override\n    protected void cancelSelection() {\n        super.cancelSelection();\n        mViewModel.clearSelections();\n    }\n\n    @Override\n    protected int getSelectedItemCount() {\n        return mViewModel.getSelectedItemCount();\n    }\n\n    @Override\n    protected int getTotalItemCount() {\n        return mAdapterList.size();\n    }\n\n    private PopupMenu getPopupMenu(@NonNull View anchor, @NonNull FmItem item, int position) {\n        PopupMenu popupMenu = new PopupMenu(anchor.getContext(), anchor);\n        popupMenu.setForceShowIcon(true);\n        popupMenu.inflate(R.menu.fragment_fm_item_actions);\n        Menu menu = popupMenu.getMenu();\n        MenuItem openWithAction = menu.findItem(R.id.action_open_with);\n        MenuItem cutAction = menu.findItem(R.id.action_cut);\n        MenuItem copyAction = menu.findItem(R.id.action_copy);\n        MenuItem renameAction = menu.findItem(R.id.action_rename);\n        MenuItem deleteAction = menu.findItem(R.id.action_delete);\n        MenuItem shareAction = menu.findItem(R.id.action_share);\n        MenuItem selectAction = menu.findItem(R.id.action_select);\n        // Disable actions based on criteria\n        boolean canRead = item.path.canRead();\n        boolean canWrite = item.path.canWrite();\n        openWithAction.setEnabled(canRead);\n        cutAction.setEnabled(canRead && canWrite);\n        copyAction.setEnabled(canRead);\n        renameAction.setEnabled(canRead && canWrite);\n        deleteAction.setEnabled(canRead && canWrite);\n        shareAction.setEnabled(canRead);\n        // Set actions\n        openWithAction.setOnMenuItemClickListener(menuItem -> {\n            OpenWithDialogFragment fragment = OpenWithDialogFragment.getInstance(item.path);\n            fragment.show(mFmActivity.getSupportFragmentManager(), OpenWithDialogFragment.TAG);\n            return true;\n        });\n        cutAction.setOnMenuItemClickListener(menuItem -> {\n            FmTasks.FmTask fmTask = new FmTasks.FmTask(FmTasks.FmTask.TYPE_CUT, Collections.singletonList(item.path));\n            FmTasks.getInstance().enqueue(fmTask);\n            UIUtils.displayShortToast(R.string.copied_to_clipboard);\n            return false;\n        });\n        copyAction.setOnMenuItemClickListener(menuItem -> {\n            FmTasks.FmTask fmTask = new FmTasks.FmTask(FmTasks.FmTask.TYPE_COPY, Collections.singletonList(item.path));\n            FmTasks.getInstance().enqueue(fmTask);\n            UIUtils.displayShortToast(R.string.copied_to_clipboard);\n            return false;\n        });\n        renameAction.setOnMenuItemClickListener(menuItem -> {\n            RenameDialogFragment dialog = RenameDialogFragment.getInstance(item.path.getName(), (prefix, extension) -> {\n                String displayName;\n                if (!TextUtils.isEmpty(extension)) {\n                    displayName = prefix + \".\" + extension;\n                } else {\n                    displayName = prefix;\n                }\n                if (item.path.renameTo(displayName)) {\n                    UIUtils.displayShortToast(R.string.renamed_successfully);\n                    mViewModel.reload();\n                } else {\n                    UIUtils.displayShortToast(R.string.failed);\n                }\n            });\n            dialog.show(mFmActivity.getSupportFragmentManager(), RenameDialogFragment.TAG);\n            return false;\n        });\n        deleteAction.setOnMenuItemClickListener(menuItem -> {\n            new MaterialAlertDialogBuilder(mFmActivity)\n                    .setTitle(mFmActivity.getString(R.string.delete_filename, item.path.getName()))\n                    .setMessage(R.string.are_you_sure)\n                    .setNegativeButton(R.string.cancel, null)\n                    .setPositiveButton(R.string.confirm_file_deletion, (dialog, which) -> {\n                        if (item.path.delete()) {\n                            UIUtils.displayShortToast(R.string.deleted_successfully);\n                            mViewModel.reload();\n                        } else {\n                            UIUtils.displayShortToast(R.string.failed);\n                        }\n                    })\n                    .show();\n            return true;\n        });\n        shareAction.setOnMenuItemClickListener(menuItem -> {\n            mViewModel.shareFiles(Collections.singletonList(item.path));\n            return true;\n        });\n        selectAction.setOnMenuItemClickListener(menuItem -> {\n            select(position);\n            notifySelectionChange();\n            notifyItemChanged(position, AdapterUtils.STUB);\n            return true;\n        });\n        boolean isVfs = mViewModel.getOptions().isVfs();\n        menu.findItem(R.id.action_shortcut)\n                // TODO: 31/5/23 Enable creating shortcuts for VFS\n                .setEnabled(!isVfs)\n                .setVisible(!isVfs)\n                .setOnMenuItemClickListener(menuItem -> {\n                    mViewModel.createShortcut(item);\n                    return true;\n                });\n        MenuItem favItem = menu.findItem(R.id.action_add_to_favorites);\n        favItem.setOnMenuItemClickListener(menuItem -> {\n            mViewModel.addToFavorite(item.path, mViewModel.getOptions());\n            return true;\n        });\n        favItem.setEnabled(item.isDirectory);\n        favItem.setVisible(item.isDirectory);\n        menu.findItem(R.id.action_copy_path).setOnMenuItemClickListener(menuItem -> {\n            String path = FmUtils.getDisplayablePath(item.path);\n            Utils.copyToClipboard(mFmActivity, \"Path\", path);\n            return true;\n        });\n        menu.findItem(R.id.action_properties).setOnMenuItemClickListener(menuItem -> {\n            mViewModel.getDisplayPropertiesLiveData().setValue(item.path.getUri());\n            return true;\n        });\n        return popupMenu;\n    }\n\n    protected static class ViewHolder extends MultiSelectionView.ViewHolder {\n        final MaterialCardView itemView;\n        final ShapeableImageView icon;\n        final ShapeableImageView symbolicLinkIcon;\n        final MaterialButton action;\n        final AppCompatTextView title;\n        final AppCompatTextView subtitle;\n\n        public ViewHolder(@NonNull View itemView) {\n            super(itemView);\n            this.itemView = (MaterialCardView) itemView;\n            icon = itemView.findViewById(android.R.id.icon);\n            symbolicLinkIcon = itemView.findViewById(R.id.symbolic_link_icon);\n            action = itemView.findViewById(android.R.id.button1);\n            action.setContentDescription(itemView.getContext().getString(androidx.appcompat.R.string.abc_action_menu_overflow_description));\n            title = itemView.findViewById(android.R.id.title);\n            subtitle = itemView.findViewById(android.R.id.summary);\n            action.setIconResource(io.github.muntashirakon.ui.R.drawable.ic_more_vert);\n            itemView.findViewById(R.id.divider).setVisibility(View.GONE);\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/fm/FmDrawerItem.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.fm;\n\nimport android.graphics.drawable.Drawable;\n\nimport androidx.annotation.ColorInt;\nimport androidx.annotation.DrawableRes;\nimport androidx.annotation.IntDef;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\n\npublic class FmDrawerItem {\n    public static final int ITEM_TYPE_LABEL = 0;\n    public static final int ITEM_TYPE_FAVORITE = 1;\n    public static final int ITEM_TYPE_LOCATION = 2;\n    public static final int ITEM_TYPE_TAG = 3;\n\n    @IntDef({ITEM_TYPE_LABEL, ITEM_TYPE_FAVORITE, ITEM_TYPE_LOCATION, ITEM_TYPE_TAG})\n    @Retention(RetentionPolicy.SOURCE)\n    public @interface DrawerItemType {\n    }\n\n    public final long id;\n    @NonNull\n    public final String name;\n    @Nullable\n    public final FmActivity.Options options;\n    @DrawerItemType\n    public final int type;\n    @DrawableRes\n    public int iconRes;\n    @Nullable\n    public Drawable icon;\n    @ColorInt\n    public int color;\n\n    public FmDrawerItem(long id, @NonNull String name, @Nullable FmActivity.Options options, @DrawerItemType int type) {\n        this.id = id;\n        this.name = name;\n        this.options = options;\n        this.type = type;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/fm/FmFavoritesManager.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.fm;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.WorkerThread;\nimport androidx.lifecycle.LiveData;\nimport androidx.lifecycle.MutableLiveData;\n\nimport java.util.List;\n\nimport io.github.muntashirakon.AppManager.db.AppsDb;\nimport io.github.muntashirakon.AppManager.db.entity.FmFavorite;\nimport io.github.muntashirakon.io.Path;\n\npublic final class FmFavoritesManager {\n\n    private static final MutableLiveData<FmFavorite> sFavoriteAddedLiveData = new MutableLiveData<>();\n\n    public static LiveData<FmFavorite> getFavoriteAddedLiveData() {\n        return sFavoriteAddedLiveData;\n    }\n\n    @WorkerThread\n    public static long addToFavorite(@NonNull Path path, @NonNull FmActivity.Options options) {\n        FmFavorite fmFavorite = new FmFavorite();\n        fmFavorite.name = path.getName();\n        fmFavorite.uri = options.isVfs() ? options.uri.toString() : path.getUri().toString();\n        fmFavorite.initUri = options.isVfs() ? path.getUri().toString() : null;\n        fmFavorite.options = options.options;\n        long id = AppsDb.getInstance().fmFavoriteDao().insert(fmFavorite);\n        sFavoriteAddedLiveData.postValue(fmFavorite);\n        return id;\n    }\n\n    @WorkerThread\n    public static void removeFromFavorite(long id) {\n        AppsDb.getInstance().fmFavoriteDao().delete(id);\n        sFavoriteAddedLiveData.postValue(null);\n    }\n\n    public static void renameFavorite(long id, @NonNull String newName) {\n        AppsDb.getInstance().fmFavoriteDao().rename(id, newName);\n        sFavoriteAddedLiveData.postValue(null);\n    }\n\n    @WorkerThread\n    public static List<FmFavorite> getAllFavorites() {\n        return AppsDb.getInstance().fmFavoriteDao().getAll();\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/fm/FmFragment.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.fm;\n\nimport static io.github.muntashirakon.AppManager.fm.FmTasks.FmTask.TYPE_CUT;\n\nimport android.content.ContentResolver;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.graphics.Bitmap;\nimport android.graphics.drawable.Drawable;\nimport android.net.Uri;\nimport android.os.Bundle;\nimport android.os.SystemClock;\nimport android.provider.DocumentsContract;\nimport android.text.TextUtils;\nimport android.text.format.Formatter;\nimport android.view.LayoutInflater;\nimport android.view.Menu;\nimport android.view.MenuInflater;\nimport android.view.MenuItem;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.view.ViewTreeObserver;\nimport android.widget.ImageView;\nimport android.widget.TextView;\n\nimport androidx.activity.OnBackPressedCallback;\nimport androidx.annotation.DrawableRes;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.WorkerThread;\nimport androidx.appcompat.app.AlertDialog;\nimport androidx.appcompat.widget.LinearLayoutCompat;\nimport androidx.appcompat.widget.SearchView;\nimport androidx.core.content.ContextCompat;\nimport androidx.core.os.BundleCompat;\nimport androidx.core.provider.DocumentsContractCompat;\nimport androidx.core.view.MenuProvider;\nimport androidx.fragment.app.Fragment;\nimport androidx.lifecycle.Lifecycle;\nimport androidx.lifecycle.ViewModelProvider;\nimport androidx.recyclerview.widget.LinearLayoutManager;\n\nimport com.google.android.material.button.MaterialButton;\nimport com.google.android.material.dialog.MaterialAlertDialogBuilder;\nimport com.google.android.material.progressindicator.LinearProgressIndicator;\nimport com.leinardi.android.speeddial.SpeedDialActionItem;\nimport com.leinardi.android.speeddial.SpeedDialView;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.lang.ref.WeakReference;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Objects;\nimport java.util.Optional;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.Future;\nimport java.util.concurrent.atomic.AtomicInteger;\nimport java.util.concurrent.atomic.AtomicReference;\n\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.fm.dialogs.FilePropertiesDialogFragment;\nimport io.github.muntashirakon.AppManager.fm.dialogs.NewFileDialogFragment;\nimport io.github.muntashirakon.AppManager.fm.dialogs.NewFolderDialogFragment;\nimport io.github.muntashirakon.AppManager.fm.dialogs.NewSymbolicLinkDialogFragment;\nimport io.github.muntashirakon.AppManager.fm.dialogs.RenameDialogFragment;\nimport io.github.muntashirakon.AppManager.settings.Prefs;\nimport io.github.muntashirakon.AppManager.settings.SettingsActivity;\nimport io.github.muntashirakon.AppManager.shortcut.CreateShortcutDialogFragment;\nimport io.github.muntashirakon.AppManager.utils.FileUtils;\nimport io.github.muntashirakon.AppManager.utils.ThreadUtils;\nimport io.github.muntashirakon.AppManager.utils.UIUtils;\nimport io.github.muntashirakon.AppManager.utils.Utils;\nimport io.github.muntashirakon.dialog.TextInputDialogBuilder;\nimport io.github.muntashirakon.io.Path;\nimport io.github.muntashirakon.io.Paths;\nimport io.github.muntashirakon.multiselection.MultiSelectionActionsView;\nimport io.github.muntashirakon.util.UiUtils;\nimport io.github.muntashirakon.widget.FloatingActionButtonGroup;\nimport io.github.muntashirakon.widget.MultiSelectionView;\nimport io.github.muntashirakon.widget.RecyclerView;\nimport io.github.muntashirakon.widget.SwipeRefreshLayout;\n\npublic class FmFragment extends Fragment implements MenuProvider, SearchView.OnQueryTextListener,\n        SwipeRefreshLayout.OnRefreshListener, SpeedDialView.OnActionSelectedListener,\n        MultiSelectionActionsView.OnItemSelectedListener,\n        MultiSelectionView.OnSelectionModeChangeListener {\n    public static final String TAG = FmFragment.class.getSimpleName();\n\n    private static final String ARG_URI = \"uri\";\n    public static final String ARG_OPTIONS = \"opt\";\n    public static final String ARG_POSITION = \"pos\";\n\n    @NonNull\n    public static FmFragment getNewInstance(@NonNull FmActivity.Options options,\n                                            @Nullable Integer position) {\n        FmFragment fragment = new FmFragment();\n        Bundle args = new Bundle();\n        args.putParcelable(ARG_OPTIONS, options);\n        if (position != null) {\n            args.putInt(ARG_POSITION, position);\n        }\n        fragment.setArguments(args);\n        return fragment;\n    }\n\n    private FmViewModel mModel;\n    @Nullable\n    private RecyclerView mRecyclerView;\n    private LinearLayoutCompat mEmptyView;\n    private ImageView mEmptyViewIcon;\n    private TextView mEmptyViewTitle;\n    private TextView mEmptyViewDetails;\n    @Nullable\n    private FmAdapter mAdapter;\n    @Nullable\n    private SwipeRefreshLayout mSwipeRefresh;\n    @Nullable\n    private MultiSelectionView mMultiSelectionView;\n    private FloatingActionButtonGroup mFabGroup;\n    private FmPathListAdapter mPathListAdapter;\n    private FmActivity mActivity;\n\n    @Nullable\n    private FolderShortInfo mFolderShortInfo;\n\n    private final ViewTreeObserver.OnGlobalLayoutListener mMultiSelectionViewChangeListener = () -> {\n        if (mFabGroup != null && getActivity() != null) {\n            int defaultMargin = UiUtils.dpToPx(requireContext(), 16);\n            int newMargin;\n            if (mMultiSelectionView.getVisibility() == View.VISIBLE) {\n                newMargin = defaultMargin + mMultiSelectionView.getHeight();\n            } else newMargin = defaultMargin;\n            ViewGroup.MarginLayoutParams marginLayoutParams = (ViewGroup.MarginLayoutParams) mFabGroup.getLayoutParams();\n            if (marginLayoutParams.bottomMargin != newMargin) {\n                marginLayoutParams.bottomMargin = newMargin;\n                mFabGroup.setLayoutParams(marginLayoutParams);\n            }\n        }\n    };\n\n    private final OnBackPressedCallback mExitSelectionBackPressedCallback = new OnBackPressedCallback(false) {\n        @Override\n        public void handleOnBackPressed() {\n            if (mAdapter != null && mMultiSelectionView != null && mAdapter.isInSelectionMode()) {\n                mMultiSelectionView.cancel();\n                return;\n            }\n            setEnabled(false);\n            requireActivity().getOnBackPressedDispatcher().onBackPressed();\n        }\n    };\n    private final OnBackPressedCallback mGoUpBackPressedCallback = new OnBackPressedCallback(false) {\n        @Override\n        public void handleOnBackPressed() {\n            if (mPathListAdapter != null && mPathListAdapter.getCurrentPosition() > 0) {\n                mModel.loadFiles(mPathListAdapter.calculateUri(mPathListAdapter.getCurrentPosition() - 1));\n                return;\n            }\n            setEnabled(false);\n            requireActivity().getOnBackPressedDispatcher().onBackPressed();\n        }\n    };\n\n    @Override\n    public void onCreate(@Nullable Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        mModel = new ViewModelProvider(this).get(FmViewModel.class);\n    }\n\n    @Nullable\n    @Override\n    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {\n        return inflater.inflate(R.layout.fragment_fm, container, false);\n    }\n\n    @Override\n    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {\n        super.onViewCreated(view, savedInstanceState);\n        FmActivity.Options options = null;\n        Uri uri = null;\n        AtomicInteger scrollPosition = new AtomicInteger(RecyclerView.NO_POSITION);\n        if (savedInstanceState != null) {\n            uri = BundleCompat.getParcelable(savedInstanceState, ARG_URI, Uri.class);\n            options = BundleCompat.getParcelable(savedInstanceState, ARG_OPTIONS, FmActivity.Options.class);\n            scrollPosition.set(savedInstanceState.getInt(ARG_POSITION, RecyclerView.NO_POSITION));\n        }\n        if (options == null) {\n            options = Objects.requireNonNull(BundleCompat.getParcelable(requireArguments(), ARG_OPTIONS, FmActivity.Options.class));\n            if (uri == null) {\n                uri = options.getInitUriForVfs();\n            }\n            if (requireArguments().containsKey(ARG_POSITION)) {\n                scrollPosition.set(requireArguments().getInt(ARG_POSITION, RecyclerView.NO_POSITION));\n            }\n        }\n        mActivity = (FmActivity) requireActivity();\n        mSwipeRefresh = view.findViewById(R.id.swipe_refresh);\n        mSwipeRefresh.setOnRefreshListener(this);\n        UiUtils.applyWindowInsetsAsPadding(view.findViewById(R.id.path_container), false, true);\n        RecyclerView pathListView = view.findViewById(R.id.path_list);\n        pathListView.setLayoutManager(new LinearLayoutManager(mActivity, RecyclerView.HORIZONTAL, false));\n        mPathListAdapter = new FmPathListAdapter(mModel);\n        mPathListAdapter.registerAdapterDataObserver(new RecyclerView.AdapterDataObserver() {\n            @Override\n            public void onChanged() {\n                pathListView.setSelection(mPathListAdapter.getCurrentPosition());\n            }\n\n            @Override\n            public void onItemRangeChanged(int positionStart, int itemCount) {\n                onChanged();\n            }\n        });\n        pathListView.setAdapter(mPathListAdapter);\n        MaterialButton pathEditButton = view.findViewById(R.id.uri_edit);\n        pathEditButton.setOnClickListener(v -> {\n            Uri currentUri = mModel.getCurrentUri();\n            String path = currentUri != null ? FmUtils.getDisplayablePath(currentUri) : null;\n            new TextInputDialogBuilder(mActivity, null)\n                    .setTitle(R.string.go_to_path)\n                    .setInputText(path)\n                    .setPositiveButton(R.string.go, (dialog, which, inputText, isChecked) -> {\n                        if (TextUtils.isEmpty(inputText)) {\n                            return;\n                        }\n                        goToRawPath(inputText.toString().trim());\n                    })\n                    .setNegativeButton(R.string.close, null)\n                    .show();\n        });\n        mFabGroup = view.findViewById(R.id.fab);\n        mFabGroup.inflate(R.menu.fragment_fm_speed_dial);\n        mFabGroup.setOnActionSelectedListener(this);\n        mFabGroup.setContentDescription(getString(R.string.add));\n        UiUtils.applyWindowInsetsAsMargin(view.findViewById(R.id.fab_holder));\n        mEmptyView = view.findViewById(android.R.id.empty);\n        mEmptyViewIcon = view.findViewById(R.id.icon);\n        mEmptyViewTitle = view.findViewById(R.id.title);\n        mEmptyViewDetails = view.findViewById(R.id.message);\n        mRecyclerView = view.findViewById(R.id.list_item);\n        mRecyclerView.setLayoutManager(UIUtils.getGridLayoutAt450Dp(mActivity));\n        mAdapter = new FmAdapter(mModel, mActivity);\n        mAdapter.registerAdapterDataObserver(new RecyclerView.AdapterDataChangedObserver() {\n            @Override\n            public void onChanged() {\n                if (mAdapter.isInSelectionMode()) {\n                    // Avoid setting a selection in selection mode (directory cannot be changed\n                    // in selection mode anyway).\n                    return;\n                }\n                if (scrollPosition.get() != RecyclerView.NO_POSITION) {\n                    // Update scroll position\n                    mRecyclerView.setSelection(scrollPosition.get());\n                    scrollPosition.set(RecyclerView.NO_POSITION);\n                } else {\n                    mRecyclerView.setSelection(mModel.getCurrentScrollPosition());\n                }\n            }\n        });\n        mRecyclerView.setAdapter(mAdapter);\n        mRecyclerView.addOnScrollListener(new androidx.recyclerview.widget.RecyclerView.OnScrollListener() {\n            @Override\n            public void onScrolled(@NonNull androidx.recyclerview.widget.RecyclerView recyclerView, int dx, int dy) {\n                if (mFolderShortInfo == null) {\n                    return;\n                }\n                if (dy < 0 && mFolderShortInfo.canWrite && !mFabGroup.isShown()) {\n                    mFabGroup.show();\n                } else if (dy > 0 && mFabGroup.isShown()) {\n                    mFabGroup.hide();\n                }\n            }\n        });\n        mMultiSelectionView = view.findViewById(R.id.selection_view);\n        mMultiSelectionView.setOnItemSelectedListener(this);\n        mMultiSelectionView.setOnSelectionModeChangeListener(this);\n        mMultiSelectionView.setAdapter(mAdapter);\n        mMultiSelectionView.updateCounter(true);\n        mMultiSelectionView.getViewTreeObserver().addOnGlobalLayoutListener(mMultiSelectionViewChangeListener);\n        BatchOpsHandler batchOpsHandler = new BatchOpsHandler(mMultiSelectionView);\n        mMultiSelectionView.setOnSelectionChangeListener(batchOpsHandler);\n        mActivity.addMenuProvider(this, getViewLifecycleOwner(), Lifecycle.State.RESUMED);\n        // Set observer\n        mModel.getLastUriLiveData().observe(getViewLifecycleOwner(), uri1 -> {\n            // force disable empty view\n            if (mEmptyView.isShown()) {\n                mEmptyView.setVisibility(View.GONE);\n            }\n            // Reset subtitle\n            Optional.ofNullable(mActivity.getSupportActionBar()).ifPresent(actionBar ->\n                    actionBar.setSubtitle(R.string.loading));\n            if (uri1 == null) {\n                return;\n            }\n            if (mRecyclerView != null) {\n                View v = mRecyclerView.getChildAt(0);\n                if (v != null) {\n                    mModel.setScrollPosition(uri1, mRecyclerView.getChildAdapterPosition(v));\n                }\n                mAdapter.setFmList(Collections.emptyList());\n            }\n            if (mMultiSelectionView.isShown()) {\n                mMultiSelectionView.cancel();\n            }\n        });\n        mModel.getFmItemsLiveData().observe(getViewLifecycleOwner(), fmItems -> {\n            if (mSwipeRefresh != null) {\n                mSwipeRefresh.setRefreshing(false);\n            }\n            mAdapter.setFmList(fmItems);\n            if (fmItems.isEmpty()) {\n                handleEmptyView(R.drawable.ic_file, getString(R.string.empty_folder), null);\n            }\n        });\n        mModel.getFmErrorLiveData().observe(getViewLifecycleOwner(), throwable -> {\n            if (mSwipeRefresh != null) {\n                mSwipeRefresh.setRefreshing(false);\n            }\n            handleEmptyView(io.github.muntashirakon.ui.R.drawable.ic_caution, throwable.getMessage(), throwable);\n        });\n        mModel.getUriLiveData().observe(getViewLifecycleOwner(), uri1 -> {\n            FmActivity.Options options1 = mModel.getOptions();\n            String alternativeRootName = options1.isVfs() ? options1.uri.getLastPathSegment() : null;\n            Optional.ofNullable(mActivity.getSupportActionBar()).ifPresent(actionBar -> {\n                String title = uri1.getLastPathSegment();\n                if (TextUtils.isEmpty(title)) {\n                    title = alternativeRootName != null ? alternativeRootName : \"Root\";\n                }\n                actionBar.setTitle(title);\n            });\n            if (mSwipeRefresh != null) {\n                mSwipeRefresh.setRefreshing(true);\n            }\n            mPathListAdapter.setCurrentUri(uri1);\n            mPathListAdapter.setAlternativeRootName(alternativeRootName);\n            mGoUpBackPressedCallback.setEnabled(mPathListAdapter.getCurrentPosition() > 0);\n        });\n        mModel.getFolderShortInfoLiveData().observe(getViewLifecycleOwner(), folderShortInfo -> {\n            mFolderShortInfo = folderShortInfo;\n            StringBuilder subtitle = new StringBuilder();\n            // 1. Size\n            if (folderShortInfo.size > 0) {\n                subtitle.append(Formatter.formatShortFileSize(requireContext(), folderShortInfo.size)).append(\" • \");\n            }\n            // 2. Folders and files\n            if (folderShortInfo.folderCount > 0 && folderShortInfo.fileCount > 0) {\n                subtitle.append(getResources().getQuantityString(R.plurals.folder_count, folderShortInfo.folderCount,\n                                folderShortInfo.folderCount))\n                        .append(\", \")\n                        .append(getResources().getQuantityString(R.plurals.file_count, folderShortInfo.fileCount,\n                                folderShortInfo.fileCount));\n            } else if (folderShortInfo.folderCount > 0) {\n                subtitle.append(getResources().getQuantityString(R.plurals.folder_count, folderShortInfo.folderCount,\n                        folderShortInfo.folderCount));\n            } else if (folderShortInfo.fileCount > 0) {\n                subtitle.append(getResources().getQuantityString(R.plurals.file_count, folderShortInfo.fileCount,\n                        folderShortInfo.fileCount));\n            } else {\n                subtitle.append(getString(R.string.empty_folder));\n            }\n            // 3. Mode\n            if (folderShortInfo.canRead || folderShortInfo.canWrite) {\n                subtitle.append(\" • \");\n                if (folderShortInfo.canRead) {\n                    subtitle.append(\"R\");\n                }\n                if (folderShortInfo.canWrite) {\n                    subtitle.append(\"W\");\n                }\n            }\n            if (!folderShortInfo.canWrite) {\n                if (mFabGroup.isShown()) {\n                    mFabGroup.hide();\n                }\n            } else {\n                if (!mFabGroup.isShown()) {\n                    mFabGroup.show();\n                }\n            }\n            Optional.ofNullable(mActivity.getSupportActionBar()).ifPresent(actionBar ->\n                    actionBar.setSubtitle(subtitle)\n            );\n        });\n        mModel.getDisplayPropertiesLiveData().observe(getViewLifecycleOwner(), uri1 -> {\n            FilePropertiesDialogFragment dialogFragment = FilePropertiesDialogFragment.getInstance(uri1);\n            dialogFragment.show(mActivity.getSupportFragmentManager(), FilePropertiesDialogFragment.TAG);\n        });\n        mModel.getShortcutCreatorLiveData().observe(getViewLifecycleOwner(), pathBitmapPair -> {\n            Path path = pathBitmapPair.first;\n            Bitmap icon = pathBitmapPair.second;\n            FmShortcutInfo shortcutInfo = new FmShortcutInfo(path, null);\n            if (icon != null) {\n                shortcutInfo.setIcon(icon);\n            } else {\n                Drawable drawable = Objects.requireNonNull(ContextCompat.getDrawable(requireContext(),\n                        path.isDirectory() ? R.drawable.ic_folder : R.drawable.ic_file));\n                shortcutInfo.setIcon(UIUtils.getBitmapFromDrawable(drawable));\n            }\n            CreateShortcutDialogFragment dialog = CreateShortcutDialogFragment.getInstance(shortcutInfo);\n            dialog.show(getChildFragmentManager(), CreateShortcutDialogFragment.TAG);\n        });\n        mModel.getSharableItemsLiveData().observe(getViewLifecycleOwner(), sharableItems ->\n                mActivity.startActivity(sharableItems.toSharableIntent()));\n        mModel.setOptions(options, uri);\n    }\n\n    @Override\n    public void onStop() {\n        super.onStop();\n        if (mModel != null && mRecyclerView != null) {\n            Prefs.FileManager.setLastOpenedPath(mModel.getOptions(), mModel.getCurrentUri(), getRecyclerViewFirstChildPosition());\n        }\n    }\n\n    @Override\n    public void onDestroyView() {\n        if (mMultiSelectionView != null) {\n            mMultiSelectionView.getViewTreeObserver().removeOnGlobalLayoutListener(mMultiSelectionViewChangeListener);\n        }\n        super.onDestroyView();\n    }\n\n    @Override\n    public void onSaveInstanceState(@NonNull Bundle outState) {\n        if (mModel != null) {\n            outState.putParcelable(ARG_URI, mModel.getCurrentUri());\n            outState.putParcelable(ARG_OPTIONS, mModel.getOptions());\n        }\n        if (mRecyclerView != null) {\n            View v = mRecyclerView.getChildAt(0);\n            if (v != null) {\n                outState.putInt(ARG_POSITION, mRecyclerView.getChildAdapterPosition(v));\n            }\n        }\n    }\n\n    @Override\n    public void onAttach(@NonNull Context context) {\n        super.onAttach(context);\n        // Handle back press: The order MUST be kept same\n        requireActivity().getOnBackPressedDispatcher().addCallback(this, mGoUpBackPressedCallback);\n        requireActivity().getOnBackPressedDispatcher().addCallback(this, mExitSelectionBackPressedCallback);\n    }\n\n    @Override\n    public void onCreateMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) {\n        inflater.inflate(R.menu.activity_fm_actions, menu);\n    }\n\n    @Override\n    public void onPrepareMenu(@NonNull Menu menu) {\n        MenuItem pasteMenu = menu.findItem(R.id.action_paste);\n        if (pasteMenu != null) {\n            FmTasks.FmTask fmTask = FmTasks.getInstance().peek();\n            pasteMenu.setEnabled(mFolderShortInfo != null && fmTask != null && mFolderShortInfo.canWrite && fmTask.canPaste());\n        }\n    }\n\n    @Override\n    public boolean onMenuItemSelected(@NonNull MenuItem item) {\n        int id = item.getItemId();\n        if (id == R.id.action_refresh) {\n            mModel.reload();\n            return true;\n        } else if (id == R.id.action_shortcut) {\n            Uri uri = mPathListAdapter.getCurrentUri();\n            if (uri != null) {\n                mModel.createShortcut(uri);\n            }\n            return true;\n        } else if (id == R.id.action_list_options) {\n            FmListOptions listOptions = new FmListOptions();\n            listOptions.setListOptionActions(mModel);\n            listOptions.show(getChildFragmentManager(), FmListOptions.TAG);\n            return true;\n        } else if (id == R.id.action_paste) {\n            FmTasks.FmTask task = FmTasks.getInstance().dequeue();\n            if (task != null) {\n                startBatchPaste(task);\n            }\n            return true;\n        } else if (id == R.id.action_new_window) {\n            Intent intent = new Intent(mActivity, FmActivity.class);\n            if (!mModel.getOptions().isVfs()) {\n                intent.setDataAndType(mModel.getCurrentUri(), DocumentsContract.Document.MIME_TYPE_DIR);\n            }\n            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT | Intent.FLAG_ACTIVITY_MULTIPLE_TASK);\n            startActivity(intent);\n            return true;\n        } else if (id == R.id.action_add_to_favorites) {\n            Uri uri = mPathListAdapter.getCurrentUri();\n            if (uri != null) {\n                mModel.addToFavorite(Paths.get(uri), mModel.getOptions());\n            }\n            return true;\n        } else if (id == R.id.action_settings) {\n            Intent intent = SettingsActivity.getSettingsIntent(requireContext(), \"files_prefs\");\n            startActivity(intent);\n            return true;\n        }\n        return false;\n    }\n\n    @Override\n    public boolean onActionSelected(@NonNull SpeedDialActionItem actionItem) {\n        int id = actionItem.getId();\n        if (id == R.id.action_file) {\n            NewFileDialogFragment dialog = NewFileDialogFragment.getInstance(this::createNewFile);\n            dialog.show(getChildFragmentManager(), NewFileDialogFragment.TAG);\n        } else if (id == R.id.action_folder) {\n            NewFolderDialogFragment dialog = NewFolderDialogFragment.getInstance(this::createNewFolder);\n            dialog.show(getChildFragmentManager(), NewFolderDialogFragment.TAG);\n        } else if (id == R.id.action_symbolic_link) {\n            Uri uri = mPathListAdapter.getCurrentUri();\n            if (uri == null) {\n                return false;\n            }\n            Path path = Paths.get(uri);\n            if (path.getFile() == null) {\n                UIUtils.displayLongToast(R.string.symbolic_link_not_supported);\n                return false;\n            }\n            NewSymbolicLinkDialogFragment dialog = NewSymbolicLinkDialogFragment.getInstance(this::createNewSymbolicLink);\n            dialog.show(getChildFragmentManager(), NewSymbolicLinkDialogFragment.TAG);\n        }\n        return false;\n    }\n\n    @Override\n    public void onSelectionModeEnabled() {\n        mExitSelectionBackPressedCallback.setEnabled(true);\n    }\n\n    @Override\n    public void onSelectionModeDisabled() {\n        mExitSelectionBackPressedCallback.setEnabled(false);\n    }\n\n    @Override\n    public boolean onNavigationItemSelected(@NonNull MenuItem item) {\n        int id = item.getItemId();\n        List<Path> selectedFiles = mModel.getSelectedItems();\n        if (selectedFiles.isEmpty()) {\n            // Do nothing on empty list\n            return false;\n        }\n        if (id == R.id.action_share) {\n            mModel.shareFiles(selectedFiles);\n        } else if (id == R.id.action_rename) {\n            RenameDialogFragment dialog = RenameDialogFragment.getInstance(null, (prefix, extension) ->\n                    startBatchRenaming(selectedFiles, prefix, extension));\n            dialog.show(getChildFragmentManager(), RenameDialogFragment.TAG);\n        } else if (id == R.id.action_delete) {\n            new MaterialAlertDialogBuilder(mActivity)\n                    .setTitle(R.string.title_confirm_deletion)\n                    .setMessage(R.string.are_you_sure)\n                    .setPositiveButton(R.string.cancel, null)\n                    .setNegativeButton(R.string.confirm_file_deletion, (dialog, which) -> startBatchDeletion(selectedFiles))\n                    .show();\n        } else if (id == R.id.action_cut) {\n            FmTasks.FmTask fmTask = new FmTasks.FmTask(TYPE_CUT, selectedFiles);\n            FmTasks.getInstance().enqueue(fmTask);\n            UIUtils.displayShortToast(R.string.copied_to_clipboard);\n        } else if (id == R.id.action_copy) {\n            FmTasks.FmTask fmTask = new FmTasks.FmTask(FmTasks.FmTask.TYPE_COPY, selectedFiles);\n            FmTasks.getInstance().enqueue(fmTask);\n            UIUtils.displayShortToast(R.string.copied_to_clipboard);\n        } else if (id == R.id.action_copy_path) {\n            List<String> paths = new ArrayList<>(selectedFiles.size());\n            for (Path path : selectedFiles) {\n                paths.add(FmUtils.getDisplayablePath(path));\n            }\n            Utils.copyToClipboard(mActivity, \"Paths\", TextUtils.join(\"\\n\", paths));\n        }\n        return false;\n    }\n\n    @Override\n    public boolean onQueryTextSubmit(String query) {\n        return false;\n    }\n\n    @Override\n    public boolean onQueryTextChange(String newText) {\n        // TODO: 11/7/21\n        return false;\n    }\n\n    @Override\n    public void onRefresh() {\n        if (mModel != null) mModel.reload();\n    }\n\n    public int getRecyclerViewFirstChildPosition() {\n        if (mRecyclerView != null) {\n            View v = mRecyclerView.getChildAt(0);\n            return mRecyclerView.getChildAdapterPosition(v);\n        }\n        return RecyclerView.NO_POSITION;\n    }\n\n    private void goToRawPath(@NonNull String p) {\n        Uri uncheckedUri = Uri.parse(p);\n        if (uncheckedUri.getScheme() != null) {\n            Uri checkedUri = FmUtils.sanitizeContentInput(uncheckedUri);\n            if (checkedUri != null) {\n                // Valid path\n                mModel.loadFiles(checkedUri);\n            } // else bad URI\n            return;\n        }\n        // Bad Uri, consider it to be a file://\n        if (p.startsWith(File.separator)) {\n            // absolute file\n            Uri checkedUri = FmUtils.sanitizeContentInput(uncheckedUri.buildUpon().scheme(ContentResolver.SCHEME_FILE).build());\n            if (checkedUri != null) {\n                mModel.loadFiles(checkedUri);\n            } // else bad file\n            return;\n        }\n        // Relative path\n        String goodPath = Paths.sanitize(p, false);\n        if (goodPath == null || goodPath.equals(File.separator)) {\n            // No relative path means current path which is already loaded\n            return;\n        }\n        Uri currentUri = mModel.getCurrentUri();\n        if (DocumentsContractCompat.isDocumentUri(requireContext(), currentUri)) {\n            List<String> pathSegments = currentUri.getPathSegments();\n            if (pathSegments.size() == 4) {\n                // For a tree URI, the 3rd index is the path\n                String lastPathSegment = pathSegments.get(3) + File.separator + goodPath;\n                Uri.Builder b = new Uri.Builder()\n                        .scheme(currentUri.getScheme())\n                        .authority(currentUri.getAuthority())\n                        .appendPath(pathSegments.get(0))\n                        .appendPath(pathSegments.get(1))\n                        .appendPath(pathSegments.get(2))\n                        .appendPath(lastPathSegment);\n                mModel.loadFiles(b.build());\n            }\n            // Other document Uris don't support navigation nor do they support folders/trees\n            return;\n        }\n        // For others, simply append path segments at the end\n        @SuppressWarnings(\"SuspiciousRegexArgument\") // We aren't on Windows\n        String[] segments = goodPath.split(File.separator);\n        Uri.Builder b = currentUri.buildUpon();\n        for (String segment : segments) {\n            b.appendPath(segment);\n        }\n        mModel.loadFiles(b.build());\n    }\n\n    private void handleEmptyView(@DrawableRes int icon, @Nullable CharSequence title, @Nullable Throwable th) {\n        if (!mEmptyView.isShown()) {\n            mEmptyView.setVisibility(View.VISIBLE);\n        }\n        mEmptyViewIcon.setImageResource(icon);\n        mEmptyViewTitle.setText(title);\n        if (th == null) {\n            mEmptyViewDetails.setVisibility(View.GONE);\n            return;\n        }\n        // Only log the first three lines\n        StackTraceElement[] arr = th.getStackTrace();\n        StringBuilder report = new StringBuilder(th + \"\\n\");\n        int i = 0;\n        for (StackTraceElement traceElement : arr) {\n            if (i == 3) break;\n            report.append(\"    at \").append(traceElement.toString()).append(\"\\n\");\n            ++i;\n        }\n        Throwable cause = th;\n        while ((cause = cause.getCause()) != null) {\n            report.append(\" Caused by: \").append(cause).append(\"\\n\");\n            arr = cause.getStackTrace();\n            i = 0;\n            for (StackTraceElement stackTraceElement : arr) {\n                if (i == 3) break;\n                report.append(\"   at \").append(stackTraceElement.toString()).append(\"\\n\");\n                ++i;\n            }\n        }\n        mEmptyViewDetails.setVisibility(View.VISIBLE);\n        mEmptyViewDetails.setText(report);\n    }\n\n    private void createNewFolder(String name) {\n        Uri uri = mPathListAdapter.getCurrentUri();\n        if (uri == null) {\n            return;\n        }\n        Path path = Paths.get(uri);\n        String displayName = findNextBestDisplayName(path, name, null);\n        try {\n            Path newDir = path.createNewDirectory(displayName);\n            UIUtils.displayShortToast(R.string.done);\n            mModel.reload(newDir.getName());\n        } catch (IOException e) {\n            e.printStackTrace();\n            UIUtils.displayShortToast(R.string.failed);\n        }\n    }\n\n    private void createNewFile(String prefix, @Nullable String extension, String template) {\n        Uri uri = mPathListAdapter.getCurrentUri();\n        if (uri == null) {\n            return;\n        }\n        Path path = Paths.get(uri);\n        String displayName = findNextBestDisplayName(path, prefix, extension);\n        try {\n            Path newFile = path.createNewFile(displayName, null);\n            FileUtils.copyFromAsset(requireContext(), \"blanks/\" + template, newFile);\n            UIUtils.displayShortToast(R.string.done);\n            mModel.reload(newFile.getName());\n        } catch (IOException e) {\n            e.printStackTrace();\n            UIUtils.displayShortToast(R.string.failed);\n        }\n    }\n\n    private void createNewSymbolicLink(String prefix, @Nullable String extension, String targetPath) {\n        Uri uri = mPathListAdapter.getCurrentUri();\n        if (uri == null) {\n            return;\n        }\n        Path basePath = Paths.get(uri);\n        String displayName = findNextBestDisplayName(basePath, prefix, extension);\n        Path sourcePath = Paths.build(basePath, displayName);\n        if (sourcePath != null && sourcePath.createNewSymbolicLink(targetPath)) {\n            UIUtils.displayShortToast(R.string.done);\n            mModel.reload(sourcePath.getName());\n        } else {\n            UIUtils.displayShortToast(R.string.failed);\n        }\n    }\n\n    private void startBatchDeletion(@NonNull List<Path> paths) {\n        // TODO: 27/6/23 Ideally, these should be done in a bound service\n        AtomicReference<Future<?>> deletionThread = new AtomicReference<>();\n        View view = View.inflate(requireContext(), R.layout.dialog_progress, null);\n        LinearProgressIndicator progress = view.findViewById(R.id.progress_linear);\n        TextView label = view.findViewById(android.R.id.text1);\n        TextView counter = view.findViewById(android.R.id.text2);\n        counter.setText(String.format(Locale.getDefault(), \"%d/%d\", 0, paths.size()));\n        AlertDialog dialog = new MaterialAlertDialogBuilder(requireContext())\n                .setTitle(R.string.delete)\n                .setView(view)\n                .setPositiveButton(R.string.action_stop_service, (dialog1, which) -> {\n                    if (deletionThread.get() != null) {\n                        deletionThread.get().cancel(true);\n                    }\n                })\n                .setCancelable(false)\n                .show();\n        deletionThread.set(ThreadUtils.postOnBackgroundThread(() -> {\n            WeakReference<LinearProgressIndicator> progressRef = new WeakReference<>(progress);\n            WeakReference<TextView> labelRef = new WeakReference<>(label);\n            WeakReference<TextView> counterRef = new WeakReference<>(counter);\n            WeakReference<AlertDialog> dialogRef = new WeakReference<>(dialog);\n            try {\n                LinearProgressIndicator p = progressRef.get();\n                if (p != null) {\n                    p.setMax(paths.size());\n                    p.setProgress(0);\n                    p.setIndeterminate(false);\n                }\n                int i = 1;\n                for (Path path : paths) {\n                    // Update label\n                    TextView l = labelRef.get();\n                    if (l != null) {\n                        ThreadUtils.postOnMainThread(() -> l.setText(path.getName()));\n                    }\n                    if (ThreadUtils.isInterrupted()) {\n                        break;\n                    }\n                    // Sleep, delete, progress\n                    SystemClock.sleep(2_000);\n                    if (ThreadUtils.isInterrupted()) {\n                        break;\n                    }\n                    path.delete();\n                    TextView c = counterRef.get();\n                    int finalI = i;\n                    ThreadUtils.postOnMainThread(() -> {\n                        if (c != null) {\n                            c.setText(String.format(Locale.getDefault(), \"%d/%d\", finalI, paths.size()));\n                        }\n                        if (p != null) {\n                            p.setProgress(finalI);\n                        }\n                    });\n                    ++i;\n                    if (ThreadUtils.isInterrupted()) {\n                        break;\n                    }\n                }\n            } finally {\n                AlertDialog d = dialogRef.get();\n                if (d != null) {\n                    ThreadUtils.postOnMainThread(() -> {\n                        d.dismiss();\n                        UIUtils.displayShortToast(R.string.deleted_successfully);\n                        mModel.reload();\n                    });\n                }\n            }\n        }));\n    }\n\n    private void startBatchRenaming(List<Path> paths, String prefix, @Nullable String extension) {\n        AtomicReference<Future<?>> renameThread = new AtomicReference<>();\n        View view = View.inflate(requireContext(), R.layout.dialog_progress, null);\n        LinearProgressIndicator progress = view.findViewById(R.id.progress_linear);\n        TextView label = view.findViewById(android.R.id.text1);\n        TextView counter = view.findViewById(android.R.id.text2);\n        counter.setText(String.format(Locale.getDefault(), \"%d/%d\", 0, paths.size()));\n        AlertDialog dialog = new MaterialAlertDialogBuilder(requireContext())\n                .setTitle(R.string.rename)\n                .setView(view)\n                .setPositiveButton(R.string.action_stop_service, (dialog1, which) -> {\n                    if (renameThread.get() != null) {\n                        renameThread.get().cancel(true);\n                    }\n                })\n                .setCancelable(false)\n                .show();\n        renameThread.set(ThreadUtils.postOnBackgroundThread(() -> {\n            WeakReference<LinearProgressIndicator> progressRef = new WeakReference<>(progress);\n            WeakReference<TextView> labelRef = new WeakReference<>(label);\n            WeakReference<TextView> counterRef = new WeakReference<>(counter);\n            WeakReference<AlertDialog> dialogRef = new WeakReference<>(dialog);\n            try {\n                LinearProgressIndicator p = progressRef.get();\n                if (p != null) {\n                    p.setMax(paths.size());\n                    p.setProgress(0);\n                    p.setIndeterminate(false);\n                }\n                int i = 1;\n                for (Path path : paths) {\n                    // Update label\n                    TextView l = labelRef.get();\n                    if (l != null) {\n                        ThreadUtils.postOnMainThread(() -> l.setText(path.getName()));\n                    }\n                    if (ThreadUtils.isInterrupted()) {\n                        break;\n                    }\n                    // Sleep, rename, progress\n                    SystemClock.sleep(2_000);\n                    if (ThreadUtils.isInterrupted()) {\n                        break;\n                    }\n                    Path basePath = path.getParent();\n                    if (basePath != null) {\n                        String displayName = findNextBestDisplayName(basePath, prefix, extension, i);\n                        path.renameTo(displayName);\n                    }\n                    TextView c = counterRef.get();\n                    int finalI = i;\n                    ThreadUtils.postOnMainThread(() -> {\n                        if (c != null) {\n                            c.setText(String.format(Locale.getDefault(), \"%d/%d\", finalI, paths.size()));\n                        }\n                        if (p != null) {\n                            p.setProgress(finalI);\n                        }\n                    });\n                    ++i;\n                    if (ThreadUtils.isInterrupted()) {\n                        break;\n                    }\n                }\n            } finally {\n                AlertDialog d = dialogRef.get();\n                if (d != null) {\n                    ThreadUtils.postOnMainThread(() -> {\n                        d.dismiss();\n                        UIUtils.displayShortToast(R.string.renamed_successfully);\n                        mModel.reload();\n                    });\n                }\n            }\n        }));\n    }\n\n    private void startBatchPaste(@NonNull FmTasks.FmTask task) {\n        Uri uri = mPathListAdapter.getCurrentUri();\n        if (uri == null) {\n            return;\n        }\n        AtomicReference<Future<?>> pasteThread = new AtomicReference<>();\n        View view = View.inflate(requireContext(), R.layout.dialog_progress, null);\n        LinearProgressIndicator progress = view.findViewById(R.id.progress_linear);\n        TextView label = view.findViewById(android.R.id.text1);\n        TextView counter = view.findViewById(android.R.id.text2);\n        counter.setText(String.format(Locale.getDefault(), \"%d/%d\", 0, task.files.size()));\n        AlertDialog dialog = new MaterialAlertDialogBuilder(requireContext())\n                .setTitle(R.string.paste)\n                .setView(view)\n                .setPositiveButton(R.string.action_stop_service, (dialog1, which) -> {\n                    if (pasteThread.get() != null) {\n                        pasteThread.get().cancel(true);\n                    }\n                })\n                .setCancelable(false)\n                .show();\n        pasteThread.set(ThreadUtils.postOnBackgroundThread(() -> {\n            WeakReference<LinearProgressIndicator> progressRef = new WeakReference<>(progress);\n            WeakReference<TextView> labelRef = new WeakReference<>(label);\n            WeakReference<TextView> counterRef = new WeakReference<>(counter);\n            WeakReference<AlertDialog> dialogRef = new WeakReference<>(dialog);\n            Path targetPath = Paths.get(uri);\n            try {\n                LinearProgressIndicator p = progressRef.get();\n                if (p != null) {\n                    p.setMax(task.files.size());\n                    p.setProgress(0);\n                    p.setIndeterminate(false);\n                }\n                int i = 1;\n                for (Path sourcePath : task.files) {\n                    // Update label\n                    TextView l = labelRef.get();\n                    if (l != null) {\n                        ThreadUtils.postOnMainThread(() -> l.setText(sourcePath.getName()));\n                    }\n                    if (ThreadUtils.isInterrupted()) {\n                        break;\n                    }\n                    // Sleep, copy, progress\n                    SystemClock.sleep(2_000);\n                    if (ThreadUtils.isInterrupted()) {\n                        break;\n                    }\n                    if (!copy(sourcePath, targetPath)) {\n                        // Failed to copy, abort\n                        ThreadUtils.postOnMainThread(() -> new MaterialAlertDialogBuilder(requireContext())\n                                .setTitle(R.string.error)\n                                .setMessage(getString(R.string.failed_to_copy_specified_file, sourcePath.getName()))\n                                .setPositiveButton(R.string.close, null)\n                                .show());\n                        return;\n                    }\n                    if (task.type == TYPE_CUT) {\n                        if (!sourcePath.delete()) {\n                            // Failed to move, abort\n                            ThreadUtils.postOnMainThread(() -> new MaterialAlertDialogBuilder(requireContext())\n                                    .setTitle(R.string.error)\n                                    .setMessage(getString(R.string.failed_to_delete_specified_file_after_copying, sourcePath.getName()))\n                                    .setPositiveButton(R.string.close, null)\n                                    .show());\n                            return;\n                        }\n                    }\n                    TextView c = counterRef.get();\n                    int finalI = i;\n                    ThreadUtils.postOnMainThread(() -> {\n                        if (c != null) {\n                            c.setText(String.format(Locale.getDefault(), \"%d/%d\", finalI, task.files.size()));\n                        }\n                        if (p != null) {\n                            p.setProgress(finalI);\n                        }\n                    });\n                    ++i;\n                    if (ThreadUtils.isInterrupted()) {\n                        break;\n                    }\n                }\n                UIUtils.displayShortToast(task.type == TYPE_CUT ? R.string.moved_successfully : R.string.copied_successfully);\n            } finally {\n                AlertDialog d = dialogRef.get();\n                if (d != null) {\n                    ThreadUtils.postOnMainThread(() -> {\n                        d.dismiss();\n                        mModel.reload();\n                    });\n                }\n            }\n        }));\n    }\n\n    @WorkerThread\n    private boolean copy(Path source, Path dest) {\n        String name = source.getName();\n        if (dest.hasFile(name)) {\n            // Duplicate found. Ask user for what to do.\n            CountDownLatch waitForUser = new CountDownLatch(1);\n            AtomicReference<Boolean> keepBoth = new AtomicReference<>(null);\n            ThreadUtils.postOnMainThread(() -> new MaterialAlertDialogBuilder(requireContext())\n                    .setTitle(R.string.conflict_detected_while_copying)\n                    .setMessage(getString(R.string.conflict_detected_while_copying_message, name))\n                    .setCancelable(false)\n                    .setOnDismissListener(dialog -> waitForUser.countDown())\n                    .setPositiveButton(R.string.replace, (dialog, which) -> keepBoth.set(false))\n                    .setNegativeButton(R.string.action_stop_service, (dialog, which) -> keepBoth.set(null))\n                    .setNeutralButton(R.string.copy_keep_both_file, (dialog, which) -> keepBoth.set(true))\n                    .show());\n            try {\n                waitForUser.await();\n            } catch (InterruptedException ignore) {\n            }\n            if (keepBoth.get() == null) {\n                // Abort copying\n                return false;\n            }\n            if (keepBoth.get()) {\n                // Keep both\n                String prefix;\n                String extension;\n                if (!source.isDirectory()) {\n                    prefix = Paths.trimPathExtension(name);\n                    extension = Paths.getPathExtension(name);\n                } else {\n                    prefix = name;\n                    extension = null;\n                }\n                String newName = findNextBestDisplayName(dest, prefix, extension);\n                try {\n                    Path newPath = source.isDirectory() ? dest.createNewDirectory(newName) : dest.createNewFile(newName, null);\n                    // Need to create that path again\n                    newPath.delete();\n                    return source.copyTo(newPath) != null;\n                } catch (IOException e) {\n                    e.printStackTrace();\n                    return false;\n                }\n            } else {\n                // Overwrite\n                return source.copyTo(dest, true) != null;\n            }\n        }\n        // Simply copy\n        return source.copyTo(dest, false) != null;\n    }\n\n    private String findNextBestDisplayName(@NonNull Path basePath, @NonNull String prefix, @Nullable String extension) {\n        return findNextBestDisplayName(basePath, prefix, extension, 1);\n    }\n\n    private String findNextBestDisplayName(@NonNull Path basePath, @NonNull String prefix, @Nullable String extension, int startIndex) {\n        if (TextUtils.isEmpty(extension)) {\n            extension = \"\";\n        } else extension = \".\" + extension;\n        String displayName = prefix + extension;\n        int i = startIndex;\n        // We need to find the next best file name if current exists\n        while (basePath.hasFile(displayName)) {\n            displayName = String.format(Locale.ROOT, \"%s (%d)%s\", prefix, i, extension);\n            ++i;\n        }\n        return displayName;\n    }\n\n    private class BatchOpsHandler implements MultiSelectionView.OnSelectionChangeListener {\n        private final MenuItem mShareMenu;\n        private final MenuItem mRenameMenu;\n        private final MenuItem mDeleteMenu;\n        private final MenuItem mCutMenu;\n        private final MenuItem mCopyMenu;\n        private final MenuItem mCopyPathsMenu;\n\n        public BatchOpsHandler(@NonNull MultiSelectionView multiSelectionView) {\n            Menu menu = multiSelectionView.getMenu();\n            mShareMenu = menu.findItem(R.id.action_share);\n            mRenameMenu = menu.findItem(R.id.action_rename);\n            mDeleteMenu = menu.findItem(R.id.action_delete);\n            mCutMenu = menu.findItem(R.id.action_cut);\n            mCopyMenu = menu.findItem(R.id.action_copy);\n            mCopyPathsMenu = menu.findItem(R.id.action_copy_path);\n        }\n\n        @Override\n        public boolean onSelectionChange(int selectionCount) {\n            boolean nonZeroSelection = selectionCount > 0;\n            boolean canRead = mFolderShortInfo != null && mFolderShortInfo.canRead;\n            boolean canWrite = mFolderShortInfo != null && mFolderShortInfo.canWrite;\n            mShareMenu.setEnabled(nonZeroSelection && canRead);\n            mRenameMenu.setEnabled(nonZeroSelection && canWrite);\n            mDeleteMenu.setEnabled(nonZeroSelection && canWrite);\n            mCutMenu.setEnabled(nonZeroSelection && canWrite);\n            mCopyMenu.setEnabled(nonZeroSelection && canRead);\n            mCopyPathsMenu.setEnabled(nonZeroSelection);\n            return false;\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/fm/FmItem.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.fm;\n\nimport android.util.Base64;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport java.io.IOException;\nimport java.nio.charset.StandardCharsets;\nimport java.util.Objects;\n\nimport io.github.muntashirakon.AppManager.utils.ThreadUtils;\nimport io.github.muntashirakon.io.Path;\nimport io.github.muntashirakon.io.PathAttributes;\nimport io.github.muntashirakon.io.PathContentInfo;\n\npublic class FmItem implements Comparable<FmItem> {\n    public static final int UNRESOLVED = -2;\n\n    final boolean isDirectory;\n    @NonNull\n    public final Path path;\n\n    @Nullable\n    private String mTag;\n    @Nullable\n    private PathContentInfo mContentInfo;\n    @Nullable\n    private PathAttributes mAttributes;\n    @Nullable\n    private String mName;\n    private int mChildCount = UNRESOLVED;\n    private boolean mCached = false;\n\n    public FmItem(@NonNull Path path) {\n        this.path = path;\n        isDirectory = path.isDirectory();\n    }\n\n    FmItem(@NonNull Path path, @NonNull PathAttributes attributes) {\n        this.path = path;\n        mAttributes = attributes;\n        mName = mAttributes.name;\n        isDirectory = mAttributes.isDirectory;\n    }\n\n    @NonNull\n    public String getTag() {\n        if (mTag == null) {\n            mTag = \"fm_\" + Base64.encodeToString(path.toString().getBytes(StandardCharsets.UTF_8), Base64.NO_WRAP);\n        }\n        return mTag;\n    }\n\n    @NonNull\n    public String getName() {\n        if (mName != null) {\n            return mName;\n        }\n        if (mAttributes != null) {\n            return mAttributes.name;\n        }\n        return path.getName();\n    }\n\n    public long getLastModified() {\n        if (mAttributes != null) {\n            return mAttributes.lastModified;\n        }\n        return path.lastModified();\n    }\n\n    public long getSize() {\n        if (mAttributes != null) {\n            return mAttributes.size;\n        }\n        return path.length();\n    }\n\n    public int getChildCount() {\n        if (!isDirectory) {\n            return 0;\n        }\n        if (mChildCount == UNRESOLVED) {\n            mChildCount = path.listFiles().length;\n        }\n        return mChildCount;\n    }\n\n    @Nullable\n    public PathContentInfo getContentInfo() {\n        return mContentInfo;\n    }\n\n    public void setContentInfo(@Nullable PathContentInfo contentInfo) {\n        this.mContentInfo = contentInfo;\n    }\n\n    public void cache() {\n        try {\n            getTag();\n            fetchAttributes();\n            if (ThreadUtils.isInterrupted()) {\n                return;\n            }\n            if (isDirectory) {\n                getChildCount();\n            } else mChildCount = 0;\n        } finally {\n            mCached = true;\n        }\n    }\n\n    public boolean isCached() {\n        return mCached;\n    }\n\n    private void fetchAttributes() {\n        try {\n            // WARNING: The attributes can be changed in SAF anytime from anywhere.\n            // But we don't care because speed matters more.\n            mAttributes = path.getAttributes();\n            mName = mAttributes.name;\n        } catch (IOException e) {\n            e.printStackTrace();\n            mName = path.getName();\n        }\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) return true;\n        if (!(o instanceof FmItem)) return false;\n        FmItem item = (FmItem) o;\n        return path.equals(item.path);\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hash(path);\n    }\n\n    @Override\n    public int compareTo(FmItem o) {\n        if (equals(o)) return 0;\n        int typeComp = -Boolean.compare(isDirectory, o.isDirectory);\n        if (typeComp == 0) {\n            return path.getName().compareToIgnoreCase(o.path.getName());\n        } else return typeComp;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/fm/FmListOptions.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.fm;\n\nimport androidx.annotation.IntDef;\nimport androidx.annotation.Nullable;\n\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.util.LinkedHashMap;\n\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.misc.ListOptions;\n\npublic class FmListOptions extends ListOptions {\n    public static final String TAG = FmListOptions.class.getSimpleName();\n\n    @IntDef({SORT_BY_NAME, SORT_BY_LAST_MODIFIED, SORT_BY_SIZE, SORT_BY_TYPE})\n    @Retention(RetentionPolicy.SOURCE)\n    public @interface SortOrder {\n    }\n\n    public static final int SORT_BY_NAME = 0;\n    public static final int SORT_BY_LAST_MODIFIED = 1;\n    public static final int SORT_BY_SIZE = 2;\n    public static final int SORT_BY_TYPE = 3;\n\n    @IntDef(flag = true, value = {OPTIONS_DISPLAY_DOT_FILES, OPTIONS_FOLDERS_FIRST})\n    @Retention(RetentionPolicy.SOURCE)\n    public @interface Options {\n    }\n\n    public static final int OPTIONS_DISPLAY_DOT_FILES = 1 << 0;\n    public static final int OPTIONS_FOLDERS_FIRST = 1 << 1;\n    public static final int OPTIONS_ONLY_FOR_THIS_FOLDER = 1 << 2; // TODO: 11/12/22\n\n    private static final LinkedHashMap<Integer, Integer> SORT_ITEMS_MAP = new LinkedHashMap<Integer, Integer>() {{\n        put(SORT_BY_NAME, R.string.sort_by_filename);\n        put(SORT_BY_LAST_MODIFIED, R.string.sort_by_last_modified);\n        put(SORT_BY_SIZE, R.string.sort_by_file_size);\n        put(SORT_BY_TYPE, R.string.sort_by_file_type);\n    }};\n\n    private static final LinkedHashMap<Integer, Integer> OPTIONS_MAP = new LinkedHashMap<Integer, Integer>() {{\n        put(OPTIONS_DISPLAY_DOT_FILES, R.string.option_display_dot_files);\n        put(OPTIONS_FOLDERS_FIRST, R.string.option_display_folders_on_top);\n    }};\n\n    @Nullable\n    @Override\n    public LinkedHashMap<Integer, Integer> getSortIdLocaleMap() {\n        return SORT_ITEMS_MAP;\n    }\n\n    @Nullable\n    @Override\n    public LinkedHashMap<Integer, Integer> getFilterFlagLocaleMap() {\n        return null;\n    }\n\n    @Nullable\n    @Override\n    public LinkedHashMap<Integer, Integer> getOptionIdLocaleMap() {\n        return OPTIONS_MAP;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/fm/FmPathListAdapter.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.fm;\n\nimport android.content.Context;\nimport android.content.Intent;\nimport android.net.Uri;\nimport android.provider.DocumentsContract;\nimport android.view.LayoutInflater;\nimport android.view.Menu;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.TextView;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.appcompat.widget.PopupMenu;\nimport androidx.recyclerview.widget.RecyclerView;\n\nimport com.google.android.material.color.MaterialColors;\n\nimport java.io.File;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Objects;\n\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.io.Paths;\nimport io.github.muntashirakon.util.AdapterUtils;\nimport io.github.muntashirakon.AppManager.utils.Utils;\n\nclass FmPathListAdapter extends RecyclerView.Adapter<FmPathListAdapter.PathHolder> {\n    private final FmViewModel mViewModel;\n    private final List<String> mPathParts = Collections.synchronizedList(new ArrayList<>());\n    @Nullable\n    private String mAlternativeRootName = null;\n    private int mCurrentPosition = -1;\n    @Nullable\n    private Uri mCurrentUri;\n\n    FmPathListAdapter(FmViewModel viewModel) {\n        mViewModel = viewModel;\n    }\n\n    public void setCurrentUri(@NonNull Uri currentUri) {\n        Uri lastPath = mCurrentUri;\n        String lastPathStr = lastPath != null ? lastPath.toString() : null;\n        mCurrentUri = currentUri;\n        List<String> paths = FmUtils.uriToPathParts(currentUri);\n        String currentPathStr = currentUri.toString();\n        if (!currentPathStr.endsWith(File.separator)) {\n            currentPathStr += File.separator;\n        }\n        // Two cases:\n        // 1. currentPath is a subset of lastPath, update currentPosition\n        // 2. Otherwise, alter pathParts and set (length - 1) as the currentPosition\n        if (lastPathStr != null && lastPathStr.startsWith(currentPathStr)) {\n            // Case 1\n            setCurrentPosition(paths.size() - 1);\n        } else {\n            // Case 2\n            mCurrentPosition = paths.size() - 1;\n            AdapterUtils.notifyDataSetChanged(this, mPathParts, paths);\n        }\n    }\n\n    public void setAlternativeRootName(@Nullable String alternativeRootName) {\n        mAlternativeRootName = alternativeRootName;\n    }\n\n    @Nullable\n    public Uri getCurrentUri() {\n        return mCurrentUri;\n    }\n\n    public int getCurrentPosition() {\n        return mCurrentPosition;\n    }\n\n    public Uri calculateUri(int position) {\n        return FmUtils.uriFromPathParts(Objects.requireNonNull(mCurrentUri), mPathParts, position);\n    }\n\n    private void setCurrentPosition(int currentPosition) {\n        int lastPosition = mCurrentPosition;\n        mCurrentPosition = currentPosition;\n        if (lastPosition >= 0) {\n            notifyItemChanged(lastPosition, AdapterUtils.STUB);\n        }\n        notifyItemChanged(currentPosition, AdapterUtils.STUB);\n    }\n\n    @NonNull\n    @Override\n    public PathHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {\n        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_path, parent, false);\n        return new PathHolder(view);\n    }\n\n    @Override\n    public void onBindViewHolder(@NonNull PathHolder holder, int position) {\n        String actualPathPart = mPathParts.get(position);\n        String pathPart;\n        if (position == 0) {\n            pathPart = mAlternativeRootName != null ? mAlternativeRootName : actualPathPart;\n        } else pathPart = \"» \" + actualPathPart;\n        holder.textView.setText(pathPart);\n        if (position == 0 && pathPart.equals(\"/\")) {\n            holder.itemView.setContentDescription(holder.itemView.getContext().getString(R.string.root));\n        } else holder.itemView.setContentDescription(actualPathPart);\n        holder.itemView.setOnClickListener(v -> {\n            if (mCurrentPosition != position) {\n                mViewModel.loadFiles(calculateUri(position));\n            }\n        });\n        holder.itemView.setOnLongClickListener(v -> {\n            Context context = v.getContext();\n            PopupMenu popupMenu = new PopupMenu(context, v);\n            Menu menu = popupMenu.getMenu();\n            // Copy path\n            menu.add(R.string.copy_this_path)\n                    .setOnMenuItemClickListener(menuItem -> {\n                        String path = FmUtils.getDisplayablePath(calculateUri(position));\n                        Utils.copyToClipboard(context, \"Path\", path);\n                        return true;\n                    });\n            // Open in new window\n            menu.add(R.string.open_in_new_window)\n                    .setOnMenuItemClickListener(menuItem -> {\n                        Intent intent = new Intent(context, FmActivity.class);\n                        intent.setDataAndType(calculateUri(position), DocumentsContract.Document.MIME_TYPE_DIR);\n                        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT | Intent.FLAG_ACTIVITY_MULTIPLE_TASK);\n                        context.startActivity(intent);\n                        return true;\n                    });\n            // Add to favorites\n            menu.add(R.string.add_to_favorites)\n                    .setOnMenuItemClickListener(item -> {\n                        mViewModel.addToFavorite(Paths.get(calculateUri(position)), mViewModel.getOptions());\n                        return true;\n                    });\n            // Properties\n            menu.add(R.string.file_properties)\n                    .setOnMenuItemClickListener(menuItem -> {\n                        mViewModel.getDisplayPropertiesLiveData().setValue(calculateUri(position));\n                        return true;\n                    });\n            popupMenu.show();\n            return true;\n        });\n        holder.textView.setTextColor(mCurrentPosition == position\n                ? MaterialColors.getColor(holder.textView, androidx.appcompat.R.attr.colorPrimary)\n                : MaterialColors.getColor(holder.textView, android.R.attr.textColorSecondary));\n    }\n\n    @Override\n    public int getItemCount() {\n        return mPathParts.size();\n    }\n\n    public static class PathHolder extends RecyclerView.ViewHolder {\n        public final TextView textView;\n\n        public PathHolder(@NonNull View itemView) {\n            super(itemView);\n            this.textView = itemView.findViewById(android.R.id.text1);\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/fm/FmProvider.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.fm;\n\nimport android.content.ContentProvider;\nimport android.content.ContentResolver;\nimport android.content.ContentValues;\nimport android.content.Context;\nimport android.content.pm.ProviderInfo;\nimport android.database.Cursor;\nimport android.database.MatrixCursor;\nimport android.net.Uri;\nimport android.os.Binder;\nimport android.os.Build;\nimport android.os.Handler;\nimport android.os.HandlerThread;\nimport android.os.ParcelFileDescriptor;\nimport android.os.Process;\nimport android.provider.DocumentsContract;\nimport android.provider.MediaStore;\nimport android.provider.OpenableColumns;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.VisibleForTesting;\n\nimport java.io.File;\nimport java.io.FileNotFoundException;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.Objects;\n\nimport io.github.muntashirakon.AppManager.BuildConfig;\nimport io.github.muntashirakon.AppManager.utils.ArrayUtils;\nimport io.github.muntashirakon.AppManager.utils.ExUtils;\nimport io.github.muntashirakon.io.Path;\nimport io.github.muntashirakon.io.Paths;\nimport io.github.muntashirakon.io.fs.VirtualFileSystem;\n\n// Copyright 2018 Hai Zhang <dreaming.in.code.zh@gmail.com>\n// Modified from FileProvider.kt\npublic class FmProvider extends ContentProvider {\n    public static final String AUTHORITY = BuildConfig.APPLICATION_ID + \".file\";\n\n    @NonNull\n    public static Uri getContentUri(@NonNull Path path) {\n        return getContentUri(path.getUri());\n    }\n\n    @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)\n    @NonNull\n    static Uri getContentUri(@NonNull Uri uri) {\n        Uri.Builder builder = uri.buildUpon()\n                .scheme(ContentResolver.SCHEME_CONTENT)\n                .authority(AUTHORITY)\n                .path(null);\n        // Uri could be a file, content or vfs\n        // 1. file:// Only use path\n        // 2. content:// Use ! + authority followed by path\n        // 3. vfs:// Use !! + authority (vfs ID) followed by path\n        if (ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) {\n            builder.appendPath(\"!\" + uri.getAuthority());\n        } else if (VirtualFileSystem.SCHEME.equals(uri.getScheme())) {\n            builder.appendPath(\"!!\" + uri.getAuthority());\n        }\n        for (String segment : uri.getPathSegments()) {\n            builder.appendPath(segment);\n        }\n        // The rests (query params, etc.) remains the same\n        return builder.build();\n    }\n\n    private static final String[] DEFAULT_PROJECTION = new String[]{\n            OpenableColumns.DISPLAY_NAME,\n            OpenableColumns.SIZE,\n            MediaStore.MediaColumns.DATA,\n            DocumentsContract.Document.COLUMN_MIME_TYPE,\n            DocumentsContract.Document.COLUMN_LAST_MODIFIED,\n    };\n\n    private static final String[] CHOOSER_ACTIVITY_DEFAULT_PROJECTION = new String[]{\n            OpenableColumns.DISPLAY_NAME\n    };\n\n    private HandlerThread mCallbackThread;\n    private Handler mCallbackHandler;\n\n    @Override\n    public boolean onCreate() {\n        mCallbackThread = new HandlerThread(\"FmProvider.HandlerThread\");\n        mCallbackThread.start();\n        mCallbackHandler = new Handler(Objects.requireNonNull(mCallbackThread.getLooper()));\n        return true;\n    }\n\n    @Override\n    public void shutdown() {\n        mCallbackThread.quitSafely();\n    }\n\n    @Override\n    public void attachInfo(Context context, ProviderInfo info) {\n        super.attachInfo(context, info);\n        if (info.exported) {\n            throw new SecurityException(\"Provider must not be exported\");\n        }\n        if (!info.grantUriPermissions) {\n            throw new SecurityException(\"Provider must grant uri permissions\");\n        }\n    }\n\n    @NonNull\n    @Override\n    public Cursor query(@NonNull Uri uri, @Nullable String[] projection, @Nullable String selection,\n                        @Nullable String[] selectionArgs, @Nullable String sortOrder) {\n        // ContentProvider has already checked granted permissions\n        String[] defaultProjection = getDefaultProjection();\n        List<String> columns;\n        if (projection != null) {\n            columns = new ArrayList<>();\n            for (String column : projection) {\n                if (ArrayUtils.contains(defaultProjection, column)) {\n                    columns.add(column);\n                }\n            }\n        } else columns = Arrays.asList(defaultProjection);\n        Path path = ExUtils.exceptionAsNull(() -> getFileProviderPath(uri));\n        if (path == null) {\n            return new MatrixCursor(columns.toArray(new String[0]), 0);\n        }\n        List<Object> row = new ArrayList<>();\n        for (String column : columns) {\n            switch (column) {\n                case OpenableColumns.DISPLAY_NAME:\n                    row.add(path.getName());\n                    break;\n                case OpenableColumns.SIZE:\n                    row.add(path.isFile() ? path.length() : null);\n                    break;\n                case MediaStore.MediaColumns.DATA:\n                    String filePath = path.getFilePath();\n                    if (filePath == null\n                            || !new File(filePath).canRead()\n                            || Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {\n                        row.add(null);\n                        continue;\n                    }\n                    row.add(filePath);\n                    break;\n                // TODO: We should actually implement a DocumentsProvider since we are handling\n                //  ACTION_OPEN_DOCUMENT.\n                case DocumentsContract.Document.COLUMN_MIME_TYPE:\n                    row.add(path.isDirectory() ? DocumentsContract.Document.MIME_TYPE_DIR : path.getType());\n                    break;\n                case DocumentsContract.Document.COLUMN_LAST_MODIFIED:\n                    row.add(path.lastModified());\n                    break;\n            }\n        }\n        return new MatrixCursor(columns.toArray(new String[0]), 1) {{\n            addRow(row);\n        }};\n    }\n\n    @Nullable\n    @Override\n    public String getType(@NonNull Uri uri) {\n        return ExUtils.exceptionAsNull(() -> getFileProviderPath(uri).getType());\n    }\n\n    @Nullable\n    @Override\n    public Uri insert(@NonNull Uri uri, @Nullable ContentValues values) {\n        throw new UnsupportedOperationException(\"No external inserts\");\n    }\n\n    @Override\n    public int delete(@NonNull Uri uri, @Nullable String selection, @Nullable String[] selectionArgs) {\n        throw new UnsupportedOperationException(\"No external deletes\");\n    }\n\n    @Override\n    public int update(@NonNull Uri uri, @Nullable ContentValues values, @Nullable String selection, @Nullable String[] selectionArgs) {\n        throw new UnsupportedOperationException(\"No external updates\");\n    }\n\n    @Nullable\n    @Override\n    public ParcelFileDescriptor openFile(@NonNull Uri uri, @NonNull String mode) throws FileNotFoundException {\n        // ContentProvider has already checked granted permissions\n        return getFileProviderPath(uri).openFileDescriptor(checkMode(mode), mCallbackHandler);\n    }\n\n    private static String[] getDefaultProjection() {\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q\n                && Binder.getCallingUid() == Process.SYSTEM_UID) {\n            // com.android.internal.app.ChooserActivity.queryResolver() in Q queries with a null\n            // projection (meaning all columns) on main thread but only actually needs the display\n            // name (and document flags). However, if we do return all the columns, we may perform\n            // network requests and crash it due to StrictMode. So just work around by only\n            // returning the display name in this case.\n            return CHOOSER_ACTIVITY_DEFAULT_PROJECTION;\n        } else {\n            return DEFAULT_PROJECTION;\n        }\n    }\n\n    @NonNull\n    private static Path getFileProviderPath(@NonNull Uri uri) throws FileNotFoundException {\n        return Paths.getStrict(getFileProviderPathInternal(uri));\n    }\n\n    /**\n     * Decode path.\n     *\n     * @see #getContentUri(Uri)\n     */\n    @VisibleForTesting(otherwise = VisibleForTesting.PACKAGE_PRIVATE)\n    @NonNull\n    static Uri getFileProviderPathInternal(@NonNull Uri uri) {\n        List<String> pathParts = uri.getPathSegments();\n        int pathStartIndex = 0;\n        String scheme = ContentResolver.SCHEME_FILE;\n        String authority = \"\";\n        if (pathParts.size() > 0) {\n            String firstPart = pathParts.get(0);\n            if (firstPart.startsWith(\"!!\")) {\n                // Virtual File System\n                pathStartIndex = 1;\n                scheme = VirtualFileSystem.SCHEME;\n                authority = firstPart.substring(2);\n            } else if (firstPart.startsWith(\"!\")) {\n                // Content provider\n                pathStartIndex = 1;\n                scheme = ContentResolver.SCHEME_CONTENT;\n                authority = firstPart.substring(1);\n            }\n        }\n        Uri.Builder builder = uri.buildUpon()\n                .scheme(scheme)\n                .authority(authority)\n                .path(null);\n        for (int i = pathStartIndex; i < pathParts.size(); ++i) {\n            builder.appendPath(pathParts.get(i));\n        }\n        return builder.build();\n    }\n\n    @NonNull\n    private static String checkMode(@NonNull String mode) {\n        // Add `t` flag if neither truncate nor append is supplied\n        if (mode.indexOf('w') != -1 && mode.indexOf('a') == -1) {\n            // w exists but a doesn't\n            if (mode.indexOf('t') == -1) {\n                return mode + 't';\n            }\n        }\n        return mode;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/fm/FmShortcutInfo.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.fm;\n\nimport android.content.Context;\nimport android.content.Intent;\nimport android.net.Uri;\nimport android.os.Parcel;\nimport android.provider.DocumentsContract;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.core.os.ParcelCompat;\n\nimport java.util.Objects;\nimport java.util.UUID;\n\nimport io.github.muntashirakon.AppManager.shortcut.ShortcutInfo;\nimport io.github.muntashirakon.io.Path;\n\npublic class FmShortcutInfo extends ShortcutInfo {\n    private final boolean mIsDirectory;\n    @NonNull\n    private final Uri mUri;\n    @Nullable\n    private final String mCustomMimeType;\n\n    public FmShortcutInfo(@NonNull Path path, @Nullable String customMimeType) {\n        mIsDirectory = path.isDirectory();\n        mCustomMimeType = customMimeType;\n        mUri = path.getUri();\n        setName(path.getName());\n        setId(UUID.randomUUID().toString());\n    }\n\n    protected FmShortcutInfo(Parcel in) {\n        super(in);\n        mIsDirectory = ParcelCompat.readBoolean(in);\n        mUri = Objects.requireNonNull(ParcelCompat.readParcelable(in, Uri.class.getClassLoader(), Uri.class));\n        mCustomMimeType = in.readString();\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        super.writeToParcel(dest, flags);\n        ParcelCompat.writeBoolean(dest, mIsDirectory);\n        dest.writeParcelable(mUri, flags);\n        dest.writeString(mCustomMimeType);\n    }\n\n    @Override\n    public Intent toShortcutIntent(@NonNull Context context) {\n        Intent intent;\n        if (mIsDirectory) {\n            intent = new Intent(context, FmActivity.class);\n            intent.setDataAndType(mUri, mCustomMimeType != null ? mCustomMimeType : DocumentsContract.Document.MIME_TYPE_DIR);\n        } else {\n            intent = new Intent(context, OpenWithActivity.class);\n            if (mCustomMimeType != null) {\n                intent.setDataAndType(mUri, mCustomMimeType);\n            } else intent.setData(mUri);\n        }\n        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT | Intent.FLAG_ACTIVITY_MULTIPLE_TASK);\n        return intent;\n    }\n\n    public static final Creator<FmShortcutInfo> CREATOR = new Creator<FmShortcutInfo>() {\n        @Override\n        public FmShortcutInfo createFromParcel(Parcel source) {\n            return new FmShortcutInfo(source);\n        }\n\n        @Override\n        public FmShortcutInfo[] newArray(int size) {\n            return new FmShortcutInfo[size];\n        }\n    };\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/fm/FmTasks.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.fm;\n\nimport androidx.annotation.IntDef;\nimport androidx.annotation.Nullable;\n\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.util.ArrayList;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Queue;\n\nimport io.github.muntashirakon.io.Path;\n\npublic class FmTasks {\n    // It's okay to use a singleton class since we won't be following application lifecycle.\n    // If the app instance is destroyed, tasks will cease to exist.\n    private static final FmTasks sInstance = new FmTasks();\n\n    public static FmTasks getInstance() {\n        return sInstance;\n    }\n\n    private final Queue<FmTask> taskList = new LinkedList<>();\n\n    public void enqueue(FmTask fmTask) {\n        // Currently, we only allow a single task. So, clear the queue first.\n        taskList.clear();\n        taskList.add(fmTask);\n    }\n\n    @Nullable\n    public FmTask peek() {\n        return taskList.peek();\n    }\n\n    @Nullable\n    public FmTask dequeue() {\n        FmTask task = peek();\n        if (task != null && task.type == FmTask.TYPE_COPY) {\n            // Copy is allowed multiple times but others aren't\n            return task;\n        }\n        return taskList.poll();\n    }\n\n    public boolean isEmpty() {\n        return taskList.isEmpty();\n    }\n\n    public static class FmTask {\n        @IntDef({TYPE_COPY, TYPE_CUT})\n        @Retention(RetentionPolicy.SOURCE)\n        public @interface TaskType {\n        }\n\n        public static final int TYPE_COPY = 0;\n        public static final int TYPE_CUT = 1;\n\n        @TaskType\n        public final int type;\n        public final long timestamp;\n        public final List<Path> files;\n\n        private int mFlags;\n\n        public FmTask(@TaskType int type, List<Path> files) {\n            this.type = type;\n            this.timestamp = System.currentTimeMillis();\n            this.files = new ArrayList<>(files);\n        }\n\n        public boolean canPaste() {\n            return type == TYPE_COPY || type == TYPE_CUT;\n        }\n\n        public void addFlag(int flag) {\n            mFlags |= flag;\n        }\n\n        public void removeFlag(int flag) {\n            mFlags &= ~flag;\n        }\n\n        public boolean hasFlag(int flag) {\n            return (mFlags & flag) != 0;\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/fm/FmUtils.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.fm;\n\nimport android.content.ContentResolver;\nimport android.content.Intent;\nimport android.content.pm.ResolveInfo;\nimport android.net.Uri;\nimport android.provider.DocumentsContract;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport java.io.File;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Objects;\n\nimport io.github.muntashirakon.AppManager.logs.Log;\nimport io.github.muntashirakon.AppManager.utils.ContextUtils;\nimport io.github.muntashirakon.io.Path;\nimport io.github.muntashirakon.io.Paths;\nimport io.github.muntashirakon.io.fs.VirtualFileSystem;\n\npublic final class FmUtils {\n    public static final String TAG = FmUtils.class.getSimpleName();\n\n    @NonNull\n    public static String getDisplayablePath(@NonNull Path path) {\n        return getDisplayablePath(path.getUri());\n    }\n\n    @NonNull\n    public static String getDisplayablePath(@NonNull Uri uri) {\n        if (ContentResolver.SCHEME_FILE.equals(uri.getScheme())) {\n            return uri.getPath();\n        }\n        return uri.toString();\n    }\n\n    @SuppressWarnings(\"OctalInteger\")\n    @NonNull\n    public static String getFormattedMode(int mode) {\n        // Ref: https://man7.org/linux/man-pages/man7/inode.7.html\n        String s = getSingleMode(mode >> 6, (mode & 04000) != 0, \"s\") +\n                getSingleMode(mode >> 3, (mode & 02000) != 0, \"s\") +\n                getSingleMode(mode, (mode & 01000) != 0, \"t\");\n        return String.format(Locale.ROOT, \"%s (0%o)\", s, mode & 07777);\n    }\n\n    @SuppressWarnings(\"OctalInteger\")\n    @NonNull\n    private static String getSingleMode(int mode, boolean special, String specialChar) {\n        boolean canExecute = (mode & 01) != 0;\n        String execMode;\n        if (canExecute) {\n            execMode = special ? specialChar.toLowerCase(Locale.ROOT) : \"x\";\n        } else if (special) {\n            execMode = specialChar.toUpperCase(Locale.ROOT);\n        } else execMode = \"-\";\n        return ((mode & 04) != 0 ? \"r\" : \"-\") +\n                ((mode & 02) != 0 ? \"w\" : \"-\") +\n                execMode;\n    }\n\n\n    @Nullable\n    public static Uri sanitizeContentInput(@Nullable Uri uri) {\n        if (uri == null) {\n            return null;\n        }\n        // App Manager supports three schemes: file, content and vfs (private)\n        String scheme = uri.getScheme();\n        if (scheme == null) {\n            // Scheme must be non-null unless explicitly required (such as in FmActivity)\n            return null;\n        }\n        switch (scheme) {\n            case ContentResolver.SCHEME_CONTENT:\n                // Content schemes are handled by authority.\n                if (FmProvider.AUTHORITY.equals(uri.getAuthority())) {\n                    // Sanitize the path part which must be an absolute URL\n                    Uri realUri = FmProvider.getFileProviderPathInternal(uri);\n                    Uri fixedUri = sanitizeContentInput(realUri);\n                    return fixedUri != null ? FmProvider.getContentUri(fixedUri) : null;\n                }\n                // If it's not App Manager itself, return as is.\n                return uri;\n            case ContentResolver.SCHEME_FILE: {\n                // Sanitize the path which must be an absolute URL\n                String path = uri.getPath();\n                path = Paths.relativePath(path, File.separator);\n                return uri.buildUpon().path(path).build();\n            }\n            case VirtualFileSystem.SCHEME: {\n                if (uri.getAuthority() == null) {\n                    // VFS must have an authority\n                    return null;\n                }\n                // VFS path must be absolute URL\n                String path = uri.getPath();\n                if (!path.startsWith(File.separator)) {\n                    path = File.separator + path;\n                }\n                path = Paths.relativePath(path, File.separator);\n                return uri.buildUpon().path(path).build();\n            }\n            case \"package\":\n                if (!uri.isHierarchical()) {\n                    // package:package-name is not a hierarchical format\n                    return uri;\n                }\n            default:\n                Log.i(TAG, \"Invalid/unsupported scheme: \" + scheme);\n                // Invalid path\n                return null;\n        }\n    }\n\n    @SuppressWarnings(\"SuspiciousRegexArgument\") // We're not on Windows\n    public static List<String> uriToPathParts(@NonNull Uri uri) {\n        switch (uri.getScheme()) {\n            case ContentResolver.SCHEME_CONTENT: {\n                if (isDocumentsProvider(uri.getAuthority())) {\n                    List<String> paths = uri.getPathSegments();\n                    if (paths.size() == 2) {\n                        if (\"document\".equals(paths.get(0))) {\n                            return Collections.singletonList(paths.get(1));\n                        }\n                    } else if (paths.size() == 4) {\n                        if (\"tree\".equals(paths.get(0)) && \"document\".equals(paths.get(2))) {\n                            String id = paths.get(1);\n                            String actualPath = paths.get(3);\n                            if (actualPath.length() > (id.length() + 1)) {\n                                // Relative path, omitting the first `/`\n                                actualPath = actualPath.substring(id.length() + 1);\n                            } else actualPath = null;\n                            List<String> pathParts = new ArrayList<>();\n                            pathParts.add(id);\n                            if (actualPath != null) {\n                                pathParts.addAll(Arrays.asList(actualPath.split(File.separator)));\n                            }\n                            return pathParts;\n                        }\n                    }\n                }\n                // Deliberate fall-through\n            }\n            default:\n            case ContentResolver.SCHEME_FILE:\n            case VirtualFileSystem.SCHEME: {\n                List<String> pathParts = new ArrayList<>();\n                pathParts.add(File.separator);\n                pathParts.addAll(uri.getPathSegments());\n                return pathParts;\n            }\n        }\n    }\n\n    public static Uri uriFromPathParts(@NonNull Uri baseUri, @NonNull List<String> pathParts, int endPosition) {\n        if (endPosition >= pathParts.size()) {\n            throw new IndexOutOfBoundsException(\"EndPosition: \" + endPosition + \", Size: \" + pathParts.size());\n        }\n        Uri.Builder builder = baseUri.buildUpon();\n        builder.path(null);\n        switch (Objects.requireNonNull(baseUri.getScheme())) {\n            case ContentResolver.SCHEME_CONTENT: {\n                if (isDocumentsProvider(Objects.requireNonNull(baseUri.getAuthority()))) {\n                    List<String> paths = baseUri.getPathSegments();\n                    if (paths.size() == 2) {\n                        if (\"document\".equals(paths.get(0))) {\n                            // index 0 = document\n                            // index 1 = (path) pathParts.get(0)\n                            builder.appendPath(\"document\");\n                            builder.appendPath(pathParts.get(0));\n                            return builder.build();\n                        }\n                    } else if (paths.size() == 4) {\n                        if (\"tree\".equals(paths.get(0)) && \"document\".equals(paths.get(2))) {\n                            // index 0 = tree\n                            // index 1 = (id) paths.get(1)\n                            // index 2 = document\n                            // index 3 = (path) pathParts.get(0..length)\n                            builder.appendPath(\"tree\");\n                            builder.appendPath(paths.get(1));\n                            builder.appendPath(\"document\");\n                            StringBuilder pathBuilder = new StringBuilder();\n                            for (int i = 0; i < endPosition; ++i) {\n                                pathBuilder.append(pathParts.get(i)).append(File.separator);\n                            }\n                            pathBuilder.append(pathParts.get(endPosition));\n                            builder.appendPath(pathBuilder.toString());\n                            return builder.build();\n                        }\n                    }\n                }\n                // Deliberate fall-through\n            }\n            default:\n            case ContentResolver.SCHEME_FILE:\n            case VirtualFileSystem.SCHEME: {\n                if (endPosition == 0) {\n                    builder.path(\"/\");\n                } else {\n                    // Append up-to endPosition, skipping the root (index = 0)\n                    for (int i = 1; i <= endPosition; ++i) {\n                        builder.appendPath(pathParts.get(i));\n                    }\n                }\n                return builder.build();\n            }\n        }\n    }\n\n    private static boolean isDocumentsProvider(@NonNull String authority) {\n        final Intent intent = new Intent(DocumentsContract.PROVIDER_INTERFACE);\n        final List<ResolveInfo> infos = ContextUtils.getContext().getPackageManager().queryIntentContentProviders(intent, 0);\n        for (ResolveInfo info : infos) {\n            if (authority.equals(info.providerInfo.authority)) {\n                return true;\n            }\n        }\n        return false;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/fm/FmViewModel.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.fm;\n\nimport android.annotation.SuppressLint;\nimport android.app.Application;\nimport android.content.ContentResolver;\nimport android.database.Cursor;\nimport android.graphics.Bitmap;\nimport android.net.Uri;\nimport android.provider.DocumentsContract;\nimport android.text.TextUtils;\n\nimport androidx.annotation.MainThread;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.WorkerThread;\nimport androidx.core.util.Pair;\nimport androidx.lifecycle.AndroidViewModel;\nimport androidx.lifecycle.LiveData;\nimport androidx.lifecycle.MutableLiveData;\n\nimport com.j256.simplemagic.ContentType;\n\nimport java.io.FileNotFoundException;\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.Iterator;\nimport java.util.LinkedHashSet;\nimport java.util.List;\nimport java.util.Objects;\nimport java.util.Set;\nimport java.util.concurrent.Future;\n\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.dex.DexUtils;\nimport io.github.muntashirakon.AppManager.fm.icons.FmIconFetcher;\nimport io.github.muntashirakon.AppManager.logs.Log;\nimport io.github.muntashirakon.AppManager.misc.AdvancedSearchView;\nimport io.github.muntashirakon.AppManager.misc.ListOptions;\nimport io.github.muntashirakon.AppManager.self.filecache.FileCache;\nimport io.github.muntashirakon.AppManager.self.imagecache.ImageLoader;\nimport io.github.muntashirakon.AppManager.settings.Prefs;\nimport io.github.muntashirakon.AppManager.utils.AlphanumComparator;\nimport io.github.muntashirakon.AppManager.utils.ExUtils;\nimport io.github.muntashirakon.AppManager.utils.FileUtils;\nimport io.github.muntashirakon.AppManager.utils.ThreadUtils;\nimport io.github.muntashirakon.io.IoUtils;\nimport io.github.muntashirakon.io.Path;\nimport io.github.muntashirakon.io.PathAttributes;\nimport io.github.muntashirakon.io.Paths;\nimport io.github.muntashirakon.io.fs.VirtualFileSystem;\nimport io.github.muntashirakon.lifecycle.SingleLiveEvent;\n\npublic class FmViewModel extends AndroidViewModel implements ListOptions.ListOptionActions {\n    public static final String TAG = FmViewModel.class.getSimpleName();\n\n    private final Object mSizeLock = new Object();\n    private final MutableLiveData<List<FmItem>> mFmItemsLiveData = new MutableLiveData<>();\n    private final MutableLiveData<Throwable> mFmErrorLiveData = new MutableLiveData<>();\n    private final MutableLiveData<FolderShortInfo> mFolderShortInfoLiveData = new MutableLiveData<>();\n    private final MutableLiveData<Uri> mUriLiveData = new MutableLiveData<>();\n    private final MutableLiveData<Uri> mLastUriLiveData = new MutableLiveData<>();\n    private final MutableLiveData<Uri> mDisplayPropertiesLiveData = new MutableLiveData<>();\n    private final SingleLiveEvent<Pair<Path, Bitmap>> mShortcutCreatorLiveData = new SingleLiveEvent<>();\n    private final SingleLiveEvent<SharableItems> mSharableItemsLiveData = new SingleLiveEvent<>();\n    private final List<FmItem> mFmItems = new ArrayList<>();\n    private final Set<Path> mSelectedItems = Collections.synchronizedSet(new LinkedHashSet<>());\n    private final HashMap<Uri, Integer> mPathScrollPositionMap = new HashMap<>();\n    private FmActivity.Options mOptions;\n    private Uri mCurrentUri;\n    @FmListOptions.SortOrder\n    private int mSortBy;\n    private boolean mReverseSort;\n    @FmListOptions.Options\n    private int mSelectedOptions;\n    @Nullable\n    private String mQueryString;\n    @Nullable\n    private String mScrollToFilename;\n    @Nullable\n    private Future<?> mFmFileLoaderResult;\n    private Future<?> mFmFileSystemLoaderResult;\n    private final Set<Integer> mVfsIdSet = new HashSet<>();\n    private final FileCache mFileCache = new FileCache();\n\n    public FmViewModel(@NonNull Application application) {\n        super(application);\n        mSortBy = Prefs.FileManager.getSortOrder();\n        mReverseSort = Prefs.FileManager.isReverseSort();\n        mSelectedOptions = Prefs.FileManager.getOptions();\n    }\n\n    @Override\n    protected void onCleared() {\n        // Ensure that file loader no longer doing anything\n        if (mFmFileLoaderResult != null) {\n            mFmFileLoaderResult.cancel(true);\n        }\n        if (mFmFileSystemLoaderResult != null) {\n            mFmFileSystemLoaderResult.cancel(true);\n        }\n        // Clear VFS related data\n        for (int vfsId : mVfsIdSet) {\n            ExUtils.exceptionAsIgnored(() -> VirtualFileSystem.unmount(vfsId));\n        }\n        IoUtils.closeQuietly(mFileCache);\n        super.onCleared();\n    }\n\n    @Override\n    public void setSortBy(@FmListOptions.SortOrder int sortBy) {\n        mSortBy = sortBy;\n        Prefs.FileManager.setSortOrder(sortBy);\n        ThreadUtils.postOnBackgroundThread(this::filterAndSort);\n    }\n\n    @FmListOptions.SortOrder\n    @Override\n    public int getSortBy() {\n        return mSortBy;\n    }\n\n    @Override\n    public void setReverseSort(boolean reverseSort) {\n        mReverseSort = reverseSort;\n        Prefs.FileManager.setReverseSort(reverseSort);\n        ThreadUtils.postOnBackgroundThread(this::filterAndSort);\n    }\n\n    @Override\n    public boolean isReverseSort() {\n        return mReverseSort;\n    }\n\n    @Override\n    public boolean isOptionSelected(@FmListOptions.Options int option) {\n        return (mSelectedOptions & option) != 0;\n    }\n\n    @Override\n    public void onOptionSelected(@FmListOptions.Options int option, boolean selected) {\n        if (selected) mSelectedOptions |= option;\n        else mSelectedOptions &= ~option;\n        Prefs.FileManager.setOptions(mSelectedOptions);\n        ThreadUtils.postOnBackgroundThread(this::filterAndSort);\n    }\n\n    public void setQueryString(@Nullable String queryString) {\n        mQueryString = queryString;\n        ThreadUtils.postOnBackgroundThread(this::filterAndSort);\n    }\n\n    @MainThread\n    public void setOptions(@NonNull FmActivity.Options options, @Nullable Uri defaultUri) {\n        if (mFmFileLoaderResult != null) {\n            mFmFileLoaderResult.cancel(true);\n        }\n        if (mFmFileSystemLoaderResult != null) {\n            mFmFileSystemLoaderResult.cancel(true);\n        }\n        mOptions = options;\n        if (!options.isVfs()) {\n            // No need to mount anything. Options#uri is the base URI\n            loadFiles(defaultUri != null ? defaultUri : options.uri, null);\n            return;\n        }\n        // Need to mount the file system\n        mFmFileSystemLoaderResult = ThreadUtils.postOnBackgroundThread(() -> {\n            try {\n                VirtualFileSystem fs = mountVfs();\n                int vfsId = fs.getFsId();\n                mVfsIdSet.add(vfsId);\n                // vfs ID/authority has altered\n                Uri newUri;\n                if (defaultUri != null) {\n                    newUri = defaultUri.buildUpon().authority(String.valueOf(vfsId)).build();\n                } else newUri = fs.getRootPath().getUri();\n                // Now load files\n                ThreadUtils.postOnMainThread(() -> loadFiles(newUri, null));\n            } catch (IOException e) {\n                handleError(e, mOptions.uri);\n            }\n        });\n    }\n\n    public FmActivity.Options getOptions() {\n        return mOptions;\n    }\n\n    public Uri getCurrentUri() {\n        return mCurrentUri;\n    }\n\n    public void setScrollPosition(Uri uri, int currentScrollPosition) {\n        Log.d(TAG, \"Store: Scroll position = %d, uri = %s\", currentScrollPosition, uri);\n        mPathScrollPositionMap.put(uri, currentScrollPosition);\n    }\n\n    public int getCurrentScrollPosition() {\n        Integer scrollPosition = mPathScrollPositionMap.get(mCurrentUri);\n        Log.d(TAG, \"Load: Scroll position = %d, uri = %s\", scrollPosition, mCurrentUri);\n        return scrollPosition != null ? scrollPosition : 0;\n    }\n\n    public List<Path> getSelectedItems() {\n        return new ArrayList<>(mSelectedItems);\n    }\n\n    @Nullable\n    public Path getLastSelectedItem() {\n        // Last selected item is the same as the last added item.\n        Iterator<Path> it = mSelectedItems.iterator();\n        Path lastItem = null;\n        while (it.hasNext()) {\n            lastItem = it.next();\n        }\n        return lastItem;\n    }\n\n    public int getSelectedItemCount() {\n        return mSelectedItems.size();\n    }\n\n    public void setSelectedItem(@NonNull Path path, boolean select) {\n        if (select) {\n            mSelectedItems.add(path);\n        } else {\n            mSelectedItems.remove(path);\n        }\n    }\n\n    public boolean isSelected(@NonNull Path path) {\n        return mSelectedItems.contains(path);\n    }\n\n    public void clearSelections() {\n        mSelectedItems.clear();\n    }\n\n    @MainThread\n    public void reload() {\n        reload(null);\n    }\n\n    @MainThread\n    public void reload(@Nullable String scrollToFilename) {\n        if (mOptions != null && mCurrentUri != null) {\n            loadFiles(mCurrentUri, scrollToFilename);\n        }\n    }\n\n    @MainThread\n    public void loadFiles(@NonNull Uri uri) {\n        if (mCurrentUri != null) {\n            // May need to reload options\n            if (!Objects.equals(mCurrentUri.getScheme(), uri.getScheme())\n                    || !Objects.equals(mCurrentUri.getAuthority(), uri.getAuthority())) {\n                updateOptions(uri);\n                return;\n            }\n        }\n        loadFiles(uri, null);\n    }\n\n    @MainThread\n    private void updateOptions(@NonNull Uri refUri) {\n        FmActivity.Options options = new FmActivity.Options(refUri);\n        setOptions(options, null);\n    }\n\n    @SuppressLint(\"WrongThread\")\n    @MainThread\n    private void loadFiles(@NonNull Uri uri, @Nullable String scrollToFilename) {\n        if (mFmFileLoaderResult != null) {\n            mFmFileLoaderResult.cancel(true);\n        }\n        mScrollToFilename = scrollToFilename;\n        Uri lastUri = mCurrentUri;\n        // Send last URI\n        mLastUriLiveData.setValue(lastUri);\n        mCurrentUri = uri;\n        Path currentPath;\n        try {\n            currentPath = Paths.getStrict(uri);\n        } catch (IOException e) {\n            handleError(e, uri);\n            return;\n        }\n        while (currentPath.isSymbolicLink()) {\n            try {\n                Path realPath = currentPath.getRealPath();\n                if (realPath == null || realPath.equals(currentPath)) {\n                    // Not a symbolic link\n                    break;\n                }\n                currentPath = realPath;\n                mCurrentUri = realPath.getUri();\n            } catch (IOException ignore) {\n                // Since we couldn't resolve the path, try currentPath instead\n            }\n        }\n        Path path = currentPath;\n        mFmFileLoaderResult = ThreadUtils.postOnBackgroundThread(() -> {\n            if (!path.isDirectory()) {\n                IOException e;\n                if (path.exists()) {\n                    e = new FileNotFoundException(getApplication().getString(R.string.path_not_a_folder, path.getName()));\n                } else {\n                    e = new IOException(getApplication().getString(R.string.path_does_not_exist, path.getName()));\n                }\n                handleError(e, mCurrentUri);\n                return;\n            }\n            // Send current URI\n            mUriLiveData.postValue(mCurrentUri);\n            long s, e;\n            boolean isSaf = ContentResolver.SCHEME_CONTENT.equals(mCurrentUri.getScheme());\n            FolderShortInfo folderShortInfo = new FolderShortInfo();\n            int folderCount = 0;\n            synchronized (mFmItems) {\n                mFmItems.clear();\n                if (isSaf) {\n                    // SAF needs special handling to retrieve children\n                    s = System.currentTimeMillis();\n                    ContentResolver resolver = getApplication().getContentResolver();\n                    Uri childrenUri = DocumentsContract.buildChildDocumentsUriUsingTree(mCurrentUri,\n                            DocumentsContract.getDocumentId(mCurrentUri));\n                    Cursor c = null;\n                    try {\n                        c = resolver.query(childrenUri, null, null, null, null);\n                        String[] columns = c.getColumnNames();\n                        while (c.moveToNext()) {\n                            String documentId = null;\n                            for (int i = 0; i < columns.length; ++i) {\n                                if (DocumentsContract.Document.COLUMN_DOCUMENT_ID.equals(columns[i])) {\n                                    documentId = c.getString(i);\n                                }\n                            }\n                            if (documentId == null) {\n                                // Invalid document, probably loading still?\n                                continue;\n                            }\n                            Uri documentUri = DocumentsContract.buildDocumentUriUsingTree(mCurrentUri, documentId);\n                            Path child = Paths.getTreeDocument(path, documentUri);\n                            PathAttributes attributes = Paths.getAttributesFromSafTreeCursor(documentUri, c);\n                            FmItem fmItem = new FmItem(child, attributes);\n                            mFmItems.add(fmItem);\n                            if (fmItem.isDirectory) {\n                                ++folderCount;\n                            }\n                            if (ThreadUtils.isInterrupted()) {\n                                return;\n                            }\n                        }\n                        e = System.currentTimeMillis();\n                        Log.d(TAG, \"Time to fetch files via SAF: %d ms\", e - s);\n                    } catch (Exception ex) {\n                        Log.w(TAG, \"Failed query: %s\", ex);\n                    } finally {\n                        IoUtils.closeQuietly(c);\n                    }\n                } else {\n                    s = System.currentTimeMillis();\n                    Path[] children = path.listFiles();\n                    e = System.currentTimeMillis();\n                    Log.d(TAG, \"Time to list files: %d ms\", e - s);\n                    s = System.currentTimeMillis();\n                    for (Path child : children) {\n                        FmItem fmItem = new FmItem(child);\n                        mFmItems.add(fmItem);\n                        if (fmItem.isDirectory) {\n                            ++folderCount;\n                        }\n                        if (ThreadUtils.isInterrupted()) {\n                            return;\n                        }\n                    }\n                    e = System.currentTimeMillis();\n                    Log.d(TAG, \"Time to process file list: %d ms\", e - s);\n                }\n            }\n            folderShortInfo.folderCount = folderCount;\n            folderShortInfo.fileCount = mFmItems.size() - folderCount;\n            folderShortInfo.canRead = path.canRead();\n            folderShortInfo.canWrite = path.canWrite();\n            if (ThreadUtils.isInterrupted()) {\n                return;\n            }\n            // Send folder info for the first time\n            mFolderShortInfoLiveData.postValue(folderShortInfo);\n            // Run filter and sorting options for fmItems\n            s = System.currentTimeMillis();\n            filterAndSort();\n            e = System.currentTimeMillis();\n            Log.d(TAG, \"Time to sort files: %d ms\", e - s);\n            synchronized (mSizeLock) {\n                // Calculate size and send folder info again\n                folderShortInfo.size = Paths.size(path);\n                if (ThreadUtils.isInterrupted()) {\n                    return;\n                }\n                mFolderShortInfoLiveData.postValue(folderShortInfo);\n            }\n        });\n    }\n\n    public void addToFavorite(@NonNull Path path, @NonNull FmActivity.Options options) {\n        ThreadUtils.postOnBackgroundThread(() -> {\n            FmFavoritesManager.addToFavorite(path, options);\n        });\n    }\n\n    public void createShortcut(@NonNull FmItem fmItem) {\n        ThreadUtils.postOnBackgroundThread(() -> {\n            Bitmap bitmap = ImageLoader.getInstance().getCachedImage(fmItem.getTag());\n            if (bitmap == null) {\n                ImageLoader.ImageFetcherResult result = new FmIconFetcher(fmItem).fetchImage(fmItem.getTag());\n                bitmap = result.bitmap != null ? result.bitmap : result.defaultImage.getImage();\n            }\n            mShortcutCreatorLiveData.postValue(new Pair<>(fmItem.path, bitmap));\n        });\n    }\n\n    public void shareFiles(@NonNull List<Path> pathList) {\n        ThreadUtils.postOnBackgroundThread(() -> {\n            SharableItems sharableItems = new SharableItems(pathList);\n            mSharableItemsLiveData.postValue(sharableItems);\n        });\n    }\n\n    public void createShortcut(@NonNull Uri uri) {\n        createShortcut(new FmItem(Paths.get(uri)));\n    }\n\n    public LiveData<List<FmItem>> getFmItemsLiveData() {\n        return mFmItemsLiveData;\n    }\n\n    public LiveData<Throwable> getFmErrorLiveData() {\n        return mFmErrorLiveData;\n    }\n\n    public LiveData<Uri> getUriLiveData() {\n        return mUriLiveData;\n    }\n\n    public LiveData<FolderShortInfo> getFolderShortInfoLiveData() {\n        return mFolderShortInfoLiveData;\n    }\n\n    public LiveData<Uri> getLastUriLiveData() {\n        return mLastUriLiveData;\n    }\n\n    public MutableLiveData<Uri> getDisplayPropertiesLiveData() {\n        return mDisplayPropertiesLiveData;\n    }\n\n    public LiveData<Pair<Path, Bitmap>> getShortcutCreatorLiveData() {\n        return mShortcutCreatorLiveData;\n    }\n\n    public LiveData<SharableItems> getSharableItemsLiveData() {\n        return mSharableItemsLiveData;\n    }\n\n    private void handleError(@NonNull Throwable th, @NonNull Uri currentUri) {\n        FolderShortInfo folderShortInfo = new FolderShortInfo();\n        if (ThreadUtils.isMainThread()) {\n            mUriLiveData.setValue(currentUri);\n            mFolderShortInfoLiveData.setValue(folderShortInfo);\n            mFmErrorLiveData.setValue(th);\n        } else {\n            mUriLiveData.postValue(currentUri);\n            mFolderShortInfoLiveData.postValue(folderShortInfo);\n            mFmErrorLiveData.postValue(th);\n        }\n    }\n\n    private void filterAndSort() {\n        boolean displayDotFiles = (mSelectedOptions & FmListOptions.OPTIONS_DISPLAY_DOT_FILES) != 0;\n        boolean foldersOnTop = (mSelectedOptions & FmListOptions.OPTIONS_FOLDERS_FIRST) != 0;\n\n        List<FmItem> filteredList;\n        synchronized (mFmItems) {\n            if (!TextUtils.isEmpty(mQueryString)) {\n                filteredList = AdvancedSearchView.matches(mQueryString, mFmItems, FmItem::getName,\n                        AdvancedSearchView.SEARCH_TYPE_CONTAINS);\n            } else filteredList = new ArrayList<>(mFmItems);\n        }\n        if (ThreadUtils.isInterrupted()) {\n            return;\n        }\n        if (!displayDotFiles) {\n            Iterator<FmItem> iterator = filteredList.listIterator();\n            while (iterator.hasNext()) {\n                FmItem fmItem = iterator.next();\n                if (fmItem.getName().startsWith(\".\")) {\n                    iterator.remove();\n                }\n            }\n        }\n        if (ThreadUtils.isInterrupted()) {\n            return;\n        }\n        // Sort by name first\n        Collections.sort(filteredList, (o1, o2) -> AlphanumComparator.compareStringIgnoreCase(o1.getName(), o2.getName()));\n        if (mSortBy == FmListOptions.SORT_BY_NAME) {\n            if (mReverseSort) {\n                Collections.reverse(filteredList);\n            }\n        } else {\n            // Other sorting options\n            int inverse = mReverseSort ? -1 : 1;\n            Collections.sort(filteredList, (o1, o2) -> {\n                Path p1 = o1.path;\n                Path p2 = o2.path;\n                if (mSortBy == FmListOptions.SORT_BY_LAST_MODIFIED) {\n                    return -Long.compare(o1.getLastModified(), o2.getLastModified()) * inverse;\n                }\n                if (mSortBy == FmListOptions.SORT_BY_SIZE) {\n                    return -Long.compare(o1.getSize(), o2.getSize()) * inverse;\n                }\n                if (mSortBy == FmListOptions.SORT_BY_TYPE) {\n                    return p1.getType().compareToIgnoreCase(p2.getType()) * inverse;\n                }\n                return 0;\n            });\n        }\n        if (foldersOnTop) {\n            // Folders should be on top\n            Collections.sort(filteredList, (o1, o2) -> -Boolean.compare(o1.isDirectory, o2.isDirectory));\n        }\n        if (ThreadUtils.isInterrupted()) {\n            return;\n        }\n        if (mScrollToFilename != null) {\n            for (int i = 0; i < filteredList.size(); ++i) {\n                if (mScrollToFilename.equals(filteredList.get(i).getName())) {\n                    setScrollPosition(mCurrentUri, i);\n                    break;\n                }\n            }\n            mScrollToFilename = null;\n        }\n        mFmItemsLiveData.postValue(filteredList);\n    }\n\n    @WorkerThread\n    @NonNull\n    private VirtualFileSystem mountVfs() throws IOException {\n        if (!mOptions.isVfs()) {\n            throw new IOException(\"VFS expected, found regular FS.\");\n        }\n        VirtualFileSystem fs = VirtualFileSystem.getFileSystem(mOptions.uri);\n        if (fs == null) {\n            // TODO: 31/5/23 Handle read-only\n            Path filePath = Paths.getStrict(mOptions.uri);\n            Path cachedPath = Paths.get(mFileCache.getCachedFile(filePath));\n            String type = cachedPath.getType();\n            int vfsId;\n            if (ContentType.APK.getMimeType().equals(type)) {\n                vfsId = VirtualFileSystem.mount(filePath.getUri(), cachedPath, ContentType.APK.getMimeType());\n            } else if (FileUtils.isZip(cachedPath)) {\n                vfsId = VirtualFileSystem.mount(filePath.getUri(), cachedPath, ContentType.ZIP.getMimeType());\n            } else if (DexUtils.isDex(cachedPath)) {\n                vfsId = VirtualFileSystem.mount(filePath.getUri(), cachedPath, ContentType2.DEX.getMimeType());\n            } else {\n                vfsId = VirtualFileSystem.mount(filePath.getUri(), cachedPath, cachedPath.getType());\n            }\n            fs = VirtualFileSystem.getFileSystem(vfsId);\n            if (fs == null) {\n                throw new IOException(\"Could not mount \" + mOptions.uri);\n            }\n        }\n        return fs;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/fm/FolderShortInfo.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.fm;\n\nfinal class FolderShortInfo {\n    public int folderCount;\n    public int fileCount;\n    public boolean canRead;\n    public boolean canWrite;\n    public long size = -1;\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/fm/OpenWithActivity.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.fm;\n\nimport android.net.Uri;\nimport android.os.Bundle;\n\nimport androidx.annotation.Nullable;\n\nimport io.github.muntashirakon.AppManager.BaseActivity;\nimport io.github.muntashirakon.AppManager.fm.dialogs.OpenWithDialogFragment;\n\npublic class OpenWithActivity extends BaseActivity {\n    @Override\n    public boolean getTransparentBackground() {\n        return true;\n    }\n\n    @Override\n    protected void onAuthenticated(@Nullable Bundle savedInstanceState) {\n        Uri uri = getIntent().getData();\n        if (uri == null) {\n            finish();\n            return;\n        }\n        OpenWithDialogFragment fragment = OpenWithDialogFragment.getInstance(uri, getIntent().getType(), true);\n        fragment.show(getSupportFragmentManager(), OpenWithDialogFragment.TAG);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/fm/SharableItems.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.fm;\n\nimport android.content.Intent;\nimport android.net.Uri;\n\nimport androidx.annotation.NonNull;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport io.github.muntashirakon.io.Path;\n\npublic class SharableItems {\n    public final List<Path> pathList;\n    public final String mimeType;\n\n    public SharableItems(List<Path> pathList) {\n        this(pathList, findBestMimeType(pathList));\n    }\n\n    public SharableItems(List<Path> pathList, String mimeType) {\n        this.pathList = pathList;\n        this.mimeType = mimeType;\n    }\n\n    public Intent toSharableIntent() {\n        Intent intent;\n        if (pathList.size() == 1) {\n            intent = new Intent(Intent.ACTION_SEND)\n                    .setType(mimeType)\n                    .putExtra(Intent.EXTRA_STREAM, FmProvider.getContentUri(pathList.get(0)))\n                    .addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);\n        } else {\n            ArrayList<Uri> sharableUris = new ArrayList<>(pathList.size());\n            for (Path path : pathList) {\n                sharableUris.add(FmProvider.getContentUri(path));\n            }\n            intent = new Intent(Intent.ACTION_SEND_MULTIPLE)\n                    .setType(mimeType)\n                    .putParcelableArrayListExtra(Intent.EXTRA_STREAM, sharableUris)\n                    .addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);\n        }\n        return Intent.createChooser(intent, null).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);\n    }\n\n    @NonNull\n    public static String findBestMimeType(@NonNull List<Path> pathList) {\n        String mimeType = null;\n        boolean splitMime = false;\n        for (Path path : pathList) {\n            String thisMime = path.getPathContentInfo().getMimeType();\n            if (thisMime == null) {\n                thisMime = path.getType();\n            }\n            if (splitMime) {\n                thisMime = thisMime.split(\"/\")[0];\n            }\n            if (mimeType == null) {\n                mimeType = thisMime;\n            } else if (!mimeType.equals(thisMime)) {\n                if (splitMime) {\n                    // The first part aren't consistent\n                    return \"*/*\";\n                }\n                String splitMimeType = mimeType.split(\"/\")[0];\n                String thisSplitMime = thisMime.split(\"/\")[0];\n                if (!splitMimeType.equals(thisSplitMime)) {\n                    // The first part aren't consistent\n                    return \"*/*\";\n                }\n                splitMime = true;\n                mimeType = splitMimeType;\n            }\n        }\n        if (mimeType == null) {\n            mimeType = ContentType2.OTHER.getMimeType();\n        }\n        return splitMime ? (mimeType + \"/*\") : mimeType;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/fm/dialogs/ChangeFileModeDialogFragment.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.fm.dialogs;\n\nimport android.app.Dialog;\nimport android.os.Bundle;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.fragment.app.DialogFragment;\n\nimport com.google.android.material.checkbox.MaterialCheckBox;\nimport com.google.android.material.dialog.MaterialAlertDialogBuilder;\nimport com.google.android.material.materialswitch.MaterialSwitch;\n\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.fm.FmUtils;\nimport io.github.muntashirakon.widget.TextInputTextView;\n\npublic class ChangeFileModeDialogFragment extends DialogFragment {\n    public static final String TAG = ChangeFileModeDialogFragment.class.getSimpleName();\n\n    public interface OnChangeFileModeInterface {\n        void onChangeMode(int mode, boolean recursive);\n    }\n\n    private static final String ARG_MODE = \"mode\";\n    private static final String ARG_DISPLAY_RECURSIVE = \"recursive\";\n\n    @NonNull\n    public static ChangeFileModeDialogFragment getInstance(int mode, boolean recursive,\n                                                           @Nullable OnChangeFileModeInterface changeFileModeInterface) {\n        ChangeFileModeDialogFragment fragment = new ChangeFileModeDialogFragment();\n        Bundle args = new Bundle();\n        args.putInt(ARG_MODE, mode);\n        args.putBoolean(ARG_DISPLAY_RECURSIVE, recursive);\n        fragment.setArguments(args);\n        fragment.setOnChangeFileModeInterface(changeFileModeInterface);\n        return fragment;\n    }\n\n    @Nullable\n    private OnChangeFileModeInterface mOnChangeFileModeInterface;\n    private View mDialogView;\n    private MaterialCheckBox mOwnerRead;\n    private MaterialCheckBox mOwnerWrite;\n    private MaterialCheckBox mOwnerExec;\n    private MaterialCheckBox mGroupRead;\n    private MaterialCheckBox mGroupWrite;\n    private MaterialCheckBox mGroupExec;\n    private MaterialCheckBox mOthersRead;\n    private MaterialCheckBox mOthersWrite;\n    private MaterialCheckBox mOthersExec;\n    private MaterialSwitch mUidBit;\n    private MaterialSwitch mGidBit;\n    private MaterialSwitch mStickyBit;\n    private TextInputTextView mPreview;\n    private MaterialCheckBox mRecursive;\n    private int mOldMode;\n    private int mMode;\n\n    @SuppressWarnings(\"OctalInteger\")\n    @NonNull\n    @Override\n    public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {\n        mMode = mOldMode = requireArguments().getInt(ARG_MODE);\n        boolean displayRecursive = requireArguments().getBoolean(ARG_DISPLAY_RECURSIVE);\n        mDialogView = View.inflate(requireActivity(), R.layout.dialog_change_file_mode, null);\n        mOwnerRead = mDialogView.findViewById(R.id.user_read);\n        mOwnerRead.setChecked((mOldMode & 0400) != 0);\n        mOwnerRead.setOnCheckedChangeListener((buttonView, isChecked) -> updateModePreview(0400, isChecked));\n        mOwnerWrite = mDialogView.findViewById(R.id.user_write);\n        mOwnerWrite.setChecked((mOldMode & 0200) != 0);\n        mOwnerWrite.setOnCheckedChangeListener((buttonView, isChecked) -> updateModePreview(0200, isChecked));\n        mOwnerExec = mDialogView.findViewById(R.id.user_exec);\n        mOwnerExec.setChecked((mOldMode & 0100) != 0);\n        mOwnerExec.setOnCheckedChangeListener((buttonView, isChecked) -> updateModePreview(0100, isChecked));\n        mGroupRead = mDialogView.findViewById(R.id.group_read);\n        mGroupRead.setChecked((mOldMode & 040) != 0);\n        mGroupRead.setOnCheckedChangeListener((buttonView, isChecked) -> updateModePreview(040, isChecked));\n        mGroupWrite = mDialogView.findViewById(R.id.group_write);\n        mGroupWrite.setChecked((mOldMode & 020) != 0);\n        mGroupWrite.setOnCheckedChangeListener((buttonView, isChecked) -> updateModePreview(020, isChecked));\n        mGroupExec = mDialogView.findViewById(R.id.group_exec);\n        mGroupExec.setChecked((mOldMode & 010) != 0);\n        mGroupExec.setOnCheckedChangeListener((buttonView, isChecked) -> updateModePreview(010, isChecked));\n        mOthersRead = mDialogView.findViewById(R.id.others_read);\n        mOthersRead.setChecked((mOldMode & 04) != 0);\n        mOthersRead.setOnCheckedChangeListener((buttonView, isChecked) -> updateModePreview(04, isChecked));\n        mOthersWrite = mDialogView.findViewById(R.id.others_write);\n        mOthersWrite.setChecked((mOldMode & 02) != 0);\n        mOthersWrite.setOnCheckedChangeListener((buttonView, isChecked) -> updateModePreview(02, isChecked));\n        mOthersExec = mDialogView.findViewById(R.id.others_exec);\n        mOthersExec.setChecked((mOldMode & 01) != 0);\n        mOthersExec.setOnCheckedChangeListener((buttonView, isChecked) -> updateModePreview(01, isChecked));\n        mUidBit = mDialogView.findViewById(R.id.uid_bit);\n        mUidBit.setChecked((mOldMode & 04000) != 0);\n        mUidBit.setOnCheckedChangeListener((buttonView, isChecked) -> updateModePreview(04000, isChecked));\n        mGidBit = mDialogView.findViewById(R.id.gid_bit);\n        mGidBit.setChecked((mOldMode & 02000) != 0);\n        mGidBit.setOnCheckedChangeListener((buttonView, isChecked) -> updateModePreview(02000, isChecked));\n        mStickyBit = mDialogView.findViewById(R.id.sticky_bit);\n        mStickyBit.setChecked((mOldMode & 01000) != 0);\n        mStickyBit.setOnCheckedChangeListener((buttonView, isChecked) -> updateModePreview(01000, isChecked));\n        mPreview = mDialogView.findViewById(R.id.preview);\n        mPreview.setText(FmUtils.getFormattedMode(mOldMode));\n        mRecursive = mDialogView.findViewById(R.id.checkbox);\n        mRecursive.setVisibility(displayRecursive ? View.VISIBLE : View.GONE);\n        return new MaterialAlertDialogBuilder(requireActivity())\n                .setTitle(R.string.change_mode)\n                .setView(mDialogView)\n                .setPositiveButton(R.string.ok, (dialog, which) -> {\n                    if (mOnChangeFileModeInterface != null) {\n                        mOnChangeFileModeInterface.onChangeMode(mMode, mRecursive.isChecked());\n                    }\n                })\n                .setNegativeButton(R.string.cancel, null)\n                .create();\n    }\n\n    @Nullable\n    @Override\n    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {\n        return mDialogView;\n    }\n\n    public void setOnChangeFileModeInterface(@Nullable OnChangeFileModeInterface changeFileModeInterface) {\n        mOnChangeFileModeInterface = changeFileModeInterface;\n    }\n\n    private void updateModePreview(int mode, boolean enabled) {\n        if (enabled) {\n            mMode |= mode;\n        } else mMode &= ~mode;\n        mPreview.setText(FmUtils.getFormattedMode(mMode));\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/fm/dialogs/ChecksumsDialogFragment.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.fm.dialogs;\n\nimport static io.github.muntashirakon.AppManager.utils.UIUtils.displayLongToast;\n\nimport android.app.Application;\nimport android.app.Dialog;\nimport android.net.Uri;\nimport android.os.Bundle;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.core.os.BundleCompat;\nimport androidx.core.util.Pair;\nimport androidx.fragment.app.DialogFragment;\nimport androidx.lifecycle.AndroidViewModel;\nimport androidx.lifecycle.LiveData;\nimport androidx.lifecycle.MutableLiveData;\nimport androidx.lifecycle.ViewModelProvider;\nimport androidx.recyclerview.widget.LinearLayoutManager;\nimport androidx.recyclerview.widget.RecyclerView;\n\nimport com.google.android.material.button.MaterialButton;\nimport com.google.android.material.dialog.MaterialAlertDialogBuilder;\nimport com.google.android.material.textfield.TextInputLayout;\n\nimport org.bouncycastle.jce.provider.BouncyCastleProvider;\n\nimport java.io.InputStream;\nimport java.security.MessageDigest;\nimport java.security.Provider;\nimport java.security.Security;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.zip.CRC32;\n\nimport aosp.libcore.util.HexEncoding;\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.utils.ClipboardUtils;\nimport io.github.muntashirakon.AppManager.utils.DigestUtils;\nimport io.github.muntashirakon.AppManager.utils.ThreadUtils;\nimport io.github.muntashirakon.adapters.SelectedArrayAdapter;\nimport io.github.muntashirakon.dialog.DialogTitleBuilder;\nimport io.github.muntashirakon.io.IoUtils;\nimport io.github.muntashirakon.io.Path;\nimport io.github.muntashirakon.io.Paths;\nimport io.github.muntashirakon.util.AccessibilityUtils;\nimport io.github.muntashirakon.view.TextInputLayoutCompat;\nimport io.github.muntashirakon.widget.MaterialSpinner;\nimport io.github.muntashirakon.widget.TextInputTextView;\n\npublic class ChecksumsDialogFragment extends DialogFragment {\n    public static final String TAG = ChecksumsDialogFragment.class.getSimpleName();\n\n    private static final String ARG_PATH = \"path\";\n\n    @NonNull\n    public static ChecksumsDialogFragment getInstance(@NonNull Path path) {\n        ChecksumsDialogFragment fragment = new ChecksumsDialogFragment();\n        Bundle args = new Bundle();\n        args.putParcelable(ARG_PATH, path.getUri());\n        fragment.setArguments(args);\n        return fragment;\n    }\n\n    private Path mPath;\n    private View mDialogView;\n    private RecyclerView mRecyclerView;\n    private MaterialSpinner mSpinner;\n    private MaterialButton mButton;\n    private TextInputTextView mTextView;\n    private ChecksumsViewModel mViewModel;\n    private ChecksumsRecyclerViewAdapter mAdapter;\n\n    @NonNull\n    @Override\n    public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {\n        mViewModel = new ViewModelProvider(this).get(ChecksumsViewModel.class);\n        mPath = Paths.get(Objects.requireNonNull(BundleCompat.getParcelable(requireArguments(), ARG_PATH, Uri.class)));\n        mAdapter = new ChecksumsRecyclerViewAdapter();\n        mDialogView = View.inflate(requireActivity(), R.layout.dialog_checksums, null);\n        mRecyclerView = mDialogView.findViewById(R.id.recycler_view);\n        mRecyclerView.setLayoutManager(new LinearLayoutManager(requireContext()));\n        mRecyclerView.setAdapter(mAdapter);\n        mSpinner = mDialogView.findViewById(R.id.spinner);\n        SelectedArrayAdapter<String> algorithmsAdapter = new SelectedArrayAdapter<>(requireContext(),\n                io.github.muntashirakon.ui.R.layout.auto_complete_dropdown_item_small, getAlgorithms());\n        mSpinner.setAdapter(algorithmsAdapter);\n        mButton = mDialogView.findViewById(R.id.action);\n        mButton.setOnClickListener(v -> {\n            String algorithm = mSpinner.getEditText().getText().toString().trim();\n            mViewModel.loadChecksum(algorithm, mPath);\n        });\n        mTextView = mDialogView.findViewById(R.id.text);\n        mTextView.setVisibility(View.GONE);\n        DialogTitleBuilder titleBuilder = new DialogTitleBuilder(requireActivity())\n                .setTitle(R.string.checksums)\n                .setSubtitle(mPath.getName())\n                .setEndIcon(R.drawable.ic_content_paste, v -> {\n                    String data = ClipboardUtils.readHashValueFromClipboard(v.getContext());\n                    if (data != null) {\n                        for (Map.Entry<String, String> digest : mAdapter.mNameChecksumMap) {\n                            if (digest.getValue().equals(data)) {\n                                if (digest.getValue().equals(DigestUtils.MD5) || digest.getValue().equals(DigestUtils.SHA_1)) {\n                                    displayLongToast(R.string.verified_using_unreliable_hash);\n                                } else {\n                                    displayLongToast(R.string.verified);\n                                }\n                                return;\n                            }\n                        }\n                        displayLongToast(R.string.not_verified);\n                    }\n                })\n                .setEndIconContentDescription(R.string.paste);\n        return new MaterialAlertDialogBuilder(requireActivity())\n                .setCustomTitle(titleBuilder.build())\n                .setView(mDialogView)\n                .setNegativeButton(R.string.close, null)\n                .create();\n    }\n\n    @Nullable\n    @Override\n    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {\n        return mDialogView;\n    }\n\n    @Override\n    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {\n        if (mViewModel != null) {\n            mViewModel.getChecksumsLiveData().observe(getViewLifecycleOwner(), map -> mAdapter.setDefaultList(map));\n            mViewModel.getChecksumLiveData().observe(getViewLifecycleOwner(), algoHashPair -> {\n                mTextView.setVisibility(View.VISIBLE);\n                mTextView.setText(algoHashPair.second);\n                TextInputLayoutCompat.fromTextInputEditText(mTextView).setHint(algoHashPair.first);\n                AccessibilityUtils.requestAccessibilityFocus(mTextView);\n            });\n            mViewModel.loadChecksums(mPath);\n        }\n    }\n\n    private List<String> getAlgorithms() {\n        Provider provider = Security.getProvider(BouncyCastleProvider.PROVIDER_NAME);\n        List<String> algorithms = new ArrayList<>();\n        for (Provider.Service service : provider.getServices()) {\n            if (\"MessageDigest\".equals(service.getType())) {\n                algorithms.add(service.getAlgorithm());\n            }\n        }\n        return algorithms;\n    }\n\n    private static class ChecksumsRecyclerViewAdapter extends RecyclerView.Adapter<ChecksumsRecyclerViewAdapter.ViewHolder> {\n        @NonNull\n        private final List<Map.Entry<String, String>> mNameChecksumMap = new ArrayList<>();\n\n        public void setDefaultList(@NonNull Map<String, String> map) {\n            synchronized (mNameChecksumMap) {\n                mNameChecksumMap.clear();\n                mNameChecksumMap.addAll(map.entrySet());\n                notifyDataSetChanged();\n            }\n        }\n\n        @NonNull\n        @Override\n        public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {\n            View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_text_input_layout_monospace, parent, false);\n            return new ViewHolder(view);\n        }\n\n        @Override\n        public void onBindViewHolder(@NonNull ViewHolder holder, int position) {\n            Map.Entry<String, String> entry;\n            synchronized (mNameChecksumMap) {\n                entry = mNameChecksumMap.get(position);\n            }\n            holder.input.setHint(entry.getKey());\n            holder.textView.setText(entry.getValue());\n        }\n\n        @Override\n        public int getItemCount() {\n            synchronized (mNameChecksumMap) {\n                return mNameChecksumMap.size();\n            }\n        }\n\n        static class ViewHolder extends RecyclerView.ViewHolder {\n            TextInputLayout input;\n            TextInputTextView textView;\n\n            public ViewHolder(@NonNull View itemView) {\n                super(itemView);\n                input = (TextInputLayout) itemView;\n                textView = (TextInputTextView) Objects.requireNonNull(input.getEditText());\n            }\n        }\n    }\n\n    public static class ChecksumsViewModel extends AndroidViewModel {\n        private final MutableLiveData<Map<String, String>> mChecksumsLiveData = new MutableLiveData<>();\n        private final MutableLiveData<Pair<String, String>> mChecksumLiveData = new MutableLiveData<>();\n\n        public ChecksumsViewModel(@NonNull Application application) {\n            super(application);\n        }\n\n        public LiveData<Map<String, String>> getChecksumsLiveData() {\n            return mChecksumsLiveData;\n        }\n\n        public LiveData<Pair<String, String>> getChecksumLiveData() {\n            return mChecksumLiveData;\n        }\n\n        public void loadChecksum(@NonNull String algo, @NonNull Path path) {\n            ThreadUtils.postOnBackgroundThread(() -> {\n                try {\n                    MessageDigest digest = MessageDigest.getInstance(algo, BouncyCastleProvider.PROVIDER_NAME);\n                    try (InputStream is = path.openInputStream()) {\n                        byte[] buffer = new byte[IoUtils.DEFAULT_BUFFER_SIZE];\n                        int length;\n                        while ((length = is.read(buffer)) != -1) {\n                            digest.update(buffer, 0, length);\n                        }\n                    }\n                    mChecksumLiveData.postValue(new Pair<>(algo, HexEncoding.encodeToString(digest.digest(), false)));\n                } catch (Exception e) {\n                    e.printStackTrace();\n                    mChecksumLiveData.postValue(new Pair<>(null, null));\n                }\n            });\n        }\n\n        public void loadChecksums(@NonNull Path path) {\n            ThreadUtils.postOnBackgroundThread(() -> {\n                try {\n                    mChecksumsLiveData.postValue(generateChecksums(path));\n                } catch (Exception e) {\n                    e.printStackTrace();\n                    mChecksumsLiveData.postValue(Collections.emptyMap());\n                }\n            });\n        }\n\n        private Map<String, String> generateChecksums(@NonNull Path path) throws Exception {\n            String[] nativeAlgo = new String[]{\"MD5\", \"SHA-1\", \"SHA-256\", \"SHA-512\"};\n            String[] bcAlgo = new String[]{\"SHA3-256\", \"SHA3-512\"};\n            MessageDigest[] messageDigests = new MessageDigest[nativeAlgo.length + bcAlgo.length];\n            String[] algoNames = new String[]{\"MD5 (unreliable)\", \"SHA-1 (unreliable)\", \"SHA-256\", \"SHA-512\", \"SHA3-256\", \"SHA3-512\"};\n            for (int i = 0; i < nativeAlgo.length; ++i) {\n                messageDigests[i] = MessageDigest.getInstance(nativeAlgo[i]);\n            }\n            for (int i = 0; i < bcAlgo.length; ++i) {\n                messageDigests[nativeAlgo.length + i] = MessageDigest.getInstance(bcAlgo[i], BouncyCastleProvider.PROVIDER_NAME);\n            }\n            CRC32 crc32 = new CRC32();\n            try (InputStream is = path.openInputStream()) {\n                byte[] buffer = new byte[IoUtils.DEFAULT_BUFFER_SIZE];\n                int length;\n                while ((length = is.read(buffer)) != -1) {\n                    for (MessageDigest messageDigest : messageDigests) {\n                        messageDigest.update(buffer, 0, length);\n                    }\n                    crc32.update(buffer, 0, length);\n                }\n            }\n            Map<String, String> checksums = new LinkedHashMap<>(messageDigests.length + 1);\n            checksums.put(\"CRC32 (insecure)\", HexEncoding.encodeToString(DigestUtils.longToBytes(crc32.getValue()), false));\n            for (int i = 0; i < messageDigests.length; ++i) {\n                checksums.put(algoNames[i], HexEncoding.encodeToString(messageDigests[i].digest(), false));\n            }\n            return checksums;\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/fm/dialogs/FilePropertiesDialogFragment.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.fm.dialogs;\n\nimport android.app.Application;\nimport android.content.Context;\nimport android.content.pm.ApplicationInfo;\nimport android.content.pm.PackageManager;\nimport android.net.Uri;\nimport android.os.Build;\nimport android.os.Bundle;\nimport android.system.ErrnoException;\nimport android.text.SpannableStringBuilder;\nimport android.text.TextUtils;\nimport android.text.format.Formatter;\nimport android.util.Log;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.ImageView;\nimport android.widget.TextView;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.WorkerThread;\nimport androidx.core.os.BundleCompat;\nimport androidx.lifecycle.AndroidViewModel;\nimport androidx.lifecycle.LiveData;\nimport androidx.lifecycle.MutableLiveData;\nimport androidx.lifecycle.ViewModelProvider;\n\nimport com.google.android.material.button.MaterialButton;\nimport com.google.android.material.checkbox.MaterialCheckBox;\nimport com.google.android.material.textfield.TextInputLayout;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.concurrent.Future;\n\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.fm.FmItem;\nimport io.github.muntashirakon.AppManager.fm.FmUtils;\nimport io.github.muntashirakon.AppManager.fm.icons.FmIconFetcher;\nimport io.github.muntashirakon.AppManager.self.imagecache.ImageLoader;\nimport io.github.muntashirakon.AppManager.settings.Ops;\nimport io.github.muntashirakon.AppManager.users.Groups;\nimport io.github.muntashirakon.AppManager.users.Owners;\nimport io.github.muntashirakon.AppManager.utils.DateUtils;\nimport io.github.muntashirakon.AppManager.utils.PackageUtils;\nimport io.github.muntashirakon.AppManager.utils.ThreadUtils;\nimport io.github.muntashirakon.AppManager.utils.UIUtils;\nimport io.github.muntashirakon.dialog.CapsuleBottomSheetDialogFragment;\nimport io.github.muntashirakon.dialog.SearchableSingleChoiceDialogBuilder;\nimport io.github.muntashirakon.dialog.TextInputDialogBuilder;\nimport io.github.muntashirakon.io.ExtendedFile;\nimport io.github.muntashirakon.io.Path;\nimport io.github.muntashirakon.io.PathContentInfo;\nimport io.github.muntashirakon.io.Paths;\nimport io.github.muntashirakon.io.UidGidPair;\nimport io.github.muntashirakon.util.LocalizedString;\nimport io.github.muntashirakon.view.TextInputLayoutCompat;\nimport io.github.muntashirakon.widget.TextInputTextView;\n\npublic class FilePropertiesDialogFragment extends CapsuleBottomSheetDialogFragment {\n    public static final String TAG = FilePropertiesDialogFragment.class.getSimpleName();\n\n    private static final String ARG_PATH = \"path\";\n\n    @NonNull\n    public static FilePropertiesDialogFragment getInstance(@NonNull Uri uri) {\n        FilePropertiesDialogFragment fragment = new FilePropertiesDialogFragment();\n        Bundle args = new Bundle();\n        args.putParcelable(ARG_PATH, uri);\n        fragment.setArguments(args);\n        return fragment;\n    }\n\n    private ImageView mIconView;\n    private ImageView mSymlinkIconView;\n    private TextView mNameView;\n    private TextView mSummaryView;\n    private TextView mChecksumsView;\n    private MaterialButton mMoreButton;\n    private TextInputTextView mPathView;\n    private TextInputTextView mTypeView;\n    private TextInputTextView mTargetPathView;\n    private TextInputLayout mTargetPathLayout;\n    private TextInputTextView mOpenWithView;\n    private TextInputLayout mOpenWithLayout;\n    private TextInputTextView mSizeView;\n    private TextInputTextView mDateCreatedView;\n    private TextInputTextView mDateModifiedView;\n    private TextInputLayout mDateModifiedLayout;\n    private TextInputTextView mDateAccessedView;\n    private TextInputLayout mDateAccessedLayout;\n    private TextInputTextView mMoreInfoView;\n    private TextInputTextView mModeView;\n    private TextInputLayout mModeLayout;\n    private TextInputTextView mOwnerView;\n    private TextInputLayout mOwnerLayout;\n    private TextInputTextView mGroupView;\n    private TextInputLayout mGroupLayout;\n    private TextInputTextView mSelinuxContextView;\n    private TextInputLayout mSelinuxContextLayout;\n\n    private FilePropertiesViewModel mViewModel;\n    @Nullable\n    private FileProperties mFileProperties;\n\n    @NonNull\n    @Override\n    public View initRootView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {\n        return inflater.inflate(R.layout.dialog_file_properties, container, false);\n    }\n\n    @Override\n    public void onBodyInitialized(@NonNull View bodyView, @Nullable Bundle savedInstanceState) {\n        Path path = Paths.get(Objects.requireNonNull(BundleCompat.getParcelable(requireArguments(), ARG_PATH, Uri.class)));\n        mViewModel = new ViewModelProvider(this).get(FilePropertiesViewModel.class);\n        mIconView = bodyView.findViewById(android.R.id.icon);\n        mSymlinkIconView = bodyView.findViewById(R.id.symbolic_link_icon);\n        mNameView = bodyView.findViewById(R.id.name);\n        mSummaryView = bodyView.findViewById(R.id.summary);\n        mChecksumsView = bodyView.findViewById(R.id.checksums);\n        mChecksumsView.setOnClickListener(v -> {\n            ChecksumsDialogFragment fragment = ChecksumsDialogFragment.getInstance(path);\n            fragment.show(getChildFragmentManager(), ChecksumsDialogFragment.TAG);\n        });\n        mMoreButton = bodyView.findViewById(R.id.more);\n        mMoreButton.setVisibility(View.GONE);\n        mPathView = bodyView.findViewById(R.id.path);\n        mTypeView = bodyView.findViewById(R.id.type);\n        mTargetPathView = bodyView.findViewById(R.id.target_file);\n        mTargetPathLayout = TextInputLayoutCompat.fromTextInputEditText(mTargetPathView);\n        mOpenWithView = bodyView.findViewById(R.id.open_with);\n        mOpenWithLayout = TextInputLayoutCompat.fromTextInputEditText(mOpenWithView);\n        TextInputLayoutCompat.fixEndIcon(mOpenWithLayout);\n        // TODO: 16/11/22 Handle open with\n        mOpenWithLayout.setVisibility(View.GONE);\n        mSizeView = bodyView.findViewById(R.id.size);\n        mDateCreatedView = bodyView.findViewById(R.id.date_created);\n        mDateModifiedView = bodyView.findViewById(R.id.date_modified);\n        mDateModifiedLayout = TextInputLayoutCompat.fromTextInputEditText(mDateModifiedView);\n        TextInputLayoutCompat.fixEndIcon(mDateModifiedLayout);\n        mDateModifiedLayout.setEndIconOnClickListener(v -> {\n            if (mFileProperties != null) {\n                mViewModel.setModificationTime(mFileProperties, System.currentTimeMillis());\n            }\n        });\n        mDateAccessedView = bodyView.findViewById(R.id.date_accessed);\n        mDateAccessedLayout = TextInputLayoutCompat.fromTextInputEditText(mDateAccessedView);\n        mDateAccessedLayout.setEndIconOnClickListener(v -> {\n            if (mFileProperties != null) {\n                mViewModel.setLastAccessTime(mFileProperties, System.currentTimeMillis());\n            }\n        });\n        TextInputLayoutCompat.fixEndIcon(mDateAccessedLayout);\n        mMoreInfoView = bodyView.findViewById(R.id.more_info);\n        TextInputLayoutCompat.fromTextInputEditText(mMoreInfoView).setVisibility(View.GONE);\n        mModeView = bodyView.findViewById(R.id.file_mode);\n        mModeLayout = TextInputLayoutCompat.fromTextInputEditText(mModeView);\n        TextInputLayoutCompat.fixEndIcon(mModeLayout);\n        mModeLayout.setEndIconOnClickListener(v -> {\n            if (mFileProperties != null) {\n                ChangeFileModeDialogFragment dialog = ChangeFileModeDialogFragment.getInstance(mFileProperties.mode,\n                        mFileProperties.isDirectory, (mode, recursive) ->\n                                mViewModel.setMode(mFileProperties, mode, recursive));\n                dialog.show(getChildFragmentManager(), ChangeFileModeDialogFragment.TAG);\n            }\n        });\n        mOwnerView = bodyView.findViewById(R.id.owner_id);\n        mOwnerLayout = TextInputLayoutCompat.fromTextInputEditText(mOwnerView);\n        TextInputLayoutCompat.fixEndIcon(mOwnerLayout);\n        mOwnerLayout.setEndIconOnClickListener(v -> {\n            if (mFileProperties != null) {\n                mViewModel.fetchOwnerList();\n            }\n        });\n        mGroupView = bodyView.findViewById(R.id.group_id);\n        mGroupLayout = TextInputLayoutCompat.fromTextInputEditText(mGroupView);\n        TextInputLayoutCompat.fixEndIcon(mGroupLayout);\n        mGroupLayout.setEndIconOnClickListener(v -> {\n            if (mFileProperties != null) {\n                mViewModel.fetchGroupList();\n            }\n        });\n        mSelinuxContextView = bodyView.findViewById(R.id.selinux_context);\n        mSelinuxContextLayout = TextInputLayoutCompat.fromTextInputEditText(mSelinuxContextView);\n        TextInputLayoutCompat.fixEndIcon(mSelinuxContextLayout);\n        mSelinuxContextLayout.setEndIconOnClickListener(v -> displaySeContextUpdater());\n\n        // Live data\n        mViewModel.getFilePropertiesLiveData().observe(getViewLifecycleOwner(), this::updateProperties);\n        mViewModel.getFmItemLiveData().observe(getViewLifecycleOwner(), fmItem -> {\n            ImageLoader.getInstance().displayImage(fmItem.getTag(), mIconView, new FmIconFetcher(fmItem));\n            PathContentInfo contentInfo = fmItem.getContentInfo();\n            if (contentInfo != null) {\n                String name = contentInfo.getName();\n                String mime = contentInfo.getMimeType();\n                String message = contentInfo.getMessage();\n                if (mime != null) {\n                    mTypeView.setText(String.format(Locale.ROOT, \"%s (%s)\", name, mime));\n                } else {\n                    mTypeView.setText(name);\n                }\n                if (message != null) {\n                    TextInputLayoutCompat.fromTextInputEditText(mMoreInfoView).setVisibility(View.VISIBLE);\n                    mMoreInfoView.setText(message);\n                }\n            }\n        });\n        mViewModel.getOwnerListLiveData().observe(getViewLifecycleOwner(), this::displayUidUpdater);\n        mViewModel.getGroupListLiveData().observe(getViewLifecycleOwner(), this::displayGidUpdater);\n        mViewModel.getOwnerLiveData().observe(getViewLifecycleOwner(), ownerName -> {\n            assert mFileProperties != null;\n            assert mFileProperties.uidGidPair != null;\n            mOwnerView.setText(String.format(Locale.ROOT, \"%s (%d)\", ownerName, mFileProperties.uidGidPair.uid));\n        });\n        mViewModel.getGroupLiveData().observe(getViewLifecycleOwner(), groupName -> {\n            assert mFileProperties != null;\n            assert mFileProperties.uidGidPair != null;\n            mGroupView.setText(String.format(Locale.ROOT, \"%s (%d)\", groupName, mFileProperties.uidGidPair.gid));\n        });\n\n        // Load live data\n        mViewModel.loadFileProperties(path);\n        mViewModel.loadFmItem(path);\n    }\n\n    private void updateProperties(@NonNull FileProperties fileProperties) {\n        boolean noInit = mFileProperties == null;\n        if (noInit && fileProperties.isDirectory) {\n            mChecksumsView.setVisibility(View.GONE);\n        }\n        boolean uidGidChanged = noInit || mFileProperties.uidGidPair != fileProperties.uidGidPair;\n        if (noInit || mFileProperties.isDirectory != fileProperties.isDirectory) {\n            if (fileProperties.isDirectory) {\n                mIconView.setImageResource(R.drawable.ic_folder);\n            }\n        }\n        if (noInit || mFileProperties.isSymlink != fileProperties.isSymlink) {\n            mSymlinkIconView.setVisibility(fileProperties.isSymlink ? View.VISIBLE : View.GONE);\n        }\n        if (noInit || !Objects.equals(mFileProperties.name, fileProperties.name)) {\n            mNameView.setText(fileProperties.name);\n        }\n        if (noInit || !Objects.equals(mFileProperties.readablePath, fileProperties.readablePath)) {\n            mPathView.setText(fileProperties.readablePath);\n        }\n        if (noInit || !Objects.equals(mFileProperties.targetPath, fileProperties.targetPath)) {\n            if (fileProperties.targetPath != null) {\n                mTargetPathView.setText(fileProperties.targetPath);\n            } else {\n                mTargetPathLayout.setVisibility(View.GONE);\n            }\n        }\n        if (noInit || mFileProperties.size != fileProperties.size) {\n            if (fileProperties.size != -1) {\n                mSizeView.setText(String.format(Locale.getDefault(), \"%s (%,d bytes)\",\n                        Formatter.formatShortFileSize(requireContext(), fileProperties.size), fileProperties.size));\n            }\n        }\n        if (noInit || mFileProperties.size != fileProperties.size\n                || mFileProperties.lastModified != fileProperties.lastModified\n                || mFileProperties.fileCount != fileProperties.fileCount\n                || mFileProperties.folderCount != fileProperties.folderCount) {\n            updateSummary(fileProperties);\n        }\n        if (noInit || mFileProperties.lastModified != fileProperties.lastModified) {\n            mDateModifiedView.setText(DateUtils.formatDateTime(requireContext(), fileProperties.lastModified));\n        }\n        if (noInit || mFileProperties.creationTime != fileProperties.creationTime) {\n            mDateCreatedView.setText(fileProperties.creationTime > 0 ? DateUtils.formatDateTime(requireContext(),\n                    fileProperties.creationTime) : \"--\");\n        }\n        if (noInit || mFileProperties.lastAccess != fileProperties.lastAccess) {\n            mDateAccessedView.setText(fileProperties.lastAccess > 0 ? DateUtils.formatDateTime(requireContext(),\n                    fileProperties.lastAccess) : \"--\");\n        }\n        if (noInit || mFileProperties.canWrite != fileProperties.canWrite) {\n            boolean isPhysicalWritable = fileProperties.canWrite && fileProperties.isPhysicalFs;\n            mDateModifiedLayout.setEndIconVisible(isPhysicalWritable);\n            mDateAccessedLayout.setEndIconVisible(isPhysicalWritable);\n            mOwnerLayout.setEndIconVisible(isPhysicalWritable);\n            mGroupLayout.setEndIconVisible(isPhysicalWritable);\n            mModeLayout.setEndIconVisible(isPhysicalWritable);\n            mSelinuxContextLayout.setEndIconVisible(Ops.isWorkingUidRoot() && isPhysicalWritable);\n        }\n        if (noInit || mFileProperties.mode != fileProperties.mode) {\n            mModeView.setText(fileProperties.mode != 0 ? FmUtils.getFormattedMode(fileProperties.mode) : \"--\");\n        }\n        if (uidGidChanged) {\n            if (fileProperties.uidGidPair == null) {\n                mOwnerView.setText(\"--\");\n                mGroupView.setText(\"--\");\n            }\n        }\n        if (noInit || !Objects.equals(mFileProperties.context, fileProperties.context)) {\n            mSelinuxContextView.setText(fileProperties.context != null ? fileProperties.context : \"--\");\n        }\n        mFileProperties = fileProperties;\n        // Load others\n        if (fileProperties.size == -1) {\n            mViewModel.loadFileSize(fileProperties);\n        }\n        if (fileProperties.uidGidPair != null && uidGidChanged) {\n            mViewModel.loadOwnerInfo(fileProperties.uidGidPair.uid);\n            mViewModel.loadGroupInfo(fileProperties.uidGidPair.gid);\n        }\n    }\n\n    private void updateSummary(@NonNull FileProperties fileProperties) {\n        StringBuilder summary = new StringBuilder();\n        // 1. Date modified\n        summary.append(DateUtils.formatDateTime(requireContext(), fileProperties.lastModified));\n        // 2. Size\n        if (fileProperties.size > 0) {\n            summary.append(\" • \").append(Formatter.formatShortFileSize(requireContext(), fileProperties.size));\n        }\n        // 3. Folders and files\n        if (fileProperties.folderCount > 0 && fileProperties.fileCount > 0) {\n            summary.append(\" • \")\n                    .append(getResources().getQuantityString(R.plurals.folder_count, fileProperties.folderCount,\n                            fileProperties.folderCount))\n                    .append(\", \")\n                    .append(getResources().getQuantityString(R.plurals.file_count, fileProperties.fileCount,\n                            fileProperties.fileCount));\n        } else if (fileProperties.folderCount > 0) {\n            summary.append(\" • \")\n                    .append(getResources().getQuantityString(R.plurals.folder_count, fileProperties.folderCount,\n                            fileProperties.folderCount));\n        } else if (fileProperties.fileCount > 0) {\n            summary.append(\" • \")\n                    .append(getResources().getQuantityString(R.plurals.file_count, fileProperties.fileCount,\n                            fileProperties.fileCount));\n        }\n        mSummaryView.setText(summary);\n    }\n\n    private void displayUidUpdater(@NonNull List<AndroidId> owners) {\n        assert mFileProperties != null;\n        List<CharSequence> uidNames = new ArrayList<>(owners.size());\n        for (AndroidId androidId : owners) {\n            uidNames.add(androidId.toLocalizedString(requireContext()));\n        }\n        AndroidId selectedUid;\n        if (mFileProperties.uidGidPair != null) {\n            selectedUid = new AndroidId();\n            selectedUid.id = mFileProperties.uidGidPair.uid;\n        } else selectedUid = null;\n        View view;\n        MaterialCheckBox checkBox;\n        if (mFileProperties.isDirectory) {\n            view = View.inflate(requireContext(), R.layout.item_checkbox, null);\n            checkBox = view.findViewById(R.id.checkbox);\n            checkBox.setText(R.string.apply_recursively);\n        } else {\n            view = null;\n            checkBox = null;\n        }\n        new SearchableSingleChoiceDialogBuilder<>(requireContext(), owners, uidNames)\n                .setSelection(selectedUid)\n                .setTitle(R.string.change_owner_uid)\n                .setView(view)\n                .setPositiveButton(R.string.ok, (dialog, which, uid) -> {\n                    if (uid != null) {\n                        mViewModel.setUid(mFileProperties, uid.id, checkBox != null && checkBox.isChecked());\n                    }\n                })\n                .setNegativeButton(R.string.cancel, null)\n                .show();\n    }\n\n    private void displayGidUpdater(@NonNull List<AndroidId> groups) {\n        assert mFileProperties != null;\n        List<CharSequence> gidNames = new ArrayList<>(groups.size());\n        for (AndroidId androidId : groups) {\n            gidNames.add(androidId.toLocalizedString(requireContext()));\n        }\n        AndroidId selectedGid;\n        if (mFileProperties.uidGidPair != null) {\n            selectedGid = new AndroidId();\n            selectedGid.id = mFileProperties.uidGidPair.gid;\n        } else selectedGid = null;\n        View view;\n        MaterialCheckBox checkBox;\n        if (mFileProperties.isDirectory) {\n            view = View.inflate(requireContext(), R.layout.item_checkbox, null);\n            checkBox = view.findViewById(R.id.checkbox);\n            checkBox.setText(R.string.apply_recursively);\n        } else {\n            view = null;\n            checkBox = null;\n        }\n        new SearchableSingleChoiceDialogBuilder<>(requireContext(), groups, gidNames)\n                .setSelection(selectedGid)\n                .setTitle(R.string.change_group_gid)\n                .setView(view)\n                .setPositiveButton(R.string.ok, (dialog, which, gid) -> {\n                    if (gid != null) {\n                        mViewModel.setGid(mFileProperties, gid.id, checkBox != null && checkBox.isChecked());\n                    }\n                })\n                .setNegativeButton(R.string.cancel, null)\n                .show();\n    }\n\n    private void displaySeContextUpdater() {\n        assert mFileProperties != null;\n        new TextInputDialogBuilder(requireContext(), null)\n                .setTitle(R.string.title_change_selinux_context)\n                .setInputText(mFileProperties.context)\n                .setCheckboxLabel(mFileProperties.isDirectory ? R.string.apply_recursively : 0)\n                .setPositiveButton(R.string.ok, (dialog, which, context, recursive) -> {\n                    if (!TextUtils.isEmpty(context)) {\n                        mViewModel.setSeContext(mFileProperties, context.toString().trim(), recursive);\n                    }\n                })\n                .setNegativeButton(R.string.cancel, null)\n                .setNeutralButton(R.string.restore, (dialog, which, context, recursive) ->\n                        mViewModel.restorecon(mFileProperties, recursive))\n                .show();\n    }\n\n    public static class FilePropertiesViewModel extends AndroidViewModel {\n        private final MutableLiveData<FileProperties> mFilePropertiesLiveData = new MutableLiveData<>();\n        private final MutableLiveData<FmItem> mFmItemLiveData = new MutableLiveData<>();\n        private final MutableLiveData<List<AndroidId>> mOwnerListLiveData = new MutableLiveData<>();\n        private final MutableLiveData<List<AndroidId>> mGroupListLiveData = new MutableLiveData<>();\n        private final MutableLiveData<String> mOwnerLiveData = new MutableLiveData<>();\n        private final MutableLiveData<String> mGroupLiveData = new MutableLiveData<>();\n\n        private final List<AndroidId> mOwnerList = new ArrayList<>();\n        private final List<AndroidId> mGroupList = new ArrayList<>();\n\n        @Nullable\n        private Future<?> sizeResult;\n\n        public FilePropertiesViewModel(@NonNull Application application) {\n            super(application);\n        }\n\n        @Override\n        protected void onCleared() {\n            // Size checks can take forever, so it's a good idea to terminate the process when the dialog is exited\n            if (sizeResult != null) {\n                sizeResult.cancel(true);\n            }\n            super.onCleared();\n        }\n\n        public void setMode(@NonNull FileProperties properties, int mode, boolean recursive) {\n            ThreadUtils.postOnBackgroundThread(() -> {\n                ExtendedFile file = properties.path.getFile();\n                if (file == null) {\n                    return;\n                }\n                if (recursive) {\n                    setModeRecursive(file, mode);\n                }\n                try {\n                    file.setMode(mode);\n                    FileProperties newProperties = new FileProperties(properties);\n                    newProperties.mode = newProperties.path.getMode();\n                    mFilePropertiesLiveData.postValue(newProperties);\n                } catch (ErrnoException e) {\n                    e.printStackTrace();\n                }\n            });\n        }\n\n        public void fetchOwnerList() {\n            ThreadUtils.postOnBackgroundThread(() -> {\n                if (mOwnerList.isEmpty()) {\n                    getOwnersAndGroupsInternal();\n                }\n                mOwnerListLiveData.postValue(new ArrayList<>(mOwnerList));\n            });\n        }\n\n        public void fetchGroupList() {\n            ThreadUtils.postOnBackgroundThread(() -> {\n                if (mGroupList.isEmpty()) {\n                    getOwnersAndGroupsInternal();\n                }\n                mGroupListLiveData.postValue(new ArrayList<>(mGroupList));\n            });\n        }\n\n        @WorkerThread\n        private void getOwnersAndGroupsInternal() {\n            mOwnerList.clear();\n            mGroupList.clear();\n            // Add owners\n            Map<Integer, String> uidOwnerMap = Owners.getUidOwnerMap(false);\n            for (int uid : uidOwnerMap.keySet()) {\n                AndroidId id = new AndroidId();\n                id.id = uid;\n                id.name = Objects.requireNonNull(uidOwnerMap.get(uid));\n                // TODO: 30/6/23 Add a more readable description from android_filesystem_config.h\n                id.description = \"System\";\n                mOwnerList.add(id);\n            }\n            // Add groups\n            Map<Integer, String> gidGroupMap = Groups.getGidGroupMap(false);\n            for (int gid : gidGroupMap.keySet()) {\n                AndroidId id = new AndroidId();\n                id.id = gid;\n                id.name = Objects.requireNonNull(gidGroupMap.get(gid));\n                id.description = \"System\";\n                mGroupList.add(id);\n            }\n            List<ApplicationInfo> applicationInfoList = PackageUtils.getAllApplications(0);\n            Map<Integer, CharSequence> uidList = new HashMap<>(applicationInfoList.size());\n            PackageManager pm = getApplication().getPackageManager();\n            for (ApplicationInfo info : applicationInfoList) {\n                if (uidOwnerMap.containsKey(info.uid)) {\n                    // Omit system UID/GIDs\n                    continue;\n                }\n                if (!uidList.containsKey(info.uid)) {\n                    // Include only the first app label\n                    // TODO: 30/6/23 Include all app names?\n                    uidList.put(info.uid, info.loadLabel(pm));\n                }\n            }\n            for (int uid : uidList.keySet()) {\n                AndroidId id = new AndroidId();\n                id.id = uid;\n                id.name = Owners.formatUid(uid);\n                id.description = Objects.requireNonNull(uidList.get(uid));\n                mOwnerList.add(id);\n                mGroupList.add(id);\n                // Add cached uid\n                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {\n                    int gid = Groups.getCacheAppGid(uid);\n                    if (gid == -1 || gid == uid) {\n                        continue;\n                    }\n                    AndroidId cachedGid = new AndroidId();\n                    cachedGid.id = gid;\n                    cachedGid.name = Groups.formatGid(gid);\n                    cachedGid.description = id.description;\n                    mGroupList.add(cachedGid);\n                }\n            }\n            Collections.sort(mOwnerList, (o1, o2) -> Integer.compare(o1.id, o2.id));\n            Collections.sort(mGroupList, (o1, o2) -> Integer.compare(o1.id, o2.id));\n        }\n\n        public void setUid(@NonNull FileProperties properties, int uid, boolean recursive) {\n            ThreadUtils.postOnBackgroundThread(() -> {\n                ExtendedFile file = properties.path.getFile();\n                if (file == null) {\n                    return;\n                }\n                if (recursive) {\n                    setUidRecursive(file, uid);\n                }\n                try {\n                    UidGidPair pair = file.getUidGid();\n                    file.setUidGid(uid, pair.gid);\n                    FileProperties newProperties = new FileProperties(properties);\n                    newProperties.uidGidPair = newProperties.path.getUidGid();\n                    mFilePropertiesLiveData.postValue(newProperties);\n                } catch (ErrnoException e) {\n                    e.printStackTrace();\n                }\n            });\n        }\n\n        public void setGid(@NonNull FileProperties properties, int gid, boolean recursive) {\n            ThreadUtils.postOnBackgroundThread(() -> {\n                ExtendedFile file = properties.path.getFile();\n                if (file == null) {\n                    return;\n                }\n                if (recursive) {\n                    setGidRecursive(file, gid);\n                }\n                try {\n                    UidGidPair pair = file.getUidGid();\n                    file.setUidGid(pair.uid, gid);\n                    FileProperties newProperties = new FileProperties(properties);\n                    newProperties.uidGidPair = newProperties.path.getUidGid();\n                    mFilePropertiesLiveData.postValue(newProperties);\n                } catch (ErrnoException e) {\n                    e.printStackTrace();\n                }\n            });\n        }\n\n        public void restorecon(@NonNull FileProperties properties, boolean recursive) {\n            ThreadUtils.postOnBackgroundThread(() -> {\n                ExtendedFile file = properties.path.getFile();\n                if (file == null) {\n                    return;\n                }\n                if (recursive) {\n                    restoreconRecursive(file);\n                }\n                if (file.restoreSelinuxContext()) {\n                    FileProperties newProperties = new FileProperties(properties);\n                    newProperties.context = newProperties.path.getSelinuxContext();\n                    mFilePropertiesLiveData.postValue(newProperties);\n                }\n            });\n        }\n\n        public void setSeContext(@NonNull FileProperties properties, @NonNull String newContext, boolean recursive) {\n            ThreadUtils.postOnBackgroundThread(() -> {\n                ExtendedFile file = properties.path.getFile();\n                if (file == null) {\n                    return;\n                }\n                if (recursive) {\n                    setSeContextRecursive(file, newContext);\n                }\n                if (file.setSelinuxContext(newContext)) {\n                    FileProperties newProperties = new FileProperties(properties);\n                    newProperties.context = newProperties.path.getSelinuxContext();\n                    mFilePropertiesLiveData.postValue(newProperties);\n                }\n            });\n        }\n\n        public void setModificationTime(@NonNull FileProperties properties, long time) {\n            ThreadUtils.postOnBackgroundThread(() -> {\n                if (properties.path.setLastModified(time)) {\n                    FileProperties newProperties = new FileProperties(properties);\n                    newProperties.lastModified = newProperties.path.lastModified();\n                    mFilePropertiesLiveData.postValue(newProperties);\n                }\n            });\n        }\n\n        public void setLastAccessTime(@NonNull FileProperties properties, long time) {\n            ThreadUtils.postOnBackgroundThread(() -> {\n                if (properties.path.setLastAccess(time)) {\n                    FileProperties newProperties = new FileProperties(properties);\n                    newProperties.lastAccess = newProperties.path.lastAccess();\n                    mFilePropertiesLiveData.postValue(newProperties);\n                }\n            });\n        }\n\n        public void loadFileProperties(@NonNull Path path) {\n            ThreadUtils.postOnBackgroundThread(() -> {\n                FileProperties properties = new FileProperties();\n                Path[] children = path.listFiles();\n                int count = children.length;\n                int folderCount = 0;\n                for (Path child : children) {\n                    if (child.isDirectory()) {\n                        ++folderCount;\n                    }\n                }\n                properties.path = path;\n                properties.isPhysicalFs = path.getFile() != null;\n                properties.name = path.getName();\n                properties.readablePath = FmUtils.getDisplayablePath(path);\n                properties.folderCount = folderCount;\n                properties.fileCount = count - folderCount;\n                properties.isDirectory = path.isDirectory();\n                properties.isSymlink = path.isSymbolicLink();\n                properties.canRead = path.canRead();\n                properties.canWrite = path.canWrite();\n                properties.lastAccess = path.lastAccess();\n                properties.lastModified = path.lastModified();\n                properties.creationTime = path.creationTime();\n                properties.mode = path.getMode();\n                properties.uidGidPair = path.getUidGid();\n                properties.context = path.getSelinuxContext();\n                if (properties.isSymlink) {\n                    try {\n                        properties.targetPath = path.getRealFilePath();\n                    } catch (IOException ignore) {\n                    }\n                }\n                mFilePropertiesLiveData.postValue(properties);\n            });\n        }\n\n        public void loadFileSize(@NonNull FileProperties properties) {\n            sizeResult = ThreadUtils.postOnBackgroundThread(() -> {\n                FileProperties newProperties = new FileProperties(properties);\n                newProperties.size = Paths.size(newProperties.path);\n                mFilePropertiesLiveData.postValue(newProperties);\n            });\n        }\n\n        public void loadFmItem(@NonNull Path path) {\n            ThreadUtils.postOnBackgroundThread(() -> {\n                FmItem fmItem = new FmItem(path);\n                fmItem.setContentInfo(path.getPathContentInfo());\n                mFmItemLiveData.postValue(fmItem);\n            });\n        }\n\n        public void loadOwnerInfo(int uid) {\n            ThreadUtils.postOnBackgroundThread(() -> {\n                String ownerName = Owners.getOwnerName(uid);\n                mOwnerLiveData.postValue(ownerName);\n            });\n        }\n\n        public void loadGroupInfo(int gid) {\n            ThreadUtils.postOnBackgroundThread(() -> {\n                String groupName = Groups.getGroupName(gid);\n                mGroupLiveData.postValue(groupName);\n            });\n        }\n\n        public LiveData<FileProperties> getFilePropertiesLiveData() {\n            return mFilePropertiesLiveData;\n        }\n\n        public LiveData<FmItem> getFmItemLiveData() {\n            return mFmItemLiveData;\n        }\n\n        public LiveData<List<AndroidId>> getOwnerListLiveData() {\n            return mOwnerListLiveData;\n        }\n\n        public LiveData<List<AndroidId>> getGroupListLiveData() {\n            return mGroupListLiveData;\n        }\n\n        public LiveData<String> getOwnerLiveData() {\n            return mOwnerLiveData;\n        }\n\n        public LiveData<String> getGroupLiveData() {\n            return mGroupLiveData;\n        }\n\n        private boolean setModeRecursive(@NonNull ExtendedFile dir, int mode) {\n            if (dir.isSymlink()) {\n                // Avoid following symbolic links\n                return true;\n            }\n            ExtendedFile[] files = dir.listFiles();\n            boolean success = true;\n            if (files != null) {\n                for (ExtendedFile file : files) {\n                    if (file.isDirectory()) {\n                        success &= setModeRecursive(file, mode);\n                    }\n                    try {\n                        file.setMode(mode);\n                    } catch (ErrnoException e) {\n                        Log.w(TAG, \"Failed to set mode \" + mode + \" on \" + file);\n                        success = false;\n                    }\n                }\n            }\n            return success;\n        }\n\n        private boolean setUidRecursive(@NonNull ExtendedFile dir, int uid) {\n            if (dir.isSymlink()) {\n                // Avoid following symbolic links\n                return true;\n            }\n            ExtendedFile[] files = dir.listFiles();\n            boolean success = true;\n            if (files != null) {\n                for (ExtendedFile file : files) {\n                    if (file.isDirectory()) {\n                        success &= setUidRecursive(file, uid);\n                    }\n                    try {\n                        UidGidPair pair = file.getUidGid();\n                        file.setUidGid(uid, pair.gid);\n                    } catch (ErrnoException e) {\n                        Log.w(TAG, \"Failed to set UID \" + uid + \" on \" + file);\n                        success = false;\n                    }\n                }\n            }\n            return success;\n        }\n\n\n        private boolean setGidRecursive(@NonNull ExtendedFile dir, int gid) {\n            if (dir.isSymlink()) {\n                // Avoid following symbolic links\n                return true;\n            }\n            ExtendedFile[] files = dir.listFiles();\n            boolean success = true;\n            if (files != null) {\n                for (ExtendedFile file : files) {\n                    if (file.isDirectory()) {\n                        success &= setGidRecursive(file, gid);\n                    }\n                    try {\n                        UidGidPair pair = file.getUidGid();\n                        file.setUidGid(pair.uid, gid);\n                    } catch (ErrnoException e) {\n                        Log.w(TAG, \"Failed to set GID \" + gid + \" on \" + file);\n                        success = false;\n                    }\n                }\n            }\n            return success;\n        }\n\n        private boolean restoreconRecursive(@NonNull ExtendedFile dir) {\n            if (dir.isSymlink()) {\n                // Avoid following symbolic links\n                return true;\n            }\n            ExtendedFile[] files = dir.listFiles();\n            boolean success = true;\n            if (files != null) {\n                for (ExtendedFile file : files) {\n                    if (file.isDirectory()) {\n                        success &= restoreconRecursive(file);\n                    }\n                    if (!file.restoreSelinuxContext()) {\n                        Log.w(TAG, \"Failed to restorecon on \" + file);\n                        success = false;\n                    }\n                }\n            }\n            return success;\n        }\n\n        private boolean setSeContextRecursive(@NonNull ExtendedFile dir, @NonNull String newContext) {\n            if (dir.isSymlink()) {\n                // Avoid following symbolic links\n                return true;\n            }\n            ExtendedFile[] files = dir.listFiles();\n            boolean success = true;\n            if (files != null) {\n                for (ExtendedFile file : files) {\n                    if (file.isDirectory()) {\n                        success &= setSeContextRecursive(file, newContext);\n                    }\n                    if (!file.setSelinuxContext(newContext)) {\n                        Log.w(TAG, \"Failed to set SELinux context on \" + file);\n                        success = false;\n                    }\n                }\n            }\n            return success;\n        }\n    }\n\n    public static class AndroidId implements LocalizedString {\n        public int id;\n        public String name;\n        public CharSequence description;\n\n        @NonNull\n        @Override\n        public CharSequence toLocalizedString(@NonNull Context context) {\n            return new SpannableStringBuilder(name).append(\" (\").append(String.valueOf(id)).append(\")\\n\")\n                    .append(UIUtils.getSmallerText(UIUtils.getSecondaryText(context, description)));\n        }\n\n        @Override\n        public boolean equals(Object o) {\n            if (this == o) return true;\n            if (!(o instanceof AndroidId)) return false;\n            AndroidId androidId = (AndroidId) o;\n            return id == androidId.id;\n        }\n\n        @Override\n        public int hashCode() {\n            return Objects.hash(id);\n        }\n    }\n\n    public static class FileProperties {\n        public Path path;\n        public boolean isPhysicalFs;\n        public String name;\n        public String readablePath;\n        public int folderCount;\n        public int fileCount;\n        public boolean isDirectory;\n        public boolean isSymlink;\n        public boolean canRead;\n        public boolean canWrite;\n        public long size = -1;\n        public long lastAccess;\n        public long lastModified;\n        public long creationTime;\n        public int mode;\n        @Nullable\n        public UidGidPair uidGidPair;\n        @Nullable\n        public String context;\n        @Nullable\n        public String targetPath;\n\n        public FileProperties() {\n        }\n\n        public FileProperties(@NonNull FileProperties fileProperties) {\n            path = fileProperties.path;\n            isPhysicalFs = fileProperties.isPhysicalFs;\n            name = fileProperties.name;\n            readablePath = fileProperties.readablePath;\n            folderCount = fileProperties.folderCount;\n            fileCount = fileProperties.fileCount;\n            isDirectory = fileProperties.isDirectory;\n            isSymlink = fileProperties.isSymlink;\n            canRead = fileProperties.canRead;\n            canWrite = fileProperties.canWrite;\n            size = fileProperties.size;\n            lastAccess = fileProperties.lastAccess;\n            lastModified = fileProperties.lastModified;\n            creationTime = fileProperties.creationTime;\n            mode = fileProperties.mode;\n            uidGidPair = fileProperties.uidGidPair;\n            context = fileProperties.context;\n            targetPath = fileProperties.targetPath;\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/fm/dialogs/NewFileDialogFragment.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.fm.dialogs;\n\nimport android.app.Dialog;\nimport android.os.Bundle;\nimport android.text.Editable;\nimport android.text.TextUtils;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.ArrayAdapter;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.fragment.app.DialogFragment;\n\nimport com.google.android.material.dialog.MaterialAlertDialogBuilder;\nimport com.google.android.material.textfield.TextInputEditText;\n\nimport java.lang.ref.WeakReference;\n\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.adapters.SelectedArrayAdapter;\nimport io.github.muntashirakon.io.Paths;\nimport io.github.muntashirakon.lifecycle.SoftInputLifeCycleObserver;\nimport io.github.muntashirakon.widget.MaterialSpinner;\n\npublic class NewFileDialogFragment extends DialogFragment {\n    public static final String TAG = NewFileDialogFragment.class.getSimpleName();\n\n    public interface OnCreateNewFileInterface {\n        void onCreate(@NonNull String prefix, @Nullable String extension, @NonNull String template);\n    }\n\n    @NonNull\n    public static NewFileDialogFragment getInstance(@Nullable OnCreateNewFileInterface createNewFileInterface) {\n        NewFileDialogFragment fragment = new NewFileDialogFragment();\n        fragment.setOnCreateNewFileInterface(createNewFileInterface);\n        return fragment;\n    }\n\n    private static final int TYPE_TEXT = 0;\n    private static final int TYPE_PDF = 1;\n    private static final int TYPE_DOCS = 2;\n    private static final int TYPE_SHEET = 3;\n    private static final int TYPE_PRESENTATION = 4;\n    private static final int TYPE_DB = 5;\n\n    private static final String[] TYPE_LABELS = new String[]{\n            \"Text\",                         // TYPE_TEXT\n            \"PDF\",                          // TYPE_PDF\n            \"Document (.docx, .odt)\",       // TYPE_DOCS\n            \"Sheet (.xlsx, .ods)\",          // TYPE_SHEET\n            \"Presentation (.ppt, .odp)\",    // TYPE_PRESENTATION\n            \"Database\",                     // TYPE_DB\n    };\n\n    private static final String[] TYPE_DEFAULT_EXTENSIONS = new String[]{\n            \"txt\",      // TYPE_TEXT\n            \"pdf\",      // TYPE_PDF\n            \"docx\",     // TYPE_DOCS\n            \"xlsx\",     // TYPE_SHEET\n            \"pptx\",    // TYPE_PRESENTATION\n            \"db\",      // TYPE_DB\n    };\n\n    @Nullable\n    private OnCreateNewFileInterface mOnCreateNewFileInterface;\n    private View mDialogView;\n    private TextInputEditText mEditText;\n    private int mType;\n\n    @NonNull\n    @Override\n    public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {\n        mDialogView = View.inflate(requireActivity(), R.layout.dialog_new_file, null);\n        mEditText = mDialogView.findViewById(R.id.name);\n        String name = \"New file.txt\";\n        mEditText.setText(name);\n        handleFilename(name, null);\n        MaterialSpinner spinner = mDialogView.findViewById(R.id.type_selector_spinner);\n        ArrayAdapter<CharSequence> spinnerAdapter = new SelectedArrayAdapter<>(requireContext(),\n                io.github.muntashirakon.ui.R.layout.auto_complete_dropdown_item, TYPE_LABELS);\n        spinner.setAdapter(spinnerAdapter);\n        spinner.setSelection(TYPE_TEXT);\n        spinner.setOnItemClickListener((parent, view, position, id) -> {\n            if (mType != position) {\n                mType = position;\n                handleFilename(mEditText.getText(), TYPE_DEFAULT_EXTENSIONS[mType]);\n            }\n        });\n        return new MaterialAlertDialogBuilder(requireActivity())\n                .setTitle(R.string.create_new_file)\n                .setView(mDialogView)\n                .setPositiveButton(R.string.ok, (dialog, which) -> {\n                    Editable editable = mEditText.getText();\n                    if (!TextUtils.isEmpty(editable) && mOnCreateNewFileInterface != null) {\n                        String newName = editable.toString();\n                        String prefix = Paths.trimPathExtension(newName);\n                        String extension = Paths.getPathExtension(newName, false);\n                        String template = getFileTemplateFromTypeAndExtension(mType, extension);\n                        mOnCreateNewFileInterface.onCreate(prefix, extension, template);\n                    }\n                })\n                .setNegativeButton(R.string.cancel, null)\n                .create();\n    }\n\n    @Nullable\n    @Override\n    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {\n        return mDialogView;\n    }\n\n    @Override\n    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {\n        getLifecycle().addObserver(new SoftInputLifeCycleObserver(new WeakReference<>(mEditText)));\n    }\n\n    public void setOnCreateNewFileInterface(@Nullable OnCreateNewFileInterface createNewFileInterface) {\n        mOnCreateNewFileInterface = createNewFileInterface;\n    }\n\n    private void handleFilename(@Nullable CharSequence charSequence, @Nullable String newExtension) {\n        if (charSequence == null) {\n            return;\n        }\n        String name = charSequence.toString();\n        int lastIndex = name.lastIndexOf('.');\n        if (newExtension != null && lastIndex != -1) {\n            // Change extension before setting selection\n            name = name.substring(0, lastIndex) + \".\" + newExtension;\n            mEditText.setText(name);\n            lastIndex = name.lastIndexOf('.');\n        }\n        if (lastIndex != -1 || lastIndex == name.length() - 1) {\n            mEditText.setSelection(0, lastIndex);\n        } else {\n            mEditText.selectAll();\n        }\n    }\n\n    @NonNull\n    private static String getFileTemplateFromTypeAndExtension(int type, @Nullable String extension) {\n        String prefix = \"blank\";\n        switch (type) {\n            default:\n            case TYPE_TEXT:\n                return prefix + \".txt\";\n            case TYPE_PDF:\n                return prefix + \".pdf\";\n            case TYPE_DOCS:\n                return prefix + (\"odt\".equals(extension) ? \".odt\" : \".docx\");\n            case TYPE_SHEET:\n                return prefix + (\"ods\".equals(extension) ? \".ods\" : \".xlsx\");\n            case TYPE_PRESENTATION:\n                return prefix + (\"odp\".equals(extension) ? \".odp\" : \".pptx\");\n            case TYPE_DB:\n                return prefix + \".db\";\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/fm/dialogs/NewFolderDialogFragment.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.fm.dialogs;\n\nimport android.annotation.SuppressLint;\nimport android.app.Dialog;\nimport android.os.Bundle;\nimport android.text.Editable;\nimport android.text.TextUtils;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.fragment.app.DialogFragment;\n\nimport com.google.android.material.dialog.MaterialAlertDialogBuilder;\nimport com.google.android.material.textfield.TextInputEditText;\n\nimport java.lang.ref.WeakReference;\n\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.lifecycle.SoftInputLifeCycleObserver;\n\npublic class NewFolderDialogFragment extends DialogFragment {\n    public static final String TAG = NewFolderDialogFragment.class.getSimpleName();\n\n    public interface OnCreateNewFolderInterface {\n        void onCreate(@NonNull String name);\n    }\n\n    @NonNull\n    public static NewFolderDialogFragment getInstance(@Nullable OnCreateNewFolderInterface createNewFolderInterface) {\n        NewFolderDialogFragment fragment = new NewFolderDialogFragment();\n        fragment.setOnCreateNewFolderInterface(createNewFolderInterface);\n        return fragment;\n    }\n\n    @Nullable\n    private OnCreateNewFolderInterface mOnCreateNewFolderInterface;\n    private View mDialogView;\n    private TextInputEditText mEditText;\n\n    @SuppressLint(\"SetTextI18n\")\n    @NonNull\n    @Override\n    public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {\n        mDialogView = View.inflate(requireActivity(), R.layout.dialog_rename, null);\n        mEditText = mDialogView.findViewById(R.id.rename);\n        mEditText.setText(\"New folder\");\n        mEditText.selectAll();\n        return new MaterialAlertDialogBuilder(requireActivity())\n                .setTitle(R.string.create_new_folder)\n                .setView(mDialogView)\n                .setPositiveButton(R.string.ok, (dialog, which) -> {\n                    Editable editable = mEditText.getText();\n                    if (!TextUtils.isEmpty(editable) && mOnCreateNewFolderInterface != null) {\n                        mOnCreateNewFolderInterface.onCreate(editable.toString());\n                    }\n                })\n                .setNegativeButton(R.string.cancel, null)\n                .create();\n    }\n\n    @Nullable\n    @Override\n    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {\n        return mDialogView;\n    }\n\n    @Override\n    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {\n        getLifecycle().addObserver(new SoftInputLifeCycleObserver(new WeakReference<>(mEditText)));\n    }\n\n    public void setOnCreateNewFolderInterface(@Nullable OnCreateNewFolderInterface createNewFolderInterface) {\n        mOnCreateNewFolderInterface = createNewFolderInterface;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/fm/dialogs/NewSymbolicLinkDialogFragment.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.fm.dialogs;\n\nimport android.annotation.SuppressLint;\nimport android.app.Dialog;\nimport android.os.Bundle;\nimport android.text.Editable;\nimport android.text.TextUtils;\nimport android.text.TextWatcher;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.fragment.app.DialogFragment;\n\nimport com.google.android.material.dialog.MaterialAlertDialogBuilder;\nimport com.google.android.material.textfield.TextInputEditText;\nimport com.google.android.material.textfield.TextInputLayout;\n\nimport java.lang.ref.WeakReference;\nimport java.util.Objects;\n\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.io.Path;\nimport io.github.muntashirakon.io.Paths;\nimport io.github.muntashirakon.lifecycle.SoftInputLifeCycleObserver;\n\npublic class NewSymbolicLinkDialogFragment extends DialogFragment {\n    public static final String TAG = NewSymbolicLinkDialogFragment.class.getSimpleName();\n\n    public interface OnCreateNewLinkInterface {\n        void onCreate(@NonNull String prefix, @Nullable String extension, @NonNull String targetPath);\n    }\n\n    @NonNull\n    public static NewSymbolicLinkDialogFragment getInstance(@Nullable OnCreateNewLinkInterface createNewLinkInterface) {\n        NewSymbolicLinkDialogFragment fragment = new NewSymbolicLinkDialogFragment();\n        fragment.setOnCreateNewLinkInterface(createNewLinkInterface);\n        return fragment;\n    }\n\n    @Nullable\n    private OnCreateNewLinkInterface mOnCreateNewLinkInterface;\n    private View mDialogView;\n    private TextInputEditText mNameField;\n    private TextInputLayout mTargetPathLayout;\n    private TextInputEditText mTargetPathField;\n    private boolean mValidPath = false;\n\n    private final TextWatcher mPathValidator = new TextWatcher() {\n        @Override\n        public void beforeTextChanged(CharSequence s, int start, int count, int after) {\n        }\n\n        @Override\n        public void onTextChanged(CharSequence s, int start, int before, int count) {\n        }\n\n        @Override\n        public void afterTextChanged(Editable s) {\n            if (TextUtils.isEmpty(s)) {\n                return;\n            }\n            Path targetPath = Paths.get(s.toString());\n            mValidPath = targetPath.getFile() != null && targetPath.exists();\n            if (!mValidPath) {\n                mTargetPathLayout.setError(getText(R.string.invalid_target_path));\n            } else {\n                mTargetPathLayout.setError(null);\n            }\n        }\n    };\n\n    @SuppressLint(\"SetTextI18n\")\n    @NonNull\n    @Override\n    public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {\n        mDialogView = View.inflate(requireActivity(), R.layout.dialog_new_symlink, null);\n        mNameField = mDialogView.findViewById(R.id.name);\n        mNameField.setText(\"New link\");\n        mNameField.selectAll();\n        mTargetPathField = mDialogView.findViewById(R.id.target_file);\n        mTargetPathLayout = mDialogView.findViewById(R.id.target_file_layout);\n        mTargetPathField.addTextChangedListener(mPathValidator);\n        return new MaterialAlertDialogBuilder(requireActivity())\n                .setTitle(R.string.create_new_symbolic_link)\n                .setView(mDialogView)\n                .setPositiveButton(R.string.ok, (dialog, which) -> {\n                    Editable name = mNameField.getText();\n                    Editable targetPath = mTargetPathField.getText();\n                    if (!TextUtils.isEmpty(name) && mValidPath && mOnCreateNewLinkInterface != null) {\n                        String newName = name.toString();\n                        String prefix = Paths.trimPathExtension(newName);\n                        String extension = Paths.getPathExtension(newName, false);\n                        mOnCreateNewLinkInterface.onCreate(prefix, extension, Objects.requireNonNull(targetPath).toString());\n                    }\n                })\n                .setNegativeButton(R.string.cancel, null)\n                .create();\n    }\n\n    @Nullable\n    @Override\n    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {\n        return mDialogView;\n    }\n\n    @Override\n    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {\n        getLifecycle().addObserver(new SoftInputLifeCycleObserver(new WeakReference<>(mNameField)));\n    }\n\n    public void setOnCreateNewLinkInterface(@Nullable OnCreateNewLinkInterface createNewLinkInterface) {\n        mOnCreateNewLinkInterface = createNewLinkInterface;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/fm/dialogs/OpenWithDialogFragment.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.fm.dialogs;\n\nimport android.app.Activity;\nimport android.app.Application;\nimport android.app.Dialog;\nimport android.content.Intent;\nimport android.content.pm.PackageManager;\nimport android.content.pm.ResolveInfo;\nimport android.graphics.drawable.Drawable;\nimport android.net.Uri;\nimport android.os.Bundle;\nimport android.os.UserHandleHidden;\nimport android.text.TextUtils;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.Button;\nimport android.widget.CheckBox;\nimport android.widget.ImageView;\nimport android.widget.TextView;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.appcompat.app.AlertDialog;\nimport androidx.core.os.BundleCompat;\nimport androidx.fragment.app.DialogFragment;\nimport androidx.lifecycle.AndroidViewModel;\nimport androidx.lifecycle.LiveData;\nimport androidx.lifecycle.MutableLiveData;\nimport androidx.lifecycle.ViewModelProvider;\nimport androidx.recyclerview.widget.LinearLayoutManager;\nimport androidx.recyclerview.widget.RecyclerView;\n\nimport com.google.android.material.dialog.MaterialAlertDialogBuilder;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Objects;\n\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.compat.ActivityManagerCompat;\nimport io.github.muntashirakon.AppManager.fm.FmProvider;\nimport io.github.muntashirakon.AppManager.intercept.ActivityInterceptor;\nimport io.github.muntashirakon.AppManager.self.imagecache.ImageLoader;\nimport io.github.muntashirakon.AppManager.settings.FeatureController;\nimport io.github.muntashirakon.util.AdapterUtils;\nimport io.github.muntashirakon.AppManager.utils.ContextUtils;\nimport io.github.muntashirakon.AppManager.utils.ThreadUtils;\nimport io.github.muntashirakon.AppManager.utils.UIUtils;\nimport io.github.muntashirakon.dialog.DialogTitleBuilder;\nimport io.github.muntashirakon.dialog.SearchableItemsDialogBuilder;\nimport io.github.muntashirakon.io.Path;\nimport io.github.muntashirakon.io.PathContentInfo;\nimport io.github.muntashirakon.io.Paths;\nimport io.github.muntashirakon.lifecycle.SingleLiveEvent;\nimport io.github.muntashirakon.widget.SearchView;\n\npublic class OpenWithDialogFragment extends DialogFragment {\n    public static final String TAG = OpenWithDialogFragment.class.getSimpleName();\n\n    private static final String ARG_PATH = \"path\";\n    private static final String ARG_TYPE = \"type\";\n    private static final String ARG_CLOSE_ACTIVITY = \"close\";\n\n    @NonNull\n    public static OpenWithDialogFragment getInstance(@NonNull Path path) {\n        return getInstance(path, null);\n    }\n\n    @NonNull\n    public static OpenWithDialogFragment getInstance(@NonNull Path path, @Nullable String type) {\n        return getInstance(path.getUri(), type, false);\n    }\n\n    @NonNull\n    public static OpenWithDialogFragment getInstance(@NonNull Uri uri, @Nullable String type, boolean closeActivity) {\n        OpenWithDialogFragment fragment = new OpenWithDialogFragment();\n        Bundle args = new Bundle();\n        args.putParcelable(ARG_PATH, uri);\n        args.putString(ARG_TYPE, type);\n        args.putBoolean(ARG_CLOSE_ACTIVITY, closeActivity);\n        fragment.setArguments(args);\n        return fragment;\n    }\n\n    private static class ResolvedActivityInfo {\n        @NonNull\n        public final ResolveInfo resolveInfo;\n        @NonNull\n        public final String packageName;\n        @NonNull\n        public final String name;\n        @NonNull\n        public final String shortName;\n        @NonNull\n        public final CharSequence label;\n        @NonNull\n        public final CharSequence appLabel;\n\n        private ResolvedActivityInfo(@NonNull ResolveInfo resolveInfo, @NonNull CharSequence label, @NonNull CharSequence appLabel) {\n            this.resolveInfo = resolveInfo;\n            this.packageName = resolveInfo.activityInfo.packageName;\n            this.name = resolveInfo.activityInfo.name;\n            this.shortName = getShortActivityName(this.name);\n            this.label = label;\n            this.appLabel = appLabel;\n        }\n\n        public boolean matches(@Nullable String constraint) {\n            if (constraint == null) {\n                return true;\n            }\n            // Match the following:\n            // 1. Label\n            // 2. Short name\n            // 3. App label\n            return label.toString().toLowerCase(Locale.getDefault()).contains(constraint)\n                    || shortName.contains(constraint)\n                    || appLabel.toString().toLowerCase(Locale.getDefault()).contains(constraint);\n        }\n\n        @NonNull\n        private String getShortActivityName(@NonNull String longName) {\n            int idxOfDot = longName.lastIndexOf('.');\n            if (idxOfDot == -1) {\n                return longName;\n            }\n            return longName.substring(idxOfDot + 1);\n        }\n    }\n\n    private Path mPath;\n    private String mCustomType;\n    private boolean mCloseActivity;\n    private View mDialogView;\n    private SearchView mSearchView;\n    private OpenWithViewModel mViewModel;\n    private MatchingActivitiesRecyclerViewAdapter mAdapter;\n\n    @NonNull\n    @Override\n    public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {\n        mViewModel = new ViewModelProvider(this).get(OpenWithViewModel.class);\n        mPath = Paths.get(Objects.requireNonNull(BundleCompat.getParcelable(requireArguments(), ARG_PATH, Uri.class)));\n        mCustomType = requireArguments().getString(ARG_TYPE, null);\n        mCloseActivity = requireArguments().getBoolean(ARG_CLOSE_ACTIVITY, false);\n        mAdapter = new MatchingActivitiesRecyclerViewAdapter(mViewModel, requireActivity());\n        mAdapter.setIntent(getIntent(mPath, mCustomType));\n        mDialogView = View.inflate(requireActivity(), R.layout.dialog_open_with, null);\n        mSearchView = mDialogView.findViewById(io.github.muntashirakon.ui.R.id.action_search);\n        mSearchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {\n            @Override\n            public boolean onQueryTextSubmit(String query) {\n                return false;\n            }\n\n            @Override\n            public boolean onQueryTextChange(String newText) {\n                mAdapter.setFilteredItems(newText);\n                return true;\n            }\n        });\n        RecyclerView matchingActivitiesView = mDialogView.findViewById(R.id.intent_matching_activities);\n        matchingActivitiesView.setLayoutManager(new LinearLayoutManager(requireContext()));\n        matchingActivitiesView.setAdapter(mAdapter);\n        // TODO: 19/11/22 Add support for always open and only for this file\n        CheckBox alwaysOpen = mDialogView.findViewById(R.id.always_open);\n        CheckBox openForThisFileOnly = mDialogView.findViewById(R.id.only_for_this_file);\n        alwaysOpen.setVisibility(View.GONE);\n        openForThisFileOnly.setVisibility(View.GONE);\n        DialogTitleBuilder titleBuilder = new DialogTitleBuilder(requireActivity())\n                .setTitle(R.string.file_open_with)\n                .setSubtitle(mPath.getName())\n                .setEndIcon(R.drawable.ic_open_in_new, v1 -> {\n                    if (mAdapter != null && mAdapter.getIntent().resolveActivityInfo(requireActivity()\n                            .getPackageManager(), 0) != null) {\n                        startActivity(mAdapter.getIntent());\n                    }\n                    dismiss();\n                })\n                .setEndIconContentDescription(R.string.file_open_with_os_default_dialog);\n        AlertDialog alertDialog = new MaterialAlertDialogBuilder(requireActivity())\n                .setCustomTitle(titleBuilder.build())\n                .setView(mDialogView)\n                .setPositiveButton(R.string.file_open_as, null)\n                .setNeutralButton(R.string.file_open_with_custom_activity, null)\n                .create();\n        alertDialog.setOnShowListener(dialog -> {\n            Button fileOpenAsButton = alertDialog.getButton(AlertDialog.BUTTON_POSITIVE);\n            Button customButton = alertDialog.getButton(AlertDialog.BUTTON_NEUTRAL);\n            fileOpenAsButton.setOnClickListener(v -> {\n                String[] customTypes = requireContext().getResources().getStringArray(R.array.file_open_as_option_types);\n                new SearchableItemsDialogBuilder<>(requireActivity(), R.array.file_open_as_options)\n                        .setTitle(R.string.file_open_as)\n                        .hideSearchBar(true)\n                        .setOnItemClickListener((dialog1, which, item) -> {\n                            mCustomType = customTypes[which];\n                            if (mAdapter != null) {\n                                mAdapter.setIntent(getIntent(mPath, mCustomType));\n                                if (mViewModel != null) {\n                                    // Reload activities\n                                    mViewModel.loadMatchingActivities(mAdapter.getIntent());\n                                }\n                            }\n                            dialog1.dismiss();\n                        })\n                        .setNegativeButton(R.string.close, null)\n                        .show();\n            });\n            // TODO: 20/11/22 Add option to set custom activity\n            customButton.setVisibility(View.GONE);\n        });\n        return alertDialog;\n    }\n\n    @Nullable\n    @Override\n    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {\n        return mDialogView;\n    }\n\n    @Override\n    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {\n        if (mViewModel != null) {\n            mViewModel.getMatchingActivitiesLiveData().observe(getViewLifecycleOwner(), matchingActivities -> {\n                mAdapter.setDefaultList(matchingActivities);\n                // Don't display search bar if items are less than 6\n                mSearchView.setVisibility(matchingActivities.size() < 6 ? View.GONE : View.VISIBLE);\n            });\n            mViewModel.getPathContentInfoLiveData().observe(getViewLifecycleOwner(), pathContentInfo -> {\n                if (mAdapter != null) {\n                    mAdapter.setIntent(getIntent(mPath, pathContentInfo.getMimeType()));\n                    if (mViewModel != null) {\n                        // Reload activities\n                        mViewModel.loadMatchingActivities(mAdapter.getIntent());\n                    }\n                }\n            });\n            mViewModel.getIntentLiveData().observe(getViewLifecycleOwner(), intent -> {\n                try {\n                    // Resolved activities may contain non-exported activity\n                    ActivityManagerCompat.startActivity(intent, UserHandleHidden.myUserId());\n                    dismiss();\n                } catch (SecurityException e) {\n                    UIUtils.displayLongToast(\"Failed: \" + e.getMessage());\n                }\n            });\n            if (mCustomType == null) {\n                mViewModel.loadFileContentInfo(mPath);\n            }\n            if (mAdapter != null) {\n                mViewModel.loadMatchingActivities(mAdapter.getIntent());\n            }\n        }\n    }\n\n    @Override\n    public void onDestroy() {\n        super.onDestroy();\n        if (mCloseActivity) {\n            requireActivity().finish();\n        }\n    }\n\n    @NonNull\n    private Intent getIntent(@NonNull Path path, @Nullable String customType) {\n        int flags = Intent.FLAG_ACTIVITY_NEW_TASK;\n        if (path.canRead()) {\n            flags |= Intent.FLAG_GRANT_READ_URI_PERMISSION;\n        }\n        if (path.canWrite()) {\n            flags |= Intent.FLAG_GRANT_WRITE_URI_PERMISSION;\n        }\n        Intent intent = new Intent(Intent.ACTION_VIEW);\n        intent.setDataAndType(FmProvider.getContentUri(path), customType != null ? customType : path.getType());\n        intent.setFlags(flags);\n        return intent;\n    }\n\n    private static class MatchingActivitiesRecyclerViewAdapter extends RecyclerView.Adapter<MatchingActivitiesRecyclerViewAdapter.ViewHolder> {\n        @NonNull\n        private final List<ResolvedActivityInfo> mMatchingActivities = new ArrayList<>();\n        @NonNull\n        private final ArrayList<Integer> mFilteredItems = new ArrayList<>();\n        private final Activity mActivity;\n        private final OpenWithViewModel mViewModel;\n        private final ImageLoader mImageLoader = ImageLoader.getInstance();\n\n        private Intent mIntent;\n        @Nullable\n        private String mConstraint;\n\n        public MatchingActivitiesRecyclerViewAdapter(OpenWithViewModel viewModel, Activity activity) {\n            mViewModel = viewModel;\n            mActivity = activity;\n        }\n\n        public Intent getIntent() {\n            return mIntent;\n        }\n\n        public void setIntent(Intent intent) {\n            mIntent = intent;\n        }\n\n        public void setDefaultList(@Nullable List<ResolvedActivityInfo> matchingActivities) {\n            mMatchingActivities.clear();\n            if (matchingActivities != null) {\n                mMatchingActivities.addAll(matchingActivities);\n            }\n            filterItems();\n        }\n\n        void setFilteredItems(@Nullable String constraint) {\n            mConstraint = TextUtils.isEmpty(constraint) ? null : constraint.toLowerCase(Locale.getDefault());\n            filterItems();\n        }\n\n        private void filterItems() {\n            synchronized (mFilteredItems) {\n                int lastCount = mFilteredItems.size();\n                mFilteredItems.clear();\n                for (int i = 0; i < mMatchingActivities.size(); ++i) {\n                    if (mConstraint == null || mMatchingActivities.get(i).matches(mConstraint)) {\n                        mFilteredItems.add(i);\n                    }\n                }\n                AdapterUtils.notifyDataSetChanged(this, lastCount, mFilteredItems.size());\n            }\n        }\n\n        @NonNull\n        @Override\n        public MatchingActivitiesRecyclerViewAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {\n            View view = LayoutInflater.from(parent.getContext()).inflate(io.github.muntashirakon.ui.R.layout.m3_preference, parent, false);\n            return new MatchingActivitiesRecyclerViewAdapter.ViewHolder(view);\n        }\n\n        @Override\n        public void onBindViewHolder(@NonNull MatchingActivitiesRecyclerViewAdapter.ViewHolder holder, int position) {\n            int index;\n            synchronized (mFilteredItems) {\n                index = mFilteredItems.get(position);\n            }\n            ResolvedActivityInfo resolvedInfo = mMatchingActivities.get(index);\n            holder.title.setText(resolvedInfo.label);\n            String activityName = resolvedInfo.name;\n            String summary = resolvedInfo.appLabel + \"\\n\" + resolvedInfo.shortName;\n            holder.summary.setText(summary);\n            String tag = resolvedInfo.packageName + \"_\" + resolvedInfo.label;\n            holder.icon.setTag(tag);\n            mImageLoader.displayImage(tag, holder.icon, new ResolveInfoImageFetcher(resolvedInfo.resolveInfo));\n            holder.itemView.setOnClickListener(v -> {\n                Intent intent = new Intent(mIntent);\n                intent.setClassName(resolvedInfo.packageName, activityName);\n                mViewModel.openIntent(intent);\n            });\n            holder.itemView.setOnLongClickListener(v -> {\n                if (!FeatureController.isInterceptorEnabled()) {\n                    return false;\n                }\n                Intent intent = new Intent(mIntent);\n                intent.putExtra(ActivityInterceptor.EXTRA_PACKAGE_NAME, resolvedInfo.packageName);\n                intent.putExtra(ActivityInterceptor.EXTRA_CLASS_NAME, activityName);\n                intent.setClassName(mActivity, ActivityInterceptor.class.getName());\n                mViewModel.openIntent(intent);\n                return true;\n            });\n        }\n\n        @Override\n        public int getItemCount() {\n            synchronized (mFilteredItems) {\n                return mFilteredItems.size();\n            }\n        }\n\n        static class ViewHolder extends RecyclerView.ViewHolder {\n            TextView title;\n            TextView summary;\n            ImageView icon;\n\n            public ViewHolder(@NonNull View itemView) {\n                super(itemView);\n                title = itemView.findViewById(android.R.id.title);\n                summary = itemView.findViewById(android.R.id.summary);\n                icon = itemView.findViewById(android.R.id.icon);\n                icon.setContentDescription(itemView.getContext().getString(R.string.icon));\n            }\n        }\n    }\n\n    public static class OpenWithViewModel extends AndroidViewModel {\n        private final MutableLiveData<List<ResolvedActivityInfo>> mMatchingActivitiesLiveData = new MutableLiveData<>();\n        private final MutableLiveData<PathContentInfo> mPathContentInfoLiveData = new MutableLiveData<>();\n        private final SingleLiveEvent<Intent> mIntentLiveData = new SingleLiveEvent<>();\n        private final PackageManager mPm;\n\n        public OpenWithViewModel(@NonNull Application application) {\n            super(application);\n            mPm = application.getPackageManager();\n        }\n\n        public void loadMatchingActivities(@NonNull Intent intent) {\n            ThreadUtils.postOnBackgroundThread(() -> {\n                List<ResolveInfo> resolveInfoList = mPm.queryIntentActivities(intent, 0);\n                List<ResolvedActivityInfo> resolvedActivityInfoList = new ArrayList<>(resolveInfoList.size());\n                for (ResolveInfo resolveInfo : resolveInfoList) {\n                    CharSequence label = resolveInfo.loadLabel(mPm);\n                    CharSequence appLabel = resolveInfo.activityInfo.applicationInfo.loadLabel(mPm);\n                    resolvedActivityInfoList.add(new ResolvedActivityInfo(resolveInfo, label, appLabel));\n                }\n                mMatchingActivitiesLiveData.postValue(resolvedActivityInfoList);\n            });\n        }\n\n        public void loadFileContentInfo(@NonNull Path path) {\n            ThreadUtils.postOnBackgroundThread(() -> mPathContentInfoLiveData.postValue(path.getPathContentInfo()));\n        }\n\n        public void openIntent(@NonNull Intent intent) {\n            mIntentLiveData.setValue(intent);\n        }\n\n        public LiveData<List<ResolvedActivityInfo>> getMatchingActivitiesLiveData() {\n            return mMatchingActivitiesLiveData;\n        }\n\n        public LiveData<PathContentInfo> getPathContentInfoLiveData() {\n            return mPathContentInfoLiveData;\n        }\n\n        public LiveData<Intent> getIntentLiveData() {\n            return mIntentLiveData;\n        }\n\n        @Override\n        protected void onCleared() {\n            super.onCleared();\n        }\n    }\n\n    private static class ResolveInfoImageFetcher implements ImageLoader.ImageFetcherInterface {\n        @Nullable\n        private final ResolveInfo mInfo;\n\n        public ResolveInfoImageFetcher(@Nullable ResolveInfo info) {\n            mInfo = info;\n        }\n\n        @Override\n        @NonNull\n        public ImageLoader.ImageFetcherResult fetchImage(@NonNull String tag) {\n            PackageManager pm = ContextUtils.getContext().getPackageManager();\n            Drawable drawable = mInfo != null ? mInfo.loadIcon(pm) : null;\n            return new ImageLoader.ImageFetcherResult(tag, drawable != null ? UIUtils.getBitmapFromDrawable(drawable) : null,\n                    false, true,\n                    new ImageLoader.DefaultImageDrawable(\"android_default_icon\", pm.getDefaultActivityIcon()));\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/fm/dialogs/RenameDialogFragment.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.fm.dialogs;\n\nimport android.app.Dialog;\nimport android.os.Bundle;\nimport android.text.Editable;\nimport android.text.TextUtils;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.fragment.app.DialogFragment;\n\nimport com.google.android.material.dialog.MaterialAlertDialogBuilder;\nimport com.google.android.material.textfield.TextInputEditText;\n\nimport java.lang.ref.WeakReference;\n\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.io.Paths;\nimport io.github.muntashirakon.lifecycle.SoftInputLifeCycleObserver;\n\npublic class RenameDialogFragment extends DialogFragment {\n    public static final String TAG = RenameDialogFragment.class.getSimpleName();\n\n    public interface OnRenameFilesInterface {\n        void onRename(@NonNull String prefix, @Nullable String extension);\n    }\n\n    private static final String ARG_NAME = \"name\";\n\n    @NonNull\n    public static RenameDialogFragment getInstance(@Nullable String name,\n                                                   @Nullable OnRenameFilesInterface renameFilesInterface) {\n        RenameDialogFragment fragment = new RenameDialogFragment();\n        Bundle args = new Bundle();\n        args.putString(ARG_NAME, name);\n        fragment.setArguments(args);\n        fragment.setOnRenameFilesInterface(renameFilesInterface);\n        return fragment;\n    }\n\n    @Nullable\n    private OnRenameFilesInterface mOnRenameFilesInterface;\n    private View mDialogView;\n    private TextInputEditText mEditText;\n\n    @NonNull\n    @Override\n    public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {\n        String name = getArguments() != null ? requireArguments().getString(ARG_NAME) : null;\n        mDialogView = View.inflate(requireActivity(), R.layout.dialog_rename, null);\n        mEditText = mDialogView.findViewById(R.id.rename);\n        mEditText.setText(name);\n        if (name != null) {\n            int lastIndex = name.lastIndexOf('.');\n            if (lastIndex != -1 || lastIndex == name.length() - 1) {\n                mEditText.setSelection(0, lastIndex);\n            } else {\n                mEditText.selectAll();\n            }\n        }\n        return new MaterialAlertDialogBuilder(requireActivity())\n                .setTitle(R.string.rename)\n                .setView(mDialogView)\n                .setPositiveButton(R.string.save, (dialog, which) -> {\n                    Editable editable = mEditText.getText();\n                    if (!TextUtils.isEmpty(editable) && mOnRenameFilesInterface != null) {\n                        String newName = editable.toString();\n                        String prefix = Paths.trimPathExtension(newName);\n                        String extension = Paths.getPathExtension(newName, false);\n                        mOnRenameFilesInterface.onRename(prefix, extension);\n                    }\n                })\n                .setNegativeButton(R.string.cancel, null)\n                .create();\n    }\n\n    @Nullable\n    @Override\n    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {\n        return mDialogView;\n    }\n\n    @Override\n    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {\n        getLifecycle().addObserver(new SoftInputLifeCycleObserver(new WeakReference<>(mEditText)));\n    }\n\n    public void setOnRenameFilesInterface(@Nullable OnRenameFilesInterface renameFilesInterface) {\n        mOnRenameFilesInterface = renameFilesInterface;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/fm/icons/EpubCoverGenerator.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.fm.icons;\n\nimport android.graphics.Bitmap;\nimport android.graphics.BitmapFactory;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport org.xmlpull.v1.XmlPullParser;\nimport org.xmlpull.v1.XmlPullParserException;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.nio.charset.StandardCharsets;\nimport java.util.zip.ZipEntry;\nimport java.util.zip.ZipFile;\n\nimport io.github.muntashirakon.compat.xml.Xml;\n\nfinal class EpubCoverGenerator {\n    @Nullable\n    public static Bitmap generateFromFile(@NonNull File file) {\n        try(ZipFile zipFile = new ZipFile(file)) {\n            String opfFile = getOpfFileLocation(zipFile, zipFile.getEntry(\"META-INF/container.xml\"));\n            if (opfFile == null) {\n                return null;\n            }\n            String coverId = getCoverId(zipFile, zipFile.getEntry(opfFile));\n            if (coverId == null) {\n                return null;\n            }\n            String coverImage = getCover(zipFile, zipFile.getEntry(opfFile), coverId);\n            if (coverImage == null) {\n                return null;\n            }\n            String parent = new File(opfFile).getParent();\n            String coverImageLocation;\n            if (parent != null) {\n                coverImageLocation = parent + File.separator + coverImage;\n            } else coverImageLocation = coverImage;\n            ZipEntry coverEntry = zipFile.getEntry(coverImageLocation);\n            if (coverEntry != null) {\n                return BitmapFactory.decodeStream(zipFile.getInputStream(coverEntry));\n            }\n        } catch (IOException e) {\n            e.printStackTrace();\n        }\n        return null;\n    }\n\n    @Nullable\n    private static String getOpfFileLocation(@NonNull ZipFile zipFile, @Nullable ZipEntry zipEntry) {\n        if (zipEntry == null) {\n            return null;\n        }\n        try {\n            XmlPullParser parser = Xml.newFastPullParser();\n            parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false);\n            parser.setInput(zipFile.getInputStream(zipEntry), StandardCharsets.UTF_8.name());\n            parser.nextTag();\n            parser.require(XmlPullParser.START_TAG, null, \"container\");\n            int event = parser.next();\n            while (event != XmlPullParser.END_DOCUMENT) {\n                if (event == XmlPullParser.START_TAG) {\n                    String tagName = parser.getName();\n                    if (\"rootfile\".equals(tagName)) {\n                        return parser.getAttributeValue(null, \"full-path\");\n                    }\n                }\n                event = parser.next();\n            }\n        } catch (IOException | XmlPullParserException ignore) {\n        }\n        return null;\n    }\n\n    @Nullable\n    private static String getCoverId(@NonNull ZipFile zipFile, @Nullable ZipEntry zipEntry) {\n        if (zipEntry == null) {\n            return null;\n        }\n        try {\n            XmlPullParser parser = Xml.newFastPullParser();\n            parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false);\n            parser.setInput(zipFile.getInputStream(zipEntry), StandardCharsets.UTF_8.name());\n            parser.nextTag();\n            parser.require(XmlPullParser.START_TAG, null, \"package\");\n            int event = parser.next();\n            while (event != XmlPullParser.END_DOCUMENT) {\n                if (event == XmlPullParser.START_TAG) {\n                    String tagName = parser.getName();\n                    if (\"meta\".equals(tagName) && \"cover\".equals(parser.getAttributeValue(null, \"name\"))) {\n                        return parser.getAttributeValue(null, \"content\");\n                    }\n                }\n                event = parser.next();\n            }\n        } catch (IOException | XmlPullParserException ignore) {\n        }\n        return null;\n    }\n\n    @Nullable\n    private static String getCover(@NonNull ZipFile zipFile, @Nullable ZipEntry zipEntry, @NonNull String coverId) {\n        if (zipEntry == null) {\n            return null;\n        }\n        try {\n            XmlPullParser parser = Xml.newFastPullParser();\n            parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false);\n            parser.setInput(zipFile.getInputStream(zipEntry), StandardCharsets.UTF_8.name());\n            parser.nextTag();\n            parser.require(XmlPullParser.START_TAG, null, \"package\");\n            int event = parser.next();\n            while (event != XmlPullParser.END_DOCUMENT) {\n                if (event == XmlPullParser.START_TAG) {\n                    String tagName = parser.getName();\n                    String id = parser.getAttributeValue(null, \"id\");\n                    if (\"item\".equals(tagName) && id == null) {\n                        event = parser.next();\n                        continue;\n                    }\n                    String properties = parser.getAttributeValue(null, \"properties\");\n                    if (coverId.equals(id)) {\n                        return parser.getAttributeValue(null, \"href\");\n                    } else if (\"cover-image\".equals(properties)) {\n                        return parser.getAttributeValue(null, \"href\");\n                    }\n                }\n                event = parser.next();\n            }\n        } catch (IOException | XmlPullParserException ignore) {\n        }\n        return null;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/fm/icons/FmIconFetcher.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.fm.icons;\n\nimport android.graphics.Bitmap;\nimport android.graphics.BitmapFactory;\nimport android.media.ThumbnailUtils;\nimport android.util.Size;\n\nimport androidx.annotation.NonNull;\n\nimport com.j256.simplemagic.ContentType;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.util.HashSet;\nimport java.util.Locale;\nimport java.util.Set;\n\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.compat.ThumbnailUtilsCompat;\nimport io.github.muntashirakon.AppManager.fm.ContentType2;\nimport io.github.muntashirakon.AppManager.fm.FmItem;\nimport io.github.muntashirakon.AppManager.fm.FmProvider;\nimport io.github.muntashirakon.AppManager.self.imagecache.ImageLoader;\nimport io.github.muntashirakon.AppManager.utils.ContextUtils;\nimport io.github.muntashirakon.io.PathContentInfo;\nimport io.github.muntashirakon.svg.SVG;\nimport io.github.muntashirakon.svg.SVGParser;\nimport io.github.muntashirakon.util.UiUtils;\n\npublic class FmIconFetcher implements ImageLoader.ImageFetcherInterface {\n    private static final Set<String> OPEN_DOCUMENT_FORMAT_MIME_TYPES = new HashSet<String>() {{\n        add(\"application/vnd.oasis.opendocument.text\");\n        add(\"application/vnd.oasis.opendocument.spreadsheet\");\n        add(\"application/vnd.oasis.opendocument.presentation\");\n        add(\"application/vnd.oasis.opendocument.graphics\");\n        add(\"application/vnd.oasis.opendocument.chart\");\n        add(\"application/vnd.oasis.opendocument.formula\");\n        add(\"application/vnd.oasis.opendocument.image\");\n        add(\"application/vnd.oasis.opendocument.text-master\");\n        add(\"application/vnd.sun.xml.base\");\n        add(\"application/vnd.oasis.opendocument.base\");\n        add(\"application/vnd.oasis.opendocument.database\");\n        // Templates\n        add(\"application/vnd.oasis.opendocument.text-template\");\n        add(\"application/vnd.oasis.opendocument.spreadsheet-template\");\n        add(\"application/vnd.oasis.opendocument.presentation-template\");\n        add(\"application/vnd.oasis.opendocument.graphics-template\");\n        add(\"application/vnd.oasis.opendocument.chart-template\");\n        add(\"application/vnd.oasis.opendocument.formula-template\");\n        add(\"application/vnd.oasis.opendocument.text-web\");\n    }};\n\n    @NonNull\n    private final FmItem mFmItem;\n\n    public FmIconFetcher(@NonNull FmItem fmItem) {\n        mFmItem = fmItem;\n    }\n\n    @NonNull\n    @Override\n    public ImageLoader.ImageFetcherResult fetchImage(@NonNull String tag) {\n        PathContentInfo contentInfo = mFmItem.getContentInfo();\n        if (contentInfo == null) {\n            contentInfo = mFmItem.path.getPathContentInfo();\n            mFmItem.setContentInfo(contentInfo);\n        }\n        String mimeType = contentInfo.getMimeType();\n        int drawableRes = FmIcons.getDrawableFromType(mimeType);\n        int padding = UiUtils.dpToPx(ContextUtils.getContext(), 4);\n        int length = UiUtils.dpToPx(ContextUtils.getContext(), 40);\n        ImageLoader.DefaultImage defaultImage = new ImageLoader.DefaultImageDrawableRes(\"drawable_\" + drawableRes, drawableRes, padding);\n        Size size = new Size(length, length);\n        if (OPEN_DOCUMENT_FORMAT_MIME_TYPES.contains(mimeType)) {\n            // Open document format\n            Bitmap bitmap = FmIcons.getOpenDocumentThumbnail(mFmItem.path);\n            if (bitmap != null) {\n                return new ImageLoader.ImageFetcherResult(tag, getThumbnail(bitmap, size, true),\n                        false, true, defaultImage);\n            }\n        }\n        // Others\n        if (FmIcons.isApk(drawableRes)) {\n            if (ContentType.APK.getMimeType().equals(mimeType)) {\n                Bitmap bitmap = FmIcons.generateApkIcon(mFmItem.path);\n                if (bitmap != null) {\n                    return new ImageLoader.ImageFetcherResult(tag, getThumbnail(bitmap, size, true),\n                            false, true, defaultImage);\n                }\n            } else if (ContentType2.APKM.getMimeType().equals(mimeType)) {\n                Bitmap bitmap = FmIcons.getApkmIcon(mFmItem.path);\n                if (bitmap != null) {\n                    return new ImageLoader.ImageFetcherResult(tag, getThumbnail(bitmap, size, true),\n                            false, true, defaultImage);\n                }\n            } else {\n                Bitmap bitmap = FmIcons.getApksIcon(mFmItem.path);\n                if (bitmap != null) {\n                    return new ImageLoader.ImageFetcherResult(tag, getThumbnail(bitmap, size, true),\n                            false, true, defaultImage);\n                }\n            }\n        } else if (FmIcons.isArchive(drawableRes)) {\n            if (ContentType.JAVA_ARCHIVE.getMimeType().equals(mimeType)) {\n                Bitmap bitmap = FmIcons.generateJ2meIcon(mFmItem.path);\n                if (bitmap != null) {\n                    return new ImageLoader.ImageFetcherResult(tag, getThumbnail(bitmap, size, true),\n                            false, true, defaultImage);\n                }\n            }\n        } else if (FmIcons.isAudio(drawableRes)) {\n            try {\n                Bitmap bitmap = ThumbnailUtilsCompat.createAudioThumbnail(ContextUtils.getContext(), FmProvider.getContentUri(mFmItem.path), size, null);\n                return new ImageLoader.ImageFetcherResult(tag, bitmap, false, true, defaultImage);\n            } catch (IOException e) {\n                e.printStackTrace();\n            }\n        } else if (FmIcons.isVideo(drawableRes)) {\n            try {\n                Bitmap bitmap = ThumbnailUtilsCompat.createVideoThumbnail(ContextUtils.getContext(), FmProvider.getContentUri(mFmItem.path), size, null);\n                return new ImageLoader.ImageFetcherResult(tag, getThumbnail(bitmap, size, true), false, true, defaultImage);\n            } catch (IOException e) {\n                e.printStackTrace();\n            }\n        } else if (FmIcons.isImage(drawableRes)) {\n            if (ContentType.SVG.getMimeType().equals(mimeType)) {\n                // Load SVG image\n                try (InputStream is = mFmItem.path.openInputStream()) {\n                    SVG svg = SVGParser.getSVGFromInputStream(is);\n                    Bitmap bitmap = svg.getBitmap();\n                    return new ImageLoader.ImageFetcherResult(tag, getThumbnail(bitmap, size, true), false, true, defaultImage);\n                } catch (Throwable th) {\n                    // There can be runtime exceptions\n                    th.printStackTrace();\n                }\n            } else {\n                byte[] bytes = mFmItem.path.getContentAsBinary();\n                if (bytes.length > 0) {\n                    Bitmap bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);\n                    if (bitmap != null) {\n                        return new ImageLoader.ImageFetcherResult(tag, getThumbnail(bitmap, size, true),\n                                false, true, defaultImage);\n                    }\n                }\n            }\n        } else if (FmIcons.isEbook(drawableRes)) {\n            if (ContentType.EPUB.getMimeType().equals(mimeType)) {\n                Bitmap bitmap = FmIcons.generateEpubCover(mFmItem.path);\n                if (bitmap != null) {\n                    return new ImageLoader.ImageFetcherResult(tag, getThumbnail(bitmap, size, true),\n                            false, true, defaultImage);\n                }\n            }\n        } else if (FmIcons.isFont(drawableRes)) {\n            Bitmap bitmap = FmIcons.generateFontBitmap(mFmItem.path);\n            if (bitmap != null) {\n                return new ImageLoader.ImageFetcherResult(tag, bitmap,\n                        false, true, defaultImage);\n            }\n        } else if (FmIcons.isPdf(drawableRes)) {\n            Bitmap bitmap = FmIcons.generatePdfBitmap(ContextUtils.getContext(), FmProvider.getContentUri(mFmItem.path));\n            if (bitmap != null) {\n                return new ImageLoader.ImageFetcherResult(tag, getThumbnail(bitmap, size, true),\n                        false, true, defaultImage);\n            }\n        } else if (FmIcons.isGeneric(drawableRes)) {\n            String extension = mFmItem.path.getExtension();\n            if (extension != null) {\n                // Generate icon from extension (at most 4 characters)\n                int len = Math.min(extension.length(), 4);\n                String shortExt = extension.substring(0, len).toUpperCase(Locale.ROOT);\n                String extTag = \"fm_ext_\" + shortExt;\n                return new ImageLoader.ImageFetcherResult(tag, null,\n                        new ImageLoader.DefaultImageString(extTag, shortExt));\n            }\n            if (mFmItem.path.canExecute()) {\n                // Generate executable string\n                drawableRes = R.drawable.ic_frost_termux;\n                return new ImageLoader.ImageFetcherResult(tag, null,\n                        new ImageLoader.DefaultImageDrawableRes(\"drawable_\" + drawableRes, drawableRes, padding));\n            }\n        }\n        return new ImageLoader.ImageFetcherResult(tag, null, defaultImage);\n    }\n\n    private Bitmap getThumbnail(@NonNull Bitmap bitmap, @NonNull Size size, boolean recycle) {\n        return ThumbnailUtils.extractThumbnail(bitmap, size.getWidth(), size.getHeight(), recycle ? ThumbnailUtils.OPTIONS_RECYCLE_INPUT : 0);\n    }\n}"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/fm/icons/FmIcons.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.fm.icons;\n\nimport android.content.Context;\nimport android.content.pm.ApplicationInfo;\nimport android.content.pm.PackageInfo;\nimport android.content.pm.PackageManager;\nimport android.graphics.Bitmap;\nimport android.graphics.BitmapFactory;\nimport android.graphics.Color;\nimport android.graphics.Typeface;\nimport android.graphics.pdf.PdfRenderer;\nimport android.net.Uri;\nimport android.provider.DocumentsContract;\n\nimport androidx.annotation.DrawableRes;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.core.util.Pair;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.util.HashMap;\nimport java.util.Locale;\nimport java.util.Map;\nimport java.util.zip.ZipEntry;\nimport java.util.zip.ZipFile;\n\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.apk.ApkFile;\nimport io.github.muntashirakon.AppManager.apk.UriApkSource;\nimport io.github.muntashirakon.AppManager.self.filecache.FileCache;\nimport io.github.muntashirakon.AppManager.utils.ContextUtils;\nimport io.github.muntashirakon.AppManager.utils.FileUtils;\nimport io.github.muntashirakon.AppManager.utils.UIUtils;\nimport io.github.muntashirakon.io.Path;\n\n// Mostly taken from: https://github.com/zhanghai/MaterialFiles/blob/43a22b31d59a59e44a05a972269a3bd9cd0c9b8b/app/src/main/java/me/zhanghai/android/files/file/MimeTypeIcon.kt\n// Others are freelanced.\nfinal class FmIcons {\n    private static final int DRAWABLE_APK = R.drawable.ic_android;\n    private static final int DRAWABLE_ARCHIVE = R.drawable.ic_archive;\n    private static final int DRAWABLE_AUDIO = R.drawable.ic_audio_file;\n    private static final int DRAWABLE_CALENDAR = R.drawable.ic_calendar_month;\n    private static final int DRAWABLE_CERTIFICATE = R.drawable.ic_shield_key;\n    private static final int DRAWABLE_CODE = R.drawable.ic_code;\n    private static final int DRAWABLE_CONTACT = R.drawable.ic_contact_page;\n    private static final int DRAWABLE_DATABASE = R.drawable.ic_database;\n    private static final int DRAWABLE_DIRECTORY = R.drawable.ic_folder;\n    private static final int DRAWABLE_DOCUMENT = R.drawable.ic_file;\n    private static final int DRAWABLE_EBOOK = R.drawable.ic_book;\n    private static final int DRAWABLE_EMAIL = R.drawable.ic_email;\n    private static final int DRAWABLE_FONT = R.drawable.ic_font_download;\n    private static final int DRAWABLE_GENERIC = R.drawable.ic_file;\n    private static final int DRAWABLE_IMAGE = R.drawable.ic_image;\n    private static final int DRAWABLE_PDF = R.drawable.ic_pdf_file;\n    private static final int DRAWABLE_PRESENTATION = R.drawable.ic_presentation;\n    private static final int DRAWABLE_SPREADSHEET = R.drawable.ic_table;\n    private static final int DRAWABLE_TEXT = R.drawable.ic_file_document;\n    private static final int DRAWABLE_VIDEO = R.drawable.ic_video_file;\n    private static final int DRAWABLE_WORD = DRAWABLE_DOCUMENT;\n    private static final int DRAWABLE_EXCEL = DRAWABLE_SPREADSHEET;\n    private static final int DRAWABLE_POWERPOINT = DRAWABLE_PRESENTATION;\n\n    private static final Map<String, Integer> sMimeTypeToIconMap = new HashMap<String, Integer>() {\n        {\n            put(\"application/vnd.android.package-archive\", DRAWABLE_APK);\n            put(\"application/vnd.apkm\", DRAWABLE_APK);\n            put(\"application/x-apks\", DRAWABLE_APK);\n            put(\"application/xapk-package-archive\", DRAWABLE_APK);\n            put(\"application/gzip\", DRAWABLE_ARCHIVE);\n            // Not in IANA list, but Mozilla and Wikipedia say so.\n            put(\"application/java-archive\", DRAWABLE_ARCHIVE);\n            put(\"application/mac-binhex40\", DRAWABLE_ARCHIVE);\n            // Not in IANA list, but AOSP MimeUtils says so.\n            put(\"application/rar\", DRAWABLE_ARCHIVE);\n            put(\"application/zip\", DRAWABLE_ARCHIVE);\n            put(\"application/vnd.debian.binary-package\", DRAWABLE_ARCHIVE);\n            put(\"application/vnd.ms-cab-compressed\", DRAWABLE_ARCHIVE);\n            put(\"application/vnd.rar\", DRAWABLE_ARCHIVE);\n            put(\"application/x-7z-compressed\", DRAWABLE_ARCHIVE);\n            put(\"application/x-apple-diskimage\", DRAWABLE_ARCHIVE);\n            put(\"application/x-bzip\", DRAWABLE_ARCHIVE);\n            put(\"application/x-bzip2\", DRAWABLE_ARCHIVE);\n            put(\"application/x-compress\", DRAWABLE_ARCHIVE);\n            put(\"application/x-cpio\", DRAWABLE_ARCHIVE);\n            put(\"application/x-deb\", DRAWABLE_ARCHIVE);\n            put(\"application/x-debian-package\", DRAWABLE_ARCHIVE);\n            put(\"application/x-gtar\", DRAWABLE_ARCHIVE);\n            put(\"application/x-gtar-compressed\", DRAWABLE_ARCHIVE);\n            put(\"application/x-gzip\", DRAWABLE_ARCHIVE);\n            put(\"application/x-iso9660-image\", DRAWABLE_ARCHIVE);\n            put(\"application/x-java-archive\", DRAWABLE_ARCHIVE);\n            put(\"application/x-lha\", DRAWABLE_ARCHIVE);\n            put(\"application/x-lzh\", DRAWABLE_ARCHIVE);\n            put(\"application/x-lzma\", DRAWABLE_ARCHIVE);\n            put(\"application/x-lzx\", DRAWABLE_ARCHIVE);\n            put(\"application/x-rar\", DRAWABLE_ARCHIVE);\n            put(\"application/x-rar-compressed\", DRAWABLE_ARCHIVE);\n            put(\"application/x-stuffit\", DRAWABLE_ARCHIVE);\n            put(\"application/x-tar\", DRAWABLE_ARCHIVE);\n            put(\"application/x-webarchive\", DRAWABLE_ARCHIVE);\n            put(\"application/x-webarchive-xml\", DRAWABLE_ARCHIVE);\n            put(\"application/x-xz\", DRAWABLE_ARCHIVE);\n            put(\"application/ogg\", DRAWABLE_AUDIO);\n            put(\"application/x-flac\", DRAWABLE_AUDIO);\n            put(\"text/calendar\", DRAWABLE_CALENDAR);\n            put(\"text/x-vcalendar\", DRAWABLE_CALENDAR);\n            put(\"application/pem-certificate-chain\", DRAWABLE_CERTIFICATE);\n            put(\"application/pgp\", DRAWABLE_CERTIFICATE);\n            put(\"application/pgp-encrypted\", DRAWABLE_CERTIFICATE);\n            put(\"application/pgp-keys\", DRAWABLE_CERTIFICATE);\n            put(\"application/pgp-signature\", DRAWABLE_CERTIFICATE);\n            put(\"application/pkcs8\", DRAWABLE_CERTIFICATE);\n            put(\"application/x-pkcs12\", DRAWABLE_CERTIFICATE);\n            put(\"application/x-pkcs7-certificates\", DRAWABLE_CERTIFICATE);\n            put(\"application/x-pkcs7-certreqresp\", DRAWABLE_CERTIFICATE);\n            put(\"application/x-pkcs7-crl\", DRAWABLE_CERTIFICATE);\n            put(\"application/x-pkcs7-mime\", DRAWABLE_CERTIFICATE);\n            put(\"application/x-pkcs7-signature\", DRAWABLE_CERTIFICATE);\n            put(\"application/x-x509-ca-cert\", DRAWABLE_CERTIFICATE);\n            put(\"application/x-x509-server-cert\", DRAWABLE_CERTIFICATE);\n            put(\"application/x-x509-user-cert\", DRAWABLE_CERTIFICATE);\n            put(\"application/ecmascript\", DRAWABLE_CODE);\n            put(\"application/javascript\", DRAWABLE_CODE);\n            put(\"application/json\", DRAWABLE_CODE);\n            put(\"application/toml\", DRAWABLE_CODE);\n            put(\"application/typescript\", DRAWABLE_CODE);\n            put(\"application/xml\", DRAWABLE_CODE);\n            put(\"application/x-csh\", DRAWABLE_CODE);\n            put(\"application/x-ecmascript\", DRAWABLE_CODE);\n            put(\"application/x-javascript\", DRAWABLE_CODE);\n            put(\"application/x-latex\", DRAWABLE_CODE);\n            put(\"application/x-perl\", DRAWABLE_CODE);\n            put(\"application/x-plist\", DRAWABLE_CODE);\n            put(\"application/x-python\", DRAWABLE_CODE);\n            put(\"application/x-ruby\", DRAWABLE_CODE);\n            put(\"application/x-sh\", DRAWABLE_CODE);\n            put(\"application/x-shellscript\", DRAWABLE_CODE);\n            put(\"application/x-smali\", DRAWABLE_CODE);\n            put(\"application/x-texinfo\", DRAWABLE_CODE);\n            put(\"application/x-yaml\", DRAWABLE_CODE);\n            put(\"text/css\", DRAWABLE_CODE);\n            put(\"text/html\", DRAWABLE_CODE);\n            put(\"text/ecmascript\", DRAWABLE_CODE);\n            put(\"text/javascript\", DRAWABLE_CODE);\n            put(\"text/jscript\", DRAWABLE_CODE);\n            put(\"text/livescript\", DRAWABLE_CODE);\n            put(\"text/xml\", DRAWABLE_CODE);\n            put(\"text/x-asm\", DRAWABLE_CODE);\n            put(\"text/x-c++hdr\", DRAWABLE_CODE);\n            put(\"text/x-c++src\", DRAWABLE_CODE);\n            put(\"text/x-chdr\", DRAWABLE_CODE);\n            put(\"text/x-csh\", DRAWABLE_CODE);\n            put(\"text/x-csharp\", DRAWABLE_CODE);\n            put(\"text/x-csrc\", DRAWABLE_CODE);\n            put(\"text/x-dsrc\", DRAWABLE_CODE);\n            put(\"text/x-ecmascript\", DRAWABLE_CODE);\n            put(\"text/x-haskell\", DRAWABLE_CODE);\n            put(\"text/x-java\", DRAWABLE_CODE);\n            put(\"text/x-java-source\", DRAWABLE_CODE);\n            put(\"text/x-javascript\", DRAWABLE_CODE);\n            put(\"text/x-kotlin\", DRAWABLE_CODE);\n            put(\"text/x-literate-haskell\", DRAWABLE_CODE);\n            put(\"text/x-lua\", DRAWABLE_CODE);\n            put(\"text/x-pascal\", DRAWABLE_CODE);\n            put(\"text/x-perl\", DRAWABLE_CODE);\n            put(\"text/x-php\", DRAWABLE_CODE);\n            put(\"text/x-python\", DRAWABLE_CODE);\n            put(\"text/x-ruby\", DRAWABLE_CODE);\n            put(\"text/x-shellscript\", DRAWABLE_CODE);\n            put(\"text/x-tcl\", DRAWABLE_CODE);\n            put(\"text/x-tex\", DRAWABLE_CODE);\n            put(\"text/x-yaml\", DRAWABLE_CODE);\n            put(\"text/vcard\", DRAWABLE_CONTACT);\n            put(\"text/x-vcard\", DRAWABLE_CONTACT);\n            put(\"application/vnd.sqlite3\", DRAWABLE_DATABASE);\n            put(\"application/x-sqlite3\", DRAWABLE_DATABASE);\n            put(\"inode/directory\", DRAWABLE_DIRECTORY);\n            put(DocumentsContract.Document.MIME_TYPE_DIR, DRAWABLE_DIRECTORY);\n            put(\"resource/folder\", DRAWABLE_DIRECTORY);\n            put(\"application/rtf\", DRAWABLE_DOCUMENT);\n            put(\"application/vnd.oasis.opendocument.text\", DRAWABLE_DOCUMENT);\n            put(\"application/vnd.oasis.opendocument.text-master\", DRAWABLE_DOCUMENT);\n            put(\"application/vnd.oasis.opendocument.text-template\", DRAWABLE_DOCUMENT);\n            put(\"application/vnd.oasis.opendocument.text-web\", DRAWABLE_DOCUMENT);\n            put(\"application/vnd.stardivision.writer\", DRAWABLE_DOCUMENT);\n            put(\"application/vnd.stardivision.writer-global\", DRAWABLE_DOCUMENT);\n            put(\"application/vnd.sun.xml.writer\", DRAWABLE_DOCUMENT);\n            put(\"application/vnd.sun.xml.writer.global\", DRAWABLE_DOCUMENT);\n            put(\"application/vnd.sun.xml.writer.template\", DRAWABLE_DOCUMENT);\n            put(\"application/x-abiword\", DRAWABLE_DOCUMENT);\n            put(\"application/x-kword\", DRAWABLE_DOCUMENT);\n            put(\"text/rtf\", DRAWABLE_DOCUMENT);\n            put(\"application/epub+zip\", DRAWABLE_EBOOK);\n            put(\"application/vnd.amazon.ebook\", DRAWABLE_EBOOK);\n            put(\"application/x-cbr\", DRAWABLE_EBOOK);\n            put(\"application/x-cbz\", DRAWABLE_EBOOK);\n            put(\"application/x-ibooks+zip\", DRAWABLE_EBOOK);\n            put(\"application/x-mobipocket-ebook\", DRAWABLE_EBOOK);\n            put(\"application/vnd.ms-outlook\", DRAWABLE_EMAIL);\n            put(\"message/rfc822\", DRAWABLE_EMAIL);\n            put(\"application/font-cff\", DRAWABLE_FONT);\n            put(\"application/font-off\", DRAWABLE_FONT);\n            put(\"application/font-sfnt\", DRAWABLE_FONT);\n            put(\"application/font-ttf\", DRAWABLE_FONT);\n            put(\"application/font-woff\", DRAWABLE_FONT);\n            put(\"application/vnd.ms-fontobject\", DRAWABLE_FONT);\n            put(\"application/vnd.ms-opentype\", DRAWABLE_FONT);\n            put(\"application/x-font\", DRAWABLE_FONT);\n            put(\"application/x-font-otf\", DRAWABLE_FONT);\n            put(\"application/x-font-ttf\", DRAWABLE_FONT);\n            put(\"application/x-font-woff\", DRAWABLE_FONT);\n            put(\"application/vnd.oasis.opendocument.graphics\", DRAWABLE_IMAGE);\n            put(\"application/vnd.oasis.opendocument.graphics-template\", DRAWABLE_IMAGE);\n            put(\"application/vnd.oasis.opendocument.image\", DRAWABLE_IMAGE);\n            put(\"application/vnd.stardivision.draw\", DRAWABLE_IMAGE);\n            put(\"application/vnd.sun.xml.draw\", DRAWABLE_IMAGE);\n            put(\"application/vnd.sun.xml.draw.template\", DRAWABLE_IMAGE);\n            put(\"application/vnd.visio\", DRAWABLE_IMAGE);\n            put(\"application/pdf\", DRAWABLE_PDF);\n            put(\"application/vnd.oasis.opendocument.presentation\", DRAWABLE_PRESENTATION);\n            put(\"application/vnd.oasis.opendocument.presentation-template\", DRAWABLE_PRESENTATION);\n            put(\"application/vnd.stardivision.impress\", DRAWABLE_PRESENTATION);\n            put(\"application/vnd.sun.xml.impress\", DRAWABLE_PRESENTATION);\n            put(\"application/vnd.sun.xml.impress.template\", DRAWABLE_PRESENTATION);\n            put(\"application/x-kpresenter\", DRAWABLE_PRESENTATION);\n            put(\"application/vnd.oasis.opendocument.spreadsheet\", DRAWABLE_SPREADSHEET);\n            put(\"application/vnd.oasis.opendocument.spreadsheet-template\", DRAWABLE_SPREADSHEET);\n            put(\"application/vnd.stardivision.calc\", DRAWABLE_SPREADSHEET);\n            put(\"application/vnd.sun.xml.calc\", DRAWABLE_SPREADSHEET);\n            put(\"application/vnd.sun.xml.calc.template\", DRAWABLE_SPREADSHEET);\n            put(\"application/x-kspread\", DRAWABLE_SPREADSHEET);\n            put(\"application/x-quicktimeplayer\", DRAWABLE_VIDEO);\n            put(\"application/x-shockwave-flash\", DRAWABLE_VIDEO);\n            put(\"application/msword\", DRAWABLE_WORD);\n            put(\"application/vnd.openxmlformats-officedocument.wordprocessingml.document\", DRAWABLE_WORD);\n            put(\"application/vnd.openxmlformats-officedocument.wordprocessingml.template\", DRAWABLE_WORD);\n            put(\"application/vnd.ms-excel\", DRAWABLE_EXCEL);\n            put(\"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet\", DRAWABLE_EXCEL);\n            put(\"application/vnd.openxmlformats-officedocument.spreadsheetml.template\", DRAWABLE_EXCEL);\n            put(\"application/vnd.ms-powerpoint\", DRAWABLE_POWERPOINT);\n            put(\"application/vnd.openxmlformats-officedocument.presentationml.presentation\", DRAWABLE_POWERPOINT);\n            put(\"application/vnd.openxmlformats-officedocument.presentationml.slideshow\", DRAWABLE_POWERPOINT);\n            put(\"application/vnd.openxmlformats-officedocument.presentationml.template\", DRAWABLE_POWERPOINT);\n        }\n    };\n\n    private static final Map<String, Integer> sTypeToIconMap = new HashMap<String, Integer>() {\n        {\n            put(\"audio\", DRAWABLE_AUDIO);\n            put(\"font\", DRAWABLE_FONT);\n            put(\"image\", DRAWABLE_IMAGE);\n            put(\"text\", DRAWABLE_TEXT);\n            put(\"video\", DRAWABLE_VIDEO);\n        }\n    };\n\n    @DrawableRes\n    public static int getDrawableFromType(@Nullable String mimeType) {\n        if (mimeType == null) {\n            return DRAWABLE_GENERIC;\n        }\n        Integer drawable = sMimeTypeToIconMap.get(mimeType);\n        if (drawable != null) {\n            return drawable;\n        }\n        String firstPart = mimeType.split(\"/\")[0];\n        drawable = sTypeToIconMap.get(firstPart);\n        return drawable != null ? drawable : DRAWABLE_GENERIC;\n    }\n\n    public static boolean isApk(@DrawableRes int drawable) {\n        return drawable == DRAWABLE_APK;\n    }\n\n    public static boolean isArchive(@DrawableRes int drawable) {\n        return drawable == DRAWABLE_ARCHIVE;\n    }\n\n    public static boolean isImage(@DrawableRes int drawable) {\n        return drawable == DRAWABLE_IMAGE;\n    }\n\n    public static boolean isAudio(@DrawableRes int drawable) {\n        return drawable == DRAWABLE_AUDIO;\n    }\n\n    public static boolean isVideo(@DrawableRes int drawable) {\n        return drawable == DRAWABLE_VIDEO;\n    }\n\n    public static boolean isMedia(@DrawableRes int drawable) {\n        return drawable == DRAWABLE_AUDIO || drawable == DRAWABLE_VIDEO;\n    }\n\n    public static boolean isEbook(@DrawableRes int drawable) {\n        return drawable == DRAWABLE_EBOOK;\n    }\n\n    public static boolean isFont(@DrawableRes int drawable) {\n        return drawable == DRAWABLE_FONT;\n    }\n\n    public static boolean isPdf(@DrawableRes int drawable) {\n        return drawable == DRAWABLE_PDF;\n    }\n\n    public static boolean isGeneric(@DrawableRes int drawable) {\n        return drawable == DRAWABLE_GENERIC;\n    }\n\n    @Nullable\n    public static Bitmap generateFontBitmap(@NonNull Path path) {\n        String extension = path.getExtension();\n        String text = extension != null ? extension.substring(0, Math.min(extension.length(), 4))\n                .toUpperCase(Locale.ROOT) : \"FONT\";\n        Pair<File, Boolean> file = getUsableFile(path);\n        if (file == null) {\n            return null;\n        }\n        try {\n            Typeface typeface = Typeface.createFromFile(file.first);\n            return UIUtils.generateBitmapFromText(text, typeface);\n        } finally {\n            if (file.second) {\n                file.first.delete();\n            }\n        }\n    }\n\n    @Nullable\n    public static Bitmap generatePdfBitmap(@NonNull Context context, @NonNull Uri uri) {\n        PdfRenderer renderer;\n        try {\n            renderer = new PdfRenderer(FileUtils.getFdFromUri(context, uri, \"r\"));\n        } catch (IOException e) {\n            e.printStackTrace();\n            return null;\n        }\n        PdfRenderer.Page page;\n        try {\n            page = renderer.openPage(0);\n        } catch (RuntimeException e) {\n            e.printStackTrace();\n            return null;\n        }\n        int srcWidth = page.getWidth();\n        int srcHeight = page.getHeight();\n        if (srcWidth <= 0 || srcHeight <= 0) {\n            return null;\n        }\n        Bitmap bitmap = Bitmap.createBitmap(srcWidth, srcHeight, Bitmap.Config.ARGB_8888);\n        bitmap.eraseColor(Color.WHITE);\n        page.render(bitmap, null, null, PdfRenderer.Page.RENDER_MODE_FOR_DISPLAY);\n        return bitmap;\n    }\n\n    @Nullable\n    public static Bitmap generateEpubCover(@NonNull Path path) {\n        Pair<File, Boolean> file = getUsableFile(path);\n        if (file == null) {\n            return null;\n        }\n        try {\n            return EpubCoverGenerator.generateFromFile(file.first);\n        } finally {\n            if (file.second) {\n                file.first.delete();\n            }\n        }\n    }\n\n    @Nullable\n    public static Bitmap generateJ2meIcon(@NonNull Path path) {\n        Pair<File, Boolean> file = getUsableFile(path);\n        if (file == null) {\n            return null;\n        }\n        try {\n            return J2meIconExtractor.generateFromFile(file.first);\n        } finally {\n            if (file.second) {\n                file.first.delete();\n            }\n        }\n    }\n\n    @Nullable\n    public static Bitmap getOpenDocumentThumbnail(@NonNull Path path) {\n        Pair<File, Boolean> file = getUsableFile(path);\n        if (file == null) {\n            return null;\n        }\n        try (ZipFile zipFile = new ZipFile(file.first)) {\n            ZipEntry coverEntry = zipFile.getEntry(\"Thumbnails/thumbnail.png\");\n            if (coverEntry != null) {\n                return BitmapFactory.decodeStream(zipFile.getInputStream(coverEntry));\n            }\n        } catch (IOException e) {\n            e.printStackTrace();\n        } finally {\n            if (file.second) {\n                file.first.delete();\n            }\n        }\n        return null;\n    }\n\n    @Nullable\n    public static Bitmap generateApkIcon(@NonNull Path path) {\n        Pair<File, Boolean> file = getUsableFile(path);\n        if (file == null) {\n            return null;\n        }\n        try {\n            return getApkIcon(file.first);\n        } finally {\n            if (file.second) {\n                file.first.delete();\n            }\n        }\n    }\n\n    @Nullable\n    public static Bitmap getApkmIcon(@NonNull Path path) {\n        Pair<File, Boolean> file = getUsableFile(path);\n        if (file == null) {\n            return null;\n        }\n        try (ZipFile zipFile = new ZipFile(file.first)) {\n            ZipEntry iconEntry = zipFile.getEntry(\"icon.png\");\n            if (iconEntry != null) {\n                return BitmapFactory.decodeStream(zipFile.getInputStream(iconEntry));\n            }\n        } catch (IOException e) {\n            e.printStackTrace();\n        } finally {\n            if (file.second) {\n                file.first.delete();\n            }\n        }\n        return null;\n    }\n\n    @Nullable\n    public static Bitmap getApksIcon(@NonNull Path path) {\n        Pair<File, Boolean> file = getUsableFile(path);\n        if (file == null) {\n            return null;\n        }\n        try (ZipFile zipFile = new ZipFile(file.first)) {\n            ZipEntry iconEntry = zipFile.getEntry(\"icon.png\");\n            if (iconEntry != null) {\n                return BitmapFactory.decodeStream(zipFile.getInputStream(iconEntry));\n            }\n            // Load as ApkFile\n            UriApkSource apkSource = new UriApkSource(Uri.fromFile(file.first), path.getType());\n            try (ApkFile apkFile = apkSource.resolve()) {\n                ApkFile.Entry baseEntry = apkFile.getBaseEntry();\n                return getApkIcon(baseEntry.getFile(false));\n            }\n        } catch (IOException | ApkFile.ApkFileException e) {\n            e.printStackTrace();\n        } finally {\n            if (file.second) {\n                file.first.delete();\n            }\n        }\n        return null;\n    }\n\n    @Nullable\n    private static Bitmap getApkIcon(@NonNull File apkFile) {\n        PackageManager pm = ContextUtils.getContext().getPackageManager();\n        String f = apkFile.getAbsolutePath();\n        PackageInfo packageInfo = pm.getPackageArchiveInfo(f, 0);\n        if (packageInfo != null) {\n            ApplicationInfo info = packageInfo.applicationInfo;\n            info.sourceDir = info.publicSourceDir = f;\n            if (info.icon != 0) {\n                return UIUtils.getBitmapFromDrawable(info.loadIcon(pm));\n            }\n        }\n        return null;\n    }\n\n    @Nullable\n    private static Pair<File, Boolean> getUsableFile(@NonNull Path path) {\n        File f = path.getFile();\n        if (f == null) {\n            try {\n                return new Pair<>(FileCache.getGlobalFileCache().getCachedFile(path), true);\n            } catch (IOException ignore) {\n                return null;\n            }\n        }\n        f = new File(f.getPath());\n        if (!f.canRead()) {\n            try {\n                return new Pair<>(FileCache.getGlobalFileCache().getCachedFile(path), true);\n            } catch (IOException ignore) {\n                return null;\n            }\n        }\n        return new Pair<>(f, false);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/fm/icons/J2meIconExtractor.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.fm.icons;\n\nimport android.graphics.Bitmap;\nimport android.graphics.BitmapFactory;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.util.jar.Attributes;\nimport java.util.jar.Manifest;\nimport java.util.zip.ZipEntry;\nimport java.util.zip.ZipFile;\n\nclass J2meIconExtractor {\n    @Nullable\n    public static Bitmap generateFromFile(@NonNull File file) {\n        try(ZipFile zipFile = new ZipFile(file)) {\n            String iconFile = getIconLocation(zipFile, zipFile.getEntry(\"META-INF/MANIFEST.MF\"));\n            if (iconFile == null) {\n                // Not a J2ME JAR\n                return null;\n            }\n            ZipEntry iconEntry = zipFile.getEntry(iconFile);\n            if (iconEntry != null) {\n                return BitmapFactory.decodeStream(zipFile.getInputStream(iconEntry));\n            }\n        } catch (IOException e) {\n            e.printStackTrace();\n        }\n        return null;\n    }\n\n    @Nullable\n    private static String getIconLocation(@NonNull ZipFile zipFile, @Nullable ZipEntry zipEntry) {\n        if (zipEntry == null) {\n            return null;\n        }\n        try {\n            Manifest manifest = new Manifest(zipFile.getInputStream(zipEntry));\n            Attributes attributes = manifest.getMainAttributes();\n            // The logic is derived from J2ME Loader (ru.woesss.j2me.jar.Descriptor#getIcon())\n            String icon = attributes.getValue(\"MIDlet-Icon\");\n            if (icon == null || icon.trim().isEmpty()) {\n                String midlet = \"MIDlet-\" + 1;\n                icon = attributes.getValue(midlet);\n                if (icon == null) {\n                    return null;\n                }\n                int start = icon.indexOf(',');\n                if (start != -1) {\n                    int end = icon.indexOf(',', ++start);\n                    if (end != -1)\n                        icon = icon.substring(start, end);\n                }\n            }\n            icon = icon.trim();\n            if (icon.isEmpty()) {\n                return null;\n            }\n            while (icon.charAt(0) == '/') {\n                icon = icon.substring(1);\n            }\n            return icon;\n        } catch (IOException ignore) {\n        }\n        return null;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/history/IJsonSerializer.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.history;\n\nimport androidx.annotation.NonNull;\n\nimport org.json.JSONException;\nimport org.json.JSONObject;\n\npublic interface IJsonSerializer {\n    @NonNull\n    JSONObject serializeToJson() throws JSONException;\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/history/JsonDeserializer.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.history;\n\nimport androidx.annotation.NonNull;\n\nimport org.json.JSONException;\nimport org.json.JSONObject;\n\npublic class JsonDeserializer {\n    public interface Creator<T> {\n        @NonNull\n        T deserialize(@NonNull JSONObject jsonObject) throws JSONException;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/history/ops/OpHistoryActivity.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.history.ops;\n\nimport android.app.Application;\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.view.LayoutInflater;\nimport android.view.MenuItem;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.Button;\nimport android.widget.TextView;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.core.content.ContextCompat;\nimport androidx.lifecycle.AndroidViewModel;\nimport androidx.lifecycle.LiveData;\nimport androidx.lifecycle.MutableLiveData;\nimport androidx.lifecycle.ViewModelProvider;\n\nimport com.google.android.material.card.MaterialCardView;\nimport com.google.android.material.dialog.MaterialAlertDialogBuilder;\nimport com.google.android.material.floatingactionbutton.FloatingActionButton;\nimport com.google.android.material.progressindicator.LinearProgressIndicator;\n\nimport org.json.JSONException;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.concurrent.Future;\n\nimport io.github.muntashirakon.AppManager.BaseActivity;\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.db.entity.OpHistory;\nimport io.github.muntashirakon.AppManager.logs.Log;\nimport io.github.muntashirakon.AppManager.utils.DateUtils;\nimport io.github.muntashirakon.AppManager.utils.ThreadUtils;\nimport io.github.muntashirakon.AppManager.utils.UIUtils;\nimport io.github.muntashirakon.AppManager.utils.appearance.ColorCodes;\nimport io.github.muntashirakon.util.AdapterUtils;\nimport io.github.muntashirakon.util.UiUtils;\nimport io.github.muntashirakon.widget.RecyclerView;\n\npublic class OpHistoryActivity extends BaseActivity {\n    private OpHistoryViewModel mViewModel;\n    private OpHistoryAdapter mAdapter;\n    private LinearProgressIndicator mProgressIndicator;\n\n    @Override\n    protected void onAuthenticated(@Nullable Bundle savedInstanceState) {\n        setContentView(R.layout.activity_op_history);\n        setSupportActionBar(findViewById(R.id.toolbar));\n        mViewModel = new ViewModelProvider(this).get(OpHistoryViewModel.class);\n        mProgressIndicator = findViewById(R.id.progress_linear);\n        mProgressIndicator.setVisibilityAfterHide(View.GONE);\n        RecyclerView listView = findViewById(android.R.id.list);\n        listView.setLayoutManager(UIUtils.getGridLayoutAt450Dp(this));\n        listView.setEmptyView(findViewById(android.R.id.empty));\n        UiUtils.applyWindowInsetsAsPaddingNoTop(listView);\n        mAdapter = new OpHistoryAdapter(this);\n        listView.setAdapter(mAdapter);\n        FloatingActionButton fab = findViewById(R.id.floatingActionButton);\n        UiUtils.applyWindowInsetsAsMargin(fab);\n        fab.setOnClickListener(v -> new MaterialAlertDialogBuilder(this)\n                .setTitle(R.string.clear_history)\n                .setMessage(R.string.are_you_sure)\n                .setNegativeButton(R.string.no, null)\n                .setPositiveButton(R.string.yes, (dialog, which) -> {\n                    mProgressIndicator.show();\n                    mViewModel.clearHistory();\n                })\n                .show());\n        mViewModel.getOpHistoriesLiveData().observe(this, opHistories -> {\n            mProgressIndicator.hide();\n            mAdapter.setDefaultList(opHistories);\n        });\n        mViewModel.getClearHistoryLiveData().observe(this, cleared ->\n                UIUtils.displayShortToast(cleared ? R.string.done : R.string.failed));\n        mViewModel.getServiceLauncherIntentLiveData().observe(this, intent -> {\n            if (intent != null) {\n                ContextCompat.startForegroundService(this, intent);\n            } else {\n                UIUtils.displayShortToast(R.string.failed);\n            }\n        });\n        OpHistoryManager.getHistoryAddedLiveData().observe(this, opHistory -> {\n            // New history added\n            mProgressIndicator.show();\n            mViewModel.loadOpHistories();\n        });\n        mProgressIndicator.show();\n        mViewModel.loadOpHistories();\n    }\n\n    @Override\n    public boolean onOptionsItemSelected(@NonNull MenuItem item) {\n        int id = item.getItemId();\n        if (id == android.R.id.home) {\n            finish();\n        } else return super.onOptionsItemSelected(item);\n        return true;\n    }\n\n    static class OpHistoryAdapter extends RecyclerView.Adapter<OpHistoryAdapter.ViewHolder> {\n        private final List<OpHistoryItem> mAdapterList = new ArrayList<>();\n        private final OpHistoryActivity mActivity;\n        private final int mColorSuccess;\n        private final int mColorFailure;\n\n        static class ViewHolder extends RecyclerView.ViewHolder {\n            MaterialCardView itemView;\n            TextView type;\n            TextView title;\n            TextView execTime;\n            Button execBtn;\n\n            public ViewHolder(@NonNull View itemView) {\n                super(itemView);\n                this.itemView = (MaterialCardView) itemView;\n                type = itemView.findViewById(R.id.type);\n                title = itemView.findViewById(android.R.id.title);\n                execTime = itemView.findViewById(android.R.id.summary);\n                execBtn = itemView.findViewById(R.id.item_action);\n            }\n        }\n\n        OpHistoryAdapter(@NonNull OpHistoryActivity activity) {\n            mActivity = activity;\n            mColorSuccess = ColorCodes.getSuccessColor(activity);\n            mColorFailure = ColorCodes.getFailureColor(activity);\n        }\n\n        void setDefaultList(@NonNull List<OpHistoryItem> list) {\n            synchronized (mAdapterList) {\n                AdapterUtils.notifyDataSetChanged(this, mAdapterList, list);\n            }\n        }\n\n        @Override\n        public int getItemCount() {\n            synchronized (mAdapterList) {\n                return mAdapterList.size();\n            }\n        }\n\n        @Override\n        public long getItemId(int position) {\n            synchronized (mAdapterList) {\n                return mAdapterList.get(position).hashCode();\n            }\n        }\n\n        @NonNull\n        @Override\n        public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {\n            View view = LayoutInflater.from(parent.getContext())\n                    .inflate(R.layout.item_op_history, parent, false);\n            return new ViewHolder(view);\n        }\n\n        @Override\n        public void onBindViewHolder(@NonNull ViewHolder holder, int position) {\n            OpHistoryItem history;\n            synchronized (mAdapterList) {\n                history = mAdapterList.get(position);\n            }\n            holder.itemView.setStrokeColor(history.getStatus() ? mColorSuccess : mColorFailure);\n            holder.type.setText(history.getLocalizedType(mActivity));\n            holder.title.setText(history.getLabel(mActivity));\n            holder.execTime.setText(DateUtils.formatLongDateTime(mActivity, history.getTimestamp()));\n            holder.itemView.setOnClickListener(v -> {\n                // TODO: 1/26/25 Display history info\n            });\n            holder.itemView.setOnLongClickListener(v -> {\n                // TODO: 1/26/25 Possible long click options\n                //  1. Apply\n                //  2. Delete\n                //  3. Add as a profile (for profile and batch op)\n                //  4. Export (for profile)\n                //  5. Create shortcut\n                return true;\n            });\n            holder.execBtn.setOnClickListener(v -> new MaterialAlertDialogBuilder(mActivity)\n                    .setTitle(R.string.title_confirm_execution)\n                    .setMessage(R.string.are_you_sure)\n                    .setNegativeButton(R.string.no, null)\n                    .setPositiveButton(R.string.yes, (dialog, which) ->\n                            mActivity.mViewModel.getServiceLauncherIntent(history))\n                    .show());\n        }\n    }\n\n    public static class OpHistoryViewModel extends AndroidViewModel {\n        private final MutableLiveData<List<OpHistoryItem>> mOpHistoriesLiveData = new MutableLiveData<>();\n        private final MutableLiveData<Boolean> mClearHistoryLiveData = new MutableLiveData<>();\n        private final MutableLiveData<Intent> mServiceLauncherIntentLiveData = new MutableLiveData<>();\n        private Future<?> mOpHistoriesResult;\n\n        public OpHistoryViewModel(@NonNull Application application) {\n            super(application);\n        }\n\n        public LiveData<List<OpHistoryItem>> getOpHistoriesLiveData() {\n            return mOpHistoriesLiveData;\n        }\n\n        public LiveData<Boolean> getClearHistoryLiveData() {\n            return mClearHistoryLiveData;\n        }\n\n        public MutableLiveData<Intent> getServiceLauncherIntentLiveData() {\n            return mServiceLauncherIntentLiveData;\n        }\n\n        public void loadOpHistories() {\n            if (mOpHistoriesResult != null) {\n                mOpHistoriesResult.cancel(true);\n            }\n            mOpHistoriesResult = ThreadUtils.postOnBackgroundThread(() -> {\n                synchronized (mOpHistoriesLiveData) {\n                    List<OpHistory> opHistories = OpHistoryManager.getAllHistoryItems();\n                    Collections.sort(opHistories, (o1, o2) -> -Long.compare(o1.execTime, o2.execTime));\n                    List<OpHistoryItem> opHistoryItems = new ArrayList<>(opHistories.size());\n                    for (OpHistory history : opHistories) {\n                        try {\n                            opHistoryItems.add(new OpHistoryItem(history));\n                        } catch (JSONException e) {\n                            Log.w(TAG, e.getMessage(), e);\n                        }\n                    }\n                    mOpHistoriesLiveData.postValue(opHistoryItems);\n                }\n            });\n        }\n\n        public void clearHistory() {\n            ThreadUtils.postOnBackgroundThread(() -> {\n                synchronized (mOpHistoriesLiveData) {\n                    OpHistoryManager.clearAllHistory();\n                    mClearHistoryLiveData.postValue(true);\n                    mOpHistoriesLiveData.postValue(Collections.emptyList());\n                }\n            });\n        }\n\n        public void getServiceLauncherIntent(@NonNull OpHistoryItem opHistoryItem) {\n            ThreadUtils.postOnBackgroundThread(() -> {\n                try {\n                    Intent intent = OpHistoryManager.getExecutableIntent(getApplication(), opHistoryItem);\n                    mServiceLauncherIntentLiveData.postValue(intent);\n                } catch (JSONException e) {\n                    Log.w(TAG, e.getMessage(), e);\n                    mServiceLauncherIntentLiveData.postValue(null);\n                }\n            });\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/history/ops/OpHistoryItem.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.history.ops;\n\nimport android.content.Context;\nimport android.content.res.Resources;\n\nimport androidx.annotation.NonNull;\n\nimport org.json.JSONException;\nimport org.json.JSONObject;\n\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.batchops.BatchOpsService;\nimport io.github.muntashirakon.AppManager.db.entity.OpHistory;\nimport io.github.muntashirakon.AppManager.utils.JSONUtils;\n\npublic class OpHistoryItem {\n    private final OpHistory opHistory;\n    public final JSONObject jsonData;\n\n    public OpHistoryItem(@NonNull OpHistory opHistory) throws JSONException {\n        this.opHistory = opHistory;\n        jsonData = new JSONObject(opHistory.serializedData);\n    }\n\n    @OpHistoryManager.HistoryType\n    public String getType() {\n        return opHistory.type;\n    }\n\n    @NonNull\n    public String getLocalizedType(@NonNull Context context) {\n        switch (opHistory.type) {\n            case OpHistoryManager.HISTORY_TYPE_BATCH_OPS:\n                try {\n                    return context.getString(jsonData.getInt(\"title_res\"));\n                } catch (Resources.NotFoundException | JSONException e) {\n                    return context.getString(R.string.batch_ops);\n                }\n            case OpHistoryManager.HISTORY_TYPE_INSTALLER:\n                return context.getString(R.string.installer);\n            case OpHistoryManager.HISTORY_TYPE_PROFILE:\n                return context.getString(R.string.profiles);\n        }\n        throw new IllegalStateException(\"Invalid type: \" + opHistory.type);\n    }\n\n    @NonNull\n    public String getLabel(@NonNull Context context) {\n        switch (opHistory.type) {\n            case OpHistoryManager.HISTORY_TYPE_BATCH_OPS:\n                try {\n                    int op = jsonData.getInt(\"op\");\n                    return BatchOpsService.getDesiredOpTitle(context, op);\n                } catch (JSONException e) {\n                    return context.getString(R.string.unknown_op);\n                }\n            case OpHistoryManager.HISTORY_TYPE_INSTALLER: {\n                String label = JSONUtils.optString(jsonData, \"app_label\");\n                if (label != null) {\n                    return label;\n                }\n                return context.getString(R.string.state_unknown);\n            }\n            case OpHistoryManager.HISTORY_TYPE_PROFILE: {\n                String label = JSONUtils.optString(jsonData, \"profile_name\");\n                if (label != null) {\n                    return label;\n                }\n                return context.getString(R.string.state_unknown);\n            }\n        }\n        throw new IllegalStateException(\"Invalid type: \" + opHistory.type);\n    }\n\n    public long getTimestamp() {\n        return opHistory.execTime;\n    }\n\n    public boolean getStatus() {\n        return opHistory.status.equals(OpHistoryManager.STATUS_SUCCESS);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/history/ops/OpHistoryManager.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.history.ops;\n\nimport android.content.Context;\nimport android.content.Intent;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.StringDef;\nimport androidx.annotation.WorkerThread;\nimport androidx.lifecycle.LiveData;\nimport androidx.lifecycle.MutableLiveData;\n\nimport org.json.JSONException;\n\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.util.List;\n\nimport io.github.muntashirakon.AppManager.apk.installer.ApkQueueItem;\nimport io.github.muntashirakon.AppManager.apk.installer.PackageInstallerService;\nimport io.github.muntashirakon.AppManager.batchops.BatchOpsService;\nimport io.github.muntashirakon.AppManager.batchops.BatchQueueItem;\nimport io.github.muntashirakon.AppManager.db.AppsDb;\nimport io.github.muntashirakon.AppManager.db.entity.OpHistory;\nimport io.github.muntashirakon.AppManager.history.IJsonSerializer;\nimport io.github.muntashirakon.AppManager.intercept.IntentCompat;\nimport io.github.muntashirakon.AppManager.logs.Log;\nimport io.github.muntashirakon.AppManager.profiles.ProfileApplierService;\nimport io.github.muntashirakon.AppManager.profiles.ProfileQueueItem;\n\npublic final class OpHistoryManager {\n    public static final String TAG = OpHistoryManager.class.getSimpleName();\n\n    public static final String HISTORY_TYPE_BATCH_OPS = \"batch_ops\";\n    public static final String HISTORY_TYPE_INSTALLER = \"installer\";\n    public static final String HISTORY_TYPE_PROFILE = \"profile\";\n\n    @Retention(RetentionPolicy.SOURCE)\n    @StringDef({HISTORY_TYPE_BATCH_OPS, HISTORY_TYPE_INSTALLER, HISTORY_TYPE_PROFILE})\n    public @interface HistoryType {\n    }\n\n    public static final String STATUS_SUCCESS = \"success\";\n    public static final String STATUS_FAILURE = \"failure\";\n\n    @Retention(RetentionPolicy.SOURCE)\n    @StringDef({STATUS_SUCCESS, STATUS_FAILURE})\n    public @interface Status {\n    }\n\n    private static final MutableLiveData<OpHistory> sHistoryAddedLiveData = new MutableLiveData<>();\n\n    public static LiveData<OpHistory> getHistoryAddedLiveData() {\n        return sHistoryAddedLiveData;\n    }\n\n    @WorkerThread\n    public static long addHistoryItem(@HistoryType String historyType,\n                                      @NonNull IJsonSerializer item,\n                                      boolean success) {\n        try {\n            OpHistory opHistory = new OpHistory();\n            opHistory.type = historyType;\n            opHistory.execTime = System.currentTimeMillis();\n            opHistory.serializedData = item.serializeToJson().toString();\n            opHistory.status = success ? STATUS_SUCCESS : STATUS_FAILURE;\n            opHistory.serializedExtra = null;\n            long id = AppsDb.getInstance().opHistoryDao().insert(opHistory);\n            opHistory.id = id;\n            sHistoryAddedLiveData.postValue(opHistory);\n            return id;\n        } catch (JSONException e) {\n            Log.e(TAG, \"Could not serialize \" + item.getClass(), e);\n            return -1;\n        }\n    }\n\n    @WorkerThread\n    public static List<OpHistory> getAllHistoryItems() {\n        return AppsDb.getInstance().opHistoryDao().getAll();\n    }\n\n    @WorkerThread\n    public static void clearAllHistory() {\n        AppsDb.getInstance().opHistoryDao().deleteAll();\n    }\n\n    @NonNull\n    public static Intent getExecutableIntent(@NonNull Context context, @NonNull OpHistoryItem item)\n            throws JSONException {\n        switch (item.getType()) {\n            case HISTORY_TYPE_BATCH_OPS: {\n                BatchQueueItem batchQueueItem = BatchQueueItem.DESERIALIZER.deserialize(item.jsonData);\n                return BatchOpsService.getServiceIntent(context, batchQueueItem);\n            }\n            case HISTORY_TYPE_INSTALLER: {\n                ApkQueueItem apkQueueItem = ApkQueueItem.DESERIALIZER.deserialize(item.jsonData);\n                Intent intent = new Intent(context, PackageInstallerService.class);\n                IntentCompat.putWrappedParcelableExtra(intent, PackageInstallerService.EXTRA_QUEUE_ITEM, apkQueueItem);\n                return intent;\n            }\n            case HISTORY_TYPE_PROFILE: {\n                ProfileQueueItem profileQueueItem = ProfileQueueItem.DESERIALIZER.deserialize(item.jsonData);\n                return ProfileApplierService.getIntent(context, profileQueueItem, true);\n            }\n        }\n        throw new IllegalStateException(\"Invalid type: \" + item.getType());\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/intercept/ActivityInterceptor.java",
    "content": "// SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.intercept;\n\nimport android.content.ComponentName;\nimport android.content.Intent;\nimport android.content.pm.ActivityInfo;\nimport android.content.pm.PackageManager;\nimport android.content.pm.ResolveInfo;\nimport android.graphics.drawable.Drawable;\nimport android.net.Uri;\nimport android.os.BadParcelableException;\nimport android.os.Build;\nimport android.os.Bundle;\nimport android.os.RemoteException;\nimport android.os.UserHandleHidden;\nimport android.text.Editable;\nimport android.text.TextUtils;\nimport android.text.TextWatcher;\nimport android.view.LayoutInflater;\nimport android.view.Menu;\nimport android.view.MenuItem;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.Button;\nimport android.widget.ImageView;\nimport android.widget.TextView;\n\nimport androidx.activity.result.ActivityResultLauncher;\nimport androidx.activity.result.contract.ActivityResultContracts;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.appcompat.app.ActionBar;\nimport androidx.collection.LruCache;\nimport androidx.collection.SimpleArrayMap;\nimport androidx.collection.SparseArrayCompat;\nimport androidx.core.content.ContextCompat;\nimport androidx.recyclerview.widget.RecyclerView;\n\nimport com.google.android.material.button.MaterialButton;\nimport com.google.android.material.checkbox.MaterialCheckBox;\nimport com.google.android.material.textfield.TextInputEditText;\nimport com.google.android.material.textfield.TextInputLayout;\n\nimport java.net.URISyntaxException;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Objects;\nimport java.util.StringTokenizer;\nimport java.util.UUID;\n\nimport io.github.muntashirakon.AppManager.BaseActivity;\nimport io.github.muntashirakon.AppManager.BuildConfig;\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.compat.ActivityManagerCompat;\nimport io.github.muntashirakon.AppManager.compat.IntegerCompat;\nimport io.github.muntashirakon.AppManager.compat.ManifestCompat;\nimport io.github.muntashirakon.AppManager.compat.PackageManagerCompat;\nimport io.github.muntashirakon.AppManager.crypto.auth.AuthManager;\nimport io.github.muntashirakon.AppManager.logs.Log;\nimport io.github.muntashirakon.AppManager.runner.RunnerUtils;\nimport io.github.muntashirakon.AppManager.self.SelfPermissions;\nimport io.github.muntashirakon.AppManager.self.imagecache.ImageLoader;\nimport io.github.muntashirakon.AppManager.settings.Ops;\nimport io.github.muntashirakon.AppManager.shortcut.CreateShortcutDialogFragment;\nimport io.github.muntashirakon.AppManager.utils.ClipboardUtils;\nimport io.github.muntashirakon.AppManager.utils.ThreadUtils;\nimport io.github.muntashirakon.util.AdapterUtils;\nimport io.github.muntashirakon.AppManager.utils.PackageUtils;\nimport io.github.muntashirakon.AppManager.utils.UIUtils;\nimport io.github.muntashirakon.AppManager.utils.Utils;\nimport io.github.muntashirakon.dialog.TextInputDropdownDialogBuilder;\nimport io.github.muntashirakon.util.UiUtils;\nimport io.github.muntashirakon.widget.MaterialAutoCompleteTextView;\n\n// Copyright 2020 Muntashir Al-Islam\n// Copyright 2017 k3b\n// Copyright 2012 Intrications\npublic class ActivityInterceptor extends BaseActivity {\n    public static final String TAG = ActivityInterceptor.class.getSimpleName();\n\n    public static final String EXTRA_PACKAGE_NAME = BuildConfig.APPLICATION_ID + \".intent.extra.PACKAGE_NAME\";\n    public static final String EXTRA_CLASS_NAME = BuildConfig.APPLICATION_ID + \".intent.extra.CLASS_NAME\";\n    public static final String EXTRA_ACTION = BuildConfig.APPLICATION_ID + \".intent.extra.ACTION\";\n    // TODO(29/8/21): Enable getting activity result for activities launched with root\n    public static final String EXTRA_ROOT = BuildConfig.APPLICATION_ID + \".intent.extra.ROOT\";\n    // Root only\n    public static final String EXTRA_USER_HANDLE = BuildConfig.APPLICATION_ID + \".intent.extra.USER_HANDLE\";\n    // Whether to trigger the Intent on startup, requires `auth` parameter to be set\n    public static final String EXTRA_TRIGGER_ON_START = BuildConfig.APPLICATION_ID + \".intent.extra.TRIGGER_ON_START\";\n    public static final String EXTRA_AUTH = BuildConfig.APPLICATION_ID + \".intent.extra.AUTH\";\n\n    private static final String INTENT_EDITED = \"intent_edited\";\n\n    private static final SparseArrayCompat<String> INTENT_FLAG_TO_STRING = new SparseArrayCompat<String>() {\n        {\n            put(Intent.FLAG_GRANT_READ_URI_PERMISSION, \"FLAG_GRANT_READ_URI_PERMISSION\");\n            put(Intent.FLAG_GRANT_WRITE_URI_PERMISSION, \"FLAG_GRANT_WRITE_URI_PERMISSION\");\n            put(Intent.FLAG_FROM_BACKGROUND, \"FLAG_FROM_BACKGROUND\");\n            put(Intent.FLAG_DEBUG_LOG_RESOLUTION, \"FLAG_DEBUG_LOG_RESOLUTION\");\n            put(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES, \"FLAG_EXCLUDE_STOPPED_PACKAGES\");\n            put(Intent.FLAG_INCLUDE_STOPPED_PACKAGES, \"FLAG_INCLUDE_STOPPED_PACKAGES\");\n            put(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION, \"FLAG_GRANT_PERSISTABLE_URI_PERMISSION\");\n            put(Intent.FLAG_GRANT_PREFIX_URI_PERMISSION, \"FLAG_GRANT_PREFIX_URI_PERMISSION\");\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {\n                put(Intent.FLAG_DIRECT_BOOT_AUTO, \"FLAG_DIRECT_BOOT_AUTO\");\n            }\n            put(0x00000200, \"FLAG_IGNORE_EPHEMERAL\");\n            put(Intent.FLAG_ACTIVITY_NO_HISTORY, \"FLAG_ACTIVITY_NO_HISTORY\");\n            put(Intent.FLAG_ACTIVITY_SINGLE_TOP, \"FLAG_ACTIVITY_SINGLE_TOP\");\n            put(Intent.FLAG_ACTIVITY_NEW_TASK, \"FLAG_ACTIVITY_NEW_TASK\");\n            put(Intent.FLAG_ACTIVITY_MULTIPLE_TASK, \"FLAG_ACTIVITY_MULTIPLE_TASK\");\n            put(Intent.FLAG_ACTIVITY_CLEAR_TOP, \"FLAG_ACTIVITY_CLEAR_TOP\");\n            put(Intent.FLAG_ACTIVITY_FORWARD_RESULT, \"FLAG_ACTIVITY_FORWARD_RESULT\");\n            put(Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP, \"FLAG_ACTIVITY_PREVIOUS_IS_TOP\");\n            put(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS, \"FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS\");\n            put(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT, \"FLAG_ACTIVITY_BROUGHT_TO_FRONT\");\n            put(Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED, \"FLAG_ACTIVITY_RESET_TASK_IF_NEEDED\");\n            put(Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY, \"FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY\");\n            put(Intent.FLAG_ACTIVITY_NEW_DOCUMENT, \"FLAG_ACTIVITY_NEW_DOCUMENT\");\n            put(Intent.FLAG_ACTIVITY_NO_USER_ACTION, \"FLAG_ACTIVITY_NO_USER_ACTION\");\n            put(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT, \"FLAG_ACTIVITY_REORDER_TO_FRONT\");\n            put(Intent.FLAG_ACTIVITY_NO_ANIMATION, \"FLAG_ACTIVITY_NO_ANIMATION\");\n            put(Intent.FLAG_ACTIVITY_CLEAR_TASK, \"FLAG_ACTIVITY_CLEAR_TASK\");\n            put(Intent.FLAG_ACTIVITY_TASK_ON_HOME, \"FLAG_ACTIVITY_TASK_ON_HOME\");\n            put(Intent.FLAG_ACTIVITY_RETAIN_IN_RECENTS, \"FLAG_ACTIVITY_RETAIN_IN_RECENTS\");\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {\n                put(Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT, \"FLAG_ACTIVITY_LAUNCH_ADJACENT\");\n            }\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {\n                put(Intent.FLAG_ACTIVITY_MATCH_EXTERNAL, \"FLAG_ACTIVITY_MATCH_EXTERNAL\");\n            }\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {\n                put(Intent.FLAG_ACTIVITY_REQUIRE_NON_BROWSER, \"FLAG_ACTIVITY_REQUIRE_NON_BROWSER\");\n            }\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {\n                put(Intent.FLAG_ACTIVITY_REQUIRE_DEFAULT, \"FLAG_ACTIVITY_REQUIRE_DEFAULT\");\n            }\n        }\n    };\n\n    // TODO(25/1/21): Add support for receiver flags\n    private static final SparseArrayCompat<String> INTENT_RECEIVER_FLAG_TO_STRING = new SparseArrayCompat<String>() {\n        {\n            put(Intent.FLAG_RECEIVER_REGISTERED_ONLY, \"FLAG_RECEIVER_REGISTERED_ONLY\");\n            put(Intent.FLAG_RECEIVER_REPLACE_PENDING, \"FLAG_RECEIVER_REPLACE_PENDING\");\n            put(Intent.FLAG_RECEIVER_FOREGROUND, \"FLAG_RECEIVER_FOREGROUND\");\n            put(0x80000000, \"FLAG_RECEIVER_OFFLOAD\");\n            put(Intent.FLAG_RECEIVER_NO_ABORT, \"FLAG_RECEIVER_NO_ABORT\");\n            put(0x04000000, \"FLAG_RECEIVER_REGISTERED_ONLY_BEFORE_BOOT\");\n            put(0x02000000, \"FLAG_RECEIVER_BOOT_UPGRADE\");\n            put(0x01000000, \"FLAG_RECEIVER_INCLUDE_BACKGROUND\");\n            put(0x00800000, \"FLAG_RECEIVER_EXCLUDE_BACKGROUND\");\n            put(0x00400000, \"FLAG_RECEIVER_FROM_SHELL\");\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {\n                put(Intent.FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS, \"FLAG_RECEIVER_VISIBLE_TO_INSTANT_APPS\");\n            }\n        }\n    };\n\n    private static final List<String> INTENT_CATEGORIES = new ArrayList<String>() {\n        {\n            add(Intent.CATEGORY_DEFAULT);\n            add(Intent.CATEGORY_BROWSABLE);\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {\n                add(Intent.CATEGORY_VOICE);\n            }\n            add(Intent.CATEGORY_ALTERNATIVE);\n            add(Intent.CATEGORY_SELECTED_ALTERNATIVE);\n            add(Intent.CATEGORY_TAB);\n            add(Intent.CATEGORY_LAUNCHER);\n            add(Intent.CATEGORY_LEANBACK_LAUNCHER);\n            add(\"android.intent.category.CAR_LAUNCHER\");\n            add(\"android.intent.category.LEANBACK_SETTINGS\");\n            add(Intent.CATEGORY_INFO);\n            add(Intent.CATEGORY_HOME);\n            add(\"android.intent.category.HOME_MAIN\");\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {\n                add(Intent.CATEGORY_SECONDARY_HOME);\n            }\n            add(\"android.intent.category.SETUP_WIZARD\");\n            add(\"android.intent.category.LAUNCHER_APP\");\n            add(Intent.CATEGORY_PREFERENCE);\n            add(Intent.CATEGORY_DEVELOPMENT_PREFERENCE);\n            add(Intent.CATEGORY_EMBED);\n            add(Intent.CATEGORY_APP_MARKET);\n            add(Intent.CATEGORY_MONKEY);\n            add(Intent.CATEGORY_TEST);\n            add(Intent.CATEGORY_UNIT_TEST);\n            add(Intent.CATEGORY_SAMPLE_CODE);\n            add(Intent.CATEGORY_OPENABLE);\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {\n                add(Intent.CATEGORY_TYPED_OPENABLE);\n            }\n            add(Intent.CATEGORY_FRAMEWORK_INSTRUMENTATION_TEST);\n            add(Intent.CATEGORY_CAR_DOCK);\n            add(Intent.CATEGORY_DESK_DOCK);\n            add(Intent.CATEGORY_LE_DESK_DOCK);\n            add(Intent.CATEGORY_HE_DESK_DOCK);\n            add(Intent.CATEGORY_CAR_MODE);\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {\n                add(Intent.CATEGORY_VR_HOME);\n            }\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {\n                add(Intent.CATEGORY_ACCESSIBILITY_SHORTCUT_TARGET);\n            }\n            add(Intent.CATEGORY_APP_BROWSER);\n            add(Intent.CATEGORY_APP_CALCULATOR);\n            add(Intent.CATEGORY_APP_CALENDAR);\n            add(Intent.CATEGORY_APP_CONTACTS);\n            add(Intent.CATEGORY_APP_EMAIL);\n            add(Intent.CATEGORY_APP_GALLERY);\n            add(Intent.CATEGORY_APP_MAPS);\n            add(Intent.CATEGORY_APP_MESSAGING);\n            add(Intent.CATEGORY_APP_MUSIC);\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {\n                add(Intent.CATEGORY_APP_FILES);\n            }\n        }\n    };\n\n    private abstract class IntentUpdateTextWatcher implements TextWatcher {\n        private final TextView mTextView;\n\n        IntentUpdateTextWatcher(TextView textView) {\n            mTextView = textView;\n        }\n\n        @Override\n        public void onTextChanged(CharSequence s, int start, int before, int count) {\n            if (mAreTextWatchersActive) {\n                try {\n                    String modifiedContent = mTextView.getText().toString();\n                    onUpdateIntent(modifiedContent);\n                    showTextViewIntentData(mTextView);\n                    showResetIntentButton(true);\n                    refreshUI();\n                } catch (Exception e) {\n                    UIUtils.displayShortToast(e.getMessage());\n                    e.printStackTrace();\n                }\n            }\n        }\n\n        abstract protected void onUpdateIntent(String modifiedContent);\n\n        @Override\n        public void beforeTextChanged(CharSequence s, int start, int count, int after) {\n        }\n\n        @Override\n        public void afterTextChanged(Editable s) {\n        }\n    }\n\n    private MaterialAutoCompleteTextView mActionView;\n    private MaterialAutoCompleteTextView mDataView;\n    private MaterialAutoCompleteTextView mTypeView;\n    private MaterialAutoCompleteTextView mUriView;\n    private MaterialAutoCompleteTextView mPackageNameView;\n    private MaterialAutoCompleteTextView mClassNameView;\n    private TextInputEditText mIdView;\n    private TextInputEditText mUserIdEdit;\n\n    @Nullable\n    private HistoryEditText mHistory;\n\n    private CategoriesRecyclerViewAdapter mCategoriesAdapter;\n    private FlagsRecyclerViewAdapter mFlagsAdapter;\n    private ExtrasRecyclerViewAdapter mExtrasAdapter;\n    private MatchingActivitiesRecyclerViewAdapter mMatchingActivitiesAdapter;\n    private TextView mActivitiesHeader;\n    private Button mResendIntentButton;\n    private Button mResetIntentButton;\n\n    /**\n     * String representation of intent as URI\n     */\n    @Nullable\n    private String mOriginalIntent;\n    /**\n     * Extras that are lost during intent to string conversion\n     */\n    @Nullable\n    private Bundle mAdditionalExtras;\n    @Nullable\n    private Intent mMutableIntent;\n    @Nullable\n    private ComponentName mRequestedComponent;\n\n    private boolean mUseRoot;\n    private int mUserHandle;\n\n    @Nullable\n    private Integer mLastResultCode = null;\n    @Nullable\n    private Intent mLastResultIntent = null;\n\n    private final LruCache<String, CharSequence> mPackageLabelMap = new LruCache<>(16);\n\n    private volatile boolean mAreTextWatchersActive;\n\n    private final ActivityResultLauncher<Intent> mIntentLauncher = registerForActivityResult(\n            new ActivityResultContracts.StartActivityForResult(), result -> {\n                Intent data = result.getData();\n                mLastResultCode = result.getResultCode();\n                mLastResultIntent = result.getData();\n\n                // Forward the result of the activity to the caller activity\n                setResult(result.getResultCode(), data);\n\n                refreshUI();\n                Uri uri = data == null ? null : data.getData();\n                UIUtils.displayLongToast(\"%s: (%s)\", getString(R.string.activity_result), uri);\n            });\n\n    @Override\n    public void onAuthenticated(Bundle savedInstanceState) {\n        setContentView(R.layout.activity_interceptor);\n        setSupportActionBar(findViewById(R.id.toolbar));\n        findViewById(R.id.progress_linear).setVisibility(View.GONE);\n        // Get Intent\n        Intent intent = new Intent(getIntent());\n        mUseRoot = Ops.isWorkingUidRoot() && intent.getBooleanExtra(EXTRA_ROOT, false);\n        mUserHandle = intent.getIntExtra(EXTRA_USER_HANDLE, UserHandleHidden.myUserId());\n        intent.removeExtra(EXTRA_ROOT);\n        intent.removeExtra(EXTRA_USER_HANDLE);\n        intent.setPackage(null);\n        intent.setComponent(null);\n        // Get ComponentName if set\n        String pkgName;\n        if (intent.hasExtra(EXTRA_PACKAGE_NAME)) {\n            pkgName = intent.getStringExtra(EXTRA_PACKAGE_NAME);\n            intent.removeExtra(EXTRA_PACKAGE_NAME);\n            intent.setPackage(pkgName);\n            updateTitle(pkgName);\n        } else pkgName = null;\n        if (intent.hasExtra(EXTRA_CLASS_NAME)) {\n            String className;\n            className = intent.getStringExtra(EXTRA_CLASS_NAME);\n            intent.removeExtra(EXTRA_CLASS_NAME);\n            if (pkgName != null && className != null) {\n                mRequestedComponent = new ComponentName(pkgName, className);\n                intent.setComponent(mRequestedComponent);\n                updateSubtitle(mRequestedComponent);\n            }\n        }\n        String action = intent.getStringExtra(EXTRA_ACTION);\n        if (action != null) {\n            intent.setAction(action);\n        }\n        // For shortcut/startup trigger: Need authorization to prevent abuse\n        if (intent.getBooleanExtra(EXTRA_TRIGGER_ON_START, false)\n                && AuthManager.getKey().equals(intent.getStringExtra(EXTRA_AUTH))) {\n            intent.removeExtra(EXTRA_TRIGGER_ON_START);\n            intent.removeExtra(EXTRA_AUTH);\n            // Trigger intent\n            launchIntent(intent, mRequestedComponent == null);\n            // Fall-through\n        }\n        // Whether the Intent was edited\n        final boolean isVisible = savedInstanceState != null && savedInstanceState.getBoolean(INTENT_EDITED);\n        init(intent, isVisible);\n    }\n\n    private void init(@NonNull Intent intent, boolean isEdited) {\n        // Store the Intent\n        storeOriginalIntent(intent);\n        // Load Intent data\n        showInitialIntent(isEdited);\n        // Save Intent data to history\n        if (mHistory != null && mRequestedComponent == null) {\n            mHistory.saveHistory();\n        }\n    }\n\n    private void storeOriginalIntent(@NonNull Intent intent) {\n        // Store original intent as URI string\n        mOriginalIntent = getUri(intent);\n        // Get a new intent from the URI\n        Intent copyIntent = cloneIntent(mOriginalIntent);\n        // Store extras that are not available in the URI\n        Bundle originalExtras = intent.getExtras();\n        if (copyIntent == null || originalExtras == null) {\n            return;\n        }\n        Bundle additionalExtrasBundle = new Bundle(originalExtras);\n        for (String key : originalExtras.keySet()) {\n            if (copyIntent.hasExtra(key)) {\n                additionalExtrasBundle.remove(key);\n            }\n        }\n        if (!additionalExtrasBundle.isEmpty()) {\n            mAdditionalExtras = additionalExtrasBundle;\n        }\n    }\n\n    /**\n     * Create a clone of the original Intent and display it for editing\n     */\n    private void showInitialIntent(boolean isVisible) {\n        // Copy a mutable version of the intent\n        mMutableIntent = cloneIntent(mOriginalIntent);\n        // Setup views\n        setupVariables();\n        // Setup watchers to watch and update changes\n        setupTextWatchers();\n        // Display intent data\n        showAllIntentData(null);\n        // Display reset button if the intent was modified\n        showResetIntentButton(isVisible);\n    }\n\n    /**\n     * @param textViewToIgnore The {@link TextView} which should not be updated.\n     */\n    private void showAllIntentData(@Nullable TextView textViewToIgnore) {\n        showTextViewIntentData(textViewToIgnore);\n        // Display categories\n        mCategoriesAdapter.setDefaultList(mMutableIntent != null ? mMutableIntent.getCategories() : null);\n        // Display flags\n        mFlagsAdapter.setDefaultList(getFlags());\n        // Display extras\n        mExtrasAdapter.setDefaultList(getExtras());\n        refreshUI();\n    }\n\n    private void updateTitle(@Nullable String packageName) {\n        ActionBar actionBar = getSupportActionBar();\n        if (actionBar != null) {\n            if (packageName != null) {\n                CharSequence label = mPackageLabelMap.get(packageName);\n                if (label != null) {\n                    actionBar.setTitle(label);\n                } else {\n                    // Need to load the label\n                    ThreadUtils.postOnBackgroundThread(() -> {\n                        CharSequence appLabel = PackageUtils.getPackageLabel(getPackageManager(), packageName, mUserHandle);\n                        ThreadUtils.postOnMainThread(() -> {\n                            if (packageName.equals(appLabel.toString())) {\n                                // Ignore labels named after their package names\n                                actionBar.setTitle(R.string.interceptor);\n                                return;\n                            }\n                            actionBar.setTitle(appLabel);\n                            mPackageLabelMap.put(packageName, appLabel);\n                        });\n                    });\n                }\n            } else actionBar.setTitle(R.string.interceptor);\n        }\n    }\n\n    private void updateSubtitle(@Nullable ComponentName cn) {\n        ActionBar actionBar = getSupportActionBar();\n        if (actionBar != null) {\n            if (cn == null) {\n                actionBar.setSubtitle(null);\n                return;\n            }\n            PackageManager pm = getPackageManager();\n            try {\n                // Load label for the given user\n                ActivityInfo info = pm.getActivityInfo(cn, 0);\n                actionBar.setSubtitle(info.loadLabel(pm));\n            } catch (PackageManager.NameNotFoundException e) {\n                actionBar.setSubtitle(cn.getClassName());\n            }\n        }\n    }\n\n    @NonNull\n    private SimpleArrayMap<String, Object> getExtras() {\n        Bundle intentBundle;\n        if (mMutableIntent == null || (intentBundle = mMutableIntent.getExtras()) == null) {\n            return new SimpleArrayMap<>(0);\n        }\n        SimpleArrayMap<String, Object> extras = new SimpleArrayMap<>();\n        for (String extraKey : intentBundle.keySet()) {\n            Object extraValue = intentBundle.get(extraKey);\n            if (extraValue == null) continue;\n            extras.put(extraKey, extraValue);\n        }\n        return extras;\n    }\n\n    /**\n     * @param textViewToIgnore The {@link TextView} which should not be updated.\n     */\n    private void showTextViewIntentData(@Nullable TextView textViewToIgnore) {\n        if (mMutableIntent == null) return;\n        // Disable text watchers temporarily to prevent triggering modifications\n        mAreTextWatchersActive = false;\n        try {\n            if (textViewToIgnore != mActionView) {\n                mActionView.setText(mMutableIntent.getAction());\n            }\n            if (textViewToIgnore != mDataView && mMutableIntent.getDataString() != null) {\n                mDataView.setText(mMutableIntent.getDataString());\n            }\n            if (textViewToIgnore != mTypeView) {\n                mTypeView.setText(mMutableIntent.getType());\n            }\n            if (textViewToIgnore != mPackageNameView) {\n                mPackageNameView.setText(mMutableIntent.getPackage());\n            }\n            if (textViewToIgnore != mClassNameView) {\n                ComponentName cn = mMutableIntent.getComponent();\n                mClassNameView.setText(cn != null ? cn.getClassName() : null);\n            }\n            if (textViewToIgnore != mUriView) {\n                mUriView.setText(getUri(mMutableIntent));\n            }\n            if (textViewToIgnore != mIdView) {\n                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {\n                    mIdView.setText(mMutableIntent.getIdentifier());\n                }\n            }\n        } finally {\n            mAreTextWatchersActive = true;\n        }\n    }\n\n    @NonNull\n    private List<String> getFlags() {\n        if (mMutableIntent == null) {\n            return Collections.emptyList();\n        }\n        int flags = mMutableIntent.getFlags();\n        ArrayList<String> flagsStrings = new ArrayList<>();\n        for (int i = 0; i < INTENT_FLAG_TO_STRING.size(); ++i) {\n            if ((flags & INTENT_FLAG_TO_STRING.keyAt(i)) != 0) {\n                flagsStrings.add(INTENT_FLAG_TO_STRING.valueAt(i));\n            }\n        }\n        return flagsStrings;\n    }\n\n    private void checkAndShowMatchingActivities() {\n        if (mMutableIntent == null) return;\n        List<ResolveInfo> resolveInfo = getMatchingActivities();\n        if (resolveInfo.isEmpty()) {\n            mResendIntentButton.setEnabled(false);\n            mActivitiesHeader.setVisibility(View.GONE);\n        } else {\n            mResendIntentButton.setEnabled(true);\n            mActivitiesHeader.setVisibility(View.VISIBLE);\n        }\n        mActivitiesHeader.setText(getString(R.string.matching_activities));\n        mMatchingActivitiesAdapter.setDefaultList(resolveInfo);\n    }\n\n    @NonNull\n    private List<ResolveInfo> getMatchingActivities() {\n        if (mMutableIntent == null) {\n            return Collections.emptyList();\n        }\n        if (mUseRoot || SelfPermissions.checkCrossUserPermission(mUserHandle, false)) {\n            try {\n                return PackageManagerCompat.queryIntentActivities(this, mMutableIntent, PackageManager.MATCH_ALL, mUserHandle);\n            } catch (RemoteException e) {\n                e.printStackTrace();\n            }\n        }\n        return getPackageManager().queryIntentActivities(mMutableIntent, 0);\n    }\n\n    private void setupVariables() {\n        mActionView = findViewById(R.id.action_edit);\n        mDataView = findViewById(R.id.data_edit);\n        mTypeView = findViewById(R.id.type_edit);\n        mUriView = findViewById(R.id.uri_edit);\n        mPackageNameView = findViewById(R.id.package_edit);\n        mClassNameView = findViewById(R.id.class_edit);\n        mIdView = findViewById(R.id.type_id);\n\n        mHistory = new HistoryEditText(this, mActionView, mDataView, mTypeView, mUriView, mPackageNameView, mClassNameView);\n\n        // Setup user ID edit\n        mUserIdEdit = findViewById(R.id.user_id_edit);\n        mUserIdEdit.setText(String.valueOf(mUserHandle));\n        mUserIdEdit.setEnabled(SelfPermissions.checkSelfOrRemotePermission(ManifestCompat.permission.INTERACT_ACROSS_USERS)\n                || SelfPermissions.checkSelfOrRemotePermission(ManifestCompat.permission.INTERACT_ACROSS_USERS_FULL));\n        // Setup root\n        MaterialCheckBox useRootCheckBox = findViewById(R.id.use_root);\n        useRootCheckBox.setChecked(mUseRoot);\n        useRootCheckBox.setVisibility(Ops.isWorkingUidRoot() ? View.VISIBLE : View.GONE);\n        useRootCheckBox.setOnCheckedChangeListener((buttonView, isChecked) -> {\n            if (mUseRoot != isChecked) {\n                mUseRoot = isChecked;\n                refreshUI();\n            }\n        });\n        // Setup identifier\n        TextInputLayout idLayout = findViewById(R.id.type_id_layout);\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {\n            idLayout.setEndIconOnClickListener(v -> {\n                mIdView.setText(UUID.randomUUID().toString());\n                mIdView.requestFocus();\n            });\n        } else idLayout.setVisibility(View.GONE);\n\n        // Setup categories\n        MaterialButton addCategoriesButton = findViewById(R.id.intent_categories_add_btn);\n        addCategoriesButton.setOnClickListener(v -> {\n            UiUtils.fixFocus(addCategoriesButton);\n            new TextInputDropdownDialogBuilder(this, R.string.category)\n                    .setTitle(R.string.category)\n                    .setDropdownItems(INTENT_CATEGORIES, -1, true)\n                    .setNegativeButton(R.string.cancel, null)\n                    .setPositiveButton(R.string.ok, (dialog, which, inputText, isChecked) -> {\n                        if (!TextUtils.isEmpty(inputText)) {\n                            //noinspection ConstantConditions\n                            mMutableIntent.addCategory(inputText.toString().trim());\n                            mCategoriesAdapter.setDefaultList(mMutableIntent.getCategories());\n                            showTextViewIntentData(null);\n                            showResetIntentButton(true);\n                        }\n                    })\n                    .show();\n        });\n        RecyclerView categoriesRecyclerView = findViewById(R.id.intent_categories);\n        categoriesRecyclerView.setLayoutManager(UIUtils.getGridLayoutAt450Dp(this));\n        mCategoriesAdapter = new CategoriesRecyclerViewAdapter(this);\n        categoriesRecyclerView.setAdapter(mCategoriesAdapter);\n\n        // Setup flags\n        MaterialButton addFlagsButton = findViewById(R.id.intent_flags_add_btn);\n        addFlagsButton.setOnClickListener(v -> {\n            UiUtils.fixFocus(addFlagsButton);\n            new TextInputDropdownDialogBuilder(this, R.string.flags)\n                    .setTitle(R.string.flags)\n                    .setDropdownItems(getAllFlags(), -1, true)\n                    .setNegativeButton(R.string.cancel, null)\n                    .setPositiveButton(R.string.ok, (dialog, which, inputText, isChecked) -> {\n                        if (!TextUtils.isEmpty(inputText) && mMutableIntent != null) {\n                            int i = getFlagIndex(String.valueOf(inputText).trim());\n                            if (i >= 0) {\n                                mMutableIntent.addFlags(INTENT_FLAG_TO_STRING.keyAt(i));\n                            } else {\n                                try {\n                                    int flag = IntegerCompat.decode(String.valueOf(inputText).trim());\n                                    mMutableIntent.addFlags(flag);\n                                } catch (NumberFormatException e) {\n                                    return;\n                                }\n                            }\n                            mFlagsAdapter.setDefaultList(getFlags());\n                            showTextViewIntentData(null);\n                            showResetIntentButton(true);\n                        }\n                    })\n                    .show();\n        });\n        RecyclerView flagsRecyclerView = findViewById(R.id.intent_flags);\n        flagsRecyclerView.setLayoutManager(UIUtils.getGridLayoutAt450Dp(this));\n        mFlagsAdapter = new FlagsRecyclerViewAdapter(this);\n        flagsRecyclerView.setAdapter(mFlagsAdapter);\n\n        // Setup extras\n        MaterialButton addExtrasButton = findViewById(R.id.intent_extras_add_btn);\n        addExtrasButton.setOnClickListener(v -> {\n            UiUtils.fixFocus(addExtrasButton);\n            AddIntentExtraFragment fragment = new AddIntentExtraFragment();\n            fragment.setOnSaveListener((mode, prefItem) -> {\n                if (mMutableIntent != null) {\n                    IntentCompat.addToIntent(mMutableIntent, prefItem);\n                    mExtrasAdapter.setDefaultList(getExtras());\n                    showResetIntentButton(true);\n                }\n            });\n            Bundle args = new Bundle();\n            args.putInt(AddIntentExtraFragment.ARG_MODE, AddIntentExtraFragment.MODE_CREATE);\n            fragment.setArguments(args);\n            fragment.show(getSupportFragmentManager(), AddIntentExtraFragment.TAG);\n        });\n        RecyclerView extrasRecyclerView = findViewById(R.id.intent_extras);\n        extrasRecyclerView.setLayoutManager(UIUtils.getGridLayoutAt450Dp(this));\n        mExtrasAdapter = new ExtrasRecyclerViewAdapter(this);\n        extrasRecyclerView.setAdapter(mExtrasAdapter);\n\n        // Setup matching activities\n        mActivitiesHeader = findViewById(R.id.intent_matching_activities_header);\n        if (mRequestedComponent != null) {\n            // Hide matching activities since specific component requested\n            mActivitiesHeader.setVisibility(View.GONE);\n        }\n        RecyclerView matchingActivitiesRecyclerView = findViewById(R.id.intent_matching_activities);\n        matchingActivitiesRecyclerView.setLayoutManager(UIUtils.getGridLayoutAt450Dp(this));\n        mMatchingActivitiesAdapter = new MatchingActivitiesRecyclerViewAdapter(this);\n        matchingActivitiesRecyclerView.setAdapter(mMatchingActivitiesAdapter);\n\n        mResendIntentButton = findViewById(R.id.resend_intent_button);\n        mResetIntentButton = findViewById(R.id.reset_intent_button);\n\n        // Send Intent on clicking the resend intent button\n        mResendIntentButton.setOnClickListener(v -> {\n            UiUtils.fixFocus(mResendIntentButton);\n            if (mMutableIntent == null) return;\n            launchIntent(mMutableIntent, mRequestedComponent == null);\n        });\n        // Reset Intent data on clicking the reset intent button\n        mResetIntentButton.setOnClickListener(v -> {\n            UiUtils.fixFocus(mResetIntentButton);\n            mAreTextWatchersActive = false;\n            showInitialIntent(false);\n            mAreTextWatchersActive = true;\n            refreshUI();\n        });\n    }\n\n    private void setupTextWatchers() {\n        mActionView.addTextChangedListener(new IntentUpdateTextWatcher(mActionView) {\n            @Override\n            protected void onUpdateIntent(String modifiedContent) {\n                if (mMutableIntent != null) {\n                    mMutableIntent.setAction(modifiedContent);\n                }\n            }\n        });\n        mDataView.addTextChangedListener(new IntentUpdateTextWatcher(mDataView) {\n            @Override\n            protected void onUpdateIntent(String modifiedContent) {\n                if (mMutableIntent != null) {\n                    // setDataAndType clears type so we save it\n                    String savedType = mMutableIntent.getType();\n                    mMutableIntent.setDataAndType(Uri.parse(modifiedContent), savedType);\n                }\n            }\n        });\n        mTypeView.addTextChangedListener(new IntentUpdateTextWatcher(mTypeView) {\n            @Override\n            protected void onUpdateIntent(String modifiedContent) {\n                if (mMutableIntent != null) {\n                    // setDataAndType clears data so we save it\n                    String dataString = mMutableIntent.getDataString();\n                    mMutableIntent.setDataAndType(Uri.parse(dataString), modifiedContent);\n                }\n            }\n        });\n        mPackageNameView.addTextChangedListener(new IntentUpdateTextWatcher(mPackageNameView) {\n            @Override\n            protected void onUpdateIntent(String modifiedContent) {\n                if (mMutableIntent != null) {\n                    mMutableIntent.setPackage(TextUtils.isEmpty(modifiedContent) ? null : modifiedContent);\n                }\n            }\n        });\n        mClassNameView.addTextChangedListener(new IntentUpdateTextWatcher(mClassNameView) {\n            @Override\n            protected void onUpdateIntent(String modifiedComponent) {\n                if (mMutableIntent == null) return;\n                if (TextUtils.isEmpty(modifiedComponent)) {\n                    mRequestedComponent = null;\n                    mMutableIntent.setComponent(null);\n                    return;\n                }\n                String packageName = mMutableIntent.getPackage();\n                if (packageName == null) {\n                    UIUtils.displayShortToast(R.string.set_package_name_first);\n                    mAreTextWatchersActive = false;\n                    mClassNameView.setText(null);\n                    mAreTextWatchersActive = true;\n                    return;\n                }\n                mRequestedComponent = new ComponentName(packageName, (modifiedComponent.startsWith(\".\") ?\n                        packageName : \"\") + modifiedComponent);\n                mMutableIntent.setComponent(mRequestedComponent);\n            }\n        });\n        mUriView.addTextChangedListener(new IntentUpdateTextWatcher(mUriView) {\n            @Override\n            protected void onUpdateIntent(String modifiedContent) {\n                // no error yet so continue\n                mMutableIntent = cloneIntent(modifiedContent);\n                // this time must update all content since extras/flags may have been changed\n                showAllIntentData(mUriView);\n            }\n        });\n        mIdView.addTextChangedListener(new IntentUpdateTextWatcher(mIdView) {\n            @Override\n            protected void onUpdateIntent(String modifiedContent) {\n                if (mMutableIntent != null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {\n                    mMutableIntent.setIdentifier(modifiedContent);\n                }\n            }\n        });\n        mUserIdEdit.addTextChangedListener(new TextWatcher() {\n            @Override\n            public void beforeTextChanged(CharSequence s, int start, int count, int after) {\n            }\n\n            @Override\n            public void onTextChanged(CharSequence s, int start, int before, int count) {\n                if (s == null) return;\n                try {\n                    mUserHandle = Integer.decode(s.toString());\n                    refreshUI();\n                } catch (NumberFormatException ignore) {\n                }\n            }\n\n            @Override\n            public void afterTextChanged(Editable s) {\n            }\n        });\n    }\n\n    private void showResetIntentButton(boolean visible) {\n        mResendIntentButton.setText(R.string.send_edited_intent);\n        mResetIntentButton.setVisibility((visible) ? View.VISIBLE : View.GONE);\n    }\n\n    private void copyIntentDetails() {\n        Utils.copyToClipboard(this, \"Intent Details\", getIntentDetailsString());\n    }\n\n    private void copyIntentAsCommand() {\n        if (mMutableIntent == null) {\n            return;\n        }\n        List<String> args = IntentCompat.flattenToCommand(mMutableIntent);\n        String command = String.format(Locale.ROOT, \"%s start --user %d %s\", RunnerUtils.CMD_AM, mUserHandle,\n                TextUtils.join(\" \", args));\n        Utils.copyToClipboard(this, \"am command\", command);\n    }\n\n    private void pasteIntentDetails() {\n        CharSequence clipData = ClipboardUtils.readClipboard(this);\n        if (clipData == null) return;\n        String text = clipData.toString();\n        // Get ROOT <bool> and USER <id> since they aren't part of IntentCompat.unflattenFromString()\n        String[] lines = text.split(\"\\n\");\n        mUseRoot = false;\n        mUserHandle = UserHandleHidden.myUserId();\n        int parseCount = 0;\n        for (String line : lines) {\n            if (TextUtils.isEmpty(line)) continue;\n            StringTokenizer tokenizer = new StringTokenizer(line, \"\\t\");\n            switch (tokenizer.nextToken()) {\n                case \"ROOT\":\n                    mUseRoot = Ops.isWorkingUidRoot() && Boolean.parseBoolean(tokenizer.nextToken());\n                    ++parseCount;\n                    break;\n                case \"USER\":\n                    int userId = Integer.decode(tokenizer.nextToken());\n                    if (SelfPermissions.checkCrossUserPermission(userId, false)) {\n                        mUserHandle = userId;\n                    }\n                    ++parseCount;\n                    break;\n            }\n            if (parseCount == 2) {\n                // Got both ROOT and USER, no need to continue the loop\n                break;\n            }\n        }\n        // Rebuild Intent\n        Intent intent = IntentCompat.unflattenFromString(text);\n        if (intent != null) {\n            // Requested component set to NULL in case it was set previously\n            mRequestedComponent = null;\n            init(intent, false);\n        }\n    }\n\n    private void refreshUI() {\n        if (mMutableIntent == null) return;\n        if (mRequestedComponent == null) {\n            // Since no explicit component requested, display matching activities\n            checkAndShowMatchingActivities();\n        } else {\n            // Hide matching activities since specific component requested\n            mActivitiesHeader.setVisibility(View.GONE);\n            mResendIntentButton.setEnabled(true);\n        }\n        updateTitle(mMutableIntent.getPackage());\n        updateSubtitle(mMutableIntent.getComponent());\n    }\n\n    @NonNull\n    private Intent createShareIntent() {\n        Intent share = new Intent(Intent.ACTION_SEND);\n        share.setType(\"text/plain\");\n        share.putExtra(Intent.EXTRA_TEXT, getIntentDetailsString());\n        return share;\n    }\n\n    @NonNull\n    private String getIntentDetailsString() {\n        if (mMutableIntent == null) {\n            return \"\";\n        }\n        PackageManager pm = getPackageManager();\n        List<ResolveInfo> resolveInfo = getMatchingActivities();\n        int numberOfMatchingActivities = resolveInfo.size();\n\n        StringBuilder result = new StringBuilder();\n        // NOTE: At least 1 tab have to be present in each non-empty line. Empty lines are ignored.\n        // URI <URI> (unused)\n        result.append(\"URI\\t\").append(getUri(mMutableIntent)).append(\"\\n\");\n        // ROOT <bool>\n        if (mUseRoot) result.append(\"ROOT\\t\").append(mUseRoot).append(\"\\n\");\n        // USER <id>\n        if (mUserHandle != UserHandleHidden.myUserId()) {\n            result.append(\"USER\\t\").append(mUserHandle).append(\"\\n\");\n        }\n        result.append(\"\\n\");\n        // Convert the Intent to parsable string\n        result.append(IntentCompat.flattenToString(mMutableIntent)).append(\"\\n\");\n        // MATCHING ACTIVITIES <match-count>\n        result.append(\"MATCHING ACTIVITIES\\t\").append(numberOfMatchingActivities).append(\"\\n\");\n        // Calculate the number of spaces needed in order to align activity items properly\n        int spaceCount = String.valueOf(numberOfMatchingActivities).length();\n        StringBuilder spaces = new StringBuilder();\n        while ((spaceCount--) != 0) spaces.append(\" \");\n        for (int i = 0; i < numberOfMatchingActivities; ++i) {\n            ActivityInfo activityinfo = resolveInfo.get(i).activityInfo;\n            // Line 1: <no> LABEL   <activity-label>\n            // Line 2:      NAME    <activity-name>\n            // Line 3:      PACKAGE <package-name>\n            result.append(i).append(\"\\tLABEL  \\t\").append(activityinfo.loadLabel(pm)).append(\"\\n\");\n            result.append(spaces).append(\"\\tNAME   \\t\").append(activityinfo.name).append(\"\\n\");\n            result.append(spaces).append(\"\\tPACKAGE\\t\").append(activityinfo.packageName).append(\"\\n\");\n        }\n        // Add activity results\n        if (mLastResultCode != null) {\n            result.append(\"\\n\");\n            // ACTIVITY RESULT <result-code>\n            result.append(\"ACTIVITY RESULT\\t\").append(mLastResultCode).append(\"\\n\");\n            if (mLastResultIntent != null) {\n                // Print the last result intent with RESULT prefix so that it will not be parsed by the parser\n                result.append(IntentCompat.describeIntent(mLastResultIntent, \"RESULT\"));\n            }\n        }\n        return result.toString();\n    }\n\n    public void launchIntent(@NonNull Intent intent, boolean createChooser) {\n        boolean needPrivilege = mUseRoot || mUserHandle != UserHandleHidden.myUserId();\n        try {\n            if (createChooser) {\n                Intent chooserIntent = Intent.createChooser(intent, mResendIntentButton != null ?\n                        mResendIntentButton.getText() : getString(R.string.open));\n                if (needPrivilege) {\n                    // TODO: 4/2/22 Support sending activity result back to the original app\n                    ActivityManagerCompat.startActivity(chooserIntent, mUserHandle);\n                } else {\n                    mIntentLauncher.launch(chooserIntent);\n                }\n            } else { // Launch a fixed component\n                if (needPrivilege) {\n                    // TODO: 4/2/22 Support sending activity result back to the original app\n                    ActivityManagerCompat.startActivity(intent, mUserHandle);\n                } else {\n                    try {\n                        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);\n                        mIntentLauncher.launch(intent);\n                    } catch (SecurityException e) {\n                        // TODO: 4/6/24 Support sending activity result back to the original app\n                        ActivityManagerCompat.startActivity(intent, mUserHandle);\n                    }\n                }\n            }\n        } catch (Throwable th) {\n            Log.e(TAG, th);\n            UIUtils.displayLongToast(R.string.error_with_details, th.getClass().getName() + \": \" + th.getMessage());\n        }\n    }\n\n    @Override\n    public boolean onCreateOptionsMenu(Menu menu) {\n        getMenuInflater().inflate(R.menu.activity_activity_interceptor_actions, menu);\n        return super.onCreateOptionsMenu(menu);\n    }\n\n    @Override\n    public boolean onOptionsItemSelected(@NonNull MenuItem item) {\n        int id = item.getItemId();\n        if (id == android.R.id.home) {\n            finish();\n            return true;\n        } else if (id == R.id.action_copy_as_default) {\n            copyIntentDetails();\n            return true;\n        } else if (id == R.id.action_copy_as_command) {\n            copyIntentAsCommand();\n            return true;\n        } else if (id == R.id.action_paste) {\n            pasteIntentDetails();\n            return true;\n        } else if (id == R.id.action_shortcut) {\n            try {\n                ActionBar actionBar = getSupportActionBar();\n                CharSequence shortcutName = null;\n                if (actionBar != null) {\n                    shortcutName = actionBar.getSubtitle();\n                }\n                if (shortcutName == null) {\n                    shortcutName = Objects.requireNonNull(getTitle());\n                }\n                Drawable icon = Objects.requireNonNull(ContextCompat.getDrawable(this, R.drawable.ic_launcher_foreground));\n                Intent intent = new Intent(mMutableIntent);\n                // Add necessary extras\n                intent.putExtra(EXTRA_AUTH, AuthManager.getKey());\n                intent.putExtra(EXTRA_TRIGGER_ON_START, true);\n                intent.putExtra(EXTRA_ACTION, intent.getAction());\n                if (mUseRoot) {\n                    intent.putExtra(EXTRA_ROOT, true);\n                }\n                if (mUserHandle != UserHandleHidden.myUserId()) {\n                    intent.putExtra(EXTRA_USER_HANDLE, mUserHandle);\n                }\n                if (mRequestedComponent != null) {\n                    intent.putExtra(EXTRA_PACKAGE_NAME, mRequestedComponent.getPackageName());\n                    intent.putExtra(EXTRA_CLASS_NAME, mRequestedComponent.getClassName());\n                }\n                intent.setClass(getApplicationContext(), ActivityInterceptor.class);\n                InterceptorShortcutInfo shortcutInfo = new InterceptorShortcutInfo(intent);\n                shortcutInfo.setName(shortcutName);\n                shortcutInfo.setIcon(UIUtils.getBitmapFromDrawable(icon));\n                CreateShortcutDialogFragment dialog = CreateShortcutDialogFragment.getInstance(shortcutInfo);\n                dialog.show(getSupportFragmentManager(), CreateShortcutDialogFragment.TAG);\n            } catch (Throwable th) {\n                Log.e(TAG, th);\n                UIUtils.displayLongToast(R.string.error_with_details, th.getClass().getName() + \": \" + th.getMessage());\n            }\n            return true;\n        }\n        return super.onOptionsItemSelected(item);\n    }\n\n    @Override\n    protected void onPause() {\n        super.onPause();\n        mAreTextWatchersActive = false;\n    }\n\n    @Override\n    protected void onResume() {\n        super.onResume();\n        // Inhibit new activity animation when resetting intent details\n        overridePendingTransition(0, 0);\n        mAreTextWatchersActive = true;\n    }\n\n    @Override\n    protected void onSaveInstanceState(@NonNull Bundle outState) {\n        super.onSaveInstanceState(outState);\n        if (mResetIntentButton != null) {\n            outState.putBoolean(INTENT_EDITED, mResetIntentButton.getVisibility() == View.VISIBLE);\n        }\n        if (mHistory != null) {\n            mHistory.saveHistory();\n        }\n    }\n\n    @Nullable\n    private static String getUri(@Nullable Intent src) {\n        try {\n            return (src != null) ? IntentCompat.toUri(src, Intent.URI_INTENT_SCHEME) : null;\n        } catch (BadParcelableException e) {\n            // TODO: 4/2/22 Add support for invalid classes. This could be done in the following way:\n            //  1. Upon detecting a BPE (and the class name), ask the user to select the source application\n            //  2. Load the source application via the DexClassLoader\n            //  3. Use Class.forName() to load the class and it's class loader to recognize the Parcelable\n            //  The other option is to skip the problematic classes.\n            e.printStackTrace();\n            return null;\n        }\n    }\n\n    @Nullable\n    private Intent cloneIntent(@Nullable String intentUri) {\n        if (intentUri == null) return null;\n        try {\n            Intent clone;\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) {\n                clone = Intent.parseUri(intentUri, Intent.URI_INTENT_SCHEME | Intent.URI_ANDROID_APP_SCHEME\n                        | Intent.URI_ALLOW_UNSAFE);\n            } else clone = Intent.parseUri(intentUri, Intent.URI_INTENT_SCHEME);\n            // Restore extras that are lost in the intent to string conversion\n            if (mAdditionalExtras != null) {\n                clone.putExtras(mAdditionalExtras);\n            }\n            return clone;\n        } catch (URISyntaxException e) {\n            e.printStackTrace();\n        }\n        return null;\n    }\n\n    @NonNull\n    private List<String> getAllFlags() {\n        List<String> allFlags = new ArrayList<>();\n        for (int i = 0; i < INTENT_FLAG_TO_STRING.size(); ++i) {\n            allFlags.add(INTENT_FLAG_TO_STRING.valueAt(i));\n        }\n        return allFlags;\n    }\n\n    private int getFlagIndex(String flagStr) {\n        for (int i = 0; i < INTENT_FLAG_TO_STRING.size(); ++i) {\n            if (INTENT_FLAG_TO_STRING.valueAt(i).equals(flagStr)) return i;\n        }\n        return -1;\n    }\n\n    private static class CategoriesRecyclerViewAdapter extends RecyclerView.Adapter<CategoriesRecyclerViewAdapter.ViewHolder> {\n        private final List<String> mCategories = new ArrayList<>();\n        private final ActivityInterceptor mActivity;\n\n        public CategoriesRecyclerViewAdapter(ActivityInterceptor activity) {\n            mActivity = activity;\n        }\n\n        public void setDefaultList(@Nullable Collection<String> categories) {\n            AdapterUtils.notifyDataSetChanged(this, mCategories, categories != null ? new ArrayList<>(categories) : null);\n        }\n\n        @NonNull\n        @Override\n        public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {\n            View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_title_action, parent, false);\n            return new ViewHolder(view);\n        }\n\n        @Override\n        public void onBindViewHolder(@NonNull ViewHolder holder, int position) {\n            String category = mCategories.get(position);\n            holder.title.setText(category);\n            holder.title.setTextIsSelectable(true);\n            holder.actionIcon.setOnClickListener(v -> {\n                UiUtils.fixFocus(holder.actionIcon);\n                if (mActivity.mMutableIntent != null) {\n                    mActivity.mMutableIntent.removeCategory(category);\n                    setDefaultList(mActivity.mMutableIntent.getCategories());\n                    mActivity.showTextViewIntentData(null);\n                    mActivity.showResetIntentButton(true);\n                }\n            });\n        }\n\n        @Override\n        public int getItemCount() {\n            return mCategories.size();\n        }\n\n        static class ViewHolder extends RecyclerView.ViewHolder {\n            TextView title;\n            MaterialButton actionIcon;\n\n            public ViewHolder(@NonNull View itemView) {\n                super(itemView);\n                title = itemView.findViewById(R.id.item_title);\n                actionIcon = itemView.findViewById(R.id.item_action);\n                actionIcon.setContentDescription(itemView.getContext().getString(R.string.item_remove));\n            }\n        }\n    }\n\n    private static class FlagsRecyclerViewAdapter extends RecyclerView.Adapter<FlagsRecyclerViewAdapter.ViewHolder> {\n        private final List<String> mFlags = new ArrayList<>();\n        private final ActivityInterceptor mActivity;\n\n        public FlagsRecyclerViewAdapter(ActivityInterceptor activity) {\n            mActivity = activity;\n        }\n\n        public void setDefaultList(@Nullable List<String> flags) {\n            AdapterUtils.notifyDataSetChanged(this, mFlags, flags);\n        }\n\n        @NonNull\n        @Override\n        public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {\n            View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_title_action, parent, false);\n            return new ViewHolder(view);\n        }\n\n        @Override\n        public void onBindViewHolder(@NonNull ViewHolder holder, int position) {\n            String flagName = mFlags.get(position);\n            holder.title.setText(flagName);\n            holder.title.setTextIsSelectable(true);\n            holder.actionIcon.setOnClickListener(v -> {\n                UiUtils.fixFocus(holder.actionIcon);\n                int i = INTENT_FLAG_TO_STRING.indexOfValue(flagName);\n                if (i >= 0 && mActivity.mMutableIntent != null) {\n                    IntentCompat.removeFlags(mActivity.mMutableIntent, INTENT_FLAG_TO_STRING.keyAt(i));\n                    setDefaultList(mActivity.getFlags());\n                    mActivity.showTextViewIntentData(null);\n                    mActivity.showResetIntentButton(true);\n                }\n            });\n        }\n\n        @Override\n        public int getItemCount() {\n            return mFlags.size();\n        }\n\n        static class ViewHolder extends RecyclerView.ViewHolder {\n            TextView title;\n            MaterialButton actionIcon;\n\n            public ViewHolder(@NonNull View itemView) {\n                super(itemView);\n                title = itemView.findViewById(R.id.item_title);\n                actionIcon = itemView.findViewById(R.id.item_action);\n                actionIcon.setContentDescription(itemView.getContext().getString(R.string.item_remove));\n            }\n        }\n    }\n\n    private static class ExtrasRecyclerViewAdapter extends RecyclerView.Adapter<ExtrasRecyclerViewAdapter.ViewHolder> {\n        private final SimpleArrayMap<String, Object> mExtras = new SimpleArrayMap<>(0);\n        private final ActivityInterceptor mActivity;\n\n        public ExtrasRecyclerViewAdapter(ActivityInterceptor activity) {\n            mActivity = activity;\n        }\n\n        public void setDefaultList(@Nullable SimpleArrayMap<String, Object> extras) {\n            AdapterUtils.notifyDataSetChanged(this, mExtras, extras);\n        }\n\n        @NonNull\n        @Override\n        public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {\n            View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_icon_title_subtitle, parent, false);\n            return new ViewHolder(view);\n        }\n\n        @Override\n        public void onBindViewHolder(@NonNull ViewHolder holder, int position) {\n            String key = mExtras.keyAt(position);\n            Object value = mExtras.valueAt(position);\n            holder.title.setText(key);\n            holder.title.setTextIsSelectable(true);\n            holder.subtitle.setText(value.toString());\n            holder.subtitle.setTextIsSelectable(true);\n            holder.actionIcon.setOnClickListener(v -> {\n                UiUtils.fixFocus(holder.actionIcon);\n                if (mActivity.mMutableIntent != null) {\n                    mActivity.mMutableIntent.removeExtra(key);\n                    mActivity.showTextViewIntentData(null);\n                    int pos = mExtras.indexOfKey(key);\n                    if (pos >= 0) {\n                        mExtras.removeAt(pos);\n                        notifyItemRemoved(pos);\n                    }\n                    mActivity.showResetIntentButton(true);\n                }\n            });\n        }\n\n        @Override\n        public int getItemCount() {\n            return mExtras.size();\n        }\n\n        static class ViewHolder extends RecyclerView.ViewHolder {\n            TextView title;\n            TextView subtitle;\n            ImageView icon;\n            MaterialButton actionIcon;\n\n            public ViewHolder(@NonNull View itemView) {\n                super(itemView);\n                title = itemView.findViewById(R.id.item_title);\n                subtitle = itemView.findViewById(R.id.item_subtitle);\n                actionIcon = itemView.findViewById(R.id.item_open);\n                actionIcon.setIconResource(R.drawable.ic_trash_can);\n                actionIcon.setContentDescription(itemView.getContext().getString(R.string.item_remove));\n                icon = itemView.findViewById(R.id.item_icon);\n                icon.setVisibility(View.GONE);\n            }\n        }\n    }\n\n    private static class MatchingActivitiesRecyclerViewAdapter extends RecyclerView.Adapter<MatchingActivitiesRecyclerViewAdapter.ViewHolder> {\n        private final List<ResolveInfo> mMatchingActivities = new ArrayList<>();\n        private final PackageManager mPm;\n        private final ActivityInterceptor mActivity;\n\n        public MatchingActivitiesRecyclerViewAdapter(ActivityInterceptor activity) {\n            mActivity = activity;\n            mPm = activity.getPackageManager();\n        }\n\n        public void setDefaultList(@Nullable List<ResolveInfo> matchingActivities) {\n            AdapterUtils.notifyDataSetChanged(this, mMatchingActivities, matchingActivities);\n        }\n\n        @NonNull\n        @Override\n        public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {\n            View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_icon_title_subtitle, parent, false);\n            return new ViewHolder(view);\n        }\n\n        @Override\n        public void onBindViewHolder(@NonNull ViewHolder holder, int position) {\n            ResolveInfo resolveInfo = mMatchingActivities.get(position);\n            ActivityInfo info = resolveInfo.activityInfo;\n            holder.title.setText(info.loadLabel(mPm));\n            String activityName = info.name;\n            String name = info.packageName + \"\\n\" + activityName;\n            holder.subtitle.setText(name);\n            holder.subtitle.setTextIsSelectable(true);\n            String tag = info.packageName + \"_\" + activityName;\n            holder.icon.setTag(tag);\n            ImageLoader.getInstance().displayImage(tag, info, holder.icon);\n            holder.actionIcon.setOnClickListener(v -> {\n                UiUtils.fixFocus(holder.actionIcon);\n                Intent intent = new Intent(mActivity.mMutableIntent);\n                intent.setClassName(info.packageName, activityName);\n                IntentCompat.removeFlags(intent, Intent.FLAG_ACTIVITY_FORWARD_RESULT);\n                mActivity.launchIntent(intent, false);\n            });\n        }\n\n        @Override\n        public int getItemCount() {\n            return mMatchingActivities.size();\n        }\n\n        static class ViewHolder extends RecyclerView.ViewHolder {\n            TextView title;\n            TextView subtitle;\n            ImageView icon;\n            MaterialButton actionIcon;\n\n            public ViewHolder(@NonNull View itemView) {\n                super(itemView);\n                title = itemView.findViewById(R.id.item_title);\n                subtitle = itemView.findViewById(R.id.item_subtitle);\n                actionIcon = itemView.findViewById(R.id.item_open);\n                actionIcon.setContentDescription(itemView.getContext().getString(R.string.open));\n                icon = itemView.findViewById(R.id.item_icon);\n            }\n        }\n    }\n}"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/intercept/AddIntentExtraFragment.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.intercept;\n\nimport static io.github.muntashirakon.AppManager.intercept.IntentCompat.parseExtraValue;\n\nimport android.app.Dialog;\nimport android.os.Bundle;\nimport android.text.TextUtils;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.ArrayAdapter;\nimport android.widget.TextView;\n\nimport androidx.annotation.IntDef;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.fragment.app.DialogFragment;\nimport androidx.fragment.app.FragmentActivity;\n\nimport com.google.android.material.dialog.MaterialAlertDialogBuilder;\nimport com.google.android.material.materialswitch.MaterialSwitch;\nimport com.google.android.material.textfield.TextInputEditText;\nimport com.google.android.material.textfield.TextInputLayout;\n\nimport java.io.Serializable;\n\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.utils.UIUtils;\nimport io.github.muntashirakon.adapters.SelectedArrayAdapter;\nimport io.github.muntashirakon.widget.MaterialSpinner;\n\npublic class AddIntentExtraFragment extends DialogFragment {\n    public static final String TAG = \"AddIntentExtraFragment\";\n    public static final String ARG_PREF_ITEM = \"ARG_PREF_ITEM\";\n    public static final String ARG_MODE = \"ARG_MODE\";\n\n    @IntDef(value = {\n            MODE_EDIT,\n            MODE_CREATE,\n            MODE_DELETE\n    })\n    public @interface Mode {\n    }\n\n    public static final int MODE_EDIT = 1;  // Key name is disabled\n    public static final int MODE_CREATE = 2;  // Key name is not disabled\n    public static final int MODE_DELETE = 3;\n\n    @IntDef(value = {\n            TYPE_BOOLEAN,\n            TYPE_COMPONENT_NAME,\n            TYPE_FLOAT,\n            TYPE_FLOAT_ARR,\n            TYPE_FLOAT_AL,\n            TYPE_INTEGER,\n            TYPE_INT_ARR,\n            TYPE_INT_AL,\n            TYPE_LONG,\n            TYPE_LONG_ARR,\n            TYPE_LONG_AL,\n            TYPE_NULL,\n            TYPE_STRING,\n            TYPE_STRING_ARR,\n            TYPE_STRING_AL,\n            TYPE_URI,\n            TYPE_URI_ARR,\n            TYPE_URI_AL,\n    })\n    public @interface Type {\n    }\n\n    public static final int TYPE_BOOLEAN = 0;\n    public static final int TYPE_COMPONENT_NAME = 1;\n    public static final int TYPE_FLOAT = 2;\n    public static final int TYPE_FLOAT_ARR = 3;\n    public static final int TYPE_FLOAT_AL = 4;\n    public static final int TYPE_INTEGER = 5;\n    public static final int TYPE_INT_ARR = 6;\n    public static final int TYPE_INT_AL = 7;\n    public static final int TYPE_LONG = 8;\n    public static final int TYPE_LONG_ARR = 9;\n    public static final int TYPE_LONG_AL = 10;\n    public static final int TYPE_NULL = 11;\n    public static final int TYPE_STRING = 12;\n    public static final int TYPE_STRING_ARR = 13;\n    public static final int TYPE_STRING_AL = 14;\n    public static final int TYPE_URI = 15;\n    public static final int TYPE_URI_ARR = 16;\n    public static final int TYPE_URI_AL = 17;\n\n    private static final int TYPE_COUNT = 18;\n\n    @Nullable\n    private OnSaveListener mOnSaveListener;\n\n    public interface OnSaveListener {\n        void onSave(@Mode int mode, ExtraItem extraItem);\n    }\n\n    public static class ExtraItem implements Serializable {\n        private static final long serialVersionUID = 4815162342L;\n\n        @Type\n        public int type;\n        public String keyName;\n        @Nullable\n        public Object keyValue;\n\n        public ExtraItem() {\n        }\n\n        @Override\n        @NonNull\n        public String toString() {\n            return \"PrefItem{\" +\n                    \"type=\" + type +\n                    \", keyName='\" + keyName + '\\'' +\n                    \", keyValue=\" + keyValue +\n                    '}';\n        }\n    }\n\n    private final ViewGroup[] mLayoutTypes = new ViewGroup[TYPE_COUNT];\n    private final TextView[] mValues = new TextView[TYPE_COUNT];\n    @Type\n    private int mCurrentType;\n\n    public void setOnSaveListener(@Nullable OnSaveListener onSaveListener) {\n        mOnSaveListener = onSaveListener;\n    }\n\n    @NonNull\n    @Override\n    public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {\n        FragmentActivity activity = requireActivity();\n        Bundle args = requireArguments();\n        ExtraItem extraItem = (ExtraItem) args.getSerializable(ARG_PREF_ITEM);\n        @Mode int mode = args.getInt(ARG_MODE, MODE_CREATE);\n        View view = View.inflate(activity, R.layout.dialog_edit_pref_item, null);\n        MaterialSpinner spinner = view.findViewById(R.id.type_selector_spinner);\n        ArrayAdapter<CharSequence> spinnerAdapter = SelectedArrayAdapter.createFromResource(activity,\n                R.array.extras_types, io.github.muntashirakon.ui.R.layout.auto_complete_dropdown_item);\n        spinner.setAdapter(spinnerAdapter);\n        spinner.setOnItemClickListener((parent, view1, position, id) -> {\n            for (ViewGroup layout : mLayoutTypes) layout.setVisibility(View.GONE);\n            if (position != TYPE_NULL) {\n                // We don't need a value for null\n                ViewGroup viewGroup = mLayoutTypes[position];\n                viewGroup.setVisibility(View.VISIBLE);\n                if (viewGroup instanceof TextInputLayout) {\n                    ((TextInputLayout) viewGroup).setHint(spinnerAdapter.getItem(position));\n                }\n            }\n            mCurrentType = position;\n        });\n        // Set layouts\n        mLayoutTypes[TYPE_BOOLEAN] = view.findViewById(R.id.layout_bool);\n        mLayoutTypes[TYPE_COMPONENT_NAME] = view.findViewById(R.id.layout_string);\n        mLayoutTypes[TYPE_FLOAT] = view.findViewById(R.id.layout_float);\n        mLayoutTypes[TYPE_FLOAT_ARR] = view.findViewById(R.id.layout_string);\n        mLayoutTypes[TYPE_FLOAT_AL] = view.findViewById(R.id.layout_string);\n        mLayoutTypes[TYPE_INTEGER] = view.findViewById(R.id.layout_int);\n        mLayoutTypes[TYPE_INT_ARR] = view.findViewById(R.id.layout_string);\n        mLayoutTypes[TYPE_INT_AL] = view.findViewById(R.id.layout_string);\n        mLayoutTypes[TYPE_LONG] = view.findViewById(R.id.layout_long);\n        mLayoutTypes[TYPE_LONG_ARR] = view.findViewById(R.id.layout_string);\n        mLayoutTypes[TYPE_LONG_AL] = view.findViewById(R.id.layout_string);\n        mLayoutTypes[TYPE_NULL] = view.findViewById(R.id.layout_string);\n        mLayoutTypes[TYPE_STRING] = view.findViewById(R.id.layout_string);\n        mLayoutTypes[TYPE_STRING_ARR] = view.findViewById(R.id.layout_string);\n        mLayoutTypes[TYPE_STRING_AL] = view.findViewById(R.id.layout_string);\n        mLayoutTypes[TYPE_URI] = view.findViewById(R.id.layout_string);\n        mLayoutTypes[TYPE_URI_ARR] = view.findViewById(R.id.layout_string);\n        mLayoutTypes[TYPE_URI_AL] = view.findViewById(R.id.layout_string);\n        // Set views\n        mValues[TYPE_BOOLEAN] = view.findViewById(R.id.input_bool);\n        mValues[TYPE_COMPONENT_NAME] = view.findViewById(R.id.input_string);\n        mValues[TYPE_FLOAT] = view.findViewById(R.id.input_float);\n        mValues[TYPE_FLOAT_ARR] = view.findViewById(R.id.input_string);\n        mValues[TYPE_FLOAT_AL] = view.findViewById(R.id.input_string);\n        mValues[TYPE_INTEGER] = view.findViewById(R.id.input_int);\n        mValues[TYPE_INT_ARR] = view.findViewById(R.id.input_string);\n        mValues[TYPE_INT_AL] = view.findViewById(R.id.input_string);\n        mValues[TYPE_LONG] = view.findViewById(R.id.input_long);\n        mValues[TYPE_LONG_ARR] = view.findViewById(R.id.input_string);\n        mValues[TYPE_LONG_AL] = view.findViewById(R.id.input_string);\n        mValues[TYPE_NULL] = view.findViewById(R.id.input_string);\n        mValues[TYPE_STRING] = view.findViewById(R.id.input_string);\n        mValues[TYPE_STRING_ARR] = view.findViewById(R.id.input_string);\n        mValues[TYPE_STRING_AL] = view.findViewById(R.id.input_string);\n        mValues[TYPE_URI] = view.findViewById(R.id.input_string);\n        mValues[TYPE_URI_ARR] = view.findViewById(R.id.input_string);\n        mValues[TYPE_URI_AL] = view.findViewById(R.id.input_string);\n        // Key name\n        TextInputEditText editKeyName = view.findViewById(R.id.key_name);\n        if (extraItem != null) {\n            // Extra is already set\n            mCurrentType = extraItem.type;\n            String keyName = extraItem.keyName;\n            Object keyValue = extraItem.keyValue;\n            editKeyName.setText(keyName);\n            if (mode == MODE_EDIT) editKeyName.setEnabled(false);\n            for (ViewGroup layout : mLayoutTypes) layout.setVisibility(View.GONE);\n            if (mCurrentType != TYPE_NULL) {\n                // We don't need a value for null\n                ViewGroup viewGroup = mLayoutTypes[mCurrentType];\n                viewGroup.setVisibility(View.VISIBLE);\n                if (viewGroup instanceof TextInputLayout) {\n                    ((TextInputLayout) viewGroup).setHint(spinnerAdapter.getItem(mCurrentType));\n                }\n                if (keyValue != null) {\n                    // FIXME: 25/1/21 Reformat the string to support parsing\n                    TextView tv = mValues[TYPE_FLOAT];\n                    if (tv instanceof MaterialSwitch) {\n                        ((MaterialSwitch) tv).setChecked((boolean) keyValue);\n                    } else tv.setText(keyValue.toString());\n                }\n            }\n        }\n        MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(activity);\n        builder.setView(view)\n                .setPositiveButton(mode == MODE_CREATE ? R.string.add : R.string.done, (dialog, which) -> {\n                    if (mOnSaveListener == null) return;\n                    if (editKeyName.getText() == null) {\n                        UIUtils.displayLongToast(R.string.key_name_cannot_be_null);\n                        return;\n                    }\n                    String keyName = editKeyName.getText().toString().trim();\n                    ExtraItem newExtraItem;\n                    if (extraItem != null) newExtraItem = extraItem;\n                    else {\n                        newExtraItem = new ExtraItem();\n                        newExtraItem.keyName = keyName;\n                    }\n                    newExtraItem.type = mCurrentType;\n                    if (TextUtils.isEmpty(newExtraItem.keyName)) {\n                        UIUtils.displayLongToast(R.string.key_name_cannot_be_null);\n                        return;\n                    }\n                    try {\n                        if (mCurrentType == TYPE_BOOLEAN) {\n                            newExtraItem.keyValue = ((MaterialSwitch) mValues[mCurrentType]).isChecked();\n                        } else {\n                            newExtraItem.keyValue = parseExtraValue(mCurrentType, mValues[mCurrentType].getText().toString().trim());\n                        }\n                    } catch (Exception e) {\n                        e.printStackTrace();\n                        UIUtils.displayLongToast(R.string.error_evaluating_input);\n                        return;\n                    }\n                    mOnSaveListener.onSave(mode, newExtraItem);\n                })\n                .setNegativeButton(R.string.cancel, (dialog, which) -> {\n                    if (getDialog() != null) getDialog().cancel();\n                });\n        if (mode == MODE_EDIT) {\n            builder.setNeutralButton(R.string.delete, (dialog, which) -> {\n                if (mOnSaveListener != null) mOnSaveListener.onSave(MODE_DELETE, extraItem);\n            });\n        }\n        return builder.create();\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/intercept/HistoryEditText.java",
    "content": "// SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.intercept;\n\nimport android.app.Activity;\nimport android.content.SharedPreferences;\nimport android.widget.ArrayAdapter;\n\nimport androidx.annotation.NonNull;\nimport androidx.preference.PreferenceManager;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\n\nimport io.github.muntashirakon.adapters.NoFilterArrayAdapter;\nimport io.github.muntashirakon.widget.MaterialAutoCompleteTextView;\n\npublic class HistoryEditText {\n    private static final String DELIMITER = \"';'\";\n    private static final int MAX_HISTORY_SIZE = 8;\n    private static final String HISTORY_PREFIX = \"ActivityInterceptor_history_\";\n\n    private final Activity mContext;\n    private final EditorHandler[] mEditorHandlers;\n\n    /**\n     * ContextActionBar for one EditText\n     */\n    protected class EditorHandler {\n        private final MaterialAutoCompleteTextView mEditor;\n        private final String mId;\n\n        public EditorHandler(String id, MaterialAutoCompleteTextView editor) {\n            mId = id;\n            mEditor = editor;\n            showHistory();\n        }\n\n        public String toString(SharedPreferences pref) {\n            return mId + \" : '\" + getHistory(pref) + \"'\";\n        }\n\n        protected void showHistory() {\n            List<String> items = getHistoryItems();\n            ArrayAdapter<String> adapter = new NoFilterArrayAdapter<>(mContext,\n                    io.github.muntashirakon.ui.R.layout.auto_complete_dropdown_item, items);\n            mEditor.setAdapter(adapter);\n        }\n\n        @NonNull\n        private List<String> getHistoryItems() {\n            SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(mContext);\n            return getHistory(sharedPref);\n        }\n\n        @NonNull\n        private List<String> getHistory(@NonNull SharedPreferences sharedPref) {\n            String history = sharedPref.getString(mId, \"\");\n            return asList(history == null ? \"\" : history);\n        }\n\n        protected void saveHistory(@NonNull SharedPreferences sharedPref, @NonNull SharedPreferences.Editor edit) {\n            List<String> history = getHistory(sharedPref);\n            history = include(history, mEditor.getText().toString().trim());\n            String result = toString(history);\n            edit.putString(mId, result);\n        }\n\n        @NonNull\n        private List<String> asList(@NonNull String serialistedListElements) {\n            String[] items = serialistedListElements.split(DELIMITER);\n            return Arrays.asList(items);\n        }\n\n        @NonNull\n        private String toString(List<String> list) {\n            StringBuilder result = new StringBuilder();\n            if (list != null) {\n                String nextDelim = \"\";\n                for (Object instance : list) {\n                    if (instance != null) {\n                        String instanceString = instance.toString().trim();\n                        if (instanceString.length() > 0) {\n                            result.append(nextDelim).append(instanceString);\n                            nextDelim = DELIMITER;\n                        }\n                    }\n                }\n            }\n            return result.toString();\n        }\n\n        @NonNull\n        private List<String> include(List<String> history_, String newValue) {\n            List<String> history = new ArrayList<>(history_);\n            if ((newValue != null) && (newValue.length() > 0)) {\n                history.remove(newValue);\n                history.add(0, newValue);\n            }\n\n            int len = history.size();\n\n            // forget oldest entries if maxHisotrySize is reached\n            while (len > MAX_HISTORY_SIZE) {\n                len--;\n                history.remove(len);\n            }\n            return history;\n        }\n    }\n\n    /**\n     * define history function for these editors\n     */\n    public HistoryEditText(@NonNull Activity context, @NonNull MaterialAutoCompleteTextView... editors) {\n        mContext = context;\n        mEditorHandlers = new EditorHandler[editors.length];\n\n        for (int i = 0; i < editors.length; i++) {\n            mEditorHandlers[i] = createHandler(HISTORY_PREFIX + i, editors[i]);\n        }\n    }\n\n    protected EditorHandler createHandler(String id, MaterialAutoCompleteTextView editor) {\n        return new EditorHandler(id, editor);\n    }\n\n    /**\n     * include current editor-content to history and save to settings\n     */\n    public void saveHistory() {\n        SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(mContext);\n        SharedPreferences.Editor edit = sharedPref.edit();\n\n        for (EditorHandler instance : mEditorHandlers) {\n            instance.saveHistory(sharedPref, edit);\n        }\n        edit.apply();\n    }\n\n    @NonNull\n    @Override\n    public String toString() {\n        SharedPreferences sharedPref = PreferenceManager.getDefaultSharedPreferences(mContext);\n        StringBuilder result = new StringBuilder();\n        for (EditorHandler instance : mEditorHandlers) {\n            result.append(instance.toString(sharedPref)).append(\"\\n\");\n        }\n        return result.toString();\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/intercept/IntentCompat.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.intercept;\n\nimport static io.github.muntashirakon.AppManager.intercept.AddIntentExtraFragment.ExtraItem;\nimport static io.github.muntashirakon.AppManager.intercept.AddIntentExtraFragment.TYPE_BOOLEAN;\nimport static io.github.muntashirakon.AppManager.intercept.AddIntentExtraFragment.TYPE_COMPONENT_NAME;\nimport static io.github.muntashirakon.AppManager.intercept.AddIntentExtraFragment.TYPE_FLOAT;\nimport static io.github.muntashirakon.AppManager.intercept.AddIntentExtraFragment.TYPE_FLOAT_AL;\nimport static io.github.muntashirakon.AppManager.intercept.AddIntentExtraFragment.TYPE_FLOAT_ARR;\nimport static io.github.muntashirakon.AppManager.intercept.AddIntentExtraFragment.TYPE_INTEGER;\nimport static io.github.muntashirakon.AppManager.intercept.AddIntentExtraFragment.TYPE_INT_AL;\nimport static io.github.muntashirakon.AppManager.intercept.AddIntentExtraFragment.TYPE_INT_ARR;\nimport static io.github.muntashirakon.AppManager.intercept.AddIntentExtraFragment.TYPE_LONG;\nimport static io.github.muntashirakon.AppManager.intercept.AddIntentExtraFragment.TYPE_LONG_AL;\nimport static io.github.muntashirakon.AppManager.intercept.AddIntentExtraFragment.TYPE_LONG_ARR;\nimport static io.github.muntashirakon.AppManager.intercept.AddIntentExtraFragment.TYPE_NULL;\nimport static io.github.muntashirakon.AppManager.intercept.AddIntentExtraFragment.TYPE_STRING;\nimport static io.github.muntashirakon.AppManager.intercept.AddIntentExtraFragment.TYPE_STRING_AL;\nimport static io.github.muntashirakon.AppManager.intercept.AddIntentExtraFragment.TYPE_STRING_ARR;\nimport static io.github.muntashirakon.AppManager.intercept.AddIntentExtraFragment.TYPE_URI;\nimport static io.github.muntashirakon.AppManager.intercept.AddIntentExtraFragment.TYPE_URI_AL;\nimport static io.github.muntashirakon.AppManager.intercept.AddIntentExtraFragment.TYPE_URI_ARR;\nimport static io.github.muntashirakon.AppManager.intercept.AddIntentExtraFragment.Type;\n\nimport android.content.ComponentName;\nimport android.content.Intent;\nimport android.content.IntentHidden;\nimport android.graphics.Rect;\nimport android.net.Uri;\nimport android.os.Build;\nimport android.os.Bundle;\nimport android.os.Parcelable;\nimport android.text.TextUtils;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.core.os.BundleCompat;\nimport androidx.core.util.Pair;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Set;\nimport java.util.StringTokenizer;\n\nimport dev.rikka.tools.refine.Refine;\nimport io.github.muntashirakon.AppManager.compat.IntegerCompat;\nimport io.github.muntashirakon.AppManager.compat.UriCompat;\nimport io.github.muntashirakon.AppManager.fm.FmUtils;\nimport io.github.muntashirakon.AppManager.utils.ExUtils;\n\npublic final class IntentCompat {\n    public static void putWrappedParcelableExtra(@NonNull Intent intent, @Nullable String name,\n                                                 @Nullable Parcelable parcelable) {\n        Bundle bundle = new Bundle();\n        bundle.putParcelable(name, parcelable);\n        intent.putExtra(name, bundle);\n    }\n\n    @Nullable\n    public static <T extends Parcelable> T getUnwrappedParcelableExtra(@NonNull Intent intent,\n                                                                       @Nullable String name,\n                                                                       @NonNull Class<T> clazz) {\n        Bundle bundle = intent.getBundleExtra(name);\n        if (bundle == null) {\n            return null;\n        }\n        return BundleCompat.getParcelable(bundle, name, clazz);\n    }\n\n    /**\n     * Retrieve extended data from the intent.\n     *\n     * @param name  The name of the desired item.\n     * @param clazz The type of the object expected.\n     * @return the value of an item previously added with putExtra(),\n     * or null if no Parcelable value was found.\n     * @see Intent#putExtra(String, Parcelable)\n     */\n    @Nullable\n    public static <T extends Parcelable> T getParcelableExtra(@NonNull Intent intent, @Nullable String name,\n                                                              @NonNull Class<T> clazz) {\n        return androidx.core.content.IntentCompat.getParcelableExtra(intent, name, clazz);\n    }\n\n    /**\n     * Retrieve extended data from the intent.\n     *\n     * @param name  The name of the desired item.\n     * @param clazz The type of the items inside the array list. This is only verified when\n     *              parcelling.\n     * @return the value of an item previously added with\n     * putParcelableArrayListExtra(), or null if no\n     * ArrayList<Parcelable> value was found.\n     * @see Intent#putParcelableArrayListExtra(String, ArrayList)\n     */\n    @Nullable\n    public static <T extends Parcelable> ArrayList<T> getParcelableArrayListExtra(@NonNull Intent intent,\n                                                                                  @Nullable String name,\n                                                                                  @NonNull Class<? extends T> clazz) {\n        return androidx.core.content.IntentCompat.getParcelableArrayListExtra(intent, name, clazz);\n    }\n\n    @Nullable\n    public static Uri getDataUri(@Nullable Intent intent) {\n        if (intent == null) {\n            return null;\n        }\n        if (Intent.ACTION_SEND.equals(intent.getAction())) {\n            return FmUtils.sanitizeContentInput(getParcelableExtra(intent, Intent.EXTRA_STREAM, Uri.class));\n        }\n        return FmUtils.sanitizeContentInput(intent.getData());\n    }\n\n    @Nullable\n    public static List<Uri> getDataUris(@NonNull Intent intent) {\n        if (Intent.ACTION_SEND_MULTIPLE.equals(intent.getAction())) {\n            List<Uri> inputUris = getParcelableArrayListExtra(intent, Intent.EXTRA_STREAM, Uri.class);\n            if (inputUris == null) {\n                return null;\n            }\n            List<Uri> filteredUris = new ArrayList<>(inputUris.size());\n            for (Uri uri : inputUris) {\n                Uri fixedUri = FmUtils.sanitizeContentInput(uri);\n                if (fixedUri != null) {\n                    filteredUris.add(fixedUri);\n                }\n            }\n            return filteredUris.isEmpty() ? null : filteredUris;\n        }\n        Uri uri = getDataUri(intent);\n        return uri != null ? Collections.singletonList(uri) : null;\n    }\n\n    public static void removeFlags(@NonNull Intent intent, int flags) {\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {\n            intent.removeFlags(flags);\n        } else {\n            intent.setFlags(intent.getFlags() & ~flags);\n        }\n    }\n\n    @Nullable\n    public static Object parseExtraValue(@Type int type, String rawValue) {\n        switch (type) {\n            case TYPE_STRING:\n                return rawValue;\n            case TYPE_NULL:\n                return null;\n            case TYPE_INTEGER:\n                return IntegerCompat.decode(rawValue);\n            case TYPE_URI:\n                return Uri.parse(rawValue);\n            case TYPE_URI_ARR: {\n                // Split on commas unless they are preceded by an escape.\n                // The escape character must be escaped for the string and\n                // again for the regex, thus four escape characters become one.\n                String[] strings = rawValue.split(\"(?<!\\\\\\\\),\");\n                Uri[] list = new Uri[strings.length];\n                for (int i = 0; i < list.length; ++i) {\n                    list[i] = Uri.parse(strings[i]);\n                }\n                return list;\n            }\n            case TYPE_URI_AL: {\n                // Split on commas unless they are preceded by an escape.\n                // The escape character must be escaped for the string and\n                // again for the regex, thus four escape characters become one.\n                String[] strings = rawValue.split(\"(?<!\\\\\\\\),\");\n                List<Uri> list = new ArrayList<>(strings.length);\n                for (String s : strings) {\n                    list.add(Uri.parse(s));\n                }\n                return list;\n            }\n            case TYPE_COMPONENT_NAME:\n                ComponentName cn = ComponentName.unflattenFromString(rawValue);\n                if (cn == null) {\n                    throw new IllegalArgumentException(\"Bad component name: \" + rawValue);\n                }\n                return cn;\n            case TYPE_INT_ARR: {\n                String[] strings = rawValue.split(\",\");\n                int[] list = new int[strings.length];\n                for (int i = 0; i < strings.length; i++) {\n                    list[i] = IntegerCompat.decode(strings[i].trim());\n                }\n                return list;\n            }\n            case TYPE_INT_AL: {\n                String[] strings = rawValue.split(\",\");\n                ArrayList<Integer> list = new ArrayList<>(strings.length);\n                for (String string : strings) {\n                    list.add(IntegerCompat.decode(string.trim()));\n                }\n                return list;\n            }\n            case TYPE_LONG:\n                return Long.parseLong(rawValue);\n            case TYPE_LONG_ARR: {\n                String[] strings = rawValue.split(\",\");\n                long[] list = new long[strings.length];\n                for (int i = 0; i < strings.length; i++) {\n                    list[i] = Long.decode(strings[i].trim());\n                }\n                return list;\n            }\n            case TYPE_LONG_AL: {\n                String[] strings = rawValue.split(\",\");\n                ArrayList<Long> list = new ArrayList<>(strings.length);\n                for (String string : strings) {\n                    list.add(Long.decode(string.trim()));\n                }\n                return list;\n            }\n            case TYPE_FLOAT:\n                return Float.parseFloat(rawValue);\n            case TYPE_FLOAT_ARR: {\n                String[] strings = rawValue.split(\",\");\n                float[] list = new float[strings.length];\n                for (int i = 0; i < strings.length; i++) {\n                    list[i] = Float.parseFloat(strings[i]);\n                }\n                return list;\n            }\n            case TYPE_FLOAT_AL: {\n                String[] strings = rawValue.split(\",\");\n                ArrayList<Float> list = new ArrayList<>(strings.length);\n                for (String string : strings) {\n                    list.add(Float.parseFloat(string));\n                }\n                return list;\n            }\n            case TYPE_STRING_ARR:\n                // Split on commas unless they are preceded by an escape.\n                // The escape character must be escaped for the string and\n                // again for the regex, thus four escape characters become one.\n                return rawValue.split(\"(?<!\\\\\\\\),\");\n            case TYPE_STRING_AL: {\n                // Split on commas unless they are preceded by an escape.\n                // The escape character must be escaped for the string and\n                // again for the regex, thus four escape characters become one.\n                String[] strings = rawValue.split(\"(?<!\\\\\\\\),\");\n                ArrayList<String> list = new ArrayList<>(strings.length);\n                Collections.addAll(list, strings);\n                return list;\n            }\n            case TYPE_BOOLEAN: {\n                // Boolean.valueOf() results in false for anything that is not \"true\", which is\n                // error-prone in shell commands\n                boolean boolValue;\n                if (\"true\".equals(rawValue) || \"t\".equals(rawValue)) {\n                    boolValue = true;\n                } else if (\"false\".equals(rawValue) || \"f\".equals(rawValue)) {\n                    boolValue = false;\n                } else {\n                    try {\n                        boolValue = IntegerCompat.decode(rawValue) != 0;\n                    } catch (NumberFormatException ex) {\n                        throw new IllegalArgumentException(\"Invalid boolean value: \" + rawValue);\n                    }\n                }\n                return boolValue;\n            }\n            default:\n                throw new IllegalArgumentException(\"Unknown type: \" + type);\n        }\n    }\n\n    @Nullable\n    private static Pair<Integer, String> valueToParsableStringAndType(@Nullable Object object) {\n        if (object == null) {\n            return new Pair<>(TYPE_NULL, null);\n        } else if (object instanceof String) {\n            return new Pair<>(TYPE_STRING, (String) object);\n        } else if (object instanceof Integer) {\n            return new Pair<>(TYPE_INTEGER, String.valueOf((int) object));\n        } else if (object instanceof Long) {\n            return new Pair<>(TYPE_LONG, String.valueOf((long) object));\n        } else if (object instanceof Float) {\n            return new Pair<>(TYPE_FLOAT, String.valueOf((float) object));\n        } else if (object instanceof Boolean) {\n            return new Pair<>(TYPE_BOOLEAN, String.valueOf((boolean) object));\n        } else if (object instanceof Uri) {\n            return new Pair<>(TYPE_URI, object.toString());\n        } else if (object instanceof ComponentName) {\n            return new Pair<>(TYPE_COMPONENT_NAME, ((ComponentName) object).flattenToString());\n        } else if (object instanceof int[]) {\n            StringBuilder sb = new StringBuilder();\n            int[] list = (int[]) object;\n            if (list.length >= 1) sb.append(list[0]);\n            for (int i = 1; i < list.length; ++i) {\n                sb.append(\",\").append(list[i]);\n            }\n            return new Pair<>(TYPE_INT_ARR, sb.toString());\n        } else if (object instanceof long[]) {\n            StringBuilder sb = new StringBuilder();\n            long[] list = (long[]) object;\n            if (list.length >= 1) sb.append(list[0]);\n            for (int i = 1; i < list.length; ++i) {\n                sb.append(\",\").append(list[i]);\n            }\n            return new Pair<>(TYPE_LONG_ARR, sb.toString());\n        } else if (object instanceof float[]) {\n            StringBuilder sb = new StringBuilder();\n            float[] list = (float[]) object;\n            if (list.length >= 1) sb.append(list[0]);\n            for (int i = 1; i < list.length; ++i) {\n                sb.append(\",\").append(list[i]);\n            }\n            return new Pair<>(TYPE_FLOAT_ARR, sb.toString());\n        } else if (object instanceof String[]) {\n            StringBuilder sb = new StringBuilder();\n            String[] list = (String[]) object;\n            if (list.length >= 1) sb.append(list[0].replace(\",\", \"\\\\,\"));\n            for (int i = 1; i < list.length; ++i) {\n                sb.append(\",\").append(list[i].replace(\",\", \"\\\\,\"));\n            }\n            return new Pair<>(TYPE_STRING_ARR, sb.toString());\n        } else if (object instanceof Uri[]) {\n            StringBuilder sb = new StringBuilder();\n            Uri[] list = (Uri[]) object;\n            if (list.length >= 1) sb.append(list[0].toString().replace(\",\", \"\\\\,\"));\n            for (int i = 1; i < list.length; ++i) {\n                sb.append(\",\").append(list[i].toString().replace(\",\", \"\\\\,\"));\n            }\n            return new Pair<>(TYPE_URI_ARR, sb.toString());\n        } else if (object instanceof List) {\n            @SuppressWarnings(\"rawtypes\")\n            List list = (List) object;\n            if (list.isEmpty()) {\n                // Type is lost forever, return null\n                // FIXME: Try to infer type using reflection\n                return new Pair<>(TYPE_NULL, null);\n            }\n            Object item = list.get(0);\n            if (item instanceof Integer) {\n                StringBuilder sb = new StringBuilder();\n                sb.append(item);\n                for (int i = 1; i < list.size(); ++i) {\n                    sb.append(\",\").append(list.get(i));\n                }\n                return new Pair<>(TYPE_INT_AL, sb.toString());\n            } else if (item instanceof Long) {\n                StringBuilder sb = new StringBuilder();\n                sb.append(item);\n                for (int i = 1; i < list.size(); ++i) {\n                    sb.append(\",\").append(list.get(i));\n                }\n                return new Pair<>(TYPE_LONG_AL, sb.toString());\n            } else if (item instanceof Float) {\n                StringBuilder sb = new StringBuilder();\n                sb.append(item);\n                for (int i = 1; i < list.size(); ++i) {\n                    sb.append(\",\").append(list.get(i));\n                }\n                return new Pair<>(TYPE_FLOAT_AL, sb.toString());\n            } else if (item instanceof String) {\n                StringBuilder sb = new StringBuilder();\n                sb.append(((String) item).replace(\",\", \"\\\\,\"));\n                for (int i = 1; i < list.size(); ++i) {\n                    sb.append(\",\").append(((String) list.get(i)).replace(\",\", \"\\\\,\"));\n                }\n                return new Pair<>(TYPE_STRING_AL, sb.toString());\n            } else if (item instanceof Uri) {\n                StringBuilder sb = new StringBuilder();\n                sb.append(item.toString().replace(\",\", \"\\\\,\"));\n                for (int i = 1; i < list.size(); ++i) {\n                    sb.append(\",\").append(list.get(i).toString().replace(\",\", \"\\\\,\"));\n                }\n                return new Pair<>(TYPE_URI_AL, sb.toString());\n            }\n        }\n        return null;\n    }\n\n    public static void addToIntent(@NonNull Intent intent, @NonNull ExtraItem extraItem) {\n        if (extraItem.keyValue == null && extraItem.type != TYPE_NULL) {\n            return;\n        }\n        switch (extraItem.type) {\n            case TYPE_BOOLEAN:\n                intent.putExtra(extraItem.keyName, (boolean) extraItem.keyValue);\n                break;\n            case TYPE_FLOAT:\n                intent.putExtra(extraItem.keyName, (float) extraItem.keyValue);\n                break;\n            case TYPE_FLOAT_AL:\n            case TYPE_STRING_AL:\n            case TYPE_LONG_AL:\n            case TYPE_INT_AL:\n            case TYPE_URI_AL:\n                intent.putExtra(extraItem.keyName, (ArrayList<?>) extraItem.keyValue);\n                break;\n            case TYPE_FLOAT_ARR:\n                intent.putExtra(extraItem.keyName, (float[]) extraItem.keyValue);\n                break;\n            case TYPE_INTEGER:\n                intent.putExtra(extraItem.keyName, (int) extraItem.keyValue);\n                break;\n            case TYPE_INT_ARR:\n                intent.putExtra(extraItem.keyName, (int[]) extraItem.keyValue);\n                break;\n            case TYPE_LONG:\n                intent.putExtra(extraItem.keyName, (long) extraItem.keyValue);\n                break;\n            case TYPE_LONG_ARR:\n                intent.putExtra(extraItem.keyName, (long[]) extraItem.keyValue);\n                break;\n            case TYPE_NULL:\n                intent.putExtra(extraItem.keyName, (String) null);\n                break;\n            case TYPE_STRING:\n                intent.putExtra(extraItem.keyName, (String) extraItem.keyValue);\n                break;\n            case TYPE_STRING_ARR:\n                intent.putExtra(extraItem.keyName, (String[]) extraItem.keyValue);\n                break;\n            case TYPE_COMPONENT_NAME:\n            case TYPE_URI:\n                intent.putExtra(extraItem.keyName, (Parcelable) extraItem.keyValue);\n                break;\n            case TYPE_URI_ARR:\n                intent.putExtra(extraItem.keyName, (Parcelable[]) extraItem.keyValue);\n                break;\n        }\n    }\n\n    @NonNull\n    public static List<String> flattenToCommand(@NonNull Intent intent) {\n        List<String> args = new ArrayList<>();\n        String action = intent.getAction();\n        String data = intent.getDataString();\n        String type = intent.getType();\n        Set<String> categories = intent.getCategories();\n        ComponentName cn = intent.getComponent();\n        String packageName = intent.getPackage();\n        int flags = intent.getFlags();\n        Bundle extras = intent.getExtras();\n\n        if (action != null) {\n            args.add(\"-a\");\n            args.add(action);\n        }\n        if (data != null) {\n            args.add(\"-d\");\n            args.add(data);\n        }\n        if (type != null) {\n            args.add(\"-t\");\n            args.add(type);\n        }\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {\n            String id = intent.getIdentifier();\n            if (id != null) {\n                args.add(\"-i\");\n                args.add(id);\n            }\n        }\n        if (categories != null) {\n            for (String category : categories) {\n                args.add(\"-c\");\n                args.add(category);\n            }\n        }\n        if (cn != null) {\n            args.add(\"-n\");\n            args.add(cn.flattenToString());\n        }\n        if (extras != null) {\n            for (String key : extras.keySet()) {\n                Pair<Integer, String> typeAndString = valueToParsableStringAndType(extras.get(key));\n                if (typeAndString == null) {\n                    // else unsupported bundle item, ignore\n                    continue;\n                }\n                switch (typeAndString.first) {\n                    case TYPE_STRING:\n                        args.add(\"--es\");\n                        break;\n                    case TYPE_NULL:\n                        args.add(\"--esn\");\n                        break;\n                    case TYPE_BOOLEAN:\n                        args.add(\"--ez\");\n                        break;\n                    case TYPE_INTEGER:\n                        args.add(\"--ei\");\n                        break;\n                    case TYPE_LONG:\n                        args.add(\"--el\");\n                        break;\n                    case TYPE_FLOAT:\n                        args.add(\"--ef\");\n                        break;\n                    case TYPE_URI:\n                        args.add(\"--eu\");\n                        break;\n                    case TYPE_COMPONENT_NAME:\n                        args.add(\"--ecn\");\n                        break;\n                    case TYPE_INT_ARR:\n                        args.add(\"--eia\");\n                        break;\n                    case TYPE_INT_AL:\n                        args.add(\"--eial\");\n                        break;\n                    case TYPE_LONG_ARR:\n                        args.add(\"--ela\");\n                        break;\n                    case TYPE_LONG_AL:\n                        args.add(\"--elal\");\n                        break;\n                    case TYPE_FLOAT_ARR:\n                        args.add(\"--efa\");\n                        break;\n                    case TYPE_FLOAT_AL:\n                        args.add(\"--efal\");\n                        break;\n                    case TYPE_STRING_ARR:\n                        args.add(\"--esa\");\n                        break;\n                    case TYPE_STRING_AL:\n                        args.add(\"--esal\");\n                        break;\n                    default:\n                        // Unsupported\n                        continue;\n                }\n                // Add key\n                args.add(key);\n                if (typeAndString.first != TYPE_NULL) {\n                    // All except NULL has a value\n                    args.add(typeAndString.second);\n                }\n            }\n        }\n        args.add(\"-f\");\n        args.add(String.valueOf(flags));\n        if (packageName != null) {\n            args.add(packageName);\n        }\n        return args;\n    }\n\n    @NonNull\n    public static String flattenToString(@NonNull Intent intent) {\n        String action = intent.getAction();\n        String data = intent.getDataString();\n        String type = intent.getType();\n        Set<String> categories = intent.getCategories();\n        ComponentName cn = intent.getComponent();\n        String packageName = intent.getPackage();\n        int flags = intent.getFlags();\n        Bundle extras = intent.getExtras();\n\n        StringBuilder sb = new StringBuilder(\"VERSION\\t\").append(1).append(\"\\n\");\n        if (action != null) sb.append(\"ACTION\\t\").append(action).append(\"\\n\");\n        if (data != null) sb.append(\"DATA\\t\").append(data).append(\"\\n\");\n        if (type != null) sb.append(\"TYPE\\t\").append(type).append(\"\\n\");\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {\n            String id = intent.getIdentifier();\n            if (id != null) sb.append(\"IDENTIFIER\\t\").append(id).append(\"\\n\");\n        }\n        if (categories != null) {\n            for (String category : categories) {\n                sb.append(\"CATEGORY\\t\").append(category).append(\"\\n\");\n            }\n        }\n        if (cn != null) sb.append(\"COMPONENT\\t\").append(cn.flattenToString()).append(\"\\n\");\n        if (packageName != null) sb.append(\"PACKAGE\\t\").append(packageName).append(\"\\n\");\n        if (flags != 0) sb.append(\"FLAGS\\t0x\").append(Integer.toHexString(flags)).append(\"\\n\");\n        if (extras != null) {\n            for (String key : extras.keySet()) {\n                Pair<Integer, String> typeAndString = valueToParsableStringAndType(extras.get(key));\n                if (typeAndString != null) {\n                    sb.append(\"EXTRA\\t\").append(key).append(\"\\t\").append(typeAndString.first);\n                    if (typeAndString.first != TYPE_NULL) {\n                        sb.append(\"\\t\").append(typeAndString.second);\n                    }\n                    sb.append(\"\\n\");\n                } // else unsupported bundle item, ignore\n                // TODO: Add support for more items\n            }\n        }\n        return sb.toString();\n    }\n\n    @NonNull\n    public static String describeIntent(@NonNull Intent intent, String prefix) {\n        String action = intent.getAction();\n        String data = intent.getDataString();\n        String type = intent.getType();\n        Set<String> categories = intent.getCategories();\n        ComponentName cn = intent.getComponent();\n        String packageName = intent.getPackage();\n        int flags = intent.getFlags();\n        Bundle extras = intent.getExtras();\n\n        StringBuilder sb = new StringBuilder();\n        if (action != null) sb.append(prefix).append(\" ACTION\\t\").append(action).append(\"\\n\");\n        if (data != null) sb.append(prefix).append(\" DATA\\t\").append(data).append(\"\\n\");\n        if (type != null) sb.append(prefix).append(\" TYPE\\t\").append(type).append(\"\\n\");\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {\n            String id = intent.getIdentifier();\n            if (id != null) sb.append(prefix).append(\" IDENTIFIER\\t\").append(id).append(\"\\n\");\n        }\n        if (categories != null) {\n            for (String category : categories) {\n                sb.append(prefix).append(\" CATEGORY\\t\").append(category).append(\"\\n\");\n            }\n        }\n        if (cn != null)\n            sb.append(prefix).append(\" COMPONENT\\t\").append(cn.flattenToString()).append(\"\\n\");\n        if (packageName != null)\n            sb.append(prefix).append(\" PACKAGE\\t\").append(packageName).append(\"\\n\");\n        if (flags != 0)\n            sb.append(prefix).append(\" FLAGS\\t0x\").append(Integer.toHexString(flags)).append(\"\\n\");\n        if (extras != null) {\n            for (String key : extras.keySet()) {\n                Pair<Integer, String> typeAndString = valueToParsableStringAndType(extras.get(key));\n                if (typeAndString != null) {\n                    sb.append(prefix).append(\" EXTRA\\t\").append(key).append(\"\\t\").append(typeAndString.first);\n                    if (typeAndString.first != TYPE_NULL) {\n                        sb.append(\"\\t\").append(typeAndString.second);\n                    }\n                    sb.append(\"\\n\");\n                } // else unsupported bundle item, ignore\n                // TODO: Add support for more items\n            }\n        }\n        return sb.toString();\n    }\n\n    @Nullable\n    public static Intent unflattenFromString(@NonNull String intentString) {\n        Intent intent = new Intent();\n        String[] lines = intentString.split(\"\\n\");\n        Uri data = null;\n        String type = null;\n        for (String line : lines) {\n            if (TextUtils.isEmpty(line)) continue;\n            StringTokenizer tokenizer = new StringTokenizer(line, \"\\t\");\n            if (tokenizer.countTokens() < 2) {\n                // Invalid line\n                return null;\n            }\n            switch (tokenizer.nextToken()) {\n                case \"VERSION\": {\n                    int version = IntegerCompat.decode(tokenizer.nextToken());\n                    if (version != 1) {\n                        // Unsupported version\n                        return null;\n                    }\n                    break;\n                }\n                case \"ACTION\":\n                    intent.setAction(tokenizer.nextToken());\n                    break;\n                case \"DATA\":\n                    data = Uri.parse(tokenizer.nextToken());\n                    break;\n                case \"TYPE\":\n                    type = tokenizer.nextToken();\n                    break;\n                case \"IDENTIFIER\":\n                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {\n                        intent.setIdentifier(tokenizer.nextToken());\n                    }\n                    break;\n                case \"CATEGORY\":\n                    intent.addCategory(tokenizer.nextToken());\n                    break;\n                case \"COMPONENT\":\n                    intent.setComponent(ComponentName.unflattenFromString(tokenizer.nextToken()));\n                    break;\n                case \"PACKAGE\":\n                    intent.setPackage(tokenizer.nextToken());\n                    break;\n                case \"FLAGS\":\n                    intent.setFlags(IntegerCompat.decode(tokenizer.nextToken()));\n                    break;\n                case \"EXTRA\": {\n                    ExtraItem item = new ExtraItem();\n                    item.keyName = tokenizer.nextToken();\n                    item.type = IntegerCompat.decode(tokenizer.nextToken());\n                    item.keyValue = parseExtraValue(item.type, tokenizer.nextToken());\n                    addToIntent(intent, item);\n                }\n            }\n        }\n        if (data != null) {\n            intent.setDataAndType(data, type);\n        } else if (type != null) {\n            intent.setType(type);\n        }\n        return intent;\n    }\n\n    public static int getExtendedFlags(@NonNull Intent intent) {\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {\n            // Added in Android 14 r50\n            return ExUtils.requireNonNullElse(() -> Refine.<IntentHidden>unsafeCast(intent).getExtendedFlags(), 0);\n        }\n        return 0;\n    }\n\n    /**\n     * Convert this Intent into a String holding a URI representation of it.\n     * The returned URI string has been properly URI encoded, so it can be\n     * used with {@link Uri#parse Uri.parse(String)}.  The URI contains the\n     * Intent's data as the base URI, with an additional fragment describing\n     * the action, categories, type, flags, package, component, and extras.\n     *\n     * <p>You can convert the returned string back to an Intent with\n     * {@link Intent#getIntent(String)}.\n     *\n     * @param flags Additional operating flags.\n     * @return Returns a URI encoding URI string describing the entire contents\n     * of the Intent.\n     * @see Intent#toUri(int)\n     */\n    @NonNull\n    public static String toUri(@NonNull Intent intent, int flags) {\n        long flagsLong = intent.getFlags() & 0xFFFFFFFFL;\n        if (flagsLong < 0x80000000L || Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM) {\n            return intent.toUri(flags);\n        }\n        // Special workaround for Motorola and MIUI (> A10 and < A15)\n        StringBuilder uri = new StringBuilder(128);\n        if ((flags & Intent.URI_ANDROID_APP_SCHEME) != 0) {\n            if (intent.getPackage() == null) {\n                throw new IllegalArgumentException(\n                        \"Intent must include an explicit package name to build an android-app: \" + intent);\n            }\n            uri.append(\"android-app://\");\n            uri.append(Uri.encode(intent.getPackage()));\n            String scheme = null;\n            Uri data = intent.getData();\n            if (data != null) {\n                // All values here must be wrapped with Uri#encodeIfNotEncoded because it is\n                // possible to exploit the Uri API to return a raw unencoded value, which will\n                // not deserialize properly and may cause the resulting Intent to be transformed\n                // to a malicious value.\n                scheme = UriCompat.encodeIfNotEncoded(data.getScheme(), null);\n                if (scheme != null) {\n                    uri.append('/');\n                    uri.append(scheme);\n                    String authority = UriCompat.encodeIfNotEncoded(data.getEncodedAuthority(), null);\n                    if (authority != null) {\n                        uri.append('/');\n                        uri.append(authority);\n\n                        // Multiple path segments are allowed, don't encode the path / separator\n                        String path = UriCompat.encodeIfNotEncoded(data.getEncodedPath(), \"/\");\n                        if (path != null) {\n                            uri.append(path);\n                        }\n                        String queryParams = UriCompat.encodeIfNotEncoded(data.getEncodedQuery(), null);\n                        if (queryParams != null) {\n                            uri.append('?');\n                            uri.append(queryParams);\n                        }\n                        String fragment = UriCompat.encodeIfNotEncoded(data.getEncodedFragment(), null);\n                        if (fragment != null) {\n                            uri.append('#');\n                            uri.append(fragment);\n                        }\n                    }\n                }\n            }\n            toUriFragment(intent, uri, null, scheme == null ? Intent.ACTION_MAIN : Intent.ACTION_VIEW,\n                    intent.getPackage(), flags);\n            return uri.toString();\n        }\n        String scheme = null;\n        Uri dataUri = intent.getData();\n        if (dataUri != null) {\n            String data = dataUri.toString();\n            if ((flags & Intent.URI_INTENT_SCHEME) != 0) {\n                final int N = data.length();\n                for (int i = 0; i < N; i++) {\n                    char c = data.charAt(i);\n                    if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')\n                            || (c >= '0' && c <= '9') || c == '.' || c == '-' || c == '+') {\n                        continue;\n                    }\n                    if (c == ':' && i > 0) {\n                        // Valid scheme.\n                        scheme = data.substring(0, i);\n                        uri.append(\"intent:\");\n                        data = data.substring(i + 1);\n                        break;\n                    }\n\n                    // No scheme.\n                    break;\n                }\n            }\n            uri.append(data);\n\n        } else if ((flags & Intent.URI_INTENT_SCHEME) != 0) {\n            uri.append(\"intent:\");\n        }\n\n        toUriFragment(intent, uri, scheme, Intent.ACTION_VIEW, null, flags);\n\n        return uri.toString();\n    }\n\n    private static void toUriFragment(Intent intent, StringBuilder uri, @Nullable String scheme, String defAction,\n                                      @Nullable String defPackage, int flags) {\n        StringBuilder frag = new StringBuilder(128);\n\n        toUriInner(intent, frag, scheme, defAction, defPackage, flags);\n        Intent selector = intent.getSelector();\n        if (selector != null) {\n            frag.append(\"SEL;\");\n            // Note that for now we are not going to try to handle the\n            // data part; not clear how to represent this as a URI, and\n            // not much utility in it.\n            toUriInner(selector, frag, selector.getData() != null ? selector.getData().getScheme() : null,\n                    null, null, flags);\n        }\n\n        if (frag.length() > 0) {\n            uri.append(\"#Intent;\");\n            uri.append(frag);\n            uri.append(\"end\");\n        }\n    }\n\n    private static void toUriInner(Intent intent, StringBuilder uri, @Nullable String scheme,\n                                   @Nullable String defAction, @Nullable String defPackage,\n                                   int flags) {\n        if (scheme != null) {\n            uri.append(\"scheme=\").append(Uri.encode(scheme)).append(';');\n        }\n        String action = intent.getAction();\n        if (action != null && !action.equals(defAction)) {\n            uri.append(\"action=\").append(Uri.encode(action)).append(';');\n        }\n        Set<String> categories = intent.getCategories();\n        if (categories != null) {\n            for (String category : categories) {\n                uri.append(\"category=\").append(Uri.encode(category)).append(';');\n            }\n        }\n        String type = intent.getType();\n        if (type != null) {\n            uri.append(\"type=\").append(Uri.encode(type, \"/\")).append(';');\n        }\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {\n            String mIdentifier = intent.getIdentifier();\n            if (mIdentifier != null) {\n                uri.append(\"identifier=\").append(Uri.encode(mIdentifier, \"/\")).append(';');\n            }\n        }\n        int intentFlags = intent.getFlags();\n        if (intentFlags != 0) {\n            uri.append(\"launchFlags=\").append(IntegerCompat.toSignedHex(intent.getFlags())).append(';');\n        }\n\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {\n            int extendedFlags = getExtendedFlags(intent);\n            if (extendedFlags != 0) {\n                uri.append(\"extendedLaunchFlags=0x\").append(Integer.toHexString(extendedFlags))\n                        .append(';');\n            }\n        }\n        String intentPackage = intent.getPackage();\n        if (intentPackage != null && !intentPackage.equals(defPackage)) {\n            uri.append(\"package=\").append(Uri.encode(intentPackage)).append(';');\n        }\n        ComponentName component = intent.getComponent();\n        if (component != null) {\n            uri.append(\"component=\").append(Uri.encode(\n                    component.flattenToShortString(), \"/\")).append(';');\n        }\n        Rect sourceBounds = intent.getSourceBounds();\n        if (sourceBounds != null) {\n            uri.append(\"sourceBounds=\")\n                    .append(Uri.encode(sourceBounds.flattenToString()))\n                    .append(';');\n        }\n        Bundle extras = intent.getExtras();\n        if (extras != null) {\n            for (String key : extras.keySet()) {\n                final Object value = extras.get(key);\n                char entryType =\n                        value instanceof String ? 'S' :\n                                value instanceof Boolean ? 'B' :\n                                        value instanceof Byte ? 'b' :\n                                                value instanceof Character ? 'c' :\n                                                        value instanceof Double ? 'd' :\n                                                                value instanceof Float ? 'f' :\n                                                                        value instanceof Integer ? 'i' :\n                                                                                value instanceof Long ? 'l' :\n                                                                                        value instanceof Short ? 's' :\n                                                                                                '\\0';\n\n                if (entryType != '\\0') {\n                    uri.append(entryType);\n                    uri.append('.');\n                    uri.append(Uri.encode(key));\n                    uri.append('=');\n                    uri.append(Uri.encode(value.toString()));\n                    uri.append(';');\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/intercept/InterceptorShortcutInfo.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.intercept;\n\nimport android.content.Context;\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.os.Parcel;\nimport android.os.PersistableBundle;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.core.os.ParcelCompat;\n\nimport io.github.muntashirakon.AppManager.logs.Log;\nimport io.github.muntashirakon.AppManager.shortcut.ShortcutInfo;\n\npublic class InterceptorShortcutInfo extends ShortcutInfo {\n    public static final String TAG = InterceptorShortcutInfo.class.getSimpleName();\n\n    private final Intent intent;\n\n    public InterceptorShortcutInfo(@NonNull Intent intent) {\n        this.intent = new Intent(intent);\n        fixIntent(this.intent);\n    }\n\n    protected InterceptorShortcutInfo(Parcel in) {\n        super(in);\n        intent = ParcelCompat.readParcelable(in, Intent.class.getClassLoader(), Intent.class);\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        super.writeToParcel(dest, flags);\n        dest.writeParcelable(intent, flags);\n    }\n\n    @Override\n    public Intent toShortcutIntent(@NonNull Context context) {\n        return intent;\n    }\n\n    public static final Creator<InterceptorShortcutInfo> CREATOR = new Creator<InterceptorShortcutInfo>() {\n        @Override\n        public InterceptorShortcutInfo createFromParcel(Parcel source) {\n            return new InterceptorShortcutInfo(source);\n        }\n\n        @Override\n        public InterceptorShortcutInfo[] newArray(int size) {\n            return new InterceptorShortcutInfo[size];\n        }\n    };\n\n    @SuppressWarnings(\"deprecation\")\n    private static void fixIntent(@NonNull Intent intent) {\n        Bundle extras = intent.getExtras();\n        if (extras == null) {\n            // Nothing to do\n            return;\n        }\n        // Shortcuts use PersistableBundle for extras which only support 12 types\n        for (String key : extras.keySet()) {\n            Object value = extras.get(key);\n            if (!isValidType(value)) {\n                // Not a valid type, remove it from intent\n                Log.w(TAG, \"Removing unsupported key %s (class: %s, value: %s)\", key, value.getClass().getName(), value);\n                intent.removeExtra(key);\n            }\n        }\n    }\n\n    /**\n     * @see PersistableBundle#isValidType(Object)\n     */\n    private static boolean isValidType(@Nullable Object value) {\n        return (value instanceof Integer) || (value instanceof Long) ||\n                (value instanceof Double) || (value instanceof String) ||\n                (value instanceof int[]) || (value instanceof long[]) ||\n                (value instanceof double[]) || (value instanceof String[]) ||\n                (value instanceof PersistableBundle) || (value == null) ||\n                (value instanceof Boolean) || (value instanceof boolean[]);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/ipc/AMService.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.ipc;\n\nimport android.content.Intent;\nimport android.os.Binder;\nimport android.os.IBinder;\nimport android.os.Parcel;\nimport android.os.RemoteException;\nimport android.os.ServiceManager;\nimport android.system.ErrnoException;\nimport android.system.Os;\nimport android.util.Log;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport java.io.File;\n\nimport aosp.android.content.pm.ParceledListSlice;\nimport io.github.muntashirakon.AppManager.IAMService;\nimport io.github.muntashirakon.AppManager.IRemoteProcess;\nimport io.github.muntashirakon.AppManager.IRemoteShell;\nimport io.github.muntashirakon.AppManager.ipc.ps.ProcessEntry;\nimport io.github.muntashirakon.AppManager.ipc.ps.Ps;\nimport io.github.muntashirakon.AppManager.server.common.IRootServiceManager;\nimport io.github.muntashirakon.compat.os.ParcelCompat2;\n\npublic class AMService extends RootService {\n    static class IAMServiceImpl extends IAMService.Stub {\n        /**\n         * To get {@link Process}, wrap it using {@link RemoteProcess}. Since the streams are piped,\n         * I/O operations may have to be done in different threads.\n         */\n        @Override\n        public IRemoteProcess newProcess(String[] cmd, String[] env, String dir) throws RemoteException {\n            Process process;\n            try {\n                process = Runtime.getRuntime().exec(cmd, env, dir != null ? new File(dir) : null);\n            } catch (Exception e) {\n                throw new RemoteException(e.getMessage());\n            }\n            return new RemoteProcessImpl(process);\n        }\n\n        @Override\n        public IRemoteShell getShell(String[] cmd) {\n            return new RemoteShellImpl(cmd);\n        }\n\n        @Override\n        public ParceledListSlice<ProcessEntry> getRunningProcesses() {\n            Ps ps = new Ps();\n            ps.loadProcesses();\n            return new ParceledListSlice<>(ps.getProcesses());\n        }\n\n        @Override\n        public int getUid() {\n            return android.os.Process.myUid();\n        }\n\n        @Override\n        public void symlink(String file, String link) throws RemoteException {\n            try {\n                Os.symlink(file, link);\n            } catch (ErrnoException e) {\n                throw new RemoteException(e.getMessage());\n            }\n        }\n\n        @Override\n        public IBinder getService(String serviceName) throws RemoteException {\n            return ServiceManager.getService(serviceName);\n        }\n\n        @Override\n        public boolean onTransact(int code, @NonNull Parcel data, @Nullable Parcel reply, int flags) throws RemoteException {\n            if (code == ProxyBinder.PROXY_BINDER_TRANSACTION) {\n                data.enforceInterface(IRootServiceManager.class.getName());\n                transactRemote(data, reply);\n                return true;\n            }\n            return super.onTransact(code, data, reply, flags);\n        }\n\n        /**\n         * Call target Binder received through {@link ProxyBinder}.\n         *\n         * @author Rikka\n         */\n        private void transactRemote(@NonNull Parcel data, @Nullable Parcel reply) throws RemoteException {\n            IBinder targetBinder = data.readStrongBinder();\n            int targetCode = data.readInt();\n            int targetFlags = data.readInt();\n\n            Parcel newData = ParcelCompat2.obtain(targetBinder);\n            try {\n                newData.appendFrom(data, data.dataPosition(), data.dataAvail());\n                long id = Binder.clearCallingIdentity();\n                targetBinder.transact(targetCode, newData, reply, targetFlags);\n                Binder.restoreCallingIdentity(id);\n            } catch (RemoteException e) {\n                throw e;\n            } catch (Throwable th) {\n                throw (RemoteException) new RemoteException(th.getMessage()).initCause(th);\n            } finally {\n                newData.recycle();\n            }\n        }\n    }\n\n    @Override\n    public IBinder onBind(@NonNull Intent intent) {\n        Log.d(TAG, \"AMService: onBind\");\n        return new IAMServiceImpl();\n    }\n\n    @Override\n    public void onRebind(@NonNull Intent intent) {\n        super.onRebind(intent);\n    }\n\n    @Override\n    public boolean onUnbind(@NonNull Intent intent) {\n        return true;\n    }\n}"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/ipc/BinderHolder.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage io.github.muntashirakon.AppManager.ipc;\n\nimport android.os.IBinder;\nimport android.os.RemoteException;\n\nimport com.topjohnwu.superuser.internal.UiThreadHandler;\n\n// Copyright 2022 John \"topjohnwu\" Wu\nabstract class BinderHolder implements IBinder.DeathRecipient {\n    private final IBinder mBinder;\n\n    BinderHolder(IBinder b) throws RemoteException {\n        mBinder = b;\n        mBinder.linkToDeath(this, 0);\n    }\n\n    @Override\n    public final void binderDied() {\n        mBinder.unlinkToDeath(this, 0);\n        UiThreadHandler.run(this::onBinderDied);\n    }\n\n    protected abstract void onBinderDied();\n}"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/ipc/Container.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage io.github.muntashirakon.AppManager.ipc;\n\n// Copyright 2020 John \"topjohnwu\" Wu\nclass Container<T> {\n    public T obj;\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/ipc/FileSystemService.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.ipc;\n\nimport android.content.Intent;\nimport android.os.IBinder;\n\nimport androidx.annotation.NonNull;\n\nimport io.github.muntashirakon.io.FileSystemManager;\n\npublic class FileSystemService extends RootService {\n    @Override\n    public IBinder onBind(@NonNull Intent intent) {\n        return FileSystemManager.getService();\n    }\n\n    @Override\n    public void onRebind(@NonNull Intent intent) {\n        super.onRebind(intent);\n    }\n\n    @Override\n    public boolean onUnbind(@NonNull Intent intent) {\n        return true;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/ipc/HiddenAPIs.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage io.github.muntashirakon.AppManager.ipc;\n\nimport android.annotation.SuppressLint;\nimport android.content.Context;\nimport android.content.ContextWrapper;\nimport android.os.Build;\nimport android.os.IBinder;\nimport android.util.Log;\n\nimport java.lang.reflect.Method;\n\n/**\n * All hidden Android framework APIs used here are very stable.\n * <p>\n * These methods should only be accessed in the root process, since under normal circumstances\n * accessing these internal APIs through reflection will be blocked.\n */\n// Copyright 2020 John \"topjohnwu\" Wu\n@SuppressLint({\"PrivateApi,DiscouragedPrivateApi,SoonBlockedPrivateApi\", \"RestrictedApi\"})\nclass HiddenAPIs {\n    public static final String TAG = HiddenAPIs.class.getSimpleName();\n\n    private static Method sAddService;\n    private static Method sAttachBaseContext;\n    private static Method sSetAppName;\n\n    // Set this flag to silence AMS's complaints. Only exist on Android 8.0+\n    public static final int FLAG_RECEIVER_FROM_SHELL = Build.VERSION.SDK_INT >= 26 ? 0x00400000 : 0;\n\n    static {\n        try {\n            Class<?> sm = Class.forName(\"android.os.ServiceManager\");\n            if (Build.VERSION.SDK_INT >= 28) {\n                try {\n                    sAddService = sm.getDeclaredMethod(\"addService\",\n                            String.class, IBinder.class, boolean.class, int.class);\n                } catch (NoSuchMethodException ignored) {\n                    // Fallback to the 2 argument version\n                }\n            }\n            if (sAddService == null) {\n                sAddService = sm.getDeclaredMethod(\"addService\", String.class, IBinder.class);\n            }\n\n            sAttachBaseContext = ContextWrapper.class.getDeclaredMethod(\"attachBaseContext\", Context.class);\n            sAttachBaseContext.setAccessible(true);\n\n            Class<?> ddm = Class.forName(\"android.ddm.DdmHandleAppName\");\n            sSetAppName = ddm.getDeclaredMethod(\"setAppName\", String.class, int.class);\n        } catch (ReflectiveOperationException e) {\n            Log.e(TAG, e.getMessage(), e);\n        }\n    }\n\n    static void setAppName(String name) {\n        try {\n            sSetAppName.invoke(null, name, 0);\n        } catch (ReflectiveOperationException e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    static void addService(String name, IBinder service) {\n        try {\n            if (sAddService.getParameterTypes().length == 4) {\n                // Set dumpPriority to 0 so the service cannot be listed\n                sAddService.invoke(null, name, service, false, 0);\n            } else {\n                sAddService.invoke(null, name, service);\n            }\n        } catch (ReflectiveOperationException e) {\n            Log.e(TAG, e.getMessage(), e);\n        }\n    }\n\n    static void attachBaseContext(Object wrapper, Context context) {\n        if (wrapper instanceof ContextWrapper) {\n            try {\n                sAttachBaseContext.invoke(wrapper, context);\n            } catch (ReflectiveOperationException ignored) { /* Impossible */ }\n        }\n    }\n}"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/ipc/LocalServices.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.ipc;\n\nimport android.os.Process;\nimport android.os.RemoteException;\n\nimport androidx.annotation.AnyThread;\nimport androidx.annotation.MainThread;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.WorkerThread;\n\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.TimeUnit;\n\nimport io.github.muntashirakon.AppManager.BuildConfig;\nimport io.github.muntashirakon.AppManager.IAMService;\nimport io.github.muntashirakon.AppManager.misc.NoOps;\nimport io.github.muntashirakon.AppManager.settings.Ops;\nimport io.github.muntashirakon.AppManager.utils.ThreadUtils;\nimport io.github.muntashirakon.io.FileSystemManager;\n\npublic class LocalServices {\n    private static final Object sBindLock = new Object();\n\n    @NonNull\n    private static final ServiceConnectionWrapper sFileSystemServiceConnectionWrapper\n            = new ServiceConnectionWrapper(BuildConfig.APPLICATION_ID, FileSystemService.class.getName());\n\n    @WorkerThread\n    public static void bindServicesIfNotAlready() throws RemoteException {\n        if (!alive()) {\n            bindServices();\n        }\n    }\n\n    @WorkerThread\n    public static void bindServices() throws RemoteException {\n        synchronized (sBindLock) {\n            unbindServicesIfRunning();\n            bindAmService();\n            bindFileSystemManager();\n            // Verify binding\n            if (!getAmService().asBinder().pingBinder()) {\n                throw new RemoteException(\"IAmService not running.\");\n            }\n            getFileSystemManager();\n            // Update UID\n            Ops.setWorkingUid(getAmService().getUid());\n        }\n    }\n\n    public static boolean alive() {\n        synchronized (sAMServiceConnectionWrapper) {\n            return sAMServiceConnectionWrapper.isBinderActive();\n        }\n    }\n\n    @WorkerThread\n    @NoOps(used = true)\n    private static void bindFileSystemManager() throws RemoteException {\n        synchronized (sFileSystemServiceConnectionWrapper) {\n            try {\n                sFileSystemServiceConnectionWrapper.bindService();\n            } finally {\n                sFileSystemServiceConnectionWrapper.notifyAll();\n            }\n        }\n    }\n\n    @AnyThread\n    @NonNull\n    @NoOps\n    public static FileSystemManager getFileSystemManager() throws RemoteException {\n        synchronized (sFileSystemServiceConnectionWrapper) {\n            try {\n                return FileSystemManager.getRemote(sFileSystemServiceConnectionWrapper.getService());\n            } finally {\n                sFileSystemServiceConnectionWrapper.notifyAll();\n            }\n        }\n    }\n\n    @NonNull\n    private static final ServiceConnectionWrapper sAMServiceConnectionWrapper\n            = new ServiceConnectionWrapper(BuildConfig.APPLICATION_ID, AMService.class.getName());\n\n    @WorkerThread\n    @NoOps(used = true)\n    private static void bindAmService() throws RemoteException {\n        synchronized (sAMServiceConnectionWrapper) {\n            try {\n                sAMServiceConnectionWrapper.bindService();\n            } finally {\n                sAMServiceConnectionWrapper.notifyAll();\n            }\n        }\n    }\n\n    @AnyThread\n    @NonNull\n    @NoOps\n    public static IAMService getAmService() throws RemoteException {\n        synchronized (sAMServiceConnectionWrapper) {\n            try {\n                return IAMService.Stub.asInterface(sAMServiceConnectionWrapper.getService());\n            } finally {\n                sAMServiceConnectionWrapper.notifyAll();\n            }\n        }\n    }\n\n    @WorkerThread\n    @NoOps\n    public static void stopServices() {\n        synchronized (sAMServiceConnectionWrapper) {\n            sAMServiceConnectionWrapper.stopDaemon();\n        }\n        synchronized (sFileSystemServiceConnectionWrapper) {\n            sFileSystemServiceConnectionWrapper.stopDaemon();\n        }\n        Ops.setWorkingUid(Process.myUid());\n    }\n\n    @MainThread\n    public static void unbindServices() {\n        synchronized (sAMServiceConnectionWrapper) {\n            sAMServiceConnectionWrapper.unbindService();\n        }\n        synchronized (sFileSystemServiceConnectionWrapper) {\n            sFileSystemServiceConnectionWrapper.unbindService();\n        }\n        Ops.setWorkingUid(Process.myUid());\n    }\n\n    @WorkerThread\n    private static void unbindServicesIfRunning() {\n        // Basically unregister the services so that we can open another connection\n        CountDownLatch unbindWatcher = new CountDownLatch(1);\n        ThreadUtils.postOnMainThread(() -> {\n            try {\n                unbindServices();\n            } finally {\n                unbindWatcher.countDown();\n            }\n        });\n        try {\n            unbindWatcher.await(30, TimeUnit.SECONDS);\n        } catch (InterruptedException ignore) {\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/ipc/ProxyBinder.java",
    "content": "// SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.ipc;\n\nimport android.os.Build;\nimport android.os.IBinder;\nimport android.os.IInterface;\nimport android.os.Parcel;\nimport android.os.RemoteException;\nimport android.os.ResultReceiver;\nimport android.os.ServiceManager;\nimport android.os.ShellCallback;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.RequiresApi;\nimport androidx.collection.ArrayMap;\n\nimport org.jetbrains.annotations.NotNull;\n\nimport java.io.FileDescriptor;\nimport java.util.Collections;\nimport java.util.Map;\nimport java.util.Objects;\n\nimport io.github.muntashirakon.AppManager.compat.BinderCompat;\nimport io.github.muntashirakon.AppManager.logs.Log;\nimport io.github.muntashirakon.AppManager.server.common.IRootServiceManager;\nimport io.github.muntashirakon.compat.os.ParcelCompat2;\n\n// Copyright 2020 Rikka\npublic class ProxyBinder implements IBinder {\n    private static final String TAG = ProxyBinder.class.getSimpleName();\n    public static final int PROXY_BINDER_TRANSACTION = 2;\n    /**\n     * IBinder protocol transaction code: execute a shell command.\n     */\n    public static final int SHELL_COMMAND_TRANSACTION = ('_' << 24) | ('C' << 16) | ('M' << 8) | 'D';\n\n    private static final Map<String, IBinder> sServiceCache\n            = Collections.synchronizedMap(new ArrayMap<>());\n\n    @NonNull\n    public static IBinder getService(String serviceName) throws ServiceNotFoundException {\n        IBinder binder = sServiceCache.get(serviceName);\n        if (binder == null) {\n            binder = getServiceInternal(serviceName);\n            sServiceCache.put(serviceName, binder);\n        }\n        return new ProxyBinder(binder);\n    }\n\n    /**\n     * Some services can't be called without certain permissions\n     * so we redirect to AMService who can make that call no mater which mode it's in.\n     * as 0, 1000, and 2000 all have access to the overlay service.\n     *\n     * @param serviceName service to be loaded\n     * @return binder to that service\n     */\n    @NotNull\n    private static IBinder getServiceInternal(String serviceName) throws ServiceNotFoundException {\n        IBinder binder = ServiceManager.getService(serviceName);\n        if (LocalServices.alive() && binder == null) {\n            try {\n                binder = LocalServices.getAmService().getService(serviceName);\n            } catch (RemoteException e) {\n                Log.e(TAG, e);\n                throw new ServiceNotFoundException(\"Service couldn't be loaded: \" + serviceName, e);\n            }\n        }\n        if (binder == null) {\n            throw new ServiceNotFoundException(\"Service couldn't be found: \" + serviceName);\n        }\n        return binder;\n    }\n\n    @NonNull\n    public static IBinder getUnprivilegedService(String serviceName) throws ServiceNotFoundException {\n        IBinder binder = sServiceCache.get(serviceName);\n        if (binder == null) {\n            binder = ServiceManager.getService(serviceName);\n            sServiceCache.put(serviceName, binder);\n        }\n        if (binder == null) {\n            throw new ServiceNotFoundException(\"Service couldn't be found: \" + serviceName);\n        }\n        return binder;\n    }\n\n    /**\n     * @see BinderCompat#shellCommand(IBinder, FileDescriptor, FileDescriptor, FileDescriptor, String[], ShellCallback, ResultReceiver)\n     */\n    @RequiresApi(Build.VERSION_CODES.N)\n    public static void shellCommand(@NonNull IBinder binder,\n                                    @NonNull FileDescriptor in, @NonNull FileDescriptor out,\n                                    @NonNull FileDescriptor err,\n                                    @NonNull String[] args, @Nullable ShellCallback callback,\n                                    @NonNull ResultReceiver resultReceiver) throws RemoteException {\n        if (!(binder instanceof ProxyBinder)) {\n            BinderCompat.shellCommand(binder, in, out, err, args, callback, resultReceiver);\n            return;\n        }\n        ProxyBinder proxyBinder = (ProxyBinder) binder;\n        Parcel data = Parcel.obtain();\n        Parcel reply = Parcel.obtain();\n        data.writeFileDescriptor(in);\n        data.writeFileDescriptor(out);\n        data.writeFileDescriptor(err);\n        data.writeStringArray(args);\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {\n            ShellCallback.writeToParcel(callback, data);\n        }\n        resultReceiver.writeToParcel(data, 0);\n        try {\n            proxyBinder.transact(SHELL_COMMAND_TRANSACTION, data, reply, 0);\n            reply.readException();\n        } finally {\n            data.recycle();\n            reply.recycle();\n        }\n    }\n\n    private final IBinder mOriginal;\n\n    public ProxyBinder(@NonNull IBinder original) {\n        mOriginal = Objects.requireNonNull(original);\n    }\n\n    @Override\n    public boolean transact(int code, @NonNull Parcel data, @Nullable Parcel reply, int flags) throws RemoteException {\n        if (LocalServices.alive()) {\n            IBinder targetBinder = LocalServices.getAmService().asBinder();\n            Parcel newData = ParcelCompat2.obtain(targetBinder);\n            try {\n                newData.writeInterfaceToken(IRootServiceManager.class.getName());\n                newData.writeStrongBinder(mOriginal);\n                newData.writeInt(code);\n                newData.writeInt(flags);\n                newData.appendFrom(data, 0, data.dataSize());\n                // Transact via AMService\n                targetBinder.transact(PROXY_BINDER_TRANSACTION, newData, reply, 0);\n            } finally {\n                newData.recycle();\n            }\n            return true;\n        }\n        // Run unprivileged code as a fallback method\n        return mOriginal.transact(code, data, reply, flags);\n    }\n\n    @Nullable\n    @Override\n    public String getInterfaceDescriptor() {\n        try {\n            return mOriginal.getInterfaceDescriptor();\n        } catch (RemoteException e) {\n            throw new IllegalStateException(e.getClass().getSimpleName(), e);\n        }\n    }\n\n    @Override\n    public boolean pingBinder() {\n        return mOriginal.pingBinder();\n    }\n\n    @Override\n    public boolean isBinderAlive() {\n        return mOriginal.isBinderAlive();\n    }\n\n    @Nullable\n    @Override\n    public IInterface queryLocalInterface(@NonNull String descriptor) {\n        return null;\n    }\n\n    @Override\n    public void dump(@NonNull FileDescriptor fd, @Nullable String[] args) {\n        try {\n            mOriginal.dump(fd, args);\n        } catch (RemoteException e) {\n            throw new IllegalStateException(e.getClass().getSimpleName(), e);\n        }\n    }\n\n    @Override\n    public void dumpAsync(@NonNull FileDescriptor fd, @Nullable String[] args) {\n        try {\n            mOriginal.dumpAsync(fd, args);\n        } catch (RemoteException e) {\n            throw new IllegalStateException(e.getClass().getSimpleName(), e);\n        }\n    }\n\n    @Override\n    public void linkToDeath(@NonNull DeathRecipient recipient, int flags) {\n        try {\n            mOriginal.linkToDeath(recipient, flags);\n        } catch (RemoteException e) {\n            throw new IllegalStateException(e.getClass().getSimpleName(), e);\n        }\n    }\n\n    @Override\n    public boolean unlinkToDeath(@NonNull DeathRecipient recipient, int flags) {\n        return mOriginal.unlinkToDeath(recipient, flags);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/ipc/RemoteProcess.java",
    "content": "// SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.ipc;\n\nimport android.os.IBinder;\nimport android.os.Parcel;\nimport android.os.ParcelFileDescriptor;\nimport android.os.Parcelable;\nimport android.os.RemoteException;\n\nimport androidx.annotation.NonNull;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.util.concurrent.TimeUnit;\n\nimport io.github.muntashirakon.AppManager.IRemoteProcess;\n\n// Copyright 2020 Rikka\n// Copyright 2023 Muntashir Al-Islam\npublic class RemoteProcess extends Process implements Parcelable {\n    private final IRemoteProcess mRemote;\n    private OutputStream mOs;\n    private InputStream mIs;\n\n    public RemoteProcess(IRemoteProcess remote) {\n        mRemote = remote;\n    }\n\n    @Override\n    public OutputStream getOutputStream() {\n        if (mOs == null) {\n            mOs = new RemoteOutputStream(mRemote);\n        }\n        return mOs;\n    }\n\n    @Override\n    public InputStream getInputStream() {\n        if (mIs == null) {\n            try {\n                mIs = new ParcelFileDescriptor.AutoCloseInputStream(mRemote.getInputStream());\n            } catch (RemoteException e) {\n                throw new RuntimeException(e);\n            }\n        }\n        return mIs;\n    }\n\n    @Override\n    public InputStream getErrorStream() {\n        try {\n            return new ParcelFileDescriptor.AutoCloseInputStream(mRemote.getErrorStream());\n        } catch (RemoteException e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    @Override\n    public int waitFor() throws InterruptedException {\n        try {\n            return mRemote.waitFor();\n        } catch (RemoteException e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    @Override\n    public int exitValue() {\n        try {\n            return mRemote.exitValue();\n        } catch (RemoteException e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    @Override\n    public void destroy() {\n        try {\n            mRemote.destroy();\n        } catch (RemoteException e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    public boolean alive() {\n        try {\n            return mRemote.alive();\n        } catch (RemoteException e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    public boolean waitForTimeout(long timeout, TimeUnit unit) throws InterruptedException {\n        try {\n            return mRemote.waitForTimeout(timeout, unit.toString());\n        } catch (RemoteException e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    public IBinder asBinder() {\n        return mRemote.asBinder();\n    }\n\n    private RemoteProcess(Parcel in) {\n        mRemote = IRemoteProcess.Stub.asInterface(in.readStrongBinder());\n    }\n\n    public static final Creator<RemoteProcess> CREATOR = new Creator<RemoteProcess>() {\n        @Override\n        public RemoteProcess createFromParcel(Parcel in) {\n            return new RemoteProcess(in);\n        }\n\n        @Override\n        public RemoteProcess[] newArray(int size) {\n            return new RemoteProcess[size];\n        }\n    };\n\n    @Override\n    public int describeContents() {\n        return 0;\n    }\n\n    @Override\n    public void writeToParcel(Parcel dest, int flags) {\n        dest.writeStrongBinder(mRemote.asBinder());\n    }\n\n    private static class RemoteOutputStream extends OutputStream {\n        @NonNull\n        private final IRemoteProcess mRemoteProcess;\n        private OutputStream mOutputStream;\n        private boolean mIsClosed = false;\n\n        public RemoteOutputStream(@NonNull IRemoteProcess remoteProcess) {\n            mRemoteProcess = remoteProcess;\n        }\n\n        @Override\n        public void write(int b) throws IOException {\n            if (mIsClosed) {\n                throw new IOException(\"Remote is closed.\");\n            }\n            if (mOutputStream == null) {\n                try {\n                    mOutputStream = new ParcelFileDescriptor.AutoCloseOutputStream(mRemoteProcess.getOutputStream());\n                } catch (RemoteException e) {\n                    throw new IOException(e);\n                }\n            }\n            mOutputStream.write(b);\n        }\n\n        @Override\n        public void flush() throws IOException {\n            if (mIsClosed) {\n                throw new IOException(\"Remote is closed.\");\n            }\n            if (mOutputStream != null) {\n                mOutputStream.close();\n            }\n            mOutputStream = null;\n        }\n\n        @Override\n        public void close() throws IOException {\n            mIsClosed = true;\n            if (mOutputStream != null) {\n                mOutputStream.close();\n            }\n            try {\n                mRemoteProcess.closeOutputStream();\n            } catch (RemoteException e) {\n                throw new IOException(e);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/ipc/RemoteProcessImpl.java",
    "content": "// SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.ipc;\n\nimport android.os.ParcelFileDescriptor;\nimport android.os.SystemClock;\nimport android.util.Log;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.TimeUnit;\n\nimport io.github.muntashirakon.AppManager.IRemoteProcess;\nimport io.github.muntashirakon.io.IoUtils;\n\n// Copyright 2020 Rikka\n// Copyright 2023 Muntashir Al-Islam\npublic class RemoteProcessImpl extends IRemoteProcess.Stub {\n    private final Process mProcess;\n    private ParcelFileDescriptor mIn;\n    private OutputTransferThread mOutputTransferThread;\n\n    public RemoteProcessImpl(Process process) {\n        mProcess = process;\n    }\n\n    @Override\n    public ParcelFileDescriptor getOutputStream() {\n        if (mOutputTransferThread == null) {\n            mOutputTransferThread = new OutputTransferThread(mProcess);\n            mOutputTransferThread.start();\n        }\n        try {\n            return mOutputTransferThread.getWriteSide();\n        } catch (IOException | InterruptedException e) {\n            throw new IllegalStateException(e);\n        }\n    }\n\n    @Override\n    public void closeOutputStream() {\n        if (mOutputTransferThread != null) {\n            mOutputTransferThread.interrupt();\n        }\n    }\n\n    @Override\n    public ParcelFileDescriptor getInputStream() {\n        if (mIn == null) {\n            try {\n                InputTransferThread thread = new InputTransferThread(mProcess, false);\n                thread.start();\n                mIn = thread.getReadSide();\n            } catch (IOException | InterruptedException e) {\n                throw new IllegalStateException(e);\n            }\n        }\n        return mIn;\n    }\n\n    @Override\n    public ParcelFileDescriptor getErrorStream() {\n        try {\n            InputTransferThread thread = new InputTransferThread(mProcess, true);\n            thread.start();\n            return thread.getReadSide();\n        } catch (IOException | InterruptedException e) {\n            throw new IllegalStateException(e);\n        }\n    }\n\n    @Override\n    public int waitFor() {\n        try {\n            return mProcess.waitFor();\n        } catch (InterruptedException e) {\n            throw new IllegalStateException(e);\n        }\n    }\n\n    @Override\n    public int exitValue() {\n        return mProcess.exitValue();\n    }\n\n    @Override\n    public void destroy() {\n        mProcess.destroy();\n    }\n\n    @Override\n    public boolean alive() {\n        try {\n            exitValue();\n            return false;\n        } catch (IllegalThreadStateException e) {\n            return true;\n        }\n    }\n\n    @Override\n    public boolean waitForTimeout(long timeout, String unitName) {\n        TimeUnit unit = TimeUnit.valueOf(unitName);\n        long startTime = System.nanoTime();\n        long rem = unit.toNanos(timeout);\n\n        do {\n            try {\n                exitValue();\n                return true;\n            } catch (IllegalThreadStateException ex) {\n                if (rem > 0) {\n                    SystemClock.sleep(Math.min(TimeUnit.NANOSECONDS.toMillis(rem) + 1, 100));\n                }\n            }\n            rem = unit.toNanos(timeout) - (System.nanoTime() - startTime);\n        } while (rem > 0);\n        return false;\n    }\n\n    private static class OutputTransferThread extends Thread {\n        private final Process mProcess;\n        private OutputStream mProcessOutputStream;\n        @Nullable\n        private volatile ParcelFileDescriptor mWriteSide;\n        @NonNull\n        private CountDownLatch mWaitForWriteSide;\n\n        private OutputTransferThread(Process process) {\n            super();\n            mProcess = process;\n            mWaitForWriteSide = new CountDownLatch(1);\n            setDaemon(true);\n        }\n\n        @NonNull\n        public ParcelFileDescriptor getWriteSide() throws IOException, InterruptedException {\n            mWaitForWriteSide.await();\n            ParcelFileDescriptor writeSide = mWriteSide;\n            if (writeSide == null) {\n                throw new IOException(\"Could not get the write side\");\n            }\n            return writeSide;\n        }\n\n        @Override\n        public void run() {\n            if (mProcessOutputStream == null) {\n                mProcessOutputStream = mProcess.getOutputStream();\n            }\n            try {\n                do {\n                    if (mWaitForWriteSide.getCount() == 0) {\n                        mWaitForWriteSide = new CountDownLatch(1);\n                    }\n                    ParcelFileDescriptor[] pipe = ParcelFileDescriptor.createPipe();\n                    ParcelFileDescriptor readSide = pipe[0];\n                    mWriteSide = pipe[1];\n                    mWaitForWriteSide.countDown();\n                    try (InputStream in = new ParcelFileDescriptor.AutoCloseInputStream(readSide)) {\n                        byte[] buf = new byte[IoUtils.DEFAULT_BUFFER_SIZE];\n                        int len;\n                        while ((len = in.read(buf)) > 0) {\n                            mProcessOutputStream.write(buf, 0, len);\n                        }\n                    }\n                    mProcessOutputStream.flush();\n                } while (!isInterrupted());\n                mProcessOutputStream.close();\n            } catch (IOException e) {\n                Log.e(\"FD\", \"IOException when writing to out\", e);\n                mWaitForWriteSide.countDown();\n            }\n        }\n    }\n\n    private static class InputTransferThread extends Thread {\n        private final Process mProcess;\n        private final boolean mErrorStream;\n        @NonNull\n        private final CountDownLatch mWaitForReadSide;\n        @Nullable\n        private volatile ParcelFileDescriptor mReadSide;\n\n        InputTransferThread(Process process, boolean errorStream) {\n            super();\n            mProcess = process;\n            mErrorStream = errorStream;\n            mWaitForReadSide = new CountDownLatch(1);\n            setDaemon(true);\n        }\n\n        @NonNull\n        public ParcelFileDescriptor getReadSide() throws IOException, InterruptedException {\n            mWaitForReadSide.await();\n            ParcelFileDescriptor writeSide = mReadSide;\n            if (writeSide == null) {\n                throw new IOException(\"Could not get the write side\");\n            }\n            return writeSide;\n        }\n\n        @Override\n        public void run() {\n            try {\n                ParcelFileDescriptor[] pipe = ParcelFileDescriptor.createPipe();\n                mReadSide = pipe[0];\n                ParcelFileDescriptor writeSide = pipe[1];\n                mWaitForReadSide.countDown();\n                try (OutputStream out = new ParcelFileDescriptor.AutoCloseOutputStream(writeSide);\n                     InputStream in = mErrorStream ? mProcess.getErrorStream() : mProcess.getInputStream()) {\n                    byte[] buf = new byte[IoUtils.DEFAULT_BUFFER_SIZE];\n                    int len;\n                    while ((len = in.read(buf)) > 0) {\n                        out.write(buf, 0, len);\n                    }\n                }\n            } catch (IOException e) {\n                Log.e(\"FD\", \"IOException when writing to out\", e);\n                mWaitForReadSide.countDown();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/ipc/RemoteShellImpl.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.ipc;\n\nimport android.os.ParcelFileDescriptor;\n\nimport com.topjohnwu.superuser.Shell;\n\nimport aosp.android.content.pm.StringParceledListSlice;\nimport io.github.muntashirakon.AppManager.BuildConfig;\nimport io.github.muntashirakon.AppManager.IRemoteShell;\nimport io.github.muntashirakon.AppManager.IShellResult;\n\nclass RemoteShellImpl extends IRemoteShell.Stub {\n    static {\n        Shell.enableVerboseLogging = BuildConfig.DEBUG;\n        Shell.setDefaultBuilder(Shell.Builder.create()\n                .setFlags(Shell.FLAG_MOUNT_MASTER)\n                .setTimeout(10));\n    }\n\n    private final Shell.Job mJob;\n\n    public RemoteShellImpl(String[] cmd) {\n        mJob = Shell.cmd(cmd);\n    }\n\n    @Override\n    public void addCommand(String[] commands) {\n        mJob.add(commands);\n    }\n\n    @Override\n    public void addInputStream(ParcelFileDescriptor inputStream) {\n        mJob.add(new ParcelFileDescriptor.AutoCloseInputStream(inputStream));\n    }\n\n    @Override\n    public IShellResult exec() {\n        Shell.Result result = mJob.exec();\n        return new IShellResult.Stub() {\n            @Override\n            public StringParceledListSlice getStdout() {\n                return new StringParceledListSlice(result.getOut());\n            }\n\n            @Override\n            public StringParceledListSlice getStderr() {\n                return new StringParceledListSlice(result.getErr());\n            }\n\n            @Override\n            public int getExitCode() {\n                return result.getCode();\n            }\n\n            @Override\n            public boolean isSuccessful() {\n                return result.isSuccess();\n            }\n        };\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/ipc/RootService.java",
    "content": "// SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.ipc;\n\nimport android.annotation.SuppressLint;\nimport android.app.Service;\nimport android.content.ComponentName;\nimport android.content.Context;\nimport android.content.ContextWrapper;\nimport android.content.Intent;\nimport android.content.ServiceConnection;\nimport android.os.IBinder;\nimport android.os.Messenger;\nimport android.util.Log;\n\nimport androidx.annotation.MainThread;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport com.topjohnwu.superuser.Shell;\nimport com.topjohnwu.superuser.internal.UiThreadHandler;\n\nimport java.io.ByteArrayOutputStream;\nimport java.util.concurrent.Executor;\n\nimport io.github.muntashirakon.AppManager.BuildConfig;\nimport io.github.muntashirakon.AppManager.runner.Runner;\nimport io.github.muntashirakon.AppManager.servermanager.LocalServer;\nimport io.github.muntashirakon.AppManager.settings.Ops;\nimport io.github.muntashirakon.AppManager.utils.ContextUtils;\n\n/**\n * A remote root service using native Android Binder IPC.\n * <p>\n * Important: while developing an app with RootServices, modify the run/debug configuration and\n * check the \"Always install with package manager\" option if testing on Android 11+, or else the\n * code changes will not be reflected after Android Studio's deployment.\n * <p>\n * This class is almost a complete recreation of a bound service running in a root process.\n * Instead of using the original {@code Context.bindService(...)} methods to start and bind\n * to a service, use the provided static methods {@code RootService.bind(...)}.\n * Because the service will not run in the same process as your application, you have to use either\n * {@link Messenger} or AIDL to define the IPC interface for communication. Please read the\n * official documentations for more details.\n * <p>\n * Even though a {@code RootService} is a {@link Context} of your application, the ContextImpl\n * is not constructed in a normal way, so the functionality is much more limited compared\n * to the normal case. Be aware of this and do not expect all context methods to work.\n * <p>\n * All RootServices launched from the same process will run in the same root process.\n * A root service will be destroyed as soon as there are no clients bound to it.\n * This means all services will be destroyed immediately when the client process is terminated.\n * The library will NOT attempt to automatically restart and bind to a service after it was unbound.\n * <p>\n * <strong>Daemon Mode:</strong><br>\n * If you want the service to run in the background independent from the application lifecycle,\n * launch the service in \"Daemon Mode\". Check the description of {@link #CATEGORY_DAEMON_MODE}\n * for instructions on how to do so.\n * All services running in \"Daemon Mode\" will run in a daemon process created per-package that\n * is separate from regular root services. This daemon process will be used across application\n * re-launches, and even across different users on the device.\n * A root service running in \"Daemon Mode\" will be destroyed when any client called\n * {@link #stop(Intent)}, or the root service itself called {@link #stopSelf()}.\n * <p>\n * A root service process, including the daemon process, will terminate under these conditions:\n * <ul>\n *     <li>When the application is updated or deleted</li>\n *     <li>When all services running in the process are destroyed\n *         (after {@link #onDestroy()} is called)</li>\n * </ul>\n *\n * @see <a href=\"https://developer.android.com/guide/components/bound-services\">Bound services</a>\n * @see <a href=\"https://developer.android.com/guide/components/aidl\">Android Interface Definition Language (AIDL)</a>\n */\n// Copyright 2020 John \"topjohnwu\" Wu\npublic abstract class RootService extends ContextWrapper {\n    /**\n     * Launch the service in \"Daemon Mode\".\n     * <p>\n     * Add this category in the intent passed to {@link #bind(Intent, ServiceConnection)},\n     * {@link #bind(Intent, Executor, ServiceConnection)}, or\n     * {@link #bindOrTask(Intent, Executor, ServiceConnection)}\n     * to have the service launch in \"Daemon Mode\".\n     * This category also has to be added in the intent passed to {@link #stop(Intent)}\n     * and {@link #stopOrTask(Intent)} in order to refer to a daemon service instead of\n     * a regular root service.\n     */\n    public static final String CATEGORY_DAEMON_MODE = BuildConfig.APPLICATION_ID + \".DAEMON_MODE\";\n\n    static final String TAG = RootService.class.getSimpleName();\n\n    /**\n     * Bind to a root service, launching a new root process if needed.\n     *\n     * @param intent   identifies the service to connect to.\n     * @param executor callbacks on ServiceConnection will be called on this executor.\n     * @param conn     receives information as the service is started and stopped.\n     * @see Context#bindService(Intent, int, Executor, ServiceConnection)\n     */\n    @MainThread\n    public static void bind(\n            @NonNull Intent intent,\n            @NonNull Executor executor,\n            @NonNull ServiceConnection conn) {\n        Shell.Task task = bindOrTask(intent, executor, conn);\n        if (task != null) {\n            Shell.EXECUTOR.execute(asRunnable(task));\n        }\n    }\n\n    /**\n     * Bind to a root service, launching a new root process if needed.\n     *\n     * @param intent identifies the service to connect to.\n     * @param conn   receives information as the service is started and stopped.\n     * @see Context#bindService(Intent, ServiceConnection, int)\n     */\n    @MainThread\n    public static void bind(@NonNull Intent intent, @NonNull ServiceConnection conn) {\n        bind(intent, UiThreadHandler.executor, conn);\n    }\n\n    /**\n     * Bind to a root service, creating a task to launch a new root process if needed.\n     * <p>\n     * If the application is already connected to a root process, binding will happen immediately\n     * and this method will return {@code null}. Or else this method returns a {@link Shell.Task}\n     * that has to be executed to launch the root process. Binding will only happen after the\n     * developer has executed the returned task with {@link Shell#execTask(Shell.Task)}.\n     *\n     * @return the task to launch a root process. If there is no need to launch a new root\n     * process, {@code null} is returned.\n     * @see #bind(Intent, Executor, ServiceConnection)\n     */\n    @MainThread\n    @Nullable\n    public static Shell.Task bindOrTask(\n            @NonNull Intent intent,\n            @NonNull Executor executor,\n            @NonNull ServiceConnection conn) {\n        return RootServiceManager.getInstance().createBindTask(intent, executor, conn);\n    }\n\n    /**\n     * Unbind from a root service.\n     *\n     * @param conn the connection interface previously supplied to\n     *             {@link #bind(Intent, ServiceConnection)}\n     * @see Context#unbindService(ServiceConnection)\n     */\n    @MainThread\n    public static void unbind(@NonNull ServiceConnection conn) {\n        RootServiceManager.getInstance().unbind(conn);\n    }\n\n    /**\n     * Force stop a root service, launching a new root process if needed.\n     * <p>\n     * This method is used to immediately stop a root service regardless of its state.\n     * ONLY use this method to stop a daemon root service; for normal root services, please use\n     * {@link #unbind(ServiceConnection)} instead as this method has to potentially launch\n     * an additional root process to ensure daemon services are stopped.\n     *\n     * @param intent identifies the service to stop.\n     */\n    @MainThread\n    public static void stop(@NonNull Intent intent) {\n        Shell.Task task = stopOrTask(intent);\n        if (task != null) {\n            Shell.EXECUTOR.execute(asRunnable(task));\n        }\n    }\n\n    /**\n     * Force stop a root service, creating a task to launch a new root process if needed.\n     * <p>\n     * This method returns a {@link Shell.Task} that has to be executed to launch a\n     * root process if necessary, or else {@code null} will be returned.\n     *\n     * @see #stop(Intent)\n     */\n    @MainThread\n    @Nullable\n    public static Shell.Task stopOrTask(@NonNull Intent intent) {\n        return RootServiceManager.getInstance().createStopTask(intent);\n    }\n\n    private static Runnable asRunnable(Shell.Task task) {\n        return () -> {\n            try {\n                // Run task while fetching the entire command.\n                ByteArrayOutputStream os = new ByteArrayOutputStream();\n                // This works because we do not need the other streams.\n                task.run(os, null, null);\n                // The whole command has now been fetched.\n                String cmd = os.toString();\n                if (Ops.isDirectRoot()) {\n                    if (!Runner.runCommand(cmd).isSuccessful()) {\n                        Log.e(TAG, \"Couldn't start service using root.\", new Throwable());\n                    }\n                } else if (LocalServer.alive(ContextUtils.getContext())) {\n                    if (LocalServer.getInstance().runCommand(cmd).getStatusCode() != 0) {\n                        Log.e(TAG, \"Couldn't start service using ADB.\", new Throwable());\n                    }\n                } else {\n                    Log.e(TAG, \"Unable to start service using an unsupported mode.\", new Throwable());\n                }\n            } catch (Throwable e) {\n                Log.e(TAG, e.getMessage(), e);\n            }\n        };\n    }\n\n    public RootService() {\n        super(null);\n    }\n\n    @SuppressLint(\"RestrictedApi\")\n    @Override\n    protected final void attachBaseContext(Context base) {\n        super.attachBaseContext(onAttach(ContextUtils.getContextImpl(base)));\n        RootServiceServer.getInstance(base).register(this);\n        onCreate();\n    }\n\n    /**\n     * Called when the RootService is getting attached with a {@link Context}.\n     *\n     * @param base the context being attached.\n     * @return the passed in context by default.\n     */\n    @NonNull\n    protected Context onAttach(@NonNull Context base) {\n        return base;\n    }\n\n    /**\n     * Return the component name that will be used for service lookup.\n     * <p>\n     * Overriding this method is only for very unusual use cases when a different\n     * component name other than the actual class name is desired.\n     *\n     * @return the desired component name.\n     */\n    @NonNull\n    public ComponentName getComponentName() {\n        return new ComponentName(this, getClass());\n    }\n\n    @SuppressLint(\"RestrictedApi\")\n    @Override\n    public final Context getApplicationContext() {\n        return ContextUtils.rootContext;\n    }\n\n    /**\n     * @see Service#onBind(Intent)\n     */\n    abstract public IBinder onBind(@NonNull Intent intent);\n\n    /**\n     * @see Service#onCreate()\n     */\n    public void onCreate() {\n    }\n\n    /**\n     * @see Service#onUnbind(Intent)\n     */\n    public boolean onUnbind(@NonNull Intent intent) {\n        return false;\n    }\n\n    /**\n     * @see Service#onRebind(Intent)\n     */\n    public void onRebind(@NonNull Intent intent) {\n    }\n\n    /**\n     * @see Service#onDestroy()\n     */\n    public void onDestroy() {\n    }\n\n    /**\n     * Force stop this root service.\n     */\n    public final void stopSelf() {\n        RootServiceServer.getInstance(this).selfStop(getComponentName());\n    }\n\n    // Deprecated APIs\n\n    /**\n     * @deprecated use {@link #bindOrTask(Intent, Executor, ServiceConnection)}\n     */\n    @MainThread\n    @Nullable\n    @Deprecated\n    public static Runnable createBindTask(\n            @NonNull Intent intent,\n            @NonNull Executor executor,\n            @NonNull ServiceConnection conn) {\n        Shell.Task task = bindOrTask(intent, executor, conn);\n        return task == null ? null : asRunnable(task);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/ipc/RootServiceManager.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage io.github.muntashirakon.AppManager.ipc;\n\nimport static io.github.muntashirakon.AppManager.ipc.RootService.CATEGORY_DAEMON_MODE;\nimport static io.github.muntashirakon.AppManager.server.common.ServerUtils.CMDLINE_START_DAEMON;\nimport static io.github.muntashirakon.AppManager.server.common.ServerUtils.CMDLINE_START_SERVICE;\nimport static io.github.muntashirakon.AppManager.server.common.ServerUtils.CMDLINE_STOP_SERVICE;\nimport static io.github.muntashirakon.AppManager.utils.PackageUtils.PACKAGE_STAGING_DIRECTORY;\n\nimport android.annotation.SuppressLint;\nimport android.content.BroadcastReceiver;\nimport android.content.ComponentName;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.IntentFilter;\nimport android.content.ServiceConnection;\nimport android.os.Build;\nimport android.os.Bundle;\nimport android.os.Debug;\nimport android.os.Handler;\nimport android.os.IBinder;\nimport android.os.Looper;\nimport android.os.Message;\nimport android.os.Messenger;\nimport android.os.Process;\nimport android.os.RemoteException;\nimport android.util.ArrayMap;\nimport android.util.Log;\nimport android.util.Pair;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.RestrictTo;\nimport androidx.core.content.ContextCompat;\n\nimport com.topjohnwu.superuser.Shell;\nimport com.topjohnwu.superuser.ShellUtils;\nimport com.topjohnwu.superuser.internal.Utils;\n\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.nio.charset.StandardCharsets;\nimport java.util.ArrayList;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Map;\nimport java.util.concurrent.Executor;\n\nimport io.github.muntashirakon.AppManager.BuildConfig;\nimport io.github.muntashirakon.AppManager.compat.ManifestCompat;\nimport io.github.muntashirakon.AppManager.server.common.IRootServiceManager;\nimport io.github.muntashirakon.AppManager.settings.Ops;\nimport io.github.muntashirakon.AppManager.utils.ContextUtils;\nimport io.github.muntashirakon.AppManager.utils.FileUtils;\nimport io.github.muntashirakon.AppManager.utils.PackageUtils;\n\n/**\n * Runs in the non-root (client) process.\n * <p>\n * Starts the root process and manages connections with the remote process.\n */\n// Copyright 2021 John \"topjohnwu\" Wu\n@RestrictTo(RestrictTo.Scope.LIBRARY)\npublic class RootServiceManager implements Handler.Callback {\n    static final String TAG = RootServiceManager.class.getSimpleName();\n    static final String LOGGING_ENV = \"AM_VERBOSE_LOGGING\";\n    static final String DEBUG_ENV = \"AM_DEBUGGER\";\n    static final String CLASSPATH_ENV = \"CLASSPATH\";\n\n    static final int MSG_STOP = 1;\n\n    private static final String BUNDLE_BINDER_KEY = \"binder\";\n    private static final String INTENT_BUNDLE_KEY = \"extra.bundle\";\n    private static final String INTENT_DAEMON_KEY = \"extra.daemon\";\n    private static final String RECEIVER_BROADCAST = BuildConfig.APPLICATION_ID + \".RECEIVER_BROADCAST\";\n    private static final String API_27_DEBUG =\n            \"-Xrunjdwp:transport=dt_android_adb,suspend=n,server=y \" +\n                    \"-Xcompiler-option --debuggable\";\n    private static final String API_28_DEBUG =\n            \"-XjdwpProvider:adbconnection -XjdwpOptions:suspend=n,server=y \" +\n                    \"-Xcompiler-option --debuggable\";\n    private static final String JVMTI_ERROR = \" \\n\" +\n            \"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\\n\" +\n            \"! Warning: JVMTI agent is enabled. Please enable the !\\n\" +\n            \"! 'Always install with package manager' option in    !\\n\" +\n            \"! Android Studio. For more details and information,  !\\n\" +\n            \"! check out RootService's Javadoc.                   !\\n\" +\n            \"!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!\\n\";\n\n    private static final int REMOTE_EN_ROUTE = 1 << 0;\n    private static final int DAEMON_EN_ROUTE = 1 << 1;\n    private static final int RECEIVER_REGISTERED = 1 << 2;\n\n    private static final String IPCMAIN_CLASSNAME = \"io.github.muntashirakon.AppManager.server.RootServiceMain\";\n\n    private static RootServiceManager sInstance;\n\n    public static RootServiceManager getInstance() {\n        if (sInstance == null) {\n            sInstance = new RootServiceManager();\n        }\n        return sInstance;\n    }\n\n    @SuppressLint(\"WrongConstant\")\n    static Intent getBroadcastIntent(IBinder binder, boolean isDaemon) {\n        Bundle bundle = new Bundle();\n        bundle.putBinder(BUNDLE_BINDER_KEY, binder);\n        return new Intent(RECEIVER_BROADCAST)\n                .setPackage(ContextUtils.rootContext.getPackageName())\n                .addFlags(HiddenAPIs.FLAG_RECEIVER_FROM_SHELL)\n                .putExtra(INTENT_DAEMON_KEY, isDaemon)\n                .putExtra(INTENT_BUNDLE_KEY, bundle);\n    }\n\n    private static void enforceMainThread() {\n        if (!ShellUtils.onMainThread()) {\n            throw new IllegalStateException(\"This method can only be called on the main thread\");\n        }\n    }\n\n    @NonNull\n    private static ServiceKey parseIntent(Intent intent) {\n        ComponentName name = intent.getComponent();\n        if (name == null) {\n            throw new IllegalArgumentException(\"The intent does not have a component set\");\n        }\n        if (!name.getPackageName().equals(ContextUtils.getContext().getPackageName())) {\n            throw new IllegalArgumentException(\"RootServices outside of the app are not supported\");\n        }\n        return new ServiceKey(name, intent.hasCategory(CATEGORY_DAEMON_MODE));\n    }\n\n    private RemoteProcess mRemote;\n    private RemoteProcess mDaemon;\n\n    private int mFlags = 0;\n\n    private final List<BindTask> mPendingTasks = new ArrayList<>();\n    private final Map<ServiceKey, RemoteServiceRecord> mServices = new ArrayMap<>();\n    private final Map<ServiceConnection, ConnectionRecord> mConnections = new ArrayMap<>();\n\n    private RootServiceManager() {\n    }\n\n    @SuppressLint(\"RestrictedApi\")\n    private Shell.Task startRootProcess(ComponentName name, String action) {\n        Context context = ContextUtils.getContext();\n\n        if ((mFlags & RECEIVER_REGISTERED) == 0) {\n            // Register receiver to receive binder from root process\n            IntentFilter filter = new IntentFilter(RECEIVER_BROADCAST);\n            // Guard the receiver behind permission UPDATE_APP_OPS_STATS. This permission\n            // is not obtainable by normal apps, making the receiver effectively non-exported,\n            // but will allow any root/ADB/system process to send broadcast message.\n            ContextCompat.registerReceiver(context, new ServiceReceiver(), filter,\n                    ManifestCompat.permission.UPDATE_APP_OPS_STATS, null, ContextCompat.RECEIVER_EXPORTED);\n            mFlags |= RECEIVER_REGISTERED;\n        }\n\n        return (stdin, stdout, stderr) -> {\n            if (Utils.hasStartupAgents(context)) {\n                Log.e(TAG, JVMTI_ERROR);\n            }\n\n            String mainJarName = \"main.jar\";\n            Context ctx = ContextUtils.getContext();\n            Context de = ContextUtils.getDeContext(ctx);\n            File mainJar;\n            try {\n                mainJar = new File(FileUtils.getExternalCachePath(de), mainJarName);\n            } catch (IOException e) {\n                throw new IllegalStateException(\"External directory unavailable.\", e);\n            }\n            File stagingMainJar = new File(PACKAGE_STAGING_DIRECTORY, mainJarName);\n            // Dump main.jar as trampoline\n            try (InputStream in = context.getResources().getAssets().open(\"main.jar\");\n                 OutputStream out = new FileOutputStream(mainJar)) {\n                Utils.pump(in, out);\n            }\n            FileUtils.chmod644(mainJar);\n\n            StringBuilder env = new StringBuilder();\n            String params = getParams(env);\n\n            String cmd = getRunnerScript(env, mainJar, stagingMainJar, name, action, params);\n            Log.d(TAG, cmd);\n            // Write command to stdin\n            byte[] bytes = cmd.getBytes(StandardCharsets.UTF_8);\n            stdin.write(bytes);\n            stdin.write('\\n');\n            stdin.flush();\n            // Since all output for the command is redirected to /dev/null and\n            // the command runs in the background, we don't need to wait and\n            // can just return.\n        };\n    }\n\n    @SuppressLint(\"RestrictedApi\")\n    @NonNull\n    private static String getParams(StringBuilder env) {\n        String params = \"\";\n\n        if (Utils.vLog()) {\n            env.append(LOGGING_ENV + \"=1 \");\n        }\n\n        // Only support debugging on SDK >= 27\n        if (Build.VERSION.SDK_INT >= 27 && Debug.isDebuggerConnected()) {\n            env.append(DEBUG_ENV + \"=1 \");\n            // Reference of the params to start jdwp:\n            // https://developer.android.com/ndk/guides/wrap-script#debugging_when_using_wrapsh\n            if (Build.VERSION.SDK_INT == 27) {\n                params = API_27_DEBUG;\n            } else {\n                params = API_28_DEBUG;\n            }\n        }\n\n        // Disable image dex2oat as it can be quite slow in some ROMs if triggered\n        return params + \" -Xnoimage-dex2oat\";\n    }\n\n    @NonNull\n    private String getRunnerScript(@NonNull StringBuilder env,\n                                   @NonNull File mainJar,\n                                   @NonNull File stagingMainJar,\n                                   @NonNull ComponentName serviceName,\n                                   @NonNull String action,\n                                   @NonNull String debugParams) {\n        // We cannot readlink /proc/self/exe on old kernels\n        @SuppressLint(\"RestrictedApi\")\n        String execFile = \"/system/bin/app_process\" + (Utils.isProcess64Bit() ? \"64\" : \"32\");\n        String packageStagingCommand;\n        env.append(CLASSPATH_ENV).append(\"=\");\n        if (Ops.hasRoot()) {\n            // Avoid using the package staging directory\n            env.append(mainJar);\n            packageStagingCommand = \"\";\n        } else if (!Ops.isSystem()) {\n            // Use package staging directory\n            env.append(stagingMainJar);\n            packageStagingCommand = PackageUtils.ensurePackageStagingDirectoryCommand() +\n                    // Copy to main.jar to package staging directory\n                    String.format(Locale.ROOT, \" && cp %s %s && \", mainJar, PACKAGE_STAGING_DIRECTORY) +\n                    // Change permission of the main.jar\n                    String.format(Locale.ROOT, \"chmod 755 %s && chown shell:shell %s && \", stagingMainJar, stagingMainJar);\n        } else {\n            // System can't use package staging directory\n            env.append(mainJar);\n            packageStagingCommand = \"\";\n        }\n        env.append(\" \");\n        return (packageStagingCommand +\n                String.format(Locale.ROOT, \"(%s %s %s /system/bin %s %s '%s' %d %s 2>&1)&\",\n                        env,                            // Environments\n                        execFile,                       // Executable\n                        debugParams,                    // Debug parameters\n                        getNiceNameArg(action),         // Process name\n                        IPCMAIN_CLASSNAME,              // Java command\n                        serviceName.flattenToString(),  // args[0]\n                        Process.myUid(),                // args[1]\n                        action));                       // args[2]\n    }\n\n    @NonNull\n    private String getNiceNameArg(@NonNull String action) {\n        switch (action) {\n            case CMDLINE_START_SERVICE:\n                return String.format(Locale.ROOT, \"--nice-name=%s:priv:%d\",\n                        BuildConfig.APPLICATION_ID, Process.myUid() / 100000);\n            case CMDLINE_START_DAEMON:\n                return \"--nice-name=\" + BuildConfig.APPLICATION_ID + \":priv:daemon\";\n            default:\n                return \"\";\n        }\n    }\n\n    // Returns null if binding is done synchronously, or else return key\n    private ServiceKey bindInternal(Intent intent, Executor executor, ServiceConnection conn) {\n        enforceMainThread();\n\n        // Local cache\n        ServiceKey key = parseIntent(intent);\n        RemoteServiceRecord s = mServices.get(key);\n        if (s != null) {\n            mConnections.put(conn, new ConnectionRecord(s, executor));\n            s.refCount++;\n            IBinder binder = s.binder;\n            executor.execute(() -> conn.onServiceConnected(key.getName(), binder));\n            return null;\n        }\n\n        RemoteProcess p = key.isDaemon() ? mDaemon : mRemote;\n        if (p == null)\n            return key;\n\n        try {\n            IBinder binder = p.mgr.bind(intent);\n            if (binder != null) {\n                s = new RemoteServiceRecord(key, binder, p);\n                mConnections.put(conn, new ConnectionRecord(s, executor));\n                mServices.put(key, s);\n                executor.execute(() -> conn.onServiceConnected(key.getName(), binder));\n            } else if (Build.VERSION.SDK_INT >= 28) {\n                executor.execute(() -> conn.onNullBinding(key.getName()));\n            }\n        } catch (RemoteException e) {\n            Log.e(TAG, e.getMessage(), e);\n            p.binderDied();\n            return key;\n        }\n\n        return null;\n    }\n\n    public Shell.Task createBindTask(Intent intent, Executor executor, ServiceConnection conn) {\n        ServiceKey key = bindInternal(intent, executor, conn);\n        if (key != null) {\n            mPendingTasks.add(() -> bindInternal(intent, executor, conn) == null);\n            int mask = key.isDaemon() ? DAEMON_EN_ROUTE : REMOTE_EN_ROUTE;\n            if ((mFlags & mask) == 0) {\n                mFlags |= mask;\n                String action = key.isDaemon() ? CMDLINE_START_DAEMON : CMDLINE_START_SERVICE;\n                return startRootProcess(key.getName(), action);\n            }\n        }\n        return null;\n    }\n\n    public void unbind(@NonNull ServiceConnection conn) {\n        enforceMainThread();\n\n        ConnectionRecord r = mConnections.remove(conn);\n        if (r != null) {\n            RemoteServiceRecord s = r.getService();\n            s.refCount--;\n            if (s.refCount == 0) {\n                // Actually close the service\n                mServices.remove(s.key);\n                try {\n                    s.host.mgr.unbind(s.key.getName());\n                } catch (RemoteException e) {\n                    Log.e(TAG, e.getMessage(), e);\n                }\n            }\n        }\n    }\n\n    private void dropConnections(Predicate predicate) {\n        Iterator<Map.Entry<ServiceConnection, ConnectionRecord>> it = mConnections.entrySet().iterator();\n        while (it.hasNext()) {\n            Map.Entry<ServiceConnection, ConnectionRecord> e = it.next();\n            ConnectionRecord r = e.getValue();\n            if (predicate.eval(r.getService())) {\n                r.disconnect(e.getKey());\n                it.remove();\n            }\n        }\n    }\n\n    private void onServiceStopped(ServiceKey key) {\n        RemoteServiceRecord s = mServices.remove(key);\n        if (s != null)\n            dropConnections(s::equals);\n    }\n\n    public Shell.Task createStopTask(Intent intent) {\n        enforceMainThread();\n\n        ServiceKey key = parseIntent(intent);\n        RemoteProcess p = key.isDaemon() ? mDaemon : mRemote;\n        if (p == null) {\n            if (key.isDaemon()) {\n                // Start a new root process to stop daemon\n                return startRootProcess(key.getName(), CMDLINE_STOP_SERVICE);\n            }\n            return null;\n        }\n\n        try {\n            p.mgr.stop(key.getName(), -1);\n        } catch (RemoteException e) {\n            Log.e(TAG, e.getMessage(), e);\n        }\n\n        onServiceStopped(key);\n        return null;\n    }\n\n    @Override\n    public boolean handleMessage(@NonNull Message msg) {\n        if (msg.what == MSG_STOP) {\n            onServiceStopped(new ServiceKey((ComponentName) msg.obj, msg.arg1 != 0));\n        }\n        return false;\n    }\n\n    private static class ServiceKey extends Pair<ComponentName, Boolean> {\n        ServiceKey(ComponentName name, boolean isDaemon) {\n            super(name, isDaemon);\n        }\n\n        ComponentName getName() {\n            return first;\n        }\n\n        boolean isDaemon() {\n            return second;\n        }\n    }\n\n    private static class ConnectionRecord extends Pair<RemoteServiceRecord, Executor> {\n        ConnectionRecord(RemoteServiceRecord s, Executor e) {\n            super(s, e);\n        }\n\n        RemoteServiceRecord getService() {\n            return first;\n        }\n\n        void disconnect(ServiceConnection conn) {\n            second.execute(() -> conn.onServiceDisconnected(first.key.getName()));\n        }\n    }\n\n    private class RemoteProcess extends BinderHolder {\n\n        final IRootServiceManager mgr;\n\n        RemoteProcess(IRootServiceManager s) throws RemoteException {\n            super(s.asBinder());\n            mgr = s;\n        }\n\n        @Override\n        protected void onBinderDied() {\n            if (mRemote == this)\n                mRemote = null;\n            if (mDaemon == this)\n                mDaemon = null;\n\n            Iterator<RemoteServiceRecord> sit = mServices.values().iterator();\n            while (sit.hasNext()) {\n                if (sit.next().host == this) {\n                    sit.remove();\n                }\n            }\n            dropConnections(s -> s.host == this);\n        }\n    }\n\n    private static class RemoteServiceRecord {\n        final ServiceKey key;\n        final IBinder binder;\n        final RemoteProcess host;\n        int refCount = 1;\n\n        RemoteServiceRecord(ServiceKey key, IBinder binder, RemoteProcess host) {\n            this.key = key;\n            this.binder = binder;\n            this.host = host;\n        }\n    }\n\n    private class ServiceReceiver extends BroadcastReceiver {\n\n        private final Messenger m;\n\n        ServiceReceiver() {\n            // Create messenger to receive service stop notification\n            Handler h = new Handler(Looper.getMainLooper(), RootServiceManager.this);\n            m = new Messenger(h);\n        }\n\n        @Override\n        public void onReceive(Context context, Intent intent) {\n            Bundle bundle = intent.getBundleExtra(INTENT_BUNDLE_KEY);\n            if (bundle == null)\n                return;\n            IBinder binder = bundle.getBinder(BUNDLE_BINDER_KEY);\n            if (binder == null)\n                return;\n\n            IRootServiceManager mgr = IRootServiceManager.Stub.asInterface(binder);\n            try {\n                mgr.connect(m.getBinder());\n                RemoteProcess p = new RemoteProcess(mgr);\n                if (intent.getBooleanExtra(INTENT_DAEMON_KEY, false)) {\n                    mDaemon = p;\n                    mFlags &= ~DAEMON_EN_ROUTE;\n                } else {\n                    mRemote = p;\n                    mFlags &= ~REMOTE_EN_ROUTE;\n                }\n                for (int i = mPendingTasks.size() - 1; i >= 0; --i) {\n                    if (mPendingTasks.get(i).run()) {\n                        mPendingTasks.remove(i);\n                    }\n                }\n            } catch (RemoteException e) {\n                Log.e(TAG, e.getMessage(), e);\n            }\n        }\n    }\n\n    private interface BindTask {\n        boolean run();\n    }\n\n    private interface Predicate {\n        boolean eval(RemoteServiceRecord s);\n    }\n}"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/ipc/RootServiceServer.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage io.github.muntashirakon.AppManager.ipc;\n\nimport android.annotation.SuppressLint;\nimport android.content.ComponentName;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.os.Build;\nimport android.os.Debug;\nimport android.os.FileObserver;\nimport android.os.IBinder;\nimport android.os.Message;\nimport android.os.Messenger;\nimport android.os.RemoteException;\nimport android.os.UserHandle;\nimport android.util.ArrayMap;\nimport android.util.ArraySet;\nimport android.util.SparseArray;\n\nimport androidx.annotation.Nullable;\nimport androidx.annotation.RestrictTo;\n\nimport com.topjohnwu.superuser.Shell;\nimport com.topjohnwu.superuser.internal.UiThreadHandler;\nimport com.topjohnwu.superuser.internal.Utils;\n\nimport java.io.File;\nimport java.lang.reflect.Constructor;\nimport java.util.HashSet;\nimport java.util.Iterator;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.concurrent.Callable;\n\nimport io.github.muntashirakon.AppManager.server.common.IRootServiceManager;\nimport io.github.muntashirakon.AppManager.server.common.ServerUtils;\nimport io.github.muntashirakon.AppManager.utils.ContextUtils;\n\nimport static io.github.muntashirakon.AppManager.ipc.RootServiceManager.DEBUG_ENV;\nimport static io.github.muntashirakon.AppManager.ipc.RootServiceManager.LOGGING_ENV;\nimport static io.github.muntashirakon.AppManager.ipc.RootServiceManager.MSG_STOP;\n\n\n/**\n * Runs in the root (server) process.\n * <p>\n * Manages the lifecycle of RootServices and the root process.\n */\n// Copyright 2021 John \"topjohnwu\" Wu\n@RestrictTo(RestrictTo.Scope.LIBRARY)\n@SuppressLint(\"RestrictedApi\")\npublic class RootServiceServer extends IRootServiceManager.Stub implements Runnable {\n    public static final String TAG = RootServiceServer.class.getSimpleName();\n\n    @SuppressLint(\"StaticFieldLeak\")\n    private static RootServiceServer sInstance;\n\n    public static RootServiceServer getInstance(Context context) {\n        if (sInstance == null) {\n            sInstance = new RootServiceServer(context);\n        }\n        return sInstance;\n    }\n\n    @SuppressWarnings(\"FieldCanBeLocal\")\n    private final FileObserver mObserver;  /* A strong reference is required */\n    private final Map<ComponentName, ServiceRecord> mServices = new ArrayMap<>();\n    private final SparseArray<ClientProcess> mClients = new SparseArray<>();\n    private final boolean mIsDaemon;\n    private final Context mContext;\n\n    @SuppressWarnings(\"rawtypes\")\n    private RootServiceServer(Context context) {\n        Shell.enableVerboseLogging = System.getenv(LOGGING_ENV) != null;\n        mContext = context;\n        ContextUtils.rootContext = context;\n\n        // Wait for debugger to attach if needed\n        if (System.getenv(DEBUG_ENV) != null) {\n            // ActivityThread.attach(true, 0) will set this to system_process\n            HiddenAPIs.setAppName(context.getPackageName() + \":priv\");\n            Utils.log(TAG, \"Waiting for debugger to be attached...\");\n            // For some reason Debug.waitForDebugger() won't work, manual spin lock...\n            while (!Debug.isDebuggerConnected()) {\n                try {\n                    // noinspection BusyWait\n                    Thread.sleep(200);\n                } catch (InterruptedException ignored) {\n                }\n            }\n            Utils.log(TAG, \"Debugger attached!\");\n        }\n\n        mObserver = new AppObserver(new File(context.getPackageCodePath()));\n        mObserver.startWatching();\n        if (context instanceof Callable) {\n            try {\n                Object[] objs = (Object[]) ((Callable) context).call();\n                mIsDaemon = (boolean) objs[1];\n                if (mIsDaemon) {\n                    // Register ourselves as system service\n                    HiddenAPIs.addService(ServerUtils.getServiceName(context.getPackageName()), this);\n                }\n                broadcast((int) objs[0]);\n            } catch (Exception e) {\n                throw new RuntimeException(e);\n            }\n        } else {\n            throw new IllegalArgumentException(\"Expected Context to be Callable\");\n        }\n        if (!mIsDaemon) {\n            // Terminate the process if idle for 10 seconds,\n            UiThreadHandler.handler.postDelayed(this, 10 * 1000);\n        }\n    }\n\n    @Override\n    public void run() {\n        if (mClients.size() == 0) {\n            exit(\"No active clients\");\n        }\n    }\n\n    @Override\n    public void connect(IBinder binder) {\n        int uid = getCallingUid();\n        UiThreadHandler.run(() -> connectInternal(uid, binder));\n    }\n\n    private void connectInternal(int uid, IBinder binder) {\n        if (mClients.get(uid) != null)\n            return;\n        try {\n            mClients.put(uid, new ClientProcess(binder, uid));\n            UiThreadHandler.handler.removeCallbacks(this);\n        } catch (RemoteException e) {\n            Utils.err(TAG, e);\n        }\n    }\n\n    @Override\n    public void broadcast(int uid) {\n        // Use the UID argument iff caller is root\n        uid = getCallingUid() == 0 ? uid : getCallingUid();\n        Utils.log(TAG, \"broadcast to uid=\" + uid);\n        Intent intent = RootServiceManager.getBroadcastIntent(this, mIsDaemon);\n        if (Build.VERSION.SDK_INT >= 24) {\n            UserHandle h = UserHandle.getUserHandleForUid(uid);\n            mContext.sendBroadcastAsUser(intent, h);\n        } else {\n            mContext.sendBroadcast(intent);\n        }\n    }\n\n    @Override\n    public IBinder bind(Intent intent) {\n        IBinder[] b = new IBinder[1];\n        int uid = getCallingUid();\n        UiThreadHandler.runAndWait(() -> {\n            try {\n                b[0] = bindInternal(uid, intent);\n            } catch (Exception e) {\n                Utils.err(TAG, e);\n            }\n        });\n        return b[0];\n    }\n\n    @Override\n    public void unbind(ComponentName name) {\n        int uid = getCallingUid();\n        UiThreadHandler.run(() -> {\n            Utils.log(TAG, name.getClassName() + \" unbind\");\n            unbindService(uid, name);\n        });\n    }\n\n    @Override\n    public void stop(ComponentName name, int uid) {\n        // Use the UID argument iff caller is root\n        int clientUid = getCallingUid() == 0 ? uid : getCallingUid();\n        UiThreadHandler.run(() -> {\n            Utils.log(TAG, name.getClassName() + \" stop\");\n            unbindService(-1, name);\n            // If we aren't killed yet, send another broadcast\n            broadcast(clientUid);\n        });\n    }\n\n    public void selfStop(ComponentName name) {\n        UiThreadHandler.run(() -> {\n            Utils.log(TAG, name.getClassName() + \" selfStop\");\n            unbindService(-1, name);\n        });\n    }\n\n    public void register(RootService service) {\n        ServiceRecord s = new ServiceRecord(service);\n        mServices.put(service.getComponentName(), s);\n    }\n\n    @Nullable\n    private IBinder bindInternal(int uid, Intent intent) throws Exception {\n        ClientProcess c = mClients.get(uid);\n        if (c == null)\n            return null;\n\n        ComponentName name = intent.getComponent();\n\n        ServiceRecord s = mServices.get(name);\n        if (s == null) {\n            Class<?> clz = mContext.getClassLoader().loadClass(name.getClassName());\n            Constructor<?> ctor = clz.getDeclaredConstructor();\n            ctor.setAccessible(true);\n            HiddenAPIs.attachBaseContext(ctor.newInstance(), mContext);\n\n            // RootService should be registered after attachBaseContext\n            s = mServices.get(name);\n            if (s == null) {\n                return null;\n            }\n        }\n\n        if (s.binder != null) {\n            Utils.log(TAG, name.getClassName() + \" rebind\");\n            if (s.rebind)\n                s.service.onRebind(s.intent);\n        } else {\n            Utils.log(TAG, name.getClassName() + \" bind\");\n            s.binder = s.service.onBind(intent);\n            s.intent = intent.cloneFilter();\n        }\n        s.users.add(uid);\n\n        return s.binder;\n    }\n\n    private void unbindInternal(ServiceRecord s, int uid, Runnable onDestroy) {\n        boolean hadUsers = !s.users.isEmpty();\n        s.users.remove(uid);\n        if (uid < 0 || s.users.isEmpty()) {\n            if (hadUsers) {\n                s.rebind = s.service.onUnbind(s.intent);\n            }\n            if (uid < 0 || !mIsDaemon) {\n                s.service.onDestroy();\n                onDestroy.run();\n\n                // Notify all other users\n                for (int user : s.users) {\n                    ClientProcess c = mClients.get(user);\n                    if (c == null)\n                        continue;\n                    Message msg = Message.obtain();\n                    msg.what = MSG_STOP;\n                    msg.arg1 = mIsDaemon ? 1 : 0;\n                    msg.obj = s.intent.getComponent();\n                    try {\n                        c.m.send(msg);\n                    } catch (RemoteException e) {\n                        Utils.err(TAG, e);\n                    } finally {\n                        msg.recycle();\n                    }\n                }\n            }\n        }\n        if (mServices.isEmpty()) {\n            exit(\"No active services\");\n        }\n    }\n\n    private void unbindService(int uid, ComponentName name) {\n        ServiceRecord s = mServices.get(name);\n        if (s == null)\n            return;\n        unbindInternal(s, uid, () -> mServices.remove(name));\n    }\n\n    private void unbindServices(int uid) {\n        Iterator<Map.Entry<ComponentName, ServiceRecord>> it = mServices.entrySet().iterator();\n        while (it.hasNext()) {\n            ServiceRecord s = it.next().getValue();\n            if (uid < 0) {\n                // App is updated/deleted, all clients will get killed anyway,\n                // no need to notify anyone.\n                s.users.clear();\n            }\n            unbindInternal(s, uid, it::remove);\n        }\n    }\n\n    private void exit(String reason) {\n        Utils.log(TAG, \"Terminate process: \" + reason);\n        System.exit(0);\n    }\n\n    private class AppObserver extends FileObserver {\n        private final String mName;\n\n        AppObserver(File path) {\n            super(path.getParent(), CREATE | DELETE | DELETE_SELF | MOVED_TO | MOVED_FROM);\n            Utils.log(TAG, \"Start monitoring: \" + path.getParent());\n            mName = path.getName();\n        }\n\n        @Override\n        public void onEvent(int event, @Nullable String path) {\n            // App APK update, force close the root process\n            if (event == DELETE_SELF || mName.equals(path)) {\n                exit(\"Package updated\");\n            }\n        }\n    }\n\n    private class ClientProcess extends BinderHolder {\n        final Messenger m;\n        final int uid;\n\n        ClientProcess(IBinder b, int uid) throws RemoteException {\n            super(b);\n            m = new Messenger(b);\n            this.uid = uid;\n        }\n\n        @Override\n        protected void onBinderDied() {\n            Utils.log(TAG, \"Client process terminated, uid=\" + uid);\n            mClients.remove(uid);\n            unbindServices(uid);\n        }\n    }\n\n    private static class ServiceRecord {\n        final RootService service;\n        final Set<Integer> users = Build.VERSION.SDK_INT >= 23 ? new ArraySet<>() : new HashSet<>();\n\n        Intent intent;\n        IBinder binder;\n        boolean rebind;\n\n        ServiceRecord(RootService s) {\n            service = s;\n        }\n    }\n}"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/ipc/SerialExecutorService.java",
    "content": "// SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.ipc;\n\nimport java.util.ArrayDeque;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.concurrent.AbstractExecutorService;\nimport java.util.concurrent.Callable;\nimport java.util.concurrent.ExecutionException;\nimport java.util.concurrent.FutureTask;\nimport java.util.concurrent.RejectedExecutionException;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.TimeoutException;\n\nimport static com.topjohnwu.superuser.Shell.EXECUTOR;\n\n// Copyright 2020 John \"topjohnwu\" Wu\npublic class SerialExecutorService extends AbstractExecutorService implements Callable<Void> {\n    private boolean mIsShutdown = false;\n    private final ArrayDeque<Runnable> mTasks = new ArrayDeque<>();\n    private FutureTask<Void> mScheduleTask = null;\n\n    @Override\n    public Void call() {\n        for (; ; ) {\n            Runnable task;\n            synchronized (this) {\n                if ((task = mTasks.poll()) == null) {\n                    mScheduleTask = null;\n                    return null;\n                }\n            }\n            task.run();\n        }\n    }\n\n    @Override\n    public synchronized void execute(Runnable r) {\n        if (mIsShutdown) {\n            throw new RejectedExecutionException(\n                    \"Task \" + r.toString() + \" rejected from \" + this);\n        }\n        mTasks.offer(r);\n        if (mScheduleTask == null) {\n            mScheduleTask = new FutureTask<>(this);\n            EXECUTOR.execute(mScheduleTask);\n        }\n    }\n\n    @Override\n    public synchronized void shutdown() {\n        mIsShutdown = true;\n        mTasks.clear();\n    }\n\n    @Override\n    public synchronized List<Runnable> shutdownNow() {\n        mIsShutdown = true;\n        if (mScheduleTask != null)\n            mScheduleTask.cancel(true);\n        try {\n            return new ArrayList<>(mTasks);\n        } finally {\n            mTasks.clear();\n        }\n    }\n\n    @Override\n    public synchronized boolean isShutdown() {\n        return mIsShutdown;\n    }\n\n    @Override\n    public synchronized boolean isTerminated() {\n        return mIsShutdown && mScheduleTask == null;\n    }\n\n    @Override\n    public synchronized boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException {\n        if (mScheduleTask == null)\n            return true;\n        try {\n            mScheduleTask.get(timeout, unit);\n        } catch (TimeoutException e) {\n            return false;\n        } catch (ExecutionException ignored) {\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/ipc/ServiceConnectionWrapper.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.ipc;\n\nimport android.content.ComponentName;\nimport android.content.Intent;\nimport android.content.ServiceConnection;\nimport android.os.IBinder;\nimport android.os.RemoteException;\n\nimport androidx.annotation.MainThread;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.WorkerThread;\n\nimport java.util.Objects;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.TimeUnit;\n\nimport io.github.muntashirakon.AppManager.logs.Log;\nimport io.github.muntashirakon.AppManager.misc.NoOps;\nimport io.github.muntashirakon.AppManager.utils.ThreadUtils;\n\nclass ServiceConnectionWrapper {\n    public static final String TAG = ServiceConnectionWrapper.class.getSimpleName();\n\n    @Nullable\n    private IBinder mIBinder;\n    @Nullable\n    private CountDownLatch mServiceBoundWatcher;\n\n    private class ServiceConnectionImpl implements ServiceConnection {\n        @Override\n        public void onServiceConnected(ComponentName name, IBinder service) {\n            Log.d(TAG, \"service onServiceConnected: %s\", name);\n            mIBinder = service;\n            onResponseReceived();\n        }\n\n        @Override\n        public void onServiceDisconnected(ComponentName name) {\n            Log.d(TAG, \"service onServiceDisconnected: %s\", name);\n            mIBinder = null;\n            onResponseReceived();\n        }\n\n        @Override\n        public void onBindingDied(ComponentName name) {\n            Log.d(TAG, \"service onBindingDied: %s\", name);\n            mIBinder = null;\n            onResponseReceived();\n        }\n\n        @Override\n        public void onNullBinding(ComponentName name) {\n            Log.d(TAG, \"service onNullBinding: %s\", name);\n            mIBinder = null;\n            onResponseReceived();\n        }\n\n        private void onResponseReceived() {\n            if (mServiceBoundWatcher != null) {\n                // Should never be null\n                mServiceBoundWatcher.countDown();\n            } else throw new RuntimeException(\"Service watcher should never be null!\");\n        }\n    }\n\n    @NonNull\n    private final ComponentName mComponentName;\n    @NonNull\n    private final ServiceConnectionImpl mServiceConnection;\n\n    public ServiceConnectionWrapper(@NonNull String pkgName, @NonNull String className) {\n        this(new ComponentName(pkgName, className));\n    }\n\n    public ServiceConnectionWrapper(@NonNull ComponentName cn) {\n        mComponentName = cn;\n        mServiceConnection = new ServiceConnectionImpl();\n    }\n\n    @NonNull\n    public IBinder getService() throws RemoteException {\n        if (!isBinderActive()) {\n            throw new RemoteException(\"Binder not running.\");\n        }\n        return Objects.requireNonNull(mIBinder);\n    }\n\n    @NonNull\n    @NoOps(used = true)\n    public IBinder bindService() throws RemoteException {\n        synchronized (mServiceConnection) {\n            if (!isBinderActive()) {\n                startDaemon();\n            }\n            return getService();\n        }\n    }\n\n    @MainThread\n    public void unbindService() {\n        synchronized (mServiceConnection) {\n            RootService.unbind(mServiceConnection);\n        }\n    }\n\n    @WorkerThread\n    private void startDaemon() {\n        synchronized (mServiceConnection) {\n            if (isBinderActive()) {\n                Log.d(TAG, \"Binder is already active?\");\n                return;\n            }\n            mServiceBoundWatcher = new CountDownLatch(1);\n            Log.d(TAG, \"Launching service...\");\n            Intent intent = new Intent();\n            intent.setComponent(mComponentName);\n            ThreadUtils.postOnMainThread(() -> {\n                if (mIBinder != null) {\n                    RootService.stop(intent);\n                }\n                RootService.bind(intent, mServiceConnection);\n            });\n            // Wait for service to be bound\n            try {\n                mServiceBoundWatcher.await(45, TimeUnit.SECONDS);\n            } catch (InterruptedException e) {\n                Log.e(TAG, \"Service watcher interrupted.\");\n            }\n        }\n    }\n\n    @WorkerThread\n    public void stopDaemon() {\n        Intent intent = new Intent();\n        intent.setComponent(mComponentName);\n        ThreadUtils.postOnMainThread(() -> RootService.stop(intent));\n        mIBinder = null;\n    }\n\n    boolean isBinderActive() {\n        return mIBinder != null && mIBinder.pingBinder();\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/ipc/ServiceNotFoundException.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.ipc;\n\npublic class ServiceNotFoundException extends RuntimeException {\n    public ServiceNotFoundException() {\n        super();\n    }\n\n    public ServiceNotFoundException(String name) {\n        super(name);\n    }\n\n    public ServiceNotFoundException(String name, Exception cause) {\n        super(name, cause);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/ipc/package.html",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n\n<p>\n    Java classes except IPCUtils and RemoteProcess defined in the package must be executed via IPC. Main app can only access them.\n</p>\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/ipc/ps/ProcessEntry.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.ipc.ps;\n\nimport android.os.Parcel;\nimport android.os.Parcelable;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.core.os.ParcelCompat;\n\nimport java.util.Objects;\n\npublic class ProcessEntry implements Parcelable {\n    public int pid;\n    public int ppid;\n    public int priority;\n    public int niceness;\n    public long instructionPointer;\n    public long virtualMemorySize;\n    public long residentSetSize;\n    public long sharedMemory;\n    public int processGroupId;\n    public int majorPageFaults;\n    public int minorPageFaults;\n    public int realTimePriority;\n    public int schedulingPolicy;\n    public int cpu;\n    public int threadCount;\n    public int tty;\n    @Nullable\n    public String seLinuxPolicy;\n    public String name;\n    public ProcessUsers users;\n    public long cpuTimeConsumed;\n    public long cCpuTimeConsumed;\n    public long elapsedTime;\n    public String processState;\n    public String processStatePlus;\n\n    ProcessEntry() {\n    }\n\n    protected ProcessEntry(@NonNull Parcel in) {\n        pid = in.readInt();\n        ppid = in.readInt();\n        priority = in.readInt();\n        niceness = in.readInt();\n        instructionPointer = in.readLong();\n        virtualMemorySize = in.readLong();\n        residentSetSize = in.readLong();\n        sharedMemory = in.readLong();\n        processGroupId = in.readInt();\n        majorPageFaults = in.readInt();\n        minorPageFaults = in.readInt();\n        realTimePriority = in.readInt();\n        schedulingPolicy = in.readInt();\n        cpu = in.readInt();\n        threadCount = in.readInt();\n        tty = in.readInt();\n        seLinuxPolicy = in.readString();\n        name = in.readString();\n        users = Objects.requireNonNull(ParcelCompat.readParcelable(in, ProcessUsers.class.getClassLoader(), ProcessUsers.class));\n        cpuTimeConsumed = in.readLong();\n        cCpuTimeConsumed = in.readLong();\n        elapsedTime = in.readLong();\n        processState = in.readString();\n        processStatePlus = in.readString();\n    }\n\n    public static final Creator<ProcessEntry> CREATOR = new Creator<ProcessEntry>() {\n        @Override\n        @NonNull\n        public ProcessEntry createFromParcel(Parcel in) {\n            return new ProcessEntry(in);\n        }\n\n        @Override\n        @NonNull\n        public ProcessEntry[] newArray(int size) {\n            return new ProcessEntry[size];\n        }\n    };\n\n    @Override\n    public int describeContents() {\n        return 0;\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        dest.writeInt(pid);\n        dest.writeInt(ppid);\n        dest.writeInt(priority);\n        dest.writeInt(niceness);\n        dest.writeLong(instructionPointer);\n        dest.writeLong(virtualMemorySize);\n        dest.writeLong(residentSetSize);\n        dest.writeLong(sharedMemory);\n        dest.writeInt(processGroupId);\n        dest.writeInt(majorPageFaults);\n        dest.writeInt(minorPageFaults);\n        dest.writeInt(realTimePriority);\n        dest.writeInt(schedulingPolicy);\n        dest.writeInt(cpu);\n        dest.writeInt(threadCount);\n        dest.writeInt(tty);\n        dest.writeString(seLinuxPolicy);\n        dest.writeString(name);\n        dest.writeParcelable(users, flags);\n        dest.writeLong(cpuTimeConsumed);\n        dest.writeLong(cCpuTimeConsumed);\n        dest.writeLong(elapsedTime);\n        dest.writeString(processState);\n        dest.writeString(processStatePlus);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/ipc/ps/ProcessUsers.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.ipc.ps;\n\nimport android.os.Parcel;\nimport android.os.Parcelable;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\npublic class ProcessUsers implements Parcelable {\n    public final int realUid;\n    public final int realGid;\n    public final int effectiveUid;\n    public final int effectiveGid;\n    public final int savedSetUid;\n    public final int savedSetGid;\n    public final int fsUid;\n    public final int fsGid;\n\n    ProcessUsers(@Nullable String uidLine, @Nullable String gidLine) {\n        if (uidLine == null || gidLine == null) {\n            throw new IllegalArgumentException(\"UID/GID must be non null\");\n        }\n        String[] uids = uidLine.split(\"\\\\s+\");\n        String[] gids = gidLine.split(\"\\\\s+\");\n        if (uids.length != gids.length && uids.length >= 4) {\n            throw new IllegalArgumentException(\"Invalid UID/GID.\\nUid: \" + uidLine + \"\\nGid: \" + gidLine);\n        }\n        // Set uids\n        realUid = Integer.decode(uids[0].trim());\n        effectiveUid = Integer.decode(uids[1].trim());\n        savedSetUid = Integer.decode(uids[2].trim());\n        fsUid = Integer.decode(uids[3].trim());\n        // Set gids\n        realGid = Integer.decode(gids[0].trim());\n        effectiveGid = Integer.decode(gids[1].trim());\n        savedSetGid = Integer.decode(gids[2].trim());\n        fsGid = Integer.decode(gids[3].trim());\n    }\n\n    protected ProcessUsers(@NonNull Parcel in) {\n        realUid = in.readInt();\n        realGid = in.readInt();\n        effectiveUid = in.readInt();\n        effectiveGid = in.readInt();\n        savedSetUid = in.readInt();\n        savedSetGid = in.readInt();\n        fsUid = in.readInt();\n        fsGid = in.readInt();\n    }\n\n    public static final Creator<ProcessUsers> CREATOR = new Creator<ProcessUsers>() {\n        @Override\n        @NonNull\n        public ProcessUsers createFromParcel(Parcel in) {\n            return new ProcessUsers(in);\n        }\n\n        @Override\n        @NonNull\n        public ProcessUsers[] newArray(int size) {\n            return new ProcessUsers[size];\n        }\n    };\n\n    @Override\n    public int describeContents() {\n        return 0;\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        dest.writeInt(realUid);\n        dest.writeInt(realGid);\n        dest.writeInt(effectiveUid);\n        dest.writeInt(effectiveGid);\n        dest.writeInt(savedSetUid);\n        dest.writeInt(savedSetGid);\n        dest.writeInt(fsUid);\n        dest.writeInt(fsGid);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/ipc/ps/Ps.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.ipc.ps;\n\nimport android.text.TextUtils;\nimport android.util.Log;\n\nimport androidx.annotation.AnyThread;\nimport androidx.annotation.GuardedBy;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.VisibleForTesting;\nimport androidx.annotation.WorkerThread;\n\nimport java.util.ArrayList;\n\nimport io.github.muntashirakon.AppManager.utils.CpuUtils;\nimport io.github.muntashirakon.AppManager.utils.Utils;\nimport io.github.muntashirakon.io.Path;\nimport io.github.muntashirakon.io.Paths;\nimport io.github.muntashirakon.proc.ProcFs;\nimport io.github.muntashirakon.proc.ProcMemStat;\nimport io.github.muntashirakon.proc.ProcStat;\nimport io.github.muntashirakon.proc.ProcStatus;\n\n/**\n * This is a generic Java-way of parsing processes from /proc. This is a work in progress and by no means perfect. To\n * create this class, I extensively followed the documentation located at https://www.kernel.org/doc/Documentation/filesystems/proc.txt.\n */\npublic final class Ps {\n    public static final String TAG = Ps.class.getSimpleName();\n\n    @NonNull\n    private final ProcFs mProcFs;\n    @GuardedBy(\"processEntries\")\n    private final ArrayList<ProcessEntry> mProcessEntries = new ArrayList<>(256);\n    private long mUptime;\n    private long mClockTicks;\n\n    public Ps() {\n        this(Paths.get(\"/proc\"));\n    }\n\n    @VisibleForTesting\n    public Ps(@NonNull Path procPath) {\n        mProcFs = new ProcFs(procPath);\n    }\n\n    @AnyThread\n    @GuardedBy(\"processEntries\")\n    @NonNull\n    public ArrayList<ProcessEntry> getProcesses() {\n        synchronized (mProcessEntries) {\n            return mProcessEntries;\n        }\n    }\n\n    @WorkerThread\n    @GuardedBy(\"processEntries\")\n    public void loadProcesses() {\n        synchronized (mProcessEntries) {\n            mProcessEntries.clear();\n            mUptime = mProcFs.getUptime() / 1000;\n            if (!Utils.isRoboUnitTest()) {\n                mClockTicks = CpuUtils.getClockTicksPerSecond();\n            } else mClockTicks = 100; // To prevent error due to native library\n            // Get process info for each PID\n            for (int pid : mProcFs.getPids()) {\n                ProcItem procItem = new ProcItem();\n                ProcStat procStat = mProcFs.getStat(pid);\n                ProcMemStat procMemStat = mProcFs.getMemStat(pid);\n                ProcStatus procStatus = mProcFs.getStatus(pid);\n                if (procStat == null) {\n                    Log.w(TAG, \"Could not read /proc/\" + pid + \"/stat\");\n                    continue;\n                }\n                if (procMemStat == null) {\n                    Log.w(TAG, \"Could not read /proc/\" + pid + \"/statm\");\n                    continue;\n                }\n                if (procStatus == null) {\n                    Log.w(TAG, \"Could not read /proc/\" + pid + \"/status\");\n                    continue;\n                }\n                procItem.stat = procStat;\n                procItem.memStat = procMemStat;\n                procItem.status = procStatus;\n                procItem.name = mProcFs.getCmdline(pid);\n                procItem.sepol = mProcFs.getCurrentContext(pid);\n                procItem.wchan = mProcFs.getWchan(pid);\n                mProcessEntries.add(newProcess(procItem));\n            }\n        }\n    }\n\n    @NonNull\n    private ProcessEntry newProcess(@NonNull ProcItem procItem) {\n        ProcessEntry processEntry = new ProcessEntry();\n        processEntry.pid = procItem.stat.getInteger(ProcStat.STAT_PID);\n        processEntry.ppid = procItem.stat.getInteger(ProcStat.STAT_PPID);\n        processEntry.priority = procItem.stat.getInteger(ProcStat.STAT_PRIORITY);\n        processEntry.niceness = procItem.stat.getInteger(ProcStat.STAT_NICE);\n        processEntry.instructionPointer = procItem.stat.getLong(ProcStat.STAT_EIP);\n        processEntry.virtualMemorySize = procItem.stat.getLong(ProcStat.STAT_VSIZE);\n        processEntry.residentSetSize = procItem.stat.getLong(ProcStat.STAT_RSS);\n        processEntry.sharedMemory = procItem.memStat.getLong(ProcMemStat.MEM_STAT_SHARED);\n        processEntry.processGroupId = procItem.stat.getInteger(ProcStat.STAT_PGRP);\n        processEntry.majorPageFaults = procItem.stat.getInteger(ProcStat.STAT_MAJ_FLT);\n        processEntry.minorPageFaults = procItem.stat.getInteger(ProcStat.STAT_MIN_FLT);\n        processEntry.realTimePriority = procItem.stat.getInteger(ProcStat.STAT_RT_PRIORITY);\n        processEntry.schedulingPolicy = procItem.stat.getInteger(ProcStat.STAT_POLICY);\n        processEntry.cpu = procItem.stat.getInteger(ProcStat.STAT_TASK_CPU);\n        processEntry.threadCount = procItem.stat.getInteger(ProcStat.STAT_NUM_THREADS);\n        processEntry.tty = procItem.stat.getInteger(ProcStat.STAT_TTY_NR);\n        processEntry.seLinuxPolicy = procItem.sepol;\n        processEntry.name = TextUtils.isEmpty(procItem.name) ? procItem.status.getString(ProcStatus.STATUS_NAME) : procItem.name;\n        processEntry.users = new ProcessUsers(procItem.status.getString(ProcStatus.STATUS_UID), procItem.status.getString(ProcStatus.STATUS_GID));\n        processEntry.cpuTimeConsumed = (procItem.stat.getInteger(ProcStat.STAT_UTIME)\n                + procItem.stat.getInteger(ProcStat.STAT_STIME)) / mClockTicks;\n        processEntry.cCpuTimeConsumed = (procItem.stat.getInteger(ProcStat.STAT_CUTIME)\n                + procItem.stat.getInteger(ProcStat.STAT_CSTIME)) / mClockTicks;\n        processEntry.elapsedTime = mUptime - (procItem.stat.getInteger(ProcStat.STAT_START_TIME) / mClockTicks);\n        String state = procItem.status.getString(ProcStatus.STATUS_STATE);\n        if (state == null) {\n            throw new RuntimeException(\"Process state cannot be empty!\");\n        }\n        processEntry.processState = state.substring(0, 1);\n        StringBuilder stateExtra = new StringBuilder();\n        if (procItem.stat.getInteger(ProcStat.STAT_NICE) < 0) {\n            stateExtra.append(\"<\");\n        } else if (procItem.stat.getInteger(ProcStat.STAT_NICE) > 0) {\n            stateExtra.append(\"N\");\n        }\n        if (procItem.stat.getInteger(ProcStat.STAT_SID) == processEntry.pid) {\n            stateExtra.append(\"s\");\n        }\n        String vmLck = procItem.status.getString(ProcStatus.STATUS_VM_LCK);\n        if (vmLck != null && Integer.decode(vmLck.substring(0, 1)) > 0) {\n            stateExtra.append(\"L\");\n        }\n        if (procItem.stat.getInteger(ProcStat.STAT_TTY_PGRP) == processEntry.pid) {\n            stateExtra.append(\"+\");\n        }\n        processEntry.processStatePlus = stateExtra.toString();\n        return processEntry;\n    }\n\n    private static class ProcItem {\n        public ProcStat stat;\n        public ProcMemStat memStat;\n        public ProcStatus status;\n        @Nullable\n        public String name;\n        @Nullable\n        public String sepol;\n        @Nullable\n        public String wchan;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/logcat/AbsLogViewerFragment.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.logcat;\n\nimport android.content.Context;\nimport android.os.Bundle;\nimport android.view.LayoutInflater;\nimport android.view.Menu;\nimport android.view.MenuInflater;\nimport android.view.MenuItem;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.CheckBox;\nimport android.widget.Filter;\n\nimport androidx.activity.OnBackPressedCallback;\nimport androidx.annotation.CallSuper;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.core.view.MenuProvider;\nimport androidx.fragment.app.Fragment;\nimport androidx.lifecycle.Lifecycle;\nimport androidx.lifecycle.ViewModelProvider;\nimport androidx.recyclerview.widget.LinearLayoutManager;\nimport androidx.recyclerview.widget.RecyclerView;\n\nimport com.google.android.material.dialog.MaterialAlertDialogBuilder;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Objects;\n\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.logcat.helper.PreferenceHelper;\nimport io.github.muntashirakon.AppManager.logcat.helper.SaveLogHelper;\nimport io.github.muntashirakon.AppManager.logcat.struct.LogLine;\nimport io.github.muntashirakon.AppManager.logcat.struct.SearchCriteria;\nimport io.github.muntashirakon.AppManager.settings.LogViewerPreferences;\nimport io.github.muntashirakon.AppManager.utils.StoragePermission;\nimport io.github.muntashirakon.AppManager.utils.UIUtils;\nimport io.github.muntashirakon.dialog.SearchableItemsDialogBuilder;\nimport io.github.muntashirakon.dialog.SearchableMultiChoiceDialogBuilder;\nimport io.github.muntashirakon.dialog.SearchableSingleChoiceDialogBuilder;\nimport io.github.muntashirakon.dialog.TextInputDialogBuilder;\nimport io.github.muntashirakon.io.Path;\nimport io.github.muntashirakon.multiselection.MultiSelectionActionsView;\nimport io.github.muntashirakon.util.AdapterUtils;\nimport io.github.muntashirakon.widget.MultiSelectionView;\n\npublic abstract class AbsLogViewerFragment extends Fragment implements MenuProvider,\n        LogViewerViewModel.LogLinesAvailableInterface,\n        MultiSelectionActionsView.OnItemSelectedListener,\n        MultiSelectionView.OnSelectionModeChangeListener,\n        LogViewerActivity.SearchingInterface, Filter.FilterListener{\n    public static final String TAG = AbsLogViewerFragment.class.getSimpleName();\n\n    protected RecyclerView mRecyclerView;\n    protected MultiSelectionView mMultiSelectionView;\n    protected LogViewerViewModel mViewModel;\n    protected LogViewerActivity mActivity;\n    protected LogViewerRecyclerAdapter mLogListAdapter;\n\n    protected boolean mAutoscrollToBottom = true;\n    @Nullable\n    protected volatile SearchCriteria mSearchCriteria;\n\n    protected final StoragePermission mStoragePermission = StoragePermission.init(this);\n    protected final RecyclerView.OnScrollListener mRecyclerViewScrollListener = new RecyclerView.OnScrollListener() {\n        @Override\n        public void onScrollStateChanged(@NonNull RecyclerView recyclerView, int newState) {\n            super.onScrollStateChanged(recyclerView, newState);\n        }\n\n        @Override\n        public void onScrolled(@NonNull RecyclerView recyclerView, int dx, int dy) {\n            super.onScrolled(recyclerView, dx, dy);\n            // Update what the first viewable item is\n            final LinearLayoutManager layoutManager = (LinearLayoutManager) recyclerView.getLayoutManager();\n            if (layoutManager != null) {\n                // Stop autoscroll if the bottom of the list isn't visible anymore\n                mAutoscrollToBottom = layoutManager.findLastCompletelyVisibleItemPosition() ==\n                        (mLogListAdapter.getItemCount() - 1);\n            }\n        }\n    };\n    private final OnBackPressedCallback mOnBackPressedCallback = new OnBackPressedCallback(false) {\n        @Override\n        public void handleOnBackPressed() {\n            if (mLogListAdapter.isInSelectionMode()) {\n                mMultiSelectionView.cancel();\n            } else {\n                setEnabled(false);\n                requireActivity().getOnBackPressedDispatcher().onBackPressed();\n            }\n        }\n    };\n\n    @Nullable\n    @Override\n    public final View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {\n        return inflater.inflate(R.layout.fragment_logcat, container, false);\n    }\n\n    @CallSuper\n    @Override\n    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {\n        mViewModel = new ViewModelProvider(requireActivity()).get(LogViewerViewModel.class);\n        mActivity = (LogViewerActivity) requireActivity();\n        mActivity.setSearchingInterface(this);\n        mRecyclerView = view.findViewById(R.id.list);\n        mRecyclerView.setLayoutManager(new LinearLayoutManager(mActivity));\n        mRecyclerView.setItemAnimator(null);\n        // Check for query string\n        mSearchCriteria = mActivity.getSearchQuery();\n        if (mSearchCriteria != null) {\n            mRecyclerView.postDelayed(() -> mActivity.search(mSearchCriteria), 1000);\n        }\n        mLogListAdapter = new LogViewerRecyclerAdapter();\n        mLogListAdapter.setClickListener(mActivity);\n        mMultiSelectionView = view.findViewById(R.id.selection_view);\n        mMultiSelectionView.setAdapter(mLogListAdapter);\n        mMultiSelectionView.setOnItemSelectedListener(this);\n        mMultiSelectionView.setOnSelectionModeChangeListener(this);\n        mMultiSelectionView.hide();\n        mRecyclerView.setAdapter(mLogListAdapter);\n        mRecyclerView.addOnScrollListener(mRecyclerViewScrollListener);\n        mActivity.addMenuProvider(this, getViewLifecycleOwner(), Lifecycle.State.RESUMED);\n        // Observers\n        mViewModel.getExpandLogsLiveData().observe(getViewLifecycleOwner(), expanded -> {\n            int oldFirstVisibleItem = ((LinearLayoutManager) Objects.requireNonNull(mRecyclerView.getLayoutManager())).findFirstVisibleItemPosition();\n            mLogListAdapter.setCollapseMode(!expanded);\n            mLogListAdapter.notifyItemRangeChanged(0, mLogListAdapter.getItemCount(), AdapterUtils.STUB);\n            // Scroll to bottom or the first visible item\n            if (mAutoscrollToBottom) {\n                mRecyclerView.scrollToPosition(mLogListAdapter.getItemCount() - 1);\n            } else if (oldFirstVisibleItem != -1) {\n                mRecyclerView.scrollToPosition(oldFirstVisibleItem);\n            }\n            mActivity.supportInvalidateOptionsMenu();\n        });\n        mViewModel.observeLogLevelLiveData().observe(getViewLifecycleOwner(), logLevel ->\n                mLogListAdapter.setLogLevelLimit(logLevel));\n    }\n\n    @Override\n    public void onAttach(@NonNull Context context) {\n        super.onAttach(context);\n        requireActivity().getOnBackPressedDispatcher().addCallback(this, mOnBackPressedCallback);\n    }\n\n    @CallSuper\n    @Override\n    public void onDestroy() {\n        if (mRecyclerView != null) {\n            mRecyclerView.removeOnScrollListener(mRecyclerViewScrollListener);\n        }\n        super.onDestroy();\n    }\n\n    public abstract void onCreateMenu(@NonNull Menu menu, @NonNull MenuInflater menuInflater);\n\n    @CallSuper\n    @Override\n    public void onPrepareMenu(@NonNull Menu menu) {\n        MenuItem expandMenu = menu.findItem(R.id.action_expand_collapse);\n        if (expandMenu != null) {\n            if (mViewModel.isCollapsedMode()) {\n                expandMenu.setIcon(R.drawable.ic_expand_more);\n                expandMenu.setTitle(R.string.expand_all);\n            } else {\n                expandMenu.setIcon(R.drawable.ic_expand_less);\n                expandMenu.setTitle(R.string.collapse_all);\n            }\n        }\n    }\n\n    @CallSuper\n    @Override\n    public boolean onMenuItemSelected(@NonNull MenuItem item) {\n        int id = item.getItemId();\n        if (id == R.id.action_expand_collapse) {\n            mViewModel.setCollapsedMode(!mViewModel.isCollapsedMode());\n        } else if (id == R.id.action_open) {\n            mStoragePermission.request(granted -> {\n                if (granted) {\n                    displayOpenLogFileDialog();\n                }\n            });\n        } else if (id == R.id.action_save) {\n            mStoragePermission.request(granted -> {\n                if (granted) {\n                    displaySaveLogDialog(false);\n                }\n            });\n        } else if (id == R.id.action_delete) {\n            displayDeleteSavedLogsDialog();\n        } else if (id == R.id.action_change_log_level) {\n            CharSequence[] logLevelsLocalised = getResources().getStringArray(R.array.log_levels);\n            new SearchableSingleChoiceDialogBuilder<>(mActivity, LogViewerPreferences.LOG_LEVEL_VALUES, logLevelsLocalised)\n                    .setTitle(R.string.log_level)\n                    .setSelection(mViewModel.getLogLevel())\n                    .setOnSingleChoiceClickListener((dialog, which, selectedLogLevel, isChecked) -> {\n                        mViewModel.setLogLevel(selectedLogLevel);\n                        // Search again\n                        mActivity.search(mSearchCriteria);\n                    })\n                    .setNegativeButton(R.string.close, null)\n                    .show();\n        } else if (id == R.id.action_settings) {\n            mActivity.displayLogViewerSettings();\n        } else if (id == R.id.action_show_saved_filters) {\n            mViewModel.loadFilters();\n        }  else if (id == R.id.action_share) {\n            displaySaveDebugLogsDialog(true, false);\n        } else if (id == R.id.action_export) {\n            displaySaveDebugLogsDialog(false, false);\n            return true;\n        } else return false;\n        return true;\n    }\n\n    @Override\n    public void onSelectionModeEnabled() {\n        mOnBackPressedCallback.setEnabled(true);\n    }\n\n    @Override\n    public void onSelectionModeDisabled() {\n        mOnBackPressedCallback.setEnabled(false);\n    }\n\n    @CallSuper\n    @Override\n    public void onQuery(@Nullable SearchCriteria searchCriteria) {\n        mSearchCriteria = searchCriteria;\n        Filter filter = mLogListAdapter.getFilter();\n        filter.filter(searchCriteria != null ? searchCriteria.query : null, this);\n    }\n\n    @Override\n    public final void onFilterComplete(int count) {\n        mRecyclerView.scrollToPosition(count - 1);\n    }\n\n    @NonNull\n    protected final List<String> getCurrentLogsAsListOfStrings() {\n        List<String> result = new ArrayList<>(mLogListAdapter.getItemCount());\n        for (int i = 0; i < mLogListAdapter.getItemCount(); i++) {\n            result.add(mLogListAdapter.getItem(i).getOriginalLine());\n        }\n        return result;\n    }\n\n    @NonNull\n    protected final List<String> getSelectedLogsAsStrings() {\n        List<String> result = new ArrayList<>();\n        for (LogLine logLine : mLogListAdapter.getSelectedLogLines()) {\n            result.add(logLine.getOriginalLine());\n        }\n        return result;\n    }\n\n    protected final void displaySaveLogDialog(boolean onlySelected) {\n        new TextInputDialogBuilder(mActivity, R.string.filename)\n                .setTitle(R.string.save_log)\n                .setInputText(SaveLogHelper.createLogFilename())\n                .setPositiveButton(R.string.ok, (dialog, which, inputText, isChecked) -> {\n                    if (SaveLogHelper.isInvalidFilename(inputText)) {\n                        UIUtils.displayShortToast(R.string.enter_good_filename);\n                    } else {\n                        @SuppressWarnings(\"ConstantConditions\")\n                        String filename = inputText.toString();\n                        mViewModel.saveLogs(filename, onlySelected ? getSelectedLogsAsStrings() : getCurrentLogsAsListOfStrings());\n                    }\n                })\n                .setNegativeButton(R.string.cancel, null)\n                .show();\n    }\n\n    protected final void displaySaveDebugLogsDialog(boolean share, boolean onlySelected) {\n        View view = View.inflate(mActivity, R.layout.dialog_send_log, null);\n        CheckBox includeDeviceInfoCheckBox = view.findViewById(android.R.id.checkbox);\n        CheckBox includeDmesgCheckBox = view.findViewById(R.id.checkbox_dmesg);\n\n        includeDeviceInfoCheckBox.setChecked(PreferenceHelper.getIncludeDeviceInfoPreference(mActivity));\n        includeDeviceInfoCheckBox.setOnCheckedChangeListener((buttonView, isChecked) ->\n                PreferenceHelper.setIncludeDeviceInfoPreference(mActivity, isChecked));\n\n        includeDmesgCheckBox.setChecked(PreferenceHelper.getIncludeDmesgPreference(mActivity));\n        includeDmesgCheckBox.setOnCheckedChangeListener((buttonView, isChecked) ->\n                PreferenceHelper.setIncludeDmesgPreference(mActivity, isChecked));\n\n        new MaterialAlertDialogBuilder(mActivity)\n                .setTitle(share ? R.string.share : R.string.pref_export)\n                .setView(view)\n                .setPositiveButton(R.string.ok, (dialog, which) ->\n                        shareOrSaveLogs(share, onlySelected, includeDeviceInfoCheckBox.isChecked(), includeDmesgCheckBox.isChecked()))\n                .setNegativeButton(R.string.cancel, null)\n                .show();\n    }\n\n    private void shareOrSaveLogs(boolean share, boolean onlySelected, boolean includeDeviceInfo, boolean includeDmesg) {\n        mActivity.setLogsToBeShared(share, includeDeviceInfo || includeDmesg);\n        mViewModel.prepareLogsToBeSent(includeDeviceInfo, includeDmesg, onlySelected ? getSelectedLogsAsStrings() : getCurrentLogsAsListOfStrings());\n    }\n\n    private void displayOpenLogFileDialog() {\n        List<Path> logFiles = SaveLogHelper.getLogFiles();\n        if (logFiles.isEmpty()) {\n            UIUtils.displayShortToast(R.string.no_saved_logs);\n            return;\n        }\n        new SearchableItemsDialogBuilder<>(mActivity, SaveLogHelper.getFormattedFilenames(mActivity, logFiles))\n                .setTitle(R.string.open)\n                .setOnItemClickListener((dialog, which, item) -> mActivity.openLogFile(logFiles.get(which)))\n                .setNegativeButton(R.string.close, null)\n                .show();\n    }\n\n    private void displayDeleteSavedLogsDialog() {\n        List<Path> logFiles = SaveLogHelper.getLogFiles();\n        if (logFiles.isEmpty()) {\n            UIUtils.displayShortToast(R.string.no_saved_logs);\n            return;\n        }\n        CharSequence[] filenameArray = SaveLogHelper.getFormattedFilenames(mActivity, logFiles);\n        new SearchableMultiChoiceDialogBuilder<>(mActivity, logFiles, filenameArray)\n                .setTitle(R.string.manage_saved_logs)\n                .setPositiveButton(R.string.delete, (dialog, which, selectedFiles) -> {\n                    final int deleteCount = selectedFiles.size();\n                    if (deleteCount == 0) return;\n                    new MaterialAlertDialogBuilder(mActivity)\n                            .setTitle(R.string.delete_saved_log)\n                            .setCancelable(true)\n                            .setMessage(getResources().getQuantityString(R.plurals.file_deletion_confirmation,\n                                    deleteCount, deleteCount))\n                            .setPositiveButton(android.R.string.ok, (dialog1, which1) -> {\n                                for (Path selectedFile : selectedFiles) {\n                                    SaveLogHelper.deleteLogIfExists(selectedFile.getName());\n                                }\n                                UIUtils.displayShortToast(R.string.deleted_successfully);\n                            })\n                            .setNegativeButton(android.R.string.cancel, null)\n                            .show();\n                })\n                .setNegativeButton(R.string.cancel, null)\n                .show();\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/logcat/CrazyLoggerService.java",
    "content": "// SPDX-License-Identifier: WTFPL AND GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.logcat;\n\nimport android.content.Intent;\nimport android.os.SystemClock;\nimport android.util.Log;\n\nimport java.util.Random;\n\nimport io.github.muntashirakon.AppManager.types.ForegroundService;\n\n// Copyright 2012 Nolan Lawson\npublic class CrazyLoggerService extends ForegroundService {\n    public static final String TAG = CrazyLoggerService.class.getSimpleName();\n\n    public static final int[] LOG_LEVELS = new int[]{Log.VERBOSE, Log.DEBUG, Log.INFO, Log.WARN, Log.ERROR, Log.ASSERT};\n    public static final String[] LOG_MESSAGES = new String[]{\n            \"Email: email@me.com\",\n            \"FTP: ftp://website.com:21\",\n            \"HTTP: https://website.com\",\n            \"A simple log\",\n            \"Another log\"\n    };\n\n    private static final long INTERVAL = 300;\n    private boolean mKill = false;\n\n    public CrazyLoggerService() {\n        super(TAG);\n    }\n\n    protected void onHandleIntent(Intent intent) {\n        while (!mKill) {\n            SystemClock.sleep(INTERVAL);\n            if (new Random().nextInt(100) % 5 == 0) {\n                Log.println(LOG_LEVELS[new Random().nextInt(6)], TAG, LOG_MESSAGES[new Random().nextInt(5)]);\n            }\n        }\n    }\n\n    @Override\n    public void onDestroy() {\n        super.onDestroy();\n        mKill = true;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/logcat/LiveLogViewerFragment.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.logcat;\n\nimport static io.github.muntashirakon.AppManager.logcat.LogViewerActivity.UPDATE_CHECK_INTERVAL;\n\nimport android.os.Bundle;\nimport android.text.TextUtils;\nimport android.view.Menu;\nimport android.view.MenuInflater;\nimport android.view.MenuItem;\nimport android.view.View;\nimport android.widget.Filter;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport java.lang.ref.WeakReference;\nimport java.util.List;\n\nimport io.github.muntashirakon.AppManager.BuildConfig;\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.logcat.helper.ServiceHelper;\nimport io.github.muntashirakon.AppManager.logcat.struct.LogLine;\nimport io.github.muntashirakon.AppManager.logs.Log;\nimport io.github.muntashirakon.AppManager.settings.Prefs;\nimport io.github.muntashirakon.AppManager.utils.ContextUtils;\nimport io.github.muntashirakon.AppManager.utils.ThreadUtils;\nimport io.github.muntashirakon.AppManager.utils.UIUtils;\nimport io.github.muntashirakon.AppManager.utils.Utils;\nimport io.github.muntashirakon.multiselection.MultiSelectionActionsView;\n\n// Copyright 2022 Muntashir Al-Islam\npublic class LiveLogViewerFragment extends AbsLogViewerFragment implements LogViewerViewModel.LogLinesAvailableInterface,\n        MultiSelectionActionsView.OnItemSelectedListener, LogViewerActivity.SearchingInterface, Filter.FilterListener {\n    public static final String TAG = LiveLogViewerFragment.class.getSimpleName();\n\n    private int mLogCounter = 0;\n    @Override\n    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {\n        super.onViewCreated(view, savedInstanceState);\n        mMultiSelectionView.setOnSelectionChangeListener(selectionCount -> {\n            if (selectionCount == 1) {\n                mViewModel.pauseLogcat();\n            } else if (selectionCount == 0) {\n                mViewModel.resumeLogcat();\n            }\n            return false;\n        });\n        mViewModel.startLogcat(new WeakReference<>(this));\n    }\n\n    @Override\n    public void onResume() {\n        if (mLogListAdapter != null && mLogListAdapter.getItemCount() > 0) {\n            // Scroll to bottom\n            // TODO: 31/5/22 Is this really required?\n            mRecyclerView.scrollToPosition(mLogListAdapter.getItemCount() - 1);\n        }\n        if (mActivity.getSupportActionBar() != null) {\n            mActivity.getSupportActionBar().setSubtitle(\"\");\n        }\n        super.onResume();\n\n    }\n\n    @Override\n    public void onCreateMenu(@NonNull Menu menu, @NonNull MenuInflater menuInflater) {\n        menuInflater.inflate(R.menu.fragment_live_log_viewer_actions, menu);\n    }\n\n    @Override\n    public void onPrepareMenu(@NonNull Menu menu) {\n        super.onPrepareMenu(menu);\n\n        boolean recordingInProgress = ServiceHelper.checkIfServiceIsRunning(requireContext().getApplicationContext(),\n                LogcatRecordingService.class);\n        MenuItem recordMenuItem = menu.findItem(R.id.action_record);\n        recordMenuItem.setEnabled(!recordingInProgress);\n        recordMenuItem.setVisible(!recordingInProgress);\n\n        MenuItem crazyLoggerMenuItem = menu.findItem(R.id.action_crazy_logger_service);\n        crazyLoggerMenuItem.setEnabled(BuildConfig.DEBUG);\n        crazyLoggerMenuItem.setVisible(BuildConfig.DEBUG);\n    }\n\n    @Override\n    public boolean onMenuItemSelected(@NonNull MenuItem item) {\n        int id = item.getItemId();\n        if (id == R.id.action_play_pause) {\n            if (mViewModel.isLogcatPaused()) {\n                mViewModel.resumeLogcat();\n                item.setIcon(R.drawable.ic_pause);\n            } else {\n                mViewModel.pauseLogcat();\n                item.setIcon(R.drawable.ic_play_arrow);\n            }\n        } else if (id == R.id.action_clear) {\n            if (mLogListAdapter != null) {\n                mLogListAdapter.clear();\n                UIUtils.displayLongToast(R.string.log_cleared);\n            }\n        } else if (id == R.id.action_record) {\n            mStoragePermission.request(granted -> {\n                if (granted) {\n                    mActivity.showRecordLogDialog();\n                }\n            });\n        } else if (id == R.id.action_crazy_logger_service) {\n            ServiceHelper.startOrStopCrazyLogger(mActivity);\n        } else return super.onMenuItemSelected(item);\n        return true;\n    }\n\n    @Override\n    public void onNewLogsAvailable(@NonNull List<LogLine> logLines) {\n        mActivity.hideProgressBar();\n        for (LogLine logLine : logLines) {\n            mLogListAdapter.addWithFilter(logLine, mSearchCriteria, true);\n            mActivity.addToAutocompleteSuggestions(logLine);\n        }\n\n        // How many logs to keep in memory, to avoid OutOfMemoryError\n        int maxNumLogLines = Prefs.LogViewer.getDisplayLimit();\n\n        // Check to see if the list needs to be truncated to avoid OutOfMemoryError\n        ++mLogCounter;\n        if (mLogCounter % UPDATE_CHECK_INTERVAL == 0 && mLogListAdapter.getRealSize() > maxNumLogLines) {\n            int numItemsToRemove = mLogListAdapter.getRealSize() - maxNumLogLines;\n            mLogListAdapter.removeFirst(numItemsToRemove);\n            Log.d(TAG, \"Truncating %d lines from log list to avoid out of memory errors\", numItemsToRemove);\n        }\n\n        if (mAutoscrollToBottom) {\n            mRecyclerView.scrollToPosition(mLogListAdapter.getItemCount() - 1);\n        }\n    }\n\n    @Override\n    public boolean onNavigationItemSelected(@NonNull MenuItem item) {\n        int id = item.getItemId();\n        if (id == R.id.action_save) {\n            displaySaveLogDialog(true);\n        } else if (id == R.id.action_copy) {\n            ThreadUtils.postOnBackgroundThread(() -> {\n                String logs = TextUtils.join(\"\\n\", getSelectedLogsAsStrings());\n                ThreadUtils.postOnMainThread(() -> Utils.copyToClipboard(ContextUtils.getContext(), \"Logs\", logs));\n            });\n        } else if (id == R.id.action_export) {\n            displaySaveDebugLogsDialog(false, true);\n        } else if (id == R.id.action_share) {\n            displaySaveDebugLogsDialog(true, true);\n        } else return false;\n        return true;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/logcat/LogFilterAdapter.java",
    "content": "// SPDX-License-Identifier: WTFPL AND GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.logcat;\n\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.TextView;\n\nimport androidx.annotation.NonNull;\nimport androidx.recyclerview.widget.RecyclerView;\n\nimport com.google.android.material.button.MaterialButton;\n\nimport java.util.Collections;\nimport java.util.List;\n\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.db.AppsDb;\nimport io.github.muntashirakon.AppManager.db.entity.LogFilter;\nimport io.github.muntashirakon.util.AdapterUtils;\nimport io.github.muntashirakon.AppManager.utils.ThreadUtils;\n\n// Copyright 2012 Nolan Lawson\npublic class LogFilterAdapter extends RecyclerView.Adapter<LogFilterAdapter.ViewHolder> {\n\n    private OnClickListener mListener;\n    private final List<LogFilter> mItems;\n\n    public void setOnItemClickListener(OnClickListener listener) {\n        mListener = listener;\n    }\n\n    public LogFilterAdapter(@NonNull List<LogFilter> items) {\n        mItems = items;\n    }\n\n    public void add(@NonNull LogFilter filter) {\n        int previousSize = mItems.size();\n        mItems.add(filter);\n        Collections.sort(mItems, LogFilter.COMPARATOR);\n        int currentSize = mItems.size();\n        AdapterUtils.notifyDataSetChanged(this, previousSize, currentSize);\n    }\n\n    @NonNull\n    @Override\n    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {\n        View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_title_action, parent, false);\n        return new ViewHolder(v);\n    }\n\n    @Override\n    public void onBindViewHolder(@NonNull ViewHolder holder, int position) {\n        final LogFilter logFilter = mItems.get(position);\n        holder.textView.setText(logFilter.name);\n        holder.itemView.setOnClickListener(v -> {\n            if (mListener != null) {\n                mListener.onClick(holder.itemView, position, logFilter);\n            }\n        });\n        holder.actionButton.setOnClickListener(v -> {\n            ThreadUtils.postOnBackgroundThread(() -> AppsDb.getInstance().logFilterDao().delete(logFilter));\n            mItems.remove(position);\n            notifyItemRemoved(position);\n        });\n    }\n\n    @Override\n    public int getItemCount() {\n        return mItems.size();\n    }\n\n    public interface OnClickListener {\n        void onClick(View view, int position, LogFilter logFilter);\n    }\n\n    public static class ViewHolder extends RecyclerView.ViewHolder {\n        TextView textView;\n        MaterialButton actionButton;\n\n        public ViewHolder(View itemView) {\n            super(itemView);\n            textView = itemView.findViewById(R.id.item_title);\n            actionButton = itemView.findViewById(R.id.item_action);\n            actionButton.setContentDescription(itemView.getContext().getString(R.string.item_remove));\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/logcat/LogViewerActivity.java",
    "content": "// SPDX-License-Identifier: WTFPL AND GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.logcat;\n\nimport android.app.Activity;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.database.MatrixCursor;\nimport android.net.Uri;\nimport android.os.Bundle;\nimport android.os.PowerManager;\nimport android.provider.BaseColumns;\nimport android.text.TextUtils;\nimport android.view.MenuItem;\nimport android.view.View;\nimport android.widget.TextView;\n\nimport androidx.activity.result.ActivityResult;\nimport androidx.activity.result.contract.ActivityResultContracts;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.WorkerThread;\nimport androidx.appcompat.app.ActionBar;\nimport androidx.appcompat.app.AlertDialog;\nimport androidx.core.content.ContextCompat;\nimport androidx.cursoradapter.widget.CursorAdapter;\nimport androidx.cursoradapter.widget.SimpleCursorAdapter;\nimport androidx.fragment.app.DialogFragment;\nimport androidx.fragment.app.Fragment;\nimport androidx.lifecycle.ViewModelProvider;\nimport androidx.recyclerview.widget.LinearLayoutManager;\n\nimport com.google.android.material.dialog.MaterialAlertDialogBuilder;\nimport com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton;\nimport com.google.android.material.progressindicator.LinearProgressIndicator;\nimport com.google.android.material.textfield.TextInputLayout;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Objects;\nimport java.util.Set;\n\nimport io.github.muntashirakon.AppManager.BaseActivity;\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.db.AppsDb;\nimport io.github.muntashirakon.AppManager.db.dao.LogFilterDao;\nimport io.github.muntashirakon.AppManager.db.entity.LogFilter;\nimport io.github.muntashirakon.AppManager.fm.FmProvider;\nimport io.github.muntashirakon.AppManager.intercept.IntentCompat;\nimport io.github.muntashirakon.AppManager.logcat.helper.SaveLogHelper;\nimport io.github.muntashirakon.AppManager.logcat.helper.ServiceHelper;\nimport io.github.muntashirakon.AppManager.logcat.struct.LogLine;\nimport io.github.muntashirakon.AppManager.logcat.struct.SearchCriteria;\nimport io.github.muntashirakon.AppManager.settings.Prefs;\nimport io.github.muntashirakon.AppManager.settings.SettingsActivity;\nimport io.github.muntashirakon.AppManager.utils.BetterActivityResult;\nimport io.github.muntashirakon.AppManager.utils.CpuUtils;\nimport io.github.muntashirakon.AppManager.utils.MultithreadedExecutor;\nimport io.github.muntashirakon.AppManager.utils.StoragePermission;\nimport io.github.muntashirakon.AppManager.utils.ThreadUtils;\nimport io.github.muntashirakon.AppManager.utils.UIUtils;\nimport io.github.muntashirakon.dialog.DialogTitleBuilder;\nimport io.github.muntashirakon.dialog.TextInputDropdownDialogBuilder;\nimport io.github.muntashirakon.io.Path;\nimport io.github.muntashirakon.io.Paths;\nimport io.github.muntashirakon.util.UiUtils;\nimport io.github.muntashirakon.widget.RecyclerView;\nimport io.github.muntashirakon.widget.SearchView;\n\n// Copyright 2012 Nolan Lawson\n// Copyright 2021 Muntashir Al-Islam\npublic class LogViewerActivity extends BaseActivity implements SearchView.OnQueryTextListener,\n        LogViewerRecyclerAdapter.ViewHolder.OnSearchByClickListener, SearchView.OnSuggestionListener {\n    public static final String TAG = LogViewerActivity.class.getSimpleName();\n\n    public interface SearchingInterface {\n        void onQuery(@Nullable SearchCriteria searchCriteria);\n    }\n\n    public static final String EXTRA_FILTER = \"filter\";\n    public static final String EXTRA_LEVEL = \"level\";\n\n    // how often to check to see if we've gone over the max size\n    public static final int UPDATE_CHECK_INTERVAL = 200;\n\n    // how many suggestions to keep in the autosuggestions text\n    private static final int MAX_NUM_SUGGESTIONS = 1000;\n\n    public static final String EXTRA_FILENAME = \"filename\";\n\n    private LinearProgressIndicator mProgressIndicator;\n    private ExtendedFloatingActionButton mStopRecordingFab;\n    @Nullable\n    private AlertDialog mLoadingDialog;\n    private SearchView mSearchView;\n    @Nullable\n    private SearchCriteria mSearchCriteria;\n    private boolean mDynamicallyEnteringSearchQuery;\n    private final Set<String> mSearchSuggestionsSet = new HashSet<>();\n    private CursorAdapter mSearchSuggestionsAdapter;\n    private boolean mLogsToBeShared;\n    @Nullable\n    private SearchingInterface mSearchingInterface;\n    private LogViewerViewModel mViewModel;\n    private PowerManager.WakeLock mWakeLock;\n\n    private final MultithreadedExecutor mExecutor = MultithreadedExecutor.getNewInstance();\n    private final BetterActivityResult<Intent, ActivityResult> mActivityLauncher =\n            BetterActivityResult.registerActivityForResult(this);\n    private final StoragePermission mStoragePermission = StoragePermission.init(this);\n    private final BetterActivityResult<String, Uri> mSaveLauncher = BetterActivityResult\n            .registerForActivityResult(this, new ActivityResultContracts.CreateDocument(\"*/*\"));\n\n    public static void startChooser(@NonNull Context context, @Nullable String subject,\n                                    @NonNull String attachmentType, @NonNull Path attachment) {\n        Intent actionSendIntent = new Intent(Intent.ACTION_SEND)\n                .setType(attachmentType)\n                .putExtra(Intent.EXTRA_SUBJECT, subject)\n                .putExtra(Intent.EXTRA_STREAM, FmProvider.getContentUri(attachment))\n                .addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);\n        try {\n            context.startActivity(Intent.createChooser(actionSendIntent, context.getResources().getText(R.string.send_log_title))\n                    .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK));\n        } catch (Exception e) {\n            UIUtils.displayLongToast(e.getMessage());\n        }\n    }\n\n    @Override\n    public void onAuthenticated(Bundle savedInstanceState) {\n        setContentView(R.layout.activity_logcat);\n        setSupportActionBar(findViewById(R.id.toolbar));\n        mViewModel = new ViewModelProvider(this).get(LogViewerViewModel.class);\n        mProgressIndicator = findViewById(R.id.progress_linear);\n        mProgressIndicator.setVisibilityAfterHide(View.GONE);\n        mStopRecordingFab = findViewById(R.id.fab);\n        UiUtils.applyWindowInsetsAsMargin(mStopRecordingFab);\n\n        ActionBar actionBar = getSupportActionBar();\n        if (actionBar != null) {\n            actionBar.setDisplayHomeAsUpEnabled(true);\n            actionBar.setDisplayShowCustomEnabled(true);\n            mSearchView = UIUtils.setupSearchView(actionBar, this);\n            mSearchView.setOnSuggestionListener(this);\n        }\n\n        mSearchSuggestionsAdapter = new SimpleCursorAdapter(this, io.github.muntashirakon.ui.R.layout.auto_complete_dropdown_item, null,\n                new String[]{\"suggestion\"}, new int[]{android.R.id.text1},\n                CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);\n        mSearchView.setSuggestionsAdapter(mSearchSuggestionsAdapter);\n\n        // Set removal of sensitive info\n        LogLine.omitSensitiveInfo = Prefs.LogViewer.omitSensitiveInfo();\n\n        if (\"record\".equals(getIntent().getStringExtra(\"shortcut_action\"))) {\n            // Handle shortcut\n            mStoragePermission.request(granted -> {\n                if (granted) {\n                    startLogRecorder();\n                }\n            });\n            return;\n        }\n\n        mStopRecordingFab.setOnClickListener(v -> {\n            // Stop log recorder\n            ServiceHelper.stopBackgroundServiceIfRunning(LogViewerActivity.this);\n        });\n\n        // Set collapsed mode\n        mViewModel.setCollapsedMode(!Prefs.LogViewer.expandByDefault());\n\n        // It doesn't matter whether the permission has been granted or not, we can start logging\n        mViewModel.observeLoggingFinished().observe(this, finished -> {\n            if (finished) {\n                mProgressIndicator.hide();\n                if (mViewModel.isLogcatPaused()) {\n                    mViewModel.resumeLogcat();\n                }\n            }\n        });\n        mViewModel.observeLoadingProgress().observe(this, percentage ->\n                mProgressIndicator.setProgressCompat(percentage, true));\n        mViewModel.observeTruncatedLines().observe(this, maxDisplayedLines -> UIUtils.displayLongToast(\n                getResources().getQuantityString(R.plurals.toast_log_truncated, maxDisplayedLines, maxDisplayedLines)));\n        mViewModel.getLogFilters().observe(this, this::showFiltersDialog);\n        mViewModel.observeLogSaved().observe(this, path -> {\n            if (path != null) {\n                UIUtils.displayShortToast(R.string.log_saved);\n                if (!path.getName().endsWith(\".zip\")) {\n                    openLogFile(path.getName());\n                }\n            } else {\n                UIUtils.displayLongToast(R.string.unable_to_save_log);\n            }\n        });\n        mViewModel.getLogsToBeSent().observe(this, sendLogDetails -> {\n            if (mLoadingDialog != null) {\n                mLoadingDialog.dismiss();\n            }\n            if (sendLogDetails == null\n                    || sendLogDetails.getAttachmentType() == null\n                    || sendLogDetails.getAttachment() == null) {\n                UIUtils.displayLongToast(R.string.failed);\n                return;\n            }\n            if (mLogsToBeShared) {\n                // Open chooser dialog\n                startChooser(this, sendLogDetails.getSubject(), sendLogDetails.getAttachmentType(),\n                        sendLogDetails.getAttachment());\n            } else {\n                // Open SAF activity\n                mSaveLauncher.launch(sendLogDetails.getAttachment().getName(), uri -> {\n                    if (uri == null) return;\n                    mViewModel.saveLogs(Paths.get(uri), sendLogDetails);\n                });\n            }\n        });\n\n        startLogging();\n    }\n\n    public void loadNewFragment(Fragment fragment) {\n        getSupportFragmentManager()\n                .beginTransaction()\n                .replace(R.id.main_layout, fragment)\n                .addToBackStack(null)\n                .commit();\n    }\n\n    private void startLogRecorder() {\n        String logFilename = SaveLogHelper.createLogFilename();\n        mExecutor.submit(() -> {\n            // Start recording logs\n            Intent intent = ServiceHelper.getLogcatRecorderServiceIfNotAlreadyRunning(this, logFilename,\n                    \"\", Prefs.LogViewer.getLogLevel());\n            runOnUiThread(() -> {\n                if (intent != null) {\n                    ContextCompat.startForegroundService(this, intent);\n                }\n                finish();\n            });\n        });\n    }\n\n    @WorkerThread\n    private void addFiltersToSuggestions() {\n        for (LogFilter logFilter : AppsDb.getInstance().logFilterDao().getAll()) {\n            addToAutocompleteSuggestions(logFilter.name);\n        }\n    }\n\n    private void startLogging() {\n        applyFiltersFromIntent(getIntent());\n        Uri dataUri = IntentCompat.getDataUri(getIntent());\n        String filename = getIntent().getStringExtra(EXTRA_FILENAME);\n        if (dataUri != null) {\n            openLogFile(dataUri);\n        } else if (filename != null) {\n            openLogFile(filename);\n        } else {\n            mWakeLock = CpuUtils.getPartialWakeLock(\"logcat_activity\");\n            mWakeLock.acquire();\n            startLiveLogViewer(false);\n        }\n    }\n\n    private void applyFiltersFromIntent(@Nullable Intent intent) {\n        if (intent == null) return;\n        String filter = intent.getStringExtra(EXTRA_FILTER);\n        String level = intent.getStringExtra(EXTRA_LEVEL);\n        if (!TextUtils.isEmpty(filter)) {\n            setSearchQuery(filter);\n        }\n        if (!TextUtils.isEmpty(level)) {\n            int logLevelLimit = LogLine.convertCharToLogLevel(level.charAt(0));\n            if (logLevelLimit == -1) {\n                UIUtils.displayLongToast(R.string.toast_invalid_level, level);\n            } else {\n                mViewModel.setLogLevel(logLevelLimit);\n                search(mSearchCriteria);\n            }\n        }\n    }\n\n    @Override\n    public void onResume() {\n        super.onResume();\n        if (mStopRecordingFab != null) {\n            boolean recordingInProgress = ServiceHelper.checkIfServiceIsRunning(getApplicationContext(), LogcatRecordingService.class);\n            mStopRecordingFab.setVisibility(recordingInProgress ? View.VISIBLE : View.GONE);\n        }\n    }\n\n    @Override\n    protected void onNewIntent(@NonNull Intent intent) {\n        super.onNewIntent(intent);\n        applyFiltersFromIntent(intent);\n        Uri dataUri = IntentCompat.getDataUri(intent);\n        String filename = intent.getStringExtra(EXTRA_FILENAME);\n        if (dataUri != null) {\n            openLogFile(dataUri);\n        } else if (filename != null) {\n            openLogFile(filename);\n        }\n    }\n\n    @Override\n    public void onDestroy() {\n        CpuUtils.releaseWakeLock(mWakeLock);\n        super.onDestroy();\n        mExecutor.shutdownNow();\n    }\n\n    private void startLiveLogViewer(boolean force) {\n        if (!mViewModel.isLogcatKilled() && !force) {\n            // Logcat already running\n            mViewModel.resumeLogcat();\n            return;\n        }\n        // (re)start logcat\n        resetDisplay();\n        mProgressIndicator.hide();\n        mProgressIndicator.setIndeterminate(true);\n        mProgressIndicator.show();\n        if (getSupportFragmentManager().findFragmentByTag(LiveLogViewerFragment.TAG) != null) {\n            // Fragment already exists, just restart logcat\n            mViewModel.restartLogcat();\n            return;\n        }\n        getSupportFragmentManager()\n                .beginTransaction()\n                .replace(R.id.main_layout, new LiveLogViewerFragment(), LiveLogViewerFragment.TAG)\n                .commit();\n    }\n\n    private void populateSuggestionsAdapter(@Nullable String query) {\n        final MatrixCursor c = new MatrixCursor(new String[]{BaseColumns._ID, \"suggestion\"});\n        List<String> suggestionsForQuery = getSuggestionsForQuery(query);\n        for (int i = 0, suggestionsForQuerySize = suggestionsForQuery.size(); i < suggestionsForQuerySize; i++) {\n            String suggestion = suggestionsForQuery.get(i);\n            c.addRow(new Object[]{i, suggestion});\n        }\n        mSearchSuggestionsAdapter.changeCursor(c);\n    }\n\n    @NonNull\n    private List<String> getSuggestionsForQuery(@Nullable String query) {\n        List<String> suggestions = new ArrayList<>(mSearchSuggestionsSet);\n        Collections.sort(suggestions, String.CASE_INSENSITIVE_ORDER);\n        List<String> actualSuggestions = new ArrayList<>();\n        if (query != null) {\n            for (String suggestion : suggestions) {\n                if (suggestion.toLowerCase(Locale.getDefault()).startsWith(query.toLowerCase(Locale.getDefault()))) {\n                    actualSuggestions.add(suggestion);\n                }\n            }\n        }\n        return actualSuggestions;\n    }\n\n    @Override\n    public boolean onOptionsItemSelected(MenuItem item) {\n        int itemId = item.getItemId();\n        if (itemId == android.R.id.home) {\n            getOnBackPressedDispatcher().onBackPressed();\n            return true;\n        }\n        return false;\n    }\n\n    @Override\n    public boolean onSearchByClick(MenuItem item, LogLine logLine) {\n        if (logLine != null) {\n            if (logLine.getPid() == -1) {\n                // invalid line\n                return false;\n            }\n            showSearchByDialog(logLine);\n            return true;\n        }\n        return false;\n    }\n\n    @Override\n    public boolean onQueryTextSubmit(String query) {\n        return false;\n    }\n\n    @Override\n    public boolean onQueryTextChange(String newText) {\n        if (!mDynamicallyEnteringSearchQuery) {\n            search(new SearchCriteria(newText));\n            populateSuggestionsAdapter(newText);\n        }\n        mDynamicallyEnteringSearchQuery = false;\n        return false;\n    }\n\n    @Override\n    public boolean onSuggestionSelect(int position) {\n        return false;\n    }\n\n    @Override\n    public boolean onSuggestionClick(int position) {\n        List<String> suggestions = getSuggestionsForQuery(mSearchCriteria != null ? mSearchCriteria.query : null);\n        if (!suggestions.isEmpty()) {\n            mSearchView.setQuery(suggestions.get(position), true);\n        }\n        return false;\n    }\n\n    void hideProgressBar() {\n        if (mProgressIndicator != null) {\n            mProgressIndicator.hide();\n        }\n    }\n\n    void setLogsToBeShared(boolean logsToBeShared, boolean displayLoader) {\n        mLogsToBeShared = logsToBeShared;\n        if (displayLoader) {\n            mLoadingDialog = UIUtils.getProgressDialog(LogViewerActivity.this, R.string.dialog_compiling_log);\n            mLoadingDialog.show();\n        } else mLoadingDialog = null;\n    }\n\n    void addToAutocompleteSuggestions(@NonNull LogLine logLine) {\n        if (logLine.getTagName() == null) return;\n        String tag = logLine.getTagName().trim();\n        if (!TextUtils.isEmpty(tag)) {\n            addToAutocompleteSuggestions(tag);\n        }\n    }\n\n    void displayLogViewerSettings() {\n        Intent intent = SettingsActivity.getSettingsIntent(this, \"log_viewer_prefs\");\n        mActivityLauncher.launch(intent, result -> {\n            // Preferences may have changed\n            mViewModel.setCollapsedMode(!Prefs.LogViewer.expandByDefault());\n            if (result.getResultCode() == Activity.RESULT_FIRST_USER) {\n                Intent data = result.getData();\n                if (data != null && data.getBooleanExtra(\"bufferChanged\", false)) {\n                    // Log buffer changed, so update list\n                    startLiveLogViewer(true);\n                }\n            }\n        });\n    }\n\n    private void showSearchByDialog(final LogLine logLine) {\n        View view = View.inflate(this, R.layout.dialog_searchby, null);\n        AlertDialog dialog = new MaterialAlertDialogBuilder(this)\n                .setTitle(R.string.filter_choice)\n                .setIcon(io.github.muntashirakon.ui.R.drawable.ic_search)\n                .setView(view)\n                .setNegativeButton(R.string.close, null)\n                .show();\n\n        TextInputLayout pkg = view.findViewById(R.id.search_by_pkg);\n        TextInputLayout tag = view.findViewById(R.id.search_by_tag);\n        TextInputLayout uid = view.findViewById(R.id.search_by_uid);\n        TextInputLayout pid = view.findViewById(R.id.search_by_pid);\n\n        if (logLine.getPackageName() == null) {\n            pkg.setVisibility(View.GONE);\n        }\n        if (logLine.getUidOwner() == null) {\n            uid.setVisibility(View.GONE);\n        }\n\n        TextView pkgText = pkg.getEditText();\n        TextView tagText = tag.getEditText();\n        TextView uidText = uid.getEditText();\n        TextView pidText = pid.getEditText();\n\n        Objects.requireNonNull(pkgText).setText(logLine.getPackageName());\n        Objects.requireNonNull(tagText).setText(logLine.getTagName());\n        Objects.requireNonNull(uidText).setText(String.format(Locale.ROOT, \"%s (%d)\", logLine.getUidOwner(), logLine.getUid()));\n        Objects.requireNonNull(pidText).setText(String.valueOf(logLine.getPid()));\n\n        pkg.setEndIconOnClickListener(v -> {\n            setSearchQuery(SearchCriteria.PKG_KEYWORD + logLine.getPackageName());\n            dialog.dismiss();\n        });\n\n        tag.setEndIconOnClickListener(v -> {\n            String tagQuery = (logLine.getTagName().contains(\" \")) ? ('\"' + logLine.getTagName() + '\"') : logLine.getTagName();\n            setSearchQuery(SearchCriteria.TAG_KEYWORD + tagQuery);\n            dialog.dismiss();\n        });\n\n        uid.setEndIconOnClickListener(v -> {\n            setSearchQuery(SearchCriteria.UID_KEYWORD + logLine.getUidOwner());\n            dialog.dismiss();\n        });\n\n        pid.setEndIconOnClickListener(v -> {\n            setSearchQuery(SearchCriteria.PID_KEYWORD + logLine.getPid());\n            dialog.dismiss();\n        });\n    }\n\n    void showRecordLogDialog() {\n        String[] suggestions = mSearchSuggestionsSet.toArray(new String[0]);\n        DialogFragment dialog = RecordLogDialogFragment.getInstance(suggestions, () -> {\n            if (mStopRecordingFab != null) {\n                mStopRecordingFab.setVisibility(View.VISIBLE);\n            }\n        });\n        dialog.show(getSupportFragmentManager(), RecordLogDialogFragment.TAG);\n    }\n\n    private void showFiltersDialog(List<LogFilter> filters) {\n        LogFilterAdapter logFilterAdapter = new LogFilterAdapter(filters);\n        RecyclerView recyclerView = new RecyclerView(this);\n        recyclerView.setLayoutManager(new LinearLayoutManager(this));\n        recyclerView.setAdapter(logFilterAdapter);\n\n        DialogTitleBuilder builder = new DialogTitleBuilder(this)\n                .setTitle(R.string.saved_filters)\n                .setEndIcon(R.drawable.ic_add, v -> new TextInputDropdownDialogBuilder(this, R.string.text_filter_text)\n                        .setTitle(R.string.add_filter)\n                        .setDropdownItems(new ArrayList<>(mSearchSuggestionsSet), -1, true)\n                        .setPositiveButton(android.R.string.ok, (dialog1, which, inputText, isChecked) ->\n                                handleNewFilterText(inputText == null ? \"\" : inputText.toString(), logFilterAdapter))\n                        .setNegativeButton(R.string.cancel, null)\n                        .show())\n                .setEndIconContentDescription(R.string.add_filter_ellipsis);\n        AlertDialog alertDialog = new MaterialAlertDialogBuilder(this)\n                .setCustomTitle(builder.build())\n                .setView(recyclerView)\n                .setNegativeButton(R.string.ok, null)\n                .show();\n\n        logFilterAdapter.setOnItemClickListener((v, position, logFilter) -> {\n            setSearchQuery(logFilter.name);\n            alertDialog.dismiss();\n        });\n    }\n\n    protected void handleNewFilterText(@NonNull String text, final LogFilterAdapter logFilterAdapter) {\n        final String trimmed = text.trim();\n        if (!TextUtils.isEmpty(trimmed)) {\n            mExecutor.submit(() -> {\n                LogFilterDao dao = AppsDb.getInstance().logFilterDao();\n                long id = dao.insert(trimmed);\n                LogFilter logFilter = dao.get(id);\n                if (logFilter == null) {\n                    return;\n                }\n                ThreadUtils.postOnMainThread(() -> {\n                    logFilterAdapter.add(logFilter);\n                    addToAutocompleteSuggestions(trimmed);\n                });\n            });\n        }\n    }\n\n    void setSearchingInterface(@Nullable SearchingInterface searchingInterface) {\n        mSearchingInterface = searchingInterface;\n    }\n\n    void openLogFile(Path logFile) {\n        mProgressIndicator.hide();\n        mProgressIndicator.setIndeterminate(false);\n        mProgressIndicator.show();\n\n        loadNewFragment(SavedLogViewerFragment.getInstance(logFile.getUri()));\n    }\n\n    private void openLogFile(String filename) {\n        try {\n            Path logFile = SaveLogHelper.getFile(filename);\n            mProgressIndicator.hide();\n            mProgressIndicator.setIndeterminate(false);\n            mProgressIndicator.show();\n\n            loadNewFragment(SavedLogViewerFragment.getInstance(logFile.getUri()));\n        } catch (IOException e) {\n            e.printStackTrace();\n        }\n    }\n\n    private void openLogFile(Uri logFile) {\n        mProgressIndicator.hide();\n        mProgressIndicator.setIndeterminate(false);\n        mProgressIndicator.show();\n\n        loadNewFragment(SavedLogViewerFragment.getInstance(logFile));\n    }\n\n    private void resetDisplay() {\n        mViewModel.setCollapsedMode(!Prefs.LogViewer.expandByDefault());\n        // Populate suggestions with existing filters (if any)\n        mExecutor.submit(this::addFiltersToSuggestions);\n        resetFilter();\n    }\n\n    private void resetFilter() {\n        mViewModel.setLogLevel(Prefs.LogViewer.getLogLevel());\n        search(mSearchCriteria);\n    }\n\n    private void setSearchQuery(String text) {\n        // Sets the search text without invoking autosuggestions, which are really only useful when typing\n        mDynamicallyEnteringSearchQuery = true;\n        search(new SearchCriteria(text));\n        mSearchView.setIconified(false);\n        mSearchView.setQuery(mSearchCriteria != null ? mSearchCriteria.query : null, true);\n        mSearchView.clearFocus();\n    }\n\n    @Nullable\n    SearchCriteria getSearchQuery() {\n        return mSearchCriteria;\n    }\n\n    void search(@Nullable SearchCriteria searchCriteria) {\n        if (mSearchingInterface != null) {\n            mSearchingInterface.onQuery(searchCriteria);\n        }\n        mSearchCriteria = searchCriteria;\n        if (mSearchCriteria == null || !TextUtils.isEmpty(mSearchCriteria.query)) {\n            mDynamicallyEnteringSearchQuery = true;\n        }\n    }\n\n    private void addToAutocompleteSuggestions(String trimmed) {\n        if (mSearchSuggestionsSet.size() < MAX_NUM_SUGGESTIONS && !mSearchSuggestionsSet.contains(trimmed)) {\n            mSearchSuggestionsSet.add(trimmed);\n            populateSuggestionsAdapter(mSearchCriteria != null ? mSearchCriteria.query : null);\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/logcat/LogViewerRecyclerAdapter.java",
    "content": "// SPDX-License-Identifier: WTFPL AND GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.logcat;\n\nimport android.content.Context;\nimport android.view.LayoutInflater;\nimport android.view.Menu;\nimport android.view.MenuItem;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.Filter;\nimport android.widget.Filterable;\nimport android.widget.TextView;\n\nimport androidx.annotation.ColorInt;\nimport androidx.annotation.GuardedBy;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.appcompat.widget.PopupMenu;\nimport androidx.collection.SparseArrayCompat;\nimport androidx.core.content.ContextCompat;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.Iterator;\nimport java.util.LinkedHashSet;\nimport java.util.List;\nimport java.util.Set;\n\nimport io.github.muntashirakon.AppManager.BuildConfig;\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.logcat.struct.LogLine;\nimport io.github.muntashirakon.AppManager.logcat.struct.SearchCriteria;\nimport io.github.muntashirakon.AppManager.logs.Log;\nimport io.github.muntashirakon.AppManager.settings.Prefs;\nimport io.github.muntashirakon.AppManager.utils.Utils;\nimport io.github.muntashirakon.util.AccessibilityUtils;\nimport io.github.muntashirakon.util.AdapterUtils;\nimport io.github.muntashirakon.widget.MultiSelectionView;\n\n// Copyright 2012 Nolan Lawson\n// Copyright 2021 Muntashir Al-Islam\npublic class LogViewerRecyclerAdapter extends MultiSelectionView.Adapter<LogViewerRecyclerAdapter.ViewHolder>\n        implements Filterable {\n    public static final String TAG = LogViewerRecyclerAdapter.class.getSimpleName();\n\n    private static final SparseArrayCompat<Integer> BACKGROUND_COLORS = new SparseArrayCompat<Integer>(7) {\n        {\n            put(android.util.Log.VERBOSE, io.github.muntashirakon.ui.R.color.the_brown_shirts);\n            put(android.util.Log.DEBUG, io.github.muntashirakon.ui.R.color.night_blue_shadow);\n            put(android.util.Log.INFO, io.github.muntashirakon.ui.R.color.blue_popsicle);\n            put(android.util.Log.WARN, io.github.muntashirakon.ui.R.color.red_orange);\n            put(android.util.Log.ERROR, io.github.muntashirakon.ui.R.color.pure_red);\n            put(android.util.Log.ASSERT, io.github.muntashirakon.ui.R.color.pure_red);\n            put(LogLine.LOG_FATAL, io.github.muntashirakon.ui.R.color.electric_red);\n        }\n    };\n\n    private static final SparseArrayCompat<Integer> FOREGROUND_COLORS = new SparseArrayCompat<Integer>(7) {\n        {\n            put(android.util.Log.VERBOSE, io.github.muntashirakon.ui.R.color.brian_wrinkle_white);\n            put(android.util.Log.DEBUG, io.github.muntashirakon.ui.R.color.brian_wrinkle_white);\n            put(android.util.Log.INFO, io.github.muntashirakon.ui.R.color.brian_wrinkle_white);\n            put(android.util.Log.WARN, io.github.muntashirakon.ui.R.color.brian_wrinkle_white);\n            put(android.util.Log.ERROR, io.github.muntashirakon.ui.R.color.brian_wrinkle_white);\n            put(android.util.Log.ASSERT, io.github.muntashirakon.ui.R.color.brian_wrinkle_white);\n            put(LogLine.LOG_FATAL, io.github.muntashirakon.ui.R.color.brian_wrinkle_white);\n        }\n    };\n\n    private static int[] sTagColors;\n\n    @ColorInt\n    private static int getBackgroundColorForLogLevel(Context context, int logLevel) {\n        Integer result = BACKGROUND_COLORS.get(logLevel);\n        if (result == null) {\n            throw new IllegalArgumentException(\"Invalid log level: \" + logLevel);\n        }\n        return ContextCompat.getColor(context, result);\n    }\n\n    @ColorInt\n    private static int getForegroundColorForLogLevel(Context context, int logLevel) {\n        Integer result = FOREGROUND_COLORS.get(logLevel);\n        if (result == null) {\n            throw new IllegalArgumentException(\"Invalid log level: \" + logLevel);\n        }\n        return ContextCompat.getColor(context, result);\n    }\n\n    private static synchronized int getOrCreateTagColor(Context context, String tag) {\n        if (sTagColors == null) {\n            sTagColors = context.getResources().getIntArray(R.array.random_colors);\n        }\n        // Ensure consistency\n        int hashCode = (tag == null) ? 0 : tag.hashCode();\n        int smear = Math.abs(hashCode) % sTagColors.length;\n        return sTagColors[smear];\n    }\n\n    /**\n     * Lock used to modify the content of {@link #mObjects}. Any write operation\n     * performed on the array should be synchronized on this lock. This lock is also\n     * used by the filter (see {@link #getFilter()} to make a synchronized copy of\n     * the original array of data.\n     */\n    private final Object mLock = new Object();\n    /**\n     * Contains the list of objects that represent the data of this ArrayAdapter.\n     * The content of this list is referred to as \"the array\" in the documentation.\n     */\n    @GuardedBy(\"mLock\")\n    private List<LogLine> mObjects;\n\n    private ViewHolder.OnSearchByClickListener mSearchByClickListener;\n\n    private ArrayList<LogLine> mOriginalValues;\n    private ArrayFilter mFilter;\n\n    private int mLogLevelLimit = Prefs.LogViewer.getLogLevel();\n    private final Set<LogLine> mSelectedLogLines = new LinkedHashSet<>();\n\n    public LogViewerRecyclerAdapter() {\n        mObjects = new ArrayList<>();\n        setHasStableIds(true);\n    }\n\n    /**\n     * Adds the specified object at the end of the array.\n     *\n     * @param object The object to add at the end of the array.\n     */\n    @GuardedBy(\"mLock\")\n    public void add(LogLine object, boolean notify) {\n        synchronized (mLock) {\n            if (mOriginalValues != null) {\n                mOriginalValues.add(object);\n            }\n            mObjects.add(object);\n            if (notify) {\n                notifyItemInserted(mObjects.size() - 1);\n            }\n        }\n    }\n\n    @GuardedBy(\"mLock\")\n    public void readAll(LogLine object, boolean notify) {\n        synchronized (mLock) {\n            if (mOriginalValues != null) {\n                mOriginalValues.add(object);\n            }\n            mObjects.add(object);\n            if (notify) {\n                notifyItemInserted(mObjects.size() - 1);\n            }\n        }\n    }\n\n    public void addWithFilter(@NonNull LogLine object, @Nullable SearchCriteria searchCriteria, boolean notify) {\n        if (mOriginalValues != null) {\n            List<LogLine> inputList = Collections.singletonList(object);\n            if (mFilter == null) {\n                mFilter = new ArrayFilter();\n            }\n            List<LogLine> filteredObjects = mFilter.performFilteringOnList(inputList, searchCriteria);\n            synchronized (mLock) {\n                mOriginalValues.add(object);\n                mObjects.addAll(filteredObjects);\n                if (!filteredObjects.isEmpty() && notify) {\n                    notifyItemRangeInserted(mObjects.size() - filteredObjects.size(), filteredObjects.size());\n                }\n            }\n        } else {\n            synchronized (mLock) {\n                mObjects.add(object);\n                if (notify) {\n                    notifyItemInserted(mObjects.size() - 1);\n                }\n            }\n        }\n    }\n\n    /**\n     * Inserts the specified object at the specified index in the array.\n     *\n     * @param object The object to insert into the array.\n     * @param index  The index at which the object must be inserted.\n     */\n    @GuardedBy(\"mLock\")\n    public void insert(LogLine object, int index) {\n        synchronized (mLock) {\n            if (mOriginalValues != null) {\n                mOriginalValues.add(index, object);\n            } else {\n                mObjects.add(index, object);\n                notifyItemChanged(index, AdapterUtils.STUB);\n            }\n        }\n    }\n\n    /**\n     * Removes the specified object from the array.\n     *\n     * @param object The object to remove.\n     */\n    @GuardedBy(\"mLock\")\n    public void remove(LogLine object) {\n        synchronized (mLock) {\n            if (mOriginalValues != null) {\n                mOriginalValues.remove(object);\n            } else {\n                int pos = mObjects.indexOf(object);\n                if (pos >= 0) {\n                    mObjects.remove(pos);\n                    notifyItemRemoved(pos);\n                }\n            }\n        }\n    }\n\n    public void removeFirst(int n) {\n        StopWatch stopWatch = new StopWatch(\"removeFirst()\");\n        if (mOriginalValues != null) {\n            synchronized (mLock) {\n                List<LogLine> subList = mOriginalValues.subList(n, mOriginalValues.size());\n                for (int i = 0; i < n; i++) {\n                    int pos = mObjects.indexOf(mOriginalValues.get(i));\n                    if (pos >= 0) {\n                        mObjects.remove(pos);\n                        notifyItemRemoved(pos);\n                    }\n                }\n                mOriginalValues = new ArrayList<>(subList);\n            }\n        } else {\n            synchronized (mLock) {\n                mObjects = new ArrayList<>(mObjects.subList(n, mObjects.size()));\n                notifyItemRangeRemoved(0, n);\n            }\n        }\n        stopWatch.log();\n    }\n\n    /**\n     * Remove all elements from the list.\n     */\n    @GuardedBy(\"mLock\")\n    public void clear() {\n        synchronized (mLock) {\n            if (mOriginalValues != null) {\n                mOriginalValues.clear();\n            }\n            int size = mObjects.size();\n            mObjects.clear();\n            notifyItemRangeRemoved(0, size);\n        }\n    }\n\n    @GuardedBy(\"mLock\")\n    public LogLine getItem(int position) {\n        synchronized (mLock) {\n            return mObjects.get(position);\n        }\n    }\n\n    @Nullable\n    @GuardedBy(\"mLock\")\n    private LogLine getItemSafe(int position) {\n        synchronized (mLock) {\n            if (mObjects.size() > position) {\n                return mObjects.get(position);\n            }\n            return null;\n        }\n    }\n\n    @GuardedBy(\"mLock\")\n    public int getRealSize() {\n        synchronized (mLock) {\n            return (mOriginalValues != null ? mOriginalValues : mObjects).size();\n        }\n    }\n\n    public Set<LogLine> getSelectedLogLines() {\n        return mSelectedLogLines;\n    }\n\n    @GuardedBy(\"mLock\")\n    public void setCollapseMode(boolean isCollapsed) {\n        synchronized (mLock) {\n            List<LogLine> list = mOriginalValues != null ? mOriginalValues : mObjects;\n            for (LogLine logLine : list) {\n                logLine.setExpanded(!isCollapsed);\n            }\n        }\n    }\n\n    @Override\n    protected boolean select(int position) {\n        synchronized (mSelectedLogLines) {\n            LogLine logLine = getItemSafe(position);\n            if (logLine != null) {\n                mSelectedLogLines.add(logLine);\n            }\n            return logLine != null;\n        }\n    }\n\n    @Override\n    protected boolean deselect(int position) {\n        synchronized (mSelectedLogLines) {\n            LogLine logLine = getItemSafe(position);\n            if (logLine != null) {\n                return mSelectedLogLines.remove(logLine);\n            }\n            return false;\n        }\n    }\n\n    @Override\n    protected boolean isSelected(int position) {\n        synchronized (mSelectedLogLines) {\n            LogLine logLine = getItemSafe(position);\n            if (logLine != null) {\n                return mSelectedLogLines.contains(logLine);\n            }\n            return false;\n        }\n    }\n\n    @Override\n    protected void cancelSelection() {\n        super.cancelSelection();\n        synchronized (mSelectedLogLines) {\n            mSelectedLogLines.clear();\n        }\n    }\n\n    @Override\n    protected int getSelectedItemCount() {\n        synchronized (mSelectedLogLines) {\n            return mSelectedLogLines.size();\n        }\n    }\n\n    @Override\n    protected int getTotalItemCount() {\n        return getItemCount();\n    }\n\n    @NonNull\n    @Override\n    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {\n        View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_logcat, parent, false);\n        return new ViewHolder(v);\n    }\n\n    @Override\n    public void onBindViewHolder(@NonNull ViewHolder holder, int position) {\n        Context context = holder.itemView.getContext();\n        LogLine logLine = getItem(position);\n        holder.logLine = logLine;\n\n        int levelColor = getBackgroundColorForLogLevel(context, logLine.getLogLevel());\n        TextView t = holder.logLevel;\n        t.setText(logLine.getProcessIdText());\n        t.setBackgroundColor(levelColor);\n        t.setTextColor(getForegroundColorForLogLevel(context, logLine.getLogLevel()));\n        t.setVisibility(logLine.getLogLevel() == -1 ? View.GONE : View.VISIBLE);\n\n        holder.itemView.setBackgroundResource(0);\n        holder.contentView.setBackgroundResource(position % 2 == 0 ? io.github.muntashirakon.ui.R.drawable.item_semi_transparent : io.github.muntashirakon.ui.R.drawable.item_transparent);\n\n        // Display message\n        TextView output = holder.output;\n        output.setSingleLine(!logLine.isExpanded());\n        output.setText(logLine.getLogOutput());\n\n        //TAG TEXT VIEW\n        TextView tag = holder.tag;\n        tag.setSingleLine(!logLine.isExpanded());\n        tag.setText(logLine.getTagName());\n        tag.setVisibility(logLine.getLogLevel() == -1 ? View.GONE : View.VISIBLE);\n\n        //EXPANDED INFO\n        boolean extraInfoIsVisible = logLine.isExpanded() && logLine.getPid() != -1 // -1 marks lines like 'beginning of /dev/log...'\n                && Prefs.LogViewer.showPidTidTimestamp();\n\n        TextView infoText = holder.info;\n        infoText.setVisibility(extraInfoIsVisible ? View.VISIBLE : View.GONE);\n\n        if (extraInfoIsVisible) {\n            StringBuilder sb = new StringBuilder(logLine.getTimestamp());\n            if (logLine.getPid() >= 0) {\n                sb.append(\" • \").append(logLine.getPid());\n            }\n            if (logLine.getUidOwner() != null) {\n                sb.append(\" • \").append(logLine.getUidOwner());\n            }\n            if (logLine.getPackageName() != null) {\n                sb.append(\" • \").append(logLine.getPackageName());\n            }\n            infoText.setText(sb);\n        }\n\n        tag.setTextColor(getOrCreateTagColor(context, logLine.getTagName()));\n        // Single click on the item:\n        // 1. If it is in selection mode, select the item\n        // 2. Otherwise, expand the item\n        holder.itemView.setOnClickListener(v -> {\n            if (isInSelectionMode()) {\n                toggleSelection(position);\n                AccessibilityUtils.requestAccessibilityFocus(holder.itemView);\n            } else {\n                LogLine line = holder.logLine;\n                line.setExpanded(!line.isExpanded());\n                notifyItemChanged(position, AdapterUtils.STUB);\n            }\n        });\n        // Long click on the item:\n        // 1. If it is in selection mode, select range of item\n        // 2. Open context menu\n        holder.itemView.setOnLongClickListener(v -> {\n            if (isInSelectionMode()) {\n                int lastSelectedItemPosition = getLastSelectedItemPosition();\n                if (lastSelectedItemPosition >= 0) {\n                    // Select from last selection to this selection\n                    selectRange(lastSelectedItemPosition, position);\n                } else {\n                    toggleSelection(position);\n                    AccessibilityUtils.requestAccessibilityFocus(holder.itemView);\n                }\n                return true;\n            }\n            PopupMenu popupMenu = new PopupMenu(v.getContext(), v);\n            popupMenu.setForceShowIcon(true);\n            Menu menu = popupMenu.getMenu();\n            menu.add(R.string.filter_choice)\n                    .setIcon(io.github.muntashirakon.ui.R.drawable.ic_search)\n                    .setOnMenuItemClickListener(menuItem -> {\n                        if (mSearchByClickListener != null) {\n                            return mSearchByClickListener.onSearchByClick(menuItem, holder.logLine);\n                        }\n                        return true;\n                    });\n            menu.add(R.string.copy_to_clipboard)\n                    .setIcon(R.drawable.ic_content_copy)\n                    .setOnMenuItemClickListener(menuItem -> {\n                        Utils.copyToClipboard(context, null, holder.logLine.getOriginalLine());\n                        return true;\n                    });\n            menu.add(R.string.item_select)\n                    .setIcon(R.drawable.ic_check_circle)\n                    .setOnMenuItemClickListener(menuItem -> {\n                        toggleSelection(position);\n                        AccessibilityUtils.requestAccessibilityFocus(holder.itemView);\n                        return true;\n                    });\n            popupMenu.show();\n            return true;\n        });\n        super.onBindViewHolder(holder, position);\n    }\n\n    @GuardedBy(\"mLock\")\n    @Override\n    public long getItemId(int position) {\n        synchronized (mLock) {\n            return mObjects.get(position).getOriginalLine().hashCode();\n        }\n    }\n\n    @GuardedBy(\"mLock\")\n    @Override\n    public int getItemCount() {\n        synchronized (mLock) {\n            return mObjects.size();\n        }\n    }\n\n    public int getLogLevelLimit() {\n        return mLogLevelLimit;\n    }\n\n    public void setLogLevelLimit(int logLevelLimit) {\n        mLogLevelLimit = logLevelLimit;\n    }\n\n    /**\n     * {@inheritDoc}\n     */\n    @Override\n    public Filter getFilter() {\n        if (mFilter == null) {\n            mFilter = new ArrayFilter();\n        }\n        return mFilter;\n    }\n\n    public void setClickListener(ViewHolder.OnSearchByClickListener clickListener) {\n        mSearchByClickListener = clickListener;\n    }\n\n    private int getLastSelectedItemPosition() {\n        // Last selected item is the same as the last added item.\n        Iterator<LogLine> it = mSelectedLogLines.iterator();\n        LogLine lastItem = null;\n        while (it.hasNext()) {\n            lastItem = it.next();\n        }\n        if (lastItem != null) {\n            int i = 0;\n            for (LogLine fmItem : mObjects) {\n                if (fmItem.equals(lastItem)) {\n                    return i;\n                }\n                ++i;\n            }\n        }\n        return -1;\n    }\n\n    /**\n     * <p>An array filter constrains the content of the array adapter with\n     * a prefix. Each item that does not start with the supplied prefix\n     * is removed from the list.</p>\n     */\n    private class ArrayFilter extends Filter {\n        @NonNull\n        @Override\n        protected FilterResults performFiltering(CharSequence prefix) {\n            FilterResults results = new FilterResults();\n\n            if (mOriginalValues == null) {\n                synchronized (mLock) {\n                    mOriginalValues = new ArrayList<>(mObjects);\n                }\n            }\n\n            SearchCriteria searchCriteria = new SearchCriteria(prefix != null ? prefix.toString() : null);\n            ArrayList<LogLine> allValues = performFilteringOnList(mOriginalValues, searchCriteria);\n\n            results.values = allValues;\n            results.count = allValues.size();\n\n            return results;\n        }\n\n        public ArrayList<LogLine> performFilteringOnList(List<LogLine> inputList, @Nullable SearchCriteria searchCriteria) {\n            // search by log level\n            ArrayList<LogLine> allValues = new ArrayList<>();\n\n            ArrayList<LogLine> logLines;\n            synchronized (mLock) {\n                logLines = new ArrayList<>(inputList);\n            }\n\n            for (LogLine logLine : logLines) {\n                if (logLine != null && logLine.getLogLevel() >= mLogLevelLimit) {\n                    allValues.add(logLine);\n                }\n            }\n            ArrayList<LogLine> finalValues = allValues;\n\n            // search by criteria\n            if (searchCriteria != null && !searchCriteria.isEmpty()) {\n                final int count = allValues.size();\n                final ArrayList<LogLine> newValues = new ArrayList<>(count);\n                for (final LogLine value : allValues) {\n                    // search the logline based on the criteria\n                    if (searchCriteria.matches(value)) {\n                        newValues.add(value);\n                    }\n                }\n                finalValues = newValues;\n            }\n            return finalValues;\n        }\n\n        @SuppressWarnings(\"unchecked\")\n        @Override\n        protected void publishResults(CharSequence constraint, FilterResults results) {\n            synchronized (mLock) {\n                int previousCount = mObjects != null ? mObjects.size() : 0;\n                mObjects = (List<LogLine>) results.values;\n                AdapterUtils.notifyDataSetChanged(LogViewerRecyclerAdapter.this, previousCount, mObjects.size());\n            }\n        }\n    }\n\n    private static class StopWatch {\n        private long mStartTime;\n        private String mName;\n\n        public StopWatch(String name) {\n            if (BuildConfig.DEBUG) {\n                mName = name;\n                mStartTime = System.currentTimeMillis();\n            }\n        }\n\n        public void log() {\n            Log.d(TAG, \"%s took %d ms\", mName, (System.currentTimeMillis() - mStartTime));\n        }\n    }\n\n    public static class ViewHolder extends MultiSelectionView.ViewHolder {\n        LogLine logLine;\n        View contentView;\n        TextView logLevel;\n        TextView tag;\n        TextView output;\n        TextView info;\n\n        public ViewHolder(View itemView) {\n            super(itemView);\n            contentView = itemView.findViewById(R.id.log_content);\n            logLevel = itemView.findViewById(R.id.log_level_text);\n            tag = itemView.findViewById(R.id.tag_text);\n            output = itemView.findViewById(R.id.log_output_text);\n            info = itemView.findViewById(R.id.info);\n        }\n\n        public interface OnSearchByClickListener {\n            boolean onSearchByClick(MenuItem item, LogLine logLine);\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/logcat/LogViewerViewModel.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.logcat;\n\nimport android.app.Application;\nimport android.net.Uri;\n\nimport androidx.annotation.AnyThread;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.UiThread;\nimport androidx.annotation.WorkerThread;\nimport androidx.lifecycle.AndroidViewModel;\nimport androidx.lifecycle.LiveData;\nimport androidx.lifecycle.MutableLiveData;\n\nimport java.io.BufferedOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.lang.ref.WeakReference;\nimport java.nio.charset.StandardCharsets;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.regex.Pattern;\nimport java.util.zip.ZipEntry;\nimport java.util.zip.ZipOutputStream;\n\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.db.AppsDb;\nimport io.github.muntashirakon.AppManager.db.entity.LogFilter;\nimport io.github.muntashirakon.AppManager.logcat.helper.BuildHelper;\nimport io.github.muntashirakon.AppManager.logcat.helper.SaveLogHelper;\nimport io.github.muntashirakon.AppManager.logcat.reader.LogcatReader;\nimport io.github.muntashirakon.AppManager.logcat.reader.LogcatReaderLoader;\nimport io.github.muntashirakon.AppManager.logcat.struct.LogLine;\nimport io.github.muntashirakon.AppManager.logcat.struct.SavedLog;\nimport io.github.muntashirakon.AppManager.logcat.struct.SendLogDetails;\nimport io.github.muntashirakon.AppManager.logs.Log;\nimport io.github.muntashirakon.AppManager.runner.Runner;\nimport io.github.muntashirakon.AppManager.self.filecache.FileCache;\nimport io.github.muntashirakon.AppManager.settings.Prefs;\nimport io.github.muntashirakon.AppManager.utils.MultithreadedExecutor;\nimport io.github.muntashirakon.AppManager.utils.ThreadUtils;\nimport io.github.muntashirakon.io.IoUtils;\nimport io.github.muntashirakon.io.Path;\nimport io.github.muntashirakon.io.Paths;\n\n// Copyright 2022 Muntashir Al-Islam\npublic class LogViewerViewModel extends AndroidViewModel {\n    public static final String TAG = LogViewerViewModel.class.getSimpleName();\n\n    public interface LogLinesAvailableInterface {\n        @UiThread\n        void onNewLogsAvailable(@NonNull List<LogLine> logLines);\n    }\n\n    private final Object mLock = new Object();\n\n    private volatile boolean mPaused;\n    private volatile boolean mKilled = true;\n    private volatile boolean mCollapsedMode;\n    private volatile int mLogLevel;\n    private volatile LogcatReader mReader;\n\n    private final Pattern mFilterPattern;\n    private final MutableLiveData<Boolean> mExpandLogsLiveData = new MutableLiveData<>();\n    private final MutableLiveData<Boolean> mLoggingFinishedLiveData = new MutableLiveData<>();\n    private final MutableLiveData<Integer> mLoadingProgressLiveData = new MutableLiveData<>();\n    private final MutableLiveData<Integer> mTruncatedLinesLiveData = new MutableLiveData<>();\n    private final MutableLiveData<Integer> mLogLevelLiveData = new MutableLiveData<>();\n    private final MutableLiveData<List<LogFilter>> mLogFiltersLiveData = new MutableLiveData<>();\n    private final MutableLiveData<Path> mLogSavedLiveData = new MutableLiveData<>();\n    private final MutableLiveData<SendLogDetails> mLogToBeSentLiveData = new MutableLiveData<>();\n    private final MultithreadedExecutor mExecutor = MultithreadedExecutor.getNewInstance();\n\n    public LogViewerViewModel(@NonNull Application application) {\n        super(application);\n        mFilterPattern = Pattern.compile(Prefs.LogViewer.getFilterPattern());\n    }\n\n    @Override\n    protected void onCleared() {\n        killLogcatReaderInternal();\n        mExecutor.shutdown();\n        super.onCleared();\n    }\n\n    public LiveData<Boolean> observeLoggingFinished() {\n        return mLoggingFinishedLiveData;\n    }\n\n    public LiveData<Integer> observeLoadingProgress() {\n        return mLoadingProgressLiveData;\n    }\n\n    public LiveData<Integer> observeTruncatedLines() {\n        return mTruncatedLinesLiveData;\n    }\n\n    public LiveData<List<LogFilter>> getLogFilters() {\n        return mLogFiltersLiveData;\n    }\n\n    public LiveData<Path> observeLogSaved() {\n        return mLogSavedLiveData;\n    }\n\n    public MutableLiveData<Integer> observeLogLevelLiveData() {\n        return mLogLevelLiveData;\n    }\n\n    public LiveData<SendLogDetails> getLogsToBeSent() {\n        return mLogToBeSentLiveData;\n    }\n\n    public LiveData<Boolean> getExpandLogsLiveData() {\n        return mExpandLogsLiveData;\n    }\n\n    @AnyThread\n    public void startLogcat(@Nullable WeakReference<LogLinesAvailableInterface> logLinesAvailableInterface) {\n        mExecutor.submit(() -> {\n            mKilled = false;\n            try {\n                mReader = LogcatReaderLoader.create(true).loadReader();\n\n                int maxLines = Prefs.LogViewer.getDisplayLimit();\n\n                String line;\n                LinkedList<LogLine> initialLines = new LinkedList<>();\n                while ((line = mReader.readLine()) != null && !ThreadUtils.isInterrupted()) {\n                    if (mPaused) {\n                        synchronized (mLock) {\n                            if (mPaused) {\n                                mLock.wait();\n                            }\n                        }\n                    }\n                    LogLine logLine = LogLine.newLogLine(line, !mCollapsedMode, mFilterPattern);\n                    if (logLine == null) {\n                        if (mReader.readyToRecord()) {\n                            // Logcat is ready\n                        }\n                    } else if (!mReader.readyToRecord()) {\n                        // \"ready to record\" in this case means all the initial lines have been flushed from the reader\n                        initialLines.add(logLine);\n                        if (initialLines.size() > maxLines) {\n                            initialLines.removeFirst();\n                        }\n                    } else if (!initialLines.isEmpty()) {\n                        // flush all the initial lines we've loaded\n                        initialLines.add(logLine);\n                        sendNewLogs(initialLines, logLinesAvailableInterface);\n                        initialLines.clear();\n                    } else {\n                        // just proceed as normal\n                        sendNewLogs(Collections.singletonList(logLine), logLinesAvailableInterface);\n                    }\n                }\n            } catch (Exception e) {\n                Log.e(TAG, e);\n            } finally {\n                if (logLinesAvailableInterface != null) {\n                    logLinesAvailableInterface.clear();\n                }\n                killLogcatReaderInternal();\n            }\n            mLoggingFinishedLiveData.postValue(true);\n        });\n    }\n\n    @AnyThread\n    public void restartLogcat() {\n        mExecutor.submit(() -> {\n            synchronized (mLock) {\n                // Pause -> reload reader -> resume\n                mPaused = true;\n                try {\n                    mReader = LogcatReaderLoader.create(true).loadReader();\n                } catch (Exception e) {\n                    // Errors do not matter\n                    Log.e(TAG, e);\n                } finally {\n                    mPaused = false;\n                    mLock.notify();\n                }\n            }\n        });\n    }\n\n    private static void sendNewLogs(@NonNull List<LogLine> logLines, @Nullable WeakReference<LogLinesAvailableInterface> logLinesAvailableInterface) {\n        if (logLinesAvailableInterface != null) {\n            LogLinesAvailableInterface i = logLinesAvailableInterface.get();\n            List<LogLine> logLines1 = new ArrayList<>(logLines);\n            if (i != null) {\n                ThreadUtils.postOnMainThread(() -> i.onNewLogsAvailable(logLines1));\n            }\n        }\n    }\n\n    @AnyThread\n    public void pauseLogcat() {\n        mExecutor.submit(() -> {\n            synchronized (mLock) {\n                mPaused = true;\n            }\n        });\n    }\n\n    @AnyThread\n    public void resumeLogcat() {\n        mExecutor.submit(() -> {\n            synchronized (mLock) {\n                mPaused = false;\n                mLock.notify();\n            }\n        });\n    }\n\n    public boolean isLogcatPaused() {\n        return mPaused;\n    }\n\n    public boolean isLogcatKilled() {\n        return mKilled;\n    }\n\n    public boolean isCollapsedMode() {\n        return mCollapsedMode;\n    }\n\n    public void setCollapsedMode(boolean collapsedMode) {\n        mCollapsedMode = collapsedMode;\n        mExpandLogsLiveData.postValue(collapsedMode);\n    }\n\n    public int getLogLevel() {\n        return mLogLevel;\n    }\n\n    public void setLogLevel(int logLevel) {\n        mLogLevel = logLevel;\n        mLogLevelLiveData.postValue(mLogLevel);\n    }\n\n    @AnyThread\n    public void killLogcatReader() {\n        mExecutor.submit(this::killLogcatReaderInternal);\n    }\n\n    @WorkerThread\n    private void killLogcatReaderInternal() {\n        if (!mKilled) {\n            synchronized (mLock) {\n                if (!mKilled && mReader != null) {\n                    mReader.killQuietly();\n                    mKilled = true;\n                }\n            }\n        }\n    }\n\n    @AnyThread\n    public void openLogsFromFile(Uri filename, @Nullable WeakReference<LogLinesAvailableInterface> logLinesAvailableInterface) {\n        mExecutor.submit(() -> {\n            // remove any lines at the beginning if necessary\n            final int maxLines = Prefs.LogViewer.getDisplayLimit();\n            SavedLog savedLog;\n            savedLog = SaveLogHelper.openLog(filename, maxLines);\n            List<String> lines = savedLog.getLogLines();\n            List<LogLine> logLines = new ArrayList<>();\n            for (int lineNumber = 0, linesSize = lines.size(); lineNumber < linesSize; lineNumber++) {\n                String line = lines.get(lineNumber);\n                LogLine logLine = LogLine.newLogLine(line, !mCollapsedMode, mFilterPattern);\n                if (logLine != null) {\n                    logLines.add(logLine);\n                }\n                mLoadingProgressLiveData.postValue(lineNumber * 100 / linesSize);\n            }\n            sendNewLogs(logLines, logLinesAvailableInterface);\n            if (savedLog.isTruncated()) {\n                mTruncatedLinesLiveData.postValue(maxLines);\n            }\n        });\n    }\n\n    @AnyThread\n    public void loadFilters() {\n        mExecutor.submit(() -> {\n            final List<LogFilter> filters = AppsDb.getInstance().logFilterDao().getAll();\n            Collections.sort(filters);\n            mLogFiltersLiveData.postValue(filters);\n        });\n    }\n\n    @AnyThread\n    public void saveLogs(String filename, @NonNull List<String> logLines) {\n        mExecutor.submit(() -> {\n            SaveLogHelper.deleteLogIfExists(filename);\n            mLogSavedLiveData.postValue(SaveLogHelper.saveLog(logLines, filename));\n        });\n    }\n\n    @AnyThread\n    public void saveLogs(@NonNull Path path, @NonNull SendLogDetails sendLogDetails) {\n        mExecutor.submit(() -> {\n            if (sendLogDetails.getAttachmentType() == null || sendLogDetails.getAttachment() == null) {\n                mLogSavedLiveData.postValue(null);\n                return;\n            }\n            try (OutputStream output = path.openOutputStream()) {\n                try (InputStream input = sendLogDetails.getAttachment().openInputStream()) {\n                    IoUtils.copy(input, output);\n                }\n                mLogSavedLiveData.postValue(path);\n            } catch (IOException e) {\n                mLogSavedLiveData.postValue(null);\n                e.printStackTrace();\n            }\n        });\n    }\n\n    @AnyThread\n    public void prepareLogsToBeSent(boolean includeDeviceInfo, boolean includeDmesg, @NonNull Collection<String> logLines) {\n        mExecutor.submit(() -> {\n            SendLogDetails sendLogDetails = new SendLogDetails();\n            sendLogDetails.setSubject(getApplication().getString(R.string.subject_log_report));\n            // either zip up multiple files or just attach the one file\n            String deviceInfo = null;\n            if (includeDeviceInfo) {\n                deviceInfo = BuildHelper.getBuildInformationAsString();\n            }\n            String dmesg = null;\n            if (includeDmesg) {\n                Runner.Result result = Runner.runCommand(new String[]{\"dmesg\"});\n                if (result.isSuccessful()) {\n                    dmesg = result.getOutput();\n                    if (dmesg.length() == 0) {\n                        dmesg = null;\n                    }\n                }\n            }\n            int exportCount = 0;\n            if (!logLines.isEmpty()) {\n                ++exportCount;\n            }\n            if (deviceInfo != null) {\n                ++exportCount;\n            }\n            if (dmesg != null) {\n                ++exportCount;\n            }\n\n            if (exportCount == 0) {\n                sendLogDetails.setAttachmentType(null);\n            } else if (exportCount == 1) {\n                Path tempFile;\n                if (!logLines.isEmpty()) {\n                    tempFile = SaveLogHelper.saveTemporaryFile(\"log\", null, logLines);\n                } else if (dmesg != null) {\n                    tempFile = SaveLogHelper.saveTemporaryFile(\"txt\", dmesg, null);\n                } else { // Device info\n                    tempFile = SaveLogHelper.saveTemporaryFile(\"txt\", deviceInfo, null);\n                }\n                sendLogDetails.setAttachmentType(\"text/plain\");\n                sendLogDetails.setAttachment(tempFile);\n            } else { // Multiple attachments, make zip first\n                try {\n                    Path zipFile = Paths.get(FileCache.getGlobalFileCache().createCachedFile(\"zip\"));\n                    try (ZipOutputStream output = new ZipOutputStream(new BufferedOutputStream(zipFile.openOutputStream(), 0x1000))) {\n                        if (!logLines.isEmpty()) {\n                            output.putNextEntry(new ZipEntry(SaveLogHelper.LOG_FILENAME));\n                            for (String logLine : logLines) {\n                                output.write(logLine.getBytes(StandardCharsets.UTF_8));\n                                output.write(\"\\n\".getBytes(StandardCharsets.UTF_8));\n                            }\n                        }\n                        if (deviceInfo != null) {\n                            output.putNextEntry(new ZipEntry(SaveLogHelper.DEVICE_INFO_FILENAME));\n                            output.write(deviceInfo.getBytes(StandardCharsets.UTF_8));\n                        }\n                        if (dmesg != null) {\n                            output.putNextEntry(new ZipEntry(SaveLogHelper.DMESG_FILENAME));\n                            output.write(dmesg.getBytes(StandardCharsets.UTF_8));\n                        }\n                    }\n                    sendLogDetails.setAttachmentType(\"application/zip\");\n                    sendLogDetails.setAttachment(zipFile);\n                } catch (Throwable th) {\n                    th.printStackTrace();\n                    sendLogDetails.setAttachmentType(null);\n                }\n            }\n            mLogToBeSentLiveData.postValue(sendLogDetails);\n        });\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/logcat/LogcatRecordingService.java",
    "content": "// SPDX-License-Identifier: WTFPL AND GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.logcat;\n\nimport android.app.PendingIntent;\nimport android.content.BroadcastReceiver;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.IntentFilter;\nimport android.net.Uri;\nimport android.os.PowerManager;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.core.app.NotificationManagerCompat;\nimport androidx.core.app.PendingIntentCompat;\nimport androidx.core.app.ServiceCompat;\nimport androidx.core.content.ContextCompat;\n\nimport java.io.IOException;\nimport java.util.Random;\nimport java.util.regex.Pattern;\n\nimport io.github.muntashirakon.AppManager.BuildConfig;\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.intercept.IntentCompat;\nimport io.github.muntashirakon.AppManager.logcat.helper.SaveLogHelper;\nimport io.github.muntashirakon.AppManager.logcat.helper.ServiceHelper;\nimport io.github.muntashirakon.AppManager.logcat.helper.WidgetHelper;\nimport io.github.muntashirakon.AppManager.logcat.reader.LogcatReader;\nimport io.github.muntashirakon.AppManager.logcat.reader.LogcatReaderLoader;\nimport io.github.muntashirakon.AppManager.logcat.struct.LogLine;\nimport io.github.muntashirakon.AppManager.logcat.struct.SearchCriteria;\nimport io.github.muntashirakon.AppManager.logs.Log;\nimport io.github.muntashirakon.AppManager.progress.NotificationProgressHandler;\nimport io.github.muntashirakon.AppManager.progress.QueuedProgressHandler;\nimport io.github.muntashirakon.AppManager.settings.Prefs;\nimport io.github.muntashirakon.AppManager.types.ForegroundService;\nimport io.github.muntashirakon.AppManager.utils.CpuUtils;\nimport io.github.muntashirakon.AppManager.utils.NotificationUtils;\nimport io.github.muntashirakon.AppManager.utils.ThreadUtils;\nimport io.github.muntashirakon.AppManager.utils.UIUtils;\n\n/**\n * Reads logs.\n */\n// Copyright 2012 Nolan Lawson\n// Copyright 2021 Muntashir Al-Islam\npublic class LogcatRecordingService extends ForegroundService {\n    public static final String TAG = LogcatRecordingService.class.getSimpleName();\n\n    public static final String URI_SCHEME = \"am_logcat_recording_service\";\n    public static final String EXTRA_FILENAME = \"filename\";\n    public static final String EXTRA_LOADER = \"loader\";\n    public static final String EXTRA_QUERY_FILTER = \"filter\";\n    public static final String EXTRA_LEVEL = \"level\";\n\n    private static final String ACTION_STOP_RECORDING = BuildConfig.APPLICATION_ID + \".action.STOP_RECORDING\";\n    public static final String CHANNEL_ID = BuildConfig.APPLICATION_ID + \".channel.LOGCAT_RECORDER\";\n\n    private final Object mLock = new Object();\n    private LogcatReader mReader;\n    private boolean mKilled;\n    private QueuedProgressHandler mProgressHandler;\n    private PowerManager.WakeLock mWakeLock;\n    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {\n        @Override\n        public void onReceive(Context context, Intent intent) {\n            // Received broadcast to kill service\n            killProcess();\n            ServiceHelper.stopBackgroundServiceIfRunning(context);\n        }\n    };\n\n    public LogcatRecordingService() {\n        super(\"AppTrackerService\");\n    }\n\n    @Override\n    public void onCreate() {\n        super.onCreate();\n        IntentFilter intentFilter = new IntentFilter(ACTION_STOP_RECORDING);\n        intentFilter.addDataScheme(URI_SCHEME);\n        ContextCompat.registerReceiver(this, mReceiver, intentFilter, ContextCompat.RECEIVER_NOT_EXPORTED);\n        mWakeLock = CpuUtils.getPartialWakeLock(\"logcat_recorder\");\n        mWakeLock.acquire();\n    }\n\n\n    private void initializeReader(@NonNull LogcatReaderLoader loader) {\n        try {\n            mReader = loader.loadReader();\n            while (mReader != null && !mReader.readyToRecord() && !mKilled) {\n                mReader.readLine();\n                // Keep skipping lines until we find one that is past the last log line, i.e.\n                // it's ready to record\n            }\n            if (!mKilled) {\n                ThreadUtils.postOnMainThread(() -> UIUtils.displayShortToast(R.string.log_recording_started));\n            }\n        } catch (IOException e) {\n            Log.e(TAG, e);\n        }\n    }\n\n    @Override\n    public void onDestroy() {\n        CpuUtils.releaseWakeLock(mWakeLock);\n        super.onDestroy();\n        killProcess();\n        unregisterReceiver(mReceiver);\n        ServiceCompat.stopForeground(this, ServiceCompat.STOP_FOREGROUND_REMOVE);\n        WidgetHelper.updateWidgets(getApplicationContext(), false);\n    }\n\n    @Override\n    public int onStartCommand(Intent intent, int flags, int startId) {\n        // Update widget\n        WidgetHelper.updateWidgets(getApplicationContext());\n        mProgressHandler = new NotificationProgressHandler(this,\n                new NotificationProgressHandler.NotificationManagerInfo(CHANNEL_ID, \"Logcat Recorder\", NotificationManagerCompat.IMPORTANCE_DEFAULT),\n                NotificationUtils.HIGH_PRIORITY_NOTIFICATION_INFO,\n                null);\n        Intent stopRecordingIntent = new Intent();\n        stopRecordingIntent.setAction(ACTION_STOP_RECORDING);\n        // Have to make this unique for God knows what reason\n        stopRecordingIntent.setData(Uri.withAppendedPath(Uri.parse(URI_SCHEME + \"://stop/\"),\n                Long.toHexString(new Random().nextLong())));\n        PendingIntent pendingIntent = PendingIntentCompat.getBroadcast(this, 0 /* no requestCode */,\n                stopRecordingIntent, PendingIntent.FLAG_ONE_SHOT, false);\n\n        Object notificationInfo = new NotificationProgressHandler.NotificationInfo()\n                .setTitle(getString(R.string.notification_title))\n                .setBody(getString(R.string.notification_subtext))\n                .setStatusBarText(getText(R.string.notification_ticker))\n                .setDefaultAction(pendingIntent);\n        mProgressHandler.onAttach(this, notificationInfo);\n        return super.onStartCommand(intent, flags, startId);\n    }\n\n    protected void onHandleIntent(@Nullable Intent intent) {\n        if (intent == null) {\n            // Empty calls\n            return;\n        }\n        Log.d(TAG, \"Starting with intent: %s\", intent);\n        String filename = intent.getStringExtra(EXTRA_FILENAME);\n        String queryText = intent.getStringExtra(EXTRA_QUERY_FILTER);\n        SearchCriteria searchCriteria = new SearchCriteria(queryText);\n        int logLevel = intent.getIntExtra(EXTRA_LEVEL, Prefs.LogViewer.getLogLevel());\n        boolean searchCriteriaWillAlwaysMatch = searchCriteria.isEmpty();\n        boolean logLevelAcceptsEverything = logLevel == android.util.Log.VERBOSE;\n        StringBuilder stringBuilder = new StringBuilder();\n        LogcatReaderLoader loader = IntentCompat.getUnwrappedParcelableExtra(intent, EXTRA_LOADER, LogcatReaderLoader.class);\n        if (loader == null) {\n            // No loader found\n            return;\n        }\n\n        SaveLogHelper.deleteLogIfExists(filename);\n        initializeReader(loader);\n        try {\n            String line;\n            int lineCount = 0;\n            int logLinePeriod = Prefs.LogViewer.getLogWritingInterval();\n            Pattern filterPattern = Pattern.compile(Prefs.LogViewer.getFilterPattern());\n            while (mReader != null && (line = mReader.readLine()) != null && !mKilled) {\n                // filter\n                if (!searchCriteriaWillAlwaysMatch || !logLevelAcceptsEverything) {\n                    if (!checkLogLine(line, searchCriteria, logLevel, filterPattern)) {\n                        continue;\n                    }\n                }\n                stringBuilder.append(line).append(\"\\n\");\n                if (++lineCount % logLinePeriod == 0) {\n                    // avoid OutOfMemoryErrors; flush now\n                    SaveLogHelper.saveLog(stringBuilder, filename);\n                    stringBuilder.delete(0, stringBuilder.length()); // clear\n                }\n            }\n        } catch (IOException e) {\n            Log.e(TAG, e);\n        } finally {\n            killProcess();\n            Log.d(TAG, \"Service ended\");\n            boolean logSaved = SaveLogHelper.saveLog(stringBuilder, filename);\n            NotificationProgressHandler.NotificationInfo notificationInfo =\n                    new NotificationProgressHandler.NotificationInfo()\n                            .setTitle(getString(R.string.notification_title))\n                            .setAutoCancel(true);\n            if (logSaved) {\n                notificationInfo.setTitle(getString(R.string.log_saved))\n                        .setStatusBarText(getString(R.string.log_saved))\n                        .setBody(getString(R.string.tap_to_see_details))\n                        .setDefaultAction(getLogcatActivityToViewSavedFile(filename));\n            } else {\n                notificationInfo.setTitle(getString(R.string.unable_to_save_log));\n            }\n            ThreadUtils.postOnMainThread(() -> mProgressHandler.onResult(notificationInfo));\n        }\n    }\n\n    private boolean checkLogLine(String line, SearchCriteria searchCriteria, int logLevel, Pattern filterPattern) {\n        LogLine logLine = LogLine.newLogLine(line, false, filterPattern);\n        return logLine != null && logLine.getLogLevel() >= logLevel && searchCriteria.matches(logLine);\n    }\n\n\n    private PendingIntent getLogcatActivityToViewSavedFile(String filename) {\n        // Start up the logcat activity if necessary and show the saved file\n        Intent targetIntent = new Intent(getApplicationContext(), LogViewerActivity.class);\n        targetIntent.setFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_NEW_TASK);\n        targetIntent.setAction(Intent.ACTION_MAIN);\n        targetIntent.putExtra(LogViewerActivity.EXTRA_FILENAME, filename);\n        return PendingIntentCompat.getActivity(this, 0, targetIntent, PendingIntent.FLAG_ONE_SHOT, false);\n    }\n\n\n    private void killProcess() {\n        if (!mKilled) {\n            synchronized (mLock) {\n                if (!mKilled && mReader != null) {\n                    // kill the logcat process\n                    mReader.killQuietly();\n                    mKilled = true;\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/logcat/RecordLogDialogActivity.java",
    "content": "// SPDX-License-Identifier: WTFPL AND GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.logcat;\n\nimport android.os.Bundle;\n\nimport io.github.muntashirakon.AppManager.BaseActivity;\n\n// Copyright 2012 Nolan Lawson\n// Copyright 2021 Muntashir Al-Islam\npublic class RecordLogDialogActivity extends BaseActivity {\n    public static final String EXTRA_QUERY_SUGGESTIONS = \"suggestions\";\n\n    @Override\n    public boolean getTransparentBackground() {\n        return true;\n    }\n\n    @Override\n    protected void onAuthenticated(Bundle savedInstanceState) {\n        RecordLogDialogFragment dialog;\n        dialog = RecordLogDialogFragment.getInstance(getIntent().getStringArrayExtra(EXTRA_QUERY_SUGGESTIONS), null);\n        dialog.show(getSupportFragmentManager(), RecordLogDialogFragment.TAG);\n        dialog.setOnDismissListener(v -> finish());\n    }\n\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/logcat/RecordLogDialogFragment.java",
    "content": "// SPDX-License-Identifier: WTFPL AND GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.logcat;\n\nimport android.app.Dialog;\nimport android.content.Context;\nimport android.content.DialogInterface;\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.widget.Button;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.appcompat.app.AlertDialog;\nimport androidx.core.content.ContextCompat;\nimport androidx.fragment.app.DialogFragment;\nimport androidx.fragment.app.FragmentActivity;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\n\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.logcat.helper.SaveLogHelper;\nimport io.github.muntashirakon.AppManager.logcat.helper.ServiceHelper;\nimport io.github.muntashirakon.AppManager.logcat.helper.WidgetHelper;\nimport io.github.muntashirakon.AppManager.settings.LogViewerPreferences;\nimport io.github.muntashirakon.AppManager.settings.Prefs;\nimport io.github.muntashirakon.AppManager.utils.ThreadUtils;\nimport io.github.muntashirakon.AppManager.utils.UIUtils;\nimport io.github.muntashirakon.dialog.TextInputDialogBuilder;\nimport io.github.muntashirakon.dialog.TextInputDropdownDialogBuilder;\n\n// Copyright 2012 Nolan Lawson\n// Copyright 2021 Muntashir Al-Islam\npublic class RecordLogDialogFragment extends DialogFragment {\n    public static final String TAG = RecordLogDialogFragment.class.getSimpleName();\n\n    private static final String QUERY_SUGGESTIONS = \"suggestions\";\n\n    public interface OnRecordingServiceStartedListenerInterface {\n        void onServiceStarted();\n    }\n\n    @NonNull\n    public static RecordLogDialogFragment getInstance(@Nullable String[] suggestions,\n                                                      @Nullable OnRecordingServiceStartedListenerInterface listener) {\n        RecordLogDialogFragment dialogFragment = new RecordLogDialogFragment();\n        Bundle args = new Bundle();\n        args.putStringArray(QUERY_SUGGESTIONS, suggestions);\n        dialogFragment.setArguments(args);\n        dialogFragment.mListener = listener;\n        return dialogFragment;\n    }\n\n    private FragmentActivity mActivity;\n    private String mFilterQuery;\n    private int mLogLevel;\n    @Nullable\n    private OnRecordingServiceStartedListenerInterface mListener;\n    @Nullable\n    private DialogInterface.OnDismissListener mDismissListener;\n\n    public void setOnDismissListener(DialogInterface.OnDismissListener dismissListener) {\n        mDismissListener = dismissListener;\n    }\n\n    @NonNull\n    @Override\n    public Dialog onCreateDialog(Bundle savedInstanceState) {\n        mActivity = requireActivity();\n        String[] suggestions = requireArguments().getStringArray(QUERY_SUGGESTIONS);\n        String logFilename = SaveLogHelper.createLogFilename();\n        mLogLevel = Prefs.LogViewer.getLogLevel();\n        mFilterQuery = \"\";\n        return new TextInputDialogBuilder(mActivity, R.string.enter_filename)\n                .setTitle(R.string.record_log)\n                .setInputText(logFilename)\n                .setPositiveButton(R.string.ok, (dialog, which, inputText, isChecked) -> {\n                    if (SaveLogHelper.isInvalidFilename(inputText)) {\n                        UIUtils.displayShortToast(R.string.enter_good_filename);\n                    } else {\n                        //noinspection ConstantConditions\n                        String filename = inputText.toString();\n                        Context context = mActivity.getApplicationContext();\n                        ThreadUtils.postOnBackgroundThread(() -> {\n                            Intent intent = ServiceHelper.getLogcatRecorderServiceIfNotAlreadyRunning(context, filename,\n                                    mFilterQuery, mLogLevel);\n                            ThreadUtils.postOnMainThread(() -> {\n                                if (intent != null) {\n                                    ContextCompat.startForegroundService(context, intent);\n                                }\n                                if (mListener != null && !(mActivity.isFinishing() || mActivity.isDestroyed())) {\n                                    mListener.onServiceStarted();\n                                }\n                            });\n                        });\n                    }\n                })\n                .setNegativeButton(R.string.cancel, (dialog, which, inputText, isChecked) ->\n                        WidgetHelper.updateWidgets(mActivity))\n                .setNeutralButton(R.string.text_filter_ellipsis, null)\n                .setOnShowListener(dialog -> {\n                    AlertDialog dialog1 = (AlertDialog) dialog;\n                    Button filterButton = dialog1.getButton(AlertDialog.BUTTON_NEUTRAL);\n                    filterButton.setOnClickListener(v -> {\n                        WidgetHelper.updateWidgets(mActivity);\n                        showFilterDialogForRecording(suggestions != null ? Arrays.asList(suggestions) : Collections.emptyList());\n                    });\n                })\n                .create();\n    }\n\n    @Override\n    public void onDismiss(@NonNull DialogInterface dialog) {\n        super.onDismiss(dialog);\n        if (mDismissListener != null) {\n            mDismissListener.onDismiss(dialog);\n        }\n    }\n\n    public void showFilterDialogForRecording(List<String> filterQuerySuggestions) {\n        List<CharSequence> logLevelsLocalised = Arrays.asList(getResources().getStringArray(R.array.log_levels));\n        int idx = LogViewerPreferences.LOG_LEVEL_VALUES.indexOf(mLogLevel);\n        TextInputDropdownDialogBuilder builder = new TextInputDropdownDialogBuilder(mActivity, R.string.text_filter_text)\n                .setTitle(R.string.filter)\n                .setInputText(mFilterQuery)\n                .setDropdownItems(filterQuerySuggestions, -1, true)\n                .setAuxiliaryInput(getText(R.string.log_level), null, logLevelsLocalised.get(idx),\n                        logLevelsLocalised, true)\n                .setNegativeButton(R.string.cancel, null);\n        builder.setPositiveButton(R.string.ok, (dialog, which, inputText, isChecked) -> {\n            if (inputText == null || builder.getAuxiliaryInput() == null) return;\n            int logLevelIdx = logLevelsLocalised.indexOf(builder.getAuxiliaryInput().toString().trim());\n            if (logLevelIdx == -1) return;\n            mLogLevel = LogViewerPreferences.LOG_LEVEL_VALUES.get(logLevelIdx);\n            mFilterQuery = inputText.toString();\n        }).show();\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/logcat/RecordingWidgetProvider.java",
    "content": "// SPDX-License-Identifier: WTFPL AND GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.logcat;\n\nimport android.appwidget.AppWidgetManager;\nimport android.appwidget.AppWidgetProvider;\nimport android.content.Context;\nimport android.content.Intent;\n\nimport androidx.annotation.NonNull;\n\nimport io.github.muntashirakon.AppManager.logcat.helper.PreferenceHelper;\nimport io.github.muntashirakon.AppManager.logcat.helper.ServiceHelper;\nimport io.github.muntashirakon.AppManager.logcat.helper.WidgetHelper;\n\nimport java.util.Arrays;\n\nimport io.github.muntashirakon.AppManager.BuildConfig;\nimport io.github.muntashirakon.AppManager.logs.Log;\n\n// Copyright 2012 Nolan Lawson\npublic class RecordingWidgetProvider extends AppWidgetProvider {\n    public static final String TAG = RecordingWidgetProvider.class.getSimpleName();\n\n    public static final String ACTION_RECORD_OR_STOP = BuildConfig.APPLICATION_ID + \".action.RECORD_OR_STOP\";\n\n    public static final String URI_SCHEME = \"log_viewer_widget\";\n\n    @Override\n    public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {\n        super.onUpdate(context, appWidgetManager, appWidgetIds);\n        Log.d(TAG, \"onUpdate() for appWidgetIds %s\", Arrays.toString(appWidgetIds));\n\n        // track which widgets were created, since there's a bug in the android system that lets\n        // stale app widget ids stick around\n        PreferenceHelper.setWidgetExistsPreference(context, appWidgetIds);\n\n        WidgetHelper.updateWidgets(context, appWidgetIds);\n    }\n\n    @Override\n    public void onReceive(@NonNull final Context context, @NonNull Intent intent) {\n        super.onReceive(context, intent);\n        Log.d(TAG, \"onReceive called with intent %s\", intent);\n        if (ACTION_RECORD_OR_STOP.equals(intent.getAction())) {\n            // Start or stop recording as necessary\n            synchronized (RecordingWidgetProvider.class) {\n                boolean alreadyRunning = ServiceHelper.checkIfServiceIsRunning(context, LogcatRecordingService.class);\n                if (alreadyRunning) {\n                    // stop the current recording process\n                    ServiceHelper.stopBackgroundServiceIfRunning(context);\n                } else {\n                    // start a new recording process\n                    Intent targetIntent = new Intent();\n                    targetIntent.setClass(context, RecordLogDialogActivity.class);\n                    targetIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK\n                            | Intent.FLAG_ACTIVITY_MULTIPLE_TASK\n                            | Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS);\n\n                    context.startActivity(targetIntent);\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/logcat/SavedLogViewerFragment.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.logcat;\n\nimport android.net.Uri;\nimport android.os.Bundle;\nimport android.text.TextUtils;\nimport android.view.Menu;\nimport android.view.MenuInflater;\nimport android.view.MenuItem;\nimport android.view.View;\nimport android.widget.Filter;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.core.os.BundleCompat;\n\nimport java.lang.ref.WeakReference;\nimport java.util.List;\n\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.logcat.struct.LogLine;\nimport io.github.muntashirakon.AppManager.logcat.struct.SearchCriteria;\nimport io.github.muntashirakon.AppManager.utils.ContextUtils;\nimport io.github.muntashirakon.AppManager.utils.ThreadUtils;\nimport io.github.muntashirakon.AppManager.utils.Utils;\nimport io.github.muntashirakon.multiselection.MultiSelectionActionsView;\n\n// Copyright 2022 Muntashir Al-Islam\npublic class SavedLogViewerFragment extends AbsLogViewerFragment implements LogViewerViewModel.LogLinesAvailableInterface,\n        MultiSelectionActionsView.OnItemSelectedListener, LogViewerActivity.SearchingInterface, Filter.FilterListener {\n    public static final String TAG = SavedLogViewerFragment.class.getSimpleName();\n    public static final String ARG_FILE_URI = \"file_uri\";\n\n    @NonNull\n    public static SavedLogViewerFragment getInstance(@NonNull Uri uri) {\n        SavedLogViewerFragment fragment = new SavedLogViewerFragment();\n        Bundle args = new Bundle();\n        args.putParcelable(ARG_FILE_URI, uri);\n        fragment.setArguments(args);\n        return fragment;\n    }\n\n    private String mFilename = \"\";\n\n    @Override\n    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {\n        super.onViewCreated(view, savedInstanceState);\n        Uri uri = BundleCompat.getParcelable(requireArguments(), ARG_FILE_URI, Uri.class);\n        if (uri == null) {\n            // TODO: 31/5/22 Handle invalid URI\n            return;\n        }\n        mFilename = uri.getLastPathSegment();\n        mViewModel.openLogsFromFile(uri, new WeakReference<>(this));\n    }\n\n    @Override\n    public void onResume() {\n        if (mLogListAdapter != null && mLogListAdapter.getItemCount() > 0) {\n            // Scroll to bottom\n            // TODO: 31/5/22 Is this really required?\n            mRecyclerView.scrollToPosition(mLogListAdapter.getItemCount() - 1);\n        }\n        if (mActivity.getSupportActionBar() != null) {\n            mActivity.getSupportActionBar().setSubtitle(mFilename);\n        }\n        super.onResume();\n    }\n\n    @Override\n    public void onCreateMenu(@NonNull Menu menu, @NonNull MenuInflater menuInflater) {\n        menuInflater.inflate(R.menu.fragment_saved_log_viewer_actions, menu);\n    }\n\n    @Override\n    public boolean onMenuItemSelected(@NonNull MenuItem item) {\n        return super.onMenuItemSelected(item);\n    }\n\n    @Override\n    public void onNewLogsAvailable(@NonNull List<LogLine> logLines) {\n        mActivity.hideProgressBar();\n        for (LogLine logLine : logLines) {\n            mLogListAdapter.addWithFilter(logLine, new SearchCriteria(null), true);\n            mActivity.addToAutocompleteSuggestions(logLine);\n        }\n\n        mRecyclerView.scrollToPosition(mLogListAdapter.getItemCount() - 1);\n    }\n\n    @Override\n    public boolean onNavigationItemSelected(@NonNull MenuItem item) {\n        int id = item.getItemId();\n        if (id == R.id.action_save) {\n            displaySaveLogDialog(true);\n        } else if (id == R.id.action_copy) {\n            ThreadUtils.postOnBackgroundThread(() -> {\n                String logs = TextUtils.join(\"\\n\", getSelectedLogsAsStrings());\n                ThreadUtils.postOnMainThread(() -> Utils.copyToClipboard(ContextUtils.getContext(), \"Logs\", logs));\n            });\n        } else if (id == R.id.action_export) {\n            displaySaveDebugLogsDialog(false, true);\n        } else if (id == R.id.action_share) {\n            displaySaveDebugLogsDialog(true, true);\n        } else return false;\n        return true;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/logcat/helper/BuildHelper.java",
    "content": "// SPDX-License-Identifier: WTFPL AND GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.logcat.helper;\n\nimport android.os.Build;\n\nimport androidx.annotation.NonNull;\n\nimport java.lang.reflect.Field;\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Map.Entry;\nimport java.util.SortedMap;\nimport java.util.TreeMap;\n\n// Copyright 2012 Nolan Lawson\npublic class BuildHelper {\n    // From android.os.Build\n    private static final List<String> BUILD_FIELDS = Arrays.asList(\n            \"BOARD\", \"BOOTLOADER\", \"BRAND\", \"CPU_ABI\", \"CPU_ABI2\",\n            \"DEVICE\", \"DISPLAY\", \"FINGERPRINT\", \"HARDWARE\", \"HOST\",\n            \"ID\", \"MANUFACTURER\", \"MODEL\", \"PRODUCT\", \"RADIO\",\n            \"SERIAL\", \"TAGS\", \"TIME\", \"TYPE\", \"USER\");\n\n    // From android.os.Build.Version\n    private static final List<String> BUILD_VERSION_FIELDS = Arrays.asList(\n            \"CODENAME\", \"INCREMENTAL\", \"RELEASE\", \"SDK_INT\");\n\n    @NonNull\n    public static String getBuildInformationAsString() {\n        SortedMap<String, String> keysToValues = new TreeMap<>();\n        for (String buildField : BUILD_FIELDS) {\n            putKeyValue(Build.class, buildField, keysToValues);\n        }\n        for (String buildVersionField : BUILD_VERSION_FIELDS) {\n            putKeyValue(Build.VERSION.class, buildVersionField, keysToValues);\n        }\n        StringBuilder stringBuilder = new StringBuilder();\n        for (Entry<String, String> entry : keysToValues.entrySet()) {\n            stringBuilder.append(entry.getKey()).append(\": \").append(entry.getValue()).append('\\n');\n        }\n        return stringBuilder.toString();\n    }\n\n    private static void putKeyValue(@NonNull Class<?> clazz, String buildField,\n                                    @NonNull SortedMap<String, String> keysToValues) {\n        try {\n            Field field = clazz.getField(buildField);\n            Object value = field.get(null);\n            String key = clazz.getSimpleName().toLowerCase(Locale.ROOT) + \".\" + buildField.toLowerCase(Locale.ROOT);\n            keysToValues.put(key, String.valueOf(value));\n        } catch (SecurityException | NoSuchFieldException | IllegalAccessException ignore) {\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/logcat/helper/LogcatHelper.java",
    "content": "// SPDX-License-Identifier: WTFPL AND GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.logcat.helper;\n\nimport androidx.annotation.IntDef;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport java.io.BufferedReader;\nimport java.io.IOException;\nimport java.io.InputStreamReader;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\n\nimport io.github.muntashirakon.AppManager.compat.ProcessCompat;\nimport io.github.muntashirakon.AppManager.logs.Log;\n\n// Copyright 2012 Nolan Lawson\npublic class LogcatHelper {\n    public static final String TAG = LogcatHelper.class.getSimpleName();\n\n    @IntDef(value = {LOG_ID_MAIN, LOG_ID_RADIO, LOG_ID_EVENTS, LOG_ID_SYSTEM, LOG_ID_CRASH}, flag = true)\n    @Retention(RetentionPolicy.SOURCE)\n    public @interface LogBufferId {\n    }\n\n    public static final int LOG_ID_MAIN = 1;\n    public static final int LOG_ID_RADIO = 1 << 1;\n    public static final int LOG_ID_EVENTS = 1 << 2;\n    public static final int LOG_ID_SYSTEM = 1 << 3;\n    public static final int LOG_ID_CRASH = 1 << 4;\n    public static final int LOG_ID_ALL = LOG_ID_MAIN | LOG_ID_RADIO | LOG_ID_EVENTS | LOG_ID_SYSTEM | LOG_ID_CRASH;\n    public static final int LOG_ID_DEFAULT = LOG_ID_MAIN | LOG_ID_SYSTEM | LOG_ID_CRASH;\n\n    public static final String BUFFER_MAIN = \"main\";\n    public static final String BUFFER_RADIO = \"radio\";\n    public static final String BUFFER_EVENTS = \"events\";\n    public static final String BUFFER_SYSTEM = \"system\";\n    public static final String BUFFER_CRASH = \"crash\";\n    public static final String BUFFER_ALL = \"all\";\n    public static final String BUFFER_DEFAULT = \"default\";\n\n    public static final int DEFAULT_DISPLAY_LIMIT = 10_000;\n    public static final int DEFAULT_LOG_WRITE_INTERVAL = 200;\n\n    public static Process getLogcatProcess(@LogBufferId int buffers) throws IOException {\n        return ProcessCompat.exec(getLogcatArgs(buffers, false));\n    }\n\n    @Nullable\n    public static String getLastLogLine(@LogBufferId int buffers) {\n        Process dumpLogcatProcess = null;\n        String result = null;\n        try {\n            dumpLogcatProcess = ProcessCompat.exec(getLogcatArgs(buffers, true));\n            try (BufferedReader reader = new BufferedReader(new InputStreamReader(dumpLogcatProcess\n                    .getInputStream()), 8192)) {\n                String line;\n                while ((line = reader.readLine()) != null) {\n                    result = line;\n                }\n            }\n        } catch (IOException e) {\n            Log.e(TAG, e);\n        } finally {\n            if (dumpLogcatProcess != null) {\n                dumpLogcatProcess.destroy();\n                Log.d(TAG, \"destroyed 1 dump logcat process\");\n            }\n        }\n        return result;\n    }\n\n    @NonNull\n    public static String[] getLogcatArgs(@LogBufferId int buffers, boolean dumpAndExit) {\n        // https://cs.android.com/android/platform/superproject/main/+/main:system/logging/liblog/logprint.cpp;l=1547;drc=b4d6320e2ae398b36f0aaafb2ecd83609d2d99af\n        // threadtime: <time:%m-%d %H:%M:%S.%03ld> <uid:%5s> <pid:%5d> <tid:%5d> <level:%c> <tag:%s\\s+>: <message>\n        // Modifiers:\n        // - uid: Display UID (Android 7 onwards)\n        // - descriptive: Descriptive output, currently NOP (Android 8 onwards)\n        // * UID is not guaranteed\n        List<String> args = new ArrayList<>(Arrays.asList(\"logcat\", \"-v\", \"threadtime\", \"-v\", \"uid\"));\n\n        if (buffers == LOG_ID_ALL) {\n            args.add(\"-b\");\n            args.add(BUFFER_ALL);\n        } else if (buffers == LOG_ID_DEFAULT) {\n            args.add(\"-b\");\n            args.add(BUFFER_DEFAULT);\n        } else {\n            if ((buffers & LOG_ID_MAIN) != 0) {\n                args.add(\"-b\");\n                args.add(BUFFER_MAIN);\n            }\n            if ((buffers & LOG_ID_RADIO) != 0) {\n                args.add(\"-b\");\n                args.add(BUFFER_RADIO);\n            }\n            if ((buffers & LOG_ID_EVENTS) != 0) {\n                args.add(\"-b\");\n                args.add(BUFFER_EVENTS);\n            }\n            if ((buffers & LOG_ID_SYSTEM) != 0) {\n                args.add(\"-b\");\n                args.add(BUFFER_SYSTEM);\n            }\n            if ((buffers & LOG_ID_CRASH) != 0) {\n                args.add(\"-b\");\n                args.add(BUFFER_CRASH);\n            }\n        }\n        if (dumpAndExit) args.add(\"-d\");\n        return args.toArray(new String[0]);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/logcat/helper/PreferenceHelper.java",
    "content": "// SPDX-License-Identifier: WTFPL AND GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.logcat.helper;\n\nimport android.content.Context;\nimport android.content.SharedPreferences;\nimport android.content.SharedPreferences.Editor;\nimport android.preference.PreferenceManager;\n\nimport androidx.annotation.NonNull;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.settings.Prefs;\n\n// Copyright 2012 Nolan Lawson\npublic class PreferenceHelper {\n    private static final String WIDGET_EXISTS_PREFIX = \"widget_\";\n\n    public static boolean getWidgetExistsPreference(Context context, int appWidgetId) {\n        SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(context);\n        String widgetExists = WIDGET_EXISTS_PREFIX.concat(Integer.toString(appWidgetId));\n        return sharedPrefs.getBoolean(widgetExists, false);\n    }\n\n    public static void setWidgetExistsPreference(Context context, @NonNull int[] appWidgetIds) {\n        SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(context);\n        Editor editor = sharedPrefs.edit();\n        for (int appWidgetId : appWidgetIds) {\n            String widgetExists = WIDGET_EXISTS_PREFIX.concat(Integer.toString(appWidgetId));\n            editor.putBoolean(widgetExists, true);\n        }\n        editor.apply();\n    }\n\n    @NonNull\n    public static List<Integer> getBuffers() {\n        return getBuffers(Prefs.LogViewer.getBuffers());\n    }\n\n    @NonNull\n    public static List<Integer> getBuffers(@LogcatHelper.LogBufferId int buffers) {\n        List<Integer> separatedBuffers = new ArrayList<>();\n        if ((buffers & LogcatHelper.LOG_ID_MAIN) != 0) {\n            separatedBuffers.add(LogcatHelper.LOG_ID_MAIN);\n        }\n        if ((buffers & LogcatHelper.LOG_ID_RADIO) != 0) {\n            separatedBuffers.add(LogcatHelper.LOG_ID_RADIO);\n        }\n        if ((buffers & LogcatHelper.LOG_ID_EVENTS) != 0) {\n            separatedBuffers.add(LogcatHelper.LOG_ID_EVENTS);\n        }\n        if ((buffers & LogcatHelper.LOG_ID_SYSTEM) != 0) {\n            separatedBuffers.add(LogcatHelper.LOG_ID_SYSTEM);\n        }\n        if ((buffers & LogcatHelper.LOG_ID_CRASH) != 0) {\n            separatedBuffers.add(LogcatHelper.LOG_ID_CRASH);\n        }\n        return separatedBuffers;\n    }\n\n    public static boolean getIncludeDeviceInfoPreference(Context context) {\n        SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(context);\n        return sharedPrefs.getBoolean(context.getString(R.string.pref_include_device_info), true);\n    }\n\n    public static void setIncludeDeviceInfoPreference(Context context, boolean value) {\n        SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(context);\n        Editor editor = sharedPrefs.edit();\n        editor.putBoolean(context.getString(R.string.pref_include_device_info), value);\n        editor.apply();\n    }\n\n    public static boolean getIncludeDmesgPreference(Context context) {\n        SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(context);\n        return sharedPrefs.getBoolean(context.getString(R.string.pref_include_dmesg), true);\n    }\n\n    public static void setIncludeDmesgPreference(Context context, boolean value) {\n        SharedPreferences sharedPrefs = PreferenceManager.getDefaultSharedPreferences(context);\n        Editor editor = sharedPrefs.edit();\n        editor.putBoolean(context.getString(R.string.pref_include_dmesg), value);\n        editor.apply();\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/logcat/helper/SaveLogHelper.java",
    "content": "// SPDX-License-Identifier: WTFPL AND GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.logcat.helper;\n\nimport android.content.Context;\nimport android.net.Uri;\nimport android.text.SpannableStringBuilder;\nimport android.text.TextUtils;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport org.jetbrains.annotations.Contract;\n\nimport java.io.BufferedOutputStream;\nimport java.io.BufferedReader;\nimport java.io.IOException;\nimport java.io.InputStreamReader;\nimport java.io.PrintStream;\nimport java.text.DateFormat;\nimport java.text.DecimalFormat;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Calendar;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.Date;\nimport java.util.GregorianCalendar;\nimport java.util.LinkedList;\nimport java.util.List;\n\nimport io.github.muntashirakon.AppManager.logcat.struct.SavedLog;\nimport io.github.muntashirakon.AppManager.logs.Log;\nimport io.github.muntashirakon.AppManager.self.filecache.FileCache;\nimport io.github.muntashirakon.AppManager.settings.Prefs;\nimport io.github.muntashirakon.AppManager.utils.UIUtils;\nimport io.github.muntashirakon.io.Path;\nimport io.github.muntashirakon.io.Paths;\n\n// Copyright 2012 Nolan Lawson\npublic class SaveLogHelper {\n    public static final String TAG = SaveLogHelper.class.getSimpleName();\n\n    public static final String DEVICE_INFO_FILENAME = \"device_info.txt\";\n    public static final String LOG_FILENAME = \"logcat.am.log\";\n    public static final String DMESG_FILENAME = \"dmesg.txt\";\n    public static final String SAVED_LOGS_DIR = \"saved_logs\";\n    private static final int BUFFER = 0x1000; // 4K\n\n    @Nullable\n    public static Path saveTemporaryFile(String extension, CharSequence text, Collection<String> lines) {\n        try {\n            Path tempFile = Paths.get(FileCache.getGlobalFileCache().createCachedFile(extension));\n            try (PrintStream out = new PrintStream(new BufferedOutputStream(tempFile.openOutputStream(), BUFFER))) {\n                if (text != null) { // one big string\n                    out.print(text);\n                } else { // multiple lines separated by newline\n                    for (CharSequence line : lines) {\n                        out.println(line);\n                    }\n                }\n                Log.d(TAG, \"Saved temp file: %s\", tempFile);\n                return tempFile;\n            }\n        } catch (IOException e) {\n            Log.e(TAG, e);\n            return null;\n        }\n    }\n\n    @NonNull\n    public static Path getFile(@NonNull String filename) throws IOException {\n        return getSavedLogsDirectory().findFile(filename);\n    }\n\n    public static void deleteLogIfExists(@Nullable String filename) {\n        if (filename == null) return;\n        try {\n            getFile(filename).delete();\n        } catch (IOException ignore) {\n        }\n    }\n\n    @NonNull\n    public static CharSequence[] getFormattedFilenames(@NonNull Context context, @NonNull List<Path> files) {\n        CharSequence[] fileNames = new CharSequence[files.size()];\n        DateFormat dateFormat = DateFormat.getDateTimeInstance();\n        for (int i = 0; i < files.size(); ++i) {\n            fileNames[i] = new SpannableStringBuilder(files.get(i).getName())\n                    .append(\"\\n\").append(UIUtils.getSmallerText(UIUtils.getSecondaryText(context,\n                            dateFormat.format(new Date(files.get(i).lastModified())))));\n        }\n        return fileNames;\n    }\n\n    @NonNull\n    public static List<Path> getLogFiles() {\n        try {\n            Path[] filesArray = getSavedLogsDirectory().listFiles();\n            List<Path> files = new ArrayList<>(Arrays.asList(filesArray));\n            Collections.sort(files, (o1, o2) -> Long.compare(o2.lastModified(), o1.lastModified()));\n            return files;\n        } catch (IOException e) {\n            return Collections.emptyList();\n        }\n    }\n\n    @NonNull\n    public static SavedLog openLog(@NonNull Uri fileUri, int maxLines) {\n        Path logFile = Paths.get(fileUri);\n        LinkedList<String> logLines = new LinkedList<>();\n        boolean truncated = false;\n        try (BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(logFile.openInputStream()), BUFFER)) {\n            while (bufferedReader.ready()) {\n                logLines.add(bufferedReader.readLine());\n                if (logLines.size() > maxLines) {\n                    logLines.removeFirst();\n                    truncated = true;\n                }\n            }\n        } catch (IOException e) {\n            Log.e(TAG, e);\n        }\n        return new SavedLog(logLines, truncated);\n    }\n\n    public static synchronized boolean saveLog(CharSequence logString, String filename) {\n        try {\n            saveLog(null, logString, filename);\n            return true;\n        } catch (IOException e) {\n            e.printStackTrace();\n            return false;\n        }\n    }\n\n    @Nullable\n    public static synchronized Path saveLog(List<String> logLines, String filename) {\n        try {\n            return saveLog(logLines, null, filename);\n        } catch (IOException e) {\n            e.printStackTrace();\n            return null;\n        }\n    }\n\n    @NonNull\n    private static Path saveLog(List<String> logLines, CharSequence logString, String filename) throws IOException {\n        Path newFile = getSavedLogsDirectory().createNewFile(filename, null);\n        try (PrintStream out = new PrintStream(new BufferedOutputStream(newFile.openOutputStream(), BUFFER))) {\n            // Save a log as either a list of strings\n            if (logLines != null) {\n                for (CharSequence line : logLines) {\n                    out.println(line);\n                }\n            } else if (logString != null) {\n                out.print(logString);\n            }\n        }\n        return newFile;\n    }\n\n    @NonNull\n    private static Path getSavedLogsDirectory() throws IOException {\n        Path amDir = Prefs.Storage.getAppManagerDirectory();\n        if (!amDir.exists()) {\n            amDir.mkdir();\n        }\n        return amDir.findOrCreateDirectory(SAVED_LOGS_DIR);\n    }\n\n    @NonNull\n    public static String createLogFilename() {\n        Date date = new Date();\n        GregorianCalendar calendar = new GregorianCalendar();\n        calendar.setTime(date);\n\n        DecimalFormat twoDigitDecimalFormat = new DecimalFormat(\"00\");\n        DecimalFormat fourDigitDecimalFormat = new DecimalFormat(\"0000\");\n\n        String year = fourDigitDecimalFormat.format(calendar.get(Calendar.YEAR));\n        String month = twoDigitDecimalFormat.format(calendar.get(Calendar.MONTH) + 1);\n        String day = twoDigitDecimalFormat.format(calendar.get(Calendar.DAY_OF_MONTH));\n        String hour = twoDigitDecimalFormat.format(calendar.get(Calendar.HOUR_OF_DAY));\n        String minute = twoDigitDecimalFormat.format(calendar.get(Calendar.MINUTE));\n        String second = twoDigitDecimalFormat.format(calendar.get(Calendar.SECOND));\n\n        return year + \"-\" + month + \"-\" + day + \"-\" + hour + \"-\" + minute\n                + \"-\" + second + \".am.log\";\n    }\n\n    @Contract(\"null -> true\")\n    public static boolean isInvalidFilename(@Nullable CharSequence filename) {\n        String filenameAsString;\n        return TextUtils.isEmpty(filename)\n                || (filenameAsString = filename.toString()).contains(\"/\")\n                || filenameAsString.contains(\":\")\n                || filenameAsString.contains(\" \")\n                || !filenameAsString.endsWith(\".log\");\n    }\n\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/logcat/helper/ServiceHelper.java",
    "content": "// SPDX-License-Identifier: WTFPL AND GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.logcat.helper;\n\nimport android.app.ActivityManager;\nimport android.content.ComponentName;\nimport android.content.Context;\nimport android.content.Intent;\n\nimport androidx.annotation.Nullable;\n\nimport java.util.List;\n\nimport io.github.muntashirakon.AppManager.BuildConfig;\nimport io.github.muntashirakon.AppManager.intercept.IntentCompat;\nimport io.github.muntashirakon.AppManager.logcat.CrazyLoggerService;\nimport io.github.muntashirakon.AppManager.logcat.LogcatRecordingService;\nimport io.github.muntashirakon.AppManager.logcat.reader.LogcatReaderLoader;\nimport io.github.muntashirakon.AppManager.logs.Log;\n\n// Copyright 2012 Nolan Lawson\npublic class ServiceHelper {\n    public static final String TAG = ServiceHelper.class.getSimpleName();\n\n    public static void startOrStopCrazyLogger(Context context) {\n        if (BuildConfig.DEBUG) {\n            Intent intent = new Intent(context, CrazyLoggerService.class);\n            if (!context.stopService(intent)) {\n                // Service wasn't running\n                context.startService(intent);\n            }\n        }\n    }\n\n    public static synchronized void stopBackgroundServiceIfRunning(Context context) {\n        boolean alreadyRunning = ServiceHelper.checkIfServiceIsRunning(context, LogcatRecordingService.class);\n        Log.d(TAG, \"Is LogcatRecordingService running: %s\", alreadyRunning);\n        if (alreadyRunning) {\n            Intent intent = new Intent(context, LogcatRecordingService.class);\n            context.stopService(intent);\n        }\n    }\n\n    @Nullable\n    public static synchronized Intent getLogcatRecorderServiceIfNotAlreadyRunning(Context context, String filename,\n                                                                              String queryFilter, int logLevel) {\n        boolean alreadyRunning = ServiceHelper.checkIfServiceIsRunning(context, LogcatRecordingService.class);\n        if (alreadyRunning) {\n            return null;\n        }\n        Intent intent = new Intent(context, LogcatRecordingService.class);\n        intent.putExtra(LogcatRecordingService.EXTRA_FILENAME, filename);\n        // Load \"lastLine\" in the background\n        LogcatReaderLoader loader = LogcatReaderLoader.create(true);\n        IntentCompat.putWrappedParcelableExtra(intent, LogcatRecordingService.EXTRA_LOADER, loader);\n        // Add query text and log level\n        intent.putExtra(LogcatRecordingService.EXTRA_QUERY_FILTER, queryFilter);\n        intent.putExtra(LogcatRecordingService.EXTRA_LEVEL, logLevel);\n        return intent;\n    }\n\n    public static boolean checkIfServiceIsRunning(Context context, Class<?> service) {\n        String serviceName = service.getName();\n        ComponentName componentName = new ComponentName(context.getPackageName(), serviceName);\n        ActivityManager activityManager = (ActivityManager) context.getSystemService(Context.ACTIVITY_SERVICE);\n        List<ActivityManager.RunningServiceInfo> procList = activityManager.getRunningServices(Integer.MAX_VALUE);\n        if (procList != null) {\n            for (ActivityManager.RunningServiceInfo appProcInfo : procList) {\n                if (appProcInfo != null && componentName.equals(appProcInfo.service)) {\n                    Log.d(TAG, \"%s is already running.\", serviceName);\n                    return true;\n                }\n            }\n        }\n        Log.d(TAG, \"%s is not running.\", serviceName);\n        return false;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/logcat/helper/WidgetHelper.java",
    "content": "// SPDX-License-Identifier: WTFPL AND GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.logcat.helper;\n\nimport android.app.PendingIntent;\nimport android.appwidget.AppWidgetManager;\nimport android.content.ComponentName;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.net.Uri;\nimport android.widget.RemoteViews;\n\nimport androidx.annotation.NonNull;\nimport androidx.core.app.PendingIntentCompat;\n\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.logcat.LogcatRecordingService;\nimport io.github.muntashirakon.AppManager.logcat.RecordingWidgetProvider;\nimport io.github.muntashirakon.AppManager.logs.Log;\n\n// Copyright 2012 Nolan Lawson\npublic class WidgetHelper {\n    public static void updateWidgets(Context context) {\n        int[] appWidgetIds = findAppWidgetIds(context);\n        updateWidgets(context, appWidgetIds);\n    }\n\n    /**\n     * manually tell us if the service is running or not\n     */\n    public static void updateWidgets(Context context, boolean serviceRunning) {\n        int[] appWidgetIds = findAppWidgetIds(context);\n        updateWidgets(context, appWidgetIds, serviceRunning);\n    }\n\n    public static void updateWidgets(Context context, int[] appWidgetIds) {\n        boolean serviceRunning = ServiceHelper.checkIfServiceIsRunning(context, LogcatRecordingService.class);\n        updateWidgets(context, appWidgetIds, serviceRunning);\n    }\n\n    public static void updateWidgets(Context context, @NonNull int[] appWidgetIds, boolean serviceRunning) {\n        AppWidgetManager manager = AppWidgetManager.getInstance(context);\n        for (int appWidgetId : appWidgetIds) {\n            if (!PreferenceHelper.getWidgetExistsPreference(context, appWidgetId)) {\n                // android has a bug that sometimes keeps stale app widget ids around\n                Log.d(\"WidgetHelper\", \"Found stale app widget id %d; skipping...\", appWidgetId);\n                continue;\n            }\n            updateWidget(context, manager, appWidgetId, serviceRunning);\n        }\n    }\n\n    private static void updateWidget(Context context, AppWidgetManager manager, int appWidgetId, boolean serviceRunning) {\n        RemoteViews updateViews = new RemoteViews(context.getPackageName(), R.layout.widget_recording);\n        // change the subtext depending on whether the service is running or not\n        CharSequence subtext = context.getText(serviceRunning ? R.string.widget_recording_in_progress :\n                R.string.widget_start_recording);\n        updateViews.setTextViewText(R.id.widget_subtext, subtext);\n        PendingIntent pendingIntent = getPendingIntent(context, appWidgetId);\n        updateViews.setOnClickPendingIntent(R.id.clickable_linear_layout, pendingIntent);\n        manager.updateAppWidget(appWidgetId, updateViews);\n    }\n\n    private static PendingIntent getPendingIntent(Context context, int appWidgetId) {\n        Intent intent = new Intent(context, RecordingWidgetProvider.class);\n        intent.setAction(RecordingWidgetProvider.ACTION_RECORD_OR_STOP);\n        intent.putExtra(AppWidgetManager.EXTRA_APPWIDGET_ID, appWidgetId);\n        // gotta make this unique for this appwidgetid - otherwise, the PendingIntents conflict\n        // it seems to be a quasi-bug in Android\n        Uri data = Uri.withAppendedPath(Uri.parse(RecordingWidgetProvider.URI_SCHEME + \"://widget/id/#\"), String.valueOf(appWidgetId));\n        intent.setData(data);\n        return PendingIntentCompat.getBroadcast(context, 0 /* no requestCode */, intent,\n                PendingIntent.FLAG_UPDATE_CURRENT, false);\n    }\n\n    private static int[] findAppWidgetIds(Context context) {\n        AppWidgetManager manager = AppWidgetManager.getInstance(context);\n        ComponentName widget = new ComponentName(context, RecordingWidgetProvider.class);\n        return manager.getAppWidgetIds(widget);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/logcat/reader/AbsLogcatReader.java",
    "content": "// SPDX-License-Identifier: WTFPL AND GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.logcat.reader;\n\n\n// Copyright 2012 Nolan Lawson\nabstract class AbsLogcatReader implements LogcatReader {\n    protected boolean recordingMode;\n\n    public AbsLogcatReader(boolean recordingMode) {\n        this.recordingMode = recordingMode;\n    }\n\n    public boolean isRecordingMode() {\n        return recordingMode;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/logcat/reader/LogcatReader.java",
    "content": "// SPDX-License-Identifier: WTFPL AND GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.logcat.reader;\n\nimport java.io.IOException;\nimport java.util.List;\n\n// Copyright 2012 Nolan Lawson\npublic interface LogcatReader {\n    /**\n     * Read a single log line, ala {@link java.io.BufferedReader#readLine()}.\n     *\n     * @return A single log line\n     */\n    String readLine() throws IOException;\n\n    /**\n     * Kill the reader and close all resources without throwing any exceptions.\n     */\n    void killQuietly();\n\n    @SuppressWarnings(\"BooleanMethodIsAlwaysInverted\")\n    boolean readyToRecord();\n\n    List<Process> getProcesses();\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/logcat/reader/LogcatReaderLoader.java",
    "content": "// SPDX-License-Identifier: WTFPL AND GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.logcat.reader;\n\nimport android.os.Parcel;\nimport android.os.Parcelable;\n\nimport androidx.annotation.NonNull;\n\nimport java.io.IOException;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport io.github.muntashirakon.AppManager.logcat.helper.LogcatHelper;\nimport io.github.muntashirakon.AppManager.logcat.helper.PreferenceHelper;\nimport io.github.muntashirakon.util.ParcelUtils;\n\n// Copyright 2012 Nolan Lawson\n// Copyright 2021 Muntashir Al-Islam\npublic class LogcatReaderLoader implements Parcelable {\n    private final Map<Integer, String> mLastLines;\n    private final boolean mRecordingMode;\n    private final boolean mMultipleBuffers;\n\n    private LogcatReaderLoader(@LogcatHelper.LogBufferId @NonNull List<Integer> buffers, boolean recordingMode) {\n        this.mRecordingMode = recordingMode;\n        this.mMultipleBuffers = buffers.size() > 1;\n        this.mLastLines = new HashMap<>();\n        for (Integer buffer : buffers) {\n            // No need to grab the last line if this isn't recording mode\n            String lastLine = recordingMode ? LogcatHelper.getLastLogLine(buffer) : null;\n            mLastLines.put(buffer, lastLine);\n        }\n    }\n\n    @NonNull\n    public static LogcatReaderLoader create(boolean recordingMode) {\n        List<Integer> buffers = PreferenceHelper.getBuffers();\n        return new LogcatReaderLoader(buffers, recordingMode);\n    }\n\n    public LogcatReader loadReader() throws IOException {\n        LogcatReader reader;\n        if (!mMultipleBuffers) {\n            // single reader\n            Integer buffers = mLastLines.keySet().iterator().next();\n            String lastLine = mLastLines.values().iterator().next();\n            reader = new SingleLogcatReader(mRecordingMode, buffers, lastLine);\n        } else {\n            // multiple reader\n            reader = new MultipleLogcatReader(mRecordingMode, mLastLines);\n        }\n\n        return reader;\n    }\n\n    @Override\n    public int describeContents() {\n        return 0;\n    }\n\n    public static final Parcelable.Creator<LogcatReaderLoader> CREATOR = new Parcelable.Creator<LogcatReaderLoader>() {\n        public LogcatReaderLoader createFromParcel(Parcel in) {\n            return new LogcatReaderLoader(in);\n        }\n\n        public LogcatReaderLoader[] newArray(int size) {\n            return new LogcatReaderLoader[size];\n        }\n    };\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        dest.writeInt(mRecordingMode ? 1 : 0);\n        dest.writeInt(mMultipleBuffers ? 1 : 0);\n        ParcelUtils.writeMap(mLastLines, dest);\n    }\n\n    private LogcatReaderLoader(@NonNull Parcel in) {\n        this.mRecordingMode = in.readInt() == 1;\n        this.mMultipleBuffers = in.readInt() == 1;\n        this.mLastLines = ParcelUtils.readMap(in, Integer.class.getClassLoader(), String.class.getClassLoader());\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/logcat/reader/MultipleLogcatReader.java",
    "content": "// SPDX-License-Identifier: WTFPL AND GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.logcat.reader;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Map.Entry;\nimport java.util.concurrent.ArrayBlockingQueue;\nimport java.util.concurrent.BlockingQueue;\n\nimport io.github.muntashirakon.AppManager.logcat.helper.LogcatHelper;\nimport io.github.muntashirakon.AppManager.logs.Log;\nimport io.github.muntashirakon.AppManager.utils.ThreadUtils;\n\n/**\n * Combines multiple buffered readers into a single reader that merges all input synchronously.\n */\n// Copyright 2012 Nolan Lawson\npublic class MultipleLogcatReader extends AbsLogcatReader {\n    public static final String TAG = MultipleLogcatReader.class.getSimpleName();\n\n    private static final String DUMMY_NULL = \"\";  // Stop marker\n    private final List<ReaderThread> mReaderThreads = new LinkedList<>();\n    private final BlockingQueue<String> mQueue = new ArrayBlockingQueue<>(1);\n\n    public MultipleLogcatReader(boolean recordingMode, Map<Integer, String> lastLines) throws IOException {\n        super(recordingMode);\n        // Read from all three buffers all at once\n        for (Entry<Integer, String> entry : lastLines.entrySet()) {\n            Integer buffers = entry.getKey();\n            String lastLine = entry.getValue();\n            ReaderThread readerThread = new ReaderThread(buffers, lastLine);\n            readerThread.start();\n            mReaderThreads.add(readerThread);\n        }\n    }\n\n    public String readLine() throws IOException {\n        try {\n            String value = mQueue.take();\n            if (!value.equals(DUMMY_NULL)) {\n                return value;\n            }\n        } catch (InterruptedException e) {\n            Log.e(TAG, e);\n        }\n        return null;\n    }\n\n\n    @Override\n    public boolean readyToRecord() {\n        for (ReaderThread thread : mReaderThreads) {\n            if (!thread.mReader.readyToRecord()) {\n                return false;\n            }\n        }\n        return true;\n    }\n\n    @Override\n    public void killQuietly() {\n        for (ReaderThread thread : mReaderThreads) {\n            thread.mKilled = true;\n        }\n        // Kill all threads in the background\n        ThreadUtils.postOnBackgroundThread(() -> {\n            for (ReaderThread thread : mReaderThreads) {\n                thread.mReader.killQuietly();\n            }\n            mQueue.offer(DUMMY_NULL);\n        });\n    }\n\n    @Override\n    public List<Process> getProcesses() {\n        List<Process> result = new ArrayList<>();\n        for (ReaderThread thread : mReaderThreads) {\n            result.addAll(thread.mReader.getProcesses());\n        }\n        return result;\n    }\n\n    private class ReaderThread extends Thread {\n        private final SingleLogcatReader mReader;\n        private boolean mKilled;\n\n        public ReaderThread(@LogcatHelper.LogBufferId int logBuffer, String lastLine) throws IOException {\n            mReader = new SingleLogcatReader(recordingMode, logBuffer, lastLine);\n        }\n\n        @Override\n        public void run() {\n            String line;\n            try {\n                while (!mKilled && (line = mReader.readLine()) != null && !mKilled) {\n                    mQueue.put(line);\n                }\n            } catch (IOException | InterruptedException e) {\n                Log.e(TAG, e);\n            }\n            Log.w(TAG, \"Thread died\");\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/logcat/reader/ScrubberUtils.java",
    "content": "// SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.logcat.reader;\n\nimport java.util.regex.Pattern;\n\n// Copyright 2014 CyanogenMod Project\npublic class ScrubberUtils {\n    private static final Pattern EMAIL_PATTERN = Pattern.compile(\"[a-zA-Z0-9_]+(?:\\\\.[A-Za-z0-9!#$%&'*+/=?^_`{|}~-]+)*(@|%40)(?!([a-zA-Z0-9]*\\\\.[a-zA-Z0-9]*\\\\.[a-zA-Z0-9]*\\\\.))(?:[A-Za-z0-9](?:[a-zA-Z0-9-]*[A-Za-z0-9])?\\\\.)+[a-zA-Z](?:[a-zA-Z0-9-]*[a-zA-Z0-9])?\");\n    private static final Pattern PHONE_NUMBER_PATTERN = Pattern.compile(\"^(?:(?:\\\\+?1\\\\s*(?:[.-]\\\\s*)?)?(?:\\\\(\\\\s*([2-9]1[02-9]|[2-9][02-8]1|[2-9][02-8][02-9])\\\\s*\\\\)|([2-9]1[02-9]|[2-9][02-8]1|[2-9][02-8][02-9]))\\\\s*(?:[.-]\\\\s*)?)?([2-9]1[02-9]|[2-9][02-9]1|[2-9][02-9]{2})\\\\s*(?:[.-]\\\\s*)?([0-9]{4})(?:\\\\s*(?:#|x\\\\.?|ext\\\\.?|extension)\\\\s*(\\\\d+))?$\");\n    private static final Pattern WEB_URL_PATTERN = Pattern.compile(\"\\\\b(https?|ftp|file)://[-a-zA-Z0-9+&@#/%?=~_|!:,.;]*[-a-zA-Z0-9+&@#/%=~_|]\");\n    private static final Pattern IP_ADDRESS_PATTERN = Pattern.compile(\"^([01]?\\\\d\\\\d?|2[0-4]\\\\d|25[0-5])\\\\.([01]?\\\\d\\\\d?|2[0-4]\\\\d|25[0-5])\\\\.([01]?\\\\d\\\\d?|2[0-4]\\\\d|25[0-5])\\\\.([01]?\\\\d\\\\d?|2[0-4]\\\\d|25[0-5])$\");\n    private static final Pattern PHONE_INFO_PATTERN = Pattern.compile(\"(msisdn=|mMsisdn=|iccid=|iccid: |mImsi=)[a-zA-Z0-9]*\", Pattern.CASE_INSENSITIVE);\n    private static final Pattern USER_INFO_PATTERN = Pattern.compile(\"(UserInfo\\\\{\\\\d:)[a-zA-Z0-9\\\\s]*\", Pattern.CASE_INSENSITIVE);\n    private static final Pattern ACCOUNT_INFO_PATTERN = Pattern.compile(\"(Account \\\\{name=)[a-zA-Z0-9]*\", Pattern.CASE_INSENSITIVE);\n\n    private static final String IGNORE_DATA_RESOURCE_CACHE = \"/data/resource-cache\";\n    private static final String IGNORE_DATA_DALVIK_CACHE = \"/data/dalvik-cache\";\n    private static final String IGNORE_CACHE_DALVIK_CACHE = \"/cache/dalvik-cache\";\n\n    public static String scrubLine(String line) {\n        if (line.contains(IGNORE_DATA_RESOURCE_CACHE)\n                || line.contains(IGNORE_DATA_DALVIK_CACHE)\n                || line.contains(IGNORE_CACHE_DALVIK_CACHE)) {\n            // Ugly work around :/\n            return line;\n        }\n        line = IP_ADDRESS_PATTERN.matcher(line).replaceAll(\"<IP address omitted>\");\n        line = EMAIL_PATTERN.matcher(line).replaceAll(\"<email omitted>\");\n        line = PHONE_NUMBER_PATTERN.matcher(line).replaceAll(\"<phone number omitted>\");\n        line = WEB_URL_PATTERN.matcher(line).replaceAll(\"<web url omitted>\");\n        line = PHONE_INFO_PATTERN.matcher(line).replaceAll(\"<omitted>\");\n        line = USER_INFO_PATTERN.matcher(line).replaceAll(\"<omitted>\");\n        line = ACCOUNT_INFO_PATTERN.matcher(line).replaceAll(\"<omitted>\");\n\n        return line;\n    }\n}"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/logcat/reader/SingleLogcatReader.java",
    "content": "// SPDX-License-Identifier: WTFPL AND GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.logcat.reader;\n\nimport android.text.TextUtils;\n\nimport androidx.annotation.Nullable;\n\nimport java.io.BufferedReader;\nimport java.io.IOException;\nimport java.io.InputStreamReader;\nimport java.util.Collections;\nimport java.util.List;\n\nimport io.github.muntashirakon.AppManager.logcat.helper.LogcatHelper;\nimport io.github.muntashirakon.AppManager.logs.Log;\n\n// Copyright 2012 Nolan Lawson\npublic class SingleLogcatReader extends AbsLogcatReader {\n    private final Process mLogcatProcess;\n    private final BufferedReader mBufferedReader;\n    @Nullable\n    private String mLastLine;\n\n    public SingleLogcatReader(boolean recordingMode, @LogcatHelper.LogBufferId int buffers, @Nullable String lastLine)\n            throws IOException {\n        super(recordingMode);\n        mLastLine = lastLine;\n\n        // Use the \"time\" log so we can see what time the logs were logged at\n        mLogcatProcess = LogcatHelper.getLogcatProcess(buffers);\n        mBufferedReader = new BufferedReader(new InputStreamReader(mLogcatProcess.getInputStream()), 8192);\n    }\n\n    @Override\n    public void killQuietly() {\n        if (mLogcatProcess != null) {\n            mLogcatProcess.destroy();\n            Log.d(\"SLR\", \"killed 1 logcat process\");\n        }\n    }\n\n    @Override\n    public String readLine() throws IOException {\n        String line = mBufferedReader.readLine();\n        if (recordingMode && mLastLine != null) { // Still skipping past the 'last line'\n            if (mLastLine.equals(line) /*|| isAfterLastTime(line)*/) {\n                mLastLine = null; // Indicates we've passed the last line\n            }\n        }\n        return line;\n    }\n\n    private boolean isAfterLastTime(String line) {\n        if (mLastLine == null) {\n            return false;\n        }\n        // Doing a string comparison is sufficient to determine whether this line is chronologically\n        // after the last line, because the format they use is exactly the same and\n        // lists larger time period before smaller ones\n        return isDatedLogLine(mLastLine) && isDatedLogLine(line) && line.compareTo(mLastLine) > 0;\n    }\n\n    private boolean isDatedLogLine(String line) {\n        // 18 is the size of the logcat timestamp\n        return (!TextUtils.isEmpty(line) && line.length() >= 18 && Character.isDigit(line.charAt(0)));\n    }\n\n    @Override\n    public boolean readyToRecord() {\n        return recordingMode && mLastLine == null;\n    }\n\n    @Override\n    public List<Process> getProcesses() {\n        return Collections.singletonList(mLogcatProcess);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/logcat/struct/LogLine.java",
    "content": "// SPDX-License-Identifier: WTFPL AND GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.logcat.struct;\n\nimport android.os.RemoteException;\nimport android.text.TextUtils;\nimport android.util.Log;\nimport android.util.LruCache;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport java.util.Objects;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\nimport io.github.muntashirakon.AppManager.compat.PackageManagerCompat;\nimport io.github.muntashirakon.AppManager.logcat.helper.LogcatHelper;\nimport io.github.muntashirakon.AppManager.logcat.reader.ScrubberUtils;\nimport io.github.muntashirakon.AppManager.users.Owners;\n\n\n// Copyright 2012 Nolan Lawson\n// Copyright 2021 Muntashir Al-Islam\npublic class LogLine {\n    public static final String TAG = LogLine.class.getSimpleName();\n\n    public static final int LOG_FATAL = 15;\n\n    /**\n     * %s %5d %5d %c %-8s:\n     * %s %s%5d %5d %c %-8s: (Android 7+)\n     *\n     * @see LogcatHelper#getLogcatArgs(int, boolean)\n     */\n    private static final Pattern LOG_PATTERN = Pattern.compile(\n            // Timestamp\n            \"(\\\\d{2}-\\\\d{2}\\\\s\\\\d{2}:\\\\d{2}:\\\\d{2}\\\\.\\\\d{3})\\\\s+\" +\n                    // UID PID\n                    \"(.+\\\\d+)\\\\s+\" +\n                    // TID\n                    \"(\\\\d+)\\\\s+\" +\n                    // Log level\n                    \"([ADEIVWF])\\\\s+\" +\n                    // Tag\n                    \"(.+?)\" +\n                    // Message\n                    \": (.*)\");\n    /**\n     * This is the old pattern used prior to v4.0.0. Format: {timestamp} {level}/{tag}(\\s{pid}): message\n     */\n    private static final Pattern LOG_PATTERN_LEGACY = Pattern.compile(\n            // Timestamp\n            \"(\\\\d{2}-\\\\d{2}\\\\s\\\\d{2}:\\\\d{2}:\\\\d{2}\\\\.\\\\d{3})\\\\s+\" +\n                    // Log level\n                    \"([ADEIVWF])/\" +\n                    // Tag\n                    \"([^(].+)\" +\n                    // PID with optional * prefixed number seen on ZTE blade (Android 4.4)\n                    \"\\\\(\\\\s*(\\\\d+)(?:\\\\*\\\\s*\\\\d+)?\\\\)\" +\n                    // Message\n                    \": (.*)\");\n    private static final String BEGIN = \"--------- beginning of \";\n\n    public static boolean omitSensitiveInfo = false;\n\n    @Nullable\n    public static LogLine newLogLine(@NonNull String originalLine, boolean expanded, @Nullable Pattern filterPattern) {\n        LogLine logLine = new LogLine(originalLine);\n        logLine.setExpanded(expanded);\n\n        if (matchPattern(originalLine, logLine)) {\n            if (filterPattern != null && filterPattern.matcher(logLine.getTagName()).matches()) {\n                return null;\n            }\n            return logLine;\n        }\n        if (matchPatternLegacy(originalLine, logLine)) {\n            if (filterPattern != null && filterPattern.matcher(logLine.getTagName()).matches()) {\n                return null;\n            }\n            return logLine;\n        }\n        if (originalLine.startsWith(BEGIN)) {\n            Log.d(TAG, \"Started buffer: \" + originalLine.substring(BEGIN.length()));\n            return null;\n        } else {\n            Log.w(TAG, \"Line doesn't match pattern: \" + originalLine);\n            logLine.setLogOutput(originalLine);\n            logLine.setLogLevel(-1);\n        }\n        return logLine;\n    }\n\n    public static int convertCharToLogLevel(char logLevelChar) {\n        switch (logLevelChar) {\n            case 'A':\n                return Log.ASSERT;\n            case 'D':\n                return Log.DEBUG;\n            case 'E':\n                return Log.ERROR;\n            case 'I':\n                return Log.INFO;\n            case 'V':\n                return Log.VERBOSE;\n            case 'W':\n                return Log.WARN;\n            case 'F':\n                return LOG_FATAL;\n        }\n        return -1;\n    }\n\n    public static char convertLogLevelToChar(int logLevel) {\n        switch (logLevel) {\n            case Log.ASSERT:\n                return 'A';\n            case Log.DEBUG:\n                return 'D';\n            case Log.ERROR:\n                return 'E';\n            case Log.INFO:\n                return 'I';\n            case Log.VERBOSE:\n                return 'V';\n            case Log.WARN:\n                return 'W';\n            case LOG_FATAL:\n                return 'F';\n        }\n        return ' ';\n    }\n\n    @NonNull\n    private final String mOriginalLine;\n\n    @Nullable\n    private String mTimestamp;\n    private int mLogLevel;\n    private String mTagName;\n    private String mLogOutput;\n    private int mPid = -1;\n    private int mTid = -1;\n    private int mUid = -1;\n    @Nullable\n    private String mUidOwner;\n    @Nullable\n    private String mPackageName;\n\n    private boolean mExpanded = false;\n\n    public LogLine(@NonNull String originalLine) {\n        mOriginalLine = originalLine;\n    }\n\n    public String getOriginalLine() {\n        return mOriginalLine;\n    }\n\n    public String getProcessIdText() {\n        return Character.toString(convertLogLevelToChar(mLogLevel));\n    }\n\n    public int getLogLevel() {\n        return mLogLevel;\n    }\n\n    public void setLogLevel(int logLevel) {\n        mLogLevel = logLevel;\n    }\n\n    public String getTagName() {\n        return mTagName;\n    }\n\n    public void setTag(String tag) {\n        mTagName = tag;\n    }\n\n    public String getLogOutput() {\n        return mLogOutput;\n    }\n\n    public void setLogOutput(String logOutput) {\n        if (omitSensitiveInfo) {\n            mLogOutput = ScrubberUtils.scrubLine(logOutput);\n        } else {\n            mLogOutput = logOutput;\n        }\n    }\n\n    public int getPid() {\n        return mPid;\n    }\n\n    public void setPid(int pid) {\n        mPid = pid;\n    }\n\n    public int getTid() {\n        return mTid;\n    }\n\n    public void setTid(int tid) {\n        mTid = tid;\n    }\n\n    public int getUid() {\n        return mUid;\n    }\n\n    public void setUid(int uid) {\n        mUid = uid;\n    }\n\n    @Nullable\n    public String getUidOwner() {\n        return mUidOwner;\n    }\n\n    public void setUidOwner(@Nullable String owner) {\n        mUidOwner = owner;\n    }\n\n    @Nullable\n    public String getPackageName() {\n        return mPackageName;\n    }\n\n    public void setPackageName(@Nullable String packageName) {\n        mPackageName = packageName;\n    }\n\n    @Nullable\n    public String getTimestamp() {\n        return mTimestamp;\n    }\n\n    public void setTimestamp(@Nullable String timestamp) {\n        mTimestamp = timestamp;\n    }\n\n    public boolean isExpanded() {\n        return mExpanded;\n    }\n\n    public void setExpanded(boolean expanded) {\n        this.mExpanded = expanded;\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) return true;\n        if (!(o instanceof LogLine)) return false;\n        LogLine logLine = (LogLine) o;\n        return mOriginalLine.equals(logLine.mOriginalLine);\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hash(mOriginalLine);\n    }\n\n    @NonNull\n    @Override\n    public String toString() {\n        return mOriginalLine;\n    }\n\n    private static boolean matchPatternLegacy(@NonNull String originalLine, @NonNull LogLine logLine) {\n        Matcher matcher = LOG_PATTERN_LEGACY.matcher(originalLine);\n        if (!matcher.matches()) {\n            return false;\n        }\n        // Group 1: Timestamp\n        logLine.setTimestamp(Objects.requireNonNull(matcher.group(1)));\n        // Group 2: Log level\n        logLine.setLogLevel(convertCharToLogLevel(Objects.requireNonNull(matcher.group(2)).charAt(0)));\n        // Group 3: Tag\n        logLine.setTag(Objects.requireNonNull(matcher.group(3)).trim());\n        // Group 4: PID\n        logLine.setPid(Integer.parseInt(matcher.group(4)));\n        // Group 5: Message\n        logLine.setLogOutput(Objects.requireNonNull(matcher.group(5)));\n        return true;\n    }\n\n    private static boolean matchPattern(@NonNull String originalLine, @NonNull LogLine logLine) {\n        Matcher matcher = LOG_PATTERN.matcher(originalLine);\n        if (!matcher.matches()) {\n            return false;\n        }\n        // Group 1: Timestamp\n        logLine.setTimestamp(Objects.requireNonNull(matcher.group(1)));\n        // Group 2: UID PID\n        String[] uidPid = Objects.requireNonNull(matcher.group(2)).split(\"\\\\s+\", 2);\n        if (uidPid.length == 2) {\n            String owner = uidPid[0];\n            int uid = Owners.parseUid(owner);\n            logLine.setUidOwner(owner);\n            logLine.setUid(uid);\n            // Set package name\n            logLine.setPackageName(retrievePackageName(uid));\n        }\n        logLine.setPid(Integer.parseInt(uidPid[uidPid.length == 2 ? 1 : 0]));\n        // Group 3: TID\n        logLine.setTid(Integer.parseInt(matcher.group(3)));\n        // Group 4: Log level\n        logLine.setLogLevel(convertCharToLogLevel(Objects.requireNonNull(matcher.group(4)).charAt(0)));\n        // Group 5: Tag\n        logLine.setTag(Objects.requireNonNull(matcher.group(5)).trim());\n        // Group 6: Message\n        logLine.setLogOutput(Objects.requireNonNull(matcher.group(6)));\n        return true;\n    }\n\n    private static final LruCache<Integer, String> sUidPackageNameCache = new LruCache<>(300);\n\n    @Nullable\n    private static String retrievePackageName(int uid) {\n        if (uid < 0) {\n            return null;\n        }\n        String packageName = sUidPackageNameCache.get(uid);\n        if (packageName != null) {\n            return TextUtils.isEmpty(packageName) ? null : packageName;\n        }\n        // TODO: 1/18/25\n        // Assumptions for multiple UIDs:\n        // 1. Process name likely matches/starts with the package name\n        // 2. Shortest package name is preferred (the primary package in a shared UID is likely to have the shortest package name)\n        // Ignored assumption:\n        // 3. Primary package is likely to be installed first\n        try {\n            String[] packages = PackageManagerCompat.getPackageManager().getPackagesForUid(uid);\n            String selectedPackage = null;\n            if (packages == null || packages.length == 0) {\n                selectedPackage = null;\n            } else {\n                if (packages.length == 1) {\n                    selectedPackage = packages[0];\n                } else {\n                    int shortestIndex = 0;\n                    for (int i = 0; i < packages.length; ++i) {\n                        if (packages[shortestIndex].length() > packages[i].length()) {\n                            shortestIndex = i;\n                        }\n                    }\n                    if (selectedPackage == null) {\n                        selectedPackage = packages[shortestIndex];\n                    }\n                }\n            }\n            if (selectedPackage != null) {\n                sUidPackageNameCache.put(uid, selectedPackage);\n            } else {\n                // Still cache this data\n                sUidPackageNameCache.put(uid, \"\");\n            }\n            return selectedPackage;\n        } catch (RemoteException e) {\n            return null;\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/logcat/struct/SavedLog.java",
    "content": "// SPDX-License-Identifier: WTFPL AND GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.logcat.struct;\n\nimport java.util.List;\n\n// Copyright 2012 Nolan Lawson\npublic class SavedLog {\n    private final List<String> mLogLines;\n    private final boolean mTruncated;\n\n    public SavedLog(List<String> logLines, boolean truncated) {\n        mLogLines = logLines;\n        mTruncated = truncated;\n    }\n\n    public List<String> getLogLines() {\n        return mLogLines;\n    }\n\n    public boolean isTruncated() {\n        return mTruncated;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/logcat/struct/SearchCriteria.java",
    "content": "// SPDX-License-Identifier: WTFPL AND GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.logcat.struct;\n\nimport android.os.Build;\nimport android.text.TextUtils;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.StringDef;\n\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.regex.Pattern;\n\nimport io.github.muntashirakon.AppManager.utils.ArrayUtils;\n\n// Copyright 2012 Nolan Lawson\npublic class SearchCriteria {\n\n    @Retention(RetentionPolicy.SOURCE)\n    @StringDef({TYPE_MSG, TYPE_PID, TYPE_PKG, TYPE_TAG, TYPE_UID})\n    private @interface FilterType {\n    }\n\n    private static final String TYPE_MSG = \"msg\";\n    private static final String TYPE_PID = \"pid\";\n    private static final String TYPE_PKG = \"pkg\";\n    private static final String TYPE_TAG = \"tag\";\n    private static final String TYPE_UID = \"uid\";\n\n    private static final String[] TYPES = new String[]{\n            TYPE_MSG, TYPE_PID, TYPE_PKG, TYPE_TAG, TYPE_UID,\n    };\n\n    public static final String PID_KEYWORD = TYPE_PID + \":\";\n    public static final String PKG_KEYWORD = TYPE_PKG + \"=:\";\n    public static final String TAG_KEYWORD = TYPE_TAG + \"=:\";\n    public static final String UID_KEYWORD = TYPE_UID + \"=:\";\n\n    @Nullable\n    public final String query;\n    private final List<Filter> mFilters = new ArrayList<>();\n\n    public SearchCriteria(@Nullable String query) {\n        this.query = query;\n        if (query == null) {\n            return;\n        }\n        String[] parts = query.split(\" \");\n        // Check for keywords, we support the following keywords:\n        // 1. pid:<int>\n        // 2. pkg:<string>|\"<string>\"\n        // 3. proc:<string>|\"<string>\"\n        // 4. tag:<string>|\"<string>\"\n        // Each can take regex if it has ~: separator instead of :\n        // For exact match, it has =: instead of :\n        // Each can be inverse if it begins with -\n        StringBuilder lastString = null;\n        StringBuilder queryString = new StringBuilder();\n        for (String part : parts) {\n            if (lastString != null) {\n                // This part belongs to the last filter\n                if (part.endsWith(\"\\\"\")) {\n                    Filter filter = mFilters.get(mFilters.size() - 1);\n                    filter.setValue(lastString + \" \" + part.substring(0, parts.length - 1));\n                    lastString = null;\n                } else lastString.append(\" \").append(part);\n                continue;\n            }\n            int colon = part.indexOf(\":\");\n            if (colon > 0) {\n                String type = part.substring(0, colon);\n                boolean inv = type.startsWith(\"-\");\n                boolean regex = type.endsWith(\"~\");\n                boolean exact = type.endsWith(\"=\");\n                // Check for inverse\n                if (inv && type.length() > 1) type = type.substring(1);\n                if (regex && type.length() > 1) type = type.substring(0, type.length() - 1);\n                if (exact && type.length() > 1) type = type.substring(0, type.length() - 1);\n                if (ArrayUtils.contains(TYPES, type)) {\n                    // Valid type\n                    Filter filter = new Filter(type, regex, inv, exact);\n                    mFilters.add(filter);\n                    if (colon + 1 < part.length()) {\n                        String value = part.substring(colon + 1);\n                        // Check if value begins with quote\n                        if (value.startsWith(\"\\\"\")) {\n                            if (value.length() > 1) {\n                                if (value.endsWith(\"\\\"\")) {\n                                    filter.setValue(value.substring(1, value.length() - 1));\n                                } else {\n                                    // Value didn't end here\n                                    lastString = new StringBuilder(value.substring(1));\n                                }\n                            } else lastString = new StringBuilder();\n                        } else filter.setValue(value);\n                    }\n                    continue;\n                }\n            }\n            // Query string\n            queryString.append(\" \").append(part);\n        }\n        String text = queryString.toString().trim();\n        if (!text.isEmpty()) {\n            mFilters.add(new Filter(TYPE_MSG, queryString.toString().trim()));\n        }\n    }\n\n    public boolean isEmpty() {\n        for (Filter filter : mFilters) {\n            if (!filter.isEmpty()) {\n                return false;\n            }\n        }\n        return true;\n    }\n\n    public boolean matches(LogLine logLine) {\n        // Consider the criteria to be ANDed\n        for (Filter filter : mFilters) {\n            if (!filter.matches(logLine)) {\n                return false;\n            }\n        }\n        return true;\n    }\n\n    private static class Filter {\n        @FilterType\n        private final String mType;\n        private final boolean mRegex;\n        private final boolean mExact;\n        private final boolean mInverse;\n        @Nullable\n        private Object mValue;\n\n        public Filter(@FilterType String type, boolean regex, boolean inverse, boolean exact) {\n            mType = type;\n            mRegex = regex;\n            mInverse = inverse;\n            mExact = exact;\n        }\n\n        public Filter(@FilterType String type, @Nullable String value) {\n            mType = type;\n            mRegex = false;\n            mInverse = false;\n            mExact = false;\n            mValue = getRealValue(value);\n        }\n\n        public void setValue(@Nullable String value) {\n            mValue = getRealValue(value);\n        }\n\n        public boolean isEmpty() {\n            if (mValue instanceof CharSequence) {\n                return TextUtils.isEmpty((CharSequence) mValue);\n            }\n            return mValue == null;\n        }\n\n        /**\n         * @noinspection DataFlowIssue\n         */\n        public boolean matches(@NonNull LogLine logLine) {\n            if (isEmpty()) {\n                // Empty always matches\n                return true;\n            }\n            boolean matches;\n            switch (mType) {\n                case TYPE_MSG: {\n                    String tag = logLine.getTagName();\n                    String out = logLine.getLogOutput();\n                    if (tag == null && out == null) {\n                        return false;\n                    }\n                    if (mRegex) {\n                        Pattern p = (Pattern) mValue;\n                        matches = matchPattern(p, tag) || matchPattern(p, out);\n                    } else {\n                        String query = (String) mValue;\n                        matches = matchQuery(query, tag, mExact) || matchQuery(query, tag, mExact);\n                    }\n                    break;\n                }\n                case TYPE_PID: {\n                    if (mRegex) {\n                        matches = matchPattern((Pattern) mValue, String.valueOf(logLine.getPid()));\n                    } else {\n                        matches = logLine.getPid() == ((int) mValue);\n                    }\n                    break;\n                }\n                case TYPE_PKG: {\n                    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {\n                        // Package name is not available for these versions\n                        // Use match-all\n                        return true;\n                    }\n                    String packageName = logLine.getPackageName();\n                    if (mRegex) {\n                        matches = matchPattern((Pattern) mValue, packageName);\n                    } else {\n                        matches = matchQuery((String) mValue, packageName, mExact);\n                    }\n                    break;\n                }\n                case TYPE_UID: {\n                    if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {\n                        // UID is not available for these versions\n                        // Use match-all\n                        return true;\n                    }\n                    String owner = logLine.getUidOwner();\n                    int uid = logLine.getUid();\n                    if (mRegex) {\n                        Pattern p = (Pattern) mValue;\n                        matches = matchPattern(p, owner) || matchPattern(p, String.valueOf(uid));\n                    } else {\n                        if (mValue instanceof Integer) {\n                            matches = uid == ((int) mValue);\n                        } else matches = matchQuery((String) mValue, owner, mExact);\n                    }\n                    break;\n                }\n                case TYPE_TAG: {\n                    String tag = logLine.getTagName();\n                    if (mRegex) {\n                        matches = matchPattern((Pattern) mValue, tag);\n                    } else {\n                        matches = matchQuery((String) mValue, tag, mExact);\n                    }\n                    break;\n                }\n                default:\n                    throw new IllegalArgumentException(\"Invalid filter: \" + mType);\n            }\n            return mInverse != matches;\n        }\n\n        @Nullable\n        private Object getRealValue(@Nullable String value) {\n            if (value == null) {\n                return null;\n            }\n            if (mRegex) {\n                return Pattern.compile(Pattern.quote(value));\n            }\n            switch (mType) {\n                case TYPE_UID: {\n                    if (TextUtils.isDigitsOnly(value)) {\n                        return Integer.parseInt(value);\n                    } // else fallthrough\n                }\n                case TYPE_MSG:\n                case TYPE_PKG:\n                case TYPE_TAG: {\n                    return mExact ? value : value.toLowerCase(Locale.ROOT);\n                }\n                case TYPE_PID: {\n                    return TextUtils.isDigitsOnly(value) ? Integer.parseInt(value) : null;\n                }\n                default:\n                    throw new IllegalArgumentException(\"Invalid filter: \" + mType);\n            }\n        }\n\n        @NonNull\n        @Override\n        public String toString() {\n            return \"Filter{\" +\n                    \"mType='\" + mType + '\\'' +\n                    \", mRegex=\" + mRegex +\n                    \", mExact=\" + mExact +\n                    \", mInverse=\" + mInverse +\n                    \", mValue=\" + mValue +\n                    '}';\n        }\n\n        private static boolean matchPattern(@NonNull Pattern pattern, @Nullable String value) {\n            if (value == null) {\n                return false;\n            }\n            return pattern.matcher(value).matches();\n        }\n\n        private static boolean matchQuery(@NonNull String query, @Nullable String value, boolean exact) {\n            if (value == null) {\n                return false;\n            }\n            return exact ? value.equals(query) : value.toLowerCase(Locale.ROOT).contains(query);\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/logcat/struct/SendLogDetails.java",
    "content": "// SPDX-License-Identifier: WTFPL AND GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.logcat.struct;\n\nimport androidx.annotation.Nullable;\n\nimport io.github.muntashirakon.io.Path;\n\n// Copyright 2012 Nolan Lawson\n// Copyright 2021 Muntashir Al-Islam\npublic class SendLogDetails {\n    @Nullable\n    private String mSubject;\n    @Nullable\n    private Path mAttachment;\n    @Nullable\n    private String mAttachmentType;\n\n    @Nullable\n    public String getSubject() {\n        return mSubject;\n    }\n\n    public void setSubject(@Nullable String subject) {\n        mSubject = subject;\n    }\n\n    @Nullable\n    public Path getAttachment() {\n        return mAttachment;\n    }\n\n    public void setAttachment(@Nullable Path attachment) {\n        mAttachment = attachment;\n    }\n\n    @Nullable\n    public String getAttachmentType() {\n        return mAttachmentType;\n    }\n\n    public void setAttachmentType(@Nullable String attachmentType) {\n        mAttachmentType = attachmentType;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/magisk/MagiskDenyList.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.magisk;\n\nimport static io.github.muntashirakon.AppManager.magisk.MagiskUtils.ISOLATED_MAGIC;\n\nimport android.content.pm.PackageInfo;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.WorkerThread;\n\nimport java.util.Collection;\nimport java.util.List;\n\nimport io.github.muntashirakon.AppManager.runner.Runner;\nimport io.github.muntashirakon.AppManager.settings.Ops;\n\n@WorkerThread\npublic class MagiskDenyList {\n    /**\n     * Whether Magisk DenyList is available.\n     */\n    public static boolean available() {\n        return Ops.isWorkingUidRoot() && Runner.runCommand(new String[]{\"magisk\", \"--denylist\", \"ls\"}).isSuccessful();\n    }\n\n    /**\n     * Enable Magisk DenyList if it is not already enabled.\n     *\n     * @return {@code true} iff Magisk DenyList is enabled.\n     */\n    public static boolean enableIfNotAlready(boolean forceEnable) {\n        // Check DenyList status\n        if (!Runner.runCommand(new String[]{\"magisk\", \"--denylist\", \"status\"}).isSuccessful()) {\n            // Enable DenyList\n            if (forceEnable) {\n                return Runner.runCommand(new String[]{\"magisk\", \"--denylist\", \"enable\"}).isSuccessful();\n            } else return false;\n        } else return true;\n    }\n\n    public static boolean apply(@NonNull MagiskProcess magiskProcess, boolean forceEnable) {\n        String packageName = magiskProcess.isIsolatedProcess() && !magiskProcess.isAppZygote() ? ISOLATED_MAGIC\n                : magiskProcess.packageName;\n        if (magiskProcess.isEnabled()) {\n            return add(packageName, magiskProcess.name, forceEnable);\n        }\n        return remove(packageName, magiskProcess.name);\n    }\n\n    private static boolean add(String packageName, String processName, boolean forceEnable) {\n        // Check DenyList status\n        if (!enableIfNotAlready(forceEnable)) return false;\n        // DenyList is enabled, enable hide for the package\n        return Runner.runCommand(new String[]{\"magisk\", \"--denylist\", \"add\", packageName, processName}).isSuccessful();\n    }\n\n    private static boolean remove(String packageName, String processName) {\n        // Disable hide for the package (don't need to check for status)\n        return Runner.runCommand(new String[]{\"magisk\", \"--denylist\", \"rm\", packageName, processName}).isSuccessful();\n    }\n\n    @NonNull\n    public static List<MagiskProcess> getProcesses(@NonNull PackageInfo packageInfo) {\n        return MagiskUtils.getProcesses(packageInfo, getProcesses(packageInfo.packageName));\n    }\n\n    @NonNull\n    public static Collection<String> getProcesses(@NonNull String packageName) {\n        Runner.Result result = Runner.runCommand(new String[]{\"magisk\", \"--denylist\", \"ls\"});\n        return MagiskUtils.parseProcesses(packageName, result);\n    }\n\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/magisk/MagiskHide.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.magisk;\n\nimport static io.github.muntashirakon.AppManager.magisk.MagiskUtils.ISOLATED_MAGIC;\n\nimport android.content.pm.PackageInfo;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.WorkerThread;\n\nimport java.util.Collection;\nimport java.util.List;\n\nimport io.github.muntashirakon.AppManager.runner.Runner;\nimport io.github.muntashirakon.AppManager.settings.Ops;\n\n@WorkerThread\npublic class MagiskHide {\n    /**\n     * Whether MagiskHide is available.\n     */\n    public static boolean available() {\n        return Ops.isWorkingUidRoot() && Runner.runCommand(new String[]{\"command\", \"-v\", \"magiskhide\"}).isSuccessful();\n    }\n\n    /**\n     * Enable MagiskHide if it is not already enabled.\n     *\n     * @return {@code true} iff MagiskHide is enabled.\n     */\n    public static boolean enableIfNotAlready(boolean forceEnable) {\n        // Check MagiskHide status\n        if (!Runner.runCommand(new String[]{\"magiskhide\", \"status\"}).isSuccessful()) {\n            // Enable MagiskHide\n            if (forceEnable) {\n                return Runner.runCommand(new String[]{\"magiskhide\", \"enable\"}).isSuccessful();\n            } else return false;\n        } else return true;\n    }\n\n    public static boolean apply(@NonNull MagiskProcess magiskProcess, boolean forceEnable) {\n        String packageName = magiskProcess.isIsolatedProcess() && !magiskProcess.isAppZygote() ? ISOLATED_MAGIC\n                : magiskProcess.packageName;\n        if (magiskProcess.isEnabled()) {\n            return add(packageName, magiskProcess.name, forceEnable);\n        }\n        return remove(packageName, magiskProcess.name);\n    }\n\n    private static boolean add(String packageName, String processName, boolean forceEnable) {\n        // Check MagiskHide status\n        if (!enableIfNotAlready(forceEnable)) return false;\n        // MagiskHide is enabled, enable hide for the package\n        return Runner.runCommand(new String[]{\"magiskhide\", \"add\", packageName, processName}).isSuccessful();\n    }\n\n    private static boolean remove(String packageName, String processName) {\n        // Disable hide for the package (don't need to check for status)\n        return Runner.runCommand(new String[]{\"magiskhide\", \"rm\", packageName, processName}).isSuccessful();\n    }\n\n    @NonNull\n    public static List<MagiskProcess> getProcesses(@NonNull PackageInfo packageInfo) {\n        return MagiskUtils.getProcesses(packageInfo, getProcesses(packageInfo.packageName));\n    }\n\n    @NonNull\n    public static Collection<String> getProcesses(@NonNull String packageName) {\n        Runner.Result result = Runner.runCommand(new String[]{\"magiskhide\", \"ls\"});\n        return MagiskUtils.parseProcesses(packageName, result);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/magisk/MagiskProcess.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.magisk;\n\nimport androidx.annotation.NonNull;\n\nimport java.util.Objects;\n\npublic class MagiskProcess {\n    @NonNull\n    public final String packageName;\n    @NonNull\n    public final String name;\n\n    private boolean mIsolatedProcess;\n    private boolean mIsRunning;\n    private boolean mIsEnabled;\n    private boolean mIsAppZygote;\n\n    public MagiskProcess(@NonNull String packageName, @NonNull String name) {\n        this.packageName = packageName;\n        this.name = name;\n    }\n\n    public MagiskProcess(@NonNull String packageName) {\n        this.packageName = packageName;\n        this.name = packageName;\n    }\n\n    public MagiskProcess(@NonNull MagiskProcess magiskProcess) {\n        packageName = magiskProcess.packageName;\n        name = magiskProcess.name;\n        mIsolatedProcess = magiskProcess.mIsolatedProcess;\n        mIsRunning = magiskProcess.mIsRunning;\n        mIsEnabled = magiskProcess.mIsEnabled;\n        mIsAppZygote = magiskProcess.mIsAppZygote;\n    }\n\n    public void setEnabled(boolean enabled) {\n        mIsEnabled = enabled;\n    }\n\n    public boolean isEnabled() {\n        return mIsEnabled;\n    }\n\n    public void setIsolatedProcess(boolean isolatedProcess) {\n        mIsolatedProcess = isolatedProcess;\n    }\n\n    public void setRunning(boolean running) {\n        mIsRunning = running;\n    }\n\n    public boolean isIsolatedProcess() {\n        return mIsolatedProcess;\n    }\n\n    public boolean isRunning() {\n        return mIsRunning;\n    }\n\n    public void setAppZygote(boolean appZygote) {\n        mIsAppZygote = appZygote;\n    }\n\n    public boolean isAppZygote() {\n        return mIsAppZygote;\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) return true;\n        if (!(o instanceof MagiskProcess)) return false;\n        MagiskProcess that = (MagiskProcess) o;\n        return name.equals(that.name);\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hash(name);\n    }\n}"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/magisk/MagiskUtils.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.magisk;\n\nimport android.content.pm.ApplicationInfo;\nimport android.content.pm.ComponentInfo;\nimport android.content.pm.PackageInfo;\nimport android.content.pm.ServiceInfo;\nimport android.os.Build;\n\nimport androidx.annotation.NonNull;\n\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.Set;\n\nimport io.github.muntashirakon.AppManager.runner.Runner;\nimport io.github.muntashirakon.AppManager.utils.AlphanumComparator;\nimport io.github.muntashirakon.io.Path;\nimport io.github.muntashirakon.io.Paths;\n\npublic class MagiskUtils {\n    // FIXME(20/9/20): This isn't always true, see check_data in util_functions.sh\n    public static final String NVBASE = \"/data/adb\";\n    private static boolean sBootMode = false;\n\n    public static final String ISOLATED_MAGIC = \"isolated\";\n\n    private static final String[] SCAN_PATHS = new String[]{\n            \"/system/app\", \"/system/priv-app\", \"/system/preload\",\n            \"/system/product/app\", \"/system/product/priv-app\", \"/system/product/overlay\",\n            \"/system/vendor/app\", \"/system/vendor/overlay\",\n            \"/system/system_ext/app\", \"/system/system_ext/priv-app\",\n            \"/system_ext/app\", \"/system_ext/priv-app\",\n\n            \"/vendor/app\", \"/vendor/overlay\",\n\n            \"/product/app\", \"/product/priv-app\", \"/product/overlay\",\n    };\n\n    @NonNull\n    public static Path getModDir() {\n        return Paths.get(NVBASE + \"/modules\" + (sBootMode ? \"_update\" : \"\"));\n    }\n\n    public static void setBootMode(boolean bootMode) {\n        MagiskUtils.sBootMode = bootMode;\n    }\n\n    private static List<String> sSystemlessPaths;\n\n    @NonNull\n    private static List<String> getSystemlessPaths() {\n        if (sSystemlessPaths == null) {\n            sSystemlessPaths = new ArrayList<>();\n            Path modDir = getModDir();\n            if (!modDir.canRead()) {\n                // No permission or no-magisk\n                return Collections.emptyList();\n            }\n            // Get module paths\n            Path[] modulePaths = modDir.listFiles(Path::isDirectory);\n            // Scan module paths\n            for (Path file : modulePaths) {\n                // Get system apk files\n                for (String sysPath : SCAN_PATHS) {\n                    // Always NonNull since it's a Linux FS\n                    Path[] paths = Objects.requireNonNull(Paths.build(file, sysPath)).listFiles(Path::isDirectory);\n                    for (Path path : paths) {\n                        if (hasApkFile(path)) {\n                            sSystemlessPaths.add(sysPath + \"/\" + path.getName());\n                        }\n                    }\n                }\n            }\n        }\n        return sSystemlessPaths;\n    }\n\n    public static boolean isSystemlessPath(@NonNull String path) {\n        return getSystemlessPaths().contains(path);\n    }\n\n    private static boolean hasApkFile(@NonNull Path file) {\n        if (file.isDirectory()) {\n            Path[] files = file.listFiles((dir, name) -> name.endsWith(\".apk\"));\n            return files.length > 0;\n        }\n        return false;\n    }\n\n    @NonNull\n    static List<MagiskProcess> getProcesses(@NonNull PackageInfo packageInfo,\n                                                  @NonNull Collection<String> enabledProcesses) {\n        String packageName = packageInfo.packageName;\n        ApplicationInfo applicationInfo = packageInfo.applicationInfo;\n        Map<String, MagiskProcess> processNameProcessMap = new HashMap<>();\n        {\n            // Add default process\n            MagiskProcess mp = new MagiskProcess(packageName);\n            mp.setEnabled(enabledProcesses.contains(packageName));\n            processNameProcessMap.put(packageName, mp);\n        }\n        // Add other processes: order must be preserved\n        if (packageInfo.services != null) {\n            for (ServiceInfo info : packageInfo.services) {\n                if ((info.flags & ServiceInfo.FLAG_ISOLATED_PROCESS) != 0) {\n                    // Isolated process\n                    if ((info.flags & ServiceInfo.FLAG_USE_APP_ZYGOTE) != 0) {\n                        // Uses app zygote\n                        String processName = (applicationInfo.processName == null ? applicationInfo.packageName : applicationInfo.processName) + \"_zygote\";\n                        if (processNameProcessMap.get(processName) == null) {\n                            MagiskProcess mp = new MagiskProcess(packageName, processName);\n                            mp.setEnabled(enabledProcesses.contains(processName));\n                            mp.setIsolatedProcess(true);\n                            mp.setAppZygote(true);\n                            processNameProcessMap.put(processName, mp);\n                        }\n                    } else {\n                        String processName = getProcessName(applicationInfo, info)\n                                + (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q ? (\":\" + packageName) : \"\");\n                        if (processNameProcessMap.get(processName) == null) {\n                            MagiskProcess mp = new MagiskProcess(packageName, processName);\n                            mp.setEnabled(enabledProcesses.contains(processName));\n                            mp.setIsolatedProcess(true);\n                            processNameProcessMap.put(processName, mp);\n                        }\n                    }\n                } else {\n                    String processName = getProcessName(applicationInfo, info);\n                    if (processNameProcessMap.get(processName) == null) {\n                        MagiskProcess mp = new MagiskProcess(packageName, processName);\n                        mp.setEnabled(enabledProcesses.contains(processName));\n                        processNameProcessMap.put(processName, mp);\n                    }\n                }\n            }\n        }\n        if (packageInfo.activities != null) {\n            for (ComponentInfo info : packageInfo.activities) {\n                String processName = getProcessName(applicationInfo, info);\n                if (processNameProcessMap.get(processName) == null) {\n                    MagiskProcess mp = new MagiskProcess(packageName, processName);\n                    mp.setEnabled(enabledProcesses.contains(processName));\n                    processNameProcessMap.put(processName, mp);\n                }\n            }\n        }\n        if (packageInfo.providers != null) {\n            for (ComponentInfo info : packageInfo.providers) {\n                String processName = getProcessName(applicationInfo, info);\n                if (processNameProcessMap.get(processName) == null) {\n                    MagiskProcess mp = new MagiskProcess(packageName, processName);\n                    mp.setEnabled(enabledProcesses.contains(processName));\n                    processNameProcessMap.put(processName, mp);\n                }\n            }\n        }\n        if (packageInfo.receivers != null) {\n            for (ComponentInfo info : packageInfo.receivers) {\n                String processName = getProcessName(applicationInfo, info);\n                if (processNameProcessMap.get(processName) == null) {\n                    MagiskProcess mp = new MagiskProcess(packageName, processName);\n                    mp.setEnabled(enabledProcesses.contains(processName));\n                    processNameProcessMap.put(processName, mp);\n                }\n            }\n        }\n        List<MagiskProcess> magiskProcesses = new ArrayList<>(processNameProcessMap.values());\n        Collections.sort(magiskProcesses, (o1, o2) -> AlphanumComparator.compareStringIgnoreCase(o1.name, o2.name));\n        return magiskProcesses;\n    }\n\n    @NonNull\n    static Collection<String> parseProcesses(@NonNull String packageName, @NonNull Runner.Result result) {\n        if (!result.isSuccessful()) {\n            // No matches\n            return Collections.emptyList();\n        }\n        Set<String> processes = new HashSet<>();\n        for (String line : result.getOutputAsList()) {\n            String[] splits = line.split(\"\\\\|\", 2);\n            if (splits.length == 1) {\n                // Old style outputs\n                if (splits[0].equals(packageName)) {\n                    processes.add(packageName);\n                } // else mismatch due to greedy algorithm\n            } else if (splits.length == 2) {\n                // New style output\n                if (splits[0].equals(packageName) || splits[0].equals(ISOLATED_MAGIC)) {\n                    processes.add(splits[1]);\n                } // else mismatch due to greedy algorithm\n            } // else unknown match\n        }\n        return processes;\n    }\n\n    @NonNull\n    private static String getProcessName(@NonNull ApplicationInfo applicationInfo, @NonNull ComponentInfo info) {\n        // Priority: component process name > application process name > package name\n        return info.processName != null ? info.processName : (applicationInfo.processName != null\n                ? applicationInfo.processName : applicationInfo.packageName);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/main/ApplicationItem.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.main;\n\nimport static io.github.muntashirakon.AppManager.compat.PackageManagerCompat.GET_SIGNING_CERTIFICATES;\nimport static io.github.muntashirakon.AppManager.compat.PackageManagerCompat.MATCH_DISABLED_COMPONENTS;\nimport static io.github.muntashirakon.AppManager.compat.PackageManagerCompat.MATCH_STATIC_SHARED_AND_SDK_LIBRARIES;\nimport static io.github.muntashirakon.AppManager.compat.PackageManagerCompat.MATCH_UNINSTALLED_PACKAGES;\n\nimport android.Manifest;\nimport android.content.pm.ActivityInfo;\nimport android.content.pm.ApplicationInfo;\nimport android.content.pm.ComponentInfo;\nimport android.content.pm.FeatureInfo;\nimport android.content.pm.PackageInfo;\nimport android.content.pm.PackageItemInfo;\nimport android.content.pm.PackageManager;\nimport android.content.pm.PermissionInfo;\nimport android.content.pm.ProviderInfo;\nimport android.content.pm.ServiceInfo;\nimport android.graphics.drawable.Drawable;\nimport android.os.Build;\nimport android.os.RemoteException;\nimport android.os.UserHandleHidden;\nimport android.text.TextUtils;\nimport android.util.Pair;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.RequiresApi;\nimport androidx.annotation.WorkerThread;\n\nimport java.io.InputStream;\nimport java.security.cert.CertificateEncodingException;\nimport java.security.cert.X509Certificate;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashSet;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.Set;\nimport java.util.concurrent.TimeUnit;\n\nimport aosp.libcore.util.EmptyArray;\nimport io.github.muntashirakon.AppManager.StaticDataset;\nimport io.github.muntashirakon.AppManager.apk.signing.SignerInfo;\nimport io.github.muntashirakon.AppManager.backup.BackupUtils;\nimport io.github.muntashirakon.AppManager.compat.AppOpsManagerCompat;\nimport io.github.muntashirakon.AppManager.compat.ApplicationInfoCompat;\nimport io.github.muntashirakon.AppManager.compat.DeviceIdleManagerCompat;\nimport io.github.muntashirakon.AppManager.compat.InstallSourceInfoCompat;\nimport io.github.muntashirakon.AppManager.compat.ManifestCompat;\nimport io.github.muntashirakon.AppManager.compat.PackageManagerCompat;\nimport io.github.muntashirakon.AppManager.compat.PermissionCompat;\nimport io.github.muntashirakon.AppManager.compat.SensorServiceCompat;\nimport io.github.muntashirakon.AppManager.compat.UsageStatsManagerCompat;\nimport io.github.muntashirakon.AppManager.db.entity.Backup;\nimport io.github.muntashirakon.AppManager.debloat.DebloatObject;\nimport io.github.muntashirakon.AppManager.filters.IFilterableAppInfo;\nimport io.github.muntashirakon.AppManager.filters.options.ComponentsOption;\nimport io.github.muntashirakon.AppManager.filters.options.FreezeOption;\nimport io.github.muntashirakon.AppManager.rules.compontents.ComponentUtils;\nimport io.github.muntashirakon.AppManager.rules.compontents.ComponentsBlocker;\nimport io.github.muntashirakon.AppManager.self.SelfPermissions;\nimport io.github.muntashirakon.AppManager.types.PackageSizeInfo;\nimport io.github.muntashirakon.AppManager.usage.AppUsageStatsManager;\nimport io.github.muntashirakon.AppManager.usage.PackageUsageInfo;\nimport io.github.muntashirakon.AppManager.utils.ArrayUtils;\nimport io.github.muntashirakon.AppManager.utils.ContextUtils;\nimport io.github.muntashirakon.AppManager.utils.DigestUtils;\nimport io.github.muntashirakon.AppManager.utils.ExUtils;\nimport io.github.muntashirakon.AppManager.utils.FreezeUtils;\nimport io.github.muntashirakon.AppManager.utils.KeyStoreUtils;\nimport io.github.muntashirakon.AppManager.utils.PackageUtils;\nimport io.github.muntashirakon.io.Path;\n\n/**\n * Stores an application info\n */\npublic class ApplicationItem extends PackageItemInfo implements IFilterableAppInfo {\n    /**\n     * Version name\n     */\n    public String versionName;\n    /**\n     * Version code\n     */\n    public long versionCode;\n    /**\n     * Backup info\n     */\n    @Nullable\n    public Backup backup;\n    /**\n     * Application flags.\n     * See {@link android.content.pm.ApplicationInfo#flags}\n     */\n    public int flags = 0;\n    /**\n     * Kernel user id.\n     * See {@link android.content.pm.ApplicationInfo#uid}\n     */\n    public int uid = 0;\n    /**\n     * Shared user id name.\n     * See {@link android.content.pm.PackageInfo#sharedUserId}\n     */\n    @Nullable\n    public String sharedUserId;\n    /**\n     * Application label (or name)\n     */\n    public String label;\n    /**\n     * True if debuggable, false otherwise\n     */\n    public boolean debuggable = false;\n    /**\n     * First install time\n     */\n    public long firstInstallTime = 0L;\n    /**\n     * Last update time\n     */\n    public Long lastUpdateTime = 0L;\n    /**\n     * Target SDK version\n     */\n    public Integer targetSdk;\n    /**\n     * Issuer and signature\n     */\n    @Nullable\n    public Pair<String, String> sha;\n    /**\n     * Blocked components count\n     */\n    public Integer blockedCount = 0;\n    public Integer trackerCount = 0;\n    public Long lastActionTime = 0L;\n    public Long dataUsage = 0L;\n    public Long totalSize = 0L;\n    public int openCount = 0;\n    public Long screenTime = 0L;\n    public Long lastUsageTime = 0L;\n    /**\n     * Whether the item is a user app (or system app)\n     */\n    public boolean isUser;\n    /**\n     * Whether the app is disabled\n     */\n    public boolean isDisabled;\n    /**\n     * Whether the app is installed\n     */\n    public boolean isInstalled = true;\n    public boolean isOnlyDataInstalled = true;\n    /**\n     * Whether the app has any activities\n     */\n    public boolean hasActivities = false;\n    /**\n     * Whether the app has any splits\n     */\n    public boolean hasSplits = false;\n    public boolean hasKeystore = false;\n    public boolean usesSaf = false;\n    public String ssaid = null;\n    /**\n     * Whether the item is selected\n     */\n    public boolean isSelected = false;\n\n    @NonNull\n    public int[] userIds = EmptyArray.INT;\n\n    // Other info\n    public boolean isStopped;\n    public boolean isSystem;\n    public boolean isPersistent;\n    public boolean usesCleartextTraffic;\n    public boolean canReadLogs;\n    public boolean allowClearingUserData;\n    public boolean isAppInactive;\n    public String uidOrAppIds;\n    public String issuerShortName;\n    public String versionTag;\n    public String appTypePostfix;\n    public String sdkString;\n    public long diffInstallUpdateInDays;\n    public long lastBackupDays;\n    public StringBuilder backupFlagsStr;\n\n    // Fields below only required for filters, hence, loaded dynamically\n    @Nullable\n    private PackageInfo mPackageInfo;\n    @Nullable\n    private PackageUsageInfo mPackageUsageInfo;\n    @Nullable\n    private ApplicationInfo mApplicationInfo;\n    private InstallSourceInfoCompat mInstallerInfo;\n    @Nullable\n    private SignerInfo mSignerInfo;\n    private String[] mSignatureSubjectLines;\n    private String[] mSignatureSha256Checksums;\n    private Map<ComponentInfo, Integer> mAllComponents;\n    private Map<ComponentInfo, Integer> mTrackerComponents;\n    private List<String> mUsedPermissions;\n    private Backup[] mBackups;\n    private List<AppOpsManagerCompat.OpEntry> mAppOpEntries;\n    @Nullable\n    private PackageSizeInfo mPackageSizeInfo;\n    @Nullable\n    private AppUsageStatsManager.DataUsage mDataUsage;\n    @Nullable\n    private DebloatObject mBloatwareInfo;\n    private Integer mFreezeFlags = null;\n    private Integer mUserId = null;\n    private Boolean mUsesSensors = null;\n    private Boolean mBatteryOptEnabled = null;\n    private Boolean mHasKeystoreItems = null;\n    private Integer mRulesCount = null;\n    private boolean mIsRunning = false;\n\n    public ApplicationItem() {\n        super();\n    }\n\n    public void generateOtherInfo() {\n        isStopped = (flags & ApplicationInfo.FLAG_STOPPED) != 0;\n        isSystem = (flags & ApplicationInfo.FLAG_SYSTEM) != 0;\n        isPersistent = (flags & ApplicationInfo.FLAG_PERSISTENT) != 0;\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {\n            usesCleartextTraffic = (flags & ApplicationInfo.FLAG_USES_CLEARTEXT_TRAFFIC) != 0;\n        }\n        for (int userId : userIds) {\n            canReadLogs |= (PermissionCompat.checkPermission(Manifest.permission.READ_LOGS, packageName, userId) == PackageManager.PERMISSION_GRANTED);\n            isAppInactive |= UsageStatsManagerCompat.isAppInactive(packageName, userId);\n        }\n        allowClearingUserData = (flags & ApplicationInfo.FLAG_ALLOW_CLEAR_USER_DATA) != 0;\n        // UID\n        if (userIds.length > 1) {\n            int appId = UserHandleHidden.getAppId(uid);\n            uidOrAppIds = userIds.length + \"+\" + appId;\n        } else if (userIds.length == 1) {\n            uidOrAppIds = String.valueOf(uid);\n        } else uidOrAppIds = \"\";\n        // Cert short name\n        if (sha != null) {\n            try {\n                issuerShortName = \"CN=\" + (sha.first).split(\"CN=\", 2)[1];\n            } catch (ArrayIndexOutOfBoundsException e) {\n                issuerShortName = sha.first;\n            }\n            if (TextUtils.isEmpty(sha.second)) {\n                sha = null;\n            }\n        }\n        // Version info\n        versionTag = versionName;\n        if (isInstalled && (flags & ApplicationInfo.FLAG_HARDWARE_ACCELERATED) == 0)\n            versionTag = \"_\" + versionTag;\n        if ((flags & ApplicationInfo.FLAG_DEBUGGABLE) != 0) versionTag = \"debug\" + versionTag;\n        if ((flags & ApplicationInfo.FLAG_TEST_ONLY) != 0) versionTag = \"~\" + versionTag;\n        // App type flags\n        appTypePostfix = \"\";\n        if ((flags & ApplicationInfo.FLAG_LARGE_HEAP) != 0) appTypePostfix += \"#\";\n        if ((flags & ApplicationInfo.FLAG_SUSPENDED) != 0) appTypePostfix += \"°\";\n        if ((flags & ApplicationInfo.FLAG_MULTIARCH) != 0) appTypePostfix += \"X\";\n        if ((flags & ApplicationInfo.FLAG_HAS_CODE) == 0) appTypePostfix += \"0\";\n        if ((flags & ApplicationInfo.FLAG_VM_SAFE_MODE) != 0) appTypePostfix += \"?\";\n        // Sdk\n        if (targetSdk != null && targetSdk > 0) {\n            sdkString = \"SDK \" + targetSdk;\n        }\n        diffInstallUpdateInDays = TimeUnit.DAYS.convert(lastUpdateTime - firstInstallTime, TimeUnit.MILLISECONDS);\n        // Backup\n        if (backup != null) {\n            lastBackupDays = TimeUnit.DAYS.convert(System.currentTimeMillis() - backup.backupTime, TimeUnit.MILLISECONDS);\n            backupFlagsStr = new StringBuilder();\n            if (backup.getFlags().backupApkFiles()) backupFlagsStr.append(\"apk\");\n            if (backup.getFlags().backupData()) {\n                if (backupFlagsStr.length() > 0) backupFlagsStr.append(\"+\");\n                backupFlagsStr.append(\"data\");\n            }\n            if (backup.hasRules) {\n                if (backupFlagsStr.length() > 0) backupFlagsStr.append(\"+\");\n                backupFlagsStr.append(\"rules\");\n            }\n        }\n    }\n\n    @WorkerThread\n    @Override\n    public Drawable loadIcon(PackageManager pm) {\n        fetchPackageInfo();\n        if (mApplicationInfo != null) {\n            return mApplicationInfo.loadIcon(pm);\n        }\n        // App not installed\n        if (backup != null) {\n            try {\n                Path iconFile = backup.getItem().getIconFile();\n                if (iconFile.exists()) {\n                    try (InputStream is = iconFile.openInputStream()) {\n                        Drawable drawable = Drawable.createFromStream(is, name);\n                        if (drawable != null) {\n                            return drawable;\n                        }\n                    }\n                }\n            } catch (Throwable ignore) {\n            }\n        }\n        return pm.getDefaultActivityIcon();\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) return true;\n        if (!(o instanceof ApplicationItem)) return false;\n        ApplicationItem item = (ApplicationItem) o;\n        return packageName.equals(item.packageName);\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hash(packageName);\n    }\n\n    @NonNull\n    @Override\n    public String getPackageName() {\n        return packageName;\n    }\n\n    @Override\n    public int getUserId() {\n        if (mUserId != null) {\n            return mUserId;\n        }\n        if (userIds.length > 0) {\n            int myUserId = UserHandleHidden.myUserId();\n            for (int userId : userIds) {\n                // Prefer current user\n                if (userId == myUserId) {\n                    mUserId = myUserId;\n                    break;\n                }\n            }\n            if (mUserId == null) {\n                // Failed, assign the first user\n                mUserId = userIds[0];\n            }\n            return mUserId;\n        }\n        return -1;\n    }\n\n    @Override\n    public int getUid() {\n        int uid = mApplicationInfo != null ? mApplicationInfo.uid : this.uid;\n        return UserHandleHidden.getAppId(uid);\n    }\n\n    public void setPackageUsageInfo(@Nullable PackageUsageInfo packageUsageInfo) {\n        mPackageUsageInfo = packageUsageInfo;\n    }\n\n    private void fetchPackageInfo() {\n        if (mPackageInfo != null) {\n            return;\n        }\n        int userId = getUserId();\n        if (userId < 0) {\n            return;\n        }\n        try {\n            mPackageInfo = PackageManagerCompat.getPackageInfo(packageName,\n                    PackageManager.GET_META_DATA | GET_SIGNING_CERTIFICATES\n                            | PackageManager.GET_ACTIVITIES | PackageManager.GET_RECEIVERS\n                            | PackageManager.GET_PROVIDERS | PackageManager.GET_SERVICES\n                            | PackageManager.GET_CONFIGURATIONS | PackageManager.GET_PERMISSIONS\n                            | PackageManager.GET_URI_PERMISSION_PATTERNS\n                            | MATCH_DISABLED_COMPONENTS | MATCH_UNINSTALLED_PACKAGES\n                            | MATCH_STATIC_SHARED_AND_SDK_LIBRARIES, userId);\n            mApplicationInfo = Objects.requireNonNull(mPackageInfo.applicationInfo);\n            // Update dynamic info\n            isStopped = (mApplicationInfo.flags & ApplicationInfo.FLAG_STOPPED) != 0;\n            isDisabled = FreezeUtils.isFrozen(mApplicationInfo);\n        } catch (RemoteException | PackageManager.NameNotFoundException ignore) {\n        }\n    }\n\n    @NonNull\n    @Override\n    public String getAppLabel() {\n        return label;\n    }\n\n    @NonNull\n    @Override\n    public Drawable getAppIcon() {\n        return loadIcon(ContextUtils.getContext().getPackageManager());\n    }\n\n    @Nullable\n    @Override\n    public String getVersionName() {\n        return versionName;\n    }\n\n    @Override\n    public long getVersionCode() {\n        return versionCode;\n    }\n\n    @Override\n    public long getFirstInstallTime() {\n        return firstInstallTime;\n    }\n\n    @Override\n    public long getLastUpdateTime() {\n        return lastUpdateTime;\n    }\n\n    @Override\n    public int getTargetSdk() {\n        return targetSdk;\n    }\n\n    @Override\n    @RequiresApi(Build.VERSION_CODES.S)\n    public int getCompileSdk() {\n        fetchPackageInfo();\n        if (mApplicationInfo != null) {\n            return mApplicationInfo.compileSdkVersion;\n        }\n        return targetSdk;\n    }\n\n    @Override\n    @RequiresApi(Build.VERSION_CODES.N)\n    public int getMinSdk() {\n        fetchPackageInfo();\n        if (mApplicationInfo != null) {\n            return mApplicationInfo.minSdkVersion;\n        }\n        return 0;\n    }\n\n    @NonNull\n    @Override\n    public Backup[] getBackups() {\n        if (mBackups == null) {\n            mBackups = BackupUtils.getBackupMetadataFromDbNoLockValidate(getPackageName()).toArray(new Backup[0]);\n        }\n        return mBackups;\n    }\n\n    public void setRunning(boolean running) {\n        mIsRunning = running;\n    }\n\n    @Override\n    public boolean isRunning() {\n        return mIsRunning;\n    }\n\n    @NonNull\n    @Override\n    public Map<ComponentInfo, Integer> getTrackerComponents() {\n        if (mTrackerComponents == null) {\n            Map<ComponentInfo, Integer> allComponents = getAllComponents();\n            Map<ComponentInfo, Integer> trackerComponents = new LinkedHashMap<>();\n            for (ComponentInfo itemInfo : allComponents.keySet()) {\n                if (ComponentUtils.isTracker(itemInfo.name)) {\n                    trackerComponents.put(itemInfo, allComponents.get(itemInfo));\n                }\n            }\n            mTrackerComponents = trackerComponents;\n        }\n        return mTrackerComponents;\n    }\n\n    @NonNull\n    @Override\n    public List<AppOpsManagerCompat.OpEntry> getAppOps() {\n        fetchPackageInfo();\n        if (mApplicationInfo != null && mAppOpEntries == null && isInstalled()) {\n            List<AppOpsManagerCompat.PackageOps> packageOps = ExUtils.exceptionAsNull(() -> new AppOpsManagerCompat().getOpsForPackage(mApplicationInfo.uid, getPackageName(), null));\n            if (packageOps != null && packageOps.size() == 1) {\n                mAppOpEntries = packageOps.get(0).getOps();\n            }\n        } else mAppOpEntries = Collections.emptyList();\n        return mAppOpEntries;\n    }\n\n    @NonNull\n    @Override\n    public Map<ComponentInfo, Integer> getAllComponents() {\n        fetchPackageInfo();\n        if (mPackageInfo != null && mAllComponents == null) {\n            Map<ComponentInfo, Integer> components = new LinkedHashMap<>();\n            if (mPackageInfo.activities != null) {\n                for (ActivityInfo info : mPackageInfo.activities) {\n                    components.put(info, ComponentsOption.COMPONENT_TYPE_ACTIVITY);\n                }\n            }\n            if (mPackageInfo.services != null) {\n                for (ServiceInfo info : mPackageInfo.services) {\n                    components.put(info, ComponentsOption.COMPONENT_TYPE_SERVICE);\n                }\n            }\n            if (mPackageInfo.receivers != null) {\n                for (ActivityInfo info : mPackageInfo.receivers) {\n                    components.put(info, ComponentsOption.COMPONENT_TYPE_RECEIVER);\n                }\n            }\n            if (mPackageInfo.providers != null) {\n                for (ProviderInfo info : mPackageInfo.providers) {\n                    components.put(info, ComponentsOption.COMPONENT_TYPE_PROVIDER);\n                }\n            }\n            mAllComponents = components;\n        }\n        return mAllComponents;\n    }\n\n    @NonNull\n    @Override\n    public List<String> getAllPermissions() {\n        fetchPackageInfo();\n        if (mPackageInfo != null && mUsedPermissions == null) {\n            Set<String> usedPermissions = new HashSet<>();\n            if (mPackageInfo.requestedPermissions != null) {\n                Collections.addAll(usedPermissions, mPackageInfo.requestedPermissions);\n            }\n            if (mPackageInfo.permissions != null) {\n                for (PermissionInfo perm : mPackageInfo.permissions) {\n                    usedPermissions.add(perm.name);\n                }\n            }\n            if (mPackageInfo.activities != null) {\n                for (ActivityInfo info : mPackageInfo.activities) {\n                    if (info.permission != null) {\n                        usedPermissions.add(info.permission);\n                    }\n                }\n            }\n            if (mPackageInfo.services != null) {\n                for (ServiceInfo info : mPackageInfo.services) {\n                    if (info.permission != null) {\n                        usedPermissions.add(info.permission);\n                    }\n                }\n            }\n            if (mPackageInfo.receivers != null) {\n                for (ActivityInfo info : mPackageInfo.receivers) {\n                    if (info.permission != null) {\n                        usedPermissions.add(info.permission);\n                    }\n                }\n            }\n            mUsedPermissions = new ArrayList<>(usedPermissions);\n        }\n        return mUsedPermissions;\n    }\n\n    @NonNull\n    @Override\n    public FeatureInfo[] getAllRequestedFeatures() {\n        fetchPackageInfo();\n        if (mPackageInfo != null) {\n            return ArrayUtils.defeatNullable(FeatureInfo.class, mPackageInfo.reqFeatures);\n        }\n        return new FeatureInfo[0];\n    }\n\n    @Override\n    public boolean isInstalled() {\n        return isInstalled;\n    }\n\n    @Override\n    public boolean isFrozen() {\n        return !isEnabled() || isSuspended() || isHidden();\n    }\n\n    @Override\n    public int getFreezeFlags() {\n        if (mFreezeFlags != null) {\n            return mFreezeFlags;\n        }\n        mFreezeFlags = 0;\n        if (!isEnabled()) {\n            mFreezeFlags |= FreezeOption.FREEZE_TYPE_DISABLED;\n        }\n        if (isHidden()) {\n            mFreezeFlags |= FreezeOption.FREEZE_TYPE_HIDDEN;\n        }\n        if (isSuspended()) {\n            mFreezeFlags |= FreezeOption.FREEZE_TYPE_SUSPENDED;\n        }\n        return mFreezeFlags;\n    }\n\n    @Override\n    public boolean isStopped() {\n        return isStopped;\n    }\n\n    @Override\n    public boolean isTestOnly() {\n        return (flags & ApplicationInfo.FLAG_TEST_ONLY) != 0;\n    }\n\n    @Override\n    public boolean isDebuggable() {\n        return debuggable;\n    }\n\n    @Override\n    public boolean isSystemApp() {\n        return isSystem;\n    }\n\n    @Override\n    public boolean hasCode() {\n        return (flags & ApplicationInfo.FLAG_HAS_CODE) != 0;\n    }\n\n    @Override\n    public boolean isPersistent() {\n        return isPersistent;\n    }\n\n    @Override\n    public boolean isUpdatedSystemApp() {\n        return (flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0;\n    }\n\n    @Override\n    public boolean backupAllowed() {\n        return (flags & ApplicationInfo.FLAG_ALLOW_BACKUP) != 0;\n    }\n\n    @Override\n    public boolean installedInExternalStorage() {\n        return (flags & ApplicationInfo.FLAG_EXTERNAL_STORAGE) != 0;\n    }\n\n    @Override\n    public boolean requestedLargeHeap() {\n        return (flags & ApplicationInfo.FLAG_LARGE_HEAP) != 0;\n    }\n\n    @Override\n    public boolean supportsRTL() {\n        return (flags & ApplicationInfo.FLAG_SUPPORTS_RTL) != 0;\n    }\n\n    @Override\n    public boolean dataOnlyApp() {\n        return (flags & ApplicationInfo.FLAG_IS_DATA_ONLY) != 0;\n    }\n\n    @Override\n    public boolean usesHttp() {\n        return usesCleartextTraffic;\n    }\n\n    @Override\n    public boolean isPrivileged() {\n        fetchPackageInfo();\n        if (mApplicationInfo != null) {\n            return ApplicationInfoCompat.isPrivileged(mApplicationInfo);\n        }\n        return false;\n    }\n\n    @RequiresApi(Build.VERSION_CODES.P)\n    public boolean usesSensors() {\n        if (mUsesSensors == null) {\n            if (isInstalled() && SelfPermissions.checkSelfOrRemotePermission(ManifestCompat.permission.MANAGE_SENSORS)) {\n                mUsesSensors = SensorServiceCompat.isSensorEnabled(getPackageName(), getUserId());\n            } else mUsesSensors = isInstalled(); // Worse case: always true\n        }\n        return mUsesSensors;\n    }\n\n    @Override\n    public boolean isBatteryOptEnabled() {\n        if (mBatteryOptEnabled == null) {\n            if (isInstalled()) {\n                mBatteryOptEnabled = DeviceIdleManagerCompat.isBatteryOptimizedApp(getPackageName());\n            } else mBatteryOptEnabled = true;\n        }\n        return mBatteryOptEnabled;\n    }\n\n    @Override\n    public boolean hasKeyStoreItems() {\n        fetchPackageInfo();\n        if (mHasKeystoreItems == null) {\n            if (mApplicationInfo != null && isInstalled()) {\n                mHasKeystoreItems = KeyStoreUtils.hasKeyStore(mApplicationInfo.uid);\n            } else mHasKeystoreItems = false;\n        }\n        return mHasKeystoreItems;\n    }\n\n    @Override\n    public int getRuleCount() {\n        if (mRulesCount == null) {\n            mRulesCount = 0;\n            for (int userId : userIds) {\n                try (ComponentsBlocker cb = ComponentsBlocker.getInstance(getPackageName(), userId, false)) {\n                    mRulesCount += cb.entryCount();\n                }\n            }\n        }\n        return mRulesCount;\n    }\n\n    @Nullable\n    @Override\n    public String getSsaid() {\n        return ssaid;\n    }\n\n    @Override\n    public boolean hasDomainUrls() {\n        fetchPackageInfo();\n        if (mApplicationInfo != null) {\n            return ApplicationInfoCompat.hasDomainUrls(mApplicationInfo);\n        }\n        return false;\n    }\n\n    @Override\n    public boolean hasStaticSharedLibrary() {\n        fetchPackageInfo();\n        if (mApplicationInfo != null) {\n            return ApplicationInfoCompat.isStaticSharedLibrary(mApplicationInfo);\n        }\n        return false;\n    }\n\n    @Override\n    public boolean isHidden() {\n        fetchPackageInfo();\n        if (mApplicationInfo != null) {\n            return ApplicationInfoCompat.isHidden(mApplicationInfo);\n        }\n        return false;\n    }\n\n    @Override\n    public boolean isSuspended() {\n        fetchPackageInfo();\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && mApplicationInfo != null) {\n            return ApplicationInfoCompat.isSuspended(mApplicationInfo);\n        }\n        // Not supported\n        return false;\n    }\n\n    @Override\n    public boolean isEnabled() {\n        fetchPackageInfo();\n        if (mApplicationInfo != null) {\n            return mApplicationInfo.enabled;\n        }\n        return !isDisabled;\n    }\n\n    @Nullable\n    @Override\n    public String getSharedUserId() {\n        fetchPackageInfo();\n        return mPackageInfo != null ? mPackageInfo.sharedUserId : sharedUserId;\n    }\n\n    private void fetchPackageSizeInfo() {\n        int userId = getUserId();\n        if (userId >= 0 && mPackageSizeInfo == null && isInstalled()) {\n            mPackageSizeInfo = PackageUtils.getPackageSizeInfo(ContextUtils.getContext(), getPackageName(), userId, null);\n        }\n    }\n\n    @Override\n    public long getTotalSize() {\n        fetchPackageSizeInfo();\n        return mPackageSizeInfo != null ? mPackageSizeInfo.getTotalSize() : 0;\n    }\n\n    @Override\n    public long getApkSize() {\n        fetchPackageSizeInfo();\n        return mPackageSizeInfo != null ? (mPackageSizeInfo.codeSize + mPackageSizeInfo.obbSize) : 0;\n    }\n\n    @Override\n    public long getCacheSize() {\n        fetchPackageSizeInfo();\n        return mPackageSizeInfo != null ? mPackageSizeInfo.cacheSize : 0;\n    }\n\n    @Override\n    public long getDataSize() {\n        fetchPackageSizeInfo();\n        return mPackageSizeInfo != null ? (mPackageSizeInfo.dataSize + mPackageSizeInfo.mediaSize + mPackageSizeInfo.cacheSize) : 0;\n    }\n\n    @Override\n    @NonNull\n    public AppUsageStatsManager.DataUsage getDataUsage() {\n        if (mDataUsage == null && isInstalled()) {\n            if (mPackageUsageInfo != null) {\n                mDataUsage = AppUsageStatsManager.DataUsage.fromDataUsage(mPackageUsageInfo.mobileData, mPackageUsageInfo.wifiData);\n            }\n        }\n        if (mDataUsage == null) {\n            mDataUsage = AppUsageStatsManager.DataUsage.EMPTY;\n        }\n        return mDataUsage;\n    }\n\n    @Override\n    public int getTimesOpened() {\n        fetchPackageInfo();\n        return mPackageUsageInfo != null ? mPackageUsageInfo.timesOpened : openCount;\n    }\n\n    @Override\n    public long getTotalScreenTime() {\n        fetchPackageInfo();\n        return mPackageUsageInfo != null ? mPackageUsageInfo.screenTime : screenTime;\n    }\n\n    @Override\n    public long getLastUsedTime() {\n        fetchPackageInfo();\n        return mPackageUsageInfo != null ? mPackageUsageInfo.lastUsageTime : lastUsageTime;\n    }\n\n    @Override\n    @Nullable\n    public SignerInfo fetchSignerInfo() {\n        fetchPackageInfo();\n        if (mPackageInfo != null && mSignerInfo == null) {\n            mSignerInfo = PackageUtils.getSignerInfo(mPackageInfo, !isInstalled());\n        }\n        return mSignerInfo;\n    }\n\n    @Override\n    @NonNull\n    public String[] getSignatureSubjectLines() {\n        fetchSignerInfo();\n        if (mSignerInfo != null && mSignatureSubjectLines == null) {\n            X509Certificate[] signatures = mSignerInfo.getAllSignerCerts();\n            if (signatures != null) {\n                mSignatureSubjectLines = new String[signatures.length];\n                for (int i = 0; i < signatures.length; ++i) {\n                    mSignatureSubjectLines[i] = signatures[i].getSubjectX500Principal().getName();\n                }\n            }\n        }\n        return mSignatureSubjectLines != null ? mSignatureSubjectLines : EmptyArray.STRING;\n    }\n\n    @Override\n    @NonNull\n    public String[] getSignatureSha256Checksums() {\n        fetchSignerInfo();\n        if (mSignerInfo != null && mSignatureSha256Checksums == null) {\n            X509Certificate[] signatures = mSignerInfo.getAllSignerCerts();\n            if (signatures != null) {\n                mSignatureSha256Checksums = new String[signatures.length];\n                for (int i = 0; i < signatures.length; ++i) {\n                    try {\n                        mSignatureSha256Checksums[i] = DigestUtils.getHexDigest(DigestUtils.SHA_256, signatures[i].getEncoded());\n                    } catch (CertificateEncodingException e) {\n                        mSignatureSha256Checksums[i] = \"\";\n                    }\n                }\n            }\n        }\n        return mSignatureSha256Checksums != null ? mSignatureSha256Checksums : EmptyArray.STRING;\n    }\n\n    @Override\n    @Nullable\n    public InstallSourceInfoCompat getInstallerInfo() {\n        int userId = getUserId();\n        if (userId >= 0 && mInstallerInfo == null && isInstalled()) {\n            try {\n                mInstallerInfo = PackageManagerCompat.getInstallSourceInfo(getPackageName(), userId);\n            } catch (RemoteException ignore) {\n            }\n        }\n        return mInstallerInfo;\n    }\n\n    @Override\n    @Nullable\n    public DebloatObject getBloatwareInfo() {\n        if (mBloatwareInfo == null) {\n            for (DebloatObject debloatObject : StaticDataset.getDebloatObjects()) {\n                if (getPackageName().equals(debloatObject.packageName)) {\n                    mBloatwareInfo = debloatObject;\n                    break;\n                }\n            }\n        }\n        return mBloatwareInfo;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/main/MainActivity.java",
    "content": "// SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.main;\n\nimport android.annotation.SuppressLint;\nimport android.content.BroadcastReceiver;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.IntentFilter;\nimport android.content.pm.PackageManager;\nimport android.net.Uri;\nimport android.os.Bundle;\nimport android.text.TextUtils;\nimport android.view.Gravity;\nimport android.view.Menu;\nimport android.view.MenuItem;\nimport android.view.View;\nimport android.view.ViewGroup;\n\nimport androidx.activity.OnBackPressedCallback;\nimport androidx.activity.result.ActivityResultLauncher;\nimport androidx.activity.result.contract.ActivityResultContracts;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.appcompat.app.ActionBar;\nimport androidx.collection.ArrayMap;\nimport androidx.core.content.ContextCompat;\nimport androidx.lifecycle.ViewModelProvider;\nimport androidx.recyclerview.widget.LinearLayoutManager;\nimport androidx.recyclerview.widget.RecyclerView;\n\nimport com.google.android.material.checkbox.MaterialCheckBox;\nimport com.google.android.material.dialog.MaterialAlertDialogBuilder;\nimport com.google.android.material.progressindicator.LinearProgressIndicator;\nimport com.google.android.material.snackbar.Snackbar;\n\nimport org.xmlpull.v1.XmlPullParserException;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.Iterator;\nimport java.util.List;\n\nimport io.github.muntashirakon.AppManager.BaseActivity;\nimport io.github.muntashirakon.AppManager.BuildConfig;\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.apk.behavior.FreezeUnfreeze;\nimport io.github.muntashirakon.AppManager.apk.dexopt.DexOptDialog;\nimport io.github.muntashirakon.AppManager.apk.list.ListExporter;\nimport io.github.muntashirakon.AppManager.backup.dialog.BackupRestoreDialogFragment;\nimport io.github.muntashirakon.AppManager.batchops.BatchOpsManager;\nimport io.github.muntashirakon.AppManager.batchops.BatchOpsService;\nimport io.github.muntashirakon.AppManager.batchops.BatchQueueItem;\nimport io.github.muntashirakon.AppManager.batchops.struct.BatchFreezeOptions;\nimport io.github.muntashirakon.AppManager.batchops.struct.BatchNetPolicyOptions;\nimport io.github.muntashirakon.AppManager.batchops.struct.IBatchOpOptions;\nimport io.github.muntashirakon.AppManager.changelog.Changelog;\nimport io.github.muntashirakon.AppManager.changelog.ChangelogParser;\nimport io.github.muntashirakon.AppManager.changelog.ChangelogRecyclerAdapter;\nimport io.github.muntashirakon.AppManager.compat.NetworkPolicyManagerCompat;\nimport io.github.muntashirakon.AppManager.debloat.DebloaterActivity;\nimport io.github.muntashirakon.AppManager.filters.FinderActivity;\nimport io.github.muntashirakon.AppManager.misc.AdvancedSearchView;\nimport io.github.muntashirakon.AppManager.misc.HelpActivity;\nimport io.github.muntashirakon.AppManager.misc.LabsActivity;\nimport io.github.muntashirakon.AppManager.oneclickops.OneClickOpsActivity;\nimport io.github.muntashirakon.AppManager.profiles.AddToProfileDialogFragment;\nimport io.github.muntashirakon.AppManager.profiles.ProfilesActivity;\nimport io.github.muntashirakon.AppManager.rules.RulesTypeSelectionDialogFragment;\nimport io.github.muntashirakon.AppManager.runningapps.RunningAppsActivity;\nimport io.github.muntashirakon.AppManager.self.life.FundingCampaignChecker;\nimport io.github.muntashirakon.AppManager.settings.FeatureController;\nimport io.github.muntashirakon.AppManager.settings.Prefs;\nimport io.github.muntashirakon.AppManager.settings.SettingsActivity;\nimport io.github.muntashirakon.AppManager.usage.AppUsageActivity;\nimport io.github.muntashirakon.AppManager.users.Users;\nimport io.github.muntashirakon.AppManager.utils.AppPref;\nimport io.github.muntashirakon.AppManager.utils.DateUtils;\nimport io.github.muntashirakon.AppManager.utils.StoragePermission;\nimport io.github.muntashirakon.AppManager.utils.UIUtils;\nimport io.github.muntashirakon.dialog.AlertDialogBuilder;\nimport io.github.muntashirakon.dialog.ScrollableDialogBuilder;\nimport io.github.muntashirakon.dialog.SearchableFlagsDialogBuilder;\nimport io.github.muntashirakon.dialog.SearchableSingleChoiceDialogBuilder;\nimport io.github.muntashirakon.io.Paths;\nimport io.github.muntashirakon.multiselection.MultiSelectionActionsView;\nimport io.github.muntashirakon.util.UiUtils;\nimport io.github.muntashirakon.widget.MultiSelectionView;\nimport io.github.muntashirakon.widget.SwipeRefreshLayout;\n\npublic class MainActivity extends BaseActivity implements AdvancedSearchView.OnQueryTextListener,\n        SwipeRefreshLayout.OnRefreshListener, MultiSelectionActionsView.OnItemSelectedListener,\n        MultiSelectionView.OnSelectionModeChangeListener {\n    private static final String PACKAGE_NAME_APK_UPDATER = \"com.apkupdater\";\n    private static final String ACTIVITY_NAME_APK_UPDATER = \"com.apkupdater.activity.MainActivity\";\n\n    private static boolean SHOW_DISCLAIMER = true;\n\n    MainViewModel viewModel;\n\n    private MainRecyclerAdapter mAdapter;\n    private AdvancedSearchView mSearchView;\n    private LinearProgressIndicator mProgressIndicator;\n    private SwipeRefreshLayout mSwipeRefresh;\n    private MultiSelectionView mMultiSelectionView;\n    MainBatchOpsHandler mBatchOpsHandler;\n    private MenuItem mAppUsageMenu;\n\n    private final StoragePermission mStoragePermission = StoragePermission.init(this);\n\n    private final ActivityResultLauncher<String> mBatchExportRules = registerForActivityResult(\n            new ActivityResultContracts.CreateDocument(\"text/tab-separated-values\"),\n            uri -> {\n                if (uri == null) {\n                    // Back button pressed.\n                    return;\n                }\n                if (viewModel == null) {\n                    // Invalid state\n                    return;\n                }\n                RulesTypeSelectionDialogFragment dialogFragment = new RulesTypeSelectionDialogFragment();\n                Bundle args = new Bundle();\n                args.putInt(RulesTypeSelectionDialogFragment.ARG_MODE, RulesTypeSelectionDialogFragment.MODE_EXPORT);\n                args.putParcelable(RulesTypeSelectionDialogFragment.ARG_URI, uri);\n                args.putStringArrayList(RulesTypeSelectionDialogFragment.ARG_PKG, new ArrayList<>(viewModel.getSelectedPackages().keySet()));\n                args.putIntArray(RulesTypeSelectionDialogFragment.ARG_USERS, Users.getUsersIds());\n                dialogFragment.setArguments(args);\n                dialogFragment.show(getSupportFragmentManager(), RulesTypeSelectionDialogFragment.TAG);\n            });\n\n    private final ActivityResultLauncher<String> mExportAppListCsv = registerForActivityResult(\n            new ActivityResultContracts.CreateDocument(\"text/csv\"),\n            uri -> {\n                if (uri == null) {\n                    // Back button pressed.\n                    return;\n                }\n                mProgressIndicator.show();\n                viewModel.saveExportedAppList(ListExporter.EXPORT_TYPE_CSV, Paths.get(uri));\n            });\n    private final ActivityResultLauncher<String> mExportAppListJson = registerForActivityResult(\n            new ActivityResultContracts.CreateDocument(\"application/json\"),\n            uri -> {\n                if (uri == null) {\n                    // Back button pressed.\n                    return;\n                }\n                mProgressIndicator.show();\n                viewModel.saveExportedAppList(ListExporter.EXPORT_TYPE_JSON, Paths.get(uri));\n            });\n    private final ActivityResultLauncher<String> mExportAppListXml = registerForActivityResult(\n            new ActivityResultContracts.CreateDocument(\"text/xml\"),\n            uri -> {\n                if (uri == null) {\n                    // Back button pressed.\n                    return;\n                }\n                mProgressIndicator.show();\n                viewModel.saveExportedAppList(ListExporter.EXPORT_TYPE_XML, Paths.get(uri));\n            });\n    private final ActivityResultLauncher<String> mExportAppListMarkdown = registerForActivityResult(\n            new ActivityResultContracts.CreateDocument(\"text/markdown\"),\n            uri -> {\n                if (uri == null) {\n                    // Back button pressed.\n                    return;\n                }\n                mProgressIndicator.show();\n                viewModel.saveExportedAppList(ListExporter.EXPORT_TYPE_MARKDOWN, Paths.get(uri));\n            });\n\n    private final BroadcastReceiver mBatchOpsBroadCastReceiver = new BroadcastReceiver() {\n        @Override\n        public void onReceive(Context context, Intent intent) {\n            showProgressIndicator(false);\n        }\n    };\n\n    private final OnBackPressedCallback mOnBackPressedCallback = new OnBackPressedCallback(false) {\n        @Override\n        public void handleOnBackPressed() {\n            if (mAdapter != null && mMultiSelectionView != null && mAdapter.isInSelectionMode()) {\n                mMultiSelectionView.cancel();\n                return;\n            }\n            setEnabled(false);\n            getOnBackPressedDispatcher().onBackPressed();\n        }\n    };\n\n    @SuppressLint(\"RestrictedApi\")\n    @Override\n    protected void onAuthenticated(Bundle savedInstanceState) {\n        setContentView(R.layout.activity_main);\n        setSupportActionBar(findViewById(R.id.toolbar));\n        getOnBackPressedDispatcher().addCallback(this, mOnBackPressedCallback);\n        viewModel = new ViewModelProvider(this).get(MainViewModel.class);\n        ActionBar actionBar = getSupportActionBar();\n        if (actionBar != null) {\n            actionBar.setDisplayShowCustomEnabled(true);\n            actionBar.setDisplayOptions(0, ActionBar.DISPLAY_SHOW_TITLE);\n            AdvancedSearchView searchView = new AdvancedSearchView(actionBar.getThemedContext());\n            searchView.setId(R.id.action_search);\n            searchView.setOnQueryTextListener(this);\n            // Set layout params\n            ActionBar.LayoutParams layoutParams = new ActionBar.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,\n                    ViewGroup.LayoutParams.WRAP_CONTENT);\n            layoutParams.gravity = Gravity.CENTER;\n            actionBar.setCustomView(searchView, layoutParams);\n            mSearchView = searchView;\n            mSearchView.setIconifiedByDefault(false);\n            mSearchView.setOnFocusChangeListener((v, hasFocus) -> {\n                if (!hasFocus) {\n                    UiUtils.hideKeyboard(v);\n                }\n            });\n            // Check for market://search/?q=<query>\n            Uri marketUri = getIntent().getData();\n            if (marketUri != null && \"market\".equals(marketUri.getScheme()) && \"search\".equals(marketUri.getHost())) {\n                String query = marketUri.getQueryParameter(\"q\");\n                if (query != null) {\n                    mSearchView.setQuery(query, true);\n                }\n            }\n        }\n\n        mProgressIndicator = findViewById(R.id.progress_linear);\n        mProgressIndicator.setVisibilityAfterHide(View.GONE);\n        RecyclerView recyclerView = findViewById(R.id.item_list);\n        recyclerView.requestFocus(); // Initially (the view isn't actually focusable)\n        mSwipeRefresh = findViewById(R.id.swipe_refresh);\n        mSwipeRefresh.setOnRefreshListener(this);\n\n        mAdapter = new MainRecyclerAdapter(MainActivity.this);\n        mAdapter.setHasStableIds(true);\n        recyclerView.setLayoutManager(UIUtils.getGridLayoutAt450Dp(this));\n        recyclerView.setAdapter(mAdapter);\n        mMultiSelectionView = findViewById(R.id.selection_view);\n        mMultiSelectionView.setOnItemSelectedListener(this);\n        mMultiSelectionView.setOnSelectionModeChangeListener(this);\n        mMultiSelectionView.setAdapter(mAdapter);\n        mMultiSelectionView.updateCounter(true);\n        mBatchOpsHandler = new MainBatchOpsHandler(mMultiSelectionView, viewModel);\n        mMultiSelectionView.setOnSelectionChangeListener(mBatchOpsHandler);\n\n        if (SHOW_DISCLAIMER && AppPref.getBoolean(AppPref.PrefKey.PREF_SHOW_DISCLAIMER_BOOL)) {\n            // Disclaimer will only be shown the first time it is loaded.\n            SHOW_DISCLAIMER = false;\n            View view = View.inflate(this, R.layout.dialog_disclaimer, null);\n            new MaterialAlertDialogBuilder(this)\n                    .setView(view)\n                    .setCancelable(false)\n                    .setPositiveButton(R.string.disclaimer_agree, (dialog, which) -> {\n                        if (((MaterialCheckBox) view.findViewById(R.id.agree_forever)).isChecked()) {\n                            AppPref.set(AppPref.PrefKey.PREF_SHOW_DISCLAIMER_BOOL, false);\n                        }\n                        displayChangelogIfRequired();\n                    })\n                    .setNegativeButton(R.string.disclaimer_exit, (dialog, which) -> finishAndRemoveTask())\n                    .show();\n        } else {\n            displayChangelogIfRequired();\n        }\n\n        // Set observer\n        viewModel.getApplicationItems().observe(this, applicationItems -> {\n            if (mAdapter != null) mAdapter.setDefaultList(applicationItems);\n            showProgressIndicator(false);\n        });\n        viewModel.getOperationStatus().observe(this, status -> {\n            mProgressIndicator.hide();\n            if (status) {\n                UIUtils.displayShortToast(R.string.done);\n            } else {\n                UIUtils.displayLongToast(R.string.failed);\n            }\n        });\n    }\n\n    @Override\n    public boolean onCreateOptionsMenu(Menu menu) {\n        getMenuInflater().inflate(R.menu.activity_main_actions, menu);\n        mAppUsageMenu = menu.findItem(R.id.action_app_usage);\n        MenuItem apkUpdaterMenu = menu.findItem(R.id.action_apk_updater);\n        try {\n            if (!getPackageManager().getApplicationInfo(PACKAGE_NAME_APK_UPDATER, 0).enabled)\n                throw new PackageManager.NameNotFoundException();\n            apkUpdaterMenu.setVisible(true);\n        } catch (PackageManager.NameNotFoundException e) {\n            apkUpdaterMenu.setVisible(false);\n        }\n        MenuItem finderMenu = menu.findItem(R.id.action_finder);\n        finderMenu.setVisible(BuildConfig.DEBUG);\n        return super.onCreateOptionsMenu(menu);\n    }\n\n    @Override\n    public boolean onPrepareOptionsMenu(@NonNull Menu menu) {\n        super.onPrepareOptionsMenu(menu);\n        mAppUsageMenu.setVisible(FeatureController.isUsageAccessEnabled());\n        return true;\n    }\n\n    @SuppressLint(\"InflateParams\")\n    @Override\n    public boolean onOptionsItemSelected(@NonNull MenuItem item) {\n        int id = item.getItemId();\n        if (id == R.id.action_instructions) {\n            Intent helpIntent = new Intent(this, HelpActivity.class);\n            helpIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);\n            startActivity(helpIntent);\n        } else if (id == R.id.action_list_options) {\n            MainListOptions listOptions = new MainListOptions();\n            listOptions.setListOptionActions(viewModel);\n            listOptions.show(getSupportFragmentManager(), MainListOptions.TAG);\n        } else if (id == R.id.action_refresh) {\n            if (viewModel != null) {\n                showProgressIndicator(true);\n                viewModel.loadApplicationItems();\n            }\n        } else if (id == R.id.action_settings) {\n            Intent settingsIntent = SettingsActivity.getSettingsIntent(this);\n            startActivity(settingsIntent);\n        } else if (id == R.id.action_app_usage) {\n            Intent usageIntent = new Intent(this, AppUsageActivity.class);\n            startActivity(usageIntent);\n        } else if (id == R.id.action_one_click_ops) {\n            Intent onClickOpsIntent = new Intent(this, OneClickOpsActivity.class);\n            startActivity(onClickOpsIntent);\n        } else if (id == R.id.action_finder) {\n            Intent intent = new Intent(this, FinderActivity.class);\n            startActivity(intent);\n        } else if (id == R.id.action_apk_updater) {\n            try {\n                if (!getPackageManager().getApplicationInfo(PACKAGE_NAME_APK_UPDATER, 0).enabled)\n                    throw new PackageManager.NameNotFoundException();\n                Intent intent = new Intent();\n                intent.setClassName(PACKAGE_NAME_APK_UPDATER, ACTIVITY_NAME_APK_UPDATER);\n                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);\n                startActivity(intent);\n            } catch (Exception ignored) {\n            }\n        } else if (id == R.id.action_running_apps) {\n            Intent runningAppsIntent = new Intent(this, RunningAppsActivity.class);\n            startActivity(runningAppsIntent);\n        } else if (id == R.id.action_profiles) {\n            Intent profilesIntent = new Intent(this, ProfilesActivity.class);\n            startActivity(profilesIntent);\n        } else if (id == R.id.action_labs) {\n            Intent intent = new Intent(getApplicationContext(), LabsActivity.class);\n            intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);\n            startActivity(intent);\n        } else if (id == R.id.action_debloater) {\n            Intent intent = new Intent(getApplicationContext(), DebloaterActivity.class);\n            startActivity(intent);\n        } else return super.onOptionsItemSelected(item);\n        return true;\n    }\n\n    @Override\n    public void onSelectionModeEnabled() {\n        mOnBackPressedCallback.setEnabled(true);\n    }\n\n    @Override\n    public void onSelectionModeDisabled() {\n        mOnBackPressedCallback.setEnabled(false);\n    }\n\n    @Override\n    public boolean onNavigationItemSelected(@NonNull MenuItem item) {\n        int id = item.getItemId();\n        if (id == R.id.action_backup) {\n            if (viewModel != null) {\n                BackupRestoreDialogFragment fragment = BackupRestoreDialogFragment.getInstance(viewModel.getSelectedPackagesWithUsers());\n                fragment.setOnActionBeginListener(mode -> showProgressIndicator(true));\n                fragment.setOnActionCompleteListener((mode, failedPackages) -> showProgressIndicator(false));\n                fragment.show(getSupportFragmentManager(), BackupRestoreDialogFragment.TAG);\n            }\n        } else if (id == R.id.action_save_apk) {\n            mStoragePermission.request(granted -> {\n                if (granted) handleBatchOp(BatchOpsManager.OP_BACKUP_APK);\n            });\n        } else if (id == R.id.action_block_unblock_trackers) {\n            new MaterialAlertDialogBuilder(this)\n                    .setTitle(R.string.block_unblock_trackers)\n                    .setMessage(R.string.choose_what_to_do)\n                    .setPositiveButton(R.string.block, (dialog, which) ->\n                            handleBatchOp(BatchOpsManager.OP_BLOCK_TRACKERS))\n                    .setNegativeButton(R.string.cancel, null)\n                    .setNeutralButton(R.string.unblock, (dialog, which) ->\n                            handleBatchOp(BatchOpsManager.OP_UNBLOCK_TRACKERS))\n                    .show();\n        } else if (id == R.id.action_clear_data_cache) {\n            new MaterialAlertDialogBuilder(this)\n                    .setTitle(R.string.clear)\n                    .setMessage(R.string.choose_what_to_do)\n                    .setPositiveButton(R.string.clear_cache, (dialog, which) ->\n                            handleBatchOp(BatchOpsManager.OP_CLEAR_CACHE))\n                    .setNegativeButton(R.string.cancel, null)\n                    .setNeutralButton(R.string.clear_data, (dialog, which) ->\n                            handleBatchOp(BatchOpsManager.OP_CLEAR_DATA))\n                    .show();\n        } else if (id == R.id.action_freeze_unfreeze) {\n            showFreezeUnfreezeDialog(Prefs.Blocking.getDefaultFreezingMethod());\n        } else if (id == R.id.action_disable_background) {\n            new MaterialAlertDialogBuilder(this)\n                    .setTitle(R.string.are_you_sure)\n                    .setMessage(R.string.disable_background_run_description)\n                    .setPositiveButton(R.string.yes, (dialog, which) ->\n                            handleBatchOp(BatchOpsManager.OP_DISABLE_BACKGROUND))\n                    .setNegativeButton(R.string.no, null)\n                    .show();\n        } else if (id == R.id.action_net_policy) {\n            ArrayMap<Integer, String> netPolicyMap = NetworkPolicyManagerCompat.getAllReadablePolicies(this);\n            Integer[] polices = new Integer[netPolicyMap.size()];\n            String[] policyStrings = new String[netPolicyMap.size()];\n            Collection<ApplicationItem> applicationItems = viewModel.getSelectedPackages().values();\n            Iterator<ApplicationItem> it = applicationItems.iterator();\n            int selectedPolicies = applicationItems.size() == 1 && it.hasNext() ?\n                    NetworkPolicyManagerCompat.getUidPolicy(it.next().uid) : 0;\n            for (int i = 0; i < netPolicyMap.size(); ++i) {\n                polices[i] = netPolicyMap.keyAt(i);\n                policyStrings[i] = netPolicyMap.valueAt(i);\n            }\n            new SearchableFlagsDialogBuilder<>(this, polices, policyStrings, selectedPolicies)\n                    .setTitle(R.string.net_policy)\n                    .showSelectAll(false)\n                    .setNegativeButton(R.string.cancel, null)\n                    .setPositiveButton(R.string.apply, (dialog, which, selections) -> {\n                        int flags = 0;\n                        for (int flag : selections) {\n                            flags |= flag;\n                        }\n                        BatchNetPolicyOptions options = new BatchNetPolicyOptions(flags);\n                        handleBatchOp(BatchOpsManager.OP_NET_POLICY, options);\n                    })\n                    .show();\n        } else if (id == R.id.action_optimize) {\n            DexOptDialog dialog = DexOptDialog.getInstance(viewModel.getSelectedPackages().keySet().toArray(new String[0]));\n            dialog.show(getSupportFragmentManager(), DexOptDialog.TAG);\n        } else if (id == R.id.action_export_blocking_rules) {\n            final String fileName = \"app_manager_rules_export-\" + DateUtils.formatDateTime(this, System.currentTimeMillis()) + \".am.tsv\";\n            mBatchExportRules.launch(fileName);\n        } else if (id == R.id.action_export_app_list) {\n            List<Integer> exportTypes = Arrays.asList(ListExporter.EXPORT_TYPE_CSV,\n                    ListExporter.EXPORT_TYPE_JSON,\n                    ListExporter.EXPORT_TYPE_XML,\n                    ListExporter.EXPORT_TYPE_MARKDOWN);\n            new SearchableSingleChoiceDialogBuilder<>(this, exportTypes, R.array.export_app_list_options)\n                    .setTitle(R.string.export_app_list_select_format)\n                    .setOnSingleChoiceClickListener((dialog, which, item1, isChecked) -> {\n                        if (!isChecked) {\n                            return;\n                        }\n                        String filename = \"app_manager_app_list-\" + DateUtils.formatLongDateTime(this, System.currentTimeMillis()) + \".am\";\n                        switch (item1) {\n                            case ListExporter.EXPORT_TYPE_CSV:\n                                mExportAppListCsv.launch(filename + \".csv\");\n                                break;\n                            case ListExporter.EXPORT_TYPE_JSON:\n                                mExportAppListJson.launch(filename + \".json\");\n                                break;\n                            case ListExporter.EXPORT_TYPE_XML:\n                                mExportAppListXml.launch(filename + \".xml\");\n                                break;\n                            case ListExporter.EXPORT_TYPE_MARKDOWN:\n                                mExportAppListMarkdown.launch(filename + \".md\");\n                                break;\n                        }\n                    })\n                    .setNegativeButton(R.string.close, null)\n                    .show();\n        } else if (id == R.id.action_force_stop) {\n            handleBatchOp(BatchOpsManager.OP_FORCE_STOP);\n        } else if (id == R.id.action_uninstall) {\n            handleBatchOpWithWarning(BatchOpsManager.OP_UNINSTALL);\n        } else if (id == R.id.action_add_to_profile) {\n            AddToProfileDialogFragment dialog = AddToProfileDialogFragment.getInstance(viewModel.getSelectedPackages()\n                    .keySet().toArray(new String[0]));\n            dialog.show(getSupportFragmentManager(), AddToProfileDialogFragment.TAG);\n        } else {\n            return false;\n        }\n        return true;\n    }\n\n    @Override\n    public void onRefresh() {\n        showProgressIndicator(true);\n        if (viewModel != null) viewModel.loadApplicationItems();\n        mSwipeRefresh.setRefreshing(false);\n    }\n\n    @Override\n    protected void onStart() {\n        super.onStart();\n\n        // Set filter\n        if (viewModel != null && mSearchView != null && !TextUtils.isEmpty(viewModel.getSearchQuery())) {\n            if (mSearchView.isIconified()) {\n                mSearchView.setIconified(false);\n            }\n            mSearchView.setQuery(viewModel.getSearchQuery(), false);\n        }\n        // Show/hide app usage menu\n        if (mAppUsageMenu != null) {\n            mAppUsageMenu.setVisible(FeatureController.isUsageAccessEnabled());\n        }\n        // Check for backup volume\n        if (!Prefs.BackupRestore.backupDirectoryExists()) {\n            new MaterialAlertDialogBuilder(this)\n                    .setTitle(R.string.backup_volume)\n                    .setMessage(R.string.backup_volume_unavailable_warning)\n                    .setPositiveButton(R.string.close, null)\n                    .setNeutralButton(R.string.change_backup_volume, (dialog, which) -> {\n                        Intent intent = SettingsActivity.getSettingsIntent(this, \"backup_restore_prefs\", \"backup_volume\");\n                        startActivity(intent);\n                    })\n                    .show();\n        }\n    }\n\n    @Override\n    protected void onResume() {\n        super.onResume();\n        if (viewModel != null) viewModel.onResume();\n        if (mAdapter != null && mBatchOpsHandler != null && mAdapter.isInSelectionMode()) {\n            mBatchOpsHandler.updateConstraints();\n            mMultiSelectionView.updateCounter(false);\n        }\n        ContextCompat.registerReceiver(this, mBatchOpsBroadCastReceiver,\n                new IntentFilter(BatchOpsService.ACTION_BATCH_OPS_COMPLETED), ContextCompat.RECEIVER_NOT_EXPORTED);\n    }\n\n    @Override\n    protected void onPause() {\n        super.onPause();\n        unregisterReceiver(mBatchOpsBroadCastReceiver);\n    }\n\n    private void displayChangelogIfRequired() {\n        if (!AppPref.getBoolean(AppPref.PrefKey.PREF_DISPLAY_CHANGELOG_BOOL)) {\n            return;\n        }\n        if (FundingCampaignChecker.campaignRunning()) {\n            new ScrollableDialogBuilder(this)\n                    .setMessage(R.string.funding_campaign_dialog_message)\n                    .enableAnchors()\n                    .show();\n        }\n        Snackbar.make(findViewById(android.R.id.content), R.string.view_changelog, 3 * 60 * 1000)\n                .setAction(R.string.ok, v -> {\n                    long lastVersion = AppPref.getLong(AppPref.PrefKey.PREF_DISPLAY_CHANGELOG_LAST_VERSION_LONG);\n                    AppPref.set(AppPref.PrefKey.PREF_DISPLAY_CHANGELOG_BOOL, false);\n                    AppPref.set(AppPref.PrefKey.PREF_DISPLAY_CHANGELOG_LAST_VERSION_LONG, (long) BuildConfig.VERSION_CODE);\n                    viewModel.executor.submit(() -> {\n                        Changelog changelog;\n                        try {\n                            changelog = new ChangelogParser(getApplication(), R.raw.changelog, lastVersion).parse();\n                        } catch (IOException | XmlPullParserException e) {\n                            return;\n                        }\n                        runOnUiThread(() -> {\n                            View view = View.inflate(this, R.layout.dialog_whats_new, null);\n                            RecyclerView recyclerView = view.findViewById(android.R.id.list);\n                            recyclerView.setLayoutManager(new LinearLayoutManager(recyclerView.getContext()));\n                            ChangelogRecyclerAdapter adapter = new ChangelogRecyclerAdapter();\n                            recyclerView.setAdapter(adapter);\n                            adapter.setAdapterList(changelog.getChangelogItems());\n                            new AlertDialogBuilder(this, true)\n                                    .setTitle(R.string.changelog)\n                                    .setView(recyclerView)\n                                    .show();\n                        });\n                    });\n                }).show();\n    }\n\n    private void showFreezeUnfreezeDialog(int freezeType) {\n        View view = View.inflate(this, R.layout.item_checkbox, null);\n        MaterialCheckBox checkBox = view.findViewById(R.id.checkbox);\n        checkBox.setText(R.string.freeze_prefer_per_app_option);\n        FreezeUnfreeze.getFreezeDialog(this, freezeType)\n                .setIcon(R.drawable.ic_snowflake)\n                .setTitle(R.string.freeze_unfreeze)\n                .setView(view)\n                .setPositiveButton(R.string.freeze, (dialog, which, selectedItem) -> {\n                    if (selectedItem == null) {\n                        return;\n                    }\n                    BatchFreezeOptions options = new BatchFreezeOptions(selectedItem, checkBox.isChecked());\n                    handleBatchOp(BatchOpsManager.OP_ADVANCED_FREEZE, options);\n                })\n                .setNegativeButton(R.string.cancel, null)\n                .setNeutralButton(R.string.unfreeze, (dialog, which, selectedItem) ->\n                        handleBatchOp(BatchOpsManager.OP_UNFREEZE))\n                .show();\n    }\n\n    private void handleBatchOp(@BatchOpsManager.OpType int op) {\n        handleBatchOp(op, null);\n    }\n\n    private void handleBatchOp(@BatchOpsManager.OpType int op, @Nullable IBatchOpOptions options) {\n        if (viewModel == null) return;\n        showProgressIndicator(true);\n        BatchOpsManager.Result input = new BatchOpsManager.Result(viewModel.getSelectedPackagesWithUsers());\n        BatchQueueItem item = BatchQueueItem.getBatchOpQueue(op, input.getFailedPackages(), input.getAssociatedUsers(), options);\n        Intent intent = BatchOpsService.getServiceIntent(this, item);\n        ContextCompat.startForegroundService(this, intent);\n    }\n\n    private void handleBatchOpWithWarning(@BatchOpsManager.OpType int op) {\n        new MaterialAlertDialogBuilder(this)\n                .setTitle(R.string.are_you_sure)\n                .setMessage(R.string.this_action_cannot_be_undone)\n                .setPositiveButton(R.string.yes, (dialog, which) -> handleBatchOp(op))\n                .setNegativeButton(R.string.no, null)\n                .show();\n    }\n\n    void showProgressIndicator(boolean show) {\n        if (show) mProgressIndicator.show();\n        else mProgressIndicator.hide();\n    }\n\n    @Override\n    public boolean onQueryTextChange(String searchQuery, @AdvancedSearchView.SearchType int type) {\n        if (viewModel != null) viewModel.setSearchQuery(searchQuery, type);\n        return true;\n    }\n\n    @Override\n    public boolean onQueryTextSubmit(String query, int type) {\n        return false;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/main/MainBatchOpsHandler.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.main;\n\nimport android.Manifest;\nimport android.content.pm.ApplicationInfo;\nimport android.os.Build;\nimport android.view.Menu;\nimport android.view.MenuItem;\n\nimport java.util.Collection;\n\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.compat.ManifestCompat;\nimport io.github.muntashirakon.AppManager.self.SelfPermissions;\nimport io.github.muntashirakon.widget.MultiSelectionView;\n\npublic class MainBatchOpsHandler implements MultiSelectionView.OnSelectionChangeListener {\n    private final MainViewModel mViewModel;\n    private final MenuItem mUninstallMenu;\n    private final MenuItem mFreezeUnfreezeMenu;\n    private final MenuItem mForceStopMenu;\n    private final MenuItem mClearDataCacheMenu;\n    private final MenuItem mSaveApkMenu;\n    private final MenuItem mBackupRestoreMenu;\n    private final MenuItem mPreventBackgroundMenu;\n    private final MenuItem mBlockUnblockTrackersMenu;\n    private final MenuItem mNetPolicyMenu;\n    private final MenuItem mExportRulesMenu;\n    private final MenuItem mExportAppListMenu;\n    private final MenuItem mOptimizeMenu;\n    private final MenuItem mAddToProfileMenu;\n\n    private boolean mCanFreezeUnfreezePackages;\n    private boolean mCanForceStopPackages;\n    private boolean mCanClearData;\n    private boolean mCanClearCache;\n    private boolean mCanModifyAppOpMode;\n    private boolean mCanModifyNetPolicy;\n    private boolean mCanModifyComponentState;\n\n    public MainBatchOpsHandler(MultiSelectionView multiSelectionView, MainViewModel viewModel) {\n        Menu selectionMenu = multiSelectionView.getMenu();\n        mViewModel = viewModel;\n        mUninstallMenu = selectionMenu.findItem(R.id.action_uninstall);\n        mFreezeUnfreezeMenu = selectionMenu.findItem(R.id.action_freeze_unfreeze);\n        mForceStopMenu = selectionMenu.findItem(R.id.action_force_stop);\n        mClearDataCacheMenu = selectionMenu.findItem(R.id.action_clear_data_cache);\n        mSaveApkMenu = selectionMenu.findItem(R.id.action_save_apk);\n        mBackupRestoreMenu = selectionMenu.findItem(R.id.action_backup);\n        mPreventBackgroundMenu = selectionMenu.findItem(R.id.action_disable_background);\n        mBlockUnblockTrackersMenu = selectionMenu.findItem(R.id.action_block_unblock_trackers);\n        mNetPolicyMenu = selectionMenu.findItem(R.id.action_net_policy);\n        mExportRulesMenu = selectionMenu.findItem(R.id.action_export_blocking_rules);\n        mExportAppListMenu = selectionMenu.findItem(R.id.action_export_app_list);\n        mOptimizeMenu = selectionMenu.findItem(R.id.action_optimize);\n        mAddToProfileMenu = selectionMenu.findItem(R.id.action_add_to_profile);\n        updateConstraints();\n    }\n\n    public void updateConstraints() {\n        mCanFreezeUnfreezePackages = SelfPermissions.canFreezeUnfreezePackages();\n        mCanForceStopPackages = SelfPermissions.checkSelfOrRemotePermission(ManifestCompat.permission.FORCE_STOP_PACKAGES);\n        mCanClearData = SelfPermissions.checkSelfOrRemotePermission(ManifestCompat.permission.CLEAR_APP_USER_DATA);\n        mCanClearCache = SelfPermissions.canClearAppCache();\n        mCanModifyAppOpMode = SelfPermissions.canModifyAppOpMode();\n        mCanModifyNetPolicy = SelfPermissions.checkSelfOrRemotePermission(ManifestCompat.permission.MANAGE_NETWORK_POLICY);\n        mCanModifyComponentState = SelfPermissions.checkSelfOrRemotePermission(Manifest.permission.CHANGE_COMPONENT_ENABLED_STATE);\n    }\n\n    @Override\n    public boolean onSelectionChange(int selectionCount) {\n        Collection<ApplicationItem> selectedItems = mViewModel.getSelectedApplicationItems();\n        boolean nonZeroSelection = !selectedItems.isEmpty();\n        // It was ensured that the algorithm is greedy\n        // Best case: O(1)\n        // Worst case: O(n)\n        boolean areAllInstalled = true;\n        boolean areAllUninstalledWithoutData = true;\n        boolean areAllUninstalledSystem = true;\n        boolean doAllUninstalledhaveBackup = true;\n        for (ApplicationItem item : selectedItems) {\n            if (item.isInstalled) continue;\n            areAllInstalled = false;\n            if (areAllUninstalledWithoutData) {\n                areAllUninstalledWithoutData = item.isOnlyDataInstalled;\n            }\n            if (!doAllUninstalledhaveBackup && !areAllUninstalledSystem) {\n                // No need to check further\n                break;\n            }\n            if (areAllUninstalledSystem && item.isUser) {\n                areAllUninstalledSystem = false;\n            }\n            if (doAllUninstalledhaveBackup && item.backup == null) {\n                doAllUninstalledhaveBackup = false;\n            }\n        }\n        /* === Enable/Disable === */\n        // Enable “Uninstall” action iff all selections are installed\n        mUninstallMenu.setEnabled(nonZeroSelection && (areAllInstalled || areAllUninstalledWithoutData));\n        mFreezeUnfreezeMenu.setEnabled(nonZeroSelection && areAllInstalled);\n        mForceStopMenu.setEnabled(nonZeroSelection && areAllInstalled);\n        mClearDataCacheMenu.setEnabled(nonZeroSelection && areAllInstalled);\n        mPreventBackgroundMenu.setEnabled(nonZeroSelection && areAllInstalled);\n        mNetPolicyMenu.setEnabled(nonZeroSelection && areAllInstalled);\n        mBlockUnblockTrackersMenu.setEnabled(nonZeroSelection && areAllInstalled);\n        // Enable “Save APK” action iff all selections are installed or the uninstalled apps are all system apps\n        mSaveApkMenu.setEnabled(nonZeroSelection && (areAllInstalled || areAllUninstalledSystem));\n        // Enable “Backup/restore” action iff all selections are installed or all the uninstalled apps have backups\n        mBackupRestoreMenu.setEnabled(nonZeroSelection && (areAllInstalled || doAllUninstalledhaveBackup));\n        // Rests are enabled by default\n        mExportRulesMenu.setEnabled(nonZeroSelection);\n        mExportAppListMenu.setEnabled(nonZeroSelection);\n        mOptimizeMenu.setEnabled(nonZeroSelection);\n        mAddToProfileMenu.setEnabled(nonZeroSelection);\n        /* === Visible/Invisible === */\n        mFreezeUnfreezeMenu.setVisible(mCanFreezeUnfreezePackages);\n        mForceStopMenu.setVisible(mCanForceStopPackages);\n        mClearDataCacheMenu.setVisible(mCanClearData || mCanClearCache);\n        mPreventBackgroundMenu.setVisible(mCanModifyAppOpMode && Build.VERSION.SDK_INT >= Build.VERSION_CODES.N);\n        mNetPolicyMenu.setVisible(mCanModifyNetPolicy);\n        mBlockUnblockTrackersMenu.setVisible(mCanModifyComponentState);\n        mOptimizeMenu.setVisible(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N);\n        return true;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/main/MainListOptions.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.main;\n\nimport android.os.Bundle;\nimport android.text.TextUtils;\nimport android.view.View;\n\nimport androidx.annotation.IntDef;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.util.ArrayList;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.concurrent.Future;\n\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.filters.FilterItem;\nimport io.github.muntashirakon.AppManager.filters.options.AppTypeOption;\nimport io.github.muntashirakon.AppManager.filters.options.BackupOption;\nimport io.github.muntashirakon.AppManager.filters.options.ComponentsOption;\nimport io.github.muntashirakon.AppManager.filters.options.FreezeOption;\nimport io.github.muntashirakon.AppManager.filters.options.InstalledOption;\nimport io.github.muntashirakon.AppManager.filters.options.RunningAppsOption;\nimport io.github.muntashirakon.AppManager.misc.ListOptions;\nimport io.github.muntashirakon.AppManager.profiles.ProfileManager;\nimport io.github.muntashirakon.AppManager.settings.FeatureController;\nimport io.github.muntashirakon.AppManager.settings.Ops;\nimport io.github.muntashirakon.AppManager.users.UserInfo;\nimport io.github.muntashirakon.AppManager.users.Users;\nimport io.github.muntashirakon.AppManager.utils.ArrayUtils;\nimport io.github.muntashirakon.AppManager.utils.ThreadUtils;\nimport io.github.muntashirakon.adapters.SelectedArrayAdapter;\nimport io.github.muntashirakon.dialog.SearchableMultiChoiceDialogBuilder;\n\npublic class MainListOptions extends ListOptions {\n    public static final String TAG = MainListOptions.class.getSimpleName();\n\n    @IntDef(value = {\n            SORT_BY_DOMAIN,\n            SORT_BY_APP_LABEL,\n            SORT_BY_PACKAGE_NAME,\n            SORT_BY_LAST_UPDATE,\n            SORT_BY_SHARED_ID,\n            SORT_BY_TARGET_SDK,\n            SORT_BY_SHA,\n            SORT_BY_FROZEN_APP,\n            SORT_BY_BLOCKED_COMPONENTS,\n            SORT_BY_BACKUP,\n            SORT_BY_TRACKERS,\n            SORT_BY_LAST_ACTION,\n            SORT_BY_INSTALLATION_DATE,\n            SORT_BY_TOTAL_SIZE,\n            SORT_BY_DATA_USAGE,\n            SORT_BY_OPEN_COUNT,\n            SORT_BY_SCREEN_TIME,\n            SORT_BY_LAST_USAGE_TIME,\n    })\n    @Retention(RetentionPolicy.SOURCE)\n    public @interface SortOrder {\n    }\n\n    public static final int SORT_BY_DOMAIN = 0;  // User/system app\n    public static final int SORT_BY_APP_LABEL = 1;\n    public static final int SORT_BY_PACKAGE_NAME = 2;\n    public static final int SORT_BY_LAST_UPDATE = 3;\n    public static final int SORT_BY_SHARED_ID = 4;\n    public static final int SORT_BY_TARGET_SDK = 5;\n    public static final int SORT_BY_SHA = 6;  // Signature\n    public static final int SORT_BY_FROZEN_APP = 7;\n    public static final int SORT_BY_BLOCKED_COMPONENTS = 8;\n    public static final int SORT_BY_BACKUP = 9;\n    public static final int SORT_BY_TRACKERS = 10;\n    public static final int SORT_BY_LAST_ACTION = 11;\n    public static final int SORT_BY_INSTALLATION_DATE = 12;\n    public static final int SORT_BY_TOTAL_SIZE = 13;\n    public static final int SORT_BY_DATA_USAGE = 14;\n    public static final int SORT_BY_OPEN_COUNT = 15;\n    public static final int SORT_BY_SCREEN_TIME = 16;\n    public static final int SORT_BY_LAST_USAGE_TIME = 17;\n\n    @IntDef(flag = true, value = {\n            FILTER_NO_FILTER,\n            FILTER_USER_APPS,\n            FILTER_SYSTEM_APPS,\n            FILTER_FROZEN_APPS,\n            FILTER_UNFROZEN_APPS,\n            FILTER_APPS_WITH_RULES,\n            FILTER_APPS_WITH_ACTIVITIES,\n            FILTER_APPS_WITH_BACKUPS,\n            FILTER_RUNNING_APPS,\n            FILTER_APPS_WITH_SPLITS,\n            FILTER_INSTALLED_APPS,\n            FILTER_UNINSTALLED_APPS,\n            FILTER_APPS_WITHOUT_BACKUPS,\n            FILTER_APPS_WITH_KEYSTORE,\n            FILTER_APPS_WITH_SAF,\n            FILTER_APPS_WITH_SSAID,\n            FILTER_STOPPED_APPS,\n    })\n    @Retention(RetentionPolicy.SOURCE)\n    public @interface Filter {\n    }\n\n    public static final int FILTER_NO_FILTER = 0;\n    public static final int FILTER_USER_APPS = 1;\n    public static final int FILTER_SYSTEM_APPS = 1 << 1;\n    public static final int FILTER_FROZEN_APPS = 1 << 2;\n    public static final int FILTER_APPS_WITH_RULES = 1 << 3;\n    public static final int FILTER_APPS_WITH_ACTIVITIES = 1 << 4;\n    public static final int FILTER_APPS_WITH_BACKUPS = 1 << 5;\n    public static final int FILTER_RUNNING_APPS = 1 << 6;\n    public static final int FILTER_APPS_WITH_SPLITS = 1 << 7;\n    public static final int FILTER_INSTALLED_APPS = 1 << 8;\n    public static final int FILTER_UNINSTALLED_APPS = 1 << 9;\n    public static final int FILTER_APPS_WITHOUT_BACKUPS = 1 << 10;\n    public static final int FILTER_APPS_WITH_KEYSTORE = 1 << 11;\n    public static final int FILTER_APPS_WITH_SAF = 1 << 12;\n    public static final int FILTER_APPS_WITH_SSAID = 1 << 13;\n    public static final int FILTER_STOPPED_APPS = 1 << 14;\n    public static final int FILTER_UNFROZEN_APPS = 1 << 15;\n\n    // For now, just generate FilterItem\n    @NonNull\n    public static FilterItem getFilterItemFromFlags(int flags) {\n        FilterItem filterItem = new FilterItem();\n        // Flags\n        int appTypeWithFlags = 0;\n        if ((flags & FILTER_USER_APPS) != 0) {\n            appTypeWithFlags |= AppTypeOption.APP_TYPE_USER;\n        }\n        if ((flags & FILTER_SYSTEM_APPS) != 0) {\n            appTypeWithFlags |= AppTypeOption.APP_TYPE_SYSTEM;\n        }\n        if ((flags & FILTER_FROZEN_APPS) != 0) {\n            FreezeOption option = new FreezeOption();\n            option.setKeyValue(\"frozen\", null);\n            filterItem.addFilterOption(option);\n        }\n        if ((flags & FILTER_UNFROZEN_APPS) != 0) {\n            FreezeOption option = new FreezeOption();\n            option.setKeyValue(\"unfrozen\", null);\n            filterItem.addFilterOption(option);\n        }\n        if ((flags & FILTER_APPS_WITH_RULES) != 0) {\n            appTypeWithFlags |= AppTypeOption.APP_TYPE_WITH_RULES;\n        }\n        if ((flags & FILTER_APPS_WITH_ACTIVITIES) != 0) {\n            ComponentsOption option = new ComponentsOption();\n            option.setKeyValue(\"with_type\", String.valueOf(ComponentsOption.COMPONENT_TYPE_ACTIVITY));\n            filterItem.addFilterOption(option);\n        }\n        if ((flags & FILTER_APPS_WITH_BACKUPS) != 0) {\n            BackupOption option = new BackupOption();\n            option.setKeyValue(\"backups\", null);\n            filterItem.addFilterOption(option);\n        }\n        if ((flags & FILTER_RUNNING_APPS) != 0) {\n            RunningAppsOption option = new RunningAppsOption();\n            option.setKeyValue(\"running\", null);\n            filterItem.addFilterOption(option);\n        }\n        if ((flags & FILTER_APPS_WITH_SPLITS) != 0) {\n            // TODO: 7/28/25\n        }\n        if ((flags & FILTER_INSTALLED_APPS) != 0) {\n            InstalledOption option = new InstalledOption();\n            option.setKeyValue(\"installed\", null);\n            filterItem.addFilterOption(option);\n        }\n        if ((flags & FILTER_UNINSTALLED_APPS) != 0) {\n            InstalledOption option = new InstalledOption();\n            option.setKeyValue(\"uninstalled\", null);\n            filterItem.addFilterOption(option);\n        }\n        if ((flags & FILTER_APPS_WITHOUT_BACKUPS) != 0) {\n            BackupOption option = new BackupOption();\n            option.setKeyValue(\"no_backups\", null);\n            filterItem.addFilterOption(option);\n        }\n        if ((flags & FILTER_APPS_WITH_KEYSTORE) != 0) {\n            appTypeWithFlags |= AppTypeOption.APP_TYPE_KEYSTORE;\n        }\n        if ((flags & FILTER_APPS_WITH_SAF) != 0) {\n            // TODO: 7/28/25\n        }\n        if ((flags & FILTER_APPS_WITH_SSAID) != 0) {\n            appTypeWithFlags |= AppTypeOption.APP_TYPE_SSAID;\n        }\n        if ((flags & FILTER_STOPPED_APPS) != 0) {\n            appTypeWithFlags |= AppTypeOption.APP_TYPE_STOPPED;\n        }\n        if (appTypeWithFlags > 0) {\n            AppTypeOption appTypeWithFlagsOption = new AppTypeOption();\n            appTypeWithFlagsOption.setKeyValue(\"with_flags\", String.valueOf(appTypeWithFlags));\n            filterItem.addFilterOption(appTypeWithFlagsOption);\n        }\n        return filterItem;\n    }\n\n    private final List<String> mProfileNames = new ArrayList<>();\n    private Future<?> mProfileSuggestionsResult;\n    @Nullable\n    private SelectedArrayAdapter<String> mAdapter;\n\n    @Override\n    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {\n        super.onViewCreated(view, savedInstanceState);\n        MainActivity activity = (MainActivity) requireActivity();\n        profileNameSpinner.setOnItemClickListener((parent, view1, position, id) -> {\n            if (mAdapter == null || activity.viewModel == null) {\n                return;\n            }\n            if (position == 0) {\n                // No profiles\n                activity.viewModel.setFilterProfileName(null);\n            } else {\n                activity.viewModel.setFilterProfileName(mAdapter.getItem(position));\n            }\n        });\n        mProfileSuggestionsResult = ThreadUtils.postOnBackgroundThread(() -> {\n            mProfileNames.clear();\n            mProfileNames.add(getString(R.string.no_profiles));\n            mProfileNames.addAll(ProfileManager.getProfileNames());\n            mAdapter = new SelectedArrayAdapter<>(activity,\n                    io.github.muntashirakon.ui.R.layout.auto_complete_dropdown_item_small,\n                    mProfileNames);\n            if (isDetached() || ThreadUtils.isInterrupted()) return;\n            activity.runOnUiThread(() -> {\n                profileNameSpinner.setAdapter(mAdapter);\n                if (activity.viewModel != null) {\n                    String selectedProfile = activity.viewModel.getFilterProfileName();\n                    if (TextUtils.isEmpty(selectedProfile)) {\n                        profileNameSpinner.setSelection(0);\n                    } else {\n                        int i = mProfileNames.indexOf(selectedProfile);\n                        if (i < 0) {\n                           i = 0;\n                        }\n                        profileNameSpinner.setSelection(i);\n                    }\n                }\n            });\n        });\n        selectUserView.setVisibility(Users.getUsersIds().length <= 1 ? View.GONE : View.VISIBLE);\n        selectUserView.setOnClickListener(v -> {\n            List<UserInfo> userInfoList = Users.getUsers();\n            List<Integer> userIdList = new ArrayList<>(userInfoList.size());\n            CharSequence[] userInfoReadable = new CharSequence[userInfoList.size()];\n            int i = 0;\n            for (UserInfo userInfo : userInfoList) {\n                userInfoReadable[i] = userInfo.toLocalizedString(requireContext());\n                userIdList.add(userInfo.id);\n                ++i;\n            }\n            List<Integer> selections;\n            if (activity.viewModel != null) {\n                int[] selectedUsers = activity.viewModel.getSelectedUsers();\n                if (selectedUsers != null) {\n                    selections = new ArrayList<>();\n                    for (int userId : selectedUsers) {\n                        selections.add(userId);\n                    }\n                } else selections = userIdList;\n            } else selections = userIdList;\n            new SearchableMultiChoiceDialogBuilder<>(requireContext(), userIdList, userInfoReadable)\n                    .setTitle(R.string.filter)\n                    .setNegativeButton(R.string.close, null)\n                    .addSelections(selections)\n                    .showSelectAll(true)\n                    .hideSearchBar(true)\n                    .setPositiveButton(R.string.filter, (dialog, which, selectedItems) -> {\n                        if (activity.viewModel != null) {\n                            if (selectedItems.size() == userInfoList.size()) {\n                                // All users\n                                activity.viewModel.setSelectedUsers(null);\n                            } else {\n                                activity.viewModel.setSelectedUsers(ArrayUtils.convertToIntArray(selectedItems));\n                            }\n                        }\n                    })\n                    .show();\n        });\n    }\n\n    @Override\n    public void onDestroy() {\n        if (mProfileSuggestionsResult != null) {\n            mProfileSuggestionsResult.cancel(true);\n        }\n        super.onDestroy();\n    }\n\n    @Nullable\n    @Override\n    public LinkedHashMap<Integer, Integer> getSortIdLocaleMap() {\n        return new LinkedHashMap<Integer, Integer>() {{\n            put(SORT_BY_DOMAIN, R.string.sort_by_domain);\n            put(SORT_BY_APP_LABEL, R.string.sort_by_app_label);\n            put(SORT_BY_PACKAGE_NAME, R.string.sort_by_package_name);\n            put(SORT_BY_LAST_UPDATE, R.string.sort_by_last_update);\n            put(SORT_BY_SHARED_ID, R.string.sort_by_shared_user_id);\n            put(SORT_BY_TARGET_SDK, R.string.sort_by_target_sdk);\n            put(SORT_BY_SHA, R.string.sort_by_sha);\n            put(SORT_BY_FROZEN_APP, R.string.sort_by_frozen_app);\n            put(SORT_BY_BLOCKED_COMPONENTS, R.string.sort_by_blocked_components);\n            put(SORT_BY_BACKUP, R.string.sort_by_backup);\n            put(SORT_BY_TRACKERS, R.string.trackers);\n            put(SORT_BY_LAST_ACTION, R.string.last_actions);\n            put(SORT_BY_INSTALLATION_DATE, R.string.sort_by_installation_date);\n            if (FeatureController.isUsageAccessEnabled()) {\n                put(SORT_BY_TOTAL_SIZE, R.string.sort_by_total_size);\n                put(SORT_BY_DATA_USAGE, R.string.sort_by_data_usage);\n                put(SORT_BY_OPEN_COUNT, R.string.sort_by_times_opened);\n                put(SORT_BY_SCREEN_TIME, R.string.sort_by_screen_time);\n                put(SORT_BY_LAST_USAGE_TIME, R.string.sort_by_last_used);\n            }\n        }};\n    }\n\n    @Nullable\n    @Override\n    public LinkedHashMap<Integer, Integer> getFilterFlagLocaleMap() {\n        return new LinkedHashMap<Integer, Integer>() {{\n            put(FILTER_USER_APPS, R.string.filter_user_apps);\n            put(FILTER_SYSTEM_APPS, R.string.filter_system_apps);\n            put(FILTER_FROZEN_APPS, R.string.filter_frozen_apps);\n            put(FILTER_UNFROZEN_APPS, R.string.filter_unfrozen_apps);\n            put(FILTER_STOPPED_APPS, R.string.filter_force_stopped_apps);\n            put(FILTER_INSTALLED_APPS, R.string.installed_apps);\n            put(FILTER_UNINSTALLED_APPS, R.string.uninstalled_apps);\n            put(FILTER_APPS_WITH_RULES, R.string.filter_apps_with_rules);\n            put(FILTER_APPS_WITH_ACTIVITIES, R.string.filter_apps_with_activities);\n            put(FILTER_APPS_WITH_BACKUPS, R.string.filter_apps_with_backups);\n            put(FILTER_APPS_WITHOUT_BACKUPS, R.string.filter_apps_without_backups);\n            put(FILTER_RUNNING_APPS, R.string.filter_running_apps);\n            put(FILTER_APPS_WITH_SPLITS, R.string.filter_apps_with_splits);\n            if (Ops.isWorkingUidRoot()) {\n                put(FILTER_APPS_WITH_KEYSTORE, R.string.filter_apps_with_keystore);\n                put(FILTER_APPS_WITH_SAF, R.string.filter_apps_with_saf);\n                put(FILTER_APPS_WITH_SSAID, R.string.filter_apps_with_ssaid);\n            }\n        }};\n    }\n\n    @Nullable\n    @Override\n    public LinkedHashMap<Integer, Integer> getOptionIdLocaleMap() {\n        return null;\n    }\n\n    @Override\n    public boolean enableProfileNameInput() {\n        return true;\n    }\n\n    @Override\n    public boolean enableSelectUser() {\n        return true;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/main/MainRecyclerAdapter.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.main;\n\nimport static io.github.muntashirakon.AppManager.compat.PackageManagerCompat.MATCH_UNINSTALLED_PACKAGES;\nimport static io.github.muntashirakon.AppManager.utils.UIUtils.displayLongToast;\nimport static io.github.muntashirakon.AppManager.utils.UIUtils.displayShortToast;\n\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.pm.ApplicationInfo;\nimport android.content.pm.PackageManager;\nimport android.graphics.Color;\nimport android.net.Uri;\nimport android.os.RemoteException;\nimport android.os.UserHandleHidden;\nimport android.text.Spannable;\nimport android.text.SpannableString;\nimport android.text.TextUtils;\nimport android.text.style.RelativeSizeSpan;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.SectionIndexer;\nimport android.widget.TextView;\n\nimport androidx.annotation.GuardedBy;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.UiThread;\nimport androidx.appcompat.widget.AppCompatImageView;\nimport androidx.core.content.ContextCompat;\n\nimport com.google.android.material.card.MaterialCardView;\nimport com.google.android.material.dialog.MaterialAlertDialogBuilder;\n\nimport java.io.File;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Locale;\n\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.apk.installer.PackageInstallerActivity;\nimport io.github.muntashirakon.AppManager.apk.installer.PackageInstallerCompat;\nimport io.github.muntashirakon.AppManager.backup.dialog.BackupRestoreDialogFragment;\nimport io.github.muntashirakon.AppManager.compat.ApplicationInfoCompat;\nimport io.github.muntashirakon.AppManager.compat.PackageManagerCompat;\nimport io.github.muntashirakon.AppManager.db.entity.Backup;\nimport io.github.muntashirakon.AppManager.details.AppDetailsActivity;\nimport io.github.muntashirakon.AppManager.self.SelfPermissions;\nimport io.github.muntashirakon.AppManager.self.imagecache.ImageLoader;\nimport io.github.muntashirakon.AppManager.settings.FeatureController;\nimport io.github.muntashirakon.AppManager.types.UserPackagePair;\nimport io.github.muntashirakon.AppManager.users.UserInfo;\nimport io.github.muntashirakon.AppManager.users.Users;\nimport io.github.muntashirakon.AppManager.utils.ArrayUtils;\nimport io.github.muntashirakon.AppManager.utils.DateUtils;\nimport io.github.muntashirakon.AppManager.utils.ThreadUtils;\nimport io.github.muntashirakon.AppManager.utils.UIUtils;\nimport io.github.muntashirakon.AppManager.utils.appearance.ColorCodes;\nimport io.github.muntashirakon.dialog.SearchableItemsDialogBuilder;\nimport io.github.muntashirakon.io.Paths;\nimport io.github.muntashirakon.util.AccessibilityUtils;\nimport io.github.muntashirakon.util.AdapterUtils;\nimport io.github.muntashirakon.widget.MultiSelectionView;\n\npublic class MainRecyclerAdapter extends MultiSelectionView.Adapter<MainRecyclerAdapter.ViewHolder>\n        implements SectionIndexer {\n    private static final String sSections = \"ABCDEFGHIJKLMNOPQRSTUVWXYZ\";\n\n    private final MainActivity mActivity;\n    private String mSearchQuery;\n    @GuardedBy(\"mAdapterList\")\n    private final List<ApplicationItem> mAdapterList = new ArrayList<>();\n\n    private final int mColorGreen;\n    private final int mColorOrange;\n    private final int mColorPrimary;\n    private final int mColorSecondary;\n    private final int mQueryStringHighlight;\n\n    MainRecyclerAdapter(@NonNull MainActivity activity) {\n        super();\n        mActivity = activity;\n        mColorGreen = ContextCompat.getColor(activity, io.github.muntashirakon.ui.R.color.stopped);\n        mColorOrange = ContextCompat.getColor(activity, io.github.muntashirakon.ui.R.color.orange);\n        mColorPrimary = ContextCompat.getColor(activity, io.github.muntashirakon.ui.R.color.textColorPrimary);\n        mColorSecondary = ContextCompat.getColor(activity, io.github.muntashirakon.ui.R.color.textColorSecondary);\n        mQueryStringHighlight = ColorCodes.getQueryStringHighlightColor(activity);\n    }\n\n    @GuardedBy(\"mAdapterList\")\n    @UiThread\n    void setDefaultList(List<ApplicationItem> list) {\n        if (mActivity.viewModel == null) return;\n        synchronized (mAdapterList) {\n            mSearchQuery = mActivity.viewModel.getSearchQuery();\n            AdapterUtils.notifyDataSetChanged(this, mAdapterList, list);\n            notifySelectionChange();\n        }\n    }\n\n    @GuardedBy(\"mAdapterList\")\n    @Override\n    public void cancelSelection() {\n        super.cancelSelection();\n        mActivity.viewModel.cancelSelection();\n    }\n\n    @Override\n    public int getSelectedItemCount() {\n        if (mActivity.viewModel == null) return 0;\n        return mActivity.viewModel.getSelectedPackages().size();\n    }\n\n    @Override\n    protected int getTotalItemCount() {\n        if (mActivity.viewModel == null) return 0;\n        return mActivity.viewModel.getApplicationItemCount();\n    }\n\n    @GuardedBy(\"mAdapterList\")\n    @Override\n    protected boolean isSelected(int position) {\n        synchronized (mAdapterList) {\n            return mAdapterList.get(position).isSelected;\n        }\n    }\n\n    @GuardedBy(\"mAdapterList\")\n    @Override\n    protected boolean select(int position) {\n        synchronized (mAdapterList) {\n            mAdapterList.set(position, mActivity.viewModel.select(mAdapterList.get(position)));\n            return true;\n        }\n    }\n\n    @GuardedBy(\"mAdapterList\")\n    @Override\n    protected boolean deselect(int position) {\n        synchronized (mAdapterList) {\n            mAdapterList.set(position, mActivity.viewModel.deselect(mAdapterList.get(position)));\n            return true;\n        }\n    }\n\n    @GuardedBy(\"mAdapterList\")\n    @Override\n    public void toggleSelection(int position) {\n        synchronized (mAdapterList) {\n            super.toggleSelection(position);\n        }\n    }\n\n    @GuardedBy(\"mAdapterList\")\n    @Override\n    public void selectAll() {\n        synchronized (mAdapterList) {\n            super.selectAll();\n        }\n    }\n\n    @GuardedBy(\"mAdapterList\")\n    @Override\n    public void selectRange(int firstPosition, int secondPosition) {\n        synchronized (mAdapterList) {\n            super.selectRange(firstPosition, secondPosition);\n        }\n    }\n\n    @NonNull\n    @Override\n    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {\n        final View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_main, parent, false);\n        return new ViewHolder(view);\n    }\n\n    @GuardedBy(\"mAdapterList\")\n    @Override\n    public void onBindViewHolder(@NonNull ViewHolder holder, int position) {\n        final ApplicationItem item;\n        synchronized (mAdapterList) {\n            item = mAdapterList.get(position);\n        }\n        MaterialCardView cardView = holder.itemView;\n        Context context = cardView.getContext();\n        // Add click listeners\n        cardView.setOnClickListener(v -> {\n            // If selection mode is on, select/deselect the current item instead of the default behaviour\n            if (isInSelectionMode()) {\n                toggleSelection(position);\n                AccessibilityUtils.requestAccessibilityFocus(holder.itemView);\n                return;\n            }\n            handleClick(item);\n        });\n        cardView.setOnLongClickListener(v -> {\n            // Long click listener: Select/deselect an app.\n            // 1) Turn selection mode on if this is the first item in the selection list\n            // 2) Select between last selection position and this position (inclusive) if selection mode is on\n            synchronized (mAdapterList) {\n                ApplicationItem lastSelectedItem = mActivity.viewModel.getLastSelectedPackage();\n                int lastSelectedItemPosition = lastSelectedItem == null ? -1 : mAdapterList.indexOf(lastSelectedItem);\n                if (lastSelectedItemPosition >= 0) {\n                    // Select from last selection to this selection\n                    selectRange(lastSelectedItemPosition, position);\n                } else {\n                    toggleSelection(position);\n                    AccessibilityUtils.requestAccessibilityFocus(holder.itemView);\n                }\n            }\n            return true;\n        });\n        holder.icon.setOnClickListener(v -> {\n            toggleSelection(position);\n            AccessibilityUtils.requestAccessibilityFocus(holder.itemView);\n        });\n        // Box-stroke colors: uninstalled > disabled > force-stopped > regular\n        if (!item.isInstalled) {\n            cardView.setStrokeColor(ColorCodes.getAppUninstalledIndicatorColor(context));\n        } else if (item.isDisabled) {\n            cardView.setStrokeColor(ColorCodes.getAppDisabledIndicatorColor(context));\n        } else if (item.isStopped) {\n            cardView.setStrokeColor(ColorCodes.getAppForceStoppedIndicatorColor(context));\n        } else {\n            cardView.setStrokeColor(Color.TRANSPARENT);\n        }\n        // Display yellow star if the app is in debug mode\n        holder.debugIcon.setVisibility(item.debuggable ? View.VISIBLE : View.INVISIBLE);\n        // Set date and (if available,) days between first installation and last update\n        String lastUpdateDate = DateUtils.formatDate(context, item.lastUpdateTime);\n        if (item.firstInstallTime == item.lastUpdateTime) {\n            holder.date.setText(lastUpdateDate);\n        } else {\n            long days = item.diffInstallUpdateInDays;\n            SpannableString ssDate = new SpannableString(context.getResources()\n                    .getQuantityString(R.plurals.main_list_date_days, (int) days, lastUpdateDate, days));\n            ssDate.setSpan(new RelativeSizeSpan(.8f), lastUpdateDate.length(),\n                    ssDate.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);\n            holder.date.setText(ssDate);\n        }\n        // Set date color to orange if app can read logs (and accepted)\n        holder.date.setTextColor(item.canReadLogs ? mColorOrange : mColorSecondary);\n        if (item.isInstalled) {\n            // Set UID\n            if (item.uidOrAppIds != null) {\n                holder.userId.setText(item.uidOrAppIds);\n            }\n            // Set UID text color to orange if the package is shared\n            holder.userId.setTextColor(item.sharedUserId != null ? mColorOrange : mColorSecondary);\n        } else holder.userId.setText(\"\");\n        if (item.sha != null) {\n            // Set issuer\n            holder.issuer.setVisibility(View.VISIBLE);\n            holder.issuer.setText(item.issuerShortName);\n            // Set signature type\n            holder.sha.setVisibility(View.VISIBLE);\n            holder.sha.setText(item.sha.second);\n        } else {\n            holder.issuer.setVisibility(View.GONE);\n            holder.sha.setVisibility(View.GONE);\n        }\n        // Load app icon\n        holder.icon.setTag(item.packageName);\n        ImageLoader.getInstance().displayImage(item.packageName, item, holder.icon);\n        // Set app label\n        if (!TextUtils.isEmpty(mSearchQuery) && item.label.toLowerCase(Locale.ROOT).contains(mSearchQuery)) {\n            // Highlight searched query\n            holder.label.setText(UIUtils.getHighlightedText(item.label, mSearchQuery, mQueryStringHighlight));\n        } else holder.label.setText(item.label);\n        // Set app label color to red if clearing user data not allowed\n        if (item.isInstalled && !item.allowClearingUserData) {\n            holder.label.setTextColor(Color.RED);\n        } else holder.label.setTextColor(mColorPrimary);\n        // Set package name\n        if (!TextUtils.isEmpty(mSearchQuery) && item.packageName.toLowerCase(Locale.ROOT).contains(mSearchQuery)) {\n            // Highlight searched query\n            holder.packageName.setText(UIUtils.getHighlightedText(item.packageName, mSearchQuery, mQueryStringHighlight));\n        } else holder.packageName.setText(item.packageName);\n        // Set package name color to orange if the app has known tracker components\n        if (item.trackerCount > 0) {\n            holder.packageName.setTextColor(ColorCodes.getComponentTrackerIndicatorColor(context));\n        } else holder.packageName.setTextColor(mColorSecondary);\n        // Set version (along with HW accelerated, debug and test only flags)\n        holder.version.setText(item.versionTag);\n        // Set version color to dark cyan if the app is inactive\n        holder.version.setTextColor(item.isAppInactive ? mColorGreen : mColorSecondary);\n        // Set app type: system or user app (along with large heap, suspended, multi-arch,\n        // has code, vm safe mode)\n        if (item.isInstalled) {\n            String isSystemApp = context.getString(item.isSystem ? R.string.system : R.string.user) + item.appTypePostfix;\n            holder.isSystemApp.setText(isSystemApp);\n        } else {\n            holder.isSystemApp.setText(\"-\");\n        }\n        // Set app type text color to magenta if the app is persistent\n        holder.isSystemApp.setTextColor(item.isPersistent ? Color.MAGENTA : mColorSecondary);\n        // Set SDK\n        if (item.sdkString != null) {\n            holder.size.setText(item.sdkString);\n        } else holder.size.setText(\"-\");\n        // Set SDK color to orange if the app is using cleartext (e.g. HTTP) traffic\n        holder.size.setTextColor(item.usesCleartextTraffic ? mColorOrange : mColorSecondary);\n        // Check for backup\n        if (item.backup != null) {\n            holder.backupIndicator.setVisibility(View.VISIBLE);\n            holder.backupInfo.setVisibility(View.VISIBLE);\n            holder.backupInfoExt.setVisibility(View.VISIBLE);\n            holder.backupIndicator.setText(R.string.backup);\n            int indicatorColor;\n            if (item.isInstalled) {\n                if (item.backup.versionCode >= item.versionCode) {\n                    // Up-to-date backup\n                    indicatorColor = ColorCodes.getBackupLatestIndicatorColor(context);\n                } else {\n                    // Outdated backup\n                    indicatorColor = ColorCodes.getBackupOutdatedIndicatorColor(context);\n                }\n            } else {\n                // App not installed\n                indicatorColor = ColorCodes.getBackupUninstalledIndicatorColor(context);\n            }\n            holder.backupIndicator.setTextColor(indicatorColor);\n            Backup backup = item.backup;\n            long days = item.lastBackupDays;\n            holder.backupInfo.setText(String.format(\"%s: %s, %s %s\",\n                    context.getString(R.string.latest_backup), context.getResources()\n                            .getQuantityString(R.plurals.usage_days, (int) days, days),\n                    context.getString(R.string.version), backup.versionName));\n            holder.backupInfoExt.setText(item.backupFlagsStr);\n        } else {\n            holder.backupIndicator.setVisibility(View.GONE);\n            holder.backupInfo.setVisibility(View.GONE);\n            holder.backupInfoExt.setVisibility(View.GONE);\n        }\n        super.onBindViewHolder(holder, position);\n    }\n\n    @GuardedBy(\"mAdapterList\")\n    @Override\n    public long getItemId(int position) {\n        synchronized (mAdapterList) {\n            return mAdapterList.get(position).hashCode();\n        }\n    }\n\n    @GuardedBy(\"mAdapterList\")\n    @Override\n    public int getItemCount() {\n        synchronized (mAdapterList) {\n            return mAdapterList.size();\n        }\n    }\n\n    @GuardedBy(\"mAdapterList\")\n    @Override\n    public int getPositionForSection(int section) {\n        synchronized (mAdapterList) {\n            for (int i = 0; i < getItemCount(); i++) {\n                String item = mAdapterList.get(i).label;\n                if (!item.isEmpty()) {\n                    if (item.charAt(0) == sSections.charAt(section))\n                        return i;\n                }\n            }\n            return 0;\n        }\n    }\n\n    @Override\n    public int getSectionForPosition(int i) {\n        return 0;\n    }\n\n    @Override\n    public Object[] getSections() {\n        String[] sectionsArr = new String[sSections.length()];\n        for (int i = 0; i < sSections.length(); i++)\n            sectionsArr[i] = String.valueOf(sSections.charAt(i));\n\n        return sectionsArr;\n    }\n\n    private void handleClick(@NonNull ApplicationItem item) {\n        if (!item.isInstalled || item.userIds.length == 0) {\n            // The app should not be installed. But make sure this is really true. (For current user only)\n            ApplicationInfo info;\n            try {\n                info = PackageManagerCompat.getApplicationInfo(item.packageName, MATCH_UNINSTALLED_PACKAGES\n                                | PackageManagerCompat.MATCH_STATIC_SHARED_AND_SDK_LIBRARIES,\n                        UserHandleHidden.myUserId());\n            } catch (RemoteException | PackageManager.NameNotFoundException e) {\n                showBackupRestoreDialogOrAppNotInstalled(item);\n                return;\n            }\n            // 1. Check if the app was really uninstalled.\n            if (ApplicationInfoCompat.isInstalled(info)) {\n                // The app is already installed, and we were wrong to assume that it was installed.\n                // Update data before opening it.\n                item.isInstalled = true;\n                item.isOnlyDataInstalled = false;\n                item.userIds = new int[]{UserHandleHidden.myUserId()};\n                Intent intent = AppDetailsActivity.getIntent(mActivity, item.packageName, UserHandleHidden.myUserId());\n                mActivity.startActivity(intent);\n                return;\n            }\n            // 2. If the app can be installed, offer it to install again.\n            if (FeatureController.isInstallerEnabled()) {\n                if (ApplicationInfoCompat.isSystemApp(info) && SelfPermissions.canInstallExistingPackages()) {\n                    // Install existing app instead of installing as an update\n                    mActivity.startActivity(PackageInstallerActivity.getLaunchableInstance(mActivity, item.packageName));\n                    return;\n                }\n                // Otherwise, try with APK files\n                // FIXME: 1/4/23 Include splits\n                if (Paths.exists(info.publicSourceDir)) {\n                    mActivity.startActivity(PackageInstallerActivity.getLaunchableInstance(mActivity,\n                            Uri.fromFile(new File(info.publicSourceDir))));\n                    return;\n                }\n            }\n            // 3. The app might be uninstalled without clearing data\n            if (ApplicationInfoCompat.isSystemApp(info)) {\n                // The app is a system app, there's no point in asking to uninstall it again\n                showBackupRestoreDialogOrAppNotInstalled(item);\n                return;\n            }\n            new MaterialAlertDialogBuilder(mActivity)\n                    .setTitle(mActivity.getString(R.string.uninstall_app, item.label))\n                    .setMessage(R.string.uninstall_app_again_message)\n                    .setNegativeButton(R.string.no, null)\n                    .setPositiveButton(R.string.yes, (dialog, which) -> ThreadUtils.postOnBackgroundThread(() -> {\n                        PackageInstallerCompat installer = PackageInstallerCompat.getNewInstance();\n                        installer.setAppLabel(item.label);\n                        boolean uninstalled = installer.uninstall(item.packageName, UserHandleHidden.myUserId(), false);\n                        ThreadUtils.postOnMainThread(() -> {\n                            if (uninstalled) {\n                                displayLongToast(R.string.uninstalled_successfully, item.label);\n                            } else {\n                                displayLongToast(R.string.failed_to_uninstall, item.label);\n                            }\n                        });\n                    }))\n                    .show();\n            return;\n        }\n        // The app is installed\n        if (item.userIds.length == 1) {\n            int[] userHandles = Users.getUsersIds();\n            if (ArrayUtils.contains(userHandles, item.userIds[0])) {\n                Intent intent = AppDetailsActivity.getIntent(mActivity, item.packageName, item.userIds[0]);\n                mActivity.startActivity(intent);\n                return;\n            }\n            // Outside our jurisdiction\n            showBackupRestoreDialogOrAppNotInstalled(item);\n            return;\n        }\n        // More than a user, ask the user to select one\n        CharSequence[] userNames = new String[item.userIds.length];\n        List<UserInfo> users = Users.getUsers();\n        for (UserInfo info : users) {\n            for (int i = 0; i < item.userIds.length; ++i) {\n                if (info.id == item.userIds[i]) {\n                    userNames[i] = info.toLocalizedString(mActivity);\n                }\n            }\n        }\n        new SearchableItemsDialogBuilder<>(mActivity, userNames)\n                .setTitle(R.string.select_user)\n                .setOnItemClickListener((dialog, which, item1) -> {\n                    Intent intent = AppDetailsActivity.getIntent(mActivity, item.packageName, item.userIds[which]);\n                    mActivity.startActivity(intent);\n                    dialog.dismiss();\n                })\n                .setNegativeButton(R.string.cancel, null)\n                .show();\n    }\n\n    private void showBackupRestoreDialogOrAppNotInstalled(@NonNull ApplicationItem item) {\n        if (item.backup == null) {\n            // No backups\n            displayShortToast(R.string.app_not_installed);\n            return;\n        }\n        // Has backups\n        BackupRestoreDialogFragment fragment = BackupRestoreDialogFragment.getInstance(\n                Collections.singletonList(new UserPackagePair(\n                        item.packageName, UserHandleHidden.myUserId())));\n        fragment.setOnActionBeginListener(mode -> mActivity.showProgressIndicator(true));\n        fragment.setOnActionCompleteListener((mode, failedPackages) -> mActivity.showProgressIndicator(false));\n        fragment.show(mActivity.getSupportFragmentManager(), BackupRestoreDialogFragment.TAG);\n    }\n\n    public static class ViewHolder extends MultiSelectionView.ViewHolder {\n        MaterialCardView itemView;\n        AppCompatImageView icon;\n        AppCompatImageView debugIcon;\n        TextView label;\n        TextView packageName;\n        TextView version;\n        TextView isSystemApp;\n        TextView date;\n        TextView size;\n        TextView userId;\n        TextView issuer;\n        TextView sha;\n        TextView backupIndicator;\n        TextView backupInfo;\n        TextView backupInfoExt;\n\n        public ViewHolder(@NonNull View itemView) {\n            super(itemView);\n            this.itemView = (MaterialCardView) itemView;\n            icon = itemView.findViewById(R.id.icon);\n            debugIcon = itemView.findViewById(R.id.favorite_icon);\n            label = itemView.findViewById(R.id.label);\n            packageName = itemView.findViewById(R.id.packageName);\n            version = itemView.findViewById(R.id.version);\n            isSystemApp = itemView.findViewById(R.id.isSystem);\n            date = itemView.findViewById(R.id.date);\n            size = itemView.findViewById(R.id.size);\n            userId = itemView.findViewById(R.id.shareid);\n            issuer = itemView.findViewById(R.id.issuer);\n            sha = itemView.findViewById(R.id.sha);\n            backupIndicator = itemView.findViewById(R.id.backup_indicator);\n            backupInfo = itemView.findViewById(R.id.backup_info);\n            backupInfoExt = itemView.findViewById(R.id.backup_info_ext);\n        }\n    }\n}"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/main/MainViewModel.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.main;\n\nimport android.app.ActivityManager;\nimport android.app.Application;\nimport android.content.Intent;\nimport android.content.pm.ApplicationInfo;\nimport android.content.pm.PackageInfo;\nimport android.content.pm.PackageManager;\nimport android.os.RemoteException;\nimport android.os.UserHandleHidden;\nimport android.text.TextUtils;\nimport android.util.Pair;\n\nimport androidx.annotation.AnyThread;\nimport androidx.annotation.GuardedBy;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.WorkerThread;\nimport androidx.lifecycle.AndroidViewModel;\nimport androidx.lifecycle.LiveData;\nimport androidx.lifecycle.MutableLiveData;\n\nimport org.json.JSONException;\n\nimport java.io.BufferedWriter;\nimport java.io.IOException;\nimport java.io.OutputStreamWriter;\nimport java.nio.charset.StandardCharsets;\nimport java.text.Collator;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.Iterator;\nimport java.util.LinkedHashMap;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.ListIterator;\nimport java.util.Locale;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.concurrent.Future;\n\nimport io.github.muntashirakon.AppManager.apk.list.ListExporter;\nimport io.github.muntashirakon.AppManager.backup.BackupUtils;\nimport io.github.muntashirakon.AppManager.compat.ActivityManagerCompat;\nimport io.github.muntashirakon.AppManager.compat.PackageManagerCompat;\nimport io.github.muntashirakon.AppManager.db.entity.App;\nimport io.github.muntashirakon.AppManager.db.utils.AppDb;\nimport io.github.muntashirakon.AppManager.filters.FilterItem;\nimport io.github.muntashirakon.AppManager.filters.options.FilterOption;\nimport io.github.muntashirakon.AppManager.filters.options.PackageNameOption;\nimport io.github.muntashirakon.AppManager.logs.Log;\nimport io.github.muntashirakon.AppManager.misc.AdvancedSearchView;\nimport io.github.muntashirakon.AppManager.misc.ListOptions;\nimport io.github.muntashirakon.AppManager.profiles.ProfileManager;\nimport io.github.muntashirakon.AppManager.profiles.struct.AppsFilterProfile;\nimport io.github.muntashirakon.AppManager.profiles.struct.AppsProfile;\nimport io.github.muntashirakon.AppManager.profiles.struct.BaseProfile;\nimport io.github.muntashirakon.AppManager.self.SelfPermissions;\nimport io.github.muntashirakon.AppManager.settings.FeatureController;\nimport io.github.muntashirakon.AppManager.settings.Prefs;\nimport io.github.muntashirakon.AppManager.types.PackageChangeReceiver;\nimport io.github.muntashirakon.AppManager.types.UserPackagePair;\nimport io.github.muntashirakon.AppManager.usage.AppUsageStatsManager;\nimport io.github.muntashirakon.AppManager.usage.PackageUsageInfo;\nimport io.github.muntashirakon.AppManager.usage.TimeInterval;\nimport io.github.muntashirakon.AppManager.usage.UsageUtils;\nimport io.github.muntashirakon.AppManager.users.Users;\nimport io.github.muntashirakon.AppManager.utils.ArrayUtils;\nimport io.github.muntashirakon.AppManager.utils.ExUtils;\nimport io.github.muntashirakon.AppManager.utils.MultithreadedExecutor;\nimport io.github.muntashirakon.AppManager.utils.PackageUtils;\nimport io.github.muntashirakon.AppManager.utils.ThreadUtils;\nimport io.github.muntashirakon.AppManager.utils.Utils;\nimport io.github.muntashirakon.io.Path;\n\npublic class MainViewModel extends AndroidViewModel implements ListOptions.ListOptionActions {\n    private final PackageManager mPackageManager;\n    private final PackageIntentReceiver mPackageObserver;\n    @MainListOptions.SortOrder\n    private int mSortBy;\n    private boolean mReverseSort;\n    @MainListOptions.Filter\n    private int mFilterFlags;\n    @Nullable\n    private String mFilterProfileName;\n    @Nullable\n    private int[] mSelectedUsers;\n    private String mSearchQuery;\n    @AdvancedSearchView.SearchType\n    private int mSearchType;\n    private Future<?> mFilterResult;\n    private final Map<String, ApplicationItem> mSelectedPackageApplicationItemMap = Collections.synchronizedMap(new LinkedHashMap<>());\n    final MultithreadedExecutor executor = MultithreadedExecutor.getNewInstance();\n\n    public MainViewModel(@NonNull Application application) {\n        super(application);\n        Log.d(\"MVM\", \"New instance created\");\n        mPackageManager = application.getPackageManager();\n        mPackageObserver = new PackageIntentReceiver(this);\n        mSortBy = Prefs.MainPage.getSortOrder();\n        mReverseSort = Prefs.MainPage.isReverseSort();\n        mFilterFlags = Prefs.MainPage.getFilters();\n        mFilterProfileName = Prefs.MainPage.getFilteredProfileName();\n        mSelectedUsers = null; // TODO: 5/6/23 Load from prefs?\n        if (\"\".equals(mFilterProfileName)) mFilterProfileName = null;\n    }\n\n    private final MutableLiveData<Boolean> mOperationStatus = new MutableLiveData<>();\n    @NonNull\n    private final MutableLiveData<List<ApplicationItem>> mApplicationItemsLiveData = new MutableLiveData<>();\n    private final List<ApplicationItem> mApplicationItems = new ArrayList<>();\n\n    public int getApplicationItemCount() {\n        return mApplicationItems.size();\n    }\n\n    @NonNull\n    public LiveData<List<ApplicationItem>> getApplicationItems() {\n        if (mApplicationItemsLiveData.getValue() == null) {\n            loadApplicationItems();\n        }\n        return mApplicationItemsLiveData;\n    }\n\n    public LiveData<Boolean> getOperationStatus() {\n        return mOperationStatus;\n    }\n\n    @GuardedBy(\"applicationItems\")\n    public ApplicationItem deselect(@NonNull ApplicationItem item) {\n        synchronized (mApplicationItems) {\n            int i = mApplicationItems.indexOf(item);\n            if (i == -1) return item;\n            item = mApplicationItems.get(i);\n            mSelectedPackageApplicationItemMap.remove(item.packageName);\n            item.isSelected = false;\n            mApplicationItems.set(i, item);\n            return item;\n        }\n    }\n\n    @GuardedBy(\"applicationItems\")\n    public ApplicationItem select(@NonNull ApplicationItem item) {\n        synchronized (mApplicationItems) {\n            int i = mApplicationItems.indexOf(item);\n            if (i == -1) return item;\n            item = mApplicationItems.get(i);\n            // Removal is needed because LinkedHashMap insertion-oriented\n            mSelectedPackageApplicationItemMap.remove(item.packageName);\n            mSelectedPackageApplicationItemMap.put(item.packageName, item);\n            item.isSelected = true;\n            mApplicationItems.set(i, item);\n            return item;\n        }\n    }\n\n    public void cancelSelection() {\n        synchronized (mApplicationItems) {\n            for (ApplicationItem item : getSelectedApplicationItems()) {\n                int i = mApplicationItems.indexOf(item);\n                if (i != -1) {\n                    mApplicationItems.get(i).isSelected = false;\n                }\n            }\n            mSelectedPackageApplicationItemMap.clear();\n        }\n    }\n\n    @Nullable\n    public ApplicationItem getLastSelectedPackage() {\n        // Last selected package is the same as the last added package.\n        Iterator<ApplicationItem> it = mSelectedPackageApplicationItemMap.values().iterator();\n        ApplicationItem lastItem = null;\n        while (it.hasNext()) {\n            lastItem = it.next();\n        }\n        return lastItem;\n    }\n\n    public Map<String, ApplicationItem> getSelectedPackages() {\n        return mSelectedPackageApplicationItemMap;\n    }\n\n    @NonNull\n    public ArrayList<UserPackagePair> getSelectedPackagesWithUsers() {\n        ArrayList<UserPackagePair> userPackagePairs = new ArrayList<>();\n        int myUserId = UserHandleHidden.myUserId();\n        int[] userIds = Users.getUsersIds();\n        for (String packageName : mSelectedPackageApplicationItemMap.keySet()) {\n            int[] userIds1 = Objects.requireNonNull(mSelectedPackageApplicationItemMap.get(packageName)).userIds;\n            if (userIds1.length == 0) {\n                // Could be a backup only item\n                // Assign current user in it\n                userPackagePairs.add(new UserPackagePair(packageName, myUserId));\n            } else {\n                for (int userHandle : userIds1) {\n                    if (!ArrayUtils.contains(userIds, userHandle)) continue;\n                    userPackagePairs.add(new UserPackagePair(packageName, userHandle));\n                }\n            }\n        }\n        return userPackagePairs;\n    }\n\n    public Collection<ApplicationItem> getSelectedApplicationItems() {\n        return mSelectedPackageApplicationItemMap.values();\n    }\n\n    public String getSearchQuery() {\n        return mSearchQuery;\n    }\n\n    public void setSearchQuery(String searchQuery, @AdvancedSearchView.SearchType int searchType) {\n        this.mSearchQuery = searchType != AdvancedSearchView.SEARCH_TYPE_REGEX ? searchQuery.toLowerCase(Locale.ROOT) : searchQuery;\n        this.mSearchType = searchType;\n        cancelIfRunning();\n        mFilterResult = executor.submit(this::filterItemsByFlags);\n    }\n\n    @Override\n    public int getSortBy() {\n        return mSortBy;\n    }\n\n    @Override\n    public void setReverseSort(boolean reverseSort) {\n        cancelIfRunning();\n        mFilterResult = executor.submit(() -> {\n            sortApplicationList(mSortBy, mReverseSort);\n            filterItemsByFlags();\n        });\n        mReverseSort = reverseSort;\n        Prefs.MainPage.setReverseSort(mReverseSort);\n    }\n\n    @Override\n    public boolean isReverseSort() {\n        return mReverseSort;\n    }\n\n    @Override\n    public void setSortBy(int sortBy) {\n        if (mSortBy != sortBy) {\n            cancelIfRunning();\n            mFilterResult = executor.submit(() -> {\n                sortApplicationList(sortBy, mReverseSort);\n                filterItemsByFlags();\n            });\n        }\n        mSortBy = sortBy;\n        Prefs.MainPage.setSortOrder(mSortBy);\n    }\n\n    @Override\n    public boolean hasFilterFlag(@MainListOptions.Filter int flag) {\n        return (mFilterFlags & flag) != 0;\n    }\n\n    @Override\n    public void addFilterFlag(@MainListOptions.Filter int filterFlag) {\n        mFilterFlags |= filterFlag;\n        Prefs.MainPage.setFilters(mFilterFlags);\n        cancelIfRunning();\n        mFilterResult = executor.submit(this::filterItemsByFlags);\n    }\n\n    @Override\n    public void removeFilterFlag(@MainListOptions.Filter int filterFlag) {\n        mFilterFlags &= ~filterFlag;\n        Prefs.MainPage.setFilters(mFilterFlags);\n        cancelIfRunning();\n        mFilterResult = executor.submit(this::filterItemsByFlags);\n    }\n\n    public void setFilterProfileName(@Nullable String filterProfileName) {\n        if (mFilterProfileName == null) {\n            if (filterProfileName == null) return;\n        } else if (mFilterProfileName.equals(filterProfileName)) return;\n        mFilterProfileName = filterProfileName;\n        Prefs.MainPage.setFilteredProfileName(filterProfileName);\n        cancelIfRunning();\n        mFilterResult = executor.submit(this::filterItemsByFlags);\n    }\n\n    @Nullable\n    public String getFilterProfileName() {\n        return mFilterProfileName;\n    }\n\n    public void setSelectedUsers(@Nullable int[] selectedUsers) {\n        if (selectedUsers == null) {\n            if (mSelectedUsers == null) {\n                // No change\n                return;\n            }\n        } else if (mSelectedUsers != null) {\n            if (mSelectedUsers.length == selectedUsers.length) {\n                boolean differs = false;\n                for (int user : selectedUsers) {\n                    if (!ArrayUtils.contains(mSelectedUsers, user)) {\n                        differs = true;\n                        break;\n                    }\n                }\n                if (!differs) {\n                    // No change detected\n                    return;\n                }\n            }\n        }\n        mSelectedUsers = selectedUsers;\n        // TODO: 5/6/23 Store value to prefs\n        cancelIfRunning();\n        mFilterResult = executor.submit(this::filterItemsByFlags);\n    }\n\n    @Nullable\n    public int[] getSelectedUsers() {\n        return mSelectedUsers;\n    }\n\n    @AnyThread\n    public void onResume() {\n        if ((mFilterFlags & MainListOptions.FILTER_RUNNING_APPS) != 0) {\n            // Reload filters to get running apps again\n            cancelIfRunning();\n            mFilterResult = executor.submit(this::filterItemsByFlags);\n        }\n    }\n\n    public void saveExportedAppList(@ListExporter.ExportType int exportType, @NonNull Path path) {\n        executor.submit(() -> {\n            try (BufferedWriter writer = new BufferedWriter(new OutputStreamWriter(path.openOutputStream(), StandardCharsets.UTF_8))) {\n                List<PackageInfo> packageInfoList = new ArrayList<>();\n                for (String packageName : getSelectedPackages().keySet()) {\n                    int[] userIds = Objects.requireNonNull(getSelectedPackages().get(packageName)).userIds;\n                    for (int userId : userIds) {\n                        packageInfoList.add(PackageManagerCompat.getPackageInfo(packageName,\n                                PackageManagerCompat.MATCH_STATIC_SHARED_AND_SDK_LIBRARIES, userId));\n                        break;\n                    }\n                }\n                ListExporter.export(getApplication(), writer, exportType, packageInfoList);\n                mOperationStatus.postValue(true);\n            } catch (IOException | RemoteException | PackageManager.NameNotFoundException e) {\n                e.printStackTrace();\n                mOperationStatus.postValue(false);\n            }\n        });\n    }\n\n    @GuardedBy(\"applicationItems\")\n    public void loadApplicationItems() {\n        cancelIfRunning();\n        mFilterResult = executor.submit(() -> {\n            List<ApplicationItem> updatedApplicationItems = PackageUtils\n                    .getInstalledOrBackedUpApplicationsFromDb(getApplication(), true, true);\n            synchronized (mApplicationItems) {\n                mApplicationItems.clear();\n                mApplicationItems.addAll(updatedApplicationItems);\n                // select apps again\n                for (ApplicationItem item : getSelectedApplicationItems()) {\n                    select(item);\n                }\n                sortApplicationList(mSortBy, mReverseSort);\n                filterItemsByFlags();\n            }\n        });\n    }\n\n    private void cancelIfRunning() {\n        if (mFilterResult != null) {\n            mFilterResult.cancel(true);\n        }\n    }\n\n    @WorkerThread\n    private void filterItemsByQuery(@NonNull List<ApplicationItem> applicationItems) {\n        List<ApplicationItem> filteredApplicationItems;\n        if (mSearchType == AdvancedSearchView.SEARCH_TYPE_REGEX) {\n            filteredApplicationItems = AdvancedSearchView.matches(mSearchQuery, applicationItems,\n                    (AdvancedSearchView.ChoicesGenerator<ApplicationItem>) item -> new ArrayList<String>() {{\n                        add(item.packageName);\n                        add(item.label);\n                    }}, AdvancedSearchView.SEARCH_TYPE_REGEX);\n            mApplicationItemsLiveData.postValue(filteredApplicationItems);\n            return;\n        }\n        // Others\n        filteredApplicationItems = new ArrayList<>();\n        for (ApplicationItem item : applicationItems) {\n            if (ThreadUtils.isInterrupted()) {\n                return;\n            }\n            if (AdvancedSearchView.matches(mSearchQuery, item.packageName.toLowerCase(Locale.ROOT), mSearchType)) {\n                filteredApplicationItems.add(item);\n            } else if (mSearchType == AdvancedSearchView.SEARCH_TYPE_CONTAINS) {\n                if (Utils.containsOrHasInitials(mSearchQuery, item.label)) {\n                    filteredApplicationItems.add(item);\n                }\n            } else if (AdvancedSearchView.matches(mSearchQuery, item.label.toLowerCase(Locale.ROOT), mSearchType)) {\n                filteredApplicationItems.add(item);\n            }\n        }\n        mApplicationItemsLiveData.postValue(filteredApplicationItems);\n    }\n\n    @WorkerThread\n    @GuardedBy(\"applicationItems\")\n    private void filterItemsByFlags() {\n        synchronized (mApplicationItems) {\n            List<ApplicationItem> candidateApplicationItems = new ArrayList<>();\n            List<FilterOption> profileFilterOptions = new ArrayList<>();\n            if (mFilterProfileName != null) {\n                String profileId = ProfileManager.getProfileIdCompat(mFilterProfileName);\n                Path profilePath = ProfileManager.findProfilePathById(profileId);\n                try {\n                    BaseProfile profile = BaseProfile.fromPath(profilePath);\n                    if (profile instanceof AppsProfile) {\n                        AppsProfile appsProfile = (AppsProfile) profile;\n                        PackageNameOption option = new PackageNameOption();\n                        option.setKeyValue(\"eq_any\", TextUtils.join(\"\\n\", appsProfile.packages));\n                        profileFilterOptions.add(option);\n                    } else if (profile instanceof AppsFilterProfile) {\n                        AppsFilterProfile filterProfile = (AppsFilterProfile) profile;\n                        FilterItem filterItem = filterProfile.getFilterItem();\n                        for (int i = 0; i < filterItem.getSize(); ++i) {\n                            profileFilterOptions.add(filterItem.getFilterOptionAt(i));\n                        }\n                    }\n                } catch (IOException | JSONException e) {\n                    e.printStackTrace();\n                }\n            }\n            for (ApplicationItem item : mApplicationItems) {\n                if (ThreadUtils.isInterrupted()) {\n                    return;\n                }\n                if (isAmongSelectedUsers(item)) {\n                    candidateApplicationItems.add(item);\n                }\n            }\n            // Other filters\n            if (profileFilterOptions.isEmpty() && mFilterFlags == MainListOptions.FILTER_NO_FILTER) {\n                if (!TextUtils.isEmpty(mSearchQuery)) {\n                    filterItemsByQuery(candidateApplicationItems);\n                } else {\n                    mApplicationItemsLiveData.postValue(candidateApplicationItems);\n                }\n            } else {\n                List<ApplicationItem> filteredApplicationItems = new ArrayList<>();\n                FilterItem filterItem = MainListOptions.getFilterItemFromFlags(mFilterFlags);\n                for (FilterOption filterOption : profileFilterOptions) {\n                    filterItem.addFilterOption(filterOption);\n                }\n                Map<String, PackageUsageInfo> packageUsageInfoList = new HashMap<>();\n                if (filterItem.getTimesUsageInfoUsed() > 0) {\n                    boolean hasUsageAccess = FeatureController.isUsageAccessEnabled() && SelfPermissions.checkUsageStatsPermission();\n                    if (hasUsageAccess) {\n                        TimeInterval interval = UsageUtils.getLastWeek();\n                        for (int userId : Users.getUsersIds()) {\n                            List<PackageUsageInfo> usageInfoList;\n                            usageInfoList = ExUtils.exceptionAsNull(() -> AppUsageStatsManager\n                                    .getInstance().getUsageStats(interval, userId));\n                            if (usageInfoList != null) {\n                                for (PackageUsageInfo info : usageInfoList) {\n                                    if (ThreadUtils.isInterrupted()) return;\n                                    PackageUsageInfo oldInfo = packageUsageInfoList.get(info.packageName);\n                                    if (oldInfo != null) {\n                                        oldInfo.screenTime += info.screenTime;\n                                        oldInfo.lastUsageTime += info.lastUsageTime;\n                                        oldInfo.timesOpened += info.timesOpened;\n                                        oldInfo.mobileData = AppUsageStatsManager.DataUsage.fromDataUsage(oldInfo.mobileData, info.mobileData);\n                                        oldInfo.wifiData = AppUsageStatsManager.DataUsage.fromDataUsage(oldInfo.wifiData, info.wifiData);\n                                        if (info.entries != null) {\n                                            if (oldInfo.entries == null) {\n                                                oldInfo.entries = info.entries;\n                                            } else oldInfo.entries.addAll(info.entries);\n                                        }\n                                    } else packageUsageInfoList.put(info.packageName, info);\n                                }\n                            }\n                        }\n                    }\n                }\n                HashSet<String> runningPackages = new HashSet<>();\n                if (filterItem.getTimesRunningOptionUsed() > 0) {\n                    for (ActivityManager.RunningAppProcessInfo info : ActivityManagerCompat.getRunningAppProcesses()) {\n                        if (info.pkgList != null) {\n                            runningPackages.addAll(Arrays.asList(info.pkgList));\n                        }\n                    }\n                }\n                for (ApplicationItem item : candidateApplicationItems) {\n                    item.setPackageUsageInfo(packageUsageInfoList.get(item.packageName));\n                    item.setRunning(runningPackages.contains(item.packageName));\n                }\n                List<FilterItem.FilteredItemInfo<ApplicationItem>> result = filterItem.getFilteredList(candidateApplicationItems);\n                for (FilterItem.FilteredItemInfo<ApplicationItem> item : result) {\n                    if ((mFilterFlags & MainListOptions.FILTER_APPS_WITH_SPLITS) != 0 && !item.info.hasSplits) {\n                        continue;\n                    }\n                    if ((mFilterFlags & MainListOptions.FILTER_APPS_WITH_SAF) != 0 && !item.info.usesSaf) {\n                        continue;\n                    }\n                    filteredApplicationItems.add(item.info);\n                }\n                if (!TextUtils.isEmpty(mSearchQuery)) {\n                    filterItemsByQuery(filteredApplicationItems);\n                } else {\n                    mApplicationItemsLiveData.postValue(filteredApplicationItems);\n                }\n            }\n        }\n    }\n\n    private boolean isAmongSelectedUsers(@NonNull ApplicationItem applicationItem) {\n        if (mSelectedUsers == null) {\n            // All users\n            return true;\n        }\n        for (int userId : mSelectedUsers) {\n            if (ArrayUtils.contains(applicationItem.userIds, userId)) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    @GuardedBy(\"applicationItems\")\n    private void sortApplicationList(@MainListOptions.SortOrder int sortBy, boolean reverse) {\n        synchronized (mApplicationItems) {\n            if (sortBy != MainListOptions.SORT_BY_APP_LABEL) {\n                sortApplicationList(MainListOptions.SORT_BY_APP_LABEL, false);\n            }\n            int mode = reverse ? -1 : 1;\n            Collator collator = Collator.getInstance();\n            Collections.sort(mApplicationItems, (o1, o2) -> {\n                switch (sortBy) {\n                    case MainListOptions.SORT_BY_APP_LABEL:\n                        return mode * collator.compare(o1.label, o2.label);\n                    case MainListOptions.SORT_BY_PACKAGE_NAME:\n                        return mode * o1.packageName.compareTo(o2.packageName);\n                    case MainListOptions.SORT_BY_DOMAIN:\n                        boolean isSystem1 = (o1.flags & ApplicationInfo.FLAG_SYSTEM) != 0;\n                        boolean isSystem2 = (o2.flags & ApplicationInfo.FLAG_SYSTEM) != 0;\n                        return mode * Boolean.compare(isSystem1, isSystem2);\n                    case MainListOptions.SORT_BY_LAST_UPDATE:\n                        // Sort in decreasing order\n                        return -mode * o1.lastUpdateTime.compareTo(o2.lastUpdateTime);\n                    case MainListOptions.SORT_BY_TOTAL_SIZE:\n                        // Sort in decreasing order\n                        return -mode * o1.totalSize.compareTo(o2.totalSize);\n                    case MainListOptions.SORT_BY_DATA_USAGE:\n                        // Sort in decreasing order\n                        return -mode * o1.dataUsage.compareTo(o2.dataUsage);\n                    case MainListOptions.SORT_BY_OPEN_COUNT:\n                        // Sort in decreasing order\n                        return -mode * Integer.compare(o1.openCount, o2.openCount);\n                    case MainListOptions.SORT_BY_INSTALLATION_DATE:\n                        // Sort in decreasing order\n                        return -mode * Long.compare(o1.firstInstallTime, o2.firstInstallTime);\n                    case MainListOptions.SORT_BY_SCREEN_TIME:\n                        // Sort in decreasing order\n                        return -mode * Long.compare(o1.screenTime, o2.screenTime);\n                    case MainListOptions.SORT_BY_LAST_USAGE_TIME:\n                        // Sort in decreasing order\n                        return -mode * Long.compare(o1.lastUsageTime, o2.lastUsageTime);\n                    case MainListOptions.SORT_BY_TARGET_SDK:\n                        // null on top\n                        if (o1.targetSdk == null) return -mode;\n                        else if (o2.targetSdk == null) return +mode;\n                        return mode * o1.targetSdk.compareTo(o2.targetSdk);\n                    case MainListOptions.SORT_BY_SHARED_ID:\n                        return mode * Integer.compare(o1.uid, o2.uid);\n                    case MainListOptions.SORT_BY_SHA:\n                        // null on top\n                        if (o1.sha == null) {\n                            return -mode;\n                        } else if (o2.sha == null) {\n                            return +mode;\n                        } else {  // Both aren't null\n                            int i = o1.sha.first.compareToIgnoreCase(o2.sha.first);\n                            if (i == 0) {\n                                return mode * o1.sha.second.compareToIgnoreCase(o2.sha.second);\n                            } else return mode * i;\n                        }\n                    case MainListOptions.SORT_BY_BLOCKED_COMPONENTS:\n                        return -mode * o1.blockedCount.compareTo(o2.blockedCount);\n                    case MainListOptions.SORT_BY_FROZEN_APP:\n                        return -mode * Boolean.compare(o1.isDisabled, o2.isDisabled);\n                    case MainListOptions.SORT_BY_BACKUP:\n                        return -mode * Boolean.compare(o1.backup != null, o2.backup != null);\n                    case MainListOptions.SORT_BY_LAST_ACTION:\n                        return -mode * o1.lastActionTime.compareTo(o2.lastActionTime);\n                    case MainListOptions.SORT_BY_TRACKERS:\n                        return -mode * o1.trackerCount.compareTo(o2.trackerCount);\n                }\n                return 0;\n            });\n        }\n    }\n\n    @WorkerThread\n    private void updateInfoForUid(int uid, String action) {\n        Log.d(\"updateInfoForUid\", \"Uid: %d\", uid);\n        String[] packages;\n        if (Intent.ACTION_PACKAGE_REMOVED.equals(action)) packages = getPackagesForUid(uid);\n        else packages = mPackageManager.getPackagesForUid(uid);\n        updateInfoForPackages(packages, action);\n    }\n\n    @WorkerThread\n    private void updateInfoForPackages(@Nullable String[] packages, @NonNull String action) {\n        Log.d(\"updateInfoForPackages\", \"packages: %s\", Arrays.toString(packages));\n        if (packages == null || packages.length == 0) return;\n        boolean modified = false;\n        switch (action) {\n            case PackageChangeReceiver.ACTION_DB_PACKAGE_REMOVED:\n            case PackageChangeReceiver.ACTION_DB_PACKAGE_ALTERED:\n            case PackageChangeReceiver.ACTION_DB_PACKAGE_ADDED: {\n                AppDb appDb = new AppDb();\n                for (String packageName : packages) {\n                    ApplicationItem item = getNewApplicationItem(packageName, appDb.getAllApplications(packageName));\n                    modified |= item != null ? insertOrAddApplicationItem(item) : deleteApplicationItem(packageName);\n                }\n                break;\n            }\n            case PackageChangeReceiver.ACTION_PACKAGE_REMOVED:\n            case PackageChangeReceiver.ACTION_PACKAGE_ALTERED:\n            case PackageChangeReceiver.ACTION_PACKAGE_ADDED:\n                // case BatchOpsService.ACTION_BATCH_OPS_COMPLETED:\n            case Intent.ACTION_PACKAGE_REMOVED:\n            case Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE:\n            case Intent.ACTION_PACKAGE_ADDED:\n            case Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE:\n            case Intent.ACTION_PACKAGE_CHANGED: {\n                List<App> appList = new AppDb().updateApplications(getApplication(), packages);\n                for (String packageName : packages) {\n                    ApplicationItem item = getNewApplicationItem(packageName, appList);\n                    modified |= item != null ? insertOrAddApplicationItem(item) : deleteApplicationItem(packageName);\n                }\n                break;\n            }\n            default:\n                return;\n        }\n        if (modified) {\n            sortApplicationList(mSortBy, mReverseSort);\n            filterItemsByFlags();\n        }\n    }\n\n    @GuardedBy(\"applicationItems\")\n    private boolean insertOrAddApplicationItem(@Nullable ApplicationItem item) {\n        if (item == null) return false;\n        synchronized (mApplicationItems) {\n            if (insertApplicationItem(item)) {\n                return true;\n            }\n            boolean inserted = mApplicationItems.add(item);\n            if (mSelectedPackageApplicationItemMap.containsKey(item.packageName)) {\n                select(item);\n            }\n            return inserted;\n        }\n    }\n\n    @GuardedBy(\"applicationItems\")\n    private boolean insertApplicationItem(@NonNull ApplicationItem item) {\n        synchronized (mApplicationItems) {\n            boolean isInserted = false;\n            for (int i = 0; i < mApplicationItems.size(); ++i) {\n                if (item.equals(mApplicationItems.get(i))) {\n                    mApplicationItems.set(i, item);\n                    isInserted = true;\n                    if (mSelectedPackageApplicationItemMap.containsKey(item.packageName)) {\n                        select(item);\n                    }\n                }\n            }\n            return isInserted;\n        }\n    }\n\n    private boolean deleteApplicationItem(@NonNull String packageName) {\n        synchronized (mApplicationItems) {\n            ListIterator<ApplicationItem> it = mApplicationItems.listIterator();\n            while (it.hasNext()) {\n                ApplicationItem item = it.next();\n                if (item.packageName.equals(packageName)) {\n                    mSelectedPackageApplicationItemMap.remove(packageName);\n                    it.remove();\n                    return true;\n                }\n            }\n            return false;\n        }\n    }\n\n    @WorkerThread\n    @Nullable\n    private ApplicationItem getNewApplicationItem(@NonNull String packageName, @NonNull List<App> apps) {\n        ApplicationItem item = new ApplicationItem();\n        int thisUser = UserHandleHidden.myUserId();\n        for (App app : apps) {\n            if (!packageName.equals(app.packageName)) {\n                // Package name didn't match\n                continue;\n            }\n            if (app.isInstalled) {\n                boolean newItem = item.packageName == null || !item.isInstalled;\n                if (item.packageName == null) {\n                    item.packageName = app.packageName;\n                }\n                item.userIds = ArrayUtils.appendInt(item.userIds, app.userId);\n                item.isInstalled = true;\n                item.isOnlyDataInstalled = false;\n                item.openCount += app.openCount;\n                item.screenTime += app.screenTime;\n                if (item.lastUsageTime == 0L || item.lastUsageTime < app.lastUsageTime) {\n                    item.lastUsageTime = app.lastUsageTime;\n                }\n                item.hasKeystore |= app.hasKeystore;\n                item.usesSaf |= app.usesSaf;\n                if (app.ssaid != null) {\n                    item.ssaid = app.ssaid;\n                }\n                item.totalSize += app.codeSize + app.dataSize;\n                item.dataUsage += app.wifiDataUsage + app.mobileDataUsage;\n                if (!newItem && app.userId != thisUser) {\n                    // This user has the highest priority\n                    continue;\n                }\n            } else {\n                // App not installed but may be installed in other profiles\n                if (item.packageName != null) {\n                    // Item exists, use the previous status\n                    continue;\n                } else {\n                    item.packageName = app.packageName;\n                    item.isInstalled = false;\n                    item.isOnlyDataInstalled = app.isOnlyDataInstalled;\n                    item.hasKeystore |= app.hasKeystore;\n                }\n            }\n            item.flags = app.flags;\n            item.uid = app.uid;\n            item.debuggable = app.isDebuggable();\n            item.isUser = !app.isSystemApp();\n            item.isDisabled = !app.isEnabled;\n            item.label = app.packageLabel;\n            item.targetSdk = app.sdk;\n            item.versionName = app.versionName;\n            item.versionCode = app.versionCode;\n            item.sharedUserId = app.sharedUserId;\n            item.sha = new Pair<>(app.certName, app.certAlgo);\n            item.firstInstallTime = app.firstInstallTime;\n            item.lastUpdateTime = app.lastUpdateTime;\n            item.hasActivities = app.hasActivities;\n            item.hasSplits = app.hasSplits;\n            item.blockedCount = app.rulesCount;\n            item.trackerCount = app.trackerCount;\n            item.lastActionTime = app.lastActionTime;\n            if (item.backup == null) {\n                item.backup = BackupUtils.getLatestBackupMetadataFromDbNoLockValidate(packageName);\n            }\n            item.generateOtherInfo();\n        }\n        if (item.packageName == null) {\n            return null;\n        }\n        return item;\n    }\n\n    @GuardedBy(\"applicationItems\")\n    @NonNull\n    private String[] getPackagesForUid(int uid) {\n        synchronized (mApplicationItems) {\n            List<String> packages = new LinkedList<>();\n            for (ApplicationItem item : mApplicationItems) {\n                if (item.uid == uid) packages.add(item.packageName);\n            }\n            return packages.toArray(new String[0]);\n        }\n    }\n\n    @Override\n    protected void onCleared() {\n        if (mPackageObserver != null) getApplication().unregisterReceiver(mPackageObserver);\n        executor.shutdownNow();\n        super.onCleared();\n    }\n\n    public static class PackageIntentReceiver extends PackageChangeReceiver {\n        private final MainViewModel mModel;\n\n        public PackageIntentReceiver(@NonNull MainViewModel model) {\n            super(model.getApplication());\n            mModel = model;\n        }\n\n        @Override\n        @WorkerThread\n        protected void onPackageChanged(Intent intent, @Nullable Integer uid, @Nullable String[] packages) {\n            mModel.cancelIfRunning();\n            if (uid != null) {\n                mModel.updateInfoForUid(uid, intent.getAction());\n            } else if (packages != null) {\n                mModel.updateInfoForPackages(packages, intent.getAction());\n            } else {\n                mModel.loadApplicationItems();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/main/SplashActivity.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.main;\n\nimport static io.github.muntashirakon.AppManager.BaseActivity.ASKED_PERMISSIONS;\n\nimport android.annotation.SuppressLint;\nimport android.app.KeyguardManager;\nimport android.content.Intent;\nimport android.os.Build;\nimport android.os.Bundle;\nimport android.view.Menu;\nimport android.widget.TextView;\n\nimport androidx.activity.EdgeToEdge;\nimport androidx.activity.result.ActivityResultLauncher;\nimport androidx.activity.result.contract.ActivityResultContracts;\nimport androidx.annotation.CallSuper;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.appcompat.app.AppCompatActivity;\nimport androidx.appcompat.view.menu.MenuBuilder;\nimport androidx.biometric.BiometricPrompt;\nimport androidx.core.content.ContextCompat;\nimport androidx.core.splashscreen.SplashScreen;\nimport androidx.lifecycle.ViewModelProvider;\n\nimport com.google.android.material.color.DynamicColors;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Locale;\n\nimport io.github.muntashirakon.AppManager.BuildConfig;\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.compat.BiometricAuthenticatorsCompat;\nimport io.github.muntashirakon.AppManager.crypto.ks.KeyStoreActivity;\nimport io.github.muntashirakon.AppManager.crypto.ks.KeyStoreManager;\nimport io.github.muntashirakon.AppManager.logs.Log;\nimport io.github.muntashirakon.AppManager.self.SelfPermissions;\nimport io.github.muntashirakon.AppManager.self.life.BuildExpiryChecker;\nimport io.github.muntashirakon.AppManager.settings.Ops;\nimport io.github.muntashirakon.AppManager.settings.Prefs;\nimport io.github.muntashirakon.AppManager.settings.SecurityAndOpsViewModel;\nimport io.github.muntashirakon.AppManager.utils.UIUtils;\n\n@SuppressLint(\"CustomSplashScreen\")\npublic class SplashActivity extends AppCompatActivity {\n    public static final String TAG = SplashActivity.class.getSimpleName();\n\n    @Nullable\n    private TextView mStateNameView;\n    private SecurityAndOpsViewModel mViewModel;\n    private BiometricPrompt mBiometricPrompt;\n\n    private final ActivityResultLauncher<Intent> mKeyStoreActivity = registerForActivityResult(\n            new ActivityResultContracts.StartActivityForResult(), result -> {\n                // Need authentication and/or verify mode of operation\n                ensureSecurityAndModeOfOp();\n            });\n    private final ActivityResultLauncher<String[]> mPermissionCheckActivity = registerForActivityResult(\n            new ActivityResultContracts.RequestMultiplePermissions(),\n            permissionStatusMap -> {\n                // Run authentication\n                doAuthenticate();\n            });\n\n    @Override\n    protected final void onCreate(@Nullable Bundle savedInstanceState) {\n        setTheme(Prefs.Appearance.isPureBlackTheme() ? R.style.AppTheme_Splash_Black : R.style.AppTheme_Splash);\n        SplashScreen.installSplashScreen(this);\n        EdgeToEdge.enable(this);\n        super.onCreate(savedInstanceState);\n        DynamicColors.applyToActivityIfAvailable(this);\n        setContentView(R.layout.activity_authentication);\n        ((TextView) findViewById(R.id.version)).setText(String.format(Locale.ROOT, \"%s (%d)\",\n                BuildConfig.VERSION_NAME, BuildConfig.VERSION_CODE));\n        mStateNameView = findViewById(R.id.state_name);\n        if (Ops.isAuthenticated()) {\n            Log.d(TAG, \"Already authenticated.\");\n            startActivity(new Intent(this, MainActivity.class));\n            finish();\n            return;\n        }\n        if (Boolean.TRUE.equals(BuildExpiryChecker.buildExpired())) {\n            // Build has expired\n            BuildExpiryChecker.getBuildExpiredDialog(this, (dialog, which) -> doAuthenticate()).show();\n            return;\n        }\n        // Init permission checks\n        if (!initPermissionChecks()) {\n            // Run authentication\n            doAuthenticate();\n        }\n    }\n\n    @CallSuper\n    @SuppressLint(\"RestrictedApi\")\n    @Override\n    public boolean onCreateOptionsMenu(Menu menu) {\n        if (menu instanceof MenuBuilder) {\n            ((MenuBuilder) menu).setOptionalIconsVisible(true);\n        }\n        return super.onCreateOptionsMenu(menu);\n    }\n\n    private void doAuthenticate() {\n        mViewModel = new ViewModelProvider(this).get(SecurityAndOpsViewModel.class);\n        mBiometricPrompt = new BiometricPrompt(this, ContextCompat.getMainExecutor(this),\n                new BiometricPrompt.AuthenticationCallback() {\n                    @Override\n                    public void onAuthenticationError(int errorCode, @NonNull CharSequence errString) {\n                        super.onAuthenticationError(errorCode, errString);\n                        finishAndRemoveTask();\n                    }\n\n                    @Override\n                    public void onAuthenticationSucceeded(@NonNull BiometricPrompt.AuthenticationResult result) {\n                        super.onAuthenticationSucceeded(result);\n                        handleMigrationAndModeOfOp();\n                    }\n\n                    @Override\n                    public void onAuthenticationFailed() {\n                        super.onAuthenticationFailed();\n                    }\n                });\n        Log.d(TAG, \"Waiting to be authenticated.\");\n        mViewModel.authenticationStatus().observe(this, status -> {\n            switch (status) {\n                case Ops.STATUS_AUTO_CONNECT_WIRELESS_DEBUGGING:\n                    Log.d(TAG, \"Try auto-connecting to wireless debugging.\");\n                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {\n                        mViewModel.autoConnectWirelessDebugging();\n                        return;\n                    } // fall-through\n                case Ops.STATUS_WIRELESS_DEBUGGING_CHOOSER_REQUIRED:\n                    Log.d(TAG, \"Display wireless debugging chooser (pair or connect)\");\n                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {\n                        Ops.connectWirelessDebugging(this, mViewModel);\n                        return;\n                    } // fall-through\n                case Ops.STATUS_ADB_CONNECT_REQUIRED:\n                    Log.d(TAG, \"Display connect dialog.\");\n                    Ops.connectAdbInput(this, mViewModel);\n                    return;\n                case Ops.STATUS_ADB_PAIRING_REQUIRED:\n                    Log.d(TAG, \"Display pairing dialog.\");\n                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {\n                        Ops.pairAdbInput(this, mViewModel);\n                        return;\n                    } // fall-through\n                case Ops.STATUS_FAILURE_ADB_NEED_MORE_PERMS:\n                    Ops.displayIncompleteUsbDebuggingMessage(this);\n                case Ops.STATUS_SUCCESS:\n                case Ops.STATUS_FAILURE:\n                    Log.d(TAG, \"Authentication completed.\");\n                    mViewModel.setAuthenticating(false);\n                    Ops.setAuthenticated(this, true);\n                    startActivity(new Intent(this, MainActivity.class));\n                    finish();\n            }\n        });\n        if (!mViewModel.isAuthenticating()) {\n            mViewModel.setAuthenticating(true);\n            // Check KeyStore\n            if (KeyStoreManager.hasKeyStorePassword()) {\n                // We already have a working keystore password.\n                // Only need authentication and/or verify mode of operation.\n                ensureSecurityAndModeOfOp();\n                return;\n            }\n            Intent keyStoreIntent = new Intent(this, KeyStoreActivity.class)\n                    .putExtra(KeyStoreActivity.EXTRA_KS, true);\n            mKeyStoreActivity.launch(keyStoreIntent);\n        }\n    }\n\n    private void ensureSecurityAndModeOfOp() {\n        if (!Prefs.Privacy.isScreenLockEnabled()) {\n            // No security enabled\n            handleMigrationAndModeOfOp();\n            return;\n        }\n        Log.d(TAG, \"Security enabled.\");\n        KeyguardManager keyguardManager = (KeyguardManager) getSystemService(KEYGUARD_SERVICE);\n        if (keyguardManager.isKeyguardSecure()) {\n            // Screen lock enabled\n            BiometricPrompt.PromptInfo promptInfo = new BiometricPrompt.PromptInfo.Builder()\n                    .setTitle(getString(R.string.unlock_app_manager))\n                    .setAllowedAuthenticators(new BiometricAuthenticatorsCompat.Builder().allowEverything(true).build())\n                    .build();\n            mBiometricPrompt.authenticate(promptInfo);\n        } else {\n            // Screen lock disabled\n            UIUtils.displayLongToast(R.string.screen_lock_not_enabled);\n            finishAndRemoveTask();\n        }\n    }\n\n    private void handleMigrationAndModeOfOp() {\n        // Authentication was successful\n        Log.d(TAG, \"Authenticated\");\n        if (mStateNameView != null) {\n            mStateNameView.setText(R.string.initializing);\n        }\n        // Set mode of operation\n        if (mViewModel != null) {\n            mViewModel.setModeOfOps();\n        }\n    }\n\n    private boolean initPermissionChecks() {\n        List<String> permissionsToBeAsked = new ArrayList<>(ASKED_PERMISSIONS.size());\n        for (String permission : ASKED_PERMISSIONS.keySet()) {\n            if (!SelfPermissions.checkSelfPermission(permission)) {\n                permissionsToBeAsked.add(permission);\n            }\n        }\n        if (!permissionsToBeAsked.isEmpty()) {\n            // Ask required permissions\n            mPermissionCheckActivity.launch(permissionsToBeAsked.toArray(new String[0]));\n            return true;\n        }\n        return false;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/misc/AMExceptionHandler.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.misc;\n\nimport android.app.Notification;\nimport android.app.PendingIntent;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.os.Build;\n\nimport androidx.annotation.NonNull;\nimport androidx.core.app.NotificationCompat;\nimport androidx.core.app.PendingIntentCompat;\n\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.utils.NotificationUtils;\n\npublic class AMExceptionHandler implements Thread.UncaughtExceptionHandler {\n    private static final String E = \"am4android@riseup.net\";\n\n    private final Thread.UncaughtExceptionHandler mDefaultExceptionHandler;\n    private final Context mContext;\n\n    public AMExceptionHandler(Context context) {\n        mDefaultExceptionHandler = Thread.getDefaultUncaughtExceptionHandler();\n        mContext = context;\n    }\n\n    public void uncaughtException(@NonNull Thread t, @NonNull Throwable e) {\n        // Collect info\n        StackTraceElement[] arr = e.getStackTrace();\n        StringBuilder report = new StringBuilder(e + \"\\n\");\n        for (StackTraceElement traceElement : arr) {\n            report.append(\"    at \").append(traceElement.toString()).append(\"\\n\");\n        }\n        Throwable cause = e;\n        while((cause = cause.getCause()) != null) {\n            report.append(\" Caused by: \").append(cause).append(\"\\n\");\n            arr = cause.getStackTrace();\n            for (StackTraceElement stackTraceElement : arr) {\n                report.append(\"   at \").append(stackTraceElement.toString()).append(\"\\n\");\n            }\n        }\n        report.append(\"\\nDevice Info:\\n\");\n        report.append(new DeviceInfo(mContext));\n        // Send notification\n        Intent i = new Intent(Intent.ACTION_SEND);\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {\n            i.setIdentifier(String.valueOf(System.currentTimeMillis()));\n        }\n        i.setType(\"text/plain\");\n        i.putExtra(Intent.EXTRA_EMAIL, new String[]{E});\n        i.putExtra(Intent.EXTRA_SUBJECT, \"App Manager: Crash report\");\n        String body = report.toString();\n        i.putExtra(Intent.EXTRA_TEXT, body);\n        PendingIntent pendingIntent = PendingIntentCompat.getActivity(mContext, 0,\n                Intent.createChooser(i, mContext.getText(R.string.send_crash_report)),\n                PendingIntent.FLAG_ONE_SHOT, true);\n        NotificationCompat.Builder builder = NotificationUtils.getHighPriorityNotificationBuilder(mContext)\n                .setAutoCancel(true)\n                .setDefaults(Notification.DEFAULT_ALL)\n                .setWhen(System.currentTimeMillis())\n                .setSmallIcon(R.drawable.ic_launcher_foreground)\n                .setTicker(mContext.getText(R.string.app_name))\n                .setContentTitle(mContext.getText(R.string.am_crashed))\n                .setContentText(mContext.getText(R.string.tap_to_submit_crash_report))\n                .setContentIntent(pendingIntent);\n        NotificationUtils.displayHighPriorityNotification(mContext, builder.build());\n        // Manage the rests via the default handler\n        mDefaultExceptionHandler.uncaughtException(t, e);\n    }\n}"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/misc/AdvancedSearchView.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.misc;\n\nimport static com.google.android.material.theme.overlay.MaterialThemeOverlay.wrap;\n\nimport android.annotation.SuppressLint;\nimport android.app.SearchableInfo;\nimport android.content.Context;\nimport android.content.res.TypedArray;\nimport android.graphics.Rect;\nimport android.graphics.drawable.Drawable;\nimport android.os.Parcel;\nimport android.os.Parcelable;\nimport android.text.Spannable;\nimport android.text.SpannableStringBuilder;\nimport android.text.style.ImageSpan;\nimport android.util.AttributeSet;\nimport android.view.Menu;\nimport android.view.View;\nimport android.widget.ImageView;\n\nimport androidx.annotation.IntDef;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.appcompat.widget.PopupMenu;\nimport androidx.customview.view.AbsSavedState;\n\nimport com.google.android.material.internal.ThemeEnforcement;\n\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.regex.Pattern;\nimport java.util.regex.PatternSyntaxException;\n\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.utils.ThreadUtils;\nimport io.github.muntashirakon.util.UiUtils;\nimport io.github.muntashirakon.widget.SearchView;\n\npublic class AdvancedSearchView extends SearchView {\n    @IntDef(flag = true, value = {\n            SEARCH_TYPE_CONTAINS,\n            SEARCH_TYPE_PREFIX,\n            SEARCH_TYPE_SUFFIX,\n            SEARCH_TYPE_REGEX})\n    @Retention(RetentionPolicy.SOURCE)\n    public @interface SearchType {\n    }\n\n    /**\n     * Search using {@link String#contains(CharSequence)}.\n     */\n    public static final int SEARCH_TYPE_CONTAINS = 1;\n    /**\n     * Search using {@link String#startsWith(String)}.\n     */\n    public static final int SEARCH_TYPE_PREFIX = 1 << 1;\n    /**\n     * Search using {@link String#endsWith(String)}.\n     */\n    public static final int SEARCH_TYPE_SUFFIX = 1 << 2;\n    /**\n     * Search using {@link String#matches(String)} or {@link java.util.regex.Pattern}.\n     */\n    public static final int SEARCH_TYPE_REGEX = 1 << 3;\n\n    private static final int DEF_STYLE_RES = io.github.muntashirakon.ui.R.style.Widget_AppTheme_SearchView;\n\n    @SearchType\n    private int mType = SEARCH_TYPE_CONTAINS;\n    @SearchType\n    private int mEnabledTypes = SEARCH_TYPE_CONTAINS | SEARCH_TYPE_PREFIX | SEARCH_TYPE_SUFFIX | SEARCH_TYPE_REGEX;\n    private CharSequence mQueryHint;\n    private final ImageView mSearchTypeSelectionButton;\n    private final SearchAutoComplete mSearchSrcTextView;\n    private final Drawable mSearchHintIcon;\n    @Nullable\n    private OnQueryTextListener mOnQueryTextListener;\n    @Nullable\n    private OnClickListener mOnSearchIconClickListener;\n    private final OnClickListener mOnSearchIconClickListenerSuper;\n    @Nullable\n    private OnFocusChangeListener mOnQueryTextFocusChangeListener;\n    private final OnFocusChangeListener mOnQueryTextFocusChangeListenerSuper;\n    private final SearchView.OnQueryTextListener mOnQueryTextListenerSuper = new SearchView.OnQueryTextListener() {\n        @Override\n        public boolean onQueryTextSubmit(String query) {\n            if (mOnQueryTextListener != null) {\n                return mOnQueryTextListener.onQueryTextSubmit(query, mType);\n            }\n            return false;\n        }\n\n        @Override\n        public boolean onQueryTextChange(String newText) {\n            if (mOnQueryTextListener != null) {\n                return mOnQueryTextListener.onQueryTextChange(newText, mType);\n            }\n            return false;\n        }\n    };\n    private final View.OnClickListener onClickSearchIcon = v -> {\n        PopupMenu popupMenu = new PopupMenu(getContext(), v);\n        popupMenu.inflate(R.menu.view_advanced_search_type_selections);\n        popupMenu.setOnMenuItemClickListener(item -> {\n            int id = item.getItemId();\n            if (id == R.id.action_search_type_contains) {\n                mType = SEARCH_TYPE_CONTAINS;\n            } else if (id == R.id.action_search_type_prefix) {\n                mType = SEARCH_TYPE_PREFIX;\n            } else if (id == R.id.action_search_type_suffix) {\n                mType = SEARCH_TYPE_SUFFIX;\n            } else if (id == R.id.action_search_type_regex) {\n                mType = SEARCH_TYPE_REGEX;\n            }\n            if (mOnQueryTextListener != null) {\n                mOnQueryTextListener.onQueryTextChange(getQuery().toString(), mType);\n            }\n            updateQueryHint();\n            return true;\n        });\n        Menu menu = popupMenu.getMenu();\n        if ((mEnabledTypes & SEARCH_TYPE_CONTAINS) == 0) {\n            menu.findItem(R.id.action_search_type_contains).setVisible(false);\n        }\n        if ((mEnabledTypes & SEARCH_TYPE_PREFIX) == 0) {\n            menu.findItem(R.id.action_search_type_prefix).setVisible(false);\n        }\n        if ((mEnabledTypes & SEARCH_TYPE_SUFFIX) == 0) {\n            menu.findItem(R.id.action_search_type_suffix).setVisible(false);\n        }\n        if ((mEnabledTypes & SEARCH_TYPE_REGEX) == 0) {\n            menu.findItem(R.id.action_search_type_regex).setVisible(false);\n        }\n        popupMenu.show();\n    };\n\n    public AdvancedSearchView(@NonNull Context context) {\n        this(context, null);\n    }\n\n    public AdvancedSearchView(@NonNull Context context, @Nullable AttributeSet attrs) {\n        this(context, attrs, androidx.appcompat.R.attr.searchViewStyle);\n    }\n\n    @SuppressLint(\"RestrictedApi\")\n    public AdvancedSearchView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {\n        super(wrap(context, attrs, defStyleAttr, DEF_STYLE_RES), attrs, defStyleAttr);\n        context = getContext();\n        mSearchSrcTextView = findViewById(androidx.appcompat.R.id.search_src_text);\n        mSearchTypeSelectionButton = findViewById(androidx.appcompat.R.id.search_mag_icon);\n        mSearchTypeSelectionButton.setImageResource(R.drawable.ic_filter_menu);\n        mSearchTypeSelectionButton.setBackground(UiUtils.getDrawable(context, android.R.attr.selectableItemBackgroundBorderless));\n        mSearchTypeSelectionButton.setOnClickListener(onClickSearchIcon);\n        final TypedArray a = ThemeEnforcement.obtainStyledAttributes(\n                context, attrs, io.github.muntashirakon.ui.R.styleable.SearchView, defStyleAttr, DEF_STYLE_RES);\n        mQueryHint = a.getText(io.github.muntashirakon.ui.R.styleable.SearchView_queryHint);\n        mSearchHintIcon = a.getDrawable(io.github.muntashirakon.ui.R.styleable.SearchView_searchHintIcon);\n        a.recycle();\n        setIconified(isIconified());\n        updateQueryHint();\n        mOnQueryTextFocusChangeListenerSuper = (v, hasFocus) -> {\n            v.postDelayed(() -> {\n                // This has to be like this because the {@link SearchAutoComplete#onFocusChanged(boolean, int, Rect)}\n                // has an issue.\n                // FIXME: 29/11/21 Override SearchAutoComplete and create a new search layout from the original to\n                //  include the overridden class\n                if (!isIconified()) {\n                    mSearchTypeSelectionButton.setVisibility(VISIBLE);\n                }\n            }, 1);\n            if (mOnQueryTextFocusChangeListener != null) {\n                mOnQueryTextFocusChangeListener.onFocusChange(v, hasFocus);\n            }\n        };\n        mOnSearchIconClickListenerSuper = v -> {\n            mSearchTypeSelectionButton.setVisibility(VISIBLE);\n            if (mOnSearchIconClickListener != null) {\n                mOnSearchIconClickListener.onClick(v);\n            }\n        };\n        mSearchSrcTextView.setOnFocusChangeListener(mOnQueryTextFocusChangeListenerSuper);\n        super.setOnSearchClickListener(mOnSearchIconClickListenerSuper);\n    }\n\n    protected static class SavedState extends AbsSavedState {\n        int type;\n        int enabledTypes;\n\n        SavedState(@NonNull Parcelable superState) {\n            super(superState);\n        }\n\n        public SavedState(@NonNull Parcel source, @Nullable ClassLoader loader) {\n            super(source, loader);\n            type = source.readInt();\n            enabledTypes = source.readInt();\n        }\n\n        @Override\n        public void writeToParcel(@NonNull Parcel dest, int flags) {\n            super.writeToParcel(dest, flags);\n            dest.writeInt(type);\n            dest.writeInt(enabledTypes);\n        }\n\n        @NonNull\n        @Override\n        public String toString() {\n            return \"AdvancedSearchView.SavedState{\"\n                    + Integer.toHexString(System.identityHashCode(this))\n                    + \" type=\" + type\n                    + \" enabledTypes=\" + enabledTypes + \"}\";\n        }\n\n        public static final Creator<SavedState> CREATOR = new ClassLoaderCreator<SavedState>() {\n            @Override\n            public SavedState createFromParcel(Parcel in, ClassLoader loader) {\n                return new SavedState(in, loader);\n            }\n\n            @Override\n            public SavedState createFromParcel(Parcel in) {\n                return new SavedState(in, null);\n            }\n\n            @Override\n            public SavedState[] newArray(int size) {\n                return new SavedState[size];\n            }\n        };\n    }\n\n    @Override\n    protected Parcelable onSaveInstanceState() {\n        Parcelable superState = super.onSaveInstanceState();\n        SavedState ss = new SavedState(superState);\n        ss.type = mType;\n        ss.enabledTypes = mEnabledTypes;\n        return ss;\n    }\n\n    @Override\n    protected void onRestoreInstanceState(Parcelable state) {\n        if (state instanceof SavedState) {\n            SavedState ss = (SavedState) state;\n            super.onRestoreInstanceState(ss.getSuperState());\n            mType = ss.type;\n            mEnabledTypes = ss.enabledTypes;\n        } else super.onRestoreInstanceState(state);\n        if (!isIconified()) mSearchTypeSelectionButton.setVisibility(VISIBLE);\n        updateQueryHint();\n        requestLayout();\n    }\n\n    @Override\n    public boolean requestFocus(int direction, Rect previouslyFocusedRect) {\n        boolean result = super.requestFocus(direction, previouslyFocusedRect);\n        if (result && !isIconified()) mSearchTypeSelectionButton.setVisibility(VISIBLE);\n        return result;\n    }\n\n    @Override\n    public void setOnQueryTextFocusChangeListener(OnFocusChangeListener listener) {\n        mOnQueryTextFocusChangeListener = listener;\n    }\n\n    public void setOnQueryTextListener(@Nullable OnQueryTextListener listener) {\n        if (listener == null) return;\n        mOnQueryTextListener = listener;\n        super.setOnQueryTextListener(mOnQueryTextListenerSuper);\n    }\n\n    /**\n     * @deprecated This method is ignored. Use {@link #setOnQueryTextListener(OnQueryTextListener)} instead.\n     */\n    @Override\n    public final void setOnQueryTextListener(SearchView.OnQueryTextListener listener) {\n        throw new UnsupportedOperationException(\"Wrong function. Use the other function by the same name.\");\n    }\n\n    @Override\n    public void setOnSearchClickListener(OnClickListener listener) {\n        mOnSearchIconClickListener = listener;\n    }\n\n    @Override\n    public void setIconifiedByDefault(boolean iconified) {\n        super.setIconifiedByDefault(iconified);\n        updateQueryHint();\n    }\n\n    @Override\n    public void setSearchableInfo(SearchableInfo searchable) {\n        super.setSearchableInfo(searchable);\n        if (!isIconified()) mSearchTypeSelectionButton.setVisibility(VISIBLE);\n    }\n\n    @Override\n    public void setSubmitButtonEnabled(boolean enabled) {\n        super.setSubmitButtonEnabled(enabled);\n        if (!isIconified()) mSearchTypeSelectionButton.setVisibility(VISIBLE);\n    }\n\n    @Override\n    public void setQueryHint(@Nullable CharSequence hint) {\n        super.setQueryHint(hint);\n        mQueryHint = hint;\n    }\n\n    public void setEnabledTypes(@SearchType int enabledTypes) {\n        this.mEnabledTypes = enabledTypes;\n        if (this.mEnabledTypes == 0) {\n            mEnabledTypes = SEARCH_TYPE_CONTAINS;\n        }\n    }\n\n    public void addEnabledTypes(@SearchType int enabledTypes) {\n        this.mEnabledTypes |= enabledTypes;\n    }\n\n    public void removeEnabledTypes(@SearchType int enabledTypes) {\n        this.mEnabledTypes &= ~enabledTypes;\n        if (this.mEnabledTypes == 0) {\n            mEnabledTypes = SEARCH_TYPE_CONTAINS;\n        }\n    }\n\n    public static boolean matches(@NonNull String query, @NonNull String text, @SearchType int type) {\n        switch (type) {\n            case SEARCH_TYPE_CONTAINS:\n                return text.contains(query);\n            case SEARCH_TYPE_PREFIX:\n                return text.startsWith(query);\n            case SEARCH_TYPE_SUFFIX:\n                return text.endsWith(query);\n            case SEARCH_TYPE_REGEX:\n                return text.matches(query);\n        }\n        return false;\n    }\n\n    public interface ChoiceGenerator<T> {\n        @Nullable\n        String getChoice(T object);\n    }\n\n    public interface ChoicesGenerator<T> {\n        List<String> getChoices(T object);\n    }\n\n    public static <T> List<T> matches(@NonNull String query, @Nullable Collection<T> choices,\n                                      @NonNull ChoiceGenerator<T> generator, @SearchType int type) {\n        if (choices == null) return null;\n        if (choices.size() == 0) return Collections.emptyList();\n        List<T> results = new ArrayList<>(choices.size());\n        if (type == SEARCH_TYPE_REGEX) {\n            Pattern p;\n            try {\n                p = Pattern.compile(query);\n                for (T choice : choices) {\n                    String text = generator.getChoice(choice);\n                    if (text == null) continue;\n                    if (p.matcher(text).find()) {\n                        results.add(choice);\n                    }\n                }\n            } catch (PatternSyntaxException ignore) {\n            }\n            return results;\n        }\n        // Rests are typical\n        for (T choice : choices) {\n            String text = generator.getChoice(choice);\n            if (text == null) continue;\n            if (matches(query, text, type)) {\n                results.add(choice);\n            }\n        }\n        return results;\n    }\n\n    public static <T> List<T> matches(@NonNull String query, @Nullable Collection<T> choices,\n                                      @NonNull ChoicesGenerator<T> generator, @SearchType int type) {\n        if (choices == null) return null;\n        if (choices.isEmpty()) return Collections.emptyList();\n        List<T> results = new ArrayList<>(choices.size());\n        if (type == SEARCH_TYPE_REGEX) {\n            Pattern p;\n            try {\n                p = Pattern.compile(query);\n                for (T choice : choices) {\n                    if (ThreadUtils.isInterrupted()) {\n                        return Collections.emptyList();\n                    }\n                    List<String> texts = generator.getChoices(choice);\n                    for (String text : texts) {\n                        if (text == null) continue;\n                        if (p.matcher(text).find()) {\n                            results.add(choice);\n                            break; // Only a single match is enough\n                        }\n                    }\n                }\n            } catch (PatternSyntaxException ignore) {\n            }\n            return results;\n        }\n        // Rests are typical\n        for (T choice : choices) {\n            if (ThreadUtils.isInterrupted()) {\n                return Collections.emptyList();\n            }\n            List<String> texts = generator.getChoices(choice);\n            for (String text : texts) {\n                if (text == null) continue;\n                if (matches(query, text, type)) {\n                    results.add(choice);\n                    break; // Only a single match is enough\n                }\n            }\n        }\n        return results;\n    }\n\n    private void updateQueryHint() {\n        CharSequence hintText = mQueryHint + \" (\" + getQueryHint(mType) + \")\";\n        if (!isIconfiedByDefault() && mSearchHintIcon != null) {\n            // Search icon isn't displayed when it is iconified by default.\n            final int textSize = (int) (mSearchSrcTextView.getTextSize() * 1.25);\n            mSearchHintIcon.setBounds(0, 0, textSize, textSize);\n\n            final SpannableStringBuilder ssb = new SpannableStringBuilder(\"   \");\n            ssb.setSpan(new ImageSpan(mSearchHintIcon), 1, 2, Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);\n            ssb.append(hintText);\n            super.setQueryHint(ssb);\n            return;\n        }\n        super.setQueryHint(hintText);\n    }\n\n    @NonNull\n    private CharSequence getQueryHint(@SearchType int type) {\n        switch (type) {\n            default:\n            case SEARCH_TYPE_CONTAINS:\n                return getContext().getString(R.string.search_type_contains);\n            case SEARCH_TYPE_PREFIX:\n                return getContext().getString(R.string.search_type_prefix);\n            case SEARCH_TYPE_REGEX:\n                return getContext().getString(R.string.search_type_regular_expressions);\n            case SEARCH_TYPE_SUFFIX:\n                return getContext().getString(R.string.search_type_suffix);\n        }\n    }\n\n    public interface OnQueryTextListener {\n        boolean onQueryTextChange(String newText, @SearchType int type);\n\n        boolean onQueryTextSubmit(String query, @SearchType int type);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/misc/DeviceInfo.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.misc;\n\nimport android.content.Context;\nimport android.content.pm.PackageInfo;\nimport android.content.pm.PackageManager;\nimport android.os.Build;\n\nimport androidx.annotation.IntRange;\nimport androidx.annotation.NonNull;\nimport androidx.core.content.pm.PackageInfoCompat;\n\nimport java.util.Arrays;\nimport java.util.Locale;\n\nimport io.github.muntashirakon.AppManager.settings.Ops;\nimport io.github.muntashirakon.AppManager.settings.Prefs;\n\npublic class DeviceInfo {\n    public final String[] abis = Build.SUPPORTED_ABIS;\n    public final String[] abis32Bits = Build.SUPPORTED_32_BIT_ABIS;\n    public final String[] abis64Bits = Build.SUPPORTED_64_BIT_ABIS;\n    public final String brand = Build.BRAND;\n    public final String buildID = Build.DISPLAY;\n    public final String buildVersion = Build.VERSION.INCREMENTAL;\n    public final String device = Build.DEVICE;\n    public final String hardware = Build.HARDWARE;\n    public final String manufacturer = Build.MANUFACTURER;\n    public final String model = Build.MODEL;\n    public final String product = Build.PRODUCT;\n    public final String releaseVersion = Build.VERSION.RELEASE;\n    @IntRange(from = 0)\n    public final int sdkVersion = Build.VERSION.SDK_INT;\n    public final long versionCode;\n    public final String versionName;\n    public final CharSequence inferredMode;\n\n    public DeviceInfo(@NonNull Context context) {\n        PackageInfo packageInfo;\n        try {\n            packageInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);\n        } catch (PackageManager.NameNotFoundException e) {\n            packageInfo = null;\n        }\n        if (packageInfo != null) {\n            versionCode = PackageInfoCompat.getLongVersionCode(packageInfo);\n            versionName = packageInfo.versionName;\n        } else {\n            versionCode = -1;\n            versionName = null;\n        }\n        inferredMode = Ops.getInferredMode(context);\n    }\n\n    @NonNull\n    @Override\n    public String toString() {\n        return \"App version: \" + versionName + \"\\n\"\n                + \"App version code: \" + versionCode + \"\\n\"\n                + \"Android build version: \" + buildVersion + \"\\n\"\n                + \"Android release version: \" + releaseVersion + \"\\n\"\n                + \"Android SDK version: \" + sdkVersion + \"\\n\"\n                + \"Android build ID: \" + buildID + \"\\n\"\n                + \"Device brand: \" + brand + \"\\n\"\n                + \"Device manufacturer: \" + manufacturer + \"\\n\"\n                + \"Device name: \" + device + \"\\n\"\n                + \"Device model: \" + model + \"\\n\"\n                + \"Device product name: \" + product + \"\\n\"\n                + \"Device hardware name: \" + hardware + \"\\n\"\n                + \"ABIs: \" + Arrays.toString(abis) + \"\\n\"\n                + \"ABIs (32bit): \" + Arrays.toString(abis32Bits) + \"\\n\"\n                + \"ABIs (64bit): \" + Arrays.toString(abis64Bits) + \"\\n\"\n                + \"System language: \" + Locale.getDefault().toLanguageTag() + \"\\n\"\n                + \"In-App Language: \" + Prefs.Appearance.getLanguage() + \"\\n\"\n                + \"Mode: \" + Ops.getMode() + \"\\n\"\n                + \"Inferred Mode: \" + inferredMode;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/misc/DeviceInfo2.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.misc;\n\nimport static io.github.muntashirakon.AppManager.utils.UIUtils.getStyledKeyValue;\nimport static io.github.muntashirakon.AppManager.utils.UIUtils.getTitleText;\n\nimport android.app.ActivityManager;\nimport android.content.BroadcastReceiver;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.IntentFilter;\nimport android.content.pm.ApplicationInfo;\nimport android.content.pm.FeatureInfo;\nimport android.content.pm.PackageManager;\nimport android.opengl.GLES20;\nimport android.os.BatteryManager;\nimport android.os.Build;\nimport android.os.Bundle;\nimport android.os.SELinux;\nimport android.os.UserHandleHidden;\nimport android.text.Spannable;\nimport android.text.SpannableStringBuilder;\nimport android.text.TextUtils;\nimport android.text.format.DateFormat;\nimport android.text.format.Formatter;\nimport android.util.DisplayMetrics;\nimport android.view.Display;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.RequiresApi;\nimport androidx.annotation.StringRes;\nimport androidx.annotation.WorkerThread;\nimport androidx.collection.ArrayMap;\nimport androidx.core.os.LocaleListCompat;\nimport androidx.core.util.Pair;\nimport androidx.fragment.app.FragmentActivity;\n\nimport com.android.internal.os.PowerProfile;\n\nimport java.security.Provider;\nimport java.security.Security;\nimport java.text.ParseException;\nimport java.text.SimpleDateFormat;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.Date;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Objects;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.TimeUnit;\n\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.StaticDataset;\nimport io.github.muntashirakon.AppManager.compat.PackageManagerCompat;\nimport io.github.muntashirakon.AppManager.misc.gles.EglCore;\nimport io.github.muntashirakon.AppManager.misc.gles.OffscreenSurface;\nimport io.github.muntashirakon.AppManager.runner.Runner;\nimport io.github.muntashirakon.AppManager.runner.RunnerUtils;\nimport io.github.muntashirakon.AppManager.users.UserInfo;\nimport io.github.muntashirakon.AppManager.users.Users;\nimport io.github.muntashirakon.AppManager.utils.ContextUtils;\nimport io.github.muntashirakon.AppManager.utils.CpuUtils;\nimport io.github.muntashirakon.AppManager.utils.TextUtilsCompat;\nimport io.github.muntashirakon.AppManager.utils.Utils;\nimport io.github.muntashirakon.proc.ProcFs;\nimport io.github.muntashirakon.util.LocalizedString;\n\npublic class DeviceInfo2 implements LocalizedString {\n    public final String osVersion = Build.VERSION.RELEASE;\n    public final String bootloader = Build.BOOTLOADER;\n    public final String vm = getVmVersion();\n    public final String kernel = getKernel();\n    public final String brandName = Build.BRAND;\n    public final String model = Build.MODEL;\n    public final String board = Build.BOARD;\n    public final String manufacturer = Build.MANUFACTURER;\n    // SDK\n    public final int maxSdk = Build.VERSION.SDK_INT;\n    public final int minSdk = SystemProperties.getInt(\"ro.build.version.min_supported_target_sdk\", 0);\n    // Security\n    public boolean hasRoot;\n    public int selinux;\n    public String encryptionStatus;\n    public String dmVerity; // enforcing, disabled, eio, ...\n    @Nullable\n    public String verifiedBootState; // green (verified), yellow (self-signed), orange (unverified), red (failed) ?: orange (unverified)\n    public String verifiedBootStateString;\n    public String avbVersion;\n    public String bootloaderState;\n    public boolean debuggable;\n    public final String patchLevel;\n    public final Provider[] securityProviders = Security.getProviders();\n    public final String hardwareBackedFeatures;\n    public final String strongBoxBackedFeatures;\n    // CPU Info\n    @Nullable\n    public String cpuHardware;\n    public final String[] supportedAbis = Build.SUPPORTED_ABIS;\n    public int availableProcessors;\n    public String openGlEsVersion;\n    @Nullable\n    public String vulkanVersion;\n    // Memory\n    public final ActivityManager.MemoryInfo memoryInfo = new ActivityManager.MemoryInfo();\n    // Battery\n    public boolean batteryPresent;\n    public double batteryCapacityMAh;\n    public double batteryCapacityMAhAlt;\n    @Nullable\n    public String batteryTechnology;\n    public int batteryCycleCount;\n    public String batteryHealth;\n    // Display\n    public final int displayDensityDpi = StaticDataset.DEVICE_DENSITY;\n    public final String displayDensity = getDensity();\n    public float scalingFactor;\n    public int actualWidthPx;\n    public int actualHeightPx;\n    public int windowWidthPx;\n    public int windowHeightPx;\n    public float refreshRate;\n    // Locales\n    public final LocaleListCompat systemLocales = LocaleListCompat.getDefault();\n    // Users\n    @Nullable\n    public List<UserInfo> users;\n    // Packages\n    public ArrayMap<Integer, Pair<Integer, Integer>> userPackages = new ArrayMap<>(1);\n    // Features\n    public FeatureInfo[] features;\n\n    private final FragmentActivity mActivity;\n    private final ActivityManager mActivityManager;\n    private final PackageManager mPm;\n    private final Display mDisplay;\n\n    public DeviceInfo2(@NonNull FragmentActivity activity) {\n        this.mActivity = activity;\n        mActivityManager = (ActivityManager) activity.getSystemService(Context.ACTIVITY_SERVICE);\n        mPm = activity.getPackageManager();\n        mDisplay = getDisplay();\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {\n            patchLevel = getSecurityPatch();\n        } else patchLevel = null;\n        features = mPm.getSystemAvailableFeatures();\n        hardwareBackedFeatures = getHardwareBackedFeatures();\n        strongBoxBackedFeatures = getStrongBoxBackedFeatures();\n    }\n\n    @WorkerThread\n    public void loadInfo() {\n        hasRoot = RunnerUtils.isRootAvailable();\n        selinux = getSelinuxStatus();\n        encryptionStatus = getEncryptionStatus();\n        if (mPm.hasSystemFeature(PackageManager.FEATURE_VERIFIED_BOOT)) {\n            verifiedBootState = SystemProperties.get(\"ro.boot.verifiedbootstate\", \"\");\n            verifiedBootStateString = getVerifiedBootStateString(verifiedBootState);\n            dmVerity = SystemProperties.get(\"ro.boot.veritymode\", \"\");\n            avbVersion = SystemProperties.get(\"ro.boot.avb_version\", \"\");\n            bootloaderState = SystemProperties.get(\"ro.boot.vbmeta.device_state\", \"\");\n        } else verifiedBootState = null;\n        debuggable = \"1\".equals(SystemProperties.get(\"ro.debuggable\", \"0\"));\n        cpuHardware = getCpuHardware();\n        availableProcessors = Runtime.getRuntime().availableProcessors();\n        openGlEsVersion = Utils.getGlEsVersion(mActivityManager.getDeviceConfigurationInfo().reqGlEsVersion);\n        vulkanVersion = Utils.getVulkanVersion(mPm);\n        mActivityManager.getMemoryInfo(memoryInfo);\n        getBatteryStats(mActivity);\n        DisplayMetrics displayMetrics = new DisplayMetrics();\n        // Actual size\n        mDisplay.getRealMetrics(displayMetrics);\n        scalingFactor = displayMetrics.density;\n        actualWidthPx = displayMetrics.widthPixels;\n        actualHeightPx = displayMetrics.heightPixels;\n        // Window size\n        mDisplay.getMetrics(displayMetrics);\n        windowWidthPx = displayMetrics.widthPixels;\n        windowHeightPx = displayMetrics.heightPixels;\n        refreshRate = mDisplay.getRefreshRate();\n        users = Users.getAllUsers();\n        for (UserInfo info : users) {\n            userPackages.put(info.id, getPackageStats(info.id));\n        }\n    }\n\n    @Override\n    @NonNull\n    public CharSequence toLocalizedString(@NonNull Context ctx) {\n        SpannableStringBuilder builder = new SpannableStringBuilder();\n        // Android platform info\n        builder.append(getStyledKeyValue(ctx, R.string.os_version, osVersion)).append(\", \")\n                .append(getStyledKeyValue(ctx, \"Build\", Build.DISPLAY)).append(\"\\n\")\n                .append(getStyledKeyValue(ctx, R.string.bootloader, bootloader)).append(\", \")\n                .append(getStyledKeyValue(ctx, \"VM\", vm)).append(\"\\n\")\n                .append(getStyledKeyValue(ctx, R.string.kernel, kernel)).append(\"\\n\")\n                .append(getStyledKeyValue(ctx, R.string.brand_name, brandName)).append(\", \")\n                .append(getStyledKeyValue(ctx, R.string.model, model)).append(\"\\n\")\n                .append(getStyledKeyValue(ctx, R.string.board_name, board)).append(\", \")\n                .append(getStyledKeyValue(ctx, R.string.manufacturer, manufacturer)).append(\"\\n\");\n        // SDK\n        builder.append(\"\\n\").append(getTitleText(ctx, R.string.sdk)).append(\"\\n\")\n                .append(getStyledKeyValue(ctx, R.string.sdk_max, String.format(Locale.getDefault(), \"%d\", maxSdk)));\n        if (minSdk != 0) {\n            builder.append(\", \").append(getStyledKeyValue(ctx, R.string.sdk_min, String.format(Locale.getDefault(), \"%d\", minSdk)));\n        }\n        builder.append(\"\\n\");\n        // Security\n        builder.append(\"\\n\").append(getTitleText(ctx, R.string.security)).append(\"\\n\");\n        if (patchLevel != null) {\n            builder.append(getStyledKeyValue(ctx, R.string.patch_level, patchLevel)).append(\"\\n\");\n        }\n        builder.append(getStyledKeyValue(ctx, R.string.root, String.valueOf(hasRoot))).append(\", \")\n                .append(getStyledKeyValue(ctx, R.string.debuggable, String.valueOf(debuggable)))\n                .append(\"\\n\");\n        if (selinux != 2) {\n            builder.append(getStyledKeyValue(ctx, R.string.selinux, getString(selinux == 1 ?\n                    R.string.enforcing : R.string.permissive))).append(\", \");\n        }\n        builder.append(getStyledKeyValue(ctx, R.string.encryption, encryptionStatus)).append(\"\\n\");\n        boolean verifiedBoot = false;\n        if (!TextUtils.isEmpty(verifiedBootState)) {\n            verifiedBoot = true;\n            builder.append(getStyledKeyValue(ctx, R.string.verified_boot, verifiedBootState))\n                    .append(\" (\").append(verifiedBootStateString).append(\")\");\n        }\n        if (!TextUtils.isEmpty(avbVersion)) {\n            if (verifiedBoot) {\n                builder.append(\", \");\n            }\n            builder.append(getStyledKeyValue(ctx, R.string.android_verified_bootloader_version, avbVersion)).append(\"\\n\");\n        } else if (verifiedBoot) {\n            builder.append(\"\\n\");\n        }\n        boolean isDmVerity = false;\n        if (!TextUtils.isEmpty(dmVerity)) {\n            isDmVerity = true;\n            builder.append(getStyledKeyValue(ctx, \"dm-verity\", dmVerity));\n        }\n        if (!TextUtils.isEmpty(bootloaderState)) {\n            if (isDmVerity) {\n                builder.append(\", \");\n            }\n            builder.append(getStyledKeyValue(ctx, R.string.bootloader, bootloaderState)).append(\"\\n\");\n        } else if (isDmVerity) {\n            builder.append(\"\\n\");\n        }\n        List<CharSequence> securityProviders = new ArrayList<>();\n        boolean hasAndroidKeyStore = false;\n        for (Provider provider : this.securityProviders) {\n            if (\"AndroidKeyStore\".equals(provider.getName())) {\n                hasAndroidKeyStore = true;\n            }\n            securityProviders.add(provider.getName() + \" (v\" + provider.getVersion() + \")\");\n        }\n        builder.append(getStyledKeyValue(ctx, R.string.security_providers,\n                TextUtilsCompat.joinSpannable(\", \", securityProviders))).append(\".\\n\");\n        // Android KeyStore\n        if (hasAndroidKeyStore) {\n            builder.append(\"\\n\").append(getTitleText(ctx, \"Android KeyStore\")).append(\"\\n\");\n        }\n        StringBuilder sb = new StringBuilder(\"Software\");\n        if (hardwareBackedFeatures != null) {\n            sb.append(\", Hardware\");\n        }\n        if (strongBoxBackedFeatures != null) {\n            sb.append(\", StrongBox\");\n        }\n        builder.append(getStyledKeyValue(ctx, R.string.features, sb)).append(\"\\n\");\n        if (hardwareBackedFeatures != null) {\n            builder.append(\"   \").append(getStyledKeyValue(ctx, \"Hardware\", hardwareBackedFeatures)).append(\"\\n\");\n        }\n        if (strongBoxBackedFeatures != null) {\n            builder.append(\"   \").append(getStyledKeyValue(ctx, \"StrongBox\", strongBoxBackedFeatures)).append(\"\\n\");\n        }\n        // CPU info\n        builder.append(\"\\n\").append(getTitleText(ctx, R.string.cpu)).append(\"\\n\");\n        if (cpuHardware != null) {\n            builder.append(getStyledKeyValue(ctx, R.string.hardware, cpuHardware)).append(\"\\n\");\n        }\n        builder.append(getStyledKeyValue(ctx, R.string.support_architectures,\n                        TextUtils.join(\", \", supportedAbis))).append(\"\\n\")\n                .append(getStyledKeyValue(ctx, R.string.no_of_cores, String.format(Locale.getDefault(), \"%d\",\n                        availableProcessors))).append(\"\\n\");\n        // GPU info\n        builder.append(\"\\n\").append(getTitleText(ctx, R.string.graphics)).append(\"\\n\")\n                .append(getGlInfo(ctx))\n                .append(getStyledKeyValue(ctx, R.string.gles_version, openGlEsVersion)).append(\"\\n\");\n        if (vulkanVersion != null) {\n            builder.append(getStyledKeyValue(ctx, R.string.vulkan_version, vulkanVersion)).append(\"\\n\");\n        }\n        // RAM info\n        builder.append(\"\\n\").append(getTitleText(ctx, R.string.memory)).append(\"\\n\")\n                .append(Formatter.formatFileSize(ctx, memoryInfo.totalMem)).append(\"\\n\");\n        // Battery info\n        if (batteryPresent || batteryCapacityMAh > 0) {\n            builder.append(\"\\n\").append(getTitleText(ctx, R.string.battery)).append(\"\\n\");\n            if (batteryTechnology != null) {\n                builder.append(getStyledKeyValue(ctx, R.string.battery_technology, batteryTechnology))\n                        .append(\"\\n\");\n            }\n            if (batteryCapacityMAh > 0) {\n                builder.append(getStyledKeyValue(ctx, R.string.battery_capacity, String.valueOf(batteryCapacityMAh)))\n                        .append(\" mAh\");\n                if (batteryCapacityMAhAlt > 0) {\n                    builder.append(\" (est. \")\n                            .append(String.format(Locale.ROOT, \"%.1f\", batteryCapacityMAhAlt))\n                            .append(\" mAh)\");\n                }\n                builder.append(\"\\n\");\n            } else if (batteryCapacityMAhAlt > 0) {\n                builder.append(getStyledKeyValue(ctx, R.string.battery_capacity, String.format(Locale.ROOT, \"%.1f\", batteryCapacityMAhAlt)))\n                        .append(\" mAh (est.)\").append(\"\\n\");\n            }\n            if (batteryHealth != null) {\n                builder.append(getStyledKeyValue(ctx, R.string.battery_health, batteryHealth));\n                if (batteryCycleCount > 0) {\n                    builder.append(\" (\").append(String.valueOf(batteryCycleCount)).append(\" cycles)\");\n                }\n                builder.append(\"\\n\");\n            }\n        }\n        // Screen resolution\n        builder.append(\"\\n\").append(getTitleText(ctx, R.string.screen)).append(\"\\n\")\n                .append(getStyledKeyValue(ctx, R.string.density, String.format(Locale.getDefault(), \"%s (%d DPI)\",\n                        displayDensity, displayDensityDpi))).append(\"\\n\");\n        // Actual size\n        builder.append(getStyledKeyValue(ctx, R.string.scaling_factor, String.valueOf(scalingFactor))).append(\"\\n\")\n                .append(getStyledKeyValue(ctx, R.string.size, actualWidthPx + \"px × \" + actualHeightPx + \"px\\n\"));\n        // Window size\n        builder.append(getStyledKeyValue(ctx, R.string.window_size, windowWidthPx + \"px × \" + windowHeightPx\n                + \"px\\n\"));\n        // Refresh rate\n        builder.append(getStyledKeyValue(ctx, R.string.refresh_rate, String.format(Locale.getDefault(), \"%.1f Hz\",\n                refreshRate))).append(\"\\n\");\n        // List system locales\n        List<String> localeStrings = new ArrayList<>(systemLocales.size());\n        for (int i = 0; i < systemLocales.size(); ++i) {\n            localeStrings.add(Objects.requireNonNull(systemLocales.get(i)).getDisplayName());\n        }\n        builder.append(\"\\n\").append(getTitleText(ctx, R.string.languages))\n                .append(\"\\n\").append(TextUtilsCompat.joinSpannable(\", \", localeStrings))\n                .append(\"\\n\");\n        if (users != null) {\n            // Users\n            builder.append(\"\\n\").append(getTitleText(ctx, R.string.users))\n                    .append(\"\\n\");\n            List<String> userNames = new ArrayList<>();\n            for (UserInfo user : users) {\n                userNames.add(user.name != null ? user.name : String.valueOf(user.id));\n            }\n            builder.append(String.format(Locale.getDefault(), \"%d\", users.size())).append(\" (\")\n                    .append(TextUtilsCompat.joinSpannable(\", \", userNames))\n                    .append(\")\\n\");\n            // App stats per user\n            builder.append(\"\\n\").append(getTitleText(ctx, R.string.apps)).append(\"\\n\");\n            for (UserInfo user : users) {\n                Pair<Integer, Integer> packageSizes = userPackages.get(user.id);\n                if (packageSizes == null) continue;\n                if (packageSizes.first + packageSizes.second == 0) continue;\n                builder.append(getStyledKeyValue(ctx, R.string.user, user.toLocalizedString(ctx))).append(\"\\n   \")\n                        .append(getStyledKeyValue(ctx, R.string.total_size, String.format(Locale.getDefault(), \"%d\",\n                                packageSizes.first + packageSizes.second))).append(\", \")\n                        .append(getStyledKeyValue(ctx, R.string.user, String.format(Locale.getDefault(), \"%d\",\n                                packageSizes.first))).append(\", \")\n                        .append(getStyledKeyValue(ctx, R.string.system, String.format(Locale.getDefault(), \"%d\",\n                                packageSizes.second)))\n                        .append(\"\\n\");\n            }\n        } else {\n            builder.append(\"\\n\").append(getTitleText(ctx, R.string.apps)).append(\"\\n\");\n            Pair<Integer, Integer> packageSizes = userPackages.get(UserHandleHidden.myUserId());\n            if (packageSizes != null) {\n                builder.append(getStyledKeyValue(ctx, R.string.total_size, String.format(Locale.getDefault(), \"%d\",\n                                packageSizes.first + packageSizes.second))).append(\", \")\n                        .append(getStyledKeyValue(ctx, R.string.user, String.format(Locale.getDefault(), \"%d\",\n                                packageSizes.first))).append(\", \")\n                        .append(getStyledKeyValue(ctx, R.string.system, String.format(Locale.getDefault(), \"%d\",\n                                packageSizes.second)))\n                        .append(\"\\n\");\n            }\n        }\n        // List available hardware/features\n        builder.append(\"\\n\").append(getTitleText(ctx, R.string.features)).append(\"\\n\");\n        List<CharSequence> featureStrings = new ArrayList<>(features.length);\n        for (FeatureInfo info : features) {\n            if (info.name != null) {\n                // It's a feature\n                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && info.version != 0) {\n                    featureStrings.add(info.name + \" (v\" + info.version + \")\");\n                } else featureStrings.add(info.name);\n            }\n        }\n        Collections.sort(featureStrings, (o1, o2) -> o1.toString().compareToIgnoreCase(o2.toString()));\n        builder.append(TextUtilsCompat.joinSpannable(\"\\n\", featureStrings)).append(\"\\n\");\n        return builder;\n    }\n\n    /**\n     * Queries EGL/GL for information, then formats it all into one giant string.\n     */\n    @NonNull\n    private Spannable getGlInfo(@NonNull Context ctx) {\n        // We need a GL context to examine, which means we need an EGL surface. Create a 1x1 pbuffer.\n        EglCore eglCore = new EglCore();\n        OffscreenSurface surface = new OffscreenSurface(eglCore, 1, 1);\n        surface.makeCurrent();\n\n        String gpu = GLES20.glGetString(GLES20.GL_VENDOR) + \" \" + GLES20.glGetString(GLES20.GL_RENDERER);\n        SpannableStringBuilder sb = new SpannableStringBuilder();\n        sb.append(getStyledKeyValue(ctx, \"GPU\", gpu)).append(\"\\n\");\n        // sb.append(formatExtensions(GLES20.glGetString(GLES20.GL_EXTENSIONS)));\n\n        surface.release();\n        eglCore.release();\n\n        return sb;\n    }\n\n//    private String formatExtensions(@NonNull String ext) {\n//        String[] values = ext.split(\" \");\n//        Arrays.sort(values);\n//        StringBuilder sb = new StringBuilder();\n//        for (String value : values) {\n//            sb.append(\"  \");\n//            sb.append(value);\n//            sb.append(\"\\n\");\n//        }\n//        return sb.toString();\n//    }\n\n    private CountDownLatch mBatteryStatusLock;\n    @Nullable\n    private Bundle mBatteryStatusBundle;\n    private final BroadcastReceiver mBatteryStatusReceiver = new BroadcastReceiver() {\n        @Override\n        public void onReceive(Context context, Intent intent) {\n            if (mBatteryStatusLock != null) {\n                mBatteryStatusLock.countDown();\n            }\n            mBatteryStatusBundle = intent.getExtras();\n        }\n    };\n\n    @WorkerThread\n    private void getBatteryStats(Context ctx) {\n        batteryCapacityMAh = new PowerProfile(ContextUtils.getContext()).getBatteryCapacity();\n        IntentFilter filter = new IntentFilter(Intent.ACTION_BATTERY_CHANGED);\n        Intent data = ctx.registerReceiver(mBatteryStatusReceiver, filter);\n        if (data != null) {\n            mBatteryStatusBundle = data.getExtras();\n        }\n        if (mBatteryStatusBundle == null) {\n            // fallback to old method\n            mBatteryStatusLock = new CountDownLatch(1);\n            try {\n                if (!mBatteryStatusLock.await(10, TimeUnit.SECONDS)) {\n                    throw new InterruptedException();\n                }\n            } catch (InterruptedException e) {\n                throw new RuntimeException(e);\n            }\n        }\n        ctx.unregisterReceiver(mBatteryStatusReceiver);\n        if (mBatteryStatusBundle != null) {\n            batteryPresent = mBatteryStatusBundle.getBoolean(BatteryManager.EXTRA_PRESENT);\n            batteryTechnology = mBatteryStatusBundle.getString(BatteryManager.EXTRA_TECHNOLOGY);\n            int batteryCapacityUAh = mBatteryStatusBundle.getInt(\"charge_counter\", 0);\n            if (batteryCapacityUAh != 0) {\n                batteryCapacityMAhAlt = batteryCapacityUAh / 1000.;\n                // This is the current capacity, calculate the actual capacity using the battery\n                // percentage\n                int level = mBatteryStatusBundle.getInt(BatteryManager.EXTRA_LEVEL, 0);\n                int scale = mBatteryStatusBundle.getInt(BatteryManager.EXTRA_SCALE, 0);\n                double batteryPercent = scale > 0 ? (level * 100. / scale) : 0;\n                if (batteryPercent > 0) {\n                    batteryCapacityMAhAlt = (batteryCapacityMAhAlt * 100. / batteryPercent);\n                }\n            }\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {\n                batteryCycleCount = mBatteryStatusBundle.getInt(BatteryManager.EXTRA_CYCLE_COUNT, 0);\n            }\n            int health = mBatteryStatusBundle.getInt(BatteryManager.EXTRA_HEALTH, BatteryManager.BATTERY_HEALTH_UNKNOWN);\n            switch (health) {\n                case BatteryManager.BATTERY_HEALTH_GOOD:\n                    batteryHealth = \"Good\";\n                    break;\n                case BatteryManager.BATTERY_HEALTH_OVERHEAT:\n                    batteryHealth = \"Overheat\";\n                    break;\n                case BatteryManager.BATTERY_HEALTH_DEAD:\n                    batteryHealth = \"Dead\";\n                    break;\n                case BatteryManager.BATTERY_HEALTH_OVER_VOLTAGE:\n                    batteryHealth = \"Over voltage\";\n                    break;\n                case BatteryManager.BATTERY_HEALTH_UNSPECIFIED_FAILURE:\n                    batteryHealth = \"failure\";\n                    break;\n                case BatteryManager.BATTERY_HEALTH_COLD:\n                    batteryHealth = \"Cold\";\n                    break;\n                default:\n                    batteryHealth = \"Unknown\";\n            }\n        }\n    }\n\n    @NonNull\n    private Display getDisplay() {\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {\n            return Objects.requireNonNull(mActivity.getDisplay());\n        } else {\n            //noinspection deprecation\n            return mActivity.getWindowManager().getDefaultDisplay();\n        }\n    }\n\n    private String getDensity() {\n        int dpi = StaticDataset.DEVICE_DENSITY;\n        int smallestDiff = Integer.MAX_VALUE;\n        String density = StaticDataset.XXXHDPI;\n        // Find the smallest\n        for (int i = 0; i < StaticDataset.DENSITY_NAME_TO_DENSITY.size(); ++i) {\n            int diff = Math.abs(dpi - StaticDataset.DENSITY_NAME_TO_DENSITY.valueAt(i));\n            if (diff < smallestDiff) {\n                smallestDiff = diff;\n                density = StaticDataset.DENSITY_NAME_TO_DENSITY.keyAt(i);\n            }\n        }\n        return density;\n    }\n\n    @NonNull\n    private String getVmVersion() {\n        String vm = \"Dalvik\";\n        String vmVersion = System.getProperty(\"java.vm.version\");\n        if (vmVersion != null && vmVersion.startsWith(\"2\")) {\n            vm = \"ART\";\n        }\n        return vm;\n    }\n\n    @NonNull\n    private String getKernel() {\n        String kernel = System.getProperty(\"os.version\");\n        if (kernel == null) return \"\";\n        else return kernel;\n    }\n\n    @Nullable\n    @RequiresApi(Build.VERSION_CODES.M)\n    public static String getSecurityPatch() {\n        String patch = Build.VERSION.SECURITY_PATCH;\n        if (!\"\".equals(patch)) {\n            try {\n                SimpleDateFormat template = new SimpleDateFormat(\"yyyy-MM-dd\", Locale.ROOT);\n                Date patchDate = template.parse(patch);\n                String format = DateFormat.getBestDateTimePattern(Locale.getDefault(), \"dMMMMyyyy\");\n                patch = DateFormat.format(format, patchDate).toString();\n            } catch (ParseException e) {\n                // broken parse; fall through and use the raw string\n            }\n            return patch;\n        } else {\n            return null;\n        }\n    }\n\n    @WorkerThread\n    private int getSelinuxStatus() {\n        if (SELinux.isSELinuxEnabled()) {\n            // if (SELinux.isSELinuxEnforced()) {\n            //    return 1;\n            // }\n            Runner.Result result = Runner.runCommand(\"getenforce\");\n            if (result.isSuccessful() && result.getOutput().trim().equals(\"Permissive\")) {\n                return 0;\n            }\n            // SELinux enabled, but cannot access result means it is \"Enforcing\"\n            return 1;\n        }\n        // Disabled\n        return 2;\n    }\n\n    @NonNull\n    private String getEncryptionStatus() {\n        String state = SystemProperties.get(\"ro.crypto.state\", \"\");\n        if (\"encrypted\".equals(state)) {\n            String encryptedMsg = getString(R.string.encrypted);\n            String type = SystemProperties.get(\"ro.crypto.type\", \"\");\n            if (\"file\".equals(type)) return encryptedMsg + \" (FBE)\";\n            else if (\"block\".equals(type)) return encryptedMsg + \" (FDE)\";\n            else return encryptedMsg;\n        } else if (\"unencrypted\".equals(state)) {\n            return getString(R.string.unencrypted);\n        } else return getString(R.string.state_unknown);\n    }\n\n    @NonNull\n    private String getVerifiedBootStateString(@NonNull String color) {\n        switch (color) {\n            case \"green\":\n                return \"verified\";\n            case \"yellow\":\n                return \"self-signed\";\n            case \"red\":\n                return \"failed\";\n            case \"orange\":\n            default:\n                return \"unverified\";\n        }\n    }\n\n    @Nullable\n    private String getHardwareBackedFeatures() {\n        // We use string instead of PackageManager.FEATURE_HARDWARE_KEYSTORE because it may present\n        // in older devices.\n        FeatureInfo f = getFeature(\"android.hardware.hardware_keystore\");\n        if (f == null) {\n            return null;\n        }\n        int version;\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {\n            version = f.version;\n        } else version = 0;\n        if (version < 40) {\n            return getString(R.string.state_unknown);\n        }\n        StringBuilder sb = new StringBuilder();\n        sb.append(\"AES, HMAC, ECDSA, RSA\");\n        if (version >= 100) {\n            sb.append(\", ECDH\");\n        }\n        if (version >= 200) {\n            sb.append(\", Curve 25519\");\n        }\n        return sb.toString();\n    }\n\n    @Nullable\n    private String getStrongBoxBackedFeatures() {\n        // We use string instead of PackageManager.FEATURE_STRONGBOX_KEYSTORE because it may present\n        // in older devices.\n        FeatureInfo f = getFeature(\"android.hardware.strongbox_keystore\");\n        if (f == null) {\n            return null;\n        }\n        int version;\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {\n            version = f.version;\n        } else version = 0;\n        if (version < 40) {\n            return getString(R.string.state_unknown);\n        }\n        StringBuilder sb = new StringBuilder();\n        sb.append(\"AES, HMAC, ECDSA, RSA\");\n        if (version >= 100) {\n            sb.append(\", ECDH\");\n        }\n        return sb.toString();\n    }\n\n    @Nullable\n    private FeatureInfo getFeature(@NonNull String feature) {\n        for (FeatureInfo info : features) {\n            if (feature.equals(info.name)) {\n                return info;\n            }\n        }\n        return null;\n    }\n\n    @Nullable\n    private String getCpuHardware() {\n        String model = CpuUtils.getCpuModel();\n        if (model == null) {\n            // ARM: fallback to /proc/cpuinfo\n            model = ProcFs.getInstance().getCpuInfoHardware();\n        }\n        if (model == null) {\n            // fallback to Android properties\n            String part1 = SystemProperties.get(\"ro.soc.manufacturer\", \"\");\n            String part2 = SystemProperties.get(\"ro.soc.model\", \"\");\n            if (!part2.isEmpty()) {\n                return part1 + (!part1.isEmpty() ? \" \" : \"\") + part2;\n            }\n            model = SystemProperties.get(\"ro.board.platform\", \"\");\n        }\n        return !model.isEmpty() ? model : null;\n    }\n\n    // User + System apps\n    @NonNull\n    private Pair<Integer, Integer> getPackageStats(int userHandle) {\n        int systemApps = 0;\n        int userApps = 0;\n        try {\n            List<ApplicationInfo> applicationInfoList = PackageManagerCompat.getInstalledApplications(PackageManagerCompat.MATCH_STATIC_SHARED_AND_SDK_LIBRARIES, userHandle);\n            for (ApplicationInfo info : applicationInfoList) {\n                if ((info.flags & ApplicationInfo.FLAG_SYSTEM) == 1) {\n                    ++systemApps;\n                } else ++userApps;\n            }\n        } catch (Throwable e) {\n            e.printStackTrace();\n        }\n        return new Pair<>(userApps, systemApps);\n    }\n\n    private String getString(@StringRes int strRes) {\n        return mActivity.getString(strRes);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/misc/HelpActivity.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.misc;\n\nimport android.content.Intent;\nimport android.content.pm.PackageManager;\nimport android.net.Uri;\nimport android.os.Bundle;\nimport android.view.Menu;\nimport android.view.MenuItem;\nimport android.view.View;\nimport android.webkit.WebResourceRequest;\nimport android.webkit.WebView;\nimport android.widget.Button;\n\nimport androidx.activity.OnBackPressedCallback;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.appcompat.app.ActionBar;\nimport androidx.appcompat.widget.LinearLayoutCompat;\nimport androidx.appcompat.widget.SearchView;\nimport androidx.transition.Transition;\nimport androidx.transition.TransitionManager;\nimport androidx.webkit.WebViewClientCompat;\n\nimport com.google.android.material.transition.MaterialSharedAxis;\n\nimport io.github.muntashirakon.AppManager.BaseActivity;\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.utils.ResourceUtil;\nimport io.github.muntashirakon.AppManager.utils.appearance.AppearanceUtils;\nimport io.github.muntashirakon.util.UiUtils;\nimport me.zhanghai.android.fastscroll.FastScrollerBuilder;\n\npublic class HelpActivity extends BaseActivity implements SearchView.OnQueryTextListener {\n    private LinearLayoutCompat mContainer;\n    private WebView mWebView;\n    private LinearLayoutCompat mSearchContainer;\n    private SearchView mSearchView;\n    private final OnBackPressedCallback mOnBackPressedCallback = new OnBackPressedCallback(false) {\n        @Override\n        public void handleOnBackPressed() {\n            if (mWebView.canGoBack()) {\n                mWebView.goBack();\n                return;\n            }\n            setEnabled(false);\n            getOnBackPressedDispatcher().onBackPressed();\n        }\n    };\n\n    @Override\n    protected void onAuthenticated(@Nullable Bundle savedInstanceState) {\n        try {\n            setContentView(R.layout.activity_help);\n        } catch (Throwable th) {\n            openDocsSite();\n            return;\n        }\n        setSupportActionBar(findViewById(R.id.toolbar));\n        getOnBackPressedDispatcher().addCallback(this, mOnBackPressedCallback);\n        ActionBar actionBar = getSupportActionBar();\n        if (actionBar != null) actionBar.setTitle(R.string.user_manual);\n        findViewById(R.id.progress_linear).setVisibility(View.GONE);\n        // Check if docs are available\n        if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_WEBVIEW)\n                || ResourceUtil.getRawDataId(this, \"index\") == 0) {\n            // Docs split not installed\n            openDocsSite();\n            return;\n        }\n        mContainer = findViewById(R.id.container);\n        mWebView = findViewById(R.id.webview);\n        UiUtils.applyWindowInsetsAsPaddingNoTop(mContainer);\n\n        // Fix locale issue due to WebView (https://issuetracker.google.com/issues/37113860)\n        AppearanceUtils.applyOnlyLocale(this);\n\n        mWebView.setWebViewClient(new WebViewClientImpl());\n        mWebView.setNetworkAvailable(false);\n        mWebView.getSettings().setAllowContentAccess(false);\n        mWebView.loadUrl(\"file:///android_res/raw/index.html\");\n\n        mSearchContainer = findViewById(R.id.search_container);\n        Button nextButton = findViewById(R.id.next_button);\n        Button previousButton = findViewById(R.id.previous_button);\n        mSearchView = findViewById(R.id.search_bar);\n        mSearchView.findViewById(androidx.appcompat.R.id.search_close_btn).setOnClickListener(v -> {\n            mWebView.clearMatches();\n            mSearchView.setQuery(null, false);\n            Transition sharedAxis = new MaterialSharedAxis(MaterialSharedAxis.Y, true);\n            TransitionManager.beginDelayedTransition(mContainer, sharedAxis);\n            mSearchContainer.setVisibility(View.GONE);\n        });\n        mSearchView.setOnQueryTextListener(this);\n        nextButton.setOnClickListener(v -> mWebView.findNext(true));\n        previousButton.setOnClickListener(v -> mWebView.findNext(false));\n        new FastScrollerBuilder(mWebView).useMd2Style().build();\n    }\n\n    @Override\n    public boolean onCreateOptionsMenu(Menu menu) {\n        super.onCreateOptionsMenu(menu);\n        getMenuInflater().inflate(R.menu.activity_help_actions, menu);\n        return true;\n    }\n\n    @Override\n    public boolean onPrepareOptionsMenu(Menu menu) {\n        super.onPrepareOptionsMenu(menu);\n        return true;\n    }\n\n    @Override\n    public boolean onOptionsItemSelected(@NonNull MenuItem item) {\n        int id = item.getItemId();\n        if (id == android.R.id.home) {\n            finish();\n        } else if (id == R.id.action_search) {\n            if (mSearchContainer.getVisibility() == View.VISIBLE) {\n                mSearchView.setQuery(null, false);\n                Transition sharedAxis = new MaterialSharedAxis(MaterialSharedAxis.Y, true);\n                TransitionManager.beginDelayedTransition(mContainer, sharedAxis);\n                mSearchContainer.setVisibility(View.GONE);\n            } else {\n                Transition sharedAxis = new MaterialSharedAxis(MaterialSharedAxis.Y, false);\n                TransitionManager.beginDelayedTransition(mContainer, sharedAxis);\n                mSearchContainer.setVisibility(View.VISIBLE);\n            }\n            return true;\n        }\n        return super.onOptionsItemSelected(item);\n    }\n\n    @Override\n    public boolean onQueryTextSubmit(String query) {\n        return false;\n    }\n\n    @Override\n    public boolean onQueryTextChange(String newText) {\n        mWebView.findAllAsync(newText);\n        return true;\n    }\n\n    private void openDocsSite() {\n        Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(getString(R.string.website_message)));\n        startActivity(intent);\n        finish();\n    }\n\n    class WebViewClientImpl extends WebViewClientCompat {\n        @Override\n        public boolean shouldOverrideUrlLoading(@NonNull WebView view, @NonNull WebResourceRequest request) {\n            Uri uri = request.getUrl();\n            if (uri.toString().startsWith(\"file:///android_res\")) {\n                return false;\n            }\n            Intent intent = new Intent(Intent.ACTION_VIEW, uri);\n            startActivity(intent);\n            return true;\n        }\n\n        @Override\n        public void doUpdateVisitedHistory(WebView view, String url, boolean isReload) {\n            mOnBackPressedCallback.setEnabled(view.canGoBack());\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/misc/LabsActivity.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.misc;\n\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.res.ColorStateList;\nimport android.os.Bundle;\nimport android.view.LayoutInflater;\nimport android.view.MenuItem;\nimport android.view.ViewGroup;\n\nimport androidx.annotation.DrawableRes;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.StringRes;\n\nimport com.google.android.material.button.MaterialButton;\n\nimport io.github.muntashirakon.AppManager.BaseActivity;\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.accessibility.activity.LeadingActivityTrackerActivity;\nimport io.github.muntashirakon.AppManager.editor.CodeEditorActivity;\nimport io.github.muntashirakon.AppManager.fm.FmActivity;\nimport io.github.muntashirakon.AppManager.history.ops.OpHistoryActivity;\nimport io.github.muntashirakon.AppManager.intercept.ActivityInterceptor;\nimport io.github.muntashirakon.AppManager.logcat.LogViewerActivity;\nimport io.github.muntashirakon.AppManager.terminal.TermActivity;\nimport io.github.muntashirakon.AppManager.settings.FeatureController;\nimport io.github.muntashirakon.AppManager.sysconfig.SysConfigActivity;\nimport io.github.muntashirakon.AppManager.utils.appearance.ColorCodes;\nimport io.github.muntashirakon.widget.FlowLayout;\n\npublic class LabsActivity extends BaseActivity {\n    @Override\n    protected void onAuthenticated(@Nullable Bundle savedInstanceState) {\n        setContentView(R.layout.activity_labs);\n        setSupportActionBar(findViewById(R.id.toolbar));\n        FlowLayout flowLayout = findViewById(R.id.action_container);\n        if (FeatureController.isLogViewerEnabled()) {\n            addAction(this, flowLayout, R.string.log_viewer, R.drawable.ic_view_list)\n                    .setOnClickListener(v -> {\n                        Intent intent = new Intent(this, LogViewerActivity.class);\n                        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);\n                        startActivity(intent);\n                    });\n        }\n        addAction(this, flowLayout, R.string.sys_config, R.drawable.ic_hammer_wrench)\n                .setOnClickListener(v -> {\n                    Intent intent = new Intent(this, SysConfigActivity.class);\n                    startActivity(intent);\n                });\n        if (FeatureController.isTerminalEnabled()) {\n            addAction(this, flowLayout, R.string.title_terminal_emulator, R.drawable.ic_frost_termux)\n                    .setOnClickListener(v -> {\n                        Intent intent = new Intent(this, TermActivity.class);\n                        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);\n                        startActivity(intent);\n                    });\n        }\n        addAction(this, flowLayout, R.string.files, R.drawable.ic_file_document_multiple)\n                .setOnClickListener(v -> {\n                    Intent intent = new Intent(this, FmActivity.class);\n                    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);\n                    startActivity(intent);\n                });\n        addAction(this, flowLayout, R.string.title_ui_tracker, R.drawable.ic_cursor_default_click)\n                .setOnClickListener(v -> {\n                    Intent intent = new Intent(this, LeadingActivityTrackerActivity.class);\n                    startActivity(intent);\n                });\n        if (FeatureController.isInterceptorEnabled()) {\n            addAction(this, flowLayout, R.string.interceptor, R.drawable.ic_transit_connection)\n                    .setOnClickListener(v -> {\n                        Intent intent = new Intent(this, ActivityInterceptor.class);\n                        startActivity(intent);\n                    });\n        }\n        if (FeatureController.isCodeEditorEnabled()) {\n            addAction(this, flowLayout, R.string.title_code_editor, R.drawable.ic_code)\n                    .setOnClickListener(v -> {\n                        Intent intent = new Intent(this, CodeEditorActivity.class);\n                        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);\n                        startActivity(intent);\n                    });\n        }\n        addAction(this, flowLayout, R.string.op_history, R.drawable.ic_history)\n                .setOnClickListener(v -> {\n                    Intent intent = new Intent(this, OpHistoryActivity.class);\n                    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);\n                    startActivity(intent);\n                });\n    }\n\n    @Override\n    public boolean onOptionsItemSelected(@NonNull MenuItem item) {\n        if (item.getItemId() == android.R.id.home) {\n            finish();\n            return true;\n        }\n        return super.onOptionsItemSelected(item);\n    }\n\n    @NonNull\n    private static MaterialButton addAction(@NonNull Context context, @NonNull ViewGroup parent,\n                                            @StringRes int stringResId, @DrawableRes int iconResId) {\n        MaterialButton button = (MaterialButton) LayoutInflater.from(context).inflate(R.layout.item_app_info_action, parent, false);\n        button.setBackgroundTintList(ColorStateList.valueOf(ColorCodes.getListItemColor1(context)));\n        button.setText(stringResId);\n        button.setIconResource(iconResId);\n        parent.addView(button);\n        return button;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/misc/ListOptions.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.misc;\n\nimport android.app.Application;\nimport android.os.Bundle;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.TextView;\n\nimport androidx.annotation.CallSuper;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.StringRes;\nimport androidx.appcompat.widget.LinearLayoutCompat;\nimport androidx.lifecycle.AndroidViewModel;\nimport androidx.lifecycle.ViewModelProvider;\n\nimport com.google.android.material.button.MaterialButton;\nimport com.google.android.material.checkbox.MaterialCheckBox;\nimport com.google.android.material.chip.Chip;\nimport com.google.android.material.chip.ChipGroup;\nimport com.google.android.material.materialswitch.MaterialSwitch;\n\nimport java.util.LinkedHashMap;\nimport java.util.Objects;\n\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.dialog.CapsuleBottomSheetDialogFragment;\nimport io.github.muntashirakon.widget.MaterialSpinner;\n\npublic abstract class ListOptions extends CapsuleBottomSheetDialogFragment {\n    public static final String TAG = ListOptions.class.getSimpleName();\n\n    public interface ListOptionActions {\n        default void setReverseSort(boolean reverseSort) {\n        }\n\n        default boolean isReverseSort() {\n            return false;\n        }\n\n        default void setSortBy(int sortBy) {\n        }\n\n        default int getSortBy() {\n            return 0;\n        }\n\n        default boolean hasFilterFlag(int flag) {\n            return false;\n        }\n\n        default void addFilterFlag(int flag) {\n        }\n\n        default void removeFilterFlag(int flag) {\n        }\n\n        default boolean isOptionSelected(int option) {\n            return false;\n        }\n\n        default void onOptionSelected(int option, boolean selected) {\n        }\n    }\n\n    private TextView mSortText;\n    private ChipGroup mSortGroup;\n    private MaterialCheckBox mReverseSort;\n    private TextView mFilterText;\n    private ChipGroup mFilterOptions;\n    private TextView mOptionsText;\n    private LinearLayoutCompat mOptionsView;\n    @Nullable\n    private ListOptionActions mListOptionActions;\n    @Nullable\n    private ListOptionsViewModel mListOptionsViewModel;\n\n    protected MaterialSpinner profileNameSpinner;\n    protected MaterialButton selectUserView;\n\n    public void setListOptionActions(@Nullable ListOptionActions listOptionActions) {\n        if (mListOptionsViewModel != null) {\n            mListOptionsViewModel.setListOptionActions(listOptionActions);\n        } else mListOptionActions = listOptionActions;\n    }\n\n    @CallSuper\n    @NonNull\n    @Override\n    public View initRootView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {\n        return inflater.inflate(R.layout.dialog_list_options, container, false);\n    }\n\n    @CallSuper\n    @Override\n    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {\n        super.onViewCreated(view, savedInstanceState);\n        mListOptionsViewModel = new ViewModelProvider(this).get(ListOptionsViewModel.class);\n        mSortText = view.findViewById(R.id.sort_text);\n        mSortGroup = view.findViewById(R.id.sort_options);\n        mReverseSort = view.findViewById(R.id.reverse_sort);\n        mFilterText = view.findViewById(R.id.filter_text);\n        mFilterOptions = view.findViewById(R.id.filter_options);\n        mOptionsText = view.findViewById(R.id.options_text);\n        mOptionsView = view.findViewById(R.id.options);\n        profileNameSpinner = view.findViewById(R.id.spinner);\n        selectUserView = view.findViewById(R.id.user);\n\n        init(false);\n    }\n\n    @Nullable\n    public abstract LinkedHashMap<Integer, Integer> getSortIdLocaleMap();\n\n    @Nullable\n    public abstract LinkedHashMap<Integer, Integer> getFilterFlagLocaleMap();\n\n    @Nullable\n    public abstract LinkedHashMap<Integer, Integer> getOptionIdLocaleMap();\n\n    public boolean enableProfileNameInput() {\n        return false;\n    }\n\n    public boolean enableSelectUser() {\n        return false;\n    }\n\n    public void reloadUi() {\n        init(true);\n    }\n\n    @NonNull\n    private ListOptionActions requireListOptionActions() {\n        if (mListOptionsViewModel == null) {\n            throw new NullPointerException(\"ViewModel is not initialized.\");\n        }\n        if (mListOptionActions != null) {\n            mListOptionsViewModel.setListOptionActions(mListOptionActions);\n            mListOptionActions = null;\n        }\n        ListOptionActions actions = mListOptionsViewModel.getListOptionActions();\n        if (actions == null) {\n            throw new NullPointerException(\"ListOptionsActions must be set before calling init.\");\n        }\n        return actions;\n    }\n\n    private void init(boolean reinit) {\n        // Enable sorting\n        LinkedHashMap<Integer, Integer> sortIdLocaleMap = getSortIdLocaleMap();\n        boolean sortingEnabled = sortIdLocaleMap != null;\n        mSortText.setVisibility(sortingEnabled ? View.VISIBLE : View.GONE);\n        mSortGroup.setVisibility(sortingEnabled ? View.VISIBLE : View.GONE);\n        mReverseSort.setVisibility(sortingEnabled ? View.VISIBLE : View.GONE);\n        if (sortingEnabled) {\n            int i = 0;\n            for (int sortId : sortIdLocaleMap.keySet()) {\n                int sortStringRes = Objects.requireNonNull(sortIdLocaleMap.get(sortId));\n                mSortGroup.addView(getRadioChip(sortId, sortStringRes), i);\n                ++i;\n            }\n            mSortGroup.check(requireListOptionActions().getSortBy());\n            mSortGroup.setOnCheckedStateChangeListener((group, checkedIds) ->\n                    requireListOptionActions().setSortBy(mSortGroup.getCheckedChipId()));\n            mReverseSort.setChecked(requireListOptionActions().isReverseSort());\n            mReverseSort.setOnCheckedChangeListener((buttonView, isChecked) ->\n                    requireListOptionActions().setReverseSort(isChecked));\n        }\n\n        // Enable filtering\n        LinkedHashMap<Integer, Integer> filterFlagLocaleMap = getFilterFlagLocaleMap();\n        boolean filteringEnabled = filterFlagLocaleMap != null;\n        mFilterText.setVisibility(filteringEnabled ? View.VISIBLE : View.GONE);\n        mFilterOptions.setVisibility(filteringEnabled ? View.VISIBLE : View.GONE);\n        if (filteringEnabled) {\n            int i = 0;\n            for (int flag : filterFlagLocaleMap.keySet()) {\n                int flagStringRes = Objects.requireNonNull(filterFlagLocaleMap.get(flag));\n                mFilterOptions.addView(getFilterChip(flag, flagStringRes), i);\n                ++i;\n            }\n        }\n\n        // Enable options\n        LinkedHashMap<Integer, Integer> optionIdLocaleMap = getOptionIdLocaleMap();\n        boolean optionsEnabled = optionIdLocaleMap != null;\n        mOptionsText.setVisibility(optionsEnabled ? View.VISIBLE : View.GONE);\n        mOptionsView.setVisibility(optionsEnabled ? View.VISIBLE : View.GONE);\n        if (optionsEnabled) {\n            int i = 0;\n            for (int option : optionIdLocaleMap.keySet()) {\n                int optionStringRes = Objects.requireNonNull(optionIdLocaleMap.get(option));\n                mOptionsView.addView(getOption(option, optionStringRes), i);\n                ++i;\n            }\n        }\n\n        // Profile\n        boolean profileEnabled = enableProfileNameInput();\n        profileNameSpinner.setVisibility(profileEnabled ? View.VISIBLE : View.GONE);\n\n        // User\n        boolean selectUserEnabled = enableSelectUser();\n        selectUserView.setVisibility(selectUserEnabled ? View.VISIBLE : View.GONE);\n\n        if (reinit) {\n            return;\n        }\n\n        if (sortingEnabled && mSortGroup.getChildCount() > 0) {\n            mSortGroup.getChildAt(0).requestFocus();\n        } else if (filteringEnabled && mFilterOptions.getChildCount() > 0) {\n            mFilterOptions.getChildAt(0).requestFocus();\n        } else if (optionsEnabled && mOptionsView.getChildCount() > 0) {\n            mOptionsView.getChildAt(0).requestFocus();\n        }\n    }\n\n    @NonNull\n    private MaterialSwitch getOption(int option, @StringRes int strRes) {\n        MaterialSwitch materialSwitch = (MaterialSwitch) View.inflate(mOptionsView.getContext(), R.layout.item_switch, null);\n        materialSwitch.setFocusable(true);\n        materialSwitch.setId(option);\n        materialSwitch.setText(strRes);\n        materialSwitch.setChecked(requireListOptionActions().isOptionSelected(option));\n        materialSwitch.setOnCheckedChangeListener((buttonView, isChecked) ->\n                requireListOptionActions().onOptionSelected(option, isChecked));\n        return materialSwitch;\n    }\n\n    @NonNull\n    private Chip getFilterChip(int flag, @StringRes int strRes) {\n        Chip chip = new Chip(mFilterOptions.getContext());\n        chip.setFocusable(true);\n        chip.setCloseIconVisible(false);\n        chip.setId(flag);\n        chip.setText(strRes);\n        chip.setChecked(requireListOptionActions().hasFilterFlag(flag));\n        chip.setOnCheckedChangeListener((buttonView, isChecked) -> {\n            if (isChecked) {\n                requireListOptionActions().addFilterFlag(flag);\n            } else {\n                requireListOptionActions().removeFilterFlag(flag);\n            }\n        });\n        return chip;\n    }\n\n    @NonNull\n    private Chip getRadioChip(int sortOrder, @StringRes int strRes) {\n        Chip chip = new Chip(mSortGroup.getContext());\n        chip.setFocusable(true);\n        chip.setCloseIconVisible(false);\n        chip.setId(sortOrder);\n        chip.setText(strRes);\n        return chip;\n    }\n\n    public static class ListOptionsViewModel extends AndroidViewModel {\n        @Nullable\n        private ListOptionActions mListOptionActions;\n\n        public ListOptionsViewModel(@NonNull Application application) {\n            super(application);\n        }\n\n        public void setListOptionActions(@Nullable ListOptionActions listOptionActions) {\n            mListOptionActions = listOptionActions;\n        }\n\n        @Nullable\n        public ListOptionActions getListOptionActions() {\n            return mListOptionActions;\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/misc/NoOps.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.misc;\n\nimport java.lang.annotation.Documented;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.Target;\n\nimport io.github.muntashirakon.AppManager.settings.Ops;\n\nimport static java.lang.annotation.ElementType.CONSTRUCTOR;\nimport static java.lang.annotation.ElementType.METHOD;\nimport static java.lang.annotation.ElementType.TYPE;\nimport static java.lang.annotation.RetentionPolicy.SOURCE;\n\n/**\n * Denotes that the method, constructor or class does not contain any checks from {@link Ops}. This is useful to prevent\n * cycles when checking for root, ADB, etc.\n * <p>\n * TODO: Build a annotation detector\n */\n@Documented\n@Retention(SOURCE)\n@Target({METHOD, CONSTRUCTOR, TYPE})\npublic @interface NoOps {\n    /**\n     * Whether any {@link Ops} checks have been used.\n     */\n    boolean used() default false;\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/misc/OidMap.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.misc;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * @see android.sun.security.x509.OIDMap\n */\npublic class OidMap {\n    private static final Map<String, String> oidNameMap = new HashMap<String, String>() {{\n        put(\"2.5.29.9\", \"subjectDirectoryAttributes\");\n\n        put(\"2.5.29.14\", \"subjectKeyIdentifier\");\n        put(\"2.5.29.15\", \"keyUsage\");\n        put(\"2.5.29.16\", \"privateKeyUsagePeriod\");\n        put(\"2.5.29.17\", \"subjectAltName\");\n        put(\"2.5.29.18\", \"issuerAltName\");\n        put(\"2.5.29.19\", \"basicConstraints\");\n        put(\"2.5.29.20\", \"cRLNumber\");\n        put(\"2.5.29.21\", \"reasonCode\");\n\n        put(\"2.5.29.23\", \"instructionCode\");\n        put(\"2.5.29.24\", \"invalidityDate\");\n\n        put(\"2.5.29.27\", \"deltaCRLIndicator\");\n        put(\"2.5.29.28\", \"issuingDistributionPoint\");\n        put(\"2.5.29.29\", \"certificateIssuer\");\n        put(\"2.5.29.30\", \"nameConstraints\");\n        put(\"2.5.29.31\", \"cRLDistributionPoints\");\n        put(\"2.5.29.32\", \"certificatePolicies\");\n        put(\"2.5.29.33\", \"policyMappings\");\n\n        put(\"2.5.29.35\", \"authorityKeyIdentifier\");\n        put(\"2.5.29.36\", \"policyConstraints\");\n        put(\"2.5.29.37\", \"extKeyUsage\");\n        put(\"2.5.29.38\", \"authorityAttributeIdentifier\");\n        put(\"2.5.29.39\", \"roleSpecCertIdentifier\");\n        put(\"2.5.29.40\", \"cRLStreamIdentifier\");\n        put(\"2.5.29.41\", \"basicAttConstraints\");\n        put(\"2.5.29.42\", \"delegatedNameConstraints\");\n        put(\"2.5.29.43\", \"timeSpecification\");\n        put(\"2.5.29.44\", \"cRLScope\");\n        put(\"2.5.29.45\", \"statusReferrals\");\n        put(\"2.5.29.46\", \"freshestCRL\");\n        put(\"2.5.29.47\", \"orderedList\");\n        put(\"2.5.29.48\", \"attributeDescriptor\");\n        put(\"2.5.29.49\", \"userNotice\");\n        put(\"2.5.29.50\", \"sOAIdentifier\");\n        put(\"2.5.29.51\", \"baseUpdateTime\");\n        put(\"2.5.29.52\", \"acceptableCertPolicies\");\n        put(\"2.5.29.53\", \"deltaInfo\");\n        put(\"2.5.29.54\", \"inhibitAnyPolicy\");\n        put(\"2.5.29.55\", \"targetInformation\");\n        put(\"2.5.29.56\", \"noRevAvail\");\n        put(\"2.5.29.57\", \"acceptablePrivilegePolicies\");\n\n        put(\"2.5.29.61\", \"indirectIssuer\");\n\n        put(\"1.3.6.1.5.5.7.1.1\", \"AuthorityInfoAccess\");\n        put(\"1.3.6.1.5.5.7.1.11\", \"SubjectInfoAccess\");\n        put(\"1.3.6.1.5.5.7.48.1.5\", \"OCSPNoCheck\");\n    }};\n\n    @Nullable\n    public static String getName(@NonNull String oid) {\n        return oidNameMap.get(oid);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/misc/OsEnvironment.java",
    "content": "// SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.misc;\n\nimport android.annotation.UserIdInt;\nimport android.os.UserHandleHidden;\nimport android.os.storage.StorageManagerHidden;\nimport android.os.storage.StorageVolume;\nimport android.os.storage.StorageVolumeHidden;\nimport android.text.TextUtils;\nimport android.util.SparseArray;\n\nimport androidx.annotation.NonNull;\n\nimport java.io.File;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Objects;\n\nimport dev.rikka.tools.refine.Refine;\nimport io.github.muntashirakon.AppManager.compat.StorageManagerCompat;\nimport io.github.muntashirakon.AppManager.logs.Log;\nimport io.github.muntashirakon.AppManager.utils.ContextUtils;\nimport io.github.muntashirakon.io.Path;\nimport io.github.muntashirakon.io.Paths;\n\n// Keep this in sync with https://cs.android.com/android/platform/superproject/+/master:frameworks/base/core/java/android/os/Environment.java\n// Last snapshot https://cs.android.com/android/_/android/platform/frameworks/base/+/bc3d8b9071d4f0b2903d6836770d974e70366290\n\n@SuppressWarnings(\"unused\")\npublic final class OsEnvironment {\n    private static final String TAG = \"OsEnvironment\";\n\n    private static final String ENV_EXTERNAL_STORAGE = \"EXTERNAL_STORAGE\";\n    private static final String ENV_ANDROID_ROOT = \"ANDROID_ROOT\";\n    private static final String ENV_ANDROID_DATA = \"ANDROID_DATA\";\n    private static final String ENV_ANDROID_EXPAND = \"ANDROID_EXPAND\";\n    private static final String ENV_ANDROID_STORAGE = \"ANDROID_STORAGE\";\n    private static final String ENV_DOWNLOAD_CACHE = \"DOWNLOAD_CACHE\";\n    private static final String ENV_OEM_ROOT = \"OEM_ROOT\";\n    private static final String ENV_ODM_ROOT = \"ODM_ROOT\";\n    private static final String ENV_VENDOR_ROOT = \"VENDOR_ROOT\";\n    private static final String ENV_PRODUCT_ROOT = \"PRODUCT_ROOT\";\n    private static final String ENV_SYSTEM_EXT_ROOT = \"SYSTEM_EXT_ROOT\";\n    private static final String ENV_APEX_ROOT = \"APEX_ROOT\";\n\n    public static final String DIR_ANDROID = \"Android\";\n    private static final String DIR_DATA = \"data\";\n    private static final String DIR_MEDIA = \"media\";\n    private static final String DIR_OBB = \"obb\";\n    private static final String DIR_FILES = \"files\";\n    private static final String DIR_CACHE = \"cache\";\n\n    private static final String DIR_ANDROID_ROOT = getDirectory(ENV_ANDROID_ROOT, \"/system\");\n    private static final String DIR_ANDROID_DATA = getDirectory(ENV_ANDROID_DATA, \"/data\");\n    private static final String DIR_ANDROID_EXPAND = getDirectory(ENV_ANDROID_EXPAND, \"/mnt/expand\");\n    private static final String DIR_ANDROID_STORAGE = getDirectory(ENV_ANDROID_STORAGE, \"/storage\");\n    private static final String DIR_DOWNLOAD_CACHE = getDirectory(ENV_DOWNLOAD_CACHE, \"/cache\");\n    private static final String DIR_OEM_ROOT = getDirectory(ENV_OEM_ROOT, \"/oem\");\n    private static final String DIR_ODM_ROOT = getDirectory(ENV_ODM_ROOT, \"/odm\");\n    private static final String DIR_VENDOR_ROOT = getDirectory(ENV_VENDOR_ROOT, \"/vendor\");\n    private static final String DIR_PRODUCT_ROOT = getDirectory(ENV_PRODUCT_ROOT, \"/product\");\n    private static final String DIR_SYSTEM_EXT_ROOT = getDirectory(ENV_SYSTEM_EXT_ROOT, \"/system_ext\");\n    private static final String DIR_APEX_ROOT = getDirectory(ENV_APEX_ROOT, \"/apex\");\n\n    private static final UserEnvironment sCurrentUser;\n    private static boolean sUserRequired;\n\n    private static final SparseArray<UserEnvironment> sUserEnvironmentCache = new SparseArray<>(2);\n\n    static {\n        sCurrentUser = new UserEnvironment(UserHandleHidden.myUserId());\n        sUserEnvironmentCache.put(sCurrentUser.mUserHandle, sCurrentUser);\n    }\n\n    @NonNull\n    public static UserEnvironment getUserEnvironment(@UserIdInt int userHandle) {\n        UserEnvironment ue = sUserEnvironmentCache.get(userHandle);\n        if (ue != null) return ue;\n        ue = new UserEnvironment(userHandle);\n        sUserEnvironmentCache.put(userHandle, ue);\n        return ue;\n    }\n\n    public static class UserEnvironment {\n        @UserIdInt\n        private final int mUserHandle;\n\n        public UserEnvironment(@UserIdInt int userHandle) {\n            mUserHandle = userHandle;\n        }\n\n        @NonNull\n        public Path[] getExternalDirs() {\n            if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) {\n                final StorageVolume[] volumes = StorageManagerCompat.getVolumeList(ContextUtils.getContext(),\n                        mUserHandle, StorageManagerHidden.FLAG_FOR_WRITE);\n                final List<Path> files = new ArrayList<>();\n                File tmpFile;\n                for (@NonNull StorageVolume volume : volumes) {\n                    StorageVolumeHidden vol = Refine.unsafeCast(volume);\n                    tmpFile = vol.getPathFile();\n                    if (tmpFile != null) {\n                        files.add(Paths.get(tmpFile.getAbsolutePath()));\n                    }\n                }\n                return files.toArray(new Path[0]);\n            }\n            String rawExternalStorage = System.getenv(ENV_EXTERNAL_STORAGE);\n            String rawEmulatedTarget = System.getenv(\"EMULATED_STORAGE_TARGET\");\n            List<Path> externalForApp = new ArrayList<>();\n            if (!TextUtils.isEmpty(rawEmulatedTarget)) {\n                // Device has emulated storage; external storage paths should have\n                // userId burned into them.\n                final String rawUserId = Integer.toString(mUserHandle);\n                //noinspection ConstantConditions\n                final File emulatedTargetBase = new File(rawEmulatedTarget);\n\n                // /storage/emulated/0\n                externalForApp.add(Paths.build(emulatedTargetBase, rawUserId));\n            } else {\n                // Device has physical external storage; use plain paths.\n                if (TextUtils.isEmpty(rawExternalStorage)) {\n                    Log.w(TAG, \"EXTERNAL_STORAGE undefined; falling back to default\");\n                    rawExternalStorage = \"/storage/sdcard0\";\n                }\n                // /storage/sdcard0\n                externalForApp.add(Paths.get(rawExternalStorage));\n            }\n            return externalForApp.toArray(new Path[0]);\n        }\n\n        @Deprecated\n        public Path getExternalStorageDirectory() {\n            return getExternalDirs()[0];\n        }\n\n        @Deprecated\n        public Path getExternalStoragePublicDirectory(String type) {\n            return buildExternalStoragePublicDirs(type)[0];\n        }\n\n        public Path[] buildExternalStoragePublicDirs(String type) {\n            return Paths.build(getExternalDirs(), type);\n        }\n\n        public Path[] buildExternalStorageAndroidDataDirs() {\n            return Paths.build(getExternalDirs(), DIR_ANDROID, DIR_DATA);\n        }\n\n        public Path[] buildExternalStorageAndroidObbDirs() {\n            return Paths.build(getExternalDirs(), DIR_ANDROID, DIR_OBB);\n        }\n\n        public Path[] buildExternalStorageAppDataDirs(String packageName) {\n            return Paths.build(getExternalDirs(), DIR_ANDROID, DIR_DATA, packageName);\n        }\n\n        public Path[] buildExternalStorageAppMediaDirs(String packageName) {\n            return Paths.build(getExternalDirs(), DIR_ANDROID, DIR_MEDIA, packageName);\n        }\n\n        public Path[] buildExternalStorageAppObbDirs(String packageName) {\n            return Paths.build(getExternalDirs(), DIR_ANDROID, DIR_OBB, packageName);\n        }\n\n        public Path[] buildExternalStorageAppFilesDirs(String packageName) {\n            return Paths.build(getExternalDirs(), DIR_ANDROID, DIR_DATA, packageName, DIR_FILES);\n        }\n\n        public Path[] buildExternalStorageAppCacheDirs(String packageName) {\n            return Paths.build(getExternalDirs(), DIR_ANDROID, DIR_DATA, packageName, DIR_CACHE);\n        }\n    }\n\n    /**\n     * Return root of the \"system\" partition holding the core Android OS.\n     * Always present and mounted read-only.\n     */\n    @NonNull\n    public static Path getRootDirectory() {\n        return Paths.get(DIR_ANDROID_ROOT);\n    }\n\n    /**\n     * Return root directory of the \"oem\" partition holding OEM customizations,\n     * if any. If present, the partition is mounted read-only.\n     */\n    @NonNull\n    public static Path getOemDirectory() {\n        return Paths.get(DIR_OEM_ROOT);\n    }\n\n    /**\n     * Return root directory of the \"odm\" partition holding ODM customizations,\n     * if any. If present, the partition is mounted read-only.\n     */\n    @NonNull\n    public static Path getOdmDirectory() {\n        return Paths.get(DIR_ODM_ROOT);\n    }\n\n    /**\n     * Return root directory of the \"vendor\" partition that holds vendor-provided\n     * software that should persist across simple reflashing of the \"system\" partition.\n     */\n    @NonNull\n    public static Path getVendorDirectory() {\n        return Paths.get(DIR_VENDOR_ROOT);\n    }\n\n    @NonNull\n    public static String getVendorDirectoryRaw() {\n        return DIR_VENDOR_ROOT;\n    }\n\n    /**\n     * Return root directory of the \"product\" partition holding product-specific\n     * customizations if any. If present, the partition is mounted read-only.\n     */\n    @NonNull\n    public static Path getProductDirectory() {\n        return Paths.get(DIR_PRODUCT_ROOT);\n    }\n\n    @NonNull\n    public static String getProductDirectoryRaw() {\n        return DIR_PRODUCT_ROOT;\n    }\n\n    /**\n     * Return root directory of the \"system_ext\" partition holding system partition's extension\n     * If present, the partition is mounted read-only.\n     */\n    @NonNull\n    public static Path getSystemExtDirectory() {\n        return Paths.get(DIR_SYSTEM_EXT_ROOT);\n    }\n\n    /**\n     * Return the user data directory.\n     */\n    @NonNull\n    public static Path getDataDirectory() {\n        return Paths.get(DIR_ANDROID_DATA);\n    }\n\n    @NonNull\n    public static String getDataDirectoryRaw() {\n        return DIR_ANDROID_DATA;\n    }\n\n    @NonNull\n    public static Path getDataSystemDirectory() {\n        return Objects.requireNonNull(Paths.build(getDataDirectory(), \"system\"));\n    }\n\n    @NonNull\n    public static Path getDataAppDirectory() {\n        return Objects.requireNonNull(Paths.build(getDataDirectory(), \"app\"));\n    }\n\n    @NonNull\n    public static Path getDataDataDirectory() {\n        return Objects.requireNonNull(Paths.build(getDataDirectory(), \"data\"));\n    }\n\n    @NonNull\n    public static Path getUserSystemDirectory(int userId) {\n        return Objects.requireNonNull(Paths.build(getDataSystemDirectory(), \"users\", Integer.toString(userId)));\n    }\n\n    /**\n     * Returns the path for android-specific data on the SD card.\n     */\n    public static Path[] buildExternalStorageAndroidDataDirs() {\n        throwIfUserRequired();\n        return sCurrentUser.buildExternalStorageAndroidDataDirs();\n    }\n\n    /**\n     * Generates the raw path to an application's data\n     */\n    public static Path[] buildExternalStorageAppDataDirs(String packageName) {\n        throwIfUserRequired();\n        return sCurrentUser.buildExternalStorageAppDataDirs(packageName);\n    }\n\n    /**\n     * Generates the raw path to an application's media\n     */\n    public static Path[] buildExternalStorageAppMediaDirs(String packageName) {\n        throwIfUserRequired();\n        return sCurrentUser.buildExternalStorageAppMediaDirs(packageName);\n    }\n\n    /**\n     * Generates the raw path to an application's OBB files\n     */\n    public static Path[] buildExternalStorageAppObbDirs(String packageName) {\n        throwIfUserRequired();\n        return sCurrentUser.buildExternalStorageAppObbDirs(packageName);\n    }\n\n    /**\n     * Generates the path to an application's files.\n     */\n    public static Path[] buildExternalStorageAppFilesDirs(String packageName) {\n        throwIfUserRequired();\n        return sCurrentUser.buildExternalStorageAppFilesDirs(packageName);\n    }\n\n    /**\n     * Generates the path to an application's cache.\n     */\n    public static Path[] buildExternalStorageAppCacheDirs(String packageName) {\n        throwIfUserRequired();\n        return sCurrentUser.buildExternalStorageAppCacheDirs(packageName);\n    }\n\n    public static Path[] buildExternalStoragePublicDirs(@NonNull String dirType) {\n        throwIfUserRequired();\n        return sCurrentUser.buildExternalStoragePublicDirs(dirType);\n    }\n\n    public static Path[] buildExternalStoragePublicDirs() {\n        throwIfUserRequired();\n        return sCurrentUser.getExternalDirs();\n    }\n\n    @NonNull\n    static String getDirectory(String variableName, String defaultPath) {\n        String path = System.getenv(variableName);\n        return path == null ? defaultPath : path;\n    }\n\n    public static void setUserRequired(boolean userRequired) {\n        sUserRequired = userRequired;\n    }\n\n    private static void throwIfUserRequired() {\n        if (sUserRequired) {\n            Log.e(TAG, \"Path requests must specify a user by using UserEnvironment\", new Throwable());\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/misc/ScreenLockChecker.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.misc;\n\nimport android.app.KeyguardManager;\nimport android.content.Context;\nimport android.os.PowerManager;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.WorkerThread;\n\nimport java.util.Locale;\nimport java.util.Timer;\nimport java.util.TimerTask;\n\nimport io.github.muntashirakon.AppManager.logs.Log;\n\npublic final class ScreenLockChecker {\n    public static final String TAG = ScreenLockChecker.class.getSimpleName();\n\n    private static final int SECOND = 1000;\n    private static final int MINUTE = 60 * SECOND;\n    // This tracks the deltas between the actual options of 5s, 15s, 30s, 1m, 2m, 5m, 10m\n    // It also includes an initial offset and some extra times (for safety)\n    private static final int[] sCheckLockDelays = new int[]{SECOND, 5 * SECOND, 10 * SECOND, 20 * SECOND, 30 * SECOND,\n            MINUTE, 3 * MINUTE, 5 * MINUTE, 10 * MINUTE, 30 * MINUTE};\n\n    private final Context mContext;\n    private final Timer mTimer = new Timer();\n    @Nullable\n    private final Runnable mRunnable;\n\n    @Nullable\n    private CheckLockTask mCheckLockTask;\n\n    public ScreenLockChecker(@NonNull Context context, @Nullable Runnable runnable) {\n        mContext = context.getApplicationContext();\n        mRunnable = runnable;\n    }\n\n    public void checkLock() {\n        checkLock(-1);\n    }\n\n    @WorkerThread\n    private void checkLock(int delayIndex) {\n        KeyguardManager keyguardManager = (KeyguardManager) mContext.getSystemService(Context.KEYGUARD_SERVICE);\n        PowerManager powerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);\n\n        final boolean isProtected = keyguardManager.isKeyguardSecure();\n        final boolean isLocked = keyguardManager.isKeyguardLocked();\n        final boolean isInteractive = powerManager.isInteractive();\n        delayIndex = getSafeCheckLockDelay(delayIndex);\n        Log.i(TAG, \"checkLock: isProtected=%b, isLocked=%b, isInteractive=%b, delay=%d\",\n                isProtected, isLocked, isInteractive, sCheckLockDelays[delayIndex]);\n\n        if (mCheckLockTask != null) {\n            Log.i(TAG, \"checkLock: cancelling CheckLockTask[%x]\", System.identityHashCode(mCheckLockTask));\n            mCheckLockTask.cancel();\n        }\n\n        if (isProtected && !isLocked && !isInteractive) {\n            mCheckLockTask = new CheckLockTask(delayIndex);\n            Log.i(TAG, \"checkLock: scheduling CheckLockTask[%x] for %d ms\", System.identityHashCode(mCheckLockTask), sCheckLockDelays[delayIndex]);\n            mTimer.schedule(mCheckLockTask, sCheckLockDelays[delayIndex]);\n        } else {\n            Log.d(TAG, \"checkLock: no need to schedule CheckLockTask\");\n            if (isProtected && isLocked) {\n                if (mRunnable != null) {\n                    mRunnable.run();\n                }\n            }\n        }\n    }\n\n    private static int getSafeCheckLockDelay(final int delayIndex) {\n        final int safeDelayIndex;\n        if (delayIndex >= sCheckLockDelays.length) {\n            safeDelayIndex = sCheckLockDelays.length - 1;\n        } else safeDelayIndex = Math.max(delayIndex, 0);\n        Log.v(TAG, \"getSafeCheckLockDelay(%d) returns %d\", delayIndex, safeDelayIndex);\n        return safeDelayIndex;\n    }\n\n    private class CheckLockTask extends TimerTask {\n        final int delayIndex;\n\n        CheckLockTask(final int delayIndex) {\n            this.delayIndex = delayIndex;\n        }\n\n        @Override\n        public void run() {\n            Log.i(TAG, \"CLT.run [%x]: redirect intent to LockMonitor\", System.identityHashCode(this));\n            checkLock(getSafeCheckLockDelay(delayIndex + 1));\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/misc/SystemProperties.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.misc;\n\nimport androidx.annotation.NonNull;\n\nimport io.github.muntashirakon.AppManager.logs.Log;\nimport io.github.muntashirakon.AppManager.runner.Runner;\n\npublic final class SystemProperties {\n    @NonNull\n    public static String get(@NonNull String key, @NonNull String defaultVal) {\n        try {\n            return android.os.SystemProperties.get(key, defaultVal);\n        } catch (Exception e) {\n            Log.w(\"SystemProperties\", \"Unable to use SystemProperties.get\", e);\n            Runner.Result result = Runner.runCommand(new String[]{\"getprop\", key, defaultVal});\n            if (result.isSuccessful()) return result.getOutput().trim();\n            else return defaultVal;\n        }\n    }\n\n    public static boolean getBoolean(@NonNull String key, boolean defaultVal) {\n        String val = get(key, String.valueOf(defaultVal));\n        if (\"1\".equals(val)) return true;\n        return Boolean.parseBoolean(val);\n    }\n\n    public static int getInt(@NonNull String key, int defaultVal) {\n        String val = get(key, String.valueOf(defaultVal));\n        try {\n            return Integer.parseInt(val);\n        } catch (NumberFormatException e) {\n            return defaultVal;\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/misc/VMRuntime.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage io.github.muntashirakon.AppManager.misc;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport androidx.annotation.NonNull;\n\n// Keep this in sync with https://cs.android.com/android/platform/superproject/+/master:libcore/libart/src/main/java/dalvik/system/VMRuntime.java\npublic final class VMRuntime {\n    public static final String ABI_ARMEABI = \"armeabi\";\n    public static final String ABI_ARMEABI_V7A = \"armeabi-v7a\";\n    public static final String ABI_MIPS = \"mips\";\n    public static final String ABI_MIPS64 = \"mips64\";\n    public static final String ABI_X86 = \"x86\";\n    public static final String ABI_X86_64 = \"x86_64\";\n    public static final String ABI_ARM64_V8A = \"arm64-v8a\";\n    public static final String ABI_ARM64_V8A_HWASAN = \"arm64-v8a-hwasan\";\n\n    public static final String INSTRUCTION_SET_ARM = \"arm\";\n    public static final String INSTRUCTION_SET_MIPS = \"mips\";\n    public static final String INSTRUCTION_SET_MIPS64 = \"mips64\";\n    public static final String INSTRUCTION_SET_X86 = \"x86\";\n    public static final String INSTRUCTION_SET_X86_64 = \"x86_64\";\n    public static final String INSTRUCTION_SET_ARM64 = \"arm64\";\n\n    private static final Map<String, String> ABI_TO_INSTRUCTION_SET_MAP = new HashMap<>(16);\n\n    static {\n        ABI_TO_INSTRUCTION_SET_MAP.put(ABI_ARMEABI, INSTRUCTION_SET_ARM);\n        ABI_TO_INSTRUCTION_SET_MAP.put(ABI_ARMEABI_V7A, INSTRUCTION_SET_ARM);\n        ABI_TO_INSTRUCTION_SET_MAP.put(ABI_MIPS, INSTRUCTION_SET_MIPS);\n        ABI_TO_INSTRUCTION_SET_MAP.put(ABI_MIPS64, INSTRUCTION_SET_MIPS64);\n        ABI_TO_INSTRUCTION_SET_MAP.put(ABI_X86, INSTRUCTION_SET_X86);\n        ABI_TO_INSTRUCTION_SET_MAP.put(ABI_X86_64, INSTRUCTION_SET_X86_64);\n        ABI_TO_INSTRUCTION_SET_MAP.put(ABI_ARM64_V8A, INSTRUCTION_SET_ARM64);\n        ABI_TO_INSTRUCTION_SET_MAP.put(ABI_ARM64_V8A_HWASAN, INSTRUCTION_SET_ARM64);\n    }\n\n    @NonNull\n    public static String getInstructionSet(String abi) {\n        final String instructionSet = ABI_TO_INSTRUCTION_SET_MAP.get(abi);\n        if (instructionSet == null) {\n            throw new IllegalArgumentException(\"Unsupported ABI: \" + abi);\n        }\n\n        return instructionSet;\n    }\n\n    public static boolean is64BitInstructionSet(String instructionSet) {\n        return INSTRUCTION_SET_ARM64.equals(instructionSet) ||\n                INSTRUCTION_SET_X86_64.equals(instructionSet) ||\n                INSTRUCTION_SET_MIPS64.equals(instructionSet);\n    }\n\n    public static boolean is64BitAbi(String abi) {\n        return is64BitInstructionSet(getInstructionSet(abi));\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/misc/XposedModuleInfo.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.misc;\n\nimport static io.github.muntashirakon.AppManager.utils.UIUtils.getBoldString;\nimport static io.github.muntashirakon.AppManager.utils.UIUtils.getStyledKeyValue;\n\nimport android.content.Context;\nimport android.content.pm.ApplicationInfo;\nimport android.content.pm.PackageManager;\nimport android.text.SpannableStringBuilder;\nimport android.text.TextUtils;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport java.io.BufferedReader;\nimport java.io.IOException;\nimport java.io.InputStreamReader;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Properties;\nimport java.util.zip.ZipEntry;\nimport java.util.zip.ZipFile;\n\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.logs.Log;\nimport io.github.muntashirakon.util.LocalizedString;\nimport io.github.muntashirakon.util.UiUtils;\n\n// Source: https://github.com/LSPosed/LSPosed/blob/1c586fe41f22fac84c46d33db61e3a04ad528409/app/src/main/java/org/lsposed/manager/util/ModuleUtil.java#L88\n// Copyright 2020 EdXposed Contributors\n// Copyright 2021 LSPosed Contributors\n// Copyright 2023 Muntashir Al-Islam\npublic class XposedModuleInfo implements LocalizedString {\n    public static final String TAG = XposedModuleInfo.class.getSimpleName();\n\n    @Nullable\n    public static Boolean isXposedModule(@NonNull ApplicationInfo app, @NonNull ZipFile zipFile) {\n        if (app.metaData != null && app.metaData.containsKey(\"xposedminversion\")) {\n            return null;\n        }\n        return zipFile.getEntry(\"META-INF/xposed/module.prop\") != null;\n    }\n\n    public final String packageName;\n    public final boolean legacy;\n    public final int minVersion;\n    public final int targetVersion;\n    public final boolean staticScope;\n    private final ApplicationInfo mApp;\n\n    private CharSequence mAppLabel;\n    private CharSequence mDescription;\n    private List<String> mScopeList;\n\n    public XposedModuleInfo(@NonNull ApplicationInfo applicationInfo, @Nullable ZipFile modernModuleApk) {\n        mApp = applicationInfo;\n        packageName = mApp.packageName;\n        legacy = modernModuleApk == null;\n\n        if (legacy) {\n            Object minVersionRaw = mApp.metaData.get(\"xposedminversion\");\n            if (minVersionRaw instanceof Integer) {\n                minVersion = (Integer) minVersionRaw;\n            } else if (minVersionRaw instanceof String) {\n                minVersion = extractIntPart((String) minVersionRaw);\n            } else {\n                minVersion = 0;\n            }\n            targetVersion = minVersion; // legacy modules don't have a target version\n            staticScope = false;\n        } else {\n            int minVersion = 100;\n            int targetVersion = 100;\n            boolean staticScope = false;\n            try {\n                ZipEntry propEntry = modernModuleApk.getEntry(\"META-INF/xposed/module.prop\");\n                if (propEntry != null) {\n                    Properties prop = new Properties();\n                    prop.load(modernModuleApk.getInputStream(propEntry));\n                    minVersion = extractIntPart(prop.getProperty(\"minApiVersion\"));\n                    targetVersion = extractIntPart(prop.getProperty(\"targetApiVersion\"));\n                    staticScope = TextUtils.equals(prop.getProperty(\"staticScope\"), \"true\");\n                }\n                ZipEntry scopeEntry = modernModuleApk.getEntry(\"META-INF/xposed/scope.list\");\n                if (scopeEntry != null) {\n                    try (BufferedReader reader = new BufferedReader(new InputStreamReader(modernModuleApk.getInputStream(scopeEntry)))) {\n                        mScopeList = new ArrayList<>();\n                        String line;\n                        while ((line = reader.readLine()) != null) {\n                            mScopeList.add(line);\n                        }\n                    }\n                } else {\n                    mScopeList = Collections.emptyList();\n                }\n            } catch (IOException | OutOfMemoryError e) {\n                Log.e(TAG, \"Error while reading modern module APK\", e);\n            }\n            this.minVersion = minVersion;\n            this.targetVersion = targetVersion;\n            this.staticScope = staticScope;\n        }\n    }\n\n    public CharSequence getAppLabel(@NonNull PackageManager pm) {\n        if (mAppLabel == null)\n            mAppLabel = mApp.loadLabel(pm);\n        return mAppLabel;\n    }\n\n    public CharSequence getDescription(@NonNull PackageManager pm) {\n        if (mDescription != null) return mDescription;\n        CharSequence descriptionTmp = \"\";\n        if (legacy) {\n            Object descriptionRaw = mApp.metaData.get(\"xposeddescription\");\n            if (descriptionRaw instanceof String) {\n                descriptionTmp = ((String) descriptionRaw).trim();\n            } else if (descriptionRaw instanceof Integer) {\n                try {\n                    int resId = (Integer) descriptionRaw;\n                    if (resId != 0)\n                        descriptionTmp = pm.getResourcesForApplication(mApp).getString(resId).trim();\n                } catch (Exception ignored) {\n                }\n            }\n        } else {\n            CharSequence des = mApp.loadDescription(pm);\n            if (des != null) {\n                descriptionTmp = des;\n            }\n        }\n        mDescription = descriptionTmp;\n        return mDescription;\n    }\n\n    public List<String> getScopeList(@NonNull PackageManager pm) {\n        if (mScopeList != null) return mScopeList;\n        List<String> list = null;\n        try {\n            int scopeListResourceId = mApp.metaData.getInt(\"xposedscope\");\n            if (scopeListResourceId != 0) {\n                list = Arrays.asList(pm.getResourcesForApplication(mApp).getStringArray(scopeListResourceId));\n            } else {\n                String scopeListString = mApp.metaData.getString(\"xposedscope\");\n                if (scopeListString != null)\n                    list = Arrays.asList(scopeListString.split(\";\"));\n            }\n        } catch (Exception ignored) {\n        }\n        if (list != null) {\n            // For historical reasons, legacy modules use the opposite name.\n            // https://github.com/rovo89/XposedBridge/commit/6b49688c929a7768f3113b4c65b429c7a7032afa\n            list.replaceAll(s -> {\n                switch (s) {\n                    case \"android\":\n                        return \"system\";\n                    case \"system\":\n                        return \"android\";\n                    default:\n                        return s;\n                }\n            });\n            mScopeList = list;\n        }\n        return mScopeList;\n    }\n\n    @NonNull\n    @Override\n    public CharSequence toLocalizedString(@NonNull Context context) {\n        PackageManager pm = context.getPackageManager();\n        SpannableStringBuilder sb = new SpannableStringBuilder()\n                .append(getStyledKeyValue(context, R.string.module_name, getAppLabel(pm))).append(\"\\n\")\n                .append(getStyledKeyValue(context, R.string.title_description, getDescription(pm))).append(\"\\n\")\n                .append(getStyledKeyValue(context, R.string.type, legacy ? \"Legacy\" : \"Modern\")).append(\"\\n\");\n        if (legacy) {\n            sb.append(getStyledKeyValue(context, \"Xposed Minimum API\", String.valueOf(minVersion))).append(\"\\n\");\n        } else {\n            sb.append(getStyledKeyValue(context, \"Xposed API\", \"\")).append(\"\\n\")\n                    .append(getStyledKeyValue(context, \"  Min\", String.valueOf(minVersion))).append(\", \")\n                    .append(getStyledKeyValue(context, \"Target\", String.valueOf(targetVersion))).append(\"\\n\")\n                    .append(getStyledKeyValue(context, \"Scope\", staticScope ? \"Static\" : \"Dynamic\")).append(\"\\n\");\n        }\n        List<String> scopeList = getScopeList(pm);\n        if (scopeList != null && !scopeList.isEmpty()) {\n            sb.append(getBoldString(\"Scopes\")).append(\"\\n\").append(UiUtils.getOrderedList(scopeList));\n        }\n        return sb;\n    }\n\n    public static int extractIntPart(@NonNull String str) {\n        int result = 0, length = str.length();\n        for (int offset = 0; offset < length; offset++) {\n            char c = str.charAt(offset);\n            if ('0' <= c && c <= '9')\n                result = result * 10 + (c - '0');\n            else\n                break;\n        }\n        return result;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/misc/gles/EglCore.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage io.github.muntashirakon.AppManager.misc.gles;\n\nimport android.graphics.SurfaceTexture;\nimport android.opengl.EGL14;\nimport android.opengl.EGLConfig;\nimport android.opengl.EGLContext;\nimport android.opengl.EGLDisplay;\nimport android.opengl.EGLExt;\nimport android.opengl.EGLSurface;\nimport android.util.Log;\nimport android.view.Surface;\n\nimport androidx.annotation.Nullable;\n\n/**\n * Core EGL state (display, context, config).\n * <p>\n * The EGLContext must only be attached to one thread at a time.  This class is not thread-safe.\n */\npublic final class EglCore {\n    private static final String TAG = EglCore.class.getSimpleName();\n\n    /**\n     * Constructor flag: surface must be recordable.  This discourages EGL from using a\n     * pixel format that cannot be converted efficiently to something usable by the video\n     * encoder.\n     */\n    public static final int FLAG_RECORDABLE = 0x01;\n\n    // Android-specific extension.\n    private static final int EGL_RECORDABLE_ANDROID = 0x3142;\n\n    private EGLDisplay mEGLDisplay = EGL14.EGL_NO_DISPLAY;\n    private EGLContext mEGLContext = EGL14.EGL_NO_CONTEXT;\n    private EGLConfig mEGLConfig = null;\n    private int mGlVersion = -1;\n\n\n    /**\n     * Prepares EGL display and context.\n     * <p>\n     * Equivalent to EglCore(null, 0).\n     */\n    public EglCore() {\n        this(null, 0);\n    }\n\n    /**\n     * Prepares EGL display and context.\n     * <p>\n     *\n     * @param sharedContext The context to share, or null if sharing is not desired.\n     * @param flags         Configuration bit flags, e.g. FLAG_RECORDABLE.\n     */\n    public EglCore(@Nullable EGLContext sharedContext, int flags) {\n        if (mEGLDisplay != EGL14.EGL_NO_DISPLAY) {\n            throw new RuntimeException(\"EGL already set up\");\n        }\n\n        if (sharedContext == null) {\n            sharedContext = EGL14.EGL_NO_CONTEXT;\n        }\n\n        mEGLDisplay = EGL14.eglGetDisplay(EGL14.EGL_DEFAULT_DISPLAY);\n        if (mEGLDisplay == EGL14.EGL_NO_DISPLAY) {\n            throw new RuntimeException(\"unable to get EGL14 display\");\n        }\n        int[] version = new int[2];\n        if (!EGL14.eglInitialize(mEGLDisplay, version, 0, version, 1)) {\n            mEGLDisplay = null;\n            throw new RuntimeException(\"unable to initialize EGL14\");\n        }\n\n        // Try to get a GLES3 context\n        {\n            EGLConfig config = getConfig(flags, 3);\n            if (config != null) {\n                int[] attrib3_list = {\n                        EGL14.EGL_CONTEXT_CLIENT_VERSION, 3,\n                        EGL14.EGL_NONE\n                };\n                EGLContext context = EGL14.eglCreateContext(mEGLDisplay, config, sharedContext,\n                        attrib3_list, 0);\n\n                if (EGL14.eglGetError() == EGL14.EGL_SUCCESS) {\n                    mEGLConfig = config;\n                    mEGLContext = context;\n                    mGlVersion = 3;\n                }\n            }\n        }\n        if (mEGLContext == EGL14.EGL_NO_CONTEXT) {  // GLES 3 attempt failed\n            EGLConfig config = getConfig(flags, 2);\n            if (config == null) {\n                throw new RuntimeException(\"Unable to find a suitable EGLConfig\");\n            }\n            int[] attrib2_list = {\n                    EGL14.EGL_CONTEXT_CLIENT_VERSION, 2,\n                    EGL14.EGL_NONE\n            };\n            EGLContext context = EGL14.eglCreateContext(mEGLDisplay, config, sharedContext,\n                    attrib2_list, 0);\n            checkEglError(\"eglCreateContext\");\n            mEGLConfig = config;\n            mEGLContext = context;\n            mGlVersion = 2;\n        }\n\n        // Confirm with query.\n        int[] values = new int[1];\n        EGL14.eglQueryContext(mEGLDisplay, mEGLContext, EGL14.EGL_CONTEXT_CLIENT_VERSION,\n                values, 0);\n        Log.d(TAG, \"EGLContext created, client version \" + values[0]);\n    }\n\n    /**\n     * Finds a suitable EGLConfig.\n     *\n     * @param flags   Bit flags from constructor.\n     * @param version Must be 2 or 3.\n     */\n    @Nullable\n    private EGLConfig getConfig(int flags, int version) {\n        int renderableType = EGL14.EGL_OPENGL_ES2_BIT;\n        if (version >= 3) {\n            renderableType |= EGLExt.EGL_OPENGL_ES3_BIT_KHR;\n        }\n\n        // The actual surface is generally RGBA or RGBX, so situationally omitting alpha\n        // doesn't really help.  It can also lead to a huge performance hit on glReadPixels()\n        // when reading into a GL_RGBA buffer.\n        int[] attribList = {\n                EGL14.EGL_RED_SIZE, 8,\n                EGL14.EGL_GREEN_SIZE, 8,\n                EGL14.EGL_BLUE_SIZE, 8,\n                EGL14.EGL_ALPHA_SIZE, 8,\n                //EGL14.EGL_DEPTH_SIZE, 16,\n                //EGL14.EGL_STENCIL_SIZE, 8,\n                EGL14.EGL_RENDERABLE_TYPE, renderableType,\n                EGL14.EGL_NONE, 0,      // placeholder for recordable [@-3]\n                EGL14.EGL_NONE\n        };\n        if ((flags & FLAG_RECORDABLE) != 0) {\n            attribList[attribList.length - 3] = EGL_RECORDABLE_ANDROID;\n            attribList[attribList.length - 2] = 1;\n        }\n        EGLConfig[] configs = new EGLConfig[1];\n        int[] numConfigs = new int[1];\n        if (!EGL14.eglChooseConfig(mEGLDisplay, attribList, 0, configs, 0, configs.length,\n                numConfigs, 0)) {\n            Log.w(TAG, \"unable to find RGB8888 / \" + version + \" EGLConfig\");\n            return null;\n        }\n        return configs[0];\n    }\n\n    /**\n     * Discards all resources held by this class, notably the EGL context.  This must be\n     * called from the thread where the context was created.\n     * <p>\n     * On completion, no context will be current.\n     */\n    public void release() {\n        if (mEGLDisplay != EGL14.EGL_NO_DISPLAY) {\n            // Android is unusual in that it uses a reference-counted EGLDisplay.  So for\n            // every eglInitialize() we need an eglTerminate().\n            EGL14.eglMakeCurrent(mEGLDisplay, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_SURFACE,\n                    EGL14.EGL_NO_CONTEXT);\n            EGL14.eglDestroyContext(mEGLDisplay, mEGLContext);\n            EGL14.eglReleaseThread();\n            EGL14.eglTerminate(mEGLDisplay);\n        }\n\n        mEGLDisplay = EGL14.EGL_NO_DISPLAY;\n        mEGLContext = EGL14.EGL_NO_CONTEXT;\n        mEGLConfig = null;\n    }\n\n    @Override\n    protected void finalize() throws Throwable {\n        try {\n            if (mEGLDisplay != EGL14.EGL_NO_DISPLAY) {\n                // We're limited here -- finalizers don't run on the thread that holds\n                // the EGL state, so if a surface or context is still current on another\n                // thread we can't fully release it here.  Exceptions thrown from here\n                // are quietly discarded.  Complain in the log file.\n                Log.w(TAG, \"WARNING: EglCore was not explicitly released -- state may be leaked\");\n                release();\n            }\n        } finally {\n            super.finalize();\n        }\n    }\n\n    /**\n     * Destroys the specified surface.  Note the EGLSurface won't actually be destroyed if it's\n     * still current in a context.\n     */\n    public void releaseSurface(EGLSurface eglSurface) {\n        EGL14.eglDestroySurface(mEGLDisplay, eglSurface);\n    }\n\n    /**\n     * Creates an EGL surface associated with a Surface.\n     * <p>\n     * If this is destined for MediaCodec, the EGLConfig should have the \"recordable\" attribute.\n     */\n    public EGLSurface createWindowSurface(Object surface) {\n        if (!(surface instanceof Surface) && !(surface instanceof SurfaceTexture)) {\n            throw new RuntimeException(\"invalid surface: \" + surface);\n        }\n\n        // Create a window surface, and attach it to the Surface we received.\n        int[] surfaceAttribs = {\n                EGL14.EGL_NONE\n        };\n        EGLSurface eglSurface = EGL14.eglCreateWindowSurface(mEGLDisplay, mEGLConfig, surface,\n                surfaceAttribs, 0);\n        checkEglError(\"eglCreateWindowSurface\");\n        if (eglSurface == null) {\n            throw new RuntimeException(\"surface was null\");\n        }\n        return eglSurface;\n    }\n\n    /**\n     * Creates an EGL surface associated with an offscreen buffer.\n     */\n    public EGLSurface createOffscreenSurface(int width, int height) {\n        int[] surfaceAttribs = {\n                EGL14.EGL_WIDTH, width,\n                EGL14.EGL_HEIGHT, height,\n                EGL14.EGL_NONE\n        };\n        EGLSurface eglSurface = EGL14.eglCreatePbufferSurface(mEGLDisplay, mEGLConfig,\n                surfaceAttribs, 0);\n        checkEglError(\"eglCreatePbufferSurface\");\n        if (eglSurface == null) {\n            throw new RuntimeException(\"surface was null\");\n        }\n        return eglSurface;\n    }\n\n    /**\n     * Makes our EGL context current, using the supplied surface for both \"draw\" and \"read\".\n     */\n    public void makeCurrent(EGLSurface eglSurface) {\n        if (mEGLDisplay == EGL14.EGL_NO_DISPLAY) {\n            // called makeCurrent() before create?\n            Log.d(TAG, \"NOTE: makeCurrent w/o display\");\n        }\n        if (!EGL14.eglMakeCurrent(mEGLDisplay, eglSurface, eglSurface, mEGLContext)) {\n            throw new RuntimeException(\"eglMakeCurrent failed\");\n        }\n    }\n\n    /**\n     * Makes our EGL context current, using the supplied \"draw\" and \"read\" surfaces.\n     */\n    public void makeCurrent(EGLSurface drawSurface, EGLSurface readSurface) {\n        if (mEGLDisplay == EGL14.EGL_NO_DISPLAY) {\n            // called makeCurrent() before create?\n            Log.d(TAG, \"NOTE: makeCurrent w/o display\");\n        }\n        if (!EGL14.eglMakeCurrent(mEGLDisplay, drawSurface, readSurface, mEGLContext)) {\n            throw new RuntimeException(\"eglMakeCurrent(draw,read) failed\");\n        }\n    }\n\n    /**\n     * Makes no context current.\n     */\n    public void makeNothingCurrent() {\n        if (!EGL14.eglMakeCurrent(mEGLDisplay, EGL14.EGL_NO_SURFACE, EGL14.EGL_NO_SURFACE,\n                EGL14.EGL_NO_CONTEXT)) {\n            throw new RuntimeException(\"eglMakeCurrent failed\");\n        }\n    }\n\n    /**\n     * Calls eglSwapBuffers.  Use this to \"publish\" the current frame.\n     *\n     * @return false on failure\n     */\n    public boolean swapBuffers(EGLSurface eglSurface) {\n        return EGL14.eglSwapBuffers(mEGLDisplay, eglSurface);\n    }\n\n    /**\n     * Sends the presentation time stamp to EGL.  Time is expressed in nanoseconds.\n     */\n    public void setPresentationTime(EGLSurface eglSurface, long nsecs) {\n        EGLExt.eglPresentationTimeANDROID(mEGLDisplay, eglSurface, nsecs);\n    }\n\n    /**\n     * Returns true if our context and the specified surface are current.\n     */\n    public boolean isCurrent(EGLSurface eglSurface) {\n        return mEGLContext.equals(EGL14.eglGetCurrentContext()) &&\n                eglSurface.equals(EGL14.eglGetCurrentSurface(EGL14.EGL_DRAW));\n    }\n\n    /**\n     * Performs a simple surface query.\n     */\n    public int querySurface(EGLSurface eglSurface, int what) {\n        int[] value = new int[1];\n        EGL14.eglQuerySurface(mEGLDisplay, eglSurface, what, value, 0);\n        return value[0];\n    }\n\n    /**\n     * Queries a string value.\n     */\n    public String queryString(int what) {\n        return EGL14.eglQueryString(mEGLDisplay, what);\n    }\n\n    /**\n     * Returns the GLES version this context is configured for (currently 2 or 3).\n     */\n    public int getGlVersion() {\n        return mGlVersion;\n    }\n\n    /**\n     * Writes the current display, context, and surface to the log.\n     */\n    public static void logCurrent(String msg) {\n        EGLDisplay display;\n        EGLContext context;\n        EGLSurface surface;\n\n        display = EGL14.eglGetCurrentDisplay();\n        context = EGL14.eglGetCurrentContext();\n        surface = EGL14.eglGetCurrentSurface(EGL14.EGL_DRAW);\n        Log.i(TAG, \"Current EGL (\" + msg + \"): display=\" + display + \", context=\" + context +\n                \", surface=\" + surface);\n    }\n\n    /**\n     * Checks for EGL errors.  Throws an exception if an error has been raised.\n     */\n    private void checkEglError(String msg) {\n        int error;\n        if ((error = EGL14.eglGetError()) != EGL14.EGL_SUCCESS) {\n            throw new RuntimeException(msg + \": EGL error: 0x\" + Integer.toHexString(error));\n        }\n    }\n}"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/misc/gles/EglSurfaceBase.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage io.github.muntashirakon.AppManager.misc.gles;\n\nimport android.graphics.Bitmap;\nimport android.opengl.EGL14;\nimport android.opengl.EGLSurface;\nimport android.opengl.GLES20;\nimport android.util.Log;\n\nimport java.io.BufferedOutputStream;\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.nio.ByteBuffer;\nimport java.nio.ByteOrder;\n\n/**\n * Common base class for EGL surfaces.\n * <p>\n * There can be multiple surfaces associated with a single context.\n */\n// Copyright 2014 Google Inc.\npublic class EglSurfaceBase {\n    protected static final String TAG = EglSurfaceBase.class.getSimpleName();\n\n    // EglCore object we're associated with.  It may be associated with multiple surfaces.\n    protected EglCore mEglCore;\n\n    private EGLSurface mEGLSurface = EGL14.EGL_NO_SURFACE;\n    private int mWidth = -1;\n    private int mHeight = -1;\n\n    protected EglSurfaceBase(EglCore eglCore) {\n        mEglCore = eglCore;\n    }\n\n    /**\n     * Creates a window surface.\n     * <p>\n     *\n     * @param surface May be a Surface or SurfaceTexture.\n     */\n    public void createWindowSurface(Object surface) {\n        if (mEGLSurface != EGL14.EGL_NO_SURFACE) {\n            throw new IllegalStateException(\"surface already created\");\n        }\n        mEGLSurface = mEglCore.createWindowSurface(surface);\n\n        // Don't cache width/height here, because the size of the underlying surface can change\n        // out from under us (see e.g. HardwareScalerActivity).\n        //mWidth = mEglCore.querySurface(mEGLSurface, EGL14.EGL_WIDTH);\n        //mHeight = mEglCore.querySurface(mEGLSurface, EGL14.EGL_HEIGHT);\n    }\n\n    /**\n     * Creates an off-screen surface.\n     */\n    public void createOffscreenSurface(int width, int height) {\n        if (mEGLSurface != EGL14.EGL_NO_SURFACE) {\n            throw new IllegalStateException(\"surface already created\");\n        }\n        mEGLSurface = mEglCore.createOffscreenSurface(width, height);\n        mWidth = width;\n        mHeight = height;\n    }\n\n    /**\n     * Returns the surface's width, in pixels.\n     * <p>\n     * If this is called on a window surface, and the underlying surface is in the process\n     * of changing size, we may not see the new size right away (e.g. in the \"surfaceChanged\"\n     * callback).  The size should match after the next buffer swap.\n     */\n    public int getWidth() {\n        if (mWidth < 0) {\n            return mEglCore.querySurface(mEGLSurface, EGL14.EGL_WIDTH);\n        } else {\n            return mWidth;\n        }\n    }\n\n    /**\n     * Returns the surface's height, in pixels.\n     */\n    public int getHeight() {\n        if (mHeight < 0) {\n            return mEglCore.querySurface(mEGLSurface, EGL14.EGL_HEIGHT);\n        } else {\n            return mHeight;\n        }\n    }\n\n    /**\n     * Release the EGL surface.\n     */\n    public void releaseEglSurface() {\n        mEglCore.releaseSurface(mEGLSurface);\n        mEGLSurface = EGL14.EGL_NO_SURFACE;\n        mWidth = mHeight = -1;\n    }\n\n    /**\n     * Makes our EGL context and surface current.\n     */\n    public void makeCurrent() {\n        mEglCore.makeCurrent(mEGLSurface);\n    }\n\n    /**\n     * Makes our EGL context and surface current for drawing, using the supplied surface\n     * for reading.\n     */\n    public void makeCurrentReadFrom(EglSurfaceBase readSurface) {\n        mEglCore.makeCurrent(mEGLSurface, readSurface.mEGLSurface);\n    }\n\n    /**\n     * Calls eglSwapBuffers.  Use this to \"publish\" the current frame.\n     *\n     * @return false on failure\n     */\n    public boolean swapBuffers() {\n        boolean result = mEglCore.swapBuffers(mEGLSurface);\n        if (!result) {\n            Log.d(TAG, \"WARNING: swapBuffers() failed\");\n        }\n        return result;\n    }\n\n    /**\n     * Sends the presentation time stamp to EGL.\n     *\n     * @param nsecs Timestamp, in nanoseconds.\n     */\n    public void setPresentationTime(long nsecs) {\n        mEglCore.setPresentationTime(mEGLSurface, nsecs);\n    }\n\n    /**\n     * Saves the EGL surface to a file.\n     * <p>\n     * Expects that this object's EGL surface is current.\n     */\n    public void saveFrame(File file) throws IOException {\n        if (!mEglCore.isCurrent(mEGLSurface)) {\n            throw new RuntimeException(\"Expected EGL context/surface is not current\");\n        }\n\n        // glReadPixels fills in a \"direct\" ByteBuffer with what is essentially big-endian RGBA\n        // data (i.e. a byte of red, followed by a byte of green...).  While the Bitmap\n        // constructor that takes an int[] wants little-endian ARGB (blue/red swapped), the\n        // Bitmap \"copy pixels\" method wants the same format GL provides.\n        //\n        // Ideally we'd have some way to re-use the ByteBuffer, especially if we're calling\n        // here often.\n        //\n        // Making this even more interesting is the upside-down nature of GL, which means\n        // our output will look upside down relative to what appears on screen if the\n        // typical GL conventions are used.\n\n        String filename = file.toString();\n\n        int width = getWidth();\n        int height = getHeight();\n        ByteBuffer buf = ByteBuffer.allocateDirect(width * height * 4);\n        buf.order(ByteOrder.LITTLE_ENDIAN);\n        GLES20.glReadPixels(0, 0, width, height,\n                GLES20.GL_RGBA, GLES20.GL_UNSIGNED_BYTE, buf);\n        GlUtil.checkGlError(\"glReadPixels\");\n        buf.rewind();\n\n        BufferedOutputStream bos = null;\n        try {\n            bos = new BufferedOutputStream(new FileOutputStream(filename));\n            Bitmap bmp = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);\n            bmp.copyPixelsFromBuffer(buf);\n            bmp.compress(Bitmap.CompressFormat.PNG, 90, bos);\n            bmp.recycle();\n        } finally {\n            if (bos != null) bos.close();\n        }\n        Log.d(TAG, \"Saved \" + width + \"x\" + height + \" frame as '\" + filename + \"'\");\n    }\n}"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/misc/gles/GlUtil.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage io.github.muntashirakon.AppManager.misc.gles;\n\nimport android.opengl.GLES20;\nimport android.util.Log;\n\n/**\n * Some OpenGL utility functions.\n */\n// Copyright 2014 Google Inc.\npublic final class GlUtil {\n    public static final String TAG = GlUtil.class.getSimpleName();\n\n    private GlUtil() {}     // do not instantiate\n\n    /**\n     * Checks to see if a GLES error has been raised.\n     */\n    public static void checkGlError(String op) {\n        int error = GLES20.glGetError();\n        if (error != GLES20.GL_NO_ERROR) {\n            String msg = op + \": glError 0x\" + Integer.toHexString(error);\n            Log.e(TAG, msg);\n            throw new RuntimeException(msg);\n        }\n    }\n}"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/misc/gles/OffscreenSurface.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage io.github.muntashirakon.AppManager.misc.gles;\n\n/**\n * Off-screen EGL surface (pbuffer).\n * <p>\n * It's good practice to explicitly release() the surface, preferably from a \"finally\" block.\n */\n// Copyright 2014 Google Inc.\npublic class OffscreenSurface extends EglSurfaceBase {\n    /**\n     * Creates an off-screen surface with the specified width and height.\n     */\n    public OffscreenSurface(EglCore eglCore, int width, int height) {\n        super(eglCore);\n        createOffscreenSurface(width, height);\n    }\n\n    /**\n     * Releases any resources associated with the surface.\n     */\n    public void release() {\n        releaseEglSurface();\n    }\n}"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/misc/gles/package.html",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n\nSource: https://github.com/google/grafika"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/miui/MiuiVersionInfo.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.miui;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\n// https://www.xiaomist.com/2020/08/what-do-letters-and-numbers-that.html\npublic class MiuiVersionInfo {\n    @NonNull\n    public final String version;\n    @Nullable\n    public final String letters;\n    public final boolean isBeta;\n\n    public MiuiVersionInfo(@NonNull String version, @Nullable String letters, boolean isBeta) {\n        this.version = version;\n        this.letters = letters;\n        this.isBeta = isBeta || letters == null;\n    }\n\n    @NonNull\n    public String getVersion() {\n        return version;\n    }\n\n    @Nullable\n    public String getMiuiVersion() {\n        if (isBeta) {\n            return null;\n        }\n        String[] splits = version.split(\"\\\\.\");\n        return splits[0] + '.' + splits[1];\n    }\n\n    @Nullable\n    public String getRomVersion() {\n        if (isBeta) {\n            return null;\n        }\n        String[] splits  = version.split(\"\\\\.\");\n        return splits[2] + '.' + splits[3];\n    }\n\n    @Nullable\n    public String getAndroidVersionCodeName() {\n        if (letters == null) {\n            return null;\n        }\n        String[] splits = letters.split(\"\\\\.\");\n        return splits[0];\n    }\n\n    @Nullable\n    public String getTargetDevice() {\n        if (letters == null) {\n            return null;\n        }\n        String[] splits = letters.split(\"\\\\.\");\n        return splits[1] + splits[2];\n    }\n\n    @Nullable\n    public String getRegion() {\n        if (letters == null) {\n            return null;\n        }\n        String[] splits = letters.split(\"\\\\.\");\n        return splits[3] + splits[4];\n    }\n\n    @Nullable\n    public String getOrigin() {\n        if (letters == null) {\n            return null;\n        }\n        String[] splits = letters.split(\"\\\\.\");\n        return splits[5] + splits[6];\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/oneclickops/AppOpCount.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.oneclickops;\n\nimport java.util.Collection;\n\npublic class AppOpCount extends ItemCount {\n    public Collection<Integer> appOps;\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/oneclickops/BackupTasksDialogFragment.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.oneclickops;\n\nimport android.app.Dialog;\nimport android.os.Bundle;\nimport android.os.PowerManager;\nimport android.text.SpannableStringBuilder;\nimport android.view.View;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.UiThread;\nimport androidx.fragment.app.DialogFragment;\n\nimport com.google.android.material.dialog.MaterialAlertDialogBuilder;\n\nimport java.io.IOException;\nimport java.lang.ref.WeakReference;\nimport java.util.ArrayList;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Set;\nimport java.util.concurrent.Future;\n\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.backup.BackupManager;\nimport io.github.muntashirakon.AppManager.backup.dialog.BackupRestoreDialogFragment;\nimport io.github.muntashirakon.AppManager.db.entity.Backup;\nimport io.github.muntashirakon.AppManager.main.ApplicationItem;\nimport io.github.muntashirakon.AppManager.self.SelfPermissions;\nimport io.github.muntashirakon.AppManager.settings.FeatureController;\nimport io.github.muntashirakon.AppManager.usage.AppUsageStatsManager;\nimport io.github.muntashirakon.AppManager.usage.TimeInterval;\nimport io.github.muntashirakon.AppManager.utils.CpuUtils;\nimport io.github.muntashirakon.AppManager.utils.LangUtils;\nimport io.github.muntashirakon.AppManager.utils.PackageUtils;\nimport io.github.muntashirakon.AppManager.utils.ThreadUtils;\nimport io.github.muntashirakon.AppManager.utils.UIUtils;\nimport io.github.muntashirakon.dialog.SearchableMultiChoiceDialogBuilder;\nimport io.github.muntashirakon.io.DirectoryUtils;\nimport io.github.muntashirakon.io.Paths;\n\npublic class BackupTasksDialogFragment extends DialogFragment {\n    public static final String TAG = \"BackupTasksDialogFragment\";\n\n    private OneClickOpsActivity mActivity;\n    private Future<?> mFuture;\n\n    @NonNull\n    @Override\n    public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {\n        mActivity = (OneClickOpsActivity) requireActivity();\n        View view = View.inflate(requireContext(), R.layout.dialog_backup_tasks, null);\n        // Backup all installed apps\n        view.findViewById(R.id.backup_all).setOnClickListener(v -> {\n            mActivity.progressIndicator.show();\n            if (mFuture != null) {\n                mFuture.cancel(true);\n            }\n            WeakReference<PowerManager.WakeLock> wakeLockRef = new WeakReference<>(mActivity.wakeLock);\n            mFuture = ThreadUtils.postOnBackgroundThread(() -> {\n                PowerManager.WakeLock wakeLock = wakeLockRef.get();\n                if (wakeLock != null && !wakeLock.isHeld()) {\n                    wakeLock.acquire();\n                }\n                try {\n                    List<ApplicationItem> applicationItems = new ArrayList<>();\n                    List<CharSequence> applicationLabels = new ArrayList<>();\n                    for (ApplicationItem item : PackageUtils.getInstalledOrBackedUpApplicationsFromDb(requireContext(), false, true)) {\n                        if (ThreadUtils.isInterrupted()) return;\n                        if (item.isInstalled) {\n                            applicationItems.add(item);\n                            applicationLabels.add(item.label);\n                        }\n                    }\n                    if (ThreadUtils.isInterrupted()) return;\n                    ThreadUtils.postOnMainThread(() -> runMultiChoiceDialog(applicationItems, applicationLabels));\n                } finally {\n                    CpuUtils.releaseWakeLock(wakeLock);\n                }\n            });\n        });\n        // Redo existing backups for the installed apps\n        view.findViewById(R.id.redo_existing_backups).setOnClickListener(v -> {\n            mActivity.progressIndicator.show();\n            if (mFuture != null) {\n                mFuture.cancel(true);\n            }\n            WeakReference<PowerManager.WakeLock> wakeLockRef = new WeakReference<>(mActivity.wakeLock);\n            mFuture = ThreadUtils.postOnBackgroundThread(() -> {\n                PowerManager.WakeLock wakeLock = wakeLockRef.get();\n                if (wakeLock != null && !wakeLock.isHeld()) {\n                    wakeLock.acquire();\n                }\n                try {\n                    List<ApplicationItem> applicationItems = new ArrayList<>();\n                    List<CharSequence> applicationLabels = new ArrayList<>();\n                    for (ApplicationItem item : PackageUtils.getInstalledOrBackedUpApplicationsFromDb(requireContext(), false, true)) {\n                        if (ThreadUtils.isInterrupted()) return;\n                        if (item.isInstalled && item.backup != null) {\n                            applicationItems.add(item);\n                            applicationLabels.add(item.label);\n                        }\n                    }\n                    if (ThreadUtils.isInterrupted()) return;\n                    ThreadUtils.postOnMainThread(() -> runMultiChoiceDialog(applicationItems, applicationLabels));\n                } finally {\n                    CpuUtils.releaseWakeLock(wakeLock);\n                }\n            });\n        });\n        // Backup apps without any previous backups\n        view.findViewById(R.id.backup_apps_without_backup).setOnClickListener(v -> {\n            mActivity.progressIndicator.show();\n            if (mFuture != null) {\n                mFuture.cancel(true);\n            }\n            WeakReference<PowerManager.WakeLock> wakeLockRef = new WeakReference<>(mActivity.wakeLock);\n            mFuture = ThreadUtils.postOnBackgroundThread(() -> {\n                PowerManager.WakeLock wakeLock = wakeLockRef.get();\n                if (wakeLock != null && !wakeLock.isHeld()) {\n                    wakeLock.acquire();\n                }\n                try {\n                    List<ApplicationItem> applicationItems = new ArrayList<>();\n                    List<CharSequence> applicationLabels = new ArrayList<>();\n                    for (ApplicationItem item : PackageUtils.getInstalledOrBackedUpApplicationsFromDb(requireContext(), false, true)) {\n                        if (ThreadUtils.isInterrupted()) return;\n                        if (item.isInstalled && item.backup == null) {\n                            applicationItems.add(item);\n                            applicationLabels.add(item.label);\n                        }\n                    }\n                    if (ThreadUtils.isInterrupted()) return;\n                    ThreadUtils.postOnMainThread(() -> runMultiChoiceDialog(applicationItems, applicationLabels));\n                } finally {\n                    CpuUtils.releaseWakeLock(wakeLock);\n                }\n            });\n        });\n        view.findViewById(R.id.verify_and_redo_backups).setOnClickListener(v -> {\n            mActivity.progressIndicator.show();\n            if (mFuture != null) {\n                mFuture.cancel(true);\n            }\n            WeakReference<PowerManager.WakeLock> wakeLockRef = new WeakReference<>(mActivity.wakeLock);\n            mFuture = ThreadUtils.postOnBackgroundThread(() -> {\n                PowerManager.WakeLock wakeLock = wakeLockRef.get();\n                if (wakeLock != null && !wakeLock.isHeld()) {\n                    wakeLock.acquire();\n                }\n                try {\n                    List<ApplicationItem> applicationItems = new ArrayList<>();\n                    List<CharSequence> applicationLabels = new ArrayList<>();\n                    Backup backup;\n                    BackupManager backupManager = new BackupManager();\n                    for (ApplicationItem item : PackageUtils.getInstalledOrBackedUpApplicationsFromDb(requireContext(), false, true)) {\n                        if (ThreadUtils.isInterrupted()) return;\n                        backup = item.backup;\n                        if (backup == null || !item.isInstalled) continue;\n                        try {\n                            backupManager.verify(backup.relativeDir);\n                        } catch (Throwable e) {\n                            applicationItems.add(item);\n                            applicationLabels.add(new SpannableStringBuilder(backup.label)\n                                    .append(LangUtils.getSeparatorString())\n                                    .append(backup.backupName)\n                                    .append('\\n')\n                                    .append(UIUtils.getSmallerText(UIUtils.getSecondaryText(mActivity,\n                                            new SpannableStringBuilder(backup.packageName)\n                                                    .append('\\n')\n                                                    .append(e.getMessage())))));\n                        }\n                    }\n                    if (ThreadUtils.isInterrupted()) return;\n                    ThreadUtils.postOnMainThread(() -> runMultiChoiceDialog(applicationItems, applicationLabels));\n                } finally {\n                    CpuUtils.releaseWakeLock(wakeLock);\n                }\n            });\n        });\n        view.findViewById(R.id.backup_apps_with_changes).setOnClickListener(v -> {\n            mActivity.progressIndicator.show();\n            if (mFuture != null) {\n                mFuture.cancel(true);\n            }\n            WeakReference<PowerManager.WakeLock> wakeLockRef = new WeakReference<>(mActivity.wakeLock);\n            mFuture = ThreadUtils.postOnBackgroundThread(() -> {\n                PowerManager.WakeLock wakeLock = wakeLockRef.get();\n                if (wakeLock != null && !wakeLock.isHeld()) {\n                    wakeLock.acquire();\n                }\n                try {\n                    List<ApplicationItem> applicationItems = new ArrayList<>();\n                    List<CharSequence> applicationLabels = new ArrayList<>();\n                    Set<String> ignoredDirs = new HashSet<>();\n                    ignoredDirs.add(\"cache\");\n                    ignoredDirs.add(\"code_cache\");\n                    ignoredDirs.add(\"no_backup\");\n                    boolean hasUsageAccess = FeatureController.isUsageAccessEnabled() && SelfPermissions.checkUsageStatsPermission();\n                    BackupManager backupManager = new BackupManager();\n                    Backup backup;\n                    for (ApplicationItem item : PackageUtils.getInstalledOrBackedUpApplicationsFromDb(requireContext(), false, true)) {\n                        if (ThreadUtils.isInterrupted()) return;\n                        backup = item.backup;\n                        if (backup == null) continue;\n                        // Checks\n                        // 0. App is installed (Skip backup)\n                        if (!item.isInstalled) continue;\n                        // 1. App version code and 2. last update date (Whether to back up source)\n                        boolean needSourceUpdate = item.versionCode > backup.versionCode\n                                || item.lastUpdateTime > backup.backupTime;\n                        if (needSourceUpdate\n                                // 3. Last activity date\n                                || (hasUsageAccess && AppUsageStatsManager.getLastActivityTime(item.packageName,\n                                new TimeInterval(backup.backupTime, System.currentTimeMillis())) > backup.backupTime)\n                                // 4. Check directory change\n                                || isDataDirectoryChanged(backup, ignoredDirs)\n                                // 5. Check integrity\n                                || !isVerified(backupManager, backup)) {\n                            applicationItems.add(item);\n                            applicationLabels.add(new SpannableStringBuilder().append(backup.label)\n                                    .append(LangUtils.getSeparatorString())\n                                    .append(backup.backupName)\n                                    .append('\\n')\n                                    .append(UIUtils.getSmallerText(UIUtils.getSecondaryText(mActivity, backup.packageName))));\n                        }\n                    }\n                    if (ThreadUtils.isInterrupted()) return;\n                    ThreadUtils.postOnMainThread(() -> runMultiChoiceDialog(applicationItems, applicationLabels));\n                } finally {\n                    CpuUtils.releaseWakeLock(wakeLock);\n                }\n            });\n        });\n        return new MaterialAlertDialogBuilder(mActivity)\n                .setView(view)\n                .setTitle(R.string.back_up)\n                .setNegativeButton(R.string.cancel, null)\n                .create();\n    }\n\n    @UiThread\n    private void runMultiChoiceDialog(List<ApplicationItem> applicationItems, List<CharSequence> applicationLabels) {\n        if (isDetached()) return;\n        mActivity.progressIndicator.hide();\n        new SearchableMultiChoiceDialogBuilder<>(mActivity, applicationItems, applicationLabels)\n                .addSelections(applicationItems)\n                .setTitle(R.string.filtered_packages)\n                .setPositiveButton(R.string.back_up, (dialog, which, selectedItems) -> {\n                    if (isDetached()) return;\n                    BackupRestoreDialogFragment fragment = BackupRestoreDialogFragment.getInstance(\n                            PackageUtils.getUserPackagePairs(selectedItems), BackupRestoreDialogFragment.MODE_BACKUP);\n                    fragment.setOnActionBeginListener(mode -> mActivity.progressIndicator.show());\n                    fragment.setOnActionCompleteListener((mode, failedPackages) -> mActivity.progressIndicator.hide());\n                    if (isDetached()) return;\n                    fragment.show(getParentFragmentManager(), BackupRestoreDialogFragment.TAG);\n                })\n                .setNegativeButton(R.string.cancel, null)\n                .show();\n    }\n\n    @Override\n    public void onDestroy() {\n        if (mFuture != null) {\n            mFuture.cancel(true);\n        }\n        super.onDestroy();\n    }\n\n    private boolean isVerified(@NonNull BackupManager backupManager, @NonNull Backup backup) {\n        try {\n            backupManager.verify(backup.relativeDir);\n            return true;\n        } catch (Throwable ignore) {\n            return false;\n        }\n    }\n\n    private static boolean isDataDirectoryChanged(@NonNull Backup backup, Set<String> ignoredDirs) {\n        try {\n            for (String dir : backup.getItem().getMetadata().metadata.dataDirs) {\n                if (DirectoryUtils.isDirectoryChanged(Paths.get(dir), backup.backupTime, 3, ignoredDirs)) {\n                    return true;\n                }\n            }\n        } catch (IOException ignore) {\n        }\n        return false;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/oneclickops/ClearCacheAppWidget.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.oneclickops;\n\nimport android.app.PendingIntent;\nimport android.appwidget.AppWidgetManager;\nimport android.appwidget.AppWidgetProvider;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.widget.RemoteViews;\n\nimport androidx.core.app.PendingIntentCompat;\n\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.batchops.BatchOpsManager;\n\npublic class ClearCacheAppWidget extends AppWidgetProvider {\n\n    static void updateAppWidget(Context context, AppWidgetManager appWidgetManager, int appWidgetId) {\n        // Construct the RemoteViews object\n        RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.app_widget_clear_cache);\n        Intent intent = new Intent(context, OneClickOpsActivity.class);\n        intent.putExtra(OneClickOpsActivity.EXTRA_OP, BatchOpsManager.OP_CLEAR_CACHE);\n        views.setOnClickPendingIntent(android.R.id.background, PendingIntentCompat.getActivity(context, 0, intent,\n                PendingIntent.FLAG_UPDATE_CURRENT, false));\n        // Instruct the widget manager to update the widget\n        appWidgetManager.updateAppWidget(appWidgetId, views);\n    }\n\n    @Override\n    public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {\n        // There may be multiple widgets active, so update all of them\n        for (int appWidgetId : appWidgetIds) {\n            updateAppWidget(context, appWidgetManager, appWidgetId);\n        }\n    }\n\n    @Override\n    public void onAppWidgetOptionsChanged(Context context, AppWidgetManager appWidgetManager, int appWidgetId, Bundle newOptions) {\n        updateAppWidget(context, appWidgetManager, appWidgetId);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/oneclickops/ItemCount.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.oneclickops;\n\npublic class ItemCount {\n    public String packageName;\n    public String packageLabel;\n    public int count;\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/oneclickops/OneClickOpsActivity.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.oneclickops;\n\nimport static io.github.muntashirakon.AppManager.utils.PackageUtils.getAppOpModeNames;\nimport static io.github.muntashirakon.AppManager.utils.PackageUtils.getAppOpNames;\nimport static io.github.muntashirakon.AppManager.utils.UIUtils.getSmallerText;\n\nimport android.Manifest;\nimport android.content.BroadcastReceiver;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.IntentFilter;\nimport android.os.Build;\nimport android.os.Bundle;\nimport android.os.PowerManager;\nimport android.text.SpannableStringBuilder;\nimport android.view.MenuItem;\nimport android.view.View;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.collection.ArraySet;\nimport androidx.core.content.ContextCompat;\nimport androidx.lifecycle.ViewModelProvider;\n\nimport com.google.android.material.dialog.MaterialAlertDialogBuilder;\nimport com.google.android.material.progressindicator.LinearProgressIndicator;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.List;\nimport java.util.Set;\n\nimport io.github.muntashirakon.AppManager.BaseActivity;\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.apk.dexopt.DexOptDialog;\nimport io.github.muntashirakon.AppManager.batchops.BatchOpsManager;\nimport io.github.muntashirakon.AppManager.batchops.BatchOpsService;\nimport io.github.muntashirakon.AppManager.batchops.BatchQueueItem;\nimport io.github.muntashirakon.AppManager.batchops.struct.BatchAppOpsOptions;\nimport io.github.muntashirakon.AppManager.batchops.struct.BatchComponentOptions;\nimport io.github.muntashirakon.AppManager.compat.AppOpsManagerCompat;\nimport io.github.muntashirakon.AppManager.self.SelfPermissions;\nimport io.github.muntashirakon.AppManager.utils.ArrayUtils;\nimport io.github.muntashirakon.AppManager.utils.CpuUtils;\nimport io.github.muntashirakon.AppManager.utils.ListItemCreator;\nimport io.github.muntashirakon.AppManager.utils.TextUtilsCompat;\nimport io.github.muntashirakon.AppManager.utils.UIUtils;\nimport io.github.muntashirakon.AppManager.utils.Utils;\nimport io.github.muntashirakon.dialog.SearchableMultiChoiceDialogBuilder;\nimport io.github.muntashirakon.dialog.TextInputDialogBuilder;\nimport io.github.muntashirakon.dialog.TextInputDropdownDialogBuilder;\n\npublic class OneClickOpsActivity extends BaseActivity {\n    public static final String EXTRA_OP = \"op\";\n\n    LinearProgressIndicator progressIndicator;\n    PowerManager.WakeLock wakeLock;\n\n    private OneClickOpsViewModel mViewModel;\n    private ListItemCreator mItemCreator;\n    private final BroadcastReceiver mBatchOpsBroadCastReceiver = new BroadcastReceiver() {\n        @Override\n        public void onReceive(Context context, Intent intent) {\n            progressIndicator.hide();\n        }\n    };\n\n    @Override\n    protected void onAuthenticated(Bundle savedInstanceState) {\n        int op = getIntent().getIntExtra(EXTRA_OP, BatchOpsManager.OP_NONE);\n        if (op == BatchOpsManager.OP_CLEAR_CACHE) {\n            BatchQueueItem item = BatchQueueItem.getOneClickQueue(BatchOpsManager.OP_CLEAR_CACHE, null, null, null);\n            launchService(item);\n            finishAndRemoveTask();\n            return;\n        }\n        setContentView(R.layout.activity_one_click_ops);\n        setSupportActionBar(findViewById(R.id.toolbar));\n        mViewModel = new ViewModelProvider(this).get(OneClickOpsViewModel.class);\n        mItemCreator = new ListItemCreator(this, R.id.container);\n        progressIndicator = findViewById(R.id.progress_linear);\n        progressIndicator.setVisibilityAfterHide(View.GONE);\n        wakeLock = CpuUtils.getPartialWakeLock(\"1-click_ops\");\n        setItems();\n        // Watch LiveData\n        mViewModel.watchTrackerCount().observe(this, this::blockTrackers);\n        mViewModel.watchComponentCount().observe(this, listPair ->\n                blockComponents(listPair.first, listPair.second));\n        mViewModel.watchAppOpsCount().observe(this, listPairPair ->\n                setAppOps(listPairPair.first, listPairPair.second.first, listPairPair.second.second));\n        mViewModel.getClearDataCandidates().observe(this, this::clearData);\n        mViewModel.watchTrimCachesResult().observe(this, isSuccessful -> {\n            CpuUtils.releaseWakeLock(wakeLock);\n            progressIndicator.hide();\n            UIUtils.displayShortToast(isSuccessful ? R.string.done : R.string.failed);\n        });\n        mViewModel.getAppsInstalledByAmForDexOpt().observe(this, packages -> {\n            CpuUtils.releaseWakeLock(wakeLock);\n            progressIndicator.hide();\n            DexOptDialog dialog = DexOptDialog.getInstance(packages);\n            dialog.show(getSupportFragmentManager(), DexOptDialog.TAG);\n        });\n    }\n\n    private void setItems() {\n        mItemCreator.addItemWithTitleSubtitle(getString(R.string.block_unblock_trackers),\n                        getString(R.string.block_unblock_trackers_description))\n                .setOnClickListener(v -> new MaterialAlertDialogBuilder(this)\n                        .setTitle(R.string.block_unblock_trackers)\n                        .setMessage(R.string.apply_to_system_apps_question)\n                        .setPositiveButton(R.string.no, (dialog, which) -> {\n                            progressIndicator.show();\n                            if (!wakeLock.isHeld()) {\n                                wakeLock.acquire();\n                            }\n                            mViewModel.blockTrackers(false);\n                        })\n                        .setNegativeButton(R.string.yes, (dialog, which) -> {\n                            progressIndicator.show();\n                            if (!wakeLock.isHeld()) {\n                                wakeLock.acquire();\n                            }\n                            mViewModel.blockTrackers(true);\n                        })\n                        .show());\n        mItemCreator.addItemWithTitleSubtitle(getString(R.string.block_unblock_components_dots),\n                        getString(R.string.block_unblock_components_description))\n                .setOnClickListener(v -> new TextInputDialogBuilder(this, R.string.input_signatures)\n                        .setHelperText(R.string.input_signatures_description)\n                        .setCheckboxLabel(R.string.apply_to_system_apps)\n                        .setTitle(R.string.block_unblock_components_dots)\n                        .setPositiveButton(R.string.search, (dialog, which, signatureNames, systemApps) -> {\n                            if (signatureNames == null) return;\n                            progressIndicator.show();\n                            if (!wakeLock.isHeld()) {\n                                wakeLock.acquire();\n                            }\n                            String[] signatures = signatureNames.toString().split(\"\\\\s+\");\n                            mViewModel.blockComponents(systemApps, signatures);\n                        })\n                        .setNegativeButton(R.string.cancel, null)\n                        .show());\n        mItemCreator.addItemWithTitleSubtitle(getString(R.string.set_mode_for_app_ops_dots),\n                        getString(R.string.deny_app_ops_description))\n                .setOnClickListener(v -> showAppOpsSelectionDialog());\n        mItemCreator.addItemWithTitleSubtitle(getText(R.string.back_up),\n                getText(R.string.backup_msg)).setOnClickListener(v ->\n                new BackupTasksDialogFragment().show(getSupportFragmentManager(),\n                        BackupTasksDialogFragment.TAG));\n        mItemCreator.addItemWithTitleSubtitle(getText(R.string.restore),\n                getText(R.string.restore_msg)).setOnClickListener(v ->\n                new RestoreTasksDialogFragment().show(getSupportFragmentManager(),\n                        RestoreTasksDialogFragment.TAG));\n        mItemCreator.addItemWithTitleSubtitle(getString(R.string.clear_data_from_uninstalled_apps),\n                        getString(R.string.clear_data_from_uninstalled_apps_description))\n                .setOnClickListener(v -> {\n                    if (!wakeLock.isHeld()) {\n                        wakeLock.acquire();\n                    }\n                    mViewModel.clearData();\n                });\n//        mItemCreator.addItemWithTitleSubtitle(getString(R.string.clear_app_cache),\n//                        getString(R.string.clear_app_cache_description))\n//                .setOnClickListener(v -> clearAppCache());\n        mItemCreator.addItemWithTitleSubtitle(getString(R.string.trim_caches_in_all_apps),\n                        getString(R.string.trim_caches_in_all_apps_description))\n                .setOnClickListener(v -> {\n                    if (!SelfPermissions.checkSelfPermission(Manifest.permission.CLEAR_APP_CACHE)\n                            && !SelfPermissions.checkSelfOrRemotePermission(Manifest.permission.CLEAR_APP_CACHE)) {\n                        UIUtils.displayShortToast(R.string.only_works_in_root_or_adb_mode);\n                        return;\n                    }\n                    new MaterialAlertDialogBuilder(this)\n                            .setTitle(R.string.trim_caches_in_all_apps)\n                            .setMessage(R.string.are_you_sure)\n                            .setNegativeButton(R.string.no, null)\n                            .setPositiveButton(R.string.yes, (dialog, which) -> {\n                                progressIndicator.show();\n                                if (!wakeLock.isHeld()) {\n                                    wakeLock.acquire();\n                                }\n                                mViewModel.trimCaches();\n                            })\n                            .show();\n                });\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {\n            mItemCreator.addItemWithTitleSubtitle(getString(R.string.title_perform_runtime_optimization_to_apps),\n                            getString(R.string.summary_perform_runtime_optimization_to_apps))\n                    .setOnClickListener(v -> {\n                        if (SelfPermissions.isSystemOrRootOrShell()) {\n                            DexOptDialog dialog = DexOptDialog.getInstance(null);\n                            dialog.show(getSupportFragmentManager(), DexOptDialog.TAG);\n                            return;\n                        }\n                        progressIndicator.show();\n                        if (!wakeLock.isHeld()) {\n                            wakeLock.acquire();\n                        }\n                        mViewModel.listAppsInstalledByAmForDexOpt();\n                    });\n        }\n        progressIndicator.hide();\n    }\n\n    @Override\n    protected void onResume() {\n        super.onResume();\n        ContextCompat.registerReceiver(this, mBatchOpsBroadCastReceiver,\n                new IntentFilter(BatchOpsService.ACTION_BATCH_OPS_COMPLETED), ContextCompat.RECEIVER_NOT_EXPORTED);\n    }\n\n    @Override\n    protected void onPause() {\n        super.onPause();\n        unregisterReceiver(mBatchOpsBroadCastReceiver);\n        if (progressIndicator != null) {\n            progressIndicator.hide();\n        }\n    }\n\n    private void blockTrackers(@Nullable List<ItemCount> trackerCounts) {\n        CpuUtils.releaseWakeLock(wakeLock);\n        progressIndicator.hide();\n        if (trackerCounts == null) {\n            UIUtils.displayShortToast(R.string.failed_to_fetch_package_info);\n            return;\n        }\n        if (trackerCounts.isEmpty()) {\n            UIUtils.displayShortToast(R.string.no_tracker_found);\n            return;\n        }\n        final ArrayList<String> trackerPackages = new ArrayList<>();\n        final List<CharSequence> trackerPackagesWithTrackerCount = new ArrayList<>(trackerCounts.size());\n        for (ItemCount tracker : trackerCounts) {\n            trackerPackages.add(tracker.packageName);\n            trackerPackagesWithTrackerCount.add(new SpannableStringBuilder(tracker.packageLabel)\n                    .append(\"\\n\").append(getSmallerText(getResources().getQuantityString(R.plurals.no_of_trackers,\n                            tracker.count, tracker.count))));\n        }\n        new SearchableMultiChoiceDialogBuilder<>(this, trackerPackages, trackerPackagesWithTrackerCount)\n                .addSelections(trackerPackages)\n                .setTitle(R.string.filtered_packages)\n                .setPositiveButton(R.string.block, (dialog, which, selectedPackages) -> {\n                    progressIndicator.show();\n                    BatchQueueItem item = BatchQueueItem.getOneClickQueue(BatchOpsManager.OP_BLOCK_TRACKERS,\n                            selectedPackages, null, null);\n                    launchService(item);\n                })\n                .setNeutralButton(R.string.unblock, (dialog, which, selectedPackages) -> {\n                    progressIndicator.show();\n                    BatchQueueItem item = BatchQueueItem.getOneClickQueue(BatchOpsManager.OP_UNBLOCK_TRACKERS,\n                            selectedPackages, null, null);\n                    launchService(item);\n                })\n                .setNegativeButton(R.string.cancel, null)\n                .show();\n    }\n\n    private void blockComponents(@Nullable List<ItemCount> componentCounts, @NonNull String[] signatures) {\n        CpuUtils.releaseWakeLock(wakeLock);\n        progressIndicator.hide();\n        if (componentCounts == null) {\n            UIUtils.displayShortToast(R.string.failed_to_fetch_package_info);\n            return;\n        }\n        if (componentCounts.isEmpty()) {\n            UIUtils.displayShortToast(R.string.no_matching_package_found);\n            return;\n        }\n        SpannableStringBuilder builder;\n        final ArrayList<String> selectedPackages = new ArrayList<>();\n        List<CharSequence> packageNamesWithComponentCount = new ArrayList<>();\n        for (ItemCount component : componentCounts) {\n            builder = new SpannableStringBuilder(component.packageLabel)\n                    .append(\"\\n\").append(getSmallerText(getResources().getQuantityString(R.plurals.no_of_components,\n                            component.count, component.count)));\n            selectedPackages.add(component.packageName);\n            packageNamesWithComponentCount.add(builder);\n        }\n        BatchComponentOptions options = new BatchComponentOptions(signatures);\n        new SearchableMultiChoiceDialogBuilder<>(this, selectedPackages, packageNamesWithComponentCount)\n                .addSelections(selectedPackages)\n                .setTitle(R.string.filtered_packages)\n                .setPositiveButton(R.string.block, (dialog1, which1, selectedItems) -> {\n                    progressIndicator.show();\n                    BatchQueueItem item = BatchQueueItem.getOneClickQueue(BatchOpsManager.OP_BLOCK_COMPONENTS,\n                            selectedItems, null, options);\n                    launchService(item);\n                })\n                .setNeutralButton(R.string.unblock, (dialog1, which1, selectedItems) -> {\n                    progressIndicator.show();\n                    BatchQueueItem item = BatchQueueItem.getOneClickQueue(BatchOpsManager.OP_UNBLOCK_COMPONENTS,\n                            selectedItems, null, options);\n                    launchService(item);\n                })\n                .setNegativeButton(R.string.cancel, null)\n                .show();\n    }\n\n    private void showAppOpsSelectionDialog() {\n        if (!SelfPermissions.canModifyAppOpMode()) {\n            UIUtils.displayShortToast(R.string.only_works_in_root_or_adb_mode);\n            return;\n        }\n        List<Integer> modes = AppOpsManagerCompat.getModeConstants();\n        List<Integer> appOps = AppOpsManagerCompat.getAllOps();\n        List<CharSequence> modeNames = Arrays.asList(getAppOpModeNames(modes));\n        List<CharSequence> appOpNames = Arrays.asList(getAppOpNames(appOps));\n        TextInputDropdownDialogBuilder builder = new TextInputDropdownDialogBuilder(this, R.string.input_app_ops);\n        builder.setTitle(R.string.set_mode_for_app_ops_dots)\n                .setAuxiliaryInput(R.string.mode, null, null, modeNames, true)\n                .setCheckboxLabel(R.string.apply_to_system_apps)\n                .setHelperText(R.string.input_app_ops_description)\n                .setPositiveButton(R.string.search, (dialog, which, appOpNameList, systemApps) -> {\n                    if (appOpNameList == null) return;\n                    // Get mode\n                    int mode;\n                    int[] appOpList;\n                    try {\n                        String[] appOpsStr = appOpNameList.toString().split(\"\\\\s+\");\n                        if (appOpsStr.length == 0) return;\n                        mode = Utils.getIntegerFromString(builder.getAuxiliaryInput(), modeNames, modes);\n                        // User can unknowingly insert duplicate values for app ops\n                        Set<Integer> appOpSet = new ArraySet<>(appOpsStr.length);\n                        for (String appOp : appOpsStr) {\n                            appOpSet.add(Utils.getIntegerFromString(appOp, appOpNames, appOps));\n                        }\n                        appOpList = ArrayUtils.convertToIntArray(appOpSet);\n                    } catch (IllegalArgumentException e) {\n                        UIUtils.displayShortToast(R.string.failed_to_parse_some_numbers);\n                        return;\n                    }\n                    progressIndicator.show();\n                    if (!wakeLock.isHeld()) {\n                        wakeLock.acquire();\n                    }\n                    mViewModel.setAppOps(appOpList, mode, systemApps);\n                })\n                .setNegativeButton(R.string.cancel, null)\n                .show();\n    }\n\n    private void setAppOps(@Nullable List<AppOpCount> appOpCounts, @NonNull int[] appOpList, int mode) {\n        CpuUtils.releaseWakeLock(wakeLock);\n        progressIndicator.hide();\n        if (appOpCounts == null) {\n            UIUtils.displayShortToast(R.string.failed_to_fetch_package_info);\n            return;\n        }\n        if (appOpCounts.isEmpty()) {\n            UIUtils.displayShortToast(R.string.no_matching_package_found);\n            return;\n        }\n        SpannableStringBuilder builder1;\n        final ArrayList<String> selectedPackages = new ArrayList<>();\n        List<CharSequence> packagesWithAppOpCount = new ArrayList<>();\n        for (AppOpCount appOp : appOpCounts) {\n            builder1 = new SpannableStringBuilder(appOp.packageLabel)\n                    .append(\"\\n\").append(getSmallerText(\"(\" + appOp.count + \") \" + TextUtilsCompat.joinSpannable(\", \",\n                            appOpToNames(appOp.appOps))));\n            selectedPackages.add(appOp.packageName);\n            packagesWithAppOpCount.add(builder1);\n        }\n        BatchAppOpsOptions options = new BatchAppOpsOptions(appOpList, mode);\n        new SearchableMultiChoiceDialogBuilder<>(this, selectedPackages, packagesWithAppOpCount)\n                .addSelections(selectedPackages)\n                .setTitle(R.string.filtered_packages)\n                .setPositiveButton(R.string.apply, (dialog1, which1, selectedItems) -> {\n                    progressIndicator.show();\n                    BatchQueueItem item = BatchQueueItem.getOneClickQueue(BatchOpsManager.OP_SET_APP_OPS,\n                            selectedItems, null, options);\n                    launchService(item);\n                })\n                .setNegativeButton(R.string.cancel, (dialog1, which1, selectedItems) -> progressIndicator.hide())\n                .show();\n    }\n\n    private void clearData(@NonNull List<String> candidatePackages) {\n        CpuUtils.releaseWakeLock(wakeLock);\n        if (candidatePackages.isEmpty()) {\n            UIUtils.displayLongToast(R.string.no_matching_package_found);\n            return;\n        }\n        String[] packages = candidatePackages.toArray(new String[0]);\n        new SearchableMultiChoiceDialogBuilder<>(this, packages, packages)\n                .setTitle(R.string.filtered_packages)\n                .setPositiveButton(R.string.apply, (dialog1, which1, selectedItems) -> {\n                    progressIndicator.show();\n                    BatchQueueItem item = BatchQueueItem.getOneClickQueue(BatchOpsManager.OP_UNINSTALL,\n                            selectedItems, null, null);\n                    launchService(item);\n                })\n                .setNegativeButton(R.string.cancel, (dialog1, which1, selectedItems) -> progressIndicator.hide())\n                .show();\n    }\n\n    @Override\n    public boolean onOptionsItemSelected(@NonNull MenuItem item) {\n        if (item.getItemId() == android.R.id.home) {\n            finish();\n            return true;\n        }\n        return super.onOptionsItemSelected(item);\n    }\n\n    @Override\n    protected void onDestroy() {\n        CpuUtils.releaseWakeLock(wakeLock);\n        super.onDestroy();\n    }\n\n    private void launchService(@NonNull BatchQueueItem queueItem) {\n        Intent intent = BatchOpsService.getServiceIntent(this, queueItem);\n        ContextCompat.startForegroundService(this, intent);\n    }\n\n    @NonNull\n    private List<String> appOpToNames(@NonNull Collection<Integer> appOps) {\n        List<String> appOpNames = new ArrayList<>(appOps.size());\n        for (int appOp : appOps) {\n            appOpNames.add(AppOpsManagerCompat.opToName(appOp));\n        }\n        return appOpNames;\n    }\n}"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/oneclickops/OneClickOpsViewModel.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.oneclickops;\n\nimport static io.github.muntashirakon.AppManager.compat.PackageManagerCompat.MATCH_DISABLED_COMPONENTS;\nimport static io.github.muntashirakon.AppManager.compat.PackageManagerCompat.MATCH_UNINSTALLED_PACKAGES;\n\nimport android.Manifest;\nimport android.app.Application;\nimport android.content.pm.ApplicationInfo;\nimport android.content.pm.PackageInfo;\nimport android.content.pm.PackageManager;\nimport android.os.Build;\nimport android.os.RemoteException;\nimport android.os.UserHandleHidden;\n\nimport androidx.annotation.AnyThread;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.core.util.Pair;\nimport androidx.lifecycle.AndroidViewModel;\nimport androidx.lifecycle.LiveData;\nimport androidx.lifecycle.MutableLiveData;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.concurrent.Future;\n\nimport io.github.muntashirakon.AppManager.BuildConfig;\nimport io.github.muntashirakon.AppManager.compat.ApplicationInfoCompat;\nimport io.github.muntashirakon.AppManager.compat.ManifestCompat;\nimport io.github.muntashirakon.AppManager.compat.PackageManagerCompat;\nimport io.github.muntashirakon.AppManager.compat.StorageManagerCompat;\nimport io.github.muntashirakon.AppManager.rules.compontents.ComponentUtils;\nimport io.github.muntashirakon.AppManager.self.SelfPermissions;\nimport io.github.muntashirakon.AppManager.settings.Ops;\nimport io.github.muntashirakon.AppManager.users.Users;\nimport io.github.muntashirakon.AppManager.utils.PackageUtils;\nimport io.github.muntashirakon.AppManager.utils.ThreadUtils;\n\npublic class OneClickOpsViewModel extends AndroidViewModel {\n    public static final String TAG = OneClickOpsViewModel.class.getSimpleName();\n\n    private final PackageManager mPm;\n    private final MutableLiveData<List<ItemCount>> mTrackerCount = new MutableLiveData<>();\n    private final MutableLiveData<Pair<List<ItemCount>, String[]>> mComponentCount = new MutableLiveData<>();\n    private final MutableLiveData<Pair<List<AppOpCount>, Pair<int[], Integer>>> mAppOpsCount = new MutableLiveData<>();\n    private final MutableLiveData<List<String>> mClearDataCandidates = new MutableLiveData<>();\n    private final MutableLiveData<Boolean> mTrimCachesResult = new MutableLiveData<>();\n    private final MutableLiveData<String[]> mAppsInstalledByAmForDexOpt = new MutableLiveData<>();\n\n    @Nullable\n    private Future<?> mFutureResult;\n\n    public OneClickOpsViewModel(@NonNull Application application) {\n        super(application);\n        mPm = application.getPackageManager();\n    }\n\n    @Override\n    protected void onCleared() {\n        if (mFutureResult != null) {\n            mFutureResult.cancel(true);\n        }\n        super.onCleared();\n    }\n\n    public LiveData<List<ItemCount>> watchTrackerCount() {\n        return mTrackerCount;\n    }\n\n    public LiveData<Pair<List<ItemCount>, String[]>> watchComponentCount() {\n        return mComponentCount;\n    }\n\n    public LiveData<Pair<List<AppOpCount>, Pair<int[], Integer>>> watchAppOpsCount() {\n        return mAppOpsCount;\n    }\n\n    public LiveData<List<String>> getClearDataCandidates() {\n        return mClearDataCandidates;\n    }\n\n    public LiveData<Boolean> watchTrimCachesResult() {\n        return mTrimCachesResult;\n    }\n\n    public MutableLiveData<String[]> getAppsInstalledByAmForDexOpt() {\n        return mAppsInstalledByAmForDexOpt;\n    }\n\n    @AnyThread\n    public void blockTrackers(boolean systemApps) {\n        if (mFutureResult != null) {\n            mFutureResult.cancel(true);\n        }\n        mFutureResult = ThreadUtils.postOnBackgroundThread(() -> {\n            int flags = PackageManager.GET_ACTIVITIES | PackageManager.GET_RECEIVERS | PackageManager.GET_PROVIDERS\n                    | PackageManager.GET_SERVICES | MATCH_DISABLED_COMPONENTS | MATCH_UNINSTALLED_PACKAGES\n                    | PackageManagerCompat.MATCH_STATIC_SHARED_AND_SDK_LIBRARIES;\n            boolean canChangeComponentState = SelfPermissions.checkSelfOrRemotePermission(Manifest.permission.CHANGE_COMPONENT_ENABLED_STATE);\n            if (!canChangeComponentState) {\n                // Since there's no permission, it can only change its own component states\n                try {\n                    PackageInfo packageInfo = getApplication().getPackageManager().getPackageInfo(BuildConfig.APPLICATION_ID, flags);\n                    if (systemApps || !ApplicationInfoCompat.isSystemApp(packageInfo.applicationInfo)) {\n                        ItemCount trackerCount = getTrackerCountForApp(packageInfo);\n                        if (trackerCount.count > 0) {\n                            mTrackerCount.postValue(Collections.singletonList(trackerCount));\n                            return;\n                        }\n                    }\n                } catch (PackageManager.NameNotFoundException e) {\n                    e.printStackTrace();\n                }\n                mTrackerCount.postValue(Collections.emptyList());\n                return;\n            }\n            boolean crossUserPermission = SelfPermissions.checkSelfOrRemotePermission(ManifestCompat.permission.INTERACT_ACROSS_USERS)\n                    || SelfPermissions.checkSelfOrRemotePermission(ManifestCompat.permission.INTERACT_ACROSS_USERS_FULL);\n            boolean isShell = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && Users.getSelfOrRemoteUid() == Ops.SHELL_UID;\n            List<ItemCount> trackerCounts = new ArrayList<>();\n            HashSet<String> packageNames = new HashSet<>();\n            for (PackageInfo packageInfo : PackageUtils.getAllPackages(flags, !crossUserPermission)) {\n                if (packageNames.contains(packageInfo.packageName)) {\n                    continue;\n                }\n                packageNames.add(packageInfo.packageName);\n                if (ThreadUtils.isInterrupted()) return;\n                ApplicationInfo applicationInfo = packageInfo.applicationInfo;\n                if (isShell && !ApplicationInfoCompat.isTestOnly(applicationInfo)) {\n                    continue;\n                }\n                if (!systemApps && ApplicationInfoCompat.isSystemApp(applicationInfo)) {\n                    continue;\n                }\n                ItemCount trackerCount = getTrackerCountForApp(packageInfo);\n                if (trackerCount.count > 0) {\n                    trackerCounts.add(trackerCount);\n                }\n            }\n            mTrackerCount.postValue(trackerCounts);\n        });\n    }\n\n    @AnyThread\n    public void blockComponents(boolean systemApps, @NonNull String[] signatures) {\n        if (signatures.length == 0) return;\n        if (mFutureResult != null) {\n            mFutureResult.cancel(true);\n        }\n        mFutureResult = ThreadUtils.postOnBackgroundThread(() -> {\n            boolean canChangeComponentState = SelfPermissions.checkSelfOrRemotePermission(Manifest.permission.CHANGE_COMPONENT_ENABLED_STATE);\n            if (!canChangeComponentState) {\n                // Since there's no permission, it can only change its own component states\n                ApplicationInfo applicationInfo = getApplication().getApplicationInfo();\n                if (systemApps || !ApplicationInfoCompat.isSystemApp(applicationInfo)) {\n                    ItemCount componentCount = new ItemCount();\n                    componentCount.packageName = applicationInfo.packageName;\n                    componentCount.packageLabel = applicationInfo.loadLabel(mPm).toString();\n                    componentCount.count = PackageUtils.getFilteredComponents(applicationInfo.packageName,\n                            UserHandleHidden.myUserId(), signatures).size();\n                    if (componentCount.count > 0) {\n                        mComponentCount.postValue(new Pair<>(Collections.singletonList(componentCount), signatures));\n                        return;\n                    }\n                }\n                mComponentCount.postValue(new Pair<>(Collections.emptyList(), signatures));\n                return;\n            }\n            boolean crossUserPermission = SelfPermissions.checkSelfOrRemotePermission(ManifestCompat.permission.INTERACT_ACROSS_USERS)\n                    || SelfPermissions.checkSelfOrRemotePermission(ManifestCompat.permission.INTERACT_ACROSS_USERS_FULL);\n            boolean isShell = Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && Users.getSelfOrRemoteUid() == Ops.SHELL_UID;\n            List<ItemCount> componentCounts = new ArrayList<>();\n            HashSet<String> packageNames = new HashSet<>();\n            for (ApplicationInfo applicationInfo : PackageUtils.getAllApplications(MATCH_UNINSTALLED_PACKAGES\n                    | PackageManagerCompat.MATCH_STATIC_SHARED_AND_SDK_LIBRARIES, !crossUserPermission)) {\n                if (packageNames.contains(applicationInfo.packageName)) {\n                    continue;\n                }\n                packageNames.add(applicationInfo.packageName);\n                if (ThreadUtils.isInterrupted()) return;\n                if (isShell && !ApplicationInfoCompat.isTestOnly(applicationInfo))\n                    continue;\n                if (!systemApps && (applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0)\n                    continue;\n                ItemCount componentCount = new ItemCount();\n                componentCount.packageName = applicationInfo.packageName;\n                componentCount.packageLabel = applicationInfo.loadLabel(mPm).toString();\n                componentCount.count = PackageUtils.getFilteredComponents(applicationInfo.packageName,\n                        UserHandleHidden.myUserId(), signatures).size();\n                if (componentCount.count > 0) componentCounts.add(componentCount);\n            }\n            mComponentCount.postValue(new Pair<>(componentCounts, signatures));\n        });\n    }\n\n    @AnyThread\n    public void setAppOps(int[] appOpList, int mode, boolean systemApps) {\n        if (mFutureResult != null) {\n            mFutureResult.cancel(true);\n        }\n        mFutureResult = ThreadUtils.postOnBackgroundThread(() -> {\n            Pair<int[], Integer> appOpsModePair = new Pair<>(appOpList, mode);\n            List<AppOpCount> appOpCounts = new ArrayList<>();\n            HashSet<String> packageNames = new HashSet<>();\n            for (ApplicationInfo applicationInfo : PackageUtils.getAllApplications(MATCH_UNINSTALLED_PACKAGES\n                    | PackageManagerCompat.MATCH_STATIC_SHARED_AND_SDK_LIBRARIES)) {\n                if (packageNames.contains(applicationInfo.packageName)) {\n                    continue;\n                }\n                packageNames.add(applicationInfo.packageName);\n                if (ThreadUtils.isInterrupted()) return;\n                if (!systemApps && (applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0)\n                    continue;\n                AppOpCount appOpCount = new AppOpCount();\n                appOpCount.packageName = applicationInfo.packageName;\n                appOpCount.packageLabel = applicationInfo.loadLabel(mPm).toString();\n                appOpCount.appOps = PackageUtils.getFilteredAppOps(applicationInfo.packageName,\n                        UserHandleHidden.myUserId(), appOpList, mode);\n                appOpCount.count = appOpCount.appOps.size();\n                if (appOpCount.count > 0) appOpCounts.add(appOpCount);\n            }\n            mAppOpsCount.postValue(new Pair<>(appOpCounts, appOpsModePair));\n        });\n    }\n\n    public void clearData() {\n        if (mFutureResult != null) {\n            mFutureResult.cancel(true);\n        }\n        mFutureResult = ThreadUtils.postOnBackgroundThread(() -> {\n            HashSet<String> packageNames = new HashSet<>();\n            for (ApplicationInfo applicationInfo : PackageUtils.getAllApplications(MATCH_UNINSTALLED_PACKAGES\n                    | PackageManagerCompat.MATCH_STATIC_SHARED_AND_SDK_LIBRARIES)) {\n                if (packageNames.contains(applicationInfo.packageName)) {\n                    continue;\n                }\n                if (ApplicationInfoCompat.isOnlyDataInstalled(applicationInfo)) {\n                    packageNames.add(applicationInfo.packageName);\n                }\n                if (ThreadUtils.isInterrupted()) {\n                    return;\n                }\n            }\n            mClearDataCandidates.postValue(new ArrayList<>(packageNames));\n        });\n    }\n\n    @AnyThread\n    public void trimCaches() {\n        ThreadUtils.postOnBackgroundThread(() -> {\n            long size = 1024L * 1024L * 1024L * 1024L;  // 1 TB\n            try {\n                // TODO: 30/8/21 Iterate all volumes?\n                PackageManagerCompat.freeStorageAndNotify(null /* internal */, size,\n                        StorageManagerCompat.FLAG_ALLOCATE_DEFY_ALL_RESERVED);\n                mTrimCachesResult.postValue(true);\n            } catch (RemoteException e) {\n                mTrimCachesResult.postValue(false);\n            }\n        });\n    }\n\n    public void listAppsInstalledByAmForDexOpt() {\n        ThreadUtils.postOnBackgroundThread(() -> {\n            HashSet<String> packageNames = new HashSet<>();\n            for (ApplicationInfo applicationInfo : PackageUtils.getAllApplications(0)) {\n                if (packageNames.contains(applicationInfo.packageName)) {\n                    continue;\n                }\n                packageNames.add(applicationInfo.packageName);\n                if (ThreadUtils.isInterrupted()) {\n                    return;\n                }\n            }\n            mAppsInstalledByAmForDexOpt.postValue(packageNames.toArray(new String[0]));\n        });\n    }\n\n    @NonNull\n    private ItemCount getTrackerCountForApp(@NonNull PackageInfo packageInfo) {\n        ItemCount trackerCount = new ItemCount();\n        trackerCount.packageName = packageInfo.packageName;\n        trackerCount.packageLabel = packageInfo.applicationInfo.loadLabel(mPm).toString();\n        trackerCount.count = ComponentUtils.getTrackerComponentsCountForPackage(packageInfo);\n        return trackerCount;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/oneclickops/RestoreTasksDialogFragment.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.oneclickops;\n\nimport android.app.Dialog;\nimport android.os.Bundle;\nimport android.os.PowerManager;\nimport android.view.View;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.UiThread;\nimport androidx.fragment.app.DialogFragment;\n\nimport com.google.android.material.dialog.MaterialAlertDialogBuilder;\n\nimport java.lang.ref.WeakReference;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.concurrent.Future;\n\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.backup.dialog.BackupRestoreDialogFragment;\nimport io.github.muntashirakon.AppManager.main.ApplicationItem;\nimport io.github.muntashirakon.AppManager.utils.CpuUtils;\nimport io.github.muntashirakon.AppManager.utils.PackageUtils;\nimport io.github.muntashirakon.AppManager.utils.ThreadUtils;\nimport io.github.muntashirakon.dialog.SearchableMultiChoiceDialogBuilder;\n\npublic class RestoreTasksDialogFragment extends DialogFragment {\n    public static final String TAG = \"RestoreTasksDialogFragment\";\n\n    private OneClickOpsActivity mActivity;\n    private Future<?> mFuture;\n\n    @NonNull\n    @Override\n    public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {\n        mActivity = (OneClickOpsActivity) requireActivity();\n        View view = View.inflate(mActivity, R.layout.dialog_restore_tasks, null);\n        // Restore all apps\n        view.findViewById(R.id.restore_all).setOnClickListener(v -> {\n            mActivity.progressIndicator.show();\n            if (mFuture != null) {\n                mFuture.cancel(true);\n            }\n            WeakReference<PowerManager.WakeLock> wakeLockRef = new WeakReference<>(mActivity.wakeLock);\n            mFuture = ThreadUtils.postOnBackgroundThread(() -> {\n                PowerManager.WakeLock wakeLock = wakeLockRef.get();\n                if (wakeLock != null && !wakeLock.isHeld()) {\n                    wakeLock.acquire();\n                }\n                try {\n                    List<ApplicationItem> applicationItems = new ArrayList<>();\n                    List<CharSequence> applicationLabels = new ArrayList<>();\n                    for (ApplicationItem item : PackageUtils.getInstalledOrBackedUpApplicationsFromDb(requireContext(), false, true)) {\n                        if (ThreadUtils.isInterrupted()) return;\n                        if (item.backup != null) {\n                            applicationItems.add(item);\n                            applicationLabels.add(item.label);\n                        }\n                    }\n                    if (ThreadUtils.isInterrupted()) return;\n                    ThreadUtils.postOnMainThread(() -> runMultiChoiceDialog(applicationItems, applicationLabels));\n                } finally {\n                    CpuUtils.releaseWakeLock(wakeLock);\n                }\n            });\n        });\n        // Restore not installed\n        view.findViewById(R.id.restore_not_installed).setOnClickListener(v -> {\n            mActivity.progressIndicator.show();\n            if (mFuture != null) {\n                mFuture.cancel(true);\n            }\n            WeakReference<PowerManager.WakeLock> wakeLockRef = new WeakReference<>(mActivity.wakeLock);\n            mFuture = ThreadUtils.postOnBackgroundThread(() -> {\n                PowerManager.WakeLock wakeLock = wakeLockRef.get();\n                if (wakeLock != null && !wakeLock.isHeld()) {\n                    wakeLock.acquire();\n                }\n                try {\n                    List<ApplicationItem> applicationItems = new ArrayList<>();\n                    List<CharSequence> applicationLabels = new ArrayList<>();\n                    for (ApplicationItem item : PackageUtils.getInstalledOrBackedUpApplicationsFromDb(requireContext(), false, true)) {\n                        if (ThreadUtils.isInterrupted()) return;\n                        if (!item.isInstalled && item.backup != null) {\n                            applicationItems.add(item);\n                            applicationLabels.add(item.label);\n                        }\n                    }\n                    if (ThreadUtils.isInterrupted()) return;\n                    ThreadUtils.postOnMainThread(() -> runMultiChoiceDialog(applicationItems, applicationLabels));\n                } finally {\n                    CpuUtils.releaseWakeLock(wakeLock);\n                }\n            });\n        });\n        // Restore latest versions only\n        view.findViewById(R.id.restore_latest).setOnClickListener(v -> {\n            mActivity.progressIndicator.show();\n            if (mFuture != null) {\n                mFuture.cancel(true);\n            }\n            WeakReference<PowerManager.WakeLock> wakeLockRef = new WeakReference<>(mActivity.wakeLock);\n            mFuture = ThreadUtils.postOnBackgroundThread(() -> {\n                PowerManager.WakeLock wakeLock = wakeLockRef.get();\n                if (wakeLock != null && !wakeLock.isHeld()) {\n                    wakeLock.acquire();\n                }\n                try {\n                    List<ApplicationItem> applicationItems = new ArrayList<>();\n                    List<CharSequence> applicationLabels = new ArrayList<>();\n                    for (ApplicationItem item : PackageUtils.getInstalledOrBackedUpApplicationsFromDb(requireContext(), false, true)) {\n                        if (ThreadUtils.isInterrupted()) return;\n                        if (item.isInstalled && item.backup != null\n                                && item.versionCode < item.backup.versionCode) {\n                            applicationItems.add(item);\n                            applicationLabels.add(item.label);\n                        }\n                    }\n                    if (ThreadUtils.isInterrupted()) return;\n                    ThreadUtils.postOnMainThread(() -> runMultiChoiceDialog(applicationItems, applicationLabels));\n                } finally {\n                    CpuUtils.releaseWakeLock(wakeLock);\n                }\n            });\n        });\n        return new MaterialAlertDialogBuilder(requireActivity())\n                .setView(view)\n                .setTitle(R.string.restore)\n                .setNegativeButton(R.string.cancel, null)\n                .create();\n    }\n\n    @Override\n    public void onDestroy() {\n        if (mFuture != null) {\n            mFuture.cancel(true);\n        }\n        super.onDestroy();\n    }\n\n    @UiThread\n    private void runMultiChoiceDialog(List<ApplicationItem> applicationItems, List<CharSequence> applicationLabels) {\n        if (isDetached()) return;\n        mActivity.progressIndicator.hide();\n        new SearchableMultiChoiceDialogBuilder<>(mActivity, applicationItems, applicationLabels)\n                .addSelections(applicationItems)\n                .setTitle(R.string.filtered_packages)\n                .setPositiveButton(R.string.restore, (dialog, which, selectedItems) -> {\n                    if (isDetached()) return;\n                    BackupRestoreDialogFragment fragment = BackupRestoreDialogFragment.getInstance(\n                            PackageUtils.getUserPackagePairs(selectedItems), BackupRestoreDialogFragment.MODE_RESTORE);\n                    fragment.setOnActionBeginListener(mode -> mActivity.progressIndicator.show());\n                    fragment.setOnActionCompleteListener((mode, failedPackages) -> mActivity.progressIndicator.hide());\n                    if (isDetached()) return;\n                    fragment.show(getParentFragmentManager(), BackupRestoreDialogFragment.TAG);\n                })\n                .setNegativeButton(R.string.cancel, null)\n                .show();\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/permission/DevelopmentPermission.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.permission;\n\npublic class DevelopmentPermission extends Permission {\n    public DevelopmentPermission(String name, boolean granted, int appOp, boolean appOpAllowed, int flags) {\n        super(name, granted, appOp, appOpAllowed, flags);\n        runtime = false;\n        readOnly = false;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/permission/PermUtils.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.permission;\n\nimport static android.content.pm.PackageManager.PERMISSION_GRANTED;\nimport static io.github.muntashirakon.AppManager.compat.PermissionCompat.FLAG_PERMISSION_AUTO_REVOKED;\nimport static io.github.muntashirakon.AppManager.compat.PermissionCompat.FLAG_PERMISSION_ONE_TIME;\nimport static io.github.muntashirakon.AppManager.compat.PermissionCompat.FLAG_PERMISSION_REVIEW_REQUIRED;\nimport static io.github.muntashirakon.AppManager.compat.PermissionCompat.FLAG_PERMISSION_REVOKED_COMPAT;\nimport static io.github.muntashirakon.AppManager.compat.PermissionCompat.FLAG_PERMISSION_USER_FIXED;\nimport static io.github.muntashirakon.AppManager.compat.PermissionCompat.FLAG_PERMISSION_USER_SET;\n\nimport android.Manifest;\nimport android.annotation.UserIdInt;\nimport android.app.AppOpsManager;\nimport android.content.Intent;\nimport android.content.pm.ApplicationInfo;\nimport android.content.pm.PackageInfo;\nimport android.os.Build;\nimport android.os.RemoteException;\nimport android.os.UserHandleHidden;\nimport android.provider.Settings;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.RequiresPermission;\nimport androidx.annotation.WorkerThread;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport io.github.muntashirakon.AppManager.compat.ActivityManagerCompat;\nimport io.github.muntashirakon.AppManager.compat.AppOpsManagerCompat;\nimport io.github.muntashirakon.AppManager.compat.ManifestCompat;\nimport io.github.muntashirakon.AppManager.compat.PermissionCompat;\nimport io.github.muntashirakon.AppManager.logs.Log;\nimport io.github.muntashirakon.AppManager.self.SelfPermissions;\nimport io.github.muntashirakon.AppManager.utils.BroadcastUtils;\nimport io.github.muntashirakon.AppManager.utils.ContextUtils;\nimport io.github.muntashirakon.AppManager.utils.IntentUtils;\n\npublic class PermUtils {\n    private static final String KILL_REASON_APP_OP_CHANGE = \"Permission related app op changed\";\n\n    public static class SettingItem {\n        public final String action;\n        public final boolean supportPkg;\n\n        public SettingItem(String action, boolean supportPkg) {\n            this.action = action;\n            this.supportPkg = supportPkg;\n        }\n\n        public SettingItem(String action) {\n            this(action, true);\n        }\n\n        public Intent toIntent(String packageName) {\n            return IntentUtils.getSettings(action, supportPkg ? packageName : null);\n        }\n    }\n\n    public static final Map<String, SettingItem> permissionNameToSettingItem = new HashMap<String, SettingItem>() {{\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {\n            put(Manifest.permission.ACCESS_NOTIFICATION_POLICY, new SettingItem(Settings.ACTION_NOTIFICATION_POLICY_ACCESS_SETTINGS, false));\n            put(Manifest.permission.PACKAGE_USAGE_STATS, new SettingItem(Settings.ACTION_USAGE_ACCESS_SETTINGS));\n            put(Manifest.permission.SYSTEM_ALERT_WINDOW, new SettingItem(Settings.ACTION_MANAGE_OVERLAY_PERMISSION));\n            put(Manifest.permission.WRITE_SETTINGS, new SettingItem(Settings.ACTION_MANAGE_WRITE_SETTINGS));\n        }\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {\n            put(Manifest.permission.REQUEST_INSTALL_PACKAGES, new SettingItem(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES));\n        }\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {\n            put(Manifest.permission.MANAGE_EXTERNAL_STORAGE, new SettingItem(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION));\n            // put(Manifest.permission.SYSTEM_ALERT_WINDOW, new SettingItem(\"android.settings.MANAGE_APP_OVERLAY_PERMISSION\"));\n        }\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {\n            put(Manifest.permission.MANAGE_MEDIA, new SettingItem(Settings.ACTION_REQUEST_MANAGE_MEDIA));\n            put(Manifest.permission.SCHEDULE_EXACT_ALARM, new SettingItem(Settings.ACTION_REQUEST_SCHEDULE_EXACT_ALARM));\n        }\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {\n            put(Manifest.permission.POST_NOTIFICATIONS, new SettingItem(Settings.ACTION_APP_NOTIFICATION_SETTINGS)); // android.provider.extra.APP_PACKAGE\n        }\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {\n            put(Manifest.permission.RUN_USER_INITIATED_JOBS, new SettingItem(\"android.settings.MANAGE_APP_LONG_RUNNING_JOBS\"));\n            put(Manifest.permission.USE_FULL_SCREEN_INTENT, new SettingItem(Settings.ACTION_MANAGE_APP_USE_FULL_SCREEN_INTENT));\n        }\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM) {\n            put(Manifest.permission.MEDIA_ROUTING_CONTROL, new SettingItem(Settings.ACTION_REQUEST_MEDIA_ROUTING_CONTROL));\n        }\n        // Bound permissions\n        put(Manifest.permission.BIND_ACCESSIBILITY_SERVICE, new SettingItem(Settings.ACTION_ACCESSIBILITY_SETTINGS, false));\n        put(Manifest.permission.BIND_INPUT_METHOD, new SettingItem(Settings.ACTION_INPUT_METHOD_SETTINGS, false));\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {\n            put(Manifest.permission.BIND_AUTOFILL_SERVICE, new SettingItem(Settings.ACTION_REQUEST_SET_AUTOFILL_SERVICE));\n        }\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.VANILLA_ICE_CREAM) {\n            put(Manifest.permission.BIND_CREDENTIAL_PROVIDER_SERVICE, new SettingItem(Settings.ACTION_CREDENTIAL_PROVIDER));\n        }\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) {\n            put(Manifest.permission.BIND_NOTIFICATION_LISTENER_SERVICE, new SettingItem(Settings.ACTION_NOTIFICATION_LISTENER_SETTINGS, false));\n        }\n    }};\n\n    /**\n     * Grant the permission.\n     *\n     * <p>This also automatically grants app op if it has app op.\n     *\n     * @param setByTheUser   If the user has made the decision. This does not unset the flag\n     * @param fixedByTheUser If the user requested that she/he does not want to be asked again\n     */\n    @RequiresPermission(allOf = {\n            \"android.permission.MANAGE_APP_OPS_MODES\",\n            ManifestCompat.permission.GRANT_RUNTIME_PERMISSIONS,\n            ManifestCompat.permission.REVOKE_RUNTIME_PERMISSIONS,\n    })\n    @WorkerThread\n    public static void grantPermission(@NonNull PackageInfo packageInfo,\n                                       @NonNull Permission permission,\n                                       @NonNull AppOpsManagerCompat appOpsManager,\n                                       boolean setByTheUser,\n                                       boolean fixedByTheUser) throws PermissionException {\n        boolean killApp = false;\n        boolean wasGranted = permission.isGrantedIncludingAppOp();\n\n        if (!isModifiable(permission)) {\n            // Unmodifiable permission, do nothing\n            throw new PermissionException(\"Unmodifiable permission \" + permission.getName());\n        }\n\n        if (!permission.isReadOnly() && (!permission.isRuntime() || supportsRuntimePermissions(packageInfo.applicationInfo))) {\n            // Runtime/development permissions. In case of runtime, it is not a pre23 app.\n\n            // Ensure the permission app op is enabled before the permission grant.\n            if (permission.affectsAppOp() && !permission.isAppOpAllowed()) {\n                permission.setAppOpAllowed(true);\n            }\n\n            // Grant the permission if needed.\n            if (!permission.isGranted()) {\n                permission.setGranted(true);\n            }\n\n            // Update the permission flags.\n            if (!fixedByTheUser) {\n                // Now the apps can ask for the permission as the user\n                // no longer has it fixed in a denied state.\n                if (permission.isUserFixed()) {\n                    permission.setUserFixed(false);\n                }\n                if (setByTheUser) {\n                    if (!permission.isUserSet()) {\n                        permission.setUserSet(true);\n                    }\n                }\n            } else {\n                if (!permission.isUserFixed()) {\n                    permission.setUserFixed(true);\n                }\n                if (permission.isUserSet()) {\n                    permission.setUserSet(false);\n                }\n            }\n        } else { // Read-only or legacy permissions\n            // Legacy apps cannot have a not granted runtime permission but just in case.\n            if (permission.isRuntime() && !permission.isGranted()) {\n                throw new PermissionException(\"Legacy app cannot have not-granted runtime permission \" + permission.getName());\n            }\n\n            // If the permissions has no corresponding app op, then it is a\n            // third-party one, and we do not offer toggling of such permissions.\n            if (permission.affectsAppOp()) {\n                if (!permission.isAppOpAllowed()) {\n                    permission.setAppOpAllowed(true);\n\n                    // Legacy apps do not know that they have to retry access to a\n                    // resource due to changes in runtime permissions (app ops in this\n                    // case). Therefore, we restart them on app op change, so they\n                    // can pick up the change.\n                    killApp = true;\n                }\n\n                // Mark that the permission is not kept granted only for compatibility.\n                if (permission.isRevokedCompat()) {\n                    permission.setRevokedCompat(false);\n                }\n            }\n\n            // Granting a permission explicitly means the user already\n            // reviewed it so clear the review flag on every grant.\n            if (permission.isReviewRequired()) {\n                permission.unsetReviewRequired();\n            }\n        }\n\n        try {\n            persistChanges(packageInfo.applicationInfo, permission, appOpsManager, false, null);\n\n            if (killApp && SelfPermissions.canKillUid()) {\n                ActivityManagerCompat.killUid(packageInfo.applicationInfo.uid, KILL_REASON_APP_OP_CHANGE);\n            }\n        } catch (Exception e) {\n            throw new PermissionException(e);\n        }\n    }\n\n    /**\n     * Revoke the permission.\n     *\n     * <p>This also disallows the app op for the permission if it has app op.\n     *\n     * @param fixedByTheUser If the user requested that she/he does not want to be asked again\n     */\n    @RequiresPermission(allOf = {\n            \"android.permission.MANAGE_APP_OPS_MODES\",\n            ManifestCompat.permission.GRANT_RUNTIME_PERMISSIONS,\n            ManifestCompat.permission.REVOKE_RUNTIME_PERMISSIONS,\n    })\n    @WorkerThread\n    public static void revokePermission(@NonNull PackageInfo packageInfo,\n                                        @NonNull Permission permission,\n                                        @NonNull AppOpsManagerCompat appOpsManager,\n                                        boolean fixedByTheUser) throws PermissionException {\n        boolean killApp = false;\n\n        if (!isModifiable(permission)) {\n            // Unmodifiable permission, do nothing\n            throw new PermissionException(\"Unmodifiable permission \" + permission.getName());\n        }\n\n        if (!permission.isReadOnly() && (!permission.isRuntime() || supportsRuntimePermissions(packageInfo.applicationInfo))) {\n            // Runtime/development permissions. In case of runtime, it is not a pre23 app.\n\n            // Revoke the permission if needed.\n            if (permission.isGranted()) {\n                permission.setGranted(false);\n            }\n\n            // Update the permission flags.\n            if (fixedByTheUser) {\n                // Take a note that the user fixed the permission.\n                if (permission.isUserSet() || !permission.isUserFixed()) {\n                    permission.setUserSet(false);\n                    permission.setUserFixed(true);\n                }\n            } else {\n                if (!permission.isUserSet() || permission.isUserFixed()) {\n                    permission.setUserSet(true);\n                    permission.setUserFixed(false);\n                }\n            }\n\n            if (permission.affectsAppOp()) {\n                permission.setAppOpAllowed(false);\n            }\n        } else { // Read-only or legacy permissions\n            // Legacy apps cannot have a non-granted permission but just in case.\n            if (permission.isRuntime() && !permission.isGranted()) {\n                throw new PermissionException(\"Legacy app cannot have not-granted runtime permission \" + permission.getName());\n            }\n\n            // If the permission has no corresponding app op, then it is a\n            // third-party one and we do not offer toggling of such permissions.\n            if (permission.affectsAppOp()) {\n                if (permission.isAppOpAllowed()) {\n                    permission.setAppOpAllowed(false);\n\n                    // Disabling an app op may put the app in a situation in which it\n                    // has a handle to state it shouldn't have, so we have to kill the\n                    // app. This matches the revoke runtime permission behavior.\n                    killApp = true;\n                }\n\n                // Mark that the permission is kept granted only for compatibility.\n                if (!permission.isRevokedCompat()) {\n                    permission.setRevokedCompat(true);\n                }\n            }\n        }\n\n        try {\n            persistChanges(packageInfo.applicationInfo, permission, appOpsManager, false, null);\n\n            if (killApp && SelfPermissions.canKillUid()) {\n                ActivityManagerCompat.killUid(packageInfo.applicationInfo.uid, KILL_REASON_APP_OP_CHANGE);\n            }\n        } catch (Exception e) {\n            throw new PermissionException(e);\n        }\n    }\n\n    @RequiresPermission(allOf = {\n            \"android.permission.MANAGE_APP_OPS_MODES\",\n            ManifestCompat.permission.GRANT_RUNTIME_PERMISSIONS,\n            ManifestCompat.permission.REVOKE_RUNTIME_PERMISSIONS,\n    })\n    @WorkerThread\n    private static void persistChanges(@NonNull ApplicationInfo applicationInfo,\n                                       @NonNull Permission permission,\n                                       @NonNull AppOpsManagerCompat appOpsManager,\n                                       boolean mayKillBecauseOfAppOpsChange,\n                                       @Nullable String revokeReason)\n            throws PermissionException, RemoteException {\n        int uid = applicationInfo.uid;\n        int userId = UserHandleHidden.getUserId(uid);\n\n        boolean shouldKillApp = false;\n\n        if (!permission.isReadOnly()) {\n            if (permission.isGranted()) {\n                PermissionCompat.grantPermission(applicationInfo.packageName, permission.getName(), userId);\n                Log.d(\"PERM\", \"Granted %s\", permission.getName());\n            } else {\n                boolean isCurrentlyGranted = PermissionCompat.checkPermission(permission.getName(),\n                        applicationInfo.packageName, userId) == PERMISSION_GRANTED;\n\n                if (isCurrentlyGranted) {\n                    if (revokeReason == null) {\n                        PermissionCompat.revokePermission(applicationInfo.packageName, permission.getName(), userId);\n                    } else {\n                        PermissionCompat.revokePermission(applicationInfo.packageName, permission.getName(), userId, revokeReason);\n                    }\n                    Log.d(\"PERM\", \"Revoked %s\", permission.getName());\n                }\n            }\n        }\n\n        if (!permission.readOnly) {\n            // Flags of the system fixed permissions may also be updated\n            updateFlags(applicationInfo, permission, userId);\n        }\n\n        if (permission.affectsAppOp()) {\n            if (!permission.isSystemFixed()) {\n                // FIXME: 7/2/22 Disable system fixed check?\n                // Enabling/Disabling an app op may put the app in a situation in which it has\n                // a handle to state it shouldn't have, so we have to kill the app. This matches\n                // the revoke runtime permission behavior.\n                if (permission.isAppOpAllowed()) {\n                    boolean wasChanged = allowAppOp(appOpsManager, permission.getAppOp(), applicationInfo.packageName, uid);\n                    shouldKillApp = wasChanged && !supportsRuntimePermissions(applicationInfo);\n                } else {\n                    shouldKillApp = disallowAppOp(appOpsManager, permission.getAppOp(), applicationInfo.packageName, uid);\n                }\n            }\n        }\n\n        if (mayKillBecauseOfAppOpsChange && shouldKillApp && SelfPermissions.canKillUid()) {\n            ActivityManagerCompat.killUid(uid, KILL_REASON_APP_OP_CHANGE);\n        }\n        if (userId != UserHandleHidden.myUserId()) {\n            BroadcastUtils.sendPackageAltered(ContextUtils.getContext(), new String[]{applicationInfo.packageName});\n        }\n    }\n\n    @RequiresPermission(anyOf = {\n            ManifestCompat.permission.GET_RUNTIME_PERMISSIONS,\n            ManifestCompat.permission.GRANT_RUNTIME_PERMISSIONS,\n            ManifestCompat.permission.REVOKE_RUNTIME_PERMISSIONS,\n    })\n    private static void updateFlags(@NonNull ApplicationInfo applicationInfo, @NonNull Permission permission,\n                                    @UserIdInt int userId) throws RemoteException {\n        int flags = (permission.isUserSet() ? FLAG_PERMISSION_USER_SET : 0)\n                | (permission.isUserFixed() ? FLAG_PERMISSION_USER_FIXED : 0)\n                | (permission.isRevokedCompat()\n                ? FLAG_PERMISSION_REVOKED_COMPAT : 0)\n                // | (permission.isPolicyFixed() ? FLAG_PERMISSION_POLICY_FIXED : 0) // TODO: Disabled in AOSP\n                | (permission.isReviewRequired()\n                ? FLAG_PERMISSION_REVIEW_REQUIRED : 0);\n\n        boolean checkAdjustPolicy = PermissionCompat.getCheckAdjustPolicyFlagPermission(applicationInfo);\n\n        PermissionCompat.updatePermissionFlags(permission.getName(),\n                applicationInfo.packageName,\n                FLAG_PERMISSION_USER_SET\n                        | FLAG_PERMISSION_USER_FIXED\n                        | FLAG_PERMISSION_REVOKED_COMPAT\n                        // | FLAG_PERMISSION_POLICY_FIXED // TODO: Disabled in AOSP\n                        | (permission.isReviewRequired()\n                        ? 0 : FLAG_PERMISSION_REVIEW_REQUIRED)\n                        | FLAG_PERMISSION_ONE_TIME\n                        | FLAG_PERMISSION_AUTO_REVOKED, // clear auto revoke\n                flags, checkAdjustPolicy, userId);\n    }\n\n    /**\n     * @return {@code true} iff app-op was changed\n     */\n    @RequiresPermission(\"android.permission.MANAGE_APP_OPS_MODES\")\n    public static boolean allowAppOp(AppOpsManagerCompat appOpsManager, int appOp, String packageName, int uid)\n            throws PermissionException {\n        return setAppOpMode(appOpsManager, appOp, packageName, uid, AppOpsManager.MODE_ALLOWED);\n    }\n\n    /**\n     * @return {@code true} iff app-op was changed\n     */\n    @RequiresPermission(\"android.permission.MANAGE_APP_OPS_MODES\")\n    public static boolean disallowAppOp(AppOpsManagerCompat appOpsManager, int appOp, String packageName, int uid)\n            throws PermissionException {\n        return setAppOpMode(appOpsManager, appOp, packageName, uid, AppOpsManager.MODE_IGNORED);\n    }\n\n    /**\n     * Set mode of an app-op if needed.\n     *\n     * @return {@code true} iff app-op was changed\n     */\n    @RequiresPermission(\"android.permission.MANAGE_APP_OPS_MODES\")\n    public static boolean setAppOpMode(@NonNull AppOpsManagerCompat appOpsManager,\n                                       int appOp,\n                                       String packageName,\n                                       int uid,\n                                       @AppOpsManagerCompat.Mode int mode) throws PermissionException {\n        try {\n            int currentMode = appOpsManager.checkOperation(appOp, uid, packageName);\n            if (currentMode == mode) {\n                return false;\n            }\n            appOpsManager.setMode(appOp, uid, packageName, mode);\n            return true;\n        } catch (Exception e) {\n            throw new PermissionException(e);\n        }\n    }\n\n    private static boolean supportsRuntimePermissions(@NonNull ApplicationInfo applicationInfo) {\n        return applicationInfo.targetSdkVersion > Build.VERSION_CODES.LOLLIPOP_MR1;\n    }\n\n    public static boolean systemSupportsRuntimePermissions() {\n        return Build.VERSION.SDK_INT > Build.VERSION_CODES.LOLLIPOP_MR1;\n    }\n\n    public static boolean isModifiable(@NonNull Permission permission) {\n        // Non-readonly permissions or permissions with app ops are modifiable\n        return SelfPermissions.canModifyPermissions() && (!permission.isReadOnly() || permission.affectsAppOp());\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/permission/Permission.java",
    "content": "// SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.permission;\n\nimport static io.github.muntashirakon.AppManager.compat.PermissionCompat.FLAG_PERMISSION_GRANTED_BY_DEFAULT;\nimport static io.github.muntashirakon.AppManager.compat.PermissionCompat.FLAG_PERMISSION_POLICY_FIXED;\nimport static io.github.muntashirakon.AppManager.compat.PermissionCompat.FLAG_PERMISSION_REVIEW_REQUIRED;\nimport static io.github.muntashirakon.AppManager.compat.PermissionCompat.FLAG_PERMISSION_REVOKED_COMPAT;\nimport static io.github.muntashirakon.AppManager.compat.PermissionCompat.FLAG_PERMISSION_REVOKE_ON_UPGRADE;\nimport static io.github.muntashirakon.AppManager.compat.PermissionCompat.FLAG_PERMISSION_SYSTEM_FIXED;\nimport static io.github.muntashirakon.AppManager.compat.PermissionCompat.FLAG_PERMISSION_USER_FIXED;\nimport static io.github.muntashirakon.AppManager.compat.PermissionCompat.FLAG_PERMISSION_USER_SET;\n\nimport android.os.Build;\n\nimport io.github.muntashirakon.AppManager.compat.AppOpsManagerCompat;\nimport io.github.muntashirakon.AppManager.compat.PermissionCompat;\n\n// Copyright (C) 2015 The Android Open Source Project\npublic class Permission {\n    boolean runtime;\n    boolean readOnly;\n\n    private final String mName;\n    private final int mAppOp;\n\n    private boolean mGranted;\n    private boolean mAppOpAllowed;\n    @PermissionCompat.PermissionFlags\n    private int mFlags;\n\n    public Permission(String name, boolean granted, int appOp, boolean appOpAllowed,\n                      @PermissionCompat.PermissionFlags int flags) {\n        mName = name;\n        mGranted = granted;\n        mAppOp = appOp;\n        mAppOpAllowed = appOpAllowed;\n        mFlags = flags;\n        runtime = true;\n        readOnly = false;\n    }\n\n    public boolean isRuntime() {\n        return runtime;\n    }\n\n    public boolean isReadOnly() {\n        return readOnly || isSystemFixed();\n    }\n\n    public String getName() {\n        return mName;\n    }\n\n    public int getAppOp() {\n        return mAppOp;\n    }\n\n    @PermissionCompat.PermissionFlags\n    public int getFlags() {\n        return mFlags;\n    }\n\n    public boolean hasAppOp() {\n        return mAppOp != AppOpsManagerCompat.OP_NONE;\n    }\n\n    /**\n     * Does this permission affect app ops.\n     *\n     * <p>I.e. does this permission have a matching app op or is this a background permission. All\n     * background permissions affect the app op if it's assigned foreground permission.\n     *\n     * @return {@code true} if this permission affects app ops\n     */\n    public boolean affectsAppOp() {\n        return mAppOp != AppOpsManagerCompat.OP_NONE;\n    }\n\n    public boolean isGranted() {\n        return mGranted;\n    }\n\n    public boolean isGrantedIncludingAppOp() {\n        return mGranted && !isReviewRequired() && (!affectsAppOp() || isAppOpAllowed());\n    }\n\n    public boolean isReviewRequired() {\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {\n            return (mFlags & FLAG_PERMISSION_REVIEW_REQUIRED) != 0;\n        } else return false;\n    }\n\n    public void resetReviewRequired() {\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {\n            mFlags &= ~FLAG_PERMISSION_REVIEW_REQUIRED;\n        }\n    }\n\n    public void unsetReviewRequired() {\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {\n            mFlags &= ~FLAG_PERMISSION_REVIEW_REQUIRED;\n        }\n    }\n\n    public void setGranted(boolean mGranted) {\n        this.mGranted = mGranted;\n    }\n\n    public boolean isAppOpAllowed() {\n        return mAppOpAllowed;\n    }\n\n    public boolean isUserFixed() {\n        return (mFlags & FLAG_PERMISSION_USER_FIXED) != 0;\n    }\n\n    public void setUserFixed(boolean userFixed) {\n        if (userFixed) {\n            mFlags |= FLAG_PERMISSION_USER_FIXED;\n        } else {\n            mFlags &= ~FLAG_PERMISSION_USER_FIXED;\n        }\n    }\n\n    public boolean isSystemFixed() {\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {\n            return (mFlags & FLAG_PERMISSION_SYSTEM_FIXED) != 0;\n        }\n        return false;\n    }\n\n    public boolean isPolicyFixed() {\n        return (mFlags & FLAG_PERMISSION_POLICY_FIXED) != 0;\n    }\n\n    public boolean isUserSet() {\n        return (mFlags & FLAG_PERMISSION_USER_SET) != 0;\n    }\n\n    public boolean isGrantedByDefault() {\n        return (mFlags & FLAG_PERMISSION_GRANTED_BY_DEFAULT) != 0;\n    }\n\n    public void setUserSet(boolean userSet) {\n        if (userSet) {\n            mFlags |= FLAG_PERMISSION_USER_SET;\n        } else {\n            mFlags &= ~FLAG_PERMISSION_USER_SET;\n        }\n    }\n\n    public void setPolicyFixed(boolean policyFixed) {\n        if (policyFixed) {\n            mFlags |= FLAG_PERMISSION_POLICY_FIXED;\n        } else {\n            mFlags &= ~FLAG_PERMISSION_POLICY_FIXED;\n        }\n    }\n\n    public boolean shouldRevokeOnUpgrade() {\n        return (mFlags & FLAG_PERMISSION_REVOKE_ON_UPGRADE) != 0;\n    }\n\n    public void setRevokeOnUpgrade(boolean revokeOnUpgrade) {\n        if (revokeOnUpgrade) {\n            mFlags |= FLAG_PERMISSION_REVOKE_ON_UPGRADE;\n        } else {\n            mFlags &= ~FLAG_PERMISSION_REVOKE_ON_UPGRADE;\n        }\n    }\n\n    public boolean isRevokedCompat() {\n        return (mFlags & FLAG_PERMISSION_REVOKED_COMPAT) != 0;\n    }\n\n    public void setRevokedCompat(boolean revokedCompat) {\n        if (revokedCompat) {\n            mFlags |= FLAG_PERMISSION_REVOKED_COMPAT;\n        } else {\n            mFlags &= ~FLAG_PERMISSION_REVOKED_COMPAT;\n        }\n    }\n\n    public void setAppOpAllowed(boolean mAppOpAllowed) {\n        this.mAppOpAllowed = mAppOpAllowed;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/permission/PermissionException.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.permission;\n\nimport android.util.AndroidException;\n\npublic class PermissionException extends AndroidException {\n    public PermissionException(String name) {\n        super(name);\n    }\n\n    public PermissionException(String name, Throwable cause) {\n        super(name, cause);\n    }\n\n    public PermissionException(Exception cause) {\n        super(cause);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/permission/ReadOnlyPermission.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.permission;\n\npublic class ReadOnlyPermission extends Permission {\n    public ReadOnlyPermission(String name, boolean granted, int appOp, boolean appOpAllowed, int flags) {\n        super(name, granted, appOp, appOpAllowed, flags);\n        runtime = false;\n        readOnly = true;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/permission/RuntimePermission.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.permission;\n\npublic class RuntimePermission extends Permission {\n    public RuntimePermission(String name, boolean granted, int appOp, boolean appOpAllowed, int flags) {\n        super(name, granted, appOp, appOpAllowed, flags);\n        runtime = true;\n        readOnly = false;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/profiles/AddToProfileDialogFragment.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.profiles;\n\nimport static io.github.muntashirakon.AppManager.utils.UIUtils.getSecondaryText;\nimport static io.github.muntashirakon.AppManager.utils.UIUtils.getSmallerText;\n\nimport android.app.Dialog;\nimport android.os.Bundle;\nimport android.text.SpannableStringBuilder;\nimport android.text.TextUtils;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.appcompat.app.AlertDialog;\nimport androidx.fragment.app.DialogFragment;\n\nimport java.io.OutputStream;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.concurrent.atomic.AtomicReference;\n\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.profiles.struct.AppsProfile;\nimport io.github.muntashirakon.AppManager.utils.ExUtils;\nimport io.github.muntashirakon.AppManager.utils.ThreadUtils;\nimport io.github.muntashirakon.AppManager.utils.UIUtils;\nimport io.github.muntashirakon.dialog.DialogTitleBuilder;\nimport io.github.muntashirakon.dialog.SearchableMultiChoiceDialogBuilder;\nimport io.github.muntashirakon.dialog.TextInputDialogBuilder;\nimport io.github.muntashirakon.io.Path;\n\npublic class AddToProfileDialogFragment extends DialogFragment {\n    public static final String TAG = AddToProfileDialogFragment.class.getSimpleName();\n\n    private static final String ARG_PKGS = \"pkgs\";\n\n    public static AddToProfileDialogFragment getInstance(@NonNull String[] packages) {\n        AddToProfileDialogFragment fragment = new AddToProfileDialogFragment();\n        Bundle args = new Bundle();\n        args.putStringArray(ARG_PKGS, packages);\n        fragment.setArguments(args);\n        return fragment;\n    }\n\n    @NonNull\n    @Override\n    public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {\n        String[] packages = requireArguments().getStringArray(ARG_PKGS);\n        // TODO: 16/9/23 Migrate to bottom sheet dialog and use loader before retrieving the profiles\n        List<AppsProfile> profiles = ExUtils.requireNonNullElse(() -> ProfileManager.getProfiles(AppsProfile.PROFILE_TYPE_APPS), Collections.emptyList());\n        List<CharSequence> profileNames = new ArrayList<>(profiles.size());\n        for (AppsProfile profile : profiles) {\n            profileNames.add(new SpannableStringBuilder(profile.name).append(\"\\n\")\n                    .append(getSecondaryText(requireContext(), getSmallerText(\n                            profile.toLocalizedString(requireContext())))));\n        }\n        AtomicReference<AlertDialog> dialogRef = new AtomicReference<>();\n        DialogTitleBuilder titleBuilder = new DialogTitleBuilder(requireContext())\n                .setTitle(R.string.add_to_profile)\n                .setEndIconContentDescription(R.string.new_profile)\n                .setEndIcon(R.drawable.ic_add, v -> new TextInputDialogBuilder(requireContext(), R.string.input_profile_name)\n                        .setTitle(R.string.new_profile)\n                        .setHelperText(R.string.input_profile_name_description)\n                        .setNegativeButton(R.string.cancel, null)\n                        .setPositiveButton(R.string.go, (dialog, which, profName, isChecked) -> {\n                            if (!TextUtils.isEmpty(profName)) {\n                                startActivity(AppsProfileActivity.getNewProfileIntent(requireContext(),\n                                        profName.toString(), packages));\n                                if (dialogRef.get() != null) {\n                                    dialogRef.get().dismiss();\n                                }\n                            }\n                        })\n                        .show());\n        AlertDialog alertDialog = new SearchableMultiChoiceDialogBuilder<>(requireContext(), profiles, profileNames)\n                .setTitle(titleBuilder.build())\n                .setNegativeButton(R.string.cancel, null)\n                .setPositiveButton(R.string.add, (dialog, which, selectedItems) -> ThreadUtils.postOnBackgroundThread(() -> {\n                    boolean isSuccess = true;\n                    for (AppsProfile profile : selectedItems) {\n                        Path profilePath = ProfileManager.findProfilePathById(profile.profileId);\n                        if (profilePath == null) {\n                            isSuccess = false;\n                            continue;\n                        }\n                        try (OutputStream os = profilePath.openOutputStream()) {\n                            profile.appendPackages(packages);\n                            profile.write(os);\n                        } catch (Throwable e) {\n                            isSuccess = false;\n                            e.printStackTrace();\n                        }\n                    }\n                    if (isSuccess) {\n                        ThreadUtils.postOnMainThread(() -> UIUtils.displayShortToast(R.string.done));\n                    } else {\n                        ThreadUtils.postOnMainThread(() -> UIUtils.displayShortToast(R.string.failed));\n                    }\n                }))\n                .create();\n        dialogRef.set(alertDialog);\n        return alertDialog;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/profiles/AppsBaseProfileActivity.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.profiles;\n\nimport static io.github.muntashirakon.AppManager.profiles.ProfileApplierActivity.ST_ADVANCED;\nimport static io.github.muntashirakon.AppManager.profiles.ProfileApplierActivity.ST_SIMPLE;\n\nimport android.content.Intent;\nimport android.graphics.drawable.Drawable;\nimport android.os.Bundle;\nimport android.text.TextUtils;\nimport android.view.Menu;\nimport android.view.MenuItem;\nimport android.view.View;\n\nimport androidx.activity.OnBackPressedCallback;\nimport androidx.annotation.CallSuper;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.core.content.ContextCompat;\nimport androidx.fragment.app.Fragment;\nimport androidx.fragment.app.FragmentActivity;\nimport androidx.lifecycle.ViewModelProvider;\nimport androidx.viewpager2.adapter.FragmentStateAdapter;\nimport androidx.viewpager2.widget.ViewPager2;\n\nimport com.google.android.material.dialog.MaterialAlertDialogBuilder;\nimport com.google.android.material.floatingactionbutton.FloatingActionButton;\nimport com.google.android.material.navigation.NavigationBarView;\nimport com.google.android.material.progressindicator.LinearProgressIndicator;\n\nimport java.util.Objects;\n\nimport io.github.muntashirakon.AppManager.BaseActivity;\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.shortcut.CreateShortcutDialogFragment;\nimport io.github.muntashirakon.AppManager.utils.UIUtils;\nimport io.github.muntashirakon.dialog.SearchableSingleChoiceDialogBuilder;\nimport io.github.muntashirakon.dialog.TextInputDialogBuilder;\nimport io.github.muntashirakon.util.UiUtils;\n\npublic abstract class AppsBaseProfileActivity extends BaseActivity implements NavigationBarView.OnItemSelectedListener {\n    protected static final String EXTRA_NEW_PROFILE_NAME = \"new_prof\";\n    protected static final String EXTRA_PROFILE_ID = \"prof\";\n    protected static final String EXTRA_STATE = \"state\";\n\n    private ViewPager2 mViewPager;\n    NavigationBarView bottomNavigationView;\n    private MenuItem mPrevMenuItem;\n    private final Fragment[] mFragments = new Fragment[3];\n    private final ViewPager2.OnPageChangeCallback mPageChangeCallback = new ViewPager2.OnPageChangeCallback() {\n        @Override\n        public void onPageSelected(int position) {\n            if (mPrevMenuItem != null) {\n                mPrevMenuItem.setChecked(false);\n            } else {\n                bottomNavigationView.getMenu().getItem(0).setChecked(false);\n            }\n            bottomNavigationView.getMenu().getItem(position).setChecked(true);\n            mPrevMenuItem = bottomNavigationView.getMenu().getItem(position);\n        }\n    };\n    private final OnBackPressedCallback mOnBackPressedCallback = new OnBackPressedCallback(false) {\n        @Override\n        public void handleOnBackPressed() {\n            if (model != null && model.isModified()) {\n                new MaterialAlertDialogBuilder(AppsBaseProfileActivity.this)\n                        .setTitle(R.string.exit_confirmation)\n                        .setMessage(R.string.profile_modified_are_you_sure)\n                        .setPositiveButton(R.string.no, null)\n                        .setNegativeButton(R.string.yes, (dialog, which) -> {\n                            setEnabled(false);\n                            getOnBackPressedDispatcher().onBackPressed();\n                        })\n                        .setNeutralButton(R.string.save_and_exit, (dialog, which) -> {\n                            model.save(true);\n                            setEnabled(false);\n                        })\n                        .show();\n                return;\n            }\n            setEnabled(false);\n            getOnBackPressedDispatcher().onBackPressed();\n        }\n    };\n    @Nullable\n    protected String profileId;\n    AppsProfileViewModel model;\n    FloatingActionButton fab;\n    LinearProgressIndicator progressIndicator;\n\n    public abstract Fragment getAppsBaseFragment();\n\n    public abstract void loadNewProfile(@NonNull String newProfileName, @NonNull Intent intent);\n\n    @CallSuper\n    @Override\n    protected void onAuthenticated(@Nullable Bundle savedInstanceState) {\n        model = new ViewModelProvider(this).get(AppsProfileViewModel.class);\n        setContentView(R.layout.activity_apps_profile);\n        setSupportActionBar(findViewById(R.id.toolbar));\n        getOnBackPressedDispatcher().addCallback(this, mOnBackPressedCallback);\n        progressIndicator = findViewById(R.id.progress_linear);\n        progressIndicator.setVisibilityAfterHide(View.GONE);\n        fab = findViewById(R.id.floatingActionButton);\n        UiUtils.applyWindowInsetsAsMargin(fab);\n        if (getIntent() == null) {\n            finish();\n            return;\n        }\n        @Nullable String newProfileName = getIntent().getStringExtra(EXTRA_NEW_PROFILE_NAME);\n        profileId = getIntent().getStringExtra(EXTRA_PROFILE_ID);\n        if (profileId == null && newProfileName == null) {\n            // Neither profile name/id is set\n            finish();\n            return;\n        }\n        // Load/clone profile\n        if (newProfileName != null) {\n            // New profile requested\n            if (profileId != null) {\n                // Clone profile\n                model.loadAndCloneProfile(profileId, newProfileName);\n            } else {\n                // New profile\n                loadNewProfile(newProfileName, getIntent());\n            }\n        } else {\n            model.loadProfile(profileId);\n        }\n        mViewPager = findViewById(R.id.pager);\n        mViewPager.setOffscreenPageLimit(2);\n        mViewPager.registerOnPageChangeCallback(mPageChangeCallback);\n        mViewPager.setAdapter(new ProfileFragmentPagerAdapter(this));\n        bottomNavigationView = findViewById(R.id.bottom_navigation);\n        bottomNavigationView.setOnItemSelectedListener(this);\n        // Observers\n        model.getProfileModifiedLiveData().observe(this, modified -> {\n            mOnBackPressedCallback.setEnabled(modified);\n            if (getSupportActionBar() != null) {\n                String name = (modified ? \"* \" : \"\") + model.getProfileName();\n                getSupportActionBar().setTitle(name);\n            }\n        });\n        model.observeToast().observe(this, stringResAndIsFinish -> {\n            UIUtils.displayShortToast(stringResAndIsFinish.first);\n            if (stringResAndIsFinish.second) {\n                getOnBackPressedDispatcher().onBackPressed();\n            }\n        });\n        model.observeProfileLoaded().observe(this, profileName -> {\n            setTitle(profileName);\n            progressIndicator.hide();\n        });\n    }\n\n    @Override\n    public boolean onCreateOptionsMenu(Menu menu) {\n        getMenuInflater().inflate(R.menu.fragment_profile_apps_actions, menu);\n        return super.onCreateOptionsMenu(menu);\n    }\n\n    @Override\n    public boolean onOptionsItemSelected(@NonNull MenuItem item) {\n        int id = item.getItemId();\n        if (id == android.R.id.home) {\n            getOnBackPressedDispatcher().onBackPressed();\n        } else if (id == R.id.action_apply) {\n            Intent intent = ProfileApplierActivity.getApplierIntent(this, model.getProfileName());\n            startActivity(intent);\n        } else if (id == R.id.action_save) {\n            model.save(false);\n        } else if (id == R.id.action_discard) {\n            model.discard();\n        } else if (id == R.id.action_delete) {\n            new MaterialAlertDialogBuilder(this)\n                    .setTitle(getString(R.string.delete_filename, model.getProfileName()))\n                    .setMessage(R.string.are_you_sure)\n                    .setPositiveButton(R.string.cancel, null)\n                    .setNegativeButton(R.string.ok, (dialog, which) -> model.delete())\n                    .show();\n        } else if (id == R.id.action_duplicate) {\n            new TextInputDialogBuilder(this, R.string.input_profile_name)\n                    .setTitle(R.string.new_profile)\n                    .setHelperText(R.string.input_profile_name_description)\n                    .setNegativeButton(R.string.cancel, null)\n                    .setPositiveButton(R.string.go, (dialog, which, profName, isChecked) -> {\n                        if (TextUtils.isEmpty(profName)) {\n                            UIUtils.displayShortToast(R.string.failed_to_duplicate_profile);\n                            return;\n                        }\n                        progressIndicator.show();\n                        model.cloneProfile(profName.toString());\n                    })\n                    .show();\n        } else if (id == R.id.action_shortcut) {\n            final String[] shortcutTypesL = new String[]{\n                    getString(R.string.simple),\n                    getString(R.string.advanced)\n            };\n            final String[] shortcutTypes = new String[]{ST_SIMPLE, ST_ADVANCED};\n            new SearchableSingleChoiceDialogBuilder<>(this, shortcutTypes, shortcutTypesL)\n                    .setTitle(R.string.create_shortcut)\n                    .setOnSingleChoiceClickListener((dialog, which, item1, isChecked) -> {\n                        if (!isChecked) {\n                            return;\n                        }\n                        Drawable icon = Objects.requireNonNull(ContextCompat.getDrawable(this, R.drawable.ic_launcher_foreground));\n                        ProfileShortcutInfo shortcutInfo = new ProfileShortcutInfo(model.getProfileId(),\n                                model.getProfileName(), shortcutTypes[which], shortcutTypesL[which]);\n                        shortcutInfo.setIcon(UIUtils.getBitmapFromDrawable(icon));\n                        CreateShortcutDialogFragment dialog1 = CreateShortcutDialogFragment.getInstance(shortcutInfo);\n                        dialog1.show(getSupportFragmentManager(), CreateShortcutDialogFragment.TAG);\n                        dialog.dismiss();\n                    })\n                    .show();\n        } else return super.onOptionsItemSelected(item);\n        return true;\n    }\n\n    @Override\n    protected void onDestroy() {\n        if (mViewPager != null) {\n            mViewPager.unregisterOnPageChangeCallback(mPageChangeCallback);\n        }\n        super.onDestroy();\n    }\n\n    @Override\n    public boolean onNavigationItemSelected(@NonNull MenuItem item) {\n        int itemId = item.getItemId();\n        if (itemId == R.id.action_apps) {\n            mViewPager.setCurrentItem(0, true);\n        } else if (itemId == R.id.action_preview) {\n            mViewPager.setCurrentItem(0, true);\n        } else if (itemId == R.id.action_conf) {\n            mViewPager.setCurrentItem(1, true);\n        } else if (itemId == R.id.action_logs) {\n            mViewPager.setCurrentItem(2, true);\n        } else return false;\n        return true;\n    }\n\n    // For tab layout\n    private class ProfileFragmentPagerAdapter extends FragmentStateAdapter {\n        ProfileFragmentPagerAdapter(@NonNull FragmentActivity fragmentActivity) {\n            super(fragmentActivity);\n        }\n\n        @NonNull\n        @Override\n        public Fragment createFragment(int position) {\n            Fragment fragment = mFragments[position];\n            if (fragment == null) {\n                switch (position) {\n                    case 0:\n                        return mFragments[position] = getAppsBaseFragment();\n                    case 1:\n                        return mFragments[position] = new ConfFragment();\n                    case 2:\n                        return mFragments[position] = new LogViewerFragment();\n                }\n            }\n            return Objects.requireNonNull(fragment);\n        }\n\n        @Override\n        public int getItemCount() {\n            return mFragments.length;\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/profiles/AppsFilterProfileActivity.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.profiles;\n\nimport android.content.Context;\nimport android.content.Intent;\nimport android.os.Bundle;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.fragment.app.Fragment;\n\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.filters.EditFiltersDialogFragment;\nimport io.github.muntashirakon.AppManager.filters.FilterItem;\n\npublic class AppsFilterProfileActivity extends AppsBaseProfileActivity implements EditFiltersDialogFragment.OnSaveDialogButtonInterface {\n    @NonNull\n    public static Intent getProfileIntent(@NonNull Context context, @NonNull String profileId) {\n        Intent intent = new Intent(context, AppsFilterProfileActivity.class);\n        intent.putExtra(EXTRA_PROFILE_ID, profileId);\n        return intent;\n    }\n\n    @NonNull\n    public static Intent getNewProfileIntent(@NonNull Context context, @NonNull String profileName) {\n        Intent intent = new Intent(context, AppsFilterProfileActivity.class);\n        intent.putExtra(EXTRA_NEW_PROFILE_NAME, profileName);\n        return intent;\n    }\n\n    @NonNull\n    public static Intent getCloneProfileIntent(@NonNull Context context, @NonNull String oldProfileId,\n                                               @NonNull String newProfileName) {\n        Intent intent = new Intent(context, AppsFilterProfileActivity.class);\n        intent.putExtra(EXTRA_PROFILE_ID, oldProfileId);\n        intent.putExtra(EXTRA_NEW_PROFILE_NAME, newProfileName);\n        return intent;\n    }\n\n\n    @Override\n    public Fragment getAppsBaseFragment() {\n        return new AppsFragment();\n    }\n\n    @Override\n    public void loadNewProfile(@NonNull String newProfileName, @NonNull Intent intent) {\n        model.loadNewAppsFilterProfile(newProfileName);\n    }\n\n    @Override\n    protected void onAuthenticated(@Nullable Bundle savedInstanceState) {\n        super.onAuthenticated(savedInstanceState);\n        bottomNavigationView.getMenu().removeItem(R.id.action_apps);\n        fab.setImageResource(R.drawable.ic_filter_menu);\n        fab.setContentDescription(getString(R.string.filters));\n        fab.setOnClickListener(v -> {\n            EditFiltersDialogFragment dialog = new EditFiltersDialogFragment();\n            dialog.setOnSaveDialogButtonInterface(this);\n            dialog.show(getSupportFragmentManager(), EditFiltersDialogFragment.TAG);\n        });\n    }\n\n    @NonNull\n    @Override\n    public FilterItem getFilterItem() {\n        return model.getFilterItem();\n    }\n\n    @Override\n    public void onItemAltered(@NonNull FilterItem item) {\n        model.setModified(true);\n        model.loadPackages();\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/profiles/AppsFragment.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.profiles;\n\nimport android.content.pm.ApplicationInfo;\nimport android.content.pm.PackageManager;\nimport android.os.Bundle;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.ImageView;\nimport android.widget.TextView;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.appcompat.widget.PopupMenu;\nimport androidx.fragment.app.Fragment;\n\nimport com.google.android.material.progressindicator.LinearProgressIndicator;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Objects;\n\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.filters.IFilterableAppInfo;\nimport io.github.muntashirakon.AppManager.self.imagecache.ImageLoader;\nimport io.github.muntashirakon.AppManager.utils.UIUtils;\nimport io.github.muntashirakon.util.AdapterUtils;\nimport io.github.muntashirakon.widget.RecyclerView;\nimport io.github.muntashirakon.widget.SwipeRefreshLayout;\n\npublic class AppsFragment extends Fragment implements SwipeRefreshLayout.OnRefreshListener {\n    public static class AppsFragmentItem {\n        @NonNull\n        public final String packageName;\n        @Nullable\n        public CharSequence label;\n        public ApplicationInfo applicationInfo;\n        public IFilterableAppInfo filterableAppInfo;\n\n        public AppsFragmentItem(@NonNull String packageName) {\n            this.packageName = packageName;\n        }\n\n        @Override\n        public boolean equals(Object o) {\n            if (this == o) return true;\n            if (o instanceof String) {\n                return Objects.equals(packageName, o);\n            }\n            if (!(o instanceof AppsFragmentItem)) return false;\n            AppsFragmentItem that = (AppsFragmentItem) o;\n            return Objects.equals(packageName, that.packageName);\n        }\n\n        @Override\n        public int hashCode() {\n            return Objects.hash(packageName);\n        }\n    }\n\n    private AppsBaseProfileActivity mActivity;\n    private SwipeRefreshLayout mSwipeRefresh;\n    private LinearProgressIndicator mProgressIndicator;\n    private AppsProfileViewModel mModel;\n\n    @Override\n    public void onCreate(@Nullable Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        mActivity = (AppsBaseProfileActivity) requireActivity();\n    }\n\n    @Nullable\n    @Override\n    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {\n        return inflater.inflate(R.layout.pager_app_details, container, false);\n    }\n\n    @Override\n    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {\n        super.onViewCreated(view, savedInstanceState);\n        // Swipe refresh\n        mSwipeRefresh = view.findViewById(R.id.swipe_refresh);\n        mSwipeRefresh.setOnRefreshListener(this);\n        RecyclerView recyclerView = view.findViewById(R.id.scrollView);\n        recyclerView.setLayoutManager(UIUtils.getGridLayoutAt450Dp(mActivity));\n        final TextView emptyView = view.findViewById(android.R.id.empty);\n        emptyView.setText(R.string.no_apps);\n        recyclerView.setEmptyView(emptyView);\n        mProgressIndicator = view.findViewById(R.id.progress_linear);\n        mProgressIndicator.setVisibilityAfterHide(View.GONE);\n        mProgressIndicator.show();\n        view.findViewById(R.id.alert_text).setVisibility(View.GONE);\n        mSwipeRefresh.setOnChildScrollUpCallback((parent, child) -> recyclerView.canScrollVertically(-1));\n        mModel = mActivity.model;\n        AppsRecyclerAdapter adapter = new AppsRecyclerAdapter();\n        recyclerView.setAdapter(adapter);\n        mModel.getPackages().observe(getViewLifecycleOwner(), packages -> {\n            mProgressIndicator.hide();\n            adapter.setList(packages);\n        });\n    }\n\n    @Override\n    public void onResume() {\n        super.onResume();\n        if (mActivity.getSupportActionBar() != null) {\n            mActivity.getSupportActionBar().setSubtitle(mModel.getPreviewTitleString());\n        }\n        mActivity.fab.show();\n    }\n\n    @Override\n    public void onRefresh() {\n        mSwipeRefresh.setRefreshing(false);\n        mModel.loadPackages();\n    }\n\n    public class AppsRecyclerAdapter extends RecyclerView.Adapter<AppsRecyclerAdapter.ViewHolder> {\n        final PackageManager pm;\n        final ArrayList<AppsFragmentItem> packages = new ArrayList<>();\n        final ImageLoader.DefaultImageDrawable defaultImage;\n\n        private AppsRecyclerAdapter() {\n            pm = mActivity.getPackageManager();\n            defaultImage = new ImageLoader.DefaultImageDrawable(\"android_default_icon\", pm.getDefaultActivityIcon());\n        }\n\n        void setList(List<AppsFragmentItem> list) {\n            AdapterUtils.notifyDataSetChanged(this, packages, list);\n        }\n\n        @NonNull\n        @Override\n        public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {\n            View view = LayoutInflater.from(parent.getContext()).inflate(io.github.muntashirakon.ui.R.layout.m3_preference, parent, false);\n            return new ViewHolder(view);\n        }\n\n        @Override\n        public void onBindViewHolder(@NonNull ViewHolder holder, int position) {\n            AppsFragmentItem fragmentItem = packages.get(position);\n            holder.icon.setTag(fragmentItem);\n            if (fragmentItem.applicationInfo != null) {\n                ImageLoader.getInstance().displayImage(fragmentItem.packageName, fragmentItem.applicationInfo, holder.icon);\n            } else {\n                ImageLoader.getInstance().displayImage(fragmentItem.packageName, holder.icon, tag ->\n                        new ImageLoader.ImageFetcherResult(tag, UIUtils.getBitmapFromDrawable(fragmentItem.filterableAppInfo.getAppIcon()), true, true, defaultImage));\n            }\n            CharSequence label = fragmentItem.label;\n            holder.title.setText(label != null ? label : fragmentItem.packageName);\n            if (label != null) {\n                holder.subtitle.setVisibility(View.VISIBLE);\n                holder.subtitle.setText(fragmentItem.packageName);\n            } else {\n                holder.subtitle.setVisibility(View.GONE);\n            }\n            if (fragmentItem.applicationInfo != null) {\n                holder.itemView.setOnClickListener(v -> {\n                });\n                holder.itemView.setOnLongClickListener(v -> {\n                    PopupMenu popupMenu = new PopupMenu(mActivity, holder.itemView);\n                    popupMenu.setForceShowIcon(true);\n                    popupMenu.getMenu().add(R.string.delete).setIcon(R.drawable.ic_trash_can)\n                            .setOnMenuItemClickListener(item -> {\n                                mModel.deletePackage(fragmentItem.packageName);\n                                return true;\n                            });\n                    popupMenu.show();\n                    return true;\n                });\n            }\n        }\n\n        @Override\n        public int getItemCount() {\n            return packages.size();\n        }\n\n        public class ViewHolder extends RecyclerView.ViewHolder {\n            ImageView icon;\n            TextView title;\n            TextView subtitle;\n\n            public ViewHolder(@NonNull View itemView) {\n                super(itemView);\n                icon = itemView.findViewById(android.R.id.icon);\n                icon.setContentDescription(itemView.getContext().getString(R.string.icon));\n                title = itemView.findViewById(android.R.id.title);\n                subtitle = itemView.findViewById(android.R.id.summary);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/profiles/AppsProfileActivity.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.profiles;\n\nimport static io.github.muntashirakon.AppManager.utils.UIUtils.getSmallerText;\n\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.pm.ApplicationInfo;\nimport android.os.Bundle;\nimport android.text.SpannableStringBuilder;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.core.util.Pair;\nimport androidx.fragment.app.Fragment;\n\nimport java.util.ArrayList;\n\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.dialog.SearchableMultiChoiceDialogBuilder;\n\npublic class AppsProfileActivity extends AppsBaseProfileActivity {\n    @NonNull\n    public static Intent getProfileIntent(@NonNull Context context, @NonNull String profileId) {\n        Intent intent = new Intent(context, AppsProfileActivity.class);\n        intent.putExtra(EXTRA_PROFILE_ID, profileId);\n        return intent;\n    }\n\n    @NonNull\n    public static Intent getNewProfileIntent(@NonNull Context context, @NonNull String profileName) {\n        return getNewProfileIntent(context, profileName, null);\n    }\n\n    @NonNull\n    public static Intent getNewProfileIntent(@NonNull Context context, @NonNull String profileName, @Nullable String[] initialPackages) {\n        Intent intent = new Intent(context, AppsProfileActivity.class);\n        intent.putExtra(EXTRA_NEW_PROFILE_NAME, profileName);\n        if (initialPackages != null) {\n            intent.putExtra(EXTRA_NEW_PROFILE_PACKAGES, initialPackages);\n        }\n        return intent;\n    }\n\n    @NonNull\n    public static Intent getCloneProfileIntent(@NonNull Context context, @NonNull String oldProfileId,\n                                               @NonNull String newProfileName) {\n        Intent intent = new Intent(context, AppsProfileActivity.class);\n        intent.putExtra(EXTRA_PROFILE_ID, oldProfileId);\n        intent.putExtra(EXTRA_NEW_PROFILE_NAME, newProfileName);\n        return intent;\n    }\n\n    private static final String EXTRA_NEW_PROFILE_PACKAGES = \"new_prof_pkgs\";\n    private static final String EXTRA_SHORTCUT_TYPE = \"shortcut\";\n\n    @Override\n    public Fragment getAppsBaseFragment() {\n        return new AppsFragment();\n    }\n\n    @Override\n    public void loadNewProfile(@NonNull String newProfileName, @NonNull Intent intent) {\n        @Nullable String[] initialPackages = intent.getStringArrayExtra(EXTRA_NEW_PROFILE_PACKAGES);\n        model.loadNewAppsProfile(newProfileName, initialPackages);\n    }\n\n    @Override\n    protected void onAuthenticated(@Nullable Bundle savedInstanceState) {\n        super.onAuthenticated(savedInstanceState);\n        bottomNavigationView.getMenu().removeItem(R.id.action_preview);\n        if (getIntent().hasExtra(EXTRA_SHORTCUT_TYPE)) {\n            // Compatibility mode for shortcut\n            @ProfileApplierActivity.ShortcutType String shortcutType = getIntent().getStringExtra(EXTRA_SHORTCUT_TYPE);\n            @Nullable String profileState = getIntent().getStringExtra(EXTRA_STATE);\n            if (shortcutType != null && profileId != null) {\n                ProfileApplierActivity.getShortcutIntent(this, profileId, shortcutType, profileState);\n            }\n            // Finish regardless of whether the profile applier launched or not\n            finish();\n            return;\n        }\n        fab.setImageResource(R.drawable.ic_add);\n        fab.setContentDescription(getString(R.string.add_item));\n        fab.setOnClickListener(v -> {\n            progressIndicator.show();\n            model.loadInstalledApps();\n        });\n        model.observeInstalledApps().observe(this, itemPairs -> {\n            ArrayList<String> items = new ArrayList<>(itemPairs.size());\n            ArrayList<CharSequence> itemNames = new ArrayList<>(itemPairs.size());\n            for (Pair<CharSequence, ApplicationInfo> itemPair : itemPairs) {\n                items.add(itemPair.second.packageName);\n                boolean isSystem = (itemPair.second.flags & ApplicationInfo.FLAG_SYSTEM) != 0;\n                itemNames.add(new SpannableStringBuilder(itemPair.first)\n                        .append(\"\\n\")\n                        .append(getSmallerText(getString(isSystem ? R.string.system : R.string.user))));\n            }\n            progressIndicator.hide();\n            new SearchableMultiChoiceDialogBuilder<>(this, items, itemNames)\n                    .addSelections(model.getCurrentPackages())\n                    .setTitle(R.string.apps)\n                    .setPositiveButton(R.string.ok, (d, i, selectedItems) -> model.setPackages(selectedItems))\n                    .setNegativeButton(R.string.cancel, null)\n                    .show();\n        });\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/profiles/AppsProfileViewModel.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.profiles;\n\nimport static io.github.muntashirakon.AppManager.compat.PackageManagerCompat.MATCH_DISABLED_COMPONENTS;\nimport static io.github.muntashirakon.AppManager.compat.PackageManagerCompat.MATCH_STATIC_SHARED_AND_SDK_LIBRARIES;\nimport static io.github.muntashirakon.AppManager.compat.PackageManagerCompat.MATCH_UNINSTALLED_PACKAGES;\nimport static io.github.muntashirakon.AppManager.utils.PackageUtils.getAppOpNames;\n\nimport android.annotation.SuppressLint;\nimport android.app.Application;\nimport android.content.pm.ApplicationInfo;\nimport android.content.pm.PackageManager;\nimport android.os.RemoteException;\nimport android.os.UserHandleHidden;\n\nimport androidx.annotation.AnyThread;\nimport androidx.annotation.GuardedBy;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.StringRes;\nimport androidx.annotation.WorkerThread;\nimport androidx.core.util.Pair;\nimport androidx.lifecycle.AndroidViewModel;\nimport androidx.lifecycle.LiveData;\nimport androidx.lifecycle.MutableLiveData;\n\nimport org.json.JSONException;\n\nimport java.io.IOException;\nimport java.io.OutputStream;\nimport java.text.Collator;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Objects;\nimport java.util.Set;\nimport java.util.concurrent.Future;\n\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.compat.AppOpsManagerCompat;\nimport io.github.muntashirakon.AppManager.compat.PackageManagerCompat;\nimport io.github.muntashirakon.AppManager.filters.FilterItem;\nimport io.github.muntashirakon.AppManager.filters.FilterableAppInfo;\nimport io.github.muntashirakon.AppManager.filters.FilteringUtils;\nimport io.github.muntashirakon.AppManager.logs.Log;\nimport io.github.muntashirakon.AppManager.profiles.struct.AppsBaseProfile;\nimport io.github.muntashirakon.AppManager.profiles.struct.AppsFilterProfile;\nimport io.github.muntashirakon.AppManager.profiles.struct.AppsProfile;\nimport io.github.muntashirakon.AppManager.profiles.struct.BaseProfile;\nimport io.github.muntashirakon.AppManager.users.Users;\nimport io.github.muntashirakon.AppManager.utils.ArrayUtils;\nimport io.github.muntashirakon.AppManager.utils.PackageUtils;\nimport io.github.muntashirakon.AppManager.utils.ThreadUtils;\nimport io.github.muntashirakon.AppManager.utils.Utils;\nimport io.github.muntashirakon.io.Path;\n\npublic class AppsProfileViewModel extends AndroidViewModel {\n    private final Object mProfileLock = new Object();\n    private final MutableLiveData<Pair<Integer, Boolean>> mToast = new MutableLiveData<>();\n    private final MutableLiveData<ArrayList<Pair<CharSequence, ApplicationInfo>>> mInstalledApps = new MutableLiveData<>();\n    private final MutableLiveData<String> mProfileLoaded = new MutableLiveData<>();\n    private final MutableLiveData<Boolean> mProfileModifiedLiveData = new MutableLiveData<>();\n    private final MutableLiveData<String> mLogs = new MutableLiveData<>();\n\n    private MutableLiveData<ArrayList<AppsFragment.AppsFragmentItem>> packagesLiveData;\n    @GuardedBy(\"profileLock\")\n    @Nullable\n    private AppsBaseProfile mProfile;\n    private boolean mIsModified;\n    @Nullable\n    private Future<?> mLoadProfileResult;\n    private Future<?> mLoadAppsResult;\n\n    public AppsProfileViewModel(@NonNull Application application) {\n        super(application);\n    }\n\n    @Override\n    protected void onCleared() {\n        if (mLoadProfileResult != null) {\n            mLoadProfileResult.cancel(true);\n        }\n        if (mLoadAppsResult != null) {\n            mLoadAppsResult.cancel(true);\n        }\n        super.onCleared();\n    }\n\n    public boolean isModified() {\n        return mIsModified;\n    }\n\n    @SuppressLint(\"WrongThread\") // main thread check present\n    @AnyThread\n    public void setModified(boolean modified) {\n        if (mIsModified != modified) {\n            mIsModified = modified;\n            if (ThreadUtils.isMainThread()) {\n                mProfileModifiedLiveData.setValue(modified);\n            } else {\n                mProfileModifiedLiveData.postValue(modified);\n            }\n        }\n    }\n\n    public LiveData<Pair<Integer, Boolean>> observeToast() {\n        return mToast;\n    }\n\n    public LiveData<ArrayList<Pair<CharSequence, ApplicationInfo>>> observeInstalledApps() {\n        return mInstalledApps;\n    }\n\n    public LiveData<String> observeProfileLoaded() {\n        return mProfileLoaded;\n    }\n\n    public LiveData<Boolean> getProfileModifiedLiveData() {\n        return mProfileModifiedLiveData;\n    }\n\n    public LiveData<String> getLogs() {\n        return mLogs;\n    }\n\n    @AnyThread\n    public void loadInstalledApps() {\n        if (mLoadAppsResult != null) {\n            mLoadAppsResult.cancel(true);\n        }\n        mLoadAppsResult = ThreadUtils.postOnBackgroundThread(() -> {\n            PackageManager pm = getApplication().getPackageManager();\n            try {\n                ArrayList<Pair<CharSequence, ApplicationInfo>> itemPairs;\n                List<ApplicationInfo> applicationInfoList;\n                applicationInfoList = PackageUtils.getAllApplications(MATCH_UNINSTALLED_PACKAGES\n                        | MATCH_STATIC_SHARED_AND_SDK_LIBRARIES);\n                HashSet<String> applicationInfoHashMap = new HashSet<>();\n                itemPairs = new ArrayList<>();\n                for (ApplicationInfo info : applicationInfoList) {\n                    if (applicationInfoHashMap.contains(info.packageName)) {\n                        continue;\n                    }\n                    applicationInfoHashMap.add(info.packageName);\n                    itemPairs.add(new Pair<>(pm.getApplicationLabel(info), info));\n                    if (ThreadUtils.isInterrupted()) {\n                        return;\n                    }\n                }\n                List<String> selectedPackages = mProfile instanceof AppsProfile ?\n                        Arrays.asList(((AppsProfile) mProfile).packages) : Collections.emptyList();\n                Collator collator = Collator.getInstance();\n                Collections.sort(itemPairs, (o1, o2) -> collator.compare(o1.first.toString(), o2.first.toString()));\n                Collections.sort(itemPairs, (o1, o2) -> {\n                    boolean o1Selected = selectedPackages.contains(o1.second.packageName);\n                    boolean o2Selected = selectedPackages.contains(o2.second.packageName);\n                    if (o1Selected && o2Selected) {\n                        return 0;\n                    }\n                    if (o1Selected) {\n                        return -1;\n                    }\n                    if (o2Selected) {\n                        return +1;\n                    }\n                    return 0;\n                });\n                mInstalledApps.postValue(itemPairs);\n            } catch (Exception e) {\n                e.printStackTrace();\n            }\n        });\n    }\n\n    public String getProfileName() {\n        return mProfile != null ? mProfile.name : null;\n    }\n\n    public String getProfileId() {\n        return mProfile != null ? mProfile.profileId : null;\n    }\n\n    @AnyThread\n    public void loadProfile(@NonNull String profileId) {\n        if (mLoadProfileResult != null) {\n            mLoadProfileResult.cancel(true);\n        }\n        mLoadProfileResult = ThreadUtils.postOnBackgroundThread(() -> {\n            loadProfileInternal(profileId);\n            mProfileLoaded.postValue(mProfile != null ? mProfile.name : null);\n        });\n    }\n\n    @AnyThread\n    public void loadLogs() {\n        if (mProfile == null) {\n            return;\n        }\n        ThreadUtils.postOnBackgroundThread(() -> mLogs.postValue(ProfileLogger.getAllLogs(mProfile.profileId)));\n    }\n\n    @WorkerThread\n    @GuardedBy(\"profileLock\")\n    private void loadProfileInternal(@NonNull String profileId) {\n        synchronized (mProfileLock) {\n            Path profilePath = ProfileManager.findProfilePathById(profileId);\n            try {\n                mProfile = (AppsBaseProfile) BaseProfile.fromPath(profilePath);\n            } catch (IOException | JSONException e) {\n                e.printStackTrace();\n            }\n        }\n    }\n\n    @WorkerThread\n    @GuardedBy(\"profileLock\")\n    private void cloneProfileInternal(@NonNull String newProfileName) {\n        synchronized (mProfileLock) {\n            mProfile = (AppsBaseProfile) BaseProfile.newProfile(newProfileName, mProfile.type, mProfile);\n        }\n    }\n\n    @AnyThread\n    public void cloneProfile(@NonNull String newProfileName) {\n        if (mLoadProfileResult != null) {\n            mLoadProfileResult.cancel(true);\n        }\n        mLoadProfileResult = ThreadUtils.postOnBackgroundThread(() -> {\n            if (mProfile == null) {\n                mToast.postValue(new Pair<>(R.string.failed, false));\n                return;\n            }\n            cloneProfileInternal(newProfileName);\n            mToast.postValue(new Pair<>(R.string.done, false));\n            setModified(true);\n            mProfileLoaded.postValue(mProfile != null ? mProfile.name : null);\n        });\n    }\n\n\n    @AnyThread\n    public void loadNewAppsProfile(@NonNull String newProfileName, @Nullable String[] initialPackages) {\n        if (mLoadProfileResult != null) {\n            mLoadProfileResult.cancel(true);\n        }\n        mLoadProfileResult = ThreadUtils.postOnBackgroundThread(() -> {\n            AppsProfile appsProfile;\n            synchronized (mProfileLock) {\n                appsProfile = (AppsProfile) BaseProfile.newProfile(newProfileName, BaseProfile.PROFILE_TYPE_APPS, null);\n            }\n            if (initialPackages != null) {\n                appsProfile.packages = initialPackages;\n            }\n            mProfile = appsProfile;\n            setModified(true);\n            mProfileLoaded.postValue(mProfile != null ? mProfile.name : null);\n        });\n    }\n\n    @AnyThread\n    public void loadNewAppsFilterProfile(@NonNull String newProfileName) {\n        if (mLoadProfileResult != null) {\n            mLoadProfileResult.cancel(true);\n        }\n        mLoadProfileResult = ThreadUtils.postOnBackgroundThread(() -> {\n            synchronized (mProfileLock) {\n                mProfile = (AppsFilterProfile) BaseProfile.newProfile(newProfileName, BaseProfile.PROFILE_TYPE_APPS_FILTER, null);\n            }\n            setModified(true);\n            mProfileLoaded.postValue(mProfile != null ? mProfile.name : null);\n        });\n    }\n\n    @AnyThread\n    public void loadAndCloneProfile(@NonNull String profileId, @NonNull String newProfileName) {\n        if (mLoadProfileResult != null) {\n            mLoadProfileResult.cancel(true);\n        }\n        mLoadProfileResult = ThreadUtils.postOnBackgroundThread(() -> {\n            if (mProfile == null) {\n                loadProfileInternal(profileId);\n                if (ThreadUtils.isInterrupted()) {\n                    return;\n                }\n            }\n            cloneProfileInternal(newProfileName);\n            setModified(true);\n            mProfileLoaded.postValue(mProfile != null ? mProfile.name : null);\n        });\n    }\n\n    @AnyThread\n    @GuardedBy(\"profileLock\")\n    public void setPackages(@NonNull List<String> packages) {\n        if (mProfile == null) return;\n        assert mProfile instanceof AppsProfile;\n        setModified(true);\n        synchronized (mProfileLock) {\n            ((AppsProfile) mProfile).packages = packages.toArray(new String[0]);\n            Log.e(\"Packages\", \"%s\", packages);\n            loadPackages();\n        }\n    }\n\n    @GuardedBy(\"profileLock\")\n    public void deletePackage(@NonNull String packageName) {\n        if (mProfile == null) return;\n        assert mProfile instanceof AppsProfile;\n        setModified(true);\n        synchronized (mProfileLock) {\n            AppsProfile profile = (AppsProfile) mProfile;\n            profile.packages = Objects.requireNonNull(ArrayUtils.removeString(profile.packages, packageName));\n            loadPackages();\n        }\n    }\n\n    @AnyThread\n    @GuardedBy(\"profileLock\")\n    public void save(boolean exitOnSave) {\n        if (mProfile == null) return; // Should never happen\n        ThreadUtils.postOnBackgroundThread(() -> {\n            synchronized (mProfileLock) {\n                try {\n                    Path profilePath = ProfileManager.requireProfilePathById(mProfile.profileId);\n                    try (OutputStream os = profilePath.openOutputStream()) {\n                        mProfile.write(os);\n                        mToast.postValue(new Pair<>(R.string.saved_successfully, exitOnSave));\n                        setModified(false);\n                    }\n                } catch (IOException e) {\n                    e.printStackTrace();\n                    mToast.postValue(new Pair<>(R.string.saving_failed, false));\n                }\n            }\n        });\n    }\n\n    @AnyThread\n    public void discard() {\n        if (mLoadProfileResult != null) {\n            mLoadProfileResult.cancel(true);\n        }\n        mLoadProfileResult = ThreadUtils.postOnBackgroundThread(() -> {\n            synchronized (mProfileLock) {\n                if (mProfile != null) {\n                    loadProfileInternal(mProfile.profileId);\n                }\n                if (ThreadUtils.isInterrupted()) {\n                    return;\n                }\n                loadPackages();\n                setModified(false);\n            }\n        });\n    }\n\n    @AnyThread\n    public void delete() {\n        ThreadUtils.postOnBackgroundThread(() -> {\n            synchronized (mProfileLock) {\n                if (mProfile == null) return;\n                if (ProfileManager.deleteProfile(mProfile.profileId)) {\n                    mToast.postValue(new Pair<>(R.string.deleted_successfully, true));\n                } else mToast.postValue(new Pair<>(R.string.deletion_failed, false));\n            }\n        });\n    }\n\n    @NonNull\n    public LiveData<ArrayList<AppsFragment.AppsFragmentItem>> getPackages() {\n        if (packagesLiveData == null) {\n            packagesLiveData = new MutableLiveData<>();\n            loadPackages();\n        }\n        return packagesLiveData;\n    }\n\n    public List<String> getCurrentPackages() {\n        if (mProfile == null) {\n            return Collections.emptyList();\n        }\n        assert mProfile instanceof AppsProfile;\n        return Arrays.asList(((AppsProfile) mProfile).packages);\n    }\n\n    public FilterItem getFilterItem() {\n        assert mProfile instanceof AppsFilterProfile;\n        return ((AppsFilterProfile) mProfile).getFilterItem();\n    }\n\n    @StringRes\n    public int getPreviewTitleString() {\n        if (mProfile instanceof AppsProfile) {\n            return R.string.apps;\n        } else if (mProfile instanceof AppsFilterProfile) {\n            return R.string.preview;\n        }\n        if (mProfile != null) {\n            throw new UnsupportedOperationException(\"Invalid profile type: \" + mProfile.type);\n        } else throw new UnsupportedOperationException(\"Profile not initialized\");\n    }\n\n    @AnyThread\n    public void loadPackages() {\n        if (mLoadProfileResult != null) {\n            mLoadProfileResult.cancel(true);\n        }\n        mLoadProfileResult = ThreadUtils.postOnBackgroundThread(() -> {\n            synchronized (mProfileLock) {\n                if (mProfile instanceof AppsProfile) {\n                    packagesLiveData.postValue(loadAppsPackages((AppsProfile) mProfile));\n                } else if (mProfile instanceof AppsFilterProfile) {\n                    packagesLiveData.postValue(loadAppsFilteredPackages((AppsFilterProfile) mProfile));\n                }\n            }\n        });\n    }\n\n    @NonNull\n    private ArrayList<AppsFragment.AppsFragmentItem> loadAppsPackages(@NonNull AppsProfile profile) {\n        ArrayList<AppsFragment.AppsFragmentItem> oldItems = packagesLiveData.getValue();\n        ArrayList<AppsFragment.AppsFragmentItem> items = new ArrayList<>(profile.packages.length);\n        int userId = UserHandleHidden.myUserId();\n        PackageManager pm = getApplication().getPackageManager();\n        for (String packageName : profile.packages) {\n            AppsFragment.AppsFragmentItem item = new AppsFragment.AppsFragmentItem(packageName);\n            // Check for old item for faster loading in case there are hundreds of items\n            if (oldItems != null) {\n                int i = oldItems.indexOf(item);\n                if (i != -1) {\n                    AppsFragment.AppsFragmentItem oldItem = oldItems.get(i);\n                    if (oldItem.applicationInfo != null) {\n                        item.applicationInfo = oldItem.applicationInfo;\n                        item.label = oldItem.label;\n                    }\n                }\n            }\n            if (item.applicationInfo == null) {\n                try {\n                    item.applicationInfo = PackageManagerCompat.getApplicationInfo(packageName,\n                            MATCH_UNINSTALLED_PACKAGES | MATCH_DISABLED_COMPONENTS\n                                    | MATCH_STATIC_SHARED_AND_SDK_LIBRARIES, userId);\n                } catch (RemoteException | PackageManager.NameNotFoundException ignore) {\n                }\n                if (item.applicationInfo != null) {\n                    item.label = item.applicationInfo.loadLabel(pm);\n                }\n                if (Objects.equals(item.label, packageName)) {\n                    item.label = null;\n                }\n            }\n            items.add(item);\n        }\n        return items;\n    }\n\n    List<FilterableAppInfo> mFilterableAppInfoList;\n\n    @NonNull\n    private ArrayList<AppsFragment.AppsFragmentItem> loadAppsFilteredPackages(@NonNull AppsFilterProfile profile) {\n        int[] users = profile.users != null ? profile.users : Users.getUsersIds();\n        if (mFilterableAppInfoList == null) {\n            mFilterableAppInfoList = FilteringUtils.loadFilterableAppInfo(users);\n        }\n        List<FilterItem.FilteredItemInfo<FilterableAppInfo>> filteredItems = profile.getFilterItem().getFilteredList(mFilterableAppInfoList);\n        ArrayList<AppsFragment.AppsFragmentItem> items = new ArrayList<>(filteredItems.size());\n        for (FilterItem.FilteredItemInfo<FilterableAppInfo> itemInfo : filteredItems) {\n            AppsFragment.AppsFragmentItem item = new AppsFragment.AppsFragmentItem(itemInfo.info.getPackageName());\n            item.label = itemInfo.info.getAppLabel();\n            item.filterableAppInfo = itemInfo.info;\n            items.add(item);\n        }\n        return items;\n    }\n\n    public void putBoolean(@NonNull String key, boolean value) {\n        if (mProfile == null) return;\n        setModified(true);\n        switch (key) {\n            case \"freeze\":\n                mProfile.freeze = value;\n                break;\n            case \"force_stop\":\n                mProfile.forceStop = value;\n                break;\n            case \"clear_cache\":\n                mProfile.clearCache = value;\n                break;\n            case \"clear_data\":\n                mProfile.clearData = value;\n                break;\n            case \"block_trackers\":\n                mProfile.blockTrackers = value;\n                break;\n            case \"save_apk\":\n                mProfile.saveApk = value;\n                break;\n            case \"allow_routine\":\n                mProfile.allowRoutine = value;\n                break;\n        }\n    }\n\n    public boolean getBoolean(@NonNull String key, boolean defValue) {\n        if (mProfile == null) return defValue;\n        switch (key) {\n            case \"freeze\":\n                return mProfile.freeze;\n            case \"force_stop\":\n                return mProfile.forceStop;\n            case \"clear_cache\":\n                return mProfile.clearCache;\n            case \"clear_data\":\n                return mProfile.clearData;\n            case \"block_trackers\":\n                return mProfile.blockTrackers;\n            case \"save_apk\":\n                return mProfile.saveApk;\n            case \"allow_routine\":\n                return mProfile.allowRoutine;\n            default:\n                return defValue;\n        }\n    }\n\n    @Nullable\n    public String getComment() {\n        if (mProfile == null) return null;\n        return mProfile.comment;\n    }\n\n    public void setComment(@Nullable String comment) {\n        if (mProfile == null) return;\n        setModified(true);\n        mProfile.comment = comment;\n    }\n\n    public void setState(@BaseProfile.ProfileState String state) {\n        if (mProfile == null) return;\n        setModified(true);\n        mProfile.state = state;\n    }\n\n    @NonNull\n    @BaseProfile.ProfileState\n    public String getState() {\n        return mProfile == null || mProfile.state == null ? BaseProfile.STATE_OFF : mProfile.state;\n    }\n\n    public void setUsers(@Nullable int[] users) {\n        if (mProfile == null) return;\n        setModified(true);\n        mProfile.users = users;\n    }\n\n    @WorkerThread\n    @NonNull\n    public int[] getUsers() {\n        return mProfile == null || mProfile.users == null ? Users.getUsersIds() : mProfile.users;\n    }\n\n    public void setExportRules(@Nullable Integer flags) {\n        if (mProfile == null) return;\n        setModified(true);\n        mProfile.exportRules = flags;\n    }\n\n    @Nullable\n    public Integer getExportRules() {\n        if (mProfile == null) return null;\n        return mProfile.exportRules;\n    }\n\n    public void setComponents(@Nullable String[] components) {\n        if (mProfile == null) return;\n        setModified(true);\n        mProfile.components = components;\n    }\n\n    @Nullable\n    public String[] getComponents() {\n        if (mProfile == null) return null;\n        return mProfile.components;\n    }\n\n    public void setPermissions(@Nullable String[] permissions) {\n        if (mProfile == null) return;\n        setModified(true);\n        if (permissions != null) {\n            for (String permission : permissions) {\n                if (permission.equals(\"*\")) {\n                    // Wildcard found, ignore all permissions in favour of global wildcard\n                    mProfile.permissions = new String[]{\"*\"};\n                    return;\n                }\n            }\n        }\n        mProfile.permissions = permissions;\n    }\n\n    @Nullable\n    public String[] getPermissions() {\n        if (mProfile == null) return null;\n        return mProfile.permissions;\n    }\n\n    public void setAppOps(@Nullable String[] appOpsStr) {\n        if (mProfile == null) return;\n        setModified(true);\n        if (appOpsStr == null) {\n            mProfile.appOps = null;\n            return;\n        }\n        Set<Integer> selectedAppOps = new HashSet<>(appOpsStr.length);\n        List<Integer> appOpList = AppOpsManagerCompat.getAllOps();\n        List<CharSequence> appOpNameList = Arrays.asList(getAppOpNames(appOpList));\n        for (CharSequence appOpStr : appOpsStr) {\n            if (appOpStr.equals(\"*\")) {\n                // Wildcard found, ignore all app ops in favour of global wildcard\n                mProfile.appOps = new int[]{AppOpsManagerCompat.OP_NONE};\n                return;\n            }\n            try {\n                selectedAppOps.add(Utils.getIntegerFromString(appOpStr, appOpNameList, appOpList));\n            } catch (IllegalArgumentException ignore) {\n            }\n        }\n        mProfile.appOps = selectedAppOps.isEmpty() ? null : ArrayUtils.convertToIntArray(selectedAppOps);\n    }\n\n    @Nullable\n    public String[] getAppOpsStr() {\n        if (mProfile == null) return null;\n        int[] appOps = mProfile.appOps;\n        if (appOps == null) return null;\n        String[] appOpsStr = new String[appOps.length];\n        for (int i = 0; i < appOps.length; ++i) {\n            appOpsStr[i] = AppOpsManagerCompat.opToName(appOps[i]);\n        }\n        return appOpsStr;\n    }\n\n    public void setBackupInfo(@Nullable AppsBaseProfile.BackupInfo backupInfo) {\n        if (mProfile == null) return;\n        setModified(true);\n        mProfile.backupData = backupInfo;\n    }\n\n    @Nullable\n    public AppsBaseProfile.BackupInfo getBackupInfo() {\n        if (mProfile == null) return null;\n        return mProfile.backupData;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/profiles/ConfFragment.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.profiles;\n\nimport android.os.Bundle;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.fragment.app.Fragment;\nimport androidx.lifecycle.ViewModelProvider;\n\nimport io.github.muntashirakon.AppManager.R;\n\npublic class ConfFragment extends Fragment {\n    private AppsBaseProfileActivity mActivity;\n\n    @Override\n    public void onCreate(@Nullable Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        mActivity = (AppsBaseProfileActivity) requireActivity();\n    }\n\n    @Nullable\n    @Override\n    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {\n        return inflater.inflate(R.layout.fragment_container, container, false);\n    }\n\n    @Override\n    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {\n        super.onViewCreated(view, savedInstanceState);\n        AppsProfileViewModel model = new ViewModelProvider(requireActivity()).get(AppsProfileViewModel.class);\n        model.observeProfileLoaded().observe(getViewLifecycleOwner(), profileName -> {\n            if (profileName == null) return;\n            getChildFragmentManager()\n                    .beginTransaction()\n                    .replace(R.id.fragment_container_view_tag, new ConfPreferences())\n                    .commit();\n        });\n    }\n\n    @Override\n    public void onResume() {\n        super.onResume();\n        if (mActivity.getSupportActionBar() != null) {\n            mActivity.getSupportActionBar().setSubtitle(R.string.configurations);\n        }\n        mActivity.fab.hide();\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/profiles/ConfPreferences.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.profiles;\n\nimport android.os.Bundle;\nimport android.text.TextUtils;\nimport android.view.View;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.preference.Preference;\nimport androidx.preference.PreferenceDataStore;\nimport androidx.preference.PreferenceFragmentCompat;\nimport androidx.preference.SwitchPreferenceCompat;\nimport androidx.recyclerview.widget.RecyclerView;\n\nimport com.google.android.material.dialog.MaterialAlertDialogBuilder;\nimport com.google.android.material.textfield.TextInputEditText;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.Objects;\nimport java.util.concurrent.atomic.AtomicInteger;\n\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.backup.BackupFlags;\nimport io.github.muntashirakon.AppManager.profiles.struct.AppsBaseProfile;\nimport io.github.muntashirakon.AppManager.profiles.struct.BaseProfile;\nimport io.github.muntashirakon.AppManager.rules.RulesTypeSelectionDialogFragment;\nimport io.github.muntashirakon.AppManager.users.UserInfo;\nimport io.github.muntashirakon.AppManager.users.Users;\nimport io.github.muntashirakon.AppManager.utils.ArrayUtils;\nimport io.github.muntashirakon.AppManager.utils.TextUtilsCompat;\nimport io.github.muntashirakon.AppManager.utils.Utils;\nimport io.github.muntashirakon.dialog.SearchableMultiChoiceDialogBuilder;\nimport io.github.muntashirakon.dialog.SearchableSingleChoiceDialogBuilder;\nimport io.github.muntashirakon.dialog.TextInputDialogBuilder;\nimport io.github.muntashirakon.util.UiUtils;\n\npublic class ConfPreferences extends PreferenceFragmentCompat {\n    private AppsBaseProfileActivity mActivity;\n    private AppsProfileViewModel mModel;\n\n    @BaseProfile.ProfileState\n    private final List<String> mStates = Arrays.asList(BaseProfile.STATE_ON, BaseProfile.STATE_OFF);\n    @Nullable\n    private String[] mComponents;\n    @Nullable\n    private String[] mAppOps;\n    @Nullable\n    private String[] mPermissions;\n    @Nullable\n    private AppsBaseProfile.BackupInfo mBackupInfo;\n\n    @Override\n    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {\n        super.onViewCreated(view, savedInstanceState);\n        // https://github.com/androidx/androidx/blob/androidx-main/preference/preference/res/layout/preference_recyclerview.xml\n        RecyclerView recyclerView = view.findViewById(R.id.recycler_view);\n        recyclerView.setFitsSystemWindows(true);\n        recyclerView.setClipToPadding(false);\n        UiUtils.applyWindowInsetsAsPadding(recyclerView, false, true);\n    }\n\n    @Override\n    public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {\n        setPreferencesFromResource(R.xml.preferences_profile_config, rootKey);\n        getPreferenceManager().setPreferenceDataStore(new ConfDataStore());\n        mActivity = (AppsBaseProfileActivity) requireActivity();\n        if (mActivity.model == null) {\n            // ViewModel should never be null.\n            // If it's null, it means that we're on the wrong Fragment\n            return;\n        }\n        mModel = mActivity.model;\n        // Set profile ID\n        Preference profileIdPref = Objects.requireNonNull(findPreference(\"profile_id\"));\n        profileIdPref.setSummary(mModel.getProfileId());\n        profileIdPref.setOnPreferenceClickListener(preference -> {\n            Utils.copyToClipboard(mActivity, mModel.getProfileName(), mModel.getProfileId());\n            return true;\n        });\n        // Set comment\n        Preference commentPref = Objects.requireNonNull(findPreference(\"comment\"));\n        commentPref.setSummary(mModel.getComment());\n        commentPref.setOnPreferenceClickListener(preference -> {\n            new TextInputDialogBuilder(mActivity, R.string.comment)\n                    .setTitle(R.string.comment)\n                    .setInputText(mModel.getComment())\n                    .setPositiveButton(R.string.ok, (dialog, which, inputText, isChecked) -> {\n                        mModel.setComment(TextUtils.isEmpty(inputText) ? null : inputText.toString());\n                        commentPref.setSummary(mModel.getComment());\n                    })\n                    .setNegativeButton(R.string.cancel, null)\n                    .show();\n            return true;\n        });\n        // Set state\n        Preference statePref = Objects.requireNonNull(findPreference(\"state\"));\n        final String[] statesL = new String[]{\n                getString(R.string.on),\n                getString(R.string.off)\n        };\n        statePref.setTitle(getString(R.string.process_state, statesL[mStates.indexOf(mModel.getState())]));\n        statePref.setOnPreferenceClickListener(preference -> {\n            new SearchableSingleChoiceDialogBuilder<>(mActivity, mStates, statesL)\n                    .setTitle(R.string.profile_state)\n                    .setSelection(mModel.getState())\n                    .setOnSingleChoiceClickListener((dialog, which, item, isChecked) -> {\n                        if (!isChecked) {\n                            return;\n                        }\n                        mModel.setState(mStates.get(which));\n                        statePref.setTitle(getString(R.string.process_state, statesL[which]));\n                        dialog.dismiss();\n                    })\n                    .show();\n            return true;\n        });\n        // Set users\n        Preference usersPref = Objects.requireNonNull(findPreference(\"users\"));\n        handleUsersPref(usersPref);\n        // Set components\n        Preference componentsPref = Objects.requireNonNull(findPreference(\"components\"));\n        updateComponentsPref(componentsPref);\n        componentsPref.setOnPreferenceClickListener(preference -> {\n            new TextInputDialogBuilder(mActivity, R.string.input_signatures)\n                    .setTitle(R.string.components)\n                    .setInputText(mComponents == null ? \"\" : TextUtils.join(\" \", mComponents))\n                    .setHelperText(R.string.input_signatures_description)\n                    .setPositiveButton(R.string.ok, (dialog, which, inputText, isChecked) -> {\n                        if (!TextUtils.isEmpty(inputText)) {\n                            String[] newComponents = inputText.toString().split(\"\\\\s+\");\n                            mModel.setComponents(newComponents);\n                        } else mModel.setComponents(null);\n                        updateComponentsPref(componentsPref);\n                    })\n                    .setNegativeButton(R.string.disable, (dialog, which, inputText, isChecked) -> {\n                        mModel.setComponents(null);\n                        updateComponentsPref(componentsPref);\n                    })\n                    .show();\n            return true;\n        });\n        // Set app ops\n        Preference appOpsPref = Objects.requireNonNull(findPreference(\"app_ops\"));\n        updateAppOpsPref(appOpsPref);\n        appOpsPref.setOnPreferenceClickListener(preference -> {\n            new TextInputDialogBuilder(mActivity, R.string.input_app_ops)\n                    .setTitle(R.string.app_ops)\n                    .setInputText(mAppOps == null ? \"\" : TextUtils.join(\" \", mAppOps))\n                    .setHelperText(R.string.input_app_ops_description_profile)\n                    .setPositiveButton(R.string.ok, (dialog, which, inputText, isChecked) -> {\n                        if (!TextUtils.isEmpty(inputText)) {\n                            String[] newAppOps = inputText.toString().split(\"\\\\s+\");\n                            mModel.setAppOps(newAppOps);\n                        } else mModel.setAppOps(null);\n                        updateAppOpsPref(appOpsPref);\n                    })\n                    .setNegativeButton(R.string.disable, (dialog, which, inputText, isChecked) -> {\n                        mModel.setAppOps(null);\n                        updateAppOpsPref(appOpsPref);\n                    })\n                    .show();\n            return true;\n        });\n        // Set permissions\n        Preference permissionsPref = Objects.requireNonNull(findPreference(\"permissions\"));\n        updatePermissionsPref(permissionsPref);\n        permissionsPref.setOnPreferenceClickListener(preference -> {\n            new TextInputDialogBuilder(mActivity, R.string.input_permissions)\n                    .setTitle(R.string.declared_permission)\n                    .setInputText(mPermissions == null ? \"\" : TextUtils.join(\" \", mPermissions))\n                    .setHelperText(R.string.input_permissions_description)\n                    .setPositiveButton(R.string.ok, (dialog, which, inputText, isChecked) -> {\n                        if (!TextUtils.isEmpty(inputText)) {\n                            String[] newPermissions = inputText.toString().split(\"\\\\s+\");\n                            mModel.setPermissions(newPermissions);\n                        } else mModel.setPermissions(null);\n                        updatePermissionsPref(permissionsPref);\n                    })\n                    .setNegativeButton(R.string.disable, (dialog, which, inputText, isChecked) -> {\n                        mModel.setPermissions(null);\n                        updatePermissionsPref(permissionsPref);\n                    })\n                    .show();\n            return true;\n        });\n        Preference backupDataPref = Objects.requireNonNull(findPreference(\"backup_data\"));\n        mBackupInfo = mModel.getBackupInfo();\n        backupDataPref.setSummary(mBackupInfo != null ? R.string.enabled : R.string.disabled_app);\n        backupDataPref.setOnPreferenceClickListener(preference -> {\n            View view = View.inflate(mActivity, R.layout.dialog_profile_backup_restore, null);\n            final BackupFlags flags;\n            if (mBackupInfo != null) {\n                flags = new BackupFlags(mBackupInfo.flags);\n            } else flags = BackupFlags.fromPref();\n            final AtomicInteger backupFlags = new AtomicInteger(flags.getFlags());\n            view.findViewById(R.id.dialog_button).setOnClickListener(v -> {\n                List<Integer> supportedBackupFlags = BackupFlags.getSupportedBackupFlagsAsArray();\n                new SearchableMultiChoiceDialogBuilder<>(requireActivity(), supportedBackupFlags,\n                        BackupFlags.getFormattedFlagNames(requireContext(), supportedBackupFlags))\n                        .setTitle(R.string.backup_options)\n                        .addSelections(flags.flagsToCheckedIndexes(supportedBackupFlags))\n                        .hideSearchBar(true)\n                        .showSelectAll(false)\n                        .setPositiveButton(R.string.save, (dialog, which, selectedItems) -> {\n                            int flagsInt = 0;\n                            for (int flag : selectedItems) {\n                                flagsInt |= flag;\n                            }\n                            flags.setFlags(flagsInt);\n                            backupFlags.set(flags.getFlags());\n                        })\n                        .setNegativeButton(R.string.cancel, null)\n                        .show();\n            });\n            final TextInputEditText editText = view.findViewById(android.R.id.input);\n            if (mBackupInfo != null) {\n                editText.setText(mBackupInfo.name);\n            }\n            new MaterialAlertDialogBuilder(mActivity)\n                    .setTitle(R.string.backup_restore)\n                    .setView(view)\n                    .setPositiveButton(R.string.ok, (dialog, which) -> {\n                        if (mBackupInfo == null) {\n                            mBackupInfo = new AppsBaseProfile.BackupInfo();\n                        }\n                        CharSequence backupName = editText.getText();\n                        BackupFlags backupFlags1 = new BackupFlags(backupFlags.get());\n                        if (!TextUtils.isEmpty(backupName)) {\n                            backupFlags1.addFlag(BackupFlags.BACKUP_MULTIPLE);\n                            mBackupInfo.name = backupName.toString();\n                        } else {\n                            backupFlags1.removeFlag(BackupFlags.BACKUP_MULTIPLE);\n                            mBackupInfo.name = null;\n                        }\n                        mBackupInfo.flags = backupFlags1.getFlags();\n                        mModel.setBackupInfo(mBackupInfo);\n                        backupDataPref.setSummary(R.string.enabled);\n                    })\n                    .setNegativeButton(R.string.disable, (dialog, which) -> {\n                        mModel.setBackupInfo(mBackupInfo = null);\n                        backupDataPref.setSummary(R.string.disabled_app);\n                    })\n                    .show();\n            return true;\n        });\n        // Set export rules\n        Preference exportRulesPref = Objects.requireNonNull(findPreference(\"export_rules\"));\n        int rulesCount = RulesTypeSelectionDialogFragment.RULE_TYPES.length;\n        List<Integer> checkedItems = new ArrayList<>(rulesCount);\n        List<Integer> selectedRules = updateExportRulesPref(exportRulesPref);\n        for (int i = 0; i < rulesCount; ++i) checkedItems.add(1 << i);\n        exportRulesPref.setOnPreferenceClickListener(preference -> {\n            new SearchableMultiChoiceDialogBuilder<>(mActivity, checkedItems, R.array.rule_types)\n                    .setTitle(R.string.options)\n                    .hideSearchBar(true)\n                    .addSelections(selectedRules)\n                    .setPositiveButton(R.string.ok, (dialog, which, selectedItems) -> {\n                        int value = 0;\n                        for (int item : selectedItems) value |= item;\n                        if (value != 0) {\n                            mModel.setExportRules(value);\n                        } else mModel.setExportRules(null);\n                        selectedRules.clear();\n                        selectedRules.addAll(updateExportRulesPref(exportRulesPref));\n                    })\n                    .setNegativeButton(R.string.disable, (dialog, which, selectedItems) -> {\n                        mModel.setExportRules(null);\n                        selectedRules.clear();\n                        selectedRules.addAll(updateExportRulesPref(exportRulesPref));\n                    })\n                    .show();\n            return true;\n        });\n        // Set others\n        ((SwitchPreferenceCompat) Objects.requireNonNull(findPreference(\"freeze\")))\n                .setChecked(mModel.getBoolean(\"freeze\", false));\n        ((SwitchPreferenceCompat) Objects.requireNonNull(findPreference(\"force_stop\")))\n                .setChecked(mModel.getBoolean(\"force_stop\", false));\n        ((SwitchPreferenceCompat) Objects.requireNonNull(findPreference(\"clear_cache\")))\n                .setChecked(mModel.getBoolean(\"clear_cache\", false));\n        ((SwitchPreferenceCompat) Objects.requireNonNull(findPreference(\"clear_data\")))\n                .setChecked(mModel.getBoolean(\"clear_data\", false));\n        ((SwitchPreferenceCompat) Objects.requireNonNull(findPreference(\"block_trackers\")))\n                .setChecked(mModel.getBoolean(\"block_trackers\", false));\n        ((SwitchPreferenceCompat) Objects.requireNonNull(findPreference(\"save_apk\")))\n                .setChecked(mModel.getBoolean(\"save_apk\", false));\n        ((SwitchPreferenceCompat) Objects.requireNonNull(findPreference(\"allow_routine\")))\n                .setChecked(mModel.getBoolean(\"allow_routine\", false));\n    }\n\n    @NonNull\n    private List<Integer> updateExportRulesPref(Preference pref) {\n        Integer rules = mModel.getExportRules();\n        List<Integer> selectedRules = new ArrayList<>();\n        if (rules == null || rules == 0) pref.setSummary(R.string.disabled_app);\n        else {\n            List<String> selectedRulesStr = new ArrayList<>();\n            int i = 0;\n            while (rules != 0) {\n                int flag = (rules & (~(1 << i)));\n                if (flag != rules) {\n                    selectedRulesStr.add(RulesTypeSelectionDialogFragment.RULE_TYPES[i].toString());\n                    rules = flag;\n                    selectedRules.add(1 << i);\n                }\n                ++i;\n            }\n            pref.setSummary(TextUtils.join(\", \", selectedRulesStr));\n        }\n        return selectedRules;\n    }\n\n    private void updateComponentsPref(Preference pref) {\n        mComponents = mModel.getComponents();\n        if (mComponents == null || mComponents.length == 0) pref.setSummary(R.string.disabled_app);\n        else {\n            pref.setSummary(TextUtils.join(\", \", mComponents));\n        }\n    }\n\n    private void updateAppOpsPref(Preference pref) {\n        mAppOps = mModel.getAppOpsStr();\n        if (mAppOps == null || mAppOps.length == 0) pref.setSummary(R.string.disabled_app);\n        else {\n            pref.setSummary(TextUtils.join(\", \", mAppOps));\n        }\n    }\n\n    private void updatePermissionsPref(Preference pref) {\n        mPermissions = mModel.getPermissions();\n        if (mPermissions == null || mPermissions.length == 0) pref.setSummary(R.string.disabled_app);\n        else {\n            pref.setSummary(TextUtils.join(\", \", mPermissions));\n        }\n    }\n\n    private List<Integer> mSelectedUsers;\n\n    private void handleUsersPref(Preference pref) {\n        List<UserInfo> users = Users.getUsers();\n        if (users.size() > 1) {\n            pref.setVisible(true);\n            CharSequence[] userNames = new String[users.size()];\n            List<Integer> userHandles = new ArrayList<>(users.size());\n            int i = 0;\n            for (UserInfo info : users) {\n                userNames[i] = info.toLocalizedString(requireContext());\n                userHandles.add(info.id);\n                ++i;\n            }\n            mSelectedUsers = new ArrayList<>();\n            for (Integer user : mModel.getUsers()) {\n                mSelectedUsers.add(user);\n            }\n            mActivity.runOnUiThread(() -> {\n                pref.setSummary(TextUtilsCompat.joinSpannable(\", \", getUserInfo(users, mSelectedUsers)));\n                pref.setOnPreferenceClickListener(v -> {\n                    new SearchableMultiChoiceDialogBuilder<>(mActivity, userHandles, userNames)\n                            .setTitle(R.string.select_user)\n                            .addSelections(mSelectedUsers)\n                            .showSelectAll(false)\n                            .setPositiveButton(R.string.ok, (dialog, which, selectedUserHandles) -> {\n                                if (selectedUserHandles.isEmpty()) {\n                                    mSelectedUsers = userHandles;\n                                } else mSelectedUsers = selectedUserHandles;\n                                pref.setSummary(TextUtilsCompat.joinSpannable(\", \", getUserInfo(users, mSelectedUsers)));\n                                mModel.setUsers(ArrayUtils.convertToIntArray(mSelectedUsers));\n                            })\n                            .setNegativeButton(R.string.cancel, null)\n                            .show();\n                    return true;\n                });\n            });\n        } else {\n            mActivity.runOnUiThread(() -> pref.setVisible(false));\n        }\n    }\n\n    @NonNull\n    private List<CharSequence> getUserInfo(@NonNull List<UserInfo> userInfoList, @NonNull List<Integer> userHandles) {\n        List<CharSequence> userInfoOut = new ArrayList<>();\n        for (UserInfo info : userInfoList) {\n            if (userHandles.contains(info.id)) {\n                userInfoOut.add(info.toLocalizedString(requireContext()));\n            }\n        }\n        return userInfoOut;\n    }\n\n    public class ConfDataStore extends PreferenceDataStore {\n        @Override\n        public void putBoolean(@NonNull String key, boolean value) {\n            mModel.putBoolean(key, value);\n        }\n\n        @Override\n        public boolean getBoolean(@NonNull String key, boolean defValue) {\n            return mModel.getBoolean(key, defValue);\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/profiles/LogViewerFragment.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.profiles;\n\nimport android.graphics.Typeface;\nimport android.os.Bundle;\nimport android.text.SpannableString;\nimport android.text.Spanned;\nimport android.text.style.StyleSpan;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.appcompat.widget.AppCompatEditText;\nimport androidx.fragment.app.Fragment;\nimport androidx.lifecycle.ViewModelProvider;\n\nimport com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton;\n\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.util.UiUtils;\n\npublic class LogViewerFragment extends Fragment {\n    @Nullable\n    @Override\n    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {\n        return inflater.inflate(R.layout.fragment_log_viewer, container, false);\n    }\n\n    @Override\n    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {\n        AppsProfileViewModel model = new ViewModelProvider(requireActivity()).get(AppsProfileViewModel.class);\n        AppCompatEditText tv = view.findViewById(R.id.log_content);\n        tv.setKeyListener(null);\n        ExtendedFloatingActionButton efab = view.findViewById(R.id.floatingActionButton);\n        UiUtils.applyWindowInsetsAsMargin(efab, false, true);\n        efab.setOnClickListener(v -> {\n            ProfileLogger.clearLogs(model.getProfileId());\n            tv.setText(\"\");\n        });\n        model.getLogs().observe(getViewLifecycleOwner(), logs -> tv.setText(getFormattedLogs(logs)));\n        model.observeProfileLoaded().observe(getViewLifecycleOwner(), profileName -> model.loadLogs());\n    }\n\n    @Override\n    public void onResume() {\n        AppsBaseProfileActivity activity = (AppsBaseProfileActivity) requireActivity();\n        if (activity.getSupportActionBar() != null) {\n            activity.getSupportActionBar().setSubtitle(R.string.log_viewer);\n        }\n        activity.fab.hide();\n        super.onResume();\n    }\n\n\n    public CharSequence getFormattedLogs(String logs) {\n        SpannableString str = new SpannableString(logs);\n        int fIndex = 0;\n        while(true) {\n            fIndex = logs.indexOf(\"====> \", fIndex);\n            if (fIndex == -1) {\n                return str;\n            }\n            int lIndex = logs.indexOf('\\n', fIndex);\n            str.setSpan(new StyleSpan(Typeface.BOLD), fIndex, lIndex, Spanned.SPAN_INCLUSIVE_EXCLUSIVE);\n            fIndex = lIndex;\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/profiles/NewProfileDialogFragment.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.profiles;\n\nimport android.app.Dialog;\nimport android.os.Bundle;\nimport android.text.Editable;\nimport android.text.TextUtils;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.ArrayAdapter;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.fragment.app.DialogFragment;\n\nimport com.google.android.material.dialog.MaterialAlertDialogBuilder;\nimport com.google.android.material.textfield.TextInputEditText;\nimport com.google.android.material.textfield.TextInputLayout;\n\nimport java.lang.ref.WeakReference;\n\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.profiles.struct.BaseProfile;\nimport io.github.muntashirakon.adapters.SelectedArrayAdapter;\nimport io.github.muntashirakon.lifecycle.SoftInputLifeCycleObserver;\nimport io.github.muntashirakon.view.TextInputLayoutCompat;\nimport io.github.muntashirakon.widget.MaterialSpinner;\n\npublic class NewProfileDialogFragment extends DialogFragment {\n    public static final String TAG = NewProfileDialogFragment.class.getSimpleName();\n\n    public interface OnCreateNewProfileInterface {\n        void onCreateNewProfile(@NonNull String newProfileName, @BaseProfile.ProfileType int type);\n    }\n\n    @NonNull\n    public static NewProfileDialogFragment getInstance(@Nullable OnCreateNewProfileInterface createNewProfileInterface) {\n        NewProfileDialogFragment fragment = new NewProfileDialogFragment();\n        fragment.setOnCreateNewProfileInterface(createNewProfileInterface);\n        return fragment;\n    }\n\n    @Nullable\n    private OnCreateNewProfileInterface mOnCreateNewProfileInterface;\n    private View mDialogView;\n    private TextInputEditText mEditText;\n    private int mType;\n\n    @NonNull\n    @Override\n    public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {\n        mDialogView = View.inflate(requireActivity(), R.layout.dialog_new_file, null);\n        mEditText = mDialogView.findViewById(R.id.name);\n        String name = \"Untitled profile\";\n        mEditText.setText(name);\n        mEditText.selectAll();\n        TextInputLayout editTextLayout = TextInputLayoutCompat.fromTextInputEditText(mEditText);\n        editTextLayout.setHelperText(requireContext().getText(R.string.input_profile_name_description));\n        MaterialSpinner spinner = mDialogView.findViewById(R.id.type_selector_spinner);\n        ArrayAdapter<CharSequence> spinnerAdapter = SelectedArrayAdapter.createFromResource(requireContext(),\n                R.array.profile_types, io.github.muntashirakon.ui.R.layout.auto_complete_dropdown_item);\n        spinner.setAdapter(spinnerAdapter);\n        spinner.setSelection(BaseProfile.PROFILE_TYPE_APPS);\n        spinner.setOnItemClickListener((parent, view, position, id) -> {\n            if (mType != position) {\n                mType = position;\n            }\n        });\n        return new MaterialAlertDialogBuilder(requireActivity())\n                .setTitle(R.string.new_profile)\n                .setView(mDialogView)\n                .setPositiveButton(R.string.go, (dialog, which) -> {\n                    Editable editable = mEditText.getText();\n                    if (!TextUtils.isEmpty(editable) && mOnCreateNewProfileInterface != null) {\n                        mOnCreateNewProfileInterface.onCreateNewProfile(editable.toString(), mType);\n                    }\n                })\n                .setNegativeButton(R.string.cancel, null)\n                .create();\n    }\n\n    @Nullable\n    @Override\n    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {\n        return mDialogView;\n    }\n\n    @Override\n    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {\n        getLifecycle().addObserver(new SoftInputLifeCycleObserver(new WeakReference<>(mEditText)));\n    }\n\n    public void setOnCreateNewProfileInterface(@Nullable OnCreateNewProfileInterface createNewProfileInterface) {\n        mOnCreateNewProfileInterface = createNewProfileInterface;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/profiles/ProfileApplierActivity.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.profiles;\n\nimport android.app.Application;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.os.Bundle;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.StringDef;\nimport androidx.core.content.ContextCompat;\nimport androidx.lifecycle.AndroidViewModel;\nimport androidx.lifecycle.MutableLiveData;\nimport androidx.lifecycle.ViewModelProvider;\n\nimport org.json.JSONException;\n\nimport java.io.IOException;\nimport java.util.Arrays;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Queue;\n\nimport io.github.muntashirakon.AppManager.BaseActivity;\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.profiles.struct.BaseProfile;\nimport io.github.muntashirakon.AppManager.utils.ThreadUtils;\nimport io.github.muntashirakon.dialog.DialogTitleBuilder;\nimport io.github.muntashirakon.dialog.SearchableSingleChoiceDialogBuilder;\nimport io.github.muntashirakon.io.Path;\n\npublic class ProfileApplierActivity extends BaseActivity {\n    private static final String EXTRA_SHORTCUT_TYPE = \"shortcut\";\n\n    public static final String EXTRA_PROFILE_ID = \"prof\";\n    public static final String EXTRA_STATE = \"state\";\n    private static final String EXTRA_NOTIFY = \"notify\";\n\n    @StringDef({ST_SIMPLE, ST_ADVANCED})\n    public @interface ShortcutType {\n    }\n\n    public static final String ST_SIMPLE = \"simple\";\n    public static final String ST_ADVANCED = \"advanced\";\n\n    @NonNull\n    public static Intent getShortcutIntent(@NonNull Context context,\n                                           @NonNull String profileId,\n                                           @ShortcutType @Nullable String shortcutType,\n                                           @Nullable String state) {\n        // Compatibility: Old shortcuts still store profile name instead of profile ID.\n        String realProfileId = ProfileManager.getProfileIdCompat(profileId);\n        Intent intent = new Intent(context, ProfileApplierActivity.class);\n        intent.putExtra(EXTRA_PROFILE_ID, realProfileId);\n        if (shortcutType == null) {\n            if (state != null) { // State => It's a simple shortcut\n                intent.putExtra(EXTRA_SHORTCUT_TYPE, ST_SIMPLE);\n                intent.putExtra(EXTRA_STATE, state);\n            } else { // Otherwise it's an advance shortcut\n                intent.putExtra(EXTRA_SHORTCUT_TYPE, ST_ADVANCED);\n            }\n        } else {\n            intent.putExtra(EXTRA_SHORTCUT_TYPE, shortcutType);\n            if (state != null) {\n                intent.putExtra(EXTRA_STATE, state);\n            }\n        }\n        return intent;\n    }\n\n    @NonNull\n    public static Intent getAutomationIntent(@NonNull Context context,\n                                             @NonNull String profileId,\n                                             @Nullable String state) {\n        // Compatibility: Old shortcuts still store profile name instead of profile ID.\n        String realProfileId = ProfileManager.getProfileIdCompat(profileId);\n        Intent intent = new Intent(context, ProfileApplierActivity.class);\n        intent.putExtra(EXTRA_PROFILE_ID, realProfileId);\n        if (state != null) { // State => Automatic trigger\n            intent.putExtra(EXTRA_SHORTCUT_TYPE, ST_SIMPLE);\n            intent.putExtra(EXTRA_STATE, state);\n            // Avoid issuing completion notification\n            intent.putExtra(EXTRA_NOTIFY, false);\n        } else { // Manual trigger\n            intent.putExtra(EXTRA_SHORTCUT_TYPE, ST_ADVANCED);\n        }\n        return intent;\n    }\n\n    @NonNull\n    public static Intent getApplierIntent(@NonNull Context context, @NonNull String profileId) {\n        // Compatibility: Old shortcuts still store profile name instead of profile ID.\n        String realProfileId = ProfileManager.getProfileIdCompat(profileId);\n        Intent intent = new Intent(context, ProfileApplierActivity.class);\n        intent.putExtra(EXTRA_PROFILE_ID, realProfileId);\n        intent.putExtra(EXTRA_SHORTCUT_TYPE, ST_ADVANCED);\n        return intent;\n    }\n\n    public static class ProfileApplierInfo {\n        public BaseProfile profile;\n        public String profileId;\n        @ShortcutType\n        public String shortcutType;\n        @Nullable\n        public String state;\n        public boolean notify;\n    }\n\n    private final Queue<Intent> mQueue = new LinkedList<>();\n    private ProfileApplierViewModel mViewModel;\n\n    @Override\n    public boolean getTransparentBackground() {\n        return true;\n    }\n\n    @Override\n    protected void onAuthenticated(@Nullable Bundle savedInstanceState) {\n        mViewModel = new ViewModelProvider(this).get(ProfileApplierViewModel.class);\n        synchronized (mQueue) {\n            mQueue.add(getIntent());\n        }\n        mViewModel.mProfileLiveData.observe(this, this::handleShortcut);\n        next();\n    }\n\n    @Override\n    protected void onNewIntent(@NonNull Intent intent) {\n        synchronized (mQueue) {\n            mQueue.add(intent);\n        }\n        super.onNewIntent(intent);\n    }\n\n    private void next() {\n        Intent intent;\n        synchronized (mQueue) {\n            intent = mQueue.poll();\n        }\n        if (intent == null) {\n            finish();\n            return;\n        }\n        @ShortcutType\n        String shortcutType = intent.getStringExtra(EXTRA_SHORTCUT_TYPE);\n        String profileId = intent.getStringExtra(EXTRA_PROFILE_ID);\n        String profileState = intent.getStringExtra(EXTRA_STATE);\n        boolean notify = intent.getBooleanExtra(EXTRA_NOTIFY, true);\n        if (shortcutType == null || profileId == null) {\n            // Invalid shortcut\n            return;\n        }\n        ProfileApplierInfo info = new ProfileApplierInfo();\n        info.profileId = profileId;\n        info.shortcutType = shortcutType;\n        info.state = profileState;\n        info.notify = notify;\n        mViewModel.loadProfile(info);\n    }\n\n    private void handleShortcut(@Nullable ProfileApplierInfo info) {\n        if (info == null) {\n            next();\n            return;\n        }\n        info.state = info.state != null ? info.state : info.profile.state;\n        switch (info.shortcutType) {\n            case ST_SIMPLE:\n                Intent intent = ProfileApplierService.getIntent(this,\n                        ProfileQueueItem.fromProfiledApplierInfo(info), info.notify);\n                ContextCompat.startForegroundService(this, intent);\n                next();\n                break;\n            case ST_ADVANCED:\n                final String[] statesL = new String[]{\n                        getString(R.string.on),\n                        getString(R.string.off)\n                };\n                @BaseProfile.ProfileState final List<String> states = Arrays.asList(BaseProfile.STATE_ON, BaseProfile.STATE_OFF);\n                DialogTitleBuilder titleBuilder = new DialogTitleBuilder(this)\n                        .setTitle(getString(R.string.apply_profile, info.profile.name))\n                        .setSubtitle(R.string.choose_a_profile_state);\n                new SearchableSingleChoiceDialogBuilder<>(this, states, statesL)\n                        .setTitle(titleBuilder.build())\n                        .setSelection(info.state)\n                        .setPositiveButton(R.string.ok, (dialog, which, selectedState) -> {\n                            info.state = selectedState;\n                            Intent aIntent = ProfileApplierService.getIntent(this,\n                                    ProfileQueueItem.fromProfiledApplierInfo(info), info.notify);\n                            ContextCompat.startForegroundService(this, aIntent);\n                        })\n                        .setNegativeButton(R.string.cancel, null)\n                        .setOnDismissListener(dialog -> next())\n                        .show();\n                break;\n            default:\n                next();\n        }\n    }\n\n    public static class ProfileApplierViewModel extends AndroidViewModel {\n        final MutableLiveData<ProfileApplierInfo> mProfileLiveData = new MutableLiveData<>();\n\n        public ProfileApplierViewModel(@NonNull Application application) {\n            super(application);\n        }\n\n        public void loadProfile(ProfileApplierInfo info) {\n            ThreadUtils.postOnBackgroundThread(() -> {\n                Path profilePath = ProfileManager.findProfilePathById(info.profileId);\n                try {\n                    info.profile = BaseProfile.fromPath(profilePath);\n                    mProfileLiveData.postValue(info);\n                } catch (IOException | JSONException e) {\n                    e.printStackTrace();\n                }\n            });\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/profiles/ProfileApplierService.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.profiles;\n\nimport static io.github.muntashirakon.AppManager.history.ops.OpHistoryManager.HISTORY_TYPE_PROFILE;\n\nimport android.app.Activity;\nimport android.app.PendingIntent;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.os.PowerManager;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.core.app.NotificationManagerCompat;\nimport androidx.core.app.PendingIntentCompat;\nimport androidx.core.app.ServiceCompat;\n\nimport java.io.IOException;\n\nimport io.github.muntashirakon.AppManager.BuildConfig;\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.batchops.BatchOpsResultsActivity;\nimport io.github.muntashirakon.AppManager.batchops.BatchOpsService;\nimport io.github.muntashirakon.AppManager.history.ops.OpHistoryManager;\nimport io.github.muntashirakon.AppManager.intercept.IntentCompat;\nimport io.github.muntashirakon.AppManager.progress.NotificationProgressHandler;\nimport io.github.muntashirakon.AppManager.progress.NotificationProgressHandler.NotificationManagerInfo;\nimport io.github.muntashirakon.AppManager.progress.ProgressHandler;\nimport io.github.muntashirakon.AppManager.progress.QueuedProgressHandler;\nimport io.github.muntashirakon.AppManager.types.ForegroundService;\nimport io.github.muntashirakon.AppManager.utils.CpuUtils;\nimport io.github.muntashirakon.AppManager.utils.NotificationUtils;\nimport io.github.muntashirakon.io.Path;\n\npublic class ProfileApplierService extends ForegroundService {\n    private static final String EXTRA_QUEUE_ITEM = \"queue_item\";\n    private static final String EXTRA_NOTIFY = \"notify\";\n    /**\n     * Notification channel ID\n     */\n    private static final String CHANNEL_ID = BuildConfig.APPLICATION_ID + \".channel.PROFILE_APPLIER\";\n\n    @NonNull\n    public static Intent getIntent(@NonNull Context context, @NonNull ProfileQueueItem queueItem, boolean notify) {\n        Intent intent = new Intent(context, ProfileApplierService.class);\n        IntentCompat.putWrappedParcelableExtra(intent, EXTRA_QUEUE_ITEM, queueItem);\n        intent.putExtra(EXTRA_NOTIFY, notify);\n        return intent;\n    }\n\n    private QueuedProgressHandler mProgressHandler;\n    private NotificationProgressHandler.NotificationInfo mNotificationInfo;\n    private PowerManager.WakeLock mWakeLock;\n\n    public ProfileApplierService() {\n        super(\"ProfileApplierService\");\n    }\n\n    @Override\n    public void onCreate() {\n        super.onCreate();\n        mWakeLock = CpuUtils.getPartialWakeLock(\"profile_applier\");\n        mWakeLock.acquire();\n    }\n\n    @Override\n    public int onStartCommand(@Nullable Intent intent, int flags, int startId) {\n        if (isWorking()) return super.onStartCommand(intent, flags, startId);\n        NotificationManagerInfo notificationManagerInfo = new NotificationManagerInfo(CHANNEL_ID,\n                \"Profile Applier\", NotificationManagerCompat.IMPORTANCE_LOW);\n        mProgressHandler = new NotificationProgressHandler(this,\n                notificationManagerInfo,\n                NotificationUtils.HIGH_PRIORITY_NOTIFICATION_INFO,\n                NotificationUtils.HIGH_PRIORITY_NOTIFICATION_INFO);\n        mProgressHandler.setProgressTextInterface(ProgressHandler.PROGRESS_REGULAR);\n        mNotificationInfo = new NotificationProgressHandler.NotificationInfo()\n                .setBody(getString(R.string.operation_running))\n                .setOperationName(getText(R.string.profiles));\n        mProgressHandler.onAttach(this, mNotificationInfo);\n        return super.onStartCommand(intent, flags, startId);\n    }\n\n    @Override\n    protected void onHandleIntent(@Nullable Intent intent) {\n        ProfileQueueItem item = getQueueItem(intent);\n        if (item == null) {\n            return;\n        }\n        boolean notify = intent.getBooleanExtra(EXTRA_NOTIFY, true);\n        Path tempProfilePath = item.getTempProfilePath();\n        try {\n            ProfileManager profileManager = new ProfileManager(item.getProfileId(), tempProfilePath);\n            profileManager.applyProfile(item.getState(), mProgressHandler);\n            profileManager.conclude();\n            OpHistoryManager.addHistoryItem(HISTORY_TYPE_PROFILE, item, true);\n            sendNotification(item.getProfileName(), Activity.RESULT_OK, notify, profileManager.requiresRestart());\n        } catch (IOException e) {\n            sendNotification(item.getProfileName(), Activity.RESULT_CANCELED, notify, false);\n        } finally {\n            if (tempProfilePath != null) {\n                tempProfilePath.delete();\n            }\n        }\n    }\n\n    @Override\n    protected void onQueued(@Nullable Intent intent) {\n        ProfileQueueItem item = getQueueItem(intent);\n        if (item == null) {\n            return;\n        }\n        Object notificationInfo = new NotificationProgressHandler.NotificationInfo()\n                .setAutoCancel(true)\n                .setTime(System.currentTimeMillis())\n                .setOperationName(getText(R.string.profiles))\n                .setTitle(item.getProfileName())\n                .setBody(getString(R.string.added_to_queue));\n        mProgressHandler.onQueue(notificationInfo);\n    }\n\n    @Override\n    protected void onStartIntent(@Nullable Intent intent) {\n        ProfileQueueItem item = getQueueItem(intent);\n        if (item != null) {\n            Intent notificationIntent = ProfileManager.getProfileIntent(this, item.getProfileType(), item.getProfileId());\n            PendingIntent pendingIntent = PendingIntentCompat.getActivity(this, 0, notificationIntent,\n                    0, false);\n            mNotificationInfo.setDefaultAction(pendingIntent);\n        }\n        // Set profile name in the ongoing notification\n        mNotificationInfo.setTitle(item != null ? item.getProfileName() : null);\n        mProgressHandler.onProgressStart(-1, 0, mNotificationInfo);\n    }\n\n    @Override\n    public void onDestroy() {\n        ServiceCompat.stopForeground(this, ServiceCompat.STOP_FOREGROUND_REMOVE);\n        if (mProgressHandler != null) {\n            mProgressHandler.onDetach(this);\n        }\n        CpuUtils.releaseWakeLock(mWakeLock);\n        super.onDestroy();\n    }\n\n    @Nullable\n    private ProfileQueueItem getQueueItem(@Nullable Intent intent) {\n        if (intent == null) {\n            return null;\n        }\n        return IntentCompat.getUnwrappedParcelableExtra(intent, EXTRA_QUEUE_ITEM, ProfileQueueItem.class);\n    }\n\n    private void sendNotification(@NonNull String profileName, int result, boolean notify,\n                                  boolean requiresRestart) {\n        NotificationProgressHandler.NotificationInfo notificationInfo = new NotificationProgressHandler\n                .NotificationInfo()\n                .setAutoCancel(true)\n                .setTime(System.currentTimeMillis())\n                .setOperationName(getText(R.string.profiles))\n                .setTitle(profileName);\n        switch (result) {\n            case Activity.RESULT_CANCELED:  // Failure\n                notificationInfo.setBody(getString(R.string.error));\n                break;\n            case Activity.RESULT_OK:  // Successful\n                notificationInfo.setBody(getString(R.string.the_operation_was_successful));\n        }\n        if (requiresRestart) {\n            Intent intent = new Intent(this, BatchOpsResultsActivity.class);\n            intent.putExtra(BatchOpsService.EXTRA_REQUIRES_RESTART, true);\n            PendingIntent pendingIntent = PendingIntentCompat.getActivity(this, 0, intent,\n                    PendingIntent.FLAG_ONE_SHOT, false);\n            notificationInfo.addAction(0, getString(R.string.restart_device), pendingIntent);\n        }\n        mProgressHandler.onResult(notify ? notificationInfo : null);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/profiles/ProfileLogger.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.profiles;\n\nimport androidx.annotation.NonNull;\n\nimport java.io.File;\nimport java.io.IOException;\n\nimport io.github.muntashirakon.AppManager.logs.Logger;\nimport io.github.muntashirakon.io.Paths;\n\npublic class ProfileLogger extends Logger {\n    @NonNull\n    public static File getLogFile(@NonNull String profileId) {\n        return new File(getLoggingDirectory(), \"profile_\" + profileId + \".log\");\n    }\n\n    public ProfileLogger(@NonNull String profileId) throws IOException {\n        super(getLogFile(profileId), true);\n    }\n\n    @NonNull\n    public static String getAllLogs(@NonNull String profileId) {\n        return Paths.get(getLogFile(profileId)).getContentAsString();\n    }\n\n    public static void clearLogs(@NonNull String profileId) {\n        getLogFile(profileId).delete();\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/profiles/ProfileManager.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.profiles;\n\nimport android.annotation.SuppressLint;\nimport android.content.Context;\nimport android.content.Intent;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport org.json.JSONException;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Objects;\nimport java.util.UUID;\n\nimport io.github.muntashirakon.AppManager.profiles.struct.BaseProfile;\nimport io.github.muntashirakon.AppManager.profiles.struct.ProfileApplierResult;\nimport io.github.muntashirakon.AppManager.progress.ProgressHandler;\nimport io.github.muntashirakon.AppManager.utils.ContextUtils;\nimport io.github.muntashirakon.AppManager.utils.ThreadUtils;\nimport io.github.muntashirakon.io.Path;\nimport io.github.muntashirakon.io.Paths;\n\npublic class ProfileManager {\n    public static final String TAG = \"ProfileManager\";\n\n    public static final String PROFILE_EXT = \".am.json\";\n\n    @NonNull\n    public static Intent getProfileIntent(@NonNull Context context, @BaseProfile.ProfileType int type, @NonNull String profileId) {\n        if (type == BaseProfile.PROFILE_TYPE_APPS) {\n            return AppsProfileActivity.getProfileIntent(context, profileId);\n        } else if (type == BaseProfile.PROFILE_TYPE_APPS_FILTER) {\n            return AppsFilterProfileActivity.getProfileIntent(context, profileId);\n        } else throw new UnsupportedOperationException(\"Invalid type: \" + type);\n    }\n\n    @NonNull\n    public static Intent getNewProfileIntent(@NonNull Context context, @BaseProfile.ProfileType int type, @NonNull String profileName) {\n        if (type == BaseProfile.PROFILE_TYPE_APPS) {\n            return AppsProfileActivity.getNewProfileIntent(context, profileName);\n        } else if (type == BaseProfile.PROFILE_TYPE_APPS_FILTER) {\n            return AppsFilterProfileActivity.getNewProfileIntent(context, profileName);\n        } else throw new UnsupportedOperationException(\"Invalid type: \" + type);\n    }\n\n    @NonNull\n    public static Intent getCloneProfileIntent(@NonNull Context context,\n                                               @BaseProfile.ProfileType int type,\n                                               @NonNull String oldProfileId,\n                                               @NonNull String newProfileName) {\n        if (type == BaseProfile.PROFILE_TYPE_APPS) {\n            return AppsProfileActivity.getCloneProfileIntent(context,\n                    oldProfileId, newProfileName);\n        } else if (type == BaseProfile.PROFILE_TYPE_APPS_FILTER) {\n            return AppsFilterProfileActivity.getCloneProfileIntent(context,\n                    oldProfileId, newProfileName);\n        } else throw new UnsupportedOperationException(\"Invalid type: \" + type);\n    }\n\n    @NonNull\n    public static Path getProfilesDir() {\n        Context context = ContextUtils.getContext();\n        return Objects.requireNonNull(Paths.build(context.getFilesDir(), \"profiles\"));\n    }\n\n    @Nullable\n    public static Path findProfilePathById(@NonNull String profileId) {\n        return Paths.build(getProfilesDir(), profileId + PROFILE_EXT);\n    }\n\n    @NonNull\n    public static Path requireProfilePathById(@NonNull String profileId) throws IOException {\n        Path profilesDir = getProfilesDir();\n        if (!profilesDir.exists()) {\n            profilesDir.mkdirs();\n        }\n        return getProfilesDir().findOrCreateFile(profileId + PROFILE_EXT, null);\n    }\n\n    public static boolean deleteProfile(@NonNull String profileId) {\n        Path profilePath = findProfilePathById(profileId);\n        return profilePath == null || !profilePath.exists() || profilePath.delete();\n    }\n\n    @NonNull\n    public static String getProfileName(@NonNull String filename) {\n        int index = filename.indexOf(PROFILE_EXT);\n        if (index == -1) {\n            // Maybe only ends with .json\n            index = filename.indexOf(\".json\");\n        }\n        return index != -1 ? filename.substring(0, index) : filename;\n    }\n\n    @NonNull\n    public static ArrayList<String> getProfileNames() {\n        Path profilesPath = getProfilesDir();\n        String[] profilesFiles = profilesPath.listFileNames((dir, name) -> name.endsWith(PROFILE_EXT));\n        ArrayList<String> profileNames = new ArrayList<>(profilesFiles.length);\n        for (String profile : profilesFiles) {\n            profileNames.add(getProfileName(profile));\n        }\n        return profileNames;\n    }\n\n    @NonNull\n    public static HashMap<BaseProfile, CharSequence> getProfileSummaries(@NonNull Context context) throws IOException, JSONException {\n        Path profilesPath = getProfilesDir();\n        Path[] profilePaths = profilesPath.listFiles((dir, name) -> name.endsWith(PROFILE_EXT));\n        HashMap<BaseProfile, CharSequence> profiles = new HashMap<>(profilePaths.length);\n        for (Path profilePath : profilePaths) {\n            if (ThreadUtils.isInterrupted()) {\n                // Thread interrupted, return as is\n                return profiles;\n            }\n            BaseProfile profile = BaseProfile.fromPath(profilePath);\n            profiles.put(profile, profile.toLocalizedString(context));\n        }\n        return profiles;\n    }\n\n    @NonNull\n    public static <T> List<T> getProfiles(int type) throws IOException, JSONException {\n        Path profilesPath = getProfilesDir();\n        Path[] profilePaths = profilesPath.listFiles((dir, name) -> name.endsWith(PROFILE_EXT));\n        List<T> profiles = new ArrayList<>(profilePaths.length);\n        for (Path profilePath : profilePaths) {\n            BaseProfile profile = BaseProfile.fromPath(profilePath);\n            if (profile.type == type) {\n                profiles.add((T) profile);\n            }\n        }\n        return profiles;\n    }\n\n    @NonNull\n    public static List<BaseProfile> getProfiles() throws IOException, JSONException {\n        Path profilesPath = getProfilesDir();\n        Path[] profilePaths = profilesPath.listFiles((dir, name) -> name.endsWith(PROFILE_EXT));\n        List<BaseProfile> profiles = new ArrayList<>(profilePaths.length);\n        for (Path profilePath : profilePaths) {\n            profiles.add(BaseProfile.fromPath(profilePath));\n        }\n        return profiles;\n    }\n\n    @NonNull\n    public static String getProfileIdCompat(@NonNull String profileName) {\n        String profileId = Paths.sanitizeFilename(profileName, \"_\", Paths.SANITIZE_FLAG_SPACE\n                | Paths.SANITIZE_FLAG_UNIX_ILLEGAL_CHARS | Paths.SANITIZE_FLAG_UNIX_RESERVED\n                | Paths.SANITIZE_FLAG_FAT_ILLEGAL_CHARS);\n        return profileId != null ? profileId : UUID.randomUUID().toString();\n    }\n\n    @NonNull\n    private final BaseProfile mProfile;\n    @Nullable\n    private ProfileLogger mLogger;\n    private boolean mRequiresRestart;\n\n    public ProfileManager(@NonNull String profileId, @Nullable Path profilePath) throws IOException {\n        try {\n            mLogger = new ProfileLogger(profileId);\n        } catch (IOException e) {\n            e.printStackTrace();\n        }\n        try {\n            Path realProfilePath = profilePath != null ? profilePath : findProfilePathById(profileId);\n            mProfile = BaseProfile.fromPath(realProfilePath);\n        } catch (IOException e) {\n            if (mLogger != null) {\n                mLogger.println(null, e);\n            }\n            throw e;\n        } catch (JSONException e) {\n            if (mLogger != null) {\n                mLogger.println(null, e);\n            }\n            throw new IOException(e);\n        }\n    }\n\n    public boolean requiresRestart() {\n        return mRequiresRestart;\n    }\n\n    @SuppressLint(\"SwitchIntDef\")\n    public void applyProfile(@Nullable String state, @Nullable ProgressHandler progressHandler) {\n        // Set state\n        if (state == null) state = mProfile.state;\n        log(\"====> Started execution with state \" + state);\n        ProfileApplierResult result = mProfile.apply(state, mLogger, progressHandler);\n        mRequiresRestart = result.requiresRestart();\n        log(\"====> Execution completed.\");\n    }\n\n    public void conclude() {\n        if (mLogger != null) {\n            mLogger.close();\n        }\n    }\n\n    private void log(@Nullable String message) {\n        if (mLogger != null) {\n            mLogger.println(message);\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/profiles/ProfileQueueItem.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.profiles;\n\nimport android.net.Uri;\nimport android.os.Parcel;\nimport android.os.Parcelable;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.core.os.ParcelCompat;\n\nimport org.json.JSONException;\nimport org.json.JSONObject;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.nio.charset.StandardCharsets;\nimport java.util.Objects;\n\nimport io.github.muntashirakon.AppManager.history.IJsonSerializer;\nimport io.github.muntashirakon.AppManager.history.JsonDeserializer;\nimport io.github.muntashirakon.AppManager.profiles.ProfileApplierActivity.ProfileApplierInfo;\nimport io.github.muntashirakon.AppManager.profiles.struct.BaseProfile;\nimport io.github.muntashirakon.AppManager.self.filecache.FileCache;\nimport io.github.muntashirakon.AppManager.utils.JSONUtils;\nimport io.github.muntashirakon.io.Path;\nimport io.github.muntashirakon.io.Paths;\n\npublic class ProfileQueueItem implements Parcelable, IJsonSerializer {\n    @NonNull\n    public static ProfileQueueItem fromProfiledApplierInfo(@NonNull ProfileApplierInfo info) {\n        return new ProfileQueueItem(info.profile, info.state);\n    }\n\n    @NonNull\n    private final String mProfileId;\n    @BaseProfile.ProfileType\n    private final int mProfileType;\n    @NonNull\n    private final String mProfileName;\n    @Nullable\n    private final String mState;\n    @Nullable\n    private final Path mTempProfilePath;\n\n    private ProfileQueueItem(@NonNull BaseProfile profile, @Nullable String state) {\n        mProfileId = profile.profileId;\n        mProfileType = profile.type;\n        mProfileName = profile.name;\n        mState = state;\n        mTempProfilePath = null;\n    }\n\n    protected ProfileQueueItem(@NonNull Parcel in) {\n        mProfileId = Objects.requireNonNull(in.readString());\n        mProfileType = in.readInt();\n        mProfileName = Objects.requireNonNull(in.readString());\n        mState = in.readString();\n        Uri uri = ParcelCompat.readParcelable(in, Uri.class.getClassLoader(), Uri.class);\n        mTempProfilePath = uri != null ? Paths.get(uri) : null;\n    }\n\n    @NonNull\n    public String getProfileId() {\n        return mProfileId;\n    }\n\n    @BaseProfile.ProfileType\n    public int getProfileType() {\n        return mProfileType;\n    }\n\n    @NonNull\n    public String getProfileName() {\n        return mProfileName;\n    }\n\n    @Nullable\n    public String getState() {\n        return mState;\n    }\n\n    @Nullable\n    public Path getTempProfilePath() {\n        return mTempProfilePath;\n    }\n\n    @Override\n    public int describeContents() {\n        return 0;\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        dest.writeString(mProfileId);\n        dest.writeInt(mProfileType);\n        dest.writeString(mProfileName);\n        dest.writeString(mState);\n        dest.writeParcelable(mTempProfilePath != null ? mTempProfilePath.getUri() : null, flags);\n    }\n\n    protected ProfileQueueItem(@NonNull JSONObject jsonObject) throws JSONException {\n        mProfileId = jsonObject.getString(\"profile_id\");\n        mProfileType = jsonObject.optInt(\"profile_type\", BaseProfile.PROFILE_TYPE_APPS);\n        mProfileName = jsonObject.getString(\"profile_name\");\n        mState = JSONUtils.getString(jsonObject, \"state\");\n        JSONObject profile = jsonObject.optJSONObject(\"profile\");\n        File profilePath = null;\n        if (profile != null) {\n            try (InputStream is = new ByteArrayInputStream(profile.toString().getBytes(StandardCharsets.UTF_8))) {\n                profilePath = FileCache.getGlobalFileCache().getCachedFile(is, ProfileManager.PROFILE_EXT);\n            } catch (IOException e) {\n                //noinspection UnnecessaryInitCause\n                throw (JSONException) new JSONException(e.getMessage()).initCause(e);\n            }\n        }\n        mTempProfilePath = profilePath != null ? Paths.get(profilePath) : null;\n    }\n\n    @NonNull\n    @Override\n    public JSONObject serializeToJson() throws JSONException {\n        JSONObject jsonObject = new JSONObject();\n        jsonObject.put(\"profile_id\", mProfileId);\n        jsonObject.put(\"profile_type\", mProfileType);\n        jsonObject.put(\"profile_name\", mProfileName);\n        jsonObject.put(\"state\", mState);\n        // A profile can be altered any time. So, we need to store a snapshot of the profile\n        try {\n            BaseProfile profile = BaseProfile.fromPath(ProfileManager.findProfilePathById(mProfileId));\n            jsonObject.put(\"profile\", profile.serializeToJson());\n        } catch (IOException e) {\n            //noinspection UnnecessaryInitCause\n            throw (JSONException) new JSONException(e.getMessage()).initCause(e);\n        }\n        return jsonObject;\n    }\n\n    public static final JsonDeserializer.Creator<ProfileQueueItem> DESERIALIZER = ProfileQueueItem::new;\n\n    public static final Creator<ProfileQueueItem> CREATOR = new Creator<ProfileQueueItem>() {\n        @NonNull\n        @Override\n        public ProfileQueueItem createFromParcel(@NonNull Parcel in) {\n            return new ProfileQueueItem(in);\n        }\n\n        @NonNull\n        @Override\n        public ProfileQueueItem[] newArray(int size) {\n            return new ProfileQueueItem[size];\n        }\n    };\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/profiles/ProfileShortcutInfo.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.profiles;\n\nimport android.content.Context;\nimport android.content.Intent;\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport io.github.muntashirakon.AppManager.shortcut.ShortcutInfo;\n\npublic class ProfileShortcutInfo extends ShortcutInfo {\n    public final String profileId;\n    @ProfileApplierActivity.ShortcutType\n    public final String shortcutType;\n\n    public ProfileShortcutInfo(@NonNull String profileId, @NonNull String profileName,\n                               @ProfileApplierActivity.ShortcutType String shortcutType,\n                               @Nullable CharSequence readableShortcutType) {\n        this.profileId = profileId;\n        this.shortcutType = shortcutType;\n        setName(profileName + \" - \" + (readableShortcutType != null ? readableShortcutType : shortcutType));\n    }\n\n    protected ProfileShortcutInfo(Parcel in) {\n        super(in);\n        profileId = in.readString();\n        shortcutType = in.readString();\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        super.writeToParcel(dest, flags);\n        dest.writeString(profileId);\n        dest.writeString(shortcutType);\n    }\n\n    @Override\n    public Intent toShortcutIntent(@NonNull Context context) {\n        Intent intent = ProfileApplierActivity.getShortcutIntent(context, profileId, shortcutType, null);\n        intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP);\n        return intent;\n    }\n\n    public static final Creator<ProfileShortcutInfo> CREATOR = new Creator<ProfileShortcutInfo>() {\n        @Override\n        public ProfileShortcutInfo createFromParcel(Parcel source) {\n            return new ProfileShortcutInfo(source);\n        }\n\n        @Override\n        public ProfileShortcutInfo[] newArray(int size) {\n            return new ProfileShortcutInfo[size];\n        }\n    };\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/profiles/ProfilesActivity.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.profiles;\n\nimport static io.github.muntashirakon.AppManager.profiles.ProfileApplierActivity.ST_ADVANCED;\nimport static io.github.muntashirakon.AppManager.profiles.ProfileApplierActivity.ST_SIMPLE;\n\nimport android.content.Intent;\nimport android.graphics.drawable.Drawable;\nimport android.os.Bundle;\nimport android.text.TextUtils;\nimport android.view.LayoutInflater;\nimport android.view.Menu;\nimport android.view.MenuItem;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.Filter;\nimport android.widget.Filterable;\nimport android.widget.TextView;\n\nimport androidx.activity.result.ActivityResultLauncher;\nimport androidx.activity.result.contract.ActivityResultContracts;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.appcompat.widget.PopupMenu;\nimport androidx.core.content.ContextCompat;\nimport androidx.lifecycle.ViewModelProvider;\n\nimport com.google.android.material.dialog.MaterialAlertDialogBuilder;\nimport com.google.android.material.floatingactionbutton.FloatingActionButton;\nimport com.google.android.material.progressindicator.LinearProgressIndicator;\n\nimport org.json.JSONException;\n\nimport java.io.IOException;\nimport java.io.OutputStream;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Objects;\n\nimport io.github.muntashirakon.AppManager.BaseActivity;\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.logs.Log;\nimport io.github.muntashirakon.AppManager.profiles.struct.BaseProfile;\nimport io.github.muntashirakon.AppManager.shortcut.CreateShortcutDialogFragment;\nimport io.github.muntashirakon.AppManager.utils.UIUtils;\nimport io.github.muntashirakon.AppManager.utils.Utils;\nimport io.github.muntashirakon.AppManager.utils.appearance.ColorCodes;\nimport io.github.muntashirakon.dialog.SearchableSingleChoiceDialogBuilder;\nimport io.github.muntashirakon.dialog.TextInputDialogBuilder;\nimport io.github.muntashirakon.io.Path;\nimport io.github.muntashirakon.io.Paths;\nimport io.github.muntashirakon.util.AdapterUtils;\nimport io.github.muntashirakon.util.UiUtils;\nimport io.github.muntashirakon.widget.RecyclerView;\n\npublic class ProfilesActivity extends BaseActivity implements NewProfileDialogFragment.OnCreateNewProfileInterface {\n    private static final String TAG = \"ProfilesActivity\";\n\n    private ProfilesAdapter mAdapter;\n    private ProfilesViewModel mModel;\n    private LinearProgressIndicator mProgressIndicator;\n    @Nullable\n    private String mProfileId;\n\n    private final ActivityResultLauncher<String> mExportProfile = registerForActivityResult(\n            new ActivityResultContracts.CreateDocument(\"application/json\"),\n            uri -> {\n                if (uri == null) {\n                    // Back button pressed.\n                    return;\n                }\n                if (mProfileId != null) {\n                    // Export profile\n                    try (OutputStream os = getContentResolver().openOutputStream(uri)) {\n                        if (os == null) {\n                            return;\n                        }\n                        Path profilePath = ProfileManager.findProfilePathById(mProfileId);\n                        BaseProfile profile = BaseProfile.fromPath(profilePath);\n                        profile.write(os);\n                        UIUtils.displayShortToast(R.string.the_export_was_successful);\n                    } catch (IOException | JSONException e) {\n                        Log.e(TAG, \"Error: \", e);\n                        UIUtils.displayShortToast(R.string.export_failed);\n                    }\n                }\n            });\n    private final ActivityResultLauncher<String> mImportProfile = registerForActivityResult(\n            new ActivityResultContracts.GetContent(),\n            uri -> {\n                if (uri == null) {\n                    // Back button pressed.\n                    return;\n                }\n                try {\n                    // Verify\n                    Path profilePath = Paths.get(uri);\n                    BaseProfile profile = BaseProfile.fromPath(profilePath);\n                    BaseProfile newProfile = BaseProfile.newProfile(profile.name, profile.type, profile);\n                    Path innerProfilePath = ProfileManager.requireProfilePathById(newProfile.profileId);\n                    // Save\n                    try (OutputStream os = innerProfilePath.openOutputStream()) {\n                        newProfile.write(os);\n                    }\n                    UIUtils.displayShortToast(R.string.the_import_was_successful);\n                    // Load imported profile\n                    startActivity(ProfileManager.getProfileIntent(this, newProfile.type, newProfile.profileId));\n                } catch (IOException | JSONException e) {\n                    Log.e(TAG, \"Error: \", e);\n                    UIUtils.displayShortToast(R.string.import_failed);\n                }\n            });\n\n    @Override\n    protected void onAuthenticated(@Nullable Bundle savedInstanceState) {\n        setContentView(R.layout.activity_profiles);\n        setSupportActionBar(findViewById(R.id.toolbar));\n        mModel = new ViewModelProvider(this).get(ProfilesViewModel.class);\n        mProgressIndicator = findViewById(R.id.progress_linear);\n        mProgressIndicator.setVisibilityAfterHide(View.GONE);\n        RecyclerView listView = findViewById(android.R.id.list);\n        listView.setLayoutManager(UIUtils.getGridLayoutAt450Dp(this));\n        listView.setEmptyView(findViewById(android.R.id.empty));\n        UiUtils.applyWindowInsetsAsPaddingNoTop(listView);\n        mAdapter = new ProfilesAdapter(this);\n        listView.setAdapter(mAdapter);\n        FloatingActionButton fab = findViewById(R.id.floatingActionButton);\n        UiUtils.applyWindowInsetsAsMargin(fab);\n        fab.setOnClickListener(v -> {\n            NewProfileDialogFragment dialog = NewProfileDialogFragment.getInstance(this);\n            dialog.show(getSupportFragmentManager(), NewProfileDialogFragment.TAG);\n        });\n        mModel.getProfilesLiveData().observe(this, profiles -> {\n            mProgressIndicator.hide();\n            mAdapter.setDefaultList(profiles);\n        });\n        mProgressIndicator.show();\n        mModel.loadProfiles();\n    }\n\n    @Override\n    public boolean onCreateOptionsMenu(Menu menu) {\n        getMenuInflater().inflate(R.menu.activity_profiles_actions, menu);\n        return super.onCreateOptionsMenu(menu);\n    }\n\n    @Override\n    public boolean onOptionsItemSelected(@NonNull MenuItem item) {\n        int id = item.getItemId();\n        if (id == android.R.id.home) {\n            finish();\n        } else if (id == R.id.action_import) {\n            mImportProfile.launch(\"application/json\");\n        } else if (id == R.id.action_refresh) {\n            mProgressIndicator.show();\n            mModel.loadProfiles();\n        } else return super.onOptionsItemSelected(item);\n        return true;\n    }\n\n    @Override\n    public void onCreateNewProfile(@NonNull String newProfileName, int type) {\n        Intent intent = ProfileManager.getNewProfileIntent(this, type, newProfileName);\n        startActivity(intent);\n    }\n\n    static class ProfilesAdapter extends RecyclerView.Adapter<ProfilesAdapter.ViewHolder> implements Filterable {\n        private Filter mFilter;\n        private String mConstraint;\n        private BaseProfile[] mDefaultList;\n        private BaseProfile[] mAdapterList;\n        private HashMap<BaseProfile, CharSequence> mAdapterMap;\n        private final ProfilesActivity mActivity;\n        private final int mQueryStringHighlightColor;\n\n        static class ViewHolder extends RecyclerView.ViewHolder {\n            TextView title;\n            TextView summary;\n\n            public ViewHolder(@NonNull View itemView) {\n                super(itemView);\n                title = itemView.findViewById(android.R.id.title);\n                summary = itemView.findViewById(android.R.id.summary);\n                itemView.findViewById(R.id.icon_frame).setVisibility(View.GONE);\n            }\n        }\n\n        ProfilesAdapter(@NonNull ProfilesActivity activity) {\n            mActivity = activity;\n            mQueryStringHighlightColor = ColorCodes.getQueryStringHighlightColor(activity);\n        }\n\n        void setDefaultList(@NonNull HashMap<BaseProfile, CharSequence> list) {\n            mDefaultList = list.keySet().toArray(new BaseProfile[0]);\n            int previousCount = getItemCount();\n            mAdapterList = mDefaultList;\n            mAdapterMap = list;\n            AdapterUtils.notifyDataSetChanged(this, previousCount, mAdapterList.length);\n        }\n\n        @Override\n        public int getItemCount() {\n            return mAdapterList == null ? 0 : mAdapterList.length;\n        }\n\n        @Override\n        public long getItemId(int position) {\n            return mAdapterList[position].hashCode();\n        }\n\n        @NonNull\n        @Override\n        public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {\n            View view = LayoutInflater.from(parent.getContext()).inflate(io.github.muntashirakon.ui.R.layout.m3_preference, parent, false);\n            return new ViewHolder(view);\n        }\n\n        @Override\n        public void onBindViewHolder(@NonNull ViewHolder holder, int position) {\n            BaseProfile profile = mAdapterList[position];\n            if (mConstraint != null && profile.name.toLowerCase(Locale.ROOT).contains(mConstraint)) {\n                // Highlight searched query\n                holder.title.setText(UIUtils.getHighlightedText(profile.name, mConstraint, mQueryStringHighlightColor));\n            } else {\n                holder.title.setText(profile.name);\n            }\n            CharSequence value = mAdapterMap.get(profile);\n            holder.summary.setText(value != null ? value : \"\");\n            holder.itemView.setOnClickListener(v -> {\n                Intent intent = ProfileManager.getProfileIntent(mActivity, profile.type, profile.profileId);\n                mActivity.startActivity(intent);\n            });\n            holder.itemView.setOnLongClickListener(v -> {\n                PopupMenu popupMenu = new PopupMenu(mActivity, v);\n                popupMenu.setForceShowIcon(true);\n                popupMenu.inflate(R.menu.activity_profiles_popup_actions);\n                popupMenu.setOnMenuItemClickListener(item -> {\n                    int id = item.getItemId();\n                    if (id == R.id.action_apply) {\n                        Intent intent = ProfileApplierActivity.getApplierIntent(mActivity, profile.profileId);\n                        mActivity.startActivity(intent);\n                    } else if (id == R.id.action_delete) {\n                        new MaterialAlertDialogBuilder(mActivity)\n                                .setTitle(mActivity.getString(R.string.delete_filename, profile.name))\n                                .setMessage(R.string.are_you_sure)\n                                .setPositiveButton(R.string.cancel, null)\n                                .setNegativeButton(R.string.ok, (dialog, which) -> {\n                                    if (ProfileManager.deleteProfile(profile.profileId)) {\n                                        UIUtils.displayShortToast(R.string.deleted_successfully);\n                                    } else {\n                                        UIUtils.displayShortToast(R.string.deletion_failed);\n                                    }\n                                })\n                                .show();\n                    } else if (id == R.id.action_routine_ops) {\n                        // TODO(7/11/20): Setup routine operations for this profile\n                        UIUtils.displayShortToast(\"Not yet implemented\");\n                    } else if (id == R.id.action_duplicate) {\n                        new TextInputDialogBuilder(mActivity, R.string.input_profile_name)\n                                .setTitle(R.string.new_profile)\n                                .setHelperText(R.string.input_profile_name_description)\n                                .setNegativeButton(R.string.cancel, null)\n                                .setPositiveButton(R.string.go, (dialog, which, newProfName, isChecked) -> {\n                                    if (!TextUtils.isEmpty(newProfName)) {\n                                        Intent intent = ProfileManager.getCloneProfileIntent(\n                                                mActivity, profile.type, profile.profileId,\n                                                newProfName.toString());\n                                        mActivity.startActivity(intent);\n                                    }\n                                })\n                                .show();\n                    } else if (id == R.id.action_export) {\n                        mActivity.mProfileId = profile.profileId;\n                        mActivity.mExportProfile.launch(profile.name + \".am.json\");\n                    } else if (id == R.id.action_copy) {\n                        Utils.copyToClipboard(mActivity, profile.name, profile.profileId);\n                    } else if (id == R.id.action_shortcut) {\n                        final String[] shortcutTypesL = new String[]{\n                                mActivity.getString(R.string.simple),\n                                mActivity.getString(R.string.advanced)\n                        };\n                        final String[] shortcutTypes = new String[]{ST_SIMPLE, ST_ADVANCED};\n                        new SearchableSingleChoiceDialogBuilder<>(mActivity, shortcutTypes, shortcutTypesL)\n                                .setTitle(R.string.create_shortcut)\n                                .setOnSingleChoiceClickListener((dialog, which, item1, isChecked) -> {\n                                    if (!isChecked) {\n                                        return;\n                                    }\n                                    Drawable icon = Objects.requireNonNull(ContextCompat.getDrawable(mActivity, R.drawable.ic_launcher_foreground));\n                                    ProfileShortcutInfo shortcutInfo = new ProfileShortcutInfo(profile.profileId,\n                                            profile.name, shortcutTypes[which], shortcutTypesL[which]);\n                                    shortcutInfo.setIcon(UIUtils.getBitmapFromDrawable(icon));\n                                    CreateShortcutDialogFragment dialog1 = CreateShortcutDialogFragment.getInstance(shortcutInfo);\n                                    dialog1.show(mActivity.getSupportFragmentManager(), CreateShortcutDialogFragment.TAG);\n                                    dialog.dismiss();\n                                })\n                                .show();\n                    } else return false;\n                    return true;\n                });\n                popupMenu.show();\n                return true;\n            });\n        }\n\n        @Override\n        public Filter getFilter() {\n            if (mFilter == null)\n                mFilter = new Filter() {\n                    @Override\n                    protected FilterResults performFiltering(CharSequence charSequence) {\n                        String constraint = charSequence.toString().toLowerCase(Locale.ROOT);\n                        mConstraint = constraint;\n                        FilterResults filterResults = new FilterResults();\n                        if (constraint.isEmpty()) {\n                            filterResults.count = 0;\n                            filterResults.values = null;\n                            return filterResults;\n                        }\n\n                        List<BaseProfile> list = new ArrayList<>(mDefaultList.length);\n                        for (BaseProfile item : mDefaultList) {\n                            if (item.name.toLowerCase(Locale.ROOT).contains(constraint))\n                                list.add(item);\n                        }\n\n                        filterResults.count = list.size();\n                        filterResults.values = list.toArray(new BaseProfile[0]);\n                        return filterResults;\n                    }\n\n                    @Override\n                    protected void publishResults(CharSequence charSequence, FilterResults filterResults) {\n                        int previousCount = mAdapterList != null ? mAdapterList.length : 0;\n                        if (filterResults.values == null) {\n                            mAdapterList = mDefaultList;\n                        } else {\n                            mAdapterList = (BaseProfile[]) filterResults.values;\n                        }\n                        AdapterUtils.notifyDataSetChanged(ProfilesAdapter.this, previousCount, mAdapterList.length);\n                    }\n                };\n            return mFilter;\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/profiles/ProfilesViewModel.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.profiles;\n\nimport android.app.Application;\nimport android.os.FileObserver;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.lifecycle.AndroidViewModel;\nimport androidx.lifecycle.LiveData;\nimport androidx.lifecycle.MutableLiveData;\n\nimport org.json.JSONException;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.util.HashMap;\nimport java.util.concurrent.Future;\n\nimport io.github.muntashirakon.AppManager.profiles.struct.BaseProfile;\nimport io.github.muntashirakon.AppManager.utils.ThreadUtils;\n\npublic class ProfilesViewModel extends AndroidViewModel {\n    private final MutableLiveData<HashMap<BaseProfile, CharSequence>> mProfilesLiveData = new MutableLiveData<>();\n    private Future<?> mProfileResult;\n    private FileObserver mFileObserver;\n\n    public ProfilesViewModel(@NonNull Application application) {\n        super(application);\n    }\n\n    @Override\n    protected void onCleared() {\n        if (mFileObserver != null) {\n            mFileObserver.stopWatching();\n        }\n        super.onCleared();\n    }\n\n    public LiveData<HashMap<BaseProfile, CharSequence>> getProfilesLiveData() {\n        return mProfilesLiveData;\n    }\n\n    public void loadProfiles() {\n        if (mProfileResult != null) {\n            mProfileResult.cancel(true);\n        }\n        mProfileResult = ThreadUtils.postOnBackgroundThread(() -> {\n            synchronized (mProfilesLiveData) {\n                try {\n                    HashMap<BaseProfile, CharSequence> profiles = ProfileManager.getProfileSummaries(getApplication());\n                    setUpObserverAndStart();\n                    mProfilesLiveData.postValue(profiles);\n                } catch (IOException | JSONException e) {\n                    e.printStackTrace();\n                }\n            }\n        });\n    }\n\n    private void setUpObserverAndStart() {\n        if (mFileObserver != null) {\n            mFileObserver.startWatching();\n            return;\n        }\n        File profilePath = ProfileManager.getProfilesDir().getFile();\n        if (profilePath != null && !profilePath.exists()) {\n            // Do not set up observer yet\n            return;\n        }\n        int mask = FileObserver.CREATE\n                | FileObserver.DELETE\n                | FileObserver.DELETE_SELF\n                | FileObserver.MOVED_TO\n                | FileObserver.MODIFY\n                | FileObserver.MOVED_FROM;\n        mFileObserver = new FileObserver(profilePath, mask) {\n            @Override\n            public void onEvent(int event, @Nullable String path) {\n                loadProfiles();\n            }\n        };\n        mFileObserver.startWatching();\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/profiles/struct/AppsBaseProfile.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.profiles.struct;\n\nimport android.app.AppOpsManager;\nimport android.content.Context;\nimport android.text.TextUtils;\n\nimport androidx.annotation.CallSuper;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport org.json.JSONArray;\nimport org.json.JSONException;\nimport org.json.JSONObject;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\n\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.backup.BackupFlags;\nimport io.github.muntashirakon.AppManager.batchops.BatchOpsManager;\nimport io.github.muntashirakon.AppManager.batchops.struct.BatchAppOpsOptions;\nimport io.github.muntashirakon.AppManager.batchops.struct.BatchBackupOptions;\nimport io.github.muntashirakon.AppManager.batchops.struct.BatchComponentOptions;\nimport io.github.muntashirakon.AppManager.batchops.struct.BatchPermissionOptions;\nimport io.github.muntashirakon.AppManager.logs.Log;\nimport io.github.muntashirakon.AppManager.profiles.ProfileLogger;\nimport io.github.muntashirakon.AppManager.progress.ProgressHandler;\nimport io.github.muntashirakon.AppManager.settings.Prefs;\nimport io.github.muntashirakon.AppManager.utils.JSONUtils;\n\n\npublic abstract class AppsBaseProfile extends BaseProfile {\n    public static final String TAG = AppsBaseProfile.class.getSimpleName();\n\n    public static class BackupInfo {\n        @Nullable\n        public String name;\n        @BackupFlags.BackupFlag\n        public int flags = Prefs.BackupRestore.getBackupFlags();\n\n        public BackupInfo() {\n        }\n\n        public BackupInfo(@NonNull BackupInfo backupInfo) {\n            name = backupInfo.name;\n            flags = backupInfo.flags;\n        }\n    }\n\n    public int version = 1;  // version\n    public boolean allowRoutine = true;  // allow_routine\n    @Nullable\n    public int[] users;  // users\n    @Nullable\n    public String comment;  // comment\n    @Nullable\n    public String[] components;  // components\n    @Nullable\n    public int[] appOps;  // app_ops\n    @Nullable\n    public String[] permissions;  // permissions\n    @Nullable\n    public BackupInfo backupData;  // backup_data\n    @Nullable\n    public Integer exportRules;  // export_rules\n    /**\n     * Whether to freeze or unfreeze the selected packages. This only functions when the value is\n     * set to {@code true} and {@link #state} {@code on} means freeze and\n     * {@code off} means unfreeze. If it is set to {@code false}, it will be removed from\n     * the profile.\n     */\n    public boolean freeze = false;  // misc.disable or misc.freeze (false = remove)\n    public boolean forceStop = false;  // misc.force_stop (false = remove)\n    public boolean clearCache = false;  // misc.clear_cache (false = remove)\n    public boolean clearData = false;  // misc.clear_data (false = remove)\n    public boolean blockTrackers = false;  // misc.block_trackers (false = remove)\n    public boolean saveApk = false;  // misc.save_apk (false = remove)\n\n    protected AppsBaseProfile(@NonNull String profileId, @NonNull String profileName, int profileType) {\n        super(profileId, profileName, profileType);\n    }\n\n    protected AppsBaseProfile(@NonNull String profileId, @NonNull String profileName, @NonNull AppsBaseProfile profile) {\n        super(profileId, profileName, profile.type);\n        version = profile.version;\n        allowRoutine = profile.allowRoutine;\n        state = profile.state;\n        users = profile.users != null ? profile.users.clone() : null;\n        comment = profile.comment;\n        components = profile.components != null ? profile.components.clone() : null;\n        appOps = profile.appOps != null ? profile.appOps.clone() : null;\n        permissions = profile.permissions != null ? profile.permissions.clone() : null;\n        backupData = profile.backupData != null ? new AppsBaseProfile.BackupInfo(profile.backupData) : null;\n        exportRules = profile.exportRules != null ? profile.exportRules : null;\n        freeze = profile.freeze;\n        forceStop = profile.forceStop;\n        clearCache = profile.clearCache;\n        clearData = profile.clearData;\n        blockTrackers = profile.blockTrackers;\n        saveApk = profile.saveApk;\n    }\n\n    protected ProfileApplierResult apply(@NonNull List<String> packageList, List<Integer> assocUsers, @NonNull String state, @Nullable ProfileLogger logger, @Nullable ProgressHandler progressHandler) {\n        // Send progress\n        if (progressHandler != null) {\n            progressHandler.postUpdate(calculateMaxProgress(packageList), 0);\n        }\n        ProfileApplierResult profileApplierResult = new ProfileApplierResult();\n        BatchOpsManager batchOpsManager = new BatchOpsManager(logger);\n        BatchOpsManager.Result result;\n        // Apply component blocking\n        String[] components = this.components;\n        if (components != null) {\n            log(logger, \"====> Started block/unblock components. State: \" + state);\n            BatchComponentOptions options = new BatchComponentOptions(components);\n            int op;\n            switch (state) {\n                case BaseProfile.STATE_ON:\n                    op = BatchOpsManager.OP_BLOCK_COMPONENTS;\n                    break;\n                case BaseProfile.STATE_OFF:\n                    op = BatchOpsManager.OP_UNBLOCK_COMPONENTS;\n                    break;\n                default:\n                    op = BatchOpsManager.OP_NONE;\n            }\n            BatchOpsManager.BatchOpsInfo info = BatchOpsManager.BatchOpsInfo.getInstance(op, packageList, assocUsers, options);\n            result = batchOpsManager.performOp(info, progressHandler);\n            if (!result.isSuccessful()) {\n                Log.d(TAG, \"Failed packages: %s\", result);\n            }\n        } else Log.d(TAG, \"Skipped components.\");\n        // Apply app ops blocking\n        int[] appOps = this.appOps;\n        if (appOps != null) {\n            log(logger, \"====> Started ignore/default components. State: \" + state);\n            int mode;\n            switch (state) {\n                case BaseProfile.STATE_ON:\n                    mode = AppOpsManager.MODE_IGNORED;\n                    break;\n                case BaseProfile.STATE_OFF:\n                default:\n                    mode = AppOpsManager.MODE_DEFAULT;\n            }\n            BatchAppOpsOptions options = new BatchAppOpsOptions(appOps, mode);\n            BatchOpsManager.BatchOpsInfo info = BatchOpsManager.BatchOpsInfo.getInstance(BatchOpsManager.OP_SET_APP_OPS, packageList,\n                    assocUsers, options);\n            result = batchOpsManager.performOp(info, progressHandler);\n            if (!result.isSuccessful()) {\n                Log.d(TAG, \"Failed packages: %s\", result);\n            }\n        } else Log.d(TAG, \"Skipped app ops.\");\n        // Apply permissions\n        String[] permissions = this.permissions;\n        if (permissions != null) {\n            log(logger, \"====> Started grant/revoke permissions.\");\n            int op;\n            switch (state) {\n                case BaseProfile.STATE_ON:\n                    op = BatchOpsManager.OP_REVOKE_PERMISSIONS;\n                    break;\n                case BaseProfile.STATE_OFF:\n                    op = BatchOpsManager.OP_GRANT_PERMISSIONS;\n                    break;\n                default:\n                    op = BatchOpsManager.OP_NONE;\n            }\n            BatchPermissionOptions options = new BatchPermissionOptions(permissions);\n            BatchOpsManager.BatchOpsInfo info = BatchOpsManager.BatchOpsInfo.getInstance(op, packageList, assocUsers, options);\n            result = batchOpsManager.performOp(info, progressHandler);\n            if (!result.isSuccessful()) {\n                Log.d(TAG, \"Failed packages: %s\", result);\n            }\n        } else Log.d(TAG, \"Skipped permissions.\");\n        // Backup rules\n        Integer rulesFlag = this.exportRules;\n        if (rulesFlag != null) {\n            log(logger, \"====> Not implemented export rules.\");\n            // TODO(18/11/20): Export rules\n        } else Log.d(TAG, \"Skipped export rules.\");\n        // Disable/enable\n        if (this.freeze) {\n            log(logger, \"====> Started freeze/unfreeze. State: \" + state);\n            int op;\n            switch (state) {\n                case BaseProfile.STATE_ON:\n                    op = BatchOpsManager.OP_FREEZE;\n                    break;\n                case BaseProfile.STATE_OFF:\n                    op = BatchOpsManager.OP_UNFREEZE;\n                    break;\n                default:\n                    op = BatchOpsManager.OP_NONE;\n            }\n            BatchOpsManager.BatchOpsInfo info = BatchOpsManager.BatchOpsInfo.getInstance(op, packageList, assocUsers, null);\n            result = batchOpsManager.performOp(info, progressHandler);\n            if (!result.isSuccessful()) {\n                Log.d(TAG, \"Failed packages: %s\", result);\n            }\n        } else Log.d(TAG, \"Skipped disable/enable.\");\n        // Force-stop\n        if (this.forceStop) {\n            log(logger, \"====> Started force-stop.\");\n            BatchOpsManager.BatchOpsInfo info = BatchOpsManager.BatchOpsInfo.getInstance(BatchOpsManager.OP_FORCE_STOP, packageList, assocUsers, null);\n            result = batchOpsManager.performOp(info, progressHandler);\n            if (!result.isSuccessful()) {\n                Log.d(TAG, \"Failed packages: %s\", result);\n            }\n        } else Log.d(TAG, \"Skipped force stop.\");\n        // Clear cache\n        if (this.clearCache) {\n            log(logger, \"====> Started clear cache.\");\n            BatchOpsManager.BatchOpsInfo info = BatchOpsManager.BatchOpsInfo.getInstance(BatchOpsManager.OP_CLEAR_CACHE, packageList, assocUsers, null);\n            result = batchOpsManager.performOp(info, progressHandler);\n            if (!result.isSuccessful()) {\n                Log.d(TAG, \"Failed packages: %s\", result);\n            }\n        } else Log.d(TAG, \"Skipped clear cache.\");\n        // Clear data\n        if (this.clearData) {\n            log(logger, \"====> Started clear data.\");\n            BatchOpsManager.BatchOpsInfo info = BatchOpsManager.BatchOpsInfo.getInstance(BatchOpsManager.OP_CLEAR_DATA, packageList, assocUsers, null);\n            result = batchOpsManager.performOp(info, progressHandler);\n            if (!result.isSuccessful()) {\n                Log.d(TAG, \"Failed packages: %s\", result);\n            }\n        } else Log.d(TAG, \"Skipped clear data.\");\n        // Block trackers\n        if (this.blockTrackers) {\n            log(logger, \"====> Started block trackers. State: \" + state);\n            int op;\n            switch (state) {\n                case BaseProfile.STATE_ON:\n                    op = BatchOpsManager.OP_BLOCK_TRACKERS;\n                    break;\n                case BaseProfile.STATE_OFF:\n                    op = BatchOpsManager.OP_UNBLOCK_TRACKERS;\n                    break;\n                default:\n                    op = BatchOpsManager.OP_NONE;\n            }\n            BatchOpsManager.BatchOpsInfo info = BatchOpsManager.BatchOpsInfo.getInstance(op, packageList, assocUsers, null);\n            result = batchOpsManager.performOp(info, progressHandler);\n            if (!result.isSuccessful()) {\n                Log.d(TAG, \"Failed packages: %s\", result);\n            }\n        } else Log.d(TAG, \"Skipped block trackers.\");\n        // Backup apk\n        if (this.saveApk) {\n            log(logger, \"====> Started backup apk.\");\n            BatchOpsManager.BatchOpsInfo info = BatchOpsManager.BatchOpsInfo.getInstance(BatchOpsManager.OP_BACKUP_APK, packageList, assocUsers, null);\n            result = batchOpsManager.performOp(info, progressHandler);\n            if (!result.isSuccessful()) {\n                Log.d(TAG, \"Failed packages: %s\", result);\n            }\n        } else Log.d(TAG, \"Skipped backup apk.\");\n        // Backup/restore data\n        AppsBaseProfile.BackupInfo backupInfo = this.backupData;\n        if (backupInfo != null) {\n            log(logger, \"====> Started backup/restore.\");\n            BackupFlags backupFlags = new BackupFlags(backupInfo.flags);\n            String[] backupNames;\n            if (backupFlags.backupMultiple() && backupInfo.name != null) {\n                backupNames = new String[]{backupInfo.name};\n            } else backupNames = null;\n            // Always add backup custom users\n            backupFlags.addFlag(BackupFlags.BACKUP_CUSTOM_USERS);\n            BatchBackupOptions options = new BatchBackupOptions(backupFlags.getFlags(), backupNames, null);\n            int op;\n            switch (state) {\n                case BaseProfile.STATE_ON:  // Take backup\n                    op = BatchOpsManager.OP_BACKUP;\n                    break;\n                case BaseProfile.STATE_OFF:  // Restore backup\n                    op = BatchOpsManager.OP_RESTORE_BACKUP;\n                    break;\n                default:\n                    op = BatchOpsManager.OP_NONE;\n            }\n            BatchOpsManager.BatchOpsInfo info = BatchOpsManager.BatchOpsInfo.getInstance(op, packageList, assocUsers, options);\n            result = batchOpsManager.performOp(info, progressHandler);\n            profileApplierResult.setRequiresRestart(profileApplierResult.requiresRestart() | result.requiresRestart());\n            if (!result.isSuccessful()) {\n                Log.d(TAG, \"Failed packages: %s\", result);\n            }\n        } else Log.d(TAG, \"Skipped backup/restore.\");\n        batchOpsManager.conclude();\n        return profileApplierResult;\n    }\n\n    private int calculateMaxProgress(@NonNull List<String> userPackagePairs) {\n        int packageCount = userPackagePairs.size();\n        int opCount = 0;\n        if (components != null) ++opCount;\n        if (appOps != null) ++opCount;\n        if (permissions != null) ++opCount;\n        // if (profile.exportRules != null) ++opCount; todo\n        if (freeze) ++opCount;\n        if (forceStop) ++opCount;\n        if (clearCache) ++opCount;\n        if (clearData) ++opCount;\n        if (blockTrackers) ++opCount;\n        if (saveApk) ++opCount;\n        if (backupData != null) ++opCount;\n        return opCount * packageCount;\n    }\n\n    private void log(@Nullable ProfileLogger logger, @Nullable String message) {\n        if (logger != null) {\n            logger.println(message);\n        }\n    }\n\n    @NonNull\n    private List<String> getLocalisedSummaryOrComment(Context context) {\n        if (comment != null) {\n            return Collections.singletonList(comment);\n        }\n\n        List<String> arrayList = new ArrayList<>();\n        if (components != null) arrayList.add(context.getString(R.string.components));\n        if (appOps != null) arrayList.add(context.getString(R.string.app_ops));\n        if (permissions != null) arrayList.add(context.getString(R.string.permissions));\n        if (backupData != null) arrayList.add(context.getString(R.string.backup_restore));\n        if (exportRules != null) arrayList.add(context.getString(R.string.blocking_rules));\n        if (freeze) arrayList.add(context.getString(R.string.freeze));\n        if (forceStop) arrayList.add(context.getString(R.string.force_stop));\n        if (clearCache) arrayList.add(context.getString(R.string.clear_cache));\n        if (clearData) arrayList.add(context.getString(R.string.clear_data));\n        if (blockTrackers) arrayList.add(context.getString(R.string.trackers));\n        if (saveApk) arrayList.add(context.getString(R.string.save_apk));\n        return arrayList;\n    }\n\n    @NonNull\n    @Override\n    public CharSequence toLocalizedString(@NonNull Context context) {\n        List<String> summaries = getLocalisedSummaryOrComment(context);\n        if (summaries.isEmpty()) {\n            return context.getString(R.string.no_configurations);\n        }\n        return TextUtils.join(\", \", summaries);\n    }\n\n    @CallSuper\n    @NonNull\n    @Override\n    public JSONObject serializeToJson() throws JSONException {\n        JSONObject profileObj = super.serializeToJson();\n        profileObj.put(\"version\", version);\n        if (!allowRoutine) {\n            // Only save allow_routine if it's set to false\n            profileObj.put(\"allow_routine\", false);\n        }\n        profileObj.put(\"comment\", comment);\n        profileObj.put(\"users\", JSONUtils.getJSONArray(users));\n        profileObj.put(\"components\", JSONUtils.getJSONArray(components));\n        profileObj.put(\"app_ops\", JSONUtils.getJSONArray(appOps));\n        profileObj.put(\"permissions\", JSONUtils.getJSONArray(permissions));\n        // Backup info\n        if (backupData != null) {\n            JSONObject backupInfo = new JSONObject();\n            backupInfo.put(\"name\", backupData.name);\n            backupInfo.put(\"flags\", backupData.flags);\n            profileObj.put(\"backup_data\", backupInfo);\n        }\n        profileObj.put(\"export_rules\", exportRules);\n        // Misc\n        JSONArray jsonArray = new JSONArray();\n        if (freeze) jsonArray.put(\"freeze\");\n        if (forceStop) jsonArray.put(\"force_stop\");\n        if (clearCache) jsonArray.put(\"clear_cache\");\n        if (clearData) jsonArray.put(\"clear_data\");\n        if (blockTrackers) jsonArray.put(\"block_trackers\");\n        if (saveApk) jsonArray.put(\"save_apk\");\n        if (jsonArray.length() > 0) profileObj.put(\"misc\", jsonArray);\n        return profileObj;\n    }\n\n    protected AppsBaseProfile(@NonNull JSONObject profileObj) throws JSONException {\n        super(profileObj);\n        comment = JSONUtils.getString(profileObj, \"comment\", null);\n        version = profileObj.getInt(\"version\");\n        allowRoutine = profileObj.optBoolean(\"allow_routine\", true);\n        try {\n            users = JSONUtils.getIntArray(profileObj.getJSONArray(\"users\"));\n        } catch (JSONException ignore) {\n        }\n        try {\n            components = JSONUtils.getArray(String.class, profileObj.getJSONArray(\"components\"));\n        } catch (JSONException ignore) {\n        }\n        try {\n            appOps = JSONUtils.getIntArray(profileObj.getJSONArray(\"app_ops\"));\n        } catch (JSONException ignore) {\n        }\n        try {\n            permissions = JSONUtils.getArray(String.class, profileObj.getJSONArray(\"permissions\"));\n        } catch (JSONException ignore) {\n        }\n        // Backup info\n        try {\n            JSONObject backupInfo = profileObj.getJSONObject(\"backup_data\");\n            backupData = new AppsBaseProfile.BackupInfo();\n            backupData.name = JSONUtils.getString(backupInfo, \"name\", null);\n            backupData.flags = backupInfo.getInt(\"flags\");\n        } catch (JSONException ignore) {\n        }\n        exportRules = JSONUtils.getIntOrNull(profileObj, \"export_rules\");\n        // Misc\n        try {\n            List<String> miscConfig = JSONUtils.getArray(profileObj.getJSONArray(\"misc\"));\n            freeze = miscConfig.contains(\"disable\") || miscConfig.contains(\"freeze\");\n            forceStop = miscConfig.contains(\"force_stop\");\n            clearCache = miscConfig.contains(\"clear_cache\");\n            clearData = miscConfig.contains(\"clear_data\");\n            blockTrackers = miscConfig.contains(\"block_trackers\");\n            saveApk = miscConfig.contains(\"save_apk\");\n        } catch (Exception ignore) {\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/profiles/struct/AppsFilterProfile.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.profiles.struct;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport org.json.JSONException;\nimport org.json.JSONObject;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport io.github.muntashirakon.AppManager.filters.FilterItem;\nimport io.github.muntashirakon.AppManager.filters.FilterableAppInfo;\nimport io.github.muntashirakon.AppManager.filters.FilteringUtils;\nimport io.github.muntashirakon.AppManager.history.JsonDeserializer;\nimport io.github.muntashirakon.AppManager.profiles.ProfileLogger;\nimport io.github.muntashirakon.AppManager.progress.ProgressHandler;\nimport io.github.muntashirakon.AppManager.users.Users;\n\npublic class AppsFilterProfile extends AppsBaseProfile {\n    @NonNull\n    private final FilterItem mFilterItem;\n\n    protected AppsFilterProfile(@NonNull String profileId, @NonNull String profileName) {\n        super(profileId, profileName, PROFILE_TYPE_APPS_FILTER);\n        mFilterItem = new FilterItem();\n    }\n\n    protected AppsFilterProfile(@NonNull String profileId, @NonNull String profileName, @NonNull AppsFilterProfile profile) {\n        super(profileId, profileName, profile.type);\n        try {\n            // Shorthand for cloning filter items\n            mFilterItem = FilterItem.DESERIALIZER.deserialize(profile.mFilterItem.serializeToJson());\n        } catch (JSONException e) {\n            throw new IllegalArgumentException(\"Invalid profile\", e);\n        }\n    }\n\n    public FilterItem getFilterItem() {\n        return mFilterItem;\n    }\n\n    @Override\n    public ProfileApplierResult apply(@NonNull String state, @Nullable ProfileLogger logger, @Nullable ProgressHandler progressHandler) {\n        // Filter results\n        int[] users = this.users == null ? Users.getUsersIds() : this.users;\n        List<FilterableAppInfo> filterableAppInfoList = FilteringUtils.loadFilterableAppInfo(users);\n        List<FilterItem.FilteredItemInfo<FilterableAppInfo>> filteredList = mFilterItem.getFilteredList(filterableAppInfoList);\n        if (filteredList.isEmpty()) {\n            return ProfileApplierResult.EMPTY_RESULT;\n        }\n        List<String> packages = new ArrayList<>(filteredList.size());\n        List<Integer> assocUsers = new ArrayList<>(filteredList.size());\n        if (logger != null) {\n            logger.println(\"====> Filtered packages: \" + filteredList.size());\n        }\n        StringBuilder sb = new StringBuilder();\n        for (FilterItem.FilteredItemInfo<FilterableAppInfo> info : filteredList) {\n            packages.add(info.info.getPackageName());\n            assocUsers.add(info.info.getUserId());\n            sb.append(\"(\").append(info.info.getPackageName()).append(\", \")\n                    .append(info.info.getUserId()).append(\"), \");\n        }\n        if (logger != null) {\n            logger.println(sb);\n        }\n        return apply(packages, assocUsers, state, logger, progressHandler);\n    }\n\n    @NonNull\n    @Override\n    public JSONObject serializeToJson() throws JSONException {\n        return super.serializeToJson().put(\"filters\", mFilterItem.serializeToJson());\n    }\n\n    protected AppsFilterProfile(@NonNull JSONObject profileObj) throws JSONException {\n        super(profileObj);\n        mFilterItem = FilterItem.DESERIALIZER.deserialize(profileObj.getJSONObject(\"filters\"));\n    }\n\n    public static final JsonDeserializer.Creator<AppsFilterProfile> DESERIALIZER = AppsFilterProfile::new;\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/profiles/struct/AppsProfile.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.profiles.struct;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport org.json.JSONException;\nimport org.json.JSONObject;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport aosp.libcore.util.EmptyArray;\nimport io.github.muntashirakon.AppManager.history.JsonDeserializer;\nimport io.github.muntashirakon.AppManager.profiles.ProfileLogger;\nimport io.github.muntashirakon.AppManager.progress.ProgressHandler;\nimport io.github.muntashirakon.AppManager.users.Users;\nimport io.github.muntashirakon.AppManager.utils.ArrayUtils;\nimport io.github.muntashirakon.AppManager.utils.JSONUtils;\n\n\npublic class AppsProfile extends AppsBaseProfile {\n    @NonNull\n    public String[] packages;  // packages (a list of packages)\n\n    protected AppsProfile(@NonNull String profileId, @NonNull String profileName) {\n        super(profileId, profileName, PROFILE_TYPE_APPS);\n        packages = EmptyArray.STRING;\n    }\n\n    protected AppsProfile(@NonNull String profileId, @NonNull String profileName, @NonNull AppsProfile profile) {\n        super(profileId, profileName, profile);\n        packages = profile.packages.clone();\n    }\n\n    @Override\n    public ProfileApplierResult apply(@NonNull String state, @Nullable ProfileLogger logger, @Nullable ProgressHandler progressHandler) {\n        if (packages.length == 0) return ProfileApplierResult.EMPTY_RESULT;\n        int[] users = this.users == null ? Users.getUsersIds() : this.users;\n        int size = packages.length * users.length;\n        List<String> packageList = new ArrayList<>(size);\n        List<Integer> assocUsers = new ArrayList<>(size);\n        for (String packageName : packages) {\n            for (int user : users) {\n                packageList.add(packageName);\n                assocUsers.add(user);\n            }\n        }\n        return apply(packageList, assocUsers, state, logger, progressHandler);\n    }\n\n    public void appendPackages(@NonNull String[] packageList) {\n        List<String> uniquePackages = new ArrayList<>();\n        for (String newPackage : packageList) {\n            if (!ArrayUtils.contains(packages, newPackage)) {\n                uniquePackages.add(newPackage);\n            }\n        }\n        packages = ArrayUtils.concatElements(String.class, packages, uniquePackages.toArray(new String[0]));\n    }\n\n    @NonNull\n    @Override\n    public JSONObject serializeToJson() throws JSONException {\n        return super.serializeToJson()\n                .put(\"packages\", JSONUtils.getJSONArray(packages));\n    }\n\n    protected AppsProfile(@NonNull JSONObject profileObj) throws JSONException {\n        super(profileObj);\n        packages = JSONUtils.getArray(String.class, profileObj.getJSONArray(\"packages\"));\n    }\n\n    public static final JsonDeserializer.Creator<AppsProfile> DESERIALIZER = AppsProfile::new;\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/profiles/struct/BaseProfile.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.profiles.struct;\n\nimport static io.github.muntashirakon.AppManager.profiles.ProfileManager.PROFILE_EXT;\n\nimport androidx.annotation.CallSuper;\nimport androidx.annotation.IntDef;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.StringDef;\n\nimport org.jetbrains.annotations.Contract;\nimport org.json.JSONException;\nimport org.json.JSONObject;\n\nimport java.io.IOException;\nimport java.io.OutputStream;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.util.Objects;\n\nimport io.github.muntashirakon.AppManager.history.IJsonSerializer;\nimport io.github.muntashirakon.AppManager.history.JsonDeserializer;\nimport io.github.muntashirakon.AppManager.profiles.ProfileLogger;\nimport io.github.muntashirakon.AppManager.profiles.ProfileManager;\nimport io.github.muntashirakon.AppManager.progress.ProgressHandler;\nimport io.github.muntashirakon.AppManager.utils.JSONUtils;\nimport io.github.muntashirakon.io.Path;\nimport io.github.muntashirakon.io.Paths;\nimport io.github.muntashirakon.util.LocalizedString;\n\npublic abstract class BaseProfile implements LocalizedString, IJsonSerializer {\n    @Contract(\"null -> fail\")\n    @NonNull\n    public static BaseProfile fromPath(@Nullable Path profilePath) throws IOException, JSONException {\n        if (profilePath == null) {\n            throw new IOException(\"Empty profile path\");\n        }\n        String profileStr = profilePath.getContentAsString();\n        JSONObject profileObj = new JSONObject(profileStr);\n        return BaseProfile.DESERIALIZER.deserialize(profileObj);\n    }\n\n    @NonNull\n    public static BaseProfile newProfile(@NonNull String newProfileName, int type, @Nullable BaseProfile source) {\n        String profileId = ProfileManager.getProfileIdCompat(newProfileName);\n        // TODO: 17/9/23 TODO: Remove these once we migrated to UUID based profile ID\n        // BEGIN legacy: For legacy profile, the generated ID can be the same as an existing profile\n        Path profilesDir = ProfileManager.getProfilesDir();\n        Path profilePath = Paths.build(profilesDir, profileId + PROFILE_EXT);\n        String profileName = newProfileName;\n        int i = 1;\n        while (profilePath != null && profilePath.exists()) {\n            // Try another name\n            profileName = newProfileName + \" (\" + i + \")\";\n            profileId = ProfileManager.getProfileIdCompat(profileName);\n            profilePath = Paths.build(profilesDir, profileId + PROFILE_EXT);\n            ++i;\n        }\n        // END legacy: For legacy profile, the generated ID can be the same as an existing profile\n        switch (type) {\n            case PROFILE_TYPE_APPS:\n                if (source != null) {\n                    assert source instanceof AppsProfile;\n                    return new AppsProfile(profileId, profileName, (AppsProfile) source);\n                } else return new AppsProfile(profileId, profileName);\n            case PROFILE_TYPE_APPS_FILTER:\n                if (source != null) {\n                    assert source instanceof AppsFilterProfile;\n                    return new AppsFilterProfile(profileId, profileName, (AppsFilterProfile) source);\n                } else return new AppsFilterProfile(profileId, profileName);\n            default:\n                throw new IllegalArgumentException(\"Invalid type: \" + type);\n        }\n    }\n\n    public static final int PROFILE_TYPE_APPS = 0;\n    public static final int PROFILE_TYPE_APPS_FILTER = 1;\n\n    @IntDef({PROFILE_TYPE_APPS, PROFILE_TYPE_APPS_FILTER})\n    @Retention(RetentionPolicy.SOURCE)\n    public @interface ProfileType {\n    }\n\n    public static final String STATE_ON = \"on\";\n    public static final String STATE_OFF = \"off\";\n\n    @StringDef({STATE_ON, STATE_OFF})\n    @Retention(RetentionPolicy.SOURCE)\n    public @interface ProfileState {\n    }\n\n    @NonNull\n    public final String profileId; // id\n    @NonNull\n    public final String name;  // name (name of the profile)\n    @ProfileType\n    public final int type;  // type\n    @ProfileState\n    public String state; // state\n\n    protected BaseProfile(@NonNull String profileId, @NonNull String profileName, int profileType) {\n        this.profileId = profileId;\n        this.name = profileName;\n        this.type = profileType;\n    }\n\n    public abstract ProfileApplierResult apply(@NonNull String state, @Nullable ProfileLogger logger, @Nullable ProgressHandler progressHandler);\n\n    public void write(@NonNull OutputStream out) throws IOException {\n        try {\n            out.write(serializeToJson().toString().getBytes());\n        } catch (JSONException e) {\n            throw new IOException(e);\n        }\n    }\n\n    @NonNull\n    @CallSuper\n    @Override\n    public JSONObject serializeToJson() throws JSONException {\n        JSONObject profileObj = new JSONObject();\n        profileObj.put(\"id\", profileId);\n        profileObj.put(\"name\", name);\n        profileObj.put(\"type\", type);\n        profileObj.put(\"state\", state);\n        return profileObj;\n    }\n\n    protected BaseProfile(@NonNull JSONObject profileObj) throws JSONException {\n        name = profileObj.getString(\"name\");\n        profileId = JSONUtils.getString(profileObj, \"id\", ProfileManager.getProfileIdCompat(name));\n        type = profileObj.getInt(\"type\");\n        state = JSONUtils.getString(profileObj, \"state\", STATE_ON);\n    }\n\n    public static final JsonDeserializer.Creator<BaseProfile> DESERIALIZER = jsonObject -> {\n        int type = jsonObject.getInt(\"type\");\n        if (type == PROFILE_TYPE_APPS) {\n            return AppsProfile.DESERIALIZER.deserialize(jsonObject);\n        } else if (type == PROFILE_TYPE_APPS_FILTER) {\n            return AppsFilterProfile.DESERIALIZER.deserialize(jsonObject);\n        } else throw new JSONException(\"Invalid type: \" + type);\n    };\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) return true;\n        if (!(o instanceof BaseProfile)) return false;\n        BaseProfile that = (BaseProfile) o;\n        return Objects.equals(profileId, that.profileId);\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hash(profileId);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/profiles/struct/ProfileApplierResult.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.profiles.struct;\n\npublic class ProfileApplierResult {\n    public static final ProfileApplierResult EMPTY_RESULT = new ProfileApplierResult();\n\n    private boolean mRequiresRestart;\n\n    public void setRequiresRestart(boolean requiresRestart) {\n        mRequiresRestart = requiresRestart;\n    }\n\n    public boolean requiresRestart() {\n        return mRequiresRestart;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/progress/NotificationProgressHandler.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.progress;\n\nimport android.Manifest;\nimport android.app.Notification;\nimport android.app.PendingIntent;\nimport android.app.Service;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.pm.PackageManager;\n\nimport androidx.annotation.DrawableRes;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.core.app.ActivityCompat;\nimport androidx.core.app.NotificationChannelCompat;\nimport androidx.core.app.NotificationCompat;\nimport androidx.core.app.NotificationManagerCompat;\nimport androidx.core.app.PendingIntentCompat;\n\nimport org.jetbrains.annotations.Contract;\n\nimport java.util.ArrayList;\nimport java.util.Objects;\n\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.settings.Prefs;\nimport io.github.muntashirakon.AppManager.types.ForegroundService;\nimport io.github.muntashirakon.AppManager.utils.NotificationUtils;\n\npublic class NotificationProgressHandler extends QueuedProgressHandler {\n    private static final String TAG_PROGRESS = null;\n    private static final String TAG_QUEUE = \"queue\";\n    private static final String TAG_ALERT = \"alert\";\n\n    @NonNull\n    private final Context mContext;\n    @NonNull\n    private final NotificationManagerInfo mProgressNotificationManagerInfo;\n    @NonNull\n    private final NotificationManagerInfo mCompletionNotificationManagerInfo;\n    @Nullable\n    private final NotificationManagerInfo mQueueNotificationManagerInfo;\n    @NonNull\n    private final NotificationManagerCompat mProgressNotificationManager;\n    @NonNull\n    private final NotificationManagerCompat mCompletionNotificationManager;\n    @Nullable\n    private final NotificationManagerCompat mQueueNotificationManager;\n    private final int mProgressNotificationId;\n\n    @Nullable\n    private NotificationInfo mLastProgressNotification = null;\n    private volatile int mLastMax = MAX_INDETERMINATE;\n    private volatile float mLastProgress = 0;\n    private boolean mAttachedToService;\n\n    public NotificationProgressHandler(@NonNull Context context,\n                                       @NonNull NotificationManagerInfo progressNotificationManagerInfo,\n                                       @NonNull NotificationManagerInfo completionNotificationManagerInfo,\n                                       @Nullable NotificationManagerInfo queueNotificationManagerInfo) {\n        mContext = context;\n        mProgressNotificationManagerInfo = progressNotificationManagerInfo;\n        mCompletionNotificationManagerInfo = completionNotificationManagerInfo;\n        mQueueNotificationManagerInfo = queueNotificationManagerInfo;\n        mProgressNotificationManager = getNotificationManager(context, mProgressNotificationManagerInfo);\n        mCompletionNotificationManager = getNotificationManager(context, mCompletionNotificationManagerInfo);\n        mQueueNotificationManager = getNotificationManager(context, mQueueNotificationManagerInfo);\n        mProgressNotificationId = NotificationUtils.nextNotificationId(TAG_PROGRESS);\n    }\n\n    @Override\n    public void onQueue(@Nullable Object message) {\n        if (mQueueNotificationManager == null || mQueueNotificationManagerInfo == null || message == null) {\n            return;\n        }\n        NotificationInfo info = (NotificationInfo) message;\n        Notification notification = info\n                .getBuilder(mContext, mQueueNotificationManagerInfo)\n                .setLocalOnly(true)\n                .build();\n        notify(mContext, mQueueNotificationManager, TAG_QUEUE, NotificationUtils.nextNotificationId(TAG_QUEUE), notification);\n    }\n\n    @Override\n    public void onAttach(@Nullable Service service, @NonNull Object message) {\n        mLastProgressNotification = (NotificationInfo) message;\n        if (service != null) {\n            mAttachedToService = true;\n            Notification notification = mLastProgressNotification\n                    .getBuilder(mContext, mProgressNotificationManagerInfo)\n                    .setLocalOnly(true)\n                    .setOngoing(true)\n                    .setOnlyAlertOnce(true)\n                    .setProgress(0, 0, false)\n                    .build();\n            ForegroundService.start(service, mProgressNotificationId, notification,\n                    ForegroundService.FOREGROUND_SERVICE_TYPE_DATA_SYNC\n                            | ForegroundService.FOREGROUND_SERVICE_TYPE_SPECIAL_USE);\n        }\n    }\n\n    @Override\n    public void onProgressStart(int max, float current, @Nullable Object message) {\n        onProgressUpdate(max, current, message);\n    }\n\n    @Override\n    public void onProgressUpdate(int max, float current, @Nullable Object message) {\n        if (message != null) {\n            mLastProgressNotification = (NotificationInfo) message;\n        } else {\n            Objects.requireNonNull(mLastProgressNotification);\n        }\n        mLastMax = max;\n        mLastProgress = current;\n        CharSequence progressText = progressTextInterface.getProgressText(this);\n        boolean indeterminate = max == -1;\n        int newMax = Math.max(max, 0);\n        int newCurrent = max < 0 ? 0 : (int) current;\n        NotificationCompat.Builder builder = mLastProgressNotification\n                .getBuilder(mContext, mProgressNotificationManagerInfo)\n                .setLocalOnly(true)\n                .setOngoing(true)\n                .setOnlyAlertOnce(true)\n                .setProgress(newMax, newCurrent, indeterminate);\n        if (progressText != null) {\n            if (max > 0) {\n                builder.setContentText(progressText);\n            } else if (max == MAX_FINISHED) {\n                builder.setContentText(mContext.getString(R.string.done));\n            } else {\n                builder.setContentText(mContext.getString(R.string.operation_running));\n            }\n        }\n        notify(mContext, mProgressNotificationManager, TAG_PROGRESS, mProgressNotificationId, builder.build());\n    }\n\n    @Override\n    public void onResult(@Nullable Object message) {\n        if (!mAttachedToService) {\n            mProgressNotificationManager.cancel(TAG_PROGRESS, mProgressNotificationId);\n        } else {\n            onProgressUpdate(MAX_FINISHED, 0, null); // Trick to remove progressbar\n        }\n        if (message == null) {\n            return;\n        }\n        NotificationInfo info = (NotificationInfo) message;\n        Notification notification = info\n                .getBuilder(mContext, mCompletionNotificationManagerInfo)\n                .build();\n        notify(mContext, mCompletionNotificationManager, TAG_ALERT, NotificationUtils.nextNotificationId(TAG_ALERT), notification);\n    }\n\n    @Override\n    public void onDetach(@Nullable Service service) {\n        if (service != null) {\n            mAttachedToService = false;\n            mProgressNotificationManager.cancel(TAG_PROGRESS, mProgressNotificationId);\n        }\n    }\n\n    @Override\n    @NonNull\n    public ProgressHandler newSubProgressHandler() {\n        return new NotificationProgressHandler(mContext, mProgressNotificationManagerInfo,\n                mCompletionNotificationManagerInfo, null);\n    }\n\n    @Override\n    public int getLastMax() {\n        return mLastMax;\n    }\n\n    @Override\n    public float getLastProgress() {\n        return mLastProgress;\n    }\n\n    @Nullable\n    @Override\n    public Object getLastMessage() {\n        return mLastProgressNotification;\n    }\n\n    @Override\n    public void postUpdate(int max, float current, @Nullable Object message) {\n        // Update values immediately to avoid issues\n        mLastMax = max;\n        mLastProgress = current;\n        super.postUpdate(max, current, message);\n    }\n\n    private static void notify(@NonNull Context context,\n                               @NonNull NotificationManagerCompat notificationManager,\n                               @Nullable String notificationTag,\n                               int notificationId,\n                               @NonNull Notification notification) {\n        if (ActivityCompat.checkSelfPermission(context, Manifest.permission.POST_NOTIFICATIONS) == PackageManager.PERMISSION_GRANTED) {\n            notificationManager.notify(notificationTag, notificationId, notification);\n        }\n    }\n\n    @Nullable\n    @Contract(\"_, !null -> !null\")\n    private static NotificationManagerCompat getNotificationManager(@NonNull Context context,\n                                                                    @Nullable NotificationManagerInfo info) {\n        if (info == null) {\n            return null;\n        }\n        NotificationChannelCompat channel = new NotificationChannelCompat\n                .Builder(info.channelId, info.importance)\n                .setName(info.channelName)\n                .build();\n        NotificationManagerCompat managerCompat = NotificationManagerCompat.from(context);\n        managerCompat.createNotificationChannel(channel);\n        return managerCompat;\n    }\n\n    public static class NotificationManagerInfo {\n        @NonNull\n        public final String channelId;\n        @NonNull\n        public final CharSequence channelName;\n        @NotificationUtils.NotificationImportance\n        public final int importance;\n\n        public NotificationManagerInfo(@NonNull String channelId, @NonNull CharSequence channelName,\n                                       @NotificationUtils.NotificationImportance int importance) {\n            this.channelId = channelId;\n            this.channelName = channelName;\n            this.importance = importance;\n        }\n    }\n\n    public static class NotificationInfo {\n        @DrawableRes\n        private int icon = R.drawable.ic_default_notification;\n        private int level;\n        private long time = 0L;\n        @Nullable\n        private CharSequence operationName;\n        @Nullable\n        private CharSequence title;\n        @Nullable\n        private CharSequence body;\n        @Nullable\n        private CharSequence statusBarText;\n        @Nullable\n        private NotificationCompat.Style style;\n        private boolean autoCancel;\n        @Nullable\n        private PendingIntent defaultAction;\n        @Nullable\n        private String groupId;\n\n        private final ArrayList<NotificationCompat.Action> actions = new ArrayList<>();\n\n\n        public NotificationInfo() {\n        }\n\n        public NotificationInfo(@NonNull NotificationInfo notificationInfo) {\n            icon = notificationInfo.icon;\n            level = notificationInfo.level;\n            time = notificationInfo.time;\n            operationName = notificationInfo.operationName;\n            title = notificationInfo.title;\n            body = notificationInfo.body;\n            statusBarText = notificationInfo.statusBarText;\n            style = notificationInfo.style;\n            autoCancel = notificationInfo.autoCancel;\n            defaultAction = notificationInfo.defaultAction;\n            groupId = notificationInfo.groupId;\n            actions.addAll(notificationInfo.actions);\n        }\n\n        public NotificationInfo setIcon(int icon) {\n            this.icon = icon;\n            return this;\n        }\n\n        public NotificationInfo setLevel(int level) {\n            this.level = level;\n            return this;\n        }\n\n        public NotificationInfo setTitle(@Nullable CharSequence title) {\n            this.title = title;\n            return this;\n        }\n\n        public NotificationInfo setBody(@Nullable CharSequence body) {\n            this.body = body;\n            return this;\n        }\n\n        public NotificationInfo setStatusBarText(@Nullable CharSequence statusBarText) {\n            this.statusBarText = statusBarText;\n            return this;\n        }\n\n        public NotificationInfo setDefaultAction(@Nullable PendingIntent defaultAction) {\n            this.defaultAction = defaultAction;\n            return this;\n        }\n\n        public NotificationInfo setOperationName(@Nullable CharSequence operationName) {\n            this.operationName = operationName;\n            return this;\n        }\n\n        public NotificationInfo setStyle(@Nullable NotificationCompat.Style style) {\n            this.style = style;\n            return this;\n        }\n\n        public NotificationInfo setAutoCancel(boolean autoCancel) {\n            this.autoCancel = autoCancel;\n            return this;\n        }\n\n        public NotificationInfo setTime(long time) {\n            this.time = time;\n            return this;\n        }\n\n        public void setGroupId(@Nullable String groupId) {\n            this.groupId = groupId;\n        }\n\n        public NotificationInfo addAction(int icon, @Nullable CharSequence title,\n                                          @Nullable PendingIntent intent) {\n            actions.add(new NotificationCompat.Action(icon, title, intent));\n            return this;\n        }\n\n        @NonNull\n        NotificationCompat.Builder getBuilder(@NonNull Context context, @NonNull NotificationManagerInfo info) {\n            PendingIntent contentIntent;\n            if (autoCancel && defaultAction == null) {\n                // Auto-cancel requires a content Intent\n                contentIntent = PendingIntentCompat.getActivity(context, 0, new Intent(), 0, false);\n            } else contentIntent = defaultAction;\n            NotificationCompat.Builder builder = new NotificationCompat.Builder(context, info.channelId)\n                    .setLocalOnly(!Prefs.Misc.sendNotificationsToConnectedDevices())\n                    .setPriority(NotificationUtils.importanceToPriority(info.importance))\n                    .setDefaults(Notification.DEFAULT_ALL)\n                    .setSmallIcon(icon, level)\n                    .setSubText(operationName)\n                    .setTicker(statusBarText)\n                    .setContentTitle(title)\n                    .setContentText(body)\n                    .setContentIntent(contentIntent)\n                    .setAutoCancel(autoCancel)\n                    .setGroup(groupId)\n                    .setStyle(style);\n            if (groupId == null) {\n                builder.setGroupSummary(false);\n                builder.setGroupAlertBehavior(NotificationCompat.GROUP_ALERT_SUMMARY);\n            }\n            for (NotificationCompat.Action action : actions) {\n                builder.addAction(action);\n            }\n            if (time > 0L) {\n                builder.setWhen(time);\n                builder.setShowWhen(true);\n            }\n            return builder;\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/progress/ProgressHandler.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.progress;\n\nimport android.annotation.SuppressLint;\nimport android.app.Service;\n\nimport androidx.annotation.AnyThread;\nimport androidx.annotation.CallSuper;\nimport androidx.annotation.MainThread;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport java.util.Locale;\n\nimport io.github.muntashirakon.AppManager.utils.ThreadUtils;\n\n/**\n * A generic class to handle any kind of progress. Progress can be handled in various ways such as using notifications\n * or progress indicator or both.\n */\npublic abstract class ProgressHandler {\n    public interface ProgressTextInterface {\n        @Nullable\n        CharSequence getProgressText(@NonNull ProgressHandler progressHandler);\n    }\n\n    public static final ProgressTextInterface PROGRESS_PERCENT = progressHandler -> {\n        float current = progressHandler.getLastProgress() / progressHandler.getLastMax() * 100;\n        return String.format(Locale.getDefault(), \"%d%%\", (int) current);\n    };\n    public static final ProgressTextInterface PROGRESS_REGULAR = progressHandler ->\n            String.format(Locale.getDefault(), \"%d/%d\", (int) progressHandler.getLastProgress(),\n                    progressHandler.getLastMax());\n    protected static final ProgressTextInterface PROGRESS_DEFAULT = progressHandler -> null;\n\n    protected static final int MAX_INDETERMINATE = -1;\n    protected static final int MAX_FINISHED = -2;\n\n\n    @NonNull\n    protected ProgressTextInterface progressTextInterface = PROGRESS_DEFAULT;\n\n    /**\n     * Call this function if the progress handler is backed by a foreground service and a progressbar is needed to be\n     * initiated right away. After finished working with it, call {@link #onDetach(Service)}\n     */\n    @MainThread\n    public abstract void onAttach(@Nullable Service service, @NonNull Object message);\n\n    /**\n     * Initialise progress. Arguments here can be modified by calling {@link #onProgressUpdate(int, float, Object)}.\n     *\n     * @param max     Maximum progress value. Use {@code -1} to switch to non-determinate mode.\n     * @param current Current progress value. Should be {@code 0}. Irrelevant in non-determinate mode.\n     * @param message Additional arguments to pass on. Depends on implementation.\n     */\n    @MainThread\n    public abstract void onProgressStart(int max, float current, @Nullable Object message);\n\n    /**\n     * Update progress\n     *\n     * @param max     Maximum progress value. Use {@code -1} to switch to non-determinate mode.\n     * @param current Current progress value. Irrelevant in non-determinate mode.\n     * @param message Additional arguments to pass on. Depends on implementation.\n     */\n    @MainThread\n    public abstract void onProgressUpdate(int max, float current, @Nullable Object message);\n\n    /**\n     * Call when the progress is finished. If this is not attached to a foreground service, the progress also stops.\n     */\n    @MainThread\n    public abstract void onResult(@Nullable Object message);\n\n    /**\n     * Call this function to stop progress when this is attached to a foreground service.\n     */\n    @MainThread\n    public abstract void onDetach(@Nullable Service service);\n\n    /**\n     * Get a new progress handler from this handler. The handler will never have a queue handler.\n     */\n    @NonNull\n    public abstract ProgressHandler newSubProgressHandler();\n\n    @Nullable\n    public abstract Object getLastMessage();\n\n    public abstract int getLastMax();\n\n    public abstract float getLastProgress();\n\n    public void setProgressTextInterface(@Nullable ProgressTextInterface progressTextInterface) {\n        this.progressTextInterface = progressTextInterface != null ? progressTextInterface : PROGRESS_DEFAULT;\n    }\n\n    /**\n     * Update progress from any thread. Arguments from the last time are used.\n     *\n     * @param current Current progress value. Irrelevant in non-determinate mode.\n     */\n    @AnyThread\n    public final void postUpdate(float current) {\n        postUpdate(getLastMax(), current, getLastMessage());\n    }\n\n    /**\n     * Update progress from any thread. Arguments from the last time are used.\n     *\n     * @param max     Max progress values. Use {@code -1} to switch to non-determinate mode.\n     * @param current Current progress value. Irrelevant in non-determinate mode.\n     */\n    @AnyThread\n    public final void postUpdate(int max, float current) {\n        postUpdate(max, current, getLastMessage());\n    }\n\n    /**\n     * Update progress from any thread.\n     *\n     * @param max     Max progress values. Use {@code -1} to switch to non-determinate mode.\n     * @param current Current progress value. Irrelevant in non-determinate mode.\n     * @param message Additional arguments to pass on. Depends on implementation.\n     */\n    @SuppressLint(\"WrongThread\")\n    @AnyThread\n    @CallSuper\n    public void postUpdate(int max, float current, @Nullable Object message) {\n        if (ThreadUtils.isMainThread()) {\n            onProgressUpdate(max, current, message);\n        } else {\n            ThreadUtils.postOnMainThread(() -> onProgressUpdate(max, current, message));\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/progress/QueuedProgressHandler.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.progress;\n\nimport androidx.annotation.MainThread;\nimport androidx.annotation.Nullable;\n\npublic abstract class QueuedProgressHandler extends ProgressHandler {\n    /**\n     * Call when items are added to queue. This can be unrelated to progress, but useful in situations where queues\n     * need to be handled.\n     */\n    @MainThread\n    public abstract void onQueue(@Nullable Object message);\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/rules/PseudoRules.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.rules;\n\nimport android.os.RemoteException;\n\nimport androidx.annotation.NonNull;\n\nimport java.io.IOException;\n\nimport io.github.muntashirakon.io.Path;\nimport io.github.muntashirakon.io.Paths;\n\npublic class PseudoRules extends RulesStorageManager {\n    public PseudoRules(@NonNull String packageName, int userHandle) {\n        super(packageName, userHandle);\n        setReadOnly();\n    }\n\n    @Override\n    public void setMutable() {\n        // Do nothing\n    }\n\n    public void loadExternalEntries(Path file) throws IOException, RemoteException {\n        super.loadEntries(file, true);\n    }\n\n    /**\n     * No rules will be loaded\n     *\n     * @return /dev/null\n     */\n    @NonNull\n    @Override\n    protected Path getDesiredFile(boolean create) {\n        return Paths.get(\"/dev/null\");\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/rules/RuleType.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.rules;\n\nimport androidx.annotation.Keep;\n\n@Keep\npublic enum RuleType {\n    ACTIVITY,\n    PROVIDER,\n    RECEIVER,\n    SERVICE,\n    APP_OP,\n    PERMISSION,\n    MAGISK_HIDE,\n    MAGISK_DENY_LIST,\n    BATTERY_OPT,\n    NET_POLICY,\n    NOTIFICATION,\n    URI_GRANT,\n    SSAID,\n    FREEZE,\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/rules/RulesExporter.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.rules;\n\nimport android.content.Context;\nimport android.net.Uri;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport java.io.IOException;\nimport java.io.OutputStream;\nimport java.util.List;\n\nimport io.github.muntashirakon.AppManager.rules.compontents.ComponentUtils;\nimport io.github.muntashirakon.AppManager.rules.compontents.ComponentsBlocker;\nimport io.github.muntashirakon.AppManager.utils.ContextUtils;\n\n/**\n * Export rules to external directory either for a single package or multiple packages.\n *\n * @see RulesImporter\n */\npublic class RulesExporter {\n    @NonNull\n    private final Context mContext;\n    @Nullable\n    private List<String> mPackagesToExport;\n    @NonNull\n    private final List<RuleType> mTypesToExport;\n    @NonNull\n    private final int[] mUserIds;\n\n    public RulesExporter(@NonNull List<RuleType> typesToExport, @Nullable List<String> packagesToExport,\n                         @NonNull int[] userIds) {\n        mContext = ContextUtils.getContext();\n        mPackagesToExport = packagesToExport;\n        mTypesToExport = typesToExport;\n        mUserIds = userIds;\n    }\n\n    public void saveRules(Uri uri) throws IOException {\n        if (mPackagesToExport == null) mPackagesToExport = ComponentUtils.getAllPackagesWithRules(mContext);\n        try (OutputStream outputStream = mContext.getContentResolver().openOutputStream(uri)) {\n            if (outputStream == null) throw new IOException(\"Content provider has crashed.\");\n            for (String packageName: mPackagesToExport) {\n                for (int userHandle : mUserIds) {\n                    // Get a read-only instance\n                    try (ComponentsBlocker cb = ComponentsBlocker.getInstance(packageName, userHandle)) {\n                        ComponentUtils.storeRules(outputStream, cb.getAll(mTypesToExport), true);\n                    }\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/rules/RulesImporter.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.rules;\n\nimport android.net.Uri;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.WorkerThread;\n\nimport java.io.BufferedReader;\nimport java.io.Closeable;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.InputStreamReader;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\n\nimport io.github.muntashirakon.AppManager.rules.compontents.ComponentsBlocker;\nimport io.github.muntashirakon.AppManager.rules.struct.RuleEntry;\nimport io.github.muntashirakon.AppManager.utils.ContextUtils;\nimport io.github.muntashirakon.io.IoUtils;\nimport io.github.muntashirakon.io.Path;\n\n/**\n * Rules importer is used to import internal rules to App Manager. Rules should only be imported\n * from settings and app data restore sections (although can be exported from various places).\n * <br>\n * Format: <code>package_name component_name type mode|is_applied|is_granted</code>\n *\n * @see RulesExporter\n * @see RuleType\n */\npublic class RulesImporter implements Closeable {\n    @NonNull\n    private final HashMap<String, ComponentsBlocker>[] mComponentsBlockers;\n    @NonNull\n    private final List<RuleType> mTypesToImport;\n    @Nullable\n    private List<String> mPackagesToImport;\n    @NonNull\n    private final int[] mUserIds;\n\n    public RulesImporter(@NonNull List<RuleType> typesToImport, @NonNull int[] userIds) {\n        if (userIds.length == 0) {\n            throw new IllegalArgumentException(\"Input must contain one or more user handles\");\n        }\n        // Init CBs\n        //noinspection unchecked\n        mComponentsBlockers = new HashMap[userIds.length];\n        for (int i = 0; i < userIds.length; ++i) {\n            mComponentsBlockers[i] = new HashMap<>();\n        }\n        mTypesToImport = typesToImport;\n        mUserIds = userIds;\n    }\n\n    public void addRulesFromUri(Uri uri) throws IOException {\n        try (InputStream inputStream = ContextUtils.getContext().getContentResolver().openInputStream(uri)) {\n            if (inputStream == null) throw new IOException(\"Content provider has crashed.\");\n            try (BufferedReader TSVFile = new BufferedReader(new InputStreamReader(inputStream))) {\n                String dataRow;\n                while ((dataRow = TSVFile.readLine()) != null) {\n                    RuleEntry entry = RuleEntry.unflattenFromString(null, dataRow, true);\n                    // Parse complete, now add the row to CB\n                    for (int i = 0; i < mUserIds.length; ++i) {\n                        if (mComponentsBlockers[i].get(entry.packageName) == null) {\n                            // Get a read-only instance, commit will be called manually\n                            mComponentsBlockers[i].put(entry.packageName, ComponentsBlocker.getInstance(entry.packageName, mUserIds[i]));\n                        }\n                        if (mTypesToImport.contains(entry.type)) {\n                            //noinspection ConstantConditions Returned ComponentsBlocker will never be null here\n                            mComponentsBlockers[i].get(entry.packageName).addEntry(entry);\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n    public void addRulesFromPath(Path path) throws IOException {\n        try (InputStream inputStream = path.openInputStream()) {\n            try (BufferedReader TSVFile = new BufferedReader(new InputStreamReader(inputStream))) {\n                String dataRow;\n                while ((dataRow = TSVFile.readLine()) != null) {\n                    RuleEntry entry = RuleEntry.unflattenFromString(null, dataRow, true);\n                    // Parse complete, now add the row to CB\n                    for (int i = 0; i < mUserIds.length; ++i) {\n                        if (mComponentsBlockers[i].get(entry.packageName) == null) {\n                            // Get a read-only instance, commit will be called manually\n                            mComponentsBlockers[i].put(entry.packageName, ComponentsBlocker.getInstance(entry.packageName, mUserIds[i]));\n                        }\n                        if (mTypesToImport.contains(entry.type)) {\n                            //noinspection ConstantConditions Returned ComponentsBlocker will never be null here\n                            mComponentsBlockers[i].get(entry.packageName).addEntry(entry);\n                        }\n                    }\n                }\n            }\n        }\n    }\n\n    public List<String> getPackages() {\n        return new ArrayList<>(mComponentsBlockers[0].keySet());\n    }\n\n    public void setPackagesToImport(List<String> packageNames) {\n        mPackagesToImport = packageNames;\n    }\n\n    @WorkerThread\n    public void applyRules(boolean commitChanges) {\n        if (mPackagesToImport == null) mPackagesToImport = getPackages();\n        // When #setPackagesToImport(List<String>) is used, ComponentBlocker can be null\n        @Nullable ComponentsBlocker cb;\n        for (int i = 0; i < mUserIds.length; ++i) {\n            for (String packageName : mPackagesToImport) {\n                cb = mComponentsBlockers[i].get(packageName);\n                if (cb == null) continue;\n                // Set mutable, otherwise changes may not be applied properly\n                cb.setMutable();\n                // Apply component blocking rules\n                cb.applyRules(true);\n                // Apply app op and permissions\n                cb.applyAppOpsAndPerms();\n                // Store the changes or discard them\n                if (commitChanges) {\n                    // Commit changes\n                    cb.commit();\n                } else {\n                    // Don't commit changes, discard the rules\n                    cb.setReadOnly();\n                }\n            }\n        }\n    }\n\n    @Override\n    public void close() {\n        // When #setPackagesToImport(List<String>) is used, ComponentBlocker can be null\n        for (int i = 0; i < mUserIds.length; ++i) {\n            for (ComponentsBlocker cb : mComponentsBlockers[i].values()) {\n                IoUtils.closeQuietly(cb);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/rules/RulesStorageManager.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.rules;\n\nimport android.annotation.UserIdInt;\nimport android.content.Context;\nimport android.os.RemoteException;\n\nimport androidx.annotation.GuardedBy;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.WorkerThread;\n\nimport java.io.BufferedReader;\nimport java.io.Closeable;\nimport java.io.IOException;\nimport java.io.OutputStream;\nimport java.util.ArrayList;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.Objects;\n\nimport io.github.muntashirakon.AppManager.compat.AppOpsManagerCompat;\nimport io.github.muntashirakon.AppManager.compat.NetworkPolicyManagerCompat;\nimport io.github.muntashirakon.AppManager.compat.PermissionCompat;\nimport io.github.muntashirakon.AppManager.magisk.MagiskProcess;\nimport io.github.muntashirakon.AppManager.rules.compontents.ComponentUtils;\nimport io.github.muntashirakon.AppManager.rules.struct.AppOpRule;\nimport io.github.muntashirakon.AppManager.rules.struct.BatteryOptimizationRule;\nimport io.github.muntashirakon.AppManager.rules.struct.ComponentRule;\nimport io.github.muntashirakon.AppManager.rules.struct.FreezeRule;\nimport io.github.muntashirakon.AppManager.rules.struct.MagiskDenyListRule;\nimport io.github.muntashirakon.AppManager.rules.struct.MagiskHideRule;\nimport io.github.muntashirakon.AppManager.rules.struct.NetPolicyRule;\nimport io.github.muntashirakon.AppManager.rules.struct.NotificationListenerRule;\nimport io.github.muntashirakon.AppManager.rules.struct.PermissionRule;\nimport io.github.muntashirakon.AppManager.rules.struct.RuleEntry;\nimport io.github.muntashirakon.AppManager.rules.struct.SsaidRule;\nimport io.github.muntashirakon.AppManager.rules.struct.UriGrantRule;\nimport io.github.muntashirakon.AppManager.uri.UriManager;\nimport io.github.muntashirakon.AppManager.utils.ContextUtils;\nimport io.github.muntashirakon.AppManager.utils.FreezeUtils;\nimport io.github.muntashirakon.io.Path;\nimport io.github.muntashirakon.io.PathReader;\nimport io.github.muntashirakon.io.Paths;\n\npublic class RulesStorageManager implements Closeable {\n    @NonNull\n    private final ArrayList<RuleEntry> mEntries;\n\n    @GuardedBy(\"entries\")\n    @NonNull\n    protected String packageName;\n    @GuardedBy(\"entries\")\n    protected boolean readOnly = true;\n    @UserIdInt\n    protected int userId;\n\n    protected RulesStorageManager(@NonNull String packageName, @UserIdInt int userId) {\n        this.packageName = packageName;\n        this.userId = userId;\n        mEntries = new ArrayList<>();\n        try {\n            loadEntries(getDesiredFile(false), false);\n        } catch (Throwable ignored) {\n        }\n    }\n\n    public void setReadOnly() {\n        this.readOnly = true;\n    }\n\n    public void setMutable() {\n        this.readOnly = false;\n    }\n\n    @Override\n    public void close() {\n        if (!readOnly) commit();\n    }\n\n    @GuardedBy(\"entries\")\n    public <T extends RuleEntry> List<T> getAll(Class<T> type) {\n        synchronized (mEntries) {\n            List<T> newEntries = new ArrayList<>();\n            for (RuleEntry entry : mEntries) if (type.isInstance(entry)) newEntries.add(type.cast(entry));\n            return newEntries;\n        }\n    }\n\n    @GuardedBy(\"entries\")\n    public List<RuleEntry> getAll(List<RuleType> types) {\n        synchronized (mEntries) {\n            List<RuleEntry> newEntries = new ArrayList<>();\n            for (RuleEntry entry : mEntries) if (types.contains(entry.type)) newEntries.add(entry);\n            return newEntries;\n        }\n    }\n\n    @GuardedBy(\"entries\")\n    public List<ComponentRule> getAllComponents() {\n        return getAll(ComponentRule.class);\n    }\n\n    @GuardedBy(\"entries\")\n    public List<RuleEntry> getAll() {\n        synchronized (mEntries) {\n            return mEntries;\n        }\n    }\n\n    @GuardedBy(\"entries\")\n    public int entryCount() {\n        synchronized (mEntries) {\n            return mEntries.size();\n        }\n    }\n\n    @GuardedBy(\"entries\")\n    public void removeEntry(RuleEntry entry) {\n        synchronized (mEntries) {\n            mEntries.remove(entry);\n        }\n    }\n\n    @GuardedBy(\"entries\")\n    @Nullable\n    protected RuleEntry removeEntries(String name, RuleType type) {\n        synchronized (mEntries) {\n            Iterator<RuleEntry> entryIterator = mEntries.iterator();\n            RuleEntry entry = null;\n            while (entryIterator.hasNext()) {\n                entry = entryIterator.next();\n                if (entry.name.equals(name) && entry.type.equals(type)) {\n                    entryIterator.remove();\n                }\n            }\n            return entry;\n        }\n    }\n\n    protected void setComponent(String name, RuleType componentType, @ComponentRule.ComponentStatus String componentStatus) {\n        ComponentRule newRule = new ComponentRule(packageName, name, componentType, componentStatus);\n        RuleEntry oldRule = addUniqueEntry(newRule);\n        if (oldRule instanceof ComponentRule) {\n            newRule.setLastComponentStatus(((ComponentRule) oldRule).getComponentStatus());\n        }\n    }\n\n    public void setAppOp(int op, @AppOpsManagerCompat.Mode int mode) {\n        addUniqueEntry(new AppOpRule(packageName, op, mode));\n    }\n\n    public void setPermission(String name, boolean isGranted, @PermissionCompat.PermissionFlags int flags) {\n        addUniqueEntry(new PermissionRule(packageName, name, isGranted, flags));\n    }\n\n    public void setNotificationListener(String name, boolean isGranted) {\n        addUniqueEntry(new NotificationListenerRule(packageName, name, isGranted));\n    }\n\n    public void setMagiskHide(@NonNull MagiskProcess magiskProcess) {\n        addUniqueEntry(new MagiskHideRule(magiskProcess));\n    }\n\n    public void setMagiskDenyList(MagiskProcess magiskProcess) {\n        addUniqueEntry(new MagiskDenyListRule(magiskProcess));\n    }\n\n    public void setBatteryOptimization(boolean willOptimize) {\n        addUniqueEntry(new BatteryOptimizationRule(packageName, willOptimize));\n    }\n\n    public void setNetPolicy(@NetworkPolicyManagerCompat.NetPolicy int netPolicy) {\n        addUniqueEntry(new NetPolicyRule(packageName, netPolicy));\n    }\n\n    public void setUriGrant(@NonNull UriManager.UriGrant uriGrant) {\n        // There could be many UriGrants\n        addEntryInternal(new UriGrantRule(packageName, uriGrant));\n    }\n\n    public void setSsaid(@NonNull String ssaid) {\n        addUniqueEntry(new SsaidRule(packageName, ssaid));\n    }\n\n    public void setFreezeType(@FreezeUtils.FreezeMethod int freezeType) {\n        addUniqueEntry(new FreezeRule(packageName, freezeType));\n    }\n\n    /**\n     * Add entry, remove old entries depending on entry {@link RuleType}.\n     */\n    @GuardedBy(\"entries\")\n    public void addEntry(@NonNull RuleEntry entry) {\n        synchronized (mEntries) {\n            if (entry.type.equals(RuleType.URI_GRANT)) {\n                // UriGrant is not unique\n                addEntryInternal(entry);\n            } else addUniqueEntry(entry);\n        }\n    }\n\n    /**\n     * Remove the exact entry if exists before adding it.\n     */\n    @GuardedBy(\"entries\")\n    private void addEntryInternal(@NonNull RuleEntry entry) {\n        synchronized (mEntries) {\n            removeEntry(entry);\n            mEntries.add(entry);\n        }\n    }\n\n    /**\n     * Remove all entries of the given name and type before adding the entry.\n     */\n    @GuardedBy(\"entries\")\n    @Nullable\n    private RuleEntry addUniqueEntry(@NonNull RuleEntry entry) {\n        synchronized (mEntries) {\n            RuleEntry previousEntry = removeEntries(entry.name, entry.type);\n            mEntries.add(entry);\n            return previousEntry;\n        }\n    }\n\n    @GuardedBy(\"entries\")\n    protected void loadEntries(Path file, boolean isExternal) throws IOException {\n        String dataRow;\n        try (BufferedReader TSVFile = new BufferedReader(new PathReader(file))) {\n            while ((dataRow = TSVFile.readLine()) != null) {\n                RuleEntry entry = RuleEntry.unflattenFromString(packageName, dataRow, isExternal);\n                synchronized (mEntries) {\n                    mEntries.add(entry);\n                }\n            }\n        }\n    }\n\n    @WorkerThread\n    @GuardedBy(\"entries\")\n    public void commit() {\n        try {\n            saveEntries(getDesiredFile(true), false);\n        } catch (IOException | RemoteException ex) {\n            ex.printStackTrace();\n        }\n    }\n\n    @WorkerThread\n    @GuardedBy(\"entries\")\n    public void commitExternal(Path tsvRulesFile) {\n        try {\n            saveEntries(tsvRulesFile, true);\n        } catch (IOException | RemoteException ex) {\n            ex.printStackTrace();\n        }\n    }\n\n    @WorkerThread\n    @GuardedBy(\"entries\")\n    protected void saveEntries(Path tsvRulesFile, boolean isExternal) throws IOException, RemoteException {\n        synchronized (mEntries) {\n            if (mEntries.isEmpty()) {\n                tsvRulesFile.delete();\n                return;\n            }\n            try (OutputStream TSVFile = tsvRulesFile.openOutputStream()) {\n                ComponentUtils.storeRules(TSVFile, mEntries, isExternal);\n            }\n        }\n    }\n\n    @NonNull\n    public static Path getConfDir(@NonNull Context context) {\n        return Objects.requireNonNull(Paths.build(context.getFilesDir(), \"conf\"));\n    }\n\n    @NonNull\n    protected Path getDesiredFile(boolean create) throws IOException {\n        Path confDir = getConfDir(ContextUtils.getContext());\n        if (!confDir.exists()) {\n            confDir.mkdirs();\n        }\n        if (create) {\n            return confDir.findOrCreateFile(packageName + \".tsv\", null);\n        }\n        return confDir.findFile(packageName + \".tsv\");\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/rules/RulesTypeSelectionDialogFragment.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.rules;\n\nimport android.annotation.UserIdInt;\nimport android.app.Dialog;\nimport android.net.Uri;\nimport android.os.Bundle;\nimport android.os.PowerManager;\nimport android.os.UserHandleHidden;\n\nimport androidx.annotation.IntDef;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.core.os.BundleCompat;\nimport androidx.fragment.app.DialogFragment;\nimport androidx.fragment.app.FragmentActivity;\n\nimport java.io.IOException;\nimport java.lang.ref.WeakReference;\nimport java.util.ArrayList;\nimport java.util.HashSet;\nimport java.util.List;\n\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.logs.Log;\nimport io.github.muntashirakon.AppManager.settings.SettingsActivity;\nimport io.github.muntashirakon.AppManager.utils.CpuUtils;\nimport io.github.muntashirakon.AppManager.utils.ThreadUtils;\nimport io.github.muntashirakon.AppManager.utils.UIUtils;\nimport io.github.muntashirakon.dialog.SearchableMultiChoiceDialogBuilder;\n\npublic class RulesTypeSelectionDialogFragment extends DialogFragment {\n    public static final String TAG = \"RulesTypeSelectionDialogFragment\";\n    public static final String ARG_MODE = \"ARG_MODE\";  // int\n    public static final String ARG_URI = \"ARG_URI\";  // Uri\n    public static final String ARG_PKG = \"ARG_PKG\";  // Package Names or null (for all)\n    public static final String ARG_USERS = \"ARG_USERS\";  // Integer array of user handles\n\n    @IntDef(value = {\n            MODE_IMPORT,\n            MODE_EXPORT\n    })\n    public @interface Mode {\n    }\n\n    public static final int MODE_IMPORT = 1;\n    public static final int MODE_EXPORT = 2;\n\n    public static final RuleType[] RULE_TYPES = new RuleType[]{\n            RuleType.ACTIVITY,\n            RuleType.SERVICE,\n            RuleType.RECEIVER,\n            RuleType.PROVIDER,\n            RuleType.APP_OP,\n            RuleType.PERMISSION,\n    };\n\n    private FragmentActivity mActivity;\n    @Nullable\n    private Uri mUri;\n    private List<String> mPackages = null;\n    private HashSet<RuleType> mSelectedTypes;\n    @UserIdInt\n    private int[] mUserIds;\n\n    @NonNull\n    @Override\n    public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {\n        mActivity = requireActivity();\n        Bundle args = requireArguments();\n        @Mode int mode = args.getInt(ARG_MODE, MODE_EXPORT);\n        mPackages = args.getStringArrayList(ARG_PKG);\n        mUri = BundleCompat.getParcelable(args, ARG_URI, Uri.class);\n        mUserIds = args.getIntArray(ARG_USERS);\n        if (mUserIds == null) mUserIds = new int[]{UserHandleHidden.myUserId()};\n        if (mUri == null) return super.onCreateDialog(savedInstanceState);\n        List<Integer> ruleIndexes = new ArrayList<>();\n        for (int i = 0; i < RULE_TYPES.length; ++i) {\n            ruleIndexes.add(i);\n        }\n        mSelectedTypes = new HashSet<>(RULE_TYPES.length);\n        return new SearchableMultiChoiceDialogBuilder<>(mActivity, ruleIndexes, R.array.rule_types)\n                .setTitle(mode == MODE_IMPORT ? R.string.import_options : R.string.export_options)\n                .addSelections(ruleIndexes)\n                .setPositiveButton(mode == MODE_IMPORT ? R.string.pref_import : R.string.pref_export,\n                        (dialog1, which, selections) -> {\n                            for (int i : selections) {\n                                mSelectedTypes.add(RULE_TYPES[i]);\n                            }\n                            Log.d(\"TestImportExport\", \"Types: %s\\nURI: %s\", mSelectedTypes, mUri);\n                            if (mActivity instanceof SettingsActivity) {\n                                ((SettingsActivity) mActivity).progressIndicator.show();\n                            }\n                            if (mode == MODE_IMPORT) {\n                                handleImport();\n                            } else handleExport();\n                        })\n                .setNegativeButton(getResources().getString(R.string.cancel), null)\n                .create();\n    }\n\n    private void handleExport() {\n        if (mUri == null) {\n            return;\n        }\n        WeakReference<FragmentActivity> activityRef = new WeakReference<>(mActivity);\n        ThreadUtils.postOnBackgroundThread(() -> {\n            PowerManager.WakeLock wakeLock = CpuUtils.getPartialWakeLock(\"rules_exporter\");\n            wakeLock.acquire();\n            try {\n                RulesExporter exporter = new RulesExporter(new ArrayList<>(mSelectedTypes), mPackages, mUserIds);\n                exporter.saveRules(mUri);\n                ThreadUtils.postOnMainThread(() -> UIUtils.displayShortToast(R.string.the_export_was_successful));\n            } catch (IOException e) {\n                ThreadUtils.postOnMainThread(() -> UIUtils.displayLongToast(R.string.export_failed));\n            } finally {\n                CpuUtils.releaseWakeLock(wakeLock);\n            }\n            hideProgressBar(activityRef);\n        });\n    }\n\n    private void handleImport() {\n        if (mUri == null) {\n            return;\n        }\n        WeakReference<FragmentActivity> activityRef = new WeakReference<>(mActivity);\n        ThreadUtils.postOnBackgroundThread(() -> {\n            PowerManager.WakeLock wakeLock = CpuUtils.getPartialWakeLock(\"rules_exporter\");\n            wakeLock.acquire();\n            try (RulesImporter importer = new RulesImporter(new ArrayList<>(mSelectedTypes), mUserIds)) {\n                importer.addRulesFromUri(mUri);\n                if (mPackages != null) importer.setPackagesToImport(mPackages);\n                importer.applyRules(true);\n                ThreadUtils.postOnMainThread(() -> UIUtils.displayShortToast(R.string.the_import_was_successful));\n            } catch (IOException e) {\n                ThreadUtils.postOnMainThread(() -> UIUtils.displayLongToast(R.string.import_failed));\n            } finally {\n                CpuUtils.releaseWakeLock(wakeLock);\n            }\n            hideProgressBar(activityRef);\n        });\n    }\n\n    private void hideProgressBar(@NonNull WeakReference<FragmentActivity> activityRef) {\n        if (activityRef.get() instanceof SettingsActivity) {\n            ThreadUtils.postOnMainThread(() -> {\n                FragmentActivity activity = activityRef.get();\n                if (activity != null) {\n                    ((SettingsActivity) activity).progressIndicator.hide();\n                }\n            });\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/rules/compontents/ComponentUtils.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.rules.compontents;\n\nimport android.annotation.UserIdInt;\nimport android.app.AppOpsManager;\nimport android.content.ComponentName;\nimport android.content.Context;\nimport android.content.pm.PackageInfo;\nimport android.os.RemoteException;\nimport android.util.Xml;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.VisibleForTesting;\nimport androidx.annotation.WorkerThread;\n\nimport org.xmlpull.v1.XmlPullParser;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.stream.Collectors;\n\nimport io.github.muntashirakon.AppManager.StaticDataset;\nimport io.github.muntashirakon.AppManager.compat.AppOpsManagerCompat;\nimport io.github.muntashirakon.AppManager.compat.PermissionCompat;\nimport io.github.muntashirakon.AppManager.logs.Log;\nimport io.github.muntashirakon.AppManager.rules.RuleType;\nimport io.github.muntashirakon.AppManager.rules.RulesStorageManager;\nimport io.github.muntashirakon.AppManager.rules.struct.AppOpRule;\nimport io.github.muntashirakon.AppManager.rules.struct.ComponentRule;\nimport io.github.muntashirakon.AppManager.rules.struct.PermissionRule;\nimport io.github.muntashirakon.AppManager.rules.struct.RuleEntry;\nimport io.github.muntashirakon.AppManager.types.UserPackagePair;\nimport io.github.muntashirakon.AppManager.utils.PackageUtils;\nimport io.github.muntashirakon.io.Path;\nimport io.github.muntashirakon.io.Paths;\n\npublic final class ComponentUtils {\n    public static boolean isTracker(String componentName) {\n        return StaticDataset.getSearchableTrackerSignatures().search(componentName).length > 0;\n    }\n\n    public static int getTrackerComponentsCountForPackage(PackageInfo packageInfo) {\n        HashMap<String, RuleType> components = PackageUtils.collectComponentClassNames(packageInfo);\n        return (int) components.keySet().stream()\n                .filter(ComponentUtils::isTracker)\n                .count();\n    }\n\n    @NonNull\n    public static Map<String, RuleType> getTrackerComponentsForPackage(PackageInfo packageInfo) {\n        HashMap<String, RuleType> components = PackageUtils.collectComponentClassNames(packageInfo);\n        return components.entrySet().stream()\n                .filter(entry -> isTracker(entry.getKey()))\n                .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));\n    }\n\n    @NonNull\n    public static Map<String, RuleType> getTrackerComponentsForPackage(String packageName, @UserIdInt int userHandle) {\n        HashMap<String, RuleType> components = PackageUtils.collectComponentClassNames(packageName, userHandle);\n        return components.entrySet().stream()\n                .filter(entry -> isTracker(entry.getKey()))\n                .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));\n    }\n\n    public static void blockTrackingComponents(@NonNull UserPackagePair pair) {\n        Map<String, RuleType> components = ComponentUtils.getTrackerComponentsForPackage(pair.getPackageName(), pair.getUserId());\n        try (ComponentsBlocker cb = ComponentsBlocker.getMutableInstance(pair.getPackageName(), pair.getUserId())) {\n            for (String componentName : components.keySet()) {\n                cb.addComponent(componentName, Objects.requireNonNull(components.get(componentName)));\n            }\n            cb.applyRules(true);\n        }\n    }\n\n    @WorkerThread\n    @NonNull\n    public static List<UserPackagePair> blockTrackingComponents(@NonNull Collection<UserPackagePair> userPackagePairs) {\n        List<UserPackagePair> failedPkgList = new ArrayList<>();\n        for (UserPackagePair pair : userPackagePairs) {\n            try {\n                blockTrackingComponents(pair);\n            } catch (Exception e) {\n                e.printStackTrace();\n                failedPkgList.add(pair);\n            }\n        }\n        return failedPkgList;\n    }\n\n    public static void unblockTrackingComponents(@NonNull UserPackagePair pair) {\n        Map<String, RuleType> components = getTrackerComponentsForPackage(pair.getPackageName(), pair.getUserId());\n        try (ComponentsBlocker cb = ComponentsBlocker.getMutableInstance(pair.getPackageName(), pair.getUserId())) {\n            for (String componentName : components.keySet()) {\n                cb.removeComponent(componentName);\n            }\n            cb.applyRules(true);\n        }\n    }\n\n    @WorkerThread\n    @NonNull\n    public static List<UserPackagePair> unblockTrackingComponents(@NonNull Collection<UserPackagePair> userPackagePairs) {\n        List<UserPackagePair> failedPkgList = new ArrayList<>();\n        for (UserPackagePair pair : userPackagePairs) {\n            try {\n                unblockTrackingComponents(pair);\n            } catch (Exception e) {\n                e.printStackTrace();\n                failedPkgList.add(pair);\n            }\n        }\n        return failedPkgList;\n    }\n\n    public static void blockFilteredComponents(@NonNull UserPackagePair pair, String[] signatures) {\n        HashMap<String, RuleType> components = PackageUtils.getFilteredComponents(pair.getPackageName(), pair.getUserId(), signatures);\n        try (ComponentsBlocker cb = ComponentsBlocker.getMutableInstance(pair.getPackageName(), pair.getUserId())) {\n            for (String componentName : components.keySet()) {\n                cb.addComponent(componentName, Objects.requireNonNull(components.get(componentName)));\n            }\n            cb.applyRules(true);\n        }\n    }\n\n    public static void unblockFilteredComponents(@NonNull UserPackagePair pair, String[] signatures) {\n        HashMap<String, RuleType> components = PackageUtils.getFilteredComponents(pair.getPackageName(), pair.getUserId(), signatures);\n        try (ComponentsBlocker cb = ComponentsBlocker.getMutableInstance(pair.getPackageName(), pair.getUserId())) {\n            for (String componentName : components.keySet()) {\n                cb.removeComponent(componentName);\n            }\n            cb.applyRules(true);\n        }\n    }\n\n    public static void storeRules(@NonNull OutputStream os, @NonNull List<RuleEntry> rules, boolean isExternal)\n            throws IOException {\n        for (RuleEntry entry : rules) {\n            os.write((entry.flattenToString(isExternal) + \"\\n\").getBytes());\n        }\n    }\n\n    @NonNull\n    public static List<String> getAllPackagesWithRules(@NonNull Context context) {\n        List<String> packages = new ArrayList<>();\n        Path confDir = RulesStorageManager.getConfDir(context);\n        Path[] paths = confDir.listFiles((dir, name) -> name.endsWith(\".tsv\"));\n        for (Path path : paths) {\n            packages.add(Paths.trimPathExtension(path.getUri().getLastPathSegment()));\n        }\n        return packages;\n    }\n\n    @WorkerThread\n    public static void removeAllRules(@NonNull String packageName, int userHandle) {\n        int uid = PackageUtils.getAppUid(new UserPackagePair(packageName, userHandle));\n        try (ComponentsBlocker cb = ComponentsBlocker.getMutableInstance(packageName, userHandle)) {\n            // Remove all blocking rules\n            for (ComponentRule entry : cb.getAllComponents()) {\n                cb.removeComponent(entry.name);\n            }\n            cb.applyRules(true);\n            // Reset configured app ops\n            AppOpsManagerCompat appOpsManager = new AppOpsManagerCompat();\n            try {\n                appOpsManager.resetAllModes(userHandle, packageName);\n                for (AppOpRule entry : cb.getAll(AppOpRule.class)) {\n                    try {\n                        appOpsManager.setMode(entry.getOp(), uid, packageName, AppOpsManager.MODE_DEFAULT);\n                        cb.removeEntry(entry);\n                    } catch (Exception e) {\n                        e.printStackTrace();\n                    }\n                }\n            } catch (Exception e) {\n                e.printStackTrace();\n            }\n            // Grant configured permissions\n            for (PermissionRule entry : cb.getAll(PermissionRule.class)) {\n                try {\n                    PermissionCompat.grantPermission(packageName, entry.name, userHandle);\n                    cb.removeEntry(entry);\n                } catch (RemoteException e) {\n                    Log.e(\"ComponentUtils\", \"Cannot revoke permission %s for package %s\", e, entry.name,\n                            packageName);\n                }\n            }\n        }\n    }\n\n    @NonNull\n    public static HashMap<String, RuleType> getIFWRulesForPackage(@NonNull String packageName) {\n        return getIFWRulesForPackage(packageName, Paths.get(ComponentsBlocker.SYSTEM_RULES_PATH));\n    }\n\n    @VisibleForTesting\n    @NonNull\n    public static HashMap<String, RuleType> getIFWRulesForPackage(@NonNull String packageName, @NonNull Path path) {\n        HashMap<String, RuleType> rules = new HashMap<>();\n        Path[] files = path.listFiles((dir, name) -> {\n            // For our case, name must start with package name to support apps like Watt, Blocker and MyAndroidTools,\n            // and to prevent unwanted situation, such as when the contains unsupported tags such as intent-filter.\n            return name.startsWith(packageName) && name.endsWith(\".xml\");\n        });\n        for (Path ifwRulesFile : files) {\n            // Get file contents\n            try (InputStream inputStream = ifwRulesFile.openInputStream()) {\n                // Read rules\n                rules.putAll(readIFWRules(inputStream, packageName));\n            } catch (IOException e) {\n                e.printStackTrace();\n            }\n        }\n        return rules;\n    }\n\n    public static final String TAG_RULES = \"rules\";\n\n    public static final String TAG_ACTIVITY = \"activity\";\n    public static final String TAG_BROADCAST = \"broadcast\";\n    public static final String TAG_SERVICE = \"service\";\n\n    @NonNull\n    public static HashMap<String, RuleType> readIFWRules(@NonNull InputStream inputStream, @NonNull String packageName) {\n        HashMap<String, RuleType> rules = new HashMap<>();\n        XmlPullParser parser = Xml.newPullParser();\n        try {\n            parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false);\n            parser.setInput(inputStream, null);\n            parser.nextTag();\n            parser.require(XmlPullParser.START_TAG, null, TAG_RULES);\n            int event = parser.nextTag();\n            RuleType componentType = null;\n            while (event != XmlPullParser.END_DOCUMENT) {\n                String name = parser.getName();\n                switch (event) {\n                    case XmlPullParser.START_TAG:\n                        if (name.equals(TAG_ACTIVITY) || name.equals(TAG_BROADCAST) || name.equals(TAG_SERVICE)) {\n                            componentType = getComponentType(name);\n                        }\n                        break;\n                    case XmlPullParser.END_TAG:\n                        if (name.equals(\"component-filter\")) {\n                            String fullKey = parser.getAttributeValue(null, \"name\");\n                            ComponentName cn = ComponentName.unflattenFromString(fullKey);\n                            if (cn.getPackageName().equals(packageName)) {\n                                rules.put(cn.getClassName(), componentType);\n                            }\n                        }\n                }\n                event = parser.nextTag();\n            }\n        } catch (Throwable ignore) {\n            // The file contains errors, simply ignore\n        }\n        return rules;\n    }\n\n    /**\n     * Get component type from TAG_* constants\n     *\n     * @param componentTag Name of the constant: one of the TAG_*\n     * @return One of the {@link RuleType}\n     */\n    @Nullable\n    static RuleType getComponentType(@NonNull String componentTag) {\n        switch (componentTag) {\n            case TAG_ACTIVITY:\n                return RuleType.ACTIVITY;\n            case TAG_BROADCAST:\n                return RuleType.RECEIVER;\n            case TAG_SERVICE:\n                return RuleType.SERVICE;\n            default:\n                return null;\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/rules/compontents/ComponentsBlocker.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.rules.compontents;\n\nimport static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DEFAULT;\nimport static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_DISABLED;\nimport static android.content.pm.PackageManager.COMPONENT_ENABLED_STATE_ENABLED;\nimport static android.content.pm.PackageManager.DONT_KILL_APP;\nimport static io.github.muntashirakon.AppManager.compat.PackageManagerCompat.MATCH_DISABLED_COMPONENTS;\nimport static io.github.muntashirakon.AppManager.compat.PackageManagerCompat.MATCH_UNINSTALLED_PACKAGES;\n\nimport android.app.AppOpsManager;\nimport android.content.ComponentName;\nimport android.content.Context;\nimport android.content.pm.PackageInfo;\nimport android.content.pm.PackageManager;\nimport android.os.Build;\nimport android.os.RemoteException;\nimport android.system.ErrnoException;\n\nimport androidx.annotation.GuardedBy;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.WorkerThread;\n\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.Set;\n\nimport io.github.muntashirakon.AppManager.compat.AppOpsManagerCompat;\nimport io.github.muntashirakon.AppManager.compat.ApplicationInfoCompat;\nimport io.github.muntashirakon.AppManager.compat.PackageManagerCompat;\nimport io.github.muntashirakon.AppManager.logs.Log;\nimport io.github.muntashirakon.AppManager.permission.PermUtils;\nimport io.github.muntashirakon.AppManager.permission.Permission;\nimport io.github.muntashirakon.AppManager.rules.RuleType;\nimport io.github.muntashirakon.AppManager.rules.RulesStorageManager;\nimport io.github.muntashirakon.AppManager.rules.struct.AppOpRule;\nimport io.github.muntashirakon.AppManager.rules.struct.ComponentRule;\nimport io.github.muntashirakon.AppManager.rules.struct.PermissionRule;\nimport io.github.muntashirakon.AppManager.rules.struct.RuleEntry;\nimport io.github.muntashirakon.AppManager.self.SelfPermissions;\nimport io.github.muntashirakon.AppManager.settings.Prefs;\nimport io.github.muntashirakon.AppManager.utils.PackageUtils;\nimport io.github.muntashirakon.io.AtomicExtendedFile;\nimport io.github.muntashirakon.io.Paths;\n\n/**\n * Block application components: activities, broadcasts, services and providers.\n * <p>\n * Activities, broadcasts and services are blocked via Intent Firewall (which is superior to\n * <code>pm disable <b>component</b></code>). Rules for each package is saved as a separate tsv file\n * named after its package name and saved to {@code /data/data/${applicationId}/files/conf}. In case\n * of activities, broadcasts and services, the rules are finally saved to {@link #SYSTEM_RULES_PATH}.\n * <p>\n * Providers are blocked via {@link PackageManager#setComponentEnabledSetting(ComponentName, int, int)}\n * since there's no way to block them via Intent Firewall. Blocked providers are only kept in the\n * {@code /data/data/${applicationId}/files/conf} directory.\n *\n * @see <a href=\"https://android.googlesource.com/platform/frameworks/base/+/refs/heads/master/services/core/java/com/android/server/firewall/IntentFirewall.java\">IntentFirewall.java</a>\n */\npublic final class ComponentsBlocker extends RulesStorageManager {\n    public static final String TAG = \"ComponentBlocker\";\n\n    public static final String SYSTEM_RULES_PATH;\n\n    static {\n        SYSTEM_RULES_PATH = Build.VERSION.SDK_INT <= Build.VERSION_CODES.M ? \"/data/secure/system/ifw\"\n                : \"/data/system/ifw\";\n    }\n\n    /**\n     * Get a new or existing IMMUTABLE instance of {@link ComponentsBlocker}. The existing instance\n     * will only be returned if the existing instance has the same package name as the original.\n     * This reads rules from the {@link #SYSTEM_RULES_PATH}. If reading rules is necessary, use\n     * {@link #getInstance(String, int, boolean)} with the last argument set to true. It is also\n     * possible to make this instance mutable by calling {@link #setMutable()} and once set mutable,\n     * closing this instance will commit the changes automatically. To prevent this,\n     * {@link #setReadOnly()} should be called before closing the instance.\n     *\n     * @param packageName The package whose instance is to be returned\n     * @param userHandle  The user to whom the rules belong\n     * @return New or existing immutable instance for the package\n     * @see #getInstance(String, int, boolean)\n     * @see #getMutableInstance(String, int)\n     */\n    @NonNull\n    public static ComponentsBlocker getInstance(@NonNull String packageName, int userHandle) {\n        return getInstance(packageName, userHandle, true);\n    }\n\n    /**\n     * Get a new or existing MUTABLE instance of {@link ComponentsBlocker}. This DOES NOT read rules\n     * from the {@link #SYSTEM_RULES_PATH}. This is essentially the same as calling\n     * {@link #getInstance(String, int, boolean)} with the last argument set to {@code true} and\n     * calling {@link #setMutable()} after that. Closing this instance will commit the changes\n     * automatically. To prevent this, {@link #setReadOnly()} should be called before closing\n     * the instance.\n     *\n     * @param packageName The package whose instance is to be returned\n     * @param userHandle  The user to whom the rules belong\n     * @return New or existing mutable instance for the package\n     * @see #getInstance(String, int)\n     * @see #getInstance(String, int, boolean)\n     */\n    @NonNull\n    public static ComponentsBlocker getMutableInstance(@NonNull String packageName, int userHandle) {\n        ComponentsBlocker componentsBlocker = getInstance(packageName, userHandle, false);\n        componentsBlocker.readOnly = false;\n        return componentsBlocker;\n    }\n\n    /**\n     * Get a new or existing IMMUTABLE instance of {@link ComponentsBlocker}. The existing instance\n     * will only be returned if the existing instance has the same package name as the original. It\n     * is also possible to make this instance mutable by calling {@link #setMutable()} and once set\n     * mutable, closing this instance will commit the changes automatically. To prevent this,\n     * {@link #setReadOnly()} should be called before closing the instance.\n     *\n     * @param packageName    The package whose instance is to be returned\n     * @param userHandle     The user to whom the rules belong\n     * @param reloadFromDisk Whether to load rules from the {@link #SYSTEM_RULES_PATH}\n     * @return New or existing immutable instance for the package\n     * @see #getInstance(String, int)\n     * @see #getMutableInstance(String, int)\n     */\n    @NonNull\n    public static ComponentsBlocker getInstance(@NonNull String packageName, int userHandle, boolean reloadFromDisk) {\n        Objects.requireNonNull(packageName);\n        ComponentsBlocker blocker = new ComponentsBlocker(packageName, userHandle);\n        if (reloadFromDisk && SelfPermissions.canBlockByIFW()) {\n            blocker.retrieveDisabledComponents();\n            blocker.invalidateComponents();\n        }\n        blocker.readOnly = true;\n        return blocker;\n    }\n\n    @NonNull\n    private final AtomicExtendedFile mRulesFile;\n    @Nullable\n    private Set<String> mComponents;\n    @Nullable\n    private PackageInfo mPackageInfo;\n\n    private ComponentsBlocker(@NonNull String packageName, int userHandle) {\n        super(packageName, userHandle);\n        mRulesFile = new AtomicExtendedFile(Objects.requireNonNull(Paths.get(SYSTEM_RULES_PATH).getFile())\n                .getChildFile(packageName + \".xml\"));\n        try {\n            mPackageInfo = PackageManagerCompat.getPackageInfo(packageName, PackageManager.GET_ACTIVITIES\n                    | PackageManager.GET_RECEIVERS | PackageManager.GET_PROVIDERS | MATCH_DISABLED_COMPONENTS\n                    | MATCH_UNINSTALLED_PACKAGES | PackageManager.GET_SERVICES\n                    | PackageManagerCompat.MATCH_STATIC_SHARED_AND_SDK_LIBRARIES, userHandle);\n        } catch (Throwable e) {\n            Log.e(TAG, e.getMessage(), e);\n        }\n        mComponents = mPackageInfo != null ? PackageUtils.collectComponentClassNames(mPackageInfo).keySet() : null;\n    }\n\n    /**\n     * Reload package components\n     */\n    public void reloadComponents() {\n        mComponents = mPackageInfo != null ? PackageUtils.collectComponentClassNames(mPackageInfo).keySet() : null;\n    }\n\n    /**\n     * Apply all rules configured within App Manager. This also includes {@link #SYSTEM_RULES_PATH}.\n     *\n     * @param context    Application Context\n     * @param userHandle The user to apply rules\n     * @return {@code true} iff all rules are applied correctly.\n     */\n    @WorkerThread\n    public static boolean applyAllRules(@NonNull Context context, int userHandle) {\n        // Apply all rules from conf folder\n        File confPath = new File(context.getFilesDir(), \"conf\");\n        String[] packageNamesWithTSVExt = confPath.list((dir, name) -> name.endsWith(\".tsv\"));\n        boolean isSuccessful = true;\n        if (packageNamesWithTSVExt != null) {\n            // Apply rules\n            for (String packageNameWithTSVExt : packageNamesWithTSVExt) {\n                try (ComponentsBlocker cb = getMutableInstance(Paths.trimPathExtension(packageNameWithTSVExt), userHandle)) {\n                    isSuccessful &= cb.applyRules(true);\n                }\n            }\n        }\n        return isSuccessful;\n    }\n\n    /**\n     * Whether the given component is blocked.\n     *\n     * @param componentName The component name to check\n     * @return {@code true} if blocked, {@code false} otherwise\n     */\n    public boolean isComponentBlocked(String componentName) {\n        ComponentRule cr = getComponent(componentName);\n        return cr != null && cr.isBlocked();\n    }\n\n    /**\n     * Check if the given component exists in the rules. It does not necessarily mean that the\n     * component is being blocked.\n     *\n     * @param componentName The component name to check\n     * @return {@code true} if exists, {@code false} otherwise\n     * @see ComponentsBlocker#isComponentBlocked(String)\n     */\n    @GuardedBy(\"entries\")\n    public boolean hasComponentName(String componentName) {\n        for (ComponentRule entry : getAllComponents()) if (entry.name.equals(componentName)) return true;\n        return false;\n    }\n\n    /**\n     * Get number of components among other rules.\n     *\n     * @return Number of components\n     */\n    public int componentCount() {\n        int count = 0;\n        for (ComponentRule entry : getAllComponents()) {\n            if (!entry.toBeRemoved()) ++count;\n        }\n        return count;\n    }\n\n    @Nullable\n    public ComponentRule getComponent(String componentName) {\n        for (ComponentRule rule : getAllComponents()) {\n            if (rule.name.equals(componentName)) return rule;\n        }\n        return null;\n    }\n\n    /**\n     * Add the given component to the rules list with user preferred component status, does nothing if the instance is\n     * immutable.\n     *\n     * @param componentName The component to add\n     * @param componentType Component type\n     * @see #addEntry(RuleEntry)\n     */\n    public void addComponent(String componentName, RuleType componentType) {\n        if (!readOnly) setComponent(componentName, componentType, Prefs.Blocking.getDefaultBlockingMethod());\n    }\n\n    /**\n     * Add the given component to the rules list, does nothing if the instance is immutable.\n     *\n     * @param componentName   The component to add\n     * @param componentType   Component type\n     * @param componentStatus Component status\n     * @see #addEntry(RuleEntry)\n     */\n    public void addComponent(String componentName,\n                             RuleType componentType,\n                             @ComponentRule.ComponentStatus String componentStatus) {\n        if (!readOnly) setComponent(componentName, componentType, componentStatus);\n    }\n\n    /**\n     * Suggest removal of the given component from the rules, does nothing if the instance is\n     * immutable or the component does not exist. The rules are only applied when {@link #commit()}\n     * is called.\n     *\n     * @param componentName The component to remove\n     * @see #removeEntry(RuleEntry)\n     * @see #deleteComponent(String)\n     */\n    public void removeComponent(String componentName) {\n        if (readOnly) return;\n        ComponentRule cr = getComponent(componentName);\n        if (cr != null) {\n            setComponent(componentName, cr.type, ComponentRule.COMPONENT_TO_BE_DEFAULTED);\n        }\n    }\n\n    /**\n     * Remove component from the list rules without triggering a component removal request, does nothing\n     * if the instance is immutable or the component does not exist. The rules are only applied when\n     * {@link #commit()} is called.\n     *\n     * @param componentName The component to remove\n     * @see #removeEntry(RuleEntry)\n     * @see #removeComponent(String)\n     */\n    public void deleteComponent(String componentName) {\n        if (readOnly) return;\n        ComponentRule cr = getComponent(componentName);\n        if (cr != null) {\n            removeEntries(componentName, cr.type);\n        }\n    }\n\n    /**\n     * Save the disabled components in the {@link #SYSTEM_RULES_PATH}.\n     *\n     * @return {@code true} iff the components could be saved.\n     */\n    private boolean saveDisabledComponents(boolean apply) {\n        if (readOnly) {\n            Log.e(TAG, \"Read-only instance.\");\n            return false;\n        }\n        if (!apply || componentCount() == 0) {\n            // No components set, delete if already exists\n            mRulesFile.delete();\n            return true;\n        }\n        StringBuilder activities = new StringBuilder();\n        StringBuilder services = new StringBuilder();\n        StringBuilder receivers = new StringBuilder();\n        for (ComponentRule component : getAllComponents()) {\n            // Ignore components requiring unblocking\n            if (!component.isIfw()) continue;\n            String componentFilter = \"  <component-filter name=\\\"\" + packageName + \"/\" + component.name + \"\\\"/>\\n\";\n            switch (component.type) {\n                case ACTIVITY:\n                    activities.append(componentFilter);\n                    break;\n                case RECEIVER:\n                    receivers.append(componentFilter);\n                    break;\n                case SERVICE:\n                    services.append(componentFilter);\n                    break;\n                case PROVIDER:\n            }\n        }\n\n        String rules = \"<rules>\\n\" +\n                ((activities.length() == 0) ? \"\" : \"<activity block=\\\"true\\\" log=\\\"false\\\">\\n\" + activities + \"</activity>\\n\") +\n                ((services.length() == 0) ? \"\" : \"<service block=\\\"true\\\" log=\\\"false\\\">\\n\" + services + \"</service>\\n\") +\n                ((receivers.length() == 0) ? \"\" : \"<broadcast block=\\\"true\\\" log=\\\"false\\\">\\n\" + receivers + \"</broadcast>\\n\") +\n                \"</rules>\";\n        // Save rules\n        FileOutputStream rulesStream = null;\n        try {\n            rulesStream = mRulesFile.startWrite();\n            Log.d(TAG, \"Rules: %s\", rules);\n            rulesStream.write(rules.getBytes());\n            mRulesFile.finishWrite(rulesStream);\n            //noinspection OctalInteger\n            mRulesFile.getBaseFile().setMode(0666);\n            return true;\n        } catch (IOException e) {\n            Log.e(TAG, \"Failed to write rules for package %s\", e, packageName);\n            mRulesFile.failWrite(rulesStream);\n            return false;\n        } catch (ErrnoException e) {\n            Log.w(TAG, \"Failed to alter permission of IFW for package %s\", e, packageName);\n            return true;\n        }\n    }\n\n    /**\n     * Find if there is any component that needs blocking. Previous implementations checked for\n     * rules file in the system IFW directory as well, but since all controls are now inside the app\n     * itself, it's no longer deemed necessary to check the existence of the file. Besides, previous\n     * implementation (which was similar to Watt's) did not take providers into account, which are\n     * blocked via {@code pm}.\n     *\n     * @return {@code true} if there's no pending rules, {@code false} otherwise\n     */\n    public boolean isRulesApplied() {\n        List<ComponentRule> entries = getAllComponents();\n        for (ComponentRule entry : entries) {\n            if (!entry.isApplied()) {\n                return false;\n            }\n        }\n        return true;\n    }\n\n    /**\n     * Apply the currently modified rules if the argument apply is true. Since IFW is used, when\n     * apply is true, the IFW rules are saved to {@link #SYSTEM_RULES_PATH} and components that are\n     * set to be removed or unblocked will be removed. If apply is set to false, all rules will be\n     * removed but before that all components will be set to their default state (ie., the state\n     * described in the app manifest).\n     *\n     * @param apply Whether to apply the rules or remove them altogether.\n     * @return {@code true} iff all rules are applied correctly.\n     */\n    @WorkerThread\n    public boolean applyRules(boolean apply) {\n        // Check root. If no root is present, check if the app is test-only.\n        if (!SelfPermissions.canModifyAppComponentStates(userId, packageName, mPackageInfo != null\n                && ApplicationInfoCompat.isTestOnly(mPackageInfo.applicationInfo))) {\n            return false;\n        }\n        // Validate components\n        validateComponents();\n        // Save blocked IFW components or remove them based on the value of apply\n        if (SelfPermissions.canBlockByIFW() && !saveDisabledComponents(apply)) {\n            return false;\n        }\n        // Enable/disable components\n        List<ComponentRule> allEntries = getAllComponents();\n        Log.d(TAG, \"All: %s\", allEntries);\n        boolean isSuccessful = true;\n        if (apply) {\n            for (ComponentRule entry : allEntries) {\n                if (entry.applyDefaultState()) {\n                    // Need to set component state to default first and do nothing\n                    try {\n                        PackageManagerCompat.setComponentEnabledSetting(entry.getComponentName(),\n                                COMPONENT_ENABLED_STATE_DEFAULT, DONT_KILL_APP, userId);\n                        removeEntry(entry);\n                    } catch (Throwable e) {\n                        isSuccessful = false;\n                        Log.e(TAG, \"Could not enable component: %s/%s\", e, packageName, entry.name);\n                    }\n                }\n                switch (entry.getComponentStatus()) {\n                    case ComponentRule.COMPONENT_TO_BE_DEFAULTED:\n                        // Set component state to default and remove it\n                        try {\n                            PackageManagerCompat.setComponentEnabledSetting(\n                                    entry.getComponentName(), COMPONENT_ENABLED_STATE_DEFAULT,\n                                    DONT_KILL_APP, userId);\n                            removeEntry(entry);\n                        } catch (Throwable e) {\n                            isSuccessful = false;\n                            Log.e(TAG, \"Could not enable component: %s/%s\", e, packageName, entry.name);\n                        }\n                        break;\n                    case ComponentRule.COMPONENT_TO_BE_ENABLED:\n                        // Enable components\n                        try {\n                            PackageManagerCompat.setComponentEnabledSetting(\n                                    entry.getComponentName(), COMPONENT_ENABLED_STATE_ENABLED,\n                                    DONT_KILL_APP, userId);\n                            setComponent(entry.name, entry.type, ComponentRule.COMPONENT_ENABLED);\n                        } catch (Throwable e) {\n                            isSuccessful = false;\n                            Log.e(TAG, \"Could not disable component: %s/%s\", e, packageName, entry.name);\n                        }\n                        break;\n                    case ComponentRule.COMPONENT_TO_BE_BLOCKED_IFW:\n                        setComponent(entry.name, entry.type, ComponentRule.COMPONENT_BLOCKED_IFW);\n                        break;\n                    case ComponentRule.COMPONENT_TO_BE_BLOCKED_IFW_DISABLE:\n                    case ComponentRule.COMPONENT_TO_BE_DISABLED:\n                        // Disable components\n                        try {\n                            PackageManagerCompat.setComponentEnabledSetting(\n                                    entry.getComponentName(), COMPONENT_ENABLED_STATE_DISABLED,\n                                    DONT_KILL_APP, userId);\n                            setComponent(entry.name, entry.type, entry.getCounterpartOfToBe());\n                        } catch (Throwable e) {\n                            isSuccessful = false;\n                            Log.e(TAG, \"Could not disable component: %s/%s\", e, packageName, entry.name);\n                        }\n                        break;\n                    default:\n                        setComponent(entry.name, entry.type, entry.getCounterpartOfToBe());\n                }\n            }\n        } else {\n            // Enable all, remove to be removed components and set others to be blocked\n            for (ComponentRule entry : allEntries) {\n                // Enable components if they're disabled by other methods.\n                // IFW rules are already removed above.\n                try {\n                    PackageManagerCompat.setComponentEnabledSetting(entry.getComponentName(),\n                            COMPONENT_ENABLED_STATE_DEFAULT, DONT_KILL_APP,\n                            userId);\n                    if (entry.toBeRemoved()) {\n                        removeEntry(entry);\n                    } else setComponent(entry.name, entry.type, entry.getToBe());\n                } catch (Throwable e) {\n                    isSuccessful = false;\n                    Log.e(TAG, \"Could not enable component: %s/%s\", e, packageName, entry.name);\n                }\n            }\n        }\n        return isSuccessful;\n    }\n\n    /**\n     * Apply all configured app ops and permissions.\n     *\n     * @return {@code true} iff all the rules are applied correctly.\n     */\n    public boolean applyAppOpsAndPerms() {\n        if (mPackageInfo == null) {\n            return false;\n        }\n        boolean isSuccessful = true;\n        int uid = mPackageInfo.applicationInfo.uid;\n        AppOpsManagerCompat appOpsManager = new AppOpsManagerCompat();\n        // Apply all app ops\n        for (AppOpRule appOp : getAll(AppOpRule.class)) {\n            try {\n                appOpsManager.setMode(appOp.getOp(), uid, packageName, appOp.getMode());\n            } catch (Throwable e) {\n                isSuccessful = false;\n                Log.e(TAG, \"Could not set mode %d for app op %d\", e, appOp.getMode(), appOp.getOp());\n            }\n        }\n        // Apply all permissions\n        for (PermissionRule permissionRule : getAll(PermissionRule.class)) {\n            Permission permission = permissionRule.getPermission(true);\n            try {\n                permission.setAppOpAllowed(permission.getAppOp() != AppOpsManagerCompat.OP_NONE && appOpsManager\n                        .checkOperation(permission.getAppOp(), uid, packageName) == AppOpsManager.MODE_ALLOWED);\n                if (permission.isGranted()) {\n                    PermUtils.grantPermission(mPackageInfo, permission, appOpsManager, true, true);\n                } else {\n                    PermUtils.revokePermission(mPackageInfo, permission, appOpsManager, true);\n                }\n            } catch (Throwable e) {\n                isSuccessful = false;\n                Log.e(TAG, \"Could not %s %s\", e, (permission.isGranted() ? \"grant\" : \"revoke\"), permissionRule.name);\n            }\n        }\n        return isSuccessful;\n    }\n\n    /**\n     * Check if the components are up-to-date and remove the ones that are not up-to-date.\n     */\n    private void validateComponents() {\n        if (mComponents == null) {\n            // No validation required\n            return;\n        }\n        List<ComponentRule> allEntries = getAllComponents();\n        for (ComponentRule entry : allEntries) {\n            if (!mComponents.contains(entry.name)) {\n                // Remove non-existent components\n                removeEntry(entry);\n            }\n        }\n    }\n\n    /**\n     * Check all components that needs to be disabled/enabled and assign to be disabled/enabled if\n     * necessary.\n     */\n    public int invalidateComponents() {\n        int invalidated = 0;\n        boolean canCheckExistence = mComponents != null;\n        List<ComponentRule> allEntries = getAllComponents();\n        for (ComponentRule entry : allEntries) {\n            // First check if it actually exists\n            if (canCheckExistence && !mComponents.contains(entry.name)) {\n                removeEntry(entry);\n                ++invalidated;\n                continue;\n            }\n            try {\n                int s = PackageManagerCompat.getComponentEnabledSetting(new ComponentName(entry.packageName, entry.name), userId);\n                switch (entry.getComponentStatus()) {\n                    case ComponentRule.COMPONENT_BLOCKED_IFW_DISABLE:\n                    case ComponentRule.COMPONENT_DISABLED:\n                        // If component is enabled/defaulted, make it to be disabled\n                        if (s == COMPONENT_ENABLED_STATE_ENABLED\n                                || s == COMPONENT_ENABLED_STATE_DEFAULT) {\n                            addComponent(entry.name, entry.type, entry.getToBe());\n                            ++invalidated;\n                        }\n                        break;\n                    case ComponentRule.COMPONENT_ENABLED:\n                        // If component is not enabled, make it to be enabled\n                        if (s != COMPONENT_ENABLED_STATE_ENABLED) {\n                            addComponent(entry.name, entry.type, entry.getToBe());\n                            ++invalidated;\n                        }\n                        break;\n                }\n            } catch (Throwable ignore) {\n            }\n        }\n        return invalidated;\n    }\n\n    /**\n     * Retrieve a set of disabled components from the {@link #SYSTEM_RULES_PATH}. If they are\n     * available add them to the rules, overridden if necessary.\n     */\n    private void retrieveDisabledComponents() {\n        Log.d(TAG, \"Retrieving disabled components for package %s\", packageName);\n        if (!mRulesFile.exists() || mRulesFile.getBaseFile().length() == 0) {\n            // System doesn't have any rules.\n            // Load the rules saved inside App Manager\n            for (ComponentRule entry : getAllComponents()) {\n                setComponent(entry.name, entry.type, entry.getToBe());\n            }\n            return;\n        }\n        try (InputStream rulesStream = mRulesFile.openRead()) {\n            HashMap<String, RuleType> components = ComponentUtils.readIFWRules(rulesStream, packageName);\n            for (Map.Entry<String, RuleType> component : components.entrySet()) {\n                // Override existing rule for the component if it exists\n                setComponent(component.getKey(), component.getValue(), ComponentRule.COMPONENT_BLOCKED_IFW_DISABLE);\n            }\n            Log.d(TAG, \"Retrieved components for package %s\", packageName);\n        } catch (IOException | RemoteException ignored) {\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/rules/compontents/ExternalComponentsImporter.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.rules.compontents;\n\nimport static io.github.muntashirakon.AppManager.compat.PackageManagerCompat.MATCH_DISABLED_COMPONENTS;\n\nimport android.annotation.SuppressLint;\nimport android.content.pm.ActivityInfo;\nimport android.content.pm.PackageInfo;\nimport android.content.pm.PackageManager;\nimport android.content.pm.ProviderInfo;\nimport android.content.pm.ServiceInfo;\nimport android.net.Uri;\nimport android.os.RemoteException;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.WorkerThread;\n\nimport org.json.JSONArray;\nimport org.json.JSONObject;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.HashMap;\nimport java.util.List;\n\nimport io.github.muntashirakon.AppManager.compat.AppOpsManagerCompat;\nimport io.github.muntashirakon.AppManager.compat.PackageManagerCompat;\nimport io.github.muntashirakon.AppManager.rules.RuleType;\nimport io.github.muntashirakon.AppManager.types.UserPackagePair;\nimport io.github.muntashirakon.AppManager.utils.PackageUtils;\nimport io.github.muntashirakon.io.Path;\nimport io.github.muntashirakon.io.Paths;\n\n/**\n * Import components from external apps like Blocker, Watt\n */\npublic class ExternalComponentsImporter {\n    public static void setModeToFilteredAppOps(@NonNull AppOpsManagerCompat appOpsManager,\n                                               @NonNull UserPackagePair pair,\n                                               int[] appOps,\n                                               @AppOpsManagerCompat.Mode int mode) throws RemoteException {\n        Collection<Integer> appOpList;\n        appOpList = PackageUtils.getFilteredAppOps(pair.getPackageName(), pair.getUserId(), appOps, mode);\n        try (ComponentsBlocker cb = ComponentsBlocker.getMutableInstance(pair.getPackageName(), pair.getUserId())) {\n            for (int appOp : appOpList) {\n                appOpsManager.setMode(appOp, PackageUtils.getAppUid(pair), pair.getPackageName(), mode);\n                cb.setAppOp(appOp, mode);\n            }\n            cb.applyRules(true);\n        }\n    }\n\n    @WorkerThread\n    @NonNull\n    public static List<String> applyFromExistingBlockList(@NonNull List<String> packageNames, int userHandle) {\n        List<String> failedPkgList = new ArrayList<>();\n        HashMap<String, RuleType> components;\n        Path rulesPath = Paths.get(ComponentsBlocker.SYSTEM_RULES_PATH);\n        for (String packageName : packageNames) {\n            components = PackageUtils.getUserDisabledComponentsForPackage(packageName, userHandle);\n            try (ComponentsBlocker cb = ComponentsBlocker.getMutableInstance(packageName, userHandle)) {\n                for (String componentName : components.keySet()) {\n                    cb.addComponent(componentName, components.get(componentName));\n                }\n                // Remove IFW blocking rules if exists\n                Path[] rulesFiles = rulesPath.listFiles((dir, name) -> name.startsWith(packageName) && name.endsWith(\"xml\"));\n                for (Path rulesFile : rulesFiles) {\n                    rulesFile.delete();\n                }\n                cb.applyRules(true);\n            } catch (Exception e) {\n                e.printStackTrace();\n                failedPkgList.add(packageName);\n            }\n        }\n        return failedPkgList;\n    }\n\n    @WorkerThread\n    @NonNull\n    public static List<String> applyFromBlocker(@NonNull List<Uri> uriList, int[] userHandles) {\n        List<String> failedFiles = new ArrayList<>();\n        for (Uri uri : uriList) {\n            String filename = Paths.get(uri).getName();\n            try {\n                for (int userHandle : userHandles) {\n                    applyFromBlocker(uri, userHandle);\n                }\n            } catch (Exception e) {\n                failedFiles.add(filename);\n                e.printStackTrace();\n            }\n        }\n        return failedFiles;\n    }\n\n    @WorkerThread\n    @NonNull\n    public static List<String> applyFromWatt(@NonNull List<Uri> uriList, int[] userHandles) {\n        List<String> failedFiles = new ArrayList<>();\n        for (Uri uri : uriList) {\n            Path path = Paths.get(uri);\n            String filename = path.getName();\n            try {\n                for (int userHandle : userHandles) {\n                    applyFromWatt(Paths.trimPathExtension(filename), path, userHandle);\n                }\n            } catch (IOException e) {\n                failedFiles.add(filename);\n                e.printStackTrace();\n            }\n        }\n        return failedFiles;\n    }\n\n    /**\n     * Watt only supports IFW, so copy them directly\n     */\n    @WorkerThread\n    private static void applyFromWatt(String packageName, Path path, int userHandle)\n            throws IOException {\n        try (InputStream rulesStream = path.openInputStream()) {\n            try (ComponentsBlocker cb = ComponentsBlocker.getMutableInstance(packageName, userHandle)) {\n                HashMap<String, RuleType> components = ComponentUtils.readIFWRules(rulesStream,\n                        packageName);\n                for (String componentName : components.keySet()) {\n                    // Overwrite rules if exists\n                    cb.addComponent(componentName, components.get(componentName));\n                }\n                cb.applyRules(true);\n            }\n        }\n    }\n\n    /**\n     * Apply from blocker\n     *\n     * @param uri File URI\n     */\n    @WorkerThread\n    @SuppressLint(\"WrongConstant\")\n    private static void applyFromBlocker(Uri uri, int userHandle) throws Exception {\n        String jsonString = Paths.get(uri).getContentAsString();\n        HashMap<String, HashMap<String, RuleType>> packageComponents = new HashMap<>();\n        HashMap<String, PackageInfo> packageInfoList = new HashMap<>();\n        JSONObject jsonObject = new JSONObject(jsonString);\n        JSONArray components = jsonObject.getJSONArray(\"components\");\n        List<String> uninstalledApps = new ArrayList<>();\n        for (int i = 0; i < components.length(); ++i) {\n            JSONObject component = (JSONObject) components.get(i);\n            String packageName = component.getString(\"packageName\");\n            if (uninstalledApps.contains(packageName)) continue;\n            if (!packageInfoList.containsKey(packageName)) {\n                try {\n                    packageInfoList.put(packageName, PackageManagerCompat.getPackageInfo(packageName,\n                            PackageManager.GET_ACTIVITIES | PackageManager.GET_RECEIVERS\n                                    | PackageManager.GET_PROVIDERS | PackageManager.GET_SERVICES\n                                    | MATCH_DISABLED_COMPONENTS\n                                    | PackageManagerCompat.MATCH_STATIC_SHARED_AND_SDK_LIBRARIES, userHandle));\n                } catch (Exception e) {\n                    // App not installed\n                    uninstalledApps.add(packageName);\n                    continue;\n                }\n            }\n            String componentName = component.getString(\"name\");\n            if (!packageComponents.containsKey(packageName)) {\n                packageComponents.put(packageName, new HashMap<>());\n            }\n            // Fetch package components using PackageInfo since the type used in Blocker can be wrong\n            //noinspection ConstantConditions\n            packageComponents.get(packageName).put(componentName, getType(componentName,\n                    packageInfoList.get(packageName)));\n        }\n        if (packageComponents.size() > 0) {\n            for (String packageName : packageComponents.keySet()) {\n                HashMap<String, RuleType> disabledComponents = packageComponents.get(packageName);\n                //noinspection ConstantConditions\n                if (disabledComponents.size() > 0) {\n                    try (ComponentsBlocker cb = ComponentsBlocker.getMutableInstance(packageName, userHandle)) {\n                        for (String component : disabledComponents.keySet()) {\n                            cb.addComponent(component, disabledComponents.get(component));\n                        }\n                        cb.applyRules(true);\n                        if (!cb.isRulesApplied())\n                            throw new Exception(\"Rules not applied for package \" + packageName);\n                    }\n                }\n            }\n        }\n    }\n\n    @Nullable\n    private static RuleType getType(@NonNull String name, @NonNull PackageInfo packageInfo) {\n        for (ActivityInfo activityInfo : packageInfo.activities)\n            if (activityInfo.name.equals(name)) return RuleType.ACTIVITY;\n        for (ProviderInfo providerInfo : packageInfo.providers)\n            if (providerInfo.name.equals(name)) return RuleType.PROVIDER;\n        for (ActivityInfo receiverInfo : packageInfo.receivers)\n            if (receiverInfo.name.equals(name)) return RuleType.RECEIVER;\n        for (ServiceInfo serviceInfo : packageInfo.services)\n            if (serviceInfo.name.equals(name)) return RuleType.SERVICE;\n        return null;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/rules/struct/AppOpRule.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.rules.struct;\n\nimport androidx.annotation.NonNull;\n\nimport java.util.Objects;\nimport java.util.StringTokenizer;\n\nimport io.github.muntashirakon.AppManager.compat.AppOpsManagerCompat;\nimport io.github.muntashirakon.AppManager.rules.RuleType;\n\npublic class AppOpRule extends RuleEntry {\n    private final int mOp;\n    @AppOpsManagerCompat.Mode\n    private int mMode;\n\n    public AppOpRule(@NonNull String packageName, int op, @AppOpsManagerCompat.Mode int mode) {\n        super(packageName, String.valueOf(op), RuleType.APP_OP);\n        mOp = op;\n        mMode = mode;\n    }\n\n    public AppOpRule(@NonNull String packageName, String opInt, @NonNull StringTokenizer tokenizer)\n            throws RuntimeException {\n        super(packageName, opInt, RuleType.APP_OP);\n        mOp = Integer.parseInt(opInt);\n        if (tokenizer.hasMoreElements()) {\n            mMode = Integer.parseInt(tokenizer.nextElement().toString());\n        } else throw new IllegalArgumentException(\"Invalid format: mode not found\");\n    }\n\n    public int getOp() {\n        return mOp;\n    }\n\n    @AppOpsManagerCompat.Mode\n    public int getMode() {\n        return mMode;\n    }\n\n    public void setMode(@AppOpsManagerCompat.Mode int mode) {\n        mMode = mode;\n    }\n\n    @NonNull\n    @Override\n    public String toString() {\n        return \"AppOpRule{\" +\n                \"packageName='\" + packageName + '\\'' +\n                \", op=\" + mOp +\n                \", mode=\" + mMode +\n                '}';\n    }\n\n    @NonNull\n    @Override\n    public String flattenToString(boolean isExternal) {\n        return addPackageWithTab(isExternal) + mOp + \"\\t\" + type.name() + \"\\t\" + mMode;\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) return true;\n        if (!(o instanceof AppOpRule)) return false;\n        if (!super.equals(o)) return false;\n        AppOpRule appOpRule = (AppOpRule) o;\n        return getOp() == appOpRule.getOp() && getMode() == appOpRule.getMode();\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hash(super.hashCode(), getOp(), getMode());\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/rules/struct/BatteryOptimizationRule.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.rules.struct;\n\nimport androidx.annotation.NonNull;\n\nimport java.util.Objects;\nimport java.util.StringTokenizer;\n\nimport io.github.muntashirakon.AppManager.rules.RuleType;\n\npublic class BatteryOptimizationRule extends RuleEntry {\n    private boolean mEnabled;\n\n    public BatteryOptimizationRule(@NonNull String packageName, boolean enabled) {\n        super(packageName, STUB, RuleType.BATTERY_OPT);\n        mEnabled = enabled;\n    }\n\n    public BatteryOptimizationRule(@NonNull String packageName, @NonNull StringTokenizer tokenizer) {\n        super(packageName, STUB, RuleType.BATTERY_OPT);\n        if (tokenizer.hasMoreElements()) {\n            mEnabled = Boolean.parseBoolean(tokenizer.nextElement().toString());\n        } else throw new IllegalArgumentException(\"Invalid format: enabled not found\");\n    }\n\n    public boolean isEnabled() {\n        return mEnabled;\n    }\n\n    public void setEnabled(boolean enabled) {\n        mEnabled = enabled;\n    }\n\n    @NonNull\n    @Override\n    public String toString() {\n        return \"BatteryOptimizationRule{\" +\n                \"packageName='\" + packageName + '\\'' +\n                \", enabled=\" + mEnabled +\n                '}';\n    }\n\n    @NonNull\n    @Override\n    public String flattenToString(boolean isExternal) {\n        return addPackageWithTab(isExternal) + name + \"\\t\" + type.name() + \"\\t\" + mEnabled;\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) return true;\n        if (!(o instanceof BatteryOptimizationRule)) return false;\n        if (!super.equals(o)) return false;\n        BatteryOptimizationRule that = (BatteryOptimizationRule) o;\n        return isEnabled() == that.isEnabled();\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hash(super.hashCode(), isEnabled());\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/rules/struct/ComponentRule.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.rules.struct;\n\nimport android.content.ComponentName;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.StringDef;\n\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.util.Objects;\nimport java.util.StringTokenizer;\n\nimport io.github.muntashirakon.AppManager.rules.RuleType;\n\npublic class ComponentRule extends RuleEntry {\n    @StringDef({\n            COMPONENT_BLOCKED_IFW_DISABLE,\n            COMPONENT_BLOCKED_IFW,\n            COMPONENT_DISABLED,\n            COMPONENT_ENABLED,\n\n            COMPONENT_TO_BE_BLOCKED_IFW_DISABLE,\n            COMPONENT_TO_BE_BLOCKED_IFW,\n            COMPONENT_TO_BE_DISABLED,\n            COMPONENT_TO_BE_ENABLED,\n            COMPONENT_TO_BE_DEFAULTED\n    })\n    @Retention(RetentionPolicy.SOURCE)\n    public @interface ComponentStatus {\n    }\n\n    // One would want to use flags but couldn't in order to preserve compatibility\n    /**\n     * Component has been blocked with both IFW and PM.\n     */\n    public static final String COMPONENT_BLOCKED_IFW_DISABLE = \"true\";  // To preserve compatibility\n    /**\n     * Component has been blocked with IFW.\n     */\n    public static final String COMPONENT_BLOCKED_IFW = \"ifw_true\";\n    /**\n     * Component has been disabled.\n     */\n    public static final String COMPONENT_DISABLED = \"dis_true\";\n    /**\n     * Component has been enabled.\n     */\n    public static final String COMPONENT_ENABLED = \"en_true\";\n\n    /**\n     * Component will be blocked with both IFW and PM.\n     */\n    public static final String COMPONENT_TO_BE_BLOCKED_IFW_DISABLE = \"false\";  // To preserve compatibility\n    /**\n     * Component will be blocked with IFW.\n     */\n    public static final String COMPONENT_TO_BE_BLOCKED_IFW = \"ifw_false\";\n    /**\n     * Component will be disabled.\n     */\n    public static final String COMPONENT_TO_BE_DISABLED = \"dis_false\";\n    /**\n     * Component will be enabled.\n     */\n    public static final String COMPONENT_TO_BE_ENABLED = \"en_false\";\n    /**\n     * Component will be set to the default state, removed from IFW rules if exists and cleared from DB.\n     */\n    public static final String COMPONENT_TO_BE_DEFAULTED = \"unblocked\";\n\n    @NonNull\n    @ComponentStatus\n    private final String mComponentStatus;\n\n    @Nullable\n    @ComponentStatus\n    private String mLastComponentStatus;\n\n    public ComponentRule(@NonNull String packageName, @NonNull String name, RuleType componentType,\n                         @NonNull @ComponentStatus String componentStatus) {\n        super(packageName, name, componentType);\n        mComponentStatus = fixComponentStatus(componentStatus);\n    }\n\n    public ComponentRule(@NonNull String packageName, @NonNull String name, RuleType componentType,\n                         @NonNull StringTokenizer tokenizer) throws IllegalArgumentException {\n        super(packageName, name, componentType);\n        if (tokenizer.hasMoreElements()) {\n            mComponentStatus = fixComponentStatus(tokenizer.nextElement().toString());\n        } else throw new IllegalArgumentException(\"Invalid format: componentStatus not found\");\n    }\n\n    public ComponentName getComponentName() {\n        return new ComponentName(packageName, name);\n    }\n\n    @NonNull\n    @ComponentStatus\n    public String getComponentStatus() {\n        return mComponentStatus;\n    }\n\n    public void setLastComponentStatus(@Nullable String lastComponentStatus) {\n        mLastComponentStatus = lastComponentStatus;\n    }\n\n    public boolean applyDefaultState() {\n        if (mLastComponentStatus == null) {\n            return false;\n        }\n        if (mComponentStatus.equals(COMPONENT_TO_BE_BLOCKED_IFW)) {\n            return mLastComponentStatus.equals(COMPONENT_DISABLED)\n                    || mLastComponentStatus.equals(COMPONENT_BLOCKED_IFW_DISABLE);\n        }\n        return false;\n    }\n\n    public boolean toBeRemoved() {\n        return mComponentStatus.equals(COMPONENT_TO_BE_DEFAULTED);\n    }\n\n    public boolean isBlocked() {\n        return mComponentStatus.equals(COMPONENT_BLOCKED_IFW_DISABLE)\n                || mComponentStatus.equals(COMPONENT_BLOCKED_IFW)\n                || mComponentStatus.equals(COMPONENT_DISABLED);\n    }\n\n    public boolean isIfw() {\n        return mComponentStatus.equals(COMPONENT_TO_BE_BLOCKED_IFW)\n                || mComponentStatus.equals(COMPONENT_TO_BE_BLOCKED_IFW_DISABLE)\n                || mComponentStatus.equals(COMPONENT_BLOCKED_IFW)\n                || mComponentStatus.equals(COMPONENT_BLOCKED_IFW_DISABLE);\n    }\n\n    public boolean isApplied() {\n        return !(mComponentStatus.equals(COMPONENT_TO_BE_BLOCKED_IFW_DISABLE)\n                || mComponentStatus.equals(COMPONENT_TO_BE_BLOCKED_IFW)\n                || mComponentStatus.equals(COMPONENT_TO_BE_DISABLED)\n                || mComponentStatus.equals(COMPONENT_TO_BE_ENABLED)\n                || mComponentStatus.equals(COMPONENT_TO_BE_DEFAULTED));\n    }\n\n    @ComponentStatus\n    public String getCounterpartOfToBe() {\n        switch (mComponentStatus) {\n            case COMPONENT_TO_BE_BLOCKED_IFW_DISABLE:\n                return COMPONENT_BLOCKED_IFW_DISABLE;\n            case COMPONENT_TO_BE_BLOCKED_IFW:\n                return COMPONENT_BLOCKED_IFW;\n            case COMPONENT_TO_BE_DISABLED:\n                return COMPONENT_DISABLED;\n            case COMPONENT_TO_BE_ENABLED:\n                return COMPONENT_ENABLED;\n            default:\n                return mComponentStatus;\n        }\n    }\n\n    @ComponentStatus\n    public String getToBe() {\n        switch (mComponentStatus) {\n            case COMPONENT_BLOCKED_IFW_DISABLE:\n                return COMPONENT_TO_BE_BLOCKED_IFW_DISABLE;\n            case COMPONENT_BLOCKED_IFW:\n                return COMPONENT_TO_BE_BLOCKED_IFW;\n            case COMPONENT_DISABLED:\n                return COMPONENT_TO_BE_DISABLED;\n            case COMPONENT_ENABLED:\n                return COMPONENT_TO_BE_ENABLED;\n            default:\n                return mComponentStatus;\n        }\n    }\n\n    private String fixComponentStatus(@ComponentStatus String componentStatus) {\n        if (type != RuleType.PROVIDER) {\n            return componentStatus;\n        }\n        // Providers do not support IFW\n        switch (componentStatus) {\n            case COMPONENT_BLOCKED_IFW_DISABLE:\n                return COMPONENT_DISABLED;\n            case COMPONENT_BLOCKED_IFW:\n                return COMPONENT_ENABLED;\n            case COMPONENT_TO_BE_BLOCKED_IFW:\n            case COMPONENT_TO_BE_BLOCKED_IFW_DISABLE:\n                return COMPONENT_TO_BE_DISABLED;\n            default:\n                return componentStatus;\n        }\n    }\n\n    @NonNull\n    @Override\n    public String toString() {\n        return \"ComponentRule{\" +\n                \"packageName='\" + packageName + '\\'' +\n                \", name='\" + name + '\\'' +\n                \", type=\" + type.name() +\n                \", componentStatus='\" + mComponentStatus + '\\'' +\n                '}';\n    }\n\n    @NonNull\n    @Override\n    public String flattenToString(boolean isExternal) {\n        return addPackageWithTab(isExternal) + name + \"\\t\" + type.name() + \"\\t\" + mComponentStatus;\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) return true;\n        if (!(o instanceof ComponentRule)) return false;\n        if (!super.equals(o)) return false;\n        ComponentRule rule = (ComponentRule) o;\n        return getComponentStatus().equals(rule.getComponentStatus());\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hash(super.hashCode(), getComponentStatus());\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/rules/struct/FreezeRule.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.rules.struct;\n\nimport androidx.annotation.NonNull;\n\nimport java.util.Objects;\nimport java.util.StringTokenizer;\n\nimport io.github.muntashirakon.AppManager.rules.RuleType;\nimport io.github.muntashirakon.AppManager.utils.FreezeUtils;\n\npublic class FreezeRule extends RuleEntry {\n    @FreezeUtils.FreezeMethod\n    private int mFreezeType;\n\n    public FreezeRule(@NonNull String packageName, @FreezeUtils.FreezeMethod int freezeType) {\n        super(packageName, STUB, RuleType.FREEZE);\n        mFreezeType = freezeType;\n    }\n\n    public FreezeRule(@NonNull String packageName, @NonNull StringTokenizer tokenizer) {\n        super(packageName, STUB, RuleType.FREEZE);\n        if (tokenizer.hasMoreElements()) {\n            mFreezeType = Integer.parseInt(tokenizer.nextElement().toString());\n        } else throw new IllegalArgumentException(\"Invalid format: freeze_type not found\");\n    }\n\n    public int getFreezeType() {\n        return mFreezeType;\n    }\n\n    public void setFreezeType(@FreezeUtils.FreezeMethod int freezeType) {\n        mFreezeType = freezeType;\n    }\n\n    @NonNull\n    @Override\n    public String toString() {\n        return \"FreezeRule{\" +\n                \"mFreezeType=\" + mFreezeType +\n                \", packageName='\" + packageName + '\\'' +\n                '}';\n    }\n\n    @NonNull\n    @Override\n    public String flattenToString(boolean isExternal) {\n        return addPackageWithTab(isExternal) + name + \"\\t\" + type.name() + \"\\t\" + mFreezeType;\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) return true;\n        if (!(o instanceof FreezeRule)) return false;\n        if (!super.equals(o)) return false;\n        FreezeRule freezeRule = (FreezeRule) o;\n        return getFreezeType() == freezeRule.getFreezeType();\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hash(super.hashCode(), getFreezeType());\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/rules/struct/MagiskDenyListRule.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.rules.struct;\n\nimport androidx.annotation.NonNull;\n\nimport java.util.Objects;\nimport java.util.StringTokenizer;\n\nimport io.github.muntashirakon.AppManager.magisk.MagiskProcess;\nimport io.github.muntashirakon.AppManager.rules.RuleType;\n\npublic class MagiskDenyListRule extends RuleEntry {\n    @NonNull\n    private final MagiskProcess mMagiskProcess;\n\n    public MagiskDenyListRule(@NonNull MagiskProcess magiskProcess) {\n        super(magiskProcess.packageName, magiskProcess.name, RuleType.MAGISK_DENY_LIST);\n        mMagiskProcess = magiskProcess;\n    }\n\n    public MagiskDenyListRule(@NonNull String packageName, @NonNull String processName, @NonNull StringTokenizer tokenizer)\n            throws IllegalArgumentException {\n        super(packageName, processName, RuleType.MAGISK_DENY_LIST);\n        mMagiskProcess = new MagiskProcess(packageName, name);\n        mMagiskProcess.setAppZygote(name.endsWith(\"_zygote\"));\n        if (tokenizer.hasMoreElements()) {\n            mMagiskProcess.setEnabled(Boolean.parseBoolean(tokenizer.nextElement().toString()));\n        } else throw new IllegalArgumentException(\"Invalid format: isHidden not found\");\n        if (tokenizer.hasMoreElements()) {\n            mMagiskProcess.setIsolatedProcess(Boolean.parseBoolean(tokenizer.nextElement().toString()));\n        }\n    }\n\n    public String getProcessName() {\n        return name;\n    }\n\n    @NonNull\n    public MagiskProcess getMagiskProcess() {\n        return mMagiskProcess;\n    }\n\n    @NonNull\n    @Override\n    public String toString() {\n        return \"MagiskDenyListRule{\" +\n                \"packageName='\" + packageName + '\\'' +\n                \"processName='\" + name + '\\'' +\n                \", isDenied=\" + mMagiskProcess.isEnabled() +\n                \", isIsolated=\" + mMagiskProcess.isIsolatedProcess() +\n                \", isAppZygote=\" + mMagiskProcess.isAppZygote() +\n                '}';\n    }\n\n    @NonNull\n    @Override\n    public String flattenToString(boolean isExternal) {\n        return addPackageWithTab(isExternal) + name + \"\\t\" + type.name() + \"\\t\" + mMagiskProcess.isEnabled() + \"\\t\"\n                + mMagiskProcess.isIsolatedProcess();\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) return true;\n        if (!(o instanceof MagiskDenyListRule)) return false;\n        if (!super.equals(o)) return false;\n        MagiskDenyListRule that = (MagiskDenyListRule) o;\n        return mMagiskProcess.isEnabled() == that.mMagiskProcess.isEnabled()\n                && mMagiskProcess.isIsolatedProcess() == that.mMagiskProcess.isIsolatedProcess();\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hash(super.hashCode(), mMagiskProcess.isEnabled(), mMagiskProcess.isIsolatedProcess());\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/rules/struct/MagiskHideRule.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.rules.struct;\n\nimport androidx.annotation.NonNull;\n\nimport java.util.Objects;\nimport java.util.StringTokenizer;\n\nimport io.github.muntashirakon.AppManager.magisk.MagiskProcess;\nimport io.github.muntashirakon.AppManager.rules.RuleType;\n\npublic class MagiskHideRule extends RuleEntry {\n    @NonNull\n    private final MagiskProcess mMagiskProcess;\n\n    public MagiskHideRule(@NonNull MagiskProcess magiskProcess) {\n        super(magiskProcess.packageName, magiskProcess.name, RuleType.MAGISK_HIDE);\n        mMagiskProcess = magiskProcess;\n    }\n\n    public MagiskHideRule(@NonNull String packageName, @NonNull String processName, @NonNull StringTokenizer tokenizer)\n            throws IllegalArgumentException {\n        super(packageName, processName.equals(STUB) ? packageName : processName, RuleType.MAGISK_HIDE);\n        mMagiskProcess = new MagiskProcess(packageName, name); // name cannot be STUB\n        mMagiskProcess.setAppZygote(name.endsWith(\"_zygote\"));\n        if (tokenizer.hasMoreElements()) {\n            mMagiskProcess.setEnabled(Boolean.parseBoolean(tokenizer.nextElement().toString()));\n        } else throw new IllegalArgumentException(\"Invalid format: isHidden not found\");\n        if (tokenizer.hasMoreElements()) {\n            mMagiskProcess.setIsolatedProcess(Boolean.parseBoolean(tokenizer.nextElement().toString()));\n        }\n    }\n\n    @NonNull\n    public MagiskProcess getMagiskProcess() {\n        return mMagiskProcess;\n    }\n\n    @NonNull\n    @Override\n    public String toString() {\n        return \"MagiskHideRule{\" +\n                \"packageName='\" + packageName + '\\'' +\n                \"processName='\" + name + '\\'' +\n                \", isHidden=\" + mMagiskProcess.isEnabled() +\n                \", isIsolated=\" + mMagiskProcess.isIsolatedProcess() +\n                \", isAppZygote=\" + mMagiskProcess.isAppZygote() +\n                '}';\n    }\n\n    @NonNull\n    @Override\n    public String flattenToString(boolean isExternal) {\n        return addPackageWithTab(isExternal) + name + \"\\t\" + type.name() + \"\\t\" + mMagiskProcess.isEnabled()\n                + \"\\t\" + mMagiskProcess.isIsolatedProcess();\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) return true;\n        if (!(o instanceof MagiskHideRule)) return false;\n        if (!super.equals(o)) return false;\n        MagiskHideRule that = (MagiskHideRule) o;\n        return mMagiskProcess.isEnabled() == that.mMagiskProcess.isEnabled()\n                && mMagiskProcess.isIsolatedProcess() == that.mMagiskProcess.isIsolatedProcess();\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hash(super.hashCode(), mMagiskProcess.isEnabled(), mMagiskProcess.isIsolatedProcess());\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/rules/struct/NetPolicyRule.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.rules.struct;\n\nimport androidx.annotation.NonNull;\n\nimport java.util.Objects;\nimport java.util.StringTokenizer;\n\nimport io.github.muntashirakon.AppManager.compat.NetworkPolicyManagerCompat;\nimport io.github.muntashirakon.AppManager.rules.RuleType;\n\npublic class NetPolicyRule extends RuleEntry {\n    @NetworkPolicyManagerCompat.NetPolicy\n    private int mNetPolicies;\n\n    public NetPolicyRule(@NonNull String packageName, @NetworkPolicyManagerCompat.NetPolicy int netPolicies) {\n        super(packageName, STUB, RuleType.NET_POLICY);\n        mNetPolicies = netPolicies;\n    }\n\n    public NetPolicyRule(@NonNull String packageName, @NonNull StringTokenizer tokenizer) {\n        super(packageName, STUB, RuleType.NET_POLICY);\n        if (tokenizer.hasMoreElements()) {\n            mNetPolicies = Integer.parseInt(tokenizer.nextElement().toString());\n        } else throw new IllegalArgumentException(\"Invalid format: netPolicies not found\");\n    }\n\n    @NetworkPolicyManagerCompat.NetPolicy\n    public int getPolicies() {\n        return mNetPolicies;\n    }\n\n    public void setPolicies(@NetworkPolicyManagerCompat.NetPolicy int netPolicies) {\n        mNetPolicies = netPolicies;\n    }\n\n    @NonNull\n    @Override\n    public String toString() {\n        return \"NetPolicyRule{\" +\n                \"packageName='\" + packageName + '\\'' +\n                \", netPolicies=\" + mNetPolicies +\n                '}';\n    }\n\n    @NonNull\n    @Override\n    public String flattenToString(boolean isExternal) {\n        return addPackageWithTab(isExternal) + name + \"\\t\" + type.name() + \"\\t\" + mNetPolicies;\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) return true;\n        if (!(o instanceof NetPolicyRule)) return false;\n        if (!super.equals(o)) return false;\n        NetPolicyRule that = (NetPolicyRule) o;\n        return mNetPolicies == that.mNetPolicies;\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hash(super.hashCode(), mNetPolicies);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/rules/struct/NotificationListenerRule.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.rules.struct;\n\nimport androidx.annotation.NonNull;\n\nimport java.util.Objects;\nimport java.util.StringTokenizer;\n\nimport io.github.muntashirakon.AppManager.rules.RuleType;\n\npublic class NotificationListenerRule extends RuleEntry {\n    private boolean mIsGranted;\n\n    public NotificationListenerRule(@NonNull String packageName, String name, boolean isGranted) {\n        super(packageName, name, RuleType.NOTIFICATION);\n        this.mIsGranted = isGranted;\n    }\n\n    public NotificationListenerRule(@NonNull String packageName, String name, @NonNull StringTokenizer tokenizer) {\n        super(packageName, name, RuleType.NOTIFICATION);\n        if (tokenizer.hasMoreElements()) {\n            mIsGranted = Boolean.parseBoolean(tokenizer.nextElement().toString());\n        } else throw new IllegalArgumentException(\"Invalid format: isGranted not found\");\n    }\n\n    public boolean isGranted() {\n        return mIsGranted;\n    }\n\n    public void setGranted(boolean granted) {\n        mIsGranted = granted;\n    }\n\n    @NonNull\n    @Override\n    public String toString() {\n        return \"NotificationListenerRule{\" +\n                \"packageName='\" + packageName + '\\'' +\n                \", name='\" + name + '\\'' +\n                \", isGranted=\" + mIsGranted +\n                '}';\n    }\n\n    @NonNull\n    @Override\n    public String flattenToString(boolean isExternal) {\n        return addPackageWithTab(isExternal) + name + \"\\t\" + type.name() + \"\\t\" + mIsGranted;\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) return true;\n        if (!(o instanceof NotificationListenerRule)) return false;\n        if (!super.equals(o)) return false;\n        NotificationListenerRule that = (NotificationListenerRule) o;\n        return isGranted() == that.isGranted();\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hash(super.hashCode(), isGranted());\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/rules/struct/PermissionRule.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.rules.struct;\n\nimport android.content.pm.PermissionInfo;\nimport android.os.RemoteException;\n\nimport androidx.annotation.NonNull;\nimport androidx.core.content.pm.PermissionInfoCompat;\n\nimport java.util.Objects;\nimport java.util.StringTokenizer;\n\nimport io.github.muntashirakon.AppManager.compat.AppOpsManagerCompat;\nimport io.github.muntashirakon.AppManager.compat.PermissionCompat;\nimport io.github.muntashirakon.AppManager.permission.DevelopmentPermission;\nimport io.github.muntashirakon.AppManager.permission.PermUtils;\nimport io.github.muntashirakon.AppManager.permission.Permission;\nimport io.github.muntashirakon.AppManager.permission.ReadOnlyPermission;\nimport io.github.muntashirakon.AppManager.permission.RuntimePermission;\nimport io.github.muntashirakon.AppManager.rules.RuleType;\n\npublic class PermissionRule extends RuleEntry {\n    private final int mAppOp;\n\n    private boolean mIsGranted;\n    @PermissionCompat.PermissionFlags\n    private int mFlags;\n\n    public PermissionRule(@NonNull String packageName, @NonNull String permName, boolean isGranted,\n                          @PermissionCompat.PermissionFlags int flags) {\n        super(packageName, permName, RuleType.PERMISSION);\n        mIsGranted = isGranted;\n        mFlags = flags;\n        mAppOp = AppOpsManagerCompat.permissionToOpCode(name);\n    }\n\n    public PermissionRule(@NonNull String packageName, @NonNull String permName, @NonNull StringTokenizer tokenizer)\n            throws IllegalArgumentException {\n        super(packageName, permName, RuleType.PERMISSION);\n        if (tokenizer.hasMoreElements()) {\n            mIsGranted = Boolean.parseBoolean(tokenizer.nextElement().toString());\n        } else throw new IllegalArgumentException(\"Invalid format: isGranted not found\");\n        if (tokenizer.hasMoreElements()) {\n            mFlags = Integer.parseInt(tokenizer.nextElement().toString());\n        } else {\n            // Don't throw exception in order to provide backward compatibility\n            mFlags = 0;\n        }\n        mAppOp = AppOpsManagerCompat.permissionToOpCode(name);\n    }\n\n    public boolean isGranted() {\n        return mIsGranted;\n    }\n\n    public void setGranted(boolean granted) {\n        mIsGranted = granted;\n    }\n\n    @PermissionCompat.PermissionFlags\n    public int getFlags() {\n        return mFlags;\n    }\n\n    public void setFlags(@PermissionCompat.PermissionFlags int flags) {\n        mFlags = flags;\n    }\n\n    public int getAppOp() {\n        return mAppOp;\n    }\n\n    public Permission getPermission(boolean appOpAllowed) {\n        PermissionInfo permissionInfo = null;\n        try {\n            permissionInfo = PermissionCompat.getPermissionInfo(name, packageName, 0);\n        } catch (RemoteException ignore) {\n        }\n        if (permissionInfo == null) {\n            permissionInfo = new PermissionInfo();\n            permissionInfo.name = name;\n        }\n        int protection = PermissionInfoCompat.getProtection(permissionInfo);\n        int protectionFlags = PermissionInfoCompat.getProtectionFlags(permissionInfo);\n        if (protection == PermissionInfo.PROTECTION_DANGEROUS && PermUtils.systemSupportsRuntimePermissions()) {\n            return new RuntimePermission(name, mIsGranted, mAppOp, appOpAllowed, mFlags);\n        } else if ((protectionFlags & PermissionInfo.PROTECTION_FLAG_DEVELOPMENT) != 0) {\n            return new DevelopmentPermission(name, mIsGranted, mAppOp, appOpAllowed, mFlags);\n        } else {\n            return new ReadOnlyPermission(name, mIsGranted, mAppOp, appOpAllowed, mFlags);\n        }\n    }\n\n    @NonNull\n    @Override\n    public String toString() {\n        return \"PermissionRule{\" +\n                \"packageName='\" + packageName + '\\'' +\n                \", name='\" + name + '\\'' +\n                \", isGranted=\" + mIsGranted +\n                \", flags=\" + mFlags +\n                '}';\n    }\n\n    @NonNull\n    @Override\n    public String flattenToString(boolean isExternal) {\n        return addPackageWithTab(isExternal) + name + \"\\t\" + type.name() + \"\\t\" + mIsGranted + \"\\t\" + mFlags;\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) return true;\n        if (!(o instanceof PermissionRule)) return false;\n        if (!super.equals(o)) return false;\n        PermissionRule that = (PermissionRule) o;\n        return isGranted() == that.isGranted() && getFlags() == that.getFlags();\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hash(super.hashCode(), isGranted(), getFlags());\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/rules/struct/RuleEntry.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.rules.struct;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport java.util.Objects;\nimport java.util.StringTokenizer;\n\nimport io.github.muntashirakon.AppManager.rules.RuleType;\n\npublic abstract class RuleEntry {\n    public static final String STUB = \"STUB\";\n\n    /**\n     * Name of the entry, unique for {@link RuleType#ACTIVITY}, {@link RuleType#PROVIDER}, {@link RuleType#RECEIVER},\n     * {@link RuleType#SERVICE}, {@link RuleType#PERMISSION}, {@link RuleType#MAGISK_DENY_LIST} but not others.\n     * In other cases, they can be {@link #STUB}.\n     */\n    @NonNull\n    public final String name;\n    /**\n     * The package name this rule belong to.\n     */\n    @NonNull\n    public final String packageName;\n    /**\n     * Type of the entry.\n     */\n    @NonNull\n    public final RuleType type;\n\n    public RuleEntry(@NonNull String packageName, @NonNull String name, @NonNull RuleType type) {\n        this.packageName = packageName;\n        this.name = name;\n        this.type = type;\n    }\n\n    @NonNull\n    @Override\n    public String toString() {\n        return \"Entry{\" +\n                \"name='\" + name + '\\'' +\n                \", type=\" + type +\n                '}';\n    }\n\n    @NonNull\n    public abstract String flattenToString(boolean isExternal);\n\n    protected String addPackageWithTab(boolean isExternal) {\n        return (isExternal ? packageName + \"\\t\" : \"\");\n    }\n\n    @NonNull\n    public static RuleEntry unflattenFromString(@Nullable String packageName, @NonNull String ruleLine,\n                                                boolean isExternal) throws IllegalArgumentException {\n        StringTokenizer tokenizer = new StringTokenizer(ruleLine, \"\\t\");\n        if (isExternal) {\n            // External rules, the first part is the package name\n            if (tokenizer.hasMoreElements()) {\n                // Match package name\n                String newPackageName = tokenizer.nextElement().toString();\n                if (packageName == null) packageName = newPackageName;\n                if (!packageName.equals(newPackageName)) {\n                    throw new IllegalArgumentException(\"Invalid format: package names do not match.\");\n                }\n            } else throw new IllegalArgumentException(\"Invalid format: packageName not found for external rule.\");\n        }\n        if (packageName == null) {\n            // packageName can't be empty\n            throw new IllegalArgumentException(\"Package name cannot be empty.\");\n        }\n        String name;\n        RuleType type;\n        if (tokenizer.hasMoreElements()) {\n            name = tokenizer.nextElement().toString();\n        } else throw new IllegalArgumentException(\"Invalid format: name not found\");\n        if (tokenizer.hasMoreElements()) {\n            try {\n                type = RuleType.valueOf(tokenizer.nextElement().toString());\n            } catch (Exception e) {\n                throw new IllegalArgumentException(\"Invalid format: Invalid type\");\n            }\n        } else throw new IllegalArgumentException(\"Invalid format: entryType not found\");\n        return getRuleEntry(packageName, name, type, tokenizer);\n    }\n\n    @NonNull\n    private static RuleEntry getRuleEntry(@NonNull String packageName, @NonNull String name,\n                                          @NonNull RuleType type, @NonNull StringTokenizer tokenizer)\n            throws IllegalArgumentException {\n        switch (type) {\n            case ACTIVITY:\n            case PROVIDER:\n            case RECEIVER:\n            case SERVICE:\n                return new ComponentRule(packageName, name, type, tokenizer);\n            case APP_OP:\n                return new AppOpRule(packageName, name, tokenizer);\n            case PERMISSION:\n                return new PermissionRule(packageName, name, tokenizer);\n            case MAGISK_HIDE:\n                return new MagiskHideRule(packageName, name, tokenizer);\n            case MAGISK_DENY_LIST:\n                return new MagiskDenyListRule(packageName, name, tokenizer);\n            case BATTERY_OPT:\n                return new BatteryOptimizationRule(packageName, tokenizer);\n            case NET_POLICY:\n                return new NetPolicyRule(packageName, tokenizer);\n            case NOTIFICATION:\n                return new NotificationListenerRule(packageName, name, tokenizer);\n            case URI_GRANT:\n                return new UriGrantRule(packageName, tokenizer);\n            case SSAID:\n                return new SsaidRule(packageName, tokenizer);\n            case FREEZE:\n                return new FreezeRule(packageName, tokenizer);\n            default:\n                throw new IllegalArgumentException(\"Invalid type=\" + type.name());\n        }\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) return true;\n        if (!(o instanceof RuleEntry)) return false;\n        RuleEntry ruleEntry = (RuleEntry) o;\n        return name.equals(ruleEntry.name) && packageName.equals(ruleEntry.packageName) && type == ruleEntry.type;\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hash(name, packageName, type);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/rules/struct/SsaidRule.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.rules.struct;\n\nimport androidx.annotation.NonNull;\n\nimport java.util.Objects;\nimport java.util.StringTokenizer;\n\nimport io.github.muntashirakon.AppManager.rules.RuleType;\n\npublic class SsaidRule extends RuleEntry {\n    @NonNull\n    private String mSsaid;\n\n    public SsaidRule(@NonNull String packageName, @NonNull String ssaid) {\n        super(packageName, STUB, RuleType.SSAID);\n        mSsaid = ssaid;\n    }\n\n    public SsaidRule(@NonNull String packageName, @NonNull StringTokenizer tokenizer) {\n        super(packageName, STUB, RuleType.SSAID);\n        if (tokenizer.hasMoreElements()) {\n            mSsaid = tokenizer.nextElement().toString();\n        } else throw new IllegalArgumentException(\"Invalid format: ssaid not found\");\n    }\n\n    @NonNull\n    public String getSsaid() {\n        return mSsaid;\n    }\n\n    public void setSsaid(@NonNull String ssaid) {\n        mSsaid = ssaid;\n    }\n\n    @NonNull\n    @Override\n    public String toString() {\n        return \"SsaidRule{\" +\n                \"packageName='\" + packageName + '\\'' +\n                \", ssaid='\" + mSsaid + '\\'' +\n                '}';\n    }\n\n    @NonNull\n    @Override\n    public String flattenToString(boolean isExternal) {\n        return addPackageWithTab(isExternal) + name + \"\\t\" + type.name() + \"\\t\" + mSsaid;\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) return true;\n        if (!(o instanceof SsaidRule)) return false;\n        if (!super.equals(o)) return false;\n        SsaidRule ssaidRule = (SsaidRule) o;\n        return getSsaid().equals(ssaidRule.getSsaid());\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hash(super.hashCode(), getSsaid());\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/rules/struct/UriGrantRule.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.rules.struct;\n\nimport androidx.annotation.NonNull;\n\nimport java.util.Objects;\nimport java.util.StringTokenizer;\n\nimport io.github.muntashirakon.AppManager.rules.RuleType;\nimport io.github.muntashirakon.AppManager.uri.UriManager;\n\npublic class UriGrantRule extends RuleEntry {\n    @NonNull\n    private final UriManager.UriGrant mUriGrant;\n\n    public UriGrantRule(@NonNull String packageName, @NonNull UriManager.UriGrant uriGrant) {\n        super(packageName, STUB, RuleType.URI_GRANT);\n        mUriGrant = uriGrant;\n    }\n\n    public UriGrantRule(@NonNull String packageName, @NonNull StringTokenizer tokenizer) {\n        super(packageName, STUB, RuleType.URI_GRANT);\n        if (tokenizer.hasMoreElements()) {\n            mUriGrant = UriManager.UriGrant.unflattenFromString(tokenizer.nextElement().toString());\n        } else throw new IllegalArgumentException(\"Invalid format: uriGrant not found\");\n    }\n\n    @NonNull\n    public UriManager.UriGrant getUriGrant() {\n        return mUriGrant;\n    }\n\n    @NonNull\n    @Override\n    public String toString() {\n        return \"UriGrantRule{\" +\n                \"packageName='\" + packageName + '\\'' +\n                \", uriGrant=\" + mUriGrant +\n                '}';\n    }\n\n    @NonNull\n    @Override\n    public String flattenToString(boolean isExternal) {\n        return addPackageWithTab(isExternal) + name + \"\\t\" + type.name() + \"\\t\" + mUriGrant.flattenToString();\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) return true;\n        if (!(o instanceof UriGrantRule)) return false;\n        if (!super.equals(o)) return false;\n        UriGrantRule that = (UriGrantRule) o;\n        return getUriGrant().equals(that.getUriGrant());\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hash(super.hashCode(), getUriGrant());\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/runner/NormalShell.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.runner;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.WorkerThread;\n\nimport com.topjohnwu.superuser.Shell;\n\nimport java.io.InputStream;\nimport java.util.ArrayList;\nimport java.util.List;\n\nclass NormalShell extends Runner {\n    private final Shell mShell;\n\n    public NormalShell(boolean isRoot) {\n        if (isRoot == Shell.getShell().isRoot()) {\n            mShell = Shell.getShell();\n            return;\n        }\n        int flags = isRoot ? Shell.FLAG_MOUNT_MASTER : Shell.FLAG_NON_ROOT_SHELL;\n        mShell = Shell.Builder.create().setFlags(flags).setTimeout(10).build();\n    }\n\n    @Override\n    public boolean isRoot() {\n        return mShell.isRoot();\n    }\n\n    @WorkerThread\n    @NonNull\n    @Override\n    protected synchronized Result runCommand() {\n        List<String> stdout = new ArrayList<>();\n        List<String> stderr = new ArrayList<>();\n        Shell.Job job = mShell.newJob().add(commands.toArray(new String[0])).to(stdout, stderr);\n        for (InputStream is : inputStreams) {\n            job.add(is);\n        }\n        Shell.Result result = job.exec();\n        return new Result(stdout, stderr, result.getCode());\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/runner/PrivilegedShell.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.runner;\n\nimport android.os.RemoteException;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.WorkerThread;\n\nimport java.io.IOException;\nimport java.io.InputStream;\n\nimport io.github.muntashirakon.AppManager.IAMService;\nimport io.github.muntashirakon.AppManager.IRemoteShell;\nimport io.github.muntashirakon.AppManager.IShellResult;\nimport io.github.muntashirakon.AppManager.ipc.LocalServices;\nimport io.github.muntashirakon.AppManager.logs.Log;\nimport io.github.muntashirakon.AppManager.utils.ParcelFileDescriptorUtil;\n\nclass PrivilegedShell extends Runner {\n    @Override\n    public boolean isRoot() {\n        // ADB shell in App Manager always runs in no-root\n        return false;\n    }\n\n    @WorkerThread\n    @NonNull\n    @Override\n    protected synchronized Result runCommand() {\n        try {\n            IAMService amService = LocalServices.getAmService();\n            IRemoteShell shell = amService.getShell(commands.toArray(new String[0]));\n            for (InputStream is : inputStreams) {\n                shell.addInputStream(ParcelFileDescriptorUtil.pipeFrom(is));\n            }\n            IShellResult result = shell.exec();\n            return new Result(result.getStdout().getList(), result.getStderr().getList(), result.getExitCode());\n        } catch (RemoteException | IOException e) {\n            Log.e(PrivilegedShell.class.getSimpleName(), e);\n            return new Result();\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/runner/Runner.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.runner;\n\nimport android.text.TextUtils;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.WorkerThread;\n\nimport java.io.InputStream;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\n\nimport io.github.muntashirakon.AppManager.ipc.LocalServices;\nimport io.github.muntashirakon.AppManager.logs.Log;\nimport io.github.muntashirakon.AppManager.settings.Ops;\n\npublic abstract class Runner {\n    public static final String TAG = Runner.class.getSimpleName();\n\n    public static class Result {\n        private final List<String> mStdout;\n        private final List<String> mStderr;\n        private final int mExitCode;\n\n        Result(@NonNull List<String> stdout, @NonNull List<String> stderr, int exitCode) {\n            mStdout = stdout;\n            mStderr = stderr;\n            mExitCode = exitCode;\n            // Print stderr\n            if (stderr.size() > 0) {\n                Log.e(TAG, TextUtils.join(\"\\n\", stderr));\n            }\n        }\n\n        public Result(int exitCode) {\n            this(Collections.emptyList(), Collections.emptyList(), exitCode);\n        }\n\n        public Result() {\n            this(1);\n        }\n\n        public boolean isSuccessful() {\n            return mExitCode == 0;\n        }\n\n        public int getExitCode() {\n            return mExitCode;\n        }\n\n        @NonNull\n        public List<String> getOutputAsList() {\n            return mStdout;\n        }\n\n        @NonNull\n        public List<String> getOutputAsList(int firstIndex) {\n            if (firstIndex >= mStdout.size()) {\n                return Collections.emptyList();\n            }\n            return mStdout.subList(firstIndex, mStdout.size());\n        }\n\n        @NonNull\n        public String getOutput() {\n            return TextUtils.join(\"\\n\", mStdout);\n        }\n\n        public List<String> getStderr() {\n            return mStderr;\n        }\n    }\n\n    private static NormalShell sRootShell;\n    private static PrivilegedShell sPrivilegedShell;\n    private static NormalShell sNoRootShell;\n\n    @NonNull\n    private static Runner getInstance() {\n        if (Ops.isDirectRoot()) {\n            return getRootInstance();\n        } else if (LocalServices.alive()) {\n            return getPrivilegedInstance();\n        } else {\n            return getNoRootInstance();\n        }\n    }\n\n    @NonNull\n    static Runner getRootInstance() {\n        if (sRootShell == null) {\n            sRootShell = new NormalShell(true);\n            Log.d(TAG, \"RootShell\");\n        }\n        return sRootShell;\n    }\n\n    @NonNull\n    private static Runner getPrivilegedInstance() {\n        if (sPrivilegedShell == null) {\n            sPrivilegedShell = new PrivilegedShell();\n            Log.d(TAG, \"PrivilegedShell\");\n        }\n        return sPrivilegedShell;\n    }\n\n    private static Runner getNoRootInstance() {\n        if (sNoRootShell == null) {\n            sNoRootShell = new NormalShell(false);\n            Log.d(TAG, \"NoRootShell\");\n        }\n        return sNoRootShell;\n    }\n\n    @NonNull\n    synchronized public static Result runCommand(@NonNull String command) {\n        return runCommand(getInstance(), command, null);\n    }\n\n    @NonNull\n    synchronized public static Result runCommand(@NonNull String[] command) {\n        return runCommand(getInstance(), command, null);\n    }\n\n    @NonNull\n    synchronized public static Result runCommand(@NonNull String command, @Nullable InputStream inputStream) {\n        return runCommand(getInstance(), command, inputStream);\n    }\n\n    @NonNull\n    synchronized public static Result runCommand(@NonNull String[] command, @Nullable InputStream inputStream) {\n        return runCommand(getInstance(), command, inputStream);\n    }\n\n    @NonNull\n    synchronized private static Result runCommand(@NonNull Runner runner, @NonNull String command,\n                                                  @Nullable InputStream inputStream) {\n        return runner.run(command, inputStream);\n    }\n\n    @NonNull\n    synchronized private static Result runCommand(@NonNull Runner runner, @NonNull String[] command,\n                                                  @Nullable InputStream inputStream) {\n        StringBuilder cmd = new StringBuilder();\n        for (String part : command) {\n            cmd.append(RunnerUtils.escape(part)).append(\" \");\n        }\n        return runCommand(runner, cmd.toString(), inputStream);\n    }\n\n    protected final List<String> commands;\n    protected final List<InputStream> inputStreams;\n\n    protected Runner() {\n        this.commands = new ArrayList<>();\n        this.inputStreams = new ArrayList<>();\n    }\n\n    public void addCommand(@NonNull String command) {\n        commands.add(command);\n    }\n\n    public void add(@NonNull InputStream inputStream) {\n        inputStreams.add(inputStream);\n    }\n\n    public void clear() {\n        commands.clear();\n        inputStreams.clear();\n    }\n\n    public abstract boolean isRoot();\n\n    @WorkerThread\n    @NonNull\n    protected abstract Result runCommand();\n\n    @NonNull\n    private Result run(@NonNull String command, @Nullable InputStream inputStream) {\n        try {\n            clear();\n            addCommand(command);\n            if (inputStream != null) {\n                add(inputStream);\n            }\n            return runCommand();\n        } finally {\n            clear();\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/runner/RunnerUtils.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.runner;\n\nimport android.os.Build;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport com.topjohnwu.superuser.Shell;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.StringWriter;\nimport java.io.Writer;\nimport java.security.InvalidParameterException;\nimport java.util.BitSet;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport io.github.muntashirakon.AppManager.logs.Log;\nimport io.github.muntashirakon.AppManager.misc.NoOps;\n\npublic final class RunnerUtils {\n    public static final String TAG = RunnerUtils.class.getSimpleName();\n\n    public static final String CMD_AM = Build.VERSION.SDK_INT >= Build.VERSION_CODES.P ? \"cmd activity\" : \"am\";\n    public static final String CMD_PM = Build.VERSION.SDK_INT >= Build.VERSION_CODES.P ? \"cmd package\" : \"pm\";\n\n    private static final String EMPTY = \"\";\n\n    /**\n     * Translator object for escaping Shell command language.\n     *\n     * @see <a href=\"http://pubs.opengroup.org/onlinepubs/7908799/xcu/chap2.html\">Shell Command Language</a>\n     */\n    public static final LookupTranslator ESCAPE_XSI;\n\n    static {\n        final Map<CharSequence, CharSequence> escapeXsiMap = new HashMap<>();\n        escapeXsiMap.put(\"|\", \"\\\\|\");\n        escapeXsiMap.put(\"&\", \"\\\\&\");\n        escapeXsiMap.put(\";\", \"\\\\;\");\n        escapeXsiMap.put(\"<\", \"\\\\<\");\n        escapeXsiMap.put(\">\", \"\\\\>\");\n        escapeXsiMap.put(\"(\", \"\\\\(\");\n        escapeXsiMap.put(\")\", \"\\\\)\");\n        escapeXsiMap.put(\"$\", \"\\\\$\");\n        escapeXsiMap.put(\"`\", \"\\\\`\");\n        escapeXsiMap.put(\"\\\\\", \"\\\\\\\\\");\n        escapeXsiMap.put(\"\\\"\", \"\\\\\\\"\");\n        escapeXsiMap.put(\"'\", \"\\\\'\");\n        escapeXsiMap.put(\" \", \"\\\\ \");\n        escapeXsiMap.put(\"\\t\", \"\\\\\\t\");\n        escapeXsiMap.put(\"\\r\\n\", EMPTY);\n        escapeXsiMap.put(\"\\n\", EMPTY);\n        escapeXsiMap.put(\"*\", \"\\\\*\");\n        escapeXsiMap.put(\"?\", \"\\\\?\");\n        escapeXsiMap.put(\"[\", \"\\\\[\");\n        escapeXsiMap.put(\"#\", \"\\\\#\");\n        escapeXsiMap.put(\"~\", \"\\\\~\");\n        escapeXsiMap.put(\"=\", \"\\\\=\");\n        escapeXsiMap.put(\"%\", \"\\\\%\");\n        ESCAPE_XSI = new LookupTranslator(Collections.unmodifiableMap(escapeXsiMap));\n    }\n\n    /**\n     * <p>Escapes the characters in a {@code String} using XSI rules.</p>\n     *\n     * <p><b>Beware!</b> In most cases you don't want to escape shell commands but use multi-argument\n     * methods provided by {@link java.lang.ProcessBuilder} or {@link java.lang.Runtime#exec(String[])}\n     * instead.</p>\n     *\n     * <p>Example:</p>\n     * <pre>\n     * input string: He didn't say, \"Stop!\"\n     * output string: He\\ didn\\'t\\ say,\\ \\\"Stop!\\\"\n     * </pre>\n     *\n     * @param input String to escape values in, may be null\n     * @return String with escaped values, {@code null} if null string input\n     * @see <a href=\"http://pubs.opengroup.org/onlinepubs/7908799/xcu/chap2.html\">Shell Command Language</a>\n     */\n    public static String escape(final String input) {\n        return ESCAPE_XSI.translate(input);\n    }\n\n    @NoOps\n    public static boolean isRootGiven() {\n        return Boolean.TRUE.equals(isAppGrantedRoot());\n    }\n\n    @NoOps\n    public static boolean isRootAvailable() {\n        return !Boolean.FALSE.equals(isAppGrantedRoot());\n    }\n\n    /**\n     * @see Shell#isAppGrantedRoot()\n     */\n    @Nullable\n    @NoOps\n    public static Boolean isAppGrantedRoot() {\n        if (Runner.getRootInstance().isRoot()) {\n            // Root granted\n            return true;\n        }\n        // Check if root is available\n        String pathEnv = System.getenv(\"PATH\");\n        Log.d(TAG, \"PATH=%s\", pathEnv);\n        if (pathEnv == null) return false;\n        for (String pathDir : pathEnv.split(\":\")) {\n            File suFile = new File(pathDir, \"su\");\n            Log.d(TAG, \"SU(file=%s, exists=%s, executable=%s)\", suFile, suFile.exists(), suFile.canExecute());\n            if (new File(pathDir, \"su\").canExecute()) {\n                // Root available but App Manager is not granted root\n                return null;\n            }\n        }\n        return false;\n    }\n\n    /**\n     * An API for translating text.\n     * Its core use is to escape and unescape text. Because escaping and unescaping\n     * is completely contextual, the API does not present two separate signatures.\n     *\n     * @since 1.0\n     */\n    public static class LookupTranslator {\n        /**\n         * The mapping to be used in translation.\n         */\n        private final Map<String, String> mLookupMap;\n        /**\n         * The first character of each key in the lookupMap.\n         */\n        private final BitSet mPrefixSet;\n        /**\n         * The length of the shortest key in the lookupMap.\n         */\n        private final int mShortest;\n        /**\n         * The length of the longest key in the lookupMap.\n         */\n        private final int mLongest;\n\n        /**\n         * Define the lookup table to be used in translation\n         * <p>\n         * Note that, as of Lang 3.1 (the origin of this code), the key to the lookup\n         * table is converted to a java.lang.String. This is because we need the key\n         * to support hashCode and equals(Object), allowing it to be the key for a\n         * HashMap. See LANG-882.\n         *\n         * @param lookupMap Map&lt;CharSequence, CharSequence&gt; table of translator\n         *                  mappings\n         */\n        public LookupTranslator(final Map<CharSequence, CharSequence> lookupMap) {\n            if (lookupMap == null) {\n                throw new InvalidParameterException(\"lookupMap cannot be null\");\n            }\n            mLookupMap = new HashMap<>();\n            mPrefixSet = new BitSet();\n            int currentShortest = Integer.MAX_VALUE;\n            int currentLongest = 0;\n\n            for (final Map.Entry<CharSequence, CharSequence> pair : lookupMap.entrySet()) {\n                mLookupMap.put(pair.getKey().toString(), pair.getValue().toString());\n                mPrefixSet.set(pair.getKey().charAt(0));\n                final int sz = pair.getKey().length();\n                if (sz < currentShortest) {\n                    currentShortest = sz;\n                }\n                if (sz > currentLongest) {\n                    currentLongest = sz;\n                }\n            }\n            mShortest = currentShortest;\n            mLongest = currentLongest;\n        }\n\n        /**\n         * Translate a set of codepoints, represented by an int index into a CharSequence,\n         * into another set of codepoints. The number of codepoints consumed must be returned,\n         * and the only IOExceptions thrown must be from interacting with the Writer so that\n         * the top level API may reliably ignore StringWriter IOExceptions.\n         *\n         * @param input CharSequence that is being translated\n         * @param index int representing the current point of translation\n         * @param out   Writer to translate the text to\n         * @return int count of codepoints consumed\n         * @throws IOException if and only if the Writer produces an IOException\n         */\n        public int translate(@NonNull final CharSequence input, final int index, final Writer out) throws IOException {\n            // check if translation exists for the input at position index\n            if (mPrefixSet.get(input.charAt(index))) {\n                int max = mLongest;\n                if (index + mLongest > input.length()) {\n                    max = input.length() - index;\n                }\n                // implement greedy algorithm by trying maximum match first\n                for (int i = max; i >= mShortest; i--) {\n                    final CharSequence subSeq = input.subSequence(index, index + i);\n                    final String result = mLookupMap.get(subSeq.toString());\n\n                    if (result != null) {\n                        out.write(result);\n                        return i;\n                    }\n                }\n            }\n            return 0;\n        }\n\n        /**\n         * Helper for non-Writer usage.\n         *\n         * @param input CharSequence to be translated\n         * @return String output of translation\n         */\n        public final String translate(final CharSequence input) {\n            if (input == null) {\n                return null;\n            }\n            try {\n                final StringWriter writer = new StringWriter(input.length() * 2);\n                translate(input, writer);\n                return writer.toString();\n            } catch (final IOException ioe) {\n                // this should never ever happen while writing to a StringWriter\n                throw new RuntimeException(ioe);\n            }\n        }\n\n        /**\n         * Translate an input onto a Writer. This is intentionally final as its algorithm is\n         * tightly coupled with the abstract method of this class.\n         *\n         * @param input CharSequence that is being translated\n         * @param out   Writer to translate the text to\n         * @throws IOException if and only if the Writer produces an IOException\n         */\n        public final void translate(final CharSequence input, final Writer out) throws IOException {\n            if (input == null) {\n                return;\n            }\n            int pos = 0;\n            final int len = input.length();\n            while (pos < len) {\n                final int consumed = translate(input, pos, out);\n                if (consumed == 0) {\n                    // inlined implementation of Character.toChars(Character.codePointAt(input, pos))\n                    // avoids allocating temp char arrays and duplicate checks\n                    final char c1 = input.charAt(pos);\n                    out.write(c1);\n                    pos++;\n                    if (Character.isHighSurrogate(c1) && pos < len) {\n                        final char c2 = input.charAt(pos);\n                        if (Character.isLowSurrogate(c2)) {\n                            out.write(c2);\n                            pos++;\n                        }\n                    }\n                    continue;\n                }\n                // contract with translators is that they have to understand codepoints\n                // and they just took care of a surrogate pair\n                for (int pt = 0; pt < consumed; pt++) {\n                    pos += Character.charCount(Character.codePointAt(input, pos));\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/runningapps/AppProcessItem.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.runningapps;\n\nimport android.content.pm.PackageInfo;\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\nimport androidx.core.os.ParcelCompat;\n\nimport java.util.Objects;\n\nimport io.github.muntashirakon.AppManager.ipc.ps.ProcessEntry;\n\npublic class AppProcessItem extends ProcessItem {\n    @NonNull\n    public final PackageInfo packageInfo;\n\n    public AppProcessItem(@NonNull ProcessEntry processEntry, @NonNull PackageInfo packageInfo) {\n        super(processEntry);\n        this.packageInfo = packageInfo;\n    }\n\n    protected AppProcessItem(@NonNull Parcel in) {\n        super(in);\n        packageInfo = Objects.requireNonNull(ParcelCompat.readParcelable(in, PackageInfo.class.getClassLoader(), PackageInfo.class));\n    }\n\n    public static final Creator<AppProcessItem> CREATOR = new Creator<AppProcessItem>() {\n        @NonNull\n        @Override\n        public AppProcessItem createFromParcel(Parcel in) {\n            return new AppProcessItem(in);\n        }\n\n        @NonNull\n        @Override\n        public AppProcessItem[] newArray(int size) {\n            return new AppProcessItem[size];\n        }\n    };\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        super.writeToParcel(dest, flags);\n        dest.writeParcelable(packageInfo, flags);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/runningapps/ProcessItem.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.runningapps;\n\nimport android.os.Parcel;\nimport android.os.Parcelable;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.core.os.ParcelCompat;\n\nimport java.util.Objects;\n\nimport io.github.muntashirakon.AppManager.ipc.ps.ProcessEntry;\nimport io.github.muntashirakon.AppManager.users.Owners;\n\npublic class ProcessItem implements Parcelable {\n    public final int pid;\n    public final int ppid;\n    public final long rss;\n    public final int uid;\n    public final String user;\n    @Nullable\n    public final String context;\n\n    public String state;\n    public String state_extra;\n    public String name;\n\n    @NonNull\n    private final ProcessEntry mProcessEntry;\n\n    public ProcessItem(@NonNull ProcessEntry processEntry) {\n        mProcessEntry = processEntry;\n        pid = processEntry.pid;\n        ppid = processEntry.ppid;\n        rss = processEntry.residentSetSize;\n        uid = processEntry.users.fsUid;\n        context = processEntry.seLinuxPolicy;\n        user = Owners.getOwnerName(processEntry.users.fsUid);\n    }\n\n    /**\n     * @see <a href=\"https://stackoverflow.com/a/16736599\">How do I get the total CPU usage of an application from /proc/pid/stat?</a>\n     */\n    public double getCpuTimeInPercent() {\n        return mProcessEntry.cpuTimeConsumed * 100. / mProcessEntry.elapsedTime;\n    }\n\n    public long getCpuTimeInMillis() {\n        return mProcessEntry.cpuTimeConsumed * 1000;\n    }\n\n    public String getCommandlineArgsAsString() {\n        return mProcessEntry.name.replace('\\u0000', ' ');\n    }\n\n    public String[] getCommandlineArgs() {\n        return mProcessEntry.name.split(\"\\u0000\");\n    }\n\n    public long getMemory() {\n        return mProcessEntry.residentSetSize << 12;\n    }\n\n    public long getVirtualMemory() {\n        return mProcessEntry.virtualMemorySize;\n    }\n\n    public long getSharedMemory() {\n        return mProcessEntry.sharedMemory << 12;\n    }\n\n    public int getPriority() {\n        return mProcessEntry.priority;\n    }\n\n    public int getThreadCount() {\n        return mProcessEntry.threadCount;\n    }\n\n    protected ProcessItem(@NonNull Parcel in) {\n        mProcessEntry = Objects.requireNonNull(ParcelCompat.readParcelable(in, ProcessEntry.class.getClassLoader(), ProcessEntry.class));\n        pid = mProcessEntry.pid;\n        ppid = mProcessEntry.ppid;\n        rss = mProcessEntry.residentSetSize;\n        uid = mProcessEntry.users.fsUid;\n        context = mProcessEntry.seLinuxPolicy;\n\n        user = in.readString();\n        state = in.readString();\n        state_extra = in.readString();\n        name = in.readString();\n    }\n\n    public static final Creator<ProcessItem> CREATOR = new Creator<ProcessItem>() {\n        @NonNull\n        @Override\n        public ProcessItem createFromParcel(Parcel in) {\n            return new ProcessItem(in);\n        }\n\n        @NonNull\n        @Override\n        public ProcessItem[] newArray(int size) {\n            return new ProcessItem[size];\n        }\n    };\n\n    @Override\n    @NonNull\n    public String toString() {\n        return \"ProcessItem{\" +\n                \"pid=\" + pid +\n                \", ppid=\" + ppid +\n                \", rss=\" + rss +\n                \", user='\" + user + '\\'' +\n                \", uid=\" + uid +\n                \", state='\" + state + '\\'' +\n                \", state_extra='\" + state_extra + '\\'' +\n                \", name='\" + name + '\\'' +\n                \", context='\" + context + '\\'' +\n                '}';\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) return true;\n        if (!(o instanceof ProcessItem)) return false;\n        ProcessItem that = (ProcessItem) o;\n        return pid == that.pid;\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hash(pid);\n    }\n\n    @Override\n    public int describeContents() {\n        return 0;\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        dest.writeParcelable(mProcessEntry, flags);\n        dest.writeString(user);\n        dest.writeString(state);\n        dest.writeString(state_extra);\n        dest.writeString(name);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/runningapps/ProcessParser.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.runningapps;\n\nimport android.app.ActivityManager;\nimport android.content.Context;\nimport android.content.pm.PackageInfo;\nimport android.content.pm.PackageManager;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.VisibleForTesting;\nimport androidx.annotation.WorkerThread;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Objects;\n\nimport io.github.muntashirakon.AppManager.compat.ActivityManagerCompat;\nimport io.github.muntashirakon.AppManager.compat.PackageManagerCompat;\nimport io.github.muntashirakon.AppManager.ipc.LocalServices;\nimport io.github.muntashirakon.AppManager.ipc.ps.ProcessEntry;\nimport io.github.muntashirakon.AppManager.ipc.ps.Ps;\nimport io.github.muntashirakon.AppManager.logs.Log;\nimport io.github.muntashirakon.AppManager.utils.ContextUtils;\nimport io.github.muntashirakon.AppManager.utils.PackageUtils;\nimport io.github.muntashirakon.AppManager.utils.Utils;\nimport io.github.muntashirakon.io.Path;\nimport io.github.muntashirakon.io.Paths;\n\n@WorkerThread\npublic final class ProcessParser {\n    private final Context mContext;\n    private final PackageManager mPm;\n    private HashMap<String, PackageInfo> mInstalledPackages;\n    private HashMap<Integer, PackageInfo> mInstalledUidList;\n    private final HashMap<Integer, ActivityManager.RunningAppProcessInfo> mRunningAppProcesses = new HashMap<>(50);\n\n    ProcessParser() {\n        if (Utils.isRoboUnitTest()) {\n            mInstalledPackages = new HashMap<>();\n            mInstalledUidList = new HashMap<>();\n            mPm = null;\n            mContext = null;\n        } else {\n            mContext = ContextUtils.getContext();\n            mPm = mContext.getPackageManager();\n            getInstalledPackages();\n        }\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    @NonNull\n    List<ProcessItem> parse() {\n        List<ProcessItem> processItems = new ArrayList<>();\n        try {\n            List<ProcessEntry> processEntries;\n            if (Paths.get(\"/proc/1\").canRead() && LocalServices.alive()) {\n                processEntries = (List<ProcessEntry>) LocalServices.getAmService().getRunningProcesses().getList();\n            } else {\n                Ps ps = new Ps();\n                ps.loadProcesses();\n                processEntries = ps.getProcesses();\n            }\n            for (ProcessEntry processEntry : processEntries) {\n                if (processEntry.seLinuxPolicy != null && processEntry.seLinuxPolicy.contains(\":kernel:\")) {\n                    continue;\n                }\n                try {\n                    processItems.addAll(parseProcess(processEntry));\n                } catch (Exception ignore) {\n                }\n            }\n        } catch (Throwable th) {\n            Log.e(\"ProcessParser\", th);\n        }\n        return processItems;\n    }\n\n    @VisibleForTesting\n    @NonNull\n    HashMap<Integer, ProcessItem> parse(@NonNull Path procDir) {\n        HashMap<Integer, ProcessItem> processItems = new HashMap<>();\n        Ps ps = new Ps(procDir);\n        ps.loadProcesses();\n        List<ProcessEntry> processEntries = ps.getProcesses();\n        for (ProcessEntry processEntry : processEntries) {\n            try {\n                ProcessItem processItem = parseProcess(processEntry).get(0);\n                processItems.put(processItem.pid, processItem);\n            } catch (Exception ignore) {\n            }\n        }\n        return processItems;\n    }\n\n    @NonNull\n    private List<ProcessItem> parseProcess(@NonNull ProcessEntry processEntry) {\n        String packageName = getSupposedPackageName(processEntry.name);\n        List<ProcessItem> processItems = new ArrayList<>(1);\n        if (mRunningAppProcesses.containsKey(processEntry.pid)) {\n            String[] pkgList = Objects.requireNonNull(mRunningAppProcesses.get(processEntry.pid)).pkgList;\n            if (pkgList != null && pkgList.length > 0) {\n                for (String pkgName : pkgList) {\n                    @NonNull PackageInfo packageInfo = Objects.requireNonNull(mInstalledPackages.get(pkgName));\n                    ProcessItem processItem = new AppProcessItem(processEntry, packageInfo);\n                    processItem.name = mPm.getApplicationLabel(packageInfo.applicationInfo)\n                            + getProcessNameFilteringPackageName(processEntry.name, packageInfo.packageName);\n                    processItems.add(processItem);\n                }\n            } else {\n                ProcessItem processItem = new ProcessItem(processEntry);\n                processItem.name = getProcessName(processEntry.name);\n                processItems.add(processItem);\n            }\n        } else if (mInstalledPackages.containsKey(packageName)) {\n            @NonNull PackageInfo packageInfo = Objects.requireNonNull(mInstalledPackages.get(packageName));\n            ProcessItem processItem = new AppProcessItem(processEntry, packageInfo);\n            processItem.name = mPm.getApplicationLabel(packageInfo.applicationInfo)\n                    + getProcessNameFilteringPackageName(processEntry.name, packageInfo.packageName);\n            processItems.add(processItem);\n        } else if (mInstalledUidList.containsKey(processEntry.users.fsUid)) {\n            @NonNull PackageInfo packageInfo = Objects.requireNonNull(mInstalledUidList.get(processEntry.users.fsUid));\n            ProcessItem processItem = new AppProcessItem(processEntry, packageInfo);\n            processItem.name = mPm.getApplicationLabel(packageInfo.applicationInfo)\n                    + getProcessNameFilteringPackageName(processEntry.name, packageInfo.packageName);\n            processItems.add(processItem);\n        } else {\n            ProcessItem processItem = new ProcessItem(processEntry);\n            processItem.name = getProcessName(processEntry.name);\n            processItems.add(processItem);\n        }\n        for (ProcessItem processItem : processItems) {\n            if (mContext == null) {\n                processItem.state = processEntry.processState;\n                processItem.state_extra = processEntry.processStatePlus;\n            } else {\n                processItem.state = mContext.getString(Utils.getProcessStateName(processEntry.processState));\n                processItem.state_extra = mContext.getString(Utils.getProcessStateExtraName(\n                        processEntry.processStatePlus));\n            }\n        }\n        return processItems;\n    }\n\n    private void getInstalledPackages() {\n        List<PackageInfo> packageInfoList = PackageUtils.getAllPackages(PackageManagerCompat.MATCH_STATIC_SHARED_AND_SDK_LIBRARIES);\n        mInstalledPackages = new HashMap<>(packageInfoList.size());\n        for (PackageInfo info : packageInfoList) {\n            mInstalledPackages.put(info.packageName, info);\n        }\n        mInstalledUidList = new HashMap<>(packageInfoList.size());\n        List<Integer> duplicateUids = new ArrayList<>();\n        for (PackageInfo info : packageInfoList) {\n            int uid = info.applicationInfo.uid;\n            if (mInstalledUidList.containsKey(uid)) {\n                // A shared user ID (other way to check user ID will not work since we're only interested in\n                // duplicate values)\n                duplicateUids.add(uid);\n            } else mInstalledUidList.put(uid, info);\n        }\n        // Remove duplicate UIDs as they might create collisions\n        for (int uid : duplicateUids) mInstalledUidList.remove(uid);\n        List<ActivityManager.RunningAppProcessInfo> runningAppProcesses = ActivityManagerCompat.getRunningAppProcesses();\n        for (ActivityManager.RunningAppProcessInfo info : runningAppProcesses) {\n            mRunningAppProcesses.put(info.pid, info);\n        }\n    }\n\n    @NonNull\n    public static String getSupposedPackageName(@NonNull String processName) {\n        if (!processName.contains(\":\")) {\n            return processName;\n        }\n        int colonIdx = processName.indexOf(':');\n        return processName.substring(0, colonIdx);\n    }\n\n    @NonNull\n    public static String getProcessName(@NonNull String processName) {\n        processName = processName.split(\"\\u0000\")[0];\n        if (!processName.startsWith(\"/\")) return processName;\n        int slashIndex = processName.lastIndexOf('/');\n        return processName.substring(slashIndex + 1);\n    }\n\n    @NonNull\n    private static String getProcessNameFilteringPackageName(@NonNull String processName, @NonNull String packageName) {\n        if (processName.equals(packageName)) {\n            return \"\";\n        }\n        processName = getProcessName(processName);\n        int colonIdx = processName.indexOf(':');\n        return colonIdx < 0 ? (\":\" + processName) : processName.substring(colonIdx);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/runningapps/RunningAppDetails.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.runningapps;\n\nimport android.content.Intent;\nimport android.content.pm.PackageInfo;\nimport android.os.Bundle;\nimport android.os.UserHandleHidden;\nimport android.text.TextUtils;\nimport android.text.format.Formatter;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.ImageView;\nimport android.widget.TextView;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.appcompat.widget.LinearLayoutCompat;\nimport androidx.core.os.BundleCompat;\n\nimport com.google.android.material.button.MaterialButton;\n\nimport java.util.Locale;\n\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.details.AppDetailsActivity;\nimport io.github.muntashirakon.AppManager.self.imagecache.ImageLoader;\nimport io.github.muntashirakon.AppManager.utils.DateUtils;\nimport io.github.muntashirakon.dialog.CapsuleBottomSheetDialogFragment;\n\n\npublic class RunningAppDetails extends CapsuleBottomSheetDialogFragment {\n    public static final String TAG = RunningAppDetails.class.getSimpleName();\n\n    public static final String ARG_PS_ITEM = \"ps_item\";\n\n    @NonNull\n    public static RunningAppDetails getInstance(@NonNull ProcessItem processItem) {\n        Bundle args = new Bundle();\n        args.putParcelable(ARG_PS_ITEM, processItem);\n        RunningAppDetails fragment = new RunningAppDetails();\n        fragment.setArguments(args);\n        return fragment;\n    }\n\n    @NonNull\n    @Override\n    public View initRootView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {\n        return inflater.inflate(R.layout.dialog_running_app_details, container, false);\n    }\n\n    @Override\n    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {\n        super.onViewCreated(view, savedInstanceState);\n        ProcessItem processItem = BundleCompat.getParcelable(requireArguments(), ARG_PS_ITEM, ProcessItem.class);\n        if (processItem == null) {\n            dismiss();\n            return;\n        }\n        LinearLayoutCompat appContainer = view.findViewById(R.id.app_container);\n        ImageView appIcon = view.findViewById(R.id.icon);\n        MaterialButton openAppInfoButton = view.findViewById(R.id.info);\n        TextView appLabel = view.findViewById(R.id.name);\n        TextView packageName = view.findViewById(R.id.package_name);\n        TextView processName = view.findViewById(R.id.process_name);\n        TextView pid = view.findViewById(R.id.pid);\n        TextView ppid = view.findViewById(R.id.ppid);\n        TextView rss = view.findViewById(R.id.rss);\n        TextView vsz = view.findViewById(R.id.vsz);\n        TextView cpuPercent = view.findViewById(R.id.cpu_percent);\n        TextView cpuTime = view.findViewById(R.id.cpu_time);\n        TextView priority = view.findViewById(R.id.priority);\n        TextView threads = view.findViewById(R.id.threads);\n        TextView user = view.findViewById(R.id.user);\n        TextView state = view.findViewById(R.id.state);\n        TextView seLinuxContext = view.findViewById(R.id.selinux_context);\n        TextView cliArgs = view.findViewById(R.id.cli_args);\n\n        processName.setText(processItem.name);\n        pid.setText(String.format(Locale.getDefault(), \"%d\", processItem.pid));\n        ppid.setText(String.format(Locale.getDefault(), \"%d\", processItem.ppid));\n        rss.setText(Formatter.formatFileSize(requireContext(), processItem.getMemory()));\n        vsz.setText(Formatter.formatFileSize(requireContext(), processItem.getVirtualMemory()));\n        cpuPercent.setText(String.format(Locale.getDefault(), \"%.2f\", processItem.getCpuTimeInPercent()));\n        cpuTime.setText(DateUtils.getFormattedDuration(requireContext(), processItem.getCpuTimeInMillis(), false, true));\n        priority.setText(String.format(Locale.getDefault(), \"%d\", processItem.getPriority()));\n        threads.setText(String.format(Locale.getDefault(), \"%d\", processItem.getThreadCount()));\n        user.setText(String.format(Locale.getDefault(), \"%s (%d)\", processItem.user, processItem.uid));\n        CharSequence stateInfo;\n        if (TextUtils.isEmpty(processItem.state_extra)) {\n            stateInfo = processItem.state;\n        } else {\n            stateInfo = processItem.state + \" (\" + processItem.state_extra + \")\";\n        }\n        state.setText(stateInfo);\n        seLinuxContext.setText(processItem.context);\n        cliArgs.setText(processItem.getCommandlineArgsAsString());\n        if (processItem instanceof AppProcessItem) {\n            PackageInfo packageInfo = ((AppProcessItem) processItem).packageInfo;\n            appContainer.setVisibility(View.VISIBLE);\n            ImageLoader.getInstance().displayImage(packageInfo.packageName, packageInfo.applicationInfo, appIcon);\n            appLabel.setText(packageInfo.applicationInfo.loadLabel(requireContext().getPackageManager()));\n            packageName.setText(packageInfo.packageName);\n            openAppInfoButton.setOnClickListener(v -> {\n                Intent appDetailsIntent = AppDetailsActivity.getIntent(requireContext(), packageInfo.packageName,\n                        UserHandleHidden.getUserId(processItem.uid));\n                startActivity(appDetailsIntent);\n                dismiss();\n            });\n        } else {\n            appContainer.setVisibility(View.GONE);\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/runningapps/RunningAppsActivity.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.runningapps;\n\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.os.Process;\nimport android.text.TextUtils;\nimport android.view.Menu;\nimport android.view.MenuItem;\nimport android.view.View;\n\nimport androidx.activity.OnBackPressedCallback;\nimport androidx.annotation.IntDef;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.appcompat.app.ActionBar;\nimport androidx.core.content.ContextCompat;\nimport androidx.lifecycle.ViewModelProvider;\nimport androidx.recyclerview.widget.RecyclerView;\n\nimport com.google.android.material.dialog.MaterialAlertDialogBuilder;\nimport com.google.android.material.progressindicator.LinearProgressIndicator;\n\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Timer;\nimport java.util.TimerTask;\n\nimport io.github.muntashirakon.AppManager.BaseActivity;\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.batchops.BatchOpsManager;\nimport io.github.muntashirakon.AppManager.batchops.BatchOpsService;\nimport io.github.muntashirakon.AppManager.batchops.BatchQueueItem;\nimport io.github.muntashirakon.AppManager.compat.ManifestCompat;\nimport io.github.muntashirakon.AppManager.logcat.LogViewerActivity;\nimport io.github.muntashirakon.AppManager.logcat.struct.SearchCriteria;\nimport io.github.muntashirakon.AppManager.misc.AdvancedSearchView;\nimport io.github.muntashirakon.AppManager.scanner.vt.VtFileReport;\nimport io.github.muntashirakon.AppManager.self.SelfPermissions;\nimport io.github.muntashirakon.AppManager.settings.FeatureController;\nimport io.github.muntashirakon.AppManager.settings.Ops;\nimport io.github.muntashirakon.AppManager.settings.Prefs;\nimport io.github.muntashirakon.AppManager.utils.ThreadUtils;\nimport io.github.muntashirakon.AppManager.utils.UIUtils;\nimport io.github.muntashirakon.multiselection.MultiSelectionActionsView;\nimport io.github.muntashirakon.widget.MultiSelectionView;\n\npublic class RunningAppsActivity extends BaseActivity implements MultiSelectionView.OnSelectionChangeListener,\n        MultiSelectionActionsView.OnItemSelectedListener, AdvancedSearchView.OnQueryTextListener,\n        MultiSelectionView.OnSelectionModeChangeListener {\n\n    @IntDef(value = {\n            SORT_BY_PID,\n            SORT_BY_PROCESS_NAME,\n            SORT_BY_APPS_FIRST,\n            SORT_BY_MEMORY_USAGE,\n            SORT_BY_CPU_TIME,\n    })\n    @Retention(RetentionPolicy.SOURCE)\n    public @interface SortOrder {\n    }\n\n    public static final int SORT_BY_PID = 0;\n    public static final int SORT_BY_PROCESS_NAME = 1;\n    public static final int SORT_BY_APPS_FIRST = 2;\n    public static final int SORT_BY_MEMORY_USAGE = 3;\n    public static final int SORT_BY_CPU_TIME = 4;\n\n    @IntDef(value = {\n            FILTER_NONE,\n            FILTER_APPS,\n            FILTER_USER_APPS\n    }, flag = true)\n    @Retention(RetentionPolicy.SOURCE)\n    public @interface Filter {\n    }\n\n    public static final int FILTER_NONE = 0;\n    public static final int FILTER_APPS = 1;\n    public static final int FILTER_USER_APPS = 1 << 1;\n\n    private static final int[] SORT_ORDER_IDS = new int[]{\n            R.id.action_sort_by_pid,\n            R.id.action_sort_by_process_name,\n            R.id.action_sort_by_apps_first,\n            R.id.action_sort_by_memory_usage,\n            R.id.action_sort_by_cpu_time,\n    };\n\n    @Nullable\n    RunningAppsViewModel model;\n\n    private boolean mEnableKillForSystem = false;\n    @Nullable\n    private RunningAppsAdapter mAdapter;\n    @Nullable\n    private LinearProgressIndicator mProgressIndicator;\n    @Nullable\n    private MultiSelectionView mMultiSelectionView;\n    @Nullable\n    private Menu mSelectionMenu;\n    private Timer mTimer;\n    private final OnBackPressedCallback mOnBackPressedCallback = new OnBackPressedCallback(false) {\n        @Override\n        public void handleOnBackPressed() {\n            if (mAdapter != null && mMultiSelectionView != null && mAdapter.isInSelectionMode()) {\n                mMultiSelectionView.cancel();\n                return;\n            }\n            setEnabled(false);\n            getOnBackPressedDispatcher().onBackPressed();\n        }\n    };\n\n    @Override\n    protected void onAuthenticated(Bundle savedInstanceState) {\n        setContentView(R.layout.activity_running_apps);\n        setSupportActionBar(findViewById(R.id.toolbar));\n        getOnBackPressedDispatcher().addCallback(this, mOnBackPressedCallback);\n        ActionBar actionBar = getSupportActionBar();\n        if (actionBar != null) {\n            actionBar.setDisplayShowCustomEnabled(true);\n            UIUtils.setupAdvancedSearchView(actionBar, this);\n        }\n        model = new ViewModelProvider(this).get(RunningAppsViewModel.class);\n        mProgressIndicator = findViewById(R.id.progress_linear);\n        mProgressIndicator.setVisibilityAfterHide(View.GONE);\n        RecyclerView recyclerView = findViewById(R.id.scrollView);\n        recyclerView.setLayoutManager(UIUtils.getGridLayoutAt450Dp(this));\n        mAdapter = new RunningAppsAdapter(this);\n        mAdapter.setHasStableIds(false);\n        recyclerView.setAdapter(mAdapter);\n        // Recycler view is focused by default\n        recyclerView.requestFocus();\n        mMultiSelectionView = findViewById(R.id.selection_view);\n        mMultiSelectionView.setOnItemSelectedListener(this);\n        mMultiSelectionView.setOnSelectionModeChangeListener(this);\n        mMultiSelectionView.setOnSelectionChangeListener(this);\n        mMultiSelectionView.setAdapter(mAdapter);\n        mMultiSelectionView.updateCounter(true);\n        mSelectionMenu = mMultiSelectionView.getMenu();\n        mSelectionMenu.findItem(R.id.action_scan_vt).setVisible(false);\n        mEnableKillForSystem = Prefs.RunningApps.enableKillForSystemApps();\n\n        // Set observers\n        model.observeKillProcess().observe(this, processInfo -> {\n            if (processInfo.second /* is success */) {\n                refresh();\n            } else {\n                UIUtils.displayLongToast(R.string.failed_to_stop, processInfo.first.name /* process name */);\n            }\n        });\n        model.observeKillSelectedProcess().observe(this, processInfoList -> {\n            if (!processInfoList.isEmpty()) {\n                List<String> processNames = new ArrayList<String>() {{\n                    for (ProcessItem processItem : processInfoList) {\n                        add(processItem.name);\n                    }\n                }};\n                UIUtils.displayLongToast(R.string.failed_to_stop, TextUtils.join(\", \", processNames));\n            }\n            refresh();\n        });\n        model.observeForceStop().observe(this, applicationInfoBooleanPair -> {\n            if (applicationInfoBooleanPair.second /* is success */) {\n                refresh();\n            } else {\n                UIUtils.displayLongToast(R.string.failed_to_stop, applicationInfoBooleanPair.first\n                        .loadLabel(getPackageManager()));\n            }\n        });\n        model.observePreventBackgroundRun().observe(this, applicationInfoBooleanPair -> {\n            if (applicationInfoBooleanPair.second /* is success */) {\n                refresh();\n            } else {\n                UIUtils.displayLongToast(R.string.failed_to_prevent_background_run, applicationInfoBooleanPair.first\n                        .loadLabel(getPackageManager()));\n            }\n        });\n        model.observeProcessDetails().observe(this, processItem -> {\n            RunningAppDetails fragment = RunningAppDetails.getInstance(processItem);\n            fragment.show(getSupportFragmentManager(), RunningAppDetails.TAG);\n        });\n        model.getVtFileUpload().observe(this, processItemVtFilePermalinkPair -> {\n            ProcessItem processItem = processItemVtFilePermalinkPair.first;\n            String permalink = processItemVtFilePermalinkPair.second;\n            if (permalink == null) {\n                // Started uploading\n                UIUtils.displayShortToast(R.string.vt_uploading);\n                if (Prefs.VirusTotal.promptBeforeUpload()) {\n                    new MaterialAlertDialogBuilder(this)\n                            .setTitle(R.string.scan_in_vt)\n                            .setMessage(R.string.vt_confirm_uploading_file)\n                            .setCancelable(false)\n                            .setPositiveButton(R.string.vt_confirm_upload_and_scan, (dialog, which) -> model.enableUploading())\n                            .setNegativeButton(R.string.no, (dialog, which) -> model.disableUploading())\n                            .show();\n                } else model.enableUploading();\n            } else {\n                UIUtils.displayShortToast(R.string.vt_queued);\n            }\n            // TODO: 7/1/22 Use a separate fragment\n        });\n        model.getVtFileReport().observe(this, processItemVtFileReportPair -> {\n            ProcessItem processItem = processItemVtFileReportPair.first;\n            VtFileReport vtFileReport = processItemVtFileReportPair.second;\n            if (vtFileReport == null) {\n                UIUtils.displayShortToast(R.string.vt_failed);\n            } else {\n                UIUtils.displayLongToast(getString(R.string.vt_success, vtFileReport.getPositives(), vtFileReport.getTotal()));\n            }\n            // TODO: 7/1/22 Use a separate fragment\n        });\n        model.getProcessLiveData().observe(this, processList -> {\n            if (mProgressIndicator != null) {\n                mProgressIndicator.hide();\n            }\n            if (mAdapter != null) {\n                mAdapter.setDefaultList(processList);\n            }\n        });\n        model.getDeviceMemoryInfo().observe(this, deviceMemoryInfo -> {\n            if (mAdapter != null) {\n                mAdapter.setDeviceMemoryInfo(deviceMemoryInfo);\n            }\n        });\n    }\n\n    @Override\n    public boolean onCreateOptionsMenu(Menu menu) {\n        getMenuInflater().inflate(R.menu.activity_running_apps_actions, menu);\n        return super.onCreateOptionsMenu(menu);\n    }\n\n    @Override\n    public boolean onPrepareOptionsMenu(@NonNull Menu menu) {\n        if (model == null) return super.onPrepareOptionsMenu(menu);\n\n        menu.findItem(SORT_ORDER_IDS[model.getSortOrder()]).setChecked(true);\n        int filter = model.getFilter();\n        if ((filter & FILTER_APPS) != 0) {\n            menu.findItem(R.id.action_filter_apps).setChecked(true);\n        }\n        if ((filter & FILTER_USER_APPS) != 0) {\n            menu.findItem(R.id.action_filter_user_apps).setChecked(true);\n        }\n        return super.onPrepareOptionsMenu(menu);\n    }\n\n    @Override\n    public boolean onOptionsItemSelected(@NonNull MenuItem item) {\n        int id = item.getItemId();\n        if (id == android.R.id.home) {\n            finish();\n            return true;\n        }\n        if (model == null) return true;\n        if (id == R.id.action_toggle_kill) {\n            mEnableKillForSystem = !mEnableKillForSystem;\n            Prefs.RunningApps.setEnableKillForSystemApps(mEnableKillForSystem);\n            refresh();\n        } else if (id == R.id.action_sort_by_pid) {\n            model.setSortOrder(SORT_BY_PID);\n            item.setChecked(true);\n        } else if (id == R.id.action_sort_by_process_name) {\n            model.setSortOrder(SORT_BY_PROCESS_NAME);\n            item.setChecked(true);\n        } else if (id == R.id.action_sort_by_apps_first) {\n            model.setSortOrder(SORT_BY_APPS_FIRST);\n            item.setChecked(true);\n        } else if (id == R.id.action_sort_by_memory_usage) {\n            model.setSortOrder(SORT_BY_MEMORY_USAGE);\n            item.setChecked(true);\n        } else if (id == R.id.action_sort_by_cpu_time) {\n            model.setSortOrder(SORT_BY_CPU_TIME);\n            item.setChecked(true);\n            // Filter\n        } else if (id == R.id.action_filter_apps) {\n            if (!item.isChecked()) model.addFilter(FILTER_APPS);\n            else model.removeFilter(FILTER_APPS);\n            item.setChecked(!item.isChecked());\n        } else if (id == R.id.action_filter_user_apps) {\n            if (!item.isChecked()) model.addFilter(FILTER_USER_APPS);\n            else model.removeFilter(FILTER_USER_APPS);\n            item.setChecked(!item.isChecked());\n        } else return super.onOptionsItemSelected(item);\n        return true;\n    }\n\n    @Override\n    protected void onResume() {\n        super.onResume();\n        mTimer = new Timer(\"running_apps\");\n        mTimer.schedule(new TimerTask() {\n            @Override\n            public void run() {\n                ThreadUtils.postOnMainThread(() -> {\n                    if (model != null) {\n                        model.loadProcesses();\n                        model.loadMemoryInfo();\n                    }\n                });\n            }\n        }, 0, 10_000);\n    }\n\n    @Override\n    protected void onPause() {\n        mTimer.cancel();\n        mTimer.purge();\n        super.onPause();\n    }\n\n    @Override\n    public boolean onQueryTextSubmit(String query, int type) {\n        return false;\n    }\n\n    @Override\n    public boolean onQueryTextChange(String newText, int type) {\n        if (model != null) {\n            model.setQuery(newText, type);\n            return true;\n        }\n        return false;\n    }\n\n    @Override\n    public void onSelectionModeEnabled() {\n        mOnBackPressedCallback.setEnabled(true);\n    }\n\n    @Override\n    public void onSelectionModeDisabled() {\n        mOnBackPressedCallback.setEnabled(false);\n    }\n\n    @Override\n    public boolean onNavigationItemSelected(@NonNull MenuItem item) {\n        if (model == null || mAdapter == null) return true;\n        ArrayList<ProcessItem> selectedItems = mAdapter.getSelectedItems();\n        int id = item.getItemId();\n        if (id == R.id.action_kill) {\n            model.killSelectedProcesses();\n        } else if (id == R.id.action_force_stop) {\n            handleBatchOpWithWarning(BatchOpsManager.OP_FORCE_STOP);\n        } else if (id == R.id.action_disable_background) {\n            handleBatchOpWithWarning(BatchOpsManager.OP_DISABLE_BACKGROUND);\n        } else if (id == R.id.action_view_logs) {\n            // Should be a singleton list\n            if (selectedItems.size() == 1) {\n                ProcessItem processItem = selectedItems.get(0);\n                Intent logViewerIntent = new Intent(getApplicationContext(), LogViewerActivity.class)\n                        .putExtra(LogViewerActivity.EXTRA_FILTER, SearchCriteria.PID_KEYWORD + processItem.pid)\n                        .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);\n                startActivity(logViewerIntent);\n            }\n        }\n        return false;\n    }\n\n    @Override\n    public boolean onSelectionChange(int selectionCount) {\n        if (mSelectionMenu == null || mAdapter == null) {\n            return false;\n        }\n        ArrayList<ProcessItem> selectedItems = mAdapter.getSelectedItems();\n        MenuItem kill = mSelectionMenu.findItem(R.id.action_kill);\n        MenuItem forceStop = mSelectionMenu.findItem(R.id.action_force_stop);\n        MenuItem preventBackground = mSelectionMenu.findItem(R.id.action_disable_background);\n        MenuItem viewLogs = mSelectionMenu.findItem(R.id.action_view_logs);\n        viewLogs.setEnabled(FeatureController.isLogViewerEnabled() && selectedItems.size() == 1);\n        int appsCount = 0;\n        for (Object item : selectedItems) {\n            if (item instanceof AppProcessItem) {\n                ++appsCount;\n            } else break;\n        }\n        forceStop.setEnabled(appsCount != 0 && appsCount == selectedItems.size());\n        forceStop.setVisible(SelfPermissions.checkSelfOrRemotePermission(ManifestCompat.permission.FORCE_STOP_PACKAGES));\n        preventBackground.setEnabled(appsCount != 0 && appsCount == selectedItems.size());\n        boolean killEnabled = Ops.isWorkingUidRoot();\n        if (killEnabled && !mEnableKillForSystem) {\n            for (ProcessItem item : selectedItems) {\n                if (item.uid < Process.FIRST_APPLICATION_UID) {\n                    killEnabled = false;\n                    break;\n                }\n            }\n        }\n        kill.setEnabled(!selectedItems.isEmpty() && killEnabled);\n        return true;\n    }\n\n    private void handleBatchOp(@BatchOpsManager.OpType int op) {\n        if (model == null) return;\n        if (mProgressIndicator != null) {\n            mProgressIndicator.show();\n        }\n        BatchOpsManager.Result input = new BatchOpsManager.Result(model.getSelectedPackagesWithUsers());\n        BatchQueueItem item = BatchQueueItem.getBatchOpQueue(op, input.getFailedPackages(), input.getAssociatedUsers(), null);\n        Intent intent = BatchOpsService.getServiceIntent(this, item);\n        ContextCompat.startForegroundService(this, intent);\n    }\n\n    private void handleBatchOpWithWarning(@BatchOpsManager.OpType int op) {\n        new MaterialAlertDialogBuilder(this)\n                .setTitle(R.string.are_you_sure)\n                .setMessage(R.string.this_action_cannot_be_undone)\n                .setPositiveButton(R.string.yes, (dialog, which) -> handleBatchOp(op))\n                .setNegativeButton(R.string.no, null)\n                .show();\n    }\n\n    void refresh() {\n        if (mProgressIndicator == null || model == null) return;\n        mProgressIndicator.show();\n        model.loadProcesses();\n        model.loadMemoryInfo();\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/runningapps/RunningAppsAdapter.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.runningapps;\n\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.pm.ApplicationInfo;\nimport android.graphics.Color;\nimport android.os.Process;\nimport android.text.Spannable;\nimport android.text.TextUtils;\nimport android.text.format.Formatter;\nimport android.text.style.ForegroundColorSpan;\nimport android.view.LayoutInflater;\nimport android.view.Menu;\nimport android.view.MenuItem;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.ImageView;\nimport android.widget.TextView;\n\nimport androidx.annotation.AttrRes;\nimport androidx.annotation.NonNull;\nimport androidx.appcompat.widget.LinearLayoutCompat;\nimport androidx.appcompat.widget.PopupMenu;\n\nimport com.google.android.material.button.MaterialButton;\nimport com.google.android.material.card.MaterialCardView;\nimport com.google.android.material.color.MaterialColors;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.compat.ManifestCompat;\nimport io.github.muntashirakon.AppManager.logcat.LogViewerActivity;\nimport io.github.muntashirakon.AppManager.logcat.struct.SearchCriteria;\nimport io.github.muntashirakon.AppManager.self.SelfPermissions;\nimport io.github.muntashirakon.AppManager.self.imagecache.ImageLoader;\nimport io.github.muntashirakon.AppManager.settings.FeatureController;\nimport io.github.muntashirakon.AppManager.settings.Ops;\nimport io.github.muntashirakon.AppManager.settings.Prefs;\nimport io.github.muntashirakon.AppManager.utils.LangUtils;\nimport io.github.muntashirakon.AppManager.utils.UIUtils;\nimport io.github.muntashirakon.AppManager.utils.appearance.ColorCodes;\nimport io.github.muntashirakon.io.Paths;\nimport io.github.muntashirakon.proc.ProcMemoryInfo;\nimport io.github.muntashirakon.util.AccessibilityUtils;\nimport io.github.muntashirakon.util.AdapterUtils;\nimport io.github.muntashirakon.widget.MultiSelectionView;\n\npublic class RunningAppsAdapter extends MultiSelectionView.Adapter<MultiSelectionView.ViewHolder> {\n    private static final int VIEW_TYPE_MEMORY_INFO = 1;\n    private static final int VIEW_TYPE_PROCESS_INFO = 2;\n\n    private final RunningAppsActivity mActivity;\n    private final RunningAppsViewModel mModel;\n    private final int mQueryStringHighlightColor;\n    private final Object mLock = new Object();\n    @NonNull\n    private final List<ProcessItem> mProcessItems = new ArrayList<>();\n    private ProcMemoryInfo mProcMemoryInfo;\n\n    RunningAppsAdapter(@NonNull RunningAppsActivity activity) {\n        super();\n        mActivity = activity;\n        mModel = activity.model;\n        mQueryStringHighlightColor = ColorCodes.getQueryStringHighlightColor(activity);\n    }\n\n    void setDefaultList(@NonNull List<ProcessItem> processItems) {\n        synchronized (mLock) {\n            AdapterUtils.notifyDataSetChanged(this, 1, mProcessItems, processItems);\n        }\n        notifySelectionChange();\n    }\n\n    public void setDeviceMemoryInfo(ProcMemoryInfo procMemoryInfo) {\n        mProcMemoryInfo = procMemoryInfo;\n        notifyItemChanged(0, AdapterUtils.STUB);\n    }\n\n    @Override\n    public int getItemViewType(int position) {\n        if (position == 0) return VIEW_TYPE_MEMORY_INFO;\n        return VIEW_TYPE_PROCESS_INFO;\n    }\n\n    @NonNull\n    @Override\n    public MultiSelectionView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {\n        if (viewType == VIEW_TYPE_MEMORY_INFO) {\n            View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.header_running_apps_memory_info, parent, false);\n            return new HeaderViewHolder(view);\n        }\n        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_running_app, parent, false);\n        return new BodyViewHolder(view);\n    }\n\n    @Override\n    public void onBindViewHolder(@NonNull MultiSelectionView.ViewHolder holder, int position) {\n        if (position == 0) {\n            onBindViewHolder((HeaderViewHolder) holder);\n        } else {\n            onBindViewHolder((BodyViewHolder) holder, position);\n            super.onBindViewHolder(holder, position);\n        }\n    }\n\n    private void onBindViewHolder(@NonNull HeaderViewHolder holder) {\n        if (mProcMemoryInfo == null) {\n            return;\n        }\n        Context context = holder.itemView.getContext();\n        StringBuilder contentDescription = new StringBuilder();\n        // Memory\n        long appMemory = mProcMemoryInfo.getApplicationMemory();\n        long cachedMemory = mProcMemoryInfo.getCachedMemory();\n        long buffers = mProcMemoryInfo.getBuffers();\n        long freeMemory = mProcMemoryInfo.getFreeMemory();\n        double total = appMemory + cachedMemory + buffers + freeMemory;\n        boolean totalIsNonZero = total > 0;\n        String fUsedMemory = Formatter.formatFileSize(context, mProcMemoryInfo.getUsedMemory());\n        String fTotalMemory = Formatter.formatFileSize(context, mProcMemoryInfo.getTotalMemory());\n        String fAvailableMemory = Formatter.formatFileSize(context, mProcMemoryInfo.getAvailableMemory());\n        String fAppMemory = Formatter.formatShortFileSize(context, appMemory);\n        String fCachedMemory = Formatter.formatShortFileSize(context, cachedMemory);\n        String fBuffers = Formatter.formatShortFileSize(context, buffers);\n        String fFreeMemory = Formatter.formatShortFileSize(context, freeMemory);\n        AdapterUtils.setVisible(holder.mMemoryInfoChart, totalIsNonZero);\n        AdapterUtils.setVisible(holder.mMemoryShortInfoView, totalIsNonZero);\n        AdapterUtils.setVisible(holder.mMemoryInfoView, totalIsNonZero);\n        if (totalIsNonZero) {\n            holder.mMemoryInfoChart.post(() -> {\n                int width = holder.mMemoryInfoChart.getWidth();\n                setLayoutWidth(holder.mMemoryInfoChartChildren[0], (int) (width * appMemory / total));\n                setLayoutWidth(holder.mMemoryInfoChartChildren[1], (int) (width * cachedMemory / total));\n                setLayoutWidth(holder.mMemoryInfoChartChildren[2], (int) (width * buffers / total));\n            });\n            // Update content description for memory (free memory is not important for accessibility)\n            contentDescription.append(context.getString(R.string.memory_usage_accessibility_description,\n                    fUsedMemory, fTotalMemory, fAvailableMemory, fAppMemory, fCachedMemory, fBuffers));\n        } else {\n            contentDescription.append(context.getString(R.string.memory_usage_unavailable));\n        }\n        holder.mMemoryShortInfoView.setText(UIUtils.getStyledKeyValue(context, R.string.memory,\n                fUsedMemory + \"/\" + fTotalMemory + \" (\" +\n                context.getString(R.string.available_memory, fAvailableMemory) + \")\"));\n        // Set color info\n        Spannable memInfo = UIUtils.charSequenceToSpannable(context.getString(R.string.memory_chart_info,\n                fAppMemory, fCachedMemory, fBuffers, fFreeMemory));\n        setColors(holder.itemView, memInfo, new int[]{com.google.android.material.R.attr.colorOnSurface, androidx.appcompat.R.attr.colorPrimary, com.google.android.material.R.attr.colorTertiary,\n                com.google.android.material.R.attr.colorSurfaceVariant});\n        holder.mMemoryInfoView.setText(memInfo);\n\n        // Swap\n        long usedSwap = mProcMemoryInfo.getUsedSwap();\n        long totalSwap = mProcMemoryInfo.getTotalSwap();\n        String fUsedSwap = Formatter.formatFileSize(context, usedSwap);\n        String fTotalSwap = Formatter.formatFileSize(context, totalSwap);\n        boolean totalSwapIsNonZero = totalSwap > 0;\n        AdapterUtils.setVisible(holder.mSwapInfoChart, totalSwapIsNonZero);\n        AdapterUtils.setVisible(holder.mSwapShortInfoView, totalSwapIsNonZero);\n        AdapterUtils.setVisible(holder.mSwapInfoView, totalSwapIsNonZero);\n        if (totalSwapIsNonZero) {\n            holder.mSwapInfoChart.post(() -> {\n                int width = holder.mSwapInfoChart.getWidth();\n                setLayoutWidth(holder.mSwapInfoChartChildren[0], (int) (width * usedSwap / totalSwap));\n            });\n            // Update content description for swap\n            contentDescription.append(\"\\n\\n\");\n            contentDescription.append(context.getString(R.string.swap_usage_accessibility_description, fTotalSwap, fUsedSwap));\n        }\n        holder.mSwapShortInfoView.setText(UIUtils.getStyledKeyValue(context, R.string.swap, fUsedSwap + \"/\" + fTotalSwap));\n        // Set color and size info\n        Spannable swapInfo = UIUtils.charSequenceToSpannable(context.getString(R.string.swap_chart_info, Formatter\n                .formatShortFileSize(context, usedSwap), Formatter.formatShortFileSize(context, totalSwap - usedSwap)));\n        setColors(holder.itemView, swapInfo, new int[]{com.google.android.material.R.attr.colorOnSurface, com.google.android.material.R.attr.colorSurfaceVariant});\n        holder.mSwapInfoView.setText(swapInfo);\n        holder.itemView.setContentDescription(contentDescription);\n    }\n\n    private void onBindViewHolder(@NonNull BodyViewHolder holder, int position) {\n        ProcessItem processItem;\n        synchronized (mLock) {\n            processItem = mProcessItems.get(position);\n        }\n        ApplicationInfo applicationInfo;\n        if (processItem instanceof AppProcessItem) {\n            applicationInfo = ((AppProcessItem) processItem).packageInfo.applicationInfo;\n        } else applicationInfo = null;\n        String processName = processItem.name;\n        // Load icon\n        holder.icon.setTag(processName);\n        ImageLoader.getInstance().displayImage(processName, applicationInfo, holder.icon);\n        // Set process name\n        holder.processName.setText(UIUtils.getHighlightedText(processName, mModel.getQuery(), mQueryStringHighlightColor));\n        // Set package name\n        AdapterUtils.setVisible(holder.packageName, applicationInfo != null);\n        if (applicationInfo != null) {\n            holder.packageName.setText(UIUtils.getHighlightedText(applicationInfo.packageName, mModel.getQuery(), mQueryStringHighlightColor));\n        }\n        // Set process IDs\n        holder.processIds.setText(mActivity.getString(R.string.pid_and_ppid, processItem.pid, processItem.ppid));\n        // Set memory usage\n        holder.memoryUsage.setText(mActivity.getString(R.string.memory_virtual_memory,\n                Formatter.formatFileSize(mActivity, processItem.getMemory()),\n                Formatter.formatFileSize(mActivity, processItem.getVirtualMemory())));\n        // Set user info\n        String userInfo = mActivity.getString(R.string.user_and_uid, processItem.user, processItem.uid);\n        String stateInfo;\n        if (TextUtils.isEmpty(processItem.state_extra)) {\n            stateInfo = mActivity.getString(R.string.process_state, processItem.state);\n        } else {\n            stateInfo = mActivity.getString(R.string.process_state_with_extra, processItem.state, processItem.state_extra);\n        }\n        holder.userAndStateInfo.setText(String.format(\"%s, %s\", userInfo, stateInfo));\n        holder.selinuxContext.setText(String.format(\"SELinux%s %s\", LangUtils.getSeparatorString(),\n                processItem.context));\n        // Set more\n        holder.more.setOnClickListener(v -> {\n            PopupMenu popupMenu = new PopupMenu(mActivity, holder.more);\n            popupMenu.setForceShowIcon(true);\n            popupMenu.inflate(R.menu.activity_running_apps_popup_actions);\n            Menu menu = popupMenu.getMenu();\n            // Set kill\n            MenuItem killItem = menu.findItem(R.id.action_kill);\n            if ((processItem.uid >= Process.FIRST_APPLICATION_UID || Prefs.RunningApps.enableKillForSystemApps()) && Ops.isWorkingUidRoot()) {\n                killItem.setVisible(true).setOnMenuItemClickListener(item -> {\n                    mModel.killProcess(processItem);\n                    return true;\n                });\n            } else killItem.setVisible(false);\n            // Set view logs\n            MenuItem viewLogsItem = menu.findItem(R.id.action_view_logs);\n            if (FeatureController.isLogViewerEnabled()) {\n                viewLogsItem.setVisible(true).setOnMenuItemClickListener(item -> {\n                    Intent logViewerIntent = new Intent(mActivity.getApplicationContext(), LogViewerActivity.class)\n                            .putExtra(LogViewerActivity.EXTRA_FILTER, SearchCriteria.PID_KEYWORD + processItem.pid)\n                            .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);\n                    mActivity.startActivity(logViewerIntent);\n                    return true;\n                });\n            } else viewLogsItem.setVisible(false);\n            // Scan using VT\n            MenuItem scanVtIem = menu.findItem(R.id.action_scan_vt);\n            String firstCliArg = processItem.getCommandlineArgs()[0];\n            if (mModel.isVirusTotalAvailable() && (applicationInfo != null || Paths.get(firstCliArg).canRead())) {\n                // TODO: 7/1/22 Check other arguments for files, too?\n                scanVtIem.setVisible(true).setOnMenuItemClickListener(item -> {\n                    mModel.scanWithVt(processItem);\n                    return true;\n                });\n            } else scanVtIem.setVisible(false);\n            // Set force-stop\n            MenuItem forceStopItem = menu.findItem(R.id.action_force_stop);\n            if (applicationInfo != null) {\n                forceStopItem.setOnMenuItemClickListener(item -> {\n                            mModel.forceStop(applicationInfo);\n                            return true;\n                        })\n                        .setEnabled(SelfPermissions.checkSelfOrRemotePermission(ManifestCompat.permission.FORCE_STOP_PACKAGES));\n            } else forceStopItem.setEnabled(false);\n            MenuItem bgItem = menu.findItem(R.id.action_disable_background);\n            if (applicationInfo != null) {\n                forceStopItem.setOnMenuItemClickListener(item -> {\n                            mModel.forceStop(applicationInfo);\n                            return true;\n                        })\n                        .setVisible(SelfPermissions.checkSelfOrRemotePermission(ManifestCompat.permission.FORCE_STOP_PACKAGES));\n                if (mModel.canRunInBackground(applicationInfo)) {\n                    bgItem.setVisible(true).setOnMenuItemClickListener(item -> {\n                        mModel.preventBackgroundRun(applicationInfo);\n                        return true;\n                    });\n                } else bgItem.setVisible(false);\n            } else {\n                forceStopItem.setVisible(false);\n                bgItem.setVisible(false);\n            }\n            // Display popup menu\n            popupMenu.show();\n        });\n        // Set selections\n        holder.icon.setOnClickListener(v -> {\n            toggleSelection(position);\n            AccessibilityUtils.requestAccessibilityFocus(holder.itemView);\n        });\n        holder.itemView.setOnLongClickListener(v -> {\n            ProcessItem lastSelectedItem = mModel.getLastSelectedItem();\n            int lastSelectedItemPosition = lastSelectedItem == null ? -1 : mProcessItems.indexOf(lastSelectedItem);\n            if (lastSelectedItemPosition >= 0) {\n                // Select from last selection to this selection\n                selectRange(lastSelectedItemPosition + 1, position);\n            } else {\n                toggleSelection(position);\n                AccessibilityUtils.requestAccessibilityFocus(holder.itemView);\n            }\n            return true;\n        });\n        // Open process details\n        holder.itemView.setOnClickListener(v -> {\n            if (isInSelectionMode()) {\n                toggleSelection(position);\n                AccessibilityUtils.requestAccessibilityFocus(holder.itemView);\n            } else {\n                mModel.requestDisplayProcessDetails(processItem);\n            }\n        });\n        holder.itemView.setStrokeColor(Color.TRANSPARENT);\n    }\n\n    @Override\n    public long getItemId(int position) {\n        if (position == 0) {\n            return mProcMemoryInfo != null ? mProcMemoryInfo.hashCode() : View.NO_ID;\n        }\n        synchronized (mLock) {\n            return mProcessItems.get(position).hashCode();\n        }\n    }\n\n    @Override\n    protected boolean select(int position) {\n        if (position == 0) {\n            return false;\n        }\n        synchronized (mLock) {\n            mModel.select(mProcessItems.get(position));\n            return true;\n        }\n    }\n\n    @Override\n    protected boolean deselect(int position) {\n        if (position == 0) {\n            return false;\n        }\n        synchronized (mLock) {\n            mModel.deselect(mProcessItems.get(position));\n            return true;\n        }\n    }\n\n    @Override\n    protected boolean isSelected(int position) {\n        if (position == 0) {\n            return false;\n        }\n        synchronized (mLock) {\n            return mModel.isSelected(mProcessItems.get(position));\n        }\n    }\n\n    @Override\n    protected boolean isSelectable(int position) {\n        return position > 0;\n    }\n\n    @Override\n    protected void cancelSelection() {\n        super.cancelSelection();\n        mModel.clearSelections();\n    }\n\n    @NonNull\n    public ArrayList<ProcessItem> getSelectedItems() {\n        return mModel.getSelections();\n    }\n\n    @Override\n    protected int getSelectedItemCount() {\n        return mModel.getSelectionCount();\n    }\n\n    @Override\n    protected int getTotalItemCount() {\n        return mModel.getTotalCount();\n    }\n\n    @Override\n    public int getItemCount() {\n        synchronized (mLock) {\n            return mProcessItems.size();\n        }\n    }\n\n    private static void setColors(@NonNull View v, @NonNull Spannable text, @NonNull @AttrRes int[] colors) {\n        int idx = 0;\n        for (int color : colors) {\n            idx = text.toString().indexOf('●', idx);\n            if (idx == -1) break;\n            text.setSpan(new ForegroundColorSpan(MaterialColors.getColor(v, color)), idx, idx + 1,\n                    Spannable.SPAN_INCLUSIVE_EXCLUSIVE);\n            ++idx;\n        }\n    }\n\n    private static void setLayoutWidth(@NonNull View view, int width) {\n        ViewGroup.LayoutParams lp = view.getLayoutParams();\n        lp.width = width;\n        view.setLayoutParams(lp);\n    }\n\n    static class HeaderViewHolder extends MultiSelectionView.ViewHolder {\n        private final TextView mMemoryShortInfoView;\n        private final TextView mMemoryInfoView;\n        private final View[] mMemoryInfoChartChildren;\n        private final LinearLayoutCompat mMemoryInfoChart;\n        private final TextView mSwapShortInfoView;\n        private final TextView mSwapInfoView;\n        private final View[] mSwapInfoChartChildren;\n        private final LinearLayoutCompat mSwapInfoChart;\n\n        public HeaderViewHolder(@NonNull View itemView) {\n            super(itemView);\n            mMemoryShortInfoView = itemView.findViewById(R.id.memory_usage);\n            mMemoryInfoView = itemView.findViewById(R.id.memory_usage_info);\n            mMemoryInfoChart = itemView.findViewById(R.id.memory_usage_chart);\n            int childCount = mMemoryInfoChart.getChildCount();\n            mMemoryInfoChartChildren = new View[childCount];\n            for (int i = 0; i < childCount; ++i) {\n                mMemoryInfoChartChildren[i] = mMemoryInfoChart.getChildAt(i);\n            }\n            mSwapShortInfoView = itemView.findViewById(R.id.swap_usage);\n            mSwapInfoView = itemView.findViewById(R.id.swap_usage_info);\n            mSwapInfoChart = itemView.findViewById(R.id.swap_usage_chart);\n            childCount = mSwapInfoChart.getChildCount();\n            mSwapInfoChartChildren = new View[childCount];\n            for (int i = 0; i < childCount; ++i) {\n                mSwapInfoChartChildren[i] = mSwapInfoChart.getChildAt(i);\n            }\n        }\n    }\n\n    static class BodyViewHolder extends MultiSelectionView.ViewHolder {\n        MaterialCardView itemView;\n        ImageView icon;\n        MaterialButton more;\n        TextView processName;\n        TextView packageName;\n        TextView processIds;\n        TextView memoryUsage;\n        TextView userAndStateInfo;\n        TextView selinuxContext;\n\n        public BodyViewHolder(@NonNull View itemView) {\n            super(itemView);\n            this.itemView = (MaterialCardView) itemView;\n            icon = itemView.findViewById(R.id.icon);\n            more = itemView.findViewById(R.id.more);\n            processName = itemView.findViewById(R.id.process_name);\n            packageName = itemView.findViewById(R.id.package_name);\n            processIds = itemView.findViewById(R.id.process_ids);\n            memoryUsage = itemView.findViewById(R.id.memory_usage);\n            userAndStateInfo = itemView.findViewById(R.id.user_state_info);\n            selinuxContext = itemView.findViewById(R.id.selinux_context);\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/runningapps/RunningAppsViewModel.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.runningapps;\n\nimport android.app.AppOpsManager;\nimport android.app.Application;\nimport android.content.pm.ApplicationInfo;\nimport android.os.Build;\nimport android.os.RemoteException;\nimport android.os.UserHandleHidden;\nimport android.text.TextUtils;\n\nimport androidx.annotation.AnyThread;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.WorkerThread;\nimport androidx.core.util.Pair;\nimport androidx.lifecycle.AndroidViewModel;\nimport androidx.lifecycle.LiveData;\nimport androidx.lifecycle.MutableLiveData;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.Iterator;\nimport java.util.LinkedHashSet;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Objects;\nimport java.util.Set;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.TimeUnit;\n\nimport io.github.muntashirakon.AppManager.compat.AppOpsManagerCompat;\nimport io.github.muntashirakon.AppManager.compat.PackageManagerCompat;\nimport io.github.muntashirakon.AppManager.logs.Log;\nimport io.github.muntashirakon.AppManager.misc.AdvancedSearchView;\nimport io.github.muntashirakon.AppManager.runner.Runner;\nimport io.github.muntashirakon.AppManager.scanner.vt.VirusTotal;\nimport io.github.muntashirakon.AppManager.scanner.vt.VtFileReport;\nimport io.github.muntashirakon.AppManager.settings.Prefs;\nimport io.github.muntashirakon.AppManager.types.UserPackagePair;\nimport io.github.muntashirakon.AppManager.utils.DigestUtils;\nimport io.github.muntashirakon.AppManager.utils.MultithreadedExecutor;\nimport io.github.muntashirakon.io.Path;\nimport io.github.muntashirakon.io.Paths;\nimport io.github.muntashirakon.proc.ProcFs;\nimport io.github.muntashirakon.proc.ProcMemoryInfo;\n\npublic class RunningAppsViewModel extends AndroidViewModel {\n    @RunningAppsActivity.SortOrder\n    private int mSortOrder;\n    @RunningAppsActivity.Filter\n    private int mFilter;\n    private final MultithreadedExecutor mExecutor = MultithreadedExecutor.getNewInstance();\n    @Nullable\n    private final VirusTotal mVt;\n\n    public RunningAppsViewModel(@NonNull Application application) {\n        super(application);\n        mSortOrder = Prefs.RunningApps.getSortOrder();\n        mFilter = Prefs.RunningApps.getFilters();\n        mVt = VirusTotal.getInstance();\n    }\n\n    @Override\n    protected void onCleared() {\n        mExecutor.shutdownNow();\n        super.onCleared();\n    }\n\n    public boolean isVirusTotalAvailable() {\n        return mVt != null;\n    }\n\n    // Null = Uploading, NonNull = Queued\n    private final MutableLiveData<Pair<ProcessItem, String>> mVtFileUpload = new MutableLiveData<>();\n    // Null = Failed, NonNull = Result generated\n    private final MutableLiveData<Pair<ProcessItem, VtFileReport>> mVtFileReport = new MutableLiveData<>();\n\n    public MutableLiveData<Pair<ProcessItem, VtFileReport>> getVtFileReport() {\n        return mVtFileReport;\n    }\n\n    public MutableLiveData<Pair<ProcessItem, String>> getVtFileUpload() {\n        return mVtFileUpload;\n    }\n\n    @AnyThread\n    public void scanWithVt(@NonNull ProcessItem processItem) {\n        String file;\n        if (processItem instanceof AppProcessItem) {\n            file = ((AppProcessItem) processItem).packageInfo.applicationInfo.publicSourceDir;\n        } else file = processItem.getCommandlineArgs()[0];\n        if (mVt == null || file == null) {\n            mVtFileReport.postValue(new Pair<>(processItem, null));\n            return;\n        }\n        mExecutor.submit(() -> {\n            Path proxyFile = Paths.get(file);\n            if (!proxyFile.canRead()) {\n                mVtFileReport.postValue(new Pair<>(processItem, null));\n                return;\n            }\n            String sha256 = DigestUtils.getHexDigest(DigestUtils.SHA_256, proxyFile);\n            try {\n                mVt.fetchFileReportOrScan(proxyFile, sha256, new VirusTotal.FullScanResponseInterface() {\n                    @Override\n                    public boolean uploadFile() {\n                        mUploadingEnabled = false;\n                        mUploadingEnabledWatcher = new CountDownLatch(1);\n                        mVtFileUpload.postValue(new Pair<>(processItem, null));\n                        try {\n                            mUploadingEnabledWatcher.await(2, TimeUnit.MINUTES);\n                        } catch (InterruptedException ignore) {\n                        }\n                        return mUploadingEnabled;\n                    }\n\n                    @Override\n                    public void onUploadInitiated() {\n                    }\n\n                    @Override\n                    public void onUploadCompleted(@NonNull String permalink) {\n                        mVtFileUpload.postValue(new Pair<>(processItem, permalink));\n                    }\n\n                    @Override\n                    public void onReportReceived(@NonNull VtFileReport report) {\n                        mVtFileReport.postValue(new Pair<>(processItem, report));\n                    }\n                });\n            } catch (IOException e) {\n                e.printStackTrace();\n                mVtFileReport.postValue(new Pair<>(processItem, null));\n            }\n        });\n    }\n\n    @NonNull\n    private final MutableLiveData<List<ProcessItem>> mProcessLiveData = new MutableLiveData<>();\n\n    @NonNull\n    public LiveData<List<ProcessItem>> getProcessLiveData() {\n        return mProcessLiveData;\n    }\n\n    @NonNull\n    private final MutableLiveData<ProcessItem> mProcessItemLiveData = new MutableLiveData<>();\n\n    @NonNull\n    public LiveData<ProcessItem> observeProcessDetails() {\n        return mProcessItemLiveData;\n    }\n\n    @AnyThread\n    public void requestDisplayProcessDetails(@NonNull ProcessItem processItem) {\n        mProcessItemLiveData.postValue(processItem);\n    }\n\n    @NonNull\n    private final List<ProcessItem> mProcessList = new ArrayList<>();\n\n    @AnyThread\n    public void loadProcesses() {\n        mExecutor.submit(() -> {\n            synchronized (mProcessList) {\n                try {\n                    mProcessList.clear();\n                    mProcessList.addAll(new ProcessParser().parse());\n                    filterAndSort();\n                } catch (Throwable th) {\n                    Log.e(\"RunningApps\", th);\n                }\n            }\n        });\n    }\n\n    @NonNull\n    private final MutableLiveData<ProcMemoryInfo> mDeviceMemoryInfo = new MutableLiveData<>();\n\n    @NonNull\n    public MutableLiveData<ProcMemoryInfo> getDeviceMemoryInfo() {\n        return mDeviceMemoryInfo;\n    }\n\n    @AnyThread\n    public void loadMemoryInfo() {\n        mExecutor.submit(() -> mDeviceMemoryInfo.postValue(ProcFs.getInstance().getMemoryInfo()));\n    }\n\n    private final MutableLiveData<Pair<ProcessItem, Boolean>> mKillProcessResult = new MutableLiveData<>();\n    private final MutableLiveData<List<ProcessItem>> mKillSelectedProcessesResult = new MutableLiveData<>();\n\n    public void killProcess(ProcessItem processItem) {\n        mExecutor.submit(() -> mKillProcessResult.postValue(new Pair<>(processItem, Runner.runCommand(\n                new String[]{\"kill\", \"-9\", String.valueOf(processItem.pid)}).isSuccessful())));\n    }\n\n    public LiveData<Pair<ProcessItem, Boolean>> observeKillProcess() {\n        return mKillProcessResult;\n    }\n\n    public void killSelectedProcesses() {\n        mExecutor.submit(() -> {\n            List<ProcessItem> failedProcesses = new ArrayList<>();\n            for (ProcessItem processItem : mSelectedItems) {\n                if (!Runner.runCommand(new String[]{\"kill\", \"-9\", String.valueOf(processItem.pid)}).isSuccessful()) {\n                    failedProcesses.add(processItem);\n                }\n            }\n            mKillSelectedProcessesResult.postValue(failedProcesses);\n        });\n    }\n\n    public LiveData<List<ProcessItem>> observeKillSelectedProcess() {\n        return mKillSelectedProcessesResult;\n    }\n\n    private final MutableLiveData<Pair<ApplicationInfo, Boolean>> mForceStopAppResult = new MutableLiveData<>();\n\n    public void forceStop(@NonNull ApplicationInfo info) {\n        mExecutor.submit(() -> {\n            try {\n                PackageManagerCompat.forceStopPackage(info.packageName, UserHandleHidden.getUserId(info.uid));\n                mForceStopAppResult.postValue(new Pair<>(info, true));\n            } catch (SecurityException e) {\n                e.printStackTrace();\n                mForceStopAppResult.postValue(new Pair<>(info, false));\n            }\n        });\n    }\n\n    public LiveData<Pair<ApplicationInfo, Boolean>> observeForceStop() {\n        return mForceStopAppResult;\n    }\n\n    private final MutableLiveData<Pair<ApplicationInfo, Boolean>> mPreventBackgroundRunResult = new MutableLiveData<>();\n\n    public boolean canRunInBackground(@NonNull ApplicationInfo info) {\n        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {\n            return true;\n        }\n        try {\n            AppOpsManagerCompat appOpsManager = new AppOpsManagerCompat();\n            boolean canRun;\n            {\n                int mode = appOpsManager.checkOperation(AppOpsManagerCompat.OP_RUN_IN_BACKGROUND, info.uid, info.packageName);\n                canRun = (mode != AppOpsManager.MODE_IGNORED && mode != AppOpsManager.MODE_ERRORED);\n            }\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {\n                int mode = appOpsManager.checkOperation(AppOpsManagerCompat.OP_RUN_ANY_IN_BACKGROUND, info.uid, info.packageName);\n                canRun |= (mode != AppOpsManager.MODE_IGNORED && mode != AppOpsManager.MODE_ERRORED);\n            }\n            return canRun;\n        } catch (RemoteException | SecurityException e) {\n            return true;\n        }\n    }\n\n    public void preventBackgroundRun(@NonNull ApplicationInfo info) {\n        mExecutor.submit(() -> {\n            try {\n                AppOpsManagerCompat appOpsService = new AppOpsManagerCompat();\n                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {\n                    appOpsService.setMode(AppOpsManagerCompat.OP_RUN_IN_BACKGROUND, info.uid, info.packageName,\n                            AppOpsManager.MODE_IGNORED);\n                }\n                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {\n                    appOpsService.setMode(AppOpsManagerCompat.OP_RUN_ANY_IN_BACKGROUND, info.uid, info.packageName,\n                            AppOpsManager.MODE_IGNORED);\n                }\n                // TODO: 14/2/23 Store it to the rules\n                mPreventBackgroundRunResult.postValue(new Pair<>(info, true));\n            } catch (RemoteException e) {\n                e.printStackTrace();\n                mPreventBackgroundRunResult.postValue(new Pair<>(info, false));\n            }\n        });\n    }\n\n    public LiveData<Pair<ApplicationInfo, Boolean>> observePreventBackgroundRun() {\n        return mPreventBackgroundRunResult;\n    }\n\n    public int getTotalCount() {\n        return mProcessList.size();\n    }\n\n    private String mQuery;\n    @AdvancedSearchView.SearchType\n    private int mQueryType;\n\n    public void setQuery(@Nullable String query, int searchType) {\n        if (query == null) {\n            mQuery = null;\n        } else if (searchType == AdvancedSearchView.SEARCH_TYPE_PREFIX) {\n            mQuery = query;\n        } else {\n            mQuery = query.toLowerCase(Locale.ROOT);\n        }\n        mQueryType = searchType;\n        mExecutor.submit(this::filterAndSort);\n    }\n\n    public String getQuery() {\n        return mQuery;\n    }\n\n    public void setSortOrder(int sortOrder) {\n        mSortOrder = sortOrder;\n        Prefs.RunningApps.setSortOrder(mSortOrder);\n        mExecutor.submit(this::filterAndSort);\n    }\n\n    public int getSortOrder() {\n        return mSortOrder;\n    }\n\n    public void addFilter(int filter) {\n        mFilter |= filter;\n        Prefs.RunningApps.setFilters(mFilter);\n        mExecutor.submit(this::filterAndSort);\n    }\n\n    public void removeFilter(int filter) {\n        mFilter &= ~filter;\n        Prefs.RunningApps.setFilters(mFilter);\n        mExecutor.submit(this::filterAndSort);\n    }\n\n    public int getFilter() {\n        return mFilter;\n    }\n\n    @WorkerThread\n    public void filterAndSort() {\n        List<ProcessItem> filteredProcessList = new ArrayList<>();\n        // Apply filters\n        // There are 3 filters with “and” relations: apps > user apps > query\n        boolean filterUserApps = (mFilter & RunningAppsActivity.FILTER_USER_APPS) != 0;\n        // If user apps filter is enabled, disable it since it'll be just an overhead\n        boolean filterApps = !filterUserApps && (mFilter & RunningAppsActivity.FILTER_APPS) != 0;\n        ApplicationInfo info;\n        for (ProcessItem item : mProcessList) {\n            // Filter by apps\n            if (filterApps && !(item instanceof AppProcessItem)) {\n                continue;\n            }\n            // Filter by user apps\n            if (filterUserApps) {\n                if (item instanceof AppProcessItem) {\n                    info = ((AppProcessItem) item).packageInfo.applicationInfo;\n                    if ((info.flags & ApplicationInfo.FLAG_SYSTEM) != 0) continue;\n                    // else it's an user app\n                } else continue;\n            }\n            filteredProcessList.add(item);\n        }\n        // Apply searching\n        if (!TextUtils.isEmpty(mQuery)) {\n            filteredProcessList = AdvancedSearchView.matches(mQuery, filteredProcessList,\n                    (AdvancedSearchView.ChoicesGenerator<ProcessItem>) item -> {\n                        if (item instanceof AppProcessItem) {\n                            return Arrays.asList(item.name.toLowerCase(Locale.getDefault()),\n                                    ((AppProcessItem) item).packageInfo.packageName.toLowerCase(Locale.getDefault()));\n                        }\n                        return Collections.singletonList(item.name.toLowerCase(Locale.getDefault()));\n                    }, mQueryType);\n        }\n        // Apply sorts\n        // Sort by pid first\n        //noinspection ComparatorCombinators\n        Collections.sort(filteredProcessList, (o1, o2) -> Integer.compare(o1.pid, o2.pid));\n        if (mSortOrder != RunningAppsActivity.SORT_BY_PID) {\n            Collections.sort(filteredProcessList, (o1, o2) -> {\n                ProcessItem p1 = Objects.requireNonNull(o1);\n                ProcessItem p2 = Objects.requireNonNull(o2);\n                switch (mSortOrder) {\n                    case RunningAppsActivity.SORT_BY_APPS_FIRST:\n                        return -Boolean.compare(p1 instanceof AppProcessItem, p2 instanceof AppProcessItem);\n                    case RunningAppsActivity.SORT_BY_MEMORY_USAGE:\n                        return -Long.compare(p1.rss, p2.rss);\n                    case RunningAppsActivity.SORT_BY_PROCESS_NAME:\n                        return p1.name.compareToIgnoreCase(p2.name);\n                    case RunningAppsActivity.SORT_BY_CPU_TIME:\n                        return -Long.compare(p1.getCpuTimeInMillis(), p1.getCpuTimeInMillis());\n                    case RunningAppsActivity.SORT_BY_PID:\n                    default:\n                        return Integer.compare(p1.pid, p2.pid);\n                }\n            });\n        }\n        mProcessLiveData.postValue(filteredProcessList);\n    }\n\n    private final Set<ProcessItem> mSelectedItems = new LinkedHashSet<>();\n\n    @Nullable\n    public ProcessItem getLastSelectedItem() {\n        // Last selected package is the same as the last added package.\n        Iterator<ProcessItem> it = mSelectedItems.iterator();\n        ProcessItem lastItem = null;\n        while (it.hasNext()) {\n            lastItem = it.next();\n        }\n        return lastItem;\n    }\n\n    public int getSelectionCount() {\n        return mSelectedItems.size();\n    }\n\n    public boolean isSelected(@NonNull ProcessItem processItem) {\n        return mSelectedItems.contains(processItem);\n    }\n\n    public void select(@Nullable ProcessItem processItem) {\n        if (processItem != null) {\n            mSelectedItems.add(processItem);\n        }\n    }\n\n    public void deselect(@Nullable ProcessItem processItem) {\n        if (processItem != null) {\n            mSelectedItems.remove(processItem);\n        }\n    }\n\n    public ArrayList<ProcessItem> getSelections() {\n        return new ArrayList<>(mSelectedItems);\n    }\n\n    @NonNull\n    public ArrayList<UserPackagePair> getSelectedPackagesWithUsers() {\n        ArrayList<UserPackagePair> userPackagePairs = new ArrayList<>();\n        for (ProcessItem processItem : mSelectedItems) {\n            if (processItem instanceof AppProcessItem) {\n                ApplicationInfo applicationInfo = ((AppProcessItem) processItem).packageInfo.applicationInfo;\n                userPackagePairs.add(new UserPackagePair(applicationInfo.packageName,\n                        UserHandleHidden.getUserId(applicationInfo.uid)));\n            }\n        }\n        return userPackagePairs;\n    }\n\n    public void clearSelections() {\n        mSelectedItems.clear();\n    }\n\n    private boolean mUploadingEnabled;\n    private CountDownLatch mUploadingEnabledWatcher;\n\n    public void enableUploading() {\n        mUploadingEnabled = true;\n        if (mUploadingEnabledWatcher != null) {\n            mUploadingEnabledWatcher.countDown();\n        }\n    }\n\n    public void disableUploading() {\n        mUploadingEnabled = false;\n        if (mUploadingEnabledWatcher != null) {\n            mUploadingEnabledWatcher.countDown();\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/scanner/ClassListingFragment.java",
    "content": "// SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.scanner;\n\nimport static io.github.muntashirakon.AppManager.misc.AdvancedSearchView.SEARCH_TYPE_REGEX;\n\nimport android.app.Activity;\nimport android.content.Intent;\nimport android.graphics.Typeface;\nimport android.os.Bundle;\nimport android.text.TextUtils;\nimport android.view.LayoutInflater;\nimport android.view.Menu;\nimport android.view.MenuInflater;\nimport android.view.MenuItem;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.Filter;\nimport android.widget.Filterable;\nimport android.widget.TextView;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.UiThread;\nimport androidx.core.view.MenuProvider;\nimport androidx.fragment.app.Fragment;\nimport androidx.lifecycle.Lifecycle;\nimport androidx.lifecycle.ViewModelProvider;\n\nimport com.google.android.material.card.MaterialCardView;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Objects;\n\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.editor.CodeEditorActivity;\nimport io.github.muntashirakon.AppManager.misc.AdvancedSearchView;\nimport io.github.muntashirakon.AppManager.utils.UIUtils;\nimport io.github.muntashirakon.AppManager.utils.appearance.ColorCodes;\nimport io.github.muntashirakon.util.AdapterUtils;\nimport io.github.muntashirakon.util.UiUtils;\nimport io.github.muntashirakon.widget.RecyclerView;\n\npublic class ClassListingFragment extends Fragment implements AdvancedSearchView.OnQueryTextListener, MenuProvider {\n    private TextView mEmptyView;\n    private boolean mTrackerClassesOnly;\n    private ClassListingAdapter mClassListingAdapter;\n\n    private List<String> mAllClasses;\n    private List<String> mTrackerClasses;\n    private ScannerViewModel mViewModel;\n    private ScannerActivity mActivity;\n\n    @Nullable\n    @Override\n    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {\n        return inflater.inflate(R.layout.fragment_class_lister, container, false);\n    }\n\n    @Override\n    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {\n        mViewModel = new ViewModelProvider(requireActivity()).get(ScannerViewModel.class);\n        mActivity = (ScannerActivity) requireActivity();\n        mAllClasses = mViewModel.getAllClasses();\n        mTrackerClasses = mViewModel.getTrackerClasses();\n        if (mAllClasses == null) {\n            mActivity.getOnBackPressedDispatcher().onBackPressed();\n            return;\n        }\n        if (mTrackerClasses == null) {\n            mTrackerClasses = Collections.emptyList();\n        }\n\n        mTrackerClassesOnly = false;\n\n        RecyclerView listView = view.findViewById(R.id.list_item);\n        UiUtils.applyWindowInsetsAsPaddingNoTop(listView);\n        mEmptyView = view.findViewById(android.R.id.empty);\n        listView.setEmptyView(mEmptyView);\n        mClassListingAdapter = new ClassListingAdapter(mActivity, mViewModel);\n        listView.setLayoutManager(UIUtils.getGridLayoutAt450Dp(mActivity));\n        listView.setAdapter(mClassListingAdapter);\n        mActivity.addMenuProvider(this, getViewLifecycleOwner(), Lifecycle.State.RESUMED);\n        showProgress(true);\n        setAdapterList();\n    }\n\n    @Override\n    public void onResume() {\n        super.onResume();\n        if (mClassListingAdapter != null && !TextUtils.isEmpty(mClassListingAdapter.mConstraint)) {\n            mClassListingAdapter.filter();\n        }\n    }\n\n    @UiThread\n    private void setAdapterList() {\n        if (!mTrackerClassesOnly) {\n            mClassListingAdapter.setDefaultList(mTrackerClasses);\n            mActivity.setSubtitle(getString(R.string.tracker_classes));\n        } else {\n            mClassListingAdapter.setDefaultList(mAllClasses);\n            mActivity.setSubtitle(getString(R.string.all_classes));\n        }\n        showProgress(false);\n    }\n\n    @Override\n    public boolean onQueryTextChange(String newText, @AdvancedSearchView.SearchType int type) {\n        if (mClassListingAdapter != null) {\n            mClassListingAdapter.filter(newText, type);\n        }\n        return true;\n    }\n\n    @Override\n    public boolean onQueryTextSubmit(String query, int type) {\n        return false;\n    }\n\n    @Override\n    public void onCreateMenu(@NonNull Menu menu, @NonNull MenuInflater inflater) {\n        inflater.inflate(R.menu.fragment_class_lister_actions, menu);\n        AdvancedSearchView searchView = (AdvancedSearchView) menu.findItem(R.id.action_search).getActionView();\n        Objects.requireNonNull(searchView).setOnQueryTextListener(this);\n    }\n\n    @Override\n    public boolean onMenuItemSelected(@NonNull MenuItem item) {\n        int id = item.getItemId();\n        if (id == R.id.action_toggle_class_listing) {\n            mTrackerClassesOnly = !mTrackerClassesOnly;\n            setAdapterList();\n        } else return false;\n        return true;\n    }\n\n    private void showProgress(boolean willShow) {\n        mActivity.showProgress(willShow);\n        mEmptyView.setText(willShow ? R.string.loading : R.string.no_tracker_class);\n    }\n\n    static class ClassListingAdapter extends RecyclerView.Adapter<ClassListingAdapter.ViewHolder> implements Filterable {\n        private Filter mFilter;\n        private String mConstraint;\n        @AdvancedSearchView.SearchType\n        private int mFilterType = AdvancedSearchView.SEARCH_TYPE_CONTAINS;\n        private List<String> mDefaultList;\n        private final Activity mActivity;\n        private final ScannerViewModel mViewModel;\n        @NonNull\n        private final List<String> mAdapterList = new ArrayList<>();\n        private final int mCardColor0;\n        private final int mCardColor1;\n        private final int mQueryStringHighlightColor;\n\n        ClassListingAdapter(@NonNull Activity activity, @NonNull ScannerViewModel viewModel) {\n            mActivity = activity;\n            mViewModel = viewModel;\n            mCardColor0 = ColorCodes.getListItemColor0(activity);\n            mCardColor1 = ColorCodes.getListItemColor1(activity);\n            mQueryStringHighlightColor = ColorCodes.getQueryStringHighlightColor(activity);\n        }\n\n        @UiThread\n        void setDefaultList(@NonNull List<String> list) {\n            mDefaultList = list;\n            filter();\n        }\n\n        void filter() {\n            if (!TextUtils.isEmpty(mConstraint)) {\n                filter(mConstraint, mFilterType);\n            } else {\n                AdapterUtils.notifyDataSetChanged(this, mAdapterList, mDefaultList);\n            }\n        }\n\n        void filter(String query, @AdvancedSearchView.SearchType int filterType) {\n            mConstraint = query;\n            mFilterType = filterType;\n            getFilter().filter(mConstraint);\n        }\n\n        @Override\n        public int getItemCount() {\n            synchronized (mAdapterList) {\n                return mAdapterList.size();\n            }\n        }\n\n        @Override\n        public long getItemId(int position) {\n            synchronized (mAdapterList) {\n                return mDefaultList.indexOf(mAdapterList.get(position));\n            }\n        }\n\n        @NonNull\n        @Override\n        public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {\n            View view = LayoutInflater.from(parent.getContext()).inflate(io.github.muntashirakon.ui.R.layout.m3_preference, parent, false);\n            return new ViewHolder(view);\n        }\n\n        @Override\n        public void onBindViewHolder(@NonNull ViewHolder holder, int position) {\n            String className;\n            synchronized (mAdapterList) {\n                className = mAdapterList.get(position);\n            }\n            TextView textView = holder.classNameView;\n            textView.setTypeface(Typeface.MONOSPACE);\n            if (mConstraint != null && className.toLowerCase(Locale.ROOT).contains(mConstraint)) {\n                // Highlight searched query\n                textView.setText(UIUtils.getHighlightedText(className, mConstraint, mQueryStringHighlightColor));\n            } else {\n                textView.setText(className);\n            }\n            holder.itemView.setCardBackgroundColor(position % 2 == 0 ? mCardColor1 : mCardColor0);\n            holder.itemView.setOnClickListener(v -> {\n                try {\n                    Intent intent = CodeEditorActivity.getIntent(mActivity, mViewModel.getUriFromClassName(className), null, null, true)\n                            .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);\n                    mActivity.startActivity(intent);\n                } catch (Exception e) {\n                    e.printStackTrace();\n                    UIUtils.displayLongToast(e.toString());\n                }\n            });\n        }\n\n        @Override\n        public Filter getFilter() {\n            if (mFilter == null)\n                mFilter = new Filter() {\n                    @Override\n                    protected FilterResults performFiltering(CharSequence charSequence) {\n                        String constraint = mFilterType == SEARCH_TYPE_REGEX ? charSequence.toString()\n                                : charSequence.toString().toLowerCase(Locale.ROOT);\n                        FilterResults filterResults = new FilterResults();\n                        if (constraint.isEmpty()) {\n                            filterResults.count = 0;\n                            filterResults.values = null;\n                            return filterResults;\n                        }\n\n                        List<String> list = AdvancedSearchView.matches(\n                                constraint,\n                                mDefaultList,\n                                (AdvancedSearchView.ChoiceGenerator<String>) object -> mFilterType == SEARCH_TYPE_REGEX ? object\n                                        : object.toLowerCase(Locale.ROOT),\n                                mFilterType);\n\n                        filterResults.count = list.size();\n                        filterResults.values = list;\n                        return filterResults;\n                    }\n\n                    @Override\n                    protected void publishResults(CharSequence charSequence, FilterResults filterResults) {\n                        synchronized (mAdapterList) {\n                            if (filterResults.values == null) {\n                                AdapterUtils.notifyDataSetChanged(ClassListingAdapter.this, mAdapterList, mDefaultList);\n                            } else {\n                                //noinspection unchecked\n                                AdapterUtils.notifyDataSetChanged(ClassListingAdapter.this, mAdapterList, (List<String>) filterResults.values);\n                            }\n                        }\n                    }\n                };\n            return mFilter;\n        }\n\n        public static class ViewHolder extends RecyclerView.ViewHolder {\n            final MaterialCardView itemView;\n            final TextView classNameView;\n\n            public ViewHolder(@NonNull View itemView) {\n                super(itemView);\n                this.itemView = (MaterialCardView) itemView;\n                itemView.findViewById(android.R.id.title).setVisibility(View.GONE);\n                itemView.findViewById(R.id.icon_frame).setVisibility(View.GONE);\n                classNameView = itemView.findViewById(android.R.id.summary);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/scanner/LibraryInfoDialog.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.scanner;\n\nimport android.os.Bundle;\nimport android.view.View;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.dialog.BottomSheetAlertDialogFragment;\n\npublic class LibraryInfoDialog extends BottomSheetAlertDialogFragment {\n    public static final String TAG = LibraryInfoDialog.class.getSimpleName();\n\n    @NonNull\n    public static LibraryInfoDialog getInstance(@NonNull CharSequence subtitle, @NonNull CharSequence message) {\n        LibraryInfoDialog dialog = new LibraryInfoDialog();\n        dialog.setArguments(getArgs(null, subtitle, message));\n        return dialog;\n    }\n\n    @Override\n    public void onBodyInitialized(@NonNull View bodyView, @Nullable Bundle savedInstanceState) {\n        super.onBodyInitialized(bodyView, savedInstanceState);\n        setTitle(R.string.lib_details);\n        setMessageIsSelectable(true);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/scanner/NativeLibraries.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.scanner;\n\nimport android.content.Context;\nimport android.text.format.Formatter;\n\nimport androidx.annotation.AnyThread;\nimport androidx.annotation.IntDef;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.WorkerThread;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.nio.ByteBuffer;\nimport java.nio.ByteOrder;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Enumeration;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Set;\nimport java.util.zip.ZipEntry;\nimport java.util.zip.ZipFile;\nimport java.util.zip.ZipInputStream;\n\nimport aosp.libcore.util.HexEncoding;\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.logs.Log;\nimport io.github.muntashirakon.AppManager.utils.LangUtils;\nimport io.github.muntashirakon.util.LocalizedString;\n\npublic class NativeLibraries {\n    public static final String TAG = NativeLibraries.class.getSimpleName();\n\n    private static final int ELF_MAGIC = 0x7f454c46; // 0x7f ELF\n\n    public static abstract class NativeLib implements LocalizedString {\n        @NonNull\n        private final String mPath;\n        @NonNull\n        private final String mName;\n        private final long mSize;\n        private final byte[] mMagic;\n\n        protected NativeLib(@NonNull String path, long size, byte[] magic) {\n            mPath = path;\n            mName = new File(path).getName();\n            mSize = size;\n            mMagic = magic;\n        }\n\n        @NonNull\n        public String getPath() {\n            return mPath;\n        }\n\n        @NonNull\n        public String getName() {\n            return mName;\n        }\n\n        public long getSize() {\n            return mSize;\n        }\n\n        public byte[] getMagic() {\n            return mMagic;\n        }\n\n        @NonNull\n        public static NativeLib parse(@NonNull String path, long size, @NonNull InputStream is) throws IOException {\n            byte[] header = new byte[20]; // First 20 bytes is enough\n            is.read(header);\n            ByteBuffer buffer = ByteBuffer.wrap(header);\n            int magic = buffer.getInt();\n            if (magic != ELF_MAGIC) {\n                // Invalid library\n                Log.w(TAG, \"Invalid header magic 0x%x at path %s\", magic, path);\n                return new InvalidLib(path, size, header);\n            }\n            ElfLib elfLib = new ElfLib(path, size);\n            elfLib.mArch = buffer.get(); // EI_CLASS\n            elfLib.mEndianness = buffer.get(); // EI_DATA\n            if (elfLib.mEndianness == ElfLib.ENDIANNESS_LITTLE_ENDIAN) {\n                buffer.order(ByteOrder.LITTLE_ENDIAN);\n            }\n            buffer.position(16);\n            elfLib.mType = buffer.getChar(); // e_type\n            elfLib.mIsa = buffer.getChar(); // e_machine\n            return elfLib;\n        }\n    }\n\n    public static class InvalidLib extends NativeLib {\n        protected InvalidLib(@NonNull String path, long size, byte[] magic) {\n            super(path, size, magic);\n        }\n\n        @NonNull\n        @Override\n        public CharSequence toLocalizedString(@NonNull Context context) {\n            StringBuilder sb = new StringBuilder();\n            if (getSize() != -1) {\n                sb.append(Formatter.formatFileSize(context, getSize())).append(\", \");\n            }\n            sb.append(\"Magic\")\n                    .append(LangUtils.getSeparatorString())\n                    .append(HexEncoding.encodeToString(getMagic()))\n                    .append(\"\\n\")\n                    .append(getPath());\n            return sb;\n        }\n\n        @NonNull\n        @Override\n        public String toString() {\n            return \"InvalidLib{\" +\n                    \"mPath='\" + getPath() + '\\'' +\n                    \", mName='\" + getName() + '\\'' +\n                    '}';\n        }\n    }\n\n    public static class ElfLib extends NativeLib {\n        public static final int ARCH_NONE = 0; // ELFCLASSNONE\n        public static final int ARCH_32BIT = 1; // ELFCLASS32\n        public static final int ARCH_64BIT = 2; // ELFCLASS64\n\n        @IntDef({ARCH_NONE, ARCH_32BIT, ARCH_64BIT})\n        @Retention(RetentionPolicy.SOURCE)\n        public @interface Arch {\n        }\n\n        public static final int ENDIANNESS_NONE = 0; // ELFDATANONE\n        public static final int ENDIANNESS_LITTLE_ENDIAN = 1; // ELFDATA2LSB\n        public static final int ENDIANNESS_BIG_ENDIAN = 2; // ELFDATA2MSB\n\n        @IntDef({ENDIANNESS_NONE, ENDIANNESS_LITTLE_ENDIAN, ENDIANNESS_BIG_ENDIAN})\n        @Retention(RetentionPolicy.SOURCE)\n        public @interface Endianness {\n        }\n\n        public static final int TYPE_NONE = 0;\n        public static final int TYPE_REL = 1;\n        public static final int TYPE_EXEC = 2;\n        public static final int TYPE_DYN = 3;\n        public static final int TYPE_CORE = 4;\n\n        @IntDef({TYPE_NONE, TYPE_REL, TYPE_EXEC, TYPE_DYN, TYPE_CORE})\n        @Retention(RetentionPolicy.SOURCE)\n        public @interface Type {\n        }\n\n        @Arch\n        private int mArch;\n        @Endianness\n        private int mEndianness;\n        @Type\n        private int mType;\n        private int mIsa;\n\n        private ElfLib(@NonNull String path, long size) {\n            super(path, size, new byte[]{0x7f, 0x45, 0x4c, 0x46});\n        }\n\n        @Arch\n        public int getArch() {\n            return mArch;\n        }\n\n        @Endianness\n        public int getEndianness() {\n            return mEndianness;\n        }\n\n        @Type\n        public int getType() {\n            return mType;\n        }\n\n        public int getIsa() {\n            return mIsa;\n        }\n\n        public String getIsaString() {\n            // https://elixir.bootlin.com/linux/latest/source/include/uapi/linux/elf-em.h\n            switch (mIsa) {\n                case 0:\n                    return \"Unknown\";\n                case 3:\n                    return \"x86\";\n                case 8:\n                    return \"MIPS\";\n                case 40:\n                    return \"ARM\";\n                case 62:\n                    return \"x86_64\";\n                case 92:\n                    return \"OpenRISC\";\n                case 183:\n                    return \"AArch64\";\n                case 0xF3:\n                    return \"RISC-V\";\n                default:\n                    // Not available in Android, but just in case\n                    return String.format(\"Unknown(0x%x)\", mIsa);\n            }\n        }\n\n        @NonNull\n        @Override\n        public String toString() {\n            return \"ElfLib{\" +\n                    \"mPath='\" + getPath() + '\\'' +\n                    \", mName='\" + getName() + '\\'' +\n                    \", mArch=\" + mArch +\n                    \", mEndianness=\" + mEndianness +\n                    \", mType=\" + mType +\n                    \", mIsa=\" + getIsaString() +\n                    '}';\n        }\n\n        @NonNull\n        @Override\n        public CharSequence toLocalizedString(@NonNull Context context) {\n            StringBuilder sb = new StringBuilder();\n            if (getSize() != -1) {\n                sb.append(Formatter.formatFileSize(context, getSize())).append(\", \");\n            }\n            switch (mArch) {\n                case ARCH_32BIT:\n                    sb.append(context.getString(R.string.binary_32_bit)).append(\", \");\n                    break;\n                case ARCH_64BIT:\n                    sb.append(context.getString(R.string.binary_64_bit)).append(\", \");\n                    break;\n                case ARCH_NONE:\n                    break;\n            }\n            switch (mEndianness) {\n                case ENDIANNESS_BIG_ENDIAN:\n                    sb.append(context.getString(R.string.endianness_big_endian)).append(\", \");\n                    break;\n                case ENDIANNESS_LITTLE_ENDIAN:\n                    sb.append(context.getString(R.string.endianness_little_endian)).append(\", \");\n                    break;\n                case ENDIANNESS_NONE:\n                    break;\n            }\n            switch (mType) {\n                case TYPE_NONE:\n                case TYPE_CORE:\n                case TYPE_REL:\n                    // Not available in Android\n                    break;\n                case TYPE_DYN:\n                    sb.append(context.getString(R.string.so_type_shared_library)).append(\", \");\n                    break;\n                case TYPE_EXEC:\n                    sb.append(context.getString(R.string.so_type_executable)).append(\", \");\n                    break;\n            }\n            sb.append(getIsaString()).append(\"\\n\").append(getPath());\n            return sb;\n        }\n    }\n\n    private final List<NativeLib> mLibs = new ArrayList<>();\n    private final Set<String> mUniqueLibs = new HashSet<>();\n\n    @WorkerThread\n    public NativeLibraries(@NonNull File apkFile) throws IOException {\n        try (ZipFile zipFile = new ZipFile(apkFile)) {\n            Enumeration<? extends ZipEntry> zipEntries = zipFile.entries();\n            while (zipEntries.hasMoreElements()) {\n                ZipEntry zipEntry = zipEntries.nextElement();\n                if (zipEntry.getName().endsWith(\".so\")) {\n                    try (InputStream is = zipFile.getInputStream(zipEntry)) {\n                        NativeLib nativeLib = NativeLib.parse(zipEntry.getName(), zipEntry.getSize(), is);\n                        mLibs.add(nativeLib);\n                        mUniqueLibs.add(nativeLib.getName());\n                    } catch (IOException e) {\n                        Log.w(TAG, \"Could not load native library %s\", e, zipEntry.getName());\n                    }\n                }\n            }\n        }\n    }\n\n    @WorkerThread\n    public NativeLibraries(@NonNull InputStream apkInputStream) throws IOException {\n        try (ZipInputStream zipInputStream = new ZipInputStream(apkInputStream)) {\n            ZipEntry zipEntry;\n            while ((zipEntry = zipInputStream.getNextEntry()) != null) {\n                if (zipEntry.getName().endsWith(\".so\")) {\n                    try {\n                        NativeLib nativeLib = NativeLib.parse(zipEntry.getName(), zipEntry.getSize(), zipInputStream);\n                        mLibs.add(nativeLib);\n                        mUniqueLibs.add(nativeLib.getName());\n                    } catch (IOException e) {\n                        Log.w(TAG, \"Could not load native library %s\", e, zipEntry.getName());\n                    }\n                }\n            }\n        }\n    }\n\n    @AnyThread\n    public NativeLibraries(@NonNull ZipFile zipFile) throws IOException {\n        Enumeration<? extends ZipEntry> zipEntries = zipFile.entries();\n        while (zipEntries.hasMoreElements()) {\n            ZipEntry zipEntry = zipEntries.nextElement();\n            if (!zipEntry.isDirectory() && zipEntry.getName().endsWith(\".so\")) {\n                try (InputStream is = zipFile.getInputStream(zipEntry)) {\n                    NativeLib nativeLib = NativeLib.parse(zipEntry.getName(), zipEntry.getSize(), is);\n                    mLibs.add(nativeLib);\n                    mUniqueLibs.add(nativeLib.getName());\n                } catch (IOException e) {\n                    Log.w(TAG, \"Could not load native library %s\", e, zipEntry.getName());\n                }\n            }\n        }\n    }\n\n    @NonNull\n    public List<NativeLib> getLibs() {\n        return mLibs;\n    }\n\n    @NonNull\n    public Collection<String> getUniqueLibs() {\n        return mUniqueLibs;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/scanner/Pithus.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.scanner;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.WorkerThread;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.net.HttpURLConnection;\nimport java.net.URL;\n\npublic class Pithus {\n    private static final String BASE_URL = \"https://beta.pithus.org/report\";\n\n    @WorkerThread\n    @Nullable\n    public static String resolveReport(@NonNull String sha256Sum) throws IOException {\n        URL url = new URL(BASE_URL + File.separator + sha256Sum);\n        HttpURLConnection connection = (HttpURLConnection) url.openConnection();\n        connection.setInstanceFollowRedirects(false);\n        connection.setUseCaches(false);\n        connection.setRequestMethod(\"GET\");\n        if (connection.getResponseCode() == HttpURLConnection.HTTP_OK) {\n            return url.toString();\n        }\n        return null;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/scanner/ScannerActivity.java",
    "content": "// SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.scanner;\n\nimport android.content.Intent;\nimport android.net.Uri;\nimport android.os.Bundle;\nimport android.os.ParcelFileDescriptor;\nimport android.view.Menu;\nimport android.view.MenuItem;\nimport android.view.View;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.StringRes;\nimport androidx.appcompat.app.ActionBar;\nimport androidx.fragment.app.Fragment;\nimport androidx.lifecycle.ViewModelProvider;\n\nimport com.google.android.material.progressindicator.LinearProgressIndicator;\n\nimport java.io.File;\nimport java.io.FileNotFoundException;\n\nimport io.github.muntashirakon.AppManager.BaseActivity;\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.apk.installer.PackageInstallerActivity;\nimport io.github.muntashirakon.AppManager.fm.FmProvider;\nimport io.github.muntashirakon.AppManager.intercept.IntentCompat;\nimport io.github.muntashirakon.AppManager.settings.FeatureController;\nimport io.github.muntashirakon.AppManager.utils.FileUtils;\nimport io.github.muntashirakon.AppManager.utils.UIUtils;\nimport io.github.muntashirakon.io.IoUtils;\n\n// Copyright 2015 Google, Inc.\npublic class ScannerActivity extends BaseActivity {\n    public static final String EXTRA_IS_EXTERNAL = \"is_external\";\n\n    @Nullable\n    private ActionBar mActionBar;\n    @Nullable\n    private LinearProgressIndicator mProgressIndicator;\n    @Nullable\n    private ParcelFileDescriptor mFd;\n    @Nullable\n    private Uri mApkUri;\n    private boolean mIsExternalApk;\n\n    @Override\n    protected void onDestroy() {\n        FileUtils.deleteSilently(getCodeCacheDir());\n        IoUtils.closeQuietly(mFd);\n        super.onDestroy();\n    }\n\n    @Override\n    protected void onAuthenticated(Bundle savedInstanceState) {\n        setContentView(R.layout.activity_fm);\n        setSupportActionBar(findViewById(R.id.toolbar));\n        ScannerViewModel model = new ViewModelProvider(this).get(ScannerViewModel.class);\n        mActionBar = getSupportActionBar();\n        Intent intent = getIntent();\n        mIsExternalApk = intent.getBooleanExtra(EXTRA_IS_EXTERNAL, true);\n\n        mProgressIndicator = findViewById(R.id.progress_linear);\n        mProgressIndicator.setVisibilityAfterHide(View.GONE);\n        showProgress(true);\n\n        mApkUri = IntentCompat.getDataUri(intent);\n        if (mApkUri == null) {\n            UIUtils.displayShortToast(R.string.error);\n            finish();\n            return;\n        }\n\n        File apkFile = null;\n        if (Intent.ACTION_VIEW.equals(intent.getAction())) {\n            if (!FmProvider.AUTHORITY.equals(mApkUri.getAuthority())) {\n                try {\n                    mFd = FileUtils.getFdFromUri(this, mApkUri, \"r\");\n                    apkFile = FileUtils.getFileFromFd(mFd);\n                } catch (FileNotFoundException e) {\n                    e.printStackTrace();\n                }\n            }\n        } else {\n            String path = mApkUri.getPath();\n            if (path != null) apkFile = new File(path);\n        }\n\n        model.setApkFile(apkFile);\n        model.setApkUri(mApkUri);\n\n        getSupportFragmentManager()\n                .beginTransaction()\n                .setCustomAnimations(\n                        R.animator.enter_from_left,\n                        R.animator.enter_from_right,\n                        R.animator.exit_from_right,\n                        R.animator.exit_from_left\n                )\n                .replace(R.id.main_layout, new ScannerFragment())\n                .commit();\n    }\n\n    @Override\n    public boolean onCreateOptionsMenu(Menu menu) {\n        getMenuInflater().inflate(R.menu.activity_scanner, menu);\n        return super.onCreateOptionsMenu(menu);\n    }\n\n    @Override\n    public boolean onPrepareOptionsMenu(@NonNull Menu menu) {\n        menu.findItem(R.id.action_install).setVisible(mIsExternalApk && FeatureController.isInstallerEnabled());\n        return super.onPrepareOptionsMenu(menu);\n    }\n\n    @Override\n    public boolean onOptionsItemSelected(@NonNull MenuItem item) {\n        int id = item.getItemId();\n        if (id == android.R.id.home) {\n            getOnBackPressedDispatcher().onBackPressed();\n            return true;\n        } else if (id == R.id.action_install) {\n            if (mApkUri != null) {\n                startActivity(PackageInstallerActivity.getLaunchableInstance(getApplicationContext(), mApkUri));\n                return true;\n            }\n        }\n        return super.onOptionsItemSelected(item);\n    }\n\n    public void setSubtitle(CharSequence subtitle) {\n        if (mActionBar != null) {\n            mActionBar.setSubtitle(subtitle);\n        }\n    }\n\n    public void setSubtitle(@StringRes int subtitle) {\n        if (mActionBar != null) {\n            mActionBar.setSubtitle(subtitle);\n        }\n    }\n\n    void showProgress(boolean willShow) {\n        if (mProgressIndicator == null) {\n            return;\n        }\n        if (willShow) {\n            mProgressIndicator.show();\n        } else {\n            mProgressIndicator.hide();\n        }\n    }\n\n    public void loadNewFragment(Fragment fragment) {\n        getSupportFragmentManager()\n                .beginTransaction()\n                .setCustomAnimations(\n                        R.animator.enter_from_left,\n                        R.animator.enter_from_right,\n                        R.animator.exit_from_right,\n                        R.animator.exit_from_left\n                )\n                .replace(R.id.main_layout, fragment)\n                .addToBackStack(null)\n                .commit();\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/scanner/ScannerFragment.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.scanner;\n\nimport static io.github.muntashirakon.AppManager.utils.UIUtils.getColoredText;\nimport static io.github.muntashirakon.AppManager.utils.UIUtils.getMonospacedText;\nimport static io.github.muntashirakon.AppManager.utils.UIUtils.getPrimaryText;\nimport static io.github.muntashirakon.AppManager.utils.UIUtils.getSmallerText;\n\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.pm.ApplicationInfo;\nimport android.os.Bundle;\nimport android.text.Spannable;\nimport android.text.SpannableStringBuilder;\nimport android.text.Spanned;\nimport android.text.TextUtils;\nimport android.util.Pair;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.TextView;\n\nimport androidx.annotation.ColorInt;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.collection.ArrayMap;\nimport androidx.fragment.app.Fragment;\nimport androidx.lifecycle.ViewModelProvider;\n\nimport com.google.android.material.card.MaterialCardView;\nimport com.google.android.material.dialog.MaterialAlertDialogBuilder;\n\nimport java.io.File;\nimport java.security.cert.CertificateEncodingException;\nimport java.security.cert.X509Certificate;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.Set;\nimport java.util.regex.Pattern;\n\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.scanner.vt.VtFileReport;\nimport io.github.muntashirakon.AppManager.scanner.vt.VtAvEngineResult;\nimport io.github.muntashirakon.AppManager.settings.FeatureController;\nimport io.github.muntashirakon.AppManager.settings.Prefs;\nimport io.github.muntashirakon.AppManager.utils.ArrayUtils;\nimport io.github.muntashirakon.AppManager.utils.DateUtils;\nimport io.github.muntashirakon.AppManager.utils.DigestUtils;\nimport io.github.muntashirakon.AppManager.utils.LangUtils;\nimport io.github.muntashirakon.AppManager.utils.PackageUtils;\nimport io.github.muntashirakon.AppManager.utils.TextUtilsCompat;\nimport io.github.muntashirakon.AppManager.utils.appearance.ColorCodes;\nimport io.github.muntashirakon.dialog.SearchableMultiChoiceDialogBuilder;\nimport io.github.muntashirakon.util.UiUtils;\n\npublic class ScannerFragment extends Fragment {\n    private CharSequence mAppName;\n    private ScannerViewModel mViewModel;\n    private ScannerActivity mActivity;\n\n    private MaterialCardView mVtContainerView;\n    private TextView mVtTitleView;\n    private TextView mVtDescriptionView;\n    private TextView pithusDescriptionView;\n\n    @Nullable\n    @Override\n    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {\n        return inflater.inflate(R.layout.fragment_scanner, container, false);\n    }\n\n    @Override\n    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {\n        mViewModel = new ViewModelProvider(requireActivity()).get(ScannerViewModel.class);\n        mActivity = (ScannerActivity) requireActivity();\n        int cardColor = ColorCodes.getListItemColor1(mActivity);\n        MaterialCardView classesView = view.findViewById(R.id.classes);\n        classesView.setCardBackgroundColor(cardColor);\n        MaterialCardView trackersView = view.findViewById(R.id.tracker);\n        trackersView.setCardBackgroundColor(cardColor);\n        mVtContainerView = view.findViewById(R.id.vt);\n        mVtContainerView.setCardBackgroundColor(cardColor);\n        mVtTitleView = view.findViewById(R.id.vt_title);\n        mVtDescriptionView = view.findViewById(R.id.vt_description);\n        MaterialCardView pithusContainerView = view.findViewById(R.id.pithus);\n        pithusContainerView.setCardBackgroundColor(cardColor);\n        pithusDescriptionView = view.findViewById(R.id.pithus_description);\n        MaterialCardView libsView = view.findViewById(R.id.libs);\n        libsView.setCardBackgroundColor(cardColor);\n        MaterialCardView apkInfoView = view.findViewById(R.id.apk);\n        apkInfoView.setCardBackgroundColor(cardColor);\n        MaterialCardView signaturesView = view.findViewById(R.id.signatures);\n        signaturesView.setCardBackgroundColor(cardColor);\n        MaterialCardView missingLibsView = view.findViewById(R.id.missing_libs);\n        missingLibsView.setCardBackgroundColor(cardColor);\n        // VirusTotal\n        if (!FeatureController.isVirusTotalEnabled() || Prefs.VirusTotal.getApiKey() == null) {\n            mVtContainerView.setVisibility(View.GONE);\n            view.findViewById(R.id.vt_disclaimer).setVisibility(View.GONE);\n        }\n        // Pithus\n        if (!FeatureController.isInternetEnabled()) {\n            pithusContainerView.setVisibility(View.GONE);\n        }\n        // Checksum\n        mViewModel.apkChecksumsLiveData().observe(getViewLifecycleOwner(), checksums -> {\n            if (checksums == null) {\n                return;\n            }\n            List<CharSequence> lines = new ArrayList<>();\n            for (Pair<String, String> digest : checksums) {\n                lines.add(new SpannableStringBuilder()\n                        .append(getPrimaryText(mActivity, digest.first + LangUtils.getSeparatorString()))\n                        .append(getMonospacedText(digest.second)));\n            }\n            ((TextView) view.findViewById(R.id.apk_title)).setText(R.string.apk_checksums);\n            ((TextView) view.findViewById(R.id.apk_description)).setText(TextUtilsCompat.joinSpannable(\"\\n\", lines));\n        });\n        // Package info: Title & subtitle\n        mViewModel.packageInfoLiveData().observe(getViewLifecycleOwner(), packageInfo -> {\n            if (packageInfo != null) {\n                String archiveFilePath = mViewModel.getApkFile().getAbsolutePath();\n                final ApplicationInfo applicationInfo = packageInfo.applicationInfo;\n                applicationInfo.publicSourceDir = archiveFilePath;\n                applicationInfo.sourceDir = archiveFilePath;\n                mAppName = applicationInfo.loadLabel(mActivity.getPackageManager());\n            } else {\n                File apkFile = mViewModel.getApkFile();\n                mAppName = apkFile != null ? apkFile.getName() : mViewModel.getApkUri().getLastPathSegment();\n            }\n            mActivity.setTitle(mAppName);\n            mActivity.setSubtitle(R.string.scanner);\n        });\n        // APK verifier result\n        mViewModel.apkVerifierResultLiveData().observe(getViewLifecycleOwner(), result -> {\n            TextView checksumDescription = view.findViewById(R.id.checksum_description);\n            SpannableStringBuilder builder = new SpannableStringBuilder();\n            builder.append(PackageUtils.getApkVerifierInfo(result, mActivity));\n            List<X509Certificate> certificates = result.getSignerCertificates();\n            if (certificates != null && !certificates.isEmpty()) {\n                builder.append(getCertificateInfo(mActivity, certificates));\n            }\n            checksumDescription.setText(builder);\n        });\n        // List all classes\n        mViewModel.allClassesLiveData().observe(getViewLifecycleOwner(), allClasses -> {\n            ((TextView) view.findViewById(R.id.classes_title)).setText(getResources().getQuantityString(R.plurals.classes,\n                    allClasses.size(), allClasses.size()));\n            classesView.setOnClickListener(v -> mActivity.loadNewFragment(new ClassListingFragment()));\n        });\n        // List tracker classes\n        mViewModel.trackerClassesLiveData().observe(getViewLifecycleOwner(), trackerClasses ->\n                setTrackerInfo(trackerClasses, view));\n        // List library classes\n        mViewModel.libraryClassesLiveData().observe(getViewLifecycleOwner(), libraryClasses -> {\n            setLibraryInfo(libraryClasses, view);\n            // Progress is dismissed here because this will take the largest time\n            mActivity.showProgress(false);\n        });\n        // List missing classes\n        mViewModel.missingClassesLiveData().observe(getViewLifecycleOwner(), missingClasses -> {\n            if (!missingClasses.isEmpty()) {\n                ((TextView) view.findViewById(R.id.missing_libs_title)).setText(getResources().getQuantityString(R.plurals.missing_signatures, missingClasses.size(), missingClasses.size()));\n                missingLibsView.setVisibility(View.VISIBLE);\n                missingLibsView.setOnClickListener(v2 -> new SearchableMultiChoiceDialogBuilder<>(mActivity, missingClasses,\n                        ArrayUtils.toCharSequence(missingClasses))\n                        .setTitle(R.string.signatures)\n                        .showSelectAll(false)\n                        .setNegativeButton(R.string.ok, null)\n                        .setNeutralButton(R.string.send_selected, (dialog, which, selectedItems) -> {\n                            String message = \"Package: \" + mViewModel.getPackageName() + \"\\n\" +\n                                    \"Signatures: \" + selectedItems;\n                            Intent i = new Intent(Intent.ACTION_SEND);\n                            i.setType(\"message/rfc822\");\n                            i.putExtra(Intent.EXTRA_EMAIL, new String[]{\"am4android@riseup.net\"});\n                            i.putExtra(Intent.EXTRA_SUBJECT, \"App Manager: Missing signatures\");\n                            i.putExtra(Intent.EXTRA_TEXT, message);\n                            startActivity(Intent.createChooser(i, getText(R.string.signatures)));\n                        })\n                        .show());\n            }\n        });\n        mViewModel.vtFileUploadLiveData().observe(getViewLifecycleOwner(), permalink -> {\n            if (permalink == null) {\n                // Uploading\n                mVtTitleView.setText(R.string.vt_uploading);\n                if (Prefs.VirusTotal.promptBeforeUpload()) {\n                    new MaterialAlertDialogBuilder(mActivity)\n                            .setTitle(R.string.scan_in_vt)\n                            .setMessage(R.string.vt_confirm_uploading_file)\n                            .setCancelable(false)\n                            .setPositiveButton(R.string.vt_confirm_upload_and_scan, (dialog, which) -> mViewModel.enableUploading())\n                            .setNegativeButton(R.string.no, (dialog, which) -> mViewModel.disableUploading())\n                            .show();\n                } else mViewModel.enableUploading();\n            } else {\n                // Upload completed and queued\n                mVtTitleView.setText(R.string.vt_queued);\n                mVtDescriptionView.setText(permalink);\n            }\n        });\n        mViewModel.vtFileReportLiveData().observe(getViewLifecycleOwner(), vtFileReport -> {\n            if (vtFileReport == null) {\n                // Failed\n                mVtTitleView.setText(R.string.vt_failed);\n                mVtDescriptionView.setText(null);\n                mVtContainerView.setOnClickListener(null);\n            } else {\n                // Successful\n                publishVirusTotalReport(vtFileReport);\n            }\n        });\n        mViewModel.getPithusReportLiveData().observe(getViewLifecycleOwner(), url -> {\n            if (url != null) {\n                // Report available\n                pithusDescriptionView.setText(url);\n            } else {\n                // Report unavailable\n                pithusDescriptionView.setText(R.string.report_not_available);\n            }\n        });\n        // Load summary for the APK file\n        mViewModel.loadSummary();\n    }\n\n    private void publishVirusTotalReport(@NonNull VtFileReport vtFileReport) {\n        int positives = Objects.requireNonNull(vtFileReport.getPositives());\n        CharSequence resultSummary = getString(R.string.vt_success, positives, vtFileReport.getTotal());\n        @ColorInt\n        int color;\n        if (positives <= 3) {\n            color = ColorCodes.getVirusTotalSafeIndicatorColor(mActivity);\n        } else if (positives <= 12) {\n            color = ColorCodes.getVirusTotalUnsafeIndicatorColor(mActivity);\n        } else color = ColorCodes.getVirusTotalExtremelyUnsafeIndicatorColor(mActivity);\n        CharSequence scanDate = getString(R.string.vt_scan_date, DateUtils.formatDateTime(mActivity, vtFileReport.scanDate));\n        String permalink = vtFileReport.permalink;\n        Spanned result;\n        List<VtAvEngineResult> vtFileReportScanItems = vtFileReport.results;\n        if (!vtFileReportScanItems.isEmpty()) {\n            int colorUnsafe = ColorCodes.getVirusTotalExtremelyUnsafeIndicatorColor(mActivity);\n            int colorSafe = ColorCodes.getVirusTotalSafeIndicatorColor(mActivity);\n            ArrayList<Spannable> detectedList = new ArrayList<>();\n            ArrayList<Spannable> suspiciousList = new ArrayList<>();\n            ArrayList<Spannable> undetectedList = new ArrayList<>();\n            ArrayList<Spannable> neutralList = new ArrayList<>();\n            for (VtAvEngineResult item : vtFileReportScanItems) {\n                SpannableStringBuilder sb = new SpannableStringBuilder();\n                Spannable title = getPrimaryText(mActivity, item.engineName);\n                if (item.category < VtAvEngineResult.CAT_UNDETECTED) {\n                    sb.append(title);\n                    neutralList.add(sb);\n                } else if (item.category < VtAvEngineResult.CAT_SUSPICIOUS) {\n                    sb.append(getColoredText(title, colorSafe));\n                    undetectedList.add(sb);\n                } else if (item.category == VtAvEngineResult.CAT_SUSPICIOUS) {\n                    sb.append(getColoredText(title, colorUnsafe));\n                    suspiciousList.add(sb);\n                } else { // malicious\n                    sb.append(getColoredText(title, colorUnsafe));\n                    detectedList.add(sb);\n                }\n                sb.append(getSmallerText(\" (\" + item.engineVersion + \")\"));\n                if (item.result != null) {\n                    sb.append(\"\\n\").append(item.result);\n                }\n            }\n            detectedList.addAll(suspiciousList);\n            detectedList.addAll(undetectedList);\n            detectedList.addAll(neutralList);\n            result = UiUtils.getOrderedList(detectedList);\n        } else result = null;\n        mVtTitleView.setText(getColoredText(resultSummary, color));\n        if (result != null) {\n            mVtDescriptionView.setText(R.string.tap_to_see_details);\n            mVtContainerView.setOnClickListener(v -> {\n                VirusTotalDialog fragment = VirusTotalDialog.getInstance(resultSummary, scanDate, result, permalink);\n                fragment.show(getParentFragmentManager(), VirusTotalDialog.TAG);\n            });\n        }\n    }\n\n    @NonNull\n    private Map<String, SpannableStringBuilder> getNativeLibraryInfo(boolean trackerOnly) {\n        Collection<String> nativeLibsInApk = mViewModel.getNativeLibraries();\n        if (nativeLibsInApk.isEmpty()) return new HashMap<>();\n        String[] libNames = getResources().getStringArray(R.array.lib_native_names);\n        String[] libSignatures = getResources().getStringArray(R.array.lib_native_signatures);\n        int[] isTracker = getResources().getIntArray(R.array.lib_native_is_tracker);\n        // The following array is directly mapped to the arrays above\n        @SuppressWarnings(\"unchecked\")\n        List<String>[] matchedLibs = new List[libSignatures.length];\n        Map<String, SpannableStringBuilder> foundNativeLibInfoMap = new ArrayMap<>();\n        for (int i = 0; i < libSignatures.length; ++i) {\n            if (trackerOnly && isTracker[i] == 0) continue;\n            Pattern pattern = Pattern.compile(libSignatures[i]);\n            for (String lib : nativeLibsInApk) {\n                if (pattern.matcher(lib).find()) {\n                    if (matchedLibs[i] == null) {\n                        matchedLibs[i] = new ArrayList<>();\n                    }\n                    matchedLibs[i].add(lib);\n                }\n            }\n            if (matchedLibs[i] == null) continue;\n            SpannableStringBuilder builder = foundNativeLibInfoMap.get(libNames[i]);\n            if (builder == null) {\n                builder = new SpannableStringBuilder(getPrimaryText(mActivity, libNames[i]));\n                foundNativeLibInfoMap.put(libNames[i], builder);\n            }\n            for (String lib : matchedLibs[i]) {\n                builder.append(\"\\n\").append(getMonospacedText(lib));\n            }\n        }\n        return foundNativeLibInfoMap;\n    }\n\n    private void setTrackerInfo(@NonNull List<SignatureInfo> trackerInfoList, @NonNull View view) {\n        Map<String, SpannableStringBuilder> foundTrackerInfoMap = new ArrayMap<>();\n        foundTrackerInfoMap.putAll(getNativeLibraryInfo(true));\n        boolean hasSecondDegree = false;\n        // Iterate over signatures again but this time list only the found ones.\n        for (SignatureInfo trackerInfo : trackerInfoList) {\n            if (foundTrackerInfoMap.get(trackerInfo.label) == null) {\n                foundTrackerInfoMap.put(trackerInfo.label, new SpannableStringBuilder()\n                        .append(getPrimaryText(mActivity, trackerInfo.label)));\n            }\n            //noinspection ConstantConditions Never null here\n            foundTrackerInfoMap.get(trackerInfo.label)\n                    .append(\"\\n\")\n                    .append(getMonospacedText(trackerInfo.signature))\n                    .append(getSmallerText(\" (\" + trackerInfo.getCount() + \")\"));\n            if (!hasSecondDegree) {\n                hasSecondDegree = trackerInfo.label.startsWith(\"²\");\n            }\n        }\n        Set<String> foundTrackerNames = foundTrackerInfoMap.keySet();\n        List<Spannable> foundTrackerInfo = new ArrayList<>(foundTrackerInfoMap.values());\n        Collections.sort(foundTrackerInfo, (o1, o2) -> o1.toString().compareToIgnoreCase(o2.toString()));\n        SpannableStringBuilder trackerList = new SpannableStringBuilder(UiUtils.getOrderedList(foundTrackerInfo));\n        SpannableStringBuilder foundTrackerList = new SpannableStringBuilder();\n        int totalTrackersFound = foundTrackerInfoMap.size();\n        if (totalTrackersFound > 0) {\n            foundTrackerList.append(getString(R.string.found_trackers)).append(\" \").append(\n                    TextUtilsCompat.joinSpannable(\", \", foundTrackerNames));\n        }\n        int totalTrackerClasses = mViewModel.getTrackerClasses().size();\n        // Get summary\n        CharSequence summary;\n        if (totalTrackersFound == 0) {\n            summary = getString(R.string.no_tracker_found);\n        } else if (totalTrackersFound == 1) {\n            summary = getResources().getQuantityString(R.plurals.tracker_and_classes, totalTrackerClasses, totalTrackerClasses);\n        } else if (totalTrackersFound == 2) {\n            summary = getResources().getQuantityString(R.plurals.two_trackers_and_classes, totalTrackerClasses, totalTrackerClasses);\n        } else {\n            summary = getResources().getQuantityString(R.plurals.other_trackers_and_classes, totalTrackersFound, totalTrackersFound, totalTrackerClasses);\n        }\n        // Add colours\n        CharSequence coloredSummary;\n        if (totalTrackersFound == 0) {\n            coloredSummary = getColoredText(summary, ColorCodes.getScannerNoTrackerIndicatorColor(mActivity));\n        } else {\n            coloredSummary = getColoredText(summary, ColorCodes.getScannerTrackerIndicatorColor(mActivity));\n        }\n\n        TextView trackerInfoTitle = view.findViewById(R.id.tracker_title);\n        TextView trackerInfoDescription = view.findViewById(R.id.tracker_description);\n        trackerInfoTitle.setText(coloredSummary);\n        if (totalTrackersFound == 0) {\n            trackerInfoDescription.setVisibility(View.GONE);\n            return;\n        }\n        trackerInfoDescription.setVisibility(View.VISIBLE);\n        trackerInfoDescription.setText(foundTrackerList);\n        MaterialCardView trackersView = view.findViewById(R.id.tracker);\n        boolean finalHasSecondDegree = hasSecondDegree;\n        trackersView.setOnClickListener(v -> {\n            TrackerInfoDialog fragment = TrackerInfoDialog.getInstance(coloredSummary, trackerList, finalHasSecondDegree);\n            fragment.show(getParentFragmentManager(), TrackerInfoDialog.TAG);\n        });\n    }\n\n    private void setLibraryInfo(@NonNull List<SignatureInfo> libraryInfoList, @NonNull View view) {\n        Map<String, SpannableStringBuilder> foundLibInfoMap = new ArrayMap<>();\n        foundLibInfoMap.putAll(getNativeLibraryInfo(false));\n        // Iterate over signatures again but this time list only the found ones.\n        for (SignatureInfo libraryInfo : libraryInfoList) {\n            if (foundLibInfoMap.get(libraryInfo.label) == null) {\n                // Add the lib info since it isn't added already\n                foundLibInfoMap.put(libraryInfo.label, new SpannableStringBuilder()\n                        .append(getPrimaryText(mActivity, libraryInfo.label))\n                        .append(getSmallerText(\" (\" + libraryInfo.type + \")\")));\n            }\n            //noinspection ConstantConditions Never null here\n            foundLibInfoMap.get(libraryInfo.label)\n                    .append(\"\\n\")\n                    .append(getMonospacedText(libraryInfo.signature))\n                    .append(getSmallerText(\" (\" + libraryInfo.getCount() + \")\"));\n        }\n        Set<String> foundLibNames = foundLibInfoMap.keySet();\n        List<Spannable> foundLibInfoList = new ArrayList<>(foundLibInfoMap.values());\n        int totalLibsFound = foundLibInfoList.size();\n        Collections.sort(foundLibInfoList, (o1, o2) -> o1.toString().compareToIgnoreCase(o2.toString()));\n        Spanned foundLibsInfo = UiUtils.getOrderedList(foundLibInfoList);\n        String summary;\n        if (totalLibsFound == 0) {\n            summary = getString(R.string.no_libs);\n        } else {\n            summary = getResources().getQuantityString(R.plurals.libraries, totalLibsFound, totalLibsFound);\n        }\n\n        ((TextView) view.findViewById(R.id.libs_title)).setText(summary);\n        ((TextView) view.findViewById(R.id.libs_description)).setText(TextUtils.join(\", \", foundLibNames));\n        if (totalLibsFound == 0) return;\n        MaterialCardView libsView = view.findViewById(R.id.libs);\n        libsView.setOnClickListener(v -> {\n            LibraryInfoDialog fragment = LibraryInfoDialog.getInstance(summary, foundLibsInfo);\n            fragment.show(getParentFragmentManager(), LibraryInfoDialog.TAG);\n        });\n\n    }\n\n    @NonNull\n    private static Spannable getCertificateInfo(@NonNull Context context, @NonNull List<X509Certificate> certificates) {\n        SpannableStringBuilder builder = new SpannableStringBuilder();\n        for (X509Certificate cert : certificates) {\n            try {\n                if (builder.length() > 0) builder.append(\"\\n\\n\");\n                builder.append(getPrimaryText(context, context.getString(R.string.issuer) + LangUtils.getSeparatorString()))\n                        .append(cert.getIssuerX500Principal().getName()).append(\"\\n\")\n                        .append(getPrimaryText(context, context.getString(R.string.algorithm) + LangUtils.getSeparatorString()))\n                        .append(cert.getSigAlgName()).append(\"\\n\");\n                // Checksums\n                builder.append(getPrimaryText(context, context.getString(R.string.checksums)));\n                Pair<String, String>[] digests = DigestUtils.getDigests(cert.getEncoded());\n                for (Pair<String, String> digest : digests) {\n                    builder.append(\"\\n\")\n                            .append(getPrimaryText(context, digest.first + LangUtils.getSeparatorString()))\n                            .append(getMonospacedText(digest.second));\n                }\n            } catch (CertificateEncodingException e) {\n                e.printStackTrace();\n            }\n        }\n        return builder;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/scanner/ScannerViewModel.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.scanner;\n\nimport android.app.Application;\nimport android.content.pm.PackageInfo;\nimport android.content.pm.PackageManager;\nimport android.net.Uri;\nimport android.os.Build;\nimport android.util.Pair;\n\nimport androidx.annotation.AnyThread;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.WorkerThread;\nimport androidx.lifecycle.AndroidViewModel;\nimport androidx.lifecycle.LiveData;\nimport androidx.lifecycle.MutableLiveData;\n\nimport com.android.apksig.ApkVerifier;\nimport com.android.apksig.apk.ApkFormatException;\n\nimport java.io.File;\nimport java.io.FileNotFoundException;\nimport java.io.IOException;\nimport java.security.NoSuchAlgorithmException;\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Objects;\nimport java.util.concurrent.ConcurrentLinkedQueue;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicIntegerArray;\nimport java.util.regex.Pattern;\n\nimport io.github.muntashirakon.AppManager.BuildConfig;\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.StaticDataset;\nimport io.github.muntashirakon.AppManager.fm.ContentType2;\nimport io.github.muntashirakon.AppManager.scanner.vt.VirusTotal;\nimport io.github.muntashirakon.AppManager.scanner.vt.VtFileReport;\nimport io.github.muntashirakon.AppManager.self.filecache.FileCache;\nimport io.github.muntashirakon.AppManager.settings.FeatureController;\nimport io.github.muntashirakon.AppManager.utils.DigestUtils;\nimport io.github.muntashirakon.AppManager.utils.ExUtils;\nimport io.github.muntashirakon.AppManager.utils.FileUtils;\nimport io.github.muntashirakon.AppManager.utils.MultithreadedExecutor;\nimport io.github.muntashirakon.algo.AhoCorasick;\nimport io.github.muntashirakon.io.IoUtils;\nimport io.github.muntashirakon.io.Path;\nimport io.github.muntashirakon.io.Paths;\nimport io.github.muntashirakon.io.fs.DexFileSystem;\nimport io.github.muntashirakon.io.fs.VirtualFileSystem;\n\npublic class ScannerViewModel extends AndroidViewModel implements VirusTotal.FullScanResponseInterface {\n    private static final Pattern SIG_TO_IGNORE = Pattern.compile(\"^(android(|x)|com\\\\.android|com\\\\.google\\\\.android|java(|x)|j\\\\$\\\\.(util|time)|\\\\w\\\\d?(\\\\.\\\\w\\\\d?)+)\\\\..*$\");\n\n    private File mApkFile;\n    private boolean mIsSummaryLoaded = false;\n    private Uri mApkUri;\n    private int mDexVfsId;\n    @Nullable\n    private final VirusTotal mVt;\n    @Nullable\n    private String mPackageName;\n\n    private List<String> mAllClasses;\n    private List<String> mTrackerClasses;\n    private Collection<String> mNativeLibraries;\n\n    private CountDownLatch mWaitForFile;\n    private final FileCache mFileCache = new FileCache();\n    private final MultithreadedExecutor mExecutor = MultithreadedExecutor.getNewInstance();\n    private final MutableLiveData<Pair<String, String>[]> mApkChecksumsLiveData = new MutableLiveData<>();\n    private final MutableLiveData<ApkVerifier.Result> mApkVerifierResultLiveData = new MutableLiveData<>();\n    private final MutableLiveData<PackageInfo> mPackageInfoLiveData = new MutableLiveData<>();\n    private final MutableLiveData<List<String>> mAllClassesLiveData = new MutableLiveData<>();\n    private final MutableLiveData<List<SignatureInfo>> mTrackerClassesLiveData = new MutableLiveData<>();\n    private final MutableLiveData<List<SignatureInfo>> mLibraryClassesLiveData = new MutableLiveData<>();\n    private final MutableLiveData<ArrayList<String>> mMissingClassesLiveData = new MutableLiveData<>();\n    // Null = Uploading, NonNull = Queued\n    private final MutableLiveData<String> mVtFileUploadLiveData = new MutableLiveData<>();\n    // Null = Failed, NonNull = Result generated\n    private final MutableLiveData<VtFileReport> mVtFileReportLiveData = new MutableLiveData<>();\n    private final MutableLiveData<String> mPithusReportLiveData = new MutableLiveData<>();\n\n    public ScannerViewModel(@NonNull Application application) {\n        super(application);\n        mVt = VirusTotal.getInstance();\n    }\n\n    @Override\n    protected void onCleared() {\n        super.onCleared();\n        mExecutor.shutdownNow();\n        IoUtils.closeQuietly(mFileCache);\n        try {\n            VirtualFileSystem.unmount(mDexVfsId);\n        } catch (Throwable e) {\n            e.printStackTrace();\n        }\n    }\n\n    @AnyThread\n    public void loadSummary() {\n        if (mIsSummaryLoaded) return;\n        mIsSummaryLoaded = true;\n        mWaitForFile = new CountDownLatch(1);\n        // Cache files\n        mExecutor.submit(() -> {\n            Thread.currentThread().setPriority(Thread.MAX_PRIORITY);\n            try {\n                cacheFileIfRequired();\n            } finally {\n                mWaitForFile.countDown();\n            }\n        });\n        // Generate APK checksums\n        mExecutor.submit(this::generateApkChecksumsAndFetchScanReports);\n        // Verify APK\n        mExecutor.submit(this::loadApkVerifierResult);\n        // Load package info\n        mExecutor.submit(this::loadPackageInfo);\n        // Load all classes\n        mExecutor.submit(() -> {\n            Thread.currentThread().setPriority(Thread.MAX_PRIORITY);\n            loadAllClasses();\n        });\n    }\n\n    @NonNull\n    public LiveData<Pair<String, String>[]> apkChecksumsLiveData() {\n        return mApkChecksumsLiveData;\n    }\n\n    @NonNull\n    public LiveData<ApkVerifier.Result> apkVerifierResultLiveData() {\n        return mApkVerifierResultLiveData;\n    }\n\n    @NonNull\n    public LiveData<PackageInfo> packageInfoLiveData() {\n        return mPackageInfoLiveData;\n    }\n\n    @NonNull\n    public LiveData<List<String>> allClassesLiveData() {\n        return mAllClassesLiveData;\n    }\n\n    public LiveData<List<SignatureInfo>> trackerClassesLiveData() {\n        return mTrackerClassesLiveData;\n    }\n\n    public LiveData<List<SignatureInfo>> libraryClassesLiveData() {\n        return mLibraryClassesLiveData;\n    }\n\n    public LiveData<ArrayList<String>> missingClassesLiveData() {\n        return mMissingClassesLiveData;\n    }\n\n    public LiveData<VtFileReport> vtFileReportLiveData() {\n        return mVtFileReportLiveData;\n    }\n\n    public LiveData<String> vtFileUploadLiveData() {\n        return mVtFileUploadLiveData;\n    }\n\n    public LiveData<String> getPithusReportLiveData() {\n        return mPithusReportLiveData;\n    }\n\n    public List<String> getTrackerClasses() {\n        return mTrackerClasses;\n    }\n\n    public void setTrackerClasses(List<String> trackerClasses) {\n        mTrackerClasses = trackerClasses;\n    }\n\n    @Nullable\n    public File getApkFile() {\n        return mApkFile;\n    }\n\n    @Nullable\n    public String getPackageName() {\n        return mPackageName;\n    }\n\n    public void setApkFile(@Nullable File apkFile) {\n        mApkFile = apkFile;\n    }\n\n    public Uri getApkUri() {\n        return mApkUri;\n    }\n\n    public void setApkUri(@NonNull Uri apkUri) {\n        mApkUri = apkUri;\n    }\n\n    public List<String> getAllClasses() {\n        return mAllClasses;\n    }\n\n    public Collection<String> getNativeLibraries() {\n        return mNativeLibraries;\n    }\n\n    public Uri getUriFromClassName(String className) throws FileNotFoundException {\n        Path fsRoot = VirtualFileSystem.getFsRoot(mDexVfsId);\n        if (fsRoot == null) {\n            throw new FileNotFoundException(\"FS Root not found.\");\n        }\n        return fsRoot.findFile(className.replace('.', '/') + \".smali\").getUri();\n    }\n\n    @WorkerThread\n    private void cacheFileIfRequired() {\n        // Test if this path is readable\n        if (mApkFile == null || !FileUtils.canReadUnprivileged(mApkFile)) {\n            // Not readable, cache the file\n            try {\n                mApkFile = mFileCache.getCachedFile(Paths.get(mApkUri));\n            } catch (IOException e) {\n                e.printStackTrace();\n            }\n        }\n    }\n\n    @WorkerThread\n    private void generateApkChecksumsAndFetchScanReports() {\n        waitForFile();\n        Path file = Paths.getUnprivileged(mApkFile);\n        String pithusReportUrl = null;\n        Pair<String, String>[] digests = ExUtils.exceptionAsNull(() -> DigestUtils.getDigests(file));\n        mApkChecksumsLiveData.postValue(digests);\n        if (digests != null && FeatureController.isInternetEnabled()) {\n            String sha256 = digests[2].second;\n            pithusReportUrl = ExUtils.exceptionAsNull(() -> Pithus.resolveReport(sha256));\n        }\n        mPithusReportLiveData.postValue(pithusReportUrl);\n        if (mVt != null && digests != null && FeatureController.isVirusTotalEnabled()) {\n            String md5 = digests[0].second;\n            try {\n                mVt.fetchFileReportOrScan(file, md5, this);\n            } catch (IOException e) {\n                e.printStackTrace();\n                mVtFileReportLiveData.postValue(null);\n            }\n        } else mVtFileReportLiveData.postValue(null);\n    }\n\n    private void loadApkVerifierResult() {\n        waitForFile();\n        try {\n            ApkVerifier.Builder builder = new ApkVerifier.Builder(mApkFile)\n                    .setMaxCheckedPlatformVersion(Build.VERSION.SDK_INT);\n            ApkVerifier apkVerifier = builder.build();\n            ApkVerifier.Result apkVerifierResult = apkVerifier.verify();\n            mApkVerifierResultLiveData.postValue(apkVerifierResult);\n        } catch (IOException | ApkFormatException | NoSuchAlgorithmException e) {\n            e.printStackTrace();\n        }\n    }\n\n    @WorkerThread\n    private void loadPackageInfo() {\n        waitForFile();\n        PackageManager pm = getApplication().getPackageManager();\n        PackageInfo packageInfo = pm.getPackageArchiveInfo(mApkFile.getAbsolutePath(), 0);\n        if (packageInfo != null) {\n            mPackageName = packageInfo.packageName;\n        }\n        mPackageInfoLiveData.postValue(packageInfo);\n    }\n\n    @WorkerThread\n    private void loadAllClasses() {\n        waitForFile();\n        try {\n            NativeLibraries nativeLibraries = new NativeLibraries(mApkFile);\n            mNativeLibraries = nativeLibraries.getUniqueLibs();\n        } catch (Throwable e) {\n            mNativeLibraries = Collections.emptyList();\n        }\n        try {\n            mDexVfsId = VirtualFileSystem.mount(Uri.fromFile(mApkFile), Paths.getUnprivileged(mApkFile), ContentType2.DEX.getMimeType());\n            DexFileSystem dfs = (DexFileSystem) Objects.requireNonNull(VirtualFileSystem.getFileSystem(mDexVfsId));\n            mAllClasses = dfs.getDexClasses().getBaseClassNames();\n            Collections.sort(mAllClasses);\n        } catch (Throwable e) {\n            e.printStackTrace();\n            mAllClasses = Collections.emptyList();\n        }\n        mAllClassesLiveData.postValue(mAllClasses);\n        // Load tracker and library info\n        loadTrackers();\n        loadLibraries();\n    }\n\n    @WorkerThread\n    private void loadTrackers() {\n        if (mAllClasses == null) return;\n        List<SignatureInfo> trackerInfoList = new ArrayList<>();\n        String[] trackerNames = StaticDataset.getTrackerNames();\n        String[] trackerSignatures = StaticDataset.getTrackerCodeSignatures();\n        AtomicIntegerArray signatureCount = new AtomicIntegerArray(trackerSignatures.length);\n        mTrackerClasses = new ArrayList<>();\n        AhoCorasick aho = StaticDataset.getSearchableTrackerSignatures();\n        {\n            // Iterate over all classes\n            ConcurrentLinkedQueue<String> matchedClasses = new ConcurrentLinkedQueue<>();\n            mAllClasses.parallelStream()\n                    .filter(className -> className.length() > 8 && className.contains(\".\"))\n                    .forEach(className -> {\n                        int[] matches = aho.search(className);\n                        if (matches.length > 0) {\n                            matchedClasses.add(className);\n                            for (int idx : matches) {\n                                signatureCount.incrementAndGet(idx);\n                            }\n                        }\n                    });\n            mTrackerClasses.addAll(matchedClasses);\n        }\n        // Iterate over signatures again but this time list only the found ones.\n        for (int i = 0; i < trackerSignatures.length; i++) {\n            if (signatureCount.get(i) == 0) continue;\n            SignatureInfo signatureInfo = new SignatureInfo(trackerSignatures[i], trackerNames[i]);\n            signatureInfo.setCount(signatureCount.get(i));\n            trackerInfoList.add(signatureInfo);\n        }\n        mTrackerClassesLiveData.postValue(trackerInfoList);\n    }\n\n    public void loadLibraries() {\n        if (mAllClasses == null) return;\n        List<SignatureInfo> libraryInfoList = new ArrayList<>();\n        ArrayList<String> missingLibs = new ArrayList<>();\n        String[] libNames = getApplication().getResources().getStringArray(R.array.lib_names);\n        String[] libSignatures = getApplication().getResources().getStringArray(R.array.lib_signatures);\n        String[] libTypes = getApplication().getResources().getStringArray(R.array.lib_types);\n        // The following array is directly mapped to the arrays above\n        AtomicIntegerArray signatureCount = new AtomicIntegerArray(libSignatures.length);\n        try (AhoCorasick aho = new AhoCorasick(libSignatures)) {\n            // Iterate over all classes\n            ConcurrentLinkedQueue<String> missingClasses = new ConcurrentLinkedQueue<>();\n            mAllClasses.parallelStream()\n                    .filter(className -> className.length() > 8 && className.contains(\".\"))\n                    .forEach(className -> {\n                        int[] matches = aho.search(className);\n                        if (matches.length > 0) {\n                            for (int idx : matches) {\n                                signatureCount.incrementAndGet(idx);\n                            }\n                        } else if ((mPackageName != null\n                                && !className.startsWith(mPackageName))\n                                && !SIG_TO_IGNORE.matcher(className).matches()) {\n                            missingClasses.add(className);\n                        }\n                    });\n            missingLibs.addAll(missingClasses);\n        }\n        // Iterate over signatures again but this time list only the found ones.\n        for (int i = 0; i < libSignatures.length; i++) {\n            if (signatureCount.get(i) == 0) continue;\n            SignatureInfo signatureInfo = new SignatureInfo(libSignatures[i], libNames[i], libTypes[i]);\n            signatureInfo.setCount(signatureCount.get(i));\n            libraryInfoList.add(signatureInfo);\n        }\n        mLibraryClassesLiveData.postValue(libraryInfoList);\n\n        if (BuildConfig.DEBUG) {\n            mMissingClassesLiveData.postValue(missingLibs);\n        }\n    }\n\n    @WorkerThread\n    private void waitForFile() {\n        try {\n            mWaitForFile.await();\n        } catch (InterruptedException e) {\n            e.printStackTrace();\n        }\n    }\n\n    private boolean mUploadingEnabled;\n    private CountDownLatch mUploadingEnabledWatcher;\n\n    public void enableUploading() {\n        mUploadingEnabled = true;\n        if (mUploadingEnabledWatcher != null) {\n            mUploadingEnabledWatcher.countDown();\n        }\n    }\n\n    public void disableUploading() {\n        mUploadingEnabled = false;\n        if (mUploadingEnabledWatcher != null) {\n            mUploadingEnabledWatcher.countDown();\n        }\n    }\n\n    @Override\n    public boolean uploadFile() {\n        mUploadingEnabled = false;\n        mUploadingEnabledWatcher = new CountDownLatch(1);\n        mVtFileUploadLiveData.postValue(null);\n        try {\n            mUploadingEnabledWatcher.await(2, TimeUnit.MINUTES);\n        } catch (InterruptedException ignore) {\n        }\n        return mUploadingEnabled;\n    }\n\n    @Override\n    public void onUploadInitiated() {\n    }\n\n    @Override\n    public void onUploadCompleted(@NonNull String permalink) {\n        mVtFileUploadLiveData.postValue(permalink);\n    }\n\n    @Override\n    public void onReportReceived(@NonNull VtFileReport report) {\n        mVtFileReportLiveData.postValue(report);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/scanner/SignatureInfo.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.scanner;\n\nimport androidx.annotation.NonNull;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class SignatureInfo {\n    public final String signature;\n    public final String label;\n    public final String type;\n    public final List<String> classes;\n\n    private int mCount;\n\n    public SignatureInfo(@NonNull String signature, @NonNull String label) {\n        this.signature = signature;\n        this.label = label;\n        this.type = \"Tracker\"; // Arbitrary type\n        this.classes = new ArrayList<>();\n    }\n\n    public SignatureInfo(@NonNull String signature, @NonNull String label, @NonNull String type) {\n        this.signature = signature;\n        this.label = label;\n        this.type = type;\n        this.classes = new ArrayList<>();\n    }\n\n    public void setCount(int count) {\n        mCount = count;\n    }\n\n    public int getCount() {\n        return mCount;\n    }\n\n    public void addClass(@NonNull String className) {\n        classes.add(className);\n    }\n\n    @NonNull\n    @Override\n    public String toString() {\n        return \"SignatureInfo{\" +\n                \"signature='\" + signature + '\\'' +\n                \", label='\" + label + '\\'' +\n                \", type='\" + type + '\\'' +\n                \", classes=\" + classes +\n                \", mCount=\" + mCount +\n                '}';\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/scanner/TrackerInfoDialog.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.scanner;\n\nimport android.content.Intent;\nimport android.net.Uri;\nimport android.os.Bundle;\nimport android.text.method.LinkMovementMethod;\nimport android.view.View;\nimport android.view.ViewGroup;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.appcompat.widget.LinearLayoutCompat;\nimport androidx.lifecycle.ViewModelProvider;\n\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.dialog.BottomSheetAlertDialogFragment;\nimport io.github.muntashirakon.util.UiUtils;\nimport io.github.muntashirakon.widget.MaterialAlertView;\n\npublic class TrackerInfoDialog extends BottomSheetAlertDialogFragment {\n    public static final String TAG = TrackerInfoDialog.class.getSimpleName();\n\n    private static final String ARG_HAS_SECOND_DEGREE = \"sec_deg\";\n\n    @NonNull\n    public static TrackerInfoDialog getInstance(@NonNull CharSequence subtitle, @NonNull CharSequence message,\n                                                boolean hasSecondDegree) {\n        TrackerInfoDialog dialog = new TrackerInfoDialog();\n        Bundle args = getArgs(null, subtitle, message);\n        args.putBoolean(ARG_HAS_SECOND_DEGREE, hasSecondDegree);\n        dialog.setArguments(args);\n        return dialog;\n    }\n\n    @Override\n    public void onBodyInitialized(@NonNull View bodyView, @Nullable Bundle savedInstanceState) {\n        super.onBodyInitialized(bodyView, savedInstanceState);\n        ScannerViewModel viewModel = new ViewModelProvider(requireActivity()).get(ScannerViewModel.class);\n        String packageName = viewModel.getPackageName();\n        boolean hasSecondDegree = requireArguments().getBoolean(ARG_HAS_SECOND_DEGREE, false);\n\n        setTitle(R.string.tracker_details);\n        if (packageName != null) {\n            setEndIcon(R.drawable.ic_exodusprivacy, R.string.exodus_link, v -> {\n                Uri exodus_link = Uri.parse(String.format(\n                        \"https://reports.exodus-privacy.eu.org/en/reports/%s/latest/\", packageName));\n                Intent intent = new Intent(Intent.ACTION_VIEW, exodus_link);\n                if (intent.resolveActivity(requireContext().getPackageManager()) != null) {\n                    startActivity(intent);\n                }\n            });\n        }\n        setMessageIsSelectable(true);\n        setMessageMovementMethod(LinkMovementMethod.getInstance());\n        if (hasSecondDegree) {\n            MaterialAlertView alertView = new MaterialAlertView(bodyView.getContext());\n            alertView.setAlertType(MaterialAlertView.ALERT_TYPE_INFO);\n            alertView.setText(R.string.second_degree_tracker_note);\n            alertView.setMovementMethod(LinkMovementMethod.getInstance());\n            LinearLayoutCompat.LayoutParams layoutParams = new LinearLayoutCompat.LayoutParams(\n                    ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);\n            layoutParams.bottomMargin = layoutParams.topMargin = UiUtils.dpToPx(bodyView.getContext(), 8);\n            layoutParams.leftMargin = layoutParams.rightMargin = UiUtils.dpToPx(bodyView.getContext(), 16);\n            prependView(alertView, layoutParams);\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/scanner/VirusTotalDialog.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.scanner;\n\nimport android.content.Intent;\nimport android.net.Uri;\nimport android.os.Bundle;\nimport android.view.View;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.dialog.BottomSheetAlertDialogFragment;\n\npublic class VirusTotalDialog extends BottomSheetAlertDialogFragment {\n    public static final String TAG = VirusTotalDialog.class.getSimpleName();\n\n    private static final String ARG_PERMALINK = \"permalink\";\n\n    @NonNull\n    public static VirusTotalDialog getInstance(@NonNull CharSequence title, @NonNull CharSequence subtitle,\n                                               @NonNull CharSequence message, @Nullable String permalink) {\n        VirusTotalDialog dialog = new VirusTotalDialog();\n        Bundle args = getArgs(title, subtitle, message);\n        args.putString(ARG_PERMALINK, permalink);\n        dialog.setArguments(args);\n        return dialog;\n    }\n\n    @Override\n    public void onBodyInitialized(@NonNull View bodyView, @Nullable Bundle savedInstanceState) {\n        super.onBodyInitialized(bodyView, savedInstanceState);\n        String permalink = requireArguments().getString(ARG_PERMALINK);\n        if (permalink != null) {\n            setEndIcon(R.drawable.ic_vt, R.string.vt_permalink, v -> {\n                Uri vtPermalink = Uri.parse(permalink);\n                Intent linkIntent = new Intent(Intent.ACTION_VIEW, vtPermalink);\n                if (linkIntent.resolveActivity(requireContext().getPackageManager()) != null) {\n                    startActivity(linkIntent);\n                }\n            });\n        }\n        setMessageIsSelectable(true);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/scanner/vt/VirusTotal.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\npackage io.github.muntashirakon.AppManager.scanner.vt;\n\nimport android.os.PowerManager;\nimport android.os.SystemClock;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.WorkerThread;\n\nimport org.json.JSONException;\nimport org.json.JSONObject;\n\nimport java.io.BufferedReader;\nimport java.io.FileNotFoundException;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.InputStreamReader;\nimport java.io.OutputStream;\nimport java.net.HttpURLConnection;\nimport java.net.URL;\nimport java.nio.charset.StandardCharsets;\nimport java.util.Objects;\n\nimport io.github.muntashirakon.AppManager.settings.FeatureController;\nimport io.github.muntashirakon.AppManager.settings.Prefs;\nimport io.github.muntashirakon.AppManager.utils.CpuUtils;\nimport io.github.muntashirakon.AppManager.utils.ExUtils;\nimport io.github.muntashirakon.io.IoUtils;\nimport io.github.muntashirakon.io.Path;\n\npublic class VirusTotal {\n    public interface FullScanResponseInterface {\n        boolean uploadFile();\n\n        void onUploadInitiated();\n\n        void onUploadCompleted(@NonNull String permalink);\n\n        void onReportReceived(@NonNull VtFileReport report);\n    }\n\n    public static class ResponseV3<T> {\n        @Nullable\n        public final T response;\n        @Nullable\n        public final VtError error;\n        public final int httpCode;\n\n        public ResponseV3(@Nullable T response, @Nullable VtError error) {\n            // The params are mutually exclusive\n            assert (response != null && error == null) || (response == null && error != null);\n            this.response = response;\n            this.error = error;\n            if (error != null) {\n                httpCode = error.httpErrorCode;\n            } else httpCode = HttpURLConnection.HTTP_OK;\n        }\n\n        public boolean shouldRetry() {\n            // It should only retry when the quota is exceeded, or the resource is not found, or\n            // the resource is not yet available\n            if (error == null || error.code == null) {\n                return false;\n            }\n            return (error.code.equals(\"NotAvailableYet\")\n                    || error.code.equals(\"NotFoundError\")\n                    || error.code.equals(\"QuotaExceededError\"));\n        }\n\n        @NonNull\n        @Override\n        public String toString() {\n            return \"ResponseV3{\" +\n                    \"response=\" + response +\n                    \", error=\" + error +\n                    \", httpCode=\" + httpCode +\n                    '}';\n        }\n    }\n\n    protected static final String FORM_DATA_BOUNDARY = \"--AppManagerDataBoundary9f3d77ed3a\";\n    protected static final String API_V3_PREFIX = \"https://www.virustotal.com/api/v3\";\n    protected static final String URL_FILE_UPLOAD = API_V3_PREFIX + \"/files\";\n    protected static final String URL_LARGE_FILE_UPLOAD = API_V3_PREFIX + \"/files/upload_url\";\n    protected static final String URL_FILE_REPORT = API_V3_PREFIX + \"/files/\";\n\n    @Nullable\n    public static VirusTotal getInstance() {\n        String apiKey = Prefs.VirusTotal.getApiKey();\n        if (FeatureController.isVirusTotalEnabled() && apiKey != null) {\n            return new VirusTotal(apiKey);\n        }\n        return null;\n    }\n\n    private final String mApiKey;\n\n    public VirusTotal(@NonNull String apiKey) {\n        mApiKey = Objects.requireNonNull(apiKey);\n    }\n\n    public void fetchFileReportOrScan(@NonNull Path file,\n                                      @NonNull String checksum,\n                                      @NonNull FullScanResponseInterface response)\n            throws IOException {\n        ResponseV3<VtFileReport> responseReport = fetchFileReport(checksum);\n        if (responseReport.response != null && responseReport.response.hasReport()) {\n            // A report is found\n            response.onReportReceived(responseReport.response);\n            return;\n        }\n        // No report found: either failed or still queued\n        boolean queued = responseReport.response != null && !responseReport.response.hasReport();\n        if (!queued && !responseReport.shouldRetry()) {\n            // Retry is not available\n            throw new FileNotFoundException(\"Fetch error: \" + responseReport.error);\n        }\n        // Scan or retry\n        VtError error = Objects.requireNonNull(responseReport.error);\n        boolean waitFirst = false;\n        if (\"NotFoundError\".equals(error.code)) {\n            // Initiate scan\n            if (!response.uploadFile()) {\n                // Scanning disabled\n                throw new FileNotFoundException(\"File not found in VirusTotal.\");\n            }\n            waitFirst = true;\n            PowerManager.WakeLock wakeLock = CpuUtils.getPartialWakeLock(\"vt_upload\");\n            wakeLock.acquire();\n            try {\n                long fileSize = file.length();\n                if (fileSize > 650_000_000) {\n                    throw new IOException(\"APK is larger than 650 MB.\");\n                }\n                boolean largeFile = fileSize > 32_000_000L;\n                response.onUploadInitiated();\n                String filename = file.getName();\n                ResponseV3<String> uploadResponse;\n                try (InputStream is = file.openInputStream()) {\n                    uploadResponse = largeFile\n                            ? uploadLargeFile(filename, is)\n                            : uploadFile(filename, is);\n                }\n                if (uploadResponse.response != null) {\n                    response.onUploadCompleted(getPermalink(checksum));\n                }\n            } finally {\n                CpuUtils.releaseWakeLock(wakeLock);\n            }\n        }\n        int waitDuration = 60_000;\n        while (queued || responseReport.shouldRetry()) {\n            if (waitFirst) {\n                // Effectively makes it a do-while loop\n                waitFirst = false;\n            } else {\n                responseReport = fetchFileReport(checksum);\n                queued = responseReport.response != null && !responseReport.response.hasReport();\n            }\n            // Wait for result: First wait for 1 minute, then for 30 seconds\n            // We won't do it less than 30 seconds since the API has a limit of 4 request/minute\n            SystemClock.sleep(waitDuration);\n            // TODO: 23/5/22 Wait duration should be according to the fileSize\n            waitDuration = 30_000;\n        }\n        if (responseReport.response != null) {\n            response.onReportReceived(responseReport.response);\n        } else {\n            throw new IOException(\"Scan error: \" + responseReport.error);\n        }\n    }\n\n    @WorkerThread\n    @NonNull\n    public ResponseV3<String> uploadFile(@NonNull String filename, @NonNull InputStream is)\n            throws IOException {\n        return uploadFile(filename, is, null);\n    }\n\n    @WorkerThread\n    @NonNull\n    public ResponseV3<String> uploadFile(@NonNull String filename, @NonNull InputStream is,\n                                         @Nullable String password) throws IOException {\n        URL url = new URL(URL_FILE_UPLOAD);\n        return uploadAnyFile(url, filename, is, password);\n    }\n\n    @WorkerThread\n    @NonNull\n    public ResponseV3<String> uploadLargeFile(@NonNull String filename, @NonNull InputStream is)\n            throws IOException {\n        return uploadLargeFile(filename, is, null);\n    }\n\n    @WorkerThread\n    @NonNull\n    public ResponseV3<String> uploadLargeFile(@NonNull String filename, @NonNull InputStream is,\n                                              @Nullable String password) throws IOException {\n        // First retrieve the upload URL\n        URL url = new URL(URL_LARGE_FILE_UPLOAD);\n        HttpURLConnection connection = (HttpURLConnection) url.openConnection();\n        try {\n            connection.setUseCaches(false);\n            connection.setRequestMethod(\"POST\");\n            connection.setDoInput(true);\n            // Set headers\n            connection.setRequestProperty(\"accept\", \"application/json\");\n            connection.setRequestProperty(\"x-apikey\", mApiKey);\n            // Response\n            int status = connection.getResponseCode();\n            if (status < 300) {\n                // Success\n                // Upload the actual file\n                URL uploadUrl = getLargeFileUploadUrl(connection);\n                return uploadAnyFile(uploadUrl, filename, is, password);\n            } else {\n                // Failed\n                return new ResponseV3<>(null, getErrorResponse(connection));\n            }\n        } finally {\n            connection.disconnect();\n        }\n    }\n\n    @WorkerThread\n    @NonNull\n    public ResponseV3<String> uploadAnyFile(@NonNull URL uploadUrl, @NonNull String filename,\n                                            @NonNull InputStream is, @Nullable String password)\n            throws IOException {\n        HttpURLConnection connection = (HttpURLConnection) uploadUrl.openConnection();\n        try {\n            connection.setUseCaches(false);\n            connection.setDoOutput(true);\n            connection.setRequestMethod(\"POST\");\n            connection.setDoInput(true);\n            // Set headers\n            connection.setRequestProperty(\"accept\", \"application/json\");\n            connection.setRequestProperty(\"x-apikey\", mApiKey);\n            connection.setRequestProperty(\"content-type\", \"multipart/form-data; boundary=\" + FORM_DATA_BOUNDARY);\n            // Set form data\n            OutputStream outputStream = connection.getOutputStream();\n            if (password != null) {\n                addMultipartFormData(outputStream, \"password\", password);\n            }\n            addMultipartFormData(outputStream, \"file\", filename, is);\n            outputStream.write(\"\\r\\n\".getBytes(StandardCharsets.UTF_8));\n            outputStream.write((\"--\" + FORM_DATA_BOUNDARY + \"--\\r\\n\").getBytes(StandardCharsets.UTF_8));\n            outputStream.flush();\n            // Response\n            int status = connection.getResponseCode();\n            if (status < 300) {\n                // Success\n                // Example response: {\n                //  \"data\": {\n                //    \"type\": \"analysis\",\n                //    \"id\": \"base64_hash\",\n                //    \"links\": {\n                //      \"self\": \"https://www.virustotal.com/api/v3/analyses/base64_hash\"\n                //    }\n                //  }\n                //}\n                return new ResponseV3<>(getAnalysisId(connection), null);\n            } else {\n                // Failed\n                return new ResponseV3<>(null, getErrorResponse(connection));\n            }\n        } finally {\n            connection.disconnect();\n        }\n    }\n\n    @WorkerThread\n    @NonNull\n    public ResponseV3<VtFileReport> fetchFileReport(@NonNull String id) throws IOException {\n        URL url = new URL(URL_FILE_REPORT + id);\n        HttpURLConnection connection = (HttpURLConnection) url.openConnection();\n        try {\n            connection.setUseCaches(false);\n            connection.setRequestMethod(\"GET\");\n            connection.setDoInput(true);\n            // Set headers\n            connection.setRequestProperty(\"accept\", \"application/json\");\n            connection.setRequestProperty(\"x-apikey\", mApiKey);\n            // Response\n            int status = connection.getResponseCode();\n            if (status < 300) {\n                // Success\n                try {\n                    JSONObject jsonObject = new JSONObject(getResponseV3(connection));\n                    return new ResponseV3<>(new VtFileReport(jsonObject), null);\n                } catch (JSONException e) {\n                    throw new IOException(e);\n                }\n            } else {\n                // Failed\n                return new ResponseV3<>(null, getErrorResponse(connection));\n            }\n        } finally {\n            connection.disconnect();\n        }\n    }\n\n    @NonNull\n    public static String getPermalink(@NonNull String id) {\n        return \"https://www.virustotal.com/gui/file/\" + id;\n    }\n\n    @NonNull\n    public static String getAnalysisId(@NonNull HttpURLConnection connection) throws IOException {\n        // https://docs.virustotal.com/reference/files-scan\n        try {\n            JSONObject dataObject = new JSONObject(getResponseV3(connection))\n                    .getJSONObject(\"data\");\n            assert dataObject.getString(\"type\").equals(\"analysis\");\n            return dataObject.getString(\"id\");\n        } catch (JSONException e) {\n            throw new IOException(e);\n        }\n    }\n\n    @NonNull\n    public static URL getLargeFileUploadUrl(@NonNull HttpURLConnection connection) throws IOException {\n        // https://docs.virustotal.com/reference/files-upload-url\n        try {\n            return new URL(new JSONObject(getResponseV3(connection)).getString(\"data\"));\n        } catch (JSONException e) {\n            throw new IOException(e);\n        }\n    }\n\n    public static void addMultipartFormData(@NonNull OutputStream os, @NonNull String key, String value) throws IOException {\n        os.write((\"--\" + FORM_DATA_BOUNDARY + \"\\r\\n\").getBytes(StandardCharsets.UTF_8));\n        os.write((\"Content-Disposition: form-data; name=\\\"\" + key + \"\\\"\\r\\n\").getBytes(StandardCharsets.UTF_8));\n        os.write((\"Content-Type: text/plain; charset=UTF-8\\r\\n\").getBytes(StandardCharsets.UTF_8));\n        os.write((\"\\r\\n\" + value + \"\\r\\n\").getBytes(StandardCharsets.UTF_8));\n    }\n\n    public static void addMultipartFormData(@NonNull OutputStream os, @NonNull String key, @NonNull String filename,\n                                            @NonNull InputStream is) throws IOException {\n        os.write((\"--\" + FORM_DATA_BOUNDARY + \"\\r\\n\").getBytes(StandardCharsets.UTF_8));\n        os.write((\"Content-Disposition: form-data; name=\\\"\" + key + \"\\\"; filename=\\\"\" + filename + \"\\\"\\r\\n\")\n                .getBytes(StandardCharsets.UTF_8));\n        os.write((\"Content-Type: application/octet-stream\\r\\n\").getBytes(StandardCharsets.UTF_8));\n        os.write((\"Content-Transfer-Encoding: chunked\\r\\n\\r\\n\").getBytes(StandardCharsets.UTF_8));\n        IoUtils.copy(is, os);\n    }\n\n    @WorkerThread\n    @NonNull\n    public static String getResponseV3(@NonNull HttpURLConnection connection) throws IOException {\n        StringBuilder response = new StringBuilder();\n        try (BufferedReader reader = new BufferedReader(new InputStreamReader(\n                connection.getInputStream(), StandardCharsets.UTF_8))) {\n            String line;\n            while ((line = reader.readLine()) != null) {\n                response.append(line);\n            }\n        }\n        return response.toString();\n    }\n\n    @WorkerThread\n    @NonNull\n    public static VtError getErrorResponse(@NonNull HttpURLConnection connection) throws IOException {\n        int status = connection.getResponseCode();\n        // First try input stream\n        String inResponse = ExUtils.exceptionAsNull(() -> getResponseV3(connection));\n        if (inResponse != null) {\n            return new VtError(status, inResponse);\n        }\n        // Try error stream\n        StringBuilder response;\n        InputStream errorStream = connection.getErrorStream();\n        if (errorStream == null) {\n            response = null;\n        } else {\n            response = new StringBuilder();\n            try {\n                try (BufferedReader reader = new BufferedReader(new InputStreamReader(\n                        errorStream, StandardCharsets.UTF_8))) {\n                    String line;\n                    while ((line = reader.readLine()) != null) {\n                        response.append(line);\n                    }\n                }\n            } catch (IOException e) {\n                e.printStackTrace();\n            }\n        }\n        return new VtError(status, response != null ? response.toString() : null);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/scanner/vt/VtAvEngineResult.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\npackage io.github.muntashirakon.AppManager.scanner.vt;\n\nimport androidx.annotation.IntDef;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport org.json.JSONException;\nimport org.json.JSONObject;\n\nimport io.github.muntashirakon.AppManager.utils.JSONUtils;\n\npublic class VtAvEngineResult {\n    public static final int CAT_UNSUPPORTED = 0;\n    public static final int CAT_TIMEOUT = 1;\n    public static final int CAT_FAILURE = 2;\n    public static final int CAT_UNDETECTED = 3;\n    public static final int CAT_HARMLESS = 4;\n    public static final int CAT_SUSPICIOUS = 5;\n    public static final int CAT_MALICIOUS = 6;\n\n    @IntDef({CAT_UNSUPPORTED, CAT_TIMEOUT, CAT_FAILURE, CAT_UNDETECTED, CAT_HARMLESS,\n            CAT_SUSPICIOUS, CAT_MALICIOUS})\n    public @interface Category {\n    }\n\n    @NonNull\n    private final String internalCategory;\n    @Category\n    public final int category;\n    @NonNull\n    public final String engineName;\n    @Nullable\n    public final String engineUpdate;\n    @Nullable\n    public final String engineVersion;\n    @NonNull\n    public final String method;\n    @Nullable\n    public final String result;\n\n    public VtAvEngineResult(@NonNull JSONObject avResult) throws JSONException {\n        internalCategory = avResult.getString(\"category\");\n        category = getCategory(internalCategory);\n        engineName = avResult.getString(\"engine_name\");\n        engineUpdate = JSONUtils.optString(avResult, \"engine_update\", null);\n        engineVersion = JSONUtils.optString(avResult, \"engine_version\", null);\n        method = avResult.getString(\"method\");\n        result = JSONUtils.optString(avResult, \"result\", null);\n    }\n\n    @NonNull\n    @Override\n    public String toString() {\n        return \"VtFileReportScanItem{\" +\n                \"category='\" + internalCategory + '\\'' +\n                \", engineName='\" + engineName + '\\'' +\n                \", engineUpdate='\" + engineUpdate + '\\'' +\n                \", engineVersion='\" + engineVersion + '\\'' +\n                \", method='\" + method + '\\'' +\n                \", result='\" + result + '\\'' +\n                '}';\n    }\n\n    @Category\n    private static int getCategory(@NonNull String internalCategory) {\n        switch (internalCategory) {\n            case \"confirmed-timeout\":\n            case \"timeout\":\n                return CAT_TIMEOUT;\n            case \"harmless\":\n                return CAT_HARMLESS;\n            case \"undetected\":\n                return CAT_UNDETECTED;\n            case \"suspicious\":\n                return CAT_SUSPICIOUS;\n            case \"malicious\":\n                return CAT_MALICIOUS;\n            case \"type-unsupported\":\n                return CAT_UNSUPPORTED;\n            case \"failure\":\n            default:\n                return CAT_FAILURE;\n        }\n    }\n}"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/scanner/vt/VtAvEngineStats.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.scanner.vt;\n\nimport androidx.annotation.NonNull;\n\nimport org.json.JSONException;\nimport org.json.JSONObject;\n\npublic class VtAvEngineStats {\n    public final int confirmedTimeout;\n    public final int failure;\n    public final int harmless;\n    public final int malicious;\n    public final int suspicious;\n    public final int timeout;\n    public final int unsupported;\n    public final int undetected;\n\n    private final int mTotal;\n    private final int mDetected;\n\n    public VtAvEngineStats(@NonNull JSONObject stats) throws JSONException {\n        confirmedTimeout = stats.getInt(\"confirmed-timeout\");\n        failure = stats.getInt(\"failure\");\n        harmless = stats.getInt(\"harmless\");\n        malicious = stats.getInt(\"malicious\");\n        suspicious = stats.getInt(\"suspicious\");\n        timeout = stats.getInt(\"timeout\");\n        unsupported = stats.getInt(\"type-unsupported\");\n        undetected = stats.getInt(\"undetected\");\n\n        mTotal = harmless + malicious + suspicious + undetected;\n        mDetected = malicious;\n    }\n\n    public int getTotal() {\n        return mTotal;\n    }\n\n    public int getDetected() {\n        return mDetected;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/scanner/vt/VtError.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.scanner.vt;\n\nimport android.text.TextUtils;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport org.json.JSONException;\nimport org.json.JSONObject;\n\npublic class VtError {\n    public final int httpErrorCode;\n    public final String code;\n    public final String message;\n\n    public VtError(int httpErrorCode, @Nullable String rawJson) {\n        this.httpErrorCode = httpErrorCode;\n        if (TextUtils.isEmpty(rawJson)) {\n            code = null;\n            message = null;\n        } else {\n            String code = null;\n            String message = null;\n            try {\n                JSONObject errorObject = new JSONObject(rawJson).optJSONObject(\"error\");\n                if (errorObject != null) {\n                    code = errorObject.getString(\"code\");\n                    message = errorObject.getString(\"message\");\n                }\n            } catch (JSONException e) {\n                e.printStackTrace();\n            }\n            this.code = code;\n            this.message = message;\n        }\n    }\n\n    @NonNull\n    @Override\n    public String toString() {\n        return \"VtError{\" +\n                \"httpErrorCode=\" + httpErrorCode +\n                \", code='\" + code + '\\'' +\n                \", message='\" + message + '\\'' +\n                '}';\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/scanner/vt/VtFileReport.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\npackage io.github.muntashirakon.AppManager.scanner.vt;\n\nimport androidx.annotation.NonNull;\n\nimport java.util.ArrayList;\nimport java.util.Iterator;\n\nimport org.json.JSONException;\nimport org.json.JSONObject;\n\npublic class VtFileReport {\n    @NonNull\n    public final ArrayList<VtAvEngineResult> results;\n    @NonNull\n    public final VtAvEngineStats stats;\n    @NonNull\n    public final String scanId;\n    public final long scanDate;\n    @NonNull\n    public final String permalink;\n\n    public VtFileReport(@NonNull JSONObject jsonObject) throws JSONException {\n        // Doc: https://docs.virustotal.com/reference/files\n        // Currently, we are only interested in data.attributes.last_analysis_date,\n        // data.attributes.last_analysis_stats, data.attributes.last_analysis_results.\n        JSONObject data = jsonObject.getJSONObject(\"data\");\n        assert data.getString(\"type\").equals(\"file\");\n        scanId = data.getString(\"id\");\n        permalink = VirusTotal.getPermalink(scanId);\n        JSONObject attrs = data.getJSONObject(\"attributes\");\n        scanDate = attrs.optLong(\"last_analysis_date\") * 1_000;\n        stats = new VtAvEngineStats(attrs.getJSONObject(\"last_analysis_stats\"));\n        JSONObject jsonResults = attrs.getJSONObject(\"last_analysis_results\");\n        Iterator<String> avEnginesIt = jsonResults.keys();\n        results = new ArrayList<>();\n        while (avEnginesIt.hasNext()) {\n            results.add(new VtAvEngineResult(jsonResults.getJSONObject(avEnginesIt.next())));\n        }\n    }\n\n    public boolean hasReport() {\n        return scanDate != 0;\n    }\n\n    public int getTotal() {\n        return stats.getTotal();\n    }\n\n    public Integer getPositives() {\n        return stats.getDetected();\n    }\n\n    @NonNull\n    @Override\n    public String toString() {\n        return \"VtFileReport{\" +\n                \"results=\" + results +\n                \", stats=\" + stats +\n                \", scanId='\" + scanId + '\\'' +\n                \", scanDate=\" + scanDate +\n                \", permalink='\" + permalink + '\\'' +\n                '}';\n    }\n}"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/self/BootReceiver.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.self;\n\nimport android.content.BroadcastReceiver;\nimport android.content.Context;\nimport android.content.Intent;\n\nimport androidx.core.content.ContextCompat;\n\nimport io.github.muntashirakon.AppManager.self.filecache.InternalCacheCleanerService;\nimport io.github.muntashirakon.AppManager.servermanager.WifiWaitService;\nimport io.github.muntashirakon.AppManager.settings.Ops;\n\npublic class BootReceiver extends BroadcastReceiver {\n    @Override\n    public void onReceive(Context context, Intent intent) {\n        if (Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) {\n            if (Ops.getMode().equals(Ops.MODE_ADB_WIFI)) {\n                // Connect ADB\n                Intent serviceIntent = new Intent(context, WifiWaitService.class);\n                ContextCompat.startForegroundService(context, serviceIntent);\n            }\n            // Schedule cache cleaning\n            InternalCacheCleanerService.scheduleAlarm(context.getApplicationContext());\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/self/Migration.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.self;\n\nimport androidx.annotation.NonNull;\n\nimport java.util.ArrayList;\nimport java.util.Comparator;\nimport java.util.List;\nimport java.util.stream.Collectors;\n\nimport io.github.muntashirakon.AppManager.utils.ThreadUtils;\n\nclass Migration {\n    private final List<MigrationTask> mMigrationTasks = new ArrayList<>();\n\n    public void addTask(@NonNull MigrationTask migrationTask) {\n        mMigrationTasks.add(migrationTask);\n    }\n\n    public void migrate(long fromVersion) {\n        if (fromVersion == 0) {\n            // This is a new version, no migration needed\n            return;\n        }\n        List<MigrationTask> migrationTasks = mMigrationTasks.stream()\n                // Any tasks with toVersion > fromVersion hasn't been run yet\n                .filter(task -> task.toVersion > fromVersion)\n                // Migration performed in ascending order\n                .sorted(Comparator.comparingLong((MigrationTask task) -> task.fromVersion)\n                        .thenComparingLong(task -> task.toVersion))\n                .collect(Collectors.toList());\n        for (MigrationTask migrationTask : migrationTasks) {\n            if (migrationTask.mainThread) {\n                ThreadUtils.postOnMainThread(migrationTask);\n            } else migrationTask.run();\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/self/MigrationTask.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.self;\n\nimport android.content.Context;\n\nimport io.github.muntashirakon.AppManager.utils.ContextUtils;\n\nabstract class MigrationTask implements Runnable {\n    public final long fromVersion;\n    public final long toVersion;\n    public final boolean mainThread;\n    public final Context context;\n\n    public MigrationTask(long fromVersion, int toVersion) {\n        this(fromVersion, toVersion, false);\n    }\n\n    public MigrationTask(long fromVersion, long toVersion, boolean mainThread) {\n        this.fromVersion = fromVersion;\n        this.toVersion = toVersion;\n        this.mainThread = mainThread;\n        this.context = ContextUtils.getContext();\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/self/Migrations.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.self;\n\nimport android.annotation.SuppressLint;\n\nimport androidx.annotation.WorkerThread;\n\nimport java.io.File;\n\nimport io.github.muntashirakon.AppManager.db.AppsDb;\nimport io.github.muntashirakon.AppManager.logs.Log;\nimport io.github.muntashirakon.AppManager.servermanager.ServerConfig;\nimport io.github.muntashirakon.AppManager.settings.FeatureController;\nimport io.github.muntashirakon.AppManager.utils.ContextUtils;\nimport io.github.muntashirakon.AppManager.utils.FileUtils;\nimport io.github.muntashirakon.io.Paths;\n\n@SuppressLint(\"StaticFieldLeak\")\npublic class Migrations {\n    public static final String TAG = Migrations.class.getSimpleName();\n\n    private static final MigrationTask MIGRATE_FROM_ALL_VERSION_TO_3_0_0 = new MigrationTask(409, 410) {\n        @Override\n        public void run() {\n            Log.d(TAG, \"Running MIGRATE_FROM_ALL_VERSION_TO_3_0_0 from %d to %d\", fromVersion, toVersion);\n            // Delete am database, am.jar\n            File internalFilesDir = ContextUtils.getDeContext(context).getFilesDir().getParentFile();\n            File[] paths = new File[]{\n                    ServerConfig.getDestJarFile(),\n                    new File(internalFilesDir, \"main.jar\"),\n                    new File(internalFilesDir, \"run_server.sh\"),\n                    context.getDatabasePath(\"am\"),\n                    context.getDatabasePath(\"am-shm\"),\n                    context.getDatabasePath(\"am-wal\"),\n            };\n            for (File path : paths) {\n                FileUtils.deleteSilently(path);\n            }\n            // Delete old cache dir (removed in v2.6.4 (394))\n            File oldCacheDir = context.getExternalFilesDir(\"cache\");\n            Paths.get(oldCacheDir).delete();\n            // Disable Internet feature by default\n            FeatureController.getInstance().modifyState(FeatureController.FEAT_INTERNET, false);\n        }\n    };\n\n    private static final MigrationTask MIGRATE_FROM_3_0_0_RC01_RC04_TO_3_0_0 = new MigrationTask(406, 410) {\n        @Override\n        public void run() {\n            Log.d(TAG, \"Running MIGRATE_FROM_3_0_0_RC01_RC04_TO_3_0_0 from %d to %d\", fromVersion, toVersion);\n            // Clear DB\n            AppsDb.getInstance().backupDao().deleteAll();\n        }\n    };\n\n    private static final MigrationTask MIGRATE_FROM_4_0_5_TO_4_0_6 = new MigrationTask(445, 446) {\n        @Override\n        public void run() {\n            Log.d(TAG, \"Running MIGRATE_FROM_4_0_5_TO_4_0_6 from %d to %d\", fromVersion, toVersion);\n            //  DB\n            File newAppsDb = context.getDatabasePath(\"apps.db\");\n            if (!newAppsDb.exists()) {\n                File oldAppsDb = new File(FileUtils.getCachePath(), \"apps.db\");\n                if (oldAppsDb.exists()) {\n                    oldAppsDb.renameTo(newAppsDb);\n                }\n            }\n        }\n    };\n\n    private static final Migration migration;\n\n    static {\n        migration = new Migration();\n        migration.addTask(MIGRATE_FROM_ALL_VERSION_TO_3_0_0);\n        migration.addTask(MIGRATE_FROM_3_0_0_RC01_RC04_TO_3_0_0);\n        migration.addTask(MIGRATE_FROM_4_0_5_TO_4_0_6);\n    }\n\n    @WorkerThread\n    public static void startMigration(long fromVersion) {\n        migration.migrate(fromVersion);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/self/SelfPermissions.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.self;\n\nimport android.Manifest;\nimport android.annotation.UserIdInt;\nimport android.app.AppOpsManager;\nimport android.app.AppOpsManagerHidden;\nimport android.content.pm.PackageManager;\nimport android.os.Build;\nimport android.os.Environment;\nimport android.os.Process;\nimport android.os.RemoteException;\nimport android.os.UserHandleHidden;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.core.content.ContextCompat;\n\nimport io.github.muntashirakon.AppManager.BuildConfig;\nimport io.github.muntashirakon.AppManager.compat.AppOpsManagerCompat;\nimport io.github.muntashirakon.AppManager.compat.ManifestCompat;\nimport io.github.muntashirakon.AppManager.compat.PackageManagerCompat;\nimport io.github.muntashirakon.AppManager.compat.PermissionCompat;\nimport io.github.muntashirakon.AppManager.rules.compontents.ComponentsBlocker;\nimport io.github.muntashirakon.AppManager.settings.FeatureController;\nimport io.github.muntashirakon.AppManager.settings.Ops;\nimport io.github.muntashirakon.AppManager.users.Users;\nimport io.github.muntashirakon.AppManager.utils.ContextUtils;\nimport io.github.muntashirakon.AppManager.utils.Utils;\nimport io.github.muntashirakon.io.Paths;\n\npublic class SelfPermissions {\n    public static final String SHELL_PACKAGE_NAME = \"com.android.shell\";\n\n    public static void init() {\n        if (!canModifyPermissions()) {\n            return;\n        }\n        String[] permissions = new String[]{\n                Manifest.permission.DUMP,\n                ManifestCompat.permission.GET_APP_OPS_STATS,\n                ManifestCompat.permission.INTERACT_ACROSS_USERS,\n                Manifest.permission.READ_LOGS,\n                Manifest.permission.WRITE_SECURE_SETTINGS\n        };\n        int userId = UserHandleHidden.myUserId();\n        for (String permission : permissions) {\n            if (!checkSelfPermission(permission)) {\n                try {\n                    PermissionCompat.grantPermission(BuildConfig.APPLICATION_ID, permission, userId);\n                } catch (Exception ignore) {\n                }\n            }\n        }\n        // Grant usage stats permission (both permission and app op needs to be granted)\n        if (FeatureController.isUsageAccessEnabled()) {\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !checkSelfPermission(Manifest.permission.PACKAGE_USAGE_STATS)) {\n                try {\n                    PermissionCompat.grantPermission(BuildConfig.APPLICATION_ID, Manifest.permission.PACKAGE_USAGE_STATS, userId);\n                } catch (Exception ignore) {\n                }\n            }\n            try {\n                AppOpsManagerCompat appOps = new AppOpsManagerCompat();\n                appOps.setMode(AppOpsManagerHidden.OP_GET_USAGE_STATS, Process.myUid(), BuildConfig.APPLICATION_ID, AppOpsManager.MODE_ALLOWED);\n            } catch (RemoteException ignore) {\n            }\n        }\n    }\n\n    public static boolean canBlockByIFW() {\n        return Paths.get(ComponentsBlocker.SYSTEM_RULES_PATH).canWrite();\n    }\n\n    public static boolean canWriteToDataData() {\n        return Paths.get(\"/data/data\").canWrite();\n    }\n\n    public static boolean canModifyAppComponentStates(@UserIdInt int userId, @Nullable String packageName,\n                                                      boolean testOnlyApp) {\n        if (!checkCrossUserPermission(userId, false)) {\n            return false;\n        }\n        final int callingUid = Users.getSelfOrRemoteUid();\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {\n            // Since Oreo, shell can only disable components of test only apps\n            if (callingUid == Ops.SHELL_UID && !testOnlyApp) {\n                return false;\n            }\n        }\n        if (BuildConfig.APPLICATION_ID.equals(packageName)) {\n            // We can change components for this package\n            return true;\n        }\n        return checkSelfOrRemotePermission(Manifest.permission.CHANGE_COMPONENT_ENABLED_STATE, callingUid);\n    }\n\n    public static boolean canModifyAppOpMode() {\n        int callingUid = Users.getSelfOrRemoteUid();\n        boolean canModify = checkSelfOrRemotePermission(ManifestCompat.permission.UPDATE_APP_OPS_STATS, callingUid);\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {\n            canModify &= checkSelfOrRemotePermission(ManifestCompat.permission.MANAGE_APP_OPS_MODES, callingUid);\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {\n                canModify &= checkSelfOrRemotePermission(ManifestCompat.permission.MANAGE_APPOPS, callingUid);\n            }\n        }\n        return canModify;\n    }\n\n    public static boolean canModifyPermissions() {\n        int callingUid = Users.getSelfOrRemoteUid();\n        return checkSelfOrRemotePermission(ManifestCompat.permission.GRANT_RUNTIME_PERMISSIONS, callingUid)\n                || checkSelfOrRemotePermission(ManifestCompat.permission.REVOKE_RUNTIME_PERMISSIONS, callingUid);\n    }\n\n    public static boolean checkGetGrantRevokeRuntimePermissions() {\n        int callingUid = Users.getSelfOrRemoteUid();\n        return checkSelfOrRemotePermission(ManifestCompat.permission.GET_RUNTIME_PERMISSIONS, callingUid)\n                || checkSelfOrRemotePermission(ManifestCompat.permission.GRANT_RUNTIME_PERMISSIONS, callingUid)\n                || checkSelfOrRemotePermission(ManifestCompat.permission.REVOKE_RUNTIME_PERMISSIONS, callingUid);\n    }\n\n    public static boolean canInstallExistingPackages() {\n        int callingUid = Users.getSelfOrRemoteUid();\n        if (checkSelfOrRemotePermission(Manifest.permission.INSTALL_PACKAGES, callingUid)) {\n            return true;\n        }\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {\n            return checkSelfOrRemotePermission(ManifestCompat.permission.INSTALL_EXISTING_PACKAGES, callingUid);\n        }\n        return false;\n    }\n\n    public static boolean canFreezeUnfreezePackages() {\n        // 1. Suspend (7+): MANAGE_USERS (<= 9), SUSPEND_APPS (>= 9)\n        // 2. Disable: CHANGE_COMPONENT_ENABLED_STATE\n        // 2. HIDE: MANAGE_USERS\n        int callingUid = Users.getSelfOrRemoteUid();\n        boolean canFreezeUnfreeze = checkSelfOrRemotePermission(Manifest.permission.CHANGE_COMPONENT_ENABLED_STATE, callingUid)\n                || checkSelfOrRemotePermission(ManifestCompat.permission.MANAGE_USERS, callingUid);\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {\n            canFreezeUnfreeze |= checkSelfOrRemotePermission(ManifestCompat.permission.SUSPEND_APPS, callingUid);\n        }\n        return canFreezeUnfreeze;\n    }\n\n    public static boolean canClearAppCache() {\n        int callingUid = Users.getSelfOrRemoteUid();\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {\n            return checkSelfOrRemotePermission(ManifestCompat.permission.INTERNAL_DELETE_CACHE_FILES, callingUid);\n        }\n        return checkSelfOrRemotePermission(Manifest.permission.DELETE_CACHE_FILES, callingUid);\n    }\n\n    public static boolean canKillUid() {\n        int callingUid = Users.getSelfOrRemoteUid();\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {\n            return checkSelfOrRemotePermission(ManifestCompat.permission.KILL_UID, callingUid);\n        }\n        return callingUid == Ops.SYSTEM_UID;\n    }\n\n    public static boolean checkNotificationListenerAccess() {\n        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O_MR1) {\n            return false;\n        }\n        int callingUid = Users.getSelfOrRemoteUid();\n        if (checkSelfOrRemotePermission(ManifestCompat.permission.MANAGE_NOTIFICATION_LISTENERS, callingUid)) {\n            return true;\n        }\n        return callingUid == Ops.ROOT_UID || callingUid == Ops.SYSTEM_UID || callingUid == Ops.PHONE_UID;\n    }\n\n    public static boolean checkUsageStatsPermission() {\n        AppOpsManagerCompat appOps = new AppOpsManagerCompat();\n        int callingUid = Users.getSelfOrRemoteUid();\n        if (callingUid == Ops.ROOT_UID || callingUid == Ops.SYSTEM_UID) {\n            return true;\n        }\n        int mode = appOps.checkOpNoThrow(AppOpsManagerHidden.OP_GET_USAGE_STATS, callingUid, getCallingPackage(callingUid));\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && mode == AppOpsManager.MODE_DEFAULT) {\n            return checkSelfOrRemotePermission(Manifest.permission.PACKAGE_USAGE_STATS, callingUid);\n        }\n        return mode == AppOpsManager.MODE_ALLOWED;\n    }\n\n    public static boolean checkSelfStoragePermission() {\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {\n            if (Utils.isRoboUnitTest()) {\n                return false;\n            }\n            return Environment.isExternalStorageManager();\n        }\n        return checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE);\n    }\n\n    public static boolean checkStoragePermission() {\n        int callingUid = Users.getSelfOrRemoteUid();\n        if (callingUid == Ops.ROOT_UID) {\n            return true;\n        }\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {\n            String packageName = getCallingPackage(callingUid);\n            AppOpsManagerCompat appOps = new AppOpsManagerCompat();\n            int opMode = appOps.checkOpNoThrow(AppOpsManagerHidden.OP_MANAGE_EXTERNAL_STORAGE, callingUid, packageName);\n            switch (opMode) {\n                case AppOpsManager.MODE_DEFAULT:\n                    return checkSelfOrRemotePermission(Manifest.permission.MANAGE_EXTERNAL_STORAGE, callingUid);\n                case AppOpsManager.MODE_ALLOWED:\n                    return true;\n                case AppOpsManager.MODE_ERRORED:\n                case AppOpsManager.MODE_IGNORED:\n                    return false;\n                default:\n                    throw new IllegalStateException(\"Unknown AppOpsManager mode \" + opMode);\n            }\n        }\n        return checkSelfOrRemotePermission(Manifest.permission.WRITE_EXTERNAL_STORAGE, callingUid);\n    }\n\n    public static boolean checkCrossUserPermission(@UserIdInt int userId, boolean requireFullPermission) {\n        int callingUid = Users.getSelfOrRemoteUid();\n        return checkCrossUserPermission(userId, requireFullPermission, callingUid);\n    }\n\n    public static boolean checkCrossUserPermission(@UserIdInt int userId, boolean requireFullPermission, int callingUid) {\n        if (userId == UserHandleHidden.USER_NULL) {\n            userId = UserHandleHidden.myUserId();\n        }\n        if (userId < 0 && userId != UserHandleHidden.USER_ALL) {\n            throw new IllegalArgumentException(\"Invalid userId \" + userId);\n        }\n        if (isSystemOrRootOrShell(callingUid) || userId == UserHandleHidden.getUserId(callingUid)) {\n            return true;\n        }\n        if (requireFullPermission) {\n            return checkSelfOrRemotePermission(ManifestCompat.permission.INTERACT_ACROSS_USERS_FULL, callingUid);\n        }\n        return checkSelfOrRemotePermission(ManifestCompat.permission.INTERACT_ACROSS_USERS_FULL, callingUid)\n                || checkSelfOrRemotePermission(ManifestCompat.permission.INTERACT_ACROSS_USERS, callingUid);\n    }\n\n    public static boolean isShell() {\n        return Users.getSelfOrRemoteUid() == Ops.SHELL_UID;\n    }\n\n    public static boolean isSystem() {\n        return Users.getSelfOrRemoteUid() == Ops.SYSTEM_UID;\n    }\n\n    public static boolean isSystemOrRoot() {\n        int callingUid = Users.getSelfOrRemoteUid();\n        return callingUid == Ops.ROOT_UID || callingUid == Ops.SYSTEM_UID;\n    }\n\n    public static boolean isSystemOrRootOrShell() {\n        return isSystemOrRootOrShell(Users.getSelfOrRemoteUid());\n    }\n\n    private static boolean isSystemOrRootOrShell(int callingUid) {\n        return callingUid == Ops.ROOT_UID || callingUid == Ops.SYSTEM_UID || callingUid == Ops.SHELL_UID;\n    }\n\n    public static boolean checkSelfOrRemotePermission(@NonNull String permissionName) {\n        return checkSelfOrRemotePermission(permissionName, Users.getSelfOrRemoteUid());\n    }\n\n    public static boolean checkSelfOrRemotePermission(@NonNull String permissionName, int uid) {\n        if (uid == Ops.ROOT_UID) {\n            // Root UID has all the permissions granted\n            return true;\n        }\n        if (uid != Process.myUid()) {\n            try {\n                return PackageManagerCompat.getPackageManager().checkUidPermission(permissionName, uid)\n                        == PackageManager.PERMISSION_GRANTED;\n            } catch (RemoteException ignore) {\n            }\n        }\n        return checkSelfPermission(permissionName);\n    }\n\n    public static boolean checkSelfPermission(@NonNull String permissionName) {\n        return ContextCompat.checkSelfPermission(ContextUtils.getContext(), permissionName)\n                == PackageManager.PERMISSION_GRANTED;\n    }\n\n    public static void requireSelfPermission(@NonNull String permissionName) throws SecurityException {\n        if (!checkSelfPermission(permissionName)) {\n            throw new SecurityException(\"App Manager does not have the required permission \" + permissionName);\n        }\n    }\n\n    @NonNull\n    public static String getCallingPackage(int callingUid) {\n        if (callingUid == Ops.ROOT_UID || callingUid == Ops.SHELL_UID) {\n            return SHELL_PACKAGE_NAME;\n        }\n        if (callingUid == Ops.SYSTEM_UID) {\n            return \"android\";\n        }\n        return BuildConfig.APPLICATION_ID;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/self/SelfUriManager.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.self;\n\nimport android.net.Uri;\nimport android.os.UserHandleHidden;\nimport android.text.TextUtils;\n\nimport androidx.annotation.Nullable;\n\nimport io.github.muntashirakon.AppManager.types.UserPackagePair;\nimport io.github.muntashirakon.AppManager.utils.PackageUtils;\n\npublic class SelfUriManager {\n    public static final String APP_MANAGER_SCHEME = \"app-manager\";\n    public static final String SETTINGS_HOST = \"settings\";\n    public static final String DETAILS_HOST = \"details\";\n\n    @Nullable\n    public static UserPackagePair getUserPackagePairFromUri(@Nullable Uri detailsUri) {\n        // Required format app-manager://details?id=<pkg>&user=<user_id>\n        if (detailsUri == null || !APP_MANAGER_SCHEME.equals(detailsUri.getScheme())\n                || !DETAILS_HOST.equals(detailsUri.getHost())) {\n            return null;\n        }\n        String pkg = detailsUri.getQueryParameter(\"id\");\n        String userIdStr = detailsUri.getQueryParameter(\"user\");\n        if (pkg != null && PackageUtils.validateName(pkg.trim())) {\n            int userId;\n            if (userIdStr != null && TextUtils.isDigitsOnly(userIdStr)) {\n                userId = Integer.parseInt(userIdStr);\n            } else userId = UserHandleHidden.myUserId();\n            return new UserPackagePair(pkg, userId);\n        }\n        return null;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/self/filecache/FileCache.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.self.filecache;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport java.io.Closeable;\nimport java.io.File;\nimport java.io.FileNotFoundException;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.Map;\nimport java.util.Set;\n\nimport io.github.muntashirakon.AppManager.utils.FileUtils;\nimport io.github.muntashirakon.io.IoUtils;\nimport io.github.muntashirakon.io.Path;\nimport io.github.muntashirakon.io.Paths;\n\npublic class FileCache implements Closeable {\n\n    private static FileCache sInstance;\n\n    @NonNull\n    public static FileCache getGlobalFileCache() {\n        if (sInstance == null) {\n            sInstance = new FileCache(false);\n        }\n        return sInstance;\n    }\n\n    private final File mCacheDir;\n    private final Map<Path, File> mFileCacheMap = new HashMap<>();\n    private final Set<File> mFileCache = new HashSet<>();\n    private final Set<File> mDirectoryCache = new HashSet<>();\n    private final boolean mSessionOnly;\n\n    private boolean mClosed = false;\n\n    public FileCache() {\n        this(true);\n    }\n\n    private FileCache(boolean sessionOnly) {\n        mSessionOnly = sessionOnly;\n        mCacheDir = new File(FileUtils.getCachePath(), \"files\");\n        if (!mCacheDir.exists()) {\n            if (!mCacheDir.mkdirs()) {\n                throw new IllegalStateException(\"Could not create cache. Is this OS broken?\");\n            }\n        }\n    }\n\n    @Override\n    public void close() {\n        mClosed = true;\n        if (mSessionOnly) {\n            deleteAll();\n        }\n    }\n\n    @Override\n    protected void finalize() {\n        if (!mClosed) {\n            close();\n        }\n    }\n\n    @NonNull\n    public File getCachedFile(@NonNull Path source) throws IOException {\n        if (!source.exists()) {\n            // No need for cache if the path is non-existent\n            throw new FileNotFoundException(\"Path \" + source + \" does not exist.\");\n        }\n        File tempFile = mFileCacheMap.get(source);\n        if (tempFile == null || !tempFile.exists()) {\n            String extension = source.getExtension();\n            tempFile = File.createTempFile(source.getName() + \"_\", \".\" + (extension != null ? extension : \"tmp\"), mCacheDir);\n            mFileCacheMap.put(source, tempFile);\n        } else if (source.lastModified() > 0 && source.lastModified() < tempFile.lastModified()) {\n            return tempFile;\n        }\n        IoUtils.copy(source, Paths.get(tempFile));\n        return tempFile;\n    }\n\n    @NonNull\n    public File getCachedFile(@NonNull InputStream is, @Nullable String extension) throws IOException {\n        File tempFile = File.createTempFile(\"file_\", \".\" + (extension != null ? extension : \"tmp\"), mCacheDir);\n        mFileCache.add(tempFile);\n        try (OutputStream os = new FileOutputStream(tempFile)) {\n            IoUtils.copy(is, os);\n        }\n        return tempFile;\n    }\n\n    @NonNull\n    public File getCachedFile(@NonNull byte[] bytes, @Nullable String extension) throws IOException {\n        File tempFile = File.createTempFile(\"file_\", \".\" + (extension != null ? extension : \"tmp\"), mCacheDir);\n        mFileCache.add(tempFile);\n        try (OutputStream os = new FileOutputStream(tempFile)) {\n            os.write(bytes);\n        }\n        return tempFile;\n    }\n\n    @NonNull\n    public File createCachedFile(@Nullable String extension) throws IOException {\n        File tempFile = File.createTempFile(\"file_\", \".\" + (extension != null ? extension : \"tmp\"), mCacheDir);\n        mFileCache.add(tempFile);\n        return tempFile;\n    }\n\n    @NonNull\n    public File createCachedDir(@Nullable String prefix) {\n        if (prefix != null) {\n            prefix = Paths.sanitize(prefix, true);\n        }\n        if (prefix == null) {\n            prefix = \"folder\";\n        }\n        String dirName = prefix;\n        int i = 1;\n        File newDir = new File(mCacheDir, dirName);\n        while (newDir.exists()) {\n            dirName = prefix + \"_\" + i;\n            newDir = new File(mCacheDir, dirName);\n            ++i;\n        }\n        newDir.mkdirs();\n        // Get first path component from dirName\n        int idx = dirName.indexOf(File.separator);\n        String firstComponent;\n        if (idx == -1) {\n            firstComponent = dirName;\n        } else {\n            firstComponent = dirName.substring(0, idx);\n        }\n        mDirectoryCache.add(new File(mCacheDir, firstComponent));\n        return newDir;\n    }\n\n    public boolean delete(@Nullable Path path) {\n        File tempFile = mFileCacheMap.remove(path);\n        return tempFile != null && tempFile.delete();\n    }\n\n    public boolean delete(@Nullable File tempFile) {\n        if (mFileCache.remove(tempFile)) {\n            return tempFile != null && tempFile.delete();\n        }\n        return false;\n    }\n\n    public void deleteAll() {\n        for (File file : mFileCacheMap.values()) {\n            FileUtils.deleteSilently(file);\n        }\n        for (File file : mFileCache) {\n            FileUtils.deleteSilently(file);\n        }\n        for (File file : mDirectoryCache) {\n            Paths.get(file).delete();\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/self/filecache/InternalCacheCleanerService.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.self.filecache;\n\nimport android.app.AlarmManager;\nimport android.app.PendingIntent;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.util.Log;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.core.app.PendingIntentCompat;\n\nimport java.util.Calendar;\n\nimport io.github.muntashirakon.AppManager.types.ForegroundService;\nimport io.github.muntashirakon.AppManager.utils.FileUtils;\nimport io.github.muntashirakon.io.FileSystemManager;\nimport io.github.muntashirakon.io.Path;\nimport io.github.muntashirakon.io.Paths;\n\n// IMPORTANT: This service must be run without authentication.\npublic class InternalCacheCleanerService extends ForegroundService {\n    public static final String TAG = InternalCacheCleanerService.class.getSimpleName();\n\n    public static void scheduleAlarm(@NonNull Context context) {\n        Intent intent = new Intent(context, InternalCacheCleanerService.class);\n        int flags = PendingIntent.FLAG_UPDATE_CURRENT;\n        PendingIntent pastAlarmIntent = PendingIntentCompat.getService(context, 0, intent, flags | PendingIntent.FLAG_NO_CREATE, false);\n        if (pastAlarmIntent != null) {\n            // Already exists\n            return;\n        }\n        PendingIntent alarmIntent = PendingIntentCompat.getService(context, 0, intent, flags, false);\n\n        // Set the alarm to start at 5:00 AM\n        Calendar calendar = Calendar.getInstance();\n        calendar.setTimeInMillis(System.currentTimeMillis());\n        calendar.set(Calendar.HOUR_OF_DAY, 5);\n\n        // Run everyday\n        AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);\n        alarmManager.setInexactRepeating(AlarmManager.RTC_WAKEUP, calendar.getTimeInMillis(), AlarmManager.INTERVAL_DAY, alarmIntent);\n    }\n\n    public InternalCacheCleanerService() {\n        super(TAG);\n    }\n\n    @Override\n    public int onStartCommand(@Nullable Intent intent, int flags, int startId) {\n        return super.onStartCommand(intent, flags, startId);\n    }\n\n    @Override\n    protected void onHandleIntent(@Nullable Intent intent) {\n        clearOldFiles();\n        clearOldImages();\n    }\n\n    private void clearOldFiles() {\n        // Delete any files not accessed the last 3 days\n        long lastAccessDate = System.currentTimeMillis() - 259_200_000;\n        Path fileCache = Paths.getUnprivileged(FileSystemManager.getLocal().getFile(FileUtils.getCachePath(), \"files\"));\n        int deleteCount = deleteFilesWithAccessDate(fileCache, lastAccessDate);\n        Log.i(TAG, \"Deleted \" + deleteCount + \" files and directories.\");\n    }\n\n    private void clearOldImages() {\n        // Delete any files not accessed the last 7 days\n        long lastAccessDate = System.currentTimeMillis() - 604_800_000;\n        Path fileCache = Paths.getUnprivileged(FileSystemManager.getLocal().getFile(FileUtils.getCachePath(), \"images\"));\n        int deleteCount = deleteFilesWithAccessDate(fileCache, lastAccessDate);\n        Log.i(TAG, \"Deleted \" + deleteCount + \" images.\");\n    }\n\n    private static int deleteFilesWithAccessDate(@NonNull Path basePath, long accessDate) {\n        int deleteCount = 0;\n        Path[] files = basePath.listFiles();\n        for (Path file : files) {\n            long lastAccess = file.lastAccess();\n            if (lastAccess <= 0) {\n                lastAccess = file.lastModified();\n            }\n            if (lastAccess <= accessDate && file.delete()) {\n                ++deleteCount;\n            }\n        }\n        return deleteCount;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/self/imagecache/ImageFileCache.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.self.imagecache;\n\nimport android.graphics.Bitmap;\nimport android.graphics.BitmapFactory;\nimport android.graphics.drawable.Drawable;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\n\nimport io.github.muntashirakon.AppManager.logs.Log;\nimport io.github.muntashirakon.AppManager.utils.FileUtils;\nimport io.github.muntashirakon.AppManager.utils.UIUtils;\nimport io.github.muntashirakon.io.IoUtils;\n\nclass ImageFileCache {\n    private static final long sLastModifiedDate = System.currentTimeMillis() - 604_800_000;\n\n    private final File mCacheDir;\n\n    public ImageFileCache() {\n        mCacheDir = new File(FileUtils.getCachePath(), \"images\");\n        if (!mCacheDir.exists()) {\n            if (!mCacheDir.mkdirs()) {\n                throw new IllegalStateException(\"Could not create cache. Is this OS broken?\");\n            }\n        }\n    }\n\n    public void putImage(@NonNull String name, @NonNull InputStream inputStream) throws IOException {\n        File iconFile = getImageFile(name);\n        try (OutputStream os = new FileOutputStream(iconFile)) {\n            IoUtils.copy(inputStream, os);\n        }\n    }\n\n    public void putImage(@NonNull String name, @NonNull Drawable drawable) throws IOException {\n        putImage(name, UIUtils.getBitmapFromDrawable(drawable));\n    }\n\n    public void putImage(@NonNull String name, @NonNull Bitmap bitmap) throws IOException {\n        File iconFile = getImageFile(name);\n        try (OutputStream os = new FileOutputStream(iconFile)) {\n            bitmap.compress(Bitmap.CompressFormat.PNG, 100, os);\n            os.flush();\n        }\n    }\n\n    @Nullable\n    public Bitmap getImage(@NonNull String name) {\n        File iconFile = getImageFile(name);\n        if (iconFile.lastModified() >= sLastModifiedDate) {\n            try (FileInputStream fis = new FileInputStream(iconFile)) {\n                return BitmapFactory.decodeStream(fis);\n            } catch (IOException e) {\n                return null;\n            }\n        }\n        return null;\n    }\n\n    @Nullable\n    public Drawable getImageDrawable(@NonNull String name) {\n        File iconFile = getImageFile(name);\n        if (iconFile.lastModified() >= sLastModifiedDate) {\n            try (FileInputStream fis = new FileInputStream(iconFile)) {\n                return Drawable.createFromStream(fis, name);\n            } catch (IOException e) {\n                return null;\n            }\n        }\n        return null;\n    }\n\n    @NonNull\n    private File getImageFile(@NonNull String name) {\n        return new File(mCacheDir, name + \".png\");\n    }\n\n    public void clear() {\n        File[] files = mCacheDir.listFiles();\n        if (files == null) return;\n        int count = 0;\n        for (File f : files) {\n            if (f.lastModified() < sLastModifiedDate) {\n                if (f.delete()) ++count;\n            }\n        }\n        Log.d(\"Cache\", \"Deleted %d images.\", count);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/self/imagecache/ImageLoader.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.self.imagecache;\n\nimport android.content.pm.PackageItemInfo;\nimport android.content.pm.PackageManager;\nimport android.graphics.Bitmap;\nimport android.graphics.drawable.Drawable;\nimport android.widget.ImageView;\n\nimport androidx.annotation.AnyThread;\nimport androidx.annotation.DrawableRes;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.Px;\nimport androidx.annotation.UiThread;\nimport androidx.annotation.WorkerThread;\nimport androidx.collection.LruCache;\nimport androidx.core.content.ContextCompat;\n\nimport java.io.Closeable;\nimport java.io.IOException;\nimport java.lang.ref.WeakReference;\nimport java.util.Objects;\n\nimport io.github.muntashirakon.AppManager.utils.ContextUtils;\nimport io.github.muntashirakon.AppManager.utils.ThreadUtils;\nimport io.github.muntashirakon.AppManager.utils.UIUtils;\n\npublic class ImageLoader implements Closeable {\n    @AnyThread\n    public static void displayImage(@Nullable PackageItemInfo info, @Nullable ImageView imageView) {\n        WeakReference<ImageView> ivRef = new WeakReference<>(imageView);\n        ThreadUtils.postOnBackgroundThread(() -> {\n            ImageView iv = ivRef.get();\n            if (info == null || iv == null) {\n                return;\n            }\n            Drawable drawable = info.loadIcon(iv.getContext().getPackageManager());\n            ThreadUtils.postOnMainThread(() -> {\n                ImageView iv2 = ivRef.get();\n                if (iv2 != null) {\n                    iv2.setImageDrawable(drawable);\n                }\n            });\n        });\n    }\n\n    public interface ImageFetcherInterface {\n        @WorkerThread\n        @NonNull\n        ImageFetcherResult fetchImage(@NonNull String tag);\n    }\n\n    private static final ImageLoader sInstance = new ImageLoader();\n\n    @NonNull\n    public static ImageLoader getInstance() {\n        return sInstance;\n    }\n\n    private final LruCache<String, Bitmap> mMemoryCache = new LruCache<>(300);\n    private final ImageFileCache mImageFileCache = new ImageFileCache();\n    private boolean mIsClosed = false;\n\n    private ImageLoader() {\n    }\n\n    @WorkerThread\n    @Nullable\n    public Bitmap getCachedImage(@NonNull String tag) {\n        Bitmap image = mMemoryCache.get(tag);\n        if (image != null) {\n            return image;\n        }\n        // Load from file system\n        return mImageFileCache.getImage(tag);\n    }\n\n    @UiThread\n    public void displayImage(@NonNull String tag, @NonNull ImageView imageView,\n                             @NonNull ImageFetcherInterface imageFetcherInterface) {\n        Bitmap image = mMemoryCache.get(tag);\n        if (image != null) {\n            imageView.setImageBitmap(image);\n        } else {\n            queueImage(tag, imageView, imageFetcherInterface);\n        }\n    }\n\n    @UiThread\n    public void displayImage(@NonNull String tag, @Nullable PackageItemInfo info, @NonNull ImageView imageView) {\n        Bitmap image = mMemoryCache.get(tag);\n        if (image != null) {\n            imageView.setImageBitmap(image);\n        } else {\n            queueImage(tag, info, imageView);\n        }\n    }\n\n    @AnyThread\n    private void queueImage(@NonNull String tag, @Nullable PackageItemInfo info, @NonNull ImageView imageView) {\n        queueImage(tag, imageView, new PackageInfoImageFetcher(info));\n    }\n\n    @AnyThread\n    private void queueImage(@NonNull String tag, @NonNull ImageView imageView,\n                            @NonNull ImageFetcherInterface imageFetcherInterface) {\n        ImageLoaderQueueItem queueItem = new ImageLoaderQueueItem(tag, imageFetcherInterface, imageView);\n        ThreadUtils.postOnBackgroundThread(new LoadQueueItem(queueItem));\n    }\n\n    @Override\n    public void close() {\n        mIsClosed = true;\n        mMemoryCache.evictAll();\n        mImageFileCache.clear();\n    }\n\n    @Override\n    protected void finalize() {\n        if (!mIsClosed) {\n            close();\n        }\n    }\n\n    private static class PackageInfoImageFetcher implements ImageFetcherInterface {\n        @Nullable\n        private final PackageItemInfo mInfo;\n\n        public PackageInfoImageFetcher(@Nullable PackageItemInfo info) {\n            mInfo = info;\n        }\n\n        @Override\n        @NonNull\n        public ImageFetcherResult fetchImage(@NonNull String tag) {\n            PackageManager pm = ContextUtils.getContext().getPackageManager();\n            Drawable drawable = mInfo != null ? mInfo.loadIcon(pm) : null;\n            return new ImageFetcherResult(tag, drawable != null ? UIUtils.getBitmapFromDrawable(drawable) : null,\n                    mInfo != null && tag.equals(mInfo.packageName), true,\n                    new DefaultImageDrawable(\"android_default_icon\", pm.getDefaultActivityIcon()));\n        }\n    }\n\n    public interface DefaultImage {\n        @Nullable\n        default String getTag() {\n            return null;\n        }\n\n        @NonNull\n        Bitmap getImage();\n    }\n\n    public static class DefaultImageDrawableRes implements DefaultImage {\n        @Nullable\n        private final String mTag;\n        @DrawableRes\n        private final int mDrawableRes;\n        @Px\n        private final int mPadding;\n\n        public DefaultImageDrawableRes(@Nullable String tag, int drawableRes) {\n            this(tag, drawableRes, 0);\n        }\n\n        public DefaultImageDrawableRes(@Nullable String tag, int drawableRes, @Px int padding) {\n            mTag = tag;\n            mDrawableRes = drawableRes;\n            mPadding = padding;\n        }\n\n        @Override\n        @Nullable\n        public String getTag() {\n            return mTag;\n        }\n\n        @NonNull\n        @Override\n        public Bitmap getImage() {\n            return UIUtils.getBitmapFromDrawable(Objects.requireNonNull(ContextCompat\n                    .getDrawable(ContextUtils.getContext(), mDrawableRes)), mPadding);\n        }\n    }\n\n    public static class DefaultImageDrawable implements DefaultImage {\n        @Nullable\n        private final String mTag;\n        @NonNull\n        private final Drawable mDrawable;\n\n        public DefaultImageDrawable(@Nullable String tag, @NonNull Drawable drawable) {\n            mTag = tag;\n            mDrawable = drawable;\n        }\n\n        @Override\n        @Nullable\n        public String getTag() {\n            return mTag;\n        }\n\n        @NonNull\n        @Override\n        public Bitmap getImage() {\n            return UIUtils.getBitmapFromDrawable(mDrawable);\n        }\n    }\n\n    public static class DefaultImageString implements DefaultImage {\n        @Nullable\n        private final String mTag;\n        @NonNull\n        private final String mText;\n\n        public DefaultImageString(@Nullable String tag, @NonNull String text) {\n            mTag = tag;\n            mText = text;\n        }\n\n        @Override\n        @Nullable\n        public String getTag() {\n            return mTag;\n        }\n\n        @NonNull\n        @Override\n        public Bitmap getImage() {\n            return UIUtils.generateBitmapFromText(mText, null);\n        }\n    }\n\n    public static class ImageFetcherResult {\n        @NonNull\n        public final String tag;\n        @Nullable\n        public final Bitmap bitmap;\n        public final boolean cacheInMemory;\n        public final boolean persistCache;\n        @NonNull\n        public final DefaultImage defaultImage;\n\n        public ImageFetcherResult(@NonNull String tag, @Nullable Bitmap bitmap, @NonNull DefaultImage defaultImage) {\n            this(tag, bitmap, true, true, defaultImage);\n        }\n\n        public ImageFetcherResult(@NonNull String tag, @Nullable Bitmap bitmap, boolean cacheInMemory,\n                                  boolean persistCache, @NonNull DefaultImage defaultImage) {\n            this.tag = tag;\n            this.bitmap = bitmap;\n            this.cacheInMemory = cacheInMemory;\n            this.persistCache = persistCache;\n            this.defaultImage = defaultImage;\n        }\n    }\n\n    @AnyThread\n    public static class ImageLoaderQueueItem {\n        public final String tag;\n        public final WeakReference<ImageView> imageView;\n\n        private final ImageFetcherInterface mImageFetcherInterface;\n\n        public ImageLoaderQueueItem(@NonNull String tag, @NonNull ImageFetcherInterface imageFetcherInterface,\n                                    @NonNull ImageView imageView) {\n            this.tag = tag;\n            this.imageView = new WeakReference<>(imageView);\n            mImageFetcherInterface = imageFetcherInterface;\n        }\n    }\n\n    private class LoadQueueItem implements Runnable {\n        private final ImageLoaderQueueItem mQueueItem;\n\n        LoadQueueItem(ImageLoaderQueueItem queueItem) {\n            mQueueItem = queueItem;\n        }\n\n        @WorkerThread\n        public void run() {\n            if (imageViewReusedOrClosed(mQueueItem)) return;\n            Bitmap image = mImageFileCache.getImage(mQueueItem.tag);\n            if (image != null) {\n                // Cache hit\n                mMemoryCache.put(mQueueItem.tag, image);\n            } else {\n                // Cache miss\n                ImageFetcherResult result = mQueueItem.mImageFetcherInterface.fetchImage(mQueueItem.tag);\n                if (result.bitmap == null) {\n                    // No image produced, try default\n                    DefaultImage defaultImage = result.defaultImage;\n                    String tag = defaultImage.getTag();\n                    if (tag == null) {\n                        // No tag listed, use the image directly\n                        image = defaultImage.getImage();\n                    } else {\n                        // Listed a tag, try cache first\n                        image = mMemoryCache.get(tag);\n                        if (image == null) {\n                            image = mImageFileCache.getImage(tag);\n                        }\n                        if (image == null) {\n                            // Cache miss\n                            image = defaultImage.getImage();\n                            mMemoryCache.put(tag, image);\n                            try {\n                                mImageFileCache.putImage(tag, image);\n                            } catch (IOException ignore) {\n                            }\n                        }\n                    }\n                } else {\n                    image = result.bitmap;\n                    if (result.cacheInMemory) {\n                        mMemoryCache.put(mQueueItem.tag, image);\n                    }\n                    if (result.persistCache) {\n                        try {\n                            mImageFileCache.putImage(result.tag, image);\n                        } catch (IOException ignore) {\n                        }\n                    }\n                }\n            }\n            if (imageViewReusedOrClosed(mQueueItem)) return;\n            ThreadUtils.postOnMainThread(new LoadImageInImageView(image, mQueueItem));\n        }\n    }\n\n    // Used to display bitmap in the UI thread\n    private class LoadImageInImageView implements Runnable {\n        private final Bitmap mImage;\n        private final ImageLoaderQueueItem mQueueItem;\n\n        public LoadImageInImageView(@NonNull Bitmap image, ImageLoaderQueueItem queueItem) {\n            mImage = image;\n            mQueueItem = queueItem;\n        }\n\n        @UiThread\n        public void run() {\n            if (imageViewReusedOrClosed(mQueueItem)) return;\n            ImageView iv = mQueueItem.imageView.get();\n            if (iv != null) {\n                Object tag = iv.getTag();\n                if (tag == null || tag.equals(mQueueItem.tag)) {\n                    iv.setImageBitmap(mImage);\n                }\n            }\n        }\n    }\n\n    @AnyThread\n    private boolean imageViewReusedOrClosed(@NonNull ImageLoaderQueueItem imageLoaderQueueItem) {\n        ImageView iv = imageLoaderQueueItem.imageView.get();\n        return mIsClosed || iv == null;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/self/life/BuildExpiryChecker.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.self.life;\n\nimport android.content.DialogInterface;\nimport android.content.Intent;\nimport android.net.Uri;\n\nimport androidx.annotation.IntDef;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.appcompat.app.AlertDialog;\nimport androidx.fragment.app.FragmentActivity;\n\nimport com.google.android.material.dialog.MaterialAlertDialogBuilder;\n\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.util.Locale;\n\nimport io.github.muntashirakon.AppManager.BuildConfig;\nimport io.github.muntashirakon.AppManager.R;\n\npublic final class BuildExpiryChecker {\n    @IntDef({BUILD_TYPE_DEBUG, BUILD_TYPE_ALPHA, BUILD_TYPE_BETA, BUILD_TYPE_RC, BUILD_TYPE_STABLE})\n    @Retention(RetentionPolicy.SOURCE)\n    private @interface BuildType {}\n\n    private static final int BUILD_TYPE_DEBUG = 0;\n    private static final int BUILD_TYPE_ALPHA = 1;\n    private static final int BUILD_TYPE_BETA = 2;\n    private static final int BUILD_TYPE_RC = 3;\n    private static final int BUILD_TYPE_STABLE = 4;\n\n    private static final long[] TIME_SPAN_MILLIS = new long[]{\n            2L * 30 * 24 * 60 * 60_000, // 2 months\n            6L * 30 * 24 * 60 * 60_000, // 6 months\n            6L * 30 * 24 * 60 * 60_000, // 6 months\n            6L * 30 * 24 * 60 * 60_000, // 6 months\n            18L * 30 * 24 * 60 * 60_000, // 18 months\n    };\n\n    private static final long[] WARNING_PERIOD_MILLIS = new long[]{\n            14L * 24 * 60 * 60_000, // 2 weeks\n            30L * 24 * 60 * 60_000, // 1 month\n            30L * 24 * 60 * 60_000, // 1 month\n            30L * 24 * 60 * 60_000, // 1 month\n            3L * 30 * 24 * 60 * 60_000, // 3 months\n    };\n\n    @NonNull\n    public static AlertDialog getBuildExpiredDialog(@NonNull FragmentActivity activity,\n                                                    @Nullable DialogInterface.OnClickListener continueClickListener) {\n        MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(activity)\n                .setTitle(R.string.app_manager_build_expired)\n                .setMessage(R.string.app_manager_build_expired_message)\n                .setCancelable(false)\n                .setPositiveButton(R.string.update, (dialog, which) -> {\n                    Intent intent = new Intent(Intent.ACTION_VIEW);\n                    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);\n                    intent.setData(getUpdateUri());\n                    activity.startActivity(intent);\n                    activity.finishAndRemoveTask();\n                })\n                .setNeutralButton(R.string.uninstall, (dialog, which) -> {\n                    Intent intent = new Intent(Intent.ACTION_DELETE);\n                    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);\n                    intent.setData(Uri.parse(\"package:\" + BuildConfig.APPLICATION_ID));\n                    activity.startActivity(intent);\n                    activity.finishAndRemoveTask();\n                });\n        if (getBuildType() == BUILD_TYPE_STABLE) {\n            builder.setNeutralButton(R.string.action_continue, continueClickListener);\n        }\n        return builder.create();\n    }\n\n    @Nullable\n    public static Boolean buildExpired() {\n        int buildType = getBuildType();\n        long timeSpan = getCurrentTime() - getBuildTime();\n        long realTimeSpan = TIME_SPAN_MILLIS[buildType];\n        if (timeSpan <= realTimeSpan) {\n            // Build hasn't yet expired\n            return false;\n        }\n        // Build has expired\n        long warningPeriod = WARNING_PERIOD_MILLIS[buildType];\n        if (timeSpan <= realTimeSpan + warningPeriod) {\n            // Build has expired but in warning period\n            return null;\n        }\n        // Build has completely expired and should stop working\n        return true;\n    }\n\n    private static long getCurrentTime() {\n        // Ideally, we should fetch this from an SNTP server such as time.android.com\n        return System.currentTimeMillis();\n    }\n\n    private static long getBuildTime() {\n        return BuildConfig.BUILD_TIME_MILLIS;\n    }\n\n    private static Uri getUpdateUri() {\n        if (getBuildType() == BUILD_TYPE_DEBUG) {\n            return Uri.parse(\"https://github.com/MuntashirAkon/AppManager/actions/workflows/debug_build.yml\");\n        }\n        // TODO: 3/12/22 For Stable builds, check F-Droid too\n        return Uri.parse(\"https://github.com/MuntashirAkon/AppManager/releases\");\n    }\n\n    @BuildType\n    private static int getBuildType() {\n        if (BuildConfig.DEBUG) {\n            return BUILD_TYPE_DEBUG;\n        }\n        String[] versionParts = BuildConfig.VERSION_NAME.split(\"-\");\n        if (versionParts.length == 1) {\n            return BUILD_TYPE_STABLE;\n        }\n        String lastPart = versionParts[versionParts.length - 1];\n        switch (lastPart.substring(0, lastPart.length() - 2).toLowerCase(Locale.ROOT)) {\n            case \"alpha\":\n                return BUILD_TYPE_ALPHA;\n            case \"beta\":\n                return BUILD_TYPE_BETA;\n            case \"rc\":\n                return BUILD_TYPE_RC;\n            default:\n                throw new IllegalStateException(\"Invalid App Manager version\");\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/self/life/FundingCampaignChecker.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.self.life;\n\npublic class FundingCampaignChecker {\n    private static final long FUNDING_CAMPAIGN_START = 1703160000000L;\n    private static final long FUNDING_CAMPAIGN_END = 1717200000000L;\n\n    public static boolean campaignRunning() {\n        long currentTime = System.currentTimeMillis();\n        return currentTime >= FUNDING_CAMPAIGN_START && currentTime <= FUNDING_CAMPAIGN_END;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/self/pref/TipsPrefs.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.self.pref;\n\nimport androidx.annotation.NonNull;\n\nimport io.github.muntashirakon.AppManager.utils.AppPref;\n\npublic class TipsPrefs {\n    private static final int TIPS_TAB_APP_OPS = 1 << 0;\n    private static final int TIPS_TAB_USES_PERMISSIONS = 1 << 1;\n    private static final int TIPS_TAB_PERMISSIONS = 1 << 2;\n    private static final int TIPS_TAB_OVERLAYS = 1 << 3;\n\n    private static TipsPrefs sInstance;\n\n    @NonNull\n    public static TipsPrefs getInstance() {\n        if (sInstance != null) {\n            return sInstance;\n        }\n        return sInstance = new TipsPrefs();\n    }\n\n    private int mFlags;\n\n    private TipsPrefs() {\n        mFlags = AppPref.getInt(AppPref.PrefKey.PREF_TIPS_PREFS_INT);\n    }\n\n    public boolean displayInAppOpsTab() {\n        return (mFlags & TIPS_TAB_APP_OPS) != 0;\n    }\n\n    public void setDisplayInAppOpsTab(boolean display) {\n        save(TIPS_TAB_APP_OPS, display);\n    }\n\n    public boolean displayInUsesPermissionsTab() {\n        return (mFlags & TIPS_TAB_USES_PERMISSIONS) != 0;\n    }\n\n    public void setDisplayInUsesPermissionsTab(boolean display) {\n        save(TIPS_TAB_USES_PERMISSIONS, display);\n    }\n\n    public boolean displayInPermissionsTab() {\n        return (mFlags & TIPS_TAB_PERMISSIONS) != 0;\n    }\n\n    public void setDisplayInPermissionsTab(boolean display) {\n        save(TIPS_TAB_PERMISSIONS, display);\n    }\n\n    public boolean displayInOverlaysTab() {\n        return (mFlags & TIPS_TAB_USES_PERMISSIONS) != 0;\n    }\n\n    public void setDisplayInOverlaysTab(boolean display) {\n        save(TIPS_TAB_OVERLAYS, display);\n    }\n\n    private void save(int flag, boolean display) {\n        if (display) mFlags |= flag;\n        else mFlags &= ~flag;\n        AppPref.set(AppPref.PrefKey.PREF_TIPS_PREFS_INT, mFlags);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/servermanager/AssetsUtils.java",
    "content": "// SPDX-License-Identifier: MIT AND GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.servermanager;\n\nimport android.content.Context;\nimport android.content.res.AssetFileDescriptor;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.WorkerThread;\n\nimport org.jetbrains.annotations.NotNull;\n\nimport java.io.BufferedReader;\nimport java.io.BufferedWriter;\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileOutputStream;\nimport java.io.FileWriter;\nimport java.io.IOException;\nimport java.io.InputStreamReader;\n\nimport io.github.muntashirakon.AppManager.BuildConfig;\nimport io.github.muntashirakon.AppManager.server.common.ConfigParams;\nimport io.github.muntashirakon.AppManager.server.common.Constants;\nimport io.github.muntashirakon.io.IoUtils;\n\n// Copyright 2016 Zheng Li\n@SuppressWarnings(\"ResultOfMethodCallIgnored\")\nclass AssetsUtils {\n    @WorkerThread\n    public static void copyFile(@NonNull Context context, String fileName, File destFile, boolean force)\n            throws IOException {\n        try (AssetFileDescriptor openFd = context.getAssets().openFd(fileName)) {\n            if (force) {\n                destFile.delete();\n            } else {\n                if (destFile.exists()) {\n                    if (destFile.length() != openFd.getLength()) {\n                        destFile.delete();\n                    } else {\n                        return;\n                    }\n                }\n            }\n\n            try (FileInputStream open = openFd.createInputStream();\n                 FileOutputStream fos = new FileOutputStream(destFile)) {\n                byte[] buff = new byte[IoUtils.DEFAULT_BUFFER_SIZE];\n                int len;\n                while ((len = open.read(buff)) != -1) {\n                    fos.write(buff, 0, len);\n                }\n                fos.flush();\n                fos.getFD().sync();\n            }\n        }\n    }\n\n    @WorkerThread\n    static void writeServerExecScript(@NonNull Context context, @NonNull File destFile, @NonNull String classPath) throws IOException {\n        try (AssetFileDescriptor openFd = context.getAssets().openFd(ServerConfig.SERVER_RUNNER_EXEC_NAME);\n             BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(openFd.createInputStream()))) {\n            if (destFile.exists()) {\n                destFile.delete();\n            }\n            try (BufferedWriter bw = new BufferedWriter(new FileWriter(destFile, false))) {\n                // Set variables\n                StringBuilder script = new StringBuilder();\n                script.append(\"SERVER_NAME=\").append(Constants.SERVER_NAME).append(\"\\n\")\n                        .append(\"JAR_NAME=\").append(Constants.JAR_NAME).append(\"\\n\")\n                        .append(\"JAR_PATH=\").append(classPath).append(\"\\n\")\n                        .append(\"ARGS=\").append(getServerArgs()).append(\"\\n\");\n                String line;\n                while ((line = bufferedReader.readLine()) != null) {\n                    String wl;\n                    if (\"%ENV_VARS%\".equals(line.trim())) {\n                        wl = script.toString();\n                    } else wl = line;\n                    bw.write(wl);\n                    bw.newLine();\n                }\n                bw.flush();\n            }\n        }\n    }\n\n    @NotNull\n    private static String getServerArgs() {\n        StringBuilder argsBuilder = new StringBuilder();\n        argsBuilder.append(',').append(ConfigParams.PARAM_APP).append(':').append(BuildConfig.APPLICATION_ID);\n        if (ServerConfig.getAllowBgRunning()) {\n            argsBuilder.append(',').append(ConfigParams.PARAM_RUN_IN_BACKGROUND).append(':').append(1);\n        }\n        if (BuildConfig.DEBUG) {\n            argsBuilder.append(',').append(ConfigParams.PARAM_DEBUG).append(':').append(1);\n        }\n        return argsBuilder.toString();\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/servermanager/LocalServer.java",
    "content": "// SPDX-License-Identifier: MIT AND GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.servermanager;\n\nimport android.annotation.SuppressLint;\nimport android.content.Context;\n\nimport androidx.annotation.AnyThread;\nimport androidx.annotation.GuardedBy;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.WorkerThread;\n\nimport java.io.IOException;\nimport java.net.InetSocketAddress;\nimport java.net.ServerSocket;\nimport java.net.SocketTimeoutException;\n\nimport io.github.muntashirakon.AppManager.logs.Log;\nimport io.github.muntashirakon.AppManager.misc.NoOps;\nimport io.github.muntashirakon.AppManager.server.common.Caller;\nimport io.github.muntashirakon.AppManager.server.common.CallerResult;\nimport io.github.muntashirakon.AppManager.server.common.Shell;\nimport io.github.muntashirakon.AppManager.server.common.ShellCaller;\nimport io.github.muntashirakon.AppManager.utils.ContextUtils;\nimport io.github.muntashirakon.adb.AdbPairingRequiredException;\n\n// Copyright 2016 Zheng Li\npublic class LocalServer {\n    @GuardedBy(\"lockObject\")\n    private static final Object sLock = new Object();\n\n    @SuppressLint(\"StaticFieldLeak\")\n    @Nullable\n    private static LocalServer sLocalServer;\n\n    @GuardedBy(\"lockObject\")\n    @WorkerThread\n    @NoOps(used = true)\n    public static LocalServer getInstance() throws IOException, AdbPairingRequiredException {\n        // Non-null check must be done outside the synchronised block to prevent deadlock on ADB over TCP mode.\n        if (sLocalServer != null) return sLocalServer;\n        synchronized (sLock) {\n            try {\n                Log.d(\"IPC\", \"Init: Local server\");\n                sLocalServer = new LocalServer();\n            } finally {\n                sLock.notifyAll();\n            }\n        }\n        return sLocalServer;\n    }\n\n    public static void die() {\n        synchronized (sLock) {\n            try {\n                if (sLocalServer != null) {\n                    sLocalServer.destroy();\n                }\n            } finally {\n                sLocalServer = null;\n            }\n        }\n    }\n\n    @WorkerThread\n    @NoOps\n    public static boolean alive(Context context) {\n        try (ServerSocket socket = new ServerSocket()) {\n            socket.bind(new InetSocketAddress(ServerConfig.getLocalServerHost(context),\n                    ServerConfig.getLocalServerPort()), 1);\n            return false;\n        } catch (IOException e) {\n            return true;\n        }\n    }\n\n    @NonNull\n    private final Context mContext;\n    @NonNull\n    private final LocalServerManager mLocalServerManager;\n\n    @WorkerThread\n    @NoOps(used = true)\n    private LocalServer() throws IOException, AdbPairingRequiredException {\n        mContext = ContextUtils.getDeContext(ContextUtils.getContext());\n        mLocalServerManager = LocalServerManager.getInstance(mContext);\n        // Initialise necessary files and permissions\n        ServerConfig.init(mContext);\n        // Start server if not already\n        checkConnect();\n    }\n\n    private final Object mConnectLock = new Object();\n    private boolean mConnectStarted = false;\n\n    @GuardedBy(\"connectLock\")\n    @WorkerThread\n    @NoOps(used = true)\n    public void checkConnect() throws IOException, AdbPairingRequiredException {\n        synchronized (mConnectLock) {\n            if (mConnectStarted) {\n                try {\n                    mConnectLock.wait();\n                } catch (InterruptedException e) {\n                    return;\n                }\n            }\n            mConnectStarted = true;\n            try {\n                mLocalServerManager.start();\n            } catch (IOException | AdbPairingRequiredException e) {\n                mConnectStarted = false;\n                mConnectLock.notify();\n                throw e;\n            }\n            mConnectStarted = false;\n            mConnectLock.notify();\n        }\n    }\n\n    public Shell.Result runCommand(String command) throws IOException {\n        ShellCaller shellCaller = new ShellCaller(command);\n        CallerResult callerResult = exec(shellCaller);\n        Throwable th = callerResult.getThrowable();\n        if (th != null) {\n            throw new IOException(th);\n        }\n        return (Shell.Result) callerResult.getReplyObj();\n    }\n\n    @WorkerThread\n    public CallerResult exec(Caller caller) throws IOException {\n        try {\n            checkConnect();\n            return mLocalServerManager.execNew(caller);\n        } catch (SocketTimeoutException e) {\n            e.printStackTrace();\n            closeBgServer();\n            // Retry\n            try {\n                checkConnect();\n                return mLocalServerManager.execNew(caller);\n            } catch (AdbPairingRequiredException e2) {\n                throw new IOException(e2);\n            }\n        } catch (AdbPairingRequiredException e) {\n            throw new IOException(e);\n        }\n    }\n\n    @AnyThread\n    public boolean isRunning() {\n        return mLocalServerManager.isRunning();\n    }\n\n    public void destroy() {\n        mLocalServerManager.stop();\n    }\n\n    @WorkerThread\n    public void closeBgServer() throws IOException {\n        mLocalServerManager.closeBgServer();\n        mLocalServerManager.stop();\n    }\n\n    @WorkerThread\n    @NoOps(used = true)\n    public static void restart() throws IOException, AdbPairingRequiredException {\n        if (sLocalServer != null) {\n            LocalServerManager manager = sLocalServer.mLocalServerManager;\n            manager.closeBgServer();\n            manager.stop();\n            manager.start();\n        } else {\n            getInstance();\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/servermanager/LocalServerManager.java",
    "content": "// SPDX-License-Identifier: MIT AND GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.servermanager;\n\nimport android.annotation.SuppressLint;\nimport android.content.Context;\nimport android.os.SystemClock;\n\nimport androidx.annotation.AnyThread;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.WorkerThread;\n\nimport java.io.BufferedReader;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.InputStreamReader;\nimport java.io.OutputStream;\nimport java.net.Socket;\nimport java.util.Objects;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.TimeUnit;\n\nimport io.github.muntashirakon.AppManager.adb.AdbConnectionManager;\nimport io.github.muntashirakon.AppManager.logs.Log;\nimport io.github.muntashirakon.AppManager.misc.NoOps;\nimport io.github.muntashirakon.AppManager.runner.Runner;\nimport io.github.muntashirakon.AppManager.server.common.BaseCaller;\nimport io.github.muntashirakon.AppManager.server.common.Caller;\nimport io.github.muntashirakon.AppManager.server.common.CallerResult;\nimport io.github.muntashirakon.AppManager.server.common.Constants;\nimport io.github.muntashirakon.AppManager.server.common.DataTransmission;\nimport io.github.muntashirakon.AppManager.server.common.ParcelableUtil;\nimport io.github.muntashirakon.AppManager.settings.Ops;\nimport io.github.muntashirakon.adb.AdbPairingRequiredException;\nimport io.github.muntashirakon.adb.AdbStream;\nimport io.github.muntashirakon.io.IoUtils;\n\n// Copyright 2016 Zheng Li\nclass LocalServerManager {\n    private static final String TAG = \"LocalServerManager\";\n\n    @SuppressLint(\"StaticFieldLeak\")\n    private static LocalServerManager sLocalServerManager;\n\n    @AnyThread\n    @NoOps\n    @NonNull\n    static LocalServerManager getInstance(@NonNull Context context) {\n        synchronized (LocalServerManager.class) {\n            if (sLocalServerManager == null) {\n                sLocalServerManager = new LocalServerManager(context);\n            }\n        }\n        return sLocalServerManager;\n    }\n\n    private final Object mLock = new Object();\n    @NonNull\n    private final Context mContext;\n    @Nullable\n    private ClientSession mSession;\n\n    @AnyThread\n    private LocalServerManager(@NonNull Context context) {\n        mContext = context;\n    }\n\n    /**\n     * Get current session. If no session is running, create a new one. If no server is running,\n     * create one first.\n     *\n     * @return Currently running session\n     * @throws IOException When creating session fails or server couldn't be started\n     */\n    @WorkerThread\n    @NonNull\n    @NoOps(used = true)\n    private ClientSession getSession() throws IOException, AdbPairingRequiredException {\n        synchronized (mLock) {\n            if (mSession == null || !mSession.isRunning()) {\n                try {\n                    mSession = createSession();\n                } catch (Exception e) {\n                    if (!Ops.isDirectRoot() && !Ops.isAdb()) {\n                        // Do not bother attempting to create a new session\n                        throw new IOException(\"Could not create session\", e);\n                    }\n                }\n                if (mSession == null) {\n                    try {\n                        startServer();\n                    } catch (AdbPairingRequiredException e) {\n                        throw e;\n                    } catch (Exception e) {\n                        throw new IOException(\"Could not start server\", e);\n                    }\n                    mSession = createSession();\n                }\n            }\n            return mSession;\n        }\n    }\n\n    @AnyThread\n    public boolean isRunning() {\n        return mSession != null && mSession.isRunning();\n    }\n\n    /**\n     * Close client session\n     */\n    @AnyThread\n    void closeSession() {\n        IoUtils.closeQuietly(mSession);\n        mSession = null;\n    }\n\n    /**\n     * Stop ADB and then close client session\n     */\n    void stop() {\n        IoUtils.closeQuietly(mAdbStream);\n        IoUtils.closeQuietly(mSession);\n        mAdbStream = null;\n        mSession = null;\n    }\n\n    @WorkerThread\n    @NoOps(used = true)\n    void start() throws IOException, AdbPairingRequiredException {\n        getSession();\n    }\n\n    @WorkerThread\n    @NonNull\n    private DataTransmission getSessionDataTransmission() throws IOException {\n        try {\n            return getSession().getDataTransmission();\n        } catch (AdbPairingRequiredException e) {\n            throw new IOException(e);\n        }\n    }\n\n    @WorkerThread\n    @NonNull\n    private byte[] execPre(@NonNull byte[] params) throws IOException {\n        try {\n            return getSessionDataTransmission().sendAndReceiveMessage(params);\n        } catch (IOException e) {\n            if (e.getMessage() != null && e.getMessage().contains(\"pipe\")) {\n                closeSession();\n                return getSessionDataTransmission().sendAndReceiveMessage(params);\n            }\n            throw e;\n        }\n    }\n\n    @WorkerThread\n    CallerResult execNew(@NonNull Caller caller) throws IOException {\n        byte[] result = execPre(ParcelableUtil.marshall(new BaseCaller(caller.wrapParameters())));\n        return ParcelableUtil.unmarshall(result, CallerResult.CREATOR);\n    }\n\n    @WorkerThread\n    void closeBgServer() throws IOException {\n        try {\n            BaseCaller baseCaller = new BaseCaller(BaseCaller.TYPE_CLOSE);\n            getSession().getDataTransmission().sendAndReceiveMessage(ParcelableUtil.marshall(baseCaller));\n        } catch (Exception e) {\n            // Since the server is closed abruptly, this should always produce error\n            Log.w(TAG, \"closeBgServer: Error\", e);\n        }\n        // Check if the server is still active\n        if (LocalServer.alive(mContext)) {\n            // Server still active, need to run killall am_local_server\n            try {\n                stopServer();\n            } catch (Exception e) {\n                throw new IOException(e);\n            }\n        }\n    }\n\n    @Nullable\n    private volatile AdbStream mAdbStream;\n    private volatile CountDownLatch mAdbConnectionWatcher = new CountDownLatch(1);\n    private volatile boolean mAdbServerStarted;\n    private final Runnable mAdbOutputThread = () -> {\n        try (BufferedReader reader = new BufferedReader(new InputStreamReader(Objects.requireNonNull(mAdbStream).openInputStream()))) {\n            String s;\n            while ((s = reader.readLine()) != null) {\n                Log.d(TAG, \"RESPONSE: %s\", s);\n                if (s.startsWith(\"Success!\")) {\n                    mAdbServerStarted = true;\n                    mAdbConnectionWatcher.countDown();\n                    break;\n                } else if (s.startsWith(\"Error!\")) {\n                    mAdbServerStarted = false;\n                    mAdbConnectionWatcher.countDown();\n                    break;\n                }\n            }\n        } catch (Throwable e) {\n            Log.e(TAG, \"useAdbStartServer: unable to read from shell.\", e);\n        }\n    };\n\n    @WorkerThread\n    private void useAdbStartServer() throws Exception {\n        if (mAdbStream == null || Objects.requireNonNull(mAdbStream).isClosed()) {\n            // ADB shell not running\n            String adbHost = ServerConfig.getAdbHost(mContext);\n            int adbPort = ServerConfig.getAdbPort();\n            AdbConnectionManager manager = AdbConnectionManager.getInstance();\n            Log.d(TAG, \"useAdbStartServer: Connecting using host=%s, port=%d\", adbHost, adbPort);\n            manager.setTimeout(10, TimeUnit.SECONDS);\n            if (!manager.isConnected() && !manager.connect(adbHost, adbPort)) {\n                throw new IOException(\"Could not connect to ADB.\");\n            }\n\n            Log.d(TAG, \"useAdbStartServer: Opening shell...\");\n            mAdbStream = manager.openStream(\"shell:\");\n            mAdbConnectionWatcher = new CountDownLatch(1);\n            mAdbServerStarted = false;\n            new Thread(mAdbOutputThread).start();\n        }\n        Log.d(TAG, \"useAdbStartServer: Shell opened.\");\n\n        try (OutputStream os = Objects.requireNonNull(mAdbStream).openOutputStream()) {\n            os.write(\"id\\n\".getBytes());\n            // ADB may require a fallback method\n            String command = ServerConfig.getServerRunnerAdbCommand();\n            Log.d(TAG, \"useAdbStartServer: %s\", command);\n            os.write((command + \"\\n\").getBytes());\n        }\n\n        if (!mAdbConnectionWatcher.await(1, TimeUnit.MINUTES) || !mAdbServerStarted) {\n            throw new Exception(\"Server wasn't started.\");\n        }\n        Log.d(TAG, \"useAdbStartServer: Server has started.\");\n    }\n\n    @WorkerThread\n    private void useRootStartServer() throws Exception {\n        if (!Ops.hasRoot()) {\n            throw new Exception(\"Root access denied\");\n        }\n        String command = ServerConfig.getServerRunnerCommand(0);\n        // + \"\\n\" + \"supolicy --live 'allow qti_init_shell zygote_exec file execute'\";\n        Log.d(TAG, \"useRootStartServer: %s\", command);\n        Runner.Result result = Runner.runCommand(command);\n\n        Log.d(TAG, \"useRootStartServer: %s\", result.getOutput());\n        if (!result.isSuccessful()) {\n            throw new Exception(\"Could not start server.\");\n        }\n        SystemClock.sleep(3000);\n        Log.e(TAG, \"useRootStartServer: Server has started.\");\n    }\n\n    /**\n     * Start root or ADB server based on config\n     */\n    @WorkerThread\n    @NoOps(used = true)\n    private void startServer() throws Exception {\n        if (Ops.isAdb()) {\n            useAdbStartServer();\n        } else if (Ops.isDirectRoot()) {\n            useRootStartServer();\n        } else throw new Exception(\"Neither root nor ADB mode is enabled.\");\n    }\n\n    /**\n     * Stop root or ADB server based on config\n     */\n    @WorkerThread\n    @NoOps(used = true)\n    private void stopServer() throws Exception {\n        String command = \"killall \" + Constants.SERVER_NAME;\n        if (Ops.isAdb()) {\n            if (mAdbStream == null || Objects.requireNonNull(mAdbStream).isClosed()) {\n                // ADB shell not running\n                String adbHost = ServerConfig.getAdbHost(mContext);\n                int adbPort = ServerConfig.getAdbPort();\n                AdbConnectionManager manager = AdbConnectionManager.getInstance();\n                Log.d(TAG, \"stopServer (ADB): Connecting using host=%s, port=%d\", adbHost, adbPort);\n                manager.setTimeout(10, TimeUnit.SECONDS);\n                if (!manager.isConnected() && !manager.connect(adbHost, adbPort)) {\n                    throw new IOException(\"Could not connect to ADB.\");\n                }\n\n                Log.d(TAG, \"stopServer (ADB): Opening shell...\");\n                mAdbStream = manager.openStream(\"shell:\");\n                mAdbConnectionWatcher = new CountDownLatch(1);\n                mAdbServerStarted = false;\n                new Thread(mAdbOutputThread).start();\n            }\n            Log.d(TAG, \"stopServer (ADB): Shell opened.\");\n\n            try (OutputStream os = Objects.requireNonNull(mAdbStream).openOutputStream()) {\n                os.write(\"id\\n\".getBytes());\n                Log.d(TAG, \"stopServer (ADB): %s\", command);\n                os.write((command + \"\\n\").getBytes());\n            }\n\n            if (!mAdbConnectionWatcher.await(1, TimeUnit.MINUTES) || !mAdbServerStarted) {\n                throw new Exception(\"Server wasn't stopped.\");\n            }\n            Log.d(TAG, \"useAdbStartServer: Server has stopped.\");\n        } else if (Ops.isDirectRoot()) {\n            if (!Ops.hasRoot()) {\n                throw new Exception(\"Root access denied\");\n            }\n            Log.d(TAG, \"stopServer (root): %s\", command);\n            Runner.Result result = Runner.runCommand(command);\n            Log.d(TAG, \"stopServer (root): %s\", result.getOutput());\n            if (!result.isSuccessful()) {\n                throw new Exception(\"Could not start server.\");\n            }\n            SystemClock.sleep(3000);\n            Log.e(TAG, \"useRootStartServer: Server has started.\");\n        } else throw new Exception(\"Neither root nor ADB mode is enabled.\");\n    }\n\n    /**\n     * Create a client session\n     *\n     * @return New session if not running, running session otherwise\n     * @throws IOException If session creation failed\n     */\n    @WorkerThread\n    @NonNull\n    @NoOps(used = true)\n    private ClientSession createSession() throws IOException {\n        if (isRunning()) {\n            // Non-null check has already been done\n            return Objects.requireNonNull(mSession);\n        }\n        String host = ServerConfig.getLocalServerHost(mContext);\n        int port = ServerConfig.getLocalServerPort();\n        Socket socket = new Socket(host, port);\n        socket.setSoTimeout(30_000);\n        // NOTE: (CWE-319) No need for SSL since it only runs on a random port in localhost with specific authorization.\n        // TODO: 5/8/23 We could use an SSL server with a randomly generated certificate per session without requiring\n        //  any other authorization methods. This session is independent of the application.\n        OutputStream os = socket.getOutputStream();\n        InputStream is = socket.getInputStream();\n        DataTransmission transfer = new DataTransmission(os, is, false);\n        transfer.shakeHands(ServerConfig.getLocalToken(), DataTransmission.Role.Client);\n        return new ClientSession(socket, transfer);\n    }\n\n    /**\n     * The client session handler\n     */\n    private static class ClientSession implements AutoCloseable {\n        private volatile boolean mIsRunning;\n        @NonNull\n        private final Socket mSocket;\n        @NonNull\n        private final DataTransmission mDataTransmission;\n\n        @AnyThread\n        ClientSession(@NonNull Socket socket, @NonNull DataTransmission dataTransmission) {\n            mSocket = socket;\n            mDataTransmission = dataTransmission;\n            mIsRunning = true;\n        }\n\n        /**\n         * Close the session, stop any active transmission\n         */\n        @AnyThread\n        @Override\n        public void close() throws IOException {\n            if (mIsRunning) {\n                mIsRunning = false;\n                mDataTransmission.close();\n                mSocket.close();\n            }\n        }\n\n        /**\n         * Whether the client session is running\n         */\n        @AnyThread\n        boolean isRunning() {\n            return mIsRunning;\n        }\n\n        @AnyThread\n        @NonNull\n        DataTransmission getDataTransmission() {\n            return mDataTransmission;\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/servermanager/ServerConfig.java",
    "content": "// SPDX-License-Identifier: MIT AND GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.servermanager;\n\nimport android.annotation.SuppressLint;\nimport android.content.Context;\nimport android.content.SharedPreferences;\nimport android.os.Build;\nimport android.provider.Settings;\nimport android.text.TextUtils;\n\nimport androidx.annotation.AnyThread;\nimport androidx.annotation.IntRange;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.WorkerThread;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.net.Inet4Address;\nimport java.security.SecureRandom;\n\nimport io.github.muntashirakon.AppManager.BuildConfig;\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.logs.Log;\nimport io.github.muntashirakon.AppManager.misc.NoOps;\nimport io.github.muntashirakon.AppManager.server.common.Constants;\nimport io.github.muntashirakon.AppManager.settings.Prefs;\nimport io.github.muntashirakon.AppManager.utils.ContextUtils;\nimport io.github.muntashirakon.AppManager.utils.FileUtils;\n\n// Copyright 2016 Zheng Li\npublic final class ServerConfig {\n    public static final String TAG = ServerConfig.class.getSimpleName();\n\n    public static final int DEFAULT_ADB_PORT = 5555;\n    static final String SERVER_RUNNER_EXEC_NAME = \"run_server.sh\";\n    private static final String LOCAL_TOKEN = \"l_token\";\n    private static final File[] SERVER_RUNNER_EXEC = new File[2];\n    private static final File[] SERVER_RUNNER_JAR = new File[2];\n    private static final SharedPreferences sPreferences = ContextUtils.getContext()\n            .getSharedPreferences(\"server_config\", Context.MODE_PRIVATE);\n    private static volatile boolean sInitialised = false;\n\n    @WorkerThread\n    @NoOps\n    public static void init(@NonNull Context context) throws IOException {\n        if (sInitialised) {\n            return;\n        }\n\n        // Setup paths\n        File externalCachePath = FileUtils.getExternalCachePath(context);\n        File externalMediaPath = FileUtils.getExternalMediaPath(context);\n        File deStorage = ContextUtils.getDeContext(context).getCacheDir();\n        SERVER_RUNNER_EXEC[0] = new File(externalCachePath, SERVER_RUNNER_EXEC_NAME);\n        SERVER_RUNNER_EXEC[1] = new File(deStorage, SERVER_RUNNER_EXEC_NAME);\n        SERVER_RUNNER_JAR[0] = new File(externalCachePath, Constants.JAR_NAME);\n        SERVER_RUNNER_JAR[1] = new File(deStorage, Constants.JAR_NAME);\n        // Copy JAR\n        boolean force = BuildConfig.DEBUG;\n        AssetsUtils.copyFile(context, Constants.JAR_NAME, SERVER_RUNNER_JAR[0], force);\n        AssetsUtils.copyFile(context, Constants.JAR_NAME, SERVER_RUNNER_JAR[1], force);\n        // Write script\n        AssetsUtils.writeServerExecScript(context, SERVER_RUNNER_EXEC[0], SERVER_RUNNER_JAR[0].getAbsolutePath());\n        AssetsUtils.writeServerExecScript(context, SERVER_RUNNER_EXEC[1], SERVER_RUNNER_JAR[1].getAbsolutePath());\n        // Update permission\n        FileUtils.chmod711(deStorage);\n        FileUtils.chmod644(SERVER_RUNNER_JAR[1]);\n        FileUtils.chmod644(SERVER_RUNNER_EXEC[1]);\n\n        sInitialised = true;\n    }\n\n    @AnyThread\n    @NonNull\n    public static File getDestJarFile() {\n        // For compatibility only\n        return SERVER_RUNNER_JAR[0];\n    }\n\n    @AnyThread\n    @NonNull\n    public static String getServerRunnerCommand(int index) throws IndexOutOfBoundsException {\n        Log.e(TAG, \"Classpath: %s\", SERVER_RUNNER_JAR[index]);\n        Log.e(TAG, \"Exec path: %s\", SERVER_RUNNER_EXEC[index]);\n        return \"sh \" + SERVER_RUNNER_EXEC[index] + \" \" + getLocalServerPort() + \" \" + getLocalToken();\n    }\n\n    @AnyThread\n    @NonNull\n    public static String getServerRunnerAdbCommand() throws IndexOutOfBoundsException {\n        return getServerRunnerCommand(0) + \" || \" + getServerRunnerCommand(1);\n    }\n\n    /**\n     * Get existing or generate new 16-digit token for client session\n     *\n     * @return Existing or new token\n     */\n    @AnyThread\n    @NonNull\n    public static String getLocalToken() {\n        String token = sPreferences.getString(LOCAL_TOKEN, null);\n        if (TextUtils.isEmpty(token)) {\n            token = generateToken();\n            sPreferences.edit().putString(LOCAL_TOKEN, token).apply();\n        }\n        return token;\n    }\n\n    @AnyThread\n    public static boolean getAllowBgRunning() {\n        return sPreferences.getBoolean(\"allow_bg_running\", true);\n    }\n\n    @AnyThread\n    @IntRange(from = 0, to = 65535)\n    @NoOps\n    public static int getAdbPort() {\n        return sPreferences.getInt(\"adb_port\", DEFAULT_ADB_PORT);\n    }\n\n    @AnyThread\n    @NoOps\n    public static void setAdbPort(@IntRange(from = 0, to = 65535) int port) {\n        sPreferences.edit().putInt(\"adb_port\", port).apply();\n    }\n\n    @AnyThread\n    public static int getLocalServerPort() {\n        return Prefs.Misc.getAdbLocalServerPort();\n    }\n\n    @WorkerThread\n    @NonNull\n    public static String getAdbHost(Context context) {\n        return getHostIpAddress(context);\n    }\n\n    @WorkerThread\n    @NonNull\n    public static String getLocalServerHost(Context context) {\n        String ipAddress = Inet4Address.getLoopbackAddress().getHostAddress();\n        if (ipAddress == null || ipAddress.equals(\"::1\")) return \"127.0.0.1\";\n        return ipAddress;\n    }\n\n    @WorkerThread\n    @NonNull\n    private static String getHostIpAddress(@NonNull Context context) {\n        if (isEmulator(context)) return \"10.0.2.2\";\n        String ipAddress = Inet4Address.getLoopbackAddress().getHostAddress();\n        if (ipAddress == null || ipAddress.equals(\"::1\")) return \"127.0.0.1\";\n        return ipAddress;\n    }\n\n    // https://github.com/firebase/firebase-android-sdk/blob/7d86138304a6573cbe2c61b66b247e930fa05767/firebase-crashlytics/src/main/java/com/google/firebase/crashlytics/internal/common/CommonUtils.java#L402\n    private static final String GOLDFISH = \"goldfish\";\n    private static final String RANCHU = \"ranchu\";\n    private static final String SDK = \"sdk\";\n\n    private static boolean isEmulator(@NonNull Context context) {\n        @SuppressLint(\"HardwareIds\")\n        String androidId = Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ANDROID_ID);\n        return Build.PRODUCT.contains(SDK)\n                || Build.HARDWARE.contains(GOLDFISH)\n                || Build.HARDWARE.contains(RANCHU)\n                || androidId == null;\n    }\n\n\n    @AnyThread\n    @NonNull\n    private static String generateToken() {\n        Context context = ContextUtils.getContext();\n        String[] wordList = context.getResources().getStringArray(R.array.word_list);\n        SecureRandom secureRandom = new SecureRandom();\n        String[] tokenItems = new String[3 + secureRandom.nextInt(3)];\n        for (int i = 0; i < tokenItems.length; ++i) {\n            tokenItems[i] = wordList[secureRandom.nextInt(wordList.length)];\n        }\n        return TextUtils.join(\"-\", tokenItems);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/servermanager/ServerStatusChangeReceiver.java",
    "content": "// SPDX-License-Identifier: MIT\n\npackage io.github.muntashirakon.AppManager.servermanager;\n\nimport android.content.BroadcastReceiver;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.os.Process;\nimport android.os.RemoteException;\nimport android.os.SystemClock;\n\nimport androidx.annotation.AnyThread;\nimport androidx.annotation.NonNull;\n\nimport java.io.IOException;\n\nimport io.github.muntashirakon.AppManager.ipc.LocalServices;\nimport io.github.muntashirakon.AppManager.logs.Log;\nimport io.github.muntashirakon.AppManager.server.common.ConfigParams;\nimport io.github.muntashirakon.AppManager.server.common.ServerActions;\nimport io.github.muntashirakon.AppManager.settings.Ops;\nimport io.github.muntashirakon.AppManager.utils.ThreadUtils;\nimport io.github.muntashirakon.adb.AdbPairingRequiredException;\n\n// Copyright 2016 Zheng Li\npublic class ServerStatusChangeReceiver extends BroadcastReceiver {\n    private static final String TAG = ServerStatusChangeReceiver.class.getSimpleName();\n\n    @Override\n    public void onReceive(Context context, @NonNull Intent intent) {\n        String action = intent.getAction();\n        if (action == null) {\n            return;\n        }\n        // Verify token before doing action\n        String token = intent.getStringExtra(ConfigParams.PARAM_TOKEN);\n        if (!ServerConfig.getLocalToken().equals(token)) {\n            Log.d(TAG, \"Mismatch token. Expected: %s, Received: %s\", ServerConfig.getLocalToken(), token);\n            return;\n        }\n        String uidString = intent.getStringExtra(ConfigParams.PARAM_UID);\n        if (uidString == null) {\n            Log.w(TAG, \"No UID received from the server.\");\n            return;\n        }\n        Log.d(TAG, \"onReceive --> %s %s\", action, uidString);\n        int uid = Integer.parseInt(uidString);\n\n        switch (action) {\n            case ServerActions.ACTION_SERVER_STARTED:\n                // Server was started for the first time\n                Ops.setWorkingUid(uid);\n                startServerIfNotAlready(context);\n                // TODO: 8/4/24 Need to broadcast this message to update UI and/or trigger development\n                break;\n            case ServerActions.ACTION_SERVER_STOPPED:\n                // Server was stopped\n                LocalServer.die();\n                Ops.setWorkingUid(Process.myUid());\n                break;\n            case ServerActions.ACTION_SERVER_CONNECTED:\n                // Server was connected with App Manager\n                Ops.setWorkingUid(uid);\n                break;\n            case ServerActions.ACTION_SERVER_DISCONNECTED:\n                // Exited from App Manager\n                Ops.setWorkingUid(Process.myUid());\n                break;\n        }\n    }\n\n    @AnyThread\n    private void startServerIfNotAlready(@NonNull Context context) {\n        ThreadUtils.postOnBackgroundThread(() -> {\n            try {\n                while (!LocalServer.alive(context)) {\n                    // Server isn't yet in listening mode\n                    Log.w(TAG, \"Waiting for server...\");\n                    SystemClock.sleep(100);\n                }\n                LocalServer.getInstance();\n                LocalServices.bindServicesIfNotAlready();\n            } catch (IOException | AdbPairingRequiredException e) {\n                Log.w(TAG, \"Failed to start server\", e);\n            } catch (RemoteException e) {\n                Log.w(TAG, \"Failed to start services\", e);\n            }\n        });\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/servermanager/WifiWaitService.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.servermanager;\n\nimport android.app.Notification;\nimport android.app.Service;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.net.ConnectivityManager;\nimport android.net.Network;\nimport android.net.NetworkCapabilities;\nimport android.net.NetworkRequest;\nimport android.os.Build;\nimport android.os.IBinder;\nimport android.util.Log;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.RequiresApi;\nimport androidx.annotation.WorkerThread;\nimport androidx.core.app.NotificationCompat;\nimport androidx.core.app.NotificationManagerCompat;\n\nimport io.github.muntashirakon.AppManager.BuildConfig;\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.adb.AdbUtils;\nimport io.github.muntashirakon.AppManager.settings.Ops;\nimport io.github.muntashirakon.AppManager.types.ForegroundService;\nimport io.github.muntashirakon.AppManager.utils.NotificationUtils;\nimport io.github.muntashirakon.AppManager.utils.ThreadUtils;\nimport io.github.muntashirakon.AppManager.utils.Utils;\n\n@RequiresApi(Build.VERSION_CODES.R)\npublic class WifiWaitService extends Service {\n    private static final String TAG = WifiWaitService.class.getSimpleName();\n    public static final String CHANNEL_ID = BuildConfig.APPLICATION_ID + \".channel.WIFI_WAIT_SERVICE\";\n\n    private final ConnectivityManager.NetworkCallback mNetworkCallback = new ConnectivityManager.NetworkCallback() {\n        @Override\n        public void onAvailable(@NonNull Network network) {\n            Log.d(TAG, \"Wi-Fi network available\");\n        }\n\n        @Override\n        public void onLost(@NonNull Network network) {\n            Log.d(TAG, \"Network lost\");\n        }\n\n        @Override\n        public void onCapabilitiesChanged(@NonNull Network network,\n                                          @NonNull NetworkCapabilities networkCapabilities) {\n            // Double-check Wi-Fi availability when capabilities change\n            if (networkCapabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) &&\n                    !mAutoconnectCompleted) {\n                connectAdbWifi();\n                unregisterNetworkCallback();\n            }\n        }\n    };\n    private ConnectivityManager mConnectivityManager;\n    private boolean mAutoconnectCompleted = false;\n    private boolean mUnregisterDone = true;\n\n    @Override\n    public void onCreate() {\n        super.onCreate();\n        NotificationUtils.getNewNotificationManager(this, CHANNEL_ID, \"Wi-Fi Wait Service\",\n                NotificationManagerCompat.IMPORTANCE_LOW);\n        mConnectivityManager = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE);\n    }\n\n    @Override\n    public int onStartCommand(Intent intent, int flags, int startId) {\n        Notification notification = new NotificationCompat.Builder(this, CHANNEL_ID)\n                .setContentTitle(getString(R.string.waiting_for_wifi))\n                .setSmallIcon(android.R.drawable.ic_dialog_info)\n                .setPriority(NotificationCompat.PRIORITY_LOW)\n                .setOngoing(true)\n                .build();\n        ForegroundService.start(this, NotificationUtils.nextNotificationId(null),\n                notification, ForegroundService.FOREGROUND_SERVICE_TYPE_DATA_SYNC\n                        | ForegroundService.FOREGROUND_SERVICE_TYPE_SPECIAL_USE);\n\n        if (LocalServer.alive(getApplicationContext())) {\n            // Already connected\n            mAutoconnectCompleted = true;\n        }\n\n        if (!mAutoconnectCompleted) {\n            registerNetworkCallback();\n        } else {\n            stopSelf();\n        }\n\n        return START_NOT_STICKY; // Don't restart if killed\n    }\n\n    private void registerNetworkCallback() {\n        NetworkRequest networkRequest = new NetworkRequest.Builder()\n                .addTransportType(NetworkCapabilities.TRANSPORT_WIFI)\n                .build();\n        try {\n            mConnectivityManager.registerNetworkCallback(networkRequest, mNetworkCallback);\n            mUnregisterDone = false;\n            Log.d(TAG, \"Network callback registered\");\n        } catch (Exception e) {\n            Log.e(TAG, \"Failed to register network callback\", e);\n            stopSelf();\n        }\n    }\n\n    private void connectAdbWifi() {\n        if (mAutoconnectCompleted) {\n            return; // Prevent multiple executions\n        }\n        mAutoconnectCompleted = true;\n\n        ThreadUtils.postOnBackgroundThread(() -> {\n            try {\n                doConnectAdbWifi();\n            } finally {\n                stopSelf();\n            }\n        });\n    }\n\n    @WorkerThread\n    private void doConnectAdbWifi() {\n        Context context = getApplicationContext();\n        if (!Utils.isWifiActive(context)) {\n            Log.w(TAG, \"Autoconnect failed: Wi-Fi not enabled.\");\n            return;\n        }\n\n        if (!AdbUtils.enableWirelessDebugging(context)) {\n            Log.w(TAG, \"Autoconnect failed: Could not enable wireless debugging.\");\n            return;\n        }\n\n        int status = Ops.autoConnectWirelessDebugging(context);\n        if (status == Ops.STATUS_ADB_PAIRING_REQUIRED) {\n            Log.w(TAG, \"Autoconnect failed: pairing required\");\n        } else if (status == Ops.STATUS_WIRELESS_DEBUGGING_CHOOSER_REQUIRED) {\n            Log.w(TAG, \"Autoconnect failed: could not find a valid port\");\n        } else if (status == Ops.STATUS_FAILURE_ADB_NEED_MORE_PERMS) {\n            Log.w(TAG, \"Autoconnect failed: not enough permissions available\");\n        } else if (status == Ops.STATUS_SUCCESS) {\n            Log.i(TAG, \"Autoconnect success!\");\n        } else {\n            Log.w(TAG, \"Autoconnect failed\");\n        }\n    }\n\n    private void unregisterNetworkCallback() {\n        if (mUnregisterDone) {\n            return;\n        }\n        mUnregisterDone = true;\n        try {\n            mConnectivityManager.unregisterNetworkCallback(mNetworkCallback);\n            Log.d(TAG, \"Network callback unregistered\");\n        } catch (Exception e) {\n            Log.e(TAG, \"Error unregistering callback\", e);\n        }\n    }\n\n    @Nullable\n    @Override\n    public IBinder onBind(Intent intent) {\n        return null;\n    }\n\n    @Override\n    public void onDestroy() {\n        unregisterNetworkCallback();\n        super.onDestroy();\n        Log.d(TAG, \"Service destroyed\");\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/session/SessionMonitoringService.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.session;\n\nimport android.app.PendingIntent;\nimport android.app.Service;\nimport android.content.BroadcastReceiver;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.IntentFilter;\nimport android.os.IBinder;\nimport android.os.Process;\n\nimport androidx.annotation.Nullable;\nimport androidx.core.app.NotificationCompat;\nimport androidx.core.app.NotificationManagerCompat;\nimport androidx.core.app.PendingIntentCompat;\nimport androidx.core.app.ServiceCompat;\nimport androidx.core.content.ContextCompat;\n\nimport java.util.concurrent.Future;\n\nimport io.github.muntashirakon.AppManager.BuildConfig;\nimport io.github.muntashirakon.AppManager.DummyActivity;\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.misc.ScreenLockChecker;\nimport io.github.muntashirakon.AppManager.settings.Prefs;\nimport io.github.muntashirakon.AppManager.types.ForegroundService;\nimport io.github.muntashirakon.AppManager.utils.NotificationUtils;\nimport io.github.muntashirakon.AppManager.utils.ThreadUtils;\n\npublic class SessionMonitoringService extends Service {\n    public static final String TAG = SessionMonitoringService.class.getSimpleName();\n\n    public static final String CHANNEL_ID = BuildConfig.APPLICATION_ID + \".channel.SESSION_MONITOR\";\n\n    public static final String STOP_ACTION = BuildConfig.APPLICATION_ID + \".action.STOP_SESSION_MONITOR\";\n\n    private boolean mIsWorking;\n    @Nullable\n    private Future<?> mCheckLockResult;\n    private ScreenLockChecker mScreenLockChecker;\n    private boolean mScreenLockedReceiverRegistered = false;\n\n    private final BroadcastReceiver mScreenLockedReceiver = new BroadcastReceiver() {\n        @Override\n        public void onReceive(Context context, Intent intent) {\n            try {\n                if (mCheckLockResult != null) {\n                    mCheckLockResult.cancel(true);\n                }\n                mCheckLockResult = ThreadUtils.postOnBackgroundThread(() -> {\n                    if (mScreenLockChecker == null) {\n                        mScreenLockChecker = new ScreenLockChecker(SessionMonitoringService.this, () -> lockScreen());\n                    }\n                    mScreenLockChecker.checkLock();\n                });\n            } catch (Throwable th) {\n                th.printStackTrace();\n            }\n        }\n    };\n\n    public SessionMonitoringService() {\n    }\n\n    @Override\n    public int onStartCommand(Intent intent, int flags, int startId) {\n        if (intent != null && STOP_ACTION.equals(intent.getAction())) {\n            lockScreen();\n            return START_NOT_STICKY;\n        }\n        if (mIsWorking) {\n            return START_NOT_STICKY;\n        }\n        mIsWorking = true;\n        boolean screenLockEnabled = Prefs.Privacy.isScreenLockEnabled();\n        NotificationUtils.getNewNotificationManager(this, CHANNEL_ID, \"Session Monitor\",\n                NotificationManagerCompat.IMPORTANCE_LOW);\n        Intent notificationSettingIntent = NotificationUtils.getNotificationSettingIntent(CHANNEL_ID);\n        PendingIntent defaultIntent = PendingIntentCompat.getActivity(this, 0, notificationSettingIntent, PendingIntent.FLAG_UPDATE_CURRENT, false);\n        Intent stopIntent = new Intent(this, SessionMonitoringService.class).setAction(STOP_ACTION);\n        PendingIntent pendingIntent = PendingIntentCompat.getService(this, 0, stopIntent, PendingIntent.FLAG_ONE_SHOT, false);\n        NotificationCompat.Action stopServiceAction = new NotificationCompat.Action.Builder(null,\n                getString(screenLockEnabled ? R.string.action_lock_app : R.string.action_stop_service), pendingIntent)\n                .setAuthenticationRequired(true)\n                .build();\n        NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID)\n                .setLocalOnly(true)\n                .setOngoing(true)\n                .setOnlyAlertOnce(true)\n                .setSilent(true)\n                .setContentTitle(getString(screenLockEnabled ? R.string.app_manager_is_unlocked : R.string.app_manager_is_running))\n                .setContentText(getString(R.string.tap_to_open_notification_settings))\n                .setSmallIcon(R.drawable.ic_default_notification)\n                .setPriority(NotificationCompat.PRIORITY_LOW)\n                .setContentIntent(defaultIntent)\n                .addAction(stopServiceAction);\n        ForegroundService.start(this, NotificationUtils.nextNotificationId(null), builder.build(),\n                ForegroundService.FOREGROUND_SERVICE_TYPE_DATA_SYNC\n                        | ForegroundService.FOREGROUND_SERVICE_TYPE_SPECIAL_USE);\n        if (screenLockEnabled && Prefs.Privacy.isAutoLockEnabled()) {\n            IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_ON);\n            filter.addAction(Intent.ACTION_SCREEN_OFF);\n            filter.addAction(Intent.ACTION_USER_PRESENT);\n            ContextCompat.registerReceiver(this, mScreenLockedReceiver, filter, ContextCompat.RECEIVER_EXPORTED);\n            mScreenLockedReceiverRegistered = true;\n        }\n        return START_NOT_STICKY;\n    }\n\n    @Nullable\n    @Override\n    public IBinder onBind(Intent intent) {\n        return null;\n    }\n\n    @Override\n    public void onTaskRemoved(Intent rootIntent) {\n        // https://issuetracker.google.com/issues/36967794\n        Intent intent = new Intent(this, DummyActivity.class);\n        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);\n        startActivity(intent);\n    }\n\n    @Override\n    public void onDestroy() {\n        if (mScreenLockedReceiverRegistered) {\n            unregisterReceiver(mScreenLockedReceiver);\n            mScreenLockedReceiverRegistered = false;\n        }\n        ServiceCompat.stopForeground(this, ServiceCompat.STOP_FOREGROUND_REMOVE);\n        super.onDestroy();\n    }\n\n    public void lockScreen() {\n        // Simply stopping the service is enough\n        // TODO: 16/7/23 Wipe memory? Ref: https://github.com/mollyim/mollyim-android/blob/2f8fe769628f7daddc87e8acfab1c4b5d301f728/app/src/main/java/org/thoughtcrime/securesms/service/WipeMemoryService.java#L102\n        stopSelf();\n        Process.killProcess(Process.myPid());\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/settings/AboutDeviceFragment.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.settings;\n\nimport android.os.Build;\nimport android.os.Bundle;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.TextView;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.core.widget.NestedScrollView;\nimport androidx.fragment.app.Fragment;\nimport androidx.lifecycle.ViewModelProvider;\n\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.misc.DeviceInfo2;\nimport io.github.muntashirakon.util.UiUtils;\n\npublic class AboutDeviceFragment extends Fragment {\n    private MainPreferencesViewModel mModel;\n    private TextView mTextView;\n\n    @Override\n    public void onCreate(@Nullable Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        mModel = new ViewModelProvider(requireActivity()).get(MainPreferencesViewModel.class);\n    }\n\n    @Override\n    public void onStart() {\n        super.onStart();\n        requireActivity().setTitle(R.string.about_device);\n    }\n\n    @Nullable\n    @Override\n    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {\n        NestedScrollView view = (NestedScrollView) inflater.inflate(io.github.muntashirakon.ui.R.layout.dialog_scrollable_text_view, container, false);\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {\n            view.setScrollIndicators(0);\n        }\n        ViewGroup.LayoutParams lp = view.getLayoutParams();\n        if (lp instanceof ViewGroup.MarginLayoutParams) {\n            ViewGroup.MarginLayoutParams mlp = (ViewGroup.MarginLayoutParams) lp;\n            mlp.topMargin = 0;\n            view.setLayoutParams(mlp);\n        }\n        boolean secondary = false;\n        if (getArguments() != null) {\n            secondary = requireArguments().getBoolean(PreferenceFragment.PREF_SECONDARY);\n            requireArguments().remove(PreferenceFragment.PREF_KEY);\n            requireArguments().remove(PreferenceFragment.PREF_SECONDARY);\n        }\n        if (secondary) {\n            UiUtils.applyWindowInsetsAsPadding(view, false, true, false, true);\n        } else UiUtils.applyWindowInsetsAsPaddingNoTop(view);\n        return view;\n    }\n\n    @Override\n    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {\n        mTextView = view.findViewById(android.R.id.content);\n        view.findViewById(android.R.id.checkbox).setVisibility(View.GONE);\n        mModel.getDeviceInfo().observe(getViewLifecycleOwner(), deviceInfo ->\n                mTextView.setText(deviceInfo.toLocalizedString(requireActivity())));\n        mModel.loadDeviceInfo(new DeviceInfo2(requireActivity()));\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/settings/AboutPreferences.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.settings;\n\nimport android.content.Intent;\nimport android.net.Uri;\nimport android.os.Bundle;\nimport android.view.View;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.lifecycle.ViewModelProvider;\nimport androidx.preference.Preference;\nimport androidx.recyclerview.widget.LinearLayoutManager;\nimport androidx.recyclerview.widget.RecyclerView;\n\nimport com.google.android.material.transition.MaterialSharedAxis;\n\nimport java.util.Locale;\nimport java.util.Objects;\n\nimport io.github.muntashirakon.AppManager.BuildConfig;\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.changelog.ChangelogRecyclerAdapter;\nimport io.github.muntashirakon.AppManager.misc.HelpActivity;\nimport io.github.muntashirakon.dialog.AlertDialogBuilder;\nimport io.github.muntashirakon.dialog.ScrollableDialogBuilder;\n\npublic class AboutPreferences extends PreferenceFragment {\n    private MainPreferencesViewModel mModel;\n\n    @Override\n    public void onCreatePreferences(@Nullable Bundle savedInstanceState, @Nullable String rootKey) {\n        setPreferencesFromResource(R.xml.preferences_about, rootKey);\n        getPreferenceManager().setPreferenceDataStore(new SettingsDataStore());\n        mModel = new ViewModelProvider(requireActivity()).get(MainPreferencesViewModel.class);\n        Preference versionPref = Objects.requireNonNull(findPreference(\"version\"));\n        versionPref.setSummary(String.format(Locale.getDefault(), \"%s (%d)\", BuildConfig.VERSION_NAME, BuildConfig.VERSION_CODE));\n        versionPref.setOnPreferenceClickListener(preference -> {\n            mModel.loadChangeLog();\n            return true;\n        });\n        // User manual\n        ((Preference) Objects.requireNonNull(findPreference(\"user_manual\")))\n                .setOnPreferenceClickListener(preference -> {\n                    Intent helpIntent = new Intent(requireContext(), HelpActivity.class);\n                    startActivity(helpIntent);\n                    return true;\n                });\n        // Website\n        ((Preference) Objects.requireNonNull(findPreference(\"website\")))\n                .setOnPreferenceClickListener(preference -> {\n                    Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(getString(R.string.website_message)));\n                    startActivity(intent);\n                    return true;\n                });\n        // Get help\n        ((Preference) Objects.requireNonNull(findPreference(\"get_help\")))\n                .setOnPreferenceClickListener(preference -> {\n                    Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(getString(R.string.discussions_site)));\n                    startActivity(intent);\n                    return true;\n                });\n        // Third-party libraries\n        ((Preference) Objects.requireNonNull(findPreference(\"third_party_libraries\")))\n                .setOnPreferenceClickListener(preference -> {\n                    new ScrollableDialogBuilder(requireActivity())\n                            .setTitle(R.string.third_party)\n                            .setMessage(R.string.third_party_message)\n                            .enableAnchors()\n                            .setNegativeButton(R.string.close, null)\n                            .show();\n                    return true;\n                });\n        // Credits\n        ((Preference) Objects.requireNonNull(findPreference(\"credits\")))\n                .setOnPreferenceClickListener(preference -> {\n                    new ScrollableDialogBuilder(requireActivity())\n                            .setTitle(R.string.credits)\n                            .setMessage(R.string.credits_message)\n                            .enableAnchors()\n                            .setNegativeButton(R.string.close, null)\n                            .show();\n                    return true;\n                });\n    }\n\n    @Override\n    public void onCreate(@Nullable Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setEnterTransition(new MaterialSharedAxis(MaterialSharedAxis.Z, true));\n        setReturnTransition(new MaterialSharedAxis(MaterialSharedAxis.Z, false));\n    }\n\n    @Override\n    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {\n        super.onViewCreated(view, savedInstanceState);\n        // Observe Changelog\n        mModel.getChangeLog().observe(getViewLifecycleOwner(), changelog -> {\n            View v = View.inflate(requireContext(), R.layout.dialog_whats_new, null);\n            RecyclerView recyclerView = v.findViewById(android.R.id.list);\n            recyclerView.setLayoutManager(new LinearLayoutManager(recyclerView.getContext()));\n            ChangelogRecyclerAdapter adapter = new ChangelogRecyclerAdapter();\n            recyclerView.setAdapter(adapter);\n            adapter.setAdapterList(changelog.getChangelogItems());\n            new AlertDialogBuilder(requireActivity(), true)\n                    .setTitle(R.string.changelog)\n                    .setView(recyclerView)\n                    .show();\n        });\n    }\n\n    @Override\n    public int getTitle() {\n        return R.string.about;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/settings/AdvancedPreferences.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.settings;\n\nimport android.os.Build;\nimport android.os.Bundle;\nimport android.text.Editable;\nimport android.text.InputType;\nimport android.text.TextUtils;\nimport android.view.View;\nimport android.view.inputmethod.EditorInfo;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.appcompat.app.AlertDialog;\nimport androidx.core.view.inputmethod.EditorInfoCompat;\nimport androidx.fragment.app.DialogFragment;\nimport androidx.lifecycle.ViewModelProvider;\nimport androidx.preference.Preference;\nimport androidx.preference.SwitchPreferenceCompat;\n\nimport com.google.android.material.chip.Chip;\nimport com.google.android.material.chip.ChipGroup;\nimport com.google.android.material.dialog.MaterialAlertDialogBuilder;\nimport com.google.android.material.textfield.TextInputEditText;\nimport com.google.android.material.transition.MaterialSharedAxis;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Objects;\n\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.settings.crypto.ImportExportKeyStoreDialogFragment;\nimport io.github.muntashirakon.AppManager.utils.AppPref;\nimport io.github.muntashirakon.AppManager.utils.ArrayUtils;\nimport io.github.muntashirakon.AppManager.utils.MultithreadedExecutor;\nimport io.github.muntashirakon.AppManager.utils.Utils;\nimport io.github.muntashirakon.dialog.SearchableMultiChoiceDialogBuilder;\nimport io.github.muntashirakon.dialog.TextInputDialogBuilder;\nimport io.github.muntashirakon.util.UiUtils;\n\npublic class AdvancedPreferences extends PreferenceFragment {\n    public static final String[] APK_NAME_FORMATS = new String[]{\n            \"%label%\",\n            \"%package_name%\",\n            \"%version%\",\n            \"%version_code%\",\n            \"%min_sdk%\",\n            \"%target_sdk%\",\n            \"%datetime%\"\n    };\n\n    private int mThreadCount;\n    private MainPreferencesViewModel mModel;\n\n    @Override\n    public void onCreatePreferences(@Nullable Bundle savedInstanceState, @Nullable String rootKey) {\n        setPreferencesFromResource(R.xml.preferences_advanced, rootKey);\n        getPreferenceManager().setPreferenceDataStore(new SettingsDataStore());\n        mModel = new ViewModelProvider(requireActivity()).get(MainPreferencesViewModel.class);\n        // Selected users\n        Preference usersPref = Objects.requireNonNull(findPreference(\"selected_users\"));\n        usersPref.setOnPreferenceClickListener(preference -> {\n            mModel.loadAllUsers();\n            return true;\n        });\n        // Saved apk name format\n        Preference savedApkFormatPref = Objects.requireNonNull(findPreference(\"saved_apk_format\"));\n        savedApkFormatPref.setOnPreferenceClickListener(preference -> {\n            View view = getLayoutInflater().inflate(R.layout.dialog_set_apk_format, null);\n            TextInputEditText inputApkNameFormat = view.findViewById(R.id.input_apk_name_format);\n            inputApkNameFormat.setText(AppPref.getString(AppPref.PrefKey.PREF_SAVED_APK_FORMAT_STR));\n            ChipGroup apkNameFormats = view.findViewById(R.id.apk_name_formats);\n            for (String apkNameFormatStr : APK_NAME_FORMATS) {\n                if (\"%min_sdk%\".equals(apkNameFormatStr) && Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {\n                    // Old devices does not support min SDK\n                    continue;\n                }\n                addChip(apkNameFormats, apkNameFormatStr).setOnClickListener(v -> {\n                    Editable apkFormat = inputApkNameFormat.getText();\n                    if (apkFormat != null) {\n                        apkFormat.insert(inputApkNameFormat.getSelectionStart(), ((Chip) v).getText());\n                    }\n                });\n            }\n            AlertDialog dialog = new MaterialAlertDialogBuilder(requireActivity())\n                    .setTitle(R.string.pref_saved_apk_name_format)\n                    .setView(view)\n                    .setPositiveButton(R.string.save, (dialog1, which) -> {\n                        Editable apkFormat = inputApkNameFormat.getText();\n                        if (!TextUtils.isEmpty(apkFormat)) {\n                            AppPref.set(AppPref.PrefKey.PREF_SAVED_APK_FORMAT_STR, apkFormat.toString().trim());\n                        }\n                    })\n                    .setNegativeButton(R.string.cancel, null)\n                    .create();\n            dialog.setOnShowListener(dialog1 -> inputApkNameFormat.postDelayed(() -> {\n                inputApkNameFormat.requestFocus();\n                inputApkNameFormat.requestFocusFromTouch();\n                inputApkNameFormat.setSelection(inputApkNameFormat.length());\n                UiUtils.showKeyboard(inputApkNameFormat);\n            }, 200));\n            dialog.show();\n            return true;\n        });\n        // Thread count\n        Preference threadCountPref = Objects.requireNonNull(findPreference(\"thread_count\"));\n        mThreadCount = MultithreadedExecutor.getThreadCount();\n        threadCountPref.setSummary(getResources().getQuantityString(R.plurals.pref_thread_count_msg, mThreadCount, mThreadCount));\n        threadCountPref.setOnPreferenceClickListener(preference -> {\n            new TextInputDialogBuilder(requireActivity(), null)\n                    .setTitle(R.string.pref_thread_count)\n                    .setHelperText(getString(R.string.pref_thread_count_hint, Utils.getTotalCores()))\n                    .setInputText(String.valueOf(mThreadCount))\n                    .setInputInputType(InputType.TYPE_CLASS_NUMBER)\n                    .setInputImeOptions(EditorInfo.IME_ACTION_DONE | EditorInfoCompat.IME_FLAG_NO_PERSONALIZED_LEARNING)\n                    .setNegativeButton(R.string.cancel, null)\n                    .setPositiveButton(R.string.save, (dialog, which, inputText, isChecked) -> {\n                        if (inputText != null && TextUtils.isDigitsOnly(inputText)) {\n                            int c = Integer.decode(inputText.toString());\n                            MultithreadedExecutor.setThreadCount(c);\n                            mThreadCount = MultithreadedExecutor.getThreadCount();\n                            threadCountPref.setSummary(getResources().getQuantityString(R.plurals.pref_thread_count_msg, mThreadCount, mThreadCount));\n                        }\n                    })\n                    .show();\n            return true;\n        });\n        // ADB local server port\n        Preference adbLsPort = Objects.requireNonNull(findPreference(\"adb_local_server_port\"));\n        int port = Prefs.Misc.getAdbLocalServerPort();\n        adbLsPort.setSummary(String.valueOf(port));\n        adbLsPort.setOnPreferenceClickListener(pref -> {\n            new TextInputDialogBuilder(requireActivity(), null)\n                    .setTitle(R.string.adb_local_server_port)\n                    .setInputText(String.valueOf(port))\n                    .setInputInputType(InputType.TYPE_CLASS_NUMBER)\n                    .setInputImeOptions(EditorInfo.IME_ACTION_DONE | EditorInfoCompat.IME_FLAG_NO_PERSONALIZED_LEARNING)\n                    .setNegativeButton(R.string.cancel, null)\n                    .setPositiveButton(R.string.save, (dialog, which, inputText, isChecked) -> {\n                        if (inputText != null && TextUtils.isDigitsOnly(inputText)) {\n                            int c = Integer.decode(inputText.toString());\n                            // TODO: 10/18/25 If the port number is different, restart the local server with this new port if possible.\n                            Prefs.Misc.setAdbLocalServerPort(c);\n                            adbLsPort.setSummary(String.valueOf(c));\n                        }\n                    })\n                    .show();\n            return true;\n        });\n        // Import/export App Manager's KeyStore\n        ((Preference) Objects.requireNonNull(findPreference(\"import_export_keystore\")))\n                .setOnPreferenceClickListener(preference -> {\n                    DialogFragment fragment = new ImportExportKeyStoreDialogFragment();\n                    fragment.show(getParentFragmentManager(), ImportExportKeyStoreDialogFragment.TAG);\n                    return true;\n                });\n        // Send notifications to the connected device\n        ((SwitchPreferenceCompat) Objects.requireNonNull(findPreference(\"send_notifications_to_connected_devices\")))\n                .setChecked(Prefs.Misc.sendNotificationsToConnectedDevices());\n    }\n\n    @Override\n    public void onCreate(@Nullable Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setEnterTransition(new MaterialSharedAxis(MaterialSharedAxis.Z, true));\n        setReturnTransition(new MaterialSharedAxis(MaterialSharedAxis.Z, false));\n    }\n\n    @Override\n    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {\n        super.onViewCreated(view, savedInstanceState);\n        mModel.selectUsers().observe(getViewLifecycleOwner(), users -> {\n            if (users == null) return;\n            int[] selectedUsers = Prefs.Misc.getSelectedUsers();\n            Integer[] userIds = new Integer[users.size()];\n            CharSequence[] userInfo = new CharSequence[users.size()];\n            List<Integer> preselectedUserIds = new ArrayList<>();\n            for (int i = 0; i < users.size(); ++i) {\n                userIds[i] = users.get(i).id;\n                userInfo[i] = users.get(i).toLocalizedString(requireContext());\n                if (selectedUsers == null || ArrayUtils.contains(selectedUsers, userIds[i])) {\n                    preselectedUserIds.add(userIds[i]);\n                }\n            }\n            new SearchableMultiChoiceDialogBuilder<>(requireActivity(), userIds, userInfo)\n                    .setTitle(R.string.pref_selected_users)\n                    .addSelections(preselectedUserIds)\n                    .setPositiveButton(R.string.save, (dialog, which, selectedUserIds) -> {\n                        if (!selectedUserIds.isEmpty()) {\n                            Prefs.Misc.setSelectedUsers(ArrayUtils.convertToIntArray(selectedUserIds));\n                        } else Prefs.Misc.setSelectedUsers(null);\n                        Utils.relaunchApp(requireActivity());\n                    })\n                    .setNegativeButton(R.string.cancel, null)\n                    .setNeutralButton(R.string.use_default, (dialog, which, selectedUserIds) -> {\n                        Prefs.Misc.setSelectedUsers(null);\n                        Utils.relaunchApp(requireActivity());\n                    })\n                    .show();\n        });\n    }\n\n    @Override\n    public int getTitle() {\n        return R.string.pref_cat_advanced;\n    }\n\n    @NonNull\n    private static Chip addChip(@NonNull ChipGroup apkFormats, @NonNull CharSequence text) {\n        Chip chip = new Chip(apkFormats.getContext());\n        chip.setText(text);\n        apkFormats.addView(chip);\n        return chip;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/settings/ApkSigningPreferences.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.settings;\n\nimport android.os.Bundle;\nimport android.view.View;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.lifecycle.ViewModelProvider;\nimport androidx.preference.Preference;\nimport androidx.preference.SwitchPreferenceCompat;\n\nimport com.google.android.material.transition.MaterialSharedAxis;\n\nimport java.util.Objects;\n\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.apk.signing.SigSchemes;\nimport io.github.muntashirakon.AppManager.apk.signing.Signer;\nimport io.github.muntashirakon.AppManager.settings.crypto.RSACryptoSelectionDialogFragment;\nimport io.github.muntashirakon.AppManager.utils.DigestUtils;\nimport io.github.muntashirakon.dialog.SearchableFlagsDialogBuilder;\n\npublic class ApkSigningPreferences extends PreferenceFragment {\n    public static final String TAG = \"ApkSigningPreferences\";\n\n    private SettingsActivity mActivity;\n    private Preference mCustomSigPref;\n    private MainPreferencesViewModel mModel;\n\n    @Override\n    public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {\n        setPreferencesFromResource(R.xml.preferences_signature, rootKey);\n        getPreferenceManager().setPreferenceDataStore(new SettingsDataStore());\n        mModel = new ViewModelProvider(requireActivity()).get(MainPreferencesViewModel.class);\n        mActivity = (SettingsActivity) requireActivity();\n        // Set signature schemes\n        Preference sigSchemes = Objects.requireNonNull(findPreference(\"signature_schemes\"));\n        final SigSchemes sigSchemeFlags = Prefs.Signing.getSigSchemes();\n        sigSchemes.setOnPreferenceClickListener(preference -> {\n            new SearchableFlagsDialogBuilder<>(mActivity, sigSchemeFlags.getAllItems(), R.array.sig_schemes, sigSchemeFlags.getFlags())\n                    .setTitle(R.string.app_signing_signature_schemes)\n                    .setPositiveButton(R.string.save, (dialog, which, selections) -> {\n                        int flags = 0;\n                        for (int flag : selections) {\n                            flags |= flag;\n                        }\n                        sigSchemeFlags.setFlags(flags);\n                        Prefs.Signing.setSigSchemes(flags);\n                    })\n                    .setNegativeButton(R.string.cancel, null)\n                    .setNeutralButton(R.string.reset_to_default, (dialog, which, selections) -> {\n                        sigSchemeFlags.setFlags(SigSchemes.DEFAULT_SCHEMES);\n                        Prefs.Signing.setSigSchemes(SigSchemes.DEFAULT_SCHEMES);\n                    })\n                    .show();\n            return true;\n        });\n        mCustomSigPref = Objects.requireNonNull(findPreference(\"signing_keys\"));\n        mCustomSigPref.setOnPreferenceClickListener(preference -> {\n            RSACryptoSelectionDialogFragment fragment = RSACryptoSelectionDialogFragment.getInstance(Signer.SIGNING_KEY_ALIAS);\n            fragment.setOnKeyPairUpdatedListener((keyPair, certificateBytes) -> {\n                if (keyPair != null && certificateBytes != null) {\n                    String hash = DigestUtils.getHexDigest(DigestUtils.SHA_256, certificateBytes);\n                    try {\n                        keyPair.destroy();\n                    } catch (Exception ignore) {\n                    }\n                    mCustomSigPref.setSummary(hash);\n                } else {\n                    mCustomSigPref.setSummary(R.string.key_not_set);\n                }\n            });\n            fragment.show(getParentFragmentManager(), RSACryptoSelectionDialogFragment.TAG);\n            return true;\n        });\n        ((SwitchPreferenceCompat) Objects.requireNonNull(findPreference(\"zip_align\")))\n                .setChecked(Prefs.Signing.zipAlign());\n    }\n\n    @Override\n    public void onCreate(@Nullable Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setEnterTransition(new MaterialSharedAxis(MaterialSharedAxis.Z, true));\n        setReturnTransition(new MaterialSharedAxis(MaterialSharedAxis.Z, false));\n    }\n\n    @Override\n    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {\n        super.onViewCreated(view, savedInstanceState);\n        mModel.getSigningKeySha256HashLiveData().observe(getViewLifecycleOwner(), hash -> {\n            if (hash != null) {\n                mCustomSigPref.setSummary(hash);\n            } else {\n                mCustomSigPref.setSummary(R.string.key_not_set);\n            }\n        });\n        mModel.loadSigningKeySha256Hash();\n    }\n\n    @Override\n    public int getTitle() {\n        return R.string.apk_signing;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/settings/AppearancePreferences.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.settings;\n\nimport android.os.Bundle;\nimport android.view.View;\n\nimport androidx.annotation.Nullable;\nimport androidx.appcompat.app.AppCompatDelegate;\nimport androidx.preference.Preference;\nimport androidx.preference.SwitchPreferenceCompat;\n\nimport com.google.android.material.transition.MaterialSharedAxis;\n\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.Objects;\n\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.utils.appearance.AppearanceUtils;\nimport io.github.muntashirakon.AppManager.utils.appearance.TypefaceUtil;\nimport io.github.muntashirakon.dialog.SearchableFlagsDialogBuilder;\nimport io.github.muntashirakon.dialog.SearchableSingleChoiceDialogBuilder;\n\npublic class AppearancePreferences extends PreferenceFragment {\n    private static final List<Integer> THEME_CONST = Arrays.asList(\n            AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM,\n            AppCompatDelegate.MODE_NIGHT_AUTO_BATTERY,\n            AppCompatDelegate.MODE_NIGHT_NO,\n            AppCompatDelegate.MODE_NIGHT_YES);\n    private static final List<Integer> LAYOUT_ORIENTATION_CONST = Arrays.asList(\n            View.LAYOUT_DIRECTION_LOCALE,\n            View.LAYOUT_DIRECTION_LTR,\n            View.LAYOUT_DIRECTION_RTL);\n\n    private int mCurrentTheme;\n    private int mCurrentLayoutDirection;\n\n    @Override\n    public void onCreatePreferences(@Nullable Bundle savedInstanceState, @Nullable String rootKey) {\n        setPreferencesFromResource(R.xml.preferences_appearance, rootKey);\n        getPreferenceManager().setPreferenceDataStore(new SettingsDataStore());\n        // App theme\n        final String[] themes = getResources().getStringArray(R.array.themes);\n        mCurrentTheme = Prefs.Appearance.getNightMode();\n        Preference appTheme = Objects.requireNonNull(findPreference(\"app_theme\"));\n        appTheme.setSummary(themes[THEME_CONST.indexOf(mCurrentTheme)]);\n        appTheme.setOnPreferenceClickListener(preference -> {\n            new SearchableSingleChoiceDialogBuilder<>(requireActivity(), THEME_CONST, themes)\n                    .setTitle(R.string.select_theme)\n                    .setSelection(mCurrentTheme)\n                    .setPositiveButton(R.string.apply, (dialog, which, selectedTheme) -> {\n                        if (selectedTheme != null && selectedTheme != mCurrentTheme) {\n                            mCurrentTheme = selectedTheme;\n                            Prefs.Appearance.setNightMode(mCurrentTheme);\n                            AppCompatDelegate.setDefaultNightMode(mCurrentTheme);\n                        }\n                    })\n                    .setNegativeButton(R.string.cancel, null)\n                    .show();\n            return true;\n        });\n        // Black theme/custom theme\n        SwitchPreferenceCompat fullBlackTheme = Objects.requireNonNull(findPreference(\"app_theme_pure_black\"));\n        fullBlackTheme.setChecked(Prefs.Appearance.isPureBlackTheme());\n        fullBlackTheme.setOnPreferenceChangeListener((preference, newValue) -> {\n            boolean enabled = (boolean) newValue;\n            Prefs.Appearance.setPureBlackTheme(enabled);\n            AppearanceUtils.applyConfigurationChangesToActivities();\n            return true;\n        });\n        // Black theme/custom theme\n        SwitchPreferenceCompat useSystemFontPref = Objects.requireNonNull(findPreference(\"use_system_font\"));\n        useSystemFontPref.setChecked(Prefs.Appearance.useSystemFont());\n        useSystemFontPref.setOnPreferenceChangeListener((preference, newValue) -> {\n            if (((boolean) newValue)) {\n                // Enable system font\n                TypefaceUtil.replaceFontsWithSystem(requireContext());\n            } else {\n                // Disable system font\n                TypefaceUtil.restoreFonts();\n            }\n            AppearanceUtils.applyConfigurationChangesToActivities();\n            return true;\n        });\n        // Layout orientation\n        final String[] layoutOrientations = getResources().getStringArray(R.array.layout_orientations);\n        mCurrentLayoutDirection = Prefs.Appearance.getLayoutDirection();\n        Preference layoutOrientation = Objects.requireNonNull(findPreference(\"layout_orientation\"));\n        layoutOrientation.setSummary(layoutOrientations[LAYOUT_ORIENTATION_CONST.indexOf(mCurrentLayoutDirection)]);\n        layoutOrientation.setOnPreferenceClickListener(preference -> {\n            new SearchableSingleChoiceDialogBuilder<>(requireActivity(), LAYOUT_ORIENTATION_CONST, layoutOrientations)\n                    .setTitle(R.string.pref_layout_direction)\n                    .setSelection(mCurrentLayoutDirection)\n                    .setPositiveButton(R.string.apply, (dialog, which, selectedLayoutOrientation) -> {\n                        mCurrentLayoutDirection = Objects.requireNonNull(selectedLayoutOrientation);\n                        Prefs.Appearance.setLayoutDirection(mCurrentLayoutDirection);\n                        AppearanceUtils.applyConfigurationChangesToActivities();\n                    })\n                    .setNegativeButton(R.string.cancel, null)\n                    .show();\n            return true;\n        });\n        // Enable/disable features\n        FeatureController fc = FeatureController.getInstance();\n        ((Preference) Objects.requireNonNull(findPreference(\"enabled_features\")))\n                .setOnPreferenceClickListener(preference -> {\n                    new SearchableFlagsDialogBuilder<>(requireActivity(), FeatureController.featureFlags, FeatureController.getFormattedFlagNames(requireActivity()), fc.getFlags())\n                            .setTitle(R.string.enable_disable_features)\n                            .setOnMultiChoiceClickListener((dialog, which, item, isChecked) ->\n                                    fc.modifyState(FeatureController.featureFlags.get(which), isChecked))\n                            .setNegativeButton(R.string.close, null)\n                            .show();\n                    return true;\n                });\n    }\n\n    @Override\n    public void onCreate(@Nullable Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setEnterTransition(new MaterialSharedAxis(MaterialSharedAxis.Z, true));\n        setReturnTransition(new MaterialSharedAxis(MaterialSharedAxis.Z, false));\n    }\n\n    @Override\n    public int getTitle() {\n        return R.string.pref_cat_appearance;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/settings/BackupRestorePreferences.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.settings;\n\nimport static io.github.muntashirakon.AppManager.utils.UIUtils.getSecondaryText;\nimport static io.github.muntashirakon.AppManager.utils.UIUtils.getSmallerText;\n\nimport android.app.Activity;\nimport android.content.Intent;\nimport android.net.Uri;\nimport android.os.Bundle;\nimport android.text.SpannableStringBuilder;\nimport android.view.View;\n\nimport androidx.activity.result.ActivityResultLauncher;\nimport androidx.activity.result.contract.ActivityResultContracts;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.StringRes;\nimport androidx.annotation.UiThread;\nimport androidx.appcompat.app.AlertDialog;\nimport androidx.collection.ArrayMap;\nimport androidx.core.content.ContextCompat;\nimport androidx.fragment.app.DialogFragment;\nimport androidx.lifecycle.ViewModelProvider;\nimport androidx.preference.Preference;\nimport androidx.preference.SwitchPreferenceCompat;\n\nimport com.google.android.material.dialog.MaterialAlertDialogBuilder;\nimport com.google.android.material.transition.MaterialSharedAxis;\n\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Objects;\nimport java.util.concurrent.atomic.AtomicReference;\n\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.backup.BackupFlags;\nimport io.github.muntashirakon.AppManager.backup.BackupUtils;\nimport io.github.muntashirakon.AppManager.backup.CryptoUtils;\nimport io.github.muntashirakon.AppManager.backup.convert.ImportType;\nimport io.github.muntashirakon.AppManager.batchops.BatchOpsManager;\nimport io.github.muntashirakon.AppManager.batchops.BatchOpsService;\nimport io.github.muntashirakon.AppManager.batchops.BatchQueueItem;\nimport io.github.muntashirakon.AppManager.batchops.struct.BatchBackupImportOptions;\nimport io.github.muntashirakon.AppManager.crypto.RSACrypto;\nimport io.github.muntashirakon.AppManager.settings.crypto.AESCryptoSelectionDialogFragment;\nimport io.github.muntashirakon.AppManager.settings.crypto.ECCCryptoSelectionDialogFragment;\nimport io.github.muntashirakon.AppManager.settings.crypto.OpenPgpKeySelectionDialogFragment;\nimport io.github.muntashirakon.AppManager.settings.crypto.RSACryptoSelectionDialogFragment;\nimport io.github.muntashirakon.dialog.DialogTitleBuilder;\nimport io.github.muntashirakon.dialog.SearchableItemsDialogBuilder;\nimport io.github.muntashirakon.dialog.SearchableMultiChoiceDialogBuilder;\nimport io.github.muntashirakon.dialog.SearchableSingleChoiceDialogBuilder;\nimport io.github.muntashirakon.io.Paths;\n\npublic class BackupRestorePreferences extends PreferenceFragment {\n    private static final String[] ENCRYPTION = new String[]{\n            CryptoUtils.MODE_NO_ENCRYPTION,\n            CryptoUtils.MODE_OPEN_PGP,\n            CryptoUtils.MODE_AES,\n            CryptoUtils.MODE_RSA,\n            CryptoUtils.MODE_ECC\n    };\n    @StringRes\n    private static final Integer[] ENCRYPTION_NAMES = new Integer[]{\n            R.string.none,\n            R.string.open_pgp_provider,\n            R.string.aes,\n            R.string.rsa,\n            R.string.ecc,\n    };\n\n    private SettingsActivity mActivity;\n    private String mCurrentCompressionMethod;\n    private Uri mBackupVolume;\n    @ImportType\n    private int mImportType;\n    private boolean mDeleteBackupsAfterImport;\n    private MainPreferencesViewModel mModel;\n\n    private final ActivityResultLauncher<Intent> mSafSelectBackupVolume = registerForActivityResult(\n            new ActivityResultContracts.StartActivityForResult(),\n            result -> {\n                try {\n                    if (result.getResultCode() != Activity.RESULT_OK) return;\n                    Intent data = result.getData();\n                    if (data == null) return;\n                    Uri treeUri = data.getData();\n                    if (treeUri == null) return;\n                    int takeFlags = data.getFlags() & (Intent.FLAG_GRANT_READ_URI_PERMISSION\n                            | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);\n                    requireContext().getContentResolver().takePersistableUriPermission(treeUri, takeFlags);\n                } finally {\n                    // Display backup volumes again\n                    mModel.loadStorageVolumes();\n                }\n            });\n    private final ActivityResultLauncher<Intent> mSafSelectImportDirectory = registerForActivityResult(\n            new ActivityResultContracts.StartActivityForResult(),\n            result -> {\n                if (result.getResultCode() != Activity.RESULT_OK) return;\n                Intent data = result.getData();\n                if (data == null) return;\n                Uri treeUri = data.getData();\n                if (treeUri == null) return;\n                int takeFlags = data.getFlags() & (Intent.FLAG_GRANT_READ_URI_PERMISSION\n                        | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);\n                requireContext().getContentResolver().takePersistableUriPermission(treeUri, takeFlags);\n                startImportOperation(mImportType, treeUri, mDeleteBackupsAfterImport);\n            });\n\n    @Override\n    public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {\n        setPreferencesFromResource(R.xml.preferences_backup_restore, rootKey);\n        getPreferenceManager().setPreferenceDataStore(new SettingsDataStore());\n        mModel = new ViewModelProvider(requireActivity()).get(MainPreferencesViewModel.class);\n        mActivity = (SettingsActivity) requireActivity();\n        // Backup compression method\n        mCurrentCompressionMethod = Prefs.BackupRestore.getCompressionMethod();\n        Preference compressionMethod = Objects.requireNonNull(findPreference(\"backup_compression_method\"));\n        compressionMethod.setSummary(BackupUtils.getReadableTarType(mCurrentCompressionMethod));\n        compressionMethod.setOnPreferenceClickListener(preference -> {\n            new SearchableSingleChoiceDialogBuilder<>(mActivity, BackupUtils.TAR_TYPES, BackupUtils.TAR_TYPES_READABLE)\n                    .setTitle(R.string.pref_compression_method)\n                    .setSelection(mCurrentCompressionMethod)\n                    .setPositiveButton(R.string.save, (dialog, which, selectedTarType) -> {\n                        if (selectedTarType != null) {\n                            mCurrentCompressionMethod = selectedTarType;\n                            Prefs.BackupRestore.setCompressionMethod(mCurrentCompressionMethod);\n                            compressionMethod.setSummary(BackupUtils.getReadableTarType(mCurrentCompressionMethod));\n                        }\n                    })\n                    .setNegativeButton(R.string.cancel, null)\n                    .show();\n            return true;\n        });\n        // Backup flags\n        BackupFlags flags = BackupFlags.fromPref();\n        ((Preference) Objects.requireNonNull(findPreference(\"backup_flags\"))).setOnPreferenceClickListener(preference -> {\n            List<Integer> supportedBackupFlags = BackupFlags.getSupportedBackupFlagsAsArray();\n            new SearchableMultiChoiceDialogBuilder<>(requireActivity(), supportedBackupFlags, BackupFlags.getFormattedFlagNames(requireContext(), supportedBackupFlags))\n                    .setTitle(R.string.backup_options)\n                    .addSelections(flags.flagsToCheckedIndexes(supportedBackupFlags))\n                    .hideSearchBar(true)\n                    .showSelectAll(false)\n                    .setPositiveButton(R.string.save, (dialog, which, selectedItems) -> {\n                        int flagsInt = 0;\n                        for (int flag : selectedItems) {\n                            flagsInt |= flag;\n                        }\n                        flags.setFlags(flagsInt);\n                        Prefs.BackupRestore.setBackupFlags(flags.getFlags());\n                    })\n                    .setNegativeButton(R.string.cancel, null)\n                    .show();\n            return true;\n        });\n        // Keystore toggle\n        SwitchPreferenceCompat backupKeyStore = Objects.requireNonNull(findPreference(\"backup_android_keystore\"));\n        backupKeyStore.setChecked(Prefs.BackupRestore.backupAppsWithKeyStore());\n        // Encryption\n        ((Preference) Objects.requireNonNull(findPreference(\"encryption\"))).setOnPreferenceClickListener(preference -> {\n            CharSequence[] encryptionNamesText = new CharSequence[ENCRYPTION_NAMES.length];\n            for (int i = 0; i < ENCRYPTION_NAMES.length; ++i) {\n                encryptionNamesText[i] = getString(ENCRYPTION_NAMES[i]);\n            }\n            new SearchableSingleChoiceDialogBuilder<>(mActivity, ENCRYPTION, encryptionNamesText)\n                    .setTitle(R.string.encryption)\n                    .setSelection(Prefs.Encryption.getEncryptionMode())\n                    .setOnSingleChoiceClickListener((dialog, which, encryptionMode, isChecked) -> {\n                        if (!isChecked) return;\n                        switch (encryptionMode) {\n                            case CryptoUtils.MODE_NO_ENCRYPTION:\n                                Prefs.Encryption.setEncryptionMode(encryptionMode);\n                                break;\n                            case CryptoUtils.MODE_AES: {\n                                DialogFragment fragment = new AESCryptoSelectionDialogFragment();\n                                fragment.show(getParentFragmentManager(), AESCryptoSelectionDialogFragment.TAG);\n                                break;\n                            }\n                            case CryptoUtils.MODE_RSA: {\n                                RSACryptoSelectionDialogFragment fragment = RSACryptoSelectionDialogFragment.getInstance(RSACrypto.RSA_KEY_ALIAS);\n                                fragment.setOnKeyPairUpdatedListener((keyPair, certificateBytes) -> {\n                                    if (keyPair != null) {\n                                        Prefs.Encryption.setEncryptionMode(CryptoUtils.MODE_RSA);\n                                    }\n                                });\n                                fragment.show(getParentFragmentManager(), RSACryptoSelectionDialogFragment.TAG);\n                                break;\n                            }\n                            case CryptoUtils.MODE_ECC: {\n                                ECCCryptoSelectionDialogFragment fragment = new ECCCryptoSelectionDialogFragment();\n                                fragment.setOnKeyPairUpdatedListener((keyPair, certificateBytes) -> {\n                                    if (keyPair != null) {\n                                        Prefs.Encryption.setEncryptionMode(CryptoUtils.MODE_ECC);\n                                    }\n                                });\n                                fragment.show(getParentFragmentManager(), RSACryptoSelectionDialogFragment.TAG);\n                                break;\n                            }\n                            case CryptoUtils.MODE_OPEN_PGP: {\n                                Prefs.Encryption.setEncryptionMode(encryptionMode);\n                                DialogFragment fragment = new OpenPgpKeySelectionDialogFragment();\n                                fragment.show(getParentFragmentManager(), OpenPgpKeySelectionDialogFragment.TAG);\n                            }\n                        }\n                    })\n                    .setPositiveButton(R.string.ok, null)\n                    .show();\n            return true;\n        });\n        // Backup volume\n        mBackupVolume = Prefs.Storage.getVolumePath();\n        ((Preference) Objects.requireNonNull(findPreference(\"backup_volume\")))\n                .setOnPreferenceClickListener(preference -> {\n                    mModel.loadStorageVolumes();\n                    return true;\n                });\n        // Import backups\n        ((Preference) Objects.requireNonNull(findPreference(\"import_backups\")))\n                .setOnPreferenceClickListener(preference -> {\n                    new SearchableItemsDialogBuilder<>(mActivity, R.array.import_backup_options)\n                            .setTitle(new DialogTitleBuilder(mActivity)\n                                    .setTitle(R.string.pref_import_backups)\n                                    .setSubtitle(R.string.pref_import_backups_hint)\n                                    .build())\n                            .setOnItemClickListener((dialog, which, item) -> {\n                                mImportType = which;\n                                String path;\n                                switch (mImportType) {\n                                    case ImportType.OAndBackup:\n                                        path = \"oandbackups\";\n                                        break;\n                                    case ImportType.TitaniumBackup:\n                                        path = \"TitaniumBackup\";\n                                        break;\n                                    case ImportType.SwiftBackup:\n                                        path = \"SwiftBackup\";\n                                        break;\n                                    default:\n                                        path = \"\";\n                                }\n                                new MaterialAlertDialogBuilder(mActivity)\n                                        .setTitle(R.string.pref_import_backups)\n                                        .setMessage(R.string.import_backups_warning_delete_backups_after_import)\n                                        .setPositiveButton(R.string.no, (dialog1, which1) -> {\n                                            mDeleteBackupsAfterImport = false;\n                                            mSafSelectImportDirectory.launch(getSafIntent(path));\n                                        })\n                                        .setNegativeButton(R.string.yes, (dialog1, which1) -> {\n                                            mDeleteBackupsAfterImport = true;\n                                            mSafSelectImportDirectory.launch(getSafIntent(path));\n                                        })\n                                        .setNeutralButton(R.string.cancel, null)\n                                        .show();\n                            })\n                            .setNegativeButton(R.string.close, null)\n                            .show();\n                    return true;\n                });\n    }\n\n    @Override\n    public void onCreate(@Nullable Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setEnterTransition(new MaterialSharedAxis(MaterialSharedAxis.Z, true));\n        setReturnTransition(new MaterialSharedAxis(MaterialSharedAxis.Z, false));\n    }\n\n    @Override\n    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {\n        super.onViewCreated(view, savedInstanceState);\n        mModel.getStorageVolumesLiveData().observe(getViewLifecycleOwner(), this::displayVolumeSelectionDialog);\n    }\n\n    @Override\n    public int getTitle() {\n        return R.string.backup_restore;\n    }\n\n    @UiThread\n    private void startImportOperation(@ImportType int backupType, Uri uri, boolean removeImported) {\n        // Start batch ops service\n        BatchOpsManager.Result input = new BatchOpsManager.Result(Collections.emptyList());\n        BatchBackupImportOptions options = new BatchBackupImportOptions(backupType, uri, removeImported);\n        BatchQueueItem item = BatchQueueItem.getBatchOpQueue(BatchOpsManager.OP_IMPORT_BACKUPS,\n                input.getFailedPackages(), input.getAssociatedUsers(), options);\n        Intent intent = BatchOpsService.getServiceIntent(mActivity, item);\n        ContextCompat.startForegroundService(mActivity, intent);\n    }\n\n    private void displayVolumeSelectionDialog(@NonNull ArrayMap<String, Uri> storageLocations) {\n        // TODO: 13/8/22 Move to a separate BottomSheet dialog fragment\n        AtomicReference<AlertDialog> alertDialog = new AtomicReference<>(null);\n        DialogTitleBuilder titleBuilder = new DialogTitleBuilder(mActivity)\n                .setTitle(R.string.backup_volume)\n                .setSubtitle(R.string.backup_volume_dialog_description)\n                .setStartIcon(R.drawable.ic_zip_disk)\n                .setEndIcon(R.drawable.ic_add, v -> new MaterialAlertDialogBuilder(mActivity)\n                        .setTitle(R.string.notice)\n                        .setMessage(R.string.notice_saf)\n                        .setPositiveButton(R.string.go, (dialog1, which1) -> {\n                            if (alertDialog.get() != null) {\n                                alertDialog.get().dismiss();\n                            }\n                            mSafSelectBackupVolume.launch(getSafIntent(\"AppManager\"));\n                        })\n                        .setNeutralButton(R.string.cancel, null)\n                        .show());\n\n        if (storageLocations.isEmpty()) {\n            alertDialog.set(new MaterialAlertDialogBuilder(mActivity)\n                    .setCustomTitle(titleBuilder.build())\n                    .setMessage(R.string.no_volumes_found)\n                    .setNegativeButton(R.string.ok, null)\n                    .show());\n            return;\n        }\n        Uri[] backupVolumes = new Uri[storageLocations.size()];\n        CharSequence[] backupVolumesStr = new CharSequence[storageLocations.size()];\n        for (int i = 0; i < storageLocations.size(); ++i) {\n            backupVolumes[i] = storageLocations.valueAt(i);\n            backupVolumesStr[i] = new SpannableStringBuilder(storageLocations.keyAt(i)).append(\"\\n\")\n                    .append(getSecondaryText(mActivity, getSmallerText(backupVolumes[i].getPath())));\n        }\n        alertDialog.set(new SearchableSingleChoiceDialogBuilder<>(mActivity, backupVolumes, backupVolumesStr)\n                .setTitle(titleBuilder.build())\n                .setSelection(mBackupVolume)\n                .setNegativeButton(R.string.cancel, null)\n                .setPositiveButton(R.string.save, (dialog, which, selectedBackupVolume) -> {\n                    mBackupVolume = selectedBackupVolume;\n                    Uri lastBackupVolume = Prefs.Storage.getVolumePath();\n                    if (!lastBackupVolume.equals(mBackupVolume)) {\n                        Prefs.Storage.setVolumePath(mBackupVolume.toString());\n                        mModel.reloadApps();\n                    }\n                })\n                .show());\n    }\n\n    private Intent getSafIntent(String path) {\n        return new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE)\n                .putExtra(\"android.provider.extra.SHOW_ADVANCED\", true)\n                .putExtra(\"android.provider.extra.INITIAL_URI\", Paths.getPrimaryPath(path).getUri());\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/settings/ChangeLanguageFragment.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.settings;\n\nimport android.annotation.SuppressLint;\nimport android.os.Build;\nimport android.os.Bundle;\nimport android.text.TextUtils;\nimport android.util.TypedValue;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.CheckedTextView;\nimport android.widget.FrameLayout;\n\nimport androidx.annotation.LayoutRes;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.collection.ArraySet;\nimport androidx.core.widget.TextViewCompat;\nimport androidx.fragment.app.Fragment;\nimport androidx.recyclerview.widget.LinearLayoutManager;\n\nimport com.google.android.material.color.MaterialColors;\nimport com.google.android.material.resources.MaterialAttributes;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Map;\nimport java.util.Set;\nimport java.util.concurrent.atomic.AtomicBoolean;\n\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.utils.LangUtils;\nimport io.github.muntashirakon.AppManager.utils.appearance.AppearanceUtils;\nimport io.github.muntashirakon.util.AdapterUtils;\nimport io.github.muntashirakon.util.UiUtils;\nimport io.github.muntashirakon.widget.RecyclerView;\nimport io.github.muntashirakon.widget.SearchView;\n\npublic class ChangeLanguageFragment extends Fragment {\n    private SearchView mSearchView;\n    private RecyclerView mRecyclerView;\n    private FrameLayout mViewContainer;\n    @Nullable\n    private SearchableRecyclerViewAdapter<String> mAdapter;\n    private String mCurrentLang;\n    private boolean mIsTextSelectable;\n\n    @Nullable\n    @Override\n    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {\n        View view = inflater.inflate(io.github.muntashirakon.ui.R.layout.dialog_searchable_single_choice, container, false);\n        mRecyclerView = view.findViewById(android.R.id.list);\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {\n            mRecyclerView.setScrollIndicators(0);\n        }\n        mRecyclerView.setLayoutManager(new LinearLayoutManager(view.getContext(), LinearLayoutManager.VERTICAL, false));\n        mViewContainer = view.findViewById(io.github.muntashirakon.ui.R.id.container);\n        mSearchView = view.findViewById(io.github.muntashirakon.ui.R.id.action_search);\n        mSearchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {\n            @Override\n            public boolean onQueryTextSubmit(String query) {\n                return false;\n            }\n\n            @Override\n            public boolean onQueryTextChange(String newText) {\n                if (mAdapter != null) mAdapter.setFilteredItems(newText);\n                return true;\n            }\n        });\n        view.setFitsSystemWindows(true);\n        boolean secondary = false;\n        if (getArguments() != null) {\n            secondary = requireArguments().getBoolean(PreferenceFragment.PREF_SECONDARY);\n            requireArguments().remove(PreferenceFragment.PREF_KEY);\n            requireArguments().remove(PreferenceFragment.PREF_SECONDARY);\n        }\n        if (secondary) {\n            UiUtils.applyWindowInsetsAsPadding(view, false, true, false, true);\n        } else UiUtils.applyWindowInsetsAsPaddingNoTop(view);\n        return view;\n    }\n\n    @Override\n    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {\n        super.onViewCreated(view, savedInstanceState);\n        mCurrentLang = Prefs.Appearance.getLanguage();\n        Map<String, Locale> locales = LangUtils.getAppLanguages(requireActivity());\n        final CharSequence[] languageNames = getLanguagesL(locales);\n        final String[] languages = new String[languageNames.length];\n        int i = 0;\n        int localeIndex = 0;\n        for (Map.Entry<String, Locale> localeEntry : locales.entrySet()) {\n            languages[i] = localeEntry.getKey();\n            if (languages[i].equals(mCurrentLang)) {\n                localeIndex = i;\n            }\n            ++i;\n        }\n        @SuppressLint({\"RestrictedApi\", \"PrivateResource\"})\n        int layoutId = MaterialAttributes.resolveInteger(requireContext(), androidx.appcompat.R.attr.singleChoiceItemLayout,\n                com.google.android.material.R.layout.mtrl_alert_select_dialog_singlechoice);\n        mAdapter = new SearchableRecyclerViewAdapter<>(Arrays.asList(languageNames), Arrays.asList(languages), layoutId);\n        mAdapter.setSelectedIndex(localeIndex, false);\n        mRecyclerView.setAdapter(mAdapter);\n    }\n\n    @Override\n    public void onStart() {\n        super.onStart();\n        requireActivity().setTitle(R.string.choose_language);\n    }\n\n    @NonNull\n    private CharSequence[] getLanguagesL(@NonNull Map<String, Locale> locales) {\n        CharSequence[] localesL = new CharSequence[locales.size()];\n        Locale locale;\n        int i = 0;\n        for (Map.Entry<String, Locale> localeEntry : locales.entrySet()) {\n            locale = localeEntry.getValue();\n            if (LangUtils.LANG_AUTO.equals(localeEntry.getKey())) {\n                localesL[i] = getString(R.string.auto);\n            } else localesL[i] = locale.getDisplayName(locale);\n            ++i;\n        }\n        return localesL;\n    }\n\n    private void triggerSingleChoiceClickListener(int index, boolean isChecked) {\n        if (mAdapter == null) {\n            return;\n        }\n        String selectedItem = mAdapter.mItems.get(index);\n        if (selectedItem != null && isChecked) {\n            mCurrentLang = selectedItem;\n            Prefs.Appearance.setLanguage(mCurrentLang);\n            AppearanceUtils.applyConfigurationChangesToActivities();\n        }\n    }\n\n    class SearchableRecyclerViewAdapter<T> extends RecyclerView.Adapter<SearchableRecyclerViewAdapter<T>.ViewHolder> {\n        @NonNull\n        private final List<CharSequence> mItemNames;\n        @NonNull\n        private final List<T> mItems;\n        @NonNull\n        private final ArrayList<Integer> mFilteredItems = new ArrayList<>();\n        private int mSelectedItem = -1;\n        private final Set<Integer> mDisabledItems = new ArraySet<>();\n        @LayoutRes\n        private final int mLayoutId;\n\n        SearchableRecyclerViewAdapter(@NonNull List<CharSequence> itemNames, @NonNull List<T> items, int layoutId) {\n            mItemNames = itemNames;\n            mItems = items;\n            mLayoutId = layoutId;\n            synchronized (mFilteredItems) {\n                for (int i = 0; i < items.size(); ++i) {\n                    mFilteredItems.add(i);\n                }\n            }\n        }\n\n        void setFilteredItems(String constraint) {\n            constraint = TextUtils.isEmpty(constraint) ? null : constraint.toLowerCase(Locale.ROOT);\n            Locale locale = Locale.getDefault();\n            synchronized (mFilteredItems) {\n                int previousCount = mFilteredItems.size();\n                mFilteredItems.clear();\n                for (int i = 0; i < mItems.size(); ++i) {\n                    if (constraint == null\n                            || mItemNames.get(i).toString().toLowerCase(locale).contains(constraint)\n                            || mItems.get(i).toString().toLowerCase(Locale.ROOT).contains(constraint)) {\n                        mFilteredItems.add(i);\n                    }\n                }\n                AdapterUtils.notifyDataSetChanged(this, previousCount, mFilteredItems.size());\n            }\n        }\n\n        @Nullable\n        T getSelection() {\n            if (mSelectedItem >= 0) {\n                return mItems.get(mSelectedItem);\n            }\n            return null;\n        }\n\n        void setSelection(@Nullable T selectedItem, boolean triggerListener) {\n            if (selectedItem != null) {\n                int index = mItems.indexOf(selectedItem);\n                if (index != -1) {\n                    setSelectedIndex(index, triggerListener);\n                }\n            }\n        }\n\n        void setSelectedIndex(int selectedIndex, boolean triggerListener) {\n            if (selectedIndex == mSelectedItem) {\n                // Do nothing\n                return;\n            }\n            updateSelection(false, triggerListener);\n            mSelectedItem = selectedIndex;\n            updateSelection(true, triggerListener);\n            mRecyclerView.setSelection(selectedIndex);\n        }\n\n        void addDisabledItems(@Nullable List<T> disabledItems) {\n            if (disabledItems != null) {\n                for (T item : disabledItems) {\n                    int index = mItems.indexOf(item);\n                    if (index != -1) {\n                        synchronized (mDisabledItems) {\n                            mDisabledItems.add(index);\n                        }\n                    }\n                }\n            }\n        }\n\n        @NonNull\n        @Override\n        public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {\n            View view = LayoutInflater.from(parent.getContext()).inflate(mLayoutId, parent, false);\n            return new ViewHolder(view);\n        }\n\n        @Override\n        public void onBindViewHolder(@NonNull ViewHolder holder, int position) {\n            Integer index;\n            synchronized (mFilteredItems) {\n                index = mFilteredItems.get(position);\n            }\n            final AtomicBoolean selected = new AtomicBoolean(mSelectedItem == index);\n            holder.item.setText(mItemNames.get(index));\n            holder.item.setTextIsSelectable(mIsTextSelectable);\n            synchronized (mDisabledItems) {\n                holder.item.setEnabled(!mDisabledItems.contains(index));\n            }\n            holder.item.setChecked(selected.get());\n            holder.item.setOnClickListener(v -> {\n                if (selected.get()) {\n                    // Already selected, do nothing\n                    return;\n                }\n                // Unselect the previous and select this one\n                updateSelection(false, true);\n                mSelectedItem = index;\n                // Update selection manually\n                selected.set(!selected.get());\n                holder.item.setChecked(selected.get());\n                triggerSingleChoiceClickListener(index, selected.get());\n            });\n        }\n\n        @Override\n        public int getItemCount() {\n            synchronized (mFilteredItems) {\n                return mFilteredItems.size();\n            }\n        }\n\n        private void updateSelection(boolean selected, boolean triggerListener) {\n            if (mSelectedItem < 0) {\n                return;\n            }\n            int position;\n            synchronized (mFilteredItems) {\n                position = mFilteredItems.indexOf(mSelectedItem);\n            }\n            if (position >= 0) {\n                notifyItemChanged(position, AdapterUtils.STUB);\n            }\n            if (triggerListener) {\n                triggerSingleChoiceClickListener(mSelectedItem, selected);\n            }\n        }\n\n        class ViewHolder extends RecyclerView.ViewHolder {\n            CheckedTextView item;\n\n            @SuppressLint(\"RestrictedApi\")\n            public ViewHolder(@NonNull View itemView) {\n                super(itemView);\n                item = itemView.findViewById(android.R.id.text1);\n                int textAppearanceBodyLarge = MaterialAttributes.resolveInteger(item.getContext(), com.google.android.material.R.attr.textAppearanceBodyLarge, 0);\n                TextViewCompat.setTextAppearance(item, textAppearanceBodyLarge);\n                item.setTextSize(TypedValue.COMPLEX_UNIT_SP, 16);\n                item.setTextColor(MaterialColors.getColor(item.getContext(), com.google.android.material.R.attr.colorOnSurfaceVariant, -1));\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/settings/FeatureController.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.settings;\n\nimport android.Manifest;\nimport android.content.ComponentName;\nimport android.content.Context;\nimport android.content.pm.PackageManager;\n\nimport androidx.annotation.IntDef;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.appcompat.app.AppCompatActivity;\nimport androidx.collection.SparseArrayCompat;\n\nimport java.util.ArrayList;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Objects;\n\nimport io.github.muntashirakon.AppManager.BuildConfig;\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.apk.installer.PackageInstallerActivity;\nimport io.github.muntashirakon.AppManager.details.AppDetailsActivity;\nimport io.github.muntashirakon.AppManager.details.manifest.ManifestViewerActivity;\nimport io.github.muntashirakon.AppManager.editor.CodeEditorActivity;\nimport io.github.muntashirakon.AppManager.intercept.ActivityInterceptor;\nimport io.github.muntashirakon.AppManager.logcat.LogViewerActivity;\nimport io.github.muntashirakon.AppManager.scanner.ScannerActivity;\nimport io.github.muntashirakon.AppManager.self.SelfPermissions;\nimport io.github.muntashirakon.AppManager.terminal.TermActivity;\nimport io.github.muntashirakon.AppManager.utils.AppPref;\nimport io.github.muntashirakon.AppManager.utils.ContextUtils;\nimport io.github.muntashirakon.AppManager.viewer.ExplorerActivity;\n\npublic class FeatureController {\n    @IntDef(flag = true, value = {\n            FEAT_INTERCEPTOR,\n            FEAT_MANIFEST,\n            FEAT_SCANNER,\n            FEAT_INSTALLER,\n            FEAT_USAGE_ACCESS,\n            FEAT_LOG_VIEWER,\n            FEAT_INTERNET,\n            FEAT_APP_EXPLORER,\n            FEAT_APP_INFO,\n            FEAT_CODE_EDITOR,\n            FEAT_VIRUS_TOTAL,\n            FEAT_TERMINAL,\n    })\n    public @interface FeatureFlags {\n    }\n\n    private static final int FEAT_INTERCEPTOR = 1;\n    private static final int FEAT_MANIFEST = 1 << 1;\n    private static final int FEAT_SCANNER = 1 << 2;\n    public static final int FEAT_INSTALLER = 1 << 3;\n    public static final int FEAT_USAGE_ACCESS = 1 << 4;\n    public static final int FEAT_LOG_VIEWER = 1 << 5;\n    public static final int FEAT_INTERNET = 1 << 6;\n    private static final int FEAT_APP_EXPLORER = 1 << 7;\n    private static final int FEAT_APP_INFO = 1 << 8;\n    private static final int FEAT_CODE_EDITOR = 1 << 9;\n    public static final int FEAT_VIRUS_TOTAL = 1 << 10;\n    public static final int FEAT_TERMINAL = 1 << 11;\n\n    @NonNull\n    public static FeatureController getInstance() {\n        return new FeatureController();\n    }\n\n    @FeatureFlags\n    public static final List<Integer> featureFlags = new ArrayList<>();\n\n    private static final LinkedHashMap<Integer, Integer> sFeatureFlagsMap = new LinkedHashMap<Integer, Integer>() {\n        {\n            featureFlags.add(FEAT_APP_EXPLORER);\n            put(FEAT_APP_EXPLORER, R.string.app_explorer);\n            featureFlags.add(FEAT_APP_INFO);\n            put(FEAT_APP_INFO, R.string.app_info);\n            featureFlags.add(FEAT_CODE_EDITOR);\n            put(FEAT_CODE_EDITOR, R.string.title_code_editor);\n            featureFlags.add(FEAT_INTERCEPTOR);\n            put(FEAT_INTERCEPTOR, R.string.interceptor);\n            featureFlags.add(FEAT_LOG_VIEWER);\n            put(FEAT_LOG_VIEWER, R.string.log_viewer);\n            featureFlags.add(FEAT_MANIFEST);\n            put(FEAT_MANIFEST, R.string.manifest_viewer);\n            featureFlags.add(FEAT_INSTALLER);\n            put(FEAT_INSTALLER, R.string.package_installer);\n            featureFlags.add(FEAT_SCANNER);\n            put(FEAT_SCANNER, R.string.scanner);\n            featureFlags.add(FEAT_TERMINAL);\n            put(FEAT_TERMINAL, R.string.title_terminal_emulator);\n            featureFlags.add(FEAT_USAGE_ACCESS);\n            put(FEAT_USAGE_ACCESS, R.string.usage_access);\n            featureFlags.add(FEAT_VIRUS_TOTAL);\n            put(FEAT_VIRUS_TOTAL, R.string.virus_total);\n        }\n    };\n\n    @NonNull\n    public static CharSequence[] getFormattedFlagNames(@NonNull Context context) {\n        CharSequence[] flagNames = new CharSequence[featureFlags.size()];\n        for (int i = 0; i < flagNames.length; ++i) {\n            flagNames[i] = context.getText(Objects.requireNonNull(sFeatureFlagsMap.get(featureFlags.get(i))));\n        }\n        return flagNames;\n    }\n\n    private static final SparseArrayCompat<ComponentName> sComponentCache = new SparseArrayCompat<>(4);\n\n    private final String mPackageName = BuildConfig.APPLICATION_ID;\n    private final PackageManager mPm;\n    private int mFlags;\n\n    private FeatureController() {\n        mPm = ContextUtils.getContext().getPackageManager();\n        mFlags = AppPref.getInt(AppPref.PrefKey.PREF_ENABLED_FEATURES_INT);\n    }\n\n    public int getFlags() {\n        return mFlags;\n    }\n\n    public static boolean isInterceptorEnabled() {\n        return getInstance().isEnabled(FEAT_INTERCEPTOR);\n    }\n\n    public static boolean isManifestEnabled() {\n        return getInstance().isEnabled(FEAT_MANIFEST);\n    }\n\n    public static boolean isScannerEnabled() {\n        return getInstance().isEnabled(FEAT_SCANNER);\n    }\n\n    public static boolean isInstallerEnabled() {\n        return getInstance().isEnabled(FEAT_INSTALLER);\n    }\n\n    public static boolean isUsageAccessEnabled() {\n        return getInstance().isEnabled(FEAT_USAGE_ACCESS);\n    }\n\n    public static boolean isLogViewerEnabled() {\n        return getInstance().isEnabled(FEAT_LOG_VIEWER);\n    }\n\n    public static boolean isInternetEnabled() {\n        return getInstance().isEnabled(FEAT_INTERNET);\n    }\n\n    public static boolean isVirusTotalEnabled() {\n        return getInstance().isEnabled(FEAT_VIRUS_TOTAL);\n    }\n\n    public static boolean isCodeEditorEnabled() {\n        return getInstance().isEnabled(FEAT_CODE_EDITOR);\n    }\n\n    public static boolean isTerminalEnabled() {\n        return getInstance().isEnabled(FEAT_TERMINAL);\n    }\n\n    private boolean isEnabled(@FeatureFlags int key) {\n        ComponentName cn;\n        switch (key) {\n            case FEAT_INSTALLER:\n                cn = getComponentName(key, PackageInstallerActivity.class);\n                break;\n            case FEAT_INTERCEPTOR:\n                cn = getComponentName(key, ActivityInterceptor.class);\n                break;\n            case FEAT_MANIFEST:\n                cn = getComponentName(key, ManifestViewerActivity.class);\n                break;\n            case FEAT_SCANNER:\n                cn = getComponentName(key, ScannerActivity.class);\n                break;\n            case FEAT_USAGE_ACCESS:\n                // Only depends on flag\n                return (mFlags & key) != 0;\n            case FEAT_VIRUS_TOTAL:\n                return (mFlags & key) != 0 && isEnabled(FEAT_INTERNET);\n            case FEAT_INTERNET:\n                return (mFlags & key) != 0 && SelfPermissions.checkSelfPermission(Manifest.permission.INTERNET);\n            case FEAT_LOG_VIEWER:\n                cn = getComponentName(key, LogViewerActivity.class);\n                break;\n            case FEAT_APP_EXPLORER:\n                cn = getComponentName(key, ExplorerActivity.class);\n                break;\n            case FEAT_APP_INFO:\n                cn = getComponentName(key, AppDetailsActivity.ALIAS_APP_INFO);\n                break;\n            case FEAT_CODE_EDITOR:\n                cn = getComponentName(key, CodeEditorActivity.ALIAS_EDITOR);\n                break;\n            case FEAT_TERMINAL:\n                cn = getComponentName(key, TermActivity.class);\n                break;\n            default:\n                throw new IllegalArgumentException();\n        }\n        return isComponentEnabled(cn) && (mFlags & key) != 0;\n    }\n\n    public void modifyState(@FeatureFlags int key, boolean enabled) {\n        switch (key) {\n            case FEAT_INSTALLER:\n                modifyState(key, PackageInstallerActivity.class, enabled);\n                break;\n            case FEAT_INTERCEPTOR:\n                modifyState(key, ActivityInterceptor.class, enabled);\n                break;\n            case FEAT_MANIFEST:\n                modifyState(key, ManifestViewerActivity.class, enabled);\n                break;\n            case FEAT_SCANNER:\n                modifyState(key, ScannerActivity.class, enabled);\n                break;\n            case FEAT_USAGE_ACCESS:\n            case FEAT_INTERNET:\n            case FEAT_VIRUS_TOTAL:\n                // Only depends on flag\n                break;\n            case FEAT_LOG_VIEWER:\n                modifyState(key, LogViewerActivity.class, enabled);\n                break;\n            case FEAT_APP_EXPLORER:\n                modifyState(key, ExplorerActivity.class, enabled);\n                break;\n            case FEAT_APP_INFO:\n                modifyState(key, AppDetailsActivity.ALIAS_APP_INFO, enabled);\n                break;\n            case FEAT_CODE_EDITOR:\n                modifyState(key, CodeEditorActivity.ALIAS_EDITOR, enabled);\n                break;\n            case FEAT_TERMINAL:\n                modifyState(key, TermActivity.class, enabled);\n                break;\n        }\n        // Modify flags\n        mFlags = enabled ? (mFlags | key) : (mFlags & ~key);\n        // Save to pref\n        AppPref.set(AppPref.PrefKey.PREF_ENABLED_FEATURES_INT, mFlags);\n    }\n\n    private void modifyState(@FeatureFlags int key, @Nullable Class<? extends AppCompatActivity> clazz, boolean enabled) {\n        ComponentName cn = getComponentName(key, clazz);\n        if (cn == null) return;\n        int state = enabled ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED : PackageManager.COMPONENT_ENABLED_STATE_DISABLED;\n        mPm.setComponentEnabledSetting(cn, state, PackageManager.DONT_KILL_APP);\n    }\n\n    private void modifyState(@FeatureFlags int key, @Nullable String name, boolean enabled) {\n        ComponentName cn = getComponentName(key, name);\n        if (cn == null) return;\n        int state = enabled ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED : PackageManager.COMPONENT_ENABLED_STATE_DISABLED;\n        mPm.setComponentEnabledSetting(cn, state, PackageManager.DONT_KILL_APP);\n    }\n\n    @Nullable\n    private ComponentName getComponentName(@FeatureFlags int key, @Nullable Class<? extends AppCompatActivity> clazz) {\n        if (clazz == null) return null;\n        ComponentName cn = sComponentCache.get(key);\n        if (cn == null) {\n            cn = new ComponentName(mPackageName, clazz.getName());\n            sComponentCache.put(key, cn);\n        }\n        return cn;\n    }\n\n    @Nullable\n    private ComponentName getComponentName(@FeatureFlags int key, @Nullable String name) {\n        if (name == null) return null;\n        ComponentName cn = sComponentCache.get(key);\n        if (cn == null) {\n            cn = new ComponentName(mPackageName, name);\n            sComponentCache.put(key, cn);\n        }\n        return cn;\n    }\n\n    private boolean isComponentEnabled(@Nullable ComponentName componentName) {\n        if (componentName == null) return true;\n        int status = mPm.getComponentEnabledSetting(componentName);\n        return status == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT || status == PackageManager.COMPONENT_ENABLED_STATE_ENABLED;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/settings/FileManagerPreferences.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.settings;\n\nimport android.content.ComponentName;\nimport android.content.ContentResolver;\nimport android.content.pm.PackageManager;\nimport android.net.Uri;\nimport android.os.Bundle;\nimport android.text.InputType;\nimport android.text.TextUtils;\nimport android.view.inputmethod.EditorInfo;\n\nimport androidx.annotation.Nullable;\nimport androidx.core.view.inputmethod.EditorInfoCompat;\nimport androidx.preference.Preference;\nimport androidx.preference.SwitchPreferenceCompat;\n\nimport com.google.android.material.transition.MaterialSharedAxis;\n\nimport java.io.File;\nimport java.util.Objects;\n\nimport io.github.muntashirakon.AppManager.BuildConfig;\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.fm.FmActivity;\nimport io.github.muntashirakon.AppManager.fm.FmUtils;\nimport io.github.muntashirakon.dialog.TextInputDialogBuilder;\n\npublic class FileManagerPreferences extends PreferenceFragment {\n\n    @Override\n    public void onCreatePreferences(@Nullable Bundle savedInstanceState, @Nullable String rootKey) {\n        setPreferencesFromResource(R.xml.preferences_file_manager, rootKey);\n        getPreferenceManager().setPreferenceDataStore(new SettingsDataStore());\n        // Display in launcher\n        SwitchPreferenceCompat displayInLauncherPref = Objects.requireNonNull(findPreference(\"fm_display_in_launcher\"));\n        displayInLauncherPref.setChecked(Prefs.FileManager.displayInLauncher());\n        displayInLauncherPref.setOnPreferenceChangeListener((preference, newValue) -> {\n            boolean isChecked = (boolean) newValue;\n            int newState = isChecked ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED : PackageManager.COMPONENT_ENABLED_STATE_DISABLED;\n            ComponentName componentName = new ComponentName(BuildConfig.APPLICATION_ID, FmActivity.LAUNCHER_ALIAS);\n            requireContext().getPackageManager().setComponentEnabledSetting(componentName, newState, PackageManager.DONT_KILL_APP);\n            return true;\n        });\n        // Remember last opened path\n        SwitchPreferenceCompat filesRememberLastPathPref = Objects.requireNonNull(findPreference(\"fm_remember_last_path\"));\n        filesRememberLastPathPref.setChecked(Prefs.FileManager.isRememberLastOpenedPath());\n        // Set home\n        Preference setHomePrefs = Objects.requireNonNull(findPreference(\"fm_home\"));\n        setHomePrefs.setSummary(FmUtils.getDisplayablePath(Prefs.FileManager.getHome()));\n        setHomePrefs.setOnPreferenceClickListener(preference -> {\n            new TextInputDialogBuilder(requireContext(), null)\n                    .setTitle(R.string.pref_set_home)\n                    .setInputText(FmUtils.getDisplayablePath(Prefs.FileManager.getHome()))\n                    .setInputInputType(InputType.TYPE_CLASS_TEXT)\n                    .setInputImeOptions(EditorInfo.IME_ACTION_DONE | EditorInfoCompat.IME_FLAG_NO_PERSONALIZED_LEARNING)\n                    .setNegativeButton(R.string.cancel, null)\n                    .setPositiveButton(R.string.ok, (dialog, which, inputText, isChecked) -> {\n                        if (TextUtils.isEmpty(inputText)) {\n                            return;\n                        }\n                        String newHome = inputText.toString();\n                        Uri uri;\n                        if (newHome.startsWith(File.separator)) {\n                            uri = new Uri.Builder().scheme(ContentResolver.SCHEME_FILE).path(newHome).build();\n                        } else uri = Uri.parse(newHome);\n                        Prefs.FileManager.setHome(uri);\n                        setHomePrefs.setSummary(FmUtils.getDisplayablePath(uri));\n                    })\n                    .show();\n            return true;\n        });\n    }\n\n    @Override\n    public void onCreate(@Nullable Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setEnterTransition(new MaterialSharedAxis(MaterialSharedAxis.Z, true));\n        setReturnTransition(new MaterialSharedAxis(MaterialSharedAxis.Z, false));\n    }\n\n    @Override\n    public int getTitle() {\n        return R.string.files;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/settings/ImportExportRulesPreferences.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.settings;\n\nimport android.os.Bundle;\nimport android.os.UserHandleHidden;\nimport android.text.SpannableStringBuilder;\n\nimport androidx.activity.result.ActivityResultLauncher;\nimport androidx.activity.result.contract.ActivityResultContracts;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.preference.Preference;\n\nimport com.google.android.material.dialog.MaterialAlertDialogBuilder;\nimport com.google.android.material.transition.MaterialSharedAxis;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Objects;\nimport java.util.concurrent.Future;\n\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.db.entity.App;\nimport io.github.muntashirakon.AppManager.db.utils.AppDb;\nimport io.github.muntashirakon.AppManager.oneclickops.ItemCount;\nimport io.github.muntashirakon.AppManager.rules.RulesTypeSelectionDialogFragment;\nimport io.github.muntashirakon.AppManager.rules.compontents.ExternalComponentsImporter;\nimport io.github.muntashirakon.AppManager.self.SelfPermissions;\nimport io.github.muntashirakon.AppManager.users.Users;\nimport io.github.muntashirakon.AppManager.utils.DateUtils;\nimport io.github.muntashirakon.AppManager.utils.PackageUtils;\nimport io.github.muntashirakon.AppManager.utils.ThreadUtils;\nimport io.github.muntashirakon.AppManager.utils.UIUtils;\nimport io.github.muntashirakon.dialog.SearchableItemsDialogBuilder;\nimport io.github.muntashirakon.dialog.SearchableMultiChoiceDialogBuilder;\nimport io.github.muntashirakon.view.ProgressIndicatorCompat;\n\npublic class ImportExportRulesPreferences extends PreferenceFragment {\n    private static final String MIME_JSON = \"application/json\";\n    private static final String MIME_TSV = \"text/tab-separated-values\";\n    private static final String MIME_XML = \"text/xml\";\n\n    private final int mUserHandle = UserHandleHidden.myUserId();\n    private SettingsActivity mActivity;\n    @Nullable\n    private Future<?> importExistingFuture;\n    private final ActivityResultLauncher<String> mExportRules = registerForActivityResult(\n            new ActivityResultContracts.CreateDocument(MIME_TSV),\n            uri -> {\n                if (uri == null) {\n                    // Back button pressed.\n                    return;\n                }\n                RulesTypeSelectionDialogFragment dialogFragment = new RulesTypeSelectionDialogFragment();\n                Bundle args = new Bundle();\n                args.putInt(RulesTypeSelectionDialogFragment.ARG_MODE, RulesTypeSelectionDialogFragment.MODE_EXPORT);\n                args.putParcelable(RulesTypeSelectionDialogFragment.ARG_URI, uri);\n                args.putStringArrayList(RulesTypeSelectionDialogFragment.ARG_PKG, null);\n                args.putIntArray(RulesTypeSelectionDialogFragment.ARG_USERS, Users.getUsersIds());\n                dialogFragment.setArguments(args);\n                dialogFragment.show(getParentFragmentManager(), RulesTypeSelectionDialogFragment.TAG);\n            });\n    private final ActivityResultLauncher<String> mImportRules = registerForActivityResult(\n            new ActivityResultContracts.GetContent(),\n            uri -> {\n                if (uri == null) {\n                    // Back button pressed.\n                    return;\n                }\n                RulesTypeSelectionDialogFragment dialogFragment = new RulesTypeSelectionDialogFragment();\n                Bundle args = new Bundle();\n                args.putInt(RulesTypeSelectionDialogFragment.ARG_MODE, RulesTypeSelectionDialogFragment.MODE_IMPORT);\n                args.putParcelable(RulesTypeSelectionDialogFragment.ARG_URI, uri);\n                args.putStringArrayList(RulesTypeSelectionDialogFragment.ARG_PKG, null);\n                args.putIntArray(RulesTypeSelectionDialogFragment.ARG_USERS, Users.getUsersIds());\n                dialogFragment.setArguments(args);\n                dialogFragment.show(getParentFragmentManager(), RulesTypeSelectionDialogFragment.TAG);\n            });\n    private final ActivityResultLauncher<String> mImportFromWatt = registerForActivityResult(\n            new ActivityResultContracts.GetMultipleContents(),\n            uris -> {\n                if (uris == null || uris.isEmpty()) {\n                    // Back button pressed.\n                    return;\n                }\n                ThreadUtils.postOnBackgroundThread(() -> {\n                    List<String> failedFiles = ExternalComponentsImporter.applyFromWatt(uris, Users.getUsersIds());\n                    ThreadUtils.postOnMainThread(() -> displayImportExternalRulesFailedPackagesDialog(failedFiles));\n                });\n            });\n    private final ActivityResultLauncher<String> mImportFromBlocker = registerForActivityResult(\n            new ActivityResultContracts.GetMultipleContents(),\n            uris -> {\n                if (uris == null || uris.isEmpty()) {\n                    // Back button pressed.\n                    return;\n                }\n                ThreadUtils.postOnBackgroundThread(() -> {\n                    List<String> failedFiles = ExternalComponentsImporter.applyFromBlocker(uris, Users.getUsersIds());\n                    ThreadUtils.postOnMainThread(() -> displayImportExternalRulesFailedPackagesDialog(failedFiles));\n                });\n            });\n\n    @Override\n    public void onCreatePreferences(@Nullable Bundle savedInstanceState, @Nullable String rootKey) {\n        addPreferencesFromResource(R.xml.preferences_rules_import_export);\n        getPreferenceManager().setPreferenceDataStore(new SettingsDataStore());\n        mActivity = (SettingsActivity) requireActivity();\n        ((Preference) Objects.requireNonNull(findPreference(\"export\")))\n                .setOnPreferenceClickListener(preference -> {\n                    final String fileName = \"app_manager_rules_export-\" + DateUtils.formatDateTime(mActivity, System.currentTimeMillis()) + \".am.tsv\";\n                    mExportRules.launch(fileName);\n                    return true;\n                });\n        ((Preference) Objects.requireNonNull(findPreference(\"import\")))\n                .setOnPreferenceClickListener(preference -> {\n                    mImportRules.launch(MIME_TSV);\n                    return true;\n                });\n        ((Preference) Objects.requireNonNull(findPreference(\"import_existing\")))\n                .setOnPreferenceClickListener(preference -> {\n                    new MaterialAlertDialogBuilder(requireActivity())\n                            .setTitle(R.string.pref_import_existing)\n                            .setMessage(R.string.apply_to_system_apps_question)\n                            .setPositiveButton(R.string.no, (dialog, which) -> importExistingRules(false))\n                            .setNegativeButton(R.string.yes, ((dialog, which) -> importExistingRules(true)))\n                            .show();\n                    return true;\n                });\n        ((Preference) Objects.requireNonNull(findPreference(\"import_watt\")))\n                .setOnPreferenceClickListener(preference -> {\n                    mImportFromWatt.launch(MIME_XML);\n                    return true;\n                });\n        ((Preference) Objects.requireNonNull(findPreference(\"import_blocker\")))\n                .setOnPreferenceClickListener(preference -> {\n                    mImportFromBlocker.launch(MIME_JSON);\n                    return true;\n                });\n    }\n\n    @Override\n    public void onCreate(@Nullable Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setEnterTransition(new MaterialSharedAxis(MaterialSharedAxis.Z, true));\n        setReturnTransition(new MaterialSharedAxis(MaterialSharedAxis.Z, false));\n    }\n\n    @Override\n    public void onDestroy() {\n        if (importExistingFuture != null) {\n            importExistingFuture.cancel(true);\n        }\n        super.onDestroy();\n    }\n\n    @Override\n    public int getTitle() {\n        return R.string.pref_import_export_blocking_rules;\n    }\n\n    private void importExistingRules(final boolean systemApps) {\n        if (!SelfPermissions.canModifyAppComponentStates(UserHandleHidden.myUserId(), null, true)) {\n            UIUtils.displayShortToast(R.string.only_works_in_root_or_adb_mode);\n            return;\n        }\n        ProgressIndicatorCompat.setVisibility(mActivity.progressIndicator, true);\n        importExistingFuture = ThreadUtils.postOnBackgroundThread(() -> {\n            final List<ItemCount> itemCounts = new ArrayList<>();\n            ItemCount itemCount;\n            for (App app : new AppDb().getAllInstalledApplications()) {\n                if (ThreadUtils.isInterrupted()) return;\n                if (!systemApps && app.isSystemApp())\n                    continue;\n                itemCount = new ItemCount();\n                itemCount.packageName = app.packageName;\n                itemCount.packageLabel = app.packageLabel;\n                itemCount.count = PackageUtils.getUserDisabledComponentsForPackage(app.packageName, mUserHandle).size();\n                if (itemCount.count > 0) itemCounts.add(itemCount);\n            }\n            ThreadUtils.postOnMainThread(() -> displayImportExistingRulesPackageSelectionDialog(itemCounts));\n        });\n    }\n\n    private void displayImportExistingRulesPackageSelectionDialog(@NonNull List<ItemCount> itemCounts) {\n        if (itemCounts.isEmpty()) {\n            ProgressIndicatorCompat.setVisibility(mActivity.progressIndicator, false);\n            UIUtils.displayShortToast(R.string.no_matching_package_found);\n            return;\n        }\n        final List<String> packages = new ArrayList<>();\n        final CharSequence[] packagesWithItemCounts = new CharSequence[itemCounts.size()];\n        ItemCount itemCount;\n        for (int i = 0; i < itemCounts.size(); ++i) {\n            itemCount = itemCounts.get(i);\n            packages.add(itemCount.packageName);\n            packagesWithItemCounts[i] = new SpannableStringBuilder(itemCount.packageLabel).append(\"\\n\")\n                    .append(UIUtils.getSmallerText(UIUtils.getSecondaryText(mActivity, getResources()\n                            .getQuantityString(R.plurals.no_of_components, itemCount.count,\n                                    itemCount.count))));\n        }\n        ProgressIndicatorCompat.setVisibility(mActivity.progressIndicator, false);\n        new SearchableMultiChoiceDialogBuilder<>(requireActivity(), packages, packagesWithItemCounts)\n                .setTitle(R.string.filtered_packages)\n                .setPositiveButton(R.string.apply, (dialog, which, selectedPackages) -> {\n                    ProgressIndicatorCompat.setVisibility(mActivity.progressIndicator, true);\n                    ThreadUtils.postOnBackgroundThread(() -> {\n                        List<String> failedPackages = ExternalComponentsImporter\n                                .applyFromExistingBlockList(selectedPackages, mUserHandle);\n                        ThreadUtils.postOnMainThread(() -> displayImportExistingRulesFailedPackagesDialog(failedPackages));\n                    });\n                })\n                .setNegativeButton(R.string.cancel, null)\n                .show();\n    }\n\n    private void displayImportExistingRulesFailedPackagesDialog(@NonNull List<String> failedPackages) {\n        if (isDetached()) {\n            if (failedPackages.isEmpty()) {\n                UIUtils.displayShortToast(R.string.the_import_was_successful);\n            } else {\n                UIUtils.displayShortToast(R.string.failed);\n            }\n            return;\n        }\n        ProgressIndicatorCompat.setVisibility(mActivity.progressIndicator, false);\n        if (failedPackages.isEmpty()) {\n            UIUtils.displayShortToast(R.string.the_import_was_successful);\n            return;\n        }\n        new SearchableItemsDialogBuilder<>(requireActivity(), failedPackages)\n                .setTitle(R.string.failed_packages)\n                .setNegativeButton(R.string.ok, null)\n                .show();\n    }\n\n    private void displayImportExternalRulesFailedPackagesDialog(@NonNull List<String> failedFiles) {\n        if (isDetached()) {\n            if (failedFiles.isEmpty()) {\n                UIUtils.displayShortToast(R.string.the_import_was_successful);\n            } else {\n                UIUtils.displayLongToastPl(R.plurals.failed_to_import_files, failedFiles.size(), failedFiles.size());\n            }\n            return;\n        }\n        ProgressIndicatorCompat.setVisibility(mActivity.progressIndicator, false);\n        if (failedFiles.isEmpty()) {\n            UIUtils.displayShortToast(R.string.the_import_was_successful);\n            return;\n        }\n        new SearchableItemsDialogBuilder<>(requireActivity(), failedFiles)\n                .setTitle(getResources().getQuantityString(R.plurals.failed_to_import_files, failedFiles.size(),\n                        failedFiles.size()))\n                .setNegativeButton(R.string.close, null)\n                .show();\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/settings/InstallerPreferences.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.settings;\n\nimport static io.github.muntashirakon.AppManager.utils.UIUtils.getSecondaryText;\nimport static io.github.muntashirakon.AppManager.utils.UIUtils.getSmallerText;\n\nimport android.Manifest;\nimport android.annotation.SuppressLint;\nimport android.content.Intent;\nimport android.content.pm.PackageInfo;\nimport android.content.pm.PackageInstaller;\nimport android.content.pm.PackageManager;\nimport android.net.Uri;\nimport android.os.Build;\nimport android.os.Bundle;\nimport android.os.UserHandleHidden;\nimport android.text.InputType;\nimport android.text.SpannableStringBuilder;\nimport android.view.View;\nimport android.view.inputmethod.EditorInfo;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.core.util.Pair;\nimport androidx.core.view.inputmethod.EditorInfoCompat;\nimport androidx.lifecycle.ViewModelProvider;\nimport androidx.preference.Preference;\nimport androidx.preference.PreferenceCategory;\nimport androidx.preference.SwitchPreferenceCompat;\n\nimport com.google.android.material.dialog.MaterialAlertDialogBuilder;\nimport com.google.android.material.transition.MaterialSharedAxis;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Objects;\n\nimport io.github.muntashirakon.AppManager.BuildConfig;\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.apk.signing.Signer;\nimport io.github.muntashirakon.AppManager.self.SelfPermissions;\nimport io.github.muntashirakon.AppManager.utils.PackageUtils;\nimport io.github.muntashirakon.AppManager.utils.Utils;\nimport io.github.muntashirakon.dialog.ScrollableDialogBuilder;\nimport io.github.muntashirakon.dialog.SearchableSingleChoiceDialogBuilder;\nimport io.github.muntashirakon.dialog.TextInputDialogBuilder;\nimport io.github.muntashirakon.preference.TopSwitchPreference;\n\npublic class InstallerPreferences extends PreferenceFragment {\n    public static final Integer[] INSTALL_LOCATIONS = new Integer[] {\n            PackageInfo.INSTALL_LOCATION_AUTO,\n            PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY,\n            PackageInfo.INSTALL_LOCATION_PREFER_EXTERNAL\n    };\n    public static final int[] INSTALL_LOCATION_NAMES = new int[]{\n            R.string.auto,  // PackageInfo.INSTALL_LOCATION_AUTO\n            R.string.install_location_internal_only,  // PackageInfo.INSTALL_LOCATION_INTERNAL_ONLY\n            R.string.install_location_prefer_external,  // PackageInfo.INSTALL_LOCATION_PREFER_EXTERNAL\n    };\n\n    @SuppressLint(\"InlinedApi\")\n    public static final Integer[] PKG_SOURCES = new Integer[] {\n            PackageInstaller.PACKAGE_SOURCE_UNSPECIFIED,\n            PackageInstaller.PACKAGE_SOURCE_OTHER,\n            PackageInstaller.PACKAGE_SOURCE_STORE,\n            PackageInstaller.PACKAGE_SOURCE_LOCAL_FILE,\n            PackageInstaller.PACKAGE_SOURCE_DOWNLOADED_FILE,\n    };\n\n    public static final int[] PKG_SOURCES_NAMES = new int[]{\n            R.string._undefined,  // PackageInstaller.PACKAGE_SOURCE_UNSPECIFIED\n            R.string.package_source_other,  // PackageInstaller.PACKAGE_SOURCE_OTHER\n            R.string.package_source_store,  // PackageInstaller.PACKAGE_SOURCE_STORE\n            R.string.package_source_local_file,  // PackageInstaller.PACKAGE_SOURCE_LOCAL_FILE\n            R.string.package_source_downloaded_file,  // PackageInstaller.PACKAGE_SOURCE_DOWNLOADED_FILE\n    };\n\n    private SettingsActivity mActivity;\n    private PackageManager mPm;\n    private String mInstallerApp;\n    private Preference mInstallerAppPref;\n    private MainPreferencesViewModel mModel;\n\n    @Override\n    public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {\n        setPreferencesFromResource(R.xml.preferences_installer, rootKey);\n        getPreferenceManager().setPreferenceDataStore(new SettingsDataStore());\n        mModel = new ViewModelProvider(requireActivity()).get(MainPreferencesViewModel.class);\n        mActivity = (SettingsActivity) requireActivity();\n        mPm = mActivity.getPackageManager();\n        boolean isInstallerEnabled = FeatureController.isInstallerEnabled();\n        PreferenceCategory catGeneral = requirePreference(\"cat_general\");\n        PreferenceCategory catAdvanced = requirePreference(\"cat_advanced\");\n        TopSwitchPreference useInstaller = requirePreference(\"use_installer\");\n        useInstaller.setChecked(isInstallerEnabled);\n        useInstaller.setOnPreferenceChangeListener((preference, newValue) -> {\n            boolean isEnabled = (boolean) newValue;\n            enablePrefs(isEnabled, catGeneral, catAdvanced);\n            FeatureController.getInstance().modifyState(FeatureController.FEAT_INSTALLER, isEnabled);\n            return true;\n        });\n        enablePrefs(isInstallerEnabled, catGeneral, catAdvanced);\n\n        // Set installation locations\n        Preference installLocationPref = Objects.requireNonNull(findPreference(\"installer_install_location\"));\n        installLocationPref.setSummary(INSTALL_LOCATION_NAMES[Prefs.Installer.getInstallLocation()]);\n        installLocationPref.setOnPreferenceClickListener(preference -> {\n            CharSequence[] installLocationTexts = new CharSequence[INSTALL_LOCATION_NAMES.length];\n            for (int i = 0; i < INSTALL_LOCATION_NAMES.length; ++i) {\n                installLocationTexts[i] = getString(INSTALL_LOCATION_NAMES[i]);\n            }\n            int defaultChoice = Prefs.Installer.getInstallLocation();\n            new SearchableSingleChoiceDialogBuilder<>(requireActivity(), INSTALL_LOCATIONS, installLocationTexts)\n                    .setTitle(R.string.install_location)\n                    .setSelection(defaultChoice)\n                    .setPositiveButton(R.string.save, (dialog, which, newInstallLocation) -> {\n                        Objects.requireNonNull(newInstallLocation);\n                        Prefs.Installer.setInstallLocation(newInstallLocation);\n                        installLocationPref.setSummary(INSTALL_LOCATION_NAMES[newInstallLocation]);\n                    })\n                    .setNegativeButton(R.string.cancel, null)\n                    .show();\n            return true;\n        });\n        // Set installer app\n        mInstallerAppPref = Objects.requireNonNull(findPreference(\"installer_installer_app\"));\n        mInstallerAppPref.setEnabled(SelfPermissions.checkSelfOrRemotePermission(Manifest.permission.INSTALL_PACKAGES));\n        mInstallerApp = Prefs.Installer.getInstallerPackageName();\n        mInstallerAppPref.setSummary(PackageUtils.getPackageLabel(mPm, mInstallerApp));\n        mInstallerAppPref.setOnPreferenceClickListener(preference -> {\n            new MaterialAlertDialogBuilder(requireActivity())\n                    .setTitle(R.string.installer_app)\n                    .setMessage(R.string.installer_app_message)\n                    .setPositiveButton(R.string.choose, (dialog1, which1) -> {\n                        mActivity.progressIndicator.show();\n                        mModel.loadPackageNameLabelPair();\n                    })\n                    .setNegativeButton(R.string.specify_custom_name, (dialog, which) ->\n                            new TextInputDialogBuilder(requireActivity(), R.string.installer_app)\n                                    .setTitle(R.string.installer_app)\n                                    .setInputText(mInstallerApp)\n                                    .setInputInputType(InputType.TYPE_CLASS_TEXT)\n                                    .setInputImeOptions(EditorInfo.IME_ACTION_DONE | EditorInfoCompat.IME_FLAG_NO_PERSONALIZED_LEARNING)\n                                    .setPositiveButton(R.string.ok, (dialog1, which1, inputText, isChecked) -> {\n                                        if (inputText == null) return;\n                                        mInstallerApp = inputText.toString().trim();\n                                        Prefs.Installer.setInstallerPackageName(mInstallerApp);\n                                        mInstallerAppPref.setSummary(PackageUtils.getPackageLabel(mPm, mInstallerApp));\n                                    })\n                                    .setNegativeButton(R.string.cancel, null)\n                                    .show())\n                    .setNeutralButton(R.string.reset_to_default, (dialog, which) -> {\n                        Prefs.Installer.setInstallerPackageName(mInstallerApp = BuildConfig.APPLICATION_ID);\n                        mInstallerAppPref.setSummary(PackageUtils.getPackageLabel(mPm, mInstallerApp));\n                    })\n                    .show();\n            return true;\n        });\n        // Disable verification\n        SwitchPreferenceCompat disableVerification = Objects.requireNonNull(findPreference(\"installer_disable_verification\"));\n        disableVerification.setEnabled(SelfPermissions.isSystemOrRootOrShell());\n        disableVerification.setChecked(Prefs.Installer.isDisableApkVerification());\n        // Update ownership\n        SwitchPreferenceCompat updateOwnership = Objects.requireNonNull(findPreference(\"installer_update_ownership\"));\n        updateOwnership.setVisible(Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE);\n        updateOwnership.setChecked(Prefs.Installer.requestUpdateOwnership());\n        // Package source\n        Preference pkgSource = Objects.requireNonNull(findPreference(\"installer_default_pkg_source\"));\n        pkgSource.setVisible(Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU);\n        pkgSource.setSummary(PKG_SOURCES_NAMES[Prefs.Installer.getPackageSource()]);\n        pkgSource.setOnPreferenceClickListener(preference -> {\n            CharSequence[] pkgSourceTexts = new CharSequence[PKG_SOURCES_NAMES.length];\n            for (int i = 0; i < PKG_SOURCES_NAMES.length; ++i) {\n                pkgSourceTexts[i] = getString(PKG_SOURCES_NAMES[i]);\n            }\n            int defaultChoice = Prefs.Installer.getPackageSource();\n            new SearchableSingleChoiceDialogBuilder<>(requireActivity(), PKG_SOURCES, pkgSourceTexts)\n                    .setTitle(R.string.pref_default_package_source)\n                    .setSelection(defaultChoice)\n                    .setPositiveButton(R.string.save, (dialog, which, newPkgSource) -> {\n                        Objects.requireNonNull(newPkgSource);\n                        Prefs.Installer.setPackageSource(newPkgSource);\n                        pkgSource.setSummary(PKG_SOURCES_NAMES[newPkgSource]);\n                    })\n                    .setNegativeButton(R.string.cancel, null)\n                    .show();\n            return true;\n        });\n        // Set origin\n        SwitchPreferenceCompat setOrigin = Objects.requireNonNull(findPreference(\"installer_set_origin\"));\n        setOrigin.setChecked(Prefs.Installer.isSetOriginatingPackage());\n        // Sign apk before installing\n        SwitchPreferenceCompat signApk = Objects.requireNonNull(findPreference(\"installer_sign_apk\"));\n        signApk.setChecked(Prefs.Installer.canSignApk());\n        signApk.setOnPreferenceChangeListener((preference, enabled) -> {\n            if ((boolean) enabled && !Signer.canSign()) {\n                new ScrollableDialogBuilder(requireActivity())\n                        .setTitle(R.string.pref_sign_apk_no_signing_key)\n                        .setMessage(R.string.pref_sign_apk_error_signing_key_not_added)\n                        .enableAnchors()\n                        .setPositiveButton(R.string.add, (dialog, which, isChecked) -> {\n                            Intent intent = new Intent(Intent.ACTION_VIEW)\n                                    .setData(Uri.parse(\"app-manager://settings/apk_signing_prefs/signing_keys\"));\n                            startActivity(intent);\n                        })\n                        .setNegativeButton(R.string.cancel, null)\n                        .show();\n                return false;\n            }\n            return true;\n        });\n        SwitchPreferenceCompat forceDexOpt = Objects.requireNonNull(findPreference(\"installer_force_dex_opt\"));\n        forceDexOpt.setVisible(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N);\n        forceDexOpt.setChecked(Prefs.Installer.forceDexOpt());\n        // Display changes\n        ((SwitchPreferenceCompat) Objects.requireNonNull(findPreference(\"installer_display_changes\")))\n                .setChecked(Prefs.Installer.displayChanges());\n        // Block trackers\n        SwitchPreferenceCompat blockTrackersPref = Objects.requireNonNull(findPreference(\"installer_block_trackers\"));\n        blockTrackersPref.setVisible(SelfPermissions.canModifyAppComponentStates(UserHandleHidden.myUserId(), null, true));\n        blockTrackersPref.setChecked(Prefs.Installer.blockTrackers());\n        // Running installer in the background\n        SwitchPreferenceCompat backgroundPref = Objects.requireNonNull(findPreference(\"installer_always_on_background\"));\n        backgroundPref.setVisible(Utils.canDisplayNotification(requireContext()));\n        backgroundPref.setChecked(Prefs.Installer.installInBackground());\n    }\n\n    @Override\n    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {\n        super.onViewCreated(view, savedInstanceState);\n        // Observe installer app selection\n        mModel.getPackageNameLabelPairLiveData().observe(getViewLifecycleOwner(), this::displayInstallerAppSelectionDialog);\n    }\n\n    @Override\n    public void onCreate(@Nullable Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setEnterTransition(new MaterialSharedAxis(MaterialSharedAxis.Z, true));\n        setReturnTransition(new MaterialSharedAxis(MaterialSharedAxis.Z, false));\n    }\n\n    @Override\n    public int getTitle() {\n        return R.string.installer;\n    }\n\n    public void displayInstallerAppSelectionDialog(@NonNull List<Pair<String, CharSequence>> appInfo) {\n        ArrayList<String> items = new ArrayList<>(appInfo.size());\n        ArrayList<CharSequence> itemNames = new ArrayList<>(appInfo.size());\n        for (Pair<String, CharSequence> pair : appInfo) {\n            items.add(pair.first);\n            itemNames.add(new SpannableStringBuilder(pair.second)\n                    .append(\"\\n\")\n                    .append(getSecondaryText(requireContext(), getSmallerText(pair.first))));\n        }\n        mActivity.progressIndicator.hide();\n        new SearchableSingleChoiceDialogBuilder<>(requireActivity(), items, itemNames)\n                .setTitle(R.string.installer_app)\n                .setSelection(mInstallerApp)\n                .setPositiveButton(R.string.save, (dialog, which, selectedInstallerApp) -> {\n                    if (selectedInstallerApp != null) {\n                        mInstallerApp = selectedInstallerApp;\n                        Prefs.Installer.setInstallerPackageName(mInstallerApp);\n                        mInstallerAppPref.setSummary(PackageUtils.getPackageLabel(mPm, mInstallerApp));\n                    }\n                })\n                .setNegativeButton(R.string.cancel, null)\n                .show();\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/settings/LogViewerPreferences.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.settings;\n\nimport android.app.Activity;\nimport android.content.Intent;\nimport android.graphics.Typeface;\nimport android.os.Bundle;\nimport android.text.InputType;\nimport android.util.Log;\nimport android.view.inputmethod.EditorInfo;\n\nimport androidx.annotation.Nullable;\nimport androidx.core.view.inputmethod.EditorInfoCompat;\nimport androidx.fragment.app.FragmentActivity;\nimport androidx.preference.Preference;\nimport androidx.preference.PreferenceCategory;\nimport androidx.preference.SwitchPreferenceCompat;\n\nimport com.google.android.material.transition.MaterialSharedAxis;\n\nimport java.util.Arrays;\nimport java.util.List;\n\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.logcat.helper.LogcatHelper;\nimport io.github.muntashirakon.AppManager.logcat.helper.PreferenceHelper;\nimport io.github.muntashirakon.AppManager.logcat.struct.LogLine;\nimport io.github.muntashirakon.AppManager.utils.UIUtils;\nimport io.github.muntashirakon.dialog.SearchableMultiChoiceDialogBuilder;\nimport io.github.muntashirakon.dialog.SearchableSingleChoiceDialogBuilder;\nimport io.github.muntashirakon.dialog.TextInputDialogBuilder;\nimport io.github.muntashirakon.preference.TopSwitchPreference;\n\npublic class LogViewerPreferences extends PreferenceFragment {\n    public static final List<Integer> LOG_LEVEL_VALUES = Arrays.asList(Log.VERBOSE, Log.DEBUG, Log.INFO, Log.WARN,\n            Log.ERROR, LogLine.LOG_FATAL);\n    public static final List<CharSequence> LOG_BUFFER_NAMES = Arrays.asList(LogcatHelper.BUFFER_MAIN, LogcatHelper.BUFFER_RADIO,\n            LogcatHelper.BUFFER_EVENTS, LogcatHelper.BUFFER_SYSTEM, LogcatHelper.BUFFER_CRASH);\n    public static final List<Integer> LOG_BUFFERS = Arrays.asList(LogcatHelper.LOG_ID_MAIN, LogcatHelper.LOG_ID_RADIO,\n            LogcatHelper.LOG_ID_EVENTS, LogcatHelper.LOG_ID_SYSTEM, LogcatHelper.LOG_ID_CRASH);\n\n    private static final int MAX_LOG_WRITE_PERIOD = 1000;\n    private static final int MIN_LOG_WRITE_PERIOD = 1;\n    private static final int MAX_DISPLAY_LIMIT = 100000;\n    private static final int MIN_DISPLAY_LIMIT = 1000;\n\n    @Override\n    public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {\n        addPreferencesFromResource(R.xml.preferences_log_viewer);\n        getPreferenceManager().setPreferenceDataStore(new SettingsDataStore());\n\n        FragmentActivity activity = requireActivity();\n        boolean isLogViewerEnabled = FeatureController.isLogViewerEnabled();\n        PreferenceCategory catAppearance = requirePreference(\"cat_appearance\");\n        PreferenceCategory catConf = requirePreference(\"cat_conf\");\n        PreferenceCategory catAdvanced = requirePreference(\"cat_advanced\");\n        TopSwitchPreference useLogViewer = requirePreference(\"use_log_viewer\");\n        useLogViewer.setChecked(isLogViewerEnabled);\n        useLogViewer.setOnPreferenceChangeListener((preference, newValue) -> {\n            boolean isEnabled = (boolean) newValue;\n            enablePrefs(isEnabled, catAppearance, catAdvanced, catConf);\n            FeatureController.getInstance().modifyState(FeatureController.FEAT_LOG_VIEWER, isEnabled);\n            return true;\n        });\n        enablePrefs(isLogViewerEnabled, catAppearance, catAdvanced, catConf);\n\n        SwitchPreferenceCompat expandByDefault = requirePreference(\"log_viewer_expand_by_default\");\n        expandByDefault.setChecked(Prefs.LogViewer.expandByDefault());\n\n        SwitchPreferenceCompat showPidTidTimestamp = requirePreference(\"log_viewer_show_pid_tid_timestamp\");\n        showPidTidTimestamp.setChecked(Prefs.LogViewer.showPidTidTimestamp());\n\n        SwitchPreferenceCompat omitSensitiveInfo = requirePreference(\"log_viewer_omit_sensitive_info\");\n        omitSensitiveInfo.setChecked(Prefs.LogViewer.omitSensitiveInfo());\n        omitSensitiveInfo.setOnPreferenceChangeListener((preference, newValue) -> {\n            LogLine.omitSensitiveInfo = (boolean) newValue;\n            return true;\n        });\n\n        Preference filterPattern = requirePreference(\"log_viewer_filter_pattern\");\n        filterPattern.setOnPreferenceClickListener(preference -> {\n            new TextInputDialogBuilder(activity, null)\n                    .setTitle(R.string.pref_filter_pattern_title)\n                    .setInputText(Prefs.LogViewer.getFilterPattern())\n                    .setInputTypeface(Typeface.MONOSPACE)\n                    .setInputImeOptions(EditorInfo.IME_ACTION_DONE | EditorInfoCompat.IME_FLAG_NO_PERSONALIZED_LEARNING)\n                    .setPositiveButton(R.string.save, (dialog, which, inputText, isChecked) -> {\n                        if (inputText == null) return;\n                        Prefs.LogViewer.setFilterPattern(inputText.toString().trim());\n                        UIUtils.displayLongToast(R.string.restart_log_viewer_to_see_changes);\n                    })\n                    .setNegativeButton(R.string.cancel, null)\n                    .setNeutralButton(R.string.reset_to_default, (dialog, which, inputText, isChecked) -> {\n                        Prefs.LogViewer.setFilterPattern(activity.getString(R.string.pref_filter_pattern_default));\n                        UIUtils.displayLongToast(R.string.restart_log_viewer_to_see_changes);\n                    })\n                    .show();\n            return true;\n        });\n\n        Preference displayLimit = requirePreference(\"log_viewer_display_limit\");\n        displayLimit.setSummary(getString(R.string.pref_display_limit_summary, Prefs.LogViewer.getDisplayLimit()));\n        displayLimit.setOnPreferenceClickListener(preference -> {\n            new TextInputDialogBuilder(activity, null)\n                    .setTitle(R.string.pref_display_limit_title)\n                    .setHelperText(getString(R.string.pref_display_limit_hint, MIN_DISPLAY_LIMIT, MAX_DISPLAY_LIMIT))\n                    .setInputText(String.valueOf(Prefs.LogViewer.getDisplayLimit()))\n                    .setInputInputType(InputType.TYPE_CLASS_NUMBER)\n                    .setInputImeOptions(EditorInfo.IME_ACTION_DONE | EditorInfoCompat.IME_FLAG_NO_PERSONALIZED_LEARNING)\n                    .setPositiveButton(R.string.save, (dialog, which, inputText, isChecked) -> {\n                        if (inputText == null) return;\n                        try {\n                            int displayLimitInt = Integer.parseInt(inputText.toString().trim());\n                            if (displayLimitInt >= MIN_DISPLAY_LIMIT && displayLimitInt <= MAX_DISPLAY_LIMIT) {\n                                Prefs.LogViewer.setDisplayLimit(displayLimitInt);\n                                UIUtils.displayLongToast(R.string.restart_log_viewer_to_see_changes);\n                                displayLimit.setSummary(getString(R.string.pref_display_limit_summary, displayLimitInt));\n                            }\n                        } catch (NumberFormatException ignore) {\n                        }\n                    })\n                    .setNegativeButton(R.string.cancel, null)\n                    .setNeutralButton(R.string.reset_to_default, (dialog, which, inputText, isChecked) -> {\n                        Prefs.LogViewer.setDisplayLimit(LogcatHelper.DEFAULT_DISPLAY_LIMIT);\n                        UIUtils.displayLongToast(R.string.restart_log_viewer_to_see_changes);\n                        displayLimit.setSummary(getString(R.string.pref_display_limit_summary,\n                                Prefs.LogViewer.getDisplayLimit()));\n                    })\n                    .show();\n            return true;\n        });\n\n        Preference writePeriod = requirePreference(\"log_viewer_write_period\");\n        writePeriod.setSummary(getString(R.string.pref_log_write_period_summary, Prefs.LogViewer.getLogWritingInterval()));\n        writePeriod.setOnPreferenceClickListener(preference -> {\n            new TextInputDialogBuilder(activity, null)\n                    .setTitle(R.string.pref_log_write_period_title)\n                    .setHelperText(getString(R.string.pref_log_line_period_error))\n                    .setInputText(String.valueOf(Prefs.LogViewer.getLogWritingInterval()))\n                    .setInputInputType(InputType.TYPE_CLASS_NUMBER)\n                    .setInputImeOptions(EditorInfo.IME_ACTION_DONE | EditorInfoCompat.IME_FLAG_NO_PERSONALIZED_LEARNING)\n                    .setPositiveButton(R.string.save, (dialog, which, inputText, isChecked) -> {\n                        if (inputText == null) return;\n                        try {\n                            int writePeriodInt = Integer.parseInt(inputText.toString().trim());\n                            if (writePeriodInt >= MIN_LOG_WRITE_PERIOD && writePeriodInt <= MAX_LOG_WRITE_PERIOD) {\n                                Prefs.LogViewer.setLogWritingInterval(writePeriodInt);\n                                UIUtils.displayLongToast(R.string.restart_log_viewer_to_see_changes);\n                                writePeriod.setSummary(getString(R.string.pref_log_write_period_summary, writePeriodInt));\n                            }\n                        } catch (NumberFormatException ignore) {\n                        }\n                    })\n                    .setNegativeButton(R.string.cancel, null)\n                    .setNeutralButton(R.string.reset_to_default, (dialog, which, inputText, isChecked) -> {\n                        Prefs.LogViewer.setLogWritingInterval(LogcatHelper.DEFAULT_LOG_WRITE_INTERVAL);\n                        UIUtils.displayLongToast(R.string.restart_log_viewer_to_see_changes);\n                        writePeriod.setSummary(getString(R.string.pref_log_write_period_summary,\n                                Prefs.LogViewer.getLogWritingInterval()));\n                    })\n                    .show();\n            return true;\n        });\n\n        Preference logLevel = requirePreference(\"log_viewer_default_log_level\");\n        logLevel.setOnPreferenceClickListener(preference -> {\n            CharSequence[] logLevelsLocalised = getResources().getStringArray(R.array.log_levels);\n            new SearchableSingleChoiceDialogBuilder<>(activity, LOG_LEVEL_VALUES, logLevelsLocalised)\n                    .setTitle(R.string.pref_default_log_level_title)\n                    .setSelection(Prefs.LogViewer.getLogLevel())\n                    .setPositiveButton(R.string.save, (dialog, which, newLogLevel) -> {\n                        if (newLogLevel != null) {\n                            Prefs.LogViewer.setLogLevel(newLogLevel);\n                        }\n                    })\n                    .setNegativeButton(R.string.cancel, null)\n                    .setNeutralButton(R.string.reset_to_default, (dialog, which, newLogLevel) -> Prefs.LogViewer.setLogLevel(Log.VERBOSE))\n                    .show();\n            return true;\n        });\n\n        Preference logBuffers = requirePreference(\"log_viewer_buffer\");\n        logBuffers.setOnPreferenceClickListener(preference -> {\n            new SearchableMultiChoiceDialogBuilder<>(activity, LOG_BUFFERS, LOG_BUFFER_NAMES)\n                    .setTitle(R.string.pref_buffer_title)\n                    .addSelections(PreferenceHelper.getBuffers())\n                    .setPositiveButton(R.string.save, (dialog, which, selectedItems) -> {\n                        if (selectedItems.isEmpty()) return;\n                        int bufferFlags = 0;\n                        for (int flag : selectedItems) {\n                            bufferFlags |= flag;\n                        }\n                        int previousFlags = Prefs.LogViewer.getBuffers();\n                        Prefs.LogViewer.setBuffers(bufferFlags);\n                        if (previousFlags != bufferFlags) {\n                            sendBufferChanged(activity);\n                        }\n                    })\n                    .setNegativeButton(R.string.cancel, null)\n                    .setNeutralButton(R.string.reset_to_default, (dialog, which, selectedItems) -> {\n                        int previousFlags = Prefs.LogViewer.getBuffers();\n                        Prefs.LogViewer.setBuffers(LogcatHelper.LOG_ID_DEFAULT);\n                        if (previousFlags != LogcatHelper.LOG_ID_DEFAULT) {\n                            sendBufferChanged(activity);\n                        }\n                    })\n                    .show();\n            return true;\n        });\n    }\n\n    @Override\n    public void onCreate(@Nullable Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setEnterTransition(new MaterialSharedAxis(MaterialSharedAxis.Z, true));\n        setReturnTransition(new MaterialSharedAxis(MaterialSharedAxis.Z, false));\n    }\n\n    public static void sendBufferChanged(FragmentActivity activity) {\n        Intent intent = new Intent().putExtra(\"bufferChanged\", true);\n        activity.setResult(Activity.RESULT_FIRST_USER, intent);\n    }\n\n    @Override\n    public int getTitle() {\n        return R.string.log_viewer;\n    }\n}"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/settings/MainPreferences.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.settings;\n\nimport android.os.Bundle;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.fragment.app.FragmentActivity;\nimport androidx.lifecycle.ViewModelProvider;\nimport androidx.preference.Preference;\n\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.Locale;\n\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.self.life.BuildExpiryChecker;\nimport io.github.muntashirakon.AppManager.self.life.FundingCampaignChecker;\nimport io.github.muntashirakon.AppManager.utils.LangUtils;\nimport io.github.muntashirakon.AppManager.utils.UIUtils;\nimport io.github.muntashirakon.preference.InfoAlertPreference;\nimport io.github.muntashirakon.preference.WarningAlertPreference;\n\npublic class MainPreferences extends PreferenceFragment {\n    @NonNull\n    public static MainPreferences getInstance(@Nullable String key, boolean dualPane) {\n        MainPreferences preferences = new MainPreferences();\n        Bundle args = new Bundle();\n        args.putString(PREF_KEY, key);\n        args.putBoolean(PREF_SECONDARY, dualPane);\n        preferences.setArguments(args);\n        return preferences;\n    }\n\n    private static final List<String> MODE_NAMES = Arrays.asList(\n            Ops.MODE_AUTO,\n            Ops.MODE_ROOT,\n            Ops.MODE_ADB_OVER_TCP,\n            Ops.MODE_ADB_WIFI,\n            Ops.MODE_NO_ROOT);\n\n    private FragmentActivity mActivity;\n    private Preference mModePref;\n    private Preference mLocalePref;\n    private String[] mModes;\n\n    @Override\n    public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {\n        setPreferencesFromResource(R.xml.preferences_main, rootKey);\n        getPreferenceManager().setPreferenceDataStore(new SettingsDataStore());\n        MainPreferencesViewModel model = new ViewModelProvider(requireActivity()).get(MainPreferencesViewModel.class);\n        mActivity = requireActivity();\n        // Expiry notice\n        WarningAlertPreference buildExpiringNotice = requirePreference(\"app_manager_expiring_notice\");\n        buildExpiringNotice.setVisible(!Boolean.FALSE.equals(BuildExpiryChecker.buildExpired()));\n        // Funding campaign notice\n        InfoAlertPreference fundingCampaignNotice = requirePreference(\"funding_campaign_notice\");\n        fundingCampaignNotice.setVisible(FundingCampaignChecker.campaignRunning());\n        // Custom locale\n        mLocalePref = requirePreference(\"custom_locale\");\n        // Mode of operation\n        mModePref = requirePreference(\"mode_of_operations\");\n        mModes = getResources().getStringArray(R.array.modes);\n\n        model.getOperationCompletedLiveData().observe(requireActivity(), completed -> {\n            if (requireActivity() instanceof SettingsActivity) {\n                ((SettingsActivity) requireActivity()).progressIndicator.hide();\n            }\n            UIUtils.displayShortToast(R.string.the_operation_was_successful);\n        });\n    }\n\n    @Override\n    public void onStart() {\n        super.onStart();\n        if (mModePref != null) {\n            mModePref.setSummary(getString(R.string.mode_of_op_with_inferred_mode_of_op,\n                    mModes[MODE_NAMES.indexOf(Ops.getMode())], Ops.getInferredMode(mActivity)));\n        }\n        if (mLocalePref != null) {\n            mLocalePref.setSummary(getLanguageName());\n        }\n    }\n\n    @Override\n    public int getTitle() {\n        return R.string.settings;\n    }\n\n    public CharSequence getLanguageName() {\n        String langTag = Prefs.Appearance.getLanguage();\n        if (LangUtils.LANG_AUTO.equals(langTag)) {\n            return getString(R.string.auto);\n        }\n        Locale locale = Locale.forLanguageTag(langTag);\n        return locale.getDisplayName(locale);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/settings/MainPreferencesViewModel.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.settings;\n\nimport android.app.Application;\nimport android.content.pm.PackageManager;\nimport android.content.pm.ResolveInfo;\nimport android.net.Uri;\nimport android.os.Build;\nimport android.os.PowerManager;\nimport android.os.UserHandleHidden;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.RequiresApi;\nimport androidx.collection.ArrayMap;\nimport androidx.core.util.Pair;\nimport androidx.documentfile.provider.DocumentFileUtils;\nimport androidx.lifecycle.AndroidViewModel;\nimport androidx.lifecycle.LiveData;\nimport androidx.lifecycle.MutableLiveData;\n\nimport org.xmlpull.v1.XmlPullParserException;\n\nimport java.io.IOException;\nimport java.security.cert.Certificate;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\n\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.apk.signing.Signer;\nimport io.github.muntashirakon.AppManager.changelog.Changelog;\nimport io.github.muntashirakon.AppManager.changelog.ChangelogParser;\nimport io.github.muntashirakon.AppManager.crypto.ks.KeyPair;\nimport io.github.muntashirakon.AppManager.crypto.ks.KeyStoreManager;\nimport io.github.muntashirakon.AppManager.db.entity.App;\nimport io.github.muntashirakon.AppManager.db.utils.AppDb;\nimport io.github.muntashirakon.AppManager.misc.DeviceInfo2;\nimport io.github.muntashirakon.AppManager.rules.compontents.ComponentUtils;\nimport io.github.muntashirakon.AppManager.rules.compontents.ComponentsBlocker;\nimport io.github.muntashirakon.AppManager.servermanager.ServerConfig;\nimport io.github.muntashirakon.AppManager.users.UserInfo;\nimport io.github.muntashirakon.AppManager.users.Users;\nimport io.github.muntashirakon.AppManager.utils.CpuUtils;\nimport io.github.muntashirakon.AppManager.utils.DigestUtils;\nimport io.github.muntashirakon.AppManager.utils.StorageUtils;\nimport io.github.muntashirakon.AppManager.utils.ThreadUtils;\nimport io.github.muntashirakon.lifecycle.SingleLiveEvent;\n\npublic class MainPreferencesViewModel extends AndroidViewModel implements Ops.AdbConnectionInterface {\n    private final Object mRulesLock = new Object();\n    private final MutableLiveData<List<UserInfo>> mSelectUsers = new SingleLiveEvent<>();\n    private final MutableLiveData<Changelog> mChangeLog = new SingleLiveEvent<>();\n    private final MutableLiveData<DeviceInfo2> mDeviceInfo = new SingleLiveEvent<>();\n    private final MutableLiveData<String> mCustomCommand0 = new SingleLiveEvent<>();\n    private final MutableLiveData<String> mCustomCommand1 = new SingleLiveEvent<>();\n    private final MutableLiveData<Integer> mModeOfOpsStatus = new SingleLiveEvent<>();\n    private final MutableLiveData<Boolean> mOperationCompletedLiveData = new SingleLiveEvent<>();\n    private final MutableLiveData<ArrayMap<String, Uri>> mStorageVolumesLiveData = new SingleLiveEvent<>();\n    private final MutableLiveData<String> mSigningKeySha256HashLiveData = new SingleLiveEvent<>();\n    private final MutableLiveData<List<Pair<String, CharSequence>>> mPackageNameLabelPairLiveData = new SingleLiveEvent<>();\n    private final ExecutorService mExecutor = Executors.newFixedThreadPool(1);\n\n    public MainPreferencesViewModel(@NonNull Application application) {\n        super(application);\n    }\n\n    public LiveData<List<UserInfo>> selectUsers() {\n        return mSelectUsers;\n    }\n\n    public void loadAllUsers() {\n        ThreadUtils.postOnBackgroundThread(() -> mSelectUsers.postValue(Users.getAllUsers()));\n    }\n\n    public LiveData<Changelog> getChangeLog() {\n        return mChangeLog;\n    }\n\n    public void loadChangeLog() {\n        ThreadUtils.postOnBackgroundThread(() -> {\n            try {\n                Changelog changelog = new ChangelogParser(getApplication(), R.raw.changelog).parse();\n                mChangeLog.postValue(changelog);\n            } catch (IOException | XmlPullParserException e) {\n                e.printStackTrace();\n            }\n        });\n    }\n\n    public LiveData<DeviceInfo2> getDeviceInfo() {\n        return mDeviceInfo;\n    }\n\n    public void loadDeviceInfo(@NonNull DeviceInfo2 di) {\n        ThreadUtils.postOnBackgroundThread(() -> {\n            di.loadInfo();\n            mDeviceInfo.postValue(di);\n        });\n    }\n\n    public void reloadApps() {\n        ThreadUtils.postOnBackgroundThread(() -> {\n            PowerManager.WakeLock wakeLock = CpuUtils.getPartialWakeLock(\"appDbUpdater\");\n            try {\n                wakeLock.acquire();\n                AppDb appDb = new AppDb();\n                appDb.deleteAllApplications();\n                appDb.deleteAllBackups();\n                appDb.loadInstalledOrBackedUpApplications(getApplication());\n            } finally {\n                CpuUtils.releaseWakeLock(wakeLock);\n            }\n        });\n    }\n\n    public MutableLiveData<String> getCustomCommand0() {\n        return mCustomCommand0;\n    }\n\n    public MutableLiveData<String> getCustomCommand1() {\n        return mCustomCommand1;\n    }\n\n    public void loadCustomCommands() {\n        mExecutor.submit(() -> {\n            try {\n                ServerConfig.init(getApplication());\n                mCustomCommand0.postValue(ServerConfig.getServerRunnerCommand(0));\n                mCustomCommand1.postValue(ServerConfig.getServerRunnerCommand(1));\n            } catch (Throwable e) {\n                e.printStackTrace();\n                mCustomCommand0.postValue(null);\n                mCustomCommand1.postValue(null);\n            }\n        });\n    }\n\n    public LiveData<Integer> getModeOfOpsStatus() {\n        return mModeOfOpsStatus;\n    }\n\n    public void setModeOfOps() {\n        mExecutor.submit(() -> {\n            int status = Ops.init(getApplication(), true);\n            mModeOfOpsStatus.postValue(status);\n        });\n    }\n\n    public LiveData<Boolean> getOperationCompletedLiveData() {\n        return mOperationCompletedLiveData;\n    }\n\n    public void applyAllRules() {\n        ThreadUtils.postOnBackgroundThread(() -> {\n            synchronized (mRulesLock) {\n                // TODO: 13/8/22 Synchronise in ComponentsBlocker instead of here\n                ComponentsBlocker.applyAllRules(getApplication(), UserHandleHidden.myUserId());\n            }\n        });\n    }\n\n    public void removeAllRules() {\n        ThreadUtils.postOnBackgroundThread(() -> {\n            int[] userHandles = Users.getUsersIds();\n            List<String> packages = ComponentUtils.getAllPackagesWithRules(getApplication());\n            for (int userHandle : userHandles) {\n                for (String packageName : packages) {\n                    ComponentUtils.removeAllRules(packageName, userHandle);\n                }\n            }\n            mOperationCompletedLiveData.postValue(true);\n        });\n    }\n\n    public LiveData<ArrayMap<String, Uri>> getStorageVolumesLiveData() {\n        return mStorageVolumesLiveData;\n    }\n\n    public void loadStorageVolumes() {\n        ThreadUtils.postOnBackgroundThread(() -> {\n            ArrayMap<String, Uri> locations = StorageUtils.getAllStorageLocations(getApplication());\n            ArrayMap<String, Uri> newLocations = new ArrayMap<>(locations.size());\n            PackageManager pm = getApplication().getPackageManager();\n            for (int i = 0; i < locations.size(); ++i) {\n                Uri uri = locations.valueAt(i);\n                String authority = uri.getAuthority();\n                if (authority != null) {\n                    ResolveInfo resolveInfo = DocumentFileUtils.getUriSource(getApplication(), uri);\n                    String readableName = resolveInfo != null\n                            ? resolveInfo.loadLabel(pm).toString()\n                            : locations.keyAt(i);\n                    newLocations.put(readableName, locations.valueAt(i));\n                } else newLocations.put(locations.keyAt(i), locations.valueAt(i));\n            }\n            mStorageVolumesLiveData.postValue(newLocations);\n        });\n    }\n\n    public LiveData<String> getSigningKeySha256HashLiveData() {\n        return mSigningKeySha256HashLiveData;\n    }\n\n    public void loadSigningKeySha256Hash() {\n        mExecutor.submit(() -> {\n            String hash = null;\n            try {\n                KeyStoreManager keyStoreManager = KeyStoreManager.getInstance();\n                if (keyStoreManager.containsKey(Signer.SIGNING_KEY_ALIAS)) {\n                    KeyPair keyPair = keyStoreManager.getKeyPair(Signer.SIGNING_KEY_ALIAS);\n                    if (keyPair != null) {\n                        Certificate certificate = keyPair.getCertificate();\n                        hash = DigestUtils.getHexDigest(DigestUtils.SHA_256, certificate.getEncoded());\n                        try {\n                            keyPair.destroy();\n                        } catch (Exception ignore) {\n                        }\n                    }\n                }\n            } catch (Exception e) {\n                e.printStackTrace();\n            }\n            mSigningKeySha256HashLiveData.postValue(hash);\n        });\n    }\n\n    public LiveData<List<Pair<String, CharSequence>>> getPackageNameLabelPairLiveData() {\n        return mPackageNameLabelPairLiveData;\n    }\n\n    public void loadPackageNameLabelPair() {\n        mExecutor.submit(() -> {\n            List<App> appList = new AppDb().getAllApplications();\n            Map<String, CharSequence> packageNameLabelMap = new HashMap<>(appList.size());\n            for (App app : appList) {\n                packageNameLabelMap.put(app.packageName, app.packageLabel);\n            }\n            List<Pair<String, CharSequence>> appInfo = new ArrayList<>();\n            for (String packageName : packageNameLabelMap.keySet()) {\n                appInfo.add(new Pair<>(packageName, packageNameLabelMap.get(packageName)));\n            }\n            Collections.sort(appInfo, (o1, o2) -> o1.second.toString().compareTo(o2.second.toString()));\n            mPackageNameLabelPairLiveData.postValue(appInfo);\n        });\n    }\n\n    @RequiresApi(Build.VERSION_CODES.R)\n    public void autoConnectWirelessDebugging() {\n        mExecutor.submit(() -> {\n            int status = Ops.autoConnectWirelessDebugging(getApplication());\n            mModeOfOpsStatus.postValue(status);\n        });\n    }\n\n    @Override\n    public void connectAdb(int port) {\n        mExecutor.submit(() -> {\n            int status = Ops.connectAdb(getApplication(), port, Ops.STATUS_FAILURE);\n            mModeOfOpsStatus.postValue(status);\n        });\n    }\n\n    @Override\n    @RequiresApi(Build.VERSION_CODES.R)\n    public void pairAdb() {\n        mExecutor.submit(() -> {\n            int status = Ops.pairAdb(getApplication());\n            mModeOfOpsStatus.postValue(status);\n        });\n    }\n\n    @Override\n    public void onStatusReceived(int status) {\n        mModeOfOpsStatus.postValue(status);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/settings/ModeOfOpsPreference.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.settings;\n\nimport android.content.res.ColorStateList;\nimport android.os.Build;\nimport android.os.Bundle;\nimport android.os.Process;\nimport android.text.TextUtils;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\n\nimport androidx.annotation.DrawableRes;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.appcompat.app.AlertDialog;\nimport androidx.core.widget.TextViewCompat;\nimport androidx.fragment.app.Fragment;\nimport androidx.lifecycle.ViewModelProvider;\n\nimport com.google.android.material.button.MaterialButton;\nimport com.google.android.material.color.MaterialColors;\nimport com.google.android.material.textfield.TextInputLayout;\nimport com.google.android.material.textview.MaterialTextView;\n\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\n\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.ipc.LocalServices;\nimport io.github.muntashirakon.AppManager.servermanager.LocalServer;\nimport io.github.muntashirakon.AppManager.servermanager.ServerConfig;\nimport io.github.muntashirakon.AppManager.users.Users;\nimport io.github.muntashirakon.AppManager.utils.UIUtils;\nimport io.github.muntashirakon.AppManager.utils.Utils;\nimport io.github.muntashirakon.dialog.SearchableSingleChoiceDialogBuilder;\nimport io.github.muntashirakon.util.UiUtils;\nimport io.github.muntashirakon.view.TextInputLayoutCompat;\nimport io.github.muntashirakon.widget.TextInputTextView;\n\npublic class ModeOfOpsPreference extends Fragment {\n    private static final List<String> MODE_NAMES = Arrays.asList(\n            Ops.MODE_AUTO,\n            Ops.MODE_ROOT,\n            Ops.MODE_ADB_OVER_TCP,\n            Ops.MODE_ADB_WIFI,\n            Ops.MODE_NO_ROOT);\n\n    private MaterialTextView mInferredModeView;\n    private MaterialTextView mRemoteServerStatusView;\n    private MaterialTextView mRemoteServicesStatusView;\n    private MaterialTextView mModeOfOpsView;\n    private MainPreferencesViewModel mModel;\n    private AlertDialog mModeOfOpsAlertDialog;\n    private String[] mModes;\n    @Ops.Mode\n    private String mCurrentMode;\n    private boolean mConnecting;\n    @Nullable\n    private ColorStateList mColorActive;\n    @Nullable\n    private ColorStateList mColorInactive;\n    @Nullable\n    private ColorStateList mColorError;\n    @DrawableRes\n    private int mIconActive;\n    @DrawableRes\n    private int mIconInactive;\n    @DrawableRes\n    private int mIconProgress;\n\n    @Override\n    public void onCreate(@Nullable Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        mModel = new ViewModelProvider(requireActivity()).get(MainPreferencesViewModel.class);\n    }\n\n    @Nullable\n    @Override\n    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {\n        View view = inflater.inflate(R.layout.fragment_mode_of_ops, container, false);\n        boolean secondary = false;\n        if (getArguments() != null) {\n            secondary = requireArguments().getBoolean(PreferenceFragment.PREF_SECONDARY);\n            requireArguments().remove(PreferenceFragment.PREF_KEY);\n            requireArguments().remove(PreferenceFragment.PREF_SECONDARY);\n        }\n        if (secondary) {\n            UiUtils.applyWindowInsetsAsPadding(view, false, true, false, true);\n        } else UiUtils.applyWindowInsetsAsPaddingNoTop(view);\n        return view;\n    }\n\n    @Override\n    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {\n        mColorActive = MaterialColors.getColorStateListOrNull(view.getContext(), com.google.android.material.R.attr.colorOnPrimaryContainer);\n        mColorInactive = MaterialColors.getColorStateListOrNull(view.getContext(), com.google.android.material.R.attr.colorOutline);\n        mColorError = MaterialColors.getColorStateListOrNull(view.getContext(), com.google.android.material.R.attr.colorOnErrorContainer);\n        mIconActive = R.drawable.ic_check_circle;\n        mIconInactive = io.github.muntashirakon.ui.R.drawable.ic_caution;\n        mIconProgress = R.drawable.ic_sync;\n        mModeOfOpsAlertDialog = UIUtils.getProgressDialog(requireActivity(), getString(R.string.loading), true);\n        mModes = getResources().getStringArray(R.array.modes);\n        mCurrentMode = Ops.getMode();\n        mInferredModeView = view.findViewById(R.id.inferred_mode);\n        mRemoteServerStatusView = view.findViewById(R.id.remote_server_status);\n        mRemoteServicesStatusView = view.findViewById(R.id.remote_services_status);\n        mModeOfOpsView = view.findViewById(R.id.op_name);\n        MaterialButton changeModeView = view.findViewById(R.id.action_settings);\n        List<String> disabledItems;\n        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.R || Utils.isTv(requireContext())) {\n            disabledItems = Collections.singletonList(Ops.MODE_ADB_WIFI);\n        } else disabledItems = null;\n        changeModeView.setOnClickListener(v -> new SearchableSingleChoiceDialogBuilder<>(requireActivity(), MODE_NAMES, mModes)\n                .setTitle(R.string.pref_mode_of_operations)\n                .setSelection(mCurrentMode)\n                .addDisabledItems(disabledItems)\n                .setPositiveButton(R.string.apply, (dialog, which, selectedItem) -> {\n                    if (selectedItem != null) {\n                        mCurrentMode = selectedItem;\n                        if (Ops.MODE_ADB_OVER_TCP.equals(mCurrentMode)) {\n                            ServerConfig.setAdbPort(ServerConfig.DEFAULT_ADB_PORT);\n                        }\n                        Ops.setMode(mCurrentMode);\n                        mModeOfOpsAlertDialog.show();\n                        mConnecting = true;\n                        updateViews();\n                        mModel.setModeOfOps();\n                    }\n                })\n                .setNegativeButton(R.string.cancel, null)\n                .show());\n        TextInputTextView customCommand0 = view.findViewById(android.R.id.text1);\n        TextInputLayout customCommand0Layout = TextInputLayoutCompat.fromTextInputEditText(customCommand0);\n        customCommand0Layout.setEndIconOnClickListener(v -> {\n            CharSequence command = customCommand0.getText();\n            if (!TextUtils.isEmpty(command)) {\n                Utils.copyToClipboard(requireContext(), \"command\", command);\n            }\n        });\n        TextInputTextView customCommand1 = view.findViewById(android.R.id.text2);\n        TextInputLayout customCommand1Layout = TextInputLayoutCompat.fromTextInputEditText(customCommand1);\n        customCommand1Layout.setEndIconOnClickListener(v -> {\n            CharSequence command = customCommand1.getText();\n            if (!TextUtils.isEmpty(command)) {\n                Utils.copyToClipboard(requireContext(), \"command\", command);\n            }\n        });\n        mModel.loadCustomCommands();\n        updateViews();\n        // Mode of ops\n        mModel.getModeOfOpsStatus().observe(getViewLifecycleOwner(), status -> {\n            switch (status) {\n                case Ops.STATUS_AUTO_CONNECT_WIRELESS_DEBUGGING:\n                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {\n                        updateViews();\n                        mModel.autoConnectWirelessDebugging();\n                        return;\n                    } // fall-through\n                case Ops.STATUS_WIRELESS_DEBUGGING_CHOOSER_REQUIRED:\n                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {\n                        mModeOfOpsAlertDialog.dismiss();\n                        updateViews();\n                        Ops.connectWirelessDebugging(requireActivity(), mModel);\n                        return;\n                    } // fall-through\n                case Ops.STATUS_ADB_CONNECT_REQUIRED:\n                    mModeOfOpsAlertDialog.dismiss();\n                    updateViews();\n                    Ops.connectAdbInput(requireActivity(), mModel);\n                    return;\n                case Ops.STATUS_ADB_PAIRING_REQUIRED:\n                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {\n                        mModeOfOpsAlertDialog.dismiss();\n                        updateViews();\n                        Ops.pairAdbInput(requireActivity(), mModel);\n                        return;\n                    } // fall-through\n                case Ops.STATUS_FAILURE_ADB_NEED_MORE_PERMS:\n                    Ops.displayIncompleteUsbDebuggingMessage(requireActivity());\n                case Ops.STATUS_SUCCESS:\n                case Ops.STATUS_FAILURE:\n                    mConnecting = false;\n                    mModeOfOpsAlertDialog.dismiss();\n                    mCurrentMode = Ops.getMode();\n                    updateViews();\n            }\n        });\n        mModel.getCustomCommand0().observe(getViewLifecycleOwner(), customCommand0::setText);\n        mModel.getCustomCommand1().observe(getViewLifecycleOwner(), customCommand1::setText);\n    }\n\n    @Override\n    public void onStart() {\n        super.onStart();\n        requireActivity().setTitle(R.string.pref_mode_of_operations);\n    }\n\n    private void updateViews() {\n        boolean serverActive = LocalServer.alive(requireContext());\n        boolean serverRequired = requireRemoteServer(mCurrentMode);\n        boolean servicesActive = LocalServices.alive();\n        boolean servicesRequired = requireRemoteServices(mCurrentMode);\n        // Mode\n        if (mConnecting) {\n            mInferredModeView.setText(R.string.status_connecting);\n            mInferredModeView.setTextColor(mColorActive);\n            TextViewCompat.setCompoundDrawableTintList(mModeOfOpsView, mColorActive);\n            mModeOfOpsView.setTextColor(mColorActive);\n            mModeOfOpsView.setCompoundDrawablesRelativeWithIntrinsicBounds(mIconProgress, 0, 0, 0);\n            mModeOfOpsView.setText(getString(R.string.status_connecting_via_mode, mModes[MODE_NAMES.indexOf(mCurrentMode)]));\n        } else {\n            int uid = Users.getSelfOrRemoteUid();\n            boolean goodMode = !badInferredMode(mCurrentMode, uid);\n            mInferredModeView.setText(Ops.getInferredMode(requireContext()));\n            if (goodMode) {\n                mInferredModeView.setTextColor(mColorActive);\n                TextViewCompat.setCompoundDrawableTintList(mModeOfOpsView, mColorActive);\n                mModeOfOpsView.setTextColor(mColorActive);\n                mModeOfOpsView.setCompoundDrawablesRelativeWithIntrinsicBounds(mIconActive, 0, 0, 0);\n                CharSequence mode;\n                if (serverActive && uid != Process.myUid()) {\n                    mode = \"remote service\";\n                } else mode = mModes[MODE_NAMES.indexOf(mCurrentMode)];\n                mModeOfOpsView.setText(getString(R.string.status_connected_via_mode, mode));\n            } else {\n                mInferredModeView.setTextColor(mColorError);\n                TextViewCompat.setCompoundDrawableTintList(mModeOfOpsView, mColorError);\n                mModeOfOpsView.setTextColor(mColorError);\n                mModeOfOpsView.setCompoundDrawablesRelativeWithIntrinsicBounds(mIconInactive, 0, 0, 0);\n                mModeOfOpsView.setText(getString(R.string.status_not_connected_via_mode, mModes[MODE_NAMES.indexOf(mCurrentMode)]));\n            }\n        }\n        // Server\n        if (serverRequired) {\n            mRemoteServerStatusView.setTextColor(serverActive ? mColorActive : mColorError);\n            TextViewCompat.setCompoundDrawableTintList(mRemoteServerStatusView, serverActive ? mColorActive : mColorError);\n        } else {\n            mRemoteServerStatusView.setTextColor(mColorInactive);\n            TextViewCompat.setCompoundDrawableTintList(mRemoteServerStatusView, mColorInactive);\n        }\n        mRemoteServerStatusView.setCompoundDrawablesRelativeWithIntrinsicBounds(serverActive ? mIconActive : mIconInactive, 0, 0, 0);\n        mRemoteServerStatusView.setText(serverActive ? R.string.status_remote_server_active : R.string.status_remote_server_inactive);\n        // Services\n        if (servicesRequired) {\n            mRemoteServicesStatusView.setTextColor(servicesActive ? mColorActive : mColorError);\n            TextViewCompat.setCompoundDrawableTintList(mRemoteServicesStatusView, servicesActive ? mColorActive : mColorError);\n        } else {\n            mRemoteServicesStatusView.setTextColor(mColorInactive);\n            TextViewCompat.setCompoundDrawableTintList(mRemoteServicesStatusView, mColorInactive);\n        }\n        mRemoteServicesStatusView.setCompoundDrawablesRelativeWithIntrinsicBounds(servicesActive ? mIconActive : mIconInactive, 0, 0, 0);\n        mRemoteServicesStatusView.setText(servicesActive ? R.string.status_remote_services_active : R.string.status_remote_services_inactive);\n    }\n\n    private static boolean requireRemoteServer(@NonNull String mode) {\n        return Ops.MODE_ADB_OVER_TCP.equals(mode) || Ops.MODE_ADB_WIFI.equals(mode);\n    }\n\n    private static boolean requireRemoteServices(@NonNull String mode) {\n        return !Ops.MODE_AUTO.equals(mode) && !Ops.MODE_NO_ROOT.equals(mode);\n    }\n\n    private static boolean badInferredMode(@NonNull String mode, int uid) {\n        switch (mode) {\n            case Ops.MODE_ROOT:\n                return uid != Ops.ROOT_UID;\n            case Ops.MODE_ADB_OVER_TCP:\n            case Ops.MODE_ADB_WIFI:\n                return uid > Ops.SHELL_UID;\n            default:\n                return false;\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/settings/Ops.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.settings;\n\nimport android.Manifest;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.os.Build;\nimport android.os.Process;\nimport android.os.RemoteException;\nimport android.provider.Settings;\nimport android.text.TextUtils;\n\nimport androidx.annotation.AnyThread;\nimport androidx.annotation.GuardedBy;\nimport androidx.annotation.IntDef;\nimport androidx.annotation.MainThread;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.RequiresApi;\nimport androidx.annotation.StringDef;\nimport androidx.annotation.UiThread;\nimport androidx.annotation.WorkerThread;\nimport androidx.core.content.ContextCompat;\nimport androidx.fragment.app.FragmentActivity;\nimport androidx.lifecycle.Observer;\n\nimport com.google.android.material.dialog.MaterialAlertDialogBuilder;\n\nimport java.io.IOException;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.util.Locale;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicReference;\n\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.adb.AdbConnectionManager;\nimport io.github.muntashirakon.AppManager.adb.AdbPairingService;\nimport io.github.muntashirakon.AppManager.adb.AdbUtils;\nimport io.github.muntashirakon.AppManager.compat.ManifestCompat;\nimport io.github.muntashirakon.AppManager.ipc.LocalServices;\nimport io.github.muntashirakon.AppManager.logcat.helper.ServiceHelper;\nimport io.github.muntashirakon.AppManager.logs.Log;\nimport io.github.muntashirakon.AppManager.misc.NoOps;\nimport io.github.muntashirakon.AppManager.runner.RunnerUtils;\nimport io.github.muntashirakon.AppManager.self.SelfPermissions;\nimport io.github.muntashirakon.AppManager.servermanager.LocalServer;\nimport io.github.muntashirakon.AppManager.servermanager.ServerConfig;\nimport io.github.muntashirakon.AppManager.session.SessionMonitoringService;\nimport io.github.muntashirakon.AppManager.users.Owners;\nimport io.github.muntashirakon.AppManager.users.Users;\nimport io.github.muntashirakon.AppManager.utils.AppPref;\nimport io.github.muntashirakon.AppManager.utils.ExUtils;\nimport io.github.muntashirakon.AppManager.utils.ThreadUtils;\nimport io.github.muntashirakon.AppManager.utils.UIUtils;\nimport io.github.muntashirakon.AppManager.utils.Utils;\nimport io.github.muntashirakon.adb.AdbPairingRequiredException;\nimport io.github.muntashirakon.dialog.DialogTitleBuilder;\nimport io.github.muntashirakon.dialog.ScrollableDialogBuilder;\nimport io.github.muntashirakon.dialog.TextInputDialogBuilder;\n\n/**\n * Controls mode of operation and other related functions\n */\npublic class Ops {\n    public static final String TAG = Ops.class.getSimpleName();\n\n    @StringDef({MODE_AUTO, MODE_ROOT, MODE_ADB_OVER_TCP, MODE_ADB_WIFI, MODE_NO_ROOT})\n    @Retention(RetentionPolicy.SOURCE)\n    public @interface Mode {\n    }\n\n    public static final String MODE_AUTO = \"auto\";\n    public static final String MODE_ROOT = \"root\";\n    public static final String MODE_ADB_OVER_TCP = \"adb_tcp\";\n    public static final String MODE_ADB_WIFI = \"adb_wifi\";\n    public static final String MODE_NO_ROOT = \"no-root\";\n\n    @IntDef({\n            STATUS_SUCCESS,\n            STATUS_FAILURE,\n            STATUS_AUTO_CONNECT_WIRELESS_DEBUGGING,\n            STATUS_WIRELESS_DEBUGGING_CHOOSER_REQUIRED,\n            STATUS_ADB_PAIRING_REQUIRED,\n            STATUS_ADB_CONNECT_REQUIRED,\n            STATUS_FAILURE_ADB_NEED_MORE_PERMS,\n    })\n    @Retention(RetentionPolicy.SOURCE)\n    public @interface Status {\n    }\n\n    public static final int STATUS_SUCCESS = 0;\n    public static final int STATUS_FAILURE = 1;\n    public static final int STATUS_AUTO_CONNECT_WIRELESS_DEBUGGING = 2;\n    public static final int STATUS_WIRELESS_DEBUGGING_CHOOSER_REQUIRED = 3;\n    public static final int STATUS_ADB_PAIRING_REQUIRED = 4;\n    public static final int STATUS_ADB_CONNECT_REQUIRED = 5;\n    public static final int STATUS_FAILURE_ADB_NEED_MORE_PERMS = 6;\n\n    public static int ROOT_UID = 0;\n    public static int SHELL_UID = 2000;\n    public static int PHONE_UID = Process.PHONE_UID;\n    public static int SYSTEM_UID = Process.SYSTEM_UID;\n\n    private static volatile int sWorkingUid = Process.myUid();\n    private static volatile boolean sDirectRoot = false; // AM has root AND that root is being used\n    private static boolean sIsAdb = false; // UID = 2000\n    private static boolean sIsSystem = false; // UID = 1000\n    private static boolean sIsRoot = false; // UID = 0\n\n    // Security\n    private static final Object sSecurityLock = new Object();\n    @GuardedBy(\"sSecurityLock\")\n    private static boolean sIsAuthenticated = false;\n\n    private Ops() {\n    }\n\n    @AnyThread\n    public static int getWorkingUid() {\n        return sWorkingUid;\n    }\n\n    @AnyThread\n    public static void setWorkingUid(int newUid) {\n        sWorkingUid = newUid;\n    }\n\n    @AnyThread\n    public static int getWorkingUidOrRoot() {\n        int uid = getWorkingUid();\n        if (uid != ROOT_UID && sDirectRoot) {\n            return ROOT_UID;\n        }\n        return uid;\n    }\n\n    @AnyThread\n    public static boolean isWorkingUidRoot() {\n        return getWorkingUid() == ROOT_UID;\n    }\n\n    /**\n     * Whether App Manager is currently using direct root (e.g. root granted to the app) to perform operations. The\n     * result returned by this method may not reflect the actual state due to other factors.\n     */\n    @AnyThread\n    public static boolean isDirectRoot() {\n        return sDirectRoot;\n    }\n\n    /**\n     * Whether App Manager is running in system mode\n     */\n    @AnyThread\n    public static boolean isSystem() {\n        return sIsSystem;\n    }\n\n    /**\n     * Whether App Manager is running in ADB mode\n     */\n    @AnyThread\n    public static boolean isAdb() {\n        return sIsAdb;\n    }\n\n    /**\n     * Whether the current App Manager session is authenticated by the user. It does two things:\n     * <ol>\n     *     <li>If security is enabled, it marks that the user has got passed the security challenge.\n     *     <li>It checks if a mode of operation is set before proceeding further.\n     * </ol>\n     */\n    @GuardedBy(\"sSecurityLock\")\n    @AnyThread\n    public static boolean isAuthenticated() {\n        synchronized (sSecurityLock) {\n            return sIsAuthenticated;\n        }\n    }\n\n    @GuardedBy(\"sSecurityLock\")\n    @MainThread\n    public static void setAuthenticated(@NonNull Context context, boolean authenticated) {\n        synchronized (sSecurityLock) {\n            sIsAuthenticated = authenticated;\n            if (Prefs.Privacy.isPersistentSessionAllowed()) {\n                Intent service = new Intent(context, SessionMonitoringService.class);\n                if (authenticated) {\n                    ContextCompat.startForegroundService(context, service);\n                } else {\n                    context.stopService(service);\n                }\n            }\n        }\n    }\n\n    @NonNull\n    public static CharSequence getInferredMode(@NonNull Context context) {\n        int uid = Users.getSelfOrRemoteUid();\n        if (uid == ROOT_UID) {\n            return context.getString(R.string.root);\n        }\n        if (uid == SHELL_UID) {\n            return \"ADB\";\n        }\n        if (uid != Process.myUid()) {\n            String uidStr = Owners.getUidOwnerMap(false).get(uid);\n            if (!TextUtils.isEmpty(uidStr)) {\n                return uidStr.substring(0, 1).toUpperCase(Locale.ROOT)\n                        + (uidStr.length() > 1 ? uidStr.substring(1) : \"\");\n            }\n        }\n        return context.getString(R.string.no_root);\n    }\n\n    @NoOps\n    public static String getMode() {\n        String mode = AppPref.getString(AppPref.PrefKey.PREF_MODE_OF_OPS_STR);\n        // Backward compatibility for v2.6.0\n        if (mode.equals(\"adb\")) {\n            mode = MODE_ADB_OVER_TCP;\n        }\n        if ((MODE_ADB_OVER_TCP.equals(mode) || MODE_ADB_WIFI.equals(mode))\n                && !SelfPermissions.checkSelfPermission(Manifest.permission.INTERNET)) {\n            // ADB enabled but the INTERNET permission is not granted, replace current with auto.\n            return MODE_AUTO;\n        }\n        return mode;\n    }\n\n    @NoOps\n    public static void setMode(@NonNull String newMode) {\n        AppPref.set(AppPref.PrefKey.PREF_MODE_OF_OPS_STR, newMode);\n    }\n\n    @WorkerThread\n    @NoOps // Although we've used Ops checks, its overall usage does not affect anything\n    @Status\n    public static int init(@NonNull Context context, boolean force) {\n        String mode = getMode();\n        sDirectRoot = hasRoot();\n        if (MODE_AUTO.equals(mode)) {\n            autoDetectRootSystemOrAdbAndPersist(context);\n            return sIsAdb ? STATUS_SUCCESS : initPermissionsWithSuccess();\n        }\n        if (MODE_NO_ROOT.equals(mode)) {\n            sDirectRoot = false;\n            sIsAdb = sIsSystem = sIsRoot = false;\n            // Also, stop existing services if any\n            if (LocalServices.alive()) {\n                LocalServices.stopServices();\n            }\n            if (LocalServer.alive(context)) {\n                // We don't care about its results\n                ThreadUtils.postOnBackgroundThread(() -> ExUtils.exceptionAsIgnored(() ->\n                        LocalServer.getInstance().closeBgServer()));\n            }\n            return STATUS_SUCCESS;\n        }\n        if (!force && isAMServiceUpAndRunning(context, mode)) {\n            // An instance of AMService is already running\n            return sIsAdb ? STATUS_SUCCESS : initPermissionsWithSuccess();\n        }\n        try {\n            switch (mode) {\n                case MODE_ROOT:\n                    if (!sDirectRoot) {\n                        throw new Exception(\"Root is unavailable.\");\n                    }\n                    // Disable server first\n                    ExUtils.exceptionAsIgnored(() -> {\n                        if (LocalServer.alive(context)) {\n                            LocalServer.getInstance().closeBgServer();\n                        }\n                    });\n                    sIsSystem = sIsAdb = false;\n                    sIsRoot = true;\n                    LocalServices.bindServicesIfNotAlready();\n                    return initPermissionsWithSuccess();\n                case MODE_ADB_WIFI:\n                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {\n                        if (!Utils.isWifiActive(context.getApplicationContext())) {\n                            throw new Exception(\"Wifi not enabled.\");\n                        }\n                        if (AdbUtils.enableWirelessDebugging(context)) {\n                            // Wireless debugging enabled, try auto-connect\n                            return STATUS_AUTO_CONNECT_WIRELESS_DEBUGGING;\n                        } else {\n                            // Wireless debugging is turned off or there's no permission\n                            return STATUS_WIRELESS_DEBUGGING_CHOOSER_REQUIRED;\n                        }\n                    } // else fallback to ADB over TCP\n                case MODE_ADB_OVER_TCP:\n                    sIsRoot = sIsSystem = false;\n                    sIsAdb = true;\n                    ServerConfig.setAdbPort(findAdbPort(context, 10, AdbUtils.getAdbPortOrDefault()));\n                    LocalServer.restart();\n                    LocalServices.bindServicesIfNotAlready();\n                    return checkRootOrIncompleteUsbDebuggingInAdb();\n            }\n        } catch (Throwable e) {\n            Log.e(TAG, e);\n            // Fallback to no-root mode for this session, this does not modify the user preference\n            sIsAdb = sIsSystem = sIsRoot = false;\n            ThreadUtils.postOnMainThread(() -> UIUtils.displayLongToast(R.string.failed_to_use_the_current_mode_of_operation));\n        }\n        return STATUS_FAILURE;\n    }\n\n    /**\n     * Whether App Manager has been granted root permission.\n     *\n     * @return {@code true} iff root is granted.\n     */\n    @AnyThread\n    @NoOps\n    public static boolean hasRoot() {\n        return RunnerUtils.isRootGiven();\n    }\n\n    @WorkerThread\n    @NoOps // Although we've used Ops checks, its overall usage does not affect anything\n    private static void autoDetectRootSystemOrAdbAndPersist(@NonNull Context context) {\n        sIsRoot = sDirectRoot;\n        if (sDirectRoot) {\n            // Root permission was granted\n            setMode(MODE_ROOT);\n            // Disable remote server\n            ExUtils.exceptionAsIgnored(() -> {\n                if (LocalServer.alive(context)) {\n                    LocalServer.getInstance().closeBgServer();\n                }\n            });\n            // Disable ADB and force root\n            sIsSystem = sIsAdb = false;\n            if (LocalServices.alive()) {\n                if (Users.getSelfOrRemoteUid() == ROOT_UID) {\n                    // Service is already running in root mode\n                    return;\n                }\n                // Service is running in ADB/other mode, but we need root\n                LocalServices.stopServices();\n            }\n            try {\n                // Service is confirmed dead\n                LocalServices.bindServices();\n                if (LocalServices.alive() && Users.getSelfOrRemoteUid() == ROOT_UID) {\n                    // Service is running in root\n                    return;\n                }\n            } catch (RemoteException e) {\n                Log.e(TAG, e);\n            }\n            // Root is granted but Binder communication cannot be initiated\n            Log.e(TAG, \"Root granted but could not use root to initiate a connection. Trying ADB...\");\n            if (AdbUtils.startAdb(AdbUtils.getAdbPortOrDefault())) {\n                Log.i(TAG, \"Started ADB over TCP via root.\");\n            } else {\n                Log.w(TAG, \"Could not start ADB over TCP via root.\");\n            }\n            sIsRoot = false;\n            // Fall-through, in case we can use other options\n        }\n        // Root was not working/granted, but check for AM service just in case\n        if (LocalServices.alive()) {\n            setMode(MODE_ADB_OVER_TCP);\n            int uid = Users.getSelfOrRemoteUid();\n            if (uid == ROOT_UID) {\n                sIsSystem = sIsAdb = false;\n                sIsRoot = true;\n                return;\n            }\n            if (uid == SYSTEM_UID) {\n                sIsRoot = sIsAdb = false;\n                sIsSystem = true;\n                return;\n            }\n            if (uid == SHELL_UID) {\n                sIsRoot = sIsSystem = false;\n                sIsAdb = true;\n                ThreadUtils.postOnMainThread(() -> UIUtils.displayShortToast(R.string.working_on_adb_mode));\n                return;\n            }\n        }\n        // Root not granted\n        if (!SelfPermissions.checkSelfPermission(Manifest.permission.INTERNET)) {\n            // INTERNET permission is not granted\n            setMode(MODE_NO_ROOT);\n            // Skip checking for ADB\n            sIsAdb = false;\n            return;\n        }\n        // Check for ADB\n        if (!AdbUtils.isAdbdRunning()) {\n            // ADB not running. In auto mode, we do not attempt to enable it either\n            setMode(MODE_NO_ROOT);\n            sIsAdb = sIsSystem = sIsRoot = false;\n            return;\n        }\n        sIsAdb = true; // First enable ADB if not already\n        try {\n            ServerConfig.setAdbPort(findAdbPort(context, 7, ServerConfig.getAdbPort()));\n            LocalServer.restart();\n            LocalServices.bindServicesIfNotAlready();\n        } catch (Throwable e) {\n            Log.e(TAG, e);\n        }\n        sIsAdb = LocalServices.alive();\n        if (sIsAdb) {\n            // No need to return anything here because we're in auto-mode.\n            // Any message produced by the method below is just a helpful message.\n            checkRootOrIncompleteUsbDebuggingInAdb();\n        }\n        setMode(getWorkingUid() != Process.myUid() ? MODE_ADB_OVER_TCP : MODE_NO_ROOT);\n    }\n\n    @UiThread\n    @RequiresApi(Build.VERSION_CODES.R)\n    @NoOps // Although we've used Ops checks, its overall usage does not affect anything\n    public static void connectWirelessDebugging(@NonNull FragmentActivity activity,\n                                                @NonNull AdbConnectionInterface callback) {\n        DialogTitleBuilder builder = new DialogTitleBuilder(activity)\n                .setTitle(R.string.wireless_debugging)\n                .setEndIcon(R.drawable.ic_open_in_new, v -> {\n                    Intent intent = new Intent(android.provider.Settings.ACTION_APPLICATION_DEVELOPMENT_SETTINGS)\n                            .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);\n                    activity.startActivity(intent);\n                })\n                .setEndIconContentDescription(R.string.open_developer_options_page);\n\n        new MaterialAlertDialogBuilder(activity)\n                .setCustomTitle(builder.build())\n                .setMessage(R.string.choose_what_to_do)\n                .setCancelable(false)\n                .setPositiveButton(R.string.adb_connect, (dialog1, which1) -> callback.onStatusReceived(STATUS_ADB_CONNECT_REQUIRED))\n                .setNeutralButton(R.string.adb_pair, (dialog1, which1) -> callback.onStatusReceived(STATUS_ADB_PAIRING_REQUIRED))\n                .setNegativeButton(R.string.cancel, (dialog, which) -> callback.connectAdb(-1))\n                .show();\n    }\n\n    @WorkerThread\n    @NoOps // Although we've used Ops checks, its overall usage does not affect anything\n    @Status\n    public static int autoConnectWirelessDebugging(@NonNull Context context) {\n        boolean lastAdb = sIsAdb;\n        boolean lastSystem = sIsSystem;\n        boolean lastRoot = sIsRoot;\n        sIsAdb = true;\n        sIsSystem = sIsRoot = false;\n        try {\n            ServerConfig.setAdbPort(findAdbPort(context, 5, ServerConfig.getAdbPort()));\n            LocalServer.restart();\n            LocalServices.bindServicesIfNotAlready();\n            return checkRootOrIncompleteUsbDebuggingInAdb();\n        } catch (RemoteException | IOException | AdbPairingRequiredException e) {\n            Log.e(TAG, \"Could not auto-connect to adbd\", e);\n            // Go back to the last mode\n            sIsAdb = lastAdb;\n            sIsSystem = lastSystem;\n            sIsRoot = lastRoot;\n            if (e instanceof AdbPairingRequiredException) {\n                // Only pairing is required\n                return STATUS_ADB_PAIRING_REQUIRED;\n            } else return STATUS_WIRELESS_DEBUGGING_CHOOSER_REQUIRED;\n        }\n    }\n\n    @WorkerThread\n    @NoOps // Although we've used Ops checks, its overall usage does not affect anything\n    @Status\n    public static int connectAdb(@NonNull Context context, int port, @Status int returnCodeOnFailure) {\n        if (port < 0) return returnCodeOnFailure;\n        boolean lastAdb = sIsAdb;\n        boolean lastSystem = sIsSystem;\n        boolean lastRoot = sIsRoot;\n        sIsAdb = true;\n        sIsSystem = sIsRoot = false;\n        try {\n            ServerConfig.setAdbPort(port);\n            LocalServer.restart();\n            LocalServices.bindServicesIfNotAlready();\n            return checkRootOrIncompleteUsbDebuggingInAdb();\n        } catch (RemoteException | IOException | AdbPairingRequiredException e) {\n            Log.e(TAG, \"Could not connect to adbd using port \" + port, e);\n            // Go back to the last mode\n            sIsAdb = lastAdb;\n            sIsSystem = lastSystem;\n            sIsRoot = lastRoot;\n            return returnCodeOnFailure;\n        }\n    }\n\n    @UiThread\n    @NoOps\n    public static void connectAdbInput(@NonNull FragmentActivity activity,\n                                       @NonNull AdbConnectionInterface callback) {\n        new TextInputDialogBuilder(activity, R.string.port_number)\n                .setTitle(R.string.wireless_debugging)\n                .setInputText(String.valueOf(ServerConfig.getAdbPort()))\n                .setHelperText(R.string.adb_connect_port_number_description)\n                .setPositiveButton(R.string.ok, (dialog2, which2, inputText, isChecked) -> {\n                    if (TextUtils.isEmpty(inputText)) {\n                        UIUtils.displayShortToast(R.string.port_number_empty);\n                        callback.connectAdb(-1);\n                        return;\n                    }\n                    try {\n                        callback.connectAdb(Integer.decode(inputText.toString().trim()));\n                    } catch (NumberFormatException e) {\n                        UIUtils.displayShortToast(R.string.port_number_invalid);\n                        callback.connectAdb(-1);\n                    }\n                })\n                .setNegativeButton(R.string.cancel, (dialog, which, inputText, isChecked) -> callback.connectAdb(-1))\n                .setCancelable(false)\n                .show();\n    }\n\n    @RequiresApi(Build.VERSION_CODES.R)\n    @UiThread\n    @NoOps\n    public static void pairAdbInput(@NonNull FragmentActivity activity,\n                                    @NonNull AdbConnectionInterface callback) {\n        new MaterialAlertDialogBuilder(activity)\n                .setTitle(R.string.wireless_debugging)\n                .setMessage(R.string.adb_pairing_instruction)\n                .setCancelable(false)\n                .setNeutralButton(R.string.action_manual, (dialog, which) -> {\n                    Intent adbPairingServiceIntent = new Intent(activity, AdbPairingService.class)\n                            .setAction(AdbPairingService.ACTION_START_PAIRING);\n                    ContextCompat.startForegroundService(activity, adbPairingServiceIntent);\n                    callback.pairAdb();\n                })\n                .setNegativeButton(R.string.cancel, (dialog, which) -> callback.onStatusReceived(STATUS_FAILURE))\n                .setPositiveButton(R.string.go, (dialog, which) -> {\n                    Intent developerOptionsIntent = new Intent(Settings.ACTION_APPLICATION_DEVELOPMENT_SETTINGS)\n                            .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);\n                    Intent adbPairingServiceIntent = new Intent(activity, AdbPairingService.class)\n                            .setAction(AdbPairingService.ACTION_START_PAIRING);\n                    activity.startActivity(developerOptionsIntent);\n                    ContextCompat.startForegroundService(activity, adbPairingServiceIntent);\n                    callback.pairAdb();\n                })\n                .show();\n    }\n\n    @WorkerThread\n    @NoOps\n    @RequiresApi(Build.VERSION_CODES.R)\n    @Status\n    public static int pairAdb(@NonNull Context context) {\n        try {\n            AdbConnectionManager conn = AdbConnectionManager.getInstance();\n            int status = pairAdbInternal(context, conn);\n            if (status == STATUS_ADB_CONNECT_REQUIRED) {\n                return connectAdb(context, findAdbPort(context, 7, ServerConfig.getAdbPort()),\n                        STATUS_ADB_CONNECT_REQUIRED);\n            }\n        } catch (Exception e) {\n            ThreadUtils.postOnMainThread(() -> UIUtils.displayShortToast(R.string.failed));\n            Log.e(TAG, e);\n            // Failed, fall-through\n        }\n        return STATUS_FAILURE;\n    }\n\n\n    @WorkerThread\n    @NoOps\n    @RequiresApi(Build.VERSION_CODES.R)\n    @Status\n    private static int pairAdbInternal(@NonNull Context context, @NonNull AdbConnectionManager conn) {\n        AtomicReference<CountDownLatch> observerObserver = new AtomicReference<>(new CountDownLatch(1));\n        AtomicReference<Exception> pairingError = new AtomicReference<>();\n        Observer<Exception> observer = e -> {\n            pairingError.set(e);\n            observerObserver.get().countDown();\n        };\n        ThreadUtils.postOnMainThread(() -> conn.getPairingObserver().observeForever(observer));\n        while (true) {\n            boolean success;\n            try {\n                success = observerObserver.get().await(1, TimeUnit.HOURS);\n            } catch (InterruptedException ignore) {\n                success = false;\n            }\n            if (success) {\n                if (pairingError.get() != null) {\n                    if (ServiceHelper.checkIfServiceIsRunning(context, AdbPairingService.class)) {\n                        observerObserver.set(new CountDownLatch(1));\n                        continue;\n                    }\n                    success = false;\n                }\n            }\n            ThreadUtils.postOnMainThread(() -> conn.getPairingObserver().removeObserver(observer));\n            if (success) {\n                return STATUS_ADB_CONNECT_REQUIRED;\n            } else {\n                context.stopService(new Intent(context, AdbPairingService.class));\n                return STATUS_FAILURE;\n            }\n        }\n    }\n\n    @UiThread\n    public static void displayIncompleteUsbDebuggingMessage(@NonNull FragmentActivity activity) {\n        new ScrollableDialogBuilder(activity)\n                .setTitle(R.string.adb_incomplete_usb_debugging_title)\n                .setMessage(R.string.adb_incomplete_usb_debugging_message)\n                .enableAnchors()\n                .setNegativeButton(R.string.close, null)\n                .setPositiveButton(R.string.open, (dialog, which, isChecked) -> {\n                    Intent intent = new Intent(Settings.ACTION_APPLICATION_DEVELOPMENT_SETTINGS)\n                            .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);\n                    try {\n                        activity.startActivity(intent);\n                    } catch (Throwable ignore) {\n                    }\n                })\n                .show();\n    }\n\n    private static int initPermissionsWithSuccess() {\n        SelfPermissions.init();\n        return STATUS_SUCCESS;\n    }\n\n    /**\n     * @return {@code true} iff AMService is up and running\n     */\n    @WorkerThread\n    @NoOps // Although we've used Ops checks, its overall usage does not affect anything\n    private static boolean isAMServiceUpAndRunning(@NonNull Context context, @Mode @NonNull String mode) {\n        boolean lastAdb = sIsAdb;\n        boolean lastSystem = sIsSystem;\n        boolean lastRoot = sIsRoot;\n        // At this point, we have already checked MODE_AUTO, and MODE_NO_ROOT has lower priority.\n        sIsRoot = MODE_ROOT.equals(mode);\n        sIsAdb = !sIsRoot; // Because the rests are ADB\n        sIsSystem = false;\n        if (LocalServer.alive(context)) {\n            // Remote server is running, but local server may not be running\n            try {\n                LocalServer.getInstance();\n                LocalServices.bindServicesIfNotAlready();\n            } catch (RemoteException | IOException | AdbPairingRequiredException e) {\n                Log.e(TAG, e);\n                // fall-through, because the remote service may still be alive\n            }\n        }\n        if (LocalServices.alive()) {\n            // AM service is running\n            int uid = Users.getSelfOrRemoteUid();\n            if (sIsRoot && uid == ROOT_UID) {\n                // AM service is running as root\n                return true;\n            }\n            if (uid == SYSTEM_UID) {\n                // AM service is running as system\n                sIsSystem = true;\n                sIsRoot = sIsAdb = false;\n                return true;\n            }\n            if (sIsAdb) {\n                // AM service is running as ADB\n                return checkRootOrIncompleteUsbDebuggingInAdb() == STATUS_SUCCESS;\n            }\n            // All checks are failed, stop services\n            LocalServices.stopServices();\n        }\n        // Checks are failed, revert everything\n        sIsAdb = lastAdb;\n        sIsSystem = lastSystem;\n        sIsRoot = lastRoot;\n        return false;\n    }\n\n    @NoOps // Although we've used Ops checks, its overall usage does not affect anything\n    private static int checkRootOrIncompleteUsbDebuggingInAdb() {\n        // ADB already granted and AM service is running\n        int uid = Users.getSelfOrRemoteUid();\n        if (uid == ROOT_UID) {\n            // AM service is being run as root\n            sIsRoot = true;\n            sIsSystem = sIsAdb = false;\n            ThreadUtils.postOnMainThread(() -> UIUtils.displayLongToast(R.string.warning_working_on_root_mode));\n        } else if (uid == SYSTEM_UID) {\n            // AM service is being run as system\n            sIsSystem = true;\n            sIsRoot = sIsAdb = false;\n            ThreadUtils.postOnMainThread(() -> UIUtils.displayLongToast(R.string.warning_working_on_system_mode));\n        } else if (uid == SHELL_UID) { // ADB mode\n            if (!SelfPermissions.checkSelfOrRemotePermission(ManifestCompat.permission.GRANT_RUNTIME_PERMISSIONS)) {\n                // USB debugging is incomplete, revert back to no-root\n                sIsAdb = sIsSystem = sIsRoot = false;\n                return STATUS_FAILURE_ADB_NEED_MORE_PERMS;\n            }\n            ThreadUtils.postOnMainThread(() -> UIUtils.displayShortToast(R.string.working_on_adb_mode));\n        } else {\n            // No-root mode\n            sIsAdb = sIsSystem = sIsRoot = false;\n            return STATUS_FAILURE;\n        }\n        return initPermissionsWithSuccess();\n    }\n\n    @WorkerThread\n    @RequiresApi(Build.VERSION_CODES.R)\n    @NoOps\n    private static int findAdbPort(@NonNull Context context, long timeoutInSeconds)\n            throws IOException, InterruptedException {\n        return AdbUtils.getLatestAdbDaemon(context, timeoutInSeconds, TimeUnit.SECONDS).second;\n    }\n\n    @WorkerThread\n    @NoOps\n    private static int findAdbPort(@NonNull Context context, long timeoutInSeconds, int defaultPort)\n            throws IOException {\n        if (!AdbUtils.isAdbdRunning()) {\n            throw new IOException(\"ADB daemon not running.\");\n        }\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {\n            // Find ADB port only in Android 11 (R) or later\n            try {\n                return findAdbPort(context, timeoutInSeconds);\n            } catch (IOException | InterruptedException e) {\n                Log.w(TAG, \"Could not find ADB port\", e);\n            }\n        }\n        return defaultPort;\n    }\n\n    @AnyThread\n    public interface AdbConnectionInterface {\n        // TODO: 8/4/24 Remove the first two methods since the third method can be used instead of them\n        void connectAdb(int port);\n\n        @RequiresApi(Build.VERSION_CODES.R)\n        void pairAdb();\n\n        void onStatusReceived(@Status int status);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/settings/PreferenceFragment.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.settings;\n\nimport android.annotation.SuppressLint;\nimport android.os.Bundle;\nimport android.view.View;\n\nimport androidx.annotation.CallSuper;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.StringRes;\nimport androidx.preference.Preference;\nimport androidx.preference.PreferenceFragmentCompat;\nimport androidx.recyclerview.widget.RecyclerView;\n\nimport java.util.Objects;\n\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.util.UiUtils;\n\npublic abstract class PreferenceFragment extends PreferenceFragmentCompat {\n    public static final String PREF_KEY = \"key\";\n    public static final String PREF_SECONDARY = \"secondary\";\n\n    @Nullable\n    private String mPrefKey;\n\n    @CallSuper\n    @Override\n    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {\n        super.onViewCreated(view, savedInstanceState);\n        boolean secondary = false;\n        if (getArguments() != null) {\n            mPrefKey = requireArguments().getString(PREF_KEY);\n            secondary = requireArguments().getBoolean(PREF_SECONDARY);\n            requireArguments().remove(PREF_KEY);\n            requireArguments().remove(PREF_SECONDARY);\n        }\n        // https://github.com/androidx/androidx/blob/androidx-main/preference/preference/res/layout/preference_recyclerview.xml\n        RecyclerView recyclerView = view.findViewById(R.id.recycler_view);\n        recyclerView.setFitsSystemWindows(true);\n        recyclerView.setClipToPadding(false);\n        if (secondary) {\n            if (this instanceof MainPreferences) {\n                UiUtils.applyWindowInsetsAsPadding(recyclerView, false, true, true, false);\n            } else {\n                UiUtils.applyWindowInsetsAsPadding(recyclerView, false, true, false, true);\n            }\n        } else UiUtils.applyWindowInsetsAsPaddingNoTop(recyclerView);\n    }\n\n    @CallSuper\n    @Override\n    public void onStart() {\n        requireActivity().setTitle(getTitle());\n        super.onStart();\n        updateUi();\n    }\n\n    @StringRes\n    public abstract int getTitle();\n\n    public void setPrefKey(@Nullable String prefKey) {\n        mPrefKey = prefKey;\n        updateUi();\n    }\n\n    public <T extends androidx.preference.Preference> T requirePreference(CharSequence key) {\n        return Objects.requireNonNull(findPreference(key));\n    }\n\n    protected void enablePrefs(boolean enable, Preference ...prefs) {\n        if (prefs == null) {\n            return;\n        }\n        for (Preference pref : prefs) {\n            pref.setEnabled(enable);\n        }\n    }\n\n    @SuppressLint(\"RestrictedApi\")\n    private void updateUi() {\n        if (mPrefKey != null) {\n            Preference prefToNavigate = findPreference(mPrefKey);\n            if (prefToNavigate != null) {\n                scrollToPreference(prefToNavigate);\n                if (prefToNavigate.getFragment() != null) {\n                    prefToNavigate.performClick();\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/settings/Prefs.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.settings;\n\nimport static io.github.muntashirakon.AppManager.backup.BackupUtils.TAR_TYPES;\n\nimport android.Manifest;\nimport android.content.ComponentName;\nimport android.content.ContentResolver;\nimport android.content.Context;\nimport android.content.pm.PackageManager;\nimport android.net.Uri;\nimport android.os.Build;\nimport android.text.TextUtils;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.StyleRes;\nimport androidx.core.util.Pair;\n\nimport org.json.JSONException;\nimport org.json.JSONObject;\n\nimport java.io.File;\nimport java.io.FileNotFoundException;\nimport java.util.Objects;\n\nimport io.github.muntashirakon.AppManager.BuildConfig;\nimport io.github.muntashirakon.AppManager.apk.signing.SigSchemes;\nimport io.github.muntashirakon.AppManager.apk.signing.Signer;\nimport io.github.muntashirakon.AppManager.backup.BackupFlags;\nimport io.github.muntashirakon.AppManager.backup.CryptoUtils;\nimport io.github.muntashirakon.AppManager.compat.ManifestCompat;\nimport io.github.muntashirakon.AppManager.details.AppDetailsFragment;\nimport io.github.muntashirakon.AppManager.fm.FmActivity;\nimport io.github.muntashirakon.AppManager.fm.FmListOptions;\nimport io.github.muntashirakon.AppManager.logcat.helper.LogcatHelper;\nimport io.github.muntashirakon.AppManager.main.MainListOptions;\nimport io.github.muntashirakon.AppManager.rules.struct.ComponentRule;\nimport io.github.muntashirakon.AppManager.runningapps.RunningAppsActivity;\nimport io.github.muntashirakon.AppManager.self.SelfPermissions;\nimport io.github.muntashirakon.AppManager.utils.AppPref;\nimport io.github.muntashirakon.AppManager.utils.ArrayUtils;\nimport io.github.muntashirakon.AppManager.utils.ContextUtils;\nimport io.github.muntashirakon.AppManager.utils.FileUtils;\nimport io.github.muntashirakon.AppManager.utils.FreezeUtils;\nimport io.github.muntashirakon.AppManager.utils.TarUtils;\nimport io.github.muntashirakon.io.Path;\nimport io.github.muntashirakon.io.Paths;\n\n// Why this class?\n//\n// This class is just an abstract over the AppPref to make life a bit easier. In the future, however, it might be\n// possible to deliver the changes to the settings using lifecycle where required. For example, in the log viewer page,\n// changes to the settings are not immediately reflected unless the settings page is opened from the page itself.\npublic final class Prefs {\n    public static final class AppDetailsPage {\n        public static boolean displayDefaultAppOps() {\n            return AppPref.getBoolean(AppPref.PrefKey.PREF_APP_OP_SHOW_DEFAULT_BOOL);\n        }\n\n        public static void setDisplayDefaultAppOps(boolean display) {\n            AppPref.set(AppPref.PrefKey.PREF_APP_OP_SHOW_DEFAULT_BOOL, display);\n        }\n\n        @AppDetailsFragment.SortOrder\n        public static int getAppOpsSortOrder() {\n            return AppPref.getInt(AppPref.PrefKey.PREF_APP_OP_SORT_ORDER_INT);\n        }\n\n        public static void setAppOpsSortOrder(@AppDetailsFragment.SortOrder int sortOrder) {\n            AppPref.set(AppPref.PrefKey.PREF_APP_OP_SORT_ORDER_INT, sortOrder);\n        }\n\n        @AppDetailsFragment.SortOrder\n        public static int getComponentsSortOrder() {\n            return AppPref.getInt(AppPref.PrefKey.PREF_COMPONENTS_SORT_ORDER_INT);\n        }\n\n        public static void setComponentsSortOrder(@AppDetailsFragment.SortOrder int sortOrder) {\n            AppPref.set(AppPref.PrefKey.PREF_COMPONENTS_SORT_ORDER_INT, sortOrder);\n        }\n\n        @AppDetailsFragment.SortOrder\n        public static int getPermissionsSortOrder() {\n            return AppPref.getInt(AppPref.PrefKey.PREF_PERMISSIONS_SORT_ORDER_INT);\n        }\n\n        public static void setPermissionsSortOrder(@AppDetailsFragment.SortOrder int sortOrder) {\n            AppPref.set(AppPref.PrefKey.PREF_PERMISSIONS_SORT_ORDER_INT, sortOrder);\n        }\n\n        @AppDetailsFragment.SortOrder\n        public static int getOverlaysSortOrder() {\n            return AppPref.getInt(AppPref.PrefKey.PREF_OVERLAYS_SORT_ORDER_INT);\n        }\n\n        public static void setOverlaysSortOrder(@AppDetailsFragment.SortOrder int sortOrder) {\n            AppPref.set(AppPref.PrefKey.PREF_OVERLAYS_SORT_ORDER_INT, sortOrder);\n        }\n    }\n\n    public static final class Appearance {\n        @NonNull\n        public static String getLanguage() {\n            return AppPref.getString(AppPref.PrefKey.PREF_CUSTOM_LOCALE_STR);\n        }\n\n        @NonNull\n        public static String getLanguage(@NonNull Context context) {\n            // Required when application isn't initialised properly\n            AppPref appPref = AppPref.getNewInstance(context);\n            return (String) appPref.getValue(AppPref.PrefKey.PREF_CUSTOM_LOCALE_STR);\n        }\n\n        public static void setLanguage(@NonNull String language) {\n            AppPref.set(AppPref.PrefKey.PREF_CUSTOM_LOCALE_STR, language);\n        }\n\n        public static int getLayoutDirection() {\n            return AppPref.getInt(AppPref.PrefKey.PREF_LAYOUT_ORIENTATION_INT);\n        }\n\n        public static void setLayoutDirection(int layoutDirection) {\n            AppPref.set(AppPref.PrefKey.PREF_LAYOUT_ORIENTATION_INT, layoutDirection);\n        }\n\n        @StyleRes\n        public static int getAppTheme() {\n            switch (AppPref.getInt(AppPref.PrefKey.PREF_APP_THEME_CUSTOM_INT)) {\n                case 1: // Full black theme\n                    return io.github.muntashirakon.ui.R.style.AppTheme_Black;\n                default: // Normal theme\n                    return io.github.muntashirakon.ui.R.style.AppTheme;\n            }\n        }\n\n        @StyleRes\n        public static int getTransparentAppTheme() {\n            switch (AppPref.getInt(AppPref.PrefKey.PREF_APP_THEME_CUSTOM_INT)) {\n                case 1: // Full black theme\n                    return io.github.muntashirakon.ui.R.style.AppTheme_TransparentBackground_Black;\n                default: // Normal theme\n                    return io.github.muntashirakon.ui.R.style.AppTheme_TransparentBackground;\n            }\n        }\n\n        public static boolean isPureBlackTheme() {\n            return AppPref.getInt(AppPref.PrefKey.PREF_APP_THEME_CUSTOM_INT) == 1;\n        }\n\n        public static void setPureBlackTheme(boolean enabled) {\n            AppPref.set(AppPref.PrefKey.PREF_APP_THEME_CUSTOM_INT, enabled ? 1 : 0);\n        }\n\n        public static int getNightMode() {\n            return AppPref.getInt(AppPref.PrefKey.PREF_APP_THEME_INT);\n        }\n\n        public static void setNightMode(int nightMode) {\n            AppPref.set(AppPref.PrefKey.PREF_APP_THEME_INT, nightMode);\n        }\n\n        public static boolean useSystemFont() {\n            return AppPref.getBoolean(AppPref.PrefKey.PREF_USE_SYSTEM_FONT_BOOL);\n        }\n    }\n\n    public static final class BackupRestore {\n        public static boolean backupAppsWithKeyStore() {\n            return AppPref.getBoolean(AppPref.PrefKey.PREF_BACKUP_ANDROID_KEYSTORE_BOOL);\n        }\n\n        @NonNull\n        @TarUtils.TarType\n        public static String getCompressionMethod() {\n            String tarType = AppPref.getString(AppPref.PrefKey.PREF_BACKUP_COMPRESSION_METHOD_STR);\n            // Verify tar type\n            if (ArrayUtils.indexOf(TAR_TYPES, tarType) == -1) {\n                // Unknown tar type, set default\n                tarType = TarUtils.TAR_GZIP;\n            }\n            return tarType;\n        }\n\n        public static void setCompressionMethod(@NonNull @TarUtils.TarType String tarType) {\n            AppPref.set(AppPref.PrefKey.PREF_BACKUP_COMPRESSION_METHOD_STR, tarType);\n        }\n\n        @BackupFlags.BackupFlag\n        public static int getBackupFlags() {\n            return AppPref.getInt(AppPref.PrefKey.PREF_BACKUP_FLAGS_INT);\n        }\n\n        public static void setBackupFlags(@BackupFlags.BackupFlag int flags) {\n            AppPref.set(AppPref.PrefKey.PREF_BACKUP_FLAGS_INT, flags);\n        }\n\n        public static boolean backupDirectoryExists() {\n            Uri uri = Storage.getVolumePath();\n            Path path;\n            if (uri.getScheme().equals(ContentResolver.SCHEME_FILE)) {\n                // Append AppManager only if storage permissions are granted\n                String newPath = uri.getPath();\n                if (SelfPermissions.checkStoragePermission()) {\n                    newPath += File.separator + \"AppManager\";\n                }\n                path = Paths.get(newPath);\n            } else path = Paths.get(uri);\n            return path.exists();\n        }\n    }\n\n    public static final class Blocking {\n        public static boolean globalBlockingEnabled() {\n            return AppPref.getBoolean(AppPref.PrefKey.PREF_GLOBAL_BLOCKING_ENABLED_BOOL);\n        }\n\n        @ComponentRule.ComponentStatus\n        public static String getDefaultBlockingMethod() {\n            String selectedStatus = AppPref.getString(AppPref.PrefKey.PREF_DEFAULT_BLOCKING_METHOD_STR);\n            if (!SelfPermissions.canBlockByIFW()) {\n                if (selectedStatus.equals(ComponentRule.COMPONENT_TO_BE_BLOCKED_IFW_DISABLE)\n                        || selectedStatus.equals(ComponentRule.COMPONENT_TO_BE_BLOCKED_IFW)) {\n                    // Lower the status\n                    return ComponentRule.COMPONENT_TO_BE_DISABLED;\n                }\n            }\n            return selectedStatus;\n        }\n\n        public static void setDefaultBlockingMethod(@NonNull @ComponentRule.ComponentStatus String blockingMethod) {\n            AppPref.set(AppPref.PrefKey.PREF_DEFAULT_BLOCKING_METHOD_STR, blockingMethod);\n        }\n\n        @FreezeUtils.FreezeMethod\n        public static int getDefaultFreezingMethod() {\n            int freezeType = AppPref.getInt(AppPref.PrefKey.PREF_FREEZE_TYPE_INT);\n            if (freezeType == FreezeUtils.FREEZE_HIDE) {\n                // Requires MANAGE_USERS permission\n                if (!SelfPermissions.checkSelfOrRemotePermission(ManifestCompat.permission.MANAGE_USERS)) {\n                    return FreezeUtils.FREEZE_DISABLE;\n                }\n            } else if (freezeType == FreezeUtils.FREEZE_SUSPEND || freezeType == FreezeUtils.FREEZE_ADV_SUSPEND) {\n                // 7+ only. Requires MANAGE_USERS permission until P. Requires SUSPEND_APPS permission after that.\n                if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N\n                        || Build.VERSION.SDK_INT >= Build.VERSION_CODES.P && !SelfPermissions.checkSelfOrRemotePermission(ManifestCompat.permission.SUSPEND_APPS)\n                        || (Build.VERSION.SDK_INT < Build.VERSION_CODES.P && !SelfPermissions.checkSelfOrRemotePermission(ManifestCompat.permission.MANAGE_USERS))) {\n                    return FreezeUtils.FREEZE_DISABLE;\n                }\n            }\n            return freezeType;\n        }\n\n        public static void setDefaultFreezingMethod(@FreezeUtils.FreezeMethod int freezeType) {\n            AppPref.set(AppPref.PrefKey.PREF_FREEZE_TYPE_INT, freezeType);\n        }\n    }\n\n    public static final class Encryption {\n        @NonNull\n        @CryptoUtils.Mode\n        public static String getEncryptionMode() {\n            return AppPref.getString(AppPref.PrefKey.PREF_ENCRYPTION_STR);\n        }\n\n        public static void setEncryptionMode(@NonNull @CryptoUtils.Mode String mode) {\n            AppPref.set(AppPref.PrefKey.PREF_ENCRYPTION_STR, mode);\n        }\n\n        @NonNull\n        public static String getOpenPgpProvider() {\n            return AppPref.getString(AppPref.PrefKey.PREF_OPEN_PGP_PACKAGE_STR);\n        }\n\n        public static void setOpenPgpProvider(@NonNull String providerPackage) {\n            AppPref.set(AppPref.PrefKey.PREF_OPEN_PGP_PACKAGE_STR, providerPackage);\n        }\n\n        @NonNull\n        public static String getOpenPgpKeyIds() {\n            return AppPref.getString(AppPref.PrefKey.PREF_OPEN_PGP_USER_ID_STR);\n        }\n\n        public static void setOpenPgpKeyIds(@NonNull String keyIds) {\n            AppPref.set(AppPref.PrefKey.PREF_OPEN_PGP_USER_ID_STR, keyIds);\n        }\n    }\n\n    public static final class FileManager {\n        public static boolean displayInLauncher() {\n            ComponentName componentName = new ComponentName(BuildConfig.APPLICATION_ID, FmActivity.LAUNCHER_ALIAS);\n            int state = ContextUtils.getContext().getPackageManager().getComponentEnabledSetting(componentName);\n            return state == PackageManager.COMPONENT_ENABLED_STATE_ENABLED;\n        }\n\n        public static Uri getHome() {\n            return Uri.parse(AppPref.getString(AppPref.PrefKey.PREF_FM_HOME_STR));\n        }\n\n        public static void setHome(@NonNull Uri uri) {\n            AppPref.set(AppPref.PrefKey.PREF_FM_HOME_STR, uri.toString());\n        }\n\n        public static boolean isRememberLastOpenedPath() {\n            return AppPref.getBoolean(AppPref.PrefKey.PREF_FM_REMEMBER_LAST_PATH_BOOL);\n        }\n\n        @Nullable\n        public static Pair<FmActivity.Options, Pair<Uri, Integer>> getLastOpenedPath() {\n            String jsonString = AppPref.getString(AppPref.PrefKey.PREF_FM_LAST_PATH_STR);\n            try {\n                JSONObject object = new JSONObject(jsonString);\n                if (object.has(\"path\") && object.has(\"pos\")) {\n                    boolean vfs = object.has(\"vfs\") && object.getBoolean(\"vfs\");\n                    FmActivity.Options options = new FmActivity.Options(Uri.parse(object.getString(\"path\")),\n                            vfs, false, false);\n                    if (!Paths.getStrict(options.uri).exists()) {\n                        // Do not bother if path does not exist\n                        return null;\n                    }\n                    Uri initUri;\n                    if (vfs && object.has(\"init\")) {\n                        initUri = Uri.parse(object.getString(\"init\"));\n                    } else initUri = null;\n                    Pair<Uri, Integer> uriPositionPair = new Pair<>(initUri, object.getInt(\"pos\"));\n                    return new Pair<>(options, uriPositionPair);\n                }\n            } catch (JSONException | FileNotFoundException e) {\n                e.printStackTrace();\n            }\n            return null;\n        }\n\n        public static void setLastOpenedPath(@NonNull FmActivity.Options options, @NonNull Uri initUri, int position) {\n            try {\n                if (options.isVfs()) {\n                    // Ignore VFS for now\n                    return;\n                }\n                JSONObject object = new JSONObject();\n                object.put(\"pos\", position);\n                if (options.isVfs()) {\n                    object.put(\"vfs\", true);\n                    object.put(\"path\", options.uri.toString());\n                    object.put(\"init\", initUri.toString());\n                } else {\n                    object.put(\"path\", initUri.toString());\n                }\n                AppPref.set(AppPref.PrefKey.PREF_FM_LAST_PATH_STR, object.toString());\n            } catch (JSONException e) {\n                e.printStackTrace();\n            }\n        }\n\n        @FmListOptions.Options\n        public static int getOptions() {\n            return AppPref.getInt(AppPref.PrefKey.PREF_FM_OPTIONS_INT);\n        }\n\n        public static void setOptions(@FmListOptions.Options int options) {\n            AppPref.set(AppPref.PrefKey.PREF_FM_OPTIONS_INT, options);\n        }\n\n        @FmListOptions.SortOrder\n        public static int getSortOrder() {\n            return AppPref.getInt(AppPref.PrefKey.PREF_FM_SORT_ORDER_INT);\n        }\n\n        public static void setSortOrder(@FmListOptions.SortOrder int sortOrder) {\n            AppPref.set(AppPref.PrefKey.PREF_FM_SORT_ORDER_INT, sortOrder);\n        }\n\n        public static boolean isReverseSort() {\n            return AppPref.getBoolean(AppPref.PrefKey.PREF_FM_SORT_REVERSE_BOOL);\n        }\n\n        public static void setReverseSort(boolean reverseSort) {\n            AppPref.set(AppPref.PrefKey.PREF_FM_SORT_REVERSE_BOOL, reverseSort);\n        }\n    }\n\n    public static final class Installer {\n        public static boolean installInBackground() {\n            return AppPref.getBoolean(AppPref.PrefKey.PREF_INSTALLER_ALWAYS_ON_BACKGROUND_BOOL);\n        }\n\n        public static boolean displayChanges() {\n            return AppPref.getBoolean(AppPref.PrefKey.PREF_INSTALLER_DISPLAY_CHANGES_BOOL);\n        }\n\n        public static boolean blockTrackers() {\n            return AppPref.getBoolean(AppPref.PrefKey.PREF_INSTALLER_BLOCK_TRACKERS_BOOL);\n        }\n\n        public static boolean forceDexOpt() {\n            return Build.VERSION.SDK_INT >= Build.VERSION_CODES.N\n                    && AppPref.getBoolean(AppPref.PrefKey.PREF_INSTALLER_FORCE_DEX_OPT_BOOL);\n        }\n\n        public static boolean canSignApk() {\n            if (!AppPref.getBoolean(AppPref.PrefKey.PREF_INSTALLER_SIGN_APK_BOOL)) {\n                // Signing not enabled\n                return false;\n            }\n            return Signer.canSign();\n        }\n\n        public static int getInstallLocation() {\n            return AppPref.getInt(AppPref.PrefKey.PREF_INSTALLER_INSTALL_LOCATION_INT);\n        }\n\n        public static void setInstallLocation(int installLocation) {\n            AppPref.set(AppPref.PrefKey.PREF_INSTALLER_INSTALL_LOCATION_INT, installLocation);\n        }\n\n        @NonNull\n        public static String getInstallerPackageName() {\n            if (!SelfPermissions.checkSelfOrRemotePermission(Manifest.permission.INSTALL_PACKAGES)) {\n                return BuildConfig.APPLICATION_ID;\n            }\n            return AppPref.getString(AppPref.PrefKey.PREF_INSTALLER_INSTALLER_APP_STR);\n        }\n\n        public static void setInstallerPackageName(@NonNull String packageName) {\n            AppPref.set(AppPref.PrefKey.PREF_INSTALLER_INSTALLER_APP_STR, packageName);\n        }\n\n        public static boolean isSetOriginatingPackage() {\n            return AppPref.getBoolean(AppPref.PrefKey.PREF_INSTALLER_SET_ORIGIN_BOOL);\n        }\n\n        public static int getPackageSource() {\n            return AppPref.getInt(AppPref.PrefKey.PREF_INSTALLER_DEFAULT_PKG_SOURCE_INT);\n        }\n\n        public static void setPackageSource(int source) {\n            AppPref.set(AppPref.PrefKey.PREF_INSTALLER_DEFAULT_PKG_SOURCE_INT, source);\n        }\n\n        public static boolean requestUpdateOwnership() {\n            // Shell default is false\n            return AppPref.getBoolean(AppPref.PrefKey.PREF_INSTALLER_UPDATE_OWNERSHIP_BOOL);\n        }\n\n        public static boolean isDisableApkVerification() {\n            return AppPref.getBoolean(AppPref.PrefKey.PREF_INSTALLER_DISABLE_VERIFICATION_BOOL);\n        }\n    }\n\n    public static final class LogViewer {\n        @LogcatHelper.LogBufferId\n        public static int getBuffers() {\n            return AppPref.getInt(AppPref.PrefKey.PREF_LOG_VIEWER_BUFFER_INT);\n        }\n\n        public static void setBuffers(@LogcatHelper.LogBufferId int buffers) {\n            AppPref.set(AppPref.PrefKey.PREF_LOG_VIEWER_BUFFER_INT, buffers);\n        }\n\n        public static int getLogLevel() {\n            return AppPref.getInt(AppPref.PrefKey.PREF_LOG_VIEWER_DEFAULT_LOG_LEVEL_INT);\n        }\n\n        public static void setLogLevel(int logLevel) {\n            AppPref.set(AppPref.PrefKey.PREF_LOG_VIEWER_DEFAULT_LOG_LEVEL_INT, logLevel);\n        }\n\n        public static int getDisplayLimit() {\n            return AppPref.getInt(AppPref.PrefKey.PREF_LOG_VIEWER_DISPLAY_LIMIT_INT);\n        }\n\n        public static void setDisplayLimit(int displayLimit) {\n            AppPref.set(AppPref.PrefKey.PREF_LOG_VIEWER_DISPLAY_LIMIT_INT, displayLimit);\n        }\n\n        @NonNull\n        public static String getFilterPattern() {\n            return AppPref.getString(AppPref.PrefKey.PREF_LOG_VIEWER_FILTER_PATTERN_STR);\n        }\n\n        public static void setFilterPattern(@NonNull String filterPattern) {\n            AppPref.set(AppPref.PrefKey.PREF_LOG_VIEWER_FILTER_PATTERN_STR, filterPattern);\n        }\n\n        public static int getLogWritingInterval() {\n            return AppPref.getInt(AppPref.PrefKey.PREF_LOG_VIEWER_WRITE_PERIOD_INT);\n        }\n\n        public static void setLogWritingInterval(int logWritingInterval) {\n            AppPref.set(AppPref.PrefKey.PREF_LOG_VIEWER_WRITE_PERIOD_INT, logWritingInterval);\n        }\n\n        public static boolean expandByDefault() {\n            return AppPref.getBoolean(AppPref.PrefKey.PREF_LOG_VIEWER_EXPAND_BY_DEFAULT_BOOL);\n        }\n\n        public static boolean omitSensitiveInfo() {\n            return AppPref.getBoolean(AppPref.PrefKey.PREF_LOG_VIEWER_OMIT_SENSITIVE_INFO_BOOL);\n        }\n\n        public static boolean showPidTidTimestamp() {\n            return AppPref.getBoolean(AppPref.PrefKey.PREF_LOG_VIEWER_SHOW_PID_TID_TIMESTAMP_BOOL);\n        }\n    }\n\n    public static final class MainPage {\n        @MainListOptions.SortOrder\n        public static int getSortOrder() {\n            return AppPref.getInt(AppPref.PrefKey.PREF_MAIN_WINDOW_SORT_ORDER_INT);\n        }\n\n        public static void setSortOrder(@RunningAppsActivity.SortOrder int sortOrder) {\n            AppPref.set(AppPref.PrefKey.PREF_MAIN_WINDOW_SORT_ORDER_INT, sortOrder);\n        }\n\n        public static boolean isReverseSort() {\n            return AppPref.getBoolean(AppPref.PrefKey.PREF_MAIN_WINDOW_SORT_REVERSE_BOOL);\n        }\n\n        public static void setReverseSort(boolean reverseSort) {\n            AppPref.set(AppPref.PrefKey.PREF_MAIN_WINDOW_SORT_REVERSE_BOOL, reverseSort);\n        }\n\n        @MainListOptions.Filter\n        public static int getFilters() {\n            return AppPref.getInt(AppPref.PrefKey.PREF_MAIN_WINDOW_FILTER_FLAGS_INT);\n        }\n\n        public static void setFilters(@MainListOptions.Filter int filters) {\n            AppPref.set(AppPref.PrefKey.PREF_MAIN_WINDOW_FILTER_FLAGS_INT, filters);\n        }\n\n        @Nullable\n        public static String getFilteredProfileName() {\n            String profileName = AppPref.getString(AppPref.PrefKey.PREF_MAIN_WINDOW_FILTER_PROFILE_STR);\n            if (TextUtils.isEmpty(profileName)) {\n                return null;\n            }\n            return profileName;\n        }\n\n        public static void setFilteredProfileName(@Nullable String profileName) {\n            AppPref.set(AppPref.PrefKey.PREF_MAIN_WINDOW_FILTER_PROFILE_STR, profileName == null ? \"\" : profileName);\n        }\n    }\n\n    public static final class Misc {\n        @Nullable\n        public static int[] getSelectedUsers() {\n            String usersStr = AppPref.getString(AppPref.PrefKey.PREF_SELECTED_USERS_STR);\n            if (usersStr.isEmpty()) return null;\n            String[] usersSplitStr = usersStr.split(\",\");\n            int[] users = new int[usersSplitStr.length];\n            for (int i = 0; i < users.length; ++i) {\n                users[i] = Integer.decode(usersSplitStr[i]);\n            }\n            return users;\n        }\n\n        public static void setSelectedUsers(@Nullable int[] users) {\n            if (users == null) {\n                AppPref.set(AppPref.PrefKey.PREF_SELECTED_USERS_STR, \"\");\n                return;\n            }\n            String[] userString = new String[users.length];\n            for (int i = 0; i < users.length; ++i) {\n                userString[i] = String.valueOf(users[i]);\n            }\n            AppPref.set(AppPref.PrefKey.PREF_SELECTED_USERS_STR, TextUtils.join(\",\", userString));\n        }\n\n        public static boolean sendNotificationsToConnectedDevices() {\n            return AppPref.getBoolean(AppPref.PrefKey.PREF_SEND_NOTIFICATIONS_TO_CONNECTED_DEVICES_BOOL);\n        }\n\n        public static void setAdbLocalServerPort(int port) {\n            AppPref.set(AppPref.PrefKey.PREF_ADB_LOCAL_SERVER_PORT_INT, port);\n        }\n\n        public static int getAdbLocalServerPort() {\n            return AppPref.getInt(AppPref.PrefKey.PREF_ADB_LOCAL_SERVER_PORT_INT);\n        }\n    }\n\n    public static final class RunningApps {\n        @RunningAppsActivity.SortOrder\n        public static int getSortOrder() {\n            return AppPref.getInt(AppPref.PrefKey.PREF_RUNNING_APPS_SORT_ORDER_INT);\n        }\n\n        public static void setSortOrder(@RunningAppsActivity.SortOrder int sortOrder) {\n            AppPref.set(AppPref.PrefKey.PREF_RUNNING_APPS_SORT_ORDER_INT, sortOrder);\n        }\n\n        @RunningAppsActivity.Filter\n        public static int getFilters() {\n            return AppPref.getInt(AppPref.PrefKey.PREF_RUNNING_APPS_FILTER_FLAGS_INT);\n        }\n\n        public static void setFilters(@RunningAppsActivity.Filter int filters) {\n            AppPref.set(AppPref.PrefKey.PREF_RUNNING_APPS_FILTER_FLAGS_INT, filters);\n        }\n\n        public static boolean enableKillForSystemApps() {\n            return AppPref.getBoolean(AppPref.PrefKey.PREF_ENABLE_KILL_FOR_SYSTEM_BOOL);\n        }\n\n        public static void setEnableKillForSystemApps(boolean enable) {\n            AppPref.set(AppPref.PrefKey.PREF_ENABLE_KILL_FOR_SYSTEM_BOOL, enable);\n        }\n    }\n\n    public static final class Privacy {\n        public static boolean isScreenLockEnabled() {\n            return AppPref.getBoolean(AppPref.PrefKey.PREF_ENABLE_SCREEN_LOCK_BOOL);\n        }\n\n        public static boolean isAutoLockEnabled() {\n            return AppPref.getBoolean(AppPref.PrefKey.PREF_ENABLE_AUTO_LOCK_BOOL);\n        }\n\n        public static boolean isPersistentSessionAllowed() {\n            return AppPref.getBoolean(AppPref.PrefKey.PREF_ENABLE_PERSISTENT_SESSION_BOOL);\n        }\n    }\n\n    public static final class Signing {\n        @NonNull\n        public static SigSchemes getSigSchemes() {\n            SigSchemes sigSchemes = new SigSchemes(AppPref.getInt(AppPref.PrefKey.PREF_SIGNATURE_SCHEMES_INT));\n            if (sigSchemes.isEmpty()) {\n                // Use default if no flag is set\n                return new SigSchemes(SigSchemes.DEFAULT_SCHEMES);\n            }\n            return sigSchemes;\n        }\n\n        public static void setSigSchemes(int flags) {\n            AppPref.set(AppPref.PrefKey.PREF_SIGNATURE_SCHEMES_INT, flags);\n        }\n\n        public static boolean zipAlign() {\n            return AppPref.getBoolean(AppPref.PrefKey.PREF_ZIP_ALIGN_BOOL);\n        }\n    }\n\n    public static final class Storage {\n        @NonNull\n        public static Path getAppManagerDirectory() {\n            Uri uri = getVolumePath();\n            Path path;\n            if (Objects.equals(uri.getScheme(), ContentResolver.SCHEME_FILE)) {\n                // Append AppManager\n                String newPath = uri.getPath() + File.separator + \"AppManager\";\n                path = Paths.get(newPath);\n            } else path = Paths.get(uri);\n            if (!path.exists()) path.mkdirs();\n            return path;\n        }\n\n        public static Uri getVolumePath() {\n            String uriOrBareFile = AppPref.getString(AppPref.PrefKey.PREF_BACKUP_VOLUME_STR);\n            if (uriOrBareFile.startsWith(\"/\")) {\n                // A good URI starts with file:// or content://, if not, migrate\n                Uri uri = new Uri.Builder().scheme(ContentResolver.SCHEME_FILE).path(uriOrBareFile).build();\n                AppPref.set(AppPref.PrefKey.PREF_BACKUP_VOLUME_STR, uri.toString());\n                return uri;\n            }\n            return Uri.parse(uriOrBareFile);\n        }\n\n\n        public static void setVolumePath(@NonNull String path) {\n            AppPref.set(AppPref.PrefKey.PREF_BACKUP_VOLUME_STR, path);\n        }\n\n        @NonNull\n        public static Path getTempPath() {\n            // This path is intended for storing temporary data for backup/restore and similar operations\n            return Paths.get(FileUtils.getCachePath());\n        }\n    }\n\n    public static final class VirusTotal {\n        @Nullable\n        public static String getApiKey() {\n            String apiKey = AppPref.getString(AppPref.PrefKey.PREF_VIRUS_TOTAL_API_KEY_STR);\n            if (TextUtils.isEmpty(apiKey)) {\n                return null;\n            }\n            return apiKey;\n        }\n\n\n        public static void setApiKey(@Nullable String apiKey) {\n            AppPref.set(AppPref.PrefKey.PREF_VIRUS_TOTAL_API_KEY_STR, apiKey);\n        }\n\n        public static boolean promptBeforeUpload() {\n            return AppPref.getBoolean(AppPref.PrefKey.PREF_VIRUS_TOTAL_PROMPT_BEFORE_UPLOADING_BOOL);\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/settings/PrivacyPreferences.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.settings;\n\nimport android.Manifest;\nimport android.content.Intent;\nimport android.os.Bundle;\n\nimport androidx.annotation.Nullable;\nimport androidx.core.content.ContextCompat;\nimport androidx.preference.SwitchPreferenceCompat;\n\nimport com.google.android.material.transition.MaterialSharedAxis;\n\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.crypto.auth.AuthManagerActivity;\nimport io.github.muntashirakon.AppManager.self.SelfPermissions;\nimport io.github.muntashirakon.AppManager.session.SessionMonitoringService;\n\npublic class PrivacyPreferences extends PreferenceFragment {\n    @Override\n    public void onCreatePreferences(@Nullable Bundle savedInstanceState, @Nullable String rootKey) {\n        setPreferencesFromResource(R.xml.preferences_privacy, rootKey);\n        getPreferenceManager().setPreferenceDataStore(new SettingsDataStore());\n        boolean isScreenLockEnabled = Prefs.Privacy.isScreenLockEnabled();\n        boolean isPersistentSessionEnabled = Prefs.Privacy.isPersistentSessionAllowed();\n        // Auto lock\n        SwitchPreferenceCompat autoLock = requirePreference(\"enable_auto_lock\");\n        autoLock.setVisible(isScreenLockEnabled && isPersistentSessionEnabled);\n        autoLock.setChecked(Prefs.Privacy.isAutoLockEnabled());\n        autoLock.setOnPreferenceChangeListener((preference, newValue) -> {\n            boolean enabled = (boolean) newValue;\n            restartServiceIfNeeded(null, enabled, null);\n            return true;\n        });\n        // Screen lock\n        SwitchPreferenceCompat screenLock = requirePreference(\"enable_screen_lock\");\n        screenLock.setChecked(isScreenLockEnabled);\n        screenLock.setOnPreferenceChangeListener((preference, newValue) -> {\n            boolean enabled = (boolean) newValue;\n            // Auto lock pref has to be updated depending on this\n            if (enabled) {\n                autoLock.setVisible(Prefs.Privacy.isPersistentSessionAllowed());\n            } else autoLock.setVisible(false);\n            restartServiceIfNeeded(enabled, null, null);\n            return true;\n        });\n        // Persistent session\n        SwitchPreferenceCompat persistentSession = requirePreference(\"enable_persistent_session\");\n        persistentSession.setChecked(isPersistentSessionEnabled);\n        persistentSession.setOnPreferenceChangeListener((preference, newValue) -> {\n            boolean enabled = (boolean) newValue;\n            // Auto lock pref has to be updated depending on this\n            if (enabled) {\n                autoLock.setVisible(Prefs.Privacy.isScreenLockEnabled());\n            } else autoLock.setVisible(false);\n            restartServiceIfNeeded(null, null, enabled);\n            return true;\n        });\n        // Toggle Internet\n        SwitchPreferenceCompat toggleInternet = requirePreference(\"toggle_internet\");\n        toggleInternet.setEnabled(SelfPermissions.checkSelfPermission(Manifest.permission.INTERNET));\n        toggleInternet.setChecked(FeatureController.isInternetEnabled());\n        toggleInternet.setOnPreferenceChangeListener((preference, newValue) -> {\n            boolean isEnabled = (boolean) newValue;\n            FeatureController.getInstance().modifyState(FeatureController.FEAT_INTERNET, isEnabled);\n            return true;\n        });\n        // Authorization Management\n        requirePreference(\"auth_manager\").setOnPreferenceClickListener(preference -> {\n            startActivity(new Intent(requireContext(), AuthManagerActivity.class));\n            return true;\n        });\n    }\n\n    @Override\n    public void onCreate(@Nullable Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setEnterTransition(new MaterialSharedAxis(MaterialSharedAxis.Z, true));\n        setReturnTransition(new MaterialSharedAxis(MaterialSharedAxis.Z, false));\n    }\n\n    @Override\n    public int getTitle() {\n        return R.string.pref_privacy;\n    }\n\n    public void restartServiceIfNeeded(@Nullable Boolean screenLockEnabled, @Nullable Boolean autoLockEnabled,\n                                       @Nullable Boolean persistentSessionEnabled) {\n        if (screenLockEnabled == null && autoLockEnabled == null && persistentSessionEnabled == null) {\n            // Nothing is set\n            return;\n        }\n        Intent service = new Intent(requireContext(), SessionMonitoringService.class);\n        if (Boolean.FALSE.equals(persistentSessionEnabled)) {\n            // Stop background session\n            requireContext().stopService(service);\n            return;\n        }\n        if (Boolean.TRUE.equals(persistentSessionEnabled)) {\n            // Start background session\n            ContextCompat.startForegroundService(requireContext(), service);\n            return;\n        }\n        persistentSessionEnabled = Prefs.Privacy.isPersistentSessionAllowed();\n        if (!persistentSessionEnabled) {\n            // Session not enabled and not running\n            return;\n        }\n        // Session enabled\n        if (autoLockEnabled != null || screenLockEnabled != null) {\n            // Auto lock preference has changed, restart service\n            requireContext().stopService(service);\n            ContextCompat.startForegroundService(requireContext(), service);\n        }\n    }\n\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/settings/RulesPreferences.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.settings;\n\nimport android.os.Bundle;\nimport android.text.SpannableStringBuilder;\n\nimport androidx.annotation.Nullable;\nimport androidx.lifecycle.ViewModelProvider;\nimport androidx.preference.Preference;\nimport androidx.preference.SwitchPreferenceCompat;\n\nimport com.google.android.material.dialog.MaterialAlertDialogBuilder;\nimport com.google.android.material.transition.MaterialSharedAxis;\n\nimport java.util.Objects;\nimport java.util.concurrent.atomic.AtomicInteger;\n\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.rules.struct.ComponentRule;\nimport io.github.muntashirakon.AppManager.self.SelfPermissions;\nimport io.github.muntashirakon.AppManager.utils.ArrayUtils;\nimport io.github.muntashirakon.AppManager.utils.FreezeUtils;\nimport io.github.muntashirakon.AppManager.utils.UIUtils;\nimport io.github.muntashirakon.dialog.DialogTitleBuilder;\nimport io.github.muntashirakon.dialog.SearchableSingleChoiceDialogBuilder;\n\npublic class RulesPreferences extends PreferenceFragment {\n    private static final String[] BLOCKING_METHODS = new String[]{\n            ComponentRule.COMPONENT_TO_BE_BLOCKED_IFW_DISABLE,\n            ComponentRule.COMPONENT_TO_BE_BLOCKED_IFW,\n            ComponentRule.COMPONENT_TO_BE_DISABLED\n    };\n\n    private static final Integer[] BLOCKING_METHOD_TITLES = new Integer[]{\n            R.string.intent_firewall_and_disable,\n            R.string.intent_firewall,\n            R.string.disable\n    };\n\n    private static final Integer[] BLOCKING_METHOD_DESCRIPTIONS = new Integer[]{\n            R.string.pref_intent_firewall_and_disable_description,\n            R.string.pref_intent_firewall_description,\n            R.string.pref_disable_description\n    };\n\n    private static final Integer[] FREEZING_METHODS = new Integer[]{\n            FreezeUtils.FREEZE_SUSPEND,\n            FreezeUtils.FREEZE_ADV_SUSPEND,\n            FreezeUtils.FREEZE_DISABLE,\n            FreezeUtils.FREEZE_HIDE\n    };\n\n    private static final Integer[] FREEZING_METHOD_TITLES = new Integer[]{\n            R.string.suspend_app,\n            R.string.advanced_suspend_app,\n            R.string.disable,\n            R.string.hide_app\n    };\n\n    private static final Integer[] FREEZING_METHOD_DESCRIPTIONS = new Integer[]{\n            R.string.suspend_app_description,\n            R.string.advanced_suspend_app_description,\n            R.string.disable_app_description,\n            R.string.hide_app_description\n    };\n\n    private SettingsActivity mActivity;\n\n    @Override\n    public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {\n        addPreferencesFromResource(R.xml.preferences_rules);\n        getPreferenceManager().setPreferenceDataStore(new SettingsDataStore());\n        MainPreferencesViewModel model = new ViewModelProvider(requireActivity()).get(MainPreferencesViewModel.class);\n        mActivity = (SettingsActivity) requireActivity();\n        // Default freezing method\n        Preference defaultFreezingMethod = Objects.requireNonNull(findPreference(\"freeze_type\"));\n        AtomicInteger freezeTypeIdx = new AtomicInteger(ArrayUtils.indexOf(FREEZING_METHODS,\n                Prefs.Blocking.getDefaultFreezingMethod()));\n        if (freezeTypeIdx.get() != -1) {\n            defaultFreezingMethod.setSummary(FREEZING_METHOD_TITLES[freezeTypeIdx.get()]);\n        }\n        defaultFreezingMethod.setEnabled(SelfPermissions.canFreezeUnfreezePackages());\n        defaultFreezingMethod.setOnPreferenceClickListener(preference -> {\n            CharSequence[] itemDescription = new CharSequence[FREEZING_METHODS.length];\n            for (int i = 0; i < FREEZING_METHODS.length; ++i) {\n                itemDescription[i] = new SpannableStringBuilder(getString(FREEZING_METHOD_TITLES[i])).append(\"\\n\")\n                        .append(UIUtils.getSmallerText(getString(FREEZING_METHOD_DESCRIPTIONS[i])));\n            }\n            new SearchableSingleChoiceDialogBuilder<>(mActivity, FREEZING_METHODS, itemDescription)\n                    .setTitle(new DialogTitleBuilder(mActivity)\n                            .setTitle(R.string.pref_default_freezing_method)\n                            .setSubtitle(R.string.pref_default_freezing_method_description)\n                            .build())\n                    .setSelection(Prefs.Blocking.getDefaultFreezingMethod())\n                    .setOnSingleChoiceClickListener((dialog, which, selectedFreezingMethod, isChecked) -> {\n                        if (!isChecked) {\n                            return;\n                        }\n                        Prefs.Blocking.setDefaultFreezingMethod(selectedFreezingMethod);\n                        defaultFreezingMethod.setSummary(FREEZING_METHOD_TITLES[which]);\n                        freezeTypeIdx.set(which);\n                        dialog.dismiss();\n                    })\n                    .setNegativeButton(R.string.close, null)\n                    .show();\n            return true;\n        });\n        // Default component blocking method\n        Preference defaultBlockingMethod = Objects.requireNonNull(findPreference(\"default_blocking_method\"));\n        // Disable this option if IFW folder can't be accessed\n        defaultBlockingMethod.setEnabled(SelfPermissions.canBlockByIFW());\n        int csIdx = ArrayUtils.indexOf(BLOCKING_METHODS, Prefs.Blocking.getDefaultBlockingMethod());\n        if (csIdx != -1) {\n            defaultBlockingMethod.setSummary(BLOCKING_METHOD_TITLES[csIdx]);\n        }\n        defaultBlockingMethod.setOnPreferenceClickListener(preference -> {\n            CharSequence[] itemDescription = new CharSequence[BLOCKING_METHODS.length];\n            for (int i = 0; i < BLOCKING_METHODS.length; ++i) {\n                itemDescription[i] = new SpannableStringBuilder(getString(BLOCKING_METHOD_TITLES[i])).append(\"\\n\")\n                        .append(UIUtils.getSmallerText(getString(BLOCKING_METHOD_DESCRIPTIONS[i])));\n            }\n            new SearchableSingleChoiceDialogBuilder<>(mActivity, BLOCKING_METHODS, itemDescription)\n                    .setTitle(new DialogTitleBuilder(mActivity)\n                            .setTitle(R.string.pref_default_blocking_method)\n                            .setSubtitle(R.string.pref_default_blocking_method_description)\n                            .build())\n                    .setSelection(Prefs.Blocking.getDefaultBlockingMethod())\n                    .setOnSingleChoiceClickListener((dialog, which, selectedBlockingMethod, isChecked) -> {\n                        if (!isChecked) {\n                            return;\n                        }\n                        Prefs.Blocking.setDefaultBlockingMethod(selectedBlockingMethod);\n                        defaultBlockingMethod.setSummary(BLOCKING_METHOD_TITLES[which]);\n                        dialog.dismiss();\n                    })\n                    .setNegativeButton(R.string.close, null)\n                    .show();\n            return true;\n        });\n        // Global blocking enabled\n        final SwitchPreferenceCompat gcb = Objects.requireNonNull(findPreference(\"global_blocking_enabled\"));\n        gcb.setChecked(Prefs.Blocking.globalBlockingEnabled());\n        gcb.setOnPreferenceChangeListener((preference, isEnabled) -> {\n            if ((boolean) isEnabled) {\n                model.applyAllRules();\n            }\n            return true;\n        });\n        // Remove all rules\n        ((Preference) Objects.requireNonNull(findPreference(\"remove_all_rules\"))).setOnPreferenceClickListener(preference -> {\n            new MaterialAlertDialogBuilder(mActivity)\n                    .setTitle(R.string.pref_remove_all_rules)\n                    .setMessage(getString(R.string.are_you_sure) + \" \" + getString(R.string.pref_remove_all_rules_msg))\n                    .setPositiveButton(R.string.yes, (dialog, which) -> {\n                        mActivity.progressIndicator.show();\n                        model.removeAllRules();\n                    })\n                    .setNegativeButton(R.string.no, null)\n                    .show();\n            return true;\n        });\n    }\n\n    @Override\n    public void onCreate(@Nullable Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setEnterTransition(new MaterialSharedAxis(MaterialSharedAxis.Z, true));\n        setReturnTransition(new MaterialSharedAxis(MaterialSharedAxis.Z, false));\n    }\n\n    @Override\n    public int getTitle() {\n        return R.string.rules;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/settings/SecurityAndOpsViewModel.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.settings;\n\nimport android.app.Application;\nimport android.os.Build;\n\nimport androidx.annotation.AnyThread;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.RequiresApi;\nimport androidx.lifecycle.AndroidViewModel;\nimport androidx.lifecycle.LiveData;\nimport androidx.lifecycle.MutableLiveData;\n\nimport io.github.muntashirakon.AppManager.BuildConfig;\nimport io.github.muntashirakon.AppManager.logs.Log;\nimport io.github.muntashirakon.AppManager.self.Migrations;\nimport io.github.muntashirakon.AppManager.utils.AppPref;\nimport io.github.muntashirakon.AppManager.utils.MultithreadedExecutor;\n\npublic class SecurityAndOpsViewModel extends AndroidViewModel implements Ops.AdbConnectionInterface {\n    public static final String TAG = SecurityAndOpsViewModel.class.getSimpleName();\n\n    private boolean mIsAuthenticating = false;\n    private final MutableLiveData<Integer> mAuthenticationStatus = new MutableLiveData<>();\n    private final MultithreadedExecutor mExecutor = MultithreadedExecutor.getNewInstance();\n\n    public SecurityAndOpsViewModel(@NonNull Application application) {\n        super(application);\n    }\n\n    @Override\n    protected void onCleared() {\n        mExecutor.shutdown();\n        super.onCleared();\n    }\n\n    public boolean isAuthenticating() {\n        return mIsAuthenticating;\n    }\n\n    public void setAuthenticating(boolean authenticating) {\n        mIsAuthenticating = authenticating;\n    }\n\n    public LiveData<Integer> authenticationStatus() {\n        return mAuthenticationStatus;\n    }\n\n    @AnyThread\n    public void setModeOfOps() {\n        mExecutor.submit(() -> {\n            // Migration\n            long thisVersion = BuildConfig.VERSION_CODE;\n            long lastVersion = AppPref.getLong(AppPref.PrefKey.PREF_LAST_VERSION_CODE_LONG);\n            if (lastVersion == 0) {\n                // First version: set this as the last version\n                AppPref.set(AppPref.PrefKey.PREF_LAST_VERSION_CODE_LONG, (long) BuildConfig.VERSION_CODE);\n                AppPref.set(AppPref.PrefKey.PREF_DISPLAY_CHANGELOG_LAST_VERSION_LONG, (long) BuildConfig.VERSION_CODE);\n            }\n            if (lastVersion < thisVersion) {\n                Log.d(TAG, \"Start migration\");\n                // App is updated\n                AppPref.set(AppPref.PrefKey.PREF_DISPLAY_CHANGELOG_BOOL, true);\n                Migrations.startMigration(lastVersion);\n                // Migration is done: set this as the last version\n                AppPref.set(AppPref.PrefKey.PREF_LAST_VERSION_CODE_LONG, (long) BuildConfig.VERSION_CODE);\n                Log.d(TAG, \"End migration\");\n            }\n            // Ops\n            Log.d(TAG, \"Before Ops::init\");\n            int status = Ops.init(getApplication(), false);\n            Log.d(TAG, \"After Ops::init\");\n            mAuthenticationStatus.postValue(status);\n        });\n    }\n\n    @AnyThread\n    @RequiresApi(Build.VERSION_CODES.R)\n    public void autoConnectWirelessDebugging() {\n        mExecutor.submit(() -> {\n            Log.d(TAG, \"Before Ops::autoConnectWirelessDebugging\");\n            int status = Ops.autoConnectWirelessDebugging(getApplication());\n            Log.d(TAG, \"After Ops::autoConnectWirelessDebugging\");\n            mAuthenticationStatus.postValue(status);\n        });\n    }\n\n    @Override\n    @AnyThread\n    public void connectAdb(int port) {\n        mExecutor.submit(() -> {\n            Log.d(TAG, \"Before Ops::connectAdb\");\n            int status = Ops.connectAdb(getApplication(), port, Ops.STATUS_FAILURE);\n            Log.d(TAG, \"After Ops::connectAdb\");\n            mAuthenticationStatus.postValue(status);\n        });\n    }\n\n    @Override\n    @AnyThread\n    @RequiresApi(Build.VERSION_CODES.R)\n    public void pairAdb() {\n        mExecutor.submit(() -> {\n            Log.d(TAG, \"Before Ops::pairAdb\");\n            int status = Ops.pairAdb(getApplication());\n            Log.d(TAG, \"After Ops::pairAdb\");\n            mAuthenticationStatus.postValue(status);\n        });\n    }\n\n    @Override\n    public void onStatusReceived(int status) {\n        mAuthenticationStatus.postValue(status);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/settings/SettingsActivity.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.settings;\n\nimport android.content.Context;\nimport android.content.Intent;\nimport android.net.Uri;\nimport android.os.Bundle;\nimport android.view.MenuItem;\nimport android.view.View;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.fragment.app.Fragment;\nimport androidx.fragment.app.FragmentContainerView;\nimport androidx.fragment.app.FragmentManager;\nimport androidx.fragment.app.FragmentTransaction;\nimport androidx.preference.Preference;\nimport androidx.preference.PreferenceFragmentCompat;\n\nimport com.google.android.material.appbar.MaterialToolbar;\nimport com.google.android.material.progressindicator.LinearProgressIndicator;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Objects;\n\nimport io.github.muntashirakon.AppManager.BaseActivity;\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.logs.Log;\nimport io.github.muntashirakon.AppManager.self.SelfUriManager;\nimport io.github.muntashirakon.util.UiUtils;\n\npublic class SettingsActivity extends BaseActivity implements PreferenceFragmentCompat.OnPreferenceStartFragmentCallback {\n    public static final String TAG = SettingsActivity.class.getSimpleName();\n\n    private static final String SAVED_KEYS = \"saved_keys\";\n\n    @NonNull\n    public static Intent getSettingsIntent(@NonNull Context context, @Nullable String... paths) {\n        Intent intent = new Intent(context, SettingsActivity.class);\n        if (paths != null) {\n            intent.setData(getSettingUri(paths));\n        }\n        return intent;\n    }\n\n    @NonNull\n    private static Uri getSettingUri(@NonNull String... pathSegments) {\n        Uri.Builder builder = new Uri.Builder()\n                .scheme(SelfUriManager.APP_MANAGER_SCHEME)\n                .authority(SelfUriManager.SETTINGS_HOST);\n        for (String pathSegment : pathSegments) {\n            builder.appendPath(pathSegment);\n        }\n        return builder.build();\n    }\n\n    public LinearProgressIndicator progressIndicator;\n    @NonNull\n    private List<String> mKeys = Collections.emptyList();\n    @NonNull\n    private ArrayList<String> mSavedKeys = new ArrayList<>();\n    private int mLevel = 0;\n    private boolean mDualPaneMode;\n    @Nullable\n    private MaterialToolbar mSecondaryToolbar;\n\n    @Override\n    protected void onAuthenticated(Bundle savedInstanceState) {\n        int mainPrefSize = UiUtils.dpToPx(this, 450);\n        int windowWidth = getResources().getDisplayMetrics().widthPixels;\n        mDualPaneMode = windowWidth >= 2 * mainPrefSize;\n        setContentView(mDualPaneMode ? R.layout.activity_settings_dual_pane : R.layout.activity_settings);\n        setSupportActionBar(findViewById(R.id.toolbar));\n        mSecondaryToolbar = findViewById(R.id.toolbar2);\n        FragmentContainerView secondaryContainer = findViewById(R.id.secondary_layout);\n        progressIndicator = findViewById(R.id.progress_linear);\n        progressIndicator.setVisibilityAfterHide(View.GONE);\n        progressIndicator.hide();\n        // Apply necessary padding: ignore start\n        if (mSecondaryToolbar != null) {\n            UiUtils.applyWindowInsetsAsPadding(mSecondaryToolbar, true, false, false, true);\n        }\n        if (secondaryContainer != null) {\n            UiUtils.applyWindowInsetsAsPadding(secondaryContainer, false, true, false, true);\n        }\n\n        if (savedInstanceState != null) {\n            clearBackStack();\n            ArrayList<String> savedKeys = savedInstanceState.getStringArrayList(SAVED_KEYS);\n            if (savedKeys != null) {\n                mSavedKeys = savedKeys;\n            }\n        }\n        setKeysFromIntent(getIntent());\n\n        getSupportFragmentManager().addFragmentOnAttachListener((fragmentManager, fragment) -> {\n            if (!(fragment instanceof MainPreferences)) {\n                ++mLevel;\n            }\n        });\n        getSupportFragmentManager().addOnBackStackChangedListener(() -> {\n            mLevel = getSupportFragmentManager().getBackStackEntryCount();\n            Log.d(TAG, \"Backstack changed. Level: %d\", mLevel);\n            // Update saved level: Delete everything from mLevel to the last item)\n            int size = mSavedKeys.size();\n            if (mLevel <= size - 1) {\n                mSavedKeys.subList(mLevel, size).clear();\n            }\n        });\n\n        String defaultPref = getKey(mLevel);\n        if (defaultPref == null && mDualPaneMode) {\n            defaultPref = \"custom_locale\";\n        }\n        getSupportFragmentManager()\n                .beginTransaction()\n                .setCustomAnimations(\n                        R.animator.enter_from_left,\n                        R.animator.enter_from_right,\n                        R.animator.exit_from_right,\n                        R.animator.exit_from_left\n                )\n                .replace(R.id.main_layout, MainPreferences.getInstance(defaultPref, mDualPaneMode))\n                .commit();\n    }\n\n    @Override\n    protected void onNewIntent(@NonNull Intent intent) {\n        super.onNewIntent(intent);\n        if (setKeysFromIntent(intent)) {\n            // Clear old items\n            mSavedKeys.clear();\n            clearBackStack();\n            Fragment fragment = getSupportFragmentManager().findFragmentById(R.id.main_layout);\n            if (fragment instanceof MainPreferences) {\n                ((MainPreferences) fragment).setPrefKey(getKey(mLevel = 0));\n                Log.d(TAG, \"Selected pref: %s\", fragment.getClass().getName());\n            }\n        }\n    }\n\n    @Override\n    public void setTitle(int titleId) {\n        if (mDualPaneMode) {\n            Objects.requireNonNull(mSecondaryToolbar).setTitle(titleId);\n        } else super.setTitle(titleId);\n    }\n\n    @Override\n    public boolean onOptionsItemSelected(@NonNull MenuItem item) {\n        if (item.getItemId() == android.R.id.home) {\n            getOnBackPressedDispatcher().onBackPressed();\n            return true;\n        }\n        return super.onOptionsItemSelected(item);\n    }\n\n    @Override\n    public boolean onPreferenceStartFragment(@NonNull PreferenceFragmentCompat caller, @NonNull Preference pref) {\n        if (pref.getFragment() == null) {\n            return false;\n        }\n        FragmentManager fragmentManager = getSupportFragmentManager();\n        Bundle args = pref.getExtras();\n        Fragment fragment = fragmentManager.getFragmentFactory().instantiate(getClassLoader(), pref.getFragment());\n        if (fragment instanceof PreferenceFragment) {\n            // Inject dual pane mode\n            args.putBoolean(PreferenceFragment.PREF_SECONDARY, mDualPaneMode);\n            // Inject subKey to the arguments\n            String subKey = getKey(mLevel + 1);\n            if (subKey != null && Objects.equals(pref.getKey(), getKey(mLevel))) {\n                args.putString(PreferenceFragment.PREF_KEY, subKey);\n            }\n            // Save current key\n            saveKey(mLevel, pref.getKey());\n        }\n        fragment.setArguments(args);\n        // The line below is kept because this is how it is handled in AndroidX library\n        fragment.setTargetFragment(caller, 0);\n        FragmentTransaction transaction = fragmentManager.beginTransaction();\n        if (!mDualPaneMode) {\n            transaction.setCustomAnimations(\n                    R.animator.enter_from_left,\n                    R.animator.enter_from_right,\n                    R.animator.exit_from_right,\n                    R.animator.exit_from_left\n            ).addToBackStack(null);\n        }\n        transaction\n                .replace(mDualPaneMode ? R.id.secondary_layout : R.id.main_layout, fragment)\n                .commit();\n        return true;\n    }\n\n    @Override\n    protected void onSaveInstanceState(@NonNull Bundle outState) {\n        outState.putStringArrayList(SAVED_KEYS, mSavedKeys);\n        super.onSaveInstanceState(outState);\n    }\n\n    @Nullable\n    private String getKey(int level) {\n        if (!mSavedKeys.isEmpty() && mSavedKeys.size() > level) {\n            String key = mSavedKeys.get(level);\n            if (key != null) {\n                return key;\n            }\n        }\n        if (mKeys.size() > level) {\n            return mKeys.get(level);\n        }\n        return null;\n    }\n\n    private void saveKey(int level, @Nullable String key) {\n        Log.d(TAG, \"Save level: %d, Key: %s\", level, key);\n        int size = mSavedKeys.size();\n        if (level >= size) {\n            // Create levels\n            int count = level - size + 1;\n            for (int i = 0; i < count; ++i) {\n                mSavedKeys.add(null);\n            }\n        }\n        // Add this level\n        mSavedKeys.set(level, key);\n    }\n\n    private boolean setKeysFromIntent(@NonNull Intent intent) {\n        Uri uri = intent.getData();\n        if (uri != null && SelfUriManager.APP_MANAGER_SCHEME.equals(uri.getScheme())\n                && SelfUriManager.SETTINGS_HOST.equals(uri.getHost()) && uri.getPath() != null) {\n            mKeys = Objects.requireNonNull(uri.getPathSegments());\n            return true;\n        }\n        return false;\n    }\n}"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/settings/SettingsDataStore.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.settings;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.preference.PreferenceDataStore;\nimport io.github.muntashirakon.AppManager.utils.AppPref;\n\npublic class SettingsDataStore extends PreferenceDataStore {\n    private final AppPref mAppPref;\n\n    public SettingsDataStore() {\n        super();\n        mAppPref = AppPref.getInstance();\n    }\n\n    @Override\n    public void putString(String key, @Nullable String value) {\n        mAppPref.setPref(key, value);\n    }\n\n    @Override\n    public void putInt(String key, int value) {\n        mAppPref.setPref(key, value);\n    }\n\n    @Override\n    public void putLong(String key, long value) {\n        mAppPref.setPref(key, value);\n    }\n\n    @Override\n    public void putFloat(String key, float value) {\n        mAppPref.setPref(key, value);\n    }\n\n    @Override\n    public void putBoolean(String key, boolean value) {\n        mAppPref.setPref(key, value);\n    }\n\n    @NonNull\n    @Override\n    public String getString(String key, @Nullable String defValue) {\n        return (String) mAppPref.get(key);\n    }\n\n    @Override\n    public int getInt(String key, int defValue) {\n        return (int) mAppPref.get(key);\n    }\n\n    @Override\n    public long getLong(String key, long defValue) {\n        return (long) mAppPref.get(key);\n    }\n\n    @Override\n    public float getFloat(String key, float defValue) {\n        return (float) mAppPref.get(key);\n    }\n\n    @Override\n    public boolean getBoolean(String key, boolean defValue) {\n        return (boolean) mAppPref.get(key);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/settings/TroubleshootingPreferences.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.settings;\n\nimport android.os.Bundle;\n\nimport androidx.annotation.Nullable;\nimport androidx.lifecycle.ViewModelProvider;\nimport androidx.preference.Preference;\n\nimport com.google.android.material.transition.MaterialSharedAxis;\n\nimport java.util.Objects;\n\nimport io.github.muntashirakon.AppManager.R;\n\npublic class TroubleshootingPreferences extends PreferenceFragment {\n    @Override\n    public void onCreatePreferences(@Nullable Bundle savedInstanceState, @Nullable String rootKey) {\n        setPreferencesFromResource(R.xml.preferences_troubleshooting, rootKey);\n        getPreferenceManager().setPreferenceDataStore(new SettingsDataStore());\n        MainPreferencesViewModel model = new ViewModelProvider(requireActivity()).get(MainPreferencesViewModel.class);\n        // Reload apps\n        ((Preference) Objects.requireNonNull(findPreference(\"reload_apps\")))\n                .setOnPreferenceClickListener(preference -> {\n                    model.reloadApps();\n                    return true;\n                });\n    }\n\n    @Override\n    public void onCreate(@Nullable Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setEnterTransition(new MaterialSharedAxis(MaterialSharedAxis.Z, true));\n        setReturnTransition(new MaterialSharedAxis(MaterialSharedAxis.Z, false));\n    }\n\n    @Override\n    public int getTitle() {\n        return R.string.troubleshooting;\n    }\n}"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/settings/VirusTotalPreferences.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.settings;\n\nimport android.graphics.Typeface;\nimport android.os.Bundle;\nimport android.text.InputType;\nimport android.text.TextUtils;\nimport android.view.inputmethod.EditorInfo;\n\nimport androidx.annotation.Nullable;\nimport androidx.core.view.inputmethod.EditorInfoCompat;\nimport androidx.lifecycle.ViewModelProvider;\nimport androidx.preference.Preference;\nimport androidx.preference.SwitchPreferenceCompat;\n\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.dialog.TextInputDialogBuilder;\nimport io.github.muntashirakon.preference.DefaultAlertPreference;\nimport io.github.muntashirakon.preference.TopSwitchPreference;\n\npublic class VirusTotalPreferences extends PreferenceFragment {\n    private MainPreferencesViewModel mModel;\n\n    @Override\n    public int getTitle() {\n        return R.string.virus_total;\n    }\n\n    @Override\n    public void onCreatePreferences(@Nullable Bundle bundle, @Nullable String rootKey) {\n        setPreferencesFromResource(R.xml.preferences_virus_total, rootKey);\n        getPreferenceManager().setPreferenceDataStore(new SettingsDataStore());\n        mModel = new ViewModelProvider(requireActivity()).get(MainPreferencesViewModel.class);\n        boolean hasInternet = FeatureController.isInternetEnabled();\n        boolean isVtEnabled = FeatureController.isVirusTotalEnabled();\n        String apiKey = Prefs.VirusTotal.getApiKey();\n        TopSwitchPreference useVtPref = requirePreference(\"use_vt\");\n        DefaultAlertPreference infoNoInternetPref = requirePreference(\"info_no_internet\");\n        Preference vtApiKeyPref = requirePreference(\"virus_total_api_key\");\n        SwitchPreferenceCompat promptBeforeUploadPref = requirePreference(\"virus_total_prompt_before_uploading\");\n        DefaultAlertPreference infoPref = requirePreference(\"info\");\n        // Set values\n        useVtPref.setEnabled(hasInternet);\n        useVtPref.setChecked(isVtEnabled);\n        useVtPref.setOnPreferenceChangeListener((preference, newValue) -> {\n            boolean isEnabled = (boolean) newValue;\n            enablePrefs(isEnabled, vtApiKeyPref, promptBeforeUploadPref);\n            FeatureController.getInstance().modifyState(FeatureController.FEAT_VIRUS_TOTAL, isEnabled);\n            return true;\n        });\n        infoNoInternetPref.setVisible(!hasInternet);\n        enablePrefs(isVtEnabled, vtApiKeyPref, promptBeforeUploadPref);\n        if (apiKey != null) {\n            vtApiKeyPref.setSummary(apiKey);\n        } else {\n            vtApiKeyPref.setSummary(R.string.key_not_set);\n        }\n        vtApiKeyPref.setOnPreferenceClickListener(preference -> {\n            new TextInputDialogBuilder(requireContext(), null)\n                    .setTitle(R.string.pref_vt_apikey)\n                    .setInputText(Prefs.VirusTotal.getApiKey())\n                    .setInputTypeface(Typeface.MONOSPACE)\n                    .setInputInputType(InputType.TYPE_CLASS_TEXT)\n                    .setInputImeOptions(EditorInfo.IME_ACTION_DONE | EditorInfoCompat.IME_FLAG_NO_PERSONALIZED_LEARNING)\n                    .setNegativeButton(R.string.cancel, null)\n                    .setPositiveButton(R.string.save, (dialog, which, inputText, isChecked) -> {\n                        String newApiKey = !TextUtils.isEmpty(inputText) ? inputText.toString() : null;\n                        Prefs.VirusTotal.setApiKey(newApiKey);\n                        if (newApiKey != null) {\n                            vtApiKeyPref.setSummary(newApiKey);\n                        } else {\n                            vtApiKeyPref.setSummary(R.string.key_not_set);\n                        }\n                    })\n                    .show();\n            return true;\n        });\n        promptBeforeUploadPref.setChecked(Prefs.VirusTotal.promptBeforeUpload());\n        infoPref.setSummary(getString(R.string.pref_vt_apikey_description) + \"\\n\\n\" + getString(R.string.vt_disclaimer));\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/settings/crypto/AESCryptoSelectionDialogFragment.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.settings.crypto;\n\nimport static io.github.muntashirakon.AppManager.crypto.AESCrypto.AES_KEY_ALIAS;\n\nimport android.app.Dialog;\nimport android.content.DialogInterface;\nimport android.os.Bundle;\nimport android.text.Editable;\nimport android.text.TextUtils;\nimport android.widget.Button;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.appcompat.app.AlertDialog;\nimport androidx.fragment.app.DialogFragment;\nimport androidx.fragment.app.FragmentActivity;\n\nimport java.nio.CharBuffer;\nimport java.security.SecureRandom;\nimport java.util.Arrays;\n\nimport javax.crypto.SecretKey;\nimport javax.crypto.spec.SecretKeySpec;\nimport javax.security.auth.DestroyFailedException;\n\nimport aosp.libcore.util.HexEncoding;\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.backup.CryptoUtils;\nimport io.github.muntashirakon.AppManager.crypto.ks.KeyStoreManager;\nimport io.github.muntashirakon.AppManager.crypto.ks.SecretKeyCompat;\nimport io.github.muntashirakon.AppManager.logs.Log;\nimport io.github.muntashirakon.AppManager.settings.Prefs;\nimport io.github.muntashirakon.AppManager.utils.ThreadUtils;\nimport io.github.muntashirakon.AppManager.utils.UIUtils;\nimport io.github.muntashirakon.AppManager.utils.Utils;\nimport io.github.muntashirakon.dialog.TextInputDialogBuilder;\nimport io.github.muntashirakon.dialog.TextInputDropdownDialogBuilder;\n\npublic class AESCryptoSelectionDialogFragment extends DialogFragment {\n    public static final String TAG = \"AESCryptoSelectionDialogFragment\";\n\n    private FragmentActivity mActivity;\n    private TextInputDialogBuilder mBuilder;\n    @Nullable\n    private KeyStoreManager mKeyStoreManager;\n    @Nullable\n    private char[] mKeyChars;\n\n    @NonNull\n    @Override\n    public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {\n        mActivity = requireActivity();\n        mBuilder = new TextInputDialogBuilder(mActivity, R.string.input_key)\n                .setTitle(R.string.aes)\n                .setNeutralButton(R.string.generate_key, null)\n                .setNegativeButton(R.string.cancel, null)\n                .setPositiveButton(R.string.save, null)\n                .setOnShowListener(dialog -> {\n                    AlertDialog dialog1 = (AlertDialog) dialog;\n                    Button positiveButton = dialog1.getButton(AlertDialog.BUTTON_POSITIVE);\n                    Button neutralButton = dialog1.getButton(AlertDialog.BUTTON_NEUTRAL);\n                    // Save\n                    positiveButton.setOnClickListener(v -> {\n                        Editable inputText = mBuilder.getInputText();\n                        if (TextUtils.isEmpty(inputText)) return;\n                        if (mKeyStoreManager == null) {\n                            UIUtils.displayLongToast(R.string.failed_to_initialize_key_store);\n                            return;\n                        }\n                        mKeyChars = new char[inputText.length()];\n                        inputText.getChars(0, inputText.length(), mKeyChars, 0);\n                        byte[] keyBytes;\n                        try {\n                            keyBytes = HexEncoding.decode(mKeyChars);\n                        } catch (IllegalArgumentException e) {\n                            UIUtils.displayLongToast(R.string.invalid_aes_key_size);\n                            return;\n                        }\n                        if (keyBytes.length != 16 && keyBytes.length != 32) {\n                            UIUtils.displayLongToast(R.string.invalid_aes_key_size);\n                            return;\n                        }\n                        SecretKey secretKey = new SecretKeySpec(keyBytes, \"AES\");\n                        try {\n                            mKeyStoreManager.addSecretKey(AES_KEY_ALIAS, secretKey, true);\n                            Prefs.Encryption.setEncryptionMode(CryptoUtils.MODE_AES);\n                        } catch (Exception e) {\n                            Log.e(TAG, e);\n                            UIUtils.displayLongToast(R.string.failed_to_save_key);\n                        }\n                        Utils.clearBytes(keyBytes);\n                        try {\n                            SecretKeyCompat.destroy(secretKey);\n                        } catch (DestroyFailedException e) {\n                            Log.e(TAG, e);\n                        }\n                        dialog.dismiss();\n                    });\n                    // Key generator\n                    neutralButton.setOnClickListener(v -> new TextInputDropdownDialogBuilder(mActivity, R.string.crypto_key_size)\n                            .setDropdownItems(Arrays.asList(128, 256), 0, false)\n                            .setTitle(R.string.generate_key)\n                            .setNegativeButton(R.string.cancel, null)\n                            .setPositiveButton(R.string.generate_key, (dialog2, which, inputText, isChecked) -> {\n                                if (TextUtils.isEmpty(inputText)) return;\n                                int keySize = 128 / 8;\n                                try {\n                                    //noinspection ConstantConditions\n                                    keySize = Integer.decode(inputText.toString().trim()) / 8;\n                                } catch (NumberFormatException ignore) {\n                                }\n                                SecureRandom random = new SecureRandom();\n                                byte[] key = new byte[keySize];\n                                random.nextBytes(key);\n                                mKeyChars = HexEncoding.encode(key);\n                                mBuilder.setInputText(CharBuffer.wrap(mKeyChars));\n                            })\n                            .show());\n                });\n        ThreadUtils.postOnBackgroundThread(() -> {\n            try {\n                mKeyStoreManager = KeyStoreManager.getInstance();\n                SecretKey secretKey = mKeyStoreManager.getSecretKey(AES_KEY_ALIAS);\n                if (secretKey != null) {\n                    mKeyChars = HexEncoding.encode(secretKey.getEncoded());\n                    try {\n                        SecretKeyCompat.destroy(secretKey);\n                    } catch (Exception ex) {\n                        Log.e(TAG, ex);\n                    }\n                    mActivity.runOnUiThread(() -> mBuilder.setInputText(CharBuffer.wrap(mKeyChars)));\n                }\n            } catch (Exception e) {\n                Log.e(TAG, e);\n            }\n        });\n        return mBuilder.create();\n    }\n\n    @Override\n    public void onDismiss(@NonNull DialogInterface dialog) {\n        if (mKeyChars != null) Utils.clearChars(mKeyChars);\n    }\n\n    @Override\n    public void onDestroy() {\n        super.onDestroy();\n        if (mKeyChars != null) Utils.clearChars(mKeyChars);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/settings/crypto/ECCCryptoSelectionDialogFragment.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.settings.crypto;\n\nimport android.app.Dialog;\nimport android.os.Bundle;\nimport android.widget.Button;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.UiThread;\nimport androidx.annotation.WorkerThread;\nimport androidx.appcompat.app.AlertDialog;\nimport androidx.fragment.app.DialogFragment;\nimport androidx.fragment.app.FragmentActivity;\n\nimport java.security.cert.CertificateEncodingException;\nimport java.security.cert.X509Certificate;\n\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.backup.CryptoUtils;\nimport io.github.muntashirakon.AppManager.crypto.ECCCrypto;\nimport io.github.muntashirakon.AppManager.crypto.ks.KeyPair;\nimport io.github.muntashirakon.AppManager.crypto.ks.KeyStoreManager;\nimport io.github.muntashirakon.AppManager.logs.Log;\nimport io.github.muntashirakon.AppManager.utils.PackageUtils;\nimport io.github.muntashirakon.AppManager.utils.ThreadUtils;\nimport io.github.muntashirakon.AppManager.utils.UIUtils;\nimport io.github.muntashirakon.dialog.ScrollableDialogBuilder;\n\npublic class ECCCryptoSelectionDialogFragment extends DialogFragment {\n    public static final String TAG = ECCCryptoSelectionDialogFragment.class.getSimpleName();\n\n    public interface OnKeyPairUpdatedListener {\n        @UiThread\n        void keyPairUpdated(@Nullable KeyPair keyPair, @Nullable byte[] certificateBytes);\n    }\n\n    private FragmentActivity mActivity;\n    private ScrollableDialogBuilder mBuilder;\n    @Nullable\n    private OnKeyPairUpdatedListener mListener;\n    @Nullable\n    private KeyStoreManager mKeyStoreManager;\n    private final String mTargetAlias = ECCCrypto.ECC_KEY_ALIAS;\n\n    public void setOnKeyPairUpdatedListener(OnKeyPairUpdatedListener listener) {\n        mListener = listener;\n    }\n\n    @NonNull\n    @Override\n    public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {\n        mActivity = requireActivity();\n        mBuilder = new ScrollableDialogBuilder(mActivity)\n                .setTitle(R.string.ecc)\n                .setPositiveButton(R.string.ok, null)\n                .setNegativeButton(R.string.pref_import, null)\n                .setNeutralButton(R.string.generate_key, null);\n        ThreadUtils.postOnBackgroundThread(() -> {\n            if (ThreadUtils.isInterrupted()) return;\n            CharSequence info = getSigningInfo();\n            ThreadUtils.postOnMainThread(() -> mBuilder.setMessage(info));\n        });\n        AlertDialog alertDialog = mBuilder.create();\n        alertDialog.setOnShowListener(dialog -> {\n            AlertDialog dialog1 = (AlertDialog) dialog;\n            Button defaultOrOkButton = dialog1.getButton(AlertDialog.BUTTON_POSITIVE);\n            Button importButton = dialog1.getButton(AlertDialog.BUTTON_NEGATIVE);\n            Button generateButton = dialog1.getButton(AlertDialog.BUTTON_NEUTRAL);\n            importButton.setOnClickListener(v -> {\n                KeyPairImporterDialogFragment fragment = new KeyPairImporterDialogFragment();\n                Bundle args = new Bundle();\n                args.putString(KeyPairImporterDialogFragment.EXTRA_ALIAS, mTargetAlias);\n                fragment.setArguments(args);\n                fragment.setOnKeySelectedListener((keyPair) -> ThreadUtils.postOnBackgroundThread(() ->\n                        addKeyPair(keyPair)));\n                fragment.show(getParentFragmentManager(), KeyPairImporterDialogFragment.TAG);\n            });\n            generateButton.setOnClickListener(v -> {\n                KeyPairGeneratorDialogFragment fragment = new KeyPairGeneratorDialogFragment();\n                Bundle args = new Bundle();\n                args.putString(KeyPairGeneratorDialogFragment.EXTRA_KEY_TYPE, CryptoUtils.MODE_ECC);\n                fragment.setArguments(args);\n                fragment.setOnGenerateListener((keyPair) -> ThreadUtils.postOnBackgroundThread(() ->\n                        addKeyPair(keyPair)));\n                fragment.show(getParentFragmentManager(), KeyPairGeneratorDialogFragment.TAG);\n            });\n            defaultOrOkButton.setOnClickListener(v -> ThreadUtils.postOnBackgroundThread(() -> {\n                try {\n                    if (ThreadUtils.isInterrupted()) return;\n                    ThreadUtils.postOnMainThread(() -> UIUtils.displayShortToast(R.string.done));\n                    keyPairUpdated();\n                } catch (Exception e) {\n                    Log.e(TAG, e);\n                    ThreadUtils.postOnMainThread(() -> UIUtils.displayLongToast(R.string.failed_to_save_key));\n                } finally {\n                    alertDialog.dismiss();\n                }\n            }));\n        });\n        return alertDialog;\n    }\n\n    @WorkerThread\n    private CharSequence getSigningInfo() {\n        KeyPair keyPair = getKeyPair();\n        if (keyPair != null) {\n            try {\n                return PackageUtils.getSigningCertificateInfo(mActivity, (X509Certificate) keyPair.getCertificate());\n            } catch (CertificateEncodingException e) {\n                return getString(R.string.failed_to_load_key);\n            }\n        }\n        return getString(R.string.key_not_set);\n    }\n\n    @WorkerThread\n    private void addKeyPair(@Nullable KeyPair keyPair) {\n        try {\n            if (keyPair == null) {\n                throw new Exception(\"Keypair can't be null.\");\n            }\n            mKeyStoreManager = KeyStoreManager.getInstance();\n            mKeyStoreManager.addKeyPair(mTargetAlias, keyPair, true);\n            if (ThreadUtils.isInterrupted()) return;\n            ThreadUtils.postOnMainThread(() -> UIUtils.displayShortToast(R.string.done));\n            keyPairUpdated();\n            if (ThreadUtils.isInterrupted()) return;\n            CharSequence info = getSigningInfo();\n            ThreadUtils.postOnMainThread(() -> mBuilder.setMessage(info));\n        } catch (Exception e) {\n            Log.e(TAG, e);\n            ThreadUtils.postOnMainThread(() -> UIUtils.displayLongToast(R.string.failed_to_save_key));\n        }\n    }\n\n    @WorkerThread\n    private void keyPairUpdated() {\n        try {\n            KeyPair keyPair = getKeyPair();\n            if (keyPair != null) {\n                if (mListener != null) {\n                    byte[] bytes = keyPair.getCertificate().getEncoded();\n                    ThreadUtils.postOnMainThread(() -> mListener.keyPairUpdated(keyPair, bytes));\n                }\n                return;\n            }\n        } catch (Exception e) {\n            Log.e(TAG, e);\n        }\n        if (mListener != null) {\n            ThreadUtils.postOnMainThread(() -> mListener.keyPairUpdated(null, null));\n        }\n    }\n\n    @WorkerThread\n    @Nullable\n    private KeyPair getKeyPair() {\n        try {\n            mKeyStoreManager = KeyStoreManager.getInstance();\n            if (mKeyStoreManager.containsKey(mTargetAlias)) {\n                return mKeyStoreManager.getKeyPair(mTargetAlias);\n            }\n        } catch (Exception e) {\n            Log.e(TAG, e);\n        }\n        return null;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/settings/crypto/ImportExportKeyStoreDialogFragment.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.settings.crypto;\n\nimport static io.github.muntashirakon.AppManager.crypto.ks.KeyStoreManager.AM_KEYSTORE_FILE;\n\nimport android.app.Dialog;\nimport android.os.Bundle;\nimport android.widget.Button;\n\nimport androidx.activity.result.ActivityResultLauncher;\nimport androidx.activity.result.contract.ActivityResultContracts;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.appcompat.app.AlertDialog;\nimport androidx.fragment.app.DialogFragment;\nimport androidx.fragment.app.FragmentActivity;\n\nimport com.google.android.material.dialog.MaterialAlertDialogBuilder;\n\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.TimeUnit;\n\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.crypto.ks.KeyStoreManager;\nimport io.github.muntashirakon.AppManager.utils.ExUtils;\nimport io.github.muntashirakon.AppManager.utils.ThreadUtils;\nimport io.github.muntashirakon.AppManager.utils.UIUtils;\nimport io.github.muntashirakon.io.IoUtils;\n\npublic class ImportExportKeyStoreDialogFragment extends DialogFragment {\n    public static final String TAG = \"IEKeyStoreDialogFragment\";\n\n    private FragmentActivity mActivity;\n    private final ActivityResultLauncher<String> mExportKeyStore = registerForActivityResult(\n            new ActivityResultContracts.CreateDocument(\"application/octet-stream\"), uri -> {\n                if (uri == null) {\n                    dismiss();\n                    return;\n                }\n                ThreadUtils.postOnBackgroundThread(() -> {\n                    try (InputStream is = new FileInputStream(AM_KEYSTORE_FILE);\n                         OutputStream os = mActivity.getContentResolver().openOutputStream(uri)) {\n                        if (os == null) throw new IOException(\"Unable to open URI\");\n                        IoUtils.copy(is, os);\n                        ThreadUtils.postOnMainThread(() -> {\n                            UIUtils.displayShortToast(R.string.done);\n                            ExUtils.exceptionAsIgnored(this::dismiss);\n                        });\n                    } catch (IOException e) {\n                        ThreadUtils.postOnMainThread(() -> {\n                            UIUtils.displayShortToast(R.string.failed);\n                            ExUtils.exceptionAsIgnored(this::dismiss);\n                        });\n                    }\n                });\n            });\n    private final ActivityResultLauncher<String> mImportKeyStore = registerForActivityResult(\n            new ActivityResultContracts.GetContent(), uri -> {\n                if (uri == null) {\n                    dismiss();\n                    return;\n                }\n                new MaterialAlertDialogBuilder(mActivity)\n                        .setTitle(R.string.import_keystore)\n                        .setMessage(R.string.confirm_import_keystore)\n                        .setPositiveButton(R.string.yes, (dialog, which) -> ThreadUtils.postOnBackgroundThread(() -> {\n                            // Rename old file that will be restored in case of error\n                            File tmpFile = new File(AM_KEYSTORE_FILE.getAbsolutePath() + \".tmp\");\n                            if (AM_KEYSTORE_FILE.exists()) {\n                                AM_KEYSTORE_FILE.renameTo(tmpFile);\n                            }\n                            try (InputStream is = mActivity.getContentResolver().openInputStream(uri);\n                                 OutputStream os = new FileOutputStream(AM_KEYSTORE_FILE)) {\n                                if (is == null) throw new IOException(\"Unable to open URI\");\n                                IoUtils.copy(is, os);\n                                if (KeyStoreManager.hasKeyStorePassword()) {\n                                    CountDownLatch waitForKs = new CountDownLatch(1);\n                                    KeyStoreManager.inputKeyStorePassword(mActivity, waitForKs::countDown);\n                                    waitForKs.await(2, TimeUnit.MINUTES);\n                                    if (waitForKs.getCount() == 1) {\n                                        throw new Exception();\n                                    }\n                                }\n                                KeyStoreManager.reloadKeyStore();\n                                // TODO: 21/4/21 Only import the keys that we use instead of replacing the entire keystore\n                                ThreadUtils.postOnMainThread(() -> {\n                                    UIUtils.displayShortToast(R.string.done);\n                                    ExUtils.exceptionAsIgnored(this::dismiss);\n                                });\n                            } catch (Exception e) {\n                                if (tmpFile.exists()) {\n                                    AM_KEYSTORE_FILE.delete();\n                                    tmpFile.renameTo(AM_KEYSTORE_FILE);\n                                    try {\n                                        KeyStoreManager.reloadKeyStore();\n                                    } catch (Exception ignore) {\n                                    }\n                                }\n                                ThreadUtils.postOnMainThread(() -> {\n                                    UIUtils.displayShortToast(R.string.failed);\n                                    ExUtils.exceptionAsIgnored(this::dismiss);\n                                });\n                            }\n                        }))\n                        .setNegativeButton(R.string.close, (dialog, which) -> dismiss())\n                        .setCancelable(false)\n                        .show();\n            });\n\n    @NonNull\n    @Override\n    public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {\n        mActivity = requireActivity();\n        MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(mActivity)\n                .setTitle(R.string.pref_import_export_keystore)\n                .setMessage(R.string.choose_what_to_do)\n                .setPositiveButton(R.string.pref_export, null)\n                .setNegativeButton(R.string.cancel, null)\n                .setNeutralButton(R.string.pref_import, null);\n        AlertDialog alertDialog = builder.create();\n        alertDialog.setOnShowListener(dialog -> {\n            AlertDialog dialog1 = (AlertDialog) dialog;\n            Button exportButton = dialog1.getButton(AlertDialog.BUTTON_POSITIVE);\n            Button importButton = dialog1.getButton(AlertDialog.BUTTON_NEUTRAL);\n            if (AM_KEYSTORE_FILE.exists()) {\n                exportButton.setOnClickListener(v -> mExportKeyStore.launch(KeyStoreManager.AM_KEYSTORE_FILE_NAME));\n            }\n            importButton.setOnClickListener(v -> mImportKeyStore.launch(\"application/*\"));\n        });\n        return alertDialog;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/settings/crypto/KeyPairGeneratorDialogFragment.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.settings.crypto;\n\nimport android.app.Dialog;\nimport android.os.Bundle;\nimport android.text.TextUtils;\nimport android.view.View;\nimport android.widget.EditText;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.UiThread;\nimport androidx.fragment.app.DialogFragment;\nimport androidx.fragment.app.FragmentActivity;\n\nimport com.google.android.material.datepicker.MaterialDatePicker;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.concurrent.atomic.AtomicReference;\n\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.backup.CryptoUtils;\nimport io.github.muntashirakon.AppManager.crypto.ks.KeyPair;\nimport io.github.muntashirakon.AppManager.crypto.ks.KeyStoreUtils;\nimport io.github.muntashirakon.AppManager.logs.Log;\nimport io.github.muntashirakon.AppManager.utils.DateUtils;\nimport io.github.muntashirakon.AppManager.utils.ExUtils;\nimport io.github.muntashirakon.AppManager.utils.ThreadUtils;\nimport io.github.muntashirakon.AppManager.utils.UIUtils;\nimport io.github.muntashirakon.adapters.SelectedArrayAdapter;\nimport io.github.muntashirakon.dialog.AlertDialogBuilder;\nimport io.github.muntashirakon.widget.MaterialSpinner;\n\npublic class KeyPairGeneratorDialogFragment extends DialogFragment {\n    public static final String TAG = \"KeyPairGeneratorDialogFragment\";\n\n    public static final String EXTRA_KEY_TYPE = \"type\";\n\n    public static final List<Integer> SUPPORTED_RSA_KEY_SIZES = Arrays.asList(2048, 4096);\n\n    public interface OnGenerateListener {\n        void onGenerate(@Nullable KeyPair keyPair);\n    }\n\n    private OnGenerateListener mListener;\n    private int mKeySize;\n    private long mExpiryDate;\n    @CryptoUtils.Mode\n    private String mKeyType;\n\n    public void setOnGenerateListener(OnGenerateListener listener) {\n        mListener = listener;\n    }\n\n    @NonNull\n    @Override\n    public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {\n        FragmentActivity activity = requireActivity();\n        mKeyType = requireArguments().getString(EXTRA_KEY_TYPE, CryptoUtils.MODE_RSA);\n        View view = View.inflate(activity, R.layout.dialog_certificate_generator, null);\n        MaterialSpinner keySizeSpinner = view.findViewById(R.id.key_size_selector_spinner);\n        if (mKeyType.equals(CryptoUtils.MODE_RSA)) {\n            mKeySize = 2048;\n            keySizeSpinner.setAdapter(new SelectedArrayAdapter<>(activity, androidx.appcompat.R.layout.support_simple_spinner_dropdown_item,\n                    SUPPORTED_RSA_KEY_SIZES));\n            keySizeSpinner.setOnItemClickListener((parent, view1, position, id) ->\n                    mKeySize = SUPPORTED_RSA_KEY_SIZES.get(position));\n        } else {\n            // There's no keysize for ECC\n            keySizeSpinner.setVisibility(View.GONE);\n        }\n        EditText expiryDate = view.findViewById(R.id.expiry_date);\n        expiryDate.setKeyListener(null);\n        expiryDate.setOnFocusChangeListener((v, hasFocus) -> {\n            if (v.isInTouchMode() && hasFocus) {\n                v.performClick();\n            }\n        });\n        expiryDate.setOnClickListener(v -> pickExpiryDate(expiryDate));\n        EditText commonName = view.findViewById(R.id.common_name);\n        EditText orgUnit = view.findViewById(R.id.organization_unit);\n        EditText orgName = view.findViewById(R.id.organization_name);\n        EditText locality = view.findViewById(R.id.locality_name);\n        EditText state = view.findViewById(R.id.state_name);\n        EditText country = view.findViewById(R.id.country_name);\n        AlertDialogBuilder builder = new AlertDialogBuilder(activity, true)\n                .setTitle(R.string.generate_key)\n                .setView(view)\n                .setExitOnButtonPress(false)\n                .setPositiveButton(R.string.generate_key, (dialog, which) -> ThreadUtils.postOnBackgroundThread(() -> {\n                    AtomicReference<KeyPair> keyPair = new AtomicReference<>(null);\n                    String formattedSubject = getFormattedSubject(commonName.getText().toString(),\n                            orgUnit.getText().toString(), orgName.getText().toString(),\n                            locality.getText().toString(), state.getText().toString(),\n                            country.getText().toString());\n                    if (mExpiryDate == 0) {\n                        ThreadUtils.postOnMainThread(() -> UIUtils.displayShortToast(R.string.expiry_date_cannot_be_empty));\n                        return;\n                    }\n                    if (formattedSubject.isEmpty()) {\n                        formattedSubject = \"CN=App Manager\";\n                    }\n                    try {\n                        if (mKeyType.equals(CryptoUtils.MODE_RSA)) {\n                            keyPair.set(KeyStoreUtils.generateRSAKeyPair(formattedSubject, mKeySize, mExpiryDate));\n                        } else if (mKeyType.equals(CryptoUtils.MODE_ECC)) {\n                            keyPair.set(KeyStoreUtils.generateECCKeyPair(formattedSubject, mExpiryDate));\n                        }\n                    } catch (Exception e) {\n                        Log.e(TAG, e);\n                    } finally {\n                        ThreadUtils.postOnMainThread(() -> {\n                            if (mListener != null) mListener.onGenerate(keyPair.get());\n                            ExUtils.exceptionAsIgnored(dialog::dismiss);\n                        });\n                    }\n                }))\n                .setNegativeButton(R.string.cancel, null);\n        return builder.create();\n    }\n\n    @NonNull\n    public String getFormattedSubject(@Nullable String commonName,\n                                      @Nullable String organizationUnit,\n                                      @Nullable String organizationName,\n                                      @Nullable String localityName,\n                                      @Nullable String stateName,\n                                      @Nullable String countryName) {\n        List<String> subjectArray = new ArrayList<>(6);\n        if (!TextUtils.isEmpty(commonName)) subjectArray.add(\"CN=\" + commonName);\n        if (!TextUtils.isEmpty(organizationUnit)) subjectArray.add(\"OU=\" + organizationUnit);\n        if (!TextUtils.isEmpty(organizationName)) subjectArray.add(\"O=\" + organizationName);\n        if (!TextUtils.isEmpty(localityName)) subjectArray.add(\"L=\" + localityName);\n        if (!TextUtils.isEmpty(stateName)) subjectArray.add(\"ST=\" + stateName);\n        if (!TextUtils.isEmpty(countryName)) subjectArray.add(\"C=\" + countryName);\n        return TextUtils.join(\", \", subjectArray);\n    }\n\n    @UiThread\n    public void pickExpiryDate(EditText expiryDate) {\n        MaterialDatePicker<Long> datePicker = MaterialDatePicker.Builder.datePicker()\n                .setTitleText(R.string.expiry_date)\n                .setSelection(MaterialDatePicker.todayInUtcMilliseconds())\n                .build();\n        datePicker.addOnPositiveButtonClickListener(selection -> {\n            mExpiryDate = selection;\n            expiryDate.setText(DateUtils.formatDate(requireContext(), selection));\n        });\n        datePicker.show(getChildFragmentManager(), \"DatePicker\");\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/settings/crypto/KeyPairImporterDialogFragment.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.settings.crypto;\n\nimport android.app.Dialog;\nimport android.net.Uri;\nimport android.os.Bundle;\nimport android.text.method.KeyListener;\nimport android.view.View;\nimport android.widget.Button;\nimport android.widget.EditText;\n\nimport androidx.activity.result.contract.ActivityResultContracts;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.appcompat.app.AlertDialog;\nimport androidx.fragment.app.DialogFragment;\nimport androidx.fragment.app.FragmentActivity;\n\nimport com.google.android.material.dialog.MaterialAlertDialogBuilder;\nimport com.google.android.material.textfield.TextInputLayout;\n\nimport java.util.ArrayList;\n\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.crypto.ks.KeyPair;\nimport io.github.muntashirakon.AppManager.crypto.ks.KeyStoreUtils;\nimport io.github.muntashirakon.AppManager.logs.Log;\nimport io.github.muntashirakon.AppManager.utils.BetterActivityResult;\nimport io.github.muntashirakon.AppManager.utils.ExUtils;\nimport io.github.muntashirakon.AppManager.utils.ThreadUtils;\nimport io.github.muntashirakon.AppManager.utils.UIUtils;\nimport io.github.muntashirakon.AppManager.utils.Utils;\nimport io.github.muntashirakon.adapters.SelectedArrayAdapter;\nimport io.github.muntashirakon.dialog.TextInputDropdownDialogBuilder;\nimport io.github.muntashirakon.widget.MaterialSpinner;\n\npublic class KeyPairImporterDialogFragment extends DialogFragment {\n    public static final String TAG = \"KeyPairImporterDialogFragment\";\n\n    public static final String EXTRA_ALIAS = \"alias\";\n\n    public interface OnKeySelectedListener {\n        void onKeySelected(@Nullable KeyPair keyPair);\n    }\n\n    @Nullable\n    private OnKeySelectedListener mListener;\n    private FragmentActivity mActivity;\n    private TextInputLayout mKsPassOrPk8Layout;\n    private EditText mKsPassOrPk8;\n    private KeyListener mKeyListener;\n    private TextInputLayout mKsLocationOrPemLayout;\n    private EditText mKsLocationOrPem;\n    @KeyStoreUtils.KeyType\n    private int mKeyType;\n    @Nullable\n    private Uri mKsOrPemFile;\n    @Nullable\n    private Uri mPk8File;\n    private final BetterActivityResult<String, Uri> mImportFile = BetterActivityResult\n            .registerForActivityResult(this, new ActivityResultContracts.GetContent());\n\n    public void setOnKeySelectedListener(OnKeySelectedListener listener) {\n        mListener = listener;\n    }\n\n    @NonNull\n    @Override\n    public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {\n        mActivity = requireActivity();\n        String targetAlias = requireArguments().getString(EXTRA_ALIAS);\n        if (targetAlias == null) {\n            return super.onCreateDialog(savedInstanceState);\n        }\n        View view = getLayoutInflater().inflate(R.layout.dialog_key_pair_importer, null);\n        MaterialSpinner keyTypeSpinner = view.findViewById(R.id.key_type_selector_spinner);\n        mKsPassOrPk8Layout = view.findViewById(R.id.hint);\n        mKsPassOrPk8 = view.findViewById(R.id.text);\n        mKeyListener = mKsPassOrPk8.getKeyListener();\n        mKsLocationOrPemLayout = view.findViewById(R.id.hint2);\n        mKsLocationOrPem = view.findViewById(R.id.text2);\n        mKsLocationOrPem.setKeyListener(null);\n        mKsLocationOrPem.setOnFocusChangeListener((v, hasFocus) -> {\n            if (v.isInTouchMode() && hasFocus) {\n                v.performClick();\n            }\n        });\n        mKsLocationOrPem.setOnClickListener(v -> mImportFile.launch(\"application/*\", result -> {\n            mKsOrPemFile = result;\n            if (result != null) {\n                mKsLocationOrPem.setText(result.toString());\n            }\n        }));\n        keyTypeSpinner.setAdapter(SelectedArrayAdapter.createFromResource(mActivity, R.array.crypto_import_types,\n                io.github.muntashirakon.ui.R.layout.auto_complete_dropdown_item));\n        keyTypeSpinner.setOnItemClickListener((parent, view1, position, id) -> {\n                mKsPassOrPk8.setText(null);\n                mKsLocationOrPem.setText(null);\n\n                if (position == KeyStoreUtils.KeyType.PK8) {\n                    // PKCS #8 and PEM\n                    mKsPassOrPk8Layout.setHint(R.string.pk8_file);\n                    mKsPassOrPk8.setKeyListener(null);\n                    mKsPassOrPk8.setOnFocusChangeListener((v, hasFocus) -> {\n                        if (v.isInTouchMode() && hasFocus) {\n                            v.performClick();\n                        }\n                    });\n                    mKsPassOrPk8.setOnClickListener(v -> mImportFile.launch(\"application/*\", result -> {\n                        mPk8File = result;\n                        if (result != null) {\n                            mKsPassOrPk8.setText(result.toString());\n                        }\n                    }));\n                    mKsLocationOrPemLayout.setHint(R.string.pem_file);\n                } else {\n                    // KeyStore\n                    setDefault();\n                }\n                mKeyType = position;\n        });\n        setDefault();\n        AlertDialog alertDialog = new MaterialAlertDialogBuilder(mActivity)\n                .setTitle(R.string.import_key)\n                .setView(view)\n                .setPositiveButton(R.string.ok, null)\n                .setNegativeButton(R.string.cancel, null)\n                .create();\n        alertDialog.setOnShowListener(dialog -> {\n            AlertDialog dialog1 = (AlertDialog) dialog;\n            Button okButton = dialog1.getButton(AlertDialog.BUTTON_POSITIVE);\n            okButton.setOnClickListener(v -> {\n                if (mListener == null) return;\n                if (mKeyType == KeyStoreUtils.KeyType.PK8) {\n                    // PKCS #8 and PEM\n                    try {\n                        if (mPk8File == null || mKsOrPemFile == null) {\n                            throw new Exception(\"PK8 or PEM can't be null.\");\n                        }\n                        KeyPair keyPair = KeyStoreUtils.getKeyPair(mActivity, mPk8File, mKsOrPemFile);\n                        mListener.onKeySelected(keyPair);\n                    } catch (Exception e) {\n                        Log.e(TAG, e);\n                        mListener.onKeySelected(null);\n                    }\n                    dialog.dismiss();\n                } else {\n                    // KeyStore\n                    char[] ksPassword = Utils.getChars(mKsPassOrPk8.getText());\n                    ThreadUtils.postOnBackgroundThread(() -> {\n                        try {\n                            if (mKsOrPemFile == null) {\n                                throw new Exception(\"KeyStore file can't be null.\");\n                            }\n                            ArrayList<String> aliases = KeyStoreUtils.listAliases(mActivity, mKsOrPemFile, mKeyType,\n                                    ksPassword);\n                            if (mListener == null) return;\n                            ThreadUtils.postOnMainThread(() -> {\n                                if (aliases.isEmpty()) {\n                                    UIUtils.displayLongToast(R.string.found_no_alias_in_keystore);\n                                    ExUtils.exceptionAsIgnored(dialog::dismiss);\n                                    return;\n                                }\n                                TextInputDropdownDialogBuilder builder;\n                                builder = new TextInputDropdownDialogBuilder(mActivity, R.string.choose_an_alias)\n                                        .setDropdownItems(aliases, -1, true)\n                                        .setAuxiliaryInputLabel(R.string.alias_pass)\n                                        .setTitle(R.string.choose_an_alias)\n                                        .setNegativeButton(R.string.cancel, null);\n                                builder.setPositiveButton(R.string.ok, (dialog2, which, inputText, isChecked) -> {\n                                    String aliasName = inputText == null ? null : inputText.toString();\n                                    char[] aliasPassword = Utils.getChars(builder.getAuxiliaryInput());\n                                    ThreadUtils.postOnBackgroundThread(() -> {\n                                        try {\n                                            KeyPair keyPair = KeyStoreUtils.getKeyPair(mActivity, mKsOrPemFile, mKeyType,\n                                                    aliasName, ksPassword, aliasPassword);\n                                            mListener.onKeySelected(keyPair);\n                                        } catch (Exception e) {\n                                            Log.e(TAG, e);\n                                            mListener.onKeySelected(null);\n                                        }\n                                        ThreadUtils.postOnMainThread(() -> ExUtils.exceptionAsIgnored(dialog::dismiss));\n                                    });\n                                }).show();\n                            });\n                        } catch (Exception e) {\n                            Log.e(TAG, e);\n                            ThreadUtils.postOnMainThread(() -> UIUtils.displayLongToast(R.string.failed_to_read_keystore));\n                        }\n                    });\n                }\n            });\n        });\n        return alertDialog;\n    }\n\n    private void setDefault() {\n        mKeyType = KeyStoreUtils.KeyType.JKS;\n        // KeyStore\n        mKsPassOrPk8Layout.setHint(R.string.keystore_pass);\n        mKsPassOrPk8.setKeyListener(mKeyListener);\n        mKsPassOrPk8.setOnFocusChangeListener(null);\n        mKsPassOrPk8.setOnClickListener(null);\n        mKsLocationOrPemLayout.setHint(R.string.keystore_file);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/settings/crypto/OpenPgpKeySelectionDialogFragment.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.settings.crypto;\n\nimport android.app.Dialog;\nimport android.app.PendingIntent;\nimport android.content.Intent;\nimport android.content.pm.PackageManager;\nimport android.content.pm.ServiceInfo;\nimport android.os.Bundle;\nimport android.text.TextUtils;\nimport android.widget.Button;\n\nimport androidx.activity.result.ActivityResultLauncher;\nimport androidx.activity.result.IntentSenderRequest;\nimport androidx.activity.result.contract.ActivityResultContracts;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.appcompat.app.AlertDialog;\nimport androidx.fragment.app.DialogFragment;\nimport androidx.fragment.app.FragmentActivity;\n\nimport org.openintents.openpgp.IOpenPgpService2;\nimport org.openintents.openpgp.OpenPgpError;\nimport org.openintents.openpgp.util.OpenPgpApi;\nimport org.openintents.openpgp.util.OpenPgpServiceConnection;\nimport org.openintents.openpgp.util.OpenPgpUtils;\n\nimport java.util.List;\nimport java.util.Objects;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\n\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.intercept.IntentCompat;\nimport io.github.muntashirakon.AppManager.logs.Log;\nimport io.github.muntashirakon.AppManager.settings.Prefs;\nimport io.github.muntashirakon.dialog.SearchableSingleChoiceDialogBuilder;\n\npublic class OpenPgpKeySelectionDialogFragment extends DialogFragment {\n    public static final String TAG = \"OpenPgpKeySelectionDialogFragment\";\n\n    private String mOpenPgpProvider;\n    private OpenPgpServiceConnection mServiceConnection;\n    private AlertDialog mDialog;\n    private FragmentActivity mActivity;\n    private final ActivityResultLauncher<IntentSenderRequest> mKeyIdResultLauncher = registerForActivityResult(\n            new ActivityResultContracts.StartIntentSenderForResult(), result -> {\n                if (result.getData() != null) {\n                    getUserId(result.getData());\n                }\n            });\n    private final ExecutorService mExecutor = Executors.newSingleThreadExecutor(runnable -> {\n        Thread thread = new Thread(runnable);\n        thread.setDaemon(true);\n        return thread;\n    });\n\n    @NonNull\n    @Override\n    public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {\n        mActivity = requireActivity();\n        mOpenPgpProvider = Prefs.Encryption.getOpenPgpProvider();\n        List<ServiceInfo> serviceInfoList = OpenPgpUtils.getPgpClientServices(mActivity);\n        CharSequence[] packageLabels = new String[serviceInfoList.size()];\n        String[] packageNames = new String[serviceInfoList.size()];\n        ServiceInfo serviceInfo;\n        PackageManager pm = mActivity.getPackageManager();\n        for (int i = 0; i < packageLabels.length; ++i) {\n            serviceInfo = serviceInfoList.get(i);\n            packageLabels[i] = serviceInfo.loadLabel(pm);\n            packageNames[i] = serviceInfo.packageName;\n        }\n        mDialog = new SearchableSingleChoiceDialogBuilder<>(mActivity, packageNames, packageLabels)\n                .setTitle(R.string.open_pgp_provider)\n                .setSelection(mOpenPgpProvider)\n                .setNegativeButton(R.string.cancel, null)\n                .setPositiveButton(R.string.save, (dialog1, which, selectedItem) -> {\n                    if (selectedItem != null) {\n                        mOpenPgpProvider = selectedItem;\n                        Prefs.Encryption.setOpenPgpProvider(mOpenPgpProvider);\n                    }\n                })\n                .create();\n        mDialog.setOnShowListener(dialog1 -> {\n            Button positiveButton = ((AlertDialog) dialog1).getButton(AlertDialog.BUTTON_POSITIVE);\n            positiveButton.setOnClickListener(v -> chooseKey());\n        });\n        return mDialog;\n    }\n\n    private void chooseKey() {\n        // Bind to service\n        mServiceConnection = new OpenPgpServiceConnection(requireContext(), mOpenPgpProvider,\n                new OpenPgpServiceConnection.OnBound() {\n                    @Override\n                    public void onBound(IOpenPgpService2 service) {\n                        getUserId(new Intent());\n                    }\n\n                    @Override\n                    public void onError(Exception e) {\n                        Log.e(OpenPgpApi.TAG, \"exception on binding!\", e);\n                    }\n                }\n        );\n        mServiceConnection.bindToService();\n    }\n\n    private void getUserId(@NonNull Intent data) {\n        data.setAction(OpenPgpApi.ACTION_GET_KEY_IDS);\n        data.putExtra(OpenPgpApi.EXTRA_USER_IDS, new String[]{});\n        OpenPgpApi api = new OpenPgpApi(mActivity, mServiceConnection.getService());\n        api.executeApiAsync(mExecutor, data, null, null, result -> {\n            switch (result.getIntExtra(OpenPgpApi.RESULT_CODE, OpenPgpApi.RESULT_CODE_ERROR)) {\n                case OpenPgpApi.RESULT_CODE_SUCCESS: {\n                    long[] keyIds = result.getLongArrayExtra(OpenPgpApi.EXTRA_KEY_IDS);\n                    if (keyIds == null || keyIds.length == 0) {\n                        // Remove encryption\n                        Prefs.Encryption.setOpenPgpProvider(\"\");\n                        Prefs.Encryption.setOpenPgpKeyIds(\"\");\n                    } else {\n                        String[] keyIdsStr = new String[keyIds.length];\n                        for (int i = 0; i < keyIds.length; ++i) {\n                            keyIdsStr[i] = String.valueOf(keyIds[i]);\n                        }\n                        Prefs.Encryption.setOpenPgpKeyIds(TextUtils.join(\",\", keyIdsStr));\n                    }\n                    mDialog.dismiss();\n                    break;\n                }\n                case OpenPgpApi.RESULT_CODE_USER_INTERACTION_REQUIRED: {\n                    PendingIntent pi = Objects.requireNonNull(IntentCompat.getParcelableExtra(result, OpenPgpApi.RESULT_INTENT, PendingIntent.class));\n                    mKeyIdResultLauncher.launch(new IntentSenderRequest.Builder(pi).build());\n                    break;\n                }\n                case OpenPgpApi.RESULT_CODE_ERROR: {\n                    OpenPgpError error = IntentCompat.getParcelableExtra(result, OpenPgpApi.RESULT_ERROR, OpenPgpError.class);\n                    if (error != null) {\n                        Log.e(OpenPgpApi.TAG, \"RESULT_CODE_ERROR: %s\", error.getMessage());\n                    }\n                    mDialog.dismiss();\n                    break;\n                }\n            }\n        });\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/settings/crypto/RSACryptoSelectionDialogFragment.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.settings.crypto;\n\nimport android.app.Application;\nimport android.app.Dialog;\nimport android.os.Bundle;\nimport android.widget.Button;\n\nimport androidx.annotation.AnyThread;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.UiThread;\nimport androidx.annotation.WorkerThread;\nimport androidx.appcompat.app.AlertDialog;\nimport androidx.core.util.Pair;\nimport androidx.fragment.app.DialogFragment;\nimport androidx.lifecycle.AndroidViewModel;\nimport androidx.lifecycle.LiveData;\nimport androidx.lifecycle.MutableLiveData;\nimport androidx.lifecycle.ViewModelProvider;\n\nimport java.security.cert.CertificateEncodingException;\nimport java.security.cert.X509Certificate;\nimport java.util.Objects;\n\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.backup.CryptoUtils;\nimport io.github.muntashirakon.AppManager.crypto.ks.KeyPair;\nimport io.github.muntashirakon.AppManager.crypto.ks.KeyStoreManager;\nimport io.github.muntashirakon.AppManager.logs.Log;\nimport io.github.muntashirakon.AppManager.utils.PackageUtils;\nimport io.github.muntashirakon.AppManager.utils.ThreadUtils;\nimport io.github.muntashirakon.AppManager.utils.UIUtils;\nimport io.github.muntashirakon.dialog.ScrollableDialogBuilder;\n\npublic class RSACryptoSelectionDialogFragment extends DialogFragment {\n    public static final String TAG = RSACryptoSelectionDialogFragment.class.getSimpleName();\n\n    private static final String EXTRA_ALIAS = \"alias\";\n\n    @NonNull\n    public static RSACryptoSelectionDialogFragment getInstance(@NonNull String alias) {\n        RSACryptoSelectionDialogFragment fragment = new RSACryptoSelectionDialogFragment();\n        Bundle args = new Bundle();\n        args.putString(EXTRA_ALIAS, alias);\n        fragment.setArguments(args);\n        return fragment;\n    }\n\n    public interface OnKeyPairUpdatedListener {\n        @UiThread\n        void keyPairUpdated(@Nullable KeyPair keyPair, @Nullable byte[] certificateBytes);\n    }\n\n    @Nullable\n    ScrollableDialogBuilder mBuilder;\n    @Nullable\n    private OnKeyPairUpdatedListener mListener;\n    private String mTargetAlias;\n    @Nullable\n    private RSACryptoSelectionViewModel mModel;\n\n    public void setOnKeyPairUpdatedListener(OnKeyPairUpdatedListener listener) {\n        mListener = listener;\n    }\n\n    @Override\n    public void onCreate(@Nullable Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        mModel = new ViewModelProvider(this).get(RSACryptoSelectionViewModel.class);\n        mModel.observeStatus().observe(this, status -> {\n            if (status.second /* long toast */) {\n                UIUtils.displayLongToast(status.first);\n            } else {\n                UIUtils.displayShortToast(status.first);\n            }\n        });\n        mModel.observeKeyUpdated().observe(this, updatedKeyPair -> {\n            if (mListener == null) return;\n            mListener.keyPairUpdated(updatedKeyPair.first, updatedKeyPair.second);\n        });\n        mModel.observeSigningInfo().observe(this, keyPair -> {\n            if (mBuilder != null) mBuilder.setMessage(getSigningInfo(keyPair));\n        });\n    }\n\n    @NonNull\n    @Override\n    public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {\n        mTargetAlias = requireArguments().getString(EXTRA_ALIAS);\n        mBuilder = new ScrollableDialogBuilder(requireActivity())\n                .setTitle(R.string.rsa)\n                .setNegativeButton(R.string.pref_import, null)\n                .setNeutralButton(R.string.generate_key, null)\n                .setPositiveButton(R.string.ok, null);\n        Objects.requireNonNull(mModel).loadSigningInfo(mTargetAlias);\n        AlertDialog dialog = Objects.requireNonNull(mBuilder).create();\n        dialog.setOnShowListener(dialog3 -> {\n            AlertDialog dialog1 = (AlertDialog) dialog3;\n            Button importButton = dialog1.getButton(AlertDialog.BUTTON_NEGATIVE);\n            Button generateButton = dialog1.getButton(AlertDialog.BUTTON_NEUTRAL);\n            importButton.setOnClickListener(v -> {\n                KeyPairImporterDialogFragment fragment = new KeyPairImporterDialogFragment();\n                Bundle args = new Bundle();\n                args.putString(KeyPairImporterDialogFragment.EXTRA_ALIAS, mTargetAlias);\n                fragment.setArguments(args);\n                fragment.setOnKeySelectedListener(keyPair -> mModel.addKeyPair(mTargetAlias, keyPair));\n                fragment.show(getParentFragmentManager(), KeyPairImporterDialogFragment.TAG);\n            });\n            generateButton.setOnClickListener(v -> {\n                KeyPairGeneratorDialogFragment fragment = new KeyPairGeneratorDialogFragment();\n                Bundle args = new Bundle();\n                args.putString(KeyPairGeneratorDialogFragment.EXTRA_KEY_TYPE, CryptoUtils.MODE_RSA);\n                fragment.setArguments(args);\n                fragment.setOnGenerateListener(keyPair -> mModel.addKeyPair(mTargetAlias, keyPair));\n                fragment.show(getParentFragmentManager(), KeyPairGeneratorDialogFragment.TAG);\n            });\n        });\n        return dialog;\n    }\n\n    private CharSequence getSigningInfo(@Nullable KeyPair keyPair) {\n        if (keyPair != null) {\n            try {\n                return PackageUtils.getSigningCertificateInfo(requireActivity(), (X509Certificate) keyPair.getCertificate());\n            } catch (CertificateEncodingException e) {\n                return getString(R.string.failed_to_load_key);\n            }\n        }\n        return getString(R.string.key_not_set);\n    }\n\n    public static class RSACryptoSelectionViewModel extends AndroidViewModel {\n        // StringRes, isLongToast\n        private final MutableLiveData<Pair<Integer, Boolean>> status = new MutableLiveData<>();\n        private final MutableLiveData<Pair<KeyPair, byte[]>> keyUpdated = new MutableLiveData<>();\n        private final MutableLiveData<KeyPair> signingInfo = new MutableLiveData<>();\n\n        public RSACryptoSelectionViewModel(@NonNull Application application) {\n            super(application);\n        }\n\n        public LiveData<Pair<Integer, Boolean>> observeStatus() {\n            return status;\n        }\n\n        public LiveData<Pair<KeyPair, byte[]>> observeKeyUpdated() {\n            return keyUpdated;\n        }\n\n        public LiveData<KeyPair> observeSigningInfo() {\n            return signingInfo;\n        }\n\n        @AnyThread\n        public void loadSigningInfo(String targetAlias) {\n            ThreadUtils.postOnBackgroundThread(() -> signingInfo.postValue(getKeyPair(targetAlias)));\n        }\n\n        @AnyThread\n        private void addKeyPair(String targetAlias, @Nullable KeyPair keyPair) {\n            ThreadUtils.postOnBackgroundThread(() -> {\n                try {\n                    if (keyPair == null) {\n                        throw new Exception(\"Keypair can't be null.\");\n                    }\n                    KeyStoreManager keyStoreManager = KeyStoreManager.getInstance();\n                    keyStoreManager.addKeyPair(targetAlias, keyPair, true);\n                    status.postValue(new Pair<>(R.string.done, false));\n                    keyPairUpdated(targetAlias);\n                    signingInfo.postValue(getKeyPair(targetAlias));\n                } catch (Exception e) {\n                    Log.e(TAG, e);\n                    status.postValue(new Pair<>(R.string.failed_to_save_key, true));\n                }\n            });\n        }\n\n        @WorkerThread\n        @Nullable\n        private KeyPair getKeyPair(String targetAlias) {\n            try {\n                KeyStoreManager keyStoreManager = KeyStoreManager.getInstance();\n                if (keyStoreManager.containsKey(targetAlias)) {\n                    return keyStoreManager.getKeyPair(targetAlias);\n                }\n            } catch (Exception e) {\n                Log.e(TAG, e);\n            }\n            return null;\n        }\n\n        @WorkerThread\n        private void keyPairUpdated(String targetAlias) {\n            try {\n                KeyPair keyPair = getKeyPair(targetAlias);\n                if (keyPair != null) {\n                    byte[] bytes = keyPair.getCertificate().getEncoded();\n                    keyUpdated.postValue(new Pair<>(keyPair, bytes));\n                    return;\n                }\n            } catch (Exception e) {\n                Log.e(TAG, e);\n            }\n            keyUpdated.postValue(new Pair<>(null, null));\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/sharedpref/EditPrefItemFragment.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.sharedpref;\n\nimport android.app.Dialog;\nimport android.os.Bundle;\nimport android.os.Parcel;\nimport android.os.Parcelable;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.ArrayAdapter;\nimport android.widget.TextView;\n\nimport androidx.annotation.IntDef;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.core.os.BundleCompat;\nimport androidx.fragment.app.DialogFragment;\nimport androidx.fragment.app.FragmentActivity;\n\nimport com.google.android.material.dialog.MaterialAlertDialogBuilder;\nimport com.google.android.material.materialswitch.MaterialSwitch;\nimport com.google.android.material.textfield.TextInputEditText;\n\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.util.Set;\n\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.utils.UIUtils;\nimport io.github.muntashirakon.adapters.SelectedArrayAdapter;\nimport io.github.muntashirakon.widget.MaterialSpinner;\n\npublic class EditPrefItemFragment extends DialogFragment {\n    public static final String TAG = EditPrefItemFragment.class.getSimpleName();\n    public static final String ARG_PREF_ITEM = \"ARG_PREF_ITEM\";\n    public static final String ARG_MODE = \"ARG_MODE\";\n\n    @IntDef(value = {\n            MODE_EDIT,\n            MODE_CREATE,\n            MODE_DELETE\n    })\n    @Retention(RetentionPolicy.SOURCE)\n    public @interface Mode {\n    }\n\n    public static final int MODE_EDIT = 1;  // Key name is disabled\n    public static final int MODE_CREATE = 2;  // Key name is not disabled\n    public static final int MODE_DELETE = 3;\n\n    @IntDef(value = {\n            TYPE_BOOLEAN,\n            TYPE_FLOAT,\n            TYPE_INTEGER,\n            TYPE_LONG,\n            TYPE_STRING,\n            TYPE_SET\n    })\n    @Retention(RetentionPolicy.SOURCE)\n    public @interface Type {\n    }\n\n    private static final int TYPE_BOOLEAN = 0;\n    private static final int TYPE_FLOAT = 1;\n    private static final int TYPE_INTEGER = 2;\n    private static final int TYPE_LONG = 3;\n    private static final int TYPE_STRING = 4;\n    private static final int TYPE_SET = 5;\n\n    private InterfaceCommunicator mInterfaceCommunicator;\n\n    public interface InterfaceCommunicator {\n        void sendInfo(@Mode int mode, PrefItem prefItem);\n    }\n\n    public static class PrefItem implements Parcelable {\n        public String keyName;\n        public Object keyValue;\n\n        public PrefItem() {\n        }\n\n        protected PrefItem(@NonNull Parcel in) {\n            keyName = in.readString();\n        }\n\n        @Override\n        public void writeToParcel(@NonNull Parcel dest, int flags) {\n            dest.writeString(keyName);\n        }\n\n        @Override\n        public int describeContents() {\n            return 0;\n        }\n\n        public static final Creator<PrefItem> CREATOR = new Creator<PrefItem>() {\n            @Override\n            public PrefItem createFromParcel(Parcel in) {\n                return new PrefItem(in);\n            }\n\n            @Override\n            public PrefItem[] newArray(int size) {\n                return new PrefItem[size];\n            }\n        };\n    }\n\n    private final ViewGroup[] mLayoutTypes = new ViewGroup[6];\n    private final TextView[] mValues = new TextView[6];\n    @Type\n    private int mCurrentType;\n\n    @NonNull\n    @Override\n    public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {\n        FragmentActivity activity = requireActivity();\n        Bundle args = requireArguments();\n        PrefItem prefItem = BundleCompat.getParcelable(args, ARG_PREF_ITEM, PrefItem.class);\n        @Mode int mode = args.getInt(ARG_MODE);\n        View view = View.inflate(activity, R.layout.dialog_edit_pref_item, null);\n        MaterialSpinner spinner = view.findViewById(R.id.type_selector_spinner);\n        ArrayAdapter<CharSequence> spinnerAdapter = SelectedArrayAdapter.createFromResource(activity,\n                R.array.shared_pref_types, io.github.muntashirakon.ui.R.layout.auto_complete_dropdown_item);\n        spinner.setAdapter(spinnerAdapter);\n        spinner.setOnItemClickListener((parent, view1, position, id) -> {\n            for (ViewGroup layout : mLayoutTypes) layout.setVisibility(View.GONE);\n            mLayoutTypes[position].setVisibility(View.VISIBLE);\n            mCurrentType = position;\n        });\n        // Set layouts\n        mLayoutTypes[TYPE_BOOLEAN] = view.findViewById(R.id.layout_bool);\n        mLayoutTypes[TYPE_FLOAT] = view.findViewById(R.id.layout_float);\n        mLayoutTypes[TYPE_INTEGER] = view.findViewById(R.id.layout_int);\n        mLayoutTypes[TYPE_LONG] = view.findViewById(R.id.layout_long);\n        mLayoutTypes[TYPE_STRING] = view.findViewById(R.id.layout_string);\n        mLayoutTypes[TYPE_SET] = view.findViewById(R.id.layout_string);\n        // Set views\n        mValues[TYPE_BOOLEAN] = view.findViewById(R.id.input_bool);\n        mValues[TYPE_FLOAT] = view.findViewById(R.id.input_float);\n        mValues[TYPE_INTEGER] = view.findViewById(R.id.input_int);\n        mValues[TYPE_LONG] = view.findViewById(R.id.input_long);\n        mValues[TYPE_STRING] = view.findViewById(R.id.input_string);\n        mValues[TYPE_SET] = view.findViewById(R.id.input_string);\n        // Key name\n        TextInputEditText editKeyName = view.findViewById(R.id.key_name);\n        if (prefItem != null) {\n            String keyName = prefItem.keyName;\n            Object keyValue = prefItem.keyValue;\n            editKeyName.setText(keyName);\n            if (mode == MODE_EDIT) {\n                editKeyName.setKeyListener(null);\n            }\n            // Key value\n            if (keyValue instanceof Boolean) {\n                mCurrentType = TYPE_BOOLEAN;\n                mLayoutTypes[TYPE_BOOLEAN].setVisibility(View.VISIBLE);\n                ((MaterialSwitch) mValues[TYPE_BOOLEAN]).setChecked((Boolean) keyValue);\n                spinner.setSelection(TYPE_BOOLEAN);\n            } else if (keyValue instanceof Float) {\n                mCurrentType = TYPE_FLOAT;\n                mLayoutTypes[TYPE_FLOAT].setVisibility(View.VISIBLE);\n                mValues[TYPE_FLOAT].setText(keyValue.toString());\n                spinner.setSelection(TYPE_FLOAT);\n            } else if (keyValue instanceof Integer) {\n                mCurrentType = TYPE_INTEGER;\n                mLayoutTypes[TYPE_INTEGER].setVisibility(View.VISIBLE);\n                mValues[TYPE_INTEGER].setText(keyValue.toString());\n                spinner.setSelection(TYPE_INTEGER);\n            } else if (keyValue instanceof Long) {\n                mCurrentType = TYPE_LONG;\n                mLayoutTypes[TYPE_LONG].setVisibility(View.VISIBLE);\n                mValues[TYPE_LONG].setText(keyValue.toString());\n                spinner.setSelection(TYPE_LONG);\n            } else if (keyValue instanceof String) {\n                mCurrentType = TYPE_STRING;\n                mLayoutTypes[TYPE_STRING].setVisibility(View.VISIBLE);\n                mValues[TYPE_STRING].setText((String) keyValue);\n                spinner.setSelection(TYPE_STRING);\n            } else if (keyValue instanceof Set) {\n                mCurrentType = TYPE_SET;\n                mLayoutTypes[TYPE_SET].setVisibility(View.VISIBLE);\n                //noinspection unchecked\n                mValues[TYPE_SET].setText(SharedPrefsUtil.flattenToString((Set<String>) keyValue));\n                spinner.setSelection(TYPE_SET);\n            }\n        }\n        mInterfaceCommunicator = (InterfaceCommunicator) activity;\n        MaterialAlertDialogBuilder builder = new MaterialAlertDialogBuilder(activity);\n        builder.setView(view)\n                .setPositiveButton(mode == MODE_CREATE ? R.string.add : R.string.done, (dialog, which) -> {\n                    PrefItem newPrefItem;\n                    if (prefItem != null) newPrefItem = prefItem;\n                    else {\n                        newPrefItem = new PrefItem();\n                        newPrefItem.keyName = editKeyName.getText().toString();\n                    }\n                    if (newPrefItem.keyName == null) {\n                        UIUtils.displayLongToast(R.string.key_name_cannot_be_null);\n                        return;\n                    }\n\n                    try {\n                        switch (mCurrentType) {\n                            case TYPE_BOOLEAN:\n                                newPrefItem.keyValue = ((MaterialSwitch) mValues[mCurrentType]).isChecked();\n                                break;\n                            case TYPE_FLOAT:\n                                newPrefItem.keyValue = Float.valueOf(mValues[mCurrentType].getText().toString());\n                                break;\n                            case TYPE_INTEGER:\n                                newPrefItem.keyValue = Integer.valueOf(mValues[mCurrentType].getText().toString());\n                                break;\n                            case TYPE_LONG:\n                                newPrefItem.keyValue = Long.valueOf(mValues[mCurrentType].getText().toString());\n                                break;\n                            case TYPE_STRING:\n                                newPrefItem.keyValue = mValues[mCurrentType].getText().toString();\n                                break;\n                            case TYPE_SET:\n                                newPrefItem.keyValue = SharedPrefsUtil.unflattenToSet(mValues[mCurrentType].getText().toString());\n                                break;\n                        }\n                    } catch (Exception e) {\n                        e.printStackTrace();\n                        UIUtils.displayLongToast(R.string.error_evaluating_input);\n                        return;\n                    }\n                    mInterfaceCommunicator.sendInfo(mode, newPrefItem);\n                })\n                .setNegativeButton(R.string.cancel, (dialog, which) -> {\n                    if (getDialog() != null) getDialog().cancel();\n                });\n        if (mode == MODE_EDIT) builder.setNeutralButton(R.string.delete,\n                (dialog, which) -> mInterfaceCommunicator.sendInfo(MODE_DELETE, prefItem));\n        return builder.create();\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/sharedpref/SharedPrefsActivity.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.sharedpref;\n\nimport android.content.Intent;\nimport android.net.Uri;\nimport android.os.Bundle;\nimport android.text.TextUtils;\nimport android.view.LayoutInflater;\nimport android.view.Menu;\nimport android.view.MenuItem;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.Filter;\nimport android.widget.Filterable;\nimport android.widget.TextView;\n\nimport androidx.activity.OnBackPressedCallback;\nimport androidx.annotation.NonNull;\nimport androidx.appcompat.app.ActionBar;\nimport androidx.appcompat.widget.SearchView;\nimport androidx.fragment.app.DialogFragment;\nimport androidx.lifecycle.ViewModelProvider;\n\nimport com.google.android.material.dialog.MaterialAlertDialogBuilder;\nimport com.google.android.material.floatingactionbutton.FloatingActionButton;\nimport com.google.android.material.progressindicator.LinearProgressIndicator;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Map;\n\nimport io.github.muntashirakon.AppManager.BaseActivity;\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.intercept.IntentCompat;\nimport io.github.muntashirakon.AppManager.utils.UIUtils;\nimport io.github.muntashirakon.AppManager.utils.appearance.ColorCodes;\nimport io.github.muntashirakon.io.Paths;\nimport io.github.muntashirakon.util.AdapterUtils;\nimport io.github.muntashirakon.util.UiUtils;\nimport io.github.muntashirakon.widget.RecyclerView;\n\npublic class SharedPrefsActivity extends BaseActivity implements\n        SearchView.OnQueryTextListener, EditPrefItemFragment.InterfaceCommunicator {\n    public static final String EXTRA_PREF_LOCATION = \"loc\";\n    public static final String EXTRA_PREF_LABEL = \"label\";  // Optional\n\n    public static final int REASONABLE_STR_SIZE = 200;\n\n    private SharedPrefsListingAdapter mAdapter;\n    private LinearProgressIndicator mProgressIndicator;\n    private SharedPrefsViewModel mViewModel;\n    private boolean mWriteAndExit = false;\n    private final OnBackPressedCallback mOnBackPressedCallback = new OnBackPressedCallback(false) {\n        @Override\n        public void handleOnBackPressed() {\n            if (mViewModel.isModified()) {\n                new MaterialAlertDialogBuilder(SharedPrefsActivity.this)\n                        .setTitle(R.string.exit_confirmation)\n                        .setMessage(R.string.file_modified_are_you_sure)\n                        .setCancelable(false)\n                        .setPositiveButton(R.string.no, null)\n                        .setNegativeButton(R.string.yes, (dialog, which) -> {\n                            setEnabled(false);\n                            getOnBackPressedDispatcher().onBackPressed();\n                        })\n                        .setNeutralButton(R.string.save_and_exit, (dialog, which) -> {\n                            mWriteAndExit = true;\n                            mViewModel.writeSharedPrefs();\n                            setEnabled(false);\n                        })\n                        .show();\n                return;\n            }\n            setEnabled(false);\n            getOnBackPressedDispatcher().onBackPressed();\n        }\n    };\n\n    @Override\n    protected void onAuthenticated(Bundle savedInstanceState) {\n        setContentView(R.layout.activity_shared_prefs);\n        setSupportActionBar(findViewById(R.id.toolbar));\n        getOnBackPressedDispatcher().addCallback(this, mOnBackPressedCallback);\n        Uri sharedPrefUri = IntentCompat.getParcelableExtra(getIntent(), EXTRA_PREF_LOCATION, Uri.class);\n        String appLabel = getIntent().getStringExtra(EXTRA_PREF_LABEL);\n        if (sharedPrefUri == null) {\n            finish();\n            return;\n        }\n        mViewModel = new ViewModelProvider(this).get(SharedPrefsViewModel.class);\n        mViewModel.setSharedPrefsFile(Paths.get(sharedPrefUri));\n        ActionBar actionBar = getSupportActionBar();\n        if (actionBar != null) {\n            actionBar.setTitle(appLabel);\n            actionBar.setSubtitle(mViewModel.getSharedPrefFilename());\n            actionBar.setDisplayShowCustomEnabled(true);\n            UIUtils.setupSearchView(actionBar, this);\n        }\n        mProgressIndicator = findViewById(R.id.progress_linear);\n        mProgressIndicator.setVisibilityAfterHide(View.GONE);\n        mProgressIndicator.show();\n        RecyclerView recyclerView = findViewById(android.R.id.list);\n        recyclerView.setLayoutManager(UIUtils.getGridLayoutAt450Dp(this));\n        recyclerView.setEmptyView(findViewById(android.R.id.empty));\n        mAdapter = new SharedPrefsListingAdapter(this);\n        recyclerView.setAdapter(mAdapter);\n        FloatingActionButton fab = findViewById(R.id.floatingActionButton);\n        UiUtils.applyWindowInsetsAsMargin(fab);\n        fab.setOnClickListener(v -> {\n            DialogFragment dialogFragment = new EditPrefItemFragment();\n            Bundle args = new Bundle();\n            args.putInt(EditPrefItemFragment.ARG_MODE, EditPrefItemFragment.MODE_CREATE);\n            dialogFragment.setArguments(args);\n            dialogFragment.show(getSupportFragmentManager(), EditPrefItemFragment.TAG);\n        });\n        mViewModel.getSharedPrefsMapLiveData().observe(this, sharedPrefsMap -> {\n            mProgressIndicator.hide();\n            mAdapter.setDefaultList(sharedPrefsMap);\n        });\n        mViewModel.getSharedPrefsSavedLiveData().observe(this, saved -> {\n            if (saved) {\n                UIUtils.displayShortToast(R.string.saved_successfully);\n                if (mWriteAndExit) {\n                    getOnBackPressedDispatcher().onBackPressed();\n                    mWriteAndExit = false;\n                }\n            } else {\n                UIUtils.displayShortToast(R.string.saving_failed);\n            }\n        });\n        mViewModel.getSharedPrefsDeletedLiveData().observe(this, deleted -> {\n            if (deleted) {\n                UIUtils.displayShortToast(R.string.deleted_successfully);\n                finish();\n            } else {\n                UIUtils.displayShortToast(R.string.deletion_failed);\n            }\n        });\n        mViewModel.getSharedPrefsModifiedLiveData().observe(this, modified -> {\n            mOnBackPressedCallback.setEnabled(modified);\n            if (modified) {\n                if (actionBar != null) {\n                    actionBar.setTitle(\"* \" + mViewModel.getSharedPrefFilename());\n                }\n            } else {\n                if (actionBar != null) {\n                    actionBar.setTitle(mViewModel.getSharedPrefFilename());\n                }\n            }\n        });\n        mViewModel.loadSharedPrefs();\n    }\n\n    @Override\n    public boolean onCreateOptionsMenu(Menu menu) {\n        getMenuInflater().inflate(R.menu.activity_shared_prefs_actions, menu);\n        return super.onCreateOptionsMenu(menu);\n    }\n\n    @Override\n    public void sendInfo(@EditPrefItemFragment.Mode int mode, EditPrefItemFragment.PrefItem prefItem) {\n        if (prefItem != null) {\n            switch (mode) {\n                case EditPrefItemFragment.MODE_CREATE:\n                case EditPrefItemFragment.MODE_EDIT:\n                    mViewModel.add(prefItem.keyName, prefItem.keyValue);\n                    break;\n                case EditPrefItemFragment.MODE_DELETE:\n                    mViewModel.remove(prefItem.keyName);\n                    break;\n            }\n        }\n    }\n\n    @Override\n    public boolean onPrepareOptionsMenu(Menu menu) {\n        MenuItem newWindow = menu.findItem(R.id.action_separate_window);\n        if (newWindow != null) {\n            newWindow.setEnabled(!mViewModel.isModified());\n        }\n        return super.onPrepareOptionsMenu(menu);\n    }\n\n    @Override\n    public boolean onOptionsItemSelected(@NonNull MenuItem item) {\n        int id = item.getItemId();\n        if (id == android.R.id.home) {\n            getOnBackPressedDispatcher().onBackPressed();\n        } else if (id == R.id.action_discard) {\n            finish();\n        } else if (id == R.id.action_delete) {\n            mViewModel.deleteSharedPrefFile();\n        } else if (id == R.id.action_save) {\n            mViewModel.writeSharedPrefs();\n        } else if (id == R.id.action_separate_window) {\n            if (!mViewModel.isModified()) {\n                Intent intent = new Intent(getIntent());\n                intent.setClass(this, SharedPrefsActivity.class);\n                intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_MULTIPLE_TASK);\n                startActivity(intent);\n                finish();\n            }\n        } else return super.onOptionsItemSelected(item);\n        return true;\n    }\n\n    @Override\n    protected void onResume() {\n        super.onResume();\n        if (mAdapter != null && !TextUtils.isEmpty(mAdapter.mConstraint)) {\n            mAdapter.getFilter().filter(mAdapter.mConstraint);\n        }\n    }\n\n    @Override\n    public boolean onQueryTextSubmit(String query) {\n        return false;\n    }\n\n    @Override\n    public boolean onQueryTextChange(String newText) {\n        if (mAdapter != null) mAdapter.getFilter().filter(newText.toLowerCase(Locale.ROOT));\n        return true;\n    }\n\n    private void displayEditor(@NonNull String prefName) {\n        EditPrefItemFragment.PrefItem prefItem = new EditPrefItemFragment.PrefItem();\n        prefItem.keyName = prefName;\n        prefItem.keyValue = mViewModel.getValue(prefName);\n        EditPrefItemFragment dialogFragment = new EditPrefItemFragment();\n        Bundle args = new Bundle();\n        args.putParcelable(EditPrefItemFragment.ARG_PREF_ITEM, prefItem);\n        args.putInt(EditPrefItemFragment.ARG_MODE, EditPrefItemFragment.MODE_EDIT);\n        dialogFragment.setArguments(args);\n        dialogFragment.show(getSupportFragmentManager(), EditPrefItemFragment.TAG);\n    }\n\n    static class SharedPrefsListingAdapter extends RecyclerView.Adapter<SharedPrefsListingAdapter.ViewHolder> implements Filterable {\n        private final SharedPrefsActivity mActivity;\n        private Filter mFilter;\n        private String mConstraint;\n        private String[] mDefaultList;\n        private String[] mAdapterList;\n        private Map<String, Object> mAdapterMap;\n\n        private final int mQueryStringHighlightColor;\n\n        static class ViewHolder extends RecyclerView.ViewHolder {\n            TextView itemName;\n            TextView itemValue;\n\n            public ViewHolder(@NonNull View itemView) {\n                super(itemView);\n                itemName = itemView.findViewById(android.R.id.title);\n                itemValue = itemView.findViewById(android.R.id.summary);\n                itemView.findViewById(R.id.icon_frame).setVisibility(View.GONE);\n            }\n        }\n\n        SharedPrefsListingAdapter(@NonNull SharedPrefsActivity activity) {\n            mActivity = activity;\n            mQueryStringHighlightColor = ColorCodes.getQueryStringHighlightColor(activity);\n        }\n\n        void setDefaultList(@NonNull Map<String, Object> list) {\n            mDefaultList = list.keySet().toArray(new String[0]);\n            mAdapterMap = list;\n            if (!TextUtils.isEmpty(mConstraint)) {\n                getFilter().filter(mConstraint);\n            } else {\n                int previousCount = mAdapterList != null ? mAdapterList.length : 0;\n                mAdapterList = mDefaultList;\n                AdapterUtils.notifyDataSetChanged(this, previousCount, mAdapterList.length);\n            }\n        }\n\n        @Override\n        public int getItemCount() {\n            return mAdapterList == null ? 0 : mAdapterList.length;\n        }\n\n        @NonNull\n        @Override\n        public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {\n            View v = LayoutInflater.from(parent.getContext()).inflate(io.github.muntashirakon.ui.R.layout.m3_preference, parent, false);\n            return new ViewHolder(v);\n        }\n\n        @Override\n        public void onBindViewHolder(@NonNull ViewHolder holder, int position) {\n            String prefName = mAdapterList[position];\n            if (mConstraint != null && prefName.toLowerCase(Locale.ROOT).contains(mConstraint)) {\n                // Highlight searched query\n                holder.itemName.setText(UIUtils.getHighlightedText(prefName, mConstraint, mQueryStringHighlightColor));\n            } else {\n                holder.itemName.setText(prefName);\n            }\n            Object value = mAdapterMap.get(prefName);\n            String strValue = (value != null) ? value.toString() : \"\";\n            holder.itemValue.setText(strValue.length() > REASONABLE_STR_SIZE ?\n                    strValue.substring(0, REASONABLE_STR_SIZE) : strValue);\n            holder.itemView.setOnClickListener(v -> mActivity.displayEditor(prefName));\n        }\n\n        @Override\n        public long getItemId(int position) {\n            return position;\n        }\n\n        @Override\n        public Filter getFilter() {\n            if (mFilter == null)\n                mFilter = new Filter() {\n                    @Override\n                    protected FilterResults performFiltering(CharSequence charSequence) {\n                        String constraint = charSequence.toString().toLowerCase(Locale.ROOT);\n                        mConstraint = constraint;\n                        FilterResults filterResults = new FilterResults();\n                        if (constraint.isEmpty()) {\n                            filterResults.count = 0;\n                            filterResults.values = null;\n                            return filterResults;\n                        }\n\n                        List<String> list = new ArrayList<>(mDefaultList.length);\n                        for (String item : mDefaultList) {\n                            if (item.toLowerCase(Locale.ROOT).contains(constraint))\n                                list.add(item);\n                        }\n\n                        filterResults.count = list.size();\n                        filterResults.values = list.toArray(new String[0]);\n                        return filterResults;\n                    }\n\n                    @Override\n                    protected void publishResults(CharSequence charSequence, FilterResults filterResults) {\n                        int previousCount = mAdapterList != null ? mAdapterList.length : 0;\n                        if (filterResults.values == null) {\n                            mAdapterList = mDefaultList;\n                        } else {\n                            mAdapterList = (String[]) filterResults.values;\n                        }\n                        AdapterUtils.notifyDataSetChanged(SharedPrefsListingAdapter.this, previousCount, mAdapterList.length);\n                    }\n                };\n            return mFilter;\n        }\n    }\n}"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/sharedpref/SharedPrefsUtil.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.sharedpref;\n\nimport android.text.TextUtils;\nimport android.util.Xml;\n\nimport androidx.annotation.NonNull;\n\nimport org.xmlpull.v1.XmlPullParser;\nimport org.xmlpull.v1.XmlPullParserException;\nimport org.xmlpull.v1.XmlSerializer;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.io.StringWriter;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.Set;\n\n\npublic final class SharedPrefsUtil {\n    public static final String TAG_ROOT = \"map\";  // <map></map>\n    public static final String TAG_BOOLEAN = \"boolean\";  // <boolean name=\"bool\" value=\"true\" />\n    public static final String TAG_FLOAT = \"float\";  // <float name=\"float\" value=\"12.3\" />\n    public static final String TAG_INTEGER = \"int\";  // <int name=\"integer\" value=\"123\" />\n    public static final String TAG_LONG = \"long\";  // <long name=\"long\" value=\"123456789\" />\n    public static final String TAG_STRING = \"string\";  // <string name=\"string\"></string>\n    public static final String TAG_SET = \"set\";  // <set name=\"string_set\"><string></string></set>\n\n    @NonNull\n    public static HashMap<String, Object> readSharedPref(@NonNull InputStream is)\n            throws XmlPullParserException, IOException {\n        HashMap<String, Object> prefs = new HashMap<>();\n        XmlPullParser parser = Xml.newPullParser();\n        parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false);\n        parser.setInput(is, null);\n        parser.nextTag();\n        parser.require(XmlPullParser.START_TAG, null, TAG_ROOT);\n        int event = parser.next();\n        while (event != XmlPullParser.END_DOCUMENT) {\n            if (event == XmlPullParser.START_TAG) {\n                String tagName = parser.getName();\n                String attrName = parser.getAttributeValue(null, \"name\");\n                if (attrName == null) attrName = \"\";\n                String attrValue = parser.getAttributeValue(null, \"value\");\n                switch (tagName) {\n                    case TAG_BOOLEAN:\n                        prefs.put(attrName, Objects.equals(attrValue, \"true\"));\n                        break;\n                    case TAG_FLOAT:\n                        if (attrValue != null) {\n                            prefs.put(attrName, Float.valueOf(attrValue));\n                        }\n                        break;\n                    case TAG_INTEGER:\n                        if (attrValue != null) {\n                            prefs.put(attrName, Integer.valueOf(attrValue));\n                        }\n                        break;\n                    case TAG_LONG:\n                        if (attrValue != null) {\n                            prefs.put(attrName, Long.valueOf(attrValue));\n                        }\n                        break;\n                    case TAG_STRING:\n                        prefs.put(attrName, parser.nextText());\n                        break;\n                    case TAG_SET:\n                        Set<String> stringSet = new HashSet<>();\n                        prefs.put(attrName, stringSet);\n                        // Grab all strings\n                        event = parser.next();\n                        tagName = parser.getName();\n                        while (event != XmlPullParser.END_TAG || !Objects.equals(tagName, TAG_SET)) {\n                            if (event == XmlPullParser.START_TAG) {\n                                if (!Objects.equals(tagName, TAG_STRING)) {\n                                    throw new XmlPullParserException(\"Invalid tag inside <set>: \" + tagName);\n                                }\n                                stringSet.add(parser.nextText());\n                            }\n                            event = parser.next();\n                            tagName = parser.getName();\n                        }\n                        break;\n                    default:\n                        throw new XmlPullParserException(\"Invalid tag: \" + tagName);\n                }\n            }\n            event = parser.next();\n        }\n        return prefs;\n    }\n\n    public static void writeSharedPref(@NonNull OutputStream os, @NonNull Map<String, Object> hashMap)\n            throws IOException {\n        XmlSerializer xmlSerializer = Xml.newSerializer();\n        StringWriter stringWriter = new StringWriter();\n        xmlSerializer.setOutput(stringWriter);\n        xmlSerializer.startDocument(\"UTF-8\", true);\n        xmlSerializer.startTag(\"\", TAG_ROOT);\n        // Add values\n        for (String name : hashMap.keySet()) {\n            Object value = hashMap.get(name);\n            if (value instanceof Boolean) {\n                xmlSerializer.startTag(\"\", TAG_BOOLEAN);\n                xmlSerializer.attribute(\"\", \"name\", name);\n                xmlSerializer.attribute(\"\", \"value\", value.toString());\n                xmlSerializer.endTag(\"\", TAG_BOOLEAN);\n            } else if (value instanceof Float) {\n                xmlSerializer.startTag(\"\", TAG_FLOAT);\n                xmlSerializer.attribute(\"\", \"name\", name);\n                xmlSerializer.attribute(\"\", \"value\", value.toString());\n                xmlSerializer.endTag(\"\", TAG_FLOAT);\n            } else if (value instanceof Integer) {\n                xmlSerializer.startTag(\"\", TAG_INTEGER);\n                xmlSerializer.attribute(\"\", \"name\", name);\n                xmlSerializer.attribute(\"\", \"value\", value.toString());\n                xmlSerializer.endTag(\"\", TAG_INTEGER);\n            } else if (value instanceof Long) {\n                xmlSerializer.startTag(\"\", TAG_LONG);\n                xmlSerializer.attribute(\"\", \"name\", name);\n                xmlSerializer.attribute(\"\", \"value\", value.toString());\n                xmlSerializer.endTag(\"\", TAG_LONG);\n            } else if (value instanceof String) {\n                xmlSerializer.startTag(\"\", TAG_STRING);\n                xmlSerializer.attribute(\"\", \"name\", name);\n                xmlSerializer.text(value.toString());\n                xmlSerializer.endTag(\"\", TAG_STRING);\n            } else if (value instanceof Set) {\n                xmlSerializer.startTag(\"\", TAG_SET);\n                xmlSerializer.attribute(\"\", \"name\", name);\n                //noinspection unchecked\n                for (String v : (Set<String>) value) {\n                    xmlSerializer.startTag(\"\", TAG_STRING);\n                    xmlSerializer.text(v);\n                    xmlSerializer.endTag(\"\", TAG_STRING);\n                }\n                xmlSerializer.endTag(\"\", TAG_SET);\n            } else {\n                throw new IOException(\"Invalid value for key: \" + name + \" (value: \" + value + \")\");\n            }\n        }\n        xmlSerializer.endTag(\"\", TAG_ROOT);\n        xmlSerializer.endDocument();\n        xmlSerializer.flush();\n        os.write(stringWriter.toString().getBytes());\n    }\n\n    @NonNull\n    public static String flattenToString(@NonNull Set<String> stringSet) {\n        List<String> stringList = new ArrayList<>(stringSet.size());\n        for (String string : stringSet) {\n            stringList.add(string.replace(\",\", \"\\\\,\"));\n        }\n        return TextUtils.join(\",\", stringList);\n    }\n\n    @NonNull\n    public static Set<String> unflattenToSet(@NonNull String rawValue) {\n        // Split on commas unless they are preceded by an escape.\n        // The escape character must be escaped for the string and\n        // again for the regex, thus four escape characters become one.\n        String[] strings = rawValue.split(\"(?<!\\\\\\\\),\");\n        Set<String> stringSet = new HashSet<>(strings.length);\n        Collections.addAll(stringSet, strings);\n        return stringSet;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/sharedpref/SharedPrefsViewModel.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.sharedpref;\n\nimport android.app.Application;\n\nimport androidx.annotation.AnyThread;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.lifecycle.AndroidViewModel;\nimport androidx.lifecycle.LiveData;\nimport androidx.lifecycle.MutableLiveData;\n\nimport org.xmlpull.v1.XmlPullParserException;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport io.github.muntashirakon.AppManager.utils.MultithreadedExecutor;\nimport io.github.muntashirakon.io.Path;\n\npublic class SharedPrefsViewModel extends AndroidViewModel {\n    private final MultithreadedExecutor mExecutor = MultithreadedExecutor.getNewInstance();\n    private final MutableLiveData<Map<String, Object>> mSharedPrefsMapLiveData = new MutableLiveData<>();\n    private final MutableLiveData<Boolean> mSharedPrefsSavedLiveData = new MutableLiveData<>();\n    private final MutableLiveData<Boolean> mSharedPrefsDeletedLiveData = new MutableLiveData<>();\n    private final MutableLiveData<Boolean> mSharedPrefsModifiedLiveData = new MutableLiveData<>();\n\n    // TODO: 8/2/22 Use AtomicExtendedFile to better handle errors\n    private Path mSharedPrefsFile;\n    private Map<String, Object> mSharedPrefsMap;\n    private boolean mModified;\n\n    public SharedPrefsViewModel(@NonNull Application application) {\n        super(application);\n    }\n\n    @Override\n    protected void onCleared() {\n        mExecutor.shutdownNow();\n        super.onCleared();\n    }\n\n    public void setSharedPrefsFile(@NonNull Path sharedPrefFile) {\n        mSharedPrefsFile = sharedPrefFile;\n    }\n\n    public boolean isModified() {\n        return mModified;\n    }\n\n    @Nullable\n    public String getSharedPrefFilename() {\n        if (mSharedPrefsFile != null) {\n            return mSharedPrefsFile.getName();\n        }\n        return null;\n    }\n\n    @Nullable\n    public Object getValue(@NonNull String key) {\n        return mSharedPrefsMap.get(key);\n    }\n\n    public void remove(@NonNull String key) {\n        mSharedPrefsModifiedLiveData.postValue(mModified = true);\n        mSharedPrefsMap.remove(key);\n        mSharedPrefsMapLiveData.postValue(mSharedPrefsMap);\n    }\n\n    public void add(@NonNull String key, @NonNull Object value) {\n        mSharedPrefsModifiedLiveData.postValue(mModified = true);\n        mSharedPrefsMap.put(key, value);\n        mSharedPrefsMapLiveData.postValue(mSharedPrefsMap);\n    }\n\n    public LiveData<Map<String, Object>> getSharedPrefsMapLiveData() {\n        return mSharedPrefsMapLiveData;\n    }\n\n    public LiveData<Boolean> getSharedPrefsSavedLiveData() {\n        return mSharedPrefsSavedLiveData;\n    }\n\n    public LiveData<Boolean> getSharedPrefsDeletedLiveData() {\n        return mSharedPrefsDeletedLiveData;\n    }\n\n    public LiveData<Boolean> getSharedPrefsModifiedLiveData() {\n        return mSharedPrefsModifiedLiveData;\n    }\n\n    @AnyThread\n    public void deleteSharedPrefFile() {\n        mExecutor.submit(() -> mSharedPrefsDeletedLiveData.postValue(mSharedPrefsFile.delete()));\n    }\n\n    @AnyThread\n    public void writeSharedPrefs() {\n        mExecutor.submit(() -> {\n            try (OutputStream xmlFile = mSharedPrefsFile.openOutputStream()) {\n                SharedPrefsUtil.writeSharedPref(xmlFile, mSharedPrefsMap);\n                // TODO: 9/7/21 Investigate the state of permission (should be unchanged)\n                mSharedPrefsSavedLiveData.postValue(true);\n                mSharedPrefsModifiedLiveData.postValue(mModified = false);\n            } catch (IOException e) {\n                e.printStackTrace();\n                mSharedPrefsSavedLiveData.postValue(false);\n            }\n        });\n    }\n\n    @AnyThread\n    public void loadSharedPrefs() {\n        mExecutor.submit(() -> {\n            try (InputStream rulesStream = mSharedPrefsFile.openInputStream()) {\n                mSharedPrefsModifiedLiveData.postValue(mModified = false);\n                mSharedPrefsMap = SharedPrefsUtil.readSharedPref(rulesStream);\n                mSharedPrefsMapLiveData.postValue(mSharedPrefsMap);\n            } catch (IOException | XmlPullParserException e) {\n                e.printStackTrace();\n                mSharedPrefsMap = new HashMap<>();\n                mSharedPrefsMapLiveData.postValue(mSharedPrefsMap);\n            }\n        });\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/shortcut/CreateShortcutDialogFragment.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.shortcut;\n\nimport android.app.Dialog;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.pm.PackageManager;\nimport android.content.res.Resources;\nimport android.graphics.drawable.Drawable;\nimport android.os.Bundle;\nimport android.text.Editable;\nimport android.text.TextUtils;\nimport android.text.TextWatcher;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.core.content.pm.ShortcutInfoCompat;\nimport androidx.core.content.pm.ShortcutManagerCompat;\nimport androidx.core.graphics.drawable.IconCompat;\nimport androidx.core.os.BundleCompat;\nimport androidx.fragment.app.DialogFragment;\n\nimport com.google.android.material.dialog.MaterialAlertDialogBuilder;\nimport com.google.android.material.imageview.ShapeableImageView;\nimport com.google.android.material.textfield.TextInputEditText;\nimport com.google.android.material.textfield.TextInputLayout;\nimport com.google.android.material.textview.MaterialTextView;\n\nimport java.lang.ref.WeakReference;\nimport java.util.Objects;\nimport java.util.UUID;\n\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.details.IconPickerDialogFragment;\nimport io.github.muntashirakon.AppManager.utils.ResourceUtil;\nimport io.github.muntashirakon.AppManager.utils.UIUtils;\nimport io.github.muntashirakon.lifecycle.SoftInputLifeCycleObserver;\nimport io.github.muntashirakon.view.TextInputLayoutCompat;\n\npublic class CreateShortcutDialogFragment extends DialogFragment {\n    public static final String TAG = CreateShortcutDialogFragment.class.getSimpleName();\n\n    private static final String ARG_SHORTCUT_INFO = \"info\";\n\n    @NonNull\n    public static CreateShortcutDialogFragment getInstance(@NonNull ShortcutInfo shortcutInfo) {\n        CreateShortcutDialogFragment dialog = new CreateShortcutDialogFragment();\n        Bundle args = new Bundle();\n        args.putParcelable(ARG_SHORTCUT_INFO, shortcutInfo);\n        dialog.setArguments(args);\n        return dialog;\n    }\n\n    private boolean mValidName = true;\n    private ShortcutInfo mShortcutInfo;\n    private View mDialogView;\n    private TextInputEditText mShortcutNameField;\n    private TextInputEditText mShortcutIconField;\n    private TextInputLayout mShortcutIconLayout;\n    private ShapeableImageView mShortcutIconPreview;\n    private MaterialTextView mShortcutNamePreview;\n    private PackageManager mPm;\n\n    @NonNull\n    @Override\n    public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {\n        mPm = requireActivity().getPackageManager();\n        mShortcutInfo = Objects.requireNonNull(BundleCompat.getParcelable(requireArguments(), ARG_SHORTCUT_INFO, ShortcutInfo.class));\n        mDialogView = View.inflate(requireActivity(), R.layout.dialog_create_shortcut, null);\n        mShortcutNameField = mDialogView.findViewById(R.id.shortcut_name);\n        mShortcutIconField = mDialogView.findViewById(R.id.insert_icon);\n        mShortcutIconLayout = TextInputLayoutCompat.fromTextInputEditText(mShortcutIconField);\n        mShortcutIconPreview = mDialogView.findViewById(R.id.icon);\n        mShortcutNamePreview = mDialogView.findViewById(R.id.name);\n\n        mShortcutNameField.addTextChangedListener(new TextWatcher() {\n            @Override\n            public void beforeTextChanged(CharSequence s, int start, int count, int after) {\n            }\n\n            @Override\n            public void onTextChanged(CharSequence s, int start, int before, int count) {\n            }\n\n            @Override\n            public void afterTextChanged(Editable s) {\n                if (!TextUtils.isEmpty(s)) {\n                    mValidName = true;\n                    mShortcutInfo.setName(s);\n                    mShortcutNamePreview.setText(s);\n                } else mValidName = false;\n            }\n        });\n        mShortcutIconField.addTextChangedListener(new TextWatcher() {\n            @Override\n            public void beforeTextChanged(CharSequence s, int start, int count, int after) {\n            }\n\n            @Override\n            public void onTextChanged(CharSequence s, int start, int before, int count) {\n            }\n\n            @Override\n            public void afterTextChanged(Editable s) {\n                Drawable drawable = getDrawable(s.toString());\n                if (drawable != null) {\n                    mShortcutInfo.setIcon(UIUtils.getBitmapFromDrawable(drawable));\n                    mShortcutIconPreview.setImageDrawable(drawable);\n                }\n            }\n        });\n        mShortcutIconLayout.setEndIconOnClickListener(v -> {\n            IconPickerDialogFragment dialog = new IconPickerDialogFragment();\n            dialog.attachIconPickerListener(icon -> {\n                mShortcutIconField.setText(icon.name);\n                Drawable drawable = icon.loadIcon(mPm);\n                mShortcutInfo.setIcon(UIUtils.getBitmapFromDrawable(drawable));\n                mShortcutIconPreview.setImageDrawable(drawable);\n            });\n            dialog.show(getParentFragmentManager(), IconPickerDialogFragment.TAG);\n        });\n        mShortcutNameField.setText(mShortcutInfo.getName());\n        mShortcutNamePreview.setText(mShortcutInfo.getName());\n        mShortcutIconPreview.setImageBitmap(mShortcutInfo.getIcon());\n\n        return new MaterialAlertDialogBuilder(requireActivity())\n                .setTitle(R.string.create_shortcut)\n                .setView(mDialogView)\n                .setPositiveButton(R.string.ok, (dialog, which) -> {\n                    if (mValidName) {\n                        requestPinShortcut(mShortcutInfo);\n                    }\n                })\n                .setNegativeButton(R.string.cancel, null)\n                .create();\n    }\n\n\n    @Nullable\n    @Override\n    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {\n        return mDialogView;\n    }\n\n    @Override\n    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {\n        getLifecycle().addObserver(new SoftInputLifeCycleObserver(new WeakReference<>(mShortcutNameField)));\n    }\n\n\n    @Nullable\n    private Drawable getDrawable(@Nullable String iconResString) {\n        if (TextUtils.isEmpty(iconResString)) {\n            return null;\n        }\n        try {\n            Drawable drawable = ResourceUtil.getResourceFromName(mPm, iconResString).getDrawable(requireActivity().getTheme());\n            if (drawable != null) {\n                return drawable;\n            }\n        } catch (PackageManager.NameNotFoundException | Resources.NotFoundException ignore) {\n        }\n        return null;\n        // return mPm.getDefaultActivityIcon();\n    }\n\n    private void requestPinShortcut(@NonNull ShortcutInfo shortcutInfo) {\n        Context context = requireContext().getApplicationContext();\n        CharSequence name = Objects.requireNonNull(shortcutInfo.getName());\n        String shortcutId = shortcutInfo.getId();\n        if (shortcutId == null) {\n            shortcutId = UUID.randomUUID().toString();\n        }\n        Intent shortcutIntent = shortcutInfo.toShortcutIntent(context);\n        // Set action for shortcut\n        shortcutIntent.setAction(Intent.ACTION_CREATE_SHORTCUT);\n\n        ShortcutInfoCompat shortcutInfoCompat = new ShortcutInfoCompat.Builder(context, shortcutId)\n                // Enforce shortcut name to be a String\n                .setShortLabel(name.toString())\n                .setLongLabel(name)\n                .setIcon(IconCompat.createWithBitmap(shortcutInfo.getIcon()))\n                .setIntent(shortcutIntent)\n                .build();\n\n        boolean shortcutPinned = ShortcutManagerCompat.isRequestPinShortcutSupported(context)\n                && ShortcutManagerCompat.requestPinShortcut(context, shortcutInfoCompat, null);\n        if (!shortcutPinned) {\n            new MaterialAlertDialogBuilder(context)\n                    .setTitle(context.getString(R.string.error_creating_shortcut))\n                    .setMessage(context.getString(R.string.error_verbose_pin_shortcut))\n                    .setPositiveButton(context.getString(R.string.ok), (dialog, which) -> dialog.cancel())\n                    .show();\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/shortcut/ShortcutInfo.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.shortcut;\n\nimport android.content.Context;\nimport android.content.Intent;\nimport android.graphics.Bitmap;\nimport android.os.Parcel;\nimport android.os.Parcelable;\nimport android.text.TextUtils;\n\nimport androidx.annotation.NonNull;\nimport androidx.core.os.ParcelCompat;\n\npublic abstract class ShortcutInfo implements Parcelable {\n    private String mId;\n    private CharSequence mName;\n    private Bitmap mIcon;\n\n    public ShortcutInfo() {\n    }\n\n    protected ShortcutInfo(Parcel in) {\n        mName = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);\n        mIcon = ParcelCompat.readParcelable(in, Bitmap.class.getClassLoader(), Bitmap.class);\n    }\n\n    public String getId() {\n        return mId;\n    }\n\n    public void setId(String id) {\n        mId = id;\n    }\n\n    public CharSequence getName() {\n        return mName;\n    }\n\n    public void setName(CharSequence name) {\n        mName = name;\n    }\n\n    public Bitmap getIcon() {\n        return mIcon;\n    }\n\n    public void setIcon(Bitmap icon) {\n        mIcon = icon;\n    }\n\n    @Override\n    public int describeContents() {\n        return 0;\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        TextUtils.writeToParcel(mName, dest, flags);\n        dest.writeParcelable(mIcon, flags);\n    }\n\n    public abstract Intent toShortcutIntent(@NonNull Context context);\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/ssaid/ChangeSsaidDialog.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.ssaid;\n\nimport android.app.Dialog;\nimport android.content.DialogInterface;\nimport android.os.Build;\nimport android.os.Bundle;\nimport android.os.UserHandleHidden;\nimport android.text.Editable;\nimport android.text.TextWatcher;\nimport android.view.View;\nimport android.widget.Button;\n\nimport androidx.annotation.MainThread;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.RequiresApi;\nimport androidx.appcompat.app.AlertDialog;\nimport androidx.fragment.app.DialogFragment;\nimport androidx.fragment.app.FragmentActivity;\n\nimport com.google.android.material.dialog.MaterialAlertDialogBuilder;\nimport com.google.android.material.textfield.TextInputEditText;\nimport com.google.android.material.textfield.TextInputLayout;\n\nimport java.io.IOException;\nimport java.util.Objects;\nimport java.util.concurrent.Future;\nimport java.util.concurrent.atomic.AtomicReference;\n\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.utils.ThreadUtils;\n\n@RequiresApi(Build.VERSION_CODES.O)\npublic class ChangeSsaidDialog extends DialogFragment {\n    public static final String TAG = ChangeSsaidDialog.class.getSimpleName();\n\n    @NonNull\n    public static ChangeSsaidDialog getInstance(@NonNull String packageName, int uid, @Nullable String ssaid) {\n        ChangeSsaidDialog dialog = new ChangeSsaidDialog();\n        Bundle args = new Bundle();\n        args.putString(ARG_PACKAGE_NAME, packageName);\n        args.putInt(ARG_UID, uid);\n        args.putString(ARG_OPTIONAL_SSAID, ssaid);\n        dialog.setArguments(args);\n        return dialog;\n    }\n\n    public interface SsaidChangedInterface {\n        @MainThread\n        void onSsaidChanged(String newSsaid, boolean isSuccessful);\n    }\n\n    public static final String ARG_PACKAGE_NAME = \"pkg\";\n    public static final String ARG_UID = \"uid\";\n    public static final String ARG_OPTIONAL_SSAID = \"ssaid\";\n\n    private String mSsaid;\n    private String mOldSsaid;\n    @Nullable\n    private SsaidChangedInterface mSsaidChangedInterface;\n    @Nullable\n    private Future<?> mSsaidChangedResult;\n\n    @NonNull\n    @Override\n    public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {\n        FragmentActivity activity = requireActivity();\n        mSsaid = requireArguments().getString(ARG_OPTIONAL_SSAID);\n        mOldSsaid = mSsaid;\n        String packageName = Objects.requireNonNull(requireArguments().getString(ARG_PACKAGE_NAME));\n        int uid = requireArguments().getInt(ARG_UID);\n        int sizeByte = packageName.equals(\"android\") ? 32 : 8;\n        View view = getLayoutInflater().inflate(R.layout.dialog_ssaid_info, null);\n        AlertDialog alertDialog = new MaterialAlertDialogBuilder(activity)\n                .setTitle(R.string.ssaid)\n                .setView(view)\n                .setPositiveButton(R.string.apply, null)\n                .setNegativeButton(R.string.close, null)\n                .setNeutralButton(R.string.reset_to_default, null)\n                .create();\n        TextInputEditText ssaidEditText = view.findViewById(android.R.id.text1);\n        TextInputLayout ssaidInputLayout = view.findViewById(R.id.ssaid_layout);\n        AtomicReference<Button> applyButton = new AtomicReference<>();\n        AtomicReference<Button> resetButton = new AtomicReference<>();\n\n        alertDialog.setOnShowListener(dialog -> {\n            applyButton.set(alertDialog.getButton(AlertDialog.BUTTON_POSITIVE));\n            resetButton.set(alertDialog.getButton(AlertDialog.BUTTON_NEUTRAL));\n            applyButton.get().setVisibility(View.GONE);\n            applyButton.get().setOnClickListener(v -> {\n                mSsaidChangedResult = ThreadUtils.postOnBackgroundThread(() -> {\n                    try {\n                        Editable editable = ssaidEditText.getText();\n                        if (editable == null) {\n                            throw new IOException(\"Empty SSAID field.\");\n                        }\n                        mSsaid = editable.toString();\n                        if (mSsaid.length() != sizeByte * 2) {\n                            throw new IOException(\"Invalid SSAID size \" + mSsaid.length());\n                        }\n                        if (!mSsaid.matches(\"[0-9A-Fa-f]+\")) {\n                            throw new IOException(\"Invalid SSAID \" + mSsaid.length());\n                        }\n                        SsaidSettings ssaidSettings = new SsaidSettings(UserHandleHidden.getUserId(uid));\n                        boolean isSuccess = ssaidSettings.setSsaid(packageName, uid, mSsaid);\n                        if (isSuccess) {\n                            alertDialog.dismiss();\n                        }\n                        if (mSsaidChangedInterface != null) {\n                            ThreadUtils.postOnMainThread(() -> mSsaidChangedInterface.onSsaidChanged(mSsaid, isSuccess));\n                        }\n                    } catch (IOException e) {\n                        e.printStackTrace();\n                        if (mSsaidChangedInterface != null) {\n                            ThreadUtils.postOnMainThread(() -> mSsaidChangedInterface.onSsaidChanged(mSsaid, false));\n                        }\n                    }\n                });\n            });\n            resetButton.get().setVisibility(View.GONE);\n            resetButton.get().setOnClickListener(v -> {\n                mSsaid = mOldSsaid;\n                ssaidEditText.setText(mSsaid);\n                applyButton.get().performClick();\n                resetButton.get().setVisibility(View.GONE);\n                applyButton.get().setVisibility(View.GONE);\n            });\n        });\n        ssaidEditText.setText(mSsaid);\n        ssaidEditText.addTextChangedListener(new TextWatcher() {\n            @Override\n            public void beforeTextChanged(CharSequence s, int start, int count, int after) {\n            }\n\n            @Override\n            public void onTextChanged(CharSequence s, int start, int before, int count) {\n                boolean valid = !s.equals(mSsaid) && s.length() == (2 * sizeByte);\n                if (resetButton.get() != null) {\n                    resetButton.get().setVisibility(valid && !mOldSsaid.contentEquals(s) ? View.VISIBLE : View.GONE);\n                }\n                if (applyButton.get() != null) {\n                    applyButton.get().setVisibility(valid ? View.VISIBLE : View.GONE);\n                }\n            }\n\n            @Override\n            public void afterTextChanged(Editable s) {\n            }\n        });\n        ssaidInputLayout.setEndIconOnClickListener(v -> {\n            mSsaid = SsaidSettings.generateSsaid(packageName);\n            ssaidEditText.setText(mSsaid);\n            if (!mOldSsaid.equals(mSsaid)) {\n                if (resetButton.get() != null) {\n                    resetButton.get().setVisibility(View.VISIBLE);\n                }\n                if (applyButton.get() != null) {\n                    applyButton.get().setVisibility(View.VISIBLE);\n                }\n            }\n        });\n        ssaidInputLayout.setHelperText(getString(R.string.input_ssaid_instruction, sizeByte, sizeByte * 2));\n        ssaidInputLayout.setCounterMaxLength(sizeByte * 2);\n        return alertDialog;\n    }\n\n    @Override\n    public void onDismiss(@NonNull DialogInterface dialog) {\n        if (mSsaidChangedResult != null) {\n            mSsaidChangedResult.cancel(true);\n        }\n        super.onDismiss(dialog);\n    }\n\n    public void setSsaidChangedInterface(@Nullable SsaidChangedInterface ssaidChangedInterface) {\n        mSsaidChangedInterface = ssaidChangedInterface;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/ssaid/SettingsState.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.ssaid;\n\npublic interface SettingsState {\n    String SYSTEM_PACKAGE_NAME = \"android\";\n\n    int MAX_BYTES_PER_APP_PACKAGE_UNLIMITED = -1;\n    int MAX_BYTES_PER_APP_PACKAGE_LIMITED = 20000;\n\n    int SETTINGS_TYPE_GLOBAL = 0;\n    int SETTINGS_TYPE_SYSTEM = 1;\n    int SETTINGS_TYPE_SECURE = 2;\n    int SETTINGS_TYPE_SSAID = 3;\n    int SETTINGS_TYPE_CONFIG = 4;\n\n    Setting getSettingLocked(String name);\n\n    boolean insertSettingLocked(String name, String value, String tag, boolean makeDefault, String packageName);\n\n    interface Setting {\n        String getValue();\n\n        boolean isNull();\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/ssaid/SettingsStateV26.java",
    "content": "// SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.ssaid;\n\nimport android.os.Build;\nimport android.os.RemoteException;\nimport android.os.SystemClock;\nimport android.text.TextUtils;\nimport android.util.ArrayMap;\nimport android.util.Base64;\n\nimport androidx.annotation.GuardedBy;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.RequiresApi;\n\nimport org.xmlpull.v1.XmlPullParser;\nimport org.xmlpull.v1.XmlPullParserException;\n\nimport java.io.FileInputStream;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.util.ArrayList;\nimport java.util.HashSet;\nimport java.util.Iterator;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.Set;\n\nimport io.github.muntashirakon.AppManager.BuildConfig;\nimport io.github.muntashirakon.AppManager.logs.Log;\nimport io.github.muntashirakon.compat.xml.TypedXmlPullParser;\nimport io.github.muntashirakon.compat.xml.TypedXmlSerializer;\nimport io.github.muntashirakon.compat.xml.Xml;\nimport io.github.muntashirakon.io.AtomicExtendedFile;\nimport io.github.muntashirakon.io.IoUtils;\nimport io.github.muntashirakon.io.Path;\nimport io.github.muntashirakon.io.Paths;\n\n/**\n * This class contains the state for one type of settings. It is responsible\n * for saving the state asynchronously to an XML file after a mutation and\n * loading the from an XML file on construction.\n * <p>\n * This class uses the same lock as the settings provider to ensure that\n * multiple changes made by the settings provider, e,g, upgrade, bulk insert,\n * etc, are atomically persisted since the asynchronous persistence is using\n * the same lock to grab the current state to write to disk.\n * </p>\n */\n@RequiresApi(Build.VERSION_CODES.O)\n// Copyright 2015 The Android Open Source Project\npublic final class SettingsStateV26 implements SettingsState {\n    private static final boolean DEBUG = false;\n    private static final boolean DEBUG_PERSISTENCE = false;\n\n    private static final String LOG_TAG = SettingsStateV26.class.getSimpleName();\n\n    static final int SETTINGS_VERSION_NEW_ENCODING = 121;\n\n    private static final long WRITE_SETTINGS_DELAY_MILLIS = 200;\n    private static final long MAX_WRITE_SETTINGS_DELAY_MILLIS = 2000;\n\n    public static final int VERSION_UNDEFINED = -1;\n\n    public static final String FALLBACK_FILE_SUFFIX = \".fallback\";\n\n    private static final String TAG_SETTINGS = \"settings\";\n    private static final String TAG_SETTING = \"setting\";\n    private static final String ATTR_PACKAGE = \"package\";\n    private static final String ATTR_DEFAULT_SYS_SET = \"defaultSysSet\";\n    private static final String ATTR_TAG = \"tag\";\n    private static final String ATTR_TAG_BASE64 = \"tagBase64\";\n\n    private static final String ATTR_VERSION = \"version\";\n    private static final String ATTR_ID = \"id\";\n    private static final String ATTR_NAME = \"name\";\n\n    private static final String TAG_NAMESPACE_HASHES = \"namespaceHashes\";\n    private static final String TAG_NAMESPACE_HASH = \"namespaceHash\";\n    private static final String ATTR_NAMESPACE = \"namespace\";\n    private static final String ATTR_BANNED_HASH = \"bannedHash\";\n\n    private static final String ATTR_PRESERVE_IN_RESTORE = \"preserve_in_restore\";\n\n    /**\n     * Non-binary value will be written in this attributes.\n     */\n    private static final String ATTR_VALUE = \"value\";\n    private static final String ATTR_DEFAULT_VALUE = \"defaultValue\";\n\n    /**\n     * KXmlSerializer won't like some characters. We encode such characters\n     * in base64 and store in this attribute.\n     * NOTE: A null value will have *neither* ATTR_VALUE nor ATTR_VALUE_BASE64.\n     */\n    private static final String ATTR_VALUE_BASE64 = \"valueBase64\";\n    private static final String ATTR_DEFAULT_VALUE_BASE64 = \"defaultValueBase64\";\n\n    // This was used in version 120 and before.\n    private static final String NULL_VALUE_OLD_STYLE = \"null\";\n\n    private static final int HISTORICAL_OPERATION_COUNT = 20;\n    private static final String HISTORICAL_OPERATION_UPDATE = \"update\";\n    private static final String HISTORICAL_OPERATION_DELETE = \"delete\";\n    private static final String HISTORICAL_OPERATION_PERSIST = \"persist\";\n    private static final String HISTORICAL_OPERATION_INITIALIZE = \"initialize\";\n    private static final String HISTORICAL_OPERATION_RESET = \"reset\";\n\n    private static final String NULL_VALUE = \"null\";\n\n    private final Object mWriteLock = new Object();\n\n    private final Object mLock;\n\n    @GuardedBy(\"mLock\")\n    private final ArrayMap<String, Setting> mSettings = new ArrayMap<>();\n\n    @GuardedBy(\"mLock\")\n    private final ArrayMap<String, String> mNamespaceBannedHashes = new ArrayMap<>();\n\n    @GuardedBy(\"mLock\")\n    private final ArrayMap<String, Integer> mPackageToMemoryUsage;\n\n    @GuardedBy(\"mLock\")\n    private final int mMaxBytesPerAppPackage;\n\n    @GuardedBy(\"mLock\")\n    private final Path mStatePersistFile;\n\n    private final Setting mNullSetting = new Setting(null, null, false, null, null) {\n        @Override\n        public boolean isNull() {\n            return true;\n        }\n    };\n\n    @GuardedBy(\"mLock\")\n    private final List<HistoricalOperation> mHistoricalOperations;\n\n    @GuardedBy(\"mLock\")\n    public final int mKey;\n\n    @GuardedBy(\"mLock\")\n    private int mVersion = VERSION_UNDEFINED;\n\n    @GuardedBy(\"mLock\")\n    private long mLastNotWrittenMutationTimeMillis;\n\n    @GuardedBy(\"mLock\")\n    private boolean mDirty;\n\n    @GuardedBy(\"mLock\")\n    private boolean mWriteScheduled;\n\n    @GuardedBy(\"mLock\")\n    private long mNextId;\n\n    @GuardedBy(\"mLock\")\n    private int mNextHistoricalOpIdx;\n\n    public static final int SETTINGS_TYPE_MASK = 0xF0000000;\n    public static final int SETTINGS_TYPE_SHIFT = 28;\n\n    public static int makeKey(int type, int userId) {\n        return (type << SETTINGS_TYPE_SHIFT) | userId;\n    }\n\n    public static int getTypeFromKey(int key) {\n        return key >>> SETTINGS_TYPE_SHIFT;\n    }\n\n    public static int getUserIdFromKey(int key) {\n        return key & ~SETTINGS_TYPE_MASK;\n    }\n\n    @NonNull\n    public static String settingTypeToString(int type) {\n        switch (type) {\n            case SETTINGS_TYPE_CONFIG: {\n                return \"SETTINGS_CONFIG\";\n            }\n            case SETTINGS_TYPE_GLOBAL: {\n                return \"SETTINGS_GLOBAL\";\n            }\n            case SETTINGS_TYPE_SECURE: {\n                return \"SETTINGS_SECURE\";\n            }\n            case SETTINGS_TYPE_SYSTEM: {\n                return \"SETTINGS_SYSTEM\";\n            }\n            case SETTINGS_TYPE_SSAID: {\n                return \"SETTINGS_SSAID\";\n            }\n            default: {\n                return \"UNKNOWN\";\n            }\n        }\n    }\n\n    @NonNull\n    public static String keyToString(int key) {\n        return \"Key[user=\" + getUserIdFromKey(key) + \";type=\"\n                + settingTypeToString(getTypeFromKey(key)) + \"]\";\n    }\n\n    public SettingsStateV26(Object lock, Path file, int key, int maxBytesPerAppPackage)\n            throws IllegalStateException {\n        // It is important that we use the same lock as the settings provider\n        // to ensure multiple mutations on this state are atomically persisted\n        // as the async persistence should be blocked while we make changes.\n        mLock = lock;\n        mStatePersistFile = file;\n        mKey = key;\n        if (maxBytesPerAppPackage == MAX_BYTES_PER_APP_PACKAGE_LIMITED) {\n            mMaxBytesPerAppPackage = maxBytesPerAppPackage;\n            mPackageToMemoryUsage = new ArrayMap<>();\n        } else {\n            mMaxBytesPerAppPackage = maxBytesPerAppPackage;\n            mPackageToMemoryUsage = null;\n        }\n\n        mHistoricalOperations = BuildConfig.DEBUG ? new ArrayList<>(HISTORICAL_OPERATION_COUNT) : null;\n\n        synchronized (mLock) {\n            readStateSyncLocked();\n        }\n    }\n\n    // The settings provider must hold its lock when calling here.\n    @GuardedBy(\"mLock\")\n    public int getVersionLocked() {\n        return mVersion;\n    }\n\n    public Setting getNullSetting() {\n        return mNullSetting;\n    }\n\n    // The settings provider must hold its lock when calling here.\n    @GuardedBy(\"mLock\")\n    public void setVersionLocked(int version) {\n        if (version == mVersion) {\n            return;\n        }\n        mVersion = version;\n\n        scheduleWriteIfNeededLocked();\n    }\n\n    // The settings provider must hold its lock when calling here.\n    @GuardedBy(\"mLock\")\n    public void removeSettingsForPackageLocked(String packageName) {\n        boolean removedSomething = false;\n\n        final int settingCount = mSettings.size();\n        for (int i = settingCount - 1; i >= 0; i--) {\n            Setting setting = mSettings.valueAt(i);\n            if (packageName.equals(setting.packageName)) {\n                mSettings.removeAt(i);\n                removedSomething = true;\n            }\n        }\n\n        if (removedSomething) {\n            scheduleWriteIfNeededLocked();\n        }\n    }\n\n    // The settings provider must hold its lock when calling here.\n    @NonNull\n    @GuardedBy(\"mLock\")\n    public List<String> getSettingNamesLocked() {\n        ArrayList<String> names = new ArrayList<>();\n        final int settingsCount = mSettings.size();\n        for (int i = 0; i < settingsCount; i++) {\n            String name = mSettings.keyAt(i);\n            names.add(name);\n        }\n        return names;\n    }\n\n    // The settings provider must hold its lock when calling here.\n    @GuardedBy(\"mLock\")\n    @Override\n    public Setting getSettingLocked(String name) {\n        if (TextUtils.isEmpty(name)) {\n            return mNullSetting;\n        }\n        Setting setting = mSettings.get(name);\n        if (setting != null) {\n            return new Setting(setting);\n        }\n        return mNullSetting;\n    }\n\n    // The settings provider must hold its lock when calling here.\n    public boolean updateSettingLocked(String name, String value, String tag,\n                                       boolean makeValue, String packageName) {\n        if (!hasSettingLocked(name)) {\n            return false;\n        }\n\n        return insertSettingLocked(name, value, tag, makeValue, packageName);\n    }\n\n    // The settings provider must hold its lock when calling here.\n    @GuardedBy(\"mLock\")\n    public void resetSettingDefaultValueLocked(String name) {\n        Setting oldSetting = getSettingLocked(name);\n        if (oldSetting != null && !oldSetting.isNull() && oldSetting.getDefaultValue() != null) {\n            String oldValue = oldSetting.getValue();\n            String oldDefaultValue = oldSetting.getDefaultValue();\n            Setting newSetting = new Setting(name, oldSetting.getValue(), null,\n                    oldSetting.getPackageName(), oldSetting.getTag(), false,\n                    oldSetting.getId());\n            mSettings.put(name, newSetting);\n            updateMemoryUsagePerPackageLocked(newSetting.getPackageName(), oldValue,\n                    newSetting.getValue(), oldDefaultValue, newSetting.getDefaultValue());\n            scheduleWriteIfNeededLocked();\n        }\n    }\n\n    // The settings provider must hold its lock when calling here.\n    @GuardedBy(\"mLock\")\n    public boolean insertSettingOverrideableByRestoreLocked(String name, String value, String tag,\n                                                            boolean makeDefault, String packageName) {\n        return insertSettingLocked(name, value, tag, makeDefault, false, packageName,\n                /* overrideableByRestore */ true);\n    }\n\n    // The settings provider must hold its lock when calling here.\n    @GuardedBy(\"mLock\")\n    @Override\n    public boolean insertSettingLocked(String name, String value, String tag,\n                                       boolean makeDefault, String packageName) {\n        return insertSettingLocked(name, value, tag, makeDefault, false, packageName,\n                /* overrideableByRestore */ false);\n    }\n\n    // The settings provider must hold its lock when calling here.\n    @GuardedBy(\"mLock\")\n    public boolean insertSettingLocked(String name, String value, String tag,\n                                       boolean makeDefault, boolean forceNonSystemPackage, String packageName,\n                                       boolean overrideableByRestore) {\n        if (TextUtils.isEmpty(name)) {\n            return false;\n        }\n\n        Setting oldState = mSettings.get(name);\n        String oldValue = (oldState != null) ? oldState.value : null;\n        String oldDefaultValue = (oldState != null) ? oldState.defaultValue : null;\n        Setting newState;\n\n        if (oldState != null) {\n            if (!oldState.update(value, makeDefault, packageName, tag, forceNonSystemPackage,\n                    overrideableByRestore)) {\n                return false;\n            }\n            newState = oldState;\n        } else {\n            newState = new Setting(name, value, makeDefault, packageName, tag,\n                    forceNonSystemPackage);\n            mSettings.put(name, newState);\n        }\n\n        addHistoricalOperationLocked(HISTORICAL_OPERATION_UPDATE, newState);\n\n        updateMemoryUsagePerPackageLocked(packageName, oldValue, value,\n                oldDefaultValue, newState.getDefaultValue());\n\n        scheduleWriteIfNeededLocked();\n\n        return true;\n    }\n\n    @GuardedBy(\"mLock\")\n    public boolean isNewConfigBannedLocked(String prefix, Map<String, String> keyValues) {\n        // Replaces old style \"null\" String values with actual null's. This is done to simulate\n        // what will happen to String \"null\" values when they are written to Settings. This needs to\n        // be done here make sure that config hash computed during is banned check matches the\n        // one computed during banning when values are already stored.\n        keyValues = removeNullValueOldStyle(keyValues);\n        String bannedHash = mNamespaceBannedHashes.get(prefix);\n        if (bannedHash == null) {\n            return false;\n        }\n        return bannedHash.equals(hashCode(keyValues));\n    }\n\n    @GuardedBy(\"mLock\")\n    public void unbanAllConfigIfBannedConfigUpdatedLocked(String prefix) {\n        // If the prefix updated is a banned namespace, clear mNamespaceBannedHashes\n        // to unban all unbanned namespaces.\n        if (mNamespaceBannedHashes.get(prefix) != null) {\n            mNamespaceBannedHashes.clear();\n            scheduleWriteIfNeededLocked();\n        }\n    }\n\n    @GuardedBy(\"mLock\")\n    public void banConfigurationLocked(String prefix, Map<String, String> keyValues) {\n        if (prefix == null || keyValues.isEmpty()) {\n            return;\n        }\n        // The write is intentionally not scheduled here, banned hashes should and will be written\n        // when the related setting changes are written\n        mNamespaceBannedHashes.put(prefix, hashCode(keyValues));\n    }\n\n    @GuardedBy(\"mLock\")\n    public Set<String> getAllConfigPrefixesLocked() {\n        Set<String> prefixSet = new HashSet<>();\n        final int settingsCount = mSettings.size();\n        for (int i = 0; i < settingsCount; i++) {\n            String name = mSettings.keyAt(i);\n            prefixSet.add(name.split(\"/\")[0] + \"/\");\n        }\n        return prefixSet;\n    }\n\n    // The settings provider must hold its lock when calling here.\n    // Returns the list of keys which changed (added, updated, or deleted).\n    @GuardedBy(\"mLock\")\n    public List<String> setSettingsLocked(String prefix, Map<String, String> keyValues,\n                                          String packageName) {\n        List<String> changedKeys = new ArrayList<>();\n        final Iterator<Map.Entry<String, Setting>> iterator = mSettings.entrySet().iterator();\n        // Delete old keys with the prefix that are not part of the new set.\n        while (iterator.hasNext()) {\n            Map.Entry<String, Setting> entry = iterator.next();\n            final String key = entry.getKey();\n            final Setting oldState = entry.getValue();\n            if (key != null && key.startsWith(prefix) && !keyValues.containsKey(key)) {\n                iterator.remove();\n\n                addHistoricalOperationLocked(HISTORICAL_OPERATION_DELETE, oldState);\n                changedKeys.add(key); // key was removed\n            }\n        }\n\n        // Update/add new keys\n        for (String key : keyValues.keySet()) {\n            String value = keyValues.get(key);\n            String oldValue = null;\n            Setting state = mSettings.get(key);\n            if (state == null) {\n                state = new Setting(key, value, false, packageName, null);\n                mSettings.put(key, state);\n                changedKeys.add(key); // key was added\n            } else if (!state.value.equals(value)) {\n                oldValue = state.value;\n                state.update(value, false, packageName, null, true,\n                        /* overrideableByRestore */ false);\n                changedKeys.add(key); // key was updated\n            } else {\n                // this key/value already exists, no change and no logging necessary\n                continue;\n            }\n\n            addHistoricalOperationLocked(HISTORICAL_OPERATION_UPDATE, state);\n        }\n\n        if (!changedKeys.isEmpty()) {\n            scheduleWriteIfNeededLocked();\n        }\n\n        return changedKeys;\n    }\n\n    // The settings provider must hold its lock when calling here.\n    public void persistSyncLocked() {\n        doWriteState();\n    }\n\n    // The settings provider must hold its lock when calling here.\n    @GuardedBy(\"mLock\")\n    public boolean deleteSettingLocked(String name) {\n        if (TextUtils.isEmpty(name) || !hasSettingLocked(name)) {\n            return false;\n        }\n\n        Setting oldState = mSettings.remove(name);\n\n        updateMemoryUsagePerPackageLocked(oldState.packageName, oldState.value,\n                null, oldState.defaultValue, null);\n\n        addHistoricalOperationLocked(HISTORICAL_OPERATION_DELETE, oldState);\n\n        scheduleWriteIfNeededLocked();\n\n        return true;\n    }\n\n    // The settings provider must hold its lock when calling here.\n    @GuardedBy(\"mLock\")\n    public boolean resetSettingLocked(String name) {\n        if (TextUtils.isEmpty(name) || !hasSettingLocked(name)) {\n            return false;\n        }\n\n        Setting setting = mSettings.get(name);\n\n        Setting oldSetting = new Setting(setting);\n        String oldValue = setting.getValue();\n        String oldDefaultValue = setting.getDefaultValue();\n\n        if (!setting.reset()) {\n            return false;\n        }\n\n        String newValue = setting.getValue();\n        String newDefaultValue = setting.getDefaultValue();\n\n        updateMemoryUsagePerPackageLocked(setting.packageName, oldValue,\n                newValue, oldDefaultValue, newDefaultValue);\n\n        addHistoricalOperationLocked(HISTORICAL_OPERATION_RESET, oldSetting);\n\n        scheduleWriteIfNeededLocked();\n\n        return true;\n    }\n\n    // The settings provider must hold its lock when calling here.\n    @GuardedBy(\"mLock\")\n    public void destroyLocked(Runnable callback) {\n        if (callback != null) {\n            if (mDirty) {\n                doWriteState();\n            }\n            callback.run();\n        }\n    }\n\n    @GuardedBy(\"mLock\")\n    private void addHistoricalOperationLocked(String type, Setting setting) {\n        if (mHistoricalOperations == null) {\n            return;\n        }\n        HistoricalOperation operation = new HistoricalOperation(\n                SystemClock.elapsedRealtime(), type,\n                setting != null ? new Setting(setting) : null);\n        if (mNextHistoricalOpIdx >= mHistoricalOperations.size()) {\n            mHistoricalOperations.add(operation);\n        } else {\n            mHistoricalOperations.set(mNextHistoricalOpIdx, operation);\n        }\n        mNextHistoricalOpIdx++;\n        if (mNextHistoricalOpIdx >= HISTORICAL_OPERATION_COUNT) {\n            mNextHistoricalOpIdx = 0;\n        }\n    }\n\n    @GuardedBy(\"mLock\")\n    private void updateMemoryUsagePerPackageLocked(String packageName, String oldValue,\n                                                   String newValue, String oldDefaultValue, String newDefaultValue) {\n        if (mMaxBytesPerAppPackage == MAX_BYTES_PER_APP_PACKAGE_UNLIMITED) {\n            return;\n        }\n\n        if (SYSTEM_PACKAGE_NAME.equals(packageName)) {\n            return;\n        }\n\n        final int oldValueSize = (oldValue != null) ? oldValue.length() : 0;\n        final int newValueSize = (newValue != null) ? newValue.length() : 0;\n        final int oldDefaultValueSize = (oldDefaultValue != null) ? oldDefaultValue.length() : 0;\n        final int newDefaultValueSize = (newDefaultValue != null) ? newDefaultValue.length() : 0;\n        final int deltaSize = newValueSize + newDefaultValueSize\n                - oldValueSize - oldDefaultValueSize;\n\n        Integer currentSize = mPackageToMemoryUsage.get(packageName);\n        final int newSize = Math.max((currentSize != null)\n                ? currentSize + deltaSize : deltaSize, 0);\n\n        if (newSize > mMaxBytesPerAppPackage) {\n            throw new IllegalStateException(\"You are adding too many system settings. \"\n                    + \"You should stop using system settings for app specific data\"\n                    + \" package: \" + packageName);\n        }\n\n        if (DEBUG) {\n            Log.i(LOG_TAG, \"Settings for package: %s size: %s bytes.\", packageName, newSize);\n        }\n\n        mPackageToMemoryUsage.put(packageName, newSize);\n    }\n\n    @GuardedBy(\"mLock\")\n    private boolean hasSettingLocked(String name) {\n        return mSettings.indexOfKey(name) >= 0;\n    }\n\n    @GuardedBy(\"mLock\")\n    private void scheduleWriteIfNeededLocked() {\n        // If dirty then we have a write already scheduled.\n        if (!mDirty) {\n            mDirty = true;\n            writeStateAsyncLocked();\n        }\n    }\n\n    @GuardedBy(\"mLock\")\n    private void writeStateAsyncLocked() {\n        doWriteState();\n    }\n\n    private void doWriteState() {\n        boolean wroteState = false;\n        final int version;\n        final ArrayMap<String, Setting> settings;\n        final ArrayMap<String, String> namespaceBannedHashes;\n\n        synchronized (mLock) {\n            version = mVersion;\n            settings = new ArrayMap<>(mSettings);\n            namespaceBannedHashes = new ArrayMap<>(mNamespaceBannedHashes);\n            mDirty = false;\n            mWriteScheduled = false;\n        }\n\n        synchronized (mWriteLock) {\n            if (DEBUG_PERSISTENCE) {\n                Log.i(LOG_TAG, \"[PERSIST START]\");\n            }\n\n            AtomicExtendedFile destination = new AtomicExtendedFile(mStatePersistFile.getFile());\n            FileOutputStream out = null;\n            try {\n                out = destination.startWrite();\n\n                TypedXmlSerializer serializer = Xml.resolveSerializer(out);\n                serializer.startDocument(null, true);\n                serializer.startTag(null, TAG_SETTINGS);\n                serializer.attributeInt(null, ATTR_VERSION, version);\n\n                final int settingCount = settings.size();\n                for (int i = 0; i < settingCount; i++) {\n                    Setting setting = settings.valueAt(i);\n\n                    if (writeSingleSetting(mVersion, serializer, setting.getId(), setting.getName(),\n                            setting.getValue(), setting.getDefaultValue(), setting.getPackageName(),\n                            setting.getTag(), setting.isDefaultFromSystem(),\n                            setting.isValuePreservedInRestore())) {\n                        if (DEBUG_PERSISTENCE) {\n                            Log.i(LOG_TAG, \"[PERSISTED] %s=%s\", setting.getName(), setting.getValue());\n                        }\n                    }\n                }\n                serializer.endTag(null, TAG_SETTINGS);\n\n                serializer.startTag(null, TAG_NAMESPACE_HASHES);\n                for (int i = 0; i < namespaceBannedHashes.size(); i++) {\n                    String namespace = namespaceBannedHashes.keyAt(i);\n                    String bannedHash = namespaceBannedHashes.get(namespace);\n                    if (writeSingleNamespaceHash(serializer, namespace, bannedHash)) {\n                        if (DEBUG_PERSISTENCE) {\n                            Log.i(LOG_TAG, \"[PERSISTED] namespace=%s, bannedHash=%s\", namespace, bannedHash);\n                        }\n                    }\n                }\n                serializer.endTag(null, TAG_NAMESPACE_HASHES);\n                serializer.endDocument();\n                destination.finishWrite(out);\n\n                wroteState = true;\n\n                if (DEBUG_PERSISTENCE) {\n                    Log.i(LOG_TAG, \"[PERSIST END]\");\n                }\n            } catch (Throwable t) {\n                Log.e(LOG_TAG, \"Failed to write settings, restoring backup\", t);\n                if (t instanceof IOException) {\n                    // we failed to create a directory, so log the permissions and existence\n                    // state for the settings file and directory\n                    logSettingsDirectoryInformation(Paths.get(destination.getBaseFile()));\n                    if (t.getMessage().contains(\"Couldn't create directory\")) {\n                        // attempt to create the directory with Files.createDirectories, which\n                        // throws more informative errors than File.mkdirs.\n                        Path parentPath = Paths.get(destination.getBaseFile().getParentFile());\n                        if (parentPath.mkdirs()) {\n                            Log.i(LOG_TAG, \"Successfully created %s\", parentPath);\n                        } else {\n                            Log.e(LOG_TAG, \"Failed to write %s with Files.writeDirectories\", parentPath);\n                        }\n                    }\n                }\n                destination.failWrite(out);\n            } finally {\n                IoUtils.closeQuietly(out);\n            }\n        }\n\n        if (wroteState) {\n            synchronized (mLock) {\n                addHistoricalOperationLocked(HISTORICAL_OPERATION_PERSIST, null);\n            }\n        }\n    }\n\n    private static void logSettingsDirectoryInformation(Path settingsFile) {\n        Path parent = settingsFile.getParent();\n        Log.i(LOG_TAG, \"directory info for directory/file %s with stacktrace \", new Exception(), settingsFile);\n        Path ancestorDir = parent;\n        while (ancestorDir != null) {\n            if (!ancestorDir.exists()) {\n                Log.i(LOG_TAG, \"ancestor directory %s does not exist\", ancestorDir);\n                ancestorDir = ancestorDir.getParent();\n            } else {\n                Log.i(LOG_TAG, \"ancestor directory %s exists\", ancestorDir);\n                Log.i(LOG_TAG, \"ancestor directory %s permissions: r: %s w: %s x: %s\", ancestorDir,\n                        ancestorDir.canRead(), ancestorDir.canWrite(), ancestorDir.canExecute());\n                Path ancestorParent = ancestorDir.getParent();\n                if (ancestorParent != null) {\n                    Log.i(LOG_TAG, \"ancestor's parent directory %s permissions: r: %s w: %s\" + \" x: %s\",\n                            ancestorParent, ancestorParent.canRead(), ancestorParent.canWrite(),\n                            ancestorParent.canExecute());\n                }\n                break;\n            }\n        }\n    }\n\n    static boolean writeSingleSetting(int version, TypedXmlSerializer serializer, String id,\n                                   String name, String value, String defaultValue, String packageName,\n                                   String tag, boolean defaultSysSet, boolean isValuePreservedInRestore)\n            throws IOException {\n        if (id == null || isBinary(id) || name == null || isBinary(name)\n                || packageName == null || isBinary(packageName)) {\n            if (DEBUG_PERSISTENCE) {\n                Log.w(LOG_TAG, \"Invalid arguments for writeSingleSetting: version=\" + version\n                        + \", id=\" + id + \", name=\" + name + \", value=\" + value\n                        + \", defaultValue=\" + defaultValue + \", packageName=\" + packageName\n                        + \", tag=\" + tag + \", defaultSysSet=\" + defaultSysSet\n                        + \", isValuePreservedInRestore=\" + isValuePreservedInRestore);\n            }\n            return false;\n        }\n        serializer.startTag(null, TAG_SETTING);\n        serializer.attribute(null, ATTR_ID, id);\n        serializer.attribute(null, ATTR_NAME, name);\n        setValueAttribute(ATTR_VALUE, ATTR_VALUE_BASE64,\n                version, serializer, value);\n        serializer.attribute(null, ATTR_PACKAGE, packageName);\n        if (defaultValue != null) {\n            setValueAttribute(ATTR_DEFAULT_VALUE, ATTR_DEFAULT_VALUE_BASE64,\n                    version, serializer, defaultValue);\n            serializer.attributeBoolean(null, ATTR_DEFAULT_SYS_SET, defaultSysSet);\n            setValueAttribute(ATTR_TAG, ATTR_TAG_BASE64,\n                    version, serializer, tag);\n        }\n        if (isValuePreservedInRestore) {\n            serializer.attributeBoolean(null, ATTR_PRESERVE_IN_RESTORE, true);\n        }\n        serializer.endTag(null, TAG_SETTING);\n        return true;\n    }\n\n    static void setValueAttribute(String attr, String attrBase64, int version,\n                                  TypedXmlSerializer serializer, String value) throws IOException {\n        if (version >= SETTINGS_VERSION_NEW_ENCODING) {\n            if (value == null) {\n                // Null value -> No ATTR_VALUE nor ATTR_VALUE_BASE64.\n            } else if (isBinary(value)) {\n                serializer.attribute(null, attrBase64, base64Encode(value));\n            } else {\n                serializer.attribute(null, attr, value);\n            }\n        } else {\n            // Old encoding.\n            if (value == null) {\n                serializer.attribute(null, attr, NULL_VALUE_OLD_STYLE);\n            } else {\n                serializer.attribute(null, attr, value);\n            }\n        }\n    }\n\n    private static boolean writeSingleNamespaceHash(TypedXmlSerializer serializer, String namespace,\n                                                 String bannedHashCode) throws IOException {\n        if (namespace == null || bannedHashCode == null) {\n            if (DEBUG_PERSISTENCE) {\n                Log.w(LOG_TAG, \"Invalid arguments for writeSingleNamespaceHash: namespace=\"\n                        + namespace + \", bannedHashCode=\" + bannedHashCode);\n            }\n            return false;\n        }\n        serializer.startTag(null, TAG_NAMESPACE_HASH);\n        serializer.attribute(null, ATTR_NAMESPACE, namespace);\n        serializer.attribute(null, ATTR_BANNED_HASH, bannedHashCode);\n        serializer.endTag(null, TAG_NAMESPACE_HASH);\n        return true;\n    }\n\n    private static String hashCode(Map<String, String> keyValues) {\n        return Integer.toString(keyValues.hashCode());\n    }\n\n    private String getValueAttribute(TypedXmlPullParser parser, String attr, String base64Attr) {\n        if (mVersion >= SETTINGS_VERSION_NEW_ENCODING) {\n            final String value = parser.getAttributeValue(null, attr);\n            if (value != null) {\n                return value;\n            }\n            final String base64 = parser.getAttributeValue(null, base64Attr);\n            if (base64 != null) {\n                return base64Decode(base64);\n            }\n            // null has neither ATTR_VALUE nor ATTR_VALUE_BASE64.\n            return null;\n        } else {\n            // Old encoding.\n            final String stored = parser.getAttributeValue(null, attr);\n            if (NULL_VALUE_OLD_STYLE.equals(stored)) {\n                return null;\n            } else {\n                return stored;\n            }\n        }\n    }\n\n    @GuardedBy(\"mLock\")\n    private void readStateSyncLocked() throws IllegalStateException {\n        FileInputStream in;\n        AtomicExtendedFile file = new AtomicExtendedFile(mStatePersistFile.getFile());\n        try {\n            in = file.openRead();\n        } catch (IOException | RemoteException fnfe) {\n            Log.w(LOG_TAG, \"No settings state %s\", mStatePersistFile);\n            logSettingsDirectoryInformation(mStatePersistFile);\n            addHistoricalOperationLocked(HISTORICAL_OPERATION_INITIALIZE, null);\n            return;\n        }\n        if (parseStateFromXmlStreamLocked(in)) {\n            return;\n        }\n\n        // Settings file exists but is corrupted. Retry with the fallback file\n        Path statePersistFallbackFile = Paths.get(mStatePersistFile.getFilePath() + FALLBACK_FILE_SUFFIX);\n        Log.i(LOG_TAG, \"Failed parsing settings file: %s, retrying with fallback file: %s\", mStatePersistFile,\n                statePersistFallbackFile);\n        try {\n            in = new AtomicExtendedFile(statePersistFallbackFile.getFile()).openRead();\n        } catch (IOException | RemoteException fnfe) {\n            final String message = \"No fallback file found for: \" + mStatePersistFile;\n            throw new IllegalStateException(message, fnfe);\n        }\n        if (parseStateFromXmlStreamLocked(in)) {\n            // Parsed state from fallback file. Restore original file with fallback file\n            try {\n                IoUtils.copy(statePersistFallbackFile, mStatePersistFile);\n            } catch (IOException ignored) {\n                // Failed to copy, but it's okay because we already parsed states from fallback file\n            }\n        } else {\n            final String message = \"Failed parsing settings file: \" + mStatePersistFile;\n            throw new IllegalStateException(message);\n        }\n    }\n\n    @GuardedBy(\"mLock\")\n    private boolean parseStateFromXmlStreamLocked(InputStream in) {\n        try {\n            TypedXmlPullParser parser = Xml.resolvePullParser(in);\n            parseStateLocked(parser);\n            return true;\n        } catch (XmlPullParserException | IOException e) {\n            return false;\n        } finally {\n            IoUtils.closeQuietly(in);\n        }\n    }\n\n    /**\n     * Uses AtomicExtendedFile to check if the file or its backup exists.\n     *\n     * @param file The file to check for existence\n     * @return whether the original or backup exist\n     */\n    public static boolean stateFileExists(Path file) {\n        AtomicExtendedFile stateFile = new AtomicExtendedFile(Objects.requireNonNull(file.getFile()));\n        return stateFile.exists();\n    }\n\n    private void parseStateLocked(@NonNull TypedXmlPullParser parser)\n            throws IOException, XmlPullParserException {\n        final int outerDepth = parser.getDepth();\n        int type;\n        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT\n                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {\n            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {\n                continue;\n            }\n\n            String tagName = parser.getName();\n            if (tagName.equals(TAG_SETTINGS)) {\n                parseSettingsLocked(parser);\n            } else if (tagName.equals(TAG_NAMESPACE_HASHES)) {\n                parseNamespaceHash(parser);\n            }\n        }\n    }\n\n    @GuardedBy(\"mLock\")\n    private void parseSettingsLocked(@NonNull TypedXmlPullParser parser) throws IOException, XmlPullParserException {\n\n        mVersion = parser.getAttributeInt(null, ATTR_VERSION);\n\n        final int outerDepth = parser.getDepth();\n        int type;\n        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT\n                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {\n            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {\n                continue;\n            }\n\n            String tagName = parser.getName();\n            if (tagName.equals(TAG_SETTING)) {\n                String id = parser.getAttributeValue(null, ATTR_ID);\n                String name = parser.getAttributeValue(null, ATTR_NAME);\n                String value = getValueAttribute(parser, ATTR_VALUE, ATTR_VALUE_BASE64);\n                String packageName = parser.getAttributeValue(null, ATTR_PACKAGE);\n                String defaultValue = getValueAttribute(parser, ATTR_DEFAULT_VALUE,\n                        ATTR_DEFAULT_VALUE_BASE64);\n                boolean isPreservedInRestore = parser.getAttributeBoolean(null,\n                        ATTR_PRESERVE_IN_RESTORE, false);\n                String tag = null;\n                boolean fromSystem = false;\n                if (defaultValue != null) {\n                    fromSystem = parser.getAttributeBoolean(null, ATTR_DEFAULT_SYS_SET);\n                    tag = getValueAttribute(parser, ATTR_TAG, ATTR_TAG_BASE64);\n                }\n                mSettings.put(name, new Setting(name, value, defaultValue, packageName, tag,\n                        fromSystem, id, isPreservedInRestore));\n\n                if (DEBUG_PERSISTENCE) {\n                    Log.i(LOG_TAG, \"[RESTORED] %s=%s\", name, value);\n                }\n            }\n        }\n    }\n\n    @GuardedBy(\"mLock\")\n    private void parseNamespaceHash(TypedXmlPullParser parser)\n            throws IOException, XmlPullParserException {\n\n        final int outerDepth = parser.getDepth();\n        int type;\n        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT\n                && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {\n            if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {\n                continue;\n            }\n\n            if (parser.getName().equals(TAG_NAMESPACE_HASH)) {\n                String namespace = parser.getAttributeValue(null, ATTR_NAMESPACE);\n                String bannedHashCode = parser.getAttributeValue(null, ATTR_BANNED_HASH);\n                mNamespaceBannedHashes.put(namespace, bannedHashCode);\n            }\n        }\n    }\n\n    private static Map<String, String> removeNullValueOldStyle(@NonNull Map<String, String> keyValues) {\n        for (Map.Entry<String, String> keyValueEntry : keyValues.entrySet()) {\n            if (NULL_VALUE_OLD_STYLE.equals(keyValueEntry.getValue())) {\n                keyValueEntry.setValue(null);\n            }\n        }\n        return keyValues;\n    }\n\n    private class HistoricalOperation {\n        final long mTimestamp;\n        final String mOperation;\n        final Setting mSetting;\n\n        public HistoricalOperation(long timestamp,\n                                   String operation, Setting setting) {\n            mTimestamp = timestamp;\n            mOperation = operation;\n            mSetting = setting;\n        }\n    }\n\n    class Setting implements SettingsState.Setting {\n        private String name;\n        private String value;\n        private String defaultValue;\n        private String packageName;\n        private String id;\n        private String tag;\n        // Whether the default is set by the system\n        private boolean defaultFromSystem;\n        // Whether the value of this setting will be preserved when restore happens.\n        private boolean isValuePreservedInRestore;\n\n        public Setting(@NonNull Setting other) {\n            name = other.name;\n            value = other.value;\n            defaultValue = other.defaultValue;\n            packageName = other.packageName;\n            id = other.id;\n            defaultFromSystem = other.defaultFromSystem;\n            tag = other.tag;\n            isValuePreservedInRestore = other.isValuePreservedInRestore;\n        }\n\n        public Setting(String name, String value, boolean makeDefault, String packageName,\n                       String tag) {\n            this(name, value, makeDefault, packageName, tag, false);\n        }\n\n        Setting(String name, String value, boolean makeDefault, String packageName,\n                String tag, boolean forceNonSystemPackage) {\n            this.name = name;\n            // overrideableByRestore = true as the first initialization isn't considered a\n            // modification.\n            update(value, makeDefault, packageName, tag, forceNonSystemPackage, true);\n        }\n\n        public Setting(String name, String value, String defaultValue,\n                       String packageName, String tag, boolean fromSystem, String id) {\n            this(name, value, defaultValue, packageName, tag, fromSystem, id,\n                    /* isOverrideableByRestore */ false);\n        }\n\n        Setting(String name, String value, String defaultValue,\n                String packageName, String tag, boolean fromSystem, String id,\n                boolean isValuePreservedInRestore) {\n            mNextId = Math.max(mNextId, Long.parseLong(id) + 1);\n            if (NULL_VALUE.equals(value)) {\n                value = null;\n            }\n            init(name, value, tag, defaultValue, packageName, fromSystem, id,\n                    isValuePreservedInRestore);\n        }\n\n        private void init(String name, String value, String tag, String defaultValue,\n                          String packageName, boolean fromSystem, String id,\n                          boolean isValuePreservedInRestore) {\n            this.name = name;\n            this.value = value;\n            this.tag = tag;\n            this.defaultValue = defaultValue;\n            this.packageName = packageName;\n            this.id = id;\n            this.defaultFromSystem = fromSystem;\n            this.isValuePreservedInRestore = isValuePreservedInRestore;\n        }\n\n        public String getName() {\n            return name;\n        }\n\n        public int getKey() {\n            return mKey;\n        }\n\n        public String getValue() {\n            return value;\n        }\n\n        public String getTag() {\n            return tag;\n        }\n\n        public String getDefaultValue() {\n            return defaultValue;\n        }\n\n        public String getPackageName() {\n            return packageName;\n        }\n\n        public boolean isDefaultFromSystem() {\n            return defaultFromSystem;\n        }\n\n        public boolean isValuePreservedInRestore() {\n            return isValuePreservedInRestore;\n        }\n\n        public String getId() {\n            return id;\n        }\n\n        public boolean isNull() {\n            return false;\n        }\n\n        /**\n         * @return whether the value changed\n         */\n        public boolean reset() {\n            // overrideableByRestore = true as resetting to default value isn't considered a\n            // modification.\n            return update(this.defaultValue, false, packageName, null, true, true,\n                    /* resetToDefault */ true);\n        }\n\n        public boolean update(String value, boolean setDefault, String packageName, String tag,\n                              boolean forceNonSystemPackage, boolean overrideableByRestore) {\n            return update(value, setDefault, packageName, tag, forceNonSystemPackage,\n                    overrideableByRestore, /* resetToDefault */ false);\n        }\n\n        private boolean update(String value, boolean setDefault, String packageName, String tag,\n                               boolean forceNonSystemPackage, boolean overrideableByRestore,\n                               boolean resetToDefault) {\n            if (NULL_VALUE.equals(value)) {\n                value = null;\n            }\n\n            String defaultValue = this.defaultValue;\n            boolean defaultFromSystem = this.defaultFromSystem;\n            if (setDefault) {\n                if (!Objects.equals(value, this.defaultValue)) {\n                    defaultValue = value;\n                    // Default null means no default, so the tag is irrelevant\n                    // since it is used to reset a settings subset their defaults.\n                    // Also it is irrelevant if the system set the canonical default.\n                    if (defaultValue == null) {\n                        tag = null;\n                        defaultFromSystem = false;\n                    }\n                }\n                if (!defaultFromSystem && value != null) {\n                    defaultFromSystem = true;\n                }\n            }\n\n            // isValuePreservedInRestore shouldn't change back to false if it has been set to true.\n            boolean isPreserved = shouldPreserveSetting(overrideableByRestore, resetToDefault,\n                    packageName, value);\n\n            // Is something gonna change?\n            if (Objects.equals(value, this.value)\n                    && Objects.equals(defaultValue, this.defaultValue)\n                    && Objects.equals(packageName, this.packageName)\n                    && Objects.equals(tag, this.tag)\n                    && defaultFromSystem == this.defaultFromSystem\n                    && isPreserved == this.isValuePreservedInRestore) {\n                return false;\n            }\n\n            init(name, value, tag, defaultValue, packageName, defaultFromSystem,\n                    String.valueOf(mNextId++), isPreserved);\n\n            return true;\n        }\n\n        @NonNull\n        public String toString() {\n            return \"Setting{name=\" + name + \" value=\" + value\n                    + (defaultValue != null ? \" default=\" + defaultValue : \"\")\n                    + \" packageName=\" + packageName + \" tag=\" + tag\n                    + \" defaultFromSystem=\" + defaultFromSystem + \"}\";\n        }\n\n        private boolean shouldPreserveSetting(boolean overrideableByRestore,\n                                              boolean resetToDefault, String packageName, String value) {\n            if (resetToDefault) {\n                // By default settings are not marked as preserved.\n                return false;\n            }\n            if (value != null && value.equals(this.value)\n                    && SYSTEM_PACKAGE_NAME.equals(packageName)) {\n                // Do not mark preserved if it's the system reinitializing to the same value.\n                return false;\n            }\n\n            // isValuePreservedInRestore shouldn't change back to false if it has been set to true.\n            return this.isValuePreservedInRestore || !overrideableByRestore;\n        }\n    }\n\n    /**\n     * @return TRUE if a string is considered \"binary\" from KXML's point of view.  NOTE DO NOT\n     * pass null.\n     */\n    public static boolean isBinary(String s) {\n        if (s == null) {\n            throw new NullPointerException();\n        }\n        // See KXmlSerializer.writeEscaped\n        for (int i = 0; i < s.length(); i++) {\n            char c = s.charAt(i);\n            boolean allowedInXml = (c >= 0x20 && c <= 0xd7ff) || (c >= 0xe000 && c <= 0xfffd);\n            if (!allowedInXml) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    private static String base64Encode(String s) {\n        return Base64.encodeToString(toBytes(s), Base64.NO_WRAP);\n    }\n\n    @NonNull\n    private static String base64Decode(String s) {\n        return fromBytes(Base64.decode(s, Base64.DEFAULT));\n    }\n\n    // Note the followings are basically just UTF-16 encode/decode.  But we want to preserve\n    // contents as-is, even if it contains broken surrogate pairs, we do it by ourselves,\n    // since I don't know how Charset would treat them.\n\n    @NonNull\n    private static byte[] toBytes(@NonNull String s) {\n        final byte[] result = new byte[s.length() * 2];\n        int resultIndex = 0;\n        for (int i = 0; i < s.length(); ++i) {\n            char ch = s.charAt(i);\n            result[resultIndex++] = (byte) (ch >> 8);\n            result[resultIndex++] = (byte) ch;\n        }\n        return result;\n    }\n\n    @NonNull\n    private static String fromBytes(@NonNull byte[] bytes) {\n        final StringBuilder sb = new StringBuilder(bytes.length / 2);\n\n        final int last = bytes.length - 1;\n\n        for (int i = 0; i < last; i += 2) {\n            final char ch = (char) ((bytes[i] & 0xff) << 8 | (bytes[i + 1] & 0xff));\n            sb.append(ch);\n        }\n        return sb.toString();\n    }\n}"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/ssaid/SsaidSettings.java",
    "content": "// SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.ssaid;\n\nimport static io.github.muntashirakon.AppManager.ssaid.SettingsState.SYSTEM_PACKAGE_NAME;\n\nimport android.annotation.UserIdInt;\nimport android.content.pm.PackageInfo;\nimport android.os.Build;\nimport android.os.UserHandleHidden;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.RequiresApi;\nimport androidx.annotation.VisibleForTesting;\nimport androidx.annotation.WorkerThread;\n\nimport java.io.IOException;\nimport java.nio.ByteBuffer;\nimport java.security.InvalidKeyException;\nimport java.security.NoSuchAlgorithmException;\nimport java.security.SecureRandom;\nimport java.security.cert.X509Certificate;\nimport java.util.Objects;\n\nimport javax.crypto.Mac;\nimport javax.crypto.spec.SecretKeySpec;\n\nimport aosp.libcore.util.HexEncoding;\nimport io.github.muntashirakon.AppManager.apk.signing.SignerInfo;\nimport io.github.muntashirakon.AppManager.compat.PackageManagerCompat;\nimport io.github.muntashirakon.AppManager.misc.OsEnvironment;\nimport io.github.muntashirakon.AppManager.utils.PackageUtils;\nimport io.github.muntashirakon.io.Path;\n\n@RequiresApi(Build.VERSION_CODES.O)\npublic class SsaidSettings {\n    public static final String SSAID_USER_KEY = \"userkey\";\n\n    @SuppressWarnings(\"FieldCanBeLocal\")\n    private final Object mLock = new Object();\n    private final SettingsState mSettingsState;\n\n    @WorkerThread\n    public SsaidSettings(@UserIdInt int userId) throws IOException {\n        Path ssaidLocation = OsEnvironment.getUserSystemDirectory(userId)\n                .findFile(\"settings_ssaid.xml\");\n        if (!ssaidLocation.canRead()) {\n            throw new IOException(\"settings_ssaid.xml is inaccessible.\");\n        }\n        mSettingsState = init(ssaidLocation, userId);\n    }\n\n    @VisibleForTesting\n    public SsaidSettings(Path ssaidLocation, @UserIdInt int userId) throws IOException {\n        mSettingsState = init(ssaidLocation, userId);\n    }\n\n    @NonNull\n    private SettingsState init(Path ssaidLocation, @UserIdInt int userId) throws IOException {\n        int ssaidKey = SettingsStateV26.makeKey(SettingsState.SETTINGS_TYPE_SSAID, userId);\n        try {\n            return new SettingsStateV26(mLock, ssaidLocation, ssaidKey,\n                    SettingsState.MAX_BYTES_PER_APP_PACKAGE_UNLIMITED);\n        } catch (IllegalStateException e) {\n            throw new IOException(e);\n        }\n    }\n\n    @Nullable\n    public String getSsaid(@NonNull String packageName, int uid) {\n        return mSettingsState.getSettingLocked(getName(packageName, uid)).getValue();\n    }\n\n    public boolean setSsaid(@NonNull String packageName, int uid, String ssaid) {\n        try {\n            PackageManagerCompat.forceStopPackage(packageName, UserHandleHidden.getUserId(uid));\n        } catch (Throwable e) {\n            e.printStackTrace();\n        }\n        return mSettingsState.insertSettingLocked(getName(packageName, uid), ssaid, null, true, packageName);\n    }\n\n    private static String getName(@Nullable String packageName, int uid) {\n        return Objects.equals(packageName, SYSTEM_PACKAGE_NAME) ? SSAID_USER_KEY : String.valueOf(uid);\n    }\n\n    @NonNull\n    public static String generateSsaid(@NonNull String packageName) {\n        boolean isUserKey = packageName.equals(SYSTEM_PACKAGE_NAME);\n        // Generate a random key for each user used for creating a new ssaid.\n        final byte[] keyBytes = new byte[isUserKey ? 32 : 8];\n        final SecureRandom rand = new SecureRandom();\n        rand.nextBytes(keyBytes);\n        // Convert to string for storage in settings table.\n        return HexEncoding.encodeToString(keyBytes, isUserKey /* upperCase */);\n    }\n\n    @NonNull\n    public static String generateSsaid(@NonNull PackageInfo callingPkg) throws IOException {\n        // Read the user's key from the ssaid table.\n        SsaidSettings ssaidSettings = new SsaidSettings(UserHandleHidden.getUserId(callingPkg.applicationInfo.uid));\n        SettingsState settingsState = ssaidSettings.mSettingsState;\n        SettingsState.Setting userKeySetting = settingsState.getSettingLocked(SSAID_USER_KEY);\n        if (userKeySetting == null || userKeySetting.isNull()\n                || userKeySetting.getValue() == null) {\n            // Lazy initialize and store the user key.\n            String userKey = generateSsaid(SYSTEM_PACKAGE_NAME);\n            settingsState.insertSettingLocked(SSAID_USER_KEY, userKey, null, true, SYSTEM_PACKAGE_NAME);\n            userKeySetting = settingsState.getSettingLocked(SSAID_USER_KEY);\n            if (userKeySetting == null || userKeySetting.isNull()\n                    || userKeySetting.getValue() == null) {\n                throw new IllegalStateException(\"User key not accessible\");\n            }\n        }\n        final String userKey = userKeySetting.getValue();\n        if (userKey == null || userKey.length() % 2 != 0) {\n            throw new IllegalStateException(\"User key invalid\");\n        }\n\n        // Convert the user's key back to a byte array.\n        final byte[] keyBytes = HexEncoding.decode(userKey);\n\n        // Validate that the key is of expected length.\n        // Keys are currently 32 bytes, but were once 16 bytes during Android O development.\n        if (keyBytes.length != 16 && keyBytes.length != 32) {\n            throw new IllegalStateException(\"User key invalid\");\n        }\n\n        final Mac m;\n        try {\n            m = Mac.getInstance(\"HmacSHA256\");\n            m.init(new SecretKeySpec(keyBytes, m.getAlgorithm()));\n        } catch (NoSuchAlgorithmException e) {\n            throw new IllegalStateException(\"HmacSHA256 is not available\", e);\n        } catch (InvalidKeyException e) {\n            throw new IllegalStateException(\"Key is corrupted\", e);\n        }\n\n        // Mac each of the developer signatures.\n        SignerInfo signerInfo = PackageUtils.getSignerInfo(callingPkg, false);\n        if (signerInfo != null) {\n            X509Certificate[] signerCerts = signerInfo.getCurrentSignerCerts();\n            if (signerCerts != null) {\n                for (X509Certificate cert : signerCerts) {\n                    try {\n                        byte[] sig = cert.getEncoded();\n                        m.update(getLengthPrefix(sig), 0, 4);\n                        m.update(sig);\n                    } catch (Exception ignore) {\n                    }\n                }\n            }\n        }\n\n        // Convert result to a string for storage in settings table. Only want first 64 bits.\n        return HexEncoding.encodeToString(m.doFinal(), false /* upperCase */).substring(0, 16);\n    }\n\n    @NonNull\n    private static byte[] getLengthPrefix(@NonNull byte[] data) {\n        return ByteBuffer.allocate(4).putInt(data.length).array();\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/sysconfig/SysConfigActivity.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.sysconfig;\n\nimport static io.github.muntashirakon.AppManager.utils.UIUtils.getStyledKeyValue;\n\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.pm.ApplicationInfo;\nimport android.content.pm.PackageManager;\nimport android.os.Bundle;\nimport android.text.SpannableStringBuilder;\nimport android.view.LayoutInflater;\nimport android.view.MenuItem;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.ArrayAdapter;\nimport android.widget.ImageView;\nimport android.widget.TextView;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.lifecycle.ViewModelProvider;\n\nimport com.google.android.material.card.MaterialCardView;\nimport com.google.android.material.progressindicator.LinearProgressIndicator;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.Optional;\n\nimport io.github.muntashirakon.AppManager.BaseActivity;\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.details.AppDetailsActivity;\nimport io.github.muntashirakon.AppManager.self.imagecache.ImageLoader;\nimport io.github.muntashirakon.AppManager.utils.UIUtils;\nimport io.github.muntashirakon.util.AdapterUtils;\nimport io.github.muntashirakon.AppManager.utils.LangUtils;\nimport io.github.muntashirakon.AppManager.utils.appearance.ColorCodes;\nimport io.github.muntashirakon.adapters.SelectedArrayAdapter;\nimport io.github.muntashirakon.util.UiUtils;\nimport io.github.muntashirakon.widget.MaterialSpinner;\nimport io.github.muntashirakon.widget.RecyclerView;\n\npublic class SysConfigActivity extends BaseActivity {\n    private SysConfigRecyclerAdapter mAdapter;\n    private LinearProgressIndicator mProgressIndicator;\n    @NonNull\n    @SysConfigType\n    private String mType = SysConfigType.TYPE_GROUP;\n    private SysConfigViewModel mViewModel;\n\n    @Override\n    protected void onAuthenticated(@Nullable Bundle savedInstanceState) {\n        setContentView(R.layout.activity_sys_config);\n        setSupportActionBar(findViewById(R.id.toolbar));\n        mViewModel = new ViewModelProvider(this).get(SysConfigViewModel.class);\n        MaterialSpinner spinner = findViewById(R.id.spinner);\n        UiUtils.applyWindowInsetsAsMargin(spinner, false, false);\n        // Make spinner the first item to focus on\n        spinner.requestFocus();\n        RecyclerView recyclerView = findViewById(R.id.recycler_view);\n        recyclerView.setEmptyView(findViewById(android.R.id.empty));\n        mProgressIndicator = findViewById(R.id.progress_linear);\n        mProgressIndicator.setVisibilityAfterHide(View.GONE);\n\n        String[] sysConfigTypes = getResources().getStringArray(R.array.sys_config_names);\n        ArrayAdapter<String> intervalSpinnerAdapter = new SelectedArrayAdapter<>(this,\n                io.github.muntashirakon.ui.R.layout.auto_complete_dropdown_item_small, android.R.id.text1, sysConfigTypes);\n        spinner.setAdapter(intervalSpinnerAdapter);\n        spinner.setOnItemClickListener((parent, view, position, id) -> {\n            mProgressIndicator.show();\n            mType = sysConfigTypes[position];\n            mViewModel.loadSysConfigInfo(mType);\n        });\n\n        mAdapter = new SysConfigRecyclerAdapter(this);\n        recyclerView.setLayoutManager(UIUtils.getGridLayoutAt450Dp(this));\n        recyclerView.setAdapter(mAdapter);\n        // Observe data\n        mViewModel.getSysConfigInfoListLiveData().observe(this, sysConfigInfoList -> {\n            Optional.ofNullable(getSupportActionBar())\n                    .ifPresent(actionBar -> actionBar.setSubtitle(mType));\n            mAdapter.setList(sysConfigInfoList);\n            mProgressIndicator.hide();\n        });\n\n        mViewModel.loadSysConfigInfo(mType);\n    }\n\n    @Override\n    public boolean onOptionsItemSelected(@NonNull MenuItem item) {\n        if (item.getItemId() == android.R.id.home) {\n            finish();\n            return true;\n        }\n        return super.onOptionsItemSelected(item);\n    }\n\n    public static class SysConfigRecyclerAdapter extends RecyclerView.Adapter<SysConfigRecyclerAdapter.ViewHolder> {\n        private final List<SysConfigInfo> mList = new ArrayList<>();\n        private final SysConfigActivity mActivity;\n        private final PackageManager mPm;\n        private final int mCardColor0;\n        private final int mCardColor1;\n\n        SysConfigRecyclerAdapter(SysConfigActivity activity) {\n            mActivity = activity;\n            mPm = activity.getPackageManager();\n            mCardColor0 = ColorCodes.getListItemColor0(activity);\n            mCardColor1 = ColorCodes.getListItemColor1(activity);\n        }\n\n        @NonNull\n        @Override\n        public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {\n            View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_sys_config, parent, false);\n            return new ViewHolder(view);\n        }\n\n        void setList(List<SysConfigInfo> list) {\n            AdapterUtils.notifyDataSetChanged(this, mList, list);\n        }\n\n        @Override\n        public void onBindViewHolder(@NonNull ViewHolder holder, int position) {\n            holder.icon.setImageDrawable(null);\n\n            holder.itemView.setCardBackgroundColor(position % 2 == 0 ? mCardColor1 : mCardColor0);\n\n            SysConfigInfo info = mList.get(position);\n            if (info.isPackage) {\n                holder.icon.setVisibility(View.VISIBLE);\n                try {\n                    ApplicationInfo applicationInfo = mPm.getApplicationInfo(info.name, 0);\n                    holder.title.setText(applicationInfo.loadLabel(mPm));\n                    holder.packageName.setVisibility(View.VISIBLE);\n                    holder.packageName.setText(info.name);\n                    // Load icon\n                    holder.icon.setTag(applicationInfo.packageName);\n                    ImageLoader.getInstance().displayImage(applicationInfo.packageName, applicationInfo, holder.icon);\n                } catch (PackageManager.NameNotFoundException e) {\n                    holder.title.setText(info.name);\n                    holder.packageName.setVisibility(View.GONE);\n                    holder.icon.setTag(info.name);\n                    ImageLoader.getInstance().displayImage(info.name, null, holder.icon);\n                }\n                holder.icon.setOnClickListener(v -> {\n                    Intent appDetailsIntent = AppDetailsActivity.getIntent(mActivity, info.name, 0);\n                    mActivity.startActivity(appDetailsIntent);\n                });\n            } else {\n                holder.icon.setVisibility(View.GONE);\n                holder.title.setText(info.name);\n                holder.packageName.setVisibility(View.GONE);\n            }\n            setSubtitle(holder, info);\n        }\n\n        @Override\n        public int getItemCount() {\n            return mList.size();\n        }\n\n        private void setSubtitle(@NonNull ViewHolder holder, @NonNull SysConfigInfo info) {\n            Context context = holder.itemView.getContext();\n            SpannableStringBuilder sb = new SpannableStringBuilder();\n            switch (info.type) {\n                case SysConfigType.TYPE_GROUP:\n                case SysConfigType.TYPE_UNAVAILABLE_FEATURE:\n                case SysConfigType.TYPE_ALLOW_IN_POWER_SAVE_EXCEPT_IDLE:\n                case SysConfigType.TYPE_ALLOW_IN_POWER_SAVE:\n                case SysConfigType.TYPE_ALLOW_IN_DATA_USAGE_SAVE:\n                case SysConfigType.TYPE_ALLOW_UNTHROTTLED_LOCATION:\n                case SysConfigType.TYPE_ALLOW_IGNORE_LOCATION_SETTINGS:\n                case SysConfigType.TYPE_ALLOW_IMPLICIT_BROADCAST:\n                case SysConfigType.TYPE_APP_LINK:\n                case SysConfigType.TYPE_SYSTEM_USER_WHITELISTED_APP:\n                case SysConfigType.TYPE_SYSTEM_USER_BLACKLISTED_APP:\n                case SysConfigType.TYPE_DISABLED_UNTIL_USED_PREINSTALLED_CARRIER_APP:\n                case SysConfigType.TYPE_HIDDEN_API_WHITELISTED_APP:\n                case SysConfigType.TYPE_APP_DATA_ISOLATION_WHITELISTED_APP:\n                case SysConfigType.TYPE_BUGREPORT_WHITELISTED:\n                case SysConfigType.TYPE_ROLLBACK_WHITELISTED_APP:\n                case SysConfigType.TYPE_WHITELISTED_STAGED_INSTALLER:\n                    break;\n                case SysConfigType.TYPE_PERMISSION: {\n                    // TODO: Display permission info\n                    sb.append(getStyledKeyValue(context, \"GID\", Arrays.toString(info.gids))).append(\"\\n\");\n                    sb.append(getStyledKeyValue(context, \"Per user\", String.valueOf(info.perUser)));\n                }\n                break;\n                case SysConfigType.TYPE_ASSIGN_PERMISSION: {\n                    // TODO: Display permission info\n                    sb.append(getStyledKeyValue(context, \"Permissions\", \"\"));\n                    if (info.permissions.length == 0) {\n                        sb.append(\" None\");\n                    }\n                    for (String permissionName : info.permissions) {\n                        sb.append(\"\\n- \").append(permissionName);\n                    }\n                }\n                break;\n                case SysConfigType.TYPE_SPLIT_PERMISSION: {\n                    sb.append(getStyledKeyValue(context, \"Target SDK\", String.valueOf(info.targetSdk))).append(\"\\n\");\n                    sb.append(getStyledKeyValue(context, \"Permissions\", \"\"));\n                    if (info.permissions.length == 0) {\n                        sb.append(\" None\");\n                    }\n                    for (String permissionName : info.permissions) {\n                        sb.append(\"\\n- \").append(permissionName);\n                    }\n                }\n                break;\n                case SysConfigType.TYPE_LIBRARY: {\n                    sb.append(getStyledKeyValue(context, \"Filename\", info.filename)).append(\"\\n\");\n                    sb.append(getStyledKeyValue(context, \"Dependencies\", \"\"));\n                    if (info.dependencies.length == 0) {\n                        sb.append(\" None\");\n                    }\n                    for (String dependencyName : info.dependencies) {\n                        sb.append(\"\\n- \").append(dependencyName);\n                    }\n                }\n                break;\n                case SysConfigType.TYPE_FEATURE: {\n                    if (info.version > 0) {\n                        sb.append(getStyledKeyValue(context, \"Version\", String.valueOf(info.version)));\n                    }\n                }\n                break;\n                case SysConfigType.TYPE_DEFAULT_ENABLED_VR_APP: {\n                    sb.append(getStyledKeyValue(context, \"Components\", Arrays.toString(info.classNames)));\n                    if (info.classNames.length == 0) {\n                        sb.append(\" None\");\n                    }\n                    for (String className : info.classNames) {\n                        sb.append(\"\\n- \").append(className);\n                    }\n                }\n                break;\n                case SysConfigType.TYPE_COMPONENT_OVERRIDE: {\n                    sb.append(getStyledKeyValue(context, \"Components\", \"\"));\n                    if (info.classNames.length == 0) {\n                        sb.append(\" None\");\n                    }\n                    for (int i = 0; i < info.classNames.length; ++i) {\n                        sb.append(\"\\n- \")\n                                .append(info.classNames[i])\n                                .append(\" = \")\n                                .append(info.whitelist[i] ? \"Enabled\" : \"Disabled\");\n                    }\n                }\n                break;\n                case SysConfigType.TYPE_BACKUP_TRANSPORT_WHITELISTED_SERVICE: {\n                    sb.append(getStyledKeyValue(context, \"Services\", \"\"));\n                    if (info.classNames.length == 0) {\n                        sb.append(\" None\");\n                    }\n                    for (String className : info.classNames) {\n                        sb.append(\"\\n- \").append(className);\n                    }\n                }\n                break;\n                case SysConfigType.TYPE_DISABLED_UNTIL_USED_PREINSTALLED_CARRIER_ASSOCIATED_APP: {\n                    sb.append(getStyledKeyValue(context, \"Associated packages\", \"\"));\n                    if (info.packages.length == 0) {\n                        sb.append(\" None\");\n                    }\n                    for (int i = 0; i < info.packages.length; ++i) {\n                        // TODO Display package labels\n                        sb.append(\"\\n- \")\n                                .append(\"Package\")\n                                .append(LangUtils.getSeparatorString())\n                                .append(info.packages[i])\n                                .append(\", Target SDK\")\n                                .append(LangUtils.getSeparatorString())\n                                .append(String.valueOf(info.targetSdks[i]));\n                    }\n                }\n                break;\n                case SysConfigType.TYPE_PRIVAPP_PERMISSIONS:\n                case SysConfigType.TYPE_OEM_PERMISSIONS: {\n                    sb.append(getStyledKeyValue(context, \"Permissions\", \"\"));\n                    if (info.permissions.length == 0) {\n                        sb.append(\" None\");\n                    }\n                    for (int i = 0; i < info.permissions.length; ++i) {\n                        sb.append(\"\\n- \")\n                                .append(info.permissions[i])\n                                .append(\" = \")\n                                .append(info.whitelist[i] ? \"Granted\" : \"Revoked\");\n                    }\n                }\n                break;\n                case SysConfigType.TYPE_ALLOW_ASSOCIATION: {\n                    sb.append(getStyledKeyValue(context, \"Associated packages\", \"\"));\n                    if (info.packages.length == 0) {\n                        sb.append(\" None\");\n                    }\n                    for (String packageName : info.packages) {\n                        // TODO Display package labels\n                        sb.append(\"\\n- \").append(packageName);\n                    }\n                }\n                break;\n                case SysConfigType.TYPE_INSTALL_IN_USER_TYPE: {\n                    sb.append(getStyledKeyValue(context, \"User types\", \"\"));\n                    if (info.userTypes.length == 0) {\n                        sb.append(\" None\");\n                    }\n                    for (int i = 0; i < info.userTypes.length; ++i) {\n                        sb.append(\"\\n- \")\n                                .append(info.userTypes[i])\n                                .append(\" = \")\n                                .append(info.whitelist[i] ? \"Whitelisted\" : \"Blacklisted\");\n                    }\n                }\n                break;\n                case SysConfigType.TYPE_NAMED_ACTOR: {\n                    for (int i = 0; i < info.actors.length; ++i) {\n                        sb.append(\"Actor\")\n                                .append(LangUtils.getSeparatorString())\n                                .append(info.actors[i])\n                                .append(\", Package\")\n                                .append(LangUtils.getSeparatorString())\n                                .append(info.packages[i]).append(\"\\n\");\n                    }\n                }\n                break;\n            }\n            if (sb.length() > 0) {\n                holder.subtitle.setVisibility(View.VISIBLE);\n                holder.subtitle.setText(sb);\n            } else holder.subtitle.setVisibility(View.GONE);\n        }\n\n        public static class ViewHolder extends RecyclerView.ViewHolder {\n            public MaterialCardView itemView;\n            public TextView title;\n            public TextView packageName;\n            public TextView subtitle;\n            public ImageView icon;\n\n            public ViewHolder(@NonNull View itemView) {\n                super(itemView);\n                this.itemView = (MaterialCardView) itemView;\n                title = itemView.findViewById(android.R.id.title);\n                packageName = itemView.findViewById(R.id.package_name);\n                subtitle = itemView.findViewById(android.R.id.summary);\n                icon = itemView.findViewById(android.R.id.icon);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/sysconfig/SysConfigInfo.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.sysconfig;\n\nimport androidx.annotation.NonNull;\n\nclass SysConfigInfo {\n    @SysConfigType\n    final String type;\n    /**\n     * Name of the config. The value is usually a package name but could be other name as well, such as\n     * <ul>\n     * <li> gid for {@link SysConfigType#TYPE_GROUP}\n     * <li> permission name for {@link SysConfigType#TYPE_PERMISSION} and {@link SysConfigType#TYPE_SPLIT_PERMISSION}\n     * <li> uid for {@link SysConfigType#TYPE_ASSIGN_PERMISSION}\n     * <li> library name for {@link SysConfigType#TYPE_LIBRARY}\n     * <li> feature name for {@link SysConfigType#TYPE_FEATURE} and {@link SysConfigType#TYPE_UNAVAILABLE_FEATURE}\n     * <li> action name for {@link SysConfigType#TYPE_ALLOW_IMPLICIT_BROADCAST}\n     * <li> namespace for {@link SysConfigType#TYPE_NAMED_ACTOR}\n     *\n     * @see #isPackage\n     */\n    @NonNull\n    final String name;\n    final boolean isPackage;\n\n    /**\n     * Actors for a certain namespace, applicable for {@link SysConfigType#TYPE_NAMED_ACTOR}.\n     *\n     * @see #packages\n     */\n    String[] actors;\n    /**\n     * Component names of a package, applicable for {@link SysConfigType#TYPE_COMPONENT_OVERRIDE},\n     * {@link SysConfigType#TYPE_DEFAULT_ENABLED_VR_APP} and\n     * {@link SysConfigType#TYPE_BACKUP_TRANSPORT_WHITELISTED_SERVICE}.\n     *\n     * @see #whitelist\n     */\n    String[] classNames;\n    /**\n     * Denotes enable/disable state for {@link SysConfigType#TYPE_COMPONENT_OVERRIDE}, grant/revoke\n     * for {@link SysConfigType#TYPE_PRIVAPP_PERMISSIONS} and {@link SysConfigType#TYPE_OEM_PERMISSIONS},\n     * and whitelist/blacklist {@link SysConfigType#TYPE_INSTALL_IN_USER_TYPE}.\n     *\n     * @see #classNames\n     * @see #permissions\n     * @see #userTypes\n     */\n    boolean[] whitelist;\n    /**\n     * Packages associated with a carrier package (for {@link SysConfigType#TYPE_DISABLED_UNTIL_USED_PREINSTALLED_CARRIER_ASSOCIATED_APP}),\n     * packages associate with certain actors under a namespace (for {@link SysConfigType#TYPE_NAMED_ACTOR})\n     * or packages associated with another package (for {@link SysConfigType#TYPE_ALLOW_ASSOCIATION}).\n     *\n     * @see #actors\n     * @see #targetSdks\n     */\n    String[] packages;\n    /**\n     * Library filename, applicable for {@link SysConfigType#TYPE_LIBRARY}.\n     *\n     * @see #dependencies\n     */\n    String filename;\n    /**\n     * FIXME(20/10/20): Find documentation regarding GIDs\n     * Applicable for {@link SysConfigType#TYPE_PERMISSION}.\n     *\n     * @see #perUser\n     */\n    int[] gids;\n    /**\n     * Permissions belonging certain uid for {@link SysConfigType#TYPE_ASSIGN_PERMISSION}, split\n     * permissions for {@link SysConfigType#TYPE_SPLIT_PERMISSION}, and permissions for\n     * {@link SysConfigType#TYPE_PRIVAPP_PERMISSIONS} and {@link SysConfigType#TYPE_OEM_PERMISSIONS}.\n     *\n     * @see #whitelist\n     * @see #targetSdk\n     */\n    String[] permissions;\n    /**\n     * Library dependencies, applicable for {@link SysConfigType#TYPE_LIBRARY}.\n     *\n     * @see #filename\n     */\n    String[] dependencies;\n    /**\n     * User types for certain package, applicable for {@link SysConfigType#TYPE_INSTALL_IN_USER_TYPE}\n     *\n     * @see #whitelist\n     */\n    String[] userTypes;\n    /**\n     * FIXME(20/10/20): Find documentation regarding perUser\n     * Applicable for {@link SysConfigType#TYPE_PERMISSION}.\n     *\n     * @see #gids\n     */\n    boolean perUser;\n    /**\n     * Target SDK for {@link SysConfigType#TYPE_SPLIT_PERMISSION}.\n     *\n     * @see #permissions\n     */\n    int targetSdk;\n    /**\n     * Target SDKs for {@link #permissions}. Applicable for\n     * {@link SysConfigType#TYPE_DISABLED_UNTIL_USED_PREINSTALLED_CARRIER_ASSOCIATED_APP}.\n     *\n     * @see #permissions\n     */\n    int[] targetSdks;\n    /**\n     * Feature version (Android O or later), applicable for {@link SysConfigType#TYPE_FEATURE}.\n     */\n    int version;\n\n    SysConfigInfo(@SysConfigType String type, @NonNull String name, boolean isPackage) {\n        this.type = type;\n        this.name = name;\n        this.isPackage = isPackage;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/sysconfig/SysConfigType.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.sysconfig;\n\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\n\nimport androidx.annotation.StringDef;\n\n@StringDef(value = {\n        SysConfigType.TYPE_GROUP,\n        SysConfigType.TYPE_PERMISSION,\n        SysConfigType.TYPE_ASSIGN_PERMISSION,\n        SysConfigType.TYPE_SPLIT_PERMISSION,\n        SysConfigType.TYPE_LIBRARY,\n        SysConfigType.TYPE_FEATURE,\n        SysConfigType.TYPE_UNAVAILABLE_FEATURE,\n        SysConfigType.TYPE_ALLOW_IN_POWER_SAVE_EXCEPT_IDLE,\n        SysConfigType.TYPE_ALLOW_IN_POWER_SAVE,\n        SysConfigType.TYPE_ALLOW_IN_DATA_USAGE_SAVE,\n        SysConfigType.TYPE_ALLOW_UNTHROTTLED_LOCATION,\n        SysConfigType.TYPE_ALLOW_IGNORE_LOCATION_SETTINGS,\n        SysConfigType.TYPE_ALLOW_IMPLICIT_BROADCAST,\n        SysConfigType.TYPE_APP_LINK,\n        SysConfigType.TYPE_SYSTEM_USER_WHITELISTED_APP,\n        SysConfigType.TYPE_SYSTEM_USER_BLACKLISTED_APP,\n        SysConfigType.TYPE_DEFAULT_ENABLED_VR_APP,\n        SysConfigType.TYPE_COMPONENT_OVERRIDE,\n        SysConfigType.TYPE_BACKUP_TRANSPORT_WHITELISTED_SERVICE,\n        SysConfigType.TYPE_DISABLED_UNTIL_USED_PREINSTALLED_CARRIER_ASSOCIATED_APP,\n        SysConfigType.TYPE_DISABLED_UNTIL_USED_PREINSTALLED_CARRIER_APP,\n        SysConfigType.TYPE_PRIVAPP_PERMISSIONS,\n        SysConfigType.TYPE_OEM_PERMISSIONS,\n        SysConfigType.TYPE_HIDDEN_API_WHITELISTED_APP,\n        SysConfigType.TYPE_ALLOW_ASSOCIATION,\n        SysConfigType.TYPE_APP_DATA_ISOLATION_WHITELISTED_APP,\n        SysConfigType.TYPE_BUGREPORT_WHITELISTED,\n        SysConfigType.TYPE_INSTALL_IN_USER_TYPE,\n        SysConfigType.TYPE_NAMED_ACTOR,\n        SysConfigType.TYPE_ROLLBACK_WHITELISTED_APP,\n        SysConfigType.TYPE_WHITELISTED_STAGED_INSTALLER,\n})\n@Retention(RetentionPolicy.SOURCE)\n@interface SysConfigType {\n    String TYPE_GROUP = \"group\";\n    String TYPE_PERMISSION = \"permission\";\n    String TYPE_ASSIGN_PERMISSION = \"assign-permission\";\n    String TYPE_SPLIT_PERMISSION = \"split-permission\";\n    String TYPE_LIBRARY = \"library\";\n    String TYPE_FEATURE = \"feature\";  // available-feature\n    String TYPE_UNAVAILABLE_FEATURE = \"unavailable-feature\";\n    String TYPE_ALLOW_IN_POWER_SAVE_EXCEPT_IDLE = \"allow-in-power-save-except-idle\";\n    String TYPE_ALLOW_IN_POWER_SAVE = \"allow-in-power-save\";\n    String TYPE_ALLOW_IN_DATA_USAGE_SAVE = \"allow-in-data-usage-save\";\n    String TYPE_ALLOW_UNTHROTTLED_LOCATION = \"allow-unthrottled-location\";\n    String TYPE_ALLOW_IGNORE_LOCATION_SETTINGS = \"allow-ignore-location-settings\";\n    String TYPE_ALLOW_IMPLICIT_BROADCAST = \"allow-implicit-broadcast\";\n    String TYPE_APP_LINK = \"app-link\";\n    String TYPE_SYSTEM_USER_WHITELISTED_APP = \"system-user-whitelisted-app\";\n    String TYPE_SYSTEM_USER_BLACKLISTED_APP = \"system-user-blacklisted-app\";\n    String TYPE_DEFAULT_ENABLED_VR_APP = \"default-enabled-vr-app\";\n    String TYPE_COMPONENT_OVERRIDE = \"component-override\";\n    String TYPE_BACKUP_TRANSPORT_WHITELISTED_SERVICE = \"backup-transport-whitelisted-service\";\n    String TYPE_DISABLED_UNTIL_USED_PREINSTALLED_CARRIER_ASSOCIATED_APP = \"disabled-until-used-preinstalled-carrier-associated-app\";\n    String TYPE_DISABLED_UNTIL_USED_PREINSTALLED_CARRIER_APP = \"disabled-until-used-preinstalled-carrier-app\";\n    String TYPE_PRIVAPP_PERMISSIONS = \"privapp-permissions\";\n    String TYPE_OEM_PERMISSIONS = \"oem-permissions\";\n    String TYPE_HIDDEN_API_WHITELISTED_APP = \"hidden-api-whitelisted-app\";\n    String TYPE_ALLOW_ASSOCIATION = \"allow-association\";\n    String TYPE_APP_DATA_ISOLATION_WHITELISTED_APP = \"app-data-isolation-whitelisted-app\";\n    String TYPE_BUGREPORT_WHITELISTED = \"bugreport-whitelisted\";\n    String TYPE_INSTALL_IN_USER_TYPE = \"install-in-user-type\";\n    String TYPE_NAMED_ACTOR = \"named-actor\";\n    String TYPE_ROLLBACK_WHITELISTED_APP = \"rollback-whitelisted-app\";\n    String TYPE_WHITELISTED_STAGED_INSTALLER = \"whitelisted-staged-installer\";\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/sysconfig/SysConfigViewModel.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.sysconfig;\n\nimport android.app.Application;\n\nimport androidx.annotation.AnyThread;\nimport androidx.annotation.NonNull;\nimport androidx.lifecycle.AndroidViewModel;\nimport androidx.lifecycle.LiveData;\nimport androidx.lifecycle.MutableLiveData;\n\nimport java.util.Collections;\nimport java.util.List;\n\nimport io.github.muntashirakon.AppManager.utils.MultithreadedExecutor;\n\npublic class SysConfigViewModel extends AndroidViewModel {\n    private final MutableLiveData<List<SysConfigInfo>> mSysConfigInfoListLiveData = new MutableLiveData<>();\n    private final MultithreadedExecutor mExecutor = MultithreadedExecutor.getNewInstance();\n\n    public SysConfigViewModel(@NonNull Application application) {\n        super(application);\n    }\n\n    @Override\n    protected void onCleared() {\n        super.onCleared();\n        mExecutor.shutdown();\n    }\n\n    public LiveData<List<SysConfigInfo>> getSysConfigInfoListLiveData() {\n        return mSysConfigInfoListLiveData;\n    }\n\n    @AnyThread\n    public void loadSysConfigInfo(@SysConfigType String sysConfigType) {\n        mExecutor.submit(() -> {\n            List<SysConfigInfo> sysConfigInfoList = SysConfigWrapper.getSysConfigs(sysConfigType);\n            Collections.sort(sysConfigInfoList, (o1, o2) -> o1.name.compareToIgnoreCase(o2.name));\n            mSysConfigInfoListLiveData.postValue(sysConfigInfoList);\n        });\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/sysconfig/SysConfigWrapper.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.sysconfig;\n\nimport android.content.ComponentName;\nimport android.content.pm.FeatureInfo;\nimport android.os.Build;\nimport android.util.ArrayMap;\nimport android.util.SparseArray;\n\nimport java.util.ArrayList;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.WorkerThread;\n\n@WorkerThread\nclass SysConfigWrapper {\n    @NonNull\n    static List<SysConfigInfo> getSysConfigs(@NonNull @SysConfigType String type) {\n        List<SysConfigInfo> list = new ArrayList<>();\n        SystemConfig config = SystemConfig.getInstance();\n        switch (type) {\n            case SysConfigType.TYPE_GROUP: {\n                int[] globalGids = config.getGlobalGids();\n                if (globalGids != null) {\n                    for (int gid : globalGids) {\n                        list.add(new SysConfigInfo(SysConfigType.TYPE_GROUP, String.valueOf(gid), false));\n                    }\n                }\n            }\n            break;\n            case SysConfigType.TYPE_PERMISSION: {\n                Map<String, SystemConfig.PermissionEntry> permissionEntries = config.getPermissions();\n                SystemConfig.PermissionEntry entry;\n                for (String permission : permissionEntries.keySet()) {\n                    entry = permissionEntries.get(permission);\n                    if (entry == null) continue;\n                    SysConfigInfo info = new SysConfigInfo(SysConfigType.TYPE_PERMISSION, permission, false);\n                    info.gids = entry.gids;\n                    info.perUser = entry.perUser;\n                    list.add(info);\n                }\n            }\n            break;\n            case SysConfigType.TYPE_ASSIGN_PERMISSION: {\n                SparseArray<Set<String>> uidAndPermissions = config.getSystemPermissions();\n                Set<String> entry;\n                for (int i = 0; i < uidAndPermissions.size(); ++i) {\n                    int uid = uidAndPermissions.keyAt(i);\n                    entry = uidAndPermissions.valueAt(i);\n                    SysConfigInfo info = new SysConfigInfo(SysConfigType.TYPE_ASSIGN_PERMISSION, String.valueOf(uid), false);\n                    info.permissions = entry.toArray(new String[0]);\n                    list.add(info);\n                }\n            }\n            break;\n            case SysConfigType.TYPE_SPLIT_PERMISSION: {\n                List<SystemConfig.SplitPermissionInfo> permissionInfoList = config.getSplitPermissions();\n                for (SystemConfig.SplitPermissionInfo permissionInfo : permissionInfoList) {\n                    SysConfigInfo info = new SysConfigInfo(SysConfigType.TYPE_SPLIT_PERMISSION, permissionInfo.getSplitPermission(), false);\n                    info.permissions = permissionInfo.getNewPermissions().toArray(new String[0]);\n                    info.targetSdk = permissionInfo.getTargetSdk();\n                    list.add(info);\n                }\n            }\n            break;\n            case SysConfigType.TYPE_LIBRARY: {\n                Map<String, SystemConfig.SharedLibraryEntry> sharedLibraries = config.getSharedLibraries();\n                SystemConfig.SharedLibraryEntry entry;\n                for (String libName : sharedLibraries.keySet()) {\n                    entry = sharedLibraries.get(libName);\n                    if (entry == null) continue;\n                    SysConfigInfo info = new SysConfigInfo(SysConfigType.TYPE_LIBRARY, libName, false);\n                    info.filename = entry.filename;\n                    info.dependencies = entry.dependencies;\n                    list.add(info);\n                }\n            }\n            break;\n            case SysConfigType.TYPE_FEATURE: {\n                Map<String, FeatureInfo> features = config.getAvailableFeatures();\n                FeatureInfo featureInfo;\n                for (String feature : features.keySet()) {\n                    featureInfo = features.get(feature);\n                    if (featureInfo == null) continue;\n                    SysConfigInfo info = new SysConfigInfo(SysConfigType.TYPE_FEATURE, feature, false);\n                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {\n                        info.version = featureInfo.version;\n                    }\n                    list.add(info);\n                }\n            }\n            break;\n            case SysConfigType.TYPE_UNAVAILABLE_FEATURE:\n                for (String feature : config.mUnavailableFeatures) {\n                    list.add(new SysConfigInfo(SysConfigType.TYPE_UNAVAILABLE_FEATURE, feature, false));\n                }\n                break;\n            case SysConfigType.TYPE_ALLOW_IN_POWER_SAVE_EXCEPT_IDLE:\n                for (String packageName : config.getAllowInPowerSaveExceptIdle()) {\n                    list.add(new SysConfigInfo(SysConfigType.TYPE_ALLOW_IN_POWER_SAVE_EXCEPT_IDLE, packageName, true));\n                }\n                break;\n            case SysConfigType.TYPE_ALLOW_IN_POWER_SAVE:\n                for (String packageName : config.getAllowInPowerSave()) {\n                    list.add(new SysConfigInfo(SysConfigType.TYPE_ALLOW_IN_POWER_SAVE, packageName, true));\n                }\n                break;\n            case SysConfigType.TYPE_ALLOW_IN_DATA_USAGE_SAVE:\n                for (String packageName : config.getAllowInDataUsageSave()) {\n                    list.add(new SysConfigInfo(SysConfigType.TYPE_ALLOW_IN_DATA_USAGE_SAVE, packageName, true));\n                }\n                break;\n            case SysConfigType.TYPE_ALLOW_UNTHROTTLED_LOCATION:\n                for (String packageName : config.getAllowUnthrottledLocation()) {\n                    list.add(new SysConfigInfo(SysConfigType.TYPE_ALLOW_UNTHROTTLED_LOCATION, packageName, true));\n                }\n                break;\n            case SysConfigType.TYPE_ALLOW_IGNORE_LOCATION_SETTINGS:\n                for (String packageName : config.getAllowIgnoreLocationSettings()) {\n                    list.add(new SysConfigInfo(SysConfigType.TYPE_ALLOW_IGNORE_LOCATION_SETTINGS, packageName, true));\n                }\n                break;\n            case SysConfigType.TYPE_ALLOW_IMPLICIT_BROADCAST: {\n                for (String action : config.getAllowImplicitBroadcasts()) {\n                    list.add(new SysConfigInfo(SysConfigType.TYPE_ALLOW_IMPLICIT_BROADCAST, action, false));\n                }\n            }\n            break;\n            case SysConfigType.TYPE_APP_LINK:\n                for (String packageName : config.getLinkedApps()) {\n                    list.add(new SysConfigInfo(SysConfigType.TYPE_APP_LINK, packageName, true));\n                }\n                break;\n            case SysConfigType.TYPE_SYSTEM_USER_WHITELISTED_APP:\n                for (String packageName : config.getSystemUserWhitelistedApps()) {\n                    list.add(new SysConfigInfo(SysConfigType.TYPE_SYSTEM_USER_WHITELISTED_APP, packageName, true));\n                }\n                break;\n            case SysConfigType.TYPE_SYSTEM_USER_BLACKLISTED_APP:\n                for (String packageName : config.getSystemUserBlacklistedApps()) {\n                    list.add(new SysConfigInfo(SysConfigType.TYPE_SYSTEM_USER_BLACKLISTED_APP, packageName, true));\n                }\n                break;\n            case SysConfigType.TYPE_DEFAULT_ENABLED_VR_APP: {\n                // Get components per package\n                ArrayMap<String, Set<String>> packageComponentsMap = new ArrayMap<>();\n                Set<String> components;\n                for (ComponentName info : config.getDefaultVrComponents()) {\n                    components = packageComponentsMap.get(info.getPackageName());\n                    if (components == null) {\n                        components = new HashSet<>();\n                        packageComponentsMap.put(info.getPackageName(), components);\n                    }\n                    components.add(info.getClassName());\n                }\n                // Add them to the list\n                for (String packageName : packageComponentsMap.keySet()) {\n                    components = packageComponentsMap.get(packageName);\n                    SysConfigInfo info = new SysConfigInfo(SysConfigType.TYPE_DEFAULT_ENABLED_VR_APP, packageName, true);\n                    if (components != null) info.classNames = components.toArray(new String[0]);\n                    list.add(info);\n                }\n            }\n            break;\n            case SysConfigType.TYPE_COMPONENT_OVERRIDE: {\n                Map<String, ArrayMap<String, Boolean>> packageComponentEnabledState = config.mPackageComponentEnabledState;\n                ArrayMap<String, Boolean> componentEnableState;\n                for (String packageName : packageComponentEnabledState.keySet()) {\n                    componentEnableState = packageComponentEnabledState.get(packageName);\n                    SysConfigInfo info = new SysConfigInfo(SysConfigType.TYPE_COMPONENT_OVERRIDE, packageName, true);\n                    if (componentEnableState != null) {\n                        info.classNames = new String[componentEnableState.size()];\n                        info.whitelist = new boolean[componentEnableState.size()];\n                        for (int i = 0; i < componentEnableState.size(); ++i) {\n                            info.classNames[i] = componentEnableState.keyAt(i);\n                            info.whitelist[i] = componentEnableState.valueAt(i);\n                        }\n                    }\n                    list.add(info);\n                }\n            }\n            break;\n            case SysConfigType.TYPE_BACKUP_TRANSPORT_WHITELISTED_SERVICE: {\n                // Get components per package\n                ArrayMap<String, Set<String>> packageComponentsMap = new ArrayMap<>();\n                Set<String> components;\n                for (ComponentName info : config.getBackupTransportWhitelist()) {\n                    components = packageComponentsMap.get(info.getPackageName());\n                    if (components == null) {\n                        components = new HashSet<>();\n                        packageComponentsMap.put(info.getPackageName(), components);\n                    }\n                    components.add(info.getClassName());\n                }\n                // Add them to the list\n                for (String packageName : packageComponentsMap.keySet()) {\n                    components = packageComponentsMap.get(packageName);\n                    SysConfigInfo info = new SysConfigInfo(SysConfigType.TYPE_BACKUP_TRANSPORT_WHITELISTED_SERVICE, packageName, true);\n                    if (components != null) info.classNames = components.toArray(new String[0]);\n                    list.add(info);\n                }\n            }\n            break;\n            case SysConfigType.TYPE_DISABLED_UNTIL_USED_PREINSTALLED_CARRIER_ASSOCIATED_APP: {\n                ArrayMap<String, List<SystemConfig.CarrierAssociatedAppEntry>> packages = config.getDisabledUntilUsedPreinstalledCarrierAssociatedApps();\n                List<SystemConfig.CarrierAssociatedAppEntry> entries;\n                SystemConfig.CarrierAssociatedAppEntry entry;\n                for (String packageName : packages.keySet()) {\n                    entries = packages.get(packageName);\n                    SysConfigInfo info = new SysConfigInfo(SysConfigType.TYPE_DISABLED_UNTIL_USED_PREINSTALLED_CARRIER_ASSOCIATED_APP, packageName, true);\n                    if (entries != null) {\n                        info.packages = new String[entries.size()];\n                        info.targetSdks = new int[entries.size()];\n                        for (int i = 0; i < entries.size(); ++i) {\n                            entry = entries.get(i);\n                            info.packages[i] = entry.packageName;\n                            info.targetSdks[i] = entry.addedInSdk;\n                        }\n                    }\n                    list.add(info);\n                }\n            }\n            break;\n            case SysConfigType.TYPE_DISABLED_UNTIL_USED_PREINSTALLED_CARRIER_APP:\n                for (String packageName : config.getDisabledUntilUsedPreinstalledCarrierApps()) {\n                    list.add(new SysConfigInfo(SysConfigType.TYPE_DISABLED_UNTIL_USED_PREINSTALLED_CARRIER_APP, packageName, true));\n                }\n                break;\n            case SysConfigType.TYPE_PRIVAPP_PERMISSIONS: {\n                ArrayMap<String, ArrayMap<String, Boolean>> packagePermissionsMap = new ArrayMap<>();\n                convertToMap(packagePermissionsMap, config.mVendorPrivAppPermissions, config.mVendorPrivAppDenyPermissions);\n                convertToMap(packagePermissionsMap, config.mProductPrivAppPermissions, config.mProductPrivAppDenyPermissions);\n                convertToMap(packagePermissionsMap, config.mSystemExtPrivAppPermissions, config.mSystemExtPrivAppDenyPermissions);\n                convertToMap(packagePermissionsMap, config.mPrivAppPermissions, config.mPrivAppDenyPermissions);\n                // Add permissions\n                ArrayMap<String, Boolean> permissions;\n                for (String packageName : packagePermissionsMap.keySet()) {\n                    permissions = packagePermissionsMap.get(packageName);\n                    SysConfigInfo info = new SysConfigInfo(SysConfigType.TYPE_PRIVAPP_PERMISSIONS, packageName, true);\n                    if (permissions != null) {\n                        info.permissions = new String[permissions.size()];\n                        info.whitelist = new boolean[permissions.size()];\n                        for (int i = 0; i < permissions.size(); ++i) {\n                            info.permissions[i] = permissions.keyAt(i);\n                            info.whitelist[i] = permissions.valueAt(i);\n                        }\n                    }\n                    list.add(info);\n                }\n            }\n            break;\n            case SysConfigType.TYPE_OEM_PERMISSIONS: {\n                Map<String, ArrayMap<String, Boolean>> packagePermissionsMap = config.mOemPermissions;\n                ArrayMap<String, Boolean> permissions;\n                for (String packageName : packagePermissionsMap.keySet()) {\n                    permissions = packagePermissionsMap.get(packageName);\n                    SysConfigInfo info = new SysConfigInfo(SysConfigType.TYPE_OEM_PERMISSIONS, packageName, true);\n                    if (permissions != null) {\n                        info.permissions = new String[permissions.size()];\n                        info.whitelist = new boolean[permissions.size()];\n                        for (int i = 0; i < permissions.size(); ++i) {\n                            info.permissions[i] = permissions.keyAt(i);\n                            info.whitelist[i] = permissions.valueAt(i);\n                        }\n                    }\n                    list.add(info);\n                }\n            }\n            break;\n            case SysConfigType.TYPE_HIDDEN_API_WHITELISTED_APP:\n                for (String packageName : config.getHiddenApiWhitelistedApps()) {\n                    list.add(new SysConfigInfo(SysConfigType.TYPE_HIDDEN_API_WHITELISTED_APP, packageName, true));\n                }\n                break;\n            case SysConfigType.TYPE_ALLOW_ASSOCIATION: {\n                ArrayMap<String, Set<String>> associations = config.getAllowedAssociations();\n                for (int i = 0; i < associations.size(); ++i) {\n                    SysConfigInfo info = new SysConfigInfo(SysConfigType.TYPE_ALLOW_ASSOCIATION, associations.keyAt(i), true);\n                    info.packages = associations.valueAt(i).toArray(new String[0]);\n                    list.add(info);\n                }\n            }\n            break;\n            case SysConfigType.TYPE_APP_DATA_ISOLATION_WHITELISTED_APP:\n                for (String packageName : config.getAppDataIsolationWhitelistedApps()) {\n                    list.add(new SysConfigInfo(SysConfigType.TYPE_APP_DATA_ISOLATION_WHITELISTED_APP, packageName, true));\n                }\n                break;\n            case SysConfigType.TYPE_BUGREPORT_WHITELISTED:\n                for (String packageName : config.getBugreportWhitelistedPackages()) {\n                    list.add(new SysConfigInfo(SysConfigType.TYPE_BUGREPORT_WHITELISTED, packageName, true));\n                }\n                break;\n            case SysConfigType.TYPE_INSTALL_IN_USER_TYPE: {\n                ArrayMap<String, ArrayMap<String, Boolean>> packageUserTypesMap = new ArrayMap<>();\n                convertToMap(packageUserTypesMap, config.mPackageToUserTypeWhitelist, config.mPackageToUserTypeBlacklist);\n                ArrayMap<String, Boolean> userTypes;\n                for (String packageName : packageUserTypesMap.keySet()) {\n                    userTypes = packageUserTypesMap.get(packageName);\n                    SysConfigInfo info = new SysConfigInfo(SysConfigType.TYPE_INSTALL_IN_USER_TYPE, packageName, true);\n                    if (userTypes != null) {\n                        info.userTypes = new String[userTypes.size()];\n                        info.whitelist = new boolean[userTypes.size()];\n                        for (int i = 0; i < userTypes.size(); ++i) {\n                            info.userTypes[i] = userTypes.keyAt(i);\n                            info.whitelist[i] = userTypes.valueAt(i);\n                        }\n                    }\n                    list.add(info);\n                }\n            }\n            break;\n            case SysConfigType.TYPE_NAMED_ACTOR: {\n                ArrayMap<String, ArrayMap<String, String>> actorMap = config.getNamedActors();\n                ArrayMap<String, String> actors;\n                for (int i = 0; i < actorMap.size(); ++i) {\n                    SysConfigInfo info = new SysConfigInfo(SysConfigType.TYPE_NAMED_ACTOR, /* namespace */ actorMap.keyAt(i), false);\n                    actors = actorMap.valueAt(i);\n                    if (actors != null) {\n                        info.actors = new String[actors.size()];\n                        info.packages = new String[actors.size()];\n                        for (int j = 0; j < actors.size(); ++i) {\n                            info.actors[i] = actors.keyAt(i);\n                            info.packages[i] = actors.valueAt(i);\n                        }\n                    }\n                    list.add(info);\n                }\n            }\n            break;\n            case SysConfigType.TYPE_ROLLBACK_WHITELISTED_APP:\n                for (String packageName : config.getRollbackWhitelistedPackages()) {\n                    list.add(new SysConfigInfo(SysConfigType.TYPE_ROLLBACK_WHITELISTED_APP, packageName, true));\n                }\n                break;\n            case SysConfigType.TYPE_WHITELISTED_STAGED_INSTALLER:\n                for (String packageName : config.getWhitelistedStagedInstallers()) {\n                    list.add(new SysConfigInfo(SysConfigType.TYPE_WHITELISTED_STAGED_INSTALLER, packageName, true));\n                }\n                break;\n            default:\n                throw new IllegalStateException(\"Unexpected value: \" + type);\n        }\n        return list;\n    }\n\n    private static void convertToMap(final ArrayMap<String, ArrayMap<String, Boolean>> packagePermissionsMap,\n                                     @NonNull ArrayMap<String, Set<String>> grantMap,\n                                     @NonNull ArrayMap<String, Set<String>> denyMap) {\n        ArrayMap<String, Boolean> perms;\n        String packageName;\n        for (int i = 0; i < grantMap.size(); ++i) {\n            packageName = grantMap.keyAt(i);\n            perms = packagePermissionsMap.get(packageName);\n            if (perms == null) {\n                perms = new ArrayMap<>();\n                packagePermissionsMap.put(packageName, perms);\n            }\n            for (String permission : grantMap.valueAt(i)) {\n                perms.put(permission, true);\n            }\n        }\n        for (int i = 0; i < denyMap.size(); ++i) {\n            packageName = denyMap.keyAt(i);\n            perms = packagePermissionsMap.get(packageName);\n            if (perms == null) {\n                perms = new ArrayMap<>();\n                packagePermissionsMap.put(packageName, perms);\n            }\n            for (String permission : denyMap.valueAt(i)) {\n                perms.put(permission, false);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/sysconfig/SystemConfig.java",
    "content": "// SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.sysconfig;\n\nimport android.content.ComponentName;\nimport android.content.pm.FeatureInfo;\nimport android.content.pm.PackageManager;\nimport android.os.Build;\nimport android.os.Environment;\nimport android.os.Process;\nimport android.text.TextUtils;\nimport android.util.ArrayMap;\nimport android.util.SparseArray;\nimport android.util.Xml;\n\nimport androidx.annotation.IntRange;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.WorkerThread;\n\nimport org.xmlpull.v1.XmlPullParser;\nimport org.xmlpull.v1.XmlPullParserException;\n\nimport java.io.IOException;\nimport java.io.StringReader;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\n\nimport io.github.muntashirakon.AppManager.logs.Log;\nimport io.github.muntashirakon.AppManager.misc.OsEnvironment;\nimport io.github.muntashirakon.AppManager.misc.SystemProperties;\nimport io.github.muntashirakon.AppManager.utils.ArrayUtils;\nimport io.github.muntashirakon.AppManager.utils.TextUtilsCompat;\nimport io.github.muntashirakon.compat.xml.XmlUtils;\nimport io.github.muntashirakon.io.IoUtils;\nimport io.github.muntashirakon.io.Path;\nimport io.github.muntashirakon.io.Paths;\n\n/**\n * Loads global system configuration info.\n * Note: Initializing this class hits the disk and is slow.  This class should generally only be\n * accessed by the system_server process.\n */\n// Source: https://cs.android.com/android/_/android/platform/frameworks/base/+/9c0d523bc0b1ac3ebba92acb7e5d9675aff08aef:core/java/com/android/server/SystemConfig.java;l=36;bpv=1;bpt=0;drc=1172ffa7c261a499132fb59e18c2f972b1f57f45\npublic class SystemConfig {\n    static final String TAG = \"SystemConfig\";\n\n    static SystemConfig sInstance;\n\n    // permission flag, determines which types of configuration are allowed to be read\n    private static final int ALLOW_FEATURES = 0x01;\n    private static final int ALLOW_LIBS = 0x02;\n    private static final int ALLOW_PERMISSIONS = 0x04;\n    private static final int ALLOW_APP_CONFIGS = 0x08;\n    private static final int ALLOW_PRIVAPP_PERMISSIONS = 0x10;\n    private static final int ALLOW_OEM_PERMISSIONS = 0x20;\n    private static final int ALLOW_HIDDENAPI_WHITELISTING = 0x40;\n    private static final int ALLOW_ASSOCIATIONS = 0x80;\n    private static final int ALLOW_ALL = ~0;\n\n    // property for runtime configuration differentiation\n    private static final String SKU_PROPERTY = \"ro.boot.product.hardware.sku\";\n\n    // property for runtime configuration differentiation in vendor\n    private static final String VENDOR_SKU_PROPERTY = \"ro.boot.product.vendor.sku\";\n\n    // Group-ids that are given to all packages as read from etc/permissions/*.xml.\n    int[] mGlobalGids;\n\n    // These are the built-in uid -> permission mappings that were read from the\n    // system configuration files.\n    final SparseArray<Set<String>> mSystemPermissions = new SparseArray<>();\n\n    /**\n     * A permission that was added in a previous API level might have split into several\n     * permissions. This object describes one such split.\n     */\n    // Source: https://cs.android.com/android/_/android/platform/frameworks/base/+/9c0d523bc0b1ac3ebba92acb7e5d9675aff08aef:core/java/android/content/pm/permission/SplitPermissionInfoParcelable.java\n    public static final class SplitPermissionInfo {\n\n        /**\n         * The permission that is split.\n         */\n        @NonNull\n        private final String mSplitPermission;\n\n        /**\n         * The permissions that are added.\n         */\n        @NonNull\n        private final List<String> mNewPermissions;\n\n        /**\n         * The target API level when the permission was split.\n         */\n        @IntRange(from = 0)\n        private final int mTargetSdk;\n\n        /**\n         * Get the permission that is split.\n         */\n        public @NonNull String getSplitPermission() {\n            return mSplitPermission;\n        }\n\n        /**\n         * Get the permissions that are added.\n         */\n        public @NonNull List<String> getNewPermissions() {\n            return mNewPermissions;\n        }\n\n        /**\n         * Get the target API level when the permission was split.\n         */\n        public int getTargetSdk() {\n            return mTargetSdk;\n        }\n\n        /**\n         * Constructs a split permission.\n         *\n         * @param splitPerm old permission that will be split\n         * @param newPerms list of new permissions that {@code rootPerm} will be split into\n         * @param targetSdk apps targetting SDK versions below this will have {@code rootPerm}\n         * split into {@code newPerms}\n         */\n        public SplitPermissionInfo(@NonNull String splitPerm, @NonNull List<String> newPerms,\n                                   int targetSdk) {\n            mSplitPermission = splitPerm;\n            mNewPermissions = newPerms;\n            mTargetSdk = targetSdk;\n        }\n    }\n\n    final ArrayList<SplitPermissionInfo> mSplitPermissions = new ArrayList<>();\n\n    public static final class SharedLibraryEntry {\n        public final String name;\n        public final String filename;\n        public final String[] dependencies;\n\n        SharedLibraryEntry(String name, String filename, String[] dependencies) {\n            this.name = name;\n            this.filename = filename;\n            this.dependencies = dependencies;\n        }\n    }\n\n    // These are the built-in shared libraries that were read from the\n    // system configuration files. Keys are the library names; values are\n    // the individual entries that contain information such as filename\n    // and dependencies.\n    final ArrayMap<String, SharedLibraryEntry> mSharedLibraries = new ArrayMap<>();\n\n    // These are the features this devices supports that were read from the\n    // system configuration files.\n    final ArrayMap<String, FeatureInfo> mAvailableFeatures = new ArrayMap<>();\n\n    // These are the features which this device doesn't support; the OEM\n    // partition uses these to opt-out of features from the system image.\n    final Set<String> mUnavailableFeatures = new HashSet<>();\n\n    public static final class PermissionEntry {\n        public final String name;\n        public int[] gids;\n        public boolean perUser;\n\n        PermissionEntry(String name, boolean perUser) {\n            this.name = name;\n            this.perUser = perUser;\n        }\n    }\n\n    // These are the permission -> gid mappings that were read from the\n    // system configuration files.\n    final ArrayMap<String, PermissionEntry> mPermissions = new ArrayMap<>();\n\n    // These are the packages that are white-listed to be able to run in the\n    // background while in power save mode (but not whitelisted from device idle modes),\n    // as read from the configuration files.\n    final Set<String> mAllowInPowerSaveExceptIdle = new HashSet<>();\n\n    // These are the packages that are white-listed to be able to run in the\n    // background while in power save mode, as read from the configuration files.\n    final Set<String> mAllowInPowerSave = new HashSet<>();\n\n    // These are the packages that are white-listed to be able to run in the\n    // background while in data-usage save mode, as read from the configuration files.\n    final Set<String> mAllowInDataUsageSave = new HashSet<>();\n\n    // These are the packages that are white-listed to be able to run background location\n    // without throttling, as read from the configuration files.\n    final Set<String> mAllowUnthrottledLocation = new HashSet<>();\n\n    // These are the packages that are white-listed to be able to retrieve location even when user\n    // location settings are off, for emergency purposes, as read from the configuration files.\n    final Set<String> mAllowIgnoreLocationSettings = new HashSet<>();\n\n    // These are the action strings of broadcasts which are whitelisted to\n    // be delivered anonymously even to apps which target O+.\n    final Set<String> mAllowImplicitBroadcasts = new HashSet<>();\n\n    // These are the package names of apps which should be in the 'always'\n    // URL-handling state upon factory reset.\n    final Set<String> mLinkedApps = new HashSet<>();\n\n    // These are the packages that are whitelisted to be able to run as system user\n    final Set<String> mSystemUserWhitelistedApps = new HashSet<>();\n\n    // These are the packages that should not run under system user\n    final Set<String> mSystemUserBlacklistedApps = new HashSet<>();\n\n    // These are the components that are enabled by default as VR mode listener services.\n    final Set<ComponentName> mDefaultVrComponents = new HashSet<>();\n\n    // These are the permitted backup transport service components\n    final Set<ComponentName> mBackupTransportWhitelist = new HashSet<>();\n\n    // These are packages mapped to maps of component class name to default enabled state.\n    final ArrayMap<String, ArrayMap<String, Boolean>> mPackageComponentEnabledState = new ArrayMap<>();\n\n    // Package names that are exempted from private API blacklisting\n    final Set<String> mHiddenApiPackageWhitelist = new HashSet<>();\n\n    // The list of carrier applications which should be disabled until used.\n    // This function suppresses update notifications for these pre-installed apps.\n    // In SubscriptionInfoUpdater, the listed applications are disabled until used when all of the\n    // following conditions are met.\n    // 1. Not currently carrier-privileged according to the inserted SIM\n    // 2. Pre-installed\n    // 3. In the default state (enabled but not explicitly)\n    // And SubscriptionInfoUpdater undoes this and marks the app enabled when a SIM is inserted\n    // that marks the app as carrier privileged. It also grants the app default permissions\n    // for Phone and Location. As such, apps MUST only ever be added to this list if they\n    // obtain user consent to access their location through other means.\n    final Set<String> mDisabledUntilUsedPreinstalledCarrierApps = new HashSet<>();\n\n    /**\n     * Represents a carrier app entry for use with {@link SystemConfig}.\n     */\n    // Taken from https://cs.android.com/android/_/android/platform/frameworks/base/+/9c0d523bc0b1ac3ebba92acb7e5d9675aff08aef:core/java/android/os/CarrierAssociatedAppEntry.java\n    public static final class CarrierAssociatedAppEntry {\n        /**\n         * For carrier-associated app entries that don't specify the addedInSdk XML\n         * attribute.\n         */\n        public static final int SDK_UNSPECIFIED = -1;\n\n        public final String packageName;\n        /**\n         * May be {@link #SDK_UNSPECIFIED}.\n         */\n        public final int addedInSdk;\n\n        public CarrierAssociatedAppEntry(String packageName, int addedInSdk) {\n            this.packageName = packageName;\n            this.addedInSdk = addedInSdk;\n        }\n\n        @NonNull\n        @Override\n        public String toString() {\n            return \"CarrierAssociatedAppEntry{\" +\n                    \"packageName='\" + packageName + '\\'' +\n                    \", addedInSdk=\" + addedInSdk +\n                    '}';\n        }\n    }\n\n    // These are the packages of carrier-associated apps which should be disabled until used until\n    // a SIM is inserted which grants carrier privileges to that carrier app.\n    final ArrayMap<String, List<CarrierAssociatedAppEntry>>\n            mDisabledUntilUsedPreinstalledCarrierAssociatedApps = new ArrayMap<>();\n\n    final ArrayMap<String, Set<String>> mPrivAppPermissions = new ArrayMap<>();\n    final ArrayMap<String, Set<String>> mPrivAppDenyPermissions = new ArrayMap<>();\n\n    final ArrayMap<String, Set<String>> mVendorPrivAppPermissions = new ArrayMap<>();\n    final ArrayMap<String, Set<String>> mVendorPrivAppDenyPermissions = new ArrayMap<>();\n\n    final ArrayMap<String, Set<String>> mProductPrivAppPermissions = new ArrayMap<>();\n    final ArrayMap<String, Set<String>> mProductPrivAppDenyPermissions = new ArrayMap<>();\n\n    final ArrayMap<String, Set<String>> mSystemExtPrivAppPermissions = new ArrayMap<>();\n    final ArrayMap<String, Set<String>> mSystemExtPrivAppDenyPermissions = new ArrayMap<>();\n\n    final ArrayMap<String, ArrayMap<String, Boolean>> mOemPermissions = new ArrayMap<>();\n\n    // Allowed associations between applications.  If there are any entries\n    // for an app, those are the only associations allowed; otherwise, all associations\n    // are allowed.  Allowing an association from app A to app B means app A can not\n    // associate with any other apps, but does not limit what apps B can associate with.\n    final ArrayMap<String, Set<String>> mAllowedAssociations = new ArrayMap<>();\n\n    private final Set<String> mBugreportWhitelistedPackages = new HashSet<>();\n    private final Set<String> mAppDataIsolationWhitelistedApps = new HashSet<>();\n\n    // Map of packagesNames to userTypes. Stored temporarily until cleared by UserManagerService().\n    ArrayMap<String, Set<String>> mPackageToUserTypeWhitelist = new ArrayMap<>();\n    ArrayMap<String, Set<String>> mPackageToUserTypeBlacklist = new ArrayMap<>();\n\n    private final Set<String> mRollbackWhitelistedPackages = new HashSet<>();\n    private final Set<String> mWhitelistedStagedInstallers = new HashSet<>();\n\n    /**\n     * Map of system pre-defined, uniquely named actors; keys are namespace,\n     * value maps actor name to package name.\n     */\n    private ArrayMap<String, ArrayMap<String, String>> mNamedActors = new ArrayMap<>();\n\n    public static SystemConfig getInstance() {\n        synchronized (SystemConfig.class) {\n            if (sInstance == null) {\n                sInstance = new SystemConfig();\n            }\n            return sInstance;\n        }\n    }\n\n    public int[] getGlobalGids() {\n        return mGlobalGids;\n    }\n\n    public SparseArray<Set<String>> getSystemPermissions() {\n        return mSystemPermissions;\n    }\n\n    public ArrayList<SplitPermissionInfo> getSplitPermissions() {\n        return mSplitPermissions;\n    }\n\n    public ArrayMap<String, SharedLibraryEntry> getSharedLibraries() {\n        return mSharedLibraries;\n    }\n\n    public ArrayMap<String, FeatureInfo> getAvailableFeatures() {\n        return mAvailableFeatures;\n    }\n\n    public ArrayMap<String, PermissionEntry> getPermissions() {\n        return mPermissions;\n    }\n\n    public Set<String> getAllowImplicitBroadcasts() {\n        return mAllowImplicitBroadcasts;\n    }\n\n    public Set<String> getAllowInPowerSaveExceptIdle() {\n        return mAllowInPowerSaveExceptIdle;\n    }\n\n    public Set<String> getAllowInPowerSave() {\n        return mAllowInPowerSave;\n    }\n\n    public Set<String> getAllowInDataUsageSave() {\n        return mAllowInDataUsageSave;\n    }\n\n    public Set<String> getAllowUnthrottledLocation() {\n        return mAllowUnthrottledLocation;\n    }\n\n    public Set<String> getAllowIgnoreLocationSettings() {\n        return mAllowIgnoreLocationSettings;\n    }\n\n    public Set<String> getLinkedApps() {\n        return mLinkedApps;\n    }\n\n    public Set<String> getSystemUserWhitelistedApps() {\n        return mSystemUserWhitelistedApps;\n    }\n\n    public Set<String> getSystemUserBlacklistedApps() {\n        return mSystemUserBlacklistedApps;\n    }\n\n    public Set<String> getHiddenApiWhitelistedApps() {\n        return mHiddenApiPackageWhitelist;\n    }\n\n    public Set<ComponentName> getDefaultVrComponents() {\n        return mDefaultVrComponents;\n    }\n\n    public Set<ComponentName> getBackupTransportWhitelist() {\n        return mBackupTransportWhitelist;\n    }\n\n    public ArrayMap<String, Boolean> getComponentsEnabledStates(String packageName) {\n        return mPackageComponentEnabledState.get(packageName);\n    }\n\n    public Set<String> getDisabledUntilUsedPreinstalledCarrierApps() {\n        return mDisabledUntilUsedPreinstalledCarrierApps;\n    }\n\n    public ArrayMap<String, List<CarrierAssociatedAppEntry>>\n    getDisabledUntilUsedPreinstalledCarrierAssociatedApps() {\n        return mDisabledUntilUsedPreinstalledCarrierAssociatedApps;\n    }\n\n    public Set<String> getPrivAppPermissions(String packageName) {\n        return mPrivAppPermissions.get(packageName);\n    }\n\n    public Set<String> getPrivAppDenyPermissions(String packageName) {\n        return mPrivAppDenyPermissions.get(packageName);\n    }\n\n    public Set<String> getVendorPrivAppPermissions(String packageName) {\n        return mVendorPrivAppPermissions.get(packageName);\n    }\n\n    public Set<String> getVendorPrivAppDenyPermissions(String packageName) {\n        return mVendorPrivAppDenyPermissions.get(packageName);\n    }\n\n    public Set<String> getProductPrivAppPermissions(String packageName) {\n        return mProductPrivAppPermissions.get(packageName);\n    }\n\n    public Set<String> getProductPrivAppDenyPermissions(String packageName) {\n        return mProductPrivAppDenyPermissions.get(packageName);\n    }\n\n    /**\n     * Read from \"permission\" tags in /system_ext/etc/permissions/*.xml\n     *\n     * @return Set of privileged permissions that are explicitly granted.\n     */\n    public Set<String> getSystemExtPrivAppPermissions(String packageName) {\n        return mSystemExtPrivAppPermissions.get(packageName);\n    }\n\n    /**\n     * Read from \"deny-permission\" tags in /system_ext/etc/permissions/*.xml\n     *\n     * @return Set of privileged permissions that are explicitly denied.\n     */\n    public Set<String> getSystemExtPrivAppDenyPermissions(String packageName) {\n        return mSystemExtPrivAppDenyPermissions.get(packageName);\n    }\n\n    public Map<String, Boolean> getOemPermissions(String packageName) {\n        final Map<String, Boolean> oemPermissions = mOemPermissions.get(packageName);\n        if (oemPermissions != null) {\n            return oemPermissions;\n        }\n        return Collections.emptyMap();\n    }\n\n    public ArrayMap<String, Set<String>> getAllowedAssociations() {\n        return mAllowedAssociations;\n    }\n\n    public Set<String> getBugreportWhitelistedPackages() {\n        return mBugreportWhitelistedPackages;\n    }\n\n    public Set<String> getRollbackWhitelistedPackages() {\n        return mRollbackWhitelistedPackages;\n    }\n\n    public Set<String> getWhitelistedStagedInstallers() {\n        return mWhitelistedStagedInstallers;\n    }\n\n    public Set<String> getAppDataIsolationWhitelistedApps() {\n        return mAppDataIsolationWhitelistedApps;\n    }\n\n    /**\n     * Gets map of packagesNames to userTypes, dictating on which user types each package should be\n     * initially installed, and then removes this map from SystemConfig.\n     * Called by UserManagerService when it is constructed.\n     */\n    public ArrayMap<String, Set<String>> getAndClearPackageToUserTypeWhitelist() {\n        ArrayMap<String, Set<String>> r = mPackageToUserTypeWhitelist;\n        mPackageToUserTypeWhitelist = new ArrayMap<>(0);\n        return r;\n    }\n\n    /**\n     * Gets map of packagesNames to userTypes, dictating on which user types each package should NOT\n     * be initially installed, even if they are whitelisted, and then removes this map from\n     * SystemConfig.\n     * Called by UserManagerService when it is constructed.\n     */\n    public ArrayMap<String, Set<String>> getAndClearPackageToUserTypeBlacklist() {\n        ArrayMap<String, Set<String>> r = mPackageToUserTypeBlacklist;\n        mPackageToUserTypeBlacklist = new ArrayMap<>(0);\n        return r;\n    }\n\n    @NonNull\n    public ArrayMap<String, ArrayMap<String, String>> getNamedActors() {\n        return mNamedActors;\n    }\n\n    /**\n     * Only use for testing. Do NOT use in production code.\n     *\n     * @param readPermissions false to create an empty SystemConfig; true to read the permissions.\n     */\n    @WorkerThread\n    public SystemConfig(boolean readPermissions) {\n        if (readPermissions) {\n            Log.w(TAG, \"Constructing a test SystemConfig\");\n            readAllPermissions();\n        } else {\n            Log.w(TAG, \"Constructing an empty test SystemConfig\");\n        }\n    }\n\n    @WorkerThread\n    SystemConfig() {\n        readAllPermissions();\n    }\n\n    private void readAllPermissions() {\n        // Read configuration from system\n        readPermissions(Paths.build(Environment.getRootDirectory(), \"etc\", \"sysconfig\"), ALLOW_ALL);\n\n        // Read configuration from the old permissions dir\n        readPermissions(Paths.build(Environment.getRootDirectory(), \"etc\", \"permissions\"), ALLOW_ALL);\n\n        // Vendors are only allowed to customize these\n        int vendorPermissionFlag = ALLOW_LIBS | ALLOW_FEATURES | ALLOW_PRIVAPP_PERMISSIONS\n                | ALLOW_ASSOCIATIONS;\n        if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.O_MR1) {\n            // For backward compatibility\n            vendorPermissionFlag |= (ALLOW_PERMISSIONS | ALLOW_APP_CONFIGS);\n        }\n        readPermissions(Paths.build(OsEnvironment.getVendorDirectory(), \"etc\", \"sysconfig\"), vendorPermissionFlag);\n        readPermissions(Paths.build(OsEnvironment.getVendorDirectory(), \"etc\", \"permissions\"), vendorPermissionFlag);\n\n        String vendorSkuProperty = SystemProperties.get(VENDOR_SKU_PROPERTY, \"\");\n        if (!vendorSkuProperty.isEmpty()) {\n            String vendorSkuDir = \"sku_\" + vendorSkuProperty;\n            readPermissions(Paths.build(OsEnvironment.getVendorDirectory(), \"etc\", \"sysconfig\", vendorSkuDir),\n                    vendorPermissionFlag);\n            readPermissions(Paths.build(OsEnvironment.getVendorDirectory(), \"etc\", \"permissions\", vendorSkuDir),\n                    vendorPermissionFlag);\n        }\n\n        // Allow ODM to customize system configs as much as Vendor, because /odm is another\n        // vendor partition other than /vendor.\n        int odmPermissionFlag = vendorPermissionFlag;\n        readPermissions(Paths.build(OsEnvironment.getOdmDirectory(), \"etc\", \"sysconfig\"), odmPermissionFlag);\n        readPermissions(Paths.build(OsEnvironment.getOdmDirectory(), \"etc\", \"permissions\"), odmPermissionFlag);\n\n        String skuProperty = SystemProperties.get(SKU_PROPERTY, \"\");\n        if (!skuProperty.isEmpty()) {\n            String skuDir = \"sku_\" + skuProperty;\n\n            readPermissions(Paths.build(OsEnvironment.getOdmDirectory(), \"etc\", \"sysconfig\", skuDir),\n                    odmPermissionFlag);\n            readPermissions(Paths.build(OsEnvironment.getOdmDirectory(), \"etc\", \"permissions\", skuDir),\n                    odmPermissionFlag);\n        }\n\n        // Allow OEM to customize these\n        int oemPermissionFlag = ALLOW_FEATURES | ALLOW_OEM_PERMISSIONS | ALLOW_ASSOCIATIONS;\n        readPermissions(Paths.build(OsEnvironment.getOemDirectory(), \"etc\", \"sysconfig\"), oemPermissionFlag);\n        readPermissions(Paths.build(OsEnvironment.getOemDirectory(), \"etc\", \"permissions\"), oemPermissionFlag);\n\n        // Allow Product to customize all system configs\n        readPermissions(Paths.build(OsEnvironment.getProductDirectory(), \"etc\", \"sysconfig\"), ALLOW_ALL);\n        readPermissions(Paths.build(OsEnvironment.getProductDirectory(), \"etc\", \"permissions\"), ALLOW_ALL);\n\n        // Allow /system_ext to customize all system configs\n        readPermissions(Paths.build(OsEnvironment.getSystemExtDirectory(), \"etc\", \"sysconfig\"), ALLOW_ALL);\n        readPermissions(Paths.build(OsEnvironment.getSystemExtDirectory(), \"etc\", \"permissions\"), ALLOW_ALL);\n    }\n\n    public void readPermissions(@Nullable Path libraryDir, int permissionFlag) {\n        // Read permissions from given directory.\n        if (libraryDir == null || !libraryDir.exists() || !libraryDir.isDirectory()) {\n            if (permissionFlag == ALLOW_ALL) {\n                Log.w(TAG, \"No directory \" + libraryDir + \", skipping\");\n            }\n            return;\n        }\n\n        // Iterate over the files in the directory and scan .xml files\n        Path platformFile = null;\n        for (Path f : libraryDir.listFiles()) {\n            if (!f.isFile()) {\n                continue;\n            }\n\n            // We'll read platform.xml last\n            if (f.getUri().getPath().endsWith(\"etc/permissions/platform.xml\")) {\n                platformFile = f;\n                continue;\n            }\n\n            if (!f.getUri().getPath().endsWith(\".xml\")) {\n                Log.i(TAG, \"Non-xml file \" + f + \" in \" + libraryDir + \" directory, ignoring\");\n                continue;\n            }\n            if (!f.canRead()) {\n                Log.w(TAG, \"Permissions library file \" + f + \" cannot be read\");\n                continue;\n            }\n\n            readPermissionsFromXml(f, permissionFlag);\n        }\n\n        // Read platform permissions last so it will take precedence\n        if (platformFile != null) {\n            readPermissionsFromXml(platformFile, permissionFlag);\n        }\n    }\n\n    private void logNotAllowedInPartition(String name, Path permFile, @NonNull XmlPullParser parser) {\n        Log.w(TAG, \"<\" + name + \"> not allowed in partition of \"\n                + permFile + \" at \" + parser.getPositionDescription());\n    }\n\n    private void readPermissionsFromXml(Path permFile, int permissionFlag) {\n        StringReader permReader = new StringReader(permFile.getContentAsString());\n        Log.i(TAG, \"Reading permissions from \" + permFile);\n\n//        final boolean lowRam = ActivityManager.isLowRamDeviceStatic();\n\n        try {\n            XmlPullParser parser = Xml.newPullParser();\n            parser.setInput(permReader);\n\n            int type;\n            //noinspection StatementWithEmptyBody\n            while ((type = parser.next()) != parser.START_TAG && type != parser.END_DOCUMENT) {\n            }\n\n            if (type != parser.START_TAG) {\n                throw new XmlPullParserException(\"No start tag found\");\n            }\n\n            if (!parser.getName().equals(\"permissions\") && !parser.getName().equals(\"config\")) {\n                throw new XmlPullParserException(\"Unexpected start tag in \" + permFile\n                        + \": found \" + parser.getName() + \", expected 'permissions' or 'config'\");\n            }\n\n            final boolean allowAll = permissionFlag == ALLOW_ALL;\n            final boolean allowLibs = (permissionFlag & ALLOW_LIBS) != 0;\n            final boolean allowFeatures = (permissionFlag & ALLOW_FEATURES) != 0;\n            final boolean allowPermissions = (permissionFlag & ALLOW_PERMISSIONS) != 0;\n            final boolean allowAppConfigs = (permissionFlag & ALLOW_APP_CONFIGS) != 0;\n            final boolean allowPrivappPermissions = (permissionFlag & ALLOW_PRIVAPP_PERMISSIONS)\n                    != 0;\n            final boolean allowOemPermissions = (permissionFlag & ALLOW_OEM_PERMISSIONS) != 0;\n            final boolean allowApiWhitelisting = (permissionFlag & ALLOW_HIDDENAPI_WHITELISTING)\n                    != 0;\n            final boolean allowAssociations = (permissionFlag & ALLOW_ASSOCIATIONS) != 0;\n            while (true) {\n                XmlUtils.nextElement(parser);\n                if (parser.getEventType() == XmlPullParser.END_DOCUMENT) {\n                    break;\n                }\n\n                @SysConfigType String name = parser.getName();\n                if (name == null) {\n                    XmlUtils.skipCurrentTag(parser);\n                    continue;\n                }\n                switch (name) {\n                    case SysConfigType.TYPE_GROUP: {\n                        if (allowAll) {\n                            String gidStr = parser.getAttributeValue(null, \"gid\");\n                            if (gidStr != null) {\n                                int gid = android.os.Process.getGidForName(gidStr);\n                                mGlobalGids = ArrayUtils.appendInt(mGlobalGids, gid);\n                            } else {\n                                Log.w(TAG, \"<\" + name + \"> without gid in \" + permFile + \" at \"\n                                        + parser.getPositionDescription());\n                            }\n                        } else {\n                            logNotAllowedInPartition(name, permFile, parser);\n                        }\n                        XmlUtils.skipCurrentTag(parser);\n                    }\n                    break;\n                    case SysConfigType.TYPE_PERMISSION: {\n                        if (allowPermissions) {\n                            String perm = parser.getAttributeValue(null, \"name\");\n                            if (perm == null) {\n                                Log.w(TAG, \"<\" + name + \"> without name in \" + permFile + \" at \"\n                                        + parser.getPositionDescription());\n                                XmlUtils.skipCurrentTag(parser);\n                                break;\n                            }\n                            perm = perm.intern();\n                            readPermission(parser, perm);\n                        } else {\n                            logNotAllowedInPartition(name, permFile, parser);\n                            XmlUtils.skipCurrentTag(parser);\n                        }\n                    }\n                    break;\n                    case SysConfigType.TYPE_ASSIGN_PERMISSION: {\n                        if (allowPermissions) {\n                            String perm = parser.getAttributeValue(null, \"name\");\n                            if (perm == null) {\n                                Log.w(TAG, \"<\" + name + \"> without name in \" + permFile\n                                        + \" at \" + parser.getPositionDescription());\n                                XmlUtils.skipCurrentTag(parser);\n                                break;\n                            }\n                            String uidStr = parser.getAttributeValue(null, \"uid\");\n                            if (uidStr == null) {\n                                Log.w(TAG, \"<\" + name + \"> without uid in \" + permFile\n                                        + \" at \" + parser.getPositionDescription());\n                                XmlUtils.skipCurrentTag(parser);\n                                break;\n                            }\n                            int uid = Process.getUidForName(uidStr);\n                            if (uid < 0) {\n                                Log.w(TAG, \"<\" + name + \"> with unknown uid \\\"\"\n                                        + uidStr + \"  in \" + permFile + \" at \"\n                                        + parser.getPositionDescription());\n                                XmlUtils.skipCurrentTag(parser);\n                                break;\n                            }\n                            perm = perm.intern();\n                            Set<String> perms = mSystemPermissions.get(uid);\n                            if (perms == null) {\n                                perms = new HashSet<>();\n                                mSystemPermissions.put(uid, perms);\n                            }\n                            perms.add(perm);\n                        } else {\n                            logNotAllowedInPartition(name, permFile, parser);\n                        }\n                        XmlUtils.skipCurrentTag(parser);\n                    }\n                    break;\n                    case SysConfigType.TYPE_SPLIT_PERMISSION: {\n                        if (allowPermissions) {\n                            readSplitPermission(parser, permFile);\n                        } else {\n                            logNotAllowedInPartition(name, permFile, parser);\n                            XmlUtils.skipCurrentTag(parser);\n                        }\n                    }\n                    break;\n                    case SysConfigType.TYPE_LIBRARY: {\n                        if (allowLibs) {\n                            String lname = parser.getAttributeValue(null, \"name\");\n                            String lfile = parser.getAttributeValue(null, \"file\");\n                            String ldependency = parser.getAttributeValue(null, \"dependency\");\n                            if (lname == null) {\n                                Log.w(TAG, \"<\" + name + \"> without name in \" + permFile + \" at \"\n                                        + parser.getPositionDescription());\n                            } else if (lfile == null) {\n                                Log.w(TAG, \"<\" + name + \"> without file in \" + permFile + \" at \"\n                                        + parser.getPositionDescription());\n                            } else {\n                                //Log.i(TAG, \"Got library \" + lname + \" in \" + lfile);\n                                SharedLibraryEntry entry = new SharedLibraryEntry(lname, lfile,\n                                        ldependency == null ? new String[0] : ldependency.split(\":\"));\n                                mSharedLibraries.put(lname, entry);\n                            }\n                        } else {\n                            logNotAllowedInPartition(name, permFile, parser);\n                        }\n                        XmlUtils.skipCurrentTag(parser);\n                    }\n                    break;\n                    case SysConfigType.TYPE_FEATURE: {\n                        if (allowFeatures) {\n                            String fname = parser.getAttributeValue(null, \"name\");\n                            int fversion = XmlUtils.readIntAttribute(parser, \"version\", 0);\n                            boolean allowed = true;  // FIXME\n//                            if (!lowRam) {\n//                                allowed = true;\n//                            } else {\n//                            String notLowRam = parser.getAttributeValue(null, \"notLowRam\");\n//                            allowed = !\"true\".equals(notLowRam);\n//                            }\n                            if (fname == null) {\n                                Log.w(TAG, \"<\" + name + \"> without name in \" + permFile + \" at \"\n                                        + parser.getPositionDescription());\n                            } else if (allowed) {\n                                addFeature(fname, fversion);\n                            }\n                        } else {\n                            logNotAllowedInPartition(name, permFile, parser);\n                        }\n                        XmlUtils.skipCurrentTag(parser);\n                    }\n                    break;\n                    case SysConfigType.TYPE_UNAVAILABLE_FEATURE: {\n                        if (allowFeatures) {\n                            String fname = parser.getAttributeValue(null, \"name\");\n                            if (fname == null) {\n                                Log.w(TAG, \"<\" + name + \"> without name in \" + permFile\n                                        + \" at \" + parser.getPositionDescription());\n                            } else {\n                                mUnavailableFeatures.add(fname);\n                            }\n                        } else {\n                            logNotAllowedInPartition(name, permFile, parser);\n                        }\n                        XmlUtils.skipCurrentTag(parser);\n                    }\n                    break;\n                    case SysConfigType.TYPE_ALLOW_IN_POWER_SAVE_EXCEPT_IDLE: {\n                        if (allowAll) {\n                            String pkgname = parser.getAttributeValue(null, \"package\");\n                            if (pkgname == null) {\n                                Log.w(TAG, \"<\" + name + \"> without package in \"\n                                        + permFile + \" at \" + parser.getPositionDescription());\n                            } else {\n                                mAllowInPowerSaveExceptIdle.add(pkgname);\n                            }\n                        } else {\n                            logNotAllowedInPartition(name, permFile, parser);\n                        }\n                        XmlUtils.skipCurrentTag(parser);\n                    }\n                    break;\n                    case SysConfigType.TYPE_ALLOW_IN_POWER_SAVE: {\n                        if (allowAll) {\n                            String pkgname = parser.getAttributeValue(null, \"package\");\n                            if (pkgname == null) {\n                                Log.w(TAG, \"<\" + name + \"> without package in \"\n                                        + permFile + \" at \" + parser.getPositionDescription());\n                            } else {\n                                mAllowInPowerSave.add(pkgname);\n                            }\n                        } else {\n                            logNotAllowedInPartition(name, permFile, parser);\n                        }\n                        XmlUtils.skipCurrentTag(parser);\n                    }\n                    break;\n                    case SysConfigType.TYPE_ALLOW_IN_DATA_USAGE_SAVE: {\n                        if (allowAll) {\n                            String pkgname = parser.getAttributeValue(null, \"package\");\n                            if (pkgname == null) {\n                                Log.w(TAG, \"<\" + name + \"> without package in \"\n                                        + permFile + \" at \" + parser.getPositionDescription());\n                            } else {\n                                mAllowInDataUsageSave.add(pkgname);\n                            }\n                        } else {\n                            logNotAllowedInPartition(name, permFile, parser);\n                        }\n                        XmlUtils.skipCurrentTag(parser);\n                    }\n                    break;\n                    case SysConfigType.TYPE_ALLOW_UNTHROTTLED_LOCATION: {\n                        if (allowAll) {\n                            String pkgname = parser.getAttributeValue(null, \"package\");\n                            if (pkgname == null) {\n                                Log.w(TAG, \"<\" + name + \"> without package in \"\n                                        + permFile + \" at \" + parser.getPositionDescription());\n                            } else {\n                                mAllowUnthrottledLocation.add(pkgname);\n                            }\n                        } else {\n                            logNotAllowedInPartition(name, permFile, parser);\n                        }\n                        XmlUtils.skipCurrentTag(parser);\n                    }\n                    break;\n                    case SysConfigType.TYPE_ALLOW_IGNORE_LOCATION_SETTINGS: {\n                        if (allowAll) {\n                            String pkgname = parser.getAttributeValue(null, \"package\");\n                            if (pkgname == null) {\n                                Log.w(TAG, \"<\" + name + \"> without package in \"\n                                        + permFile + \" at \" + parser.getPositionDescription());\n                            } else {\n                                mAllowIgnoreLocationSettings.add(pkgname);\n                            }\n                        } else {\n                            logNotAllowedInPartition(name, permFile, parser);\n                        }\n                        XmlUtils.skipCurrentTag(parser);\n                    }\n                    break;\n                    case SysConfigType.TYPE_ALLOW_IMPLICIT_BROADCAST: {\n                        if (allowAll) {\n                            String action = parser.getAttributeValue(null, \"action\");\n                            if (action == null) {\n                                Log.w(TAG, \"<\" + name + \"> without action in \"\n                                        + permFile + \" at \" + parser.getPositionDescription());\n                            } else {\n                                mAllowImplicitBroadcasts.add(action);\n                            }\n                        } else {\n                            logNotAllowedInPartition(name, permFile, parser);\n                        }\n                        XmlUtils.skipCurrentTag(parser);\n                    }\n                    break;\n                    case SysConfigType.TYPE_APP_LINK: {\n                        if (allowAppConfigs) {\n                            String pkgname = parser.getAttributeValue(null, \"package\");\n                            if (pkgname == null) {\n                                Log.w(TAG, \"<\" + name + \"> without package in \" + permFile\n                                        + \" at \" + parser.getPositionDescription());\n                            } else {\n                                mLinkedApps.add(pkgname);\n                            }\n                        } else {\n                            logNotAllowedInPartition(name, permFile, parser);\n                        }\n                        XmlUtils.skipCurrentTag(parser);\n                    }\n                    break;\n                    case SysConfigType.TYPE_SYSTEM_USER_WHITELISTED_APP: {\n                        if (allowAppConfigs) {\n                            String pkgname = parser.getAttributeValue(null, \"package\");\n                            if (pkgname == null) {\n                                Log.w(TAG, \"<\" + name + \"> without package in \"\n                                        + permFile + \" at \" + parser.getPositionDescription());\n                            } else {\n                                mSystemUserWhitelistedApps.add(pkgname);\n                            }\n                        } else {\n                            logNotAllowedInPartition(name, permFile, parser);\n                        }\n                        XmlUtils.skipCurrentTag(parser);\n                    }\n                    break;\n                    case SysConfigType.TYPE_SYSTEM_USER_BLACKLISTED_APP: {\n                        if (allowAppConfigs) {\n                            String pkgname = parser.getAttributeValue(null, \"package\");\n                            if (pkgname == null) {\n                                Log.w(TAG, \"<\" + name + \"> without package in \"\n                                        + permFile + \" at \" + parser.getPositionDescription());\n                            } else {\n                                mSystemUserBlacklistedApps.add(pkgname);\n                            }\n                        } else {\n                            logNotAllowedInPartition(name, permFile, parser);\n                        }\n                        XmlUtils.skipCurrentTag(parser);\n                    }\n                    break;\n                    case SysConfigType.TYPE_DEFAULT_ENABLED_VR_APP: {\n                        if (allowAppConfigs) {\n                            String pkgname = parser.getAttributeValue(null, \"package\");\n                            String clsname = parser.getAttributeValue(null, \"class\");\n                            if (pkgname == null) {\n                                Log.w(TAG, \"<\" + name + \"> without package in \"\n                                        + permFile + \" at \" + parser.getPositionDescription());\n                            } else if (clsname == null) {\n                                Log.w(TAG, \"<\" + name + \"> without class in \"\n                                        + permFile + \" at \" + parser.getPositionDescription());\n                            } else {\n                                mDefaultVrComponents.add(new ComponentName(pkgname, clsname));\n                            }\n                        } else {\n                            logNotAllowedInPartition(name, permFile, parser);\n                        }\n                        XmlUtils.skipCurrentTag(parser);\n                    }\n                    break;\n                    case SysConfigType.TYPE_COMPONENT_OVERRIDE: {\n                        readComponentOverrides(parser, permFile);\n                    }\n                    break;\n                    case SysConfigType.TYPE_BACKUP_TRANSPORT_WHITELISTED_SERVICE: {\n                        if (allowFeatures) {\n                            String serviceName = parser.getAttributeValue(null, \"service\");\n                            if (serviceName == null) {\n                                Log.w(TAG, \"<\" + name + \"> without service in \"\n                                        + permFile + \" at \" + parser.getPositionDescription());\n                            } else {\n                                ComponentName cn = ComponentName.unflattenFromString(serviceName);\n                                if (cn == null) {\n                                    Log.w(TAG, \"<\" + name + \"> with invalid service name \"\n                                            + serviceName + \" in \" + permFile\n                                            + \" at \" + parser.getPositionDescription());\n                                } else {\n                                    mBackupTransportWhitelist.add(cn);\n                                }\n                            }\n                        } else {\n                            logNotAllowedInPartition(name, permFile, parser);\n                        }\n                        XmlUtils.skipCurrentTag(parser);\n                    }\n                    break;\n                    case SysConfigType.TYPE_DISABLED_UNTIL_USED_PREINSTALLED_CARRIER_ASSOCIATED_APP: {\n                        if (allowAppConfigs) {\n                            String pkgname = parser.getAttributeValue(null, \"package\");\n                            String carrierPkgname = parser.getAttributeValue(null,\n                                    \"carrierAppPackage\");\n                            if (pkgname == null || carrierPkgname == null) {\n                                Log.w(TAG, \"<\" + name\n                                        + \"> without package or carrierAppPackage in \" + permFile\n                                        + \" at \" + parser.getPositionDescription());\n                            } else {\n                                // APKs added to system images via OTA should specify the addedInSdk\n                                // attribute, otherwise they may be enabled-by-default in too many\n                                // cases. See CarrierAppUtils for more info.\n                                int addedInSdk = CarrierAssociatedAppEntry.SDK_UNSPECIFIED;\n                                String addedInSdkStr = parser.getAttributeValue(null, \"addedInSdk\");\n                                if (!TextUtils.isEmpty(addedInSdkStr)) {\n                                    try {\n                                        addedInSdk = Integer.parseInt(addedInSdkStr);\n                                    } catch (NumberFormatException e) {\n                                        Log.w(TAG, \"<\" + name + \"> addedInSdk not an integer in \"\n                                                + permFile + \" at \"\n                                                + parser.getPositionDescription());\n                                        XmlUtils.skipCurrentTag(parser);\n                                        break;\n                                    }\n                                }\n                                List<CarrierAssociatedAppEntry> associatedPkgs =\n                                        mDisabledUntilUsedPreinstalledCarrierAssociatedApps.get(\n                                                carrierPkgname);\n                                if (associatedPkgs == null) {\n                                    associatedPkgs = new ArrayList<>();\n                                    mDisabledUntilUsedPreinstalledCarrierAssociatedApps.put(\n                                            carrierPkgname, associatedPkgs);\n                                }\n                                associatedPkgs.add(\n                                        new CarrierAssociatedAppEntry(pkgname, addedInSdk));\n                            }\n                        } else {\n                            logNotAllowedInPartition(name, permFile, parser);\n                        }\n                        XmlUtils.skipCurrentTag(parser);\n                    }\n                    break;\n                    case SysConfigType.TYPE_DISABLED_UNTIL_USED_PREINSTALLED_CARRIER_APP: {\n                        if (allowAppConfigs) {\n                            String pkgname = parser.getAttributeValue(null, \"package\");\n                            if (pkgname == null) {\n                                Log.w(TAG,\n                                        \"<\" + name + \"> without \"\n                                                + \"package in \" + permFile + \" at \"\n                                                + parser.getPositionDescription());\n                            } else {\n                                mDisabledUntilUsedPreinstalledCarrierApps.add(pkgname);\n                            }\n                        } else {\n                            logNotAllowedInPartition(name, permFile, parser);\n                        }\n                        XmlUtils.skipCurrentTag(parser);\n                    }\n                    break;\n                    case SysConfigType.TYPE_PRIVAPP_PERMISSIONS: {\n                        if (allowPrivappPermissions) {\n                            // privapp permissions from system, vendor, product and system_ext\n                            // partitions are stored separately. This is to prevent xml files in\n                            // the vendor partition from granting permissions to priv apps in the\n                            // system partition and vice versa.\n                            boolean vendor = permFile.getFilePath().startsWith(\n                                    OsEnvironment.getVendorDirectory().getFilePath() + \"/\")\n                                    || permFile.getFilePath().startsWith(\n                                    OsEnvironment.getOdmDirectory().getFilePath() + \"/\");\n                            boolean product = permFile.getFilePath().startsWith(\n                                    OsEnvironment.getProductDirectory().getFilePath() + \"/\");\n                            boolean systemExt = permFile.getFilePath().startsWith(\n                                    OsEnvironment.getSystemExtDirectory().getFilePath() + \"/\");\n                            if (vendor) {\n                                readPrivAppPermissions(parser, mVendorPrivAppPermissions,\n                                        mVendorPrivAppDenyPermissions);\n                            } else if (product) {\n                                readPrivAppPermissions(parser, mProductPrivAppPermissions,\n                                        mProductPrivAppDenyPermissions);\n                            } else if (systemExt) {\n                                readPrivAppPermissions(parser, mSystemExtPrivAppPermissions,\n                                        mSystemExtPrivAppDenyPermissions);\n                            } else {\n                                readPrivAppPermissions(parser, mPrivAppPermissions,\n                                        mPrivAppDenyPermissions);\n                            }\n                        } else {\n                            logNotAllowedInPartition(name, permFile, parser);\n                            XmlUtils.skipCurrentTag(parser);\n                        }\n                    }\n                    break;\n                    case SysConfigType.TYPE_OEM_PERMISSIONS: {\n                        if (allowOemPermissions) {\n                            readOemPermissions(parser);\n                        } else {\n                            logNotAllowedInPartition(name, permFile, parser);\n                            XmlUtils.skipCurrentTag(parser);\n                        }\n                    }\n                    break;\n                    case SysConfigType.TYPE_HIDDEN_API_WHITELISTED_APP: {\n                        if (allowApiWhitelisting) {\n                            String pkgname = parser.getAttributeValue(null, \"package\");\n                            if (pkgname == null) {\n                                Log.w(TAG, \"<\" + name + \"> without package in \"\n                                        + permFile + \" at \" + parser.getPositionDescription());\n                            } else {\n                                mHiddenApiPackageWhitelist.add(pkgname);\n                            }\n                        } else {\n                            logNotAllowedInPartition(name, permFile, parser);\n                        }\n                        XmlUtils.skipCurrentTag(parser);\n                    }\n                    break;\n                    case SysConfigType.TYPE_ALLOW_ASSOCIATION: {\n                        if (allowAssociations) {\n                            String target = parser.getAttributeValue(null, \"target\");\n                            if (target == null) {\n                                Log.w(TAG, \"<\" + name + \"> without target in \" + permFile\n                                        + \" at \" + parser.getPositionDescription());\n                                XmlUtils.skipCurrentTag(parser);\n                                break;\n                            }\n                            String allowed = parser.getAttributeValue(null, \"allowed\");\n                            if (allowed == null) {\n                                Log.w(TAG, \"<\" + name + \"> without allowed in \" + permFile\n                                        + \" at \" + parser.getPositionDescription());\n                                XmlUtils.skipCurrentTag(parser);\n                                break;\n                            }\n                            target = target.intern();\n                            allowed = allowed.intern();\n                            Set<String> associations = mAllowedAssociations.get(target);\n                            if (associations == null) {\n                                associations = new HashSet<>();\n                                mAllowedAssociations.put(target, associations);\n                            }\n                            Log.i(TAG, \"Adding association: \" + target + \" <- \" + allowed);\n                            associations.add(allowed);\n                        } else {\n                            logNotAllowedInPartition(name, permFile, parser);\n                        }\n                        XmlUtils.skipCurrentTag(parser);\n                    }\n                    break;\n                    case SysConfigType.TYPE_APP_DATA_ISOLATION_WHITELISTED_APP: {\n                        String pkgname = parser.getAttributeValue(null, \"package\");\n                        if (pkgname == null) {\n                            Log.w(TAG, \"<\" + name + \"> without package in \" + permFile\n                                    + \" at \" + parser.getPositionDescription());\n                        } else {\n                            mAppDataIsolationWhitelistedApps.add(pkgname);\n                        }\n                        XmlUtils.skipCurrentTag(parser);\n                    }\n                    break;\n                    case SysConfigType.TYPE_BUGREPORT_WHITELISTED: {\n                        String pkgname = parser.getAttributeValue(null, \"package\");\n                        if (pkgname == null) {\n                            Log.w(TAG, \"<\" + name + \"> without package in \" + permFile\n                                    + \" at \" + parser.getPositionDescription());\n                        } else {\n                            mBugreportWhitelistedPackages.add(pkgname);\n                        }\n                        XmlUtils.skipCurrentTag(parser);\n                    }\n                    break;\n                    case SysConfigType.TYPE_INSTALL_IN_USER_TYPE: {\n                        // NB: We allow any directory permission to declare install-in-user-type.\n                        readInstallInUserType(parser,\n                                mPackageToUserTypeWhitelist, mPackageToUserTypeBlacklist);\n                    }\n                    break;\n                    case SysConfigType.TYPE_NAMED_ACTOR: {\n                        String namespace = TextUtilsCompat.safeIntern(\n                                parser.getAttributeValue(null, \"namespace\"));\n                        String actorName = parser.getAttributeValue(null, \"name\");\n                        String pkgName = TextUtilsCompat.safeIntern(\n                                parser.getAttributeValue(null, \"package\"));\n                        if (TextUtils.isEmpty(namespace)) {\n                            Log.e(TAG, \"<\" + name + \"> without namespace in \" + permFile\n                                    + \" at \" + parser.getPositionDescription());\n                        } else if (TextUtils.isEmpty(actorName)) {\n                            Log.e(TAG, \"<\" + name + \"> without actor name in \" + permFile\n                                    + \" at \" + parser.getPositionDescription());\n                        } else if (TextUtils.isEmpty(pkgName)) {\n                            Log.e(TAG, \"<\" + name + \"> without package name in \" + permFile\n                                    + \" at \" + parser.getPositionDescription());\n                        } else if (\"android\".equalsIgnoreCase(namespace)) {\n                            throw new IllegalStateException(\"Defining \" + actorName + \" as \"\n                                    + pkgName + \" for the android namespace is not allowed\");\n                        } else {\n                            ArrayMap<String, String> nameToPkgMap = mNamedActors.get(namespace);\n                            if (nameToPkgMap == null) {\n                                nameToPkgMap = new ArrayMap<>();\n                                mNamedActors.put(namespace, nameToPkgMap);\n                            } else if (nameToPkgMap.containsKey(actorName)) {\n                                String existing = nameToPkgMap.get(actorName);\n                                throw new IllegalStateException(\"Duplicate actor definition for \"\n                                        + namespace + \"/\" + actorName\n                                        + \"; defined as both \" + existing + \" and \" + pkgName);\n                            }\n\n                            nameToPkgMap.put(actorName, pkgName);\n                        }\n                        XmlUtils.skipCurrentTag(parser);\n                    }\n                    break;\n                    case SysConfigType.TYPE_ROLLBACK_WHITELISTED_APP: {\n                        String pkgname = parser.getAttributeValue(null, \"package\");\n                        if (pkgname == null) {\n                            Log.w(TAG, \"<\" + name + \"> without package in \" + permFile\n                                    + \" at \" + parser.getPositionDescription());\n                        } else {\n                            mRollbackWhitelistedPackages.add(pkgname);\n                        }\n                        XmlUtils.skipCurrentTag(parser);\n                    }\n                    break;\n                    case SysConfigType.TYPE_WHITELISTED_STAGED_INSTALLER: {\n                        if (allowAppConfigs) {\n                            String pkgname = parser.getAttributeValue(null, \"package\");\n                            if (pkgname == null) {\n                                Log.w(TAG, \"<\" + name + \"> without package in \" + permFile\n                                        + \" at \" + parser.getPositionDescription());\n                            } else {\n                                mWhitelistedStagedInstallers.add(pkgname);\n                            }\n                        } else {\n                            logNotAllowedInPartition(name, permFile, parser);\n                        }\n                        XmlUtils.skipCurrentTag(parser);\n                    }\n                    break;\n                    default: {\n                        Log.w(TAG, \"Tag \" + name + \" is unknown in \"\n                                + permFile + \" at \" + parser.getPositionDescription());\n                        XmlUtils.skipCurrentTag(parser);\n                    }\n                    break;\n                }\n            }\n        } catch (XmlPullParserException | IOException e) {\n            Log.w(TAG, \"Got exception parsing permissions.\", e);\n        } finally {\n            IoUtils.closeQuietly(permReader);\n        }\n\n        // Some devices can be field-converted to FBE, so offer to splice in\n        // those features if not already defined by the static config\n        // FIXME\n//        if (StorageManager.isFileEncryptedNativeOnly()) {\n//            addFeature(PackageManager.FEATURE_FILE_BASED_ENCRYPTION, 0);\n//            addFeature(PackageManager.FEATURE_SECURELY_REMOVES_USERS, 0);\n//        }\n//\n//        // Help legacy devices that may not have updated their static config\n//        if (StorageManager.hasAdoptable()) {\n//            addFeature(PackageManager.FEATURE_ADOPTABLE_STORAGE, 0);\n//        }\n//\n//        if (ActivityManager.isLowRamDeviceStatic()) {\n//            addFeature(PackageManager.FEATURE_RAM_LOW, 0);\n//        } else {\n//            addFeature(PackageManager.FEATURE_RAM_NORMAL, 0);\n//        }\n//\n//        if (IncrementalManager.isFeatureEnabled()) {\n//            addFeature(PackageManager.FEATURE_INCREMENTAL_DELIVERY, 0);\n//        }\n//\n//        if (PackageManager.APP_ENUMERATION_ENABLED_BY_DEFAULT) {\n//            addFeature(PackageManager.FEATURE_APP_ENUMERATION, 0);\n//        }\n\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {\n            addFeature(PackageManager.FEATURE_IPSEC_TUNNELS, 0);\n        }\n\n        for (String featureName : mUnavailableFeatures) {\n            removeFeature(featureName);\n        }\n    }\n\n    private void addFeature(String name, int version) {\n        FeatureInfo fi = mAvailableFeatures.get(name);\n        if (fi == null) {\n            fi = new FeatureInfo();\n            fi.name = name;\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {\n                fi.version = version;\n            }\n            mAvailableFeatures.put(name, fi);\n        } else {\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {\n                fi.version = Math.max(fi.version, version);\n            }\n        }\n    }\n\n    private void removeFeature(String name) {\n        if (mAvailableFeatures.remove(name) != null) {\n            Log.d(TAG, \"Removed unavailable feature \" + name);\n        }\n    }\n\n    void readPermission(XmlPullParser parser, String name)\n            throws IOException, XmlPullParserException {\n        if (mPermissions.containsKey(name)) {\n            throw new IllegalStateException(\"Duplicate permission definition for \" + name);\n        }\n\n        final boolean perUser = XmlUtils.readBooleanAttribute(parser, \"perUser\", false);\n        final PermissionEntry perm = new PermissionEntry(name, perUser);\n        mPermissions.put(name, perm);\n\n        int outerDepth = parser.getDepth();\n        int type;\n        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT\n                && (type != XmlPullParser.END_TAG\n                || parser.getDepth() > outerDepth)) {\n            if (type == XmlPullParser.END_TAG\n                    || type == XmlPullParser.TEXT) {\n                continue;\n            }\n\n            String tagName = parser.getName();\n            if (\"group\".equals(tagName)) {\n                String gidStr = parser.getAttributeValue(null, \"gid\");\n                if (gidStr != null) {\n                    int gid = Process.getGidForName(gidStr);\n                    perm.gids = ArrayUtils.appendInt(perm.gids, gid);\n                } else {\n                    Log.w(TAG, \"<group> without gid at \"\n                            + parser.getPositionDescription());\n                }\n            }\n            XmlUtils.skipCurrentTag(parser);\n        }\n    }\n\n    private void readPrivAppPermissions(@NonNull XmlPullParser parser,\n                                        ArrayMap<String, Set<String>> grantMap,\n                                        ArrayMap<String, Set<String>> denyMap)\n            throws IOException, XmlPullParserException {\n        String packageName = parser.getAttributeValue(null, \"package\");\n        if (TextUtils.isEmpty(packageName)) {\n            Log.w(TAG, \"package is required for <privapp-permissions> in \"\n                    + parser.getPositionDescription());\n            return;\n        }\n\n        Set<String> permissions = grantMap.get(packageName);\n        if (permissions == null) {\n            permissions = new HashSet<>();\n        }\n        Set<String> denyPermissions = denyMap.get(packageName);\n        int depth = parser.getDepth();\n        while (XmlUtils.nextElementWithin(parser, depth)) {\n            String name = parser.getName();\n            if (\"permission\".equals(name)) {\n                String permName = parser.getAttributeValue(null, \"name\");\n                if (TextUtils.isEmpty(permName)) {\n                    Log.w(TAG, \"name is required for <permission> in \"\n                            + parser.getPositionDescription());\n                    continue;\n                }\n                permissions.add(permName);\n            } else if (\"deny-permission\".equals(name)) {\n                String permName = parser.getAttributeValue(null, \"name\");\n                if (TextUtils.isEmpty(permName)) {\n                    Log.w(TAG, \"name is required for <deny-permission> in \"\n                            + parser.getPositionDescription());\n                    continue;\n                }\n                if (denyPermissions == null) {\n                    denyPermissions = new HashSet<>();\n                }\n                denyPermissions.add(permName);\n            }\n        }\n        grantMap.put(packageName, permissions);\n        if (denyPermissions != null) {\n            denyMap.put(packageName, denyPermissions);\n        }\n    }\n\n    private void readInstallInUserType(@NonNull XmlPullParser parser,\n                                       Map<String, Set<String>> doInstallMap,\n                                       Map<String, Set<String>> nonInstallMap)\n            throws IOException, XmlPullParserException {\n        final String packageName = parser.getAttributeValue(null, \"package\");\n        if (TextUtils.isEmpty(packageName)) {\n            Log.w(TAG, \"package is required for <install-in-user-type> in \"\n                    + parser.getPositionDescription());\n            return;\n        }\n\n        Set<String> userTypesYes = doInstallMap.get(packageName);\n        Set<String> userTypesNo = nonInstallMap.get(packageName);\n        final int depth = parser.getDepth();\n        while (XmlUtils.nextElementWithin(parser, depth)) {\n            final String name = parser.getName();\n            if (\"install-in\".equals(name)) {\n                final String userType = parser.getAttributeValue(null, \"user-type\");\n                if (TextUtils.isEmpty(userType)) {\n                    Log.w(TAG, \"user-type is required for <install-in-user-type> in \"\n                            + parser.getPositionDescription());\n                    continue;\n                }\n                if (userTypesYes == null) {\n                    userTypesYes = new HashSet<>();\n                    doInstallMap.put(packageName, userTypesYes);\n                }\n                userTypesYes.add(userType);\n            } else if (\"do-not-install-in\".equals(name)) {\n                final String userType = parser.getAttributeValue(null, \"user-type\");\n                if (TextUtils.isEmpty(userType)) {\n                    Log.w(TAG, \"user-type is required for <install-in-user-type> in \"\n                            + parser.getPositionDescription());\n                    continue;\n                }\n                if (userTypesNo == null) {\n                    userTypesNo = new HashSet<>();\n                    nonInstallMap.put(packageName, userTypesNo);\n                }\n                userTypesNo.add(userType);\n            } else {\n                Log.w(TAG, \"unrecognized tag in <install-in-user-type> in \"\n                        + parser.getPositionDescription());\n            }\n        }\n    }\n\n    void readOemPermissions(@NonNull XmlPullParser parser) throws IOException, XmlPullParserException {\n        final String packageName = parser.getAttributeValue(null, \"package\");\n        if (TextUtils.isEmpty(packageName)) {\n            Log.w(TAG, \"package is required for <oem-permissions> in \"\n                    + parser.getPositionDescription());\n            return;\n        }\n\n        ArrayMap<String, Boolean> permissions = mOemPermissions.get(packageName);\n        if (permissions == null) {\n            permissions = new ArrayMap<>();\n        }\n        final int depth = parser.getDepth();\n        while (XmlUtils.nextElementWithin(parser, depth)) {\n            final String name = parser.getName();\n            if (\"permission\".equals(name)) {\n                final String permName = parser.getAttributeValue(null, \"name\");\n                if (TextUtils.isEmpty(permName)) {\n                    Log.w(TAG, \"name is required for <permission> in \"\n                            + parser.getPositionDescription());\n                    continue;\n                }\n                permissions.put(permName, Boolean.TRUE);\n            } else if (\"deny-permission\".equals(name)) {\n                String permName = parser.getAttributeValue(null, \"name\");\n                if (TextUtils.isEmpty(permName)) {\n                    Log.w(TAG, \"name is required for <deny-permission> in \"\n                            + parser.getPositionDescription());\n                    continue;\n                }\n                permissions.put(permName, Boolean.FALSE);\n            }\n        }\n        mOemPermissions.put(packageName, permissions);\n    }\n\n    private void readSplitPermission(@NonNull XmlPullParser parser, Path permFile)\n            throws IOException, XmlPullParserException {\n        String splitPerm = parser.getAttributeValue(null, \"name\");\n        if (splitPerm == null) {\n            Log.w(TAG, \"<split-permission> without name in \" + permFile + \" at \"\n                    + parser.getPositionDescription());\n            XmlUtils.skipCurrentTag(parser);\n            return;\n        }\n        String targetSdkStr = parser.getAttributeValue(null, \"targetSdk\");\n        int targetSdk = Build.VERSION_CODES.CUR_DEVELOPMENT + 1;\n        if (!TextUtils.isEmpty(targetSdkStr)) {\n            try {\n                targetSdk = Integer.parseInt(targetSdkStr);\n            } catch (NumberFormatException e) {\n                Log.w(TAG, \"<split-permission> targetSdk not an integer in \" + permFile + \" at \"\n                        + parser.getPositionDescription());\n                XmlUtils.skipCurrentTag(parser);\n                return;\n            }\n        }\n        final int depth = parser.getDepth();\n        List<String> newPermissions = new ArrayList<>();\n        while (XmlUtils.nextElementWithin(parser, depth)) {\n            String name = parser.getName();\n            if (\"new-permission\".equals(name)) {\n                final String newName = parser.getAttributeValue(null, \"name\");\n                if (TextUtils.isEmpty(newName)) {\n                    Log.w(TAG, \"name is required for <new-permission> in \"\n                            + parser.getPositionDescription());\n                    continue;\n                }\n                newPermissions.add(newName);\n            } else {\n                XmlUtils.skipCurrentTag(parser);\n            }\n        }\n        if (!newPermissions.isEmpty()) {\n            mSplitPermissions.add(new SplitPermissionInfo(splitPerm, newPermissions, targetSdk));\n        }\n    }\n\n    private void readComponentOverrides(@NonNull XmlPullParser parser, Path permFile)\n            throws IOException, XmlPullParserException {\n        String pkgname = parser.getAttributeValue(null, \"package\");\n        if (pkgname == null) {\n            Log.w(TAG, \"<component-override> without package in \"\n                    + permFile + \" at \" + parser.getPositionDescription());\n            return;\n        }\n\n        pkgname = pkgname.intern();\n\n        final int depth = parser.getDepth();\n        while (XmlUtils.nextElementWithin(parser, depth)) {\n            if (\"component\".equals(parser.getName())) {\n                String clsname = parser.getAttributeValue(null, \"class\");\n                String enabled = parser.getAttributeValue(null, \"enabled\");\n                if (clsname == null) {\n                    Log.w(TAG, \"<component> without class in \"\n                            + permFile + \" at \" + parser.getPositionDescription());\n                    return;\n                } else if (enabled == null) {\n                    Log.w(TAG, \"<component> without enabled in \"\n                            + permFile + \" at \" + parser.getPositionDescription());\n                    return;\n                }\n\n                if (clsname.startsWith(\".\")) {\n                    clsname = pkgname + clsname;\n                }\n\n                clsname = clsname.intern();\n\n                ArrayMap<String, Boolean> componentEnabledStates =\n                        mPackageComponentEnabledState.get(pkgname);\n                if (componentEnabledStates == null) {\n                    componentEnabledStates = new ArrayMap<>();\n                    mPackageComponentEnabledState.put(pkgname,\n                            componentEnabledStates);\n                }\n\n                componentEnabledStates.put(clsname, !\"false\".equals(enabled));\n            }\n        }\n    }\n}"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/terminal/TermActivity.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.terminal;\n\nimport android.graphics.Color;\nimport android.graphics.Typeface;\nimport android.os.Bundle;\nimport android.os.PowerManager;\nimport android.text.Editable;\nimport android.text.Spanned;\nimport android.text.style.BackgroundColorSpan;\nimport android.text.style.ForegroundColorSpan;\nimport android.text.style.StrikethroughSpan;\nimport android.text.style.StyleSpan;\nimport android.text.style.UnderlineSpan;\nimport android.view.KeyEvent;\nimport android.view.MenuItem;\nimport android.view.inputmethod.EditorInfo;\nimport android.widget.TextView;\n\nimport androidx.annotation.ColorInt;\nimport androidx.annotation.MainThread;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.UiThread;\nimport androidx.appcompat.widget.AppCompatEditText;\nimport androidx.appcompat.widget.AppCompatTextView;\n\nimport com.google.android.material.color.MaterialColors;\n\nimport java.io.BufferedOutputStream;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.nio.charset.StandardCharsets;\nimport java.util.Arrays;\nimport java.util.Objects;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\n\nimport io.github.muntashirakon.AppManager.BaseActivity;\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.compat.ProcessCompat;\nimport io.github.muntashirakon.AppManager.logs.Log;\nimport io.github.muntashirakon.AppManager.utils.CpuUtils;\n\n// TODO: 11/9/23 Replace it with an actual terminal\npublic class TermActivity extends BaseActivity {\n    public static final String TAG = TermActivity.class.getSimpleName();\n    private final Object mLock = new Object();\n    private AppCompatEditText mCommandInput;\n    private AppCompatTextView mCommandOutput;\n    private Process mProc;\n    private OutputStream mProcessOutputStream;\n    private PowerManager.WakeLock mWakeLock;\n    private final ExecutorService mExecutor = Executors.newFixedThreadPool(3);\n    private int mDefaultForegroundColor;\n    private int mDefaultBackgroundColor;\n    private final AnsiState mAnsiState = new AnsiState();\n\n    @Override\n    protected void onAuthenticated(@Nullable Bundle savedInstanceState) {\n        setContentView(R.layout.activity_term);\n        setSupportActionBar(findViewById(R.id.toolbar));\n        mCommandInput = findViewById(R.id.command_input);\n        mCommandOutput = findViewById(R.id.command_output);\n        mCommandOutput.setText(\"\", TextView.BufferType.EDITABLE);\n        mDefaultForegroundColor = mCommandInput.getCurrentTextColor();\n        mDefaultBackgroundColor = MaterialColors.getColor(mCommandInput, com.google.android.material.R.attr.colorSurface);\n        mCommandInput.setOnEditorActionListener((v, actionId, event) -> {\n            if (actionId == EditorInfo.IME_ACTION_DONE) {\n                String command = Objects.requireNonNull(mCommandInput.getText()).toString();\n                appendBoldOutput(command);\n                appendOutput(\"\\n\");\n                mAnsiState.homePosition = mCommandOutput.getEditableText().length();\n                return sendToStdin(command, true);\n            }\n            return false;\n        });\n        mCommandInput.setOnKeyListener((v, keyCode, event) -> {\n            if (event.getAction() != KeyEvent.ACTION_DOWN) {\n                // Only handle key down\n                return false;\n            }\n\n            // TAB\n            if (keyCode == KeyEvent.KEYCODE_TAB) {\n                // TODO: 7/21/25 Support minimal completion\n            }\n\n            // Arrow Keys (UP/DOWN/PGUP/PGDOWN)\n            switch (keyCode) {\n                case KeyEvent.KEYCODE_DPAD_UP:\n                case KeyEvent.KEYCODE_DPAD_DOWN:\n                case KeyEvent.KEYCODE_PAGE_UP:\n                case KeyEvent.KEYCODE_PAGE_DOWN:\n                    // TODO: 7/21/25 Support history\n            }\n\n            // CTRL + KEY\n            if (event.isCtrlPressed()) {\n                int c = event.getUnicodeChar();\n                char ctrlChar;\n                if (c >= 'a' && c <= 'z') {\n                    ctrlChar = (char)(c - 'a' + 1);\n                } else if (c >= 'A' && c <= 'Z') {\n                    ctrlChar = (char)(c - 'A' + 1);\n                } else return false;\n                appendBoldOutput(\"^\" + (char) (c + 'A'));\n                appendOutput(\"\\n\");\n                sendToStdin(String.valueOf(ctrlChar), true);\n            }\n            return false;\n        });\n        initShell();\n    }\n\n    @Override\n    public boolean onOptionsItemSelected(@NonNull MenuItem item) {\n        if (item.getItemId() == android.R.id.home) {\n            finish();\n            return true;\n        }\n        return super.onOptionsItemSelected(item);\n    }\n\n    @Override\n    protected void onDestroy() {\n        CpuUtils.releaseWakeLock(mWakeLock);\n        mExecutor.shutdownNow();\n        super.onDestroy();\n    }\n\n    private void initShell() {\n        mWakeLock = CpuUtils.getPartialWakeLock(\"term\");\n        mWakeLock.acquire();\n        mExecutor.submit(() -> {\n            try {\n                mProc = ProcessCompat.exec(new String[]{\"sh\", \"-i\"}, new String[]{\"TERM=xterm-256color\", \"HOME=/\"});\n                mProcessOutputStream = new BufferedOutputStream(mProc.getOutputStream());\n                mExecutor.submit(() -> {\n                    try (InputStream in = mProc.getInputStream()) {\n                        byte[] buffer = new byte[1024];\n                        int len;\n                        while ((len = in.read(buffer)) != -1) {\n                            synchronized (mLock) {\n                                String chunk = new String(buffer, 0, len, StandardCharsets.UTF_8);\n                                runOnUiThread(() -> processChunk(chunk, mAnsiState));\n                            }\n                        }\n                    } catch (Throwable e) {\n                        e.printStackTrace();\n                    }\n                });\n                mExecutor.submit(() -> {\n                    try (InputStream in = mProc.getErrorStream()) {\n                        byte[] buffer = new byte[1024];\n                        int len;\n                        while ((len = in.read(buffer)) != -1) {\n                            synchronized (mLock) {\n                                String chunk = new String(buffer, 0, len, StandardCharsets.UTF_8);\n                                runOnUiThread(() -> processChunk(chunk, mAnsiState));\n                            }\n                        }\n                    } catch (Throwable e) {\n                        e.printStackTrace();\n                    }\n                });\n                // TODO: 7/21/25 Support init script\n                mProc.waitFor();\n                runOnUiThread(this::finishAndRemoveTask);\n            } catch (Throwable e) {\n                e.printStackTrace();\n                // TODO: 23/1/23 Handle error\n            }\n        });\n    }\n\n    static class AnsiState {\n        @ColorInt\n        int foreground = -1;\n        @ColorInt\n        int background = -1;\n        boolean bold = false;\n        boolean underline = false;\n        boolean italic = false;\n        boolean strike = false;\n        boolean reverse = false;\n        boolean hide = false;\n        int savedPosition = -1;\n        boolean navigateToHome = false;\n        int homePosition = 0;\n\n        void reset() {\n            foreground = -1;\n            background = -1;\n            bold = false;\n            underline = false;\n            italic = false;\n            strike = false;\n            reverse = false;\n            hide = false;\n            savedPosition = -1;\n            navigateToHome = false;\n        }\n    }\n\n    @UiThread\n    private void processChunk(@NonNull String chunk, @NonNull AnsiState state) {\n        StringBuilder plainTextBuffer = new StringBuilder();\n        for (int i = 0; i < chunk.length(); ++i) {\n            char ch = chunk.charAt(i);\n            if (ch == '\\u001b') {\n                // Start escape sequence\n                // Flush plain text\n                if (plainTextBuffer.length() > 0) {\n                    appendOutput(plainTextBuffer.toString(), state);\n                    plainTextBuffer.setLength(0);\n                }\n                ++i;\n                if (i >= chunk.length()) {\n                    // Invalid sequence\n                    break;\n                }\n                ch = chunk.charAt(i);\n                if (ch == '[') {\n                    // Start of special sequences\n                    StringBuilder numberBuilder = new StringBuilder();\n                    numberBuilder.append(ch);\n                    for (++i; i < chunk.length(); ++i) {\n                        char c = chunk.charAt(i);\n                        if (c >= '0' && c <= '9') {\n                            // A number\n                            numberBuilder.append(c);\n                        } else if (c == ';' || c == '?') {\n                            // Separator\n                            numberBuilder.append(c);\n                        } else {\n                            // Any other ANSI character\n                            numberBuilder.append(c);\n                            processAnsiSeq(numberBuilder.toString(), state);\n                            // We're done\n                            break;\n                        }\n                    }\n                } else if (ch == 'M') {\n                    // ENTER\n                    processAnsiSeq(\"M\", state);\n                } // else Invalid sequence\n            } else {\n                plainTextBuffer.append(ch);\n            }\n        }\n        if (plainTextBuffer.length() > 0) {\n            appendOutput(plainTextBuffer.toString(), state);\n        }\n    }\n\n    @MainThread\n    void processAnsiSeq(@NonNull String seq, @NonNull AnsiState state) {\n        if (seq.matches(\"\\\\[[0-2]?J\")) {\n            String code = seq.substring(1, seq.length() - 1);\n            switch (code) {\n                case \"2\": // Clear entire screen\n                    resetOutput(state);\n                    break;\n                case \"1\": // Clear screen from cursor up\n                    Log.i(TAG, \"Unhandled escape sequence: \" + seq);\n                    break;\n                case \"0\": // Clear screen from cursor down\n                default:\n                    if (state.navigateToHome) {\n                        resetOutputToPosition(state.homePosition);\n                    } // else Not handled\n            }\n        } else if (seq.equals(\"[H\") || seq.equals(\"[;H\") || seq.equals(\"[f\")) {\n            state.navigateToHome = true;\n        } else if (seq.equals(\"[2K\")) {\n            clearLastLine();\n        } else if (seq.equals(\"[s\")) {\n            Editable editable = mCommandOutput.getEditableText();\n            state.savedPosition = editable.length();\n        } else if (seq.equals(\"[u\")) {\n            Editable editable = mCommandOutput.getEditableText();\n            if (state.savedPosition >= 0 && state.savedPosition <= editable.length()) {\n                editable.delete(state.savedPosition, editable.length());\n            }\n        } else if (seq.matches(\"\\\\[[0-9;]*m\")) {\n            // Parse the numbers\n            String params = seq.substring(1, seq.length() - 1);\n            String[] codes = params.split(\";\");\n            for (String code : codes) {\n                int value;\n                try {\n                    value = Integer.parseInt(code);\n                } catch (Exception e) {\n                    if (code.isEmpty()) {\n                        value = 0; // Same as RESET\n                    } else continue;\n                }\n                switch (value) {\n                    case 0: // RESET\n                        state.reset();\n                        break;\n                    case 1: // BOLD\n                        state.bold = true;\n                        break;\n                    case 22: // RESET BOLD\n                        state.bold = false;\n                        break;\n                    case 3: // ITALIC\n                        state.italic = true;\n                        break;\n                    case 23: // RESET ITALIC\n                        state.italic = false;\n                        break;\n                    case 4: // UNDERLINE\n                        state.underline = true;\n                        break;\n                    case 24: // RESET UNDERLINE\n                        state.underline = false;\n                        break;\n                    case 7: // REVERSE VIDEO\n                        state.reverse = true;\n                        break;\n                    case 27: // RESET REVERSE VIDEO\n                        state.reverse = false;\n                        break;\n                    case 8: // HIDE\n                        state.hide = true;\n                        break;\n                    case 28: // RESET HIDE\n                        state.hide = false;\n                        break;\n                    case 9: // STRIKETHROUGH\n                        state.strike = true;\n                        break;\n                    case 29: // RESET STRIKETHROUGH\n                        state.strike = false;\n                        break;\n                    case 39: // RESET FOREGROUND\n                        state.foreground = -1;\n                        break;\n                    case 30:\n                        state.foreground = Color.BLACK;\n                        break;\n                    case 31:\n                        state.foreground = Color.RED;\n                        break;\n                    case 32:\n                        state.foreground = Color.GREEN;\n                        break;\n                    case 33:\n                        state.foreground = Color.YELLOW;\n                        break;\n                    case 34:\n                        state.foreground = Color.BLUE;\n                        break;\n                    case 35:\n                        state.foreground = Color.MAGENTA;\n                        break;\n                    case 36:\n                        state.foreground = Color.CYAN;\n                        break;\n                    case 37:\n                        state.foreground = Color.WHITE;\n                        break;\n                    case 49: // RESET BACKGROUND\n                        state.background = -1;\n                        break;\n                    case 40:\n                        state.background = Color.BLACK;\n                        break;\n                    case 41:\n                        state.background = Color.RED;\n                        break;\n                    case 42:\n                        state.background = Color.GREEN;\n                        break;\n                    case 43:\n                        state.background = Color.YELLOW;\n                        break;\n                    case 44:\n                        state.background = Color.BLUE;\n                        break;\n                    case 45:\n                        state.background = Color.MAGENTA;\n                        break;\n                    case 46:\n                        state.background = Color.CYAN;\n                        break;\n                    case 47:\n                        state.background = Color.WHITE;\n                        break;\n                    default:\n                        Log.i(TAG, \"Unhandled escape sequence: \" + seq);\n                }\n            }\n        } else {\n            Log.i(TAG, \"Unhandled escape sequence: \" + seq);\n        }\n    }\n\n    @MainThread\n    private void resetOutput(@NonNull AnsiState state) {\n        mCommandOutput.getEditableText().clear();\n        state.homePosition = 0;\n    }\n\n    @MainThread\n    private void resetOutputToPosition(int position) {\n        Editable editable = mCommandOutput.getEditableText();\n        if (position <= 0) {\n            editable.clear();\n        } else {\n            int length = editable.length();\n            if (position < length) {\n                editable.delete(position, length);\n            }\n        }\n    }\n\n    private void clearLastLine() {\n        Editable editable = mCommandOutput.getEditableText();\n        int length = editable.length();\n        if (length > 0) {\n            // Find the index of the last newline character\n            int lastNewline = editable.toString().lastIndexOf('\\n', length - 2);\n            // If no newline found, delete everything\n            resetOutputToPosition(lastNewline + 1);\n        }\n    }\n\n    @MainThread\n    private void appendOutput(@NonNull String text) {\n        mCommandOutput.getEditableText().append(text);\n    }\n\n    @MainThread\n    private void appendOutput(@NonNull String text, @NonNull AnsiState state) {\n        state.navigateToHome = false;\n        if (state.hide) {\n            // Replace with spaces\n            char[] blank = new char[text.length()];\n            Arrays.fill(blank, ' ');\n            text = new String(blank);\n        }\n        Editable editable = mCommandOutput.getEditableText();\n        int start = editable.length();\n        editable.append(text);\n        int end = editable.length();\n        if (start == end) {\n            return;\n        }\n        if (state.bold) {\n            editable.setSpan(new StyleSpan(Typeface.BOLD), start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);\n        }\n        if (state.italic) {\n            editable.setSpan(new StyleSpan(Typeface.ITALIC), start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);\n        }\n        if (state.underline) {\n            editable.setSpan(new UnderlineSpan(), start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);\n        }\n        if (state.strike) {\n            editable.setSpan(new StrikethroughSpan(), start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);\n        }\n        int foregroundColor = state.foreground != -1 ? state.foreground : mDefaultForegroundColor;\n        int backgroundColor = state.background != -1 ? state.background : mDefaultBackgroundColor;\n        editable.setSpan(new ForegroundColorSpan(state.reverse ? backgroundColor : foregroundColor),\n                start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);\n        editable.setSpan(new BackgroundColorSpan(state.reverse ? foregroundColor : backgroundColor),\n                start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);\n    }\n\n    @MainThread\n    private void appendBoldOutput(@NonNull String boldText) {\n        Editable editable = mCommandOutput.getEditableText();\n        int start = editable.length();\n        editable.append(boldText);\n        editable.setSpan(new StyleSpan(Typeface.BOLD), start, editable.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);\n    }\n\n    private boolean sendToStdin(@NonNull String command, boolean newLine) {\n        if (mProcessOutputStream != null) {\n            if (!ProcessCompat.isAlive(mProc)) {\n                // Process is dead\n                return false;\n            }\n            try {\n                mProcessOutputStream.write(command.getBytes(StandardCharsets.UTF_8));\n                if (newLine) {\n                    mProcessOutputStream.write(\"\\n\".getBytes(StandardCharsets.UTF_8));\n                }\n                mProcessOutputStream.flush();\n            } catch (Throwable e) {\n                e.printStackTrace();\n            }\n        }\n        return true;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/types/ForegroundService.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\npackage io.github.muntashirakon.AppManager.types;\n\nimport android.annotation.SuppressLint;\nimport android.app.Notification;\nimport android.app.Service;\nimport android.content.Intent;\nimport android.content.pm.ServiceInfo;\nimport android.os.Build;\nimport android.os.Bundle;\nimport android.os.Handler;\nimport android.os.HandlerThread;\nimport android.os.IBinder;\nimport android.os.Looper;\nimport android.os.Message;\nimport android.os.Process;\n\nimport androidx.annotation.CallSuper;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.UiThread;\nimport androidx.annotation.WorkerThread;\nimport androidx.core.app.ServiceCompat;\nimport androidx.core.os.BundleCompat;\n\nimport io.github.muntashirakon.AppManager.utils.ThreadUtils;\n\npublic abstract class ForegroundService extends Service {\n    public static final int FOREGROUND_SERVICE_TYPE_DATA_SYNC;\n    public static final int FOREGROUND_SERVICE_TYPE_SPECIAL_USE;\n\n    static {\n        FOREGROUND_SERVICE_TYPE_DATA_SYNC = Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q ? ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC : 0;\n        FOREGROUND_SERVICE_TYPE_SPECIAL_USE = Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE ? ServiceInfo.FOREGROUND_SERVICE_TYPE_SPECIAL_USE : 0;\n    }\n\n    @SuppressLint(\"ForegroundServiceType\")\n    public static void start(@NonNull Service service, int id, @NonNull Notification notification,\n                             int foregroundServiceType) {\n        ServiceCompat.startForeground(service, id, notification, foregroundServiceType);\n    }\n\n    public static class Binder extends android.os.Binder {\n        private final ForegroundService mService;\n\n        private Binder(ForegroundService service) {\n            mService = service;\n        }\n\n        @SuppressWarnings(\"unchecked\")\n        public <T extends ForegroundService> T getService() {\n            return (T) mService;\n        }\n    }\n\n    private final String mName;\n    private final IBinder mBinder = new Binder(this);\n    @SuppressWarnings(\"FieldCanBeLocal\")\n    private Looper mServiceLooper;\n    private ServiceHandler mServiceHandler;\n    private volatile boolean mIsWorking = false;\n\n    // Handler that receives messages from the thread\n    private final class ServiceHandler extends Handler {\n        public ServiceHandler(Looper looper) {\n            super(looper);\n        }\n\n        @Override\n        public void handleMessage(Message msg) {\n            Intent intent = BundleCompat.getParcelable(msg.getData(), \"intent\", Intent.class);\n            ThreadUtils.postOnMainThread(() -> onStartIntent(intent));\n            onHandleIntent(intent);\n            // It works because of Handler uses FIFO\n            stopSelfResult(msg.arg1);\n        }\n    }\n\n    protected ForegroundService(String name) {\n        mName = name;\n    }\n\n    public final boolean isWorking() {\n        return mIsWorking;\n    }\n\n    @Override\n    public void onCreate() {\n        HandlerThread thread = new HandlerThread(mName, Process.THREAD_PRIORITY_BACKGROUND);\n        thread.start();\n        mServiceLooper = thread.getLooper();\n        mServiceHandler = new ServiceHandler(mServiceLooper);\n    }\n\n    @CallSuper\n    @Override\n    public int onStartCommand(@Nullable Intent intent, int flags, int startId) {\n        // TODO: 15/6/21 Make it final, extended classes shouldn't need to use it\n        if (mIsWorking) {\n            // Service already running\n            onQueued(intent);\n        }\n        mIsWorking = true;\n        Message msg = mServiceHandler.obtainMessage();\n        msg.arg1 = startId;\n        Bundle args = new Bundle();\n        args.putParcelable(\"intent\", intent);\n        msg.setData(args);\n        mServiceHandler.sendMessage(msg);\n        return START_NOT_STICKY;\n    }\n\n    @CallSuper\n    @Override\n    public void onDestroy() {\n        super.onDestroy();\n        mServiceLooper.quitSafely();\n    }\n\n    /**\n     * The work to be performed.\n     *\n     * @param intent The intent sent by {@link android.content.Context#startService(Intent)}\n     */\n    @WorkerThread\n    protected abstract void onHandleIntent(@Nullable Intent intent);\n\n    /**\n     * The service is running and a new intent has been queued.\n     *\n     * @param intent The new intent that has been queued\n     */\n    @UiThread\n    protected void onQueued(@Nullable Intent intent) {\n    }\n\n    /**\n     * An intent is being processed. Called right before {@link #onHandleIntent(Intent)}.\n     *\n     * @param intent The intent to be processed.\n     */\n    @UiThread\n    protected void onStartIntent(@Nullable Intent intent) {\n    }\n\n    @NonNull\n    @Override\n    public IBinder onBind(Intent intent) {\n        return mBinder;\n    }\n}"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/types/PackageChangeReceiver.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.types;\n\nimport static io.github.muntashirakon.AppManager.batchops.BatchOpsService.ACTION_BATCH_OPS_COMPLETED;\n\nimport android.content.BroadcastReceiver;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.IntentFilter;\nimport android.os.Build;\nimport android.os.Bundle;\nimport android.os.Handler;\nimport android.os.HandlerThread;\nimport android.os.Looper;\nimport android.os.Message;\nimport android.os.Process;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.UiThread;\nimport androidx.annotation.WorkerThread;\nimport androidx.core.content.ContextCompat;\nimport androidx.core.os.BundleCompat;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Objects;\n\nimport io.github.muntashirakon.AppManager.BuildConfig;\nimport io.github.muntashirakon.AppManager.batchops.BatchOpsManager;\nimport io.github.muntashirakon.AppManager.batchops.BatchOpsService;\n\npublic abstract class PackageChangeReceiver extends BroadcastReceiver {\n    /**\n     * Specifies that some packages have been altered. This could be due to batch operations, database update, etc.\n     * It has one extra namely {@link Intent#EXTRA_CHANGED_PACKAGE_LIST}.\n     */\n    public static final String ACTION_PACKAGE_ALTERED = BuildConfig.APPLICATION_ID + \".action.PACKAGE_ALTERED\";\n    /**\n     * Specifies that some packages have been added. This could be due to batch operations, database update, etc.\n     * It has one extra namely {@link Intent#EXTRA_CHANGED_PACKAGE_LIST}.\n     */\n    public static final String ACTION_PACKAGE_ADDED = BuildConfig.APPLICATION_ID + \".action.PACKAGE_ADDED\";\n    /**\n     * Specifies that some packages have been removed. This could be due to batch operations, database update, etc.\n     * It has one extra namely {@link Intent#EXTRA_CHANGED_PACKAGE_LIST}.\n     */\n    public static final String ACTION_PACKAGE_REMOVED = BuildConfig.APPLICATION_ID + \".action.PACKAGE_REMOVED\";\n\n    /**\n     * Specifies that some packages have been altered. This could be due to batch operations, database update, etc.\n     * It has one extra namely {@link Intent#EXTRA_CHANGED_PACKAGE_LIST}.\n     */\n    public static final String ACTION_DB_PACKAGE_ALTERED = BuildConfig.APPLICATION_ID + \".action.DB_PACKAGE_ALTERED\";\n    /**\n     * Specifies that some packages have been added. This could be due to batch operations, database update, etc.\n     * It has one extra namely {@link Intent#EXTRA_CHANGED_PACKAGE_LIST}.\n     */\n    public static final String ACTION_DB_PACKAGE_ADDED = BuildConfig.APPLICATION_ID + \".action.DB_PACKAGE_ADDED\";\n    /**\n     * Specifies that some packages have been removed. This could be due to batch operations, database update, etc.\n     * It has one extra namely {@link Intent#EXTRA_CHANGED_PACKAGE_LIST}.\n     */\n    public static final String ACTION_DB_PACKAGE_REMOVED = BuildConfig.APPLICATION_ID + \".action.DB_PACKAGE_REMOVED\";\n\n    public PackageChangeReceiver(@NonNull Context context) {\n        IntentFilter filter = new IntentFilter(Intent.ACTION_PACKAGE_ADDED);\n        filter.addAction(Intent.ACTION_PACKAGE_REMOVED);\n        filter.addAction(Intent.ACTION_PACKAGE_CHANGED);\n        filter.addDataScheme(\"package\");\n        ContextCompat.registerReceiver(context, this, filter, ContextCompat.RECEIVER_EXPORTED);\n        // Other filters\n        IntentFilter sdFilter = new IntentFilter();\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {\n            sdFilter.addAction(Intent.ACTION_PACKAGES_SUSPENDED);\n            sdFilter.addAction(Intent.ACTION_PACKAGES_UNSUSPENDED);\n        }\n        sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE);\n        sdFilter.addAction(Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE);\n        sdFilter.addAction(Intent.ACTION_PACKAGE_RESTARTED);\n        sdFilter.addAction(ACTION_PACKAGE_ALTERED);\n        sdFilter.addAction(ACTION_PACKAGE_ADDED);\n        sdFilter.addAction(ACTION_PACKAGE_REMOVED);\n        sdFilter.addAction(ACTION_DB_PACKAGE_ALTERED);\n        sdFilter.addAction(ACTION_DB_PACKAGE_ADDED);\n        sdFilter.addAction(ACTION_DB_PACKAGE_REMOVED);\n        sdFilter.addAction(ACTION_BATCH_OPS_COMPLETED);\n        ContextCompat.registerReceiver(context, this, sdFilter, ContextCompat.RECEIVER_EXPORTED);\n    }\n\n    @WorkerThread\n    protected abstract void onPackageChanged(Intent intent, @Nullable Integer uid, @Nullable String[] packages);\n\n    @Override\n    @UiThread\n    public final void onReceive(Context context, @NonNull Intent intent) {\n        HandlerThread thread = new HandlerThread(\"PackageChangeReceiver\", Process.THREAD_PRIORITY_BACKGROUND);\n        thread.start();\n        ReceiverHandler receiverHandler = new ReceiverHandler(thread.getLooper());\n        Message msg = receiverHandler.obtainMessage();\n        Bundle args = new Bundle();\n        args.putParcelable(\"intent\", intent);\n        msg.setData(args);\n        receiverHandler.sendMessage(msg);\n        thread.quitSafely();\n    }\n\n    // Handler that receives messages from the thread\n    private final class ReceiverHandler extends Handler {\n        public ReceiverHandler(Looper looper) {\n            super(looper);\n        }\n\n        @Override\n        public void handleMessage(@NonNull Message msg) {\n            Intent intent = Objects.requireNonNull(BundleCompat.getParcelable(msg.getData(), \"intent\", Intent.class));\n            switch (Objects.requireNonNull(intent.getAction())) {\n                case Intent.ACTION_PACKAGE_REMOVED:\n                    if (intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {\n                        // The package is being updated, not removed\n                        return;\n                    }\n                case Intent.ACTION_PACKAGE_ADDED:\n                case Intent.ACTION_PACKAGE_CHANGED:\n                case Intent.ACTION_PACKAGE_RESTARTED: {\n                    int uid = intent.getIntExtra(Intent.EXTRA_UID, -1);\n                    if (uid != -1) {\n                        onPackageChanged(intent, uid, null);\n                    }\n                    return;\n                }\n                case ACTION_PACKAGE_ADDED:\n                case ACTION_PACKAGE_ALTERED:\n                case ACTION_PACKAGE_REMOVED:\n                case ACTION_DB_PACKAGE_ADDED:\n                case ACTION_DB_PACKAGE_ALTERED:\n                case ACTION_DB_PACKAGE_REMOVED:\n                case Intent.ACTION_PACKAGES_SUSPENDED:\n                case Intent.ACTION_PACKAGES_UNSUSPENDED:\n                case Intent.ACTION_EXTERNAL_APPLICATIONS_AVAILABLE:\n                case Intent.ACTION_EXTERNAL_APPLICATIONS_UNAVAILABLE: {\n                    String[] packages = intent.getStringArrayExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST);\n                    onPackageChanged(intent, null, packages);\n                    return;\n                }\n                case ACTION_BATCH_OPS_COMPLETED: {\n                    // Trigger for all ops except disable, force-stop and uninstall\n                    @BatchOpsManager.OpType int op;\n                    op = intent.getIntExtra(BatchOpsService.EXTRA_OP, BatchOpsManager.OP_NONE);\n                    if (op != BatchOpsManager.OP_NONE && op != BatchOpsManager.OP_ADVANCED_FREEZE\n                            && op != BatchOpsManager.OP_FREEZE && op != BatchOpsManager.OP_UNFREEZE\n                            && op != BatchOpsManager.OP_UNINSTALL) {\n                        String[] packages = intent.getStringArrayExtra(BatchOpsService.EXTRA_OP_PKG);\n                        ArrayList<String> failedPackages = intent.getStringArrayListExtra(BatchOpsService.EXTRA_FAILED_PKG);\n                        if (packages != null && failedPackages != null) {\n                            List<String> packageList = new ArrayList<>();\n                            for (String packageName : packages) {\n                                if (!failedPackages.contains(packageName)) {\n                                    packageList.add(packageName);\n                                }\n                            }\n                            if (!packageList.isEmpty()) {\n                                onPackageChanged(intent, null, packageList.toArray(new String[0]));\n                            }\n                        }\n                    }\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/types/PackageSizeInfo.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.types;\n\nimport android.annotation.UserIdInt;\nimport android.app.usage.StorageStats;\nimport android.os.Build;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.RequiresApi;\nimport androidx.annotation.WorkerThread;\n\nimport io.github.muntashirakon.AppManager.misc.OsEnvironment;\nimport io.github.muntashirakon.io.Path;\nimport io.github.muntashirakon.io.Paths;\n\npublic class PackageSizeInfo {\n    public final String packageName;\n    public final long codeSize;\n    public final long dataSize;\n    public final long cacheSize;\n    public final long mediaSize;\n    public final long obbSize;\n\n    @SuppressWarnings(\"deprecation\")\n    public PackageSizeInfo(@NonNull android.content.pm.PackageStats packageStats) {\n        packageName = packageStats.packageName;\n        codeSize = packageStats.codeSize + packageStats.externalCodeSize;\n        dataSize = packageStats.dataSize + packageStats.externalDataSize;\n        cacheSize = packageStats.cacheSize + packageStats.externalCacheSize;\n        obbSize = packageStats.externalObbSize;\n        mediaSize = packageStats.externalMediaSize;\n    }\n\n    @RequiresApi(Build.VERSION_CODES.O)\n    @WorkerThread\n    public PackageSizeInfo(@NonNull String packageName, @NonNull StorageStats storageStats, @UserIdInt int userHandle) {\n        this.packageName = packageName;\n        cacheSize = storageStats.getCacheBytes();\n        codeSize = storageStats.getAppBytes();\n        dataSize = storageStats.getDataBytes() - cacheSize;\n        OsEnvironment.UserEnvironment ue = OsEnvironment.getUserEnvironment(userHandle);\n        mediaSize = getMediaSizeInternal(ue);\n        obbSize = getObbSizeInternal(ue);\n    }\n\n    public long getTotalSize() {\n        return codeSize + dataSize + cacheSize + mediaSize + obbSize;\n    }\n\n    @RequiresApi(Build.VERSION_CODES.O)\n    private long getMediaSizeInternal(@NonNull OsEnvironment.UserEnvironment ue) {\n        Path[] files = ue.buildExternalStorageAppMediaDirs(packageName);\n        long size = 0L;\n        for (Path file : files) {\n            if (file.exists()) size += Paths.size(file);\n        }\n        return size;\n    }\n\n    @RequiresApi(Build.VERSION_CODES.O)\n    private long getObbSizeInternal(@NonNull OsEnvironment.UserEnvironment ue) {\n        Path[] files = ue.buildExternalStorageAppObbDirs(packageName);\n        long size = 0L;\n        for (Path file : files) {\n            if (file.exists()) {\n                size += Paths.size(file);\n            }\n        }\n        return size;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/types/UserPackagePair.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.types;\n\nimport android.annotation.UserIdInt;\nimport android.os.Parcel;\nimport android.os.Parcelable;\n\nimport androidx.annotation.NonNull;\nimport androidx.core.util.Pair;\n\npublic final class UserPackagePair extends Pair<String, Integer> implements Parcelable {\n    public UserPackagePair(String packageName, @UserIdInt int userId) {\n        super(packageName, userId);\n    }\n\n    public String getPackageName() {\n        return super.first;\n    }\n\n    @UserIdInt\n    public int getUserId() {\n        return super.second;\n    }\n\n    @NonNull\n    @Override\n    public String toString() {\n        return \"(\" + first + \", \" + second + \")\";\n    }\n\n    private UserPackagePair(@NonNull Parcel in) {\n        super(in.readString(), in.readInt());\n    }\n\n    public static final Creator<UserPackagePair> CREATOR = new Creator<UserPackagePair>() {\n        @Override\n        @NonNull\n        public UserPackagePair createFromParcel(Parcel in) {\n            return new UserPackagePair(in);\n        }\n\n        @Override\n        @NonNull\n        public UserPackagePair[] newArray(int size) {\n            return new UserPackagePair[size];\n        }\n    };\n\n    @Override\n    public int describeContents() {\n        return 0;\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        dest.writeString(getPackageName());\n        dest.writeInt(getUserId());\n    }\n}"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/uri/GrantUriUtils.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.uri;\n\nimport static io.github.muntashirakon.AppManager.utils.UIUtils.getSmallerText;\nimport static io.github.muntashirakon.AppManager.utils.UIUtils.getStyledKeyValue;\n\nimport android.content.ContentResolver;\nimport android.content.Context;\nimport android.net.Uri;\nimport android.os.Environment;\nimport android.text.SpannableStringBuilder;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport java.io.File;\nimport java.util.List;\nimport java.util.Locale;\n\nimport io.github.muntashirakon.AppManager.R;\n\npublic final class GrantUriUtils {\n    @NonNull\n    public static CharSequence toLocalisedString(@NonNull Context context, @NonNull Uri uri) {\n        if (!ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) {\n            throw new UnsupportedOperationException(\"Invalid URI: \" + uri);\n        }\n        String authority = uri.getAuthority();\n        List<String> paths = uri.getPathSegments();\n        boolean isTree = paths.size() >= 2 && \"tree\".equals(paths.get(0));\n        boolean isDocument = paths.size() >= 2 && \"document\".equals(paths.get(0));\n        String basePath = isTree ? paths.get(1) : null;\n        String file;\n        if (isTree) {\n            file = paths.size() == 4 ? paths.get(3) : null;\n        } else if (isDocument) {\n            file = paths.get(1);\n        } else {\n            // Other types of file\n            file = uri.getPath();\n        }\n        SpannableStringBuilder sb = new SpannableStringBuilder();\n        if (basePath != null) {\n            String realPath = getRealPath(authority, basePath);\n            sb.append(getStyledKeyValue(context, R.string.folder, realPath != null ? realPath : basePath));\n        }\n        if (file != null) {\n            if (basePath != null) sb.append(\"\\n\");\n            String realFile = getRealPath(authority, file);\n            sb.append(getStyledKeyValue(context, R.string.file, realFile != null ? realFile : file));\n        }\n        sb.append(\"\\n\")\n                .append(getSmallerText(getStyledKeyValue(context, R.string.authority, authority)))\n                .append(\"\\n\")\n                .append(getSmallerText(getStyledKeyValue(context, R.string.type, isTree ? \"Tree\" : \"Document\")));\n        return sb;\n    }\n\n    @Nullable\n    private static String getRealPath(@NonNull String authority, @NonNull String dirtyFile) {\n        switch (authority) {\n            case \"com.android.externalstorage.documents\": {\n                int splitIndex = dirtyFile.indexOf(\":\", 1);\n                String rootId = dirtyFile.substring(0, splitIndex);\n                String path = dirtyFile.substring(splitIndex + 1);\n                if (\"primary\".equals(rootId) || \"home\".equals(rootId)) {\n                    return new File(Environment.getExternalStorageDirectory(), path).getAbsolutePath();\n                }\n                return String.format(Locale.ROOT, \"/storage/%s/%s\", rootId, path);\n            }\n            case \"com.android.providers.downloads.documents\": {\n                int splitIndex = dirtyFile.indexOf(\":\", 1);\n                String rootId = dirtyFile.substring(0, splitIndex);\n                String path = dirtyFile.substring(splitIndex + 1);\n                if (\"raw\".equals(rootId)) {\n                    // Raw/absolute path\n                    return path;\n                }\n                // Other cases are: msf (MediaStore file), msd (MediaStore directory) or simply an integer.\n                break;\n            }\n            case \"com.termux.documents\":\n                // Same as the dirty file\n                return dirtyFile;\n            case \"me.zhanghai.android.files.file_provider\":\n                Uri uri = Uri.parse(dirtyFile);\n                if (uri == null || !ContentResolver.SCHEME_FILE.equals(uri.getScheme())) {\n                    // Unsupported file\n                    return dirtyFile;\n                } else {\n                    return uri.getPath();\n                }\n        }\n        // Others aren't supported\n        return null;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/uri/UriManager.java",
    "content": "// SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.uri;\n\nimport static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;\nimport static org.xmlpull.v1.XmlPullParser.START_TAG;\n\nimport android.net.Uri;\nimport android.os.RemoteException;\nimport android.os.UserHandleHidden;\nimport android.system.ErrnoException;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport org.xmlpull.v1.XmlPullParserException;\n\nimport java.io.BufferedInputStream;\nimport java.io.FileNotFoundException;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Objects;\nimport java.util.StringTokenizer;\n\nimport io.github.muntashirakon.AppManager.logs.Log;\nimport io.github.muntashirakon.AppManager.misc.OsEnvironment;\nimport io.github.muntashirakon.compat.xml.TypedXmlPullParser;\nimport io.github.muntashirakon.compat.xml.TypedXmlSerializer;\nimport io.github.muntashirakon.compat.xml.Xml;\nimport io.github.muntashirakon.io.AtomicExtendedFile;\nimport io.github.muntashirakon.io.ExtendedFile;\nimport io.github.muntashirakon.io.Paths;\n\npublic class UriManager {\n    public static final String TAG = \"UriManager\";\n\n    private final AtomicExtendedFile mGrantFile;\n\n    private final HashMap<String, ArrayList<UriGrant>> mUriGrantsHashMap = new HashMap<>();\n\n    /**\n     * XML constants used in {@link #mGrantFile}\n     */\n    private static final String TAG_URI_GRANTS = \"uri-grants\";\n    private static final String TAG_URI_GRANT = \"uri-grant\";\n    private static final String ATTR_USER_HANDLE = \"userHandle\";\n    private static final String ATTR_SOURCE_USER_ID = \"sourceUserId\";\n    private static final String ATTR_TARGET_USER_ID = \"targetUserId\";\n    private static final String ATTR_SOURCE_PKG = \"sourcePkg\";\n    private static final String ATTR_TARGET_PKG = \"targetPkg\";\n    private static final String ATTR_URI = \"uri\";\n    private static final String ATTR_MODE_FLAGS = \"modeFlags\";\n    private static final String ATTR_CREATED_TIME = \"createdTime\";\n    private static final String ATTR_PREFIX = \"prefix\";\n\n    public UriManager() {\n        mGrantFile = new AtomicExtendedFile(Objects.requireNonNull(Objects.requireNonNull(Paths.build(\n                OsEnvironment.getDataSystemDirectory(), \"urigrants.xml\")).getFile()));\n        readGrantedUriPermissions();\n    }\n\n    @Nullable\n    public ArrayList<UriGrant> getGrantedUris(String packageName) {\n        synchronized (this) {\n            return mUriGrantsHashMap.get(packageName);\n        }\n    }\n\n    public void grantUri(@NonNull UriGrant uriGrant) {\n        synchronized (this) {\n            ArrayList<UriGrant> uriGrants = mUriGrantsHashMap.get(uriGrant.targetPkg);\n            if (uriGrants == null) {\n                uriGrants = new ArrayList<>();\n                mUriGrantsHashMap.put(uriGrant.targetPkg, uriGrants);\n            }\n            uriGrants.add(uriGrant);\n        }\n    }\n\n    @SuppressWarnings(\"OctalInteger\")\n    public void writeGrantedUriPermissions() {\n        // Snapshot permissions so we can persist without lock\n        List<UriGrant> persist = new ArrayList<>();\n        synchronized (this) {\n            for (List<UriGrant> uriGrants : mUriGrantsHashMap.values()) {\n                persist.addAll(uriGrants);\n            }\n        }\n\n        FileOutputStream fos = null;\n        try {\n            fos = mGrantFile.startWrite();\n            TypedXmlSerializer out = Xml.resolveSerializer(fos);\n            out.startDocument(null, true);\n            out.startTag(null, TAG_URI_GRANTS);\n            for (UriGrant perm : persist) {\n                out.startTag(null, TAG_URI_GRANT);\n                out.attributeInt(null, ATTR_SOURCE_USER_ID, perm.sourceUserId);\n                out.attributeInt(null, ATTR_TARGET_USER_ID, perm.targetUserId);\n                out.attributeInterned(null, ATTR_SOURCE_PKG, perm.sourcePkg);\n                out.attributeInterned(null, ATTR_TARGET_PKG, perm.targetPkg);\n                out.attribute(null, ATTR_URI, String.valueOf(perm.uri));\n                out.attributeBoolean(null, ATTR_PREFIX, perm.prefix);\n                out.attributeInt(null, ATTR_MODE_FLAGS, perm.modeFlags);\n                out.attributeLong(null, ATTR_CREATED_TIME, perm.createdTime);\n                out.endTag(null, TAG_URI_GRANT);\n            }\n            out.endTag(null, TAG_URI_GRANTS);\n            out.endDocument();\n            mGrantFile.finishWrite(fos);\n            ExtendedFile file = mGrantFile.getBaseFile();\n            file.setMode(0600);\n            file.setUidGid(1000, 1000);\n            file.restoreSelinuxContext();\n        } catch (ErrnoException e) {\n            Log.e(TAG, \"Failed to change file permissions.\", e);\n        } catch (IOException e) {\n            Log.e(TAG, \"Failed writing Uri grants\", e);\n            mGrantFile.failWrite(fos);\n        }\n    }\n\n    private void readGrantedUriPermissions() {\n        final long now = System.currentTimeMillis();\n        try (InputStream is = new BufferedInputStream(mGrantFile.openRead())) {\n            final TypedXmlPullParser in = Xml.resolvePullParser(is);\n            int type;\n            while ((type = in.next()) != END_DOCUMENT) {\n                final String tag = in.getName();\n                if (type == START_TAG) {\n                    if (TAG_URI_GRANT.equals(tag)) {\n                        final int sourceUserId;\n                        final int targetUserId;\n                        final int userHandle = in.getAttributeInt(null, ATTR_USER_HANDLE,\n                                UserHandleHidden.USER_NULL);\n                        if (userHandle != UserHandleHidden.USER_NULL) {\n                            // For backwards compatibility.\n                            sourceUserId = userHandle;\n                            targetUserId = userHandle;\n                        } else {\n                            sourceUserId = in.getAttributeInt(null, ATTR_SOURCE_USER_ID);\n                            targetUserId = in.getAttributeInt(null, ATTR_TARGET_USER_ID);\n                        }\n                        final String sourcePkg = in.getAttributeValue(null, ATTR_SOURCE_PKG);\n                        final String targetPkg = in.getAttributeValue(null, ATTR_TARGET_PKG);\n                        final Uri uri = Uri.parse(in.getAttributeValue(null, ATTR_URI));\n                        final boolean prefix = in.getAttributeBoolean(null, ATTR_PREFIX, false);\n                        final int modeFlags = in.getAttributeInt(null, ATTR_MODE_FLAGS);\n                        final long createdTime = in.getAttributeLong(null, ATTR_CREATED_TIME, now);\n\n                        UriGrant uriGrant = new UriGrant(sourceUserId, targetUserId, userHandle,\n                                sourcePkg, targetPkg, uri, prefix, modeFlags, createdTime);\n                        synchronized (this) {\n                            ArrayList<UriGrant> uriGrants = mUriGrantsHashMap.get(targetPkg);\n                            if (uriGrants == null) {\n                                uriGrants = new ArrayList<>();\n                                mUriGrantsHashMap.put(targetPkg, uriGrants);\n                            }\n                            uriGrants.add(uriGrant);\n                        }\n                    }\n                }\n            }\n        } catch (FileNotFoundException e) {\n            // Missing grants is okay\n        } catch (IOException | XmlPullParserException | RemoteException e) {\n            Log.w(TAG, \"Failed reading Uri grants\", e);\n        }\n    }\n\n    public static class UriGrant {\n        public final int sourceUserId;\n        public final int targetUserId;\n        public final int userHandle;\n        public final String sourcePkg;\n        public final String targetPkg;\n        public final Uri uri;\n        public final boolean prefix;\n        public final int modeFlags;\n        public final long createdTime;\n\n        public UriGrant(int sourceUserId, int targetUserId, int userHandle, String sourcePkg,\n                        String targetPkg, Uri uri, boolean prefix, int modeFlags, long createdTime) {\n            this.sourceUserId = sourceUserId;\n            this.targetUserId = targetUserId;\n            this.userHandle = userHandle;\n            this.sourcePkg = sourcePkg;\n            this.targetPkg = targetPkg;\n            this.uri = uri;\n            this.prefix = prefix;\n            this.modeFlags = modeFlags;\n            this.createdTime = createdTime;\n        }\n\n        @NonNull\n        @Override\n        public String toString() {\n            // To preserve compatibility\n            return flattenToString();\n        }\n\n        public String flattenToString() {\n            return sourceUserId + \",\" + targetUserId + \",\" + userHandle + \",\" + sourcePkg + \",\" +\n                    targetPkg + \",\" + prefix + \",\" + modeFlags + \",\" + createdTime + \",\" + uri.toString();\n        }\n\n        @NonNull\n        public static UriGrant unflattenFromString(@NonNull String string) {\n            Objects.requireNonNull(string);\n            StringTokenizer tokenizer = new StringTokenizer(string, \",\");\n            int sourceUserId = Integer.parseInt(tokenizer.nextElement().toString());\n            int targetUserId = Integer.parseInt(tokenizer.nextElement().toString());\n            int userHandle = Integer.parseInt(tokenizer.nextElement().toString());\n            String sourcePkg = tokenizer.nextElement().toString();\n            String targetPkg = tokenizer.nextElement().toString();\n            boolean prefix = Boolean.parseBoolean(tokenizer.nextElement().toString());\n            int modeFlags = Integer.parseInt(tokenizer.nextElement().toString());\n            long createdTime = Long.parseLong(tokenizer.nextElement().toString());\n            StringBuilder uriString = new StringBuilder(tokenizer.nextElement().toString());\n            while (tokenizer.hasMoreElements()) {\n                uriString.append(\",\").append(tokenizer.nextElement().toString());\n            }\n            Uri uri = Uri.parse(uriString.toString());\n            return new UriGrant(sourceUserId, targetUserId, userHandle, sourcePkg, targetPkg, uri,\n                    prefix, modeFlags, createdTime);\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/usage/AppUsageActivity.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.usage;\n\nimport android.Manifest;\nimport android.annotation.SuppressLint;\nimport android.content.ActivityNotFoundException;\nimport android.content.Intent;\nimport android.os.Bundle;\nimport android.provider.Settings;\nimport android.view.Menu;\nimport android.view.MenuItem;\nimport android.view.View;\nimport android.widget.ArrayAdapter;\n\nimport androidx.activity.result.contract.ActivityResultContracts;\nimport androidx.annotation.NonNull;\nimport androidx.appcompat.app.ActionBar;\nimport androidx.core.app.ActivityCompat;\nimport androidx.lifecycle.ViewModelProvider;\n\nimport com.google.android.material.dialog.MaterialAlertDialogBuilder;\nimport com.google.android.material.progressindicator.LinearProgressIndicator;\n\nimport io.github.muntashirakon.AppManager.BaseActivity;\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.self.SelfPermissions;\nimport io.github.muntashirakon.AppManager.settings.FeatureController;\nimport io.github.muntashirakon.AppManager.utils.BetterActivityResult;\nimport io.github.muntashirakon.AppManager.utils.UIUtils;\nimport io.github.muntashirakon.adapters.SelectedArrayAdapter;\nimport io.github.muntashirakon.util.AccessibilityUtils;\nimport io.github.muntashirakon.util.UiUtils;\nimport io.github.muntashirakon.view.ProgressIndicatorCompat;\nimport io.github.muntashirakon.widget.MaterialSpinner;\nimport io.github.muntashirakon.widget.RecyclerView;\nimport io.github.muntashirakon.widget.SwipeRefreshLayout;\n\npublic class AppUsageActivity extends BaseActivity implements SwipeRefreshLayout.OnRefreshListener {\n    private static final int[] sSortMenuItemIdsMap = {\n            R.id.action_sort_by_app_label, R.id.action_sort_by_last_used,\n            R.id.action_sort_by_mobile_data, R.id.action_sort_by_package_name,\n            R.id.action_sort_by_screen_time, R.id.action_sort_by_times_opened,\n            R.id.action_sort_by_wifi_data};\n\n    AppUsageViewModel viewModel;\n    MaterialSpinner spinner;\n    RecyclerView recyclerView;\n    LinearProgressIndicator progressIndicator;\n    private SwipeRefreshLayout mSwipeRefresh;\n    private AppUsageAdapter mAppUsageAdapter;\n    private final BetterActivityResult<String, Boolean> mRequestPerm = BetterActivityResult\n            .registerForActivityResult(this, new ActivityResultContracts.RequestPermission());\n\n    @SuppressLint(\"WrongConstant\")\n    @Override\n    protected void onAuthenticated(Bundle savedInstanceState) {\n        if (!FeatureController.isUsageAccessEnabled()) {\n            finish();\n            return;\n        }\n        setContentView(R.layout.activity_app_usage);\n        setSupportActionBar(findViewById(R.id.toolbar));\n        viewModel = new ViewModelProvider(this).get(AppUsageViewModel.class);\n        ActionBar actionBar = getSupportActionBar();\n        if (actionBar != null) {\n            actionBar.setTitle(getString(R.string.app_usage));\n        }\n\n        progressIndicator = findViewById(R.id.progress_linear);\n        progressIndicator.setVisibilityAfterHide(View.GONE);\n\n        // Interval\n        spinner = findViewById(R.id.spinner);\n        UiUtils.applyWindowInsetsAsMargin(spinner, false, false);\n        spinner.requestFocus();\n        ArrayAdapter<CharSequence> intervalSpinnerAdapter = SelectedArrayAdapter.createFromResource(this,\n                R.array.usage_interval_dropdown_list, io.github.muntashirakon.ui.R.layout.auto_complete_dropdown_item_small);\n        spinner.setAdapter(intervalSpinnerAdapter);\n        spinner.setSelection(viewModel.getCurrentInterval());\n        spinner.setOnItemClickListener((parent, view, position, id) -> {\n            ProgressIndicatorCompat.setVisibility(progressIndicator, true);\n            viewModel.setCurrentInterval(position);\n        });\n\n        // Get usage stats\n        mAppUsageAdapter = new AppUsageAdapter(this);\n        recyclerView = findViewById(R.id.scrollView);\n        recyclerView.setEmptyView(findViewById(android.R.id.empty));\n        recyclerView.setLayoutManager(UIUtils.getGridLayoutAt450Dp(this));\n        recyclerView.setAdapter(mAppUsageAdapter);\n\n        mSwipeRefresh = findViewById(R.id.swipe_refresh);\n        mSwipeRefresh.setOnRefreshListener(this);\n        mSwipeRefresh.setOnChildScrollUpCallback((parent, child) -> recyclerView.canScrollVertically(-1));\n\n        viewModel.getPackageUsageInfoList().observe(this, packageUsageInfoList -> {\n            ProgressIndicatorCompat.setVisibility(progressIndicator, false);\n            mAppUsageAdapter.setDefaultList(packageUsageInfoList);\n            // Focus on the first item\n            recyclerView.post(() -> {\n                if (recyclerView.getChildCount() > 0) {\n                    View firstChild = recyclerView.getChildAt(0);\n                    if (firstChild != null) {\n                        AccessibilityUtils.requestAccessibilityFocus(firstChild);\n                    }\n                }\n            });\n        });\n        viewModel.getPackageUsageInfo().observe(this, packageUsageInfo -> {\n            AppUsageDetailsDialog fragment = AppUsageDetailsDialog.getInstance(packageUsageInfo,\n                    viewModel.getCurrentInterval(), viewModel.getCurrentDate());\n            fragment.show(getSupportFragmentManager(), AppUsageDetailsDialog.TAG);\n        });\n        checkPermissions();\n    }\n\n    @Override\n    public void onRefresh() {\n        mSwipeRefresh.setRefreshing(false);\n        checkPermissions();\n    }\n\n    private void checkPermissions() {\n        // Check permission\n        if (!SelfPermissions.checkUsageStatsPermission()) {\n            promptForUsageStatsPermission();\n        } else {\n            ProgressIndicatorCompat.setVisibility(progressIndicator, true);\n            viewModel.loadPackageUsageInfoList();\n        }\n        if (AppUsageStatsManager.requireReadPhoneStatePermission()) {\n            // Grant READ_PHONE_STATE permission\n            mRequestPerm.launch(Manifest.permission.READ_PHONE_STATE, granted -> {\n                if (granted) {\n                    ActivityCompat.recreate(this);\n                }\n            });\n        }\n    }\n\n    @Override\n    public boolean onCreateOptionsMenu(Menu menu) {\n        getMenuInflater().inflate(R.menu.activity_app_usage_actions, menu);\n        return super.onCreateOptionsMenu(menu);\n    }\n\n    @Override\n    public boolean onPrepareOptionsMenu(Menu menu) {\n        if (viewModel != null) {\n            menu.findItem(sSortMenuItemIdsMap[viewModel.getSortOrder()]).setChecked(true);\n        }\n        return super.onPrepareOptionsMenu(menu);\n    }\n\n    @Override\n    public boolean onOptionsItemSelected(@NonNull MenuItem item) {\n        int id = item.getItemId();\n        if (id == android.R.id.home) {\n            finish();\n        } else if (id == R.id.action_sort_by_app_label) {\n            setSortBy(SortOrder.SORT_BY_APP_LABEL);\n            item.setChecked(true);\n        } else if (id == R.id.action_sort_by_last_used) {\n            setSortBy(SortOrder.SORT_BY_LAST_USED);\n            item.setChecked(true);\n        } else if (id == R.id.action_sort_by_mobile_data) {\n            setSortBy(SortOrder.SORT_BY_MOBILE_DATA);\n            item.setChecked(true);\n        } else if (id == R.id.action_sort_by_package_name) {\n            setSortBy(SortOrder.SORT_BY_PACKAGE_NAME);\n            item.setChecked(true);\n        } else if (id == R.id.action_sort_by_screen_time) {\n            setSortBy(SortOrder.SORT_BY_SCREEN_TIME);\n            item.setChecked(true);\n        } else if (id == R.id.action_sort_by_times_opened) {\n            setSortBy(SortOrder.SORT_BY_TIMES_OPENED);\n            item.setChecked(true);\n        } else if (id == R.id.action_sort_by_wifi_data) {\n            setSortBy(SortOrder.SORT_BY_WIFI_DATA);\n            item.setChecked(true);\n        } else return super.onOptionsItemSelected(item);\n        return true;\n    }\n\n    private void setSortBy(@SortOrder int sort) {\n        if (viewModel != null) {\n            viewModel.setSortOrder(sort);\n        }\n    }\n\n    private void promptForUsageStatsPermission() {\n        new MaterialAlertDialogBuilder(this)\n                .setTitle(R.string.grant_usage_access)\n                .setMessage(R.string.grant_usage_acess_message)\n                .setPositiveButton(R.string.go, (dialog, which) -> {\n                    try {\n                        startActivity(new Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS));\n                    } catch (ActivityNotFoundException e) {\n                        // Usage access isn't available\n                        new MaterialAlertDialogBuilder(this)\n                                .setCancelable(false)\n                                .setTitle(R.string.grant_usage_access)\n                                .setMessage(R.string.usage_access_not_supported)\n                                .setPositiveButton(R.string.go_back, (dialog1, which1) -> {\n                                    FeatureController.getInstance().modifyState(FeatureController\n                                            .FEAT_USAGE_ACCESS, false);\n                                    finish();\n                                })\n                                .show();\n                    }\n                })\n                .setNegativeButton(getString(R.string.go_back), (dialog, which) -> finish())\n                .setCancelable(false)\n                .show();\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/usage/AppUsageAdapter.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.usage;\n\nimport android.graphics.drawable.Drawable;\nimport android.text.format.Formatter;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.ImageView;\n\nimport androidx.annotation.GuardedBy;\nimport androidx.annotation.NonNull;\nimport androidx.core.content.ContextCompat;\n\nimport com.google.android.material.button.MaterialButton;\nimport com.google.android.material.progressindicator.LinearProgressIndicator;\nimport com.google.android.material.textview.MaterialTextView;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Objects;\n\nimport io.github.muntashirakon.AppManager.BuildConfig;\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.self.imagecache.ImageLoader;\nimport io.github.muntashirakon.AppManager.utils.DateUtils;\nimport io.github.muntashirakon.AppManager.utils.UIUtils;\nimport io.github.muntashirakon.util.AdapterUtils;\nimport io.github.muntashirakon.widget.RecyclerView;\n\nclass AppUsageAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {\n    private static final int VIEW_TYPE_HEADER = 1;\n    private static final int VIEW_TYPE_LIST_ITEM = 2;\n\n    @GuardedBy(\"mAdapterList\")\n    private final List<PackageUsageInfo> mAdapterList = new ArrayList<>();\n    private final AppUsageActivity mActivity;\n\n    static class ListHeaderViewHolder extends RecyclerView.ViewHolder {\n        final MaterialTextView screenTimeView;\n        final MaterialTextView usageIntervalView;\n        final MaterialButton previousButton;\n        final MaterialButton nextButton;\n        final BarChartView barChartView;\n\n        public ListHeaderViewHolder(@NonNull View itemView) {\n            super(itemView);\n            screenTimeView = itemView.findViewById(R.id.screen_time);\n            usageIntervalView = itemView.findViewById(R.id.time);\n            previousButton = itemView.findViewById(R.id.action_previous);\n            nextButton = itemView.findViewById(R.id.action_next);\n            barChartView = itemView.findViewById(R.id.bar_chart);\n        }\n    }\n\n    static class ListItemViewHolder extends RecyclerView.ViewHolder {\n        ImageView appIcon;\n        MaterialTextView appLabel;\n        MaterialTextView badge;\n        MaterialTextView packageName;\n        MaterialTextView lastUsageDate;\n        MaterialTextView mobileDataUsage;\n        MaterialTextView wifiDataUsage;\n        MaterialTextView screenTime;\n        MaterialTextView percentUsage;\n        LinearProgressIndicator usageIndicator;\n\n        public ListItemViewHolder(@NonNull View itemView) {\n            super(itemView);\n            appIcon = itemView.findViewById(R.id.icon);\n            appIcon.setClipToOutline(true);\n            badge = itemView.findViewById(R.id.badge);\n            appLabel = itemView.findViewById(R.id.label);\n            packageName = itemView.findViewById(R.id.package_name);\n            lastUsageDate = itemView.findViewById(R.id.date);\n            mobileDataUsage = itemView.findViewById(R.id.data_usage);\n            wifiDataUsage = itemView.findViewById(R.id.wifi_usage);\n            screenTime = itemView.findViewById(R.id.screen_time);\n            percentUsage = itemView.findViewById(R.id.percent_usage);\n            usageIndicator = itemView.findViewById(R.id.progress_linear);\n        }\n    }\n\n    AppUsageAdapter(@NonNull AppUsageActivity activity) {\n        mActivity = activity;\n    }\n\n    void setDefaultList(List<PackageUsageInfo> list) {\n        synchronized (mAdapterList) {\n            notifyItemChanged(0, AdapterUtils.STUB);\n            AdapterUtils.notifyDataSetChanged(this, 1, mAdapterList, list);\n        }\n    }\n\n    @Override\n    public int getItemViewType(int position) {\n        if (position == 0) {\n            return VIEW_TYPE_HEADER;\n        }\n        return VIEW_TYPE_LIST_ITEM;\n    }\n\n    @Override\n    public int getItemCount() {\n        synchronized (mAdapterList) {\n            return mAdapterList.size();\n        }\n    }\n\n    @Override\n    public long getItemId(int position) {\n        if (position == 0) {\n            return 0;\n        }\n        synchronized (mAdapterList) {\n            return Objects.hashCode(mAdapterList.get(position));\n        }\n    }\n\n    @NonNull\n    @Override\n    public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {\n        View view;\n        switch (viewType) {\n            case VIEW_TYPE_HEADER:\n                view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_app_usage_header, parent, false);\n                return new ListHeaderViewHolder(view);\n            case VIEW_TYPE_LIST_ITEM:\n            default:\n                view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_app_usage, parent, false);\n                return new ListItemViewHolder(view);\n        }\n    }\n\n    @Override\n    public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {\n        if (position == 0) {\n            onBindViewHolder((ListHeaderViewHolder) holder);\n        } else onBindViewHolder((ListItemViewHolder) holder, position);\n    }\n\n    public void onBindViewHolder(@NonNull ListHeaderViewHolder holder) {\n        int intervalType = mActivity.viewModel.getCurrentInterval();\n        long duration = mActivity.viewModel.getTotalScreenTime();\n        long date = mActivity.viewModel.getCurrentDate();\n        CharSequence formattedDuration = DateUtils.getFormattedDuration(mActivity, duration);\n        CharSequence intervalDescription = UsageUtils.getIntervalDescription(mActivity, intervalType, date);\n        StringBuilder contentDescription = new StringBuilder()\n                .append(mActivity.getString(R.string.app_usage))\n                .append(\" \")\n                .append(intervalDescription)\n                .append(\". \")\n                .append(formattedDuration);\n        holder.itemView.setContentDescription(contentDescription);\n        holder.screenTimeView.setText(formattedDuration);\n        holder.usageIntervalView.setText(intervalDescription);\n        holder.nextButton.setVisibility(UsageUtils.hasNextDay(date) ? View.VISIBLE : View.INVISIBLE);\n        holder.nextButton.setOnClickListener(v -> mActivity.viewModel.loadNext());\n        holder.previousButton.setOnClickListener(v -> mActivity.viewModel.loadPrevious());\n        UsageDataProcessor.updateChartWithAppUsage(holder.barChartView, mActivity.viewModel.getPackageUsageEntries(), intervalType, date);\n    }\n\n    public void onBindViewHolder(@NonNull ListItemViewHolder holder, int position) {\n        final PackageUsageInfo usageInfo;\n        synchronized (mAdapterList) {\n            usageInfo = mAdapterList.get(position);\n        }\n        final int percentUsage = getUsagePercent(usageInfo.screenTime);\n        // Set label (or package name on failure)\n        holder.appLabel.setText(usageInfo.appLabel);\n        // Set icon\n        holder.appIcon.setTag(usageInfo.packageName);\n        ImageLoader.getInstance().displayImage(usageInfo.packageName, usageInfo.applicationInfo, holder.appIcon);\n        // Set user ID\n        if (mActivity.viewModel.hasMultipleUsers()) {\n            holder.badge.setVisibility(View.VISIBLE);\n            holder.badge.setText(String.format(Locale.getDefault(), \"%d\", usageInfo.userId));\n        } else {\n            holder.badge.setVisibility(View.GONE);\n        }\n        // Set package name\n        holder.packageName.setText(usageInfo.packageName);\n        // Set usage\n        long lastTimeUsed = usageInfo.lastUsageTime > 1 ? (System.currentTimeMillis() - usageInfo.lastUsageTime) : 0;\n        long currentDate = mActivity.viewModel.getCurrentDate();\n        if (usageInfo.packageName.equals(BuildConfig.APPLICATION_ID) && UsageUtils.isToday(currentDate)) {\n            // Special case for App Manager since the user is using the app right now\n            holder.lastUsageDate.setText(R.string.running);\n        } else if (lastTimeUsed > 1) {\n            holder.lastUsageDate.setText(String.format(Locale.getDefault(), \"%s %s\",\n                    DateUtils.getFormattedDuration(mActivity, lastTimeUsed), mActivity.getString(R.string.ago)));\n        } else {\n            holder.lastUsageDate.setText(R.string._undefined);\n        }\n        String screenTimesWithTimesOpened;\n        // Set times opened\n        screenTimesWithTimesOpened = mActivity.getResources().getQuantityString(R.plurals.no_of_times_opened, usageInfo.timesOpened, usageInfo.timesOpened);\n        // Set screen time\n        screenTimesWithTimesOpened += \", \" + DateUtils.getFormattedDuration(mActivity, usageInfo.screenTime);\n        holder.screenTime.setText(screenTimesWithTimesOpened);\n        // Set data usage\n        AppUsageStatsManager.DataUsage mobileData = usageInfo.mobileData;\n        if (mobileData != null && (mobileData.first != 0 || mobileData.second != 0)) {\n            Drawable phoneIcon = ContextCompat.getDrawable(mActivity, R.drawable.ic_phone_android);\n            String dataUsage = String.format(\"  ↑ %1$s ↓ %2$s\",\n                    Formatter.formatFileSize(mActivity, mobileData.first),\n                    Formatter.formatFileSize(mActivity, mobileData.second));\n            holder.mobileDataUsage.setText(UIUtils.setImageSpan(dataUsage, phoneIcon, holder.mobileDataUsage));\n        } else holder.mobileDataUsage.setText(\"\");\n        AppUsageStatsManager.DataUsage wifiData = usageInfo.wifiData;\n        if (wifiData != null && (wifiData.first != 0 || wifiData.second != 0)) {\n            Drawable wifiIcon = ContextCompat.getDrawable(mActivity, R.drawable.ic_wifi);\n            String dataUsage = String.format(\"  ↑ %1$s ↓ %2$s\",\n                    Formatter.formatFileSize(mActivity, wifiData.first),\n                    Formatter.formatFileSize(mActivity, wifiData.second));\n            holder.wifiDataUsage.setText(UIUtils.setImageSpan(dataUsage, wifiIcon, holder.wifiDataUsage));\n        } else holder.wifiDataUsage.setText(\"\");\n        // Set usage percentage\n        holder.percentUsage.setText(String.format(Locale.getDefault(), \"%d%%\", percentUsage));\n        holder.usageIndicator.show();\n        holder.usageIndicator.setProgress(percentUsage);\n        // On Click Listener\n        holder.itemView.setOnClickListener(v -> mActivity.viewModel.loadPackageUsageInfo(usageInfo));\n    }\n\n    int getUsagePercent(long screenTime) {\n        return (int) (screenTime * 100. / mActivity.viewModel.getTotalScreenTime());\n    }\n}"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/usage/AppUsageDetailsDialog.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.usage;\n\nimport android.content.Intent;\nimport android.content.pm.ApplicationInfo;\nimport android.content.pm.PackageManager;\nimport android.os.Bundle;\nimport android.text.format.Formatter;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.appcompat.widget.LinearLayoutCompat;\nimport androidx.core.os.BundleCompat;\nimport androidx.fragment.app.FragmentActivity;\n\nimport com.google.android.material.textfield.TextInputLayout;\n\nimport java.util.Locale;\n\nimport io.github.muntashirakon.AppManager.BuildConfig;\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.details.AppDetailsActivity;\nimport io.github.muntashirakon.AppManager.utils.DateUtils;\nimport io.github.muntashirakon.dialog.CapsuleBottomSheetDialogFragment;\nimport io.github.muntashirakon.dialog.DialogTitleBuilder;\nimport io.github.muntashirakon.view.TextInputLayoutCompat;\nimport io.github.muntashirakon.widget.TextInputTextView;\n\npublic class AppUsageDetailsDialog extends CapsuleBottomSheetDialogFragment {\n    public static final String TAG = AppUsageDetailsDialog.class.getSimpleName();\n\n    private static final String ARG_PACKAGE_USAGE_INFO = \"pkg_usg_info\";\n    private static final String ARG_INTERVAL_TYPE = \"interval\";\n    private static final String ARG_DATE = \"date\";\n\n    @NonNull\n    public static AppUsageDetailsDialog getInstance(@Nullable PackageUsageInfo usageInfo,\n                                                    @IntervalType int interval, long date) {\n        AppUsageDetailsDialog fragment = new AppUsageDetailsDialog();\n        Bundle args = new Bundle();\n        args.putParcelable(AppUsageDetailsDialog.ARG_PACKAGE_USAGE_INFO, usageInfo);\n        args.putInt(ARG_INTERVAL_TYPE, interval);\n        args.putLong(ARG_DATE, date);\n        fragment.setArguments(args);\n        return fragment;\n    }\n\n    @NonNull\n    @Override\n    public View initRootView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {\n        return inflater.inflate(R.layout.dialog_app_usage_details, container, false);\n    }\n\n    @Override\n    public boolean displayLoaderByDefault() {\n        return true;\n    }\n\n    @Override\n    public void onBodyInitialized(@NonNull View view, @Nullable Bundle savedInstanceState) {\n        FragmentActivity activity = requireActivity();\n        PackageUsageInfo usageInfo = BundleCompat.getParcelable(requireArguments(), ARG_PACKAGE_USAGE_INFO, PackageUsageInfo.class);\n        if (usageInfo == null) {\n            finishLoading();\n            return;\n        }\n        @IntervalType int intervalType = requireArguments().getInt(ARG_INTERVAL_TYPE);\n        long date = requireArguments().getLong(ARG_DATE);\n        // Set header first\n        DialogTitleBuilder titleBuilder = new DialogTitleBuilder(activity)\n                .setTitle(usageInfo.appLabel)\n                .setTitleSelectable(true)\n                .setSubtitle(usageInfo.packageName)\n                .setSubtitleSelectable(true)\n                .setEndIcon(io.github.muntashirakon.ui.R.drawable.ic_information, v -> {\n                    Intent appDetailsIntent = AppDetailsActivity.getIntent(activity, usageInfo.packageName,\n                            usageInfo.userId);\n                    startActivity(appDetailsIntent);\n                })\n                .setEndIconContentDescription(R.string.app_info);\n        ApplicationInfo applicationInfo = usageInfo.applicationInfo;\n        if (applicationInfo != null) {\n            PackageManager pm = activity.getPackageManager();\n            titleBuilder.setStartIcon(applicationInfo.loadIcon(pm));\n        }\n        setHeader(titleBuilder.build());\n\n        final BarChartView barChartView;\n        final TextInputTextView screenTime = view.findViewById(R.id.screen_time);\n        final TextInputTextView timesOpened = view.findViewById(R.id.times_opened);\n        final TextInputTextView lastUsed = view.findViewById(R.id.last_used);\n        final TextInputTextView userId = view.findViewById(R.id.user_id);\n        final TextInputTextView mobileDataUsage = view.findViewById(R.id.data_usage);\n        final TextInputLayout mobileDataUsageLayout = TextInputLayoutCompat.fromTextInputEditText(mobileDataUsage);\n        final TextInputTextView wifiDataUsage = view.findViewById(R.id.wifi_usage);\n        final TextInputLayout wifiDataUsageLayout = TextInputLayoutCompat.fromTextInputEditText(wifiDataUsage);\n        final LinearLayoutCompat dataUsageLayout = view.findViewById(R.id.data_usage_layout);\n        barChartView = view.findViewById(R.id.bar_chart);\n\n        AppUsageStatsManager.DataUsage mobileData = usageInfo.mobileData;\n        AppUsageStatsManager.DataUsage wifiData = usageInfo.wifiData;\n\n        screenTime.setText(DateUtils.getFormattedDuration(requireContext(), usageInfo.screenTime));\n        timesOpened.setText(getResources().getQuantityString(R.plurals.no_of_times_opened,\n                usageInfo.timesOpened, usageInfo.timesOpened));\n        long lastRun = usageInfo.lastUsageTime > 1 ? (System.currentTimeMillis() - usageInfo.lastUsageTime) : 0;\n        if (usageInfo.packageName.equals(BuildConfig.APPLICATION_ID)) {\n            // Special case for App Manager since the user is using the app right now\n            lastUsed.setText(R.string.running);\n        } else if (lastRun > 1) {\n            lastUsed.setText(String.format(Locale.getDefault(), \"%s %s\", DateUtils\n                    .getFormattedDuration(requireContext(), lastRun), getString(R.string.ago)));\n        } else {\n            lastUsed.setText(R.string._undefined);\n        }\n        userId.setText(String.format(Locale.getDefault(), \"%d\", usageInfo.userId));\n        if ((mobileData == null && wifiData == null) || (mobileData != null && wifiData != null\n                && (mobileData.getTotal() + wifiData.getTotal() == 0))) {\n            dataUsageLayout.setVisibility(View.GONE);\n        } else {\n            dataUsageLayout.setVisibility(View.VISIBLE);\n            if (mobileData != null && mobileData.getTotal() != 0) {\n                String dataUsage = String.format(\"  ↑ %1$s ↓ %2$s\",\n                        Formatter.formatFileSize(requireContext(), mobileData.first),\n                        Formatter.formatFileSize(requireContext(), mobileData.second));\n                mobileDataUsageLayout.setVisibility(View.VISIBLE);\n                mobileDataUsage.setText(dataUsage);\n            } else mobileDataUsageLayout.setVisibility(View.GONE);\n            if (wifiData != null && wifiData.getTotal() != 0) {\n                String dataUsage = String.format(\"  ↑ %1$s ↓ %2$s\",\n                        Formatter.formatFileSize(requireContext(), wifiData.first),\n                        Formatter.formatFileSize(requireContext(), wifiData.second));\n                wifiDataUsageLayout.setVisibility(View.VISIBLE);\n                wifiDataUsage.setText(dataUsage);\n            } else wifiDataUsageLayout.setVisibility(View.GONE);\n        }\n        if (usageInfo.entries != null) {\n            UsageDataProcessor.updateChartWithAppUsage(barChartView, usageInfo.entries, intervalType, date);\n        }\n\n        // Load the body\n        requireView().postDelayed(this::finishLoading, 300);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/usage/AppUsageStatsManager.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.usage;\n\nimport static android.net.NetworkCapabilities.TRANSPORT_CELLULAR;\nimport static android.net.NetworkCapabilities.TRANSPORT_WIFI;\nimport static io.github.muntashirakon.AppManager.compat.PackageManagerCompat.MATCH_UNINSTALLED_PACKAGES;\n\nimport android.Manifest;\nimport android.annotation.SuppressLint;\nimport android.annotation.UserIdInt;\nimport android.app.usage.UsageEvents;\nimport android.content.Context;\nimport android.content.pm.ApplicationInfo;\nimport android.content.pm.PackageManager;\nimport android.net.NetworkCapabilities;\nimport android.net.NetworkStats;\nimport android.os.Build;\nimport android.os.Parcel;\nimport android.os.Parcelable;\nimport android.os.RemoteException;\nimport android.os.UserHandleHidden;\nimport android.telephony.SubscriptionInfo;\nimport android.telephony.TelephonyManager;\n\nimport androidx.annotation.IntDef;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.RequiresApi;\nimport androidx.annotation.RequiresPermission;\nimport androidx.collection.SparseArrayCompat;\nimport androidx.core.util.Pair;\n\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.Stack;\n\nimport io.github.muntashirakon.AppManager.compat.ManifestCompat;\nimport io.github.muntashirakon.AppManager.compat.NetworkStatsCompat;\nimport io.github.muntashirakon.AppManager.compat.NetworkStatsManagerCompat;\nimport io.github.muntashirakon.AppManager.compat.PackageManagerCompat;\nimport io.github.muntashirakon.AppManager.compat.SubscriptionManagerCompat;\nimport io.github.muntashirakon.AppManager.compat.UsageStatsManagerCompat;\nimport io.github.muntashirakon.AppManager.logs.Log;\nimport io.github.muntashirakon.AppManager.self.SelfPermissions;\nimport io.github.muntashirakon.AppManager.utils.ContextUtils;\nimport io.github.muntashirakon.AppManager.utils.ExUtils;\nimport io.github.muntashirakon.AppManager.utils.Utils;\nimport io.github.muntashirakon.proc.ProcFs;\nimport io.github.muntashirakon.proc.ProcUidNetStat;\n\npublic class AppUsageStatsManager {\n    public static final String TAG = AppUsageStatsManager.class.getSimpleName();\n\n    @Retention(RetentionPolicy.SOURCE)\n    @IntDef(value = {\n            TRANSPORT_CELLULAR,\n            TRANSPORT_WIFI\n    })\n    public @interface Transport {\n    }\n\n    public static final class DataUsage extends Pair<Long, Long> implements Parcelable, Comparable<DataUsage> {\n        public static final DataUsage EMPTY = new DataUsage(0, 0);\n\n        public static DataUsage fromDataUsage(DataUsage... dataUsages) {\n            if (dataUsages == null) {\n                return EMPTY;\n            }\n            long tx = 0, rx = 0;\n            for (DataUsage dataUsage : dataUsages) {\n                tx += dataUsage.getTx();\n                rx += dataUsage.getRx();\n            }\n            return new DataUsage(tx, rx);\n        }\n\n        private final long mTotal;\n\n        public DataUsage(long tx, long rx) {\n            super(tx, rx);\n            mTotal = tx + rx;\n        }\n\n        private DataUsage(@NonNull Parcel in) {\n            super(in.readLong(), in.readLong());\n            mTotal = first + second;\n        }\n\n        public static final Creator<DataUsage> CREATOR = new Creator<DataUsage>() {\n            @NonNull\n            @Override\n            public DataUsage createFromParcel(Parcel in) {\n                return new DataUsage(in);\n            }\n\n            @NonNull\n            @Override\n            public DataUsage[] newArray(int size) {\n                return new DataUsage[size];\n            }\n        };\n\n        public long getTx() {\n            return first;\n        }\n\n        public long getRx() {\n            return second;\n        }\n\n        public long getTotal() {\n            return mTotal;\n        }\n\n        @Override\n        public int describeContents() {\n            return 0;\n        }\n\n        @Override\n        public void writeToParcel(Parcel dest, int flags) {\n            dest.writeLong(first);\n            dest.writeLong(second);\n        }\n\n        @Override\n        public int compareTo(@Nullable DataUsage o) {\n            if (o == null) return 1;\n            return Long.compare(mTotal, o.mTotal);\n        }\n    }\n\n    public static boolean requireReadPhoneStatePermission() {\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && Build.VERSION.SDK_INT < Build.VERSION_CODES.P) {\n            return !SelfPermissions.checkSelfOrRemotePermission(Manifest.permission.READ_PHONE_STATE);\n        }\n        return false;\n    }\n\n    @SuppressLint(\"StaticFieldLeak\")\n    private static AppUsageStatsManager appUsageStatsManager;\n\n    public static AppUsageStatsManager getInstance() {\n        if (appUsageStatsManager == null)\n            appUsageStatsManager = new AppUsageStatsManager();\n        return appUsageStatsManager;\n    }\n\n    @SuppressLint(\"InlinedApi\") // These are constant values, API compatibility does not apply\n    private static final int[] USUAL_ACTIVITY_EVENTS = new int[]{\n            UsageEvents.Event.ACTIVITY_RESUMED,\n            UsageEvents.Event.ACTIVITY_PAUSED,\n            UsageEvents.Event.ACTIVITY_STOPPED,\n            UsageEvents.Event.DEVICE_SHUTDOWN,\n    };\n\n    @NonNull\n    private final Context mContext;\n\n    @SuppressLint(\"WrongConstant\")\n    private AppUsageStatsManager() {\n        mContext = ContextUtils.getContext();\n    }\n\n    /**\n     * Calculate screen time based on the assumption that no application can be run in the middle of\n     * a running application. This is a valid assumption since <code>Activity#onPause()</code> is\n     * called whenever an app goes to background and <code>Activity#onResume</code> is called\n     * whenever an app appears in foreground.\n     *\n     * @param interval Usage interval\n     * @return A list of package usage\n     * @throws SecurityException If usage stats permission is not available for the user\n     * @throws RemoteException   If usage stats cannot be retrieved due to transaction error\n     */\n    @RequiresPermission(\"android.permission.PACKAGE_USAGE_STATS\")\n    @NonNull\n    public List<PackageUsageInfo> getUsageStats(@NonNull TimeInterval interval, @UserIdInt int userId)\n            throws RemoteException, SecurityException {\n        List<PackageUsageInfo> packageUsageInfoList = new ArrayList<>();\n        int _try = 5; // try to get usage stats at most 5 times\n        Throwable re;\n        do {\n            try {\n                packageUsageInfoList.addAll(getUsageStatsInternal(interval, userId));\n                re = null;\n            } catch (Throwable e) {\n                re = e;\n            }\n        } while (0 != --_try && packageUsageInfoList.isEmpty());\n        if (re != null) {\n            throw (RemoteException) (new RemoteException(re.getMessage()).initCause(re));\n        }\n        return packageUsageInfoList;\n    }\n\n    @RequiresPermission(\"android.permission.PACKAGE_USAGE_STATS\")\n    @NonNull\n    public PackageUsageInfo getUsageStatsForPackage(@NonNull String packageName,\n                                                    @NonNull TimeInterval range,\n                                                    @UserIdInt int userId)\n            throws RemoteException, PackageManager.NameNotFoundException {\n        ApplicationInfo applicationInfo = PackageManagerCompat.getApplicationInfo(packageName, MATCH_UNINSTALLED_PACKAGES\n                | PackageManagerCompat.MATCH_STATIC_SHARED_AND_SDK_LIBRARIES, userId);\n        PackageUsageInfo packageUsageInfo = new PackageUsageInfo(mContext, packageName, userId, applicationInfo);\n        PerPackageUsageInternal usage = new PerPackageUsageInternal(packageName);\n        List<UsageEvents.Event> events = UsageStatsManagerCompat.queryEventsSorted(range.getStartTime(), range.getEndTime(), userId, USUAL_ACTIVITY_EVENTS);\n        long lastShutdownTime = 0L;\n        for (UsageEvents.Event event : events) {\n            int eventType = event.getEventType();\n            if (eventType == UsageEvents.Event.DEVICE_SHUTDOWN) {\n                lastShutdownTime = event.getTimeStamp();\n            } else if (Objects.equals(packageName, event.getPackageName())) {\n                // Queries are sorted in descending order, so a not-running activity should be paused\n                // or stopped first and then resumed (i.e., reversed logic)\n                if (isActivityClosed(eventType)) {\n                    usage.setLastEndTime(event.getTimeStamp());\n                } else if (isActivityOpened(eventType)) {\n                    if (lastShutdownTime != 0L) {\n                        // The device was shutdown. Adding the shutdown time here as no impact if\n                        // the event already has an end time.\n                        usage.setLastEndTime(lastShutdownTime);\n                    }\n                    usage.setLastStartTime(event.getTimeStamp());\n                }\n            }\n        }\n        packageUsageInfo.entries = usage.entries;\n        return packageUsageInfo;\n    }\n\n    private static class PerPackageUsageInternal {\n        @NonNull\n        public final String packageName;\n        public final Stack<PackageUsageInfo.Entry> entries = new Stack<>();\n        public long screenTime = 0;\n        public long lastUsed = 0;\n        public int accessCount = 0;\n\n        private long mLastStartTime = 0;\n        private long mLastEndTime = 0;\n        private boolean mOverrideLastEntry = false;\n\n        public PerPackageUsageInternal(@NonNull String packageName) {\n            this.packageName = packageName;\n        }\n\n        public void setLastStartTime(long startTime) {\n            // Start time is added last due to how events are sorted\n            if (mLastEndTime == 0) {\n                Log.d(TAG, \"End time is zero for package %s\", packageName);\n                return;\n            }\n            mLastStartTime = startTime;\n            // Add to entries\n            if (mOverrideLastEntry) {\n                mOverrideLastEntry = false;\n                PackageUsageInfo.Entry entry = entries.pop();\n                entries.push(new PackageUsageInfo.Entry(mLastStartTime, entry.endTime));\n                // Remove this screen time\n                screenTime -= entry.getDuration();\n            } else {\n                entries.push(new PackageUsageInfo.Entry(mLastStartTime, mLastEndTime));\n            }\n            // Add to screen time\n            screenTime += entries.peek().getDuration();\n            // Reset end time\n            mLastEndTime = 0;\n        }\n\n        public void setLastEndTime(long endTime) {\n            // End time is added first due to how events are sorted\n            if (mLastEndTime != 0) {\n                // Log.d(TAG, \"Start time non-zero (%d) for package %s\", mLastEndTime, packageName);\n                // Prefer stop times over pause. So, ignore all the subsequent events until an\n                // resume event is found. This may result in inaccurate access count. However,\n                // this inaccuracy is acceptable.\n                return;\n            }\n            mLastEndTime = endTime;\n            // Set access count\n            if (mLastStartTime > 0 && (mLastStartTime - mLastEndTime) <= 500) {\n                // 500 ms is a heuristic diff that depends on the processing speed & anim time.\n                // Request updating the last entry\n                mOverrideLastEntry = true;\n            } else ++accessCount;\n            // Set last used time if not already (we only add the first end time because of how\n            // the events are sorted)\n            if (lastUsed == 0) {\n                lastUsed = endTime;\n            }\n        }\n    }\n\n    /**\n     * Calculate screen time based on the assumption that no application can be run in the middle of\n     * a running application. This is a valid assumption since <code>Activity#onPause()</code> is\n     * called whenever an app goes to background and <code>Activity#onResume</code> is called\n     * whenever an app appears in foreground.\n     *\n     * @param interval Usage interval\n     * @return A list of package usage\n     */\n    @NonNull\n    private List<PackageUsageInfo> getUsageStatsInternal(@NonNull TimeInterval interval,\n                                                         @UserIdInt int userId) {\n        List<PackageUsageInfo> screenTimeList = new ArrayList<>();\n        Map<String, PerPackageUsageInternal> perPackageUsageMap = new HashMap<>();\n        // Get events\n        List<UsageEvents.Event> events = UsageStatsManagerCompat.queryEventsSorted(interval.getStartTime(), interval.getEndTime(), userId, USUAL_ACTIVITY_EVENTS);\n        long lastShutdownTime = 0L;\n        for (UsageEvents.Event event : events) {\n            int eventType = event.getEventType();\n            String packageName = event.getPackageName();\n            if (packageName == null) {\n                Log.i(TAG, \"Ignored event with empty package name: \" + Utils.prettyPrintObject(event));\n                continue;\n            }\n            // Queries are sorted in descending order, so a not-running activity should be paused or\n            // stopped first and then resumed (i.e., reversed logic).\n            if (eventType == UsageEvents.Event.DEVICE_SHUTDOWN) {\n                lastShutdownTime = event.getTimeStamp();\n            } else if (isActivityClosed(eventType)) {\n                PerPackageUsageInternal usage = perPackageUsageMap.get(packageName);\n                if (usage == null) {\n                    usage = new PerPackageUsageInternal(packageName);\n                    perPackageUsageMap.put(packageName, usage);\n                }\n                usage.setLastEndTime(event.getTimeStamp());\n            } else if (isActivityOpened(eventType)) {\n                PerPackageUsageInternal usage = perPackageUsageMap.get(packageName);\n                if (usage == null) {\n                    usage = new PerPackageUsageInternal(packageName);\n                    perPackageUsageMap.put(packageName, usage);\n                }\n                if (lastShutdownTime != 0L) {\n                    // The device was shutdown. Adding the shutdown time here as no impact if the\n                    // event already has an end time.\n                    usage.setLastEndTime(lastShutdownTime);\n                }\n                usage.setLastStartTime(event.getTimeStamp());\n            }\n        }\n        SparseArrayCompat<DataUsage> mobileData = getMobileData(interval);\n        SparseArrayCompat<DataUsage> wifiData = getWifiData(interval);\n        for (PerPackageUsageInternal usage : perPackageUsageMap.values()) {\n            // Skip uninstalled packages?\n            ApplicationInfo applicationInfo = ExUtils.exceptionAsNull(() -> PackageManagerCompat\n                    .getApplicationInfo(usage.packageName, MATCH_UNINSTALLED_PACKAGES\n                            | PackageManagerCompat.MATCH_STATIC_SHARED_AND_SDK_LIBRARIES, userId));\n            PackageUsageInfo packageUsageInfo = new PackageUsageInfo(mContext, usage.packageName, userId, applicationInfo);\n            packageUsageInfo.timesOpened = usage.accessCount;\n            packageUsageInfo.lastUsageTime = usage.lastUsed;\n            packageUsageInfo.screenTime = usage.screenTime;\n            int uid = applicationInfo != null ? applicationInfo.uid : 0;\n            if (mobileData.containsKey(uid)) {\n                packageUsageInfo.mobileData = mobileData.get(uid);\n            } else packageUsageInfo.mobileData = DataUsage.EMPTY;\n            if (wifiData.containsKey(uid)) {\n                packageUsageInfo.wifiData = wifiData.get(uid);\n            } else packageUsageInfo.wifiData = DataUsage.EMPTY;\n            packageUsageInfo.entries = usage.entries;\n            screenTimeList.add(packageUsageInfo);\n        }\n        return screenTimeList;\n    }\n\n    @SuppressLint(\"InlinedApi\") // These are constant values, API compatibility does not apply\n    private static boolean isActivityClosed(int eventType) {\n        return eventType == UsageEvents.Event.ACTIVITY_STOPPED\n                || eventType == UsageEvents.Event.ACTIVITY_PAUSED;\n    }\n\n    @SuppressLint(\"InlinedApi\") // These are constant values, API compatibility does not apply\n    private static boolean isActivityOpened(int eventType) {\n        return eventType == UsageEvents.Event.ACTIVITY_RESUMED;\n    }\n\n    @RequiresPermission(\"android.permission.PACKAGE_USAGE_STATS\")\n    public static long getLastActivityTime(String packageName, @NonNull TimeInterval interval) {\n        UsageEvents events = UsageStatsManagerCompat.queryEvents(interval.getStartTime(), interval.getEndTime(),\n                UserHandleHidden.myUserId());\n        if (events == null) return 0L;\n        UsageEvents.Event event = new UsageEvents.Event();\n        long lastTime = 0L;\n        while (events.hasNextEvent()) {\n            events.getNextEvent(event);\n            if (event.getPackageName().equals(packageName) && lastTime < event.getTimeStamp()) {\n                lastTime = event.getTimeStamp();\n            }\n        }\n        return lastTime;\n    }\n\n    @RequiresPermission(\"android.permission.PACKAGE_USAGE_STATS\")\n    @NonNull\n    public static SparseArrayCompat<DataUsage> getMobileData(@NonNull TimeInterval interval) {\n        return getDataUsageForNetwork(TRANSPORT_CELLULAR, interval);\n    }\n\n\n    @RequiresPermission(\"android.permission.PACKAGE_USAGE_STATS\")\n    @NonNull\n    public static SparseArrayCompat<DataUsage> getWifiData(@NonNull TimeInterval interval) {\n        return getDataUsageForNetwork(TRANSPORT_WIFI, interval);\n    }\n\n    @RequiresPermission(\"android.permission.PACKAGE_USAGE_STATS\")\n    @NonNull\n    public static SparseArrayCompat<DataUsage> getDataUsageForNetwork(@Transport int networkType,\n                                                                      @NonNull TimeInterval interval) {\n        SparseArrayCompat<DataUsage> dataUsageSparseArray = new SparseArrayCompat<>();\n        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {\n            @SuppressWarnings(\"deprecation\")\n            List<ProcUidNetStat> netStats = ProcFs.getInstance().getAllUidNetStat();\n            for (ProcUidNetStat netStat : netStats) {\n                dataUsageSparseArray.put(netStat.uid, new DataUsage(netStat.txBytes, netStat.rxBytes));\n            }\n            return dataUsageSparseArray;\n        }\n        List<String> subscriberIds = getSubscriberIds(networkType);\n        for (String subscriberId : subscriberIds) {\n            try (NetworkStatsCompat networkStats = NetworkStatsManagerCompat.querySummary(networkType, subscriberId,\n                    interval.getStartTime(), interval.getEndTime())) {\n                while (networkStats.hasNextEntry()) {\n                    NetworkStats.Entry entry = networkStats.getNextEntry(true);\n                    if (entry == null) {\n                        continue;\n                    }\n                    DataUsage dataUsage = dataUsageSparseArray.get(entry.uid);\n                    if (dataUsage != null) {\n                        dataUsage = new DataUsage(entry.txBytes + dataUsage.getTx(), entry.rxBytes + dataUsage.getRx());\n                    } else {\n                        dataUsage = new DataUsage(entry.txBytes, entry.rxBytes);\n                    }\n                    dataUsageSparseArray.put(entry.uid, dataUsage);\n                }\n            } catch (RemoteException | SecurityException | IllegalStateException e) {\n                e.printStackTrace();\n            }\n        }\n\n        return dataUsageSparseArray;\n    }\n\n    @RequiresPermission(\"android.permission.PACKAGE_USAGE_STATS\")\n    @NonNull\n    public static DataUsage getDataUsageForPackage(int uid, @NonNull TimeInterval range) {\n        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {\n            @SuppressWarnings(\"deprecation\")\n            ProcUidNetStat netStat = ProcFs.getInstance().getUidNetStat(uid);\n            return netStat != null ? new DataUsage(netStat.txBytes, netStat.rxBytes) : DataUsage.EMPTY;\n        }\n        List<String> subscriberIds;\n        long totalTx = 0;\n        long totalRx = 0;\n        for (int networkId = 0; networkId < 2; ++networkId) {\n            subscriberIds = getSubscriberIds(networkId);\n            for (String subscriberId : subscriberIds) {\n                try (NetworkStatsCompat networkStats = NetworkStatsManagerCompat.querySummary(networkId, subscriberId,\n                        range.getStartTime(), range.getEndTime())) {\n                    while (networkStats.hasNextEntry()) {\n                        NetworkStats.Entry entry = networkStats.getNextEntry(true);\n                        if (entry != null && entry.uid == uid) {\n                            totalTx += entry.txBytes;\n                            totalRx += entry.rxBytes;\n                        }\n                    }\n                } catch (RemoteException | SecurityException | IllegalStateException e) {\n                    e.printStackTrace();\n                }\n            }\n        }\n        return new DataUsage(totalTx, totalRx);\n    }\n\n    /**\n     * @return A list of subscriber IDs if networkType is {@link NetworkCapabilities#TRANSPORT_CELLULAR}, or\n     * a singleton array with {@code null} being the only element.\n     */\n    @SuppressLint({\"HardwareIds\", \"MissingPermission\"})\n    @RequiresApi(Build.VERSION_CODES.M) // LOLLIPOP_MR1, but we don't need it for API < 23\n    @NonNull\n    private static List<String> getSubscriberIds(@Transport int networkType) {\n        if (networkType != TRANSPORT_CELLULAR) {\n            // Unsupported API\n            return Collections.singletonList(null);\n        }\n        Context ctx = ContextUtils.getContext();\n        PackageManager pm = ctx.getPackageManager();\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU\n                && !pm.hasSystemFeature(PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION)) {\n            Log.i(TAG, \"No such feature: %s\", PackageManager.FEATURE_TELEPHONY_SUBSCRIPTION);\n            return Collections.emptyList();\n        } else if (!pm.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)) {\n            Log.i(TAG, \"No such feature: %s\", PackageManager.FEATURE_TELEPHONY);\n            return Collections.emptyList();\n        }\n        TelephonyManager telephonyManager = (TelephonyManager) ctx.getSystemService(Context.TELEPHONY_SERVICE);\n        if (telephonyManager.getPhoneType() == TelephonyManager.PHONE_TYPE_NONE) {\n            Log.i(TAG, \"Device does not have a phone radio.\");\n            return Collections.emptyList();\n        }\n        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q && !SelfPermissions.checkSelfOrRemotePermission(Manifest.permission.READ_PHONE_STATE)) {\n            Log.w(TAG, \"Missing required permission: %s\", Manifest.permission.READ_PHONE_STATE);\n            return Collections.emptyList();\n        }\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q && !SelfPermissions.checkSelfOrRemotePermission(ManifestCompat.permission.READ_PRIVILEGED_PHONE_STATE)) {\n            Log.w(TAG, \"Missing required permission: %s\", ManifestCompat.permission.READ_PRIVILEGED_PHONE_STATE);\n            return Collections.singletonList(null);\n        }\n        List<SubscriptionInfo> subscriptionInfoList = SubscriptionManagerCompat.getActiveSubscriptionInfoList();\n        if (subscriptionInfoList == null) {\n            Log.i(TAG, \"No subscriptions found.\");\n            return Collections.singletonList(null);\n        }\n        List<String> subscriberIds = new ArrayList<>();\n        for (SubscriptionInfo info : subscriptionInfoList) {\n            int subscriptionId = info.getSubscriptionId();\n            try {\n                String subscriberId = SubscriptionManagerCompat.getSubscriberIdForSubscriber(subscriptionId);\n                subscriberIds.add(subscriberId);\n            } catch (SecurityException ignore) {\n            }\n        }\n        return subscriberIds.isEmpty() ? Collections.singletonList(null) : subscriberIds;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/usage/AppUsageViewModel.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.usage;\n\nimport android.app.Application;\n\nimport androidx.annotation.AnyThread;\nimport androidx.annotation.NonNull;\nimport androidx.lifecycle.AndroidViewModel;\nimport androidx.lifecycle.LiveData;\nimport androidx.lifecycle.MutableLiveData;\n\nimport java.text.Collator;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Set;\n\nimport io.github.muntashirakon.AppManager.users.Users;\nimport io.github.muntashirakon.AppManager.utils.ExUtils;\nimport io.github.muntashirakon.AppManager.utils.ThreadUtils;\n\npublic class AppUsageViewModel extends AndroidViewModel {\n    private final MutableLiveData<List<PackageUsageInfo>> mPackageUsageInfoListLiveData = new MutableLiveData<>();\n    private final MutableLiveData<PackageUsageInfo> mPackageUsageInfoLiveData = new MutableLiveData<>();\n    private final List<PackageUsageInfo> mPackageUsageInfoList = Collections.synchronizedList(new ArrayList<>());\n    private final List<PackageUsageInfo.Entry> mPackageUsageEntries = Collections.synchronizedList(new ArrayList<>());\n\n    private long mTotalScreenTime;\n    private boolean mHasMultipleUsers;\n    @IntervalType\n    private int mCurrentInterval = IntervalType.INTERVAL_DAILY;\n    private long mCurrentDate = System.currentTimeMillis();\n    private int mSortOrder = SortOrder.SORT_BY_SCREEN_TIME;\n\n    public AppUsageViewModel(@NonNull Application application) {\n        super(application);\n    }\n\n    public LiveData<List<PackageUsageInfo>> getPackageUsageInfoList() {\n        return mPackageUsageInfoListLiveData;\n    }\n\n    public LiveData<PackageUsageInfo> getPackageUsageInfo() {\n        return mPackageUsageInfoLiveData;\n    }\n\n    public List<PackageUsageInfo.Entry> getPackageUsageEntries() {\n        return mPackageUsageEntries;\n    }\n\n    public void setCurrentDate(long currentDate) {\n        mCurrentDate = currentDate;\n        loadPackageUsageInfoList();\n    }\n\n    public long getCurrentDate() {\n        return mCurrentDate;\n    }\n\n    public void setCurrentInterval(@IntervalType int currentInterval) {\n        mCurrentInterval = currentInterval;\n        mCurrentDate = System.currentTimeMillis();\n        loadPackageUsageInfoList();\n    }\n\n    @IntervalType\n    public int getCurrentInterval() {\n        return mCurrentInterval;\n    }\n\n    public void setSortOrder(int sortOrder) {\n        mSortOrder = sortOrder;\n        ThreadUtils.postOnBackgroundThread(this::sortItems);\n    }\n\n    public int getSortOrder() {\n        return mSortOrder;\n    }\n\n    public long getTotalScreenTime() {\n        return mTotalScreenTime;\n    }\n\n    public boolean hasMultipleUsers() {\n        return mHasMultipleUsers;\n    }\n\n    public void loadNext() {\n        setCurrentDate(UsageUtils.getNextDateFromInterval(mCurrentInterval, mCurrentDate));\n    }\n\n    public void loadPrevious() {\n        setCurrentDate(UsageUtils.getPreviousDateFromInterval(mCurrentInterval, mCurrentDate));\n    }\n\n    public void loadPackageUsageInfo(PackageUsageInfo usageInfo) {\n        if (ThreadUtils.isMainThread()) {\n            mPackageUsageInfoLiveData.setValue(usageInfo);\n        } else {\n            mPackageUsageInfoLiveData.postValue(usageInfo);\n        }\n    }\n\n    @AnyThread\n    public void loadPackageUsageInfoList() {\n        ThreadUtils.postOnBackgroundThread(() -> {\n            int[] userIds = Users.getUsersIds();\n            AppUsageStatsManager usageStatsManager = AppUsageStatsManager.getInstance();\n            TimeInterval interval = UsageUtils.getTimeInterval(mCurrentInterval, mCurrentDate);\n            mPackageUsageInfoList.clear();\n            for (int userId : userIds) {\n                ExUtils.exceptionAsIgnored(() -> mPackageUsageInfoList.addAll(usageStatsManager\n                        .getUsageStats(interval, userId)));\n            }\n            mTotalScreenTime = 0;\n            Set<Integer> users = new HashSet<>(3);\n            mPackageUsageEntries.clear();\n            for (PackageUsageInfo appItem : mPackageUsageInfoList) {\n                if (appItem.entries != null) {\n                    mPackageUsageEntries.addAll(appItem.entries);\n                }\n                mTotalScreenTime += appItem.screenTime;\n                users.add(appItem.userId);\n            }\n            mHasMultipleUsers = users.size() > 1;\n            sortItems();\n        });\n    }\n\n    private void sortItems() {\n        Collator collator = Collator.getInstance();\n        Collections.sort(mPackageUsageInfoList, ((o1, o2) -> {\n            switch (mSortOrder) {\n                case SortOrder.SORT_BY_APP_LABEL:\n                    return collator.compare(o1.appLabel, o2.appLabel);\n                case SortOrder.SORT_BY_LAST_USED:\n                    return -Long.compare(o1.lastUsageTime, o2.lastUsageTime);\n                case SortOrder.SORT_BY_MOBILE_DATA:\n                    if (o1.mobileData == null) return o2.mobileData == null ? 0 : -1;\n                    return -o1.mobileData.compareTo(o2.mobileData);\n                case SortOrder.SORT_BY_PACKAGE_NAME:\n                    return o1.packageName.compareToIgnoreCase(o2.packageName);\n                case SortOrder.SORT_BY_SCREEN_TIME:\n                    return -Long.compare(o1.screenTime, o2.screenTime);\n                case SortOrder.SORT_BY_TIMES_OPENED:\n                    return -Integer.compare(o1.timesOpened, o2.timesOpened);\n                case SortOrder.SORT_BY_WIFI_DATA:\n                    if (o1.wifiData == null) return o2.wifiData == null ? 0 : -1;\n                    return -o1.wifiData.compareTo(o2.wifiData);\n            }\n            return 0;\n        }));\n        mPackageUsageInfoListLiveData.postValue(mPackageUsageInfoList);\n    }\n}"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/usage/BarChartView.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.usage;\n\nimport static com.google.android.material.theme.overlay.MaterialThemeOverlay.wrap;\n\nimport android.annotation.SuppressLint;\nimport android.content.Context;\nimport android.graphics.Canvas;\nimport android.graphics.DashPathEffect;\nimport android.graphics.Paint;\nimport android.graphics.Rect;\nimport android.os.Bundle;\nimport android.text.TextUtils;\nimport android.util.AttributeSet;\nimport android.view.KeyEvent;\nimport android.view.MotionEvent;\nimport android.view.View;\nimport android.view.accessibility.AccessibilityEvent;\n\nimport androidx.annotation.ColorInt;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.appcompat.widget.TintTypedArray;\nimport androidx.core.view.ViewCompat;\nimport androidx.core.view.accessibility.AccessibilityNodeInfoCompat;\nimport androidx.customview.widget.ExploreByTouchHelper;\n\nimport com.google.android.material.internal.ThemeEnforcement;\n\nimport java.text.DecimalFormat;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Locale;\n\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.util.UiUtils;\n\n@SuppressWarnings(\"unused\")\npublic class BarChartView extends View {\n    private static final int DEF_STYLE_RES = R.style.Widget_AppTheme_BarChartView;\n    // Data structures\n    private final List<BarData> mBarDataList = new ArrayList<>();\n    private final List<String> mXAxisLabels = new ArrayList<>();\n\n    // Drawing objects\n    private Paint mBarPaint;\n    private Paint mSelectedBarPaint;\n    private Paint mGridPaint;\n    private Paint mTextPaint;\n    private Paint mTouchLinePaint;\n    private Paint mTooltipTextPaint;\n    private Paint mTooltipBgPaint;\n\n    private float mChartWidth;\n    private float mChartHeight;\n    private float mChartLeft;\n    private float mChartTop;\n    private float mChartRight;\n    private float mChartBottom;\n\n    // Touch handling\n    private boolean mShowTouchLine = false;\n    private int mTouchedBarIndex = -1;\n\n    // Chart configuration\n    private int mGridLineCount;\n    private boolean mShowGridLabelsOnLeft;\n    private float mMaxValue = 0f;\n    @Nullable\n    private Float mManualMinValue = null;\n    @Nullable\n    private Float mManualMaxValue = null;\n    @Nullable\n    private String mYAxisFormat;\n    private final DecimalFormat mValueFormatter = new DecimalFormat(\"#.#\");\n\n    // Custom attributes with defaults\n    private int mBarColor;\n    private int mSelectedBarColor;\n    private int mGridColor;\n    private float mGridStrokeWidth;\n    private int mTextColor;\n    private float mTextSizeSp;\n    private int mTouchLineColor;\n    private float mTouchLineWidth;\n    private float mMinBarWidthDp;\n    private float mMaxBarWidthDp;\n    private int mTooltipBgColor;\n    private int mTooltipTextColor;\n    private float mTooltipCornerRadius;\n    private boolean mUseCustomLabelSpacing = false;\n    private int mCustomSkipEvery = 1;\n    private int mCustomStartFrom = 0;\n    @Nullable\n    private String mEmptyText;\n    private boolean mValueOnTopOfBar;\n\n    // Accessibility\n    @Nullable\n    private BarChartAccessibilityHelper mAccessibilityHelper;\n    private int mFocusedBarIndex = -1;\n\n    // Tooltip listener\n    @Nullable\n    private TooltipListener mTooltipListener = null;\n\n    public interface TooltipListener {\n        /**\n         * Called when tooltip should be displayed\n         *\n         * @param barIndex Index of the touched bar\n         * @param value    Value of the bar\n         * @param label    Label of the bar\n         * @return Custom tooltip text\n         */\n        @NonNull\n        String getTooltipText(Context context, int barIndex, float value, String label);\n\n        /**\n         * Called when accessibility is used\n         *\n         * @param barIndex Index of the touched bar\n         * @param barCount Number of bars\n         * @param value    Value of the bar\n         * @param label    Label of the bar\n         * @return Custom accessibility text\n         */\n        @NonNull\n        String getAccessibilityText(Context context, int barIndex, int barCount, float value, String label);\n    }\n\n    public BarChartView(@NonNull Context context) {\n        this(context, null);\n    }\n\n    public BarChartView(@NonNull Context context, @Nullable AttributeSet attrs) {\n        this(context, attrs, R.attr.barChartViewStyle);\n    }\n\n    @SuppressLint(\"RestrictedApi\")\n    public BarChartView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {\n        super(wrap(context, attrs, defStyleAttr, DEF_STYLE_RES), attrs, defStyleAttr);\n        context = getContext();\n        final TintTypedArray a = ThemeEnforcement.obtainTintedStyledAttributes(\n                context, attrs, R.styleable.BarChartView, defStyleAttr, DEF_STYLE_RES);\n        try {\n            mBarColor = a.getColor(R.styleable.BarChartView_barColor, 0);\n            mSelectedBarColor = a.getColor(R.styleable.BarChartView_selectedBarColor, 0);\n            mGridColor = a.getColor(R.styleable.BarChartView_gridColor, 0);\n            mGridStrokeWidth = a.getDimension(R.styleable.BarChartView_gridStrokeWidth, 0);\n            mTextColor = a.getColor(R.styleable.BarChartView_textColor, 0);\n            mTextSizeSp = a.getDimension(R.styleable.BarChartView_textSize, 0);\n            mTouchLineColor = a.getColor(R.styleable.BarChartView_touchLineColor, 0);\n            mTouchLineWidth = a.getDimension(R.styleable.BarChartView_touchLineWidth, 0);\n            mMinBarWidthDp = a.getDimension(R.styleable.BarChartView_minBarWidth, 0);\n            mMaxBarWidthDp = a.getDimension(R.styleable.BarChartView_maxBarWidth, 0);\n            mTooltipBgColor = a.getColor(R.styleable.BarChartView_tooltipBackgroundColor, 0);\n            mTooltipTextColor = a.getColor(R.styleable.BarChartView_tooltipTextColor, 0);\n            mTooltipCornerRadius = a.getDimension(R.styleable.BarChartView_tooltipCornerRadius, 0);\n            mValueOnTopOfBar = a.getBoolean(R.styleable.BarChartView_valueOnTopOfBar, false);\n            mGridLineCount = a.getInt(R.styleable.BarChartView_gridLineCount, 0);\n            mShowGridLabelsOnLeft = a.getBoolean(R.styleable.BarChartView_gridLabelsOnLeft, true);\n            String format = a.getString(R.styleable.BarChartView_yAxisFormat);\n            if (!TextUtils.isEmpty(format)) {\n                mYAxisFormat = format;\n            } else mYAxisFormat = null;\n            mEmptyText = a.getString(R.styleable.BarChartView_emptyText);\n        } finally {\n            a.recycle();\n        }\n        initializePaints();\n        initializeAccessibility();\n    }\n\n    private void initializePaints() {\n        mBarPaint = new Paint(Paint.ANTI_ALIAS_FLAG);\n        mBarPaint.setColor(mBarColor);\n        mBarPaint.setStyle(Paint.Style.FILL);\n\n        mSelectedBarPaint = new Paint(Paint.ANTI_ALIAS_FLAG);\n        mSelectedBarPaint.setColor(mSelectedBarColor);\n        mSelectedBarPaint.setStyle(Paint.Style.FILL);\n\n        mGridPaint = new Paint(Paint.ANTI_ALIAS_FLAG);\n        mGridPaint.setColor(mGridColor);\n        mGridPaint.setStrokeWidth(mGridStrokeWidth);\n\n        mTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);\n        mTextPaint.setColor(mTextColor);\n        mTextPaint.setTextSize(mTextSizeSp);\n\n        mTouchLinePaint = new Paint(Paint.ANTI_ALIAS_FLAG);\n        mTouchLinePaint.setColor(mTouchLineColor);\n        mTouchLinePaint.setStrokeWidth(mTouchLineWidth);\n        mTouchLinePaint.setStyle(Paint.Style.STROKE);\n        mTouchLinePaint.setPathEffect(new DashPathEffect(new float[]{12, 6}, 0));\n\n        mTooltipTextPaint = new Paint(Paint.ANTI_ALIAS_FLAG);\n        mTooltipTextPaint.setColor(mTooltipTextColor);\n        mTooltipTextPaint.setTextSize(spToPx(13));\n\n        mTooltipBgPaint = new Paint(Paint.ANTI_ALIAS_FLAG);\n        mTooltipBgPaint.setColor(mTooltipBgColor);\n        mTooltipBgPaint.setStyle(Paint.Style.FILL);\n    }\n\n    private void initializeAccessibility() {\n        mAccessibilityHelper = new BarChartAccessibilityHelper(this);\n        ViewCompat.setAccessibilityDelegate(this, mAccessibilityHelper);\n\n        // Make the view focusable for keyboard navigation\n        setFocusable(true);\n        setFocusableInTouchMode(true);\n\n        // Set initial content description\n        updateOverallContentDescription();\n    }\n\n    private float dpToPx(float dp) {\n        return UiUtils.dpToPx(getContext(), dp);\n    }\n\n    private float spToPx(float sp) {\n        return UiUtils.spToPx(getContext(), sp);\n    }\n\n    public void setTooltipListener(@Nullable TooltipListener listener) {\n        mTooltipListener = listener;\n    }\n\n    public void setManualYAxisRange(@Nullable Float minValue, @Nullable Float maxValue) {\n        mManualMinValue = minValue;\n        mManualMaxValue = maxValue;\n        calculateValueRange();\n        invalidate();\n    }\n\n    // e.g., \"%.2f min\"\n    public void setYAxisFormat(@Nullable String format) {\n        mYAxisFormat = format;\n        invalidate();\n    }\n\n    public void setBarColor(@ColorInt int color) {\n        mBarColor = color;\n        mBarPaint.setColor(color);\n        invalidate();\n    }\n\n    public void setSelectedBarColor(@ColorInt int color) {\n        mSelectedBarColor = color;\n        mSelectedBarPaint.setColor(color);\n        invalidate();\n    }\n\n    /**\n     * Set data for the bar chart\n     */\n    public void setData(@Nullable List<Float> values, @Nullable List<String> labels) {\n        mBarDataList.clear();\n        mXAxisLabels.clear();\n\n        if (values != null && labels != null && values.size() == labels.size()) {\n            for (int i = 0; i < values.size(); i++) {\n                mBarDataList.add(new BarData(values.get(i), labels.get(i)));\n                mXAxisLabels.add(labels.get(i));\n            }\n            calculateValueRange();\n        }\n\n        invalidate();\n\n        // Update accessibility\n        updateOverallContentDescription();\n        if (mAccessibilityHelper != null) {\n            mAccessibilityHelper.invalidateRoot();\n        }\n\n        // Reset focus\n        mFocusedBarIndex = -1;\n        mTouchedBarIndex = -1;\n        mShowTouchLine = false;\n    }\n\n    private void calculateValueRange() {\n        if (mBarDataList.isEmpty()) {\n            mMaxValue = 1f;\n            return;\n        }\n\n        List<Float> values = new ArrayList<>();\n        for (BarData bar : mBarDataList) {\n            values.add(bar.value);\n        }\n\n        if (mManualMaxValue != null) {\n            mMaxValue = mManualMaxValue;\n        } else {\n            mMaxValue = Collections.max(values);\n        }\n\n        if (mManualMinValue != null) {\n            // TODO: 9/21/25 Handle manual min value. All our charts for now begins with 0\n        }\n    }\n\n    /**\n     * Specify the position of the Y-axis labels. Labels are shown on the left hand-side by default.\n     * Setting the argument to false results in labels being shown on the right hand-side.\n     */\n    public void setGridLabelsOnLeft(boolean onLeft) {\n        mShowGridLabelsOnLeft = onLeft;\n        invalidate();\n    }\n\n    /**\n     * A minimum 2 grid lines are required. Default is 6.\n     */\n    public void setGridLineCount(int count) {\n        mGridLineCount = Math.max(2, count);\n        invalidate();\n    }\n\n    @Override\n    protected void onSizeChanged(int w, int h, int oldw, int oldh) {\n        super.onSizeChanged(w, h, oldw, oldh);\n        calculateDynamicMargins(w, h);\n    }\n\n    private void calculateDynamicMargins(int width, int height) {\n        float leftMargin;\n        float rightMargin;\n        float topMargin;\n        float bottomMargin;\n        if (mBarDataList.isEmpty()) {\n            leftMargin = dpToPx(40);\n            rightMargin = dpToPx(20);\n            topMargin = dpToPx(20);\n            bottomMargin = dpToPx(40);\n        } else {\n            // Measure Y-axis labels\n            float maxYLabelWidth = 0f;\n            for (int i = 0; i < mGridLineCount; i++) {\n                float value = (mMaxValue * i) / (mGridLineCount - 1);\n                String label = formatYAxisValue(value);\n                Rect textBounds = new Rect();\n                mTextPaint.getTextBounds(label, 0, label.length(), textBounds);\n                maxYLabelWidth = Math.max(maxYLabelWidth, textBounds.width());\n            }\n\n            // Measure X-axis labels\n            float maxXLabelWidth = 0f;\n            float maxXLabelHeight = 0f;\n            for (String label : mXAxisLabels) {\n                Rect textBounds = new Rect();\n                mTextPaint.getTextBounds(label, 0, label.length(), textBounds);\n                maxXLabelWidth = Math.max(maxXLabelWidth, textBounds.width());\n                maxXLabelHeight = Math.max(maxXLabelHeight, textBounds.height());\n            }\n\n            leftMargin = maxYLabelWidth + dpToPx(12);\n            rightMargin = Math.max(dpToPx(16), maxXLabelWidth * 0.5f);\n            topMargin = dpToPx(30);\n            bottomMargin = maxXLabelHeight + dpToPx(16);\n        }\n\n        mChartLeft = leftMargin;\n        mChartTop = topMargin;\n        mChartRight = width - rightMargin;\n        mChartBottom = height - bottomMargin;\n        mChartWidth = mChartRight - mChartLeft;\n        mChartHeight = mChartBottom - mChartTop;\n    }\n\n    @NonNull\n    private String formatYAxisValue(float value) {\n        if (mYAxisFormat != null) {\n            return String.format(mYAxisFormat, value);\n        } else {\n            return mValueFormatter.format(value);\n        }\n    }\n\n    @Override\n    protected void onDraw(@NonNull Canvas canvas) {\n        super.onDraw(canvas);\n\n        if (mBarDataList.isEmpty()) {\n            drawEmptyState(canvas);\n            return;\n        }\n\n        calculateDynamicMargins(getWidth(), getHeight());\n\n        drawGridLines(canvas);\n        drawBarsWithSpacing(canvas);\n        drawXAxisLabelsWithTickMarks(canvas);\n\n        // Draw touch line LAST to ensure visibility\n        if (mShowTouchLine && mTouchedBarIndex >= 0) {\n            drawTouchLineAndTooltip(canvas);\n        }\n    }\n\n    private void drawEmptyState(@NonNull Canvas canvas) {\n        if (TextUtils.isEmpty(mEmptyText)) {\n            return;\n        }\n        Paint emptyTextPaint = new Paint(mTextPaint);\n        emptyTextPaint.setTextSize(spToPx(16));\n        emptyTextPaint.setColor(mTextColor);\n\n        Rect textBounds = new Rect();\n        emptyTextPaint.getTextBounds(mEmptyText, 0, mEmptyText.length(), textBounds);\n\n        float x = (getWidth() - textBounds.width()) / 2f;\n        float y = (getHeight() + textBounds.height()) / 2f;\n\n        canvas.drawText(mEmptyText, x, y, emptyTextPaint);\n    }\n\n    private void drawGridLines(@NonNull Canvas canvas) {\n        for (int i = 0; i < mGridLineCount; i++) {\n            float y = mChartBottom - (i * mChartHeight / (mGridLineCount - 1));\n\n            // Draw horizontal grid line\n            canvas.drawLine(mChartLeft, y, mChartRight, y, mGridPaint);\n\n            // Draw grid value labels\n            float value = (mMaxValue * i) / (mGridLineCount - 1);\n            String label = formatYAxisValue(value);\n\n            Rect textBounds = new Rect();\n            mTextPaint.getTextBounds(label, 0, label.length(), textBounds);\n\n            if (mShowGridLabelsOnLeft) {\n                canvas.drawText(label, mChartLeft - textBounds.width() - dpToPx(8),\n                        y + textBounds.height() / 2f, mTextPaint);\n            } else {\n                canvas.drawText(label, mChartRight + dpToPx(8),\n                        y + textBounds.height() / 2f, mTextPaint);\n            }\n        }\n    }\n\n    private void drawBarsWithSpacing(@NonNull Canvas canvas) {\n        int barCount = mBarDataList.size();\n        if (barCount == 0) return;\n\n        // Calculate bar dimensions\n        BarDimensions dims = calculateBarDimensions();\n\n        for (int i = 0; i < barCount; i++) {\n            BarData bar = mBarDataList.get(i);\n\n            float barLeft = mChartLeft + dims.gapWidth + (i * (dims.barWidth + dims.gapWidth));\n            float barRight = barLeft + dims.barWidth;\n            float barTop = mChartBottom - (bar.value / mMaxValue) * mChartHeight;\n            float barBottom = mChartBottom;\n\n            // Choose paint based on selection state\n            Paint currentBarPaint = (i == mTouchedBarIndex) ? mSelectedBarPaint : mBarPaint;\n\n            // Draw bar\n            canvas.drawRect(barLeft, barTop, barRight, barBottom, currentBarPaint);\n\n            if (mValueOnTopOfBar) {\n                // Draw value on top of bar\n                if (bar.value > 0 && barTop > mChartTop + dpToPx(20)) {\n                    String valueText = formatYAxisValue(bar.value);\n                    Rect textBounds = new Rect();\n                    mTextPaint.getTextBounds(valueText, 0, valueText.length(), textBounds);\n\n                    float textX = barLeft + (dims.barWidth - textBounds.width()) / 2f;\n                    float textY = barTop - dpToPx(5);\n\n                    if (textBounds.width() <= dims.barWidth) {\n                        canvas.drawText(valueText, textX, textY, mTextPaint);\n                    }\n                }\n            }\n        }\n    }\n\n    @NonNull\n    private BarDimensions calculateBarDimensions() {\n        int barCount = mBarDataList.size();\n        float minGap = dpToPx(4);\n        float totalGapWidth = minGap * (barCount + 1);\n        float availableWidthForBars = mChartWidth - totalGapWidth;\n        float calculatedBarWidth = availableWidthForBars / barCount;\n\n        // Apply min/max constraints\n        float barWidth = Math.max(mMinBarWidthDp, Math.min(calculatedBarWidth, mMaxBarWidthDp));\n\n        float actualTotalBarWidth = barWidth * barCount;\n        float remainingWidth = mChartWidth - actualTotalBarWidth;\n        float gapWidth = remainingWidth / (barCount + 1);\n\n        return new BarDimensions(barWidth, gapWidth);\n    }\n\n    private static class BarDimensions {\n        final float barWidth;\n        final float gapWidth;\n\n        BarDimensions(float barWidth, float gapWidth) {\n            this.barWidth = barWidth;\n            this.gapWidth = gapWidth;\n        }\n    }\n\n    private void drawTouchLineAndTooltip(@NonNull Canvas canvas) {\n        if (mTouchedBarIndex < 0 || mTouchedBarIndex >= mBarDataList.size()) return;\n\n        BarDimensions dims = calculateBarDimensions();\n        float barCenter = mChartLeft + dims.gapWidth + (mTouchedBarIndex * (dims.barWidth + dims.gapWidth)) + dims.barWidth / 2f;\n\n        // Calculate the bar's top position\n        BarData bar = mBarDataList.get(mTouchedBarIndex);\n        float barTop = mChartBottom - (bar.value / mMaxValue) * mChartHeight;\n\n        // Draw vertical line from chart top to bar top\n        canvas.drawLine(barCenter, mChartTop, barCenter, barTop, mTouchLinePaint);\n\n        // Draw tooltip\n        drawTooltip(canvas, barCenter);\n    }\n\n    private void drawTooltip(@NonNull Canvas canvas, float lineX) {\n        if (mTouchedBarIndex < 0 || mTouchedBarIndex >= mBarDataList.size()) return;\n\n        BarData bar = mBarDataList.get(mTouchedBarIndex);\n        String tooltipText;\n\n        // Use custom tooltip if listener is set\n        if (mTooltipListener != null) {\n            tooltipText = mTooltipListener.getTooltipText(getContext(), mTouchedBarIndex, bar.value, bar.label);\n        } else {\n            tooltipText = String.format(\"(%s, %s)\", bar.label, formatYAxisValue(bar.value));\n        }\n\n        Rect textBounds = new Rect();\n        mTooltipTextPaint.getTextBounds(tooltipText, 0, tooltipText.length(), textBounds);\n\n        float tooltipWidth = textBounds.width() + dpToPx(16);\n        float tooltipHeight = textBounds.height() + dpToPx(12);\n\n        float tooltipX = lineX - tooltipWidth / 2f;\n        float tooltipY = mChartTop - tooltipHeight - dpToPx(8);\n\n        // Keep tooltip within bounds\n        tooltipX = Math.max(dpToPx(8), Math.min(tooltipX, getWidth() - tooltipWidth - dpToPx(8)));\n        tooltipY = Math.max(dpToPx(8), tooltipY);\n\n        // Draw tooltip background\n        canvas.drawRoundRect(tooltipX, tooltipY,\n                tooltipX + tooltipWidth, tooltipY + tooltipHeight,\n                mTooltipCornerRadius, mTooltipCornerRadius, mTooltipBgPaint);\n\n        // Draw tooltip text\n        canvas.drawText(tooltipText,\n                tooltipX + dpToPx(8),\n                tooltipY + tooltipHeight - dpToPx(6),\n                mTooltipTextPaint);\n    }\n\n    @Override\n    public boolean dispatchHoverEvent(MotionEvent event) {\n        if (mAccessibilityHelper != null && mAccessibilityHelper.dispatchHoverEvent(event)) {\n            return true;\n        }\n        return super.dispatchHoverEvent(event);\n    }\n\n    @Override\n    public boolean dispatchKeyEvent(KeyEvent event) {\n        if (mAccessibilityHelper != null && mAccessibilityHelper.dispatchKeyEvent(event)) {\n            return true;\n        }\n        return super.dispatchKeyEvent(event);\n    }\n\n    @Override\n    protected void onFocusChanged(boolean gainFocus, int direction,\n                                  @Nullable Rect previouslyFocusedRect) {\n        super.onFocusChanged(gainFocus, direction, previouslyFocusedRect);\n        if (mAccessibilityHelper != null) {\n            mAccessibilityHelper.onFocusChanged(gainFocus, direction, previouslyFocusedRect);\n        }\n    }\n\n    @Override\n    public boolean onKeyDown(int keyCode, KeyEvent event) {\n        // Handle keyboard navigation\n        switch (keyCode) {\n            case KeyEvent.KEYCODE_DPAD_LEFT:\n            case KeyEvent.KEYCODE_DPAD_RIGHT:\n                return handleDirectionalNavigation(keyCode);\n            case KeyEvent.KEYCODE_DPAD_CENTER:\n            case KeyEvent.KEYCODE_ENTER:\n                return handleBarSelection();\n            case KeyEvent.KEYCODE_ESCAPE:\n                return handleClearSelection();\n        }\n        return super.onKeyDown(keyCode, event);\n    }\n\n    /**\n     * Handle directional navigation with keyboard/D-pad\n     */\n    private boolean handleDirectionalNavigation(int keyCode) {\n        if (mBarDataList.isEmpty()) return false;\n\n        int newFocusedIndex = mFocusedBarIndex;\n\n        if (keyCode == KeyEvent.KEYCODE_DPAD_LEFT) {\n            newFocusedIndex = Math.max(0, mFocusedBarIndex - 1);\n        } else if (keyCode == KeyEvent.KEYCODE_DPAD_RIGHT) {\n            newFocusedIndex = Math.min(mBarDataList.size() - 1, mFocusedBarIndex + 1);\n        }\n\n        if (newFocusedIndex != mFocusedBarIndex) {\n            mFocusedBarIndex = newFocusedIndex;\n\n            // Announce the newly focused bar\n            BarData bar = mBarDataList.get(mFocusedBarIndex);\n            String announcement = getAccessibleBarDescription(mFocusedBarIndex, bar);\n            announceForAccessibility(announcement);\n\n            // Update accessibility focus\n            if (mAccessibilityHelper != null) {\n                mAccessibilityHelper.invalidateVirtualView(mFocusedBarIndex);\n            }\n\n            invalidate();\n            return true;\n        }\n\n        return false;\n    }\n\n    /**\n     * Handle bar selection via keyboard\n     */\n    private boolean handleBarSelection() {\n        if (mFocusedBarIndex >= 0 && mFocusedBarIndex < mBarDataList.size()) {\n            selectBarForAccessibility(mFocusedBarIndex);\n            return true;\n        }\n        return false;\n    }\n\n    /**\n     * Handle clearing selection\n     */\n    private boolean handleClearSelection() {\n        if (mTouchedBarIndex >= 0) {\n            mTouchedBarIndex = -1;\n            mShowTouchLine = false;\n            invalidate();\n            // TODO: 9/22/25 Support localization\n            announceForAccessibility(\"Selection cleared\");\n            return true;\n        }\n        return false;\n    }\n\n    @Override\n    public boolean performClick() {\n        // Ensure performClick is called for accessibility\n        super.performClick();\n\n        // If there's a focused bar, select it\n        if (mFocusedBarIndex >= 0 && mFocusedBarIndex < mBarDataList.size()) {\n            selectBarForAccessibility(mFocusedBarIndex);\n            return true;\n        }\n\n        return true;\n    }\n\n    @Override\n    public boolean onTouchEvent(@NonNull MotionEvent event) {\n        switch (event.getAction()) {\n            case MotionEvent.ACTION_DOWN:\n            case MotionEvent.ACTION_MOVE:\n                handleTouch(event.getX(), event.getY());\n                return true;\n\n            case MotionEvent.ACTION_UP:\n            case MotionEvent.ACTION_CANCEL:\n                mShowTouchLine = false;\n                mTouchedBarIndex = -1;\n                invalidate();\n                return true;\n\n            default:\n                return super.onTouchEvent(event);\n        }\n    }\n\n    private void handleTouch(float x, float y) {\n        if (mBarDataList.isEmpty()) return;\n\n        if (x < mChartLeft || x > mChartRight || y < mChartTop || y > mChartBottom) {\n            mShowTouchLine = false;\n            mTouchedBarIndex = -1;\n            invalidate();\n            return;\n        }\n\n        BarDimensions dims = calculateBarDimensions();\n\n        for (int i = 0; i < mBarDataList.size(); i++) {\n            float barLeft = mChartLeft + dims.gapWidth + (i * (dims.barWidth + dims.gapWidth));\n            float barRight = barLeft + dims.barWidth;\n\n            if (x >= barLeft && x <= barRight) {\n                mTouchedBarIndex = i;\n                mShowTouchLine = true;\n                invalidate();\n                break;\n            }\n        }\n    }\n\n    private void drawXAxisLabelsWithTickMarks(@NonNull Canvas canvas) {\n        int barCount = mBarDataList.size();\n        if (barCount == 0) return;\n\n        BarDimensions dims = calculateBarDimensions();\n\n        // Calculate label spacing to prevent overlapping\n        LabelSpacing spacing;\n        if (mUseCustomLabelSpacing) {\n            spacing = new LabelSpacing(mCustomSkipEvery, mCustomStartFrom);\n        } else {\n            spacing = calculateOptimalLabelSpacing(dims);\n        }\n\n        for (int i = 0; i < mXAxisLabels.size(); i++) {\n            // Only draw labels that should be shown based on spacing calculation\n            if (!spacing.shouldShowLabel(i)) {\n                continue;\n            }\n\n            float barCenter = mChartLeft + dims.gapWidth + (i * (dims.barWidth + dims.gapWidth)) + dims.barWidth / 2f;\n\n            // Draw tick mark ONLY for labels that are shown\n            float tickTop = mChartBottom;\n            float tickBottom = mChartBottom + dpToPx(4); // 4dp tick mark height\n            canvas.drawLine(barCenter, tickTop, barCenter, tickBottom, mGridPaint);\n\n            // Draw label\n            String label = mXAxisLabels.get(i);\n            Rect textBounds = new Rect();\n            mTextPaint.getTextBounds(label, 0, label.length(), textBounds);\n\n            float textX = barCenter - textBounds.width() / 2f;\n            float textY = mChartBottom + textBounds.height() + dpToPx(8);\n\n            canvas.drawText(label, textX, textY, mTextPaint);\n        }\n    }\n\n    @NonNull\n    private LabelSpacing calculateOptimalLabelSpacing(@NonNull BarDimensions dims) {\n        if (mXAxisLabels.isEmpty()) {\n            return new LabelSpacing(1, 0);\n        }\n\n        // Measure the widest label to determine minimum spacing needed\n        float maxLabelWidth = 0f;\n        for (String label : mXAxisLabels) {\n            Rect textBounds = new Rect();\n            mTextPaint.getTextBounds(label, 0, label.length(), textBounds);\n            maxLabelWidth = Math.max(maxLabelWidth, textBounds.width());\n        }\n\n        // Add padding between labels\n        float minSpacingNeeded = maxLabelWidth + dpToPx(8);\n\n        // Calculate available space per label\n        float availableSpacePerLabel = dims.barWidth + dims.gapWidth;\n\n        // Determine how many labels to skip\n        int skipCount = 1;\n        if (availableSpacePerLabel < minSpacingNeeded) {\n            skipCount = (int) Math.ceil(minSpacingNeeded / availableSpacePerLabel);\n        }\n\n        int startOffset = 0;\n\n        return new LabelSpacing(skipCount, startOffset);\n    }\n\n    private static class LabelSpacing {\n        private final int skipCount;\n        private final int startOffset;\n\n        LabelSpacing(int skipCount, int startOffset) {\n            this.skipCount = Math.max(1, skipCount);\n            this.startOffset = Math.max(0, startOffset);\n        }\n\n        boolean shouldShowLabel(int index) {\n            return (index - startOffset) % skipCount == 0 && index >= startOffset;\n        }\n    }\n\n    /**\n     * Set custom label spacing pattern\n     *\n     * @param skipEvery Show every Nth label (1 = show all, 2 = show every other, etc.)\n     * @param startFrom Index to start showing labels from (0-based)\n     */\n    public void setLabelSkipPattern(int skipEvery, int startFrom) {\n        mCustomSkipEvery = Math.max(1, skipEvery);\n        mCustomStartFrom = Math.max(0, startFrom);\n        mUseCustomLabelSpacing = true;\n        invalidate();\n    }\n\n    /**\n     * Enable or disable automatic label spacing (default: true)\n     * When auto is true, the chart automatically determines optimal label spacing\n     * When auto is false, uses custom skip pattern if set\n     */\n    public void setAutoLabelSpacing(boolean auto) {\n        mUseCustomLabelSpacing = !auto;\n        invalidate();\n    }\n\n    /**\n     * Get the current label skip pattern being used\n     *\n     * @return Array [skipEvery, startFrom] or null if auto-spacing is used\n     */\n    @NonNull\n    public int[] getCurrentLabelSpacing() {\n        if (mUseCustomLabelSpacing) {\n            return new int[]{mCustomSkipEvery, mCustomStartFrom};\n        }\n\n        // Calculate current auto spacing\n        if (mBarDataList.isEmpty()) {\n            return new int[]{1, 0};\n        }\n\n        BarDimensions dims = calculateBarDimensions();\n        LabelSpacing spacing = calculateOptimalLabelSpacing(dims);\n        return new int[]{spacing.skipCount, spacing.startOffset};\n    }\n\n    private static class BarData {\n        float value;\n        String label;\n\n        BarData(float value, String label) {\n            this.value = value;\n            this.label = label;\n        }\n    }\n\n    /**\n     * Get accessible description for a specific bar\n     */\n    @NonNull\n    private String getAccessibleBarDescription(int barIndex, BarData bar) {\n        if (mTooltipListener != null) {\n            return mTooltipListener.getAccessibilityText(getContext(), barIndex, mBarDataList.size(), bar.value, bar.label);\n        }\n        String valueText = formatYAxisValue(bar.value);\n        return String.format(Locale.getDefault(), \"%s: %s. Bar %d of %d.\", bar.label, valueText, barIndex + 1, mBarDataList.size());\n    }\n\n    @NonNull\n    private Rect getBarBounds(int barIndex) {\n        if (barIndex < 0 || barIndex >= mBarDataList.size()) {\n            return new Rect();\n        }\n\n        BarDimensions dims = calculateBarDimensions();\n        float barLeft = mChartLeft + dims.gapWidth + (barIndex * (dims.barWidth + dims.gapWidth));\n        float barRight = barLeft + dims.barWidth;\n\n        BarData bar = mBarDataList.get(barIndex);\n        float barTop = mChartBottom - (bar.value / mMaxValue) * mChartHeight;\n        float barBottom = mChartBottom;\n\n        return new Rect((int) barLeft, (int) barTop, (int) barRight, (int) barBottom);\n    }\n\n    private int getBarIndexAtPosition(float x, float y) {\n        if (mBarDataList.isEmpty()) return -1;\n        if (x < mChartLeft || x > mChartRight || y < mChartTop || y > mChartBottom) {\n            return -1;\n        }\n\n        BarDimensions dims = calculateBarDimensions();\n        for (int i = 0; i < mBarDataList.size(); i++) {\n            float barLeft = mChartLeft + dims.gapWidth + (i * (dims.barWidth + dims.gapWidth));\n            float barRight = barLeft + dims.barWidth;\n\n            if (x >= barLeft && x <= barRight) {\n                return i;\n            }\n        }\n        return -1;\n    }\n\n    private void selectBarForAccessibility(int barIndex) {\n        if (barIndex >= 0 && barIndex < mBarDataList.size()) {\n            mTouchedBarIndex = barIndex;\n            mShowTouchLine = true;\n            invalidate();\n\n            // Announce the selection\n            BarData bar = mBarDataList.get(barIndex);\n            String announcement = getAccessibleBarDescription(barIndex, bar);\n            // TODO: 9/22/25 Localization\n            announceForAccessibility(\"Selected. \" + announcement);\n\n            // Notify accessibility helper\n            if (mAccessibilityHelper != null) {\n                mAccessibilityHelper.invalidateVirtualView(barIndex);\n                mAccessibilityHelper.sendEventForVirtualView(barIndex,\n                        AccessibilityEvent.TYPE_VIEW_SELECTED);\n            }\n        }\n    }\n\n    private void updateOverallContentDescription() {\n        String description;\n        if (mBarDataList.isEmpty()) {\n            description = mEmptyText != null ? mEmptyText : \"Empty bar chart\";\n        } else {\n            description = getContext().getString(R.string.bar_chart_content_description, mBarDataList.size());\n        }\n        setContentDescription(description);\n    }\n\n    /**\n     * Custom ExploreByTouchHelper for making individual bars accessible\n     */\n    private class BarChartAccessibilityHelper extends ExploreByTouchHelper {\n\n        public BarChartAccessibilityHelper(View forView) {\n            super(forView);\n        }\n\n        @Override\n        protected int getVirtualViewAt(float x, float y) {\n            // Find which bar is at the given coordinates\n            int barIndex = getBarIndexAtPosition(x, y);\n            return barIndex >= 0 ? barIndex : ExploreByTouchHelper.INVALID_ID;\n        }\n\n        @Override\n        protected void getVisibleVirtualViews(List<Integer> virtualViewIds) {\n            // Add all visible bars as virtual views\n            for (int i = 0; i < mBarDataList.size(); i++) {\n                virtualViewIds.add(i);\n            }\n        }\n\n        @Override\n        protected void onPopulateNodeForVirtualView(int virtualViewId,\n                                                    @NonNull AccessibilityNodeInfoCompat node) {\n            if (virtualViewId < 0 || virtualViewId >= mBarDataList.size()) {\n                return;\n            }\n\n            BarData bar = mBarDataList.get(virtualViewId);\n\n            // Set the content description\n            String description = getAccessibleBarDescription(virtualViewId, bar);\n            node.setContentDescription(description);\n\n            // Set the role\n            node.setClassName(\"android.widget.Button\"); // Treat as button for interaction\n\n            // Make it clickable and focusable\n            node.setClickable(true);\n            node.setFocusable(true);\n            node.setVisibleToUser(true);\n\n            // Add click action\n            node.addAction(AccessibilityNodeInfoCompat.ACTION_CLICK);\n\n            // Set the bounds of this virtual view\n            Rect bounds = getBarBounds(virtualViewId);\n            node.setBoundsInParent(bounds);\n\n            // Set state information\n            if (virtualViewId == mTouchedBarIndex) {\n                node.setSelected(true);\n                node.addAction(AccessibilityNodeInfoCompat.ACTION_CLEAR_SELECTION);\n            }\n        }\n\n        @Override\n        protected boolean onPerformActionForVirtualView(int virtualViewId, int action,\n                                                        @Nullable Bundle arguments) {\n            if (virtualViewId < 0 || virtualViewId >= mBarDataList.size()) {\n                return false;\n            }\n\n            switch (action) {\n                case AccessibilityNodeInfoCompat.ACTION_CLICK:\n                    // Simulate bar selection\n                    selectBarForAccessibility(virtualViewId);\n                    return true;\n\n                case AccessibilityNodeInfoCompat.ACTION_ACCESSIBILITY_FOCUS:\n                    mFocusedBarIndex = virtualViewId;\n                    invalidateVirtualView(virtualViewId);\n                    return true;\n\n                case AccessibilityNodeInfoCompat.ACTION_CLEAR_ACCESSIBILITY_FOCUS:\n                    if (mFocusedBarIndex == virtualViewId) {\n                        mFocusedBarIndex = -1;\n                        invalidateVirtualView(virtualViewId);\n                    }\n                    return true;\n\n                case AccessibilityNodeInfoCompat.ACTION_CLEAR_SELECTION:\n                    if (mTouchedBarIndex == virtualViewId) {\n                        mTouchedBarIndex = -1;\n                        mShowTouchLine = false;\n                        invalidate();\n                        // TODO: 9/22/25 Localization\n                        announceForAccessibility(\"Bar deselected\");\n                    }\n                    return true;\n            }\n            return false;\n        }\n\n        @Override\n        protected void onPopulateEventForVirtualView(int virtualViewId, @NonNull AccessibilityEvent event) {\n            if (virtualViewId < 0 || virtualViewId >= mBarDataList.size()) {\n                return;\n            }\n\n            BarData bar = mBarDataList.get(virtualViewId);\n            event.setContentDescription(getAccessibleBarDescription(virtualViewId, bar));\n            event.setClassName(\"android.widget.Button\");\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/usage/DataUsageAppWidget.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.usage;\n\nimport android.app.PendingIntent;\nimport android.appwidget.AppWidgetManager;\nimport android.appwidget.AppWidgetProvider;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.os.Build;\nimport android.os.Bundle;\nimport android.text.format.Formatter;\nimport android.widget.RemoteViews;\n\nimport androidx.collection.SparseArrayCompat;\nimport androidx.core.app.PendingIntentCompat;\n\nimport com.google.android.material.color.MaterialColors;\n\nimport java.util.Objects;\n\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.self.SelfPermissions;\nimport io.github.muntashirakon.AppManager.settings.FeatureController;\nimport io.github.muntashirakon.AppManager.utils.appearance.AppearanceUtils;\nimport io.github.muntashirakon.util.UiUtils;\n\npublic class DataUsageAppWidget extends AppWidgetProvider {\n    static void updateAppWidget(Context context, AppWidgetManager appWidgetManager, int appWidgetId) {\n        if (!FeatureController.isUsageAccessEnabled() || !SelfPermissions.checkUsageStatsPermission()) {\n            return;\n        }\n        // Fetch colors\n        context = AppearanceUtils.getThemedWidgetContext(context, false);\n        // Fetch data\n        TimeInterval interval = UsageUtils.getToday();\n        SparseArrayCompat<AppUsageStatsManager.DataUsage> mobileData = AppUsageStatsManager.getMobileData(interval);\n        SparseArrayCompat<AppUsageStatsManager.DataUsage> wifiData = AppUsageStatsManager.getWifiData(interval);\n        long mobileTx = 0;\n        long mobileRx = 0;\n        long wifiTx = 0;\n        long wifiRx = 0;\n        AppUsageStatsManager.DataUsage usage;\n        for (int i = 0; i < mobileData.size(); ++i) {\n            usage = Objects.requireNonNull(mobileData.valueAt(i));\n            mobileRx += usage.getRx();\n            mobileTx += usage.getTx();\n        }\n        for (int i = 0; i < wifiData.size(); ++i) {\n            usage = Objects.requireNonNull(wifiData.valueAt(i));\n            wifiRx += usage.getRx();\n            wifiTx += usage.getTx();\n        }\n        long totalTx = mobileTx + wifiTx;\n        long totalRx = mobileRx + wifiRx;\n        // Construct the RemoteViews object\n        RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.app_widget_data_usage_small);\n        // Set data usage\n        views.setTextViewText(R.id.data_usage, String.format(\"↑ %1$s ↓ %2$s\",\n                Formatter.formatShortFileSize(context, totalTx),\n                Formatter.formatShortFileSize(context, totalRx)));\n        // Set colors\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {\n            boolean isNight = UiUtils.isDarkMode(context);\n            int colorSurface = MaterialColors.getColor(context, com.google.android.material.R.attr.colorSurface, \"colorSurface\");\n            int colorSurfaceInverse = MaterialColors.getColor(context, com.google.android.material.R.attr.colorSurfaceInverse, \"colorSurfaceInverse\");\n            if (isNight) {\n                views.setColorInt(R.id.widget_background, \"setBackgroundColor\", colorSurfaceInverse, colorSurface);\n            } else views.setColorInt(R.id.widget_background, \"setBackgroundColor\", colorSurface, colorSurfaceInverse);\n        }\n        // Get PendingIntent for App Usage page\n        Intent appUsageIntent = new Intent(context, AppUsageActivity.class);\n        PendingIntent appUsagePendingIntent = PendingIntentCompat.getActivity(context, 0,\n                appUsageIntent, PendingIntent.FLAG_UPDATE_CURRENT, false);\n        views.setOnClickPendingIntent(R.id.widget_background, appUsagePendingIntent);\n        // Get PendingIntent for widget update\n        Intent appWidgetIntent = new Intent(context, DataUsageAppWidget.class)\n                .setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE)\n                .putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, new int[]{appWidgetId});\n        PendingIntent appWidgetPendingIntent = PendingIntentCompat.getBroadcast(context, 0,\n                appWidgetIntent, PendingIntent.FLAG_UPDATE_CURRENT, false);\n        views.setOnClickPendingIntent(R.id.screen_time_refresh, appWidgetPendingIntent);\n        // Instruct the widget manager to update the widget\n        appWidgetManager.updateAppWidget(appWidgetId, views);\n    }\n\n    @Override\n    public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {\n        for (int appWidgetId : appWidgetIds) {\n            updateAppWidget(context, appWidgetManager, appWidgetId);\n        }\n    }\n\n    @Override\n    public void onAppWidgetOptionsChanged(Context context, AppWidgetManager appWidgetManager, int appWidgetId, Bundle newOptions) {\n        updateAppWidget(context, appWidgetManager, appWidgetId);\n    }\n}"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/usage/IntervalType.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.usage;\n\nimport androidx.annotation.IntDef;\n\n@IntDef({IntervalType.INTERVAL_DAILY, IntervalType.INTERVAL_WEEKLY})\npublic @interface IntervalType {\n    // These numbers are tied to \"usage_interval_dropdown_list\" array.\n    // DO NOT MODIFY!\n    int INTERVAL_DAILY = 0;\n    int INTERVAL_WEEKLY = 1;\n}"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/usage/PackageUsageInfo.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.usage;\n\nimport android.annotation.UserIdInt;\nimport android.content.Context;\nimport android.content.pm.ApplicationInfo;\nimport android.os.Parcel;\nimport android.os.Parcelable;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.core.os.ParcelCompat;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Objects;\n\npublic class PackageUsageInfo implements Parcelable {\n    @NonNull\n    public final String packageName;\n    @UserIdInt\n    public final int userId;\n    @Nullable\n    public final ApplicationInfo applicationInfo;\n    @NonNull\n    public final String appLabel;\n\n    public long screenTime;\n    public long lastUsageTime;\n    public int timesOpened;\n    @Nullable\n    public AppUsageStatsManager.DataUsage mobileData;\n    @Nullable\n    public AppUsageStatsManager.DataUsage wifiData;\n    @Nullable\n    public List<Entry> entries;\n\n    public PackageUsageInfo(@NonNull Context context, @NonNull String packageName, @UserIdInt int userId,\n                            @Nullable ApplicationInfo applicationInfo) {\n        this.packageName = packageName;\n        this.userId = userId;\n        this.applicationInfo = applicationInfo;\n        if (applicationInfo != null) {\n            appLabel = applicationInfo.loadLabel(context.getPackageManager()).toString();\n        } else appLabel = packageName;\n    }\n\n    protected PackageUsageInfo(@NonNull Parcel in) {\n        packageName = Objects.requireNonNull(in.readString());\n        userId = in.readInt();\n        applicationInfo = ParcelCompat.readParcelable(in, ApplicationInfo.class.getClassLoader(), ApplicationInfo.class);\n        appLabel = in.readString();\n        screenTime = in.readLong();\n        lastUsageTime = in.readLong();\n        timesOpened = in.readInt();\n        mobileData = ParcelCompat.readParcelable(in, AppUsageStatsManager.DataUsage.class.getClassLoader(), AppUsageStatsManager.DataUsage.class);\n        wifiData = ParcelCompat.readParcelable(in, AppUsageStatsManager.DataUsage.class.getClassLoader(), AppUsageStatsManager.DataUsage.class);\n        int size = in.readInt();\n        if (size != 0) {\n            entries = new ArrayList<>(size);\n            ParcelCompat.readList(in, entries, Entry.class.getClassLoader(), Entry.class);\n        }\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        dest.writeString(packageName);\n        dest.writeInt(userId);\n        dest.writeParcelable(applicationInfo, flags);\n        dest.writeString(appLabel);\n        dest.writeLong(screenTime);\n        dest.writeLong(lastUsageTime);\n        dest.writeInt(timesOpened);\n        dest.writeParcelable(mobileData, flags);\n        dest.writeParcelable(wifiData, flags);\n        dest.writeInt(entries == null ? 0 : entries.size());\n        if (entries != null) {\n            dest.writeList(entries);\n        }\n    }\n\n    @Override\n    public int describeContents() {\n        return 0;\n    }\n\n    public static final Creator<PackageUsageInfo> CREATOR = new Creator<PackageUsageInfo>() {\n        @NonNull\n        @Override\n        public PackageUsageInfo createFromParcel(Parcel in) {\n            return new PackageUsageInfo(in);\n        }\n\n        @NonNull\n        @Override\n        public PackageUsageInfo[] newArray(int size) {\n            return new PackageUsageInfo[size];\n        }\n    };\n\n    public void copyOthers(@NonNull PackageUsageInfo packageUS) {\n        screenTime = packageUS.screenTime;\n        lastUsageTime = packageUS.lastUsageTime;\n        timesOpened = packageUS.timesOpened;\n        mobileData = packageUS.mobileData;\n        wifiData = packageUS.wifiData;\n    }\n\n    @NonNull\n    @Override\n    public String toString() {\n        return \"PackageUS{\" +\n                \"packageName='\" + packageName + '\\'' +\n                \", appLabel='\" + appLabel + '\\'' +\n                \", screenTime=\" + screenTime +\n                \", lastUsageTime=\" + lastUsageTime +\n                \", timesOpened=\" + timesOpened +\n                \", txData=\" + mobileData +\n                \", rxData=\" + wifiData +\n                \", entries=\" + entries +\n                '}';\n    }\n\n    public static class Entry implements Parcelable {\n        public final long startTime;\n        public final long endTime;\n\n        public Entry(long startTime, long endTime) {\n            this.startTime = startTime;\n            this.endTime = endTime;\n        }\n\n        protected Entry(Parcel in) {\n            this.startTime = in.readLong();\n            this.endTime = in.readLong();\n        }\n\n        public static final Creator<Entry> CREATOR = new Creator<Entry>() {\n            @NonNull\n            @Override\n            public Entry createFromParcel(Parcel in) {\n                return new Entry(in);\n            }\n\n            @NonNull\n            @Override\n            public Entry[] newArray(int size) {\n                return new Entry[size];\n            }\n        };\n\n        public long getDuration() {\n            return endTime - startTime;\n        }\n\n        @NonNull\n        @Override\n        public String toString() {\n            return \"USEntry{\" +\n                    \"startTime=\" + startTime +\n                    \", endTime=\" + endTime +\n                    '}';\n        }\n\n        @Override\n        public int describeContents() {\n            return 0;\n        }\n\n        @Override\n        public void writeToParcel(Parcel dest, int flags) {\n            dest.writeLong(startTime);\n            dest.writeLong(endTime);\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/usage/ScreenTimeAppWidget.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.usage;\n\nimport android.app.PendingIntent;\nimport android.appwidget.AppWidgetManager;\nimport android.appwidget.AppWidgetProvider;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.res.ColorStateList;\nimport android.content.res.Configuration;\nimport android.graphics.Color;\nimport android.os.Build;\nimport android.os.Bundle;\nimport android.util.Size;\nimport android.view.View;\nimport android.widget.RemoteViews;\n\nimport androidx.annotation.NonNull;\nimport androidx.core.app.PendingIntentCompat;\n\nimport com.google.android.material.color.MaterialColors;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\n\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.self.SelfPermissions;\nimport io.github.muntashirakon.AppManager.settings.FeatureController;\nimport io.github.muntashirakon.AppManager.users.Users;\nimport io.github.muntashirakon.AppManager.utils.DateUtils;\nimport io.github.muntashirakon.AppManager.utils.ExUtils;\nimport io.github.muntashirakon.AppManager.utils.appearance.AppearanceUtils;\nimport io.github.muntashirakon.util.UiUtils;\n\npublic class ScreenTimeAppWidget extends AppWidgetProvider {\n    static void updateAppWidget(Context context, AppWidgetManager appWidgetManager, int appWidgetId) {\n        if (!FeatureController.isUsageAccessEnabled() || !SelfPermissions.checkUsageStatsPermission()) {\n            return;\n        }\n        // Fetch colors\n        context = AppearanceUtils.getThemedWidgetContext(context, false);\n        // Fetch screens time\n        int[] userIds = Users.getUsersIds();\n        List<PackageUsageInfo> packageUsageInfoList = new ArrayList<>();\n        AppUsageStatsManager usageStatsManager = AppUsageStatsManager.getInstance();\n        TimeInterval interval = UsageUtils.getToday();\n        for (int userId : userIds) {\n            ExUtils.exceptionAsIgnored(() -> packageUsageInfoList.addAll(usageStatsManager\n                    .getUsageStats(interval, userId)));\n        }\n        Collections.sort(packageUsageInfoList, (o1, o2) -> -Long.compare(o1.screenTime, o2.screenTime));\n        long totalScreenTime = 0;\n        for (PackageUsageInfo appItem : packageUsageInfoList) {\n            totalScreenTime += appItem.screenTime;\n        }\n        // Construct the RemoteViews object\n        Size appWidgetSize = getAppWidgetSize(context, appWidgetManager, appWidgetId);\n        RemoteViews views;\n        if (appWidgetSize.getHeight() <= 200) {\n            views = new RemoteViews(context.getPackageName(), R.layout.app_widget_screen_time_small);\n        } else if (appWidgetSize.getWidth() <= 250) {\n            views = new RemoteViews(context.getPackageName(), R.layout.app_widget_screen_time);\n        } else {\n            views = new RemoteViews(context.getPackageName(), R.layout.app_widget_screen_time_large);\n        }\n        // Set screen time\n        views.setTextViewText(R.id.screen_time, DateUtils.getFormattedDurationShort(totalScreenTime, false, true, false));\n        int len = Math.min(packageUsageInfoList.size(), 3);\n        // Set visibility\n        int app3_visibility = len == 3 ? View.VISIBLE : View.INVISIBLE;\n        int app2_visibility = len >= 2 ? View.VISIBLE : View.INVISIBLE;\n        int app1_visibility = len >= 1 ? View.VISIBLE : View.INVISIBLE;\n        views.setViewVisibility(R.id.app3_circle, app3_visibility);\n        views.setViewVisibility(R.id.app3_time, app3_visibility);\n        views.setViewVisibility(R.id.app3_label, app3_visibility);\n        views.setViewVisibility(R.id.app2_circle, app2_visibility);\n        views.setViewVisibility(R.id.app2_time, app2_visibility);\n        views.setViewVisibility(R.id.app2_label, app2_visibility);\n        views.setViewVisibility(R.id.app1_circle, app1_visibility);\n        views.setViewVisibility(R.id.app1_time, app1_visibility);\n        views.setViewVisibility(R.id.app1_label, app1_visibility);\n        // Set app info\n        if (app3_visibility == View.VISIBLE) {\n            PackageUsageInfo item3 = packageUsageInfoList.get(2);\n            views.setTextViewText(R.id.app3_label, item3.appLabel);\n            views.setTextViewText(R.id.app3_time, DateUtils.getFormattedDurationSingle(item3.screenTime, false));\n        }\n        if (app2_visibility == View.VISIBLE) {\n            PackageUsageInfo item2 = packageUsageInfoList.get(1);\n            views.setTextViewText(R.id.app2_label, item2.appLabel);\n            views.setTextViewText(R.id.app2_time, DateUtils.getFormattedDurationSingle(item2.screenTime, false));\n        }\n        if (app1_visibility == View.VISIBLE) {\n            PackageUsageInfo item1 = packageUsageInfoList.get(0);\n            views.setTextViewText(R.id.app1_label, item1.appLabel);\n            views.setTextViewText(R.id.app1_time, DateUtils.getFormattedDurationSingle(item1.screenTime, false));\n        }\n        // Set colors\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {\n            boolean isNight = UiUtils.isDarkMode(context);\n            int colorSurface = MaterialColors.getColor(context, com.google.android.material.R.attr.colorSurface, \"colorSurface\");\n            int colorSurfaceInverse = MaterialColors.getColor(context, com.google.android.material.R.attr.colorSurfaceInverse, \"colorSurfaceInverse\");\n            ColorStateList color1 = ColorStateList.valueOf(MaterialColors.harmonizeWithPrimary(context, Color.parseColor(\"#1b1b1b\")));\n            ColorStateList color2 = ColorStateList.valueOf(MaterialColors.harmonizeWithPrimary(context, Color.parseColor(\"#565e71\")));\n            ColorStateList color3 = ColorStateList.valueOf(MaterialColors.harmonizeWithPrimary(context, Color.parseColor(\"#d4e3ff\")));\n            views.setColorStateList(R.id.app1_time, \"setBackgroundTintList\", color1);\n            views.setColorStateList(R.id.app1_circle, \"setBackgroundTintList\", color1);\n            views.setColorStateList(R.id.app2_time, \"setBackgroundTintList\", color2);\n            views.setColorStateList(R.id.app2_circle, \"setBackgroundTintList\", color2);\n            views.setColorStateList(R.id.app3_time, \"setBackgroundTintList\", color3);\n            views.setColorStateList(R.id.app3_circle, \"setBackgroundTintList\", color3);\n            if (isNight) {\n                views.setColorInt(R.id.widget_background, \"setBackgroundColor\", colorSurfaceInverse, colorSurface);\n            } else views.setColorInt(R.id.widget_background, \"setBackgroundColor\", colorSurface, colorSurfaceInverse);\n        }\n        // Get PendingIntent for App Usage page\n        Intent appUsageIntent = new Intent(context, AppUsageActivity.class);\n        PendingIntent appUsagePendingIntent = PendingIntentCompat.getActivity(context, 0,\n                appUsageIntent, PendingIntent.FLAG_UPDATE_CURRENT, false);\n        views.setOnClickPendingIntent(R.id.widget_background, appUsagePendingIntent);\n        // Get PendingIntent for widget update\n        Intent appWidgetIntent = new Intent(context, ScreenTimeAppWidget.class)\n                .setAction(AppWidgetManager.ACTION_APPWIDGET_UPDATE)\n                .putExtra(AppWidgetManager.EXTRA_APPWIDGET_IDS, new int[]{appWidgetId});\n        PendingIntent appWidgetPendingIntent = PendingIntentCompat.getBroadcast(context, 0,\n                appWidgetIntent, PendingIntent.FLAG_UPDATE_CURRENT, false);\n        views.setOnClickPendingIntent(R.id.screen_time_refresh, appWidgetPendingIntent);\n        // Instruct the widget manager to update the widget\n        appWidgetManager.updateAppWidget(appWidgetId, views);\n    }\n\n    @Override\n    public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {\n        for (int appWidgetId : appWidgetIds) {\n            updateAppWidget(context, appWidgetManager, appWidgetId);\n        }\n    }\n\n    @Override\n    public void onAppWidgetOptionsChanged(Context context, AppWidgetManager appWidgetManager, int appWidgetId, Bundle newOptions) {\n        updateAppWidget(context, appWidgetManager, appWidgetId);\n    }\n\n    @NonNull\n    private static Size getAppWidgetSize(@NonNull Context context, @NonNull AppWidgetManager manager, int appWidgetId) {\n        Bundle appWidgetOptions = manager.getAppWidgetOptions(appWidgetId);\n        boolean isPortrait = context.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT;\n        int width = appWidgetOptions.getInt(isPortrait ? AppWidgetManager.OPTION_APPWIDGET_MIN_WIDTH : AppWidgetManager.OPTION_APPWIDGET_MAX_WIDTH);\n        int height = appWidgetOptions.getInt(isPortrait ? AppWidgetManager.OPTION_APPWIDGET_MAX_HEIGHT : AppWidgetManager.OPTION_APPWIDGET_MIN_HEIGHT);\n        return new Size(width, height);\n    }\n}"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/usage/SortOrder.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.usage;\n\nimport androidx.annotation.IntDef;\n\n@IntDef(value = {\n        SortOrder.SORT_BY_APP_LABEL,\n        SortOrder.SORT_BY_LAST_USED,\n        SortOrder.SORT_BY_MOBILE_DATA,\n        SortOrder.SORT_BY_PACKAGE_NAME,\n        SortOrder.SORT_BY_SCREEN_TIME,\n        SortOrder.SORT_BY_TIMES_OPENED,\n        SortOrder.SORT_BY_WIFI_DATA\n})\n@interface SortOrder {\n    int SORT_BY_APP_LABEL = 0;\n    int SORT_BY_LAST_USED = 1;\n    int SORT_BY_MOBILE_DATA = 2;\n    int SORT_BY_PACKAGE_NAME = 3;\n    int SORT_BY_SCREEN_TIME = 4;\n    int SORT_BY_TIMES_OPENED = 5;\n    int SORT_BY_WIFI_DATA = 6;\n}"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/usage/TimeInterval.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.usage;\n\nimport androidx.annotation.NonNull;\nimport androidx.core.util.Pair;\n\npublic class TimeInterval extends Pair<Long, Long> {\n    private final int mIntervalType;\n\n    public TimeInterval(int intervalType, long begin, long end) {\n        super(begin, end);\n        mIntervalType = intervalType;\n    }\n\n    public TimeInterval(long begin, long end) {\n        super(begin, end);\n        mIntervalType = IntervalType.INTERVAL_DAILY;\n    }\n\n    public int getIntervalType() {\n        return mIntervalType;\n    }\n\n    public long getStartTime() {\n        return first;\n    }\n\n    public long getEndTime() {\n        return second;\n    }\n\n    public long getDuration() {\n        return second - first + 1;\n    }\n\n    @NonNull\n    @Override\n    public String toString() {\n        return \"TimeInterval{\" +\n                \"startTime=\" + first +\n                \", endTime=\" + second +\n                '}';\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/usage/UsageDataProcessor.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.usage;\n\nimport android.content.Context;\n\nimport androidx.annotation.NonNull;\n\nimport java.time.DayOfWeek;\nimport java.time.format.TextStyle;\nimport java.util.ArrayList;\nimport java.util.Calendar;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.TimeZone;\n\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.utils.ArrayUtils;\nimport io.github.muntashirakon.AppManager.utils.ContextUtils;\n\npublic class UsageDataProcessor {\n    private static final long HOUR_IN_MILLIS = 60 * 60 * 1000L;\n    private static final long DAY_IN_MILLIS = 24L * 60 * 60 * 1000;\n\n    public static void updateChartWithAppUsage(@NonNull BarChartView chart,\n                                               @NonNull List<PackageUsageInfo.Entry> events,\n                                               @IntervalType int interval, long targetDate) {\n        switch (interval) {\n            case IntervalType.INTERVAL_WEEKLY:\n                updateChartWithDailyAppUsage(chart, events, targetDate);\n                break;\n            case IntervalType.INTERVAL_DAILY:\n            default:\n                updateChartWithHourlyAppUsage(chart, events, targetDate);\n        }\n    }\n\n    public static void updateChartWithHourlyAppUsage(BarChartView chart, List<PackageUsageInfo.Entry> events, long targetDate) {\n        float[] hourlyMinutes = convertToMinutes(groupIntoHourlyBucketsForDay(events, targetDate));\n\n        List<Float> values = new ArrayList<>();\n        List<String> labels = new ArrayList<>();\n        String[] timeLabels = getHourLabels();\n\n        for (int i = 0; i < Math.min(hourlyMinutes.length, timeLabels.length); i++) {\n            values.add(hourlyMinutes[i]);\n            labels.add(timeLabels[i]);\n        }\n\n        chart.setManualYAxisRange(0f, nextDivisibleBy4(Collections.max(values)));\n        chart.setYAxisFormat(chart.getContext().getString(R.string.usage_bar_chart_y_axis_label_minute));\n        chart.setData(values, labels);\n        chart.setTooltipListener(new BarChartView.TooltipListener() {\n            @NonNull\n            @Override\n            public String getTooltipText(Context context, int barIndex, float value, String label) {\n                return context.getString(R.string.usage_bar_chart_tooltip_minutes, label, value);\n            }\n\n            @NonNull\n            @Override\n            public String getAccessibilityText(Context context, int barIndex, int barCount, float value, String label) {\n                return context.getString(R.string.usage_daily_bar_chart_accessibility_description,\n                        label, value, (barIndex + 1), barCount);\n            }\n        });\n    }\n\n    public static void updateChartWithDailyAppUsage(BarChartView chart, List<PackageUsageInfo.Entry> events, long targetDate) {\n        long[] dailyMillis = groupIntoDailyBucketsForWeek(events, targetDate);\n        boolean displayInHours = ArrayUtils.max(dailyMillis) > 2 * HOUR_IN_MILLIS;\n        float[] dailyUsage;\n        if (displayInHours) {\n            dailyUsage = convertToHours(dailyMillis);\n        } else {\n            dailyUsage = convertToMinutes(dailyMillis);\n        }\n\n        List<Float> values = new ArrayList<>();\n        List<String> labels = new ArrayList<>();\n        String[] weekDayLabels = getWeekDayLabels();\n\n        for (int i = 0; i < Math.min(dailyUsage.length, weekDayLabels.length); i++) {\n            values.add(dailyUsage[i]);\n            labels.add(getLocalizedShortDayNameFromLabel(weekDayLabels[i]));\n        }\n\n        chart.setManualYAxisRange(0f, nextDivisibleBy4(Collections.max(values)));\n        String yAxisFormat;\n        if (displayInHours) {\n            yAxisFormat = chart.getContext().getString(R.string.usage_bar_chart_y_axis_label_hour);\n        } else {\n            yAxisFormat = chart.getContext().getString(R.string.usage_bar_chart_y_axis_label_minute);\n        }\n        chart.setYAxisFormat(yAxisFormat);\n        chart.setData(values, labels);\n        chart.setTooltipListener(new BarChartView.TooltipListener() {\n            @NonNull\n            @Override\n            public String getTooltipText(Context context, int barIndex, float value, String label) {\n                String localizedLabel = getLocalizedFullDayNameFromLabel(weekDayLabels[barIndex]);\n                if (displayInHours) {\n                    return context.getString(R.string.usage_bar_chart_tooltip_hours, localizedLabel, value);\n                } else {\n                    return context.getString(R.string.usage_bar_chart_tooltip_minutes, localizedLabel, value);\n                }\n            }\n\n            @NonNull\n            @Override\n            public String getAccessibilityText(Context context, int barIndex, int barCount, float value, String label) {\n                if (displayInHours) {\n                    return context.getString(R.string.usage_weekly_hours_bar_chart_accessibility_description,\n                            getLocalizedFullDayNameFromLabel(weekDayLabels[barIndex]), value, (barIndex + 1), barCount);\n                } else {\n                    return context.getString(R.string.usage_weekly_minutes_bar_chart_accessibility_description,\n                            getLocalizedFullDayNameFromLabel(weekDayLabels[barIndex]), value, (barIndex + 1), barCount);\n                }\n            }\n        });\n    }\n\n    /**\n     * Groups events into hourly buckets for a specific day\n     */\n    @NonNull\n    public static long[] groupIntoHourlyBucketsForDay(@NonNull List<PackageUsageInfo.Entry> events, long targetDate) {\n        TimeInterval interval = UsageUtils.getDayBounds(targetDate);\n        long dayStartTimestamp = interval.getStartTime();\n        long dayEndTimestamp = interval.getEndTime();\n        long[] hourlyDurations = new long[24];\n\n        for (PackageUsageInfo.Entry event : events) {\n            // Only process events that overlap with this day\n            if (event.endTime < dayStartTimestamp || event.startTime > dayEndTimestamp) {\n                continue; // Event doesn't overlap with this day\n            }\n\n            // Clip event to day boundaries\n            long clippedStart = Math.max(event.startTime, dayStartTimestamp);\n            long clippedEnd = Math.min(event.endTime, dayEndTimestamp);\n\n            distributeClippedEventAcrossHours(clippedStart, clippedEnd, dayStartTimestamp, hourlyDurations);\n        }\n\n        return hourlyDurations;\n    }\n\n    /**\n     * Distributes a clipped event (within day boundaries) across hourly buckets\n     */\n    private static void distributeClippedEventAcrossHours(long startTime, long endTime, long dayStart,\n                                                          @NonNull long[] hourlyDurations) {\n        long currentTime = startTime;\n\n        while (currentTime <= endTime) {\n            // Calculate hour bucket based on offset from day start\n            int hourBucket = (int) ((currentTime - dayStart) / HOUR_IN_MILLIS);\n            hourBucket = Math.min(hourBucket, 23); // Ensure we don't exceed hour 23\n\n            // Calculate end of current hour\n            long hourEnd = dayStart + ((hourBucket + 1) * HOUR_IN_MILLIS) - 1;\n\n            // Calculate segment duration\n            long segmentEnd = Math.min(endTime, hourEnd);\n            long segmentDuration = (segmentEnd - currentTime) + 1;\n\n            // Add to bucket\n            hourlyDurations[hourBucket] += segmentDuration;\n\n            // Move to next hour\n            currentTime = hourEnd + 1;\n        }\n    }\n\n    /**\n     * Group events into 7 daily buckets ending at periodEnd (inclusive).\n     */\n    @NonNull\n    public static long[] groupIntoDailyBucketsForWeek(@NonNull List<PackageUsageInfo.Entry> events, long targetDate) {\n        TimeInterval interval = UsageUtils.getWeekBounds(targetDate);\n        int numDays = 7;\n        long[] msBuckets = new long[numDays];\n        long periodStart = interval.getStartTime();\n        long periodEnd = interval.getEndTime();\n\n        for (PackageUsageInfo.Entry e : events) {\n            // Clip event to [periodStart, periodEnd]\n            long start = Math.max(e.startTime, periodStart);\n            long end = Math.min(e.endTime, periodEnd);\n            if (start > end) continue;\n\n            long current = start;\n            while (current <= end) {\n                int bucketIndex = (int) ((current - periodStart) / DAY_IN_MILLIS);\n                bucketIndex = Math.min(bucketIndex, numDays - 1);\n\n                long bucketEnd = periodStart + (bucketIndex + 1) * DAY_IN_MILLIS - 1;\n                long segmentEnd = Math.min(end, bucketEnd);\n                long segmentDur = (segmentEnd - current) + 1;\n                msBuckets[bucketIndex] += segmentDur;\n\n                current = bucketEnd + 1;\n            }\n        }\n        return msBuckets;\n    }\n\n    public static String getLocalizedFullDayNameFromLabel(@NonNull String label) {\n        switch (label) {\n            case \"Mon\":\n                return DayOfWeek.MONDAY.getDisplayName(TextStyle.FULL, Locale.getDefault());\n            case \"Tue\":\n                return DayOfWeek.TUESDAY.getDisplayName(TextStyle.FULL, Locale.getDefault());\n            case \"Wed\":\n                return DayOfWeek.WEDNESDAY.getDisplayName(TextStyle.FULL, Locale.getDefault());\n            case \"Thu\":\n                return DayOfWeek.THURSDAY.getDisplayName(TextStyle.FULL, Locale.getDefault());\n            case \"Fri\":\n                return DayOfWeek.FRIDAY.getDisplayName(TextStyle.FULL, Locale.getDefault());\n            case \"Sat\":\n                return DayOfWeek.SATURDAY.getDisplayName(TextStyle.FULL, Locale.getDefault());\n            case \"Sun\":\n                return DayOfWeek.SUNDAY.getDisplayName(TextStyle.FULL, Locale.getDefault());\n        }\n        throw new IllegalArgumentException(\"Invalid label \" + label);\n    }\n\n    public static String getLocalizedShortDayNameFromLabel(@NonNull String label) {\n        switch (label) {\n            case \"Mon\":\n                return DayOfWeek.MONDAY.getDisplayName(TextStyle.SHORT, Locale.getDefault());\n            case \"Tue\":\n                return DayOfWeek.TUESDAY.getDisplayName(TextStyle.SHORT, Locale.getDefault());\n            case \"Wed\":\n                return DayOfWeek.WEDNESDAY.getDisplayName(TextStyle.SHORT, Locale.getDefault());\n            case \"Thu\":\n                return DayOfWeek.THURSDAY.getDisplayName(TextStyle.SHORT, Locale.getDefault());\n            case \"Fri\":\n                return DayOfWeek.FRIDAY.getDisplayName(TextStyle.SHORT, Locale.getDefault());\n            case \"Sat\":\n                return DayOfWeek.SATURDAY.getDisplayName(TextStyle.SHORT, Locale.getDefault());\n            case \"Sun\":\n                return DayOfWeek.SUNDAY.getDisplayName(TextStyle.SHORT, Locale.getDefault());\n        }\n        throw new IllegalArgumentException(\"Invalid label \" + label);\n    }\n\n    @NonNull\n    public static String[] getHourLabels() {\n        boolean is24Hour = android.text.format.DateFormat.is24HourFormat(ContextUtils.getContext());\n        if (is24Hour) {\n            return new String[]{\n                    \"00:00\", \"01:00\", \"02:00\", \"03:00\", \"04:00\", \"05:00\", \"06:00\", \"07:00\", \"08:00\",\n                    \"09:00\", \"10:00\", \"11:00\", \"12:00\", \"13:00\", \"14:00\", \"15:00\", \"16:00\", \"17:00\",\n                    \"18:00\", \"19:00\", \"20:00\", \"21:00\", \"22:00\", \"23:00\"\n            };\n\n        }\n        return new String[]{\n                \"12 AM\", \"1 AM\", \"2 AM\", \"3 AM\", \"4 AM\", \"5 AM\", \"6 AM\", \"7 AM\", \"8 AM\", \"9 AM\",\n                \"10 AM\", \"11 AM\", \"12 PM\", \"1 PM\", \"2 PM\", \"3 PM\", \"4 PM\", \"5 PM\", \"6 PM\", \"7 PM\",\n                \"8 PM\", \"9 PM\", \"10 PM\", \"11 PM\"\n        };\n    }\n\n    @NonNull\n    public static String[] getWeekDayLabels() {\n        String[] labels;\n        int firstDayOfWeek = Calendar.getInstance(TimeZone.getDefault()).getFirstDayOfWeek();\n        if (firstDayOfWeek == Calendar.MONDAY) {\n            labels = new String[]{\"Mon\", \"Tue\", \"Wed\", \"Thu\", \"Fri\", \"Sat\", \"Sun\"};\n        } else if (firstDayOfWeek == Calendar.TUESDAY) {\n            labels = new String[]{\"Tue\", \"Wed\", \"Thu\", \"Fri\", \"Sat\", \"Sun\", \"Mon\"};\n        } else if (firstDayOfWeek == Calendar.WEDNESDAY) {\n            labels = new String[]{\"Wed\", \"Thu\", \"Fri\", \"Sat\", \"Sun\", \"Mon\", \"Tue\"};\n        } else if (firstDayOfWeek == Calendar.THURSDAY) {\n            labels = new String[]{\"Thu\", \"Fri\", \"Sat\", \"Sun\", \"Mon\", \"Tue\", \"Wed\"};\n        } else if (firstDayOfWeek == Calendar.FRIDAY) {\n            labels = new String[]{\"Fri\", \"Sat\", \"Sun\", \"Mon\", \"Tue\", \"Wed\", \"Thu\"};\n        } else if (firstDayOfWeek == Calendar.SATURDAY) {\n            labels = new String[]{\"Sat\", \"Sun\", \"Mon\", \"Tue\", \"Wed\", \"Thu\", \"Fri\"};\n        } else {// if (firstDayOfWeek == Calendar.SUNDAY) {\n            labels = new String[]{\"Sun\", \"Mon\", \"Tue\", \"Wed\", \"Thu\", \"Fri\", \"Sat\"};\n        }\n        return labels;\n    }\n\n    /**\n     * Find the next float value > maxValue that is divisible by 4.\n     * <p>\n     * Note: This only works for positive data.\n     */\n    public static float nextDivisibleBy4(float maxValue) {\n        float ceil = (float) Math.ceil(maxValue);\n        int multiple = ((int) ceil + 3) / 4;\n        float upperBound = multiple * 4;\n        if (upperBound <= maxValue) {\n            upperBound += 4;\n        }\n        return upperBound;\n    }\n\n    @NonNull\n    public static float[] convertToMinutes(@NonNull long[] durationsMillis) {\n        float[] minutes = new float[durationsMillis.length];\n        for (int i = 0; i < durationsMillis.length; i++) {\n            minutes[i] = durationsMillis[i] / 60_000f;\n        }\n        return minutes;\n    }\n\n    @NonNull\n    public static float[] convertToHours(@NonNull long[] durationsMillis) {\n        float[] hours = new float[durationsMillis.length];\n        for (int i = 0; i < durationsMillis.length; i++) {\n            hours[i] = durationsMillis[i] / 3_600_000f;\n        }\n        return hours;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/usage/UsageUtils.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.usage;\n\nimport android.content.Context;\nimport android.text.format.DateFormat;\n\nimport androidx.annotation.NonNull;\n\nimport java.util.Calendar;\nimport java.util.TimeZone;\n\nimport io.github.muntashirakon.AppManager.R;\n\npublic final class UsageUtils {\n    @NonNull\n    public static TimeInterval getTimeInterval(@IntervalType int interval, long date) {\n        switch (interval) {\n            case IntervalType.INTERVAL_WEEKLY:\n                return getWeekBounds(date);\n            case IntervalType.INTERVAL_DAILY:\n            default:\n                return getDayBounds(date);\n        }\n    }\n\n    @NonNull\n    public static CharSequence getIntervalDescription(@NonNull Context context,\n                                                      @IntervalType int interval,\n                                                      long date) {\n        switch (interval) {\n            case IntervalType.INTERVAL_WEEKLY:\n                return getWeekDescription(context, date);\n            case IntervalType.INTERVAL_DAILY:\n            default:\n                return getDateDescription(context, date);\n        }\n    }\n\n    public static long getNextDateFromInterval(@IntervalType int interval, long currentDate) {\n        switch (interval) {\n            case IntervalType.INTERVAL_WEEKLY:\n                return UsageUtils.getNextWeekDay(currentDate);\n            case IntervalType.INTERVAL_DAILY:\n            default:\n                return UsageUtils.getNextDay(currentDate);\n        }\n    }\n\n    public static long getPreviousDateFromInterval(@IntervalType int interval, long currentDate) {\n        switch (interval) {\n            case IntervalType.INTERVAL_WEEKLY:\n                return UsageUtils.getPreviousWeekDay(currentDate);\n            case IntervalType.INTERVAL_DAILY:\n            default:\n                return UsageUtils.getPreviousDay(currentDate);\n        }\n    }\n\n    public static boolean isToday(long date) {\n        Calendar calendar = Calendar.getInstance(TimeZone.getDefault());\n        calendar.setTimeInMillis(date);\n        moveToStartOfDay(calendar);\n        long targetTime = calendar.getTimeInMillis();\n        calendar.setTimeInMillis(System.currentTimeMillis());\n        moveToStartOfDay(calendar);\n        return targetTime == calendar.getTimeInMillis();\n    }\n\n    @NonNull\n    public static TimeInterval getToday() {\n        long timeNow = System.currentTimeMillis();\n        return getDayBounds(timeNow);\n    }\n\n    @NonNull\n    public static TimeInterval getLastWeek() {\n        long timeNow = System.currentTimeMillis();\n        return getWeekBounds(timeNow);\n    }\n\n    /**\n     * Gets the beginning and end time of the day in milliseconds for a given date\n     *\n     * @param date Input date in milliseconds\n     */\n    @NonNull\n    public static TimeInterval getDayBounds(long date) {\n        Calendar calendar = Calendar.getInstance(TimeZone.getDefault());\n        calendar.setTimeInMillis(date);\n        // Set to beginning of day (00:00:00.000)\n        moveToStartOfDay(calendar);\n        long beginningOfDay = calendar.getTimeInMillis();\n        // Set to end of day (23:59:59.999)\n        moveToEndOfDay(calendar);\n        long endOfDay = calendar.getTimeInMillis();\n        return new TimeInterval(IntervalType.INTERVAL_DAILY, beginningOfDay, endOfDay);\n    }\n\n    public static boolean hasNextDay(long date) {\n        Calendar calendar = Calendar.getInstance(TimeZone.getDefault());\n        calendar.setTimeInMillis(date);\n        calendar.add(Calendar.DAY_OF_MONTH, 1);\n        moveToStartOfDay(calendar);\n        long dayStart = calendar.getTimeInMillis();\n        calendar.setTimeInMillis(System.currentTimeMillis());\n        moveToStartOfDay(calendar);\n        long todayStart = calendar.getTimeInMillis();\n        return dayStart <= todayStart;\n    }\n\n    /**\n     * Gets the next day date from a given date\n     *\n     * @param date Input date in milliseconds\n     * @return Next day date in milliseconds\n     */\n    public static long getNextDay(long date) {\n        Calendar calendar = Calendar.getInstance(TimeZone.getDefault());\n        calendar.setTimeInMillis(date);\n        calendar.add(Calendar.DAY_OF_MONTH, 1);\n        return calendar.getTimeInMillis();\n    }\n\n    /**\n     * Gets the next day date from a given date\n     *\n     * @param date Input date in milliseconds\n     * @return Next day date in milliseconds\n     */\n    public static long getNextWeekDay(long date) {\n        Calendar calendar = Calendar.getInstance(TimeZone.getDefault());\n        calendar.setTimeInMillis(date);\n        calendar.add(Calendar.DAY_OF_MONTH, 7);\n        return calendar.getTimeInMillis();\n    }\n\n    /**\n     * Gets the previous day date from a given date\n     *\n     * @param date Input date in milliseconds\n     * @return Previous day date in milliseconds\n     */\n    public static long getPreviousDay(long date) {\n        Calendar calendar = Calendar.getInstance(TimeZone.getDefault());\n        calendar.setTimeInMillis(date);\n        calendar.add(Calendar.DAY_OF_MONTH, -1);\n        return calendar.getTimeInMillis();\n    }\n\n    /**\n     * Gets the previous day date from a given date\n     *\n     * @param date Input date in milliseconds\n     * @return Previous day date in milliseconds\n     */\n    public static long getPreviousWeekDay(long date) {\n        Calendar calendar = Calendar.getInstance(TimeZone.getDefault());\n        calendar.setTimeInMillis(date);\n        calendar.add(Calendar.DAY_OF_MONTH, -7);\n        return calendar.getTimeInMillis();\n    }\n\n    /**\n     * Gets the beginning and end time of a week in milliseconds\n     *\n     * @param date Any date in the week in milliseconds\n     */\n    @NonNull\n    public static TimeInterval getWeekBounds(long date) {\n        Calendar calendar = Calendar.getInstance();\n        calendar.setTimeInMillis(date);\n        // Clear time part for start of day calculation\n        moveToStartOfDay(calendar);\n        // Move to the first day of the week according to locale\n        calendar.set(Calendar.DAY_OF_WEEK, calendar.getFirstDayOfWeek());\n        long startOfWeekMillis = calendar.getTimeInMillis();\n        // Move to the last day of the week\n        calendar.add(Calendar.DAY_OF_WEEK, 6);\n        // Set time to the end of the day (23:59:59.999) for the last day\n        moveToEndOfDay(calendar);\n        long endOfWeekMillis = calendar.getTimeInMillis();\n\n        return new TimeInterval(IntervalType.INTERVAL_WEEKLY, startOfWeekMillis, endOfWeekMillis);\n    }\n\n    /**\n     * Returns a CharSequence describing the given dateMillis relative to today.\n     *\n     * @param context    Android context to access resources\n     * @param dateMillis Date in milliseconds since epoch\n     * @return description of date\n     */\n    @NonNull\n    public static CharSequence getWeekDescription(Context context, long dateMillis) {\n        TimeInterval targetInterval = getWeekBounds(dateMillis);\n        long today = System.currentTimeMillis();\n\n        if (today >= targetInterval.getStartTime() && today <= targetInterval.getEndTime()) {\n            return context.getString(R.string.usage_this_week);\n        }\n\n        long sameDayLastWeek = getPreviousWeekDay(today);\n        if (sameDayLastWeek >= targetInterval.getStartTime() && sameDayLastWeek <= targetInterval.getEndTime()) {\n            return context.getString(R.string.usage_last_week);\n        }\n\n        java.text.DateFormat formatter = DateFormat.getMediumDateFormat(context);\n        return formatter.format(targetInterval.getStartTime()) + \"–\" + formatter.format(targetInterval.getEndTime());\n    }\n\n    /**\n     * Returns a CharSequence describing the given dateMillis relative to today.\n     *\n     * @param context    Android context to access resources\n     * @param dateMillis Date in milliseconds since epoch\n     * @return description of date\n     */\n    @NonNull\n    public static CharSequence getDateDescription(Context context, long dateMillis) {\n        Calendar inputCal = Calendar.getInstance();\n        inputCal.setTimeInMillis(dateMillis);\n\n        Calendar todayCal = Calendar.getInstance();\n\n        // Clear time components for accurate comparison\n        moveToStartOfDay(todayCal);\n        moveToStartOfDay(inputCal);\n\n        long diffMillis = todayCal.getTimeInMillis() - inputCal.getTimeInMillis();\n        long oneDayMillis = 24 * 60 * 60 * 1000L;\n\n        if (diffMillis == 0) {\n            // Same day -> today\n            return context.getString(R.string.usage_today);\n        } else if (diffMillis == oneDayMillis) {\n            // Yesterday\n            return context.getString(R.string.usage_yesterday);\n        } else {\n            // Otherwise, formatted date string using system locale and patterns\n            return DateFormat.getMediumDateFormat(context).format(dateMillis);\n        }\n    }\n\n    public static void moveToStartOfDay(@NonNull Calendar cal) {\n        cal.set(Calendar.HOUR_OF_DAY, 0);\n        cal.set(Calendar.MINUTE, 0);\n        cal.set(Calendar.SECOND, 0);\n        cal.set(Calendar.MILLISECOND, 0);\n    }\n\n    public static void moveToEndOfDay(@NonNull Calendar cal) {\n        cal.set(Calendar.HOUR_OF_DAY, 23);\n        cal.set(Calendar.MINUTE, 59);\n        cal.set(Calendar.SECOND, 59);\n        cal.set(Calendar.MILLISECOND, 999);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/users/Groups.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.users;\n\nimport android.os.UserHandleHidden;\nimport android.system.ErrnoException;\n\nimport androidx.annotation.NonNull;\n\nimport java.util.HashMap;\nimport java.util.Locale;\nimport java.util.Map;\n\nimport io.github.muntashirakon.AppManager.utils.ExUtils;\nimport io.github.muntashirakon.compat.system.OsCompat;\nimport io.github.muntashirakon.compat.system.StructGroup;\n\npublic class Groups {\n    private static final int AID_USER_OFFSET = 100000;\n    private static final int AID_APP_START = 10000;\n    private static final int AID_APP_END = 19999;\n    private static final int AID_CACHE_GID_START = 20000;\n    private static final int AID_CACHE_GID_END = 29999;\n    private static final int AID_EXT_GID_START = 30000;\n    private static final int AID_EXT_GID_END = 39999;\n    private static final int AID_EXT_CACHE_GID_START = 40000;\n    private static final int AID_EXT_CACHE_GID_END = 49999;\n    private static final int AID_SHARED_GID_START = 50000;\n    private static final int AID_SHARED_GID_END = 59999;\n    private static final int AID_ISOLATED_START = 99000;\n\n    private static final Map<Integer, String> sGidGroupMap = new HashMap<>();\n\n    public static Map<Integer, String> getGidGroupMap(boolean reload) {\n        synchronized (sGidGroupMap) {\n            if (sGidGroupMap.isEmpty() || reload) {\n                try {\n                    OsCompat.setgrent();\n                    StructGroup passwd;\n                    while ((passwd = OsCompat.getgrent()) != null) {\n                        sGidGroupMap.put(passwd.gr_id, passwd.gr_name);\n                    }\n                } catch (ErrnoException e) {\n                    e.printStackTrace();\n                } finally {\n                    ExUtils.exceptionAsIgnored(OsCompat::endgrent);\n                }\n            }\n            return sGidGroupMap;\n        }\n    }\n\n    @NonNull\n    public static String getGroupName(int uid) {\n        String name = getGidGroupMap(false).get(uid);\n        if (name != null) {\n            return name;\n        }\n        return formatGid(uid);\n    }\n\n    @NonNull\n    public static String formatGid(int gid) { // print_app_name_from_gid\n        int appid = gid % AID_USER_OFFSET;\n        int userid = gid / AID_USER_OFFSET;\n        if (appid >= AID_ISOLATED_START) {\n            return String.format(Locale.ROOT, \"u%d_i%d\", userid, appid - AID_ISOLATED_START);\n        } else if (userid == 0 && appid >= AID_SHARED_GID_START && appid <= AID_SHARED_GID_END) {\n            return String.format(Locale.ROOT, \"all_a%d\", appid - AID_SHARED_GID_START);\n        } else if (appid >= AID_EXT_CACHE_GID_START && appid <= AID_EXT_CACHE_GID_END) {\n            return String.format(Locale.ROOT, \"u%d_a%d_ext_cache\", userid, appid - AID_EXT_CACHE_GID_START);\n        } else if (appid >= AID_EXT_GID_START && appid <= AID_EXT_GID_END) {\n            return String.format(Locale.ROOT, \"u%d_a%d_ext\", userid, appid - AID_EXT_GID_START);\n        } else if (appid >= AID_CACHE_GID_START && appid <= AID_CACHE_GID_END) {\n            return String.format(Locale.ROOT, \"u%d_a%d_cache\", userid, appid - AID_CACHE_GID_START);\n        } else if (appid < AID_APP_START) {\n            return String.valueOf(gid); // As per UserHandle\n        } else {\n            return String.format(Locale.ROOT, \"u%d_a%d\", userid, appid - AID_APP_START);\n        }\n    }\n\n    public static int getCacheAppGid(int uid) {\n        int appId = uid % AID_USER_OFFSET;\n        int userId = uid / AID_USER_OFFSET;\n        if (appId >= AID_APP_START && appId <= AID_APP_END) {\n            return UserHandleHidden.getUid(userId, (appId - AID_APP_START) + AID_CACHE_GID_START);\n        } else {\n            return -1;\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/users/Owners.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.users;\n\nimport android.os.UserHandleHidden;\nimport android.system.ErrnoException;\nimport android.system.StructPasswd;\nimport android.text.TextUtils;\n\nimport androidx.annotation.NonNull;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport io.github.muntashirakon.AppManager.compat.ProcessCompat;\nimport io.github.muntashirakon.AppManager.utils.ExUtils;\nimport io.github.muntashirakon.compat.system.OsCompat;\n\npublic class Owners {\n    private static final Map<Integer, String> sUidOwnerMap = new HashMap<>();\n    private static final Map<String, Integer> sOwnerUidMap = new HashMap<>();\n\n    public static Map<Integer, String> getUidOwnerMap(boolean reload) {\n        synchronized (sUidOwnerMap) {\n            if (sUidOwnerMap.isEmpty() || reload) {\n                try {\n                    OsCompat.setpwent();\n                    StructPasswd passwd;\n                    while ((passwd = OsCompat.getpwent()) != null) {\n                        sUidOwnerMap.put(passwd.pw_uid, passwd.pw_name);\n                        sOwnerUidMap.put(passwd.pw_name, passwd.pw_uid);\n                    }\n                } catch (ErrnoException e) {\n                    e.printStackTrace();\n                } finally {\n                    ExUtils.exceptionAsIgnored(OsCompat::endpwent);\n                }\n            }\n            return sUidOwnerMap;\n        }\n    }\n\n    @NonNull\n    public static String getOwnerName(int uid) {\n        String name = getUidOwnerMap(false).get(uid);\n        if (name != null) {\n            return name;\n        }\n        return formatUid(uid);\n    }\n\n    public static int parseUid(String uidString) {\n        // This is effectively the reverse of #formatUid(int)\n        if (TextUtils.isDigitsOnly(uidString)) {\n            return Integer.parseInt(uidString);\n        }\n        getUidOwnerMap(false);\n        Integer uid = sOwnerUidMap.get(uidString);\n        if (uid != null) {\n            return uid;\n        }\n        if (!uidString.isEmpty() && uidString.charAt(0) == 'u') {\n            int i = 1;\n            while (TextUtils.isDigitsOnly(String.valueOf(uidString.charAt(i)))) {\n                ++i;\n            }\n            int userId = Integer.parseInt(uidString.substring(1, i));\n            // Skip any underscore\n            if (uidString.charAt(i) == '_') {\n                ++i;\n            }\n            int appId;\n            String type;\n            if (uidString.charAt(i+1) == 'i') {\n                type = uidString.substring(i, i + 2);\n                i += 2;\n            } else {\n                type = uidString.substring(i, i + 1);\n                ++i;\n            }\n            int shortAppId = Integer.parseInt(uidString.substring(i));\n            switch (type) {\n                case \"s\":\n                    appId = shortAppId;\n                    break;\n                case \"a\":\n                    appId = ProcessCompat.FIRST_APPLICATION_UID + shortAppId;\n                    break;\n                case \"i\":\n                    appId = ProcessCompat.FIRST_ISOLATED_UID + shortAppId;\n                    break;\n                case \"ai\":\n                    appId = ProcessCompat.FIRST_APP_ZYGOTE_ISOLATED_UID + shortAppId;\n                    break;\n                default:\n                    throw new IllegalArgumentException(\"Invalid u-prefixed string: \" + uidString);\n            }\n            return UserHandleHidden.getUid(userId, appId);\n        }\n        throw new IllegalArgumentException(\"Malformed UID string: \" + uidString);\n    }\n\n    @NonNull\n    public static String formatUid(int uid) {\n        StringBuilder sb = new StringBuilder();\n        UserHandleHidden.formatUid(sb, uid);\n        if (sb.indexOf(\"u\") == 0) { // u\\d+([ais]|ai)\\d+\n            // u-prefixed name, add _ (underscore) after u\\d+\n            int i = 1;\n            while (TextUtils.isDigitsOnly(String.valueOf(sb.charAt(i)))) {\n                ++i;\n            }\n            sb.insert(i, '_');\n        }\n        return sb.toString();\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/users/UserInfo.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.users;\n\nimport android.content.Context;\nimport android.os.UserHandle;\nimport android.os.UserHandleHidden;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport io.github.muntashirakon.util.LocalizedString;\n\npublic class UserInfo implements LocalizedString {\n    @NonNull\n    public final UserHandle userHandle;\n    public final int id;\n    @Nullable\n    public final String name;\n\n    UserInfo(@NonNull android.content.pm.UserInfo userInfo) {\n        userHandle = userInfo.getUserHandle();\n        id = userInfo.id;\n        String username = userInfo.name;\n        if (username == null) {\n            this.name = id == UserHandleHidden.myUserId() ? \"This\" : \"Other\";\n        } else this.name = username;\n    }\n\n    @NonNull\n    @Override\n    public CharSequence toLocalizedString(@NonNull Context context) {\n        return name == null ? String.valueOf(id) : (name + \" (\" + id + \")\");\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/users/Users.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.users;\n\nimport android.annotation.UserIdInt;\nimport android.content.Context;\nimport android.os.Build;\nimport android.os.IUserManager;\nimport android.os.Process;\nimport android.os.RemoteException;\nimport android.os.UserHandle;\nimport android.os.UserHandleHidden;\nimport android.os.UserManager;\n\nimport androidx.annotation.IntRange;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport io.github.muntashirakon.AppManager.compat.ManifestCompat;\nimport io.github.muntashirakon.AppManager.ipc.LocalServices;\nimport io.github.muntashirakon.AppManager.ipc.ProxyBinder;\nimport io.github.muntashirakon.AppManager.logs.Log;\nimport io.github.muntashirakon.AppManager.self.SelfPermissions;\nimport io.github.muntashirakon.AppManager.settings.Ops;\nimport io.github.muntashirakon.AppManager.settings.Prefs;\nimport io.github.muntashirakon.AppManager.utils.ArrayUtils;\nimport io.github.muntashirakon.AppManager.utils.ExUtils;\n\npublic final class Users {\n    public static final String TAG = \"Users\";\n\n    private static final List<UserInfo> sUserInfoList = new ArrayList<>();\n    private static boolean sUnprivilegedMode = false;\n\n    @NonNull\n    public static List<UserInfo> getAllUsers() {\n        if (sUserInfoList.isEmpty() || sUnprivilegedMode) {\n            int uid = getSelfOrRemoteUid();\n            IUserManager userManager = IUserManager.Stub.asInterface(ProxyBinder.getService(Context.USER_SERVICE));\n            if (SelfPermissions.checkSelfOrRemotePermission(ManifestCompat.permission.MANAGE_USERS)\n                    || SelfPermissions.checkSelfOrRemotePermission(ManifestCompat.permission.CREATE_USERS)) {\n                if (sUnprivilegedMode) {\n                    // User info were previously fetched in unprivileged mode. We need to fetch them again.\n                    sUnprivilegedMode = false;\n                    sUserInfoList.clear();\n                }\n                List<android.content.pm.UserInfo> userInfoList = null;\n                try {\n                    userInfoList = userManager.getUsers(true);\n                } catch (RemoteException | NoSuchMethodError e) {\n                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {\n                        userInfoList = ExUtils.exceptionAsNull(() -> userManager.getUsers(true, true, true));\n                    }\n                }\n                if (userInfoList != null) {\n                    for (android.content.pm.UserInfo userInfo : userInfoList) {\n                        try {\n                            if (uid == Ops.SHELL_UID && userManager.hasUserRestriction(UserManager.DISALLOW_DEBUGGING_FEATURES, userInfo.id)) {\n                                Log.w(TAG, \"Shell cannot access user %s as debugging is disallowed.\", userInfo.id);\n                                continue;\n                            }\n                        } catch (RemoteException e) {\n                            ExUtils.rethrowFromSystemServer(e);\n                        }\n                        sUserInfoList.add(new UserInfo(userInfo));\n                    }\n                }\n            }\n            if (sUserInfoList.isEmpty()) {\n                sUnprivilegedMode = true;\n                // The above didn't succeed, try no-root mode\n                Log.d(TAG, \"Missing required permission: MANAGE_USERS or CREATE_USERS (7+). Falling back to unprivileged mode.\");\n                List<android.content.pm.UserInfo> userInfoList = userManager.getProfiles(\n                        UserHandleHidden.getUserId(uid), false);\n                for (android.content.pm.UserInfo userInfo : userInfoList) {\n                    sUserInfoList.add(new UserInfo(userInfo));\n                }\n            }\n        }\n        return sUserInfoList;\n    }\n\n    @NonNull\n    @UserIdInt\n    public static int[] getAllUserIds() {\n        getAllUsers();\n        List<Integer> users = new ArrayList<>();\n        for (UserInfo userInfo : sUserInfoList) {\n            users.add(userInfo.id);\n        }\n        return ArrayUtils.convertToIntArray(users);\n    }\n\n    @NonNull\n    public static List<UserInfo> getUsers() {\n        getAllUsers();\n        int[] selectedUserIds = Prefs.Misc.getSelectedUsers();\n        List<UserInfo> users = new ArrayList<>();\n        for (UserInfo userInfo : sUserInfoList) {\n            if (selectedUserIds == null || ArrayUtils.contains(selectedUserIds, userInfo.id)) {\n                users.add(userInfo);\n            }\n        }\n        return users;\n    }\n\n    @NonNull\n    @UserIdInt\n    public static int[] getUsersIds() {\n        getAllUsers();\n        int[] selectedUserIds = Prefs.Misc.getSelectedUsers();\n        List<Integer> users = new ArrayList<>();\n        for (UserInfo userInfo : sUserInfoList) {\n            if (selectedUserIds == null || ArrayUtils.contains(selectedUserIds, userInfo.id)) {\n                users.add(userInfo.id);\n            }\n        }\n        return ArrayUtils.convertToIntArray(users);\n    }\n\n    @Nullable\n    public static UserHandle getUserHandle(@UserIdInt int userId) {\n        getAllUsers();\n        for (UserInfo userInfo : sUserInfoList) {\n            if (userInfo.id == userId) {\n                return userInfo.userHandle;\n            }\n        }\n        return null;\n    }\n\n    @IntRange(from = 0)\n    public static int getSelfOrRemoteUid() {\n        try {\n            return LocalServices.getAmService().getUid();\n        } catch (RemoteException e) {\n            return Process.myUid();\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/utils/AlphanumComparator.java",
    "content": "// SPDX-License-Identifier: MIT AND GPL-3.0\n\npackage io.github.muntashirakon.AppManager.utils;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport java.util.Comparator;\n\n// Copyright 2007-2017 David Koelle\n// Copyright 2025 Muntashir Al-Islam\npublic class AlphanumComparator implements Comparator<String> {\n    private static boolean isDigit(char ch) {\n        return ((ch >= 48) && (ch <= 57));\n    }\n\n    /**\n     * Length of string is passed in for improved efficiency (only need to calculate it once)\n     **/\n    @NonNull\n    private static String getChunk(@NonNull String s, int sLength, int marker) {\n        StringBuilder chunk = new StringBuilder();\n        char c = s.charAt(marker);\n        chunk.append(c);\n        marker++;\n        if (isDigit(c)) {\n            while (marker < sLength) {\n                c = s.charAt(marker);\n                if (!isDigit(c))\n                    break;\n                chunk.append(c);\n                marker++;\n            }\n        } else {\n            while (marker < sLength) {\n                c = s.charAt(marker);\n                if (isDigit(c))\n                    break;\n                chunk.append(c);\n                marker++;\n            }\n        }\n        return chunk.toString();\n    }\n\n\n    private static int compareString(@Nullable String s1, @Nullable String s2, boolean ignoreCase) {\n        if ((s1 == null) || (s2 == null)) {\n            return 0;\n        }\n\n        int thisMarker = 0;\n        int thatMarker = 0;\n        int s1Length = s1.length();\n        int s2Length = s2.length();\n\n        while (thisMarker < s1Length && thatMarker < s2Length) {\n            String thisChunk = getChunk(s1, s1Length, thisMarker);\n            thisMarker += thisChunk.length();\n\n            String thatChunk = getChunk(s2, s2Length, thatMarker);\n            thatMarker += thatChunk.length();\n\n            // If both chunks contain numeric characters, sort them numerically\n            int result;\n            if (isDigit(thisChunk.charAt(0)) && isDigit(thatChunk.charAt(0))) {\n                // Simple chunk comparison by length.\n                int thisChunkLength = thisChunk.length();\n                result = thisChunkLength - thatChunk.length();\n                // If equal, the first different number counts\n                if (result == 0) {\n                    for (int i = 0; i < thisChunkLength; i++) {\n                        result = thisChunk.charAt(i) - thatChunk.charAt(i);\n                        if (result != 0) {\n                            return result;\n                        }\n                    }\n                }\n            } else {\n                result = ignoreCase\n                        ? thisChunk.compareToIgnoreCase(thatChunk)\n                        : thisChunk.compareTo(thatChunk);\n            }\n\n            if (result != 0)\n                return result;\n        }\n\n        return s1Length - s2Length;\n    }\n\n    public static int compareString(@Nullable String s1, @Nullable String s2) {\n        return compareString(s1, s2, false);\n    }\n\n    public static int compareStringIgnoreCase(@Nullable String s1, @Nullable String s2) {\n        return compareString(s1, s2, true);\n    }\n\n    public int compare(String s1, String s2) {\n        return compareString(s1, s2);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/utils/AppPref.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.utils;\n\nimport android.annotation.SuppressLint;\nimport android.content.Context;\nimport android.content.SharedPreferences;\nimport android.content.pm.PackageInfo;\nimport android.content.pm.PackageInstaller;\nimport android.net.Uri;\nimport android.os.Build;\nimport android.os.Environment;\nimport android.os.UserHandleHidden;\nimport android.util.Log;\nimport android.view.View;\n\nimport androidx.annotation.IntDef;\nimport androidx.annotation.Keep;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.appcompat.app.AppCompatDelegate;\n\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Objects;\n\nimport io.github.muntashirakon.AppManager.BuildConfig;\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.apk.signing.SigSchemes;\nimport io.github.muntashirakon.AppManager.backup.BackupFlags;\nimport io.github.muntashirakon.AppManager.backup.CryptoUtils;\nimport io.github.muntashirakon.AppManager.crypto.auth.AuthManager;\nimport io.github.muntashirakon.AppManager.debloat.DebloaterListOptions;\nimport io.github.muntashirakon.AppManager.details.AppDetailsFragment;\nimport io.github.muntashirakon.AppManager.fm.FmListOptions;\nimport io.github.muntashirakon.AppManager.logcat.helper.LogcatHelper;\nimport io.github.muntashirakon.AppManager.main.MainListOptions;\nimport io.github.muntashirakon.AppManager.rules.struct.ComponentRule;\nimport io.github.muntashirakon.AppManager.runningapps.RunningAppsActivity;\nimport io.github.muntashirakon.AppManager.settings.Ops;\n\npublic class AppPref {\n    private static final String PREF_NAME = \"preferences\";\n\n    private static final int PREF_SKIP = 5;\n\n    /**\n     * Preference keys. It's necessary to do things manually as the shared prefs in Android is\n     * literary unusable.\n     * <br/>\n     * Keep these in sync with {@link #getDefaultValue(PrefKey)}.\n     */\n    @Keep\n    public enum PrefKey {\n        PREF_ADB_LOCAL_SERVER_PORT_INT,\n        PREF_APP_OP_SHOW_DEFAULT_BOOL,\n        PREF_APP_OP_SORT_ORDER_INT,\n        PREF_APP_THEME_INT,\n        PREF_APP_THEME_CUSTOM_INT,\n        // This is just a placeholder to prevent crash\n        PREF_APP_THEME_PURE_BLACK_BOOL,\n        // We store this in plain text because if the attackers attack us, they can also attack the other apps\n        PREF_AUTHORIZATION_KEY_STR,\n\n        PREF_BACKUP_ANDROID_KEYSTORE_BOOL,\n        PREF_BACKUP_COMPRESSION_METHOD_STR,\n        PREF_BACKUP_FLAGS_INT,\n        PREF_BACKUP_VOLUME_STR,\n\n        PREF_COMPONENTS_SORT_ORDER_INT,\n        PREF_CONCURRENCY_THREAD_COUNT_INT,\n        PREF_CUSTOM_LOCALE_STR,\n\n        PREF_DISPLAY_CHANGELOG_BOOL,\n        PREF_DISPLAY_CHANGELOG_LAST_VERSION_LONG,\n\n        PREF_DEBLOATER_FILTER_FLAGS_INT,\n\n        PREF_ENABLE_KILL_FOR_SYSTEM_BOOL,\n        PREF_ENABLE_AUTO_LOCK_BOOL,\n        PREF_ENABLE_PERSISTENT_SESSION_BOOL,\n        PREF_ENABLE_SCREEN_LOCK_BOOL,\n        PREF_ENABLED_FEATURES_INT,\n        PREF_ENCRYPTION_STR,\n\n        PREF_FREEZE_TYPE_INT,\n        PREF_FM_DISPLAY_IN_LAUNCHER_BOOL,\n        PREF_FM_HOME_STR,\n        PREF_FM_LAST_PATH_STR,\n        PREF_FM_OPTIONS_INT,\n        PREF_FM_REMEMBER_LAST_PATH_BOOL,\n        PREF_FM_SORT_ORDER_INT,\n        PREF_FM_SORT_REVERSE_BOOL,\n\n        PREF_GLOBAL_BLOCKING_ENABLED_BOOL,\n        PREF_DEFAULT_BLOCKING_METHOD_STR,\n\n        PREF_INSTALLER_BLOCK_TRACKERS_BOOL,\n        PREF_INSTALLER_ALWAYS_ON_BACKGROUND_BOOL,\n        PREF_INSTALLER_DEFAULT_PKG_SOURCE_INT,\n        PREF_INSTALLER_DISABLE_VERIFICATION_BOOL,\n        PREF_INSTALLER_DISPLAY_CHANGES_BOOL,\n        PREF_INSTALLER_FORCE_DEX_OPT_BOOL,\n        PREF_INSTALLER_INSTALL_LOCATION_INT,\n        PREF_INSTALLER_INSTALLER_APP_STR,\n        PREF_INSTALLER_SET_ORIGIN_BOOL,\n        PREF_INSTALLER_SIGN_APK_BOOL,\n        PREF_INSTALLER_UPDATE_OWNERSHIP_BOOL,\n\n        PREF_LAST_VERSION_CODE_LONG,\n        PREF_LAYOUT_ORIENTATION_INT,\n\n        PREF_LOG_VIEWER_BUFFER_INT,\n        PREF_LOG_VIEWER_DEFAULT_LOG_LEVEL_INT,\n        PREF_LOG_VIEWER_DISPLAY_LIMIT_INT,\n        PREF_LOG_VIEWER_EXPAND_BY_DEFAULT_BOOL,\n        PREF_LOG_VIEWER_FILTER_PATTERN_STR,\n        PREF_LOG_VIEWER_OMIT_SENSITIVE_INFO_BOOL,\n        PREF_LOG_VIEWER_SHOW_PID_TID_TIMESTAMP_BOOL,\n        PREF_LOG_VIEWER_WRITE_PERIOD_INT,\n\n        PREF_MAIN_WINDOW_FILTER_FLAGS_INT,\n        PREF_MAIN_WINDOW_FILTER_PROFILE_STR,\n        PREF_MAIN_WINDOW_SORT_ORDER_INT,\n        PREF_MAIN_WINDOW_SORT_REVERSE_BOOL,\n\n        PREF_MODE_OF_OPS_STR,\n        PREF_OPEN_PGP_PACKAGE_STR,\n        PREF_OPEN_PGP_USER_ID_STR,\n        PREF_PERMISSIONS_SORT_ORDER_INT,\n        PREF_OVERLAYS_SORT_ORDER_INT,\n\n        PREF_RUNNING_APPS_FILTER_FLAGS_INT,\n        PREF_RUNNING_APPS_SORT_ORDER_INT,\n\n        PREF_SAVED_APK_FORMAT_STR,\n        PREF_SELECTED_USERS_STR,\n        PREF_SEND_NOTIFICATIONS_TO_CONNECTED_DEVICES_BOOL,\n        PREF_SIGNATURE_SCHEMES_INT,\n        PREF_SHOW_DISCLAIMER_BOOL,\n\n        PREF_TIPS_PREFS_INT,\n\n        PREF_VIRUS_TOTAL_API_KEY_STR,\n        PREF_VIRUS_TOTAL_PROMPT_BEFORE_UPLOADING_BOOL,\n\n        PREF_USE_SYSTEM_FONT_BOOL,\n        PREF_ZIP_ALIGN_BOOL,\n        ;\n\n        private static final String[] sKeys = new String[values().length];\n        @Type\n        private static final int[] sTypes = new int[values().length];\n        private static final List<PrefKey> sPrefKeyList = Arrays.asList(values());\n\n        static {\n            String keyStr;\n            int typeSeparator;\n            PrefKey[] keyValues = values();\n            for (int i = 0; i < keyValues.length; ++i) {\n                keyStr = keyValues[i].name();\n                typeSeparator = keyStr.lastIndexOf('_');\n                sKeys[i] = keyStr.substring(PREF_SKIP, typeSeparator).toLowerCase(Locale.ROOT);\n                sTypes[i] = inferType(keyStr.substring(typeSeparator + 1));\n            }\n        }\n\n        public static int indexOf(PrefKey key) {\n            return sPrefKeyList.indexOf(key);\n        }\n\n        public static int indexOf(String key) {\n            return ArrayUtils.indexOf(sKeys, key);\n        }\n\n        @Type\n        private static int inferType(@NonNull String typeName) {\n            switch (typeName) {\n                case \"BOOL\":\n                    return TYPE_BOOLEAN;\n                case \"FLOAT\":\n                    return TYPE_FLOAT;\n                case \"INT\":\n                    return TYPE_INTEGER;\n                case \"LONG\":\n                    return TYPE_LONG;\n                case \"STR\":\n                    return TYPE_STRING;\n                default:\n                    throw new IllegalArgumentException(\"Unsupported type.\");\n            }\n        }\n    }\n\n    @IntDef(value = {\n            TYPE_BOOLEAN,\n            TYPE_FLOAT,\n            TYPE_INTEGER,\n            TYPE_LONG,\n            TYPE_STRING\n    })\n    @Retention(RetentionPolicy.SOURCE)\n    public @interface Type {\n    }\n\n    public static final int TYPE_BOOLEAN = 0;\n    public static final int TYPE_FLOAT = 1;\n    public static final int TYPE_INTEGER = 2;\n    public static final int TYPE_LONG = 3;\n    public static final int TYPE_STRING = 4;\n\n    @SuppressLint(\"StaticFieldLeak\")\n    private static AppPref sAppPref;\n\n    @NonNull\n    public static AppPref getInstance() {\n        if (sAppPref == null) {\n            sAppPref = new AppPref(ContextUtils.getContext());\n        }\n        return sAppPref;\n    }\n\n    @NonNull\n    public static AppPref getNewInstance(@NonNull Context context) {\n        return new AppPref(context);\n    }\n\n    @NonNull\n    public static Object get(PrefKey key) {\n        int index = PrefKey.indexOf(key);\n        AppPref appPref = getInstance();\n        switch (PrefKey.sTypes[index]) {\n            case TYPE_BOOLEAN:\n                return appPref.mPreferences.getBoolean(PrefKey.sKeys[index], (boolean) appPref.getDefaultValue(key));\n            case TYPE_FLOAT:\n                return appPref.mPreferences.getFloat(PrefKey.sKeys[index], (float) appPref.getDefaultValue(key));\n            case TYPE_INTEGER:\n                return appPref.mPreferences.getInt(PrefKey.sKeys[index], (int) appPref.getDefaultValue(key));\n            case TYPE_LONG:\n                return appPref.mPreferences.getLong(PrefKey.sKeys[index], (long) appPref.getDefaultValue(key));\n            case TYPE_STRING:\n                return Objects.requireNonNull(appPref.mPreferences.getString(PrefKey.sKeys[index],\n                        (String) appPref.getDefaultValue(key)));\n        }\n        throw new IllegalArgumentException(\"Unknown key or type.\");\n    }\n\n    public static boolean getBoolean(PrefKey key) {\n        return (boolean) get(key);\n    }\n\n    public static int getInt(PrefKey key) {\n        return (int) get(key);\n    }\n\n    public static long getLong(PrefKey key) {\n        return (long) get(key);\n    }\n\n    @NonNull\n    public static String getString(PrefKey key) {\n        return (String) get(key);\n    }\n\n    public static void set(PrefKey key, Object value) {\n        getInstance().setPref(key, value);\n    }\n\n    @NonNull\n    private final SharedPreferences mPreferences;\n    @NonNull\n    private final SharedPreferences.Editor mEditor;\n\n    private final Context mContext;\n\n    @SuppressLint(\"CommitPrefEdits\")\n    private AppPref(@NonNull Context context) {\n        mContext = context;\n        mPreferences = context.getSharedPreferences(PREF_NAME, Context.MODE_PRIVATE);\n        mEditor = mPreferences.edit();\n        init();\n    }\n\n    public void setPref(PrefKey key, Object value) {\n        int index = PrefKey.indexOf(key);\n        if (value instanceof Boolean) mEditor.putBoolean(PrefKey.sKeys[index], (Boolean) value);\n        else if (value instanceof Float) mEditor.putFloat(PrefKey.sKeys[index], (Float) value);\n        else if (value instanceof Integer) mEditor.putInt(PrefKey.sKeys[index], (Integer) value);\n        else if (value instanceof Long) mEditor.putLong(PrefKey.sKeys[index], (Long) value);\n        else if (value instanceof String) mEditor.putString(PrefKey.sKeys[index], (String) value);\n        mEditor.apply();\n        mEditor.commit();\n    }\n\n    public void setPref(String key, @Nullable Object value) {\n        int index = PrefKey.indexOf(key);\n        if (index == -1) throw new IllegalArgumentException(\"Invalid key: \" + key);\n        // Set default value if the requested value is null\n        if (value == null) value = getDefaultValue(PrefKey.sPrefKeyList.get(index));\n        if (value instanceof Boolean) mEditor.putBoolean(key, (Boolean) value);\n        else if (value instanceof Float) mEditor.putFloat(key, (Float) value);\n        else if (value instanceof Integer) mEditor.putInt(key, (Integer) value);\n        else if (value instanceof Long) mEditor.putLong(key, (Long) value);\n        else if (value instanceof String) mEditor.putString(key, (String) value);\n        mEditor.apply();\n        mEditor.commit();\n    }\n\n    @NonNull\n    public Object get(String key) {\n        int index = PrefKey.indexOf(key);\n        if (index == -1) throw new IllegalArgumentException(\"Invalid key: \" + key);\n        Object defaultValue = getDefaultValue(PrefKey.sPrefKeyList.get(index));\n        switch (PrefKey.sTypes[index]) {\n            case TYPE_BOOLEAN:\n                return mPreferences.getBoolean(key, (boolean) defaultValue);\n            case TYPE_FLOAT:\n                return mPreferences.getFloat(key, (float) defaultValue);\n            case TYPE_INTEGER:\n                return mPreferences.getInt(key, (int) defaultValue);\n            case TYPE_LONG:\n                return mPreferences.getLong(key, (long) defaultValue);\n            case TYPE_STRING:\n                return Objects.requireNonNull(mPreferences.getString(key, (String) defaultValue));\n        }\n        throw new IllegalArgumentException(\"Unknown key or type.\");\n    }\n\n    @NonNull\n    public Object getValue(PrefKey key) {\n        int index = PrefKey.indexOf(key);\n        switch (PrefKey.sTypes[index]) {\n            case TYPE_BOOLEAN:\n                return mPreferences.getBoolean(PrefKey.sKeys[index], (boolean) getDefaultValue(key));\n            case TYPE_FLOAT:\n                return mPreferences.getFloat(PrefKey.sKeys[index], (float) getDefaultValue(key));\n            case TYPE_INTEGER:\n                return mPreferences.getInt(PrefKey.sKeys[index], (int) getDefaultValue(key));\n            case TYPE_LONG:\n                return mPreferences.getLong(PrefKey.sKeys[index], (long) getDefaultValue(key));\n            case TYPE_STRING:\n                return Objects.requireNonNull(mPreferences.getString(PrefKey.sKeys[index],\n                        (String) getDefaultValue(key)));\n        }\n        throw new IllegalArgumentException(\"Unknown key or type.\");\n    }\n\n    private void init() {\n        for (int i = 0; i < PrefKey.sKeys.length; ++i) {\n            if (!mPreferences.contains(PrefKey.sKeys[i])) {\n                switch (PrefKey.sTypes[i]) {\n                    case TYPE_BOOLEAN:\n                        mEditor.putBoolean(PrefKey.sKeys[i], (boolean) getDefaultValue(PrefKey.sPrefKeyList.get(i)));\n                        break;\n                    case TYPE_FLOAT:\n                        mEditor.putFloat(PrefKey.sKeys[i], (float) getDefaultValue(PrefKey.sPrefKeyList.get(i)));\n                        break;\n                    case TYPE_INTEGER:\n                        mEditor.putInt(PrefKey.sKeys[i], (int) getDefaultValue(PrefKey.sPrefKeyList.get(i)));\n                        break;\n                    case TYPE_LONG:\n                        mEditor.putLong(PrefKey.sKeys[i], (long) getDefaultValue(PrefKey.sPrefKeyList.get(i)));\n                        break;\n                    case TYPE_STRING:\n                        mEditor.putString(PrefKey.sKeys[i], (String) getDefaultValue(PrefKey.sPrefKeyList.get(i)));\n                }\n            }\n        }\n        mEditor.apply();\n    }\n\n    @NonNull\n    public Object getDefaultValue(@NonNull PrefKey key) {\n        switch (key) {\n            case PREF_ADB_LOCAL_SERVER_PORT_INT:\n                return (UserHandleHidden.myUserId() + 60001);\n            case PREF_BACKUP_FLAGS_INT:\n                return BackupFlags.BACKUP_INT_DATA | BackupFlags.BACKUP_RULES\n                        | BackupFlags.BACKUP_APK_FILES | BackupFlags.BACKUP_EXTRAS;\n            case PREF_BACKUP_COMPRESSION_METHOD_STR:\n                return TarUtils.TAR_GZIP;\n            case PREF_ENABLE_KILL_FOR_SYSTEM_BOOL:\n            case PREF_GLOBAL_BLOCKING_ENABLED_BOOL:\n            case PREF_INSTALLER_ALWAYS_ON_BACKGROUND_BOOL:\n            case PREF_INSTALLER_BLOCK_TRACKERS_BOOL:\n            case PREF_INSTALLER_DISABLE_VERIFICATION_BOOL:\n            case PREF_INSTALLER_FORCE_DEX_OPT_BOOL:\n            case PREF_INSTALLER_SIGN_APK_BOOL:\n            case PREF_BACKUP_ANDROID_KEYSTORE_BOOL:\n            case PREF_ENABLE_SCREEN_LOCK_BOOL:\n            case PREF_MAIN_WINDOW_SORT_REVERSE_BOOL:\n            case PREF_LOG_VIEWER_EXPAND_BY_DEFAULT_BOOL:\n            case PREF_APP_THEME_PURE_BLACK_BOOL:\n            case PREF_DISPLAY_CHANGELOG_BOOL:\n            case PREF_FM_DISPLAY_IN_LAUNCHER_BOOL:\n            case PREF_FM_REMEMBER_LAST_PATH_BOOL:\n            case PREF_FM_SORT_REVERSE_BOOL:\n            case PREF_ENABLE_PERSISTENT_SESSION_BOOL:\n            case PREF_USE_SYSTEM_FONT_BOOL:\n                return false;\n            case PREF_APP_OP_SHOW_DEFAULT_BOOL:\n            case PREF_SHOW_DISCLAIMER_BOOL:\n            case PREF_LOG_VIEWER_SHOW_PID_TID_TIMESTAMP_BOOL:\n            case PREF_LOG_VIEWER_OMIT_SENSITIVE_INFO_BOOL:\n            case PREF_INSTALLER_DISPLAY_CHANGES_BOOL:\n            case PREF_INSTALLER_SET_ORIGIN_BOOL:\n            case PREF_INSTALLER_UPDATE_OWNERSHIP_BOOL:\n            case PREF_VIRUS_TOTAL_PROMPT_BEFORE_UPLOADING_BOOL:\n            case PREF_ZIP_ALIGN_BOOL:\n            case PREF_SEND_NOTIFICATIONS_TO_CONNECTED_DEVICES_BOOL:\n            case PREF_ENABLE_AUTO_LOCK_BOOL:\n                return true;\n            case PREF_CONCURRENCY_THREAD_COUNT_INT:\n            case PREF_APP_THEME_CUSTOM_INT:\n            case PREF_TIPS_PREFS_INT:\n                return 0;\n            case PREF_LAST_VERSION_CODE_LONG:\n            case PREF_DISPLAY_CHANGELOG_LAST_VERSION_LONG:\n                return 0L;\n            case PREF_ENABLED_FEATURES_INT:\n                return 0xffff_ffff;  /* All features enabled */\n            case PREF_APP_THEME_INT:\n                return AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM;\n            case PREF_MAIN_WINDOW_FILTER_FLAGS_INT:\n                return MainListOptions.FILTER_NO_FILTER;\n            case PREF_MAIN_WINDOW_SORT_ORDER_INT:\n                return MainListOptions.SORT_BY_APP_LABEL;\n            case PREF_CUSTOM_LOCALE_STR:\n                return LangUtils.LANG_AUTO;\n            case PREF_APP_OP_SORT_ORDER_INT:\n            case PREF_COMPONENTS_SORT_ORDER_INT:\n            case PREF_PERMISSIONS_SORT_ORDER_INT:\n                return AppDetailsFragment.SORT_BY_NAME;\n            case PREF_OVERLAYS_SORT_ORDER_INT:\n                return AppDetailsFragment.SORT_BY_PRIORITY;\n            case PREF_RUNNING_APPS_SORT_ORDER_INT:\n                return RunningAppsActivity.SORT_BY_PID;\n            case PREF_RUNNING_APPS_FILTER_FLAGS_INT:\n                return RunningAppsActivity.FILTER_NONE;\n            case PREF_ENCRYPTION_STR:\n                return CryptoUtils.MODE_NO_ENCRYPTION;\n            case PREF_OPEN_PGP_PACKAGE_STR:\n            case PREF_OPEN_PGP_USER_ID_STR:\n            case PREF_MAIN_WINDOW_FILTER_PROFILE_STR:\n            case PREF_SELECTED_USERS_STR:\n            case PREF_VIRUS_TOTAL_API_KEY_STR:\n                return \"\";\n            case PREF_MODE_OF_OPS_STR:\n                return Ops.MODE_AUTO;\n            case PREF_INSTALLER_DEFAULT_PKG_SOURCE_INT:\n                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {\n                    // Shell default\n                    return PackageInstaller.PACKAGE_SOURCE_OTHER;\n                } else return 0;\n            case PREF_INSTALLER_INSTALL_LOCATION_INT:\n                return PackageInfo.INSTALL_LOCATION_AUTO;\n            case PREF_INSTALLER_INSTALLER_APP_STR:\n                return BuildConfig.APPLICATION_ID;\n            case PREF_SIGNATURE_SCHEMES_INT:\n                return SigSchemes.DEFAULT_SCHEMES;\n            case PREF_BACKUP_VOLUME_STR:\n            case PREF_FM_HOME_STR:\n                return Uri.fromFile(Environment.getExternalStorageDirectory()).toString();\n            case PREF_LOG_VIEWER_FILTER_PATTERN_STR:\n                return mContext.getString(R.string.pref_filter_pattern_default);\n            case PREF_LOG_VIEWER_DISPLAY_LIMIT_INT:\n                return LogcatHelper.DEFAULT_DISPLAY_LIMIT;\n            case PREF_LOG_VIEWER_WRITE_PERIOD_INT:\n                return LogcatHelper.DEFAULT_LOG_WRITE_INTERVAL;\n            case PREF_LOG_VIEWER_DEFAULT_LOG_LEVEL_INT:\n                return Log.VERBOSE;\n            case PREF_LOG_VIEWER_BUFFER_INT:\n                return LogcatHelper.LOG_ID_DEFAULT;\n            case PREF_LAYOUT_ORIENTATION_INT:\n                return View.LAYOUT_DIRECTION_LTR;\n            case PREF_DEFAULT_BLOCKING_METHOD_STR:\n                // This is default for root\n                return ComponentRule.COMPONENT_TO_BE_BLOCKED_IFW_DISABLE;\n            case PREF_SAVED_APK_FORMAT_STR:\n                return \"%label%_%version%\";\n            case PREF_AUTHORIZATION_KEY_STR:\n                return AuthManager.generateKey();\n            case PREF_FREEZE_TYPE_INT:\n                return FreezeUtils.FREEZE_DISABLE;\n            case PREF_FM_OPTIONS_INT:\n                return FmListOptions.OPTIONS_DISPLAY_DOT_FILES | FmListOptions.OPTIONS_FOLDERS_FIRST;\n            case PREF_FM_SORT_ORDER_INT:\n                return FmListOptions.SORT_BY_NAME;\n            case PREF_DEBLOATER_FILTER_FLAGS_INT:\n                return DebloaterListOptions.getDefaultFilterFlags();\n            case PREF_FM_LAST_PATH_STR:\n                return \"{}\";\n        }\n        throw new IllegalArgumentException(\"Pref key not found.\");\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/utils/ArrayUtils.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage io.github.muntashirakon.AppManager.utils;\n\n// Source: https://cs.android.com/android/platform/superproject/+/master:frameworks/base/core/java/com/android/internal/util/ArrayUtils.java\n\nimport android.os.Build;\nimport android.util.ArraySet;\n\nimport androidx.annotation.CheckResult;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.RequiresApi;\n\nimport java.io.File;\nimport java.lang.reflect.Array;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.Set;\nimport java.util.function.IntFunction;\nimport java.util.function.Predicate;\n\nimport aosp.libcore.util.EmptyArray;\n\n/**\n * ArrayUtils contains some methods that you can call to find out\n * the most efficient increments by which to grow arrays.\n */\n@SuppressWarnings(\"unused\")\npublic class ArrayUtils {\n    private static final int CACHE_SIZE = 73;\n    private static final Object[] sCache = new Object[CACHE_SIZE];\n\n    public static final File[] EMPTY_FILE = new File[0];\n\n    private ArrayUtils() { /* cannot be instantiated */ }\n\n    /**\n     * Throws {@link ArrayIndexOutOfBoundsException} if the range is out of bounds.\n     *\n     * @param len    length of the array. Must be non-negative\n     * @param offset start index of the range. Must be non-negative\n     * @param count  length of the range. Must be non-negative\n     * @throws ArrayIndexOutOfBoundsException if the range from {@code offset} with length\n     *                                        {@code count} is out of bounds of the array\n     */\n    public static void throwsIfOutOfBounds(int len, int offset, int count) {\n        if (len < 0) {\n            throw new ArrayIndexOutOfBoundsException(\"Negative length: \" + len);\n        }\n\n        if ((offset | count) < 0 || offset > len - count) {\n            throw new ArrayIndexOutOfBoundsException(\n                    \"length=\" + len + \"; regionStart=\" + offset + \"; regionLength=\" + count);\n        }\n    }\n\n    /**\n     * Checks if the beginnings of two byte arrays are equal.\n     *\n     * @param array1 the first byte array\n     * @param array2 the second byte array\n     * @param length the number of bytes to check\n     * @return true if they're equal, false otherwise\n     */\n    public static boolean equals(byte[] array1, byte[] array2, int length) {\n        if (length < 0) {\n            throw new IllegalArgumentException();\n        }\n\n        if (array1 == array2) {\n            return true;\n        }\n        if (array1 == null || array2 == null || array1.length < length || array2.length < length) {\n            return false;\n        }\n        for (int i = 0; i < length; i++) {\n            if (array1[i] != array2[i]) {\n                return false;\n            }\n        }\n        return true;\n    }\n\n    /**\n     * Returns an empty array of the specified type.  The intent is that\n     * it will return the same empty array every time to avoid reallocation,\n     * although this is not guaranteed.\n     */\n    @SuppressWarnings(\"unchecked\")\n    public static <T> T[] emptyArray(Class<T> kind) {\n        if (kind == Object.class) {\n            return (T[]) EmptyArray.OBJECT;\n        }\n\n        int bucket = (kind.hashCode() & 0x7FFFFFFF) % CACHE_SIZE;\n        Object cache = sCache[bucket];\n\n        if (cache == null || cache.getClass().getComponentType() != kind) {\n            cache = Array.newInstance(kind, 0);\n            sCache[bucket] = cache;\n\n            // Log.e(\"cache\", \"new empty \" + kind.getName() + \" at \" + bucket);\n        }\n\n        return (T[]) cache;\n    }\n\n    /**\n     * Checks if given array is null or has zero elements.\n     */\n    public static boolean isEmpty(@Nullable Collection<?> array) {\n        return array == null || array.isEmpty();\n    }\n\n    /**\n     * Checks if given map is null or has zero elements.\n     */\n    public static boolean isEmpty(@Nullable Map<?, ?> map) {\n        return map == null || map.isEmpty();\n    }\n\n    /**\n     * Checks if given array is null or has zero elements.\n     */\n    public static <T> boolean isEmpty(@Nullable T[] array) {\n        return array == null || array.length == 0;\n    }\n\n    /**\n     * Checks if given array is null or has zero elements.\n     */\n    public static boolean isEmpty(@Nullable int[] array) {\n        return array == null || array.length == 0;\n    }\n\n    /**\n     * Checks if given array is null or has zero elements.\n     */\n    public static boolean isEmpty(@Nullable long[] array) {\n        return array == null || array.length == 0;\n    }\n\n    /**\n     * Checks if given array is null or has zero elements.\n     */\n    public static boolean isEmpty(@Nullable byte[] array) {\n        return array == null || array.length == 0;\n    }\n\n    /**\n     * Checks if given array is null or has zero elements.\n     */\n    public static boolean isEmpty(@Nullable boolean[] array) {\n        return array == null || array.length == 0;\n    }\n\n    /**\n     * Length of the given array or 0 if it's null.\n     */\n    public static int size(@Nullable Object[] array) {\n        return array == null ? 0 : array.length;\n    }\n\n    /**\n     * Length of the given collection or 0 if it's null.\n     */\n    public static int size(@Nullable Collection<?> collection) {\n        return collection == null ? 0 : collection.size();\n    }\n\n    /**\n     * Checks that value is present as at least one of the elements of the array.\n     *\n     * @param array the array to check in\n     * @param value the value to check for\n     * @return true if the value is present in the array\n     */\n    public static <T> boolean contains(@Nullable T[] array, T value) {\n        return indexOf(array, value) != -1;\n    }\n\n    /**\n     * Return first index of {@code value} in {@code array}, or {@code -1} if\n     * not found.\n     */\n    public static <T> int indexOf(@Nullable T[] array, T value) {\n        if (array == null) return -1;\n        for (int i = 0; i < array.length; i++) {\n            if (Objects.equals(array[i], value)) return i;\n        }\n        return -1;\n    }\n\n    /**\n     * Test if all {@code check} items are contained in {@code array}.\n     */\n    public static <T> boolean containsAll(@Nullable T[] array, T[] check) {\n        if (check == null) return true;\n        for (T checkItem : check) {\n            if (!contains(array, checkItem)) {\n                return false;\n            }\n        }\n        return true;\n    }\n\n    /**\n     * Test if any {@code check} items are contained in {@code array}.\n     */\n    public static <T> boolean containsAny(@Nullable T[] array, T[] check) {\n        if (check == null) return false;\n        for (T checkItem : check) {\n            if (contains(array, checkItem)) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    public static boolean contains(@Nullable int[] array, int value) {\n        if (array == null) return false;\n        for (int element : array) {\n            if (element == value) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    public static boolean contains(@Nullable long[] array, long value) {\n        if (array == null) return false;\n        for (long element : array) {\n            if (element == value) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    public static boolean contains(@Nullable char[] array, char value) {\n        if (array == null) return false;\n        for (char element : array) {\n            if (element == value) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    /**\n     * Test if all {@code check} items are contained in {@code array}.\n     */\n    public static <T> boolean containsAll(@Nullable char[] array, char[] check) {\n        if (check == null) return true;\n        for (char checkItem : check) {\n            if (!contains(array, checkItem)) {\n                return false;\n            }\n        }\n        return true;\n    }\n\n    public static long total(@Nullable long[] array) {\n        long total = 0;\n        if (array != null) {\n            for (long value : array) {\n                total += value;\n            }\n        }\n        return total;\n    }\n\n    public static int max(@NonNull int[] array) {\n        int candidate = array[0];\n        for (int i = 1; i < array.length; ++i) {\n            int next = array[i];\n            if (next > candidate) {\n                candidate = next;\n            }\n        }\n        return candidate;\n    }\n\n    public static long max(@NonNull long[] array) {\n        long candidate = array[0];\n        for (int i = 1; i < array.length; ++i) {\n            long next = array[i];\n            if (next > candidate) {\n                candidate = next;\n            }\n        }\n        return candidate;\n    }\n\n    public static float max(@NonNull float[] array) {\n        float candidate = array[0];\n        for (int i = 1; i < array.length; ++i) {\n            float next = array[i];\n            if (next > candidate) {\n                candidate = next;\n            }\n        }\n        return candidate;\n    }\n\n    public static <T extends Object & Comparable<? super T>> T max(@NonNull T[] array) {\n        T candidate = array[0];\n        for (int i = 1; i < array.length; ++i) {\n            T next = array[i];\n            if (next.compareTo(candidate) > 0) {\n                candidate = next;\n            }\n        }\n        return candidate;\n    }\n\n    @NonNull\n    public static int[] convertToIntArray(@NonNull List<Integer> list) {\n        int[] array = new int[list.size()];\n        for (int i = 0; i < list.size(); i++) {\n            array[i] = list.get(i);\n        }\n        return array;\n    }\n\n    @NonNull\n    public static int[] convertToIntArray(@NonNull Set<Integer> set) {\n        return convertToIntArray(new ArrayList<>(set));\n    }\n\n    @Nullable\n    public static long[] convertToLongArray(@Nullable int[] intArray) {\n        if (intArray == null) return null;\n        long[] array = new long[intArray.length];\n        for (int i = 0; i < intArray.length; i++) {\n            array[i] = intArray[i];\n        }\n        return array;\n    }\n\n    @NonNull\n    public static <T> ArrayList<CharSequence> toCharSequence(@NonNull ArrayList<T> list) {\n        ArrayList<CharSequence> charSequenceList = new ArrayList<>(list.size());\n        try {\n            for (T item : list) charSequenceList.add((CharSequence) item);\n        } catch (ClassCastException e) {\n            throw new IllegalArgumentException(e);\n        }\n        return charSequenceList;\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    @CheckResult\n    @NonNull\n    public static <T> T[] concatElements(Class<T> kind, @Nullable T[] a, @Nullable T[] b) {\n        final int an = (a != null) ? a.length : 0;\n        final int bn = (b != null) ? b.length : 0;\n        if (an == 0 && bn == 0) {\n            if (kind == String.class) {\n                return (T[]) EmptyArray.STRING;\n            } else if (kind == Object.class) {\n                return (T[]) EmptyArray.OBJECT;\n            }\n        }\n        final T[] res = (T[]) Array.newInstance(kind, an + bn);\n        if (an > 0) System.arraycopy(a, 0, res, 0, an);\n        if (bn > 0) System.arraycopy(b, 0, res, an, bn);\n        return res;\n    }\n\n    /**\n     * Adds value to given array if not already present, providing set-like\n     * behavior.\n     */\n    @CheckResult\n    @NonNull\n    public static <T> T[] appendElement(Class<T> kind, @Nullable T[] array, T element) {\n        return appendElement(kind, array, element, false);\n    }\n\n    /**\n     * Adds value to given array.\n     */\n    @SuppressWarnings(\"unchecked\")\n    @CheckResult\n    @NonNull\n    public static <T> T[] appendElement(Class<T> kind, @Nullable T[] array, T element,\n                                        boolean allowDuplicates) {\n        final T[] result;\n        final int end;\n        if (array != null) {\n            if (!allowDuplicates && contains(array, element)) return array;\n            end = array.length;\n            result = (T[]) Array.newInstance(kind, end + 1);\n            System.arraycopy(array, 0, result, 0, end);\n        } else {\n            end = 0;\n            result = (T[]) Array.newInstance(kind, 1);\n        }\n        result[end] = element;\n        return result;\n    }\n\n    /**\n     * Removes value from given array if present, providing set-like behavior.\n     */\n    @SuppressWarnings(\"unchecked\")\n    @Nullable\n    public static <T> T[] removeElement(Class<T> kind, @Nullable T[] array, T element) {\n        if (array != null) {\n            if (!contains(array, element)) return array;\n            final int length = array.length;\n            for (int i = 0; i < length; i++) {\n                if (Objects.equals(array[i], element)) {\n                    if (length == 1) {\n                        return null;\n                    }\n                    T[] result = (T[]) Array.newInstance(kind, length - 1);\n                    System.arraycopy(array, 0, result, 0, i);\n                    System.arraycopy(array, i + 1, result, i, length - i - 1);\n                    return result;\n                }\n            }\n        }\n        return array;\n    }\n\n    /**\n     * Adds value to given array.\n     */\n    @NonNull\n    public static int[] appendInt(@Nullable int[] cur, int val,\n                                  boolean allowDuplicates) {\n        if (cur == null) {\n            return new int[]{val};\n        }\n        final int N = cur.length;\n        if (!allowDuplicates) {\n            for (int value : cur) {\n                if (value == val) {\n                    return cur;\n                }\n            }\n        }\n        int[] ret = new int[N + 1];\n        System.arraycopy(cur, 0, ret, 0, N);\n        ret[N] = val;\n        return ret;\n    }\n\n    /**\n     * Adds value to given array if not already present, providing set-like\n     * behavior.\n     */\n    @NonNull\n    public static int[] appendInt(@Nullable int[] cur, int val) {\n        return appendInt(cur, val, false);\n    }\n\n    /**\n     * Removes value from given array if present, providing set-like behavior.\n     */\n    @Nullable\n    public static int[] removeInt(@Nullable int[] cur, int val) {\n        if (cur == null) {\n            return null;\n        }\n        final int N = cur.length;\n        for (int i = 0; i < N; i++) {\n            if (cur[i] == val) {\n                int[] ret = new int[N - 1];\n                if (i > 0) {\n                    System.arraycopy(cur, 0, ret, 0, i);\n                }\n                if (i < (N - 1)) {\n                    System.arraycopy(cur, i + 1, ret, i, N - i - 1);\n                }\n                return ret;\n            }\n        }\n        return cur;\n    }\n\n    /**\n     * Removes value from given array if present, providing set-like behavior.\n     */\n    @Nullable\n    public static String[] removeString(@Nullable String[] cur, String val) {\n        if (cur == null) {\n            return null;\n        }\n        final int N = cur.length;\n        for (int i = 0; i < N; i++) {\n            if (Objects.equals(cur[i], val)) {\n                String[] ret = new String[N - 1];\n                if (i > 0) {\n                    System.arraycopy(cur, 0, ret, 0, i);\n                }\n                if (i < (N - 1)) {\n                    System.arraycopy(cur, i + 1, ret, i, N - i - 1);\n                }\n                return ret;\n            }\n        }\n        return cur;\n    }\n\n    /**\n     * Adds value to given array if not already present, providing set-like\n     * behavior.\n     */\n    @NonNull\n    public static long[] appendLong(@Nullable long[] cur, long val,\n                                    boolean allowDuplicates) {\n        if (cur == null) {\n            return new long[]{val};\n        }\n        final int N = cur.length;\n        if (!allowDuplicates) {\n            for (long l : cur) {\n                if (l == val) {\n                    return cur;\n                }\n            }\n        }\n        long[] ret = new long[N + 1];\n        System.arraycopy(cur, 0, ret, 0, N);\n        ret[N] = val;\n        return ret;\n    }\n\n    /**\n     * Adds value to given array if not already present, providing set-like\n     * behavior.\n     */\n    @NonNull\n    public static long[] appendLong(@Nullable long[] cur, long val) {\n        return appendLong(cur, val, false);\n    }\n\n    /**\n     * Removes value from given array if present, providing set-like behavior.\n     */\n    @Nullable\n    public static long[] removeLong(@Nullable long[] cur, long val) {\n        if (cur == null) {\n            return null;\n        }\n        final int N = cur.length;\n        for (int i = 0; i < N; i++) {\n            if (cur[i] == val) {\n                long[] ret = new long[N - 1];\n                if (i > 0) {\n                    System.arraycopy(cur, 0, ret, 0, i);\n                }\n                if (i < (N - 1)) {\n                    System.arraycopy(cur, i + 1, ret, i, N - i - 1);\n                }\n                return ret;\n            }\n        }\n        return cur;\n    }\n\n    @Nullable\n    public static long[] cloneOrNull(@Nullable long[] array) {\n        return (array != null) ? array.clone() : null;\n    }\n\n    /**\n     * Clones an array or returns null if the array is null.\n     */\n    @Nullable\n    public static <T> T[] cloneOrNull(@Nullable T[] array) {\n        return (array != null) ? array.clone() : null;\n    }\n\n    @Nullable\n    public static <T> HashSet<T> cloneOrNull(@Nullable HashSet<T> array) {\n        return (array != null) ? new HashSet<>(array) : null;\n    }\n\n    @RequiresApi(api = Build.VERSION_CODES.M)\n    @Nullable\n    public static <T> ArraySet<T> cloneOrNull(@Nullable ArraySet<T> array) {\n        return (array != null) ? new ArraySet<>(array) : null;\n    }\n\n    @RequiresApi(api = Build.VERSION_CODES.M)\n    @NonNull\n    public static <T> ArraySet<T> add(@Nullable ArraySet<T> cur, T val) {\n        if (cur == null) {\n            cur = new ArraySet<>();\n        }\n        cur.add(val);\n        return cur;\n    }\n\n    @Nullable\n    public static <T> ArraySet<T> remove(@Nullable ArraySet<T> cur, T val) {\n        if (cur == null) {\n            return null;\n        }\n        cur.remove(val);\n        if (cur.isEmpty()) {\n            return null;\n        } else {\n            return cur;\n        }\n    }\n\n    @NonNull\n    public static <T> ArrayList<T> add(@Nullable ArrayList<T> cur, T val) {\n        if (cur == null) {\n            cur = new ArrayList<>();\n        }\n        cur.add(val);\n        return cur;\n    }\n\n    @Nullable\n    public static <T> ArrayList<T> remove(@Nullable ArrayList<T> cur, T val) {\n        if (cur == null) {\n            return null;\n        }\n        cur.remove(val);\n        if (cur.isEmpty()) {\n            return null;\n        } else {\n            return cur;\n        }\n    }\n\n    public static <T> boolean contains(@Nullable Collection<T> cur, T val) {\n        return cur != null && cur.contains(val);\n    }\n\n    @Nullable\n    public static <T> T[] trimToSize(@Nullable T[] array, int size) {\n        if (array == null || size == 0) {\n            return null;\n        } else if (array.length == size) {\n            return array;\n        } else {\n            return Arrays.copyOf(array, size);\n        }\n    }\n\n    /**\n     * Returns true if the two ArrayLists are equal with respect to the objects they contain.\n     * The objects must be in the same order and be reference equal (== not .equals()).\n     */\n    public static <T> boolean referenceEquals(ArrayList<T> a, ArrayList<T> b) {\n        if (a == b) {\n            return true;\n        }\n        if (a == null || b == null) {\n            return false;\n        }\n        final int sizeA = a.size();\n        final int sizeB = b.size();\n        if (sizeA != sizeB) {\n            return false;\n        }\n        boolean diff = false;\n        for (int i = 0; i < sizeA && !diff; i++) {\n            diff |= a.get(i) != b.get(i);\n        }\n        return !diff;\n    }\n\n    /**\n     * Removes elements that match the predicate in an efficient way that alters the order of\n     * elements in the collection. This should only be used if order is not important.\n     *\n     * @param collection The ArrayList from which to remove elements.\n     * @param predicate  The predicate that each element is tested against.\n     * @return the number of elements removed.\n     */\n    @RequiresApi(api = Build.VERSION_CODES.N)\n    public static <T> int unstableRemoveIf(@Nullable ArrayList<T> collection,\n                                           @NonNull Predicate<T> predicate) {\n        if (collection == null) {\n            return 0;\n        }\n\n        final int size = collection.size();\n        int leftIdx = 0;\n        int rightIdx = size - 1;\n        while (leftIdx <= rightIdx) {\n            // Find the next element to remove moving left to right.\n            while (leftIdx < size && !predicate.test(collection.get(leftIdx))) {\n                leftIdx++;\n            }\n\n            // Find the next element to keep moving right to left.\n            while (rightIdx > leftIdx && predicate.test(collection.get(rightIdx))) {\n                rightIdx--;\n            }\n\n            if (leftIdx >= rightIdx) {\n                // Done.\n                break;\n            }\n\n            Collections.swap(collection, leftIdx, rightIdx);\n            leftIdx++;\n            rightIdx--;\n        }\n\n        // leftIdx is now at the end.\n        if (size > leftIdx) {\n            collection.subList(leftIdx, size).clear();\n        }\n        return size - leftIdx;\n    }\n\n    @NonNull\n    public static int[] defeatNullable(@Nullable int[] val) {\n        return (val != null) ? val : EmptyArray.INT;\n    }\n\n    @NonNull\n    public static String[] defeatNullable(@Nullable String[] val) {\n        return (val != null) ? val : EmptyArray.STRING;\n    }\n\n    @NonNull\n    public static File[] defeatNullable(@Nullable File[] val) {\n        return (val != null) ? val : EMPTY_FILE;\n    }\n\n    @NonNull\n    public static <T> T[] defeatNullable(Class<T> clazz, @Nullable T[] val) {\n        return (val != null) ? val : emptyArray(clazz);\n    }\n\n    /**\n     * Throws {@link ArrayIndexOutOfBoundsException} if the index is out of bounds.\n     *\n     * @param len   length of the array. Must be non-negative\n     * @param index the index to check\n     * @throws ArrayIndexOutOfBoundsException if the {@code index} is out of bounds of the array\n     */\n    public static void checkBounds(int len, int index) {\n        if (index < 0 || len <= index) {\n            throw new ArrayIndexOutOfBoundsException(\"length=\" + len + \"; index=\" + index);\n        }\n    }\n\n    /**\n     * Returns an array with values from {@code val} minus {@code null} values\n     *\n     * @param arrayConstructor typically {@code T[]::new} e.g. {@code String[]::new}\n     */\n    @RequiresApi(api = Build.VERSION_CODES.N)\n    public static <T> T[] filterNotNull(T[] val, IntFunction<T[]> arrayConstructor) {\n        int nullCount = 0;\n        int size = size(val);\n        for (int i = 0; i < size; i++) {\n            if (val[i] == null) {\n                nullCount++;\n            }\n        }\n        if (nullCount == 0) {\n            return val;\n        }\n        T[] result = arrayConstructor.apply(size - nullCount);\n        int outIdx = 0;\n        for (int i = 0; i < size; i++) {\n            if (val[i] != null) {\n                result[outIdx++] = val[i];\n            }\n        }\n        return result;\n    }\n\n    public static boolean startsWith(byte[] cur, byte[] val) {\n        if (cur == null || val == null) return false;\n        if (cur.length < val.length) return false;\n        for (int i = 0; i < val.length; i++) {\n            if (cur[i] != val[i]) return false;\n        }\n        return true;\n    }\n\n    /**\n     * Returns the first element from the array for which\n     * condition {@code predicate} is true, or null if there is no such element\n     */\n    @RequiresApi(api = Build.VERSION_CODES.N)\n    @Nullable\n    public static <T> T find(@Nullable T[] items, @NonNull Predicate<T> predicate) {\n        if (isEmpty(items)) return null;\n        for (final T item : items) {\n            if (predicate.test(item)) return item;\n        }\n        return null;\n    }\n\n    public static String deepToString(Object value) {\n        if (value != null && value.getClass().isArray()) {\n            if (value.getClass() == boolean[].class) {\n                return Arrays.toString((boolean[]) value);\n            } else if (value.getClass() == byte[].class) {\n                return Arrays.toString((byte[]) value);\n            } else if (value.getClass() == char[].class) {\n                return Arrays.toString((char[]) value);\n            } else if (value.getClass() == double[].class) {\n                return Arrays.toString((double[]) value);\n            } else if (value.getClass() == float[].class) {\n                return Arrays.toString((float[]) value);\n            } else if (value.getClass() == int[].class) {\n                return Arrays.toString((int[]) value);\n            } else if (value.getClass() == long[].class) {\n                return Arrays.toString((long[]) value);\n            } else if (value.getClass() == short[].class) {\n                return Arrays.toString((short[]) value);\n            } else {\n                return Arrays.deepToString((Object[]) value);\n            }\n        } else {\n            return String.valueOf(value);\n        }\n    }\n\n    @Nullable\n    public static <T> T firstOrNull(@NonNull T[] items) {\n        return items.length > 0 ? items[0] : null;\n    }\n}"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/utils/BetterActivityResult.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later OR Apache-2.0\n\npackage io.github.muntashirakon.AppManager.utils;\n\nimport android.content.Intent;\nimport androidx.activity.result.ActivityResult;\nimport androidx.activity.result.ActivityResultCaller;\nimport androidx.activity.result.ActivityResultLauncher;\nimport androidx.activity.result.contract.ActivityResultContract;\nimport androidx.activity.result.contract.ActivityResultContracts;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\npublic class BetterActivityResult<Input, Result> {\n    /**\n     * Register activity result using a {@link ActivityResultContract} and an in-place activity result callback like\n     * the default approach. You can still customise callback using {@link #launch(Object, OnActivityResult)}.\n     */\n    @NonNull\n    public static <Input, Result> BetterActivityResult<Input, Result> registerForActivityResult(\n            @NonNull ActivityResultCaller caller,\n            @NonNull ActivityResultContract<Input, Result> contract,\n            @Nullable OnActivityResult<Result> onActivityResult) {\n        return new BetterActivityResult<>(caller, contract, onActivityResult);\n    }\n\n    /**\n     * Same as {@link #registerForActivityResult(ActivityResultCaller, ActivityResultContract, OnActivityResult)} except\n     * the last argument is set to {@code null}.\n     */\n    @NonNull\n    public static <Input, Result> BetterActivityResult<Input, Result> registerForActivityResult(\n            @NonNull ActivityResultCaller caller,\n            @NonNull ActivityResultContract<Input, Result> contract) {\n        return registerForActivityResult(caller, contract, null);\n    }\n\n    /**\n     * Specialised method for launching new activities.\n     */\n    @NonNull\n    public static BetterActivityResult<Intent, ActivityResult> registerActivityForResult(\n            @NonNull ActivityResultCaller caller) {\n        return registerForActivityResult(caller, new ActivityResultContracts.StartActivityForResult());\n    }\n\n    /**\n     * Callback interface\n     */\n    public interface OnActivityResult<O> {\n        /**\n         * Called after receiving a result from the target activity\n         */\n        void onActivityResult(O result);\n    }\n\n    private final ActivityResultLauncher<Input> mLauncher;\n    @Nullable\n    private OnActivityResult<Result> mOnActivityResult;\n\n    private BetterActivityResult(@NonNull ActivityResultCaller caller,\n                                 @NonNull ActivityResultContract<Input, Result> contract,\n                                 @Nullable OnActivityResult<Result> onActivityResult) {\n        mOnActivityResult = onActivityResult;\n        mLauncher = caller.registerForActivityResult(contract, this::callOnActivityResult);\n    }\n\n    public void setOnActivityResult(@Nullable OnActivityResult<Result> onActivityResult) {\n        mOnActivityResult = onActivityResult;\n    }\n\n    /**\n     * Launch activity, same as {@link ActivityResultLauncher#launch(Object)} except that it allows a callback\n     * executed after receiving a result from the target activity.\n     */\n    public void launch(Input input, @Nullable OnActivityResult<Result> onActivityResult) {\n        if (onActivityResult != null) {\n            mOnActivityResult = onActivityResult;\n        }\n        mLauncher.launch(input);\n    }\n\n    /**\n     * Same as {@link #launch(Object, OnActivityResult)} with last parameter set to {@code null}.\n     */\n    public void launch(Input input) {\n        launch(input, mOnActivityResult);\n    }\n\n    private void callOnActivityResult(Result result) {\n        if (mOnActivityResult != null) mOnActivityResult.onActivityResult(result);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/utils/BinderShellExecutor.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.utils;\n\nimport android.os.Build;\nimport android.os.Bundle;\nimport android.os.IBinder;\nimport android.os.ParcelFileDescriptor;\nimport android.os.RemoteException;\nimport android.os.ResultReceiver;\nimport android.text.TextUtils;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.RequiresApi;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.File;\nimport java.io.FileDescriptor;\nimport java.io.FileInputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.atomic.AtomicInteger;\n\nimport io.github.muntashirakon.AppManager.BuildConfig;\nimport io.github.muntashirakon.AppManager.ipc.ProxyBinder;\nimport io.github.muntashirakon.AppManager.logs.Log;\nimport io.github.muntashirakon.io.Path;\n\n@RequiresApi(Build.VERSION_CODES.N)\npublic class BinderShellExecutor {\n    public static class ShellResult {\n        private int resultCode;\n        private String stdout;\n        private String stderr;\n\n        private ShellResult() {\n        }\n\n        public int getResultCode() {\n            return resultCode;\n        }\n\n        public String getStdout() {\n            return stdout;\n        }\n\n        public String getStderr() {\n            return stderr;\n        }\n    }\n\n    public static ShellResult execute(@NonNull IBinder binder, @NonNull String[] command,\n                                      @Nullable File input) throws IOException {\n        if (input == null) {\n            return execute(binder, command);\n        }\n        try (FileInputStream out = new FileInputStream(input)) {\n            return execute(binder, command, out);\n        }\n    }\n\n    public static ShellResult execute(@NonNull IBinder binder, @NonNull String[] command,\n                                      @Nullable Path input) throws IOException {\n        if (input == null) {\n            return execute(binder, command);\n        }\n        try (InputStream os = input.openInputStream()) {\n            return execute(binder, command, os);\n        }\n    }\n\n    public static ShellResult execute(@NonNull IBinder binder, @NonNull String[] command,\n                                      @Nullable FileInputStream input) throws IOException {\n        if (input == null) {\n            return execute(binder, command);\n        }\n        return execute(binder, command, input.getFD());\n    }\n\n    public static ShellResult execute(@NonNull IBinder binder, @NonNull String[] command, @Nullable InputStream input) throws IOException {\n        if (input == null) {\n            return execute(binder, command);\n        }\n        ParcelFileDescriptor inputFd = ParcelFileDescriptorUtil.pipeFrom(input);\n        return execute(binder, command, inputFd.getFileDescriptor());\n    }\n\n    public static ShellResult execute(@NonNull IBinder binder, @NonNull String[] command,\n                                      @Nullable FileDescriptor input) throws IOException {\n        if (input == null) {\n            return execute(binder, command);\n        }\n        return executeInternal(binder, command, input);\n    }\n\n    public static ShellResult execute(@NonNull IBinder binder, @NonNull String[] command)\n            throws IOException {\n        ParcelFileDescriptor[] pipe = ParcelFileDescriptor.createPipe();\n        ParcelFileDescriptor readSide = pipe[0];\n        ParcelFileDescriptor writeSide = pipe[1];\n        return executeInternal(binder, command, readSide.getFileDescriptor());\n    }\n\n    private static ShellResult executeInternal(@NonNull IBinder binder, @NonNull String[] command,\n                                               @NonNull FileDescriptor in) throws IOException {\n        try (ByteArrayOutputStream stdoutStream = new ByteArrayOutputStream();\n             ByteArrayOutputStream stderrStream = new ByteArrayOutputStream()) {\n            ParcelFileDescriptor stdoutFd = ParcelFileDescriptorUtil.pipeTo(stdoutStream);\n            ParcelFileDescriptor stderrFd = ParcelFileDescriptorUtil.pipeTo(stderrStream);\n            AtomicInteger atomicResultCode = new AtomicInteger(-1);\n            CountDownLatch sem = new CountDownLatch(1);\n            ProxyBinder.shellCommand(binder, in, stdoutFd.getFileDescriptor(), stderrFd.getFileDescriptor(), command, null, new ResultReceiver(ThreadUtils.getUiThreadHandler()) {\n                @Override\n                protected void onReceiveResult(int resultCode, Bundle resultData) {\n                    atomicResultCode.set(resultCode);\n                    sem.countDown();\n                }\n            });\n            try {\n                sem.await();\n            } catch (InterruptedException ignore) {\n            }\n            int resultCode = atomicResultCode.get();\n            if (resultCode == -1) {\n                throw new IOException(\"Invalid result code \" + resultCode);\n            }\n            ShellResult result = new ShellResult();\n            result.resultCode = resultCode;\n            result.stdout = stdoutStream.toString();\n            result.stderr = stderrStream.toString();\n            if (BuildConfig.DEBUG) {\n                Log.d(\"BinderShell_IN\", TextUtils.join(\" \", command));\n                Log.d(\"BinderShell_OUT\", \"(exit code: \" + result.resultCode + \")\");\n                Log.d(\"BinderShell_OUT\", result.stdout);\n            }\n            return result;\n        } catch (RemoteException e) {\n            return ExUtils.rethrowFromSystemServer(e);\n        } catch (Throwable th) {\n            return ExUtils.rethrowAsIOException(th);\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/utils/BitmapRandomizer.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.utils;\n\nimport android.graphics.Bitmap;\nimport android.graphics.Color;\n\nimport androidx.annotation.NonNull;\n\nimport io.github.muntashirakon.AppManager.crypto.ks.CompatUtil;\n\npublic class BitmapRandomizer {\n    public static void randomizePixel(@NonNull Bitmap bitmap) {\n        if (!bitmap.isMutable()) {\n            throw new IllegalArgumentException(\"Bitmap must be mutable\");\n        }\n\n        int width = bitmap.getWidth();\n        int height = bitmap.getHeight();\n\n        // Randomly select a pixel location\n        int x = CompatUtil.getPrng().nextInt(width);\n        int y = CompatUtil.getPrng().nextInt(height);\n\n        // Get the original pixel color\n        int originalColor = bitmap.getPixel(x, y);\n\n        // Extract ARGB components\n        int alpha = Color.alpha(originalColor);\n        int red = Color.red(originalColor);\n        int green = Color.green(originalColor);\n        int blue = Color.blue(originalColor);\n\n        // Get neighboring pixels for blending\n        int[] neighborColors = getNeighborColors(bitmap, x, y);\n\n        // Calculate average of neighbors for blending\n        int avgRed = 0, avgGreen = 0, avgBlue = 0;\n        for (int neighborColor : neighborColors) {\n            avgRed += Color.red(neighborColor);\n            avgGreen += Color.green(neighborColor);\n            avgBlue += Color.blue(neighborColor);\n        }\n        avgRed /= neighborColors.length;\n        avgGreen /= neighborColors.length;\n        avgBlue /= neighborColors.length;\n\n        // Modify at least one MSB (Most Significant Bit) while blending\n        int newRed = modifyMsbWithBlending(red, avgRed);\n        int newGreen = modifyMsbWithBlending(green, avgGreen);\n        int newBlue = modifyMsbWithBlending(blue, avgBlue);\n\n        // Ensure the new color is different from original\n        int newColor = Color.argb(alpha, newRed, newGreen, newBlue);\n        if (newColor == originalColor) {\n            // Force a change by flipping the MSB of red channel\n            newRed = red ^ 0x80; // Flip bit 7 (MSB)\n            newColor = Color.argb(alpha, newRed, newGreen, newBlue);\n        }\n\n        // Set the modified pixel\n        bitmap.setPixel(x, y, newColor);\n    }\n\n    private static int[] getNeighborColors(Bitmap bitmap, int x, int y) {\n        int width = bitmap.getWidth();\n        int height = bitmap.getHeight();\n\n        // Get up to 8 neighboring pixels\n        int[] neighbors = new int[8];\n        int count = 0;\n\n        for (int dx = -1; dx <= 1; dx++) {\n            for (int dy = -1; dy <= 1; dy++) {\n                if (dx == 0 && dy == 0) continue; // Skip center pixel\n\n                int nx = x + dx;\n                int ny = y + dy;\n\n                if (nx >= 0 && nx < width && ny >= 0 && ny < height) {\n                    neighbors[count++] = bitmap.getPixel(nx, ny);\n                }\n            }\n        }\n\n        // Return only valid neighbors\n        int[] result = new int[count];\n        System.arraycopy(neighbors, 0, result, 0, count);\n        return result;\n    }\n\n    private static int modifyMsbWithBlending(int originalValue, int avgNeighborValue) {\n        // Blend original with neighbor average (50% blend)\n        int blended = (originalValue + avgNeighborValue) / 2;\n\n        // Ensure MSB modification by flipping a random bit in upper half (bits 4-7)\n        int bitToFlip = 4 + CompatUtil.getPrng().nextInt(4); // Random bit from 4 to 7\n        int modified = blended ^ (1 << bitToFlip);\n\n        // Clamp to valid range [0, 255]\n        return Math.max(0, Math.min(255, modified));\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/utils/BroadcastUtils.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.utils;\n\nimport android.content.Context;\nimport android.content.Intent;\n\nimport androidx.annotation.NonNull;\n\nimport io.github.muntashirakon.AppManager.types.PackageChangeReceiver;\n\npublic class BroadcastUtils {\n    public static void sendPackageAdded(@NonNull Context context, String[] packageNames) {\n        Intent intent = new Intent(PackageChangeReceiver.ACTION_PACKAGE_ADDED);\n        intent.setPackage(context.getPackageName());\n        intent.putExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST, packageNames);\n        context.sendBroadcast(intent);\n    }\n\n    public static void sendPackageAltered(@NonNull Context context, String[] packageNames) {\n        Intent intent = new Intent(PackageChangeReceiver.ACTION_PACKAGE_ALTERED);\n        intent.setPackage(context.getPackageName());\n        intent.putExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST, packageNames);\n        context.sendBroadcast(intent);\n    }\n\n    public static void sendPackageRemoved(@NonNull Context context, String[] packageNames) {\n        Intent intent = new Intent(PackageChangeReceiver.ACTION_PACKAGE_REMOVED);\n        intent.setPackage(context.getPackageName());\n        intent.putExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST, packageNames);\n        context.sendBroadcast(intent);\n    }\n\n    public static void sendDbPackageAdded(@NonNull Context context, String[] packageNames) {\n        Intent intent = new Intent(PackageChangeReceiver.ACTION_DB_PACKAGE_ADDED);\n        intent.setPackage(context.getPackageName());\n        intent.putExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST, packageNames);\n        context.sendBroadcast(intent);\n    }\n\n    public static void sendDbPackageAltered(@NonNull Context context, String[] packageNames) {\n        Intent intent = new Intent(PackageChangeReceiver.ACTION_DB_PACKAGE_ALTERED);\n        intent.setPackage(context.getPackageName());\n        intent.putExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST, packageNames);\n        context.sendBroadcast(intent);\n    }\n\n    public static void sendDbPackageRemoved(@NonNull Context context, String[] packageNames) {\n        Intent intent = new Intent(PackageChangeReceiver.ACTION_DB_PACKAGE_REMOVED);\n        intent.setPackage(context.getPackageName());\n        intent.putExtra(Intent.EXTRA_CHANGED_PACKAGE_LIST, packageNames);\n        context.sendBroadcast(intent);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/utils/ClipboardUtils.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.utils;\n\nimport android.content.ClipData;\nimport android.content.ClipboardManager;\nimport android.content.Context;\nimport android.net.Uri;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.util.Locale;\n\nimport io.github.muntashirakon.AppManager.fm.FmProvider;\nimport io.github.muntashirakon.AppManager.self.filecache.FileCache;\nimport io.github.muntashirakon.io.Paths;\n\npublic class ClipboardUtils {\n    private static final int MAX_CLIPBOARD_SIZE_BYTES = 1024 * 1024;\n\n    /**\n     * Copies text to clipboard, using URI fallback if text is larger.\n     */\n    public static void copyToClipboard(@NonNull Context context, @Nullable CharSequence label, @NonNull String text) {\n        ClipboardManager clipboard = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);\n        byte[] textBytes = text.getBytes();\n        ClipData clip;\n        if (textBytes.length < MAX_CLIPBOARD_SIZE_BYTES) {\n            // Small text: copy directly\n            clip = ClipData.newPlainText(label, text);\n        } else {\n            // Large text: save to file and copy Uri reference\n            try {\n                File cacheFile = FileCache.getGlobalFileCache().getCachedFile(textBytes, \"txt\");\n                // Use FileProvider to get content Uri for the file\n                Uri contentUri = FmProvider.getContentUri(Paths.get(cacheFile));\n                // Grant temporary read permission\n                clip = ClipData.newUri(context.getContentResolver(), label, contentUri);\n            } catch (IOException e) {\n                e.printStackTrace();\n                // Fallback: copy truncated text if writing file fails\n                clip = ClipData.newPlainText(\"text\", text.substring(0, MAX_CLIPBOARD_SIZE_BYTES - 1));\n            }\n        }\n        clipboard.setPrimaryClip(clip);\n    }\n\n\n    @Nullable\n    public static CharSequence readClipboard(@NonNull Context context) {\n        ClipboardManager clipboard = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);\n        ClipData clipData = clipboard.getPrimaryClip();\n        if (clipData != null && clipData.getItemCount() > 0) {\n            return clipData.getItemAt(0).coerceToText(context);\n        }\n        return null;\n    }\n\n    @Nullable\n    public static String readHashValueFromClipboard(@NonNull Context context) {\n        CharSequence clipData = readClipboard(context);\n        if (clipData != null) {\n            String data = clipData.toString().trim().toLowerCase(Locale.ROOT);\n            if (data.matches(\"[0-9a-f: \\n]+\")) {\n                return data.replaceAll(\"[: \\n]+\", \"\");\n            }\n        }\n        return null;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/utils/ContextUtils.java",
    "content": "// SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.utils;\n\nimport android.annotation.SuppressLint;\nimport android.content.BroadcastReceiver;\nimport android.content.Context;\nimport android.content.ContextWrapper;\nimport android.os.Build;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport org.jetbrains.annotations.Contract;\n\nimport java.util.Objects;\n\n// Copyright 2020 John \"topjohnwu\" Wu\npublic final class ContextUtils {\n    public static final String TAG = ContextUtils.class.getSimpleName();\n    @SuppressLint(\"StaticFieldLeak\")\n    public static Context rootContext;\n    @SuppressLint(\"StaticFieldLeak\")\n    private static Context sContext;\n\n    @SuppressLint({\"PrivateApi\", \"RestrictedApi\"})\n    @NonNull\n    public static Context getContext() {\n        if (sContext == null) {\n            // Fetching ActivityThread on the main thread is no longer required on API 18+\n            // See: https://cs.android.com/android/platform/frameworks/base/+/66a017b63461a22842b3678c9520f803d5ddadfc\n            try {\n                Context c = (Context) Class.forName(\"android.app.ActivityThread\")\n                        .getMethod(\"currentApplication\")\n                        .invoke(null);\n                sContext = getContextImpl(Objects.requireNonNull(c));\n            } catch (Exception e) {\n                // Shall never happen\n                throw new RuntimeException(e);\n            }\n        }\n        return sContext;\n    }\n\n    @Contract(\"!null -> !null\")\n    public static Context getDeContext(Context context) {\n        return Build.VERSION.SDK_INT >= Build.VERSION_CODES.N ?\n                context.createDeviceProtectedStorageContext() : context;\n    }\n\n    @Contract(\"!null -> !null\")\n    @Nullable\n    public static Context getContextImpl(@Nullable Context context) {\n        while (context instanceof ContextWrapper) {\n            context = ((ContextWrapper) context).getBaseContext();\n        }\n        return context;\n    }\n\n    public static void unregisterReceiver(@NonNull Context context, @NonNull BroadcastReceiver receiver) {\n        ExUtils.exceptionAsIgnored(() -> context.unregisterReceiver(receiver));\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/utils/CpuUtils.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.utils;\n\nimport android.content.Context;\nimport android.os.PowerManager;\n\nimport androidx.annotation.Keep;\nimport androidx.annotation.Nullable;\n\npublic class CpuUtils {\n    static {\n        System.loadLibrary(\"am\");\n    }\n\n    @Keep\n    public static native long getClockTicksPerSecond();\n\n    @Keep\n    @Nullable\n    public static native String getCpuModel();\n\n    public static PowerManager.WakeLock getPartialWakeLock(String tagPostfix) {\n        PowerManager pm = (PowerManager) ContextUtils.getContext().getSystemService(Context.POWER_SERVICE);\n        return pm.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, \"AppManager::\" + tagPostfix);\n    }\n\n    public static void releaseWakeLock(@Nullable PowerManager.WakeLock wakeLock) {\n        if (wakeLock != null && wakeLock.isHeld()) {\n            wakeLock.release();\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/utils/DateUtils.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.utils;\n\nimport android.content.Context;\nimport android.content.res.Resources;\n\nimport androidx.annotation.NonNull;\n\nimport java.text.DateFormat;\nimport java.util.Date;\n\nimport io.github.muntashirakon.AppManager.R;\n\npublic final class DateUtils {\n    @NonNull\n    public static String formatDate(@NonNull Context context, long millis) {\n        Date dateTime = new Date(millis);\n        return getDateFormat(context).format(dateTime);\n    }\n\n    @NonNull\n    public static String formatDateTime(@NonNull Context context, long millis) {\n        Date dateTime = new Date(millis);\n        String date = getDateFormat(context).format(dateTime);\n        String time = getTimeFormat(context).format(dateTime);\n        return date + \" \" + time;\n    }\n\n    @NonNull\n    public static String formatMediumDateTime(@NonNull Context context, long millis) {\n        Date dateTime = new Date(millis);\n        String date = getMediumDateFormat(context).format(dateTime);\n        String time = getTimeFormat(context).format(dateTime);\n        return date + \" \" + time;\n    }\n\n    @NonNull\n    public static String formatLongDateTime(@NonNull Context context, long millis) {\n        Date dateTime = new Date(millis);\n        String date = getLongDateFormat(context).format(dateTime);\n        String time = getTimeFormat(context).format(dateTime);\n        return date + \" \" + time;\n    }\n\n    public static String getFormattedDuration(@NonNull Context context, long millis) {\n        return getFormattedDuration(context, millis, false);\n    }\n\n    public static String getFormattedDuration(@NonNull Context context, long millis, boolean addSign) {\n        return getFormattedDuration(context, millis, addSign, false);\n    }\n\n    public static String getFormattedDuration(@NonNull Context context, long millis, boolean addSign,\n                                              boolean includeSeconds) {\n        Resources res = context.getResources();\n        if (millis == 0) {\n            return res.getQuantityString(R.plurals.usage_minutes, 0, 0);\n        }\n        String fTime = \"\";\n        if (millis < 0) {\n            millis = -millis;\n            if (addSign) fTime = \"- \";\n        }\n        long time = millis / 1000; // seconds\n        long month, day, hour, min, sec;\n        month = time / 2_592_000;\n        time %= 2_592_000;\n        day = time / 86_400;\n        time %= 86_400;\n        hour = time / 3_600;\n        time = time % 3_600;\n        min = time / 60;\n        sec = time % 60;\n        int count = 0;\n        if (month != 0) {\n            fTime += res.getQuantityString(R.plurals.usage_months, (int) month, month);\n            ++count;\n        }\n        if (day != 0) {\n            fTime += (count > 0 ? \" \" : \"\") + res.getQuantityString(R.plurals.usage_days, (int) day, day);\n            ++count;\n        }\n        if (hour != 0) {\n            fTime += (count > 0 ? \" \" : \"\") + res.getQuantityString(R.plurals.usage_hours, (int) hour, hour);\n            ++count;\n        }\n        if (min != 0) {\n            fTime += (count > 0 ? \" \" : \"\") + res.getQuantityString(R.plurals.usage_minutes, (int) min, min);\n            ++count;\n        } else if (count == 0 && !includeSeconds) {\n            fTime = context.getString(R.string.usage_less_than_a_minute);\n        }\n        if (includeSeconds) {\n            fTime += (count > 0 ? \" \" : \"\") + res.getQuantityString(R.plurals.usage_seconds, (int) sec, sec);\n        }\n        return fTime;\n    }\n\n    @NonNull\n    public static String getFormattedDurationShort(long millis, boolean addSign, boolean includeMinutes, boolean includeSeconds) {\n        StringBuilder fTime = new StringBuilder();\n        boolean isNegative;\n        if (millis < 0) {\n            millis = -millis;\n            isNegative = true;\n        } else isNegative = false;\n        long time = millis / 1000; // seconds\n        long month, day, hour, min, sec;\n        month = time / 2_592_000;\n        time %= 2_592_000;\n        day = time / 86_400;\n        time %= 86_400;\n        hour = time / 3_600;\n        time = time % 3_600;\n        min = time / 60;\n        sec = time % 60;\n        if (!includeMinutes && (min > 0 || sec > 0)) {\n            fTime.append(\"~\");\n        }\n        if (isNegative && addSign) {\n            fTime.append(\"-\");\n        }\n        int count = 0;\n        if (month != 0) {\n            fTime.append(month).append(\"mo\");\n            ++count;\n        }\n        if (day != 0) {\n            if (count > 0) fTime.append(\" \");\n            fTime.append(day).append(\"d\");\n            ++count;\n        }\n        if (hour != 0) {\n            if (count > 0) fTime.append(\" \");\n            fTime.append(hour).append(\"h\");\n            ++count;\n        }\n        if (min != 0) {\n            if (count > 0) fTime.append(\" \");\n            fTime.append(min).append(\"m\");\n            ++count;\n        } else if (count == 0 && !includeSeconds) {\n            fTime.append(\"1m\");\n        }\n        if (includeSeconds) {\n            if (count > 0) fTime.append(\" \");\n            fTime.append(sec).append(\"s\");\n        }\n        return fTime.toString();\n    }\n\n    @NonNull\n    public static String getFormattedDurationSingle(long millis, boolean addSign) {\n        StringBuilder fTime = new StringBuilder();\n        boolean isNegative;\n        if (millis < 0) {\n            millis = -millis;\n            isNegative = true;\n        } else isNegative = false;\n        long time = millis / 1000; // seconds\n        long month, day, hour, min;\n        month = time / 2_592_000;\n        time %= 2_592_000;\n        day = time / 86_400;\n        time %= 86_400;\n        hour = time / 3_600;\n        time = time % 3_600;\n        min = time / 60;\n        if (month > 0) {\n            if (day > 0) {\n                fTime.append('~');\n            }\n            fTime.append(month).append(\"mo\");\n        } else if (day > 0) {\n            if (hour > 0) fTime.append('~');\n            fTime.append(day).append('d');\n        } else if (hour > 0) {\n            if (min > 0) fTime.append('~');\n            fTime.append(hour).append('h');\n        } else if (min > 0) {\n            fTime.append(min).append(\"m\");\n        } else {\n            // Seconds not included\n            fTime.append(\"<1m\");\n        }\n        return (addSign && isNegative ? \"-\" : \"\") + fTime;\n    }\n\n    private static DateFormat getDateFormat(@NonNull Context context) {\n        return android.text.format.DateFormat.getDateFormat(context);\n    }\n\n    private static DateFormat getMediumDateFormat(@NonNull Context context) {\n        return android.text.format.DateFormat.getMediumDateFormat(context);\n    }\n\n    private static DateFormat getLongDateFormat(@NonNull Context context) {\n        return android.text.format.DateFormat.getLongDateFormat(context);\n    }\n\n    private static DateFormat getTimeFormat(@NonNull Context context) {\n        return android.text.format.DateFormat.getTimeFormat(context);\n    }\n}"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/utils/DigestUtils.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.utils;\n\nimport android.annotation.TargetApi;\nimport android.text.TextUtils;\nimport android.util.Pair;\n\nimport androidx.annotation.AnyThread;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.StringDef;\nimport androidx.annotation.VisibleForTesting;\nimport androidx.annotation.WorkerThread;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.security.DigestInputStream;\nimport java.security.MessageDigest;\nimport java.security.NoSuchAlgorithmException;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.zip.CRC32;\nimport java.util.zip.CheckedInputStream;\n\nimport aosp.libcore.util.HexEncoding;\nimport io.github.muntashirakon.io.IoUtils;\nimport io.github.muntashirakon.io.Path;\nimport io.github.muntashirakon.io.Paths;\n\npublic class DigestUtils {\n    @StringDef({CRC32, MD2, MD5, SHA_1, SHA_224, SHA_256, SHA_384, SHA_512})\n    @Retention(RetentionPolicy.SOURCE)\n    public @interface Algorithm {\n    }\n\n    public static final String CRC32 = \"CRC32\";\n    public static final String MD2 = \"MD2\";\n    public static final String MD5 = \"MD5\";\n    public static final String SHA_1 = \"SHA-1\";\n    @TargetApi(22)\n    public static final String SHA_224 = \"SHA-224\";\n    public static final String SHA_256 = \"SHA-256\";\n    public static final String SHA_384 = \"SHA-384\";\n    public static final String SHA_512 = \"SHA-512\";\n\n    @AnyThread\n    @NonNull\n    public static String getHexDigest(@Algorithm String algo, @NonNull byte[] bytes) {\n        return HexEncoding.encodeToString(getDigest(algo, bytes), false /* lowercase */);\n    }\n\n    @VisibleForTesting\n    @WorkerThread\n    @NonNull\n    public static String getHexDigest(@Algorithm String algo, @NonNull File path) {\n        return getHexDigest(algo, Paths.get(path));\n    }\n\n    @WorkerThread\n    @NonNull\n    public static String getHexDigest(@Algorithm String algo, @NonNull Path path) {\n        List<Path> allFiles = Paths.getAll(path);\n        List<String> hashes = new ArrayList<>(allFiles.size());\n        for (Path file : allFiles) {\n            if (file.isDirectory()) continue;\n            try (InputStream fileInputStream = file.openInputStream()) {\n                hashes.add(getHexDigest(algo, fileInputStream));\n            } catch (IOException e) {\n                e.printStackTrace();\n            }\n        }\n        if (hashes.size() == 0) return HexEncoding.encodeToString(new byte[0], false /* lowercase */);\n        if (hashes.size() == 1) return hashes.get(0);\n        String fullString = TextUtils.join(\"\", hashes);\n        return getHexDigest(algo, fullString.getBytes());\n    }\n\n    @WorkerThread\n    @NonNull\n    public static String getHexDigest(@Algorithm String algo, @NonNull InputStream stream) {\n        return HexEncoding.encodeToString(getDigest(algo, stream), false /* lowercase */);\n    }\n\n    @AnyThread\n    @NonNull\n    public static byte[] getDigest(@Algorithm String algo, @NonNull byte[] bytes) {\n        if (CRC32.equals(algo)) {\n            return longToBytes(calculateCrc32(bytes));\n        }\n        try {\n            return MessageDigest.getInstance(algo).digest(bytes);\n        } catch (NoSuchAlgorithmException e) {\n            e.printStackTrace();\n            return new byte[0];\n        }\n    }\n\n    @WorkerThread\n    @NonNull\n    public static byte[] getDigest(@Algorithm String algo, @NonNull InputStream stream) {\n        if (CRC32.equals(algo)) {\n            try {\n                return longToBytes(calculateCrc32(stream));\n            } catch (IOException e) {\n                e.printStackTrace();\n                return new byte[0];\n            }\n        }\n        try {\n            MessageDigest messageDigest = MessageDigest.getInstance(algo);\n            try (DigestInputStream digestInputStream = new DigestInputStream(stream, messageDigest)) {\n                byte[] buffer = new byte[IoUtils.DEFAULT_BUFFER_SIZE];\n                //noinspection StatementWithEmptyBody\n                while (digestInputStream.read(buffer) != -1) {\n                }\n                digestInputStream.close();\n                return messageDigest.digest();\n            }\n        } catch (NoSuchAlgorithmException | IOException e) {\n            e.printStackTrace();\n            return new byte[0];\n        }\n    }\n\n    @WorkerThread\n    public static long calculateCrc32(Path file) throws IOException {\n        try (InputStream is = file.openInputStream()) {\n            return calculateCrc32(is);\n        }\n    }\n\n    @AnyThread\n    public static long calculateCrc32(byte[] bytes) {\n        CRC32 crc32 = new CRC32();\n        crc32.update(bytes);\n        return crc32.getValue();\n    }\n\n    @AnyThread\n    public static long calculateCrc32(InputStream stream) throws IOException {\n        CRC32 crc32 = new CRC32();\n        byte[] buffer = new byte[IoUtils.DEFAULT_BUFFER_SIZE];\n        try (CheckedInputStream cis = new CheckedInputStream(stream, crc32)) {\n            //noinspection StatementWithEmptyBody\n            while (cis.read(buffer) >= 0) {\n            }\n        }\n        return crc32.getValue();\n    }\n\n    @WorkerThread\n    @NonNull\n    public static Pair<String, String>[] getDigests(@NonNull Path file) throws IOException {\n        if (!file.isFile()) {\n            throw new IOException(file + \" is not a file.\");\n        }\n        @Algorithm String[] algorithms = new String[]{MD5, SHA_1, SHA_256, SHA_384, SHA_512};\n        MessageDigest[] messageDigests = new MessageDigest[algorithms.length];\n        @SuppressWarnings(\"unchecked\")\n        Pair<String, String>[] digests = new Pair[algorithms.length];\n        for (int i = 0; i < algorithms.length; ++i) {\n            try {\n                messageDigests[i] = MessageDigest.getInstance(algorithms[i]);\n            } catch (NoSuchAlgorithmException e) {\n                return ExUtils.rethrowAsIOException(e);\n            }\n        }\n        try (InputStream is = file.openInputStream()) {\n            byte[] buffer = new byte[IoUtils.DEFAULT_BUFFER_SIZE];\n            int length;\n            while ((length = is.read(buffer)) != -1) {\n                for (int i = 0; i < algorithms.length; ++i) {\n                    messageDigests[i].update(buffer, 0, length);\n                }\n            }\n        }\n        for (int i = 0; i < algorithms.length; ++i) {\n            digests[i] = new Pair<>(algorithms[i], HexEncoding.encodeToString(messageDigests[i].digest(), false));\n        }\n        return digests;\n    }\n\n    @AnyThread\n    @NonNull\n    public static Pair<String, String>[] getDigests(byte[] bytes) {\n        @Algorithm String[] algorithms = new String[]{MD5, SHA_1, SHA_256, SHA_384, SHA_512};\n        @SuppressWarnings(\"unchecked\")\n        Pair<String, String>[] digests = new Pair[algorithms.length];\n        for (int i = 0; i < algorithms.length; ++i) {\n            digests[i] = new Pair<>(algorithms[i], getHexDigest(algorithms[i], bytes));\n        }\n        return digests;\n    }\n\n    @NonNull\n    public static byte[] longToBytes(long l) {\n        byte[] bytes = new byte[4];\n        bytes[0] = (byte) ((l >> 24) & 0xFF);\n        bytes[1] = (byte) ((l >> 16) & 0xFF);\n        bytes[2] = (byte) ((l >> 8) & 0xFF);\n        bytes[3] = (byte) (l & 0xFF);\n        return bytes;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/utils/ExUtils.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.utils;\n\nimport android.os.Build;\nimport android.os.DeadObjectException;\nimport android.os.DeadSystemException;\nimport android.os.RemoteException;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport org.jetbrains.annotations.Contract;\n\nimport java.io.IOException;\nimport java.util.Optional;\n\nimport io.github.muntashirakon.AppManager.backup.BackupException;\nimport io.github.muntashirakon.AppManager.logs.Log;\nimport io.github.muntashirakon.compat.ObjectsCompat;\n\npublic class ExUtils {\n    public interface ThrowingRunnable<T> {\n        T run() throws Throwable;\n    }\n\n    public interface ThrowingRunnableNoReturn {\n        void run() throws Throwable;\n    }\n\n    @Contract(\"_ -> fail\")\n    public static <T> T rethrowAsIOException(@NonNull Throwable e) throws IOException {\n        IOException ioException = new IOException(e.getMessage());\n        //noinspection UnnecessaryInitCause\n        ioException.initCause(e);\n        throw ioException;\n    }\n\n    @Contract(\"_, _ -> fail\")\n    public static <T> T rethrowAsBackupException(@NonNull String message, @NonNull Throwable e) throws BackupException {\n        BackupException backupException = new BackupException(message);\n        //noinspection UnnecessaryInitCause\n        backupException.initCause(e);\n        throw backupException;\n    }\n\n    @Contract(\"_ -> fail\")\n    public static  <T> T rethrowAsRuntimeException(@NonNull Throwable th) {\n        throw new RuntimeException(th);\n    }\n\n    /**\n     * Rethrow this exception when we know it came from the system server. This\n     * gives us an opportunity to throw a nice clean\n     * {@link DeadSystemException} signal to avoid spamming logs with\n     * misleading stack traces.\n     * <p>\n     * Apps making calls into the system server may end up persisting internal\n     * state or making security decisions based on the perceived success or\n     * failure of a call, or any default values returned. For this reason, we\n     * want to strongly throw when there was trouble with the transaction.\n     */\n    @Contract(\"_ -> fail\")\n    public static  <T> T rethrowFromSystemServer(@NonNull RemoteException e) {\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {\n            throw e.rethrowFromSystemServer();\n        }\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && e instanceof DeadObjectException) {\n                throw new RuntimeException(new DeadSystemException());\n        } else {\n            throw new RuntimeException(e);\n        }\n    }\n\n    @Nullable\n    public static <T> T exceptionAsNull(ThrowingRunnable<T> r) {\n        try {\n            return r.run();\n        } catch (Throwable th) {\n            Log.w(\"ExUtils\", \"(Suppressed error)\", th);\n            return null;\n        }\n    }\n\n    @NonNull\n    public static <T> T requireNonNullElse(ThrowingRunnable<T> r, T defaultObj) {\n        return ObjectsCompat.requireNonNullElse(exceptionAsNull(r), defaultObj);\n    }\n\n    @Nullable\n    public static <T> T asRuntimeException(ThrowingRunnable<T> r) {\n        try {\n            return r.run();\n        } catch (Throwable th) {\n            throw new RuntimeException(th);\n        }\n    }\n\n    public static void exceptionAsIgnored(ThrowingRunnableNoReturn r) {\n        try {\n            r.run();\n        } catch (Throwable th) {\n            Log.w(\"ExUtils\", \"(Suppressed error)\", th);\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/utils/FileUtils.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.utils;\n\nimport static android.system.OsConstants.O_ACCMODE;\nimport static android.system.OsConstants.O_APPEND;\nimport static android.system.OsConstants.O_RDONLY;\nimport static android.system.OsConstants.O_RDWR;\nimport static android.system.OsConstants.O_TRUNC;\nimport static android.system.OsConstants.O_WRONLY;\n\nimport android.content.Context;\nimport android.net.Uri;\nimport android.os.Environment;\nimport android.os.ParcelFileDescriptor;\nimport android.system.ErrnoException;\nimport android.system.Os;\n\nimport androidx.annotation.AnyThread;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.WorkerThread;\n\nimport java.io.File;\nimport java.io.FileNotFoundException;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.math.BigInteger;\nimport java.nio.channels.FileChannel;\nimport java.util.Objects;\nimport java.util.zip.ZipEntry;\n\nimport io.github.muntashirakon.AppManager.logs.Log;\nimport io.github.muntashirakon.AppManager.progress.ProgressHandler;\nimport io.github.muntashirakon.AppManager.self.filecache.FileCache;\nimport io.github.muntashirakon.io.FileSystemManager;\nimport io.github.muntashirakon.io.IoUtils;\nimport io.github.muntashirakon.io.Path;\nimport io.github.muntashirakon.io.Paths;\n\npublic final class FileUtils {\n    public static final String TAG = FileUtils.class.getSimpleName();\n\n    @AnyThread\n    public static boolean isZip(@NonNull Path path) throws IOException {\n        int header;\n        try (InputStream is = path.openInputStream()) {\n            byte[] headerBytes = new byte[4];\n            is.read(headerBytes);\n            header = new BigInteger(headerBytes).intValue();\n        }\n        return header == 0x504B0304 || header == 0x504B0506 || header == 0x504B0708;\n    }\n\n    @AnyThread\n    @NonNull\n    public static String getFilenameFromZipEntry(@NonNull ZipEntry zipEntry) {\n        return Paths.getLastPathSegment(zipEntry.getName());\n    }\n\n    @NonNull\n    public static ParcelFileDescriptor getFdFromUri(@NonNull Context context, @NonNull Uri uri, String mode)\n            throws FileNotFoundException {\n        ParcelFileDescriptor fd = context.getContentResolver().openFileDescriptor(uri, mode);\n        if (fd == null) {\n            throw new FileNotFoundException(\"Uri inaccessible or empty.\");\n        }\n        return fd;\n    }\n\n    @AnyThread\n    @NonNull\n    public static File getFileFromFd(@NonNull ParcelFileDescriptor fd) {\n        return new File(\"/proc/self/fd/\" + fd.getFd());\n    }\n\n    @AnyThread\n    public static void deleteSilently(@Nullable Path path) {\n        if (path == null || !path.exists()) return;\n        if (!path.delete()) {\n            Log.w(TAG, \"Unable to delete %s\", path);\n        }\n    }\n\n    @AnyThread\n    public static void deleteSilently(@Nullable File file) {\n        if (!Paths.exists(file)) return;\n        if (!file.delete()) {\n            Log.w(TAG, \"Unable to delete %s\", file);\n        }\n    }\n\n    @WorkerThread\n    @NonNull\n    public static String getContentFromAssets(@NonNull Context context, String fileName) {\n        try (InputStream inputStream = context.getResources().getAssets().open(fileName)) {\n            return IoUtils.getInputStreamContent(inputStream);\n        } catch (IOException e) {\n            e.printStackTrace();\n        }\n        return \"\";\n    }\n\n    @AnyThread\n    public static boolean isAssetDirectory(@NonNull Context context, @NonNull String path) {\n        String[] files;\n        try {\n            files = context.getAssets().list(path);\n        } catch (IOException e) {\n            // Doesn't exist\n            return false;\n        }\n        return files != null && files.length > 0;\n    }\n\n    @AnyThread\n    public static long copy(@NonNull Path from, @NonNull Path to, @Nullable ProgressHandler progressHandler)\n            throws IOException {\n        try (InputStream in = from.openInputStream();\n             OutputStream out = to.openOutputStream()) {\n            return copy(in, out, from.length(), progressHandler);\n        }\n    }\n\n    /**\n     * Copy the contents of one stream to another.\n     *\n     * @param totalSize Total size of the stream. Only used for handling progress. Set {@code -1} if unknown.\n     */\n    @AnyThread\n    public static long copy(@NonNull InputStream in, @NonNull OutputStream out, long totalSize,\n                            @Nullable ProgressHandler progressHandler) throws IOException {\n        float lastProgress = progressHandler != null ? progressHandler.getLastProgress() : 0;\n        return IoUtils.copy(in, out, ThreadUtils.getBackgroundThreadExecutor(), progress -> {\n            if (progressHandler != null) {\n                progressHandler.postUpdate(100, lastProgress + (progress * 100f / totalSize));\n            }\n        });\n    }\n\n    @WorkerThread\n    public static void copyFromAsset(@NonNull Context context, @NonNull String fileName, @NonNull Path dest)\n            throws IOException {\n        try (InputStream is = context.getAssets().open(fileName);\n             OutputStream os = dest.openOutputStream()) {\n            IoUtils.copy(is, os);\n        }\n    }\n\n    @AnyThread\n    @NonNull\n    public static Path getTempPath(@NonNull String relativeDir, @NonNull String filename) {\n        File newDir = FileCache.getGlobalFileCache().createCachedDir(relativeDir);\n        return Paths.get(new File(newDir, filename));\n    }\n\n    @AnyThread\n    @NonNull\n    public static File getCachePath() {\n        Context context = ContextUtils.getContext();\n        try {\n            return getExternalCachePath(context);\n        } catch (FileNotFoundException e) {\n            return context.getCacheDir();\n        }\n    }\n\n    @AnyThread\n    @NonNull\n    public static File getExternalCachePath(@NonNull Context context) throws FileNotFoundException {\n        return getBestExternalPath(context.getExternalCacheDirs());\n    }\n\n    @AnyThread\n    @NonNull\n    public static File getExternalMediaPath(@NonNull Context context) throws FileNotFoundException {\n        return getBestExternalPath(context.getExternalMediaDirs());\n    }\n\n    @AnyThread\n    @NonNull\n    public static File getBestExternalPath(@Nullable File[] extDirs) throws FileNotFoundException {\n        if (extDirs == null) {\n            throw new FileNotFoundException(\"Shared storage unavailable.\");\n        }\n        String lastReason = null;\n        for (File extDir : extDirs) {\n            // The priority is from top to bottom of the list as per Context#getExternalDir()\n            if (extDir == null) {\n                // Other external directory might exist\n                continue;\n            }\n            if (!(extDir.exists() || extDir.mkdirs())) {\n                lastReason = extDir + \": permission denied.\";\n                Log.w(TAG, \"Could not use %s.\", extDir);\n                continue;\n            }\n            String storageState = Environment.getExternalStorageState(extDir);\n            if (!Objects.equals(storageState, Environment.MEDIA_MOUNTED)) {\n                lastReason = extDir + \": not mounted (\" + storageState + \")\";\n                Log.w(TAG, \"Path %s not mounted. State: %s\", extDir, storageState);\n                continue;\n            }\n            return extDir;\n        }\n        throw new FileNotFoundException(lastReason != null ? lastReason : \"No available shared storage found.\");\n    }\n\n    @AnyThread\n    public static void chmod711(@NonNull File file) throws IOException {\n        try {\n            Os.chmod(file.getAbsolutePath(), 457);\n        } catch (ErrnoException e) {\n            Log.e(\"IOUtils\", \"Failed to apply mode 711 to \" + file);\n            throw new IOException(e);\n        }\n    }\n\n    @AnyThread\n    public static void chmod644(@NonNull File file) throws IOException {\n        try {\n            Os.chmod(file.getAbsolutePath(), 420);\n        } catch (ErrnoException e) {\n            Log.e(TAG, \"Failed to apply mode 644 to %s\", file);\n            throw new IOException(e);\n        }\n    }\n\n    public static boolean canReadUnprivileged(@NonNull File file) {\n        if (file.canRead()) {\n            try (FileChannel ignored = FileSystemManager.getLocal().openChannel(file, FileSystemManager.MODE_READ_ONLY)) {\n                return true;\n            } catch (IOException | SecurityException e) {\n                return false;\n            }\n        }\n        return false;\n    }\n\n    public static String translateModePosixToString(int mode) {\n        String res;\n        if ((mode & O_ACCMODE) == O_RDWR) {\n            res = \"rw\";\n        } else if ((mode & O_ACCMODE) == O_WRONLY) {\n            res = \"w\";\n        } else if ((mode & O_ACCMODE) == O_RDONLY) {\n            res = \"r\";\n        } else {\n            throw new IllegalArgumentException(\"Bad mode: \" + mode);\n        }\n        if ((mode & O_TRUNC) == O_TRUNC) {\n            res += \"t\";\n        }\n        if ((mode & O_APPEND) == O_APPEND) {\n            res += \"a\";\n        }\n        return res;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/utils/FreezeUtils.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.utils;\n\nimport android.annotation.UserIdInt;\nimport android.content.pm.ApplicationInfo;\nimport android.content.pm.PackageManager;\nimport android.os.Build;\nimport android.os.RemoteException;\nimport android.os.UserHandleHidden;\n\nimport androidx.annotation.IntDef;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.WorkerThread;\n\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\n\nimport io.github.muntashirakon.AppManager.BuildConfig;\nimport io.github.muntashirakon.AppManager.compat.ApplicationInfoCompat;\nimport io.github.muntashirakon.AppManager.compat.ManifestCompat;\nimport io.github.muntashirakon.AppManager.compat.PackageManagerCompat;\nimport io.github.muntashirakon.AppManager.db.AppsDb;\nimport io.github.muntashirakon.AppManager.db.entity.FreezeType;\nimport io.github.muntashirakon.AppManager.self.SelfPermissions;\nimport io.github.muntashirakon.AppManager.settings.Prefs;\n\npublic final class FreezeUtils {\n    @IntDef({FREEZE_DISABLE, FREEZE_SUSPEND, FREEZE_HIDE, FREEZE_ADV_SUSPEND})\n    @Retention(RetentionPolicy.SOURCE)\n    public @interface FreezeMethod {\n    }\n\n    public static final int FREEZE_DISABLE = 1;\n    public static final int FREEZE_SUSPEND = 1 << 1;\n    public static final int FREEZE_HIDE = 1 << 2;\n    public static final int FREEZE_ADV_SUSPEND = 1 << 3;\n\n    @WorkerThread\n    public static void storeFreezeMethod(@NonNull String packageName, @FreezeMethod int freezeType) {\n        AppsDb.getInstance().freezeTypeDao().insert(new FreezeType(packageName, freezeType));\n    }\n\n    @WorkerThread\n    public static void deleteFreezeMethod(@NonNull String packageName) {\n        AppsDb.getInstance().freezeTypeDao().delete(packageName);\n    }\n\n    @WorkerThread\n    @FreezeMethod\n    @Nullable\n    public static Integer loadFreezeMethod(@Nullable String packageName) {\n        if (packageName != null) {\n            FreezeType freezeType;\n            freezeType = AppsDb.getInstance().freezeTypeDao().get(packageName);\n            if (freezeType != null) {\n                return freezeType.type;\n            }\n        }\n        // No package-specific freezing method exists\n        return null;\n    }\n\n    public static boolean isFrozen(@NonNull ApplicationInfo applicationInfo) {\n        // An app is frozen if one of the following operations return true: suspend, disable or hide\n        if (!applicationInfo.enabled) {\n            return true;\n        }\n        if (ApplicationInfoCompat.isSuspended(applicationInfo)) {\n            return true;\n        }\n        return ApplicationInfoCompat.isHidden(applicationInfo);\n    }\n\n    @Deprecated\n    public static void freeze(@NonNull String packageName, @UserIdInt int userId) throws RemoteException {\n        freeze(packageName, userId, Prefs.Blocking.getDefaultFreezingMethod());\n    }\n\n    public static void freeze(@NonNull String packageName, @UserIdInt int userId, @FreezeMethod int freezeType)\n            throws RemoteException {\n        if (BuildConfig.APPLICATION_ID.equals(packageName) && userId == UserHandleHidden.myUserId()) {\n            throw new RemoteException(\"Could not freeze myself.\");\n        }\n        if (freezeType == FREEZE_HIDE) {\n            if (SelfPermissions.checkSelfOrRemotePermission(ManifestCompat.permission.MANAGE_USERS)) {\n                PackageManagerCompat.hidePackage(packageName, userId, true);\n                return;\n            }\n            // No permission, fall-through\n        } else if ((freezeType == FREEZE_SUSPEND || freezeType == FREEZE_ADV_SUSPEND) && Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {\n            if (freezeType == FREEZE_ADV_SUSPEND) {\n                // Force-stop app\n                if (SelfPermissions.checkSelfOrRemotePermission(ManifestCompat.permission.FORCE_STOP_PACKAGES)) {\n                    PackageManagerCompat.forceStopPackage(packageName, userId);\n                }\n            }\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {\n                if (SelfPermissions.checkSelfOrRemotePermission(ManifestCompat.permission.SUSPEND_APPS)) {\n                    PackageManagerCompat.suspendPackages(new String[]{packageName}, userId, true);\n                    return;\n                }\n                // No permission, fall-through\n            } else {\n                if (SelfPermissions.checkSelfOrRemotePermission(ManifestCompat.permission.MANAGE_USERS)) {\n                    PackageManagerCompat.suspendPackages(new String[]{packageName}, userId, true);\n                    return;\n                }\n                // No permission, fall-through\n            }\n        }\n        PackageManagerCompat.setApplicationEnabledSetting(packageName, PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER, 0, userId);\n    }\n\n    public static void unfreeze(@NonNull String packageName, @UserIdInt int userId) throws RemoteException {\n        // Ignore checking preference, unfreeze for all types\n        if (PackageManagerCompat.isPackageHidden(packageName, userId)) {\n            PackageManagerCompat.hidePackage(packageName, userId, false);\n        }\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && PackageManagerCompat.isPackageSuspended(packageName, userId)) {\n            PackageManagerCompat.suspendPackages(new String[]{packageName}, userId, false);\n        }\n        if (PackageManagerCompat.getApplicationEnabledSetting(packageName, userId) != PackageManager.COMPONENT_ENABLED_STATE_ENABLED) {\n            PackageManagerCompat.setApplicationEnabledSetting(packageName, PackageManager.COMPONENT_ENABLED_STATE_ENABLED, 0, userId);\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/utils/HuaweiUtils.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.utils;\n\nimport android.os.Build;\n\npublic final class HuaweiUtils {\n    public static boolean isHuaweiDevice() {\n        String manufacturer = Build.MANUFACTURER;\n        String brand = Build.BRAND;\n        return manufacturer.equalsIgnoreCase(\"HUAWEI\") || brand.equalsIgnoreCase(\"HUAWEI\");\n    }\n\n    public static boolean isEmui() {\n        String emuiVersion = System.getProperty(\"ro.build.version.emui\");\n        return emuiVersion != null && !emuiVersion.isEmpty();\n    }\n\n    public static boolean isHarmonyOs() {\n        String harmonyVersion = System.getProperty(\"ro.harmony.version\");\n        return harmonyVersion != null && !harmonyVersion.isEmpty();\n    }\n\n    public  static boolean isStockHuawei() {\n        return isHuaweiDevice() && (isHarmonyOs() || isEmui());\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/utils/IntegerUtils.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.utils;\n\nimport androidx.annotation.NonNull;\n\nimport java.nio.ByteBuffer;\n\npublic class IntegerUtils {\n    public static int getUInt8(@NonNull ByteBuffer buffer) {\n        return buffer.get() & 0xff;\n    }\n\n    public static int getUInt16(@NonNull ByteBuffer buffer) {\n        return buffer.getShort() & 0xffff;\n    }\n\n    public static long getUInt32(@NonNull ByteBuffer buffer) {\n        return buffer.getInt() & 0xffffffffL;\n    }\n\n    public static long getUInt32(@NonNull ByteBuffer buffer, int position) {\n        return buffer.getInt(position) & 0xffffffffL;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/utils/IntentUtils.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.utils;\n\nimport android.annotation.SuppressLint;\nimport android.content.Intent;\nimport android.net.Uri;\nimport android.os.Build;\nimport android.provider.Settings;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.RequiresApi;\n\npublic final class IntentUtils {\n    @NonNull\n    public static Intent getAppDetailsSettings(@NonNull String packageName) {\n        return getSettings(Settings.ACTION_APPLICATION_DETAILS_SETTINGS, packageName);\n    }\n\n    @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM) // Added in r20\n    @NonNull\n    public static Intent getAppStorageSettings(@NonNull String packageName) {\n        return getSettings(\"com.android.settings.APP_STORAGE_SETTINGS\", packageName);\n    }\n\n    @RequiresApi(Build.VERSION_CODES.N)\n    @NonNull\n    public static Intent getNetPolicySettings(@NonNull String packageName) {\n        return getSettings(Settings.ACTION_IGNORE_BACKGROUND_DATA_RESTRICTIONS_SETTINGS, packageName);\n    }\n\n    @SuppressLint(\"BatteryLife\")\n    @RequiresApi(Build.VERSION_CODES.M)\n    @NonNull\n    public static Intent getBatteryOptSettings(@NonNull String packageName) {\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {\n            return getSettings(\"android.settings.VIEW_ADVANCED_POWER_USAGE_DETAIL\", packageName);\n        }\n        return getSettings(Settings.ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS, null);\n    }\n\n    @NonNull\n    public static Intent getSettings(@NonNull String action, @Nullable String packageName) {\n        Intent intent = new Intent(action)\n                .addCategory(Intent.CATEGORY_DEFAULT)\n                .addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);\n        if (packageName != null) {\n            if (action.equals(Settings.ACTION_APP_NOTIFICATION_SETTINGS)\n                    && Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {\n                intent.putExtra(Settings.EXTRA_APP_PACKAGE, packageName);\n            } else intent.setData(Uri.parse(\"package:\" + packageName));\n        }\n        return intent;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/utils/JSONUtils.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.utils;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport org.jetbrains.annotations.Contract;\nimport org.json.JSONArray;\nimport org.json.JSONException;\nimport org.json.JSONObject;\n\nimport java.lang.reflect.Array;\nimport java.util.ArrayList;\nimport java.util.Collection;\n\npublic final class JSONUtils {\n    public static void putAll(@NonNull JSONObject base, @Nullable JSONObject jsonObject) throws JSONException {\n        if (jsonObject == null) return;\n        JSONArray keys = jsonObject.names();\n        if (keys != null) {\n            for (int i = 0; i < keys.length(); i++) {\n                String key = keys.getString(i);\n                base.put(key, jsonObject.get(key));\n            }\n        }\n    }\n\n    @Contract(\"!null -> !null\")\n    @Nullable\n    public static <T> JSONArray getJSONArray(@Nullable final T[] typicalArray) {\n        if (typicalArray == null) return null;\n        JSONArray jsonArray = new JSONArray();\n        for (T elem : typicalArray) jsonArray.put(elem);\n        return jsonArray;\n    }\n\n    @Contract(\"!null -> !null\")\n    @Nullable\n    public static JSONArray getJSONArray(@Nullable final int[] typicalArray) {\n        if (typicalArray == null) return null;\n        JSONArray jsonArray = new JSONArray();\n        for (int elem : typicalArray) jsonArray.put(elem);\n        return jsonArray;\n    }\n\n    @Contract(\"!null -> !null\")\n    @Nullable\n    public static <T> JSONArray getJSONArray(@Nullable final Collection<T> collection) {\n        if (collection == null) return null;\n        JSONArray jsonArray = new JSONArray();\n        for (T elem : collection) jsonArray.put(elem);\n        return jsonArray;\n    }\n\n    @Contract(\"_,!null -> !null\")\n    @Nullable\n    public static <T> T[] getArray(Class<T> clazz, @Nullable final JSONArray jsonArray)\n            throws JSONException {\n        if (jsonArray == null) return null;\n        //noinspection unchecked\n        T[] typicalArray = (T[]) Array.newInstance(clazz, jsonArray.length());\n        for (int i = 0; i < jsonArray.length(); ++i) typicalArray[i] = clazz.cast(jsonArray.get(i));\n        return typicalArray;\n    }\n\n    @Contract(\"!null -> !null\")\n    @Nullable\n    public static int[] getIntArray(@Nullable final JSONArray jsonArray)\n            throws JSONException {\n        if (jsonArray == null) return null;\n        int[] typicalArray = new int[jsonArray.length()];\n        for (int i = 0; i < jsonArray.length(); ++i) typicalArray[i] = jsonArray.getInt(i);\n        return typicalArray;\n    }\n\n    @Contract(\"!null -> !null\")\n    @Nullable\n    public static <T> ArrayList<T> getArray(@Nullable final JSONArray jsonArray)\n            throws JSONException {\n        if (jsonArray == null) return null;\n        ArrayList<T> arrayList = new ArrayList<>(jsonArray.length());\n        for (int i = 0; i < jsonArray.length(); ++i) {\n            //noinspection unchecked\n            arrayList.add((T) jsonArray.get(i));\n        }\n        return arrayList;\n    }\n\n    @Contract(\"_,_,!null -> !null\")\n    @Nullable\n    public static String getString(@NonNull final JSONObject jsonObject, @NonNull String key,\n                                   @Nullable String defaultValue) {\n        try {\n            return jsonObject.getString(key);\n        } catch (JSONException e) {\n            return defaultValue;\n        }\n    }\n\n    @Nullable\n    public static Integer getIntOrNull(@NonNull final JSONObject jsonObject, @NonNull String key) {\n        try {\n            return jsonObject.getInt(key);\n        } catch (JSONException ignore) {\n        }\n        return null;\n    }\n\n    @Nullable\n    public static String getString(@NonNull final JSONObject jsonObject, @NonNull String key)\n            throws JSONException {\n        Object obj = jsonObject.get(key);\n        if (obj == JSONObject.NULL) {\n            return null;\n        }\n        return jsonObject.getString(key);\n    }\n\n    @Nullable\n    public static String optString(@NonNull final JSONObject jsonObject, @NonNull String key) {\n        Object obj = jsonObject.opt(key);\n        if (obj == null || obj == JSONObject.NULL) {\n            return null;\n        }\n        return jsonObject.optString(key);\n    }\n\n\n    @Nullable\n    public static String optString(@NonNull final JSONObject jsonObject, @NonNull String key,\n                                   @Nullable String fallback) {\n        Object obj = jsonObject.opt(key);\n        if (obj == null || obj == JSONObject.NULL) {\n            return null;\n        }\n        return jsonObject.optString(key, fallback);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/utils/KeyStoreUtils.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.utils;\n\nimport android.os.Build;\nimport android.os.UserHandleHidden;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.RequiresApi;\n\nimport java.io.FileNotFoundException;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport io.github.muntashirakon.AppManager.runner.Runner;\nimport io.github.muntashirakon.io.Path;\nimport io.github.muntashirakon.io.Paths;\n\npublic final class KeyStoreUtils {\n    public static boolean hasKeyStore(int uid) {\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {\n            return hasKeyStoreV2(uid);\n        }\n        return hasKeyStoreV1(uid);\n    }\n\n    public static boolean hasMasterKey(int uid) {\n        try {\n            return getMasterKey(UserHandleHidden.getUserId(uid)).exists();\n        } catch (FileNotFoundException e) {\n            return false;\n        }\n    }\n\n    @NonNull\n    public static Path getKeyStorePath(int userHandle) {\n        return Paths.get(\"/data/misc/keystore/user_\" + userHandle);\n    }\n\n    @NonNull\n    public static List<String> getKeyStoreFiles(int uid, int userHandle) {\n        // For any app, the key path is as follows:\n        // /data/misc/keystore/user_{user_handle}/{uid}_{KEY_NAME}_{alias}\n        Path keyStorePath = getKeyStorePath(userHandle);\n        String[] fileNames = keyStorePath.listFileNames();\n        List<String> keyStoreFiles = new ArrayList<>();\n        String uidStr = uid + \"_\";\n        for (String fileName : fileNames) {\n            if (fileName.startsWith(uidStr) || fileName.startsWith(\".\" + uidStr)) {\n                keyStoreFiles.add(fileName);\n            }\n        }\n        return keyStoreFiles;\n    }\n\n    @NonNull\n    public static Path getMasterKey(int userHandle) throws FileNotFoundException {\n        return getKeyStorePath(userHandle).findFile(\".masterkey\");\n    }\n\n    @RequiresApi(Build.VERSION_CODES.S)\n    public static boolean hasKeyStoreV2(int uid) {\n        return Runner.runCommand(new String[]{\"su\", \"\" + uid, \"-c\", \"keystore_cli_v2\", \"list\"})\n                .getOutputAsList().size() > 1;\n    }\n\n    public static boolean hasKeyStoreV1(int uid) {\n        Path keyStorePath = getKeyStorePath(UserHandleHidden.getUserId(uid));\n        String[] fileNames = keyStorePath.listFileNames();\n        String uidStr = uid + \"_\";\n        for (String fileName : fileNames) {\n            if (fileName.startsWith(uidStr)) return true;\n        }\n        return false;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/utils/LangUtils.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later OR Apache-2.0\n\npackage io.github.muntashirakon.AppManager.utils;\n\nimport android.annotation.SuppressLint;\nimport android.content.Context;\nimport android.content.res.Configuration;\nimport android.content.res.Resources;\nimport android.content.res.XmlResourceParser;\nimport android.os.Build;\n\nimport androidx.annotation.NonNull;\nimport androidx.core.os.ConfigurationCompat;\n\nimport org.xmlpull.v1.XmlPullParser;\nimport org.xmlpull.v1.XmlPullParserException;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.IllformedLocaleException;\nimport java.util.LinkedHashMap;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Map;\n\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.settings.Prefs;\n\npublic final class LangUtils {\n    public static final String LANG_AUTO = \"auto\";\n\n    private static Map<String, Locale> sLocaleMap;\n\n    @SuppressLint(\"AppBundleLocaleChanges\") // We don't use Play Store\n    private static void loadAppLanguages(@NonNull Context context) {\n        if (sLocaleMap == null) sLocaleMap = new LinkedHashMap<>();\n        Resources res = context.getResources();\n        Configuration conf = res.getConfiguration();\n\n        sLocaleMap.put(LANG_AUTO, null);\n        for (String locale : parseLocalesConfig(context)) {\n            conf.setLocale(Locale.forLanguageTag(locale));\n            sLocaleMap.put(locale, ConfigurationCompat.getLocales(conf).get(0));\n        }\n    }\n\n    @NonNull\n    public static Map<String, Locale> getAppLanguages(@NonNull Context context) {\n        if (sLocaleMap == null) loadAppLanguages(context);\n        return sLocaleMap;\n    }\n\n    @NonNull\n    public static Locale getFromPreference(@NonNull Context context) {\n        String language = Prefs.Appearance.getLanguage(context);\n        Locale locale = getAppLanguages(context).get(language);\n        if (locale != null) {\n            return locale;\n        }\n        // Load from system configuration\n        Configuration conf = Resources.getSystem().getConfiguration();\n        //noinspection deprecation\n        return Build.VERSION.SDK_INT >= Build.VERSION_CODES.N ? conf.getLocales().get(0) : conf.locale;\n    }\n\n    public static boolean isValidLocale(@NonNull String languageTag) {\n        try {\n            Locale locale = Locale.forLanguageTag(languageTag);\n            for (Locale validLocale : Locale.getAvailableLocales()) {\n                if (validLocale.equals(locale)) {\n                    return true;\n                }\n            }\n        } catch (IllformedLocaleException ignore) {\n        }\n        return false;\n    }\n\n    @NonNull\n    public static String getSeparatorString() {\n        if (Locale.getDefault().getLanguage().equals(new Locale(\"fr\").getLanguage())) {\n            return \" : \";\n        }\n        return \": \";\n    }\n\n    @NonNull\n    public static List<String> parseLocalesConfig(@NonNull Context context) {\n        List<String> localeNames = new ArrayList<>();\n\n        try (XmlResourceParser parser = context.getResources().getXml(R.xml.locales_config)) {\n            int eventType = parser.getEventType();\n            while (eventType != XmlPullParser.END_DOCUMENT) {\n                if (eventType == XmlPullParser.START_TAG && \"locale\".equals(parser.getName())) {\n                    String localeName = parser.getAttributeValue(\"http://schemas.android.com/apk/res/android\", \"name\");\n                    if (localeName != null) {\n                        localeNames.add(localeName);\n                    }\n                }\n                eventType = parser.next();\n            }\n        } catch (XmlPullParserException | IOException ignore) {\n        }\n        return localeNames;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/utils/ListItemCreator.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.utils;\n\nimport android.app.Activity;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.widget.ImageView;\nimport android.widget.TextView;\n\nimport androidx.annotation.DrawableRes;\nimport androidx.annotation.IdRes;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.appcompat.widget.LinearLayoutCompat;\n\nimport io.github.muntashirakon.AppManager.R;\n\n// TODO: 2/7/23 Replace this with preferences\npublic class ListItemCreator {\n    private static final int EMPTY = -1;\n\n    private final LinearLayoutCompat mListContainer;\n    private final LayoutInflater mLayoutInflater;\n\n    public View listItem;\n    public TextView itemTitle;\n    public TextView itemSubtitle;\n    public ImageView itemIcon;\n\n    public ListItemCreator(@NonNull Activity activity, @IdRes int resIdMenuContainer) {\n        mListContainer = activity.findViewById(resIdMenuContainer);\n        mListContainer.removeAllViews();\n        mLayoutInflater = activity.getLayoutInflater();\n    }\n\n    public View addItemWithTitleSubtitle(CharSequence title, CharSequence subtitle) {\n        return addItemWithTitleSubtitle(title, subtitle, EMPTY);\n    }\n\n    public View addItemWithTitleSubtitle(CharSequence title, CharSequence subtitle, int resIdIcon) {\n        return addItemWithIconTitleSubtitle(title, subtitle, resIdIcon);\n    }\n\n    /**\n     * Add a menu item to the main menu container.\n     *\n     * @param title     Title\n     * @param subtitle  Subtitle (null to remove it)\n     * @param resIdIcon Resource ID for icon (ListItemCreator.EMPTY to leave it empty)\n     * @return The menu item is returned which can be used for other purpose\n     */\n    private View addItemWithIconTitleSubtitle(@NonNull CharSequence title,\n                                              @Nullable CharSequence subtitle,\n                                              @DrawableRes int resIdIcon) {\n        listItem = mLayoutInflater.inflate(io.github.muntashirakon.ui.R.layout.m3_preference, mListContainer, false);\n        listItem.findViewById(R.id.icon_frame).setVisibility(View.GONE);\n        // Item title\n        itemTitle = listItem.findViewById(android.R.id.title);\n        itemTitle.setText(title);\n        // Item subtitle\n        itemSubtitle = listItem.findViewById(android.R.id.summary);\n        if (subtitle != null) itemSubtitle.setText(subtitle);\n        else itemSubtitle.setVisibility(View.GONE);\n        // Item icon\n        itemIcon = listItem.findViewById(android.R.id.icon);\n        if (resIdIcon != EMPTY) itemIcon.setImageResource(resIdIcon);\n        else itemIcon.setVisibility(View.GONE);\n        // Add new menu to the container\n        mListContainer.addView(listItem);\n        return listItem;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/utils/MiuiUtils.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.utils;\n\nimport android.annotation.SuppressLint;\nimport android.miui.AppOpsUtils;\nimport android.os.Build;\nimport android.text.TextUtils;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport io.github.muntashirakon.AppManager.misc.SystemProperties;\nimport io.github.muntashirakon.AppManager.miui.MiuiVersionInfo;\n\n// Copyright 2020 Aefyr\npublic class MiuiUtils {\n    @Nullable\n    private static MiuiVersionInfo sMiuiVersionInfo;\n\n    public static boolean isMiui() {\n        return !TextUtils.isEmpty(SystemProperties.get(\"ro.miui.ui.version.name\", \"\"));\n    }\n\n    @Nullable\n    public static MiuiVersionInfo getMiuiVersionInfo() {\n        if (sMiuiVersionInfo != null) {\n            return sMiuiVersionInfo;\n        }\n        if (!isMiui()) {\n            return null;\n        }\n        String versionString = Build.VERSION.INCREMENTAL;\n        if (TextUtils.isDigitsOnly(versionString)) {\n            return sMiuiVersionInfo = new MiuiVersionInfo(versionString, null, true);\n        }\n        if (!versionString.startsWith(\"V\")) {\n            throw new IllegalStateException(\"Stable version must begin with `V`\");\n        }\n        versionString = versionString.substring(1);\n        int firstNoDigitIndex = -1;\n        final int len = versionString.length();\n        for (char cp, i = 0; i < len; ++i) {\n            cp = versionString.charAt(i);\n            if (cp >= '0' && cp <= '9' || cp == '.') {\n                continue;\n            }\n            // Non-digit\n            firstNoDigitIndex = i;\n            break;\n        }\n        return sMiuiVersionInfo = new MiuiVersionInfo(versionString.substring(0, firstNoDigitIndex), versionString.substring(firstNoDigitIndex), false);\n    }\n\n    @NonNull\n    private static int[] parseVersionIntoParts(@NonNull String version) {\n        try {\n            String[] versionParts = version.split(\"\\\\.\");\n            int[] intVersionParts = new int[versionParts.length];\n\n            for (int i = 0; i < versionParts.length; i++) {\n                intVersionParts[i] = Integer.parseInt(versionParts[i]);\n            }\n\n            return intVersionParts;\n        } catch (Exception e) {\n            return new int[]{-1};\n        }\n    }\n\n    /**\n     * @return 0 if versions are equal, values less than 0 if ver1 is lower than ver2, value more than 0 if ver1 is higher than ver2\n     */\n    private static int compareVersions(@NonNull String version1, @NonNull String version2) {\n        if (version1.equals(version2)) {\n            return 0;\n        }\n\n        int[] version1Parts = parseVersionIntoParts(version1);\n        int[] version2Parts = parseVersionIntoParts(version2);\n\n        for (int i = 0; i < version2Parts.length; i++) {\n            if (i >= version1Parts.length)\n                return -1;\n\n            if (version1Parts[i] < version2Parts[i])\n                return -1;\n\n            if (version1Parts[i] > version2Parts[i])\n                return 1;\n        }\n\n        return 1;\n    }\n\n    public static boolean isActualMiuiVersionAtLeast(@NonNull String targetVersion, @NonNull String targetVersionBeta) {\n        MiuiVersionInfo actualVersionInfo = getMiuiVersionInfo();\n        if (actualVersionInfo == null) {\n            // Not MIUI\n            return false;\n        }\n        String sourceVersion = actualVersionInfo.getMiuiVersion();\n        if (sourceVersion == null) {\n            // Beta versions do not have MIUI version string.\n            // Compare beta versions\n            return compareVersions(actualVersionInfo.version, targetVersionBeta) >= 0;\n        }\n        // This is a stable version\n        return compareVersions(sourceVersion, targetVersion) >= 0;\n    }\n\n    @SuppressLint(\"PrivateApi\")\n    public static boolean isMiuiOptimizationDisabled() {\n        // ApplicationPackageManager#isXOptMode()\n        if (!SystemProperties.getBoolean(\"persist.sys.miui_optimization\", !\"1\".equals(SystemProperties.get(\"ro.miui.cts\", \"0\")))) {\n            return true;\n        }\n        try {\n            return AppOpsUtils.isXOptMode();\n        } catch (Throwable e) {\n            return false;\n        }\n    }\n}"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/utils/MotorolaUtils.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.utils;\n\nimport androidx.annotation.Nullable;\n\nimport io.github.muntashirakon.AppManager.misc.SystemProperties;\n\npublic class MotorolaUtils {\n    public static boolean isMotorola() {\n        return SystemProperties.getInt(\"ro.mot.build.version.sdk_int\", 0) != 0;\n    }\n\n    @Nullable\n    public static String getMotorolaVersion() {\n        int sdk = SystemProperties.getInt(\"ro.mot.build.version.sdk_int\", 0);\n        int increment = SystemProperties.getInt(\"ro.mot.build.product.increment\", 0);\n        if (sdk == 0) {\n            return null;\n        }\n        return sdk + \".\" + increment;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/utils/MultithreadedExecutor.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.utils;\n\nimport androidx.annotation.AnyThread;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.WorkerThread;\n\nimport java.util.ArrayList;\nimport java.util.Collection;\nimport java.util.List;\nimport java.util.concurrent.Callable;\nimport java.util.concurrent.ExecutionException;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\nimport java.util.concurrent.Future;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.TimeoutException;\n\nimport io.github.muntashirakon.AppManager.logs.Log;\n\npublic class MultithreadedExecutor implements ExecutorService {\n    private static final List<MultithreadedExecutor> sExecutorCache = new ArrayList<>();\n\n    @AnyThread\n    @NonNull\n    public static MultithreadedExecutor getNewInstance() {\n        if (sExecutorCache.size() > 0) {\n            // Check if any executor has been shutdown\n            for (MultithreadedExecutor executor : sExecutorCache) {\n                if (executor.isTerminated()) {\n                    executor.renew();\n                    return executor;\n                }\n            }\n        }\n        MultithreadedExecutor executor = new MultithreadedExecutor();\n        sExecutorCache.add(executor);\n        return executor;\n    }\n\n    @NonNull\n    private ExecutorService mExecutor;\n\n    private MultithreadedExecutor() {\n        mExecutor = Executors.newFixedThreadPool(getThreadCount());\n    }\n\n    private void renew() {\n        if (mExecutor.isTerminated()) {\n            // TODO: 26/5/21 Find a better way to recreate an executor\n            mExecutor = Executors.newFixedThreadPool(getThreadCount());\n        }\n    }\n\n    @Override\n    public Future<?> submit(Runnable task) {\n        if (mExecutor.isShutdown()) throw new UnsupportedOperationException(\"The executor was terminated\");\n        return mExecutor.submit(task);\n    }\n\n    @Override\n    public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks) throws InterruptedException {\n        return mExecutor.invokeAll(tasks);\n    }\n\n    @Override\n    public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit)\n            throws InterruptedException {\n        return mExecutor.invokeAll(tasks, timeout, unit);\n    }\n\n    @Override\n    public <T> T invokeAny(Collection<? extends Callable<T>> tasks) throws ExecutionException, InterruptedException {\n        return mExecutor.invokeAny(tasks);\n    }\n\n    @Override\n    public <T> T invokeAny(Collection<? extends Callable<T>> tasks, long timeout, TimeUnit unit) throws ExecutionException, InterruptedException, TimeoutException {\n        return mExecutor.invokeAny(tasks, timeout, unit);\n    }\n\n    @Override\n    public <T> Future<T> submit(Callable<T> task) {\n        if (mExecutor.isShutdown()) throw new UnsupportedOperationException(\"The executor was terminated\");\n        return mExecutor.submit(task);\n    }\n\n    @Override\n    public <T> Future<T> submit(Runnable task, T result) {\n        if (mExecutor.isShutdown()) throw new UnsupportedOperationException(\"The executor was terminated\");\n        return mExecutor.submit(task, result);\n    }\n\n    @WorkerThread\n    public void awaitCompletion() {\n        shutdown();\n        while (!isTerminated()) {\n            try {\n                awaitTermination(1, TimeUnit.MINUTES);\n            } catch (InterruptedException e) {\n                Log.e(\"MultithreadedExecutor\", e);\n            }\n        }\n    }\n\n    @Override\n    public void shutdown() {\n        mExecutor.shutdown();\n    }\n\n    @Override\n    public List<Runnable> shutdownNow() {\n        return mExecutor.shutdownNow();\n    }\n\n    @Override\n    public boolean isShutdown() {\n        return mExecutor.isShutdown();\n    }\n\n    @Override\n    public boolean isTerminated() {\n        return mExecutor.isTerminated();\n    }\n\n    @Override\n    public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException {\n        return mExecutor.awaitTermination(timeout, unit);\n    }\n\n    @Override\n    public void execute(Runnable command) {\n        mExecutor.execute(command);\n    }\n\n    public static int getThreadCount() {\n        int configuredCount = AppPref.getInt(AppPref.PrefKey.PREF_CONCURRENCY_THREAD_COUNT_INT);\n        int totalCores = Utils.getTotalCores();\n        if (configuredCount <= 0 || configuredCount > totalCores) return totalCores;\n        return configuredCount;\n    }\n\n    /**\n     *\n     * @param threadCount 1 - total cores. 0 = Total cores.\n     */\n    public static void setThreadCount(int threadCount) {\n        AppPref.set(AppPref.PrefKey.PREF_CONCURRENCY_THREAD_COUNT_INT, threadCount);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/utils/NonNullUtils.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.utils;\n\nimport androidx.annotation.Nullable;\n\npublic final class NonNullUtils {\n    public static long defeatNullable(@Nullable Long longValue) {\n        return longValue == null ? 0 : longValue;\n    }\n\n    public static int defeatNullable(@Nullable Integer integerValue) {\n        return integerValue == null ? 0 : integerValue;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/utils/NotificationUtils.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.utils;\n\nimport android.Manifest;\nimport android.app.Notification;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.os.Build;\nimport android.os.Process;\nimport android.provider.Settings;\n\nimport androidx.annotation.IntDef;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.core.app.NotificationChannelCompat;\nimport androidx.core.app.NotificationCompat;\nimport androidx.core.app.NotificationManagerCompat;\n\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport io.github.muntashirakon.AppManager.BuildConfig;\nimport io.github.muntashirakon.AppManager.progress.NotificationProgressHandler;\nimport io.github.muntashirakon.AppManager.self.SelfPermissions;\nimport io.github.muntashirakon.AppManager.settings.Prefs;\n\npublic final class NotificationUtils {\n    private static final String HIGH_PRIORITY_CHANNEL_ID = BuildConfig.APPLICATION_ID + \".channel.HIGH_PRIORITY\";\n    private static final String INSTALL_CONFIRM_CHANNEL_ID = BuildConfig.APPLICATION_ID + \".channel.INSTALL_CONFIRM\";\n    private static final String FREEZE_UNFREEZE_CHANNEL_ID = BuildConfig.APPLICATION_ID + \".channel.FREEZE_UNFREEZE\";\n\n    public static final NotificationProgressHandler.NotificationManagerInfo HIGH_PRIORITY_NOTIFICATION_INFO =\n            new NotificationProgressHandler.NotificationManagerInfo(\n                    HIGH_PRIORITY_CHANNEL_ID, \"Alerts\", NotificationManagerCompat.IMPORTANCE_HIGH);\n\n    @IntDef({\n            NotificationManagerCompat.IMPORTANCE_UNSPECIFIED,\n            NotificationManagerCompat.IMPORTANCE_NONE,\n            NotificationManagerCompat.IMPORTANCE_MIN,\n            NotificationManagerCompat.IMPORTANCE_LOW,\n            NotificationManagerCompat.IMPORTANCE_DEFAULT,\n            NotificationManagerCompat.IMPORTANCE_HIGH,\n            NotificationManagerCompat.IMPORTANCE_MAX,\n    })\n    @Retention(RetentionPolicy.SOURCE)\n    public @interface NotificationImportance {\n    }\n\n    @IntDef({\n            NotificationCompat.PRIORITY_MIN,\n            NotificationCompat.PRIORITY_LOW,\n            NotificationCompat.PRIORITY_DEFAULT,\n            NotificationCompat.PRIORITY_HIGH,\n            NotificationCompat.PRIORITY_MAX,\n    })\n    @Retention(RetentionPolicy.SOURCE)\n    public @interface NotificationPriority {\n    }\n\n    public interface NotificationBuilder {\n        Notification build(NotificationCompat.Builder builder);\n    }\n\n    private static final Map<String, Integer> sNotificationIds = Collections.synchronizedMap(new HashMap<>());\n\n    public static int nextNotificationId(@Nullable String tag) {\n        Integer id = sNotificationIds.get(tag);\n        if (id == null) {\n            sNotificationIds.put(tag, 1);\n            return 1;\n        }\n        ++id;\n        sNotificationIds.put(tag, id);\n        return id;\n    }\n\n    @NonNull\n    public static NotificationCompat.Builder getHighPriorityNotificationBuilder(@NonNull Context context) {\n        return new NotificationCompat.Builder(context, NotificationUtils.HIGH_PRIORITY_CHANNEL_ID)\n                .setLocalOnly(!Prefs.Misc.sendNotificationsToConnectedDevices())\n                .setPriority(NotificationCompat.PRIORITY_HIGH);\n    }\n\n    public static void displayHighPriorityNotification(@NonNull Context context, Notification notification) {\n        displayHighPriorityNotification(context, builder -> notification);\n    }\n\n    public static void displayHighPriorityNotification(@NonNull Context context,\n                                                       @NonNull NotificationBuilder notification) {\n        String notificationTag = \"alert\";\n        int notificationId = nextNotificationId(notificationTag);\n        displayNotification(context, HIGH_PRIORITY_CHANNEL_ID, \"Alerts\",\n                NotificationManagerCompat.IMPORTANCE_HIGH, notificationTag , notificationId, notification);\n    }\n\n    public static void displayFreezeUnfreezeNotification(@NonNull Context context,\n                                                         String notificationTag,\n                                                         @NonNull NotificationBuilder notification) {\n        displayNotification(context, FREEZE_UNFREEZE_CHANNEL_ID, \"Freeze\",\n                NotificationManagerCompat.IMPORTANCE_DEFAULT, notificationTag, 1, notification);\n    }\n\n    public static int displayInstallConfirmNotification(@NonNull Context context,\n                                                        @NonNull NotificationBuilder notification) {\n        int notificationId = nextNotificationId(INSTALL_CONFIRM_CHANNEL_ID);\n        displayNotification(context, INSTALL_CONFIRM_CHANNEL_ID, \"Confirm Installation\",\n                NotificationManagerCompat.IMPORTANCE_HIGH, INSTALL_CONFIRM_CHANNEL_ID, notificationId, notification);\n        return notificationId;\n    }\n\n    public static void cancelInstallConfirmNotification(@NonNull Context context, int notificationId) {\n        if (notificationId <= 0) {\n            return;\n        }\n        NotificationManagerCompat manager = getNewNotificationManager(context, INSTALL_CONFIRM_CHANNEL_ID,\n                \"Confirm Installation\", NotificationManagerCompat.IMPORTANCE_HIGH);\n        manager.cancel(INSTALL_CONFIRM_CHANNEL_ID, notificationId);\n    }\n\n    private static void displayNotification(@NonNull Context context,\n                                            @NonNull String channelId,\n                                            @NonNull CharSequence channelName,\n                                            @NotificationImportance int importance,\n                                            @Nullable String notificationTag,\n                                            int notificationId,\n                                            @NonNull NotificationBuilder notification) {\n        NotificationManagerCompat manager = getNewNotificationManager(context, channelId, channelName, importance);\n        NotificationCompat.Builder builder = new NotificationCompat.Builder(context, channelId)\n                .setLocalOnly(!Prefs.Misc.sendNotificationsToConnectedDevices())\n                .setPriority(importanceToPriority(importance));\n        if (SelfPermissions.checkSelfPermission(Manifest.permission.POST_NOTIFICATIONS)) {\n            manager.notify(notificationTag, notificationId, notification.build(builder));\n        }\n    }\n\n    @NonNull\n    public static NotificationManagerCompat getFreezeUnfreezeNotificationManager(@NonNull Context context) {\n        return getNewNotificationManager(context, FREEZE_UNFREEZE_CHANNEL_ID, \"Freeze\",\n                NotificationManagerCompat.IMPORTANCE_DEFAULT);\n    }\n\n    @NonNull\n    public static NotificationManagerCompat getNewNotificationManager(@NonNull Context context,\n                                                                      @NonNull String channelId,\n                                                                      CharSequence channelName,\n                                                                      int importance) {\n        NotificationChannelCompat channel = new NotificationChannelCompat.Builder(channelId, importance)\n                .setName(channelName)\n                .build();\n        NotificationManagerCompat managerCompat = NotificationManagerCompat.from(context);\n        managerCompat.createNotificationChannel(channel);\n        return managerCompat;\n    }\n\n    @NotificationPriority\n    public static int importanceToPriority(@NotificationImportance int importance) {\n        switch (importance) {\n            default:\n            case NotificationManagerCompat.IMPORTANCE_DEFAULT:\n            case NotificationManagerCompat.IMPORTANCE_UNSPECIFIED:\n                return NotificationCompat.PRIORITY_DEFAULT;\n            case NotificationManagerCompat.IMPORTANCE_HIGH:\n                return NotificationCompat.PRIORITY_HIGH;\n            case NotificationManagerCompat.IMPORTANCE_LOW:\n                return NotificationCompat.PRIORITY_LOW;\n            case NotificationManagerCompat.IMPORTANCE_MAX:\n                return NotificationCompat.PRIORITY_MAX;\n            case NotificationManagerCompat.IMPORTANCE_NONE:\n            case NotificationManagerCompat.IMPORTANCE_MIN:\n                return NotificationCompat.PRIORITY_MIN;\n        }\n    }\n\n    public static Intent getNotificationSettingIntent(@Nullable String channelId) {\n        Intent intent = new Intent();\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {\n            if (channelId != null) {\n                intent.setAction(Settings.ACTION_CHANNEL_NOTIFICATION_SETTINGS);\n                intent.putExtra(Settings.EXTRA_CHANNEL_ID, channelId);\n            } else {\n                intent.setAction(Settings.ACTION_APP_NOTIFICATION_SETTINGS);\n            }\n            intent.putExtra(Settings.EXTRA_APP_PACKAGE, BuildConfig.APPLICATION_ID);\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {\n                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);\n            }\n        } else {\n            intent.setAction(\"android.settings.APP_NOTIFICATION_SETTINGS\");\n            intent.putExtra(\"app_package\", BuildConfig.APPLICATION_ID);\n            intent.putExtra(\"app_uid\", Process.myUid());\n        }\n        return intent;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/utils/PackageUtils.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.utils;\n\nimport static io.github.muntashirakon.AppManager.compat.PackageManagerCompat.MATCH_DISABLED_COMPONENTS;\nimport static io.github.muntashirakon.AppManager.compat.PackageManagerCompat.MATCH_UNINSTALLED_PACKAGES;\nimport static io.github.muntashirakon.AppManager.utils.UIUtils.getBoldString;\nimport static io.github.muntashirakon.AppManager.utils.UIUtils.getColoredText;\nimport static io.github.muntashirakon.AppManager.utils.UIUtils.getMonospacedText;\nimport static io.github.muntashirakon.AppManager.utils.UIUtils.getPrimaryText;\nimport static io.github.muntashirakon.AppManager.utils.UIUtils.getStyledKeyValue;\nimport static io.github.muntashirakon.AppManager.utils.UIUtils.getTitleText;\n\nimport android.annotation.SuppressLint;\nimport android.annotation.UserIdInt;\nimport android.app.usage.IStorageStatsManager;\nimport android.app.usage.StorageStats;\nimport android.content.ComponentName;\nimport android.content.Context;\nimport android.content.pm.ActivityInfo;\nimport android.content.pm.ApplicationInfo;\nimport android.content.pm.ComponentInfo;\nimport android.content.pm.IPackageManager;\nimport android.content.pm.IPackageStatsObserver;\nimport android.content.pm.PackageInfo;\nimport android.content.pm.PackageManager;\nimport android.content.pm.PackageManager.NameNotFoundException;\nimport android.content.pm.SigningInfo;\nimport android.os.Build;\nimport android.os.PowerManager;\nimport android.os.RemoteException;\nimport android.os.UserHandleHidden;\nimport android.os.storage.StorageManagerHidden;\nimport android.system.ErrnoException;\nimport android.text.Spannable;\nimport android.text.SpannableStringBuilder;\nimport android.util.Pair;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.RequiresPermission;\nimport androidx.annotation.WorkerThread;\nimport androidx.core.content.pm.PackageInfoCompat;\n\nimport com.android.apksig.ApkVerifier;\nimport com.android.apksig.apk.ApkFormatException;\n\nimport org.jetbrains.annotations.Contract;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.security.NoSuchAlgorithmException;\nimport java.security.PublicKey;\nimport java.security.cert.CertificateEncodingException;\nimport java.security.cert.CertificateExpiredException;\nimport java.security.cert.CertificateNotYetValidException;\nimport java.security.cert.X509Certificate;\nimport java.security.interfaces.ECPublicKey;\nimport java.security.interfaces.RSAPublicKey;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collection;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.Set;\nimport java.util.UUID;\nimport java.util.concurrent.CountDownLatch;\nimport java.util.concurrent.TimeUnit;\nimport java.util.concurrent.atomic.AtomicReference;\n\nimport aosp.libcore.util.EmptyArray;\nimport aosp.libcore.util.HexEncoding;\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.apk.signing.Signer;\nimport io.github.muntashirakon.AppManager.apk.signing.SignerInfo;\nimport io.github.muntashirakon.AppManager.compat.AppOpsManagerCompat;\nimport io.github.muntashirakon.AppManager.compat.PackageManagerCompat;\nimport io.github.muntashirakon.AppManager.db.entity.App;\nimport io.github.muntashirakon.AppManager.db.entity.Backup;\nimport io.github.muntashirakon.AppManager.db.utils.AppDb;\nimport io.github.muntashirakon.AppManager.ipc.ProxyBinder;\nimport io.github.muntashirakon.AppManager.logs.Log;\nimport io.github.muntashirakon.AppManager.main.ApplicationItem;\nimport io.github.muntashirakon.AppManager.misc.OidMap;\nimport io.github.muntashirakon.AppManager.rules.RuleType;\nimport io.github.muntashirakon.AppManager.rules.compontents.ComponentUtils;\nimport io.github.muntashirakon.AppManager.runner.Runner;\nimport io.github.muntashirakon.AppManager.runner.RunnerUtils;\nimport io.github.muntashirakon.AppManager.self.SelfPermissions;\nimport io.github.muntashirakon.AppManager.types.PackageSizeInfo;\nimport io.github.muntashirakon.AppManager.types.UserPackagePair;\nimport io.github.muntashirakon.AppManager.users.Users;\nimport io.github.muntashirakon.AppManager.utils.appearance.ColorCodes;\nimport io.github.muntashirakon.io.ExtendedFile;\nimport io.github.muntashirakon.io.Path;\nimport io.github.muntashirakon.io.Paths;\nimport io.github.muntashirakon.io.UidGidPair;\n\npublic final class PackageUtils {\n    public static final String TAG = PackageUtils.class.getSimpleName();\n\n    public static final File PACKAGE_STAGING_DIRECTORY = new File(\"/data/local/tmp\");\n\n    @NonNull\n    public static ArrayList<UserPackagePair> getUserPackagePairs(@NonNull List<ApplicationItem> applicationItems) {\n        ArrayList<UserPackagePair> userPackagePairList = new ArrayList<>();\n        int currentUser = UserHandleHidden.myUserId();\n        for (ApplicationItem item : applicationItems) {\n            if (item.userIds.length > 0) {\n                for (int userId : item.userIds)\n                    userPackagePairList.add(new UserPackagePair(item.packageName, userId));\n            } else {\n                userPackagePairList.add(new UserPackagePair(item.packageName, currentUser));\n            }\n        }\n        return userPackagePairList;\n    }\n\n    /**\n     * List all applications stored in App Manager database as well as from the system.\n     *\n     * @param loadInBackground Retrieve applications from the system using the given thread instead of the current thread.\n     * @param loadBackups      Load/List backup metadata\n     * @return List of applications, which could be the cached version if the executor parameter is {@code null}.\n     */\n    @WorkerThread\n    @NonNull\n    public static List<ApplicationItem> getInstalledOrBackedUpApplicationsFromDb(@NonNull Context context,\n                                                                                 boolean loadInBackground,\n                                                                                 boolean loadBackups) {\n        HashMap<String, ApplicationItem> applicationItems = new HashMap<>();\n        AppDb appDb = new AppDb();\n        List<App> apps = appDb.getAllApplications();\n        if (loadInBackground && apps.isEmpty()) {\n            // Force-load in foreground\n            loadInBackground = false;\n        }\n        if (!loadInBackground) {\n            PowerManager.WakeLock wakeLock = CpuUtils.getPartialWakeLock(\"appDbUpdater\");\n            try {\n                wakeLock.acquire();\n                // Load app list for the first time\n                Log.d(TAG, \"Loading apps for the first time.\");\n                appDb.loadInstalledOrBackedUpApplications(context);\n                apps = appDb.getAllApplications();\n            } finally {\n                CpuUtils.releaseWakeLock(wakeLock);\n            }\n        }\n        Map<String, Backup> backups = appDb.getBackups(false);\n        int thisUser = UserHandleHidden.myUserId();\n        // Get application items from apps\n        for (App app : apps) {\n            ApplicationItem item;\n            ApplicationItem oldItem = applicationItems.get(app.packageName);\n            if (app.isInstalled) {\n                boolean newItem = oldItem == null || !oldItem.isInstalled;\n                if (oldItem != null) {\n                    // Item already exists\n                    item = oldItem;\n                } else {\n                    // Item doesn't exist\n                    item = new ApplicationItem();\n                    applicationItems.put(app.packageName, item);\n                    item.packageName = app.packageName;\n                }\n                item.userIds = ArrayUtils.appendInt(item.userIds, app.userId);\n                item.isInstalled = true;\n                item.isOnlyDataInstalled = false;\n                item.openCount += app.openCount;\n                item.screenTime += app.screenTime;\n                if (item.lastUsageTime == 0L || item.lastUsageTime < app.lastUsageTime) {\n                    item.lastUsageTime = app.lastUsageTime;\n                }\n                item.hasKeystore |= app.hasKeystore;\n                item.usesSaf |= app.usesSaf;\n                if (app.ssaid != null) {\n                    item.ssaid = app.ssaid;\n                }\n                item.totalSize += app.codeSize + app.dataSize;\n                item.dataUsage += app.wifiDataUsage + app.mobileDataUsage;\n                if (!newItem && app.userId != thisUser) {\n                    // This user has the highest priority\n                    continue;\n                }\n            } else {\n                // App not installed but may be installed in other profiles\n                if (oldItem != null) {\n                    // Item exists, use the previous status\n                    continue;\n                } else {\n                    // Item doesn't exist, don't add user handle\n                    item = new ApplicationItem();\n                    item.packageName = app.packageName;\n                    applicationItems.put(app.packageName, item);\n                    item.isInstalled = false;\n                    item.isOnlyDataInstalled = app.isOnlyDataInstalled;\n                    item.hasKeystore |= app.hasKeystore;\n                }\n            }\n            item.backup = backups.remove(item.packageName);\n            item.flags = app.flags;\n            item.uid = app.uid;\n            item.debuggable = app.isDebuggable();\n            item.isUser = !app.isSystemApp();\n            item.isDisabled = !app.isEnabled;\n            item.label = app.packageLabel;\n            item.targetSdk = app.sdk;\n            item.versionName = app.versionName;\n            item.versionCode = app.versionCode;\n            item.sharedUserId = app.sharedUserId;\n            item.sha = new Pair<>(app.certName, app.certAlgo);\n            item.firstInstallTime = app.firstInstallTime;\n            item.lastUpdateTime = app.lastUpdateTime;\n            item.hasActivities = app.hasActivities;\n            item.hasSplits = app.hasSplits;\n            item.blockedCount = app.rulesCount;\n            item.trackerCount = app.trackerCount;\n            item.lastActionTime = app.lastActionTime;\n            item.generateOtherInfo();\n        }\n        // Add rest of the backups\n        for (String packageName : backups.keySet()) {\n            Backup backup = backups.get(packageName);\n            if (backup == null) continue;\n            ApplicationItem item = new ApplicationItem();\n            item.packageName = backup.packageName;\n            applicationItems.put(backup.packageName, item);\n            item.backup = backup;\n            item.versionName = backup.versionName;\n            item.versionCode = backup.versionCode;\n            item.label = backup.label;\n            item.firstInstallTime = backup.backupTime;\n            item.lastUpdateTime = backup.backupTime;\n            item.isUser = !backup.isSystem;\n            item.isDisabled = false;\n            item.isInstalled = false;\n            item.isOnlyDataInstalled = false;\n            item.hasSplits = backup.hasSplits;\n            item.hasKeystore = backup.hasKeyStore;\n            item.generateOtherInfo();\n        }\n        if (loadInBackground) {\n            // Update list of apps safely in the background.\n            // We need to do this here to avoid locks in AppDb\n            ThreadUtils.postOnBackgroundThread(() -> {\n                PowerManager.WakeLock wakeLock = CpuUtils.getPartialWakeLock(\"appDbUpdater\");\n                try {\n                    wakeLock.acquire();\n                    if (loadBackups) {\n                        appDb.loadInstalledOrBackedUpApplications(context);\n                    } else appDb.updateApplications(context);\n                } finally {\n                    CpuUtils.releaseWakeLock(wakeLock);\n                }\n            });\n        }\n        return new ArrayList<>(applicationItems.values());\n    }\n\n    @NonNull\n    public static List<PackageInfo> getAllPackages(int flags) {\n        return getAllPackages(flags, false);\n    }\n\n    @NonNull\n    public static List<PackageInfo> getAllPackages(int flags, boolean currentUserOnly) {\n        if (currentUserOnly) {\n            return PackageManagerCompat.getInstalledPackages(flags, UserHandleHidden.myUserId());\n        }\n        List<PackageInfo> packageInfoList = new ArrayList<>();\n        for (int userId : Users.getUsersIds()) {\n            if (!SelfPermissions.checkCrossUserPermission(userId, false)) {\n                // No support for cross user\n                continue;\n            }\n            packageInfoList.addAll(PackageManagerCompat.getInstalledPackages(flags, userId));\n            if (ThreadUtils.isInterrupted()) {\n                break;\n            }\n        }\n        return packageInfoList;\n    }\n\n\n    @NonNull\n    public static List<ApplicationInfo> getAllApplications(int flags) {\n        return getAllApplications(flags, false);\n    }\n\n    @NonNull\n    public static List<ApplicationInfo> getAllApplications(int flags, boolean currentUserOnly) {\n        if (currentUserOnly) {\n            return ExUtils.requireNonNullElse(() -> PackageManagerCompat.getInstalledApplications(flags,\n                    UserHandleHidden.myUserId()), Collections.emptyList());\n        }\n        List<ApplicationInfo> applicationInfoList = new ArrayList<>();\n        for (int userId : Users.getUsersIds()) {\n            try {\n                applicationInfoList.addAll(PackageManagerCompat.getInstalledApplications(flags, userId));\n                if (ThreadUtils.isInterrupted()) {\n                    break;\n                }\n            } catch (RemoteException ignore) {\n            }\n        }\n        return applicationInfoList;\n    }\n\n    @WorkerThread\n    @RequiresPermission(\"android.permission.PACKAGE_USAGE_STATS\")\n    @Nullable\n    public static PackageSizeInfo getPackageSizeInfo(@NonNull Context context, @NonNull String packageName,\n                                                     @UserIdInt int userHandle, @Nullable UUID storageUuid) {\n        AtomicReference<PackageSizeInfo> packageSizeInfo = new AtomicReference<>();\n        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {\n            CountDownLatch waitForStats = new CountDownLatch(1);\n            try {\n                IPackageManager pm;\n                if (UserHandleHidden.myUserId() == userHandle) {\n                    // Since GET_PACKAGE_SIZE is a normal permission, there's no need to use a privileged service\n                    pm = PackageManagerCompat.getUnprivilegedPackageManager();\n                } else {\n                    // May return SecurityException in the ADB mode\n                    pm = PackageManagerCompat.getPackageManager();\n                }\n                pm.getPackageSizeInfo(packageName, userHandle,\n                        new IPackageStatsObserver.Stub() {\n                            @Override\n                            public void onGetStatsCompleted(final android.content.pm.PackageStats pStats, boolean succeeded) {\n                                try {\n                                    if (succeeded) packageSizeInfo.set(new PackageSizeInfo(pStats));\n                                } finally {\n                                    waitForStats.countDown();\n                                }\n                            }\n                        });\n                waitForStats.await(5, TimeUnit.SECONDS);\n            } catch (RemoteException | InterruptedException | SecurityException e) {\n                Log.e(TAG, e);\n            }\n        } else {\n            try {\n                IStorageStatsManager storageStatsManager = IStorageStatsManager.Stub.asInterface(ProxyBinder\n                        .getService(Context.STORAGE_STATS_SERVICE));\n                String uuidString = storageUuid != null ? StorageManagerHidden.convert(storageUuid) : null;\n                StorageStats storageStats = storageStatsManager.queryStatsForPackage(uuidString, packageName,\n                        userHandle, context.getPackageName());\n                packageSizeInfo.set(new PackageSizeInfo(packageName, storageStats, userHandle));\n            } catch (Throwable e) {\n                Log.w(TAG, e);\n            }\n        }\n        return packageSizeInfo.get();\n    }\n\n    @NonNull\n    public static HashMap<String, RuleType> collectComponentClassNames(String packageName, @UserIdInt int userHandle) {\n        try {\n            PackageInfo packageInfo = PackageManagerCompat.getPackageInfo(packageName,\n                    PackageManager.GET_ACTIVITIES | PackageManager.GET_RECEIVERS | PackageManager.GET_PROVIDERS\n                            | MATCH_DISABLED_COMPONENTS | MATCH_UNINSTALLED_PACKAGES | PackageManager.GET_SERVICES\n                            | PackageManagerCompat.MATCH_STATIC_SHARED_AND_SDK_LIBRARIES,\n                    userHandle);\n            return collectComponentClassNames(packageInfo);\n        } catch (Throwable e) {\n            e.printStackTrace();\n        }\n        return new HashMap<>();\n    }\n\n    @NonNull\n    public static HashMap<String, RuleType> collectComponentClassNames(@Nullable PackageInfo packageInfo) {\n        HashMap<String, RuleType> componentClasses = new HashMap<>();\n        if (packageInfo == null) return componentClasses;\n        // Add activities\n        if (packageInfo.activities != null) {\n            for (ActivityInfo activityInfo : packageInfo.activities) {\n                componentClasses.put(activityInfo.name, RuleType.ACTIVITY);\n            }\n        }\n        // Add others\n        if (packageInfo.services != null) {\n            for (ComponentInfo componentInfo : packageInfo.services)\n                componentClasses.put(componentInfo.name, RuleType.SERVICE);\n        }\n        if (packageInfo.receivers != null) {\n            for (ComponentInfo componentInfo : packageInfo.receivers)\n                componentClasses.put(componentInfo.name, RuleType.RECEIVER);\n        }\n        if (packageInfo.providers != null) {\n            for (ComponentInfo componentInfo : packageInfo.providers)\n                componentClasses.put(componentInfo.name, RuleType.PROVIDER);\n        }\n        return componentClasses;\n    }\n\n    @NonNull\n    public static HashMap<String, RuleType> getFilteredComponents(String packageName, @UserIdInt int userHandle, String[] signatures) {\n        HashMap<String, RuleType> filteredComponents = new HashMap<>();\n        HashMap<String, RuleType> components = collectComponentClassNames(packageName, userHandle);\n        for (String componentName : components.keySet()) {\n            for (String signature : signatures) {\n                if (componentName.startsWith(signature) || componentName.contains(signature)) {\n                    filteredComponents.put(componentName, components.get(componentName));\n                }\n            }\n        }\n        return filteredComponents;\n    }\n\n    @NonNull\n    public static Collection<Integer> getFilteredAppOps(String packageName, @UserIdInt int userHandle, @NonNull int[] appOps, int mode) {\n        List<Integer> filteredAppOps = new ArrayList<>();\n        AppOpsManagerCompat appOpsManager = new AppOpsManagerCompat();\n        int uid = PackageUtils.getAppUid(new UserPackagePair(packageName, userHandle));\n        for (int appOp : appOps) {\n            try {\n                if (appOpsManager.checkOperation(appOp, uid, packageName) != mode) {\n                    filteredAppOps.add(appOp);\n                }\n            } catch (Exception e) {\n                e.printStackTrace();\n            }\n        }\n        return filteredAppOps;\n    }\n\n    @NonNull\n    public static HashMap<String, RuleType> getUserDisabledComponentsForPackage(String packageName, @UserIdInt int userId) {\n        HashMap<String, RuleType> componentClasses = collectComponentClassNames(packageName, userId);\n        HashMap<String, RuleType> disabledComponents = new HashMap<>();\n        for (String componentName : componentClasses.keySet()) {\n            try {\n                if (isComponentDisabledByUser(packageName, componentName, userId)) {\n                    disabledComponents.put(componentName, componentClasses.get(componentName));\n                }\n            } catch (NameNotFoundException ignore) {\n                // Component unavailable\n            }\n        }\n        disabledComponents.putAll(ComponentUtils.getIFWRulesForPackage(packageName));\n        return disabledComponents;\n    }\n\n    @SuppressLint(\"SwitchIntDef\")\n    public static boolean isComponentDisabledByUser(@NonNull String packageName, @NonNull String componentClassName,\n                                                    @UserIdInt int userId)\n            throws SecurityException, NameNotFoundException {\n        try {\n            ComponentName componentName = new ComponentName(packageName, componentClassName);\n            switch (PackageManagerCompat.getComponentEnabledSetting(componentName, userId)) {\n                case PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER:\n                    return true;\n                case PackageManager.COMPONENT_ENABLED_STATE_DISABLED:\n                case PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED:\n                case PackageManager.COMPONENT_ENABLED_STATE_ENABLED:\n                case PackageManager.COMPONENT_ENABLED_STATE_DEFAULT:\n                default:\n                    return false;\n            }\n        } catch (IllegalArgumentException e) {\n            throw (NameNotFoundException) new NameNotFoundException(e.getMessage()).initCause(e);\n        }\n    }\n\n    @Nullable\n    public static String[] getPermissionsForPackage(String packageName, @UserIdInt int userId)\n            throws NameNotFoundException, RemoteException {\n        PackageInfo info = PackageManagerCompat.getPackageInfo(packageName, PackageManager.GET_PERMISSIONS\n                | PackageManagerCompat.MATCH_STATIC_SHARED_AND_SDK_LIBRARIES, userId);\n        return info.requestedPermissions;\n    }\n\n    @NonNull\n    public static String getPackageLabel(@NonNull PackageManager pm, String packageName) {\n        try {\n            @SuppressLint(\"WrongConstant\")\n            ApplicationInfo applicationInfo = pm.getApplicationInfo(packageName, MATCH_UNINSTALLED_PACKAGES);\n            return pm.getApplicationLabel(applicationInfo).toString();\n        } catch (NameNotFoundException ignore) {\n        }\n        return packageName;\n    }\n\n    @NonNull\n    public static CharSequence getPackageLabel(@NonNull PackageManager pm, String packageName, int userHandle) {\n        try {\n            ApplicationInfo applicationInfo = PackageManagerCompat.getApplicationInfo(packageName,\n                    PackageManagerCompat.MATCH_STATIC_SHARED_AND_SDK_LIBRARIES, userHandle);\n            return applicationInfo.loadLabel(pm);\n        } catch (Exception ignore) {\n        }\n        return packageName;\n    }\n\n    @Nullable\n    public static ArrayList<CharSequence> packagesToAppLabels(@NonNull PackageManager pm, @Nullable List<String> packages, List<Integer> userHandles) {\n        if (packages == null) return null;\n        ArrayList<CharSequence> appLabels = new ArrayList<>();\n        int i = 0;\n        for (String packageName : packages) {\n            appLabels.add(PackageUtils.getPackageLabel(pm, packageName, userHandles.get(i)).toString());\n            ++i;\n        }\n        return appLabels;\n    }\n\n    public static int getAppUid(@NonNull UserPackagePair pair) {\n        return ExUtils.requireNonNullElse(() -> PackageManagerCompat.getApplicationInfo(pair.getPackageName(),\n                PackageManagerCompat.MATCH_STATIC_SHARED_AND_SDK_LIBRARIES, pair.getUserId()).uid, -1);\n    }\n\n    @NonNull\n    public static String getSourceDir(@NonNull ApplicationInfo applicationInfo) {\n        String sourceDir = new File(applicationInfo.publicSourceDir).getParent(); // or applicationInfo.sourceDir\n        if (sourceDir == null) {\n            throw new RuntimeException(\"Application source directory cannot be empty\");\n        }\n        return sourceDir;\n    }\n\n    @Nullable\n    @Contract(\"_,!null -> !null\")\n    public static String getHiddenCodePathOrDefault(@NonNull String packageName, @Nullable String defaultPath) {\n        Runner.Result result = Runner.runCommand(RunnerUtils.CMD_PM + \" dump \" + packageName + \" | grep codePath\");\n        if (result.isSuccessful()) {\n            List<String> paths = result.getOutputAsList();\n            if (!paths.isEmpty()) {\n                // Get only the last path\n                String codePath = paths.get(paths.size() - 1);\n                int start = codePath.indexOf('=');\n                if (start != -1) return codePath.substring(start + 1);\n            }\n        }\n        return defaultPath != null ? new File(defaultPath).getParent() : null;\n    }\n\n    @NonNull\n    public static CharSequence[] getAppOpModeNames(@NonNull List<Integer> appOpModes) {\n        CharSequence[] appOpModeNames = new CharSequence[appOpModes.size()];\n        for (int i = 0; i < appOpModes.size(); ++i) {\n            appOpModeNames[i] = AppOpsManagerCompat.modeToName(appOpModes.get(i));\n        }\n        return appOpModeNames;\n    }\n\n    @NonNull\n    public static CharSequence[] getAppOpNames(@NonNull List<Integer> appOps) {\n        CharSequence[] appOpNames = new CharSequence[appOps.size()];\n        for (int i = 0; i < appOps.size(); ++i) {\n            appOpNames[i] = AppOpsManagerCompat.opToName(appOps.get(i));\n        }\n        return appOpNames;\n    }\n\n    /**\n     * Whether the app may be using Play App Signing i.e. letting Google manage the app's signing keys.\n     *\n     * @param applicationInfo {@link PackageManager#GET_META_DATA} must be used while fetching application info.\n     * @see <a href=\"https://support.google.com/googleplay/android-developer/answer/9842756#zippy=%2Capp-signing-process\">Use Play App Signing</a>\n     */\n    public static boolean usesPlayAppSigning(@NonNull ApplicationInfo applicationInfo) {\n        return applicationInfo.metaData != null\n                && \"STAMP_TYPE_DISTRIBUTION_APK\".equals(applicationInfo.metaData\n                .getString(\"com.android.stamp.type\"))\n                && \"https://play.google.com/store\".equals(applicationInfo.metaData\n                .getString(\"com.android.stamp.source\"));\n    }\n\n    @Nullable\n    public static SignerInfo getSignerInfo(@NonNull PackageInfo packageInfo, boolean isExternal) {\n        if (!isExternal || Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {\n                SigningInfo signingInfo = packageInfo.signingInfo;\n                if (signingInfo == null) {\n                    if (!isExternal) {\n                        return null;\n                    } // else Could be a false-negative\n                } else {\n                    return new SignerInfo(signingInfo);\n                }\n            }\n        }\n        // Is an external app\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P || packageInfo.signatures == null) {\n            // Could be a false-negative, try with apksig library\n            String apkPath = packageInfo.applicationInfo.publicSourceDir;\n            if (apkPath != null) {\n                Log.w(TAG, \"getSignerInfo: Using fallback method\");\n                return getSignerInfo(new File(apkPath));\n            }\n        }\n        return new SignerInfo(packageInfo.signatures);\n    }\n\n    @Nullable\n    private static SignerInfo getSignerInfo(@NonNull File apkFile) {\n        ApkVerifier apkVerifier = new ApkVerifier.Builder(apkFile)\n                .setMaxCheckedPlatformVersion(Build.VERSION.SDK_INT)\n                .build();\n        try {\n            return new SignerInfo(apkVerifier.verify());\n        } catch (IOException | ApkFormatException | NoSuchAlgorithmException e) {\n            e.printStackTrace();\n            return null;\n        }\n    }\n\n    @NonNull\n    public static String[] getSigningCertSha256Checksum(@NonNull PackageInfo packageInfo) {\n        return getSigningCertSha256Checksum(packageInfo, false);\n    }\n\n    public static boolean isSignatureDifferent(@NonNull PackageInfo newPkgInfo, @NonNull PackageInfo oldPkgInfo) {\n        SignerInfo newSignerInfo = getSignerInfo(newPkgInfo, true);\n        SignerInfo oldSignerInfo = getSignerInfo(oldPkgInfo, false);\n        if (newSignerInfo == null && oldSignerInfo == null) {\n            // No signers\n            return false;\n        }\n        if (newSignerInfo == null || oldSignerInfo == null) {\n            // One of them is signed, other doesn't\n            return true;\n        }\n        String[] newChecksums;\n        List<String> oldChecksums;\n        newChecksums = getSigningCertChecksums(DigestUtils.SHA_256, newSignerInfo);\n        oldChecksums = Arrays.asList(getSigningCertChecksums(DigestUtils.SHA_256, oldSignerInfo));\n        if (newSignerInfo.hasMultipleSigners()) {\n            // For multiple signers, all signatures must match.\n            if (newChecksums.length != oldChecksums.size()) {\n                // Signature is different if the number of signatures don't match\n                return true;\n            }\n            for (String newChecksum : newChecksums) {\n                oldChecksums.remove(newChecksum);\n            }\n            // Old checksums should contain no values if the checksums are the same\n            return !oldChecksums.isEmpty();\n        }\n        // For single signer, there could be one or more extra certificates for rotation.\n        if (newChecksums.length == 0 && oldChecksums.isEmpty()) {\n            // No signers\n            return false;\n        }\n        if (newChecksums.length == 0 || oldChecksums.isEmpty()) {\n            // One of them is signed, other doesn't\n            return true;\n        }\n        // Check if the user is downgrading or reinstalling\n        long oldVersionCode = PackageInfoCompat.getLongVersionCode(oldPkgInfo);\n        long newVersionCode = PackageInfoCompat.getLongVersionCode(newPkgInfo);\n        if (oldVersionCode >= newVersionCode) {\n            // Downgrading to an older version or reinstalling. Match only the first signature\n            return !newChecksums[0].equals(oldChecksums.get(0));\n        }\n        // Updating or reinstalling. Match only one signature\n        for (String newChecksum : newChecksums) {\n            if (oldChecksums.contains(newChecksum)) {\n                return false;\n            }\n        }\n        return true;\n    }\n\n    @NonNull\n    public static String[] getSigningCertSha256Checksum(PackageInfo packageInfo, boolean isExternal) {\n        return getSigningCertChecksums(DigestUtils.SHA_256, packageInfo, isExternal);\n    }\n\n    @NonNull\n    public static String[] getSigningCertChecksums(@DigestUtils.Algorithm String algo,\n                                                   PackageInfo packageInfo, boolean isExternal) {\n        SignerInfo signerInfo = getSignerInfo(packageInfo, isExternal);\n        return getSigningCertChecksums(algo, signerInfo);\n    }\n\n    @NonNull\n    public static String[] getSigningCertChecksums(@DigestUtils.Algorithm String algo,\n                                                   @Nullable SignerInfo signerInfo) {\n        X509Certificate[] signatureArray = signerInfo == null ? null : signerInfo.getAllSignerCerts();\n        if (signatureArray != null) {\n            ArrayList<String> checksums = new ArrayList<>();\n            for (X509Certificate signature : signatureArray) {\n                try {\n                    checksums.add(DigestUtils.getHexDigest(algo, signature.getEncoded()));\n                } catch (CertificateEncodingException e) {\n                    e.printStackTrace();\n                }\n            }\n            return checksums.toArray(new String[0]);\n        }\n        return EmptyArray.STRING;\n    }\n\n    @NonNull\n    public static Spannable getSigningCertificateInfo(@NonNull Context ctx, @Nullable X509Certificate certificate)\n            throws CertificateEncodingException {\n        SpannableStringBuilder builder = new SpannableStringBuilder();\n        if (certificate == null) return builder;\n        final String separator = LangUtils.getSeparatorString();\n        byte[] certBytes = certificate.getEncoded();\n        builder.append(getStyledKeyValue(ctx, R.string.subject, certificate.getSubjectX500Principal().getName(), separator))\n                .append(\"\\n\")\n                .append(getStyledKeyValue(ctx, R.string.issuer, certificate.getIssuerX500Principal().getName(), separator))\n                .append(\"\\n\")\n                .append(getStyledKeyValue(ctx, R.string.issued_date, certificate.getNotBefore().toString(), separator))\n                .append(\"\\n\")\n                .append(getStyledKeyValue(ctx, R.string.expiry_date, certificate.getNotAfter().toString(), separator))\n                .append(\"\\n\")\n                .append(getStyledKeyValue(ctx, R.string.type, certificate.getType(), separator))\n                .append(\", \")\n                .append(getStyledKeyValue(ctx, R.string.version, String.valueOf(certificate.getVersion()), separator))\n                .append(\", \");\n        int validity;\n        try {\n            certificate.checkValidity();\n            validity = R.string.valid;\n        } catch (CertificateExpiredException e) {\n            validity = R.string.expired;\n        } catch (CertificateNotYetValidException e) {\n            validity = R.string.not_yet_valid;\n        }\n        builder.append(getStyledKeyValue(ctx, R.string.validity, ctx.getText(validity), separator))\n                .append(\"\\n\")\n                .append(getPrimaryText(ctx, ctx.getString(R.string.serial_no) + separator))\n                .append(getMonospacedText(HexEncoding.encodeToString(certificate.getSerialNumber().toByteArray(), false)))\n                .append(\"\\n\");\n        // Checksums\n        builder.append(getTitleText(ctx, ctx.getString(R.string.checksums))).append(\"\\n\");\n        Pair<String, String>[] digests = DigestUtils.getDigests(certBytes);\n        for (Pair<String, String> digest : digests) {\n            builder.append(getPrimaryText(ctx, digest.first + separator))\n                    .append(getMonospacedText(digest.second))\n                    .append(\"\\n\");\n        }\n        // Signature\n        builder.append(getTitleText(ctx, ctx.getString(R.string.app_signing_signature)))\n                .append(\"\\n\")\n                .append(getStyledKeyValue(ctx, R.string.algorithm, certificate.getSigAlgName(), separator))\n                .append(\"\\n\")\n                .append(getStyledKeyValue(ctx, \"OID\", certificate.getSigAlgOID(), separator))\n                .append(\"\\n\")\n                .append(getPrimaryText(ctx, ctx.getString(R.string.app_signing_signature) + separator))\n                .append(getMonospacedText(HexEncoding.encodeToString(certificate.getSignature(), false))).append(\"\\n\");\n        // Public key used by Google: https://github.com/google/conscrypt\n        // 1. X509PublicKey (PublicKey)\n        // 2. OpenSSLRSAPublicKey (RSAPublicKey)\n        // 3. OpenSSLECPublicKey (ECPublicKey)\n        PublicKey publicKey = certificate.getPublicKey();\n        builder.append(getTitleText(ctx, ctx.getString(R.string.public_key)))\n                .append(\"\\n\")\n                .append(getStyledKeyValue(ctx, R.string.algorithm, publicKey.getAlgorithm(), separator))\n                .append(\"\\n\")\n                .append(getStyledKeyValue(ctx, R.string.format, publicKey.getFormat(), separator));\n        if (publicKey instanceof RSAPublicKey) {\n            RSAPublicKey rsaPublicKey = (RSAPublicKey) publicKey;\n            builder.append(\"\\n\")\n                    .append(getStyledKeyValue(ctx, R.string.rsa_exponent, rsaPublicKey.getPublicExponent().toString(), separator))\n                    .append(\"\\n\")\n                    .append(getPrimaryText(ctx, ctx.getString(R.string.rsa_modulus) + separator))\n                    .append(getMonospacedText(HexEncoding.encodeToString(rsaPublicKey.getModulus().toByteArray(), false)));\n        } else if (publicKey instanceof ECPublicKey) {\n            ECPublicKey ecPublicKey = (ECPublicKey) publicKey;\n            builder.append(\"\\n\")\n                    .append(getStyledKeyValue(ctx, R.string.dsa_affine_x, ecPublicKey.getW().getAffineX().toString(), separator))\n                    .append(\"\\n\")\n                    .append(getStyledKeyValue(ctx, R.string.dsa_affine_y, ecPublicKey.getW().getAffineY().toString(), separator));\n        }\n        // TODO(5/10/20): Add description for each extensions\n        Set<String> critSet = certificate.getCriticalExtensionOIDs();\n        if (critSet != null && !critSet.isEmpty()) {\n            builder.append(\"\\n\").append(getTitleText(ctx, ctx.getString(R.string.critical_exts)));\n            for (String oid : critSet) {\n                String oidName = OidMap.getName(oid);\n                builder.append(\"\\n- \")\n                        .append(getPrimaryText(ctx, (oidName != null ? oidName : oid) + separator))\n                        .append(getMonospacedText(HexEncoding.encodeToString(certificate.getExtensionValue(oid), false)));\n            }\n        }\n        Set<String> nonCritSet = certificate.getNonCriticalExtensionOIDs();\n        if (nonCritSet != null && !nonCritSet.isEmpty()) {\n            builder.append(\"\\n\").append(getTitleText(ctx, ctx.getString(R.string.non_critical_exts)));\n            for (String oid : nonCritSet) {\n                String oidName = OidMap.getName(oid);\n                builder.append(\"\\n- \")\n                        .append(getPrimaryText(ctx, (oidName != null ? oidName : oid) + separator))\n                        .append(getMonospacedText(HexEncoding.encodeToString(certificate.getExtensionValue(oid), false)));\n            }\n        }\n        return builder;\n    }\n\n    @NonNull\n    public static Spannable getApkVerifierInfo(@Nullable ApkVerifier.Result result, Context ctx) {\n        SpannableStringBuilder builder = new SpannableStringBuilder();\n        if (result == null) return builder;\n        int colorFailure = ColorCodes.getFailureColor(ctx);\n        int colorSuccess = ColorCodes.getSuccessColor(ctx);\n        int warnCount = 0;\n        List<CharSequence> errors = new ArrayList<>();\n        for (ApkVerifier.IssueWithParams err : result.getErrors()) {\n            errors.add(getColoredText(err.toString(), colorFailure));\n        }\n        warnCount += result.getWarnings().size();\n        for (ApkVerifier.Result.V1SchemeSignerInfo signer : result.getV1SchemeIgnoredSigners()) {\n            String name = signer.getName();\n            for (ApkVerifier.IssueWithParams err : signer.getErrors()) {\n                errors.add(getColoredText(new SpannableStringBuilder(getBoldString(name + LangUtils.getSeparatorString())).append(err.toString()), colorFailure));\n            }\n            warnCount += signer.getWarnings().size();\n        }\n        if (result.isVerified()) {\n            if (warnCount == 0) {\n                builder.append(getColoredText(getTitleText(ctx, \"✔ \" +\n                        ctx.getString(R.string.verified)), colorSuccess));\n            } else {\n                builder.append(getColoredText(getTitleText(ctx, \"✔ \" + ctx.getResources()\n                        .getQuantityString(R.plurals.verified_with_warning, warnCount, warnCount)), colorSuccess));\n            }\n            if (result.isSourceStampVerified()) {\n                String source = Signer.getSourceStampSource(result.getSourceStampInfo());\n                if (source != null) {\n                    builder.append(\"\\n✔ \").append(ctx.getString(R.string.source_stamp_verified_and_identified_to_be_from_source, source));\n                } else builder.append(\"\\n✔ \").append(ctx.getString(R.string.source_stamp_verified));\n            }\n            List<CharSequence> sigSchemes = new LinkedList<>();\n            if (result.isVerifiedUsingV1Scheme()) sigSchemes.add(\"v1\");\n            if (result.isVerifiedUsingV2Scheme()) sigSchemes.add(\"v2\");\n            if (result.isVerifiedUsingV3Scheme()) sigSchemes.add(\"v3\");\n            if (result.isVerifiedUsingV31Scheme()) sigSchemes.add(\"v3.1\");\n            if (result.isVerifiedUsingV4Scheme()) sigSchemes.add(\"v4\");\n            builder.append(\"\\n\").append(getPrimaryText(ctx, ctx.getResources()\n                    .getQuantityString(R.plurals.app_signing_signature_schemes_pl, sigSchemes.size()) + LangUtils.getSeparatorString()));\n            builder.append(TextUtilsCompat.joinSpannable(\", \", sigSchemes));\n        } else {\n            builder.append(getColoredText(getTitleText(ctx, \"✘ \" + ctx.getString(R.string.not_verified)), colorFailure));\n        }\n        builder.append(\"\\n\");\n        // If there are errors, no certificate info will be loaded\n        builder.append(TextUtilsCompat.joinSpannable(\"\\n\", errors)).append(\"\\n\");\n        return builder;\n    }\n\n    public static void ensurePackageStagingDirectoryPrivileged() throws ErrnoException {\n        if (!Paths.get(\"/data/local\").canWrite()) {\n            return;\n        }\n        Path psd = Paths.get(PACKAGE_STAGING_DIRECTORY);\n        if (!psd.isDirectory()) {\n            // Recreate directory\n            Path parent = psd.getParent();\n            if (parent == null) {\n                throw new IllegalStateException(\"Parent should be /data/local\");\n            }\n            if (psd.exists()) psd.delete();\n            psd.mkdir();\n        }\n        // Change permission\n        ExtendedFile f = Objects.requireNonNull(psd.getFile());\n        if ((f.getMode() & 0x1FF) != 0711) {\n            f.setMode(0711);\n        }\n        // Change UID, GID\n        UidGidPair uidGidPair = f.getUidGid();\n        if (uidGidPair.uid != 2000 || uidGidPair.gid != 2000) {\n            f.setUidGid(2000, 2000);\n        }\n    }\n\n    @NonNull\n    public static String ensurePackageStagingDirectoryCommand() {\n        String psd = PACKAGE_STAGING_DIRECTORY.getAbsolutePath();\n        return String.format(\"( [ -d  %s ] || ( rm %s; mkdir %s && chmod 771 %s && chown 2000:2000 %s ) )\", psd, psd, psd, psd, psd);\n    }\n\n    /**\n     * Check if the given package name is valid.\n     *\n     * @param packageName The name to check.\n     * @return Success if it's valid.\n     * @see <a href=\"https://cs.android.com/android/platform/superproject/main/+/main:frameworks/base/core/java/android/content/pm/parsing/FrameworkParsingPackageUtils.java;l=72;drc=1bc76ef01ec070d5155d99be0c495fd4ee60d074\">FrameworkParsingPackageUtils.java</a>\n     */\n    public static boolean validateName(@NonNull String packageName) {\n        if (packageName.equals(\"android\")) {\n            // platform package\n            return true;\n        }\n        final int N = packageName.length();\n        boolean hasSep = false;\n        boolean front = true;\n        for (int i = 0; i < N; i++) {\n            final char c = packageName.charAt(i);\n            if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) {\n                front = false;\n                continue;\n            }\n            if (!front) {\n                if ((c >= '0' && c <= '9') || c == '_') {\n                    continue;\n                }\n            }\n            if (c == '.') {\n                hasSep = true;\n                front = true;\n                continue;\n            }\n            return false;\n        }\n        return hasSep;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/utils/ParcelFileDescriptorUtil.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage io.github.muntashirakon.AppManager.utils;\n\nimport android.os.ParcelFileDescriptor;\nimport android.util.Log;\n\nimport androidx.annotation.NonNull;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\n\nimport io.github.muntashirakon.io.IoUtils;\n\n// Copyright 2013 Florian Schmaus\npublic class ParcelFileDescriptorUtil {\n\n    @NonNull\n    public static ParcelFileDescriptor pipeFrom(@NonNull InputStream inputStream)\n            throws IOException {\n        ParcelFileDescriptor[] pipe = ParcelFileDescriptor.createPipe();\n        ParcelFileDescriptor readSide = pipe[0];\n        ParcelFileDescriptor writeSide = pipe[1];\n\n        new TransferThread(inputStream, new ParcelFileDescriptor.AutoCloseOutputStream(writeSide))\n                .start();\n\n        return readSide;\n    }\n\n\n    @NonNull\n    public static TransferThread pipeTo(@NonNull OutputStream outputStream,\n                                        @NonNull ParcelFileDescriptor output) {\n        TransferThread t = new TransferThread(new ParcelFileDescriptor.AutoCloseInputStream(output), outputStream);\n        t.start();\n        return t;\n    }\n\n    @NonNull\n    public static ParcelFileDescriptor pipeTo(@NonNull OutputStream outputStream)\n            throws IOException {\n        ParcelFileDescriptor[] pipe = ParcelFileDescriptor.createPipe();\n        ParcelFileDescriptor readSide = pipe[0];\n        ParcelFileDescriptor writeSide = pipe[1];\n\n        new TransferThread(new ParcelFileDescriptor.AutoCloseInputStream(readSide), outputStream)\n                .start();\n\n        return writeSide;\n    }\n\n\n    static class TransferThread extends Thread {\n        private final InputStream mIn;\n        private final OutputStream mOut;\n\n        TransferThread(InputStream in, OutputStream out) {\n            super(\"IPC Transfer Thread\");\n            mIn = in;\n            mOut = out;\n            setDaemon(true);\n        }\n\n        @Override\n        public void run() {\n            byte[] buf = new byte[IoUtils.DEFAULT_BUFFER_SIZE];\n            int len;\n\n            try {\n                while ((len = mIn.read(buf)) > 0) {\n                    mOut.write(buf, 0, len);\n                }\n            } catch (IOException e) {\n                Log.e(\"FD\", \"IOException when writing to out\", e);\n            } finally {\n                try {\n                    mIn.close();\n                } catch (IOException ignored) {\n                }\n                try {\n                    mOut.close();\n                } catch (IOException ignored) {\n                }\n            }\n        }\n    }\n\n}"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/utils/ResourceUtil.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.utils;\n\nimport android.annotation.SuppressLint;\nimport android.content.ComponentName;\nimport android.content.Context;\nimport android.content.pm.PackageManager;\nimport android.content.res.Resources;\nimport android.graphics.drawable.Drawable;\n\nimport androidx.annotation.DrawableRes;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.core.content.res.ResourcesCompat;\n\npublic final class ResourceUtil {\n    public static class ParsedResource {\n        @NonNull\n        private final String mPackageName;\n        @NonNull\n        private final Resources mRes;\n        @DrawableRes\n        private final int mResId;\n\n        private ParsedResource(@NonNull String packageName, @NonNull Resources res, @DrawableRes int resId) {\n            mPackageName = packageName;\n            mRes = res;\n            mResId = resId;\n        }\n\n        @NonNull\n        public String getPackageName() {\n            return mPackageName;\n        }\n\n        /**\n         * @see ResourcesCompat#getDrawable(Resources, int, Resources.Theme)\n         */\n        @Nullable\n        public Drawable getDrawable() {\n            return getDrawable(null);\n        }\n\n        /**\n         * @see ResourcesCompat#getDrawable(Resources, int, Resources.Theme)\n         */\n        @Nullable\n        public Drawable getDrawable(@Nullable Resources.Theme theme) {\n            return ResourcesCompat.getDrawable(mRes, mResId, theme);\n        }\n    }\n\n    /**\n     * Parse a resource name having the following format:\n     * <p>\n     * <code>\n     * package-name:type/res-name\n     * </code>\n     */\n    @NonNull\n    public static ParsedResource getResourceFromName(@NonNull PackageManager pm, @NonNull String resName)\n            throws PackageManager.NameNotFoundException, Resources.NotFoundException {\n        int indexOfColon = resName.indexOf(':');\n        int indexOfSlash = resName.indexOf('/');\n        if (indexOfColon == -1 || indexOfSlash == -1) {\n            throw new Resources.NotFoundException(\"Resource \" + resName + \" is not found.\");\n        }\n        String packageName = resName.substring(0, indexOfColon);\n        String type = resName.substring(indexOfColon + 1, indexOfSlash);\n        String name = resName.substring(indexOfSlash + 1);\n        Resources res = pm.getResourcesForApplication(packageName);\n        @SuppressLint(\"DiscouragedApi\")\n        int resId = res.getIdentifier(name, type, packageName);\n        if (resId == 0) {\n            throw new Resources.NotFoundException(\"Resource \" + name + \" of type \" + type + \" is not found in package \" + packageName);\n        }\n        return new ParsedResource(packageName, res, resId);\n    }\n\n    @SuppressLint(\"DiscouragedApi\")\n    public static int getRawDataId(@NonNull Context context, @NonNull String name) {\n        return context.getResources().getIdentifier(name, \"raw\", context.getPackageName());\n    }\n\n    @Nullable\n    public String packageName;\n    @Nullable\n    public String className;\n    @Nullable\n    public Resources resources;\n\n    public boolean loadResources(@NonNull PackageManager pm, @NonNull String packageName) {\n        try {\n            this.packageName = packageName;\n            this.className = null;\n            this.resources = pm.getResourcesForApplication(packageName);\n            return true;\n        } catch (PackageManager.NameNotFoundException e) {\n            return false;\n        }\n    }\n\n    public boolean loadResources(@NonNull PackageManager pm, @NonNull String packageName, @NonNull String className) {\n        try {\n            this.packageName = packageName;\n            this.className = className;\n            this.resources = pm.getResourcesForActivity(new ComponentName(packageName, className));\n            return true;\n        } catch (PackageManager.NameNotFoundException e) {\n            return false;\n        }\n    }\n\n    public boolean loadAndroidResources() {\n        this.packageName = \"android\";\n        this.className = null;\n        this.resources = Resources.getSystem();\n        return true;\n    }\n\n    /**\n     * Return the string value associated with a particular resource ID. It will be stripped of any styled text information.\n     *\n     * @param stringRes The desired resource identifier.\n     * @return String The string data associated with the resource, stripped of styled text information.\n     * @throws Resources.NotFoundException Throws NotFoundException if the given ID does not exist.\n     */\n    @NonNull\n    @SuppressLint(\"DiscouragedApi\")\n    public String getString(@NonNull String stringRes) throws Resources.NotFoundException {\n        if (resources == null) {\n            throw new Resources.NotFoundException(\"No resource could be loaded.\");\n        }\n        int intStringRes = resources.getIdentifier(stringRes, \"string\", packageName);\n        if (intStringRes == 0) throw new Resources.NotFoundException(\"String resource ID \" + stringRes);\n        return this.resources.getString(intStringRes);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/utils/RestartUtils.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.utils;\n\nimport androidx.annotation.IntDef;\n\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.util.Locale;\n\nimport io.github.muntashirakon.AppManager.runner.Runner;\n\npublic class RestartUtils {\n    @IntDef({\n            RESTART_NORMAL,\n            RESTART_RECOVERY,\n            RESTART_BOOTLOADER,\n            RESTART_USERSPACE,\n            RESTART_DOWNLOAD,\n            RESTART_EDL,\n    })\n    @Retention(RetentionPolicy.SOURCE)\n    public @interface RestartType {\n    }\n\n    public static final int RESTART_NORMAL = 0;\n    public static final int RESTART_RECOVERY = 1;\n    public static final int RESTART_BOOTLOADER = 2;\n    public static final int RESTART_USERSPACE = 3;\n    public static final int RESTART_DOWNLOAD = 4;\n    public static final int RESTART_EDL = 5;\n\n    private static final String[] RESTART_REASON = new String[]{\n            // Mapped to above\n            \"\", \"recovery\", \"bootloader\", \"userspace\", \"download\", \"edl\"\n    };\n\n    public static void restart(@RestartType int type) {\n        restart(RESTART_REASON[type]);\n    }\n\n    private static void restart(String reason) {\n        // https://github.com/topjohnwu/Magisk/blob/5512917ec123e815dec1e3af871357f760acc1f3/app/src/main/java/com/topjohnwu/magisk/ktx/XSU.kt\n        if (RESTART_REASON[RESTART_RECOVERY].equals(reason)) {\n            // KEYCODE_POWER = 26, hide incorrect \"Factory data reset\" message\n            Runner.runCommand(new String[]{\"/system/bin/input\", \"keyevent\", \"26\"});\n        }\n        String cmd = String.format(Locale.ROOT, \"/system/bin/svc power reboot %s || /system/bin/reboot %s\", reason, reason);\n        Runner.runCommand(cmd);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/utils/SAFUtils.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.utils;\n\nimport android.content.Context;\nimport android.content.UriPermission;\nimport android.net.Uri;\n\nimport androidx.annotation.NonNull;\nimport androidx.collection.ArrayMap;\n\nimport java.util.List;\n\npublic final class SAFUtils {\n    private SAFUtils() {\n    }\n\n    @NonNull\n    public static ArrayMap<Uri, Long> getUrisWithDate(@NonNull Context context) {\n        List<UriPermission> permissionList = context.getContentResolver().getPersistedUriPermissions();\n        ArrayMap<Uri, Long> uris = new ArrayMap<>(permissionList.size());\n        for (UriPermission permission : permissionList) {\n            if (permission.isReadPermission() && permission.isWritePermission()) {\n                // We only work with rw directories\n                uris.put(permission.getUri(), permission.getPersistedTime());\n            }\n        }\n        return uris;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/utils/StoragePermission.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.utils;\n\nimport android.Manifest;\nimport android.content.Intent;\nimport android.os.Build;\nimport android.os.Environment;\nimport android.provider.Settings;\n\nimport androidx.activity.result.ActivityResult;\nimport androidx.activity.result.ActivityResultCaller;\nimport androidx.activity.result.contract.ActivityResultContracts;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.RequiresApi;\n\nimport io.github.muntashirakon.AppManager.self.SelfPermissions;\n\npublic class StoragePermission {\n    @NonNull\n    public static StoragePermission init(@NonNull ActivityResultCaller caller) {\n        return new StoragePermission(caller);\n    }\n\n    public interface StoragePermissionCallback {\n        void onResult(boolean granted);\n    }\n\n    private BetterActivityResult<String, Boolean> mStoragePerm;\n    @RequiresApi(api = Build.VERSION_CODES.R)\n    private BetterActivityResult<Intent, ActivityResult> mStoragePermApi30;\n\n    private StoragePermission(@NonNull ActivityResultCaller caller) {\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {\n            mStoragePermApi30 = BetterActivityResult.registerForActivityResult(caller, new ActivityResultContracts.StartActivityForResult());\n        } else {\n            mStoragePerm = BetterActivityResult.registerForActivityResult(caller, new ActivityResultContracts.RequestPermission());\n        }\n    }\n\n    @SuppressWarnings(\"InlinedApi\")\n    public void request(@Nullable StoragePermissionCallback callback) {\n        if (SelfPermissions.checkSelfStoragePermission()) {\n            if (callback != null) callback.onResult(true);\n            return;\n        }\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {\n            mStoragePermApi30.launch(new Intent(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION), result -> {\n                if (callback != null) {\n                    callback.onResult(Environment.isExternalStorageManager());\n                }\n            });\n        } else {\n            mStoragePerm.launch(Manifest.permission.WRITE_EXTERNAL_STORAGE, result -> {\n                if (callback != null) {\n                    callback.onResult(SelfPermissions.checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE));\n                }\n            });\n        }\n    }\n\n    public void request() {\n        request(null);\n    }\n\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/utils/StorageUtils.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.utils;\n\nimport android.content.Context;\nimport android.net.Uri;\nimport android.os.Environment;\nimport android.os.storage.StorageVolume;\nimport android.os.storage.StorageVolumeHidden;\nimport android.text.TextUtils;\nimport android.util.Log;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.WorkerThread;\nimport androidx.collection.ArrayMap;\nimport androidx.core.content.ContextCompat;\n\nimport java.io.BufferedReader;\nimport java.io.File;\nimport java.io.IOException;\nimport java.util.Arrays;\nimport java.util.HashSet;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Set;\n\nimport dev.rikka.tools.refine.Refine;\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.compat.StorageManagerCompat;\nimport io.github.muntashirakon.AppManager.users.Users;\nimport io.github.muntashirakon.io.Path;\nimport io.github.muntashirakon.io.PathReader;\nimport io.github.muntashirakon.io.Paths;\n\npublic class StorageUtils {\n    public static final String TAG = \"StorageUtils\";\n\n    private static final String ENV_SECONDARY_STORAGE = \"SECONDARY_STORAGE\";\n\n    @WorkerThread\n    @NonNull\n    public static ArrayMap<String, Uri> getAllStorageLocations(@NonNull Context context) {\n        ArrayMap<String, Uri> storageLocations = new ArrayMap<>(10);\n        Path sdCard = Paths.get(Environment.getExternalStorageDirectory());\n        addStorage(context.getString(R.string.external_storage), sdCard, storageLocations);\n        getStorageEnv(context, storageLocations);\n        retrieveStorageManager(context, storageLocations);\n        retrieveStorageFilesystem(storageLocations);\n        getStorageExternalFilesDir(context, storageLocations);\n        // Get SAF persisted directories\n        ArrayMap<Uri, Long> grantedUrisAndDate = SAFUtils.getUrisWithDate(context);\n        for (int i = 0; i < grantedUrisAndDate.size(); ++i) {\n            Uri uri = grantedUrisAndDate.keyAt(i);\n            long time = grantedUrisAndDate.valueAt(i);\n            if (Paths.get(uri).isDirectory()) {\n                // Only directories are locations\n                String readableName = Paths.getLastPathSegment(uri.getPath()) + \" \" + DateUtils.formatDate(context, time);\n                storageLocations.put(readableName, getFixedTreeUri(uri));\n            }\n        }\n        return storageLocations;\n    }\n\n    /**\n     * unified test function to add storage if fitting\n     */\n    private static void addStorage(@NonNull String label, @Nullable Path entry, @NonNull Map<String, Uri> storageLocations) {\n        if (entry == null) {\n            return;\n        }\n        if (entry.isSymbolicLink()) {\n            // Use the real path\n            Path finalEntry = entry;\n            entry = ExUtils.requireNonNullElse(finalEntry::getRealPath, finalEntry);\n        }\n        Uri uri = entry.getUri();\n        if (!storageLocations.containsValue(uri)) {\n            storageLocations.put(label, uri);\n        } else {\n            Log.d(TAG, entry.getUri().toString());\n        }\n    }\n\n    /**\n     * Get storage from ENV, as recommended by 99%, doesn't detect external SD card, only internal ?!\n     */\n    private static void getStorageEnv(@NonNull Context context, Map<String, Uri> storageLocations) {\n        final String rawSecondaryStorage = System.getenv(ENV_SECONDARY_STORAGE);\n        if (!TextUtils.isEmpty(rawSecondaryStorage)) {\n            //noinspection ConstantConditions\n            String[] externalCards = rawSecondaryStorage.split(\":\");\n            for (int i = 0; i < externalCards.length; i++) {\n                String path = externalCards[i];\n                addStorage(context.getString(R.string.sd_card) + (i == 0 ? \"\" : \" \" + i), Paths.get(path), storageLocations);\n            }\n        }\n    }\n\n    /**\n     * Get storage indirect, best solution so far\n     */\n    private static void getStorageExternalFilesDir(Context context, Map<String, Uri> storageLocations) {\n        // Get primary & secondary external device storage (internal storage & micro SDCARD slot...)\n        File[] listExternalDirs = ContextCompat.getExternalFilesDirs(context, null);\n        for (File listExternalDir : listExternalDirs) {\n            if (listExternalDir != null) {\n                String path = listExternalDir.getAbsolutePath();\n                int indexMountRoot = path.indexOf(\"/Android/data/\");\n                if (indexMountRoot >= 0) {\n                    // Get the root path for the external directory\n                    Path file = Paths.get(path.substring(0, indexMountRoot));\n                    addStorage(file.getName(), file, storageLocations);\n                }\n            }\n        }\n    }\n\n    /**\n     * Get storages via StorageManager\n     */\n    private static void retrieveStorageManager(Context context, Map<String, Uri> storageLocations) {\n        Set<StorageVolume> storageVolumes = new HashSet<>();\n        int[] users = Users.getUsersIds();\n        for (int user : users) {\n            try {\n                storageVolumes.addAll(Arrays.asList(StorageManagerCompat.getVolumeList(context, user, 0)));\n            } catch (SecurityException ignore) {\n            }\n        }\n        try {\n            for (@NonNull StorageVolume volume : storageVolumes) {\n                StorageVolumeHidden vol = Refine.unsafeCast(volume);\n                File dir = vol.getPathFile();\n                if (dir == null) continue;\n                String label = vol.getUserLabel();\n                addStorage(label == null ? dir.getName() : label, Paths.get(dir), storageLocations);\n            }\n            Log.d(TAG, \"used storagemanager\");\n        } catch (Exception e) {\n            Log.w(TAG, \"error during storage retrieval\", e);\n        }\n    }\n\n    /**\n     * Get storage via /proc/mounts, probably never works\n     */\n    private static void retrieveStorageFilesystem(Map<String, Uri> storageLocations) {\n        Path mountFile = Paths.get(\"/proc/mounts\");\n        if (!mountFile.isDirectory()) {\n            return;\n        }\n        try (BufferedReader reader = new BufferedReader(new PathReader(mountFile))) {\n            String line;\n            while ((line = reader.readLine()) != null) {\n                if (line.startsWith(\"/dev/block/vold/\")) {\n                    String[] lineElements = line.split(\" \");\n                    Path element = Paths.get(lineElements[1]);\n                    // Don't add the default mount path since it's already in the list.\n                    addStorage(element.getName(), element, storageLocations);\n                }\n            }\n        } catch (IOException ignore) {\n        }\n    }\n\n    @NonNull\n    private static Uri getFixedTreeUri(@NonNull Uri uri) {\n        List<String> paths = uri.getPathSegments();\n        int size = paths.size();\n        if (size < 2 || !\"tree\".equals(paths.get(0))) {\n            throw new IllegalArgumentException(\"Not a tree URI.\");\n        }\n        // FORMAT: /tree/<id>/document/<id>%2F<others>\n        switch (size) {\n            case 2:\n                return uri.buildUpon()\n                        .appendPath(\"document\")\n                        .appendPath(paths.get(1))\n                        .build();\n            case 3:\n                if (!\"document\".equals(paths.get(2))) {\n                    throw new IllegalArgumentException(\"Not a document URI.\");\n                }\n                return uri.buildUpon()\n                        .appendPath(paths.get(1))\n                        .build();\n            case 4:\n                if (!\"document\".equals(paths.get(2))) {\n                    throw new IllegalArgumentException(\"Not a document URI.\");\n                }\n                return uri;\n            default:\n                throw new IllegalArgumentException(\"Malformed URI.\");\n        }\n    }\n}"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/utils/TarUtils.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.utils;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.StringDef;\nimport androidx.annotation.VisibleForTesting;\nimport androidx.annotation.WorkerThread;\n\nimport com.github.luben.zstd.ZstdInputStream;\nimport com.github.luben.zstd.ZstdOutputStream;\n\nimport org.apache.commons.compress.archivers.tar.TarArchiveEntry;\nimport org.apache.commons.compress.archivers.tar.TarArchiveInputStream;\nimport org.apache.commons.compress.archivers.tar.TarArchiveOutputStream;\nimport org.apache.commons.compress.archivers.tar.TarConstants;\nimport org.apache.commons.compress.compressors.bzip2.BZip2CompressorInputStream;\nimport org.apache.commons.compress.compressors.bzip2.BZip2CompressorOutputStream;\nimport org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream;\nimport org.apache.commons.compress.compressors.gzip.GzipCompressorOutputStream;\nimport org.jetbrains.annotations.Contract;\n\nimport java.io.BufferedInputStream;\nimport java.io.BufferedOutputStream;\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.util.List;\nimport java.util.regex.Pattern;\n\nimport io.github.muntashirakon.io.IoUtils;\nimport io.github.muntashirakon.io.Path;\nimport io.github.muntashirakon.io.Paths;\nimport io.github.muntashirakon.io.SplitInputStream;\nimport io.github.muntashirakon.io.SplitOutputStream;\n\npublic final class TarUtils {\n    public static final long DEFAULT_SPLIT_SIZE = 1024 * 1024 * 1024;\n\n    @StringDef(value = {\n            TAR_GZIP,\n            TAR_BZIP2,\n            TAR_ZSTD,\n    })\n    @Retention(RetentionPolicy.SOURCE)\n    public @interface TarType {\n    }\n\n    public static final String TAR_GZIP = \"z\";\n    public static final String TAR_BZIP2 = \"j\";\n    public static final String TAR_ZSTD = \"s\";\n\n    /**\n     * Create a tar file using the given compression method and split it into multiple files based\n     * on the supplied split size.\n     *\n     * @param type           Compression type\n     * @param source         Source directory/file\n     * @param dest           Destination directory\n     * @param destFilePrefix filename as a prefix (.0, .1, etc. are added at the end)\n     * @param filters        A list of mutually exclusive regex filters\n     * @param splitSize      Size of the split, {@link #DEFAULT_SPLIT_SIZE} will be used if null is supplied\n     * @param exclude        A list of mutually exclusive regex patterns to be excluded\n     * @param followLinks    Whether to follow the links\n     * @return List of added files\n     */\n    @WorkerThread\n    @NonNull\n    public static List<Path> create(@NonNull @TarType String type, @NonNull Path source, @NonNull Path dest,\n                                    @NonNull String destFilePrefix, @Nullable String[] filters,\n                                    @Nullable Long splitSize, @Nullable String[] exclude, boolean followLinks)\n            throws IOException {\n        try (SplitOutputStream sos = new SplitOutputStream(dest, destFilePrefix, splitSize == null ? DEFAULT_SPLIT_SIZE : splitSize);\n             BufferedOutputStream bos = new BufferedOutputStream(sos);\n             OutputStream os = createCompressedStream(bos, type)) {\n            try (TarArchiveOutputStream tos = new TarArchiveOutputStream(os)) {\n                tos.setLongFileMode(TarArchiveOutputStream.LONGFILE_POSIX);\n                tos.setBigNumberMode(TarArchiveOutputStream.BIGNUMBER_POSIX);\n                Path basePath = source.isDirectory() ? source : source.getParent();\n                if (basePath == null) {\n                    basePath = Paths.get(\"/\");\n                }\n                List<Path> files = Paths.getAll(basePath, source, filters, exclude, followLinks);\n                for (Path file : files) {\n                    String relativePath = Paths.relativePath(file, basePath);\n                    if (relativePath.isEmpty() || relativePath.equals(\"/\")) continue;\n                    // For links, check if followLinks is enabled\n                    if (!followLinks && file.isSymbolicLink()) {\n                        // A path can be symbolic link only if it's a file\n                        // Add the link as is\n                        TarArchiveEntry tarEntry = new TarArchiveEntry(relativePath, TarConstants.LF_SYMLINK);\n                        tarEntry.setLinkName(file.getRealFilePath());\n                        tos.putArchiveEntry(tarEntry);\n                    } else {\n                        TarArchiveEntry tarEntry = new TarArchiveEntry(file, relativePath);\n                        tos.putArchiveEntry(tarEntry);\n                        if (!file.isDirectory()) {\n                            try (InputStream is = file.openInputStream()) {\n                                IoUtils.copy(is, tos);\n                            }\n                        }\n                    }\n                    tos.closeArchiveEntry();\n                }\n                tos.finish();\n            } finally {\n                os.close();\n            }\n            return sos.getFiles();\n        }\n    }\n\n    /**\n     * Create a tar file using the given compression method and split it into multiple files based\n     * on the supplied split size.\n     *\n     * @param type       Compression type\n     * @param sources    Source files, sorted properly if there are multiple files.\n     * @param dest       Destination directory\n     * @param filters    A list of mutually exclusive regex filters\n     * @param exclusions A list of mutually exclusive regex patterns to be excluded\n     */\n    @WorkerThread\n    public static void extract(@NonNull @TarType String type, @NonNull Path[] sources, @NonNull Path dest,\n                               @Nullable String[] filters, @Nullable String[] exclusions,\n                               @Nullable String realDataAppPath)\n            throws IOException {\n        // Convert filters into patterns to reduce overheads\n        Pattern[] filterPatterns;\n        if (filters != null) {\n            filterPatterns = new Pattern[filters.length];\n            for (int i = 0; i < filters.length; ++i) {\n                filterPatterns[i] = Pattern.compile(filters[i]);\n            }\n        } else filterPatterns = null;\n        Pattern[] exclusionPatterns;\n        if (exclusions != null) {\n            exclusionPatterns = new Pattern[exclusions.length];\n            for (int i = 0; i < exclusions.length; ++i) {\n                exclusionPatterns[i] = Pattern.compile(exclusions[i]);\n            }\n        } else exclusionPatterns = null;\n        // Run extraction\n        try (SplitInputStream sis = new SplitInputStream(sources);\n             BufferedInputStream bis = new BufferedInputStream(sis);\n             InputStream is = createDecompressedStream(bis, type)) {\n            try (TarArchiveInputStream tis = new TarArchiveInputStream(is)) {\n                String realDestPath = dest.getRealFilePath();\n                TarArchiveEntry entry;\n                while ((entry = tis.getNextEntry()) != null) {\n                    String filename = Paths.normalize(entry.getName());\n                    // Early zip slip vulnerability check to avoid creating any files at all\n                    if (filename == null || filename.startsWith(\"../\")) {\n                        throw new IOException(\"Zip slip vulnerability detected!\" +\n                                \"\\nExpected dest: \" + new File(realDestPath, entry.getName()) +\n                                \"\\nActual path: \" + (filename != null ? new File(realDestPath, filename) : realDestPath));\n                    }\n                    Path file;\n                    if (entry.isDirectory()) {\n                        file = dest.createDirectoriesIfRequired(filename);\n                    } else file = dest.createNewArbitraryFile(filename, null);\n                    if (!entry.isDirectory() && (!Paths.isUnderFilter(file, dest, filterPatterns)\n                            || Paths.willExclude(file, dest, exclusionPatterns))) {\n                        // Unlike create, there's no efficient way to detect if a directory contains any filters.\n                        // Therefore, directory can't be filtered during extraction\n                        file.delete();\n                        continue;\n                    }\n                    // Check if the given entry is a link.\n                    if (entry.isSymbolicLink() && file.getFilePath() != null) {\n                        if ((!Paths.isUnderFilter(file, dest, filterPatterns) || Paths.willExclude(file, dest, exclusionPatterns))) {\n                            // Do not create this link even if it is a directory\n                            continue;\n                        }\n                        String linkName = entry.getLinkName();\n                        // There's no need to check if the linkName exists as it may be extracted\n                        // after the link has been created\n                        // Special check for /data/app\n                        if (linkName.startsWith(\"/data/app/\")) {\n                            linkName = getAbsolutePathToDataApp(linkName, realDataAppPath);\n                        }\n                        file.delete();\n                        if (!file.createNewSymbolicLink(linkName)) {\n                            throw new IOException(\"Couldn't create symbolic link \" + file + \" pointing to \" + linkName);\n                        }\n                        continue;  // links do not need permission fixes\n                    } else {\n                        // Zip slip vulnerability might still be present\n                        String realFilePath = file.getRealFilePath();\n                        if (realDestPath != null && realFilePath != null && !realFilePath.startsWith(realDestPath)) {\n                            throw new IOException(\"Zip slip vulnerability detected!\" +\n                                    \"\\nExpected dest: \" + new File(realDestPath, entry.getName()) +\n                                    \"\\nActual path: \" + realFilePath);\n                        }\n                        if (!entry.isDirectory()) {\n                            try (OutputStream os = file.openOutputStream()) {\n                                IoUtils.copy(tis, os);\n                            }\n                        }\n                    }\n                    // Fix permissions\n                    TarArchiveEntry finalEntry = entry;\n                    ExUtils.exceptionAsIgnored(() -> Paths.setPermissions(file, finalEntry.getMode(),\n                            finalEntry.getUserId(), finalEntry.getGroupId()));\n                    // Restore timestamp\n                    long modificationTime = entry.getModTime().getTime();\n                    if (modificationTime > 0) { // Backward-compatibility\n                        file.setLastModified(entry.getModTime().getTime());\n                    }\n                }\n            } finally {\n                is.close();\n            }\n        }\n    }\n\n    @Contract(\"_, _ -> new\")\n    @NonNull\n    public static InputStream createDecompressedStream(@NonNull InputStream compressedStream,\n                                                        @NonNull @TarType String tarType)\n            throws IOException {\n        switch (tarType) {\n            case TAR_GZIP:\n                return new GzipCompressorInputStream(compressedStream, true);\n            case TAR_BZIP2:\n                return new BZip2CompressorInputStream(compressedStream, true);\n            case TAR_ZSTD:\n                return new ZstdInputStream(compressedStream);\n            default:\n                throw new IllegalArgumentException(\"Invalid compression type: \" + tarType);\n        }\n    }\n\n    @Contract(\"_, _ -> new\")\n    @NonNull\n    public static OutputStream createCompressedStream(@NonNull OutputStream regularStream,\n                                                       @NonNull @TarType String tarType)\n            throws IOException {\n        switch (tarType) {\n            case TAR_GZIP:\n                return new GzipCompressorOutputStream(regularStream);\n            case TAR_BZIP2:\n                return new BZip2CompressorOutputStream(regularStream);\n            case TAR_ZSTD:\n                return new ZstdOutputStream(regularStream);\n            default:\n                throw new IllegalArgumentException(\"Invalid compression type: \" + tarType);\n        }\n    }\n\n    @VisibleForTesting\n    @NonNull\n    static String getAbsolutePathToDataApp(@NonNull String brokenPath, @Nullable String realPath) {\n        brokenPath = brokenPath.endsWith(File.separator) ? brokenPath.substring(0, brokenPath.length() - 1) : brokenPath;\n        if (realPath == null) return brokenPath;\n        if (\"/data/app\".equals(brokenPath)) {\n            return brokenPath;\n        }\n        //noinspection SuspiciousRegexArgument\n        String[] brokenPathParts = brokenPath.split(File.separator);\n        // The initial number of File.separator is 4, and the rests could be either part of the app path or\n        // point to lib, oat or apk files\n        // Index 4-1 = 3 is always a link to app\n        if (brokenPathParts.length <= 4) {\n            return realPath;\n        }\n        if (\"lib\".equals(brokenPathParts[4]) || \"oat\".equals(brokenPathParts[4]) || brokenPathParts[4].endsWith(\".apk\")) {\n            StringBuilder sb = new StringBuilder(realPath);\n            for (int i = 4; i < brokenPathParts.length; ++i) {\n                sb.append(File.separator).append(brokenPathParts[i]);\n            }\n            return sb.toString();\n        }\n        // Index 5-1 = 4 is also a part of the app\n        if (brokenPathParts.length == 5) {\n            return realPath;\n        }\n        // Index 6-1 = 5 and later are currently not a part of the app\n        StringBuilder sb = new StringBuilder(realPath);\n        for (int i = 5; i < brokenPathParts.length; ++i) {\n            sb.append(File.separator).append(brokenPathParts[i]);\n        }\n        return sb.toString();\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/utils/TextUtilsCompat.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.utils;\n\nimport android.text.Spannable;\nimport android.text.SpannableString;\nimport android.text.SpannableStringBuilder;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport java.util.Iterator;\n\npublic class TextUtilsCompat {\n    /**\n     * Returns a string containing the tokens joined by delimiters.\n     *\n     * @param delimiter a CharSequence that will be inserted between the tokens. If null, the string\n     *                  \"null\" will be used as the delimiter.\n     * @param tokens    an array objects to be joined. Strings will be formed from the objects by\n     *                  calling object.toString() except CharSequence. If tokens is null, a\n     *                  NullPointerException will be thrown. If tokens is empty, an empty string\n     *                  will be returned.\n     */\n    @NonNull\n    public static Spannable joinSpannable(@NonNull CharSequence delimiter, @NonNull Iterable<?> tokens) {\n        final Iterator<?> it = tokens.iterator();\n        if (!it.hasNext()) {\n            return new SpannableString(\"\");\n        }\n        final SpannableStringBuilder sb = new SpannableStringBuilder();\n        Object object = it.next();\n        if (object instanceof CharSequence) {\n            sb.append((CharSequence) object);\n        } else sb.append(object.toString());\n        while (it.hasNext()) {\n            sb.append(delimiter);\n            object = it.next();\n            if (object instanceof CharSequence) {\n                sb.append((CharSequence) object);\n            } else sb.append(object.toString());\n        }\n        return sb;\n    }\n\n    /**\n     * @return interned string if it's not null.\n     */\n    @Nullable\n    public static String safeIntern(@Nullable String s) {\n        return (s != null) ? s.intern() : null;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/utils/ThreadUtils.java",
    "content": "// SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.utils;\n\nimport android.os.Handler;\nimport android.os.Looper;\n\nimport java.util.concurrent.Callable;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Future;\n\nimport io.github.muntashirakon.AppManager.logs.Log;\n\n// Copyright 2016 The Android Open Source Project\npublic class ThreadUtils {\n    private static volatile Thread sMainThread;\n    private static volatile Handler sMainThreadHandler;\n    private static volatile ExecutorService sThreadExecutor;\n\n    /**\n     * Returns true if the current thread is the UI thread.\n     */\n    public static boolean isMainThread() {\n        if (sMainThread == null) {\n            sMainThread = Looper.getMainLooper().getThread();\n        }\n        return Thread.currentThread() == sMainThread;\n    }\n\n    /**\n     * Returns a shared UI thread handler.\n     */\n    public static Handler getUiThreadHandler() {\n        if (sMainThreadHandler == null) {\n            sMainThreadHandler = new Handler(Looper.getMainLooper());\n        }\n\n        return sMainThreadHandler;\n    }\n\n    /**\n     * Checks that the current thread is the UI thread. Otherwise, throws an exception.\n     */\n    public static void ensureMainThread() {\n        if (!isMainThread()) {\n            throw new RuntimeException(\"Must be called on the UI thread\");\n        }\n    }\n\n    /**\n     * Checks that the current thread is a worker thread. Otherwise, throws an exception.\n     */\n    public static void ensureWorkerThread() {\n        if (isMainThread()) {\n            throw new RuntimeException(\"Must be called on a worker thread\");\n        }\n    }\n\n    /**\n     * Tests whether this thread has been interrupted. The <i>interrupted status</i> of the thread is unaffected by this\n     * method.\n     *\n     * <p>A thread interruption ignored because a thread was not alive at the time of the interrupt will be reflected by\n     * this method returning false.\n     *\n     * @return {@code true} if this thread has been interrupted; {@code false} otherwise.\n     */\n    public static boolean isInterrupted() {\n        boolean interrupted = Thread.currentThread().isInterrupted();\n        if (interrupted) {\n            Log.d(\"ThreadUtils\", \"Thread interrupted.\");\n        }\n        return interrupted;\n    }\n\n    /**\n     * Posts runnable in background using shared background thread pool.\n     *\n     * @return A future of the task that can be monitored for updates or cancelled.\n     */\n    public static Future<?> postOnBackgroundThread(Runnable runnable) {\n        return getBackgroundThreadExecutor().submit(runnable);\n    }\n\n    /**\n     * Posts callable in background using shared background thread pool.\n     *\n     * @return A future of the task that can be monitored for updates or cancelled.\n     */\n    public static <T> Future<T> postOnBackgroundThread(Callable<T> callable) {\n        return getBackgroundThreadExecutor().submit(callable);\n    }\n\n    /**\n     * Posts the runnable on the main thread.\n     */\n    public static void postOnMainThread(Runnable runnable) {\n        getUiThreadHandler().post(runnable);\n    }\n\n    /**\n     * Posts the runnable on the main thread with a delay.\n     */\n    public static void postOnMainThreadDelayed(Runnable runnable, long delayMillis) {\n        getUiThreadHandler().postDelayed(runnable, delayMillis);\n    }\n\n    public static synchronized ExecutorService getBackgroundThreadExecutor() {\n        if (sThreadExecutor == null) {\n            sThreadExecutor = MultithreadedExecutor.getNewInstance();\n        }\n        return sThreadExecutor;\n    }\n}"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/utils/UIUtils.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.utils;\n\nimport android.annotation.TargetApi;\nimport android.content.Context;\nimport android.graphics.Bitmap;\nimport android.graphics.Canvas;\nimport android.graphics.Color;\nimport android.graphics.ColorMatrix;\nimport android.graphics.ColorMatrixColorFilter;\nimport android.graphics.Paint;\nimport android.graphics.Rect;\nimport android.graphics.Typeface;\nimport android.graphics.drawable.BitmapDrawable;\nimport android.graphics.drawable.Drawable;\nimport android.os.Build;\nimport android.text.Spannable;\nimport android.text.SpannableStringBuilder;\nimport android.text.Spanned;\nimport android.text.TextPaint;\nimport android.text.TextUtils;\nimport android.text.style.AbsoluteSizeSpan;\nimport android.text.style.BackgroundColorSpan;\nimport android.text.style.ForegroundColorSpan;\nimport android.text.style.ImageSpan;\nimport android.text.style.RelativeSizeSpan;\nimport android.text.style.StyleSpan;\nimport android.text.style.TypefaceSpan;\nimport android.text.style.UnderlineSpan;\nimport android.util.TypedValue;\nimport android.view.ContextThemeWrapper;\nimport android.view.Gravity;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.TextView;\nimport android.widget.Toast;\n\nimport androidx.annotation.AnyThread;\nimport androidx.annotation.ColorInt;\nimport androidx.annotation.FloatRange;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.PluralsRes;\nimport androidx.annotation.Px;\nimport androidx.annotation.StringRes;\nimport androidx.annotation.UiThread;\nimport androidx.appcompat.app.ActionBar;\nimport androidx.appcompat.app.AlertDialog;\nimport androidx.fragment.app.FragmentActivity;\n\nimport com.google.android.material.color.MaterialColors;\nimport com.google.android.material.dialog.MaterialAlertDialogBuilder;\n\nimport java.util.Locale;\n\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.misc.AdvancedSearchView;\nimport io.github.muntashirakon.dialog.DialogTitleBuilder;\nimport io.github.muntashirakon.util.UiUtils;\nimport io.github.muntashirakon.view.AutoFitGridLayoutManager;\nimport io.github.muntashirakon.widget.SearchView;\n\npublic class UIUtils {\n    static final Spannable.Factory sSpannableFactory = Spannable.Factory.getInstance();\n\n    @NonNull\n    public static Spannable getHighlightedText(@NonNull String text, @Nullable String constraint,\n                                               @ColorInt int color) {\n        Spannable spannable = sSpannableFactory.newSpannable(text);\n        if (TextUtils.isEmpty(constraint)) {\n            return spannable;\n        }\n        int start = text.toLowerCase(Locale.ROOT).indexOf(constraint);\n        if (start == -1) return spannable;\n        int end = start + constraint.length();\n        if (end > text.length()) return spannable;\n        spannable.setSpan(new BackgroundColorSpan(color), start, end, Spannable.SPAN_INCLUSIVE_EXCLUSIVE);\n        return spannable;\n    }\n\n    @NonNull\n    public static Spannable getColoredText(@NonNull CharSequence text, int color) {\n        Spannable spannable = charSequenceToSpannable(text);\n        spannable.setSpan(new ForegroundColorSpan(color), 0, spannable.length(),\n                Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);\n        return spannable;\n    }\n\n    @NonNull\n    public static Spannable setTypefaceSpan(@NonNull CharSequence text, @NonNull String family) {\n        Spannable spannable = charSequenceToSpannable(text);\n        spannable.setSpan(new TypefaceSpan(family), 0, spannable.length(),\n                Spannable.SPAN_INCLUSIVE_EXCLUSIVE);\n        return spannable;\n    }\n\n    @NonNull\n    public static Spannable getMonospacedText(@NonNull CharSequence text) {\n        return setTypefaceSpan(text, \"monospace\");\n    }\n\n    @NonNull\n    public static Spannable getPrimaryText(@NonNull Context context, @NonNull CharSequence text) {\n        return getColoredText(setTypefaceSpan(text, \"sans-serif-medium\"), getTextColorPrimary(context));\n    }\n\n    @NonNull\n    public static Spannable getPrimaryText(@NonNull Context context, @StringRes int strRes) {\n        return getPrimaryText(context, context.getText(strRes));\n    }\n\n    @NonNull\n    public static Spannable getStyledKeyValue(@NonNull Context context, @StringRes int keyRes, CharSequence value,\n                                              CharSequence separator) {\n        return getStyledKeyValue(context, context.getText(keyRes), value, separator);\n    }\n\n    @NonNull\n    public static Spannable getStyledKeyValue(@NonNull Context context, @StringRes int keyRes, CharSequence value) {\n        return getStyledKeyValue(context, context.getText(keyRes), value);\n    }\n\n    @NonNull\n    public static Spannable getStyledKeyValue(@NonNull Context context, CharSequence key, CharSequence value) {\n        return getStyledKeyValue(context, key, value, LangUtils.getSeparatorString());\n    }\n\n    @NonNull\n    public static Spannable getStyledKeyValue(@NonNull Context context,\n                                              CharSequence key,\n                                              CharSequence value,\n                                              CharSequence separator) {\n        return new SpannableStringBuilder(getPrimaryText(context, new SpannableStringBuilder(key).append(separator)))\n                .append(value);\n    }\n\n    @NonNull\n    public static Spannable getSecondaryText(@NonNull Context context, @NonNull CharSequence text) {\n        return getColoredText(text, getTextColorSecondary(context));\n    }\n\n    @NonNull\n    public static Spannable getTitleText(Context context, @NonNull CharSequence text) {\n        Spannable spannable = charSequenceToSpannable(text);\n        spannable.setSpan(new AbsoluteSizeSpan(getTitleSize(context)), 0, spannable.length(),\n                Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);\n        return getPrimaryText(context, spannable);\n    }\n\n    @NonNull\n    public static Spannable getTitleText(Context context, @StringRes int strRes) {\n        return getTitleText(context, context.getText(strRes));\n    }\n\n    @NonNull\n    public static Spannable getSmallerText(@NonNull CharSequence text) {\n        Spannable spannable = charSequenceToSpannable(text);\n        spannable.setSpan(new RelativeSizeSpan(.8f), 0, spannable.length(),\n                Spanned.SPAN_INCLUSIVE_EXCLUSIVE);\n        return spannable;\n    }\n\n    @NonNull\n    public static Spannable getUnderlinedString(@NonNull CharSequence text) {\n        Spannable spannable = charSequenceToSpannable(text);\n        spannable.setSpan(new UnderlineSpan(), 0, spannable.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE);\n        return spannable;\n    }\n\n    @NonNull\n    public static Spannable getBoldString(@NonNull CharSequence text) {\n        Spannable spannable = charSequenceToSpannable(text);\n        spannable.setSpan(new StyleSpan(Typeface.BOLD), 0, spannable.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE);\n        return spannable;\n    }\n\n    @NonNull\n    public static Spannable getItalicString(@NonNull CharSequence text) {\n        Spannable ss = charSequenceToSpannable(text);\n        ss.setSpan(new StyleSpan(Typeface.ITALIC), 0, ss.length(), Spanned.SPAN_INCLUSIVE_EXCLUSIVE);\n        return ss;\n    }\n\n    @NonNull\n    public static Spannable setImageSpan(@NonNull CharSequence text, @Nullable Drawable image, @NonNull TextView tv) {\n        return setImageSpan(text, image, tv, 0, 1);\n    }\n\n    @NonNull\n    public static Spannable setImageSpan(@NonNull CharSequence text, @Nullable Drawable image, @NonNull TextView tv, int start) {\n        return setImageSpan(text, image, tv, start, start + 1);\n    }\n\n    @NonNull\n    public static Spannable setImageSpan(@NonNull CharSequence text, @Nullable Drawable image, @NonNull TextView tv, int start, int end) {\n        Spannable spannable = charSequenceToSpannable(text);\n        if (image == null) {\n            return spannable;\n        }\n        Paint textPaint = tv.getPaint();\n        Paint.FontMetricsInt fontMetrics = textPaint.getFontMetricsInt();\n        image.setBounds(0, fontMetrics.ascent, fontMetrics.bottom - fontMetrics.ascent, fontMetrics.bottom);\n        spannable.setSpan(new ImageSpan(image), start, end, Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);\n        return spannable;\n    }\n\n    @TargetApi(Build.VERSION_CODES.Q)\n    public static int getSystemColor(@NonNull Context context, int resAttrColor) { // Ex. android.R.attr.colorPrimary\n        TypedValue typedValue = new TypedValue();\n        ContextThemeWrapper contextThemeWrapper = new ContextThemeWrapper(context,\n                android.R.style.Theme_DeviceDefault_DayNight);\n        contextThemeWrapper.getTheme().resolveAttribute(resAttrColor, typedValue, true);\n        return typedValue.data;\n    }\n\n    public static int getTextColorPrimary(@NonNull Context context) {\n        return MaterialColors.getColor(context, com.google.android.material.R.attr.colorOnSurface, -1);\n    }\n\n    public static int getTextColorSecondary(@NonNull Context context) {\n        return MaterialColors.getColor(context, com.google.android.material.R.attr.colorOnSurfaceVariant, -1);\n    }\n\n    public static int getTitleSize(@NonNull Context context) {\n        return context.getResources().getDimensionPixelSize(R.dimen.title_font);\n    }\n\n    public static int getSubtitleSize(@NonNull Context context) {\n        return context.getResources().getDimensionPixelSize(R.dimen.subtitle_font);\n    }\n\n    @UiThread\n    @NonNull\n    public static View getDialogTitle(@NonNull FragmentActivity activity, @NonNull CharSequence title,\n                                      @Nullable Drawable drawable, @Nullable CharSequence subtitle) {\n        return new DialogTitleBuilder(activity).setTitle(title).setSubtitle(subtitle).setStartIcon(drawable).build();\n    }\n\n    @NonNull\n    public static AlertDialog getProgressDialog(@NonNull FragmentActivity activity, @Nullable CharSequence text, boolean circular) {\n        int layout = circular ? R.layout.dialog_progress_circular : R.layout.dialog_progress2;\n        View view = activity.getLayoutInflater().inflate(layout, null);\n        if (text != null) {\n            TextView tv = view.findViewById(android.R.id.text1);\n            tv.setText(text);\n        }\n        return new MaterialAlertDialogBuilder(activity)\n                .setCancelable(false)\n                .setView(view)\n                .create();\n    }\n\n    @NonNull\n    public static AlertDialog getProgressDialog(@NonNull FragmentActivity activity, @StringRes int text) {\n        View view = activity.getLayoutInflater().inflate(R.layout.dialog_progress2, null);\n        TextView tv = view.findViewById(android.R.id.text1);\n        tv.setText(text);\n        return new MaterialAlertDialogBuilder(activity)\n                .setCancelable(false)\n                .setView(view)\n                .create();\n    }\n\n    @NonNull\n    public static SearchView setupSearchView(@NonNull ActionBar actionBar,\n                                             @Nullable SearchView.OnQueryTextListener queryTextListener) {\n        SearchView searchView = new SearchView(actionBar.getThemedContext());\n        searchView.setId(R.id.action_search);\n        searchView.setOnQueryTextListener(queryTextListener);\n        // Set layout params\n        ActionBar.LayoutParams layoutParams = new ActionBar.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,\n                ViewGroup.LayoutParams.WRAP_CONTENT);\n        layoutParams.gravity = Gravity.END;\n        actionBar.setCustomView(searchView, layoutParams);\n        return searchView;\n    }\n\n    @NonNull\n    public static AdvancedSearchView setupAdvancedSearchView(@NonNull ActionBar actionBar,\n                                                             @Nullable AdvancedSearchView.OnQueryTextListener queryTextListener) {\n        AdvancedSearchView searchView = new AdvancedSearchView(actionBar.getThemedContext());\n        searchView.setId(R.id.action_search);\n        searchView.setOnQueryTextListener(queryTextListener);\n        // Set layout params\n        ActionBar.LayoutParams layoutParams = new ActionBar.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,\n                ViewGroup.LayoutParams.WRAP_CONTENT);\n        layoutParams.gravity = Gravity.END;\n        actionBar.setCustomView(searchView, layoutParams);\n        return searchView;\n    }\n\n    @UiThread\n    public static void displayShortToast(CharSequence message) {\n        Toast.makeText(ContextUtils.getContext(), message, Toast.LENGTH_SHORT).show();\n    }\n\n    @UiThread\n    public static void displayShortToast(String format, Object... args) {\n        Toast.makeText(ContextUtils.getContext(), String.format(Locale.getDefault(), format, args), Toast.LENGTH_SHORT).show();\n    }\n\n    @UiThread\n    public static void displayShortToast(@StringRes int res) {\n        Toast.makeText(ContextUtils.getContext(), res, Toast.LENGTH_SHORT).show();\n    }\n\n    @UiThread\n    public static void displayShortToast(@StringRes int res, Object... args) {\n        Context appContext = ContextUtils.getContext();\n        Toast.makeText(appContext, appContext.getString(res, args), Toast.LENGTH_SHORT).show();\n    }\n\n    @UiThread\n    public static void displayLongToast(CharSequence message) {\n        Toast.makeText(ContextUtils.getContext(), message, Toast.LENGTH_LONG).show();\n    }\n\n\n    @UiThread\n    public static void displayLongToast(String format, Object... args) {\n        Toast.makeText(ContextUtils.getContext(), String.format(Locale.getDefault(), format, args),\n                Toast.LENGTH_LONG).show();\n    }\n\n    @UiThread\n    public static void displayLongToast(@StringRes int res) {\n        Toast.makeText(ContextUtils.getContext(), res, Toast.LENGTH_LONG).show();\n    }\n\n    @UiThread\n    public static void displayLongToast(@StringRes int res, Object... args) {\n        Context appContext = ContextUtils.getContext();\n        Toast.makeText(appContext, appContext.getString(res, args), Toast.LENGTH_LONG).show();\n    }\n\n    @UiThread\n    public static void displayLongToastPl(@PluralsRes int res, int count, Object... args) {\n        Context appContext = ContextUtils.getContext();\n        Toast.makeText(appContext, appContext.getResources().getQuantityString(res, count, args), Toast.LENGTH_LONG).show();\n    }\n\n    @NonNull\n    public static AutoFitGridLayoutManager getGridLayoutAt450Dp(@NonNull Context context) {\n        return new AutoFitGridLayoutManager(context, UiUtils.dpToPx(context, 450));\n    }\n\n    @NonNull\n    public static Spannable charSequenceToSpannable(@NonNull CharSequence text) {\n        if (text instanceof Spannable) {\n            return (Spannable) text;\n        } else return sSpannableFactory.newSpannable(text);\n    }\n\n    @AnyThread\n    @NonNull\n    public static Bitmap getMutableBitmapFromDrawable(@NonNull Drawable drawable) {\n        if (drawable instanceof BitmapDrawable) {\n            Bitmap bitmap = ((BitmapDrawable) drawable).getBitmap();\n            return bitmap.copy(Bitmap.Config.ARGB_8888, true);\n        }\n        final Bitmap bmp = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);\n        final Canvas canvas = new Canvas(bmp);\n        drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());\n        drawable.draw(canvas);\n        return bmp;\n    }\n\n    @AnyThread\n    @NonNull\n    public static Bitmap getBitmapFromDrawable(@NonNull Drawable drawable) {\n        if (drawable instanceof BitmapDrawable) {\n            return ((BitmapDrawable) drawable).getBitmap();\n        }\n        final Bitmap bmp = Bitmap.createBitmap(drawable.getIntrinsicWidth(), drawable.getIntrinsicHeight(), Bitmap.Config.ARGB_8888);\n        final Canvas canvas = new Canvas(bmp);\n        drawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());\n        drawable.draw(canvas);\n        return bmp;\n    }\n\n    @AnyThread\n    @NonNull\n    public static Bitmap getBitmapFromDrawable(@NonNull Drawable drawable, @Px int padding) {\n        if (padding == 0) {\n            return getBitmapFromDrawable(drawable);\n        }\n        int width = drawable.getIntrinsicWidth() + 2 * padding;\n        int height = drawable.getIntrinsicHeight() + 2 * padding;\n        Bitmap bmp = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);\n        Canvas canvas = new Canvas(bmp);\n        drawable.setBounds(padding, padding, canvas.getWidth() - padding, canvas.getHeight() - padding);\n        drawable.draw(canvas);\n        return bmp;\n    }\n\n    @NonNull\n    public static Bitmap generateBitmapFromText(@NonNull String text, @Nullable Typeface typeface) {\n        int fontSize = 100;\n        TextPaint textPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG);\n        textPaint.setTextSize(fontSize);\n        textPaint.setColor(Color.WHITE);\n        textPaint.setTextAlign(Paint.Align.LEFT);\n        textPaint.setTypeface(typeface != null ? typeface : Typeface.SANS_SERIF);\n\n        Rect textRect = new Rect();\n        textPaint.getTextBounds(text, 0, text.length(), textRect);\n        int length = Math.max(textRect.width(), textRect.height()) + 80;\n        Bitmap bitmap = Bitmap.createBitmap(length, length, Bitmap.Config.ARGB_8888);\n\n        Canvas canvas = new Canvas(bitmap);\n        float x = canvas.getWidth() / 2f - textRect.width() / 2f - textRect.left;\n        float y = canvas.getHeight() / 2f + textRect.height() / 2f - textRect.bottom;\n        canvas.drawText(text, x, y, textPaint);\n        return bitmap;\n    }\n\n    public static Bitmap getDimmedBitmap(@NonNull Bitmap bitmap) {\n        Bitmap newBmp = bitmap.isMutable() ? bitmap : bitmap.copy(Bitmap.Config.ARGB_8888, true);\n        setBrightness(newBmp, -120f);\n        return newBmp;\n    }\n\n    public static void setBrightness(Bitmap bmp, @FloatRange(from = -255, to = 255) float brightness) {\n        assert bmp.isMutable();\n        ColorMatrix cm = new ColorMatrix(new float[]{\n                1, 0, 0, 0, brightness,\n                0, 1, 0, 0, brightness,\n                0, 0, 1, 0, brightness,\n                0, 0, 0, 1, 0\n        });\n        Canvas canvas = new Canvas(bmp);\n        Paint paint = new Paint();\n        paint.setColorFilter(new ColorMatrixColorFilter(cm));\n        canvas.drawBitmap(bmp, 0, 0, paint);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/utils/Utils.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.utils;\n\nimport static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_FOREGROUND;\nimport static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE;\n\nimport android.app.Activity;\nimport android.app.ActivityManager;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.pm.ActivityInfo;\nimport android.content.pm.ConfigurationInfo;\nimport android.content.pm.PackageInfo;\nimport android.content.pm.PackageManager;\nimport android.content.pm.PermissionInfo;\nimport android.content.pm.ServiceInfo;\nimport android.content.res.Configuration;\nimport android.net.ConnectivityManager;\nimport android.net.NetworkCapabilities;\nimport android.net.NetworkInfo;\nimport android.net.Uri;\nimport android.os.Build;\nimport android.os.UserHandleHidden;\nimport android.text.GetChars;\nimport android.text.TextUtils;\nimport android.util.Pair;\nimport android.view.View;\nimport android.view.WindowManager;\n\nimport androidx.annotation.CheckResult;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.StringRes;\nimport androidx.core.content.pm.PermissionInfoCompat;\nimport androidx.fragment.app.FragmentActivity;\n\nimport org.jetbrains.annotations.Contract;\n\nimport java.lang.reflect.Field;\nimport java.nio.ByteBuffer;\nimport java.nio.CharBuffer;\nimport java.nio.charset.StandardCharsets;\nimport java.security.cert.X509Certificate;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.Locale;\n\nimport aosp.libcore.util.EmptyArray;\nimport io.github.muntashirakon.AppManager.BuildConfig;\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.apk.signing.SignerInfo;\nimport io.github.muntashirakon.AppManager.compat.PackageManagerCompat;\nimport io.github.muntashirakon.AppManager.misc.OsEnvironment;\n\npublic class Utils {\n    public static final String TERMUX_LOGIN_PATH = OsEnvironment.getDataDirectoryRaw() + \"/data/com.termux/files/usr/bin/login\";\n\n    @NonNull\n    public static String camelCaseToSpaceSeparatedString(@NonNull String str) {\n        return TextUtils.join(\" \", splitByCharacterType(str, true)).replace(\" _\", \"\");\n    }\n\n\n    public static boolean containsOrHasInitials(@NonNull String query, @NonNull String str) {\n        query = query.toLowerCase(Locale.ROOT);\n        if (str.toLowerCase(Locale.ROOT).contains(query)) return true;\n        return getFirstLettersInLowerCase(camelCaseToSpaceSeparatedString(str)).contains(query);\n    }\n\n    @NonNull\n    public static String getFirstLettersInLowerCase(@NonNull String str) {\n        String[] strings = str.split(\"\\\\s\");\n        StringBuilder builder = new StringBuilder();\n        for (String s : strings) {\n            if (!s.isEmpty()) builder.append(s.charAt(0));\n        }\n        return builder.toString().toLowerCase(Locale.ROOT);\n    }\n\n    // https://github.com/apache/commons-lang/blob/master/src/main/java/org/apache/commons/lang3/StringUtils.java#L7514\n    @NonNull\n    public static String[] splitByCharacterType(@NonNull String str, boolean camelCase) {\n        if (str.isEmpty()) return EmptyArray.STRING;\n        char[] c = str.toCharArray();\n        List<String> list = new ArrayList<>();\n        int tokenStart = 0;\n        int currentType = Character.getType(c[tokenStart]);\n        for (int pos = tokenStart + 1; pos < c.length; pos++) {\n            int type = Character.getType(c[pos]);\n            if (type == currentType) {\n                continue;\n            }\n            if (camelCase && type == Character.LOWERCASE_LETTER && currentType == Character.UPPERCASE_LETTER) {\n                int newTokenStart = pos - 1;\n                if (newTokenStart != tokenStart) {\n                    list.add(new String(c, tokenStart, newTokenStart - tokenStart));\n                    tokenStart = newTokenStart;\n                }\n            } else {\n                list.add(new String(c, tokenStart, pos - tokenStart));\n                tokenStart = pos;\n            }\n            currentType = type;\n        }\n        list.add(new String(c, tokenStart, c.length - tokenStart));\n        return list.toArray(new String[0]);\n    }\n\n    @NonNull\n    public static String getLastComponent(@NonNull String str) {\n        try {\n            return str.substring(str.lastIndexOf('.') + 1);\n        } catch (Exception e) {\n            return str;\n        }\n    }\n\n    @StringRes\n    public static int getProcessStateName(@NonNull String shortName) {\n        switch (shortName) {\n            case \"R\":\n                return R.string.running;\n            case \"S\":\n                return R.string.state_sleeping;\n            case \"D\":\n                return R.string.state_device_io;\n            case \"T\":\n                return R.string.stopped;\n            case \"t\":\n                return R.string.state_trace_stop;\n            case \"x\":\n            case \"X\":\n                return R.string.state_dead;\n            case \"Z\":\n                return R.string.state_zombie;\n            case \"P\":\n                return R.string.state_parked;\n            case \"I\":\n                return R.string.state_idle;\n            case \"K\":\n                return R.string.state_wake_kill;\n            case \"W\":\n                return R.string.state_waking;\n            default:\n                return R.string.state_unknown;\n        }\n    }\n\n    @StringRes\n    public static int getProcessStateExtraName(String shortName) {\n        if (shortName == null) return R.string.empty;\n        switch (shortName) {\n            case \"<\":\n                return R.string.state_high_priority;\n            case \"N\":\n                return R.string.state_low_priority;\n            case \"L\":\n                return R.string.state_locked_memory;\n            case \"s\":\n                return R.string.state_session_leader;\n            case \"+\":\n                return R.string.state_foreground;\n            case \"l\":\n                return R.string.state_multithreaded;\n            default:\n                return R.string.state_unknown;\n        }\n    }\n\n    @StringRes\n    public static int getLaunchMode(int mode) {\n        switch (mode) {\n            case ActivityInfo.LAUNCH_MULTIPLE:\n                return R.string.launch_mode_multiple;\n            case ActivityInfo.LAUNCH_SINGLE_INSTANCE:\n                return R.string.launch_mode_single_instance;\n            case ActivityInfo.LAUNCH_SINGLE_TASK:\n                return R.string.launch_mode_single_task;\n            case ActivityInfo.LAUNCH_SINGLE_TOP:\n                return R.string.launch_mode_single_top;\n            default:\n                return R.string._null;\n        }\n    }\n\n    @StringRes\n    public static int getOrientationString(int orientation) {\n        switch (orientation) {\n            case ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED:\n                return R.string.orientation_unspecified;\n            case ActivityInfo.SCREEN_ORIENTATION_BEHIND:\n                return R.string.orientation_behind;\n            case ActivityInfo.SCREEN_ORIENTATION_FULL_SENSOR:\n                return R.string.orientation_full_sensor;\n            case ActivityInfo.SCREEN_ORIENTATION_FULL_USER:\n                return R.string.orientation_full_user;\n            case ActivityInfo.SCREEN_ORIENTATION_LOCKED:\n                return R.string.orientation_locked;\n            case ActivityInfo.SCREEN_ORIENTATION_NOSENSOR:\n                return R.string.orientation_no_sensor;\n            case ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE:\n                return R.string.orientation_landscape;\n            case ActivityInfo.SCREEN_ORIENTATION_PORTRAIT:\n                return R.string.orientation_portrait;\n            case ActivityInfo.SCREEN_ORIENTATION_REVERSE_PORTRAIT:\n                return R.string.orientation_reverse_portrait;\n            case ActivityInfo.SCREEN_ORIENTATION_REVERSE_LANDSCAPE:\n                return R.string.orientation_reverse_landscape;\n            case ActivityInfo.SCREEN_ORIENTATION_USER:\n                return R.string.orientation_user;\n            case ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE:\n                return R.string.orientation_sensor_landscape;\n            case ActivityInfo.SCREEN_ORIENTATION_SENSOR_PORTRAIT:\n                return R.string.orientation_sensor_portrait;\n            case ActivityInfo.SCREEN_ORIENTATION_SENSOR:\n                return R.string.orientation_sensor;\n            case ActivityInfo.SCREEN_ORIENTATION_USER_LANDSCAPE:\n                return R.string.orientation_user_landscape;\n            case ActivityInfo.SCREEN_ORIENTATION_USER_PORTRAIT:\n                return R.string.orientation_user_portrait;\n            default:\n                return R.string._null;\n        }\n    }\n\n    // FIXME: Translation support\n    @NonNull\n    public static String getSoftInputString(int flag) {\n        StringBuilder builder = new StringBuilder();\n        if ((flag & WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING) != 0)\n            builder.append(\"Adjust nothing, \");\n        if ((flag & WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN) != 0)\n            builder.append(\"Adjust pan, \");\n        if ((flag & WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE) != 0)\n            builder.append(\"Adjust resize, \");\n        if ((flag & WindowManager.LayoutParams.SOFT_INPUT_ADJUST_UNSPECIFIED) != 0)\n            builder.append(\"Adjust unspecified, \");\n        if ((flag & WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_HIDDEN) != 0)\n            builder.append(\"Always hidden, \");\n        if ((flag & WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE) != 0)\n            builder.append(\"Always visible, \");\n        if ((flag & WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN) != 0)\n            builder.append(\"Hidden, \");\n        if ((flag & WindowManager.LayoutParams.SOFT_INPUT_STATE_VISIBLE) != 0)\n            builder.append(\"Visible, \");\n        if ((flag & WindowManager.LayoutParams.SOFT_INPUT_STATE_UNCHANGED) != 0)\n            builder.append(\"Unchanged, \");\n        if ((flag & WindowManager.LayoutParams.SOFT_INPUT_STATE_UNSPECIFIED) != 0)\n            builder.append(\"Unspecified, \");\n        if ((flag & WindowManager.LayoutParams.SOFT_INPUT_IS_FORWARD_NAVIGATION) != 0)\n            builder.append(\"ForwardNav, \");\n        if ((flag & WindowManager.LayoutParams.SOFT_INPUT_MASK_ADJUST) != 0)\n            builder.append(\"Mask adjust, \");\n        if ((flag & WindowManager.LayoutParams.SOFT_INPUT_MASK_STATE) != 0)\n            builder.append(\"Mask state, \");\n        if ((flag & WindowManager.LayoutParams.SOFT_INPUT_MODE_CHANGED) != 0)\n            builder.append(\"Mode changed, \");\n        checkStringBuilderEnd(builder);\n        String result = builder.toString();\n        return result.isEmpty() ? \"null\" : result;\n    }\n\n    // FIXME Add translation support\n    @NonNull\n    public static CharSequence getServiceFlagsString(int flag) {\n        StringBuilder builder = new StringBuilder();\n        if ((flag & ServiceInfo.FLAG_STOP_WITH_TASK) != 0)\n            builder.append(\"Stop with task, \");\n        if ((flag & ServiceInfo.FLAG_ISOLATED_PROCESS) != 0)\n            builder.append(\"Isolated process, \");\n\n        if ((flag & ServiceInfo.FLAG_SINGLE_USER) != 0)\n            builder.append(\"Single user, \");\n\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {\n            if ((flag & ServiceInfo.FLAG_EXTERNAL_SERVICE) != 0)\n                builder.append(\"External service, \");\n\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {\n                if ((flag & ServiceInfo.FLAG_USE_APP_ZYGOTE) != 0)\n                    builder.append(\"Use app zygote, \");\n            }\n        }\n        checkStringBuilderEnd(builder);\n        String result = builder.toString();\n        return TextUtils.isEmpty(result) ? \"\" : (\"⚑ \" + result);\n    }\n\n    // FIXME Add translation support\n    @NonNull\n    public static String getActivitiesFlagsString(int flag) {\n        StringBuilder builder = new StringBuilder();\n        if ((flag & ActivityInfo.FLAG_ALLOW_TASK_REPARENTING) != 0)\n            builder.append(\"AllowReparenting, \");\n        if ((flag & ActivityInfo.FLAG_ALWAYS_RETAIN_TASK_STATE) != 0)\n            builder.append(\"AlwaysRetain, \");\n        if ((flag & ActivityInfo.FLAG_AUTO_REMOVE_FROM_RECENTS) != 0)\n            builder.append(\"AutoRemove, \");\n        if ((flag & ActivityInfo.FLAG_CLEAR_TASK_ON_LAUNCH) != 0)\n            builder.append(\"ClearOnLaunch, \");\n        if ((flag & ActivityInfo.FLAG_ENABLE_VR_MODE) != 0)\n            builder.append(\"EnableVR, \");\n        if ((flag & ActivityInfo.FLAG_EXCLUDE_FROM_RECENTS) != 0)\n            builder.append(\"ExcludeRecent, \");\n        if ((flag & ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS) != 0)\n            builder.append(\"FinishCloseDialogs, \");\n        if ((flag & ActivityInfo.FLAG_FINISH_ON_TASK_LAUNCH) != 0)\n            builder.append(\"FinishLaunch, \");\n        if ((flag & ActivityInfo.FLAG_HARDWARE_ACCELERATED) != 0)\n            builder.append(\"HardwareAccel, \");\n        if ((flag & ActivityInfo.FLAG_IMMERSIVE) != 0)\n            builder.append(\"Immersive, \");\n        if ((flag & ActivityInfo.FLAG_MULTIPROCESS) != 0)\n            builder.append(\"Multiprocess, \");\n        if ((flag & ActivityInfo.FLAG_NO_HISTORY) != 0)\n            builder.append(\"NoHistory, \");\n        if ((flag & ActivityInfo.FLAG_RELINQUISH_TASK_IDENTITY) != 0)\n            builder.append(\"RelinquishIdentity, \");\n        if ((flag & ActivityInfo.FLAG_RESUME_WHILE_PAUSING) != 0)\n            builder.append(\"Resume, \");\n        if ((flag & ActivityInfo.FLAG_SINGLE_USER) != 0)\n            builder.append(\"Single, \");\n        if ((flag & ActivityInfo.FLAG_STATE_NOT_NEEDED) != 0)\n            builder.append(\"NotNeeded, \");\n        checkStringBuilderEnd(builder);\n        String result = builder.toString();\n        return result.isEmpty() ? \"⚐\" : \"⚑ \" + result;\n    }\n\n    // FIXME Add translation support\n    @NonNull\n    public static String getProtectionLevelString(PermissionInfo permissionInfo) {\n        int basePermissionType = PermissionInfoCompat.getProtection(permissionInfo);\n        int permissionFlags = PermissionInfoCompat.getProtectionFlags(permissionInfo);\n        String protectionLevel = \"????\";\n        switch (basePermissionType) {\n            case PermissionInfo.PROTECTION_DANGEROUS:\n                protectionLevel = \"dangerous\";\n                break;\n            case PermissionInfo.PROTECTION_NORMAL:\n                protectionLevel = \"normal\";\n                break;\n            case PermissionInfo.PROTECTION_SIGNATURE:\n                protectionLevel = \"signature\";\n                break;\n            case PermissionInfo.PROTECTION_SIGNATURE_OR_SYSTEM:\n            case PermissionInfo.PROTECTION_SIGNATURE | PermissionInfo.PROTECTION_FLAG_PRIVILEGED:\n                protectionLevel = \"signatureOrPrivileged\";\n                break;\n        }\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {\n            if ((permissionFlags & PermissionInfo.PROTECTION_FLAG_PRIVILEGED) != 0)\n                protectionLevel += \"|privileged\";\n            if ((permissionFlags & PermissionInfo.PROTECTION_FLAG_PRE23) != 0)\n                protectionLevel += \"|pre23\";  // pre marshmallow\n            if ((permissionFlags & PermissionInfo.PROTECTION_FLAG_INSTALLER) != 0)\n                protectionLevel += \"|installer\";\n            if ((permissionFlags & PermissionInfo.PROTECTION_FLAG_VERIFIER) != 0)\n                protectionLevel += \"|verifier\";\n            if ((permissionFlags & PermissionInfo.PROTECTION_FLAG_PREINSTALLED) != 0)\n                protectionLevel += \"|preinstalled\";\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {\n                if ((permissionFlags & PermissionInfo.PROTECTION_FLAG_SETUP) != 0)\n                    protectionLevel += \"|setup\";\n            }\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {\n                if ((permissionFlags & PermissionInfo.PROTECTION_FLAG_RUNTIME_ONLY) != 0)\n                    protectionLevel += \"|runtime\";\n            }\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O_MR1) {\n                if ((permissionFlags & PermissionInfo.PROTECTION_FLAG_INSTANT) != 0)\n                    protectionLevel += \"|instant\";\n            }\n        } else {\n            if ((permissionFlags & PermissionInfo.PROTECTION_FLAG_SYSTEM) != 0) {\n                protectionLevel += \"|system\";\n            }\n        }\n\n        if ((permissionFlags & PermissionInfo.PROTECTION_FLAG_DEVELOPMENT) != 0) {\n            protectionLevel += \"|development\";\n        }\n        if ((permissionFlags & PermissionInfo.PROTECTION_FLAG_APPOP) != 0) {\n            protectionLevel += \"|appop\";\n        }\n        return protectionLevel;\n    }\n\n    // FIXME Add translation support\n    @NonNull\n    public static String getInputFeaturesString(int flag) {\n        String string = \"\";\n        if ((flag & ConfigurationInfo.INPUT_FEATURE_FIVE_WAY_NAV) != 0)\n            string += \"Five way nav\";\n        if ((flag & ConfigurationInfo.INPUT_FEATURE_HARD_KEYBOARD) != 0)\n            string += (string.isEmpty() ? \"\" : \"|\") + \"Hard keyboard\";\n        return string.isEmpty() ? \"null\" : string;\n    }\n\n    @StringRes\n    public static int getKeyboardType(int KbType) {\n        switch (KbType) {\n            case Configuration.KEYBOARD_NOKEYS:\n                return R.string.keyboard_no_keys;\n            case Configuration.KEYBOARD_QWERTY:\n                return R.string.keyboard_qwerty;\n            case Configuration.KEYBOARD_12KEY:\n                return R.string.keyboard_12_keys;\n            case Configuration.KEYBOARD_UNDEFINED:\n            default:\n                return R.string._undefined;\n        }\n    }\n\n    @StringRes\n    public static int getNavigation(int navId) {\n        switch (navId) {\n            case Configuration.NAVIGATION_NONAV:\n                return R.string.navigation_no_nav;\n            case Configuration.NAVIGATION_DPAD:\n                return R.string.navigation_dial_pad;\n            case Configuration.NAVIGATION_TRACKBALL:\n                return R.string.navigation_trackball;\n            case Configuration.NAVIGATION_WHEEL:\n                return R.string.navigation_wheel;\n            case Configuration.NAVIGATION_UNDEFINED:\n            default:\n                return R.string._undefined;\n        }\n    }\n\n    @StringRes\n    public static int getTouchScreen(int touchId) {\n        switch (touchId) {\n            case Configuration.TOUCHSCREEN_NOTOUCH:\n                return R.string.touchscreen_no_touch;\n            case 2:  // Configuration.TOUCHSCREEN_STYLUS\n                return R.string.touchscreen_stylus;\n            case Configuration.TOUCHSCREEN_FINGER:\n                return R.string.touchscreen_finger;\n            case Configuration.TOUCHSCREEN_UNDEFINED:\n            default:\n                return R.string._undefined;\n        }\n    }\n\n    public static void checkStringBuilderEnd(@NonNull StringBuilder builder) {\n        int length = builder.length();\n        if (length > 2) builder.delete(length - 2, length);\n    }\n\n    @NonNull\n    public static String getGlEsVersion(int reqGlEsVersion) {\n        int major = ((reqGlEsVersion & 0xffff0000) >> 16);\n        int minor = reqGlEsVersion & 0x0000ffff;\n        return major + \".\" + minor;\n    }\n\n    @Nullable\n    public static String getVulkanVersion(PackageManager pm) {\n        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {\n            return null;\n        }\n        // https://cs.android.com/android/platform/superproject/main/+/main:frameworks/base/core/java/android/os/GraphicsEnvironment.java;l=193;drc=f80e786d308318894be30d54b93f38034496fc66\n        if (pm.hasSystemFeature(PackageManager.FEATURE_VULKAN_HARDWARE_VERSION, 0x00403000)) {\n            return \"1.3\";\n        }\n        if (pm.hasSystemFeature(PackageManager.FEATURE_VULKAN_HARDWARE_VERSION, 0x00402000)) {\n            return \"1.2\";\n        }\n        if (pm.hasSystemFeature(PackageManager.FEATURE_VULKAN_HARDWARE_VERSION, 0x00401000)) {\n            return \"1.1\";\n        }\n        if (pm.hasSystemFeature(PackageManager.FEATURE_VULKAN_HARDWARE_VERSION, 0x00400000)) {\n            return \"1.0\";\n        }\n        return null;\n    }\n\n    @CheckResult\n    @NonNull\n    public static byte[] charsToBytes(@NonNull char[] chars) {\n        final ByteBuffer byteBuffer = StandardCharsets.UTF_8.encode(CharBuffer.wrap(chars));\n        byte[] bytes = Arrays.copyOf(byteBuffer.array(), byteBuffer.limit());\n        clearBytes(byteBuffer.array());\n        return bytes;\n    }\n\n    @Nullable\n    public static char[] getChars(@Nullable GetChars getChars) {\n        if (TextUtils.isEmpty(getChars)) return null;\n        @SuppressWarnings(\"ConstantConditions\")\n        char[] chars = new char[getChars.length()];\n        getChars.getChars(0, chars.length, chars, 0);\n        return chars;\n    }\n\n    @CheckResult\n    @NonNull\n    public static char[] bytesToChars(@NonNull byte[] bytes) {\n        final CharBuffer charBuffer = StandardCharsets.UTF_8.decode(ByteBuffer.wrap(bytes));\n        char[] chars = Arrays.copyOf(charBuffer.array(), charBuffer.limit());\n        clearChars(charBuffer.array());\n        return chars;\n    }\n\n    public static void clearBytes(@NonNull byte[] bytes) {\n        Arrays.fill(bytes, (byte) 0);\n    }\n\n    public static void clearChars(@NonNull char[] chars) {\n        Arrays.fill(chars, '\\u0000');\n    }\n\n    @NonNull\n    public static Pair<String, String> getIssuerAndAlg(@NonNull PackageInfo p) {\n        SignerInfo signerInfo = PackageUtils.getSignerInfo(p, false);\n        if (signerInfo != null) {\n            X509Certificate[] certs = signerInfo.getCurrentSignerCerts();\n            if (certs != null && certs.length > 0) {\n                X509Certificate c = certs[0];\n                return new Pair<>(c.getIssuerX500Principal().getName(), c.getSigAlgName());\n            }\n        }\n        return new Pair<>(\"\", \"\");\n    }\n\n    /**\n     * Replace the first occurrence of matched string\n     *\n     * @param text         The text where the operation will be carried out\n     * @param searchString The string to replace\n     * @param replacement  The string that takes in place of the search string\n     * @return The modified string\n     */\n    // Similar impl. of https://commons.apache.org/proper/commons-lang/apidocs/src-html/org/apache/commons/lang3/StringUtils.html#line.6418\n    @NonNull\n    public static String replaceOnce(@NonNull String text, @NonNull CharSequence searchString, @NonNull CharSequence replacement) {\n        if (TextUtils.isEmpty(text) || TextUtils.isEmpty(searchString)) {\n            return text;\n        }\n        int start = 0;\n        final int end = TextUtils.indexOf(text, searchString, start);\n        if (end == -1) {\n            return text;\n        }\n        final int replLength = searchString.length();\n        final int increase = Math.max(replacement.length() - replLength, 0);\n        final StringBuilder buf = new StringBuilder(text.length() + increase);\n        buf.append(text, start, end).append(replacement);\n        start = end + replLength;\n        buf.append(text, start, text.length());\n        return buf.toString();\n    }\n\n    @Contract(\"null,_,_ -> fail\")\n    public static int getIntegerFromString(@Nullable CharSequence needle,\n                                           @NonNull List<CharSequence> stringsToMatch,\n                                           @NonNull List<Integer> associatedIntegers)\n            throws IllegalArgumentException {\n        if (needle == null) throw new IllegalArgumentException(\"Needle cannot be null\");\n        if (stringsToMatch.size() != associatedIntegers.size()) {\n            throw new IllegalArgumentException(\"String and integer arrays have different sizes\");\n        }\n        CharSequence trimmedNeedle = needle.toString().trim();\n        int index = stringsToMatch.indexOf(trimmedNeedle);\n        if (index == -1) {\n            // Might be a numeric value\n            return Integer.parseInt(trimmedNeedle.toString());\n        } else {\n            return associatedIntegers.get(index);\n        }\n    }\n\n    public static boolean isTv(@NonNull Context context) {\n        return context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_LEANBACK);\n    }\n\n    public static boolean canDisplayNotification(@NonNull Context context) {\n        // Notifications can be displayed in all supported devices except Android TV (O+)\n        return Build.VERSION.SDK_INT < Build.VERSION_CODES.O || !isTv(context);\n    }\n\n    public static boolean isAppInForeground() {\n        ActivityManager.RunningAppProcessInfo appProcessInfo = new ActivityManager.RunningAppProcessInfo();\n        ActivityManager.getMyMemoryState(appProcessInfo);\n        return (appProcessInfo.importance == IMPORTANCE_FOREGROUND || appProcessInfo.importance == IMPORTANCE_VISIBLE);\n    }\n\n    public static int getTotalCores() {\n        return Runtime.getRuntime().availableProcessors();\n    }\n\n    public static void copyToClipboard(@NonNull Context context, @Nullable CharSequence label, @NonNull CharSequence text) {\n        ClipboardUtils.copyToClipboard(context, label, text.toString());\n        UIUtils.displayShortToast(R.string.copied_to_clipboard);\n    }\n\n    @Nullable\n    public static View.OnClickListener openAsFolderInFM(@NonNull Context context, @Nullable String dir) {\n        if (dir == null) return null;\n        return view -> {\n            Intent openFile = new Intent(Intent.ACTION_VIEW);\n            openFile.setDataAndType(Uri.parse(dir), \"resource/folder\");\n            openFile.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);\n            if (openFile.resolveActivityInfo(context.getPackageManager(), 0) != null)\n                context.startActivity(openFile);\n        };\n    }\n\n    public static void relaunchApp(@NonNull FragmentActivity activity) {\n        Intent intent = PackageManagerCompat.getLaunchIntentForPackage(activity.getPackageName(), UserHandleHidden.myUserId());\n        if (intent == null) {\n            // No launch intent\n            return;\n        }\n        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_CLEAR_TASK);\n        activity.startActivity(intent);\n        activity.finish();\n    }\n\n    @Nullable\n    public static String getRealReferrer(@NonNull Activity activity) {\n        String callingPackage = activity.getCallingPackage();\n        if (callingPackage != null && !BuildConfig.APPLICATION_ID.equals(callingPackage)) {\n            return callingPackage;\n        }\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP_MR1) {\n            Intent intent = activity.getIntent();\n            intent.removeExtra(Intent.EXTRA_REFERRER_NAME);\n            intent.removeExtra(Intent.EXTRA_REFERRER);\n            // Now that the custom referrers are removed, it should return the real referrer.\n            // android-app:authority\n            Uri referrer = activity.getReferrer();\n            return referrer != null ? referrer.getAuthority() : null;\n        }\n        return null;\n    }\n\n    public static boolean isWifiActive(@NonNull Context context) {\n        ConnectivityManager cm = (ConnectivityManager) context.getSystemService(Context.CONNECTIVITY_SERVICE);\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {\n            NetworkCapabilities capabilities = cm.getNetworkCapabilities(cm.getActiveNetwork());\n            return capabilities != null && capabilities.hasTransport(NetworkCapabilities.TRANSPORT_WIFI);\n        }\n        NetworkInfo info = cm.getActiveNetworkInfo();\n        return info != null && info.getType() == ConnectivityManager.TYPE_WIFI;\n    }\n\n    @NonNull\n    public static <T> String prettyPrintObject(@Nullable T obj) {\n        if (obj == null) {\n            return \"null\";\n        }\n        StringBuilder sb = new StringBuilder();\n        Class<?> clazz = obj.getClass();\n        sb.append(clazz.getSimpleName()).append(\"{\");\n        Field[] fields = clazz.getDeclaredFields();\n        for (int i = 0; i < fields.length; i++) {\n            Field field = fields[i];\n            field.setAccessible(true);\n            sb.append(field.getName()).append(\"=\");\n            try {\n                Object value = field.get(obj);\n                sb.append(value);\n            } catch (IllegalAccessException e) {\n                sb.append(\"N/A\");\n            }\n            if (i < fields.length - 1) {\n                sb.append(\", \");\n            }\n        }\n        sb.append(\"}\");\n        return sb.toString();\n    }\n\n\n    public static boolean isRoboUnitTest() {\n        return \"robolectric\".equals(Build.FINGERPRINT);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/utils/appearance/AppearanceUtils.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.utils.appearance;\n\nimport android.annotation.SuppressLint;\nimport android.app.Activity;\nimport android.app.Application;\nimport android.app.UiModeManager;\nimport android.content.ComponentCallbacks2;\nimport android.content.Context;\nimport android.content.ContextWrapper;\nimport android.content.res.Configuration;\nimport android.content.res.Resources;\nimport android.os.Build;\nimport android.os.Bundle;\nimport android.os.LocaleList;\nimport android.os.PowerManager;\nimport android.view.ContextThemeWrapper;\nimport android.view.View;\nimport android.view.Window;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.RequiresApi;\nimport androidx.appcompat.app.AppCompatDelegate;\nimport androidx.appcompat.app.PublicTwilightManager;\nimport androidx.collection.ArrayMap;\nimport androidx.core.app.ActivityCompat;\nimport androidx.core.view.WindowCompat;\n\nimport com.google.android.material.color.DynamicColors;\n\nimport java.lang.ref.WeakReference;\nimport java.util.LinkedHashSet;\nimport java.util.Locale;\n\nimport io.github.muntashirakon.AppManager.PerProcessActivity;\nimport io.github.muntashirakon.AppManager.settings.Prefs;\nimport io.github.muntashirakon.AppManager.utils.LangUtils;\n\npublic final class AppearanceUtils {\n    public static final String TAG = AppearanceUtils.class.getSimpleName();\n\n    private static final ArrayMap<Integer, WeakReference<Activity>> sActivityReferences = new ArrayMap<>();\n\n    private static class AppearanceOptions {\n        public Locale locale;\n        public Integer layoutDirection;\n        public Integer theme;\n        public Integer nightMode;\n    }\n\n    public static void applyOnlyLocale(@NonNull Context context) {\n        // Update locale and layout direction for the application\n        AppearanceOptions options = new AppearanceOptions();\n        options.locale = LangUtils.getFromPreference(context);\n        options.layoutDirection = Prefs.Appearance.getLayoutDirection();\n        updateConfiguration(context, options);\n        if (!context.equals(context.getApplicationContext())) {\n            updateConfiguration(context.getApplicationContext(), options);\n        }\n    }\n\n    /**\n     * Return a {@link ContextThemeWrapper} with the default locale, layout direction, theme and night mode.\n     */\n    @NonNull\n    public static Context getThemedContext(@NonNull Context context, boolean transparent) {\n        AppearanceOptions options = new AppearanceOptions();\n        options.locale = LangUtils.getFromPreference(context);\n        options.layoutDirection = Prefs.Appearance.getLayoutDirection();\n        options.theme = transparent ? Prefs.Appearance.getTransparentAppTheme() : Prefs.Appearance.getAppTheme();\n        options.nightMode = Prefs.Appearance.getNightMode();\n        ContextThemeWrapper newCtx = new ContextThemeWrapper(context, options.theme);\n        newCtx.applyOverrideConfiguration(createOverrideConfiguration(context, options));\n        return DynamicColors.wrapContextIfAvailable(newCtx);\n    }\n\n    /**\n     * Return a {@link ContextThemeWrapper} with the default locale, layout direction, theme and night mode.\n     */\n    @NonNull\n    public static Context getThemedWidgetContext(@NonNull Context context, boolean transparent) {\n        int theme = transparent ? Prefs.Appearance.getTransparentAppTheme() : Prefs.Appearance.getAppTheme();\n        ContextThemeWrapper newCtx = new ContextThemeWrapper(context, theme);\n        return DynamicColors.wrapContextIfAvailable(newCtx);\n    }\n\n    /**\n     * Return a {@link ContextWrapper} with system configuration. This is helpful when it is necessary to access system\n     * configurations instead of the one used in the app.\n     */\n    @NonNull\n    public static Context getSystemContext(@NonNull Context context) {\n        Resources res = Resources.getSystem();\n        Configuration configuration = res.getConfiguration();\n        return new ContextWrapper(context.createConfigurationContext(configuration));\n    }\n\n    /**\n     * Initialize appearance in the app. Must be called from {@link Application#onCreate()}.\n     */\n    public static void init(@NonNull Application application) {\n        application.registerActivityLifecycleCallbacks(new ActivityAppearanceCallback());\n        application.registerComponentCallbacks(new ComponentAppearanceCallback(application));\n        applyOnlyLocale(application);\n        if (Prefs.Appearance.useSystemFont()) {\n            TypefaceUtil.replaceFontsWithSystem(application);\n        }\n    }\n\n    /**\n     * This is similar to what the delegate methods such as {@link AppCompatDelegate#setDefaultNightMode(int)} does.\n     * This is required because simply calling {@link ActivityCompat#recreate(Activity)} cannot apply the changes to\n     * all the active activities.\n     */\n    public static void applyConfigurationChangesToActivities() {\n        for (WeakReference<Activity> activityRef : sActivityReferences.values()) {\n            Activity activity = activityRef.get();\n            if (activity != null) {\n                ActivityCompat.recreate(activity);\n            }\n        }\n    }\n\n    private static class ActivityAppearanceCallback implements Application.ActivityLifecycleCallbacks {\n        @Override\n        public void onActivityPreCreated(@NonNull Activity activity, @Nullable Bundle savedInstanceState) {\n            if (activity instanceof PerProcessActivity) {\n                boolean transparentBackground = ((PerProcessActivity) activity).getTransparentBackground();\n                activity.setTheme(transparentBackground\n                        ? Prefs.Appearance.getTransparentAppTheme()\n                        : Prefs.Appearance.getAppTheme());\n            }\n            // Theme must be set first because the method below will add dynamic attributes to the theme\n            DynamicColors.applyToActivityIfAvailable(activity);\n        }\n\n        @Override\n        public void onActivityCreated(@NonNull Activity activity, @Nullable Bundle savedInstanceState) {\n            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {\n                onActivityPreCreated(activity, savedInstanceState);\n            }\n            Window window = activity.getWindow();\n            WindowCompat.setDecorFitsSystemWindows(window, false);\n            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {\n                onActivityPostCreated(activity, savedInstanceState);\n            }\n        }\n\n        @Override\n        public void onActivityPostCreated(@NonNull Activity activity, @Nullable Bundle savedInstanceState) {\n            applyOnlyLocale(activity);\n            AppCompatDelegate.setDefaultNightMode(Prefs.Appearance.getNightMode());\n\n            sActivityReferences.put(activity.hashCode(), new WeakReference<>(activity));\n        }\n\n        @Override\n        public void onActivityStarted(@NonNull Activity activity) {\n        }\n\n        @Override\n        public void onActivityResumed(@NonNull Activity activity) {\n        }\n\n        @Override\n        public void onActivityPaused(@NonNull Activity activity) {\n        }\n\n        @Override\n        public void onActivityStopped(@NonNull Activity activity) {\n        }\n\n        @Override\n        public void onActivitySaveInstanceState(@NonNull Activity activity, @NonNull Bundle outState) {\n        }\n\n        @Override\n        public void onActivityPreDestroyed(@NonNull Activity activity) {\n            sActivityReferences.remove(activity.hashCode());\n        }\n\n        @Override\n        public void onActivityDestroyed(@NonNull Activity activity) {\n            if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {\n                onActivityPreDestroyed(activity);\n            }\n        }\n    }\n\n    private static class ComponentAppearanceCallback implements ComponentCallbacks2 {\n        private final Application mApplication;\n\n        public ComponentAppearanceCallback(@NonNull Application application) {\n            mApplication = application;\n        }\n\n        @Override\n        public void onConfigurationChanged(@NonNull Configuration newConfig) {\n            applyOnlyLocale(mApplication);\n        }\n\n        @Override\n        public void onLowMemory() {\n        }\n\n        @Override\n        public void onTrimMemory(int level) {\n        }\n    }\n\n    private static void updateConfiguration(@NonNull Context context, @NonNull AppearanceOptions options) {\n        Resources res = context.getResources();\n        // Set theme\n        if (options.theme != null) {\n            context.setTheme(options.theme);\n        }\n        // Update configuration\n        Configuration overrideConf = createOverrideConfiguration(context, options);\n        //noinspection deprecation\n        res.updateConfiguration(overrideConf, res.getDisplayMetrics());\n    }\n\n    @NonNull\n    private static Configuration createOverrideConfiguration(@NonNull Context context, @NonNull AppearanceOptions options) {\n        return createOverrideConfiguration(context, options, null, false);\n    }\n\n    @SuppressLint(\"AppBundleLocaleChanges\") // We don't use Play Store\n    @NonNull\n    private static Configuration createOverrideConfiguration(@NonNull Context context,\n                                                             @NonNull AppearanceOptions options,\n                                                             @Nullable Configuration configOverlay,\n                                                             boolean ignoreFollowSystem) {\n        // Order matters!\n        Resources res = context.getResources();\n        Configuration oldConf = res.getConfiguration();\n        Configuration overrideConf = new Configuration(oldConf);\n\n        // Set locale\n        if (options.locale != null) {\n            Locale.setDefault(options.locale);\n            //noinspection deprecation\n            Locale currentLocale = Build.VERSION.SDK_INT >= Build.VERSION_CODES.N ? oldConf.getLocales().get(0) : oldConf.locale;\n            if (currentLocale != options.locale) {\n                // Locale has changed\n                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {\n                    setLocaleApi24(overrideConf, options.locale);\n                } else {\n                    overrideConf.setLocale(options.locale);\n                    overrideConf.setLayoutDirection(options.locale);\n                }\n            }\n        }\n        // Set layout direction\n        if (options.layoutDirection != null) {\n            int currentLayoutDirection = overrideConf.getLayoutDirection();\n            if (currentLayoutDirection != options.layoutDirection) {\n                switch (options.layoutDirection) {\n                    case View.LAYOUT_DIRECTION_RTL:\n                        overrideConf.setLayoutDirection(Locale.forLanguageTag(\"ar\"));\n                        break;\n                    case View.LAYOUT_DIRECTION_LTR:\n                        overrideConf.setLayoutDirection(Locale.ENGLISH);\n                }\n            }\n        }\n\n        // Set night mode\n        if (options.nightMode != null) {\n            // Follow AppCompatDelegateImpl\n            int nightMode = options.nightMode != AppCompatDelegate.MODE_NIGHT_UNSPECIFIED ? options.nightMode\n                    : AppCompatDelegate.getDefaultNightMode();\n            int modeToApply = mapNightModeOnce(context, nightMode);\n            int newNightMode;\n            switch (modeToApply) {\n                case AppCompatDelegate.MODE_NIGHT_YES:\n                    newNightMode = Configuration.UI_MODE_NIGHT_YES;\n                    break;\n                case AppCompatDelegate.MODE_NIGHT_NO:\n                    newNightMode = Configuration.UI_MODE_NIGHT_NO;\n                    break;\n                default:\n                case AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM:\n                    if (ignoreFollowSystem) {\n                        // We're generating an overlay to be used on top of the system configuration,\n                        // so use whatever's already there.\n                        newNightMode = Configuration.UI_MODE_NIGHT_UNDEFINED;\n                    } else {\n                        // If we're following the system, we just use the system default from the\n                        // application context\n                        final Configuration sysConf = Resources.getSystem().getConfiguration();\n                        newNightMode = sysConf.uiMode & Configuration.UI_MODE_NIGHT_MASK;\n                    }\n                    break;\n            }\n            overrideConf.uiMode = newNightMode | (overrideConf.uiMode & ~Configuration.UI_MODE_NIGHT_MASK);\n        }\n\n        // Apply overlay\n        if (configOverlay != null) {\n            overrideConf.setTo(configOverlay);\n        }\n        return overrideConf;\n    }\n\n    @RequiresApi(Build.VERSION_CODES.N)\n    private static void setLocaleApi24(@NonNull Configuration config, @NonNull Locale locale) {\n        LocaleList defaultLocales = LocaleList.getDefault();\n        LinkedHashSet<Locale> locales = new LinkedHashSet<>(defaultLocales.size() + 1);\n        // Bring the target locale to the front of the list\n        // There's a hidden API, but it's not currently used here.\n        locales.add(locale);\n        for (int i = 0; i < defaultLocales.size(); ++i) {\n            locales.add(defaultLocales.get(i));\n        }\n        config.setLocales(new LocaleList(locales.toArray(new Locale[0])));\n    }\n\n    @SuppressWarnings(\"deprecation\")\n    private static int mapNightModeOnce(@NonNull Context context, @AppCompatDelegate.NightMode final int mode) {\n        switch (mode) {\n            case AppCompatDelegate.MODE_NIGHT_NO:\n            case AppCompatDelegate.MODE_NIGHT_YES:\n            case AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM:\n                // $FALLTHROUGH since these are all valid modes to return\n                return mode;\n            case AppCompatDelegate.MODE_NIGHT_AUTO_TIME:\n                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {\n                    UiModeManager uiModeManager = (UiModeManager) context.getApplicationContext()\n                            .getSystemService(Context.UI_MODE_SERVICE);\n                    if (uiModeManager.getNightMode() == UiModeManager.MODE_NIGHT_AUTO) {\n                        // If we're set to AUTO and the system's auto night mode is already enabled,\n                        // we'll just let the system handle it by returning FOLLOW_SYSTEM\n                        return AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM;\n                    }\n                }\n                // Unlike AppCompatDelegateImpl, we don't need to change it based on configuration\n                return PublicTwilightManager.isNight(context) ? AppCompatDelegate.MODE_NIGHT_YES\n                        : AppCompatDelegate.MODE_NIGHT_NO;\n            case AppCompatDelegate.MODE_NIGHT_AUTO_BATTERY: {\n                // Unlike AppCompatDelegateImpl, we don't need to change it based on configuration\n                PowerManager pm = (PowerManager) context.getApplicationContext()\n                        .getSystemService(Context.POWER_SERVICE);\n                return pm.isPowerSaveMode() ? AppCompatDelegate.MODE_NIGHT_YES : AppCompatDelegate.MODE_NIGHT_NO;\n            }\n            case AppCompatDelegate.MODE_NIGHT_UNSPECIFIED:\n                // If we don't have a mode specified, let the system handle it\n                return AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM;\n            default:\n                throw new IllegalStateException(\"Unknown value set for night mode. Please use one\"\n                        + \" of the MODE_NIGHT values from AppCompatDelegate.\");\n        }\n    }\n\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/utils/appearance/ColorCodes.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.utils.appearance;\n\nimport android.content.Context;\n\nimport androidx.annotation.ColorInt;\nimport androidx.annotation.NonNull;\nimport androidx.core.content.ContextCompat;\n\nimport com.google.android.material.color.MaterialColors;\nimport com.google.android.material.elevation.SurfaceColors;\n\nimport io.github.muntashirakon.AppManager.debloat.DebloatObject;\nimport io.github.muntashirakon.ui.R;\n\npublic final class ColorCodes {\n    @ColorInt\n    public static int getListItemColor0(@NonNull Context context) {\n        return MaterialColors.getColor(context, com.google.android.material.R.attr.colorSurface, ColorCodes.class.getCanonicalName());\n    }\n\n    @ColorInt\n    public static int getListItemColor1(@NonNull Context context) {\n        return SurfaceColors.SURFACE_1.getColor(context);\n    }\n\n    @ColorInt\n    public static int getListItemDefaultIndicatorColor(@NonNull Context context) {\n        return SurfaceColors.SURFACE_3.getColor(context);\n    }\n\n    @ColorInt\n    public static int getQueryStringHighlightColor(@NonNull Context context) {\n        return ContextCompat.getColor(context, R.color.highlight);\n    }\n\n    public static int getSuccessColor(@NonNull Context context) {\n        return ContextCompat.getColor(context, R.color.salem_green);\n    }\n\n    public static int getFailureColor(@NonNull Context context) {\n        return ContextCompat.getColor(context, R.color.electric_red);\n    }\n\n    public static int getAppDisabledIndicatorColor(@NonNull Context context) {\n        return ContextCompat.getColor(context, R.color.disabled_user);\n    }\n\n    public static int getAppForceStoppedIndicatorColor(@NonNull Context context) {\n        return ContextCompat.getColor(context, R.color.stopped);\n    }\n\n    public static int getAppKeystoreIndicatorColor(@NonNull Context context) {\n        return ContextCompat.getColor(context, R.color.tracker);\n    }\n\n    public static int getAppNoBatteryOptimizationIndicatorColor(@NonNull Context context) {\n        return ContextCompat.getColor(context, R.color.red_orange);\n    }\n\n    public static int getAppSsaidIndicatorColor(@NonNull Context context) {\n        return ContextCompat.getColor(context, R.color.tracker);\n    }\n\n    public static int getAppPlayAppSigningIndicatorColor(@NonNull Context context) {\n        return ContextCompat.getColor(context, R.color.disabled_user);\n    }\n\n    public static int getAppWriteAndExecuteIndicatorColor(@NonNull Context context) {\n        return ContextCompat.getColor(context, R.color.red);\n    }\n\n    public static int getBloatwareIndicatorColor(@NonNull Context context, @DebloatObject.Removal int removal) {\n        switch (removal) {\n            case DebloatObject.REMOVAL_REPLACE:\n                return getRemovalReplaceIndicatorColor(context);\n            case DebloatObject.REMOVAL_SAFE:\n                return getRemovalSafeIndicatorColor(context);\n            case DebloatObject.REMOVAL_CAUTION:\n                return getRemovalCautionIndicatorColor(context);\n            case DebloatObject.REMOVAL_UNSAFE:\n            default:\n                return getRemovalUnsafeIndicatorColor(context);\n        }\n    }\n\n    public static int getAppSuspendedIndicatorColor(@NonNull Context context) {\n        return ContextCompat.getColor(context, R.color.stopped);\n    }\n\n    public static int getAppHiddenIndicatorColor(@NonNull Context context) {\n        return ContextCompat.getColor(context, R.color.disabled_user);\n    }\n\n    public static int getAppUninstalledIndicatorColor(@NonNull Context context) {\n        return ContextCompat.getColor(context, R.color.red);\n    }\n\n    public static int getBackupLatestIndicatorColor(@NonNull Context context) {\n        return getSuccessColor(context);\n    }\n\n    public static int getBackupOutdatedIndicatorColor(@NonNull Context context) {\n        return ContextCompat.getColor(context, R.color.orange);\n    }\n\n    public static int getBackupUninstalledIndicatorColor(@NonNull Context context) {\n        return ContextCompat.getColor(context, R.color.red);\n    }\n\n    public static int getComponentRunningIndicatorColor(@NonNull Context context) {\n        return ContextCompat.getColor(context, R.color.running);\n    }\n\n    public static int getComponentTrackerIndicatorColor(@NonNull Context context) {\n        return ContextCompat.getColor(context, R.color.tracker);\n    }\n\n    public static int getComponentTrackerBlockedIndicatorColor(@NonNull Context context) {\n        return getSuccessColor(context);\n    }\n\n    public static int getComponentBlockedIndicatorColor(@NonNull Context context) {\n        return ContextCompat.getColor(context, R.color.red);\n    }\n\n    public static int getComponentExternallyBlockedIndicatorColor(@NonNull Context context) {\n        return ContextCompat.getColor(context, R.color.disabled_user);\n    }\n\n    public static int getPermissionDangerousIndicatorColor(@NonNull Context context) {\n        return ContextCompat.getColor(context, R.color.red);\n    }\n\n    public static int getScannerTrackerIndicatorColor(@NonNull Context context) {\n        return getFailureColor(context);\n    }\n\n    public static int getRemovalSafeIndicatorColor(@NonNull Context context) {\n        return getSuccessColor(context);\n    }\n\n    public static int getRemovalReplaceIndicatorColor(@NonNull Context context) {\n        return ContextCompat.getColor(context, R.color.lilac_bush_purple);\n    }\n\n    public static int getRemovalCautionIndicatorColor(@NonNull Context context) {\n        return ContextCompat.getColor(context, R.color.pumpkin_orange);\n    }\n\n    public static int getRemovalUnsafeIndicatorColor(@NonNull Context context) {\n        return getFailureColor(context);\n    }\n\n    public static int getScannerNoTrackerIndicatorColor(@NonNull Context context) {\n        return getSuccessColor(context);\n    }\n\n    public static int getVirusTotalSafeIndicatorColor(@NonNull Context context) {\n        return getSuccessColor(context);\n    }\n\n    public static int getVirusTotalUnsafeIndicatorColor(@NonNull Context context) {\n        return ContextCompat.getColor(context, R.color.tracker);\n    }\n\n    public static int getVirusTotalExtremelyUnsafeIndicatorColor(@NonNull Context context) {\n        return getFailureColor(context);\n    }\n\n    public static int getWhatsNewPlusIndicatorColor(@NonNull Context context) {\n        return getSuccessColor(context);\n    }\n\n    public static int getWhatsNewMinusIndicatorColor(@NonNull Context context) {\n        return getFailureColor(context);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/utils/appearance/TypefaceUtil.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.utils.appearance;\n\nimport android.annotation.SuppressLint;\nimport android.content.Context;\nimport android.content.res.TypedArray;\nimport android.graphics.Typeface;\nimport android.os.Build;\nimport android.view.ContextThemeWrapper;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport java.lang.reflect.Field;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport io.github.muntashirakon.AppManager.logs.Log;\n\npublic class TypefaceUtil {\n    public static final String TAG = TypefaceUtil.class.getSimpleName();\n\n    private static final Map<String, Typeface> sOverriddenFonts = new HashMap<>();\n\n    public static void replaceFontsWithSystem(@NonNull Context context) {\n        String normalFont = getSystemFontFamily(context);\n        if (normalFont == null) {\n            Log.i(TAG, \"No system font exists. Skip applying font overrides.\");\n            return;\n        }\n\n        try {\n            overrideFonts(normalFont);\n        } catch (Exception e) {\n            Log.w(TAG, \"Could not override fonts\", e);\n        }\n    }\n\n    @SuppressLint(\"DiscouragedPrivateApi\")\n    @SuppressWarnings({\"JavaReflectionMemberAccess\", \"unchecked\"})\n    public static void restoreFonts() {\n        if (sOverriddenFonts.isEmpty()) {\n            return;\n        }\n        try {\n            final Field field = Typeface.class.getDeclaredField(\"sSystemFontMap\");\n            field.setAccessible(true);\n            Map<String, Typeface> allFontsForThisApp = (Map<String, Typeface>) field.get(null);\n            if (allFontsForThisApp == null) {\n                Log.i(TAG, \"No fonts are set for this app. Weird!\");\n                return;\n            }\n            for (Map.Entry<String, Typeface> entry : sOverriddenFonts.entrySet()) {\n                if (entry.getValue() == null) {\n                    // Delete this entry\n                    allFontsForThisApp.remove(entry.getKey());\n                } else {\n                    // Replace\n                    allFontsForThisApp.put(entry.getKey(), entry.getValue());\n                }\n            }\n            field.set(null, allFontsForThisApp);\n            field.setAccessible(false);\n        } catch (Exception e) {\n            Log.w(TAG, \"Could not restore fonts\", e);\n        }\n    }\n\n    @Nullable\n    private static String getSystemFontFamily(@NonNull Context context) {\n        ContextThemeWrapper themedContext;\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {\n            themedContext = new ContextThemeWrapper(context, android.R.style.Theme_DeviceDefault_DayNight);\n        } else {\n            themedContext = new ContextThemeWrapper(context, android.R.style.Theme_DeviceDefault);\n        }\n        TypedArray ta = themedContext.obtainStyledAttributes(android.R.style.TextAppearance_DeviceDefault,\n                new int[]{android.R.attr.fontFamily});\n        String value = ta.getString(0);\n        ta.recycle();\n        return value;\n    }\n\n    @SuppressLint(\"DiscouragedPrivateApi\")\n    @SuppressWarnings({\"JavaReflectionMemberAccess\", \"unchecked\"})\n    private static void overrideFonts(@NonNull String normalFont) throws Exception {\n        final Field field = Typeface.class.getDeclaredField(\"sSystemFontMap\");\n        field.setAccessible(true);\n        Map<String, Typeface> allFontsForThisApp = (Map<String, Typeface>) field.get(null);\n        if (allFontsForThisApp == null) {\n            Log.i(TAG, \"No fonts are set for this app. Weird!\");\n            return;\n        }\n        Map<String, Typeface> fontsMap = new HashMap<String, Typeface>() {{\n            // Fortunately for us, normalFont is always the basic font.\n            // We can find other fonts by checking whether they starts with normalFont- and\n            // append the substring to sans-serif\n            List<String> fontFamilies = new ArrayList<>(allFontsForThisApp.keySet());\n            for (String fontFamily : fontFamilies) {\n                if (fontFamily.startsWith(normalFont)) {\n                    Typeface typeface = allFontsForThisApp.get(fontFamily);\n                    if (fontFamily.equals(normalFont)) {\n                        put(\"sans-serif\", typeface);\n                    } else {\n                        String suffix = fontFamily.substring(normalFont.length());\n                        if (suffix.contains(\"-medium\")) {\n                            // For some reason, material themes use medium instead of bold for bold\n                            // fonts. We need to check if a bold font exist for this font. If there\n                            // is one, we'll use that font instead of the medium font.\n                            String s = normalFont + suffix.replace(\"-medium\", \"-bold\");\n                            if (fontFamilies.contains(s)) {\n                                typeface = allFontsForThisApp.get(s);\n                            }\n                        }\n                        put(\"sans-serif\" + suffix, typeface);\n                    }\n                }\n            }\n        }};\n        // Store overridden fonts\n        if (sOverriddenFonts.isEmpty()) {\n            for (String fontFamily : fontsMap.keySet()) {\n                sOverriddenFonts.put(fontFamily, allFontsForThisApp.get(fontFamily));\n            }\n        }\n        allFontsForThisApp.putAll(fontsMap);\n        field.set(null, allFontsForThisApp);\n        field.setAccessible(false);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/viewer/ExplorerActivity.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.viewer;\n\nimport android.content.Intent;\nimport android.net.Uri;\nimport android.os.Bundle;\n\nimport androidx.annotation.Nullable;\n\nimport io.github.muntashirakon.AppManager.BaseActivity;\nimport io.github.muntashirakon.AppManager.fm.FmActivity;\nimport io.github.muntashirakon.AppManager.intercept.IntentCompat;\n\npublic class ExplorerActivity extends BaseActivity {\n    @Override\n    protected void onAuthenticated(@Nullable Bundle savedInstanceState) {\n        Uri uri = IntentCompat.getDataUri(getIntent());\n        if (uri == null) {\n            finish();\n            return;\n        }\n        FmActivity.Options options = new FmActivity.Options(uri, true, true, true);\n        Intent intent = new Intent(this, FmActivity.class);\n        intent.putExtra(FmActivity.EXTRA_OPTIONS, options);\n        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT | Intent.FLAG_ACTIVITY_MULTIPLE_TASK);\n        startActivity(intent);\n        finish();\n    }\n\n    @Override\n    public boolean getTransparentBackground() {\n        return true;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/viewer/audio/AudioMetadata.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.viewer.audio;\n\nimport android.graphics.Bitmap;\nimport android.net.Uri;\n\nimport androidx.annotation.Nullable;\n\nfinal class AudioMetadata {\n    public Uri uri;\n    @Nullable\n    public Bitmap cover;\n    public String title;\n    public String artist;\n    public String album;\n    public String albumArtist;\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/viewer/audio/AudioPlayerActivity.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.viewer.audio;\n\nimport android.net.Uri;\nimport android.os.Bundle;\n\nimport androidx.annotation.Nullable;\n\nimport java.util.List;\n\nimport io.github.muntashirakon.AppManager.PerProcessActivity;\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.intercept.IntentCompat;\n\npublic class AudioPlayerActivity extends PerProcessActivity {\n    @Override\n    public boolean getTransparentBackground() {\n        return true;\n    }\n\n    @Override\n    protected void onCreate(@Nullable Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        setContentView(R.layout.activity_audio_player);\n        List<Uri> uriList = IntentCompat.getDataUris(getIntent());\n        if (uriList == null) {\n            finish();\n            return;\n        }\n        AudioPlayerDialogFragment fragment = AudioPlayerDialogFragment.getInstance(uriList.toArray(new Uri[0]), true);\n        fragment.show(getSupportFragmentManager(), AudioPlayerDialogFragment.TAG);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/viewer/audio/AudioPlayerDialogFragment.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.viewer.audio;\n\nimport android.content.DialogInterface;\nimport android.media.MediaPlayer;\nimport android.net.Uri;\nimport android.os.Build;\nimport android.os.Bundle;\nimport android.os.Handler;\nimport android.os.Looper;\nimport android.os.PowerManager;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.ImageView;\nimport android.widget.TextView;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.lifecycle.ViewModelProvider;\n\nimport com.google.android.material.slider.Slider;\n\nimport java.util.Locale;\n\nimport io.github.muntashirakon.AppManager.R;\nimport io.github.muntashirakon.AppManager.utils.CpuUtils;\nimport io.github.muntashirakon.dialog.CapsuleBottomSheetDialogFragment;\n\n// Raw code taken from DialogMusicPlayer <https://github.com/VishnuSanal/DialogMusicPlayer>.\n// Inspired by other players such as Music Player Go, Poweramp\npublic class AudioPlayerDialogFragment extends CapsuleBottomSheetDialogFragment {\n    public static final String TAG = AudioPlayerDialogFragment.class.getSimpleName();\n    private static final String ARG_URI_LIST = \"uris\";\n    private static final String ARG_CLOSE_ACTIVITY = \"close\";\n\n    @NonNull\n    public static AudioPlayerDialogFragment getInstance(@NonNull Uri[] uriList, boolean closeActivity) {\n        AudioPlayerDialogFragment dialog = new AudioPlayerDialogFragment();\n        Bundle args = new Bundle();\n        args.putParcelableArray(ARG_URI_LIST, uriList);\n        args.putBoolean(ARG_CLOSE_ACTIVITY, closeActivity);\n        dialog.setArguments(args);\n        return dialog;\n    }\n\n    private ImageView mIconView;\n    private TextView mPlaylistSizeView;\n    private TextView mTitleView;\n    private TextView mInfoView;\n    private Slider mSlider;\n    private TextView mProgressView;\n    private TextView mDurationView;\n    private TextView mPlaybackSpeedView;\n    private ImageView mRewindButton;\n    private ImageView mForwardButton;\n    private ImageView mPlayPauseButton;\n    private ImageView mRepeatButton;\n\n    private Handler mUpdateHandler;\n    private Runnable mUpdateRunnable;\n\n    private boolean mIsTimeReversed = false;\n    private boolean mShouldCheckRepeat = true;\n\n    private MediaPlayer mMediaPlayer;\n    private AudioPlayerViewModel mViewModel;\n    private PowerManager.WakeLock mWakeLock;\n\n    private boolean mCloseActivity;\n\n    @NonNull\n    @Override\n    public View initRootView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {\n        return inflater.inflate(R.layout.dialog_audio_player, container, false);\n    }\n\n    @Override\n    public void onBodyInitialized(@NonNull View bodyView, @Nullable Bundle savedInstanceState) {\n        mViewModel = new ViewModelProvider(this).get(AudioPlayerViewModel.class);\n        Uri[] uriList = (Uri[]) requireArguments().getParcelableArray(ARG_URI_LIST);\n        mCloseActivity = requireArguments().getBoolean(ARG_CLOSE_ACTIVITY);\n        mIconView = bodyView.findViewById(android.R.id.icon);\n        mPlaylistSizeView = bodyView.findViewById(R.id.size);\n        mTitleView = bodyView.findViewById(android.R.id.title);\n        mInfoView = bodyView.findViewById(R.id.info);\n        mSlider = bodyView.findViewById(R.id.slider);\n        mProgressView = bodyView.findViewById(R.id.progress);\n        mDurationView = bodyView.findViewById(R.id.duration);\n        mPlaybackSpeedView = bodyView.findViewById(R.id.playback_speed);\n        mRewindButton = bodyView.findViewById(R.id.action_rewind);\n        mForwardButton = bodyView.findViewById(R.id.action_forward);\n        mPlayPauseButton = bodyView.findViewById(R.id.action_play_pause);\n        mRepeatButton = bodyView.findViewById(R.id.action_repeat);\n        // Set tags\n        mPlaybackSpeedView.setTag(1.0f);\n        mRepeatButton.setTag(RepeatMode.NO_REPEAT);\n        // Listeners\n        mMediaPlayer = new MediaPlayer();\n        setListeners();\n        mViewModel.getAudioMetadataLiveData().observe(getViewLifecycleOwner(), this::setupMetadata);\n        mViewModel.getMediaPlayerPreparedLiveData().observe(getViewLifecycleOwner(), prepared -> {\n            if (!prepared) {\n                return;\n            }\n            startPlayingMedia();\n            mShouldCheckRepeat = true;\n        });\n        mViewModel.getPlaylistLoadedLiveData().observe(getViewLifecycleOwner(), loaded -> updatePlaylistSize());\n        mViewModel.addToPlaylist(uriList);\n        mWakeLock = CpuUtils.getPartialWakeLock(\"pasteThread\");\n    }\n\n    @Override\n    public void onStart() {\n        super.onStart();\n        if (mWakeLock != null && !mWakeLock.isHeld()) {\n            mWakeLock.acquire();\n        }\n    }\n\n    @Override\n    public void onDismiss(@NonNull DialogInterface dialog) {\n        if (mediaPlayerInitialized()) {\n            mMediaPlayer.stop();\n            mMediaPlayer.release();\n        }\n        super.onDismiss(dialog);\n    }\n\n    @Override\n    public void onDestroy() {\n        CpuUtils.releaseWakeLock(mWakeLock);\n        super.onDestroy();\n        if (mCloseActivity) {\n            requireActivity().finish();\n        }\n    }\n\n    private void setListeners() {\n        mSlider.addOnChangeListener((slider, value, fromUser) -> {\n            if (!fromUser) {\n                return;\n            }\n            if (mediaPlayerInitialized()) {\n                mMediaPlayer.seekTo((int) value);\n\n                if (!mMediaPlayer.isPlaying()) {\n                    if (value != mMediaPlayer.getDuration()) {\n                        mPlayPauseButton.setImageResource(R.drawable.ic_play_arrow);\n                    } else resetMediaPlayer();\n                }\n            }\n        });\n        mSlider.setLabelFormatter(value -> getFormattedTime((long) value, mIsTimeReversed));\n\n        mUpdateHandler = new Handler(Looper.myLooper());\n        mUpdateRunnable = new Runnable() {\n            @Override\n            public void run() {\n                if (mediaPlayerInitialized()) {\n                    final int currentPosition = mMediaPlayer.getCurrentPosition();\n                    if (currentPosition <= mSlider.getValueTo()) {\n                        mSlider.setValue(currentPosition);\n                    }\n\n                    mProgressView.setText(getFormattedTime(currentPosition, mIsTimeReversed));\n                    mUpdateHandler.postDelayed(this, 10);\n                }\n            }\n        };\n\n\n        // Play/Pause: Click -> Play/pause, Long click -> Set duration to zero\n        mPlayPauseButton.setOnClickListener(v -> {\n            if (mediaPlayerInitialized())\n                if (!mMediaPlayer.isPlaying()) {\n                    if (mMediaPlayer.getCurrentPosition() == mMediaPlayer.getDuration()) {\n                        mMediaPlayer.seekTo(0);\n                    }\n                    resumeMediaPlayer();\n                } else {\n                    pauseMediaPlayer();\n                }\n        });\n        mPlayPauseButton.setOnLongClickListener(v -> {\n            mMediaPlayer.seekTo(0);\n            return true;\n        });\n\n        mProgressView.setOnClickListener(v -> mIsTimeReversed = !mIsTimeReversed);\n\n        mPlaybackSpeedView.setOnClickListener(v -> {\n            float speed = (float) mPlaybackSpeedView.getTag();\n            if (speed == 0.5F) {\n                mPlaybackSpeedView.setText(\"0.75x\");\n                mPlaybackSpeedView.setTag(0.75F);\n            } else if (speed == 0.75F) {\n                mPlaybackSpeedView.setText(\"1x\");\n                mPlaybackSpeedView.setTag(1F);\n            } else if (speed == 1.0F) {\n                mPlaybackSpeedView.setText(\"1.25x\");\n                mPlaybackSpeedView.setTag(1.25F);\n            } else if (speed == 1.25F) {\n                mPlaybackSpeedView.setText(\"1.5x\");\n                mPlaybackSpeedView.setTag(1.5F);\n            } else if (speed == 1.5F) {\n                mPlaybackSpeedView.setText(\"2.0x\");\n                mPlaybackSpeedView.setTag(2.0F);\n            } else if (speed == 2.0F) {\n                mPlaybackSpeedView.setText(\"0.5x\");\n                mPlaybackSpeedView.setTag(0.5F);\n            }\n            updatePlaybackSpeed();\n        });\n\n        mRepeatButton.setOnClickListener(v -> {\n            @RepeatMode\n            int state = (int) mRepeatButton.getTag();\n            switch (state) {\n                case RepeatMode.NO_REPEAT:\n                    mRepeatButton.setImageResource(R.drawable.ic_repeat);\n                    mRepeatButton.setTag(RepeatMode.REPEAT_INDEFINITELY);\n                    break;\n                case RepeatMode.REPEAT_INDEFINITELY:\n                    mRepeatButton.setImageResource(R.drawable.ic_repeat_one);\n                    mRepeatButton.setTag(RepeatMode.REPEAT_SINGLE_INDEFINITELY);\n                    break;\n                case RepeatMode.REPEAT_SINGLE_INDEFINITELY:\n                    mRepeatButton.setImageResource(R.drawable.ic_repeat_off);\n                    mRepeatButton.setTag(RepeatMode.NO_REPEAT);\n                    break;\n            }\n        });\n\n        // Rewind: Click -> -10 sec, Long click -> Play previous item\n        mRewindButton.setOnClickListener(v -> {\n            if (mediaPlayerInitialized()) {\n                mMediaPlayer.seekTo(mMediaPlayer.getCurrentPosition() - 10 * 1000);\n            }\n        });\n        mRewindButton.setOnLongClickListener(v -> {\n            mViewModel.playPrevious();\n            return true;\n        });\n\n        // Forward: Click -> +10 sec, Long click -> Play next item\n        mForwardButton.setOnClickListener(v -> {\n            if (mediaPlayerInitialized()) {\n                mMediaPlayer.seekTo(mMediaPlayer.getCurrentPosition() + 10 * 1000);\n            }\n        });\n        mForwardButton.setOnLongClickListener(v -> {\n            mViewModel.playNext(false);\n            return true;\n        });\n\n        mMediaPlayer.setOnCompletionListener(mediaPlayer -> {\n            if (!mShouldCheckRepeat) {\n                mShouldCheckRepeat = true;\n                return;\n            }\n            @RepeatMode\n            int state = (int) mRepeatButton.getTag();\n            resetMediaPlayer();\n            if (state == RepeatMode.REPEAT_SINGLE_INDEFINITELY) {\n                if (mediaPlayer.getCurrentPosition() == mediaPlayer.getDuration()) {\n                    mediaPlayer.seekTo(0);\n                }\n                resumeMediaPlayer();\n            } else {\n                mViewModel.playNext(state);\n            }\n        });\n    }\n\n    private void updatePlaybackSpeed() {\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && mediaPlayerInitialized()) {\n            boolean isPlaying = mMediaPlayer.isPlaying();\n            mMediaPlayer.setPlaybackParams(mMediaPlayer.getPlaybackParams().setSpeed((float) mPlaybackSpeedView.getTag()));\n            if (!isPlaying) {\n                mMediaPlayer.pause();\n            }\n        }\n    }\n\n    private void pauseMediaPlayer() {\n        if (mediaPlayerInitialized()) {\n            mMediaPlayer.pause();\n            mPlayPauseButton.setImageResource(R.drawable.ic_play_arrow);\n        }\n    }\n\n    private void resumeMediaPlayer() {\n        if (mediaPlayerInitialized()) {\n            mMediaPlayer.start();\n            mPlayPauseButton.setImageResource(R.drawable.ic_pause);\n        }\n    }\n\n    private void resetMediaPlayer() {\n        mPlayPauseButton.setImageResource(R.drawable.ic_replay);\n    }\n\n    private String getFormattedTime(long millis, boolean isTimeReversed) {\n        if (!mediaPlayerInitialized()) {\n            return \"00:00\";\n        }\n        long minutes = (millis / 1000) / 60;\n        long seconds = (millis / 1000) % 60;\n        String secondsStr = Long.toString(seconds);\n        String secs = (secondsStr.length() >= 2) ? secondsStr.substring(0, 2) : \"0\" + secondsStr;\n        if (!isTimeReversed) return minutes + \":\" + secs;\n        return \"-\" + getFormattedTime(mMediaPlayer.getDuration() - millis, false);\n    }\n\n    private boolean mediaPlayerInitialized() {\n        if (mMediaPlayer == null) {\n            return false;\n        }\n        try {\n            mMediaPlayer.isPlaying();\n            return true;\n        } catch (IllegalStateException e) {\n            return false;\n        }\n    }\n\n    private void updatePlaylistSize() {\n        int currentAudio = mViewModel.getCurrentPlaylistIndex() + 1;\n        int playlistSize = mViewModel.playlistSize();\n        mPlaylistSizeView.setVisibility(playlistSize > 1 ? View.VISIBLE : View.GONE);\n        mPlaylistSizeView.setText(String.format(Locale.ROOT, \"%d/%d\", currentAudio, playlistSize));\n    }\n\n    private void setupMetadata(@NonNull AudioMetadata meta) {\n        if (meta.cover != null) {\n            mIconView.setImageBitmap(meta.cover);\n        } else {\n            mIconView.setImageResource(R.drawable.ic_audio_file);\n        }\n        updatePlaylistSize();\n        mTitleView.setText(String.format(Locale.ROOT, \"%s - %s\", meta.artist, meta.title));\n        mTitleView.setSelected(true);\n        mInfoView.setText(String.format(Locale.ROOT, \"%s - %s\", meta.albumArtist, meta.album));\n        mInfoView.setSelected(true);\n\n        mShouldCheckRepeat = false;\n        mViewModel.prepareMediaPlayer(mMediaPlayer, meta.uri);\n    }\n\n    private void startPlayingMedia() {\n        int duration = mMediaPlayer.getDuration();\n        mSlider.setValueFrom(0);\n        mSlider.setValueTo(duration);\n\n        mDurationView.setText(getFormattedTime(duration, mIsTimeReversed));\n\n        mMediaPlayer.seekTo(0);\n        resumeMediaPlayer();\n        mUpdateHandler.postDelayed(mUpdateRunnable, 0);\n\n        mPlayPauseButton.setImageResource(R.drawable.ic_pause);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/viewer/audio/AudioPlayerViewModel.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.viewer.audio;\n\nimport android.app.Application;\nimport android.graphics.BitmapFactory;\nimport android.media.MediaMetadataRetriever;\nimport android.media.MediaPlayer;\nimport android.net.Uri;\n\nimport androidx.annotation.NonNull;\nimport androidx.lifecycle.AndroidViewModel;\nimport androidx.lifecycle.LiveData;\nimport androidx.lifecycle.MutableLiveData;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\n\nimport io.github.muntashirakon.AppManager.utils.ThreadUtils;\n\npublic class AudioPlayerViewModel extends AndroidViewModel {\n    private final MutableLiveData<AudioMetadata> mAudioMetadataLiveData = new MutableLiveData<>();\n    private final MutableLiveData<Boolean> mMediaPlayerPreparedLiveData = new MutableLiveData<>();\n    private final MutableLiveData<Boolean> mPlaylistLoadedLiveData = new MutableLiveData<>();\n    private final List<AudioMetadata> mPlaylist = Collections.synchronizedList(new ArrayList<>());\n\n    private int mCurrentPlaylistIndex = -1;\n\n    public AudioPlayerViewModel(@NonNull Application application) {\n        super(application);\n    }\n\n    public int getCurrentPlaylistIndex() {\n        return mCurrentPlaylistIndex;\n    }\n\n    public int playlistSize() {\n        return mPlaylist.size();\n    }\n\n    public void addToPlaylist(@NonNull Uri[] uriList) {\n        ThreadUtils.postOnBackgroundThread(() -> {\n            for (Uri uri : uriList) {\n                AudioMetadata audioMetadata = fetchAudioMetadata(uri);\n                mPlaylist.add(audioMetadata);\n                int index = mCurrentPlaylistIndex;\n                if (index == -1) {\n                    // Start playing immediately if nothing is playing\n                    mCurrentPlaylistIndex = 0;\n                    mAudioMetadataLiveData.postValue(audioMetadata);\n                }\n            }\n            mPlaylistLoadedLiveData.postValue(true);\n        });\n    }\n\n    public void playNext(@RepeatMode int repeatMode) {\n        switch (repeatMode) {\n            default:\n            case RepeatMode.NO_REPEAT:\n                playNext(false);\n                break;\n            case RepeatMode.REPEAT_INDEFINITELY:\n                playNext(true);\n                break;\n            case RepeatMode.REPEAT_SINGLE_INDEFINITELY:\n                mAudioMetadataLiveData.postValue(mPlaylist.get(mCurrentPlaylistIndex));\n        }\n    }\n\n    public void playNext(boolean repeat) {\n        int index = mCurrentPlaylistIndex;\n        if (index < (mPlaylist.size() - 1)) {\n            ++index;\n            mCurrentPlaylistIndex = index;\n            mAudioMetadataLiveData.postValue(mPlaylist.get(index));\n        } else if (repeat) {\n            // Reset index\n            index = 0;\n            mCurrentPlaylistIndex = index;\n            mAudioMetadataLiveData.postValue(mPlaylist.get(index));\n        }\n    }\n\n    public void playPrevious() {\n        int index = mCurrentPlaylistIndex;\n        if (index > 0) {\n            --index;\n            mCurrentPlaylistIndex = index;\n            mAudioMetadataLiveData.postValue(mPlaylist.get(index));\n        }\n    }\n\n    public LiveData<AudioMetadata> getAudioMetadataLiveData() {\n        return mAudioMetadataLiveData;\n    }\n\n    public LiveData<Boolean> getMediaPlayerPreparedLiveData() {\n        return mMediaPlayerPreparedLiveData;\n    }\n\n    public LiveData<Boolean> getPlaylistLoadedLiveData() {\n        return mPlaylistLoadedLiveData;\n    }\n\n    public void prepareMediaPlayer(@NonNull MediaPlayer mediaPlayer, @NonNull Uri uri) {\n        ThreadUtils.postOnBackgroundThread(() -> {\n            try {\n                mediaPlayer.reset();\n                mediaPlayer.setDataSource(getApplication(), uri);\n                mediaPlayer.prepare();\n                mMediaPlayerPreparedLiveData.postValue(true);\n            } catch (IOException e) {\n                e.printStackTrace();\n                mMediaPlayerPreparedLiveData.postValue(false);\n            }\n        });\n    }\n\n    @NonNull\n    private AudioMetadata fetchAudioMetadata(@NonNull Uri uri) {\n        AudioMetadata audioMetadata = new AudioMetadata();\n        audioMetadata.uri = uri;\n        try (MediaMetadataRetriever retriever = new MediaMetadataRetriever()) {\n            retriever.setDataSource(getApplication(), uri);\n            final byte[] raw = retriever.getEmbeddedPicture();\n            if (raw != null) {\n                audioMetadata.cover = BitmapFactory.decodeByteArray(raw, 0, raw.length);\n            }\n            String title = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_TITLE);\n            if (title == null) {\n                title = uri.getLastPathSegment();\n                if (title == null) {\n                    title = \"<Unknown Title>\";\n                }\n            }\n            String artist = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_ARTIST);\n            if (artist == null) {\n                artist = \"<Unknown Artist>\";\n            }\n            String album = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_ALBUM);\n            if (album == null) {\n                album = \"<Unknown Album>\";\n            }\n            String albumArtist = retriever.extractMetadata(MediaMetadataRetriever.METADATA_KEY_ALBUMARTIST);\n            if (albumArtist == null) {\n                albumArtist = \"<Unknown Artist>\";\n            }\n            audioMetadata.title = title;\n            audioMetadata.album = album;\n            audioMetadata.albumArtist = albumArtist;\n            audioMetadata.artist = artist;\n        } catch (RuntimeException | IOException e) {\n            e.printStackTrace();\n            String title = uri.getLastPathSegment();\n            if (title == null) {\n                title = \"<Unknown Title>\";\n            }\n            audioMetadata.title = title;\n            audioMetadata.album = \"<Unknown Album>\";\n            audioMetadata.albumArtist = \"<Unknown Artist>\";\n            audioMetadata.artist = \"<Unknown Artist>\";\n        }\n        return audioMetadata;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/AppManager/viewer/audio/RepeatMode.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.viewer.audio;\n\nimport androidx.annotation.IntDef;\n\n@IntDef({RepeatMode.NO_REPEAT, RepeatMode.REPEAT_INDEFINITELY, RepeatMode.REPEAT_SINGLE_INDEFINITELY})\npublic @interface RepeatMode {\n    int NO_REPEAT = 0;\n    int REPEAT_INDEFINITELY = 1;\n    int REPEAT_SINGLE_INDEFINITELY = 3;\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/algo/AhoCorasick.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.algo;\n\npublic class AhoCorasick implements AutoCloseable {\n    static {\n        System.loadLibrary(\"am\");\n    }\n\n    private long nativeInstanceId;\n\n    /**\n     * Creates the native Aho-Corasick instance with the given patterns.\n     */\n    public AhoCorasick(String[] patterns) {\n        nativeInstanceId = createNative(patterns);\n        if (nativeInstanceId == 0) {\n            throw new RuntimeException(\"Failed to create native AhoCorasick instance\");\n        }\n    }\n\n    private native long createNative(String[] patterns);\n\n    private native int[] searchNative(long instanceId, String text);\n\n    private native void destroyNative(long instanceId);\n\n    /**\n     * Search the text for matching patterns.\n     */\n    public int[] search(String text) {\n        if (nativeInstanceId == 0) throw new IllegalStateException(\"Instance already closed\");\n        return searchNative(nativeInstanceId, text);\n    }\n\n    /**\n     * Releases native resources automatically when try-with-resources ends.\n     */\n    @Override\n    public void close() {\n        if (nativeInstanceId != 0) {\n            destroyNative(nativeInstanceId);\n            nativeInstanceId = 0;\n        }\n    }\n\n    @Override\n    protected void finalize() throws Throwable {\n        try {\n            close(); // Backup safety to release native resources\n        } finally {\n            super.finalize();\n        }\n    }\n}"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/csv/CsvWriter.java",
    "content": "// SPDX-License-Identifier: MIT AND GPL-3.0-or-later\n\npackage io.github.muntashirakon.csv;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport java.io.IOException;\nimport java.io.Writer;\nimport java.util.Collection;\nimport java.util.Objects;\nimport java.util.stream.Collectors;\nimport java.util.stream.Stream;\n\n// Copyright 2020 Yong Mook Kim\n// Copyright 2024 Muntashir Al-Islam\npublic class CsvWriter {\n    private static final String COMMA = \",\";\n    private static final String DEFAULT_SEPARATOR = COMMA;\n    private static final String DOUBLE_QUOTES = \"\\\"\";\n    private static final String EMBEDDED_DOUBLE_QUOTES = \"\\\"\\\"\";\n    private static final String NEW_LINE_UNIX = \"\\n\";\n    private static final String NEW_LINE_WINDOWS = \"\\r\\n\";\n\n    private final Writer mWriter;\n    private final String mSeparator;\n\n    private boolean mInitialized = false;\n    private int mFirstFieldCount = 0;\n    private int mCurrentFieldCount = 0;\n\n    public CsvWriter(@NonNull Writer writer) {\n        this(writer, DEFAULT_SEPARATOR);\n    }\n\n    public CsvWriter(@NonNull Writer writer, @NonNull String separator) {\n        mWriter = Objects.requireNonNull(writer);\n        mSeparator = Objects.requireNonNull(separator);\n    }\n\n    public void addField(@Nullable String field) throws IOException {\n        addField(field, false);\n    }\n\n    public void addField(@Nullable String field, boolean addQuotes) throws IOException {\n        boolean previouslyInitialized = mInitialized;\n        ++mCurrentFieldCount;\n        checkFieldAvailable();\n        if (mCurrentFieldCount > 1) {\n            // There are other fields\n            mWriter.write(mSeparator);\n        } else if (previouslyInitialized) {\n            // This is the first field since the last line\n            mWriter.append(System.lineSeparator());\n        }\n        mWriter.append(getFormattedField(field, addQuotes));\n    }\n\n    public void addLine() {\n        initIfNotAlready();\n        checkFieldCountSame();\n        mCurrentFieldCount = 0;\n    }\n\n    public void addLine(@NonNull String[] line) throws IOException {\n        addLine(line, false);\n    }\n\n    /**\n     * @param addQuotes Whether all fields are to be enclosed in double quotes\n     */\n    public void addLine(@NonNull String[] line, boolean addQuotes) throws IOException {\n        boolean previouslyInitialized = mInitialized;\n        mCurrentFieldCount = line.length;\n        initIfNotAlready();\n        checkFieldCountSame();\n        mCurrentFieldCount = 0;\n        if (previouslyInitialized) {\n            // There were other lines\n            mWriter.append(System.lineSeparator());\n        }\n        mWriter.append(getFormattedLine(line, addQuotes));\n    }\n\n    public void addLines(@NonNull Collection<String[]> lines) throws IOException {\n        addLines(lines, false);\n    }\n\n    /**\n     * @param addQuotes Whether all fields are to be enclosed in double quotes\n     */\n    public void addLines(@NonNull Collection<String[]> lines, boolean addQuotes) throws IOException {\n        for (String[] line : lines) {\n            addLine(line, addQuotes);\n        }\n    }\n\n    @NonNull\n    private String getFormattedLine(@NonNull String[] line, boolean addQuotes) {\n        return Stream.of(line)\n                .map(field -> getFormattedField(field, addQuotes))\n                .collect(Collectors.joining(mSeparator));\n    }\n\n    @NonNull\n    private String getFormattedField(@Nullable String field, boolean addQuotes) {\n        if (field == null) {\n            // For a null field, add null as string\n            return addQuotes ? (DOUBLE_QUOTES + \"null\" + DOUBLE_QUOTES) : \"null\";\n        }\n        if (field.contains(COMMA)\n                || field.contains(DOUBLE_QUOTES)\n                || field.contains(NEW_LINE_UNIX)\n                || field.contains(NEW_LINE_WINDOWS)\n                || field.contains(mSeparator)) {\n\n            // If the field contains double quotes, replace it with two double quotes \\\"\\\"\n            String result = field.replace(DOUBLE_QUOTES, EMBEDDED_DOUBLE_QUOTES);\n\n            // Enclose the field in double quotes\n            return DOUBLE_QUOTES + result + DOUBLE_QUOTES;\n        } else if (addQuotes) {\n            // Add quotation even if not needed\n            return DOUBLE_QUOTES + field + DOUBLE_QUOTES;\n        } else return field;\n    }\n\n    private void checkFieldAvailable() {\n        if (mInitialized && mCurrentFieldCount > mFirstFieldCount) {\n            throw new IndexOutOfBoundsException(\"CSV fields don't match. Previously added \"\n                    + mFirstFieldCount + \" fields and now \" + mCurrentFieldCount + \" fields\");\n        }\n    }\n\n    private void checkFieldCountSame() {\n        if (mInitialized && mCurrentFieldCount != mFirstFieldCount) {\n            throw new IndexOutOfBoundsException(\"CSV fields don't match. Previously added \"\n                    + mFirstFieldCount + \" fields and now \" + mCurrentFieldCount + \" fields\");\n        }\n    }\n\n    private void initIfNotAlready() {\n        if (!mInitialized) {\n            mInitialized = true;\n            mFirstFieldCount = mCurrentFieldCount;\n        }\n    }\n}"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/io/DirectoryUtils.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.io;\n\nimport java.util.Set;\n\npublic class DirectoryUtils {\n    private static boolean isDirectoryChanged(Path directory, long sinceTimestamp, int maxDepth,\n                                              Set<String> ignoredDirs, int currentDepth) {\n        // Check depth limit\n        if (currentDepth > maxDepth) {\n            return false;\n        }\n\n        // Ensure it's a valid directory\n        if (!directory.exists() || !directory.isDirectory()) {\n            return false;\n        }\n\n        try {\n            Path[] files = directory.listFiles();\n            for (Path file : files) {\n                // Skip ignored folders\n                if (file.isDirectory() && ignoredDirs.contains(file.getName())) {\n                    continue;\n                }\n\n                // Check if file/directory has been modified since timestamp\n                if (file.lastModified() > sinceTimestamp ||\n                        file.creationTime() > sinceTimestamp) {\n                    return true;\n                }\n\n                // Recursively check subdirectories\n                if (file.isDirectory() && currentDepth < maxDepth) {\n                    if (isDirectoryChanged(file, sinceTimestamp, maxDepth, ignoredDirs,\n                            currentDepth + 1)) {\n                        // Early return\n                        return true;\n                    }\n                }\n            }\n        } catch (SecurityException e) {\n            // Handle permission errors gracefully\n            return false;\n        }\n        return false; // No changes detected\n    }\n\n    public static boolean isDirectoryChanged(Path directoryPath, long sinceTimestamp,\n                                             int maxDepth, Set<String> ignoredDirs) {\n        return isDirectoryChanged(directoryPath, sinceTimestamp, maxDepth, ignoredDirs, 0);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/io/LocalFileOverlay.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.io;\n\nimport static io.github.muntashirakon.AppManager.compat.PackageManagerCompat.MATCH_STATIC_SHARED_AND_SDK_LIBRARIES;\nimport static io.github.muntashirakon.AppManager.compat.PackageManagerCompat.MATCH_UNINSTALLED_PACKAGES;\n\nimport android.content.pm.ApplicationInfo;\nimport android.os.Build;\nimport android.os.RemoteException;\nimport android.os.UserHandleHidden;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport java.io.File;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport io.github.muntashirakon.AppManager.compat.PackageManagerCompat;\n\nfinal class LocalFileOverlay {\n    private static final String[] ROOT_FILES = new String[]{\"acct\", \"apex\", \"audit_filter_table\", \"bin\", \"bugreports\",\n            \"cache\", \"carrier\", \"config\", \"d\", \"data\", \"data_mirror\", \"debug_ramdisk\", \"default.prop\", \"dev\", \"dpolicy\",\n            \"dsp\", \"efs\", \"etc\", \"init\", \"init.container.rc\", \"init.environ.rc\", \"lib\", \"linkerconfig\", \"lost+found\",\n            \"metadata\", \"mnt\", \"odm\", \"odm_dklm\", \"oem\", \"omr\", \"oneplus\", \"op1\", \"postinstall\", \"proc\", \"product\",\n            \"sdcard\", \"second_state_resources\", \"sepolicy_version\", \"spu\", \"storage\", \"sys\", \"system\", \"system_ext\",\n            \"vendor\", \"vendor_dlkm\"};\n    // There might be more, but these are what I've got for now (also, /system/apex)\n    private static final String[] APEX_PKGS = new String[]{\n            \"com.android.adbd\",\n            \"com.android.adservices\",\n            \"com.android.appsearch\",\n            \"com.android.art\",\n            \"com.android.art.debug\",\n            \"com.android.art.release\",\n            \"com.android.bluetooth\",\n            \"com.android.bootanimation\",\n            \"com.android.btservices\",\n            \"com.android.car.framework\",\n            \"com.android.cellbroadcast\",\n            \"com.android.conscrypt\",\n            \"com.android.devicelock\",\n            \"com.android.extservices\",\n            \"com.android.extservices.gms\",\n            \"com.android.federatedcompute\",\n            \"com.android.geotz\",\n            \"com.android.gki\",\n            \"com.android.healthfitness\",\n            \"com.android.i18n\",\n            \"com.android.ipsec\",\n            \"com.android.media\",\n            \"com.android.media.swcodec\",\n            \"com.android.mediaprovider\",\n            \"com.android.neuralnetworks\",\n            \"com.android.ondevicepersonalization\",\n            \"com.android.os.statsd\",\n            \"com.android.permission\",\n            \"com.android.permission.gms\",\n            \"com.android.resolv\",\n            \"com.android.rkpd\",\n            \"com.android.runtime\",\n            \"com.android.scheduling\",\n            \"com.android.sdkext\",\n            \"com.android.sepolicy\",\n            \"com.android.telephony\",\n            \"com.android.tethering\",\n            \"com.android.tethering.inprocess\",\n            \"com.android.tzdata\",\n            \"com.android.uwb\",\n            \"com.android.virt\",\n            \"com.android.vndk\",\n            \"com.android.vndk.current\",\n            \"com.android.vndk.v\" + Build.VERSION.SDK_INT,\n            \"com.android.wifi\",\n    };\n    private static final String[] DATA_FILES = new String[]{\"app\", \"app-ephemeral\", \"app-lib\", \"cache\", \"dalvik-cache\",\n            \"data\", \"local\", \"media\", \"misc\", \"misc_ce\", \"misc_de\", \"per_boot\", \"resource-cache\", \"rollback\",\n            \"rollback-observer\", \"ss\", \"system\", \"system_ce\", \"system_de\", \"user\", \"user_ce\", \"user_de\", \"vendor\",\n            \"vendor_ce\", \"vendor_de\"};\n    // Read-only here means whether this should be accessed by ReadOnlyDirectory, it has nothing to do with the actual mode of the file.\n    private static final HashMap<String, String[]> sPathReadOnlyMap = new HashMap<String, String[]>() {{\n        int userId = UserHandleHidden.myUserId();\n        String appId;\n        try {\n            appId = (String) Class.forName(\"io.github.muntashirakon.AppManager.BuildConfig\").getDeclaredField(\"APPLICATION_ID\").get(null);\n        } catch (Exception e) {\n            appId = \"io.github.muntashirakon.AppManager\" + (BuildConfig.DEBUG ? \".debug\" : \"\");\n        }\n        put(\"/\", ROOT_FILES); // Permission denied\n        put(\"/apex\", APEX_PKGS); // Permission denied\n        put(\"/data\", DATA_FILES); // Permission denied\n        put(\"/data/app\", null); // Permission denied\n        put(\"/data/data\", new String[]{appId}); // Permission denied\n        put(\"/data/local\", new String[]{\"tmp\"}); // Permission denied\n        put(\"/data/misc\", new String[]{\"ethernet\", \"gcov\", \"keychain\", \"profiles\", \"textclassifier\", \"user\", \"zoneinfo\"});\n        put(\"/data/misc/user\", new String[]{appId});\n        put(\"/data/misc/profiles\", new String[]{\"cur\"});\n        put(\"/data/misc/profiles/cur\", new String[]{appId});\n        put(\"/data/misc_ce\", new String[]{String.valueOf(userId)}); // Permission denied\n        put(\"/data/misc_de\", new String[]{String.valueOf(userId)}); // Permission denied\n        put(\"/data/user\", new String[]{String.valueOf(userId)}); // Permission denied\n        put(\"/data/user/\" + userId, new String[]{appId}); // Permission denied\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {\n            put(\"/data/user_de\", new String[]{String.valueOf(userId)}); // Permission denied\n            put(\"/data/user_de/\" + userId, new String[]{appId}); // Permission denied\n        }\n        put(\"/mnt/sdcard\", new String[]{\"/storage/self/primary\"}); // Permission denied, but redirects to /storage/self/primary\n        put(\"/storage\", new String[]{\"emulated\", \"self\"}); // Permission denied\n        put(\"/storage/emulated\", new String[]{String.valueOf(userId)}); // Permission denied\n    }};\n\n    @NonNull\n    public static ExtendedFile getOverlayFile(@NonNull ExtendedFile file) {\n        ExtendedFile file1 = getOverlayFileOrNull(file);\n        return file1 != null ? file1 : file;\n    }\n\n    @Nullable\n    public static ExtendedFile getOverlayFileOrNull(@NonNull ExtendedFile file) {\n        String path = Paths.sanitize(file.getAbsolutePath(), false);\n        if (path == null) {\n            return null;\n        }\n        String[] children = listChildrenInternal(path);\n        if (children != null) {\n            // Check for potential alias\n            for (String child : children) {\n                if (child.startsWith(File.separator)) {\n                    return ReadOnlyLocalFile.getAliasInstance(path, child);\n                }\n            }\n            // No alias found\n            return new ReadOnlyLocalFile(path);\n        }\n        // No overlay needed\n        return null;\n    }\n\n    @Nullable\n    public static String[] listChildren(@NonNull File file) {\n        return listChildrenInternal(Paths.sanitize(file.getAbsolutePath(), false));\n    }\n\n    @Nullable\n    private static String[] listChildrenInternal(@Nullable String path) {\n        if (path == null) {\n            return null;\n        }\n        if (path.equals(\"/data/app\")) {\n            fetchDataAppPaths();\n        }\n        return sPathReadOnlyMap.get(path);\n    }\n\n    @SuppressWarnings(\"SuspiciousRegexArgument\") // Not on windows\n    public static void fetchDataAppPaths() {\n        if (sPathReadOnlyMap.get(\"/data/app\") != null) {\n            return;\n        }\n        List<ApplicationInfo> applicationInfoList = null;\n        try {\n            applicationInfoList = PackageManagerCompat.getInstalledApplications(MATCH_STATIC_SHARED_AND_SDK_LIBRARIES | MATCH_UNINSTALLED_PACKAGES, UserHandleHidden.myUserId());\n        } catch (RemoteException ignore) {\n        }\n        if (applicationInfoList == null) {\n            return;\n        }\n        Map<String, List<String>> paths = new HashMap<>();\n        for (ApplicationInfo info : applicationInfoList) {\n            if (info.publicSourceDir == null) {\n                continue;\n            }\n            String path = new File(info.publicSourceDir).getParent();\n            if (path == null || !path.startsWith(\"/data/app/\")) {\n                continue;\n            }\n            path = path.substring(10); // \"/data/app/\".length()\n            // Remaining path is required one. It can contain either two or one paths\n            String[] pathParts = path.split(File.separator);\n            switch (pathParts.length) {\n                case 1:\n                    paths.put(pathParts[0], null);\n                    break;\n                case 2: {\n                    String part1 = pathParts[0];\n                    List<String> part2 = paths.get(part1);\n                    if (part2 == null) {\n                        part2 = new ArrayList<>();\n                        paths.put(part1, part2);\n                    }\n                    part2.add(pathParts[1]);\n                    break;\n                }\n            }\n        }\n        // Update pathReadOnlyMap\n        sPathReadOnlyMap.put(\"/data/app\", paths.keySet().toArray(new String[0]));\n        for (String part1 : paths.keySet()) {\n            List<String> part2 = paths.get(part1);\n            if (part2 == null) {\n                continue;\n            }\n            sPathReadOnlyMap.put(\"/data/app/\" + part1, part2.toArray(new String[0]));\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/io/PathAttributesImpl.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.io;\n\nimport android.content.ContentResolver;\nimport android.content.Context;\nimport android.database.Cursor;\nimport android.net.Uri;\nimport android.provider.DocumentsContract;\nimport android.system.OsConstants;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.core.provider.DocumentsContractCompat;\nimport androidx.documentfile.provider.DocumentFile;\nimport androidx.documentfile.provider.DocumentFileUtils;\nimport androidx.documentfile.provider.ExtendedRawDocumentFile;\nimport androidx.documentfile.provider.VirtualDocumentFile;\n\nimport java.io.IOException;\n\nimport io.github.muntashirakon.AppManager.utils.ExUtils;\n\nclass PathAttributesImpl extends PathAttributes {\n    @NonNull\n    public static PathAttributesImpl fromFile(@NonNull ExtendedRawDocumentFile file) {\n        ExtendedFile f = file.getFile();\n        int mode = ExUtils.requireNonNullElse(f::getMode, 0);\n        return new PathAttributesImpl(f.getName(), file.getType(), f.lastModified(), f.lastAccess(), f.creationTime(),\n                OsConstants.S_ISREG(mode), OsConstants.S_ISDIR(mode), OsConstants.S_ISLNK(mode), f.length());\n    }\n\n    @NonNull\n    public static PathAttributesImpl fromVirtual(@NonNull VirtualDocumentFile file) {\n        int mode = file.getMode();\n        return new PathAttributesImpl(file.getName(), file.getType(), file.lastModified(), file.lastAccess(), file.creationTime(),\n                OsConstants.S_ISREG(mode), OsConstants.S_ISDIR(mode), OsConstants.S_ISLNK(mode), file.length());\n    }\n\n    @NonNull\n    public static PathAttributesImpl fromSaf(@NonNull Context context, @NonNull DocumentFile safDocumentFile)\n            throws IOException {\n        Uri documentUri = safDocumentFile.getUri();\n        ContentResolver resolver = context.getContentResolver();\n        try (Cursor c = resolver.query(documentUri, null, null, null, null)) {\n            if (!c.moveToFirst()) {\n                throw new IOException(\"Could not fetch attributes for tree \" + documentUri);\n            }\n            String[] columns = c.getColumnNames();\n            String name = null;\n            String type = null;\n            long lastModified = 0;\n            long size = 0;\n            for (int i = 0; i < columns.length; ++i) {\n                switch (columns[i]) {\n                    case DocumentsContract.Document.COLUMN_DISPLAY_NAME:\n                        name = c.getString(i);\n                        break;\n                    case DocumentsContract.Document.COLUMN_MIME_TYPE:\n                        type = c.getString(i);\n                        break;\n                    case DocumentsContract.Document.COLUMN_LAST_MODIFIED:\n                        lastModified = c.getLong(i);\n                        break;\n                    case DocumentsContract.Document.COLUMN_SIZE:\n                        size = c.getLong(i);\n                        break;\n                }\n            }\n            boolean isDirectory = DocumentsContract.Document.MIME_TYPE_DIR.equals(type);\n            if (name == null) {\n                name = DocumentFileUtils.resolveAltNameForSaf(safDocumentFile);\n            }\n            return new PathAttributesImpl(name, type, lastModified, 0, 0, !isDirectory, isDirectory,\n                    false, size);\n        } catch (IOException e) {\n            throw e;\n        } catch (Exception e) {\n            throw new IOException(e);\n        }\n    }\n\n    @NonNull\n    public static PathAttributesImpl fromSafTreeCursor(@NonNull Uri treeUri, @NonNull Cursor c) {\n        if (!DocumentsContractCompat.isTreeUri(treeUri)) {\n            throw new IllegalArgumentException(\"Not a tree document.\");\n        }\n        String[] columns = c.getColumnNames();\n        String name = null;\n        String type = null;\n        long lastModified = 0;\n        long size = 0;\n        for (int i = 0; i < columns.length; ++i) {\n            switch (columns[i]) {\n                case DocumentsContract.Document.COLUMN_DISPLAY_NAME:\n                    name = c.getString(i);\n                    break;\n                case DocumentsContract.Document.COLUMN_MIME_TYPE:\n                    type = c.getString(i);\n                    break;\n                case DocumentsContract.Document.COLUMN_LAST_MODIFIED:\n                    lastModified = c.getLong(i);\n                    break;\n                case DocumentsContract.Document.COLUMN_SIZE:\n                    size = c.getLong(i);\n                    break;\n            }\n        }\n        boolean isDirectory = DocumentsContract.Document.MIME_TYPE_DIR.equals(type);\n        if (name == null) {\n            name = DocumentFileUtils.resolveAltNameForTreeUri(treeUri);\n        }\n        return new PathAttributesImpl(name, type, lastModified, 0, 0, !isDirectory, isDirectory,\n                false, size);\n    }\n\n    private PathAttributesImpl(@NonNull String displayName, @Nullable String mimeType, long lastModified, long lastAccess,\n                               long creationTime, boolean isRegularFile, boolean isDirectory, boolean isSymbolicLink,\n                               long size) {\n        super(displayName, mimeType, lastModified, lastAccess, creationTime, isRegularFile, isDirectory, isSymbolicLink,\n                size);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/io/PathContentInfoImpl.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.io;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport com.j256.simplemagic.ContentInfo;\nimport com.j256.simplemagic.ContentInfoUtil;\n\nimport java.io.InputStream;\nimport java.util.Arrays;\nimport java.util.HashMap;\nimport java.util.HashSet;\n\nimport io.github.muntashirakon.AppManager.fm.ContentType2;\nimport io.github.muntashirakon.AppManager.logs.Log;\n\nclass PathContentInfoImpl extends PathContentInfo {\n    public static final String TAG = PathContentInfoImpl.class.getSimpleName();\n    // Associations not present in ContentInfoUtil, they're derived from simple-name\n    private static final HashMap<String, String> sSimpleNameMimeAssociations = new HashMap<String, String>() {{\n        put(\"SQLite\", \"application/vnd.sqlite3\");\n    }};\n\n    private static final HashMap<String, Boolean> sPartialOverrides = new HashMap<String, Boolean>() {{\n        put(\"application/zip\", true);\n    }};\n\n    private static ContentInfoUtil sContentInfoUtil;\n\n    @NonNull\n    public static PathContentInfoImpl fromExtension(@NonNull Path path) {\n        if (path.isDirectory()) {\n            return DIRECTORY;\n        }\n        String ext = path.getExtension();\n        ContentInfo extInfo = ext != null ? ContentInfoUtil.findExtensionMatch(ext) : null;\n        ContentType2 extType2 = ext != null ? ContentType2.fromFileExtension(ext) : null;\n        if (extInfo != null) {\n            return withPartialOverride(fromContentInfo(extInfo), extType2);\n        }\n        if (extType2 != null) {\n            return fromContentType2(extType2);\n        }\n        return fromContentType2(ContentType2.OTHER);\n    }\n\n    @NonNull\n    public static PathContentInfoImpl fromPath(@NonNull Path path) {\n        if (path.isDirectory()) {\n            return DIRECTORY;\n        }\n        if (sContentInfoUtil == null) {\n            sContentInfoUtil = new ContentInfoUtil();\n        }\n        String ext = path.getExtension();\n        ContentInfo extInfo = ext != null ? ContentInfoUtil.findExtensionMatch(ext) : null;\n        ContentType2 extType2 = ext != null ? ContentType2.fromFileExtension(ext) : null;\n        try (InputStream is = path.openInputStream()) {\n            ContentInfo contentInfo = sContentInfoUtil.findMatch(is);\n            if (contentInfo != null) {\n                // FIXME: 20/11/22 This will not work for invalid extensions. A better option is to use magic-mime-db\n                //  instead which is currently a WIP.\n                if (extInfo != null) {\n                    return withPartialOverride(fromPathContentInfo(\n                            new PathContentInfoImpl(extInfo.getName(), contentInfo.getMessage(), extInfo.getMimeType(),\n                                    extInfo.getFileExtensions(), contentInfo.isPartial())), extType2);\n                }\n                if (extType2 != null) {\n                    return fromPathContentInfo(new PathContentInfoImpl(extType2.getSimpleName(), contentInfo.getMessage(),\n                            extType2.getMimeType(), extType2.getFileExtensions(), contentInfo.isPartial()));\n                }\n                return fromContentInfo(contentInfo);\n            }\n        } catch (Throwable e) {\n            Log.e(TAG, \"Could not load MIME type for path %s\", e, path);\n        }\n        if (extInfo != null) {\n            return withPartialOverride(fromContentInfo(extInfo), extType2);\n        }\n        if (extType2 != null) {\n            return fromContentType2(extType2);\n        }\n        return fromContentType2(ContentType2.OTHER);\n    }\n\n    private static PathContentInfoImpl withPartialOverride(@NonNull PathContentInfoImpl contentInfo, @Nullable ContentType2 contentType2) {\n        if (contentType2 != null) {\n            boolean partial = contentInfo.isPartial() || Boolean.TRUE.equals(sPartialOverrides.get(contentInfo.getMimeType()));\n            if (partial) {\n                // Override MIME type, name and extension\n                return new PathContentInfoImpl(contentType2.getSimpleName(), contentInfo.getMessage(),\n                        contentType2.getMimeType(), contentType2.getFileExtensions(), false);\n            }\n        }\n        return contentInfo;\n    }\n\n    @NonNull\n    private static PathContentInfoImpl fromContentInfo(@NonNull ContentInfo contentInfo) {\n        String mime = sSimpleNameMimeAssociations.get(contentInfo.getName());\n        if (mime != null) {\n            ContentType2 contentType2 = ContentType2.fromMimeType(mime);\n            // Association exists, replace MIME type and merge file extensions\n            HashSet<String> extensions = new HashSet<>();\n            if (contentInfo.getFileExtensions() != null) {\n                extensions.addAll(Arrays.asList(contentInfo.getFileExtensions()));\n            }\n            if (contentType2.getFileExtensions() != null) {\n                extensions.addAll(Arrays.asList(contentType2.getFileExtensions()));\n            }\n            return new PathContentInfoImpl(contentInfo.getName(), contentInfo.getMessage(), mime,\n                    extensions.isEmpty() ? null : extensions.toArray(new String[0]), contentInfo.isPartial());\n        }\n        return new PathContentInfoImpl(contentInfo.getName(), contentInfo.getMessage(), contentInfo.getMimeType(),\n                contentInfo.getFileExtensions(), contentInfo.isPartial());\n    }\n\n    @NonNull\n    private static PathContentInfoImpl fromPathContentInfo(@NonNull PathContentInfoImpl contentInfo) {\n        String mime = sSimpleNameMimeAssociations.get(contentInfo.getName());\n        if (mime != null) {\n            ContentType2 contentType2 = ContentType2.fromMimeType(mime);\n            // Association exists, replace MIME type and merge file extensions\n            HashSet<String> extensions = new HashSet<>();\n            if (contentInfo.getFileExtensions() != null) {\n                extensions.addAll(Arrays.asList(contentInfo.getFileExtensions()));\n            }\n            if (contentType2.getFileExtensions() != null) {\n                extensions.addAll(Arrays.asList(contentType2.getFileExtensions()));\n            }\n            return new PathContentInfoImpl(contentInfo.getName(), contentInfo.getMessage(), mime,\n                    extensions.isEmpty() ? null : extensions.toArray(new String[0]), contentInfo.isPartial());\n        }\n        return contentInfo;\n    }\n\n    @NonNull\n    private static PathContentInfoImpl fromContentType2(@NonNull ContentType2 contentType2) {\n        return new PathContentInfoImpl(contentType2.getSimpleName(), null, contentType2.getMimeType(),\n                contentType2.getFileExtensions(), false);\n    }\n\n    private static final PathContentInfoImpl DIRECTORY = new PathContentInfoImpl(\"Directory\", null,\n            \"resource/folder\", null, false);\n\n\n    private PathContentInfoImpl(@NonNull String name, @Nullable String message, @Nullable String mimeType,\n                                @Nullable String[] fileExtensions, boolean partial) {\n        super(name, message, mimeType, fileExtensions, partial);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/io/PathImpl.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.io;\n\nimport android.Manifest;\nimport android.content.ContentResolver;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.pm.ResolveInfo;\nimport android.net.Uri;\nimport android.os.Build;\nimport android.os.Handler;\nimport android.os.ParcelFileDescriptor;\nimport android.os.Process;\nimport android.os.RemoteException;\nimport android.os.UserHandleHidden;\nimport android.provider.DocumentsContract;\nimport android.system.ErrnoException;\nimport android.system.OsConstants;\nimport android.text.TextUtils;\nimport android.util.Log;\nimport android.webkit.MimeTypeMap;\n\nimport androidx.annotation.CheckResult;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.core.provider.DocumentsContractCompat;\nimport androidx.core.util.Pair;\nimport androidx.documentfile.provider.DocumentFile;\nimport androidx.documentfile.provider.DocumentFileUtils;\nimport androidx.documentfile.provider.ExtendedRawDocumentFile;\nimport androidx.documentfile.provider.MediaDocumentFile;\nimport androidx.documentfile.provider.VirtualDocumentFile;\n\nimport java.io.File;\nimport java.io.FileNotFoundException;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.nio.ByteBuffer;\nimport java.nio.channels.FileChannel;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Objects;\n\nimport io.github.muntashirakon.AppManager.compat.StorageManagerCompat;\nimport io.github.muntashirakon.AppManager.ipc.LocalServices;\nimport io.github.muntashirakon.AppManager.self.SelfPermissions;\nimport io.github.muntashirakon.AppManager.utils.ContextUtils;\nimport io.github.muntashirakon.AppManager.utils.FileUtils;\nimport io.github.muntashirakon.io.fs.VirtualFileSystem;\n\n/**\n * Provide an interface to {@link File} and {@link DocumentFile} with basic functionalities.\n */\nclass PathImpl extends Path {\n    public static final String TAG = PathImpl.class.getSimpleName();\n\n    private static final List<Boolean> EXCLUSIVE_ACCESS_GRANTED = new ArrayList<>();\n    private static final List<String> EXCLUSIVE_ACCESS_PATHS = new ArrayList<>();\n\n    static {\n        setAccessPaths();\n    }\n\n    private static void setAccessPaths() {\n        if (Process.myUid() == Process.ROOT_UID || Process.myUid() == Process.SYSTEM_UID || Process.myUid() == Process.SHELL_UID) {\n            // Root/ADB\n            return;\n        }\n        // We cannot use Path API here\n        // Read-write\n        Context context = ContextUtils.getContext();\n        EXCLUSIVE_ACCESS_PATHS.add(Objects.requireNonNull(context.getFilesDir().getParentFile()).getAbsolutePath());\n        EXCLUSIVE_ACCESS_GRANTED.add(true);\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {\n            EXCLUSIVE_ACCESS_PATHS.add(context.createDeviceProtectedStorageContext().getDataDir().getAbsolutePath());\n            EXCLUSIVE_ACCESS_GRANTED.add(true);\n        }\n        File[] extDirs = context.getExternalCacheDirs();\n        if (extDirs != null) {\n            for (File dir : extDirs) {\n                if (dir == null) continue;\n                EXCLUSIVE_ACCESS_PATHS.add(Objects.requireNonNull(dir.getParentFile()).getAbsolutePath());\n                EXCLUSIVE_ACCESS_GRANTED.add(true);\n            }\n        }\n        if (SelfPermissions.checkSelfStoragePermission()) {\n            int userId = UserHandleHidden.myUserId();\n            String[] cards;\n            if (userId == 0) {\n                cards = new String[]{\n                        \"/sdcard\",\n                        \"/storage/emulated/\" + userId,\n                        \"/storage/self/primary\"\n                };\n            } else cards = new String[]{\"/storage/emulated/\" + userId};\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {\n                // Add Android/data and Android/obb to the exemption list\n                boolean canInstallApps = SelfPermissions.checkSelfPermission(Manifest.permission.REQUEST_INSTALL_PACKAGES)\n                        || SelfPermissions.checkSelfPermission(Manifest.permission.INSTALL_PACKAGES);\n                for (String card : cards) {\n                    EXCLUSIVE_ACCESS_PATHS.add(card + \"/Android/data\");\n                    EXCLUSIVE_ACCESS_GRANTED.add(false);\n                    if (!canInstallApps) {\n                        EXCLUSIVE_ACCESS_PATHS.add(card + \"/Android/obb\");\n                        EXCLUSIVE_ACCESS_GRANTED.add(false);\n                    }\n                }\n            }\n            // Lowest priority\n            for (String card : cards) {\n                EXCLUSIVE_ACCESS_PATHS.add(card);\n                EXCLUSIVE_ACCESS_GRANTED.add(true);\n            }\n        }\n        // Assert sizes\n        if (EXCLUSIVE_ACCESS_PATHS.size() != EXCLUSIVE_ACCESS_GRANTED.size()) {\n            throw new RuntimeException();\n        }\n    }\n\n    private static boolean needPrivilegedAccess(@NonNull String path) {\n        if (Process.myUid() == Process.ROOT_UID || Process.myUid() == Process.SYSTEM_UID || Process.myUid() == Process.SHELL_UID) {\n            // Root/shell\n            return false;\n        }\n        for (int i = 0; i < EXCLUSIVE_ACCESS_PATHS.size(); ++i) {\n            if (path.startsWith(EXCLUSIVE_ACCESS_PATHS.get(i))) {\n                // May need no privileged access\n                return !EXCLUSIVE_ACCESS_GRANTED.get(i);\n            }\n        }\n        return true;\n    }\n\n    @NonNull\n    private static DocumentFile getRequiredRawDocument(@NonNull String path) {\n        if (needPrivilegedAccess(path) && LocalServices.alive()) {\n            try {\n                FileSystemManager fs = LocalServices.getFileSystemManager();\n                return new ExtendedRawDocumentFile(fs.getFile(path));\n            } catch (RemoteException e) {\n                Log.w(TAG, \"Could not get privileged access to path \" + path + \" due to \\\"\" + e.getMessage() + \"\\\"\");\n                // Fall-back to unprivileged access\n            }\n        }\n        ExtendedFile file = FileSystemManager.getLocal().getFile(path);\n        return new ExtendedRawDocumentFile(LocalFileOverlay.getOverlayFile(file));\n    }\n\n    // An invalid MIME so that it doesn't match any extension\n    private static final String DEFAULT_MIME = \"application/x-invalid-mime-type\";\n\n    /* package */ PathImpl(@NonNull Context context, @NonNull String fileLocation) {\n        super(context, getRequiredRawDocument(fileLocation));\n    }\n\n    /* package */ PathImpl(@NonNull Context context, @NonNull VirtualFileSystem fs) {\n        super(context, new VirtualDocumentFile(getParentFile(context, fs), fs));\n    }\n\n    /* package */ PathImpl(@NonNull Context context, @NonNull String fileLocation, boolean privileged) throws RemoteException {\n        super(context, null);\n        if (privileged) {\n            FileSystemManager fs = LocalServices.getFileSystemManager();\n            documentFile = new ExtendedRawDocumentFile(fs.getFile(fileLocation));\n        } else {\n            ExtendedFile file = FileSystemManager.getLocal().getFile(fileLocation);\n            documentFile = new ExtendedRawDocumentFile(LocalFileOverlay.getOverlayFile(file));\n        }\n    }\n\n    /* package */ PathImpl(@NonNull Context context, @NonNull Uri uri) {\n        super(context, null);\n        // At first check if the Uri is in VFS since it gets higher priority.\n        Path fsRoot = VirtualFileSystem.getFsRoot(uri);\n        if (fsRoot != null) {\n            documentFile = fsRoot.documentFile;\n            return;\n        }\n        if (uri.getScheme() == null) {\n            throw new IllegalArgumentException(\"Uri has no scheme: \" + uri);\n        }\n        DocumentFile documentFile;\n        switch (uri.getScheme()) {\n            case ContentResolver.SCHEME_CONTENT:\n                if (isDocumentsProvider(context, uri.getAuthority())) { // We can't use DocumentsContract.isDocumentUri() because it expects something that isn't always correct\n                    boolean isTreeUri = DocumentsContractCompat.isTreeUri(uri);\n                    documentFile = Objects.requireNonNull(isTreeUri ? DocumentFile.fromTreeUri(context, uri) : DocumentFile.fromSingleUri(context, uri));\n                } else {\n                    // Content provider\n                    documentFile = new MediaDocumentFile(null, context, uri);\n                }\n                break;\n            case ContentResolver.SCHEME_FILE:\n                documentFile = getRequiredRawDocument(uri.getPath());\n                break;\n            case VirtualFileSystem.SCHEME: {\n                Pair<Integer, String> parsedUri = VirtualDocumentFile.parseUri(uri);\n                if (parsedUri != null) {\n                    Path rootPath = VirtualFileSystem.getFsRoot(parsedUri.first);\n                    if (rootPath != null) {\n                        String path = Paths.sanitize(parsedUri.second, true);\n                        if (TextUtils.isEmpty(path) || path.equals(File.separator)) {\n                            // Root requested\n                            documentFile = rootPath.documentFile;\n                        } else {\n                            // Find file is acceptable here since the file always exists\n                            String[] pathComponents = path.split(File.separator);\n                            DocumentFile finalDocumentFile = rootPath.documentFile;\n                            for (String pathComponent : pathComponents) {\n                                finalDocumentFile = Objects.requireNonNull(finalDocumentFile.findFile(pathComponent));\n                            }\n                            documentFile = finalDocumentFile;\n                        }\n                        break;\n                    }\n                }\n            }\n            default:\n                throw new IllegalArgumentException(\"Unsupported uri \" + uri);\n        }\n        // Setting mDocumentFile at the end ensures that it is never null\n        this.documentFile = documentFile;\n    }\n\n    /**\n     * NOTE: This construct is only applicable for tree Uri\n     */\n    /* package */ PathImpl(@Nullable Path parent, @NonNull Context context, @NonNull Uri documentUri) {\n        super(context, null);\n        DocumentFile parentDocumentFile = parent != null ? parent.documentFile : null;\n        documentFile = DocumentFileUtils.newTreeDocumentFile(parentDocumentFile, context, documentUri);\n    }\n\n    private PathImpl(@NonNull Context context, @NonNull DocumentFile documentFile) {\n        super(context, null);\n        if (documentFile instanceof ExtendedRawDocumentFile) {\n            ExtendedFile file = ((ExtendedRawDocumentFile) documentFile).getFile();\n            if (file instanceof LocalFile) {\n                ExtendedFile newFile = LocalFileOverlay.getOverlayFileOrNull(file);\n                if (newFile != null) {\n                    documentFile = new ExtendedRawDocumentFile(newFile);\n                }\n            }\n        }\n        this.documentFile = documentFile;\n    }\n\n    @NonNull\n    public String getName() {\n        // Last path segment is required.\n        String name = documentFile.getName();\n        if (name != null) {\n            return name;\n        }\n        return DocumentFileUtils.resolveAltNameForSaf(documentFile);\n    }\n\n\n    /**\n     * Return the underlying {@link ExtendedFile} if the path is backed by a real file,\n     * {@code null} otherwise.\n     */\n    @Nullable\n    public ExtendedFile getFile() {\n        if (documentFile instanceof ExtendedRawDocumentFile) {\n            return ((ExtendedRawDocumentFile) documentFile).getFile();\n        }\n        return null;\n    }\n\n    /**\n     * Same as {@link #getFile()} except it return a raw string.\n     */\n    @Nullable\n    public String getFilePath() {\n        if (documentFile instanceof ExtendedRawDocumentFile) {\n            return documentFile.getUri().getPath();\n        }\n        return null;\n    }\n\n    /**\n     * Same as {@link #getFile()} except it returns the real path if the\n     * current path is a symbolic link.\n     */\n    @Nullable\n    public String getRealFilePath() throws IOException {\n        if (documentFile instanceof ExtendedRawDocumentFile) {\n            return Objects.requireNonNull(getFile()).getCanonicalPath();\n        }\n        return null;\n    }\n\n    /**\n     * Same as {@link #getFile()} except it returns the real path if the\n     * current path is a symbolic link.\n     */\n    @Nullable\n    public Path getRealPath() throws IOException {\n        if (documentFile instanceof ExtendedRawDocumentFile) {\n            return Paths.get(Objects.requireNonNull(getFile()).getCanonicalFile());\n        }\n        return null;\n    }\n\n    @NonNull\n    public String getType() {\n        String type = getRealDocumentFile(documentFile).getType();\n        if (type == null) {\n            type = PathContentInfoImpl.fromExtension(this).getMimeType();\n        }\n        if (type == null) {\n            type = \"application/octet-stream\";\n        }\n        return type;\n    }\n\n    @NonNull\n    public PathContentInfo getPathContentInfo() {\n        return PathContentInfoImpl.fromPath(this);\n    }\n\n    @CheckResult\n    public long length() {\n        return getRealDocumentFile(documentFile).length();\n    }\n\n    @CheckResult\n    public boolean recreate() {\n        DocumentFile documentFile = getRealDocumentFile(this.documentFile);\n        if (documentFile.isDirectory()) {\n            // Directory does not need to be created again.\n            return true;\n        }\n        if (documentFile.exists() && !documentFile.isFile()) return false;\n        // For Linux documents, recreate using file APIs\n        if (documentFile instanceof ExtendedRawDocumentFile) {\n            try {\n                File f = Objects.requireNonNull(((ExtendedRawDocumentFile) documentFile).getFile());\n                if (f.exists()) f.delete();\n                return f.createNewFile();\n            } catch (IOException | SecurityException e) {\n                return false;\n            }\n        }\n        // In other cases, open OutputStream to make the file empty.\n        // We can directly use openOutputStream because if it were a mount point, it would be a directory.\n        try (OutputStream ignored = openOutputStream(false)) {\n            return true;\n        } catch (IOException e) {\n            return false;\n        }\n    }\n\n    @NonNull\n    public Path createNewFile(@NonNull String displayName, @Nullable String mimeType) throws IOException {\n        displayName = Paths.sanitize(displayName, true);\n        if (displayName == null) {\n            throw new IOException(\"Empty display name.\");\n        }\n        return createFileAsDirectChild(context, documentFile, displayName, mimeType);\n    }\n\n    @NonNull\n    public Path createNewDirectory(@NonNull String displayName) throws IOException {\n        displayName = Paths.sanitize(displayName, true);\n        if (displayName == null) {\n            throw new IOException(\"Empty display name.\");\n        }\n        if (displayName.indexOf(File.separatorChar) != -1) {\n            throw new IllegalArgumentException(\"Display name contains file separator.\");\n        }\n        DocumentFile documentFile = getRealDocumentFile(this.documentFile);\n        if (!documentFile.isDirectory()) {\n            throw new IOException(\"Current file is not a directory.\");\n        }\n        checkVfs(Paths.appendPathSegment(documentFile.getUri(), displayName));\n        DocumentFile file = documentFile.createDirectory(displayName);\n        if (file == null) throw new IOException(\"Could not create directory named \" + displayName);\n        return new PathImpl(context, file);\n    }\n\n    @NonNull\n    public Path createNewArbitraryFile(@NonNull String displayName, @Nullable String mimeType) throws IOException {\n        displayName = Paths.sanitize(displayName, true);\n        if (displayName == null) {\n            throw new IOException(\"Empty display name.\");\n        }\n        String[] names = displayName.split(File.separator);\n        if (names.length == 0) {\n            throw new IllegalArgumentException(\"Display name is empty.\");\n        }\n        for (String name : names) {\n            if (name.equals(\"..\")) {\n                throw new IOException(\"Could not create directories in the parent directory.\");\n            }\n        }\n        DocumentFile file = createArbitraryDirectories(documentFile, names, names.length - 1);\n        return createFileAsDirectChild(context, file, names[names.length - 1], mimeType);\n    }\n\n    @NonNull\n    public Path createDirectoriesIfRequired(@NonNull String displayName) throws IOException {\n        displayName = Paths.sanitize(displayName, true);\n        if (displayName == null) {\n            throw new IOException(\"Empty display name.\");\n        }\n        String[] dirNames = displayName.split(File.separator);\n        if (dirNames.length == 0) {\n            throw new IllegalArgumentException(\"Display name is empty\");\n        }\n        for (String name : dirNames) {\n            if (name.equals(\"..\")) {\n                throw new IOException(\"Could not create directories in the parent directory.\");\n            }\n        }\n        DocumentFile file = createArbitraryDirectories(documentFile, dirNames, dirNames.length);\n        return new PathImpl(context, file);\n    }\n\n    @NonNull\n    public Path createDirectories(@NonNull String displayName) throws IOException {\n        displayName = Paths.sanitize(displayName, true);\n        if (displayName == null) {\n            throw new IOException(\"Empty display name.\");\n        }\n        String[] dirNames = displayName.split(File.separator);\n        if (dirNames.length == 0) {\n            throw new IllegalArgumentException(\"Display name is empty\");\n        }\n        for (String name : dirNames) {\n            if (name.equals(\"..\")) {\n                throw new IOException(\"Could not create directories in the parent directory.\");\n            }\n        }\n        DocumentFile file = createArbitraryDirectories(documentFile, dirNames, dirNames.length - 1);\n        // Special case for the last segment\n        String lastSegment = dirNames[dirNames.length - 1];\n        Path fsRoot = VirtualFileSystem.getFsRoot(Paths.appendPathSegment(file.getUri(), lastSegment));\n        DocumentFile t = fsRoot != null ? fsRoot.documentFile : file.findFile(lastSegment);\n        if (t != null) {\n            throw new IOException(t.getUri() + \" already exists.\");\n        }\n        t = file.createDirectory(lastSegment);\n        if (t == null) {\n            throw new IOException(\"Directory\" + file.getUri() + File.separator + lastSegment + \" could not be created.\");\n        }\n        return new PathImpl(context, t);\n    }\n\n    @Nullable\n    public Path getParent() {\n        DocumentFile file = getRealDocumentFile(documentFile).getParentFile();\n        return file == null ? null : new PathImpl(context, file);\n    }\n\n    public boolean hasFile(@NonNull String displayName) {\n        return findFileInternal(documentFile, displayName) != null;\n    }\n\n    @NonNull\n    public Path findFile(@NonNull String displayName) throws FileNotFoundException {\n        DocumentFile nextPath = findFileInternal(documentFile, displayName);\n        if (nextPath == null) {\n            throw new FileNotFoundException(\"Cannot find \" + this + File.separatorChar + displayName);\n        }\n        return new PathImpl(context, nextPath);\n    }\n\n    @NonNull\n    public Path findOrCreateFile(@NonNull String displayName, @Nullable String mimeType) throws IOException {\n        displayName = Paths.sanitize(displayName, true);\n        if (displayName == null) {\n            throw new IOException(\"Empty display name.\");\n        }\n        if (displayName.indexOf(File.separatorChar) != -1) {\n            throw new IllegalArgumentException(\"Display name contains file separator.\");\n        }\n        DocumentFile documentFile = getRealDocumentFile(this.documentFile);\n        if (!documentFile.isDirectory()) {\n            throw new IOException(\"Current file is not a directory.\");\n        }\n        String extension = null;\n        if (mimeType != null) {\n            extension = MimeTypeMap.getSingleton().getExtensionFromMimeType(mimeType);\n        } else mimeType = DEFAULT_MIME;\n        String nameWithExtension = displayName + (extension != null ? \".\" + extension : \"\");\n        checkVfs(Paths.appendPathSegment(documentFile.getUri(), nameWithExtension));\n        DocumentFile file = documentFile.findFile(displayName);\n        if (file != null) {\n            if (file.isDirectory()) {\n                throw new IOException(\"Directory cannot be converted to file\");\n            }\n            return new PathImpl(context, file);\n        }\n        file = documentFile.createFile(mimeType, displayName);\n        if (file == null) {\n            throw new IOException(\"Could not create \" + documentFile.getUri() + File.separatorChar + nameWithExtension + \" with type \" + mimeType);\n        }\n        return new PathImpl(context, file);\n    }\n\n    @NonNull\n    public Path findOrCreateDirectory(@NonNull String displayName) throws IOException {\n        displayName = Paths.sanitize(displayName, true);\n        if (displayName == null) {\n            throw new IOException(\"Empty display name.\");\n        }\n        if (displayName.indexOf(File.separatorChar) != -1) {\n            throw new IllegalArgumentException(\"Display name contains file separator.\");\n        }\n        DocumentFile documentFile = getRealDocumentFile(this.documentFile);\n        if (!documentFile.isDirectory()) {\n            throw new IOException(\"Current file is not a directory.\");\n        }\n        Path fsRoot = VirtualFileSystem.getFsRoot(Paths.appendPathSegment(documentFile.getUri(), displayName));\n        if (fsRoot != null) return fsRoot;\n        DocumentFile file = documentFile.findFile(displayName);\n        if (file != null) {\n            if (!file.isDirectory()) {\n                throw new IOException(\"Existing file is not a directory\");\n            }\n            return new PathImpl(context, file);\n        }\n        file = documentFile.createDirectory(displayName);\n        if (file == null) throw new IOException(\"Could not create directory named \" + displayName);\n        return new PathImpl(context, file);\n    }\n\n    @NonNull\n    public PathAttributes getAttributes() throws IOException {\n        if (documentFile instanceof ExtendedRawDocumentFile) {\n            return PathAttributesImpl.fromFile((ExtendedRawDocumentFile) documentFile);\n        }\n        if (documentFile instanceof VirtualDocumentFile) {\n            return PathAttributesImpl.fromVirtual((VirtualDocumentFile) documentFile);\n        }\n        return PathAttributesImpl.fromSaf(context, documentFile);\n    }\n\n    @CheckResult\n    public boolean exists() {\n        return getRealDocumentFile(documentFile).exists();\n    }\n\n    @CheckResult\n    public boolean isDirectory() {\n        return getRealDocumentFile(documentFile).isDirectory();\n    }\n\n    @CheckResult\n    public boolean isFile() {\n        return getRealDocumentFile(documentFile).isFile();\n    }\n\n    @CheckResult\n    public boolean isVirtual() {\n        return getRealDocumentFile(documentFile).isVirtual();\n    }\n\n    @CheckResult\n    public boolean isSymbolicLink() {\n        if (getRealDocumentFile(documentFile) instanceof ExtendedRawDocumentFile) {\n            return Objects.requireNonNull(getFile()).isSymlink();\n        }\n        return false;\n    }\n\n    public boolean createNewSymbolicLink(String target) {\n        if (getRealDocumentFile(documentFile) instanceof ExtendedRawDocumentFile) {\n            try {\n                return Objects.requireNonNull(getFile()).createNewSymlink(target);\n            } catch (IOException e) {\n                e.printStackTrace();\n            }\n        }\n        return false;\n    }\n\n    public boolean canRead() {\n        return getRealDocumentFile(documentFile).canRead();\n    }\n\n    public boolean canWrite() {\n        return getRealDocumentFile(documentFile).canWrite();\n    }\n\n    public boolean canExecute() {\n        if (getRealDocumentFile(documentFile) instanceof ExtendedRawDocumentFile) {\n            return Objects.requireNonNull(getFile()).canExecute();\n        }\n        return false;\n    }\n\n    public int getMode() {\n        if (documentFile instanceof ExtendedRawDocumentFile) {\n            try {\n                return Objects.requireNonNull(getFile()).getMode();\n            } catch (ErrnoException e) {\n                return 0;\n            }\n        }\n        if (documentFile instanceof VirtualDocumentFile) {\n            return ((VirtualDocumentFile) documentFile).getMode();\n        }\n        return 0;\n    }\n\n    public boolean setMode(int mode) {\n        if (documentFile instanceof ExtendedRawDocumentFile) {\n            try {\n                Objects.requireNonNull(getFile()).setMode(mode);\n                return true;\n            } catch (ErrnoException e) {\n                return false;\n            }\n        }\n        if (documentFile instanceof VirtualDocumentFile) {\n            return ((VirtualDocumentFile) documentFile).setMode(mode);\n        }\n        return false;\n    }\n\n    @Nullable\n    public UidGidPair getUidGid() {\n        if (documentFile instanceof ExtendedRawDocumentFile) {\n            try {\n                return Objects.requireNonNull(getFile()).getUidGid();\n            } catch (ErrnoException e) {\n                return null;\n            }\n        }\n        if (documentFile instanceof VirtualDocumentFile) {\n            return ((VirtualDocumentFile) documentFile).getUidGid();\n        }\n        return null;\n    }\n\n    public boolean setUidGid(UidGidPair uidGidPair) {\n        if (documentFile instanceof ExtendedRawDocumentFile) {\n            try {\n                return Objects.requireNonNull(getFile()).setUidGid(uidGidPair.uid, uidGidPair.gid);\n            } catch (ErrnoException e) {\n                return false;\n            }\n        }\n        if (documentFile instanceof VirtualDocumentFile) {\n            return ((VirtualDocumentFile) documentFile).setUidGid(uidGidPair);\n        }\n        return false;\n    }\n\n    @Nullable\n    public String getSelinuxContext() {\n        if (documentFile instanceof ExtendedRawDocumentFile) {\n            return Objects.requireNonNull(getFile()).getSelinuxContext();\n        }\n        return null;\n    }\n\n    public boolean setSelinuxContext(@Nullable String context) {\n        if (documentFile instanceof ExtendedRawDocumentFile) {\n            if (context == null) {\n                return Objects.requireNonNull(getFile()).restoreSelinuxContext();\n            }\n            return Objects.requireNonNull(getFile()).setSelinuxContext(context);\n        }\n        return false;\n    }\n\n    public boolean isMountPoint() {\n        return VirtualFileSystem.isMountPoint(getUri());\n    }\n\n    public boolean mkdir() {\n        DocumentFile documentFile = getRealDocumentFile(this.documentFile);\n        if (documentFile.exists()) {\n            return false;\n        }\n        if (documentFile instanceof ExtendedRawDocumentFile) {\n            return Objects.requireNonNull(getFile()).mkdir();\n        } else {\n            DocumentFile parent = documentFile.getParentFile();\n            if (parent != null) {\n                DocumentFile thisFile = parent.createDirectory(getName());\n                if (thisFile != null) {\n                    this.documentFile = thisFile;\n                    return true;\n                }\n            }\n        }\n        return false;\n    }\n\n    public boolean mkdirs() {\n        DocumentFile documentFile = getRealDocumentFile(this.documentFile);\n        if (documentFile.exists()) {\n            return false;\n        }\n        if (documentFile instanceof ExtendedRawDocumentFile) {\n            return Objects.requireNonNull(getFile()).mkdirs();\n        }\n        // For others, directory can't be created recursively as parent must exist\n        DocumentFile parent = documentFile.getParentFile();\n        if (parent != null) {\n            DocumentFile thisFile = parent.createDirectory(getName());\n            if (thisFile != null) {\n                this.documentFile = thisFile;\n                return true;\n            }\n        }\n        return false;\n    }\n\n    public boolean renameTo(@NonNull String displayName) {\n        displayName = Paths.sanitize(displayName, true);\n        if (displayName == null) {\n            // Empty display name\n            return false;\n        }\n        if (displayName.contains(File.separator)) {\n            // Display name must belong to the same directory.\n            return false;\n        }\n        DocumentFile parent = documentFile.getParentFile();\n        if (parent == null) {\n            return false;\n        }\n        DocumentFile file = parent.findFile(displayName);\n        if (file != null) {\n            // File exists\n            return false;\n        }\n        Path fsRoot = VirtualFileSystem.getFsRoot(Paths.appendPathSegment(parent.getUri(), displayName));\n        if (fsRoot != null) {\n            // Mount point exists\n            return false;\n        }\n        Uri oldMountPoint = documentFile.getUri();\n        if (documentFile.renameTo(displayName)) {\n            if (VirtualFileSystem.getFileSystem(oldMountPoint) != null) {\n                // Change mount point\n                VirtualFileSystem.alterMountPoint(oldMountPoint, documentFile.getUri());\n            }\n            return true;\n        }\n        return false;\n    }\n\n    public boolean moveTo(@NonNull Path path, boolean override) {\n        DocumentFile source = getRealDocumentFile(documentFile);\n        DocumentFile dest = getRealDocumentFile(path.documentFile);\n        if (!source.exists()) {\n            // Source itself does not exist.\n            return false;\n        }\n        if (dest.exists() && !dest.canWrite()) {\n            // There's no point is attempting to move if the destination is read-only.\n            return false;\n        }\n        if (dest.getUri().toString().startsWith(source.getUri().toString())) {\n            // Destination cannot be the same or a subdirectory of source\n            return false;\n        }\n        if (source instanceof ExtendedRawDocumentFile && dest instanceof ExtendedRawDocumentFile) {\n            // Try Linux-default file move\n            File srcFile = Objects.requireNonNull(((ExtendedRawDocumentFile) source).getFile());\n            File dstFile = Objects.requireNonNull(((ExtendedRawDocumentFile) dest).getFile());\n            // Java rename cannot infer anything about the source and destination. Therefore, hacks are needed\n            if (srcFile.isFile()) { // Source is a file\n                if (dstFile.isDirectory()) {\n                    // Move source file inside this directory\n                    dstFile = new File(dstFile, srcFile.getName());\n                } else if (dstFile.isFile()) {\n                    // If destination is a file, it overrides it\n                    if (!override) {\n                        // Overriding is disabled\n                        return false;\n                    }\n                }\n                // else destination does not exist and Java is able to create it\n            } else if (srcFile.isDirectory()) { // Source is a directory\n                if (dstFile.isDirectory()) {\n                    // Move source directory inside this directory\n                    dstFile = new File(dstFile, srcFile.getName());\n                } else if (dstFile.isFile()) {\n                    // Destination cannot be a file\n                    return false;\n                }\n                // else destination does not exist and Java is able to create it\n            } else {\n                // Unsupported file\n                return false;\n            }\n            if (srcFile.renameTo(dstFile)) {\n                documentFile = getRequiredRawDocument(dstFile.getAbsolutePath());\n                if (VirtualFileSystem.getFileSystem(Uri.fromFile(srcFile)) != null) {\n                    // Move mount point\n                    VirtualFileSystem.alterMountPoint(Uri.fromFile(srcFile), Uri.fromFile(dstFile));\n                }\n                return true;\n            }\n        }\n        // Try Path#renameTo if both are located in the same directory. Mount point is already handled here.\n        DocumentFile sourceParent = source.getParentFile();\n        DocumentFile destParent = dest.getParentFile();\n        if (sourceParent != null && sourceParent.equals(destParent)) {\n            // If both path are located in the same directory, rename them\n            if (renameTo(path.getName())) {\n                return true;\n            }\n        }\n        // Try copy and delete approach\n        if (source.isDirectory()) { // Source is a directory\n            if (dest.isDirectory()) {\n                // Destination is a directory: Apply copy-and-delete inside the dest\n                DocumentFile newPath = dest.createDirectory(Objects.requireNonNull(source.getName()));\n                if (newPath == null || newPath.listFiles().length != 0) {\n                    // Couldn't create directory or the directory is not empty\n                    return false;\n                }\n                try {\n                    // Copy all the directory items to the new path and delete source\n                    copyDirectory(context, source, newPath);\n                    source.delete();\n                    documentFile = newPath;\n                    return true;\n                } catch (IOException e) {\n                    return false;\n                }\n            }\n            if (!dest.exists()) {\n                // Destination does not exist, simply create and copy\n                // Make sure that parent exists, and it is a directory\n                if (destParent == null || !destParent.isDirectory()) {\n                    return false;\n                }\n                DocumentFile newPath = destParent.createDirectory(Objects.requireNonNull(dest.getName()));\n                if (newPath == null || newPath.listFiles().length != 0) {\n                    // Couldn't create directory or the directory is not empty\n                    return false;\n                }\n                try {\n                    // Copy all the directory items to the new path and delete source\n                    copyDirectory(context, source, newPath);\n                    source.delete();\n                    documentFile = newPath;\n                    return true;\n                } catch (IOException e) {\n                    return false;\n                }\n            }\n            // Current path is a directory but target is not a directory\n            return false;\n        }\n        if (source.isFile()) { // Source is a file\n            DocumentFile newPath;\n            if (dest.isDirectory()) {\n                // Move the file inside the directory\n                newPath = dest.createFile(DEFAULT_MIME, getName());\n            } else if (dest.isFile()) {\n                // Rename the file and override the existing dest\n                if (!override) {\n                    // overriding is disabled\n                    return false;\n                }\n                newPath = dest;\n            } else if (destParent != null) {\n                // File does not exist, create a new one\n                newPath = destParent.createFile(DEFAULT_MIME, Objects.requireNonNull(dest.getName()));\n            } else {\n                // File does not exist, but nothing could be done about it\n                return false;\n            }\n            if (newPath == null) {\n                // For some reason, newPath could not be created\n                return false;\n            }\n            try {\n                // Copy the contents of the source file and delete it\n                copyFile(context, source, newPath);\n                source.delete();\n                documentFile = newPath;\n                return true;\n            } catch (IOException e) {\n                return false;\n            }\n        }\n        return false;\n    }\n\n\n    @Nullable\n    public Path copyTo(@NonNull Path path) {\n        return copyTo(path, true);\n    }\n\n    @Nullable\n    public Path copyTo(@NonNull Path path, boolean override) {\n        DocumentFile source = getRealDocumentFile(documentFile);\n        DocumentFile dest = getRealDocumentFile(path.documentFile);\n        if (!source.exists()) {\n            // Source itself does not exist.\n            Log.d(TAG, \"Source does not exist.\");\n            return null;\n        }\n        if (dest.exists() && !dest.canWrite()) {\n            // There's no point is attempting to copy if the destination is read-only.\n            Log.d(TAG, \"Read-only destination.\");\n            return null;\n        }\n        // Add separator to avoid matching wrong files\n        String destStr = dest.getUri() + File.separator;\n        String srcStr = source.getUri() + File.separator;\n        if (destStr.startsWith(srcStr)) {\n            // Destination cannot be the same or a subdirectory of source\n            Log.d(TAG, \"Destination is a subdirectory of source.\");\n            return null;\n        }\n        DocumentFile destParent = dest.getParentFile();\n        if (source.isDirectory()) { // Source is a directory\n            if (dest.isDirectory()) {\n                // Destination is a directory: Apply copy source inside the dest\n                String name = Objects.requireNonNull(source.getName());\n                DocumentFile newPath = dest.findFile(name);\n                if (newPath != null) {\n                    // Desired directory exists\n                    if (!override) {\n                        Log.d(TAG, \"Overwriting isn't enabled.\");\n                        return null;\n                    }\n                    // Check if this is the source\n                    if (source.getUri().equals(newPath.getUri())) {\n                        Log.d(TAG, \"Source and destination are the same.\");\n                        return null;\n                    }\n                }\n                newPath = dest.createDirectory(name);\n                if (newPath == null) {\n                    // Couldn't create directory\n                    Log.d(TAG, \"Could not create directory in the destination.\");\n                    return null;\n                }\n                try {\n                    // Copy all the directory items to the new path\n                    copyDirectory(context, source, newPath, override);\n                    return new PathImpl(context, newPath);\n                } catch (IOException e) {\n                    Log.d(TAG, \"Could not copy files.\", e);\n                    return null;\n                }\n            }\n            if (!dest.exists()) {\n                // Destination does not exist, simply create and copy\n                // Make sure that parent exists, and it is a directory\n                if (destParent == null || !destParent.isDirectory()) {\n                    Log.d(TAG, \"Parent of destination must exist.\");\n                    return null;\n                }\n                DocumentFile newPath = destParent.createDirectory(Objects.requireNonNull(dest.getName()));\n                if (newPath == null) {\n                    // Couldn't create directory or the directory is not empty\n                    Log.d(TAG, \"Could not create directory or non-empty directory.\");\n                    return null;\n                }\n                try {\n                    // Copy all the directory items to the new path\n                    copyDirectory(context, source, newPath, override);\n                    return new PathImpl(context, newPath);\n                } catch (IOException e) {\n                    Log.d(TAG, \"Could not copy files.\", e);\n                    return null;\n                }\n            }\n            // Current path is a directory but target is not a directory\n            Log.d(TAG, \"Source is a directory while destination is not.\");\n            return null;\n        }\n        if (source.isFile()) { // Source is a file\n            DocumentFile newPath;\n            if (dest.isDirectory()) {\n                // Move the file inside the directory\n                newPath = dest.findFile(getName());\n                if (newPath != null) {\n                    // File exists\n                    if (!override) {\n                        Log.d(TAG, \"Overwriting isn't enabled.\");\n                        return null;\n                    }\n                    // Check if this is the source\n                    if (source.getUri().equals(newPath.getUri())) {\n                        Log.d(TAG, \"Source and destination are the same.\");\n                        return null;\n                    }\n                }\n                newPath = dest.createFile(DEFAULT_MIME, getName());\n            } else if (dest.isFile()) {\n                // Override the existing dest\n                if (!override) {\n                    // overriding is disabled\n                    Log.d(TAG, \"Overwriting isn't enabled.\");\n                    return null;\n                }\n                newPath = dest;\n            } else if (destParent != null) {\n                // File does not exist, create a new one\n                newPath = destParent.createFile(DEFAULT_MIME, Objects.requireNonNull(dest.getName()));\n            } else {\n                // File does not exist, but nothing could be done about it\n                Log.d(TAG, \"Could not copy file.\");\n                return null;\n            }\n            if (newPath == null) {\n                // For some reason, newPath could not be created\n                Log.d(TAG, \"Could not create file in the destination.\");\n                return null;\n            }\n            try {\n                // Copy the contents of the source file\n                copyFile(context, source, newPath);\n                return new PathImpl(context, newPath);\n            } catch (IOException e) {\n                Log.d(TAG, \"Could not copy files.\", e);\n                return null;\n            }\n        }\n        Log.d(TAG, \"Unknown error during copying.\");\n        return null;\n    }\n\n    private static void copyFile(@NonNull Context context, @NonNull DocumentFile src, @NonNull DocumentFile dst)\n            throws IOException {\n        copyFile(new PathImpl(context, src), new PathImpl(context, dst));\n    }\n\n    private static void copyFile(@NonNull Path src, @NonNull Path dst) throws IOException {\n        if (src.isMountPoint() || dst.isMountPoint()) {\n            throw new IOException(\"Either source or destination are a mount point.\");\n        }\n        IoUtils.copy(src, dst);\n    }\n\n    // Copy directory content\n    private static void copyDirectory(@NonNull Context context, @NonNull DocumentFile src, @NonNull DocumentFile dst,\n                                      boolean override) throws IOException {\n        copyDirectory(new PathImpl(context, src), new PathImpl(context, dst), override);\n    }\n\n    private static void copyDirectory(@NonNull Context context, @NonNull DocumentFile src, @NonNull DocumentFile dst)\n            throws IOException {\n        copyDirectory(new PathImpl(context, src), new PathImpl(context, dst), true);\n    }\n\n    private static void copyDirectory(@NonNull Path src, @NonNull Path dst, boolean override) throws IOException {\n        for (Path file : src.listFiles()) {\n            String name = file.getName();\n            if (file.isDirectory()) {\n                Path newDir = dst.createNewDirectory(name);\n                Path fsRoot = VirtualFileSystem.getFsRoot(file.getUri());\n                if (fsRoot != null) {\n                    VirtualFileSystem.alterMountPoint(file.getUri(), newDir.getUri());\n                }\n                copyDirectory(file, newDir, override);\n            } else if (file.isFile()) {\n                if (dst.hasFile(name) && !override) {\n                    // Override disabled\n                    continue;\n                }\n                Path newFile = dst.createNewFile(name, null);\n                copyFile(file, newFile);\n            }\n        }\n    }\n\n    public long lastModified() {\n        return documentFile.lastModified();\n    }\n\n    public boolean setLastModified(long time) {\n        if (documentFile instanceof ExtendedRawDocumentFile) {\n            return Objects.requireNonNull(getFile()).setLastModified(time);\n        }\n        if (documentFile instanceof VirtualDocumentFile) {\n            return ((VirtualDocumentFile) documentFile).setLastModified(time);\n        }\n        return false;\n    }\n\n    public long lastAccess() {\n        if (documentFile instanceof ExtendedRawDocumentFile) {\n            return Objects.requireNonNull(getFile()).lastAccess();\n        }\n        if (documentFile instanceof VirtualDocumentFile) {\n            return ((VirtualDocumentFile) documentFile).lastAccess();\n        }\n        return 0;\n    }\n\n    public boolean setLastAccess(long millis) {\n        if (documentFile instanceof ExtendedRawDocumentFile) {\n            return Objects.requireNonNull(getFile()).setLastAccess(millis);\n        }\n//        // TODO: 28/6/23\n//        if (mDocumentFile instanceof VirtualDocumentFile) {\n//            return ((VirtualDocumentFile) mDocumentFile).setLastAccess();\n//        }\n        return false;\n    }\n\n    public long creationTime() {\n        if (documentFile instanceof ExtendedRawDocumentFile) {\n            return Objects.requireNonNull(getFile()).creationTime();\n        }\n        if (documentFile instanceof VirtualDocumentFile) {\n            return ((VirtualDocumentFile) documentFile).creationTime();\n        }\n        return 0;\n    }\n\n    @NonNull\n    public Path[] listFiles() {\n        // Get all file systems mounted at this Uri\n        DocumentFile documentFile = getRealDocumentFile(this.documentFile);\n        VirtualFileSystem[] fileSystems = VirtualFileSystem.getFileSystemsAtUri(documentFile.getUri());\n        HashMap<String, Uri> nameMountPointMap = new HashMap<>(fileSystems.length);\n        for (VirtualFileSystem fs : fileSystems) {\n            Uri mountPoint = Objects.requireNonNull(fs.getMountPoint());\n            nameMountPointMap.put(mountPoint.getLastPathSegment(), mountPoint);\n        }\n        // List documents at this folder\n        DocumentFile[] ss = documentFile.listFiles();\n        if (nameMountPointMap.isEmpty()) {\n            // No need to go further\n            Path[] paths = new Path[ss.length];\n            for (int i = 0; i < ss.length; ++i) {\n                paths[i] = new PathImpl(context, ss[i]);\n            }\n            return paths;\n        }\n        List<Path> paths = new ArrayList<>(ss.length + fileSystems.length);\n        // Remove mount points\n        for (DocumentFile s : ss) {\n            if (nameMountPointMap.get(s.getName()) != null) {\n                // Mount point exists, remove it from map\n                nameMountPointMap.remove(s.getName());\n            }\n            paths.add(new PathImpl(context, s));\n        }\n        // Add all the other mount points\n        for (Uri mountPoint : nameMountPointMap.values()) {\n            paths.add(new PathImpl(context, mountPoint));\n        }\n        return paths.toArray(new Path[0]);\n    }\n\n    @NonNull\n    public String[] listFileNames(@Nullable FilenameFilter filter) {\n        Path[] ss = listFiles();\n        ArrayList<String> files = new ArrayList<>();\n        for (Path s : ss) {\n            s.getName();\n            if (filter == null || filter.accept(s, s.getName())) {\n                files.add(s.getName());\n            }\n        }\n        return files.toArray(new String[0]);\n    }\n\n    @NonNull\n    public ParcelFileDescriptor openFileDescriptor(@NonNull String mode, @NonNull Handler callbackHandler)\n            throws FileNotFoundException {\n        DocumentFile documentFile = getRealDocumentFile(this.documentFile);\n        if (documentFile instanceof ExtendedRawDocumentFile) {\n            ExtendedFile file = Objects.requireNonNull(getFile());\n            if (file instanceof RemoteFile) {\n                int modeBits = ParcelFileDescriptor.parseMode(mode);\n                try {\n                    return StorageManagerCompat.openProxyFileDescriptor(modeBits, new ProxyStorageCallback(\n                            file.getAbsolutePath(), modeBits, callbackHandler));\n                } catch (IOException e) {\n                    throw (FileNotFoundException) new FileNotFoundException(\"Could not open file \" + file).initCause(e);\n                }\n            } // else use the default content provider\n        } else if (documentFile instanceof VirtualDocumentFile) {\n            int modeBits = ParcelFileDescriptor.parseMode(mode);\n            try {\n                return ((VirtualDocumentFile) documentFile).openFileDescriptor(modeBits);\n            } catch (IOException e) {\n                throw (FileNotFoundException) new FileNotFoundException(e.getMessage()).initCause(e);\n            }\n        }\n        return FileUtils.getFdFromUri(context, documentFile.getUri(), mode);\n    }\n\n    @NonNull\n    public OutputStream openOutputStream(boolean append) throws IOException {\n        DocumentFile documentFile = resolveFileOrNull(this.documentFile);\n        if (documentFile == null) {\n            throw new IOException(this.documentFile.getUri() + \" is a directory\");\n        }\n        if (documentFile instanceof ExtendedRawDocumentFile) {\n            try {\n                return Objects.requireNonNull(getFile()).newOutputStream(append);\n            } catch (IOException e) {\n                throw new IOException(\"Could not open file for writing: \" + documentFile.getUri(), e);\n            }\n        } else if (documentFile instanceof VirtualDocumentFile) {\n            return ((VirtualDocumentFile) documentFile).openOutputStream(append);\n        }\n        String mode = \"w\" + (append ? \"a\" : \"t\");\n        OutputStream os = context.getContentResolver().openOutputStream(documentFile.getUri(), mode);\n        if (os == null) {\n            throw new IOException(\"Could not resolve Uri: \" + documentFile.getUri());\n        }\n        return os;\n    }\n\n    @NonNull\n    public InputStream openInputStream() throws IOException {\n        DocumentFile documentFile = resolveFileOrNull(this.documentFile);\n        if (documentFile == null) {\n            throw new IOException(this.documentFile.getUri() + \" is a directory\");\n        }\n        if (documentFile instanceof ExtendedRawDocumentFile) {\n            try {\n                return Objects.requireNonNull(getFile()).newInputStream();\n            } catch (IOException e) {\n                throw new IOException(\"Could not open file for reading: \" + documentFile.getUri(), e);\n            }\n        } else if (documentFile instanceof VirtualDocumentFile) {\n            return ((VirtualDocumentFile) documentFile).openInputStream();\n        }\n        try {\n            InputStream is = context.getContentResolver().openInputStream(documentFile.getUri());\n            if (is == null) {\n                throw new IOException(\"Could not resolve Uri: \" + documentFile.getUri());\n            }\n            return is;\n        } catch (SecurityException e) {\n            throw new IOException(e);\n        }\n    }\n\n    public FileChannel openFileChannel(int mode) throws IOException {\n        DocumentFile documentFile = resolveFileOrNull(this.documentFile);\n        if (documentFile == null) {\n            throw new IOException(this.documentFile.getUri() + \" is a directory\");\n        }\n        if (documentFile instanceof ExtendedRawDocumentFile) {\n            ExtendedFile file = Objects.requireNonNull(getFile());\n            if (file instanceof RemoteFile) {\n                try {\n                    return LocalServices.getFileSystemManager().openChannel(file, mode);\n                } catch (RemoteException e) {\n                    throw new IOException(e);\n                }\n            }\n            return FileSystemManager.getLocal().openChannel(file, mode);\n        } else if (documentFile instanceof VirtualDocumentFile) {\n            return ((VirtualDocumentFile) documentFile).openChannel(mode);\n        }\n        throw new IOException(\"Target is not backed by a real file\");\n    }\n\n    @NonNull\n    private static Path createFileAsDirectChild(@NonNull Context context,\n                                                @NonNull DocumentFile documentFile,\n                                                @NonNull String displayName,\n                                                @Nullable String mimeType) throws IOException {\n        if (displayName.indexOf(File.separatorChar) != -1) {\n            throw new IllegalArgumentException(\"Display name contains file separator.\");\n        }\n        documentFile = getRealDocumentFile(documentFile);\n        if (!documentFile.isDirectory()) {\n            throw new IOException(\"Current file is not a directory.\");\n        }\n        String extension = null;\n        if (mimeType != null) {\n            extension = MimeTypeMap.getSingleton().getExtensionFromMimeType(mimeType);\n        } else mimeType = DEFAULT_MIME;\n        String nameWithExtension = displayName + (extension != null ? \".\" + extension : \"\");\n        checkVfs(Paths.appendPathSegment(documentFile.getUri(), nameWithExtension));\n        DocumentFile f = documentFile.findFile(displayName);\n        if (f != null) {\n            if (f.isDirectory()) {\n                throw new IOException(\"Directory cannot be converted to file\");\n            }\n            // Delete the file if exists\n            f.delete();\n        }\n        DocumentFile file = documentFile.createFile(mimeType, displayName);\n        if (file == null) {\n            throw new IOException(\"Could not create \" + documentFile.getUri() + File.separatorChar + nameWithExtension + \" with type \" + mimeType);\n        }\n        return new PathImpl(context, file);\n    }\n\n    @Nullable\n    private static DocumentFile findFileInternal(@NonNull DocumentFile documentFile, @NonNull String dirtyDisplayName) {\n        String displayName = Paths.sanitize(dirtyDisplayName, true);\n        if (displayName == null) {\n            // Empty display name\n            return null;\n        }\n        String[] parts = displayName.split(File.separator);\n        documentFile = getRealDocumentFile(documentFile);\n        for (String part : parts) {\n            // Check for mount point\n            Uri newUri = Paths.appendPathSegment(documentFile.getUri(), part);\n            Path fsRoot = VirtualFileSystem.getFsRoot(newUri);\n            // Mount point has the higher priority\n            documentFile = fsRoot != null ? fsRoot.documentFile : documentFile.findFile(part);\n            if (documentFile == null) return null;\n        }\n        return documentFile;\n    }\n\n    @Nullable\n    private static DocumentFile getParentFile(@NonNull Context context, @NonNull VirtualFileSystem vfs) {\n        Uri mountPoint = vfs.getMountPoint();\n        if (mountPoint == null) {\n            return null;\n        }\n        // FIXME: 9/9/23 This doesn't actually work for content URIs\n        Uri parentUri = Paths.removeLastPathSegment(mountPoint);\n        return new PathImpl(context, parentUri).documentFile;\n    }\n\n    @NonNull\n    private static DocumentFile createArbitraryDirectories(@NonNull DocumentFile documentFile,\n                                                           @NonNull String[] names,\n                                                           int length) throws IOException {\n        DocumentFile file = getRealDocumentFile(documentFile);\n        for (int i = 0; i < length; ++i) {\n            Path fsRoot = VirtualFileSystem.getFsRoot(Paths.appendPathSegment(file.getUri(), names[i]));\n            DocumentFile t = fsRoot != null ? fsRoot.documentFile : file.findFile(names[i]);\n            if (t == null) {\n                t = file.createDirectory(names[i]);\n            } else if (!t.isDirectory()) {\n                throw new IOException(t.getUri() + \" exists and it is not a directory.\");\n            }\n            if (t == null) {\n                throw new IOException(\"Could not create directory \" + file.getUri() + File.separatorChar + names[i]);\n            }\n            file = t;\n        }\n        return file;\n    }\n\n    @NonNull\n    private static DocumentFile getRealDocumentFile(@NonNull DocumentFile documentFile) {\n        Path fsRoot = VirtualFileSystem.getFsRoot(documentFile.getUri());\n        if (fsRoot != null) {\n            return fsRoot.documentFile;\n        }\n        return documentFile;\n    }\n\n    @Nullable\n    private static DocumentFile resolveFileOrNull(@NonNull DocumentFile documentFile) {\n        DocumentFile realDocumentFile = getRealDocumentFile(documentFile);\n        if (!realDocumentFile.isDirectory()) {\n            return realDocumentFile;\n        }\n        // Try original\n        if (!documentFile.isDirectory()) {\n            return documentFile;\n        }\n        return null;\n    }\n\n    private static void checkVfs(Uri uri) throws IOException {\n        if (VirtualFileSystem.getFileSystem(uri) != null) {\n            throw new IOException(\"Destination is a mount point.\");\n        }\n    }\n\n    private static boolean isDocumentsProvider(@NonNull Context context, @Nullable String authority) {\n        final Intent intent = new Intent(DocumentsContract.PROVIDER_INTERFACE);\n        final List<ResolveInfo> infos = context.getPackageManager().queryIntentContentProviders(intent, 0);\n        for (ResolveInfo info : infos) {\n            if (Objects.equals(authority, info.providerInfo.authority)) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    private static class ProxyStorageCallback extends StorageManagerCompat.ProxyFileDescriptorCallbackCompat {\n        @NonNull\n        private final FileChannel mChannel;\n\n        private ProxyStorageCallback(String path, int modeBits, @NonNull Handler handler) throws IOException {\n            super(handler);\n            try {\n                FileSystemManager fs = LocalServices.getFileSystemManager();\n                mChannel = fs.openChannel(path, modeBits);\n            } catch (Throwable throwable) {\n                throw new IOException(throwable);\n            }\n        }\n\n        @Override\n        public long onGetSize() throws ErrnoException {\n            try {\n                return mChannel.size();\n            } catch (IOException e) {\n                throw new ErrnoException(e.getMessage(), OsConstants.EBADF);\n            }\n        }\n\n        @Override\n        public int onRead(long offset, int size, byte[] data) throws ErrnoException {\n            ByteBuffer bf = ByteBuffer.wrap(data);\n            bf.limit(size);\n            try {\n                return mChannel.read(bf, offset);\n            } catch (IOException e) {\n                throw new ErrnoException(e.getMessage(), OsConstants.EBADF);\n            }\n        }\n\n        @Override\n        public int onWrite(long offset, int size, byte[] data) throws ErrnoException {\n            ByteBuffer bf = ByteBuffer.wrap(data);\n            bf.limit(size);\n            try {\n                return mChannel.write(bf, offset);\n            } catch (IOException e) {\n                throw new ErrnoException(e.getMessage(), OsConstants.EBADF);\n            }\n        }\n\n        @Override\n        public void onFsync() throws ErrnoException {\n            try {\n                mChannel.force(true);\n            } catch (IOException e) {\n                throw new ErrnoException(e.getMessage(), OsConstants.EBADF);\n            }\n        }\n\n        @Override\n        protected void onRelease() {\n            try {\n                mChannel.close();\n            } catch (IOException e) {\n                e.printStackTrace();\n            }\n        }\n\n        @Override\n        protected void finalize() throws Throwable {\n            if (mChannel != null) {\n                mChannel.close();\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/io/Paths.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.io;\n\nimport android.content.ContentResolver;\nimport android.database.Cursor;\nimport android.net.Uri;\nimport android.os.RemoteException;\nimport android.os.UserHandleHidden;\nimport android.system.ErrnoException;\nimport android.system.OsConstants;\nimport android.text.TextUtils;\n\nimport androidx.annotation.AnyThread;\nimport androidx.annotation.IntDef;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.VisibleForTesting;\n\nimport org.jetbrains.annotations.Contract;\n\nimport java.io.File;\nimport java.io.FileNotFoundException;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.LinkedList;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Objects;\nimport java.util.Stack;\nimport java.util.regex.Pattern;\n\nimport io.github.muntashirakon.AppManager.utils.AlphanumComparator;\nimport io.github.muntashirakon.AppManager.utils.ContextUtils;\nimport io.github.muntashirakon.AppManager.utils.ThreadUtils;\nimport io.github.muntashirakon.io.fs.VirtualFileSystem;\n\n@SuppressWarnings(\"SuspiciousRegexArgument\") // Not Windows, Android is Linux\npublic final class Paths {\n    public static final String TAG = Paths.class.getSimpleName();\n\n    /**\n     * Replace spaces with replacement\n     */\n    public static final int SANITIZE_FLAG_SPACE = 1;\n    /**\n     * Replace {@code /} with replacement\n     */\n    public static final int SANITIZE_FLAG_UNIX_ILLEGAL_CHARS = 1 << 1;\n    /**\n     * Returns null if the filename becomes {@code .} or {@code ..} after applying all the sanitization rules\n     */\n    public static final int SANITIZE_FLAG_UNIX_RESERVED = 1 << 2;\n    /**\n     * Replace {@code :} with replacement\n     */\n    public static final int SANITIZE_FLAG_MAC_OS_ILLEGAL_CHARS = 1 << 3;\n    /**\n     * Replace {@code / ? < > \\ : * | \"} and control characters with replacement\n     */\n    public static final int SANITIZE_FLAG_NTFS_ILLEGAL_CHARS = 1 << 4;\n    /**\n     * Replace {@code / ? < > \\ : * | \" ^} and control characters with replacement\n     */\n    public static final int SANITIZE_FLAG_FAT_ILLEGAL_CHARS = 1 << 5;\n    /**\n     * Returns null if the filename becomes com1, com2, com3, com4, com5, com6, com7, com8, com9, lpt1, lpt2, lpt3,\n     * lpt4, lpt5, lpt6, lpt7, lpt8, lpt9, con, nul, or prn after applying all the sanitization rules\n     */\n    public static final int SANITIZE_FLAG_WINDOWS_RESERVED = 1 << 6;\n\n    @IntDef(flag = true, value = {\n            SANITIZE_FLAG_SPACE,\n            SANITIZE_FLAG_UNIX_ILLEGAL_CHARS,\n            SANITIZE_FLAG_UNIX_RESERVED,\n            SANITIZE_FLAG_MAC_OS_ILLEGAL_CHARS,\n            SANITIZE_FLAG_NTFS_ILLEGAL_CHARS,\n            SANITIZE_FLAG_FAT_ILLEGAL_CHARS,\n            SANITIZE_FLAG_WINDOWS_RESERVED\n    })\n    public @interface SanitizeFlags {\n    }\n\n    @NonNull\n    public static Path getPrimaryPath(@Nullable String path) {\n        return get(new Uri.Builder()\n                .scheme(ContentResolver.SCHEME_CONTENT)\n                .authority(\"com.android.externalstorage.documents\")\n                .path(\"/tree/primary:\" + (path == null ? \"\" : path))\n                .build());\n    }\n\n    @NonNull\n    public static Path getUnprivileged(@NonNull File pathName) {\n        Path path = null;\n        try {\n            path = new PathImpl(ContextUtils.getContext(), pathName.getAbsolutePath(), false);\n        } catch (RemoteException ignore) {\n            // This exception is never called in unprivileged mode.\n        }\n        // Path is never null because RE is never called.\n        return Objects.requireNonNull(path);\n    }\n\n    @NonNull\n    public static Path getUnprivileged(@NonNull String pathName) {\n        Path path = null;\n        try {\n            path = new PathImpl(ContextUtils.getContext(), pathName, false);\n        } catch (RemoteException ignore) {\n            // This exception is never called in unprivileged mode.\n        }\n        // Path is never null because RE is never called.\n        return Objects.requireNonNull(path);\n    }\n\n    @NonNull\n    public static Path get(@NonNull String pathName) {\n        return new PathImpl(ContextUtils.getContext(), Objects.requireNonNull(pathName));\n    }\n\n    @NonNull\n    public static Path get(@NonNull File pathName) {\n        return new PathImpl(ContextUtils.getContext(), pathName.getAbsolutePath());\n    }\n\n    @NonNull\n    public static Path get(@NonNull Uri pathUri) {\n        return new PathImpl(ContextUtils.getContext(), pathUri);\n    }\n\n    @NonNull\n    public static Path getStrict(@NonNull Uri pathUri) throws FileNotFoundException {\n        try {\n            return new PathImpl(ContextUtils.getContext(), pathUri);\n        } catch (IllegalArgumentException e) {\n            throw (FileNotFoundException) (new FileNotFoundException(e.getMessage())).initCause(e);\n        }\n    }\n\n    @NonNull\n    public static Path get(@NonNull VirtualFileSystem fs) {\n        return new PathImpl(ContextUtils.getContext(), fs);\n    }\n\n    @NonNull\n    public static Path getTreeDocument(@Nullable Path parent, @NonNull Uri documentUri) {\n        return new PathImpl(parent, ContextUtils.getContext(), documentUri);\n    }\n\n    @NonNull\n    public static Path[] build(@NonNull Path[] base, String... segments) {\n        Path[] result = new Path[base.length];\n        for (int i = 0; i < base.length; i++) {\n            result[i] = build(base[i], segments);\n        }\n        return result;\n    }\n\n    @Nullable\n    public static Path build(@NonNull File base, @NonNull String... segments) {\n        return build(get(base), segments);\n    }\n\n    @Nullable\n    public static Path build(@NonNull Path base, @NonNull String... segments) {\n        Path cur = base;\n        boolean isLfs = cur.getFile() != null;\n        try {\n            for (String segment : segments) {\n                if (isLfs) {\n                    cur = get(new File(cur.getFilePath(), segment));\n                } else {\n                    cur = cur.findFile(segment);\n                }\n            }\n            return cur;\n        } catch (FileNotFoundException e) {\n            return null;\n        }\n    }\n\n    public static boolean exists(@Nullable String path) {\n        return path != null && get(path).exists();\n    }\n\n    public static boolean exists(@Nullable File path) {\n        return path != null && path.exists();\n    }\n\n    @Nullable\n    @Contract(\"!null -> !null\")\n    public static Path[] getSortedPaths(@Nullable Path[] paths) {\n        if (paths == null) {\n            return null;\n        }\n        // Default sort is usually an alphabetical sort which should've been an alphanumerical sort\n        ArrayList<Path> sortedPaths = new ArrayList<>(Arrays.asList(paths));\n        Collections.sort(sortedPaths, (o1, o2) -> AlphanumComparator.compareStringIgnoreCase(o1.getName(), o2.getName()));\n        return sortedPaths.toArray(new Path[0]);\n    }\n\n    @NonNull\n    public static PathAttributes getAttributesFromSafTreeCursor(@NonNull Uri treeUri, @NonNull Cursor c) {\n        return PathAttributesImpl.fromSafTreeCursor(treeUri, c);\n    }\n\n    /**\n     * Replace /storage/emulated with /data/media if the directory is inaccessible\n     */\n    @NonNull\n    public static Path getAccessiblePath(@NonNull Path path) {\n        if (!path.getUri().getScheme().equals(ContentResolver.SCHEME_FILE)) {\n            // Scheme other than file are already readable at their best notion\n            return path;\n        }\n        if (path.canRead()) {\n            return path;\n        }\n        String pathString = Objects.requireNonNull(path.getFilePath());\n        if (pathString.startsWith(\"/storage/emulated/\")) {\n            // The only inaccessible path is /storage/emulated/{!myUserId} and it has to be replaced with /data/media/{!myUserId}\n            if (!String.format(Locale.ROOT, \"/storage/emulated/%d\", UserHandleHidden.myUserId()).equals(pathString)) {\n                return get(pathString.replaceFirst(\"/storage/emulated/\", \"/data/media/\"));\n            }\n        }\n        return path;\n    }\n\n    @Nullable\n    public static String sanitizeFilename(@Nullable String filename) {\n        return sanitizeFilename(filename, null);\n    }\n\n    @Nullable\n    public static String sanitizeFilename(@Nullable String filename, @Nullable String replacement) {\n        return sanitizeFilename(filename, replacement, SANITIZE_FLAG_UNIX_ILLEGAL_CHARS | SANITIZE_FLAG_UNIX_RESERVED);\n    }\n\n    @Nullable\n    public static String sanitizeFilename(@Nullable String filename, @Nullable String replacement, @SanitizeFlags int flags) {\n        if (filename == null) {\n            return null;\n        }\n        if (replacement == null) {\n            replacement = \"\";\n        }\n        boolean spaces = (flags & SANITIZE_FLAG_SPACE) != 0;\n        boolean unixIllegal = (flags & SANITIZE_FLAG_UNIX_ILLEGAL_CHARS) != 0;\n        boolean unixReserved = (flags & SANITIZE_FLAG_UNIX_RESERVED) != 0;\n        boolean macOsIllegal = (flags & SANITIZE_FLAG_MAC_OS_ILLEGAL_CHARS) != 0;\n        boolean ntfsIllegal = (flags & SANITIZE_FLAG_NTFS_ILLEGAL_CHARS) != 0;\n        boolean fatIllegal = (flags & SANITIZE_FLAG_FAT_ILLEGAL_CHARS) != 0;\n        boolean windowsReserved = (flags & SANITIZE_FLAG_WINDOWS_RESERVED) != 0;\n        String illegal = \"[\\n\\r\"; // Always replace newlines\n        if (fatIllegal) {\n            illegal += \"\\\\\\\\/:*?\\\"<>|^\\u0000-\\u001f\\u0080-\\u009f\";\n        } else if (ntfsIllegal) {\n            illegal += \"\\\\\\\\/:*?\\\"<>|\\u0000-\\u001f\\u0080-\\u009f\";\n        } else if (macOsIllegal && unixIllegal) {\n            illegal += \":/\";\n        } else if (macOsIllegal) {\n            illegal += \":\";\n        } else if (unixIllegal) {\n            illegal += \"/\";\n        }\n        if (spaces) {\n            illegal += \" \";\n        }\n        illegal += \"]\";\n        filename = filename.trim().replaceAll(illegal, replacement);\n        if (filename.isEmpty()) {\n            return null;\n        }\n        if (unixReserved && (filename.equals(\".\") || filename.equals(\"..\"))) {\n            return null;\n        }\n        if (windowsReserved && filename.matches(\"^(con|prn|aux|nul|com[0-9]|lpt[0-9])(\\\\..*)?$\")) {\n            return null;\n        }\n        if (fatIllegal) {\n            // Supports only 255 chars\n            int maxLimit = Math.min(filename.length(), 255);\n            return filename.substring(0, maxLimit);\n        }\n        if (ntfsIllegal) {\n            // Supports only 256 chars\n            int maxLimit = Math.min(filename.length(), 256);\n            return filename.substring(0, maxLimit);\n        }\n        return filename;\n    }\n\n    /**\n     * Same as path normalization except that it does not attempt to follow {@code ..}.\n     *\n     * @param path     Path to sanitize\n     * @param omitRoot Whether to omit root when {@code path} is not {@code /}\n     * @return Sanitized path on success, {@code null} when the final result is empty.\n     */\n    @Contract(\"null, _ -> null\")\n    @Nullable\n    public static String sanitize(@Nullable String path, boolean omitRoot) {\n        if (path == null) {\n            return null;\n        }\n        if (path.isEmpty()) {\n            return null;\n        }\n        path = path.replaceAll(\"[\\r\\n]\", \"\");\n        boolean isAbsolute = path.startsWith(File.separator);\n        String[] parts = path.split(File.separator);\n        List<String> newParts = new ArrayList<>(parts.length);\n        for (String part : parts) {\n            if (part.isEmpty() || part.equals(\".\")) continue;\n            newParts.add(part);\n        }\n        path = TextUtils.join(File.separator, newParts);\n        if (isAbsolute) {\n            if (path.isEmpty()) {\n                return File.separator;\n            }\n            if (!omitRoot) {\n                return File.separator + path;\n            }\n        }\n        return path.isEmpty() ? null : path;\n    }\n\n    /**\n     * Normalize the given path. It resolves {@code ..} to find the ultimate path which may or may not be the real path\n     * since it does not check for symbolic links.\n     *\n     * @param path Path to normalize\n     * @return Normalized path on success, {@code null} when the final result is empty.\n     */\n    @Contract(\"null -> null\")\n    @Nullable\n    public static String normalize(@Nullable String path) {\n        if (path == null) {\n            return null;\n        }\n        if (path.isEmpty()) {\n            return null;\n        }\n        path = path.replaceAll(\"[\\r\\n]\", \"\");\n        boolean isAbsolute = path.startsWith(File.separator);\n        String[] parts = path.split(File.separator);\n        Stack<String> newParts = new Stack<>();\n        for (String part : parts) {\n            if (part.isEmpty() || part.equals(\".\")) continue;\n            if (!part.equals(\"..\") || (!isAbsolute && newParts.isEmpty()) || (!newParts.isEmpty() && \"..\".equals(newParts.peek()))) {\n                newParts.push(part);\n            } else if (!newParts.isEmpty()) {\n                newParts.pop();\n            }\n        }\n        path = TextUtils.join(File.separator, newParts);\n        if (isAbsolute) {\n            return File.separator + path;\n        }\n        return path.isEmpty() ? null : path;\n    }\n\n    /**\n     * Return the last segment from the given path. If the path has a trailing `/`, it removes it and attempt to find\n     * the last segment again. If it contains only `/` or no `/` at all, it returns empty string.\n     * <p>\n     * TODO: It should return null when no last path segment is found\n     *\n     * @param path An abstract path, may or may not start and/or end with `/`.\n     */\n    @AnyThread\n    @NonNull\n    public static String getLastPathSegment(@NonNull String path) {\n        path = sanitize(path, false);\n        // path has no trailing / or .\n        if (path == null || path.equals(File.separator)) {\n            return \"\";\n        }\n        int separatorIndex = path.lastIndexOf(File.separator);\n        if (separatorIndex == -1) {\n            // There are no `/` in the string, so return as is.\n            return path;\n        }\n        // There are path components, so return the last one.\n        String lastPart = path.substring(separatorIndex + 1);\n        if (lastPart.equals(\"..\")) {\n            // Invalid part\n            return \"\";\n        }\n        return lastPart;\n    }\n\n    @NonNull\n    public static String removeLastPathSegment(@NonNull String path) {\n        if (path.isEmpty()) {\n            return \"\";\n        }\n        boolean isAbsolute = path.startsWith(File.separator);\n        String[] parts = path.split(File.separator);\n        Stack<String> newParts = new Stack<>();\n        for (String part : parts) {\n            if (part.isEmpty() || part.equals(\".\")) continue;\n            newParts.push(part);\n        }\n        if (!newParts.isEmpty() && !newParts.peek().equals(\"..\")) {\n            newParts.pop();\n        }\n        path = TextUtils.join(File.separator, newParts);\n        if (isAbsolute) {\n            return File.separator + path;\n        }\n        return path;\n    }\n\n    @NonNull\n    public static String appendPathSegment(@NonNull String path, @NonNull String lastPathSegment) {\n        if (lastPathSegment.isEmpty()) {\n            return path;\n        }\n        lastPathSegment = lastPathSegment.replaceAll(\"[\\r\\n]\", \"\");\n        String[] parts = lastPathSegment.split(File.separator);\n        List<String> newParts = new ArrayList<>(parts.length);\n        for (String part : parts) {\n            if (part.isEmpty() || part.equals(\".\")) continue;\n            newParts.add(part);\n        }\n        String name = TextUtils.join(File.separator, newParts);\n        if (name.isEmpty()) {\n            return path;\n        }\n        if (path.endsWith(File.separator)) {\n            return path + name;\n        }\n        return path + File.separator + name;\n    }\n\n    @AnyThread\n    @NonNull\n    public static String trimPathExtension(@NonNull String path) {\n        if (path.isEmpty()) {\n            return \"\";\n        }\n        boolean isAbsolute = path.startsWith(File.separator);\n        String[] parts = path.split(File.separator);\n        Stack<String> newParts = new Stack<>();\n        for (String part : parts) {\n            if (part.isEmpty() || part.equals(\".\")) continue;\n            newParts.push(part);\n        }\n        if (newParts.isEmpty()) {\n            return isAbsolute ? File.separator : \"\";\n        }\n        String lastPart = newParts.peek();\n        if (!lastPart.equals(\"..\")) {\n            int lastIndexOfDot = lastPart.lastIndexOf('.');\n            int lastIndexOfPath = lastPart.length() - 1;\n            if (lastIndexOfDot != 0 && lastIndexOfDot != -1 && lastIndexOfDot != lastIndexOfPath) {\n                newParts.pop();\n                newParts.push(lastPart.substring(0, lastIndexOfDot));\n            }\n        }\n        path = TextUtils.join(File.separator, newParts);\n        if (isAbsolute) {\n            return File.separator + path;\n        }\n        return path;\n    }\n\n    @AnyThread\n    @Nullable\n    public static String getPathExtension(@NonNull String path) {\n        return getPathExtension(path, true);\n    }\n\n    @AnyThread\n    @Nullable\n    public static String getPathExtension(@NonNull String path, boolean forceLowercase) {\n        String str = getLastPathSegment(path);\n        int lastIndexOfDot = str.lastIndexOf('.');\n        if (lastIndexOfDot == -1 || lastIndexOfDot == str.length() - 1) return null;\n        String extension = str.substring(lastIndexOfDot + 1);\n        return forceLowercase ? extension.toLowerCase(Locale.ROOT) : extension;\n    }\n\n    public static Uri appendPathSegment(@NonNull Uri uri, @NonNull String lastPathSegment) {\n        return new Uri.Builder()\n                .scheme(uri.getScheme())\n                .authority(uri.getAuthority())\n                .path(sanitize(uri.getPath() + File.separator + lastPathSegment, false))\n                .build();\n    }\n\n    public static Uri removeLastPathSegment(@NonNull Uri uri) {\n        String path = uri.getPath();\n        if (path.equals(File.separator)) return uri;\n        return new Uri.Builder()\n                .scheme(uri.getScheme())\n                .authority(uri.getAuthority())\n                .path(removeLastPathSegment(path))\n                .build();\n    }\n\n    @NonNull\n    public static String findNextBestDisplayName(@NonNull Path basePath, @NonNull String prefix,\n                                                 @Nullable String extension) {\n        return findNextBestDisplayName(basePath, prefix, extension, 1);\n    }\n\n    @NonNull\n    public static String findNextBestDisplayName(@NonNull Path basePath, @NonNull String prefix,\n                                                 @Nullable String extension, int initialIndex) {\n        if (TextUtils.isEmpty(extension)) {\n            extension = \"\";\n        } else extension = \".\" + extension;\n        String displayName = prefix + extension;\n        int i = initialIndex;\n        // We need to find the next best file name if current exists\n        while (basePath.hasFile(displayName)) {\n            displayName = String.format(Locale.ROOT, \"%s (%d)%s\", prefix, i, extension);\n            ++i;\n        }\n        return displayName;\n    }\n\n    public static long size(@Nullable Path root) {\n        if (root == null) {\n            return 0;\n        }\n        if (root.isFile()) {\n            return root.length();\n        }\n        if (root.isSymbolicLink()) {\n            return 0;\n        }\n        if (!root.isDirectory()) {\n            // Other types of files aren't supported\n            return 0;\n        }\n        long length = 0;\n        Path[] files = root.listFiles();\n        for (Path file : files) {\n            if (ThreadUtils.isInterrupted()) {\n                // Size could be too long\n                return length;\n            }\n            length += size(file);\n        }\n        return length;\n    }\n\n    public static void chmod(@NonNull Path path, int mode) throws ErrnoException {\n        ExtendedFile file = path.getFile();\n        if (file == null) {\n            throw new ErrnoException(\"Supplied path is not a Linux path.\", OsConstants.EBADF);\n        }\n        file.setMode(mode);\n    }\n\n    public static void chown(@NonNull Path path, int uid, int gid) throws ErrnoException {\n        ExtendedFile file = path.getFile();\n        if (file == null) {\n            throw new ErrnoException(\"Supplied path is not a Linux path.\", OsConstants.EBADF);\n        }\n        file.setUidGid(uid, gid);\n    }\n\n    /**\n     * Set owner and mode of given path.\n     *\n     * @param mode to apply through {@code chmod}\n     * @param uid  to apply through {@code chown}, or -1 to leave unchanged\n     * @param gid  to apply through {@code chown}, or -1 to leave unchanged\n     */\n    public static void setPermissions(@NonNull Path path, int mode, int uid, int gid) throws ErrnoException {\n        chmod(path, mode);\n        if (uid >= 0 || gid >= 0) {\n            chown(path, uid, gid);\n        }\n    }\n\n    /**\n     * Same as {@link #getAll(Path, Path, String[], String[], boolean)} except that all nullable fields are set to\n     * {@code null} and following symbolic link is disabled.\n     *\n     * @param source All files and directories inside the path is listed, including the source file itself.\n     * @return List of all files and directories inside {@code source} (inclusive).\n     */\n    @NonNull\n    public static List<Path> getAll(@NonNull Path source) {\n        return getAll(null, source, null, null, false);\n    }\n\n    /**\n     * Get a list of files and directories inside {@code source} including the source file itself. This method is fully\n     * capable of handling path filters as regular expressions and can follow symbolic links. It uses a non-recursive\n     * algorithm and should be much faster than a recursive implementation.\n     * <p>\n     * <b>Note:</b> Currently, it can only retrieve regular files as well as directories. Any other file formats (e.g.\n     * FIFO) are not currently supported.\n     *\n     * @param base        Base path is the path in respect to which {@code filters} and {@code exclusions} are applied.\n     *                    If it is {@code null}, no base path is considered.\n     * @param source      All files and directories inside the path is listed, including the source file itself.\n     * @param filters     Filters to be applied. No filters are applied if it's set to {@code null}. The filters are\n     *                    expected to be regular expressions and are mutually exclusive.\n     * @param exclusions  Same as {@code filters}, except that it ignores the given patterns.\n     * @param followLinks Whether to follow symbolic links. If disabled, a linked directory will be added as a regular\n     *                    file.\n     * @return List of files and directories inside {@code source} (inclusive).\n     */\n    @NonNull\n    public static List<Path> getAll(@Nullable Path base, @NonNull Path source, @Nullable String[] filters,\n                                    @Nullable String[] exclusions, boolean followLinks) {\n        Objects.requireNonNull(source);\n        // Convert filters into patterns to reduce overheads\n        Pattern[] filterPatterns;\n        if (filters != null) {\n            filterPatterns = new Pattern[filters.length];\n            for (int i = 0; i < filters.length; ++i) {\n                filterPatterns[i] = Pattern.compile(filters[i]);\n            }\n        } else filterPatterns = null;\n        Pattern[] exclusionPatterns;\n        if (exclusions != null) {\n            exclusionPatterns = new Pattern[exclusions.length];\n            for (int i = 0; i < exclusions.length; ++i) {\n                exclusionPatterns[i] = Pattern.compile(exclusions[i]);\n            }\n        } else exclusionPatterns = null;\n        // Start collecting files\n        LinkedList<Path> allFiles = new LinkedList<>();\n        if (source.isFile()) { // OsConstants#S_ISREG\n            // Add it and return\n            allFiles.add(source);\n            return allFiles;\n        } else if (source.isDirectory()) { // OsConstants#S_ISDIR\n            if (!followLinks && source.isSymbolicLink()) {\n                // Add the directory only if it's a symbolic link and followLinks is disabled\n                allFiles.add(source);\n                return allFiles;\n            }\n        } else {\n            // No support for any other files\n            return allFiles;\n        }\n        // Top-level directory\n        Path[] fileList = source.listFiles(pathname -> pathname.isDirectory()\n                || (isUnderFilter(pathname, base, filterPatterns) && !willExclude(pathname, base, exclusionPatterns)));\n        if (fileList.length == 0) {\n            // Add this directory nonetheless if it matches one of the filters, no symlink checks needed\n            if (isUnderFilter(source, base, filterPatterns) && !willExclude(source, base, exclusionPatterns)) {\n                allFiles.add(source);\n            }\n            return allFiles;\n        } else {\n            // Has children, don't check for filters, just add the directory\n            allFiles.add(source);\n        }\n        // Declare a collection of stored directories\n        LinkedList<Path> dirCheckList = new LinkedList<>();\n        for (Path curFile : fileList) {\n            if (curFile.isFile()) { // OsConstants#S_ISREG\n                allFiles.add(curFile);\n            } else if (curFile.isDirectory()) { // OsConstants#S_ISDIR\n                if (!followLinks && curFile.isSymbolicLink()) {\n                    // Add the directory only if it's a symbolic link and followLinks is disabled\n                    allFiles.add(curFile);\n                } else {\n                    // Not a symlink\n                    dirCheckList.add(curFile);\n                }\n            } // else No support for any other files\n        }\n        while (!dirCheckList.isEmpty()) {\n            Path removedDir = dirCheckList.removeFirst();\n            // Remove the first catalog\n            Path[] removedDirFileList = removedDir.listFiles(pathname -> pathname.isDirectory()\n                    || (isUnderFilter(pathname, base, filterPatterns) && !willExclude(pathname, base, exclusionPatterns)));\n            if (removedDirFileList.length == 0) {\n                // Add this directory nonetheless if it matches one of the filters, no symlink checks needed\n                if (isUnderFilter(removedDir, base, filterPatterns) && !willExclude(removedDir, base, exclusionPatterns)) {\n                    allFiles.add(removedDir);\n                }\n                continue;\n            } else {\n                // Has children\n                allFiles.add(removedDir);\n            }\n            for (Path curFile : removedDirFileList) {\n                if (curFile.isFile()) { // OsConstants#S_ISREG\n                    allFiles.add(curFile);\n                } else if (curFile.isDirectory()) { // OsConstants#S_ISDIR\n                    if (!followLinks && curFile.isSymbolicLink()) {\n                        // Add the directory only if it's a symbolic link and followLinks is disabled\n                        allFiles.add(curFile);\n                    } else {\n                        // Not a symlink\n                        dirCheckList.add(curFile);\n                    }\n                } // else No support for any other files\n            }\n        }\n        return allFiles;\n    }\n\n    public static boolean isUnderFilter(@NonNull Path file, @Nullable Path basePath, @Nullable Pattern[] filters) {\n        if (filters == null) return true;\n        String fileStr = basePath == null ? file.getUri().getPath() : relativePath(file, basePath);\n        for (Pattern filter : filters) {\n            if (filter.matcher(fileStr).matches()) return true;\n        }\n        return false;\n    }\n\n    public static boolean willExclude(@NonNull Path file, @Nullable Path basePath, @Nullable Pattern[] exclude) {\n        if (exclude == null) return false;\n        String fileStr = basePath == null ? file.getUri().getPath() : relativePath(file, basePath);\n        for (Pattern excludeRegex : exclude) {\n            if (excludeRegex.matcher(fileStr).matches()) return true;\n        }\n        return false;\n    }\n\n    @NonNull\n    public static String relativePath(@NonNull Path file, @NonNull Path basePath) {\n        String baseDir = basePath.getUri().getPath() + (basePath.isDirectory() ? File.separator : \"\");\n        String targetPath = file.getUri().getPath() + (file.isDirectory() ? File.separator : \"\");\n        return relativePath(targetPath, baseDir);\n    }\n\n    @NonNull\n    public static String relativePath(@NonNull String targetPath, @NonNull String baseDir) {\n        return relativePath(targetPath, baseDir, File.separator);\n    }\n\n    @VisibleForTesting\n    @NonNull\n    public static String relativePath(@NonNull String targetPath, @NonNull String baseDir, @NonNull String separator) {\n        String[] base = baseDir.split(Pattern.quote(separator));\n        String[] target = targetPath.split(Pattern.quote(separator));\n\n        // Count common elements and their length\n        int commonCount = 0, commonLength = 0, maxCount = Math.min(target.length, base.length);\n        while (commonCount < maxCount) {\n            String targetElement = target[commonCount];\n            if (!targetElement.equals(base[commonCount])) break;\n            commonCount++;\n            commonLength += targetElement.length() + 1; // Directory name length plus slash\n        }\n        if (commonCount == 0) return targetPath; // No common path element\n\n        int targetLength = targetPath.length();\n        int dirsUp = base.length - commonCount;\n        StringBuilder relative = new StringBuilder(dirsUp * 3 + targetLength - commonLength + 1);\n        for (int i = 0; i < dirsUp; i++) {\n            relative.append(\"..\").append(separator);\n        }\n        if (commonLength < targetLength) relative.append(targetPath.substring(commonLength));\n        return relative.toString();\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/io/ReadOnlyLocalFile.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.io;\n\nimport android.system.ErrnoException;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport java.io.File;\nimport java.util.ArrayList;\nimport java.util.List;\n\nclass ReadOnlyLocalFile extends LocalFile {\n    @NonNull\n    public static ReadOnlyLocalFile getAliasInstance(@NonNull String pathname, @NonNull String alias) {\n        ReadOnlyLocalFile file = new ReadOnlyLocalFile(alias);\n        file.mActualPath = pathname;\n        return file;\n    }\n\n    @Nullable\n    private String mActualPath;\n\n    public ReadOnlyLocalFile(@NonNull String pathname) {\n        super(pathname);\n    }\n\n    private ReadOnlyLocalFile(@Nullable String parent, @NonNull String child) {\n        super(parent, child);\n    }\n\n    @NonNull\n    @Override\n    public String getName() {\n        if (mActualPath != null) {\n            return new File(mActualPath).getName();\n        }\n        return super.getName();\n    }\n\n    @Override\n    public boolean isSymlink() {\n        if (mActualPath != null) {\n            return true;\n        }\n        return super.isSymlink();\n    }\n\n    @Override\n    protected LocalFile create(String path) {\n        String[] children = LocalFileOverlay.listChildren(new File(path));\n        if (children != null) {\n            // Emulated directory\n            // Check for potential alias\n            for (String child : children) {\n                if (child.startsWith(File.separator)) {\n                    // Alias\n                    return getAliasInstance(path, child);\n                }\n            }\n            // No alias found\n            return new ReadOnlyLocalFile(path);\n        }\n        return super.create(path);\n    }\n\n    @NonNull\n    @Override\n    public LocalFile getChildFile(String name) {\n        String[] children = LocalFileOverlay.listChildren(this);\n        if (children != null) {\n            for (String child : children) {\n                if (child.equals(name)) {\n                    return new ReadOnlyLocalFile(getPath(), child);\n                }\n            }\n        }\n        return super.getChildFile(name);\n    }\n\n    @SuppressWarnings(\"OctalInteger\")\n    @Override\n    public int getMode() {\n        try {\n            return super.getMode();\n        } catch (ErrnoException e) {\n            // Folder + read-only\n            return 0040444;\n        }\n    }\n\n    @Override\n    public UidGidPair getUidGid() {\n        try {\n            return super.getUidGid();\n        } catch (ErrnoException e) {\n            return new UidGidPair(0, 0);\n        }\n    }\n\n    @Nullable\n    @Override\n    public String[] list() {\n        String[] children = LocalFileOverlay.listChildren(this);\n        if (children == null) {\n            return super.list();\n        }\n        List<String> childList = new ArrayList<>(children.length);\n        for (String child : children) {\n            if (!child.startsWith(File.separator)) {\n                // Check if the path actually exist\n                if (new File(this, child).exists()) {\n                    childList.add(child);\n                }\n            }\n        }\n        return childList.toArray(new String[0]);\n    }\n}"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/io/fs/ApkFileSystem.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.io.fs;\n\nimport android.system.OsConstants;\nimport android.util.LruCache;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport com.android.apksig.apk.ApkFormatException;\nimport com.android.apksig.apk.ApkUtils;\nimport com.android.apksig.internal.zip.CentralDirectoryRecord;\nimport com.android.apksig.internal.zip.LocalFileRecord;\nimport com.android.apksig.internal.zip.ZipUtils;\nimport com.android.apksig.util.DataSink;\nimport com.android.apksig.util.DataSinks;\nimport com.android.apksig.util.DataSource;\nimport com.android.apksig.util.DataSources;\nimport com.android.apksig.zip.ZipFormatException;\nimport com.j256.simplemagic.ContentType;\n\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileNotFoundException;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.RandomAccessFile;\nimport java.util.Calendar;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\n\nimport io.github.muntashirakon.AppManager.utils.ExUtils;\nimport io.github.muntashirakon.io.Path;\nimport io.github.muntashirakon.io.Paths;\n\nclass ApkFileSystem extends VirtualFileSystem {\n    public static final String TYPE = ContentType.APK.getMimeType();\n\n    private final LruCache<String, Node<CentralDirectoryRecord>> mCache = new LruCache<>(100);\n    @Nullable\n    private RandomAccessFile mIn;\n    @Nullable\n    private DataSource mApk;\n    @Nullable\n    private ApkUtils.ZipSections mApkSections;\n    @Nullable\n    private List<CentralDirectoryRecord> mCdRecords;\n    @Nullable\n    private Node<CentralDirectoryRecord> mRootNode;\n\n    protected ApkFileSystem(@NonNull Path zipFile) {\n        super(zipFile);\n    }\n\n    @Override\n    public String getType() {\n        return TYPE;\n    }\n\n    @Override\n    protected Path onMount() throws IOException {\n        if (Objects.requireNonNull(getOptions()).remount && mIn != null && mRootNode != null) {\n            // Remount requested, no need to generate anything if they're already generated.\n            return Paths.get(this);\n        }\n        mIn = new RandomAccessFile(Objects.requireNonNull(getFile().getFile()), \"r\");\n        mApk = DataSources.asDataSource(mIn);\n        try {\n            mApkSections = ApkUtils.findZipSections(mApk);\n        } catch (ZipFormatException e) {\n            return ExUtils.rethrowAsIOException(e);\n        }\n        try {\n            mCdRecords = ZipUtils.parseZipCentralDirectory(mApk, mApkSections);\n        } catch (ApkFormatException e) {\n            return ExUtils.rethrowAsIOException(e);\n        }\n        mRootNode = buildTree(Objects.requireNonNull(mCdRecords));\n        return Paths.get(this);\n    }\n\n    @Nullable\n    @Override\n    protected File onUnmount(@NonNull Map<String, List<Action>> actionList) throws IOException {\n        mRootNode = null;\n        mCache.evictAll();\n        mApk = null;\n        mApkSections = null;\n        mCdRecords = null;\n        if (mIn != null) {\n            mIn.close();\n            mIn = null;\n        }\n        // Does not support modification\n        return null;\n    }\n\n    @Nullable\n    @Override\n    protected Node<?> getNode(String path) {\n        checkMounted();\n        Node<CentralDirectoryRecord> targetNode = mCache.get(path);\n        if (targetNode == null) {\n            if (path.equals(File.separator)) {\n                targetNode = mRootNode;\n            } else {\n                targetNode = Objects.requireNonNull(mRootNode).getLastChild(Paths.sanitize(path, true));\n            }\n            if (targetNode != null) {\n                mCache.put(path, targetNode);\n            }\n        }\n        return targetNode;\n    }\n\n    @Override\n    protected void invalidate(String path) {\n        mCache.remove(path);\n    }\n\n    @Override\n    protected long lastModified(@NonNull Node<?> node) {\n        Long time = node.getExtra(\"mtime\");\n        if (time == null) {\n            return getFile().lastModified();\n        }\n        return time;\n    }\n\n    @Override\n    public long length(String path) {\n        Node<?> targetNode = getNode(path);\n        if (targetNode == null) {\n            return -1;\n        }\n        if (targetNode.isDirectory()) {\n            return 0;\n        }\n        if (!targetNode.isFile()) {\n            return -1;\n        }\n        if (targetNode.getObject() == null) {\n            // Check for cache\n            File cachedFile = findCachedFile(targetNode);\n            if (cachedFile != null) {\n                return cachedFile.length();\n            }\n            return targetNode.isPhysical() ? -1 : 0;\n        }\n        return ((CentralDirectoryRecord) targetNode.getObject()).getSize();\n    }\n\n    @Override\n    public boolean checkAccess(String path, int access) {\n        Node<?> targetNode = getNode(path);\n        if (access == OsConstants.F_OK) {\n            return targetNode != null;\n        }\n        //noinspection RedundantIfStatement\n        if (access == OsConstants.R_OK) {\n            return true;\n        }\n        // X_OK, R_OK|X_OK, W_OK, R_OK|W_OK, R_OK|W_OK|X_OK are false\n        return false;\n    }\n\n    @NonNull\n    @Override\n    protected InputStream getInputStream(@NonNull Node<?> node) throws IOException {\n        return new FileInputStream(getCachedFile(node, false));\n    }\n\n    @Override\n    protected void cacheFile(@NonNull Node<?> src, @NonNull File sink) throws IOException {\n        CentralDirectoryRecord cdRecord = (CentralDirectoryRecord) src.getObject();\n        if (cdRecord == null || mApk == null || mApkSections == null) {\n            throw new FileNotFoundException(\"Class definition for \" + src.getFullPath() + \" is not found.\");\n        }\n        DataSource lfhSection = mApk.slice(0, mApkSections.getZipCentralDirectoryOffset());\n        try (FileOutputStream os = new FileOutputStream(sink)) {\n            DataSink out = DataSinks.asDataSink(os);\n            LocalFileRecord.outputUncompressedData(lfhSection, cdRecord, lfhSection.size(), out);\n        } catch (ZipFormatException e) {\n            throw new IOException(e);\n        }\n    }\n\n    @NonNull\n    private static Node<CentralDirectoryRecord> buildTree(@NonNull List<CentralDirectoryRecord> cdRecords) {\n        Node<CentralDirectoryRecord> rootNode = new Node<>(null, File.separator);\n        rootNode.addExtra(\"mtime\", System.currentTimeMillis());\n        for (CentralDirectoryRecord cdRecord : cdRecords) {\n            buildTree(rootNode, cdRecord);\n        }\n        return rootNode;\n    }\n\n    // Build nodes as needed by the entry, entry itself is the last node in the tree if it is not a directory\n    private static void buildTree(@NonNull Node<CentralDirectoryRecord> rootNode, @NonNull CentralDirectoryRecord cdRecord) {\n        String filename = Paths.sanitize(cdRecord.getName(), true);\n        if (filename == null) {\n            return;\n        }\n        String[] components = filename.split(File.separator);\n        if (components.length < 1) return;\n        long lastModTime = convertToUnixMillis(cdRecord.getLastModificationDate(), cdRecord.getLastModificationTime());\n        Node<CentralDirectoryRecord> lastNode = rootNode;\n        for (int i = 0; i < components.length - 1 /* last one will be set manually */; ++i) {\n            Node<CentralDirectoryRecord> newNode = lastNode.getChild(components[i]);\n            if (newNode == null) {\n                // Add children\n                newNode = new Node<>(lastNode, components[i]);\n                newNode.addExtra(\"mtime\", lastModTime);\n                lastNode.addChild(newNode);\n            }\n            lastNode = newNode;\n        }\n        Node<CentralDirectoryRecord> finalNode = new Node<>(lastNode, components[components.length - 1],\n                cdRecord.getName().endsWith(File.separator) ? null : cdRecord);\n        finalNode.addExtra(\"mtime\", lastModTime);\n        lastNode.addChild(finalNode);\n    }\n\n    public static long convertToUnixMillis(int date, int time) {\n        // Extract date components\n        int day = (date & 0x1F);\n        int month = ((date >> 5) & 0xF);\n        int year = ((date >> 9) & 0x7F) + 1980;\n\n        // Extract time components\n        int second = (time & 0x1F) * 2; // Seconds are rounded to the nearest even second\n        int minute = ((time >> 5) & 0x3F);\n        int hour = ((time >> 11) & 0x1F);\n\n        // Create a Calendar object\n        Calendar calendar = Calendar.getInstance();\n        calendar.set(Calendar.YEAR, year);\n        calendar.set(Calendar.MONTH, month - 1); // Java months are 0-based\n        calendar.set(Calendar.DAY_OF_MONTH, day);\n        calendar.set(Calendar.HOUR_OF_DAY, hour);\n        calendar.set(Calendar.MINUTE, minute);\n        calendar.set(Calendar.SECOND, second);\n        calendar.set(Calendar.MILLISECOND, 0);\n\n        // Convert to Unix millis\n        return calendar.getTimeInMillis();\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/io/fs/DexFileSystem.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.io.fs;\n\nimport android.system.OsConstants;\nimport android.util.LruCache;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport com.android.tools.smali.dexlib2.iface.ClassDef;\nimport com.android.tools.smali.dexlib2.writer.io.FileDataStore;\n\nimport org.antlr.runtime.RecognitionException;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.File;\nimport java.io.FileNotFoundException;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.nio.charset.StandardCharsets;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\n\nimport io.github.muntashirakon.AppManager.dex.DexClasses;\nimport io.github.muntashirakon.AppManager.dex.DexUtils;\nimport io.github.muntashirakon.AppManager.fm.ContentType2;\nimport io.github.muntashirakon.AppManager.self.filecache.FileCache;\nimport io.github.muntashirakon.io.ExtendedFile;\nimport io.github.muntashirakon.io.Path;\nimport io.github.muntashirakon.io.Paths;\n\npublic class DexFileSystem extends VirtualFileSystem {\n    public static final String TYPE = ContentType2.DEX.getMimeType();\n\n    private static class ClassInfo {\n        @Nullable\n        public final File cachedFile;\n        public final boolean physical;\n        public final boolean directory;\n\n        private ClassInfo(@Nullable File cachedFile, boolean physical) {\n            this(cachedFile, physical, false);\n        }\n\n        private ClassInfo(@Nullable File cachedFile, boolean physical, boolean directory) {\n            this.cachedFile = cachedFile;\n            this.physical = physical;\n            this.directory = directory;\n        }\n    }\n\n    private final LruCache<String, Node<ClassDef>> mCache = new LruCache<>(100);\n    @Nullable\n    private DexClasses mDexClasses;\n    @Nullable\n    private Node<ClassDef> mRootNode;\n\n    protected DexFileSystem(@NonNull Path dexPath) {\n        super(dexPath);\n    }\n\n    public int getApiLevel() {\n        // TODO: 26/11/22 Set via MountOptions\n        return -1;\n    }\n\n    @Override\n    public String getType() {\n        return TYPE;\n    }\n\n    @NonNull\n    public final DexClasses getDexClasses() {\n        checkMounted();\n        return Objects.requireNonNull(mDexClasses);\n    }\n\n    @Override\n    protected Path onMount() throws IOException {\n        if (\".dex\".equals(getFile().getExtension())) {\n            try (InputStream is = getFile().openInputStream()) {\n                mDexClasses = new DexClasses(is, getApiLevel());\n            }\n        } else { // APK/Zip file, may need caching\n            ExtendedFile file = getFile().getFile();\n            if (file != null) {\n                mDexClasses = new DexClasses(file, getApiLevel());\n            } else {\n                File cachedFile = FileCache.getGlobalFileCache().getCachedFile(getFile());\n                mDexClasses = new DexClasses(cachedFile, getApiLevel());\n            }\n        }\n        mRootNode = buildTree(Objects.requireNonNull(mDexClasses));\n        return Paths.get(this);\n    }\n\n    @Override\n    protected File onUnmount(@NonNull Map<String, List<Action>> actions) throws IOException {\n        File cachedFile = getUpdatedDexFile(actions);\n        if (mDexClasses != null) {\n            mDexClasses.close();\n        }\n        mRootNode = null;\n        mCache.evictAll();\n        return cachedFile;\n    }\n\n    @Nullable\n    private File getUpdatedDexFile(@NonNull Map<String, List<Action>> actionList) throws IOException {\n        if (!Objects.requireNonNull(getOptions()).readWrite || actionList.isEmpty()) {\n            return null;\n        }\n        String extension = getFile().getExtension();\n        File file = FileCache.getGlobalFileCache().createCachedFile(extension);\n        Map<String, ClassInfo> classInfoMap = new HashMap<>();\n        for (String className : Objects.requireNonNull(mDexClasses).getClassNames()) {\n            classInfoMap.put(File.separator + className, new ClassInfo(null, true));\n        }\n        for (String path : actionList.keySet()) {\n            // Perform action for each path\n            List<Action> actions = actionList.get(path);\n            if (actions == null) continue;\n            for (Action action : actions) {\n                Node<?> targetNode = action.targetNode;\n                // Actions are linear\n                switch (action.action) {\n                    case ACTION_CREATE:\n                        // This must be a new file/folder. So, override the existing one.\n                        classInfoMap.put(targetNode.getFullPath(), new ClassInfo(null, false, targetNode.isDirectory()));\n                        break;\n                    case ACTION_DELETE:\n                        // Delete the entry\n                        classInfoMap.remove(targetNode.getFullPath());\n                        break;\n                    case ACTION_UPDATE: {\n                        // It's a file and it's updated. So, cached file must exist.\n                        File cachedFile = Objects.requireNonNull(action.getCachedPath());\n                        String targetPath = targetNode.getFullPath();\n                        ClassInfo classInfo = classInfoMap.get(targetPath);\n                        classInfoMap.put(targetPath, new ClassInfo(cachedFile, classInfo != null && classInfo.physical));\n                        break;\n                    }\n                    case ACTION_MOVE:\n                        // File/directory move\n                        String sourcePath = Objects.requireNonNull(action.getSourcePath());\n                        ClassInfo classInfo = classInfoMap.get(sourcePath);\n                        if (classInfo != null) {\n                            classInfoMap.put(targetNode.getFullPath(), classInfo);\n                        } else {\n                            classInfoMap.put(targetNode.getFullPath(), new ClassInfo(null, false, targetNode.isDirectory()));\n                        }\n                        classInfoMap.remove(sourcePath);\n                        break;\n                }\n            }\n        }\n        // Build dex\n        List<String> paths = new ArrayList<>(classInfoMap.keySet());\n        Collections.sort(paths);\n        List<ClassDef> classDefList = new ArrayList<>(paths.size());\n        for (String path : paths) {\n            String className = path.substring(1);\n            ClassInfo classInfo = Objects.requireNonNull(classInfoMap.get(path));\n            if (classInfo.directory) {\n                // Skip all directories\n                continue;\n            }\n            if (classInfo.cachedFile != null) {\n                // The class was modified\n                try {\n                    classDefList.add(DexUtils.toClassDef(classInfo.cachedFile, getApiLevel()));\n                } catch (RecognitionException e) {\n                    throw new IOException(e);\n                }\n                continue;\n            }\n            if (classInfo.physical) {\n                try {\n                    classDefList.add(mDexClasses.getClassDef(className));\n                } catch (ClassNotFoundException e) {\n                    throw new IOException(e);\n                }\n            }\n            // Skip other non-physical classes because they were never modified and will fail\n        }\n        DexUtils.storeDex(classDefList, new FileDataStore(file), getApiLevel());\n        return file;\n    }\n\n    @Nullable\n    @Override\n    protected Node<?> getNode(String path) {\n        checkMounted();\n        Node<ClassDef> targetNode = mCache.get(path);\n        if (targetNode == null) {\n            if (path.equals(File.separator)) {\n                targetNode = mRootNode;\n            } else {\n                targetNode = Objects.requireNonNull(mRootNode).getLastChild(Paths.sanitize(path, true));\n            }\n            if (targetNode != null) {\n                mCache.put(path, targetNode);\n            }\n        }\n        return targetNode;\n    }\n\n    @Override\n    protected void invalidate(String path) {\n        mCache.remove(path);\n    }\n\n    @Override\n    protected long lastModified(@NonNull Node<?> node) {\n        return getFile().lastModified();\n    }\n\n    @Override\n    public long length(String path) {\n        Node<?> targetNode = getNode(path);\n        if (targetNode == null) {\n            return -1;\n        }\n        if (targetNode.isDirectory()) {\n            return 0L;\n        }\n        if (!targetNode.isFile() || targetNode.getObject() == null) {\n            return -1;\n        }\n        try {\n            return Objects.requireNonNull(mDexClasses)\n                    .getClassContents((ClassDef) targetNode.getObject())\n                    .getBytes(StandardCharsets.UTF_8)\n                    .length;\n        } catch (ClassNotFoundException e) {\n            return -1;\n        }\n    }\n\n    @SuppressWarnings({\"PointlessBooleanExpression\", \"ConstantConditions\"})\n    @Override\n    public boolean checkAccess(String path, int access) {\n        Node<?> targetNode = getNode(path);\n        if (access == OsConstants.F_OK) {\n            return targetNode != null;\n        }\n        boolean canAccess = true;\n        if ((access & OsConstants.R_OK) != 0) {\n            canAccess &= true;\n        }\n        if ((access & OsConstants.W_OK) != 0) {\n            canAccess &= false;\n        }\n        if ((access & OsConstants.X_OK) != 0) {\n            canAccess &= false;\n        }\n        return canAccess;\n    }\n\n    @NonNull\n    @Override\n    protected InputStream getInputStream(@NonNull Node<?> node) throws IOException {\n        ClassDef classDef = (ClassDef) node.getObject();\n        if (classDef == null) {\n            throw new FileNotFoundException(\"Class definition for \" + node.getFullPath() + \" is not found.\");\n        }\n        try {\n            return new ByteArrayInputStream(getDexClasses().getClassContents(classDef).getBytes(StandardCharsets.UTF_8));\n        } catch (ClassNotFoundException e) {\n            throw new IOException(e);\n        }\n    }\n\n    @Override\n    protected void cacheFile(@NonNull Node<?> src, @NonNull File sink) throws IOException {\n        ClassDef classDef = (ClassDef) src.getObject();\n        if (classDef == null) {\n            throw new FileNotFoundException(\"Class definition for \" + src.getFullPath() + \" is not found.\");\n        }\n        try (FileOutputStream os = new FileOutputStream(sink)) {\n            os.write(getDexClasses().getClassContents(classDef).getBytes(StandardCharsets.UTF_8));\n        } catch (ClassNotFoundException e) {\n            throw new IOException(e);\n        }\n    }\n\n    @NonNull\n    private static Node<ClassDef> buildTree(@NonNull DexClasses dexClasses) {\n        Node<ClassDef> rootNode = new Node<>(null, File.separator);\n        List<String> classNames = dexClasses.getClassNames();\n        for (String className : classNames) {\n            ClassDef classDef;\n            try {\n                classDef = dexClasses.getClassDef(className);\n            } catch (ClassNotFoundException e) {\n                classDef = null;\n            }\n            buildTree(rootNode, className, Objects.requireNonNull(classDef));\n        }\n        return rootNode;\n    }\n\n    // Build nodes as needed by the entry, entry itself is the last node in the tree if it is not a directory\n    private static void buildTree(@NonNull Node<ClassDef> rootNode, @NonNull String className, @NonNull ClassDef classDef) {\n        String[] components = className.split(\"\\\\.\");\n        if (components.length == 0) {\n            return;\n        }\n        Node<ClassDef> lastNode = rootNode;\n        for (int i = 0; i < components.length - 1 /* last one will be set manually */; ++i) {\n            Node<ClassDef> newNode = lastNode.getChild(components[i]);\n            if (newNode == null) {\n                // Add children\n                newNode = new Node<>(lastNode, components[i]);\n                lastNode.addChild(newNode);\n            }\n            lastNode = newNode;\n        }\n        lastNode.addChild(new Node<>(lastNode, components[components.length - 1] + \".smali\", classDef));\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/io/fs/VirtualFileSystem.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.io.fs;\n\nimport static io.github.muntashirakon.io.FileSystemManager.MODE_READ_ONLY;\nimport static io.github.muntashirakon.io.FileSystemManager.MODE_READ_WRITE;\nimport static io.github.muntashirakon.io.FileSystemManager.MODE_WRITE_ONLY;\n\nimport android.net.Uri;\nimport android.os.ParcelFileDescriptor;\nimport android.system.OsConstants;\n\nimport androidx.annotation.IntDef;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.WorkerThread;\nimport androidx.collection.SparseArrayCompat;\n\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileNotFoundException;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.nio.channels.FileChannel;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.concurrent.ThreadLocalRandom;\n\nimport io.github.muntashirakon.AppManager.logs.Log;\nimport io.github.muntashirakon.AppManager.self.filecache.FileCache;\nimport io.github.muntashirakon.AppManager.utils.ArrayUtils;\nimport io.github.muntashirakon.io.FileSystemManager;\nimport io.github.muntashirakon.io.Path;\nimport io.github.muntashirakon.io.Paths;\nimport io.github.muntashirakon.io.UidGidPair;\n\n@SuppressWarnings(\"unused\")\npublic abstract class VirtualFileSystem {\n    public static final String TAG = VirtualFileSystem.class.getSimpleName();\n\n    public static class MountOptions {\n        public static class Builder {\n            private boolean mRemount = false;\n            private boolean mReadWrite = false;\n            private int mMode = 0;\n            @Nullable\n            private UidGidPair mUidGidPair = null;\n            @Nullable\n            private OnFileSystemUnmounted mOnFileSystemUnmounted = null;\n\n            public Builder setRemount(boolean remount) {\n                mRemount = remount;\n                return this;\n            }\n\n            public Builder setReadWrite(boolean readWrite) {\n                mReadWrite = readWrite;\n                return this;\n            }\n\n            public Builder setMode(int mode) {\n                mMode = mode;\n                return this;\n            }\n\n            public Builder setUidGidPair(@Nullable UidGidPair uidGidPair) {\n                mUidGidPair = uidGidPair;\n                return this;\n            }\n\n            public Builder setOnFileSystemUnmounted(@Nullable OnFileSystemUnmounted fileSystemUnmounted) {\n                mOnFileSystemUnmounted = fileSystemUnmounted;\n                return this;\n            }\n\n            public MountOptions build() {\n                return new MountOptions(mRemount, mReadWrite, mMode, mUidGidPair, mOnFileSystemUnmounted);\n            }\n        }\n\n        public final boolean remount;\n        public final boolean readWrite;\n        public final int mode;\n        @Nullable\n        public final UidGidPair uidGidPair;\n        @Nullable\n        public final OnFileSystemUnmounted onFileSystemUnmounted;\n\n        private MountOptions(boolean remount, boolean readWrite, int mode, @Nullable UidGidPair uidGidPair,\n                             @Nullable OnFileSystemUnmounted fileSystemUnmounted) {\n            this.remount = remount;\n            this.readWrite = readWrite;\n            this.mode = mode;\n            this.uidGidPair = uidGidPair;\n            this.onFileSystemUnmounted = fileSystemUnmounted;\n        }\n    }\n\n    public static final String SCHEME = \"vfs\";\n\n    public static Uri getUri(int fsId, @Nullable String path) {\n        return new Uri.Builder()\n                .scheme(SCHEME)\n                .authority(String.valueOf(fsId))\n                .path(path != null ? path : File.separator)\n                .build();\n    }\n\n    @NonNull\n    private static VirtualFileSystem getNewInstance(@NonNull Path file, @NonNull String type) {\n        if (ZipFileSystem.TYPE.equals(type)) {\n            return new ZipFileSystem(file);\n        }\n        if (ApkFileSystem.TYPE.equals(type)) {\n            return new ApkFileSystem(file);\n        }\n        if (DexFileSystem.TYPE.equals(type)) {\n            return new DexFileSystem(file);\n        }\n        throw new IllegalArgumentException(\"Invalid type \" + type);\n    }\n\n    private static final SparseArrayCompat<VirtualFileSystem> sFileSystems = new SparseArrayCompat<>(3);\n    private static final HashMap<Uri, Integer> sUriVfsIdsMap = new HashMap<>(3);\n    private static final HashMap<Uri, List<Integer>> sParentUriVfsIdsMap = new HashMap<>(3);\n\n    @WorkerThread\n    public static int mount(@NonNull Uri mountPoint, @NonNull Path file, @NonNull String type) throws IOException {\n        return mount(mountPoint, file, type, new MountOptions.Builder().build());\n    }\n\n    @WorkerThread\n    public static int mount(@NonNull Uri mountPoint,\n                            @NonNull Path file,\n                            @NonNull String type,\n                            @NonNull MountOptions options)\n            throws IOException {\n        return mount(mountPoint, getNewInstance(file, type), options);\n    }\n\n    @WorkerThread\n    private static int mount(@NonNull Uri mountPoint, @NonNull VirtualFileSystem fs, @NonNull MountOptions options)\n            throws IOException {\n        int vfsId;\n        synchronized (sFileSystems) {\n            synchronized (sUriVfsIdsMap) {\n                if (!options.remount && sUriVfsIdsMap.get(mountPoint) != null) {\n                    throw new IOException(String.format(\"Mount point (%s) is already in use.\", mountPoint));\n                }\n            }\n            do {\n                vfsId = ThreadLocalRandom.current().nextInt(1, Integer.MAX_VALUE);\n            } while (vfsId == 0 || sFileSystems.get(vfsId) != null);\n            fs.mount(mountPoint, vfsId, options);\n            sFileSystems.put(vfsId, fs);\n        }\n        synchronized (sUriVfsIdsMap) {\n            sUriVfsIdsMap.put(mountPoint, vfsId);\n        }\n        synchronized (sParentUriVfsIdsMap) {\n            Uri uri = Paths.removeLastPathSegment(mountPoint);\n            List<Integer> vfsIds = sParentUriVfsIdsMap.get(uri);\n            if (vfsIds == null) {\n                vfsIds = new ArrayList<>(1);\n                sParentUriVfsIdsMap.put(uri, vfsIds);\n            }\n            vfsIds.add(vfsId);\n        }\n        Log.d(TAG, \"Mounted %d at %s\", vfsId, mountPoint);\n        return vfsId;\n    }\n\n    @WorkerThread\n    public static void unmount(int vfsId) throws IOException {\n        VirtualFileSystem fs = getFileSystem(vfsId);\n        if (fs == null) return;\n        Uri mountPoint = fs.getMountPoint();\n        synchronized (sFileSystems) {\n            sFileSystems.remove(vfsId);\n        }\n        synchronized (sUriVfsIdsMap) {\n            sUriVfsIdsMap.remove(mountPoint);\n        }\n        synchronized (sParentUriVfsIdsMap) {\n            if (mountPoint != null) {\n                Uri uri = Paths.removeLastPathSegment(mountPoint);\n                List<Integer> vfsIds = sParentUriVfsIdsMap.get(uri);\n                if (vfsIds != null && vfsIds.contains(vfsId)) {\n                    if (vfsIds.size() == 1) sParentUriVfsIdsMap.remove(uri);\n                    else vfsIds.remove((Integer) vfsId);\n                }\n            }\n        }\n        fs.unmount();\n        Log.d(TAG, \"%d unmounted at %s\", vfsId, mountPoint);\n    }\n\n    public static void alterMountPoint(Uri oldMountPoint, Uri newMountPoint) {\n        VirtualFileSystem fs = getFileSystem(oldMountPoint);\n        if (fs == null) return;\n        synchronized (sUriVfsIdsMap) {\n            sUriVfsIdsMap.remove(oldMountPoint);\n            sUriVfsIdsMap.put(newMountPoint, fs.getFsId());\n        }\n        synchronized (sParentUriVfsIdsMap) {\n            // Remove old mount point\n            Uri oldParent = Paths.removeLastPathSegment(oldMountPoint);\n            List<Integer> oldFsIds = sParentUriVfsIdsMap.get(oldParent);\n            if (oldFsIds != null) {\n                oldFsIds.remove((Integer) fs.getFsId());\n            }\n            // Add new mount point\n            Uri newParent = Paths.removeLastPathSegment(newMountPoint);\n            List<Integer> newFsIds = sParentUriVfsIdsMap.get(newParent);\n            if (newFsIds == null) {\n                newFsIds = new ArrayList<>(1);\n                sParentUriVfsIdsMap.put(newParent, newFsIds);\n            }\n            newFsIds.add(fs.getFsId());\n        }\n        fs.mMountPoint = newMountPoint;\n        Log.d(TAG, \"Mount point of %d altered from %s to %s\", fs.getFsId(), oldMountPoint, newMountPoint);\n    }\n\n    public static boolean isMountPoint(@NonNull Uri uri) {\n        return getFileSystem(uri) != null;\n    }\n\n    /**\n     * @see #getRootPath()\n     */\n    @Nullable\n    public static Path getFsRoot(int vfsId) {\n        VirtualFileSystem fs = getFileSystem(vfsId);\n        return fs != null ? fs.getRootPath() : null;\n    }\n\n    /**\n     * @see #getRootPath()\n     */\n    @Nullable\n    public static Path getFsRoot(Uri mountPoint) {\n        Integer vfsId;\n        synchronized (sUriVfsIdsMap) {\n            vfsId = sUriVfsIdsMap.get(mountPoint);\n        }\n        if (vfsId == null) return null;\n        return getFsRoot(vfsId);\n    }\n\n    @Nullable\n    public static VirtualFileSystem getFileSystem(Uri mountPoint) {\n        Integer vfsId;\n        synchronized (sUriVfsIdsMap) {\n            vfsId = sUriVfsIdsMap.get(mountPoint);\n        }\n        if (vfsId == null) return null;\n        return getFileSystem(vfsId);\n    }\n\n    @Nullable\n    public static VirtualFileSystem getFileSystem(int vfsId) {\n        synchronized (sFileSystems) {\n            return sFileSystems.get(vfsId);\n        }\n    }\n\n    @NonNull\n    public static VirtualFileSystem[] getFileSystemsAtUri(Uri parentUri) {\n        List<Integer> vfsIds;\n        synchronized (sParentUriVfsIdsMap) {\n            vfsIds = sParentUriVfsIdsMap.get(parentUri);\n        }\n        if (vfsIds == null) return ArrayUtils.emptyArray(VirtualFileSystem.class);\n        VirtualFileSystem[] fs = new VirtualFileSystem[vfsIds.size()];\n        synchronized (sFileSystems) {\n            for (int i = 0; i < fs.length; ++i) {\n                fs[i] = sFileSystems.get(vfsIds.get(i));\n            }\n        }\n        return fs;\n    }\n\n    /* Static members ends */\n\n    public interface OnFileSystemUnmounted {\n        /**\n         * Run after the file is unmounted.\n         *\n         * @param fs         The file system, now unusable\n         * @param cachedFile The cached file created by the file system if it supports writing\n         * @return {@code true} if the cached file is handled manually, {@code false} otherwise. The file should be\n         * handled manually in most cases.\n         */\n        boolean onUnmounted(@NonNull VirtualFileSystem fs, @Nullable File cachedFile);\n    }\n\n    @IntDef({ACTION_CREATE, ACTION_UPDATE, ACTION_DELETE, ACTION_MOVE})\n    @Retention(RetentionPolicy.SOURCE)\n    protected @interface CrudAction {\n    }\n\n    /**\n     * Create a new path in the system. {@link Action#targetNode} for this action may not exist.\n     */\n    protected static final int ACTION_CREATE = 1;\n    protected static final int ACTION_UPDATE = 2;\n    protected static final int ACTION_DELETE = 3;\n    protected static final int ACTION_MOVE = 4;\n\n    protected static class Action {\n        @CrudAction\n        public final int action;\n        /**\n         * Target path within this file system. It may or may not be an actual path depending on the previous actions.\n         */\n        @NonNull\n        public final Node<?> targetNode;\n\n        /**\n         * Cached path is located outside the file system, in a physical location. Contents of this path is later used\n         * to modify the virtual file system.\n         */\n        @Nullable\n        private File mCachedPath;\n        // Only applicable for ACTION_MOVE\n        private String mSourcePath;\n\n        public Action(@CrudAction int action, @NonNull Node<?> targetNode) {\n            this.action = action;\n            this.targetNode = targetNode;\n        }\n\n        private void setCachedPath(@Nullable File cachedPath) {\n            mCachedPath = cachedPath;\n        }\n\n        @Nullable\n        public File getCachedPath() {\n            return mCachedPath;\n        }\n\n        private void setSourcePath(String sourcePath) {\n            mSourcePath = sourcePath;\n        }\n\n        public String getSourcePath() {\n            return mSourcePath;\n        }\n\n        @Override\n        public boolean equals(Object o) {\n            if (this == o) return true;\n            if (!(o instanceof Action)) return false;\n            Action action1 = (Action) o;\n            return action == action1.action;\n        }\n\n        @Override\n        public int hashCode() {\n            return Objects.hash(action);\n        }\n    }\n\n    private static class FileCacheItem {\n        @NonNull\n        public final File cachedFile;\n\n        private boolean mModified;\n\n        private FileCacheItem(@NonNull File cachedFile) {\n            this.cachedFile = cachedFile;\n        }\n\n        public void setModified(boolean modified) {\n            mModified = modified;\n        }\n\n        public boolean isModified() {\n            return mModified;\n        }\n\n        @Override\n        public boolean equals(Object o) {\n            if (this == o) return true;\n            if (!(o instanceof FileCacheItem)) return false;\n            FileCacheItem fileCacheItem = (FileCacheItem) o;\n            return cachedFile.equals(fileCacheItem.cachedFile);\n        }\n\n        @Override\n        public int hashCode() {\n            return Objects.hash(cachedFile);\n        }\n    }\n\n    private final Object sLock = new Object();\n    @NonNull\n    private final Map<String, List<Action>> mActions = new HashMap<>();\n    private final Map<String, FileCacheItem> mFileCacheMap = new HashMap<>();\n    private final FileCache mFileCache = new FileCache();\n    @NonNull\n    private final Path mFile;\n\n    @Nullable\n    private Uri mMountPoint;\n    @Nullable\n    private MountOptions mOptions;\n    private int mFsId = 0;\n    private Path mRootPath;\n\n    protected VirtualFileSystem(@NonNull Path file) {\n        mFile = file;\n    }\n\n    @NonNull\n    public Path getFile() {\n        return mFile;\n    }\n\n    public abstract String getType();\n\n    public int getFsId() {\n        return mFsId;\n    }\n\n    /**\n     * Return the abstract location where the file system is mounted. This is similar to the mount point returned by the\n     * {@code mount} command.\n     */\n    @Nullable\n    public final Uri getMountPoint() {\n        return mMountPoint;\n    }\n\n    @Nullable\n    public MountOptions getOptions() {\n        return mOptions;\n    }\n\n    /**\n     * Return the abstract location where the file system is located. This is not the same as {@link #getMountPoint()}\n     * which returns the abstract location where the file system is mounted. In other words, this is the real location\n     * to the file system, and should never be used other than the Path APIs.\n     */\n    @NonNull\n    public Path getRootPath() {\n        return Objects.requireNonNull(mRootPath);\n    }\n\n    /**\n     * Mount the file system.\n     *\n     * @param fsId Unique file system ID to locate it.\n     * @throws IOException If the file system cannot be mounted.\n     */\n    private void mount(@NonNull Uri mountPoint, int fsId, MountOptions options) throws IOException {\n        synchronized (sLock) {\n            mMountPoint = mountPoint;\n            mFsId = fsId;\n            mOptions = options;\n            onPreMount();\n            mRootPath = onMount();\n            onMounted();\n        }\n    }\n\n\n    /**\n     * Instructions to execute before mounting the file system.\n     * <p>\n     * Note that the root path haven't been initialised at this point and calling {@link #getRootPath()} would throw\n     * an NPE.\n     */\n    protected void onPreMount() {\n    }\n\n    /**\n     * Mount the file system. Operations related to mounting the file system should be done here.\n     *\n     * @return The real path of the file system AKA root path.\n     * @see #getRootPath()\n     */\n    protected abstract Path onMount() throws IOException;\n\n    /**\n     * Instructions to execute after mounting the file system. Any initialisations such as building file trees should\n     * be done where.\n     */\n    protected void onMounted() {\n    }\n\n    private void unmount() throws IOException {\n        checkMounted();\n        Objects.requireNonNull(mOptions);\n        synchronized (sLock) {\n            // Update actions\n            for (String path : mFileCacheMap.keySet()) {\n                FileCacheItem fileCacheItem = Objects.requireNonNull(mFileCacheMap.get(path));\n                if (fileCacheItem.isModified()) {\n                    Node<?> node = getNode(path);\n                    if (node != null) {\n                        Action action = new Action(ACTION_UPDATE, node);\n                        action.setCachedPath(fileCacheItem.cachedFile);\n                        addAction(node.getFullPath(), action);\n                    }\n                }\n            }\n            File cachedFile = onUnmount(mActions);\n            mFsId = 0;\n            mMountPoint = null;\n            // Cleanup\n            mFileCacheMap.clear();\n            mFileCache.deleteAll();\n            mActions.clear();\n            // Handle cached file\n            if (cachedFile != null) {\n                // Run interface if available\n                boolean handled = mOptions.onFileSystemUnmounted != null\n                        && mOptions.onFileSystemUnmounted.onUnmounted(this, cachedFile);\n                if (!handled) {\n                    // Cached file isn't handled above, try the default ignoring all issues\n                    Path dest = getFile();\n                    Path source = Paths.get(cachedFile);\n                    dest.delete();\n                    source.moveTo(dest);\n                }\n            }\n            mOptions = null;\n            onUnmounted();\n        }\n    }\n\n    @Override\n    protected void finalize() {\n        mFileCache.close();\n    }\n\n    /**\n     * Instructions to execute to unmount the file system. Example operations include cleaning up trees, saving\n     * changes, closing resources.\n     *\n     * @return The final cached file if the file system support modification, {@code null} otherwise.\n     */\n    @Nullable\n    protected abstract File onUnmount(@NonNull Map<String, List<Action>> actions) throws IOException;\n\n    /**\n     * Instructions to execute after unmounting the file system.\n     */\n    protected void onUnmounted() {\n    }\n\n    protected void checkMounted() {\n        synchronized (sLock) {\n            if (mFsId == 0) {\n                throw new NotMountedException(\"Not mounted\");\n            }\n        }\n    }\n\n    /* File APIs */\n    private void addAction(@NonNull String path, @NonNull Action action) {\n        synchronized (mActions) {\n            List<Action> actionSet = mActions.get(path);\n            if (actionSet == null) {\n                actionSet = new ArrayList<>();\n                mActions.put(path, actionSet);\n            }\n            actionSet.add(action);\n        }\n    }\n\n    @Nullable\n    protected abstract Node<?> getNode(String path);\n\n    protected abstract void invalidate(String path);\n\n    @Nullable\n    public String getCanonicalPath(String path) {\n        checkMounted();\n        return null;\n    }\n\n    public boolean isDirectory(String path) {\n        Node<?> targetNode = getNode(path);\n        if (targetNode == null) {\n            return false;\n        }\n        return targetNode.isDirectory();\n    }\n\n    public boolean isFile(String path) {\n        Node<?> targetNode = getNode(path);\n        if (targetNode == null) {\n            return false;\n        }\n        return targetNode.isFile();\n    }\n\n    public boolean isHidden(String path) {\n        Node<?> targetNode = getNode(path);\n        if (targetNode == null) {\n            return false;\n        }\n        return targetNode.getName().startsWith(\".\");\n    }\n\n    protected abstract long lastModified(@NonNull Node<?> path);\n\n    public long lastModified(String path) {\n        Node<?> targetNode = getNode(path);\n        if (targetNode == null) {\n            return getFile().lastModified();\n        }\n        File cachedFile = findCachedFile(targetNode);\n        if (cachedFile != null) {\n            return cachedFile.lastModified();\n        }\n        return lastModified(targetNode);\n    }\n\n    public long lastAccess(String path) {\n        return lastModified(path);\n    }\n\n    public long creationTime(String path) {\n        return lastModified(path);\n    }\n\n    public abstract long length(String path);\n\n    public boolean createNewFile(String path) {\n        if (checkAccess(path, OsConstants.F_OK)) {\n            return false;\n        }\n        String filename = Paths.getLastPathSegment(path);\n        String parent = Paths.removeLastPathSegment(path);\n        if (!checkAccess(parent, OsConstants.W_OK)) {\n            return false;\n        }\n        Node<?> parentNode = getNode(parent);\n        if (parentNode == null || !parentNode.isDirectory()) {\n            return false;\n        }\n        Node<?> newFileNode = new Node<>(parentNode, filename, false);\n        newFileNode.setFile(true);\n        parentNode.addChild(newFileNode);\n        addAction(newFileNode.getFullPath(), new Action(ACTION_CREATE, newFileNode));\n        invalidate(path);\n        return true;\n    }\n\n    public boolean delete(String path) {\n        if (!checkAccess(path, OsConstants.W_OK)) {\n            return false;\n        }\n        Node<?> targetNode = getNode(path);\n        if (targetNode == null) {\n            return false;\n        }\n        addAction(targetNode.getFullPath(), new Action(ACTION_DELETE, targetNode));\n        Node<?> parentNode = targetNode.getParent();\n        if (parentNode != null) {\n            parentNode.removeChild(targetNode);\n        }\n        invalidate(path);\n        return true;\n    }\n\n    @Nullable\n    public String[] list(String path) {\n        Node<?> targetNode = getNode(path);\n        if (targetNode == null) {\n            return null;\n        }\n        Node<?>[] children = targetNode.listChildren();\n        if (children == null) {\n            return null;\n        }\n        String[] childNames = new String[children.length];\n        for (int i = 0; i < children.length; ++i) {\n            childNames[i] = children[i].getName();\n        }\n        return childNames;\n    }\n\n    public boolean mkdir(String path) {\n        if (checkAccess(path, OsConstants.F_OK)) {\n            // File/folder exists\n            return false;\n        }\n        String filename = Paths.getLastPathSegment(path);\n        String parent = Paths.removeLastPathSegment(path);\n        if (!checkAccess(parent, OsConstants.W_OK)) {\n            return false;\n        }\n        Node<?> parentNode = getNode(parent);\n        if (parentNode == null || !parentNode.isDirectory()) {\n            return false;\n        }\n        Node<?> newFileNode = new Node<>(parentNode, filename, false);\n        newFileNode.setDirectory(true);\n        parentNode.addChild(newFileNode);\n        addAction(newFileNode.getFullPath(), new Action(ACTION_CREATE, newFileNode));\n        invalidate(path);\n        return true;\n    }\n\n    public boolean mkdirs(String path) {\n        if (checkAccess(path, OsConstants.F_OK)) {\n            // File/folder exists\n            return false;\n        }\n        List<String> parts = new ArrayList<>();\n        String parent = path;\n        Node<?> parentNode;\n        do {\n            String filename = Paths.getLastPathSegment(parent);\n            parent = Paths.removeLastPathSegment(parent);\n            parts.add(filename);\n            parentNode = getNode(parent);\n        } while (parentNode == null && !parent.equals(File.separator));\n        // Found a parent node\n        if (!checkAccess(parent, OsConstants.W_OK) || parentNode == null || !parentNode.isDirectory()) {\n            // Parent node is inaccessible\n            return false;\n        }\n        for (int i = parts.size() - 1; i >= 0; --i) {\n            parentNode = new Node<>(parentNode, parts.get(i), false);\n            parentNode.setDirectory(true);\n            Objects.requireNonNull(parentNode.getParent()).addChild(parentNode);\n            String fullPath = parentNode.getFullPath();\n            addAction(fullPath, new Action(ACTION_CREATE, parentNode));\n            invalidate(fullPath);\n        }\n        return true;\n    }\n\n    /**\n     * Similar to Java File API in Unix.\n     *\n     * <ul>\n     *  <li>If destination is a file, it overrides it.\n     *  <li>If destination is a directory, it overrides it only if it has no children.\n     *  <li>If destination is does not exist, it creates it.\n     * </ul>\n     */\n    public boolean renameTo(String source, String dest) {\n        // path and dest must belong to the same file system and are relative as usual.\n        if (dest.startsWith(source)) {\n            // Destination cannot be the same or a subdirectory of source\n            return false;\n        }\n        if (!checkAccess(source, OsConstants.W_OK)) {\n            // Directory not modifiable\n            return false;\n        }\n        boolean destExists = checkAccess(dest, OsConstants.F_OK);\n        Node<?> sourceNode = getNode(source);\n        if (sourceNode == null) {\n            return false;\n        }\n        if (sourceNode.isDirectory()) {\n            // Source node is a directory, so create some directories and move whatever this directory has.\n            String filename = Paths.getLastPathSegment(dest);\n            String parent = Paths.removeLastPathSegment(dest);\n            mkdirs(parent);\n            Node<?> targetNode = getNode(parent);\n            if (targetNode == null) {\n                return false;\n            }\n            if (destExists) {\n                // Override existing node\n                Node<?> node = getNode(filename);\n                if (node != null) {\n                    if (node.isFile()) {\n                        // Existing node is a file\n                        return false;\n                    } else if (node.listChildren() != null) {\n                        // Is a directory with children\n                        return false;\n                    } else {\n                        // A directory with no children\n                        addAction(dest, new Action(ACTION_DELETE, node));\n                        targetNode.removeChild(node);\n                        invalidate(dest);\n                    }\n                }\n            }\n            // Rename sourceNode to filename\n            moveChildren(sourceNode, source, dest);\n            Node<?> parentNode = sourceNode.getParent();\n            if (parentNode != null) {\n                parentNode.removeChild(sourceNode);\n            }\n            @SuppressWarnings({\"unchecked\", \"rawtypes\"})\n            Node<?> renamedNode = new Node(targetNode, sourceNode, filename);\n            Action action = new Action(ACTION_MOVE, renamedNode);\n            action.setSourcePath(source);\n            if (!dest.equals(renamedNode.getFullPath())) {\n                throw new IllegalStateException(String.format(Locale.ROOT, \"Invalid destination for the renamed node. Required: %s, was: %s\", dest, renamedNode.getFullPath()));\n            }\n            addAction(dest, action);\n            targetNode.addChild(renamedNode);\n            invalidate(source);\n        } else if (sourceNode.isFile()) {\n            // Source node is a file, create some directories up to this point and move this file to there\n            // Overriding the existing one if necessary.\n            String filename = Paths.getLastPathSegment(dest);\n            String parent = Paths.removeLastPathSegment(dest);\n            // Output of mkdirs is not relevant\n            mkdirs(parent);\n            Node<?> targetNode = getNode(parent);\n            if (targetNode == null) {\n                return false;\n            }\n            if (destExists) {\n                // Override existing node\n                Node<?> destNode = getNode(filename);\n                if (destNode != null) {\n                    if (destNode.isDirectory()) {\n                        // Existing node is a directory\n                        return false;\n                    }\n                    addAction(dest, new Action(ACTION_DELETE, destNode));\n                    targetNode.removeChild(destNode);\n                    invalidate(dest);\n                }\n            }\n            // Rename sourceNode to filename\n            Node<?> parentNode = sourceNode.getParent();\n            if (parentNode != null) {\n                parentNode.removeChild(sourceNode);\n            }\n            @SuppressWarnings({\"unchecked\", \"rawtypes\"})\n            Node<?> renamedNode = new Node(targetNode, sourceNode, filename);\n            Action action = new Action(ACTION_MOVE, renamedNode);\n            action.setSourcePath(source);\n            if (!dest.equals(renamedNode.getFullPath())) {\n                throw new IllegalStateException(String.format(Locale.ROOT, \"Invalid destination for the renamed node. Required: %s, was: %s\", dest, renamedNode.getFullPath()));\n            }\n            addAction(dest, action);\n            // Check if it's cached\n            FileCacheItem cache = mFileCacheMap.remove(source);\n            if (cache != null) {\n                // Cache exists, alter it\n                mFileCacheMap.put(dest, cache);\n            }\n            targetNode.addChild(renamedNode);\n            invalidate(source);\n        }\n        return true;\n    }\n\n    private void moveChildren(@NonNull Node<?> parentNode, @NonNull String sourceBase, @NonNull String destBase) {\n        Node<?>[] children = parentNode.listChildren();\n        if (children == null) {\n            return;\n        }\n        for (Node<?> node : children) {\n            moveChildren(node, sourceBase, destBase);\n            // Move this node\n            String source = node.getFullPath();\n            String dest = new File(destBase, Paths.relativePath(sourceBase, source)).getAbsolutePath();\n            Action action = new Action(ACTION_MOVE, node);\n            action.setSourcePath(source);\n            addAction(dest, action);\n            // Check if it's cached\n            FileCacheItem cache = mFileCacheMap.remove(source);\n            if (cache != null) {\n                // Cache exists, alter it\n                mFileCacheMap.put(dest, cache);\n            }\n            invalidate(source);\n            invalidate(dest);\n        }\n    }\n\n    public boolean setLastModified(String path, long time) {\n        checkMounted();\n        return false;\n    }\n\n    public boolean setReadOnly(String path) {\n        checkMounted();\n        return false;\n    }\n\n    public boolean setWritable(String path, boolean writable, boolean ownerOnly) {\n        checkMounted();\n        return false;\n    }\n\n    public boolean setReadable(String path, boolean readable, boolean ownerOnly) {\n        checkMounted();\n        return false;\n    }\n\n    public boolean setExecutable(String path, boolean executable, boolean ownerOnly) {\n        checkMounted();\n        return false;\n    }\n\n    public abstract boolean checkAccess(String path, int access);\n\n//    public abstract long getTotalSpace(String path);\n//\n//    public abstract long getFreeSpace(String path);\n//\n//    public abstract long getUsableSpace(String path);\n\n    @SuppressWarnings(\"OctalInteger\")\n    public int getMode(String path) {\n        Node<?> targetNode = getNode(path);\n        if (targetNode == null) {\n            return 0;\n        }\n        int mode = Objects.requireNonNull(getOptions()).mode & 0777;\n        if (mode == 0) {\n            mode = getOptions().readWrite ? 0666 : 0444;\n        }\n        if (targetNode.isDirectory()) {\n            return mode | OsConstants.S_IFDIR;\n        }\n        if (targetNode.isFile()) {\n            return mode | OsConstants.S_IFREG;\n        }\n        return 0;\n    }\n\n    public void setMode(String path, int mode) {\n        // TODO: 7/12/22 This should either throw ErrnoException or a boolean value\n        checkMounted();\n    }\n\n    @Nullable\n    public UidGidPair getUidGid(String path) {\n        checkMounted();\n        return Objects.requireNonNull(getOptions()).uidGidPair;\n    }\n\n    public void setUidGid(String path, int uid, int gid) {\n        // TODO: 7/12/22 This should either throw ErrnoException or a boolean value\n        checkMounted();\n    }\n\n    public boolean createLink(String link, String target, boolean soft) {\n        checkMounted();\n        return false;\n    }\n\n    /* I/O APIs */\n    @NonNull\n    public FileInputStream newInputStream(String path) throws IOException {\n        if (!checkAccess(path, OsConstants.R_OK)) {\n            throw new IOException(path + \" is inaccessible.\");\n        }\n        Node<?> targetNode = getNode(path);\n        if (targetNode == null) {\n            throw new FileNotFoundException(path + \" does not exist.\");\n        }\n        if (!targetNode.isFile()) {\n            throw new IOException(path + \" is not a file.\");\n        }\n        return new FileInputStream(getCachedFile(targetNode, false));\n    }\n\n    @NonNull\n    public FileOutputStream newOutputStream(String path, boolean append) throws IOException {\n        if (!checkAccess(path, OsConstants.W_OK)) {\n            throw new IOException(path + \" is inaccessible.\");\n        }\n        Node<?> targetNode = getNode(path);\n        if (targetNode == null) {\n            throw new FileNotFoundException(path + \" does not exist.\");\n        }\n        if (!targetNode.isFile()) {\n            throw new IOException(path + \" is not a file.\");\n        }\n        return new FileOutputStream(getCachedFile(targetNode, true), append);\n    }\n\n    @NonNull\n    public FileChannel openChannel(String path, int mode) throws IOException {\n        boolean read = false;\n        boolean write = false;\n        if ((mode & MODE_READ_WRITE) != 0) {\n            read = true;\n            write = true;\n        } else if ((mode & MODE_READ_ONLY) != 0) {\n            read = true;\n        } else if ((mode & MODE_WRITE_ONLY) != 0) {\n            write = true;\n        } else {\n            throw new IllegalArgumentException(\"Bad mode: \" + mode);\n        }\n\n        if (read && write && !checkAccess(path, OsConstants.R_OK | OsConstants.W_OK)) {\n            throw new IOException(path + \" cannot be opened for both reading and writing.\");\n        } else if (read && !checkAccess(path, OsConstants.R_OK)) {\n            throw new IOException(path + \" cannot be opened for both reading.\");\n        } else if (write && !checkAccess(path, OsConstants.W_OK)) {\n            throw new IOException(path + \" cannot be opened for both writing.\");\n        }\n        Node<?> targetNode = getNode(path);\n        if (targetNode == null) {\n            throw new FileNotFoundException(path + \" does not exist.\");\n        }\n        if (!targetNode.isFile()) {\n            throw new IOException(path + \" is not a file.\");\n        }\n        return FileSystemManager.getLocal().openChannel(getCachedFile(targetNode, write), mode);\n    }\n\n    @NonNull\n    public ParcelFileDescriptor openFileDescriptor(String path, int mode) throws IOException {\n        boolean read = false;\n        boolean write = false;\n        if ((mode & MODE_READ_WRITE) != 0) {\n            read = true;\n            write = true;\n        } else if ((mode & MODE_READ_ONLY) != 0) {\n            read = true;\n        } else if ((mode & MODE_WRITE_ONLY) != 0) {\n            write = true;\n        } else {\n            throw new IllegalArgumentException(\"Bad mode: \" + mode);\n        }\n\n        if (read && write && !checkAccess(path, OsConstants.R_OK | OsConstants.W_OK)) {\n            write = false;\n            // The below does not work with ContentProvider, only disable writing\n            // throw new IOException(path + \" cannot be opened for both reading and writing.\");\n        }\n        if (read && !checkAccess(path, OsConstants.R_OK)) {\n            throw new IOException(path + \" cannot be opened for both reading.\");\n        }\n        if (write && !checkAccess(path, OsConstants.W_OK)) {\n            throw new IOException(path + \" cannot be opened for both writing.\");\n        }\n        Node<?> targetNode = getNode(path);\n        if (targetNode == null) {\n            throw new FileNotFoundException(path + \" does not exist.\");\n        }\n        if (!targetNode.isFile()) {\n            throw new IOException(path + \" is not a file.\");\n        }\n        return ParcelFileDescriptor.open(getCachedFile(targetNode, write), mode);\n    }\n\n    @NonNull\n    protected abstract InputStream getInputStream(@NonNull Node<?> node) throws IOException;\n\n    protected abstract void cacheFile(@NonNull Node<?> src, @NonNull File sink) throws IOException;\n\n    @Nullable\n    protected File findCachedFile(@NonNull Node<?> node) {\n        FileCacheItem fileCacheItem = mFileCacheMap.get(node.getFullPath());\n        return fileCacheItem != null ? fileCacheItem.cachedFile : null;\n    }\n\n    protected File getCachedFile(@NonNull Node<?> node, boolean write) throws IOException {\n        FileCacheItem fileCacheItem = mFileCacheMap.get(node.getFullPath());\n        if (fileCacheItem != null) {\n            if (write) {\n                fileCacheItem.setModified(true);\n            }\n            return fileCacheItem.cachedFile;\n        }\n        // File hasn't been cached.\n        File cachedFile = mFileCache.createCachedFile(Paths.getPathExtension(node.getName()));\n        if (node.isPhysical()) {\n            // The file exists physically. It has to be cached first.\n            cacheFile(node, cachedFile);\n        }\n        fileCacheItem = new FileCacheItem(cachedFile);\n        if (write) {\n            fileCacheItem.setModified(true);\n        }\n        mFileCacheMap.put(node.getFullPath(), fileCacheItem);\n        return fileCacheItem.cachedFile;\n    }\n\n    /* File tree */\n    protected static class Node<T> {\n        // TODO: 23/11/22 Should include modification, creation, access times\n        @NonNull\n        private final String mName;\n        @Nullable\n        private final T mObject;\n        private final boolean mPhysical;\n        @Nullable\n        private final String mPhysicalFullPath;\n\n        @Nullable\n        private Node<T> mParent;\n        @Nullable\n        private HashMap<String, Node<T>> mChildren = null;\n        private boolean mDirectory;\n        @Nullable\n        private HashMap<String, Object> mExtra = null;\n\n        protected Node(@Nullable Node<T> parent, @NonNull String name) {\n            this(parent, name, null);\n        }\n\n        protected Node(@Nullable Node<T> parent, @NonNull String name, boolean physical) {\n            this(parent, name, null, physical);\n        }\n\n        protected Node(@Nullable Node<T> parent, @NonNull String name, @Nullable T object) {\n            this(parent, name, object, true);\n        }\n\n        protected Node(@Nullable Node<T> parent, @NonNull Node<T> node, @NonNull String newName) {\n            this(parent, newName, node.mObject, node.mPhysical);\n            mChildren = node.mChildren;\n            mDirectory = node.mDirectory;\n            if (mChildren != null) {\n                for (Node<T> child : mChildren.values()) {\n                    child.mParent = this;\n                }\n            }\n        }\n\n        protected Node(@Nullable Node<T> parent, @NonNull String name, @Nullable T object, boolean physical) {\n            mParent = parent;\n            mName = name;\n            mObject = object;\n            mPhysical = physical;\n            mDirectory = object == null;\n            mPhysicalFullPath = physical ? calculateFullPath(parent, this) : null;\n        }\n\n        @NonNull\n        public String getName() {\n            return mName;\n        }\n\n        @Nullable\n        public Node<T> getParent() {\n            return mParent;\n        }\n\n        @NonNull\n        public String getFullPath() {\n            return calculateFullPath(mParent, this);\n        }\n\n        @Nullable\n        public String getPhysicalFullPath() {\n            return mPhysicalFullPath;\n        }\n\n        @Nullable\n        public T getObject() {\n            return mObject;\n        }\n\n        public boolean isPhysical() {\n            return mPhysical;\n        }\n\n        public void setDirectory(boolean directory) {\n            mDirectory = directory;\n        }\n\n        public void setFile(boolean file) {\n            mDirectory = !file;\n        }\n\n        public boolean isDirectory() {\n            return mDirectory;\n        }\n\n        public boolean isFile() {\n            return !mDirectory;\n        }\n\n        @Nullable\n        public Node<T> getChild(String name) {\n            if (mChildren == null) return null;\n            return mChildren.get(name);\n        }\n\n        @Nullable\n        public Node<T> getLastChild(@Nullable String name) {\n            if (mChildren == null) return null;\n            return getLastNode(this, name);\n        }\n\n        @SuppressWarnings(\"unchecked\")\n        @Nullable\n        public Node<T>[] listChildren() {\n            if (mChildren == null || mChildren.isEmpty()) return null;\n            return mChildren.values().toArray(new Node[0]);\n        }\n\n        @SuppressWarnings(\"unchecked\")\n        public void addChild(@Nullable Node<?> child) {\n            if (child == null) return;\n            if (mChildren == null) mChildren = new HashMap<>();\n            Node<T> node = (Node<T>) child;\n            node.mParent = this;\n            mChildren.put(node.mName, node);\n        }\n\n        public void removeChild(@Nullable Node<?> child) {\n            if (child == null || mChildren == null) return;\n            mChildren.remove(child.mName);\n            child.mParent = null;\n        }\n\n        public <U> void addExtra(@NonNull String fieldName, @Nullable U object) {\n            if (mExtra == null) {\n                mExtra = new HashMap<>();\n            }\n            mExtra.put(fieldName, object);\n        }\n\n        @Nullable\n        public <U> U getExtra(@NonNull String fieldName) {\n            //noinspection unchecked\n            return mExtra != null ? (U) mExtra.get(fieldName) : null;\n        }\n\n        @Nullable\n        public <U> U removeExtra(@NonNull String fieldName) {\n            if (mExtra != null) {\n                Object v = mExtra.remove(fieldName);\n                if (v != null) {\n                    //noinspection unchecked\n                    return (U) v;\n                }\n            }\n            return null;\n        }\n\n        private static String calculateFullPath(@Nullable Node<?> parent, @NonNull Node<?> child) {\n            String basePath = parent == null ? File.separator : parent.getFullPath();\n            return (basePath.equals(File.separator) ? (child.mName.equals(File.separator) ? \"\" : File.separator)\n                    : basePath + File.separatorChar) + child.mName;\n        }\n\n        @SuppressWarnings(\"SuspiciousRegexArgument\") // Not on Windows\n        @Nullable\n        private static <T> Node<T> getLastNode(@NonNull Node<T> baseNode, @Nullable String dirtyPath) {\n            if (dirtyPath == null) return baseNode;\n            String path = Paths.sanitize(dirtyPath, true);\n            if (path == null) {\n                return baseNode;\n            }\n            String[] components = path.split(File.separator);\n            Node<T> lastNode = baseNode;\n            for (String component : components) {\n                lastNode = lastNode.getChild(component);\n                if (lastNode == null) {\n                    // File do not exist\n                    return null;\n                }\n            }\n            return lastNode;\n        }\n    }\n\n    public static class NotMountedException extends RuntimeException {\n        public NotMountedException() {\n            super();\n        }\n\n        public NotMountedException(String message) {\n            super(message);\n        }\n\n        public NotMountedException(String message, Throwable th) {\n            super(message, th);\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/io/fs/ZipFileSystem.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.io.fs;\n\nimport android.os.Build;\nimport android.system.OsConstants;\nimport android.util.LruCache;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport com.j256.simplemagic.ContentType;\n\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileNotFoundException;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.nio.file.attribute.FileTime;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.Enumeration;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\nimport java.util.zip.Deflater;\nimport java.util.zip.ZipEntry;\nimport java.util.zip.ZipFile;\nimport java.util.zip.ZipOutputStream;\n\nimport io.github.muntashirakon.AppManager.self.filecache.FileCache;\nimport io.github.muntashirakon.AppManager.utils.DigestUtils;\nimport io.github.muntashirakon.io.IoUtils;\nimport io.github.muntashirakon.io.Path;\nimport io.github.muntashirakon.io.Paths;\n\nclass ZipFileSystem extends VirtualFileSystem {\n    public static final String TYPE = ContentType.ZIP.getMimeType();\n\n    private static class VirtualZipEntry extends ZipEntry {\n        private File mCachedFile;\n\n        public VirtualZipEntry(String name) {\n            super(name);\n        }\n\n        public File getCachedFile() {\n            return mCachedFile;\n        }\n\n        public void setCachedFile(File cachedFile) {\n            mCachedFile = cachedFile;\n        }\n    }\n\n    private final LruCache<String, Node<ZipEntry>> mCache = new LruCache<>(100);\n    @Nullable\n    private ZipFile mZipFile;\n    @Nullable\n    private Node<ZipEntry> mRootNode;\n\n    protected ZipFileSystem(@NonNull Path zipFile) {\n        super(zipFile);\n    }\n\n    @Override\n    public String getType() {\n        return TYPE;\n    }\n\n    @Override\n    protected Path onMount() throws IOException {\n        if (Objects.requireNonNull(getOptions()).remount && mZipFile != null && mRootNode != null) {\n            // Remount requested, no need to generate anything if they're already generated.\n            return Paths.get(this);\n        }\n        mZipFile = new ZipFile(Objects.requireNonNull(getFile().getFile()));\n        mRootNode = buildTree(Objects.requireNonNull(mZipFile));\n        return Paths.get(this);\n    }\n\n    @Nullable\n    @Override\n    protected File onUnmount(@NonNull Map<String, List<Action>> actionList) throws IOException {\n        File cachedFile = getUpdatedZipFile(actionList);\n        mRootNode = null;\n        mCache.evictAll();\n        if (mZipFile != null) {\n            mZipFile.close();\n            mZipFile = null;\n        }\n        return cachedFile;\n    }\n\n    @Nullable\n    private File getUpdatedZipFile(@NonNull Map<String, List<Action>> actionList) throws IOException {\n        if (!Objects.requireNonNull(getOptions()).readWrite || actionList.isEmpty()) {\n            return null;\n        }\n        String extension = getFile().getExtension();\n        File file = FileCache.getGlobalFileCache().createCachedFile(extension);\n        Map<String, ZipEntry> zipEntries = new HashMap<>();\n        for (ZipEntry zipEntry : Collections.list(Objects.requireNonNull(mZipFile).entries())) {\n            zipEntries.put(Paths.sanitize(File.separator + zipEntry.getName(), false), zipEntry);\n        }\n        for (String path : actionList.keySet()) {\n            // Perform action for each path\n            List<Action> actions = actionList.get(path);\n            if (actions == null) continue;\n            for (Action action : actions) {\n                Node<?> targetNode = action.targetNode;\n                // Actions are linear\n                switch (action.action) {\n                    case ACTION_CREATE:\n                        // This must be a new file/folder. So, override the existing one.\n                        zipEntries.put(targetNode.getFullPath(), getNewZipEntry(targetNode));\n                        break;\n                    case ACTION_DELETE:\n                        // Delete the entry\n                        zipEntries.remove(targetNode.getFullPath());\n                        break;\n                    case ACTION_UPDATE:\n                        // It's a file and it's updated. So, cached file must exist.\n                        File cachedFile = Objects.requireNonNull(action.getCachedPath());\n                        zipEntries.put(targetNode.getFullPath(), getZipEntry(targetNode, cachedFile));\n                        break;\n                    case ACTION_MOVE:\n                        // File/directory move\n                        String sourcePath = Objects.requireNonNull(action.getSourcePath());\n                        ZipEntry zipEntry = zipEntries.get(sourcePath);\n                        if (zipEntry != null) {\n                            zipEntries.put(targetNode.getFullPath(), zipEntry);\n                        } else {\n                            zipEntries.put(targetNode.getFullPath(), getNewZipEntry(targetNode));\n                        }\n                        zipEntries.remove(sourcePath);\n                        break;\n                }\n            }\n        }\n        try (FileOutputStream os = new FileOutputStream(file);\n             ZipOutputStream zos = new ZipOutputStream(os)) {\n            zos.setMethod(ZipOutputStream.DEFLATED);\n            zos.setLevel(Deflater.BEST_COMPRESSION);\n            List<String> paths = new ArrayList<>(zipEntries.keySet());\n            Collections.sort(paths);\n            for (String path : paths) {\n                ZipEntry zipEntry = zipEntries.get(path);\n                if (zipEntry == null) continue;\n                if (zipEntry instanceof VirtualZipEntry) {\n                    // Our custom zip files\n                    zos.putNextEntry(zipEntry);\n                    if (zipEntry.isDirectory()) {\n                        zos.closeEntry();\n                        continue;\n                    }\n                    // Entry is a file\n                    File cachedFile = ((VirtualZipEntry) zipEntry).getCachedFile();\n                    if (cachedFile != null) {\n                        try (InputStream is = new FileInputStream(cachedFile)) {\n                            IoUtils.copy(is, zos);\n                        }\n                    } // else cached file was not created because the file was only created and never written to\n                    zos.closeEntry();\n                } else {\n                    // Not our custom files, need to copy from zipEntry everything except the name\n                    ZipEntry newZipEntry = getZipEntry(path, zipEntry);\n                    zos.putNextEntry(newZipEntry);\n                    if (zipEntry.isDirectory()) {\n                        zos.closeEntry();\n                        continue;\n                    }\n                    // Entry is a file\n                    try (InputStream is = mZipFile.getInputStream(zipEntry)) {\n                        IoUtils.copy(is, zos);\n                    }\n                    zos.closeEntry();\n                }\n            }\n        }\n        return file;\n    }\n\n    @NonNull\n    private ZipEntry getNewZipEntry(@NonNull Node<?> node) {\n        String name = Paths.sanitize(node.getFullPath(), false);\n        if (node.isDirectory()) {\n            name += File.separator;\n        }\n        ZipEntry zipEntry = new VirtualZipEntry(name);\n        zipEntry.setMethod(ZipEntry.DEFLATED);\n        if (node.isFile()) {\n            zipEntry.setSize(0L);\n        }\n        zipEntry.setTime(System.currentTimeMillis());\n        return zipEntry;\n    }\n\n    @NonNull\n    private ZipEntry getZipEntry(@NonNull Node<?> node, @NonNull File cachedFile) throws IOException {\n        String name = Paths.sanitize(node.getFullPath(), false);\n        if (node.isDirectory()) {\n            name += File.separator;\n        }\n        VirtualZipEntry zipEntry = new VirtualZipEntry(name);\n        zipEntry.setMethod(ZipEntry.DEFLATED);\n        zipEntry.setCachedFile(cachedFile);\n        zipEntry.setSize(cachedFile.length());\n        zipEntry.setCrc(DigestUtils.calculateCrc32(Paths.get(cachedFile)));\n        zipEntry.setTime(cachedFile.lastModified());\n        return zipEntry;\n    }\n\n    @NonNull\n    private ZipEntry getZipEntry(@NonNull String path, @NonNull ZipEntry zipEntry) {\n        String name = Paths.sanitize(File.separator + path, false);\n        if (zipEntry.isDirectory()) {\n            name += File.separator;\n        }\n        ZipEntry zipEntry1 = new VirtualZipEntry(name);\n        zipEntry1.setMethod(ZipEntry.DEFLATED);\n        zipEntry1.setSize(zipEntry.getSize());\n        zipEntry1.setCrc(zipEntry.getCrc());\n        zipEntry1.setTime(zipEntry.getTime());\n        zipEntry1.setComment(zipEntry.getComment());\n        zipEntry1.setExtra(zipEntry.getExtra());\n        return zipEntry1;\n    }\n\n    @Nullable\n    @Override\n    protected Node<?> getNode(String path) {\n        checkMounted();\n        Node<ZipEntry> targetNode = mCache.get(path);\n        if (targetNode == null) {\n            if (path.equals(File.separator)) {\n                targetNode = mRootNode;\n            } else {\n                targetNode = Objects.requireNonNull(mRootNode).getLastChild(Paths.sanitize(path, true));\n            }\n            if (targetNode != null) {\n                mCache.put(path, targetNode);\n            }\n        }\n        return targetNode;\n    }\n\n    @Override\n    protected void invalidate(String path) {\n        mCache.remove(path);\n    }\n\n    @Override\n    protected long lastModified(@NonNull Node<?> node) {\n        if (node.getObject() == null) {\n            return getFile().lastModified();\n        }\n        return ((ZipEntry) node.getObject()).getTime();\n    }\n\n    @Override\n    public long lastAccess(String path) {\n        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {\n            return lastModified(path);\n        }\n        Node<?> targetNode = getNode(path);\n        if (targetNode == null || targetNode.getObject() == null) {\n            return getFile().lastModified();\n        }\n        FileTime ft = ((ZipEntry) targetNode.getObject()).getLastAccessTime();\n        if (ft != null) {\n            return ft.toMillis();\n        }\n        return ((ZipEntry) targetNode.getObject()).getTime();\n    }\n\n    @Override\n    public long creationTime(String path) {\n        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.O) {\n            return lastModified(path);\n        }\n        Node<?> targetNode = getNode(path);\n        if (targetNode == null || targetNode.getObject() == null) {\n            return getFile().lastModified();\n        }\n        FileTime ft = ((ZipEntry) targetNode.getObject()).getCreationTime();\n        if (ft != null) {\n            return ft.toMillis();\n        }\n        return ((ZipEntry) targetNode.getObject()).getTime();\n    }\n\n    @Override\n    public long length(String path) {\n        Node<?> targetNode = getNode(path);\n        if (targetNode == null) {\n            return -1;\n        }\n        if (targetNode.isDirectory()) {\n            return 0;\n        }\n        if (!targetNode.isFile()) {\n            return -1;\n        }\n        if (targetNode.getObject() == null) {\n            // Check for cache\n            File cachedFile = findCachedFile(targetNode);\n            if (cachedFile != null) {\n                return cachedFile.length();\n            }\n            return targetNode.isPhysical() ? -1 : 0;\n        }\n        return ((ZipEntry) targetNode.getObject()).getSize();\n    }\n\n    @Override\n    public boolean checkAccess(String path, int access) {\n        Node<?> targetNode = getNode(path);\n        if (access == OsConstants.F_OK) {\n            return targetNode != null;\n        }\n        if (access == OsConstants.R_OK) {\n            return true;\n        }\n        if (access == OsConstants.W_OK) {\n            return Objects.requireNonNull(getOptions()).readWrite;\n        }\n        if (access == (OsConstants.R_OK | OsConstants.W_OK)) {\n            return Objects.requireNonNull(getOptions()).readWrite;\n        }\n        // X_OK, R_OK|X_OK, R_OK|W_OK|X_OK are false\n        return false;\n    }\n\n    @NonNull\n    @Override\n    protected InputStream getInputStream(@NonNull Node<?> node) throws IOException {\n        ZipEntry zipEntry = (ZipEntry) node.getObject();\n        if (zipEntry == null) {\n            throw new FileNotFoundException(\"Class definition for \" + node.getFullPath() + \" is not found.\");\n        }\n        return Objects.requireNonNull(mZipFile).getInputStream(zipEntry);\n    }\n\n    @Override\n    protected void cacheFile(@NonNull Node<?> src, @NonNull File sink) throws IOException {\n        try (InputStream is = getInputStream(src);\n             FileOutputStream os = new FileOutputStream(sink)) {\n            IoUtils.copy(is, os);\n        }\n    }\n\n    @NonNull\n    private static Node<ZipEntry> buildTree(@NonNull ZipFile zipFile) {\n        Node<ZipEntry> rootNode = new Node<>(null, File.separator);\n        Enumeration<? extends ZipEntry> zipEntries = zipFile.entries();\n        while (zipEntries.hasMoreElements()) {\n            ZipEntry zipEntry = zipEntries.nextElement();\n            buildTree(rootNode, zipEntry);\n        }\n        return rootNode;\n    }\n\n    // Build nodes as needed by the entry, entry itself is the last node in the tree if it is not a directory\n    private static void buildTree(@NonNull Node<ZipEntry> rootNode, @NonNull ZipEntry zipEntry) {\n        String filename = Paths.sanitize(zipEntry.getName(), true);\n        if (filename == null) {\n            return;\n        }\n        String[] components = filename.split(File.separator);\n        if (components.length < 1) return;\n        Node<ZipEntry> lastNode = rootNode;\n        for (int i = 0; i < components.length - 1 /* last one will be set manually */; ++i) {\n            Node<ZipEntry> newNode = lastNode.getChild(components[i]);\n            if (newNode == null) {\n                // Add children\n                newNode = new Node<>(lastNode, components[i]);\n                lastNode.addChild(newNode);\n            }\n            lastNode = newNode;\n        }\n        lastNode.addChild(new Node<>(lastNode, components[components.length - 1],\n                zipEntry.isDirectory() ? null : zipEntry));\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/proc/ProcFdInfoList.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.proc;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport java.util.Collection;\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport io.github.muntashirakon.AppManager.utils.FileUtils;\nimport io.github.muntashirakon.io.Path;\n\npublic class ProcFdInfoList {\n    public static class ProcFdInfo {\n        public final int id;\n        public final long offset;\n        public final int mode;\n        public final int mountId;\n        @NonNull\n        public final Path realPath;\n        @NonNull\n        public final String[] extras;\n\n        private ProcFdInfo(int id, @NonNull Path realPath, @NonNull String[] info) {\n            this.id = id;\n            this.realPath = realPath;\n            this.extras = new String[info.length - 3]; // Ignore three mandatory fields\n            int i = 0;\n            long offset = -1;\n            int mode = -1;\n            int mountId = -1;\n            for (String line : info) {\n                if (line.startsWith(\"pos:\")) {\n                    offset = Long.decode(line.substring(4).trim());\n                } else if (line.startsWith(\"flags:\")) {\n                    mode = Integer.decode(line.substring(6).trim());\n                } else if (line.startsWith(\"mnt_id:\")) {\n                    mountId = Integer.decode(line.substring(7).trim());\n                } else {\n                    extras[i++] = line;\n                }\n            }\n            assert offset != -1;\n            assert mode != -1;\n            assert mountId != -1;\n\n            this.offset = offset;\n            this.mode = mode;\n            this.mountId = mountId;\n        }\n\n        public String getModeString() {\n            return FileUtils.translateModePosixToString(mode);\n        }\n    }\n\n    private final Map<Integer, ProcFdInfo> mFdInfoMap;\n\n    ProcFdInfoList(@NonNull Path[] fdFiles, @NonNull String[] fdInfoList) {\n        assert fdFiles.length == fdInfoList.length;\n        mFdInfoMap = new HashMap<>(fdFiles.length);\n        for (int i = 0; i < fdFiles.length; ++i) {\n            String fdInfo = fdInfoList[i];\n            if (fdInfo == null) {\n                // FD no longer exists\n                continue;\n            }\n            Path fdFile = fdFiles[i];\n            int fd = Integer.decode(fdFile.getName());\n            ProcFdInfo procFdInfo = new ProcFdInfo(fd, fdFile, fdInfo.split(\"\\\\n\"));\n            mFdInfoMap.put(fd, procFdInfo);\n        }\n    }\n\n    public Collection<Integer> getFds() {\n        return mFdInfoMap.keySet();\n    }\n\n    @Nullable\n    public ProcFdInfo getFdInfo(int fd) {\n        return mFdInfoMap.get(fd);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/proc/ProcFs.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.proc;\n\nimport android.os.SystemClock;\nimport android.text.TextUtils;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.VisibleForTesting;\n\nimport java.io.BufferedReader;\nimport java.io.FileNotFoundException;\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport io.github.muntashirakon.io.Path;\nimport io.github.muntashirakon.io.PathReader;\nimport io.github.muntashirakon.io.Paths;\n\npublic class ProcFs {\n    // Files in /proc/ directory\n    private static final String CPU_INFO = \"cpuinfo\";\n    private static final String MEM_INFO = \"meminfo\";\n    private static final String UID_STAT = \"uid_stat\";\n    private static final String UPTIME = \"uptime\";\n\n    // Files in /proc/$PID/ and /proc/$PID/task/$TID/ directory\n    private static final String ATTR = \"attr\";\n    private static final String AUXV = \"auxv\";\n    private static final String CGROUP = \"cgroup\";\n    private static final String CMDLINE = \"cmdline\";\n    private static final String COMM = \"comm\";\n    private static final String COREDUMP_FILTER = \"coredump_filter\"; // Only for PID\n    private static final String CPUSET = \"cpuset\";\n    private static final String CWD = \"cwd\";\n    private static final String ENVIRON = \"environ\";\n    private static final String EXE = \"exe\";\n    private static final String FD = \"fd\";\n    private static final String FD_INFO = \"fdinfo\";\n    private static final String IO = \"io\";\n    private static final String LIMITS = \"limits\";\n    private static final String MAP_FILES = \"map_files\"; // Only for PID\n    private static final String MAPS = \"maps\";\n    private static final String MOUNT_INFO = \"mountinfo\";\n    private static final String MOUNTS = \"mounts\";\n    private static final String MOUNT_STATS = \"mountstats\"; // Only for PID\n    private static final String NET = \"net\";\n    private static final String OOM_ADJ = \"oom_adj\";\n    private static final String OOM_SCORE = \"oom_score\";\n    private static final String OOM_SCORE_ADJ = \"oom_score_adj\";\n    private static final String PAGE_MAP = \"pagemap\";\n    private static final String PERSONALITY = \"personality\";\n    private static final String ROOT = \"root\";\n    private static final String SCHED = \"sched\";\n    private static final String SCHED_GROUP_ID = \"sched_group_id\"; // Only for PID\n    private static final String SCHED_INIT_TASK_LOAD = \"sched_init_task_load\"; // Only for PID\n    private static final String SCHED_WAKE_UP_IDLE = \"sched_wake_up_idle\"; // Only for PID\n    private static final String SCHED_STAT = \"schedstat\";\n    private static final String SMAPS = \"smaps\";\n    private static final String SMAPS_ROLLUP = \"smaps_rollup\";\n    private static final String STACK = \"stack\";\n    private static final String STAT = \"stat\";\n    private static final String STAT_MEM = \"statm\";\n    private static final String STATUS = \"status\";\n    private static final String SYSCALL = \"syscall\";\n    private static final String TASK = \"task\"; // Only for PID\n    private static final String TIME_IN_STATE = \"time_in_state\";\n    private static final String TIMER_SLACK_NS = \"timerslack_ns\"; // Only for PID\n    private static final String WCHAN = \"wchan\";\n\n    // Files in /proc/$PID/attr\n    private static final String CURRENT = \"current\"; // Current context\n    private static final String PREV = \"prev\"; // Previous context\n\n    // TODO: Files in /proc/$PID/net\n\n    // Files in /proc/uid_stat/$UID\n    private static final String TCP_SND = \"tcp_snd\";\n    private static final String TCP_RCV = \"tcp_rcv\";\n\n    private static ProcFs sInstance;\n\n    @NonNull\n    public static ProcFs getInstance() {\n        if (sInstance == null) {\n            sInstance = new ProcFs();\n        }\n        return sInstance;\n    }\n\n    private final Path procRoot;\n\n    private ProcFs() {\n        this(Paths.get(\"/proc\"));\n    }\n\n    @VisibleForTesting\n    public ProcFs(Path procRoot) {\n        this.procRoot = procRoot;\n    }\n\n    @Nullable\n    public String getCpuInfoHardware() {\n        // Only hardware is the relevant output, other outputs can be parsed from\n        // /sys/devices/system/cpu/\n        Path cpuInfoPath = Paths.build(procRoot, CPU_INFO);\n        if (cpuInfoPath == null) {\n            return null;\n        }\n        try (BufferedReader reader = new BufferedReader(new PathReader(cpuInfoPath))) {\n            String line;\n            while ((line = reader.readLine()) != null) {\n                if (line.trim().startsWith(\"Hardware\")) {\n                    int colonLoc = line.indexOf(':');\n                    if (colonLoc == -1) continue;\n                    colonLoc += 2;\n                    return line.substring(colonLoc).trim();\n                }\n            }\n        } catch (Throwable e) {\n            e.printStackTrace();\n        }\n        return null;\n    }\n\n    @Nullable\n    public ProcMemoryInfo getMemoryInfo() {\n        String statFileContents = getStringOrNull(Paths.build(procRoot, MEM_INFO));\n        if (statFileContents == null) {\n            return null;\n        }\n        return ProcMemoryInfo.parse(statFileContents);\n    }\n\n    @NonNull\n    public int[] getPids() {\n        Path[] pidFiles = procRoot.listFiles((dir, name) -> TextUtils.isDigitsOnly(name));\n        int[] pids = new int[pidFiles.length];\n        for (int i = 0; i < pidFiles.length; ++i) {\n            pids[i] = Integer.decode(pidFiles[i].getName());\n        }\n        return pids;\n    }\n\n    public long getUptime() {\n        Path uptimePath = Paths.build(procRoot, UPTIME); // Uptime is in seconds\n        if (uptimePath != null) {\n            String uptimeString = uptimePath.getContentAsString(null);\n            if (uptimeString != null) {\n                return Double.valueOf(uptimeString.split(\"\\\\s+\")[0]).longValue() * 1000;\n            }\n        }\n        return SystemClock.elapsedRealtime();\n    }\n\n    @Nullable\n    public String getCmdline(int pid) {\n        return getStringOrNull(Paths.build(procRoot, String.valueOf(pid), CMDLINE));\n    }\n\n    @Nullable\n    public String getCwd(int pid) {\n        Path cwdPath = Paths.build(procRoot, String.valueOf(pid), CWD);\n        if (cwdPath != null) {\n            try {\n                return cwdPath.getRealFilePath();\n            } catch (IOException e) {\n                e.printStackTrace();\n            }\n        }\n        return null;\n    }\n\n    @Nullable\n    public String[] getEnvVars(int pid) {\n        String data = getStringOrNull(Paths.build(procRoot, String.valueOf(pid), ENVIRON));\n        return data != null ? data.split(\"\\0\") : null;\n    }\n\n    @Nullable\n    public String getExe(int pid) {\n        Path exePath = Paths.build(procRoot, String.valueOf(pid), EXE);\n        if (exePath != null) {\n            try {\n                return exePath.getRealFilePath();\n            } catch (IOException e) {\n                e.printStackTrace();\n            }\n        }\n        return null;\n    }\n\n    @Nullable\n    public ProcFdInfoList getFdInfo(int pid) {\n        Path fdDir = Paths.build(procRoot, String.valueOf(pid), FD);\n        Path fdInfoDir = Paths.build(procRoot, String.valueOf(pid), FD_INFO);\n        if (fdDir == null || fdInfoDir == null) {\n            return null;\n        }\n        Path[] fdList = fdDir.listFiles();\n        String[] fdInfoList = new String[fdList.length];\n        for (int i = 0; i < fdList.length; ++i) {\n            Path fdInfoFile = Paths.build(fdInfoDir, fdList[i].getName());\n            fdInfoList[i] = fdInfoFile != null ? fdInfoFile.getContentAsString(null) : null;\n        }\n        return new ProcFdInfoList(fdList, fdInfoList);\n    }\n\n    @Nullable\n    public ProcMappedFiles getMapFiles(int pid) {\n        Path mapFilesDir = Paths.build(procRoot, String.valueOf(pid), MAP_FILES);\n        return mapFilesDir != null ? new ProcMappedFiles(mapFilesDir.listFiles()) : null;\n    }\n\n    @Nullable\n    public ProcStat getStat(int pid) {\n        String statFileContents = getStringOrNull(Paths.build(procRoot, String.valueOf(pid), STAT));\n        if (statFileContents == null) {\n            return null;\n        }\n        return ProcStat.parse(statFileContents.toCharArray());\n    }\n\n    @Nullable\n    public ProcMemStat getMemStat(int pid) {\n        String statFileContents = getStringOrNull(Paths.build(procRoot, String.valueOf(pid), STAT_MEM));\n        if (statFileContents == null) {\n            return null;\n        }\n        return ProcMemStat.parse(statFileContents);\n    }\n\n    @Nullable\n    public String getRoot(int pid) {\n        Path rootPath = Paths.build(procRoot, String.valueOf(pid), ROOT);\n        if (rootPath != null) {\n            try {\n                return rootPath.getRealFilePath();\n            } catch (IOException e) {\n                e.printStackTrace();\n            }\n        }\n        return null;\n    }\n\n    @Nullable\n    public ProcStatus getStatus(int pid) {\n        String statFileContents = getStringOrNull(Paths.build(procRoot, String.valueOf(pid), STATUS));\n        if (statFileContents == null) {\n            return null;\n        }\n        return ProcStatus.parse(statFileContents);\n    }\n\n    @Nullable\n    public String getWchan(int pid) {\n        return getStringOrNull(Paths.build(procRoot, String.valueOf(pid), WCHAN));\n    }\n\n    @Nullable\n    public String getCurrentContext(int pid) {\n        String context = getStringOrNull(Paths.build(procRoot, String.valueOf(pid), ATTR, CURRENT));\n        if (context == null) {\n            return null;\n        }\n        return context.trim();\n    }\n\n    @Nullable\n    public String getPreviousContext(int pid) {\n        String context = getStringOrNull(Paths.build(procRoot, String.valueOf(pid), ATTR, PREV));\n        if (context == null) {\n            return null;\n        }\n        return context.trim();\n    }\n\n    /**\n     * @deprecated Removed in API 23 (Android M). Use usage stats API instead\n     */\n    @Deprecated\n    @Nullable\n    public ProcUidNetStat getUidNetStat(int uid) {\n        Path uidPath = Paths.build(procRoot, UID_STAT, String.valueOf(uid));\n        if (uidPath == null) {\n            return null;\n        }\n        return getUidNetStatInternal(uid, uidPath);\n    }\n\n    /**\n     * @deprecated Removed in API 23 (Android M). Use usage stats API instead\n     */\n    @Deprecated\n    public List<ProcUidNetStat> getAllUidNetStat() {\n        Path[] uidPaths = procRoot.listFiles((dir, name) -> TextUtils.isDigitsOnly(name));\n        List<ProcUidNetStat> netStats = new ArrayList<>(uidPaths.length);\n        for (Path uidPath : uidPaths) {\n            int uid = Integer.parseInt(uidPath.getName());\n            ProcUidNetStat netStat = getUidNetStatInternal(uid, uidPath);\n            if (netStat != null) {\n                netStats.add(netStat);\n            }\n        }\n        return netStats;\n    }\n\n    @Nullable\n    private ProcUidNetStat getUidNetStatInternal(int uid, @NonNull Path uidPath) {\n        try {\n            Path txFile = uidPath.findFile(TCP_SND);\n            Path rxFile = uidPath.findFile(TCP_RCV);\n            long tx = Long.parseLong(txFile.getContentAsString(\"0\").trim());\n            long rx = Long.parseLong(rxFile.getContentAsString(\"0\").trim());\n            return new ProcUidNetStat(uid, tx, rx);\n        } catch (FileNotFoundException ignore) {\n        }\n        return null;\n    }\n\n    @Nullable\n    private String getStringOrNull(@Nullable Path file) {\n        return file != null ? file.getContentAsString(null) : null;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/proc/ProcMappedFiles.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.proc;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport java.io.IOException;\nimport java.util.Collection;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\n\nimport io.github.muntashirakon.io.Path;\nimport kotlin.collections.ArrayDeque;\n\npublic class ProcMappedFiles {\n    public static class MappedFile {\n        public final Path memoryPath;\n        public final String realPath;\n        public final long vmStart;\n        public final long vmEnd;\n\n        private MappedFile(@NonNull Path memoryPath, @NonNull String realPath) {\n            this.memoryPath = memoryPath;\n            this.realPath = realPath;\n            String[] vmAreaStruct = memoryPath.getName().split(\"-\");\n            vmStart = Long.decode(\"0x\" + vmAreaStruct[0]);\n            vmEnd = Long.decode(\"0x\" + vmAreaStruct[1]);\n        }\n    }\n\n    private final Map<String, List<MappedFile>> mMappedFiles;\n\n    ProcMappedFiles(@NonNull Path[] mappedFiles) {\n        mMappedFiles = new HashMap<>(mappedFiles.length);\n        for (Path file : mappedFiles) {\n            try {\n                String realPath = Objects.requireNonNull(file.getRealFilePath());\n                MappedFile mappedFile = new MappedFile(file, realPath);\n                List<MappedFile> mappedFileList = mMappedFiles.get(realPath);\n                if (mappedFileList == null) {\n                    mappedFileList = new ArrayDeque<>();\n                    mMappedFiles.put(realPath, mappedFileList);\n                }\n                mappedFileList.add(mappedFile);\n            } catch (IOException e) {\n                e.printStackTrace();\n            }\n        }\n    }\n\n    @NonNull\n    public Collection<String> getRealFiles() {\n        return mMappedFiles.keySet();\n    }\n\n    @Nullable\n    public List<MappedFile> getMappedFiles(@NonNull String realPath) {\n        return mMappedFiles.get(realPath);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/proc/ProcMemStat.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.proc;\n\nimport android.util.Log;\n\nimport androidx.annotation.NonNull;\n\n/**\n * Used for accessing contents from /proc/$PID/statm. See Table 1-3 in <a href=\"https://www.kernel.org/doc/Documentation/filesystems/proc.txt\">The /proc filesystem</a>\n */\npublic final class ProcMemStat {\n    public static final int MEM_STAT_SIZE = 0;\n    public static final int MEM_STAT_RESIDENT = 1;\n    public static final int MEM_STAT_SHARED = 2;\n    public static final int MEM_STAT_TRS = 3;\n    public static final int MEM_STAT_LRS = 4;\n    public static final int MEM_STAT_DRS = 5;\n    public static final int MEM_STAT_DT = 6;\n\n    private static final int MEM_STAT_COUNT = 7;\n\n    @NonNull\n    public static ProcMemStat parse(@NonNull String data) {\n        String[] result = data.split(\"\\\\s\");\n        if (result.length != MEM_STAT_COUNT) {\n            Log.w(ProcMemStat.class.getSimpleName(), \"Field counts did not match, expected: \" + MEM_STAT_COUNT\n                    + \", actual: \" + result.length);\n        }\n        return new ProcMemStat(result);\n    }\n\n    @NonNull\n    private final String[] mMemStat;\n\n    private ProcMemStat(@NonNull String[] memStat) {\n        mMemStat = memStat;\n    }\n\n    public long getLong(int index) {\n        return Long.decode(mMemStat[index]);\n    }\n}"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/proc/ProcMemoryInfo.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.proc;\n\nimport androidx.annotation.NonNull;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\nimport io.github.muntashirakon.compat.ObjectsCompat;\nimport io.github.muntashirakon.io.Path;\nimport io.github.muntashirakon.io.Paths;\n\npublic class ProcMemoryInfo {\n    private static final String MEMINFO = \"meminfo\";\n\n    private static final String MEMINFO_MEM_TOTAL = \"MemTotal\";\n    private static final String MEMINFO_MEM_FREE = \"MemFree\";\n    private static final String MEMINFO_MEM_AVAILABLE = \"MemAvailable\";\n    private static final String MEMINFO_BUFFERS = \"Buffers\";\n    private static final String MEMINFO_CACHED = \"Cached\";\n    private static final String MEMINFO_SWAP_CACHED = \"SwapCached\";\n    private static final String MEMINFO_ACTIVE = \"Active\";\n    private static final String MEMINFO_INACTIVE = \"Inactive\";\n    private static final String MEMINFO_ACTIVE_ANON = \"Active(anon)\";\n    private static final String MEMINFO_INACTIVE_ANON = \"Inactive(anon)\";\n    private static final String MEMINFO_ACTIVE_FILE = \"Active(file)\";\n    private static final String MEMINFO_INACTIVE_FILE = \"Inactive(file)\";\n    private static final String MEMINFO_UNEVICTABLE = \"Unevictable\";\n    private static final String MEMINFO_MLOCKED = \"Mlocked\";\n    private static final String MEMINFO_SWAP_TOTAL = \"SwapTotal\";\n    private static final String MEMINFO_SWAP_FREE = \"SwapFree\";\n    private static final String MEMINFO_DIRTY = \"Dirty\";\n    private static final String MEMINFO_WRITEBACK = \"Writeback\";\n    private static final String MEMINFO_ANON_PAGES = \"AnonPages\";\n    private static final String MEMINFO_MAPPED = \"Mapped\";\n    private static final String MEMINFO_SHMEM = \"Shmem\";\n    private static final String MEMINFO_SLAB = \"Slab\";\n    private static final String MEMINFO_S_RECLAIMABLE = \"SReclaimable\";\n    private static final String MEMINFO_S_UNRECLAIM = \"SUnreclaim\";\n    private static final String MEMINFO_KERNEL_STACK = \"KernelStack\";\n    private static final String MEMINFO_PAGE_TABLES = \"PageTables\";\n    private static final String MEMINFO_NFS_UNSTABLE = \"NFS_Unstable\";\n    private static final String MEMINFO_BOUNCE = \"Bounce\";\n    private static final String MEMINFO_WRITEBACK_TMP = \"WritebackTmp\";\n    private static final String MEMINFO_COMMIT_LIMIT = \"CommitLimit\";\n    private static final String MEMINFO_COMMITTED_AS = \"Committed_AS\";\n    private static final String MEMINFO_VMALLOC_TOTAL = \"VmallocTotal\";\n    private static final String MEMINFO_VMALLOC_USED = \"VmallocUsed\";\n    private static final String MEMINFO_VMALLOC_CHUNK = \"VmallocChunk\";\n    private static final String MEMINFO_CMA_TOTAL = \"CmaTotal\";\n    private static final String MEMINFO_CMA_FREE = \"CmaFree\";\n\n    @NonNull\n    public static ProcMemoryInfo parse(@NonNull String data) {\n        Map<String, Long> result = new HashMap<>(36);\n        for (String line : data.split(\"\\\\n\")) {\n            int idxOfColon = line.indexOf(':');\n            int idxOfKb = line.lastIndexOf(\"kB\");\n            if (idxOfColon != -1 && idxOfKb != -1) {\n                result.put(line.substring(0, idxOfColon).trim(), Long.decode(line.substring(idxOfColon + 1, idxOfKb).trim()) << 10);\n            }\n        }\n        return new ProcMemoryInfo(result);\n    }\n\n    private final Map<String, Long> mMemInfo;\n\n    public ProcMemoryInfo(Map<String, Long> memInfo) {\n        mMemInfo = memInfo;\n    }\n\n    public long get(@NonNull String key, long defaultValue) {\n        return ObjectsCompat.requireNonNullElse(mMemInfo.get(key), defaultValue);\n    }\n\n    public long getTotalMemory() {\n        return get(MEMINFO_MEM_TOTAL, 0);\n    }\n\n    public long getFreeMemory() {\n        return get(MEMINFO_MEM_FREE, 0);\n    }\n\n    public long getUsedMemory() {\n        return getTotalMemory() - getFreeMemory();\n    }\n\n    public long getAvailableMemory() {\n        return get(MEMINFO_MEM_AVAILABLE, 0);\n    }\n\n    public long getBuffers() {\n        return get(MEMINFO_BUFFERS, 0);\n    }\n\n    public long getCachedMemory() {\n        return get(MEMINFO_CACHED, 0) + get(MEMINFO_SLAB, 0);\n    }\n\n    public long getApplicationMemory() {\n        return getUsedMemory() - getBuffers() - getCachedMemory();\n    }\n\n    public long getTotalSwap() {\n        return get(MEMINFO_SWAP_TOTAL, 0);\n    }\n\n    public long getFreeSwap() {\n        return get(MEMINFO_SWAP_FREE, 0);\n    }\n\n    public long getUsedSwap() {\n        return getTotalSwap() - getFreeSwap();\n    }\n\n    public long getTotalZram() {\n        // https://www.kernel.org/doc/html/latest/_sources/admin-guide/blockdev/zram.rst.txt\n        Path[] zramPaths = Paths.get(\"/sys/block/\").listFiles((dir, name) -> name.startsWith(\"zram\"));\n        long totalZram = 0;\n        for (Path zramPath : zramPaths) {\n            Path mmStat = Paths.build(zramPath, \"mm_stat\");\n            if (mmStat != null && mmStat.canRead()) {\n                totalZram += Long.decode(mmStat.getContentAsString().split(\"\\\\s\")[2].trim());\n            }\n        }\n        return totalZram;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/proc/ProcStat.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.proc;\n\nimport android.util.Log;\n\nimport androidx.annotation.NonNull;\n\n/**\n * Used for accessing contents from /proc/$PID/stat. See Table 1-4 in <a href=\"https://www.kernel.org/doc/Documentation/filesystems/proc.txt\">The /proc filesystem</a>\n */\npublic final class ProcStat {\n    public static final int STAT_PID = 0;\n    public static final int STAT_TCOMM = 1;\n    public static final int STAT_STATE = 2;\n    public static final int STAT_PPID = 3;\n    public static final int STAT_PGRP = 4;\n    public static final int STAT_SID = 5;\n    public static final int STAT_TTY_NR = 6;\n    public static final int STAT_TTY_PGRP = 7;\n    public static final int STAT_FLAGS = 8;\n    public static final int STAT_MIN_FLT = 9;\n    public static final int STAT_CMIN_FLT = 10;\n    public static final int STAT_MAJ_FLT = 11;\n    public static final int STAT_CMAJ_FLT = 12;\n    public static final int STAT_UTIME = 13;\n    public static final int STAT_STIME = 14;\n    public static final int STAT_CUTIME = 15;\n    public static final int STAT_CSTIME = 16;\n    public static final int STAT_PRIORITY = 17;\n    public static final int STAT_NICE = 18;\n    public static final int STAT_NUM_THREADS = 19;\n    public static final int STAT_IT_REAL_VALUE = 20;\n    public static final int STAT_START_TIME = 21;\n    public static final int STAT_VSIZE = 22;\n    public static final int STAT_RSS = 23;\n    public static final int STAT_RSSLIM = 24;\n    public static final int STAT_START_CODE = 25;\n    public static final int STAT_END_CODE = 26;\n    public static final int STAT_START_STACK = 27;\n    public static final int STAT_ESP = 28;\n    public static final int STAT_EIP = 29;\n    public static final int STAT_PENDING = 30;\n    public static final int STAT_BLOCKED = 31;\n    public static final int STAT_SIGIGN = 32;\n    public static final int STAT_SIGCATCH = 33;\n    public static final int STAT_PLACEHOLDER_0 = 34;\n    public static final int STAT_PLACEHOLDER_1 = 35;\n    public static final int STAT_PLACEHOLDER_2 = 36;\n    public static final int STAT_EXIT_SIGNAL = 37;\n    public static final int STAT_TASK_CPU = 38;\n    public static final int STAT_RT_PRIORITY = 39;\n    public static final int STAT_POLICY = 40;\n    public static final int STAT_BLKIO_TICKS = 41;\n    public static final int STAT_GTIME = 42;\n    public static final int STAT_CGTIME = 43;\n    public static final int STAT_START_DATA = 44;\n    public static final int STAT_END_DATA = 45;\n    public static final int STAT_START_BRK = 46;\n    public static final int STAT_ARG_START = 47;\n    public static final int STAT_ARG_END = 48;\n    public static final int STAT_ENV_START = 49;\n    public static final int STAT_ENV_END = 50;\n    public static final int STAT_EXIT_CODE = 51;\n\n    private static final int STAT_COUNT = 52;\n\n    @NonNull\n    public static ProcStat parse(@NonNull char[] data) {\n        String[] result = new String[STAT_COUNT];\n        // See: https://www.openwall.com/lists/oss-security/2022/12/21/6\n        int bracketCount = 0;\n        int fieldIndex = 0;\n        int lastOffset = 0;\n        for (int i = 0; i < data.length; ++i) {\n            char c = data[i];\n            if (c == '(') {\n                ++bracketCount;\n            } else if (c == ')') {\n                --bracketCount;\n            } else if (bracketCount == 0 && c == ' ') {\n                result[fieldIndex] = new String(data, lastOffset, i - lastOffset);\n                ++fieldIndex;\n                lastOffset = i + 1;\n            }\n        }\n        // Add last field\n        result[fieldIndex] = new String(data, lastOffset, data.length - lastOffset);\n        if (fieldIndex + 1 != STAT_COUNT) {\n            Log.w(ProcStat.class.getSimpleName(), \"Field counts did not match, expected: \" + STAT_COUNT\n                    + \", actual: \" + (fieldIndex + 1));\n        }\n        return new ProcStat(result);\n    }\n\n    @NonNull\n    private final String[] mStat;\n\n    private ProcStat(@NonNull String[] stat) {\n        mStat = stat;\n    }\n\n    @NonNull\n    public String getString(int index) {\n        return mStat[index];\n    }\n\n    public int getInteger(int index) {\n        return Integer.decode(mStat[index]);\n    }\n\n    public long getLong(int index) {\n        return Long.decode(mStat[index]);\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/proc/ProcStatus.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.proc;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * Used for accessing contents from /proc/$PID/status. See Table 1-2 in <a href=\"https://www.kernel.org/doc/Documentation/filesystems/proc.txt\">The /proc filesystem</a>\n */\npublic class ProcStatus {\n    public static final String STATUS_NAME = \"Name\";\n    public static final String STATUS_UMASK = \"Umask\";\n    public static final String STATUS_STATE = \"State\";\n    public static final String STATUS_TGID = \"Tgid\";\n    public static final String STATUS_NGID = \"Ngid\";\n    public static final String STATUS_PID = \"Pid\";\n    public static final String STATUS_PPID = \"PPid\";\n    public static final String STATUS_TRACER_PID = \"TracerPid\";\n    public static final String STATUS_UID = \"Uid\";  // Real, effective, saved set, and file system UIDs\n    public static final String STATUS_GID = \"Gid\";  // Real, effective, saved set, and file system GIDs\n    public static final String STATUS_FD_SIZE = \"FDSize\";\n    public static final String STATUS_GROUPS = \"FDSize\";\n    public static final String STATUS_NS_TGID = \"NStgid\";\n    public static final String STATUS_NS_PID = \"NSpid\";\n    public static final String STATUS_NS_PGID = \"NSpgid\";\n    public static final String STATUS_NS_SID = \"NSsid\";\n    public static final String STATUS_VM_PEAK = \"VmPeak\";\n    public static final String STATUS_VM_SIZE = \"VmSize\";\n    public static final String STATUS_VM_LCK = \"VmLck\";\n    public static final String STATUS_VM_PIN = \"VmPin\";\n    public static final String STATUS_VM_HWM = \"VmHWM\";\n    public static final String STATUS_VM_RSS = \"VmRSS\";\n    public static final String STATUS_RSS_ANON = \"RssAnon\";\n    public static final String STATUS_RSS_FILE = \"RssFile\";\n    public static final String STATUS_RSS_SHMEM = \"RssShmem\";\n    public static final String STATUS_VM_DATA = \"VmData\";\n    public static final String STATUS_VM_STK = \"VmStk\";\n    public static final String STATUS_VM_EXE = \"VmExe\";\n    public static final String STATUS_VM_LIB = \"VmLib\";\n    public static final String STATUS_VM_PTE = \"VmPTE\";\n    public static final String STATUS_VM_SWAP = \"VmSwap\";\n    public static final String STATUS_HUGETLB_PAGES = \"HugetlbPages\";\n    public static final String STATUS_CORE_DUMPING = \"CoreDumping\";\n    public static final String STATUS_THP_ENABLED = \"THP_enabled\";\n    public static final String STATUS_THREADS = \"Threads\";\n    public static final String STATUS_SIG_Q = \"SigQ\";\n    public static final String STATUS_SIG_PND = \"SigPnd\";\n    public static final String STATUS_SHD_PND = \"ShdPnd\";\n    public static final String STATUS_SIG_BLK = \"SigBlk\";\n    public static final String STATUS_SIG_IGN = \"SigIgn\";\n    public static final String STATUS_SIG_CGT = \"SigCgt\";\n    public static final String STATUS_CAP_INH = \"CapInh\";\n    public static final String STATUS_CAP_PRM = \"CapPrm\";\n    public static final String STATUS_CAP_EFF = \"CapEff\";\n    public static final String STATUS_CAP_BND = \"CapBnd\";\n    public static final String STATUS_CAP_AMB = \"CapAmb\";\n    public static final String STATUS_NO_NEW_PRIVS = \"NoNewPrivs\";\n    public static final String STATUS_SECCOMP = \"Seccomp\";\n    public static final String STATUS_SPECULATION_STORE_BYPASS = \"Speculation_Store_Bypass\";\n    public static final String STATUS_CPUS_ALLOWED = \"Cpus_allowed\";\n    public static final String STATUS_CPUS_ALLOWED_LIST = \"Cpus_allowed_list\";\n    public static final String STATUS_MEMS_ALLOWED = \"Mems_allowed\";\n    public static final String STATUS_MEMS_ALLOWED_LIST = \"Mems_allowed_list\";\n    public static final String STATUS_VOLUNTARY_CTX_SWITCHES = \"voluntary_ctxt_switches\";\n    public static final String STATUS_NON_VOLUNTARY_CTX_SWITCHES = \"nonvoluntary_ctxt_switches\";\n\n    @NonNull\n    public static ProcStatus parse(@NonNull String data) {\n        Map<String, String> result = new HashMap<>(56);\n        for (String line : data.split(\"\\\\n\")) {\n            int idxOfColon = line.indexOf(':');\n            if (idxOfColon != -1) {\n                result.put(line.substring(0, idxOfColon).trim(), line.substring(idxOfColon + 1).trim());\n            }\n        }\n        return new ProcStatus(result);\n    }\n\n    @NonNull\n    private final Map<String, String> mStatus;\n\n    private ProcStatus(@NonNull Map<String, String> status) {\n        mStatus = status;\n    }\n\n    @Nullable\n    public String getString(@NonNull String key) {\n        return mStatus.get(key);\n    }\n\n    public int getInteger(@NonNull String key, int defaultValue) {\n        String string = getString(key);\n        return string != null ? Integer.decode(string) : defaultValue;\n    }\n\n    public long getLong(@NonNull String key, long defaultValue) {\n        String string = getString(key);\n        return string != null ? Long.decode(string) : defaultValue;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/proc/ProcUidNetStat.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.proc;\n\npublic class ProcUidNetStat {\n    public final int uid;\n    public final long txBytes;\n    public final long rxBytes;\n\n    public ProcUidNetStat(int uid, long txBytes, long rxBytes) {\n        this.uid = uid;\n        this.txBytes = txBytes;\n        this.rxBytes = rxBytes;\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/svg/ParserHelper.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage io.github.muntashirakon.svg;\n\nimport androidx.annotation.Nullable;\n\n/**\n * Parses numbers from SVG text. Based on the Batik Number Parser (Apache 2 License).\n *\n * @author Apache Software Foundation, Larva Labs LLC\n */\n// Copyright 2011 Larva Labs, LLC\n// Copyright 1999 Apache Software Foundation\npublic class ParserHelper {\n    public int pos;\n\n    private final CharSequence s;\n    private char current;\n    private final int n;\n\n    public ParserHelper(CharSequence s, int pos) {\n        this.s = s;\n        this.pos = pos;\n        n = s.length();\n        current = n != 0 ? s.charAt(pos) : 0;\n    }\n\n    private char read() {\n        if (pos < n) {\n            pos++;\n        }\n        if (pos == n) {\n            return '\\0';\n        } else {\n            return s.charAt(pos);\n        }\n    }\n\n    public void skipWhitespace() {\n        while (pos < n) {\n            if (Character.isWhitespace(s.charAt(pos))) {\n                advance();\n            } else {\n                break;\n            }\n        }\n    }\n\n    public void skipNumberSeparator() {\n        while (pos < n) {\n            char c = s.charAt(pos);\n            switch (c) {\n                case ' ':\n                case ',':\n                case '\\n':\n                case '\\t':\n                    advance();\n                    break;\n                default:\n                    return;\n            }\n        }\n    }\n\n    public void advance() {\n        current = read();\n    }\n\n    /**\n     * Parses the content of the buffer and converts it to a float.\n     */\n    public float parseFloat() {\n        int mant = 0;\n        int mantDig = 0;\n        boolean mantPos = true;\n        boolean mantRead = false;\n\n        int exp = 0;\n        int expDig = 0;\n        int expAdj = 0;\n        boolean expPos = true;\n\n        switch (current) {\n            case '-':\n                mantPos = false;\n                // fallthrough\n            case '+':\n                current = read();\n        }\n\n        m1:\n        switch (current) {\n            default:\n                return Float.NaN;\n\n            case '.':\n                break;\n\n            case '0':\n                mantRead = true;\n                l:\n                for (; ; ) {\n                    current = read();\n                    switch (current) {\n                        case '1':\n                        case '2':\n                        case '3':\n                        case '4':\n                        case '5':\n                        case '6':\n                        case '7':\n                        case '8':\n                        case '9':\n                            break l;\n                        case '.':\n                        case 'e':\n                        case 'E':\n                            break m1;\n                        default:\n                            return 0.0f;\n                        case '0':\n                    }\n                }\n\n            case '1':\n            case '2':\n            case '3':\n            case '4':\n            case '5':\n            case '6':\n            case '7':\n            case '8':\n            case '9':\n                mantRead = true;\n                l:\n                for (; ; ) {\n                    if (mantDig < 9) {\n                        mantDig++;\n                        mant = mant * 10 + (current - '0');\n                    } else {\n                        expAdj++;\n                    }\n                    current = read();\n                    switch (current) {\n                        default:\n                            break l;\n                        case '0':\n                        case '1':\n                        case '2':\n                        case '3':\n                        case '4':\n                        case '5':\n                        case '6':\n                        case '7':\n                        case '8':\n                        case '9':\n                    }\n                }\n        }\n\n        if (current == '.') {\n            current = read();\n            m2:\n            switch (current) {\n                default:\n                case 'e':\n                case 'E':\n                    if (!mantRead) {\n                        reportUnexpectedCharacterError(current);\n                        return 0.0f;\n                    }\n                    break;\n\n                case '0':\n                    if (mantDig == 0) {\n                        l:\n                        for (; ; ) {\n                            current = read();\n                            expAdj--;\n                            switch (current) {\n                                case '1':\n                                case '2':\n                                case '3':\n                                case '4':\n                                case '5':\n                                case '6':\n                                case '7':\n                                case '8':\n                                case '9':\n                                    break l;\n                                default:\n                                    if (!mantRead) {\n                                        return 0.0f;\n                                    }\n                                    break m2;\n                                case '0':\n                            }\n                        }\n                    }\n                case '1':\n                case '2':\n                case '3':\n                case '4':\n                case '5':\n                case '6':\n                case '7':\n                case '8':\n                case '9':\n                    l:\n                    for (; ; ) {\n                        if (mantDig < 9) {\n                            mantDig++;\n                            mant = mant * 10 + (current - '0');\n                            expAdj--;\n                        }\n                        current = read();\n                        switch (current) {\n                            default:\n                                break l;\n                            case '0':\n                            case '1':\n                            case '2':\n                            case '3':\n                            case '4':\n                            case '5':\n                            case '6':\n                            case '7':\n                            case '8':\n                            case '9':\n                        }\n                    }\n            }\n        }\n\n        switch (current) {\n            case 'e':\n            case 'E':\n                current = read();\n                switch (current) {\n                    default:\n                        reportUnexpectedCharacterError(current);\n                        return 0f;\n                    case '-':\n                        expPos = false;\n                    case '+':\n                        current = read();\n                        switch (current) {\n                            default:\n                                reportUnexpectedCharacterError(current);\n                                return 0f;\n                            case '0':\n                            case '1':\n                            case '2':\n                            case '3':\n                            case '4':\n                            case '5':\n                            case '6':\n                            case '7':\n                            case '8':\n                            case '9':\n                        }\n                    case '0':\n                    case '1':\n                    case '2':\n                    case '3':\n                    case '4':\n                    case '5':\n                    case '6':\n                    case '7':\n                    case '8':\n                    case '9':\n                }\n\n                en:\n                switch (current) {\n                    case '0':\n                        l:\n                        for (; ; ) {\n                            current = read();\n                            switch (current) {\n                                case '1':\n                                case '2':\n                                case '3':\n                                case '4':\n                                case '5':\n                                case '6':\n                                case '7':\n                                case '8':\n                                case '9':\n                                    break l;\n                                default:\n                                    break en;\n                                case '0':\n                            }\n                        }\n\n                    case '1':\n                    case '2':\n                    case '3':\n                    case '4':\n                    case '5':\n                    case '6':\n                    case '7':\n                    case '8':\n                    case '9':\n                        l:\n                        for (; ; ) {\n                            if (expDig < 3) {\n                                expDig++;\n                                exp = exp * 10 + (current - '0');\n                            }\n                            current = read();\n                            switch (current) {\n                                default:\n                                    break l;\n                                case '0':\n                                case '1':\n                                case '2':\n                                case '3':\n                                case '4':\n                                case '5':\n                                case '6':\n                                case '7':\n                                case '8':\n                                case '9':\n                            }\n                        }\n                }\n            default:\n        }\n\n        if (!expPos) {\n            exp = -exp;\n        }\n        exp += expAdj;\n        if (!mantPos) {\n            mant = -mant;\n        }\n\n        return buildFloat(mant, exp);\n    }\n\n    private void reportUnexpectedCharacterError(char c) {\n        throw new RuntimeException(\"Unexpected char '\" + c + \"'.\");\n    }\n\n    /**\n     * Computes a float from mantissa and exponent.\n     */\n    public static float buildFloat(int mant, int exp) {\n        if (exp < -125 || mant == 0) {\n            return 0.0f;\n        }\n\n        if (exp >= 128) {\n            return (mant > 0)\n                    ? Float.POSITIVE_INFINITY\n                    : Float.NEGATIVE_INFINITY;\n        }\n\n        if (exp == 0) {\n            return mant;\n        }\n\n        if (mant >= (1 << 26)) {\n            mant++;  // round up trailing bits if they will be dropped.\n        }\n\n        return (float) ((exp > 0) ? mant * pow10[exp] : mant / pow10[-exp]);\n    }\n\n    /**\n     * Array of powers of ten. Using double instead of float gives a tiny bit more precision.\n     */\n    private static final double[] pow10 = new double[128];\n\n    static {\n        for (int i = 0; i < pow10.length; i++) {\n            pow10[i] = Math.pow(10, i);\n        }\n    }\n\n    public float nextFloat() {\n        skipWhitespace();\n        float f = parseFloat();\n        skipNumberSeparator();\n        return f;\n    }\n}"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/svg/SVG.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage io.github.muntashirakon.svg;\n\nimport android.graphics.Bitmap;\nimport android.graphics.Canvas;\nimport android.graphics.Picture;\nimport android.graphics.RectF;\nimport android.graphics.drawable.PictureDrawable;\n\nimport androidx.annotation.NonNull;\n\n/**\n * Describes a vector Picture object, and optionally its bounds.\n */\n// Copyright 2011 Larva Labs, LLC\npublic class SVG {\n    /**\n     * The parsed Picture object.\n     */\n    @NonNull\n    private final Picture picture;\n\n    /**\n     * These are the bounds for the SVG specified as a hidden \"bounds\" layer in the SVG.\n     */\n    private final RectF bounds;\n\n    /**\n     * These are the estimated bounds of the SVG computed from the SVG elements while parsing.\n     * Note that this could be null if there was a failure to compute limits (ie. an empty SVG).\n     */\n    private RectF limits = null;\n\n    /**\n     * Construct a new SVG.\n     *\n     * @param picture the parsed picture object.\n     * @param bounds  the bounds computed from the \"bounds\" layer in the SVG.\n     */\n    SVG(@NonNull Picture picture, RectF bounds) {\n        this.picture = picture;\n        this.bounds = bounds;\n    }\n\n    /**\n     * Set the limits of the SVG, which are the estimated bounds computed by the parser.\n     *\n     * @param limits the bounds computed while parsing the SVG, may not be entirely accurate.\n     */\n    void setLimits(RectF limits) {\n        this.limits = limits;\n    }\n\n    /**\n     * Create a picture drawable from the SVG.\n     *\n     * @return the PictureDrawable.\n     */\n    @NonNull\n    public PictureDrawable createPictureDrawable() {\n        return new PictureDrawable(picture);\n//        return new PictureDrawable(picture) {\n//            @Override\n//            public int getIntrinsicWidth() {\n//                if (bounds != null) {\n//                    return (int) bounds.width();\n//                } else if (limits != null) {\n//                    return (int) limits.width();\n//                } else {\n//                    return -1;\n//                }\n//            }\n//\n//            @Override\n//            public int getIntrinsicHeight() {\n//                if (bounds != null) {\n//                    return (int) bounds.height();\n//                } else if (limits != null) {\n//                    return (int) limits.height();\n//                } else {\n//                    return -1;\n//                }\n//            }\n//        };\n    }\n\n    @NonNull\n    public Bitmap getBitmap() {\n        Bitmap bitmap = Bitmap.createBitmap(picture.getWidth(), picture.getHeight(), Bitmap.Config.ARGB_8888);\n        Canvas canvas = new Canvas(bitmap);\n        picture.draw(canvas);\n        return bitmap;\n    }\n\n    /**\n     * Get the parsed SVG picture data.\n     *\n     * @return the picture.\n     */\n    @NonNull\n    public Picture getPicture() {\n        return picture;\n    }\n\n    /**\n     * Gets the bounding rectangle for the SVG, if one was specified.\n     *\n     * @return rectangle representing the bounds.\n     */\n    public RectF getBounds() {\n        return bounds;\n    }\n\n    /**\n     * Gets the bounding rectangle for the SVG that was computed upon parsing. It may not be entirely accurate for certain curves or transformations, but is often better than nothing.\n     *\n     * @return rectangle representing the computed bounds.\n     */\n    public RectF getLimits() {\n        return limits;\n    }\n}"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/svg/SVGParseException.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage io.github.muntashirakon.svg;\n\n/**\n * Runtime exception thrown when there is a problem parsing an SVG.\n */\n// Copyright 2011 Larva Labs, LLC\npublic class SVGParseException extends RuntimeException {\n    public SVGParseException(String s) {\n        super(s);\n    }\n\n    public SVGParseException(String s, Throwable throwable) {\n        super(s, throwable);\n    }\n\n    public SVGParseException(Throwable throwable) {\n        super(throwable);\n    }\n}"
  },
  {
    "path": "app/src/main/java/io/github/muntashirakon/svg/SVGParser.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage io.github.muntashirakon.svg;\n\nimport android.content.res.AssetManager;\nimport android.content.res.Resources;\nimport android.graphics.Canvas;\nimport android.graphics.Color;\nimport android.graphics.LinearGradient;\nimport android.graphics.Matrix;\nimport android.graphics.Paint;\nimport android.graphics.Path;\nimport android.graphics.Picture;\nimport android.graphics.RadialGradient;\nimport android.graphics.RectF;\nimport android.graphics.Shader;\nimport android.util.Log;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport org.jetbrains.annotations.Contract;\nimport org.xml.sax.Attributes;\nimport org.xml.sax.InputSource;\nimport org.xml.sax.XMLReader;\nimport org.xml.sax.helpers.DefaultHandler;\n\nimport java.io.ByteArrayInputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.util.ArrayList;\nimport java.util.HashMap;\n\nimport javax.xml.parsers.SAXParser;\nimport javax.xml.parsers.SAXParserFactory;\n\n/**\n * Entry point for parsing SVG files for Android.\n * Use one of the various static methods for parsing SVGs by resource, asset or input stream.\n * Optionally, a single color can be searched and replaced in the SVG while parsing.\n * You can also parse an svg path directly.\n *\n * @author Larva Labs, LLC\n * @see #getSVGFromResource(android.content.res.Resources, int)\n * @see #getSVGFromAsset(android.content.res.AssetManager, String)\n * @see #getSVGFromString(String)\n * @see #getSVGFromInputStream(java.io.InputStream)\n * @see #parsePath(String)\n */\n// Copyright 2011 Larva Labs, LLC\npublic class SVGParser {\n    static final String TAG = SVGParser.class.getSimpleName();\n\n    /**\n     * Parse SVG data from an input stream.\n     *\n     * @param svgData the input stream, with SVG XML data in UTF-8 character encoding.\n     * @return the parsed SVG.\n     * @throws SVGParseException if there is an error while parsing.\n     */\n    public static SVG getSVGFromInputStream(InputStream svgData) throws SVGParseException {\n        return SVGParser.parse(svgData, 0, 0, false);\n    }\n\n    /**\n     * Parse SVG data from a string.\n     *\n     * @param svgData the string containing SVG XML data.\n     * @return the parsed SVG.\n     * @throws SVGParseException if there is an error while parsing.\n     */\n    public static SVG getSVGFromString(String svgData) throws SVGParseException {\n        return SVGParser.parse(new ByteArrayInputStream(svgData.getBytes()), 0, 0, false);\n    }\n\n    /**\n     * Parse SVG data from an Android application resource.\n     *\n     * @param resources the Android context resources.\n     * @param resId     the ID of the raw resource SVG.\n     * @return the parsed SVG.\n     * @throws SVGParseException if there is an error while parsing.\n     */\n    public static SVG getSVGFromResource(Resources resources, int resId) throws SVGParseException {\n        return SVGParser.parse(resources.openRawResource(resId), 0, 0, false);\n    }\n\n    /**\n     * Parse SVG data from an Android application asset.\n     *\n     * @param assetMngr the Android asset manager.\n     * @param svgPath   the path to the SVG file in the application's assets.\n     * @return the parsed SVG.\n     * @throws SVGParseException if there is an error while parsing.\n     * @throws IOException       if there was a problem reading the file.\n     */\n    public static SVG getSVGFromAsset(AssetManager assetMngr, String svgPath) throws SVGParseException, IOException {\n        InputStream inputStream = assetMngr.open(svgPath);\n        SVG svg = getSVGFromInputStream(inputStream);\n        inputStream.close();\n        return svg;\n    }\n\n    /**\n     * Parse SVG data from an input stream, replacing a single color with another color.\n     *\n     * @param svgData      the input stream, with SVG XML data in UTF-8 character encoding.\n     * @param searchColor  the color in the SVG to replace.\n     * @param replaceColor the color with which to replace the search color.\n     * @return the parsed SVG.\n     * @throws SVGParseException if there is an error while parsing.\n     */\n    public static SVG getSVGFromInputStream(InputStream svgData, int searchColor, int replaceColor) throws SVGParseException {\n        return SVGParser.parse(svgData, searchColor, replaceColor, false);\n    }\n\n    /**\n     * Parse SVG data from a string.\n     *\n     * @param svgData      the string containing SVG XML data.\n     * @param searchColor  the color in the SVG to replace.\n     * @param replaceColor the color with which to replace the search color.\n     * @return the parsed SVG.\n     * @throws SVGParseException if there is an error while parsing.\n     */\n    public static SVG getSVGFromString(String svgData, int searchColor, int replaceColor) throws SVGParseException {\n        return SVGParser.parse(new ByteArrayInputStream(svgData.getBytes()), searchColor, replaceColor, false);\n    }\n\n    /**\n     * Parse SVG data from an Android application resource.\n     *\n     * @param resources    the Android context\n     * @param resId        the ID of the raw resource SVG.\n     * @param searchColor  the color in the SVG to replace.\n     * @param replaceColor the color with which to replace the search color.\n     * @return the parsed SVG.\n     * @throws SVGParseException if there is an error while parsing.\n     */\n    public static SVG getSVGFromResource(Resources resources, int resId, int searchColor, int replaceColor) throws SVGParseException {\n        return SVGParser.parse(resources.openRawResource(resId), searchColor, replaceColor, false);\n    }\n\n    /**\n     * Parse SVG data from an Android application asset.\n     *\n     * @param assetMngr    the Android asset manager.\n     * @param svgPath      the path to the SVG file in the application's assets.\n     * @param searchColor  the color in the SVG to replace.\n     * @param replaceColor the color with which to replace the search color.\n     * @return the parsed SVG.\n     * @throws SVGParseException if there is an error while parsing.\n     * @throws IOException       if there was a problem reading the file.\n     */\n    public static SVG getSVGFromAsset(AssetManager assetMngr, String svgPath, int searchColor, int replaceColor) throws SVGParseException, IOException {\n        InputStream inputStream = assetMngr.open(svgPath);\n        SVG svg = getSVGFromInputStream(inputStream, searchColor, replaceColor);\n        inputStream.close();\n        return svg;\n    }\n\n    /**\n     * Parses a single SVG path and returns it as a <code>android.graphics.Path</code> object.\n     * An example path is <code>M250,150L150,350L350,350Z</code>, which draws a triangle.\n     *\n     * @param pathString the SVG path, see the specification <a href=\"http://www.w3.org/TR/SVG/paths.html\">here</a>.\n     */\n    public static Path parsePath(String pathString) {\n        return doPath(pathString);\n    }\n\n    private static SVG parse(InputStream in, Integer searchColor, Integer replaceColor, boolean whiteMode) throws SVGParseException {\n        // Log.d(TAG, \"Parsing SVG...\");\n        try {\n            // long start = System.currentTimeMillis();\n            SAXParserFactory spf = SAXParserFactory.newInstance();\n            SAXParser sp = spf.newSAXParser();\n            XMLReader xr = sp.getXMLReader();\n            final Picture picture = new Picture();\n            SVGHandler handler = new SVGHandler(picture);\n            handler.setColorSwap(searchColor, replaceColor);\n            handler.setWhiteMode(whiteMode);\n            xr.setContentHandler(handler);\n            xr.parse(new InputSource(in));\n            // Log.d(TAG, \"Parsing complete in \" + (System.currentTimeMillis() - start) + \" millis.\");\n            SVG result = new SVG(picture, handler.bounds);\n            // Skip bounds if it was an empty pic\n            if (!Float.isInfinite(handler.limits.top)) {\n                result.setLimits(handler.limits);\n            }\n            return result;\n        } catch (Exception e) {\n            throw new SVGParseException(e);\n        }\n    }\n\n    @NonNull\n    private static NumberParse parseNumbers(String s) {\n        // Log.d(TAG, \"Parsing numbers from: '\" + s + \"'\");\n        int n = s.length();\n        int p = 0;\n        ArrayList<Float> numbers = new ArrayList<>();\n        boolean skipChar = false;\n        for (int i = 1; i < n; i++) {\n            if (skipChar) {\n                skipChar = false;\n                continue;\n            }\n            char c = s.charAt(i);\n            switch (c) {\n                // This ends the parsing, as we are on the next element\n                case 'M':\n                case 'm':\n                case 'Z':\n                case 'z':\n                case 'L':\n                case 'l':\n                case 'H':\n                case 'h':\n                case 'V':\n                case 'v':\n                case 'C':\n                case 'c':\n                case 'S':\n                case 's':\n                case 'Q':\n                case 'q':\n                case 'T':\n                case 't':\n                case 'a':\n                case 'A':\n                case ')': {\n                    String str = s.substring(p, i);\n                    if (str.trim().length() > 0) {\n                        // Log.d(TAG, \"  Last: \" + str);\n                        Float f = Float.parseFloat(str);\n                        numbers.add(f);\n                    }\n                    p = i;\n                    return new NumberParse(numbers, p);\n                }\n                case '\\n':\n                case '\\t':\n                case ' ':\n                case ',':\n                case '-': {\n                    String str = s.substring(p, i);\n                    // Just keep moving if multiple whitespace\n                    if (str.trim().length() > 0) {\n                        // Log.d(TAG, \"  Next: \" + str);\n                        Float f = Float.parseFloat(str);\n                        numbers.add(f);\n                        if (c == '-') {\n                            p = i;\n                        } else {\n                            p = i + 1;\n                            skipChar = true;\n                        }\n                    } else {\n                        p++;\n                    }\n                    break;\n                }\n            }\n        }\n        String last = s.substring(p);\n        if (last.length() > 0) {\n            // Log.d(TAG, \"  Last: \" + last);\n            try {\n                numbers.add(Float.parseFloat(last));\n            } catch (NumberFormatException nfe) {\n                // Just white-space, forget it\n            }\n            p = s.length();\n        }\n        return new NumberParse(numbers, p);\n    }\n\n    @Nullable\n    private static Matrix parseTransform(String s) {\n        if (s.startsWith(\"matrix(\")) {\n            NumberParse np = parseNumbers(s.substring(\"matrix(\".length()));\n            if (np.numbers.size() == 6) {\n                Matrix matrix = new Matrix();\n                matrix.setValues(new float[]{\n                        // Row 1\n                        np.numbers.get(0),\n                        np.numbers.get(2),\n                        np.numbers.get(4),\n                        // Row 2\n                        np.numbers.get(1),\n                        np.numbers.get(3),\n                        np.numbers.get(5),\n                        // Row 3\n                        0,\n                        0,\n                        1,\n                });\n                return matrix;\n            }\n        } else if (s.startsWith(\"translate(\")) {\n            NumberParse np = parseNumbers(s.substring(\"translate(\".length()));\n            if (np.numbers.size() > 0) {\n                float tx = np.numbers.get(0);\n                float ty = 0;\n                if (np.numbers.size() > 1) {\n                    ty = np.numbers.get(1);\n                }\n                Matrix matrix = new Matrix();\n                matrix.postTranslate(tx, ty);\n                return matrix;\n            }\n        } else if (s.startsWith(\"scale(\")) {\n            NumberParse np = parseNumbers(s.substring(\"scale(\".length()));\n            if (np.numbers.size() > 0) {\n                float sx = np.numbers.get(0);\n                float sy = 0;\n                if (np.numbers.size() > 1) {\n                    sy = np.numbers.get(1);\n                }\n                Matrix matrix = new Matrix();\n                matrix.postScale(sx, sy);\n                return matrix;\n            }\n        } else if (s.startsWith(\"skewX(\")) {\n            NumberParse np = parseNumbers(s.substring(\"skewX(\".length()));\n            if (np.numbers.size() > 0) {\n                float angle = np.numbers.get(0);\n                Matrix matrix = new Matrix();\n                matrix.postSkew((float) Math.tan(angle), 0);\n                return matrix;\n            }\n        } else if (s.startsWith(\"skewY(\")) {\n            NumberParse np = parseNumbers(s.substring(\"skewY(\".length()));\n            if (np.numbers.size() > 0) {\n                float angle = np.numbers.get(0);\n                Matrix matrix = new Matrix();\n                matrix.postSkew(0, (float) Math.tan(angle));\n                return matrix;\n            }\n        } else if (s.startsWith(\"rotate(\")) {\n            NumberParse np = parseNumbers(s.substring(\"rotate(\".length()));\n            if (np.numbers.size() > 0) {\n                float angle = np.numbers.get(0);\n                float cx = 0;\n                float cy = 0;\n                if (np.numbers.size() > 2) {\n                    cx = np.numbers.get(1);\n                    cy = np.numbers.get(2);\n                }\n                Matrix matrix = new Matrix();\n                matrix.postTranslate(cx, cy);\n                matrix.postRotate(angle);\n                matrix.postTranslate(-cx, -cy);\n                return matrix;\n            }\n        }\n        return null;\n    }\n\n    /**\n     * This is where the hard-to-parse paths are handled.\n     * Uppercase rules are absolute positions, lowercase are relative.\n     * Types of path rules:\n     * <p/>\n     * <ol>\n     * <li>M/m - (x y)+ - Move to (without drawing)\n     * <li>Z/z - (no params) - Close path (back to starting point)\n     * <li>L/l - (x y)+ - Line to\n     * <li>H/h - x+ - Horizontal ine to\n     * <li>V/v - y+ - Vertical line to\n     * <li>C/c - (x1 y1 x2 y2 x y)+ - Cubic bezier to\n     * <li>S/s - (x2 y2 x y)+ - Smooth cubic bezier to (shorthand that assumes the x2, y2 from previous C/S is the x1, y1 of this bezier)\n     * <li>Q/q - (x1 y1 x y)+ - Quadratic bezier to\n     * <li>T/t - (x y)+ - Smooth quadratic bezier to (assumes previous control point is \"reflection\" of last one w.r.t. to current point)\n     * </ol>\n     * <p/>\n     * Numbers are separate by whitespace, comma or nothing at all (!) if they are self-delimiting, (ie. begin with a - sign)\n     *\n     * @param s the path string from the XML\n     */\n    @NonNull\n    private static Path doPath(String s) {\n        int n = s.length();\n        ParserHelper ph = new ParserHelper(s, 0);\n        ph.skipWhitespace();\n        Path p = new Path();\n        float lastX = 0;\n        float lastY = 0;\n        float lastX1 = 0;\n        float lastY1 = 0;\n        float subPathStartX = 0;\n        float subPathStartY = 0;\n        char prevCmd = 0;\n        while (ph.pos < n) {\n            char cmd = s.charAt(ph.pos);\n            switch (cmd) {\n                case '-':\n                case '+':\n                case '0':\n                case '1':\n                case '2':\n                case '3':\n                case '4':\n                case '5':\n                case '6':\n                case '7':\n                case '8':\n                case '9':\n                    if (prevCmd == 'm' || prevCmd == 'M') {\n                        cmd = (char) (((int) prevCmd) - 1);\n                        break;\n                    } else if (prevCmd == 'c' || prevCmd == 'C') {\n                        cmd = prevCmd;\n                        break;\n                    } else if (prevCmd == 'l' || prevCmd == 'L') {\n                        cmd = prevCmd;\n                        break;\n                    }\n                default: {\n                    ph.advance();\n                    prevCmd = cmd;\n                }\n            }\n\n            boolean wasCurve = false;\n            switch (cmd) {\n                case 'M':\n                case 'm': {\n                    float x = ph.nextFloat();\n                    float y = ph.nextFloat();\n                    if (cmd == 'm') {\n                        subPathStartX += x;\n                        subPathStartY += y;\n                        p.rMoveTo(x, y);\n                        lastX += x;\n                        lastY += y;\n                    } else {\n                        subPathStartX = x;\n                        subPathStartY = y;\n                        p.moveTo(x, y);\n                        lastX = x;\n                        lastY = y;\n                    }\n                    break;\n                }\n                case 'Z':\n                case 'z': {\n                    p.close();\n                    p.moveTo(subPathStartX, subPathStartY);\n                    lastX = subPathStartX;\n                    lastY = subPathStartY;\n                    lastX1 = subPathStartX;\n                    lastY1 = subPathStartY;\n                    wasCurve = true;\n                    break;\n                }\n                case 'L':\n                case 'l': {\n                    float x = ph.nextFloat();\n                    float y = ph.nextFloat();\n                    if (cmd == 'l') {\n                        p.rLineTo(x, y);\n                        lastX += x;\n                        lastY += y;\n                    } else {\n                        p.lineTo(x, y);\n                        lastX = x;\n                        lastY = y;\n                    }\n                    break;\n                }\n                case 'H':\n                case 'h': {\n                    float x = ph.nextFloat();\n                    if (cmd == 'h') {\n                        p.rLineTo(x, 0);\n                        lastX += x;\n                    } else {\n                        p.lineTo(x, lastY);\n                        lastX = x;\n                    }\n                    break;\n                }\n                case 'V':\n                case 'v': {\n                    float y = ph.nextFloat();\n                    if (cmd == 'v') {\n                        p.rLineTo(0, y);\n                        lastY += y;\n                    } else {\n                        p.lineTo(lastX, y);\n                        lastY = y;\n                    }\n                    break;\n                }\n                case 'C':\n                case 'c': {\n                    wasCurve = true;\n                    float x1 = ph.nextFloat();\n                    float y1 = ph.nextFloat();\n                    float x2 = ph.nextFloat();\n                    float y2 = ph.nextFloat();\n                    float x = ph.nextFloat();\n                    float y = ph.nextFloat();\n                    if (cmd == 'c') {\n                        x1 += lastX;\n                        x2 += lastX;\n                        x += lastX;\n                        y1 += lastY;\n                        y2 += lastY;\n                        y += lastY;\n                    }\n                    p.cubicTo(x1, y1, x2, y2, x, y);\n                    lastX1 = x2;\n                    lastY1 = y2;\n                    lastX = x;\n                    lastY = y;\n                    break;\n                }\n                case 'S':\n                case 's': {\n                    wasCurve = true;\n                    float x2 = ph.nextFloat();\n                    float y2 = ph.nextFloat();\n                    float x = ph.nextFloat();\n                    float y = ph.nextFloat();\n                    if (cmd == 's') {\n                        x2 += lastX;\n                        x += lastX;\n                        y2 += lastY;\n                        y += lastY;\n                    }\n                    float x1 = 2 * lastX - lastX1;\n                    float y1 = 2 * lastY - lastY1;\n                    p.cubicTo(x1, y1, x2, y2, x, y);\n                    lastX1 = x2;\n                    lastY1 = y2;\n                    lastX = x;\n                    lastY = y;\n                    break;\n                }\n                case 'A':\n                case 'a': {\n                    float rx = ph.nextFloat();\n                    float ry = ph.nextFloat();\n                    float theta = ph.nextFloat();\n                    int largeArc = (int) ph.nextFloat();\n                    int sweepArc = (int) ph.nextFloat();\n                    float x = ph.nextFloat();\n                    float y = ph.nextFloat();\n                    drawArc(p, lastX, lastY, x, y, rx, ry, theta, largeArc, sweepArc);\n                    lastX = x;\n                    lastY = y;\n                    break;\n                }\n            }\n            if (!wasCurve) {\n                lastX1 = lastX;\n                lastY1 = lastY;\n            }\n            ph.skipWhitespace();\n        }\n        return p;\n    }\n\n    private static void drawArc(Path p, float lastX, float lastY, float x, float y, float rx, float ry, float theta, int largeArc, int sweepArc) {\n        // todo - not implemented yet, may be very hard to do using Android drawing facilities.\n    }\n\n    @Nullable\n    private static NumberParse getNumberParseAttr(String name, Attributes attributes) {\n        int n = attributes.getLength();\n        for (int i = 0; i < n; i++) {\n            if (attributes.getLocalName(i).equals(name)) {\n                return parseNumbers(attributes.getValue(i));\n            }\n        }\n        return null;\n    }\n\n    @Nullable\n    private static String getStringAttr(String name, Attributes attributes) {\n        int n = attributes.getLength();\n        for (int i = 0; i < n; i++) {\n            if (attributes.getLocalName(i).equals(name)) {\n                return attributes.getValue(i);\n            }\n        }\n        return null;\n    }\n\n    @Nullable\n    private static Float getFloatAttr(String name, Attributes attributes) {\n        return getFloatAttr(name, attributes, null);\n    }\n\n    @Contract(\"_, _, !null -> !null\")\n    @Nullable\n    private static Float getFloatAttr(String name, Attributes attributes, @Nullable Float defaultValue) {\n        String v = getStringAttr(name, attributes);\n        if (v == null) {\n            return defaultValue;\n        } else {\n            if (v.endsWith(\"px\")) {\n                v = v.substring(0, v.length() - 2);\n            }\n            // Log.d(TAG, \"Float parsing '\" + name + \"=\" + v + \"'\");\n            return Float.parseFloat(v);\n        }\n    }\n\n    @Nullable\n    private static Integer getHexAttr(String name, Attributes attributes) {\n        String v = getStringAttr(name, attributes);\n        // Log.d(TAG, \"Hex parsing '\" + name + \"=\" + v + \"'\");\n        if (v == null) {\n            return null;\n        } else {\n            try {\n                return Integer.parseInt(v.substring(1), 16);\n            } catch (NumberFormatException nfe) {\n                // todo - parse word-based color here\n                return null;\n            }\n        }\n    }\n\n    private static class NumberParse {\n        private final ArrayList<Float> numbers;\n        private final int nextCmd;\n\n        public NumberParse(ArrayList<Float> numbers, int nextCmd) {\n            this.numbers = numbers;\n            this.nextCmd = nextCmd;\n        }\n\n        public int getNextCmd() {\n            return nextCmd;\n        }\n\n        public float getNumber(int index) {\n            return numbers.get(index);\n        }\n\n    }\n\n    private static class Gradient {\n        String id;\n        String xlink;\n        boolean isLinear;\n        float x1, y1, x2, y2;\n        float x, y, radius;\n        ArrayList<Float> positions = new ArrayList<>();\n        ArrayList<Integer> colors = new ArrayList<>();\n        Matrix matrix = null;\n\n        public Gradient createChild(Gradient g) {\n            Gradient child = new Gradient();\n            child.id = g.id;\n            child.xlink = id;\n            child.isLinear = g.isLinear;\n            child.x1 = g.x1;\n            child.x2 = g.x2;\n            child.y1 = g.y1;\n            child.y2 = g.y2;\n            child.x = g.x;\n            child.y = g.y;\n            child.radius = g.radius;\n            child.positions = positions;\n            child.colors = colors;\n            child.matrix = matrix;\n            if (g.matrix != null) {\n                if (matrix == null) {\n                    child.matrix = g.matrix;\n                } else {\n                    Matrix m = new Matrix(matrix);\n                    m.preConcat(g.matrix);\n                    child.matrix = m;\n                }\n            }\n            return child;\n        }\n    }\n\n    private static class StyleSet {\n        HashMap<String, String> styleMap = new HashMap<>();\n\n        private StyleSet(String string) {\n            String[] styles = string.split(\";\");\n            for (String s : styles) {\n                String[] style = s.split(\":\");\n                if (style.length == 2) {\n                    styleMap.put(style[0], style[1]);\n                }\n            }\n        }\n\n        @Nullable\n        public String getStyle(String name) {\n            return styleMap.get(name);\n        }\n    }\n\n    private static class Properties {\n        StyleSet styles = null;\n        Attributes atts;\n\n        private Properties(Attributes atts) {\n            this.atts = atts;\n            String styleAttr = getStringAttr(\"style\", atts);\n            if (styleAttr != null) {\n                styles = new StyleSet(styleAttr);\n            }\n        }\n\n        @Nullable\n        public String getAttr(String name) {\n            String v = null;\n            if (styles != null) {\n                v = styles.getStyle(name);\n            }\n            if (v == null) {\n                v = getStringAttr(name, atts);\n            }\n            return v;\n        }\n\n        @Nullable\n        public String getString(String name) {\n            return getAttr(name);\n        }\n\n        @Nullable\n        public Integer getHex(String name) {\n            String v = getAttr(name);\n            if (v == null || !v.startsWith(\"#\")) {\n                return null;\n            } else {\n                try {\n                    return Integer.parseInt(v.substring(1), 16);\n                } catch (NumberFormatException nfe) {\n                    // todo - parse word-based color here\n                    return null;\n                }\n            }\n        }\n\n        @NonNull\n        public Float getFloat(String name, float defaultValue) {\n            Float v = getFloat(name);\n            if (v == null) {\n                return defaultValue;\n            } else {\n                return v;\n            }\n        }\n\n        @Nullable\n        public Float getFloat(String name) {\n            String v = getAttr(name);\n            if (v == null) {\n                return null;\n            } else {\n                try {\n                    return Float.parseFloat(v);\n                } catch (NumberFormatException nfe) {\n                    return null;\n                }\n            }\n        }\n    }\n\n    private static class SVGHandler extends DefaultHandler {\n\n        Picture picture;\n        Canvas canvas;\n        Paint paint;\n        // Scratch rect (so we aren't constantly making new ones)\n        RectF rect = new RectF();\n        RectF bounds = null;\n        RectF limits = new RectF(Float.POSITIVE_INFINITY, Float.POSITIVE_INFINITY, Float.NEGATIVE_INFINITY, Float.NEGATIVE_INFINITY);\n\n        Integer searchColor = null;\n        Integer replaceColor = null;\n\n        boolean whiteMode = false;\n\n        boolean pushed = false;\n\n        HashMap<String, Shader> gradientMap = new HashMap<>();\n        HashMap<String, Gradient> gradientRefMap = new HashMap<>();\n        Gradient gradient = null;\n\n        private SVGHandler(Picture picture) {\n            this.picture = picture;\n            paint = new Paint();\n            paint.setAntiAlias(true);\n        }\n\n        public void setColorSwap(Integer searchColor, Integer replaceColor) {\n            this.searchColor = searchColor;\n            this.replaceColor = replaceColor;\n        }\n\n        public void setWhiteMode(boolean whiteMode) {\n            this.whiteMode = whiteMode;\n        }\n\n        @Override\n        public void startDocument() {\n            // Set up prior to parsing a doc\n        }\n\n        @Override\n        public void endDocument() {\n            // Clean up after parsing a doc\n        }\n\n        private boolean doFill(Properties atts, HashMap<String, Shader> gradients) {\n            if (\"none\".equals(atts.getString(\"display\"))) {\n                return false;\n            }\n            if (whiteMode) {\n                paint.setStyle(Paint.Style.FILL);\n                paint.setColor(0xFFFFFFFF);\n                return true;\n            }\n            String fillString = atts.getString(\"fill\");\n            if (fillString != null && fillString.startsWith(\"url(#\")) {\n                // It's a gradient fill, look it up in our map\n                String id = fillString.substring(\"url(#\".length(), fillString.length() - 1);\n                Shader shader = gradients.get(id);\n                if (shader != null) {\n                    // Log.d(TAG, \"Found shader!\");\n                    paint.setShader(shader);\n                    paint.setStyle(Paint.Style.FILL);\n                    return true;\n                } else {\n                    // Log.d(TAG, \"Didn't find shader!\");\n                    return false;\n                }\n            } else {\n                paint.setShader(null);\n                Integer color = atts.getHex(\"fill\");\n                if (color != null) {\n                    doColor(atts, color, true);\n                    paint.setStyle(Paint.Style.FILL);\n                    return true;\n                } else if (atts.getString(\"fill\") == null && atts.getString(\"stroke\") == null) {\n                    // Default is black fill\n                    paint.setStyle(Paint.Style.FILL);\n                    paint.setColor(0xFF000000);\n                    return true;\n                }\n            }\n            return false;\n        }\n\n        private boolean doStroke(Properties atts) {\n            if (whiteMode) {\n                // Never stroke in white mode\n                return false;\n            }\n            if (\"none\".equals(atts.getString(\"display\"))) {\n                return false;\n            }\n            Integer color = atts.getHex(\"stroke\");\n            if (color != null) {\n                doColor(atts, color, false);\n                // Check for other stroke attributes\n                Float width = atts.getFloat(\"stroke-width\");\n                // Set defaults\n\n                if (width != null) {\n                    paint.setStrokeWidth(width);\n                }\n                String linecap = atts.getString(\"stroke-linecap\");\n                if (\"round\".equals(linecap)) {\n                    paint.setStrokeCap(Paint.Cap.ROUND);\n                } else if (\"square\".equals(linecap)) {\n                    paint.setStrokeCap(Paint.Cap.SQUARE);\n                } else if (\"butt\".equals(linecap)) {\n                    paint.setStrokeCap(Paint.Cap.BUTT);\n                }\n                String linejoin = atts.getString(\"stroke-linejoin\");\n                if (\"miter\".equals(linejoin)) {\n                    paint.setStrokeJoin(Paint.Join.MITER);\n                } else if (\"round\".equals(linejoin)) {\n                    paint.setStrokeJoin(Paint.Join.ROUND);\n                } else if (\"bevel\".equals(linejoin)) {\n                    paint.setStrokeJoin(Paint.Join.BEVEL);\n                }\n                paint.setStyle(Paint.Style.STROKE);\n                return true;\n            }\n            return false;\n        }\n\n        private Gradient doGradient(boolean isLinear, Attributes atts) {\n            Gradient gradient = new Gradient();\n            gradient.id = getStringAttr(\"id\", atts);\n            gradient.isLinear = isLinear;\n            if (isLinear) {\n                gradient.x1 = getFloatAttr(\"x1\", atts, 0f);\n                gradient.x2 = getFloatAttr(\"x2\", atts, 0f);\n                gradient.y1 = getFloatAttr(\"y1\", atts, 0f);\n                gradient.y2 = getFloatAttr(\"y2\", atts, 0f);\n            } else {\n                gradient.x = getFloatAttr(\"cx\", atts, 0f);\n                gradient.y = getFloatAttr(\"cy\", atts, 0f);\n                gradient.radius = getFloatAttr(\"r\", atts, 0f);\n            }\n            String transform = getStringAttr(\"gradientTransform\", atts);\n            if (transform != null) {\n                gradient.matrix = parseTransform(transform);\n            }\n            String xlink = getStringAttr(\"href\", atts);\n            if (xlink != null) {\n                if (xlink.startsWith(\"#\")) {\n                    xlink = xlink.substring(1);\n                }\n                gradient.xlink = xlink;\n            }\n            return gradient;\n        }\n\n        private void doColor(Properties atts, Integer color, boolean fillMode) {\n            int c = (0xFFFFFF & color) | 0xFF000000;\n            if (searchColor != null && searchColor == c) {\n                c = replaceColor;\n            }\n            paint.setColor(c);\n            Float opacity = atts.getFloat(\"opacity\");\n            if (opacity == null) {\n                opacity = atts.getFloat(fillMode ? \"fill-opacity\" : \"stroke-opacity\");\n            }\n            if (opacity == null) {\n                paint.setAlpha(255);\n            } else {\n                paint.setAlpha((int) (255 * opacity));\n            }\n        }\n\n        private boolean hidden = false;\n        private int hiddenLevel = 0;\n        private boolean boundsMode = false;\n\n        private void doLimits(float x, float y) {\n            if (x < limits.left) {\n                limits.left = x;\n            }\n            if (x > limits.right) {\n                limits.right = x;\n            }\n            if (y < limits.top) {\n                limits.top = y;\n            }\n            if (y > limits.bottom) {\n                limits.bottom = y;\n            }\n        }\n\n        private void doLimits(float x, float y, float width, float height) {\n            doLimits(x, y);\n            doLimits(x + width, y + height);\n        }\n\n        private void doLimits(Path path) {\n            path.computeBounds(rect, false);\n            doLimits(rect.left, rect.top);\n            doLimits(rect.right, rect.bottom);\n        }\n\n        private void pushTransform(Attributes atts) {\n            final String transform = getStringAttr(\"transform\", atts);\n            pushed = transform != null;\n            if (pushed) {\n                final Matrix matrix = parseTransform(transform);\n                canvas.save();\n                canvas.concat(matrix);\n            }\n        }\n\n        private void popTransform() {\n            if (pushed) {\n                canvas.restore();\n            }\n        }\n\n        @Override\n        public void startElement(String namespaceURI, String localName, String qName, Attributes atts) {\n            // Reset paint opacity\n            paint.setAlpha(255);\n            // Ignore everything but rectangles in bounds mode\n            if (boundsMode) {\n                if (localName.equals(\"rect\")) {\n                    Float x = getFloatAttr(\"x\", atts);\n                    if (x == null) {\n                        x = 0f;\n                    }\n                    Float y = getFloatAttr(\"y\", atts);\n                    if (y == null) {\n                        y = 0f;\n                    }\n                    Float width = getFloatAttr(\"width\", atts);\n                    Float height = getFloatAttr(\"height\", atts);\n                    bounds = new RectF(x, y, x + width, y + width);\n                }\n                return;\n            }\n            if (localName.equals(\"svg\")) {\n                int width = (int) Math.ceil(getFloatAttr(\"width\", atts));\n                int height = (int) Math.ceil(getFloatAttr(\"height\", atts));\n                canvas = picture.beginRecording(width, height);\n            } else if (localName.equals(\"defs\")) {\n                // Ignore\n            } else if (localName.equals(\"linearGradient\")) {\n                gradient = doGradient(true, atts);\n            } else if (localName.equals(\"radialGradient\")) {\n                gradient = doGradient(false, atts);\n            } else if (localName.equals(\"stop\")) {\n                if (gradient != null) {\n                    float offset = getFloatAttr(\"offset\", atts);\n                    String styles = getStringAttr(\"style\", atts);\n                    StyleSet styleSet = new StyleSet(styles);\n                    String colorStyle = styleSet.getStyle(\"stop-color\");\n                    int color = Color.BLACK;\n                    if (colorStyle != null) {\n                        if (colorStyle.startsWith(\"#\")) {\n                            color = Integer.parseInt(colorStyle.substring(1), 16);\n                        } else {\n                            color = Integer.parseInt(colorStyle, 16);\n                        }\n                    }\n                    String opacityStyle = styleSet.getStyle(\"stop-opacity\");\n                    if (opacityStyle != null) {\n                        float alpha = Float.parseFloat(opacityStyle);\n                        int alphaInt = Math.round(255 * alpha);\n                        color |= (alphaInt << 24);\n                    } else {\n                        color |= 0xFF000000;\n                    }\n                    gradient.positions.add(offset);\n                    gradient.colors.add(color);\n                }\n            } else if (localName.equals(\"g\")) {\n                // Check to see if this is the \"bounds\" layer\n                if (\"bounds\".equalsIgnoreCase(getStringAttr(\"id\", atts))) {\n                    boundsMode = true;\n                }\n                if (hidden) {\n                    hiddenLevel++;\n                    // Log.d(TAG, \"Hidden up: \" + hiddenLevel);\n                }\n                // Go in to hidden mode if display is \"none\"\n                if (\"none\".equals(getStringAttr(\"display\", atts))) {\n                    if (!hidden) {\n                        hidden = true;\n                        hiddenLevel = 1;\n                        // Log.d(TAG, \"Hidden up: \" + hiddenLevel);\n                    }\n                }\n            } else if (!hidden && localName.equals(\"rect\")) {\n                Float x = getFloatAttr(\"x\", atts);\n                if (x == null) {\n                    x = 0f;\n                }\n                Float y = getFloatAttr(\"y\", atts);\n                if (y == null) {\n                    y = 0f;\n                }\n                Float width = getFloatAttr(\"width\", atts);\n                Float height = getFloatAttr(\"height\", atts);\n                pushTransform(atts);\n                Properties props = new Properties(atts);\n                if (doFill(props, gradientMap)) {\n                    doLimits(x, y, width, height);\n                    canvas.drawRect(x, y, x + width, y + height, paint);\n                }\n                if (doStroke(props)) {\n                    canvas.drawRect(x, y, x + width, y + height, paint);\n                }\n                popTransform();\n            } else if (!hidden && localName.equals(\"line\")) {\n                Float x1 = getFloatAttr(\"x1\", atts);\n                Float x2 = getFloatAttr(\"x2\", atts);\n                Float y1 = getFloatAttr(\"y1\", atts);\n                Float y2 = getFloatAttr(\"y2\", atts);\n                Properties props = new Properties(atts);\n                if (doStroke(props)) {\n                    pushTransform(atts);\n                    doLimits(x1, y1);\n                    doLimits(x2, y2);\n                    canvas.drawLine(x1, y1, x2, y2, paint);\n                    popTransform();\n                }\n            } else if (!hidden && localName.equals(\"circle\")) {\n                Float centerX = getFloatAttr(\"cx\", atts);\n                Float centerY = getFloatAttr(\"cy\", atts);\n                Float radius = getFloatAttr(\"r\", atts);\n                if (centerX != null && centerY != null && radius != null) {\n                    pushTransform(atts);\n                    Properties props = new Properties(atts);\n                    if (doFill(props, gradientMap)) {\n                        doLimits(centerX - radius, centerY - radius);\n                        doLimits(centerX + radius, centerY + radius);\n                        canvas.drawCircle(centerX, centerY, radius, paint);\n                    }\n                    if (doStroke(props)) {\n                        canvas.drawCircle(centerX, centerY, radius, paint);\n                    }\n                    popTransform();\n                }\n            } else if (!hidden && localName.equals(\"ellipse\")) {\n                Float centerX = getFloatAttr(\"cx\", atts);\n                Float centerY = getFloatAttr(\"cy\", atts);\n                Float radiusX = getFloatAttr(\"rx\", atts);\n                Float radiusY = getFloatAttr(\"ry\", atts);\n                if (centerX != null && centerY != null && radiusX != null && radiusY != null) {\n                    pushTransform(atts);\n                    Properties props = new Properties(atts);\n                    rect.set(centerX - radiusX, centerY - radiusY, centerX + radiusX, centerY + radiusY);\n                    if (doFill(props, gradientMap)) {\n                        doLimits(centerX - radiusX, centerY - radiusY);\n                        doLimits(centerX + radiusX, centerY + radiusY);\n                        canvas.drawOval(rect, paint);\n                    }\n                    if (doStroke(props)) {\n                        canvas.drawOval(rect, paint);\n                    }\n                    popTransform();\n                }\n            } else if (!hidden && (localName.equals(\"polygon\") || localName.equals(\"polyline\"))) {\n                NumberParse numbers = getNumberParseAttr(\"points\", atts);\n                if (numbers != null) {\n                    Path p = new Path();\n                    ArrayList<Float> points = numbers.numbers;\n                    if (points.size() > 1) {\n                        pushTransform(atts);\n                        Properties props = new Properties(atts);\n                        p.moveTo(points.get(0), points.get(1));\n                        for (int i = 2; i < points.size(); i += 2) {\n                            float x = points.get(i);\n                            float y = points.get(i + 1);\n                            p.lineTo(x, y);\n                        }\n                        // Don't close a polyline\n                        if (localName.equals(\"polygon\")) {\n                            p.close();\n                        }\n                        if (doFill(props, gradientMap)) {\n                            doLimits(p);\n                            canvas.drawPath(p, paint);\n                        }\n                        if (doStroke(props)) {\n                            canvas.drawPath(p, paint);\n                        }\n                        popTransform();\n                    }\n                }\n            } else if (!hidden && localName.equals(\"path\")) {\n                Path p = doPath(getStringAttr(\"d\", atts));\n                pushTransform(atts);\n                Properties props = new Properties(atts);\n                if (doFill(props, gradientMap)) {\n                    doLimits(p);\n                    canvas.drawPath(p, paint);\n                }\n                if (doStroke(props)) {\n                    canvas.drawPath(p, paint);\n                }\n                popTransform();\n            } else if (!hidden) {\n                Log.d(TAG, \"UNRECOGNIZED SVG COMMAND: \" + localName);\n            }\n        }\n\n        @Override\n        public void characters(char[] ch, int start, int length) {\n            // no-op\n        }\n\n        @Override\n        public void endElement(String namespaceURI, String localName, String qName) {\n            switch (localName) {\n                case \"svg\":\n                    picture.endRecording();\n                    break;\n                case \"linearGradient\":\n                    if (gradient.id != null) {\n                        if (gradient.xlink != null) {\n                            Gradient parent = gradientRefMap.get(gradient.xlink);\n                            if (parent != null) {\n                                gradient = parent.createChild(gradient);\n                            }\n                        }\n                        int[] colors = new int[gradient.colors.size()];\n                        for (int i = 0; i < colors.length; i++) {\n                            colors[i] = gradient.colors.get(i);\n                        }\n                        float[] positions = new float[gradient.positions.size()];\n                        for (int i = 0; i < positions.length; i++) {\n                            positions[i] = gradient.positions.get(i);\n                        }\n                        if (colors.length == 0) {\n                            Log.d(\"BAD\", \"BAD\");\n                        }\n                        LinearGradient g = new LinearGradient(gradient.x1, gradient.y1, gradient.x2, gradient.y2, colors, positions, Shader.TileMode.CLAMP);\n                        if (gradient.matrix != null) {\n                            g.setLocalMatrix(gradient.matrix);\n                        }\n                        gradientMap.put(gradient.id, g);\n                        gradientRefMap.put(gradient.id, gradient);\n                    }\n                    break;\n                case \"radialGradient\":\n                    if (gradient.id != null) {\n                        if (gradient.xlink != null) {\n                            Gradient parent = gradientRefMap.get(gradient.xlink);\n                            if (parent != null) {\n                                gradient = parent.createChild(gradient);\n                            }\n                        }\n                        int[] colors = new int[gradient.colors.size()];\n                        for (int i = 0; i < colors.length; i++) {\n                            colors[i] = gradient.colors.get(i);\n                        }\n                        float[] positions = new float[gradient.positions.size()];\n                        for (int i = 0; i < positions.length; i++) {\n                            positions[i] = gradient.positions.get(i);\n                        }\n                        if (gradient.xlink != null) {\n                            Gradient parent = gradientRefMap.get(gradient.xlink);\n                            if (parent != null) {\n                                gradient = parent.createChild(gradient);\n                            }\n                        }\n                        RadialGradient g = new RadialGradient(gradient.x, gradient.y, gradient.radius, colors, positions, Shader.TileMode.CLAMP);\n                        if (gradient.matrix != null) {\n                            g.setLocalMatrix(gradient.matrix);\n                        }\n                        gradientMap.put(gradient.id, g);\n                        gradientRefMap.put(gradient.id, gradient);\n                    }\n                    break;\n                case \"g\":\n                    if (boundsMode) {\n                        boundsMode = false;\n                    }\n                    // Break out of hidden mode\n                    if (hidden) {\n                        hiddenLevel--;\n                        // Log.d(TAG, \"Hidden down: \" + hiddenLevel);\n                        if (hiddenLevel == 0) {\n                            hidden = false;\n                        }\n                    }\n                    // Clear gradient map\n                    gradientMap.clear();\n                    break;\n            }\n        }\n    }\n}"
  },
  {
    "path": "app/src/main/java/org/apache/commons/compress/archivers/ArchiveEntry.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage org.apache.commons.compress.archivers;\n\nimport java.util.Date;\n\n/**\n * Represents an entry of an archive.\n */\n// Copyright 2008 Torsten Curdt\npublic interface ArchiveEntry {\n\n    /**\n     * Gets the name of the entry in this archive. May refer to a file or directory or other item.\n     *\n     * <p>This method returns the raw name as it is stored inside of the archive.</p>\n     *\n     * @return The name of this entry in the archive.\n     */\n    String getName();\n\n    /**\n     * Gets the uncompressed size of this entry. May be -1 (SIZE_UNKNOWN) if the size is unknown\n     *\n     * @return the uncompressed size of this entry.\n     */\n    long getSize();\n\n    /** Special value indicating that the size is unknown */\n    long SIZE_UNKNOWN = -1;\n\n    /**\n     * Returns true if this entry refers to a directory.\n     *\n     * @return true if this entry refers to a directory.\n     */\n    boolean isDirectory();\n\n    /**\n     * Gets the last modified date of this entry.\n     *\n     * @return the last modified date of this entry.\n     * @since 1.1\n     */\n    Date getLastModifiedDate();\n}\n"
  },
  {
    "path": "app/src/main/java/org/apache/commons/compress/archivers/ArchiveInputStream.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage org.apache.commons.compress.archivers;\n\nimport java.io.IOException;\nimport java.io.InputStream;\n\n/**\n * Archive input streams <b>MUST</b> override the\n * {@link #read(byte[], int, int)} - or {@link #read()} -\n * method so that reading from the stream generates EOF for the end of\n * data in each entry as well as at the end of the file proper.\n * <p>\n * The {@link #getNextEntry()} method is used to reset the input stream\n * ready for reading the data from the next entry.\n * <p>\n * The input stream classes must also implement a method with the signature:\n * <pre>\n * public static boolean matches(byte[] signature, int length)\n * </pre>\n * which is used by the {@link ArchiveStreamFactory} to autodetect\n * the archive type from the first few bytes of a stream.\n */\n// Copyright 2008 Torsten Curdt\npublic abstract class ArchiveInputStream extends InputStream {\n\n    private final byte[] single = new byte[1];\n    private static final int BYTE_MASK = 0xFF;\n\n    /** holds the number of bytes read in this stream */\n    private long bytesRead = 0;\n\n    /**\n     * Returns the next Archive Entry in this Stream.\n     *\n     * @return the next entry,\n     *         or {@code null} if there are no more entries\n     * @throws IOException if the next entry could not be read\n     */\n    public abstract ArchiveEntry getNextEntry() throws IOException;\n\n    /*\n     * Note that subclasses also implement specific get() methods which\n     * return the appropriate class without need for a cast.\n     * See SVN revision r743259\n     * @return\n     * @throws IOException\n     */\n    // public abstract XXXArchiveEntry getNextXXXEntry() throws IOException;\n\n    /**\n     * Reads a byte of data. This method will block until enough input is\n     * available.\n     *\n     * Simply calls the {@link #read(byte[], int, int)} method.\n     *\n     * MUST be overridden if the {@link #read(byte[], int, int)} method\n     * is not overridden; may be overridden otherwise.\n     *\n     * @return the byte read, or -1 if end of input is reached\n     * @throws IOException\n     *             if an I/O error has occurred\n     */\n    @Override\n    public int read() throws IOException {\n        final int num = read(single, 0, 1);\n        return num == -1 ? -1 : single[0] & BYTE_MASK;\n    }\n\n    /**\n     * Increments the counter of already read bytes.\n     * Doesn't increment if the EOF has been hit (read == -1)\n     *\n     * @param read the number of bytes read\n     */\n    protected void count(final int read) {\n        count((long) read);\n    }\n\n    /**\n     * Increments the counter of already read bytes.\n     * Doesn't increment if the EOF has been hit (read == -1)\n     *\n     * @param read the number of bytes read\n     * @since 1.1\n     */\n    protected void count(final long read) {\n        if (read != -1) {\n            bytesRead = bytesRead + read;\n        }\n    }\n\n    /**\n     * Decrements the counter of already read bytes.\n     *\n     * @param pushedBack the number of bytes pushed back.\n     * @since 1.1\n     */\n    protected void pushedBackBytes(final long pushedBack) {\n        bytesRead -= pushedBack;\n    }\n\n    /**\n     * Returns the current number of bytes read from this stream.\n     * @return the number of read bytes\n     * @deprecated this method may yield wrong results for large\n     * archives, use #getBytesRead instead\n     */\n    @Deprecated\n    public int getCount() {\n        return (int) bytesRead;\n    }\n\n    /**\n     * Returns the current number of bytes read from this stream.\n     * @return the number of read bytes\n     * @since 1.1\n     */\n    public long getBytesRead() {\n        return bytesRead;\n    }\n\n    /**\n     * Whether this stream is able to read the given entry.\n     *\n     * <p>\n     * Some archive formats support variants or details that are not supported (yet).\n     * </p>\n     *\n     * @param archiveEntry\n     *            the entry to test\n     * @return This implementation always returns true.\n     *\n     * @since 1.1\n     */\n    public boolean canReadEntryData(final ArchiveEntry archiveEntry) {\n        return true;\n    }\n\n}"
  },
  {
    "path": "app/src/main/java/org/apache/commons/compress/archivers/ArchiveOutputStream.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage org.apache.commons.compress.archivers;\n\nimport android.system.ErrnoException;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.OutputStream;\nimport java.nio.file.LinkOption;\n\n/**\n * Archive output stream implementations are expected to override the\n * {@link #write(byte[], int, int)} method to improve performance.\n * They should also override {@link #close()} to ensure that any necessary\n * trailers are added.\n *\n * <p>The normal sequence of calls when working with ArchiveOutputStreams is:</p>\n * <ul>\n *   <li>Create ArchiveOutputStream object,</li>\n *   <li>optionally write SFX header (Zip only),</li>\n *   <li>repeat as needed:\n *     <ul>\n *       <li>{@link #putArchiveEntry(ArchiveEntry)} (writes entry header),\n *       <li>{@link #write(byte[])} (writes entry data, as often as needed),\n *       <li>{@link #closeArchiveEntry()} (closes entry),\n *     </ul>\n *   </li>\n *   <li> {@link #finish()} (ends the addition of entries),</li>\n *   <li> optionally write additional data, provided format supports it,</li>\n *   <li>{@link #close()}.</li>\n * </ul>\n */\n// Copyright 2008 Torsten Curdt\npublic abstract class ArchiveOutputStream extends OutputStream {\n\n    /** Temporary buffer used for the {@link #write(int)} method */\n    private final byte[] oneByte = new byte[1];\n    static final int BYTE_MASK = 0xFF;\n\n    /** holds the number of bytes written to this stream */\n    private long bytesWritten = 0;\n    // Methods specific to ArchiveOutputStream\n\n    /**\n     * Writes the headers for an archive entry to the output stream.\n     * The caller must then write the content to the stream and call\n     * {@link #closeArchiveEntry()} to complete the process.\n     *\n     * @param entry describes the entry\n     * @throws IOException if an I/O error occurs\n     */\n    public abstract void putArchiveEntry(ArchiveEntry entry) throws IOException;\n\n    /**\n     * Closes the archive entry, writing any trailer information that may\n     * be required.\n     * @throws IOException if an I/O error occurs\n     */\n    public abstract void closeArchiveEntry() throws IOException;\n\n    /**\n     * Finishes the addition of entries to this stream, without closing it.\n     * Additional data can be written, if the format supports it.\n     *\n     * @throws IOException if the user forgets to close the entry.\n     */\n    public abstract void finish() throws IOException;\n\n    /**\n     * Create an archive entry using the inputFile and entryName provided.\n     *\n     * @param inputFile the file to create the entry from\n     * @param entryName name to use for the entry\n     * @return the ArchiveEntry set up with details from the file\n     *\n     * @throws IOException if an I/O error occurs\n     */\n    public abstract ArchiveEntry createArchiveEntry(File inputFile, String entryName) throws IOException;\n\n    /**\n     * Create an archive entry using the inputPath and entryName provided.\n     *\n     * The default implementation calls simply delegates as:\n     * <pre>return createArchiveEntry(inputFile.toFile(), entryName);</pre>\n     *\n     * Subclasses should override this method.\n     *\n     * @param inputPath the file to create the entry from\n     * @param entryName name to use for the entry\n     * @param options options indicating how symbolic links are handled.\n     * @return the ArchiveEntry set up with details from the file\n     *\n     * @throws IOException if an I/O error occurs\n     * @since 1.21\n     */\n    public ArchiveEntry createArchiveEntry(final File inputPath, final String entryName, final LinkOption... options) throws IOException, ErrnoException {\n        return createArchiveEntry(inputPath, entryName);\n    }\n\n    // Generic implementations of OutputStream methods that may be useful to sub-classes\n\n    /**\n     * Writes a byte to the current archive entry.\n     *\n     * <p>This method simply calls {@code write( byte[], 0, 1 )}.\n     *\n     * <p>MUST be overridden if the {@link #write(byte[], int, int)} method\n     * is not overridden; may be overridden otherwise.\n     *\n     * @param b The byte to be written.\n     * @throws IOException on error\n     */\n    @Override\n    public void write(final int b) throws IOException {\n        oneByte[0] = (byte) (b & BYTE_MASK);\n        write(oneByte, 0, 1);\n    }\n\n    /**\n     * Increments the counter of already written bytes.\n     * Doesn't increment if EOF has been hit ({@code written == -1}).\n     *\n     * @param written the number of bytes written\n     */\n    protected void count(final int written) {\n        count((long) written);\n    }\n\n    /**\n     * Increments the counter of already written bytes.\n     * Doesn't increment if EOF has been hit ({@code written == -1}).\n     *\n     * @param written the number of bytes written\n     * @since 1.1\n     */\n    protected void count(final long written) {\n        if (written != -1) {\n            bytesWritten = bytesWritten + written;\n        }\n    }\n\n    /**\n     * Returns the current number of bytes written to this stream.\n     * @return the number of written bytes\n     * @deprecated this method may yield wrong results for large\n     * archives, use #getBytesWritten instead\n     */\n    @Deprecated\n    public int getCount() {\n        return (int) bytesWritten;\n    }\n\n    /**\n     * Returns the current number of bytes written to this stream.\n     * @return the number of written bytes\n     * @since 1.1\n     */\n    public long getBytesWritten() {\n        return bytesWritten;\n    }\n\n    /**\n     * Whether this stream is able to write the given entry.\n     *\n     * <p>Some archive formats support variants or details that are\n     * not supported (yet).</p>\n     *\n     * @param archiveEntry\n     *            the entry to test\n     * @return This implementation always returns true.\n     * @since 1.1\n     */\n    public boolean canWriteEntryData(final ArchiveEntry archiveEntry) {\n        return true;\n    }\n}"
  },
  {
    "path": "app/src/main/java/org/apache/commons/compress/archivers/EntryStreamOffsets.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage org.apache.commons.compress.archivers;\n\n/**\n * Provides information about ArchiveEntry stream offsets.\n */\n// Copyright 2017 Zbynek Vyskovsky\npublic interface EntryStreamOffsets {\n\n    /** Special value indicating that the offset is unknown. */\n    long OFFSET_UNKNOWN = -1;\n\n    /**\n     * Gets the offset of data stream within the archive file,\n     *\n     * @return\n     *      the offset of entry data stream, {@code OFFSET_UNKNOWN} if not known.\n     */\n    long getDataOffset();\n\n    /**\n     * Indicates whether the stream is contiguous, i.e. not split among\n     * several archive parts, interspersed with control blocks, etc.\n     *\n     * @return\n     *      true if stream is contiguous, false otherwise.\n     */\n    boolean isStreamContiguous();\n}"
  },
  {
    "path": "app/src/main/java/org/apache/commons/compress/archivers/tar/TarArchiveEntry.java",
    "content": "// SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-or-later\n\npackage org.apache.commons.compress.archivers.tar;\n\nimport android.os.RemoteException;\nimport android.system.ErrnoException;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport org.apache.commons.compress.archivers.ArchiveEntry;\nimport org.apache.commons.compress.archivers.EntryStreamOffsets;\nimport org.apache.commons.compress.archivers.zip.ZipEncoding;\nimport org.apache.commons.compress.utils.ArchiveUtils;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.Date;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport io.github.muntashirakon.io.ExtendedFile;\nimport io.github.muntashirakon.io.Path;\nimport io.github.muntashirakon.io.Paths;\nimport io.github.muntashirakon.io.UidGidPair;\n\n/**\n * This class represents an entry in a Tar archive. It consists\n * of the entry's header, as well as the entry's File. Entries\n * can be instantiated in one of three ways, depending on how\n * they are to be used.\n * <p>\n * TarEntries that are created from the header bytes read from\n * an archive are instantiated with the {@link TarArchiveEntry#TarArchiveEntry(byte[])}\n * constructor. These entries will be used when extracting from\n * or listing the contents of an archive. These entries have their\n * header filled in using the header bytes. They also set the File\n * to null, since they reference an archive entry not a file.\n * <p>\n * TarEntries that are created from Files that are to be written\n * into an archive are instantiated with the {@link TarArchiveEntry#TarArchiveEntry(File)}\n * constructor.\n * These entries have their header filled in using the File's information.\n * They also keep a reference to the File for convenience when writing entries.\n * <p>\n * Finally, TarEntries can be constructed from nothing but a name.\n * This allows the programmer to construct the entry by hand, for\n * instance when only an InputStream is available for writing to\n * the archive, and the header information is constructed from\n * other information. In this case the header fields are set to\n * defaults and the File is set to null.\n *\n * <p>\n * The C structure for a Tar Entry's header is:\n * <pre>\n * struct header {\n * char name[100];     // TarConstants.NAMELEN    - offset   0\n * char mode[8];       // TarConstants.MODELEN    - offset 100\n * char uid[8];        // TarConstants.UIDLEN     - offset 108\n * char gid[8];        // TarConstants.GIDLEN     - offset 116\n * char size[12];      // TarConstants.SIZELEN    - offset 124\n * char mtime[12];     // TarConstants.MODTIMELEN - offset 136\n * char chksum[8];     // TarConstants.CHKSUMLEN  - offset 148\n * char linkflag[1];   //                         - offset 156\n * char linkname[100]; // TarConstants.NAMELEN    - offset 157\n * The following fields are only present in new-style POSIX tar archives:\n * char magic[6];      // TarConstants.MAGICLEN   - offset 257\n * char version[2];    // TarConstants.VERSIONLEN - offset 263\n * char uname[32];     // TarConstants.UNAMELEN   - offset 265\n * char gname[32];     // TarConstants.GNAMELEN   - offset 297\n * char devmajor[8];   // TarConstants.DEVLEN     - offset 329\n * char devminor[8];   // TarConstants.DEVLEN     - offset 337\n * char prefix[155];   // TarConstants.PREFIXLEN  - offset 345\n * // Used if \"name\" field is not long enough to hold the path\n * char pad[12];       // NULs                    - offset 500\n * } header;\n * All unused bytes are set to null.\n * New-style GNU tar files are slightly different from the above.\n * For values of size larger than 077777777777L (11 7s)\n * or uid and gid larger than 07777777L (7 7s)\n * the sign bit of the first byte is set, and the rest of the\n * field is the binary representation of the number.\n * See TarUtils.parseOctalOrBinary.\n * </pre>\n *\n * <p>\n * The C structure for a old GNU Tar Entry's header is:\n * <pre>\n * struct oldgnu_header {\n * char unused_pad1[345]; // TarConstants.PAD1LEN_GNU       - offset 0\n * char atime[12];        // TarConstants.ATIMELEN_GNU      - offset 345\n * char ctime[12];        // TarConstants.CTIMELEN_GNU      - offset 357\n * char offset[12];       // TarConstants.OFFSETLEN_GNU     - offset 369\n * char longnames[4];     // TarConstants.LONGNAMESLEN_GNU  - offset 381\n * char unused_pad2;      // TarConstants.PAD2LEN_GNU       - offset 385\n * struct sparse sp[4];   // TarConstants.SPARSELEN_GNU     - offset 386\n * char isextended;       // TarConstants.ISEXTENDEDLEN_GNU - offset 482\n * char realsize[12];     // TarConstants.REALSIZELEN_GNU   - offset 483\n * char unused_pad[17];   // TarConstants.PAD3LEN_GNU       - offset 495\n * };\n * </pre>\n * Whereas, \"struct sparse\" is:\n * <pre>\n * struct sparse {\n * char offset[12];   // offset 0\n * char numbytes[12]; // offset 12\n * };\n * </pre>\n *\n * <p>\n * The C structure for a xstar (Jörg Schilling star) Tar Entry's header is:\n * <pre>\n * struct star_header {\n *  char name[100];\t\t// offset   0\n *  char mode[8];\t\t// offset 100\n *  char uid[8];\t\t// offset 108\n *  char gid[8];\t\t// offset 116\n *  char size[12];\t\t// offset 124\n *  char mtime[12];\t\t// offset 136\n *  char chksum[8];\t\t// offset 148\n *  char typeflag;\t\t// offset 156\n *  char linkname[100];\t\t// offset 157\n *  char magic[6];\t\t// offset 257\n *  char version[2];\t\t// offset 263\n *  char uname[32];\t\t// offset 265\n *  char gname[32];\t\t// offset 297\n *  char devmajor[8];\t\t// offset 329\n *  char devminor[8];\t\t// offset 337\n *  char prefix[131];\t\t// offset 345\n *  char atime[12];             // offset 476\n *  char ctime[12];             // offset 488\n *  char mfill[8];              // offset 500\n *  char xmagic[4];             // offset 508  \"tar\"\n * };\n * </pre>\n * <p>which is identical to new-style POSIX up to the first 130 bytes of the prefix.</p>\n *\n * @NotThreadSafe\n */\n// Copyright 2008 Torsten Curdt\npublic class TarArchiveEntry implements ArchiveEntry, TarConstants, EntryStreamOffsets {\n    private static final TarArchiveEntry[] EMPTY_TAR_ARCHIVE_ENTRY_ARRAY = new TarArchiveEntry[0];\n\n    /**\n     * Value used to indicate unknown mode, user/groupids, device numbers and modTime when parsing a file in lenient\n     * mode an the archive contains illegal fields.\n     *\n     * @since 1.19\n     */\n    public static final long UNKNOWN = -1L;\n\n    /**\n     * The entry's name.\n     */\n    private String name = \"\";\n\n    /**\n     * Whether to allow leading slashes or drive names inside the name\n     */\n    private final boolean preserveAbsolutePath;\n\n    /**\n     * The entry's permission mode.\n     */\n    private int mode;\n\n    /**\n     * The entry's user id.\n     */\n    private long userId = 0;\n\n    /**\n     * The entry's group id.\n     */\n    private long groupId = 0;\n\n    /**\n     * The entry's size.\n     */\n    private long size = 0;\n\n    /**\n     * The entry's modification time.\n     */\n    private long modTime;\n\n    /**\n     * If the header checksum is reasonably correct.\n     */\n    private boolean checkSumOK;\n\n    /**\n     * The entry's link flag.\n     */\n    private byte linkFlag;\n\n    /**\n     * The entry's link name.\n     */\n    private String linkName = \"\";\n\n    /**\n     * The entry's magic tag.\n     */\n    private String magic = MAGIC_POSIX;\n    /**\n     * The version of the format\n     */\n    private String version = VERSION_POSIX;\n\n    /**\n     * The entry's user name.\n     */\n    private String userName;\n\n    /**\n     * The entry's group name.\n     */\n    private String groupName = \"\";\n\n    /**\n     * The entry's major device number.\n     */\n    private int devMajor = 0;\n\n    /**\n     * The entry's minor device number.\n     */\n    private int devMinor = 0;\n\n    /**\n     * The sparse headers in tar\n     */\n    private List<TarArchiveStructSparse> sparseHeaders;\n\n    /**\n     * If an extension sparse header follows.\n     */\n    private boolean isExtended;\n\n    /**\n     * The entry's real size in case of a sparse file.\n     */\n    private long realSize;\n\n    /**\n     * is this entry a GNU sparse entry using one of the PAX formats?\n     */\n    private boolean paxGNUSparse;\n\n    /**\n     * is this entry a GNU sparse entry using 1.X PAX formats?\n     * the sparse headers of 1.x PAX Format is stored in file data block\n     */\n    private boolean paxGNU1XSparse = false;\n\n    /**\n     * is this entry a star sparse entry using the PAX header?\n     */\n    private boolean starSparse;\n\n    /**\n     * The entry's file reference\n     */\n    @Nullable\n    private final File file;\n\n    /**\n     * The entry's file reference\n     */\n    @Nullable\n    private final Path path;\n\n    /**\n     * Extra, user supplied pax headers\n     */\n    private final Map<String, String> extraPaxHeaders = new HashMap<>();\n\n    /**\n     * Maximum length of a user's name in the tar file\n     */\n    public static final int MAX_NAMELEN = 31;\n\n    /**\n     * Default permissions bits for directories\n     */\n    public static final int DEFAULT_DIR_MODE = 040755;\n\n    /**\n     * Default permissions bits for files\n     */\n    public static final int DEFAULT_FILE_MODE = 0100644;\n\n    /**\n     * Convert millis to seconds\n     */\n    public static final int MILLIS_PER_SECOND = 1000;\n\n    private long dataOffset = EntryStreamOffsets.OFFSET_UNKNOWN;\n\n    /**\n     * Construct an empty entry and prepares the header values.\n     */\n    private TarArchiveEntry(final boolean preserveAbsolutePath) {\n        String user = System.getProperty(\"user.name\", \"\");\n\n        if (user.length() > MAX_NAMELEN) {\n            user = user.substring(0, MAX_NAMELEN);\n        }\n\n        this.userName = user;\n        this.file = null;\n        this.path = null;\n        this.preserveAbsolutePath = preserveAbsolutePath;\n    }\n\n    /**\n     * Construct an entry with only a name. This allows the programmer\n     * to construct the entry's header \"by hand\". File is set to null.\n     *\n     * <p>The entry's name will be the value of the {@code name}\n     * argument with all file separators replaced by forward slashes\n     * and leading slashes as well as Windows drive letters stripped.</p>\n     *\n     * @param name the entry name\n     */\n    public TarArchiveEntry(final String name) {\n        this(name, false);\n    }\n\n    /**\n     * Construct an entry with only a name. This allows the programmer\n     * to construct the entry's header \"by hand\". File is set to null.\n     *\n     * <p>The entry's name will be the value of the {@code name}\n     * argument with all file separators replaced by forward slashes.\n     * Leading slashes and Windows drive letters are stripped if\n     * {@code preserveAbsolutePath} is {@code false}.</p>\n     *\n     * @param name                 the entry name\n     * @param preserveAbsolutePath whether to allow leading slashes\n     *                             or drive letters in the name.\n     * @since 1.1\n     */\n    public TarArchiveEntry(String name, final boolean preserveAbsolutePath) {\n        this(preserveAbsolutePath);\n\n        name = normalizeFileName(name, preserveAbsolutePath);\n        final boolean isDir = name.endsWith(\"/\");\n\n        this.name = name;\n        this.mode = isDir ? DEFAULT_DIR_MODE : DEFAULT_FILE_MODE;\n        this.linkFlag = isDir ? LF_DIR : LF_NORMAL;\n        this.modTime = System.currentTimeMillis() / MILLIS_PER_SECOND;\n        this.userName = \"\";\n    }\n\n    /**\n     * Construct an entry with a name and a link flag.\n     *\n     * <p>The entry's name will be the value of the {@code name}\n     * argument with all file separators replaced by forward slashes\n     * and leading slashes as well as Windows drive letters\n     * stripped.</p>\n     *\n     * @param name     the entry name\n     * @param linkFlag the entry link flag.\n     */\n    public TarArchiveEntry(final String name, final byte linkFlag) {\n        this(name, linkFlag, false);\n    }\n\n    /**\n     * Construct an entry with a name and a link flag.\n     *\n     * <p>The entry's name will be the value of the {@code name}\n     * argument with all file separators replaced by forward slashes.\n     * Leading slashes and Windows drive letters are stripped if\n     * {@code preserveAbsolutePath} is {@code false}.</p>\n     *\n     * @param name                 the entry name\n     * @param linkFlag             the entry link flag.\n     * @param preserveAbsolutePath whether to allow leading slashes\n     *                             or drive letters in the name.\n     * @since 1.5\n     */\n    public TarArchiveEntry(final String name, final byte linkFlag, final boolean preserveAbsolutePath) {\n        this(name, preserveAbsolutePath);\n        this.linkFlag = linkFlag;\n        if (linkFlag == LF_GNUTYPE_LONGNAME) {\n            magic = MAGIC_GNU;\n            version = VERSION_GNU_SPACE;\n        }\n    }\n\n    /**\n     * Construct an entry for a file. File is set to file, and the\n     * header is constructed from information from the file.\n     * The name is set from the normalized file path.\n     *\n     * <p>The entry's name will be the value of the {@code file}'s\n     * path with all file separators replaced by forward slashes and\n     * leading slashes as well as Windows drive letters stripped. The\n     * name will end in a slash if the {@code file} represents a\n     * directory.</p>\n     *\n     * @param file The file that the entry represents.\n     */\n    public TarArchiveEntry(final File file) {\n        this(file, file.getPath());\n    }\n\n    /**\n     * Construct an entry for a file. File is set to file, and the\n     * header is constructed from information from the file.\n     *\n     * <p>The entry's name will be the value of the {@code fileName}\n     * argument with all file separators replaced by forward slashes\n     * and leading slashes as well as Windows drive letters stripped.\n     * The name will end in a slash if the {@code file} represents a\n     * directory.</p>\n     *\n     * @param file     The file that the entry represents.\n     * @param fileName the name to be used for the entry.\n     */\n    public TarArchiveEntry(final File file, final String fileName) {\n        this(Paths.get(file), fileName);\n    }\n\n    /**\n     * Construct an entry for a file. File is set to file, and the\n     * header is constructed from information from the file.\n     *\n     * <p>The entry's name will be the value of the {@code fileName}\n     * argument with all file separators replaced by forward slashes\n     * and leading slashes as well as Windows drive letters stripped.\n     * The name will end in a slash if the {@code file} represents a\n     * directory.</p>\n     *\n     * @param file     The file that the entry represents.\n     * @param fileName the name to be used for the entry.\n     */\n    public TarArchiveEntry(@NonNull final Path file, final String fileName) {\n        final String normalizedName = normalizeFileName(fileName, false);\n        this.path = file;\n        this.file = null;\n        try {\n            readFileMode(file, normalizedName);\n        } catch (final IOException | ErrnoException | RemoteException e) {\n            if (!file.isDirectory()) {\n                this.size = file.length();\n            }\n            this.modTime = file.lastModified() / MILLIS_PER_SECOND;\n        }\n        this.userName = \"\";\n        preserveAbsolutePath = false;\n    }\n\n    private void readFileMode(@NonNull final Path file, final String normalizedName)\n            throws IOException, ErrnoException, RemoteException {\n        if (file.isDirectory()) {\n            this.linkFlag = LF_DIR;\n            final int nameLength = normalizedName.length();\n            if (nameLength == 0 || normalizedName.charAt(nameLength - 1) != '/') {\n                this.name = normalizedName + \"/\";\n            } else {\n                this.name = normalizedName;\n            }\n        } else {\n            this.linkFlag = LF_NORMAL;\n            this.name = normalizedName;\n            this.size = file.length();\n        }\n        // Setup file attributes\n        ExtendedFile f = file.getFile();\n        if (f != null) {\n            this.mode = f.getMode();\n            UidGidPair p = f.getUidGid();\n            this.userId = p.uid;\n            this.groupId = p.gid;\n        }\n        this.modTime = file.lastModified() / MILLIS_PER_SECOND;\n    }\n\n    /**\n     * Construct an entry from an archive's header bytes. File is set\n     * to null.\n     *\n     * @param headerBuf The header bytes from a tar archive entry.\n     * @throws IllegalArgumentException if any of the numeric fields have an invalid format\n     */\n    public TarArchiveEntry(final byte[] headerBuf) {\n        this(false);\n        parseTarHeader(headerBuf);\n    }\n\n    /**\n     * Construct an entry from an archive's header bytes. File is set\n     * to null.\n     *\n     * @param headerBuf The header bytes from a tar archive entry.\n     * @param encoding  encoding to use for file names\n     * @throws IllegalArgumentException if any of the numeric fields have an invalid format\n     * @throws IOException              on error\n     * @since 1.4\n     */\n    public TarArchiveEntry(final byte[] headerBuf, final ZipEncoding encoding)\n            throws IOException {\n        this(headerBuf, encoding, false);\n    }\n\n    /**\n     * Construct an entry from an archive's header bytes. File is set\n     * to null.\n     *\n     * @param headerBuf The header bytes from a tar archive entry.\n     * @param encoding  encoding to use for file names\n     * @param lenient   when set to true illegal values for group/userid, mode, device numbers and timestamp will be\n     *                  ignored and the fields set to {@link #UNKNOWN}. When set to false such illegal fields cause an exception instead.\n     * @throws IllegalArgumentException if any of the numeric fields have an invalid format\n     * @throws IOException              on error\n     * @since 1.19\n     */\n    public TarArchiveEntry(final byte[] headerBuf, final ZipEncoding encoding, final boolean lenient)\n            throws IOException {\n        this(false);\n        parseTarHeader(headerBuf, encoding, false, lenient);\n    }\n\n    /**\n     * Construct an entry from an archive's header bytes for random access tar. File is set to null.\n     *\n     * @param headerBuf  the header bytes from a tar archive entry.\n     * @param encoding   encoding to use for file names.\n     * @param lenient    when set to true illegal values for group/userid, mode, device numbers and timestamp will be\n     *                   ignored and the fields set to {@link #UNKNOWN}. When set to false such illegal fields cause an exception instead.\n     * @param dataOffset position of the entry data in the random access file.\n     * @throws IllegalArgumentException if any of the numeric fields have an invalid format.\n     * @throws IOException              on error.\n     * @since 1.21\n     */\n    public TarArchiveEntry(final byte[] headerBuf, final ZipEncoding encoding, final boolean lenient,\n                           final long dataOffset) throws IOException {\n        this(headerBuf, encoding, lenient);\n        setDataOffset(dataOffset);\n    }\n\n    /**\n     * Determine if the two entries are equal. Equality is determined\n     * by the header names being equal.\n     *\n     * @param it Entry to be checked for equality.\n     * @return True if the entries are equal.\n     */\n    public boolean equals(final TarArchiveEntry it) {\n        return it != null && getName().equals(it.getName());\n    }\n\n    /**\n     * Determine if the two entries are equal. Equality is determined\n     * by the header names being equal.\n     *\n     * @param it Entry to be checked for equality.\n     * @return True if the entries are equal.\n     */\n    @Override\n    public boolean equals(final Object it) {\n        if (it == null || getClass() != it.getClass()) {\n            return false;\n        }\n        return equals((TarArchiveEntry) it);\n    }\n\n    /**\n     * Hashcodes are based on entry names.\n     *\n     * @return the entry hashcode\n     */\n    @Override\n    public int hashCode() {\n        return getName().hashCode();\n    }\n\n    /**\n     * Determine if the given entry is a descendant of this entry.\n     * Descendancy is determined by the name of the descendant\n     * starting with this entry's name.\n     *\n     * @param desc Entry to be checked as a descendent of this.\n     * @return True if entry is a descendant of this.\n     */\n    public boolean isDescendent(final TarArchiveEntry desc) {\n        return desc.getName().startsWith(getName());\n    }\n\n    /**\n     * Get this entry's name.\n     *\n     * <p>This method returns the raw name as it is stored inside of the archive.</p>\n     *\n     * @return This entry's name.\n     */\n    @Override\n    public String getName() {\n        return name;\n    }\n\n    /**\n     * Set this entry's name.\n     *\n     * @param name This entry's new name.\n     */\n    public void setName(final String name) {\n        this.name = normalizeFileName(name, this.preserveAbsolutePath);\n    }\n\n    /**\n     * Set the mode for this entry\n     *\n     * @param mode the mode for this entry\n     */\n    public void setMode(final int mode) {\n        this.mode = mode;\n    }\n\n    /**\n     * Get this entry's link name.\n     *\n     * @return This entry's link name.\n     */\n    public String getLinkName() {\n        return linkName;\n    }\n\n    /**\n     * Set this entry's link name.\n     *\n     * @param link the link name to use.\n     *\n     * @since 1.1\n     */\n    public void setLinkName(final String link) {\n        this.linkName = link;\n    }\n\n    /**\n     * Get this entry's user id. On Android, it's always less than {@link Integer#MAX_VALUE}.\n     *\n     * @return This entry's user id.\n     */\n    public int getUserId() {\n        return (int) userId;\n    }\n\n    /**\n     * Set this entry's user id.\n     *\n     * @param userId This entry's new user id.\n     */\n    public void setUserId(final int userId) {\n        setUserId((long) userId);\n    }\n\n    /**\n     * Get this entry's user id.\n     *\n     * @return This entry's user id.\n     * @since 1.10\n     */\n    public long getLongUserId() {\n        return userId;\n    }\n\n    /**\n     * Set this entry's user id.\n     *\n     * @param userId This entry's new user id.\n     * @since 1.10\n     */\n    public void setUserId(final long userId) {\n        this.userId = userId;\n    }\n\n    /**\n     * Get this entry's group id. On Android, it's always less than {@link Integer#MAX_VALUE}.\n     *\n     * @return This entry's group id.\n     */\n    public int getGroupId() {\n        return (int) groupId;\n    }\n\n    /**\n     * Set this entry's group id.\n     *\n     * @param groupId This entry's new group id.\n     */\n    public void setGroupId(final int groupId) {\n        setGroupId((long) groupId);\n    }\n\n    /**\n     * Get this entry's group id.\n     *\n     * @return This entry's group id.\n     * @since 1.10\n     */\n    public long getLongGroupId() {\n        return groupId;\n    }\n\n    /**\n     * Set this entry's group id.\n     *\n     * @param groupId This entry's new group id.\n     * @since 1.10\n     */\n    public void setGroupId(final long groupId) {\n        this.groupId = groupId;\n    }\n\n    /**\n     * Get this entry's user name.\n     *\n     * @return This entry's user name.\n     */\n    public String getUserName() {\n        return userName;\n    }\n\n    /**\n     * Set this entry's user name.\n     *\n     * @param userName This entry's new user name.\n     */\n    public void setUserName(final String userName) {\n        this.userName = userName;\n    }\n\n    /**\n     * Get this entry's group name.\n     *\n     * @return This entry's group name.\n     */\n    public String getGroupName() {\n        return groupName;\n    }\n\n    /**\n     * Set this entry's group name.\n     *\n     * @param groupName This entry's new group name.\n     */\n    public void setGroupName(final String groupName) {\n        this.groupName = groupName;\n    }\n\n    /**\n     * Convenience method to set this entry's group and user ids.\n     *\n     * @param userId  This entry's new user id.\n     * @param groupId This entry's new group id.\n     */\n    public void setIds(final int userId, final int groupId) {\n        setUserId(userId);\n        setGroupId(groupId);\n    }\n\n    /**\n     * Convenience method to set this entry's group and user names.\n     *\n     * @param userName  This entry's new user name.\n     * @param groupName This entry's new group name.\n     */\n    public void setNames(final String userName, final String groupName) {\n        setUserName(userName);\n        setGroupName(groupName);\n    }\n\n    /**\n     * Set this entry's modification time. The parameter passed\n     * to this method is in \"Java time\".\n     *\n     * @param time This entry's new modification time.\n     */\n    public void setModTime(final long time) {\n        modTime = time / MILLIS_PER_SECOND;\n    }\n\n    /**\n     * Set this entry's modification time.\n     *\n     * @param time This entry's new modification time.\n     */\n    public void setModTime(final Date time) {\n        modTime = time.getTime() / MILLIS_PER_SECOND;\n    }\n\n    /**\n     * Get this entry's modification time.\n     *\n     * @return This entry's modification time.\n     */\n    public Date getModTime() {\n        return new Date(modTime * MILLIS_PER_SECOND);\n    }\n\n    @Override\n    public Date getLastModifiedDate() {\n        return getModTime();\n    }\n\n    /**\n     * Get this entry's checksum status.\n     *\n     * @return if the header checksum is reasonably correct\n     * @see TarUtils#verifyCheckSum(byte[])\n     * @since 1.5\n     */\n    public boolean isCheckSumOK() {\n        return checkSumOK;\n    }\n\n    /**\n     * Get this entry's file.\n     *\n     * <p>This method is only useful for entries created from a {@code\n     * File} or {@code Path} but not for entries read from an archive.</p>\n     *\n     * @return this entry's file or null if the entry was not created from a file.\n     */\n    @Nullable\n    public File getFile() {\n        return file;\n    }\n\n    /**\n     * Get this entry's path.\n     *\n     * <p>This method is only useful for entries created from a {@link\n     * File} or {@link Path} but not for entries read from an archive.</p>\n     *\n     * @return this entry's file or null if the entry was not created from a file.\n     */\n    @Nullable\n    public Path getPath() {\n        return path;\n    }\n\n    /**\n     * Get this entry's mode.\n     *\n     * @return This entry's mode.\n     */\n    public int getMode() {\n        return mode;\n    }\n\n    /**\n     * Get this entry's file size.\n     *\n     * @return This entry's file size.\n     */\n    @Override\n    public long getSize() {\n        return size;\n    }\n\n    /**\n     * Set this entry's sparse headers\n     *\n     * @param sparseHeaders The new sparse headers\n     * @since 1.20\n     */\n    public void setSparseHeaders(final List<TarArchiveStructSparse> sparseHeaders) {\n        this.sparseHeaders = sparseHeaders;\n    }\n\n    /**\n     * Get this entry's sparse headers\n     *\n     * @return This entry's sparse headers\n     * @since 1.20\n     */\n    public List<TarArchiveStructSparse> getSparseHeaders() {\n        return sparseHeaders;\n    }\n\n    /**\n     * Get if this entry is a sparse file with 1.X PAX Format or not\n     *\n     * @return True if this entry is a sparse file with 1.X PAX Format\n     * @since 1.20\n     */\n    public boolean isPaxGNU1XSparse() {\n        return paxGNU1XSparse;\n    }\n\n    /**\n     * Set this entry's file size.\n     *\n     * @param size This entry's new file size.\n     * @throws IllegalArgumentException if the size is &lt; 0.\n     */\n    public void setSize(final long size) {\n        if (size < 0) {\n            throw new IllegalArgumentException(\"Size is out of range: \" + size);\n        }\n        this.size = size;\n    }\n\n    /**\n     * Get this entry's major device number.\n     *\n     * @return This entry's major device number.\n     * @since 1.4\n     */\n    public int getDevMajor() {\n        return devMajor;\n    }\n\n    /**\n     * Set this entry's major device number.\n     *\n     * @param devNo This entry's major device number.\n     * @throws IllegalArgumentException if the devNo is &lt; 0.\n     * @since 1.4\n     */\n    public void setDevMajor(final int devNo) {\n        if (devNo < 0) {\n            throw new IllegalArgumentException(\"Major device number is out of \" + \"range: \" + devNo);\n        }\n        this.devMajor = devNo;\n    }\n\n    /**\n     * Get this entry's minor device number.\n     *\n     * @return This entry's minor device number.\n     * @since 1.4\n     */\n    public int getDevMinor() {\n        return devMinor;\n    }\n\n    /**\n     * Set this entry's minor device number.\n     *\n     * @param devNo This entry's minor device number.\n     * @throws IllegalArgumentException if the devNo is &lt; 0.\n     * @since 1.4\n     */\n    public void setDevMinor(final int devNo) {\n        if (devNo < 0) {\n            throw new IllegalArgumentException(\"Minor device number is out of \" + \"range: \" + devNo);\n        }\n        this.devMinor = devNo;\n    }\n\n    /**\n     * Indicates in case of an oldgnu sparse file if an extension\n     * sparse header follows.\n     *\n     * @return true if an extension oldgnu sparse header follows.\n     */\n    public boolean isExtended() {\n        return isExtended;\n    }\n\n    /**\n     * Get this entry's real file size in case of a sparse file.\n     * <p>If the file is not a sparse file, return size instead of realSize.</p>\n     *\n     * @return This entry's real file size, if the file is not a sparse file, return size instead of realSize.\n     */\n    public long getRealSize() {\n        if (!isSparse()) {\n            return size;\n        }\n        return realSize;\n    }\n\n    /**\n     * Indicate if this entry is a GNU sparse block.\n     *\n     * @return true if this is a sparse extension provided by GNU tar\n     */\n    public boolean isGNUSparse() {\n        return isOldGNUSparse() || isPaxGNUSparse();\n    }\n\n    /**\n     * Indicate if this entry is a GNU or star sparse block using the\n     * oldgnu format.\n     *\n     * @return true if this is a sparse extension provided by GNU tar or star\n     * @since 1.11\n     */\n    public boolean isOldGNUSparse() {\n        return linkFlag == LF_GNUTYPE_SPARSE;\n    }\n\n    /**\n     * Indicate if this entry is a GNU sparse block using one of the\n     * PAX formats.\n     *\n     * @return true if this is a sparse extension provided by GNU tar\n     * @since 1.11\n     */\n    public boolean isPaxGNUSparse() {\n        return paxGNUSparse;\n    }\n\n    /**\n     * Indicate if this entry is a star sparse block using PAX headers.\n     *\n     * @return true if this is a sparse extension provided by star\n     * @since 1.11\n     */\n    public boolean isStarSparse() {\n        return starSparse;\n    }\n\n    /**\n     * Indicate if this entry is a GNU long linkname block\n     *\n     * @return true if this is a long name extension provided by GNU tar\n     */\n    public boolean isGNULongLinkEntry() {\n        return linkFlag == LF_GNUTYPE_LONGLINK;\n    }\n\n    /**\n     * Indicate if this entry is a GNU long name block\n     *\n     * @return true if this is a long name extension provided by GNU tar\n     */\n    public boolean isGNULongNameEntry() {\n        return linkFlag == LF_GNUTYPE_LONGNAME;\n    }\n\n    /**\n     * Check if this is a Pax header.\n     *\n     * @return {@code true} if this is a Pax header.\n     * @since 1.1\n     */\n    public boolean isPaxHeader() {\n        return linkFlag == LF_PAX_EXTENDED_HEADER_LC\n                || linkFlag == LF_PAX_EXTENDED_HEADER_UC;\n    }\n\n    /**\n     * Check if this is a Pax header.\n     *\n     * @return {@code true} if this is a Pax header.\n     * @since 1.1\n     */\n    public boolean isGlobalPaxHeader() {\n        return linkFlag == LF_PAX_GLOBAL_EXTENDED_HEADER;\n    }\n\n    /**\n     * Return whether or not this entry represents a directory.\n     *\n     * @return True if this entry is a directory.\n     */\n    @Override\n    public boolean isDirectory() {\n        if (file != null) {\n            return file.isDirectory();\n        }\n\n        if (path != null) {\n            return path.isDirectory();\n        }\n\n        if (linkFlag == LF_DIR) {\n            return true;\n        }\n\n        return !isPaxHeader() && !isGlobalPaxHeader() && getName().endsWith(\"/\");\n    }\n\n    /**\n     * Check if this is a \"normal file\"\n     *\n     * @return whether this is a \"normal file\"\n     * @since 1.2\n     */\n    public boolean isFile() {\n        if (file != null) {\n            return file.isFile();\n        }\n        if (path != null) {\n            return path.isFile();\n        }\n        if (linkFlag == LF_OLDNORM || linkFlag == LF_NORMAL) {\n            return true;\n        }\n        return !getName().endsWith(\"/\");\n    }\n\n    /**\n     * Check if this is a symbolic link entry.\n     *\n     * @return whether this is a symbolic link\n     * @since 1.2\n     */\n    public boolean isSymbolicLink() {\n        return linkFlag == LF_SYMLINK;\n    }\n\n    /**\n     * Check if this is a link entry.\n     *\n     * @return whether this is a link entry\n     * @since 1.2\n     */\n    public boolean isLink() {\n        return linkFlag == LF_LINK;\n    }\n\n    /**\n     * Check if this is a character device entry.\n     *\n     * @return whether this is a character device\n     * @since 1.2\n     */\n    public boolean isCharacterDevice() {\n        return linkFlag == LF_CHR;\n    }\n\n    /**\n     * Check if this is a block device entry.\n     *\n     * @return whether this is a block device\n     * @since 1.2\n     */\n    public boolean isBlockDevice() {\n        return linkFlag == LF_BLK;\n    }\n\n    /**\n     * Check if this is a FIFO (pipe) entry.\n     *\n     * @return whether this is a FIFO entry\n     * @since 1.2\n     */\n    public boolean isFIFO() {\n        return linkFlag == LF_FIFO;\n    }\n\n    /**\n     * Check whether this is a sparse entry.\n     *\n     * @return whether this is a sparse entry\n     * @since 1.11\n     */\n    public boolean isSparse() {\n        return isGNUSparse() || isStarSparse();\n    }\n\n    /**\n     * {@inheritDoc}\n     *\n     * @since 1.21\n     */\n    @Override\n    public long getDataOffset() {\n        return dataOffset;\n    }\n\n    /**\n     * Set the offset of the data for the tar entry.\n     *\n     * @param dataOffset the position of the data in the tar.\n     * @since 1.21\n     */\n    public void setDataOffset(final long dataOffset) {\n        if (dataOffset < 0) {\n            throw new IllegalArgumentException(\"The offset can not be smaller than 0\");\n        }\n        this.dataOffset = dataOffset;\n    }\n\n    /**\n     * {@inheritDoc}\n     *\n     * @since 1.21\n     */\n    @Override\n    public boolean isStreamContiguous() {\n        return true;\n    }\n\n    /**\n     * get extra PAX Headers\n     *\n     * @return read-only map containing any extra PAX Headers\n     * @since 1.15\n     */\n    public Map<String, String> getExtraPaxHeaders() {\n        return Collections.unmodifiableMap(extraPaxHeaders);\n    }\n\n    /**\n     * clear all extra PAX headers.\n     *\n     * @since 1.15\n     */\n    public void clearExtraPaxHeaders() {\n        extraPaxHeaders.clear();\n    }\n\n    /**\n     * add a PAX header to this entry. If the header corresponds to an existing field in the entry,\n     * that field will be set; otherwise the header will be added to the extraPaxHeaders Map\n     *\n     * @param name  The full name of the header to set.\n     * @param value value of header.\n     * @since 1.15\n     */\n    public void addPaxHeader(final String name, final String value) {\n        processPaxHeader(name, value);\n    }\n\n    /**\n     * get named extra PAX header\n     * @param name The full name of an extended PAX header to retrieve\n     * @return The value of the header, if any.\n     * @since 1.15\n     */\n    public String getExtraPaxHeader(final String name) {\n        return extraPaxHeaders.get(name);\n    }\n\n    /**\n     * Update the entry using a map of pax headers.\n     * @param headers\n     * @since 1.15\n     */\n    void updateEntryFromPaxHeaders(final Map<String, String> headers) {\n        for (final Map.Entry<String, String> ent : headers.entrySet()) {\n            final String key = ent.getKey();\n            final String val = ent.getValue();\n            processPaxHeader(key, val, headers);\n        }\n    }\n\n    /**\n     * process one pax header, using the entries extraPaxHeaders map as source for extra headers\n     * used when handling entries for sparse files.\n     *\n     * @since 1.15\n     */\n    private void processPaxHeader(final String key, final String val) {\n        processPaxHeader(key, val, extraPaxHeaders);\n    }\n\n    /**\n     * Process one pax header, using the supplied map as source for extra headers to be used when handling\n     * entries for sparse files\n     *\n     * @param key     the header name.\n     * @param val     the header value.\n     * @param headers map of headers used for dealing with sparse file.\n     * @throws NumberFormatException if encountered errors when parsing the numbers\n     * @since 1.15\n     */\n    private void processPaxHeader(final String key, final String val, final Map<String, String> headers) {\n        /*\n         * The following headers are defined for Pax.\n         * atime, ctime, charset: cannot use these without changing TarArchiveEntry fields\n         * mtime\n         * comment\n         * gid, gname\n         * linkpath\n         * size\n         * uid,uname\n         * SCHILY.devminor, SCHILY.devmajor: don't have setters/getters for those\n         *\n         * GNU sparse files use additional members, we use\n         * GNU.sparse.size to detect the 0.0 and 0.1 versions and\n         * GNU.sparse.realsize for 1.0.\n         *\n         * star files use additional members of which we use\n         * SCHILY.filetype in order to detect star sparse files.\n         *\n         * If called from addExtraPaxHeader, these additional headers must be already present .\n         */\n        switch (key) {\n            case \"path\":\n                setName(val);\n                break;\n            case \"linkpath\":\n                setLinkName(val);\n                break;\n            case \"gid\":\n                setGroupId(Long.parseLong(val));\n                break;\n            case \"gname\":\n                setGroupName(val);\n                break;\n            case \"uid\":\n                setUserId(Long.parseLong(val));\n                break;\n            case \"uname\":\n                setUserName(val);\n                break;\n            case \"size\":\n                setSize(Long.parseLong(val));\n                break;\n            case \"mtime\":\n                setModTime((long) (Double.parseDouble(val) * 1000));\n                break;\n            case \"SCHILY.devminor\":\n                setDevMinor(Integer.parseInt(val));\n                break;\n            case \"SCHILY.devmajor\":\n                setDevMajor(Integer.parseInt(val));\n                break;\n            case \"GNU.sparse.size\":\n                fillGNUSparse0xData(headers);\n                break;\n            case \"GNU.sparse.realsize\":\n                fillGNUSparse1xData(headers);\n                break;\n            case \"SCHILY.filetype\":\n                if (\"sparse\".equals(val)) {\n                    fillStarSparseData(headers);\n                }\n                break;\n            default:\n                extraPaxHeaders.put(key, val);\n        }\n    }\n\n\n    /**\n     * If this entry represents a file, and the file is a directory, return\n     * an array of TarEntries for this entry's children.\n     *\n     * <p>This method is only useful for entries created from a {@code\n     * File} or {@code Path} but not for entries read from an archive.</p>\n     *\n     * @return An array of TarEntry's for this entry's children.\n     */\n    public TarArchiveEntry[] getDirectoryEntries() {\n        if ((file == null && path == null) || !isDirectory()) {\n            return EMPTY_TAR_ARCHIVE_ENTRY_ARRAY;\n        }\n        if (file != null) {\n            File[] dirStream = file.listFiles();\n            if (dirStream == null) {\n                return EMPTY_TAR_ARCHIVE_ENTRY_ARRAY;\n            }\n            final List<TarArchiveEntry> entries = new ArrayList<>();\n            for (File f : dirStream) {\n                entries.add(new TarArchiveEntry(f));\n            }\n            return entries.toArray(EMPTY_TAR_ARCHIVE_ENTRY_ARRAY);\n        } else {  // path != null\n            Path[] dirStream = path.listFiles();\n            final List<TarArchiveEntry> entries = new ArrayList<>();\n            for (Path f : dirStream) {\n                entries.add(new TarArchiveEntry(f, this.name + File.separatorChar + f.getName()));\n            }\n            return entries.toArray(EMPTY_TAR_ARCHIVE_ENTRY_ARRAY);\n        }\n    }\n\n    /**\n     * Write an entry's header information to a header buffer.\n     *\n     * <p>This method does not use the star/GNU tar/BSD tar extensions.</p>\n     *\n     * @param outbuf The tar entry header buffer to fill in.\n     */\n    public void writeEntryHeader(final byte[] outbuf) {\n        try {\n            writeEntryHeader(outbuf, TarUtils.DEFAULT_ENCODING, false);\n        } catch (final IOException ex) { // NOSONAR\n            try {\n                writeEntryHeader(outbuf, TarUtils.FALLBACK_ENCODING, false);\n            } catch (final IOException ex2) {\n                // impossible\n                throw new RuntimeException(ex2); //NOSONAR\n            }\n        }\n    }\n\n    /**\n     * Write an entry's header information to a header buffer.\n     *\n     * @param outbuf   The tar entry header buffer to fill in.\n     * @param encoding encoding to use when writing the file name.\n     * @param starMode whether to use the star/GNU tar/BSD tar\n     *                 extension for numeric fields if their value doesn't fit in the\n     *                 maximum size of standard tar archives\n     * @throws IOException on error\n     * @since 1.4\n     */\n    public void writeEntryHeader(final byte[] outbuf, final ZipEncoding encoding,\n                                 final boolean starMode) throws IOException {\n        int offset = 0;\n\n        offset = TarUtils.formatNameBytes(name, outbuf, offset, NAMELEN,\n                encoding);\n        offset = writeEntryHeaderField(mode, outbuf, offset, MODELEN, starMode);\n        offset = writeEntryHeaderField(userId, outbuf, offset, UIDLEN,\n                starMode);\n        offset = writeEntryHeaderField(groupId, outbuf, offset, GIDLEN,\n                starMode);\n        offset = writeEntryHeaderField(size, outbuf, offset, SIZELEN, starMode);\n        offset = writeEntryHeaderField(modTime, outbuf, offset, MODTIMELEN,\n                starMode);\n\n        final int csOffset = offset;\n\n        for (int c = 0; c < CHKSUMLEN; ++c) {\n            outbuf[offset++] = (byte) ' ';\n        }\n\n        outbuf[offset++] = linkFlag;\n        offset = TarUtils.formatNameBytes(linkName, outbuf, offset, NAMELEN,\n                encoding);\n        offset = TarUtils.formatNameBytes(magic, outbuf, offset, MAGICLEN);\n        offset = TarUtils.formatNameBytes(version, outbuf, offset, VERSIONLEN);\n        offset = TarUtils.formatNameBytes(userName, outbuf, offset, UNAMELEN,\n                encoding);\n        offset = TarUtils.formatNameBytes(groupName, outbuf, offset, GNAMELEN,\n                encoding);\n        offset = writeEntryHeaderField(devMajor, outbuf, offset, DEVLEN,\n                starMode);\n        offset = writeEntryHeaderField(devMinor, outbuf, offset, DEVLEN,\n                starMode);\n\n        while (offset < outbuf.length) {\n            outbuf[offset++] = 0;\n        }\n\n        final long chk = TarUtils.computeCheckSum(outbuf);\n\n        TarUtils.formatCheckSumOctalBytes(chk, outbuf, csOffset, CHKSUMLEN);\n    }\n\n    private int writeEntryHeaderField(final long value, final byte[] outbuf, final int offset,\n                                      final int length, final boolean starMode) {\n        if (!starMode && (value < 0\n                || value >= 1L << 3 * (length - 1))) {\n            // value doesn't fit into field when written as octal\n            // number, will be written to PAX header or causes an\n            // error\n            return TarUtils.formatLongOctalBytes(0, outbuf, offset, length);\n        }\n        return TarUtils.formatLongOctalOrBinaryBytes(value, outbuf, offset,\n                length);\n    }\n\n    /**\n     * Parse an entry's header information from a header buffer.\n     *\n     * @param header The tar entry header buffer to get information from.\n     * @throws IllegalArgumentException if any of the numeric fields have an invalid format\n     */\n    public void parseTarHeader(final byte[] header) {\n        try {\n            parseTarHeader(header, TarUtils.DEFAULT_ENCODING);\n        } catch (final IOException ex) { // NOSONAR\n            try {\n                parseTarHeader(header, TarUtils.DEFAULT_ENCODING, true, false);\n            } catch (final IOException ex2) {\n                // not really possible\n                throw new RuntimeException(ex2); //NOSONAR\n            }\n        }\n    }\n\n    /**\n     * Parse an entry's header information from a header buffer.\n     *\n     * @param header   The tar entry header buffer to get information from.\n     * @param encoding encoding to use for file names\n     * @throws IllegalArgumentException if any of the numeric fields have an invalid format\n     * @throws IOException              on error\n     * @since 1.4\n     */\n    public void parseTarHeader(final byte[] header, final ZipEncoding encoding)\n            throws IOException {\n        parseTarHeader(header, encoding, false, false);\n    }\n\n    private void parseTarHeader(final byte[] header, final ZipEncoding encoding,\n                                final boolean oldStyle, final boolean lenient)\n            throws IOException {\n        int offset = 0;\n\n        name = oldStyle ? TarUtils.parseName(header, offset, NAMELEN)\n                : TarUtils.parseName(header, offset, NAMELEN, encoding);\n        offset += NAMELEN;\n        mode = (int) parseOctalOrBinary(header, offset, MODELEN, lenient);\n        offset += MODELEN;\n        userId = (int) parseOctalOrBinary(header, offset, UIDLEN, lenient);\n        offset += UIDLEN;\n        groupId = (int) parseOctalOrBinary(header, offset, GIDLEN, lenient);\n        offset += GIDLEN;\n        size = TarUtils.parseOctalOrBinary(header, offset, SIZELEN);\n        if (size < 0) {\n            throw new IOException(\"broken archive, entry with negative size\");\n        }\n        offset += SIZELEN;\n        modTime = parseOctalOrBinary(header, offset, MODTIMELEN, lenient);\n        offset += MODTIMELEN;\n        checkSumOK = TarUtils.verifyCheckSum(header);\n        offset += CHKSUMLEN;\n        linkFlag = header[offset++];\n        linkName = oldStyle ? TarUtils.parseName(header, offset, NAMELEN)\n                : TarUtils.parseName(header, offset, NAMELEN, encoding);\n        offset += NAMELEN;\n        magic = TarUtils.parseName(header, offset, MAGICLEN);\n        offset += MAGICLEN;\n        version = TarUtils.parseName(header, offset, VERSIONLEN);\n        offset += VERSIONLEN;\n        userName = oldStyle ? TarUtils.parseName(header, offset, UNAMELEN)\n                : TarUtils.parseName(header, offset, UNAMELEN, encoding);\n        offset += UNAMELEN;\n        groupName = oldStyle ? TarUtils.parseName(header, offset, GNAMELEN)\n                : TarUtils.parseName(header, offset, GNAMELEN, encoding);\n        offset += GNAMELEN;\n        if (linkFlag == LF_CHR || linkFlag == LF_BLK) {\n            devMajor = (int) parseOctalOrBinary(header, offset, DEVLEN, lenient);\n            offset += DEVLEN;\n            devMinor = (int) parseOctalOrBinary(header, offset, DEVLEN, lenient);\n            offset += DEVLEN;\n        } else {\n            offset += 2 * DEVLEN;\n        }\n\n        final int type = evaluateType(header);\n        switch (type) {\n            case FORMAT_OLDGNU: {\n                offset += ATIMELEN_GNU;\n                offset += CTIMELEN_GNU;\n                offset += OFFSETLEN_GNU;\n                offset += LONGNAMESLEN_GNU;\n                offset += PAD2LEN_GNU;\n                sparseHeaders = new ArrayList<>();\n                for (int i = 0; i < SPARSE_HEADERS_IN_OLDGNU_HEADER; i++) {\n                    final TarArchiveStructSparse sparseHeader = TarUtils.parseSparse(header,\n                            offset + i * (SPARSE_OFFSET_LEN + SPARSE_NUMBYTES_LEN));\n\n                    // some sparse headers are empty, we need to skip these sparse headers\n                    if (sparseHeader.getOffset() > 0 || sparseHeader.getNumbytes() > 0) {\n                        sparseHeaders.add(sparseHeader);\n                    }\n                }\n                offset += SPARSELEN_GNU;\n                isExtended = TarUtils.parseBoolean(header, offset);\n                offset += ISEXTENDEDLEN_GNU;\n                realSize = TarUtils.parseOctal(header, offset, REALSIZELEN_GNU);\n                offset += REALSIZELEN_GNU; // NOSONAR - assignment as documentation\n                break;\n            }\n            case FORMAT_XSTAR: {\n                final String xstarPrefix = oldStyle\n                        ? TarUtils.parseName(header, offset, PREFIXLEN_XSTAR)\n                        : TarUtils.parseName(header, offset, PREFIXLEN_XSTAR, encoding);\n                if (!xstarPrefix.isEmpty()) {\n                    name = xstarPrefix + \"/\" + name;\n                }\n                break;\n            }\n            case FORMAT_POSIX:\n            default: {\n                final String prefix = oldStyle\n                        ? TarUtils.parseName(header, offset, PREFIXLEN)\n                        : TarUtils.parseName(header, offset, PREFIXLEN, encoding);\n                // SunOS tar -E does not add / to directory names, so fix\n                // up to be consistent\n                if (isDirectory() && !name.endsWith(\"/\")) {\n                    name = name + \"/\";\n                }\n                if (!prefix.isEmpty()) {\n                    name = prefix + \"/\" + name;\n                }\n            }\n        }\n    }\n\n    private long parseOctalOrBinary(final byte[] header, final int offset, final int length, final boolean lenient) {\n        if (lenient) {\n            try {\n                return TarUtils.parseOctalOrBinary(header, offset, length);\n            } catch (final IllegalArgumentException ex) { //NOSONAR\n                return UNKNOWN;\n            }\n        }\n        return TarUtils.parseOctalOrBinary(header, offset, length);\n    }\n\n    /**\n     * Strips Windows' drive letter as well as any leading slashes,\n     * turns path separators into forward slahes.\n     */\n    private static String normalizeFileName(String fileName, final boolean preserveAbsolutePath) {\n        fileName = fileName.replace(File.separatorChar, '/');\n\n        // No absolute pathnames\n        // Windows (and Posix?) paths can start with \"\\\\NetworkDrive\\\",\n        // so we loop on starting /'s.\n        while (!preserveAbsolutePath && fileName.startsWith(\"/\")) {\n            fileName = fileName.substring(1);\n        }\n        return fileName;\n    }\n\n    /**\n     * Evaluate an entry's header format from a header buffer.\n     *\n     * @param header The tar entry header buffer to evaluate the format for.\n     * @return format type\n     */\n    private int evaluateType(final byte[] header) {\n        if (ArchiveUtils.matchAsciiBuffer(MAGIC_GNU, header, MAGIC_OFFSET, MAGICLEN)) {\n            return FORMAT_OLDGNU;\n        }\n        if (ArchiveUtils.matchAsciiBuffer(MAGIC_POSIX, header, MAGIC_OFFSET, MAGICLEN)) {\n            if (ArchiveUtils.matchAsciiBuffer(MAGIC_XSTAR, header, XSTAR_MAGIC_OFFSET,\n                    XSTAR_MAGIC_LEN)) {\n                return FORMAT_XSTAR;\n            }\n            return FORMAT_POSIX;\n        }\n        return 0;\n    }\n\n    void fillGNUSparse0xData(final Map<String, String> headers) {\n        paxGNUSparse = true;\n        realSize = Integer.parseInt(headers.get(\"GNU.sparse.size\"));\n        if (headers.containsKey(\"GNU.sparse.name\")) {\n            // version 0.1\n            name = headers.get(\"GNU.sparse.name\");\n        }\n    }\n\n    void fillGNUSparse1xData(final Map<String, String> headers) {\n        paxGNUSparse = true;\n        paxGNU1XSparse = true;\n        realSize = Integer.parseInt(headers.get(\"GNU.sparse.realsize\"));\n        name = headers.get(\"GNU.sparse.name\");\n    }\n\n    void fillStarSparseData(final Map<String, String> headers) {\n        starSparse = true;\n        if (headers.containsKey(\"SCHILY.realsize\")) {\n            realSize = Long.parseLong(headers.get(\"SCHILY.realsize\"));\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/main/java/org/apache/commons/compress/archivers/tar/TarArchiveInputStream.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\n/*\n * This package is based on the work done by Timothy Gerard Endres\n * (time@ice.com) to whom the Ant project is very grateful for his great code.\n */\n\npackage org.apache.commons.compress.archivers.tar;\n\nimport org.apache.commons.compress.archivers.ArchiveEntry;\nimport org.apache.commons.compress.archivers.ArchiveInputStream;\nimport org.apache.commons.compress.archivers.zip.ZipEncoding;\nimport org.apache.commons.compress.archivers.zip.ZipEncodingHelper;\nimport org.apache.commons.compress.utils.ArchiveUtils;\nimport org.apache.commons.compress.utils.BoundedInputStream;\nimport org.apache.commons.compress.utils.IOUtils;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.FileInputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.Comparator;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\n/**\n * The TarInputStream reads a UNIX tar archive as an InputStream.\n * methods are provided to position at each successive entry in\n * the archive, and the read each entry as a normal input stream\n * using read().\n * @NotThreadSafe\n */\n// Copyright 2008 Torsten Curdt\npublic class TarArchiveInputStream extends ArchiveInputStream {\n\n    private static final int SMALL_BUFFER_SIZE = 256;\n\n    private final byte[] smallBuf = new byte[SMALL_BUFFER_SIZE];\n\n    /** The size the TAR header */\n    private final int recordSize;\n\n    /** The buffer to store the TAR header **/\n    private final byte[] recordBuffer;\n\n    /** The size of a block */\n    private final int blockSize;\n\n    /** True if file has hit EOF */\n    private boolean hasHitEOF;\n\n    /** Size of the current entry */\n    private long entrySize;\n\n    /** How far into the entry the stream is at */\n    private long entryOffset;\n\n    /** An input stream to read from */\n    private final InputStream inputStream;\n\n    /** Input streams for reading sparse entries **/\n    private List<InputStream> sparseInputStreams;\n\n    /** the index of current input stream being read when reading sparse entries */\n    private int currentSparseInputStreamIndex;\n\n    /** The meta-data about the current entry */\n    private TarArchiveEntry currEntry;\n\n    /** The encoding of the file */\n    private final ZipEncoding zipEncoding;\n\n    // the provided encoding (for unit tests)\n    final String encoding;\n\n    // the global PAX header\n    private Map<String, String> globalPaxHeaders = new HashMap<>();\n\n    // the global sparse headers, this is only used in PAX Format 0.X\n    private final List<TarArchiveStructSparse> globalSparseHeaders = new ArrayList<>();\n\n    private final boolean lenient;\n\n    /**\n     * Constructor for TarInputStream.\n     * @param is the input stream to use\n     */\n    public TarArchiveInputStream(final InputStream is) {\n        this(is, TarConstants.DEFAULT_BLKSIZE, TarConstants.DEFAULT_RCDSIZE);\n    }\n\n    /**\n     * Constructor for TarInputStream.\n     * @param is the input stream to use\n     * @param lenient when set to true illegal values for group/userid, mode, device numbers and timestamp will be\n     * ignored and the fields set to {@link TarArchiveEntry#UNKNOWN}. When set to false such illegal fields cause an\n     * exception instead.\n     * @since 1.19\n     */\n    public TarArchiveInputStream(final InputStream is, final boolean lenient) {\n        this(is, TarConstants.DEFAULT_BLKSIZE, TarConstants.DEFAULT_RCDSIZE, null, lenient);\n    }\n\n    /**\n     * Constructor for TarInputStream.\n     * @param is the input stream to use\n     * @param encoding name of the encoding to use for file names\n     * @since 1.4\n     */\n    public TarArchiveInputStream(final InputStream is, final String encoding) {\n        this(is, TarConstants.DEFAULT_BLKSIZE, TarConstants.DEFAULT_RCDSIZE,\n             encoding);\n    }\n\n    /**\n     * Constructor for TarInputStream.\n     * @param is the input stream to use\n     * @param blockSize the block size to use\n     */\n    public TarArchiveInputStream(final InputStream is, final int blockSize) {\n        this(is, blockSize, TarConstants.DEFAULT_RCDSIZE);\n    }\n\n    /**\n     * Constructor for TarInputStream.\n     * @param is the input stream to use\n     * @param blockSize the block size to use\n     * @param encoding name of the encoding to use for file names\n     * @since 1.4\n     */\n    public TarArchiveInputStream(final InputStream is, final int blockSize,\n                                 final String encoding) {\n        this(is, blockSize, TarConstants.DEFAULT_RCDSIZE, encoding);\n    }\n\n    /**\n     * Constructor for TarInputStream.\n     * @param is the input stream to use\n     * @param blockSize the block size to use\n     * @param recordSize the record size to use\n     */\n    public TarArchiveInputStream(final InputStream is, final int blockSize, final int recordSize) {\n        this(is, blockSize, recordSize, null);\n    }\n\n    /**\n     * Constructor for TarInputStream.\n     * @param is the input stream to use\n     * @param blockSize the block size to use\n     * @param recordSize the record size to use\n     * @param encoding name of the encoding to use for file names\n     * @since 1.4\n     */\n    public TarArchiveInputStream(final InputStream is, final int blockSize, final int recordSize,\n                                 final String encoding) {\n        this(is, blockSize, recordSize, encoding, false);\n    }\n\n    /**\n     * Constructor for TarInputStream.\n     * @param is the input stream to use\n     * @param blockSize the block size to use\n     * @param recordSize the record size to use\n     * @param encoding name of the encoding to use for file names\n     * @param lenient when set to true illegal values for group/userid, mode, device numbers and timestamp will be\n     * ignored and the fields set to {@link TarArchiveEntry#UNKNOWN}. When set to false such illegal fields cause an\n     * exception instead.\n     * @since 1.19\n     */\n    public TarArchiveInputStream(final InputStream is, final int blockSize, final int recordSize,\n                                 final String encoding, final boolean lenient) {\n        this.inputStream = is;\n        this.hasHitEOF = false;\n        this.encoding = encoding;\n        this.zipEncoding = ZipEncodingHelper.getZipEncoding(encoding);\n        this.recordSize = recordSize;\n        this.recordBuffer = new byte[recordSize];\n        this.blockSize = blockSize;\n        this.lenient = lenient;\n    }\n\n    /**\n     * Closes this stream. Calls the TarBuffer's close() method.\n     * @throws IOException on error\n     */\n    @Override\n    public void close() throws IOException {\n        // Close all the input streams in sparseInputStreams\n        if(sparseInputStreams != null) {\n            for (final InputStream inputStream : sparseInputStreams) {\n                inputStream.close();\n            }\n        }\n\n        inputStream.close();\n    }\n\n    /**\n     * Get the record size being used by this stream's buffer.\n     *\n     * @return The TarBuffer record size.\n     */\n    public int getRecordSize() {\n        return recordSize;\n    }\n\n    /**\n     * Get the available data that can be read from the current\n     * entry in the archive. This does not indicate how much data\n     * is left in the entire archive, only in the current entry.\n     * This value is determined from the entry's size header field\n     * and the amount of data already read from the current entry.\n     * Integer.MAX_VALUE is returned in case more than Integer.MAX_VALUE\n     * bytes are left in the current entry in the archive.\n     *\n     * @return The number of available bytes for the current entry.\n     * @throws IOException for signature\n     */\n    @Override\n    public int available() throws IOException {\n        if (isDirectory()) {\n            return 0;\n        }\n\n        if (currEntry.getRealSize() - entryOffset > Integer.MAX_VALUE) {\n            return Integer.MAX_VALUE;\n        }\n        return (int) (currEntry.getRealSize() - entryOffset);\n    }\n\n\n    /**\n     * Skips over and discards <code>n</code> bytes of data from this input\n     * stream. The <code>skip</code> method may, for a variety of reasons, end\n     * up skipping over some smaller number of bytes, possibly <code>0</code>.\n     * This may result from any of a number of conditions; reaching end of file\n     * or end of entry before <code>n</code> bytes have been skipped; are only\n     * two possibilities. The actual number of bytes skipped is returned. If\n     * <code>n</code> is negative, no bytes are skipped.\n     *\n     *\n     * @param n\n     *            the number of bytes to be skipped.\n     * @return the actual number of bytes skipped.\n     * @throws IOException if a truncated tar archive is detected\n     *                     or some other I/O error occurs\n     */\n    @Override\n    public long skip(final long n) throws IOException {\n        if (n <= 0 || isDirectory()) {\n            return 0;\n        }\n\n        final long availableOfInputStream = inputStream.available();\n        final long available = currEntry.getRealSize() - entryOffset;\n        final long numToSkip = Math.min(n, available);\n        long skipped;\n\n        if (!currEntry.isSparse()) {\n            skipped = IOUtils.skip(inputStream, numToSkip);\n            // for non-sparse entry, we should get the bytes actually skipped bytes along with\n            // inputStream.available() if inputStream is instance of FileInputStream\n            skipped = getActuallySkipped(availableOfInputStream, skipped, numToSkip);\n        } else {\n            skipped = skipSparse(numToSkip);\n        }\n\n\n        count(skipped);\n        entryOffset += skipped;\n        return skipped;\n    }\n\n    /**\n     * Skip n bytes from current input stream, if the current input stream doesn't have enough data to skip,\n     * jump to the next input stream and skip the rest bytes, keep doing this until total n bytes are skipped\n     * or the input streams are all skipped\n     *\n     * @param n bytes of data to skip\n     * @return actual bytes of data skipped\n     * @throws IOException\n     */\n    private long skipSparse(final long n) throws IOException {\n        if (sparseInputStreams == null || sparseInputStreams.isEmpty()) {\n            return inputStream.skip(n);\n        }\n\n        long bytesSkipped = 0;\n\n        while (bytesSkipped < n && currentSparseInputStreamIndex < sparseInputStreams.size()) {\n            final InputStream  currentInputStream = sparseInputStreams.get(currentSparseInputStreamIndex);\n            bytesSkipped += currentInputStream.skip(n - bytesSkipped);\n\n            if (bytesSkipped < n) {\n                currentSparseInputStreamIndex++;\n            }\n        }\n\n        return bytesSkipped;\n    }\n\n    /**\n     * Since we do not support marking just yet, we return false.\n     *\n     * @return False.\n     */\n    @Override\n    public boolean markSupported() {\n        return false;\n    }\n\n    /**\n     * Since we do not support marking just yet, we do nothing.\n     *\n     * @param markLimit The limit to mark.\n     */\n    @Override\n    public synchronized void mark(final int markLimit) {\n    }\n\n    /**\n     * Since we do not support marking just yet, we do nothing.\n     */\n    @Override\n    public synchronized void reset() {\n    }\n\n    /**\n     * Get the next entry in this tar archive. This will skip\n     * over any remaining data in the current entry, if there\n     * is one, and place the input stream at the header of the\n     * next entry, and read the header and instantiate a new\n     * TarEntry from the header bytes and return that entry.\n     * If there are no more entries in the archive, null will\n     * be returned to indicate that the end of the archive has\n     * been reached.\n     *\n     * @return The next TarEntry in the archive, or null.\n     * @throws IOException on error\n     */\n    public TarArchiveEntry getNextTarEntry() throws IOException {\n        if (isAtEOF()) {\n            return null;\n        }\n\n        if (currEntry != null) {\n            /* Skip will only go to the end of the current entry */\n            IOUtils.skip(this, Long.MAX_VALUE);\n\n            /* skip to the end of the last record */\n            skipRecordPadding();\n        }\n\n        final byte[] headerBuf = getRecord();\n\n        if (headerBuf == null) {\n            /* hit EOF */\n            currEntry = null;\n            return null;\n        }\n\n        try {\n            currEntry = new TarArchiveEntry(headerBuf, zipEncoding, lenient);\n        } catch (final IllegalArgumentException e) {\n            throw new IOException(\"Error detected parsing the header\", e);\n        }\n\n        entryOffset = 0;\n        entrySize = currEntry.getSize();\n\n        if (currEntry.isGNULongLinkEntry()) {\n            final byte[] longLinkData = getLongNameData();\n            if (longLinkData == null) {\n                // Bugzilla: 40334\n                // Malformed tar file - long link entry name not followed by\n                // entry\n                return null;\n            }\n            currEntry.setLinkName(zipEncoding.decode(longLinkData));\n        }\n\n        if (currEntry.isGNULongNameEntry()) {\n            final byte[] longNameData = getLongNameData();\n            if (longNameData == null) {\n                // Bugzilla: 40334\n                // Malformed tar file - long entry name not followed by\n                // entry\n                return null;\n            }\n\n            // COMPRESS-509 : the name of directories should end with '/'\n            final String name = zipEncoding.decode(longNameData);\n            currEntry.setName(name);\n            if (currEntry.isDirectory() && !name.endsWith(\"/\")) {\n                currEntry.setName(name + \"/\");\n            }\n        }\n\n        if (currEntry.isGlobalPaxHeader()){ // Process Global Pax headers\n            readGlobalPaxHeaders();\n        }\n\n        try {\n            if (currEntry.isPaxHeader()){ // Process Pax headers\n                paxHeaders();\n            } else if (!globalPaxHeaders.isEmpty()) {\n                applyPaxHeadersToCurrentEntry(globalPaxHeaders, globalSparseHeaders);\n            }\n        } catch (final NumberFormatException e) {\n            throw new IOException(\"Error detected parsing the pax header\", e);\n        }\n\n        if (currEntry.isOldGNUSparse()){ // Process sparse files\n            readOldGNUSparse();\n        }\n\n        // If the size of the next element in the archive has changed\n        // due to a new size being reported in the posix header\n        // information, we update entrySize here so that it contains\n        // the correct value.\n        entrySize = currEntry.getSize();\n\n        return currEntry;\n    }\n\n    /**\n     * The last record block should be written at the full size, so skip any\n     * additional space used to fill a record after an entry.\n     *\n     * @throws IOException if a truncated tar archive is detected\n     */\n    private void skipRecordPadding() throws IOException {\n        if (!isDirectory() && this.entrySize > 0 && this.entrySize % this.recordSize != 0) {\n            final long available = inputStream.available();\n            final long numRecords = (this.entrySize / this.recordSize) + 1;\n            final long padding = (numRecords * this.recordSize) - this.entrySize;\n            long skipped = IOUtils.skip(inputStream, padding);\n\n            skipped = getActuallySkipped(available, skipped, padding);\n\n            count(skipped);\n        }\n    }\n\n    /**\n     * For FileInputStream, the skip always return the number you input, so we\n     * need the available bytes to determine how many bytes are actually skipped\n     *\n     * @param available available bytes returned by inputStream.available()\n     * @param skipped   skipped bytes returned by inputStream.skip()\n     * @param expected  bytes expected to skip\n     * @return number of bytes actually skipped\n     * @throws IOException if a truncated tar archive is detected\n     */\n    private long getActuallySkipped(final long available, final long skipped, final long expected) throws IOException {\n        long actuallySkipped = skipped;\n        if (inputStream instanceof FileInputStream) {\n            actuallySkipped = Math.min(skipped, available);\n        }\n\n        if (actuallySkipped != expected) {\n            throw new IOException(\"Truncated TAR archive\");\n        }\n\n        return actuallySkipped;\n    }\n\n    /**\n     * Get the next entry in this tar archive as longname data.\n     *\n     * @return The next entry in the archive as longname data, or null.\n     * @throws IOException on error\n     */\n    protected byte[] getLongNameData() throws IOException {\n        // read in the name\n        final ByteArrayOutputStream longName = new ByteArrayOutputStream();\n        int length = 0;\n        while ((length = read(smallBuf)) >= 0) {\n            longName.write(smallBuf, 0, length);\n        }\n        getNextEntry();\n        if (currEntry == null) {\n            // Bugzilla: 40334\n            // Malformed tar file - long entry name not followed by entry\n            return null;\n        }\n        byte[] longNameData = longName.toByteArray();\n        // remove trailing null terminator(s)\n        length = longNameData.length;\n        while (length > 0 && longNameData[length - 1] == 0) {\n            --length;\n        }\n        if (length != longNameData.length) {\n            final byte[] l = new byte[length];\n            System.arraycopy(longNameData, 0, l, 0, length);\n            longNameData = l;\n        }\n        return longNameData;\n    }\n\n    /**\n     * Get the next record in this tar archive. This will skip\n     * over any remaining data in the current entry, if there\n     * is one, and place the input stream at the header of the\n     * next entry.\n     *\n     * <p>If there are no more entries in the archive, null will be\n     * returned to indicate that the end of the archive has been\n     * reached.  At the same time the {@code hasHitEOF} marker will be\n     * set to true.</p>\n     *\n     * @return The next header in the archive, or null.\n     * @throws IOException on error\n     */\n    private byte[] getRecord() throws IOException {\n        byte[] headerBuf = readRecord();\n        setAtEOF(isEOFRecord(headerBuf));\n        if (isAtEOF() && headerBuf != null) {\n            tryToConsumeSecondEOFRecord();\n            consumeRemainderOfLastBlock();\n            headerBuf = null;\n        }\n        return headerBuf;\n    }\n\n    /**\n     * Determine if an archive record indicate End of Archive. End of\n     * archive is indicated by a record that consists entirely of null bytes.\n     *\n     * @param record The record data to check.\n     * @return true if the record data is an End of Archive\n     */\n    protected boolean isEOFRecord(final byte[] record) {\n        return record == null || ArchiveUtils.isArrayZero(record, recordSize);\n    }\n\n    /**\n     * Read a record from the input stream and return the data.\n     *\n     * @return The record data or null if EOF has been hit.\n     * @throws IOException on error\n     */\n    protected byte[] readRecord() throws IOException {\n        final int readNow = IOUtils.readFully(inputStream, recordBuffer);\n        count(readNow);\n        if (readNow != recordSize) {\n            return null;\n        }\n\n        return recordBuffer;\n    }\n\n    private void readGlobalPaxHeaders() throws IOException {\n        globalPaxHeaders = TarUtils.parsePaxHeaders(this, globalSparseHeaders, globalPaxHeaders, entrySize);\n        getNextEntry(); // Get the actual file entry\n\n        if (currEntry == null) {\n            throw new IOException(\"Error detected parsing the pax header\");\n        }\n    }\n\n    /**\n     * For PAX Format 0.0, the sparse headers(GNU.sparse.offset and GNU.sparse.numbytes)\n     * may appear multi times, and they look like:\n     *\n     * GNU.sparse.size=size\n     * GNU.sparse.numblocks=numblocks\n     * repeat numblocks times\n     *   GNU.sparse.offset=offset\n     *   GNU.sparse.numbytes=numbytes\n     * end repeat\n     *\n     *\n     * For PAX Format 0.1, the sparse headers are stored in a single variable : GNU.sparse.map\n     *\n     * GNU.sparse.map\n     *    Map of non-null data chunks. It is a string consisting of comma-separated values \"offset,size[,offset-1,size-1...]\"\n     *\n     *\n     * For PAX Format 1.X:\n     * The sparse map itself is stored in the file data block, preceding the actual file data.\n     * It consists of a series of decimal numbers delimited by newlines. The map is padded with nulls to the nearest block boundary.\n     * The first number gives the number of entries in the map. Following are map entries, each one consisting of two numbers\n     * giving the offset and size of the data block it describes.\n     * @throws IOException\n     */\n    private void paxHeaders() throws IOException {\n        List<TarArchiveStructSparse> sparseHeaders = new ArrayList<>();\n        final Map<String, String> headers = TarUtils.parsePaxHeaders(this, sparseHeaders, globalPaxHeaders, entrySize);\n\n        // for 0.1 PAX Headers\n        if (headers.containsKey(\"GNU.sparse.map\")) {\n            sparseHeaders = TarUtils.parsePAX01SparseHeaders(headers.get(\"GNU.sparse.map\"));\n        }\n        getNextEntry(); // Get the actual file entry\n        if (currEntry == null) {\n            throw new IOException(\"premature end of tar archive. Didn't find any entry after PAX header.\");\n        }\n        applyPaxHeadersToCurrentEntry(headers, sparseHeaders);\n\n        // for 1.0 PAX Format, the sparse map is stored in the file data block\n        if (currEntry.isPaxGNU1XSparse()) {\n            sparseHeaders = TarUtils.parsePAX1XSparseHeaders(inputStream, recordSize);\n            currEntry.setSparseHeaders(sparseHeaders);\n        }\n\n        // sparse headers are all done reading, we need to build\n        // sparse input streams using these sparse headers\n        buildSparseInputStreams();\n    }\n\n    private void applyPaxHeadersToCurrentEntry(final Map<String, String> headers, final List<TarArchiveStructSparse> sparseHeaders) {\n        currEntry.updateEntryFromPaxHeaders(headers);\n        currEntry.setSparseHeaders(sparseHeaders);\n    }\n\n    /**\n     * Adds the sparse chunks from the current entry to the sparse chunks,\n     * including any additional sparse entries following the current entry.\n     *\n     * @throws IOException on error\n     */\n    private void readOldGNUSparse() throws IOException {\n        if (currEntry.isExtended()) {\n            TarArchiveSparseEntry entry;\n            do {\n                final byte[] headerBuf = getRecord();\n                if (headerBuf == null) {\n                    currEntry = null;\n                    break;\n                }\n                entry = new TarArchiveSparseEntry(headerBuf);\n                currEntry.getSparseHeaders().addAll(entry.getSparseHeaders());\n            } while (entry.isExtended());\n        }\n\n        // sparse headers are all done reading, we need to build\n        // sparse input streams using these sparse headers\n        buildSparseInputStreams();\n    }\n\n    private boolean isDirectory() {\n        return currEntry != null && currEntry.isDirectory();\n    }\n\n    /**\n     * Returns the next Archive Entry in this Stream.\n     *\n     * @return the next entry,\n     *         or {@code null} if there are no more entries\n     * @throws IOException if the next entry could not be read\n     */\n    @Override\n    public TarArchiveEntry getNextEntry() throws IOException {\n        return getNextTarEntry();\n    }\n\n    /**\n     * Tries to read the next record rewinding the stream if it is not a EOF record.\n     *\n     * <p>This is meant to protect against cases where a tar\n     * implementation has written only one EOF record when two are\n     * expected.  Actually this won't help since a non-conforming\n     * implementation likely won't fill full blocks consisting of - by\n     * default - ten records either so we probably have already read\n     * beyond the archive anyway.</p>\n     */\n    private void tryToConsumeSecondEOFRecord() throws IOException {\n        boolean shouldReset = true;\n        final boolean marked = inputStream.markSupported();\n        if (marked) {\n            inputStream.mark(recordSize);\n        }\n        try {\n            shouldReset = !isEOFRecord(readRecord());\n        } finally {\n            if (shouldReset && marked) {\n                pushedBackBytes(recordSize);\n                inputStream.reset();\n            }\n        }\n    }\n\n    /**\n     * Reads bytes from the current tar archive entry.\n     *\n     * This method is aware of the boundaries of the current\n     * entry in the archive and will deal with them as if they\n     * were this stream's start and EOF.\n     *\n     * @param buf The buffer into which to place bytes read.\n     * @param offset The offset at which to place bytes read.\n     * @param numToRead The number of bytes to read.\n     * @return The number of bytes read, or -1 at EOF.\n     * @throws IOException on error\n     */\n    @Override\n    public int read(final byte[] buf, final int offset, int numToRead) throws IOException {\n        if (numToRead == 0) {\n            return 0;\n        }\n    \tint totalRead = 0;\n\n        if (isAtEOF() || isDirectory()) {\n            return -1;\n        }\n\n        if (currEntry == null) {\n            throw new IllegalStateException(\"No current tar entry\");\n        }\n\n        if (!currEntry.isSparse()) {\n            if (entryOffset >= entrySize) {\n                return -1;\n            }\n        } else {\n            // for sparse entries, there are actually currEntry.getRealSize() bytes to read\n            if (entryOffset >= currEntry.getRealSize()) {\n                return -1;\n            }\n        }\n\n        numToRead = Math.min(numToRead, available());\n\n        if (currEntry.isSparse()) {\n            // for sparse entries, we need to read them in another way\n            totalRead = readSparse(buf, offset, numToRead);\n        } else {\n            totalRead = inputStream.read(buf, offset, numToRead);\n        }\n\n        if (totalRead == -1) {\n            if (numToRead > 0) {\n                throw new IOException(\"Truncated TAR archive\");\n            }\n            setAtEOF(true);\n        } else {\n            count(totalRead);\n            entryOffset += totalRead;\n        }\n\n        return totalRead;\n    }\n\n    /**\n     * For sparse tar entries, there are many \"holes\"(consisting of all 0) in the file. Only the non-zero data is\n     * stored in tar files, and they are stored separately. The structure of non-zero data is introduced by the\n     * sparse headers using the offset, where a block of non-zero data starts, and numbytes, the length of the\n     * non-zero data block.\n     * When reading sparse entries, the actual data is read out with \"holes\" and non-zero data combined together\n     * according to the sparse headers.\n     *\n     * @param buf The buffer into which to place bytes read.\n     * @param offset The offset at which to place bytes read.\n     * @param numToRead The number of bytes to read.\n     * @return The number of bytes read, or -1 at EOF.\n     * @throws IOException on error\n     */\n    private int readSparse(final byte[] buf, final int offset, final int numToRead) throws IOException {\n        // if there are no actual input streams, just read from the original input stream\n        if (sparseInputStreams == null || sparseInputStreams.isEmpty()) {\n            return inputStream.read(buf, offset, numToRead);\n        }\n\n        if (currentSparseInputStreamIndex >= sparseInputStreams.size()) {\n            return -1;\n        }\n\n        final InputStream currentInputStream = sparseInputStreams.get(currentSparseInputStreamIndex);\n        final int readLen = currentInputStream.read(buf, offset, numToRead);\n\n        // if the current input stream is the last input stream,\n        // just return the number of bytes read from current input stream\n        if (currentSparseInputStreamIndex == sparseInputStreams.size() - 1) {\n            return readLen;\n        }\n\n        // if EOF of current input stream is meet, open a new input stream and recursively call read\n        if (readLen == -1) {\n            currentSparseInputStreamIndex++;\n            return readSparse(buf, offset, numToRead);\n        }\n\n        // if the rest data of current input stream is not long enough, open a new input stream\n        // and recursively call read\n        if (readLen < numToRead) {\n            currentSparseInputStreamIndex++;\n            final int readLenOfNext = readSparse(buf, offset + readLen, numToRead - readLen);\n            if (readLenOfNext == -1) {\n                return readLen;\n            }\n\n            return readLen + readLenOfNext;\n        }\n\n        // if the rest data of current input stream is enough(which means readLen == len), just return readLen\n        return readLen;\n    }\n\n    /**\n     * Whether this class is able to read the given entry.\n     *\n     * @return The implementation will return true if the {@link ArchiveEntry} is an instance of {@link TarArchiveEntry}\n     */\n    @Override\n    public boolean canReadEntryData(final ArchiveEntry ae) {\n        return ae instanceof TarArchiveEntry;\n    }\n\n    /**\n     * Get the current TAR Archive Entry that this input stream is processing\n     *\n     * @return The current Archive Entry\n     */\n    public TarArchiveEntry getCurrentEntry() {\n        return currEntry;\n    }\n\n    protected final void setCurrentEntry(final TarArchiveEntry e) {\n        currEntry = e;\n    }\n\n    protected final boolean isAtEOF() {\n        return hasHitEOF;\n    }\n\n    protected final void setAtEOF(final boolean b) {\n        hasHitEOF = b;\n    }\n\n    /**\n     * This method is invoked once the end of the archive is hit, it\n     * tries to consume the remaining bytes under the assumption that\n     * the tool creating this archive has padded the last block.\n     */\n    private void consumeRemainderOfLastBlock() throws IOException {\n        final long bytesReadOfLastBlock = getBytesRead() % blockSize;\n        if (bytesReadOfLastBlock > 0) {\n            final long skipped = IOUtils.skip(inputStream, blockSize - bytesReadOfLastBlock);\n            count(skipped);\n        }\n    }\n\n    /**\n     * Checks if the signature matches what is expected for a tar file.\n     *\n     * @param signature\n     *            the bytes to check\n     * @param length\n     *            the number of bytes to check\n     * @return true, if this stream is a tar archive stream, false otherwise\n     */\n    public static boolean matches(final byte[] signature, final int length) {\n        if (length < TarConstants.VERSION_OFFSET+TarConstants.VERSIONLEN) {\n            return false;\n        }\n\n        if (ArchiveUtils.matchAsciiBuffer(TarConstants.MAGIC_POSIX,\n                signature, TarConstants.MAGIC_OFFSET, TarConstants.MAGICLEN)\n            &&\n            ArchiveUtils.matchAsciiBuffer(TarConstants.VERSION_POSIX,\n                signature, TarConstants.VERSION_OFFSET, TarConstants.VERSIONLEN)\n                ){\n            return true;\n        }\n        if (ArchiveUtils.matchAsciiBuffer(TarConstants.MAGIC_GNU,\n                signature, TarConstants.MAGIC_OFFSET, TarConstants.MAGICLEN)\n            &&\n            (\n             ArchiveUtils.matchAsciiBuffer(TarConstants.VERSION_GNU_SPACE,\n                signature, TarConstants.VERSION_OFFSET, TarConstants.VERSIONLEN)\n            ||\n            ArchiveUtils.matchAsciiBuffer(TarConstants.VERSION_GNU_ZERO,\n                signature, TarConstants.VERSION_OFFSET, TarConstants.VERSIONLEN)\n            )\n                ){\n            return true;\n        }\n        // COMPRESS-107 - recognise Ant tar files\n        return ArchiveUtils.matchAsciiBuffer(TarConstants.MAGIC_ANT,\n                signature, TarConstants.MAGIC_OFFSET, TarConstants.MAGICLEN)\n                &&\n                ArchiveUtils.matchAsciiBuffer(TarConstants.VERSION_ANT,\n                        signature, TarConstants.VERSION_OFFSET, TarConstants.VERSIONLEN);\n    }\n\n    /**\n     * Build the input streams consisting of all-zero input streams and non-zero input streams.\n     * When reading from the non-zero input streams, the data is actually read from the original input stream.\n     * The size of each input stream is introduced by the sparse headers.\n     *\n     * NOTE : Some all-zero input streams and non-zero input streams have the size of 0. We DO NOT store the\n     *        0 size input streams because they are meaningless.\n     */\n    private void buildSparseInputStreams() throws IOException {\n        currentSparseInputStreamIndex = -1;\n        sparseInputStreams = new ArrayList<>();\n\n        final List<TarArchiveStructSparse> sparseHeaders = currEntry.getSparseHeaders();\n        // sort the sparse headers in case they are written in wrong order\n        if (sparseHeaders != null && sparseHeaders.size() > 1) {\n            final Comparator<TarArchiveStructSparse> sparseHeaderComparator = (p, q) -> {\n                final Long pOffset = p.getOffset();\n                final Long qOffset = q.getOffset();\n                return pOffset.compareTo(qOffset);\n            };\n            Collections.sort(sparseHeaders, sparseHeaderComparator);\n        }\n\n        if (sparseHeaders != null) {\n            // Stream doesn't need to be closed at all as it doesn't use any resources\n            final InputStream zeroInputStream = new TarArchiveSparseZeroInputStream(); //NOSONAR\n            long offset = 0;\n            for (final TarArchiveStructSparse sparseHeader : sparseHeaders) {\n                if (sparseHeader.getOffset() == 0 && sparseHeader.getNumbytes() == 0) {\n                    break;\n                }\n\n                if ((sparseHeader.getOffset() - offset) < 0) {\n                    throw new IOException(\"Corrupted struct sparse detected\");\n                }\n\n                // only store the input streams with non-zero size\n                if ((sparseHeader.getOffset() - offset) > 0) {\n                    sparseInputStreams.add(new BoundedInputStream(zeroInputStream, sparseHeader.getOffset() - offset));\n                }\n\n                // only store the input streams with non-zero size\n                if (sparseHeader.getNumbytes() > 0) {\n                    sparseInputStreams.add(new BoundedInputStream(inputStream, sparseHeader.getNumbytes()));\n                }\n\n                offset = sparseHeader.getOffset() + sparseHeader.getNumbytes();\n            }\n        }\n\n        if (!sparseInputStreams.isEmpty()) {\n            currentSparseInputStreamIndex = 0;\n        }\n    }\n}"
  },
  {
    "path": "app/src/main/java/org/apache/commons/compress/archivers/tar/TarArchiveOutputStream.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage org.apache.commons.compress.archivers.tar;\n\nimport android.system.ErrnoException;\nimport org.apache.commons.compress.archivers.ArchiveEntry;\nimport org.apache.commons.compress.archivers.ArchiveOutputStream;\nimport org.apache.commons.compress.archivers.zip.ZipEncoding;\nimport org.apache.commons.compress.archivers.zip.ZipEncodingHelper;\nimport org.apache.commons.compress.utils.CountingOutputStream;\nimport org.apache.commons.compress.utils.FixedLengthBlockOutputStream;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.OutputStream;\nimport java.io.StringWriter;\nimport java.nio.ByteBuffer;\nimport java.nio.charset.StandardCharsets;\nimport java.nio.file.LinkOption;\nimport java.util.Arrays;\nimport java.util.Date;\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * The TarOutputStream writes a UNIX tar archive as an OutputStream. Methods are provided to put\n * entries, and then write their contents by writing to this stream using write().\n *\n * <p>tar archives consist of a sequence of records of 512 bytes each\n * that are grouped into blocks. Prior to Apache Commons Compress 1.14\n * it has been possible to configure a record size different from 512\n * bytes and arbitrary block sizes. Starting with Compress 1.15 512 is\n * the only valid option for the record size and the block size must\n * be a multiple of 512. Also the default block size changed from\n * 10240 bytes prior to Compress 1.15 to 512 bytes with Compress\n * 1.15.</p>\n *\n * @NotThreadSafe\n */\n// Copyright 2008 Torsten Curdt\npublic class TarArchiveOutputStream extends ArchiveOutputStream {\n\n    /**\n     * Fail if a long file name is required in the archive.\n     */\n    public static final int LONGFILE_ERROR = 0;\n\n    /**\n     * Long paths will be truncated in the archive.\n     */\n    public static final int LONGFILE_TRUNCATE = 1;\n\n    /**\n     * GNU tar extensions are used to store long file names in the archive.\n     */\n    public static final int LONGFILE_GNU = 2;\n\n    /**\n     * POSIX/PAX extensions are used to store long file names in the archive.\n     */\n    public static final int LONGFILE_POSIX = 3;\n\n    /**\n     * Fail if a big number (e.g. size &gt; 8GiB) is required in the archive.\n     */\n    public static final int BIGNUMBER_ERROR = 0;\n\n    /**\n     * star/GNU tar/BSD tar extensions are used to store big number in the archive.\n     */\n    public static final int BIGNUMBER_STAR = 1;\n\n    /**\n     * POSIX/PAX extensions are used to store big numbers in the archive.\n     */\n    public static final int BIGNUMBER_POSIX = 2;\n    private static final int RECORD_SIZE = 512;\n\n    private long currSize;\n    private String currName;\n    private long currBytes;\n    private final byte[] recordBuf;\n    private int longFileMode = LONGFILE_ERROR;\n    private int bigNumberMode = BIGNUMBER_ERROR;\n    private int recordsWritten;\n    private final int recordsPerBlock;\n\n    private boolean closed = false;\n\n    /**\n     * Indicates if putArchiveEntry has been called without closeArchiveEntry\n     */\n    private boolean haveUnclosedEntry = false;\n\n    /**\n     * indicates if this archive is finished\n     */\n    private boolean finished = false;\n\n    private final FixedLengthBlockOutputStream out;\n    private final CountingOutputStream countingOut;\n\n    private final ZipEncoding zipEncoding;\n\n    // the provided encoding (for unit tests)\n    final String encoding;\n\n    private boolean addPaxHeadersForNonAsciiNames = false;\n    private static final ZipEncoding ASCII =\n        ZipEncodingHelper.getZipEncoding(\"ASCII\");\n\n    private static final int BLOCK_SIZE_UNSPECIFIED = -511;\n\n    /**\n     * Constructor for TarArchiveOutputStream.\n     *\n     * <p>Uses a block size of 512 bytes.</p>\n     *\n     * @param os the output stream to use\n     */\n    public TarArchiveOutputStream(final OutputStream os) {\n        this(os, BLOCK_SIZE_UNSPECIFIED);\n    }\n\n    /**\n     * Constructor for TarArchiveOutputStream.\n     *\n     * <p>Uses a block size of 512 bytes.</p>\n     *\n     * @param os the output stream to use\n     * @param encoding name of the encoding to use for file names\n     * @since 1.4\n     */\n    public TarArchiveOutputStream(final OutputStream os, final String encoding) {\n        this(os, BLOCK_SIZE_UNSPECIFIED, encoding);\n    }\n\n    /**\n     * Constructor for TarArchiveOutputStream.\n     *\n     * @param os the output stream to use\n     * @param blockSize the block size to use. Must be a multiple of 512 bytes.\n     */\n    public TarArchiveOutputStream(final OutputStream os, final int blockSize) {\n        this(os, blockSize, null);\n    }\n\n\n    /**\n     * Constructor for TarArchiveOutputStream.\n     *\n     * @param os the output stream to use\n     * @param blockSize the block size to use\n     * @param recordSize the record size to use. Must be 512 bytes.\n     * @deprecated recordSize must always be 512 bytes. An IllegalArgumentException will be thrown\n     * if any other value is used\n     */\n    @Deprecated\n    public TarArchiveOutputStream(final OutputStream os, final int blockSize,\n        final int recordSize) {\n        this(os, blockSize, recordSize, null);\n    }\n\n    /**\n     * Constructor for TarArchiveOutputStream.\n     *\n     * @param os the output stream to use\n     * @param blockSize the block size to use . Must be a multiple of 512 bytes.\n     * @param recordSize the record size to use. Must be 512 bytes.\n     * @param encoding name of the encoding to use for file names\n     * @since 1.4\n     * @deprecated recordSize must always be 512 bytes. An IllegalArgumentException will be thrown\n     * if any other value is used.\n     */\n    @Deprecated\n    public TarArchiveOutputStream(final OutputStream os, final int blockSize,\n        final int recordSize, final String encoding) {\n        this(os, blockSize, encoding);\n        if (recordSize != RECORD_SIZE) {\n            throw new IllegalArgumentException(\n                \"Tar record size must always be 512 bytes. Attempt to set size of \" + recordSize);\n        }\n\n    }\n\n    /**\n     * Constructor for TarArchiveOutputStream.\n     *\n     * @param os the output stream to use\n     * @param blockSize the block size to use. Must be a multiple of 512 bytes.\n     * @param encoding name of the encoding to use for file names\n     * @since 1.4\n     */\n    public TarArchiveOutputStream(final OutputStream os, final int blockSize,\n        final String encoding) {\n        final int realBlockSize;\n        if (BLOCK_SIZE_UNSPECIFIED == blockSize) {\n            realBlockSize = RECORD_SIZE;\n        } else {\n            realBlockSize = blockSize;\n        }\n\n        if (realBlockSize <=0 || realBlockSize % RECORD_SIZE != 0) {\n            throw new IllegalArgumentException(\"Block size must be a multiple of 512 bytes. Attempt to use set size of \" + blockSize);\n        }\n        out = new FixedLengthBlockOutputStream(countingOut = new CountingOutputStream(os),\n                                               RECORD_SIZE);\n        this.encoding = encoding;\n        this.zipEncoding = ZipEncodingHelper.getZipEncoding(encoding);\n\n        this.recordBuf = new byte[RECORD_SIZE];\n        this.recordsPerBlock = realBlockSize / RECORD_SIZE;\n    }\n\n    /**\n     * Set the long file mode. This can be LONGFILE_ERROR(0), LONGFILE_TRUNCATE(1) or\n     * LONGFILE_GNU(2). This specifies the treatment of long file names (names &gt;=\n     * TarConstants.NAMELEN). Default is LONGFILE_ERROR.\n     *\n     * @param longFileMode the mode to use\n     */\n    public void setLongFileMode(final int longFileMode) {\n        this.longFileMode = longFileMode;\n    }\n\n    /**\n     * Set the big number mode. This can be BIGNUMBER_ERROR(0), BIGNUMBER_POSIX(1) or\n     * BIGNUMBER_STAR(2). This specifies the treatment of big files (sizes &gt;\n     * TarConstants.MAXSIZE) and other numeric values to big to fit into a traditional tar header.\n     * Default is BIGNUMBER_ERROR.\n     *\n     * @param bigNumberMode the mode to use\n     * @since 1.4\n     */\n    public void setBigNumberMode(final int bigNumberMode) {\n        this.bigNumberMode = bigNumberMode;\n    }\n\n    /**\n     * Whether to add a PAX extension header for non-ASCII file names.\n     *\n     * @param b whether to add a PAX extension header for non-ASCII file names.\n     * @since 1.4\n     */\n    public void setAddPaxHeadersForNonAsciiNames(final boolean b) {\n        addPaxHeadersForNonAsciiNames = b;\n    }\n\n    @Deprecated\n    @Override\n    public int getCount() {\n        return (int) getBytesWritten();\n    }\n\n    @Override\n    public long getBytesWritten() {\n        return countingOut.getBytesWritten();\n    }\n\n    /**\n     * Ends the TAR archive without closing the underlying OutputStream.\n     *\n     * An archive consists of a series of file entries terminated by an\n     * end-of-archive entry, which consists of two 512 blocks of zero bytes.\n     * POSIX.1 requires two EOF records, like some other implementations.\n     *\n     * @throws IOException on error\n     */\n    @Override\n    public void finish() throws IOException {\n        if (finished) {\n            throw new IOException(\"This archive has already been finished\");\n        }\n\n        if (haveUnclosedEntry) {\n            throw new IOException(\"This archive contains unclosed entries.\");\n        }\n        writeEOFRecord();\n        writeEOFRecord();\n        padAsNeeded();\n        out.flush();\n        finished = true;\n    }\n\n    /**\n     * Closes the underlying OutputStream.\n     *\n     * @throws IOException on error\n     */\n    @Override\n    public void close() throws IOException {\n        try {\n            if (!finished) {\n                finish();\n            }\n        } finally {\n            if (!closed) {\n                out.close();\n                closed = true;\n            }\n        }\n    }\n\n    /**\n     * Get the record size being used by this stream's TarBuffer.\n     *\n     * @return The TarBuffer record size.\n     * @deprecated\n     */\n    @Deprecated\n    public int getRecordSize() {\n        return RECORD_SIZE;\n    }\n\n    /**\n     * Put an entry on the output stream. This writes the entry's header record and positions the\n     * output stream for writing the contents of the entry. Once this method is called, the stream\n     * is ready for calls to write() to write the entry's contents. Once the contents are written,\n     * closeArchiveEntry() <B>MUST</B> be called to ensure that all buffered data is completely\n     * written to the output stream.\n     *\n     * @param archiveEntry The TarEntry to be written to the archive.\n     * @throws IOException on error\n     * @throws ClassCastException if archiveEntry is not an instance of TarArchiveEntry\n     * @throws IllegalArgumentException if the {@link TarArchiveOutputStream#longFileMode} equals\n     *                                  {@link TarArchiveOutputStream#LONGFILE_ERROR} and the file\n     *                                  name is too long\n     * @throws IllegalArgumentException if the {@link TarArchiveOutputStream#bigNumberMode} equals\n     *         {@link TarArchiveOutputStream#BIGNUMBER_ERROR} and one of the numeric values\n     *         exceeds the limits of a traditional tar header.\n     */\n    @Override\n    public void putArchiveEntry(final ArchiveEntry archiveEntry) throws IOException {\n        if (finished) {\n            throw new IOException(\"Stream has already been finished\");\n        }\n        final TarArchiveEntry entry = (TarArchiveEntry) archiveEntry;\n        if (entry.isGlobalPaxHeader()) {\n            final byte[] data = encodeExtendedPaxHeadersContents(entry.getExtraPaxHeaders());\n            entry.setSize(data.length);\n            entry.writeEntryHeader(recordBuf, zipEncoding, bigNumberMode == BIGNUMBER_STAR);\n            writeRecord(recordBuf);\n            currSize= entry.getSize();\n            currBytes = 0;\n            this.haveUnclosedEntry = true;\n            write(data);\n            closeArchiveEntry();\n        } else {\n            final Map<String, String> paxHeaders = new HashMap<>();\n            final String entryName = entry.getName();\n            final boolean paxHeaderContainsPath = handleLongName(entry, entryName, paxHeaders, \"path\",\n                TarConstants.LF_GNUTYPE_LONGNAME, \"file name\");\n\n            final String linkName = entry.getLinkName();\n            final boolean paxHeaderContainsLinkPath = linkName != null && !linkName.isEmpty()\n                && handleLongName(entry, linkName, paxHeaders, \"linkpath\",\n                TarConstants.LF_GNUTYPE_LONGLINK, \"link name\");\n\n            if (bigNumberMode == BIGNUMBER_POSIX) {\n                addPaxHeadersForBigNumbers(paxHeaders, entry);\n            } else if (bigNumberMode != BIGNUMBER_STAR) {\n                failForBigNumbers(entry);\n            }\n\n            if (addPaxHeadersForNonAsciiNames && !paxHeaderContainsPath\n                && !ASCII.canEncode(entryName)) {\n                paxHeaders.put(\"path\", entryName);\n            }\n\n            if (addPaxHeadersForNonAsciiNames && !paxHeaderContainsLinkPath\n                && (entry.isLink() || entry.isSymbolicLink())\n                && !ASCII.canEncode(linkName)) {\n                paxHeaders.put(\"linkpath\", linkName);\n            }\n            paxHeaders.putAll(entry.getExtraPaxHeaders());\n\n            if (!paxHeaders.isEmpty()) {\n                writePaxHeaders(entry, entryName, paxHeaders);\n            }\n\n            entry.writeEntryHeader(recordBuf, zipEncoding, bigNumberMode == BIGNUMBER_STAR);\n            writeRecord(recordBuf);\n\n            currBytes = 0;\n\n            if (entry.isDirectory()) {\n                currSize = 0;\n            } else {\n                currSize = entry.getSize();\n            }\n            currName = entryName;\n            haveUnclosedEntry = true;\n        }\n    }\n\n    /**\n     * Close an entry. This method MUST be called for all file entries that contain data. The reason\n     * is that we must buffer data written to the stream in order to satisfy the buffer's record\n     * based writes. Thus, there may be data fragments still being assembled that must be written to\n     * the output stream before this entry is closed and the next entry written.\n     *\n     * @throws IOException on error\n     */\n    @Override\n    public void closeArchiveEntry() throws IOException {\n        if (finished) {\n            throw new IOException(\"Stream has already been finished\");\n        }\n        if (!haveUnclosedEntry) {\n            throw new IOException(\"No current entry to close\");\n        }\n        out.flushBlock();\n        if (currBytes < currSize) {\n            throw new IOException(\"Entry '\" + currName + \"' closed at '\"\n                + currBytes\n                + \"' before the '\" + currSize\n                + \"' bytes specified in the header were written\");\n        }\n        recordsWritten += (int) (currSize / RECORD_SIZE);\n        if (0 != currSize % RECORD_SIZE) {\n            recordsWritten++;\n        }\n        haveUnclosedEntry = false;\n    }\n\n    /**\n     * Writes bytes to the current tar archive entry. This method is aware of the current entry and\n     * will throw an exception if you attempt to write bytes past the length specified for the\n     * current entry.\n     *\n     * @param wBuf The buffer to write to the archive.\n     * @param wOffset The offset in the buffer from which to get bytes.\n     * @param numToWrite The number of bytes to write.\n     * @throws IOException on error\n     */\n    @Override\n    public void write(final byte[] wBuf, final int wOffset, final int numToWrite) throws IOException {\n        if (!haveUnclosedEntry) {\n            throw new IllegalStateException(\"No current tar entry\");\n        }\n        if (currBytes + numToWrite > currSize) {\n            throw new IOException(\"Request to write '\" + numToWrite\n                + \"' bytes exceeds size in header of '\"\n                + currSize + \"' bytes for entry '\"\n                + currName + \"'\");\n        }\n        out.write(wBuf, wOffset, numToWrite);\n        currBytes += numToWrite;\n    }\n\n    /**\n     * Writes a PAX extended header with the given map as contents.\n     *\n     * @since 1.4\n     */\n    void writePaxHeaders(final TarArchiveEntry entry,\n        final String entryName,\n        final Map<String, String> headers) throws IOException {\n        String name = \"./PaxHeaders.X/\" + stripTo7Bits(entryName);\n        if (name.length() >= TarConstants.NAMELEN) {\n            name = name.substring(0, TarConstants.NAMELEN - 1);\n        }\n        final TarArchiveEntry pex = new TarArchiveEntry(name,\n            TarConstants.LF_PAX_EXTENDED_HEADER_LC);\n        transferModTime(entry, pex);\n\n        final byte[] data = encodeExtendedPaxHeadersContents(headers);\n        pex.setSize(data.length);\n        putArchiveEntry(pex);\n        write(data);\n        closeArchiveEntry();\n    }\n\n    private byte[] encodeExtendedPaxHeadersContents(final Map<String, String> headers) {\n        final StringWriter w = new StringWriter();\n        for (final Map.Entry<String, String> h : headers.entrySet()) {\n            final String key = h.getKey();\n            final String value = h.getValue();\n            int len = key.length() + value.length()\n                + 3 /* blank, equals and newline */\n                + 2 /* guess 9 < actual length < 100 */;\n            String line = len + \" \" + key + \"=\" + value + \"\\n\";\n            int actualLength = line.getBytes(StandardCharsets.UTF_8).length;\n            while (len != actualLength) {\n                // Adjust for cases where length < 10 or > 100\n                // or where UTF-8 encoding isn't a single octet\n                // per character.\n                // Must be in loop as size may go from 99 to 100 in\n                // first pass so we'd need a second.\n                len = actualLength;\n                line = len + \" \" + key + \"=\" + value + \"\\n\";\n                actualLength = line.getBytes(StandardCharsets.UTF_8).length;\n            }\n            w.write(line);\n        }\n        return w.toString().getBytes(StandardCharsets.UTF_8);\n    }\n\n    private String stripTo7Bits(final String name) {\n        final int length = name.length();\n        final StringBuilder result = new StringBuilder(length);\n        for (int i = 0; i < length; i++) {\n            final char stripped = (char) (name.charAt(i) & 0x7F);\n            if (shouldBeReplaced(stripped)) {\n                result.append(\"_\");\n            } else {\n                result.append(stripped);\n            }\n        }\n        return result.toString();\n    }\n\n    /**\n     * @return true if the character could lead to problems when used inside a TarArchiveEntry name\n     * for a PAX header.\n     */\n    private boolean shouldBeReplaced(final char c) {\n        return c == 0 // would be read as Trailing null\n            || c == '/' // when used as last character TAE will consider the PAX header a directory\n            || c == '\\\\'; // same as '/' as slashes get \"normalized\" on Windows\n    }\n\n    /**\n     * Write an EOF (end of archive) record to the tar archive. An EOF record consists of a record\n     * of all zeros.\n     */\n    private void writeEOFRecord() throws IOException {\n        Arrays.fill(recordBuf, (byte) 0);\n        writeRecord(recordBuf);\n    }\n\n    @Override\n    public void flush() throws IOException {\n        out.flush();\n    }\n\n    @Override\n    public ArchiveEntry createArchiveEntry(final File inputFile, final String entryName)\n        throws IOException {\n        if (finished) {\n            throw new IOException(\"Stream has already been finished\");\n        }\n        return new TarArchiveEntry(inputFile, entryName);\n    }\n\n    @Override\n    public ArchiveEntry createArchiveEntry(final File inputPath, final String entryName, final LinkOption... options) throws IOException, ErrnoException {\n        if (finished) {\n            throw new IOException(\"Stream has already been finished\");\n        }\n        return new TarArchiveEntry(inputPath, entryName);\n    }\n\n    /**\n     * Write an archive record to the archive.\n     *\n     * @param record The record data to write to the archive.\n     * @throws IOException on error\n     */\n    private void writeRecord(final byte[] record) throws IOException {\n        if (record.length != RECORD_SIZE) {\n            throw new IOException(\"Record to write has length '\"\n                + record.length\n                + \"' which is not the record size of '\"\n                + RECORD_SIZE + \"'\");\n        }\n\n        out.write(record);\n        recordsWritten++;\n    }\n\n    private void padAsNeeded() throws IOException {\n        final int start = recordsWritten % recordsPerBlock;\n        if (start != 0) {\n            for (int i = start; i < recordsPerBlock; i++) {\n                writeEOFRecord();\n            }\n        }\n    }\n\n    private void addPaxHeadersForBigNumbers(final Map<String, String> paxHeaders,\n        final TarArchiveEntry entry) {\n        addPaxHeaderForBigNumber(paxHeaders, \"size\", entry.getSize(),\n            TarConstants.MAXSIZE);\n        addPaxHeaderForBigNumber(paxHeaders, \"gid\", entry.getLongGroupId(),\n            TarConstants.MAXID);\n        addPaxHeaderForBigNumber(paxHeaders, \"mtime\",\n            entry.getModTime().getTime() / 1000,\n            TarConstants.MAXSIZE);\n        addPaxHeaderForBigNumber(paxHeaders, \"uid\", entry.getLongUserId(),\n            TarConstants.MAXID);\n        // star extensions by J\\u00f6rg Schilling\n        addPaxHeaderForBigNumber(paxHeaders, \"SCHILY.devmajor\",\n            entry.getDevMajor(), TarConstants.MAXID);\n        addPaxHeaderForBigNumber(paxHeaders, \"SCHILY.devminor\",\n            entry.getDevMinor(), TarConstants.MAXID);\n        // there is no PAX header for file mode\n        failForBigNumber(\"mode\", entry.getMode(), TarConstants.MAXID);\n    }\n\n    private void addPaxHeaderForBigNumber(final Map<String, String> paxHeaders,\n        final String header, final long value,\n        final long maxValue) {\n        if (value < 0 || value > maxValue) {\n            paxHeaders.put(header, String.valueOf(value));\n        }\n    }\n\n    private void failForBigNumbers(final TarArchiveEntry entry) {\n        failForBigNumber(\"entry size\", entry.getSize(), TarConstants.MAXSIZE);\n        failForBigNumberWithPosixMessage(\"group id\", entry.getLongGroupId(), TarConstants.MAXID);\n        failForBigNumber(\"last modification time\",\n            entry.getModTime().getTime() / 1000,\n            TarConstants.MAXSIZE);\n        failForBigNumber(\"user id\", entry.getLongUserId(), TarConstants.MAXID);\n        failForBigNumber(\"mode\", entry.getMode(), TarConstants.MAXID);\n        failForBigNumber(\"major device number\", entry.getDevMajor(),\n            TarConstants.MAXID);\n        failForBigNumber(\"minor device number\", entry.getDevMinor(),\n            TarConstants.MAXID);\n    }\n\n    private void failForBigNumber(final String field, final long value, final long maxValue) {\n        failForBigNumber(field, value, maxValue, \"\");\n    }\n\n    private void failForBigNumberWithPosixMessage(final String field, final long value,\n        final long maxValue) {\n        failForBigNumber(field, value, maxValue,\n            \" Use STAR or POSIX extensions to overcome this limit\");\n    }\n\n    private void failForBigNumber(final String field, final long value, final long maxValue,\n        final String additionalMsg) {\n        if (value < 0 || value > maxValue) {\n            throw new IllegalArgumentException(field + \" '\" + value //NOSONAR\n                + \"' is too big ( > \"\n                + maxValue + \" ).\" + additionalMsg);\n        }\n    }\n\n    /**\n     * Handles long file or link names according to the longFileMode setting.\n     *\n     * <p>I.e. if the given name is too long to be written to a plain tar header then <ul> <li>it\n     * creates a pax header who's name is given by the paxHeaderName parameter if longFileMode is\n     * POSIX</li> <li>it creates a GNU longlink entry who's type is given by the linkType parameter\n     * if longFileMode is GNU</li> <li>it throws an exception if longFileMode is ERROR</li> <li>it\n     * truncates the name if longFileMode is TRUNCATE</li> </ul></p>\n     *\n     * @param entry entry the name belongs to\n     * @param name the name to write\n     * @param paxHeaders current map of pax headers\n     * @param paxHeaderName name of the pax header to write\n     * @param linkType type of the GNU entry to write\n     * @param fieldName the name of the field\n     * @throws IllegalArgumentException if the {@link TarArchiveOutputStream#longFileMode} equals\n     *                                  {@link TarArchiveOutputStream#LONGFILE_ERROR} and the file\n     *                                  name is too long\n     * @return whether a pax header has been written.\n     */\n    private boolean handleLongName(final TarArchiveEntry entry, final String name,\n        final Map<String, String> paxHeaders,\n        final String paxHeaderName, final byte linkType, final String fieldName)\n        throws IOException {\n        final ByteBuffer encodedName = zipEncoding.encode(name);\n        final int len = encodedName.limit() - encodedName.position();\n        if (len >= TarConstants.NAMELEN) {\n\n            if (longFileMode == LONGFILE_POSIX) {\n                paxHeaders.put(paxHeaderName, name);\n                return true;\n            } else if (longFileMode == LONGFILE_GNU) {\n                // create a TarEntry for the LongLink, the contents\n                // of which are the link's name\n                final TarArchiveEntry longLinkEntry = new TarArchiveEntry(TarConstants.GNU_LONGLINK,\n                    linkType);\n\n                longLinkEntry.setSize(len + 1L); // +1 for NUL\n                transferModTime(entry, longLinkEntry);\n                putArchiveEntry(longLinkEntry);\n                write(encodedName.array(), encodedName.arrayOffset(), len);\n                write(0); // NUL terminator\n                closeArchiveEntry();\n            } else if (longFileMode != LONGFILE_TRUNCATE) {\n                throw new IllegalArgumentException(fieldName + \" '\" + name //NOSONAR\n                    + \"' is too long ( > \"\n                    + TarConstants.NAMELEN + \" bytes)\");\n            }\n        }\n        return false;\n    }\n\n    private void transferModTime(final TarArchiveEntry from, final TarArchiveEntry to) {\n        Date fromModTime = from.getModTime();\n        final long fromModTimeSeconds = fromModTime.getTime() / 1000;\n        if (fromModTimeSeconds < 0 || fromModTimeSeconds > TarConstants.MAXSIZE) {\n            fromModTime = new Date(0);\n        }\n        to.setModTime(fromModTime);\n    }\n}"
  },
  {
    "path": "app/src/main/java/org/apache/commons/compress/archivers/tar/TarArchiveSparseEntry.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage org.apache.commons.compress.archivers.tar;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.List;\n\n/**\n * This class represents a sparse entry in a Tar archive.\n *\n * <p>\n * The C structure for a sparse entry is:\n * <pre>\n * struct posix_header {\n * struct sparse sp[21]; // TarConstants.SPARSELEN_GNU_SPARSE     - offset 0\n * char isextended;      // TarConstants.ISEXTENDEDLEN_GNU_SPARSE - offset 504\n * };\n * </pre>\n * Whereas, \"struct sparse\" is:\n * <pre>\n * struct sparse {\n * char offset[12];   // offset 0\n * char numbytes[12]; // offset 12\n * };\n * </pre>\n */\n// Copyright 2011 Stefan Bodewig\npublic class TarArchiveSparseEntry implements TarConstants {\n    /** If an extension sparse header follows. */\n    private final boolean isExtended;\n\n    private final List<TarArchiveStructSparse> sparseHeaders;\n\n    /**\n     * Construct an entry from an archive's header bytes. File is set\n     * to null.\n     *\n     * @param headerBuf The header bytes from a tar archive entry.\n     * @throws IOException on unknown format\n     */\n    public TarArchiveSparseEntry(final byte[] headerBuf) throws IOException {\n        int offset = 0;\n        sparseHeaders = new ArrayList<>();\n        for(int i = 0; i < SPARSE_HEADERS_IN_EXTENSION_HEADER;i++) {\n            final TarArchiveStructSparse sparseHeader = TarUtils.parseSparse(headerBuf,\n                    offset + i * (SPARSE_OFFSET_LEN + SPARSE_NUMBYTES_LEN));\n\n            // some sparse headers are empty, we need to skip these sparse headers\n            if(sparseHeader.getOffset() > 0 || sparseHeader.getNumbytes() > 0) {\n                sparseHeaders.add(sparseHeader);\n            }\n        }\n\n        offset += SPARSELEN_GNU_SPARSE;\n        isExtended = TarUtils.parseBoolean(headerBuf, offset);\n    }\n\n    public boolean isExtended() {\n        return isExtended;\n    }\n\n    /**\n     * Obtains information about the configuration for the sparse entry.\n     * @since 1.20\n     * @return information about the configuration for the sparse entry.\n     */\n    public List<TarArchiveStructSparse> getSparseHeaders() {\n        return sparseHeaders;\n    }\n}"
  },
  {
    "path": "app/src/main/java/org/apache/commons/compress/archivers/tar/TarArchiveSparseZeroInputStream.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage org.apache.commons.compress.archivers.tar;\n\nimport java.io.IOException;\nimport java.io.InputStream;\n\n/**\n * This is an inputstream that always return 0,\n * this is used when reading the \"holes\" of a sparse file\n */\n// Copyright 2021 Robin Schimpf\nclass TarArchiveSparseZeroInputStream extends InputStream {\n\n    /**\n     * Just return 0\n     */\n    @Override\n    public int read() throws IOException {\n        return 0;\n    }\n\n    /**\n     * these's nothing need to do when skipping\n     *\n     * @param n bytes to skip\n     * @return bytes actually skipped\n     */\n    @Override\n    public long skip(final long n) {\n        return n;\n    }\n}"
  },
  {
    "path": "app/src/main/java/org/apache/commons/compress/archivers/tar/TarArchiveStructSparse.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage org.apache.commons.compress.archivers.tar;\n\nimport java.util.Objects;\n\n/**\n * This class represents struct sparse in a Tar archive.\n * <p>\n * Whereas, \"struct sparse\" is:\n * <pre>\n * struct sparse {\n * char offset[12];   // offset 0\n * char numbytes[12]; // offset 12\n * };\n * </pre>\n * @since 1.20\n */\n// Copyright 2019 Peter Alfred Lee\npublic final class TarArchiveStructSparse {\n    private final long offset;\n    private final long numbytes;\n\n    public TarArchiveStructSparse(final long offset, final long numbytes) {\n        this.offset = offset;\n        this.numbytes = numbytes;\n    }\n\n    @Override\n    public boolean equals(final Object o) {\n        if (this == o) {\n            return true;\n        }\n        if (o == null || getClass() != o.getClass()) {\n            return false;\n        }\n        final TarArchiveStructSparse that = (TarArchiveStructSparse) o;\n        return offset == that.offset &&\n                numbytes == that.numbytes;\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hash(offset, numbytes);\n    }\n\n    @Override\n    public String toString() {\n        return \"TarArchiveStructSparse{\" +\n                \"offset=\" + offset +\n                \", numbytes=\" + numbytes +\n                '}';\n    }\n\n    public long getOffset() {\n        return offset;\n    }\n\n    public long getNumbytes() {\n        return numbytes;\n    }\n}"
  },
  {
    "path": "app/src/main/java/org/apache/commons/compress/archivers/tar/TarConstants.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage org.apache.commons.compress.archivers.tar;\n\n/**\n * This interface contains all the definitions used in the package.\n *\n * For tar formats (FORMAT_OLDGNU, FORMAT_POSIX, etc.) see GNU tar\n * <I>tar.h</I> type <I>enum archive_format</I>\n */\n// Copyright 2008 Torsten Curdt\npublic interface TarConstants {\n\n    /** Default record size */\n    int DEFAULT_RCDSIZE = 512;\n\n    /** Default block size */\n    int DEFAULT_BLKSIZE = DEFAULT_RCDSIZE * 20;\n\n    /**\n     * GNU format as per before tar 1.12.\n     */\n    int    FORMAT_OLDGNU = 2;\n\n    /**\n     * Pure Posix format.\n     */\n    int    FORMAT_POSIX = 3;\n\n    /**\n     * xstar format used by Jörg Schilling's star.\n     */\n    int    FORMAT_XSTAR = 4;\n\n    /**\n     * The length of the name field in a header buffer.\n     */\n    int    NAMELEN = 100;\n\n    /**\n     * The length of the mode field in a header buffer.\n     */\n    int    MODELEN = 8;\n\n    /**\n     * The length of the user id field in a header buffer.\n     */\n    int    UIDLEN = 8;\n\n    /**\n     * The length of the group id field in a header buffer.\n     */\n    int    GIDLEN = 8;\n\n    /**\n     * The maximum value of gid/uid in a tar archive which can\n     * be expressed in octal char notation (that's 7 sevens, octal).\n     */\n    long    MAXID = 07777777L;\n\n    /**\n     * The length of the checksum field in a header buffer.\n     */\n    int    CHKSUMLEN = 8;\n\n    /**\n     * Offset of the checksum field within header record.\n     * @since 1.5\n     */\n    int    CHKSUM_OFFSET = 148;\n\n    /**\n     * The length of the size field in a header buffer.\n     * Includes the trailing space or NUL.\n     */\n    int    SIZELEN = 12;\n\n    /**\n     * The maximum size of a file in a tar archive\n     * which can be expressed in octal char notation (that's 11 sevens, octal).\n     */\n    long   MAXSIZE = 077777777777L;\n\n    /** Offset of start of magic field within header record */\n    int    MAGIC_OFFSET = 257;\n    /**\n     * The length of the magic field in a header buffer.\n     */\n    int    MAGICLEN = 6;\n\n    /** Offset of start of magic field within header record */\n    int    VERSION_OFFSET = 263;\n    /**\n     * Previously this was regarded as part of \"magic\" field, but it is separate.\n     */\n    int    VERSIONLEN = 2;\n\n    /**\n     * The length of the modification time field in a header buffer.\n     */\n    int    MODTIMELEN = 12;\n\n    /**\n     * The length of the user name field in a header buffer.\n     */\n    int    UNAMELEN = 32;\n\n    /**\n     * The length of the group name field in a header buffer.\n     */\n    int    GNAMELEN = 32;\n\n    /**\n     * The length of each of the device fields (major and minor) in a header buffer.\n     */\n    int    DEVLEN = 8;\n\n    /**\n     * Length of the prefix field.\n     *\n     */\n    int    PREFIXLEN = 155;\n\n    /**\n     * The length of the access time field in an old GNU header buffer.\n     *\n     */\n    int    ATIMELEN_GNU = 12;\n\n    /**\n     * The length of the created time field in an old GNU header buffer.\n     *\n     */\n    int    CTIMELEN_GNU = 12;\n\n    /**\n     * The length of the multivolume start offset field in an old GNU header buffer.\n     *\n     */\n    int    OFFSETLEN_GNU = 12;\n\n    /**\n     * The length of the long names field in an old GNU header buffer.\n     *\n     */\n    int    LONGNAMESLEN_GNU = 4;\n\n    /**\n     * The length of the padding field in an old GNU header buffer.\n     *\n     */\n    int    PAD2LEN_GNU = 1;\n\n    /**\n     * The sum of the length of all sparse headers in an old GNU header buffer.\n     *\n     */\n    int    SPARSELEN_GNU = 96;\n\n    /**\n     * The length of the is extension field in an old GNU header buffer.\n     *\n     */\n    int    ISEXTENDEDLEN_GNU = 1;\n\n    /**\n     * The length of the real size field in an old GNU header buffer.\n     *\n     */\n    int    REALSIZELEN_GNU = 12;\n\n    /**\n     * The length of offset in struct sparse\n     * @since 1.20\n     */\n    int    SPARSE_OFFSET_LEN = 12;\n\n    /**\n     * The length of numbytes in struct sparse\n     * @since 1.20\n     */\n    int    SPARSE_NUMBYTES_LEN = 12;\n\n    /**\n     *  The number of sparse headers in an old GNU header\n     * @since 1.20\n     */\n    int    SPARSE_HEADERS_IN_OLDGNU_HEADER = 4;\n\n    /**\n     *  The number of sparse headers in an extension header\n     * @since 1.20\n     */\n    int    SPARSE_HEADERS_IN_EXTENSION_HEADER = 21;\n\n    /**\n     * The sum of the length of all sparse headers in a sparse header buffer.\n     *\n     */\n    int    SPARSELEN_GNU_SPARSE = 504;\n\n    /**\n     * The length of the is extension field in a sparse header buffer.\n     *\n     */\n    int    ISEXTENDEDLEN_GNU_SPARSE = 1;\n\n    /**\n     * LF_ constants represent the \"link flag\" of an entry, or more commonly,\n     * the \"entry type\". This is the \"old way\" of indicating a normal file.\n     */\n    byte   LF_OLDNORM = 0;\n\n    /**\n     * Normal file type.\n     */\n    byte   LF_NORMAL = (byte) '0';\n\n    /**\n     * Link file type.\n     */\n    byte   LF_LINK = (byte) '1';\n\n    /**\n     * Symbolic link file type.\n     */\n    byte   LF_SYMLINK = (byte) '2';\n\n    /**\n     * Character device file type.\n     */\n    byte   LF_CHR = (byte) '3';\n\n    /**\n     * Block device file type.\n     */\n    byte   LF_BLK = (byte) '4';\n\n    /**\n     * Directory file type.\n     */\n    byte   LF_DIR = (byte) '5';\n\n    /**\n     * FIFO (pipe) file type.\n     */\n    byte   LF_FIFO = (byte) '6';\n\n    /**\n     * Contiguous file type.\n     */\n    byte   LF_CONTIG = (byte) '7';\n\n    /**\n     * Identifies the *next* file on the tape as having a long linkname.\n     */\n    byte LF_GNUTYPE_LONGLINK = (byte) 'K';\n\n    /**\n     * Identifies the *next* file on the tape as having a long name.\n     */\n    byte LF_GNUTYPE_LONGNAME = (byte) 'L';\n\n    /**\n     * Sparse file type.\n     * @since 1.1.1\n     */\n    byte LF_GNUTYPE_SPARSE = (byte) 'S';\n\n    // See \"http://www.opengroup.org/onlinepubs/009695399/utilities/pax.html#tag_04_100_13_02\"\n\n    /**\n     * Identifies the entry as a Pax extended header.\n     * @since 1.1\n     */\n    byte LF_PAX_EXTENDED_HEADER_LC = (byte) 'x';\n\n    /**\n     * Identifies the entry as a Pax extended header (SunOS tar -E).\n     *\n     * @since 1.1\n     */\n    byte LF_PAX_EXTENDED_HEADER_UC = (byte) 'X';\n\n    /**\n     * Identifies the entry as a Pax global extended header.\n     *\n     * @since 1.1\n     */\n    byte LF_PAX_GLOBAL_EXTENDED_HEADER = (byte) 'g';\n\n    /**\n     * The magic tag representing a POSIX tar archive.\n     */\n    String MAGIC_POSIX = \"ustar\\0\";\n    String VERSION_POSIX = \"00\";\n\n    /**\n     * The magic tag representing a GNU tar archive.\n     */\n    String MAGIC_GNU = \"ustar \";\n    // Appear to be two possible GNU versions\n    String VERSION_GNU_SPACE = \" \\0\";\n    String VERSION_GNU_ZERO  = \"0\\0\";\n\n    /**\n     * The magic tag representing an Ant tar archive.\n     *\n     * @since 1.1\n     */\n    String MAGIC_ANT = \"ustar\\0\";\n\n    /**\n     * The \"version\" representing an Ant tar archive.\n     *\n     * @since 1.1\n     */\n    // Does not appear to have a version, however Ant does write 8 bytes,\n    // so assume the version is 2 nulls\n    String VERSION_ANT = \"\\0\\0\";\n\n    /**\n     * The name of the GNU tar entry which contains a long name.\n     */\n    String GNU_LONGLINK = \"././@LongLink\"; // TODO rename as LONGLINK_GNU ?\n\n    /**\n     * The magix string used in the last four bytes of the header to\n     * identify the xstar format.\n     * @since 1.11\n     */\n    String MAGIC_XSTAR = \"tar\\0\";\n\n    /**\n     * Offset inside the header for the xstar magic bytes.\n     * @since 1.11\n     */\n    int XSTAR_MAGIC_OFFSET = 508;\n\n    /**\n     * Length of the XSTAR magic.\n     * @since 1.11\n     */\n    int XSTAR_MAGIC_LEN = 4;\n\n    /**\n     * Length of the prefix field in xstar archives.\n     *\n     * @since 1.11\n     */\n    int PREFIXLEN_XSTAR = 131;\n\n    /**\n     * The length of the access time field in a xstar header buffer.\n     *\n     * @since 1.11\n     */\n    int ATIMELEN_XSTAR = 12;\n\n    /**\n     * The length of the created time field in a xstar header buffer.\n     *\n     * @since 1.11\n     */\n    int CTIMELEN_XSTAR = 12;\n}"
  },
  {
    "path": "app/src/main/java/org/apache/commons/compress/archivers/tar/TarUtils.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage org.apache.commons.compress.archivers.tar;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.math.BigInteger;\nimport java.nio.ByteBuffer;\nimport java.nio.charset.StandardCharsets;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\n\nimport org.apache.commons.compress.archivers.zip.ZipEncoding;\nimport org.apache.commons.compress.archivers.zip.ZipEncodingHelper;\nimport org.apache.commons.compress.utils.CharsetNames;\nimport org.apache.commons.compress.utils.IOUtils;\n\nimport static org.apache.commons.compress.archivers.tar.TarConstants.CHKSUMLEN;\nimport static org.apache.commons.compress.archivers.tar.TarConstants.CHKSUM_OFFSET;\nimport static org.apache.commons.compress.archivers.tar.TarConstants.SPARSE_NUMBYTES_LEN;\nimport static org.apache.commons.compress.archivers.tar.TarConstants.SPARSE_OFFSET_LEN;\n\n/**\n * This class provides static utility methods to work with byte streams.\n *\n * @Immutable\n */\n// Copyright 2008 Torsten Curdt\npublic class TarUtils {\n\n    private static final int BYTE_MASK = 255;\n\n    static final ZipEncoding DEFAULT_ENCODING =\n        ZipEncodingHelper.getZipEncoding(null);\n\n    /**\n     * Encapsulates the algorithms used up to Commons Compress 1.3 as\n     * ZipEncoding.\n     */\n    static final ZipEncoding FALLBACK_ENCODING = new ZipEncoding() {\n            @Override\n            public boolean canEncode(final String name) { return true; }\n\n            @Override\n            public ByteBuffer encode(final String name) {\n                final int length = name.length();\n                final byte[] buf = new byte[length];\n\n                // copy until end of input or output is reached.\n                for (int i = 0; i < length; ++i) {\n                    buf[i] = (byte) name.charAt(i);\n                }\n                return ByteBuffer.wrap(buf);\n            }\n\n            @Override\n            public String decode(final byte[] buffer) {\n                final int length = buffer.length;\n                final StringBuilder result = new StringBuilder(length);\n\n                for (final byte b : buffer) {\n                    if (b == 0) { // Trailing null\n                        break;\n                    }\n                    result.append((char) (b & 0xFF)); // Allow for sign-extension\n                }\n\n                return result.toString();\n            }\n        };\n\n    /** Private constructor to prevent instantiation of this utility class. */\n    private TarUtils(){\n    }\n\n    /**\n     * Parse an octal string from a buffer.\n     *\n     * <p>Leading spaces are ignored.\n     * The buffer must contain a trailing space or NUL,\n     * and may contain an additional trailing space or NUL.</p>\n     *\n     * <p>The input buffer is allowed to contain all NULs,\n     * in which case the method returns 0L\n     * (this allows for missing fields).</p>\n     *\n     * <p>To work-around some tar implementations that insert a\n     * leading NUL this method returns 0 if it detects a leading NUL\n     * since Commons Compress 1.4.</p>\n     *\n     * @param buffer The buffer from which to parse.\n     * @param offset The offset into the buffer from which to parse.\n     * @param length The maximum number of bytes to parse - must be at least 2 bytes.\n     * @return The long value of the octal string.\n     * @throws IllegalArgumentException if the trailing space/NUL is missing or if a invalid byte is detected.\n     */\n    public static long parseOctal(final byte[] buffer, final int offset, final int length) {\n        long    result = 0;\n        int     end = offset + length;\n        int     start = offset;\n\n        if (length < 2){\n            throw new IllegalArgumentException(\"Length \"+length+\" must be at least 2\");\n        }\n\n        if (buffer[start] == 0) {\n            return 0L;\n        }\n\n        // Skip leading spaces\n        while (start < end){\n            if (buffer[start] == ' '){\n                start++;\n            } else {\n                break;\n            }\n        }\n\n        // Trim all trailing NULs and spaces.\n        // The ustar and POSIX tar specs require a trailing NUL or\n        // space but some implementations use the extra digit for big\n        // sizes/uids/gids ...\n        byte trailer = buffer[end - 1];\n        while (start < end && (trailer == 0 || trailer == ' ')) {\n            end--;\n            trailer = buffer[end - 1];\n        }\n\n        for ( ;start < end; start++) {\n            final byte currentByte = buffer[start];\n            // CheckStyle:MagicNumber OFF\n            if (currentByte < '0' || currentByte > '7'){\n                throw new IllegalArgumentException(\n                        exceptionMessage(buffer, offset, length, start, currentByte));\n            }\n            result = (result << 3) + (currentByte - '0'); // convert from ASCII\n            // CheckStyle:MagicNumber ON\n        }\n\n        return result;\n    }\n\n    /**\n     * Compute the value contained in a byte buffer.  If the most\n     * significant bit of the first byte in the buffer is set, this\n     * bit is ignored and the rest of the buffer is interpreted as a\n     * binary number.  Otherwise, the buffer is interpreted as an\n     * octal number as per the parseOctal function above.\n     *\n     * @param buffer The buffer from which to parse.\n     * @param offset The offset into the buffer from which to parse.\n     * @param length The maximum number of bytes to parse.\n     * @return The long value of the octal or binary string.\n     * @throws IllegalArgumentException if the trailing space/NUL is\n     * missing or an invalid byte is detected in an octal number, or\n     * if a binary number would exceed the size of a signed long\n     * 64-bit integer.\n     * @since 1.4\n     */\n    public static long parseOctalOrBinary(final byte[] buffer, final int offset,\n                                          final int length) {\n\n        if ((buffer[offset] & 0x80) == 0) {\n            return parseOctal(buffer, offset, length);\n        }\n        final boolean negative = buffer[offset] == (byte) 0xff;\n        if (length < 9) {\n            return parseBinaryLong(buffer, offset, length, negative);\n        }\n        return parseBinaryBigInteger(buffer, offset, length, negative);\n    }\n\n    private static long parseBinaryLong(final byte[] buffer, final int offset,\n                                        final int length,\n                                        final boolean negative) {\n        if (length >= 9) {\n            throw new IllegalArgumentException(\"At offset \" + offset + \", \"\n                                               + length + \" byte binary number\"\n                                               + \" exceeds maximum signed long\"\n                                               + \" value\");\n        }\n        long val = 0;\n        for (int i = 1; i < length; i++) {\n            val = (val << 8) + (buffer[offset + i] & 0xff);\n        }\n        if (negative) {\n            // 2's complement\n            val--;\n            val ^= (long) Math.pow(2.0, (length - 1) * 8.0) - 1;\n        }\n        return negative ? -val : val;\n    }\n\n    private static long parseBinaryBigInteger(final byte[] buffer,\n                                              final int offset,\n                                              final int length,\n                                              final boolean negative) {\n        final byte[] remainder = new byte[length - 1];\n        System.arraycopy(buffer, offset + 1, remainder, 0, length - 1);\n        BigInteger val = new BigInteger(remainder);\n        if (negative) {\n            // 2's complement\n            val = val.add(BigInteger.valueOf(-1)).not();\n        }\n        if (val.bitLength() > 63) {\n            throw new IllegalArgumentException(\"At offset \" + offset + \", \"\n                                               + length + \" byte binary number\"\n                                               + \" exceeds maximum signed long\"\n                                               + \" value\");\n        }\n        return negative ? -val.longValue() : val.longValue();\n    }\n\n    /**\n     * Parse a boolean byte from a buffer.\n     * Leading spaces and NUL are ignored.\n     * The buffer may contain trailing spaces or NULs.\n     *\n     * @param buffer The buffer from which to parse.\n     * @param offset The offset into the buffer from which to parse.\n     * @return The boolean value of the bytes.\n     * @throws IllegalArgumentException if an invalid byte is detected.\n     */\n    public static boolean parseBoolean(final byte[] buffer, final int offset) {\n        return buffer[offset] == 1;\n    }\n\n    // Helper method to generate the exception message\n    private static String exceptionMessage(final byte[] buffer, final int offset,\n            final int length, final int current, final byte currentByte) {\n        // default charset is good enough for an exception message,\n        //\n        // the alternative was to modify parseOctal and\n        // parseOctalOrBinary to receive the ZipEncoding of the\n        // archive (deprecating the existing public methods, of\n        // course) and dealing with the fact that ZipEncoding#decode\n        // can throw an IOException which parseOctal* doesn't declare\n        String string = new String(buffer, offset, length);\n\n        string=string.replaceAll(\"\\0\", \"{NUL}\"); // Replace NULs to allow string to be printed\n        return \"Invalid byte \"+currentByte+\" at offset \"+(current-offset)+\" in '\"+string+\"' len=\"+length;\n    }\n\n    /**\n     * Parse an entry name from a buffer.\n     * Parsing stops when a NUL is found\n     * or the buffer length is reached.\n     *\n     * @param buffer The buffer from which to parse.\n     * @param offset The offset into the buffer from which to parse.\n     * @param length The maximum number of bytes to parse.\n     * @return The entry name.\n     */\n    public static String parseName(final byte[] buffer, final int offset, final int length) {\n        try {\n            return parseName(buffer, offset, length, DEFAULT_ENCODING);\n        } catch (final IOException ex) { // NOSONAR\n            try {\n                return parseName(buffer, offset, length, FALLBACK_ENCODING);\n            } catch (final IOException ex2) {\n                // impossible\n                throw new RuntimeException(ex2); //NOSONAR\n            }\n        }\n    }\n\n    /**\n     * Parse an entry name from a buffer.\n     * Parsing stops when a NUL is found\n     * or the buffer length is reached.\n     *\n     * @param buffer The buffer from which to parse.\n     * @param offset The offset into the buffer from which to parse.\n     * @param length The maximum number of bytes to parse.\n     * @param encoding name of the encoding to use for file names\n     * @since 1.4\n     * @return The entry name.\n     * @throws IOException on error\n     */\n    public static String parseName(final byte[] buffer, final int offset,\n                                   final int length,\n                                   final ZipEncoding encoding)\n        throws IOException {\n\n        int len = 0;\n        for (int i = offset; len < length && buffer[i] != 0; i++) {\n            len++;\n        }\n        if (len > 0) {\n            final byte[] b = new byte[len];\n            System.arraycopy(buffer, offset, b, 0, len);\n            return encoding.decode(b);\n        }\n        return \"\";\n    }\n\n    /**\n     * Parses the content of a PAX 1.0 sparse block.\n     * @since 1.20\n     * @param buffer The buffer from which to parse.\n     * @param offset The offset into the buffer from which to parse.\n     * @return a parsed sparse struct\n     */\n    public static TarArchiveStructSparse parseSparse(final byte[] buffer, final int offset) {\n        final long sparseOffset = parseOctalOrBinary(buffer, offset, SPARSE_OFFSET_LEN);\n        final long sparseNumbytes = parseOctalOrBinary(buffer, offset + SPARSE_OFFSET_LEN, SPARSE_NUMBYTES_LEN);\n\n        return new TarArchiveStructSparse(sparseOffset, sparseNumbytes);\n    }\n\n    /**\n     * Copy a name into a buffer.\n     * Copies characters from the name into the buffer\n     * starting at the specified offset.\n     * If the buffer is longer than the name, the buffer\n     * is filled with trailing NULs.\n     * If the name is longer than the buffer,\n     * the output is truncated.\n     *\n     * @param name The header name from which to copy the characters.\n     * @param buf The buffer where the name is to be stored.\n     * @param offset The starting offset into the buffer\n     * @param length The maximum number of header bytes to copy.\n     * @return The updated offset, i.e. offset + length\n     */\n    public static int formatNameBytes(final String name, final byte[] buf, final int offset, final int length) {\n        try {\n            return formatNameBytes(name, buf, offset, length, DEFAULT_ENCODING);\n        } catch (final IOException ex) { // NOSONAR\n            try {\n                return formatNameBytes(name, buf, offset, length,\n                                       FALLBACK_ENCODING);\n            } catch (final IOException ex2) {\n                // impossible\n                throw new RuntimeException(ex2); //NOSONAR\n            }\n        }\n    }\n\n    /**\n     * Copy a name into a buffer.\n     * Copies characters from the name into the buffer\n     * starting at the specified offset.\n     * If the buffer is longer than the name, the buffer\n     * is filled with trailing NULs.\n     * If the name is longer than the buffer,\n     * the output is truncated.\n     *\n     * @param name The header name from which to copy the characters.\n     * @param buf The buffer where the name is to be stored.\n     * @param offset The starting offset into the buffer\n     * @param length The maximum number of header bytes to copy.\n     * @param encoding name of the encoding to use for file names\n     * @since 1.4\n     * @return The updated offset, i.e. offset + length\n     * @throws IOException on error\n     */\n    public static int formatNameBytes(final String name, final byte[] buf, final int offset,\n                                      final int length,\n                                      final ZipEncoding encoding)\n        throws IOException {\n        int len = name.length();\n        ByteBuffer b = encoding.encode(name);\n        while (b.limit() > length && len > 0) {\n            b = encoding.encode(name.substring(0, --len));\n        }\n        final int limit = b.limit() - b.position();\n        System.arraycopy(b.array(), b.arrayOffset(), buf, offset, limit);\n\n        // Pad any remaining output bytes with NUL\n        for (int i = limit; i < length; ++i) {\n            buf[offset + i] = 0;\n        }\n\n        return offset + length;\n    }\n\n    /**\n     * Fill buffer with unsigned octal number, padded with leading zeroes.\n     *\n     * @param value number to convert to octal - treated as unsigned\n     * @param buffer destination buffer\n     * @param offset starting offset in buffer\n     * @param length length of buffer to fill\n     * @throws IllegalArgumentException if the value will not fit in the buffer\n     */\n    public static void formatUnsignedOctalString(final long value, final byte[] buffer,\n            final int offset, final int length) {\n        int remaining = length;\n        remaining--;\n        if (value == 0) {\n            buffer[offset + remaining--] = (byte) '0';\n        } else {\n            long val = value;\n            for (; remaining >= 0 && val != 0; --remaining) {\n                // CheckStyle:MagicNumber OFF\n                buffer[offset + remaining] = (byte) ((byte) '0' + (byte) (val & 7));\n                val = val >>> 3;\n                // CheckStyle:MagicNumber ON\n            }\n            if (val != 0){\n                throw new IllegalArgumentException\n                (value+\"=\"+Long.toOctalString(value)+ \" will not fit in octal number buffer of length \"+length);\n            }\n        }\n\n        for (; remaining >= 0; --remaining) { // leading zeros\n            buffer[offset + remaining] = (byte) '0';\n        }\n    }\n\n    /**\n     * Write an octal integer into a buffer.\n     *\n     * Uses {@link #formatUnsignedOctalString} to format\n     * the value as an octal string with leading zeros.\n     * The converted number is followed by space and NUL\n     *\n     * @param value The value to write\n     * @param buf The buffer to receive the output\n     * @param offset The starting offset into the buffer\n     * @param length The size of the output buffer\n     * @return The updated offset, i.e offset+length\n     * @throws IllegalArgumentException if the value (and trailer) will not fit in the buffer\n     */\n    public static int formatOctalBytes(final long value, final byte[] buf, final int offset, final int length) {\n\n        int idx=length-2; // For space and trailing null\n        formatUnsignedOctalString(value, buf, offset, idx);\n\n        buf[offset + idx++] = (byte) ' '; // Trailing space\n        buf[offset + idx]   = 0; // Trailing null\n\n        return offset + length;\n    }\n\n    /**\n     * Write an octal long integer into a buffer.\n     *\n     * Uses {@link #formatUnsignedOctalString} to format\n     * the value as an octal string with leading zeros.\n     * The converted number is followed by a space.\n     *\n     * @param value The value to write as octal\n     * @param buf The destinationbuffer.\n     * @param offset The starting offset into the buffer.\n     * @param length The length of the buffer\n     * @return The updated offset\n     * @throws IllegalArgumentException if the value (and trailer) will not fit in the buffer\n     */\n    public static int formatLongOctalBytes(final long value, final byte[] buf, final int offset, final int length) {\n\n        final int idx=length-1; // For space\n\n        formatUnsignedOctalString(value, buf, offset, idx);\n        buf[offset + idx] = (byte) ' '; // Trailing space\n\n        return offset + length;\n    }\n\n    /**\n     * Write an long integer into a buffer as an octal string if this\n     * will fit, or as a binary number otherwise.\n     *\n     * Uses {@link #formatUnsignedOctalString} to format\n     * the value as an octal string with leading zeros.\n     * The converted number is followed by a space.\n     *\n     * @param value The value to write into the buffer.\n     * @param buf The destination buffer.\n     * @param offset The starting offset into the buffer.\n     * @param length The length of the buffer.\n     * @return The updated offset.\n     * @throws IllegalArgumentException if the value (and trailer)\n     * will not fit in the buffer.\n     * @since 1.4\n     */\n    public static int formatLongOctalOrBinaryBytes(\n        final long value, final byte[] buf, final int offset, final int length) {\n\n        // Check whether we are dealing with UID/GID or SIZE field\n        final long maxAsOctalChar = length == TarConstants.UIDLEN ? TarConstants.MAXID : TarConstants.MAXSIZE;\n\n        final boolean negative = value < 0;\n        if (!negative && value <= maxAsOctalChar) { // OK to store as octal chars\n            return formatLongOctalBytes(value, buf, offset, length);\n        }\n\n        if (length < 9) {\n            formatLongBinary(value, buf, offset, length, negative);\n        } else {\n            formatBigIntegerBinary(value, buf, offset, length, negative);\n        }\n\n        buf[offset] = (byte) (negative ? 0xff : 0x80);\n        return offset + length;\n    }\n\n    private static void formatLongBinary(final long value, final byte[] buf,\n                                         final int offset, final int length,\n                                         final boolean negative) {\n        final int bits = (length - 1) * 8;\n        final long max = 1L << bits;\n        long val = Math.abs(value); // Long.MIN_VALUE stays Long.MIN_VALUE\n        if (val < 0 || val >= max) {\n            throw new IllegalArgumentException(\"Value \" + value +\n                \" is too large for \" + length + \" byte field.\");\n        }\n        if (negative) {\n            val ^= max - 1;\n            val++;\n            val |= 0xffL << bits;\n        }\n        for (int i = offset + length - 1; i >= offset; i--) {\n            buf[i] = (byte) val;\n            val >>= 8;\n        }\n    }\n\n    private static void formatBigIntegerBinary(final long value, final byte[] buf,\n                                               final int offset,\n                                               final int length,\n                                               final boolean negative) {\n        final BigInteger val = BigInteger.valueOf(value);\n        final byte[] b = val.toByteArray();\n        final int len = b.length;\n        if (len > length - 1) {\n            throw new IllegalArgumentException(\"Value \" + value +\n                \" is too large for \" + length + \" byte field.\");\n        }\n        final int off = offset + length - len;\n        System.arraycopy(b, 0, buf, off, len);\n        final byte fill = (byte) (negative ? 0xff : 0);\n        for (int i = offset + 1; i < off; i++) {\n            buf[i] = fill;\n        }\n    }\n\n    /**\n     * Writes an octal value into a buffer.\n     *\n     * Uses {@link #formatUnsignedOctalString} to format\n     * the value as an octal string with leading zeros.\n     * The converted number is followed by NUL and then space.\n     *\n     * @param value The value to convert\n     * @param buf The destination buffer\n     * @param offset The starting offset into the buffer.\n     * @param length The size of the buffer.\n     * @return The updated value of offset, i.e. offset+length\n     * @throws IllegalArgumentException if the value (and trailer) will not fit in the buffer\n     */\n    public static int formatCheckSumOctalBytes(final long value, final byte[] buf, final int offset, final int length) {\n\n        int idx=length-2; // for NUL and space\n        formatUnsignedOctalString(value, buf, offset, idx);\n\n        buf[offset + idx++]   = 0; // Trailing null\n        buf[offset + idx]     = (byte) ' '; // Trailing space\n\n        return offset + length;\n    }\n\n    /**\n     * Compute the checksum of a tar entry header.\n     *\n     * @param buf The tar entry's header buffer.\n     * @return The computed checksum.\n     */\n    public static long computeCheckSum(final byte[] buf) {\n        long sum = 0;\n\n        for (final byte element : buf) {\n            sum += BYTE_MASK & element;\n        }\n\n        return sum;\n    }\n\n    /**\n     * Wikipedia <a href=\"https://en.wikipedia.org/wiki/Tar_(file_format)#File_header\">says</a>:\n     * <blockquote>\n     * The checksum is calculated by taking the sum of the unsigned byte values\n     * of the header block with the eight checksum bytes taken to be ascii\n     * spaces (decimal value 32). It is stored as a six digit octal number with\n     * leading zeroes followed by a NUL and then a space. Various\n     * implementations do not adhere to this format. For better compatibility,\n     * ignore leading and trailing whitespace, and get the first six digits. In\n     * addition, some historic tar implementations treated bytes as signed.\n     * Implementations typically calculate the checksum both ways, and treat it\n     * as good if either the signed or unsigned sum matches the included\n     * checksum.\n     * </blockquote>\n     * <p>\n     * The return value of this method should be treated as a best-effort\n     * heuristic rather than an absolute and final truth. The checksum\n     * verification logic may well evolve over time as more special cases\n     * are encountered.\n     *\n     * @param header tar header\n     * @return whether the checksum is reasonably good\n     * @see <a href=\"https://issues.apache.org/jira/browse/COMPRESS-191\">COMPRESS-191</a>\n     * @since 1.5\n     */\n    public static boolean verifyCheckSum(final byte[] header) {\n        final long storedSum = parseOctal(header, CHKSUM_OFFSET, CHKSUMLEN);\n        long unsignedSum = 0;\n        long signedSum = 0;\n\n        for (int i = 0; i < header.length; i++) {\n            byte b = header[i];\n            if (CHKSUM_OFFSET  <= i && i < CHKSUM_OFFSET + CHKSUMLEN) {\n                b = ' ';\n            }\n            unsignedSum += 0xff & b;\n            signedSum += b;\n        }\n        return storedSum == unsignedSum || storedSum == signedSum;\n    }\n\n    /**\n     * For PAX Format 0.0, the sparse headers(GNU.sparse.offset and GNU.sparse.numbytes)\n     * may appear multi times, and they look like:\n     *\n     * GNU.sparse.size=size\n     * GNU.sparse.numblocks=numblocks\n     * repeat numblocks times\n     *   GNU.sparse.offset=offset\n     *   GNU.sparse.numbytes=numbytes\n     * end repeat\n     *\n     * For PAX Format 0.1, the sparse headers are stored in a single variable : GNU.sparse.map\n     *\n     * GNU.sparse.map\n     *    Map of non-null data chunks. It is a string consisting of comma-separated values \"offset,size[,offset-1,size-1...]\"\n     *\n     * @param inputStream inputstream to read keys and values\n     * @param sparseHeaders used in PAX Format 0.0 &amp; 0.1, as it may appear multi times,\n     *                      the sparse headers need to be stored in an array, not a map\n     * @param globalPaxHeaders global PAX headers of the tar archive\n     * @return map of PAX headers values found inside of the current (local or global) PAX headers tar entry.\n     * @throws IOException\n     */\n    @Deprecated\n    protected static Map<String, String> parsePaxHeaders(final InputStream inputStream, final List<TarArchiveStructSparse> sparseHeaders, final Map<String, String> globalPaxHeaders)\n            throws IOException {\n                return parsePaxHeaders(inputStream, sparseHeaders, globalPaxHeaders, -1);\n    }\n     /**\n     * For PAX Format 0.0, the sparse headers(GNU.sparse.offset and GNU.sparse.numbytes)\n     * may appear multi times, and they look like:\n     *\n     * GNU.sparse.size=size\n     * GNU.sparse.numblocks=numblocks\n     * repeat numblocks times\n     *   GNU.sparse.offset=offset\n     *   GNU.sparse.numbytes=numbytes\n     * end repeat\n     *\n     * For PAX Format 0.1, the sparse headers are stored in a single variable : GNU.sparse.map\n     *\n     * GNU.sparse.map\n     *    Map of non-null data chunks. It is a string consisting of comma-separated values \"offset,size[,offset-1,size-1...]\"\n     *\n     * @param inputStream input stream to read keys and values\n     * @param sparseHeaders used in PAX Format 0.0 &amp; 0.1, as it may appear multiple times,\n     *                      the sparse headers need to be stored in an array, not a map\n     * @param globalPaxHeaders global PAX headers of the tar archive\n     * @param headerSize total size of the PAX header, will be ignored if negative\n     * @return map of PAX headers values found inside of the current (local or global) PAX headers tar entry.\n     * @throws IOException if an I/O error occurs.\n     * @since 1.21\n     */\n    protected static Map<String, String> parsePaxHeaders(final InputStream inputStream,\n            final List<TarArchiveStructSparse> sparseHeaders, final Map<String, String> globalPaxHeaders,\n            final long headerSize) throws IOException {\n        final Map<String, String> headers = new HashMap<>(globalPaxHeaders);\n        Long offset = null;\n        // Format is \"length keyword=value\\n\";\n        int totalRead = 0;\n        while(true) { // get length\n            int ch;\n            int len = 0;\n            int read = 0;\n            while((ch = inputStream.read()) != -1) {\n                read++;\n                totalRead++;\n                if (ch == '\\n') { // blank line in header\n                    break;\n                } else if (ch == ' '){ // End of length string\n                    // Get keyword\n                    final ByteArrayOutputStream coll = new ByteArrayOutputStream();\n                    while((ch = inputStream.read()) != -1) {\n                        read++;\n                        totalRead++;\n                        if (totalRead < 0 || (headerSize >= 0 && totalRead >= headerSize)) {\n                             break;\n                         }\n                        if (ch == '='){ // end of keyword\n                            final String keyword = coll.toString(CharsetNames.UTF_8);\n                            // Get rest of entry\n                            final int restLen = len - read;\n                            if (restLen <= 1) { // only NL\n                                headers.remove(keyword);\n                            } else if (headerSize >= 0 && restLen > headerSize - totalRead) {\n                                throw new IOException(\"Paxheader value size \" + restLen\n                                    + \" exceeds size of header record\");\n\n                            } else {\n                                final byte[] rest = new byte[restLen];\n                                final int got = IOUtils.readFully(inputStream, rest);\n                                if (got != restLen) {\n                                    throw new IOException(\"Failed to read \"\n                                            + \"Paxheader. Expected \"\n                                            + restLen\n                                            + \" bytes, read \"\n                                            + got);\n                                }\n                                totalRead += restLen;\n                                // Drop trailing NL\n                                if (rest[restLen - 1] != '\\n') {\n                                    throw new IOException(\"Failed to read Paxheader.\"\n                                       + \"Value should end with a newline\");\n                                }\n                                final String value = new String(rest, 0,\n                                        restLen - 1, StandardCharsets.UTF_8);\n                                headers.put(keyword, value);\n\n                                // for 0.0 PAX Headers\n                                if (keyword.equals(\"GNU.sparse.offset\")) {\n                                    if (offset != null) {\n                                        // previous GNU.sparse.offset header but but no numBytes\n                                        sparseHeaders.add(new TarArchiveStructSparse(offset, 0));\n                                    }\n                                    offset = Long.valueOf(value);\n                                }\n\n                                // for 0.0 PAX Headers\n                                if (keyword.equals(\"GNU.sparse.numbytes\")) {\n                                    if (offset == null) {\n                                        throw new IOException(\"Failed to read Paxheader.\" +\n                                                \"GNU.sparse.offset is expected before GNU.sparse.numbytes shows up.\");\n                                    }\n                                    sparseHeaders.add(new TarArchiveStructSparse(offset, Long.parseLong(value)));\n                                    offset = null;\n                                }\n                            }\n                            break;\n                        }\n                        coll.write((byte) ch);\n                    }\n                    break; // Processed single header\n                }\n\n                // COMPRESS-530 : throw if we encounter a non-number while reading length\n                if (ch < '0' || ch > '9') {\n                    throw new IOException(\"Failed to read Paxheader. Encountered a non-number while reading length\");\n                }\n\n                len *= 10;\n                len += ch - '0';\n            }\n            if (ch == -1){ // EOF\n                break;\n            }\n        }\n        if (offset != null) {\n            // offset but no numBytes\n            sparseHeaders.add(new TarArchiveStructSparse(offset, 0));\n        }\n        return headers;\n    }\n\n    /**\n     * For PAX Format 0.1, the sparse headers are stored in a single variable : GNU.sparse.map\n     * GNU.sparse.map\n     *    Map of non-null data chunks. It is a string consisting of comma-separated values \"offset,size[,offset-1,size-1...]\"\n     *\n     * @param sparseMap the sparse map string consisting of comma-separated values \"offset,size[,offset-1,size-1...]\"\n     * @return sparse headers parsed from sparse map\n     */\n    protected static List<TarArchiveStructSparse> parsePAX01SparseHeaders(String sparseMap) {\n        List<TarArchiveStructSparse> sparseHeaders = new ArrayList<>();\n        String[] sparseHeaderStrings = sparseMap.split(\",\");\n\n        for (int i = 0; i < sparseHeaderStrings.length; i += 2) {\n            long sparseOffset = Long.parseLong(sparseHeaderStrings[i]);\n            long sparseNumbytes = Long.parseLong(sparseHeaderStrings[i + 1]);\n            sparseHeaders.add(new TarArchiveStructSparse(sparseOffset, sparseNumbytes));\n        }\n\n        return sparseHeaders;\n    }\n\n    /**\n     * For PAX Format 1.X:\n     * The sparse map itself is stored in the file data block, preceding the actual file data.\n     * It consists of a series of decimal numbers delimited by newlines. The map is padded with nulls to the nearest block boundary.\n     * The first number gives the number of entries in the map. Following are map entries, each one consisting of two numbers\n     * giving the offset and size of the data block it describes.\n     * @param inputStream\n     * @param recordSize\n     * @return sparse headers\n     * @throws IOException\n     */\n    protected static List<TarArchiveStructSparse> parsePAX1XSparseHeaders(final InputStream inputStream, final int recordSize) throws IOException {\n        // for 1.X PAX Headers\n        List<TarArchiveStructSparse> sparseHeaders = new ArrayList<>();\n        long bytesRead = 0;\n\n        long[] readResult = readLineOfNumberForPax1X(inputStream);\n        long sparseHeadersCount = readResult[0];\n        bytesRead += readResult[1];\n        while (sparseHeadersCount-- > 0) {\n            readResult = readLineOfNumberForPax1X(inputStream);\n            long sparseOffset = readResult[0];\n            bytesRead += readResult[1];\n\n            readResult = readLineOfNumberForPax1X(inputStream);\n            long sparseNumbytes = readResult[0];\n            bytesRead += readResult[1];\n            sparseHeaders.add(new TarArchiveStructSparse(sparseOffset, sparseNumbytes));\n        }\n\n        // skip the rest of this record data\n        long bytesToSkip = recordSize - bytesRead % recordSize;\n        IOUtils.skip(inputStream, bytesToSkip);\n        return sparseHeaders;\n    }\n\n    /**\n     * For 1.X PAX Format, the sparse headers are stored in the file data block, preceding the actual file data.\n     * It consists of a series of decimal numbers delimited by newlines.\n     *\n     * @param inputStream the input stream of the tar file\n     * @return the decimal number delimited by '\\n', and the bytes read from input stream\n     * @throws IOException\n     */\n    private static long[] readLineOfNumberForPax1X(final InputStream inputStream) throws IOException {\n        int number;\n        long result = 0;\n        long bytesRead = 0;\n\n        while ((number = inputStream.read()) != '\\n') {\n            bytesRead += 1;\n            if (number == -1) {\n                throw new IOException(\"Unexpected EOF when reading parse information of 1.X PAX format\");\n            }\n            result = result * 10 + (number - '0');\n        }\n        bytesRead += 1;\n\n        return new long[]{result, bytesRead};\n    }\n\n}"
  },
  {
    "path": "app/src/main/java/org/apache/commons/compress/archivers/zip/CharsetAccessor.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage org.apache.commons.compress.archivers.zip;\n\nimport java.nio.charset.Charset;\n\n/**\n * An interface added to allow access to the character set associated with an {@link NioZipEncoding},\n * without requiring a new method to be added to {@link ZipEncoding}.\n * <p>\n * This avoids introducing a\n * potentially breaking change, or making {@link NioZipEncoding} a public class.\n * </p>\n * @since 1.15\n */\n// Copyright 2017 Gary Gregory\npublic interface CharsetAccessor {\n\n    /**\n     * Provides access to the character set associated with an object.\n     * <p>\n     *     This allows nio oriented code to use more natural character encoding/decoding methods,\n     *     whilst allowing existing code to continue to rely on special-case error handling for UTF-8.\n     * </p>\n     * @return the character set associated with this object\n     */\n    Charset getCharset();\n}"
  },
  {
    "path": "app/src/main/java/org/apache/commons/compress/archivers/zip/NioZipEncoding.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage org.apache.commons.compress.archivers.zip;\n\nimport java.io.IOException;\nimport java.nio.ByteBuffer;\nimport java.nio.CharBuffer;\nimport java.nio.charset.Charset;\nimport java.nio.charset.CharsetDecoder;\nimport java.nio.charset.CharsetEncoder;\nimport java.nio.charset.CoderResult;\nimport java.nio.charset.CodingErrorAction;\n\n/**\n * A ZipEncoding, which uses a java.nio {@link\n * java.nio.charset.Charset Charset} to encode names.\n * <p>The methods of this class are reentrant.</p>\n * @Immutable\n */\n// Copyright 2009 Stefan Bodewig\nclass NioZipEncoding implements ZipEncoding, CharsetAccessor {\n\n    private final Charset charset;\n    private final boolean useReplacement;\n    private static final char REPLACEMENT = '?';\n    private static final byte[] REPLACEMENT_BYTES = { (byte) REPLACEMENT };\n    private static final String REPLACEMENT_STRING = String.valueOf(REPLACEMENT);\n    private static final char[] HEX_CHARS = new char[] {\n        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'\n    };\n\n\n    /**\n     * Construct an NioZipEncoding using the given charset.\n     * @param charset  The character set to use.\n     * @param useReplacement should invalid characters be replaced, or reported.\n     */\n    NioZipEncoding(final Charset charset, final boolean useReplacement) {\n        this.charset = charset;\n        this.useReplacement = useReplacement;\n    }\n\n    @Override\n    public Charset getCharset() {\n        return charset;\n    }\n\n    /**\n     * @see  ZipEncoding#canEncode(java.lang.String)\n     */\n    @Override\n    public boolean canEncode(final String name) {\n        final CharsetEncoder enc = newEncoder();\n\n        return enc.canEncode(name);\n    }\n\n    /**\n     * @see ZipEncoding#encode(java.lang.String)\n     */\n    @Override\n    public ByteBuffer encode(final String name) {\n        final CharsetEncoder enc = newEncoder();\n\n        final CharBuffer cb = CharBuffer.wrap(name);\n        CharBuffer tmp = null;\n        ByteBuffer out = ByteBuffer.allocate(estimateInitialBufferSize(enc, cb.remaining()));\n\n        while (cb.hasRemaining()) {\n            final CoderResult res = enc.encode(cb, out, false);\n\n            if (res.isUnmappable() || res.isMalformed()) {\n\n                // write the unmappable characters in utf-16\n                // pseudo-URL encoding style to ByteBuffer.\n\n                final int spaceForSurrogate = estimateIncrementalEncodingSize(enc, 6 * res.length());\n                if (spaceForSurrogate > out.remaining()) {\n                    // if the destination buffer isn't over sized, assume that the presence of one\n                    // unmappable character makes it likely that there will be more. Find all the\n                    // un-encoded characters and allocate space based on those estimates.\n                    int charCount = 0;\n                    for (int i = cb.position() ; i < cb.limit(); i++) {\n                        charCount += !enc.canEncode(cb.get(i)) ? 6 : 1;\n                    }\n                    final int totalExtraSpace = estimateIncrementalEncodingSize(enc, charCount);\n                    out = ZipEncodingHelper.growBufferBy(out, totalExtraSpace - out.remaining());\n                }\n                if (tmp == null) {\n                    tmp = CharBuffer.allocate(6);\n                }\n                for (int i = 0; i < res.length(); ++i) {\n                    out = encodeFully(enc, encodeSurrogate(tmp, cb.get()), out);\n                }\n\n            } else if (res.isOverflow()) {\n                final int increment = estimateIncrementalEncodingSize(enc, cb.remaining());\n                out = ZipEncodingHelper.growBufferBy(out, increment);\n\n            } else if (res.isUnderflow() || res.isError()) {\n                break;\n            }\n        }\n        // tell the encoder we are done\n        enc.encode(cb, out, true);\n        // may have caused underflow, but that's been ignored traditionally\n\n        out.limit(out.position());\n        out.rewind();\n        return out;\n    }\n\n    /**\n     * @see ZipEncoding#decode(byte[])\n     */\n    @Override\n    public String decode(final byte[] data) throws IOException {\n        return newDecoder()\n            .decode(ByteBuffer.wrap(data)).toString();\n    }\n\n    private static ByteBuffer encodeFully(final CharsetEncoder enc, final CharBuffer cb, final ByteBuffer out) {\n        ByteBuffer o = out;\n        while (cb.hasRemaining()) {\n            final CoderResult result = enc.encode(cb, o, false);\n            if (result.isOverflow()) {\n                final int increment = estimateIncrementalEncodingSize(enc, cb.remaining());\n                o = ZipEncodingHelper.growBufferBy(o, increment);\n            }\n        }\n        return o;\n    }\n\n    private static CharBuffer encodeSurrogate(final CharBuffer cb, final char c) {\n        cb.position(0).limit(6);\n        cb.put('%');\n        cb.put('U');\n\n        cb.put(HEX_CHARS[(c >> 12) & 0x0f]);\n        cb.put(HEX_CHARS[(c >> 8) & 0x0f]);\n        cb.put(HEX_CHARS[(c >> 4) & 0x0f]);\n        cb.put(HEX_CHARS[c & 0x0f]);\n        cb.flip();\n        return cb;\n    }\n\n    private CharsetEncoder newEncoder() {\n        if (useReplacement) {\n            return charset.newEncoder()\n                .onMalformedInput(CodingErrorAction.REPLACE)\n                .onUnmappableCharacter(CodingErrorAction.REPLACE)\n                .replaceWith(REPLACEMENT_BYTES);\n        }\n        return charset.newEncoder()\n            .onMalformedInput(CodingErrorAction.REPORT)\n            .onUnmappableCharacter(CodingErrorAction.REPORT);\n    }\n\n    private CharsetDecoder newDecoder() {\n        if (!useReplacement) {\n            return this.charset.newDecoder()\n                .onMalformedInput(CodingErrorAction.REPORT)\n                .onUnmappableCharacter(CodingErrorAction.REPORT);\n        }\n        return  charset.newDecoder()\n            .onMalformedInput(CodingErrorAction.REPLACE)\n            .onUnmappableCharacter(CodingErrorAction.REPLACE)\n            .replaceWith(REPLACEMENT_STRING);\n    }\n\n    /**\n     * Estimate the initial encoded size (in bytes) for a character buffer.\n     * <p>\n     * The estimate assumes that one character consumes uses the maximum length encoding,\n     * whilst the rest use an average size encoding. This accounts for any BOM for UTF-16, at\n     * the expense of a couple of extra bytes for UTF-8 encoded ASCII.\n     * </p>\n     *\n     * @param enc        encoder to use for estimates\n     * @param charChount number of characters in string\n     * @return estimated size in bytes.\n     */\n    private static int estimateInitialBufferSize(final CharsetEncoder enc, final int charChount) {\n        final float first = enc.maxBytesPerChar();\n        final float rest = (charChount - 1) * enc.averageBytesPerChar();\n        return (int) Math.ceil(first + rest);\n    }\n\n    /**\n     * Estimate the size needed for remaining characters\n     *\n     * @param enc       encoder to use for estimates\n     * @param charCount number of characters remaining\n     * @return estimated size in bytes.\n     */\n    private static int estimateIncrementalEncodingSize(final CharsetEncoder enc, final int charCount) {\n        return (int) Math.ceil(charCount * enc.averageBytesPerChar());\n    }\n\n}"
  },
  {
    "path": "app/src/main/java/org/apache/commons/compress/archivers/zip/ZipEncoding.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage org.apache.commons.compress.archivers.zip;\n\nimport java.io.IOException;\nimport java.nio.ByteBuffer;\n\n/**\n * An interface for encoders that do a pretty encoding of ZIP\n * file names.\n *\n * <p>There are mostly two implementations, one that uses java.nio\n * {@link java.nio.charset.Charset Charset} and one implementation,\n * which copes with simple 8 bit charsets, because java-1.4 did not\n * support Cp437 in java.nio.</p>\n *\n * <p>The main reason for defining an own encoding layer comes from\n * the problems with {@link java.lang.String#getBytes(String)\n * String.getBytes}, which encodes unknown characters as ASCII\n * quotation marks ('?'). Quotation marks are per definition an\n * invalid file name on some operating systems  like Windows, which\n * leads to ignored ZIP entries.</p>\n *\n * <p>All implementations should implement this interface in a\n * reentrant way.</p>\n */\n// Copyright 2009 Stefan Bodewig\npublic interface ZipEncoding {\n    /**\n     * Check, whether the given string may be losslessly encoded using this\n     * encoding.\n     *\n     * @param name A file name or ZIP comment.\n     * @return Whether the given name may be encoded with out any losses.\n     */\n    boolean canEncode(String name);\n\n    /**\n     * Encode a file name or a comment to a byte array suitable for\n     * storing it to a serialized zip entry.\n     *\n     * <p>Examples for CP 437 (in pseudo-notation, right hand side is\n     * C-style notation):</p>\n     * <pre>\n     *  encode(\"\\u20AC_for_Dollar.txt\") = \"%U20AC_for_Dollar.txt\"\n     *  encode(\"\\u00D6lf\\u00E4sser.txt\") = \"\\231lf\\204sser.txt\"\n     * </pre>\n     *\n     * @param name A file name or ZIP comment.\n     * @return A byte buffer with a backing array containing the\n     *         encoded name.  Unmappable characters or malformed\n     *         character sequences are mapped to a sequence of utf-16\n     *         words encoded in the format <code>%Uxxxx</code>.  It is\n     *         assumed, that the byte buffer is positioned at the\n     *         beginning of the encoded result, the byte buffer has a\n     *         backing array and the limit of the byte buffer points\n     *         to the end of the encoded result.\n     * @throws IOException on error\n     */\n    ByteBuffer encode(String name) throws IOException;\n\n    /**\n     * @param data The byte values to decode.\n     * @return The decoded string.\n     * @throws IOException on error\n     */\n    String decode(byte [] data) throws IOException;\n}"
  },
  {
    "path": "app/src/main/java/org/apache/commons/compress/archivers/zip/ZipEncodingHelper.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage org.apache.commons.compress.archivers.zip;\n\nimport java.nio.ByteBuffer;\nimport java.nio.charset.Charset;\nimport java.nio.charset.StandardCharsets;\nimport java.nio.charset.UnsupportedCharsetException;\n\n/**\n * Static helper functions for robustly encoding file names in zip files.\n */\n// Copyright 2009 Stefan Bodewig\npublic abstract class ZipEncodingHelper {\n\n\n    /**\n     * name of the encoding UTF-8\n     */\n    static final String UTF8 = \"UTF8\";\n\n    /**\n     * the encoding UTF-8\n     */\n    static final ZipEncoding UTF8_ZIP_ENCODING = getZipEncoding(UTF8);\n\n    /**\n     * Instantiates a zip encoding. An NIO based character set encoder/decoder will be returned.\n     * As a special case, if the character set is UTF-8, the nio encoder will be configured  replace malformed and\n     * unmappable characters with '?'. This matches existing behavior from the older fallback encoder.\n     * <p>\n     *     If the requested character set cannot be found, the platform default will\n     *     be used instead.\n     * </p>\n     * @param name The name of the zip encoding. Specify {@code null} for\n     *             the platform's default encoding.\n     * @return A zip encoding for the given encoding name.\n     */\n    public static ZipEncoding getZipEncoding(final String name) {\n        Charset cs = Charset.defaultCharset();\n        if (name != null) {\n            try {\n                cs = Charset.forName(name);\n            } catch (final UnsupportedCharsetException e) { // NOSONAR we use the default encoding instead\n            }\n        }\n        final boolean useReplacement = isUTF8(cs.name());\n        return new NioZipEncoding(cs, useReplacement);\n    }\n\n    /**\n     * Returns whether a given encoding is UTF-8. If the given name is null, then check the platform's default encoding.\n     *\n     * @param charsetName If the given name is null, then check the platform's default encoding.\n     */\n    static boolean isUTF8(String charsetName) {\n        if (charsetName == null) {\n            // check platform's default encoding\n            charsetName = Charset.defaultCharset().name();\n        }\n        if (StandardCharsets.UTF_8.name().equalsIgnoreCase(charsetName)) {\n            return true;\n        }\n        for (final String alias : StandardCharsets.UTF_8.aliases()) {\n            if (alias.equalsIgnoreCase(charsetName)) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    static ByteBuffer growBufferBy(final ByteBuffer buffer, final int increment) {\n        buffer.limit(buffer.position());\n        buffer.rewind();\n\n        final ByteBuffer on = ByteBuffer.allocate(buffer.capacity() + increment);\n\n        on.put(buffer);\n        return on;\n    }\n}"
  },
  {
    "path": "app/src/main/java/org/apache/commons/compress/compressors/CompressorInputStream.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage org.apache.commons.compress.compressors;\n\nimport java.io.InputStream;\n\n// Copyright 2008 Torsten Curdt\npublic abstract class CompressorInputStream extends InputStream {\n    private long bytesRead = 0;\n\n    /**\n     * Increments the counter of already read bytes.\n     * Doesn't increment if the EOF has been hit (read == -1)\n     *\n     * @param read the number of bytes read\n     *\n     * @since 1.1\n     */\n    protected void count(final int read) {\n        count((long) read);\n    }\n\n    /**\n     * Increments the counter of already read bytes.\n     * Doesn't increment if the EOF has been hit (read == -1)\n     *\n     * @param read the number of bytes read\n     */\n    protected void count(final long read) {\n        if (read != -1) {\n            bytesRead = bytesRead + read;\n        }\n    }\n\n    /**\n     * Decrements the counter of already read bytes.\n     *\n     * @param pushedBack the number of bytes pushed back.\n     * @since 1.7\n     */\n    protected void pushedBackBytes(final long pushedBack) {\n        bytesRead -= pushedBack;\n    }\n\n    /**\n     * Returns the current number of bytes read from this stream.\n     * @return the number of read bytes\n     * @deprecated this method may yield wrong results for large\n     * archives, use #getBytesRead instead\n     */\n    @Deprecated\n    public int getCount() {\n        return (int) bytesRead;\n    }\n\n    /**\n     * Returns the current number of bytes read from this stream.\n     * @return the number of read bytes\n     *\n     * @since 1.1\n     */\n    public long getBytesRead() {\n        return bytesRead;\n    }\n\n    /**\n     * Returns the amount of raw or compressed bytes read by the stream.\n     *\n     * <p>This implementation invokes {@link #getBytesRead}.</p>\n     *\n     * <p>Provides half of {@link\n     * org.apache.commons.compress.utils.InputStreamStatistics}\n     * without forcing subclasses to implement the other half.</p>\n     *\n     * @return the amount of decompressed bytes returned by the stream\n     * @since 1.17\n     */\n    public long getUncompressedCount() {\n        return getBytesRead();\n    }\n}"
  },
  {
    "path": "app/src/main/java/org/apache/commons/compress/compressors/CompressorOutputStream.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage org.apache.commons.compress.compressors;\n\nimport java.io.OutputStream;\n\n// Copyright 2008 Torsten Curdt\npublic abstract class CompressorOutputStream extends OutputStream {\n    // TODO\n}"
  },
  {
    "path": "app/src/main/java/org/apache/commons/compress/compressors/FileNameUtil.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage org.apache.commons.compress.compressors;\n\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.Locale;\nimport java.util.Map;\n\n/**\n * File name mapping code for the compression formats.\n * @ThreadSafe\n * @since 1.4\n */\n// Copyright 2011 Stefan Bodewig\npublic class FileNameUtil {\n\n    /**\n     * Map from common file name suffixes to the suffixes that identify compressed\n     * versions of those file types. For example: from \".tar\" to \".tgz\".\n     */\n    private final Map<String, String> compressSuffix =\n        new HashMap<>();\n\n    /**\n     * Map from common file name suffixes of compressed files to the\n     * corresponding suffixes of uncompressed files. For example: from\n     * \".tgz\" to \".tar\".\n     * <p>\n     * This map also contains format-specific suffixes like \".gz\" and \"-z\".\n     * These suffixes are mapped to the empty string, as they should simply\n     * be removed from the file name when the file is uncompressed.\n     */\n    private final Map<String, String> uncompressSuffix;\n\n    /**\n     * Length of the longest compressed suffix.\n     */\n    private final int longestCompressedSuffix;\n\n    /**\n     * Length of the shortest compressed suffix.\n     */\n    private final int shortestCompressedSuffix;\n\n    /**\n     * Length of the longest uncompressed suffix.\n     */\n    private final int longestUncompressedSuffix;\n\n    /**\n     * Length of the shortest uncompressed suffix longer than the\n     * empty string.\n     */\n    private final int shortestUncompressedSuffix;\n\n    /**\n     * The format's default extension.\n     */\n    private final String defaultExtension;\n\n    /**\n     * sets up the utility with a map of known compressed to\n     * uncompressed suffix mappings and the default extension of the\n     * format.\n     *\n     * @param uncompressSuffix Map from common file name suffixes of\n     * compressed files to the corresponding suffixes of uncompressed\n     * files. For example: from \".tgz\" to \".tar\".  This map also\n     * contains format-specific suffixes like \".gz\" and \"-z\".  These\n     * suffixes are mapped to the empty string, as they should simply\n     * be removed from the file name when the file is uncompressed.\n     *\n     * @param defaultExtension the format's default extension like \".gz\"\n     */\n    public FileNameUtil(final Map<String, String> uncompressSuffix,\n                        final String defaultExtension) {\n        this.uncompressSuffix = Collections.unmodifiableMap(uncompressSuffix);\n        int lc = Integer.MIN_VALUE, sc = Integer.MAX_VALUE;\n        int lu = Integer.MIN_VALUE, su = Integer.MAX_VALUE;\n        for (final Map.Entry<String, String> ent : uncompressSuffix.entrySet()) {\n            final int cl = ent.getKey().length();\n            if (cl > lc) {\n                lc = cl;\n            }\n            if (cl < sc) {\n                sc = cl;\n            }\n\n            final String u = ent.getValue();\n            final int ul = u.length();\n            if (ul > 0) {\n                if (!compressSuffix.containsKey(u)) {\n                    compressSuffix.put(u, ent.getKey());\n                }\n                if (ul > lu) {\n                    lu = ul;\n                }\n                if (ul < su) {\n                    su = ul;\n                }\n            }\n        }\n        longestCompressedSuffix = lc;\n        longestUncompressedSuffix = lu;\n        shortestCompressedSuffix = sc;\n        shortestUncompressedSuffix = su;\n        this.defaultExtension = defaultExtension;\n    }\n\n    /**\n     * Detects common format suffixes in the given file name.\n     *\n     * @param fileName name of a file\n     * @return {@code true} if the file name has a common format suffix,\n     *         {@code false} otherwise\n     */\n    public boolean isCompressedFilename(final String fileName) {\n        final String lower = fileName.toLowerCase(Locale.ENGLISH);\n        final int n = lower.length();\n        for (int i = shortestCompressedSuffix;\n             i <= longestCompressedSuffix && i < n; i++) {\n            if (uncompressSuffix.containsKey(lower.substring(n - i))) {\n                return true;\n            }\n        }\n        return false;\n    }\n\n    /**\n     * Maps the given name of a compressed file to the name that the\n     * file should have after uncompression. Commonly used file type specific\n     * suffixes like \".tgz\" or \".svgz\" are automatically detected and\n     * correctly mapped. For example the name \"package.tgz\" is mapped to\n     * \"package.tar\". And any file names with the generic \".gz\" suffix\n     * (or any other generic gzip suffix) is mapped to a name without that\n     * suffix. If no format suffix is detected, then the file name is returned\n     * unmapped.\n     *\n     * @param fileName name of a file\n     * @return name of the corresponding uncompressed file\n     */\n    public String getUncompressedFilename(final String fileName) {\n        final String lower = fileName.toLowerCase(Locale.ENGLISH);\n        final int n = lower.length();\n        for (int i = shortestCompressedSuffix;\n             i <= longestCompressedSuffix && i < n; i++) {\n            final String suffix = uncompressSuffix.get(lower.substring(n - i));\n            if (suffix != null) {\n                return fileName.substring(0, n - i) + suffix;\n            }\n        }\n        return fileName;\n    }\n\n    /**\n     * Maps the given file name to the name that the file should have after\n     * compression. Common file types with custom suffixes for\n     * compressed versions are automatically detected and correctly mapped.\n     * For example the name \"package.tar\" is mapped to \"package.tgz\". If no\n     * custom mapping is applicable, then the default \".gz\" suffix is appended\n     * to the file name.\n     *\n     * @param fileName name of a file\n     * @return name of the corresponding compressed file\n     */\n    public String getCompressedFilename(final String fileName) {\n        final String lower = fileName.toLowerCase(Locale.ENGLISH);\n        final int n = lower.length();\n        for (int i = shortestUncompressedSuffix;\n             i <= longestUncompressedSuffix && i < n; i++) {\n            final String suffix = compressSuffix.get(lower.substring(n - i));\n            if (suffix != null) {\n                return fileName.substring(0, n - i) + suffix;\n            }\n        }\n        // No custom suffix found, just append the default\n        return fileName + defaultExtension;\n    }\n}"
  },
  {
    "path": "app/src/main/java/org/apache/commons/compress/compressors/bzip2/BZip2CompressorInputStream.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage org.apache.commons.compress.compressors.bzip2;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.nio.ByteOrder;\nimport java.util.Arrays;\n\nimport org.apache.commons.compress.compressors.CompressorInputStream;\nimport org.apache.commons.compress.utils.BitInputStream;\nimport org.apache.commons.compress.utils.CloseShieldFilterInputStream;\nimport org.apache.commons.compress.utils.InputStreamStatistics;\n\n/**\n * An input stream that decompresses from the BZip2 format to be read as any other stream.\n *\n * @NotThreadSafe\n */\n// Copyright 2008 Torsten Curdt\npublic class BZip2CompressorInputStream extends CompressorInputStream\n        implements BZip2Constants, InputStreamStatistics {\n\n    /**\n     * Index of the last char in the block, so the block size == last + 1.\n     */\n    private int last;\n\n    /**\n     * Index in zptr[] of original string after sorting.\n     */\n    private int origPtr;\n\n    /**\n     * always: in the range 0 .. 9. The current block size is 100000 * this\n     * number.\n     */\n    private int blockSize100k;\n\n    private boolean blockRandomised;\n\n    private final CRC crc = new CRC();\n\n    private int nInUse;\n\n    private BitInputStream bin;\n    private final boolean decompressConcatenated;\n\n    private static final int EOF = 0;\n    private static final int START_BLOCK_STATE = 1;\n    private static final int RAND_PART_A_STATE = 2;\n    private static final int RAND_PART_B_STATE = 3;\n    private static final int RAND_PART_C_STATE = 4;\n    private static final int NO_RAND_PART_A_STATE = 5;\n    private static final int NO_RAND_PART_B_STATE = 6;\n    private static final int NO_RAND_PART_C_STATE = 7;\n\n    private int currentState = START_BLOCK_STATE;\n\n    private int storedBlockCRC, storedCombinedCRC;\n    private int computedBlockCRC, computedCombinedCRC;\n\n    // Variables used by setup* methods exclusively\n\n    private int su_count;\n    private int su_ch2;\n    private int su_chPrev;\n    private int su_i2;\n    private int su_j2;\n    private int su_rNToGo;\n    private int su_rTPos;\n    private int su_tPos;\n    private char su_z;\n\n    /**\n     * All memory intensive stuff. This field is initialized by initBlock().\n     */\n    private BZip2CompressorInputStream.Data data;\n\n    /**\n     * Constructs a new BZip2CompressorInputStream which decompresses bytes\n     * read from the specified stream. This doesn't support decompressing\n     * concatenated .bz2 files.\n     *\n     * @param in the InputStream from which this object should be created\n     * @throws IOException\n     *             if the stream content is malformed or an I/O error occurs.\n     * @throws NullPointerException\n     *             if {@code in == null}\n     */\n    public BZip2CompressorInputStream(final InputStream in) throws IOException {\n        this(in, false);\n    }\n\n    /**\n     * Constructs a new BZip2CompressorInputStream which decompresses bytes\n     * read from the specified stream.\n     *\n     * @param in the InputStream from which this object should be created\n     * @param decompressConcatenated\n     *                     if true, decompress until the end of the input;\n     *                     if false, stop after the first .bz2 stream and\n     *                     leave the input position to point to the next\n     *                     byte after the .bz2 stream\n     *\n     * @throws IOException\n     *             if {@code in == null}, the stream content is malformed, or an I/O error occurs.\n     */\n    public BZip2CompressorInputStream(final InputStream in, final boolean decompressConcatenated) throws IOException {\n        this.bin = new BitInputStream(in == System.in ? new CloseShieldFilterInputStream(in) : in,\n                ByteOrder.BIG_ENDIAN);\n        this.decompressConcatenated = decompressConcatenated;\n\n        init(true);\n        initBlock();\n    }\n\n    @Override\n    public int read() throws IOException {\n        if (this.bin != null) {\n            final int r = read0();\n            count(r < 0 ? -1 : 1);\n            return r;\n        }\n        throw new IOException(\"Stream closed\");\n    }\n\n    /*\n     * (non-Javadoc)\n     *\n     * @see java.io.InputStream#read(byte[], int, int)\n     */\n    @Override\n    public int read(final byte[] dest, final int offs, final int len)\n            throws IOException {\n        if (offs < 0) {\n            throw new IndexOutOfBoundsException(\"offs(\" + offs + \") < 0.\");\n        }\n        if (len < 0) {\n            throw new IndexOutOfBoundsException(\"len(\" + len + \") < 0.\");\n        }\n        if (offs + len > dest.length) {\n            throw new IndexOutOfBoundsException(\"offs(\" + offs + \") + len(\"\n                    + len + \") > dest.length(\" + dest.length + \").\");\n        }\n        if (this.bin == null) {\n            throw new IOException(\"Stream closed\");\n        }\n        if (len == 0) {\n            return 0;\n        }\n\n        final int hi = offs + len;\n        int destOffs = offs;\n        int b;\n        while (destOffs < hi && ((b = read0()) >= 0)) {\n            dest[destOffs++] = (byte) b;\n            count(1);\n        }\n\n        return (destOffs == offs) ? -1 : (destOffs - offs);\n    }\n\n    /**\n     * @since 1.17\n     */\n    @Override\n    public long getCompressedCount() {\n        return bin.getBytesRead();\n    }\n\n    private void makeMaps() {\n        final boolean[] inUse = this.data.inUse;\n        final byte[] seqToUnseq = this.data.seqToUnseq;\n\n        int nInUseShadow = 0;\n\n        for (int i = 0; i < 256; i++) {\n            if (inUse[i]) {\n                seqToUnseq[nInUseShadow++] = (byte) i;\n            }\n        }\n\n        this.nInUse = nInUseShadow;\n    }\n\n    private int read0() throws IOException {\n        switch (currentState) {\n            case EOF:\n                return -1;\n\n            case START_BLOCK_STATE:\n                return setupBlock();\n\n            case RAND_PART_A_STATE:\n                throw new IllegalStateException();\n\n            case RAND_PART_B_STATE:\n                return setupRandPartB();\n\n            case RAND_PART_C_STATE:\n                return setupRandPartC();\n\n            case NO_RAND_PART_A_STATE:\n                throw new IllegalStateException();\n\n            case NO_RAND_PART_B_STATE:\n                return setupNoRandPartB();\n\n            case NO_RAND_PART_C_STATE:\n                return setupNoRandPartC();\n\n            default:\n                throw new IllegalStateException();\n        }\n    }\n\n    private int readNextByte(final BitInputStream in) throws IOException {\n        final long b = in.readBits(8);\n        return (int) b;\n    }\n\n    private boolean init(final boolean isFirstStream) throws IOException {\n        if (null == bin) {\n            throw new IOException(\"No InputStream\");\n        }\n\n        if (!isFirstStream) {\n            bin.clearBitCache();\n        }\n\n        final int magic0 = readNextByte(this.bin);\n        if (magic0 == -1 && !isFirstStream) {\n            return false;\n        }\n        final int magic1 = readNextByte(this.bin);\n        final int magic2 = readNextByte(this.bin);\n\n        if (magic0 != 'B' || magic1 != 'Z' || magic2 != 'h') {\n            throw new IOException(isFirstStream\n                    ? \"Stream is not in the BZip2 format\"\n                    : \"Garbage after a valid BZip2 stream\");\n        }\n\n        final int blockSize = readNextByte(this.bin);\n        if ((blockSize < '1') || (blockSize > '9')) {\n            throw new IOException(\"BZip2 block size is invalid\");\n        }\n\n        this.blockSize100k = blockSize - '0';\n\n        this.computedCombinedCRC = 0;\n\n        return true;\n    }\n\n    private void initBlock() throws IOException {\n        final BitInputStream bin = this.bin;\n        char magic0;\n        char magic1;\n        char magic2;\n        char magic3;\n        char magic4;\n        char magic5;\n\n        while (true) {\n            // Get the block magic bytes.\n            magic0 = bsGetUByte(bin);\n            magic1 = bsGetUByte(bin);\n            magic2 = bsGetUByte(bin);\n            magic3 = bsGetUByte(bin);\n            magic4 = bsGetUByte(bin);\n            magic5 = bsGetUByte(bin);\n\n            // If isn't end of stream magic, break out of the loop.\n            if (magic0 != 0x17 || magic1 != 0x72 || magic2 != 0x45\n                    || magic3 != 0x38 || magic4 != 0x50 || magic5 != 0x90) {\n                break;\n            }\n\n            // End of stream was reached. Check the combined CRC and\n            // advance to the next .bz2 stream if decoding concatenated\n            // streams.\n            if (complete()) {\n                return;\n            }\n        }\n\n        if (magic0 != 0x31 || // '1'\n                magic1 != 0x41 || // ')'\n                magic2 != 0x59 || // 'Y'\n                magic3 != 0x26 || // '&'\n                magic4 != 0x53 || // 'S'\n                magic5 != 0x59 // 'Y'\n        ) {\n            this.currentState = EOF;\n            throw new IOException(\"Bad block header\");\n        }\n        this.storedBlockCRC = bsGetInt(bin);\n        this.blockRandomised = bsR(bin, 1) == 1;\n\n        /*\n         * Allocate data here instead in constructor, so we do not allocate\n         * it if the input file is empty.\n         */\n        if (this.data == null) {\n            this.data = new Data(this.blockSize100k);\n        }\n\n        // currBlockNo++;\n        getAndMoveToFrontDecode();\n\n        this.crc.initializeCRC();\n        this.currentState = START_BLOCK_STATE;\n    }\n\n    private void endBlock() throws IOException {\n        this.computedBlockCRC = this.crc.getFinalCRC();\n\n        // A bad CRC is considered a fatal error.\n        if (this.storedBlockCRC != this.computedBlockCRC) {\n            // make next blocks readable without error\n            // (repair feature, not yet documented, not tested)\n            this.computedCombinedCRC = (this.storedCombinedCRC << 1)\n                    | (this.storedCombinedCRC >>> 31);\n            this.computedCombinedCRC ^= this.storedBlockCRC;\n\n            throw new IOException(\"BZip2 CRC error\");\n        }\n\n        this.computedCombinedCRC = (this.computedCombinedCRC << 1)\n                | (this.computedCombinedCRC >>> 31);\n        this.computedCombinedCRC ^= this.computedBlockCRC;\n    }\n\n    private boolean complete() throws IOException {\n        this.storedCombinedCRC = bsGetInt(bin);\n        this.currentState = EOF;\n        this.data = null;\n\n        if (this.storedCombinedCRC != this.computedCombinedCRC) {\n            throw new IOException(\"BZip2 CRC error\");\n        }\n\n        // Look for the next .bz2 stream if decompressing\n        // concatenated files.\n        return !decompressConcatenated || !init(false);\n    }\n\n    @Override\n    public void close() throws IOException {\n        final BitInputStream inShadow = this.bin;\n        if (inShadow != null) {\n            try {\n                inShadow.close();\n            } finally {\n                this.data = null;\n                this.bin = null;\n            }\n        }\n    }\n\n    /**\n     * read bits from the input stream\n     * @param n the number of bits to read, must not exceed 32?\n     * @return the requested bits combined into an int\n     * @throws IOException\n     */\n    private static int bsR(final BitInputStream bin, final int n) throws IOException {\n        final long thech = bin.readBits(n);\n        if (thech < 0) {\n            throw new IOException(\"Unexpected end of stream\");\n        }\n        return (int) thech;\n    }\n\n    private static boolean bsGetBit(final BitInputStream bin) throws IOException {\n        return bsR(bin, 1) != 0;\n    }\n\n    private static char bsGetUByte(final BitInputStream bin) throws IOException {\n        return (char) bsR(bin, 8);\n    }\n\n    private static int bsGetInt(final BitInputStream bin) throws IOException {\n        return bsR(bin, 32);\n    }\n\n    private static void checkBounds(final int checkVal, final int limitExclusive, final String name)\n            throws IOException {\n        if (checkVal < 0) {\n            throw new IOException(\"Corrupted input, \" + name + \" value negative\");\n        }\n        if (checkVal >= limitExclusive) {\n            throw new IOException(\"Corrupted input, \" + name + \" value too big\");\n        }\n    }\n\n    /**\n     * Called by createHuffmanDecodingTables() exclusively.\n     */\n    private static void hbCreateDecodeTables(final int[] limit,\n                                             final int[] base, final int[] perm, final char[] length,\n                                             final int minLen, final int maxLen, final int alphaSize)\n            throws IOException {\n        for (int i = minLen, pp = 0; i <= maxLen; i++) {\n            for (int j = 0; j < alphaSize; j++) {\n                if (length[j] == i) {\n                    perm[pp++] = j;\n                }\n            }\n        }\n\n        for (int i = MAX_CODE_LEN; --i > 0;) {\n            base[i] = 0;\n            limit[i] = 0;\n        }\n\n        for (int i = 0; i < alphaSize; i++) {\n            final int l = length[i];\n            checkBounds(l, MAX_ALPHA_SIZE, \"length\");\n            base[l + 1]++;\n        }\n\n        for (int i = 1, b = base[0]; i < MAX_CODE_LEN; i++) {\n            b += base[i];\n            base[i] = b;\n        }\n\n        for (int i = minLen, vec = 0, b = base[i]; i <= maxLen; i++) {\n            final int nb = base[i + 1];\n            vec += nb - b;\n            b = nb;\n            limit[i] = vec - 1;\n            vec <<= 1;\n        }\n\n        for (int i = minLen + 1; i <= maxLen; i++) {\n            base[i] = ((limit[i - 1] + 1) << 1) - base[i];\n        }\n    }\n\n    private void recvDecodingTables() throws IOException {\n        final BitInputStream bin = this.bin;\n        final Data dataShadow = this.data;\n        final boolean[] inUse = dataShadow.inUse;\n        final byte[] pos = dataShadow.recvDecodingTables_pos;\n        final byte[] selector = dataShadow.selector;\n        final byte[] selectorMtf = dataShadow.selectorMtf;\n\n        int inUse16 = 0;\n\n        /* Receive the mapping table */\n        for (int i = 0; i < 16; i++) {\n            if (bsGetBit(bin)) {\n                inUse16 |= 1 << i;\n            }\n        }\n\n        Arrays.fill(inUse, false);\n        for (int i = 0; i < 16; i++) {\n            if ((inUse16 & (1 << i)) != 0) {\n                final int i16 = i << 4;\n                for (int j = 0; j < 16; j++) {\n                    if (bsGetBit(bin)) {\n                        inUse[i16 + j] = true;\n                    }\n                }\n            }\n        }\n\n        makeMaps();\n        final int alphaSize = this.nInUse + 2;\n        /* Now the selectors */\n        final int nGroups = bsR(bin, 3);\n        final int selectors = bsR(bin, 15);\n        if (selectors < 0) {\n            throw new IOException(\"Corrupted input, nSelectors value negative\");\n        }\n        checkBounds(alphaSize, MAX_ALPHA_SIZE + 1, \"alphaSize\");\n        checkBounds(nGroups, N_GROUPS + 1, \"nGroups\");\n\n        // Don't fail on nSelectors overflowing boundaries but discard the values in overflow\n        // See https://gnu.wildebeest.org/blog/mjw/2019/08/02/bzip2-and-the-cve-that-wasnt/\n        // and https://sourceware.org/ml/bzip2-devel/2019-q3/msg00007.html\n\n        for (int i = 0; i < selectors; i++) {\n            int j = 0;\n            while (bsGetBit(bin)) {\n                j++;\n            }\n            if (i < MAX_SELECTORS) {\n                selectorMtf[i] = (byte) j;\n            }\n        }\n        final int nSelectors = selectors > MAX_SELECTORS ? MAX_SELECTORS : selectors;\n\n        /* Undo the MTF values for the selectors. */\n        for (int v = nGroups; --v >= 0;) {\n            pos[v] = (byte) v;\n        }\n\n        for (int i = 0; i < nSelectors; i++) {\n            int v = selectorMtf[i] & 0xff;\n            checkBounds(v, N_GROUPS, \"selectorMtf\");\n            final byte tmp = pos[v];\n            while (v > 0) {\n                // nearly all times v is zero, 4 in most other cases\n                pos[v] = pos[v - 1];\n                v--;\n            }\n            pos[0] = tmp;\n            selector[i] = tmp;\n        }\n\n        final char[][] len = dataShadow.temp_charArray2d;\n\n        /* Now the coding tables */\n        for (int t = 0; t < nGroups; t++) {\n            int curr = bsR(bin, 5);\n            final char[] len_t = len[t];\n            for (int i = 0; i < alphaSize; i++) {\n                while (bsGetBit(bin)) {\n                    curr += bsGetBit(bin) ? -1 : 1;\n                }\n                len_t[i] = (char) curr;\n            }\n        }\n\n        // finally create the Huffman tables\n        createHuffmanDecodingTables(alphaSize, nGroups);\n    }\n\n    /**\n     * Called by recvDecodingTables() exclusively.\n     */\n    private void createHuffmanDecodingTables(final int alphaSize,\n                                             final int nGroups) throws IOException {\n        final Data dataShadow = this.data;\n        final char[][] len = dataShadow.temp_charArray2d;\n        final int[] minLens = dataShadow.minLens;\n        final int[][] limit = dataShadow.limit;\n        final int[][] base = dataShadow.base;\n        final int[][] perm = dataShadow.perm;\n\n        for (int t = 0; t < nGroups; t++) {\n            int minLen = 32;\n            int maxLen = 0;\n            final char[] len_t = len[t];\n            for (int i = alphaSize; --i >= 0;) {\n                final char lent = len_t[i];\n                if (lent > maxLen) {\n                    maxLen = lent;\n                }\n                if (lent < minLen) {\n                    minLen = lent;\n                }\n            }\n            hbCreateDecodeTables(limit[t], base[t], perm[t], len[t], minLen,\n                    maxLen, alphaSize);\n            minLens[t] = minLen;\n        }\n    }\n\n    private void getAndMoveToFrontDecode() throws IOException {\n        final BitInputStream bin = this.bin;\n        this.origPtr = bsR(bin, 24);\n        recvDecodingTables();\n\n        final Data dataShadow = this.data;\n        final byte[] ll8 = dataShadow.ll8;\n        final int[] unzftab = dataShadow.unzftab;\n        final byte[] selector = dataShadow.selector;\n        final byte[] seqToUnseq = dataShadow.seqToUnseq;\n        final char[] yy = dataShadow.getAndMoveToFrontDecode_yy;\n        final int[] minLens = dataShadow.minLens;\n        final int[][] limit = dataShadow.limit;\n        final int[][] base = dataShadow.base;\n        final int[][] perm = dataShadow.perm;\n        final int limitLast = this.blockSize100k * 100000;\n\n        /*\n         * Setting up the unzftab entries here is not strictly necessary, but it\n         * does save having to do it later in a separate pass, and so saves a\n         * block's worth of cache misses.\n         */\n        for (int i = 256; --i >= 0;) {\n            yy[i] = (char) i;\n            unzftab[i] = 0;\n        }\n\n        int groupNo = 0;\n        int groupPos = G_SIZE - 1;\n        final int eob = this.nInUse + 1;\n        int nextSym = getAndMoveToFrontDecode0();\n        int lastShadow = -1;\n        int zt = selector[groupNo] & 0xff;\n        checkBounds(zt, N_GROUPS, \"zt\");\n        int[] base_zt = base[zt];\n        int[] limit_zt = limit[zt];\n        int[] perm_zt = perm[zt];\n        int minLens_zt = minLens[zt];\n\n        while (nextSym != eob) {\n            if ((nextSym == RUNA) || (nextSym == RUNB)) {\n                int s = -1;\n\n                for (int n = 1; true; n <<= 1) {\n                    if (nextSym == RUNA) {\n                        s += n;\n                    } else if (nextSym == RUNB) {\n                        s += n << 1;\n                    } else {\n                        break;\n                    }\n\n                    if (groupPos == 0) {\n                        groupPos = G_SIZE - 1;\n                        checkBounds(++groupNo, MAX_SELECTORS, \"groupNo\");\n                        zt = selector[groupNo] & 0xff;\n                        checkBounds(zt, N_GROUPS, \"zt\");\n                        base_zt = base[zt];\n                        limit_zt = limit[zt];\n                        perm_zt = perm[zt];\n                        minLens_zt = minLens[zt];\n                    } else {\n                        groupPos--;\n                    }\n\n                    int zn = minLens_zt;\n                    checkBounds(zn, MAX_ALPHA_SIZE, \"zn\");\n                    int zvec = bsR(bin, zn);\n                    while(zvec > limit_zt[zn]) {\n                        checkBounds(++zn, MAX_ALPHA_SIZE, \"zn\");\n                        zvec = (zvec << 1) | bsR(bin, 1);\n                    }\n                    final int tmp = zvec - base_zt[zn];\n                    checkBounds(tmp, MAX_ALPHA_SIZE, \"zvec\");\n                    nextSym = perm_zt[tmp];\n                }\n                checkBounds(s, this.data.ll8.length, \"s\");\n\n                final int yy0 = yy[0];\n                checkBounds(yy0, 256, \"yy\");\n                final byte ch = seqToUnseq[yy0];\n                unzftab[ch & 0xff] += s + 1;\n\n                final int from = ++lastShadow;\n                lastShadow += s;\n                checkBounds(lastShadow, this.data.ll8.length, \"lastShadow\");\n                Arrays.fill(ll8, from, lastShadow + 1, ch);\n\n                if (lastShadow >= limitLast) {\n                    throw new IOException(\"Block overrun while expanding RLE in MTF, \"\n                            + lastShadow + \" exceeds \" + limitLast);\n                }\n            } else {\n                if (++lastShadow >= limitLast) {\n                    throw new IOException(\"Block overrun in MTF, \"\n                            + lastShadow + \" exceeds \" + limitLast);\n                }\n                checkBounds(nextSym, 256 + 1, \"nextSym\");\n\n                final char tmp = yy[nextSym - 1];\n                checkBounds(tmp, 256, \"yy\");\n                unzftab[seqToUnseq[tmp] & 0xff]++;\n                ll8[lastShadow] = seqToUnseq[tmp];\n\n                /*\n                 * This loop is hammered during decompression, hence avoid\n                 * native method call overhead of System.arraycopy for very\n                 * small ranges to copy.\n                 */\n                if (nextSym <= 16) {\n                    for (int j = nextSym - 1; j > 0;) {\n                        yy[j] = yy[--j];\n                    }\n                } else {\n                    System.arraycopy(yy, 0, yy, 1, nextSym - 1);\n                }\n\n                yy[0] = tmp;\n\n                if (groupPos == 0) {\n                    groupPos = G_SIZE - 1;\n                    checkBounds(++groupNo, MAX_SELECTORS, \"groupNo\");\n                    zt = selector[groupNo] & 0xff;\n                    checkBounds(zt, N_GROUPS, \"zt\");\n                    base_zt = base[zt];\n                    limit_zt = limit[zt];\n                    perm_zt = perm[zt];\n                    minLens_zt = minLens[zt];\n                } else {\n                    groupPos--;\n                }\n\n                int zn = minLens_zt;\n                checkBounds(zn, MAX_ALPHA_SIZE, \"zn\");\n                int zvec = bsR(bin, zn);\n                while(zvec > limit_zt[zn]) {\n                    checkBounds(++zn, MAX_ALPHA_SIZE, \"zn\");\n                    zvec = (zvec << 1) | bsR(bin, 1);\n                }\n                final int idx = zvec - base_zt[zn];\n                checkBounds(idx, MAX_ALPHA_SIZE, \"zvec\");\n                nextSym = perm_zt[idx];\n            }\n        }\n\n        this.last = lastShadow;\n    }\n\n    private int getAndMoveToFrontDecode0() throws IOException {\n        final Data dataShadow = this.data;\n        final int zt = dataShadow.selector[0] & 0xff;\n        checkBounds(zt, N_GROUPS, \"zt\");\n        final int[] limit_zt = dataShadow.limit[zt];\n        int zn = dataShadow.minLens[zt];\n        checkBounds(zn, MAX_ALPHA_SIZE, \"zn\");\n        int zvec = bsR(bin, zn);\n        while (zvec > limit_zt[zn]) {\n            checkBounds(++zn, MAX_ALPHA_SIZE, \"zn\");\n            zvec = (zvec << 1) | bsR(bin, 1);\n        }\n        final int tmp = zvec - dataShadow.base[zt][zn];\n        checkBounds(tmp, MAX_ALPHA_SIZE, \"zvec\");\n\n        return dataShadow.perm[zt][tmp];\n    }\n\n    private int setupBlock() throws IOException {\n        if (currentState == EOF || this.data == null) {\n            return -1;\n        }\n\n        final int[] cftab = this.data.cftab;\n        final int ttLen = this.last + 1;\n        final int[] tt = this.data.initTT(ttLen);\n        final byte[] ll8 = this.data.ll8;\n        cftab[0] = 0;\n        System.arraycopy(this.data.unzftab, 0, cftab, 1, 256);\n\n        for (int i = 1, c = cftab[0]; i <= 256; i++) {\n            c += cftab[i];\n            cftab[i] = c;\n        }\n\n        for (int i = 0, lastShadow = this.last; i <= lastShadow; i++) {\n            final int tmp = cftab[ll8[i] & 0xff]++;\n            checkBounds(tmp, ttLen, \"tt index\");\n            tt[tmp] = i;\n        }\n\n        if ((this.origPtr < 0) || (this.origPtr >= tt.length)) {\n            throw new IOException(\"Stream corrupted\");\n        }\n\n        this.su_tPos = tt[this.origPtr];\n        this.su_count = 0;\n        this.su_i2 = 0;\n        this.su_ch2 = 256; /* not a char and not EOF */\n\n        if (this.blockRandomised) {\n            this.su_rNToGo = 0;\n            this.su_rTPos = 0;\n            return setupRandPartA();\n        }\n        return setupNoRandPartA();\n    }\n\n    private int setupRandPartA() throws IOException {\n        if (this.su_i2 <= this.last) {\n            this.su_chPrev = this.su_ch2;\n            int su_ch2Shadow = this.data.ll8[this.su_tPos] & 0xff;\n            checkBounds(this.su_tPos, this.data.tt.length, \"su_tPos\");\n            this.su_tPos = this.data.tt[this.su_tPos];\n            if (this.su_rNToGo == 0) {\n                this.su_rNToGo = Rand.rNums(this.su_rTPos) - 1;\n                if (++this.su_rTPos == 512) {\n                    this.su_rTPos = 0;\n                }\n            } else {\n                this.su_rNToGo--;\n            }\n            this.su_ch2 = su_ch2Shadow ^= (this.su_rNToGo == 1) ? 1 : 0;\n            this.su_i2++;\n            this.currentState = RAND_PART_B_STATE;\n            this.crc.updateCRC(su_ch2Shadow);\n            return su_ch2Shadow;\n        }\n        endBlock();\n        initBlock();\n        return setupBlock();\n    }\n\n    private int setupNoRandPartA() throws IOException {\n        if (this.su_i2 <= this.last) {\n            this.su_chPrev = this.su_ch2;\n            final int su_ch2Shadow = this.data.ll8[this.su_tPos] & 0xff;\n            this.su_ch2 = su_ch2Shadow;\n            checkBounds(this.su_tPos, this.data.tt.length, \"su_tPos\");\n            this.su_tPos = this.data.tt[this.su_tPos];\n            this.su_i2++;\n            this.currentState = NO_RAND_PART_B_STATE;\n            this.crc.updateCRC(su_ch2Shadow);\n            return su_ch2Shadow;\n        }\n        this.currentState = NO_RAND_PART_A_STATE;\n        endBlock();\n        initBlock();\n        return setupBlock();\n    }\n\n    private int setupRandPartB() throws IOException {\n        if (this.su_ch2 != this.su_chPrev) {\n            this.currentState = RAND_PART_A_STATE;\n            this.su_count = 1;\n            return setupRandPartA();\n        }\n        if (++this.su_count < 4) {\n            this.currentState = RAND_PART_A_STATE;\n            return setupRandPartA();\n        }\n        this.su_z = (char) (this.data.ll8[this.su_tPos] & 0xff);\n        checkBounds(this.su_tPos, this.data.tt.length, \"su_tPos\");\n        this.su_tPos = this.data.tt[this.su_tPos];\n        if (this.su_rNToGo == 0) {\n            this.su_rNToGo = Rand.rNums(this.su_rTPos) - 1;\n            if (++this.su_rTPos == 512) {\n                this.su_rTPos = 0;\n            }\n        } else {\n            this.su_rNToGo--;\n        }\n        this.su_j2 = 0;\n        this.currentState = RAND_PART_C_STATE;\n        if (this.su_rNToGo == 1) {\n            this.su_z ^= 1;\n        }\n        return setupRandPartC();\n    }\n\n    private int setupRandPartC() throws IOException {\n        if (this.su_j2 < this.su_z) {\n            this.crc.updateCRC(this.su_ch2);\n            this.su_j2++;\n            return this.su_ch2;\n        }\n        this.currentState = RAND_PART_A_STATE;\n        this.su_i2++;\n        this.su_count = 0;\n        return setupRandPartA();\n    }\n\n    private int setupNoRandPartB() throws IOException {\n        if (this.su_ch2 != this.su_chPrev) {\n            this.su_count = 1;\n            return setupNoRandPartA();\n        }\n        if (++this.su_count >= 4) {\n            checkBounds(this.su_tPos, this.data.ll8.length, \"su_tPos\");\n            this.su_z = (char) (this.data.ll8[this.su_tPos] & 0xff);\n            this.su_tPos = this.data.tt[this.su_tPos];\n            this.su_j2 = 0;\n            return setupNoRandPartC();\n        }\n        return setupNoRandPartA();\n    }\n\n    private int setupNoRandPartC() throws IOException {\n        if (this.su_j2 < this.su_z) {\n            final int su_ch2Shadow = this.su_ch2;\n            this.crc.updateCRC(su_ch2Shadow);\n            this.su_j2++;\n            this.currentState = NO_RAND_PART_C_STATE;\n            return su_ch2Shadow;\n        }\n        this.su_i2++;\n        this.su_count = 0;\n        return setupNoRandPartA();\n    }\n\n    private static final class Data {\n\n        // (with blockSize 900k)\n        final boolean[] inUse = new boolean[256]; // 256 byte\n\n        final byte[] seqToUnseq = new byte[256]; // 256 byte\n        final byte[] selector = new byte[MAX_SELECTORS]; // 18002 byte\n        final byte[] selectorMtf = new byte[MAX_SELECTORS]; // 18002 byte\n\n        /**\n         * Freq table collected to save a pass over the data during\n         * decompression.\n         */\n        final int[] unzftab = new int[256]; // 1024 byte\n\n        final int[][] limit = new int[N_GROUPS][MAX_ALPHA_SIZE]; // 6192 byte\n        final int[][] base = new int[N_GROUPS][MAX_ALPHA_SIZE]; // 6192 byte\n        final int[][] perm = new int[N_GROUPS][MAX_ALPHA_SIZE]; // 6192 byte\n        final int[] minLens = new int[N_GROUPS]; // 24 byte\n\n        final int[] cftab = new int[257]; // 1028 byte\n        final char[] getAndMoveToFrontDecode_yy = new char[256]; // 512 byte\n        final char[][] temp_charArray2d = new char[N_GROUPS][MAX_ALPHA_SIZE]; // 3096\n        // byte\n        final byte[] recvDecodingTables_pos = new byte[N_GROUPS]; // 6 byte\n        // ---------------\n        // 60798 byte\n\n        int[] tt; // 3600000 byte\n        final byte[] ll8; // 900000 byte\n\n        // ---------------\n        // 4560782 byte\n        // ===============\n\n        Data(final int blockSize100k) {\n            this.ll8 = new byte[blockSize100k * BZip2Constants.BASEBLOCKSIZE];\n        }\n\n        /**\n         * Initializes the {@link #tt} array.\n         *\n         * This method is called when the required length of the array is known.\n         * I don't initialize it at construction time to avoid unnecessary\n         * memory allocation when compressing small files.\n         */\n        int[] initTT(final int length) {\n            int[] ttShadow = this.tt;\n\n            // tt.length should always be >= length, but theoretically\n            // it can happen, if the compressor mixed small and large\n            // blocks. Normally only the last block will be smaller\n            // than others.\n            if ((ttShadow == null) || (ttShadow.length < length)) {\n                this.tt = ttShadow = new int[length];\n            }\n\n            return ttShadow;\n        }\n\n    }\n\n    /**\n     * Checks if the signature matches what is expected for a bzip2 file.\n     *\n     * @param signature\n     *            the bytes to check\n     * @param length\n     *            the number of bytes to check\n     * @return true, if this stream is a bzip2 compressed stream, false otherwise\n     *\n     * @since 1.1\n     */\n    public static boolean matches(final byte[] signature, final int length) {\n        return length >= 3 && signature[0] == 'B' &&\n                signature[1] == 'Z' && signature[2] == 'h';\n    }\n}"
  },
  {
    "path": "app/src/main/java/org/apache/commons/compress/compressors/bzip2/BZip2CompressorOutputStream.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage org.apache.commons.compress.compressors.bzip2;\n\nimport java.io.IOException;\nimport java.io.OutputStream;\n\nimport org.apache.commons.compress.compressors.CompressorOutputStream;\n\n/**\n * An output stream that compresses into the BZip2 format into another stream.\n *\n * <p>\n * The compression requires large amounts of memory. Thus you should call the\n * {@link #close() close()} method as soon as possible, to force\n * {@code BZip2CompressorOutputStream} to release the allocated memory.\n * </p>\n *\n * <p> You can shrink the amount of allocated memory and maybe raise\n * the compression speed by choosing a lower blocksize, which in turn\n * may cause a lower compression ratio. You can avoid unnecessary\n * memory allocation by avoiding using a blocksize which is bigger\n * than the size of the input.  </p>\n *\n * <p> You can compute the memory usage for compressing by the\n * following formula: </p>\n *\n * <pre>\n * &lt;code&gt;400k + (9 * blocksize)&lt;/code&gt;.\n * </pre>\n *\n * <p> To get the memory required for decompression by {@link\n * BZip2CompressorInputStream} use </p>\n *\n * <pre>\n * &lt;code&gt;65k + (5 * blocksize)&lt;/code&gt;.\n * </pre>\n *\n * <table style=\"width:100%\" border=\"1\">\n * <caption>Memory usage by blocksize</caption>\n * <tr>\n * <th colspan=\"3\">Memory usage by blocksize</th>\n * </tr>\n * <tr>\n * <th style=\"text-align: right\">Blocksize</th> <th style=\"text-align: right\">Compression<br>\n * memory usage</th> <th style=\"text-align: right\">Decompression<br>\n * memory usage</th>\n * </tr>\n * <tr>\n * <td style=\"text-align: right\">100k</td>\n * <td style=\"text-align: right\">1300k</td>\n * <td style=\"text-align: right\">565k</td>\n * </tr>\n * <tr>\n * <td style=\"text-align: right\">200k</td>\n * <td style=\"text-align: right\">2200k</td>\n * <td style=\"text-align: right\">1065k</td>\n * </tr>\n * <tr>\n * <td style=\"text-align: right\">300k</td>\n * <td style=\"text-align: right\">3100k</td>\n * <td style=\"text-align: right\">1565k</td>\n * </tr>\n * <tr>\n * <td style=\"text-align: right\">400k</td>\n * <td style=\"text-align: right\">4000k</td>\n * <td style=\"text-align: right\">2065k</td>\n * </tr>\n * <tr>\n * <td style=\"text-align: right\">500k</td>\n * <td style=\"text-align: right\">4900k</td>\n * <td style=\"text-align: right\">2565k</td>\n * </tr>\n * <tr>\n * <td style=\"text-align: right\">600k</td>\n * <td style=\"text-align: right\">5800k</td>\n * <td style=\"text-align: right\">3065k</td>\n * </tr>\n * <tr>\n * <td style=\"text-align: right\">700k</td>\n * <td style=\"text-align: right\">6700k</td>\n * <td style=\"text-align: right\">3565k</td>\n * </tr>\n * <tr>\n * <td style=\"text-align: right\">800k</td>\n * <td style=\"text-align: right\">7600k</td>\n * <td style=\"text-align: right\">4065k</td>\n * </tr>\n * <tr>\n * <td style=\"text-align: right\">900k</td>\n * <td style=\"text-align: right\">8500k</td>\n * <td style=\"text-align: right\">4565k</td>\n * </tr>\n * </table>\n *\n * <p>\n * For decompression {@code BZip2CompressorInputStream} allocates less memory if the\n * bzipped input is smaller than one block.\n * </p>\n *\n * <p>\n * Instances of this class are not threadsafe.\n * </p>\n *\n * <p>\n * TODO: Update to BZip2 1.0.1\n * </p>\n * @NotThreadSafe\n */\n// Copyright 2008 Torsten Curdt\npublic class BZip2CompressorOutputStream extends CompressorOutputStream\n        implements BZip2Constants {\n\n    /**\n     * The minimum supported blocksize {@code  == 1}.\n     */\n    public static final int MIN_BLOCKSIZE = 1;\n\n    /**\n     * The maximum supported blocksize {@code  == 9}.\n     */\n    public static final int MAX_BLOCKSIZE = 9;\n\n    private static final int GREATER_ICOST = 15;\n    private static final int LESSER_ICOST = 0;\n\n    private static void hbMakeCodeLengths(final byte[] len, final int[] freq,\n                                          final Data dat, final int alphaSize,\n                                          final int maxLen) {\n        /*\n         * Nodes and heap entries run from 1. Entry 0 for both the heap and\n         * nodes is a sentinel.\n         */\n        final int[] heap = dat.heap;\n        final int[] weight = dat.weight;\n        final int[] parent = dat.parent;\n\n        for (int i = alphaSize; --i >= 0;) {\n            weight[i + 1] = (freq[i] == 0 ? 1 : freq[i]) << 8;\n        }\n\n        for (boolean tooLong = true; tooLong;) {\n            tooLong = false;\n\n            int nNodes = alphaSize;\n            int nHeap = 0;\n            heap[0] = 0;\n            weight[0] = 0;\n            parent[0] = -2;\n\n            for (int i = 1; i <= alphaSize; i++) {\n                parent[i] = -1;\n                nHeap++;\n                heap[nHeap] = i;\n\n                int zz = nHeap;\n                final int tmp = heap[zz];\n                while (weight[tmp] < weight[heap[zz >> 1]]) {\n                    heap[zz] = heap[zz >> 1];\n                    zz >>= 1;\n                }\n                heap[zz] = tmp;\n            }\n\n            while (nHeap > 1) {\n                final int n1 = heap[1];\n                heap[1] = heap[nHeap];\n                nHeap--;\n\n                int yy = 0;\n                int zz = 1;\n                int tmp = heap[1];\n\n                while (true) {\n                    yy = zz << 1;\n\n                    if (yy > nHeap) {\n                        break;\n                    }\n\n                    if ((yy < nHeap)\n                            && (weight[heap[yy + 1]] < weight[heap[yy]])) {\n                        yy++;\n                    }\n\n                    if (weight[tmp] < weight[heap[yy]]) {\n                        break;\n                    }\n\n                    heap[zz] = heap[yy];\n                    zz = yy;\n                }\n\n                heap[zz] = tmp;\n\n                final int n2 = heap[1];\n                heap[1] = heap[nHeap];\n                nHeap--;\n\n                yy = 0;\n                zz = 1;\n                tmp = heap[1];\n\n                while (true) {\n                    yy = zz << 1;\n\n                    if (yy > nHeap) {\n                        break;\n                    }\n\n                    if ((yy < nHeap)\n                            && (weight[heap[yy + 1]] < weight[heap[yy]])) {\n                        yy++;\n                    }\n\n                    if (weight[tmp] < weight[heap[yy]]) {\n                        break;\n                    }\n\n                    heap[zz] = heap[yy];\n                    zz = yy;\n                }\n\n                heap[zz] = tmp;\n                nNodes++;\n                parent[n1] = parent[n2] = nNodes;\n\n                final int weight_n1 = weight[n1];\n                final int weight_n2 = weight[n2];\n                weight[nNodes] = ((weight_n1 & 0xffffff00)\n                        + (weight_n2 & 0xffffff00))\n                        | (1 + (((weight_n1 & 0x000000ff)\n                        > (weight_n2 & 0x000000ff))\n                        ? (weight_n1 & 0x000000ff)\n                        : (weight_n2 & 0x000000ff)));\n\n                parent[nNodes] = -1;\n                nHeap++;\n                heap[nHeap] = nNodes;\n\n                tmp = 0;\n                zz = nHeap;\n                tmp = heap[zz];\n                final int weight_tmp = weight[tmp];\n                while (weight_tmp < weight[heap[zz >> 1]]) {\n                    heap[zz] = heap[zz >> 1];\n                    zz >>= 1;\n                }\n                heap[zz] = tmp;\n\n            }\n\n            for (int i = 1; i <= alphaSize; i++) {\n                int j = 0;\n                int k = i;\n\n                for (int parent_k; (parent_k = parent[k]) >= 0;) {\n                    k = parent_k;\n                    j++;\n                }\n\n                len[i - 1] = (byte) j;\n                if (j > maxLen) {\n                    tooLong = true;\n                }\n            }\n\n            if (tooLong) {\n                for (int i = 1; i < alphaSize; i++) {\n                    int j = weight[i] >> 8;\n                    j = 1 + (j >> 1);\n                    weight[i] = j << 8;\n                }\n            }\n        }\n    }\n\n    /**\n     * Index of the last char in the block, so the block size == last + 1.\n     */\n    private int last;\n\n    /**\n     * Always: in the range 0 .. 9. The current block size is 100000 * this\n     * number.\n     */\n    private final int blockSize100k;\n\n    private int bsBuff;\n    private int bsLive;\n    private final CRC crc = new CRC();\n\n    private int nInUse;\n\n    private int nMTF;\n\n    private int currentChar = -1;\n    private int runLength = 0;\n\n    private int blockCRC;\n    private int combinedCRC;\n    private final int allowableBlockSize;\n\n    /**\n     * All memory intensive stuff.\n     */\n    private Data data;\n    private BlockSort blockSorter;\n\n    private OutputStream out;\n    private volatile boolean closed;\n\n    /**\n     * Chooses a blocksize based on the given length of the data to compress.\n     *\n     * @return The blocksize, between {@link #MIN_BLOCKSIZE} and\n     *         {@link #MAX_BLOCKSIZE} both inclusive. For a negative\n     *         {@code inputLength} this method returns {@code MAX_BLOCKSIZE}\n     *         always.\n     *\n     * @param inputLength\n     *            The length of the data which will be compressed by\n     *            {@code BZip2CompressorOutputStream}.\n     */\n    public static int chooseBlockSize(final long inputLength) {\n        return (inputLength > 0) ? (int) Math\n                .min((inputLength / 132000) + 1, 9) : MAX_BLOCKSIZE;\n    }\n\n    /**\n     * Constructs a new {@code BZip2CompressorOutputStream} with a blocksize of 900k.\n     *\n     * @param out\n     *            the destination stream.\n     *\n     * @throws IOException\n     *             if an I/O error occurs in the specified stream.\n     * @throws NullPointerException\n     *             if <code>out == null</code>.\n     */\n    public BZip2CompressorOutputStream(final OutputStream out)\n            throws IOException {\n        this(out, MAX_BLOCKSIZE);\n    }\n\n    /**\n     * Constructs a new {@code BZip2CompressorOutputStream} with specified blocksize.\n     *\n     * @param out\n     *            the destination stream.\n     * @param blockSize\n     *            the blockSize as 100k units.\n     *\n     * @throws IOException\n     *             if an I/O error occurs in the specified stream.\n     * @throws IllegalArgumentException\n     *             if <code>(blockSize &lt; 1) || (blockSize &gt; 9)</code>.\n     * @throws NullPointerException\n     *             if <code>out == null</code>.\n     *\n     * @see #MIN_BLOCKSIZE\n     * @see #MAX_BLOCKSIZE\n     */\n    public BZip2CompressorOutputStream(final OutputStream out, final int blockSize) throws IOException {\n        if (blockSize < 1) {\n            throw new IllegalArgumentException(\"blockSize(\" + blockSize + \") < 1\");\n        }\n        if (blockSize > 9) {\n            throw new IllegalArgumentException(\"blockSize(\" + blockSize + \") > 9\");\n        }\n\n        this.blockSize100k = blockSize;\n        this.out = out;\n\n        /* 20 is just a paranoia constant */\n        this.allowableBlockSize = (this.blockSize100k * BZip2Constants.BASEBLOCKSIZE) - 20;\n        init();\n    }\n\n    @Override\n    public void write(final int b) throws IOException {\n        if (closed) {\n            throw new IOException(\"Closed\");\n        }\n        write0(b);\n    }\n\n    /**\n     * Writes the current byte to the buffer, run-length encoding it\n     * if it has been repeated at least four times (the first step\n     * RLEs sequences of four identical bytes).\n     *\n     * <p>Flushes the current block before writing data if it is\n     * full.</p>\n     *\n     * <p>\"write to the buffer\" means adding to data.buffer starting\n     * two steps \"after\" this.last - initially starting at index 1\n     * (not 0) - and updating this.last to point to the last index\n     * written minus 1.</p>\n     */\n    private void writeRun() throws IOException {\n        final int lastShadow = this.last;\n\n        if (lastShadow < this.allowableBlockSize) {\n            final int currentCharShadow = this.currentChar;\n            final Data dataShadow = this.data;\n            dataShadow.inUse[currentCharShadow] = true;\n            final byte ch = (byte) currentCharShadow;\n\n            int runLengthShadow = this.runLength;\n            this.crc.updateCRC(currentCharShadow, runLengthShadow);\n\n            switch (runLengthShadow) {\n                case 1:\n                    dataShadow.block[lastShadow + 2] = ch;\n                    this.last = lastShadow + 1;\n                    break;\n\n                case 2:\n                    dataShadow.block[lastShadow + 2] = ch;\n                    dataShadow.block[lastShadow + 3] = ch;\n                    this.last = lastShadow + 2;\n                    break;\n\n                case 3: {\n                    final byte[] block = dataShadow.block;\n                    block[lastShadow + 2] = ch;\n                    block[lastShadow + 3] = ch;\n                    block[lastShadow + 4] = ch;\n                    this.last = lastShadow + 3;\n                }\n                break;\n\n                default: {\n                    runLengthShadow -= 4;\n                    dataShadow.inUse[runLengthShadow] = true;\n                    final byte[] block = dataShadow.block;\n                    block[lastShadow + 2] = ch;\n                    block[lastShadow + 3] = ch;\n                    block[lastShadow + 4] = ch;\n                    block[lastShadow + 5] = ch;\n                    block[lastShadow + 6] = (byte) runLengthShadow;\n                    this.last = lastShadow + 5;\n                }\n                break;\n\n            }\n        } else {\n            endBlock();\n            initBlock();\n            writeRun();\n        }\n    }\n\n    /**\n     * Overridden to warn about an unclosed stream.\n     */\n    @Override\n    protected void finalize() throws Throwable {\n        if (!closed) {\n            System.err.println(\"Unclosed BZip2CompressorOutputStream detected, will *not* close it\");\n        }\n        super.finalize();\n    }\n\n\n    public void finish() throws IOException {\n        if (!closed) {\n            closed = true;\n            try {\n                if (this.runLength > 0) {\n                    writeRun();\n                }\n                this.currentChar = -1;\n                endBlock();\n                endCompression();\n            } finally {\n                this.out = null;\n                this.blockSorter = null;\n                this.data = null;\n            }\n        }\n    }\n\n    @Override\n    public void close() throws IOException {\n        if (!closed) {\n            try (OutputStream outShadow = this.out) {\n                finish();\n            }\n        }\n    }\n\n    @Override\n    public void flush() throws IOException {\n        final OutputStream outShadow = this.out;\n        if (outShadow != null) {\n            outShadow.flush();\n        }\n    }\n\n    /**\n     * Writes magic bytes like BZ on the first position of the stream\n     * and bytes indicating the file-format, which is\n     * huffmanised, followed by a digit indicating blockSize100k.\n     * @throws IOException if the magic bytes could not been written\n     */\n    private void init() throws IOException {\n        bsPutUByte('B');\n        bsPutUByte('Z');\n\n        this.data = new Data(this.blockSize100k);\n        this.blockSorter = new BlockSort(this.data);\n\n        // huffmanised magic bytes\n        bsPutUByte('h');\n        bsPutUByte('0' + this.blockSize100k);\n\n        this.combinedCRC = 0;\n        initBlock();\n    }\n\n    private void initBlock() {\n        // blockNo++;\n        this.crc.initializeCRC();\n        this.last = -1;\n        // ch = 0;\n\n        final boolean[] inUse = this.data.inUse;\n        for (int i = 256; --i >= 0;) {\n            inUse[i] = false;\n        }\n\n    }\n\n    private void endBlock() throws IOException {\n        this.blockCRC = this.crc.getFinalCRC();\n        this.combinedCRC = (this.combinedCRC << 1) | (this.combinedCRC >>> 31);\n        this.combinedCRC ^= this.blockCRC;\n\n        // empty block at end of file\n        if (this.last == -1) {\n            return;\n        }\n\n        /* sort the block and establish posn of original string */\n        blockSort();\n\n        /*\n         * A 6-byte block header, the value chosen arbitrarily as 0x314159265359\n         * :-). A 32 bit value does not really give a strong enough guarantee\n         * that the value will not appear by chance in the compressed\n         * datastream. Worst-case probability of this event, for a 900k block,\n         * is about 2.0e-3 for 32 bits, 1.0e-5 for 40 bits and 4.0e-8 for 48\n         * bits. For a compressed file of size 100Gb -- about 100000 blocks --\n         * only a 48-bit marker will do. NB: normal compression/ decompression\n         * donot rely on these statistical properties. They are only important\n         * when trying to recover blocks from damaged files.\n         */\n        bsPutUByte(0x31);\n        bsPutUByte(0x41);\n        bsPutUByte(0x59);\n        bsPutUByte(0x26);\n        bsPutUByte(0x53);\n        bsPutUByte(0x59);\n\n        /* Now the block's CRC, so it is in a known place. */\n        bsPutInt(this.blockCRC);\n\n        /* Now a single bit indicating no randomisation. */\n        bsW(1, 0);\n\n        /* Finally, block's contents proper. */\n        moveToFrontCodeAndSend();\n    }\n\n    private void endCompression() throws IOException {\n        /*\n         * Now another magic 48-bit number, 0x177245385090, to indicate the end\n         * of the last block. (sqrt(pi), if you want to know. I did want to use\n         * e, but it contains too much repetition -- 27 18 28 18 28 46 -- for me\n         * to feel statistically comfortable. Call me paranoid.)\n         */\n        bsPutUByte(0x17);\n        bsPutUByte(0x72);\n        bsPutUByte(0x45);\n        bsPutUByte(0x38);\n        bsPutUByte(0x50);\n        bsPutUByte(0x90);\n\n        bsPutInt(this.combinedCRC);\n        bsFinishedWithStream();\n    }\n\n    /**\n     * Returns the blocksize parameter specified at construction time.\n     * @return the blocksize parameter specified at construction time\n     */\n    public final int getBlockSize() {\n        return this.blockSize100k;\n    }\n\n    @Override\n    public void write(final byte[] buf, int offs, final int len)\n            throws IOException {\n        if (offs < 0) {\n            throw new IndexOutOfBoundsException(\"offs(\" + offs + \") < 0.\");\n        }\n        if (len < 0) {\n            throw new IndexOutOfBoundsException(\"len(\" + len + \") < 0.\");\n        }\n        if (offs + len > buf.length) {\n            throw new IndexOutOfBoundsException(\"offs(\" + offs + \") + len(\"\n                    + len + \") > buf.length(\"\n                    + buf.length + \").\");\n        }\n        if (closed) {\n            throw new IOException(\"Stream closed\");\n        }\n\n        for (final int hi = offs + len; offs < hi;) {\n            write0(buf[offs++]);\n        }\n    }\n\n    /**\n     * Keeps track of the last bytes written and implicitly performs\n     * run-length encoding as the first step of the bzip2 algorithm.\n     */\n    private void write0(int b) throws IOException {\n        if (this.currentChar != -1) {\n            b &= 0xff;\n            if (this.currentChar == b) {\n                if (++this.runLength > 254) {\n                    writeRun();\n                    this.currentChar = -1;\n                    this.runLength = 0;\n                }\n                // else nothing to do\n            } else {\n                writeRun();\n                this.runLength = 1;\n                this.currentChar = b;\n            }\n        } else {\n            this.currentChar = b & 0xff;\n            this.runLength++;\n        }\n    }\n\n    private static void hbAssignCodes(final int[] code, final byte[] length,\n                                      final int minLen, final int maxLen,\n                                      final int alphaSize) {\n        int vec = 0;\n        for (int n = minLen; n <= maxLen; n++) {\n            for (int i = 0; i < alphaSize; i++) {\n                if ((length[i] & 0xff) == n) {\n                    code[i] = vec;\n                    vec++;\n                }\n            }\n            vec <<= 1;\n        }\n    }\n\n    private void bsFinishedWithStream() throws IOException {\n        while (this.bsLive > 0) {\n            final int ch = this.bsBuff >> 24;\n            this.out.write(ch); // write 8-bit\n            this.bsBuff <<= 8;\n            this.bsLive -= 8;\n        }\n    }\n\n    private void bsW(final int n, final int v) throws IOException {\n        final OutputStream outShadow = this.out;\n        int bsLiveShadow = this.bsLive;\n        int bsBuffShadow = this.bsBuff;\n\n        while (bsLiveShadow >= 8) {\n            outShadow.write(bsBuffShadow >> 24); // write 8-bit\n            bsBuffShadow <<= 8;\n            bsLiveShadow -= 8;\n        }\n\n        this.bsBuff = bsBuffShadow | (v << (32 - bsLiveShadow - n));\n        this.bsLive = bsLiveShadow + n;\n    }\n\n    private void bsPutUByte(final int c) throws IOException {\n        bsW(8, c);\n    }\n\n    private void bsPutInt(final int u) throws IOException {\n        bsW(8, (u >> 24) & 0xff);\n        bsW(8, (u >> 16) & 0xff);\n        bsW(8, (u >> 8) & 0xff);\n        bsW(8, u & 0xff);\n    }\n\n    private void sendMTFValues() throws IOException {\n        final byte[][] len = this.data.sendMTFValues_len;\n        final int alphaSize = this.nInUse + 2;\n\n        for (int t = N_GROUPS; --t >= 0;) {\n            final byte[] len_t = len[t];\n            for (int v = alphaSize; --v >= 0;) {\n                len_t[v] = GREATER_ICOST;\n            }\n        }\n\n        /* Decide how many coding tables to use */\n        // assert (this.nMTF > 0) : this.nMTF;\n        final int nGroups = (this.nMTF < 200) ? 2 : (this.nMTF < 600) ? 3\n                : (this.nMTF < 1200) ? 4 : (this.nMTF < 2400) ? 5 : 6;\n\n        /* Generate an initial set of coding tables */\n        sendMTFValues0(nGroups, alphaSize);\n\n        /*\n         * Iterate up to N_ITERS times to improve the tables.\n         */\n        final int nSelectors = sendMTFValues1(nGroups, alphaSize);\n\n        /* Compute MTF values for the selectors. */\n        sendMTFValues2(nGroups, nSelectors);\n\n        /* Assign actual codes for the tables. */\n        sendMTFValues3(nGroups, alphaSize);\n\n        /* Transmit the mapping table. */\n        sendMTFValues4();\n\n        /* Now the selectors. */\n        sendMTFValues5(nGroups, nSelectors);\n\n        /* Now the coding tables. */\n        sendMTFValues6(nGroups, alphaSize);\n\n        /* And finally, the block data proper */\n        sendMTFValues7();\n    }\n\n    private void sendMTFValues0(final int nGroups, final int alphaSize) {\n        final byte[][] len = this.data.sendMTFValues_len;\n        final int[] mtfFreq = this.data.mtfFreq;\n\n        int remF = this.nMTF;\n        int gs = 0;\n\n        for (int nPart = nGroups; nPart > 0; nPart--) {\n            final int tFreq = remF / nPart;\n            int ge = gs - 1;\n            int aFreq = 0;\n\n            for (final int a = alphaSize - 1; (aFreq < tFreq) && (ge < a);) {\n                aFreq += mtfFreq[++ge];\n            }\n\n            if ((ge > gs) && (nPart != nGroups) && (nPart != 1)\n                    && (((nGroups - nPart) & 1) != 0)) {\n                aFreq -= mtfFreq[ge--];\n            }\n\n            final byte[] len_np = len[nPart - 1];\n            for (int v = alphaSize; --v >= 0;) {\n                if ((v >= gs) && (v <= ge)) {\n                    len_np[v] = LESSER_ICOST;\n                } else {\n                    len_np[v] = GREATER_ICOST;\n                }\n            }\n\n            gs = ge + 1;\n            remF -= aFreq;\n        }\n    }\n\n    private int sendMTFValues1(final int nGroups, final int alphaSize) {\n        final Data dataShadow = this.data;\n        final int[][] rfreq = dataShadow.sendMTFValues_rfreq;\n        final int[] fave = dataShadow.sendMTFValues_fave;\n        final short[] cost = dataShadow.sendMTFValues_cost;\n        final char[] sfmap = dataShadow.sfmap;\n        final byte[] selector = dataShadow.selector;\n        final byte[][] len = dataShadow.sendMTFValues_len;\n        final byte[] len_0 = len[0];\n        final byte[] len_1 = len[1];\n        final byte[] len_2 = len[2];\n        final byte[] len_3 = len[3];\n        final byte[] len_4 = len[4];\n        final byte[] len_5 = len[5];\n        final int nMTFShadow = this.nMTF;\n\n        int nSelectors = 0;\n\n        for (int iter = 0; iter < N_ITERS; iter++) {\n            for (int t = nGroups; --t >= 0;) {\n                fave[t] = 0;\n                final int[] rfreqt = rfreq[t];\n                for (int i = alphaSize; --i >= 0;) {\n                    rfreqt[i] = 0;\n                }\n            }\n\n            nSelectors = 0;\n\n            for (int gs = 0; gs < this.nMTF;) {\n                /* Set group start & end marks. */\n\n                /*\n                 * Calculate the cost of this group as coded by each of the\n                 * coding tables.\n                 */\n\n                final int ge = Math.min(gs + G_SIZE - 1, nMTFShadow - 1);\n\n                if (nGroups == N_GROUPS) {\n                    // unrolled version of the else-block\n\n                    short cost0 = 0;\n                    short cost1 = 0;\n                    short cost2 = 0;\n                    short cost3 = 0;\n                    short cost4 = 0;\n                    short cost5 = 0;\n\n                    for (int i = gs; i <= ge; i++) {\n                        final int icv = sfmap[i];\n                        cost0 += (short) (len_0[icv] & 0xff);\n                        cost1 += (short) (len_1[icv] & 0xff);\n                        cost2 += (short) (len_2[icv] & 0xff);\n                        cost3 += (short) (len_3[icv] & 0xff);\n                        cost4 += (short) (len_4[icv] & 0xff);\n                        cost5 += (short) (len_5[icv] & 0xff);\n                    }\n\n                    cost[0] = cost0;\n                    cost[1] = cost1;\n                    cost[2] = cost2;\n                    cost[3] = cost3;\n                    cost[4] = cost4;\n                    cost[5] = cost5;\n\n                } else {\n                    for (int t = nGroups; --t >= 0;) {\n                        cost[t] = 0;\n                    }\n\n                    for (int i = gs; i <= ge; i++) {\n                        final int icv = sfmap[i];\n                        for (int t = nGroups; --t >= 0;) {\n                            cost[t] += (short) (len[t][icv] & 0xff);\n                        }\n                    }\n                }\n\n                /*\n                 * Find the coding table which is best for this group, and\n                 * record its identity in the selector table.\n                 */\n                int bt = -1;\n                for (int t = nGroups, bc = 999999999; --t >= 0;) {\n                    final int cost_t = cost[t];\n                    if (cost_t < bc) {\n                        bc = cost_t;\n                        bt = t;\n                    }\n                }\n\n                fave[bt]++;\n                selector[nSelectors] = (byte) bt;\n                nSelectors++;\n\n                /*\n                 * Increment the symbol frequencies for the selected table.\n                 */\n                final int[] rfreq_bt = rfreq[bt];\n                for (int i = gs; i <= ge; i++) {\n                    rfreq_bt[sfmap[i]]++;\n                }\n\n                gs = ge + 1;\n            }\n\n            /*\n             * Recompute the tables based on the accumulated frequencies.\n             */\n            for (int t = 0; t < nGroups; t++) {\n                hbMakeCodeLengths(len[t], rfreq[t], this.data, alphaSize, 20);\n            }\n        }\n\n        return nSelectors;\n    }\n\n    private void sendMTFValues2(final int nGroups, final int nSelectors) {\n        // assert (nGroups < 8) : nGroups;\n\n        final Data dataShadow = this.data;\n        final byte[] pos = dataShadow.sendMTFValues2_pos;\n\n        for (int i = nGroups; --i >= 0;) {\n            pos[i] = (byte) i;\n        }\n\n        for (int i = 0; i < nSelectors; i++) {\n            final byte ll_i = dataShadow.selector[i];\n            byte tmp = pos[0];\n            int j = 0;\n\n            while (ll_i != tmp) {\n                j++;\n                final byte tmp2 = tmp;\n                tmp = pos[j];\n                pos[j] = tmp2;\n            }\n\n            pos[0] = tmp;\n            dataShadow.selectorMtf[i] = (byte) j;\n        }\n    }\n\n    private void sendMTFValues3(final int nGroups, final int alphaSize) {\n        final int[][] code = this.data.sendMTFValues_code;\n        final byte[][] len = this.data.sendMTFValues_len;\n\n        for (int t = 0; t < nGroups; t++) {\n            int minLen = 32;\n            int maxLen = 0;\n            final byte[] len_t = len[t];\n            for (int i = alphaSize; --i >= 0;) {\n                final int l = len_t[i] & 0xff;\n                if (l > maxLen) {\n                    maxLen = l;\n                }\n                if (l < minLen) {\n                    minLen = l;\n                }\n            }\n\n            // assert (maxLen <= 20) : maxLen;\n            // assert (minLen >= 1) : minLen;\n\n            hbAssignCodes(code[t], len[t], minLen, maxLen, alphaSize);\n        }\n    }\n\n    private void sendMTFValues4() throws IOException {\n        final boolean[] inUse = this.data.inUse;\n        final boolean[] inUse16 = this.data.sentMTFValues4_inUse16;\n\n        for (int i = 16; --i >= 0;) {\n            inUse16[i] = false;\n            final int i16 = i * 16;\n            for (int j = 16; --j >= 0;) {\n                if (inUse[i16 + j]) {\n                    inUse16[i] = true;\n                    break;\n                }\n            }\n        }\n\n        for (int i = 0; i < 16; i++) {\n            bsW(1, inUse16[i] ? 1 : 0);\n        }\n\n        final OutputStream outShadow = this.out;\n        int bsLiveShadow = this.bsLive;\n        int bsBuffShadow = this.bsBuff;\n\n        for (int i = 0; i < 16; i++) {\n            if (inUse16[i]) {\n                final int i16 = i * 16;\n                for (int j = 0; j < 16; j++) {\n                    // inlined: bsW(1, inUse[i16 + j] ? 1 : 0);\n                    while (bsLiveShadow >= 8) {\n                        outShadow.write(bsBuffShadow >> 24); // write 8-bit\n                        bsBuffShadow <<= 8;\n                        bsLiveShadow -= 8;\n                    }\n                    if (inUse[i16 + j]) {\n                        bsBuffShadow |= 1 << (32 - bsLiveShadow - 1);\n                    }\n                    bsLiveShadow++;\n                }\n            }\n        }\n\n        this.bsBuff = bsBuffShadow;\n        this.bsLive = bsLiveShadow;\n    }\n\n    private void sendMTFValues5(final int nGroups, final int nSelectors)\n            throws IOException {\n        bsW(3, nGroups);\n        bsW(15, nSelectors);\n\n        final OutputStream outShadow = this.out;\n        final byte[] selectorMtf = this.data.selectorMtf;\n\n        int bsLiveShadow = this.bsLive;\n        int bsBuffShadow = this.bsBuff;\n\n        for (int i = 0; i < nSelectors; i++) {\n            for (int j = 0, hj = selectorMtf[i] & 0xff; j < hj; j++) {\n                // inlined: bsW(1, 1);\n                while (bsLiveShadow >= 8) {\n                    outShadow.write(bsBuffShadow >> 24);\n                    bsBuffShadow <<= 8;\n                    bsLiveShadow -= 8;\n                }\n                bsBuffShadow |= 1 << (32 - bsLiveShadow - 1);\n                bsLiveShadow++;\n            }\n\n            // inlined: bsW(1, 0);\n            while (bsLiveShadow >= 8) {\n                outShadow.write(bsBuffShadow >> 24);\n                bsBuffShadow <<= 8;\n                bsLiveShadow -= 8;\n            }\n            // bsBuffShadow |= 0 << (32 - bsLiveShadow - 1);\n            bsLiveShadow++;\n        }\n\n        this.bsBuff = bsBuffShadow;\n        this.bsLive = bsLiveShadow;\n    }\n\n    private void sendMTFValues6(final int nGroups, final int alphaSize)\n            throws IOException {\n        final byte[][] len = this.data.sendMTFValues_len;\n        final OutputStream outShadow = this.out;\n\n        int bsLiveShadow = this.bsLive;\n        int bsBuffShadow = this.bsBuff;\n\n        for (int t = 0; t < nGroups; t++) {\n            final byte[] len_t = len[t];\n            int curr = len_t[0] & 0xff;\n\n            // inlined: bsW(5, curr);\n            while (bsLiveShadow >= 8) {\n                outShadow.write(bsBuffShadow >> 24); // write 8-bit\n                bsBuffShadow <<= 8;\n                bsLiveShadow -= 8;\n            }\n            bsBuffShadow |= curr << (32 - bsLiveShadow - 5);\n            bsLiveShadow += 5;\n\n            for (int i = 0; i < alphaSize; i++) {\n                final int lti = len_t[i] & 0xff;\n                while (curr < lti) {\n                    // inlined: bsW(2, 2);\n                    while (bsLiveShadow >= 8) {\n                        outShadow.write(bsBuffShadow >> 24); // write 8-bit\n                        bsBuffShadow <<= 8;\n                        bsLiveShadow -= 8;\n                    }\n                    bsBuffShadow |= 2 << (32 - bsLiveShadow - 2);\n                    bsLiveShadow += 2;\n\n                    curr++; /* 10 */\n                }\n\n                while (curr > lti) {\n                    // inlined: bsW(2, 3);\n                    while (bsLiveShadow >= 8) {\n                        outShadow.write(bsBuffShadow >> 24); // write 8-bit\n                        bsBuffShadow <<= 8;\n                        bsLiveShadow -= 8;\n                    }\n                    bsBuffShadow |= 3 << (32 - bsLiveShadow - 2);\n                    bsLiveShadow += 2;\n\n                    curr--; /* 11 */\n                }\n\n                // inlined: bsW(1, 0);\n                while (bsLiveShadow >= 8) {\n                    outShadow.write(bsBuffShadow >> 24); // write 8-bit\n                    bsBuffShadow <<= 8;\n                    bsLiveShadow -= 8;\n                }\n                // bsBuffShadow |= 0 << (32 - bsLiveShadow - 1);\n                bsLiveShadow++;\n            }\n        }\n\n        this.bsBuff = bsBuffShadow;\n        this.bsLive = bsLiveShadow;\n    }\n\n    private void sendMTFValues7() throws IOException {\n        final Data dataShadow = this.data;\n        final byte[][] len = dataShadow.sendMTFValues_len;\n        final int[][] code = dataShadow.sendMTFValues_code;\n        final OutputStream outShadow = this.out;\n        final byte[] selector = dataShadow.selector;\n        final char[] sfmap = dataShadow.sfmap;\n        final int nMTFShadow = this.nMTF;\n\n        int selCtr = 0;\n\n        int bsLiveShadow = this.bsLive;\n        int bsBuffShadow = this.bsBuff;\n\n        for (int gs = 0; gs < nMTFShadow;) {\n            final int ge = Math.min(gs + G_SIZE - 1, nMTFShadow - 1);\n            final int selector_selCtr = selector[selCtr] & 0xff;\n            final int[] code_selCtr = code[selector_selCtr];\n            final byte[] len_selCtr = len[selector_selCtr];\n\n            while (gs <= ge) {\n                final int sfmap_i = sfmap[gs];\n\n                //\n                // inlined: bsW(len_selCtr[sfmap_i] & 0xff,\n                // code_selCtr[sfmap_i]);\n                //\n                while (bsLiveShadow >= 8) {\n                    outShadow.write(bsBuffShadow >> 24);\n                    bsBuffShadow <<= 8;\n                    bsLiveShadow -= 8;\n                }\n                final int n = len_selCtr[sfmap_i] & 0xFF;\n                bsBuffShadow |= code_selCtr[sfmap_i] << (32 - bsLiveShadow - n);\n                bsLiveShadow += n;\n\n                gs++;\n            }\n\n            gs = ge + 1;\n            selCtr++;\n        }\n\n        this.bsBuff = bsBuffShadow;\n        this.bsLive = bsLiveShadow;\n    }\n\n    private void moveToFrontCodeAndSend() throws IOException {\n        bsW(24, this.data.origPtr);\n        generateMTFValues();\n        sendMTFValues();\n    }\n\n    private void blockSort() {\n        blockSorter.blockSort(data, last);\n    }\n\n    /*\n     * Performs Move-To-Front on the Burrows-Wheeler transformed\n     * buffer, storing the MTFed data in data.sfmap in RUNA/RUNB\n     * run-length-encoded form.\n     *\n     * <p>Keeps track of byte frequencies in data.mtfFreq at the same time.</p>\n     */\n    private void generateMTFValues() {\n        final int lastShadow = this.last;\n        final Data dataShadow = this.data;\n        final boolean[] inUse = dataShadow.inUse;\n        final byte[] block = dataShadow.block;\n        final int[] fmap = dataShadow.fmap;\n        final char[] sfmap = dataShadow.sfmap;\n        final int[] mtfFreq = dataShadow.mtfFreq;\n        final byte[] unseqToSeq = dataShadow.unseqToSeq;\n        final byte[] yy = dataShadow.generateMTFValues_yy;\n\n        // make maps\n        int nInUseShadow = 0;\n        for (int i = 0; i < 256; i++) {\n            if (inUse[i]) {\n                unseqToSeq[i] = (byte) nInUseShadow;\n                nInUseShadow++;\n            }\n        }\n        this.nInUse = nInUseShadow;\n\n        final int eob = nInUseShadow + 1;\n\n        for (int i = eob; i >= 0; i--) {\n            mtfFreq[i] = 0;\n        }\n\n        for (int i = nInUseShadow; --i >= 0;) {\n            yy[i] = (byte) i;\n        }\n\n        int wr = 0;\n        int zPend = 0;\n\n        for (int i = 0; i <= lastShadow; i++) {\n            final byte ll_i = unseqToSeq[block[fmap[i]] & 0xff];\n            byte tmp = yy[0];\n            int j = 0;\n\n            while (ll_i != tmp) {\n                j++;\n                final byte tmp2 = tmp;\n                tmp = yy[j];\n                yy[j] = tmp2;\n            }\n            yy[0] = tmp;\n\n            if (j == 0) {\n                zPend++;\n            } else {\n                if (zPend > 0) {\n                    zPend--;\n                    while (true) {\n                        if ((zPend & 1) == 0) {\n                            sfmap[wr] = RUNA;\n                            wr++;\n                            mtfFreq[RUNA]++;\n                        } else {\n                            sfmap[wr] = RUNB;\n                            wr++;\n                            mtfFreq[RUNB]++;\n                        }\n\n                        if (zPend < 2) {\n                            break;\n                        }\n                        zPend = (zPend - 2) >> 1;\n                    }\n                    zPend = 0;\n                }\n                sfmap[wr] = (char) (j + 1);\n                wr++;\n                mtfFreq[j + 1]++;\n            }\n        }\n\n        if (zPend > 0) {\n            zPend--;\n            while (true) {\n                if ((zPend & 1) == 0) {\n                    sfmap[wr] = RUNA;\n                    wr++;\n                    mtfFreq[RUNA]++;\n                } else {\n                    sfmap[wr] = RUNB;\n                    wr++;\n                    mtfFreq[RUNB]++;\n                }\n\n                if (zPend < 2) {\n                    break;\n                }\n                zPend = (zPend - 2) >> 1;\n            }\n        }\n\n        sfmap[wr] = (char) eob;\n        mtfFreq[eob]++;\n        this.nMTF = wr + 1;\n    }\n\n    static final class Data {\n\n        // with blockSize 900k\n        /* maps unsigned byte => \"does it occur in block\" */\n        final boolean[] inUse = new boolean[256]; // 256 byte\n        final byte[] unseqToSeq = new byte[256]; // 256 byte\n        final int[] mtfFreq = new int[MAX_ALPHA_SIZE]; // 1032 byte\n        final byte[] selector = new byte[MAX_SELECTORS]; // 18002 byte\n        final byte[] selectorMtf = new byte[MAX_SELECTORS]; // 18002 byte\n\n        final byte[] generateMTFValues_yy = new byte[256]; // 256 byte\n        final byte[][] sendMTFValues_len = new byte[N_GROUPS][MAX_ALPHA_SIZE]; // 1548\n        // byte\n        final int[][] sendMTFValues_rfreq = new int[N_GROUPS][MAX_ALPHA_SIZE]; // 6192\n        // byte\n        final int[] sendMTFValues_fave = new int[N_GROUPS]; // 24 byte\n        final short[] sendMTFValues_cost = new short[N_GROUPS]; // 12 byte\n        final int[][] sendMTFValues_code = new int[N_GROUPS][MAX_ALPHA_SIZE]; // 6192\n        // byte\n        final byte[] sendMTFValues2_pos = new byte[N_GROUPS]; // 6 byte\n        final boolean[] sentMTFValues4_inUse16 = new boolean[16]; // 16 byte\n\n        final int[] heap = new int[MAX_ALPHA_SIZE + 2]; // 1040 byte\n        final int[] weight = new int[MAX_ALPHA_SIZE * 2]; // 2064 byte\n        final int[] parent = new int[MAX_ALPHA_SIZE * 2]; // 2064 byte\n\n        // ------------\n        // 333408 byte\n\n        /* holds the RLEd block of original data starting at index 1.\n         * After sorting the last byte added to the buffer is at index\n         * 0. */\n        final byte[] block; // 900021 byte\n        /* maps index in Burrows-Wheeler transformed block => index of\n         * byte in original block */\n        final int[] fmap; // 3600000 byte\n        final char[] sfmap; // 3600000 byte\n        // ------------\n        // 8433529 byte\n        // ============\n\n        /**\n         * Index of original line in Burrows-Wheeler table.\n         *\n         * <p>This is the index in fmap that points to the last byte\n         * of the original data.</p>\n         */\n        int origPtr;\n\n        Data(final int blockSize100k) {\n            final int n = blockSize100k * BZip2Constants.BASEBLOCKSIZE;\n            this.block = new byte[(n + 1 + NUM_OVERSHOOT_BYTES)];\n            this.fmap = new int[n];\n            this.sfmap = new char[2 * n];\n        }\n\n    }\n\n}"
  },
  {
    "path": "app/src/main/java/org/apache/commons/compress/compressors/bzip2/BZip2Constants.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage org.apache.commons.compress.compressors.bzip2;\n\n/**\n * Constants for both the compress and decompress BZip2 classes.\n */\n// Copyright 2008 Torsten Curdt\ninterface BZip2Constants {\n\n    int BASEBLOCKSIZE = 100000;\n    int MAX_ALPHA_SIZE = 258;\n    int MAX_CODE_LEN = 23;\n    int RUNA = 0;\n    int RUNB = 1;\n    int N_GROUPS = 6;\n    int G_SIZE = 50;\n    int N_ITERS = 4;\n    int MAX_SELECTORS = (2 + (900000 / G_SIZE));\n    int NUM_OVERSHOOT_BYTES = 20;\n\n}"
  },
  {
    "path": "app/src/main/java/org/apache/commons/compress/compressors/bzip2/BZip2Utils.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage org.apache.commons.compress.compressors.bzip2;\n\nimport java.util.LinkedHashMap;\nimport java.util.Map;\nimport org.apache.commons.compress.compressors.FileNameUtil;\n\n/**\n * Utility code for the BZip2 compression format.\n * @ThreadSafe\n * @since 1.1\n */\n// Copyright 2017 Stefan Bodewig\npublic abstract class BZip2Utils {\n\n    private static final FileNameUtil fileNameUtil;\n\n    static {\n        final Map<String, String> uncompressSuffix =\n            new LinkedHashMap<>();\n        // backwards compatibility: BZip2Utils never created the short\n        // tbz form, so .tar.bz2 has to be added explicitly\n        uncompressSuffix.put(\".tar.bz2\", \".tar\");\n        uncompressSuffix.put(\".tbz2\", \".tar\");\n        uncompressSuffix.put(\".tbz\", \".tar\");\n        uncompressSuffix.put(\".bz2\", \"\");\n        uncompressSuffix.put(\".bz\", \"\");\n        fileNameUtil = new FileNameUtil(uncompressSuffix, \".bz2\");\n    }\n\n    /** Private constructor to prevent instantiation of this utility class. */\n    private BZip2Utils() {\n    }\n\n    /**\n     * Detects common bzip2 suffixes in the given file name.\n     *\n     * @param fileName name of a file\n     * @return {@code true} if the file name has a common bzip2 suffix,\n     *         {@code false} otherwise\n     */\n    public static boolean isCompressedFilename(final String fileName) {\n        return fileNameUtil.isCompressedFilename(fileName);\n    }\n\n    /**\n     * Maps the given name of a bzip2-compressed file to the name that the\n     * file should have after uncompression. Commonly used file type specific\n     * suffixes like \".tbz\" or \".tbz2\" are automatically detected and\n     * correctly mapped. For example the name \"package.tbz2\" is mapped to\n     * \"package.tar\". And any file names with the generic \".bz2\" suffix\n     * (or any other generic bzip2 suffix) is mapped to a name without that\n     * suffix. If no bzip2 suffix is detected, then the file name is returned\n     * unmapped.\n     *\n     * @param fileName name of a file\n     * @return name of the corresponding uncompressed file\n     */\n    public static String getUncompressedFilename(final String fileName) {\n        return fileNameUtil.getUncompressedFilename(fileName);\n    }\n\n    /**\n     * Maps the given file name to the name that the file should have after\n     * compression with bzip2. Currently this method simply appends the suffix\n     * \".bz2\" to the file name based on the standard behavior of the \"bzip2\"\n     * program, but a future version may implement a more complex mapping if\n     * a new widely used naming pattern emerges.\n     *\n     * @param fileName name of a file\n     * @return name of the corresponding compressed file\n     */\n    public static String getCompressedFilename(final String fileName) {\n        return fileNameUtil.getCompressedFilename(fileName);\n    }\n\n}"
  },
  {
    "path": "app/src/main/java/org/apache/commons/compress/compressors/bzip2/BlockSort.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage org.apache.commons.compress.compressors.bzip2;\n\nimport java.util.BitSet;\n\n/**\n * Encapsulates the Burrows-Wheeler sorting algorithm needed by {@link\n * BZip2CompressorOutputStream}.\n *\n * <p>This class is based on a Java port of Julian Seward's\n * blocksort.c in his libbzip2</p>\n *\n * <p>The Burrows-Wheeler transform is a reversible transform of the\n * original data that is supposed to group similar bytes close to\n * each other.  The idea is to sort all permutations of the input and\n * only keep the last byte of each permutation.  E.g. for \"Commons\n * Compress\" you'd get:</p>\n *\n * <pre>\n *  CompressCommons\n * Commons Compress\n * CompressCommons\n * essCommons Compr\n * mmons CompressCo\n * mons CompressCom\n * mpressCommons Co\n * ns CompressCommo\n * ommons CompressC\n * ompressCommons C\n * ons CompressComm\n * pressCommons Com\n * ressCommons Comp\n * s CompressCommon\n * sCommons Compres\n * ssCommons Compre\n * </pre>\n *\n * <p>Which results in a new text \"ss romooCCmmpnse\", in adition the\n * index of the first line that contained the original text is kept -\n * in this case it is 1.  The idea is that in a long English text all\n * permutations that start with \"he\" are likely suffixes of a \"the\" and\n * thus they end in \"t\" leading to a larger block of \"t\"s that can\n * better be compressed by the subsequent Move-to-Front, run-length\n * und Huffman encoding steps.</p>\n *\n * <p>For more information see for example:</p>\n * <ul>\n *   <li><a\n *   href=\"http://www.hpl.hp.com/techreports/Compaq-DEC/SRC-RR-124.pdf\">Burrows,\n *   M. and Wheeler, D.: A Block-sorting Lossless Data Compression\n *   Algorithm</a></li>\n *   <li><a href=\"http://webglimpse.net/pubs/suffix.pdf\">Manber, U. and\n *   Myers, G.: Suffix arrays: A new method for on-line string\n *   searches</a></li>\n *   <li><a\n *   href=\"http://www.cs.tufts.edu/~nr/comp150fp/archive/bob-sedgewick/fast-strings.pdf\">Bentley,\n *   J.L. and Sedgewick, R.: Fast Algorithms for Sorting and Searching\n *   Strings</a></li>\n * </ul>\n *\n * @NotThreadSafe\n */\n// Copyright 2017 Stefan Bodewig\nclass BlockSort {\n\n    /*\n     * Some of the constructs used in the C code cannot be ported\n     * literally to Java - for example macros, unsigned types.  Some\n     * code has been hand-tuned to improve performance.  In order to\n     * avoid memory pressure some structures are reused for several\n     * blocks and some memory is even shared between sorting and the\n     * MTF stage even though either algorithm uses it for its own\n     * purpose.\n     *\n     * Comments preserved from the actual C code are prefixed with\n     * \"LBZ2:\".\n     */\n\n    /*\n     * 2012-05-20 Stefan Bodewig:\n     *\n     * This class seems to mix several revisions of libbzip2's code.\n     * The mainSort function and those used by it look closer to the\n     * 0.9.5 version but show some variations introduced later.  At\n     * the same time the logic of Compress 1.4 to randomize the block\n     * on bad input has been dropped after libbzip2 0.9.0 and replaced\n     * by a fallback sorting algorithm.\n     *\n     * I've added the fallbackSort function of 1.0.6 and tried to\n     * integrate it with the existing code without touching too much.\n     * I've also removed the now unused randomization code.\n     */\n\n    /*\n     * LBZ2: If you are ever unlucky/improbable enough to get a stack\n     * overflow whilst sorting, increase the following constant and\n     * try again. In practice I have never seen the stack go above 27\n     * elems, so the following limit seems very generous.\n     */\n    private static final int QSORT_STACK_SIZE = 1000;\n\n    private static final int FALLBACK_QSORT_STACK_SIZE = 100;\n\n    private static final int STACK_SIZE =\n            QSORT_STACK_SIZE < FALLBACK_QSORT_STACK_SIZE\n                    ? FALLBACK_QSORT_STACK_SIZE : QSORT_STACK_SIZE;\n\n    /*\n     * Used when sorting. If too many long comparisons happen, we stop sorting,\n     * and use fallbackSort instead.\n     */\n    private int workDone;\n    private int workLimit;\n    private boolean firstAttempt;\n\n    private final int[] stack_ll = new int[STACK_SIZE]; // 4000 byte\n    private final int[] stack_hh = new int[STACK_SIZE]; // 4000 byte\n    private final int[] stack_dd = new int[QSORT_STACK_SIZE]; // 4000 byte\n\n    private final int[] mainSort_runningOrder = new int[256]; // 1024 byte\n    private final int[] mainSort_copy = new int[256]; // 1024 byte\n    private final boolean[] mainSort_bigDone = new boolean[256]; // 256 byte\n\n    private final int[] ftab = new int[65537]; // 262148 byte\n\n    /**\n     * Array instance identical to Data's sfmap, both are used only\n     * temporarily and indepently, so we do not need to allocate\n     * additional memory.\n     */\n    private final char[] quadrant;\n\n    BlockSort(final BZip2CompressorOutputStream.Data data) {\n        this.quadrant = data.sfmap;\n    }\n\n    void blockSort(final BZip2CompressorOutputStream.Data data, final int last) {\n        this.workLimit = WORK_FACTOR * last;\n        this.workDone = 0;\n        this.firstAttempt = true;\n\n        if (last + 1 < 10000) {\n            fallbackSort(data, last);\n        } else {\n            mainSort(data, last);\n\n            if (this.firstAttempt && (this.workDone > this.workLimit)) {\n                fallbackSort(data, last);\n            }\n        }\n\n        final int[] fmap = data.fmap;\n        data.origPtr = -1;\n        for (int i = 0; i <= last; i++) {\n            if (fmap[i] == 0) {\n                data.origPtr = i;\n                break;\n            }\n        }\n\n        // assert (data.origPtr != -1) : data.origPtr;\n    }\n\n    /**\n     * Adapt fallbackSort to the expected interface of the rest of the\n     * code, in particular deal with the fact that block starts at\n     * offset 1 (in libbzip2 1.0.6 it starts at 0).\n     */\n    final void fallbackSort(final BZip2CompressorOutputStream.Data data,\n                            final int last) {\n        data.block[0] = data.block[last + 1];\n        fallbackSort(data.fmap, data.block, last + 1);\n        for (int i = 0; i < last + 1; i++) {\n            --data.fmap[i];\n        }\n        for (int i = 0; i < last + 1; i++) {\n            if (data.fmap[i] == -1) {\n                data.fmap[i] = last;\n                break;\n            }\n        }\n    }\n\n    /*---------------------------------------------*/\n\n    /*---------------------------------------------*/\n    /*--- LBZ2: Fallback O(N log(N)^2) sorting        ---*/\n    /*--- algorithm, for repetitive blocks      ---*/\n    /*---------------------------------------------*/\n\n    /*\n     * This is the fallback sorting algorithm libbzip2 1.0.6 uses for\n     * repetitive or very short inputs.\n     *\n     * The idea is inspired by Manber-Myers string suffix sorting\n     * algorithm.  First a bucket sort places each permutation of the\n     * block into a bucket based on its first byte.  Permutations are\n     * represented by pointers to their first character kept in\n     * (partially) sorted order inside the array ftab.\n     *\n     * The next step visits all buckets in order and performs a\n     * quicksort on all permutations of the bucket based on the index\n     * of the bucket the second byte of the permutation belongs to,\n     * thereby forming new buckets.  When arrived here the\n     * permutations are sorted up to the second character and we have\n     * buckets of permutations that are identical up to two\n     * characters.\n     *\n     * Repeat the step of quicksorting each bucket, now based on the\n     * bucket holding the sequence of the third and forth character\n     * leading to four byte buckets.  Repeat this doubling of bucket\n     * sizes until all buckets only contain single permutations or the\n     * bucket size exceeds the block size.\n     *\n     * I.e.\n     *\n     * \"abraba\" form three buckets for the chars \"a\", \"b\", and \"r\" in\n     * the first step with\n     *\n     * fmap = { 'a:' 5, 3, 0, 'b:' 4, 1, 'r', 2 }\n     *\n     * when looking at the bucket of \"a\"s the second characters are in\n     * the buckets that start with fmap-index 0 (rolled over), 3 and 3\n     * respectively, forming two new buckets \"aa\" and \"ab\", so we get\n     *\n     * fmap = { 'aa:' 5, 'ab:' 3, 0, 'ba:' 4, 'br': 1, 'ra:' 2 }\n     *\n     * since the last bucket only contained a single item it didn't\n     * have to be sorted at all.\n     *\n     * There now is just one bucket with more than one permutation\n     * that remains to be sorted.  For the permutation that starts\n     * with index 3 the third and forth char are in bucket 'aa' at\n     * index 0 and for the one starting at block index 0 they are in\n     * bucket 'ra' with sort index 5.  The fully sorted order then becomes.\n     *\n     * fmap = { 5, 3, 0, 4, 1, 2 }\n     *\n     */\n\n    /**\n     * @param fmap points to the index of the starting point of a\n     *        permutation inside the block of data in the current\n     *        partially sorted order\n     * @param eclass points from the index of a character inside the\n     *        block to the first index in fmap that contains the\n     *        bucket of its suffix that is sorted in this step.\n     * @param lo lower boundary of the fmap-interval to be sorted\n     * @param hi upper boundary of the fmap-interval to be sorted\n     */\n    private void fallbackSimpleSort(final int[] fmap,\n                                    final int[] eclass,\n                                    final int lo,\n                                    final int hi) {\n        if (lo == hi) {\n            return;\n        }\n\n        int j;\n        if (hi - lo > 3) {\n            for (int i = hi - 4; i >= lo; i--) {\n                final int tmp = fmap[i];\n                final int ec_tmp = eclass[tmp];\n                for (j = i + 4; j <= hi && ec_tmp > eclass[fmap[j]];\n                     j += 4) {\n                    fmap[j - 4] = fmap[j];\n                }\n                fmap[j - 4] = tmp;\n            }\n        }\n\n        for (int i = hi - 1; i >= lo; i--) {\n            final int tmp = fmap[i];\n            final int ec_tmp = eclass[tmp];\n            for (j = i + 1; j <= hi && ec_tmp > eclass[fmap[j]]; j++) {\n                fmap[j - 1] = fmap[j];\n            }\n            fmap[j-1] = tmp;\n        }\n    }\n\n    private static final int FALLBACK_QSORT_SMALL_THRESH = 10;\n\n    /**\n     * swaps two values in fmap\n     */\n    private void fswap(final int[] fmap, final int zz1, final int zz2) {\n        final int zztmp = fmap[zz1];\n        fmap[zz1] = fmap[zz2];\n        fmap[zz2] = zztmp;\n    }\n\n    /**\n     * swaps two intervals starting at yyp1 and yyp2 of length yyn inside fmap.\n     */\n    private void fvswap(final int[] fmap, int yyp1, int yyp2, int yyn) {\n        while (yyn > 0) {\n            fswap(fmap, yyp1, yyp2);\n            yyp1++; yyp2++; yyn--;\n        }\n    }\n\n    private int fmin(final int a, final int b) {\n        return a < b ? a : b;\n    }\n\n    private void fpush(final int sp, final int lz, final int hz) {\n        stack_ll[sp] = lz;\n        stack_hh[sp] = hz;\n    }\n\n    private int[] fpop(final int sp) {\n        return new int[] { stack_ll[sp], stack_hh[sp] };\n    }\n\n    /**\n     * @param fmap points to the index of the starting point of a\n     *        permutation inside the block of data in the current\n     *        partially sorted order\n     * @param eclass points from the index of a character inside the\n     *        block to the first index in fmap that contains the\n     *        bucket of its suffix that is sorted in this step.\n     * @param loSt lower boundary of the fmap-interval to be sorted\n     * @param hiSt upper boundary of the fmap-interval to be sorted\n     */\n    private void fallbackQSort3(final int[] fmap,\n                                final int[] eclass,\n                                final int loSt,\n                                final int hiSt) {\n        int lo, unLo, ltLo, hi, unHi, gtHi, n;\n\n        long r = 0;\n        int sp = 0;\n        fpush(sp++, loSt, hiSt);\n\n        while (sp > 0) {\n            final int[] s = fpop(--sp);\n            lo = s[0]; hi = s[1];\n\n            if (hi - lo < FALLBACK_QSORT_SMALL_THRESH) {\n                fallbackSimpleSort(fmap, eclass, lo, hi);\n                continue;\n            }\n\n            /* LBZ2: Random partitioning.  Median of 3 sometimes fails to\n               avoid bad cases.  Median of 9 seems to help but\n               looks rather expensive.  This too seems to work but\n               is cheaper.  Guidance for the magic constants\n               7621 and 32768 is taken from Sedgewick's algorithms\n               book, chapter 35.\n            */\n            r = ((r * 7621) + 1) % 32768;\n            final long r3 = r % 3;\n            final long med;\n            if (r3 == 0) {\n                med = eclass[fmap[lo]];\n            } else if (r3 == 1) {\n                med = eclass[fmap[(lo + hi) >>> 1]];\n            } else {\n                med = eclass[fmap[hi]];\n            }\n\n            unLo = ltLo = lo;\n            unHi = gtHi = hi;\n\n            // looks like the ternary partition attributed to Wegner\n            // in the cited Sedgewick paper\n            while (true) {\n                while (true) {\n                    if (unLo > unHi) {\n                        break;\n                    }\n                    n = eclass[fmap[unLo]] - (int) med;\n                    if (n == 0) {\n                        fswap(fmap, unLo, ltLo);\n                        ltLo++; unLo++;\n                        continue;\n                    }\n                    if (n > 0) {\n                        break;\n                    }\n                    unLo++;\n                }\n                while (true) {\n                    if (unLo > unHi) {\n                        break;\n                    }\n                    n = eclass[fmap[unHi]] - (int) med;\n                    if (n == 0) {\n                        fswap(fmap, unHi, gtHi);\n                        gtHi--; unHi--;\n                        continue;\n                    }\n                    if (n < 0) {\n                        break;\n                    }\n                    unHi--;\n                }\n                if (unLo > unHi) {\n                    break;\n                }\n                fswap(fmap, unLo, unHi); unLo++; unHi--;\n            }\n\n            if (gtHi < ltLo) {\n                continue;\n            }\n\n            n = fmin(ltLo - lo, unLo - ltLo);\n            fvswap(fmap, lo, unLo - n, n);\n            int m = fmin(hi - gtHi, gtHi - unHi);\n            fvswap(fmap, unHi + 1, hi - m + 1, m);\n\n            n = lo + unLo - ltLo - 1;\n            m = hi - (gtHi - unHi) + 1;\n\n            if (n - lo > hi - m) {\n                fpush(sp++, lo, n);\n                fpush(sp++, m, hi);\n            } else {\n                fpush(sp++, m, hi);\n                fpush(sp++, lo, n);\n            }\n        }\n    }\n\n\n    /*---------------------------------------------*/\n\n    private int[] eclass;\n\n    private int[] getEclass() {\n        if (eclass == null) {\n            eclass = new int[quadrant.length / 2];\n        }\n        return eclass;\n    }\n\n    /*\n     * The C code uses an array of ints (each int holding 32 flags) to\n     * represents the bucket-start flags (bhtab).  It also contains\n     * optimizations to skip over 32 consecutively set or\n     * consecutively unset bits on word boundaries at once.  For now\n     * I've chosen to use the simpler but potentially slower code\n     * using BitSet - also in the hope that using the BitSet#nextXXX\n     * methods may be fast enough.\n     */\n\n    /**\n     * @param fmap points to the index of the starting point of a\n     *        permutation inside the block of data in the current\n     *        partially sorted order\n     * @param block the original data\n     * @param nblock size of the block\n     */\n    final void fallbackSort(final int[] fmap, final byte[] block, final int nblock) {\n        final int[] ftab = new int[257];\n        int H, i, j, k, l, r, cc, cc1;\n        int nNotDone;\n        final int nBhtab;\n        final int[] eclass = getEclass();\n\n        for (i = 0; i < nblock; i++) {\n            eclass[i] = 0;\n        }\n        /*--\n          LBZ2: Initial 1-char radix sort to generate\n          initial fmap and initial BH bits.\n          --*/\n        for (i = 0; i < nblock; i++) {\n            ftab[block[i] & 0xff]++;\n        }\n        for (i = 1; i < 257;    i++) {\n            ftab[i] += ftab[i - 1];\n        }\n\n        for (i = 0; i < nblock; i++) {\n            j = block[i] & 0xff;\n            k = ftab[j] - 1;\n            ftab[j] = k;\n            fmap[k] = i;\n        }\n\n        nBhtab = 64 + nblock;\n        final BitSet bhtab = new BitSet(nBhtab);\n        for (i = 0; i < 256; i++) {\n            bhtab.set(ftab[i]);\n        }\n\n        /*--\n          LBZ2: Inductively refine the buckets.  Kind-of an\n          \"exponential radix sort\" (!), inspired by the\n          Manber-Myers suffix array construction algorithm.\n          --*/\n\n        /*-- LBZ2: set sentinel bits for block-end detection --*/\n        for (i = 0; i < 32; i++) {\n            bhtab.set(nblock + 2 * i);\n            bhtab.clear(nblock + 2 * i + 1);\n        }\n\n        /*-- LBZ2: the log(N) loop --*/\n        H = 1;\n        while (true) {\n\n            j = 0;\n            for (i = 0; i < nblock; i++) {\n                if (bhtab.get(i)) {\n                    j = i;\n                }\n                k = fmap[i] - H;\n                if (k < 0) {\n                    k += nblock;\n                }\n                eclass[k] = j;\n            }\n\n            nNotDone = 0;\n            r = -1;\n            while (true) {\n\n                /*-- LBZ2: find the next non-singleton bucket --*/\n                k = r + 1;\n                k = bhtab.nextClearBit(k);\n                l = k - 1;\n                if (l >= nblock) {\n                    break;\n                }\n                k = bhtab.nextSetBit(k + 1);\n                r = k - 1;\n                if (r >= nblock) {\n                    break;\n                }\n\n                /*-- LBZ2: now [l, r] bracket current bucket --*/\n                if (r > l) {\n                    nNotDone += (r - l + 1);\n                    fallbackQSort3(fmap, eclass, l, r);\n\n                    /*-- LBZ2: scan bucket and generate header bits-- */\n                    cc = -1;\n                    for (i = l; i <= r; i++) {\n                        cc1 = eclass[fmap[i]];\n                        if (cc != cc1) {\n                            bhtab.set(i);\n                            cc = cc1;\n                        }\n                    }\n                }\n            }\n\n            H *= 2;\n            if (H > nblock || nNotDone == 0) {\n                break;\n            }\n        }\n    }\n\n    /*---------------------------------------------*/\n\n    /*\n     * LBZ2: Knuth's increments seem to work better than Incerpi-Sedgewick here.\n     * Possibly because the number of elems to sort is usually small, typically\n     * &lt;= 20.\n     */\n    private static final int[] INCS = { 1, 4, 13, 40, 121, 364, 1093, 3280,\n            9841, 29524, 88573, 265720, 797161,\n            2391484 };\n\n    /**\n     * This is the most hammered method of this class.\n     *\n     * <p>\n     * This is the version using unrolled loops. Normally I never use such ones\n     * in Java code. The unrolling has shown a noticable performance improvement\n     * on JRE 1.4.2 (Linux i586 / HotSpot Client). Of course it depends on the\n     * JIT compiler of the vm.\n     * </p>\n     */\n    private boolean mainSimpleSort(final BZip2CompressorOutputStream.Data dataShadow,\n                                   final int lo, final int hi, final int d,\n                                   final int lastShadow) {\n        final int bigN = hi - lo + 1;\n        if (bigN < 2) {\n            return this.firstAttempt && (this.workDone > this.workLimit);\n        }\n\n        int hp = 0;\n        while (INCS[hp] < bigN) {\n            hp++;\n        }\n\n        final int[] fmap = dataShadow.fmap;\n        final char[] quadrant = this.quadrant;\n        final byte[] block = dataShadow.block;\n        final int lastPlus1 = lastShadow + 1;\n        final boolean firstAttemptShadow = this.firstAttempt;\n        final int workLimitShadow = this.workLimit;\n        int workDoneShadow = this.workDone;\n\n        // Following block contains unrolled code which could be shortened by\n        // coding it in additional loops.\n\n        HP: while (--hp >= 0) {\n            final int h = INCS[hp];\n            final int mj = lo + h - 1;\n\n            for (int i = lo + h; i <= hi;) {\n                // copy\n                for (int k = 3; (i <= hi) && (--k >= 0); i++) {\n                    final int v = fmap[i];\n                    final int vd = v + d;\n                    int j = i;\n\n                    // for (int a;\n                    // (j > mj) && mainGtU((a = fmap[j - h]) + d, vd,\n                    // block, quadrant, lastShadow);\n                    // j -= h) {\n                    // fmap[j] = a;\n                    // }\n                    //\n                    // unrolled version:\n\n                    // start inline mainGTU\n                    boolean onceRunned = false;\n                    int a = 0;\n\n                    HAMMER: while (true) {\n                        if (onceRunned) {\n                            fmap[j] = a;\n                            if ((j -= h) <= mj) { //NOSONAR\n                                break HAMMER;\n                            }\n                        } else {\n                            onceRunned = true;\n                        }\n\n                        a = fmap[j - h];\n                        int i1 = a + d;\n                        int i2 = vd;\n\n                        // following could be done in a loop, but\n                        // unrolled it for performance:\n                        if (block[i1 + 1] == block[i2 + 1]) {\n                            if (block[i1 + 2] == block[i2 + 2]) {\n                                if (block[i1 + 3] == block[i2 + 3]) {\n                                    if (block[i1 + 4] == block[i2 + 4]) {\n                                        if (block[i1 + 5] == block[i2 + 5]) {\n                                            if (block[(i1 += 6)] == block[(i2 += 6)]) { //NOSONAR\n                                                int x = lastShadow;\n                                                X: while (x > 0) {\n                                                    x -= 4;\n                                                    if (block[i1 + 1] == block[i2 + 1]) {\n                                                        if (quadrant[i1] == quadrant[i2]) {\n                                                            if (block[i1 + 2] == block[i2 + 2]) {\n                                                                if (quadrant[i1 + 1] == quadrant[i2 + 1]) {\n                                                                    if (block[i1 + 3] == block[i2 + 3]) {\n                                                                        if (quadrant[i1 + 2] == quadrant[i2 + 2]) {\n                                                                            if (block[i1 + 4] == block[i2 + 4]) {\n                                                                                if (quadrant[i1 + 3] == quadrant[i2 + 3]) {\n                                                                                    if ((i1 += 4) >= lastPlus1) { //NOSONAR\n                                                                                        i1 -= lastPlus1;\n                                                                                    }\n                                                                                    if ((i2 += 4) >= lastPlus1) { //NOSONAR\n                                                                                        i2 -= lastPlus1;\n                                                                                    }\n                                                                                    workDoneShadow++;\n                                                                                    continue X;\n                                                                                }\n                                                                                if ((quadrant[i1 + 3] > quadrant[i2 + 3])) {\n                                                                                    continue HAMMER;\n                                                                                }\n                                                                                break HAMMER;\n                                                                            }\n                                                                            if ((block[i1 + 4] & 0xff) > (block[i2 + 4] & 0xff)) {\n                                                                                continue HAMMER;\n                                                                            }\n                                                                            break HAMMER;\n                                                                        }\n                                                                        if ((quadrant[i1 + 2] > quadrant[i2 + 2])) {\n                                                                            continue HAMMER;\n                                                                        }\n                                                                        break HAMMER;\n                                                                    }\n                                                                    if ((block[i1 + 3] & 0xff) > (block[i2 + 3] & 0xff)) {\n                                                                        continue HAMMER;\n                                                                    }\n                                                                    break HAMMER;\n                                                                }\n                                                                if ((quadrant[i1 + 1] > quadrant[i2 + 1])) {\n                                                                    continue HAMMER;\n                                                                }\n                                                                break HAMMER;\n                                                            }\n                                                            if ((block[i1 + 2] & 0xff) > (block[i2 + 2] & 0xff)) {\n                                                                continue HAMMER;\n                                                            }\n                                                            break HAMMER;\n                                                        }\n                                                        if ((quadrant[i1] > quadrant[i2])) {\n                                                            continue HAMMER;\n                                                        }\n                                                        break HAMMER;\n                                                    }\n                                                    if ((block[i1 + 1] & 0xff) > (block[i2 + 1] & 0xff)) {\n                                                        continue HAMMER;\n                                                    }\n                                                    break HAMMER;\n\n                                                }\n                                                break HAMMER;\n                                            } // while x > 0\n                                            if ((block[i1] & 0xff) > (block[i2] & 0xff)) {\n                                                continue HAMMER;\n                                            }\n                                            break HAMMER;\n                                        }\n                                        if ((block[i1 + 5] & 0xff) > (block[i2 + 5] & 0xff)) {\n                                            continue HAMMER;\n                                        }\n                                        break HAMMER;\n                                    }\n                                    if ((block[i1 + 4] & 0xff) > (block[i2 + 4] & 0xff)) {\n                                        continue HAMMER;\n                                    }\n                                    break HAMMER;\n                                }\n                                if ((block[i1 + 3] & 0xff) > (block[i2 + 3] & 0xff)) {\n                                    continue HAMMER;\n                                }\n                                break HAMMER;\n                            }\n                            if ((block[i1 + 2] & 0xff) > (block[i2 + 2] & 0xff)) {\n                                continue HAMMER;\n                            }\n                            break HAMMER;\n                        }\n                        if ((block[i1 + 1] & 0xff) > (block[i2 + 1] & 0xff)) {\n                            continue HAMMER;\n                        }\n                        break HAMMER;\n\n                    } // HAMMER\n                    // end inline mainGTU\n\n                    fmap[j] = v;\n                }\n\n                if (firstAttemptShadow && (i <= hi)\n                        && (workDoneShadow > workLimitShadow)) {\n                    break HP;\n                }\n            }\n        }\n\n        this.workDone = workDoneShadow;\n        return firstAttemptShadow && (workDoneShadow > workLimitShadow);\n    }\n\n/*--\n   LBZ2: The following is an implementation of\n   an elegant 3-way quicksort for strings,\n   described in a paper \"Fast Algorithms for\n   Sorting and Searching Strings\", by Robert\n   Sedgewick and Jon L. Bentley.\n--*/\n\n    private static void vswap(final int[] fmap, int p1, int p2, int n) {\n        n += p1;\n        while (p1 < n) {\n            final int t = fmap[p1];\n            fmap[p1++] = fmap[p2];\n            fmap[p2++] = t;\n        }\n    }\n\n    private static byte med3(final byte a, final byte b, final byte c) {\n        return (a < b) ? (b < c ? b : a < c ? c : a) : (b > c ? b : a > c ? c\n                : a);\n    }\n\n    private static final int SMALL_THRESH = 20;\n    private static final int DEPTH_THRESH = 10;\n    private static final int WORK_FACTOR = 30;\n\n    /**\n     * Method \"mainQSort3\", file \"blocksort.c\", BZip2 1.0.2\n     */\n    private void mainQSort3(final BZip2CompressorOutputStream.Data dataShadow,\n                            final int loSt, final int hiSt, final int dSt,\n                            final int last) {\n        final int[] stack_ll = this.stack_ll;\n        final int[] stack_hh = this.stack_hh;\n        final int[] stack_dd = this.stack_dd;\n        final int[] fmap = dataShadow.fmap;\n        final byte[] block = dataShadow.block;\n\n        stack_ll[0] = loSt;\n        stack_hh[0] = hiSt;\n        stack_dd[0] = dSt;\n\n        for (int sp = 1; --sp >= 0;) {\n            final int lo = stack_ll[sp];\n            final int hi = stack_hh[sp];\n            final int d = stack_dd[sp];\n\n            if ((hi - lo < SMALL_THRESH) || (d > DEPTH_THRESH)) {\n                if (mainSimpleSort(dataShadow, lo, hi, d, last)) {\n                    return;\n                }\n            } else {\n                final int d1 = d + 1;\n                final int med = med3(block[fmap[lo] + d1],\n                        block[fmap[hi] + d1], block[fmap[(lo + hi) >>> 1] + d1]) & 0xff;\n\n                int unLo = lo;\n                int unHi = hi;\n                int ltLo = lo;\n                int gtHi = hi;\n\n                while (true) {\n                    while (unLo <= unHi) {\n                        final int n = (block[fmap[unLo] + d1] & 0xff)\n                                - med;\n                        if (n == 0) {\n                            final int temp = fmap[unLo];\n                            fmap[unLo++] = fmap[ltLo];\n                            fmap[ltLo++] = temp;\n                        } else if (n < 0) {\n                            unLo++;\n                        } else {\n                            break;\n                        }\n                    }\n\n                    while (unLo <= unHi) {\n                        final int n = (block[fmap[unHi] + d1] & 0xff)\n                                - med;\n                        if (n == 0) {\n                            final int temp = fmap[unHi];\n                            fmap[unHi--] = fmap[gtHi];\n                            fmap[gtHi--] = temp;\n                        } else if (n > 0) {\n                            unHi--;\n                        } else {\n                            break;\n                        }\n                    }\n\n                    if (unLo > unHi) {\n                        break;\n                    }\n                    final int temp = fmap[unLo];\n                    fmap[unLo++] = fmap[unHi];\n                    fmap[unHi--] = temp;\n                }\n\n                if (gtHi < ltLo) {\n                    stack_ll[sp] = lo;\n                    stack_hh[sp] = hi;\n                    stack_dd[sp] = d1;\n                    sp++;\n                } else {\n                    int n = ((ltLo - lo) < (unLo - ltLo)) ? (ltLo - lo) : (unLo - ltLo);\n                    vswap(fmap, lo, unLo - n, n);\n                    int m = ((hi - gtHi) < (gtHi - unHi)) ? (hi - gtHi) : (gtHi - unHi);\n                    vswap(fmap, unLo, hi - m + 1, m);\n\n                    n = lo + unLo - ltLo - 1;\n                    m = hi - (gtHi - unHi) + 1;\n\n                    stack_ll[sp] = lo;\n                    stack_hh[sp] = n;\n                    stack_dd[sp] = d;\n                    sp++;\n\n                    stack_ll[sp] = n + 1;\n                    stack_hh[sp] = m - 1;\n                    stack_dd[sp] = d1;\n                    sp++;\n\n                    stack_ll[sp] = m;\n                    stack_hh[sp] = hi;\n                    stack_dd[sp] = d;\n                    sp++;\n                }\n            }\n        }\n    }\n\n    private static final int SETMASK = (1 << 21);\n    private static final int CLEARMASK = (~SETMASK);\n\n    final void mainSort(final BZip2CompressorOutputStream.Data dataShadow,\n                        final int lastShadow) {\n        final int[] runningOrder = this.mainSort_runningOrder;\n        final int[] copy = this.mainSort_copy;\n        final boolean[] bigDone = this.mainSort_bigDone;\n        final int[] ftab = this.ftab;\n        final byte[] block = dataShadow.block;\n        final int[] fmap = dataShadow.fmap;\n        final char[] quadrant = this.quadrant;\n        final int workLimitShadow = this.workLimit;\n        final boolean firstAttemptShadow = this.firstAttempt;\n\n        // LBZ2: Set up the 2-byte frequency table\n        for (int i = 65537; --i >= 0;) {\n            ftab[i] = 0;\n        }\n\n        /*\n         * In the various block-sized structures, live data runs from 0 to\n         * last+NUM_OVERSHOOT_BYTES inclusive. First, set up the overshoot area\n         * for block.\n         */\n        for (int i = 0; i < BZip2Constants.NUM_OVERSHOOT_BYTES; i++) {\n            block[lastShadow + i + 2] = block[(i % (lastShadow + 1)) + 1];\n        }\n        for (int i = lastShadow + BZip2Constants.NUM_OVERSHOOT_BYTES +1; --i >= 0;) {\n            quadrant[i] = 0;\n        }\n        block[0] = block[lastShadow + 1];\n\n        // LBZ2: Complete the initial radix sort:\n\n        int c1 = block[0] & 0xff;\n        for (int i = 0; i <= lastShadow; i++) {\n            final int c2 = block[i + 1] & 0xff;\n            ftab[(c1 << 8) + c2]++;\n            c1 = c2;\n        }\n\n        for (int i = 1; i <= 65536; i++) {\n            ftab[i] += ftab[i - 1];\n        }\n\n        c1 = block[1] & 0xff;\n        for (int i = 0; i < lastShadow; i++) {\n            final int c2 = block[i + 2] & 0xff;\n            fmap[--ftab[(c1 << 8) + c2]] = i;\n            c1 = c2;\n        }\n\n        fmap[--ftab[((block[lastShadow + 1] & 0xff) << 8) + (block[1] & 0xff)]] = lastShadow;\n\n        /*\n         * LBZ2: Now ftab contains the first loc of every small bucket. Calculate the\n         * running order, from smallest to largest big bucket.\n         */\n        for (int i = 256; --i >= 0;) {\n            bigDone[i] = false;\n            runningOrder[i] = i;\n        }\n\n        // h = 364, 121, 40, 13, 4, 1\n        for (int h = 364; h != 1;) { //NOSONAR\n            h /= 3;\n            for (int i = h; i <= 255; i++) {\n                final int vv = runningOrder[i];\n                final int a = ftab[(vv + 1) << 8] - ftab[vv << 8];\n                final int b = h - 1;\n                int j = i;\n                for (int ro = runningOrder[j - h]; (ftab[(ro + 1) << 8] - ftab[ro << 8]) > a; ro = runningOrder[j\n                        - h]) {\n                    runningOrder[j] = ro;\n                    j -= h;\n                    if (j <= b) {\n                        break;\n                    }\n                }\n                runningOrder[j] = vv;\n            }\n        }\n\n        /*\n         * LBZ2: The main sorting loop.\n         */\n        for (int i = 0; i <= 255; i++) {\n            /*\n             * LBZ2: Process big buckets, starting with the least full.\n             */\n            final int ss = runningOrder[i];\n\n            // Step 1:\n            /*\n             * LBZ2: Complete the big bucket [ss] by quicksorting any unsorted small\n             * buckets [ss, j]. Hopefully previous pointer-scanning phases have\n             * already completed many of the small buckets [ss, j], so we don't\n             * have to sort them at all.\n             */\n            for (int j = 0; j <= 255; j++) {\n                final int sb = (ss << 8) + j;\n                final int ftab_sb = ftab[sb];\n                if ((ftab_sb & SETMASK) != SETMASK) {\n                    final int lo = ftab_sb & CLEARMASK;\n                    final int hi = (ftab[sb + 1] & CLEARMASK) - 1;\n                    if (hi > lo) {\n                        mainQSort3(dataShadow, lo, hi, 2, lastShadow);\n                        if (firstAttemptShadow\n                                && (this.workDone > workLimitShadow)) {\n                            return;\n                        }\n                    }\n                    ftab[sb] = ftab_sb | SETMASK;\n                }\n            }\n\n            // Step 2:\n            // LBZ2: Now scan this big bucket so as to synthesise the\n            // sorted order for small buckets [t, ss] for all t != ss.\n\n            for (int j = 0; j <= 255; j++) {\n                copy[j] = ftab[(j << 8) + ss] & CLEARMASK;\n            }\n\n            for (int j = ftab[ss << 8] & CLEARMASK, hj = (ftab[(ss + 1) << 8] & CLEARMASK); j < hj; j++) {\n                final int fmap_j = fmap[j];\n                c1 = block[fmap_j] & 0xff;\n                if (!bigDone[c1]) {\n                    fmap[copy[c1]] = (fmap_j == 0) ? lastShadow : (fmap_j - 1);\n                    copy[c1]++;\n                }\n            }\n\n            for (int j = 256; --j >= 0;) {\n                ftab[(j << 8) + ss] |= SETMASK;\n            }\n\n            // Step 3:\n            /*\n             * LBZ2: The ss big bucket is now done. Record this fact, and update the\n             * quadrant descriptors. Remember to update quadrants in the\n             * overshoot area too, if necessary. The \"if (i < 255)\" test merely\n             * skips this updating for the last bucket processed, since updating\n             * for the last bucket is pointless.\n             */\n            bigDone[ss] = true;\n\n            if (i < 255) {\n                final int bbStart = ftab[ss << 8] & CLEARMASK;\n                final int bbSize = (ftab[(ss + 1) << 8] & CLEARMASK) - bbStart;\n                int shifts = 0;\n\n                while ((bbSize >> shifts) > 65534) {\n                    shifts++;\n                }\n\n                for (int j = 0; j < bbSize; j++) {\n                    final int a2update = fmap[bbStart + j];\n                    final char qVal = (char) (j >> shifts);\n                    quadrant[a2update] = qVal;\n                    if (a2update < BZip2Constants.NUM_OVERSHOOT_BYTES) {\n                        quadrant[a2update + lastShadow + 1] = qVal;\n                    }\n                }\n            }\n\n        }\n    }\n\n}"
  },
  {
    "path": "app/src/main/java/org/apache/commons/compress/compressors/bzip2/CRC.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage org.apache.commons.compress.compressors.bzip2;\n\n/**\n * A simple class the hold and calculate the CRC for sanity checking of the\n * data.\n *\n * @NotThreadSafe\n */\n// Copyright 2008 Torsten Curdt\nclass CRC {\n    private static final int[] crc32Table = {\n            0x00000000, 0x04c11db7, 0x09823b6e, 0x0d4326d9,\n            0x130476dc, 0x17c56b6b, 0x1a864db2, 0x1e475005,\n            0x2608edb8, 0x22c9f00f, 0x2f8ad6d6, 0x2b4bcb61,\n            0x350c9b64, 0x31cd86d3, 0x3c8ea00a, 0x384fbdbd,\n            0x4c11db70, 0x48d0c6c7, 0x4593e01e, 0x4152fda9,\n            0x5f15adac, 0x5bd4b01b, 0x569796c2, 0x52568b75,\n            0x6a1936c8, 0x6ed82b7f, 0x639b0da6, 0x675a1011,\n            0x791d4014, 0x7ddc5da3, 0x709f7b7a, 0x745e66cd,\n            0x9823b6e0, 0x9ce2ab57, 0x91a18d8e, 0x95609039,\n            0x8b27c03c, 0x8fe6dd8b, 0x82a5fb52, 0x8664e6e5,\n            0xbe2b5b58, 0xbaea46ef, 0xb7a96036, 0xb3687d81,\n            0xad2f2d84, 0xa9ee3033, 0xa4ad16ea, 0xa06c0b5d,\n            0xd4326d90, 0xd0f37027, 0xddb056fe, 0xd9714b49,\n            0xc7361b4c, 0xc3f706fb, 0xceb42022, 0xca753d95,\n            0xf23a8028, 0xf6fb9d9f, 0xfbb8bb46, 0xff79a6f1,\n            0xe13ef6f4, 0xe5ffeb43, 0xe8bccd9a, 0xec7dd02d,\n            0x34867077, 0x30476dc0, 0x3d044b19, 0x39c556ae,\n            0x278206ab, 0x23431b1c, 0x2e003dc5, 0x2ac12072,\n            0x128e9dcf, 0x164f8078, 0x1b0ca6a1, 0x1fcdbb16,\n            0x018aeb13, 0x054bf6a4, 0x0808d07d, 0x0cc9cdca,\n            0x7897ab07, 0x7c56b6b0, 0x71159069, 0x75d48dde,\n            0x6b93dddb, 0x6f52c06c, 0x6211e6b5, 0x66d0fb02,\n            0x5e9f46bf, 0x5a5e5b08, 0x571d7dd1, 0x53dc6066,\n            0x4d9b3063, 0x495a2dd4, 0x44190b0d, 0x40d816ba,\n            0xaca5c697, 0xa864db20, 0xa527fdf9, 0xa1e6e04e,\n            0xbfa1b04b, 0xbb60adfc, 0xb6238b25, 0xb2e29692,\n            0x8aad2b2f, 0x8e6c3698, 0x832f1041, 0x87ee0df6,\n            0x99a95df3, 0x9d684044, 0x902b669d, 0x94ea7b2a,\n            0xe0b41de7, 0xe4750050, 0xe9362689, 0xedf73b3e,\n            0xf3b06b3b, 0xf771768c, 0xfa325055, 0xfef34de2,\n            0xc6bcf05f, 0xc27dede8, 0xcf3ecb31, 0xcbffd686,\n            0xd5b88683, 0xd1799b34, 0xdc3abded, 0xd8fba05a,\n            0x690ce0ee, 0x6dcdfd59, 0x608edb80, 0x644fc637,\n            0x7a089632, 0x7ec98b85, 0x738aad5c, 0x774bb0eb,\n            0x4f040d56, 0x4bc510e1, 0x46863638, 0x42472b8f,\n            0x5c007b8a, 0x58c1663d, 0x558240e4, 0x51435d53,\n            0x251d3b9e, 0x21dc2629, 0x2c9f00f0, 0x285e1d47,\n            0x36194d42, 0x32d850f5, 0x3f9b762c, 0x3b5a6b9b,\n            0x0315d626, 0x07d4cb91, 0x0a97ed48, 0x0e56f0ff,\n            0x1011a0fa, 0x14d0bd4d, 0x19939b94, 0x1d528623,\n            0xf12f560e, 0xf5ee4bb9, 0xf8ad6d60, 0xfc6c70d7,\n            0xe22b20d2, 0xe6ea3d65, 0xeba91bbc, 0xef68060b,\n            0xd727bbb6, 0xd3e6a601, 0xdea580d8, 0xda649d6f,\n            0xc423cd6a, 0xc0e2d0dd, 0xcda1f604, 0xc960ebb3,\n            0xbd3e8d7e, 0xb9ff90c9, 0xb4bcb610, 0xb07daba7,\n            0xae3afba2, 0xaafbe615, 0xa7b8c0cc, 0xa379dd7b,\n            0x9b3660c6, 0x9ff77d71, 0x92b45ba8, 0x9675461f,\n            0x8832161a, 0x8cf30bad, 0x81b02d74, 0x857130c3,\n            0x5d8a9099, 0x594b8d2e, 0x5408abf7, 0x50c9b640,\n            0x4e8ee645, 0x4a4ffbf2, 0x470cdd2b, 0x43cdc09c,\n            0x7b827d21, 0x7f436096, 0x7200464f, 0x76c15bf8,\n            0x68860bfd, 0x6c47164a, 0x61043093, 0x65c52d24,\n            0x119b4be9, 0x155a565e, 0x18197087, 0x1cd86d30,\n            0x029f3d35, 0x065e2082, 0x0b1d065b, 0x0fdc1bec,\n            0x3793a651, 0x3352bbe6, 0x3e119d3f, 0x3ad08088,\n            0x2497d08d, 0x2056cd3a, 0x2d15ebe3, 0x29d4f654,\n            0xc5a92679, 0xc1683bce, 0xcc2b1d17, 0xc8ea00a0,\n            0xd6ad50a5, 0xd26c4d12, 0xdf2f6bcb, 0xdbee767c,\n            0xe3a1cbc1, 0xe760d676, 0xea23f0af, 0xeee2ed18,\n            0xf0a5bd1d, 0xf464a0aa, 0xf9278673, 0xfde69bc4,\n            0x89b8fd09, 0x8d79e0be, 0x803ac667, 0x84fbdbd0,\n            0x9abc8bd5, 0x9e7d9662, 0x933eb0bb, 0x97ffad0c,\n            0xafb010b1, 0xab710d06, 0xa6322bdf, 0xa2f33668,\n            0xbcb4666d, 0xb8757bda, 0xb5365d03, 0xb1f740b4\n    };\n\n    CRC() {\n        initializeCRC();\n    }\n\n    void initializeCRC() {\n        globalCrc = 0xffffffff;\n    }\n\n    int getFinalCRC() {\n        return ~globalCrc;\n    }\n\n    int getGlobalCRC() {\n        return globalCrc;\n    }\n\n    void setGlobalCRC(final int newCrc) {\n        globalCrc = newCrc;\n    }\n\n    void updateCRC(final int inCh) {\n        int temp = (globalCrc >> 24) ^ inCh;\n        if (temp < 0) {\n            temp = 256 + temp;\n        }\n        globalCrc = (globalCrc << 8) ^ CRC.crc32Table[temp];\n    }\n\n    void updateCRC(final int inCh, int repeat) {\n        int globalCrcShadow = this.globalCrc;\n        while (repeat-- > 0) {\n            final int temp = (globalCrcShadow >> 24) ^ inCh;\n            globalCrcShadow = (globalCrcShadow << 8) ^ crc32Table[(temp >= 0)\n                    ? temp\n                    : (temp + 256)];\n        }\n        this.globalCrc = globalCrcShadow;\n    }\n\n    private int globalCrc;\n}"
  },
  {
    "path": "app/src/main/java/org/apache/commons/compress/compressors/bzip2/Rand.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage org.apache.commons.compress.compressors.bzip2;\n\n/**\n * Random numbers for both the compress and decompress BZip2 classes.\n */\n// Copyright 2009 sebbASF\nfinal class Rand {\n\n    private static final int[] RNUMS = {\n        619, 720, 127, 481, 931, 816, 813, 233, 566, 247,\n        985, 724, 205, 454, 863, 491, 741, 242, 949, 214,\n        733, 859, 335, 708, 621, 574,  73, 654, 730, 472,\n        419, 436, 278, 496, 867, 210, 399, 680, 480,  51,\n        878, 465, 811, 169, 869, 675, 611, 697, 867, 561,\n        862, 687, 507, 283, 482, 129, 807, 591, 733, 623,\n        150, 238,  59, 379, 684, 877, 625, 169, 643, 105,\n        170, 607, 520, 932, 727, 476, 693, 425, 174, 647,\n         73, 122, 335, 530, 442, 853, 695, 249, 445, 515,\n        909, 545, 703, 919, 874, 474, 882, 500, 594, 612,\n        641, 801, 220, 162, 819, 984, 589, 513, 495, 799,\n        161, 604, 958, 533, 221, 400, 386, 867, 600, 782,\n        382, 596, 414, 171, 516, 375, 682, 485, 911, 276,\n         98, 553, 163, 354, 666, 933, 424, 341, 533, 870,\n        227, 730, 475, 186, 263, 647, 537, 686, 600, 224,\n        469,  68, 770, 919, 190, 373, 294, 822, 808, 206,\n        184, 943, 795, 384, 383, 461, 404, 758, 839, 887,\n        715,  67, 618, 276, 204, 918, 873, 777, 604, 560,\n        951, 160, 578, 722,  79, 804,  96, 409, 713, 940,\n        652, 934, 970, 447, 318, 353, 859, 672, 112, 785,\n        645, 863, 803, 350, 139,  93, 354,  99, 820, 908,\n        609, 772, 154, 274, 580, 184,  79, 626, 630, 742,\n        653, 282, 762, 623, 680,  81, 927, 626, 789, 125,\n        411, 521, 938, 300, 821,  78, 343, 175, 128, 250,\n        170, 774, 972, 275, 999, 639, 495,  78, 352, 126,\n        857, 956, 358, 619, 580, 124, 737, 594, 701, 612,\n        669, 112, 134, 694, 363, 992, 809, 743, 168, 974,\n        944, 375, 748,  52, 600, 747, 642, 182, 862,  81,\n        344, 805, 988, 739, 511, 655, 814, 334, 249, 515,\n        897, 955, 664, 981, 649, 113, 974, 459, 893, 228,\n        433, 837, 553, 268, 926, 240, 102, 654, 459, 51,\n        686, 754, 806, 760, 493, 403, 415, 394, 687, 700,\n        946, 670, 656, 610, 738, 392, 760, 799, 887, 653,\n        978, 321, 576, 617, 626, 502, 894, 679, 243, 440,\n        680, 879, 194, 572, 640, 724, 926,  56, 204, 700,\n        707, 151, 457, 449, 797, 195, 791, 558, 945, 679,\n        297,  59,  87, 824, 713, 663, 412, 693, 342, 606,\n        134, 108, 571, 364, 631, 212, 174, 643, 304, 329,\n        343,  97, 430, 751, 497, 314, 983, 374, 822, 928,\n        140, 206,  73, 263, 980, 736, 876, 478, 430, 305,\n        170, 514, 364, 692, 829,  82, 855, 953, 676, 246,\n        369, 970, 294, 750, 807, 827, 150, 790, 288, 923,\n        804, 378, 215, 828, 592, 281, 565, 555, 710,  82,\n        896, 831, 547, 261, 524, 462, 293, 465, 502,  56,\n        661, 821, 976, 991, 658, 869, 905, 758, 745, 193,\n        768, 550, 608, 933, 378, 286, 215, 979, 792, 961,\n         61, 688, 793, 644, 986, 403, 106, 366, 905, 644,\n        372, 567, 466, 434, 645, 210, 389, 550, 919, 135,\n        780, 773, 635, 389, 707, 100, 626, 958, 165, 504,\n        920, 176, 193, 713, 857, 265, 203,  50, 668, 108,\n        645, 990, 626, 197, 510, 357, 358, 850, 858, 364,\n        936, 638\n    };\n\n    /**\n     * Return the random number at a specific index.\n     *\n     * @param i the index\n     * @return the random number\n     */\n    static int rNums(final int i){\n        return RNUMS[i];\n    }\n}"
  },
  {
    "path": "app/src/main/java/org/apache/commons/compress/compressors/gzip/GzipCompressorInputStream.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage org.apache.commons.compress.compressors.gzip;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.IOException;\nimport java.io.EOFException;\nimport java.io.InputStream;\nimport java.io.DataInput;\nimport java.io.DataInputStream;\nimport java.io.BufferedInputStream;\nimport java.nio.charset.StandardCharsets;\nimport java.util.zip.DataFormatException;\nimport java.util.zip.Deflater;\nimport java.util.zip.Inflater;\nimport java.util.zip.CRC32;\n\nimport org.apache.commons.compress.compressors.CompressorInputStream;\nimport org.apache.commons.compress.utils.ByteUtils;\nimport org.apache.commons.compress.utils.CountingInputStream;\nimport org.apache.commons.compress.utils.IOUtils;\nimport org.apache.commons.compress.utils.InputStreamStatistics;\n\n/**\n * Input stream that decompresses .gz files.\n *\n * <p>This supports decompressing concatenated .gz files which is important\n * when decompressing standalone .gz files.</p>\n *\n * <p>\n * {@link java.util.zip.GZIPInputStream} doesn't decompress concatenated .gz\n * files: it stops after the first member and silently ignores the rest.\n * It doesn't leave the read position to point to the beginning of the next\n * member, which makes it difficult workaround the lack of concatenation\n * support.\n * </p>\n *\n * <p>\n * Instead of using <code>GZIPInputStream</code>, this class has its own .gz\n * container format decoder. The actual decompression is done with\n * {@link java.util.zip.Inflater}.\n * </p>\n *\n * <p>If you use the constructor {@code GzipCompressorInputStream(in)}\n * or {@code GzipCompressorInputStream(in, false)} with some {@code\n * InputStream} {@code in} then {@link #read} will return -1 as soon\n * as the first internal member has been read completely. The stream\n * {@code in} will be positioned at the start of the second gzip\n * member if there is one.</p>\n *\n * <p>If you use the constructor {@code GzipCompressorInputStream(in,\n * true)} with some {@code InputStream} {@code in} then {@link #read}\n * will return -1 once the stream {@code in} has been exhausted. The\n * data read from a stream constructed this way will consist of the\n * concatenated data of all gzip members contained inside {@code\n * in}.</p>\n *\n * @see \"https://tools.ietf.org/html/rfc1952\"\n */\n// Copyright 2011 sebbASF\npublic class GzipCompressorInputStream extends CompressorInputStream\n        implements InputStreamStatistics {\n\n    // Header flags\n    // private static final int FTEXT = 0x01; // Uninteresting for us\n    private static final int FHCRC = 0x02;\n    private static final int FEXTRA = 0x04;\n    private static final int FNAME = 0x08;\n    private static final int FCOMMENT = 0x10;\n    private static final int FRESERVED = 0xE0;\n\n    private final CountingInputStream countingStream;\n\n    // Compressed input stream, possibly wrapped in a\n    // BufferedInputStream, always wrapped in countingStream above\n    private final InputStream in;\n\n    // True if decompressing multi member streams.\n    private final boolean decompressConcatenated;\n\n    // Buffer to hold the input data\n    private final byte[] buf = new byte[8192];\n\n    // Amount of data in buf.\n    private int bufUsed;\n\n    // Decompressor\n    private Inflater inf = new Inflater(true);\n\n    // CRC32 from uncompressed data\n    private final CRC32 crc = new CRC32();\n\n    // True once everything has been decompressed\n    private boolean endReached = false;\n\n    // used in no-arg read method\n    private final byte[] oneByte = new byte[1];\n\n    private final GzipParameters parameters = new GzipParameters();\n\n    /**\n     * Constructs a new input stream that decompresses gzip-compressed data\n     * from the specified input stream.\n     * <p>\n     * This is equivalent to <code>GzipCompressorInputStream(inputStream, false)</code> and thus will not decompress\n     * concatenated .gz files.\n     *\n     * @param inputStream The InputStream from which this object should be created of\n     * @throws IOException If the stream could not be created\n     */\n    public GzipCompressorInputStream(final InputStream inputStream)\n            throws IOException {\n        this(inputStream, false);\n    }\n\n    /**\n     * Constructs a new input stream that decompresses gzip-compressed data\n     * from the specified input stream.\n     * <p>\n     * If <code>decompressConcatenated</code> is {@code false}:\n     * This decompressor might read more input than it will actually use.\n     * If <code>inputStream</code> supports <code>mark</code> and\n     * <code>reset</code>, then the input position will be adjusted\n     * so that it is right after the last byte of the compressed stream.\n     * If <code>mark</code> isn't supported, the input position will be\n     * undefined.\n     *\n     * @param inputStream            the InputStream from which this object should\n     *                               be created of\n     * @param decompressConcatenated if true, decompress until the end of the input;\n     *                               if false, stop after the first .gz member\n     * @throws IOException if the stream could not be created\n     */\n    public GzipCompressorInputStream(final InputStream inputStream,\n                                     final boolean decompressConcatenated)\n            throws IOException {\n        countingStream = new CountingInputStream(inputStream);\n        // Mark support is strictly needed for concatenated files only,\n        // but it's simpler if it is always available.\n        if (countingStream.markSupported()) {\n            in = countingStream;\n        } else {\n            in = new BufferedInputStream(countingStream);\n        }\n\n        this.decompressConcatenated = decompressConcatenated;\n        init(true);\n    }\n\n    /**\n     * Provides the stream's meta data - may change with each stream\n     * when decompressing concatenated streams.\n     *\n     * @return the stream's meta data\n     * @since 1.8\n     */\n    public GzipParameters getMetaData() {\n        return parameters;\n    }\n\n    private boolean init(final boolean isFirstMember) throws IOException {\n        if (!isFirstMember && !decompressConcatenated) {\n            throw new IOException(\"Initialised without a first member nor the decompressConcatenated is enabled\");\n        }\n\n        // Check the magic bytes without a possibility of EOFException.\n        final int magic0 = in.read();\n\n        // If end of input was reached after decompressing at least\n        // one .gz member, we have reached the end of the file successfully.\n        if (magic0 == -1 && !isFirstMember) {\n            return false;\n        }\n\n        if (magic0 != 31 || in.read() != 139) {\n            throw new IOException(isFirstMember ? \"Input is not in the .gz format\"\n                    : \"Garbage after a valid .gz stream\");\n        }\n\n        // Parsing the rest of the header may throw EOFException.\n        final DataInput inData = new DataInputStream(in);\n        final int method = inData.readUnsignedByte();\n        if (method != Deflater.DEFLATED) {\n            throw new IOException(\"Unsupported compression method \" + method + \" in the .gz header\");\n        }\n\n        final int flg = inData.readUnsignedByte();\n        if ((flg & FRESERVED) != 0) {\n            throw new IOException(\n                    \"Reserved flags are set in the .gz header\");\n        }\n\n        parameters.setModificationTime(ByteUtils.fromLittleEndian(inData, 4) * 1000);\n        switch (inData.readUnsignedByte()) { // extra flags\n            case 2:\n                parameters.setCompressionLevel(Deflater.BEST_COMPRESSION);\n                break;\n            case 4:\n                parameters.setCompressionLevel(Deflater.BEST_SPEED);\n                break;\n            default:\n                // ignored for now\n                break;\n        }\n        parameters.setOperatingSystem(inData.readUnsignedByte());\n\n        // Extra field, ignored\n        if ((flg & FEXTRA) != 0) {\n            int xlen = inData.readUnsignedByte();\n            xlen |= inData.readUnsignedByte() << 8;\n\n            // This isn't as efficient as calling in.skip would be,\n            // but it's lazier to handle unexpected end of input this way.\n            // Most files don't have an extra field anyway.\n            while (xlen-- > 0) {\n                inData.readUnsignedByte();\n            }\n        }\n\n        // Original file name\n        if ((flg & FNAME) != 0) {\n            parameters.setFilename(new String(readToNull(inData),\n                    StandardCharsets.ISO_8859_1));\n        }\n\n        // Comment\n        if ((flg & FCOMMENT) != 0) {\n            parameters.setComment(new String(readToNull(inData),\n                    StandardCharsets.ISO_8859_1));\n        }\n\n        // Header \"CRC16\" which is actually a truncated CRC32 (which isn't\n        // as good as real CRC16). I don't know if any encoder implementation\n        // sets this, so it's not worth trying to verify it. GNU gzip 1.4\n        // doesn't support this field, but zlib seems to be able to at least\n        // skip over it.\n        if ((flg & FHCRC) != 0) {\n            inData.readShort();\n        }\n\n        // Reset\n        inf.reset();\n        crc.reset();\n\n        return true;\n    }\n\n    private static byte[] readToNull(final DataInput inData) throws IOException {\n        try (final ByteArrayOutputStream bos = new ByteArrayOutputStream()) {\n            int b;\n            while ((b = inData.readUnsignedByte()) != 0x00) { // NOPMD NOSONAR\n                bos.write(b);\n            }\n            return bos.toByteArray();\n        }\n    }\n\n    @Override\n    public int read() throws IOException {\n        return read(oneByte, 0, 1) == -1 ? -1 : oneByte[0] & 0xFF;\n    }\n\n    /**\n     * {@inheritDoc}\n     *\n     * @since 1.1\n     */\n    @Override\n    public int read(final byte[] b, int off, int len) throws IOException {\n        if (len == 0) {\n            return 0;\n        }\n        if (endReached) {\n            return -1;\n        }\n\n        int size = 0;\n\n        while (len > 0) {\n            if (inf.needsInput()) {\n                // Remember the current position because we may need to\n                // rewind after reading too much input.\n                in.mark(buf.length);\n\n                bufUsed = in.read(buf);\n                if (bufUsed == -1) {\n                    throw new EOFException();\n                }\n\n                inf.setInput(buf, 0, bufUsed);\n            }\n\n            final int ret;\n            try {\n                ret = inf.inflate(b, off, len);\n            } catch (final DataFormatException e) { // NOSONAR\n                throw new IOException(\"Gzip-compressed data is corrupt\");\n            }\n\n            crc.update(b, off, ret);\n            off += ret;\n            len -= ret;\n            size += ret;\n            count(ret);\n\n            if (inf.finished()) {\n                // We may have read too many bytes. Rewind the read\n                // position to match the actual amount used.\n                in.reset();\n\n                final int skipAmount = bufUsed - inf.getRemaining();\n                if (IOUtils.skip(in, skipAmount) != skipAmount) {\n                    throw new IOException();\n                }\n\n                bufUsed = 0;\n\n                final DataInput inData = new DataInputStream(in);\n\n                // CRC32\n                final long crcStored = ByteUtils.fromLittleEndian(inData, 4);\n\n                if (crcStored != crc.getValue()) {\n                    throw new IOException(\"Gzip-compressed data is corrupt (CRC32 error)\");\n                }\n\n                // Uncompressed size modulo 2^32 (ISIZE in the spec)\n                final long isize = ByteUtils.fromLittleEndian(inData, 4);\n\n                if (isize != (inf.getBytesWritten() & 0xffffffffL)) {\n                    throw new IOException(\"Gzip-compressed data is corrupt (uncompressed size mismatch)\");\n                }\n\n                // See if this is the end of the file.\n                if (!decompressConcatenated || !init(false)) {\n                    inf.end();\n                    inf = null;\n                    endReached = true;\n                    return size == 0 ? -1 : size;\n                }\n            }\n        }\n\n        return size;\n    }\n\n    /**\n     * Checks if the signature matches what is expected for a .gz file.\n     *\n     * @param signature the bytes to check\n     * @param length    the number of bytes to check\n     * @return true if this is a .gz stream, false otherwise\n     * @since 1.1\n     */\n    public static boolean matches(final byte[] signature, final int length) {\n        return length >= 2 && signature[0] == 31 && signature[1] == -117;\n    }\n\n    /**\n     * Closes the input stream (unless it is System.in).\n     *\n     * @since 1.2\n     */\n    @Override\n    public void close() throws IOException {\n        if (inf != null) {\n            inf.end();\n            inf = null;\n        }\n\n        if (this.in != System.in) {\n            this.in.close();\n        }\n    }\n\n    /**\n     * @since 1.17\n     */\n    @Override\n    public long getCompressedCount() {\n        return countingStream.getBytesRead();\n    }\n}"
  },
  {
    "path": "app/src/main/java/org/apache/commons/compress/compressors/gzip/GzipCompressorOutputStream.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage org.apache.commons.compress.compressors.gzip;\n\nimport java.io.IOException;\nimport java.io.OutputStream;\nimport java.nio.ByteBuffer;\nimport java.nio.ByteOrder;\nimport java.nio.charset.StandardCharsets;\nimport java.util.zip.CRC32;\nimport java.util.zip.Deflater;\nimport java.util.zip.GZIPInputStream;\nimport java.util.zip.GZIPOutputStream;\n\nimport org.apache.commons.compress.compressors.CompressorOutputStream;\n\n/**\n * Compressed output stream using the gzip format. This implementation improves\n * over the standard {@link GZIPOutputStream} class by allowing\n * the configuration of the compression level and the header metadata (file name,\n * comment, modification time, operating system and extra flags).\n *\n * @see <a href=\"https://tools.ietf.org/html/rfc1952\">GZIP File Format Specification</a>\n */\n// Copyright 2008 Torsten Curdt\npublic class GzipCompressorOutputStream extends CompressorOutputStream {\n\n    /** Header flag indicating a file name follows the header */\n    private static final int FNAME = 1 << 3;\n\n    /** Header flag indicating a comment follows the header */\n    private static final int FCOMMENT = 1 << 4;\n\n    /** The underlying stream */\n    private final OutputStream out;\n\n    /** Deflater used to compress the data */\n    private final Deflater deflater;\n\n    /** The buffer receiving the compressed data from the deflater */\n    private final byte[] deflateBuffer = new byte[512];\n\n    /** Indicates if the stream has been closed */\n    private boolean closed;\n\n    /** The checksum of the uncompressed data */\n    private final CRC32 crc = new CRC32();\n\n    /**\n     * Creates a gzip compressed output stream with the default parameters.\n     * @param out the stream to compress to\n     * @throws IOException if writing fails\n     */\n    public GzipCompressorOutputStream(final OutputStream out) throws IOException {\n        this(out, new GzipParameters());\n    }\n\n    /**\n     * Creates a gzip compressed output stream with the specified parameters.\n     * @param out the stream to compress to\n     * @param parameters the parameters to use\n     * @throws IOException if writing fails\n     *\n     * @since 1.7\n     */\n    public GzipCompressorOutputStream(final OutputStream out, final GzipParameters parameters) throws IOException {\n        this.out = out;\n        this.deflater = new Deflater(parameters.getCompressionLevel(), true);\n\n        writeHeader(parameters);\n    }\n\n    private void writeHeader(final GzipParameters parameters) throws IOException {\n        final String filename = parameters.getFilename();\n        final String comment = parameters.getComment();\n\n        final ByteBuffer buffer = ByteBuffer.allocate(10);\n        buffer.order(ByteOrder.LITTLE_ENDIAN);\n        buffer.putShort((short) GZIPInputStream.GZIP_MAGIC);\n        buffer.put((byte) Deflater.DEFLATED); // compression method (8: deflate)\n        buffer.put((byte) ((filename != null ? FNAME : 0) | (comment != null ? FCOMMENT : 0))); // flags\n        buffer.putInt((int) (parameters.getModificationTime() / 1000));\n\n        // extra flags\n        final int compressionLevel = parameters.getCompressionLevel();\n        if (compressionLevel == Deflater.BEST_COMPRESSION) {\n            buffer.put((byte) 2);\n        } else if (compressionLevel == Deflater.BEST_SPEED) {\n            buffer.put((byte) 4);\n        } else {\n            buffer.put((byte) 0);\n        }\n\n        buffer.put((byte) parameters.getOperatingSystem());\n\n        out.write(buffer.array());\n\n        if (filename != null) {\n            out.write(filename.getBytes(StandardCharsets.ISO_8859_1));\n            out.write(0);\n        }\n\n        if (comment != null) {\n            out.write(comment.getBytes(StandardCharsets.ISO_8859_1));\n            out.write(0);\n        }\n    }\n\n    private void writeTrailer() throws IOException {\n        final ByteBuffer buffer = ByteBuffer.allocate(8);\n        buffer.order(ByteOrder.LITTLE_ENDIAN);\n        buffer.putInt((int) crc.getValue());\n        buffer.putInt(deflater.getTotalIn());\n\n        out.write(buffer.array());\n    }\n\n    @Override\n    public void write(final int b) throws IOException {\n        write(new byte[]{(byte) (b & 0xff)}, 0, 1);\n    }\n\n    /**\n     * {@inheritDoc}\n     *\n     * @since 1.1\n     */\n    @Override\n    public void write(final byte[] buffer) throws IOException {\n        write(buffer, 0, buffer.length);\n    }\n\n    /**\n     * {@inheritDoc}\n     *\n     * @since 1.1\n     */\n    @Override\n    public void write(final byte[] buffer, final int offset, final int length) throws IOException {\n        if (deflater.finished()) {\n            throw new IOException(\"Cannot write more data, the end of the compressed data stream has been reached\");\n        }\n        if (length > 0) {\n            deflater.setInput(buffer, offset, length);\n\n            while (!deflater.needsInput()) {\n                deflate();\n            }\n\n            crc.update(buffer, offset, length);\n        }\n    }\n\n    private void deflate() throws IOException {\n        final int length = deflater.deflate(deflateBuffer, 0, deflateBuffer.length);\n        if (length > 0) {\n            out.write(deflateBuffer, 0, length);\n        }\n    }\n\n    /**\n     * Finishes writing compressed data to the underlying stream without closing it.\n     *\n     * @since 1.7\n     * @throws IOException on error\n     */\n    public void finish() throws IOException {\n        if (!deflater.finished()) {\n            deflater.finish();\n\n            while (!deflater.finished()) {\n                deflate();\n            }\n\n            writeTrailer();\n        }\n    }\n\n    /**\n     * {@inheritDoc}\n     *\n     * @since 1.7\n     */\n    @Override\n    public void flush() throws IOException {\n        out.flush();\n    }\n\n    @Override\n    public void close() throws IOException {\n        if (!closed) {\n            try {\n                finish();\n            } finally {\n                deflater.end();\n                out.close();\n                closed = true;\n            }\n        }\n    }\n\n}"
  },
  {
    "path": "app/src/main/java/org/apache/commons/compress/compressors/gzip/GzipParameters.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage org.apache.commons.compress.compressors.gzip;\n\nimport java.util.zip.Deflater;\n\n/**\n * Parameters for the GZIP compressor.\n *\n * @since 1.7\n */\n// Copyright 2013 Emmanuel Bourg\npublic class GzipParameters {\n\n    private int compressionLevel = Deflater.DEFAULT_COMPRESSION;\n    private long modificationTime;\n    private String filename;\n    private String comment;\n    private int operatingSystem = 255; // Unknown OS by default\n\n    public int getCompressionLevel() {\n        return compressionLevel;\n    }\n\n    /**\n     * Sets the compression level.\n     *\n     * @param compressionLevel the compression level (between 0 and 9)\n     * @see Deflater#NO_COMPRESSION\n     * @see Deflater#BEST_SPEED\n     * @see Deflater#DEFAULT_COMPRESSION\n     * @see Deflater#BEST_COMPRESSION\n     */\n    public void setCompressionLevel(final int compressionLevel) {\n        if (compressionLevel < -1 || compressionLevel > 9) {\n            throw new IllegalArgumentException(\"Invalid gzip compression level: \" + compressionLevel);\n        }\n        this.compressionLevel = compressionLevel;\n    }\n\n    public long getModificationTime() {\n        return modificationTime;\n    }\n\n    /**\n     * Sets the modification time of the compressed file.\n     *\n     * @param modificationTime the modification time, in milliseconds\n     */\n    public void setModificationTime(final long modificationTime) {\n        this.modificationTime = modificationTime;\n    }\n\n    public String getFilename() {\n        return filename;\n    }\n\n    /**\n     * Sets the name of the compressed file.\n     *\n     * @param fileName the name of the file without the directory path\n     */\n    public void setFilename(final String fileName) {\n        this.filename = fileName;\n    }\n\n    public String getComment() {\n        return comment;\n    }\n\n    public void setComment(final String comment) {\n        this.comment = comment;\n    }\n\n    public int getOperatingSystem() {\n        return operatingSystem;\n    }\n\n    /**\n     * Sets the operating system on which the compression took place.\n     * The defined values are:\n     * <ul>\n     *   <li>0: FAT file system (MS-DOS, OS/2, NT/Win32)</li>\n     *   <li>1: Amiga</li>\n     *   <li>2: VMS (or OpenVMS)</li>\n     *   <li>3: Unix</li>\n     *   <li>4: VM/CMS</li>\n     *   <li>5: Atari TOS</li>\n     *   <li>6: HPFS file system (OS/2, NT)</li>\n     *   <li>7: Macintosh</li>\n     *   <li>8: Z-System</li>\n     *   <li>9: CP/M</li>\n     *   <li>10: TOPS-20</li>\n     *   <li>11: NTFS file system (NT)</li>\n     *   <li>12: QDOS</li>\n     *   <li>13: Acorn RISCOS</li>\n     *   <li>255: Unknown</li>\n     * </ul>\n     *\n     * @param operatingSystem the code of the operating system\n     */\n    public void setOperatingSystem(final int operatingSystem) {\n        this.operatingSystem = operatingSystem;\n    }\n}"
  },
  {
    "path": "app/src/main/java/org/apache/commons/compress/compressors/gzip/GzipUtils.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage org.apache.commons.compress.compressors.gzip;\n\nimport java.util.LinkedHashMap;\nimport java.util.Map;\nimport org.apache.commons.compress.compressors.FileNameUtil;\n\n/**\n * Utility code for the gzip compression format.\n * @ThreadSafe\n */\n// Copyright 2009 sebbASF\npublic class GzipUtils {\n\n    private static final FileNameUtil fileNameUtil;\n\n    static {\n        // using LinkedHashMap so .tgz is preferred over .taz as\n        // compressed extension of .tar as FileNameUtil will use the\n        // first one found\n        final Map<String, String> uncompressSuffix =\n            new LinkedHashMap<>();\n        uncompressSuffix.put(\".tgz\", \".tar\");\n        uncompressSuffix.put(\".taz\", \".tar\");\n        uncompressSuffix.put(\".svgz\", \".svg\");\n        uncompressSuffix.put(\".cpgz\", \".cpio\");\n        uncompressSuffix.put(\".wmz\", \".wmf\");\n        uncompressSuffix.put(\".emz\", \".emf\");\n        uncompressSuffix.put(\".gz\", \"\");\n        uncompressSuffix.put(\".z\", \"\");\n        uncompressSuffix.put(\"-gz\", \"\");\n        uncompressSuffix.put(\"-z\", \"\");\n        uncompressSuffix.put(\"_z\", \"\");\n        fileNameUtil = new FileNameUtil(uncompressSuffix, \".gz\");\n    }\n\n    /** Private constructor to prevent instantiation of this utility class. */\n    private GzipUtils() {\n    }\n\n    /**\n     * Detects common gzip suffixes in the given file name.\n     *\n     * @param fileName name of a file\n     * @return {@code true} if the file name has a common gzip suffix,\n     *         {@code false} otherwise\n     */\n    public static boolean isCompressedFilename(final String fileName) {\n        return fileNameUtil.isCompressedFilename(fileName);\n    }\n\n    /**\n     * Maps the given name of a gzip-compressed file to the name that the\n     * file should have after uncompression. Commonly used file type specific\n     * suffixes like \".tgz\" or \".svgz\" are automatically detected and\n     * correctly mapped. For example the name \"package.tgz\" is mapped to\n     * \"package.tar\". And any file names with the generic \".gz\" suffix\n     * (or any other generic gzip suffix) is mapped to a name without that\n     * suffix. If no gzip suffix is detected, then the file name is returned\n     * unmapped.\n     *\n     * @param fileName name of a file\n     * @return name of the corresponding uncompressed file\n     */\n    public static String getUncompressedFilename(final String fileName) {\n        return fileNameUtil.getUncompressedFilename(fileName);\n    }\n\n    /**\n     * Maps the given file name to the name that the file should have after\n     * compression with gzip. Common file types with custom suffixes for\n     * compressed versions are automatically detected and correctly mapped.\n     * For example the name \"package.tar\" is mapped to \"package.tgz\". If no\n     * custom mapping is applicable, then the default \".gz\" suffix is appended\n     * to the file name.\n     *\n     * @param fileName name of a file\n     * @return name of the corresponding compressed file\n     */\n    public static String getCompressedFilename(final String fileName) {\n        return fileNameUtil.getCompressedFilename(fileName);\n    }\n\n}"
  },
  {
    "path": "app/src/main/java/org/apache/commons/compress/utils/ArchiveUtils.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage org.apache.commons.compress.utils;\n\nimport java.nio.charset.StandardCharsets;\nimport java.util.Arrays;\n\nimport org.apache.commons.compress.archivers.ArchiveEntry;\n\n/**\n * Generic Archive utilities\n */\n// Copyright 2009 sebbASF\npublic class ArchiveUtils {\n\n    private static final int MAX_SANITIZED_NAME_LENGTH = 255;\n\n    /** Private constructor to prevent instantiation of this utility class. */\n    private ArchiveUtils(){\n    }\n\n    /**\n     * Generates a string containing the name, isDirectory setting and size of an entry.\n     * <p>\n     * For example:\n     * <pre>\n     * -    2000 main.c\n     * d     100 testfiles\n     * </pre>\n     *\n     * @param entry the entry\n     * @return the representation of the entry\n     */\n    public static String toString(final ArchiveEntry entry){\n        final StringBuilder sb = new StringBuilder();\n        sb.append(entry.isDirectory()? 'd' : '-');// c.f. \"ls -l\" output\n        final String size = Long.toString(entry.getSize());\n        sb.append(' ');\n        // Pad output to 7 places, leading spaces\n        for(int i=7; i > size.length(); i--){\n            sb.append(' ');\n        }\n        sb.append(size);\n        sb.append(' ').append(entry.getName());\n        return sb.toString();\n    }\n\n    /**\n     * Check if buffer contents matches Ascii String.\n     *\n     * @param expected expected string\n     * @param buffer the buffer\n     * @param offset offset to read from\n     * @param length length of the buffer\n     * @return {@code true} if buffer is the same as the expected string\n     */\n    public static boolean matchAsciiBuffer(\n            final String expected, final byte[] buffer, final int offset, final int length){\n        final byte[] buffer1;\n        buffer1 = expected.getBytes(StandardCharsets.US_ASCII);\n        return isEqual(buffer1, 0, buffer1.length, buffer, offset, length, false);\n    }\n\n    /**\n     * Check if buffer contents matches Ascii String.\n     *\n     * @param expected the expected strin\n     * @param buffer the buffer\n     * @return {@code true} if buffer is the same as the expected string\n     */\n    public static boolean matchAsciiBuffer(final String expected, final byte[] buffer){\n        return matchAsciiBuffer(expected, buffer, 0, buffer.length);\n    }\n\n    /**\n     * Convert a string to Ascii bytes.\n     * Used for comparing \"magic\" strings which need to be independent of the default Locale.\n     *\n     * @param inputString string to convert\n     * @return the bytes\n     */\n    public static byte[] toAsciiBytes(final String inputString){\n        return inputString.getBytes(StandardCharsets.US_ASCII);\n    }\n\n    /**\n     * Convert an input byte array to a String using the ASCII character set.\n     *\n     * @param inputBytes bytes to convert\n     * @return the bytes, interpreted as an Ascii string\n     */\n    public static String toAsciiString(final byte[] inputBytes){\n        return new String(inputBytes, StandardCharsets.US_ASCII);\n    }\n\n    /**\n     * Convert an input byte array to a String using the ASCII character set.\n     *\n     * @param inputBytes input byte array\n     * @param offset offset within array\n     * @param length length of array\n     * @return the bytes, interpreted as an Ascii string\n     */\n    public static String toAsciiString(final byte[] inputBytes, final int offset, final int length){\n        return new String(inputBytes, offset, length, StandardCharsets.US_ASCII);\n    }\n\n    /**\n     * Compare byte buffers, optionally ignoring trailing nulls\n     *\n     * @param buffer1 first buffer\n     * @param offset1 first offset\n     * @param length1 first length\n     * @param buffer2 second buffer\n     * @param offset2 second offset\n     * @param length2 second length\n     * @param ignoreTrailingNulls whether to ignore trailing nulls\n     * @return {@code true} if buffer1 and buffer2 have same contents, having regard to trailing nulls\n     */\n    public static boolean isEqual(\n            final byte[] buffer1, final int offset1, final int length1,\n            final byte[] buffer2, final int offset2, final int length2,\n            final boolean ignoreTrailingNulls){\n        final int minLen=length1 < length2 ? length1 : length2;\n        for (int i=0; i < minLen; i++){\n            if (buffer1[offset1+i] != buffer2[offset2+i]){\n                return false;\n            }\n        }\n        if (length1 == length2){\n            return true;\n        }\n        if (ignoreTrailingNulls){\n            if (length1 > length2){\n                for(int i = length2; i < length1; i++){\n                    if (buffer1[offset1+i] != 0){\n                        return false;\n                    }\n                }\n            } else {\n                for(int i = length1; i < length2; i++){\n                    if (buffer2[offset2+i] != 0){\n                        return false;\n                    }\n                }\n            }\n            return true;\n        }\n        return false;\n    }\n\n    /**\n     * Compare byte buffers\n     *\n     * @param buffer1 the first buffer\n     * @param offset1 the first offset\n     * @param length1 the first length\n     * @param buffer2 the second buffer\n     * @param offset2 the second offset\n     * @param length2 the second length\n     * @return {@code true} if buffer1 and buffer2 have same contents\n     */\n    public static boolean isEqual(\n            final byte[] buffer1, final int offset1, final int length1,\n            final byte[] buffer2, final int offset2, final int length2){\n        return isEqual(buffer1, offset1, length1, buffer2, offset2, length2, false);\n    }\n\n    /**\n     * Compare byte buffers\n     *\n     * @param buffer1 the first buffer\n     * @param buffer2 the second buffer\n     * @return {@code true} if buffer1 and buffer2 have same contents\n     */\n    public static boolean isEqual(final byte[] buffer1, final byte[] buffer2 ){\n        return isEqual(buffer1, 0, buffer1.length, buffer2, 0, buffer2.length, false);\n    }\n\n    /**\n     * Compare byte buffers, optionally ignoring trailing nulls\n     *\n     * @param buffer1 the first buffer\n     * @param buffer2 the second buffer\n     * @param ignoreTrailingNulls whether to ignore trailing nulls\n     * @return {@code true} if buffer1 and buffer2 have same contents\n     */\n    public static boolean isEqual(final byte[] buffer1, final byte[] buffer2, final boolean ignoreTrailingNulls){\n        return isEqual(buffer1, 0, buffer1.length, buffer2, 0, buffer2.length, ignoreTrailingNulls);\n    }\n\n    /**\n     * Compare byte buffers, ignoring trailing nulls\n     *\n     * @param buffer1 the first buffer\n     * @param offset1 the first offset\n     * @param length1 the first length\n     * @param buffer2 the second buffer\n     * @param offset2 the second offset\n     * @param length2 the second length\n     * @return {@code true} if buffer1 and buffer2 have same contents, having regard to trailing nulls\n     */\n    public static boolean isEqualWithNull(\n            final byte[] buffer1, final int offset1, final int length1,\n            final byte[] buffer2, final int offset2, final int length2){\n        return isEqual(buffer1, offset1, length1, buffer2, offset2, length2, true);\n    }\n\n    /**\n     * Returns true if the first N bytes of an array are all zero\n     *\n     * @param a\n     *            The array to check\n     * @param size\n     *            The number of characters to check (not the size of the array)\n     * @return true if the first N bytes are zero\n     */\n    public static boolean isArrayZero(final byte[] a, final int size) {\n        for (int i = 0; i < size; i++) {\n            if (a[i] != 0) {\n                return false;\n            }\n        }\n        return true;\n    }\n\n    /**\n     * Returns a \"sanitized\" version of the string given as arguments,\n     * where sanitized means non-printable characters have been\n     * replaced with a question mark and the outcome is not longer\n     * than 255 chars.\n     *\n     * <p>This method is used to clean up file names when they are\n     * used in exception messages as they may end up in log files or\n     * as console output and may have been read from a corrupted\n     * input.</p>\n     *\n     * @param s the string to sanitize\n     * @return a sanitized version of the argument\n     * @since Compress 1.12\n     */\n    public static String sanitize(final String s) {\n        final char[] cs = s.toCharArray();\n        final char[] chars = cs.length <= MAX_SANITIZED_NAME_LENGTH ? cs : Arrays.copyOf(cs, MAX_SANITIZED_NAME_LENGTH);\n        if (cs.length > MAX_SANITIZED_NAME_LENGTH) {\n            for (int i = MAX_SANITIZED_NAME_LENGTH - 3; i < MAX_SANITIZED_NAME_LENGTH; i++) {\n                chars[i] = '.';\n            }\n        }\n        final StringBuilder sb = new StringBuilder();\n        for (final char c : chars) {\n            if (!Character.isISOControl(c)) {\n                final Character.UnicodeBlock block = Character.UnicodeBlock.of(c);\n                if (block != null && block != Character.UnicodeBlock.SPECIALS) {\n                    sb.append(c);\n                    continue;\n                }\n            }\n            sb.append('?');\n        }\n        return sb.toString();\n    }\n\n}"
  },
  {
    "path": "app/src/main/java/org/apache/commons/compress/utils/BitInputStream.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage org.apache.commons.compress.utils;\n\nimport java.io.Closeable;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.nio.ByteOrder;\n\n/**\n * Reads bits from an InputStream.\n * @since 1.10\n * @NotThreadSafe\n */\n// Copyright 2014 Damjan Jovanovic\npublic class BitInputStream implements Closeable {\n    private static final int MAXIMUM_CACHE_SIZE = 63; // bits in long minus sign bit\n    private static final long[] MASKS = new long[MAXIMUM_CACHE_SIZE + 1];\n\n    static {\n        for (int i = 1; i <= MAXIMUM_CACHE_SIZE; i++) {\n            MASKS[i] = (MASKS[i - 1] << 1) + 1;\n        }\n    }\n\n    private final CountingInputStream in;\n    private final ByteOrder byteOrder;\n    private long bitsCached = 0;\n    private int bitsCachedSize = 0;\n\n    /**\n     * Constructor taking an InputStream and its bit arrangement.\n     * @param in the InputStream\n     * @param byteOrder the bit arrangement across byte boundaries,\n     *      either BIG_ENDIAN (aaaaabbb bb000000) or LITTLE_ENDIAN (bbbaaaaa 000000bb)\n     */\n    public BitInputStream(final InputStream in, final ByteOrder byteOrder) {\n        this.in = new CountingInputStream(in);\n        this.byteOrder = byteOrder;\n    }\n\n    @Override\n    public void close() throws IOException {\n        in.close();\n    }\n\n    /**\n     * Clears the cache of bits that have been read from the\n     * underlying stream but not yet provided via {@link #readBits}.\n     */\n    public void clearBitCache() {\n        bitsCached = 0;\n        bitsCachedSize = 0;\n    }\n\n    /**\n     * Returns at most 63 bits read from the underlying stream.\n     *\n     * @param count the number of bits to read, must be a positive\n     * number not bigger than 63.\n     * @return the bits concatenated as a long using the stream's byte order.\n     *         -1 if the end of the underlying stream has been reached before reading\n     *         the requested number of bits\n     * @throws IOException on error\n     */\n    public long readBits(final int count) throws IOException {\n        if (count < 0 || count > MAXIMUM_CACHE_SIZE) {\n            throw new IOException(\"count must not be negative or greater than \" + MAXIMUM_CACHE_SIZE);\n        }\n        if (ensureCache(count)) {\n            return -1;\n        }\n\n        if (bitsCachedSize < count) {\n            return processBitsGreater57(count);\n        }\n        return readCachedBits(count);\n    }\n\n    /**\n     * Returns the number of bits that can be read from this input\n     * stream without reading from the underlying input stream at all.\n     * @return estimate of the number of bits that can be read without reading from the underlying stream\n     * @since 1.16\n     */\n    public int bitsCached() {\n        return bitsCachedSize;\n    }\n\n    /**\n     * Returns an estimate of the number of bits that can be read from\n     * this input stream without blocking by the next invocation of a\n     * method for this input stream.\n     * @throws IOException if the underlying stream throws one when calling available\n     * @return estimate of the number of bits that can be read without blocking\n     * @since 1.16\n     */\n    public long bitsAvailable() throws IOException {\n        return bitsCachedSize + ((long) Byte.SIZE) * in.available();\n    }\n\n    /**\n     * Drops bits until the next bits will be read from a byte boundary.\n     * @since 1.16\n     */\n    public void alignWithByteBoundary() {\n        final int toSkip = bitsCachedSize % Byte.SIZE;\n        if (toSkip > 0) {\n            readCachedBits(toSkip);\n        }\n    }\n\n    /**\n     * Returns the number of bytes read from the underlying stream.\n     *\n     * <p>This includes the bytes read to fill the current cache and\n     * not read as bits so far.</p>\n     * @return the number of bytes read from the underlying stream\n     * @since 1.17\n     */\n    public long getBytesRead() {\n        return in.getBytesRead();\n    }\n\n    private long processBitsGreater57(final int count) throws IOException {\n        final long bitsOut;\n        final int overflowBits;\n        long overflow = 0L;\n\n        // bitsCachedSize >= 57 and left-shifting it 8 bits would cause an overflow\n        final int bitsToAddCount = count - bitsCachedSize;\n        overflowBits = Byte.SIZE - bitsToAddCount;\n        final long nextByte = in.read();\n        if (nextByte < 0) {\n            return nextByte;\n        }\n        if (byteOrder == ByteOrder.LITTLE_ENDIAN) {\n            final long bitsToAdd = nextByte & MASKS[bitsToAddCount];\n            bitsCached |= (bitsToAdd << bitsCachedSize);\n            overflow = (nextByte >>> bitsToAddCount) & MASKS[overflowBits];\n        } else {\n            bitsCached <<= bitsToAddCount;\n            final long bitsToAdd = (nextByte >>> (overflowBits)) & MASKS[bitsToAddCount];\n            bitsCached |= bitsToAdd;\n            overflow = nextByte & MASKS[overflowBits];\n        }\n        bitsOut = bitsCached & MASKS[count];\n        bitsCached = overflow;\n        bitsCachedSize = overflowBits;\n        return bitsOut;\n    }\n\n    private long readCachedBits(final int count) {\n        final long bitsOut;\n        if (byteOrder == ByteOrder.LITTLE_ENDIAN) {\n            bitsOut = (bitsCached & MASKS[count]);\n            bitsCached >>>= count;\n        } else {\n            bitsOut = (bitsCached >> (bitsCachedSize - count)) & MASKS[count];\n        }\n        bitsCachedSize -= count;\n        return bitsOut;\n    }\n\n    /**\n     * Fills the cache up to 56 bits\n     * @param count\n     * @return return true, when EOF\n     * @throws IOException\n     */\n    private boolean ensureCache(final int count) throws IOException {\n        while (bitsCachedSize < count && bitsCachedSize < 57) {\n            final long nextByte = in.read();\n            if (nextByte < 0) {\n                return true;\n            }\n            if (byteOrder == ByteOrder.LITTLE_ENDIAN) {\n                bitsCached |= (nextByte << bitsCachedSize);\n            } else {\n                bitsCached <<= Byte.SIZE;\n                bitsCached |= nextByte;\n            }\n            bitsCachedSize += Byte.SIZE;\n        }\n        return false;\n    }\n\n}"
  },
  {
    "path": "app/src/main/java/org/apache/commons/compress/utils/BoundedInputStream.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage org.apache.commons.compress.utils;\n\nimport java.io.IOException;\nimport java.io.InputStream;\n\n/**\n * A stream that limits reading from a wrapped stream to a given number of bytes.\n * @NotThreadSafe\n * @since 1.6\n */\n// Copyright 2013 Damjan Jovanovic\npublic class BoundedInputStream extends InputStream {\n    private final InputStream in;\n    private long bytesRemaining;\n\n    /**\n     * Creates the stream that will at most read the given amount of\n     * bytes from the given stream.\n     * @param in the stream to read from\n     * @param size the maximum amount of bytes to read\n     */\n    public BoundedInputStream(final InputStream in, final long size) {\n        this.in = in;\n        bytesRemaining = size;\n    }\n\n    @Override\n    public int read() throws IOException {\n        if (bytesRemaining > 0) {\n            --bytesRemaining;\n            return in.read();\n        }\n        return -1;\n    }\n\n    @Override\n    public int read(final byte[] b, final int off, final int len) throws IOException {\n        if (len == 0) {\n            return 0;\n        }\n        if (bytesRemaining == 0) {\n            return -1;\n        }\n        int bytesToRead = len;\n        if (bytesToRead > bytesRemaining) {\n            bytesToRead = (int) bytesRemaining;\n        }\n        final int bytesRead = in.read(b, off, bytesToRead);\n        if (bytesRead >= 0) {\n            bytesRemaining -= bytesRead;\n        }\n        return bytesRead;\n    }\n\n    @Override\n    public void close() {\n        // there isn't anything to close in this stream and the nested\n        // stream is controlled externally\n    }\n\n    /**\n     * @since 1.20\n     */\n    @Override\n    public long skip(final long n) throws IOException {\n        final long bytesToSkip = Math.min(bytesRemaining, n);\n        final long bytesSkipped = in.skip(bytesToSkip);\n        bytesRemaining -= bytesSkipped;\n\n        return bytesSkipped;\n    }\n\n    /**\n     * @return bytes remaining to read\n     * @since 1.21\n     */\n    public long getBytesRemaining() {\n        return bytesRemaining;\n    }\n}"
  },
  {
    "path": "app/src/main/java/org/apache/commons/compress/utils/ByteUtils.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage org.apache.commons.compress.utils;\n\nimport java.io.DataInput;\nimport java.io.DataOutput;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\n\n/**\n * Utility methods for reading and writing bytes.\n * @since 1.14\n */\n// Copyright 2017 Stefan Bodewig\npublic final class ByteUtils {\n\n    /**\n     * Empty array.\n     *\n     * @since 1.21\n     */\n    public static final byte[] EMPTY_BYTE_ARRAY = new byte[0];\n\n    private ByteUtils() { /* no instances */ }\n\n    /**\n     * Used to supply bytes.\n     * @since 1.14\n     */\n    public interface ByteSupplier {\n        /**\n         * The contract is similar to {@link InputStream#read()}, return\n         * the byte as an unsigned int, -1 if there are no more bytes.\n         * @return the supplied byte or -1 if there are no more bytes\n         * @throws IOException if supplying fails\n         */\n        int getAsByte() throws IOException;\n    }\n\n    /**\n     * Used to consume bytes.\n     * @since 1.14\n     */\n    public interface ByteConsumer {\n        /**\n         * The contract is similar to {@link OutputStream#write(int)},\n         * consume the lower eight bytes of the int as a byte.\n         * @param b the byte to consume\n         * @throws IOException if consuming fails\n         */\n        void accept(int b) throws IOException;\n    }\n\n    /**\n     * Reads the given byte array as a little endian long.\n     * @param bytes the byte array to convert\n     * @return the number read\n     */\n    public static long fromLittleEndian(final byte[] bytes) {\n        return fromLittleEndian(bytes, 0, bytes.length);\n    }\n\n    /**\n     * Reads the given byte array as a little endian long.\n     * @param bytes the byte array to convert\n     * @param off the offset into the array that starts the value\n     * @param length the number of bytes representing the value\n     * @return the number read\n     * @throws IllegalArgumentException if len is bigger than eight\n     */\n    public static long fromLittleEndian(final byte[] bytes, final int off, final int length) {\n        checkReadLength(length);\n        long l = 0;\n        for (int i = 0; i < length; i++) {\n            l |= (bytes[off + i] & 0xffL) << (8 * i);\n        }\n        return l;\n    }\n\n    /**\n     * Reads the given number of bytes from the given stream as a little endian long.\n     * @param in the stream to read from\n     * @param length the number of bytes representing the value\n     * @return the number read\n     * @throws IllegalArgumentException if len is bigger than eight\n     * @throws IOException if reading fails or the stream doesn't\n     * contain the given number of bytes anymore\n     */\n    public static long fromLittleEndian(final InputStream in, final int length) throws IOException {\n        // somewhat duplicates the ByteSupplier version in order to save the creation of a wrapper object\n        checkReadLength(length);\n        long l = 0;\n        for (int i = 0; i < length; i++) {\n            final long b = in.read();\n            if (b == -1) {\n                throw new IOException(\"Premature end of data\");\n            }\n            l |= (b << (i * 8));\n        }\n        return l;\n    }\n\n    /**\n     * Reads the given number of bytes from the given supplier as a little endian long.\n     *\n     * <p>Typically used by our InputStreams that need to count the\n     * bytes read as well.</p>\n     *\n     * @param supplier the supplier for bytes\n     * @param length the number of bytes representing the value\n     * @return the number read\n     * @throws IllegalArgumentException if len is bigger than eight\n     * @throws IOException if the supplier fails or doesn't supply the\n     * given number of bytes anymore\n     */\n    public static long fromLittleEndian(final ByteSupplier supplier, final int length) throws IOException {\n        checkReadLength(length);\n        long l = 0;\n        for (int i = 0; i < length; i++) {\n            final long b = supplier.getAsByte();\n            if (b == -1) {\n                throw new IOException(\"Premature end of data\");\n            }\n            l |= (b << (i * 8));\n        }\n        return l;\n    }\n\n    /**\n     * Reads the given number of bytes from the given input as little endian long.\n     * @param in the input to read from\n     * @param length the number of bytes representing the value\n     * @return the number read\n     * @throws IllegalArgumentException if len is bigger than eight\n     * @throws IOException if reading fails or the stream doesn't\n     * contain the given number of bytes anymore\n     */\n    public static long fromLittleEndian(final DataInput in, final int length) throws IOException {\n        // somewhat duplicates the ByteSupplier version in order to save the creation of a wrapper object\n        checkReadLength(length);\n        long l = 0;\n        for (int i = 0; i < length; i++) {\n            final long b = in.readUnsignedByte();\n            l |= (b << (i * 8));\n        }\n        return l;\n    }\n\n    /**\n     * Inserts the given value into the array as a little endian\n     * sequence of the given length starting at the given offset.\n     * @param b the array to write into\n     * @param value the value to insert\n     * @param off the offset into the array that receives the first byte\n     * @param length the number of bytes to use to represent the value\n     */\n    public static void toLittleEndian(final byte[] b, final long value, final int off, final int length) {\n        long num = value;\n        for (int i = 0; i < length; i++) {\n            b[off + i] = (byte) (num & 0xff);\n            num >>= 8;\n        }\n    }\n\n    /**\n     * Writes the given value to the given stream as a little endian\n     * array of the given length.\n     * @param out the stream to write to\n     * @param value the value to write\n     * @param length the number of bytes to use to represent the value\n     * @throws IOException if writing fails\n     */\n    public static void toLittleEndian(final OutputStream out, final long value, final int length)\n            throws IOException {\n        // somewhat duplicates the ByteConsumer version in order to save the creation of a wrapper object\n        long num = value;\n        for (int i = 0; i < length; i++) {\n            out.write((int) (num & 0xff));\n            num >>= 8;\n        }\n    }\n\n    /**\n     * Provides the given value to the given consumer as a little endian\n     * sequence of the given length.\n     * @param consumer the consumer to provide the bytes to\n     * @param value the value to provide\n     * @param length the number of bytes to use to represent the value\n     * @throws IOException if writing fails\n     */\n    public static void toLittleEndian(final ByteConsumer consumer, final long value, final int length)\n            throws IOException {\n        long num = value;\n        for (int i = 0; i < length; i++) {\n            consumer.accept((int) (num & 0xff));\n            num >>= 8;\n        }\n    }\n\n    /**\n     * Writes the given value to the given stream as a little endian\n     * array of the given length.\n     * @param out the output to write to\n     * @param value the value to write\n     * @param length the number of bytes to use to represent the value\n     * @throws IOException if writing fails\n     */\n    public static void toLittleEndian(final DataOutput out, final long value, final int length)\n            throws IOException {\n        // somewhat duplicates the ByteConsumer version in order to save the creation of a wrapper object\n        long num = value;\n        for (int i = 0; i < length; i++) {\n            out.write((int) (num & 0xff));\n            num >>= 8;\n        }\n    }\n\n    /**\n     * {@link ByteSupplier} based on {@link InputStream}.\n     * @since 1.14\n     */\n    public static class InputStreamByteSupplier implements ByteSupplier {\n        private final InputStream is;\n        public InputStreamByteSupplier(final InputStream is) {\n            this.is = is;\n        }\n        @Override\n        public int getAsByte() throws IOException {\n            return is.read();\n        }\n    }\n\n    /**\n     * {@link ByteConsumer} based on {@link OutputStream}.\n     * @since 1.14\n     */\n    public static class OutputStreamByteConsumer implements ByteConsumer {\n        private final OutputStream os;\n        public OutputStreamByteConsumer(final OutputStream os) {\n            this.os = os;\n        }\n        @Override\n        public void accept(final int b) throws IOException {\n            os.write(b);\n        }\n    }\n\n    private static void checkReadLength(final int length) {\n        if (length > 8) {\n            throw new IllegalArgumentException(\"Can't read more than eight bytes into a long value\");\n        }\n    }\n}"
  },
  {
    "path": "app/src/main/java/org/apache/commons/compress/utils/CharsetNames.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage org.apache.commons.compress.utils;\n\n/**\n * Character encoding names required of every implementation of the Java platform.\n *\n * From the Java documentation <a href=\"https://download.oracle.com/javase/6/docs/api/java/nio/charset/Charset.html\">Standard\n * charsets</a>:\n * <p>\n * <cite>Every implementation of the Java platform is required to support the following character encodings. Consult the\n * release documentation for your implementation to see if any other encodings are supported. Consult the release\n * documentation for your implementation to see if any other encodings are supported. </cite>\n * </p>\n *\n * <dl>\n * <dt><code>US-ASCII</code></dt>\n * <dd>Seven-bit ASCII, a.k.a. ISO646-US, a.k.a. the Basic Latin block of the Unicode character set.</dd>\n * <dt><code>ISO-8859-1</code></dt>\n * <dd>ISO Latin Alphabet No. 1, a.k.a. ISO-LATIN-1.</dd>\n * <dt><code>UTF-8</code></dt>\n * <dd>Eight-bit Unicode Transformation Format.</dd>\n * <dt><code>UTF-16BE</code></dt>\n * <dd>Sixteen-bit Unicode Transformation Format, big-endian byte order.</dd>\n * <dt><code>UTF-16LE</code></dt>\n * <dd>Sixteen-bit Unicode Transformation Format, little-endian byte order.</dd>\n * <dt><code>UTF-16</code></dt>\n * <dd>Sixteen-bit Unicode Transformation Format, byte order specified by a mandatory initial byte-order mark (either order\n * accepted on input, big-endian used on output.)</dd>\n * </dl>\n *\n * <p>This perhaps would best belong in the [lang] project. Even if a similar interface is defined in [lang], it is not\n * foreseen that [compress] would be made to depend on [lang].</p>\n *\n * @see <a href=\"https://download.oracle.com/javase/6/docs/api/java/nio/charset/Charset.html\">Standard charsets</a>\n * @since 1.4\n */\n// Copyright 2012 Gary Gregory\npublic class CharsetNames {\n    /**\n     * CharEncodingISO Latin Alphabet No. 1, a.k.a. ISO-LATIN-1.\n     * <p>\n     * Every implementation of the Java platform is required to support this character encoding.\n     * </p>\n     *\n     * @see <a href=\"https://download.oracle.com/javase/6/docs/api/java/nio/charset/Charset.html\">Standard charsets</a>\n     */\n    public static final String ISO_8859_1 = \"ISO-8859-1\";\n\n    /**\n     * <p>\n     * Seven-bit ASCII, also known as ISO646-US, also known as the Basic Latin block of the Unicode character set.\n     * </p>\n     * <p>\n     * Every implementation of the Java platform is required to support this character encoding.\n     * </p>\n     *\n     * @see <a href=\"https://download.oracle.com/javase/6/docs/api/java/nio/charset/Charset.html\">Standard charsets</a>\n     */\n    public static final String US_ASCII = \"US-ASCII\";\n\n    /**\n     * <p>\n     * Sixteen-bit Unicode Transformation Format, The byte order specified by a mandatory initial byte-order mark\n     * (either order accepted on input, big-endian used on output)\n     * </p>\n     * <p>\n     * Every implementation of the Java platform is required to support this character encoding.\n     * </p>\n     *\n     * @see <a href=\"https://download.oracle.com/javase/6/docs/api/java/nio/charset/Charset.html\">Standard charsets</a>\n     */\n    public static final String UTF_16 = \"UTF-16\";\n\n    /**\n     * <p>\n     * Sixteen-bit Unicode Transformation Format, big-endian byte order.\n     * </p>\n     * <p>\n     * Every implementation of the Java platform is required to support this character encoding.\n     * </p>\n     *\n     * @see <a href=\"https://download.oracle.com/javase/6/docs/api/java/nio/charset/Charset.html\">Standard charsets</a>\n     */\n    public static final String UTF_16BE = \"UTF-16BE\";\n\n    /**\n     * <p>\n     * Sixteen-bit Unicode Transformation Format, little-endian byte order.\n     * </p>\n     * <p>\n     * Every implementation of the Java platform is required to support this character encoding.\n     * </p>\n     *\n     * @see <a href=\"https://download.oracle.com/javase/6/docs/api/java/nio/charset/Charset.html\">Standard charsets</a>\n     */\n    public static final String UTF_16LE = \"UTF-16LE\";\n\n    /**\n     * <p>\n     * Eight-bit Unicode Transformation Format.\n     * </p>\n     * <p>\n     * Every implementation of the Java platform is required to support this character encoding.\n     * </p>\n     *\n     * @see <a href=\"https://download.oracle.com/javase/6/docs/api/java/nio/charset/Charset.html\">Standard charsets</a>\n     */\n    public static final String UTF_8 = \"UTF-8\";\n}"
  },
  {
    "path": "app/src/main/java/org/apache/commons/compress/utils/CloseShieldFilterInputStream.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage org.apache.commons.compress.utils;\n\nimport java.io.FilterInputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\n\n/**\n * Re-implements {@link FilterInputStream#close()} to do nothing.\n * @since 1.14\n */\n// Copyright 2017 Stefan Bodewig\npublic class CloseShieldFilterInputStream extends FilterInputStream {\n\n    public CloseShieldFilterInputStream(final InputStream in) {\n        super(in);\n    }\n\n    @Override\n    public void close() throws IOException {\n        // NO IMPLEMENTATION.\n    }\n\n}"
  },
  {
    "path": "app/src/main/java/org/apache/commons/compress/utils/CountingInputStream.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage org.apache.commons.compress.utils;\n\nimport java.io.FilterInputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\n\n/**\n * Input stream that tracks the number of bytes read.\n * @since 1.3\n * @NotThreadSafe\n */\n// Copyright 2011 Stefan Bodewig\npublic class CountingInputStream extends FilterInputStream {\n    private long bytesRead;\n\n    public CountingInputStream(final InputStream in) {\n        super(in);\n    }\n\n    @Override\n    public int read() throws IOException {\n        final int r = in.read();\n        if (r >= 0) {\n            count(1);\n        }\n        return r;\n    }\n\n    @Override\n    public int read(final byte[] b) throws IOException {\n        return read(b, 0, b.length);\n    }\n\n    @Override\n    public int read(final byte[] b, final int off, final int len) throws IOException {\n        if (len == 0) {\n            return 0;\n        }\n        final int r = in.read(b, off, len);\n        if (r >= 0) {\n            count(r);\n        }\n        return r;\n    }\n\n    /**\n     * Increments the counter of already read bytes.\n     * Doesn't increment if the EOF has been hit (read == -1)\n     *\n     * @param read the number of bytes read\n     */\n    protected final void count(final long read) {\n        if (read != -1) {\n            bytesRead += read;\n        }\n    }\n\n    /**\n     * Returns the current number of bytes read from this stream.\n     * @return the number of read bytes\n     */\n    public long getBytesRead() {\n        return bytesRead;\n    }\n}"
  },
  {
    "path": "app/src/main/java/org/apache/commons/compress/utils/CountingOutputStream.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage org.apache.commons.compress.utils;\n\nimport java.io.FilterOutputStream;\nimport java.io.IOException;\nimport java.io.OutputStream;\n\n/**\n * Stream that tracks the number of bytes read.\n * @since 1.3\n * @NotThreadSafe\n */\n// Copyright 2011 Stefan Bodewig\npublic class CountingOutputStream extends FilterOutputStream {\n    private long bytesWritten = 0;\n\n    public CountingOutputStream(final OutputStream out) {\n        super(out);\n    }\n\n    @Override\n    public void write(final int b) throws IOException {\n        out.write(b);\n        count(1);\n    }\n    @Override\n    public void write(final byte[] b) throws IOException {\n        write(b, 0, b.length);\n    }\n    @Override\n    public void write(final byte[] b, final int off, final int len) throws IOException {\n        out.write(b, off, len);\n        count(len);\n    }\n\n    /**\n     * Increments the counter of already written bytes.\n     * Doesn't increment if the EOF has been hit (written == -1)\n     *\n     * @param written the number of bytes written\n     */\n    protected void count(final long written) {\n        if (written != -1) {\n            bytesWritten += written;\n        }\n    }\n\n    /**\n     * Returns the current number of bytes written to this stream.\n     * @return the number of written bytes\n     */\n    public long getBytesWritten() {\n        return bytesWritten;\n    }\n}"
  },
  {
    "path": "app/src/main/java/org/apache/commons/compress/utils/FixedLengthBlockOutputStream.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage org.apache.commons.compress.utils;\n\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.OutputStream;\nimport java.nio.ByteBuffer;\nimport java.nio.ByteOrder;\nimport java.nio.channels.ClosedChannelException;\nimport java.nio.channels.WritableByteChannel;\nimport java.util.Locale;\nimport java.util.concurrent.atomic.AtomicBoolean;\n\n/**\n * This class supports writing to an OutputStream or WritableByteChannel in fixed length blocks.\n * <p>It can be be used to support output to devices such as tape drives that require output in this\n * format. If the final block does not have enough content to fill an entire block, the output will\n * be padded to a full block size.</p>\n *\n * <p>This class can be used to support TAR,PAX, and CPIO blocked output to character special devices.\n * It is not recommended that this class be used unless writing to such devices, as the padding\n * serves no useful purpose in such cases.</p>\n *\n * <p>This class should normally wrap a FileOutputStream or associated WritableByteChannel directly.\n * If there is an intervening filter that modified the output, such as a CompressorOutputStream, or\n * performs its own buffering, such as BufferedOutputStream,  output to the device may\n * no longer be of the specified size.</p>\n *\n * <p>Any content written to this stream should be self-delimiting and should tolerate any padding\n * added to fill the last block.</p>\n *\n * @since 1.15\n */\n// Copyright 2017 Simon Spero\npublic class FixedLengthBlockOutputStream extends OutputStream implements WritableByteChannel {\n\n    private final WritableByteChannel out;\n    private final int blockSize;\n    private final ByteBuffer buffer;\n    private final AtomicBoolean closed = new AtomicBoolean(false);\n\n    /**\n     * Create a fixed length block output stream with given destination stream and block size\n     * @param os   The stream to wrap.\n     * @param blockSize The block size to use.\n     */\n    public FixedLengthBlockOutputStream(final OutputStream os, final int blockSize) {\n        if (os instanceof FileOutputStream) {\n            final FileOutputStream fileOutputStream = (FileOutputStream) os;\n            out = fileOutputStream.getChannel();\n            buffer = ByteBuffer.allocateDirect(blockSize);\n        } else {\n            out = new BufferAtATimeOutputChannel(os);\n            buffer = ByteBuffer.allocate(blockSize);\n        }\n        this.blockSize = blockSize;\n    }\n\n    /**\n     * Create a fixed length block output stream with given destination writable byte channel and block size\n     * @param out   The writable byte channel to wrap.\n     * @param blockSize The block size to use.\n     */\n    public FixedLengthBlockOutputStream(final WritableByteChannel out, final int blockSize) {\n        this.out = out;\n        this.blockSize = blockSize;\n        this.buffer = ByteBuffer.allocateDirect(blockSize);\n    }\n\n    private void maybeFlush() throws IOException {\n        if (!buffer.hasRemaining()) {\n            writeBlock();\n        }\n    }\n\n    private void writeBlock() throws IOException {\n        buffer.flip();\n        final int i = out.write(buffer);\n        final boolean hasRemaining = buffer.hasRemaining();\n        if (i != blockSize || hasRemaining) {\n            final String msg = String.format(Locale.ROOT, \"Failed to write %,d bytes atomically. Only wrote  %,d\", blockSize, i);\n            throw new IOException(msg);\n        }\n        buffer.clear();\n    }\n\n    @Override\n    public void write(final int b) throws IOException {\n        if (!isOpen()) {\n            throw new ClosedChannelException();\n        }\n        buffer.put((byte) b);\n        maybeFlush();\n    }\n\n    @Override\n    public void write(final byte[] b, final int offset, final int length) throws IOException {\n        if (!isOpen()) {\n            throw new ClosedChannelException();\n        }\n        int off = offset;\n        int len = length;\n        while (len > 0) {\n            final int n = Math.min(len, buffer.remaining());\n            buffer.put(b, off, n);\n            maybeFlush();\n            len -= n;\n            off += n;\n        }\n    }\n\n    @Override\n    public int write(final ByteBuffer src) throws IOException {\n        if (!isOpen()) {\n            throw new ClosedChannelException();\n        }\n        final int srcRemaining = src.remaining();\n\n        if (srcRemaining < buffer.remaining()) {\n            // if don't have enough bytes in src to fill up a block we must buffer\n            buffer.put(src);\n        } else {\n            int srcLeft = srcRemaining;\n            final int savedLimit = src.limit();\n            // If we're not at the start of buffer, we have some bytes already  buffered\n            // fill up the reset of buffer and write the block.\n            if (buffer.position() != 0) {\n                final int n = buffer.remaining();\n                src.limit(src.position() + n);\n                buffer.put(src);\n                writeBlock();\n                srcLeft -= n;\n            }\n            // whilst we have enough bytes in src for complete blocks,\n            // write them directly from src without copying them to buffer\n            while (srcLeft >= blockSize) {\n                src.limit(src.position() + blockSize);\n                out.write(src);\n                srcLeft -= blockSize;\n            }\n            // copy any remaining bytes into buffer\n            src.limit(savedLimit);\n            buffer.put(src);\n        }\n        return srcRemaining;\n    }\n\n    @Override\n    public boolean isOpen() {\n        if (!out.isOpen()) {\n            closed.set(true);\n        }\n        return !closed.get();\n    }\n\n    /**\n     * Potentially pads and then writes the current block to the underlying stream.\n     * @throws IOException if writing fails\n     */\n    public void flushBlock() throws IOException {\n        if (buffer.position() != 0) {\n            padBlock();\n            writeBlock();\n        }\n    }\n\n    @Override\n    public void close() throws IOException {\n        if (closed.compareAndSet(false, true)) {\n            try {\n                flushBlock();\n            } finally {\n                out.close();\n            }\n        }\n    }\n\n    private void padBlock() {\n        buffer.order(ByteOrder.nativeOrder());\n        int bytesToWrite = buffer.remaining();\n        if (bytesToWrite > 8) {\n            final int align = buffer.position() & 7;\n            if (align != 0) {\n                final int limit = 8 - align;\n                for (int i = 0; i < limit; i++) {\n                    buffer.put((byte) 0);\n                }\n                bytesToWrite -= limit;\n            }\n\n            while (bytesToWrite >= 8) {\n                buffer.putLong(0L);\n                bytesToWrite -= 8;\n            }\n        }\n        while (buffer.hasRemaining()) {\n            buffer.put((byte) 0);\n        }\n    }\n\n    /**\n     * Helper class to provide channel wrapper for arbitrary output stream that doesn't alter the\n     * size of writes.  We can't use Channels.newChannel, because for non FileOutputStreams, it\n     * breaks up writes into 8KB max chunks. Since the purpose of this class is to always write\n     * complete blocks, we need to write a simple class to take care of it.\n     */\n    private static class BufferAtATimeOutputChannel implements WritableByteChannel {\n\n        private final OutputStream out;\n        private final AtomicBoolean closed = new AtomicBoolean(false);\n\n        private BufferAtATimeOutputChannel(final OutputStream out) {\n            this.out = out;\n        }\n\n        @Override\n        public int write(final ByteBuffer buffer) throws IOException {\n            if (!isOpen()) {\n                throw new ClosedChannelException();\n            }\n            if (!buffer.hasArray()) {\n                throw new IOException(\"Direct buffer somehow written to BufferAtATimeOutputChannel\");\n            }\n\n            try {\n                final int pos = buffer.position();\n                final int len = buffer.limit() - pos;\n                out.write(buffer.array(), buffer.arrayOffset() + pos, len);\n                buffer.position(buffer.limit());\n                return len;\n            } catch (final IOException e) {\n                try {\n                    close();\n                } catch (final IOException ignored) { //NOSONAR\n                }\n                throw e;\n            }\n        }\n\n        @Override\n        public boolean isOpen() {\n            return !closed.get();\n        }\n\n        @Override\n        public void close() throws IOException {\n            if (closed.compareAndSet(false, true)) {\n                out.close();\n            }\n        }\n\n    }\n\n\n}"
  },
  {
    "path": "app/src/main/java/org/apache/commons/compress/utils/IOUtils.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage org.apache.commons.compress.utils;\n\nimport java.io.ByteArrayOutputStream;\nimport java.io.Closeable;\nimport java.io.EOFException;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.nio.ByteBuffer;\nimport java.nio.channels.ReadableByteChannel;\n\n/**\n * Utility functions\n *\n * @Immutable (has mutable data but it is write - only)\n */\n// Copyright 2008 Torsten Curdt\npublic final class IOUtils {\n\n    private static final int COPY_BUF_SIZE = 8024;\n    private static final int SKIP_BUF_SIZE = 4096;\n\n    // This buffer does not need to be synchronized because it is write only; the contents are ignored\n    // Does not affect Immutability\n    private static final byte[] SKIP_BUF = new byte[SKIP_BUF_SIZE];\n\n    /** Private constructor to prevent instantiation of this utility class. */\n    private IOUtils(){\n    }\n\n    /**\n     * Copies the content of a InputStream into an OutputStream.\n     * Uses a default buffer size of 8024 bytes.\n     *\n     * @param input\n     *            the InputStream to copy\n     * @param output\n     *            the target Stream\n     * @return the number of bytes copied\n     * @throws IOException\n     *             if an error occurs\n     */\n    public static long copy(final InputStream input, final OutputStream output) throws IOException {\n        return copy(input, output, COPY_BUF_SIZE);\n    }\n\n    /**\n     * Copies the content of a InputStream into an OutputStream\n     *\n     * @param input\n     *            the InputStream to copy\n     * @param output\n     *            the target Stream\n     * @param buffersize\n     *            the buffer size to use, must be bigger than 0\n     * @return the number of bytes copied\n     * @throws IOException\n     *             if an error occurs\n     * @throws IllegalArgumentException\n     *             if buffersize is smaller than or equal to 0\n     */\n    public static long copy(final InputStream input, final OutputStream output, final int buffersize) throws IOException {\n        if (buffersize < 1) {\n            throw new IllegalArgumentException(\"buffersize must be bigger than 0\");\n        }\n        final byte[] buffer = new byte[buffersize];\n        int n = 0;\n        long count=0;\n        while (-1 != (n = input.read(buffer))) {\n            output.write(buffer, 0, n);\n            count += n;\n        }\n        return count;\n    }\n\n    /**\n     * Skips the given number of bytes by repeatedly invoking skip on\n     * the given input stream if necessary.\n     *\n     * <p>In a case where the stream's skip() method returns 0 before\n     * the requested number of bytes has been skip this implementation\n     * will fall back to using the read() method.</p>\n     *\n     * <p>This method will only skip less than the requested number of\n     * bytes if the end of the input stream has been reached.</p>\n     *\n     * @param input stream to skip bytes in\n     * @param numToSkip the number of bytes to skip\n     * @return the number of bytes actually skipped\n     * @throws IOException on error\n     */\n    public static long skip(final InputStream input, long numToSkip) throws IOException {\n        final long available = numToSkip;\n        while (numToSkip > 0) {\n            final long skipped = input.skip(numToSkip);\n            if (skipped == 0) {\n                break;\n            }\n            numToSkip -= skipped;\n        }\n\n        while (numToSkip > 0) {\n            final int read = readFully(input, SKIP_BUF, 0,\n                                 (int) Math.min(numToSkip, SKIP_BUF_SIZE));\n            if (read < 1) {\n                break;\n            }\n            numToSkip -= read;\n        }\n        return available - numToSkip;\n    }\n\n    /**\n     * Reads as much from input as possible to fill the given array.\n     *\n     * <p>This method may invoke read repeatedly to fill the array and\n     * only read less bytes than the length of the array if the end of\n     * the stream has been reached.</p>\n     *\n     * @param input stream to read from\n     * @param array buffer to fill\n     * @return the number of bytes actually read\n     * @throws IOException on error\n     */\n    public static int readFully(final InputStream input, final byte[] array) throws IOException {\n        return readFully(input, array, 0, array.length);\n    }\n\n    /**\n     * Reads as much from input as possible to fill the given array\n     * with the given amount of bytes.\n     *\n     * <p>This method may invoke read repeatedly to read the bytes and\n     * only read less bytes than the requested length if the end of\n     * the stream has been reached.</p>\n     *\n     * @param input stream to read from\n     * @param array buffer to fill\n     * @param offset offset into the buffer to start filling at\n     * @param len of bytes to read\n     * @return the number of bytes actually read\n     * @throws IOException\n     *             if an I/O error has occurred\n     */\n    public static int readFully(final InputStream input, final byte[] array, final int offset, final int len)\n        throws IOException {\n        if (len < 0 || offset < 0 || len + offset > array.length) {\n            throw new IndexOutOfBoundsException();\n        }\n        int count = 0, x = 0;\n        while (count != len) {\n            x = input.read(array, offset + count, len - count);\n            if (x == -1) {\n                break;\n            }\n            count += x;\n        }\n        return count;\n    }\n\n    /**\n     * Reads {@code b.remaining()} bytes from the given channel\n     * starting at the current channel's position.\n     *\n     * <p>This method reads repeatedly from the channel until the\n     * requested number of bytes are read. This method blocks until\n     * the requested number of bytes are read, the end of the channel\n     * is detected, or an exception is thrown.</p>\n     *\n     * @param channel the channel to read from\n     * @param b the buffer into which the data is read.\n     * @throws IOException - if an I/O error occurs.\n     * @throws EOFException - if the channel reaches the end before reading all the bytes.\n     */\n    public static void readFully(final ReadableByteChannel channel, final ByteBuffer b) throws IOException {\n        final int expectedLength = b.remaining();\n        int read = 0;\n        while (read < expectedLength) {\n            final int readNow = channel.read(b);\n            if (readNow <= 0) {\n                break;\n            }\n            read += readNow;\n        }\n        if (read < expectedLength) {\n            throw new EOFException();\n        }\n    }\n\n    // toByteArray(InputStream) copied from:\n    // commons/proper/io/trunk/src/main/java/org/apache/commons/io/IOUtils.java?revision=1428941\n    // January 8th, 2013\n    //\n    // Assuming our copy() works just as well as theirs!  :-)\n\n    /**\n     * Gets the contents of an <code>InputStream</code> as a <code>byte[]</code>.\n     * <p>\n     * This method buffers the input internally, so there is no need to use a\n     * <code>BufferedInputStream</code>.\n     *\n     * @param input  the <code>InputStream</code> to read from\n     * @return the requested byte array\n     * @throws NullPointerException if the input is null\n     * @throws IOException if an I/O error occurs\n     * @since 1.5\n     */\n    public static byte[] toByteArray(final InputStream input) throws IOException {\n        final ByteArrayOutputStream output = new ByteArrayOutputStream();\n        copy(input, output);\n        return output.toByteArray();\n    }\n\n    /**\n     * Closes the given Closeable and swallows any IOException that may occur.\n     * @param c Closeable to close, can be null\n     * @since 1.7\n     */\n    public static void closeQuietly(final Closeable c) {\n        if (c != null) {\n            try {\n                c.close();\n            } catch (final IOException ignored) { // NOPMD NOSONAR\n            }\n        }\n    }\n}"
  },
  {
    "path": "app/src/main/java/org/apache/commons/compress/utils/InputStreamStatistics.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage org.apache.commons.compress.utils;\n\n/**\n * This interface provides statistics on the current decompression stream.\n * The stream consumer can use that statistics to handle abnormal\n * compression ratios, i.e. to prevent zip bombs.\n *\n * @since 1.17\n */\n// Copyright 2018 Stefan Bodewig\npublic interface InputStreamStatistics {\n    /**\n     * @return the amount of raw or compressed bytes read by the stream\n     */\n    long getCompressedCount();\n\n    /**\n     * @return the amount of decompressed bytes returned by the stream\n     */\n    long getUncompressedCount();\n}"
  },
  {
    "path": "app/src/main/res/animator/enter_from_left.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<set xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <objectAnimator\n        android:duration=\"@android:integer/config_shortAnimTime\"\n        android:propertyName=\"x\"\n        android:valueFrom=\"1000\"\n        android:valueTo=\"0\"\n        android:valueType=\"floatType\" />\n</set>\n"
  },
  {
    "path": "app/src/main/res/animator/enter_from_right.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<set xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <objectAnimator\n        android:duration=\"@android:integer/config_shortAnimTime\"\n        android:propertyName=\"x\"\n        android:valueFrom=\"0\"\n        android:valueTo=\"-1000\"\n        android:valueType=\"floatType\" />\n\n</set>"
  },
  {
    "path": "app/src/main/res/animator/exit_from_left.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<set xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <objectAnimator\n        android:duration=\"@android:integer/config_shortAnimTime\"\n        android:propertyName=\"x\"\n        android:valueFrom=\"0\"\n        android:valueTo=\"1000\"\n        android:valueType=\"floatType\" />\n</set>"
  },
  {
    "path": "app/src/main/res/animator/exit_from_right.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<set xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <objectAnimator\n        android:duration=\"@android:integer/config_shortAnimTime\"\n        android:propertyName=\"x\"\n        android:valueFrom=\"-1000\"\n        android:valueTo=\"0\"\n        android:valueType=\"floatType\" />\n</set>"
  },
  {
    "path": "app/src/main/res/drawable/app_widget_background.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:shape=\"rectangle\">\n\n    <corners android:radius=\"?attr/appWidgetRadius\" />\n    <solid android:color=\"?android:attr/colorBackground\" />\n</shape>\n"
  },
  {
    "path": "app/src/main/res/drawable/badge_background.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <solid android:color=\"?attr/colorSurfaceVariant\" />\n    <corners android:radius=\"15dp\" />\n</shape>\n"
  },
  {
    "path": "app/src/main/res/drawable/circle_background.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:shape=\"oval\">\n    <solid android:color=\"#000\" />\n</shape>\n"
  },
  {
    "path": "app/src/main/res/drawable/circle_with_padding.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:shape=\"oval\">\n    <stroke\n        android:width=\"2dp\"\n        android:color=\"?attr/colorSurfaceVariant\" />\n</shape>\n"
  },
  {
    "path": "app/src/main/res/drawable/dashed_border.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <stroke\n        android:width=\"2dp\"\n        android:color=\"?attr/colorControlNormal\"\n        android:dashWidth=\"10dp\"\n        android:dashGap=\"6dp\" />\n    <padding\n        android:left=\"8dp\"\n        android:top=\"8dp\"\n        android:right=\"8dp\"\n        android:bottom=\"8dp\" />\n    <corners android:radius=\"16dp\" />\n</shape>"
  },
  {
    "path": "app/src/main/res/drawable/ic_add.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"?attr/colorControlNormal\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M19,13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_android.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"?attr/colorControlNormal\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M17.6,9.48l1.84,-3.18c0.16,-0.31 0.04,-0.69 -0.26,-0.85c-0.29,-0.15 -0.65,-0.06 -0.83,0.22l-1.88,3.24c-2.86,-1.21 -6.08,-1.21 -8.94,0L5.65,5.67c-0.19,-0.29 -0.58,-0.38 -0.87,-0.2C4.5,5.65 4.41,6.01 4.56,6.3L6.4,9.48C3.3,11.25 1.28,14.44 1,18h22C22.72,14.44 20.7,11.25 17.6,9.48zM7,15.25c-0.69,0 -1.25,-0.56 -1.25,-1.25c0,-0.69 0.56,-1.25 1.25,-1.25S8.25,13.31 8.25,14C8.25,14.69 7.69,15.25 7,15.25zM17,15.25c-0.69,0 -1.25,-0.56 -1.25,-1.25c0,-0.69 0.56,-1.25 1.25,-1.25s1.25,0.56 1.25,1.25C18.25,14.69 17.69,15.25 17,15.25z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_archive.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"?attr/colorControlNormal\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M20.54,5.23l-1.39,-1.68C18.88,3.21 18.47,3 18,3L6,3c-0.47,0 -0.88,0.21 -1.16,0.55L3.46,5.23C3.17,5.57 3,6.02 3,6.5L3,19c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2L21,6.5c0,-0.48 -0.17,-0.93 -0.46,-1.27zM6.24,5h11.52l0.81,0.97L5.44,5.97l0.8,-0.97zM5,19L5,8h14v11L5,19zM13.45,10h-2.9v3L8,13l4,4 4,-4h-2.55z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_arrow_outward.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 -->\n<vector\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"?attr/colorControlNormal\"\n    >\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M6,6l0,2l8.59,0l-9.59,9.59l1.41,1.41l9.59,-9.59l0,8.59l2,0l0,-12z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_audio_file.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"?attr/colorControlNormal\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M14,2H6C4.9,2 4,2.9 4,4v16c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2V8L14,2zM6,20V4h7v5h5v11H6zM16,11h-4v3.88c-0.36,-0.24 -0.79,-0.38 -1.25,-0.38c-1.24,0 -2.25,1.01 -2.25,2.25c0,1.24 1.01,2.25 2.25,2.25S13,17.99 13,16.75V13h3V11z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_autorenew.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"?attr/colorControlNormal\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M12,6v3l4,-4 -4,-4v3c-4.42,0 -8,3.58 -8,8 0,1.57 0.46,3.03 1.24,4.26L6.7,14.8c-0.45,-0.83 -0.7,-1.79 -0.7,-2.8 0,-3.31 2.69,-6 6,-6zM18.76,7.74L17.3,9.2c0.44,0.84 0.7,1.79 0.7,2.8 0,3.31 -2.69,6 -6,6v-3l-4,4 4,4v-3c4.42,0 8,-3.58 8,-8 0,-1.57 -0.46,-3.03 -1.24,-4.26z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_backup_restore.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"?attr/colorControlNormal\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M12,3A9,9 0,0 0,3 12H0L4,16L8,12H5A7,7 0,0 1,12 5A7,7 0,0 1,19 12A7,7 0,0 1,12 19C10.5,19 9.09,18.5 7.94,17.7L6.5,19.14C8.04,20.3 9.94,21 12,21A9,9 0,0 0,21 12A9,9 0,0 0,12 3M14,12A2,2 0,0 0,12 10A2,2 0,0 0,10 12A2,2 0,0 0,12 14A2,2 0,0 0,14 12Z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_battery_plus.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"?attr/colorControlNormal\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M13.54,22H7.33C6.6,22 6,21.4 6,20.67V5.33C6,4.6 6.6,4 7.33,4H9V2H15V4H16.67C17.4,4 18,4.6 18,5.33V12C17.3,12 16.63,12.13 16,12.35V6H8V20H12.35C12.61,20.75 13,21.42 13.54,22M22,17V19H19V22H17V19H14V17H17V14H19V17H22Z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_block.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24.0\"\n    android:viewportHeight=\"24.0\"\n    android:tint=\"?attr/colorControlNormal\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM4,12c0,-4.42 3.58,-8 8,-8 1.85,0 3.55,0.63 4.9,1.69L5.69,16.9C4.63,15.55 4,13.85 4,12zM12,20c-1.85,0 -3.55,-0.63 -4.9,-1.69L18.31,7.1C19.37,8.45 20,10.15 20,12c0,4.42 -3.58,8 -8,8z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_book.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"?attr/colorControlNormal\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M18,2L6,2c-1.1,0 -2,0.9 -2,2v16c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2L20,4c0,-1.1 -0.9,-2 -2,-2zM9,4h2v5l-1,-0.75L9,9L9,4zM18,20L6,20L6,4h1v9l3,-2.25L13,13L13,4h5v16z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_brush.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later OR CC-BY-SA-4.0 -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"1024\"\n    android:viewportHeight=\"1024\"\n    android:tint=\"?attr/colorControlNormal\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"m714.8,1022.78c-3.04,0 -6.16,-0.17 -9.36,-0.46C627.73,1014.92 550.69,997.01 476.47,969.09 336.93,916.55 221.59,835.64 133.65,728.62c-16.33,-19.85 -19.78,-42.96 -9.7,-65.01 9.73,-21.31 29.6,-33.71 54.51,-34.06 63.2,-0.84 127.27,-13.37 190.45,-37.26 62.76,-23.73 107.78,-53.41 141.7,-93.46 7.27,-8.57 13.8,-18.23 20.76,-28.45 3.4,-5 6.85,-10.08 10.44,-15.12l10.98,-15.48 102.46,57.73 -13.16,19.02c-3.8,5.5 -7.45,10.98 -11.08,16.42 -8.01,12 -16.29,24.4 -25.54,36.11 -30.45,38.5 -69.9,70.93 -120.6,99.13 -53.64,29.83 -113.44,51.38 -181.89,65.49 17.88,14.41 34.55,27.26 50.8,39.16 37.43,-8.49 67.57,-23.42 91.41,-45.5l46.98,-43.5 -11.93,62.9c-3.51,18.54 -27.44,50.27 -47.02,73.74 13.07,6.26 26.41,12.81 39.25,20.35 16.7,9.81 32.3,9.5 56.79,-1.1 42.8,-18.5 79.28,-47.22 109.29,-72.88 3.63,-3.11 7.21,-6.27 11.08,-9.7l57.6,-50.67 -16.57,65.77c-5.52,21.96 -27.48,61.71 -65.35,118.36 1.84,0.38 3.68,0.75 5.52,1.08 10.78,1.97 21.6,3.71 32.43,5.45 9.68,1.56 19.37,3.13 29.01,4.85 40.5,-60.7 75.01,-126.82 106.04,-202.82 7.9,-19.33 15.2,-39.53 22.27,-59.04 3.3,-9.15 6.62,-18.3 10.01,-27.42l10.5,-28.83 110.67,38.18 -10.84,31.81c-2.88,8.53 -5.68,16.84 -8.63,25.08 -40.45,112.4 -87.71,207.87 -144.53,291.87 -2.59,3.82 -5.33,7.55 -8.07,11.26 -2.57,3.44 -5.12,6.89 -7.51,10.46 -13.33,20.06 -32.64,30.25 -57.38,30.26zM565.42,495.28c-6.99,10.29 -14.24,20.89 -22.6,30.77 -38.19,45.11 -90.2,79.67 -158.98,105.68 -67.78,25.62 -136.68,39.08 -204.79,39.99 -11.03,0.15 -14.65,4.85 -16.74,9.4 -2.43,5.33 -3.64,11.53 3.92,20.72 84.37,102.68 190.7,177.18 325.1,227.8 70.72,26.61 144.09,43.66 218.1,50.7 1.83,0.18 3.63,0.28 5.37,0.28 10.56,-0.01 16.78,-3.22 22.27,-11.47 2.78,-4.17 5.76,-8.19 8.74,-12.22 2.39,-3.22 4.78,-6.45 7.03,-9.77 54.81,-81.06 100.52,-173.47 139.76,-282.51 1.94,-5.43 3.81,-10.88 5.71,-16.45l-31.84,-10.96c-2.09,5.74 -4.17,11.47 -6.24,17.22 -7.21,19.92 -14.66,40.51 -22.88,60.64 -32.77,80.22 -69.38,149.97 -111.92,213.19 -2.78,4.15 -11.25,16.7 -28.82,16.7 -2.21,0 -4.61,-0.21 -7.24,-0.69 -10.89,-2.01 -21.89,-3.78 -32.86,-5.55 -11.09,-1.79 -22.2,-3.58 -33.24,-5.59 -8.67,-1.57 -17.26,-3.65 -25.99,-5.79 -3.77,-0.91 -7.55,-1.86 -11.41,-2.74l-30.19,-6.99 17.61,-25.51c11.81,-17.13 21.82,-32.12 30.26,-45.25 -17.7,11.72 -36.86,22.62 -57.58,31.57 -18.23,7.89 -33.79,11.54 -48.99,11.54v0c-16.01,0 -31.44,-4.32 -45.91,-12.81 -13.06,-7.67 -26.85,-14.27 -41.45,-21.24 -6.58,-3.15 -13.18,-6.3 -19.78,-9.59l-24.78,-12.34 18.47,-20.61c2.05,-2.29 4.03,-4.53 5.95,-6.72 -8.76,2.85 -17.89,5.36 -27.44,7.51 -10.39,2.36 -23.47,-0.24 -31.92,-6.41 -18.19,-13.28 -36.84,-27.69 -57,-44.01 -7.34,-5.95 -13.93,-12.16 -20.9,-18.77 -3.02,-2.85 -6.14,-5.79 -9.42,-8.8l-30.99,-28.45 44.29,-8.38c1.91,-0.37 3.11,-0.59 4.3,-0.77 78.65,-12.74 145.44,-34.78 203.95,-67.29 45.75,-25.46 81.09,-54.37 108.02,-88.44 7.7,-9.73 14.75,-20.17 22.11,-31.21zM959.86,600.31 L560.39,422.61l8.25,-19.13c11.6,-26.93 30.18,-48.09 55.24,-62.87 40.86,-24.12 85.17,-26.83 128.55,-7.97 46.08,20.06 95.42,41.72 143.99,64.21 65.11,30.14 96.57,98.77 76.5,166.92 -1.03,3.51 -2.31,6.99 -3.72,10.74zM617.61,401.9 L934.68,542.96c9.26,-45.15 -12.44,-87.71 -55.97,-107.86 -48.2,-22.31 -97.27,-43.86 -143.12,-63.82 -30.99,-13.48 -61.02,-11.62 -90.28,5.62 -11.26,6.65 -20.42,14.91 -27.69,24.99zM230.09,569.29 L226.8,569.23C162.97,567.32 112.11,514.38 113.44,451.23 114.7,389.74 167.43,337.8 228.57,337.8l2.08,0.01c30.52,0.58 60.34,13.78 81.84,36.22 21.44,22.39 32.85,51.29 32.12,81.42 -1.55,62.78 -52.92,113.83 -114.52,113.83zM229.82,379.99c-40.02,0 -73.43,33.03 -74.25,72.12 -0.83,40.12 31.68,73.75 72.48,74.98l2.04,0.03c38.25,0 71.39,-33.29 72.35,-72.69 0.46,-18.81 -6.79,-37 -20.41,-51.22 -13.78,-14.39 -32.81,-22.86 -52.18,-23.22zM903.97,389.72 L773.18,331.44c-4.36,-1.94 -6.94,-4.68 -8.18,-6l-10.06,-10.63 6.52,-16.25c1.11,-2.31 2.23,-4.6 3.42,-6.85L905.28,28.46C915.47,9.32 929.99,0 949.67,0c3.4,0 7.08,0.28 11.06,0.87 21.32,3.11 38.77,12.65 51.84,28.39 11.6,13.92 14.44,30.35 8.21,47.5C995.37,146.68 970.08,216.65 944.78,286.61l-28.41,78.53c-0.59,1.64 -1.35,3.25 -2.53,5.38zM807.85,300.72 L882.75,334.11 905.14,272.27c25.3,-69.99 50.62,-139.97 76.02,-209.92 1.15,-3.15 0.87,-3.91 -0.97,-6.13 -6.41,-7.7 -14.51,-12.03 -25.51,-13.63 -1.81,-0.27 -3.46,-0.42 -4.98,-0.42 -3.02,0 -3.92,0 -7.18,6.13zM77.61,304.45C35.53,304.45 0,268.8 0,226.6c0,-42.76 34.9,-77.56 77.8,-77.56 21.08,0.06 40.62,8.27 55.27,23.11 14.62,14.8 22.56,34.38 22.36,55.12 -0.38,42.23 -35.06,76.86 -77.28,77.18zM77.94,191.21c-19.78,0 -35.76,15.87 -35.76,35.39 0,19.34 16.22,35.68 35.44,35.68v21.08l0.24,-21.08c19.36,-0.14 35.25,-16.02 35.44,-35.41 0.08,-9.43 -3.53,-18.34 -10.2,-25.1 -6.72,-6.78 -15.64,-10.53 -25.15,-10.56zM247.91,304.43c-32.29,0 -58.59,-26.41 -58.6,-58.88 0,-32.39 26.31,-58.73 58.66,-58.73 16.25,0.11 31.11,6.45 42.25,17.88 11.03,11.3 16.97,26.09 16.7,41.65 -0.55,31.74 -26.78,57.79 -58.47,58.08zM248.1,228.99c-9.38,0 -16.61,7.27 -16.61,16.54 0,9.07 7.53,16.73 16.43,16.73v21.08l0.14,-21.08c8.76,-0.08 16.56,-7.84 16.7,-16.63 0.07,-4.22 -1.6,-8.29 -4.71,-11.48 -3.22,-3.29 -7.46,-5.13 -11.95,-5.16z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_calendar_month.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"?attr/colorControlNormal\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M19,4h-1V2h-2v2H8V2H6v2H5C3.89,4 3.01,4.9 3.01,6L3,20c0,1.1 0.89,2 2,2h14c1.1,0 2,-0.9 2,-2V6C21,4.9 20.1,4 19,4zM19,20H5V10h14V20zM19,8H5V6h14V8zM9,14H7v-2h2V14zM13,14h-2v-2h2V14zM17,14h-2v-2h2V14zM9,18H7v-2h2V18zM13,18h-2v-2h2V18zM17,18h-2v-2h2V18z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_cctv_off.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"?attr/colorControlNormal\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M20.84,22.73L18.11,20H17C15.9,20 15,19.1 15,18V16.89L12.66,14.55L11.81,15.04C10.86,15.59 9.63,15.26 9.08,14.31L7.58,11.71C7.18,11 7.25,10.18 7.68,9.57L1.11,3L2.39,1.73L22.11,21.46L20.84,22.73M18.5,13C18.5,12.43 18.3,11.9 17.97,11.5L19.94,10.35C20.95,9.76 21.3,8.47 20.71,7.46L19.33,5.06C18.74,4.05 17.45,3.7 16.44,4.28L10.77,7.57L17.86,14.66C18.26,14.22 18.5,13.64 18.5,13M2,12.62L5.5,18.68L8.03,15.5L6.03,12.03L2,12.62Z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_charity.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"?attr/colorControlNormal\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M12.75,3.94C13.75,3.22 14.91,2.86 16.22,2.86C16.94,2.86 17.73,3.05 18.59,3.45C19.45,3.84 20.13,4.3 20.63,4.83C21.66,6.11 22.09,7.6 21.94,9.3C21.78,11 21.22,12.33 20.25,13.27L12.66,20.86C12.47,21.05 12.23,21.14 11.95,21.14C11.67,21.14 11.44,21.05 11.25,20.86C11.06,20.67 10.97,20.44 10.97,20.16C10.97,19.88 11.06,19.64 11.25,19.45L15.84,14.86C16.09,14.64 16.09,14.41 15.84,14.16C15.59,13.91 15.36,13.91 15.14,14.16L10.55,18.75C10.36,18.94 10.13,19.03 9.84,19.03C9.56,19.03 9.33,18.94 9.14,18.75C8.95,18.56 8.86,18.33 8.86,18.05C8.86,17.77 8.95,17.53 9.14,17.34L13.73,12.75C14,12.5 14,12.25 13.73,12C13.5,11.75 13.28,11.75 13.03,12L8.44,16.64C8.25,16.83 8,16.92 7.73,16.92C7.45,16.92 7.21,16.83 7,16.64C6.8,16.45 6.7,16.22 6.7,15.94C6.7,15.66 6.81,15.41 7.03,15.19L11.63,10.59C11.88,10.34 11.88,10.11 11.63,9.89C11.38,9.67 11.14,9.67 10.92,9.89L6.28,14.5C6.06,14.7 5.83,14.81 5.58,14.81C5.3,14.81 5.06,14.71 4.88,14.5C4.69,14.3 4.59,14.06 4.59,13.78C4.59,13.5 4.69,13.27 4.88,13.08C7.94,10 9.83,8.14 10.55,7.45L14.11,10.97C14.5,11.34 14.95,11.53 15.5,11.53C16.2,11.53 16.75,11.25 17.16,10.69C17.44,10.28 17.54,9.83 17.46,9.33C17.38,8.83 17.17,8.41 16.83,8.06L12.75,3.94M14.81,10.27L10.55,6L3.47,13.08C2.63,12.23 2.15,10.93 2.04,9.16C1.93,7.4 2.41,5.87 3.47,4.59C4.66,3.41 6.08,2.81 7.73,2.81C9.39,2.81 10.8,3.41 11.95,4.59L16.22,8.86C16.41,9.05 16.5,9.28 16.5,9.56C16.5,9.84 16.41,10.08 16.22,10.27C16.03,10.45 15.8,10.55 15.5,10.55C15.23,10.55 15,10.45 14.81,10.27V10.27Z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_check_circle.xml",
    "content": "<!--SPDX-License-Identifier: Apache-2.0 -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"?attr/colorControlNormal\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M16.59,7.58L10,14.17l-3.59,-3.58L5,12l5,5 8,-8zM12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.42,0 -8,-3.58 -8,-8s3.58,-8 8,-8 8,3.58 8,8 -3.58,8 -8,8z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_clear_cache.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later OR CC-BY-SA-4.0 -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"1024\"\n    android:viewportHeight=\"1024\"\n    android:tint=\"?attr/colorControlNormal\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"m714.8,1022.78c-3.04,0 -6.16,-0.17 -9.36,-0.46C627.73,1014.92 550.69,997.01 476.47,969.09 336.93,916.55 221.59,835.64 133.65,728.62c-16.33,-19.85 -19.78,-42.96 -9.7,-65.01 9.73,-21.31 29.6,-33.71 54.51,-34.06 63.2,-0.84 127.27,-13.37 190.45,-37.26 62.76,-23.73 107.78,-53.41 141.7,-93.46 7.27,-8.57 13.8,-18.23 20.76,-28.45 3.4,-5 6.85,-10.08 10.44,-15.12l10.98,-15.48 102.46,57.73 -13.16,19.02c-3.8,5.5 -7.45,10.98 -11.08,16.42 -8.01,12 -16.29,24.4 -25.54,36.11 -30.45,38.5 -69.9,70.93 -120.6,99.13 -53.64,29.83 -113.44,51.38 -181.89,65.49 17.88,14.41 34.55,27.26 50.8,39.16 37.43,-8.49 67.57,-23.42 91.41,-45.5l46.98,-43.5 -11.93,62.9c-3.51,18.54 -27.44,50.27 -47.02,73.74 13.07,6.26 26.41,12.81 39.25,20.35 16.7,9.81 32.3,9.5 56.79,-1.1 42.8,-18.5 79.28,-47.22 109.29,-72.88 3.63,-3.11 7.21,-6.27 11.08,-9.7l57.6,-50.67 -16.57,65.77c-5.52,21.96 -27.48,61.71 -65.35,118.36 1.84,0.38 3.68,0.75 5.52,1.08 10.78,1.97 21.6,3.71 32.43,5.45 9.68,1.56 19.37,3.13 29.01,4.85 40.5,-60.7 75.01,-126.82 106.04,-202.82 7.9,-19.33 15.2,-39.53 22.27,-59.04 3.3,-9.15 6.62,-18.3 10.01,-27.42l10.5,-28.83 110.67,38.18 -10.84,31.81c-2.88,8.53 -5.68,16.84 -8.63,25.08 -40.45,112.4 -87.71,207.87 -144.53,291.87 -2.59,3.82 -5.33,7.55 -8.07,11.26 -2.57,3.44 -5.12,6.89 -7.51,10.46 -13.33,20.06 -32.64,30.25 -57.38,30.26zM565.42,495.28c-6.99,10.29 -14.24,20.89 -22.6,30.77 -38.19,45.11 -90.2,79.67 -158.98,105.68 -67.78,25.62 -136.68,39.08 -204.79,39.99 -11.03,0.15 -14.65,4.85 -16.74,9.4 -2.43,5.33 -3.64,11.53 3.92,20.72 84.37,102.68 190.7,177.18 325.1,227.8 70.72,26.61 144.09,43.66 218.1,50.7 1.83,0.18 3.63,0.28 5.37,0.28 10.56,-0.01 16.78,-3.22 22.27,-11.47 2.78,-4.17 5.76,-8.19 8.74,-12.22 2.39,-3.22 4.78,-6.45 7.03,-9.77 54.81,-81.06 100.52,-173.47 139.76,-282.51 1.94,-5.43 3.81,-10.88 5.71,-16.45l-31.84,-10.96c-2.09,5.74 -4.17,11.47 -6.24,17.22 -7.21,19.92 -14.66,40.51 -22.88,60.64 -32.77,80.22 -69.38,149.97 -111.92,213.19 -2.78,4.15 -11.25,16.7 -28.82,16.7 -2.21,0 -4.61,-0.21 -7.24,-0.69 -10.89,-2.01 -21.89,-3.78 -32.86,-5.55 -11.09,-1.79 -22.2,-3.58 -33.24,-5.59 -8.67,-1.57 -17.26,-3.65 -25.99,-5.79 -3.77,-0.91 -7.55,-1.86 -11.41,-2.74l-30.19,-6.99 17.61,-25.51c11.81,-17.13 21.82,-32.12 30.26,-45.25 -17.7,11.72 -36.86,22.62 -57.58,31.57 -18.23,7.89 -33.79,11.54 -48.99,11.54v0c-16.01,0 -31.44,-4.32 -45.91,-12.81 -13.06,-7.67 -26.85,-14.27 -41.45,-21.24 -6.58,-3.15 -13.18,-6.3 -19.78,-9.59l-24.78,-12.34 18.47,-20.61c2.05,-2.29 4.03,-4.53 5.95,-6.72 -8.76,2.85 -17.89,5.36 -27.44,7.51 -10.39,2.36 -23.47,-0.24 -31.92,-6.41 -18.19,-13.28 -36.84,-27.69 -57,-44.01 -7.34,-5.95 -13.93,-12.16 -20.9,-18.77 -3.02,-2.85 -6.14,-5.79 -9.42,-8.8l-30.99,-28.45 44.29,-8.38c1.91,-0.37 3.11,-0.59 4.3,-0.77 78.65,-12.74 145.44,-34.78 203.95,-67.29 45.75,-25.46 81.09,-54.37 108.02,-88.44 7.7,-9.73 14.75,-20.17 22.11,-31.21zM959.86,600.31 L560.39,422.61l8.25,-19.13c11.6,-26.93 30.18,-48.09 55.24,-62.87 40.86,-24.12 85.17,-26.83 128.55,-7.97 46.08,20.06 95.42,41.72 143.99,64.21 65.11,30.14 96.57,98.77 76.5,166.92 -1.03,3.51 -2.31,6.99 -3.72,10.74zM617.61,401.9 L934.68,542.96c9.26,-45.15 -12.44,-87.71 -55.97,-107.86 -48.2,-22.31 -97.27,-43.86 -143.12,-63.82 -30.99,-13.48 -61.02,-11.62 -90.28,5.62 -11.26,6.65 -20.42,14.91 -27.69,24.99zM230.09,569.29 L226.8,569.23C162.97,567.32 112.11,514.38 113.44,451.23 114.7,389.74 167.43,337.8 228.57,337.8l2.08,0.01c30.52,0.58 60.34,13.78 81.84,36.22 21.44,22.39 32.85,51.29 32.12,81.42 -1.55,62.78 -52.92,113.83 -114.52,113.83zM229.82,379.99c-40.02,0 -73.43,33.03 -74.25,72.12 -0.83,40.12 31.68,73.75 72.48,74.98l2.04,0.03c38.25,0 71.39,-33.29 72.35,-72.69 0.46,-18.81 -6.79,-37 -20.41,-51.22 -13.78,-14.39 -32.81,-22.86 -52.18,-23.22zM903.97,389.72 L773.18,331.44c-4.36,-1.94 -6.94,-4.68 -8.18,-6l-10.06,-10.63 6.52,-16.25c1.11,-2.31 2.23,-4.6 3.42,-6.85L905.28,28.46C915.47,9.32 929.99,0 949.67,0c3.4,0 7.08,0.28 11.06,0.87 21.32,3.11 38.77,12.65 51.84,28.39 11.6,13.92 14.44,30.35 8.21,47.5C995.37,146.68 970.08,216.65 944.78,286.61l-28.41,78.53c-0.59,1.64 -1.35,3.25 -2.53,5.38zM807.85,300.72 L882.75,334.11 905.14,272.27c25.3,-69.99 50.62,-139.97 76.02,-209.92 1.15,-3.15 0.87,-3.91 -0.97,-6.13 -6.41,-7.7 -14.51,-12.03 -25.51,-13.63 -1.81,-0.27 -3.46,-0.42 -4.98,-0.42 -3.02,0 -3.92,0 -7.18,6.13zM77.61,304.45C35.53,304.45 0,268.8 0,226.6c0,-42.76 34.9,-77.56 77.8,-77.56 21.08,0.06 40.62,8.27 55.27,23.11 14.62,14.8 22.56,34.38 22.36,55.12 -0.38,42.23 -35.06,76.86 -77.28,77.18zM77.94,191.21c-19.78,0 -35.76,15.87 -35.76,35.39 0,19.34 16.22,35.68 35.44,35.68v21.08l0.24,-21.08c19.36,-0.14 35.25,-16.02 35.44,-35.41 0.08,-9.43 -3.53,-18.34 -10.2,-25.1 -6.72,-6.78 -15.64,-10.53 -25.15,-10.56zM247.91,304.43c-32.29,0 -58.59,-26.41 -58.6,-58.88 0,-32.39 26.31,-58.73 58.66,-58.73 16.25,0.11 31.11,6.45 42.25,17.88 11.03,11.3 16.97,26.09 16.7,41.65 -0.55,31.74 -26.78,57.79 -58.47,58.08zM248.1,228.99c-9.38,0 -16.61,7.27 -16.61,16.54 0,9.07 7.53,16.73 16.43,16.73v21.08l0.14,-21.08c8.76,-0.08 16.56,-7.84 16.7,-16.63 0.07,-4.22 -1.6,-8.29 -4.71,-11.48 -3.22,-3.29 -7.46,-5.13 -11.95,-5.16z\" />\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"m682.81,242.27q-12.95,47.7 -46.53,70.82 -33.58,23.13 -90.2,23.13 -82.96,0 -131.24,-42.95 -48.06,-43.15 -48.06,-116.87 0,-73.92 48.06,-116.87 48.28,-43.15 131.24,-43.15 29.19,0 60.79,6.61 31.6,6.61 66.93,20.03L673.81,118.8L645.94,118.8Q637.38,79.98 614.78,60.78 592.17,41.37 555.09,41.37q-47.84,0 -71.1,33.24 -23.26,33.04 -23.26,101.8 0,68.76 23.26,101.8 23.26,33.04 71.54,33.04 32.7,0 53.33,-17.14 20.85,-17.14 30.29,-51.83z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_clear_data.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later OR CC-BY-SA-4.0 -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"1024\"\n    android:viewportHeight=\"1024\"\n    android:tint=\"?attr/colorControlNormal\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"m714.8,1022.78c-3.04,0 -6.16,-0.17 -9.36,-0.46C627.73,1014.92 550.69,997.01 476.47,969.09 336.93,916.55 221.59,835.64 133.65,728.62c-16.33,-19.85 -19.78,-42.96 -9.7,-65.01 9.73,-21.31 29.6,-33.71 54.51,-34.06 63.2,-0.84 127.27,-13.37 190.45,-37.26 62.76,-23.73 107.78,-53.41 141.7,-93.46 7.27,-8.57 13.8,-18.23 20.76,-28.45 3.4,-5 6.85,-10.08 10.44,-15.12l10.98,-15.48 102.46,57.73 -13.16,19.02c-3.8,5.5 -7.45,10.98 -11.08,16.42 -8.01,12 -16.29,24.4 -25.54,36.11 -30.45,38.5 -69.9,70.93 -120.6,99.13 -53.64,29.83 -113.44,51.38 -181.89,65.49 17.88,14.41 34.55,27.26 50.8,39.16 37.43,-8.49 67.57,-23.42 91.41,-45.5l46.98,-43.5 -11.93,62.9c-3.51,18.54 -27.44,50.27 -47.02,73.74 13.07,6.26 26.41,12.81 39.25,20.35 16.7,9.81 32.3,9.5 56.79,-1.1 42.8,-18.5 79.28,-47.22 109.29,-72.88 3.63,-3.11 7.21,-6.27 11.08,-9.7l57.6,-50.67 -16.57,65.77c-5.52,21.96 -27.48,61.71 -65.35,118.36 1.84,0.38 3.68,0.75 5.52,1.08 10.78,1.97 21.6,3.71 32.43,5.45 9.68,1.56 19.37,3.13 29.01,4.85 40.5,-60.7 75.01,-126.82 106.04,-202.82 7.9,-19.33 15.2,-39.53 22.27,-59.04 3.3,-9.15 6.62,-18.3 10.01,-27.42l10.5,-28.83 110.67,38.18 -10.84,31.81c-2.88,8.53 -5.68,16.84 -8.63,25.08 -40.45,112.4 -87.71,207.87 -144.53,291.87 -2.59,3.82 -5.33,7.55 -8.07,11.26 -2.57,3.44 -5.12,6.89 -7.51,10.46 -13.33,20.06 -32.64,30.25 -57.38,30.26zM565.42,495.28c-6.99,10.29 -14.24,20.89 -22.6,30.77 -38.19,45.11 -90.2,79.67 -158.98,105.68 -67.78,25.62 -136.68,39.08 -204.79,39.99 -11.03,0.15 -14.65,4.85 -16.74,9.4 -2.43,5.33 -3.64,11.53 3.92,20.72 84.37,102.68 190.7,177.18 325.1,227.8 70.72,26.61 144.09,43.66 218.1,50.7 1.83,0.18 3.63,0.28 5.37,0.28 10.56,-0.01 16.78,-3.22 22.27,-11.47 2.78,-4.17 5.76,-8.19 8.74,-12.22 2.39,-3.22 4.78,-6.45 7.03,-9.77 54.81,-81.06 100.52,-173.47 139.76,-282.51 1.94,-5.43 3.81,-10.88 5.71,-16.45l-31.84,-10.96c-2.09,5.74 -4.17,11.47 -6.24,17.22 -7.21,19.92 -14.66,40.51 -22.88,60.64 -32.77,80.22 -69.38,149.97 -111.92,213.19 -2.78,4.15 -11.25,16.7 -28.82,16.7 -2.21,0 -4.61,-0.21 -7.24,-0.69 -10.89,-2.01 -21.89,-3.78 -32.86,-5.55 -11.09,-1.79 -22.2,-3.58 -33.24,-5.59 -8.67,-1.57 -17.26,-3.65 -25.99,-5.79 -3.77,-0.91 -7.55,-1.86 -11.41,-2.74l-30.19,-6.99 17.61,-25.51c11.81,-17.13 21.82,-32.12 30.26,-45.25 -17.7,11.72 -36.86,22.62 -57.58,31.57 -18.23,7.89 -33.79,11.54 -48.99,11.54v0c-16.01,0 -31.44,-4.32 -45.91,-12.81 -13.06,-7.67 -26.85,-14.27 -41.45,-21.24 -6.58,-3.15 -13.18,-6.3 -19.78,-9.59l-24.78,-12.34 18.47,-20.61c2.05,-2.29 4.03,-4.53 5.95,-6.72 -8.76,2.85 -17.89,5.36 -27.44,7.51 -10.39,2.36 -23.47,-0.24 -31.92,-6.41 -18.19,-13.28 -36.84,-27.69 -57,-44.01 -7.34,-5.95 -13.93,-12.16 -20.9,-18.77 -3.02,-2.85 -6.14,-5.79 -9.42,-8.8l-30.99,-28.45 44.29,-8.38c1.91,-0.37 3.11,-0.59 4.3,-0.77 78.65,-12.74 145.44,-34.78 203.95,-67.29 45.75,-25.46 81.09,-54.37 108.02,-88.44 7.7,-9.73 14.75,-20.17 22.11,-31.21zM959.86,600.31 L560.39,422.61l8.25,-19.13c11.6,-26.93 30.18,-48.09 55.24,-62.87 40.86,-24.12 85.17,-26.83 128.55,-7.97 46.08,20.06 95.42,41.72 143.99,64.21 65.11,30.14 96.57,98.77 76.5,166.92 -1.03,3.51 -2.31,6.99 -3.72,10.74zM617.61,401.9 L934.68,542.96c9.26,-45.15 -12.44,-87.71 -55.97,-107.86 -48.2,-22.31 -97.27,-43.86 -143.12,-63.82 -30.99,-13.48 -61.02,-11.62 -90.28,5.62 -11.26,6.65 -20.42,14.91 -27.69,24.99zM230.09,569.29 L226.8,569.23C162.97,567.32 112.11,514.38 113.44,451.23 114.7,389.74 167.43,337.8 228.57,337.8l2.08,0.01c30.52,0.58 60.34,13.78 81.84,36.22 21.44,22.39 32.85,51.29 32.12,81.42 -1.55,62.78 -52.92,113.83 -114.52,113.83zM229.82,379.99c-40.02,0 -73.43,33.03 -74.25,72.12 -0.83,40.12 31.68,73.75 72.48,74.98l2.04,0.03c38.25,0 71.39,-33.29 72.35,-72.69 0.46,-18.81 -6.79,-37 -20.41,-51.22 -13.78,-14.39 -32.81,-22.86 -52.18,-23.22zM903.97,389.72 L773.18,331.44c-4.36,-1.94 -6.94,-4.68 -8.18,-6l-10.06,-10.63 6.52,-16.25c1.11,-2.31 2.23,-4.6 3.42,-6.85L905.28,28.46C915.47,9.32 929.99,0 949.67,0c3.4,0 7.08,0.28 11.06,0.87 21.32,3.11 38.77,12.65 51.84,28.39 11.6,13.92 14.44,30.35 8.21,47.5C995.37,146.68 970.08,216.65 944.78,286.61l-28.41,78.53c-0.59,1.64 -1.35,3.25 -2.53,5.38zM807.85,300.72 L882.75,334.11 905.14,272.27c25.3,-69.99 50.62,-139.97 76.02,-209.92 1.15,-3.15 0.87,-3.91 -0.97,-6.13 -6.41,-7.7 -14.51,-12.03 -25.51,-13.63 -1.81,-0.27 -3.46,-0.42 -4.98,-0.42 -3.02,0 -3.92,0 -7.18,6.13zM77.61,304.45C35.53,304.45 0,268.8 0,226.6c0,-42.76 34.9,-77.56 77.8,-77.56 21.08,0.06 40.62,8.27 55.27,23.11 14.62,14.8 22.56,34.38 22.36,55.12 -0.38,42.23 -35.06,76.86 -77.28,77.18zM77.94,191.21c-19.78,0 -35.76,15.87 -35.76,35.39 0,19.34 16.22,35.68 35.44,35.68v21.08l0.24,-21.08c19.36,-0.14 35.25,-16.02 35.44,-35.41 0.08,-9.43 -3.53,-18.34 -10.2,-25.1 -6.72,-6.78 -15.64,-10.53 -25.15,-10.56zM247.91,304.43c-32.29,0 -58.59,-26.41 -58.6,-58.88 0,-32.39 26.31,-58.73 58.66,-58.73 16.25,0.11 31.11,6.45 42.25,17.88 11.03,11.3 16.97,26.09 16.7,41.65 -0.55,31.74 -26.78,57.79 -58.47,58.08zM248.1,228.99c-9.38,0 -16.61,7.27 -16.61,16.54 0,9.07 7.53,16.73 16.43,16.73v21.08l0.14,-21.08c8.76,-0.08 16.56,-7.84 16.7,-16.63 0.07,-4.22 -1.6,-8.29 -4.71,-11.48 -3.22,-3.29 -7.46,-5.13 -11.95,-5.16z\" />\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"m495.39,305.25l30.5,0q51.35,0 75.05,-30.97 23.92,-30.97 23.92,-98.49 0,-67.11 -23.7,-97.87 -23.7,-30.97 -75.27,-30.97l-30.5,0zM368.99,330.24l0,-24.98l41.92,0L410.9,46.94L368.99,46.94L368.99,21.96l168.1,0q88.22,0 134.97,39.64 46.74,39.64 46.74,114.18 0,74.95 -46.96,114.8 -46.74,39.64 -134.75,39.64z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_code.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"?attr/colorControlNormal\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M9.4,16.6L4.8,12l4.6,-4.6L8,6l-6,6 6,6 1.4,-1.4zM14.6,16.6l4.6,-4.6 -4.6,-4.6L16,6l6,6 -6,6 -1.4,-1.4z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_contact_page.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"?attr/colorControlNormal\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M13.17,4L18,8.83V20H6V4H13.17M14,2H6C4.9,2 4,2.9 4,4v16c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2V8L14,2L14,2zM12,14c1.1,0 2,-0.9 2,-2c0,-1.1 -0.9,-2 -2,-2s-2,0.9 -2,2C10,13.1 10.9,14 12,14zM16,17.43c0,-0.81 -0.48,-1.53 -1.22,-1.85C13.93,15.21 12.99,15 12,15c-0.99,0 -1.93,0.21 -2.78,0.58C8.48,15.9 8,16.62 8,17.43V18h8V17.43z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_content_copy.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"?attr/colorControlNormal\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M16,1L4,1c-1.1,0 -2,0.9 -2,2v14h2L4,3h12L16,1zM19,5L8,5c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h11c1.1,0 2,-0.9 2,-2L21,7c0,-1.1 -0.9,-2 -2,-2zM19,21L8,21L8,7h11v14z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_content_cut.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportHeight=\"24\"\n    android:viewportWidth=\"24\"\n    android:tint=\"?attr/colorControlNormal\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M9.64,7.64c0.23,-0.5 0.36,-1.05 0.36,-1.64 0,-2.21 -1.79,-4 -4,-4S2,3.79 2,6s1.79,4 4,4c0.59,0 1.14,-0.13 1.64,-0.36L10,12l-2.36,2.36C7.14,14.13 6.59,14 6,14c-2.21,0 -4,1.79 -4,4s1.79,4 4,4 4,-1.79 4,-4c0,-0.59 -0.13,-1.14 -0.36,-1.64L12,14l7,7h3v-1L9.64,7.64zM6,8c-1.1,0 -2,-0.89 -2,-2s0.9,-2 2,-2 2,0.89 2,2 -0.9,2 -2,2zM6,20c-1.1,0 -2,-0.89 -2,-2s0.9,-2 2,-2 2,0.89 2,2 -0.9,2 -2,2zM12,12.5c-0.28,0 -0.5,-0.22 -0.5,-0.5s0.22,-0.5 0.5,-0.5 0.5,0.22 0.5,0.5 -0.22,0.5 -0.5,0.5zM19,3l-6,6 2,2 7,-7L22,3z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_content_duplicate.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"?attr/colorControlNormal\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M11,17H4A2,2 0,0 1,2 15V3A2,2 0,0 1,4 1H16V3H4V15H11V13L15,16L11,19V17M19,21V7H8V13H6V7A2,2 0,0 1,8 5H19A2,2 0,0 1,21 7V21A2,2 0,0 1,19 23H8A2,2 0,0 1,6 21V19H8V21H19Z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_content_paste.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"?attr/colorControlNormal\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M19,2h-4.18C14.4,0.84 13.3,0 12,0c-1.3,0 -2.4,0.84 -2.82,2L5,2c-1.1,0 -2,0.9 -2,2v16c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2L21,4c0,-1.1 -0.9,-2 -2,-2zM12,2c0.55,0 1,0.45 1,1s-0.45,1 -1,1 -1,-0.45 -1,-1 0.45,-1 1,-1zM19,20L5,20L5,4h2v3h10L17,4h2v16z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_content_save.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"?attr/colorControlNormal\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M17,3H5C3.89,3 3,3.9 3,5V19C3,20.1 3.89,21 5,21H19C20.1,21 21,20.1 21,19V7L17,3M19,19H5V5H16.17L19,7.83V19M12,12C10.34,12 9,13.34 9,15S10.34,18 12,18 15,16.66 15,15 13.66,12 12,12M6,6H15V10H6V6Z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_cursor_default_click.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"?attr/colorControlNormal\">\n  <path\n      android:fillColor=\"@android:color/white\"\n      android:pathData=\"M11.5,11L17.88,16.37L17,16.55L16.36,16.67C15.73,16.8 15.37,17.5 15.65,18.07L15.92,18.65L17.28,21.59L15.86,22.25L14.5,19.32L14.24,18.74C13.97,18.15 13.22,17.97 12.72,18.38L12.21,18.78L11.5,19.35V11M10.76,8.69A0.76,0.76 0,0 0,10 9.45V20.9C10,21.32 10.34,21.66 10.76,21.66C10.95,21.66 11.11,21.6 11.24,21.5L13.15,19.95L14.81,23.57C14.94,23.84 15.21,24 15.5,24C15.61,24 15.72,24 15.83,23.92L18.59,22.64C18.97,22.46 19.15,22 18.95,21.63L17.28,18L19.69,17.55C19.85,17.5 20,17.43 20.12,17.29C20.39,16.97 20.35,16.5 20,16.21L11.26,8.86L11.25,8.87C11.12,8.76 10.95,8.69 10.76,8.69M15,10V8H20V10H15M13.83,4.76L16.66,1.93L18.07,3.34L15.24,6.17L13.83,4.76M10,0H12V5H10V0M3.93,14.66L6.76,11.83L8.17,13.24L5.34,16.07L3.93,14.66M3.93,3.34L5.34,1.93L8.17,4.76L6.76,6.17L3.93,3.34M7,10H2V8H7V10\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_data_usage.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"?attr/colorControlNormal\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M13,2.05v3.03c3.39,0.49 6,3.39 6,6.92 0,0.9 -0.18,1.75 -0.48,2.54l2.6,1.53c0.56,-1.24 0.88,-2.62 0.88,-4.07 0,-5.18 -3.95,-9.45 -9,-9.95zM12,19c-3.87,0 -7,-3.13 -7,-7 0,-3.53 2.61,-6.43 6,-6.92V2.05c-5.06,0.5 -9,4.76 -9,9.95 0,5.52 4.47,10 9.99,10 3.31,0 6.24,-1.61 8.06,-4.09l-2.6,-1.53C16.17,17.98 14.21,19 12,19z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_database.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"?attr/colorControlNormal\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M12,3C7.58,3 4,4.79 4,7C4,9.21 7.58,11 12,11C16.42,11 20,9.21 20,7C20,4.79 16.42,3 12,3M4,9V12C4,14.21 7.58,16 12,16C16.42,16 20,14.21 20,12V9C20,11.21 16.42,13 12,13C7.58,13 4,11.21 4,9M4,14V17C4,19.21 7.58,21 12,21C16.42,21 20,19.21 20,17V14C20,16.21 16.42,18 12,18C7.58,18 4,16.21 4,14Z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_drag.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"?attr/colorControlNormal\">\n  <path\n      android:fillColor=\"@android:color/white\"\n      android:pathData=\"M7,19V17H9V19H7M11,19V17H13V19H11M15,19V17H17V19H15M7,15V13H9V15H7M11,15V13H13V15H11M15,15V13H17V15H15M7,11V9H9V11H7M11,11V9H13V11H11M15,11V9H17V11H15M7,7V5H9V7H7M11,7V5H13V7H11M15,7V5H17V7H15Z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_edit.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 -->\n<vector\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"?attr/colorControlNormal\"\n    >\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M14.06,9.02l0.92,0.92L5.92,19L5,19v-0.92l9.06,-9.06M17.66,3c-0.25,0 -0.51,0.1 -0.7,0.29l-1.83,1.83 3.75,3.75 1.83,-1.83c0.39,-0.39 0.39,-1.02 0,-1.41l-2.34,-2.34c-0.2,-0.2 -0.45,-0.29 -0.71,-0.29zM14.06,6.19L3,17.25L3,21h3.75L17.81,9.94l-3.75,-3.75z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_email.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"?attr/colorControlNormal\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M22,6c0,-1.1 -0.9,-2 -2,-2L4,4c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2L22,6zM20,6l-8,5 -8,-5h16zM20,18L4,18L4,8l8,5 8,-5v10z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_exodusprivacy.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later OR CC-BY-SA-4.0 -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"48\"\n    android:viewportHeight=\"48\"\n    android:tint=\"?attr/colorControlNormal\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M24.3691,9.4707C16.9391,9.4707 13.3691,12.9108 13.3691,17.0508C13.3691,21.1908 19.2793,23.3398 19.2793,23.3398C19.2793,23.3398 11.8906,24.6495 11.8906,30.2695C11.8906,34.4195 16.9401,38.5293 24.3301,38.5293C31.7601,38.5293 34.7305,34.7298 34.7305,32.3398A2.73,2.73 0,0 0,32.1309 29.7402C28.2509,29.7402 29.9708,36.7402 23.8008,36.7402C19.9108,36.7402 17.9102,34.5791 17.9102,30.0391C17.9102,26.1891 20.321,24.1895 23.541,24.1895A33.16,33.16 0,0 1,27.7109 24.4609C28.6609,24.4609 29.2793,24.2791 29.2793,23.3691C29.2793,22.4591 28.6609,22.2695 27.7109,22.2695A32,32 0,0 1,23.541 22.5508C20.321,22.5508 18.4102,20.5591 18.4102,17.1191C18.4102,14.3091 19.9408,11.2109 23.8008,11.2109C28.2308,11.2109 28.2303,17 31.0703,17A2.73,2.73 0,0 0,33.6699 14.3809C33.6699,11.9509 31.7991,9.4707 24.3691,9.4707z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_expand_less.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportHeight=\"24\"\n    android:viewportWidth=\"24\"\n    android:tint=\"?attr/colorControlNormal\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M12,8l-6,6 1.41,1.41L12,10.83l4.59,4.58L18,14z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_expand_more.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportHeight=\"24\"\n    android:viewportWidth=\"24\"\n    android:tint=\"?attr/colorControlNormal\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M16.59,8.59L12,13.17 7.41,8.59 6,10l6,6 6,-6z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_eye.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"?attr/colorControlNormal\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M12,9A3,3 0,0 0,9 12A3,3 0,0 0,12 15A3,3 0,0 0,15 12A3,3 0,0 0,12 9M12,17A5,5 0,0 1,7 12A5,5 0,0 1,12 7A5,5 0,0 1,17 12A5,5 0,0 1,12 17M12,4.5C7,4.5 2.73,7.61 1,12C2.73,16.39 7,19.5 12,19.5C17,19.5 21.27,16.39 23,12C21.27,7.61 17,4.5 12,4.5Z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_fast_forward.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"?attr/colorControlNormal\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M4,18l8.5,-6L4,6v12zM13,6v12l8.5,-6L13,6z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_fast_rewind.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"?attr/colorControlNormal\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M11,18L11,6l-8.5,6 8.5,6zM11.5,12l8.5,6L20,6l-8.5,6z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_file.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"?attr/colorControlNormal\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M14,2H6c-1.1,0 -1.99,0.9 -1.99,2L4,20c0,1.1 0.89,2 1.99,2H18c1.1,0 2,-0.9 2,-2V8l-6,-6zM6,20V4h7v5h5v11H6z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_file_copy.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportHeight=\"24\"\n    android:viewportWidth=\"24\"\n    android:tint=\"?attr/colorControlNormal\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M16,1L4,1c-1.1,0 -2,0.9 -2,2v14h2L4,3h12L16,1zM15,5l6,6v10c0,1.1 -0.9,2 -2,2L7.99,23C6.89,23 6,22.1 6,21l0.01,-14c0,-1.1 0.89,-2 1.99,-2h7zM14,12h5.5L14,6.5L14,12z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_file_document.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"?attr/colorControlNormal\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M6,2A2,2 0,0 0,4 4V20A2,2 0,0 0,6 22H18A2,2 0,0 0,20 20V8L14,2H6M6,4H13V9H18V20H6V4M8,12V14H16V12H8M8,16V18H13V16H8Z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_file_document_multiple.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"?attr/colorControlNormal\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M16,0H8C6.9,0 6,0.9 6,2V18C6,19.1 6.9,20 8,20H20C21.1,20 22,19.1 22,18V6L16,0M20,18H8V2H15V7H20V18M4,4V22H20V24H4C2.9,24 2,23.1 2,22V4H4M10,10V12H18V10H10M10,14V16H15V14H10Z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_file_export.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"?attr/colorControlNormal\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M14,2H6C4.9,2 4,2.9 4,4V20C4,21.1 4.9,22 6,22H18C19.1,22 20,21.1 20,20V8L14,2M18,20H6V4H13V9H18V20M16,11V18.1L13.9,16L11.1,18.8L8.3,16L11.1,13.2L8.9,11H16Z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_file_import.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"?attr/colorControlNormal\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M14,2H6C4.89,2 4,2.9 4,4V20C4,21.11 4.89,22 6,22H18C19.11,22 20,21.11 20,20V8L14,2M18,20H6V4H13V9H18V20M15,11.93V19H7.93L10.05,16.88L7.22,14.05L10.05,11.22L12.88,14.05L15,11.93Z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_file_plus.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"?attr/colorControlNormal\">\n  <path\n      android:fillColor=\"@android:color/white\"\n      android:pathData=\"M12,14V11H10V14H7V16H10V19H12V16H15V14M14,2H6A2,2 0,0 0,4 4V20A2,2 0,0 0,6 22H18A2,2 0,0 0,20 20V8L14,2M18,20H6V4H13V9H18\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_file_replace.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"?attr/colorControlNormal\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M14,3L12,1H4A2,2 0,0 0,2 3V15A2,2 0,0 0,4 17H11V19L15,16L11,13V15H4V3H14M21,10V21A2,2 0,0 1,19 23H8A2,2 0,0 1,6 21V19H8V21H19V12H14V7H8V13H6V7A2,2 0,0 1,8 5H16L21,10Z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_file_undo.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"?attr/colorControlNormal\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M14,2H6C4.89,2 4,2.9 4,4V20C4,21.11 4.89,22 6,22H18C19.11,22 20,21.11 20,20V8L14,2M18,20H6V4H13V9H18V20M17,17.61L15.84,18C15.33,16.44 13.86,15.31 12.13,15.31C11.17,15.31 10.31,15.66 9.63,16.23L11.4,18H7V13.6L8.76,15.36C9.66,14.57 10.83,14.09 12.13,14.09C14.4,14.09 16.33,15.57 17,17.61Z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_filter_list.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportHeight=\"24\"\n    android:viewportWidth=\"24\"\n    android:tint=\"?attr/colorControlNormal\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M10,18h4v-2h-4v2zM3,6v2h18L21,6L3,6zM6,13h12v-2L6,11v2z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_filter_menu.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"?attr/colorControlNormal\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M12,18.88A1,1 0,0 1,11.71 19.71A1,1 0,0 1,10.3 19.71L6.3,15.71A1,1 0,0 1,6 14.87V9.75L1.21,3.62A1,1 0,0 1,1.38 2.22A1,1 0,0 1,2 2H16A1,1 0,0 1,16.62 2.22A1,1 0,0 1,16.79 3.62L12,9.75V18.88M4,4L8,9.06V14.58L10,16.58V9.05L14,4M13,16L18,21L23,16Z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_find_and_replace.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:height=\"24dp\"\n    android:width=\"24dp\"\n    android:viewportHeight=\"24\"\n    android:viewportWidth=\"24\"\n    android:tint=\"?attr/colorControlNormal\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M11,6c1.38,0 2.63,0.56 3.54,1.46L12,10h6L18,4l-2.05,2.05C14.68,4.78 12.93,4 11,4c-3.53,0 -6.43,2.61 -6.92,6L6.1,10c0.46,-2.28 2.48,-4 4.9,-4zM16.64,15.14c0.66,-0.9 1.12,-1.97 1.28,-3.14L15.9,12c-0.46,2.28 -2.48,4 -4.9,4 -1.38,0 -2.63,-0.56 -3.54,-1.46L10,12L4,12v6l2.05,-2.05C7.32,17.22 9.07,18 11,18c1.55,0 2.98,-0.51 4.14,-1.36L20,21.49 21.49,20l-4.85,-4.86z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_find_and_replace_all.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"?attr/colorControlNormal\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"m11,4c-3.53,0 -6.43,2.61 -6.92,6h2.02c0.46,-2.28 2.48,-4 4.9,-4 1.38,0 2.629,0.561 3.539,1.461l-0.607,0.607 0.705,1.932h3.363v-6l-2.051,2.051c-1.27,-1.27 -3.019,-2.051 -4.949,-2.051zM12.818,9.182 L12,10h1.117l-0.299,-0.818zM4,12v6l2.051,-2.051c1.27,1.27 3.019,2.051 4.949,2.051 1.55,0 3.001,-0.499 4.141,-1.359l4.859,4.859 1.5,-1.5 -4.859,-4.859c0.66,-0.9 1.119,-1.971 1.279,-3.141h-2.02c-0.46,2.28 -2.48,4 -4.9,4 -1.119,0 -2.148,-0.375 -2.984,-0.994h-2.258l1.111,-3.006h-2.869z\" />\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"m14.527,13.786h-1.809l-0.469,-1.372h-2.516l-0.469,1.372h-1.764l2.507,-6.786h2.014zM11.825,11.17 L10.991,8.736 10.157,11.17z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_flag.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"?attr/colorControlNormal\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M14,6l-1,-2L5,4v17h2v-7h5l1,2h7L20,6h-6zM18,14h-4l-1,-2L7,12L7,6h5l1,2h5v6z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_fold_vertical.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"?attr/colorControlNormal\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M5.41,7.41L10,12L5.41,16.59L4,15.17L7.17,12L4,8.83L5.41,7.41M18.59,16.59L14,12L18.59,7.42L20,8.83L16.83,12L20,15.17L18.59,16.59Z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_folder.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"?attr/colorControlNormal\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M20,18H4V8H20M20,6H12L10,4H4C2.89,4 2,4.89 2,6V18A2,2 0,0 0,4 20H20A2,2 0,0 0,22 18V8C22,6.89 21.1,6 20,6Z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_font_download.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"?attr/colorControlNormal\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M9.17,15.5h5.64l1.14,3h2.09l-5.11,-13h-1.86l-5.11,13h2.09l1.12,-3zM12,7.98l2.07,5.52L9.93,13.5L12,7.98zM20,2L4,2c-1.1,0 -2,0.9 -2,2v16c0,1.1 0.9,2 2,2h16c1.1,0 2,-0.9 2,-2L22,4c0,-1.1 -0.9,-2 -2,-2zM20,20L4,20L4,4h16v16z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_form_textbox.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"?attr/colorControlNormal\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M17,7H22V17H17V19A1,1 0,0 0,18 20H20V22H17.5C16.95,22 16,21.55 16,21C16,21.55 15.05,22 14.5,22H12V20H14A1,1 0,0 0,15 19V5A1,1 0,0 0,14 4H12V2H14.5C15.05,2 16,2.45 16,3C16,2.45 16.95,2 17.5,2H20V4H18A1,1 0,0 0,17 5V7M2,7H13V9H4V15H13V17H2V7M20,15V9H17V15H20Z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_frost_aurorastore.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"48\"\n    android:viewportHeight=\"48\"\n    android:tint=\"?attr/colorControlNormal\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"m24,4.4843c-0.7298,0 -1.4586,0.3569 -1.8854,1.0697l-8.3394,13.985h-8.4308c-2.2005,0.001 -3.8007,2.091 -3.227,4.2154l4.7363,17.51c0.3548,1.3312 1.5622,2.2563 2.9399,2.2513h28.413c1.3776,0.0051 2.5851,-0.9201 2.9399,-2.2513l4.7363,-17.51c0.5737,-2.1244 -1.0265,-4.2144 -3.227,-4.2154h-8.4308l-8.3394,-13.985c-0.4268,-0.7128 -1.1556,-1.0697 -1.8854,-1.0697zM24,10.9535 L29.1251,19.5393h-10.25zM23.9212,23.7445a2.1726,2.1726 0,0 1,1.9794 1.1155l6.3219,11.175a2.2246,2.2246 0,0 1,0 2.1852,2.1986 2.1986,0 0,1 -1.9006,1.0926h-12.672a2.1986,2.1986 0,0 1,-1.8981 -1.0926,2.2246 2.2246,0 0,1 0,-2.1852l6.3473,-11.175a2.1726,2.1726 0,0 1,1.8219 -1.1155zM24,30.3763 L21.3981,34.9297h5.2038z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_frost_fdroid.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"48\"\n    android:viewportHeight=\"48\"\n    android:tint=\"?attr/colorControlNormal\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"m8.1331,23.032c-1.507,0 -3.0115,1.506 -3,3l0.1169,15.218c0.0115,1.494 1.493,3 3,3h31.5c1.507,0 3.0115,-1.506 3,-3l-0.1169,-15.218c-0.0115,-1.494 -1.493,-3 -3,-3z\" />\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"m43.777,3.75c-0.5236,0.0003 -1.0256,0.209 -1.395,0.58l-2.43,2.42h-31.905l-2.43,-2.42c-0.7693,-0.7731 -2.0207,-0.7731 -2.79,0 -0.772,0.7698 -0.772,2.0202 0,2.79l2.423,2.43v8.8279c0,1.494 1.493,3 3,3h31.5c1.507,0 3,-1.506 3,-3v-8.8279l2.423,-2.428c0.772,-0.7698 0.772,-2.0202 0,-2.79 -0.369,-0.372 -0.8711,-0.5814 -1.395,-0.582zM16.107,10.4372c5.26,0 5.26,7.89 0,7.89s-5.26,-7.89 0,-7.89zM31.892,10.4372c5.26,0 5.26,7.89 0,7.89s-5.26,-7.89 0,-7.89z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_frost_termux.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"48\"\n    android:viewportHeight=\"48\"\n    android:tint=\"?attr/colorControlNormal\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"m7,5c-1.11,0 -2,0.892 -2,2v34c0,1.11 0.892,2 2,2h34c1.11,0 2,-0.892 2,-2v-34c0,-1.11 -0.892,-2 -2,-2h-34zM10,10h5v10h-5v-10z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_get_app.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"?attr/colorControlNormal\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M19,9h-4V3H9v6H5l7,7 7,-7zM5,18v2h14v-2H5z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_hammer_wrench.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"?attr/colorControlNormal\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M13.78,15.3L19.78,21.3L21.89,19.14L15.89,13.14L13.78,15.3M17.5,10.1C17.11,10.1 16.69,10.05 16.36,9.91L4.97,21.25L2.86,19.14L10.27,11.74L8.5,9.96L7.78,10.66L6.33,9.25V12.11L5.63,12.81L2.11,9.25L2.81,8.55H5.62L4.22,7.14L7.78,3.58C8.95,2.41 10.83,2.41 12,3.58L9.89,5.74L11.3,7.14L10.59,7.85L12.38,9.63L14.2,7.75C14.06,7.42 14,7 14,6.63C14,4.66 15.56,3.11 17.5,3.11C18.09,3.11 18.61,3.25 19.08,3.53L16.41,6.2L17.91,7.7L20.58,5.03C20.86,5.5 21,6 21,6.63C21,8.55 19.45,10.1 17.5,10.1Z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_history.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"?attr/colorControlNormal\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M13,3c-4.97,0 -9,4.03 -9,9L1,12l3.89,3.89 0.07,0.14L9,12L6,12c0,-3.87 3.13,-7 7,-7s7,3.13 7,7 -3.13,7 -7,7c-1.93,0 -3.68,-0.79 -4.94,-2.06l-1.42,1.42C8.27,19.99 10.51,21 13,21c4.97,0 9,-4.03 9,-9s-4.03,-9 -9,-9zM12,8v5l4.25,2.52 0.77,-1.28 -3.52,-2.09L13.5,8z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_image.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"?attr/colorControlNormal\">\n  <path\n      android:fillColor=\"@android:color/white\"\n      android:pathData=\"M19,19H5V5H19M19,3H5A2,2 0,0 0,3 5V19A2,2 0,0 0,5 21H19A2,2 0,0 0,21 19V5A2,2 0,0 0,19 3M13.96,12.29L11.21,15.83L9.25,13.47L6.5,17H17.5L13.96,12.29Z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_information_circle.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"?attr/colorControlNormal\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M12.3,7.29C12.5,7.11 12.74,7 13,7C13.27,7 13.5,7.11 13.71,7.29C13.9,7.5 14,7.74 14,8C14,8.27 13.9,8.5 13.71,8.71C13.5,8.9 13.27,9 13,9C12.74,9 12.5,8.9 12.3,8.71C12.11,8.5 12,8.27 12,8C12,7.74 12.11,7.5 12.3,7.29M9.8,11.97C9.8,11.97 11.97,10.25 12.76,10.18C13.5,10.12 13.35,10.97 13.28,11.41L13.27,11.47C13.13,12 12.96,12.64 12.79,13.25C12.41,14.64 12.04,16 12.13,16.25C12.23,16.59 12.85,16.16 13.3,15.86C13.36,15.82 13.41,15.78 13.46,15.75C13.46,15.75 13.54,15.67 13.62,15.78C13.64,15.81 13.66,15.84 13.68,15.86C13.77,16 13.82,16.05 13.7,16.13L13.66,16.15C13.44,16.3 12.5,16.96 12.12,17.2C11.71,17.47 10.14,18.37 10.38,16.62C10.59,15.39 10.87,14.33 11.09,13.5C11.5,12 11.68,11.32 10.76,11.91C10.39,12.13 10.17,12.27 10.04,12.36C9.93,12.44 9.92,12.44 9.85,12.31L9.82,12.25L9.77,12.17C9.7,12.07 9.7,12.06 9.8,11.97M22,12C22,17.5 17.5,22 12,22C6.5,22 2,17.5 2,12C2,6.5 6.5,2 12,2C17.5,2 22,6.5 22,12M20,12C20,7.58 16.42,4 12,4C7.58,4 4,7.58 4,12C4,16.42 7.58,20 12,20C16.42,20 20,16.42 20,12Z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_launcher_fm_foreground.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later OR CC-BY-SA-4.0 -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"108dp\"\n    android:height=\"108dp\"\n    android:viewportWidth=\"108\"\n    android:viewportHeight=\"108\">\n    <group\n        android:scaleX=\"0.5\"\n        android:scaleY=\"0.5\"\n        android:translateX=\"27\"\n        android:translateY=\"27\">\n        <path\n            android:pathData=\"m10.8,10.8c-5.99,0 -10.8,4.8 -10.8,10.8v64.8a10.8,10.8 0,0 0,10.8 10.8h86.4a10.8,10.8 0,0 0,10.8 -10.8v-54c0,-5.99 -4.86,-10.8 -10.8,-10.8h-43.2l-10.8,-10.8h-32.4zM53.32,26.5c1.28,-0.14 3.49,4.16 4.53,5.76 1.39,2.1 3.15,5.47 5.27,10.13 2.12,4.65 4.45,9.27 6.5,14.12 2.07,4.85 4.15,9.61 6.22,14.26 2.1,4.65 4.08,8.47 5.95,11.45 1.9,2.96 3.45,4.44 4.66,4.44 0.1,0 0.22,-0.01 0.34,-0.04 0.15,-0.05 0.05,0.05 0.18,0.02 0.13,-0.03 0.24,-0.04 0.34,-0.04 0.13,-0.03 0.22,-0.01 0.27,0.04 0.08,0.05 0.11,0.14 0.11,0.27 0,0.43 -0.29,0.96 -1.36,1.87 -1.04,0.94 -2.24,1.78 -3.6,2.54 -1.37,0.78 -2.44,1.18 -3.22,1.18 -0.81,0 -1.68,-0.6 -2.62,-1.78 -0.91,-1.16 -1.69,-2.44 -2.35,-3.83 -0.63,-1.39 -1.34,-2.9 -1.92,-4.21 -2.59,-5.07 -6.05,-6.94 -14.43,-7.16 -5.23,-0.15 -15.12,1.65 -19.64,3.9 -2,2.45 -3.46,4.12 -4.4,5 -0.85,0.81 -2.6,2.52 -4.47,3.96 -2.03,1.39 -2.44,1.64 -4.8,2.77 -1.02,0.49 -5.8,2.28 -4.3,0.68 4.17,-3.53 6.08,-5.26 8.79,-8.09 1.09,-1.11 2.14,-2.3 3.15,-3.56 2.25,-2.83 4.31,-5.78 6.18,-8.84 1.9,-3.08 3.45,-5.97 4.66,-8.65 1.21,-2.71 2.29,-5.33 3.22,-7.89 0.94,-2.55 1.66,-4.87 2.16,-6.94 0.53,-2.1 1.27,-4.24 1.57,-5.78 0.33,-1.54 0.89,-4.09 1.02,-5.07 0.98,-6.08 0.9,-5.9 1.49,-10.15 0.14,-0.22 0.3,-0.33 0.48,-0.35zM55.97,45.06c0.03,-0.04 -0.23,0.54 -0.53,1.63 -0.28,1.09 -0.76,2.64 -1.44,4.66 -0.66,2.02 -1.48,4.24 -2.46,6.64 -0.96,2.4 -2.3,5.14 -4.02,8.23 -1.69,3.08 -3.56,6.02 -5.61,8.8 6.07,-2.96 12.07,-4.44 18.01,-4.44 1.31,0 2.57,0.07 3.75,0.23 1.19,0.15 2.12,0.3 2.81,0.46 0.68,0.13 1.06,0.19 1.14,0.19l0.07,-0.04c0,-0.28 -1.9,-4.74 -5.69,-13.39 -3.79,-8.65 -6.15,-12.77 -6.03,-12.97z\"\n            android:strokeWidth=\"5.4\"\n            android:fillColor=\"#dcaf74\" />\n    </group>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_launcher_foreground.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later OR CC-BY-SA-4.0 -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"108dp\"\n    android:height=\"108dp\"\n    android:viewportWidth=\"108\"\n    android:viewportHeight=\"108\">\n  <group android:scaleX=\"0.4\"\n      android:scaleY=\"0.4\"\n      android:translateX=\"32.4\"\n      android:translateY=\"32.4\">\n    <path\n        android:pathData=\"m49.76,17.96c-0.2,1.58 -1.1,5.66 -1.63,8.13 -0.49,2.47 -1.67,5.9 -2.52,9.27 -0.81,3.32 -1.96,7.03 -3.46,11.12 -1.5,4.09 -3.22,8.3 -5.17,12.64 -1.94,4.29 -4.44,8.91 -7.47,13.85 -3,4.9 -6.3,9.62 -9.9,14.16 -1.62,2.03 -3.3,3.93 -5.04,5.71 -4.35,4.53 -7.42,7.31 -14.09,12.97 -2.41,2.57 5.25,-0.3 6.89,-1.08 3.79,-1.81 4.45,-2.22 7.7,-4.44 3,-2.31 5.81,-5.05 7.17,-6.35 1.5,-1.42 3.85,-4.09 7.05,-8.02 7.25,-3.61 23.1,-6.48 31.48,-6.24 13.43,0.34 18.96,3.34 23.12,11.46 0.93,2.11 2.06,4.52 3.08,6.75 1.05,2.23 2.31,4.27 3.77,6.14 1.5,1.9 2.9,2.86 4.19,2.86 1.26,0 2.98,-0.63 5.17,-1.88 2.19,-1.22 4.11,-2.57 5.77,-4.07 1.7,-1.46 2.17,-2.31 2.17,-3 0,-0.2 -0.06,-0.34 -0.18,-0.43 -0.08,-0.08 -0.22,-0.1 -0.43,-0.06 -0.16,0 -0.34,0.02 -0.55,0.06 -0.2,0.04 -0.05,-0.12 -0.29,-0.04 -0.2,0.04 -0.38,0.06 -0.55,0.06 -1.94,0 -4.44,-2.37 -7.47,-7.11 -3,-4.78 -6.18,-10.9 -9.54,-18.35 -3.32,-7.45 -6.64,-15.07 -9.97,-22.85 -3.28,-7.78 -7,-15.18 -10.41,-22.63 -3.4,-7.45 -6.22,-12.86 -8.45,-16.23 -1.91,-2.94 -6.26,-11.52 -8.04,-8.66 -0.93,6.82 -0.82,6.53 -2.38,16.27zM57.15,30.86c-0.19,0.31 3.59,6.93 9.66,20.78 6.08,13.85 9.11,21 9.11,21.45l-0.12,0.06c-0.12,0 -0.73,-0.1 -1.82,-0.3 -1.09,-0.24 -2.59,-0.49 -4.5,-0.73 -1.9,-0.24 -3.91,-0.36 -6.02,-0.36 -9.52,0 -19.14,2.37 -28.86,7.11 3.28,-4.46 6.28,-9.16 8.99,-14.1 2.75,-4.94 4.9,-9.34 6.44,-13.19 1.58,-3.85 2.9,-7.39 3.95,-10.63 1.09,-3.24 1.86,-5.73 2.31,-7.47 0.49,-1.74 0.89,-2.68 0.85,-2.61z\"\n        android:strokeWidth=\"3.1112\"\n        android:fillColor=\"#dcaf74\"/>\n  </group>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_link.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"?attr/colorControlNormal\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M3.9,12c0,-1.71 1.39,-3.1 3.1,-3.1h4L11,7L7,7c-2.76,0 -5,2.24 -5,5s2.24,5 5,5h4v-1.9L7,15.1c-1.71,0 -3.1,-1.39 -3.1,-3.1zM8,13h8v-2L8,11v2zM17,7h-4v1.9h4c1.71,0 3.1,1.39 3.1,3.1s-1.39,3.1 -3.1,3.1h-4L13,17h4c2.76,0 5,-2.24 5,-5s-2.24,-5 -5,-5z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_liquid_spot_off.xml",
    "content": "<!--  SPDX-License-Identifier: Apache-2.0 -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"?attr/colorControlNormal\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"m20.5,16c-0.24,0 -0.451,0.046 -0.631,0.127l2.002,2.006c0.083,-0.199 0.129,-0.414 0.129,-0.633 0,-0.76 -0.5,-1.5 -1.5,-1.5z\" />\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"m3.305,2.111 l-1.281,1.27 2.223,2.223c-0.072,0.045 -0.143,0.096 -0.217,0.156 -0.62,0.7 -0.51,1.171 -0.25,1.621 0.26,0.45 0.671,0.878 0.641,1.488 -0.01,0.63 -0.64,0.811 -1.26,1.061 -0.61,0.25 -1.201,0.569 -1.131,1.359 0.09,1.3 0.97,1.48 1.84,1.5 0.89,0.02 1.791,-0.129 1.971,0.521 0.43,1.6 -0.32,2.51 -0.9,3.19s-1,1.209 0.1,2.119c1.22,0.58 1.961,-0.21 2.611,-1.02 0.63,-0.82 1.13,-1.65 1.85,-1.17 0.9,0.46 0.541,1.76 0.311,2.99 -0.23,1.23 -0.31,2.39 1.09,2.58 1.77,-0.21 1.749,-1.169 1.469,-2.279 -0.28,-1.1 -0.829,-2.351 -0.119,-3.131 0.65,-0.91 1.67,-0.14 2.75,0.5 0.429,0.254 0.869,0.48 1.301,0.568l5.453,5.453 1.27,-1.27z\" />\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"m19.568,2.012c-0.744,0.008 -1.416,0.775 -2.098,1.688 -1.09,1.46 -2.231,3.302 -3.801,3.012 -1.1,-0.21 -1.499,-1.38 -1.959,-2.41 -0.45,-1.03 -0.95,-1.921 -2.25,-1.561 -1.5,0.41 -1.092,1.301 -0.512,2.23 0.131,0.21 0.27,0.42 0.398,0.627l6.916,6.922c0.585,-0.18 1.533,-0.188 2.416,-0.279 1.36,-0.14 2.57,-0.481 2.06,-1.971 -0.48,-1.41 -1.471,-1.24 -2.391,-0.93 -0.93,0.31 -1.81,0.759 -2.08,-0.061 -0.46,-1.41 1.461,-2.049 3.131,-2.779 1.67,-0.78 3.1,-1.661 1.6,-3.551 -0.514,-0.675 -0.985,-0.942 -1.432,-0.938z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_list_status.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"?attr/colorControlNormal\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M16.5,11L13,7.5L14.4,6.1L16.5,8.2L20.7,4L22.1,5.4L16.5,11M11,7H2V9H11V7M21,13.4L19.6,12L17,14.6L14.4,12L13,13.4L15.6,16L13,18.6L14.4,20L17,17.4L19.6,20L21,18.6L18.4,16L21,13.4M11,15H2V17H11V15Z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_lock.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"?attr/colorControlNormal\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M18,8h-1L17,6c0,-2.76 -2.24,-5 -5,-5S7,3.24 7,6v2L6,8c-1.1,0 -2,0.9 -2,2v10c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2L20,10c0,-1.1 -0.9,-2 -2,-2zM9,6c0,-1.66 1.34,-3 3,-3s3,1.34 3,3v2L9,8L9,6zM18,20L6,20L6,10h12v10zM12,17c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_menu.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:tint=\"?attr/colorControlNormal\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\">\n\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M3,18h18v-2L3,16v2zM3,13h18v-2L3,11v2zM3,6v2h18L21,6L3,6z\" />\n\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_next.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:autoMirrored=\"true\"\n    android:tint=\"?attr/colorControlNormal\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\">\n\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M6.23,20.23l1.77,1.77l10,-10l-10,-10l-1.77,1.77l8.23,8.23z\" />\n\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_open_in_new.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"?attr/colorControlNormal\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M19,19H5V5h7V3H5c-1.11,0 -2,0.9 -2,2v14c0,1.1 0.89,2 2,2h14c1.1,0 2,-0.9 2,-2v-7h-2v7zM14,3v2h3.59l-9.83,9.83 1.41,1.41L19,6.41V10h2V3h-7z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_package.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"?attr/colorControlNormal\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M2,10.96C1.5,10.68 1.35,10.07 1.63,9.59L3.13,7C3.24,6.8 3.41,6.66 3.6,6.58L11.43,2.18C11.59,2.06 11.79,2 12,2C12.21,2 12.41,2.06 12.57,2.18L20.47,6.62C20.66,6.72 20.82,6.88 20.91,7.08L22.36,9.6C22.64,10.08 22.47,10.69 22,10.96L21,11.54V16.5C21,16.88 20.79,17.21 20.47,17.38L12.57,21.82C12.41,21.94 12.21,22 12,22C11.79,22 11.59,21.94 11.43,21.82L3.53,17.38C3.21,17.21 3,16.88 3,16.5V10.96C2.7,11.13 2.32,11.14 2,10.96M12,4.15V4.15L12,10.85V10.85L17.96,7.5L12,4.15M5,15.91L11,19.29V12.58L5,9.21V15.91M19,15.91V12.69L14,15.59C13.67,15.77 13.3,15.76 13,15.6V19.29L19,15.91M13.85,13.36L20.13,9.73L19.55,8.72L13.27,12.35L13.85,13.36Z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_palette_swatch.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"?attr/colorControlNormal\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M2.5,19.6L3.8,20.2V11.2L1.4,17C1,18.1 1.5,19.2 2.5,19.6M15.2,4.8L20.2,16.8L12.9,19.8L7.9,7.9V7.8L15.2,4.8M15.3,2.8C15,2.8 14.8,2.8 14.5,2.9L7.1,6C6.4,6.3 5.9,7 5.9,7.8C5.9,8 5.9,8.3 6,8.6L11,20.5C11.3,21.3 12,21.7 12.8,21.7C13.1,21.7 13.3,21.7 13.6,21.6L21,18.5C22,18.1 22.5,16.9 22.1,15.9L17.1,4C16.8,3.2 16,2.8 15.3,2.8M10.5,9.9C9.9,9.9 9.5,9.5 9.5,8.9S9.9,7.9 10.5,7.9C11.1,7.9 11.5,8.4 11.5,8.9S11.1,9.9 10.5,9.9M5.9,19.8C5.9,20.9 6.8,21.8 7.9,21.8H9.3L5.9,13.5V19.8Z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_pause.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportHeight=\"24\"\n    android:viewportWidth=\"24\"\n    android:tint=\"?attr/colorControlNormal\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M6,19h4L10,5L6,5v14zM14,5v14h4L18,5h-4z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_pdf_file.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"?attr/colorControlNormal\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M19,3H5C3.9,3 3,3.9 3,5V19C3,20.1 3.9,21 5,21H19C20.1,21 21,20.1 21,19V5C21,3.9 20.1,3 19,3M9.5,11.5C9.5,12.3 8.8,13 8,13H7V15H5.5V9H8C8.8,9 9.5,9.7 9.5,10.5V11.5M14.5,13.5C14.5,14.3 13.8,15 13,15H10.5V9H13C13.8,9 14.5,9.7 14.5,10.5V13.5M18.5,10.5H17V11.5H18.5V13H17V15H15.5V9H18.5V10.5M12,10.5H13V13.5H12V10.5M7,10.5H8V11.5H7V10.5Z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_phone_android.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"?attr/colorControlNormal\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M16,1L8,1C6.34,1 5,2.34 5,4v16c0,1.66 1.34,3 3,3h8c1.66,0 3,-1.34 3,-3L19,4c0,-1.66 -1.34,-3 -3,-3zM14,21h-4v-1h4v1zM17.25,18L6.75,18L6.75,4h10.5v14z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_play_arrow.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportHeight=\"24\"\n    android:viewportWidth=\"24\"\n    android:tint=\"?attr/colorControlNormal\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M8,5v14l11,-7z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_power_settings.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"?attr/colorControlNormal\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M13,3h-2v10h2L13,3zM17.83,5.17l-1.42,1.42C17.99,7.86 19,9.81 19,12c0,3.87 -3.13,7 -7,7s-7,-3.13 -7,-7c0,-2.19 1.01,-4.14 2.58,-5.42L6.17,5.17C4.23,6.82 3,9.26 3,12c0,4.97 4.03,9 9,9s9,-4.03 9,-9c0,-2.74 -1.23,-5.18 -3.17,-6.83z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_presentation.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"?attr/colorControlNormal\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M2,3H10A2,2 0,0 1,12 1A2,2 0,0 1,14 3H22V5H21V16H15.25L17,22H15L13.25,16H10.75L9,22H7L8.75,16H3V5H2V3M5,5V14H19V5H5Z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_previous.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:autoMirrored=\"true\"\n    android:tint=\"?attr/colorControlNormal\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\">\n\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M17.77,3.77l-1.77,-1.77l-10,10l10,10l1.77,-1.77l-8.23,-8.23z\" />\n\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_pulse.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"?attr/colorControlNormal\">\n  <path\n      android:fillColor=\"@android:color/white\"\n      android:pathData=\"M3,13H5.79L10.1,4.79L11.28,13.75L14.5,9.66L17.83,13H21V15H17L14.67,12.67L9.92,18.73L8.94,11.31L7,15H3V13Z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_record_rec.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"?attr/colorControlNormal\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M12.5,5A7.5,7.5 0,0 0,5 12.5A7.5,7.5 0,0 0,12.5 20A7.5,7.5 0,0 0,20 12.5A7.5,7.5 0,0 0,12.5 5M7,10H9A1,1 0,0 1,10 11V12C10,12.5 9.62,12.9 9.14,12.97L10.31,15H9.15L8,13V15H7M12,10H14V11H12V12H14V13H12V14H14V15H12A1,1 0,0 1,11 14V11A1,1 0,0 1,12 10M16,10H18V11H16V14H18V15H16A1,1 0,0 1,15 14V11A1,1 0,0 1,16 10M8,11V12H9V11\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_redo.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"?attr/colorControlNormal\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M18.4,10.6C16.55,8.99 14.15,8 11.5,8c-4.65,0 -8.58,3.03 -9.96,7.22L3.9,16c1.05,-3.19 4.05,-5.5 7.6,-5.5 1.95,0 3.73,0.72 5.12,1.88L13,16h9V7l-3.6,3.6z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_refresh.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"?attr/colorControlNormal\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M17.65,6.35C16.2,4.9 14.21,4 12,4c-4.42,0 -7.99,3.58 -7.99,8s3.57,8 7.99,8c3.73,0 6.84,-2.55 7.73,-6h-2.08c-0.82,2.33 -3.04,4 -5.65,4 -3.31,0 -6,-2.69 -6,-6s2.69,-6 6,-6c1.66,0 3.14,0.69 4.22,1.78L13,11h7V4l-2.35,2.35z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_repeat.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"?attr/colorControlNormal\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M7,7h10v3l4,-4 -4,-4v3L5,5v6h2L7,7zM17,17L7,17v-3l-4,4 4,4v-3h12v-6h-2v4z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_repeat_off.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"?attr/colorControlNormal\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M2,5.27L3.28,4L20,20.72L18.73,22L15.73,19H7V22L3,18L7,14V17H13.73L7,10.27V11H5V8.27L2,5.27M17,13H19V17.18L17,15.18V13M17,5V2L21,6L17,10V7H8.82L6.82,5H17Z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_repeat_one.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"?attr/colorControlNormal\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M7,7h10v3l4,-4 -4,-4v3L5,5v6h2L7,7zM17,17L7,17v-3l-4,4 4,4v-3h12v-6h-2v4zM13,15L13,9h-1l-2,1v1h1.5v4L13,15z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_replay.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"?attr/colorControlNormal\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M12,5V1L7,6l5,5V7c3.31,0 6,2.69 6,6s-2.69,6 -6,6 -6,-2.69 -6,-6H4c0,4.42 3.58,8 8,8s8,-3.58 8,-8 -3.58,-8 -8,-8z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_restore.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"?attr/colorControlNormal\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M13,3c-4.97,0 -9,4.03 -9,9L1,12l3.89,3.89 0.07,0.14L9,12L6,12c0,-3.87 3.13,-7 7,-7s7,3.13 7,7 -3.13,7 -7,7c-1.93,0 -3.68,-0.79 -4.94,-2.06l-1.42,1.42C8.27,19.99 10.51,21 13,21c4.97,0 9,-4.03 9,-9s-4.03,-9 -9,-9zM12,8v5l4.28,2.54 0.72,-1.21 -3.5,-2.08L13.5,8L12,8z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_run_fast.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"?attr/colorControlNormal\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M16.5,5.5A2,2 0,0 0,18.5 3.5A2,2 0,0 0,16.5 1.5A2,2 0,0 0,14.5 3.5A2,2 0,0 0,16.5 5.5M12.9,19.4L13.9,15L16,17V23H18V15.5L15.9,13.5L16.5,10.5C17.89,12.09 19.89,13 22,13V11C20.24,11.03 18.6,10.11 17.7,8.6L16.7,7C16.34,6.4 15.7,6 15,6C14.7,6 14.5,6.1 14.2,6.1L9,8.3V13H11V9.6L12.8,8.9L11.2,17L6.3,16L5.9,18L12.9,19.4M4,9A1,1 0,0 1,3 8A1,1 0,0 1,4 7H7V9H4M5,5A1,1 0,0 1,4 4A1,1 0,0 1,5 3H10V5H5M3,13A1,1 0,0 1,2 12A1,1 0,0 1,3 11H7V13H3Z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_security.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"?attr/colorControlNormal\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M12,1L3,5v6c0,5.55 3.84,10.74 9,12 5.16,-1.26 9,-6.45 9,-12L21,5l-9,-4zM12,11.99h7c-0.53,4.12 -3.28,7.79 -7,8.94L12,12L5,12L5,6.3l7,-3.11v8.8z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_security_network.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"?attr/colorControlNormal\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M13,19H14A1,1 0,0 1,15 20H22V22H15A1,1 0,0 1,14 23H10A1,1 0,0 1,9 22H2V20H9A1,1 0,0 1,10 19H11V17.34C8.07,16.13 6,13 6,9.67V5.67L12,3L18,5.67V9.67C18,13 15.93,16.13 13,17.34V19M12,5L8,6.69V10H12V5M12,10V16C13.91,15.53 16,13.06 16,11V10H12Z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_settings.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"?attr/colorControlNormal\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M19.14,12.94c0.04,-0.3 0.06,-0.61 0.06,-0.94c0,-0.32 -0.02,-0.64 -0.07,-0.94l2.03,-1.58c0.18,-0.14 0.23,-0.41 0.12,-0.61l-1.92,-3.32c-0.12,-0.22 -0.37,-0.29 -0.59,-0.22l-2.39,0.96c-0.5,-0.38 -1.03,-0.7 -1.62,-0.94L14.4,2.81c-0.04,-0.24 -0.24,-0.41 -0.48,-0.41h-3.84c-0.24,0 -0.43,0.17 -0.47,0.41L9.25,5.35C8.66,5.59 8.12,5.92 7.63,6.29L5.24,5.33c-0.22,-0.08 -0.47,0 -0.59,0.22L2.74,8.87C2.62,9.08 2.66,9.34 2.86,9.48l2.03,1.58C4.84,11.36 4.8,11.69 4.8,12s0.02,0.64 0.07,0.94l-2.03,1.58c-0.18,0.14 -0.23,0.41 -0.12,0.61l1.92,3.32c0.12,0.22 0.37,0.29 0.59,0.22l2.39,-0.96c0.5,0.38 1.03,0.7 1.62,0.94l0.36,2.54c0.05,0.24 0.24,0.41 0.48,0.41h3.84c0.24,0 0.44,-0.17 0.47,-0.41l0.36,-2.54c0.59,-0.24 1.13,-0.56 1.62,-0.94l2.39,0.96c0.22,0.08 0.47,0 0.59,-0.22l1.92,-3.32c0.12,-0.22 0.07,-0.47 -0.12,-0.61L19.14,12.94zM12,15.6c-1.98,0 -3.6,-1.62 -3.6,-3.6s1.62,-3.6 3.6,-3.6s3.6,1.62 3.6,3.6S13.98,15.6 12,15.6z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_share.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"?attr/colorControlNormal\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M18,16.08c-0.76,0 -1.44,0.3 -1.96,0.77L8.91,12.7c0.05,-0.23 0.09,-0.46 0.09,-0.7s-0.04,-0.47 -0.09,-0.7l7.05,-4.11c0.54,0.5 1.25,0.81 2.04,0.81 1.66,0 3,-1.34 3,-3s-1.34,-3 -3,-3 -3,1.34 -3,3c0,0.24 0.04,0.47 0.09,0.7L8.04,9.81C7.5,9.31 6.79,9 6,9c-1.66,0 -3,1.34 -3,3s1.34,3 3,3c0.79,0 1.5,-0.31 2.04,-0.81l7.12,4.16c-0.05,0.21 -0.08,0.43 -0.08,0.65 0,1.61 1.31,2.92 2.92,2.92 1.61,0 2.92,-1.31 2.92,-2.92s-1.31,-2.92 -2.92,-2.92z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_shield_key.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"?attr/colorControlNormal\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M21,11C21,16.55 17.16,21.74 12,23C6.84,21.74 3,16.55 3,11V5L12,1L21,5V11M12,21C15.75,20 19,15.54 19,11.22V6.3L12,3.18L5,6.3V11.22C5,15.54 8.25,20 12,21M12,6A3,3 0,0 1,15 9C15,10.31 14.17,11.42 13,11.83V14H15V16H13V18H11V11.83C9.83,11.42 9,10.31 9,9A3,3 0,0 1,12 6M12,8A1,1 0,0 0,11 9A1,1 0,0 0,12 10A1,1 0,0 0,13 9A1,1 0,0 0,12 8Z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_shortcut_record.xml",
    "content": "<!-- SPDX-License-Identifier: WTFPL -->\n<vector android:height=\"24dp\"\n    android:viewportHeight=\"192.0\"\n    android:viewportWidth=\"192.0\"\n    android:width=\"24dp\"\n    xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <path\n        android:fillColor=\"#f5f5f5\"\n        android:pathData=\"M84.58,8.82C104.35,6.14 124.96,10.56 141.94,21.02C161.23,32.78 175.65,52.22 181.18,74.13C186.3,93.99 184.24,115.64 175.23,134.09C165.68,154.19 148.15,170.29 127.33,178.15C107.39,185.87 84.59,185.85 64.65,178.15C43.16,170.05 25.16,153.11 15.84,132.11C7.61,114.09 5.86,93.24 10.84,74.08C16.31,52.4 30.49,33.15 49.48,21.37C60.1,14.76 72.16,10.39 84.58,8.82M89.44,64.58C80.72,66.28 73.17,72.14 68.48,79.58C64.15,86.48 62.98,95.1 64.68,103.01C66.42,111.3 71.95,118.48 78.94,123.11C86.22,127.94 95.59,129.19 104.01,127.08C111.9,125.14 118.67,119.75 123.12,113.04C127.97,105.73 129.19,96.33 127.06,87.89C125.02,79.82 119.43,72.92 112.46,68.51C105.69,64.23 97.24,63.04 89.44,64.58Z\" />\n    <path\n        android:fillColor=\"#f44336\"\n        android:pathData=\"M89.44,64.58C97.24,63.04 105.69,64.23 112.46,68.51C119.43,72.92 125.02,79.82 127.06,87.89C129.19,96.33 127.97,105.73 123.12,113.04C118.67,119.75 111.9,125.14 104.01,127.08C95.59,129.19 86.22,127.94 78.94,123.11C71.95,118.48 66.42,111.3 64.68,103.01C62.98,95.1 64.15,86.48 68.48,79.58C73.17,72.14 80.72,66.28 89.44,64.58Z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_snowflake.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"?attr/colorControlNormal\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M20.79,13.95L18.46,14.57L16.46,13.44V10.56L18.46,9.43L20.79,10.05L21.31,8.12L19.54,7.65L20,5.88L18.07,5.36L17.45,7.69L15.45,8.82L13,7.38V5.12L14.71,3.41L13.29,2L12,3.29L10.71,2L9.29,3.41L11,5.12V7.38L8.5,8.82L6.5,7.69L5.92,5.36L4,5.88L4.47,7.65L2.7,8.12L3.22,10.05L5.55,9.43L7.55,10.56V13.45L5.55,14.58L3.22,13.96L2.7,15.89L4.47,16.36L4,18.12L5.93,18.64L6.55,16.31L8.55,15.18L11,16.62V18.88L9.29,20.59L10.71,22L12,20.71L13.29,22L14.7,20.59L13,18.88V16.62L15.5,15.17L17.5,16.3L18.12,18.63L20,18.12L19.53,16.35L21.3,15.88L20.79,13.95M9.5,10.56L12,9.11L14.5,10.56V13.44L12,14.89L9.5,13.44V10.56Z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_snowflake_off.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"?attr/colorControlNormal\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M11,5.12L9.29,3.41L10.71,2L12,3.29L13.29,2L14.71,3.41L13,5.12V7.38L15.45,8.82L17.45,7.69L18.07,5.36L20,5.88L19.54,7.65L21.31,8.12L20.79,10.05L18.46,9.43L16.46,10.56V13.26L14.5,11.3V10.56L12.74,9.54L10.73,7.53L11,7.38V5.12M18.46,14.57L16.87,13.67L19.55,16.35L21.3,15.88L20.79,13.95L18.46,14.57M13,16.62V18.88L14.7,20.59L13.29,22L12,20.71L10.71,22L9.29,20.59L11,18.88V16.62L8.55,15.18L6.55,16.31L5.93,18.64L4,18.12L4.47,16.36L2.7,15.89L3.22,13.96L5.55,14.58L7.55,13.45V10.56L5.55,9.43L3.22,10.05L2.7,8.12L4.47,7.65L4,5.89L1.11,3L2.39,1.73L22.11,21.46L20.84,22.73L14.1,16L13,16.62M12,14.89L12.63,14.5L9.5,11.39V13.44L12,14.89Z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_sort.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"?attr/colorControlNormal\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M3,18h6v-2L3,16v2zM3,6v2h18L21,6L3,6zM3,13h12v-2L3,11v2z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_splash_logo.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<layer-list xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:drawable=\"@color/ic_launcher_background\"/>\n    <item android:drawable=\"@drawable/ic_launcher_foreground\"/>\n</layer-list>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_star.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:tint=\"?attr/colorControlNormal\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M12,17.27L18.18,21L16.54,13.97L22,9.24L14.81,8.62L12,2L9.19,8.62L2,9.24L7.45,13.97L5.82,21L12,17.27Z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_star_outline.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:tint=\"?attr/colorControlNormal\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M12,15.39L8.24,17.66L9.23,13.38L5.91,10.5L10.29,10.13L12,6.09L13.71,10.13L18.09,10.5L14.77,13.38L15.76,17.66M22,9.24L14.81,8.63L12,2L9.19,8.63L2,9.24L7.45,13.97L5.82,21L12,17.27L18.18,21L16.54,13.97L22,9.24Z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_stop.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportHeight=\"24\"\n    android:viewportWidth=\"24\"\n    android:tint=\"?attr/colorControlNormal\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M6,6h12v12H6z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_sync.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"?attr/colorControlNormal\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M12,4L12,1L8,5l4,4L12,6c3.31,0 6,2.69 6,6 0,1.01 -0.25,1.97 -0.7,2.8l1.46,1.46C19.54,15.03 20,13.57 20,12c0,-4.42 -3.58,-8 -8,-8zM12,18c-3.31,0 -6,-2.69 -6,-6 0,-1.01 0.25,-1.97 0.7,-2.8L5.24,7.74C4.46,8.97 4,10.43 4,12c0,4.42 3.58,8 8,8v3l4,-4 -4,-4v3z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_tab.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"?attr/colorControlNormal\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M21,3L3,3c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h18c1.1,0 2,-0.9 2,-2L23,5c0,-1.1 -0.9,-2 -2,-2zM21,19L3,19L3,5h10v4h8v10z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_table.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"?attr/colorControlNormal\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M5,4H19A2,2 0,0 1,21 6V18A2,2 0,0 1,19 20H5A2,2 0,0 1,3 18V6A2,2 0,0 1,5 4M5,8V12H11V8H5M13,8V12H19V8H13M5,14V18H11V14H5M13,14V18H19V14H13Z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_touch_app.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"?attr/colorControlNormal\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M9,11.24V7.5C9,6.12 10.12,5 11.5,5S14,6.12 14,7.5v3.74c1.21,-0.81 2,-2.18 2,-3.74C16,5.01 13.99,3 11.5,3S7,5.01 7,7.5C7,9.06 7.79,10.43 9,11.24zM18.84,15.87l-4.54,-2.26c-0.17,-0.07 -0.35,-0.11 -0.54,-0.11H13v-6C13,6.67 12.33,6 11.5,6S10,6.67 10,7.5v10.74c-3.6,-0.76 -3.54,-0.75 -3.67,-0.75c-0.31,0 -0.59,0.13 -0.79,0.33l-0.79,0.8l4.94,4.94C9.96,23.83 10.34,24 10.75,24h6.79c0.75,0 1.33,-0.55 1.44,-1.28l0.75,-5.27c0.01,-0.07 0.02,-0.14 0.02,-0.2C19.75,16.63 19.37,16.09 18.84,15.87z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_transit_connection.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"?attr/colorControlNormal\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M18,11H14.82C14.4,9.84 13.3,9 12,9C10.7,9 9.6,9.84 9.18,11H6C5.67,11 4,10.9 4,9V8C4,6.17 5.54,6 6,6H16.18C16.6,7.16 17.7,8 19,8A3,3 0,0 0,22 5A3,3 0,0 0,19 2C17.7,2 16.6,2.84 16.18,4H6C4.39,4 2,5.06 2,8V9C2,11.94 4.39,13 6,13H9.18C9.6,14.16 10.7,15 12,15C13.3,15 14.4,14.16 14.82,13H18C18.33,13 20,13.1 20,15V16C20,17.83 18.46,18 18,18H7.82C7.4,16.84 6.3,16 5,16A3,3 0,0 0,2 19A3,3 0,0 0,5 22C6.3,22 7.4,21.16 7.82,20H18C19.61,20 22,18.93 22,16V15C22,12.07 19.61,11 18,11M19,4A1,1 0,0 1,20 5A1,1 0,0 1,19 6A1,1 0,0 1,18 5A1,1 0,0 1,19 4M5,20A1,1 0,0 1,4 19A1,1 0,0 1,5 18A1,1 0,0 1,6 19A1,1 0,0 1,5 20Z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_translate.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"?attr/colorControlNormal\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M12.87,15.07L10.33,12.56L10.36,12.53C12.1,10.59 13.34,8.36 14.07,6H17V4H10V2H8V4H1V6H12.17C11.5,7.92 10.44,9.75 9,11.35C8.07,10.32 7.3,9.19 6.69,8H4.69C5.42,9.63 6.42,11.17 7.67,12.56L2.58,17.58L4,19L9,14L12.11,17.11L12.87,15.07M18.5,10H16.5L12,22H14L15.12,19H19.87L21,22H23L18.5,10M15.88,17L17.5,12.67L19.12,17H15.88Z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_trash_can.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"?attr/colorControlNormal\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M9,3V4H4V6H5V19A2,2 0,0 0,7 21H17A2,2 0,0 0,19 19V6H20V4H15V3H9M7,6H17V19H7V6M9,8V17H11V8H9M13,8V17H15V8H13Z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_tune.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"?attr/colorControlNormal\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M3,17v2h6v-2L3,17zM3,5v2h10L13,5L3,5zM13,21v-2h8v-2h-8v-2h-2v6h2zM7,9v2L3,11v2h4v2h2L9,9L7,9zM21,13v-2L11,11v2h10zM15,9h2L17,7h4L21,5h-4L17,3h-2v6z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_undo.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"?attr/colorControlNormal\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M12.5,8c-2.65,0 -5.05,0.99 -6.9,2.6L2,7v9h9l-3.62,-3.62c1.39,-1.16 3.16,-1.88 5.12,-1.88 3.54,0 6.55,2.31 7.6,5.5l2.37,-0.78C21.08,11.03 17.15,8 12.5,8z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_unlock.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"?attr/colorControlNormal\">\n  <path\n      android:fillColor=\"@android:color/white\"\n      android:pathData=\"M10,13C11.1,13 12,13.89 12,15C12,16.11 11.11,17 10,17S8,16.11 8,15 8.9,13 10,13M18,1C15.24,1 13,3.24 13,6V8H4C2.9,8 2,8.9 2,10V20C2,21.1 2.9,22 4,22H16C17.1,22 18,21.1 18,20V10C18,8.9 17.1,8 16,8H15V6C15,4.34 16.34,3 18,3S21,4.34 21,6V8H23V6C23,3.24 20.76,1 18,1M16,10V20H4V10H16Z\"/>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_video_file.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"?attr/colorControlNormal\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M14,2H6C4.9,2 4,2.9 4,4v16c0,1.1 0.9,2 2,2h12c1.1,0 2,-0.9 2,-2V8L14,2zM6,20V4h7v5h5v11H6zM14,14l2,-1.06v4.12L14,16v1c0,0.55 -0.45,1 -1,1H9c-0.55,0 -1,-0.45 -1,-1v-4c0,-0.55 0.45,-1 1,-1h4c0.55,0 1,0.45 1,1V14z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_view_agenda.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportHeight=\"24\"\n    android:viewportWidth=\"24\"\n    android:tint=\"?attr/colorControlNormal\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M20,13L3,13c-0.55,0 -1,0.45 -1,1v6c0,0.55 0.45,1 1,1h17c0.55,0 1,-0.45 1,-1v-6c0,-0.55 -0.45,-1 -1,-1zM20,3L3,3c-0.55,0 -1,0.45 -1,1v6c0,0.55 0.45,1 1,1h17c0.55,0 1,-0.45 1,-1L21,4c0,-0.55 -0.45,-1 -1,-1z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_view_list.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"?attr/colorControlNormal\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M4,14h4v-4L4,10v4zM4,19h4v-4L4,15v4zM4,9h4L8,5L4,5v4zM9,14h12v-4L9,10v4zM9,19h12v-4L9,15v4zM9,5v4h12L21,5L9,5z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_vt.xml",
    "content": "<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"21.36dp\"\n    android:viewportWidth=\"100\"\n    android:viewportHeight=\"89\"\n    android:tint=\"?attr/colorControlNormal\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M45.292,44.5L0,89h100V0H0l45.292,44.5zM90,80H22l35.987,-35.2L22,9h68v71z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_wifi.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"?attr/colorControlNormal\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M1,9l2,2c4.97,-4.97 13.03,-4.97 18,0l2,-2C16.93,2.93 7.08,2.93 1,9zM9,17l3,3 3,-3c-1.65,-1.66 -4.34,-1.66 -6,0zM5,13l2,2c2.76,-2.76 7.24,-2.76 10,0l2,-2C15.14,9.14 8.87,9.14 5,13z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_wrap_text.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"?attr/colorControlNormal\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M4,19h6v-2L4,17v2zM20,5L4,5v2h16L20,5zM17,11L4,11v2h13.25c1.1,0 2,0.9 2,2s-0.9,2 -2,2L15,17v-2l-3,3 3,3v-2h2c2.21,0 4,-1.79 4,-4s-1.79,-4 -4,-4z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ic_zip_disk.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"?attr/colorControlNormal\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M7,3L3,5V19A2,2 0,0 0,5 21H19A2,2 0,0 0,21 19V5L17,3V5A1,1 0,0 1,16 6H10A1,1 0,0 1,9 5V3H7M8,10H16A1,1 0,0 1,17 11V19H7V11A1,1 0,0 1,8 10Z\" />\n</vector>\n"
  },
  {
    "path": "app/src/main/res/drawable/ripple_background_24.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<layer-list xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item\n        android:width=\"24dp\"\n        android:height=\"24dp\"\n        android:drawable=\"?android:attr/selectableItemBackgroundBorderless\"\n        android:gravity=\"center\" />\n</layer-list>\n"
  },
  {
    "path": "app/src/main/res/drawable-anydpi-v24/ic_default_notification.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later OR CC-BY-SA-4.0 -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"108\"\n    android:viewportHeight=\"108\"\n    android:tint=\"#FFFFFF\">\n  <group android:scaleX=\"0.92\"\n      android:scaleY=\"0.92\"\n      android:translateX=\"4.32\"\n      android:translateY=\"4.32\">\n    <path\n        android:pathData=\"m49.76,17.96c-0.2,1.58 -1.1,5.66 -1.63,8.13 -0.49,2.47 -1.67,5.9 -2.52,9.27 -0.81,3.32 -1.96,7.03 -3.46,11.12 -1.5,4.09 -3.22,8.3 -5.17,12.64 -1.94,4.29 -4.44,8.91 -7.47,13.85 -3,4.9 -6.3,9.62 -9.9,14.16 -1.62,2.03 -3.3,3.93 -5.04,5.71 -4.35,4.53 -7.42,7.31 -14.09,12.97 -2.41,2.57 5.25,-0.3 6.89,-1.08 3.79,-1.81 4.45,-2.22 7.7,-4.44 3,-2.31 5.81,-5.05 7.17,-6.35 1.5,-1.42 3.85,-4.09 7.05,-8.02 7.25,-3.61 23.1,-6.48 31.48,-6.24 13.43,0.34 18.96,3.34 23.12,11.46 0.93,2.11 2.06,4.52 3.08,6.75 1.05,2.23 2.31,4.27 3.77,6.14 1.5,1.9 2.9,2.86 4.19,2.86 1.26,0 2.98,-0.63 5.17,-1.88 2.19,-1.22 4.11,-2.57 5.77,-4.07 1.7,-1.46 2.17,-2.31 2.17,-3 0,-0.2 -0.06,-0.34 -0.18,-0.43 -0.08,-0.08 -0.22,-0.1 -0.43,-0.06 -0.16,0 -0.34,0.02 -0.55,0.06 -0.2,0.04 -0.05,-0.12 -0.29,-0.04 -0.2,0.04 -0.38,0.06 -0.55,0.06 -1.94,0 -4.44,-2.37 -7.47,-7.11 -3,-4.78 -6.18,-10.9 -9.54,-18.35 -3.32,-7.45 -6.64,-15.07 -9.97,-22.85 -3.28,-7.78 -7,-15.18 -10.41,-22.63 -3.4,-7.45 -6.22,-12.86 -8.45,-16.23 -1.91,-2.94 -6.26,-11.52 -8.04,-8.66 -0.93,6.82 -0.82,6.53 -2.38,16.27zM57.15,30.86c-0.19,0.31 3.59,6.93 9.66,20.78 6.08,13.85 9.11,21 9.11,21.45l-0.12,0.06c-0.12,0 -0.73,-0.1 -1.82,-0.3 -1.09,-0.24 -2.59,-0.49 -4.5,-0.73 -1.9,-0.24 -3.91,-0.36 -6.02,-0.36 -9.52,0 -19.14,2.37 -28.86,7.11 3.28,-4.46 6.28,-9.16 8.99,-14.1 2.75,-4.94 4.9,-9.34 6.44,-13.19 1.58,-3.85 2.9,-7.39 3.95,-10.63 1.09,-3.24 1.86,-5.73 2.31,-7.47 0.49,-1.74 0.89,-2.68 0.85,-2.61z\"\n        android:strokeWidth=\"3.1112\"\n        android:fillColor=\"#dcaf74\"/>\n  </group>\n</vector>\n"
  },
  {
    "path": "app/src/main/res/layout/activity_app_details.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-or-later -->\n<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    tools:context=\".details.AppDetailsActivity\">\n\n    <io.github.muntashirakon.widget.AppBarLayout\n        android:id=\"@+id/appbar\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:fitsSystemWindows=\"true\"\n        app:liftOnScroll=\"true\"\n        app:liftOnScrollTargetViewId=\"@id/scrollView\">\n\n        <androidx.appcompat.widget.Toolbar\n            android:id=\"@+id/toolbar\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"?attr/actionBarSize\" />\n\n    </io.github.muntashirakon.widget.AppBarLayout>\n\n    <androidx.appcompat.widget.LinearLayoutCompat\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:orientation=\"vertical\"\n        app:layout_behavior=\"com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior\">\n\n        <com.google.android.material.tabs.TabLayout\n            android:id=\"@+id/tab_layout\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:fitsSystemWindows=\"true\"\n            app:tabMode=\"scrollable\" />\n\n        <androidx.viewpager2.widget.ViewPager2\n            android:id=\"@+id/pager\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\" />\n\n    </androidx.appcompat.widget.LinearLayoutCompat>\n\n</androidx.coordinatorlayout.widget.CoordinatorLayout>"
  },
  {
    "path": "app/src/main/res/layout/activity_app_usage.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    tools:context=\".usage.AppUsageActivity\">\n\n    <include layout=\"@layout/appbar\" />\n\n    <io.github.muntashirakon.widget.SwipeRefreshLayout\n        android:id=\"@+id/swipe_refresh\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        app:layout_behavior=\"com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior\">\n\n        <androidx.appcompat.widget.LinearLayoutCompat\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:orientation=\"vertical\">\n\n            <io.github.muntashirakon.widget.MaterialSpinner\n                android:id=\"@+id/spinner\"\n                style=\"@style/Widget.AppTheme.MaterialSpinner.Spinner.Small\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_gravity=\"center_vertical|start\"\n                android:layout_marginHorizontal=\"@dimen/padding_large\"\n                android:layout_marginVertical=\"@dimen/padding_small\"\n                android:fitsSystemWindows=\"true\"\n                android:nextFocusDown=\"@id/recycler_view\"\n                tools:hint=\"Interval\" />\n\n            <FrameLayout\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"match_parent\">\n\n                <io.github.muntashirakon.widget.RecyclerView\n                    android:id=\"@+id/scrollView\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:fitsSystemWindows=\"true\"\n                    app:fastScrollerEnabled=\"true\"\n                    tools:listitem=\"@layout/item_app_usage\" />\n\n                <com.google.android.material.textview.MaterialTextView\n                    android:id=\"@android:id/empty\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"match_parent\"\n                    android:focusable=\"false\"\n                    android:gravity=\"center\"\n                    android:text=\"@string/no_usage_in_this_time_range\"\n                    tools:visibility=\"visible\" />\n\n            </FrameLayout>\n\n        </androidx.appcompat.widget.LinearLayoutCompat>\n\n    </io.github.muntashirakon.widget.SwipeRefreshLayout>\n\n</androidx.coordinatorlayout.widget.CoordinatorLayout>"
  },
  {
    "path": "app/src/main/res/layout/activity_apps_profile.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    tools:context=\".profiles.AppsProfileActivity\">\n\n    <include layout=\"@layout/appbar\" />\n\n    <androidx.appcompat.widget.LinearLayoutCompat\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:orientation=\"vertical\"\n        app:layout_behavior=\"com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior\">\n\n        <androidx.viewpager2.widget.ViewPager2\n            android:id=\"@+id/pager\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_weight=\"1\" />\n\n        <com.google.android.material.bottomnavigation.BottomNavigationView\n            android:id=\"@+id/bottom_navigation\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            app:menu=\"@menu/activity_profile_navigation\" />\n\n    </androidx.appcompat.widget.LinearLayoutCompat>\n\n    <com.google.android.material.floatingactionbutton.FloatingActionButton\n        android:id=\"@+id/floatingActionButton\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginHorizontal=\"@dimen/padding_medium\"\n        android:layout_marginBottom=\"72dp\"\n        android:accessibilityTraversalBefore=\"@id/pager\"\n        android:clickable=\"true\"\n        android:contentDescription=\"@string/add_item\"\n        android:fitsSystemWindows=\"true\"\n        android:focusable=\"true\"\n        android:src=\"@drawable/ic_add\"\n        app:layout_anchor=\"@id/bottom_navigation\"\n        app:layout_anchorGravity=\"right|top\"\n        app:layout_behavior=\"com.google.android.material.behavior.HideBottomViewOnScrollBehavior\"\n        tools:targetApi=\"22\" />\n\n</androidx.coordinatorlayout.widget.CoordinatorLayout>"
  },
  {
    "path": "app/src/main/res/layout/activity_audio_player.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    tools:context=\".viewer.audio.AudioPlayerActivity\">\n\n</androidx.coordinatorlayout.widget.CoordinatorLayout>"
  },
  {
    "path": "app/src/main/res/layout/activity_auth_management.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    tools:context=\".crypto.auth.AuthManagerActivity\">\n\n    <include layout=\"@layout/appbar\" />\n\n    <io.github.muntashirakon.widget.NestedScrollView\n        android:id=\"@+id/scrollView\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:scrollbars=\"vertical\"\n        android:fitsSystemWindows=\"true\"\n        android:clipToPadding=\"false\"\n        app:layout_behavior=\"com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior\">\n\n        <androidx.appcompat.widget.LinearLayoutCompat\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:layout_gravity=\"center_vertical\"\n            android:paddingTop=\"@dimen/padding_small\"\n            android:paddingBottom=\"@dimen/padding_small\"\n            android:paddingStart=\"@dimen/padding_medium\"\n            android:paddingEnd=\"@dimen/padding_medium\"\n            android:orientation=\"vertical\">\n\n            <androidx.appcompat.widget.AppCompatTextView\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:text=\"@string/auth_manager_description\" />\n\n            <com.google.android.material.textfield.TextInputLayout\n                android:id=\"@+id/auth_field\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                app:endIconMode=\"custom\"\n                app:endIconDrawable=\"@drawable/ic_autorenew\">\n\n                <io.github.muntashirakon.widget.TextInputTextView\n                    android:id=\"@android:id/text1\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:textSize=\"25sp\"\n                    android:inputType=\"none\"\n                    android:textIsSelectable=\"true\"\n                    tools:text=\"@tools:sample/full_names\" />\n\n            </com.google.android.material.textfield.TextInputLayout>\n\n        </androidx.appcompat.widget.LinearLayoutCompat>\n\n    </io.github.muntashirakon.widget.NestedScrollView>\n\n</androidx.coordinatorlayout.widget.CoordinatorLayout>"
  },
  {
    "path": "app/src/main/res/layout/activity_authentication.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<androidx.appcompat.widget.LinearLayoutCompat xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:fitsSystemWindows=\"true\"\n    android:orientation=\"vertical\"\n    android:weightSum=\"2\"\n    tools:context=\".main.SplashActivity\">\n\n    <RelativeLayout\n        android:id=\"@+id/layout_top\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"0dp\"\n        android:layout_weight=\"1\">\n\n        <androidx.appcompat.widget.AppCompatImageView\n            android:id=\"@+id/icon\"\n            android:layout_width=\"48dp\"\n            android:layout_height=\"48dp\"\n            android:layout_centerInParent=\"true\"\n            android:minWidth=\"176dp\"\n            app:srcCompat=\"@mipmap/ic_launcher_round\" />\n\n        <androidx.appcompat.widget.AppCompatTextView\n            android:id=\"@+id/title\"\n            style=\"@style/TextAppearance.AppTheme.TitleLarge\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_below=\"@id/icon\"\n            android:layout_centerHorizontal=\"true\"\n            android:layout_marginTop=\"@dimen/padding_small\"\n            android:layout_marginBottom=\"@dimen/padding_very_small\"\n            android:text=\"@string/app_name\"\n            android:textAlignment=\"center\" />\n\n        <com.google.android.material.textview.MaterialTextView\n            android:id=\"@+id/state_name\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_below=\"@id/title\"\n            android:layout_centerHorizontal=\"true\"\n            android:textAlignment=\"center\"\n            android:text=\"@string/authenticating\" />\n    </RelativeLayout>\n\n    <com.google.android.material.textview.MaterialTextView\n        android:id=\"@+id/version\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"0dp\"\n        android:layout_weight=\"1\"\n        android:gravity=\"center_horizontal|bottom\"\n        android:padding=\"@dimen/padding_large\"\n        android:textAlignment=\"center\"\n        tools:text=\"Version 2.7.0\" />\n</androidx.appcompat.widget.LinearLayoutCompat>"
  },
  {
    "path": "app/src/main/res/layout/activity_batch_ops_results.xml",
    "content": "<!-- SPDX-License-Identifier: WTFPL AND GPL-3.0-or-later -->\n<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    tools:context=\".batchops.BatchOpsResultsActivity\">\n\n    <include layout=\"@layout/appbar\" />\n\n    <io.github.muntashirakon.widget.NestedScrollView\n        android:id=\"@+id/scrollView\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:fitsSystemWindows=\"true\"\n        android:clipToPadding=\"false\"\n        android:scrollbars=\"vertical\"\n        app:layout_behavior=\"com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior\">\n\n        <androidx.appcompat.widget.LinearLayoutCompat\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:orientation=\"vertical\">\n\n            <androidx.recyclerview.widget.RecyclerView\n                android:id=\"@+id/list\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:overScrollMode=\"never\"\n                tools:listitem=\"@android:layout/simple_list_item_1\" />\n\n            <com.google.android.material.button.MaterialButton\n                android:id=\"@+id/action_view_logs\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_gravity=\"end\"\n                android:layout_marginHorizontal=\"@dimen/padding_medium\"\n                android:text=\"@string/view_logs\" />\n\n            <androidx.appcompat.widget.AppCompatEditText\n                android:id=\"@+id/text\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:fontFamily=\"monospace\"\n                android:gravity=\"top\"\n                android:padding=\"@dimen/padding_small\"\n                android:textSize=\"@dimen/font_size_medium\"\n                android:textIsSelectable=\"true\"\n                android:visibility=\"gone\"\n                android:background=\"@null\"\n                tools:visibility=\"visible\"\n                tools:text=\"@tools:sample/lorem/random\" />\n\n\n        </androidx.appcompat.widget.LinearLayoutCompat>\n\n    </io.github.muntashirakon.widget.NestedScrollView>\n\n</androidx.coordinatorlayout.widget.CoordinatorLayout>"
  },
  {
    "path": "app/src/main/res/layout/activity_code_editor.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    tools:context=\".editor.CodeEditorActivity\">\n\n    <io.github.muntashirakon.widget.AppBarLayout\n        android:id=\"@+id/appbar\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:fitsSystemWindows=\"true\"\n        app:liftOnScroll=\"true\"\n        app:liftOnScrollTargetViewId=\"@id/editor\">\n\n        <com.google.android.material.appbar.MaterialToolbar\n            android:id=\"@+id/toolbar\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"?attr/actionBarSize\"\n            tools:menu=\"@menu/activity_code_editor_actions\" />\n\n        <com.google.android.material.progressindicator.LinearProgressIndicator\n            android:id=\"@+id/progress_linear\"\n            style=\"@style/Widget.AppTheme.LinearProgressIndicator\"\n            android:indeterminate=\"true\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\" />\n\n    </io.github.muntashirakon.widget.AppBarLayout>\n\n    <androidx.fragment.app.FragmentContainerView\n        android:id=\"@+id/container\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:fitsSystemWindows=\"true\"\n        android:orientation=\"vertical\"\n        app:layout_behavior=\"com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior\">\n\n    </androidx.fragment.app.FragmentContainerView>\n\n</androidx.coordinatorlayout.widget.CoordinatorLayout>"
  },
  {
    "path": "app/src/main/res/layout/activity_debloater.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:id=\"@+id/coordinator_layout\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    tools:context=\".debloat.DebloaterActivity\">\n\n    <io.github.muntashirakon.widget.AppBarLayout\n        android:id=\"@+id/appbar\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:fitsSystemWindows=\"true\"\n        app:liftOnScroll=\"true\"\n        app:liftOnScrollTargetViewId=\"@+id/recycler_view\">\n\n        <com.google.android.material.appbar.MaterialToolbar\n            android:id=\"@+id/toolbar\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"?attr/actionBarSize\"\n            app:navigationIcon=\"@null\"\n            tools:menu=\"@menu/activity_main_actions\" />\n\n        <com.google.android.material.progressindicator.LinearProgressIndicator\n            android:id=\"@+id/progress_linear\"\n            style=\"@style/Widget.AppTheme.LinearProgressIndicator\"\n            android:indeterminate=\"true\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\" />\n\n    </io.github.muntashirakon.widget.AppBarLayout>\n\n    <io.github.muntashirakon.widget.RecyclerView\n        android:id=\"@+id/recycler_view\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:scrollbars=\"none\"\n        android:focusable=\"false\"\n        android:clipToPadding=\"false\"\n        android:fitsSystemWindows=\"true\"\n        app:fastScrollerEnabled=\"true\"\n        app:layout_behavior=\"com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior\"\n        tools:listitem=\"@layout/item_main\" />\n\n    <io.github.muntashirakon.widget.MultiSelectionView\n        android:id=\"@+id/selection_view\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:fitsSystemWindows=\"true\"\n        android:focusable=\"false\"\n        app:menu=\"@menu/activity_debloater_selection_actions\" />\n\n</androidx.coordinatorlayout.widget.CoordinatorLayout>"
  },
  {
    "path": "app/src/main/res/layout/activity_finder.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    tools:context=\".usage.AppUsageActivity\">\n\n    <io.github.muntashirakon.widget.AppBarLayout\n        android:id=\"@+id/appbar\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:fitsSystemWindows=\"true\"\n        app:liftOnScroll=\"true\"\n        app:liftOnScrollTargetViewId=\"@+id/item_list\">\n\n        <com.google.android.material.appbar.MaterialToolbar\n            android:id=\"@+id/toolbar\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"?attr/actionBarSize\"\n            app:navigationIcon=\"@null\"\n            tools:menu=\"@menu/activity_main_actions\" />\n\n        <com.google.android.material.progressindicator.LinearProgressIndicator\n            android:id=\"@+id/progress_linear\"\n            style=\"@style/Widget.AppTheme.LinearProgressIndicator\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:indeterminate=\"true\" />\n\n    </io.github.muntashirakon.widget.AppBarLayout>\n\n    <io.github.muntashirakon.widget.RecyclerView\n        android:id=\"@+id/item_list\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:clipToPadding=\"false\"\n        android:fitsSystemWindows=\"true\"\n        android:focusable=\"false\"\n        android:scrollbars=\"none\"\n        app:fastScrollerEnabled=\"true\"\n        app:layout_behavior=\"com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior\"\n        tools:listitem=\"@layout/item_main\" />\n\n    <com.google.android.material.floatingactionbutton.FloatingActionButton\n        android:id=\"@+id/floatingActionButton\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"bottom|end\"\n        android:layout_margin=\"@dimen/padding_medium\"\n        android:accessibilityTraversalBefore=\"@id/item_list\"\n        android:clickable=\"true\"\n        android:contentDescription=\"@string/filter\"\n        android:fitsSystemWindows=\"true\"\n        android:focusable=\"true\"\n        android:src=\"@drawable/ic_filter_menu\"\n        app:layout_behavior=\"com.google.android.material.behavior.HideBottomViewOnScrollBehavior\"\n        tools:targetApi=\"22\" />\n\n    <io.github.muntashirakon.widget.MultiSelectionView\n        android:id=\"@+id/selection_view\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:fitsSystemWindows=\"true\"\n        android:focusable=\"false\"\n        app:menu=\"@menu/activity_main_selection_actions\" />\n\n</androidx.coordinatorlayout.widget.CoordinatorLayout>"
  },
  {
    "path": "app/src/main/res/layout/activity_fm.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<androidx.drawerlayout.widget.DrawerLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:id=\"@+id/drawer_layout\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    tools:context=\".fm.FmActivity\"\n    tools:openDrawer=\"start\">\n\n    <androidx.coordinatorlayout.widget.CoordinatorLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\">\n\n        <io.github.muntashirakon.widget.AppBarLayout\n            android:id=\"@+id/appbar\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:fitsSystemWindows=\"true\"\n            app:liftOnScroll=\"true\"\n            app:liftOnScrollTargetViewId=\"@+id/list_item\">\n\n            <com.google.android.material.appbar.MaterialToolbar\n                android:id=\"@+id/toolbar\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"?attr/actionBarSize\"\n                tools:menu=\"@menu/activity_fm_actions\" />\n\n            <com.google.android.material.progressindicator.LinearProgressIndicator\n                android:id=\"@+id/progress_linear\"\n                style=\"@style/Widget.AppTheme.LinearProgressIndicator\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:indeterminate=\"true\" />\n\n        </io.github.muntashirakon.widget.AppBarLayout>\n\n        <androidx.fragment.app.FragmentContainerView\n            android:id=\"@+id/main_layout\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            app:layout_behavior=\"com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior\" />\n\n    </androidx.coordinatorlayout.widget.CoordinatorLayout>\n\n    <FrameLayout\n        android:id=\"@+id/side_nav\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"match_parent\"\n        android:layout_gravity=\"start\"\n        android:background=\"?attr/colorSurfaceContainerLow\"\n        android:fitsSystemWindows=\"true\">\n\n        <androidx.recyclerview.widget.RecyclerView\n            android:id=\"@+id/recycler_view\"\n            android:layout_width=\"360dp\"\n            android:layout_height=\"match_parent\"\n            android:paddingHorizontal=\"12dp\"\n            tools:listitem=\"@layout/item_fm_drawer\" />\n    </FrameLayout>\n\n</androidx.drawerlayout.widget.DrawerLayout>"
  },
  {
    "path": "app/src/main/res/layout/activity_help.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    tools:context=\".misc.HelpActivity\">\n\n    <io.github.muntashirakon.widget.AppBarLayout\n        android:id=\"@+id/appbar\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:fitsSystemWindows=\"true\"\n        app:liftOnScroll=\"true\"\n        app:liftOnScrollTargetViewId=\"@id/webview\">\n\n        <com.google.android.material.appbar.MaterialToolbar\n            android:id=\"@+id/toolbar\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"?attr/actionBarSize\"\n            tools:menu=\"@menu/activity_help_actions\" />\n\n        <com.google.android.material.progressindicator.LinearProgressIndicator\n            android:id=\"@+id/progress_linear\"\n            style=\"@style/Widget.AppTheme.LinearProgressIndicator\"\n            android:indeterminate=\"true\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\" />\n\n    </io.github.muntashirakon.widget.AppBarLayout>\n\n    <androidx.appcompat.widget.LinearLayoutCompat\n        android:id=\"@+id/container\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:orientation=\"vertical\"\n        android:fitsSystemWindows=\"true\"\n        android:clipToPadding=\"false\"\n        app:layout_behavior=\"com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior\">\n\n        <androidx.appcompat.widget.LinearLayoutCompat\n            android:id=\"@+id/search_container\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:paddingHorizontal=\"@dimen/padding_medium\"\n            android:orientation=\"horizontal\"\n            android:visibility=\"gone\"\n            tools:visibility=\"visible\">\n\n            <androidx.appcompat.widget.SearchView\n                android:id=\"@+id/search_bar\"\n                android:layout_width=\"0dp\"\n                android:layout_height=\"wrap_content\"\n                android:layout_weight=\"1\"\n                app:iconifiedByDefault=\"false\" />\n\n            <com.google.android.material.button.MaterialButton\n                android:id=\"@+id/previous_button\"\n                style=\"@style/Widget.AppTheme.Button.IconButton\"\n                android:layout_width=\"40dp\"\n                android:layout_height=\"40dp\"\n                android:layout_gravity=\"center_vertical\"\n                app:icon=\"@drawable/ic_expand_less\"\n                app:iconSize=\"30dp\" />\n\n            <com.google.android.material.button.MaterialButton\n                android:id=\"@+id/next_button\"\n                style=\"@style/Widget.AppTheme.Button.IconButton\"\n                android:layout_width=\"40dp\"\n                android:layout_height=\"40dp\"\n                android:layout_gravity=\"center_vertical\"\n                app:icon=\"@drawable/ic_expand_more\"\n                app:iconSize=\"30dp\" />\n\n        </androidx.appcompat.widget.LinearLayoutCompat>\n\n        <me.zhanghai.android.fastscroll.FastScrollWebView\n            android:id=\"@+id/webview\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:clipToPadding=\"false\" />\n\n    </androidx.appcompat.widget.LinearLayoutCompat>\n\n</androidx.coordinatorlayout.widget.CoordinatorLayout>\n"
  },
  {
    "path": "app/src/main/res/layout/activity_interceptor.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-or-later -->\n<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    tools:context=\".intercept.ActivityInterceptor\">\n\n    <io.github.muntashirakon.widget.AppBarLayout\n        android:id=\"@+id/appbar\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:fitsSystemWindows=\"true\"\n        app:liftOnScroll=\"true\"\n        app:liftOnScrollTargetViewId=\"@id/scrollView\">\n\n        <com.google.android.material.appbar.MaterialToolbar\n            android:id=\"@+id/toolbar\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"?attr/actionBarSize\"\n            tools:menu=\"@menu/activity_activity_interceptor_actions\" />\n\n        <com.google.android.material.progressindicator.LinearProgressIndicator\n            android:id=\"@+id/progress_linear\"\n            style=\"@style/Widget.AppTheme.LinearProgressIndicator\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:indeterminate=\"true\" />\n\n    </io.github.muntashirakon.widget.AppBarLayout>\n\n    <io.github.muntashirakon.widget.NestedScrollView\n        android:id=\"@+id/scrollView\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:layout_weight=\"1\"\n        android:clipToPadding=\"false\"\n        android:fitsSystemWindows=\"true\"\n        android:paddingBottom=\"?attr/actionBarSize\"\n        app:fastScrollerEnabled=\"true\"\n        app:layout_behavior=\"com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior\">\n\n        <androidx.appcompat.widget.LinearLayoutCompat\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:orientation=\"vertical\"\n            android:paddingBottom=\"@dimen/padding_small\">\n\n            <com.google.android.material.textfield.TextInputLayout\n                style=\"@style/Widget.AppTheme.TextInputLayout.ExposedDropdownMenu\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:hint=\"@string/action\"\n                android:paddingStart=\"@dimen/padding_medium\"\n                android:paddingEnd=\"@dimen/padding_medium\"\n                app:hintAnimationEnabled=\"true\"\n                app:hintEnabled=\"true\">\n\n                <io.github.muntashirakon.widget.MaterialAutoCompleteTextView\n                    android:id=\"@+id/action_edit\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:inputType=\"textNoSuggestions\"\n                    android:maxLines=\"1\"\n                    tools:text=\"@tools:sample/full_names\" />\n\n            </com.google.android.material.textfield.TextInputLayout>\n\n            <com.google.android.material.textfield.TextInputLayout\n                style=\"@style/Widget.AppTheme.TextInputLayout.ExposedDropdownMenu\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:hint=\"@string/data\"\n                android:paddingStart=\"@dimen/padding_medium\"\n                android:paddingEnd=\"@dimen/padding_medium\"\n                app:hintAnimationEnabled=\"true\"\n                app:hintEnabled=\"true\">\n\n                <io.github.muntashirakon.widget.MaterialAutoCompleteTextView\n                    android:id=\"@+id/data_edit\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:inputType=\"textNoSuggestions|textMultiLine\"\n                    android:maxLines=\"3\"\n                    tools:text=\"@tools:sample/full_names\" />\n\n            </com.google.android.material.textfield.TextInputLayout>\n\n            <com.google.android.material.textfield.TextInputLayout\n                style=\"@style/Widget.AppTheme.TextInputLayout.ExposedDropdownMenu\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:hint=\"@string/mime_type\"\n                android:paddingStart=\"@dimen/padding_medium\"\n                android:paddingEnd=\"@dimen/padding_medium\"\n                app:hintAnimationEnabled=\"true\"\n                app:hintEnabled=\"true\">\n\n                <io.github.muntashirakon.widget.MaterialAutoCompleteTextView\n                    android:id=\"@+id/type_edit\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:inputType=\"textNoSuggestions\"\n                    android:maxLines=\"1\"\n                    tools:text=\"@tools:sample/full_names\" />\n\n            </com.google.android.material.textfield.TextInputLayout>\n\n            <com.google.android.material.textfield.TextInputLayout\n                style=\"@style/Widget.AppTheme.TextInputLayout.ExposedDropdownMenu\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:hint=\"@string/package_name\"\n                android:paddingStart=\"@dimen/padding_medium\"\n                android:paddingEnd=\"@dimen/padding_medium\"\n                app:hintAnimationEnabled=\"true\"\n                app:hintEnabled=\"true\">\n\n                <io.github.muntashirakon.widget.MaterialAutoCompleteTextView\n                    android:id=\"@+id/package_edit\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:inputType=\"textNoSuggestions\"\n                    android:maxLines=\"1\"\n                    tools:text=\"@tools:sample/full_names\" />\n\n            </com.google.android.material.textfield.TextInputLayout>\n\n            <com.google.android.material.textfield.TextInputLayout\n                style=\"@style/Widget.AppTheme.TextInputLayout.ExposedDropdownMenu\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:hint=\"@string/class_name\"\n                android:paddingStart=\"@dimen/padding_medium\"\n                android:paddingEnd=\"@dimen/padding_medium\"\n                app:hintAnimationEnabled=\"true\"\n                app:hintEnabled=\"true\">\n\n                <io.github.muntashirakon.widget.MaterialAutoCompleteTextView\n                    android:id=\"@+id/class_edit\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:inputType=\"textNoSuggestions\"\n                    android:maxLines=\"1\"\n                    tools:text=\"@tools:sample/full_names\" />\n\n            </com.google.android.material.textfield.TextInputLayout>\n\n            <androidx.appcompat.widget.LinearLayoutCompat\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:orientation=\"horizontal\"\n                android:paddingStart=\"@dimen/padding_medium\"\n                android:paddingEnd=\"@dimen/padding_medium\">\n\n                <com.google.android.material.textfield.TextInputLayout\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_weight=\"1\"\n                    android:hint=\"@string/user_id\"\n                    app:hintAnimationEnabled=\"true\"\n                    app:hintEnabled=\"true\">\n\n                    <com.google.android.material.textfield.TextInputEditText\n                        android:id=\"@+id/user_id_edit\"\n                        android:layout_width=\"match_parent\"\n                        android:layout_height=\"wrap_content\"\n                        android:inputType=\"textNoSuggestions\"\n                        android:maxLines=\"1\"\n                        tools:text=\"@tools:sample/full_names\" />\n\n                </com.google.android.material.textfield.TextInputLayout>\n\n                <com.google.android.material.checkbox.MaterialCheckBox\n                    android:id=\"@+id/use_root\"\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:text=\"@string/user_root\" />\n\n            </androidx.appcompat.widget.LinearLayoutCompat>\n\n            <com.google.android.material.textfield.TextInputLayout\n                android:id=\"@+id/type_id_layout\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:hint=\"@string/identifier\"\n                android:paddingStart=\"@dimen/padding_medium\"\n                android:paddingEnd=\"@dimen/padding_medium\"\n                app:endIconDrawable=\"@drawable/ic_autorenew\"\n                app:endIconMode=\"custom\"\n                app:hintAnimationEnabled=\"true\"\n                app:endIconContentDescription=\"@string/change_id\"\n                app:hintEnabled=\"true\">\n\n                <com.google.android.material.textfield.TextInputEditText\n                    android:id=\"@+id/type_id\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:inputType=\"textNoSuggestions\"\n                    android:maxLines=\"1\"\n                    tools:text=\"@tools:sample/full_names\" />\n\n            </com.google.android.material.textfield.TextInputLayout>\n\n            <com.google.android.material.textfield.TextInputLayout\n                style=\"@style/Widget.AppTheme.TextInputLayout.ExposedDropdownMenu\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:hint=\"@string/uri\"\n                android:paddingStart=\"@dimen/padding_medium\"\n                android:paddingEnd=\"@dimen/padding_medium\"\n                app:hintAnimationEnabled=\"true\"\n                app:hintEnabled=\"true\">\n\n                <io.github.muntashirakon.widget.MaterialAutoCompleteTextView\n                    android:id=\"@+id/uri_edit\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:inputType=\"textNoSuggestions|textMultiLine\"\n                    android:maxLines=\"5\"\n                    tools:text=\"@tools:sample/full_names\" />\n\n            </com.google.android.material.textfield.TextInputLayout>\n\n            <androidx.appcompat.widget.LinearLayoutCompat\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_marginTop=\"@dimen/padding_small\"\n                android:orientation=\"horizontal\"\n                android:paddingStart=\"@dimen/padding_medium\"\n                android:paddingEnd=\"@dimen/padding_medium\">\n\n                <com.google.android.material.textview.MaterialTextView\n                    android:id=\"@+id/intent_categories_header\"\n                    android:layout_width=\"0dp\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_gravity=\"center_vertical\"\n                    android:layout_weight=\"1\"\n                    android:focusable=\"false\"\n                    android:text=\"@string/category\"\n                    android:textAppearance=\"@style/TextAppearance.AppTheme.TitleMedium\"\n                    android:textColor=\"?attr/colorPrimary\" />\n\n                <com.google.android.material.button.MaterialButton\n                    android:id=\"@+id/intent_categories_add_btn\"\n                    style=\"@style/Widget.AppTheme.Button.IconButton\"\n                    android:layout_width=\"30dp\"\n                    android:layout_height=\"30dp\"\n                    android:layout_weight=\"0\"\n                    android:contentDescription=\"@string/add_item\"\n                    android:focusable=\"true\"\n                    app:icon=\"@drawable/ic_add\" />\n\n            </androidx.appcompat.widget.LinearLayoutCompat>\n\n            <androidx.recyclerview.widget.RecyclerView\n                android:id=\"@+id/intent_categories\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:overScrollMode=\"never\"\n                tools:listitem=\"@layout/m3_preference\" />\n\n            <androidx.appcompat.widget.LinearLayoutCompat\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_marginTop=\"@dimen/padding_small\"\n                android:orientation=\"horizontal\"\n                android:paddingStart=\"@dimen/padding_medium\"\n                android:paddingEnd=\"@dimen/padding_medium\">\n\n                <com.google.android.material.textview.MaterialTextView\n                    android:layout_width=\"0dp\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_gravity=\"center_vertical\"\n                    android:layout_weight=\"1\"\n                    android:focusable=\"false\"\n                    android:text=\"@string/flags\"\n                    android:textAppearance=\"@style/TextAppearance.AppTheme.TitleMedium\"\n                    android:textColor=\"?attr/colorPrimary\" />\n\n                <com.google.android.material.button.MaterialButton\n                    android:id=\"@+id/intent_flags_add_btn\"\n                    style=\"@style/Widget.AppTheme.Button.IconButton\"\n                    android:layout_width=\"30dp\"\n                    android:layout_height=\"30dp\"\n                    android:layout_weight=\"0\"\n                    android:contentDescription=\"@string/add_item\"\n                    android:focusable=\"true\"\n                    app:icon=\"@drawable/ic_add\" />\n\n            </androidx.appcompat.widget.LinearLayoutCompat>\n\n            <androidx.recyclerview.widget.RecyclerView\n                android:id=\"@+id/intent_flags\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:overScrollMode=\"never\"\n                tools:listitem=\"@layout/m3_preference\" />\n\n            <androidx.appcompat.widget.LinearLayoutCompat\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_marginTop=\"@dimen/padding_small\"\n                android:orientation=\"horizontal\"\n                android:paddingStart=\"@dimen/padding_medium\"\n                android:paddingEnd=\"@dimen/padding_medium\">\n\n                <com.google.android.material.textview.MaterialTextView\n                    android:layout_width=\"0dp\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_gravity=\"center_vertical\"\n                    android:layout_weight=\"1\"\n                    android:focusable=\"false\"\n                    android:text=\"@string/extras\"\n                    android:textAppearance=\"@style/TextAppearance.AppTheme.TitleMedium\"\n                    android:textColor=\"?attr/colorPrimary\" />\n\n                <com.google.android.material.button.MaterialButton\n                    android:id=\"@+id/intent_extras_add_btn\"\n                    style=\"@style/Widget.AppTheme.Button.IconButton\"\n                    android:layout_width=\"30dp\"\n                    android:layout_height=\"30dp\"\n                    android:layout_weight=\"0\"\n                    android:contentDescription=\"@string/add_item\"\n                    android:focusable=\"true\"\n                    app:icon=\"@drawable/ic_add\" />\n\n            </androidx.appcompat.widget.LinearLayoutCompat>\n\n            <androidx.recyclerview.widget.RecyclerView\n                android:id=\"@+id/intent_extras\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:overScrollMode=\"never\"\n                tools:listitem=\"@layout/item_app_details_secondary\" />\n\n            <com.google.android.material.textview.MaterialTextView\n                android:id=\"@+id/intent_matching_activities_header\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_marginTop=\"@dimen/padding_small\"\n                android:focusable=\"false\"\n                android:paddingStart=\"@dimen/padding_medium\"\n                android:paddingEnd=\"@dimen/padding_medium\"\n                android:text=\"@string/matching_activities\"\n                android:textAppearance=\"@style/TextAppearance.AppTheme.TitleMedium\"\n                android:textColor=\"?attr/colorPrimary\" />\n\n            <androidx.recyclerview.widget.RecyclerView\n                android:id=\"@+id/intent_matching_activities\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:overScrollMode=\"never\"\n                tools:listitem=\"@layout/item_icon_title_subtitle\" />\n\n        </androidx.appcompat.widget.LinearLayoutCompat>\n\n    </io.github.muntashirakon.widget.NestedScrollView>\n\n    <com.google.android.material.bottomappbar.BottomAppBar\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"bottom\"\n        android:fitsSystemWindows=\"true\"\n        android:minHeight=\"?attr/actionBarSize\"\n        app:contentInsetEnd=\"@dimen/padding_small\"\n        app:contentInsetStart=\"@dimen/padding_small\"\n        app:contentInsetStartWithNavigation=\"0dp\"\n        app:navigationIcon=\"@null\">\n\n        <androidx.appcompat.widget.LinearLayoutCompat\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:orientation=\"horizontal\">\n\n            <com.google.android.material.button.MaterialButton\n                android:id=\"@+id/reset_intent_button\"\n                style=\"@style/Widget.AppTheme.Button.FilledTonalButton\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_gravity=\"center_vertical\"\n                android:layout_margin=\"@dimen/padding_small\"\n                android:layout_weight=\"1\"\n                android:singleLine=\"true\"\n                android:text=\"@string/reset_to_default\"\n                android:visibility=\"gone\" />\n\n            <com.google.android.material.button.MaterialButton\n                android:id=\"@+id/resend_intent_button\"\n                style=\"@style/Widget.AppTheme.Button.FilledButton\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_gravity=\"center_vertical\"\n                android:layout_margin=\"@dimen/padding_small\"\n                android:layout_weight=\"1\"\n                android:singleLine=\"true\"\n                android:text=\"@string/resend_intent\" />\n\n        </androidx.appcompat.widget.LinearLayoutCompat>\n\n    </com.google.android.material.bottomappbar.BottomAppBar>\n\n</androidx.coordinatorlayout.widget.CoordinatorLayout>"
  },
  {
    "path": "app/src/main/res/layout/activity_labs.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    xmlns:tools=\"http://schemas.android.com/tools\">\n\n    <io.github.muntashirakon.widget.AppBarLayout\n        android:id=\"@+id/appbar\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:fitsSystemWindows=\"true\"\n        app:liftOnScroll=\"true\"\n        app:liftOnScrollTargetViewId=\"@+id/list_item\">\n\n        <com.google.android.material.appbar.MaterialToolbar\n            android:id=\"@+id/toolbar\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"?attr/actionBarSize\"\n            tools:menu=\"@menu/activity_fm_actions\" />\n\n    </io.github.muntashirakon.widget.AppBarLayout>\n\n    <io.github.muntashirakon.widget.NestedScrollView\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:fitsSystemWindows=\"true\"\n        android:clipToPadding=\"false\"\n        android:scrollbars=\"vertical\"\n        app:layout_behavior=\"com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior\">\n\n        <io.github.muntashirakon.widget.FlowLayout\n            android:id=\"@+id/action_container\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:paddingHorizontal=\"@dimen/padding_medium\"\n            android:gravity=\"center_horizontal\"\n            tools:listItem=\"@layout/item_app_info_action\" />\n\n    </io.github.muntashirakon.widget.NestedScrollView>\n\n</androidx.coordinatorlayout.widget.CoordinatorLayout>"
  },
  {
    "path": "app/src/main/res/layout/activity_logcat.xml",
    "content": "<!-- SPDX-License-Identifier: WTFPL AND GPL-3.0-or-later -->\n<!-- Copyright 2012 Nolan Lawson -->\n<!-- Copyright 2021 Muntashir Al-Islam -->\n<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    tools:context=\".logcat.LogViewerActivity\">\n\n    <io.github.muntashirakon.widget.AppBarLayout\n        android:id=\"@+id/appbar\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:fitsSystemWindows=\"true\"\n        app:liftOnScroll=\"true\"\n        app:liftOnScrollTargetViewId=\"@id/list\">\n\n        <com.google.android.material.appbar.MaterialToolbar\n            android:id=\"@+id/toolbar\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"?attr/actionBarSize\"\n            tools:menu=\"@menu/fragment_live_log_viewer_actions\" />\n\n        <com.google.android.material.progressindicator.LinearProgressIndicator\n            android:id=\"@+id/progress_linear\"\n            style=\"@style/Widget.AppTheme.LinearProgressIndicator\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:indeterminate=\"true\" />\n\n    </io.github.muntashirakon.widget.AppBarLayout>\n\n    <androidx.fragment.app.FragmentContainerView\n        android:id=\"@+id/main_layout\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        app:layout_behavior=\"com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior\" />\n\n    <com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton\n        android:id=\"@+id/fab\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"bottom|end\"\n        android:layout_margin=\"@dimen/padding_medium\"\n        android:accessibilityTraversalBefore=\"@id/main_layout\"\n        android:contentDescription=\"@string/log_stop_recording\"\n        android:fitsSystemWindows=\"true\"\n        android:text=\"@string/log_stop_recording\"\n        android:textColor=\"?attr/colorOnError\"\n        android:visibility=\"gone\"\n        app:backgroundTint=\"?attr/colorError\"\n        app:icon=\"@drawable/ic_stop\"\n        app:iconTint=\"?attr/colorOnError\"\n        app:layout_behavior=\"com.google.android.material.behavior.HideBottomViewOnScrollBehavior\"\n        tools:targetApi=\"22\"\n        tools:visibility=\"visible\" />\n\n</androidx.coordinatorlayout.widget.CoordinatorLayout>"
  },
  {
    "path": "app/src/main/res/layout/activity_main.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-or-later -->\n<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:id=\"@+id/coordinator_layout\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    tools:context=\"io.github.muntashirakon.AppManager.main.MainActivity\">\n\n    <io.github.muntashirakon.widget.AppBarLayout\n        android:id=\"@+id/appbar\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:fitsSystemWindows=\"true\"\n        app:liftOnScroll=\"true\"\n        app:liftOnScrollTargetViewId=\"@+id/item_list\">\n\n        <com.google.android.material.appbar.MaterialToolbar\n            android:id=\"@+id/toolbar\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"?attr/actionBarSize\"\n            app:navigationIcon=\"@null\"\n            tools:menu=\"@menu/activity_main_actions\" />\n\n        <com.google.android.material.progressindicator.LinearProgressIndicator\n            android:id=\"@+id/progress_linear\"\n            style=\"@style/Widget.AppTheme.LinearProgressIndicator\"\n            android:indeterminate=\"true\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\" />\n\n    </io.github.muntashirakon.widget.AppBarLayout>\n\n    <io.github.muntashirakon.widget.SwipeRefreshLayout\n        android:id=\"@+id/swipe_refresh\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:focusable=\"false\"\n        app:layout_behavior=\"com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior\">\n\n        <io.github.muntashirakon.widget.RecyclerView\n            android:id=\"@+id/item_list\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:scrollbars=\"none\"\n            android:focusable=\"false\"\n            android:clipToPadding=\"false\"\n            android:fitsSystemWindows=\"true\"\n            app:fastScrollerEnabled=\"true\"\n            tools:listitem=\"@layout/item_main\" />\n\n    </io.github.muntashirakon.widget.SwipeRefreshLayout>\n\n    <io.github.muntashirakon.widget.MultiSelectionView\n        android:id=\"@+id/selection_view\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:fitsSystemWindows=\"true\"\n        android:focusable=\"false\"\n        app:menu=\"@menu/activity_main_selection_actions\" />\n\n</androidx.coordinatorlayout.widget.CoordinatorLayout>"
  },
  {
    "path": "app/src/main/res/layout/activity_one_click_ops.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<androidx.coordinatorlayout.widget.CoordinatorLayout\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    tools:context=\".oneclickops.OneClickOpsActivity\">\n\n    <include layout=\"@layout/appbar\" />\n\n    <io.github.muntashirakon.widget.NestedScrollView\n        android:id=\"@+id/scrollView\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:scrollbars=\"vertical\"\n        android:fitsSystemWindows=\"true\"\n        android:clipToPadding=\"false\"\n        app:layout_behavior=\"com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior\">\n\n        <androidx.appcompat.widget.LinearLayoutCompat\n            android:id=\"@+id/container\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:orientation=\"vertical\" />\n\n    </io.github.muntashirakon.widget.NestedScrollView>\n\n</androidx.coordinatorlayout.widget.CoordinatorLayout>"
  },
  {
    "path": "app/src/main/res/layout/activity_op_history.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    tools:context=\".history.ops.OpHistoryActivity\">\n\n    <io.github.muntashirakon.widget.AppBarLayout\n        android:id=\"@+id/appbar\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:fitsSystemWindows=\"true\"\n        app:liftOnScroll=\"true\"\n        app:liftOnScrollTargetViewId=\"@android:id/list\">\n\n        <com.google.android.material.appbar.MaterialToolbar\n            android:id=\"@+id/toolbar\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"?attr/actionBarSize\"\n            tools:menu=\"@menu/activity_profiles_actions\" />\n\n        <com.google.android.material.progressindicator.LinearProgressIndicator\n            android:id=\"@+id/progress_linear\"\n            style=\"@style/Widget.AppTheme.LinearProgressIndicator\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:indeterminate=\"true\" />\n\n    </io.github.muntashirakon.widget.AppBarLayout>\n\n    <FrameLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        app:layout_behavior=\"com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior\">\n\n        <io.github.muntashirakon.widget.RecyclerView\n            android:id=\"@android:id/list\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:clipToPadding=\"false\"\n            android:fitsSystemWindows=\"true\"\n            app:fastScrollerEnabled=\"true\"\n            tools:listitem=\"@layout/m3_preference\" />\n\n        <androidx.appcompat.widget.AppCompatTextView\n            android:id=\"@android:id/empty\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:gravity=\"center\"\n            android:text=\"@string/no_history\" />\n\n    </FrameLayout>\n\n    <com.google.android.material.floatingactionbutton.FloatingActionButton\n        android:id=\"@+id/floatingActionButton\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"bottom|end\"\n        android:layout_margin=\"@dimen/padding_medium\"\n        android:accessibilityTraversalBefore=\"@android:id/list\"\n        android:clickable=\"true\"\n        android:contentDescription=\"@string/clear_history\"\n        android:fitsSystemWindows=\"true\"\n        android:focusable=\"true\"\n        android:src=\"@drawable/ic_brush\"\n        app:layout_behavior=\"com.google.android.material.behavior.HideBottomViewOnScrollBehavior\"\n        tools:targetApi=\"22\" />\n\n</androidx.coordinatorlayout.widget.CoordinatorLayout>"
  },
  {
    "path": "app/src/main/res/layout/activity_profiles.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    tools:context=\".profiles.ProfilesActivity\">\n\n    <io.github.muntashirakon.widget.AppBarLayout\n        android:id=\"@+id/appbar\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:fitsSystemWindows=\"true\"\n        app:liftOnScroll=\"true\"\n        app:liftOnScrollTargetViewId=\"@android:id/list\">\n\n        <com.google.android.material.appbar.MaterialToolbar\n            android:id=\"@+id/toolbar\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"?attr/actionBarSize\"\n            tools:menu=\"@menu/activity_profiles_actions\" />\n\n        <com.google.android.material.progressindicator.LinearProgressIndicator\n            android:id=\"@+id/progress_linear\"\n            style=\"@style/Widget.AppTheme.LinearProgressIndicator\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:indeterminate=\"true\" />\n\n    </io.github.muntashirakon.widget.AppBarLayout>\n\n    <FrameLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        app:layout_behavior=\"com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior\">\n\n        <io.github.muntashirakon.widget.RecyclerView\n            android:id=\"@android:id/list\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:clipToPadding=\"false\"\n            android:fitsSystemWindows=\"true\"\n            app:fastScrollerEnabled=\"true\"\n            tools:listitem=\"@layout/m3_preference\" />\n\n        <androidx.appcompat.widget.AppCompatTextView\n            android:id=\"@android:id/empty\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:gravity=\"center\"\n            android:text=\"@string/no_profiles\" />\n\n    </FrameLayout>\n\n    <com.google.android.material.floatingactionbutton.FloatingActionButton\n        android:id=\"@+id/floatingActionButton\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"bottom|end\"\n        android:layout_margin=\"@dimen/padding_medium\"\n        android:accessibilityTraversalBefore=\"@android:id/list\"\n        android:clickable=\"true\"\n        android:contentDescription=\"@string/new_profile\"\n        android:fitsSystemWindows=\"true\"\n        android:focusable=\"true\"\n        android:src=\"@drawable/ic_add\"\n        app:layout_behavior=\"com.google.android.material.behavior.HideBottomViewOnScrollBehavior\"\n        tools:targetApi=\"22\" />\n\n</androidx.coordinatorlayout.widget.CoordinatorLayout>"
  },
  {
    "path": "app/src/main/res/layout/activity_running_apps.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    tools:context=\".runningapps.RunningAppsActivity\">\n\n    <include layout=\"@layout/appbar\" />\n\n    <io.github.muntashirakon.widget.RecyclerView\n        android:id=\"@+id/scrollView\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:focusable=\"false\"\n        android:scrollbars=\"none\"\n        android:fitsSystemWindows=\"true\"\n        android:clipToPadding=\"false\"\n        app:fastScrollerEnabled=\"true\"\n        app:layout_behavior=\"com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior\"\n        tools:listitem=\"@layout/item_running_app\" />\n\n    <io.github.muntashirakon.widget.MultiSelectionView\n        android:id=\"@+id/selection_view\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:fitsSystemWindows=\"true\"\n        android:focusable=\"false\"\n        app:menu=\"@menu/activity_running_apps_popup_actions\" />\n\n</androidx.coordinatorlayout.widget.CoordinatorLayout>"
  },
  {
    "path": "app/src/main/res/layout/activity_settings.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    tools:context=\".settings.SettingsActivity\">\n\n    <io.github.muntashirakon.widget.AppBarLayout\n        android:id=\"@+id/appbar\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:fitsSystemWindows=\"true\"\n        app:liftOnScroll=\"true\">\n\n        <com.google.android.material.appbar.MaterialToolbar\n            android:id=\"@+id/toolbar\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"?attr/actionBarSize\" />\n\n        <com.google.android.material.progressindicator.LinearProgressIndicator\n            android:id=\"@+id/progress_linear\"\n            style=\"@style/Widget.AppTheme.LinearProgressIndicator\"\n            android:indeterminate=\"true\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\" />\n\n    </io.github.muntashirakon.widget.AppBarLayout>\n\n    <androidx.fragment.app.FragmentContainerView\n        android:id=\"@+id/main_layout\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        app:layout_behavior=\"com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior\" />\n\n</androidx.coordinatorlayout.widget.CoordinatorLayout>"
  },
  {
    "path": "app/src/main/res/layout/activity_settings_dual_pane.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<androidx.appcompat.widget.LinearLayoutCompat xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"horizontal\"\n    tools:context=\".settings.SettingsActivity\">\n\n    <androidx.coordinatorlayout.widget.CoordinatorLayout\n        android:layout_width=\"450dp\"\n        android:layout_height=\"match_parent\">\n\n        <io.github.muntashirakon.widget.AppBarLayout\n            android:id=\"@+id/appbar\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:fitsSystemWindows=\"true\"\n            app:liftOnScroll=\"false\">\n\n            <com.google.android.material.appbar.MaterialToolbar\n                android:id=\"@+id/toolbar\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"?attr/actionBarSize\"\n                app:title=\"@string/settings\" />\n\n            <com.google.android.material.progressindicator.LinearProgressIndicator\n                style=\"@style/Widget.AppTheme.LinearProgressIndicator\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:visibility=\"invisible\"\n                android:indeterminate=\"true\" />\n\n        </io.github.muntashirakon.widget.AppBarLayout>\n\n        <androidx.fragment.app.FragmentContainerView\n            android:id=\"@+id/main_layout\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            app:layout_behavior=\"com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior\" />\n\n    </androidx.coordinatorlayout.widget.CoordinatorLayout>\n\n    <androidx.coordinatorlayout.widget.CoordinatorLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\">\n\n        <com.google.android.material.appbar.AppBarLayout\n            android:id=\"@+id/appbar2\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:fitsSystemWindows=\"true\"\n            app:liftOnScroll=\"false\">\n\n            <com.google.android.material.appbar.MaterialToolbar\n                android:id=\"@+id/toolbar2\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"?attr/actionBarSize\"\n                app:navigationIcon=\"@null\" />\n\n            <com.google.android.material.progressindicator.LinearProgressIndicator\n                android:id=\"@+id/progress_linear\"\n                style=\"@style/Widget.AppTheme.LinearProgressIndicator\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:indeterminate=\"true\" />\n\n        </com.google.android.material.appbar.AppBarLayout>\n\n        <androidx.fragment.app.FragmentContainerView\n            android:id=\"@+id/secondary_layout\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            app:layout_behavior=\"com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior\" />\n\n    </androidx.coordinatorlayout.widget.CoordinatorLayout>\n</androidx.appcompat.widget.LinearLayoutCompat>"
  },
  {
    "path": "app/src/main/res/layout/activity_shared_prefs.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    tools:context=\".sharedpref.SharedPrefsActivity\">\n\n    <io.github.muntashirakon.widget.AppBarLayout\n        android:id=\"@+id/appbar\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:fitsSystemWindows=\"true\"\n        app:liftOnScroll=\"true\">\n\n        <com.google.android.material.appbar.MaterialToolbar\n            android:id=\"@+id/toolbar\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"?attr/actionBarSize\"\n            tools:menu=\"@menu/activity_shared_prefs_actions\" />\n\n        <com.google.android.material.progressindicator.LinearProgressIndicator\n            android:id=\"@+id/progress_linear\"\n            style=\"@style/Widget.AppTheme.LinearProgressIndicator\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:indeterminate=\"true\" />\n\n    </io.github.muntashirakon.widget.AppBarLayout>\n\n    <FrameLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        app:layout_behavior=\"com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior\">\n\n        <io.github.muntashirakon.widget.RecyclerView\n            android:id=\"@android:id/list\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:clipToPadding=\"false\"\n            android:fitsSystemWindows=\"true\"\n            app:fastScrollerEnabled=\"true\"\n            tools:listitem=\"@layout/m3_preference\" />\n\n        <androidx.appcompat.widget.AppCompatTextView\n            android:id=\"@android:id/empty\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:gravity=\"center\"\n            android:text=\"@string/no_content\" />\n\n    </FrameLayout>\n\n    <com.google.android.material.floatingactionbutton.FloatingActionButton\n        android:id=\"@+id/floatingActionButton\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"bottom|end\"\n        android:layout_margin=\"@dimen/padding_medium\"\n        android:accessibilityTraversalBefore=\"@android:id/list\"\n        android:clickable=\"true\"\n        android:contentDescription=\"@string/add_item\"\n        android:fitsSystemWindows=\"true\"\n        android:focusable=\"true\"\n        android:src=\"@drawable/ic_add\"\n        app:layout_behavior=\"com.google.android.material.behavior.HideBottomViewOnScrollBehavior\"\n        tools:targetApi=\"22\" />\n\n</androidx.coordinatorlayout.widget.CoordinatorLayout>"
  },
  {
    "path": "app/src/main/res/layout/activity_sys_config.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    tools:context=\".sysconfig.SysConfigActivity\">\n\n    <io.github.muntashirakon.widget.AppBarLayout\n        android:id=\"@+id/appbar\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:fitsSystemWindows=\"true\"\n        app:liftOnScroll=\"true\">\n\n        <com.google.android.material.appbar.MaterialToolbar\n            android:id=\"@+id/toolbar\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"?attr/actionBarSize\" />\n\n        <com.google.android.material.progressindicator.LinearProgressIndicator\n            android:id=\"@+id/progress_linear\"\n            style=\"@style/Widget.AppTheme.LinearProgressIndicator\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:indeterminate=\"true\" />\n\n    </io.github.muntashirakon.widget.AppBarLayout>\n\n    <androidx.appcompat.widget.LinearLayoutCompat\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:orientation=\"vertical\"\n        app:layout_behavior=\"com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior\">\n\n        <io.github.muntashirakon.widget.MaterialSpinner\n            android:id=\"@+id/spinner\"\n            style=\"@style/Widget.AppTheme.MaterialSpinner.Spinner.Small\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_gravity=\"start|center_vertical\"\n            android:layout_marginHorizontal=\"@dimen/padding_large\"\n            android:layout_marginVertical=\"@dimen/padding_small\"\n            android:fitsSystemWindows=\"true\"\n            android:minWidth=\"100dp\"\n            android:nextFocusDown=\"@id/recycler_view\"\n            tools:hint=\"permissions\" />\n\n        <FrameLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\">\n\n            <io.github.muntashirakon.widget.RecyclerView\n                android:id=\"@+id/recycler_view\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"match_parent\"\n                android:clipToPadding=\"false\"\n                android:fitsSystemWindows=\"true\"\n                android:nextFocusUp=\"@id/spinner\"\n                android:scrollbars=\"none\"\n                app:fastScrollerEnabled=\"true\"\n                tools:listitem=\"@layout/item_icon_title_subtitle\" />\n\n            <androidx.appcompat.widget.AppCompatTextView\n                android:id=\"@android:id/empty\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"match_parent\"\n                android:focusable=\"false\"\n                android:gravity=\"center\"\n                android:text=\"@string/no_content\" />\n\n        </FrameLayout>\n\n    </androidx.appcompat.widget.LinearLayoutCompat>\n\n</androidx.coordinatorlayout.widget.CoordinatorLayout>"
  },
  {
    "path": "app/src/main/res/layout/activity_term.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    tools:context=\".terminal.TermActivity\">\n\n    <com.google.android.material.appbar.AppBarLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:fitsSystemWindows=\"true\"\n        app:liftOnScroll=\"true\"\n        app:liftOnScrollTargetViewId=\"@id/scrollView\">\n\n        <com.google.android.material.appbar.MaterialToolbar\n            android:id=\"@+id/toolbar\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"?attr/actionBarSize\" />\n\n    </com.google.android.material.appbar.AppBarLayout>\n\n    <io.github.muntashirakon.widget.NestedScrollView\n        android:id=\"@+id/scrollView\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:paddingBottom=\"?attr/actionBarSize\"\n        android:clipToPadding=\"false\"\n        android:fitsSystemWindows=\"true\"\n        app:fastScrollerEnabled=\"true\"\n        app:layout_behavior=\"com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior\">\n\n            <androidx.appcompat.widget.AppCompatTextView\n                android:id=\"@+id/command_output\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:paddingVertical=\"8dp\"\n                android:paddingHorizontal=\"16dp\"\n                android:textIsSelectable=\"true\"\n                android:fontFamily=\"monospace\"\n                android:textSize=\"12sp\"\n                tools:text=\"Command output\" />\n\n    </io.github.muntashirakon.widget.NestedScrollView>\n\n    <com.google.android.material.bottomappbar.BottomAppBar\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:minHeight=\"?attr/actionBarSize\"\n        android:fitsSystemWindows=\"true\"\n        android:layout_gravity=\"bottom\"\n        app:contentInsetStartWithNavigation=\"0dp\"\n        app:contentInsetStart=\"@dimen/padding_small\"\n        app:contentInsetEnd=\"@dimen/padding_small\"\n        app:navigationIcon=\"@null\">\n\n        <androidx.appcompat.widget.LinearLayoutCompat\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:orientation=\"horizontal\">\n\n            <com.google.android.material.textfield.TextInputLayout\n                style=\"@style/Widget.AppTheme.TextInputLayout.Small\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                app:endIconMode=\"clear_text\"\n                tools:ignore=\"RtlSymmetry\">\n\n                <com.google.android.material.textfield.TextInputEditText\n                    android:id=\"@+id/command_input\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:inputType=\"textNoSuggestions\"\n                    android:fontFamily=\"monospace\"\n                    android:maxLines=\"1\"\n                    android:imeOptions=\"actionDone\" />\n\n            </com.google.android.material.textfield.TextInputLayout>\n\n        </androidx.appcompat.widget.LinearLayoutCompat>\n\n    </com.google.android.material.bottomappbar.BottomAppBar>\n\n</androidx.coordinatorlayout.widget.CoordinatorLayout>"
  },
  {
    "path": "app/src/main/res/layout/app_widget_clear_cache.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    style=\"@style/Widget.AppTheme.AppWidget\"\n    android:layout_width=\"48dp\"\n    android:layout_height=\"48dp\"\n    android:layout_gravity=\"center\"\n    android:background=\"@drawable/app_widget_background\"\n    android:theme=\"@style/AppTheme.AppWidgetContainer.IconOnly\">\n\n    <ImageView\n        android:id=\"@+id/appwidget_icon\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:layout_centerHorizontal=\"true\"\n        android:layout_centerVertical=\"true\"\n        android:contentDescription=\"@string/clear_app_cache\"\n        android:scaleType=\"fitCenter\"\n        android:src=\"@drawable/ic_clear_cache\"\n        android:tint=\"?android:attr/textColorSecondary\"\n        tools:ignore=\"UseAppTint\" />\n</RelativeLayout>\n"
  },
  {
    "path": "app/src/main/res/layout/app_widget_data_usage_small.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<FrameLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:id=\"@+id/widget_background\"\n    style=\"@style/Widget.AppTheme.AppWidget\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:background=\"@drawable/app_widget_background\"\n    android:orientation=\"vertical\"\n    android:padding=\"0dp\"\n    android:theme=\"@style/AppTheme.AppWidgetContainer\">\n\n    <include\n        layout=\"@layout/app_widget_refresh_button\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"end|top\" />\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:orientation=\"vertical\"\n        android:padding=\"@dimen/app_widget_background_padding\">\n\n        <TextView\n            android:id=\"@+id/data_usage_label\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_weight=\"0\"\n            android:ellipsize=\"end\"\n            android:maxLines=\"1\"\n            android:paddingStart=\"0dp\"\n            android:paddingEnd=\"16dp\"\n            android:text=\"@string/data_usage_msg\"\n            android:textColor=\"?android:attr/textColorSecondary\" />\n\n        <TextView\n            android:id=\"@+id/data_usage\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_gravity=\"center_vertical\"\n            android:layout_weight=\"1\"\n            android:autoSizeMaxTextSize=\"38sp\"\n            android:autoSizeMinTextSize=\"16sp\"\n            android:autoSizeTextType=\"uniform\"\n            android:ellipsize=\"end\"\n            android:gravity=\"center_vertical\"\n            android:maxLines=\"1\"\n            android:text=\"↑ 28 MB ↓ 1.2 GB\"\n            android:textColor=\"?android:attr/textColorPrimary\"\n            android:textSize=\"27sp\"\n            android:textStyle=\"bold\"\n            tools:ignore=\"HardcodedText\"\n            tools:targetApi=\"o\" />\n\n    </LinearLayout>\n\n</FrameLayout>\n"
  },
  {
    "path": "app/src/main/res/layout/app_widget_refresh_button.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<FrameLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:id=\"@+id/screen_time_refresh\"\n    android:layout_width=\"wrap_content\"\n    android:layout_height=\"wrap_content\"\n    android:background=\"@drawable/ripple_background_24\">\n\n    <ImageView\n        android:layout_width=\"18dp\"\n        android:layout_height=\"18dp\"\n        android:layout_gravity=\"center\"\n        android:layout_margin=\"@dimen/app_widget_background_padding\"\n        android:contentDescription=\"@string/refresh\"\n        android:src=\"@drawable/ic_refresh\"\n        android:tint=\"?android:attr/textColorSecondary\"\n        tools:ignore=\"UseAppTint\" />\n</FrameLayout>\n"
  },
  {
    "path": "app/src/main/res/layout/app_widget_screen_time.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<FrameLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:id=\"@+id/widget_background\"\n    style=\"@style/Widget.AppTheme.AppWidget\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:background=\"@drawable/app_widget_background\"\n    android:padding=\"0dp\"\n    android:theme=\"@style/AppTheme.AppWidgetContainer\">\n\n    <include\n        layout=\"@layout/app_widget_refresh_button\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"end|top\" />\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:orientation=\"vertical\"\n        android:padding=\"@dimen/app_widget_background_padding\">\n\n        <TextView\n            android:id=\"@+id/screen_time_label\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_weight=\"0\"\n            android:ellipsize=\"end\"\n            android:maxLines=\"1\"\n            android:text=\"@string/screen_time\"\n            android:textColor=\"?android:attr/textColorSecondary\" />\n\n        <TextView\n            android:id=\"@+id/screen_time\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_gravity=\"center_vertical\"\n            android:layout_weight=\"1\"\n            android:autoSizeMaxTextSize=\"38sp\"\n            android:autoSizeMinTextSize=\"16sp\"\n            android:autoSizeTextType=\"uniform\"\n            android:ellipsize=\"end\"\n            android:gravity=\"center_vertical\"\n            android:maxLines=\"1\"\n            android:text=\"2h 30m\"\n            android:textColor=\"?android:attr/textColorPrimary\"\n            android:textSize=\"27sp\"\n            android:textStyle=\"bold\"\n            tools:ignore=\"HardcodedText\"\n            tools:targetApi=\"o\" />\n\n        <LinearLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_weight=\"0\"\n            android:orientation=\"horizontal\">\n\n            <RelativeLayout\n                android:layout_width=\"52dp\"\n                android:layout_height=\"match_parent\">\n\n                <TextView\n                    android:id=\"@+id/app3_time\"\n                    android:layout_width=\"34dp\"\n                    android:layout_height=\"34dp\"\n                    android:layout_marginHorizontal=\"4sp\"\n                    android:layout_marginTop=\"64sp\"\n                    android:background=\"@drawable/circle_background\"\n                    android:backgroundTint=\"#d4e3ff\"\n                    android:gravity=\"center\"\n                    android:maxLines=\"1\"\n                    android:text=\"20m\"\n                    android:textColor=\"#1b1b1b\"\n                    android:textSize=\"@dimen/font_size_medium\"\n                    android:textStyle=\"bold\"\n                    tools:ignore=\"HardcodedText\" />\n\n                <TextView\n                    android:id=\"@+id/app2_time\"\n                    android:layout_width=\"38dp\"\n                    android:layout_height=\"38dp\"\n                    android:layout_marginHorizontal=\"2sp\"\n                    android:layout_marginTop=\"32sp\"\n                    android:background=\"@drawable/circle_background\"\n                    android:backgroundTint=\"#565e71\"\n                    android:gravity=\"center\"\n                    android:maxLines=\"1\"\n                    android:text=\"45m\"\n                    android:textColor=\"#f9f9f9\"\n                    android:textSize=\"@dimen/font_size_medium\"\n                    android:textStyle=\"bold\"\n                    tools:ignore=\"HardcodedText\" />\n\n                <TextView\n                    android:id=\"@+id/app1_time\"\n                    android:layout_width=\"42dp\"\n                    android:layout_height=\"42dp\"\n                    android:layout_marginHorizontal=\"0sp\"\n                    android:layout_marginTop=\"0sp\"\n                    android:background=\"@drawable/circle_background\"\n                    android:backgroundTint=\"#1b1b1b\"\n                    android:gravity=\"center\"\n                    android:maxLines=\"1\"\n                    android:text=\"~1h\"\n                    android:textColor=\"#f9f9f9\"\n                    android:textSize=\"@dimen/font_size_medium\"\n                    android:textStyle=\"bold\"\n                    tools:ignore=\"HardcodedText\" />\n\n            </RelativeLayout>\n\n            <RelativeLayout\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"match_parent\"\n                android:baselineAligned=\"false\"\n                android:orientation=\"vertical\">\n\n                <TextView\n                    android:id=\"@+id/app1_label\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_marginTop=\"12sp\"\n                    android:ellipsize=\"end\"\n                    android:maxLines=\"1\"\n                    android:text=\"Signal\"\n                    android:textColor=\"?android:attr/textColorSecondary\"\n                    android:textSize=\"@dimen/font_size_medium\"\n                    tools:ignore=\"HardcodedText\" />\n\n                <TextView\n                    android:id=\"@+id/app2_label\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_marginTop=\"41sp\"\n                    android:ellipsize=\"end\"\n                    android:maxLines=\"1\"\n                    android:text=\"App Manager\"\n                    android:textColor=\"?android:attr/textColorSecondary\"\n                    android:textSize=\"@dimen/font_size_medium\"\n                    tools:ignore=\"HardcodedText\" />\n\n                <TextView\n                    android:id=\"@+id/app3_label\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_marginTop=\"71sp\"\n                    android:ellipsize=\"end\"\n                    android:maxLines=\"1\"\n                    android:text=\"K-9 Mail\"\n                    android:textColor=\"?android:attr/textColorSecondary\"\n                    android:textSize=\"@dimen/font_size_medium\"\n                    tools:ignore=\"HardcodedText\" />\n\n            </RelativeLayout>\n\n        </LinearLayout>\n\n    </LinearLayout>\n\n</FrameLayout>"
  },
  {
    "path": "app/src/main/res/layout/app_widget_screen_time_large.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<FrameLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:id=\"@+id/widget_background\"\n    style=\"@style/Widget.AppTheme.AppWidget\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:background=\"@drawable/app_widget_background\"\n    android:padding=\"0dp\"\n    android:theme=\"@style/AppTheme.AppWidgetContainer\">\n\n    <include\n        layout=\"@layout/app_widget_refresh_button\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"end|top\" />\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:orientation=\"vertical\"\n        android:padding=\"@dimen/app_widget_background_padding\">\n\n        <TextView\n            android:id=\"@+id/screen_time_label\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_weight=\"0\"\n            android:ellipsize=\"end\"\n            android:maxLines=\"1\"\n            android:text=\"@string/screen_time\"\n            android:textColor=\"?android:attr/textColorSecondary\" />\n\n        <TextView\n            android:id=\"@+id/screen_time\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_gravity=\"center_vertical\"\n            android:layout_weight=\"1\"\n            android:autoSizeMaxTextSize=\"38sp\"\n            android:autoSizeMinTextSize=\"16sp\"\n            android:autoSizeTextType=\"uniform\"\n            android:ellipsize=\"end\"\n            android:gravity=\"center_vertical\"\n            android:maxLines=\"1\"\n            android:textColor=\"?android:attr/textColorPrimary\"\n            android:textSize=\"27sp\"\n            android:textStyle=\"bold\"\n            tools:targetApi=\"o\"\n            tools:text=\"2h 30m\" />\n\n        <LinearLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:gravity=\"center_vertical\"\n            android:orientation=\"horizontal\">\n\n            <TextView\n                android:id=\"@+id/app3_circle\"\n                android:layout_width=\"16dp\"\n                android:layout_height=\"16dp\"\n                android:layout_margin=\"4dp\"\n                android:background=\"@drawable/circle_background\"\n                android:backgroundTint=\"#d4e3ff\" />\n\n            <TextView\n                android:id=\"@+id/app3_label\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_margin=\"4dp\"\n                android:ellipsize=\"end\"\n                android:maxLines=\"1\"\n                android:textColor=\"?android:attr/textColorSecondary\"\n                android:textSize=\"@dimen/font_size_medium\"\n                tools:text=\"K-9 Mail\" />\n\n        </LinearLayout>\n\n        <LinearLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:gravity=\"center_vertical\"\n            android:orientation=\"horizontal\">\n\n            <TextView\n                android:id=\"@+id/app2_circle\"\n                android:layout_width=\"16dp\"\n                android:layout_height=\"16dp\"\n                android:layout_margin=\"4dp\"\n                android:background=\"@drawable/circle_background\"\n                android:backgroundTint=\"#565e71\" />\n\n            <TextView\n                android:id=\"@+id/app2_label\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_margin=\"4dp\"\n                android:ellipsize=\"end\"\n                android:maxLines=\"1\"\n                android:textColor=\"?android:attr/textColorSecondary\"\n                android:textSize=\"@dimen/font_size_medium\"\n                tools:text=\"App Manager\" />\n\n        </LinearLayout>\n\n        <LinearLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:gravity=\"center_vertical\"\n            android:orientation=\"horizontal\">\n\n            <TextView\n                android:id=\"@+id/app1_circle\"\n                android:layout_width=\"16dp\"\n                android:layout_height=\"16dp\"\n                android:layout_margin=\"4dp\"\n                android:background=\"@drawable/circle_background\"\n                android:backgroundTint=\"#1b1b1b\" />\n\n            <TextView\n                android:id=\"@+id/app1_label\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_margin=\"4dp\"\n                android:ellipsize=\"end\"\n                android:maxLines=\"1\"\n                android:textColor=\"?android:attr/textColorSecondary\"\n                android:textSize=\"@dimen/font_size_medium\"\n                tools:text=\"Signal\" />\n\n        </LinearLayout>\n\n    </LinearLayout>\n\n    <!-- Bubbles -->\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:orientation=\"horizontal\">\n\n        <TextView\n            android:layout_width=\"0dp\"\n            android:layout_height=\"match_parent\"\n            android:layout_weight=\"1\" />\n\n        <LinearLayout\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"match_parent\"\n            android:orientation=\"vertical\"\n            android:paddingTop=\"@dimen/app_widget_background_padding\">\n\n            <TextView\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"0dp\"\n                android:layout_weight=\"1\" />\n\n            <RelativeLayout\n                android:layout_width=\"112dp\"\n                android:layout_height=\"203dp\"\n                android:layout_gravity=\"bottom\">\n\n                <TextView\n                    android:id=\"@+id/app1_time\"\n                    android:layout_width=\"112dp\"\n                    android:layout_height=\"112dp\"\n                    android:layout_alignParentEnd=\"true\"\n                    android:layout_alignParentBottom=\"true\"\n                    android:background=\"@drawable/circle_background\"\n                    android:backgroundTint=\"#1b1b1b\"\n                    android:gravity=\"center\"\n                    android:maxLines=\"1\"\n                    android:textColor=\"#f9f9f9\"\n                    android:textSize=\"@dimen/font_size_large\"\n                    android:textStyle=\"bold\"\n                    tools:text=\"~1h\" />\n\n                <TextView\n                    android:id=\"@+id/app2_time\"\n                    android:layout_width=\"72dp\"\n                    android:layout_height=\"72dp\"\n                    android:layout_alignParentStart=\"true\"\n                    android:layout_alignParentBottom=\"true\"\n                    android:layout_marginEnd=\"25dp\"\n                    android:layout_marginBottom=\"95dp\"\n                    android:background=\"@drawable/circle_background\"\n                    android:backgroundTint=\"#565e71\"\n                    android:gravity=\"center\"\n                    android:maxLines=\"1\"\n                    android:textColor=\"#f9f9f9\"\n                    android:textSize=\"@dimen/font_size_large\"\n                    android:textStyle=\"bold\"\n                    tools:text=\"45m\" />\n\n                <TextView\n                    android:id=\"@+id/app3_time\"\n                    android:layout_width=\"48dp\"\n                    android:layout_height=\"48dp\"\n                    android:layout_alignParentStart=\"true\"\n                    android:layout_alignParentBottom=\"true\"\n                    android:layout_marginEnd=\"55dp\"\n                    android:layout_marginBottom=\"155dp\"\n                    android:background=\"@drawable/circle_background\"\n                    android:backgroundTint=\"#d4e3ff\"\n                    android:gravity=\"center\"\n                    android:maxLines=\"1\"\n                    android:textColor=\"#1b1b1b\"\n                    android:textSize=\"@dimen/font_size_large\"\n                    android:textStyle=\"bold\"\n                    tools:text=\"20m\" />\n\n            </RelativeLayout>\n\n        </LinearLayout>\n\n    </LinearLayout>\n\n</FrameLayout>"
  },
  {
    "path": "app/src/main/res/layout/app_widget_screen_time_small.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<FrameLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:id=\"@+id/widget_background\"\n    style=\"@style/Widget.AppTheme.AppWidget\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:background=\"@drawable/app_widget_background\"\n    android:orientation=\"vertical\"\n    android:padding=\"0dp\"\n    android:theme=\"@style/AppTheme.AppWidgetContainer\">\n\n    <include\n        layout=\"@layout/app_widget_refresh_button\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"end|top\" />\n\n    <LinearLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:orientation=\"vertical\"\n        android:padding=\"@dimen/app_widget_background_padding\">\n\n        <TextView\n            android:id=\"@+id/screen_time_label\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_weight=\"0\"\n            android:ellipsize=\"end\"\n            android:maxLines=\"1\"\n            android:paddingStart=\"0dp\"\n            android:paddingEnd=\"16dp\"\n            android:text=\"@string/screen_time\"\n            android:textColor=\"?android:attr/textColorSecondary\" />\n\n        <TextView\n            android:id=\"@+id/screen_time\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_gravity=\"center_vertical\"\n            android:layout_weight=\"1\"\n            android:autoSizeMaxTextSize=\"38sp\"\n            android:autoSizeMinTextSize=\"16sp\"\n            android:autoSizeTextType=\"uniform\"\n            android:ellipsize=\"end\"\n            android:gravity=\"center_vertical\"\n            android:maxLines=\"1\"\n            android:textColor=\"?android:attr/textColorPrimary\"\n            android:textSize=\"27sp\"\n            android:textStyle=\"bold\"\n            tools:targetApi=\"o\"\n            tools:text=\"2h 30m\" />\n\n    </LinearLayout>\n\n</FrameLayout>\n"
  },
  {
    "path": "app/src/main/res/layout/appbar.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<io.github.muntashirakon.widget.AppBarLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    android:id=\"@+id/appbar\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:fitsSystemWindows=\"true\"\n    app:liftOnScroll=\"true\"\n    app:liftOnScrollTargetViewId=\"@+id/scrollView\">\n\n    <com.google.android.material.appbar.MaterialToolbar\n        android:id=\"@+id/toolbar\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"?attr/actionBarSize\" />\n\n    <com.google.android.material.progressindicator.LinearProgressIndicator\n        android:id=\"@+id/progress_linear\"\n        style=\"@style/Widget.AppTheme.LinearProgressIndicator\"\n        android:indeterminate=\"true\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\" />\n\n</io.github.muntashirakon.widget.AppBarLayout>\n"
  },
  {
    "path": "app/src/main/res/layout/dialog_app_usage_details.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<ScrollView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n\n    <androidx.appcompat.widget.LinearLayoutCompat\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:orientation=\"vertical\">\n\n        <androidx.appcompat.widget.LinearLayoutCompat\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginBottom=\"@dimen/padding_small\"\n            android:orientation=\"horizontal\"\n            android:paddingHorizontal=\"@dimen/padding_medium\">\n\n            <com.google.android.material.textfield.TextInputLayout\n                style=\"@style/Widget.AppTheme.TextInputLayout.Small\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_marginEnd=\"@dimen/padding_small\"\n                android:layout_weight=\"1\"\n                android:hint=\"@string/screen_time\"\n                app:hintEnabled=\"true\">\n\n                <io.github.muntashirakon.widget.TextInputTextView\n                    android:id=\"@+id/screen_time\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:inputType=\"none\"\n                    android:textIsSelectable=\"true\"\n                    tools:text=\"1 hr 20 mins\" />\n\n            </com.google.android.material.textfield.TextInputLayout>\n\n            <com.google.android.material.textfield.TextInputLayout\n                style=\"@style/Widget.AppTheme.TextInputLayout.Small\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_weight=\"1\"\n                android:hint=\"@string/usage_times_opened\"\n                app:hintEnabled=\"true\">\n\n                <io.github.muntashirakon.widget.TextInputTextView\n                    android:id=\"@+id/times_opened\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:inputType=\"none\"\n                    android:textIsSelectable=\"true\"\n                    tools:text=\"@tools:sample/us_zipcodes\" />\n\n            </com.google.android.material.textfield.TextInputLayout>\n\n        </androidx.appcompat.widget.LinearLayoutCompat>\n\n        <androidx.appcompat.widget.LinearLayoutCompat\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginBottom=\"@dimen/padding_small\"\n            android:orientation=\"horizontal\"\n            android:paddingHorizontal=\"@dimen/padding_medium\">\n\n            <com.google.android.material.textfield.TextInputLayout\n                style=\"@style/Widget.AppTheme.TextInputLayout.Small\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_marginEnd=\"@dimen/padding_small\"\n                android:layout_weight=\"1\"\n                android:hint=\"@string/usage_last_used\"\n                app:hintEnabled=\"true\">\n\n                <io.github.muntashirakon.widget.TextInputTextView\n                    android:id=\"@+id/last_used\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:inputType=\"none\"\n                    android:textIsSelectable=\"true\"\n                    tools:text=\"1 hr 20 mins ago\" />\n\n            </com.google.android.material.textfield.TextInputLayout>\n\n            <com.google.android.material.textfield.TextInputLayout\n                style=\"@style/Widget.AppTheme.TextInputLayout.Small\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_weight=\"1\"\n                android:hint=\"@string/user_id\"\n                app:hintEnabled=\"true\">\n\n                <io.github.muntashirakon.widget.TextInputTextView\n                    android:id=\"@+id/user_id\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:inputType=\"none\"\n                    android:textIsSelectable=\"true\"\n                    tools:text=\"@tools:sample/us_zipcodes\" />\n\n            </com.google.android.material.textfield.TextInputLayout>\n\n        </androidx.appcompat.widget.LinearLayoutCompat>\n\n        <androidx.appcompat.widget.LinearLayoutCompat\n            android:id=\"@+id/data_usage_layout\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:orientation=\"vertical\"\n            android:paddingHorizontal=\"@dimen/padding_medium\">\n\n            <com.google.android.material.textview.MaterialTextView\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_marginBottom=\"@dimen/padding_small\"\n                android:text=\"@string/data_usage_msg\" />\n\n            <com.google.android.material.textfield.TextInputLayout\n                style=\"@style/Widget.AppTheme.TextInputLayout.Small\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_marginBottom=\"@dimen/padding_small\"\n                android:hint=\"@string/usage_mobile_data\"\n                app:hintEnabled=\"true\">\n\n                <io.github.muntashirakon.widget.TextInputTextView\n                    android:id=\"@+id/data_usage\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:inputType=\"none\"\n                    android:textIsSelectable=\"true\"\n                    tools:text=\"↑ 17.85 MB ↓ 160 MB\" />\n\n            </com.google.android.material.textfield.TextInputLayout>\n\n            <com.google.android.material.textfield.TextInputLayout\n                style=\"@style/Widget.AppTheme.TextInputLayout.Small\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_marginBottom=\"@dimen/padding_small\"\n                android:hint=\"@string/usage_wifi_data\"\n                app:hintEnabled=\"true\">\n\n                <io.github.muntashirakon.widget.TextInputTextView\n                    android:id=\"@+id/wifi_usage\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:inputType=\"none\"\n                    android:textIsSelectable=\"true\"\n                    tools:text=\"↑ 4.65 MB ↓ 305 MB\" />\n\n            </com.google.android.material.textfield.TextInputLayout>\n\n        </androidx.appcompat.widget.LinearLayoutCompat>\n\n        <io.github.muntashirakon.AppManager.usage.BarChartView\n            android:id=\"@+id/bar_chart\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"150dp\"\n            android:layout_margin=\"@dimen/padding_medium\"\n            android:layout_weight=\"0\"\n            android:importantForAccessibility=\"yes\"\n            app:gridLineCount=\"4\" />\n\n    </androidx.appcompat.widget.LinearLayoutCompat>\n</ScrollView>"
  },
  {
    "path": "app/src/main/res/layout/dialog_audio_player.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<ScrollView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n\n    <androidx.appcompat.widget.LinearLayoutCompat\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:orientation=\"vertical\"\n        android:paddingHorizontal=\"@dimen/padding_small\"\n        android:paddingVertical=\"@dimen/padding_medium\">\n\n        <androidx.appcompat.widget.LinearLayoutCompat\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:orientation=\"horizontal\">\n\n            <com.google.android.material.imageview.ShapeableImageView\n                android:id=\"@android:id/icon\"\n                android:layout_width=\"48dp\"\n                android:layout_height=\"48dp\"\n                android:layout_weight=\"0\"\n                android:layout_gravity=\"center\"\n                android:layout_marginEnd=\"@dimen/padding_small\"\n                android:contentDescription=\"@string/str_logo\"\n                app:shapeAppearanceOverlay=\"@style/ShapeAppearance.AppTheme.SmallComponent\"\n                app:srcCompat=\"@drawable/ic_audio_file\" />\n\n            <androidx.appcompat.widget.LinearLayoutCompat\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_weight=\"1\"\n                android:layout_gravity=\"center\"\n                android:orientation=\"vertical\">\n\n                <com.google.android.material.textview.MaterialTextView\n                    android:id=\"@+id/size\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:singleLine=\"true\"\n                    android:textAppearance=\"?attr/textAppearanceListItemSecondary\"\n                    android:textSize=\"9sp\"\n                    tools:text=\"1/12\"\n                    tools:ignore=\"SmallSp\" />\n\n                <com.google.android.material.textview.MaterialTextView\n                    android:id=\"@android:id/title\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:singleLine=\"true\"\n                    android:ellipsize=\"marquee\"\n                    android:marqueeRepeatLimit=\"marquee_forever\"\n                    android:scrollHorizontally=\"true\"\n                    android:textAppearance=\"?attr/textAppearanceListItem\"\n                    tools:text=\"Concerto No. 5 in E-Flat Major for Piano and Orchestra, Op. 73\" />\n\n                <com.google.android.material.textview.MaterialTextView\n                    android:id=\"@+id/info\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:singleLine=\"true\"\n                    android:ellipsize=\"marquee\"\n                    android:marqueeRepeatLimit=\"marquee_forever\"\n                    android:scrollHorizontally=\"true\"\n                    android:textAppearance=\"?attr/textAppearanceListItemSecondary\"\n                    tools:text=\"Nuremberg Symphony Orchestra - The 100 Most Essential Pieces of Classical Music\" />\n\n            </androidx.appcompat.widget.LinearLayoutCompat>\n\n        </androidx.appcompat.widget.LinearLayoutCompat>\n\n        <com.google.android.material.slider.Slider\n            android:id=\"@+id/slider\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\" />\n\n        <androidx.appcompat.widget.LinearLayoutCompat\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:orientation=\"horizontal\">\n\n            <com.google.android.material.textview.MaterialTextView\n                android:id=\"@+id/progress\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_weight=\"0\"\n                android:paddingStart=\"12dp\"\n                android:paddingEnd=\"4dp\"\n                android:gravity=\"start\"\n                android:textSize=\"12sp\"\n                tools:text=\"00:00\" />\n\n            <Space\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_weight=\"1\" />\n\n            <com.google.android.material.textview.MaterialTextView\n                android:id=\"@+id/duration\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_weight=\"0\"\n                android:paddingStart=\"4dp\"\n                android:paddingEnd=\"12dp\"\n                android:gravity=\"end\"\n                android:textSize=\"12sp\"\n                tools:text=\"00:00\" />\n\n        </androidx.appcompat.widget.LinearLayoutCompat>\n\n        <androidx.appcompat.widget.LinearLayoutCompat\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_gravity=\"center_vertical\"\n            android:orientation=\"horizontal\"\n            android:gravity=\"center\">\n\n            <com.google.android.material.textview.MaterialTextView\n                android:id=\"@+id/playback_speed\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_weight=\"0\"\n                android:layout_margin=\"4dp\"\n                android:background=\"?attr/selectableItemBackgroundBorderless\"\n                android:clickable=\"true\"\n                android:focusable=\"true\"\n                android:gravity=\"center_vertical\"\n                android:padding=\"4dp\"\n                android:text=\"1x\"\n                android:textStyle=\"bold\" />\n\n            <Space\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_weight=\"1\" />\n\n            <androidx.appcompat.widget.AppCompatImageView\n                android:id=\"@+id/action_rewind\"\n                android:layout_width=\"36dp\"\n                android:layout_height=\"36dp\"\n                android:layout_weight=\"0\"\n                android:layout_margin=\"2dp\"\n                android:background=\"?attr/selectableItemBackgroundBorderless\"\n                android:padding=\"4dp\"\n                android:scaleType=\"fitXY\"\n                android:src=\"@drawable/ic_fast_rewind\" />\n\n            <androidx.appcompat.widget.AppCompatImageView\n                android:id=\"@+id/action_play_pause\"\n                android:layout_width=\"48dp\"\n                android:layout_height=\"48dp\"\n                android:layout_marginStart=\"2dp\"\n                android:layout_marginTop=\"2dp\"\n                android:layout_marginEnd=\"8dp\"\n                android:layout_marginBottom=\"4dp\"\n                android:background=\"?attr/selectableItemBackgroundBorderless\"\n                android:padding=\"4dp\"\n                android:scaleType=\"fitXY\"\n                android:src=\"@drawable/ic_play_arrow\" />\n\n            <androidx.appcompat.widget.AppCompatImageView\n                android:id=\"@+id/action_forward\"\n                android:layout_width=\"36dp\"\n                android:layout_height=\"36dp\"\n                android:layout_weight=\"0\"\n                android:layout_margin=\"2dp\"\n                android:background=\"?attr/selectableItemBackgroundBorderless\"\n                android:padding=\"4dp\"\n                android:scaleType=\"fitXY\"\n                android:src=\"@drawable/ic_fast_forward\" />\n\n            <Space\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_weight=\"1\" />\n\n            <androidx.appcompat.widget.AppCompatImageView\n                android:id=\"@+id/action_repeat\"\n                android:layout_width=\"32dp\"\n                android:layout_height=\"32dp\"\n                android:layout_marginStart=\"8dp\"\n                android:layout_marginTop=\"2dp\"\n                android:layout_marginEnd=\"4dp\"\n                android:layout_marginBottom=\"4dp\"\n                android:background=\"?attr/selectableItemBackgroundBorderless\"\n                android:clickable=\"true\"\n                android:focusable=\"true\"\n                android:padding=\"4dp\"\n                android:scaleType=\"fitXY\"\n                android:src=\"@drawable/ic_repeat_off\" />\n\n        </androidx.appcompat.widget.LinearLayoutCompat>\n\n    </androidx.appcompat.widget.LinearLayoutCompat>\n\n</ScrollView>"
  },
  {
    "path": "app/src/main/res/layout/dialog_backup_restore.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<FrameLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\">\n\n    <!-- The sequence must be maintained. -->\n    <androidx.fragment.app.FragmentContainerView\n        android:id=\"@+id/fragment_container_view_tag\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\" />\n\n    <androidx.appcompat.widget.LinearLayoutCompat\n        android:id=\"@+id/container\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:orientation=\"vertical\"\n        android:visibility=\"gone\"\n        tools:visibility=\"visible\">\n\n        <com.google.android.material.tabs.TabLayout\n            style=\"@style/Widget.Material3.TabLayout.OnSurface\"\n            android:id=\"@+id/tab_layout\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            app:tabPadding=\"@dimen/padding_medium\"\n            app:tabMode=\"fixed\"\n            app:tabBackground=\"@drawable/tab_item_background_rounded\"\n            app:tabTextColor=\"?attr/colorOnSecondaryContainer\"\n            app:tabSelectedTextColor=\"?attr/colorOnPrimary\"\n            app:tabIndicator=\"@null\">\n\n            <com.google.android.material.tabs.TabItem\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                tools:text=\"TAB 1\" />\n\n            <com.google.android.material.tabs.TabItem\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                tools:text=\"TAB 2\" />\n\n        </com.google.android.material.tabs.TabLayout>\n\n        <androidx.viewpager2.widget.ViewPager2\n            android:id=\"@+id/pager\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:overScrollMode=\"never\" />\n\n    </androidx.appcompat.widget.LinearLayoutCompat>\n\n    <com.google.android.material.textview.MaterialTextView\n        android:id=\"@+id/message\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"320dp\"\n        android:visibility=\"gone\"\n        android:gravity=\"center\"\n        android:text=\"@string/backup_no_backups_present\"\n        tools:visibility=\"visible\" />\n\n</FrameLayout>\n"
  },
  {
    "path": "app/src/main/res/layout/dialog_backup_tasks.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<ScrollView\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n\n    <androidx.appcompat.widget.LinearLayoutCompat\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:orientation=\"vertical\">\n\n        <androidx.appcompat.widget.LinearLayoutCompat\n            android:id=\"@+id/backup_all\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:paddingHorizontal=\"@dimen/padding_medium\"\n            android:paddingVertical=\"@dimen/padding_small\"\n            android:background=\"?selectableItemBackground\"\n            android:orientation=\"vertical\">\n\n            <androidx.appcompat.widget.AppCompatTextView\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:textAppearance=\"?android:attr/textAppearanceListItem\"\n                android:text=\"@string/backup_all_apps\" />\n\n            <androidx.appcompat.widget.AppCompatTextView\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:textColor=\"?android:attr/textColorSecondary\"\n                android:textAppearance=\"?android:attr/textAppearanceListItemSecondary\"\n                android:text=\"@string/backup_all_apps_msg\" />\n\n        </androidx.appcompat.widget.LinearLayoutCompat>\n\n        <com.google.android.material.divider.MaterialDivider\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"1dp\" />\n\n        <androidx.appcompat.widget.LinearLayoutCompat\n            android:id=\"@+id/redo_existing_backups\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:paddingHorizontal=\"@dimen/padding_medium\"\n            android:paddingVertical=\"@dimen/padding_small\"\n            android:background=\"?selectableItemBackground\"\n            android:orientation=\"vertical\">\n\n            <androidx.appcompat.widget.AppCompatTextView\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:textAppearance=\"?android:attr/textAppearanceListItem\"\n                android:text=\"@string/redo_existing_backups\" />\n\n            <androidx.appcompat.widget.AppCompatTextView\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:textColor=\"?android:attr/textColorSecondary\"\n                android:textAppearance=\"?android:attr/textAppearanceListItemSecondary\"\n                android:text=\"@string/redo_existing_backups_msg\" />\n\n        </androidx.appcompat.widget.LinearLayoutCompat>\n\n        <com.google.android.material.divider.MaterialDivider\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"1dp\" />\n\n        <androidx.appcompat.widget.LinearLayoutCompat\n            android:id=\"@+id/backup_apps_without_backup\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:paddingHorizontal=\"@dimen/padding_medium\"\n            android:paddingVertical=\"@dimen/padding_small\"\n            android:background=\"?selectableItemBackground\"\n            android:orientation=\"vertical\">\n\n            <androidx.appcompat.widget.AppCompatTextView\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:textAppearance=\"?android:attr/textAppearanceListItem\"\n                android:text=\"@string/backup_apps_without_backups\" />\n\n            <androidx.appcompat.widget.AppCompatTextView\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:textColor=\"?android:attr/textColorSecondary\"\n                android:textAppearance=\"?android:attr/textAppearanceListItemSecondary\"\n                android:text=\"@string/backup_apps_without_backups_msg\" />\n\n        </androidx.appcompat.widget.LinearLayoutCompat>\n\n        <com.google.android.material.divider.MaterialDivider\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"1dp\" />\n\n        <androidx.appcompat.widget.LinearLayoutCompat\n            android:id=\"@+id/verify_and_redo_backups\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:paddingHorizontal=\"@dimen/padding_medium\"\n            android:paddingVertical=\"@dimen/padding_small\"\n            android:background=\"?selectableItemBackground\"\n            android:orientation=\"vertical\">\n\n            <androidx.appcompat.widget.AppCompatTextView\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:textAppearance=\"?android:attr/textAppearanceListItem\"\n                android:text=\"@string/verify_and_redo_backups\" />\n\n            <androidx.appcompat.widget.AppCompatTextView\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:textColor=\"?android:attr/textColorSecondary\"\n                android:textAppearance=\"?android:attr/textAppearanceListItemSecondary\"\n                android:text=\"@string/verify_and_redo_backups_msg\" />\n\n        </androidx.appcompat.widget.LinearLayoutCompat>\n\n        <com.google.android.material.divider.MaterialDivider\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"1dp\" />\n\n        <androidx.appcompat.widget.LinearLayoutCompat\n            android:id=\"@+id/backup_apps_with_changes\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:paddingHorizontal=\"@dimen/padding_medium\"\n            android:paddingVertical=\"@dimen/padding_small\"\n            android:background=\"?selectableItemBackground\"\n            android:orientation=\"vertical\">\n\n            <com.google.android.material.textview.MaterialTextView\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:textAppearance=\"?android:attr/textAppearanceListItem\"\n                android:text=\"@string/backup_apps_with_changes\" />\n\n            <androidx.appcompat.widget.AppCompatTextView\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:textColor=\"?android:attr/textColorSecondary\"\n                android:textAppearance=\"?android:attr/textAppearanceListItemSecondary\"\n                android:text=\"@string/backup_apps_with_changes_msg\" />\n\n        </androidx.appcompat.widget.LinearLayoutCompat>\n\n    </androidx.appcompat.widget.LinearLayoutCompat>\n\n</ScrollView>\n"
  },
  {
    "path": "app/src/main/res/layout/dialog_bloatware_details.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<ScrollView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\">\n\n    <androidx.appcompat.widget.LinearLayoutCompat\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:paddingTop=\"@dimen/padding_small\"\n        android:paddingBottom=\"@dimen/padding_small\"\n        android:paddingStart=\"@dimen/padding_medium\"\n        android:paddingEnd=\"@dimen/padding_medium\"\n        android:orientation=\"vertical\">\n\n        <androidx.appcompat.widget.LinearLayoutCompat\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginBottom=\"@dimen/font_size_small\"\n            android:orientation=\"horizontal\">\n\n            <androidx.appcompat.widget.AppCompatImageView\n                android:id=\"@+id/icon\"\n                android:layout_width=\"@dimen/icon_size\"\n                android:layout_height=\"@dimen/icon_size\"\n                android:layout_weight=\"0\"\n                android:layout_gravity=\"center\"\n                android:layout_marginEnd=\"@dimen/padding_small\"\n                tools:srcCompat=\"@mipmap/ic_launcher_round\" />\n\n            <androidx.appcompat.widget.LinearLayoutCompat\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_weight=\"1\"\n                android:orientation=\"vertical\">\n\n                <com.google.android.material.textview.MaterialTextView\n                    android:id=\"@+id/name\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:textIsSelectable=\"true\"\n                    android:textAppearance=\"?attr/textAppearanceTitleMedium\"\n                    tools:text=\"@string/app_name\" />\n\n                <com.google.android.material.textview.MaterialTextView\n                    android:id=\"@+id/package_name\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:textIsSelectable=\"true\"\n                    android:textAppearance=\"?attr/textAppearanceBodySmall\"\n                    android:textStyle=\"italic\"\n                    tools:text=\"package.name\" />\n\n            </androidx.appcompat.widget.LinearLayoutCompat>\n\n            <com.google.android.material.button.MaterialButton\n                android:id=\"@+id/info\"\n                style=\"@style/Widget.AppTheme.Button.IconButton.InverseColor\"\n                android:layout_width=\"@dimen/icon_size\"\n                android:layout_height=\"@dimen/icon_size\"\n                android:layout_weight=\"0\"\n                android:layout_marginStart=\"@dimen/padding_small\"\n                android:layout_gravity=\"center\"\n                app:iconSize=\"30dp\"\n                app:icon=\"@drawable/ic_information\" />\n\n        </androidx.appcompat.widget.LinearLayoutCompat>\n\n        <io.github.muntashirakon.widget.FlowLayout\n            android:id=\"@+id/tag_cloud\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:gravity=\"start\"\n            tools:listItem=\"@layout/item_chip\" />\n\n        <io.github.muntashirakon.widget.MaterialAlertView\n            android:id=\"@+id/alert_text\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            app:alertType=\"warn\"\n            tools:text=\"An example warning.\" />\n\n        <com.google.android.material.textview.MaterialTextView\n            android:id=\"@+id/apk_description\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginTop=\"8dp\"\n            android:textAppearance=\"?attr/textAppearanceListItemSecondary\"\n            android:autoLink=\"web\"\n            android:textIsSelectable=\"true\"\n            tools:text=\"@tools:sample/lorem/random\" />\n\n        <androidx.appcompat.widget.LinearLayoutCompat\n            android:id=\"@+id/container\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:orientation=\"vertical\"\n            android:visibility=\"gone\">\n\n            <com.google.android.material.textview.MaterialTextView\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_marginTop=\"8dp\"\n                android:textAppearance=\"?attr/textAppearanceListItemSecondary\"\n                android:textStyle=\"bold\"\n                android:text=\"@string/title_alternatives_to_bloatware\" />\n\n            <io.github.muntashirakon.widget.RecyclerView\n                android:id=\"@+id/recycler_view\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:overScrollMode=\"never\" />\n\n        </androidx.appcompat.widget.LinearLayoutCompat>\n\n    </androidx.appcompat.widget.LinearLayoutCompat>\n</ScrollView>"
  },
  {
    "path": "app/src/main/res/layout/dialog_certificate_generator.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<io.github.muntashirakon.widget.NestedScrollView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:id=\"@+id/scrollView\"\n    android:layout_width=\"fill_parent\"\n    android:layout_height=\"wrap_content\"\n    android:fitsSystemWindows=\"true\"\n    android:clipToPadding=\"false\">\n\n    <androidx.appcompat.widget.LinearLayoutCompat\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:orientation=\"vertical\"\n        android:paddingStart=\"@dimen/padding_medium\"\n        android:paddingEnd=\"@dimen/padding_medium\">\n\n        <io.github.muntashirakon.widget.MaterialSpinner\n            style=\"@style/Widget.AppTheme.MaterialSpinner\"\n            android:id=\"@+id/key_size_selector_spinner\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginTop=\"@dimen/padding_small\"\n            android:hint=\"@string/crypto_key_size\" />\n\n        <com.google.android.material.textfield.TextInputLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:hint=\"@string/expiry_date\"\n            android:layout_marginTop=\"@dimen/padding_small\"\n            app:hintAnimationEnabled=\"true\"\n            app:hintEnabled=\"true\">\n\n            <com.google.android.material.textfield.TextInputEditText\n                android:id=\"@+id/expiry_date\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:singleLine=\"true\"\n                android:importantForAutofill=\"no\"\n                android:inputType=\"date\"\n                tools:text=\"@tools:sample/full_names\" />\n\n        </com.google.android.material.textfield.TextInputLayout>\n\n        <com.google.android.material.textfield.TextInputLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:hint=\"@string/common_name\"\n            android:layout_marginTop=\"@dimen/padding_small\"\n            app:hintAnimationEnabled=\"true\"\n            app:hintEnabled=\"true\">\n\n            <com.google.android.material.textfield.TextInputEditText\n                android:id=\"@+id/common_name\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:singleLine=\"true\"\n                android:importantForAutofill=\"no\"\n                android:inputType=\"text\"\n                tools:text=\"@tools:sample/full_names\" />\n\n        </com.google.android.material.textfield.TextInputLayout>\n\n        <com.google.android.material.textfield.TextInputLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:hint=\"@string/organization_unit\"\n            android:layout_marginTop=\"@dimen/padding_small\"\n            app:hintAnimationEnabled=\"true\"\n            app:hintEnabled=\"true\">\n\n            <com.google.android.material.textfield.TextInputEditText\n                android:id=\"@+id/organization_unit\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:singleLine=\"true\"\n                android:importantForAutofill=\"no\"\n                android:inputType=\"text\"\n                tools:text=\"@tools:sample/full_names\" />\n\n        </com.google.android.material.textfield.TextInputLayout>\n\n        <com.google.android.material.textfield.TextInputLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:hint=\"@string/organization_name\"\n            android:layout_marginTop=\"@dimen/padding_small\"\n            app:hintAnimationEnabled=\"true\"\n            app:hintEnabled=\"true\">\n\n            <com.google.android.material.textfield.TextInputEditText\n                android:id=\"@+id/organization_name\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:singleLine=\"true\"\n                android:importantForAutofill=\"no\"\n                android:inputType=\"text\"\n                tools:text=\"@tools:sample/full_names\" />\n\n        </com.google.android.material.textfield.TextInputLayout>\n\n        <com.google.android.material.textfield.TextInputLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:hint=\"@string/locality_name\"\n            android:layout_marginTop=\"@dimen/padding_small\"\n            app:hintAnimationEnabled=\"true\"\n            app:hintEnabled=\"true\">\n\n            <com.google.android.material.textfield.TextInputEditText\n                android:id=\"@+id/locality_name\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:singleLine=\"true\"\n                android:importantForAutofill=\"no\"\n                android:inputType=\"text\"\n                tools:text=\"@tools:sample/full_names\" />\n\n        </com.google.android.material.textfield.TextInputLayout>\n\n        <com.google.android.material.textfield.TextInputLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:hint=\"@string/state_name\"\n            android:layout_marginTop=\"@dimen/padding_small\"\n            app:hintAnimationEnabled=\"true\"\n            app:hintEnabled=\"true\">\n\n            <com.google.android.material.textfield.TextInputEditText\n                android:id=\"@+id/state_name\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:singleLine=\"true\"\n                android:importantForAutofill=\"no\"\n                android:inputType=\"text\"\n                tools:text=\"@tools:sample/full_names\" />\n\n        </com.google.android.material.textfield.TextInputLayout>\n\n        <com.google.android.material.textfield.TextInputLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:hint=\"@string/country_name\"\n            android:layout_marginTop=\"@dimen/padding_small\"\n            app:hintAnimationEnabled=\"true\"\n            app:hintEnabled=\"true\">\n\n            <com.google.android.material.textfield.TextInputEditText\n                android:id=\"@+id/country_name\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:singleLine=\"true\"\n                android:importantForAutofill=\"no\"\n                android:inputType=\"text\"\n                tools:text=\"@tools:sample/full_names\" />\n\n        </com.google.android.material.textfield.TextInputLayout>\n\n    </androidx.appcompat.widget.LinearLayoutCompat>\n\n</io.github.muntashirakon.widget.NestedScrollView>\n"
  },
  {
    "path": "app/src/main/res/layout/dialog_change_file_mode.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<androidx.appcompat.widget.LinearLayoutCompat xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\"\n    android:paddingHorizontal=\"16dp\">\n\n    <androidx.appcompat.widget.LinearLayoutCompat\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:orientation=\"horizontal\">\n\n        <androidx.appcompat.widget.LinearLayoutCompat\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_weight=\"1\"\n            android:orientation=\"vertical\">\n\n            <com.google.android.material.textview.MaterialTextView\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:singleLine=\"true\" />\n\n            <com.google.android.material.textview.MaterialTextView\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"32dp\"\n                android:gravity=\"center_vertical\"\n                android:singleLine=\"true\"\n                android:text=\"Owner\" />\n\n            <com.google.android.material.textview.MaterialTextView\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"32dp\"\n                android:gravity=\"center_vertical\"\n                android:singleLine=\"true\"\n                android:text=\"Group\" />\n\n            <com.google.android.material.textview.MaterialTextView\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"32dp\"\n                android:gravity=\"center_vertical\"\n                android:singleLine=\"true\"\n                android:text=\"Others\" />\n\n        </androidx.appcompat.widget.LinearLayoutCompat>\n\n        <androidx.appcompat.widget.LinearLayoutCompat\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_weight=\"1\"\n            android:layout_marginStart=\"8dp\"\n            android:gravity=\"center\"\n            android:orientation=\"vertical\">\n\n            <com.google.android.material.textview.MaterialTextView\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:singleLine=\"true\"\n                android:text=\"Read\" />\n\n            <com.google.android.material.checkbox.MaterialCheckBox\n                android:id=\"@+id/user_read\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\" />\n\n            <com.google.android.material.checkbox.MaterialCheckBox\n                android:id=\"@+id/group_read\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\" />\n\n            <com.google.android.material.checkbox.MaterialCheckBox\n                android:id=\"@+id/others_read\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\" />\n\n        </androidx.appcompat.widget.LinearLayoutCompat>\n\n        <androidx.appcompat.widget.LinearLayoutCompat\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_weight=\"1\"\n            android:layout_marginStart=\"8dp\"\n            android:gravity=\"center\"\n            android:orientation=\"vertical\">\n\n            <com.google.android.material.textview.MaterialTextView\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:singleLine=\"true\"\n                android:text=\"Write\" />\n\n            <com.google.android.material.checkbox.MaterialCheckBox\n                android:id=\"@+id/user_write\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\" />\n\n            <com.google.android.material.checkbox.MaterialCheckBox\n                android:id=\"@+id/group_write\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\" />\n\n            <com.google.android.material.checkbox.MaterialCheckBox\n                android:id=\"@+id/others_write\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\" />\n\n        </androidx.appcompat.widget.LinearLayoutCompat>\n\n        <androidx.appcompat.widget.LinearLayoutCompat\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_weight=\"1\"\n            android:layout_marginStart=\"8dp\"\n            android:gravity=\"center\"\n            android:orientation=\"vertical\">\n\n            <com.google.android.material.textview.MaterialTextView\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:singleLine=\"true\"\n                android:text=\"Execute\" />\n\n            <com.google.android.material.checkbox.MaterialCheckBox\n                android:id=\"@+id/user_exec\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\" />\n\n            <com.google.android.material.checkbox.MaterialCheckBox\n                android:id=\"@+id/group_exec\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\" />\n\n            <com.google.android.material.checkbox.MaterialCheckBox\n                android:id=\"@+id/others_exec\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\" />\n\n        </androidx.appcompat.widget.LinearLayoutCompat>\n\n    </androidx.appcompat.widget.LinearLayoutCompat>\n\n    <com.google.android.material.materialswitch.MaterialSwitch\n        style=\"@style/Widget.AppTheme.MaterialSwitch\"\n        android:id=\"@+id/uid_bit\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:text=\"set-user-ID bit\" />\n\n    <com.google.android.material.materialswitch.MaterialSwitch\n        style=\"@style/Widget.AppTheme.MaterialSwitch\"\n        android:id=\"@+id/gid_bit\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:text=\"set-group-ID bit\" />\n\n    <com.google.android.material.materialswitch.MaterialSwitch\n        style=\"@style/Widget.AppTheme.MaterialSwitch\"\n        android:id=\"@+id/sticky_bit\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:text=\"sticky bit\" />\n\n    <com.google.android.material.textfield.TextInputLayout\n        style=\"@style/Widget.AppTheme.TextInputLayout.Small\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginBottom=\"@dimen/padding_small\">\n\n        <io.github.muntashirakon.widget.TextInputTextView\n            android:id=\"@+id/preview\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:inputType=\"none\"\n            android:textIsSelectable=\"true\"\n            tools:text=\"rwxr-xr-x (0755)\" />\n\n    </com.google.android.material.textfield.TextInputLayout>\n\n    <com.google.android.material.checkbox.MaterialCheckBox\n        android:id=\"@+id/checkbox\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:text=\"@string/apply_recursively\" />\n\n</androidx.appcompat.widget.LinearLayoutCompat>"
  },
  {
    "path": "app/src/main/res/layout/dialog_checksums.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<ScrollView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n\n    <androidx.appcompat.widget.LinearLayoutCompat\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:orientation=\"vertical\">\n\n        <androidx.recyclerview.widget.RecyclerView\n            android:id=\"@+id/recycler_view\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_weight=\"1\"\n            android:scrollbars=\"vertical\"\n            tools:listitem=\"@layout/item_icon_title_subtitle\" />\n\n        <androidx.appcompat.widget.LinearLayoutCompat\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginVertical=\"@dimen/padding_small\"\n            android:orientation=\"horizontal\">\n\n            <io.github.muntashirakon.widget.MaterialSpinner\n                android:id=\"@+id/spinner\"\n                style=\"@style/Widget.AppTheme.MaterialSpinner.Spinner.Small\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_gravity=\"center_vertical|start\"\n                android:layout_marginHorizontal=\"@dimen/padding_large\"\n                android:layout_weight=\"1\"\n                tools:hint=\"SHA3-512\" />\n\n            <com.google.android.material.button.MaterialButton\n                android:id=\"@+id/action\"\n                style=\"@style/Widget.AppTheme.Button.FilledButton\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_gravity=\"center_vertical|end\"\n                android:layout_marginVertical=\"0dp\"\n                android:layout_marginTop=\"4dp\"\n                android:layout_marginEnd=\"@dimen/padding_large\"\n                android:text=\"@string/generate_key\" />\n\n        </androidx.appcompat.widget.LinearLayoutCompat>\n\n        <com.google.android.material.textfield.TextInputLayout\n            style=\"@style/Widget.AppTheme.TextInputLayout.Small\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginBottom=\"@dimen/padding_small\"\n            android:paddingHorizontal=\"@dimen/padding_medium\"\n            app:hintEnabled=\"false\">\n\n            <io.github.muntashirakon.widget.TextInputTextView\n                android:id=\"@+id/text\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:inputType=\"none\"\n                android:textIsSelectable=\"true\"\n                tools:text=\"19d8adc99d22cd9ebc08786b7982744be94daccc9b3f1725812a776789278f0d\" />\n\n        </com.google.android.material.textfield.TextInputLayout>\n\n    </androidx.appcompat.widget.LinearLayoutCompat>\n</ScrollView>\n"
  },
  {
    "path": "app/src/main/res/layout/dialog_create_shortcut.xml",
    "content": "<!-- SPDX-License-Identifier: ISC AND GPL-3.0-or-later -->\n<ScrollView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n\n    <androidx.appcompat.widget.LinearLayoutCompat\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:orientation=\"vertical\"\n        android:paddingVertical=\"@dimen/padding_small\"\n        android:paddingHorizontal=\"@dimen/padding_medium\">\n\n        <com.google.android.material.textfield.TextInputLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:hint=\"@string/shortcut_name\"\n            app:hintAnimationEnabled=\"true\"\n            app:hintEnabled=\"true\">\n\n            <com.google.android.material.textfield.TextInputEditText\n                android:id=\"@+id/shortcut_name\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:singleLine=\"true\"\n                tools:text=\"@tools:sample/full_names\" />\n\n        </com.google.android.material.textfield.TextInputLayout>\n\n        <com.google.android.material.textfield.TextInputLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:hint=\"@string/shortcut_icon\"\n            app:endIconMode=\"custom\"\n            app:endIconDrawable=\"@drawable/ic_refresh\"\n            app:endIconContentDescription=\"@string/icon_picker\"\n            app:hintAnimationEnabled=\"true\"\n            app:hintEnabled=\"true\">\n\n            <com.google.android.material.textfield.TextInputEditText\n                android:id=\"@+id/insert_icon\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:singleLine=\"true\"\n                tools:text=\"@tools:sample/full_names\" />\n\n        </com.google.android.material.textfield.TextInputLayout>\n\n        <androidx.appcompat.widget.LinearLayoutCompat\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_gravity=\"center_horizontal\"\n            android:layout_marginHorizontal=\"16dp\"\n            android:layout_marginTop=\"8dp\"\n            android:padding=\"16dp\"\n            android:orientation=\"vertical\"\n            android:background=\"@drawable/dashed_border\">\n\n            <com.google.android.material.imageview.ShapeableImageView\n                android:id=\"@+id/icon\"\n                android:layout_width=\"200dp\"\n                android:layout_height=\"200dp\"\n                android:layout_gravity=\"center\"\n                android:scaleType=\"fitCenter\"\n                android:adjustViewBounds=\"true\"\n                android:minHeight=\"200dp\"\n                android:minWidth=\"200dp\"\n                app:shapeAppearanceOverlay=\"@style/ShapeAppearance.AppTheme.CircleComponent\"\n                app:srcCompat=\"@drawable/ic_image\" />\n\n            <com.google.android.material.textview.MaterialTextView\n                android:id=\"@+id/name\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:gravity=\"center_horizontal\"\n                android:layout_marginTop=\"16dp\"\n                android:maxLines=\"1\"\n                android:ellipsize=\"end\"\n                tools:text=\"@tools:sample/lorem[4]\" />\n\n        </androidx.appcompat.widget.LinearLayoutCompat>\n\n    </androidx.appcompat.widget.LinearLayoutCompat>\n</ScrollView>"
  },
  {
    "path": "app/src/main/res/layout/dialog_debloater_list_options.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<androidx.core.widget.NestedScrollView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    android:scrollbars=\"vertical\"\n    android:scrollIndicators=\"top|bottom\"\n    tools:ignore=\"UnusedAttribute\">\n\n    <androidx.appcompat.widget.LinearLayoutCompat\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:paddingVertical=\"@dimen/padding_small\"\n        android:paddingHorizontal=\"@dimen/padding_medium\"\n        android:orientation=\"vertical\">\n\n        <com.google.android.material.textview.MaterialTextView\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:textAppearance=\"@style/TextAppearance.AppTheme.TitleSmall\"\n            android:text=\"@string/debloat_list_type\" />\n\n        <com.google.android.material.chip.ChipGroup\n            android:id=\"@+id/list_types\"\n            android:theme=\"@style/Widget.AppTheme.ChipGroup.Filter\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:paddingVertical=\"@dimen/padding_very_small\"\n            app:itemSpacing=\"@dimen/padding_very_small\"\n            app:lineSpacing=\"@dimen/padding_very_small\" />\n\n        <com.google.android.material.textview.MaterialTextView\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:textAppearance=\"@style/TextAppearance.AppTheme.TitleSmall\"\n            android:text=\"@string/debloat_removal_type\" />\n\n        <com.google.android.material.chip.ChipGroup\n            android:id=\"@+id/removal_types\"\n            android:theme=\"@style/Widget.AppTheme.ChipGroup.Filter\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:paddingVertical=\"@dimen/padding_very_small\"\n            app:itemSpacing=\"@dimen/padding_very_small\"\n            app:lineSpacing=\"@dimen/padding_very_small\" />\n\n        <com.google.android.material.textview.MaterialTextView\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:textAppearance=\"@style/TextAppearance.AppTheme.TitleSmall\"\n            android:text=\"@string/filter\" />\n\n        <com.google.android.material.chip.ChipGroup\n            android:id=\"@+id/filter_options\"\n            android:theme=\"@style/Widget.AppTheme.ChipGroup.Filter\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:paddingVertical=\"@dimen/padding_very_small\"\n            app:itemSpacing=\"@dimen/padding_very_small\"\n            app:lineSpacing=\"@dimen/padding_very_small\" />\n\n    </androidx.appcompat.widget.LinearLayoutCompat>\n\n</androidx.core.widget.NestedScrollView>"
  },
  {
    "path": "app/src/main/res/layout/dialog_dexopt.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<ScrollView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:scrollIndicators=\"top|bottom\"\n    tools:ignore=\"UnusedAttribute\">\n\n    <androidx.appcompat.widget.LinearLayoutCompat\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:orientation=\"vertical\"\n        android:paddingHorizontal=\"@dimen/padding_medium\">\n\n        <com.google.android.material.textfield.TextInputLayout\n            style=\"@style/Widget.AppTheme.TextInputLayout.ExposedDropdownMenu\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:hint=\"@string/select_a_dex2oat_compiler_filter\"\n            app:hintAnimationEnabled=\"true\"\n            app:hintEnabled=\"true\">\n\n            <io.github.muntashirakon.widget.MaterialAutoCompleteTextView\n                android:id=\"@+id/compiler_filter\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:inputType=\"textNoSuggestions\"\n                android:maxLines=\"1\"\n                tools:text=\"@tools:sample/full_names\" />\n\n        </com.google.android.material.textfield.TextInputLayout>\n\n        <com.google.android.material.checkbox.MaterialCheckBox\n            android:id=\"@+id/compile_layouts\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:text=\"@string/optimize_option_compile_layouts\" />\n\n        <com.google.android.material.checkbox.MaterialCheckBox\n            android:id=\"@+id/clear_profile_data\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:text=\"@string/optimize_option_clear_profile_data\" />\n\n        <com.google.android.material.checkbox.MaterialCheckBox\n            android:id=\"@+id/check_profiles\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:text=\"@string/optimize_option_check_profiles\" />\n\n        <com.google.android.material.checkbox.MaterialCheckBox\n            android:id=\"@+id/force_compilation\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:text=\"@string/optimize_option_force_compilation\" />\n\n        <com.google.android.material.checkbox.MaterialCheckBox\n            android:id=\"@+id/force_dexopt\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:text=\"@string/optimize_option_force_dexopt\" />\n\n    </androidx.appcompat.widget.LinearLayoutCompat>\n</ScrollView>"
  },
  {
    "path": "app/src/main/res/layout/dialog_disclaimer.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<ScrollView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:scrollIndicators=\"top|bottom\"\n    tools:ignore=\"UnusedAttribute\">\n\n    <androidx.appcompat.widget.LinearLayoutCompat\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:orientation=\"vertical\"\n        android:paddingStart=\"@dimen/padding_medium\"\n        android:paddingTop=\"@dimen/padding_very_small\"\n        android:paddingEnd=\"@dimen/padding_medium\"\n        android:paddingBottom=\"@dimen/padding_very_small\">\n\n        <androidx.appcompat.widget.AppCompatTextView\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:paddingTop=\"@dimen/padding_small\"\n            android:paddingBottom=\"@dimen/padding_small\"\n            android:gravity=\"center_horizontal\"\n            android:textAppearance=\"?attr/textAppearanceTitleMedium\"\n            android:textAllCaps=\"true\"\n            android:text=\"@string/disclaimer_header\" />\n\n        <androidx.appcompat.widget.AppCompatTextView\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:text=\"@string/disclaimer_body\" />\n\n        <androidx.appcompat.widget.AppCompatTextView\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginTop=\"@dimen/padding_medium\"\n            android:text=\"@string/disclaimer_footer\" />\n\n        <com.google.android.material.checkbox.MaterialCheckBox\n            android:id=\"@+id/agree_forever\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:text=\"@string/disclaimer_agree_forever\" />\n\n    </androidx.appcompat.widget.LinearLayoutCompat>\n\n</ScrollView>\n"
  },
  {
    "path": "app/src/main/res/layout/dialog_edit_filter_item.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<androidx.appcompat.widget.LinearLayoutCompat xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\">\n\n    <io.github.muntashirakon.widget.MaterialAlertView\n        android:id=\"@+id/message\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginHorizontal=\"@dimen/padding_medium\"\n        android:layout_marginVertical=\"@dimen/padding_small\"\n        android:visibility=\"gone\"\n        app:alertType=\"warn\"\n        tools:text=\"Some filters may increase the loading time if used in the Main page.\"\n        tools:visibility=\"visible\" />\n\n    <io.github.muntashirakon.widget.RecyclerView\n        android:id=\"@android:id/list\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_weight=\"1\"\n        android:scrollbars=\"vertical\"\n        tools:listitem=\"@layout/item_icon_title_subtitle\" />\n\n\n    <com.google.android.material.textfield.TextInputLayout\n        android:id=\"@+id/editor_container\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginHorizontal=\"@dimen/padding_medium\"\n        app:hintEnabled=\"false\">\n\n        <com.google.android.material.textfield.TextInputEditText\n            android:id=\"@+id/editor\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:maxHeight=\"85dp\"\n            android:gravity=\"left|top\"\n            android:inputType=\"textMultiLine\"\n            tools:ignore=\"RtlHardcoded\"\n            tools:text=\"@tools:sample/lorem/random\" />\n\n    </com.google.android.material.textfield.TextInputLayout>\n\n</androidx.appcompat.widget.LinearLayoutCompat>\n"
  },
  {
    "path": "app/src/main/res/layout/dialog_edit_filter_option.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<ScrollView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\">\n\n    <androidx.appcompat.widget.LinearLayoutCompat\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:orientation=\"vertical\"\n        android:paddingHorizontal=\"@dimen/padding_medium\"\n        android:paddingVertical=\"@dimen/padding_small\">\n\n        <io.github.muntashirakon.widget.MaterialSpinner\n            style=\"@style/Widget.AppTheme.MaterialSpinner\"\n            android:id=\"@+id/filter_selector_spinner\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:hint=\"@string/select_filter\" />\n\n        <io.github.muntashirakon.widget.MaterialSpinner\n            style=\"@style/Widget.AppTheme.MaterialSpinner\"\n            android:id=\"@+id/type_selector_spinner\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:hint=\"@string/select_type\" />\n\n        <com.google.android.material.textfield.TextInputLayout\n            android:visibility=\"gone\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:hint=\"@string/string_value\"\n            app:hintAnimationEnabled=\"true\"\n            app:hintEnabled=\"true\"\n            tools:visibility=\"visible\">\n\n            <com.google.android.material.textfield.TextInputEditText\n                android:id=\"@+id/input_string\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:singleLine=\"true\"\n                android:importantForAutofill=\"no\"\n                android:inputType=\"textMultiLine\"\n                tools:text=\"@tools:sample/full_names\" />\n\n        </com.google.android.material.textfield.TextInputLayout>\n\n        <com.google.android.material.textfield.TextInputLayout\n            android:visibility=\"gone\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:hint=\"@string/string_value\"\n            app:hintAnimationEnabled=\"true\"\n            app:hintEnabled=\"true\"\n            tools:visibility=\"visible\">\n\n            <com.google.android.material.textfield.TextInputEditText\n                android:id=\"@android:id/input\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:singleLine=\"true\"\n                android:importantForAutofill=\"no\"\n                android:inputType=\"textMultiLine\"\n                tools:text=\"@tools:sample/full_names\" />\n\n        </com.google.android.material.textfield.TextInputLayout>\n\n        <io.github.muntashirakon.widget.RecyclerView\n            android:id=\"@+id/recycler_view\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:overScrollMode=\"never\" />\n\n    </androidx.appcompat.widget.LinearLayoutCompat>\n</ScrollView>"
  },
  {
    "path": "app/src/main/res/layout/dialog_edit_pref_item.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<ScrollView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\">\n\n    <androidx.appcompat.widget.LinearLayoutCompat\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:orientation=\"vertical\"\n        android:paddingHorizontal=\"@dimen/padding_medium\"\n        android:paddingVertical=\"@dimen/padding_small\">\n\n        <io.github.muntashirakon.widget.MaterialSpinner\n            style=\"@style/Widget.AppTheme.MaterialSpinner\"\n            android:id=\"@+id/type_selector_spinner\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:hint=\"@string/select_type\" />\n\n        <com.google.android.material.textfield.TextInputLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:hint=\"@string/key_name\"\n            app:hintAnimationEnabled=\"true\"\n            app:hintEnabled=\"true\">\n\n            <com.google.android.material.textfield.TextInputEditText\n                android:id=\"@+id/key_name\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:singleLine=\"true\"\n                android:importantForAutofill=\"no\"\n                android:inputType=\"text\"\n                android:scrollHorizontally=\"true\"\n                android:textIsSelectable=\"true\"\n                tools:text=\"@tools:sample/full_names\" />\n\n        </com.google.android.material.textfield.TextInputLayout>\n\n        <androidx.appcompat.widget.LinearLayoutCompat\n            android:id=\"@+id/layout_bool\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:visibility=\"gone\"\n            android:layout_marginTop=\"@dimen/padding_small\"\n            android:layout_marginBottom=\"@dimen/padding_small\"\n            android:orientation=\"horizontal\">\n\n            <com.google.android.material.materialswitch.MaterialSwitch\n                style=\"@style/Widget.AppTheme.MaterialSwitch\"\n                android:id=\"@+id/input_bool\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:text=\"@string/boolean_value\" />\n\n        </androidx.appcompat.widget.LinearLayoutCompat>\n\n        <com.google.android.material.textfield.TextInputLayout\n            android:id=\"@+id/layout_float\"\n            android:visibility=\"gone\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:hint=\"@string/decimal_value\"\n            app:hintAnimationEnabled=\"true\"\n            app:hintEnabled=\"true\">\n\n            <com.google.android.material.textfield.TextInputEditText\n                android:id=\"@+id/input_float\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:singleLine=\"true\"\n                android:importantForAutofill=\"no\"\n                android:inputType=\"numberDecimal\"\n                tools:text=\"@tools:sample/full_names\" />\n\n        </com.google.android.material.textfield.TextInputLayout>\n\n        <com.google.android.material.textfield.TextInputLayout\n            android:id=\"@+id/layout_int\"\n            android:visibility=\"gone\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:hint=\"@string/integer_value\"\n            app:hintAnimationEnabled=\"true\"\n            app:hintEnabled=\"true\">\n\n            <com.google.android.material.textfield.TextInputEditText\n                android:id=\"@+id/input_int\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:singleLine=\"true\"\n                android:importantForAutofill=\"no\"\n                android:inputType=\"number\"\n                tools:text=\"@tools:sample/full_names\" />\n\n        </com.google.android.material.textfield.TextInputLayout>\n\n        <com.google.android.material.textfield.TextInputLayout\n            android:id=\"@+id/layout_long\"\n            android:visibility=\"gone\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:hint=\"@string/long_integer_value\"\n            app:hintAnimationEnabled=\"true\"\n            app:hintEnabled=\"true\">\n\n            <com.google.android.material.textfield.TextInputEditText\n                android:id=\"@+id/input_long\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:singleLine=\"true\"\n                android:importantForAutofill=\"no\"\n                android:inputType=\"number\"\n                tools:text=\"@tools:sample/full_names\" />\n\n        </com.google.android.material.textfield.TextInputLayout>\n\n        <com.google.android.material.textfield.TextInputLayout\n            android:id=\"@+id/layout_string\"\n            android:visibility=\"gone\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:hint=\"@string/string_value\"\n            app:hintAnimationEnabled=\"true\"\n            app:hintEnabled=\"true\">\n\n            <com.google.android.material.textfield.TextInputEditText\n                android:id=\"@+id/input_string\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:singleLine=\"true\"\n                android:importantForAutofill=\"no\"\n                android:inputType=\"textMultiLine\"\n                tools:text=\"@tools:sample/full_names\" />\n\n        </com.google.android.material.textfield.TextInputLayout>\n\n    </androidx.appcompat.widget.LinearLayoutCompat>\n</ScrollView>"
  },
  {
    "path": "app/src/main/res/layout/dialog_file_properties.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<ScrollView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n\n    <androidx.appcompat.widget.LinearLayoutCompat\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:orientation=\"vertical\"\n        android:paddingHorizontal=\"@dimen/padding_small\"\n        android:paddingVertical=\"@dimen/padding_medium\">\n\n        <androidx.appcompat.widget.LinearLayoutCompat\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginBottom=\"@dimen/padding_small\"\n            android:orientation=\"horizontal\">\n\n            <FrameLayout\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_gravity=\"center\"\n                android:layout_marginEnd=\"@dimen/padding_small\"\n                android:layout_weight=\"0\">\n\n                <com.google.android.material.imageview.ShapeableImageView\n                    android:id=\"@android:id/icon\"\n                    android:layout_width=\"48dp\"\n                    android:layout_height=\"48dp\"\n                    android:layout_gravity=\"center\"\n                    android:background=\"@color/fm_icon_background\"\n                    android:contentDescription=\"@string/str_logo\"\n                    app:shapeAppearanceOverlay=\"@style/ShapeAppearance.AppTheme.SmallComponent\"\n                    tools:srcCompat=\"@mipmap/ic_launcher_round\" />\n\n                <com.google.android.material.imageview.ShapeableImageView\n                    android:id=\"@+id/symbolic_link_icon\"\n                    android:layout_width=\"20dp\"\n                    android:layout_height=\"20dp\"\n                    android:layout_gravity=\"start|bottom\"\n                    android:tint=\"@color/fm_symbolic_link\"\n                    android:visibility=\"gone\"\n                    app:srcCompat=\"@drawable/ic_arrow_outward\"\n                    tools:visibility=\"visible\" />\n\n                <com.google.android.material.imageview.ShapeableImageView\n                    android:id=\"@android:id/icon1\"\n                    android:layout_width=\"20dp\"\n                    android:layout_height=\"20dp\"\n                    android:layout_gravity=\"end|bottom\"\n                    android:visibility=\"gone\"\n                    app:shapeAppearanceOverlay=\"@style/ShapeAppearance.AppTheme.SmallComponent\"\n                    tools:srcCompat=\"@drawable/ic_repeat\"\n                    tools:visibility=\"visible\" />\n            </FrameLayout>\n\n            <androidx.appcompat.widget.LinearLayoutCompat\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_weight=\"1\"\n                android:orientation=\"vertical\">\n\n                <com.google.android.material.textview.MaterialTextView\n                    android:id=\"@+id/name\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:textAppearance=\"?attr/textAppearanceTitleMedium\"\n                    android:textIsSelectable=\"true\"\n                    tools:text=\"AppManager_v3.0.3.apk\" />\n\n                <androidx.appcompat.widget.LinearLayoutCompat\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:orientation=\"horizontal\">\n\n                    <com.google.android.material.textview.MaterialTextView\n                        android:id=\"@+id/summary\"\n                        android:layout_width=\"wrap_content\"\n                        android:layout_height=\"wrap_content\"\n                        android:textAppearance=\"?attr/textAppearanceBodySmall\"\n                        android:textIsSelectable=\"true\"\n                        tools:text=\"4/11/22 15:28 ● 14.1 MB\" />\n\n                    <com.google.android.material.textview.MaterialTextView\n                        android:id=\"@+id/checksums\"\n                        android:layout_width=\"wrap_content\"\n                        android:layout_height=\"wrap_content\"\n                        android:background=\"?android:selectableItemBackground\"\n                        android:paddingHorizontal=\"@dimen/padding_small\"\n                        android:text=\"@string/checksums\"\n                        android:textAppearance=\"?attr/textAppearanceBodySmall\"\n                        android:textColor=\"?android:textColorLink\" />\n\n                </androidx.appcompat.widget.LinearLayoutCompat>\n\n            </androidx.appcompat.widget.LinearLayoutCompat>\n\n            <com.google.android.material.button.MaterialButton\n                android:id=\"@+id/more\"\n                style=\"@style/Widget.AppTheme.Button.IconButton.InverseColor\"\n                android:layout_width=\"@dimen/icon_size\"\n                android:layout_height=\"@dimen/icon_size\"\n                android:layout_gravity=\"center\"\n                android:layout_marginStart=\"@dimen/padding_small\"\n                android:layout_weight=\"0\"\n                android:contentDescription=\"@string/more_info\"\n                app:icon=\"@drawable/ic_more_vert\"\n                app:iconSize=\"30dp\" />\n\n        </androidx.appcompat.widget.LinearLayoutCompat>\n\n        <com.google.android.material.textfield.TextInputLayout\n            style=\"@style/Widget.AppTheme.TextInputLayout.Small\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginBottom=\"@dimen/padding_small\"\n            android:hint=\"@string/file\"\n            app:hintEnabled=\"true\">\n\n            <io.github.muntashirakon.widget.TextInputTextView\n                android:id=\"@+id/path\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:inputType=\"none\"\n                android:textIsSelectable=\"true\"\n                tools:text=\"/storage/emulated/0/AppManager_v3.0.3.apk\" />\n\n        </com.google.android.material.textfield.TextInputLayout>\n\n        <com.google.android.material.textfield.TextInputLayout\n            style=\"@style/Widget.AppTheme.TextInputLayout.Small\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginBottom=\"@dimen/padding_small\"\n            android:hint=\"@string/type\"\n            app:hintEnabled=\"true\">\n\n            <io.github.muntashirakon.widget.TextInputTextView\n                android:id=\"@+id/type\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:inputType=\"none\"\n                android:textIsSelectable=\"true\"\n                tools:text=\"application/vnd.android.package-archive\" />\n\n        </com.google.android.material.textfield.TextInputLayout>\n\n        <com.google.android.material.textfield.TextInputLayout\n            style=\"@style/Widget.AppTheme.TextInputLayout.Small\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginBottom=\"@dimen/padding_small\"\n            android:hint=\"@string/file_shortcut_target_file\"\n            app:hintEnabled=\"true\">\n\n            <io.github.muntashirakon.widget.TextInputTextView\n                android:id=\"@+id/target_file\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:inputType=\"none\"\n                android:textIsSelectable=\"true\"\n                tools:text=\"/storage/emulated/0/AppManager_v3.0.3.apk\" />\n\n        </com.google.android.material.textfield.TextInputLayout>\n\n        <com.google.android.material.textfield.TextInputLayout\n            style=\"@style/Widget.AppTheme.TextInputLayout.Small\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginBottom=\"@dimen/padding_small\"\n            android:hint=\"@string/file_open_with\"\n            app:endIconCheckable=\"false\"\n            app:endIconContentDescription=\"@string/file_change_open_with\"\n            app:endIconDrawable=\"@drawable/ic_file_replace\"\n            app:endIconMode=\"custom\"\n            app:hintEnabled=\"true\"\n            app:startIconContentDescription=\"@string/str_logo\"\n            app:startIconDrawable=\"@null\">\n\n            <io.github.muntashirakon.widget.TextInputTextView\n                android:id=\"@+id/open_with\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:inputType=\"none\"\n                android:text=\"@string/_undefined\"\n                android:textIsSelectable=\"true\"\n                tools:text=\"App Manager - installer\" />\n\n        </com.google.android.material.textfield.TextInputLayout>\n\n        <androidx.appcompat.widget.LinearLayoutCompat\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:orientation=\"horizontal\">\n\n            <com.google.android.material.textfield.TextInputLayout\n                style=\"@style/Widget.AppTheme.TextInputLayout.Small\"\n                android:layout_width=\"0dp\"\n                android:layout_height=\"wrap_content\"\n                android:layout_marginEnd=\"4dp\"\n                android:layout_marginBottom=\"@dimen/padding_small\"\n                android:layout_weight=\"1\"\n                android:hint=\"@string/size\"\n                app:hintEnabled=\"true\">\n\n                <io.github.muntashirakon.widget.TextInputTextView\n                    android:id=\"@+id/size\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:inputType=\"none\"\n                    android:maxLines=\"2\"\n                    android:text=\"@string/calculating_file_size\"\n                    android:textIsSelectable=\"true\"\n                    tools:text=\"14.1 MB (13,831,425 bytes)\" />\n\n            </com.google.android.material.textfield.TextInputLayout>\n\n            <com.google.android.material.textfield.TextInputLayout\n                style=\"@style/Widget.AppTheme.TextInputLayout.Small\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_marginStart=\"4dp\"\n                android:layout_marginBottom=\"@dimen/padding_small\"\n                android:layout_weight=\"0\"\n                android:hint=\"@string/file_creation_date\"\n                app:hintEnabled=\"true\">\n\n                <io.github.muntashirakon.widget.TextInputTextView\n                    android:id=\"@+id/date_created\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:inputType=\"none\"\n                    android:maxLines=\"2\"\n                    android:textIsSelectable=\"true\"\n                    tools:text=\"4/11/22 15:24\" />\n\n            </com.google.android.material.textfield.TextInputLayout>\n\n        </androidx.appcompat.widget.LinearLayoutCompat>\n\n        <androidx.appcompat.widget.LinearLayoutCompat\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:orientation=\"horizontal\">\n\n            <com.google.android.material.textfield.TextInputLayout\n                style=\"@style/Widget.AppTheme.TextInputLayout.Small\"\n                android:layout_width=\"0dp\"\n                android:layout_height=\"wrap_content\"\n                android:layout_marginEnd=\"4dp\"\n                android:layout_marginBottom=\"@dimen/padding_small\"\n                android:layout_weight=\"1\"\n                android:hint=\"@string/file_modification_date\"\n                app:endIconCheckable=\"false\"\n                app:endIconContentDescription=\"@string/modify_last_modification_time\"\n                app:endIconDrawable=\"@drawable/ic_touch_app\"\n                app:endIconMode=\"custom\"\n                app:hintEnabled=\"true\">\n\n                <io.github.muntashirakon.widget.TextInputTextView\n                    android:id=\"@+id/date_modified\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:inputType=\"none\"\n                    android:maxLines=\"2\"\n                    android:textIsSelectable=\"true\"\n                    tools:text=\"4/11/22 15:28\" />\n\n            </com.google.android.material.textfield.TextInputLayout>\n\n            <com.google.android.material.textfield.TextInputLayout\n                style=\"@style/Widget.AppTheme.TextInputLayout.Small\"\n                android:layout_width=\"0dp\"\n                android:layout_height=\"wrap_content\"\n                android:layout_marginStart=\"4dp\"\n                android:layout_marginBottom=\"@dimen/padding_small\"\n                android:layout_weight=\"1\"\n                android:hint=\"@string/file_accessed_date\"\n                app:endIconContentDescription=\"@string/modify_last_access_time\"\n                app:endIconDrawable=\"@drawable/ic_touch_app\"\n                app:endIconMode=\"custom\"\n                app:endIconCheckable=\"false\"\n                app:hintEnabled=\"true\">\n\n                <io.github.muntashirakon.widget.TextInputTextView\n                    android:id=\"@+id/date_accessed\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:inputType=\"none\"\n                    android:maxLines=\"2\"\n                    android:textIsSelectable=\"true\"\n                    tools:text=\"16/11/22 12:53\" />\n\n            </com.google.android.material.textfield.TextInputLayout>\n\n        </androidx.appcompat.widget.LinearLayoutCompat>\n\n        <com.google.android.material.textfield.TextInputLayout\n            style=\"@style/Widget.AppTheme.TextInputLayout.Small\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginBottom=\"@dimen/padding_small\"\n            android:hint=\"@string/more_info\"\n            app:hintEnabled=\"true\">\n\n            <io.github.muntashirakon.widget.TextInputTextView\n                android:id=\"@+id/more_info\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:inputType=\"none\"\n                android:maxLines=\"2\"\n                android:textIsSelectable=\"true\"\n                tools:text=\"@tools:sample/lorem/random\" />\n\n        </com.google.android.material.textfield.TextInputLayout>\n\n        <androidx.appcompat.widget.LinearLayoutCompat\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:orientation=\"horizontal\">\n\n            <com.google.android.material.textfield.TextInputLayout\n                style=\"@style/Widget.AppTheme.TextInputLayout.Small\"\n                android:layout_width=\"0dp\"\n                android:layout_height=\"wrap_content\"\n                android:layout_marginEnd=\"4dp\"\n                android:layout_marginBottom=\"@dimen/padding_small\"\n                android:layout_weight=\"1\"\n                android:hint=\"@string/file_owner_id\"\n                app:endIconCheckable=\"false\"\n                app:endIconContentDescription=\"@string/change_owner_uid\"\n                app:endIconDrawable=\"@drawable/ic_edit\"\n                app:endIconMode=\"custom\"\n                app:hintEnabled=\"true\">\n\n                <io.github.muntashirakon.widget.TextInputTextView\n                    android:id=\"@+id/owner_id\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:inputType=\"none\"\n                    android:maxLines=\"2\"\n                    android:textIsSelectable=\"true\"\n                    tools:text=\"root (0)\" />\n\n            </com.google.android.material.textfield.TextInputLayout>\n\n            <com.google.android.material.textfield.TextInputLayout\n                style=\"@style/Widget.AppTheme.TextInputLayout.Small\"\n                android:layout_width=\"0dp\"\n                android:layout_height=\"wrap_content\"\n                android:layout_marginStart=\"4dp\"\n                android:layout_marginBottom=\"@dimen/padding_small\"\n                android:layout_weight=\"1\"\n                android:hint=\"@string/file_group_id\"\n                app:endIconCheckable=\"false\"\n                app:endIconContentDescription=\"@string/change_group_gid\"\n                app:endIconDrawable=\"@drawable/ic_edit\"\n                app:endIconMode=\"custom\"\n                app:hintEnabled=\"true\">\n\n                <io.github.muntashirakon.widget.TextInputTextView\n                    android:id=\"@+id/group_id\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:inputType=\"none\"\n                    android:maxLines=\"2\"\n                    android:textIsSelectable=\"true\"\n                    tools:text=\"everybody (9997)\" />\n\n            </com.google.android.material.textfield.TextInputLayout>\n\n        </androidx.appcompat.widget.LinearLayoutCompat>\n\n        <androidx.appcompat.widget.LinearLayoutCompat\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:orientation=\"horizontal\">\n\n            <com.google.android.material.textfield.TextInputLayout\n                style=\"@style/Widget.AppTheme.TextInputLayout.Small\"\n                android:layout_width=\"0dp\"\n                android:layout_height=\"wrap_content\"\n                android:layout_marginEnd=\"4dp\"\n                android:layout_marginBottom=\"@dimen/padding_small\"\n                android:layout_weight=\"1\"\n                android:hint=\"@string/unix_file_permissions\"\n                app:endIconCheckable=\"false\"\n                app:endIconContentDescription=\"@string/change_mode\"\n                app:endIconDrawable=\"@drawable/ic_edit\"\n                app:endIconMode=\"custom\"\n                app:hintEnabled=\"true\">\n\n                <io.github.muntashirakon.widget.TextInputTextView\n                    android:id=\"@+id/file_mode\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:inputType=\"none\"\n                    android:maxLines=\"2\"\n                    android:textIsSelectable=\"true\"\n                    tools:text=\"rw-rw---- (660)\" />\n\n            </com.google.android.material.textfield.TextInputLayout>\n\n            <com.google.android.material.textfield.TextInputLayout\n                style=\"@style/Widget.AppTheme.TextInputLayout.Small\"\n                android:layout_width=\"0dp\"\n                android:layout_height=\"wrap_content\"\n                android:layout_marginStart=\"4dp\"\n                android:layout_marginBottom=\"@dimen/padding_small\"\n                android:layout_weight=\"1\"\n                android:hint=\"@string/selinux_context\"\n                app:endIconContentDescription=\"@string/title_change_selinux_context\"\n                app:endIconDrawable=\"@drawable/ic_edit\"\n                app:endIconMode=\"custom\"\n                app:endIconCheckable=\"false\"\n                app:hintEnabled=\"true\">\n\n                <io.github.muntashirakon.widget.TextInputTextView\n                    android:id=\"@+id/selinux_context\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:inputType=\"none\"\n                    android:maxLines=\"2\"\n                    android:textIsSelectable=\"true\"\n                    tools:text=\"u:object_r:fuse:s0\" />\n\n            </com.google.android.material.textfield.TextInputLayout>\n\n        </androidx.appcompat.widget.LinearLayoutCompat>\n\n    </androidx.appcompat.widget.LinearLayoutCompat>\n\n</ScrollView>"
  },
  {
    "path": "app/src/main/res/layout/dialog_icon_picker.xml",
    "content": "<!-- SPDX-License-Identifier: ISC AND GPL-3.0-or-later -->\n<GridView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:layout_gravity=\"center_vertical|center_horizontal\"\n    android:columnWidth=\"50dp\"\n    android:horizontalSpacing=\"8dp\"\n    android:numColumns=\"auto_fit\"\n    android:paddingStart=\"@dimen/padding_medium\"\n    android:paddingEnd=\"@dimen/padding_medium\"\n    android:stretchMode=\"spacingWidthUniform\"\n    android:verticalSpacing=\"8dp\" />\n"
  },
  {
    "path": "app/src/main/res/layout/dialog_installer.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<FrameLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\">\n\n    <!-- The sequence must be maintained. -->\n    <androidx.fragment.app.FragmentContainerView\n        android:id=\"@+id/fragment_container_view_tag\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\" />\n\n    <com.google.android.material.textview.MaterialTextView\n        android:id=\"@+id/message\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:paddingHorizontal=\"@dimen/padding_medium\"\n        android:paddingVertical=\"@dimen/padding_large\"\n        tools:text=\"@tools:sample/lorem\" />\n\n    <androidx.appcompat.widget.LinearLayoutCompat\n        android:id=\"@+id/layout\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:orientation=\"vertical\" />\n</FrameLayout>"
  },
  {
    "path": "app/src/main/res/layout/dialog_installer_options.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<ScrollView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n\n    <androidx.appcompat.widget.LinearLayoutCompat\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:paddingVertical=\"8dp\"\n        android:paddingHorizontal=\"16dp\"\n        android:orientation=\"vertical\">\n\n        <io.github.muntashirakon.widget.MaterialSpinner\n            android:id=\"@+id/user\"\n            style=\"@style/Widget.AppTheme.MaterialSpinner.Small\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginBottom=\"8dp\"\n            android:hint=\"@string/select_user\" />\n\n        <io.github.muntashirakon.widget.MaterialSpinner\n            android:id=\"@+id/install_location\"\n            style=\"@style/Widget.AppTheme.MaterialSpinner.Small\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginBottom=\"8dp\"\n            android:hint=\"@string/install_location\" />\n\n        <com.google.android.material.textfield.TextInputLayout\n            style=\"@style/Widget.AppTheme.TextInputLayout.Small\"\n            android:id=\"@+id/installer\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginBottom=\"8dp\"\n            android:hint=\"@string/installer_app\"\n            app:endIconMode=\"custom\"\n            app:endIconDrawable=\"@drawable/ic_refresh\"\n            app:hintAnimationEnabled=\"true\"\n            app:hintEnabled=\"true\">\n\n            <io.github.muntashirakon.widget.TextInputTextView\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:inputType=\"none\"\n                android:textIsSelectable=\"true\"\n                tools:text=\"@tools:sample/lorem[4]\" />\n\n        </com.google.android.material.textfield.TextInputLayout>\n\n        <io.github.muntashirakon.widget.MaterialSpinner\n            android:id=\"@+id/package_source\"\n            style=\"@style/Widget.AppTheme.MaterialSpinner.Small\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginBottom=\"8dp\"\n            android:hint=\"@string/pref_default_package_source\" />\n\n        <com.google.android.material.materialswitch.MaterialSwitch\n            android:id=\"@+id/action_disable_verification\"\n            style=\"@style/Widget.AppTheme.MaterialSwitch\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:text=\"@string/pref_disable_apk_verification\" />\n\n        <com.google.android.material.materialswitch.MaterialSwitch\n            android:id=\"@+id/action_update_ownership\"\n            style=\"@style/Widget.AppTheme.MaterialSwitch\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:text=\"@string/pref_request_update_ownership\" />\n\n        <com.google.android.material.materialswitch.MaterialSwitch\n            android:id=\"@+id/action_set_origin\"\n            style=\"@style/Widget.AppTheme.MaterialSwitch\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:text=\"@string/pref_set_origin\" />\n\n        <com.google.android.material.materialswitch.MaterialSwitch\n            android:id=\"@+id/action_sign_apk\"\n            style=\"@style/Widget.AppTheme.MaterialSwitch\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:text=\"@string/pref_sign_apk\" />\n\n        <com.google.android.material.materialswitch.MaterialSwitch\n            android:id=\"@+id/action_optimize\"\n            style=\"@style/Widget.AppTheme.MaterialSwitch\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:text=\"@string/optimize_option_force_dexopt\" />\n\n        <com.google.android.material.materialswitch.MaterialSwitch\n            android:id=\"@+id/action_block_trackers\"\n            style=\"@style/Widget.AppTheme.MaterialSwitch\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:text=\"@string/block_trackers\" />\n\n    </androidx.appcompat.widget.LinearLayoutCompat>\n</ScrollView>"
  },
  {
    "path": "app/src/main/res/layout/dialog_key_pair_importer.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<ScrollView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"fill_parent\"\n    android:layout_height=\"wrap_content\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\">\n\n    <androidx.appcompat.widget.LinearLayoutCompat\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:orientation=\"vertical\"\n        android:paddingStart=\"@dimen/padding_medium\"\n        android:paddingEnd=\"@dimen/padding_medium\">\n\n        <io.github.muntashirakon.widget.MaterialSpinner\n            style=\"@style/Widget.AppTheme.MaterialSpinner\"\n            android:id=\"@+id/key_type_selector_spinner\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginTop=\"@dimen/padding_small\"\n            android:hint=\"@string/select_type\" />\n\n        <com.google.android.material.textfield.TextInputLayout\n            android:id=\"@+id/hint\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:hint=\"@string/keystore_pass\"\n            android:layout_marginTop=\"@dimen/padding_small\"\n            app:endIconMode=\"password_toggle\"\n            app:hintAnimationEnabled=\"true\"\n            app:hintEnabled=\"true\">\n\n            <com.google.android.material.textfield.TextInputEditText\n                android:id=\"@+id/text\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:importantForAutofill=\"no\"\n                android:inputType=\"textPassword\"\n                tools:text=\"@tools:sample/lorem[4]\" />\n\n        </com.google.android.material.textfield.TextInputLayout>\n\n        <com.google.android.material.textfield.TextInputLayout\n            android:id=\"@+id/hint2\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:hint=\"@string/keystore_file\"\n            android:layout_marginTop=\"@dimen/padding_small\"\n            app:hintAnimationEnabled=\"true\"\n            app:hintEnabled=\"true\">\n\n            <com.google.android.material.textfield.TextInputEditText\n                android:id=\"@+id/text2\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:importantForAutofill=\"no\"\n                android:inputType=\"text\"\n                tools:text=\"@tools:sample/full_names\" />\n\n        </com.google.android.material.textfield.TextInputLayout>\n\n    </androidx.appcompat.widget.LinearLayoutCompat>\n\n</ScrollView>\n"
  },
  {
    "path": "app/src/main/res/layout/dialog_keystore_password.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<androidx.appcompat.widget.LinearLayoutCompat xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    android:paddingTop=\"@dimen/padding_small\"\n    android:paddingBottom=\"@dimen/padding_small\"\n    android:paddingStart=\"@dimen/padding_medium\"\n    android:paddingEnd=\"@dimen/padding_medium\"\n    android:orientation=\"vertical\">\n\n    <androidx.appcompat.widget.AppCompatTextView\n        android:id=\"@android:id/text1\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:text=\"@string/keystore_password_info\" />\n\n    <com.google.android.material.textfield.TextInputLayout\n        android:id=\"@android:id/text2\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        app:endIconMode=\"password_toggle\">\n\n        <com.google.android.material.textfield.TextInputEditText\n            android:id=\"@+id/ks_pass\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:textSize=\"25sp\"\n            android:inputType=\"textVisiblePassword|textMultiLine\"\n            android:focusable=\"true\"\n            android:cursorVisible=\"false\"\n            android:fontFamily=\"monospace\"\n            tools:text=\"@tools:sample/full_names\">\n\n            <requestFocus />\n\n        </com.google.android.material.textfield.TextInputEditText>\n\n    </com.google.android.material.textfield.TextInputLayout>\n\n</androidx.appcompat.widget.LinearLayoutCompat>"
  },
  {
    "path": "app/src/main/res/layout/dialog_list_options.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<androidx.core.widget.NestedScrollView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    android:scrollbars=\"vertical\"\n    android:scrollIndicators=\"top|bottom\"\n    tools:ignore=\"UnusedAttribute\">\n\n    <androidx.appcompat.widget.LinearLayoutCompat\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:paddingVertical=\"@dimen/padding_small\"\n        android:paddingHorizontal=\"@dimen/padding_medium\"\n        android:orientation=\"vertical\">\n\n        <androidx.appcompat.widget.LinearLayoutCompat\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:orientation=\"horizontal\"\n            android:gravity=\"center_vertical\">\n\n            <androidx.appcompat.widget.AppCompatTextView\n                android:id=\"@+id/sort_text\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_weight=\"1\"\n                android:paddingVertical=\"8dp\"\n                android:textAppearance=\"?attr/preferenceCategoryTitleTextAppearance\"\n                android:textColor=\"?attr/preferenceCategoryTitleTextColor\"\n                android:text=\"@string/sort\" />\n\n            <com.google.android.material.checkbox.MaterialCheckBox\n                android:id=\"@+id/reverse_sort\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_weight=\"0\"\n                android:text=\"@string/reverse\" />\n\n        </androidx.appcompat.widget.LinearLayoutCompat>\n\n        <com.google.android.material.chip.ChipGroup\n            android:id=\"@+id/sort_options\"\n            android:theme=\"@style/Widget.AppTheme.ChipGroup.Filter\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:paddingVertical=\"@dimen/padding_very_small\"\n            app:itemSpacing=\"@dimen/padding_very_small\"\n            app:lineSpacing=\"@dimen/padding_very_small\"\n            app:singleSelection=\"true\" />\n\n        <androidx.appcompat.widget.LinearLayoutCompat\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:orientation=\"horizontal\"\n            android:layout_marginTop=\"16dp\"\n            android:gravity=\"center_vertical\">\n\n            <androidx.appcompat.widget.AppCompatTextView\n                android:id=\"@+id/filter_text\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_weight=\"1\"\n                android:paddingVertical=\"8dp\"\n                android:textAppearance=\"?attr/preferenceCategoryTitleTextAppearance\"\n                android:textColor=\"?attr/preferenceCategoryTitleTextColor\"\n                android:text=\"@string/filter\" />\n\n            <com.google.android.material.button.MaterialButton\n                style=\"@style/Widget.AppTheme.Button.TextButton\"\n                android:id=\"@+id/user\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_weight=\"0\"\n                android:paddingStart=\"8dp\"\n                android:paddingEnd=\"8dp\"\n                android:paddingTop=\"4dp\"\n                android:paddingBottom=\"4dp\"\n                android:minHeight=\"40dp\"\n                android:maxWidth=\"200dp\"\n                android:text=\"@string/users\" />\n\n        </androidx.appcompat.widget.LinearLayoutCompat>\n\n        <com.google.android.material.chip.ChipGroup\n            android:id=\"@+id/filter_options\"\n            android:theme=\"@style/Widget.AppTheme.ChipGroup.Filter\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:paddingVertical=\"@dimen/padding_very_small\"\n            app:itemSpacing=\"@dimen/padding_very_small\"\n            app:lineSpacing=\"@dimen/padding_very_small\" />\n\n        <androidx.appcompat.widget.AppCompatTextView\n            android:id=\"@+id/options_text\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginTop=\"16dp\"\n            android:paddingVertical=\"8dp\"\n            android:textAppearance=\"?attr/preferenceCategoryTitleTextAppearance\"\n            android:textColor=\"?attr/preferenceCategoryTitleTextColor\"\n            android:text=\"@string/options\" />\n\n        <androidx.appcompat.widget.LinearLayoutCompat\n            android:id=\"@+id/options\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:orientation=\"vertical\" />\n\n        <io.github.muntashirakon.widget.MaterialSpinner\n            style=\"@style/Widget.AppTheme.MaterialSpinner.Small\"\n            android:id=\"@+id/spinner\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:hint=\"@string/input_profile_name\" />\n\n    </androidx.appcompat.widget.LinearLayoutCompat>\n\n</androidx.core.widget.NestedScrollView>"
  },
  {
    "path": "app/src/main/res/layout/dialog_new_file.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<androidx.appcompat.widget.LinearLayoutCompat xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    android:paddingTop=\"@dimen/padding_small\"\n    android:paddingBottom=\"@dimen/padding_small\"\n    android:paddingStart=\"@dimen/padding_medium\"\n    android:paddingEnd=\"@dimen/padding_medium\"\n    android:orientation=\"vertical\">\n\n    <com.google.android.material.textfield.TextInputLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\">\n\n        <com.google.android.material.textfield.TextInputEditText\n            android:id=\"@+id/name\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:maxLines=\"2\"\n            android:inputType=\"text\"\n            tools:text=\"@tools:sample/full_names\" />\n\n    </com.google.android.material.textfield.TextInputLayout>\n\n    <io.github.muntashirakon.widget.MaterialSpinner\n        style=\"@style/Widget.AppTheme.MaterialSpinner\"\n        android:id=\"@+id/type_selector_spinner\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        app:boxStrokeWidth=\"0dp\" />\n\n</androidx.appcompat.widget.LinearLayoutCompat>"
  },
  {
    "path": "app/src/main/res/layout/dialog_new_symlink.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<androidx.appcompat.widget.LinearLayoutCompat xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    android:paddingTop=\"@dimen/padding_small\"\n    android:paddingBottom=\"@dimen/padding_small\"\n    android:paddingStart=\"@dimen/padding_medium\"\n    android:paddingEnd=\"@dimen/padding_medium\"\n    android:orientation=\"vertical\">\n\n    <com.google.android.material.textfield.TextInputLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:hint=\"@string/enter_symbolic_link_name\">\n\n        <com.google.android.material.textfield.TextInputEditText\n            android:id=\"@+id/name\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:maxLines=\"2\"\n            android:inputType=\"text\"\n            tools:text=\"@tools:sample/full_names\" />\n\n    </com.google.android.material.textfield.TextInputLayout>\n\n    <com.google.android.material.textfield.TextInputLayout\n        android:id=\"@+id/target_file_layout\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:hint=\"@string/enter_target_path\"\n        app:errorEnabled=\"true\">\n\n        <com.google.android.material.textfield.TextInputEditText\n            android:id=\"@+id/target_file\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:maxLines=\"2\"\n            android:inputType=\"text\"\n            tools:text=\"@tools:sample/full_names\" />\n\n    </com.google.android.material.textfield.TextInputLayout>\n\n</androidx.appcompat.widget.LinearLayoutCompat>"
  },
  {
    "path": "app/src/main/res/layout/dialog_open_with.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<androidx.appcompat.widget.LinearLayoutCompat xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\">\n\n    <io.github.muntashirakon.widget.SearchView\n        style=\"@style/Widget.AppTheme.SearchView.Small\"\n        android:id=\"@+id/action_search\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"40dp\"\n        android:layout_marginHorizontal=\"@dimen/padding_medium\"\n        app:iconifiedByDefault=\"false\" />\n\n    <androidx.recyclerview.widget.RecyclerView\n        android:id=\"@+id/intent_matching_activities\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_weight=\"1\"\n        android:scrollbars=\"vertical\"\n        tools:listitem=\"@layout/item_icon_title_subtitle\" />\n\n    <com.google.android.material.checkbox.MaterialCheckBox\n        android:id=\"@+id/always_open\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_weight=\"0\"\n        android:text=\"@string/fm_always_open_with\" />\n\n    <com.google.android.material.checkbox.MaterialCheckBox\n        android:id=\"@+id/only_for_this_file\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_weight=\"0\"\n        android:text=\"@string/fm_open_with_for_this_file_only\" />\n\n</androidx.appcompat.widget.LinearLayoutCompat>"
  },
  {
    "path": "app/src/main/res/layout/dialog_profile_backup_restore.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<ScrollView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\">\n\n    <androidx.appcompat.widget.LinearLayoutCompat\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:orientation=\"vertical\"\n        android:paddingStart=\"@dimen/padding_medium\"\n        android:paddingEnd=\"@dimen/padding_medium\">\n\n        <androidx.appcompat.widget.LinearLayoutCompat\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:orientation=\"horizontal\">\n\n            <androidx.appcompat.widget.AppCompatTextView\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_weight=\"1\"\n                android:text=\"@string/backup_options\"\n                android:textAllCaps=\"true\"\n                android:labelFor=\"@id/dialog_button\" />\n\n            <com.google.android.material.button.MaterialButton\n                android:id=\"@+id/dialog_button\"\n                android:layout_width=\"200dp\"\n                android:layout_height=\"wrap_content\"\n                android:layout_weight=\"0\"\n                android:text=\"@string/choose\" />\n\n        </androidx.appcompat.widget.LinearLayoutCompat>\n\n        <androidx.appcompat.widget.LinearLayoutCompat\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:orientation=\"vertical\">\n\n            <com.google.android.material.textfield.TextInputLayout\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:hint=\"@string/input_backup_name\"\n                app:helperText=\"@string/input_backup_name_description\"\n                app:hintAnimationEnabled=\"true\"\n                app:hintEnabled=\"true\">\n\n                <com.google.android.material.textfield.TextInputEditText\n                    android:id=\"@android:id/input\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:singleLine=\"true\"\n                    tools:text=\"@tools:sample/full_names\" />\n\n            </com.google.android.material.textfield.TextInputLayout>\n\n        </androidx.appcompat.widget.LinearLayoutCompat>\n\n    </androidx.appcompat.widget.LinearLayoutCompat>\n\n</ScrollView>"
  },
  {
    "path": "app/src/main/res/layout/dialog_progress.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<androidx.appcompat.widget.LinearLayoutCompat xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\"\n    android:paddingHorizontal=\"@dimen/padding_medium\"\n    android:paddingVertical=\"@dimen/padding_large\">\n\n    <androidx.appcompat.widget.LinearLayoutCompat\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:orientation=\"horizontal\">\n\n        <androidx.appcompat.widget.AppCompatTextView\n            android:id=\"@android:id/text1\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_weight=\"1\"\n            android:singleLine=\"true\"\n            android:ellipsize=\"middle\"\n            android:gravity=\"start\"\n            android:paddingBottom=\"@dimen/padding_small\"\n            android:textAppearance=\"?android:attr/textAppearanceMedium\"\n            tools:text=\"@string/in_progress\" />\n\n        <androidx.appcompat.widget.AppCompatTextView\n            android:id=\"@android:id/text2\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:gravity=\"end\"\n            android:paddingBottom=\"@dimen/padding_small\"\n            android:textAppearance=\"?android:attr/textAppearanceSmall\"\n            tools:text=\"8/10\" />\n\n    </androidx.appcompat.widget.LinearLayoutCompat>\n\n    <com.google.android.material.progressindicator.LinearProgressIndicator\n        android:id=\"@+id/progress_linear\"\n        style=\"@style/Widget.AppTheme.LinearProgressIndicator\"\n        android:indeterminate=\"true\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\" />\n\n</androidx.appcompat.widget.LinearLayoutCompat>"
  },
  {
    "path": "app/src/main/res/layout/dialog_progress2.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<androidx.appcompat.widget.LinearLayoutCompat xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:orientation=\"vertical\"\n    android:paddingHorizontal=\"@dimen/padding_medium\"\n    android:paddingVertical=\"@dimen/padding_large\">\n\n    <androidx.appcompat.widget.AppCompatTextView\n        android:id=\"@android:id/text1\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:gravity=\"center_vertical\"\n        android:paddingBottom=\"@dimen/padding_small\"\n        android:textAppearance=\"?android:attr/textAppearanceMedium\"\n        android:text=\"@string/in_progress\" />\n\n    <com.google.android.material.progressindicator.LinearProgressIndicator\n        android:id=\"@+id/progress_linear\"\n        style=\"@style/Widget.AppTheme.LinearProgressIndicator\"\n        android:indeterminate=\"true\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\" />\n\n</androidx.appcompat.widget.LinearLayoutCompat>"
  },
  {
    "path": "app/src/main/res/layout/dialog_progress_circular.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<androidx.appcompat.widget.LinearLayoutCompat xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:orientation=\"horizontal\"\n    android:paddingHorizontal=\"@dimen/padding_medium\"\n    android:paddingVertical=\"@dimen/padding_large\">\n\n    <com.google.android.material.progressindicator.CircularProgressIndicator\n        android:id=\"@+id/progress_circular\"\n        style=\"@style/Widget.AppTheme.CircularProgressIndicator.Small\"\n        android:indeterminate=\"true\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\" />\n\n    <androidx.appcompat.widget.AppCompatTextView\n        android:id=\"@android:id/text1\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"center_vertical\"\n        android:gravity=\"center_vertical\"\n        android:layout_marginStart=\"8dp\"\n        android:paddingBottom=\"8dp\"\n        android:textAppearance=\"?android:attr/textAppearanceMedium\"\n        android:text=\"@string/in_progress\" />\n\n</androidx.appcompat.widget.LinearLayoutCompat>"
  },
  {
    "path": "app/src/main/res/layout/dialog_rename.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<androidx.appcompat.widget.LinearLayoutCompat xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:paddingTop=\"@dimen/padding_small\"\n    android:paddingBottom=\"@dimen/padding_small\"\n    android:paddingStart=\"@dimen/padding_medium\"\n    android:paddingEnd=\"@dimen/padding_medium\"\n    android:orientation=\"vertical\">\n\n    <com.google.android.material.textfield.TextInputLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\">\n\n        <com.google.android.material.textfield.TextInputEditText\n            android:id=\"@+id/rename\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:maxLines=\"2\"\n            android:inputType=\"text\"\n            tools:text=\"@tools:sample/full_names\" />\n\n    </com.google.android.material.textfield.TextInputLayout>\n\n</androidx.appcompat.widget.LinearLayoutCompat>"
  },
  {
    "path": "app/src/main/res/layout/dialog_restore_tasks.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<ScrollView\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n\n    <androidx.appcompat.widget.LinearLayoutCompat\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:orientation=\"vertical\">\n\n        <androidx.appcompat.widget.LinearLayoutCompat\n            android:id=\"@+id/restore_all\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:paddingStart=\"@dimen/padding_medium\"\n            android:paddingTop=\"@dimen/padding_small\"\n            android:paddingEnd=\"@dimen/padding_medium\"\n            android:paddingBottom=\"@dimen/padding_small\"\n            android:background=\"?selectableItemBackground\"\n            android:orientation=\"vertical\">\n\n            <androidx.appcompat.widget.AppCompatTextView\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:textAppearance=\"?android:attr/textAppearanceListItem\"\n                android:text=\"@string/restore_all\" />\n\n            <androidx.appcompat.widget.AppCompatTextView\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:textColor=\"?android:attr/textColorSecondary\"\n                android:textAppearance=\"?android:attr/textAppearanceListItemSecondary\"\n                android:text=\"@string/restore_all_msg\" />\n\n        </androidx.appcompat.widget.LinearLayoutCompat>\n\n        <com.google.android.material.divider.MaterialDivider\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"1dp\" />\n\n        <androidx.appcompat.widget.LinearLayoutCompat\n            android:id=\"@+id/restore_not_installed\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:paddingStart=\"@dimen/padding_medium\"\n            android:paddingTop=\"@dimen/padding_small\"\n            android:paddingEnd=\"@dimen/padding_medium\"\n            android:paddingBottom=\"@dimen/padding_small\"\n            android:background=\"?selectableItemBackground\"\n            android:orientation=\"vertical\">\n\n            <androidx.appcompat.widget.AppCompatTextView\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:textAppearance=\"?android:attr/textAppearanceListItem\"\n                android:text=\"@string/restore_not_installed\" />\n\n            <androidx.appcompat.widget.AppCompatTextView\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:textColor=\"?android:attr/textColorSecondary\"\n                android:textAppearance=\"?android:attr/textAppearanceListItemSecondary\"\n                android:text=\"@string/restore_not_installed_msg\" />\n\n        </androidx.appcompat.widget.LinearLayoutCompat>\n\n        <com.google.android.material.divider.MaterialDivider\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"1dp\" />\n\n        <androidx.appcompat.widget.LinearLayoutCompat\n            android:id=\"@+id/restore_latest\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:paddingStart=\"@dimen/padding_medium\"\n            android:paddingTop=\"@dimen/padding_small\"\n            android:paddingEnd=\"@dimen/padding_medium\"\n            android:paddingBottom=\"@dimen/padding_small\"\n            android:background=\"?selectableItemBackground\"\n            android:orientation=\"vertical\">\n\n            <com.google.android.material.textview.MaterialTextView\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:textAppearance=\"?android:attr/textAppearanceListItem\"\n                android:text=\"@string/restore_latest\" />\n\n            <androidx.appcompat.widget.AppCompatTextView\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:textColor=\"?android:attr/textColorSecondary\"\n                android:textAppearance=\"?android:attr/textAppearanceListItemSecondary\"\n                android:text=\"@string/restore_latest_msg\" />\n\n        </androidx.appcompat.widget.LinearLayoutCompat>\n\n    </androidx.appcompat.widget.LinearLayoutCompat>\n\n</ScrollView>\n"
  },
  {
    "path": "app/src/main/res/layout/dialog_running_app_details.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<ScrollView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\">\n\n    <androidx.appcompat.widget.LinearLayoutCompat\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:paddingTop=\"@dimen/padding_small\"\n        android:paddingBottom=\"@dimen/padding_small\"\n        android:paddingStart=\"@dimen/padding_medium\"\n        android:paddingEnd=\"@dimen/padding_medium\"\n        android:orientation=\"vertical\">\n\n        <androidx.appcompat.widget.LinearLayoutCompat\n            android:id=\"@+id/app_container\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginBottom=\"@dimen/font_size_small\"\n            android:orientation=\"horizontal\">\n\n            <androidx.appcompat.widget.AppCompatImageView\n                android:id=\"@+id/icon\"\n                android:layout_width=\"@dimen/icon_size\"\n                android:layout_height=\"@dimen/icon_size\"\n                android:layout_weight=\"0\"\n                android:layout_gravity=\"center\"\n                android:layout_marginEnd=\"@dimen/padding_small\"\n                tools:srcCompat=\"@mipmap/ic_launcher_round\" />\n\n            <androidx.appcompat.widget.LinearLayoutCompat\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_weight=\"1\"\n                android:orientation=\"vertical\">\n\n                <com.google.android.material.textview.MaterialTextView\n                    android:id=\"@+id/name\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:textIsSelectable=\"true\"\n                    android:textAppearance=\"?attr/textAppearanceTitleMedium\"\n                    tools:text=\"@string/app_name\" />\n\n                <com.google.android.material.textview.MaterialTextView\n                    android:id=\"@+id/package_name\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:textIsSelectable=\"true\"\n                    android:textAppearance=\"?attr/textAppearanceBodySmall\"\n                    android:textStyle=\"italic\"\n                    tools:text=\"@string/app_name\" />\n\n            </androidx.appcompat.widget.LinearLayoutCompat>\n\n            <com.google.android.material.button.MaterialButton\n                android:id=\"@+id/info\"\n                style=\"@style/Widget.AppTheme.Button.IconButton.InverseColor\"\n                android:layout_width=\"@dimen/icon_size\"\n                android:layout_height=\"@dimen/icon_size\"\n                android:layout_weight=\"0\"\n                android:layout_marginStart=\"@dimen/padding_small\"\n                android:layout_gravity=\"center\"\n                app:iconSize=\"30dp\"\n                app:icon=\"@drawable/ic_information\" />\n\n        </androidx.appcompat.widget.LinearLayoutCompat>\n\n        <com.google.android.material.textfield.TextInputLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginBottom=\"@dimen/padding_small\"\n            android:hint=\"@string/process_name\"\n            app:hintEnabled=\"true\">\n\n            <io.github.muntashirakon.widget.TextInputTextView\n                android:id=\"@+id/process_name\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:inputType=\"none\"\n                android:textIsSelectable=\"true\"\n                android:maxLines=\"2\"\n                tools:text=\"@tools:sample/us_zipcodes\" />\n\n        </com.google.android.material.textfield.TextInputLayout>\n\n        <androidx.appcompat.widget.LinearLayoutCompat\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginBottom=\"@dimen/padding_small\"\n            android:orientation=\"horizontal\">\n\n            <com.google.android.material.textfield.TextInputLayout\n                style=\"@style/Widget.AppTheme.TextInputLayout.Small\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_weight=\"1\"\n                android:layout_marginEnd=\"@dimen/padding_small\"\n                android:hint=\"@string/process_id\"\n                app:hintEnabled=\"true\">\n\n                <io.github.muntashirakon.widget.TextInputTextView\n                    android:id=\"@+id/pid\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:inputType=\"none\"\n                    android:textIsSelectable=\"true\"\n                    tools:text=\"@tools:sample/us_zipcodes\" />\n\n            </com.google.android.material.textfield.TextInputLayout>\n\n            <com.google.android.material.textfield.TextInputLayout\n                style=\"@style/Widget.AppTheme.TextInputLayout.Small\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_weight=\"1\"\n                android:hint=\"@string/parent_process_id\"\n                app:hintEnabled=\"true\">\n\n                <io.github.muntashirakon.widget.TextInputTextView\n                    android:id=\"@+id/ppid\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:inputType=\"none\"\n                    android:textIsSelectable=\"true\"\n                    tools:text=\"@tools:sample/us_zipcodes\" />\n\n            </com.google.android.material.textfield.TextInputLayout>\n\n        </androidx.appcompat.widget.LinearLayoutCompat>\n\n        <androidx.appcompat.widget.LinearLayoutCompat\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginBottom=\"@dimen/padding_small\"\n            android:orientation=\"horizontal\">\n\n            <com.google.android.material.textfield.TextInputLayout\n                style=\"@style/Widget.AppTheme.TextInputLayout.Small\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_weight=\"1\"\n                android:layout_marginEnd=\"@dimen/padding_small\"\n                android:hint=\"@string/memory\"\n                app:hintEnabled=\"true\">\n\n                <io.github.muntashirakon.widget.TextInputTextView\n                    android:id=\"@+id/rss\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:inputType=\"none\"\n                    android:textIsSelectable=\"true\"\n                    tools:text=\"@tools:sample/us_zipcodes\" />\n\n            </com.google.android.material.textfield.TextInputLayout>\n\n            <com.google.android.material.textfield.TextInputLayout\n                style=\"@style/Widget.AppTheme.TextInputLayout.Small\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_weight=\"1\"\n                android:hint=\"@string/virtual_memory\"\n                app:hintEnabled=\"true\">\n\n                <io.github.muntashirakon.widget.TextInputTextView\n                    android:id=\"@+id/vsz\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:inputType=\"none\"\n                    android:textIsSelectable=\"true\"\n                    tools:text=\"@tools:sample/us_zipcodes\" />\n\n            </com.google.android.material.textfield.TextInputLayout>\n\n        </androidx.appcompat.widget.LinearLayoutCompat>\n\n        <androidx.appcompat.widget.LinearLayoutCompat\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginBottom=\"@dimen/padding_small\"\n            android:orientation=\"horizontal\">\n\n            <com.google.android.material.textfield.TextInputLayout\n                style=\"@style/Widget.AppTheme.TextInputLayout.Small\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_weight=\"1\"\n                android:layout_marginEnd=\"@dimen/padding_small\"\n                android:hint=\"@string/cpu_percent\"\n                app:hintEnabled=\"true\">\n\n                <io.github.muntashirakon.widget.TextInputTextView\n                    android:id=\"@+id/cpu_percent\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:inputType=\"none\"\n                    android:textIsSelectable=\"true\"\n                    tools:text=\"@tools:sample/us_zipcodes\" />\n\n            </com.google.android.material.textfield.TextInputLayout>\n\n            <com.google.android.material.textfield.TextInputLayout\n                style=\"@style/Widget.AppTheme.TextInputLayout.Small\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_weight=\"1\"\n                android:hint=\"@string/cpu_time\"\n                app:hintEnabled=\"true\">\n\n                <io.github.muntashirakon.widget.TextInputTextView\n                    android:id=\"@+id/cpu_time\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:inputType=\"none\"\n                    android:textIsSelectable=\"true\"\n                    tools:text=\"@tools:sample/us_zipcodes\" />\n\n            </com.google.android.material.textfield.TextInputLayout>\n\n        </androidx.appcompat.widget.LinearLayoutCompat>\n\n        <androidx.appcompat.widget.LinearLayoutCompat\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginBottom=\"@dimen/padding_small\"\n            android:orientation=\"horizontal\">\n\n            <com.google.android.material.textfield.TextInputLayout\n                style=\"@style/Widget.AppTheme.TextInputLayout.Small\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_weight=\"1\"\n                android:layout_marginEnd=\"@dimen/padding_small\"\n                android:hint=\"@string/priority\"\n                app:hintEnabled=\"true\">\n\n                <io.github.muntashirakon.widget.TextInputTextView\n                    android:id=\"@+id/priority\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:inputType=\"none\"\n                    android:textIsSelectable=\"true\"\n                    tools:text=\"@tools:sample/us_zipcodes\" />\n\n            </com.google.android.material.textfield.TextInputLayout>\n\n            <com.google.android.material.textfield.TextInputLayout\n                style=\"@style/Widget.AppTheme.TextInputLayout.Small\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_weight=\"1\"\n                android:hint=\"@string/threads\"\n                app:hintEnabled=\"true\">\n\n                <io.github.muntashirakon.widget.TextInputTextView\n                    android:id=\"@+id/threads\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:inputType=\"none\"\n                    android:textIsSelectable=\"true\"\n                    tools:text=\"@tools:sample/us_zipcodes\" />\n\n            </com.google.android.material.textfield.TextInputLayout>\n\n        </androidx.appcompat.widget.LinearLayoutCompat>\n\n        <androidx.appcompat.widget.LinearLayoutCompat\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginBottom=\"@dimen/padding_small\"\n            android:orientation=\"horizontal\">\n\n            <com.google.android.material.textfield.TextInputLayout\n                style=\"@style/Widget.AppTheme.TextInputLayout.Small\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_weight=\"1\"\n                android:layout_marginEnd=\"@dimen/padding_small\"\n                android:hint=\"@string/user\"\n                app:hintEnabled=\"true\">\n\n                <io.github.muntashirakon.widget.TextInputTextView\n                    android:id=\"@+id/user\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:inputType=\"none\"\n                    android:textIsSelectable=\"true\"\n                    tools:text=\"@tools:sample/us_zipcodes\" />\n\n            </com.google.android.material.textfield.TextInputLayout>\n\n            <com.google.android.material.textfield.TextInputLayout\n                style=\"@style/Widget.AppTheme.TextInputLayout.Small\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_weight=\"1\"\n                android:hint=\"@string/state\"\n                app:hintEnabled=\"true\">\n\n                <io.github.muntashirakon.widget.TextInputTextView\n                    android:id=\"@+id/state\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:inputType=\"none\"\n                    android:textIsSelectable=\"true\"\n                    tools:text=\"@tools:sample/us_zipcodes\" />\n\n            </com.google.android.material.textfield.TextInputLayout>\n\n        </androidx.appcompat.widget.LinearLayoutCompat>\n\n        <com.google.android.material.textfield.TextInputLayout\n            style=\"@style/Widget.AppTheme.TextInputLayout.Small\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_weight=\"1\"\n            android:layout_marginBottom=\"@dimen/padding_small\"\n            android:hint=\"@string/selinux\"\n            app:hintEnabled=\"true\">\n\n            <io.github.muntashirakon.widget.TextInputTextView\n                android:id=\"@+id/selinux_context\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:inputType=\"none\"\n                android:textIsSelectable=\"true\"\n                android:maxLines=\"2\"\n                app:fontFamily=\"monospace\"\n                tools:text=\"@tools:sample/us_zipcodes\" />\n\n        </com.google.android.material.textfield.TextInputLayout>\n\n        <com.google.android.material.textfield.TextInputLayout\n            style=\"@style/Widget.AppTheme.TextInputLayout.Small\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_weight=\"1\"\n            android:hint=\"@string/commandline_args\"\n            app:hintEnabled=\"true\">\n\n            <io.github.muntashirakon.widget.TextInputTextView\n                android:id=\"@+id/cli_args\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:inputType=\"none\"\n                android:textIsSelectable=\"true\"\n                android:maxLines=\"3\"\n                app:fontFamily=\"monospace\"\n                tools:text=\"@tools:sample/us_zipcodes\" />\n\n        </com.google.android.material.textfield.TextInputLayout>\n\n    </androidx.appcompat.widget.LinearLayoutCompat>\n</ScrollView>"
  },
  {
    "path": "app/src/main/res/layout/dialog_searchable_multi_choice.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<androidx.appcompat.widget.LinearLayoutCompat xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:orientation=\"vertical\">\n\n    <io.github.muntashirakon.widget.SearchView\n        style=\"@style/Widget.AppTheme.SearchView.Small\"\n        android:id=\"@+id/action_search\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"40dp\"\n        android:layout_marginHorizontal=\"@dimen/padding_medium\"\n        app:iconifiedByDefault=\"false\" />\n\n    <io.github.muntashirakon.widget.CheckBox\n        android:id=\"@android:id/checkbox\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"48dp\"\n        android:layout_gravity=\"center_vertical\"\n        android:layout_marginStart=\"@dimen/padding_medium\"\n        android:layout_marginEnd=\"@dimen/padding_medium\"\n        android:text=\"@string/select_all\" />\n\n    <io.github.muntashirakon.widget.RecyclerView\n        android:id=\"@android:id/list\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:scrollIndicators=\"top|bottom\"\n        app:fastScrollerEnabled=\"true\"\n        tools:ignore=\"UnusedAttribute\"\n        tools:listitem=\"@layout/mtrl_alert_select_dialog_multichoice\" />\n\n</androidx.appcompat.widget.LinearLayoutCompat>"
  },
  {
    "path": "app/src/main/res/layout/dialog_searchby.xml",
    "content": "<!-- SPDX-License-Identifier: WTFPL AND GPL-3.0-or-later -->\n<androidx.appcompat.widget.LinearLayoutCompat xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:baselineAligned=\"false\"\n    android:orientation=\"vertical\"\n    android:paddingVertical=\"@dimen/padding_small\"\n    android:paddingHorizontal=\"@dimen/padding_medium\">\n\n    <com.google.android.material.textfield.TextInputLayout\n        android:id=\"@+id/search_by_pkg\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:hint=\"@string/package_name\"\n        app:hintEnabled=\"true\"\n        app:endIconMode=\"custom\"\n        app:endIconDrawable=\"@drawable/ic_search\">\n\n        <io.github.muntashirakon.widget.TextInputTextView\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:textIsSelectable=\"true\"\n            tools:text=\"@tools:sample/full_names\" />\n\n    </com.google.android.material.textfield.TextInputLayout>\n\n    <com.google.android.material.textfield.TextInputLayout\n        android:id=\"@+id/search_by_tag\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:hint=\"@string/filter_choice_tag\"\n        app:hintEnabled=\"true\"\n        app:endIconMode=\"custom\"\n        app:endIconDrawable=\"@drawable/ic_search\">\n\n        <io.github.muntashirakon.widget.TextInputTextView\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:textIsSelectable=\"true\"\n            tools:text=\"@tools:sample/full_names\" />\n\n    </com.google.android.material.textfield.TextInputLayout>\n\n    <com.google.android.material.textfield.TextInputLayout\n        android:id=\"@+id/search_by_uid\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:hint=\"@string/file_owner_id\"\n        app:hintEnabled=\"true\"\n        app:endIconMode=\"custom\"\n        app:endIconDrawable=\"@drawable/ic_search\">\n\n        <io.github.muntashirakon.widget.TextInputTextView\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:textIsSelectable=\"true\"\n            tools:text=\"@tools:sample/us_zipcodes\" />\n\n    </com.google.android.material.textfield.TextInputLayout>\n\n    <com.google.android.material.textfield.TextInputLayout\n        android:id=\"@+id/search_by_pid\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:hint=\"@string/filter_choice_pid\"\n        app:hintEnabled=\"true\"\n        app:endIconMode=\"custom\"\n        app:endIconDrawable=\"@drawable/ic_search\">\n\n        <io.github.muntashirakon.widget.TextInputTextView\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:textIsSelectable=\"true\"\n            tools:text=\"@tools:sample/us_zipcodes\" />\n\n    </com.google.android.material.textfield.TextInputLayout>\n\n</androidx.appcompat.widget.LinearLayoutCompat>"
  },
  {
    "path": "app/src/main/res/layout/dialog_send_log.xml",
    "content": "<!-- SPDX-License-Identifier: WTFPL AND GPL-3.0-or-later -->\n<androidx.appcompat.widget.LinearLayoutCompat xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:orientation=\"vertical\"\n    android:paddingEnd=\"@dimen/padding_medium\"\n    android:paddingStart=\"@dimen/padding_medium\">\n\n    <com.google.android.material.checkbox.MaterialCheckBox\n        android:id=\"@android:id/checkbox\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:checked=\"true\"\n        android:text=\"@string/text_include_device_info\" />\n\n    <com.google.android.material.checkbox.MaterialCheckBox\n        android:id=\"@+id/checkbox_dmesg\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:checked=\"true\"\n        android:text=\"@string/text_include_dmesg\" />\n\n</androidx.appcompat.widget.LinearLayoutCompat>"
  },
  {
    "path": "app/src/main/res/layout/dialog_set_apk_format.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<ScrollView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n\n    <androidx.appcompat.widget.LinearLayoutCompat\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:orientation=\"vertical\"\n        android:paddingVertical=\"@dimen/padding_small\"\n        android:paddingHorizontal=\"@dimen/padding_medium\">\n\n        <com.google.android.material.textfield.TextInputLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            app:suffixText=\".apk\">\n\n            <com.google.android.material.textfield.TextInputEditText\n                android:id=\"@+id/input_apk_name_format\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:singleLine=\"true\"\n                android:fontFamily=\"monospace\"\n                android:imeOptions=\"actionDone|flagNoPersonalizedLearning\"\n                tools:text=\"%label%_%version%\" />\n\n        </com.google.android.material.textfield.TextInputLayout>\n\n        <com.google.android.material.chip.ChipGroup\n            android:id=\"@+id/apk_name_formats\"\n            android:theme=\"@style/Widget.AppTheme.ChipGroup.Assist\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:paddingVertical=\"@dimen/padding_very_small\"\n            app:itemSpacing=\"@dimen/padding_very_small\"\n            app:lineSpacing=\"@dimen/padding_very_small\" />\n\n    </androidx.appcompat.widget.LinearLayoutCompat>\n\n</ScrollView>"
  },
  {
    "path": "app/src/main/res/layout/dialog_ssaid_info.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<androidx.appcompat.widget.LinearLayoutCompat xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    android:paddingTop=\"@dimen/padding_small\"\n    android:paddingBottom=\"@dimen/padding_small\"\n    android:paddingStart=\"@dimen/padding_medium\"\n    android:paddingEnd=\"@dimen/padding_medium\"\n    android:orientation=\"vertical\">\n\n    <androidx.appcompat.widget.AppCompatTextView\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:text=\"@string/ssaid_info\" />\n\n    <com.google.android.material.textfield.TextInputLayout\n        android:id=\"@+id/ssaid_layout\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        app:counterEnabled=\"true\"\n        app:endIconMode=\"custom\"\n        app:endIconDrawable=\"@drawable/ic_autorenew\">\n\n        <com.google.android.material.textfield.TextInputEditText\n            android:id=\"@android:id/text1\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:textSize=\"25sp\"\n            android:inputType=\"text\"\n            android:fontFamily=\"monospace\"\n            tools:text=\"@tools:sample/full_names\" />\n\n    </com.google.android.material.textfield.TextInputLayout>\n\n</androidx.appcompat.widget.LinearLayoutCompat>"
  },
  {
    "path": "app/src/main/res/layout/dialog_whats_new.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<androidx.recyclerview.widget.RecyclerView\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:id=\"@android:id/list\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\" />"
  },
  {
    "path": "app/src/main/res/layout/fragment_class_lister.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<FrameLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n\n    <io.github.muntashirakon.widget.RecyclerView\n        android:id=\"@+id/list_item\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:clipToPadding=\"false\"\n        android:fitsSystemWindows=\"true\"\n        app:fastScrollerEnabled=\"true\"\n        tools:listitem=\"@layout/m3_preference\" />\n\n    <androidx.appcompat.widget.AppCompatTextView\n        android:id=\"@android:id/empty\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:gravity=\"center\"\n        tools:text=\"@string/no_tracker_class\"\n        tools:visibility=\"gone\" />\n\n</FrameLayout>\n"
  },
  {
    "path": "app/src/main/res/layout/fragment_code_editor.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<androidx.appcompat.widget.LinearLayoutCompat xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:id=\"@+id/editor_container\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:fitsSystemWindows=\"true\"\n    android:orientation=\"vertical\">\n\n    <io.github.muntashirakon.AppManager.editor.CodeEditorWidget\n        android:id=\"@+id/editor\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"0dp\"\n        android:layout_weight=\"1\"\n        android:scrollbarThumbHorizontal=\"@drawable/afs_md2_thumb\"\n        android:scrollbarThumbVertical=\"@drawable/afs_md2_thumb\"\n        android:scrollbarTrackHorizontal=\"@drawable/afs_md2_track\"\n        android:scrollbarTrackVertical=\"@drawable/afs_md2_track\"\n        app:lnPanelPosition=\"center\"\n        app:lnPanelPositionMode=\"follow\" />\n\n    <androidx.appcompat.widget.LinearLayoutCompat\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_weight=\"0\"\n        android:orientation=\"vertical\">\n\n        <androidx.appcompat.widget.LinearLayoutCompat\n            android:id=\"@+id/search_container\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:paddingHorizontal=\"@dimen/padding_medium\"\n            android:paddingVertical=\"8dp\"\n            android:orientation=\"vertical\"\n            android:visibility=\"gone\"\n            tools:visibility=\"visible\">\n\n            <com.google.android.material.textfield.TextInputLayout\n                android:id=\"@+id/search_bar_container\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                app:hintEnabled=\"true\"\n                android:hint=\"@string/search\"\n                app:endIconMode=\"custom\"\n                app:endIconDrawable=\"@drawable/ic_settings\">\n\n                <com.google.android.material.textfield.TextInputEditText\n                    android:id=\"@+id/search_bar\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:inputType=\"text\"\n                    android:singleLine=\"true\"\n                    tools:text=\"@tools:sample/full_names\" />\n\n            </com.google.android.material.textfield.TextInputLayout>\n\n            <com.google.android.material.textfield.TextInputLayout\n                android:id=\"@+id/replace_bar_container\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                app:hintEnabled=\"true\"\n                android:hint=\"@string/replacement_text\">\n\n                <com.google.android.material.textfield.TextInputEditText\n                    android:id=\"@+id/replace_bar\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:inputType=\"text\"\n                    android:singleLine=\"true\"\n                    tools:text=\"@tools:sample/full_names\" />\n\n            </com.google.android.material.textfield.TextInputLayout>\n\n            <androidx.appcompat.widget.LinearLayoutCompat\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:orientation=\"horizontal\">\n\n                <com.google.android.material.textview.MaterialTextView\n                    android:id=\"@+id/search_result_count\"\n                    android:layout_width=\"0dp\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_weight=\"1\"\n                    android:layout_gravity=\"center_vertical\"\n                    android:paddingHorizontal=\"16dp\"\n                    android:singleLine=\"true\"\n                    android:ellipsize=\"end\"\n                    tools:text=\"10 results\" />\n\n                <com.google.android.material.button.MaterialButton\n                    android:id=\"@+id/replace_all_button\"\n                    style=\"@style/Widget.AppTheme.Button.IconButton\"\n                    android:layout_width=\"40dp\"\n                    android:layout_height=\"40dp\"\n                    android:layout_weight=\"0\"\n                    android:layout_gravity=\"center_vertical\"\n                    android:contentDescription=\"@string/replace\"\n                    app:icon=\"@drawable/ic_find_and_replace_all\"\n                    app:iconSize=\"30dp\" />\n\n                <com.google.android.material.button.MaterialButton\n                    android:id=\"@+id/replace_button\"\n                    style=\"@style/Widget.AppTheme.Button.IconButton\"\n                    android:layout_width=\"40dp\"\n                    android:layout_height=\"40dp\"\n                    android:layout_weight=\"0\"\n                    android:layout_gravity=\"center_vertical\"\n                    android:contentDescription=\"@string/action_replace_all\"\n                    app:icon=\"@drawable/ic_find_and_replace\"\n                    app:iconSize=\"30dp\" />\n\n                <com.google.android.material.button.MaterialButton\n                    android:id=\"@+id/previous_button\"\n                    style=\"@style/Widget.AppTheme.Button.IconButton\"\n                    android:layout_width=\"40dp\"\n                    android:layout_height=\"40dp\"\n                    android:layout_weight=\"0\"\n                    android:layout_gravity=\"center_vertical\"\n                    app:icon=\"@drawable/ic_expand_less\"\n                    app:iconSize=\"30dp\" />\n\n                <com.google.android.material.button.MaterialButton\n                    android:id=\"@+id/next_button\"\n                    style=\"@style/Widget.AppTheme.Button.IconButton\"\n                    android:layout_width=\"40dp\"\n                    android:layout_height=\"40dp\"\n                    android:layout_weight=\"0\"\n                    android:layout_gravity=\"center_vertical\"\n                    app:icon=\"@drawable/ic_expand_more\"\n                    app:iconSize=\"30dp\" />\n\n            </androidx.appcompat.widget.LinearLayoutCompat>\n\n        </androidx.appcompat.widget.LinearLayoutCompat>\n\n        <HorizontalScrollView\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\">\n\n            <io.github.rosemoe.sora.widget.SymbolInputView\n                android:id=\"@+id/symbol_input\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"36dp\" />\n\n        </HorizontalScrollView>\n\n        <androidx.appcompat.widget.LinearLayoutCompat\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:paddingHorizontal=\"8dp\"\n            android:paddingVertical=\"4dp\"\n            android:orientation=\"horizontal\">\n\n            <com.google.android.material.textview.MaterialTextView\n                android:id=\"@+id/position\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_weight=\"1\"\n                android:textSize=\"13sp\"\n                android:gravity=\"center\"\n                tools:text=\"108:39\" />\n\n            <com.google.android.material.textview.MaterialTextView\n                android:id=\"@+id/line_separator\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_weight=\"1\"\n                android:textSize=\"13sp\"\n                android:gravity=\"center\"\n                tools:text=\"LF\" />\n\n            <com.google.android.material.textview.MaterialTextView\n                android:id=\"@+id/tab_size\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_weight=\"1\"\n                android:textSize=\"13sp\"\n                android:gravity=\"center\"\n                tools:text=\"4 spaces\" />\n\n            <com.google.android.material.textview.MaterialTextView\n                android:id=\"@+id/language\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_weight=\"1\"\n                android:textSize=\"13sp\"\n                android:gravity=\"center\"\n                tools:text=\"Java\" />\n\n            <com.google.android.material.button.MaterialButton\n                android:id=\"@+id/lock\"\n                style=\"@style/Widget.AppTheme.Button.IconButton\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:minHeight=\"13dp\"\n                android:insetTop=\"0dp\"\n                android:insetBottom=\"0dp\"\n                android:paddingTop=\"0dp\"\n                android:paddingBottom=\"0dp\"\n                android:layout_weight=\"1\"\n                android:gravity=\"center\"\n                app:icon=\"@drawable/ic_unlock\"\n                app:iconSize=\"13dp\" />\n\n        </androidx.appcompat.widget.LinearLayoutCompat>\n\n    </androidx.appcompat.widget.LinearLayoutCompat>\n</androidx.appcompat.widget.LinearLayoutCompat>"
  },
  {
    "path": "app/src/main/res/layout/fragment_container.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<androidx.fragment.app.FragmentContainerView\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:id=\"@+id/fragment_container_view_tag\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\" />\n"
  },
  {
    "path": "app/src/main/res/layout/fragment_dialog_backup.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\">\n\n    <io.github.muntashirakon.widget.NestedScrollView\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginBottom=\"?attr/actionBarSize\"\n        android:scrollbars=\"vertical\"\n        android:scrollIndicators=\"top|bottom\"\n        tools:ignore=\"UnusedAttribute\">\n\n        <androidx.appcompat.widget.LinearLayoutCompat\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:orientation=\"vertical\">\n\n            <io.github.muntashirakon.widget.MaterialAlertView\n                android:id=\"@+id/message\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_marginHorizontal=\"@dimen/padding_medium\"\n                android:layout_marginVertical=\"@dimen/padding_small\"\n                android:visibility=\"gone\"\n                app:alertType=\"warn\"\n                tools:visibility=\"visible\"\n                tools:text=\"Some apps cannot be backed up.\" />\n\n            <io.github.muntashirakon.widget.RecyclerView\n                android:id=\"@android:id/list\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:overScrollMode=\"never\" />\n\n        </androidx.appcompat.widget.LinearLayoutCompat>\n\n    </io.github.muntashirakon.widget.NestedScrollView>\n\n    <RelativeLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"?attr/actionBarSize\"\n        android:layout_gravity=\"bottom\"\n        android:paddingHorizontal=\"@dimen/padding_medium\">\n\n        <com.google.android.material.button.MaterialButton\n            android:id=\"@+id/action_backup\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_alignParentEnd=\"true\"\n            android:layout_centerVertical=\"true\"\n            android:text=\"@string/back_up\" />\n\n    </RelativeLayout>\n\n</androidx.coordinatorlayout.widget.CoordinatorLayout>"
  },
  {
    "path": "app/src/main/res/layout/fragment_dialog_restore_multiple.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\">\n\n    <io.github.muntashirakon.widget.NestedScrollView\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginBottom=\"?attr/actionBarSize\"\n        android:scrollbars=\"vertical\"\n        android:scrollIndicators=\"top|bottom\"\n        tools:ignore=\"UnusedAttribute\">\n\n        <androidx.appcompat.widget.LinearLayoutCompat\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:orientation=\"vertical\">\n\n            <io.github.muntashirakon.widget.MaterialAlertView\n                android:id=\"@+id/message\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_marginHorizontal=\"@dimen/padding_medium\"\n                android:layout_marginVertical=\"@dimen/padding_small\"\n                android:visibility=\"gone\"\n                app:alertType=\"warn\"\n                tools:visibility=\"visible\"\n                tools:text=\"Some apps cannot be backed up.\" />\n\n            <io.github.muntashirakon.widget.RecyclerView\n                android:id=\"@android:id/list\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:overScrollMode=\"never\" />\n\n        </androidx.appcompat.widget.LinearLayoutCompat>\n\n    </io.github.muntashirakon.widget.NestedScrollView>\n\n    <RelativeLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"?attr/actionBarSize\"\n        android:layout_gravity=\"bottom\"\n        android:paddingHorizontal=\"@dimen/padding_medium\">\n\n        <com.google.android.material.button.MaterialButton\n            android:id=\"@+id/action_restore\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_alignParentEnd=\"true\"\n            android:layout_centerVertical=\"true\"\n            android:text=\"@string/restore\" />\n\n    </RelativeLayout>\n\n</androidx.coordinatorlayout.widget.CoordinatorLayout>"
  },
  {
    "path": "app/src/main/res/layout/fragment_dialog_restore_single.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\">\n\n    <io.github.muntashirakon.widget.NestedScrollView\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginBottom=\"?attr/actionBarSize\"\n        android:scrollbars=\"vertical\"\n        android:scrollIndicators=\"top|bottom\"\n        tools:ignore=\"UnusedAttribute\">\n\n        <androidx.appcompat.widget.LinearLayoutCompat\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:orientation=\"vertical\">\n\n            <io.github.muntashirakon.widget.MaterialAlertView\n                android:id=\"@+id/message\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_marginHorizontal=\"@dimen/padding_medium\"\n                android:layout_marginVertical=\"@dimen/padding_small\"\n                android:visibility=\"gone\"\n                app:alertType=\"warn\"\n                tools:visibility=\"visible\"\n                tools:text=\"Some apps cannot be backed up.\" />\n\n            <io.github.muntashirakon.widget.RecyclerView\n                android:id=\"@android:id/list\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:overScrollMode=\"never\" />\n\n        </androidx.appcompat.widget.LinearLayoutCompat>\n\n    </io.github.muntashirakon.widget.NestedScrollView>\n\n    <RelativeLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"?attr/actionBarSize\"\n        android:layout_gravity=\"bottom\"\n        android:paddingHorizontal=\"@dimen/padding_medium\">\n\n        <com.google.android.material.button.MaterialButton\n            android:id=\"@+id/action_restore\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_alignParentEnd=\"true\"\n            android:layout_centerInParent=\"true\"\n            android:layout_marginStart=\"@dimen/padding_small\"\n            android:text=\"@string/restore\" />\n\n        <com.google.android.material.button.MaterialButton\n            style=\"@style/Widget.AppTheme.Button.FilledTonalButton\"\n            android:id=\"@+id/action_delete\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_toStartOf=\"@id/action_restore\"\n            android:layout_centerInParent=\"true\"\n            android:layout_marginStart=\"@dimen/padding_small\"\n            android:text=\"@string/delete\" />\n\n        <com.google.android.material.button.MaterialButton\n            style=\"@style/Widget.AppTheme.Button.IconButton\"\n            android:id=\"@+id/more\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_toStartOf=\"@id/action_delete\"\n            android:layout_centerInParent=\"true\"\n            android:minWidth=\"48dp\"\n            android:maxWidth=\"0dp\"\n            android:maxHeight=\"0dp\"\n            app:icon=\"@drawable/ic_more_vert\"\n            app:iconPadding=\"0dp\"\n            app:iconGravity=\"textTop\"\n            app:iconSize=\"24dp\" />\n\n    </RelativeLayout>\n\n</androidx.coordinatorlayout.widget.CoordinatorLayout>\n"
  },
  {
    "path": "app/src/main/res/layout/fragment_fm.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<FrameLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    tools:context=\".fm.FmActivity\">\n\n    <com.leinardi.android.speeddial.SpeedDialOverlayLayout\n        android:id=\"@+id/overlay\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:layout_gravity=\"fill\"\n        android:fitsSystemWindows=\"true\" />\n\n    <FrameLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\">\n\n        <io.github.muntashirakon.widget.SwipeRefreshLayout\n            android:id=\"@+id/swipe_refresh\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:focusable=\"false\">\n\n            <androidx.appcompat.widget.LinearLayoutCompat\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:orientation=\"vertical\">\n\n                <androidx.appcompat.widget.LinearLayoutCompat\n                    android:id=\"@+id/path_container\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:fitsSystemWindows=\"true\"\n                    android:orientation=\"horizontal\">\n\n                    <io.github.muntashirakon.widget.RecyclerView\n                        android:id=\"@+id/path_list\"\n                        android:layout_width=\"0dp\"\n                        android:layout_height=\"wrap_content\"\n                        android:layout_weight=\"1\"\n                        android:clipToPadding=\"false\"\n                        android:fitsSystemWindows=\"false\"\n                        android:focusable=\"false\"\n                        android:paddingHorizontal=\"@dimen/padding_medium\"\n                        android:scrollbars=\"horizontal\"\n                        tools:listitem=\"@layout/m3_preference\" />\n\n                    <com.google.android.material.button.MaterialButton\n                        android:id=\"@+id/uri_edit\"\n                        style=\"@style/Widget.AppTheme.Button.IconButton\"\n                        android:layout_width=\"30dp\"\n                        android:layout_height=\"30dp\"\n                        android:layout_gravity=\"center_vertical\"\n                        android:layout_weight=\"0\"\n                        android:contentDescription=\"@string/item_edit\"\n                        app:icon=\"@drawable/ic_edit\" />\n\n                </androidx.appcompat.widget.LinearLayoutCompat>\n\n                <FrameLayout\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"match_parent\">\n\n                    <io.github.muntashirakon.widget.RecyclerView\n                        android:id=\"@+id/list_item\"\n                        android:layout_width=\"match_parent\"\n                        android:layout_height=\"match_parent\"\n                        android:clipToPadding=\"false\"\n                        android:fitsSystemWindows=\"true\"\n                        android:focusable=\"false\"\n                        android:scrollbars=\"none\"\n                        app:fastScrollerEnabled=\"true\"\n                        tools:listitem=\"@layout/m3_preference\" />\n\n                    <androidx.appcompat.widget.LinearLayoutCompat\n                        android:id=\"@android:id/empty\"\n                        android:layout_width=\"match_parent\"\n                        android:layout_height=\"match_parent\"\n                        android:gravity=\"center_vertical\"\n                        android:orientation=\"vertical\"\n                        android:paddingHorizontal=\"16dp\"\n                        android:paddingVertical=\"8dp\"\n                        android:visibility=\"gone\"\n                        tools:visibility=\"visible\">\n\n                        <androidx.appcompat.widget.AppCompatImageView\n                            android:id=\"@+id/icon\"\n                            android:layout_width=\"match_parent\"\n                            android:layout_height=\"wrap_content\"\n                            android:layout_gravity=\"center_horizontal\"\n                            android:adjustViewBounds=\"true\"\n                            android:maxHeight=\"72dp\"\n                            android:minHeight=\"48dp\"\n                            app:srcCompat=\"@drawable/ic_caution\" />\n\n                        <com.google.android.material.textview.MaterialTextView\n                            android:id=\"@+id/title\"\n                            android:layout_width=\"match_parent\"\n                            android:layout_height=\"wrap_content\"\n                            android:gravity=\"center_horizontal\"\n                            android:textAppearance=\"?attr/textAppearanceBodyLarge\"\n                            tools:text=\"Folder does not exist.\" />\n\n                        <com.google.android.material.textview.MaterialTextView\n                            android:id=\"@+id/message\"\n                            android:layout_width=\"match_parent\"\n                            android:layout_height=\"wrap_content\"\n                            android:fontFamily=\"monospace\"\n                            android:maxLines=\"10\"\n                            android:overScrollMode=\"ifContentScrolls\"\n                            android:scrollbars=\"vertical\"\n                            android:textAppearance=\"?attr/textAppearanceBodySmall\"\n                            android:textIsSelectable=\"true\"\n                            android:visibility=\"gone\"\n                            tools:text=\"Folder does not exist.\"\n                            tools:visibility=\"visible\" />\n\n                    </androidx.appcompat.widget.LinearLayoutCompat>\n\n                </FrameLayout>\n\n            </androidx.appcompat.widget.LinearLayoutCompat>\n\n        </io.github.muntashirakon.widget.SwipeRefreshLayout>\n\n        <io.github.muntashirakon.widget.MultiSelectionView\n            android:id=\"@+id/selection_view\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:fitsSystemWindows=\"true\"\n            android:focusable=\"false\"\n            app:menu=\"@menu/fragment_fm_selection_actions\" />\n\n    </FrameLayout>\n\n    <FrameLayout\n        android:id=\"@+id/fab_holder\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:clipChildren=\"false\"\n        android:clipToPadding=\"false\"\n        android:elevation=\"@dimen/sd_open_elevation\"\n        android:fitsSystemWindows=\"true\">\n\n        <io.github.muntashirakon.widget.FloatingActionButtonGroup\n            android:id=\"@+id/fab\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_gravity=\"bottom|end\"\n            android:layout_margin=\"@dimen/padding_medium\"\n            android:accessibilityTraversalBefore=\"@id/list_item\"\n            android:contentDescription=\"@string/add\"\n            app:sdMainFabClosedSrc=\"@drawable/ic_add\"\n            app:sdOverlayLayout=\"@id/overlay\"\n            tools:targetApi=\"22\" />\n    </FrameLayout>\n\n</FrameLayout>"
  },
  {
    "path": "app/src/main/res/layout/fragment_log_viewer.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n\n    <io.github.muntashirakon.widget.NestedScrollView\n        android:id=\"@+id/scrollView\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:clipToPadding=\"false\"\n        android:fitsSystemWindows=\"true\">\n\n        <androidx.appcompat.widget.AppCompatEditText\n            android:id=\"@+id/log_content\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:background=\"@null\"\n            android:fontFamily=\"monospace\"\n            android:gravity=\"top\"\n            android:padding=\"@dimen/padding_small\"\n            android:textIsSelectable=\"true\"\n            android:textSize=\"@dimen/font_size_medium\"\n            android:visibility=\"visible\"\n            tools:text=\"@tools:sample/lorem/random\" />\n\n    </io.github.muntashirakon.widget.NestedScrollView>\n\n    <com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton\n        android:id=\"@+id/floatingActionButton\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"bottom|end\"\n        android:layout_margin=\"@dimen/padding_medium\"\n        android:accessibilityTraversalBefore=\"@id/scrollView\"\n        android:fitsSystemWindows=\"true\"\n        android:text=\"@string/clear\"\n        app:icon=\"@drawable/ic_brush\"\n        app:layout_behavior=\"com.google.android.material.behavior.HideBottomViewOnScrollBehavior\"\n        tools:targetApi=\"22\" />\n\n</androidx.coordinatorlayout.widget.CoordinatorLayout>"
  },
  {
    "path": "app/src/main/res/layout/fragment_logcat.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    tools:context=\".logcat.LogViewerActivity\"\n    android:orientation=\"vertical\">\n\n    <io.github.muntashirakon.widget.RecyclerView\n        android:id=\"@+id/list\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:scrollbars=\"none\"\n        android:clipToPadding=\"false\"\n        android:fitsSystemWindows=\"true\"\n        app:fastScrollerEnabled=\"true\"\n        tools:listitem=\"@layout/item_logcat\" />\n\n    <io.github.muntashirakon.widget.MultiSelectionView\n        android:id=\"@+id/selection_view\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:fitsSystemWindows=\"true\"\n        android:focusable=\"false\"\n        app:menu=\"@menu/fragment_logcat_selection_actions\" />\n\n</androidx.coordinatorlayout.widget.CoordinatorLayout>"
  },
  {
    "path": "app/src/main/res/layout/fragment_mode_of_ops.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<io.github.muntashirakon.widget.NestedScrollView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:id=\"@+id/scrollView\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:fitsSystemWindows=\"true\"\n    android:clipToPadding=\"false\">\n\n    <androidx.appcompat.widget.LinearLayoutCompat\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:orientation=\"vertical\"\n        android:paddingHorizontal=\"@dimen/padding_medium\">\n\n        <com.google.android.material.card.MaterialCardView\n            style=\"@style/Widget.AppTheme.CardView.ListItem\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            app:cardBackgroundColor=\"?attr/colorPrimaryContainer\">\n\n            <androidx.appcompat.widget.LinearLayoutCompat\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:orientation=\"vertical\"\n                android:paddingVertical=\"16dp\"\n                android:paddingHorizontal=\"16dp\">\n\n                <com.google.android.material.textview.MaterialTextView\n                    android:id=\"@+id/inferred_mode\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:textColor=\"?attr/colorOnPrimaryContainer\"\n                    android:textAppearance=\"?attr/textAppearanceHeadlineMedium\"\n                    tools:text=\"Root\" />\n\n                <com.google.android.material.textview.MaterialTextView\n                    android:id=\"@+id/remote_server_status\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:gravity=\"center_vertical\"\n                    android:textAppearance=\"?attr/textAppearanceBodyMedium\"\n                    android:textColor=\"?attr/colorOnPrimaryContainer\"\n                    android:drawablePadding=\"@dimen/padding_very_small\"\n                    app:drawableTint=\"?attr/colorOnPrimaryContainer\"\n                    tools:drawableStartCompat=\"@drawable/ic_caution\"\n                    tools:text=\"Remote server inactive\" />\n\n\n                <com.google.android.material.textview.MaterialTextView\n                    android:id=\"@+id/remote_services_status\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:gravity=\"center_vertical\"\n                    android:textAppearance=\"?attr/textAppearanceBodyMedium\"\n                    android:textColor=\"?attr/colorOnPrimaryContainer\"\n                    android:drawablePadding=\"@dimen/padding_very_small\"\n                    app:drawableTint=\"?attr/colorOnPrimaryContainer\"\n                    tools:drawableStartCompat=\"@drawable/ic_check_circle\"\n                    tools:text=\"Remote services active\" />\n\n                <com.google.android.material.textview.MaterialTextView\n                    android:id=\"@+id/op_name\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:gravity=\"center_vertical\"\n                    android:textAppearance=\"?attr/textAppearanceBodyMedium\"\n                    android:textColor=\"?attr/colorOnPrimaryContainer\"\n                    android:drawablePadding=\"@dimen/padding_very_small\"\n                    app:drawableTint=\"?attr/colorOnPrimaryContainer\"\n                    tools:drawableStartCompat=\"@drawable/ic_check_circle\"\n                    tools:text=\"Connected via ADB over TCP\" />\n\n                <com.google.android.material.button.MaterialButton\n                    android:id=\"@+id/action_settings\"\n                    style=\"@style/Widget.AppTheme.Button.TextButton\"\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_gravity=\"end|center_vertical\"\n                    android:textColor=\"?attr/colorOnPrimaryContainer\"\n                    android:text=\"@string/change_mode\" />\n\n            </androidx.appcompat.widget.LinearLayoutCompat>\n\n        </com.google.android.material.card.MaterialCardView>\n\n        <androidx.appcompat.widget.LinearLayoutCompat\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:orientation=\"vertical\"\n            android:paddingVertical=\"@dimen/padding_medium\">\n\n            <com.google.android.material.textview.MaterialTextView\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:textAppearance=\"?attr/textAppearanceTitleMedium\"\n                android:text=\"@string/mode_of_op_custom_command_title\" />\n\n            <com.google.android.material.textview.MaterialTextView\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:text=\"@string/mode_of_op_custom_command\" />\n\n            <com.google.android.material.textfield.TextInputLayout\n                style=\"@style/Widget.AppTheme.TextInputLayout.Small\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:paddingVertical=\"@dimen/padding_small\"\n                app:endIconContentDescription=\"@string/copy\"\n                app:endIconMode=\"custom\"\n                app:endIconDrawable=\"@drawable/ic_content_copy\">\n\n                <io.github.muntashirakon.widget.TextInputTextView\n                    android:id=\"@android:id/text1\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:inputType=\"textMultiLine\"\n                    android:fontFamily=\"monospace\"\n                    android:textIsSelectable=\"true\"\n                    tools:text=\"sh /sdcard/Android/data/io.github.muntashirakon.AppManager/cache/run_server.sh 6001 yolk-good-folk\" />\n\n            </com.google.android.material.textfield.TextInputLayout>\n\n            <com.google.android.material.textview.MaterialTextView\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:text=\"@string/mode_of_op_alternative_custom_command\" />\n\n            <com.google.android.material.textfield.TextInputLayout\n                style=\"@style/Widget.AppTheme.TextInputLayout.Small\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:paddingVertical=\"@dimen/padding_small\"\n                app:endIconContentDescription=\"@string/copy\"\n                app:endIconMode=\"custom\"\n                app:endIconDrawable=\"@drawable/ic_content_copy\">\n\n                <io.github.muntashirakon.widget.TextInputTextView\n                    android:id=\"@android:id/text2\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:inputType=\"textMultiLine\"\n                    android:fontFamily=\"monospace\"\n                    android:textIsSelectable=\"true\"\n                    tools:text=\"sh /data/data_de/io.github.muntashirakon.AppManager/cache/run_server.sh 6001 yolk-good-folk\" />\n\n            </com.google.android.material.textfield.TextInputLayout>\n\n        </androidx.appcompat.widget.LinearLayoutCompat>\n\n    </androidx.appcompat.widget.LinearLayoutCompat>\n\n</io.github.muntashirakon.widget.NestedScrollView>"
  },
  {
    "path": "app/src/main/res/layout/fragment_scanner.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<androidx.appcompat.widget.LinearLayoutCompat xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    android:orientation=\"vertical\">\n\n    <io.github.muntashirakon.widget.NestedScrollView\n        android:id=\"@+id/list_item\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:fitsSystemWindows=\"true\">\n\n        <androidx.appcompat.widget.LinearLayoutCompat\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:orientation=\"vertical\">\n\n            <com.google.android.material.card.MaterialCardView\n                style=\"@style/Widget.AppTheme.CardView.ListItem.Padded\"\n                android:id=\"@+id/classes\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                app:cardElevation=\"0dp\"\n                android:focusable=\"true\">\n\n                <androidx.appcompat.widget.LinearLayoutCompat\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:padding=\"@dimen/padding_medium\"\n                    android:orientation=\"vertical\">\n\n                    <androidx.appcompat.widget.AppCompatTextView\n                        android:id=\"@+id/classes_title\"\n                        android:layout_width=\"match_parent\"\n                        android:layout_height=\"wrap_content\"\n                        android:textAppearance=\"?android:attr/textAppearanceListItem\"\n                        tools:text=\"1234 classes\" />\n\n                    <androidx.appcompat.widget.AppCompatTextView\n                        android:id=\"@+id/classes_description\"\n                        android:layout_width=\"match_parent\"\n                        android:layout_height=\"wrap_content\"\n                        android:textColor=\"?android:attr/textColorSecondary\"\n                        android:text=\"@string/tap_to_see_details\" />\n\n                </androidx.appcompat.widget.LinearLayoutCompat>\n\n            </com.google.android.material.card.MaterialCardView>\n\n            <com.google.android.material.card.MaterialCardView\n                style=\"@style/Widget.AppTheme.CardView.ListItem.Padded\"\n                android:id=\"@+id/tracker\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                app:cardElevation=\"0dp\"\n                android:focusable=\"true\">\n\n                <androidx.appcompat.widget.LinearLayoutCompat\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:padding=\"@dimen/padding_medium\"\n                    android:orientation=\"vertical\">\n\n                    <androidx.appcompat.widget.AppCompatTextView\n                        android:id=\"@+id/tracker_title\"\n                        android:layout_width=\"match_parent\"\n                        android:layout_height=\"wrap_content\"\n                        android:textAppearance=\"?android:attr/textAppearanceListItem\"\n                        tools:text=\"8 trackers with 593 classes\" />\n\n                    <androidx.appcompat.widget.AppCompatTextView\n                        android:id=\"@+id/tracker_description\"\n                        android:layout_width=\"match_parent\"\n                        android:layout_height=\"wrap_content\"\n                        android:textColor=\"?android:attr/textColorSecondary\"\n                        tools:text=\"Moat, Facebook login, Adjust, Facebook Analytics, Crashlytics\" />\n\n                </androidx.appcompat.widget.LinearLayoutCompat>\n\n            </com.google.android.material.card.MaterialCardView>\n\n            <com.google.android.material.card.MaterialCardView\n                style=\"@style/Widget.AppTheme.CardView.ListItem.Padded\"\n                android:id=\"@+id/vt\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                app:cardElevation=\"0dp\"\n                android:focusable=\"true\">\n\n                <androidx.appcompat.widget.LinearLayoutCompat\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:padding=\"@dimen/padding_medium\"\n                    android:orientation=\"vertical\">\n\n                    <androidx.appcompat.widget.AppCompatTextView\n                        android:id=\"@+id/vt_title\"\n                        android:layout_width=\"match_parent\"\n                        android:layout_height=\"wrap_content\"\n                        android:text=\"@string/vt_checking\"\n                        android:textAppearance=\"?android:attr/textAppearanceListItem\"\n                        tools:text=\"VirusTotal: 4/57\" />\n\n                    <androidx.appcompat.widget.AppCompatTextView\n                        android:id=\"@+id/vt_description\"\n                        android:layout_width=\"match_parent\"\n                        android:layout_height=\"wrap_content\"\n                        android:autoLink=\"web\"\n                        android:textColor=\"?android:attr/textColorSecondary\"\n                        android:text=\"@string/vt_slowness_warning\" />\n\n                </androidx.appcompat.widget.LinearLayoutCompat>\n\n            </com.google.android.material.card.MaterialCardView>\n\n            <com.google.android.material.card.MaterialCardView\n                style=\"@style/Widget.AppTheme.CardView.ListItem.Padded\"\n                android:id=\"@+id/pithus\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                app:cardElevation=\"0dp\"\n                android:focusable=\"true\">\n\n                <androidx.appcompat.widget.LinearLayoutCompat\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:padding=\"@dimen/padding_medium\"\n                    android:orientation=\"vertical\">\n\n                    <androidx.appcompat.widget.AppCompatTextView\n                        android:layout_width=\"match_parent\"\n                        android:layout_height=\"wrap_content\"\n                        android:text=\"@string/scan_report_from_pithus\"\n                        android:textAppearance=\"?android:attr/textAppearanceListItem\"\n                        tools:text=\"VirusTotal: 4/57\" />\n\n                    <androidx.appcompat.widget.AppCompatTextView\n                        android:id=\"@+id/pithus_description\"\n                        android:layout_width=\"match_parent\"\n                        android:layout_height=\"wrap_content\"\n                        android:autoLink=\"web\"\n                        android:textColor=\"?android:attr/textColorSecondary\"\n                        android:text=\"@string/action_checking\" />\n\n                </androidx.appcompat.widget.LinearLayoutCompat>\n\n            </com.google.android.material.card.MaterialCardView>\n\n            <com.google.android.material.card.MaterialCardView\n                style=\"@style/Widget.AppTheme.CardView.ListItem.Padded\"\n                android:id=\"@+id/libs\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                app:cardElevation=\"0dp\"\n                android:focusable=\"true\">\n\n                <androidx.appcompat.widget.LinearLayoutCompat\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:padding=\"@dimen/padding_medium\"\n                    android:orientation=\"vertical\">\n\n                    <androidx.appcompat.widget.AppCompatTextView\n                        android:id=\"@+id/libs_title\"\n                        android:layout_width=\"match_parent\"\n                        android:layout_height=\"wrap_content\"\n                        android:textAppearance=\"?android:attr/textAppearanceListItem\"\n                        tools:text=\"128 libraries\" />\n\n                    <androidx.appcompat.widget.AppCompatTextView\n                        android:id=\"@+id/libs_description\"\n                        android:layout_width=\"match_parent\"\n                        android:layout_height=\"wrap_content\"\n                        android:textColor=\"?android:attr/textColorSecondary\"\n                        tools:text=\"AppCompat, Room, Moat, Facebook login, Adjust, Facebook Analytics, Crashlytics\" />\n\n                </androidx.appcompat.widget.LinearLayoutCompat>\n\n            </com.google.android.material.card.MaterialCardView>\n\n            <com.google.android.material.card.MaterialCardView\n                style=\"@style/Widget.AppTheme.CardView.ListItem.Padded\"\n                android:id=\"@+id/apk\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                app:cardElevation=\"0dp\"\n                android:focusable=\"true\">\n\n                <androidx.appcompat.widget.LinearLayoutCompat\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:padding=\"@dimen/padding_medium\"\n                    android:orientation=\"vertical\">\n\n                    <androidx.appcompat.widget.AppCompatTextView\n                        android:id=\"@+id/apk_title\"\n                        android:layout_width=\"match_parent\"\n                        android:layout_height=\"wrap_content\"\n                        android:textAppearance=\"?android:attr/textAppearanceListItem\"\n                        tools:text=\"Apk Checksums\" />\n\n                    <androidx.appcompat.widget.AppCompatTextView\n                        android:id=\"@+id/apk_description\"\n                        android:layout_width=\"match_parent\"\n                        android:layout_height=\"wrap_content\"\n                        android:textColor=\"?android:attr/textColorSecondary\"\n                        android:textIsSelectable=\"true\"\n                        tools:text=\"@tools:sample/lorem[20]\" />\n\n                </androidx.appcompat.widget.LinearLayoutCompat>\n\n            </com.google.android.material.card.MaterialCardView>\n\n            <com.google.android.material.card.MaterialCardView\n                style=\"@style/Widget.AppTheme.CardView.ListItem.Padded\"\n                android:id=\"@+id/signatures\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                app:cardElevation=\"0dp\"\n                android:focusable=\"true\">\n\n                <androidx.appcompat.widget.LinearLayoutCompat\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:padding=\"@dimen/padding_medium\"\n                    android:orientation=\"vertical\">\n\n                    <androidx.appcompat.widget.AppCompatTextView\n                        android:id=\"@+id/checksum_title\"\n                        android:layout_width=\"match_parent\"\n                        android:layout_height=\"wrap_content\"\n                        android:textAppearance=\"?android:attr/textAppearanceListItem\"\n                        android:text=\"@string/app_signing_signature\" />\n\n                    <androidx.appcompat.widget.AppCompatTextView\n                        android:id=\"@+id/checksum_description\"\n                        android:layout_width=\"match_parent\"\n                        android:layout_height=\"wrap_content\"\n                        android:textColor=\"?android:attr/textColorSecondary\"\n                        android:textIsSelectable=\"true\"\n                        tools:text=\"@tools:sample/lorem[20]\" />\n\n                </androidx.appcompat.widget.LinearLayoutCompat>\n\n            </com.google.android.material.card.MaterialCardView>\n\n            <com.google.android.material.card.MaterialCardView\n                style=\"@style/Widget.AppTheme.CardView.ListItem.Padded\"\n                android:id=\"@+id/missing_libs\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                app:cardElevation=\"0dp\"\n                android:visibility=\"gone\"\n                tools:visibility=\"visible\">\n\n                <androidx.appcompat.widget.LinearLayoutCompat\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:padding=\"@dimen/padding_medium\"\n                    android:orientation=\"vertical\">\n\n                    <androidx.appcompat.widget.AppCompatTextView\n                        android:id=\"@+id/missing_libs_title\"\n                        android:layout_width=\"match_parent\"\n                        android:layout_height=\"wrap_content\"\n                        android:textAppearance=\"?android:attr/textAppearanceListItem\"\n                        tools:text=\"123 signatures missing\" />\n\n                    <androidx.appcompat.widget.AppCompatTextView\n                        android:id=\"@+id/missing_libs_description\"\n                        android:layout_width=\"match_parent\"\n                        android:layout_height=\"wrap_content\"\n                        android:textSize=\"@dimen/subtitle_font\"\n                        android:text=\"@string/view_missing_signatures\" />\n\n                </androidx.appcompat.widget.LinearLayoutCompat>\n\n            </com.google.android.material.card.MaterialCardView>\n\n            <androidx.appcompat.widget.AppCompatTextView\n                android:id=\"@+id/vt_disclaimer\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:padding=\"@dimen/padding_small\"\n                android:textSize=\"10sp\"\n                android:textColor=\"?android:attr/textColorSecondary\"\n                android:text=\"@string/vt_disclaimer\"\n                tools:ignore=\"SmallSp\" />\n\n        </androidx.appcompat.widget.LinearLayoutCompat>\n\n    </io.github.muntashirakon.widget.NestedScrollView>\n\n</androidx.appcompat.widget.LinearLayoutCompat>\n"
  },
  {
    "path": "app/src/main/res/layout/header_running_apps_memory_info.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<androidx.appcompat.widget.LinearLayoutCompat xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:orientation=\"vertical\">\n\n    <com.google.android.material.textview.MaterialTextView\n        android:id=\"@+id/memory_usage\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:paddingVertical=\"@dimen/padding_small\"\n        android:paddingHorizontal=\"@dimen/padding_medium\"\n        android:textSize=\"@dimen/font_size_larger\"\n        tools:text=\"Memory: 2.8 GB/2.1 GB\" />\n\n    <com.google.android.material.card.MaterialCardView\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginHorizontal=\"@dimen/padding_medium\">\n\n        <androidx.appcompat.widget.LinearLayoutCompat\n            android:id=\"@+id/memory_usage_chart\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"@dimen/padding_medium\"\n            android:orientation=\"horizontal\">\n\n            <View\n                android:layout_width=\"0dp\"\n                android:layout_height=\"match_parent\"\n                android:layout_weight=\"0\"\n                android:background=\"?attr/colorOnSurface\"\n                tools:layout_width=\"200dp\" />\n\n            <View\n                android:layout_width=\"0dp\"\n                android:layout_height=\"match_parent\"\n                android:layout_weight=\"0\"\n                android:background=\"?attr/colorPrimary\"\n                tools:layout_width=\"100dp\" />\n\n            <View\n                android:layout_width=\"0dp\"\n                android:layout_height=\"match_parent\"\n                android:layout_weight=\"0\"\n                android:background=\"?attr/colorTertiary\"\n                tools:layout_width=\"30dp\" />\n\n            <View\n                android:layout_width=\"0dp\"\n                android:layout_height=\"match_parent\"\n                android:layout_weight=\"1\"\n                android:background=\"?attr/colorSurfaceVariant\" />\n\n        </androidx.appcompat.widget.LinearLayoutCompat>\n\n    </com.google.android.material.card.MaterialCardView>\n\n    <com.google.android.material.textview.MaterialTextView\n        android:id=\"@+id/memory_usage_info\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:paddingVertical=\"@dimen/padding_small\"\n        android:paddingHorizontal=\"@dimen/padding_medium\"\n        android:textSize=\"@dimen/font_size_small\"\n        tools:text=\"@string/memory_chart_info\" />\n\n    <com.google.android.material.textview.MaterialTextView\n        android:id=\"@+id/swap_usage\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:paddingVertical=\"@dimen/padding_small\"\n        android:paddingHorizontal=\"@dimen/padding_medium\"\n        android:textSize=\"@dimen/font_size_larger\"\n        tools:text=\"Swap: 2.8 GB/2.1 GB\" />\n\n    <com.google.android.material.card.MaterialCardView\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginHorizontal=\"@dimen/padding_medium\">\n\n        <androidx.appcompat.widget.LinearLayoutCompat\n            android:id=\"@+id/swap_usage_chart\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"@dimen/padding_medium\"\n            android:orientation=\"horizontal\">\n\n            <View\n                android:layout_width=\"0dp\"\n                android:layout_height=\"match_parent\"\n                android:layout_weight=\"0\"\n                android:background=\"?attr/colorOnSurface\"\n                tools:layout_width=\"170dp\" />\n\n            <View\n                android:layout_width=\"0dp\"\n                android:layout_height=\"match_parent\"\n                android:layout_weight=\"1\"\n                android:background=\"?attr/colorSurfaceVariant\" />\n\n        </androidx.appcompat.widget.LinearLayoutCompat>\n\n    </com.google.android.material.card.MaterialCardView>\n\n    <com.google.android.material.textview.MaterialTextView\n        android:id=\"@+id/swap_usage_info\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:paddingVertical=\"@dimen/padding_small\"\n        android:paddingHorizontal=\"@dimen/padding_medium\"\n        android:textSize=\"@dimen/font_size_small\"\n        tools:text=\"@string/swap_chart_info\" />\n\n</androidx.appcompat.widget.LinearLayoutCompat>\n"
  },
  {
    "path": "app/src/main/res/layout/item_app_details_appop.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-or-later -->\n<com.google.android.material.card.MaterialCardView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    style=\"@style/Widget.AppTheme.CardView.ListItem.Outlined\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    app:cardElevation=\"0dp\"\n    android:focusable=\"true\"\n    android:layout_marginHorizontal=\"?attr/listItemMarginHorizontal\"\n    android:layout_marginVertical=\"?attr/listItemMarginVertical\">\n\n    <androidx.appcompat.widget.LinearLayoutCompat\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:orientation=\"horizontal\"\n        android:paddingHorizontal=\"?attr/listItemPaddingHorizontal\"\n        android:paddingVertical=\"?attr/listItemPaddingVertical\">\n\n        <androidx.appcompat.widget.LinearLayoutCompat\n            android:layout_width=\"0dp\"\n            android:layout_height=\"wrap_content\"\n            android:layout_weight=\"1\"\n            android:orientation=\"vertical\">\n\n            <androidx.appcompat.widget.AppCompatTextView\n                android:id=\"@+id/op_name\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:textAppearance=\"?android:attr/textAppearanceListItem\"\n                android:textIsSelectable=\"true\"\n                tools:text=\"@tools:sample/lorem\" />\n\n            <androidx.appcompat.widget.AppCompatTextView\n                android:id=\"@+id/op_mode_running_duration\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:textAppearance=\"?attr/textAppearanceBodySmall\"\n                tools:text=\"@tools:sample/lorem\" />\n\n            <androidx.appcompat.widget.AppCompatTextView\n                android:id=\"@+id/op_accept_reject_time\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:textAppearance=\"?attr/textAppearanceBodySmall\"\n                tools:text=\"@tools:sample/lorem\" />\n\n            <androidx.appcompat.widget.AppCompatTextView\n                android:id=\"@+id/perm_description\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:textAppearance=\"?attr/textAppearanceBodySmall\"\n                tools:text=\"@tools:sample/lorem\" />\n\n            <androidx.appcompat.widget.AppCompatTextView\n                android:id=\"@+id/perm_protection_level\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:textAppearance=\"?attr/textAppearanceBodySmall\"\n                android:textSize=\"10sp\"\n                tools:ignore=\"SmallSp\"\n                tools:text=\"@tools:sample/lorem\" />\n\n            <androidx.appcompat.widget.AppCompatTextView\n                android:id=\"@+id/perm_name\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:textIsSelectable=\"true\"\n                android:textAppearance=\"?attr/textAppearanceBodySmall\"\n                tools:text=\"@tools:sample/lorem\" />\n\n            <androidx.appcompat.widget.AppCompatTextView\n                android:id=\"@+id/perm_package_name\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:textIsSelectable=\"true\"\n                android:textAppearance=\"?attr/textAppearanceBodySmall\"\n                tools:text=\"@tools:sample/lorem\" />\n\n            <androidx.appcompat.widget.AppCompatTextView\n                android:id=\"@+id/perm_group\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:textIsSelectable=\"true\"\n                android:textAppearance=\"?attr/textAppearanceBodySmall\"\n                tools:text=\"@tools:sample/lorem\" />\n\n        </androidx.appcompat.widget.LinearLayoutCompat>\n\n        <com.google.android.material.materialswitch.MaterialSwitch\n            android:id=\"@+id/perm_toggle_btn\"\n            android:layout_width=\"56dp\"\n            android:layout_height=\"wrap_content\"\n            android:layout_gravity=\"center\"\n            android:layout_weight=\"0\"\n            android:clickable=\"false\"\n            android:focusable=\"false\" />\n\n    </androidx.appcompat.widget.LinearLayoutCompat>\n\n</com.google.android.material.card.MaterialCardView>"
  },
  {
    "path": "app/src/main/res/layout/item_app_details_overlay.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-or-later -->\n<com.google.android.material.card.MaterialCardView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    style=\"@style/Widget.AppTheme.CardView.ListItem.Outlined\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:layout_marginHorizontal=\"?attr/listItemMarginHorizontal\"\n    android:layout_marginVertical=\"?attr/listItemMarginVertical\"\n    android:focusable=\"true\"\n    app:cardElevation=\"0dp\">\n\n    <androidx.appcompat.widget.LinearLayoutCompat\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:orientation=\"horizontal\"\n        android:paddingHorizontal=\"?attr/listItemPaddingHorizontal\"\n        android:paddingVertical=\"?attr/listItemPaddingVertical\">\n\n        <androidx.appcompat.widget.LinearLayoutCompat\n            android:layout_width=\"0dp\"\n            android:layout_height=\"wrap_content\"\n            android:layout_weight=\"1\"\n            android:orientation=\"vertical\">\n\n            <androidx.appcompat.widget.AppCompatTextView\n                android:id=\"@+id/overlay_name\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:textAppearance=\"?android:attr/textAppearanceListItem\"\n                android:textIsSelectable=\"true\"\n                tools:text=\"OverlayName\" />\n\n            <androidx.appcompat.widget.AppCompatTextView\n                android:id=\"@+id/overlay_package_name\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:textAppearance=\"?attr/textAppearanceBodySmall\"\n                tools:text=\"@tools:sample/lorem[5]\" />\n\n            <androidx.appcompat.widget.AppCompatTextView\n                android:id=\"@+id/overlay_category\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:textAppearance=\"?attr/textAppearanceBodySmall\"\n                android:textSize=\"10sp\"\n                tools:ignore=\"SmallSp\"\n                tools:text=\"Category: rro\" />\n\n            <androidx.appcompat.widget.AppCompatTextView\n                android:id=\"@+id/overlay_state\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:textAppearance=\"?attr/textAppearanceBodySmall\"\n                android:textIsSelectable=\"true\"\n                tools:text=\"State: enabled | Priority: 1\" />\n\n        </androidx.appcompat.widget.LinearLayoutCompat>\n\n        <com.google.android.material.materialswitch.MaterialSwitch\n            android:id=\"@+id/overlay_toggle_btn\"\n            android:layout_width=\"56dp\"\n            android:layout_height=\"wrap_content\"\n            android:layout_gravity=\"center\"\n            android:layout_weight=\"0\"\n            android:clickable=\"false\"\n            android:focusable=\"false\" />\n\n    </androidx.appcompat.widget.LinearLayoutCompat>\n\n</com.google.android.material.card.MaterialCardView>"
  },
  {
    "path": "app/src/main/res/layout/item_app_details_perm.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-or-later -->\n<com.google.android.material.card.MaterialCardView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    style=\"@style/Widget.AppTheme.CardView.ListItem.Outlined\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:layout_marginHorizontal=\"?attr/listItemMarginHorizontal\"\n    android:layout_marginVertical=\"?attr/listItemMarginVertical\"\n    android:focusable=\"true\"\n    app:cardElevation=\"0dp\">\n\n    <androidx.appcompat.widget.LinearLayoutCompat\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:orientation=\"horizontal\"\n        android:paddingHorizontal=\"?attr/listItemPaddingHorizontal\"\n        android:paddingVertical=\"?attr/listItemPaddingVertical\">\n\n        <androidx.appcompat.widget.LinearLayoutCompat\n            android:layout_width=\"0dp\"\n            android:layout_height=\"wrap_content\"\n            android:layout_weight=\"1\"\n            android:orientation=\"vertical\">\n\n            <androidx.appcompat.widget.AppCompatTextView\n                android:id=\"@+id/perm_name\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:textAppearance=\"?android:attr/textAppearanceListItem\"\n                android:textIsSelectable=\"true\"\n                tools:text=\"android.permission.A_VERY_LONG_PERMISSION_NAME\" />\n\n            <androidx.appcompat.widget.AppCompatTextView\n                android:id=\"@+id/perm_description\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:textAppearance=\"?attr/textAppearanceBodySmall\"\n                tools:text=\"@tools:sample/lorem[10]\" />\n\n            <androidx.appcompat.widget.AppCompatTextView\n                android:id=\"@+id/perm_protection_level\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:textAppearance=\"?attr/textAppearanceBodySmall\"\n                android:textSize=\"10sp\"\n                tools:ignore=\"SmallSp\"\n                tools:text=\"⚑ dangerous|instant\" />\n\n            <androidx.appcompat.widget.AppCompatTextView\n                android:id=\"@+id/perm_package_name\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:textAppearance=\"?attr/textAppearanceBodySmall\"\n                android:textIsSelectable=\"true\"\n                tools:text=\"Package Name: android\" />\n\n            <androidx.appcompat.widget.AppCompatTextView\n                android:id=\"@+id/perm_group\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:textAppearance=\"?attr/textAppearanceBodySmall\"\n                android:textIsSelectable=\"true\"\n                tools:text=\"Group: android.permission-group.UNDEFINED\" />\n\n        </androidx.appcompat.widget.LinearLayoutCompat>\n\n        <androidx.appcompat.widget.LinearLayoutCompat\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_gravity=\"center\"\n            android:layout_weight=\"0\"\n            android:orientation=\"vertical\">\n\n            <com.google.android.material.materialswitch.MaterialSwitch\n                android:id=\"@+id/perm_toggle_btn\"\n                android:layout_width=\"56dp\"\n                android:layout_height=\"wrap_content\"\n                android:clickable=\"false\"\n                android:focusable=\"false\"\n                android:paddingVertical=\"@dimen/padding_medium\" />\n\n            <com.google.android.material.button.MaterialButton\n                android:id=\"@+id/action_settings\"\n                style=\"@style/Widget.AppTheme.Button.IconButton\"\n                android:layout_width=\"48dp\"\n                android:layout_height=\"48dp\"\n                android:layout_gravity=\"center\"\n                android:contentDescription=\"@string/view_in_settings\"\n                android:paddingVertical=\"@dimen/padding_small\"\n                android:visibility=\"gone\"\n                app:icon=\"@drawable/ic_settings\"\n                app:iconSize=\"20dp\"\n                tools:visibility=\"visible\" />\n\n        </androidx.appcompat.widget.LinearLayoutCompat>\n\n    </androidx.appcompat.widget.LinearLayoutCompat>\n\n</com.google.android.material.card.MaterialCardView>"
  },
  {
    "path": "app/src/main/res/layout/item_app_details_primary.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-or-later -->\n<com.google.android.material.card.MaterialCardView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    style=\"@style/Widget.AppTheme.CardView.ListItem.Outlined\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:focusable=\"true\"\n    android:descendantFocusability=\"beforeDescendants\"\n    app:cardElevation=\"0dp\"\n    android:layout_marginHorizontal=\"?attr/listItemMarginHorizontal\"\n    android:layout_marginVertical=\"?attr/listItemMarginVertical\">\n\n    <com.google.android.material.chip.Chip\n        android:id=\"@+id/type\"\n        style=\"@style/Widget.AppTheme.CardView.Outlined.DiagonallyRounded\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"12dp\"\n        android:layout_gravity=\"end\"\n        android:textSize=\"@dimen/font_size_smaller\"\n        android:textAllCaps=\"true\"\n        tools:text=\"Type\" />\n\n    <androidx.appcompat.widget.LinearLayoutCompat\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:orientation=\"vertical\"\n        android:paddingHorizontal=\"?attr/listItemPaddingHorizontal\"\n        android:paddingVertical=\"?attr/listItemPaddingVertical\">\n\n        <androidx.appcompat.widget.LinearLayoutCompat\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:orientation=\"horizontal\">\n\n            <androidx.appcompat.widget.AppCompatImageView\n                android:id=\"@+id/icon\"\n                android:layout_width=\"40dp\"\n                android:layout_height=\"40dp\"\n                android:layout_marginEnd=\"@dimen/padding_small\"\n                android:layout_weight=\"0\"\n                android:contentDescription=\"@string/str_logo\" />\n\n            <androidx.appcompat.widget.LinearLayoutCompat\n                android:layout_width=\"0dp\"\n                android:layout_height=\"wrap_content\"\n                android:layout_weight=\"1\"\n                android:orientation=\"vertical\">\n\n                <com.google.android.material.textview.MaterialTextView\n                    android:id=\"@+id/label\"\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_gravity=\"center_vertical\"\n                    android:gravity=\"center\"\n                    android:singleLine=\"true\"\n                    android:textIsSelectable=\"true\"\n                    android:textAppearance=\"?android:attr/textAppearanceListItem\"\n                    tools:text=\"@tools:sample/lorem\" />\n\n                <com.google.android.material.textview.MaterialTextView\n                    android:id=\"@+id/orientation\"\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:textIsSelectable=\"true\"\n                    android:textAppearance=\"?attr/textAppearanceBodySmall\"\n                    android:textSize=\"10sp\"\n                    tools:text=\"@tools:sample/lorem\"\n                    tools:ignore=\"SmallSp\" />\n\n            </androidx.appcompat.widget.LinearLayoutCompat>\n\n            <com.google.android.material.materialswitch.MaterialSwitch\n                android:id=\"@+id/toggle_button\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_gravity=\"center\"\n                android:layout_weight=\"0\"\n                android:clickable=\"false\"\n                android:focusable=\"false\" />\n\n        </androidx.appcompat.widget.LinearLayoutCompat>\n\n        <androidx.appcompat.widget.LinearLayoutCompat\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:orientation=\"horizontal\"\n            android:gravity=\"end\">\n\n            <com.google.android.material.textview.MaterialTextView\n                android:id=\"@+id/softInput\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_weight=\"1\"\n                android:textIsSelectable=\"true\"\n                android:textAppearance=\"?attr/textAppearanceBodySmall\"\n                android:textSize=\"9sp\"\n                tools:text=\"@tools:sample/lorem\"\n                tools:ignore=\"SmallSp\" />\n\n            <com.google.android.material.textview.MaterialTextView\n                android:id=\"@+id/method\"\n                android:layout_width=\"52dp\"\n                android:layout_height=\"wrap_content\"\n                android:textAppearance=\"?attr/textAppearanceBodySmall\"\n                android:textSize=\"9sp\"\n                android:singleLine=\"true\"\n                android:textAlignment=\"center\"\n                android:visibility=\"gone\"\n                tools:visibility=\"visible\"\n                tools:text=\"IFW+D\"\n                tools:ignore=\"SmallSp\" />\n\n        </androidx.appcompat.widget.LinearLayoutCompat>\n\n        <com.google.android.material.textview.MaterialTextView\n            android:id=\"@+id/launchMode\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:textIsSelectable=\"true\"\n            android:textAppearance=\"?attr/textAppearanceBodySmall\"\n            android:textSize=\"11sp\"\n            tools:text=\"@tools:sample/lorem\"\n            tools:ignore=\"SmallSp\" />\n\n        <com.google.android.material.textview.MaterialTextView\n            android:id=\"@+id/process_name\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:textIsSelectable=\"true\"\n            android:textAppearance=\"?attr/textAppearanceBodySmall\"\n            android:textSize=\"9sp\"\n            android:visibility=\"gone\"\n            tools:text=\"@tools:sample/lorem\"\n            tools:ignore=\"SmallSp\" />\n\n        <com.google.android.material.textview.MaterialTextView\n            android:id=\"@+id/taskAffinity\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:gravity=\"center_vertical\"\n            android:textIsSelectable=\"true\"\n            android:textAppearance=\"?attr/textAppearanceBodySmall\"\n            tools:text=\"@tools:sample/lorem\" />\n\n        <com.google.android.material.textview.MaterialTextView\n            android:id=\"@+id/name\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:fontFamily=\"monospace\"\n            android:textIsSelectable=\"true\"\n            android:textAppearance=\"?attr/textAppearanceBodySmall\"\n            tools:text=\"@tools:sample/lorem\" />\n\n        <androidx.appcompat.widget.LinearLayoutCompat\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:orientation=\"horizontal\">\n\n            <com.google.android.material.button.MaterialButton\n                android:id=\"@+id/launch\"\n                style=\"@style/Widget.AppTheme.Button.OutlinedButton.Dense\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_marginHorizontal=\"@dimen/padding_small\"\n                android:layout_marginVertical=\"@dimen/padding_very_small\"\n                android:layout_weight=\"1\"\n                android:singleLine=\"true\"\n                android:textSize=\"11sp\"\n                android:text=\"@string/launch\"\n                tools:ignore=\"SmallSp\" />\n\n            <com.google.android.material.button.MaterialButton\n                android:id=\"@+id/edit_shortcut_btn\"\n                style=\"@style/Widget.AppTheme.Button.OutlinedButton.Dense\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_marginHorizontal=\"@dimen/padding_small\"\n                android:layout_marginVertical=\"@dimen/padding_very_small\"\n                android:layout_weight=\"1\"\n                android:singleLine=\"true\"\n                android:textSize=\"11sp\"\n                android:text=\"@string/create_shortcut\"\n                tools:ignore=\"SmallSp\" />\n        </androidx.appcompat.widget.LinearLayoutCompat>\n\n    </androidx.appcompat.widget.LinearLayoutCompat>\n\n</com.google.android.material.card.MaterialCardView>"
  },
  {
    "path": "app/src/main/res/layout/item_app_details_secondary.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-or-later -->\n<com.google.android.material.card.MaterialCardView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    style=\"@style/Widget.AppTheme.CardView.ListItem.Outlined\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:minHeight=\"?android:attr/listPreferredItemHeightSmall\"\n    android:focusable=\"true\"\n    app:cardElevation=\"0dp\"\n    android:layout_marginHorizontal=\"?attr/listItemMarginHorizontal\"\n    android:layout_marginVertical=\"?attr/listItemMarginVertical\">\n\n    <androidx.appcompat.widget.LinearLayoutCompat\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:orientation=\"vertical\"\n        android:focusable=\"true\"\n        android:paddingHorizontal=\"?attr/listItemPaddingHorizontal\"\n        android:paddingVertical=\"?attr/listItemPaddingVertical\">\n\n        <androidx.appcompat.widget.AppCompatTextView\n            android:id=\"@+id/name\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:textIsSelectable=\"true\"\n            android:textAppearance=\"?android:attr/textAppearanceListItem\"\n            tools:text=\"@tools:sample/lorem\" />\n\n        <androidx.appcompat.widget.AppCompatTextView\n            android:id=\"@+id/gles_ver\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:textIsSelectable=\"true\"\n            android:textAppearance=\"?attr/textAppearanceBodySmall\"\n            tools:text=\"@tools:sample/lorem\" />\n\n    </androidx.appcompat.widget.LinearLayoutCompat>\n</com.google.android.material.card.MaterialCardView>"
  },
  {
    "path": "app/src/main/res/layout/item_app_details_signature.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<com.google.android.material.card.MaterialCardView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    style=\"@style/Widget.AppTheme.CardView.ListItem.Outlined\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:minHeight=\"?android:attr/listPreferredItemHeightSmall\"\n    android:focusable=\"true\"\n    app:cardElevation=\"0dp\"\n    android:layout_marginHorizontal=\"?attr/listItemMarginHorizontal\"\n    android:layout_marginVertical=\"?attr/listItemMarginVertical\">\n\n    <androidx.appcompat.widget.LinearLayoutCompat\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:orientation=\"vertical\"\n        android:focusable=\"true\"\n        android:paddingHorizontal=\"?attr/listItemPaddingHorizontal\"\n        android:paddingVertical=\"?attr/listItemPaddingVertical\">\n\n        <androidx.appcompat.widget.AppCompatTextView\n            android:id=\"@+id/checksum_description\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:textIsSelectable=\"true\"\n            android:textAppearance=\"?android:attr/textAppearanceListItemSecondary\"\n            tools:text=\"@tools:sample/lorem\" />\n\n    </androidx.appcompat.widget.LinearLayoutCompat>\n</com.google.android.material.card.MaterialCardView>"
  },
  {
    "path": "app/src/main/res/layout/item_app_details_tertiary.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-or-later -->\n<com.google.android.material.card.MaterialCardView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    style=\"@style/Widget.AppTheme.CardView.ListItem.Outlined\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:minHeight=\"?android:attr/listPreferredItemHeightSmall\"\n    android:focusable=\"true\"\n    app:cardElevation=\"0dp\"\n    android:layout_marginHorizontal=\"?attr/listItemMarginHorizontal\"\n    android:layout_marginVertical=\"?attr/listItemMarginVertical\">\n\n    <androidx.appcompat.widget.LinearLayoutCompat\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:orientation=\"vertical\"\n        android:focusable=\"true\"\n        android:paddingHorizontal=\"?attr/listItemPaddingHorizontal\"\n        android:paddingVertical=\"?attr/listItemPaddingVertical\">\n\n        <androidx.appcompat.widget.AppCompatTextView\n            android:id=\"@+id/reqgles\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:textIsSelectable=\"true\"\n            android:textAppearance=\"?android:attr/textAppearanceListItem\"\n            tools:text=\"@tools:sample/lorem\" />\n\n        <androidx.appcompat.widget.AppCompatTextView\n            android:id=\"@+id/reqfea\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginStart=\"5dp\"\n            android:textIsSelectable=\"true\"\n            android:textAppearance=\"?attr/textAppearanceBodySmall\"\n            tools:text=\"@tools:sample/lorem\" />\n\n        <androidx.appcompat.widget.AppCompatTextView\n            android:id=\"@+id/reqkey\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginStart=\"5dp\"\n            android:textIsSelectable=\"true\"\n            android:textAppearance=\"?attr/textAppearanceBodySmall\"\n            tools:text=\"@tools:sample/lorem\" />\n\n        <androidx.appcompat.widget.AppCompatTextView\n            android:id=\"@+id/reqnav\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginStart=\"5dp\"\n            android:textIsSelectable=\"true\"\n            android:textAppearance=\"?attr/textAppearanceBodySmall\"\n            tools:text=\"@tools:sample/lorem\" />\n\n        <androidx.appcompat.widget.AppCompatTextView\n            android:id=\"@+id/reqtouch\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginStart=\"5dp\"\n            android:textIsSelectable=\"true\"\n            android:textAppearance=\"?attr/textAppearanceBodySmall\"\n            tools:text=\"@tools:sample/lorem\" />\n\n    </androidx.appcompat.widget.LinearLayoutCompat>\n\n</com.google.android.material.card.MaterialCardView>\n"
  },
  {
    "path": "app/src/main/res/layout/item_app_info_action.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<com.google.android.material.button.MaterialButton xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    style=\"@style/Widget.AppTheme.Button.TextIconButton\"\n    android:layout_width=\"wrap_content\"\n    android:layout_height=\"wrap_content\"\n    android:layout_marginHorizontal=\"1dp\"\n    android:focusable=\"true\"\n    tools:text=\"@tools:sample/cities\"\n    tools:icon=\"@tools:sample/avatars\" />\n"
  },
  {
    "path": "app/src/main/res/layout/item_app_usage.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<com.google.android.material.card.MaterialCardView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    style=\"@style/Widget.AppTheme.CardView.ListItem\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:clickable=\"true\"\n    android:focusable=\"true\"\n    android:layout_marginHorizontal=\"?attr/listItemMarginHorizontal\"\n    android:layout_marginVertical=\"?attr/listItemMarginVertical\">\n\n    <androidx.appcompat.widget.LinearLayoutCompat\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:orientation=\"horizontal\"\n        android:paddingHorizontal=\"?attr/listItemPaddingHorizontal\"\n        android:paddingVertical=\"?attr/listItemPaddingVertical\">\n\n        <androidx.appcompat.widget.LinearLayoutCompat\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"match_parent\"\n            android:layout_marginEnd=\"@dimen/padding_small\"\n            android:orientation=\"vertical\">\n\n            <View\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"0dp\"\n                android:layout_weight=\"1\" />\n\n            <FrameLayout\n                android:id=\"@+id/icon_frame\"\n                android:layout_width=\"44dp\"\n                android:layout_height=\"44dp\"\n                android:layout_weight=\"0\">\n\n                    <com.google.android.material.imageview.ShapeableImageView\n                        android:id=\"@+id/icon\"\n                        android:layout_width=\"@dimen/icon_size\"\n                        android:layout_height=\"@dimen/icon_size\"\n                        android:layout_gravity=\"center\"\n                        android:scaleType=\"centerCrop\"\n                        android:adjustViewBounds=\"true\"\n                        app:shapeAppearanceOverlay=\"@style/ShapeAppearance.AppTheme.CircleComponent\"\n                        tools:srcCompat=\"@mipmap/ic_launcher\"\n                        android:contentDescription=\"@string/str_logo\" />\n\n                <com.google.android.material.textview.MaterialTextView\n                    android:id=\"@+id/badge\"\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_gravity=\"bottom|end\"\n                    android:minHeight=\"20dp\"\n                    android:minWidth=\"20dp\"\n                    android:paddingHorizontal=\"3dp\"\n                    android:gravity=\"center\"\n                    android:background=\"@drawable/badge_background\"\n                    android:textAppearance=\"?attr/textAppearanceLabelSmall\"\n                    tools:text=\"10\" />\n\n            </FrameLayout>\n\n            <View\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"0dp\"\n                android:layout_weight=\"1\" />\n\n            <com.google.android.material.textview.MaterialTextView\n                android:id=\"@+id/percent_usage\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"14sp\"\n                android:layout_weight=\"0\"\n                android:gravity=\"center\"\n                android:textAppearance=\"?attr/textAppearanceLabelMedium\"\n                tools:text=\"40%\" />\n\n        </androidx.appcompat.widget.LinearLayoutCompat>\n\n        <androidx.appcompat.widget.LinearLayoutCompat\n            android:layout_width=\"0dp\"\n            android:layout_height=\"wrap_content\"\n            android:layout_weight=\"1\"\n            android:orientation=\"vertical\">\n\n            <com.google.android.material.textview.MaterialTextView\n                android:id=\"@+id/label\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:singleLine=\"true\"\n                android:textAppearance=\"?android:attr/textAppearanceListItem\"\n                tools:text=\"@string/app_name\" />\n\n            <com.google.android.material.textview.MaterialTextView\n                android:id=\"@+id/package_name\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:singleLine=\"true\"\n                android:textStyle=\"italic\"\n                android:textAppearance=\"?attr/textAppearanceBodySmall\"\n                tools:text=\"io.github.muntashirakon.AppManager.debug\" />\n\n            <androidx.appcompat.widget.LinearLayoutCompat\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:orientation=\"horizontal\"\n                android:baselineAligned=\"false\">\n\n                <androidx.appcompat.widget.LinearLayoutCompat\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_weight=\"1\"\n                    android:orientation=\"vertical\">\n\n                    <com.google.android.material.textview.MaterialTextView\n                        android:id=\"@+id/date\"\n                        android:layout_width=\"wrap_content\"\n                        android:layout_height=\"wrap_content\"\n                        android:singleLine=\"true\"\n                        android:textAppearance=\"?attr/textAppearanceBodySmall\"\n                        tools:text=\"@tools:sample/date/mmddyy\" />\n\n                    <com.google.android.material.textview.MaterialTextView\n                        android:id=\"@+id/screen_time\"\n                        android:layout_width=\"match_parent\"\n                        android:layout_height=\"wrap_content\"\n                        android:singleLine=\"true\"\n                        android:textAppearance=\"?attr/textAppearanceBodySmall\"\n                        tools:text=\"@tools:sample/lorem\" />\n\n                </androidx.appcompat.widget.LinearLayoutCompat>\n\n                <androidx.appcompat.widget.LinearLayoutCompat\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_weight=\"1\"\n                    android:orientation=\"vertical\">\n\n                    <com.google.android.material.textview.MaterialTextView\n                        android:id=\"@+id/data_usage\"\n                        android:layout_width=\"match_parent\"\n                        android:layout_height=\"wrap_content\"\n                        android:singleLine=\"true\"\n                        android:textAppearance=\"?attr/textAppearanceBodySmall\"\n                        tools:text=\"@tools:sample/us_zipcodes[0]\" />\n\n                    <com.google.android.material.textview.MaterialTextView\n                        android:id=\"@+id/wifi_usage\"\n                        android:layout_width=\"match_parent\"\n                        android:layout_height=\"wrap_content\"\n                        android:singleLine=\"true\"\n                        android:textAppearance=\"?attr/textAppearanceBodySmall\"\n                        tools:text=\"@tools:sample/us_zipcodes[1]\" />\n\n                </androidx.appcompat.widget.LinearLayoutCompat>\n\n            </androidx.appcompat.widget.LinearLayoutCompat>\n\n            <com.google.android.material.progressindicator.LinearProgressIndicator\n                android:id=\"@+id/progress_linear\"\n                style=\"@style/Widget.AppTheme.LinearProgressIndicator\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_marginTop=\"@dimen/padding_very_small\"\n                android:max=\"100\"\n                tools:progress=\"40\" />\n\n        </androidx.appcompat.widget.LinearLayoutCompat>\n\n    </androidx.appcompat.widget.LinearLayoutCompat>\n\n</com.google.android.material.card.MaterialCardView>"
  },
  {
    "path": "app/src/main/res/layout/item_app_usage_header.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<androidx.appcompat.widget.LinearLayoutCompat xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:orientation=\"vertical\">\n\n    <androidx.appcompat.widget.LinearLayoutCompat\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:orientation=\"horizontal\">\n\n        <com.google.android.material.button.MaterialButton\n            android:id=\"@+id/action_previous\"\n            style=\"@style/Widget.AppTheme.Button.IconButton\"\n            android:layout_width=\"48dp\"\n            android:layout_height=\"48dp\"\n            android:layout_gravity=\"center\"\n            android:layout_marginStart=\"@dimen/padding_small\"\n            android:layout_weight=\"0\"\n            android:contentDescription=\"@string/goto_previous\"\n            android:paddingVertical=\"@dimen/padding_small\"\n            app:icon=\"@drawable/ic_previous\"\n            app:iconSize=\"20dp\" />\n\n        <androidx.appcompat.widget.LinearLayoutCompat\n            android:layout_width=\"0dp\"\n            android:layout_height=\"wrap_content\"\n            android:layout_weight=\"1\"\n            android:orientation=\"vertical\">\n\n            <com.google.android.material.textview.MaterialTextView\n                android:id=\"@+id/screen_time\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:focusable=\"false\"\n                android:gravity=\"center\"\n                android:textAppearance=\"@style/TextAppearance.AppTheme.DisplaySmall\"\n                tools:text=\"1 hr 20 mins\" />\n\n            <com.google.android.material.textview.MaterialTextView\n                android:id=\"@+id/time\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:focusable=\"false\"\n                android:gravity=\"center\"\n                android:textAppearance=\"@style/TextAppearance.AppTheme.TitleSmall\"\n                tools:text=\"Today\" />\n\n        </androidx.appcompat.widget.LinearLayoutCompat>\n\n        <com.google.android.material.button.MaterialButton\n            android:id=\"@+id/action_next\"\n            style=\"@style/Widget.AppTheme.Button.IconButton\"\n            android:layout_width=\"48dp\"\n            android:layout_height=\"48dp\"\n            android:layout_gravity=\"center\"\n            android:layout_marginEnd=\"@dimen/padding_small\"\n            android:layout_weight=\"0\"\n            android:contentDescription=\"@string/next\"\n            android:paddingVertical=\"@dimen/padding_small\"\n            app:icon=\"@drawable/ic_next\"\n            app:iconSize=\"20dp\" />\n\n    </androidx.appcompat.widget.LinearLayoutCompat>\n\n    <io.github.muntashirakon.AppManager.usage.BarChartView\n        android:id=\"@+id/bar_chart\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"150dp\"\n        android:layout_margin=\"@dimen/padding_medium\"\n        android:layout_weight=\"0\"\n        android:importantForAccessibility=\"yes\"\n        app:gridLineCount=\"4\" />\n\n</androidx.appcompat.widget.LinearLayoutCompat>\n"
  },
  {
    "path": "app/src/main/res/layout/item_bloatware_details.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<androidx.appcompat.widget.LinearLayoutCompat xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:orientation=\"vertical\">\n\n    <androidx.appcompat.widget.LinearLayoutCompat\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:paddingTop=\"@dimen/padding_small\"\n        android:paddingBottom=\"@dimen/padding_small\"\n        android:paddingStart=\"@dimen/padding_medium\"\n        android:paddingEnd=\"@dimen/padding_medium\"\n        android:orientation=\"vertical\">\n\n        <androidx.appcompat.widget.LinearLayoutCompat\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:orientation=\"horizontal\">\n\n            <androidx.appcompat.widget.LinearLayoutCompat\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_weight=\"1\"\n                android:orientation=\"vertical\">\n\n                <com.google.android.material.textview.MaterialTextView\n                    android:id=\"@+id/name\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:textIsSelectable=\"true\"\n                    android:textAppearance=\"?attr/textAppearanceTitleMedium\"\n                    tools:text=\"@string/app_name\" />\n\n                <com.google.android.material.textview.MaterialTextView\n                    android:id=\"@+id/package_name\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:textIsSelectable=\"true\"\n                    android:textAppearance=\"?attr/textAppearanceBodySmall\"\n                    android:textStyle=\"italic\"\n                    tools:text=\"package.name\" />\n\n            </androidx.appcompat.widget.LinearLayoutCompat>\n\n            <com.google.android.material.button.MaterialButton\n                android:id=\"@+id/info\"\n                style=\"@style/Widget.AppTheme.Button.IconButton\"\n                android:layout_width=\"40dp\"\n                android:layout_height=\"40dp\"\n                android:layout_weight=\"0\"\n                android:layout_marginStart=\"@dimen/padding_small\"\n                android:layout_gravity=\"center\"\n                app:icon=\"@drawable/ic_information\" />\n\n        </androidx.appcompat.widget.LinearLayoutCompat>\n\n        <com.google.android.material.textview.MaterialTextView\n            android:id=\"@+id/message\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginTop=\"8dp\"\n            android:textAppearance=\"?attr/textAppearanceListItemSecondary\"\n            android:autoLink=\"web\"\n            android:textIsSelectable=\"true\"\n            tools:text=\"@tools:sample/lorem/random\" />\n\n    </androidx.appcompat.widget.LinearLayoutCompat>\n\n</androidx.appcompat.widget.LinearLayoutCompat>"
  },
  {
    "path": "app/src/main/res/layout/item_changelog_header.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<androidx.appcompat.widget.LinearLayoutCompat xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:orientation=\"vertical\"\n    android:paddingHorizontal=\"@dimen/padding_medium\"\n    android:paddingTop=\"@dimen/padding_medium\"\n    android:paddingBottom=\"@dimen/padding_small\">\n\n    <androidx.appcompat.widget.LinearLayoutCompat\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:orientation=\"horizontal\"\n        android:paddingBottom=\"@dimen/padding_small\">\n\n        <androidx.appcompat.widget.LinearLayoutCompat\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:orientation=\"vertical\">\n\n            <com.google.android.material.textview.MaterialTextView\n                android:id=\"@+id/item_label\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:gravity=\"end|center_vertical\"\n                android:textAlignment=\"viewEnd\"\n                android:textAppearance=\"@style/TextAppearance.AppTheme.LabelSmall\"\n                android:textSize=\"9sp\"\n                android:textStyle=\"normal\"\n                android:textAllCaps=\"true\"\n                android:letterSpacing=\"0.3\"\n                tools:text=\"stable release\"\n                tools:ignore=\"SmallSp\" />\n\n            <com.google.android.material.textview.MaterialTextView\n                android:id=\"@+id/item_title\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:gravity=\"start|center_vertical\"\n                android:textAlignment=\"viewStart\"\n                android:textAppearance=\"?attr/textAppearanceTitleMedium\"\n                tools:text=\"Version v3.0.0 (410)\" />\n\n        </androidx.appcompat.widget.LinearLayoutCompat>\n\n        <com.google.android.material.textview.MaterialTextView\n            android:id=\"@+id/item_subtitle\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"match_parent\"\n            android:gravity=\"end|center_vertical\"\n            android:textAlignment=\"viewEnd\"\n            android:layout_weight=\"1\"\n            android:textColor=\"?android:attr/textColorSecondary\"\n            android:textIsSelectable=\"true\"\n            tools:text=\"4 August 2022\" />\n\n    </androidx.appcompat.widget.LinearLayoutCompat>\n\n    <com.google.android.material.divider.MaterialDivider\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\" />\n\n</androidx.appcompat.widget.LinearLayoutCompat>"
  },
  {
    "path": "app/src/main/res/layout/item_changelog_item.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<androidx.appcompat.widget.LinearLayoutCompat xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:id=\"@+id/item_layout\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:orientation=\"horizontal\"\n    android:focusable=\"true\"\n    android:paddingHorizontal=\"@dimen/padding_medium\">\n\n    <com.google.android.material.textview.MaterialTextView\n        android:id=\"@+id/item_subtitle\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:textColor=\"?android:attr/textColorSecondary\"\n        android:textIsSelectable=\"true\"\n        android:gravity=\"center_vertical\"\n        tools:text=\"@tools:sample/lorem[5]\" />\n</androidx.appcompat.widget.LinearLayoutCompat>\n"
  },
  {
    "path": "app/src/main/res/layout/item_checkbox.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<androidx.appcompat.widget.LinearLayoutCompat xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\">\n\n    <com.google.android.material.checkbox.MaterialCheckBox\n        android:id=\"@+id/checkbox\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginHorizontal=\"16dp\" />\n\n</androidx.appcompat.widget.LinearLayoutCompat>\n"
  },
  {
    "path": "app/src/main/res/layout/item_chip.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<com.google.android.material.chip.Chip xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    style=\"@style/Widget.AppTheme.Chip.Assist.Elevated.Padded\"\n    android:layout_width=\"wrap_content\"\n    android:layout_height=\"wrap_content\"\n    tools:text=\"@tools:sample/cities\" />\n"
  },
  {
    "path": "app/src/main/res/layout/item_debloater.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<com.google.android.material.card.MaterialCardView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    style=\"@style/Widget.AppTheme.CardView.ListItem.Outlined\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:clickable=\"true\"\n    android:focusable=\"true\"\n    android:checkable=\"true\"\n    android:layout_marginHorizontal=\"?attr/listItemMarginHorizontal\"\n    android:layout_marginVertical=\"?attr/listItemMarginVertical\">\n\n    <androidx.appcompat.widget.LinearLayoutCompat\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:orientation=\"horizontal\"\n        android:paddingHorizontal=\"?attr/listItemPaddingHorizontal\"\n        android:paddingVertical=\"?attr/listItemPaddingVertical\">\n\n        <androidx.appcompat.widget.LinearLayoutCompat\n            android:layout_width=\"@dimen/icon_size\"\n            android:layout_height=\"match_parent\"\n            android:gravity=\"center\"\n            android:layout_marginEnd=\"@dimen/padding_small\"\n            android:orientation=\"vertical\">\n\n            <androidx.appcompat.widget.AppCompatImageView\n                android:id=\"@+id/icon\"\n                android:layout_width=\"@dimen/icon_size\"\n                android:layout_height=\"@dimen/icon_size\"\n                android:layout_weight=\"0\"\n                android:layout_gravity=\"top|center_horizontal\"\n                tools:srcCompat=\"@mipmap/ic_launcher_round\"\n                android:contentDescription=\"@string/str_logo\" />\n\n            <com.google.android.material.textview.MaterialTextView\n                android:id=\"@+id/list_type\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_weight=\"1\"\n                android:gravity=\"top|center_horizontal\"\n                android:textAppearance=\"?attr/textAppearanceLabelSmall\"\n                tools:text=\"OEM\"\n                tools:ignore=\"SmallSp\" />\n\n        </androidx.appcompat.widget.LinearLayoutCompat>\n\n        <androidx.appcompat.widget.LinearLayoutCompat\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:orientation=\"vertical\">\n\n            <com.google.android.material.textview.MaterialTextView\n                android:id=\"@+id/label\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:singleLine=\"true\"\n                android:ellipsize=\"end\"\n                android:textAppearance=\"?attr/textAppearanceListItem\"\n                tools:text=\"@string/app_name\" />\n\n            <com.google.android.material.textview.MaterialTextView\n                android:id=\"@+id/package_name\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:singleLine=\"true\"\n                android:ellipsize=\"end\"\n                android:textAppearance=\"?attr/textAppearanceListItemSecondary\"\n                android:textStyle=\"italic\"\n                tools:text=\"io.github.muntashirakon.AppManager\" />\n\n            <com.google.android.material.textview.MaterialTextView\n                android:id=\"@+id/apk_description\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:textAppearance=\"?attr/textAppearanceListItemSecondary\"\n                android:autoLink=\"web\"\n                tools:text=\"@tools:sample/lorem/random\"\n                tools:ignore=\"SmallSp\" />\n\n        </androidx.appcompat.widget.LinearLayoutCompat>\n\n    </androidx.appcompat.widget.LinearLayoutCompat>\n\n</com.google.android.material.card.MaterialCardView>"
  },
  {
    "path": "app/src/main/res/layout/item_finder.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-or-later -->\n<com.google.android.material.card.MaterialCardView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    style=\"@style/Widget.AppTheme.CardView.ListItem.Outlined\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:focusable=\"true\"\n    android:descendantFocusability=\"beforeDescendants\"\n    app:cardElevation=\"0dp\"\n    android:layout_marginHorizontal=\"?attr/listItemMarginHorizontal\"\n    android:layout_marginVertical=\"?attr/listItemMarginVertical\">\n\n    <androidx.appcompat.widget.LinearLayoutCompat\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:orientation=\"vertical\"\n        android:paddingHorizontal=\"?attr/listItemPaddingHorizontal\"\n        android:paddingVertical=\"?attr/listItemPaddingVertical\">\n\n        <androidx.appcompat.widget.LinearLayoutCompat\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:orientation=\"horizontal\">\n\n            <androidx.appcompat.widget.AppCompatImageView\n                android:id=\"@+id/icon\"\n                android:layout_width=\"40dp\"\n                android:layout_height=\"40dp\"\n                android:layout_marginEnd=\"@dimen/padding_small\"\n                android:layout_weight=\"0\"\n                android:contentDescription=\"@string/str_logo\" />\n\n            <androidx.appcompat.widget.LinearLayoutCompat\n                android:layout_width=\"0dp\"\n                android:layout_height=\"wrap_content\"\n                android:layout_weight=\"1\"\n                android:orientation=\"vertical\">\n\n                <com.google.android.material.textview.MaterialTextView\n                    android:id=\"@+id/label\"\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_gravity=\"center_vertical\"\n                    android:gravity=\"center\"\n                    android:singleLine=\"true\"\n                    android:textIsSelectable=\"true\"\n                    android:textAppearance=\"?android:attr/textAppearanceListItem\"\n                    tools:text=\"@tools:sample/lorem\" />\n\n                <com.google.android.material.textview.MaterialTextView\n                    android:id=\"@+id/package_name\"\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:textIsSelectable=\"true\"\n                    android:textAppearance=\"?attr/textAppearanceBodySmall\"\n                    android:textSize=\"10sp\"\n                    tools:text=\"@tools:sample/lorem\"\n                    tools:ignore=\"SmallSp\" />\n\n            </androidx.appcompat.widget.LinearLayoutCompat>\n\n            <com.google.android.material.materialswitch.MaterialSwitch\n                android:id=\"@+id/toggle_button\"\n                android:layout_width=\"56dp\"\n                android:layout_height=\"wrap_content\"\n                android:layout_gravity=\"center\"\n                android:layout_weight=\"0\"\n                android:clickable=\"false\"\n                android:focusable=\"false\" />\n\n        </androidx.appcompat.widget.LinearLayoutCompat>\n\n        <com.google.android.material.textview.MaterialTextView\n            android:id=\"@+id/item1\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:textIsSelectable=\"true\"\n            android:textAppearance=\"?attr/textAppearanceBodySmall\"\n            android:textSize=\"11sp\"\n            tools:text=\"@tools:sample/lorem\"\n            tools:ignore=\"SmallSp\" />\n\n        <com.google.android.material.textview.MaterialTextView\n            android:id=\"@+id/item2\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:textIsSelectable=\"true\"\n            android:textAppearance=\"?attr/textAppearanceBodySmall\"\n            android:textSize=\"11sp\"\n            tools:text=\"@tools:sample/lorem\"\n            tools:ignore=\"SmallSp\" />\n\n        <com.google.android.material.textview.MaterialTextView\n            android:id=\"@+id/item3\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:textIsSelectable=\"true\"\n            android:textAppearance=\"?attr/textAppearanceBodySmall\"\n            android:textSize=\"11sp\"\n            tools:text=\"@tools:sample/lorem\"\n            tools:ignore=\"SmallSp\" />\n\n    </androidx.appcompat.widget.LinearLayoutCompat>\n\n</com.google.android.material.card.MaterialCardView>"
  },
  {
    "path": "app/src/main/res/layout/item_fm.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<com.google.android.material.card.MaterialCardView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    style=\"@style/Widget.AppTheme.CardView.ListItem\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:minHeight=\"?android:attr/listPreferredItemHeightSmall\"\n    android:clickable=\"true\"\n    android:focusable=\"true\"\n    android:checkable=\"true\"\n    android:layout_marginHorizontal=\"?attr/listItemMarginHorizontal\"\n    android:layout_marginVertical=\"?attr/listItemMarginVertical\">\n\n    <androidx.appcompat.widget.LinearLayoutCompat\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:orientation=\"horizontal\"\n        android:paddingHorizontal=\"?attr/listItemPaddingHorizontal\"\n        android:paddingVertical=\"?attr/listItemPaddingVertical\">\n\n        <androidx.appcompat.widget.LinearLayoutCompat\n            android:id=\"@+id/icon_frame\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"match_parent\"\n            android:gravity=\"center\"\n            android:layout_marginEnd=\"@dimen/padding_small\"\n            android:orientation=\"vertical\">\n\n            <FrameLayout\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\">\n\n                <com.google.android.material.imageview.ShapeableImageView\n                    android:id=\"@android:id/icon\"\n                    android:layout_width=\"48dp\"\n                    android:layout_height=\"48dp\"\n                    android:layout_gravity=\"center\"\n                    android:background=\"@color/fm_icon_background\"\n                    android:contentDescription=\"@string/str_logo\"\n                    app:shapeAppearanceOverlay=\"@style/ShapeAppearance.AppTheme.SmallComponent\"\n                    tools:srcCompat=\"@mipmap/ic_launcher_round\" />\n\n                <com.google.android.material.imageview.ShapeableImageView\n                    android:id=\"@+id/symbolic_link_icon\"\n                    android:layout_width=\"20dp\"\n                    android:layout_height=\"20dp\"\n                    android:layout_gravity=\"start|bottom\"\n                    android:visibility=\"gone\"\n                    android:tint=\"@color/fm_symbolic_link\"\n                    app:srcCompat=\"@drawable/ic_arrow_outward\"\n                    tools:visibility=\"visible\" />\n\n                <com.google.android.material.imageview.ShapeableImageView\n                    android:id=\"@android:id/icon1\"\n                    android:layout_width=\"20dp\"\n                    android:layout_height=\"20dp\"\n                    android:layout_gravity=\"end|bottom\"\n                    android:visibility=\"gone\"\n                    app:shapeAppearanceOverlay=\"@style/ShapeAppearance.AppTheme.SmallComponent\"\n                    tools:srcCompat=\"@drawable/ic_repeat\"\n                    tools:visibility=\"visible\" />\n            </FrameLayout>\n\n        </androidx.appcompat.widget.LinearLayoutCompat>\n\n        <RelativeLayout\n            android:layout_width=\"0dp\"\n            android:layout_height=\"wrap_content\"\n            android:layout_weight=\"1\"\n            android:paddingTop=\"16dp\"\n            android:paddingBottom=\"16dp\">\n\n            <com.google.android.material.textview.MaterialTextView\n                android:id=\"@android:id/title\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:singleLine=\"true\"\n                android:textAppearance=\"?android:attr/textAppearanceListItem\"\n                android:ellipsize=\"middle\"\n                tools:text=\"@tools:sample/lorem[10]\" />\n\n            <com.google.android.material.textview.MaterialTextView\n                android:id=\"@android:id/summary\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_below=\"@android:id/title\"\n                android:layout_alignStart=\"@android:id/title\"\n                android:layout_gravity=\"start\"\n                android:textAlignment=\"viewStart\"\n                android:textAppearance=\"?android:attr/textAppearanceListItemSecondary\"\n                android:maxLines=\"10\"\n                tools:text=\"@tools:sample/lorem[10]\" />\n\n        </RelativeLayout>\n\n        <!-- Preference should place its actual preference widget here. -->\n        <androidx.appcompat.widget.LinearLayoutCompat\n            android:id=\"@android:id/widget_frame\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"match_parent\"\n            android:gravity=\"end|center_vertical\"\n            android:paddingStart=\"16dp\"\n            android:paddingEnd=\"0dp\"\n            android:orientation=\"vertical\" />\n\n    </androidx.appcompat.widget.LinearLayoutCompat>\n</com.google.android.material.card.MaterialCardView>"
  },
  {
    "path": "app/src/main/res/layout/item_fm_drawer.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<com.google.android.material.card.MaterialCardView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    style=\"@style/Widget.AppTheme.CardView.ListItem\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"56dp\">\n\n    <androidx.appcompat.widget.LinearLayoutCompat\n        android:id=\"@+id/item_layout\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:gravity=\"center_vertical\"\n        android:orientation=\"horizontal\"\n        android:paddingHorizontal=\"@dimen/padding_medium\"\n        android:paddingVertical=\"12dp\">\n\n        <androidx.appcompat.widget.AppCompatImageView\n            android:id=\"@+id/item_icon\"\n            android:layout_width=\"24dp\"\n            android:layout_height=\"24dp\"\n            android:layout_marginEnd=\"12dp\"\n            android:layout_weight=\"0\"\n            android:importantForAccessibility=\"no\"\n            tools:ignore=\"ContentDescription\"\n            tools:srcCompat=\"@tools:sample/avatars\" />\n\n        <androidx.appcompat.widget.AppCompatTextView\n            android:id=\"@+id/item_title\"\n            android:layout_width=\"0dp\"\n            android:layout_height=\"wrap_content\"\n            android:layout_weight=\"2\"\n            android:ellipsize=\"end\"\n            android:singleLine=\"true\"\n            android:textAppearance=\"?android:attr/textAppearanceListItem\"\n            tools:text=\"@tools:sample/lorem\" />\n\n    </androidx.appcompat.widget.LinearLayoutCompat>\n\n</com.google.android.material.card.MaterialCardView>"
  },
  {
    "path": "app/src/main/res/layout/item_icon_title_subtitle.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<androidx.appcompat.widget.LinearLayoutCompat xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:id=\"@+id/item_layout\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:orientation=\"horizontal\"\n    android:focusable=\"true\"\n    android:background=\"@drawable/item_transparent\"\n    android:paddingHorizontal=\"@dimen/padding_medium\"\n    android:paddingVertical=\"@dimen/padding_medium\">\n\n    <androidx.appcompat.widget.AppCompatImageView\n        android:id=\"@+id/item_icon\"\n        android:layout_width=\"@dimen/icon_size\"\n        android:layout_height=\"match_parent\"\n        android:layout_marginEnd=\"@dimen/padding_medium\"\n        android:layout_weight=\"0\"\n        tools:ignore=\"ContentDescription\"\n        tools:srcCompat=\"@tools:sample/avatars\" />\n\n    <androidx.appcompat.widget.LinearLayoutCompat\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_weight=\"1\"\n        android:orientation=\"vertical\">\n\n        <androidx.appcompat.widget.AppCompatTextView\n            android:id=\"@+id/item_title\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:textAppearance=\"?android:attr/textAppearanceListItem\"\n            tools:text=\"@tools:sample/lorem\" />\n\n        <androidx.appcompat.widget.AppCompatTextView\n            android:id=\"@+id/item_subtitle\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:textColor=\"?android:attr/textColorSecondary\"\n            android:nextFocusRight=\"@id/item_open\"\n            tools:text=\"@tools:sample/lorem\" />\n\n    </androidx.appcompat.widget.LinearLayoutCompat>\n\n    <com.google.android.material.button.MaterialButton\n        android:id=\"@+id/item_open\"\n        style=\"@style/Widget.AppTheme.Button.IconButton\"\n        android:layout_width=\"56dp\"\n        android:layout_height=\"56dp\"\n        android:layout_gravity=\"center\"\n        android:layout_marginStart=\"@dimen/padding_medium\"\n        android:layout_weight=\"0\"\n        android:background=\"@drawable/item_transparent\"\n        android:focusable=\"true\"\n        android:nextFocusLeft=\"@id/item_subtitle\"\n        app:icon=\"@drawable/ic_open_in_new\"\n        app:iconSize=\"24dp\" />\n\n</androidx.appcompat.widget.LinearLayoutCompat>\n"
  },
  {
    "path": "app/src/main/res/layout/item_logcat.xml",
    "content": "<!-- SPDX-License-Identifier: WTFPL AND GPL-3.0-or-later -->\n<androidx.appcompat.widget.LinearLayoutCompat xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:background=\"@drawable/item_transparent\"\n    android:focusable=\"true\"\n    android:orientation=\"vertical\">\n\n    <androidx.appcompat.widget.LinearLayoutCompat\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:orientation=\"horizontal\">\n\n        <androidx.appcompat.widget.AppCompatTextView\n            android:id=\"@+id/log_level_text\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"match_parent\"\n            android:layout_weight=\"0\"\n            android:gravity=\"center_vertical\"\n            android:maxLines=\"1\"\n            android:paddingHorizontal=\"3dp\"\n            android:paddingVertical=\"4dp\"\n            android:textAppearance=\"?attr/textAppearanceLabelMedium\"\n            android:typeface=\"monospace\"\n            tools:background=\"#FFFFCC99\"\n            tools:text=\"D\" />\n\n        <androidx.appcompat.widget.LinearLayoutCompat\n            android:id=\"@+id/log_content\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_weight=\"1\"\n            android:orientation=\"vertical\"\n            android:paddingHorizontal=\"3dp\"\n            android:paddingVertical=\"4dp\">\n\n            <androidx.appcompat.widget.LinearLayoutCompat\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\">\n\n                <androidx.appcompat.widget.AppCompatTextView\n                    android:id=\"@+id/info\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:ellipsize=\"end\"\n                    android:maxLines=\"1\"\n                    android:textAppearance=\"@style/TextAppearance.AppTheme.LabelSmaller\"\n                    android:typeface=\"monospace\"\n                    tools:ignore=\"RtlSymmetry,SmallSp\"\n                    tools:text=\"01-18 14:49:23.054 • 781 • shell • com.android.shell\" />\n\n            </androidx.appcompat.widget.LinearLayoutCompat>\n\n            <androidx.appcompat.widget.AppCompatTextView\n                android:id=\"@+id/tag_text\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:ellipsize=\"end\"\n                android:maxLines=\"1\"\n                android:textAppearance=\"?android:attr/textAppearanceListItem\"\n                android:textSize=\"16sp\"\n                android:typeface=\"monospace\"\n                tools:text=\"SomeActivity\" />\n\n            <androidx.appcompat.widget.AppCompatTextView\n                android:id=\"@+id/log_output_text\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:ellipsize=\"end\"\n                android:singleLine=\"true\"\n                android:textAppearance=\"?attr/textAppearanceBodySmall\"\n                android:typeface=\"monospace\"\n                tools:text=\"@tools:sample/lorem/random\" />\n\n        </androidx.appcompat.widget.LinearLayoutCompat>\n\n    </androidx.appcompat.widget.LinearLayoutCompat>\n\n</androidx.appcompat.widget.LinearLayoutCompat>"
  },
  {
    "path": "app/src/main/res/layout/item_main.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-or-later -->\n<com.google.android.material.card.MaterialCardView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    style=\"@style/Widget.AppTheme.CardView.ListItem.Outlined\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:clickable=\"true\"\n    android:focusable=\"true\"\n    android:checkable=\"true\"\n    android:layout_marginHorizontal=\"?attr/listItemMarginHorizontal\"\n    android:layout_marginVertical=\"?attr/listItemMarginVertical\">\n\n    <androidx.appcompat.widget.LinearLayoutCompat\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:orientation=\"horizontal\"\n        android:paddingHorizontal=\"?attr/listItemPaddingHorizontal\"\n        android:paddingVertical=\"?attr/listItemPaddingVertical\">\n\n        <androidx.appcompat.widget.LinearLayoutCompat\n            android:layout_width=\"@dimen/icon_size\"\n            android:layout_height=\"match_parent\"\n            android:gravity=\"center\"\n            android:layout_marginEnd=\"@dimen/padding_small\"\n            android:orientation=\"vertical\">\n\n            <androidx.appcompat.widget.AppCompatImageView\n                android:id=\"@+id/icon\"\n                android:layout_width=\"@dimen/icon_size\"\n                android:layout_height=\"@dimen/icon_size\"\n                android:layout_weight=\"1\"\n                android:layout_gravity=\"center\"\n                tools:srcCompat=\"@mipmap/ic_launcher_round\"\n                android:contentDescription=\"@string/str_logo\" />\n\n            <androidx.appcompat.widget.AppCompatTextView\n                android:id=\"@+id/backup_indicator\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_weight=\"1\"\n                android:textAppearance=\"?attr/textAppearanceLabelSmall\"\n                android:text=\"@string/backup\"\n                tools:ignore=\"SmallSp\" />\n\n        </androidx.appcompat.widget.LinearLayoutCompat>\n\n        <FrameLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_weight=\"1\">\n\n            <androidx.appcompat.widget.AppCompatImageView\n                android:id=\"@+id/favorite_icon\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:src=\"@drawable/item_favorite\"\n                android:layout_gravity=\"end|top\"\n                tools:ignore=\"ContentDescription\" />\n\n            <androidx.appcompat.widget.LinearLayoutCompat\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"match_parent\"\n                android:orientation=\"vertical\">\n\n                <androidx.appcompat.widget.AppCompatTextView\n                    android:id=\"@+id/label\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:singleLine=\"true\"\n                    android:textAppearance=\"?android:attr/textAppearanceListItem\"\n                    tools:text=\"@string/app_name\" />\n\n                <androidx.appcompat.widget.AppCompatTextView\n                    android:id=\"@+id/packageName\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:singleLine=\"true\"\n                    android:textAppearance=\"?attr/textAppearanceBodySmall\"\n                    android:textStyle=\"italic\"\n                    tools:text=\"io.github.muntashirakon.AppManager\" />\n\n                <androidx.appcompat.widget.LinearLayoutCompat\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:orientation=\"horizontal\">\n\n                    <androidx.appcompat.widget.AppCompatTextView\n                        android:id=\"@+id/date\"\n                        android:layout_width=\"wrap_content\"\n                        android:layout_height=\"wrap_content\"\n                        android:singleLine=\"true\"\n                        android:textAppearance=\"?attr/textAppearanceBodySmall\"\n                        tools:text=\"@tools:sample/date/mmddyy\" />\n\n                    <androidx.appcompat.widget.AppCompatTextView\n                        android:id=\"@+id/shareid\"\n                        android:layout_width=\"match_parent\"\n                        android:layout_height=\"wrap_content\"\n                        android:gravity=\"end\"\n                        android:paddingEnd=\"25sp\"\n                        android:singleLine=\"true\"\n                        android:textAppearance=\"?attr/textAppearanceBodySmall\"\n                        android:textSize=\"10sp\"\n                        tools:text=\"@tools:sample/us_zipcodes\"\n                        tools:ignore=\"RtlSymmetry,SmallSp\" />\n\n                </androidx.appcompat.widget.LinearLayoutCompat>\n\n                <androidx.appcompat.widget.AppCompatTextView\n                    android:id=\"@+id/issuer\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:singleLine=\"true\"\n                    android:textAppearance=\"?attr/textAppearanceBodySmall\"\n                    android:textSize=\"9sp\"\n                    tools:text=\"CN=Android,OU=Android\"\n                    tools:ignore=\"SmallSp\" />\n\n                <androidx.appcompat.widget.AppCompatTextView\n                    android:id=\"@+id/backup_info\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:singleLine=\"true\"\n                    android:textAppearance=\"?attr/textAppearanceBodySmall\"\n                    android:textSize=\"10sp\"\n                    tools:text=\"@tools:sample/lorem[6]\"\n                    tools:ignore=\"SmallSp\" />\n\n            </androidx.appcompat.widget.LinearLayoutCompat>\n\n        </FrameLayout>\n\n        <androidx.appcompat.widget.LinearLayoutCompat\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_weight=\"2\"\n            android:orientation=\"vertical\"\n            android:layout_marginStart=\"@dimen/padding_small\">\n\n            <androidx.appcompat.widget.AppCompatTextView\n                android:id=\"@+id/version\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:singleLine=\"true\"\n                android:textAppearance=\"?attr/textAppearanceBodySmall\"\n                tools:text=\"v3.0.0\" />\n\n            <androidx.appcompat.widget.AppCompatTextView\n                android:id=\"@+id/isSystem\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:singleLine=\"true\"\n                android:textAppearance=\"?attr/textAppearanceBodyMedium\"\n                tools:text=\"User\" />\n\n            <androidx.appcompat.widget.AppCompatTextView\n                android:id=\"@+id/size\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:singleLine=\"true\"\n                android:textAppearance=\"?attr/textAppearanceBodyMedium\"\n                tools:text=\"SDK 30\" />\n\n            <androidx.appcompat.widget.AppCompatTextView\n                android:id=\"@+id/sha\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:singleLine=\"true\"\n                android:textAppearance=\"?attr/textAppearanceBodyMedium\"\n                android:textSize=\"11sp\"\n                tools:text=\"SHA256withRSA\" />\n\n            <androidx.appcompat.widget.AppCompatTextView\n                android:id=\"@+id/backup_info_ext\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:singleLine=\"true\"\n                android:textAppearance=\"?attr/textAppearanceBodySmall\"\n                android:textSize=\"10sp\"\n                tools:text=\"APK+Data\"\n                tools:ignore=\"SmallSp\" />\n\n        </androidx.appcompat.widget.LinearLayoutCompat>\n\n    </androidx.appcompat.widget.LinearLayoutCompat>\n\n</com.google.android.material.card.MaterialCardView>"
  },
  {
    "path": "app/src/main/res/layout/item_op_history.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<com.google.android.material.card.MaterialCardView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    style=\"@style/Widget.AppTheme.CardView.ListItem.Outlined\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    app:cardElevation=\"0dp\"\n    android:focusable=\"true\"\n    android:layout_marginHorizontal=\"?attr/listItemMarginHorizontal\"\n    android:layout_marginVertical=\"?attr/listItemMarginVertical\">\n\n    <androidx.appcompat.widget.LinearLayoutCompat\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:orientation=\"horizontal\"\n        android:paddingHorizontal=\"?attr/listItemPaddingHorizontal\"\n        android:paddingVertical=\"?attr/listItemPaddingVertical\">\n\n        <androidx.appcompat.widget.LinearLayoutCompat\n            android:layout_width=\"0dp\"\n            android:layout_height=\"wrap_content\"\n            android:layout_weight=\"1\"\n            android:orientation=\"vertical\">\n\n            <androidx.appcompat.widget.AppCompatTextView\n                android:id=\"@+id/type\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:textAppearance=\"?attr/textAppearanceBodySmall\"\n                tools:text=\"@tools:sample/lorem\" />\n\n            <androidx.appcompat.widget.AppCompatTextView\n                android:id=\"@android:id/title\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:textAppearance=\"?android:attr/textAppearanceListItem\"\n                tools:text=\"@tools:sample/lorem\" />\n\n            <androidx.appcompat.widget.AppCompatTextView\n                android:id=\"@android:id/summary\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:textAppearance=\"?attr/textAppearanceBodySmall\"\n                tools:text=\"@tools:sample/lorem\" />\n\n        </androidx.appcompat.widget.LinearLayoutCompat>\n\n        <com.google.android.material.button.MaterialButton\n            android:id=\"@+id/item_action\"\n            style=\"@style/Widget.AppTheme.Button.IconButton\"\n            android:layout_width=\"56dp\"\n            android:layout_height=\"56dp\"\n            android:layout_gravity=\"center\"\n            android:layout_weight=\"0\"\n            app:icon=\"@drawable/ic_replay\"\n            android:contentDescription=\"@string/action_run\"\n            app:iconSize=\"20dp\" />\n\n    </androidx.appcompat.widget.LinearLayoutCompat>\n\n</com.google.android.material.card.MaterialCardView>\n"
  },
  {
    "path": "app/src/main/res/layout/item_path.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<com.google.android.material.card.MaterialCardView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    style=\"@style/Widget.AppTheme.CardView.ListItem\"\n    android:layout_width=\"wrap_content\"\n    android:layout_height=\"wrap_content\">\n\n    <com.google.android.material.textview.MaterialTextView\n        android:id=\"@android:id/text1\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:paddingHorizontal=\"@dimen/padding_small\"\n        android:paddingVertical=\"@dimen/padding_small\"\n        android:singleLine=\"true\"\n        tools:text=\"» Path\" />\n\n</com.google.android.material.card.MaterialCardView>"
  },
  {
    "path": "app/src/main/res/layout/item_right_standalone_action.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<RelativeLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:minWidth=\"49dp\"\n    android:orientation=\"horizontal\">\n\n    <com.google.android.material.divider.MaterialDivider\n        android:id=\"@+id/divider\"\n        android:layout_width=\"1dp\"\n        android:layout_height=\"48dp\"\n        android:layout_centerVertical=\"true\"\n        app:dividerThickness=\"1dp\" />\n\n    <com.google.android.material.button.MaterialButton\n        style=\"@style/Widget.AppTheme.Button.IconButton\"\n        android:id=\"@android:id/button1\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_centerInParent=\"true\"\n        android:layout_toEndOf=\"@id/divider\"\n        android:maxWidth=\"48dp\"\n        android:maxHeight=\"48dp\"\n        app:iconTint=\"?attr/colorPrimary\"\n        app:iconSize=\"24dp\"\n        tools:icon=\"@drawable/ic_more_vert\" />\n\n</RelativeLayout>"
  },
  {
    "path": "app/src/main/res/layout/item_right_summary.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<com.google.android.material.textview.MaterialTextView\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:id=\"@android:id/text1\"\n    android:layout_width=\"wrap_content\"\n    android:layout_height=\"wrap_content\"\n    android:gravity=\"end\"\n    android:textAlignment=\"viewEnd\"\n    android:textColor=\"?android:attr/textColorSecondary\"\n    android:textAppearance=\"?android:attr/textAppearanceListItemSecondary\"\n    android:textIsSelectable=\"true\"\n    tools:text=\"@tools:sample/lorem[5]\" />\n"
  },
  {
    "path": "app/src/main/res/layout/item_running_app.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<com.google.android.material.card.MaterialCardView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    style=\"@style/Widget.AppTheme.CardView.ListItem.Outlined\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:layout_marginHorizontal=\"?attr/listItemMarginHorizontal\"\n    android:layout_marginVertical=\"?attr/listItemMarginVertical\"\n    android:checkable=\"true\"\n    android:clickable=\"true\"\n    android:focusable=\"true\"\n    app:cardElevation=\"0dp\">\n\n    <androidx.appcompat.widget.LinearLayoutCompat\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:orientation=\"horizontal\"\n        android:paddingHorizontal=\"?attr/listItemPaddingHorizontal\"\n        android:paddingVertical=\"?attr/listItemPaddingVertical\">\n\n        <androidx.appcompat.widget.AppCompatImageView\n            android:id=\"@+id/icon\"\n            android:layout_width=\"@dimen/icon_size\"\n            android:layout_height=\"match_parent\"\n            android:layout_marginEnd=\"@dimen/padding_small\"\n            android:layout_weight=\"0\"\n            android:contentDescription=\"@string/str_logo\"\n            tools:srcCompat=\"@mipmap/ic_launcher\" />\n\n        <androidx.appcompat.widget.LinearLayoutCompat\n            android:layout_width=\"0dp\"\n            android:layout_height=\"wrap_content\"\n            android:layout_weight=\"1\"\n            android:orientation=\"vertical\">\n\n            <androidx.appcompat.widget.AppCompatTextView\n                android:id=\"@+id/process_name\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_gravity=\"center_vertical\"\n                android:gravity=\"center\"\n                android:singleLine=\"true\"\n                android:textAppearance=\"?android:attr/textAppearanceListItem\"\n                tools:text=\"@string/app_name\" />\n\n            <androidx.appcompat.widget.AppCompatTextView\n                android:id=\"@+id/package_name\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:textAppearance=\"?attr/textAppearanceBodySmall\"\n                android:textStyle=\"italic\"\n                tools:text=\"io.github.muntashirakon.AppManager\" />\n\n            <androidx.appcompat.widget.AppCompatTextView\n                android:id=\"@+id/process_ids\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:gravity=\"center_vertical\"\n                android:textAppearance=\"?attr/textAppearanceBodySmall\"\n                android:textSize=\"10sp\"\n                tools:ignore=\"SmallSp\"\n                tools:text=\"Process ID: 10000, Parent Process ID: 1000\" />\n\n            <androidx.appcompat.widget.AppCompatTextView\n                android:id=\"@+id/memory_usage\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:textAppearance=\"?attr/textAppearanceBodySmall\"\n                android:textSize=\"10sp\"\n                tools:ignore=\"SmallSp\"\n                tools:text=\"Memory: 162 MB, Virtual Memory: 14.72 GB\" />\n\n            <androidx.appcompat.widget.AppCompatTextView\n                android:id=\"@+id/user_state_info\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:textAppearance=\"?attr/textAppearanceBodySmall\"\n                android:textSize=\"10sp\"\n                tools:ignore=\"SmallSp\"\n                tools:text=\"User: u0_a167 (10167), State: Sleeping (Unknown)\" />\n\n            <androidx.appcompat.widget.AppCompatTextView\n                android:id=\"@+id/selinux_context\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:textAppearance=\"?attr/textAppearanceBodySmall\"\n                android:textSize=\"10sp\"\n                tools:ignore=\"SmallSp\"\n                tools:text=\"SELinux: u:r:untrusted_app:s0:c110,c257\" />\n\n        </androidx.appcompat.widget.LinearLayoutCompat>\n\n        <com.google.android.material.button.MaterialButton\n            android:id=\"@+id/more\"\n            style=\"@style/Widget.AppTheme.Button.IconButton\"\n            android:layout_width=\"@dimen/icon_size\"\n            android:layout_height=\"@dimen/icon_size\"\n            android:layout_gravity=\"center_vertical\"\n            android:layout_marginStart=\"@dimen/padding_small\"\n            android:layout_weight=\"0\"\n            android:contentDescription=\"@string/abc_action_menu_overflow_description\"\n            android:padding=\"@dimen/padding_small\"\n            app:icon=\"@drawable/ic_more_vert\"\n            app:iconSize=\"20dp\" />\n\n    </androidx.appcompat.widget.LinearLayoutCompat>\n\n</com.google.android.material.card.MaterialCardView>"
  },
  {
    "path": "app/src/main/res/layout/item_shared_lib.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<com.google.android.material.card.MaterialCardView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    style=\"@style/Widget.AppTheme.CardView.ListItem.Outlined\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    app:cardElevation=\"0dp\"\n    android:focusable=\"true\"\n    android:layout_marginHorizontal=\"?attr/listItemMarginHorizontal\"\n    android:layout_marginVertical=\"?attr/listItemMarginVertical\">\n\n    <com.google.android.material.chip.Chip\n        android:id=\"@+id/lib_type\"\n        style=\"@style/Widget.AppTheme.CardView.Outlined.DiagonallyRounded\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"12dp\"\n        android:layout_gravity=\"end\"\n        android:textSize=\"@dimen/font_size_smaller\"\n        tools:text=\".so\" />\n\n    <androidx.appcompat.widget.LinearLayoutCompat\n        android:id=\"@+id/item_layout\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:orientation=\"horizontal\"\n        android:background=\"@drawable/item_transparent\"\n        android:paddingHorizontal=\"?attr/listItemPaddingHorizontal\"\n        android:paddingVertical=\"?attr/listItemPaddingVertical\">\n\n        <androidx.appcompat.widget.LinearLayoutCompat\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_weight=\"1\"\n            android:orientation=\"vertical\">\n\n            <com.google.android.material.textview.MaterialTextView\n                android:id=\"@+id/item_title\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:textAppearance=\"?android:attr/textAppearanceListItem\"\n                tools:text=\"@tools:sample/lorem\" />\n\n            <com.google.android.material.textview.MaterialTextView\n                android:id=\"@+id/item_subtitle\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:textColor=\"?android:attr/textColorSecondary\"\n                android:textIsSelectable=\"true\"\n                android:nextFocusRight=\"@id/item_open\"\n                tools:text=\"@tools:sample/lorem\" />\n\n        </androidx.appcompat.widget.LinearLayoutCompat>\n\n        <com.google.android.material.button.MaterialButton\n            android:id=\"@+id/item_open\"\n            style=\"@style/Widget.AppTheme.Button.IconButton\"\n            android:layout_width=\"56dp\"\n            android:layout_height=\"56dp\"\n            android:layout_gravity=\"center\"\n            android:layout_marginStart=\"@dimen/padding_medium\"\n            android:layout_weight=\"0\"\n            android:nextFocusLeft=\"@id/item_subtitle\"\n            app:icon=\"@drawable/ic_open_in_new\"\n            app:iconTint=\"?attr/colorPrimary\"\n            app:iconSize=\"24dp\" />\n\n    </androidx.appcompat.widget.LinearLayoutCompat>\n\n</com.google.android.material.card.MaterialCardView>\n"
  },
  {
    "path": "app/src/main/res/layout/item_switch.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<com.google.android.material.materialswitch.MaterialSwitch xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    style=\"@style/Widget.AppTheme.MaterialSwitch\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\" />"
  },
  {
    "path": "app/src/main/res/layout/item_sys_config.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<com.google.android.material.card.MaterialCardView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    style=\"@style/Widget.AppTheme.CardView.ListItem\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:minHeight=\"?android:attr/listPreferredItemHeightSmall\"\n    android:focusable=\"true\"\n    android:layout_marginHorizontal=\"?attr/listItemMarginHorizontal\"\n    android:layout_marginVertical=\"?attr/listItemMarginVertical\">\n\n    <androidx.appcompat.widget.LinearLayoutCompat\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:orientation=\"horizontal\"\n        android:focusable=\"true\"\n        android:paddingHorizontal=\"?attr/listItemPaddingHorizontal\"\n        android:paddingVertical=\"?attr/listItemPaddingVertical\">\n\n        <androidx.appcompat.widget.AppCompatImageView\n            android:id=\"@android:id/icon\"\n            android:layout_width=\"40dp\"\n            android:layout_height=\"40dp\"\n            android:layout_marginEnd=\"@dimen/padding_small\"\n            android:layout_weight=\"0\"\n            android:scaleType=\"fitStart\"\n            android:contentDescription=\"@string/str_logo\"\n            tools:srcCompat=\"@tools:sample/avatars\" />\n\n        <androidx.appcompat.widget.LinearLayoutCompat\n            android:layout_width=\"0dp\"\n            android:layout_height=\"wrap_content\"\n            android:layout_weight=\"1\"\n            android:layout_gravity=\"center_vertical\"\n            android:orientation=\"vertical\">\n\n            <HorizontalScrollView\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\">\n\n                <com.google.android.material.textview.MaterialTextView\n                    android:id=\"@android:id/title\"\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_gravity=\"center_vertical\"\n                    android:gravity=\"center\"\n                    android:singleLine=\"true\"\n                    android:textIsSelectable=\"true\"\n                    android:textAppearance=\"?android:attr/textAppearanceListItem\"\n                    tools:text=\"@tools:sample/lorem\" />\n\n            </HorizontalScrollView>\n\n            <androidx.appcompat.widget.AppCompatTextView\n                android:id=\"@+id/package_name\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:textIsSelectable=\"true\"\n                android:textAppearance=\"?attr/textAppearanceBodySmall\"\n                android:textSize=\"11sp\"\n                tools:text=\"@tools:sample/lorem\"\n                tools:ignore=\"SmallSp\" />\n\n            <androidx.appcompat.widget.AppCompatTextView\n                android:id=\"@android:id/summary\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:gravity=\"center_vertical\"\n                android:textIsSelectable=\"true\"\n                android:textAppearance=\"?attr/textAppearanceBodySmall\"\n                tools:text=\"@tools:sample/lorem/random\" />\n\n        </androidx.appcompat.widget.LinearLayoutCompat>\n\n    </androidx.appcompat.widget.LinearLayoutCompat>\n\n</com.google.android.material.card.MaterialCardView>"
  },
  {
    "path": "app/src/main/res/layout/item_text_input_layout_monospace.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<com.google.android.material.textfield.TextInputLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    style=\"@style/Widget.AppTheme.TextInputLayout.Small\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:paddingBottom=\"@dimen/padding_small\"\n    android:paddingHorizontal=\"@dimen/padding_medium\"\n    app:hintEnabled=\"true\"\n    tools:hint=\"@string/file\">\n\n    <io.github.muntashirakon.widget.TextInputTextView\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:inputType=\"none\"\n        android:textIsSelectable=\"true\"\n        android:fontFamily=\"monospace\"\n        tools:text=\"/storage/emulated/0/AppManager_v3.0.3.apk\" />\n\n</com.google.android.material.textfield.TextInputLayout>"
  },
  {
    "path": "app/src/main/res/layout/item_text_view.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<com.google.android.material.textview.MaterialTextView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:id=\"@android:id/text1\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:paddingHorizontal=\"@dimen/padding_medium\"\n    tools:text=\"@tools:sample/lorem\" />"
  },
  {
    "path": "app/src/main/res/layout/item_title_action.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<com.google.android.material.card.MaterialCardView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    style=\"@style/Widget.AppTheme.CardView.ListItem\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:minHeight=\"?android:attr/listPreferredItemHeightSmall\"\n    android:focusable=\"true\"\n    android:layout_marginHorizontal=\"8dp\">\n\n    <androidx.appcompat.widget.LinearLayoutCompat\n        android:id=\"@+id/item_layout\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:focusable=\"true\"\n        android:orientation=\"horizontal\">\n\n        <androidx.appcompat.widget.AppCompatTextView\n            android:id=\"@+id/item_title\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_gravity=\"center_vertical\"\n            android:layout_marginStart=\"@dimen/padding_medium\"\n            android:layout_marginEnd=\"@dimen/padding_very_small\"\n            android:layout_weight=\"1\"\n            android:paddingVertical=\"@dimen/padding_small\"\n            android:textColor=\"?android:attr/textColorSecondary\"\n            tools:text=\"@tools:sample/lorem[15]\" />\n\n        <com.google.android.material.button.MaterialButton\n            android:id=\"@+id/item_action\"\n            style=\"@style/Widget.AppTheme.Button.IconButton\"\n            android:layout_width=\"48dp\"\n            android:layout_height=\"48dp\"\n            android:layout_gravity=\"center\"\n            android:layout_weight=\"0\"\n            android:paddingVertical=\"@dimen/padding_small\"\n            android:layout_marginEnd=\"@dimen/padding_small\"\n            app:icon=\"@drawable/ic_clear\"\n            app:iconSize=\"20dp\" />\n\n    </androidx.appcompat.widget.LinearLayoutCompat>\n\n</com.google.android.material.card.MaterialCardView>\n"
  },
  {
    "path": "app/src/main/res/layout/item_whats_new.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<androidx.appcompat.widget.LinearLayoutCompat xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:gravity=\"center_vertical\"\n    android:orientation=\"horizontal\">\n\n    <com.google.android.material.textview.MaterialTextView\n        android:id=\"@android:id/text2\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:paddingStart=\"@dimen/padding_medium\"\n        android:paddingEnd=\"@dimen/padding_very_small\"\n        android:textSize=\"14sp\"\n        tools:text=\"+\" />\n\n    <com.google.android.material.textview.MaterialTextView\n        android:id=\"@android:id/text1\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:paddingStart=\"@dimen/padding_very_small\"\n        android:paddingEnd=\"@dimen/padding_medium\"\n        android:textSize=\"14sp\"\n        tools:text=\"@tools:sample/lorem/random\" />\n</androidx.appcompat.widget.LinearLayoutCompat>"
  },
  {
    "path": "app/src/main/res/layout/pager_app_details.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<io.github.muntashirakon.widget.SwipeRefreshLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    android:id=\"@+id/swipe_refresh\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n\n    <RelativeLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\">\n\n        <com.google.android.material.progressindicator.LinearProgressIndicator\n            style=\"@style/Widget.AppTheme.LinearProgressIndicator\"\n            android:id=\"@+id/progress_linear\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:indeterminate=\"true\" />\n\n        <FrameLayout\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:layout_below=\"@+id/progress_linear\">\n\n            <!-- We need to use scrollView id in order to preserve compatibility -->\n            <io.github.muntashirakon.widget.RecyclerView\n                android:id=\"@+id/scrollView\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"match_parent\"\n                android:fitsSystemWindows=\"true\"\n                android:clipToPadding=\"false\"\n                app:fastScrollerEnabled=\"true\"\n                tools:listitem=\"@layout/item_app_details_primary\" />\n\n            <com.google.android.material.textview.MaterialTextView\n                android:id=\"@android:id/empty\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"match_parent\"\n                android:gravity=\"center\"\n                tools:text=\"@tools:sample/lorem[2]\"\n                tools:visibility=\"gone\" />\n\n        </FrameLayout>\n\n        <io.github.muntashirakon.widget.MaterialAlertView\n            android:id=\"@+id/alert_text\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginVertical=\"@dimen/padding_small\"\n            android:layout_marginHorizontal=\"@dimen/padding_medium\"\n            android:layout_alignParentBottom=\"true\"\n            android:fitsSystemWindows=\"true\"\n            tools:text=\"@tools:sample/lorem[5]\" />\n\n    </RelativeLayout>\n\n</io.github.muntashirakon.widget.SwipeRefreshLayout>\n"
  },
  {
    "path": "app/src/main/res/layout/pager_app_info.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<io.github.muntashirakon.widget.SwipeRefreshLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:id=\"@+id/swipe_refresh\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\">\n\n    <io.github.muntashirakon.widget.NestedScrollView\n        android:id=\"@+id/scrollView\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:clipToPadding=\"false\"\n        android:fitsSystemWindows=\"true\"\n        app:fastScrollerEnabled=\"true\">\n\n        <androidx.appcompat.widget.LinearLayoutCompat\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:orientation=\"vertical\">\n\n            <com.google.android.material.progressindicator.LinearProgressIndicator\n                android:id=\"@+id/progress_linear\"\n                style=\"@style/Widget.AppTheme.LinearProgressIndicator\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:indeterminate=\"true\" />\n\n            <androidx.appcompat.widget.LinearLayoutCompat\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:orientation=\"vertical\"\n                android:paddingHorizontal=\"@dimen/padding_medium\">\n\n                <androidx.appcompat.widget.AppCompatImageView\n                    android:id=\"@+id/icon\"\n                    android:layout_width=\"44dp\"\n                    android:layout_height=\"44dp\"\n                    android:layout_gravity=\"center_horizontal\"\n                    android:layout_marginTop=\"@dimen/padding_medium\"\n                    android:layout_marginBottom=\"@dimen/padding_small\"\n                    android:background=\"@drawable/item_transparent\"\n                    android:contentDescription=\"@string/str_logo\"\n                    android:nextFocusDown=\"@id/label\"\n                    tools:ignore=\"contentDescription\"\n                    tools:srcCompat=\"@mipmap/ic_launcher\" />\n\n                <androidx.appcompat.widget.AppCompatTextView\n                    android:id=\"@+id/label\"\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_gravity=\"center_horizontal\"\n                    android:background=\"@drawable/item_transparent\"\n                    android:nextFocusUp=\"@id/icon\"\n                    android:nextFocusDown=\"@id/packageName\"\n                    android:textAppearance=\"?attr/textAppearanceTitleMedium\"\n                    android:textIsSelectable=\"true\"\n                    tools:ignore=\"TouchTargetSizeCheck\"\n                    tools:text=\"@string/app_name\" />\n\n                <androidx.appcompat.widget.AppCompatTextView\n                    android:id=\"@+id/packageName\"\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_gravity=\"center_horizontal\"\n                    android:background=\"@drawable/item_transparent\"\n                    android:nextFocusUp=\"@id/label\"\n                    android:nextFocusDown=\"@id/version\"\n                    android:textIsSelectable=\"true\"\n                    android:textStyle=\"italic\"\n                    tools:ignore=\"TouchTargetSizeCheck\"\n                    tools:text=\"io.github.muntashirakon.AppManager.debug\" />\n\n                <androidx.appcompat.widget.AppCompatTextView\n                    android:id=\"@+id/version\"\n                    android:layout_width=\"wrap_content\"\n                    android:layout_height=\"wrap_content\"\n                    android:layout_gravity=\"center_horizontal\"\n                    android:background=\"@drawable/item_transparent\"\n                    android:nextFocusUp=\"@id/packageName\"\n                    android:nextFocusDown=\"@id/tag_cloud\"\n                    android:textIsSelectable=\"true\"\n                    tools:ignore=\"TouchTargetSizeCheck\"\n                    tools:text=\"v10.2.0 (1001)\" />\n\n            </androidx.appcompat.widget.LinearLayoutCompat>\n\n            <io.github.muntashirakon.widget.FlowLayout\n                android:id=\"@+id/tag_cloud\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:gravity=\"center_horizontal\"\n                android:nextFocusUp=\"@id/version\"\n                android:nextFocusDown=\"@id/horizontal_layout\"\n                android:paddingHorizontal=\"@dimen/padding_medium\"\n                tools:listItem=\"@layout/item_chip\" />\n\n            <io.github.muntashirakon.widget.NestedScrollableHost\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\">\n\n                <HorizontalScrollView\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:layoutDirection=\"ltr\">\n\n                    <io.github.muntashirakon.widget.RoundedFirstAndLastChildViewGroup\n                        android:id=\"@+id/horizontal_layout\"\n                        android:layout_width=\"wrap_content\"\n                        android:layout_height=\"wrap_content\"\n                        android:nextFocusUp=\"@id/tag_cloud\"\n                        android:nextFocusDown=\"@android:id/list\"\n                        android:paddingHorizontal=\"@dimen/padding_medium\"\n                        android:paddingVertical=\"@dimen/padding_small\"\n                        tools:listItem=\"@layout/item_app_info_action\" />\n\n                </HorizontalScrollView>\n\n            </io.github.muntashirakon.widget.NestedScrollableHost>\n\n            <androidx.recyclerview.widget.RecyclerView\n                android:id=\"@android:id/list\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:nextFocusUp=\"@id/horizontal_layout\"\n                android:overScrollMode=\"never\"\n                tools:listitem=\"@layout/m3_preference\" />\n\n        </androidx.appcompat.widget.LinearLayoutCompat>\n\n    </io.github.muntashirakon.widget.NestedScrollView>\n\n</io.github.muntashirakon.widget.SwipeRefreshLayout>\n"
  },
  {
    "path": "app/src/main/res/layout/widget_recording.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- SPDX-License-Identifier: WTFPL -->\n<LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:id=\"@+id/clickable_linear_layout\"\n    android:layout_width=\"wrap_content\"\n    android:layout_height=\"wrap_content\"\n    android:layout_gravity=\"center\"\n    android:orientation=\"vertical\">\n\n    <ImageView\n        android:id=\"@+id/record_badge_image_view\"\n        android:layout_width=\"48dp\"\n        android:layout_height=\"48dp\"\n        android:layout_gravity=\"center_horizontal\"\n        android:contentDescription=\"@string/record_log\"\n        android:src=\"@drawable/ic_shortcut_record\"\n        tools:visibility=\"visible\" />\n\n    <TextView\n        android:id=\"@+id/widget_subtext\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"center_horizontal\"\n        android:ellipsize=\"marquee\"\n        android:fontFamily=\"sans-serif-condensed\"\n        android:gravity=\"center\"\n        android:text=\"@string/record_log\"\n        android:textColor=\"@color/primary_text_default_material_dark\"\n        android:textSize=\"14sp\" />\n\n</LinearLayout>"
  },
  {
    "path": "app/src/main/res/layout/window_activity_tracker.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<FrameLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\">\n\n    <com.google.android.material.imageview.ShapeableImageView\n        android:id=\"@+id/icon\"\n        android:layout_width=\"45dp\"\n        android:layout_height=\"45dp\"\n        app:srcCompat=\"@mipmap/ic_launcher_round\"\n        app:shapeAppearanceOverlay=\"@style/ShapeAppearance.AppTheme.CircleComponent\" />\n\n    <com.google.android.material.card.MaterialCardView\n        android:id=\"@+id/content\"\n        style=\"@style/Widget.AppTheme.CardView.Outlined\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        app:cardBackgroundColor=\"@color/sixty_percent_white\"\n        android:minWidth=\"200dp\">\n\n        <androidx.appcompat.widget.LinearLayoutCompat\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:orientation=\"vertical\"\n            android:paddingVertical=\"@dimen/padding_small\"\n            android:paddingHorizontal=\"@dimen/padding_small\">\n\n            <androidx.appcompat.widget.LinearLayoutCompat\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_gravity=\"center_vertical\"\n                android:layout_weight=\"1\"\n                android:orientation=\"vertical\">\n\n                <com.google.android.material.textfield.TextInputLayout\n                    style=\"@style/Widget.AppTheme.TextInputLayout.Small\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:hint=\"@string/package_name\"\n                    app:hintEnabled=\"true\">\n\n                    <io.github.muntashirakon.widget.TextInputTextView\n                        android:id=\"@+id/package_name\"\n                        android:layout_width=\"match_parent\"\n                        android:layout_height=\"wrap_content\"\n                        android:inputType=\"none\"\n                        android:maxLines=\"1\"\n                        android:fontFamily=\"monospace\"\n                        tools:text=\"io.github.muntashirakon.AppManager\" />\n\n                </com.google.android.material.textfield.TextInputLayout>\n\n                <com.google.android.material.textfield.TextInputLayout\n                    style=\"@style/Widget.AppTheme.TextInputLayout.Small\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:hint=\"@string/activity_name\"\n                    app:hintEnabled=\"true\">\n\n                    <io.github.muntashirakon.widget.TextInputTextView\n                        android:id=\"@+id/activity_name\"\n                        android:layout_width=\"match_parent\"\n                        android:layout_height=\"wrap_content\"\n                        android:inputType=\"none\"\n                        android:maxLines=\"1\"\n                        android:fontFamily=\"monospace\"\n                        tools:text=\"io.github.muntashirakon.AppManager\" />\n\n                </com.google.android.material.textfield.TextInputLayout>\n\n                <com.google.android.material.textfield.TextInputLayout\n                    style=\"@style/Widget.AppTheme.TextInputLayout.Small\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:hint=\"@string/class_name\"\n                    app:hintEnabled=\"true\">\n\n                    <io.github.muntashirakon.widget.TextInputTextView\n                        android:id=\"@+id/class_name\"\n                        android:layout_width=\"match_parent\"\n                        android:layout_height=\"wrap_content\"\n                        android:inputType=\"none\"\n                        android:maxLines=\"1\"\n                        android:fontFamily=\"monospace\"\n                        tools:text=\".accessibility.activity.LeadingActivityTrackerActivity\" />\n\n                </com.google.android.material.textfield.TextInputLayout>\n\n                <com.google.android.material.textfield.TextInputLayout\n                    style=\"@style/Widget.AppTheme.TextInputLayout.Small\"\n                    android:layout_width=\"match_parent\"\n                    android:layout_height=\"wrap_content\"\n                    android:hint=\"@string/class_hierarchy\"\n                    app:hintEnabled=\"true\">\n\n                    <io.github.muntashirakon.widget.TextInputTextView\n                        android:id=\"@+id/class_hierarchy\"\n                        android:layout_width=\"match_parent\"\n                        android:layout_height=\"wrap_content\"\n                        android:gravity=\"top|start\"\n                        android:lines=\"4\"\n                        android:maxLines=\"4\"\n                        android:inputType=\"none\"\n                        android:fontFamily=\"monospace\"\n                        tools:text=\".accessibility.activity.LeadingActivityTrackerActivity\" />\n\n                </com.google.android.material.textfield.TextInputLayout>\n\n            </androidx.appcompat.widget.LinearLayoutCompat>\n\n            <androidx.appcompat.widget.LinearLayoutCompat\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:layout_gravity=\"center_vertical\"\n                android:layout_weight=\"0\"\n                android:orientation=\"horizontal\">\n\n                <com.google.android.material.button.MaterialButton\n                    android:id=\"@+id/drag\"\n                    style=\"@style/Widget.AppTheme.Button.IconButton\"\n                    android:layout_width=\"40dp\"\n                    android:layout_height=\"40dp\"\n                    android:layout_weight=\"1\"\n                    android:clickable=\"false\"\n                    app:icon=\"@drawable/ic_drag\" />\n\n                <com.google.android.material.button.MaterialButton\n                    android:id=\"@+id/info\"\n                    style=\"@style/Widget.AppTheme.Button.IconButton\"\n                    android:layout_width=\"40dp\"\n                    android:layout_height=\"40dp\"\n                    android:layout_weight=\"1\"\n                    app:icon=\"@drawable/ic_information\" />\n\n                <com.google.android.material.button.MaterialButton\n                    android:id=\"@+id/mini\"\n                    style=\"@style/Widget.AppTheme.Button.IconButton\"\n                    android:layout_width=\"40dp\"\n                    android:layout_height=\"40dp\"\n                    android:layout_weight=\"1\"\n                    app:icon=\"@drawable/ic_fold_vertical\" />\n\n                <com.google.android.material.button.MaterialButton\n                    android:id=\"@+id/action_play_pause\"\n                    style=\"@style/Widget.AppTheme.Button.IconButton\"\n                    android:layout_width=\"40dp\"\n                    android:layout_height=\"40dp\"\n                    android:layout_weight=\"1\"\n                    app:icon=\"@drawable/ic_pause\" />\n\n                <com.google.android.material.button.MaterialButton\n                    android:id=\"@android:id/closeButton\"\n                    style=\"@style/Widget.AppTheme.Button.IconButton\"\n                    android:layout_width=\"40dp\"\n                    android:layout_height=\"40dp\"\n                    android:layout_weight=\"1\"\n                    app:icon=\"@drawable/ic_power_settings\" />\n\n            </androidx.appcompat.widget.LinearLayoutCompat>\n\n        </androidx.appcompat.widget.LinearLayoutCompat>\n\n    </com.google.android.material.card.MaterialCardView>\n</FrameLayout>"
  },
  {
    "path": "app/src/main/res/menu/activity_activity_interceptor_actions.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!-- SPDX-License-Identifier: Apache-2.0 -->\n<menu xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\">\n\n    <item\n        android:id=\"@+id/action_copy\"\n        android:icon=\"@drawable/ic_content_copy\"\n        android:title=\"@string/copy\"\n        app:showAsAction=\"always\">\n        <menu>\n            <item\n                android:id=\"@+id/action_copy_as_default\"\n                android:title=\"@string/copy\" />\n            <item\n                android:id=\"@+id/action_copy_as_command\"\n                android:title=\"@string/am_command\" />\n        </menu>\n    </item>\n\n    <item\n        android:id=\"@+id/action_paste\"\n        android:icon=\"@drawable/ic_content_paste\"\n        android:title=\"@string/paste\"\n        app:showAsAction=\"never\" />\n\n    <item\n        android:id=\"@+id/action_shortcut\"\n        android:icon=\"@drawable/ic_link\"\n        android:title=\"@string/create_shortcut\"\n        app:showAsAction=\"ifRoom\" />\n\n</menu>"
  },
  {
    "path": "app/src/main/res/menu/activity_app_explorer_selection_actions.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<menu xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <item\n        android:id=\"@+id/action_save\"\n        android:icon=\"@drawable/ic_content_save\"\n        android:title=\"@string/extract\" />\n\n    <item\n        android:id=\"@+id/action_replace\"\n        android:icon=\"@drawable/ic_file_replace\"\n        android:title=\"@string/replace\" />\n\n    <item\n        android:id=\"@+id/action_delete\"\n        android:icon=\"@drawable/ic_trash_can\"\n        android:title=\"@string/delete\" />\n\n    <item\n        android:id=\"@+id/action_rename\"\n        android:icon=\"@drawable/ic_form_textbox\"\n        android:title=\"@string/rename\" />\n\n</menu>"
  },
  {
    "path": "app/src/main/res/menu/activity_app_usage_actions.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<menu xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <item\n        android:icon=\"@drawable/ic_sort\"\n        android:title=\"@string/sort\"\n        app:showAsAction=\"ifRoom\">\n\n        <menu>\n\n            <group\n                android:checkableBehavior=\"single\"\n                android:menuCategory=\"container\">\n\n                <item\n                    android:id=\"@+id/action_sort_by_app_label\"\n                    android:title=\"@string/sort_by_app_label\" />\n\n                <item\n                    android:id=\"@+id/action_sort_by_package_name\"\n                    android:title=\"@string/sort_by_package_name\" />\n\n                <item\n                    android:id=\"@+id/action_sort_by_last_used\"\n                    android:title=\"@string/sort_by_last_used\" />\n\n                <item\n                    android:id=\"@+id/action_sort_by_screen_time\"\n                    android:title=\"@string/sort_by_screen_time\" />\n\n                <item\n                    android:id=\"@+id/action_sort_by_times_opened\"\n                    android:title=\"@string/sort_by_times_opened\" />\n\n                <item\n                    android:id=\"@+id/action_sort_by_mobile_data\"\n                    android:title=\"@string/sort_by_mobile_data\" />\n\n                <item\n                    android:id=\"@+id/action_sort_by_wifi_data\"\n                    android:title=\"@string/sort_by_wifi_data\" />\n\n            </group>\n\n        </menu>\n\n    </item>\n\n</menu>"
  },
  {
    "path": "app/src/main/res/menu/activity_batch_ops_results_actions.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<menu xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <item\n        android:id=\"@+id/action_retry\"\n        android:title=\"@string/try_again\"\n        app:showAsAction=\"ifRoom\" />\n\n</menu>"
  },
  {
    "path": "app/src/main/res/menu/activity_code_editor_actions.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<menu xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <item\n        android:id=\"@+id/action_java_smali_toggle\"\n        android:title=\"@string/java\"\n        app:showAsAction=\"always\" />\n\n    <item\n        android:id=\"@+id/action_search\"\n        android:icon=\"@drawable/ic_search\"\n        android:title=\"@string/search\"\n        app:showAsAction=\"ifRoom\" />\n\n    <item\n        android:id=\"@+id/action_undo\"\n        android:icon=\"@drawable/ic_undo\"\n        android:title=\"@string/undo\"\n        app:showAsAction=\"never\" />\n\n    <item\n        android:id=\"@+id/action_redo\"\n        android:icon=\"@drawable/ic_redo\"\n        android:title=\"@string/redo\"\n        app:showAsAction=\"never\" />\n\n    <item\n        android:id=\"@+id/action_save\"\n        android:icon=\"@drawable/ic_content_save\"\n        android:title=\"@string/save\"\n        app:showAsAction=\"ifRoom\" />\n\n    <item\n        android:id=\"@+id/action_save_as\"\n        android:icon=\"@drawable/ic_content_save\"\n        android:title=\"@string/save_as\"\n        app:showAsAction=\"never\" />\n\n    <item\n        android:id=\"@+id/action_wrap\"\n        android:icon=\"@drawable/ic_wrap_text\"\n        android:title=\"@string/word_wrap\"\n        app:showAsAction=\"never\" />\n\n    <item\n        android:id=\"@+id/action_share\"\n        android:icon=\"@drawable/ic_share\"\n        android:title=\"@string/share\"\n        app:showAsAction=\"never\" />\n\n</menu>"
  },
  {
    "path": "app/src/main/res/menu/activity_debloater_actions.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<menu xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\">\n    <item\n        android:id=\"@+id/action_list_options\"\n        android:icon=\"@drawable/ic_list_status\"\n        android:title=\"@string/list_options\"\n        app:showAsAction=\"always\" />\n</menu>\n"
  },
  {
    "path": "app/src/main/res/menu/activity_debloater_selection_actions.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<menu xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item\n        android:id=\"@+id/action_uninstall\"\n        android:icon=\"@drawable/ic_trash_can\"\n        android:title=\"@string/uninstall\" />\n    <item\n        android:id=\"@+id/action_put_back\"\n        android:icon=\"@drawable/ic_restore\"\n        android:visible=\"false\"\n        android:title=\"@string/system_app_put_back\" />\n    <item\n        android:id=\"@+id/action_freeze_unfreeze\"\n        android:icon=\"@drawable/ic_snowflake\"\n        android:title=\"@string/freeze_unfreeze\" />\n    <item\n        android:id=\"@+id/action_save_apk\"\n        android:title=\"@string/save_apk\"\n        android:icon=\"@drawable/ic_get_app\" />\n    <item\n        android:id=\"@+id/action_block_unblock_trackers\"\n        android:title=\"@string/block_unblock_trackers\"\n        android:icon=\"@drawable/ic_cctv_off\" />\n    <item\n        android:id=\"@+id/action_add_to_profile\"\n        android:icon=\"@drawable/ic_file_plus\"\n        android:title=\"@string/add_to_profile\" />\n</menu>"
  },
  {
    "path": "app/src/main/res/menu/activity_fm_actions.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<menu xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\">\n\n    <item\n        android:id=\"@+id/action_list_options\"\n        android:icon=\"@drawable/ic_list_status\"\n        android:title=\"@string/list_options\"\n        app:showAsAction=\"ifRoom\" />\n\n    <item\n        android:id=\"@+id/action_refresh\"\n        android:icon=\"@drawable/ic_refresh\"\n        android:title=\"@string/refresh\"\n        app:showAsAction=\"never\" />\n\n    <item\n        android:id=\"@+id/action_new_window\"\n        android:icon=\"@drawable/ic_tab\"\n        android:title=\"@string/open_in_new_window\"\n        app:showAsAction=\"ifRoom\" />\n\n    <item\n        android:id=\"@+id/action_paste\"\n        android:icon=\"@drawable/ic_content_paste\"\n        android:title=\"@string/paste\"\n        app:showAsAction=\"never\" />\n\n    <item\n        android:id=\"@+id/action_shortcut\"\n        android:icon=\"@drawable/ic_link\"\n        android:title=\"@string/create_shortcut\"\n        app:showAsAction=\"never\" />\n\n    <item\n        android:id=\"@+id/action_add_to_favorites\"\n        android:icon=\"@drawable/ic_star_outline\"\n        android:title=\"@string/add_to_favorites\"\n        app:showAsAction=\"never\" />\n\n    <item\n        android:id=\"@+id/action_settings\"\n        android:icon=\"@drawable/ic_settings\"\n        android:title=\"@string/settings\"\n        app:showAsAction=\"never\" />\n\n</menu>\n"
  },
  {
    "path": "app/src/main/res/menu/activity_help_actions.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<menu xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    tools:context=\".misc.HelpActivity\">\n    <group android:menuCategory=\"container\">\n\n        <item\n            android:id=\"@+id/action_search\"\n            android:icon=\"@drawable/ic_search\"\n            android:title=\"@string/search\"\n            app:showAsAction=\"always\" />\n\n    </group>\n</menu>\n"
  },
  {
    "path": "app/src/main/res/menu/activity_main_actions.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-or-later -->\n<menu xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\">\n    <item\n        android:id=\"@+id/action_instructions\"\n        android:icon=\"@drawable/ic_information\"\n        android:title=\"@string/user_manual\"\n        app:showAsAction=\"never\" />\n\n    <item\n        android:id=\"@+id/action_list_options\"\n        android:icon=\"@drawable/ic_list_status\"\n        android:title=\"@string/list_options\"\n        app:showAsAction=\"ifRoom\" />\n\n    <item\n        android:id=\"@+id/action_refresh\"\n        android:icon=\"@drawable/ic_refresh\"\n        android:title=\"@string/refresh\"\n        app:showAsAction=\"never\" />\n\n    <item\n        android:id=\"@+id/action_one_click_ops\"\n        android:icon=\"@drawable/ic_cursor_default_click\"\n        android:title=\"@string/one_click_ops\" />\n\n    <item\n        android:id=\"@+id/action_finder\"\n        android:icon=\"@drawable/ic_search\"\n        android:title=\"@string/finder_title\" />\n\n    <item\n        android:id=\"@+id/action_app_usage\"\n        android:icon=\"@drawable/ic_data_usage\"\n        android:title=\"@string/app_usage\" />\n\n    <item\n        android:id=\"@+id/action_running_apps\"\n        android:icon=\"@drawable/ic_pulse\"\n        android:title=\"@string/running_apps\" />\n\n    <item\n        android:id=\"@+id/action_profiles\"\n        android:icon=\"@drawable/ic_file_document_multiple\"\n        android:title=\"@string/profiles\" />\n\n    <item\n        android:id=\"@+id/action_apk_updater\"\n        android:icon=\"@drawable/ic_sync\"\n        android:title=\"@string/apk_updater\" />\n\n    <item\n        android:id=\"@+id/action_debloater\"\n        android:icon=\"@drawable/ic_liquid_spot_off\"\n        android:title=\"@string/debloater_title\" />\n\n    <item\n        android:id=\"@+id/action_labs\"\n        android:icon=\"@drawable/ic_package\"\n        android:title=\"@string/title_labs_activity\" />\n\n    <item\n        android:id=\"@+id/action_settings\"\n        android:icon=\"@drawable/ic_settings\"\n        android:title=\"@string/app_settings\" />\n\n</menu>"
  },
  {
    "path": "app/src/main/res/menu/activity_main_selection_actions.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<menu xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <item\n        android:id=\"@+id/action_uninstall\"\n        android:icon=\"@drawable/ic_trash_can\"\n        android:title=\"@string/uninstall\" />\n    <item\n        android:id=\"@+id/action_freeze_unfreeze\"\n        android:icon=\"@drawable/ic_snowflake\"\n        android:title=\"@string/freeze_unfreeze\" />\n    <item\n        android:id=\"@+id/action_force_stop\"\n        android:title=\"@string/force_stop\"\n        android:icon=\"@drawable/ic_power_settings\" />\n    <item\n        android:id=\"@+id/action_clear_data_cache\"\n        android:icon=\"@drawable/ic_brush\"\n        android:title=\"@string/clear\" />\n    <item\n        android:id=\"@+id/action_save_apk\"\n        android:title=\"@string/save_apk\"\n        android:icon=\"@drawable/ic_get_app\" />\n    <item\n        android:id=\"@+id/action_backup\"\n        android:title=\"@string/backup_restore\"\n        android:icon=\"@drawable/ic_backup_restore\" />\n    <item\n        android:id=\"@+id/action_disable_background\"\n        android:title=\"@string/disable_background\"\n        android:icon=\"@drawable/ic_block\" />\n    <item\n        android:id=\"@+id/action_block_unblock_trackers\"\n        android:title=\"@string/block_unblock_trackers\"\n        android:icon=\"@drawable/ic_cctv_off\" />\n    <item\n        android:id=\"@+id/action_net_policy\"\n        android:title=\"@string/net_policy\"\n        android:icon=\"@drawable/ic_security_network\" />\n    <item\n        android:id=\"@+id/action_optimize\"\n        android:title=\"@string/action_optimize_app\"\n        android:icon=\"@drawable/ic_run_fast\" />\n    <item\n        android:id=\"@+id/action_export_blocking_rules\"\n        android:title=\"@string/export_blocking_rules\"\n        android:icon=\"@drawable/ic_file_export\" />\n    <item\n        android:id=\"@+id/action_export_app_list\"\n        android:title=\"@string/export_app_list\"\n        android:icon=\"@drawable/ic_file_export\" />\n    <item\n        android:id=\"@+id/action_add_to_profile\"\n        android:icon=\"@drawable/ic_file_plus\"\n        android:title=\"@string/add_to_profile\" />\n</menu>"
  },
  {
    "path": "app/src/main/res/menu/activity_profile_navigation.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<menu xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item\n        android:id=\"@+id/action_apps\"\n        android:icon=\"@drawable/ic_android\"\n        android:title=\"@string/apps\" />\n\n    <item\n        android:id=\"@+id/action_preview\"\n        android:icon=\"@drawable/ic_eye\"\n        android:title=\"@string/preview\" />\n\n    <item\n        android:id=\"@+id/action_conf\"\n        android:icon=\"@drawable/ic_tune\"\n        android:title=\"@string/configurations\" />\n\n    <item\n        android:id=\"@+id/action_logs\"\n        android:icon=\"@drawable/ic_history\"\n        android:title=\"@string/log_viewer\" />\n\n</menu>\n"
  },
  {
    "path": "app/src/main/res/menu/activity_profiles_actions.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<menu xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item\n        android:id=\"@+id/action_refresh\"\n        android:icon=\"@drawable/ic_refresh\"\n        android:title=\"@string/refresh\"\n        app:showAsAction=\"never\" />\n\n    <item\n        android:id=\"@+id/action_import\"\n        android:icon=\"@drawable/ic_file_import\"\n        android:title=\"@string/pref_import\" />\n\n</menu>"
  },
  {
    "path": "app/src/main/res/menu/activity_profiles_popup_actions.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<menu xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <item\n        android:id=\"@+id/action_apply\"\n        android:icon=\"@drawable/ic_sync\"\n        android:title=\"@string/apply_now\" />\n\n    <item\n        android:id=\"@+id/action_delete\"\n        android:icon=\"@drawable/ic_trash_can\"\n        android:title=\"@string/delete\" />\n\n    <item\n        android:id=\"@+id/action_routine_ops\"\n        android:icon=\"@drawable/ic_view_list\"\n        android:title=\"@string/routine_ops\" />\n\n    <item\n        android:id=\"@+id/action_duplicate\"\n        android:icon=\"@drawable/ic_content_duplicate\"\n        android:title=\"@string/duplicate\" />\n\n    <item\n        android:id=\"@+id/action_copy\"\n        android:icon=\"@drawable/ic_content_copy\"\n        android:title=\"@string/copy_profile_id\" />\n\n    <item\n        android:id=\"@+id/action_export\"\n        android:icon=\"@drawable/ic_file_export\"\n        android:title=\"@string/pref_export\" />\n\n    <item\n        android:id=\"@+id/action_shortcut\"\n        android:icon=\"@drawable/ic_image\"\n        android:title=\"@string/create_shortcut\" />\n\n</menu>"
  },
  {
    "path": "app/src/main/res/menu/activity_running_apps_actions.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<menu xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\">\n\n    <item\n        android:icon=\"@drawable/ic_sort\"\n        android:title=\"@string/sort\"\n        app:showAsAction=\"ifRoom\">\n        <menu>\n            <group\n                android:checkableBehavior=\"single\"\n                android:menuCategory=\"container\">\n\n                <item\n                    android:id=\"@+id/action_sort_by_pid\"\n                    android:title=\"@string/sort_by_process_id\" />\n\n                <item\n                    android:id=\"@+id/action_sort_by_process_name\"\n                    android:title=\"@string/sort_by_process_name\" />\n\n                <item\n                    android:id=\"@+id/action_sort_by_apps_first\"\n                    android:title=\"@string/sort_by_apps_first\" />\n\n                <item\n                    android:id=\"@+id/action_sort_by_memory_usage\"\n                    android:title=\"@string/sort_by_memory_usage\" />\n                <item\n                    android:id=\"@+id/action_sort_by_cpu_time\"\n                    android:title=\"@string/sort_by_cpu_time\" />\n\n            </group>\n        </menu>\n    </item>\n\n    <item\n        android:icon=\"@drawable/ic_flag\"\n        android:title=\"@string/filter\"\n        app:showAsAction=\"ifRoom\">\n        <menu>\n            <group\n                android:checkableBehavior=\"all\"\n                android:menuCategory=\"container\">\n\n                <item\n                    android:id=\"@+id/action_filter_apps\"\n                    android:title=\"@string/filter_apps\" />\n\n                <item\n                    android:id=\"@+id/action_filter_user_apps\"\n                    android:title=\"@string/filter_user_apps\" />\n\n            </group>\n        </menu>\n    </item>\n\n    <item\n        android:id=\"@+id/action_toggle_kill\"\n        android:icon=\"@drawable/ic_clear\"\n        android:title=\"@string/toggle_kill_for_system_apps\"\n        app:showAsAction=\"never\" />\n\n</menu>"
  },
  {
    "path": "app/src/main/res/menu/activity_running_apps_popup_actions.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<menu xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <item\n        android:id=\"@+id/action_kill\"\n        android:icon=\"@drawable/ic_clear\"\n        android:title=\"@string/kill_process\" />\n\n    <item\n        android:id=\"@+id/action_force_stop\"\n        android:icon=\"@drawable/ic_power_settings\"\n        android:title=\"@string/force_stop\" />\n\n    <item\n        android:id=\"@+id/action_disable_background\"\n        android:icon=\"@drawable/ic_block\"\n        android:title=\"@string/disable_background_run\" />\n\n    <item\n        android:id=\"@+id/action_view_logs\"\n        android:icon=\"@drawable/ic_view_list\"\n        android:title=\"@string/view_logs\" />\n\n    <item\n        android:id=\"@+id/action_scan_vt\"\n        android:icon=\"@drawable/ic_vt\"\n        android:title=\"@string/scan_in_vt\" />\n\n</menu>"
  },
  {
    "path": "app/src/main/res/menu/activity_scanner.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<menu xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\">\n    <item\n        android:id=\"@+id/action_install\"\n        android:icon=\"@drawable/ic_get_app\"\n        android:title=\"@string/install\"\n        app:showAsAction=\"ifRoom\" />\n</menu>"
  },
  {
    "path": "app/src/main/res/menu/activity_shared_prefs_actions.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n\n<menu xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <item\n        android:id=\"@+id/action_save\"\n        android:icon=\"@drawable/ic_content_save\"\n        android:title=\"@string/save\" />\n    <item\n        android:id=\"@+id/action_discard\"\n        android:icon=\"@drawable/ic_file_undo\"\n        android:title=\"@string/discard\" />\n    <item\n        android:id=\"@+id/action_delete\"\n        android:icon=\"@drawable/ic_trash_can\"\n        android:title=\"@string/delete\" />\n    <item\n        android:id=\"@+id/action_separate_window\"\n        android:icon=\"@drawable/ic_open_in_new\"\n        android:title=\"@string/open_in_new_window\" />\n</menu>"
  },
  {
    "path": "app/src/main/res/menu/fragment_app_details_app_ops_actions.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<menu xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\">\n\n    <item\n        android:id=\"@+id/action_refresh_details\"\n        android:icon=\"@drawable/ic_refresh\"\n        android:title=\"@string/refresh\"\n        app:showAsAction=\"never\" />\n\n    <item\n        android:id=\"@+id/action_reset_to_default\"\n        android:icon=\"@drawable/ic_restore\"\n        android:title=\"@string/reset_to_default\"\n        app:showAsAction=\"never\" />\n\n    <item\n        android:id=\"@+id/action_deny_dangerous_app_ops\"\n        android:icon=\"@drawable/ic_block\"\n        android:title=\"@string/deny_dangerous_app_ops\"\n        app:showAsAction=\"never\" />\n\n    <item\n        android:id=\"@+id/action_toggle_default_app_ops\"\n        android:icon=\"@drawable/ic_view_list\"\n        android:title=\"@string/toggle_default_app_ops\"\n        app:showAsAction=\"never\" />\n\n    <item\n        android:id=\"@+id/action_custom_app_op\"\n        android:icon=\"@drawable/ic_add\"\n        android:title=\"@string/set_custom_app_op\"\n        app:showAsAction=\"never\" />\n\n    <item\n        android:icon=\"@drawable/ic_sort\"\n        android:title=\"@string/sort\"\n        app:showAsAction=\"never\">\n\n        <menu>\n\n            <group\n                android:checkableBehavior=\"single\"\n                android:menuCategory=\"container\">\n\n                <item\n                    android:id=\"@+id/action_sort_by_name\"\n                    android:title=\"@string/sort_by_app_ops_names\" />\n\n                <item\n                    android:id=\"@+id/action_sort_by_app_ops_values\"\n                    android:title=\"@string/sort_by_app_ops_values\" />\n\n                <item\n                    android:id=\"@+id/action_sort_by_denied_app_ops\"\n                    android:title=\"@string/sort_by_denied_app_ops\" />\n\n            </group>\n\n        </menu>\n\n    </item>\n\n</menu>"
  },
  {
    "path": "app/src/main/res/menu/fragment_app_details_components_actions.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<menu xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\">\n\n    <item\n        android:id=\"@+id/action_refresh_details\"\n        android:icon=\"@drawable/ic_refresh\"\n        android:title=\"@string/refresh\"\n        app:showAsAction=\"never\" />\n\n    <item\n        android:id=\"@+id/action_toggle_blocking\"\n        android:icon=\"@drawable/ic_block\"\n        android:title=\"\"\n        app:showAsAction=\"never\" />\n\n    <item\n        android:id=\"@+id/action_block_unblock_trackers\"\n        android:icon=\"@drawable/ic_cctv_off\"\n        android:title=\"@string/block_unblock_trackers\"\n        app:showAsAction=\"never\" />\n\n    <item\n        android:icon=\"@drawable/ic_sort\"\n        android:title=\"@string/sort\"\n        app:showAsAction=\"never\">\n\n        <menu>\n\n            <group\n                android:checkableBehavior=\"single\"\n                android:menuCategory=\"container\">\n\n                <item\n                    android:id=\"@+id/action_sort_by_name\"\n                    android:title=\"@string/sort_by_component_name\" />\n\n                <item\n                    android:id=\"@+id/action_sort_by_blocked_components\"\n                    android:title=\"@string/sort_by_blocked_components\" />\n\n                <item\n                    android:id=\"@+id/action_sort_by_tracker_components\"\n                    android:title=\"@string/sort_by_tracker_components\" />\n\n            </group>\n\n        </menu>\n\n    </item>\n\n</menu>"
  },
  {
    "path": "app/src/main/res/menu/fragment_app_details_components_selection_actions.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<menu xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <item\n        android:id=\"@+id/action_ifw_and_disable\"\n        android:title=\"@string/intent_firewall_and_disable\" />\n\n    <item\n        android:id=\"@+id/action_ifw\"\n        android:title=\"@string/intent_firewall\" />\n\n    <item\n        android:id=\"@+id/action_disable\"\n        android:title=\"@string/disable\" />\n\n    <item\n        android:id=\"@+id/action_enable\"\n        android:title=\"@string/enable\" />\n\n    <item\n        android:id=\"@+id/action_default\"\n        android:title=\"@string/use_default\" />\n\n</menu>\n"
  },
  {
    "path": "app/src/main/res/menu/fragment_app_details_overlay_actions.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<menu xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\">\n\n    <item\n        android:id=\"@+id/action_refresh_details\"\n        android:icon=\"@drawable/ic_refresh\"\n        android:title=\"@string/refresh\"\n        app:showAsAction=\"never\" />\n\n    <item\n        android:icon=\"@drawable/ic_sort\"\n        android:title=\"@string/sort\"\n        app:showAsAction=\"never\">\n\n        <menu>\n\n            <group\n                android:checkableBehavior=\"single\"\n                android:menuCategory=\"container\">\n\n                <item\n                    android:id=\"@+id/action_sort_by_name\"\n                    android:title=\"@string/sort_by_overlay_names\" />\n\n                <item\n                    android:id=\"@+id/action_sort_by_priority\"\n                    android:title=\"@string/sort_by_priority\" />\n\n            </group>\n\n        </menu>\n\n    </item>\n\n</menu>"
  },
  {
    "path": "app/src/main/res/menu/fragment_app_details_permissions_actions.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<menu xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\">\n\n    <item\n        android:id=\"@+id/action_refresh_details\"\n        android:icon=\"@drawable/ic_refresh\"\n        android:title=\"@string/refresh\"\n        app:showAsAction=\"never\" />\n\n    <item\n        android:id=\"@+id/action_deny_dangerous_permissions\"\n        android:icon=\"@drawable/ic_block\"\n        android:title=\"@string/deny_dangerous_permissions\"\n        app:showAsAction=\"never\" />\n\n    <item\n        android:icon=\"@drawable/ic_sort\"\n        android:title=\"@string/sort\"\n        app:showAsAction=\"never\">\n\n        <menu>\n\n            <group\n                android:checkableBehavior=\"single\"\n                android:menuCategory=\"container\">\n\n                <item\n                    android:id=\"@+id/action_sort_by_name\"\n                    android:title=\"@string/sort_by_permission_names\" />\n\n                <item\n                    android:id=\"@+id/action_sort_by_dangerous_permissions\"\n                    android:title=\"@string/sort_by_dangerous_permissions\" />\n\n                <item\n                    android:id=\"@+id/action_sort_by_denied_permissions\"\n                    android:title=\"@string/sort_by_denied_permissions\" />\n\n            </group>\n\n        </menu>\n\n    </item>\n\n</menu>"
  },
  {
    "path": "app/src/main/res/menu/fragment_app_details_refresh_actions.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<menu xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\">\n\n    <item\n        android:id=\"@+id/action_refresh_details\"\n        android:icon=\"@drawable/ic_refresh\"\n        android:title=\"@string/refresh\"\n        app:showAsAction=\"never\" />\n\n</menu>"
  },
  {
    "path": "app/src/main/res/menu/fragment_app_info_actions.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<menu xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\">\n\n    <item\n        android:id=\"@+id/action_share_apk\"\n        android:icon=\"@drawable/ic_share\"\n        android:title=\"@string/share_apk\"\n        app:showAsAction=\"ifRoom\" />\n\n    <item\n        android:id=\"@+id/action_refresh_detail\"\n        android:icon=\"@drawable/ic_refresh\"\n        android:title=\"@string/refresh\"\n        app:showAsAction=\"never\" />\n\n    <item\n        android:id=\"@+id/action_view_settings\"\n        android:icon=\"@drawable/ic_settings\"\n        android:title=\"@string/view_in_settings\"\n        app:showAsAction=\"never\" />\n\n    <item\n        android:id=\"@+id/action_backup\"\n        android:icon=\"@drawable/ic_backup_restore\"\n        android:title=\"@string/backup_restore\"\n        app:showAsAction=\"never\" />\n\n    <item\n        android:id=\"@+id/action_export_blocking_rules\"\n        android:icon=\"@drawable/ic_file_export\"\n        android:title=\"@string/export_blocking_rules\"\n        app:showAsAction=\"never\" />\n\n    <item\n        android:id=\"@+id/action_open_in_termux\"\n        android:icon=\"@drawable/ic_frost_termux\"\n        android:title=\"@string/open_in_termux\"\n        app:showAsAction=\"never\" />\n\n    <item\n        android:id=\"@+id/action_run_in_termux\"\n        android:icon=\"@drawable/ic_frost_termux\"\n        android:title=\"@string/run_in_termux\"\n        app:showAsAction=\"never\" />\n\n    <item\n        android:id=\"@+id/action_magisk_hide\"\n        android:icon=\"@drawable/ic_security\"\n        android:title=\"@string/magisk_hide_enabled\"\n        app:showAsAction=\"never\" />\n\n    <item\n        android:id=\"@+id/action_magisk_denylist\"\n        android:icon=\"@drawable/ic_security\"\n        android:title=\"@string/magisk_denylist\"\n        app:showAsAction=\"never\" />\n\n    <item\n        android:id=\"@+id/action_battery_opt\"\n        android:icon=\"@drawable/ic_battery_plus\"\n        android:title=\"@string/battery_optimization\"\n        app:showAsAction=\"never\" />\n\n    <item\n        android:id=\"@+id/action_sensor\"\n        android:icon=\"@drawable/ic_pulse\"\n        android:title=\"@string/sensors\"\n        app:showAsAction=\"never\" />\n\n    <item\n        android:id=\"@+id/action_net_policy\"\n        android:icon=\"@drawable/ic_security_network\"\n        android:title=\"@string/net_policy\"\n        app:showAsAction=\"never\" />\n\n    <item\n        android:id=\"@+id/action_extract_icon\"\n        android:icon=\"@drawable/ic_image\"\n        android:title=\"@string/export_icon\"\n        app:showAsAction=\"never\" />\n\n    <item\n        android:id=\"@+id/action_optimize\"\n        android:icon=\"@drawable/ic_run_fast\"\n        android:title=\"@string/action_optimize_app\"\n        app:showAsAction=\"never\" />\n\n    <item\n        android:id=\"@+id/action_add_to_profile\"\n        android:icon=\"@drawable/ic_file_plus\"\n        android:title=\"@string/add_to_profile\"\n        app:showAsAction=\"never\" />\n\n    <item\n        android:id=\"@+id/action_install\"\n        android:icon=\"@drawable/ic_get_app\"\n        android:title=\"@string/install_for_another_user\"\n        app:showAsAction=\"never\" />\n\n</menu>"
  },
  {
    "path": "app/src/main/res/menu/fragment_class_lister_actions.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<menu xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    tools:context=\".scanner.ScannerActivity\">\n    <group android:menuCategory=\"container\">\n\n        <item\n            android:id=\"@+id/action_search\"\n            android:title=\"@string/search\"\n            app:actionViewClass=\"io.github.muntashirakon.AppManager.misc.AdvancedSearchView\"\n            app:showAsAction=\"always\"\n            tools:ignore=\"AlwaysShowAction\" />\n\n        <item\n            android:id=\"@+id/action_toggle_class_listing\"\n            android:icon=\"@drawable/ic_code\"\n            android:title=\"@string/toggle_class_listing\"\n            app:showAsAction=\"never\" />\n\n    </group>\n</menu>\n"
  },
  {
    "path": "app/src/main/res/menu/fragment_fm_item_actions.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<menu xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <item\n        android:id=\"@+id/action_open_with\"\n        android:icon=\"@drawable/ic_open_in_new\"\n        android:title=\"@string/file_open_with\" />\n\n    <item\n        android:id=\"@+id/action_cut\"\n        android:icon=\"@drawable/ic_content_cut\"\n        android:title=\"@string/file_cut\" />\n\n    <item\n        android:id=\"@+id/action_copy\"\n        android:icon=\"@drawable/ic_file_copy\"\n        android:title=\"@string/copy\" />\n\n    <item\n        android:id=\"@+id/action_rename\"\n        android:icon=\"@drawable/ic_form_textbox\"\n        android:title=\"@string/rename\" />\n\n    <item\n        android:id=\"@+id/action_delete\"\n        android:icon=\"@drawable/ic_trash_can\"\n        android:title=\"@string/delete\" />\n\n    <item\n        android:id=\"@+id/action_share\"\n        android:icon=\"@drawable/ic_share\"\n        android:title=\"@string/share\" />\n\n    <item\n        android:id=\"@+id/action_shortcut\"\n        android:icon=\"@drawable/ic_link\"\n        android:title=\"@string/create_shortcut\" />\n\n    <item\n        android:id=\"@+id/action_add_to_favorites\"\n        android:icon=\"@drawable/ic_star_outline\"\n        android:title=\"@string/add_to_favorites\" />\n\n    <item\n        android:id=\"@+id/action_copy_path\"\n        android:icon=\"@drawable/ic_content_copy\"\n        android:title=\"@string/copy_this_path\" />\n\n    <item\n        android:id=\"@+id/action_select\"\n        android:icon=\"@drawable/ic_check_circle\"\n        android:title=\"@string/item_select\" />\n\n    <item\n        android:id=\"@+id/action_properties\"\n        android:icon=\"@drawable/ic_information\"\n        android:title=\"@string/file_properties\" />\n\n</menu>"
  },
  {
    "path": "app/src/main/res/menu/fragment_fm_selection_actions.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<menu xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <item\n        android:id=\"@+id/action_share\"\n        android:icon=\"@drawable/ic_share\"\n        android:title=\"@string/share\" />\n\n    <item\n        android:id=\"@+id/action_rename\"\n        android:icon=\"@drawable/ic_form_textbox\"\n        android:title=\"@string/rename\" />\n\n    <item\n        android:id=\"@+id/action_delete\"\n        android:icon=\"@drawable/ic_trash_can\"\n        android:title=\"@string/delete\" />\n\n    <item\n        android:id=\"@+id/action_cut\"\n        android:icon=\"@drawable/ic_content_cut\"\n        android:title=\"@string/file_cut\" />\n\n    <item\n        android:id=\"@+id/action_copy\"\n        android:icon=\"@drawable/ic_file_copy\"\n        android:title=\"@string/copy\" />\n\n    <item\n        android:id=\"@+id/action_copy_path\"\n        android:icon=\"@drawable/ic_content_copy\"\n        android:title=\"@string/copy_these_paths\" />\n\n</menu>"
  },
  {
    "path": "app/src/main/res/menu/fragment_fm_speed_dial.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<menu xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item\n        android:id=\"@+id/action_file\"\n        android:icon=\"@drawable/ic_file\"\n        android:title=\"@string/file\" />\n\n    <item\n        android:id=\"@+id/action_folder\"\n        android:icon=\"@drawable/ic_folder\"\n        android:title=\"@string/folder\" />\n\n    <item\n        android:id=\"@+id/action_symbolic_link\"\n        android:icon=\"@drawable/ic_arrow_outward\"\n        android:title=\"@string/symbolic_link\" />\n\n</menu>"
  },
  {
    "path": "app/src/main/res/menu/fragment_live_log_viewer_actions.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<menu xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\">\n\n    <item\n        android:id=\"@+id/action_play_pause\"\n        android:icon=\"@drawable/ic_pause\"\n        android:title=\"@string/pause_unpause\"\n        app:showAsAction=\"always\" />\n\n    <item\n        android:id=\"@+id/action_expand_collapse\"\n        android:icon=\"@drawable/ic_expand_more\"\n        android:title=\"@string/expand_all\"\n        app:showAsAction=\"always\" />\n\n    <item\n        android:id=\"@+id/action_clear\"\n        android:icon=\"@drawable/ic_brush\"\n        android:title=\"@string/clear\"\n        app:showAsAction=\"ifRoom\" />\n\n    <item\n        android:icon=\"@drawable/ic_file_document\"\n        android:title=\"@string/file\">\n\n        <menu>\n            <item\n                android:id=\"@+id/action_open\"\n                android:icon=\"@drawable/ic_folder\"\n                android:title=\"@string/open\" />\n\n            <item\n                android:id=\"@+id/action_save\"\n                android:icon=\"@drawable/ic_content_save\"\n                android:title=\"@string/save\" />\n\n            <item\n                android:id=\"@+id/action_record\"\n                android:icon=\"@drawable/ic_record_rec\"\n                android:title=\"@string/start_recording_log\" />\n\n            <item\n                android:id=\"@+id/action_delete\"\n                android:icon=\"@drawable/ic_trash_can\"\n                android:title=\"@string/manage_saved_logs\" />\n        </menu>\n    </item>\n\n    <item\n        android:id=\"@+id/action_change_log_level\"\n        android:icon=\"@drawable/ic_sort\"\n        android:title=\"@string/log_level\" />\n\n    <item\n        android:id=\"@+id/action_show_saved_filters\"\n        android:icon=\"@drawable/ic_filter_list\"\n        android:title=\"@string/saved_filters\" />\n\n    <item\n        android:id=\"@+id/action_share\"\n        android:icon=\"@drawable/ic_share\"\n        android:title=\"@string/share_log\" />\n\n    <item\n        android:id=\"@+id/action_export\"\n        android:icon=\"@drawable/ic_file_export\"\n        android:title=\"@string/pref_export\" />\n\n    <item\n        android:id=\"@+id/action_settings\"\n        android:icon=\"@drawable/ic_settings\"\n        android:title=\"@string/settings\" />\n\n    <item\n        android:id=\"@+id/action_crazy_logger_service\"\n        android:title=\"Crazy Logger\"\n        tools:ignore=\"HardcodedText\" />\n\n</menu>"
  },
  {
    "path": "app/src/main/res/menu/fragment_logcat_selection_actions.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<menu xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item\n        android:id=\"@+id/action_save\"\n        android:icon=\"@drawable/ic_content_save\"\n        android:title=\"@string/save\" />\n\n    <item\n        android:id=\"@+id/action_copy\"\n        android:icon=\"@drawable/ic_content_copy\"\n        android:title=\"@string/copy\" />\n\n    <item\n        android:id=\"@+id/action_share\"\n        android:icon=\"@drawable/ic_share\"\n        android:title=\"@string/share_log\" />\n\n    <item\n        android:id=\"@+id/action_export\"\n        android:icon=\"@drawable/ic_file_export\"\n        android:title=\"@string/pref_export\" />\n\n</menu>"
  },
  {
    "path": "app/src/main/res/menu/fragment_profile_apps_actions.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<menu xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <item\n        android:id=\"@+id/action_apply\"\n        android:icon=\"@drawable/ic_sync\"\n        android:title=\"@string/apply\"\n        app:showAsAction=\"never\" />\n\n    <item\n        android:id=\"@+id/action_save\"\n        android:icon=\"@drawable/ic_content_save\"\n        android:title=\"@string/save\"\n        app:showAsAction=\"never\" />\n\n    <item\n        android:id=\"@+id/action_discard\"\n        android:icon=\"@drawable/ic_file_undo\"\n        android:title=\"@string/discard\"\n        app:showAsAction=\"never\" />\n\n    <item\n        android:id=\"@+id/action_delete\"\n        android:icon=\"@drawable/ic_trash_can\"\n        android:title=\"@string/delete\"\n        app:showAsAction=\"never\" />\n\n    <item\n        android:id=\"@+id/action_duplicate\"\n        android:icon=\"@drawable/ic_content_duplicate\"\n        android:title=\"@string/duplicate\" />\n\n    <item\n        android:id=\"@+id/action_shortcut\"\n        android:icon=\"@drawable/ic_image\"\n        android:title=\"@string/create_shortcut\" />\n\n</menu>"
  },
  {
    "path": "app/src/main/res/menu/fragment_saved_log_viewer_actions.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<menu xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\">\n\n    <item\n        android:id=\"@+id/action_expand_collapse\"\n        android:icon=\"@drawable/ic_expand_more\"\n        android:title=\"@string/expand_all\"\n        app:showAsAction=\"always\" />\n\n    <item\n        android:icon=\"@drawable/ic_file_document\"\n        android:title=\"@string/file\">\n\n        <menu>\n            <item\n                android:id=\"@+id/action_open\"\n                android:icon=\"@drawable/ic_folder\"\n                android:title=\"@string/open\" />\n\n            <item\n                android:id=\"@+id/action_save\"\n                android:icon=\"@drawable/ic_content_save\"\n                android:title=\"@string/save_as\" />\n\n            <item\n                android:id=\"@+id/action_delete\"\n                android:icon=\"@drawable/ic_trash_can\"\n                android:title=\"@string/manage_saved_logs\" />\n        </menu>\n    </item>\n\n    <item\n        android:id=\"@+id/action_change_log_level\"\n        android:icon=\"@drawable/ic_sort\"\n        android:title=\"@string/log_level\" />\n\n    <item\n        android:id=\"@+id/action_show_saved_filters\"\n        android:icon=\"@drawable/ic_filter_list\"\n        android:title=\"@string/saved_filters\" />\n\n    <item\n        android:id=\"@+id/action_share\"\n        android:icon=\"@drawable/ic_share\"\n        android:title=\"@string/share_log\" />\n\n    <item\n        android:id=\"@+id/action_export\"\n        android:icon=\"@drawable/ic_file_export\"\n        android:title=\"@string/pref_export\" />\n\n    <item\n        android:id=\"@+id/action_settings\"\n        android:icon=\"@drawable/ic_settings\"\n        android:title=\"@string/settings\" />\n\n</menu>"
  },
  {
    "path": "app/src/main/res/menu/view_advanced_search_type_selections.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<menu xmlns:android=\"http://schemas.android.com/apk/res/android\">\n\n    <item\n        android:id=\"@+id/action_search_type_contains\"\n        android:title=\"@string/search_type_contains\" />\n\n    <item\n        android:id=\"@+id/action_search_type_prefix\"\n        android:title=\"@string/search_type_prefix\" />\n\n    <item\n        android:id=\"@+id/action_search_type_suffix\"\n        android:title=\"@string/search_type_suffix\" />\n\n    <item\n        android:id=\"@+id/action_search_type_regex\"\n        android:title=\"@string/search_type_regular_expressions\" />\n\n</menu>"
  },
  {
    "path": "app/src/main/res/mipmap-anydpi-v26/ic_banner.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later OR CC-BY-SA-4.0 -->\n<adaptive-icon xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <background android:drawable=\"@color/ic_banner_background\" />\n    <foreground>\n        <inset\n            android:drawable=\"@mipmap/ic_banner_foreground\"\n            android:inset=\"16.75%\" />\n    </foreground>\n</adaptive-icon>"
  },
  {
    "path": "app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later OR CC-BY-SA-4.0 -->\n<adaptive-icon xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <background android:drawable=\"@color/ic_launcher_background\" />\n    <foreground android:drawable=\"@drawable/ic_launcher_foreground\" />\n    <monochrome android:drawable=\"@drawable/ic_launcher_foreground\" />\n</adaptive-icon>"
  },
  {
    "path": "app/src/main/res/mipmap-anydpi-v26/ic_launcher_fm.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later OR CC-BY-SA-4.0 -->\n<adaptive-icon xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <background android:drawable=\"@color/ic_launcher_fm_background\" />\n    <foreground android:drawable=\"@drawable/ic_launcher_fm_foreground\" />\n    <monochrome android:drawable=\"@drawable/ic_launcher_fm_foreground\" />\n</adaptive-icon>"
  },
  {
    "path": "app/src/main/res/mipmap-anydpi-v26/ic_launcher_fm_round.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later OR CC-BY-SA-4.0 -->\n<adaptive-icon xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <background android:drawable=\"@color/ic_launcher_fm_background\"/>\n    <foreground android:drawable=\"@drawable/ic_launcher_fm_foreground\"/>\n    <monochrome android:drawable=\"@drawable/ic_launcher_fm_foreground\" />\n</adaptive-icon>"
  },
  {
    "path": "app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later OR CC-BY-SA-4.0 -->\n<adaptive-icon xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <background android:drawable=\"@color/ic_launcher_background\" />\n    <foreground android:drawable=\"@drawable/ic_launcher_foreground\" />\n    <monochrome android:drawable=\"@drawable/ic_launcher_foreground\" />\n</adaptive-icon>"
  },
  {
    "path": "app/src/main/res/raw/changelog.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\" standalone=\"yes\"?><!DOCTYPE changelog SYSTEM \"https://raw.githubusercontent.com/MuntashirAkon/AppManager/master/schema/changlelog.dtd\">\n<changelog>\n    <release\n        type=\"stable release\"\n        version=\"v4.0.5\"\n        code=\"445\"\n        date=\"28 July 2025\">\n        <note>App Manager releases are now reproducible!</note>\n        <note subtext=\"true\">\n            AM Debug builds are also available at\n            [a href=\"https://github.com/MuntashirAkon/AMInsecureDebugBuilds\"]https://github.com/MuntashirAkon/AMInsecureDebugBuilds[/a]\n        </note>\n        <new title=\"Installer\">Added option to allow installing the existing applications</new>\n        <note subtext=\"true\">\n            Existing application is one whose APK files are still available in the system, either\n            because it's a system application or an user application installed for another user.\n            It can be installed for the current user by providing a URI to the installer that has\n            the following format:[br/]\n\n            [tt]package:package-name[/tt][br/]\n\n            App Manager inherently does not check for permissions when such requests are directly\n            made to its installer. Therefore, it will attempt to install the requested package\n            directly and fail if there are not enough permissions.[br/]\n\n            Install requests are also allowed to be mixed together. Therefore, a third-party\n            application can combine different URIs (e.g., file, content, package) with the\n            [tt]SEND_MULTIPLE[/tt] action.\n        </note>\n\n        <improve title=\"1-Click ops\">\n            Enabled \"Clear data from uninstalled apps\" to no-root users\n        </improve>\n        <note subtext=\"true\">\n            The option was altered to uninstall the apps a second time instead of attempting to\n            clear data which was faulty. Therefore, it should work with any modes of operation.\n        </note>\n        <improve title=\"App info\">\n            Open \"Open by default\" setting in the \"Open links\" dialog\n        </improve>\n        <note subtext=\"true\">\n            If App Manager does not have enough permission to manage domains or links, the\n            \"Open links\" dialog has a button that directs the user to Android Settings. If the\n            application has the \"Open by default\" page, clicking on the button will open that page\n            instead of the \"App info\" page (which is still used as a fallback method).\n        </note>\n        <improve title=\"Debloater\">Display unsafe bloatware info</improve>\n        <improve title=\"Debloater\">\n            Sort by app label (or app name) rather than package name\n        </improve>\n        <improve title=\"Log viewer\">\n            Activated \"Omit sensitive info\" option by default for new users\n        </improve>\n        <improve title=\"Terminal\">Handled common colors and cursor movements</improve>\n        <improve>Display vector icon on the splash screen in Android 7.1 and earlier</improve>\n        <improve>Enabled predictive back in Android 14 onwards</improve>\n        <improve>\n            Improved accessibility by updating the content description of the action items\n        </improve>\n\n        <fix title=\"App Info\">Fixed freezing an app with \"Remember for this app\" turned on</fix>\n        <fix title=\"App Ops\">\n            Fixed setting app ops in custom ROMs with MIUI properties injected\n        </fix>\n        <fix title=\"Profile\">\n            Fixed updating profile modification status when an application is deleted from the list\n        </fix>\n        <fix>Fixed selecting texts in the list items due to framework bugs</fix>\n\n        <note>\n            [br /][b]Full list of changes:[/b] [a\n            href=\"https://github.com/MuntashirAkon/AppManager/compare/v4.0.4...v4.0.5\"]v4.0.4...v4.0.5[/a]\n        </note>\n    </release>\n    <release\n        type=\"stable release\"\n        version=\"v4.0.4\"\n        code=\"444\"\n        date=\"30 May 2025\">\n        <improve title=\"Main page\">Optimized searching and filtering</improve>\n        <improve>Adopted sentence case for the titles</improve>\n\n        <fix title=\"Profile page\">\n            Use the configured state to execute a profile for simple shortcuts\n        </fix>\n        <fix>Prevented crashing while searching</fix>\n        <fix>Fixed integer overflow in tar compression</fix>\n\n        <note>\n            [br /][b]Full list of changes:[/b] [a\n            href=\"https://github.com/MuntashirAkon/AppManager/compare/v4.0.3...v4.0.4\"]v4.0.3...v4.0.4[/a]\n        </note>\n    </release>\n    <release\n        type=\"stable release\"\n        version=\"v4.0.3\"\n        code=\"443\"\n        date=\"25 April 2025\">\n        <improve>Updated translations</improve>\n        <improve>Improved handling the list items throughout App Manager</improve>\n\n        <fix>Fixed a regression error in file manager</fix>\n        <fix>Fixed spinners in the App Usage and the System Config pages</fix>\n\n        <note>\n            [br /][b]Full list of changes:[/b] [a\n            href=\"https://github.com/MuntashirAkon/AppManager/compare/v4.0.2...v4.0.3\"]v4.0.2...v4.0.3[/a]\n        </note>\n    </release>\n    <release\n        type=\"stable release\"\n        version=\"v4.0.2\"\n        code=\"442\"\n        date=\"28 March 2025\">\n        <improve>Updated bloatware</improve>\n        <note subtext=\"true\">Removed \"Pending\" list as it was removed from ADL.</note>\n\n        <fix>Fixed fetching applications in multi-user environment in no-root mode</fix>\n        <fix>Fixed opening [tt]app-manager[/tt] URLs from the web browsers</fix>\n        <fix>Fixed updating SSAID</fix>\n        <fix>Prevented a crash in Android &lt; 9.0 that occurs due to invalid app ops</fix>\n\n        <note>\n            [br /][b]Full list of changes:[/b] [a\n            href=\"https://github.com/MuntashirAkon/AppManager/compare/v4.0.1...v4.0.2\"]v4.0.1...v4.0.2[/a]\n        </note>\n    </release>\n    <release\n        type=\"stable release\"\n        version=\"v4.0.1\"\n        code=\"441\"\n        date=\"28 February 2025\">\n        <improve>Upgraded to Android 15</improve>\n\n        <title>App Details page</title>\n        <new>Added Overlays tab to display and manage per-app overlays</new>\n        <new>\n            Allow opening the App Details page via [tt]app-manager://details?id=&lt;pkg>&amp;user=&lt;user_id>[/tt]\n        </new>\n        <note subtext=\"true\">\n            The uri is similar to [tt]market://details?id=&lt;pkg>[/tt] in addition to supporting an\n            optional user ID as a query parameter. If user ID is provided but does not exist in\n            system, it does not fall back to the default user ID to avoid inconsistent behavior.\n        </note>\n        <improve>Offer to unfreeze temporarily when launching activity shortcuts</improve>\n        <note subtext=\"true\">\n            If the app corresponding to the shortcut being launched is frozen, offer user to\n            unfreeze the app temporarily so that the shortcut can be launched. The app will be\n            frozen again once the screen is locked. However, this may not work on devices without\n            a screen lock or if the screen is locked some time after the display goes off (possibly\n            due to power management issues).\n        </note>\n\n        <title>App Info tab</title>\n        <new>New tag: Overlay</new>\n        <note subtext=\"true\">\n            Clicking on the tag opens a dialog containing the target package name, label, category,\n            and priority, if available. In the dialog, there is an \"App Info\" button that allows\n            navigating to the App Details page of the target package if it is installed.\n        </note>\n        <improve>Set debloater tag color based on its removal type</improve>\n\n        <title>Debloater</title>\n        <improve>Altered color codes</improve>\n        <note subtext=\"true\">\n            The color codes are improved to make the texts readable in dark mode as well as to\n            facilitate color blind users.[br/]\n            - Green: Safe to delete[br/]\n            - Purple: Replace with alternative[br/]\n            - Orange: Exercise caution.\n        </note>\n        <improve>Updated bloatware and suggestions</improve>\n\n        <title>Installer</title>\n        <improve>Improved text formatting in the \"What's New\" dialog</improve>\n        <fix>Fixed downgrading apps in Android 10 onwards</fix>\n        <fix>Fixed installer issues in the Huawei stock operating systems</fix>\n\n\n        <title>UI Tracker</title>\n        <fix>Fixed clicking on the icon after it is iconified</fix>\n\n        <title>Others</title>\n        <improve>Avoided waiting for the remote server to respond when no-root mode is set</improve>\n        <note subtext=\"true\">\n            If a remote server is running in the background but the mode of operations in App\n            Manager is set to \"no-root\", it will directly launch in no-root mode instead of waiting\n            for a response from the remote server.\n        </note>\n        <improve>Improve query highlighting</improve>\n        <note subtext=\"true\">\n            Instead of red, which is used in the texts, a variant of yellow (canary) is used for\n            highlighting texts in the light mode and a variant of brown (domino) is used for\n            highlighting texts in the dark mode.\n        </note>\n        <improve>Use green instead of dark cyan for \"success\"-related operations</improve>\n\n        <note>\n            [br /][b]Full list of changes:[/b] [a\n            href=\"https://github.com/MuntashirAkon/AppManager/compare/v4.0.0...v4.0.1\"]v4.0.0...v4.0.1[/a]\n        </note>\n    </release>\n    <release\n        type=\"stable release\"\n        version=\"v4.0.0\"\n        code=\"440\"\n        date=\"10 February 2025\">\n        <note subtext=\"true\">\n            Private messages should be emailed to am4android@riseup.net. Emails sent to any other\n            email addresses shall be discarded.\n        </note>\n        <note subtext=\"true\">If you're running ADB, you may need to restart your device first.</note>\n\n        <new>New logo for App Manager!</new>\n        <new>A dedicated page for debloating the phone</new>\n        <note subtext=\"true\">\n            Debloating profiles were available as “Presets” in the Profiles page which has now been\n            replaced with the Debloater page which can be accessed from the three-dots menu in the\n            Main page. [a href=\"https://github.com/MuntashirAkon/android-debloat-list\"]ADL[/a] is a\n            new project focused on maintaining a list of bloatware as well as potential open source\n            alternatives.[br /][br /]\n\n            Color codes for the list:[br /]\n            - Dark cyan: The app is safe to remove. It does not necessarily mean that the app should\n            be removed as it is always up to the user[br /]\n            - Sand color: The app is safe to remove, but removing it might break one or more\n            features[br /]\n            - Orange: The app may or may not be safe to remove[br /]\n            - Red: The app is not safe to remove.[br /]\n            [br /]\n\n            Batch operations:[br /]\n            - Uninstallation[br /]\n            - Enable/disable[br /]\n            - Save APK[br /]\n            - Create new profile[br /]\n            - Add to profile.[br /]\n            [br /]\n\n            On clicking an item, the following information are displayed with:[br /]\n            - App icon (valid only when the app is installed)[br /]\n            - App label[br /]\n            - Package name[br /]\n            - App info button (if the app is installed)[br /]\n            - Tags[br /]\n            - Warning (if available)[br /]\n            - Description with references[br /]\n            - Dependencies[br /]\n            - Suggestions/alternatives.[br /]\n            [br /]\n\n            In addition to the typical search option, there are several filtering options available\n            in this page:[br /]\n            1. Categories: AOSP, OEM, Carrier/ISP, Google, Miscellany, and Pending[br /]\n            2. Types: Safe (i.e., safe to remove), Replace (i.e., should be replaced with\n            alternatives), Caution (i.e., generally safe to remove but no guarantees), Unsafe (may\n            cause bootloop)[br /]\n            3. Other: User apps, System apps (mutually exclusive), Installed apps and Uninstalled\n            apps (mutually exclusive).\n        </note>\n        <new>An (almost) fully-featured File Manager</new>\n        <note subtext=\"true\">\n            Features:[br/]\n            - Thumbnail previews for media files, pictures, PDFs, ePubs, OpenDocument files, APK,\n            APKM, APKS, XAPK, J2ME JAR files[br/]\n            - Sorting options: name, size, and last modification date with folders on top[br/]\n            - Filtering options: toggle dot files[br/]\n            - File operations: copy, cut, rename, delete[br/]\n            - New folders, links, and empty files, such as text files, PDF, documents (docx/odt),\n            sheet (xlsx/ods), presentation (pptx, odp), and SQLite3 database[br/]\n            - Opening folders from third-party apps[br/]\n            - Path navigation to easily navigate to different locations[br/]\n            - Batch operations: file operations and sharing[br/]\n            - Other operations: sharing, creating shortcuts, open with[br/]\n            - Settings: set default home directory, remember last opened folder and position, and\n            whether to display the file manager as “Files” in the app drawer[br/]\n            - Displaying file/folder properties.[br/]\n            - Favorites (i.e., bookmarks).\n        </note>\n        <new>Integrated code editor</new>\n        <note subtext=\"true\">\n            Manifest and code viewers have been replaced with this new editor. Among other regular\n            features, it includes proper syntax highlighting and advanced searching options. In\n            addition, files from third-party apps can also be opened for editing.\n        </note>\n        <new>New widget: Data usage</new>\n        <note subtext=\"true\">Display total download and upload speed for today.</note>\n        <new>Added options for runtime optimization in Android 7 or later</new>\n        <note subtext=\"true\">\n            This option is available for all apps in the 1-click ops page and individual app in the\n            three-dots menu in the app info tab.[br /][br /]\n\n            Features:[br /]\n            - Set Compile filters, such as speed-profile or everything-profile[br /]\n            - Compile layout resources[br /]\n            - Immediate optimization of DEX, i.e., somewhat similar to [tt]pm force-dex-opt[/tt]\n        </note>\n        <new>Save install, batch and profile operations to history</new>\n        <note subtext=\"true\">\n            Each history entry remembers everything necessary to allow it to be re-executed.\n            However, any re-execution attempt may still fail for the following reasons:[br/]\n            1. The history entry has certain apps requirements that are no longer installed[br/]\n            2. The history entry may rely on external files that are no loner available or\n            accessible to App Manager[br/]\n            3. The privilege has changed (e.g., previously it was executed with root but now\n            no-root)[br/]\n            4. The operating system no longer supports the functions[br/]\n            5. App Manager no longer allows the operation.[br/][br/]\n\n            When a profile is re-executed from history, it preserves the same applications and\n            configurations used at that point in time in order to ensure the consistency of\n            operation.\n        </note>\n        <new>Replaced log viewer, sys config, Terminal, etc. with Labs page</new>\n        <note subtext=\"true\">\n            Labs is a new page where various handy tools are listed. They include Sys Config,\n            Log Viewer, Terminal (not an actual Terminal emulator), File Manager, UI Tracker,\n            Interceptor, History, and Code Editor.\n        </note>\n\n        <!-- 1-Click Ops page -->\n        <title type=\"medium\">1-Click Ops page</title>\n        <new>\n            Added option to uninstall apps that were previously uninstalled without clearing data.\n        </new>\n        <improve>Replace “Block components…” with “Block/unblock components…”</improve>\n        <note subtext=\"true\">Components can also be unblocked using the option.</note>\n\n        <!-- App Details page -->\n        <title type=\"medium\">App Details page</title>\n        <new>Allowed launching non-exported activities in no-root/ADB mode</new>\n        <note subtext=\"true\">\n            The “Search assistant” (usually set to Google Assistant) feature allows setting\n            arbitrary activity via the [tt]assistant[/tt] key-value pair stored in the secure\n            settings database. Hence, non-exported (that is, app private) activities can be launched\n            even in no-root mode by exploiting this feature. However, modifying a secure setting\n            require [tt]android.permission.WRITE_SECURE_SETTINGS[/tt] permission which is granted\n            automatically in ADB mode and has to be granted manually in no-root mode via ADB.[br /]\n\n            App Manager also cannot trigger the assistant on its own in the no-root mode, because it\n            doesn't have enough permissions (it requires [tt]android.permission.INEJECT_EVENTS[/tt]\n            permission which cannot be granted to the user applications). Activity shortcuts also\n            use this feature when they cannot be launched in privileged mode.\n        </note>\n        <improve>Display blocking method in the components tabs</improve>\n        <note subtext=\"true\">\n            IFW+Dis = The component is blocked using both IFW and disable[br /]\n            IFW = The component is blocked using IFW[br /]\n            Dis = The component is disabled.\n        </note>\n        <improve>Improved loading performance</improve>\n        <fix title=\"App Ops\">Prevented crashes in Samsung devices running Android 6.0.1</fix>\n        <fix>Disabled “IFW” and “IFW+Disable” in the providers tab</fix>\n        <note subtext=\"true\">\n            In Rules settings, the description for “Default blocking method” was also updated with a\n            note that says IFW feature does not work with providers, “disable” is used for them\n            instead.\n        </note>\n        <fix>Fixed applying IFW method in the components tabs</fix>\n        <note subtext=\"true\">\n            Fixed applying IFW rules if the previous rules were “IFW+Disable” or “Disable”.\n        </note>\n        <fix>Fixed setting mode for some app ops</fix>\n        <note subtext=\"true\">\n            In the app ops tab, the toggle button as well as the long click options attempts to\n            alter the associated permission too if it exists. [u]To bypass this behaviour, use\n            “Set custom app op” from the three-dots menu instead.[/u]\n        </note>\n\n        <!-- App Info tab -->\n        <title type=\"medium\">App Info tab</title>\n        <new>Added option to enable/disable sensors</new>\n        <new>New tag: Bloatware</new>\n        <note subtext=\"true\">\n            Clicking on the tag opens a dialog containing description, dependencies, alternatives,\n            etc. like in the Debloater page.\n        </note>\n        <new>New tag: Open links</new>\n        <note subtext=\"true\">\n            “Open links” is displayed for apps capable of opening links from the verified domains\n            without any user intervention. This feature, added in Android 12, has raised privacy as\n            well as usability concerns, because it promotes tracking and reduce user's freedom of\n            choice. Therefore, in active state, that is, when the app is able to open the links\n            directly, this tag will have a “red” background (otherwise, it will have a “green”\n            background).[br /][br /]\n\n            On clicking the tag, a list of supported domains will be displayed in a dialog (although\n            not all domains can be opened by default). If the user has enough permissions, an option\n            to enable/disable the behaviour will be displayed. Otherwise, an option to open the app\n            details page in the Android Settings app will be displayed.\n        </note>\n        <new>New tag: Sensors disabled</new>\n        <note subtext=\"true\">\n            System may misreport this permission. The best way to check if sensors are indeed\n            disabled is by opening the app first and then visiting the App Info tab leaving the\n            other app running in the background.\n        </note>\n        <new>New tag: Static shared library</new>\n        <note subtext=\"true\">\n            The tag is displayed for static shared libraries, that is, the apps with\n            [tt]static-library[/tt] tag in their manifest files, requires root or ADB. Clicking on\n            the tag displays a dialog with a list of libraries installed under the same package\n            name, and offer the user to uninstall the selected libraries.\n        </note>\n        <new>New tag: Xposed</new>\n        <note subtext=\"true\">\n            Clicking on the tag opens a dialog with more details:[br /]\n            1. Module name[br /]\n            2. Description[br /]\n            3. Type of module (modern or legacy)[br /]\n            4. Xposed API dependency info[br /]\n            5. Scope (if available statically).\n        </note>\n        <improve>Added an option to create a new profile in the “Add to profile” dialog</improve>\n        <improve>Avoid listing split APKs “Paths &amp; Directories” section</improve>\n        <note subtext=\"true\">\n            Split APK info are already displayed in the corresponding tags above this section. There\n            is no reason to display them again.\n        </note>\n        <improve>Display detailed installer info</improve>\n        <note subtext=\"true\">\n            An info button is added next to the installer which displays the installer, the actual\n            installer (AKA initiator), and the APK source (originator). Clicking on each item opens\n            the corresponding App Details page. It also fixed displaying the installer app in\n            certain devices.\n        </note>\n        <improve>Improved performance by loading UI contents in the background</improve>\n        <improve>Hide data usage for other users</improve>\n        <note subtext=\"true\">\n            Data usage section is hidden if the following conditions are true:[br /]\n            1. OS is Android 6.0 onwards[br /]\n            2. The app does not belong to the current user, and[br /]\n            3. Self or remote UID is not system UID.\n        </note>\n        <improve>Hide “Data usage” for apps without the internet permission</improve>\n        <improve>List SAF files and directories in a user-friendly manner</improve>\n        <note subtext=\"true\">\n            Instead of a raw representation of the granted URI, display authority, type of file or\n            folder, and the file or folder itself in a meaningful way. It also attempts to retrieve\n            the original file path when possible.\n        </note>\n        <fix>Fixed displaying wrong information regarding blocked trackers</fix>\n        <fix>Fixed handling multiple users in no-root mode</fix>\n        <fix>Prevented crashes in tablets running buggy GSI firmware</fix>\n        <fix>\n            Prevented the app from crashing on attempting to enable battery optimisation of\n            restricted apps\n        </fix>\n        <note subtext=\"true\">\n            Battery optimisation cannot be enabled for system restricted apps.\n        </note>\n        <fix>Use the configured naming format when sharing an APK(S)</fix>\n\n        <!-- App Usage page -->\n        <title type=\"medium\">App Usage page</title>\n        <improve>Improve the \"Usage Widget\"</improve>\n        <note subtext=\"true\">\n            - Replaced old colors with the new ones[br/]\n            - Fixed padding issues in Android 12 onwards[br/]\n            - Set an upper limit for the widget (350dpx450dp)[br/]\n            - Utilized the dynamic text sizing on Android Oreo onwards[br/]\n            - Use secondary colors instead of the default colors for labels[br/]\n            - Use dynamic colors if available[br/]\n            - Hide bubbles/circles if available apps is &lt; 3[br/]\n            - Added a refresh button[br/]\n            - Support automatic switching between light and dark mode[br/]\n            - Added a dark theme preview.\n        </note>\n        <improve>Improve the usage time calculation method</improve>\n        <note subtext=\"true\">\n            The usage events returned by the [tt]UsageStatsManager[/tt] were assumed to be in order\n            of their timestamp which does not seem to be true and resulted in missing a few events\n            due to the standard calculation method, that is, calculating the time difference between\n            activity resume and pause timestamps. In addition, it appears that the system may log\n            activity stop timestamp without logging any pause timestamp (a typical activity cycle\n            would be resume → pause → stop → resume → …) causing further miss of events. These\n            issues were addressed by sorting the events in order of their timestamp as well as\n            measure the time difference between resume and stop timestamps instead of resume and\n            pause timestamps.\n        </note>\n        <improve>Fetch data usage for all apps in Android 5 and 5.1</improve>\n        <improve>Fetch usage stats and package size info only when the feature is enabled</improve>\n        <improve>Make the combo-box (spinner) static on top</improve>\n        <improve>Reduced lags by recycling views</improve>\n        <fix>Fixed retrieving mobile data usage in Android 12 and earlier</fix>\n        <fix>Fixed the “times opened” value</fix>\n        <note subtext=\"true\">\n            In order to calculate a more reliable number of times an app was opened, the time\n            difference between each activity opening and closing are now relaxed. So, when the user\n            navigates to another activity from an activity belonging to the same app and the time\n            difference is less than 500 ms, the time difference is added to the total usage time.\n            This calculation is technically more precise than the system's own open count because\n            certain navigation involves the use of system UI (e.g., the arrow in the gesture\n            navigation is emitted from the System UI app and should be considered as such) which are\n            ignored. However, the issues with choosing 500 ms (half of a second) time difference are\n            as follows:[br /]\n            1. Due to an user waiting a long time to trigger the back gesture or simply bad coding,\n            an app may take more than this time to open an activity which will cause them to be\n            listed as two accesses.[br /]\n            2. Some apps support multiple windows. If the user opens another activity in a new\n            window shortly after opening the first activity, the two accesses may be counted as one\n            instead of two.[br /]\n            These events are considered extraordinary and can be negligible in a real-life setting.\n        </note>\n        <fix>Take device shutdowns into account while calculating app usage</fix>\n\n        <!-- Backup/restore -->\n        <title type=\"medium\">Backup/restore</title>\n        <new>Enable experimental support for Zstandard (ZSTD) compression</new>\n        <improve>Display backup extras and rules in no-root mode</improve>\n        <improve>Improved handling custom users in backups</improve>\n        <note subtext=\"true\">\n            - Properly handle backup/restore for a single app. “Custom users” in the backup options\n            is displayed only if the app is installed for multiple users. Similarly, cross-user\n            restore is supported via the “Custom users” option. In addition, fixed issues causing\n            the backup or restore to be performed for the wrong users.[br /]\n            - Unless the “Custom users” option is selected, backup or restore is made only for the\n            current user in the batch selection mode. Others retain the old behaviour. For example,\n            in the batch selection mode, restore is only made with the “base” backup which is\n            defined to be the primary backup for the current user. So, if “Custom users” option is\n            selected for restore operation, App Manager will try to find the base backup of each\n            selected user and restore those for that user.[br /][br /]\n            These behaviours are applied throughout the app to reduce complexity and remove\n            any ambiguous behaviour.\n        </note>\n        <improve>Log the reason for a failed APK installation during restore</improve>\n        <fix>Alphanumerically sort app data to prevent restoring issue</fix>\n        <fix>Fixed creating custom backups</fix>\n        <note subtext=\"true\">\n            When custom backups are enabled but the backup name is empty, create a custom backup\n            with the current date and time instead of creating a base backup.\n        </note>\n        <fix>Fixed the “cache” “no cache” confusion in the backup flags selection dialog</fix>\n        <note subtext=\"true\">\n            The “No cache” flag was replaced by the “cache” flag, but the translations still use the\n            former. So, the string ID is altered to invalidate the translations.\n        </note>\n\n        <!-- Explorer -->\n        <title type=\"medium\">Explorer</title>\n        <improve>Avoided decoding AXML files</improve>\n        <note subtext=\"true\">Decoding should be done by code editors, not explorers.</note>\n        <improve>Specially handle APK files to prevent parsing errors</improve>\n        <fix>Fixed opening files with external editor/viewer</fix>\n\n        <!-- Freeze/unfreeze -->\n        <title type=\"medium\">Freeze/unfreeze</title>\n        <new>New freeze option: Advanced suspend</new>\n        <note subtext=\"true\">\n            Allows an app to be both force-stopped and suspended to prevent it from running in the\n            background.\n        </note>\n        <improve>Added curated freeze method selection option</improve>\n        <note subtext=\"true\">\n            Apart from selecting a default freeze method in the Settings page, it is also\n            possible to do the following:[br /]\n            - Set per-app freeze method. This allows setting a non-default freeze for each app. The\n            option can be accessed by clicking the \"Freeze\" button in the App Info tab of an app.\n            The per-app freeze method will also be backed up and restored as part of the \"Extras\"\n            backup flag.[br/]\n            - Set per-operation freeze method. All freeze-related batch operations (in the Main and\n            Debloater pages) and the \"Freeze\" option in App Info tab display a dialog button that\n            allows a user to choose a non-default, per-operation freeze method.\n        </note>\n        <fix>Prevented the app from crashing if a shortcut icon is immutable</fix>\n\n        <!-- Installer -->\n        <title type=\"medium\">Installer</title>\n        <new>Added an option to perform DEX optimisation immediately after installing an app</new>\n        <new>Added the ability to modify installer options before installing an app</new>\n        <note subtext=\"true\">\n            In the installation dialog, clicking on the settings/cog icon opens a new dialog where\n            the installer options can be temporarily set for the session. Any items queued for the\n            session will retain those temporary options.\n        </note>\n        <new>Added the option to align APK files before signing</new>\n        <note subtext=\"true\">\n            When APK signing is enabled, enabling this option will ensure that the contents of the\n            APK are aligned properly before the APK is signed. Since it doesn't modify the contents\n            of the APK, the option is enabled by default.\n        </note>\n        <improve>Accelerate the installation process in Android 12 onwards when possible</improve>\n        <note subtext=\"true\">\n            If an app is being installed in the foreground, App Manager will try to accelerate the\n            installation process by delaying various post-installation tasks carried out by the\n            system services.\n        </note>\n        <improve>Display installation progress in the notification</improve>\n        <note subtext=\"true\">\n            In some devices such as Samsung, it takes an indefinite amount of time to verify the app\n            after copying the APK files. For those cases, the progress won't be accurate as it only\n            takes into account the amount of time to copy the files.\n        </note>\n        <improve>\n            Display “Confirm install” notification even if the app is running in foreground\n        </improve>\n        <note subtext=\"true\">\n            In no-root mode, when the app is running in foreground, the user may accidentally\n            dismiss the install-confirmation dialog produced by the Android package installer which\n            would either allow the installation to run forever or for a minute until the timeout\n            occurs. To solve the issue, a silent notification is triggered at the same time the\n            dialog is shown so that even if the user accidentally dismisses the dialog, the dialog\n            can still be displayed by clicking the notification.\n        </note>\n        <improve>Enabled installing system apps with a different signature</improve>\n        <note subtext=\"true\">\n            The “Install only” button is enabled for system apps when the signatures are different.\n            This is useful for only those who have disabled signature verification using methods,\n            such as CorePatch.\n        </note>\n        <improve>\n            Enabled opening the App Details page of an app installed by App Manager from Android\n            Setting's App Info page.\n        </improve>\n        <improve>\n            Properly handle the originating URI extra supplied by third-party apps via\n            [tt]Intent.EXTRA_ORIGINATING_URI[/tt]\n        </improve>\n        <improve>Set originating package in Android 7 onwards</improve>\n        <note subtext=\"true\">\n            The originating package is automatically determined from the Intent sent from the\n            third-party apps. However, the determination logic may not always work, but it was\n            ensured that there will not be any false positives, e.g., no spoofing can be done by a\n            third-party app.\n        </note>\n        <improve>\n            Set package source to [tt]PACKAGE_SOURCE_OTHER[/tt] by default in Android 13 onwards\n        </improve>\n        <note subtext=\"true\">\n            This is done to prevent the system from applying various accessibility restrictions to\n            the app. However, [tt]PACKAGE_SOURCE_STORE[/tt] is set by default if the originating\n            package is one of the supported app stores. At present, the supported app stores are:\n            Aurora Store, Droid-ify, F-Droid, F-Droid Basic, F-Droid Classic and Neo Store. It is up\n            to the developers to ensure that they send the APK installation requests in a proper\n            way, i.e., by utilizing features such as [tt]startActivityForResult[/tt] whenever\n            possible.\n        </note>\n        <fix>Added workaround for updating system apps in HyperOS 2.0</fix>\n        <note subtext=\"true\">\n            If [tt]INSTALL_FAILED_HYPEROS_ISOLATION_VIOLATION[/tt] is triggered in the privileged\n            mode, the installer will try again with the installer set to [tt]com.android.shell[/tt].\n        </note>\n        <fix>\n            Fixed displaying re-installation prompt for apps that were uninstalled without clearing\n            data\n        </fix>\n        <fix>Fixed installing APK files queued in the background</fix>\n        <fix>Fixed installing some signed APK files</fix>\n        <note subtext=\"true\">Some signed APKs could not be installed due size mismatch.</note>\n        <fix>Fixed parsing unsigned APK files</fix>\n        <fix>Fixed installing apps for users other than the main profile</fix>\n\n        <!-- Interceptor -->\n        <title type=\"medium\">Interceptor</title>\n        <improve>Added a few intent filters related to camera</improve>\n        <improve>Intercept SAF, dialer, gallery, search, music player, and WhatsApp URLs</improve>\n        <fix>Fixed retrieving matching activities when a default is set</fix>\n        <fix>\n            Prevented the app from crashing when creating a shortcut with invalid extras or icon\n        </fix>\n        <note subtext=\"true\">\n            Shortcuts support only 11 types of data structures. Intents, on the other hand, support\n            any type of data structures. When a shortcut creation is requested, the unsupported data\n            structures are removed from the Intent to avoid crashes.\n        </note>\n\n        <!-- Log Viewer -->\n        <title type=\"medium\">Log Viewer</title>\n        <new>Added a batch option to copy the selected logs</new>\n        <improve>Changed list selection modes.</improve>\n        <note subtext=\"true\">\n            1. Normal mode[br /]\n            - Click: expand/collapse text[br /]\n            - Long click: Open context menu[br /]\n            2. Selection mode[br /]\n            - Click: Select clicked item[br /]\n            - Long click: Select items between the last selected item to the clicked\n            item if possible. Otherwise, only click the item.\n        </note>\n        <improve>Improve searching and filtering</improve>\n        <note subtext=\"true\">\n            logcat has been migrated to [tt]threadtime[/tt] format from [tt]time[/tt] with backward\n            compatibility. Searching now supports Android Studio conventions:[br/]\n            - Supported keywords are: [tt]msg[/tt], [tt]pid[/tt], [tt]pkg[/tt], [tt]tag[/tt], and\n            [tt]uid[/tt]. Any other non-keyword filtering are matched against the log messages\n            (e.g., they are appended to the [tt]msg[/tt] tag). [tt]uid[/tt] is only supported in\n            Android 7 and later[br/]\n            - Each keyword takes the intended arguments followed by a [tt]:[/tt] (colon) (e.g.,\n            [tt]pid:1[/tt] denotes filtering all the logs produced by the PID 1)[br/]\n            - All keywords are [tt]and[/tt]'ed together (e.g., [tt]pid:1651 tag:Ime[/tt] means\n            filtering all the logs with the tag containing [tt]Ime[/tt] belonging to the PID 1651)\n            [br/]\n            - Adding a [tt]-[/tt] (minus) before a keyword denotes exclusion (e.g.,\n            [tt]-pid:13[/tt] denotes listing all logs except PID 13)[br/]\n            - Adding a [tt]~[/tt] (tilde) sign before [tt]:[/tt] (colon) denotes a regular\n            expression match[br/]\n            - Adding a [tt]=[/tt] (equal) sign before [tt]:[/tt] (colon) denotes an exact match\n            (e.g., [tt]tag:Ime[/tt] filters any logs with a tag containing the string [tt]Ime[/tt]\n            whereas [tt]tag=:Ime[/tt] filters any logs with a tag that is equal to [tt]Ime[/tt]).\n            [tt]pid[/tt] and [tt]uid[/tt] keyword always do an exact match unless it is a string\n            or regular expression.[br/]\n            - [tt]~[/tt] (tilde) and [tt]=[/tt] (equal) signs are mutually exclusive with [tt]~[/tt]\n            (tilde) preferred over [tt]=[/tt] (equal), i.e., when both signs are present, only\n            [tt]~[/tt] (tilde) sign is used for regular expression matching[br/]\n            - Non-exact and non-regex filters are always case insensitive.\n        </note>\n\n        <!-- Main page -->\n        <title type=\"medium\">Main page</title>\n        <new>Added a new filtering option “Stopped apps“ to filter the force-stopped apps</new>\n        <new>Added filtering by users in the list options</new>\n        <new title=\"Batch Ops\">\n            Added a new batch operation “Optimise” to dex optimisation of the selected apps\n        </new>\n        <new title=\"Batch Ops\">Added an option to export app list as CSV and JSON</new>\n        <improve>\n            Avoided reopening the keyboard while searching is active, but the keyboard was closed\n            manually\n        </improve>\n        <improve title=\"Batch Ops\">\n            Added an option to create a new profile in the “Add to profile” dialog\n        </improve>\n        <improve title=\"Batch Ops\">\n            Display configured net policy if only one app is selected\n        </improve>\n        <improve>\n            Display a prompt to fully uninstall apps that were uninstalled without clearing data\n        </improve>\n        <improve>Display restore dialog for uninstalled apps with backups</improve>\n        <note subtext=\"true\">\n            Instead of displaying “App not installed” toast for the uninstalled apps with backups,\n            open the restore dialog instead when clicking on such an item in the Main page.\n        </note>\n        <improve>Display static libraries in privileged mode</improve>\n        <note subtext=\"true\">\n            Static libraries such as Trichrome Library are only visible to system, shell, root and\n            the apps which depend on it. Using privileged mode, it is possible to list them in the\n            Main as well as perform typical operations on them.[br /][br /]\n\n            For non-rooted users, these libraries are only visible in the “Shared Libs” tab (in App\n            Details page) of the apps that depend on them.\n        </note>\n        <improve>Display user count alongside app ID</improve>\n        <note subtext=\"true\">\n            If an app is installed in more than one profiles (that is, for multiple users), instead\n            of displaying only the kernel user ID (UID), display the app ID (i.e., UID sans the user\n            ID) and user count in the following format:[br /][br /]\n\n            [tt]&amp;lt;user count&amp;gt;+&amp;lt;app ID&amp;gt;[/tt]\n        </note>\n        <fix>\n            Fixed retrieving applications when there are too many applications installed on the\n            device\n        </fix>\n        <fix title=\"Batch ops\">Fixed saving APKS with dependencies</fix>\n        <fix title=\"Batch Ops\">Fixed saving some APK files due to naming issues</fix>\n        <fix>Prevented crashes when the installer feature is disabled</fix>\n\n        <!-- Profile page -->\n        <title type=\"medium\">Profile page</title>\n        <new>Added an option to copy profile ID</new>\n        <improve>Display app op names instead of number in the profiles page</improve>\n        <improve>Display exit confirmation dialog if there are unsaved changes</improve>\n        <improve>Display previously selected apps on top of the app list</improve>\n        <improve>Display warning before deleting a profile</improve>\n        <fix>Avoid creating duplicate profiles by auto-renaming the newly-created profile</fix>\n        <fix>Fixed displaying backup options in configurations tab</fix>\n        <fix>Fixed loading label after refreshing the app list</fix>\n\n        <!-- Profiles page -->\n        <title type=\"medium\">Profiles page</title>\n        <new>Added an option to copy profile ID</new>\n        <new>Use profile ID instead of profile name for identifying each profile</new>\n        <note subtext=\"true\">\n            In profile version 1, there's no difference between profile name and profile ID. But from profile version 2,\n            a new field [tt]id[/tt] shall be introduced which will be decoupled profile name from its ID, making it\n            possible to use any name for profile or rename it. [u]If you use automation, make sure to use profile ID\n            instead of profile name.[/u]\n        </note>\n        <improve>Auto-select the configured profile state in “Apply profile” dialog</improve>\n        <improve>\n            Avoid displaying a completion notification when a profile triggered through automation\n        </improve>\n        <improve>Handled applying multiple profiles using a queue</improve>\n        <improve>Moved shortcut handling logic to a different activity</improve>\n        <note subtext=\"true\">\n            To avoid opening existing tasks from Recents, shortcuts are handled in a separate task.\n        </note>\n        <improve>Optimised updating new or modified profile information</improve>\n        <fix>Fixed applying profiles</fix>\n\n        <!-- Running Apps page -->\n        <title type=\"medium\">Running Apps page</title>\n        <improve>Display available memory</improve>\n        <note subtext=\"true\">\n            According to Linux's [tt]meminfo[/tt] specs, \"available memory\" is the amount of memory\n            the kernel can allocate to a new process whereas \"free memory\" denotes the amount of\n            memory not utilized by the kernel.\n        </note>\n        <improve>Refresh running apps every 10 seconds</improve>\n        <fix>Fixed listing processes when some PIDs no longer exist</fix>\n\n        <!-- Scanner -->\n        <title type=\"medium\">Scanner</title>\n        <new>Display link to Pithus report if available</new>\n        <improve>Calculate file hashes more efficiently</improve>\n        <improve>Migrate to VirusTotal v3 API</improve>\n        <note subtext=\"true\">\n            Allows uploading a single file with size up to 650 MB (compared to only 32 MB in API v2\n            in the free plan)\n        </note>\n        <fix>Fixed scanning external APK files in privileged mode</fix>\n\n        <!-- Security -->\n        <title type=\"medium\">Security</title>\n        <improve>\n            Check for zip-slip vulnerability before creating a folder or a symbolic link\n        </improve>\n        <improve>Disabled access to [tt]content://[/tt] in WebView</improve>\n        <improve>Improved security of the shortcuts created within App Manager</improve>\n        <note subtext=\"true\">\n            Earlier, opening the shortcuts of exportable activities did not require any\n            authentication. From now on, authentication is required for opening any new shortcuts.\n        </note>\n        <improve>Only allow connections from supported online locations</improve>\n        <note subtext=\"true\">\n            To avoid issues with ADB, localhost is allowed unrestricted connections, but other\n            websites, namely virustotal.com and pithus.org, are restricted via SSL pinning using\n            network security configuration.\n        </note>\n        <improve>Sanitize user inputs, intents when it involves files and filenames</improve>\n        <improve>Use formatted string for logging to prevent log injections</improve>\n\n        <!-- Settings page -->\n        <title type=\"medium\">Settings page</title>\n        <new>Added options to run App Manager in the background</new>\n        <note subtext=\"true\">\n            In Settings > Privacy, two new options have been added:[br /]\n            1. Run App Manager in the background[br /]\n            2. Automatic lockdown[br /]\n            [br /]\n\n            Running App Manager in the background makes the annoying “Initializing” screen go away.\n            Due to possible privacy issues, this option is disabled by default. When automatic\n            lockdown is enabled, App Manager will attempt to lock the app by killing its process.\n            As expected, there are several side effects:[br /]\n            1. All the activities will be closed. They'll be reopened by the system based on how the\n            user was interacting with them[br /]\n            2. All the running operations as well as scheduled or running jobs will be stopped\n            immediately. This might cause data loss if potentially destructive operations are\n            running.[br /][br /]\n\n            Note: Enabling the latter option does not wipe the memory of App Manager, i.e., it does\n            not prevent a forensic software from scrapping the memory used by App Manager even if\n            the process no longer exists.\n        </note>\n        <new>Added option to disable sending notification to the connected devices</new>\n        <note subtext=\"true\">\n            The setting is located at [a href=\"app-manager://settings/advanced_prefs\"]Settings >\n            Advanced > Send notifications to the connected devices[/a] and is enabled by default.\n            Low importance notifications, e.g., ongoing notifications and optional alerts, won't be\n            delivered to the connected devices even if the setting is enabled.\n        </note>\n        <new>Added support for pure black theme</new>\n        <new>Support running custom command for mode of ops</new>\n        <improve>Added a fallback server runner command from DE storage</improve>\n        <note subtext=\"true\">\n            Added a fallback server runner command in case SD card is inaccessible from the UID from\n            which the script is being run. This leverages the device encrypted storage (data_de) by\n            making certain folder and files globally accessible.\n        </note>\n        <improve>Avoided auto-detecting ADB port number if Wi-Fi is inactive</improve>\n        <improve>Display ADB pairing dialog directly when a pairing may be required</improve>\n        <improve>Improved \"About the device\" dialog</improve>\n        <note subtext=\"true\">\n            Display build number, graphics model, Vulkan version, battery technology, estimated\n            battery capacity (which is the real battery capacity), battery health, battery cycle\n            count (in Android 14 onwards), dm-verity, verified boot, AVB version, bootloader\n            lock/unlock state (only when AVB is enabled), debuggable OS, Android KeyStore features,\n            encryption algorithms supported by the hardware- and the StrongBox-backed keystore.\n        </note>\n        <improve>Improved auto-connecting to ADB</improve>\n        <note subtext=\"true\">\n            - When mode is set to auto, instead of checking the active ADB host and port first, the\n            status of the ADB daemon is checked[br /]\n            - When mode is set to “Wireless debugging”, developer settings and wireless debugging\n            are enabled automatically before attempting any connections. This requires:[br /]\n            1. [tt]android.permission.WRITE_SECURE_SETTINGS[/tt] to be granted to App Manager, OR[br /]\n            2. App Manager connected via root or ADB at least once (in which case, the permission\n            above is granted automatically)[br /]\n            - Attempt to fetch the current port for ADB over TCP via [tt]service.adb.tcp.port[/tt]\n            property instead of using the default [tt]5555[/tt] port or the previously saved value.\n        </note>\n        <improve>Improved preferences and dialogs</improve>\n        <note subtext=\"true\">\n            - Added a dedicated page for VirusTotal[br /]\n            - Added a dedicated page for mode of operations[br /]\n            - Moved “Use the Internet” to Privacy settings[br /]\n            - Added feature toggler for Log Viewer and Installer[br /]\n            - Display build expiry and funding campaign notices only in the main settings[br /]\n            - Replace “Remove all rules” with a primary button[br /]\n            - Input boxes are focused by default[br /]\n            - For numeric inputs, only the numeric keyboard is displayed[br /]\n            - Input texts aren't added to the user suggestions.\n        </note>\n        <improve>Pair ADB via notification</improve>\n        <improve>Renamed “Layout orientation” to “Layout direction”</improve>\n        <improve>Use dual-pane layout for large displays</improve>\n        <fix>Avoided displaying “Imported” for Watt and Blocker when nothing is selected</fix>\n        <fix>\n            Check if the selected directory is actually a directory before attempting to import a\n            backup\n        </fix>\n        <fix>Fixed displaying custom commands in the mode of ops page</fix>\n        <fix>\n            Fixed displaying wireless debugging options when App Manager is unable to enable\n            Wireless Debugging\n        </fix>\n        <fix>Fixed navigating one step back after a device configuration is changed</fix>\n        <fix>Fixed saving backup options</fix>\n        <fix>Fixed the title for the Mode of Ops settings page</fix>\n        <fix>Prevented a crash that occurs on importing the rules if some of them are invalid</fix>\n\n        <!-- UI -->\n        <title type=\"medium\">UI</title>\n        <improve>\n            Better handling of application-wide notifications including the progress of various\n            operations\n        </improve>\n        <improve>\n            Display all multi-selection options in a single row with an overflow menu at the end\n        </improve>\n        <improve>Display icons in popup menus</improve>\n        <improve>\n            Display shortcut editor before creating a shortcut along with a preview panel\n        </improve>\n        <improve>Draw activities around the display cutouts</improve>\n        <improve>Improved layouts of popup and dropdown menus</improve>\n        <improve>\n            Tint combo-boxes in primary container color to match Android 12+ styles\n        </improve>\n        <improve>Used circular progress for initialization</improve>\n        <fix>Fixed styling some popup menus</fix>\n\n        <!-- UI Tracker -->\n        <title type=\"medium\">UI Tracker</title>\n        <improve>Added the ability to drag the icon when iconified</improve>\n        <improve>Added the ability to drag the window outside the visible display</improve>\n        <improve>Display current activity name when possible</improve>\n        <note subtext=\"true\">\n            In addition to displaying the class name and its hierarchies, the window will display\n            the activity name if there's is an activity (not all windows are activities). This\n            requires the usage stats permission which is enforced here even if it's disabled in the\n            settings. This is because this feature is meant to be used as a useful tool separated\n            from the rest of the app, but with some level of integration.\n        </note>\n        <fix>Fixed freezing issues in certain devices (e.g., Samsung)</fix>\n\n        <!-- Others -->\n        <title>Others</title>\n        <improve>Added a \"manual\" option in the ADB pairing dialog</improve>\n        <improve>Added more network policies from Motorola devices.</improve>\n        <note subtext=\"true\">\n            - POLICY_REJECT_METERED[br /]\n            - POLICY_REJECT_BACKGROUND[br /]\n            - POLICY_REJECT_ALL\n        </note>\n        <improve>Allow opening an application in Android TV as well as for other users</improve>\n        <note subtext=\"true\">\n            This feature does not work in the installation completion dialog or notification.\n        </note>\n        <improve>Allow the remote server to run under any privileged UID</improve>\n        <improve>Automatically grant usage stats permission in privileged mode</improve>\n        <note subtext=\"true\">The feature, as usual, can be disabled in settings.</note>\n        <improve title=\"Code viewer\">\n            Enabled Smali to Java conversion feature in Android Nougat and earlier\n        </improve>\n        <improve>\n            Enabled backing up data from App Manager via Android-default backup systems\n        </improve>\n        <improve>Enabled creating activity shortcuts for other users</improve>\n        <improve>Enabled fast scrolling in the user manual page</improve>\n        <improve>Kill and recreate the remote server when it's not responding</improve>\n        <note subtext=\"true\">\n            In some cases, the remote server fails to broadcast its presence to App Manager.\n            As a result, the connection times out, and App Manager enters into an infinite\n            loop of automatic troubleshooting. To break this infinite loop, App Manager will\n            now kill the remote server and recreate it. This effectively guarantees\n            that App Manager will never fall into an infinite loop due to an unresponsive\n            server (it will, at best, take less than two minutes), and it will never require\n            more than two attempts to fix such an issue by a user.\n        </note>\n        <improve>Made notification permission optional</improve>\n        <note subtext=\"true\">\n            Although denying notification permission will render many features useless, it is made\n            optional for those who insists on denying it. However, the permission shall still be\n            asked everytime the app is launched until it times out.\n        </note>\n        <improve>Replaced the usernames “Main” and “Work” with “This” and “Other”</improve>\n        <note subtext=\"true\">\n            In no-root mode, usernames cannot be fetched from the system. Hence, “Main” and “Work”\n            are inferred based on the status of the system. However, this can cause issues if the\n            app is installed in the Work profile. Instead, the names “This” and “Other” are used to\n            clarify the situation.\n        </note>\n        <improve>\n            Schedule cache cleaning job more actively to ensure App Manager's caches are cleared regularly\n        </improve>\n        <improve>Updated documentation to reflect latest changes</improve>\n        <note subtext=\"true\">In addition, Oxygen OS specific ADB instructions were added.</note>\n        <improve>Use definite mode of operation</improve>\n        <note subtext=\"true\">\n            When the mode of operation is set to auto, App Manager will attempt to find the best mode and set it as the\n            current mode instead of “Auto” in order to improve the startup time as well as allow stable access of\n            service via upcoming App Manager SDK.\n        </note>\n        <improve>\n            Use granted permissions rather than the mode of operation to check the eligibility of a feature\n        </improve>\n        <improve>Use grid layout in the large displays</improve>\n        <note subtext=\"true\">\n            It uses an empirically derived 450dp column width allowing each column to expand from\n            450dp to 2x450dp before adding a new grid.\n        </note>\n        <improve>Use marquee texts in suggestions/dropdown menu</improve>\n        <improve>Use outlines for color codes</improve>\n        <improve>Use wakelocks in long-running tasks to keep the CPU awake</improve>\n\n        <fix title=\"ADB\">Hide managed users which have debugging restrictions enabled</fix>\n        <fix>Avoided fetching packages for other users if there's no permission to do so</fix>\n        <fix>Fixed blocking components in Android 14</fix>\n        <fix>Fixed blocking providers when only IFW is set</fix>\n        <note subtext=\"true\">\n            Intent Firewall (IFW) does not support blocking providers. So, when IFW-only mode was\n            enabled, it tried to apply only the IFW rules which resulted in the providers remaining\n            unblocked. From now on, the providers are blocked via “disable” option.\n        </note>\n        <fix>Fixed deleting the cached application after the installation attempt fails</fix>\n        <fix>Fixed delivering changes made via batch operations</fix>\n        <fix>Fixed issues with executing automated tasks from the third-party applications</fix>\n        <fix>Fixed launching private activities from shortcuts</fix>\n        <fix>Fixed launching remote services in One Plus devices</fix>\n        <fix>Fixed parsing APK files with wrong headers</fix>\n        <fix>Fixed parsing the manifest of some apps</fix>\n        <fix>Fixed retrieving the list of packages in some devices</fix>\n        <fix>Fixed retrieving and updating permission flags in Android 12 onwards</fix>\n        <fix>Fixed retrieving list of packages in some devices</fix>\n        <fix>Fixed unresponsive continue button in build expiry dialog</fix>\n        <fix>Fixed various security issues related to JADX</fix>\n        <fix>Made setting UID/GID optional while extracting a tar archive</fix>\n\n        <note>\n            [br /][b]Full list of changes:[/b] [a\n            href=\"https://github.com/MuntashirAkon/AppManager/compare/v3.1.0...v4.0.0\"]v3.1.0...v4.0.0[/a]\n        </note>\n    </release>\n    <release\n        type=\"stable release\"\n        version=\"v3.1.0\"\n        code=\"423\"\n        date=\"25 March 2023\">\n        <new>Target Android 13</new>\n        <new>Added monochrome icon for Android 13</new>\n        <new>New languages: Korean, Romanian</new>\n        <new>Added notice for the funding campaign</new>\n        <new>Set an expiry date for each release</new>\n        <note subtext=\"true\">\n            To ensure the safety of the users, App Manager is set to expire several months after it is published. A\n            warning shall be issued for a certain period before the expiry date. After that, App Manager shall\n            completely stop responding to any requests and prompt user to update or uninstall the application. However,\n            for stable releases, it will still be possible to use the application but the warning shall be displayed\n            every time the application is launched.\n        </note>\n        <new>Added support for v3.1 signing scheme</new>\n        <new>\n            Export APKS using the new [a href=\"https://github.com/MuntashirAkon/AppManager/discussions/358\"]APKS\n            specification[/a]. This is still in pre-alpha stage.\n        </new>\n        <improve title=\"Security\">Removed default signing key</improve>\n        <note subtext=\"true\">\n            Default signing key was publicly available and could have be used by others to distribute malware. Instead,\n            enabling APK signing before installing an app now requires a signing key to be added (which can be either\n            generated or imported).\n        </note>\n        <improve>Enabled searching in various selection dialogs</improve>\n        <improve>\n            Improved cache management in the app by periodically cleaning the obsolete files from the cache\n        </improve>\n        <improve>Removed the necessity of [tt].tmp[/tt] directory</improve>\n        <improve>Resolve OID names of the X509 certificates</improve>\n        <improve>Display inferred mode of operation in the crash logs</improve>\n        <improve>Check whether Binder transaction is supported in root mode before initiating a connection</improve>\n        <note subtext=\"true\">\n            Certain superuser implementations did not enable communications through Binder (that, is binder\n            transactions) from user applications. A check has been added to ensure that the currently used superuser\n            supports such communications before attempting to create a remote service.\n        </note>\n        <improve>Fall back to ADB if root mode is not supported</improve>\n        <note subtext=\"true\">\n            If App Manager cannot connect using root, root itself is used to start ADB over TCP and connect to it. This\n            is also useful for certain rooting solutions which do not support Binder transactions.\n        </note>\n        <improve>Handle multiple users including work profile in no-root mode</improve>\n        <note subtext=\"true\">\n            Apps in the work profile can be opened in the App Details page. They can also be launched, uninstalled, and\n            the corresponding settings page can also be opened in no-root mode.\n        </note>\n        <improve>Ensured forward-compatibility in app ops</improve>\n        <note subtext=\"true\">\n            App Manager now handles vendor-specific app ops, newly added app ops in the AOSP, etc. automatically to\n            prevent random crashes.\n        </note>\n        <improve>Improved Java to Smali conversion mechanism</improve>\n        <note subtext=\"true\">\n            Now all the Smali files related to the current file (inner classes, for example) are also converted into\n            Java to make it easier to understand the code.\n        </note>\n        <improve>Handle incomplete USB debugging</improve>\n        <note subtext=\"true\">\n            On certain devices, enabling USB debugging may not be enough to use ADB. In such cases, App Manager will\n            report incomplete USB debugging along with a potential way to solve the issue.\n        </note>\n        <improve>Ensure the existence of shared cache directory before launching App Manager</improve>\n        <note subtext=\"true\">\n            Shared cache directory must exist in all Android devices. If it does not, the ROM is likely broken.\n        </note>\n        <improve>Fall back to root mode while reading the APK file</improve>\n        <note subtext=\"true\">\n            Some applications erroneously provide private files that aren't accessible to any installer other than the\n            system ones. Therefore, root mode is used to read those files if available.\n        </note>\n        <improve>Handled the Internet permission in Graphene OS</improve>\n        <improve>Replaced SLF4J dependency with Android compatible classes</improve>\n        <improve>Updated trackers and libraries</improve>\n        <fix title=\"Profile page\">Fixed crashes in the log viewer tab</fix>\n        <fix>Prevented a crash in the log viewer page</fix>\n        <fix>Fixed crashes by avoiding the deletion of channels of the ongoing notifications</fix>\n        <fix>Fixed crashing if the resource string to be parsed is ill-formatted</fix>\n        <fix>Fixed loading/storing URI grants (SAF) in Android 12 and later</fix>\n        <fix title=\"TV\">Fixed cropping the banner icon</fix>\n        <fix>Fixed the startup progress dialog from displaying indefinitely</fix>\n        <fix>Fixed issues with bottom sheet dialogs</fix>\n        <fix>Fixed various theming issues</fix>\n        <fix>Fixed retrieving usage stats in no-root mode</fix>\n        <fix>Fixed some broken features (e.g. MagiskHide, DenyList) due to I/O errors in libsu</fix>\n        <fix>Fixed SSAID not working in Android 12 and later</fix>\n        <fix>Fixed connecting to ADB immediately after pairing</fix>\n        <fix>Fixed various memory leaks</fix>\n\n        <!-- Activity Interceptor page -->\n        <title type=\"medium\">Activity Interceptor page</title>\n        <new>Added option to copy as [tt]am[/tt] command</new>\n        <note subtext=\"true\">\n            [tt]am[/tt] (short for activity manager) or [tt]cmd activity[/tt] (Android 9 and later) can be used to start\n            an activity from the terminal. This option let user copy the Intent as an [tt]am[/tt] command so that the\n            same Intent can be invoked in the terminal. But not all extras are supported, only the supported extras are\n            copied during the operation.\n        </note>\n        <fix>Fixed crashing in Motorola devices</fix>\n\n        <!-- App Details page -->\n        <title type=\"medium\">App Details page</title>\n        <new title=\"App Info tab\">New tag: WX</new>\n        <note subtext=\"true\">\n            WX tag is displayed in Android 10 and later if the application targets Android 9 or earlier. It indicates\n            [a href=\"https://en.wikipedia.org/wiki/W%5EX\"]W^X[/a] violation which allows the app to execute arbitrary\n            executable files either by the modification of executables embedded within the app or by downloading them\n            from the Internet.\n        </note>\n        <new title=\"App Info tab\">Added option to install an existing app in another profile</new>\n        <note subtext=\"true\">\n            A new menu item, namely “Install for…” is added in the three-dots menu which allows a privileged user to\n            quickly install the same app in another profile without performing a complete installation.\n        </note>\n        <improve>Hide tips forever if close button is clicked</improve>\n        <improve>Try [tt]vacuum[/tt]-ing the databases before displaying the open with dialog</improve>\n        <note subtext=\"true\">\n            To improve speed, databases are often stored in multiple files. Therefore, simply opening the main database\n            may not cover all the data in the database. By [tt]vacuum[/tt]-ing the database, all the files are merged\n            into a single database file, thereby, preventing any consistency issues.\n        </note>\n        <improve>Used monospace font in SSAID fields</improve>\n        <improve>Display app distribution source if available in the signatures tab</improve>\n        <note subtext=\"true\">Currently, the only known source is Google Play.</note>\n        <improve>Added more directories to look for systemless installations in Magisk</improve>\n        <fix>Fixed permission toggles in the uses permissions tab</fix>\n        <fix>Disabled launch buttons in the component tabs if the app is frozen</fix>\n        <fix>Fixed links not working in Play App Signing dialog</fix>\n        <improve>Display invalid native libraries in the Shared libs tab</improve>\n        <improve>Replaced block/unblock button with material switch</improve>\n        <fix>\n            Display failure message instead of crashing if a service cannot be launched from the Services tab\n        </fix>\n        <fix>Prevented the app from crashing on attempting to grant GET_APP_OPS_STATS permission</fix>\n        <fix>Fixed a crash on specifying an invalid icon resource in the edit shortcut dialog</fix>\n        <fix>Fixed crashes in the Shared Libs tab</fix>\n        <fix>Fixed shortcut creation issues in some launchers</fix>\n        <fix>Prevented a crash in the ADB mode which used to occur on attempting to fetch application data size</fix>\n        <fix>Fixed issues with setting a custom SSAID</fix>\n\n        <!-- Backup -->\n        <title type=\"medium\">Backup</title>\n        <new>Added support for elliptic-curve cryptography (ECC)</new>\n        <note subtext=\"true\">\n            ECC in App Manager uses curve 25519 with ECDH which is wrapped with SHA512withECDSA when storing the key in\n            the Bouncy Castle KeyStore.\n        </note>\n        <new>Backup metadata version updated to 4</new>\n        <improve>Use 128 bit tag size for AES encryption</improve>\n        <improve>Prevented backing up the [tt]android[/tt] package</improve>\n        <note subtext=\"true\">\n            This particular package is the heart of Android and shouldn't be backed up or restored.\n        </note>\n        <fix>Use [tt]/data/media[/tt] instead of [tt]/storage/emulated[/tt] for other users</fix>\n        <note subtext=\"true\">\n            In the newer versions of Android, [tt]/storage/emulated[/tt] directories belonging to another user (say, a\n            work profile) cannot be accessed even with root. However, [tt]/data/media[/tt] is only accessible with root.\n            Therefore, the later directory is used instead.\n        </note>\n        <fix>Fixed restoring backed up apps in no-root mode</fix>\n        <fix>Fixed extracting backups if the directory to be created already exists</fix>\n        <fix>Fixed encryption/decryption for AES 128</fix>\n        <fix>Fixed a crash if no backup is selected but restore is clicked</fix>\n        <fix>Fixed an issue with saving the PGP encrypted files</fix>\n        <fix>Fixed crashing if a storage media does not have a label</fix>\n        <fix>Fixed restoring backups for other users</fix>\n        <fix>Fixed scrolling issues in backup/restore dialog</fix>\n\n        <!-- Explorer page -->\n        <title type=\"medium\">Explorer page</title>\n        <new>Added list options containing various sorting and folder options</new>\n        <new>Allowed opening [b]jar[/b] and [b]dex[/b] files</new>\n\n        <!-- Freeze/unfreeze -->\n        <title type=\"medium\">Freeze/unfreeze</title>\n        <new>Replaced enable/disable with freeze/unfreeze</new>\n        <note subtext=\"true\">\n            Freeze/unfreeze can be [a href=\"app-manager://settings/rules_prefs/freeze_type\"]customised[/a] to disable,\n            suspend or hide the applications instead of only disabling it. The colour codes used for disabling is used\n            for freezing.\n        </note>\n        <new>Added freeze/unfreeze toggle shortcut in the App Info tab</new>\n        <note subtext=\"true\">\n            Long clicking on the freeze or unfreeze buttons in the App Info tab opens a dialog where how the shortcut\n            shall work apart from freezing/unfreezing can be configured. If a shortcut already exists, the existing\n            shortcut shall be updated.[br /]\n            It offers the following options:[br /]\n            1. Open application after unfreezing it[br /]\n            2. Open application (requires 1 to be enabled) but without an entry in Recents[br /]\n            3. Refreeze the application when the phone is locked.[br /]\n            When “open after unfreezing” flag is enabled and the app isn't frozen, clicking on the freeze shortcut opens\n            a dialog asking whether to freeze or open the app instead of performing a freeze.\n        </note>\n\n        <!-- Installer page -->\n        <title type=\"medium\">Installer page</title>\n        <improve>Ensured all the installation confirmation notifications are different in no-root mode</improve>\n        <fix>Fixed a rare crash used to occur due to the accidental closing of the installer page</fix>\n        <new>\n            Enabled installing an existing package without requiring a complete re-installation. Requires root/ADB\n        </new>\n        <improve>\n            Use PackageManager API instead of the [tt]pm[/tt] command to uninstall updates of a system app\n        </improve>\n        <improve>Added workarounds for permission denied issues in MIUI 12.5 and later</improve>\n        <fix>\n            Prevented installer from running forever in no-root mode due to the mismanagement of installer queue\n        </fix>\n        <fix>\n            Fixed installing app for all users when “all users” option is selected\n        </fix>\n        <fix>Prevented the installer from crashing if the activity Intent can't be opened</fix>\n\n        <!-- Main page -->\n        <title type=\"medium\">Main page</title>\n        <new title=\"Batch Ops\">Enabled batch uninstaller in no-root mode</new>\n        <new title=\"Batch Ops\">Added an option to export app list</new>\n        <note subtext=\"true\">\n            App list can be exported in either XML or Markdown format, making it easier to store or share. List exported\n            in XML format may be also imported to App Manager in the future.\n        </note>\n        <new>New sorting options: app size, data usage, launch count, screen time, last usage time</new>\n        <new>\n            New filtering options: apps using Android KeyStore, apps using SAF (Storage Access Framework), apps with\n            SSAID.\n        </new>\n        <new>Added support for [tt]market://search?q=query[/tt]</new>\n        <improve title=\"Batch Ops\">\n            Remove removed items from the selection list after a previous operation is finished.\n        </improve>\n        <improve>Improve updating the list of applications</improve>\n        <improve>Replaced “Instructions” with “User Manual”</improve>\n        <fix>Fixed searching issues in non-virtual keyboard</fix>\n        <fix>Fixed crashing on clicking items in list options</fix>\n        <fix>Fixed sorting when a profile is selected in the list options</fix>\n        <fix>\n            Fixed displaying backup volume unavailable messages when [tt]/sdcard/AppManager[/tt] was inaccessible or\n            unavailable\n        </fix>\n\n        <!-- Running Apps page -->\n        <title type=\"medium\">Running Apps page</title>\n        <new>Added searching by package name</new>\n        <new>Enabled advanced searching</new>\n        <fix>Fixed double scrollbars</fix>\n        <fix>Fixed crashes in no-root mode while checking for [tt]RUN_IN_BACKGROUND[/tt]</fix>\n        <fix>Fixed [tt]/proc/$PID/stat[/tt] parsing bug</fix>\n\n        <!-- Scanner page -->\n        <improve>Avoid scanning nested classes to improve the performance of the scanner</improve>\n        <fix>Fixed a rare crash used to occur when the activity is accidentally closed</fix>\n\n        <!-- Settings page -->\n        <new>\n            Added [a href=\"app-manager://settings/appearance_prefs/enabled_features\"]option[/a] to disable opening App\n            Info page from the third-party applications\n        </new>\n        <fix>Disabled wireless debugging, not ADB over TCP in API &lt; 30</fix>\n        <fix>Fixed setting default log level in log viewer preferences</fix>\n\n        <!-- UI -->\n        <title type=\"medium\">UI</title>\n        <improve>Migrated to Material 3-style preferences</improve>\n        <improve>Prevented closing multi-selection panel after starting an operation</improve>\n        <improve>Replaced MD2 (Material Design 2) switches with M3 (Material 3) switches</improve>\n        <improve>Removed dark theme hacks for the WebView in the help page</improve>\n        <fix>Fixed icon theming issues in Android 12</fix>\n        <fix>Fixed loading dynamic colours in the splash screen</fix>\n\n        <note>\n            [br /][b]Full list of changes:[/b] [a\n            href=\"https://github.com/MuntashirAkon/AppManager/compare/v3.0.0...v3.1.0\"]v3.0.0...v3.1.0[/a]\n        </note>\n    </release>\n    <release\n        type=\"stable release\"\n        version=\"v3.0.0\"\n        code=\"410\"\n        date=\"4 August 2022\">\n        <note subtext=\"true\">\n            Credit goes to [a href=\"https://github.com/PookaMustard\"]Pooka Mustard[/a] for compiling the release notes\n            from an incredible number of commits.\n        </note>\n        <new>\n            [b]App Explorer.[/b] It can be used to view and open the internal file structure of an APK. It is visible\n            when opening an APK using an external application such as a file explorer. This option can be disabled in [a\n            href=\"app-manager://settings/appearance_prefs/enabled_features\"]settings[/a].\n        </new>\n        <new>\n            [b]VirusTotal.[/b] Added ability to fetch reports from and send APK files to VirusTotal, using an API key\n            obtained from [a href=\"https://virustotal.com\"]https://virustotal.com[/a]. To use the feature, the\n            [a href=\"app-manager://settings/appearance_prefs/enabled_features\"]Internet feature[/a] must be enabled and\n            the API key must be [a href=\"app-manager://settings/vt_apikey\"]inserted[/a]\n        </new>\n\n        <!-- Main page -->\n        <title type=\"medium\">Main page</title>\n        <new>Add sort by [i]installation date[/i]</new>\n        <new title=\"Batch Ops\">New batch operations such as clearing cache, controlling net policies</new>\n        <improve>Enabled [i]Running apps[/i] filter in no-root mode</improve>\n        <improve>Reduced waiting time for updating the app list</improve>\n        <improve title=\"Batch Ops\">\n            The logs from the last batch operation can be viewed or copied if it fails\n        </improve>\n        <improve title=\"Batch Ops\">\n            Hide actions in the multi-selection view if the screen height of App Manager is too small. Actions can be\n            revealed by tapping the selected-apps counter in the top-middle part of the view\n        </improve>\n        <improve title=\"Batch Ops\">Enable only the actions that can be executed based on the selected apps</improve>\n        <fix>Fixed incomplete list of applications</fix>\n        <fix>Fixed listing running applications if they are running in different processes</fix>\n\n        <!-- App Details page -->\n        <title type=\"medium\">App Details page</title>\n        <new title=\"Services tab\">Added a launch button to launch a service</new>\n        <improve title=\"Components tab\">\n            Enabled advanced component blocking, accessible by long clicking on the block/unblock button\n        </improve>\n        <improve title=\"Components tab\">Display process name</improve>\n        <improve title=\"Activities tab\">\n            Merged two shortcut buttons into one button, namely [i]Create Shortcut[/i], and add a new button, namely\n            [i]launch[/i] button to launch the activities\n        </improve>\n        <improve title=\"Activities tab\">Enabled opening non-exported activities via Activity Interceptor</improve>\n        <note subtext=\"true\">\n            To open an activity in the Activity Interceptor, long click on the [i]Launch[/i] button.\n        </note>\n        <improve title=\"Shared Libraries tab\">\n            Display library description including its file type such as shared object, executable, jar or APK\n        </improve>\n        <improve title=\"Permissions tab\">Display external permissions required by an app</improve>\n        <fix title=\"Uses Permissions tab\">Fixed displaying unsupported or unused permissions</fix>\n        <fix title=\"Signatures tab\">Fixed retrieving signing info in older Android versions</fix>\n\n        <!-- App Info tab -->\n        <title type=\"small\">App Info tab</title>\n        <new>Display primary ABI, hidden API and SELinux info</new>\n        <note subtext=\"true\">\n            Hidden APIs are the methods and classes deliberately hidden by the OS (since Android Pie) and are\n            inaccessible to any third-party applications by default.\n        </note>\n        <new>Added [i]Play App Signing[/i] tag</new>\n        <improve>\n            Tapping any entry in the dialog accessible from the [i]running[/i] tag opens the Log Viewer page with the\n            process ID (PID) of the selected service filtered by deault.\n        </improve>\n        <improve>Display [i]Trackers[/i] in green if all the trackers are blocked</improve>\n        <note subtext=\"true\">The associated dialog also marks all the blocked trackers in green.</note>\n        <improve>Display warning if the user attempts to disable App Manager</improve>\n        <improve>Enabled editing the SSAID field</improve>\n        <improve>Display [i]View in Settings[/i] as an action in no-root mode</improve>\n        <improve>Action buttons match Android 12-style</improve>\n        <fix>Fixed displaying app info of an APK without a valid signature</fix>\n        <fix>Fixed clearing caches in Android 7.1 and older in ADB mode</fix>\n        <note subtext=\"true\">\n            In Android Marshmallow and Nougat, the only way to clear cache is to list all the applications then clear\n            their caches individually.\n        </note>\n\n        <!-- Profile -->\n        <title type=\"medium\">Profile</title>\n        <new>\n            Added the ability to trigger profiles via third-party apps such as\n            [a href=\"https://f-droid.org/en/packages/com.jens.automation2/\"]Automation[/a] or Tasker.\n            See [a href=\"https://muntashirakon.github.io/AppManager/#sec:automating-tasks\"]docs[/a] for details\n        </new>\n        <fix>Fixed displaying apps from all users</fix>\n        <fix>Prevented adding duplicate application items</fix>\n        <fix>Fixed displaying apps from all users</fix>\n\n        <!-- Backup/Restore -->\n        <title type=\"medium\">Backup/Restore</title>\n        <new>\n            Ability to import backups from old or discontinued applications such as Titanium Backup, OAndBackup and\n            Swift Backup (version 3.0–3.2)\n        </new>\n        <improve>\n            Backup/restore MagiskHide and Magisk DenyList rules. If MagiskHide rule is detected but only Magisk DenyList\n            is present, it will fall back to Magisk DenyList\n        </improve>\n        <improve>Restore last modification time</improve>\n        <improve>Display backup date in the backup info</improve>\n        <improve>Improved backup speed by removing recursive functions</improve>\n        <improve>\n            Improved backup/restore dialog to include separate tabs for backup and restore as well as the options to\n            freeze or unfreeze a backup\n        </improve>\n        <improve>Force select [i]APK files[/i] option in the restore tab if the apps aren't installed</improve>\n        <fix>Fixed restoring backups with KeyStore</fix>\n        <note subtext=\"true\">Restoring KeyStore backups may not work if they are restored in a different device.</note>\n\n        <!-- Activity Interceptor page -->\n        <title type=\"medium\">Activity Interceptor page</title>\n        <new>Added option to create shortcuts and copy-and-paste contents</new>\n        <note subtext=\"true\">\n            The copied text contains [tt]tab[/tt] separated entries. So, directly pasting them to messaging platforms\n            may not work.\n        </note>\n        <new>Added [i]class[/i], [i]package[/i] and [i]identifier[/i] fields</new>\n        <new>Added option to resolve and open activities using root</new>\n\n        <!-- Running Apps page -->\n        <title type=\"medium\">Running Apps page</title>\n        <new>Display memory (RAM) and swap information on top of the page</new>\n        <new>\n            View the details of a process by clicking on the item. For Android packages, the relevant App Info page\n            can be accessed by tapping the [i]info[/i] button in the top-right corner of the sheet\n        </new>\n        <fix>Fixed detecting running apps with zygote preload</fix>\n\n        <!-- Installer -->\n        <title type=\"medium\">Installer</title>\n        <new>\n            Added [i]App Info[/i] button in the top-right corner of the installation-completed dialog, which opens the\n            App Details page\n        </new>\n        <improve>Added the ability to install multiple applications by maintaining a queue</improve>\n        <improve>\n            In Android 12 and later, applications previous installed with App Manager can be updated without any user\n            interactions in the no-root mode\n        </improve>\n        <improve>Added the option to downgrade apps in the no-root mode</improve>\n        <improve>Improved how splits are selected during installation</improve>\n        <fix>Prevented the installer from hanging forever in the Knox-enabled Samsung devices</fix>\n        <fix>Fixed support for applications uninstalled without clearing data</fix>\n        <fix>Fixed handling applications with proof-of-rotation</fix>\n        <fix>Fixed extracting OBB files</fix>\n\n        <!-- Settings page -->\n        <title type=\"medium\">Settings</title>\n        <new>\n            Added [a href=\"app-manager://settings/advanced_prefs/saved_apk_format\"]the option[/a] to specify a format\n            for the APK files saved using batch operations or profiles\n        </new>\n        <new>\n            Added [a href=\"app-manager://settings/advanced_prefs/selected_users\"]the option[/a] to select the users App\n            Manager should work with if the device has multiple users\n        </new>\n        <new>\n            Added [a href=\"app-manager://settings/installer\"]an option[/a] to block trackers immediately after\n            installing an application if it is installed with App Manager's installer\n        </new>\n        <new>\n            Added the option to select a [a href=\"app-manager://settings/rules_prefs/default_blocking_method\"]default\n            blocking method[/a]\n        </new>\n        <new>\n            Added an option to reload apps in the [i]Troubleshooting[/i] category\n        </new>\n        <improve>\n            Added [a href=\"app-manager://settings/installer\"]the ability[/a] to install apps in the background\n        </improve>\n        <improve>Implement the new-style changelog</improve>\n        <improve>Fallback to no-root mode if root or ADB is not detected.</improve>\n        <improve>\n            Full implementation of wireless debugging. See [a\n            href=\"https://muntashirakon.github.io/AppManager/#sec:wireless-debugging\"]docs[/a] for details\n        </improve>\n        <improve>Improved auto-detection of ADB</improve>\n        <fix>Fixed changing application locale</fix>\n        <fix>\n            Fixed compatibility issues preventing pre-Marshmallow devices from displaying the [i]About the Device[/i]\n            page\n        </fix>\n        <fix>Fixed importing keys from PKCS12 KeyStore file</fix>\n        <fix>Fixed generating RSA keypair in Android Lollipop</fix>\n\n        <!-- Others -->\n        <title type=\"medium\">Others</title>\n        <new title=\"UI\">Material 3 and dynamic colours</new>\n        <new title=\"UI\">\n            Advanced searching and filtering, including the option to search by suffix, prefix or the regular\n            expressions\n        </new>\n        <new title=\"1-Click Ops page\">\n            Added [i]Trim caches in all apps[/i] operation, which deletes the cache files of all applications, including\n            Android system applications\n        </new>\n        <new title=\"Widget\">A widget to help clear caches in all applications as in the 1-click ops page</new>\n        <new title=\"Widget\">\n            A Digital Wellbeing-style widget with three resize options that displays the screen time along with the\n            three mostly used applications\n        </new>\n        <new title=\"Documentation\">New style single-page documentation</new>\n        <new title=\"Language\">Added Indonesian and Italian</new>\n        <note subtext=\"true\">Removed Bengali due to lack of translators.</note>\n        <new title=\"Shared Preferences Editor\">Added support for [tt]set[/tt] data</new>\n        <new title=\"Profile page\">\n            Added [i]log viewer[/i] section where logs from the past profile triggers are displayed\n        </new>\n        <new title=\"Log Viewer\">\n            Changed extension of saved logs from [tt].log[/tt] to [tt].am.log[/tt] which can be opened in App Manager\n            from the external apps or the system's [i]Sharing[/i] feature\n        </new>\n        <new title=\"Magisk\">Added support for Magisk DenyList rules.</new>\n        <new title=\"Magisk\">Multi-process support for MagiskHide and Magisk DenyList</new>\n\n        <improve title=\"App Usage page\">Improved app usage details dialog to include more usage information</improve>\n        <improve title=\"App Usage page\">\n            Data usage for mobile and Wi-Fi networks are shown with the Android phone and Wi-Fi icons respectively\n            instead of the 'M' and 'W' prefixes\n        </improve>\n        <improve title=\"Documentation\">Redirect to the docs site in case the WebView is unavailable</improve>\n        <improve title=\"UI\">\n            Added Fast-scroller in the app info tab, the Running Apps page, the App Usage page and in the Manifest/Code\n            Viewer page\n        </improve>\n        <improve title=\"UI\">\n            Key generator, changelog and about dialogs in the settings page are displayed in full-screen on small\n            screens\n        </improve>\n        <improve title=\"Security\">Use TLS 1.3 for connecting to ADB in Android 9 and later</improve>\n        <improve title=\"Shared Preferences Editor\">Display exit prompt if the file was edited</improve>\n        <improve title=\"Scanner page\">Display [tt].smali[/tt] content and a preview of its [tt].java[/tt] file</improve>\n        <improve title=\"Scanner page\">Renamed [i]Source Directory[/i] to [i]APK Checksums[/i]</improve>\n        <improve title=\"Log Viewer\">\n            Clicking the settings menu opens the Log Viewer settings instead of the general settings page\n        </improve>\n        <improve title=\"Log Viewer\">Replaced [b]Save Partial[/b] with multi-selection mode</improve>\n        <improve title=\"UX\">Improved navigating the app using a keyboard or a TV remote</improve>\n        <improve title=\"Manifest Viewer\">Reduced font-size to improve readability</improve>\n        <improve>Updated trackers and libraries</improve>\n\n        <fix title=\"Manifest Viewer\">Fixed displaying certain manifest files</fix>\n        <fix title=\"Documentation\">Fixed [i]File not found[/i] issue in some versions of Android</fix>\n        <fix title=\"Language\">Fixed punctuation issues in French</fix>\n        <fix title=\"UI\">Fix prominent RTL layout issues</fix>\n        <fix>App Manager files are now cached in the cache directory instead of data directory</fix>\n        <fix>fixed checking for root in some devices</fix>\n        <fix>Fixed granting or revoking some app ops and permissions</fix>\n        <fix>Fixed restoring application permissions while applying rules or restoring backups</fix>\n        <fix>Fixed crashes on attempting to disable net policies for the core applications</fix>\n\n        <note>\n            [br /][b]Full list of changes:[/b] [a\n            href=\"https://github.com/MuntashirAkon/AppManager/compare/c504b30...v3.0.0\"]v2.6.0...v3.0.0[/a]\n        </note>\n    </release>\n    <release\n        type=\"stable release\"\n        version=\"v2.6.0\"\n        code=\"385\"\n        date=\"25 Apr 2021\">\n        <new>\n            [b]New Feature:[/b] Log Viewer (accessible from the main menu, “running” tag in the app info page and\n            three-dots menu in each item of the running apps page).\n        </new>\n        <new>[b]New language:[/b] Arabic</new>\n        <new>Added AES and RSA encryption (AES/GCM/NoPadding with 12 bytes IV) for backups</new>\n        <new>Added clear cache option in ADB mode</new>\n        <new>Added filter by profile in the main page</new>\n        <new>Added options to disable log viewer</new>\n        <new>\n            Added the ability to import (JKS, BKS and PKCS #12 KeyStores and PK8 formatted private key and PEM\n            certificate) and generate signing keys\n        </new>\n        <new>\n            Added the option to import/export App Manager's KeyStore. It's a typical Bouncy Castle KeyStore in BKS\n            extension\n        </new>\n        <new>\n            Added SAF tag in the app info page for apps that uses storage access framework. Clicking on it lists the\n            granted URIs.\n        </new>\n        <new>\n            Added [b]Verify and redo backups[/b] and [b]back up apps with changes[/b] in 1-click ops page (in the backup\n            section)\n        </new>\n        <improve>\n            Removed UnAPKM from the app as newer APKMs are no longer encrypted. (Use UnAPKM extension from F-Droid to\n            continue to decrypt the encrypted APKM files.)\n        </improve>\n        <improve>Added compatibility support for mobile data usage in old operating systems</improve>\n        <improve>\n            Added colour codes to the “backup” tag in the main page denoting the age of the backups: Red => Uninstalled,\n            Dark cyan => Up to date backup, Orange => Outdated backup\n        </improve>\n        <improve>Added select all button in various multiple choice dialogs</improve>\n        <improve>Display native libraries alongside shared libraries in the shared libs tab</improve>\n        <improve>Display file names that could not be imported (when importing files from Blocker or Watt)</improve>\n        <improve>Improved formatting of the backup info dialogs</improve>\n        <improve>Moved usage access to enable/disable features in the settings page</improve>\n        <improve>Organized settings by moving a rules and installer settings to a different fragment</improve>\n        <improve>Replaced block trackers with block/unblock trackers</improve>\n        <improve>Store backup hashes in the database to detect changes in data (will be enhanced in future)</improve>\n        <improve>Updated trackers and libraries</improve>\n        <fix>Renamed global component blocking to instant component blocking</fix>\n        <fix>Renamed [b]Backup APK[/b] to [b]Save APK[/b]</fix>\n        <fix>Removed the backup option [b]Source[/b] and renamed [b]APK only[/b] to [b]APK files[/b]</fix>\n        <fix>\n            Replaced the backup option [b]Data[/b] with [b]Internal data[/b]. [b]External data[/b] no longer depends on\n            this option\n        </fix>\n        <fix>Replaced the backup option [b]Exclude cache[/b] with [b]Cache[/b] (i.e., the flag has been inverted).</fix>\n        <fix>Avoided crash in the app details page when device configuration (night mode, orientation, etc.) changes\n        </fix>\n        <fix>Backup URI grants only for the given users</fix>\n        <fix>Fixed a crash occurs occasionally when detecting whether an app is running</fix>\n        <fix>Fixed a crash when yesterday data isn't available in the app usage page</fix>\n        <fix>\n            Fixed a crash when back button is pressed immediately after pressing the add button in the profile page\n        </fix>\n        <fix>Fixed backup service from hanging if it encounters invalid file types</fix>\n        <fix>Fixed fetching storage info for users other than the current user</fix>\n        <fix>Fixed hidden API restriction bypass issue for Android 11 (which unfortunately increased the APK size)</fix>\n        <fix>Fixed displaying wrong data usage in Android Lollipop devices</fix>\n        <fix>Fixed restoring backups with symbolic links</fix>\n        <fix>Foreground service notification is removed immediately after the operation is complete</fix>\n        <note>\n            [b]Notice:[/b] After restoring apps that use SAF and SSAID, the device has to be restarted immediately.\n            Currently, the users are not notified if a restart is necessary after restoring a backup.\n            If you are in confusion, make sure to restart your device after restoring a backup.\n        </note>\n    </release>\n    <release\n        type=\"pre-release\"\n        version=\"v2.5.24\"\n        code=\"383\"\n        date=\"21 Mar 2021\">\n        <new>New language: Tradition Chinese</new>\n        <new>Added filter by uninstalled apps, apps without backups in the main page</new>\n        <new>Allow specifying custom installer package which may or may not be installed</new>\n        <new>Copy package name on clicking on the package name in the app info tab</new>\n        <new>Display file size, requirement, etc. for split APKs in the APK selection dialog</new>\n        <new>Display version and tracker info in the installation confirmation dialog</new>\n        <improve>\n            Added wildcard support for app ops and permissions for profiles. [tt]*[/tt] can be used instead of\n            specifying app ops or permissions to revoke all configured/dangerous permissions/app ops\n        </improve>\n        <improve>App icons are cached to improve load time</improve>\n        <improve>Complete rewrite of running apps internals in Java</improve>\n        <improve>Display uninstalled system apps and display installation prompt on clicking them</improve>\n        <improve>Improved ADB detection and persistence of such detection</improve>\n        <improve>Removed toybox along with its dependencies</improve>\n        <improve>Updated trackers and libraries</improve>\n        <improve>Utilise multiple CPUs for back up/restore</improve>\n        <improve>\n            Verify copied checksum with the checksum of the signing certificate of the app on clicking on the app icon\n            in the app info page\n        </improve>\n        <fix>Added additional verifications to ensure that screen lock is not bypassed</fix>\n        <fix>Fixed back up/restore failure on some Android devices</fix>\n        <fix>Fixed crashes in the app details page when system configuration changes</fix>\n        <fix>Fixed crash on creating shortcuts on devices that do not support pin shortcut</fix>\n        <fix>Fixed generating wrong checksum for certificates in the signatures tab</fix>\n        <fix>Fixed uninstalling app for multiple users</fix>\n        <fix>Fixed various crashes on opening APK files from external apps</fix>\n        <fix>Hide backup option if one of the selected apps is not installed</fix>\n        <fix>Verify KeyStore backups during restoring a backup</fix>\n    </release>\n    <release\n        type=\"pre-release\"\n        version=\"v2.5.23\"\n        code=\"381\"\n        date=\"4 Feb 2021\">\n        <new>Added screen lock</new>\n        <new>Added [b]Add to profile[/b] in the batch ops and app info tab</new>\n        <new>Added enable/disable features in settings (replacing interceptor setting)</new>\n        <new>Added leanback launcher support with banner (Android TV)</new>\n        <new>Backup/restore SSAID (requires immediate restart)</new>\n        <new>Backup APK in external SD card</new>\n        <new>\n            AppInfo: Added options to configure battery optimization, net policy, SSAID. For each of them, tag clouds\n            will be displayed if the values are not default.\n        </new>\n        <new>Interceptor: add/remove extras</new>\n        <new>Made settings page accessible from Android Settings</new>\n        <new>\n            Main: Added filter by installed app, sort by number of trackers and last actions (the latter is not stable\n            yet)\n        </new>\n        <new>New language: Japanese</new>\n        <new>Search using app initials in the main page (e.g. TS will list TrebleShot in the search results)</new>\n        <new>Use of database as a middle man to improve load time</new>\n        <improve>AppInfo: Added options to select tracker components to block/unblock</improve>\n        <improve>Improved backup volume selection</improve>\n        <improve>\n            Main: Batch selection on long click after the selection mode is turned on (i.e. selection mode is turned on\n            if you click on any app icon or long click on any app)\n        </improve>\n        <improve>Main: Replaced sort and filter with list options</improve>\n        <improve>Main: Set [b]backup[/b] to red if the app is not installed</improve>\n        <improve>Removed F-Droid, Aurora Droid in favour of F-Droid links (to support user preferred clients)</improve>\n        <improve>Updated trackers, libraries, profile presets</improve>\n        <fix>Fixed app icon (it now matches app theme)</fix>\n        <fix>Fixed crash while blocking app components of a recently updated app</fix>\n        <fix>Fixed various crashes in the app info tab</fix>\n        <fix>Properly sanitize profile names and exported APK(S) file names</fix>\n        <fix>Remove rules for all users (rather than the current user) in settings</fix>\n        <fix>Replaced AppManager/tmp with AppManager/.tmp</fix>\n        <fix>Replaced image buttons with material buttons (fixes crash when using Substratum themes)</fix>\n        <note>\n            Don't set folders inside [tt]/mnt/media_rw/[/tt] as the backup volume. It doesn't work for backup/restore.\n        </note>\n    </release>\n    <release\n        type=\"pre-release\"\n        version=\"v2.5.22\"\n        code=\"379\"\n        date=\"16 Jan 20201\">\n        <new>1-Click Ops: add backup/restore options</new>\n        <new>Added the ability to freeze backup (by creating [tt].freeze[/tt] in the corresponding backup)</new>\n        <new>Added option to enable/disable MagiskHide in the App Info tab (enable option in the overflow menu)</new>\n        <new>Added option to enable/disable interceptor (in settings)</new>\n        <new>Added option to launch services</new>\n        <new>Added option to select backup volume</new>\n        <new>Backup/restore app installer, netpolicy, deviceidle, magiskhide and notification access</new>\n        <new>Backup/restore URI grants (need immediate reboot after the restore)</new>\n        <new>Grant/revoke permissions in profile</new>\n        <new>New attribute in backup/restore: size</new>\n        <new>New attribute in profile: users</new>\n        <new>New tag in App Info: backups</new>\n        <improve>Added encryption info in about device</improve>\n        <improve>Block and disable components using IFW and PackageManager respectively for maximum protection</improve>\n        <improve>Improved instructions in the 1-Click Ops page</improve>\n        <improve>Integrated docs within AM as a dynamic feature</improve>\n        <improve>Open DRM-free APKM files without conversion</improve>\n        <improve>Sort apps by labels, display user/system tag in the profile page</improve>\n        <improve>Replace backup all users with custom users</improve>\n        <improve>Updated trackers and libraries</improve>\n        <improve>\n            Remove [tt]FLAG_ACTIVITY_FORWARD_RESULT[/tt] from list of flags (if present) in the interceptor\n        </improve>\n        <fix>Add [tt].nomedia[/tt] file in the backup folder</fix>\n        <fix>Fixed crash on clicking [i]about device[/i] item in Settings</fix>\n        <fix>Fixed crash in the profile page</fix>\n        <fix>Fixed compatibility issue of IFW in Android M or prior versions</fix>\n        <fix>Get correct user ID before performing uninstall</fix>\n        <fix>Migrate to PackageManager API instead of using unreliable pm command</fix>\n        <fix>Update theme name on changing app theme</fix>\n        <fix>Use package name from metadata instead of directory name for backups</fix>\n        <note>\n            Backup/restore feature is now beta. From now on, backward compatibility for backup/restorer will be\n            provided.\n        </note>\n    </release>\n    <release\n        type=\"pre-release\"\n        version=\"v2.5.21\"\n        code=\"377\"\n        date=\"1 Jan 2021\">\n        <new>New language: Farsi</new>\n        <new>Added about device in the settings page</new>\n        <new>Added an installation button in the scanner page for the external APK files</new>\n        <new>Added the option to set custom app ops and modes in the three-dots menu</new>\n        <improve>Added shortcut support for Android N MR1 or less</improve>\n        <improve>Display app ops associated with the declared permissions in the app ops tab</improve>\n        <improve>Display feature availability and version number in the uses features tab</improve>\n        <improve>Display icon for uninstalled but backed up apps in the main page</improve>\n        <improve>Display tracker count in a new line instead of under brackets in the 1-click ops page</improve>\n        <improve>Improved app install time for ADB users</improve>\n        <improve>\n            Renamed “deny app ops” to “set mode for app ops”, added the option to specify modes in 1-click ops page\n        </improve>\n        <improve>Reordered backup options along with description for each items</improve>\n        <improve>Updated ADBLib</improve>\n        <improve>Updated trackers and libraries</improve>\n        <fix>Fixed crashes of the app ops tab in Android 11</fix>\n        <fix>Fixed crashes of the app ops tab in MIUI</fix>\n        <fix>Fixed prompting users for ADB permission repeatedly when auto is the mode of operation</fix>\n        <fix>Hide launch and shortcut buttons from the activities tab for external APK</fix>\n        <fix>Use both package mode and UID mode for app ops from Android 6</fix>\n        <fix>Use data folder to store server/IPC related files</fix>\n    </release>\n</changelog>"
  },
  {
    "path": "app/src/main/res/values/arrays.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<resources>\n    <array name=\"TAB_TITLES\">\n        <item>@string/app_info</item>\n        <item>@string/activities</item>\n        <item>@string/service</item>\n        <item>@string/receivers</item>\n        <item>@string/providers</item>\n        <item>@string/app_ops</item>\n        <item>@string/permissions</item>\n        <item>@string/declared_permission</item>\n        <item>@string/uses_feature</item>\n        <item>@string/configurations</item>\n        <item>@string/app_signing_signatures</item>\n        <item>@string/shared_libs</item>\n        <item>@string/overlays</item>\n    </array>\n    <array name=\"rule_types\">\n        <item>@string/activities</item>\n        <item>@string/service</item>\n        <item>@string/receivers</item>\n        <item>@string/providers</item>\n        <item>@string/app_ops</item>\n        <item>@string/permissions</item>\n    </array>\n    <array name=\"themes\">\n        <item>@string/follow_system</item>\n        <item>@string/battery_mode</item>\n        <item>@string/day</item>\n        <item>@string/night</item>\n    </array>\n    <array name=\"modes\">\n        <item>@string/auto</item>\n        <item>@string/root</item>\n        <item>@string/adb_over_tcp</item>\n        <item>@string/wireless_debugging</item>\n        <item>@string/no_root</item>\n    </array>\n    <string-array name=\"shared_pref_types\">\n        <item>@string/type_boolean</item>\n        <item>@string/type_float</item>\n        <item>@string/type_int</item>\n        <item>@string/type_long</item>\n        <item>@string/type_string</item>\n        <item>@string/type_string_set</item>\n    </string-array>\n    <string-array name=\"extras_types\">\n        <item>@string/type_boolean</item>\n        <item>@string/type_component_name</item>\n        <item>@string/type_float</item>\n        <item>@string/type_float_array</item>\n        <item>@string/type_float_array_list</item>\n        <item>@string/type_int</item>\n        <item>@string/type_int_array</item>\n        <item>@string/type_int_array_list</item>\n        <item>@string/type_long</item>\n        <item>@string/type_long_array</item>\n        <item>@string/type_long_array_list</item>\n        <item>@string/type_null</item>\n        <item>@string/type_string</item>\n        <item>@string/type_string_array</item>\n        <item>@string/type_string_array_list</item>\n        <item>@string/type_uri</item>\n        <item>@string/type_uri_array</item>\n        <item>@string/type_uri_array_list</item>\n    </string-array>\n    <string-array name=\"usage_interval_dropdown_list\">\n        <item>@string/usage_daily</item>\n        <item>@string/usage_weekly</item>\n    </string-array>\n    <string-array name=\"whats_new_titles\">\n        <item>@string/version</item>\n        <item>@string/trackers</item>\n        <item>@string/app_signing_signatures</item>\n        <item>@string/declared_permission</item>\n        <item>@string/components</item>\n        <item>@string/features</item>\n        <item>@string/sdk</item>\n    </string-array>\n    <string-array name=\"sys_config_names\">\n        <!-- Must be aligned with SysConfigType -->\n        <item>group</item>\n        <item>permission</item>\n        <item>assign-permission</item>\n        <item>split-permission</item>\n        <item>library</item>\n        <item>feature</item>\n        <item>unavailable-feature</item>\n        <item>allow-in-power-save-except-idle</item>\n        <item>allow-in-power-save</item>\n        <item>allow-in-data-usage-save</item>\n        <item>allow-unthrottled-location</item>\n        <item>allow-ignore-location-settings</item>\n        <item>allow-implicit-broadcast</item>\n        <item>app-link</item>\n        <item>system-user-whitelisted-app</item>\n        <item>system-user-blacklisted-app</item>\n        <item>default-enabled-vr-app</item>\n        <item>component-override</item>\n        <item>backup-transport-whitelisted-service</item>\n        <item>disabled-until-used-preinstalled-carrier-associated-app</item>\n        <item>disabled-until-used-preinstalled-carrier-app</item>\n        <item>privapp-permissions</item>\n        <item>oem-permissions</item>\n        <item>hidden-api-whitelisted-app</item>\n        <item>allow-association</item>\n        <item>app-data-isolation-whitelisted-app</item>\n        <item>bugreport-whitelisted</item>\n        <item>install-in-user-type</item>\n        <item>named-actor</item>\n        <item>rollback-whitelisted-app</item>\n        <item>whitelisted-staged-installer</item>\n    </string-array>\n    <string-array name=\"sig_schemes\">\n        <item>@string/v1_scheme</item>\n        <item>@string/v2_scheme</item>\n        <item>@string/v3_scheme</item>\n        <item>@string/v4_scheme</item>\n    </string-array>\n    <string-array name=\"crypto_import_types\">\n        <!-- The order must be preserved -->\n        <item>@string/java_keystore</item>\n        <item>@string/pkcs12_keystore</item>\n        <item>@string/bouncy_castle_keystore</item>\n        <item>@string/pem_and_pk8</item>\n    </string-array>\n    <string-array name=\"profile_types\">\n        <item>@string/apps</item>\n        <item>@string/filters</item>\n    </string-array>\n    <integer-array name=\"random_colors\">\n        <item>@color/original_orange</item>\n        <item>@color/dark_orange</item>\n        <item>@color/pink</item>\n        <item>@color/ocean_blue</item>\n        <item>@color/pure_red</item>\n        <item>@color/bright_green</item>\n        <item>@color/electric_red</item>\n        <item>@color/deep_green</item>\n        <item>@color/power_blue</item>\n        <item>@color/purple_y</item>\n        <item>@color/yellow_gloves</item>\n        <item>@color/readhead</item>\n        <item>@color/sand_tan</item>\n        <item>@color/sand_tan_shadow</item>\n        <item>@color/night_blue</item>\n        <item>@color/night_blue_shadow</item>\n        <item>@color/coral_pink</item>\n        <item>@color/sleuthe_yellow</item>\n        <item>@color/pink_leaf</item>\n        <item>@color/grassy_green</item>\n        <item>@color/purple_mountains_majesty</item>\n        <item>@color/misty_mountain_pink</item>\n        <item>@color/factory_stone_purple</item>\n        <item>@color/green_treeline</item>\n        <item>@color/pink_highlight</item>\n        <item>@color/bluewater_lowlight</item>\n        <item>@color/yellow_background</item>\n        <item>@color/pink_red_circle</item>\n        <item>@color/orange_circle</item>\n        <item>@color/old_makeup_pink</item>\n        <item>@color/goldenrod_yellow</item>\n        <item>@color/bluebell_light_blue</item>\n        <item>@color/bold_2019_green</item>\n        <item>@color/lightning_blue</item>\n        <item>@color/lightning_purple</item>\n        <item>@color/apricot</item>\n        <item>@color/citrus</item>\n        <item>@color/left_blue</item>\n        <item>@color/right_blue_muted</item>\n        <item>@color/blue_green</item>\n        <item>@color/red_orange</item>\n        <item>@color/redder_than_you</item>\n        <item>@color/goldi_lots</item>\n        <item>@color/darker_gold</item>\n        <item>@color/silver_tongue</item>\n        <item>@color/the_brown_shirts</item>\n        <item>@color/blondey</item>\n        <item>@color/green_mountain</item>\n        <item>@color/blue_mountain</item>\n        <item>@color/light_blue_backdrop</item>\n        <item>@color/orange</item>\n        <item>@color/yellowbrite</item>\n        <item>@color/painful_red</item>\n        <item>@color/_35_years_old_purple</item>\n        <item>@color/lighter_purple_on_the_gradient</item>\n        <item>@color/shadow_purple_red</item>\n        <item>@color/green</item>\n        <item>@color/ironic_blues</item>\n        <item>@color/pinky_ring</item>\n        <item>@color/egg_yellows</item>\n    </integer-array>\n    <string-array name=\"log_levels\">\n        <item>@string/log_level_verbose</item>\n        <item>@string/log_level_debug</item>\n        <item>@string/log_level_info</item>\n        <item>@string/log_level_warn</item>\n        <item>@string/log_level_error</item>\n        <item>@string/log_level_fatal</item>\n    </string-array>\n    <string-array name=\"layout_orientations\">\n        <item>@string/orientation_follow_locale</item>\n        <item>@string/orientation_left_to_right</item>\n        <item>@string/orientation_right_to_left</item>\n    </string-array>\n    <string-array name=\"import_backup_options\">\n        <item>@string/import_from_oab</item>\n        <item>@string/import_from_tb</item>\n        <item>@string/import_from_sb</item>\n    </string-array>\n    <string-array name=\"backup_restore_tabs_single\">\n        <item>@string/backup</item>\n        <item>@string/restore_dots</item>\n    </string-array>\n    <string-array name=\"backup_restore_tabs_multiple\">\n        <item>@string/backup</item>\n        <item>@string/restore</item>\n    </string-array>\n    <string-array name=\"file_open_as_options\">\n        <item>@string/open_as_text</item>\n        <item>@string/open_as_image</item>\n        <item>@string/open_as_video</item>\n        <item>@string/open_as_archive</item>\n        <item>@string/open_as_folder</item>\n        <item>@string/open_as_other</item>\n    </string-array>\n    <string-array name=\"file_open_as_option_types\">\n        <item>text/plain</item>\n        <item>image/*</item>\n        <item>video/*</item>\n        <item>application/x-7z-compressed</item>\n        <item>resource/folder</item>\n        <item>*/*</item>\n    </string-array>\n    <string-array name=\"freeze_unfreeze_flags\">\n        <item>@string/on_unfreeze_open_application</item>\n        <item>@string/on_open_application_no_recents</item>\n        <item>@string/freeze_on_phone_locked</item>\n    </string-array>\n    <string-array name=\"export_app_list_options\">\n        <item>CSV</item>\n        <item>JSON</item>\n        <item>@string/export_option_xml</item>\n        <item>@string/export_option_markdown</item>\n    </string-array>\n    <string-array name=\"finder_filters\">\n        <item>apk_size</item>\n        <item>app_label</item>\n        <item>app_type</item>\n        <item>backup</item>\n        <item>bloatware</item>\n        <item>cache_size</item>\n        <item>compile_sdk</item>\n        <item>components</item>\n        <item>data_size</item>\n        <item>data_usage</item>\n        <item>freeze_unfreeze</item>\n        <item>installed</item>\n        <item>installer</item>\n        <item>last_update</item>\n        <item>min_sdk</item>\n        <item>permissions</item>\n        <item>pkg_name</item>\n        <item>running_apps</item>\n        <item>screen_time</item>\n        <item>signature</item>\n        <item>target_sdk</item>\n        <item>times_opened</item>\n        <item>total_size</item>\n        <item>trackers</item>\n        <item>uid</item>\n        <item>version_name</item>\n    </string-array>\n    <string name=\"usage_daily\">Daily</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values/attrs.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<resources>\n    <attr name=\"barChartViewStyle\" format=\"reference\" />\n    <declare-styleable name=\"BarChartView\">\n        <!-- Bar appearance -->\n        <attr name=\"barColor\" format=\"color\" />\n        <attr name=\"selectedBarColor\" format=\"color\" />\n        <attr name=\"minBarWidth\" format=\"dimension\" />\n        <attr name=\"maxBarWidth\" format=\"dimension\" />\n        <attr name=\"valueOnTopOfBar\" format=\"boolean\" />\n\n        <!-- Grid appearance -->\n        <attr name=\"gridColor\" format=\"color\" />\n        <attr name=\"gridStrokeWidth\" format=\"dimension\" />\n        <attr name=\"gridLineCount\" format=\"integer\" />\n        <attr name=\"gridLabelsOnLeft\" format=\"boolean\" />\n\n        <!-- Text appearance -->\n        <attr name=\"textColor\" format=\"color\" />\n        <attr name=\"textSize\" format=\"dimension\" />\n        <attr name=\"yAxisFormat\" format=\"string\" />\n        <attr name=\"emptyText\" format=\"string\" />\n\n        <!-- Touch line appearance -->\n        <attr name=\"touchLineColor\" format=\"color\" />\n        <attr name=\"touchLineWidth\" format=\"dimension\" />\n\n        <!-- Tooltip appearance -->\n        <attr name=\"tooltipBackgroundColor\" format=\"color\" />\n        <attr name=\"tooltipTextColor\" format=\"color\" />\n        <attr name=\"tooltipCornerRadius\" format=\"dimension\" />\n    </declare-styleable>\n</resources>"
  },
  {
    "path": "app/src/main/res/values/colors.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<resources>\n    <color name=\"fm_icon_background\">@color/m3_sys_color_light_on_surface_variant</color>\n    <color name=\"fm_symbolic_link\">#f37785</color>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values/dimens.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\r\n<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\r\n<resources>\r\n    <dimen name=\"icon_size\">40dp</dimen>\r\n    <dimen name=\"title_font\">16sp</dimen>\r\n    <dimen name=\"subtitle_font\">14sp</dimen>\r\n    <dimen name=\"app_widget_background_padding\">16dp</dimen>\r\n</resources>"
  },
  {
    "path": "app/src/main/res/values/disclaimer.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<resources>\n    <string name=\"disclaimer_header\">Disclaimer</string>\n    <string name=\"disclaimer_body\">App Manager offers root functions that could possibly harm\n        your device if used incorrectly. App Manager is not responsible for any damages made by\n        using this application. If you are not fully aware of how root works then you should avoid\n        using root options until you are fully aware of the risks.\n\n        \\n\\nAny link I provide to other apps and websites is for the users benefit. I am not\n        responsible for any content you may find by going on external links.\n\n        \\n\\nBy using App Manager, you accept full responsibility of your own usage and accept no\n        damages, claims or monetary value will be given due to misuse.\n\n        \\n\\nBy using this application, you accept all responsibility using it and agree that I am\n        not responsible for any actions you make that has an adverse effect on your device.\n    </string>\n    <string name=\"disclaimer_footer\" translatable=\"false\">© 2020–2025 Muntashir Al-Islam</string>\n    <string name=\"disclaimer_agree_forever\">Never show this again</string>\n    <string name=\"disclaimer_agree\">I Agree</string>\n    <string name=\"disclaimer_exit\">Exit</string>\n</resources>"
  },
  {
    "path": "app/src/main/res/values/ic_banner_background.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- SPDX-License-Identifier: GPL-3.0-or-later OR CC-BY-SA-4.0 -->\n<resources>\n    <color name=\"ic_banner_background\">#DCAF74</color>\n</resources>"
  },
  {
    "path": "app/src/main/res/values/ic_launcher_background.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later OR CC-BY-SA-4.0 -->\n<resources>\n    <color name=\"ic_launcher_background\">#090503</color>\n</resources>"
  },
  {
    "path": "app/src/main/res/values/ic_launcher_fm_background.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later OR CC-BY-SA-4.0 -->\n<resources>\n    <color name=\"ic_launcher_fm_background\">#090503</color>\n</resources>"
  },
  {
    "path": "app/src/main/res/values/libs.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<resources>\n    <array name=\"lib_signatures\">\n        <item>com.threesixtydialog.sdk.</item>\n        <item>com.geopla.</item>\n        <item>com.threebitter.sdk.</item>\n        <item>org.seamless</item>\n        <item>net.sf.sevenzipjbinding</item>\n        <item>com.m7.imkfsdk.</item>\n        <item>com.moor.imkf.</item>\n        <item>com.jecelyin.common</item>\n        <item>com.jecelyin.editor.v2</item>\n        <item>com.jecelyin.android.file_explorer</item>\n        <item>com.reactnativecommunity.checkbox</item>\n        <item>com.reactnativecommunity.clipboard</item>\n        <item>com.reactnativecommunity.geolocation</item>\n        <item>com.reactnativecommunity.netinfo</item>\n        <item>com.reactnativecommunity.slider</item>\n        <item>com.abtasty</item>\n        <item>org.acra.</item>\n        <item>ch.acra.</item>\n        <item>com.acrcloud</item>\n        <item>org.achartengine</item>\n        <item>com.adxcorp.ads</item>\n        <item>com.adxcorp.nativead</item>\n        <item>com.mocoplex.adlib.</item>\n        <item>com.adop.sdk.</item>\n        <item>com.admanmedia.</item>\n        <item>org.signal.aesgcmprovider</item>\n        <item>com.scottyab.aescrypt</item>\n        <item>com.aurelhubert.ahbottomnavigation</item>\n        <item>amirz.aidlbridge</item>\n        <item>com.ljoy.chatbot.</item>\n        <item>com.aihelp.alice.</item>\n        <item>com.amoad.</item>\n        <item>com.github.anrwatchdog</item>\n        <item>com.dsi.ant</item>\n        <item>antlr</item>\n        <item>org.antlr</item>\n        <item>org.aopalliance</item>\n        <item>com.google.api.common</item>\n        <item>com.apicloud.</item>\n        <item>com.github.penfeizhou.animation</item>\n        <item>com.alibaba.android.arouter</item>\n        <item>org.objectweb.asm</item>\n        <item>microsoft.aspnet.signalr.client</item>\n        <item>com.atinternet.</item>\n        <item>com.wang.avi</item>\n        <item>com.amazonaws.mobileconnectors.amazonmobileanalytics</item>\n        <item>com.amazonaws.metrics.</item>\n        <item>com.amazonaws.util.AWSRequestMetrics.</item>\n        <item>com.amazonaws.services</item>\n        <item>com.aarki</item>\n        <item>com.snilius.aboutit</item>\n        <item>com.mikepenz.aboutlibraries</item>\n        <item>com.arialyy.frame</item>\n        <item>com.absinthe.libraries</item>\n        <item>org.mariotaku.abstask</item>\n        <item>net.accelf.easter</item>\n        <item>com.google.accompanist</item>\n        <item>com.facebook.accountkit</item>\n        <item>com.faendir.acra.</item>\n        <item>com.alcoapps.actionbarextras</item>\n        <item>com.actionbarsherlock</item>\n        <item>com.activeandroid</item>\n        <item>com.frogermcs.activityframemetrics</item>\n        <item>com.dylanc.activityresult.launcher</item>\n        <item>me.angrybyte.numberpicker</item>\n        <item>me.actv8</item>\n        <item>com.acuant.acuantcamera</item>\n        <item>com.socdm.d.adgeneration.</item>\n        <item>com.ad2iction.</item>\n        <item>com.a4gpublisher.</item>\n        <item>com.ad4screen.sdk</item>\n        <item>com.adadapted.android.sdk.</item>\n        <item>com.purplebrain.adbuddiz.sdk.</item>\n        <item>com.adcolony.</item>\n        <item>com.jirbo.adcolony.</item>\n        <item>com.noqoush.adfalcon.android.sdk</item>\n        <item>com.kakao.adfit.</item>\n        <item>mobi.mclick.ad.</item>\n        <item>com.adform.sdk.</item>\n        <item>com.adgatemedia.</item>\n        <item>com.adgem.android.</item>\n        <item>com.adlocus.</item>\n        <item>com.admarvel.</item>\n        <item>com.rjfun.cordova.ad</item>\n        <item>com.rjfun.cordova.admob</item>\n        <item>com.admuing.danmaku.</item>\n        <item>com.adtech.adtechmobile</item>\n        <item>com.adtheorent.</item>\n        <item>com.aiming.mdt.</item>\n        <item>com.adtiming.</item>\n        <item>com.adtrial.sdk.</item>\n        <item>com.kuaiyou.loader.</item>\n        <item>com.adwhirl.</item>\n        <item>com.hannesdorfmann.adapterdelegates4</item>\n        <item>io.adaptivecards</item>\n        <item>james.adaptiveicon</item>\n        <item>com.smlnskgmail.jaman.adaptiverecyclerview</item>\n        <item>com.igaworks.adbrix</item>\n        <item>com.adcash.mobileads.</item>\n        <item>com.adcenix.</item>\n        <item>com.adchina.android</item>\n        <item>com.intentsoftware.addapptr.</item>\n        <item>com.adflake</item>\n        <item>jp.tjkapp.adfurikunsdk.</item>\n        <item>com.glossomads.sdk.</item>\n        <item>com.batoulapps.adhan</item>\n        <item>com.adincube.sdk.</item>\n        <item>io.adjoe.sdk.</item>\n        <item>io.adjoe.protection.</item>\n        <item>com.adjust.sdk.</item>\n        <item>com.adjust.android.sdk.</item>\n        <item>com.adjust.sdk</item>\n        <item>com.unbotify.mobile.sdk.</item>\n        <item>ru.tachos.admitadstatisticsdk</item>\n        <item>com.admixer</item>\n        <item>net.admixer.sdk</item>\n        <item>admost.sdk.</item>\n        <item>admost.adserver.</item>\n        <item>com.adobe.marketing.mobile</item>\n        <item>com.adotmob</item>\n        <item>.adswizz.</item>\n        <item>com.adscendmedia.sdk.</item>\n        <item>AdscendFiles.AdscendOffersActivity</item>\n        <item>com.h6ah4i.android.widget.advrecyclerview</item>\n        <item>im.delight.android.webview</item>\n        <item>com.advangelists.</item>\n        <item>com.adyen.checkout</item>\n        <item>com.aerserv.sdk.</item>\n        <item>com.afollestad.aesthetic</item>\n        <item>com.just.agentweb</item>\n        <item>jp.co.agoop.</item>\n        <item>io.agora.rtc.</item>\n        <item>io.agora.utils.</item>\n        <item>org.ahocorasick</item>\n        <item>com.aitype.android</item>\n        <item>com.holly.marge</item>\n        <item>com.bear.data</item>\n        <item>com.mb.num</item>\n        <item>io.airbridge.</item>\n        <item>com.airpush.</item>\n        <item>com.akamai.android.sdk.AkaMap</item>\n        <item>com.tapadoo.alerter</item>\n        <item>com.algolia.search</item>\n        <item>com.anythink.</item>\n        <item>com.alxad.</item>\n        <item>.anythink.</item>\n        <item>com.alibaba.sdk.android.mns</item>\n        <item>com.alibaba.sdk.android.httpdns</item>\n        <item>com.ta.utdid2</item>\n        <item>com.alibaba.analytics.</item>\n        <item>com.aliexpress.module.imsdk.</item>\n        <item>com.aliexpress.module.traffic.DDLAccsService</item>\n        <item>com.aliexpress.module.ugc.adapter.powermsg.PowermsgAccsReceiveService</item>\n        <item>com.aliexpress.sky.user.service.SkyAccsService</item>\n        <item>com.taobao.artc.accs.</item>\n        <item>com.taobao.orange.accssupport.</item>\n        <item>com.taobao.sophix.</item>\n        <item>com.adsmogo.</item>\n        <item>com.alimama.</item>\n        <item>com.alipay.sdk.</item>\n        <item>moe.feng.alipay.zerosdk</item>\n        <item>org.alohalytics.</item>\n        <item>com.github.aloomaio.androidsdk</item>\n        <item>in.myinnos.alphabetsindexfastscrollrecycler</item>\n        <item>tv.alphonso.service</item>\n        <item>org.altbeacon.beacon.</item>\n        <item>com.altbeacon.beacon.</item>\n        <item>org.altbeacon.bluetooth.</item>\n        <item>com.altamob.sdk</item>\n        <item>com.amap.api</item>\n        <item>com.amazonaws.event</item>\n        <item>com.amazonaws.handlers</item>\n        <item>com.amazonaws.http</item>\n        <item>com.amazonaws.internal</item>\n        <item>com.amazonaws.regions</item>\n        <item>com.amazonaws.auth</item>\n        <item>com.amazon.device.ads</item>\n        <item>com.amazon.insights</item>\n        <item>com.amazon.insights</item>\n        <item>com.amazonaws.mobileconnectors.pinpoint.analytics.</item>\n        <item>com.amazonaws.mobileconnectors.amazonmobileanalytics</item>\n        <item>com.amazon.device.iap</item>\n        <item>com.amplifyframework.analytics.</item>\n        <item>com.amazon.device.associates</item>\n        <item>com.amberweather.sdk.amberadsdk.</item>\n        <item>yuku.ambilwarna</item>\n        <item>com.amobee.</item>\n        <item>com.amplitude.</item>\n        <item>com.anagog.jedai</item>\n        <item>com.npaw.youbora.</item>\n        <item>iamutkarshtiwari.github.io.ananas.editimage</item>\n        <item>com.yanzhenjie.permission</item>\n        <item>com.yanzhenjie.andserver</item>\n        <item>com.klinker.android.peekview</item>\n        <item>mehdi.sakout.aboutpage</item>\n        <item>androidx.savedstate</item>\n        <item>com.devspark.appmsg</item>\n        <item>xyz.klinker.android</item>\n        <item>com.loopj.android.http</item>\n        <item>com.blandware.android.atleap</item>\n        <item>no.nordicsemi.android.ble</item>\n        <item>org.altbeacon</item>\n        <item>com.google.androidbrowserhelper.trusted</item>\n        <item>com.github.abdularis.civ</item>\n        <item>com.dd.circular.progress.button</item>\n        <item>com.android.colorpicker</item>\n        <item>com.example.android.commitcontent.ime</item>\n        <item>com.alexvasilkov.android.commons</item>\n        <item>saschpe.android.customtabs</item>\n        <item>dev.robingenz.capacitor.androiddarkmodesupport</item>\n        <item>im.dino.dbinspector</item>\n        <item>io.palaima.debugdrawer</item>\n        <item>android.support.design</item>\n        <item>com.jaredrummler.android.device</item>\n        <item>com.github.tslamic.dn</item>\n        <item>tslamic.github.io.adn</item>\n        <item>net.rdrei.android.dirchooser</item>\n        <item>org.sufficientlysecure.donations</item>\n        <item>com.daimajia.easing</item>\n        <item>ren.qinc.edit</item>\n        <item>androidx.emoji2</item>\n        <item>com.github.jorgecastillo</item>\n        <item>angtrim.com.fivestarslibrary</item>\n        <item>io.ticofab.androidgpxparser.parser</item>\n        <item>com.cocoahero.android.geojson</item>\n        <item>com.almeros.android.multitouch</item>\n        <item>com.larswerkman.holocolorpicker</item>\n        <item>com.theartofdev.edmodo.cropper</item>\n        <item>com.daimajia.slider</item>\n        <item>com.anjlab.android.iab.v3</item>\n        <item>com.rbrooks.indefinitepagerindicator</item>\n        <item>com.android.tools.ir</item>\n        <item>com.android.internal</item>\n        <item>androidx.annotation</item>\n        <item>androidx.versionedparcelable</item>\n        <item>com.android.launcher3</item>\n        <item>com.android.quickstep</item>\n        <item>androidx.hilt</item>\n        <item>com.leff.midi</item>\n        <item>com.google.android.finsky</item>\n        <item>com.gc.android.market.api</item>\n        <item>com.pes.androidmaterialcolorpickerdialog</item>\n        <item>agency.tango.materialintroscreen</item>\n        <item>com.stepstone.stepper</item>\n        <item>androidx.multidex</item>\n        <item>com.vic797.edittextutils</item>\n        <item>com.vic797.syntaxhighlight</item>\n        <item>com.stealthcopter.networktools</item>\n        <item>net.simonvt.numberpicker</item>\n        <item>com.daimajia.numberprogressbar</item>\n        <item>com.wuman.android.auth</item>\n        <item>bz.tsung.android.objectify</item>\n        <item>com.chyrta.onboarder</item>\n        <item>android.content.pm</item>\n        <item>com.astuetz.pagerslidingtabstrip</item>\n        <item>com.github.barteksc.pdfviewer</item>\n        <item>com.quinny898.library.persistentsearch</item>\n        <item>io.codetailps</item>\n        <item>org.thoughtcrime.ssl</item>\n        <item>com.birbit.android.jobqueue</item>\n        <item>com.path.android.jobqueue</item>\n        <item>be.shouldit.proxy.lib</item>\n        <item>net.londatiga.android</item>\n        <item>one.block.eosiojavarpcprovider</item>\n        <item>com.github.lzyzsd.randomcolor</item>\n        <item>be.billington.calendar.recurrencepicker</item>\n        <item>com.spazedog.lib.rootfw</item>\n        <item>com.spazedog.lib.rootfw4</item>\n        <item>com.tns.android_runtime</item>\n        <item>com.tns.bindings</item>\n        <item>com.tns.system</item>\n        <item>com.klinker.android.send_message</item>\n        <item>io.requery.android.database</item>\n        <item>com.readystatesoftware.android.sqliteassethelper</item>\n        <item>com.readystatesoftware.sqliteasset</item>\n        <item>com.jaredrummler.android.shell</item>\n        <item>com.github.gcacace.signaturepad</item>\n        <item>io.github.douglasjunior.androidSimpleTooltip</item>\n        <item>com.klinker.android.simple_videoview</item>\n        <item>com.klinker.android.sliding</item>\n        <item>com.sothree.slidinguppanel</item>\n        <item>com.loopj.android.image</item>\n        <item>com.muddzdev.styleabletoastlibrary</item>\n        <item>androidx.customview</item>\n        <item>androidx.collection</item>\n        <item>androidx.tvprovider</item>\n        <item>android.support.v13</item>\n        <item>android.support.v4</item>\n        <item>android.support.v7</item>\n        <item>com.daimajia.swipe</item>\n        <item>com.github.brnunes.swipeablerecyclerview</item>\n        <item>org.jraf.android.backport.switchwidget</item>\n        <item>com.readystatesoftware.systembartint</item>\n        <item>com.bluejamesbond.text</item>\n        <item>com.klinker.android.link_builder</item>\n        <item>it.sephiroth.android.library.xtooltip</item>\n        <item>jp.kshoji.driver.midi</item>\n        <item>com.keenencharles.unsplash</item>\n        <item>net.gotev.uploadservice</item>\n        <item>com.daimajia.androidanimations</item>\n        <item>com.viewpagerindicator</item>\n        <item>com.google.android.gms.vision</item>\n        <item>io.gresse.hugo.vumeterlibrary</item>\n        <item>com.badoo.mobile</item>\n        <item>com.google.android.gms.wearable</item>\n        <item>com.alamkanak.weekview</item>\n        <item>com.example.android.wizardpager</item>\n        <item>com.exxbrain.android.biometric</item>\n        <item>com.vb.openlibraries.android.dualcache</item>\n        <item>com.vincentbrison.openlibraries.android.dualcache</item>\n        <item>org.apmem.tools.layouts</item>\n        <item>com.github.druk.dnssd</item>\n        <item>com.github.druk.rx2dnssd</item>\n        <item>com.github.druk.rxdnssd</item>\n        <item>io.liteglue</item>\n        <item>com.mikepenz.actionitembadge</item>\n        <item>uk.co.senab.bitmapcache</item>\n        <item>com.beardedhen.androidbootstrap</item>\n        <item>it.sephiroth.android.library.easing</item>\n        <item>it.sephiroth.android.library.exif2</item>\n        <item>com.github.zagum.expandicon</item>\n        <item>com.bosphere.fadingedgelayout</item>\n        <item>com.bosphere.filelogger</item>\n        <item>droidninja.filepicker</item>\n        <item>com.mikepenz.iconics</item>\n        <item>com.mikepenz.community_material_typeface_library</item>\n        <item>com.mikepenz.google_material_typeface_library</item>\n        <item>com.mikepenz.material_design_iconic_typeface_library</item>\n        <item>com.mikepenz.octicons_typeface_library</item>\n        <item>com.evernote.android.job</item>\n        <item>com.klinker.android.logger</item>\n        <item>com.jenzz.materialpreference</item>\n        <item>com.tinmegali.mvp</item>\n        <item>com.github.ksoichiro.android.observablescrollview</item>\n        <item>com.contrarywind.view</item>\n        <item>com.devspark.progressfragment</item>\n        <item>hotchemi.android.rate</item>\n        <item>com.kobakei.ratethisapp</item>\n        <item>com.akexorcist.roundcornerprogressbar</item>\n        <item>com.yqritc.scalablevideoview</item>\n        <item>com.jetradarmobile.snowfall</item>\n        <item>com.github.ybq.android.spinkit</item>\n        <item>com.evernote.android.state</item>\n        <item>com.takisoft.fix.support.v7.preference</item>\n        <item>org.beyka.tiffbitmapfactory</item>\n        <item>com.llollox.androidtoggleswitch</item>\n        <item>com.jensdriller.libs.undobar</item>\n        <item>com.winsontan520.wversionmanager</item>\n        <item>kankan.wheel.widget</item>\n        <item>com.googlecode.androidannotations</item>\n        <item>org.androidannotations</item>\n        <item>com.koushikdutta.async</item>\n        <item>me.jessyan.autosize</item>\n        <item>com.youth.banner</item>\n        <item>com.thefinestartist</item>\n        <item>com.kunzisoft.androidclearchroma</item>\n        <item>dev.jorgecastillo.androidcolorx.library</item>\n        <item>com.asksven.android.common</item>\n        <item>android.didikee.donate</item>\n        <item>com.bullhead.equalizer</item>\n        <item>me.zhanghai.android.fastscroll</item>\n        <item>org.lsposed.hiddenapibypass</item>\n        <item>com.itsaky.androidide</item>\n        <item>com.lxj.androidktx</item>\n        <item>com.naman14.androidlame</item>\n        <item>com.hzy.libmagic</item>\n        <item>com.zomato.photofilters</item>\n        <item>com.azeesoft.lib.colorpicker</item>\n        <item>com.jaredrummler.android.processes</item>\n        <item>com.androidquery</item>\n        <item>com.etsy.android.grid</item>\n        <item>com.ahmadrosid.svgloader</item>\n        <item>com.unnamed.b.atv</item>\n        <item>de.mrapp.android.util</item>\n        <item>com.blankj.utilcode</item>\n        <item>com.tianscar.androidutils</item>\n        <item>com.skydoves.androidveil</item>\n        <item>com.danikula.videocache</item>\n        <item>androidx.activity</item>\n        <item>androidx.car.app</item>\n        <item>androidx.cursoradapter</item>\n        <item>androidx.emoji</item>\n        <item>androidx.fragment</item>\n        <item>androidx.gridlayout</item>\n        <item>androidx.inspection</item>\n        <item>androidx.localbroadcastmanager</item>\n        <item>androidx.percentlayout</item>\n        <item>com.takisoft.preferencex</item>\n        <item>androidx.security</item>\n        <item>androidx.test</item>\n        <item>androidx.wear</item>\n        <item>androidx.viewpager2</item>\n        <item>com.androidplot</item>\n        <item>androidx.core</item>\n        <item>anet.channel</item>\n        <item>com.github.AlexLiuSheng.AnimSideBar</item>\n        <item>com.anthonycr.progress</item>\n        <item>com.jaredrummler.android.animatedsvgview</item>\n        <item>com.jaredrummler.android.widget</item>\n        <item>org.jetbrains.anko</item>\n        <item>com.anvato.androidsdk.</item>\n        <item>com.car2go.maps</item>\n        <item>com.anysdk.framework.AnalyticsWrapper</item>\n        <item>com.anysdk.framework.AdsWrapper</item>\n        <item>com.anzu.sdk.</item>\n        <item>org.apache.tools</item>\n        <item>org.apache.commons</item>\n        <item>org.apache.cordova</item>\n        <item>org.apache.felix</item>\n        <item>freemarker</item>\n        <item>org.apache.ftpserver</item>\n        <item>org.apache.harmony</item>\n        <item>org.apache.http</item>\n        <item>org.apache.hc</item>\n        <item>org.apache.jackrabbit</item>\n        <item>org.apache.james</item>\n        <item>org.apache.log4j</item>\n        <item>org.apache.lucene</item>\n        <item>org.apache.mina</item>\n        <item>org.apache.maven.scm</item>\n        <item>org.apache.oltu</item>\n        <item>org.apache.openjpa</item>\n        <item>org.apache.poi</item>\n        <item>org.apache.pig</item>\n        <item>org.apache.velocity</item>\n        <item>org.apache.xmlcommons</item>\n        <item>org.apache.xerces</item>\n        <item>org.apache.xml.serialize</item>\n        <item>org.apache.wml</item>\n        <item>org.apache.html.dom</item>\n        <item>org.apfloat</item>\n        <item>apktool</item>\n        <item>brut.androlib</item>\n        <item>brut.common</item>\n        <item>brut.directory</item>\n        <item>brut.util</item>\n        <item>io.github.jeffshee.apng2gif</item>\n        <item>com.linecorp.apng</item>\n        <item>com.apollographql.apollo</item>\n        <item>com.apollographql.apollo3</item>\n        <item>com.microsoft.appcenter.push</item>\n        <item>com.appsamurai.</item>\n        <item>com.afollestad.appthemeengine</item>\n        <item>com.kabouzeid.appthemehelper</item>\n        <item>io.appanalytics.sdk</item>\n        <item>net.openid.appauth</item>\n        <item>com.appbrain.</item>\n        <item>androidx.appcompat</item>\n        <item>com.sfbx.appconsent.</item>\n        <item>me.zhanghai.android.appiconloader</item>\n        <item>com.dci.dev.appinfobadge</item>\n        <item>com.github.appintro</item>\n        <item>com.thelittlefireman.appkillermanager</item>\n        <item>me.grishka.appkit</item>\n        <item>io.applink.applinkio.AppLinkIO</item>\n        <item>com.applink.security.</item>\n        <item>com.applovin</item>\n        <item>com.yandex.metrica.</item>\n        <item>com.monet.</item>\n        <item>com.appnexus.opensdk.</item>\n        <item>com.tjeannin.apprate</item>\n        <item>com.gryphonet:appright</item>\n        <item>com.appsee.</item>\n        <item>com.github.javiersantos.appupdater</item>\n        <item>com.appvador.ads.</item>\n        <item>com.appzilo.sdk.</item>\n        <item>org.appcelerator</item>\n        <item>com.appcelerator.aps.</item>\n        <item>org.appcelerator.titanium.analytics</item>\n        <item>com.appdynamics.</item>\n        <item>com.appenda.</item>\n        <item>com.apperhand.device.</item>\n        <item>com.appirits.pusher.</item>\n        <item>com.applause.android.</item>\n        <item>me.apla.cordova</item>\n        <item>com.hf.appliftsdk.</item>\n        <item>com.appnext.sdk</item>\n        <item>com.appodeal.ads.</item>\n        <item>com.appodealx.</item>\n        <item>com.explorestack.</item>\n        <item>com.appsflyer.</item>\n        <item>com.appsgeyser.sdk</item>\n        <item>com.appsgeyser.multiTabApp.VideoPlayerActivity</item>\n        <item>com.apptentive.</item>\n        <item>com.apptimize.</item>\n        <item>biz.appvisor.push.android.sdk</item>\n        <item>com.apsalar.sdk.</item>\n        <item>com.crittercism.app.Crittercism</item>\n        <item>androidx.arch</item>\n        <item>com.mrtyvz.archedimageprogress</item>\n        <item>com.areametrics.areametricssdk</item>\n        <item>com.areametrics.nosdkandroid</item>\n        <item>net.sourceforge.argparse4j</item>\n        <item>com.fernandocejas.arrow</item>\n        <item>com.askingpoint.</item>\n        <item>com.afollestad.ason</item>\n        <item>com.santalu.aspectratioimageview</item>\n        <item>org.aspectj</item>\n        <item>com.afollestad.assent</item>\n        <item>org.astiansuite.libs</item>\n        <item>org.asynchttpclient</item>\n        <item>co.metalab.asyncawait</item>\n        <item>com.arasthel.asyncjob</item>\n        <item>androidx.asynclayoutinflater</item>\n        <item>com.musenkishi.atelier</item>\n        <item>kotlinx.atomicfu</item>\n        <item>me.jfenn.attribouter</item>\n        <item>com.franmontiel.attributionpresenter</item>\n        <item>com.krux.androidsdk</item>\n        <item>com.gauravk.audiovisualizer</item>\n        <item>org.firezenk.audiowaves</item>\n        <item>com.cleveroad.audiowidget</item>\n        <item>nl.changer.audiowife</item>\n        <item>in.basulabs.audiofocuscontroller</item>\n        <item>xyz.luan.audioplayers</item>\n        <item>com.visualizer.amplitude</item>\n        <item>rm.com.audiowave</item>\n        <item>org.audiostream</item>\n        <item>com.auditude.ads</item>\n        <item>com.google.auto</item>\n        <item>com.stardust.autojs</item>\n        <item>com.uber.autodispose</item>\n        <item>com.uber.autodispose2</item>\n        <item>com.lb.auto_fit_textview</item>\n        <item>com.luseen.autolinklibrary</item>\n        <item>auto.parcel</item>\n        <item>de.ankri.views</item>\n        <item>com.ryanharter.auto.value</item>\n        <item>com.github.reggar.ignorehashequals</item>\n        <item>de.tavendo.autobahn</item>\n        <item>androidx.autofill</item>\n        <item>com.automattic.android.tracks</item>\n        <item>com.tonikorin.cordova.plugin.autostart</item>\n        <item>com.judemanutd.autostarter</item>\n        <item>com.github.michaelwuensch.avathorlibrary</item>\n        <item>az.nativead.</item>\n        <item>com.avazu.tracking.</item>\n        <item>com.avocarrot.sdk</item>\n        <item>me.carda.awesome_notifications</item>\n        <item>com.github.sumimakito.awesomeqr</item>\n        <item>com.viksaa.sssplash</item>\n        <item>com.axonix.android.sdk</item>\n        <item>com.mobclix.android.sdk</item>\n        <item>com.azure</item>\n        <item>anywheresoftware.b4a</item>\n        <item>anywheresoftware.b4j</item>\n        <item>cn.bingoogolapple.bgabanner</item>\n        <item>cn.bingoogolapple.qrcode</item>\n        <item>com.github.orogvany.bip32</item>\n        <item>com.github.orogvany.bip39</item>\n        <item>io.github.novacrypto.bip39</item>\n        <item>com.bitsofproof.supernode</item>\n        <item>com.bottlerocketstudios.vault</item>\n        <item>com.chad.library</item>\n        <item>org.bson</item>\n        <item>com.babator.babatorui.</item>\n        <item>com.backelite.android.</item>\n        <item>com.backelite.bkdroid.</item>\n        <item>com.backendless.</item>\n        <item>com.github.backtrace-labs.</item>\n        <item>backtraceio.library.</item>\n        <item>cn.nekocode.badge</item>\n        <item>com.allenliu.badgeview</item>\n        <item>com.baidu.appx</item>\n        <item>com.baidu.crashpad.</item>\n        <item>com.baidu.xenv.</item>\n        <item>com.baidu.location</item>\n        <item>com.baidu.mapapi</item>\n        <item>com.baidu.BaiduMap</item>\n        <item>com.baidu.mobads</item>\n        <item>com.baidu.mobstat</item>\n        <item>com.baidu.navi</item>\n        <item>com.skydoves.balloon</item>\n        <item>com.zhpan.bannerview</item>\n        <item>com.barchart.udt</item>\n        <item>com.dutchconcepts.capacitor.barcodescanner</item>\n        <item>com.kroegerama.kaiteki.bcode</item>\n        <item>biz.source_code.base64Coder</item>\n        <item>razerdp.basepopup</item>\n        <item>razerdp.blur</item>\n        <item>razerdp.util</item>\n        <item>razerdp.widget</item>\n        <item>com.batch.android.</item>\n        <item>com.bazaarvoice.bvandroidsdk</item>\n        <item>at.favre.lib.crypto.bcrypt</item>\n        <item>jp.beaconbank.</item>\n        <item>com.beaconsinspace.android.beacon.detector.</item>\n        <item>com.beaglebuddy</item>\n        <item>javax.validation</item>\n        <item>com.beemray.</item>\n        <item>com.beintoo.nucleon</item>\n        <item>com.jhomlala.better_player</item>\n        <item>com.halilibo.bettervideoplayer</item>\n        <item>me.saket.bettermovementmethod</item>\n        <item>com.weiwangcn.betterspinner.library</item>\n        <item>org.ironrabbit</item>\n        <item>io.michaelrocks.bimap</item>\n        <item>io.bidmachine.</item>\n        <item>com.github.kiprobinson.bigfraction</item>\n        <item>com.github.piasy.biv</item>\n        <item>bikramsambat</item>\n        <item>com.android.billingclient</item>\n        <item>com.binance.dex.api</item>\n        <item>com.ironz.binaryprefs</item>\n        <item>me.tatarka.bindingcollectionadapter</item>\n        <item>me.tatarka.bindingcollectionadapter2</item>\n        <item>androidx.biometric</item>\n        <item>ai.bitlabs.sdk.</item>\n        <item>org.bitpedia.collider</item>\n        <item>org.bitpedia.util</item>\n        <item>com.bitly.Bitly</item>\n        <item>com.rfksystems.blake2b</item>\n        <item>com.blesh.sdk.</item>\n        <item>com.blueconic</item>\n        <item>com.intel.bluetooth</item>\n        <item>com.bluekai.sdk.</item>\n        <item>com.bluecats.sdk</item>\n        <item>dev.jahir.blueprint</item>\n        <item>me.aflak.bluetooth</item>\n        <item>me.aflak.bluetooth_library</item>\n        <item>eightbitlab.com.blurview</item>\n        <item>com.mrousavy.blurhash</item>\n        <item>jp.wasabeef.blurry</item>\n        <item>cn.bmob</item>\n        <item>com.parse.bolts</item>\n        <item>org.bondlib</item>\n        <item>com.roughike.bottombar</item>\n        <item>com.github.javiersantos.bottomdialogs</item>\n        <item>com.ittianyu.bottomnavigationviewex</item>\n        <item>com.cocosw.bottomsheet</item>\n        <item>com.github.rubensousa.bottomsheetbuilder</item>\n        <item>com.philliphsu.bottomsheetpickers</item>\n        <item>org.sandrob.bouncycastle</item>\n        <item>com.braintreepayments.api</item>\n        <item>io.branch.</item>\n        <item>com.brandio.ads</item>\n        <item>com.appboy</item>\n        <item>moe.feng.common.view.breadcrumbs</item>\n        <item>com.afollestad.bridge</item>\n        <item>com.brightcove</item>\n        <item>androidx.browser</item>\n        <item>com.igalata.bubblepicker</item>\n        <item>com.xw.repo.bubbleseekbar</item>\n        <item>com.bugclipper.android.</item>\n        <item>com.bugsense.trace.</item>\n        <item>com.bugfender.sdk.</item>\n        <item>com.buglife.sdk.</item>\n        <item>com.tencent.bugly.</item>\n        <item>com.tencent.bugly</item>\n        <item>com.bugsee.library.Bugsee</item>\n        <item>com.bugsnag.</item>\n        <item>net.md_5.bungee</item>\n        <item>butterknife</item>\n        <item>com.usebutton.sdk.</item>\n        <item>com.subsub.library</item>\n        <item>com.buzzvil.</item>\n        <item>in.uncod.android.bypass</item>\n        <item>net.bytebuddy</item>\n        <item>com.adfonic.</item>\n        <item>eu.livotov.labs.android.camview</item>\n        <item>net.vrallev.android.cat</item>\n        <item>com.upokecenter.cbor</item>\n        <item>co.nstant.in.cbor</item>\n        <item>org.benf.cfr</item>\n        <item>com.cryptape.cita</item>\n        <item>com.github.gzuliyujiang.chardet</item>\n        <item>com.steadystate.css</item>\n        <item>com.commonsware.cwac.anddown</item>\n        <item>com.commonsware.cwac.colormixer</item>\n        <item>com.commonsware.cwac.layouts</item>\n        <item>com.commonsware.cwac.richedit</item>\n        <item>com.commonsware.cwac.wakeful</item>\n        <item>com.commonsware.cwac.pager</item>\n        <item>com.pyamsoft.cachify</item>\n        <item>com.github.benmanes.caffeine</item>\n        <item>com.caldroid</item>\n        <item>com.roomorama.caldroid</item>\n        <item>com.kizitonwose.calendarview</item>\n        <item>com.callcontrol.datashare</item>\n        <item>com.calldorado.android</item>\n        <item>com.dylanc.callbacks</item>\n        <item>me.anwarshahriar.calligrapher</item>\n        <item>io.github.inflationx.calligraphy3</item>\n        <item>com.reactnativecommunity.cameraroll</item>\n        <item>com.google.android.cameraview</item>\n        <item>androidx.camera</item>\n        <item>candybar.lib</item>\n        <item>capacitor.android</item>\n        <item>com.byteowls.capacitor.oauth2</item>\n        <item>com.capacitorjs.plugins</item>\n        <item>com.tchvu3.capacitorvoicerecorder</item>\n        <item>com.caramelads.</item>\n        <item>carbon</item>\n        <item>it.gmariotti.cardslib</item>\n        <item>com.google.cardboard.sdk</item>\n        <item>com.fima.cardsui</item>\n        <item>androidx.cardview</item>\n        <item>com.carnival.sdk</item>\n        <item>com.carnivalmobile</item>\n        <item>com.nutiteq</item>\n        <item>com.carto</item>\n        <item>com.carto</item>\n        <item>com.google.android.libraries.cast.companionlibrary</item>\n        <item>com.jhomlala.catcher</item>\n        <item>cats</item>\n        <item>jp.caulis.fraud.sdk</item>\n        <item>com.fsn.cauly</item>\n        <item>com.trid.tridad</item>\n        <item>com.cauly.android.ad.</item>\n        <item>com.cedexis</item>\n        <item>org.mariotaku.chameleon</item>\n        <item>it.gmariotti.changelibs</item>\n        <item>com.michaelflisar.changelog</item>\n        <item>com.chaquo.python.android</item>\n        <item>com.chartboost.sdk.</item>\n        <item>com.hadiidbouk.charts</item>\n        <item>com.chartbeat.androidsdk</item>\n        <item>com.stfalcon.chatkit</item>\n        <item>org.chatsecure.pushsecure</item>\n        <item>com.allenliu.versionchecklib</item>\n        <item>afu.org.checkerframework</item>\n        <item>org.checkerframework</item>\n        <item>top.defaults.checkerboarddrawable</item>\n        <item>org.solovyev.android.checkout</item>\n        <item>com.cmcm.</item>\n        <item>eu.fiskur.chipcloud</item>\n        <item>com.tylersuehr.chips</item>\n        <item>com.beloo.widget.chipslayoutmanager</item>\n        <item>com.cyph.cordova</item>\n        <item>org.chromium.customtabsclient</item>\n        <item>org.chromium.net</item>\n        <item>org.chromium.url</item>\n        <item>su.litvak.chromecast.api.v2</item>\n        <item>de.mrapp.android.tabswitcher</item>\n        <item>xyz.aprildown.chromemenu</item>\n        <item>org.chromium.base</item>\n        <item>org.chromium.build</item>\n        <item>com.readystatesoftware.chuck</item>\n        <item>com.chuckerteam.chucker</item>\n        <item>com.x5.template</item>\n        <item>com.x5.util</item>\n        <item>ru.terrakok.cicerone</item>\n        <item>com.cifrasoft.</item>\n        <item>net.idik.lib.cipher</item>\n        <item>de.hdodenhof.circleimageview</item>\n        <item>me.relex.circleindicator</item>\n        <item>com.allenliu.CircleMenuView</item>\n        <item>com.github.lzyzsd.circleprogress</item>\n        <item>com.dinuscxj.progressbar</item>\n        <item>com.budiyev.android.circularprogressbar</item>\n        <item>com.mikhaellopez.circularimageview</item>\n        <item>com.mikhaellopez.circularprogressbar</item>\n        <item>antonkozyriatskyi.circularprogressindicator</item>\n        <item>io.codetail</item>\n        <item>me.tankery.lib.circularseekbar</item>\n        <item>com.google.classysharkandroid</item>\n        <item>io.cleaninsights.sdk.piwik.</item>\n        <item>com.clearblade.platform.api.</item>\n        <item>com.clevertap.</item>\n        <item>org.fourthline.cling</item>\n        <item>org.teleal.cling</item>\n        <item>com.google.cloud.audit</item>\n        <item>com.cloudrail.si</item>\n        <item>com.cloudtech.</item>\n        <item>org.cocos2dx</item>\n        <item>com.budiyev.android.codescanner</item>\n        <item>com.github.ahmadaghazadeh.editor</item>\n        <item>io.github.kbiakov.codeview</item>\n        <item>com.github.sumimakito.codeauxlib</item>\n        <item>com.ustadmobile.codec2</item>\n        <item>hidden.org.codehaus.plexus</item>\n        <item>org.codehaus.plexus</item>\n        <item>me.regexp</item>\n        <item>coil</item>\n        <item>irismod.coinswap</item>\n        <item>com.google.android.collect</item>\n        <item>net.crowdconnected.androidcolocator</item>\n        <item>com.flask.colorpicker</item>\n        <item>com.chiralcode.colorpicker</item>\n        <item>com.kizitonwose.colorpreference</item>\n        <item>com.kizitonwose.colorpreferencecompat</item>\n        <item>es.dmoral.coloromatic</item>\n        <item>com.kennyc.colorchooser</item>\n        <item>com.fourmob.colorpicker</item>\n        <item>me.uucky.colorpicker</item>\n        <item>me.jfenn.colorpickerdialog</item>\n        <item>net.margaritov.preference.colorpicker</item>\n        <item>afzkl.development.colorpickerview</item>\n        <item>com.saggitt.colorpickerx</item>\n        <item>dev.sasikanth.colorsheet</item>\n        <item>com.github.ajalt.colormath</item>\n        <item>com.comscore.</item>\n        <item>com.comm100.livechat</item>\n        <item>com.yuyh.library</item>\n        <item>com.gianlu.commonutils</item>\n        <item>org.mariotaku.commons</item>\n        <item>com.commonsware.cwac.merge</item>\n        <item>com.commonsware.cwac.sacklist</item>\n        <item>com.github.sundeepk.compactcalendarview</item>\n        <item>com.smarttoolfactory.slider</item>\n        <item>com.ramcosta.composedestinations</item>\n        <item>com.vanpra.composematerialdialogs</item>\n        <item>dev.patrickgold.compose.tooltip</item>\n        <item>id.zelory.compressor</item>\n        <item>com.comscore</item>\n        <item>com.facebook.android.crypto.keychain</item>\n        <item>com.facebook.crypto</item>\n        <item>androidx.concurrent</item>\n        <item>com.googlecode.concurrenttrees</item>\n        <item>com.bluelinelabs.conductor</item>\n        <item>com.garmin.android.apps.connectmobile.connectiq</item>\n        <item>com.garmin.android.connectiq</item>\n        <item>org.connectbot</item>\n        <item>com.android.org.conscrypt</item>\n        <item>org.conscrypt</item>\n        <item>com.jraska.console</item>\n        <item>androidx.constraintlayout</item>\n        <item>ch.byrds.capacitor.contacts</item>\n        <item>com.contentsquare.android.</item>\n        <item>com.yalantis.contextmenu</item>\n        <item>com.conversantmedia</item>\n        <item>com.greystripe.android.</item>\n        <item>com.conviva.</item>\n        <item>org.aviran.cookiebar2</item>\n        <item>com.cooladata.android.</item>\n        <item>androidx.coordinatorlayout</item>\n        <item>app.cash.copper</item>\n        <item>com.silkimen.cordovahttp</item>\n        <item>com.silkimen.http</item>\n        <item>com.rareloop.cordova.appversion</item>\n        <item>de.appplant.cordova.plugin.background</item>\n        <item>de.appplant.cordova.plugin.badge</item>\n        <item>cordova.plugins.crosswalk</item>\n        <item>com.koenromers.cordova</item>\n        <item>com.whebcraft.android.plugin</item>\n        <item>de.appplant.cordova.emailcomposer</item>\n        <item>com.homerours.musiccontrols</item>\n        <item>com.rjfun.cordova.plugin.nativeaudio</item>\n        <item>com.rjfun.cordova.ext</item>\n        <item>com.plugin.gcm</item>\n        <item>com.cordova.plugins.sms</item>\n        <item>cordova.plugins.screenorientation</item>\n        <item>nl.xservices.plugins</item>\n        <item>com.nordnetab.cordova</item>\n        <item>de.mariusbackes.cordova.plugin</item>\n        <item>com.ideas2it.aes256</item>\n        <item>com.verso.cordova.clipboard</item>\n        <item>com.couchbase.lite</item>\n        <item>com.couchbase.litecore</item>\n        <item>coelib.c.couluslibrary</item>\n        <item>ly.count.android.</item>\n        <item>in.sunilpaulmathew.crashreporter</item>\n        <item>com.balsikandar.crashreporter</item>\n        <item>com.crashsdk.</item>\n        <item>com.developer.crashx</item>\n        <item>io.fabric.</item>\n        <item>com.crashlytics.</item>\n        <item>com.google.firebase.crashlytics</item>\n        <item>com.google.firebase.crash.</item>\n        <item>io.invertase.firebase.crashlytics.</item>\n        <item>com.crazylegend.crashyreporter</item>\n        <item>jp.ac.kobe_u.cs.cream</item>\n        <item>com.criteo.</item>\n        <item>io.inventiv.critic.android</item>\n        <item>com.criware</item>\n        <item>com.google.net.cronet.okhttptransport</item>\n        <item>com.mikepenz.crossfadedrawerlayout</item>\n        <item>com.mikepenz.crossfader</item>\n        <item>de.keyboardsurfer.android.widget.crouton</item>\n        <item>com.crowdin.platform</item>\n        <item>com.evidon.</item>\n        <item>com.chimbori.crux</item>\n        <item>com.lambdaworks.crypto</item>\n        <item>com.lambdaworks.jni</item>\n        <item>com.andreacioccarelli.cryptoprefs</item>\n        <item>com.csvreader</item>\n        <item>in.srain.cube</item>\n        <item>com.cuebiq.cuebiqsdk.model.Collector</item>\n        <item>com.cuebiq.cuebiqsdk.receiver.CoverageReceiver</item>\n        <item>com.mynameismidori.currencypicker</item>\n        <item>com.squareup.curtains</item>\n        <item>curtains.internal</item>\n        <item>cat.ereza.customactivityoncrash</item>\n        <item>ir.farshid_roohi.customadapterrecycleview</item>\n        <item>com.crazylegend.customviews</item>\n        <item>com.zarinpal.libs.views</item>\n        <item>com.mahc.custombottomsheetbehavior</item>\n        <item>me.zhanghai.android.customtabshelper</item>\n        <item>com.libRG</item>\n        <item>com.jaredrummler.cyanea</item>\n        <item>com.android.tools.r8</item>\n        <item>hirondelle.date4j</item>\n        <item>com.raizlabs.android.dbflow</item>\n        <item>com.dmm.asdk.api</item>\n        <item>org.littleshoot.dnssec4j</item>\n        <item>com.dv.DVSDK</item>\n        <item>me.dozen.dpreference</item>\n        <item>dagger</item>\n        <item>com.thinkyeah.common.</item>\n        <item>com.f2prateek.dart</item>\n        <item>com.google.android.apps.dashclock.api</item>\n        <item>com.thirtydegreesray.dataautoaccess</item>\n        <item>androidx.datastore</item>\n        <item>com.upokecenter.util</item>\n        <item>androidx.databinding</item>\n        <item>com.databox.</item>\n        <item>com.datadoghq</item>\n        <item>com.afollestad.date</item>\n        <item>com.savvi.rangedatepicker</item>\n        <item>com.fourmob.datetimepicker</item>\n        <item>com.incross.dawin</item>\n        <item>com.locationvalue.</item>\n        <item>io.palaima.debugdrawer.</item>\n        <item>com.airbnb.android.deeplinkdispatch</item>\n        <item>com.airbnb.deeplinkdispatch</item>\n        <item>com.deezer.sdk</item>\n        <item>com.catchingnow.delegatedscopesmanager</item>\n        <item>com.adobe.mobile.Analytics</item>\n        <item>com.adobe.mobile.Config.</item>\n        <item>dalvik.system.DexClassLoader</item>\n        <item>com.android.dx</item>\n        <item>com.karumi.dexter</item>\n        <item>com.github.florent37.diagonallayout</item>\n        <item>com.orhanobut.dialogplus</item>\n        <item>io.didomi.sdk.</item>\n        <item>eu.ehn.dcc.certlogic</item>\n        <item>cn.shuzilm.core.</item>\n        <item>com.discord.analytics</item>\n        <item>fr.nicolaspomepuy.discreetapprate</item>\n        <item>com.yarolegovich.discretescrollview</item>\n        <item>org.adw.library.widgets.discreteseekbar</item>\n        <item>com.jakewharton.disklrucache</item>\n        <item>com.github.Justson.dispatch-queue</item>\n        <item>com.queue.library</item>\n        <item>io.display.</item>\n        <item>androidx.documentfile</item>\n        <item>dev.doubledot.doki</item>\n        <item>app.futured.donut</item>\n        <item>com.google.android.gms.ads.doubleclick</item>\n        <item>com.download.library</item>\n        <item>com.ernestoyaquello.dragdropswiperecyclerview</item>\n        <item>com.afollestad.dragselectrecyclerview</item>\n        <item>com.jmedeisis.draglinearlayout</item>\n        <item>com.woxthebox.draglistview</item>\n        <item>com.ericharlow.DragNDrop</item>\n        <item>com.mobeta.android.dslv</item>\n        <item>top.defaults.drawabletoolbox</item>\n        <item>androidx.drawerlayout</item>\n        <item>pl.droidsonroids.relinker</item>\n        <item>com.dropbox.core</item>\n        <item>com.dropbox.client2</item>\n        <item>com.shehabic.droppy</item>\n        <item>com.duapps.</item>\n        <item>com.squareup.duktape</item>\n        <item>com.furture.react</item>\n        <item>com.dynamicyield.</item>\n        <item>org.askerov.dynamicgrid</item>\n        <item>androidx.dynamicanimation</item>\n        <item>com.dynatrace.android.app</item>\n        <item>com.dynatrace.agent</item>\n        <item>com.dynatrace.tools</item>\n        <item>net.vrallev.java.ecc</item>\n        <item>org.eclipse.egit</item>\n        <item>one.block.eosiojava</item>\n        <item>one.block.eosiojavaabieosserializationprovider</item>\n        <item>one.block.eosiosoftkeysignatureprovider</item>\n        <item>de.epgpaid</item>\n        <item>com.evrythng</item>\n        <item>siclo.com.photointenthelper</item>\n        <item>siclo.com.ezphotopicker</item>\n        <item>org.jeasy.rules</item>\n        <item>com.yuyh.easyadapter</item>\n        <item>com.github.AlexLiuSheng.EasyBluetoothFrame</item>\n        <item>com.vstechlab.easyfonts</item>\n        <item>com.vstechlab.testeasyfont</item>\n        <item>pl.aprilapps.easyphotopicker</item>\n        <item>pub.devrel.easypermissions</item>\n        <item>com.vmadalin.easypermissions</item>\n        <item>com.pixplicity.easyprefs.library</item>\n        <item>com.jude.easyrecyclerview</item>\n        <item>com.grizzly.rest</item>\n        <item>org.eclipse.core</item>\n        <item>org.eclipse.equinox</item>\n        <item>org.eclipse.jdt</item>\n        <item>org.eclipse.jetty</item>\n        <item>org.eclipse.paho.android.service</item>\n        <item>org.eclipse.jface.text</item>\n        <item>org.eclipse.text</item>\n        <item>org.eclipse.tm4e</item>\n        <item>net.i2p.crypto.eddsa</item>\n        <item>com.gregacucnik.edittextview</item>\n        <item>com.editor</item>\n        <item>io.moatwel</item>\n        <item>com.otaliastudios.opengl</item>\n        <item>com.hawk</item>\n        <item>com.commit451.elasticdragdismisslayout</item>\n        <item>com.emarsys.predict</item>\n        <item>io.embrace.android.embracesdk.</item>\n        <item>com.vladium.emma</item>\n        <item>com.vanniktech.emoji</item>\n        <item>com.github.viirus.emojilib</item>\n        <item>net.pherth.android</item>\n        <item>github.ankushsachdeva.emojicon</item>\n        <item>com.athkalia.emphasis</item>\n        <item>se.simbio.encryption</item>\n        <item>third.part.android.util</item>\n        <item>co.enhance.Enhance</item>\n        <item>de.timroes.android.listview</item>\n        <item>dev.enro</item>\n        <item>enro_generated_bindings</item>\n        <item>com.ensighten.</item>\n        <item>me.weishu.epic</item>\n        <item>com.epicgames.mobile.eossdk</item>\n        <item>.services.analytics.AnalyticsProviderService</item>\n        <item>.services.analytics.HeartbeatJobService</item>\n        <item>com.airbnb.epoxy</item>\n        <item>me.ag2s.epublib</item>\n        <item>scalan</item>\n        <item>sigmastate.interpreter</item>\n        <item>special.collection</item>\n        <item>special.sigma</item>\n        <item>special.wrappers</item>\n        <item>com.google.errorprone</item>\n        <item>tr.xip.errorview</item>\n        <item>com.esri.arcgisruntime.</item>\n        <item>org.greenrobot.essentials</item>\n        <item>com.estimote.</item>\n        <item>com.eulerian.android.sdk</item>\n        <item>dev.nick.eventbus</item>\n        <item>com.alexvasilkov.events</item>\n        <item>com.evidon.</item>\n        <item>com.exacttarget.</item>\n        <item>androidx.exifinterface</item>\n        <item>com.devbrackets.android.exomedia</item>\n        <item>com.google.android.exoplayer2</item>\n        <item>com.daasuu.epf</item>\n        <item>com.github.aakira.expandablelayout</item>\n        <item>com.bignerdranch.expandablerecyclerview</item>\n        <item>github.com.st235.lib_expandablebottombar</item>\n        <item>com.nambimobile.widgets.efab</item>\n        <item>com.skydoves.expandablelayout</item>\n        <item>com.ms.square.android.expandabletextview</item>\n        <item>com.github.florent37.expansionpanel</item>\n        <item>tyrant.explosionfield</item>\n        <item>tyrantgit.explosionfield</item>\n        <item>expo.core</item>\n        <item>com.infinario.android.infinariosdk.</item>\n        <item>com.exponea.sdk</item>\n        <item>com.sygic.aura.</item>\n        <item>com.lnikkila.extendedtouchview</item>\n        <item>com.adobe.internal.xmp</item>\n        <item>com.ew.sdk.adboost.</item>\n        <item>.adboost.</item>\n        <item>com.github.kyuubiran.ezxhelper</item>\n        <item>org.fdroid.fdroid.privileged</item>\n        <item>jp.appAdForce.android.</item>\n        <item>com.github.jorgecastilloprz.listeners</item>\n        <item>com.github.jorgecastilloprz.progressarc</item>\n        <item>com.github.jorgecastilloprz.completefab</item>\n        <item>ffimageloading</item>\n        <item>com.arthenica.ffmpegkit</item>\n        <item>wseemann.media</item>\n        <item>com.fluzo.sdk.</item>\n        <item>org.fmod</item>\n        <item>mbanje.kurt.fabbutton</item>\n        <item>com.github.fabtransitionactivity</item>\n        <item>io.fabric.sdk.android</item>\n        <item>com.facebook.ads</item>\n        <item>com.facebook.appevents</item>\n        <item>com.facebook.marketing.</item>\n        <item>com.facebook.CampaignTrackingReceiver</item>\n        <item>com.facebook.audiencenetwork</item>\n        <item>com.facebook.flipper</item>\n        <item>com.facebook.gamingservices</item>\n        <item>com.facebook.login</item>\n        <item>com.facebook.notifications</item>\n        <item>com.facebook.places</item>\n        <item>com.facebook.applinks</item>\n        <item>com.facebook.devicerequests</item>\n        <item>com.facebook.internal</item>\n        <item>com.facebook.login</item>\n        <item>com.facebook.messenger</item>\n        <item>com.facebook.notifications</item>\n        <item>com.facebook.places</item>\n        <item>com.facebook.share</item>\n        <item>com.facebook.share</item>\n        <item>com.facebook.unity</item>\n        <item>com.factual.engine</item>\n        <item>com.factual.Factual</item>\n        <item>com.manuelpeinado.fadingactionbar</item>\n        <item>me.toptas.fancyshowcase</item>\n        <item>com.shashank.sony.fancytoastlib</item>\n        <item>mehdi.sakout.fancybuttons</item>\n        <item>com.androidnetworking</item>\n        <item>com.mikepenz.fastadapter</item>\n        <item>com.mikepenz.fastadapter_extensions</item>\n        <item>com.dylanvann.fastimage</item>\n        <item>fastparse</item>\n        <item>com.l4digital.fastscroll</item>\n        <item>com.mixiaoxiao.fastscroll</item>\n        <item>com.jaredrummler.fastscrollrecyclerview</item>\n        <item>lb.fast_scroller_and_recycler_view_fixes_library</item>\n        <item>com.fasterxml.jackson</item>\n        <item>org.codejargon.feather</item>\n        <item>com.tonyodev.fetch2</item>\n        <item>com.fidzup.</item>\n        <item>nordpol.android</item>\n        <item>com.halfhp.fig</item>\n        <item>com.fiksu.asotracking</item>\n        <item>com.google.android.filament</item>\n        <item>com.rustamg.filedialogs</item>\n        <item>com.mr.flutter.plugin.filepicker</item>\n        <item>com.archos.filecorelibrary</item>\n        <item>com.github.donmor.filedialog</item>\n        <item>com.liulishuo.filedownloader</item>\n        <item>com.developer.filepicker</item>\n        <item>de.c1710.filemojicompat_ui</item>\n        <item>edu.umd.cs.findbugs</item>\n        <item>nl.picnic.fingerpaintview</item>\n        <item>tech.picnic.fingerpaintview</item>\n        <item>com.multidots.fingerprintauth</item>\n        <item>com.wei.android.lib.fingerprintidentify</item>\n        <item>com.google.firebase.annotations</item>\n        <item>com.google.firebase.appindexing</item>\n        <item>com.google.firebase.auth</item>\n        <item>com.google.firebase.components</item>\n        <item>com.google.firebase.crash</item>\n        <item>com.google.firebase.database</item>\n        <item>com.google.firebase.encoders</item>\n        <item>com.google.firebase.firebase.common</item>\n        <item>com.google.firebase.firebase_common</item>\n        <item>com.google.firebase.firebase_core</item>\n        <item>com.google.firebase.heartbeatinfo</item>\n        <item>com.google.firebase.iid</item>\n        <item>com.google.firebase.internal</item>\n        <item>com.google.firebase.messaging</item>\n        <item>com.google.firebase.provider</item>\n        <item>com.google.firebase.remoteconfig</item>\n        <item>com.google.firebase.storage</item>\n        <item>com.google.firebase.analytics.</item>\n        <item>com.google.android.gms.measurement.</item>\n        <item>com.google.firebase.firebase_analytics</item>\n        <item>com.google.android.datatransport</item>\n        <item>com.google.firebase.installations</item>\n        <item>com.firebase.jobdispatcher</item>\n        <item>com.firebase.ui</item>\n        <item>com.sangcomz.fishbun</item>\n        <item>com.google.flatbuffers</item>\n        <item>com.pontiflex.mobile.</item>\n        <item>com.lytefast.flexinput</item>\n        <item>org.houxg.flexlayout</item>\n        <item>com.google.android.flexbox</item>\n        <item>com.duck.flexilogger</item>\n        <item>eu.davidea.fastscroller</item>\n        <item>eu.davidea.flexibleadapter</item>\n        <item>eu.davidea.viewholders</item>\n        <item>com.daquexian.flexiblerichtextview</item>\n        <item>eu.davidea.flipview</item>\n        <item>com.facebook.flipper.android</item>\n        <item>com.allenliu.floatview</item>\n        <item>com.leinardi.android.speeddial</item>\n        <item>com.arlib.floatingsearchview</item>\n        <item>ru.dimorinny.floatingtextbutton</item>\n        <item>com.getbase.floatingactionbutton</item>\n        <item>jahirfiquitiva.libs.fabsmenu</item>\n        <item>jp.co.recruit_lifestyle.android.floatingview</item>\n        <item>me.drakeet.floo</item>\n        <item>com.tfcporciuncula.flow</item>\n        <item>reactivecircus.flowbinding</item>\n        <item>com.nex3z.flowlayout</item>\n        <item>io.flowup</item>\n        <item>com.flowsense.flowsensesdk.</item>\n        <item>jp.fluct.fluctsdk.</item>\n        <item>com.flurry.android.ads</item>\n        <item>com.flurry.</item>\n        <item>com.mtechviral.musicfinder</item>\n        <item>io.flutter.app</item>\n        <item>io.flutter.embedding</item>\n        <item>io.flutter.plugin.common</item>\n        <item>io.flutter.plugin.editing</item>\n        <item>io.flutter.plugin.platform</item>\n        <item>io.flutter.util</item>\n        <item>io.flutter.view</item>\n        <item>io.flutter.plugins.flutter_plugin_android_lifecycle</item>\n        <item>boaventura.com.devel.br.flutteraudioquery</item>\n        <item>vn.hunghd.flutterdownloader</item>\n        <item>com.baseflow.geolocator</item>\n        <item>com.pichillilorenzo.flutter_inappwebview</item>\n        <item>com.jrai.flutter_keyboard_visibility</item>\n        <item>com.baseflow.permissionhandler</item>\n        <item>br.com.erickhaendel.flutter_screen_wake</item>\n        <item>com.bluechilli.flutteruploader</item>\n        <item>be.tramckrijte.workmanager</item>\n        <item>com.transistorsoft.flutter.backgroundfetch</item>\n        <item>com.matheusvillela.flutter.plugins.qrcodereader</item>\n        <item>com.cloudwebrtc.webrtc</item>\n        <item>com.rmawatson.flutterisolate</item>\n        <item>com.flyingpigeon</item>\n        <item>com.github.Justson.flying-pigeon</item>\n        <item>com.followanalytics.</item>\n        <item>com.shamanland.fonticon</item>\n        <item>com.footmarks.footmarkssdkm2</item>\n        <item>com.oneclickaway.opensource.formvalidationsexample</item>\n        <item>io.fotoapparat</item>\n        <item>com.fox2code.foxcompat</item>\n        <item>com.ncapdevi.fragnav</item>\n        <item>me.yokeyword.eventbus-activity-scope</item>\n        <item>me.yokeyword.fragmentation</item>\n        <item>me.yokeyword.fragmentation-swipeback</item>\n        <item>dev.jahir.frames</item>\n        <item>com.rm.freedrawview</item>\n        <item>com.freerdp.freerdpcore</item>\n        <item>me.weishu.freereflection</item>\n        <item>me.weishu.reflection</item>\n        <item>com.sun.speech.engine</item>\n        <item>tv.freewheel.ad.</item>\n        <item>com.facebook.animated.gif</item>\n        <item>com.facebook.binaryresource</item>\n        <item>com.facebook.callercontext</item>\n        <item>com.facebook.cache</item>\n        <item>com.facebook.common.activitylistener</item>\n        <item>com.facebook.common.disk</item>\n        <item>com.facebook.common.executors</item>\n        <item>com.facebook.common.file</item>\n        <item>com.facebook.common.internal</item>\n        <item>com.facebook.common.lifecycle</item>\n        <item>com.facebook.common.logging</item>\n        <item>com.facebook.common.media</item>\n        <item>com.facebook.common.memory</item>\n        <item>com.facebook.common.references</item>\n        <item>com.facebook.common.statfs</item>\n        <item>com.facebook.common.streams</item>\n        <item>com.facebook.common.time</item>\n        <item>com.facebook.common.util</item>\n        <item>com.facebook.common.webp</item>\n        <item>com.facebook.datasource</item>\n        <item>com.facebook.drawable</item>\n        <item>com.facebook.drawee</item>\n        <item>com.facebook.fresco</item>\n        <item>com.facebook.imageformat</item>\n        <item>com.facebook.imagepipeformat</item>\n        <item>com.facebook.imagepipeline</item>\n        <item>com.facebook.imagepipelinebase</item>\n        <item>com.facebook.imageutils</item>\n        <item>com.facebook.nativefilters</item>\n        <item>com.facebook.nativeimagetranscoder</item>\n        <item>com.facebook.widget.text.span</item>\n        <item>com.stfalcon.frescoimageviewer</item>\n        <item>com.fernandocejas.frodo</item>\n        <item>com.github.k1rakishou.fsaf</item>\n        <item>com.github.kittinunf.fuel</item>\n        <item>com.github.rtoshiro.view.video</item>\n        <item>irismod.token</item>\n        <item>si.virag.fuzzydateformatter</item>\n        <item>com.fyber.</item>\n        <item>com.sponsorpay</item>\n        <item>com.giphy.sdk.analytics</item>\n        <item>com.giphy.sdk.tracking</item>\n        <item>net.tmtg.glesjs</item>\n        <item>com.reach.ActionMonitor</item>\n        <item>com.reach.ActionService</item>\n        <item>com.reach.AdServiceManager</item>\n        <item>com.reach.IActivity</item>\n        <item>com.reach.IBackgroundManager</item>\n        <item>com.reach.IBackgroundService</item>\n        <item>com.reach.IBannerAd</item>\n        <item>com.reach.IConfigService</item>\n        <item>com.reach.IInterstitialAd</item>\n        <item>com.reach.INativeAd</item>\n        <item>com.reach.INativeReceiverProxy</item>\n        <item>com.reach.INativeServiceProxy</item>\n        <item>com.reach.IPushService</item>\n        <item>com.reach.IService</item>\n        <item>com.reach.ITrackService</item>\n        <item>com.reach.OverlayActivity</item>\n        <item>com.reach.PeerActivity</item>\n        <item>com.reach.widget</item>\n        <item>gnu.trove</item>\n        <item>com.gomfactory.adpie.</item>\n        <item>com.gad.sdk.</item>\n        <item>com.gpshopper</item>\n        <item>jp.co.cyberagent.android.gpuimage</item>\n        <item>com.gamania.beanfunsdk.</item>\n        <item>com.gamesparks.sdk.</item>\n        <item>com.gameanalytics.sdk</item>\n        <item>com.garmin.fit</item>\n        <item>com.gelakinetic.GathererScraper</item>\n        <item>org.codeandmagic.android.gauge</item>\n        <item>org.mozilla.gecko</item>\n        <item>com.gemius.sdk</item>\n        <item>com.crazylegend.kotlinextensions</item>\n        <item>jp.co.geniee.gnadsdk.</item>\n        <item>com.genonbeta.android</item>\n        <item>com.maxmind.geoip2</item>\n        <item>jp.gr.java_conf.androtaku.geomap</item>\n        <item>fr.geonature.commons</item>\n        <item>fr.geonature.datasync</item>\n        <item>fr.geonature.mountpoint</item>\n        <item>fr.geonature.viewpager</item>\n        <item>mil.nga.geopackage</item>\n        <item>com.geouniq.android.</item>\n        <item>org.opensextant.geodesy</item>\n        <item>net.sf.geographiclib</item>\n        <item>org.oshkimaadziig.george.androidutils</item>\n        <item>com.thesurix.gesturerecycler</item>\n        <item>com.alexvasilkov.gestures</item>\n        <item>com.cunoraz.gifview.library</item>\n        <item>us.shandian.giga</item>\n        <item>com.gigya.</item>\n        <item>com.gimbal.android</item>\n        <item>org.gioui</item>\n        <item>xyz.klinker.giphy</item>\n        <item>com.github.javierugarte.githubcontributionsview</item>\n        <item>com.github.paolorotolo.gitty_reporter</item>\n        <item>androidx.glance</item>\n        <item>org.glassfish</item>\n        <item>com.bumptech.glide</item>\n        <item>ch.qoqa.glide</item>\n        <item>jp.wasabeef.glide.transformations</item>\n        <item>com.github.florent37.glidepalette</item>\n        <item>com.github.twocoffeesoneteam.glidetovectoryou</item>\n        <item>com.avocarrot.sdk</item>\n        <item>com.jeppeman.locallydynamic</item>\n        <item>com.glympse.android.</item>\n        <item>co.infinum.goldfinger</item>\n        <item>com.google.api.client</item>\n        <item>com.google.ar.core</item>\n        <item>com.google.ads.</item>\n        <item>com.google.android.gms.ads.AdView</item>\n        <item>com.google.android.gms.ads.AdActivity</item>\n        <item>com.google.android.gms.ads.AdRequest</item>\n        <item>com.google.android.gms.ads.mediation</item>\n        <item>com.google.android.gms.ads.doubleclick</item>\n        <item>com.google.android.ads.</item>\n        <item>com.google.unity.ads.</item>\n        <item>com.google.android.gms.admob</item>\n        <item>com.google.firebase.firebase_ads.</item>\n        <item>com.google.ads</item>\n        <item>com.google.android.gms.ads.mediation</item>\n        <item>com.google.android.apps.analytics.</item>\n        <item>com.google.android.gms.analytics.</item>\n        <item>com.google.analytics.</item>\n        <item>com.danielcwilson.plugins.analytics</item>\n        <item>com.google.android.net</item>\n        <item>com.google.appengine</item>\n        <item>com.google.apphosting</item>\n        <item>com.google.appinventor</item>\n        <item>com.google.auth</item>\n        <item>com.google.android.gms.cast</item>\n        <item>com.google.cloud.audit</item>\n        <item>com.google.android.gms.cloudmessaging</item>\n        <item>com.google.common</item>\n        <item>com.google.api.services.drive</item>\n        <item>com.gae.scaffolder.plugin</item>\n        <item>com.google.android.gms.fitness</item>\n        <item>com.google.android.gcm</item>\n        <item>com.google.gson</item>\n        <item>com.google.inject</item>\n        <item>com.google.api.services</item>\n        <item>com.google.api.services.admob</item>\n        <item>com.google.api.services.adsense</item>\n        <item>com.google.api.services.adsensehost</item>\n        <item>com.google.mlkit</item>\n        <item>com.google.android.gms.maps</item>\n        <item>com.google.android.libraries.maps</item>\n        <item>io.flutter.plugins.googlemaps</item>\n        <item>com.google.android.material</item>\n        <item>com.google.android.gms.auth</item>\n        <item>com.google.android.gms.common</item>\n        <item>com.google.android.gms.location</item>\n        <item>com.android.vending</item>\n        <item>com.android.billingclient</item>\n        <item>com.google.android.play.core</item>\n        <item>com.google.android.gms.oss.licenses</item>\n        <item>com.google.android.vending</item>\n        <item>com.google.android.as.oss</item>\n        <item>com.google.protobuf</item>\n        <item>com.google.tagmanager</item>\n        <item>com.google.android.gms.tagmanager</item>\n        <item>com.proton.gopenpgp</item>\n        <item>com.grab.grabidpartnersdk</item>\n        <item>com.mikhaellopez.gradientview</item>\n        <item>com.jjoe64.graphview</item>\n        <item>com.timerazor.gravysdk.</item>\n        <item>com.greedygame.legacy</item>\n        <item>com.cyrilmottier.android.greendroid</item>\n        <item>com.greenrobot.</item>\n        <item>com.groundtruth.sdk</item>\n        <item>com.growingio.</item>\n        <item>com.growthpush.</item>\n        <item>com.growthbeat.</item>\n        <item>io.gsonfire</item>\n        <item>info.guardianproject.cacheword</item>\n        <item>info.guardianproject.iocipher</item>\n        <item>info.guardianproject.libcore</item>\n        <item>info.guardianproject.netcipher</item>\n        <item>info.guardianproject.panic</item>\n        <item>com.huawei.hms.hwid.internal</item>\n        <item>com.rarepebble.colorpicker</item>\n        <item>com.huawei.hms.iap</item>\n        <item>com.magicmicky.habitrpgwrapper</item>\n        <item>com.damnhandy.uri.template</item>\n        <item>com.huxq17.handygridview</item>\n        <item>irismod.htlc</item>\n        <item>com.himanshurawat.hasher</item>\n        <item>com.greenfrvr.hashtagview</item>\n        <item>app.futured.hauler</item>\n        <item>com.orhanobut.hawk</item>\n        <item>org.fusesource.hawtjni</item>\n        <item>com.squareup.haha</item>\n        <item>com.esaulpaugh.headlong</item>\n        <item>com.heapanalytics</item>\n        <item>lecho.lib.hellocharts</item>\n        <item>com.helpshift</item>\n        <item>com.facebook.hermes</item>\n        <item>com.connecthings.herow</item>\n        <item>com.heytap.nearx.track</item>\n        <item>com.heytap.msp.</item>\n        <item>com.heyzap.sdk.ads.</item>\n        <item>com.heyzap.mediation.</item>\n        <item>com.carrotsearch.hppc</item>\n        <item>com.pyamsoft.highlander</item>\n        <item>com.pddstudio.highlightjs</item>\n        <item>com.hivemq.client</item>\n        <item>org.hjson</item>\n        <item>xyz.aprildown.hmspickerview</item>\n        <item>net.hockeyapp.</item>\n        <item>com.hoko.blur</item>\n        <item>com.echo.holographlibrary</item>\n        <item>com.hotmob.sdk.</item>\n        <item>com.hound</item>\n        <item>houseads</item>\n        <item>org.htmlcleaner</item>\n        <item>com.ireward.htmlcompose</item>\n        <item>net.nightwhistler.htmlspanner</item>\n        <item>de.charlex.compose</item>\n        <item>org.sufficientlysecure.htmltextview</item>\n        <item>com.github.kevinsawicki.http</item>\n        <item>cz.msebera.android.httpclient</item>\n        <item>cz.msebera.httpclient</item>\n        <item>com.llew.huawei.verifier</item>\n        <item>com.huawei.appmarket.component</item>\n        <item>com.huawei.hmf.tasks</item>\n        <item>com.huawei.agconnect</item>\n        <item>com.huawei.hms</item>\n        <item>com.huawei.hms.analytics</item>\n        <item>com.huawei.hms.location</item>\n        <item>com.huawei.hms.plugin.analytics</item>\n        <item>com.huawei.hms.plugin.ads</item>\n        <item>com.huawei.updatesdk.</item>\n        <item>com.huawei.agconnect.</item>\n        <item>com.huawei.hms.support.api.push.</item>\n        <item>com.huawei.hms.flutter.analytics.</item>\n        <item>com.huawei.hms.pay</item>\n        <item>com.huawei.updatesdk</item>\n        <item>humanize</item>\n        <item>io.huq.sourcekit.</item>\n        <item>cn.hutool</item>\n        <item>com.hypertrack.hyperlog</item>\n        <item>com.hypertrack</item>\n        <item>com.hypertracklive.</item>\n        <item>io.hypertrack</item>\n        <item>com.hyprmx.android.sdk.</item>\n        <item>net.i2p</item>\n        <item>com.iab.omid.library</item>\n        <item>com.prime31.util.IabHelperImpl</item>\n        <item>com.prime31.IAB.</item>\n        <item>com.iac.notification.</item>\n        <item>com.digitalanalytics.</item>\n        <item>com.ibm.mce.sdk.</item>\n        <item>co.acoustic.mobile.push.sdk.</item>\n        <item>com.xtify.mce.sdk.</item>\n        <item>com.xtify.android.sdk.</item>\n        <item>com.inca.security</item>\n        <item>com.igg.android.ad.</item>\n        <item>com.igg.android.gamecenter.</item>\n        <item>com.igg.libs.</item>\n        <item>com.android.skyunion.ad.</item>\n        <item>com.android.skyunion.statistics.</item>\n        <item>com.skyunion.android.</item>\n        <item>tv.danmaku.ijk.media</item>\n        <item>de.infonline.</item>\n        <item>jota</item>\n        <item>inet.ipaddr</item>\n        <item>com.ipqualityscore.</item>\n        <item>io.ipinfo.api</item>\n        <item>com.iqv.</item>\n        <item>com.iqzone</item>\n        <item>com.amazonaws.ivs</item>\n        <item>icepick.injector</item>\n        <item>com.maltaisn.icondialog</item>\n        <item>com.maltaisn.iconpack</item>\n        <item>com.joanzapata.android.iconify</item>\n        <item>com.joanzapata.iconify</item>\n        <item>com.docuverse.identicon</item>\n        <item>com.igexin.sdk.</item>\n        <item>com.github.dhaval2404.imagepicker</item>\n        <item>io.flutter.plugins.imagepicker</item>\n        <item>com.nguyenhoanglam.imagepicker</item>\n        <item>it.sephiroth.android.library.imagezoom</item>\n        <item>com.gyf.immersionbar</item>\n        <item>kotlinx.collections.immutable</item>\n        <item>com.inlocomedia.android</item>\n        <item>com.proyecto26.inappbrowser</item>\n        <item>com.inbrain.sdk.</item>\n        <item>com.inmarket</item>\n        <item>com.inmobi</item>\n        <item>in.inmobi.</item>\n        <item>in3.config</item>\n        <item>in3.eth1</item>\n        <item>in3.utils</item>\n        <item>com.reddit.indicatorfastscroll</item>\n        <item>com.indooratlas.android.sdk</item>\n        <item>com.facebook.infer</item>\n        <item>com.antonyt.infiniteviewpager</item>\n        <item>com.gigamole.infinitecycleviewpager</item>\n        <item>uy.kohesive.injekt</item>\n        <item>com.simplify.ink</item>\n        <item>com.pixelcan.inkpageindicator</item>\n        <item>com.inneractive.api.ads</item>\n        <item>com.redmadrobot.inputmask</item>\n        <item>com.afollestad.inquiry</item>\n        <item>com.inrix.sdk</item>\n        <item>dev.chrisbanes.insetter</item>\n        <item>com.useinsider.insider</item>\n        <item>com.instabug.</item>\n        <item>com.instal.mobileads.</item>\n        <item>com.instal.common</item>\n        <item>com.instal.mopub.</item>\n        <item>com.instal.nativeads</item>\n        <item>com.instal.discovery</item>\n        <item>com.instal.userprofile</item>\n        <item>com.instreamatic</item>\n        <item>com.integralads.avid.library</item>\n        <item>org.intellij</item>\n        <item>org.jetbrains.java.decompiler</item>\n        <item>irismod.service</item>\n        <item>io.intercom.android.sdk</item>\n        <item>io.intercom</item>\n        <item>com.ibm.icu</item>\n        <item>com.ethlo.time</item>\n        <item>androidx.interpolator</item>\n        <item>com.intrasonics.</item>\n        <item>com.ad.intromi.</item>\n        <item>io.invertase.firebase</item>\n        <item>com.ionic.keyboard</item>\n        <item>io.ionic.keyboard</item>\n        <item>com.ionicframework.cordova.webview</item>\n        <item>com.mikepenz.itemanimators</item>\n        <item>com.google.j2objc</item>\n        <item>com.eclipsesource.v8</item>\n        <item>net.sourceforge.jaad</item>\n        <item>jadx</item>\n        <item>javax.xml.bind</item>\n        <item>org.jaudiotagger</item>\n        <item>org.jbox2d</item>\n        <item>jcifs</item>\n        <item>net.jcip.annotations</item>\n        <item>org.jctools</item>\n        <item>net.freeutils.charset</item>\n        <item>org.jcodec</item>\n        <item>com.beust.jcommander</item>\n        <item>org.jdom</item>\n        <item>org.jdom2</item>\n        <item>org.jdeferred</item>\n        <item>org.eclipse.jface</item>\n        <item>org.scilab.forge.jlatexmath</item>\n        <item>pl.edu.icm.jlargearrays</item>\n        <item>ru.noties.jlatexmath</item>\n        <item>com.samskivert.mustache</item>\n        <item>com.sun.jna</item>\n        <item>org.rocstreaming.roctoolkit</item>\n        <item>com.rotilho.jnano.commons</item>\n        <item>joptsimple</item>\n        <item>net.dean.jraw</item>\n        <item>org.json</item>\n        <item>net.arnx.jsonic</item>\n        <item>com.jcraft.jsch</item>\n        <item>de.jarnbjo.jsnappy</item>\n        <item>net.sourceforge.jsocks</item>\n        <item>ru.ubmb.jstribog</item>\n        <item>org.crosswire.common</item>\n        <item>org.crosswire.jsword</item>\n        <item>com.vividsolutions.jts</item>\n        <item>com.vividsolutions.jtsexample</item>\n        <item>org.kamranzafar.jtar</item>\n        <item>org.w3c.tidy</item>\n        <item>org.jtransforms</item>\n        <item>com.github.junrar</item>\n        <item>com.longtailvideo.jwplayer.</item>\n        <item>com.auth0.android.jwt</item>\n        <item>org.jxmpp</item>\n        <item>com.jcraft.jzlib</item>\n        <item>org.codehaus.jackson</item>\n        <item>com.gantix.JailMonkey</item>\n        <item>org.apache.oro</item>\n        <item>org.apache.regexp</item>\n        <item>com.janrain.android</item>\n        <item>com.janrain.android.engage</item>\n        <item>com.janrain.android.capture</item>\n        <item>net.ellerton.japng</item>\n        <item>com.jaspersoft.android.sdk</item>\n        <item>com.takwolf.morsecoder</item>\n        <item>com.tananaev.adblib</item>\n        <item>com.google.api.services.analytics</item>\n        <item>com.google.api.services.analyticsadmin</item>\n        <item>com.google.api.services.analyticsdata</item>\n        <item>com.google.api.services.analyticsreporting</item>\n        <item>edu.smu.tspell.wordnet</item>\n        <item>edu.jas</item>\n        <item>org.javia.arity</item>\n        <item>org.jacoco</item>\n        <item>edu.hws.jcm</item>\n        <item>jxl</item>\n        <item>org.hamcrest</item>\n        <item>io.jsonwebtoken</item>\n        <item>org.mp4parser</item>\n        <item>net.sf.marineapi</item>\n        <item>java.nio</item>\n        <item>com.kenai.constantine</item>\n        <item>jnr.constants</item>\n        <item>com.gu.option</item>\n        <item>com.github.zafarkhaja.semver</item>\n        <item>org.tanukisoftware.wrapper</item>\n        <item>java.util.stream</item>\n        <item>net.freeutils.tnef</item>\n        <item>org.java_websocket</item>\n        <item>co.rh.id.lib.concurrent_utils</item>\n        <item>org.andresoviedo.util</item>\n        <item>com.xamarin.java_interop</item>\n        <item>javax.activation</item>\n        <item>com.sun.activation</item>\n        <item>javax.mail</item>\n        <item>javax.money</item>\n        <item>ru.fazziclay.javaneoutil</item>\n        <item>com.squareup.javapoet</item>\n        <item>com.backblaze.erasure</item>\n        <item>javax.json</item>\n        <item>com.squareup.java</item>\n        <item>com.squareup.javawriter</item>\n        <item>me.xdrop.diffutils</item>\n        <item>me.xdrop.fuzzywuzzy</item>\n        <item>javax.annotation</item>\n        <item>javax.obex</item>\n        <item>javax.inject</item>\n        <item>javax.microedition</item>\n        <item>javax.servlet</item>\n        <item>javax.ws.rs</item>\n        <item>javassist</item>\n        <item>org.jaxen</item>\n        <item>com.jayway.jsonpath</item>\n        <item>com.sentaroh.jcifs</item>\n        <item>org.jellyfin.apiclient</item>\n        <item>org.jellyfin.sdk</item>\n        <item>org.zeromq</item>\n        <item>dev.patrickgold.jetpref</item>\n        <item>androidx.compose</item>\n        <item>androidx.ui</item>\n        <item>com.godaddy.android.colorpicker</item>\n        <item>com.godaddy.common.colorpicker</item>\n        <item>com.smarttoolfactory.gesture</item>\n        <item>androidx.window</item>\n        <item>cn.jpush.android</item>\n        <item>cn.jzvd</item>\n        <item>org.jitsi.meet.sdk</item>\n        <item>com.spotify.jni</item>\n        <item>org.joda.time</item>\n        <item>org.joda.money</item>\n        <item>com.evgenii.jsevaluator</item>\n        <item>org.json.simple</item>\n        <item>com.yuyh.jsonviewer</item>\n        <item>cn.wanghaomiao.xpath.model</item>\n        <item>org.seimicrawler.xpath</item>\n        <item>com.jumio.MobileSDK</item>\n        <item>com.jumptap.adtag.</item>\n        <item>junit</item>\n        <item>io.karte.android.tracker.</item>\n        <item>com.kidoz.sdk</item>\n        <item>com.kissmetrics</item>\n        <item>org.koin</item>\n        <item>com.fondesa.kpermissions</item>\n        <item>org.mariotaku.kpreferences</item>\n        <item>com.onurkaganaldemir.ktoastlib</item>\n        <item>com.markodevcic.kvalidation</item>\n        <item>se.krka.kahlua</item>\n        <item>com.kakao.ad.</item>\n        <item>com.kakao.kakaolink</item>\n        <item>katex.hourglass.in.mathlib</item>\n        <item>io.keen.client.</item>\n        <item>io.keen.client.android</item>\n        <item>io.keen.client.java</item>\n        <item>io.keen.client.scala</item>\n        <item>keepass2android.pluginsdk</item>\n        <item>com.keepassdroid</item>\n        <item>org.kefirsf</item>\n        <item>com.flaviofaria.kenburnsview</item>\n        <item>com.adzerk</item>\n        <item>org.keyczar</item>\n        <item>net.yslibrary.android.keyboardvisibilityevent</item>\n        <item>org.bitbucket.inkytonik.kiama</item>\n        <item>me.kiip.sdk</item>\n        <item>com.beust.klaxon</item>\n        <item>com.kochava.base.</item>\n        <item>com.kochava.android.tracker.</item>\n        <item>.kochavaccpa.</item>\n        <item>org.kodein.di</item>\n        <item>com.mcxiaoke.koi</item>\n        <item>com.zestadz.android.</item>\n        <item>nl.dionsegijn.konfetti</item>\n        <item>com.kontakt.sdk.android.</item>\n        <item>kotlin</item>\n        <item>kotlinx.android.extensions</item>\n        <item>kotlinx.android.parcel</item>\n        <item>com.jakewharton.retrofit2</item>\n        <item>ru.gildor.coroutines.retrofit</item>\n        <item>org.lighthousegames.logging</item>\n        <item>org.jetbrains.kotlin</item>\n        <item>org.nield.kotlinstatistics</item>\n        <item>ru.gildor.coroutines.okhttp</item>\n        <item>kotlinx.serialization</item>\n        <item>com.github.salomonbrys.kotson</item>\n        <item>nl.komponents.kovenant</item>\n        <item>me.gujun.android.span</item>\n        <item>hu.autsoft.krate.default</item>\n        <item>com.lyft.kronos</item>\n        <item>com.krux.androidsdk</item>\n        <item>com.esotericsoftware.kryo</item>\n        <item>io.ktor</item>\n        <item>dev.jahir.kuper</item>\n        <item>org.kxml2</item>\n        <item>com.mindprod.ledatastream</item>\n        <item>com.leon.lfilepickerlibrary</item>\n        <item>com.linecorp.line.admolin</item>\n        <item>com.five_corp.ad.</item>\n        <item>com.linecorp.linesdk</item>\n        <item>jp.line.android.sdk</item>\n        <item>jp.naver.line.android.analytics.</item>\n        <item>jp.naver.line.android.beacon.</item>\n        <item>com.linecorp.line.analytics.tracking</item>\n        <item>net.jpountz.lz4</item>\n        <item>net.jpountz.util</item>\n        <item>net.jpountz.xxhash</item>\n        <item>net.contrapunctus.lzma</item>\n        <item>de.lab4inf.math</item>\n        <item>com.farbod.labelledspinner</item>\n        <item>com.lambdaworks.codec</item>\n        <item>com.skydoves.landscapist</item>\n        <item>github.nisrulz.lantern</item>\n        <item>org.lantern.mobilesdk</item>\n        <item>org.getlantern.lantern</item>\n        <item>com.github.nitrico.lastadapter</item>\n        <item>uk.co.workingedge.phonegap.plugin</item>\n        <item>my.nanihadesuka.compose</item>\n        <item>com.gabrielittner.threetenbp</item>\n        <item>com.goterl.lazycode.lazysodium</item>\n        <item>com.goterl.lazysodium</item>\n        <item>com.apptracker.android.</item>\n        <item>com.pad.android.xappad.</item>\n        <item>com.Leadbolt.</item>\n        <item>leakcanary</item>\n        <item>com.squareup.leakcanary</item>\n        <item>shark.SharkLog</item>\n        <item>com.avos.avoscloud</item>\n        <item>com.leanplum.</item>\n        <item>androidx.leanback</item>\n        <item>com.lenddo.mobile</item>\n        <item>com.canelmas.let</item>\n        <item>org.iq80.leveldb</item>\n        <item>org.fusesource.leveldbjni</item>\n        <item>com.absinthe.rulesbundle</item>\n        <item>com.simprints.libsimprints</item>\n        <item>org.videolan.libvlc</item>\n        <item>gnu.inet.encoding</item>\n        <item>net.butterflytv.rtmp_client</item>\n        <item>com.larswerkman.licenseview</item>\n        <item>de.psdev.licensesdialog</item>\n        <item>androidx.lifecycle</item>\n        <item>io.liftoff.liftoffads.</item>\n        <item>LigatusManager</item>\n        <item>LigatusViewClient</item>\n        <item>com.ligatus.android.adframework</item>\n        <item>com.github.lightningnetwork.lnd</item>\n        <item>com.annimon.stream</item>\n        <item>org.solovyev.android.views</item>\n        <item>com.yariksoffice.lingver</item>\n        <item>org.liquidplayer</item>\n        <item>com.jem.liquidswipe</item>\n        <item>com.lisnr.</item>\n        <item>com.nhaarman.listviewanimations</item>\n        <item>org.litepal</item>\n        <item>com.facebook.litho</item>\n        <item>org.littleshoot.proxy</item>\n        <item>com.hadilq.liveevent</item>\n        <item>com.microsoft.live</item>\n        <item>com.jeremyliao.liveeventbus</item>\n        <item>androidx.loader</item>\n        <item>com.yanzhenjie.loading</item>\n        <item>com.twofortyfouram.locale</item>\n        <item>com.localytics.android.</item>\n        <item>com.localytics.androidx</item>\n        <item>com.localytics.react.</item>\n        <item>locus.api</item>\n        <item>com.locuslabs.sdk</item>\n        <item>com.andreacioccarelli.logkit</item>\n        <item>com.bluelinelabs.logansquare</item>\n        <item>ch.qos.logback</item>\n        <item>com.orhanobut.logger</item>\n        <item>com.github.tony19.timber.loggly</item>\n        <item>com.github.tony19.loggly</item>\n        <item>com.visiware.sync2ad.logger.loggly.</item>\n        <item>com.loopme.</item>\n        <item>com.mapzen.android.lost</item>\n        <item>com.mapzen.lost</item>\n        <item>com.lotadata.moments.</item>\n        <item>com.lotame.android</item>\n        <item>com.airbnb.lottie</item>\n        <item>com.airbnb.android.react.lottie</item>\n        <item>com.igreenwood.loupe</item>\n        <item>com.yarolegovich.lovelydialog</item>\n        <item>org.luaj.vm2</item>\n        <item>spacemadness.com.lunarconsole</item>\n        <item>com.github.pedrovgs.lynx</item>\n        <item>com.mngads.sdk</item>\n        <item>com.mngads.views</item>\n        <item>com.mngads.</item>\n        <item>com.mdotm.android</item>\n        <item>com.megvii.zhimasdk.</item>\n        <item>com.google.mlkit</item>\n        <item>com.tencent.mmkv</item>\n        <item>com.innoquant.moca</item>\n        <item>com.github.mikephil.charting</item>\n        <item>com.craxiom.mqttlibrary</item>\n        <item>com.microsoft.services.msa</item>\n        <item>eu.darken.mvpbakery</item>\n        <item>com.madhouse.android.ads</item>\n        <item>br.com.bloder.magic</item>\n        <item>net.lucode.hackware.magicindicator</item>\n        <item>ru.mail.mrgservice.advertising</item>\n        <item>ru.mail.mrgservice.analytics</item>\n        <item>com.deflocculent.fecklessness.</item>\n        <item>.BxcActivity</item>\n        <item>.B2sActivity</item>\n        <item>.MdService</item>\n        <item>.LoReceiver</item>\n        <item>.OxgReceiver</item>\n        <item>.PdsReceiver</item>\n        <item>org.gg.msdns.noroxi.</item>\n        <item>com.shahenshah.mathematics.</item>\n        <item>com.warison.authigene</item>\n        <item>com.apld.av.</item>\n        <item>com.kdeamon.libe.</item>\n        <item>net.fivefive.tek.</item>\n        <item>com.unfreezable.moze.</item>\n        <item>com.kinmall.common.</item>\n        <item>com.cleanmaster.security.heartbleed.</item>\n        <item>com.insight.sdk.</item>\n        <item>coelib.c.couluslibrary.</item>\n        <item>com.cs.bd.ad.</item>\n        <item>com.cs.bd.daemon.</item>\n        <item>com.cs.bd.hicon.</item>\n        <item>com.cs.bd.service.</item>\n        <item>com.cs.bd.receiver.</item>\n        <item>com.cs.bd.buychannel.</item>\n        <item>com.cs.bd.commerce.</item>\n        <item>com.cs.statistic.</item>\n        <item>com.cpcphone.abtestcenter.</item>\n        <item>com.fungame.advertisingsdk</item>\n        <item>com.hz.keep.</item>\n        <item>cn.rs.keepalive.</item>\n        <item>org.spaceroots.mantissa</item>\n        <item>org.mapdb</item>\n        <item>com.mapbox.mapboxsdk.module.telemetry</item>\n        <item>com.mapbox.mapboxsdk.maps.TelemetryDefinition</item>\n        <item>com.mapbox.android.telemetry.</item>\n        <item>com.mapbox.mapboxsdk</item>\n        <item>com.mapbox</item>\n        <item>com.mapbox.android.telemetry</item>\n        <item>com.google.maps.android</item>\n        <item>org.mapsforge</item>\n        <item>com.zzhoujay.markdown</item>\n        <item>us.feras.mdv</item>\n        <item>org.markdown4j</item>\n        <item>com.petebevin.markdown</item>\n        <item>org.markdownj</item>\n        <item>dev.jeziellago.compose.markdowntext</item>\n        <item>br.tiagohm.markdownview</item>\n        <item>com.mittsu.markedview</item>\n        <item>com.marketo.</item>\n        <item>io.noties.markwon</item>\n        <item>ru.noties.markwon</item>\n        <item>com.vansuita.materialabout</item>\n        <item>com.sa90.materialarcmenu</item>\n        <item>it.sephiroth.android.library.bottomnavigation</item>\n        <item>it.sephiroth.android.library.bottonnavigation</item>\n        <item>com.dvdb.materialchecklist</item>\n        <item>com.robertlevonyan.views.chip</item>\n        <item>com.github.rahatarmanahmed.cpv</item>\n        <item>com.afollestad.materialcab</item>\n        <item>com.takisoft.datetimepicker</item>\n        <item>com.wdullaer.materialdatetimepicker</item>\n        <item>com.afollestad.materialdialogs</item>\n        <item>com.github.ivbaranov.mfb</item>\n        <item>com.nbsp.materialfilepicker</item>\n        <item>net.steamcrafted.materialiconlib</item>\n        <item>com.balysv.materialmenu</item>\n        <item>soup.compose.material.motion</item>\n        <item>net.xpece.android.support</item>\n        <item>com.balysv.materialripple</item>\n        <item>com.jaredrummler.materialspinner</item>\n        <item>uk.co.samuelwall.materialtaptargetprompt</item>\n        <item>com.tbuonomo.viewpagerdotsindicator</item>\n        <item>com.applandeo.materialcalendarview</item>\n        <item>com.itsronald.widget</item>\n        <item>com.pnikosis.materialishprogress</item>\n        <item>com.borax12.materialdaterangepicker</item>\n        <item>com.mikepenz.materialdrawer</item>\n        <item>com.rengwuxian.materialedittext</item>\n        <item>za.co.riggaroo.materialhelptutorial</item>\n        <item>com.rey.material</item>\n        <item>com.lsjwzh.widget.materialloadingprogressbar</item>\n        <item>biz.kasual.materialnumberpicker</item>\n        <item>com.ohoussein.playpause</item>\n        <item>moe.shizuku.preference</item>\n        <item>com.lb.material_preferences_library</item>\n        <item>com.yarolegovich.mp</item>\n        <item>me.zhanghai.android.materialprogressbar</item>\n        <item>com.appyvet.materialrangebar</item>\n        <item>me.zhanghai.android.materialratingbar</item>\n        <item>com.turingtechnologies.materialscrollbar</item>\n        <item>com.miguelcatalan.materialsearchview</item>\n        <item>com.pavelsikun.seekbarpreference</item>\n        <item>com.gordonwong.materialsheetfab</item>\n        <item>uk.co.deanwild.materialshowcaseview</item>\n        <item>com.github.javiersantos.materialstyleddialogs</item>\n        <item>net.yanzm.mth</item>\n        <item>dev.nick.tiles</item>\n        <item>com.alexandrepiveteau.library.tutorial</item>\n        <item>com.github.florent37.materialviewpager</item>\n        <item>com.xayah.materialyoufileexplorer</item>\n        <item>com.mikepenz.materialize</item>\n        <item>org.mariuszgromada.math.mxparser</item>\n        <item>io.github.kexanie.library</item>\n        <item>com.zhihu.matisse</item>\n        <item>org.piwik</item>\n        <item>org.piwik.mobile</item>\n        <item>org.matomo</item>\n        <item>org.matomo</item>\n        <item>org.matrix.android.sdk</item>\n        <item>com.airbnb.mvrx</item>\n        <item>com.bskim.maxheightscrollview.widgets</item>\n        <item>com.maxmind.db</item>\n        <item>androidx.media</item>\n        <item>com.google.android.mediahome.video</item>\n        <item>androidx.media2</item>\n        <item>com.mediafire.sdk</item>\n        <item>com.archos.medialib</item>\n        <item>com.archos.mediaprovider</item>\n        <item>com.archos.mediascraper</item>\n        <item>org.mariotaku.mediaviewer</item>\n        <item>androidx.mediarouter</item>\n        <item>de.duenndns.ssl</item>\n        <item>net.simonvt.menudrawer</item>\n        <item>org.mariotaku.messagebubbleview</item>\n        <item>org.msgpack</item>\n        <item>com.metaps</item>\n        <item>com.codahale.metrics</item>\n        <item>com.mapps.android.</item>\n        <item>com.mz.common.</item>\n        <item>com.mmc.common</item>\n        <item>com.mezzomedia.</item>\n        <item>com.migcomponents.migbase64</item>\n        <item>com.microblink</item>\n        <item>org.microemu</item>\n        <item>com.microsoft.appcenter.analytics</item>\n        <item>com.microsoft.appcenter.crashes</item>\n        <item>com.microsoft.identity</item>\n        <item>com.microsoft.aad.adal</item>\n        <item>com.microsoft.azure.mobile.analytics</item>\n        <item>com.microsoft.band</item>\n        <item>com.microsoft.graph</item>\n        <item>microsoft.identity.client</item>\n        <item>microsoft.mappoint</item>\n        <item>com.microsoft.azure.mobile.crashes</item>\n        <item>com.microsoft.azure.mobile.distribute</item>\n        <item>com.microsoft.appcenter.analytics</item>\n        <item>com.microsoft.azure.mobile.analytics</item>\n        <item>com.microsoft.appcenter.crashes</item>\n        <item>org.billthefarmer.mididriver</item>\n        <item>com.millennialmedia.</item>\n        <item>gr.antoniom.chronometer</item>\n        <item>com.squareup.mimecraft</item>\n        <item>io.minio</item>\n        <item>com.esotericsoftware.minlog</item>\n        <item>de.measite.minidns</item>\n        <item>org.kde.necessitas.ministro</item>\n        <item>com.mintegral.</item>\n        <item>com.mbridge.msdk.</item>\n        <item>com.mixpanel.</item>\n        <item>com.moengage.</item>\n        <item>com.momo.sdk</item>\n        <item>com.mopub.mobileads</item>\n        <item>com.moat.analytics.mobile.</item>\n        <item>com.moat.analytics</item>\n        <item>com.mobfox.</item>\n        <item>com.adsdk.sdk.</item>\n        <item>com.mobpower.</item>\n        <item>com.mobclick.android</item>\n        <item>com.ubikod.capptain.</item>\n        <item>com.microsoft.azure.engagement.</item>\n        <item>com.arthenica.mobileffmpeg</item>\n        <item>xyz.belvi.mobilevisionbarcodescanner</item>\n        <item>com.mobimento.caponate.ad.</item>\n        <item>com.mobiquitynetworks.</item>\n        <item>com.spotify.mobius.android</item>\n        <item>com.moblin.pxl.</item>\n        <item>com.mobon.sdk.</item>\n        <item>com.mobvista.</item>\n        <item>org.mockito</item>\n        <item>de.Maxr1998.modernpreferences</item>\n        <item>com.github.wrdlbrnft.modularadapter</item>\n        <item>com.mofiler.android</item>\n        <item>kr.com.mojise.sdk</item>\n        <item>org.codehaus.mojo.animal_sniffer</item>\n        <item>com.zhuinden.monarchy</item>\n        <item>dev.kdrag0n.monet</item>\n        <item>com.kieronquinn.monetcompat</item>\n        <item>org.javamoney.moneta</item>\n        <item>org.fabiomsr.moneytextview</item>\n        <item>mono.android</item>\n        <item>com.moodmedia</item>\n        <item>com.mopinion.mopinionsdk</item>\n        <item>com.morgoo.droidplugin.</item>\n        <item>com.hannesdorfmann.mosby3</item>\n        <item>com.squareup.moshi</item>\n        <item>com.arellomobile.mvp</item>\n        <item>org.mozilla.intl.chardet</item>\n        <item>mozilla.components.lib.crash.service</item>\n        <item>org.mozilla.classfile</item>\n        <item>org.mozilla.javascript</item>\n        <item>org.mozilla.telemetry</item>\n        <item>org.mozilla.gecko.telemetry</item>\n        <item>mozilla.telemetry.glean.</item>\n        <item>org.mozilla.fenix.GleanMetrics</item>\n        <item>org.mozilla.fenix.components.metrics</item>\n        <item>com.artifex.mupdf</item>\n        <item>me.nereo.multi_image_selector</item>\n        <item>pl.openrnd.multilevellistview</item>\n        <item>com.abdeveloper.library</item>\n        <item>com.kennyc.multistateview</item>\n        <item>com.drakeet.multitype</item>\n        <item>com.vincent.filepicker</item>\n        <item>org.mariotaku.multivalueswitch</item>\n        <item>com.andremion.music</item>\n        <item>com.google.android.apps.muzei</item>\n        <item>com.mysql.jdbc</item>\n        <item>mmcalendar</item>\n        <item>be.mygod</item>\n        <item>org.ndeftools</item>\n        <item>com.nifcloud.mbaas</item>\n        <item>com.hootsuite.nachos</item>\n        <item>com.github.ramiz.nameinitialscircleimageview</item>\n        <item>fi.iki.elonen</item>\n        <item>io.github.aakira.napier</item>\n        <item>com.nativescript.collectionview</item>\n        <item>org.nativescript.widgets</item>\n        <item>org.nativescript.nativescript_imagepicker</item>\n        <item>org.nativescript.social_share</item>\n        <item>com.github.triniwiz.couchbase</item>\n        <item>com.nativex</item>\n        <item>com.akylas.sqlite</item>\n        <item>org.nativescript.nativescript_akylas_sqlite</item>\n        <item>tk.zielony.naturaldateformat</item>\n        <item>androidx.navigation</item>\n        <item>br.com.tombus.capacitor.plugin.navigationbar</item>\n        <item>com.fazziclay.neosocket</item>\n        <item>com.github.megatronking.netbare</item>\n        <item>eu.faircode.netguard</item>\n        <item>com.inn.passivesdk.</item>\n        <item>com.inn.feedback.</item>\n        <item>com.netki.dns</item>\n        <item>com.netki.dnssec</item>\n        <item>com.netki.tlsa</item>\n        <item>io.netty</item>\n        <item>com.typesafe.netty</item>\n        <item>com.facebook.network.connectionclass</item>\n        <item>com.newrelic.agent.</item>\n        <item>com.newrelic.mobile.</item>\n        <item>org.schabi.newpipe.extractor</item>\n        <item>kr.newspic.offerwall.</item>\n        <item>com.nexage.android.</item>\n        <item>org.nexage.</item>\n        <item>com.nextcloud.android.sso</item>\n        <item>com.nielsen.app</item>\n        <item>com.nimbusds.jose</item>\n        <item>com.nimbusds.jwt</item>\n        <item>com.nineoldandroids</item>\n        <item>com.ninjametrics.</item>\n        <item>com.github.whataa.noDrawable</item>\n        <item>com.nononsenseapps.filepicker</item>\n        <item>jp.noahapps.sdk.</item>\n        <item>com.ornach.nobobutton</item>\n        <item>com.nokia.mid</item>\n        <item>irismod.nft</item>\n        <item>com.noob.noobcameraflash</item>\n        <item>com.shasin.notificationbanner</item>\n        <item>com.aiadmobi.sdk.</item>\n        <item>com.davidmiguel.numberkeyboard</item>\n        <item>com.shawnlin.numberpicker</item>\n        <item>ren.qinc.numberbutton</item>\n        <item>com.travijuu.numberpicker</item>\n        <item>com.michaelnovakjr.numberpicker</item>\n        <item>nl.invissvenska.numberpickerpreference</item>\n        <item>cn.carbswang.android.numberpickerview</item>\n        <item>com.upokecenter.numbers</item>\n        <item>org.sdf.danielsz</item>\n        <item>org.odk.collect.android</item>\n        <item>org.javarosa</item>\n        <item>mil.nga.oapi</item>\n        <item>com.mNewsK.sdk.</item>\n        <item>be.ceau.opml</item>\n        <item>com.osbcp.cssparser</item>\n        <item>org.osgi</item>\n        <item>org.osgi.framework</item>\n        <item>org.eclipse.osgi</item>\n        <item>io.objectbox</item>\n        <item>org.mariotaku.library.objectcursor</item>\n        <item>org.objenesis</item>\n        <item>com.offertoro.sdk.</item>\n        <item>com.ogury.cm.</item>\n        <item>com.ogury.analytics.</item>\n        <item>com.ogury.consent.</item>\n        <item>com.ogury.sdk.</item>\n        <item>io.presage.</item>\n        <item>com.liulishuo.okdownload</item>\n        <item>com.squareup.okhttp</item>\n        <item>okhttp3</item>\n        <item>okio</item>\n        <item>com.github.li-xiaojun.OkhttpDownloader</item>\n        <item>org.matrix.olm</item>\n        <item>com.omniture.</item>\n        <item>com.adobe.adms.measurement.</item>\n        <item>jonathanfinerty.once</item>\n        <item>com.idanatz.oneadapter</item>\n        <item>com.oneaudience.sdk.</item>\n        <item>com.onesignal.</item>\n        <item>com.onetrust.</item>\n        <item>info.guardianproject.onionkit</item>\n        <item>com.onyx.android.sdk</item>\n        <item>com.ooyala</item>\n        <item>com.iheartradio.m3u8</item>\n        <item>com.openback</item>\n        <item>org.opencv</item>\n        <item>io.opencensus</item>\n        <item>at.stefl.opendocument.java</item>\n        <item>org.openjax.security.nacl</item>\n        <item>org.openjdk</item>\n        <item>com.safegraph.</item>\n        <item>com.openlocate</item>\n        <item>com.spatialdev.osm</item>\n        <item>org.redcross.openmapkit</item>\n        <item>com.openmediation.sdk.</item>\n        <item>com.crosspromotion.sdk</item>\n        <item>org.openintents.openpgp</item>\n        <item>org.osmdroid</item>\n        <item>io.opencensus</item>\n        <item>io.opentelemetry</item>\n        <item>org.opentripplanner</item>\n        <item>org.openudid.</item>\n        <item>org.OpenUDID.</item>\n        <item>org.openudid</item>\n        <item>de.blinkt.openvpn</item>\n        <item>com.openx.view.plugplay</item>\n        <item>com.openx.android_sdk_openx</item>\n        <item>com.huawei.openalliance.ad.</item>\n        <item>com.huawei.hms.aaid.</item>\n        <item>com.huawei.hianalytics.</item>\n        <item>au.com.bytecode.opencsv</item>\n        <item>com.opencsv</item>\n        <item>ch.poole.openinghoursparser</item>\n        <item>com.opensignal.datacollection.</item>\n        <item>net.opentracker.android</item>\n        <item>com.optimizely.</item>\n        <item>top.oply</item>\n        <item>com.subgraph.orchid</item>\n        <item>dev.leonlatsch.osslicenseview</item>\n        <item>com.otherlevels.</item>\n        <item>com.squareup.otto</item>\n        <item>com.outbrain.</item>\n        <item>outbid.com.outbidsdk.</item>\n        <item>com.mixiaoxiao.overscroll</item>\n        <item>com.chauthai.overscroll</item>\n        <item>cz.intik.overflowindicator</item>\n        <item>com.discord.panels</item>\n        <item>au.com.oztam.</item>\n        <item>com.peanutlabs.plsdk.</item>\n        <item>com.markodevcic.peko</item>\n        <item>com.beautycoder.pflockscreen</item>\n        <item>com.rtchagas.pingplacepicker</item>\n        <item>ar.com.hjg.pngj</item>\n        <item>com.pokkt.sdk.</item>\n        <item>com.downloader</item>\n        <item>org.khelekore.prtree</item>\n        <item>io.flutter.plugins.packageinfo</item>\n        <item>com.rd.animation</item>\n        <item>com.rd.draw</item>\n        <item>com.rd.pageindicatorview</item>\n        <item>androidx.paging</item>\n        <item>io.octo.bear.pago</item>\n        <item>org.eclipse.paho.client.mqttv3</item>\n        <item>androidx.palette</item>\n        <item>com.github.whataa.pandora</item>\n        <item>com.bytedance.sdk.openadsdk</item>\n        <item>com.bytedance.tea.crash.</item>\n        <item>com.bytedance.embedapplog.</item>\n        <item>com.bytedance.applog.</item>\n        <item>com.papaya.offer.</item>\n        <item>com.appflood</item>\n        <item>io.paperdb</item>\n        <item>paperparcel.internal</item>\n        <item>com.fmsirvent.ParallaxEverywhere</item>\n        <item>com.xgc1986.parallaxPagerTransformer</item>\n        <item>org.parceler</item>\n        <item>com.yelp.parcelgen</item>\n        <item>com.airbnb.paris</item>\n        <item>com.parse.Parse</item>\n        <item>com.parse.PushServiceApi</item>\n        <item>com.parse</item>\n        <item>com.parsely.parselyandroid</item>\n        <item>com.github.muhrifqii.parserss</item>\n        <item>com.parsely.parselyandroid</item>\n        <item>it.partytrack.sdk.</item>\n        <item>org.wordpress.passcodelock</item>\n        <item>com.maksim88.passwordedittext</item>\n        <item>org.pwsafe.lib</item>\n        <item>com.github.ihsg.patternlocker</item>\n        <item>me.zhanghai.android.patternlock</item>\n        <item>com.andrognito.patternlockview</item>\n        <item>org.pcap4j</item>\n        <item>es.voghdev.pdfviewpager</item>\n        <item>cfb.pearldiver</item>\n        <item>com.getpebble.android.kit</item>\n        <item>sdk.insert.io.</item>\n        <item>sdk.pendo.io.</item>\n        <item>io.perfmark</item>\n        <item>io.perfmarkr</item>\n        <item>com.greysonparrelli.permiso</item>\n        <item>com.permissionx.guolindev</item>\n        <item>permissions.dispatcher</item>\n        <item>com.franmontiel.persistentcookiejar</item>\n        <item>ly.persona.sdk</item>\n        <item>org.phoenixframework.channels</item>\n        <item>com.chariotsolutions.nfc.plugin</item>\n        <item>com.phonegap.plugins.barcodescanner</item>\n        <item>me.relex.photodraweeview</item>\n        <item>uk.co.senab.photoview</item>\n        <item>com.github.chrisbanes.photoview</item>\n        <item>com.sarriaroman.PhotoViewer</item>\n        <item>com.phunware.advertising.</item>\n        <item>com.squareup.picasso</item>\n        <item>com.squareup.picasso3</item>\n        <item>com.jakewharton.picasso</item>\n        <item>jp.wasabeef.picasso.transformations</item>\n        <item>com.github.florent37.picassopalette</item>\n        <item>org.mariotaku.pickncrop</item>\n        <item>com.reactnativecommunity.picker</item>\n        <item>com.foursquare.pilgrim</item>\n        <item>com.foursquare.pilgrimsdk.android</item>\n        <item>com.andrognito.pinlockview</item>\n        <item>com.pincrux.</item>\n        <item>com.pingstart.adsdk.</item>\n        <item>com.hb.views</item>\n        <item>com.pinterest.android.pdk.</item>\n        <item>com.github.javiersantos.licensing</item>\n        <item>com.github.javiersantos.piracychecker</item>\n        <item>org.piwik</item>\n        <item>com.fxn.pix</item>\n        <item>com.neopixl.pixlui</item>\n        <item>com.oneclickaway.opensource.placeautocomplete</item>\n        <item>com.placed.client</item>\n        <item>com.placer.client.Placer</item>\n        <item>com.google.android.gms.games</item>\n        <item>com.google.games</item>\n        <item>com.android.installreferrer</item>\n        <item>com.ugi.play_install_referrer</item>\n        <item>com.google.android.gms.places_placereport</item>\n        <item>com.google.android.gms.safetynet</item>\n        <item>com.playfab.PlayFab</item>\n        <item>com.cleveroad.play_widget</item>\n        <item>klb.android.GameEngine</item>\n        <item>com.playtestcloud.Analytics</item>\n        <item>co.vmob.sdk</item>\n        <item>com.plleti.offerwall.</item>\n        <item>com.pointinside</item>\n        <item>jp.co.polarify</item>\n        <item>com.pollfish</item>\n        <item>com.pontiflex.mobile</item>\n        <item>com.offbynull.portmapper</item>\n        <item>com.posthog.android</item>\n        <item>com.skydoves.powermenu</item>\n        <item>com.skydoves.powerspinner</item>\n        <item>org.prebid.mobile</item>\n        <item>com.telescope.android</item>\n        <item>io.predic.tracker</item>\n        <item>androidx.preference</item>\n        <item>com.mostafa.previewanyfile</item>\n        <item>com.aminography.primecalendar</item>\n        <item>androidx.print</item>\n        <item>com.jakewharton.processphoenix</item>\n        <item>jp.profilepassport.android.</item>\n        <item>.ppSDK.</item>\n        <item>androidx.profileinstaller</item>\n        <item>br.com.simplepass.loadingbutton</item>\n        <item>com.filippudak.ProgressPieView</item>\n        <item>com.skydoves.progressview</item>\n        <item>org.locationtech.proj4j</item>\n        <item>lombok</item>\n        <item>org.witness.proofmode</item>\n        <item>me.proton.core</item>\n        <item>io.proximi.proximiiolibrary</item>\n        <item>com.aefyr.pseudoapksigner</item>\n        <item>com.pubmatic.sdk</item>\n        <item>net.pubnative</item>\n        <item>com.pubnub.api.</item>\n        <item>de.schildbach.pte</item>\n        <item>com.pulsatehq.</item>\n        <item>com.pushspring.sdk.PushSpring</item>\n        <item>com.pushbullet.android</item>\n        <item>com.pusher.client.</item>\n        <item>com.pushwoosh</item>\n        <item>me.pushy.sdk.</item>\n        <item>com.pyze.</item>\n        <item>com.quseit</item>\n        <item>com.dlazaro66.qrcodereaderview</item>\n        <item>net.glxn.qrgen</item>\n        <item>androidmads.library.qrgenearator</item>\n        <item>com.qihoo.util.</item>\n        <item>com.qihoo360.mobilesafe.loader.</item>\n        <item>com.qihoo360.replugin.</item>\n        <item>org.qtproject</item>\n        <item>data.acquisition.sdk.</item>\n        <item>com.qualtrics.digital.</item>\n        <item>com.quantcast.measurement.service.</item>\n        <item>com.quantumgraph.</item>\n        <item>com.appier.</item>\n        <item>me.piruin.quickaction</item>\n        <item>com.tianscar.quickbitmap</item>\n        <item>com.quickblox</item>\n        <item>app.cash.quickjs</item>\n        <item>com.andraskindler.quickscroll</item>\n        <item>com.softwaremill.quicklens</item>\n        <item>com.fewlaps.quitnowcache</item>\n        <item>chat.rocket.rnshareextension</item>\n        <item>com.prof.rssparser</item>\n        <item>com.jkcarino.rtexteditorview</item>\n        <item>io.radar.sdk.Radar</item>\n        <item>co.ceryle.radiorealbutton</item>\n        <item>com.radiusnetworks</item>\n        <item>org.rajawali3d</item>\n        <item>com.rakuten.tech.mobile.analytics.</item>\n        <item>co.jp.rakuten.sdtd.analytics</item>\n        <item>com.rakuten.android.ads</item>\n        <item>com.rakuten.gap.ads</item>\n        <item>com.stedi.randomimagegenerator</item>\n        <item>com.edmodo.rangebar</item>\n        <item>com.jaygoo.widget</item>\n        <item>com.github.thibseisel.ratioimageview</item>\n        <item>com.mindscapehq.android.raygun4android</item>\n        <item>com.getkeepsafe.relinker</item>\n        <item>com.facebook.jni</item>\n        <item>com.facebook.quicklog</item>\n        <item>com.facebook.proguard</item>\n        <item>com.facebook.perftest</item>\n        <item>com.facebook.react</item>\n        <item>com.facebook.systrace</item>\n        <item>com.facebook.yoga</item>\n        <item>com.tectiv3.aes</item>\n        <item>com.emekalites.react.alarm.notification</item>\n        <item>com.reactnativecommunity.asyncstorage</item>\n        <item>com.ocetnik.timer</item>\n        <item>com.idehub.Billing</item>\n        <item>com.rusel.RCTBluetoothSerial</item>\n        <item>com.cmcewen.blurview</item>\n        <item>com.lwansbrough.RCTCamera</item>\n        <item>org.reactnative.barcodedetector</item>\n        <item>org.reactnative.camera</item>\n        <item>org.reactnative.facedetector</item>\n        <item>org.reactnative.frame</item>\n        <item>com.wix.RNCameraKit.camera</item>\n        <item>com.rncamerakit</item>\n        <item>com.rt2zz.reactnativecontacts</item>\n        <item>com.reactcommunity.rndatetimepicker</item>\n        <item>com.emeraldsanto.encryptedstorage</item>\n        <item>com.hieuvp.fingerprint</item>\n        <item>com.swmansion.gesturehandler</item>\n        <item>co.apptailor.googlesignin</item>\n        <item>com.imagepicker</item>\n        <item>fr.bamlab.rnimageresizer</item>\n        <item>com.mattblock.reactnative.inappbrowser</item>\n        <item>org.reactnative.maskedview</item>\n        <item>com.microsoft.codepush.react</item>\n        <item>com.reactnativenavigation</item>\n        <item>com.thebylito.navigationbarcolor</item>\n        <item>com.wix.reactnativenotifications</item>\n        <item>com.github.yamill.orientation</item>\n        <item>com.dieam.reactnativepushnotification</item>\n        <item>com.reactNativeQuickActions</item>\n        <item>com.swmansion.reanimated</item>\n        <item>com.avishayil.rnrestart</item>\n        <item>dog.craftz.sqlite_2</item>\n        <item>org.umhan35</item>\n        <item>br.com.classapp.RNSensitiveInfo</item>\n        <item>com.clipsub.RNShake</item>\n        <item>com.alinz.parkerdan.shareextension</item>\n        <item>com.remobile.toast</item>\n        <item>com.rnfingerprint</item>\n        <item>com.goldenowl.twittersignin</item>\n        <item>com.reactnativecommunity.webview</item>\n        <item>com.rnziparchive</item>\n        <item>com.doublesymmetry.trackplayer</item>\n        <item>px.tooltips</item>\n        <item>com.babisoft.ReactNativeLocalization</item>\n        <item>org.reactivestreams</item>\n        <item>com.github.pwittchen.reactivenetwork.library</item>\n        <item>com.github.pwittchen.reactivesensors</item>\n        <item>reactor.adapter</item>\n        <item>reactor.core</item>\n        <item>reactor.util</item>\n        <item>net.dankito.readability4j</item>\n        <item>io.realm</item>\n        <item>com.github.mmin18.realtimeblurview</item>\n        <item>com.github.mmin18.widget</item>\n        <item>com.facebook.rebound</item>\n        <item>com.mediabrix.android</item>\n        <item>irismod.record</item>\n        <item>com.futuremind.recyclerviewfastscroll</item>\n        <item>com.pluscubed.recyclerfastscroll</item>\n        <item>pluscubed.recyclerfastscroll</item>\n        <item>com.dinuscxj.itemdecoration</item>\n        <item>com.dinuscxj.refresh</item>\n        <item>jp.wasabeef.recyclerview</item>\n        <item>com.bignerdranch.android.multiselector</item>\n        <item>com.simplecityapps.recyclerview_fastscroll</item>\n        <item>com.yqritc.recyclerviewflexibledivider</item>\n        <item>com.qtalk.recyclerviewfastscroller</item>\n        <item>it.xabaras.android.recyclerview.swipedecorator</item>\n        <item>com.crazylegend.recyclerview</item>\n        <item>com.afollestad.recyclical</item>\n        <item>cc.redberry</item>\n        <item>com.esotericsoftware.reflectasm</item>\n        <item>com.llew.reflect</item>\n        <item>com.labo.kaji.relativepopupwindow</item>\n        <item>com.overzealous.remark</item>\n        <item>com.crossbowffs.remotepreferences</item>\n        <item>com.google.android.renderscript</item>\n        <item>com.pedrogomez.renderers</item>\n        <item>com.github.ajalt.reprint</item>\n        <item>io.repro.android.</item>\n        <item>si.mazi.rescu</item>\n        <item>androidx.resourceinspection</item>\n        <item>org.mariotaku.restfu</item>\n        <item>org.chickenhook.restrictionbypass</item>\n        <item>com.github.kittinunf.result</item>\n        <item>com.retency.sdk.android</item>\n        <item>retrofit2</item>\n        <item>com.stepleaderdigital.reveal</item>\n        <item>com.stepleaderdigital.reveal</item>\n        <item>com.revenuecat.</item>\n        <item>com.revmob.ads.</item>\n        <item>jp.wasabeef.richeditor</item>\n        <item>com.zzhoujay.richtext</item>\n        <item>rikka.preference</item>\n        <item>rikka.widget</item>\n        <item>rikka.html</item>\n        <item>rikka.annotation</item>\n        <item>rikka.appcompat</item>\n        <item>rikka.material</item>\n        <item>rikka.multiprocesspreference</item>\n        <item>rikka.recyclerview-utils</item>\n        <item>rikka.lifecycle</item>\n        <item>com.ringdroid</item>\n        <item>com.andexert.library</item>\n        <item>com.rjfun.cordova.ad</item>\n        <item>com.rjfun.cordova.admob</item>\n        <item>org.roboguice</item>\n        <item>roboguice</item>\n        <item>com.rollbar.android.</item>\n        <item>com.rometools</item>\n        <item>io.rong.imlib</item>\n        <item>io.rong.message</item>\n        <item>io.rong.push</item>\n        <item>androidx.room</item>\n        <item>dev.matrix.roomigrant</item>\n        <item>in.sunilpaulmathew.rootfilepicker</item>\n        <item>com.scottyab.rootbeer</item>\n        <item>org.sufficientlysecure.rootcommands</item>\n        <item>com.fox2code.rosettax</item>\n        <item>com.deishelon.roundedbottomsheet</item>\n        <item>com.makeramen.roundedimageview</item>\n        <item>com.roximity.sdk.</item>\n        <item>com.booking.rtlviewpager</item>\n        <item>com.rfm.sdk</item>\n        <item>com.rfm.sdk</item>\n        <item>com.rumble.sdk</item>\n        <item>com.werdpressed.partisan.rundo</item>\n        <item>com.mukesh</item>\n        <item>com.f2prateek.rx.preferences</item>\n        <item>com.f2prateek.rx.preferences2</item>\n        <item>com.f2prateek.rx.receivers</item>\n        <item>com.miguelbcr.io.rx_billing_service</item>\n        <item>com.jakewharton.rxbinding</item>\n        <item>com.jakewharton.rxbinding2</item>\n        <item>com.jakewharton.rxbinding3</item>\n        <item>com.jakewharton.rxbinding4</item>\n        <item>com.hwangjr.rxbus</item>\n        <item>com.ragnarok.rxcamera</item>\n        <item>com.uber.rxdogtag</item>\n        <item>zlc.season.rxdownload3</item>\n        <item>com.esafirm.rxdownloader</item>\n        <item>com.github.b3er.rxfirebase</item>\n        <item>rxhttp</item>\n        <item>com.mlsdev.rximagepicker</item>\n        <item>io.reactivex</item>\n        <item>com.jakewharton.rx3</item>\n        <item>hu.akarnokd.rxjava2</item>\n        <item>hu.akarnokd.rxjava.interop</item>\n        <item>com.artemzin.rxjavaproguardrules</item>\n        <item>com.trello.rxlifecycle</item>\n        <item>com.trello.rxlifecycle3</item>\n        <item>com.tbruyelle.rxpermissions</item>\n        <item>com.tbruyelle.rxpermissions2</item>\n        <item>com.jakewharton.rxrelay</item>\n        <item>com.jakewharton.rxrelay2</item>\n        <item>com.github.florent37.retrojsoup</item>\n        <item>com.github.florent37.rxjsoup</item>\n        <item>com.github.tamsiree.RxTool</item>\n        <item>com.github.vondear.RxTools</item>\n        <item>com.tans.rxutils</item>\n        <item>com.afollestad.rxkprefs</item>\n        <item>com.sam4mobile.</item>\n        <item>.S4MAnalytic</item>\n        <item>com.gigya.</item>\n        <item>com.sas.mkt.mobile.sdk.</item>\n        <item>com.sas.mkt.mobile.sdk</item>\n        <item>org.xml.sax</item>\n        <item>com.dev.sacot41.scviewpager</item>\n        <item>com.sdkbox.</item>\n        <item>org.libsdl</item>\n        <item>com.intuit.sdp</item>\n        <item>io.github.novacrypto.hashing</item>\n        <item>com.skplanet.tad</item>\n        <item>com.ss.android.</item>\n        <item>com.squareup.sqlbrite</item>\n        <item>com.squareup.sqlbrite2</item>\n        <item>com.squareup.sqlbrite3</item>\n        <item>net.sqlcipher</item>\n        <item>com.squareup.sqldelight</item>\n        <item>androidx.sqlite</item>\n        <item>org.sqlite</item>\n        <item>org.mariotaku.sqliteqb</item>\n        <item>com.ajts.androidmads.library</item>\n        <item>com.github.Drabu.SSNInputView</item>\n        <item>com.intuit.ssp</item>\n        <item>com.openlocate</item>\n        <item>com.safegraph</item>\n        <item>com.sailthru</item>\n        <item>com.salesforce.marketingcloud</item>\n        <item>com.samsung.android.sdk</item>\n        <item>com.samsung.accessory</item>\n        <item>androidx.apppickerview</item>\n        <item>androidx.indexscroll</item>\n        <item>androidx.picker</item>\n        <item>androidx.picker3</item>\n        <item>androidx.reflect</item>\n        <item>com.samsung.android.sdk.look</item>\n        <item>com.samsung.android.sdk.pass</item>\n        <item>com.samsung.util</item>\n        <item>com.samsung.context.sdk.samsunganalytics.</item>\n        <item>com.sec.android.diagmonagent.</item>\n        <item>org.sandrop</item>\n        <item>org.sandroproxy</item>\n        <item>com.sayso.ui.</item>\n        <item>com.sayso.utils.</item>\n        <item>scala</item>\n        <item>org.scaloid</item>\n        <item>com.scanlibrary</item>\n        <item>com.scandit.</item>\n        <item>com.tinder.scarlet</item>\n        <item>com.google.ar.sceneform</item>\n        <item>.schibsted.</item>\n        <item>com.lyft.android.scissors</item>\n        <item>com.lyft.scoop</item>\n        <item>com.optimizely</item>\n        <item>com.scoreloop.client.android</item>\n        <item>com.elylucas.capscreenbrightness</item>\n        <item>org.scribe</item>\n        <item>com.github.scribejava</item>\n        <item>com.googlecode.android_scripting</item>\n        <item>io.github.deweyreed.scrollhmspicker</item>\n        <item>com.bytehamster.lib.preferencesearch</item>\n        <item>com.lapism.searchview</item>\n        <item>com.toptoche.searchablespinnerlibrary</item>\n        <item>io.github.luizgrp.sectionedrecyclerviewadapter</item>\n        <item>org.jboss.security.srp</item>\n        <item>com.playseeds.android</item>\n        <item>com.triggertrap.seekarc</item>\n        <item>com.yokkomi.commons.preference.seekbar</item>\n        <item>com.segment.analytics.</item>\n        <item>com.squareup.seismic</item>\n        <item>com.vdurmont.semver4j</item>\n        <item>de.mindlib.sendIntent</item>\n        <item>com.sendbird.android</item>\n        <item>co.sensara.sensy</item>\n        <item>com.sense360.android.</item>\n        <item>com.sensoro.beacon.kit.</item>\n        <item>com.sensoro.cloud</item>\n        <item>com.sensorsdata.analytics.android.sdk</item>\n        <item>com.sentiance.sdk.</item>\n        <item>io.sentry.</item>\n        <item>com.joshdholtz.sentry</item>\n        <item>io.sentry</item>\n        <item>com.joshdholtz.sentry</item>\n        <item>github.daneren2005.serverproxy</item>\n        <item>ninja.sesame</item>\n        <item>ezy.assist.compat</item>\n        <item>ezy.assist.settingscompat</item>\n        <item>com.android.setupwizardlib</item>\n        <item>SevenZip.Compression</item>\n        <item>seventynine.sdk.</item>\n        <item>com.gigamole.library</item>\n        <item>com.jm.co.shallwead.sdk.</item>\n        <item>com.co.shallwead.sdk.</item>\n        <item>com.github.florent37.shapeofview</item>\n        <item>cn.gavinliu.android.lib.shapedimageview</item>\n        <item>io.flutter.plugins.share</item>\n        <item>com.zt.shareextend</item>\n        <item>androidx.sharetarget</item>\n        <item>com.pixplicity.sharp</item>\n        <item>com.singhajit.sherlock</item>\n        <item>com.romainpiel.shimmer</item>\n        <item>com.facebook.shimmer</item>\n        <item>com.cooltechworks.views.shimmer</item>\n        <item>com.sackcentury.shinebuttonlib</item>\n        <item>moe.shizuku.api</item>\n        <item>rikka.shizuku</item>\n        <item>com.shopkick.sdk.api.</item>\n        <item>com.shopkick.fetchers.</item>\n        <item>shortbread</item>\n        <item>me.leolin.shortcutbadger</item>\n        <item>com.njlabs.showjava</item>\n        <item>com.github.amlcurran.showcaseview</item>\n        <item>com.shuwei.location.</item>\n        <item>org.thoughtcrime.securesms</item>\n        <item>org.whispersystems.libsignal</item>\n        <item>com.signal360.sdk.core.</item>\n        <item>com.sonicnotify.sdk.core.</item>\n        <item>com.rnsignal360</item>\n        <item>com.wirelessregistry.observersdk.</item>\n        <item>james.signalstrengthslib</item>\n        <item>com.kyanogen.signatureview</item>\n        <item>oauth.signpost</item>\n        <item>com.silverpush.</item>\n        <item>org.simmetrics</item>\n        <item>com.simperium</item>\n        <item>org.simpleframework.xml</item>\n        <item>org.w3c.css.sac</item>\n        <item>com.simplemobiletools.commons</item>\n        <item>mil.nga.sf</item>\n        <item>com.marcdonald.simplelicensedisplay</item>\n        <item>org.slf4j</item>\n        <item>com.isseiaoki.simplecropview</item>\n        <item>eltos.simpledialogfragment</item>\n        <item>in.championswimmer.sfg</item>\n        <item>com.github.faucamp.simplertmp</item>\n        <item>com.ferfalk.simplesearchview</item>\n        <item>com.anggrayudi.storage</item>\n        <item>com.maxproj.simplewaveform</item>\n        <item>com.github.florent37.singledateandtimepicker</item>\n        <item>com.sptproximitykit.</item>\n        <item>com.singular.sdk</item>\n        <item>com.sina.weibo.sdk</item>\n        <item>es.situm.sdk.</item>\n        <item>.sizmek.</item>\n        <item>com.faltenreich.skeletonlayout</item>\n        <item>com.skillz.Skillz</item>\n        <item>com.github.skytube.components</item>\n        <item>com.skyhook.context.Accelerator</item>\n        <item>com.ncorti.slidetoact</item>\n        <item>me.jfenn.slideactionview</item>\n        <item>com.yydcdut.sdlv</item>\n        <item>hollowsoft.slidingdrawer</item>\n        <item>com.jeremyfeinstein.slidingmenu</item>\n        <item>com.slidingmenu</item>\n        <item>androidx.slidingpanelayout</item>\n        <item>com.r0adkll.slidr</item>\n        <item>com.smaato.</item>\n        <item>org.igniterealtime.smack</item>\n        <item>com.smartadserver.</item>\n        <item>io.nlopez.smartlocation</item>\n        <item>com.smrtbeat.</item>\n        <item>com.smartlook.sdk.smartlook.</item>\n        <item>com.scwang.smartrefresh</item>\n        <item>kr.co.smartstudy</item>\n        <item>com.ogaclejapan.smarttablayout</item>\n        <item>com.smartyads</item>\n        <item>fr.castorflex.android.smoothprogressbar</item>\n        <item>fr.castorflex.android.circularprogressbar</item>\n        <item>me.dkzwm.widget.srl</item>\n        <item>com.kenny.snackbar</item>\n        <item>org.ligi.snackengage</item>\n        <item>de.jetwick.snacktory</item>\n        <item>de.mateware.snacky</item>\n        <item>org.yaml.snakeyaml</item>\n        <item>org.snakeyaml.engine</item>\n        <item>com.snap.adkit</item>\n        <item>com.snap.appadskit</item>\n        <item>com.snapchat.kit.sdk</item>\n        <item>com.snapchat.kit.sdk.SnapLogin</item>\n        <item>dev.chrisbanes.snapper</item>\n        <item>org.iq80.snappy</item>\n        <item>com.snappydb</item>\n        <item>com.nshmura.snappysmoothscroller</item>\n        <item>org.tartarus.snowball</item>\n        <item>com.snowplowanalytics.</item>\n        <item>com.facebook.soloader</item>\n        <item>io.socket</item>\n        <item>com.ansca.corona</item>\n        <item>com.sonyericsson.cameracommon</item>\n        <item>com.soomla.</item>\n        <item>com.github.wrdlbrnft.sortedlistadapter</item>\n        <item>com.soundhound.android.adverts</item>\n        <item>com.twofortyfouram.spackle</item>\n        <item>com.robinhood.spark</item>\n        <item>at.connyduck.sparkbutton</item>\n        <item>com.thebluealliance.spectrum</item>\n        <item>edu.cmu.sphinx</item>\n        <item>io.split.android.</item>\n        <item>com.fsck.splitview</item>\n        <item>splitties</item>\n        <item>com.splunk.mint</item>\n        <item>org.spongycastle</item>\n        <item>com.spoteer.arc.</item>\n        <item>com.spotify.mobile.android.ads.</item>\n        <item>com.spotify.music.features.ads.</item>\n        <item>com.spotify.music.ads.</item>\n        <item>com.spotify.ads.</item>\n        <item>com.spotify.music.libs.adbasedondemand.</item>\n        <item>com.spotify.nativeads.</item>\n        <item>com.spotify.sdk</item>\n        <item>com.spotify.webapi</item>\n        <item>kaaes.spotify.webapi</item>\n        <item>com.wooplr.spotlight</item>\n        <item>dmax.dialog</item>\n        <item>org.springframework</item>\n        <item>github.chenupt.springindicator</item>\n        <item>com.linkedin.android.spyglass</item>\n        <item>com.squareup.cycler</item>\n        <item>com.squareup.logcat</item>\n        <item>com.beaconinside.proximitysdk.ProximityService</item>\n        <item>com.yahoo.squidb</item>\n        <item>com.blacksquircle.ui</item>\n        <item>at.stefl.svm</item>\n        <item>com.startapp.</item>\n        <item>androidx.startup</item>\n        <item>com.lxj.statelayout</item>\n        <item>com.jaeger.library</item>\n        <item>org.codehaus.stax2</item>\n        <item>com.hapramp.steemconnect4j</item>\n        <item>at.stefl.commons</item>\n        <item>params.com.stepprogressview</item>\n        <item>com.baoyachi.stepview</item>\n        <item>com.badoualy.stepperindicator</item>\n        <item>me.drozdzynski.library.steppers</item>\n        <item>com.stericson.RootShell</item>\n        <item>com.example.RootTools</item>\n        <item>com.stericson.RootTools</item>\n        <item>com.stericson.RootToolsTest</item>\n        <item>com.facebook.stetho</item>\n        <item>com.uphyca.stetho_realm</item>\n        <item>com.xiaopo.flying.sticker</item>\n        <item>com.codewaves.stickyheadergrid</item>\n        <item>com.tonicartos.widget.stickygridheaders</item>\n        <item>com.brandongogetap.stickyheaders</item>\n        <item>se.emilsjolander.stickylistheaders</item>\n        <item>com.pushtorefresh.storio</item>\n        <item>com.pushtorefresh.storio3</item>\n        <item>com.codekidlabs.storagechooser</item>\n        <item>com.nytimes.android.external</item>\n        <item>jp.shts.android.library</item>\n        <item>com.stripe.android</item>\n        <item>com.appeaser.sublimepickerlibrary</item>\n        <item>com.skydoves.submarine</item>\n        <item>com.unstoppable.submitbuttonview</item>\n        <item>com.davemorrissey.labs.subscaleview</item>\n        <item>substratum.theme.template</item>\n        <item>rikka.sui</item>\n        <item>com.sun.mail</item>\n        <item>com.luckycatlabs.sunrisesunset</item>\n        <item>ca.rmen.sunrisesunset</item>\n        <item>me.jfenn.sunrisesunsetview</item>\n        <item>org.supercsv</item>\n        <item>tv.superawesome.sdk</item>\n        <item>tv.superawesome.lib.</item>\n        <item>com.tonicartos.superslim</item>\n        <item>com.github.johnpersano.supertoasts</item>\n        <item>com.nhaarman.supertooltips</item>\n        <item>jp.supership.vamp.</item>\n        <item>com.supersonic.adapters.supersonicads</item>\n        <item>com.supersonicads.sdk</item>\n        <item>com.github.machinarius.preferencefragment</item>\n        <item>com.microsoft.device.display</item>\n        <item>com.microsoft.device.dualscreen</item>\n        <item>io.swagger</item>\n        <item>cn.pedant.SweetAlert</item>\n        <item>org.swiftp</item>\n        <item>com.ebanx.swipebtn</item>\n        <item>com.wdullaer.swipeactionadapter</item>\n        <item>me.imid.swipebacklayout</item>\n        <item>com.huxq17.swipecardsview</item>\n        <item>com.daprlabs.aaron.swipedeck</item>\n        <item>com.baoyz.swipemenulistview</item>\n        <item>com.yanzhenjie.recyclerview.swipe</item>\n        <item>com.chauthai.swipereveallayout</item>\n        <item>com.roughike.swipeselector</item>\n        <item>co.dift.ui</item>\n        <item>androidx.swiperefreshlayout</item>\n        <item>com.orangegangsters.github.swipyrefreshlayout</item>\n        <item>com.omadahealth.github.swipyrefreshlayout</item>\n        <item>com.swirl</item>\n        <item>com.kyleduo.switchbutton</item>\n        <item>com.swrve.sdk</item>\n        <item>com.visiware.sync2ad.dmp</item>\n        <item>org.matheclipse</item>\n        <item>com.visiware.sync2ad.dmp.</item>\n        <item>com.synerise.sdk</item>\n        <item>net.taparound.</item>\n        <item>com.taiwanmobile.pt.adp.</item>\n        <item>mil.nga.tiff</item>\n        <item>com.tjhello.ab.</item>\n        <item>com.tnkfactory.ad</item>\n        <item>com.evrencoskun.tableview</item>\n        <item>com.taboola.</item>\n        <item>com.tagcommander</item>\n        <item>com.tagcommander.</item>\n        <item>org.ccil.cowan.tagsoup</item>\n        <item>com.talkingdata.sdk.</item>\n        <item>com.tendcloud.tenddata.</item>\n        <item>com.talkingdata.appanalytics.</item>\n        <item>com.talkingdata.adtracking.</item>\n        <item>com.tendcloud.appcpa.</item>\n        <item>com.apptalkingdata.push.</item>\n        <item>com.gametalkingdata.push.</item>\n        <item>com.tamoco.sdk</item>\n        <item>com.mapzen.tangram</item>\n        <item>com.tapit.</item>\n        <item>com.tapr.sdk.</item>\n        <item>com.tapr.internal.</item>\n        <item>com.tapr.helpers.</item>\n        <item>com.getkeepsafe.taptargetview</item>\n        <item>com.tapad.adserving</item>\n        <item>com.tapad.tracking</item>\n        <item>com.tapdaq.sdk.</item>\n        <item>com.tapdaq.adapters.</item>\n        <item>com.squareup.tape2</item>\n        <item>com.tapjoy.</item>\n        <item>com.taplytics.sdk</item>\n        <item>com.tappx.sdk.android</item>\n        <item>com.tapstream.sdk</item>\n        <item>be.tarsos.dsp</item>\n        <item>com.farmerbb.taskbar</item>\n        <item>net.dinglisch.android.tasker</item>\n        <item>net.dinglisch.ipack</item>\n        <item>com.joaomgcd.taskerpluginlibrary</item>\n        <item>com.sdsmdg.tastytoast</item>\n        <item>tv.teads.</item>\n        <item>teads.tv.</item>\n        <item>com.tl.uic.Tealeaf</item>\n        <item>tealium.</item>\n        <item>com.github.theholywaffle.teamspeak3</item>\n        <item>com.gun0912.ted.tedbottompicker</item>\n        <item>gun0912.ted.tedbottompicker</item>\n        <item>gun0912.ted.tedimagepicker</item>\n        <item>gun0912.ted.tedkeyboardobserver</item>\n        <item>gun0912.ted.tedclustering-naver</item>\n        <item>com.gun0912.tedpermission</item>\n        <item>gun0912.ted.tedonactivityresult-rx1</item>\n        <item>com.databerries.</item>\n        <item>com.geolocstation.</item>\n        <item>com.tremorvideo.sdk.</item>\n        <item>com.telequid.</item>\n        <item>com.telerik.android</item>\n        <item>com.teliver.sdk.</item>\n        <item>com.tencent.mta</item>\n        <item>com.tencent.lbs</item>\n        <item>com.tencent.mapsdk</item>\n        <item>com.tencent.tencentmap</item>\n        <item>com.tencent.mobwin</item>\n        <item>com.qq.e.tg.</item>\n        <item>com.qq.e.ads.</item>\n        <item>com.qq.e.comm.</item>\n        <item>com.qq.e.ads</item>\n        <item>com.tencent.stat</item>\n        <item>com.tencent.wxop.stat</item>\n        <item>com.tencent.mm</item>\n        <item>com.tencent.mm.opensdk</item>\n        <item>com.tencent.connect.</item>\n        <item>wxapi.</item>\n        <item>com.tencent.weiyun</item>\n        <item>com.tencent.lbssearch</item>\n        <item>tendermint</item>\n        <item>com.tenjin.android.</item>\n        <item>com.tenjin.android.TenjinSDK</item>\n        <item>org.tensorflow</item>\n        <item>jackpal.androidterm</item>\n        <item>com.googlecode.leptonica</item>\n        <item>com.googlecode.tesseract</item>\n        <item>cz.adaptech.android.tesseract4android</item>\n        <item>com.amulyakhare.textdrawable</item>\n        <item>com.facebook.fbui.textlayoutbuilder</item>\n        <item>com.tolstykh.textviewrichdrawable</item>\n        <item>net.java.textilej</item>\n        <item>com.sprylab.android.widget</item>\n        <item>opentk</item>\n        <item>opentk_1_0</item>\n        <item>de.matthiasmann.twl</item>\n        <item>xyz.aprildown.theme</item>\n        <item>nl.bryanderidder.themedtogglebuttongroup</item>\n        <item>theoremreach.com.theoremreach.</item>\n        <item>cn.thinkingdata.</item>\n        <item>net.grandcentrix.thirtyinch</item>\n        <item>com.jakewharton.threetenabp</item>\n        <item>org.threeten.bp</item>\n        <item>com.rkam.swiperefreshlayout</item>\n        <item>com.wwl.canvas</item>\n        <item>com.robinhood.ticker</item>\n        <item>org.jvnet.tiger_types</item>\n        <item>com.muf.sdk.tiktok.</item>\n        <item>com.tickaroo.tikxml</item>\n        <item>com.qozix.tileview</item>\n        <item>com.naman14.timber</item>\n        <item>net.time4j</item>\n        <item>me.jfenn.timedatepickers</item>\n        <item>mobi.upod.timedurationpicker</item>\n        <item>com.sztorm.timepicker</item>\n        <item>com.github.vipulasri.timelineview</item>\n        <item>com.arsvechkarev.timerx</item>\n        <item>timerx</item>\n        <item>me.yaoandy107.ntut_timetable</item>\n        <item>com.github.tlaabs.timetableview</item>\n        <item>com.tinder.ads</item>\n        <item>com.tinder.analytics</item>\n        <item>com.tinder.ads</item>\n        <item>com.google.crypto.tink</item>\n        <item>com.tencent.tinker</item>\n        <item>com.github.promeg.pinyinhelper</item>\n        <item>io.github.novacrypto.toruntime</item>\n        <item>me.drakeet.support.toast</item>\n        <item>es.dmoral.toasty</item>\n        <item>com.matthewchen.togetherad</item>\n        <item>com.github.angads25.toggle</item>\n        <item>com.nex3z.togglebuttongroup</item>\n        <item>com.tokenautocomplete</item>\n        <item>com.tokenautocompleteexample</item>\n        <item>com.tomergoldst.tooltips</item>\n        <item>toothpick</item>\n        <item>io.horizontalsystems.tor</item>\n        <item>io.matthewnelson.topl_core</item>\n        <item>io.matthewnelson.topl_core_base</item>\n        <item>io.matthewnelson.topl_service</item>\n        <item>io.matthewnelson.topl_service_base</item>\n        <item>io.matthewnelson.tor_binary</item>\n        <item>im.ene.toro</item>\n        <item>com.github.se_bastiaan.torrentstream</item>\n        <item>com.ortiz.touch</item>\n        <item>com.tspoon.traceur</item>\n        <item>androidx.tracing</item>\n        <item>com.tradplus.ads.</item>\n        <item>com.yasesprox.android.transcommusdk</item>\n        <item>com.otaliastudios.transcoder</item>\n        <item>androidx.transition</item>\n        <item>com.royrodriguez.transitionbutton</item>\n        <item>com.transitionseverywhere</item>\n        <item>it.gilvegliach.android.transparenttexttextview</item>\n        <item>net.grandcentrix.tray</item>\n        <item>com.treasuredata</item>\n        <item>trikita.log</item>\n        <item>com.trilead.ssh2</item>\n        <item>com.trillbit.</item>\n        <item>com.triplelift.sdk.</item>\n        <item>com.triplelift.tl_sdk.</item>\n        <item>com.datatheorem.android.trustkit</item>\n        <item>info.guardianproject.trustedintents</item>\n        <item>tun.proxy</item>\n        <item>com.tune</item>\n        <item>com.mobileapptracker</item>\n        <item>com.tutelatechnologies.sdk</item>\n        <item>org.lasque.tusdk.core</item>\n        <item>org.lasque.tusdkpulse.core</item>\n        <item>com.twelvemonkeys</item>\n        <item>com.twine.sdk</item>\n        <item>com.twitter.sdk.android</item>\n        <item>com.mopub.</item>\n        <item>ads.AdsInfoWebViewActivity</item>\n        <item>ads.AdsCompanionWebViewActivity</item>\n        <item>analytics.TweetAnalyticsWebViewActivity</item>\n        <item>com.twitter.android.dogfood.</item>\n        <item>com.twitter.analytics.</item>\n        <item>twitter4j</item>\n        <item>org.deejdev.twowaynestedscrollview</item>\n        <item>com.github.rjeschke.txtmark</item>\n        <item>com.typesafe.config</item>\n        <item>in.codeshuffle.typewriterview</item>\n        <item>com.ucweb.union.ads.</item>\n        <item>com.UCMobile.Apollo.</item>\n        <item>com.akylas.canvas</item>\n        <item>de.martinreinhardt.cordova.plugins.urlhandler</item>\n        <item>com.uxcam.</item>\n        <item>com.ubercab.analytics.</item>\n        <item>com.ubercab.library.metrics.analytics.</item>\n        <item>com.ubercab.client.core.analytics.</item>\n        <item>xyz.aprildown.ultimateringtonepicker</item>\n        <item>com.umeng.analytics</item>\n        <item>com.umeng.analytics</item>\n        <item>com.umeng.commonsdk.stateless</item>\n        <item>com.umeng.commonsdk.statistics</item>\n        <item>com.umeng.socialize.</item>\n        <item>com.umeng.fb</item>\n        <item>com.umeng.umsdk</item>\n        <item>com.umeng.message</item>\n        <item>com.taobao.accs</item>\n        <item>com.taobao.agoo</item>\n        <item>org.android.agoo</item>\n        <item>io.github.muntashirakon.unapkm</item>\n        <item>com.pure.internal.</item>\n        <item>com.pure.sdk.</item>\n        <item>com.hippo.unifile</item>\n        <item>com.onevcat.uniwebview</item>\n        <item>me.xuender.unidecode</item>\n        <item>org.microg.nlp.api</item>\n        <item>org.mariotaku.uniqr</item>\n        <item>com.mashape.unirest</item>\n        <item>com.unity.purchasing</item>\n        <item>com.unity.androidnotifications</item>\n        <item>net.agasper.unitynotification</item>\n        <item>com.unity3d.services</item>\n        <item>com.unity3d.ads</item>\n        <item>com.davikingcode.DetectHeadset</item>\n        <item>com.nostra13.universalimageloader</item>\n        <item>com.zookey.universalpreferences</item>\n        <item>qwapi.adclient.android.view.</item>\n        <item>MediaPlayerWrapper.</item>\n        <item>nbpcorp.</item>\n        <item>com.ad.sdk.</item>\n        <item>com.sen.sdk.sen.</item>\n        <item>com.sen.websdk.</item>\n        <item>service.TrackerService</item>\n        <item>service.Analytics</item>\n        <item>com.nextapps.naswall.</item>\n        <item>BannerActivity</item>\n        <item>InterstitialActivity</item>\n        <item>com.bestgo.adsplugin.</item>\n        <item>com.zero.ta.common.</item>\n        <item>com.zjsoft.baseadlib.</item>\n        <item>de.rocketinternet.android.</item>\n        <item>com.yoc.sdk</item>\n        <item>com.yt.promolib.</item>\n        <item>com.growstarry.</item>\n        <item>com.upsight.android</item>\n        <item>com.urbanairship</item>\n        <item>com.linkedin.urls</item>\n        <item>com.usabilla.sdk.</item>\n        <item>com.felhr.deviceids</item>\n        <item>com.felhr.usbserial</item>\n        <item>com.felhr.utils</item>\n        <item>com.satsuware.usefulviews</item>\n        <item>nl.bitwalker.useragentutils</item>\n        <item>com.userexperior</item>\n        <item>com.uservoice.uservoicesdk</item>\n        <item>com.sentaroh.android.Utilities</item>\n        <item>com.vk.api.sdk</item>\n        <item>com.vk.sdk.api</item>\n        <item>com.vk.sdk.</item>\n        <item>com.vk.api.sdk.</item>\n        <item>com.vanniktech.vntnumberpickerpreference</item>\n        <item>mobi.vserv.android.adengine.</item>\n        <item>org.oscim</item>\n        <item>com.tencent.vasdolly</item>\n        <item>com.vdopia.client.android.</item>\n        <item>com.vdopia.ads.</item>\n        <item>io.vectaury.</item>\n        <item>com.oblador.vectoricons</item>\n        <item>com.devs.vectorchildfinder</item>\n        <item>androidx.vectordrawable</item>\n        <item>net.veloxity.</item>\n        <item>com.foresee.sdk.ForeSee</item>\n        <item>com.verizon.ads</item>\n        <item>com.verizondigitalmedia.mobile.</item>\n        <item>com.oath.mobile.</item>\n        <item>io.github.g00fy2.versioncompare</item>\n        <item>ernestoyaquello.com.verticalstepperform</item>\n        <item>com.h6ah4i.android.widget.verticalseekbar</item>\n        <item>fr.castorflex.android.verticalviewpager</item>\n        <item>com.vervewireless.advert.</item>\n        <item>com.crazylegend.viewbinding</item>\n        <item>org.taptwo.android.widget</item>\n        <item>by.kirich1409.viewbindingdelegate</item>\n        <item>com.afollestad.viewpagerdots</item>\n        <item>com.zhpan.indicator</item>\n        <item>com.ToxicBakery.viewpager.transforms</item>\n        <item>com.bartoszlipinski.viewpropertyobjectanimator</item>\n        <item>io.github.inflationx.viewpump</item>\n        <item>studio.forface.viewstatestore</item>\n        <item>com.github.florent37.viewtooltip</item>\n        <item>androidx.viewpager</item>\n        <item>com.virgo.ads.</item>\n        <item>io.virtualapp</item>\n        <item>com.lody.virtual</item>\n        <item>com.vivo.push.sdk.</item>\n        <item>com.vodafone.netperform.runtime.</item>\n        <item>com.android.volley</item>\n        <item>org.vosk.android</item>\n        <item>com.vpon.ads</item>\n        <item>com.vpadn.analytics</item>\n        <item>com.vpadn.ads.</item>\n        <item>com.vpadn.widget.</item>\n        <item>com.vungle.publisher.</item>\n        <item>com.vungle.warren.</item>\n        <item>com.tencent.wcdb</item>\n        <item>pl.tajchert.waitingdots</item>\n        <item>com.walkme.wmads</item>\n        <item>com.walkme.wmanalytics</item>\n        <item>com.walkme.wmcrosspromotion</item>\n        <item>abbi.io.abbisdk.</item>\n        <item>org.walletconnect</item>\n        <item>com.wannads.sdk.</item>\n        <item>ru.wapstart.plus1.sdk.</item>\n        <item>me.itangqi.library</item>\n        <item>me.itangqi.waveloadingview</item>\n        <item>com.tencent.map.geolocation</item>\n        <item>com.tencent.mm.plugin.location.</item>\n        <item>com.tencent.mm.plugin.location_soso.</item>\n        <item>com.tencent.mm.plugin.location_google</item>\n        <item>org.web3j</item>\n        <item>com.borismus.webintent</item>\n        <item>io.flutter.plugins.webviewflutter</item>\n        <item>at.pardus.android.webview</item>\n        <item>androidx.webkit</item>\n        <item>org.chromium.support_lib_boundary</item>\n        <item>com.weborama.</item>\n        <item>com.webtrekk.webtrekksdk</item>\n        <item>com.webtrends.mobile.analytics.</item>\n        <item>com.webtrends.mobile.android</item>\n        <item>com.sina.weibo.sdk</item>\n        <item>com.sina.deviceidjnisdk</item>\n        <item>com.stephentuso.welcome</item>\n        <item>uk.co.westhawk.snmp</item>\n        <item>org.bitlet.weupnp</item>\n        <item>com.haroldadmin.whatthestack</item>\n        <item>com.aigestudio.wheelpicker</item>\n        <item>com.lantouzi.wheelview</item>\n        <item>com.widespace.</item>\n        <item>com.squareup.wire</item>\n        <item>com.wireguard.android</item>\n        <item>com.wireguard.config</item>\n        <item>com.wireguard.crypto</item>\n        <item>com.wireguard.util</item>\n        <item>com.wireguard.android.backend</item>\n        <item>com.tech.freak.wizardpager</item>\n        <item>com.wonderpush</item>\n        <item>com.ctc.wstx</item>\n        <item>com.woopra.tracking.</item>\n        <item>com.woopra.tracking</item>\n        <item>com.woorlds.woorldssdk.</item>\n        <item>com.wootric.androidsdk.</item>\n        <item>androidx.work</item>\n        <item>com.squareup.workflow1</item>\n        <item>com.wortise.</item>\n        <item>io.xmode.BcnConfig</item>\n        <item>io.xmode.locationsdk</item>\n        <item>io.mysdk.</item>\n        <item>org.knowm.xchange</item>\n        <item>com.elvishew.xlog</item>\n        <item>org.xmlpull</item>\n        <item>org.apache.xmlbeans</item>\n        <item>schemaorg_apache_xmlbeans</item>\n        <item>org.custommonkey.xmlunit</item>\n        <item>com.adobe.xmp</item>\n        <item>de.Maxr1998.trackselectorlib</item>\n        <item>com.lxj.xpermission</item>\n        <item>com.lxj.xpopup-ext</item>\n        <item>com.lxj.xpopup</item>\n        <item>com.hjq.permissions</item>\n        <item>org.tukaani.xz</item>\n        <item>xamarin</item>\n        <item>com.xamarin.forms</item>\n        <item>com.xamarin.formsviewgroup</item>\n        <item>com.xiaomi.mipush</item>\n        <item>com.xiaomi.push</item>\n        <item>com.xiaomi.mipush.</item>\n        <item>com.ximpleware</item>\n        <item>de.robv.android.xposed</item>\n        <item>com.ycbjie.expandlib</item>\n        <item>com.yoc.visx</item>\n        <item>jp.co.yahoo.android.yssens.YSSensDataShareService</item>\n        <item>jp.co.yahoo.yconnect.sdk.SharedDataService</item>\n        <item>jp.co.yahoo.android.hssens.HSSensDataShareService</item>\n        <item>jp.co.yahoo.yconnect.sso.ShowPromotionViewActivity</item>\n        <item>jp.co.yahoo.android.haas.AgoopReceiver</item>\n        <item>jp.co.yahoo.android.yssens.YSSensActivityLifecycleContentProvider</item>\n        <item>jp.co.yahoo.android.yssens.YSSensBeaconer</item>\n        <item>jp.co.yahoo.android.yssens.YSSensAnalytics</item>\n        <item>com.esotericsoftware.yamlbeans</item>\n        <item>com.yandex.mobile.ads</item>\n        <item>com.yandex.disk.client</item>\n        <item>com.yext.locationsdk.</item>\n        <item>com.yieldlab.</item>\n        <item>com.yinzcam.sobek</item>\n        <item>com.yoadx.yoadx.</item>\n        <item>com.yotadevices.sdk</item>\n        <item>com.youappi.sdk.</item>\n        <item>com.google.api.services.youtubeAnalytics</item>\n        <item>com.google.api.services.youtubereporting</item>\n        <item>com.google.android.youtube.player</item>\n        <item>com.google.api.services.youtube</item>\n        <item>com.yougood.basebusiness.</item>\n        <item>com.yougoodtech.</item>\n        <item>net.youmi</item>\n        <item>com.github.kotvertolet.youtubejextractor</item>\n        <item>com.yume.android</item>\n        <item>com.uc.crashsdk</item>\n        <item>com.uc2.crashsdk</item>\n        <item>net.sourceforge.zbar</item>\n        <item>app.mosn.zdepthshadowlayout</item>\n        <item>com.github.marschall.com.sun.nio.zipfs</item>\n        <item>com.google.zxing</item>\n        <item>com.embarkmobile.zxing</item>\n        <item>com.king.zxing</item>\n        <item>com.redbricklane.zapr</item>\n        <item>cash.z.ecc.android.sdk</item>\n        <item>cash.z.wallet.sdk</item>\n        <item>com.zebra.android</item>\n        <item>com.zebra.sdk</item>\n        <item>zendesk.</item>\n        <item>com.zendrive.sdk.</item>\n        <item>com.zenjoy.ads</item>\n        <item>com.emanuelef.zdtun</item>\n        <item>com.zerotier.sdk</item>\n        <item>org.zeroturnaround.zip</item>\n        <item>net.lingala.zip4j</item>\n        <item>com.zoho.zanalytics.</item>\n        <item>com.otaliastudios.zoom</item>\n        <item>org.nuclearfog.zoomview</item>\n        <item>com.github.luben.zstd</item>\n        <item>net.zucks.</item>\n        <item>ar.com.daidalos.afiledialog</item>\n        <item>org.jraf.android.alibglitch</item>\n        <item>de.timroes.axmlrpc</item>\n        <item>com.drakeet.about</item>\n        <item>com.igaworks.adpopcorn</item>\n        <item>com.igaworks.ssp.</item>\n        <item>com.ew.sdk.adboost</item>\n        <item>com.github.stkent.amplify</item>\n        <item>codes.side.andcolorpicker</item>\n        <item>com.baoyz.widget</item>\n        <item>com.github.curioustechizen.ago</item>\n        <item>com.twofortyfouram.annotation</item>\n        <item>com.twofortyfouram.assertion</item>\n        <item>com.codetroopers.betterpickers</item>\n        <item>sheetrock.panda.changelog</item>\n        <item>com.github.chen0040.androidcodeview</item>\n        <item>com.soundcloud.android.crop</item>\n        <item>im.dlg.dialer</item>\n        <item>com.obsez.android.lib.filechooser</item>\n        <item>group.pals.android.lib.ui.filechooser</item>\n        <item>pl.droidsonroids.gif</item>\n        <item>org.unfoldingword.gogsclient</item>\n        <item>com.lelloman.identicon</item>\n        <item>io.freefair.android.injection</item>\n        <item>com.heinrichreimersoftware.androidissuereporter</item>\n        <item>org.webkit.androidjsc</item>\n        <item>de.mindpipe.android.logging.log4j</item>\n        <item>org.metalev.multitouch</item>\n        <item>com.dd.processbutton</item>\n        <item>info.hoang8f.android.segmented</item>\n        <item>fr.lium</item>\n        <item>com.snatik.storage</item>\n        <item>eu.mhutti1.utils.storage</item>\n        <item>de.viktorreiser.toolbox</item>\n        <item>net.ypresto.androidtranscoder</item>\n        <item>at.markushi.ui</item>\n        <item>io.freefair.android.preference</item>\n        <item>io.freefair.android.util</item>\n        <item>com.pierfrancescosoffritti.androidyoutubeplayer</item>\n        <item>at.huber.youtubeExtractor</item>\n        <item>com.uuzuche.lib_zxing</item>\n        <item>com.weigan.loopview</item>\n        <item>dev.kdrag0n.monet.theme</item>\n        <item>androidx.legacy</item>\n        <item>com.archos.customizedleanback</item>\n        <item>com.archos.mediacenter</item>\n        <item>shaded.org.apache.commons.codec</item>\n        <item>net.dongliu.apk.parser</item>\n        <item>com.android.apksig</item>\n        <item>de.appplant.</item>\n        <item>com.apptv.android.</item>\n        <item>com.appgeneration.ituner.ad</item>\n        <item>com.hierynomus.asn1</item>\n        <item>com.github.florent37.assets_audio_player</item>\n        <item>com.afollestad.async</item>\n        <item>com.github.derlio.waveform</item>\n        <item>com.ryanheise.audioservice</item>\n        <item>com.ryanheise.audio_session</item>\n        <item>design.codeux.autofill_service</item>\n        <item>org.nibor.autolink</item>\n        <item>com.ayetstudios.publishersdk.</item>\n        <item>rekab.app.background_locator</item>\n        <item>me.dm7.barcodescanner</item>\n        <item>barcodescanner.xservices.nl.barcodescanner</item>\n        <item>com.turbomanage.httpclient</item>\n        <item>co.nearbee</item>\n        <item>com.doomonafireball.betterpickers</item>\n        <item>io.horizontalsystems.binancechainkit</item>\n        <item>design.codeux.biometric_storage</item>\n        <item>fr.acinq.bitcoin</item>\n        <item>de.schildbach.wallet</item>\n        <item>org.bitcoin</item>\n        <item>org.bitcoinj</item>\n        <item>biweekly</item>\n        <item>com.github.hbldh.bleak</item>\n        <item>org.brotli</item>\n        <item>btools.routingapp</item>\n        <item>com.btchip</item>\n        <item>com.commit451.bypass</item>\n        <item>org.cache2k</item>\n        <item>io.github.reactivecircus.cache4k</item>\n        <item>me.saket.cascade</item>\n        <item>at.bitfire.cert4android</item>\n        <item>net.sf.cglib</item>\n        <item>com.chrynan.chords</item>\n        <item>me.priyesh.chroma</item>\n        <item>io.circe</item>\n        <item>de.cketti.library.changelog</item>\n        <item>com.rits.cloning</item>\n        <item>com.zhkrb.cloudflare_scrape_android</item>\n        <item>org.commonmark</item>\n        <item>org.shredzone.commons.suncalc</item>\n        <item>me.onebone.toolbar</item>\n        <item>com.example.connectivity</item>\n        <item>com.ourcodeworld.plugins.filebrowser</item>\n        <item>com.cordova.plugin.android.fingerprintauth</item>\n        <item>com.transistorsoft.tsbackgroundfetch</item>\n        <item>com.delagen.cordova.browser</item>\n        <item>io.github.pwlin.cordova.plugins.fileopener2</item>\n        <item>de.niklasmerz.cordova.biometric</item>\n        <item>com.davidbriglio.foreground</item>\n        <item>io.github.xfally.cordova.plugin.ftp</item>\n        <item>com.napolitano.cordova.plugin.intent</item>\n        <item>de.appplant.cordova.plugin.localnotification</item>\n        <item>de.appplant.cordova.plugin.notification</item>\n        <item>com.greybax.spinnerdialog</item>\n        <item>com.viniciusfagundes.cordova.plugin.navigationbar</item>\n        <item>com.doctolib.cordova.overview</item>\n        <item>uk.co.whiteoctober.cordova</item>\n        <item>com.bitpay.cordova.qrscanner</item>\n        <item>net.yoik.cordova.plugins.screenorientation</item>\n        <item>com.materialSnackbar</item>\n        <item>com.knowledgecode.cordova.websocket</item>\n        <item>io.sqlc</item>\n        <item>by.chemerisuk.cordova.support</item>\n        <item>de.westnordost.countryboundaries</item>\n        <item>info.monitorenter.cpdetector</item>\n        <item>com.sdsmdg.harjot.croller</item>\n        <item>com.sdsmdg.harjot.crollerTest</item>\n        <item>nl.qbusict.cupboard</item>\n        <item>org.whispersystems.curve25519</item>\n        <item>com.graphbuilder</item>\n        <item>com.zarinpal.libs.bottomsheet</item>\n        <item>org.cybergarage.http</item>\n        <item>org.cybergarage.net</item>\n        <item>org.cybergarage.soap</item>\n        <item>org.cybergarage.upnp</item>\n        <item>org.cybergarage.util</item>\n        <item>org.cybergarage.xml</item>\n        <item>com.darryncampbell.cordova.plugin</item>\n        <item>at.bitfire.dav4jvm</item>\n        <item>com.deltadna</item>\n        <item>com.deploygate.sdk.</item>\n        <item>io.flutter.plugins.deviceinfo</item>\n        <item>dev.fluttercommunity.plus.device_info</item>\n        <item>com.googlecode.dex2jar</item>\n        <item>com.taobao.android.dexposed</item>\n        <item>org.xbill.DNS</item>\n        <item>org.jitsi.dnssec</item>\n        <item>org.dom4j</item>\n        <item>org.bitbucket.inkytonik.dsprofile</item>\n        <item>io.material.plugins.dynamic_color</item>\n        <item>io.github.silvaren.easyrs</item>\n        <item>fr.acinq.eclair</item>\n        <item>com.sample.edgedetection</item>\n        <item>com.vdurmont.emoji</item>\n        <item>nl.siegmann.epublib</item>\n        <item>de.esys.esysfluttershare</item>\n        <item>net.objecthunter.exp4j</item>\n        <item>expo.modules.application</item>\n        <item>expo.modules.constants</item>\n        <item>expo.modules.errorrecovery</item>\n        <item>expo.modules.filesystem</item>\n        <item>expo.modules.font</item>\n        <item>expo.modules.imageloader</item>\n        <item>expo.modules.keepawake</item>\n        <item>expo.modules.permissions</item>\n        <item>expo.modules.screenorientation</item>\n        <item>expo.modules.splashscreen</item>\n        <item>expo.modules.sqlite</item>\n        <item>expo.modules.webbrowser</item>\n        <item>com.github.yasukotelin.ext_storage</item>\n        <item>ezvcard</item>\n        <item>com.alibaba.fastjson</item>\n        <item>com.fineapptech.fineadscreensdk.</item>\n        <item>com.fineapptech.finechubsdk.</item>\n        <item>com.mfine.sdk.capp.</item>\n        <item>com.fineapptech.finead.</item>\n        <item>com.fineboost.</item>\n        <item>com.vladsch.flexmark</item>\n        <item>net.nfet.flutter.printing</item>\n        <item>co.appbrewery</item>\n        <item>com.kasem.flutter_absolute_path</item>\n        <item>com.sidlatau.flutteremailsender</item>\n        <item>com.arthenica.flutter.ffmpeg</item>\n        <item>com.kineapps.flutter_file_dialog</item>\n        <item>com.dexterous.flutterlocalnotifications</item>\n        <item>com.dataxad.flutter_mailer</item>\n        <item>net.jonhanson.flutter_native_splash</item>\n        <item>com.whelksoft.flutter_native_timezone</item>\n        <item>io.inway.ringtone.player</item>\n        <item>com.it_nomads.fluttersecurestorage</item>\n        <item>io.github.ponnamkarthik.toast.fluttertoast</item>\n        <item>com.flymob.sdk.</item>\n        <item>com.mascotcapsule.micro3d</item>\n        <item>com.frogermcs.activityframemetrics</item>\n        <item>com.frostwire.jlibtorrent</item>\n        <item>it.sauronsoftware.ftp4j</item>\n        <item>com.fullstory.instrumentation.</item>\n        <item>com.fullstory.util.</item>\n        <item>com.fullstory.jni.</item>\n        <item>com.fullstory.FS</item>\n        <item>com.fullstory.rust.</item>\n        <item>com.fullstory.FSSessionData</item>\n        <item>de.mfietz.fyydlin</item>\n        <item>io.grpc</item>\n        <item>io.mola.galimatias</item>\n        <item>com.google.gdata</item>\n        <item>com.crashinvaders.vfx</item>\n        <item>com.aloisdeniel.geocoder</item>\n        <item>com.theapache64.github_android_sdk</item>\n        <item>fr.geonature.maps</item>\n        <item>com.danielcwilson.plugins.analytics</item>\n        <item>name.fraser.neil.plaintext</item>\n        <item>com.google.googlejavaformat</item>\n        <item>me.himanshusoni.gpxparser</item>\n        <item>graphql</item>\n        <item>org.dataloader</item>\n        <item>de.greenrobot.dao</item>\n        <item>org.greenrobot.greendao</item>\n        <item>com.xwray.groupie</item>\n        <item>com.fatboyindustrial.gsonjodatime</item>\n        <item>org.freedesktop.gstreamer</item>\n        <item>com.hcaptcha.sdk</item>\n        <item>org.jvnet.hk2</item>\n        <item>org.opendatakit.httpclientandroidlib</item>\n        <item>ch.boye.httpclientandroidlib</item>\n        <item>jp.co.imobile.sdkads.android.</item>\n        <item>net.fortuna.ical4j</item>\n        <item>net.iharder</item>\n        <item>com.itextpdf</item>\n        <item>com.itextpdf.awt</item>\n        <item>com.itextpdf.text</item>\n        <item>at.bitfire.ical4android</item>\n        <item>com.aloisdeniel.image_native_resizer</item>\n        <item>com.buildware.widget.indeterm</item>\n        <item>org.ini4j</item>\n        <item>com.koushikdutta.ion</item>\n        <item>jp.iridge.popinfo.</item>\n        <item>com.ironsource.</item>\n        <item>org.mindrot.jbcrypt</item>\n        <item>net.pterodactylus.fcp</item>\n        <item>fr.turri.jiso8601</item>\n        <item>org.jpaste</item>\n        <item>org.junit</item>\n        <item>com.github.fge.jackson</item>\n        <item>com.github.jaiimageio</item>\n        <item>com.tozny.crypto.android</item>\n        <item>io.ipfs.api</item>\n        <item>io.ipfs.cid</item>\n        <item>io.ipfs.multiaddr</item>\n        <item>io.ipfs.multibase</item>\n        <item>io.ipfs.multihash</item>\n        <item>org.kiwix.kiwixlib</item>\n        <item>com.eternitywall</item>\n        <item>info.debatty.java.stringsimilarity</item>\n        <item>info.debatty.java.utils</item>\n        <item>com.github.kiulian.downloader</item>\n        <item>jcifsng211</item>\n        <item>jcifsng212</item>\n        <item>jcifsng214</item>\n        <item>jcifsng</item>\n        <item>org.jcodings</item>\n        <item>com.kenai.jffi</item>\n        <item>javax.jmdns</item>\n        <item>com.squareup.jnagmp</item>\n        <item>jnr.enxio</item>\n        <item>jnr.ffi</item>\n        <item>jnr.posix</item>\n        <item>jnr.unixsocket</item>\n        <item>com.kenai.jnr.x86asm</item>\n        <item>net.danlew.android.joda</item>\n        <item>org.joni</item>\n        <item>org.jparsec</item>\n        <item>com.runjva.sourceforge.jsocks</item>\n        <item>com.github.fge.jsonschema</item>\n        <item>com.networknt.schema</item>\n        <item>net.minidev.asm</item>\n        <item>net.minidev.json</item>\n        <item>com.github.jasminb.jsonapi</item>\n        <item>org.jsoup</item>\n        <item>pl.droidsonroids.jspoon</item>\n        <item>net.freehaven.tor.control</item>\n        <item>org.mozilla.universalchardet</item>\n        <item>com.anthonynsimon.url</item>\n        <item>com.ryanheise.just_audio</item>\n        <item>com.beetstra.jutf7</item>\n        <item>im.tox.core</item>\n        <item>im.tox.tox4j</item>\n        <item>com.github.ghetolay.jwamp</item>\n        <item>com.zeoflow.jx</item>\n        <item>de.k3b.geo.io</item>\n        <item>de.k3b.android.geo</item>\n        <item>de.k3b.util</item>\n        <item>de.k3b.geo.api</item>\n        <item>io.karn.khttp</item>\n        <item>org.kobjects</item>\n        <item>com.github.kr328.kaidl</item>\n        <item>org.abstractj.kalium</item>\n        <item>com.charleskorn.kaml</item>\n        <item>com.joemelsha.crypto.hash</item>\n        <item>com.github.aelstad.keccakj</item>\n        <item>khttp</item>\n        <item>com.kiddoware.kidsplace.sdk</item>\n        <item>org.kivy.android</item>\n        <item>com.github.doyaaaaaken.kotlincsv</item>\n        <item>kotlinx.parcelize</item>\n        <item>com.github.michaelbull.result</item>\n        <item>kotlinx.datetime.serializers</item>\n        <item>kotlinx.coroutines</item>\n        <item>com.omarea.krscript</item>\n        <item>de.javakaffee.kryoserializers</item>\n        <item>org.ksoap2</item>\n        <item>com.optimaize.langdetect</item>\n        <item>com.antoniotari.android.lastfm</item>\n        <item>com.iyaffle.launchreview</item>\n        <item>com.badlogic.gdx</item>\n        <item>eu.chainfire.librootjava</item>\n        <item>org.adblockplus.libadblockplus</item>\n        <item>com.github.mjdev.libaums</item>\n        <item>org.whispersystems.libaxolotl</item>\n        <item>org.libdohj</item>\n        <item>com.google.i18n.phonenumbers</item>\n        <item>io.michaelrocks.libphonenumber.android</item>\n        <item>xyz.gianlu.librespot</item>\n        <item>me.zhanghai.android.libselinux</item>\n        <item>org.libsodium.jni</item>\n        <item>com.googleresearch.capturesync</item>\n        <item>com.topjohnwu.superuser</item>\n        <item>eu.chainfire.libsuperuser</item>\n        <item>com.blockstream.libwally</item>\n        <item>org.whispersystems.libwebrtc_android</item>\n        <item>io.flutter.plugins.localauth</item>\n        <item>com.github.tony19.logback.android</item>\n        <item>org.love2d.android</item>\n        <item>net.bjoernpetersen.m3u</item>\n        <item>sun.bob.mcalendarview</item>\n        <item>com.mparticle</item>\n        <item>com.mtraction.mtractioninapptracker</item>\n        <item>com.mtraction.mtractioninapptracker.</item>\n        <item>jp.maio.sdk.</item>\n        <item>com.mapswithme.maps</item>\n        <item>com.danielstone.materialaboutlibrary</item>\n        <item>com.heinrichreimersoftware.materialintro</item>\n        <item>com.shahroz.svlibrary</item>\n        <item>com.mediba.jp</item>\n        <item>mediba.ad.sdk.android.openx</item>\n        <item>com.drew</item>\n        <item>org.microg.gms</item>\n        <item>com.eclipsesource.json</item>\n        <item>lbms.plugins.mldht</item>\n        <item>com.chenlb.mmseg4j</item>\n        <item>info.javaperformance.money</item>\n        <item>com.mongodb</item>\n        <item>com.un4seen.bass</item>\n        <item>me.polynom.moxplatform_android</item>\n        <item>com.mpatric.mp3agic</item>\n        <item>com.googlecode.mp4parser</item>\n        <item>com.coremedia.iso</item>\n        <item>com.github.fge.msgsimple</item>\n        <item>lanchon.multidexlib2</item>\n        <item>net.opacapp.multilinecollapsingtoolbar</item>\n        <item>com.my.target.</item>\n        <item>com.my.tracker.</item>\n        <item>com.emanuelef.ndpi</item>\n        <item>com.google.code.regexp</item>\n        <item>com.grack.nanojson</item>\n        <item>org.nativescript.nativescript_foss_sidedrawer</item>\n        <item>org.nativescript.nativescript_imagecropper</item>\n        <item>org.nativescript.nativescript_mediafilepicker</item>\n        <item>org.nativescript.nativescript_plugin_filepicker</item>\n        <item>org.nativescript.nativescript_unit_test_runner</item>\n        <item>net.nend.android</item>\n        <item>net.nend.unity.</item>\n        <item>org.netlib</item>\n        <item>com.netmera.</item>\n        <item>com.craxiom.messaging</item>\n        <item>com.novoda.notils</item>\n        <item>com.neovisionaries.i18n</item>\n        <item>com.neovisionaries.ws.client</item>\n        <item>com.burgstaller.okhttp</item>\n        <item>se.akerfeldt.okhttp.signpost</item>\n        <item>net.gsantner.opoc</item>\n        <item>com.onionnetworks.io</item>\n        <item>com.onionnetworks.net</item>\n        <item>com.onionnetworks.util</item>\n        <item>com.onionnetworks.fec</item>\n        <item>com.crazecoder.openfile</item>\n        <item>cz.matejcik.openwig</item>\n        <item>org.w3c.dom</item>\n        <item>com.j256.ormlite</item>\n        <item>de.westnordost.osmapi</item>\n        <item>de.westnordost.osmfeatures</item>\n        <item>net.java.otr4j</item>\n        <item>me.everything.android.ui.overscroll</item>\n        <item>com.owncloud.android.lib</item>\n        <item>com.pcloud.sdk</item>\n        <item>dev.fluttercommunity.plus.packageinfo</item>\n        <item>io.flutter.plugins.pathprovider</item>\n        <item>com.amudanan.path_provider_ex</item>\n        <item>com.github.jberkel.pay.me</item>\n        <item>com.viliussutkus89.android.pdf2htmlex</item>\n        <item>com.shockwave.pdfium</item>\n        <item>com.adobe.phonegap.push</item>\n        <item>jp.pinable.ssbp.</item>\n        <item>com.hp.hpl.sparta.xpath</item>\n        <item>net.sourceforge.pinyin4j</item>\n        <item>com.github.yeriomin.playstoreapi</item>\n        <item>com.squareup.pollexor</item>\n        <item>com.github.amsacode.predict4java</item>\n        <item>org.ocpsoft.prettytime</item>\n        <item>com.github.lightningnetwork.lnd.lnrpc</item>\n        <item>com.pyamsoft.pydroid</item>\n        <item>org.jnius</item>\n        <item>org.renpy.android</item>\n        <item>com.github.liuyueyi.quick.transfer</item>\n        <item>io.flutter.plugins.quickactions</item>\n        <item>com.callstack.repack</item>\n        <item>com.github.jonnybgod.RNEventSource</item>\n        <item>com.reactnativeactionsshortcuts</item>\n        <item>com.asterinet.react.bgactions</item>\n        <item>com.transistorsoft.rnbackgroundfetch</item>\n        <item>com.pilloxa.backgroundjob</item>\n        <item>com.jamesisaac.rnbackgroundtask</item>\n        <item>com.ekreutz.barcodescanner</item>\n        <item>com.zoontek.rnbars</item>\n        <item>com.solinor.bluetoothstatus</item>\n        <item>com.zoontek.rnbootsplash</item>\n        <item>com.gnet.bottomsheet</item>\n        <item>com.lugg.ReactNativeConfig</item>\n        <item>com.psykar.cookiemanager</item>\n        <item>com.kevinresol.react_native_default_preference</item>\n        <item>com.learnium.RNDeviceInfo</item>\n        <item>com.reactnativedocumentpicker</item>\n        <item>cl.hasaezs.rndominantcolor</item>\n        <item>com.masteratul.exceptionhandler</item>\n        <item>com.github.wumke.RNExitApp</item>\n        <item>com.smixx.fabric.</item>\n        <item>com.evollu.react.fcm</item>\n        <item>com.RNFetchBlob</item>\n        <item>com.alpha0010.fs</item>\n        <item>com.vinzscam.reactnativefileviewer</item>\n        <item>com.kristiansorens.flagsecure</item>\n        <item>com.rnfs</item>\n        <item>com.reactlibrary</item>\n        <item>com.onibenjo.htmltopdf</item>\n        <item>com.AlexanderZaytsev.RNI18n</item>\n        <item>com.dooboolab.RNIap</item>\n        <item>fr.snapp.imagebase64</item>\n        <item>com.reactnative.ivpusic.imagepicker</item>\n        <item>com.rnimmersive</item>\n        <item>com.corbt.keepawake</item>\n        <item>com.oblador.keychain</item>\n        <item>com.BV.LinearGradient</item>\n        <item>io.tradle.react</item>\n        <item>com.reactcommunity.rnlocalize</item>\n        <item>com.chirag.RNMail</item>\n        <item>com.ammarahmed.mmkv</item>\n        <item>com.tanguyantoine.react</item>\n        <item>community.revteltech.nfc</item>\n        <item>com.brentvatne.react</item>\n        <item>com.reactnative.photoview</item>\n        <item>com.github.godness84.RNRecyclerViewList</item>\n        <item>com.RNRSA</item>\n        <item>com.th3rdwave.safeareacontext</item>\n        <item>com.ammarahmed.scopedstorage</item>\n        <item>com.swmansion.rnscreens</item>\n        <item>net.rhogan.rnrandombytes</item>\n        <item>net.rhogan.rnsecurerandom</item>\n        <item>com.astrocoders.selectabletext</item>\n        <item>cl.json.social</item>\n        <item>com.reactnativecomponent.splashscreen</item>\n        <item>org.libsodium.rn</item>\n        <item>com.zmxv.RNSound</item>\n        <item>com.johnsonsu.rnsoundplayer</item>\n        <item>com.react.rnspinkit</item>\n        <item>org.devio.rn.splashscreen</item>\n        <item>com.horcrux.svg</item>\n        <item>com.nikolaiwarner.RNTextInputReset</item>\n        <item>org.unimodules</item>\n        <item>com.apsl.versionnumber</item>\n        <item>com.brentvatne.exoplayer</item>\n        <item>com.brentvatne.receiver</item>\n        <item>com.oney.WebRTCModule</item>\n        <item>com.inprogress.reactnativeyoutube</item>\n        <item>org.renjin</item>\n        <item>io.requery</item>\n        <item>com.ensoft.restafari</item>\n        <item>retrofit</item>\n        <item>org.dmfs.rfc5545</item>\n        <item>com.pedro.encoder</item>\n        <item>com.pedro.rtmp</item>\n        <item>com.pedro.rtsp</item>\n        <item>com.pedro.rtpstreamer</item>\n        <item>com.pedro.rtplibrary</item>\n        <item>co.rh.id.lib.rx3_utils</item>\n        <item>nl.littlerobots.rxlint</item>\n        <item>in.sunilpaulmathew.sCommon</item>\n        <item>cl.jesualex.stooltip</item>\n        <item>net.sanukin</item>\n        <item>com.thegrizzlylabs.sardineandroid</item>\n        <item>com.trueaccord.scalapb</item>\n        <item>com.typesafe.scalalogging</item>\n        <item>scodec.bits</item>\n        <item>scorex.util</item>\n        <item>com.transferwise.sequencelayout</item>\n        <item>com.theromus.sha</item>\n        <item>com.theromus.utils</item>\n        <item>shapeless</item>\n        <item>dev.fluttercommunity.plus.share</item>\n        <item>io.flutter.plugins.sharedpreferences</item>\n        <item>org.asamk.signal</item>\n        <item>org.whispersystems.signalservice</item>\n        <item>com.novoda.simplechromecustomtabs</item>\n        <item>com.github.IrineSistiana.shadowsocks.plugin.simple_tls</item>\n        <item>org.sonatype.plexus.build.incremental</item>\n        <item>uk.uuid.slf4j.android</item>\n        <item>de.psdev.slf4j.android.logger</item>\n        <item>com.arcao.slf4j.timber</item>\n        <item>org.jf.baksmali</item>\n        <item>org.jf.dexlib2</item>\n        <item>org.jf.smali</item>\n        <item>org.jf.util</item>\n        <item>org.xerial.snappy</item>\n        <item>org.vinuxproject.sonic</item>\n        <item>io.github.rosemoe.sora</item>\n        <item>fr.cryptohash</item>\n        <item>com.tekartik.sqflite</item>\n        <item>eu.simonbinder.sqlite3_native_library</item>\n        <item>eu.simonbinder.sqlite3_flutter_libs</item>\n        <item>com.hierynomus.sshj</item>\n        <item>com.soneso.stellarmnemonics</item>\n        <item>com.timehop.stickyheadersrecyclerview</item>\n        <item>org.stockchart</item>\n        <item>org.hampelratte.svdrp</item>\n        <item>com.caverock.androidsvg</item>\n        <item>com.github.pwittchen.swipe</item>\n        <item>com.github.pwittchen.swipedetector</item>\n        <item>com.hudomju.swipe</item>\n        <item>com.tans.tadapter</item>\n        <item>com.tabtale</item>\n        <item>de.aaschmid.taskwarrior</item>\n        <item>org.mozilla.telemetry</item>\n        <item>com.uwetrottmann.thetvdb</item>\n        <item>com.squareup.timessquare</item>\n        <item>org.tinylog</item>\n        <item>com.uwetrottmann.tmdb2</item>\n        <item>com.moandjiezana.toml</item>\n        <item>com.reactnativecommunity.toolbarandroid</item>\n        <item>io.github.muntashirakon.toybox</item>\n        <item>org.ligi.tracedroid</item>\n        <item>com.uwetrottmann.trakt5</item>\n        <item>pl.polidea.treeview</item>\n        <item>com.twitter.twittertext</item>\n        <item>com.yalantis.ucrop</item>\n        <item>org.unbescape</item>\n        <item>com.github.underscore</item>\n        <item>net.sbbi.upnp</item>\n        <item>com.github.fge.uritemplate</item>\n        <item>io.flutter.plugins.urllauncher</item>\n        <item>com.hoho.android.usbserial</item>\n        <item>vavi.sound</item>\n        <item>vavi.util</item>\n        <item>at.bitfire.vcard4android</item>\n        <item>com.wnafee.vector.compat</item>\n        <item>io.flutter.plugins.videoplayer</item>\n        <item>com.github.mangstadt.vinnie</item>\n        <item>com.butterproject.libvlc</item>\n        <item>com.trustwallet.walletconnect</item>\n        <item>com.wisecrab.wc_flutter_share</item>\n        <item>org.webrtc</item>\n        <item>com.db.chart</item>\n        <item>com.db.williamchart</item>\n        <item>com.viliussutkus89.android.wvware</item>\n        <item>io.horizontalsystems.xrateskit</item>\n        <item>yuku.afw</item>\n        <item>yuku.bintex</item>\n        <item>yuku.devoxx</item>\n        <item>yuku.filechooser</item>\n        <item>yuku.snappy</item>\n        <item>cn.bertsir.zbar</item>\n        <item>com.dimagi.android.zebraprinttool</item>\n        <item>kellinwood.logging</item>\n        <item>com.nulabinc.zxcvbn</item>\n        <item>arrow.core</item>\n        <item>arrow.typeclasses</item>\n    </array>\n    <array name=\"lib_names\">\n        <item>360Dialog</item>\n        <item>39Geopla</item>\n        <item>3bitter Beacon</item>\n        <item>4th Line Seamless Libraries</item>\n        <item>7-Zip-JBinding</item>\n        <item>7Moor SDK</item>\n        <item>7Moor SDK</item>\n        <item>920 Text Editor</item>\n        <item>920 Text Editor</item>\n        <item>920 Text Editor</item>\n        <item>\\@react-native-community/checkbox</item>\n        <item>\\@react-native-community/clipboard</item>\n        <item>\\@react-native-community/geolocation</item>\n        <item>\\@react-native-community/netinfo</item>\n        <item>\\@react-native-community/slider</item>\n        <item>ABTasty</item>\n        <item>ACRA</item>\n        <item>ACRA</item>\n        <item>ACRCloud</item>\n        <item>AChartEngine</item>\n        <item>AD(X)</item>\n        <item>AD(X)</item>\n        <item>ADLIB</item>\n        <item>ADOP</item>\n        <item>ADman Media</item>\n        <item>AES-GCM-Provider</item>\n        <item>AESCrypt-Android</item>\n        <item>AHBottomNavigation</item>\n        <item>AIDLBridge</item>\n        <item>AIHelp</item>\n        <item>AIHelp</item>\n        <item>AMoAd</item>\n        <item>ANR-WatchDog</item>\n        <item>ANT and ANT+ Android SDK</item>\n        <item>ANTLR</item>\n        <item>ANTLR</item>\n        <item>AOP Alliance</item>\n        <item>API Common for Java</item>\n        <item>APICloud</item>\n        <item>APNG4Android</item>\n        <item>ARouter</item>\n        <item>ASM</item>\n        <item>ASP.NET SignalR</item>\n        <item>ATInternet</item>\n        <item>AVLoadingIndicatorView</item>\n        <item>AWS Analytics</item>\n        <item>AWS Kinesis</item>\n        <item>AWS Kinesis</item>\n        <item>AWS SDK for Java</item>\n        <item>Aarki</item>\n        <item>AboutIt</item>\n        <item>AboutLibraries</item>\n        <item>AbsFrame</item>\n        <item>Absinthe Libraries</item>\n        <item>AbstractTask</item>\n        <item>AccelForceEaster</item>\n        <item>Accompanist</item>\n        <item>AccountKit</item>\n        <item>Acrarium</item>\n        <item>ActionBarExtras</item>\n        <item>ActionBarSherlock</item>\n        <item>ActiveAndroid</item>\n        <item>ActivityFrameMetrics</item>\n        <item>ActivityResultLauncher</item>\n        <item>Actual Number Picker</item>\n        <item>Actv8me</item>\n        <item>Acuant</item>\n        <item>Ad Generation</item>\n        <item>Ad2</item>\n        <item>Ad4Game</item>\n        <item>Ad4Screen</item>\n        <item>AdAdapted</item>\n        <item>AdBuddiz</item>\n        <item>AdColony</item>\n        <item>AdColony</item>\n        <item>AdFalcon</item>\n        <item>AdFit (Daum)</item>\n        <item>AdFlex</item>\n        <item>AdForm</item>\n        <item>AdGateMedia</item>\n        <item>AdGem</item>\n        <item>AdLocus</item>\n        <item>AdMarvel</item>\n        <item>AdMob Plugin Pro</item>\n        <item>AdMob Plugin Pro</item>\n        <item>AdMuing</item>\n        <item>AdTech</item>\n        <item>AdTheorent</item>\n        <item>AdTiming</item>\n        <item>AdTiming</item>\n        <item>AdTrial</item>\n        <item>AdView</item>\n        <item>AdWhirl (AdMob)</item>\n        <item>AdapterDelegates</item>\n        <item>Adaptive Cards</item>\n        <item>AdaptiveIconView</item>\n        <item>AdaptiveRecyclerView</item>\n        <item>Adbrix</item>\n        <item>Adcash</item>\n        <item>Adcenix</item>\n        <item>Adchina</item>\n        <item>Add Apt Tr</item>\n        <item>Adflake</item>\n        <item>Adfurikun</item>\n        <item>Adfurikun</item>\n        <item>Adhan Java</item>\n        <item>Adincube</item>\n        <item>Adjoe</item>\n        <item>Adjoe</item>\n        <item>Adjust</item>\n        <item>Adjust</item>\n        <item>Adjust Android SDK</item>\n        <item>Adjust Unbotify</item>\n        <item>Admitad</item>\n        <item>Admixer</item>\n        <item>Admixer</item>\n        <item>Admost</item>\n        <item>Admost</item>\n        <item>Adobe Experience Cloud</item>\n        <item>Adot</item>\n        <item>AdsWizz</item>\n        <item>Adscend Media</item>\n        <item>Adscend Media</item>\n        <item>Advanced RecyclerView</item>\n        <item>AdvancedWebView</item>\n        <item>Advangelists</item>\n        <item>Adyen Components for Android</item>\n        <item>AerServ</item>\n        <item>Aesthetic</item>\n        <item>AgentWeb</item>\n        <item>Agoop</item>\n        <item>Agora Analytics</item>\n        <item>Agora Analytics</item>\n        <item>Aho-Corasick</item>\n        <item>Ai.type *Malverting related</item>\n        <item>Ai.type *Malverting related</item>\n        <item>Ai.type *Malverting related</item>\n        <item>Ai.type *Malverting related</item>\n        <item>Airbridge</item>\n        <item>Airpush</item>\n        <item>Akamai MAP</item>\n        <item>Alerter</item>\n        <item>Algolia Search API Client for Java</item>\n        <item>Algorix</item>\n        <item>Algorix</item>\n        <item>Algorix</item>\n        <item>Alibaba Cloud Messaging</item>\n        <item>Alibaba HTTPDNS</item>\n        <item>Alibaba UserTrack Device IDentity (UTDID)</item>\n        <item>Alibaba analytics</item>\n        <item>Alibaba analytics</item>\n        <item>Alibaba analytics</item>\n        <item>Alibaba analytics</item>\n        <item>Alibaba analytics</item>\n        <item>Alibaba analytics</item>\n        <item>Alibaba analytics</item>\n        <item>Alibaba analytics</item>\n        <item>Alimama (formerly AdsMogo)</item>\n        <item>Alimama (formerly AdsMogo)</item>\n        <item>Alipay SDK</item>\n        <item>Alipay ZeroSdk</item>\n        <item>Alohalytics</item>\n        <item>Alooma</item>\n        <item>AlphabetIndex Fast Scroll RecyclerView</item>\n        <item>Alphonso</item>\n        <item>AltBeacon</item>\n        <item>AltBeacon</item>\n        <item>AltBeacon</item>\n        <item>Altamob</item>\n        <item>Amap</item>\n        <item>Amazon AWS</item>\n        <item>Amazon AWS</item>\n        <item>Amazon AWS</item>\n        <item>Amazon AWS</item>\n        <item>Amazon AWS</item>\n        <item>Amazon AWS Auth</item>\n        <item>Amazon Advertisement</item>\n        <item>Amazon Analytics</item>\n        <item>Amazon Analytics (Amazon insights)</item>\n        <item>Amazon Analytics (Amazon insights)</item>\n        <item>Amazon Analytics (Amazon insights)</item>\n        <item>Amazon In-App Purchasing</item>\n        <item>Amazon Mobile Analytics (Amplify)</item>\n        <item>Amazon Mobile Associates</item>\n        <item>Amber Weather Ad SDK</item>\n        <item>AmbilWarna Color Picker library</item>\n        <item>Amobee</item>\n        <item>Amplitude Android SDK</item>\n        <item>Anagog</item>\n        <item>Analytics by NPAW (Youbora Suite)</item>\n        <item>Ananas Photo Editor</item>\n        <item>AndPermissions</item>\n        <item>AndServer</item>\n        <item>Android 3D Touch - PeekView</item>\n        <item>Android About Page</item>\n        <item>Android Activity Saved State</item>\n        <item>Android AppMsg (Crouton) Library</item>\n        <item>Android Article Viewer</item>\n        <item>Android Asynchronous Http Client</item>\n        <item>Android AtLeap accelerator</item>\n        <item>Android BLE Library</item>\n        <item>Android Beacon Library</item>\n        <item>Android Browser Helper</item>\n        <item>Android Circular Image View</item>\n        <item>Android Circular Progress Button</item>\n        <item>Android Color Picker</item>\n        <item>Android CommitContentSampleIME Sample</item>\n        <item>Android Commons</item>\n        <item>Android CustomTabs</item>\n        <item>Android Dark Mode Support</item>\n        <item>Android DbInspector</item>\n        <item>Android Debug Drawer</item>\n        <item>Android Design Support Library</item>\n        <item>Android Device Names</item>\n        <item>Android Device Names v2</item>\n        <item>Android Device Names v2</item>\n        <item>Android DirectoryChooser</item>\n        <item>Android Donations Lib</item>\n        <item>Android Easing Functions</item>\n        <item>Android EditText</item>\n        <item>Android Emoji2 Compat</item>\n        <item>Android FillableLoaders</item>\n        <item>Android Five Stars Library</item>\n        <item>Android GPX Parser</item>\n        <item>Android GeoJSON</item>\n        <item>Android Gesture Detectors Framework</item>\n        <item>Android Holo ColorPicker</item>\n        <item>Android Image Cropper</item>\n        <item>Android Image Slider</item>\n        <item>Android In-App Billing v3 Library</item>\n        <item>Android Indefinite Pager Indicator</item>\n        <item>Android Instant Run</item>\n        <item>Android Internal APIs</item>\n        <item>Android Jetpack Annotations</item>\n        <item>Android Jetpack VersionedParcelable</item>\n        <item>Android Launcher</item>\n        <item>Android Launcher</item>\n        <item>Android Lifecycle WorkManager Hilt Extension</item>\n        <item>Android MIDI Library</item>\n        <item>Android Market</item>\n        <item>Android Market API</item>\n        <item>Android Material Color Picker Dialog</item>\n        <item>Android Material Intro Screen</item>\n        <item>Android Material Stepper</item>\n        <item>Android Multi Dex Library</item>\n        <item>Android Native Code View</item>\n        <item>Android Native Code View</item>\n        <item>Android Network Tools</item>\n        <item>Android NumberPicker</item>\n        <item>Android NumberProgressBar</item>\n        <item>Android OAuth Client Library</item>\n        <item>Android Object Preference Loader</item>\n        <item>Android Onboarder</item>\n        <item>Android PackageManager</item>\n        <item>Android PagerSlidingTabStrip</item>\n        <item>Android PdfViewer</item>\n        <item>Android Persistent Search Library</item>\n        <item>Android Persistent Search Library</item>\n        <item>Android Pinning</item>\n        <item>Android Priority Job Queue</item>\n        <item>Android Priority Job Queue (Job Manager)</item>\n        <item>Android Proxy project</item>\n        <item>Android QuickAction</item>\n        <item>Android RPC Provider</item>\n        <item>Android Random Color</item>\n        <item>Android Recurrence Picker Library</item>\n        <item>Android Root Shell Framework</item>\n        <item>Android Root Shell Framework</item>\n        <item>Android Runtime for NativeScript</item>\n        <item>Android Runtime for NativeScript</item>\n        <item>Android Runtime for NativeScript</item>\n        <item>Android SMS/MMS Sending Library</item>\n        <item>Android SQLite support library</item>\n        <item>Android SQLiteAssetHelper</item>\n        <item>Android SQLiteAssetHelper</item>\n        <item>Android Shell</item>\n        <item>Android Signature Pad</item>\n        <item>Android Simple Tooltip</item>\n        <item>Android SimpleVideoView</item>\n        <item>Android Sliding Activity Library</item>\n        <item>Android Sliding Up Panel</item>\n        <item>Android Smart Image View</item>\n        <item>Android StyleableToast</item>\n        <item>Android Support Library Custom View</item>\n        <item>Android Support Library collections</item>\n        <item>Android Support TV Provider</item>\n        <item>Android Support v13</item>\n        <item>Android Support v4</item>\n        <item>Android Support v7</item>\n        <item>Android Swipe Layout</item>\n        <item>Android SwipeableRecyclerView</item>\n        <item>Android Switch Preference Backport</item>\n        <item>Android System Bar Tint</item>\n        <item>Android Text-Justify</item>\n        <item>Android TextView-LinkBuilder</item>\n        <item>Android Tooltip</item>\n        <item>Android USB MIDI Driver</item>\n        <item>Android Unsplash (Unofficial)</item>\n        <item>Android Upload Service</item>\n        <item>Android View Animations</item>\n        <item>Android ViewPagerIndicator</item>\n        <item>Android Vision</item>\n        <item>Android VuMeter library</item>\n        <item>Android Weak Handler</item>\n        <item>Android Wear APIs</item>\n        <item>Android Week View</item>\n        <item>Android WizardPager</item>\n        <item>Android biometric</item>\n        <item>Android dualcache</item>\n        <item>Android dualcache</item>\n        <item>Android flow layout</item>\n        <item>Android mDNSResponder</item>\n        <item>Android mDNSResponder</item>\n        <item>Android mDNSResponder</item>\n        <item>Android sqlite connector</item>\n        <item>Android-ActionItemBadge</item>\n        <item>Android-BitmapCache</item>\n        <item>Android-Bootstrap</item>\n        <item>Android-Easing</item>\n        <item>Android-Exif-Extended</item>\n        <item>Android-ExpandIcon</item>\n        <item>Android-FadingEdgeLayout</item>\n        <item>Android-FileLogger</item>\n        <item>Android-FilePicker</item>\n        <item>Android-Iconics</item>\n        <item>Android-Iconics</item>\n        <item>Android-Iconics</item>\n        <item>Android-Iconics</item>\n        <item>Android-Iconics</item>\n        <item>Android-Job</item>\n        <item>Android-Logger</item>\n        <item>Android-MaterialPreference</item>\n        <item>Android-Model-View-Presenter-MVP</item>\n        <item>Android-ObservableScrollView</item>\n        <item>Android-PickerView</item>\n        <item>Android-ProgressFragment</item>\n        <item>Android-Rate</item>\n        <item>Android-RateThisApp</item>\n        <item>Android-RoundCornerProgressBar</item>\n        <item>Android-ScalableVideoView</item>\n        <item>Android-Snowfall</item>\n        <item>Android-SpinKit</item>\n        <item>Android-State</item>\n        <item>Android-Support-Preference-V7-Fix</item>\n        <item>Android-TiffBitmapFactory</item>\n        <item>Android-Toggle-Switch</item>\n        <item>Android-UndoBar</item>\n        <item>Android-WVersionManager</item>\n        <item>Android-wheel</item>\n        <item>AndroidAnnotations API</item>\n        <item>AndroidAnnotations API</item>\n        <item>AndroidAsync</item>\n        <item>AndroidAutoSize</item>\n        <item>AndroidBanner</item>\n        <item>AndroidBaseUtils</item>\n        <item>AndroidClearChroma</item>\n        <item>AndroidColorX</item>\n        <item>AndroidCommon</item>\n        <item>AndroidDonate</item>\n        <item>AndroidEqualizer</item>\n        <item>AndroidFastScroll</item>\n        <item>AndroidHiddenApiBypass</item>\n        <item>AndroidIDE</item>\n        <item>AndroidKTX</item>\n        <item>AndroidLame</item>\n        <item>AndroidMagic</item>\n        <item>AndroidPhotoFilters</item>\n        <item>AndroidPhotoshopColorPicker</item>\n        <item>AndroidProcesses</item>\n        <item>AndroidQuery</item>\n        <item>AndroidStaggeredGrid</item>\n        <item>AndroidSvgLoader</item>\n        <item>AndroidTreeView</item>\n        <item>AndroidUtil</item>\n        <item>AndroidUtilCode</item>\n        <item>AndroidUtils</item>\n        <item>AndroidVeil</item>\n        <item>AndroidVideoCache</item>\n        <item>AndroidX Activity</item>\n        <item>AndroidX Car App</item>\n        <item>AndroidX Cursor Adapter</item>\n        <item>AndroidX Emoji</item>\n        <item>AndroidX Fragment</item>\n        <item>AndroidX GridLayout</item>\n        <item>AndroidX Inspection</item>\n        <item>AndroidX Local Broadcast Manager</item>\n        <item>AndroidX Percentlayout</item>\n        <item>AndroidX Preference eXtended</item>\n        <item>AndroidX Security</item>\n        <item>AndroidX Test</item>\n        <item>AndroidX Wear</item>\n        <item>AndroidX Widget ViewPager2</item>\n        <item>Androidplot</item>\n        <item>Androidx Core</item>\n        <item>Anet channel library</item>\n        <item>AnimSideBar</item>\n        <item>AnimatedProgressBar</item>\n        <item>AnimatedSvgView</item>\n        <item>AnimatedSvgView</item>\n        <item>Anko</item>\n        <item>Anvato (A Google Company)</item>\n        <item>AnyMaps</item>\n        <item>AnySDK</item>\n        <item>AnySDK</item>\n        <item>Anzu</item>\n        <item>Apache Ant™</item>\n        <item>Apache Commons</item>\n        <item>Apache Cordova</item>\n        <item>Apache Felix</item>\n        <item>Apache FreeMarker</item>\n        <item>Apache FtpServer</item>\n        <item>Apache Harmony</item>\n        <item>Apache Http</item>\n        <item>Apache HttpComponents</item>\n        <item>Apache Jackrabbit</item>\n        <item>Apache James Mail Enterprise Server</item>\n        <item>Apache Log4j</item>\n        <item>Apache Lucene</item>\n        <item>Apache MINA</item>\n        <item>Apache Maven SCM</item>\n        <item>Apache Oltu</item>\n        <item>Apache OpenJPA</item>\n        <item>Apache POI</item>\n        <item>Apache Pig</item>\n        <item>Apache Velocity</item>\n        <item>Apache XML</item>\n        <item>Apache Xerces</item>\n        <item>Apache Xerces</item>\n        <item>Apache Xerces</item>\n        <item>Apache Xerces</item>\n        <item>Apfloat</item>\n        <item>Apktool</item>\n        <item>Apktool</item>\n        <item>Apktool</item>\n        <item>Apktool</item>\n        <item>Apktool</item>\n        <item>Apng2Gif</item>\n        <item>ApngDrawable</item>\n        <item>Apollo GraphQL Client for Android</item>\n        <item>Apollo Kotlin</item>\n        <item>App Center Push</item>\n        <item>App Samurai</item>\n        <item>App Theme Engine</item>\n        <item>App Theme Helper</item>\n        <item>AppAnalytics</item>\n        <item>AppAuth for Android</item>\n        <item>AppBrain</item>\n        <item>AppCompat</item>\n        <item>AppConsent CMP</item>\n        <item>AppIconLoader</item>\n        <item>AppInfoBadge</item>\n        <item>AppIntro</item>\n        <item>AppKillerManager</item>\n        <item>AppKit</item>\n        <item>AppLink.io</item>\n        <item>AppLink.io</item>\n        <item>AppLovin</item>\n        <item>AppMetrica</item>\n        <item>AppMonet</item>\n        <item>AppNexus</item>\n        <item>AppRate</item>\n        <item>AppRight (by Gryphonet)</item>\n        <item>AppSee</item>\n        <item>AppUpdater</item>\n        <item>AppVador</item>\n        <item>AppZilo</item>\n        <item>Appcelerator</item>\n        <item>Appcelerator Analytics</item>\n        <item>Appcelerator Analytics</item>\n        <item>Appdynamics</item>\n        <item>Appenda</item>\n        <item>Apperhand</item>\n        <item>Appirits</item>\n        <item>Applause</item>\n        <item>Application preferences plugin for Cordova 3+</item>\n        <item>Applift</item>\n        <item>Appnext</item>\n        <item>Appodeal</item>\n        <item>Appodeal</item>\n        <item>Appodeal Stack</item>\n        <item>AppsFlyer</item>\n        <item>AppsGeyser</item>\n        <item>AppsGeyser</item>\n        <item>Apptentive</item>\n        <item>Apptimize</item>\n        <item>Appvisor push</item>\n        <item>Apsalar</item>\n        <item>Apteligent by VMWare (formerly Crittercism)</item>\n        <item>Arch</item>\n        <item>Arched Image Progress Bar</item>\n        <item>Areametrics</item>\n        <item>Areametrics</item>\n        <item>Argparse4j</item>\n        <item>Arrow</item>\n        <item>Askingpoint</item>\n        <item>Ason</item>\n        <item>Aspect Ratio ImageView</item>\n        <item>AspectJ</item>\n        <item>Assent</item>\n        <item>Astian Libs</item>\n        <item>Async Http Client</item>\n        <item>AsyncAwait</item>\n        <item>AsyncJobLibrary</item>\n        <item>Asynclayoutinflater</item>\n        <item>Atelier</item>\n        <item>AtomicFU</item>\n        <item>Attribouter</item>\n        <item>AttributionPresenter</item>\n        <item>Audience Studio (Krux)</item>\n        <item>Audio Visualizer</item>\n        <item>Audio Waves</item>\n        <item>Audio Widget Overlay View</item>\n        <item>Audio Wife</item>\n        <item>AudioFocusController</item>\n        <item>AudioPlayers</item>\n        <item>AudioRecordView</item>\n        <item>Audiogram</item>\n        <item>Audiostream</item>\n        <item>Auditude</item>\n        <item>Auto</item>\n        <item>Auto.js</item>\n        <item>AutoDispose</item>\n        <item>AutoDispose</item>\n        <item>AutoFitTextView</item>\n        <item>AutoLinkTextView</item>\n        <item>AutoParcel</item>\n        <item>AutoScale TextView</item>\n        <item>AutoValue: Gson Extension</item>\n        <item>AutoValue: Ignore Hash Equals Extension</item>\n        <item>AutobahnAndroid</item>\n        <item>Autofill</item>\n        <item>Automattic-Tracks-Android</item>\n        <item>Autostart plugin</item>\n        <item>Autostarter</item>\n        <item>Avathor-Android-Library</item>\n        <item>Avazu aNative</item>\n        <item>Avazu aNative</item>\n        <item>Avocarrot</item>\n        <item>Awesome Notifications - Flutter</item>\n        <item>Awesome QR</item>\n        <item>AwesomeSplash</item>\n        <item>Axonix</item>\n        <item>Axonix</item>\n        <item>Azure SDK for Java</item>\n        <item>B4A</item>\n        <item>B4J</item>\n        <item>BGABanner</item>\n        <item>BGAQRCode-Android</item>\n        <item>BIP32-Ed25519-java</item>\n        <item>BIP32-Ed25519-java</item>\n        <item>BIP39</item>\n        <item>BOP Bitcoin Server API</item>\n        <item>BR Vault</item>\n        <item>BRVAH</item>\n        <item>BSON library</item>\n        <item>Babator</item>\n        <item>Backelite</item>\n        <item>Backelite</item>\n        <item>Backendless</item>\n        <item>Backtrace</item>\n        <item>Backtrace</item>\n        <item>Badge</item>\n        <item>BadgeView</item>\n        <item>Baidu APPX</item>\n        <item>Baidu Crash Reporter</item>\n        <item>Baidu Crash Reporter</item>\n        <item>Baidu Location</item>\n        <item>Baidu Map</item>\n        <item>Baidu Maps</item>\n        <item>Baidu Mobile Ads</item>\n        <item>Baidu Mobile Stat</item>\n        <item>Baidu Navigation</item>\n        <item>Balloon</item>\n        <item>BannerViewPager</item>\n        <item>Barchart-UDT</item>\n        <item>Barcode Scanner</item>\n        <item>Barcode-Kaiteki</item>\n        <item>Base64Coder</item>\n        <item>BasePopup</item>\n        <item>BasePopup</item>\n        <item>BasePopup</item>\n        <item>BasePopup</item>\n        <item>Batch</item>\n        <item>Bazaarvoice</item>\n        <item>Bcrypt</item>\n        <item>BeaconBank</item>\n        <item>BeaconsInSpace (Fysical)</item>\n        <item>Beaglebuddy mp3 java library</item>\n        <item>Bean Validation API</item>\n        <item>Beemray</item>\n        <item>Beintoo</item>\n        <item>Better Player</item>\n        <item>Better Video Player</item>\n        <item>BetterLinkMovementMethod</item>\n        <item>BetterSpinner</item>\n        <item>Bho</item>\n        <item>BiMap</item>\n        <item>BidMachine</item>\n        <item>BigFraction</item>\n        <item>BigImageViewer</item>\n        <item>BikramSambat</item>\n        <item>BillingClient</item>\n        <item>Binance Chain Java SDK</item>\n        <item>Binary Preferences</item>\n        <item>BindingCollectionAdapter</item>\n        <item>BindingCollectionAdapter</item>\n        <item>Biometric</item>\n        <item>BitLabs</item>\n        <item>Bitcollider</item>\n        <item>Bitcollider</item>\n        <item>Bitly</item>\n        <item>Blake2B</item>\n        <item>Blesh</item>\n        <item>BlueConic</item>\n        <item>BlueCove</item>\n        <item>BlueKai (acquired by Oracle)</item>\n        <item>Bluecats</item>\n        <item>Blueprints</item>\n        <item>Bluetooth-Android</item>\n        <item>Bluetooth-Android</item>\n        <item>BlurView</item>\n        <item>Blurhash</item>\n        <item>Blurry</item>\n        <item>Bmob Android SDK</item>\n        <item>Bolts</item>\n        <item>Bond</item>\n        <item>BottomBar</item>\n        <item>BottomDialogs</item>\n        <item>BottomNavigationViewEx</item>\n        <item>BottomSheet</item>\n        <item>BottomSheetBuilder</item>\n        <item>BottomSheetPickers</item>\n        <item>Bouncy Castle</item>\n        <item>Braintree</item>\n        <item>Branch</item>\n        <item>Brandio</item>\n        <item>Braze (formerly Appboy)</item>\n        <item>BreadcrumbsView</item>\n        <item>Bridge</item>\n        <item>Brightcove</item>\n        <item>Browser</item>\n        <item>Bubble-Picker</item>\n        <item>BubbleSeekBar</item>\n        <item>BugClipper</item>\n        <item>BugSense</item>\n        <item>Bugfender</item>\n        <item>Buglife</item>\n        <item>Bugly</item>\n        <item>Bugly Android SDK</item>\n        <item>Bugsee</item>\n        <item>Bugsnag</item>\n        <item>BungeeCord</item>\n        <item>Butter Knife</item>\n        <item>Button</item>\n        <item>ButtonCustomShadow</item>\n        <item>BuzzAd Benefit</item>\n        <item>Bypass</item>\n        <item>Byte Buddy</item>\n        <item>Byyd (Adfonic)</item>\n        <item>CAMView</item>\n        <item>CAT</item>\n        <item>CBOR</item>\n        <item>CBOR For Java</item>\n        <item>CFR</item>\n        <item>CITA</item>\n        <item>CJKCharsetDetector</item>\n        <item>CSS Parser</item>\n        <item>CWAC AndDown</item>\n        <item>CWAC ColorMixer</item>\n        <item>CWAC Layouts</item>\n        <item>CWAC RichEditText</item>\n        <item>CWAC Wakeful</item>\n        <item>CWAC-Pager</item>\n        <item>Cachify</item>\n        <item>Caffeine</item>\n        <item>Caldroid</item>\n        <item>Caldroid</item>\n        <item>CalendarView</item>\n        <item>Call Control DataShare</item>\n        <item>CallDorado</item>\n        <item>Callbacks</item>\n        <item>Calligrapher</item>\n        <item>Calligraphy</item>\n        <item>CameraRoll</item>\n        <item>CameraView</item>\n        <item>CameraX</item>\n        <item>CandyBar</item>\n        <item>Capacitor</item>\n        <item>Capacitor OAuth 2 client plugin</item>\n        <item>Capacitor Plugins</item>\n        <item>Capacitor Voice Recorder</item>\n        <item>CaramelAds</item>\n        <item>Carbon</item>\n        <item>Card Library</item>\n        <item>Cardboard SDK</item>\n        <item>CardsUI</item>\n        <item>Cardview</item>\n        <item>Carnival</item>\n        <item>Carnival</item>\n        <item>Carto (formerly Nutiteq)</item>\n        <item>Carto (formerly Nutiteq)</item>\n        <item>Carto Mobile SDK</item>\n        <item>CastCompanionLibrary</item>\n        <item>Catcher</item>\n        <item>Cats</item>\n        <item>Caulis FraudAlert</item>\n        <item>Cauly</item>\n        <item>Cauly</item>\n        <item>Cauly</item>\n        <item>Cedexis Radar</item>\n        <item>Chameleon App Theme Engine</item>\n        <item>ChangeLog Library</item>\n        <item>Changelog</item>\n        <item>Chaquopi</item>\n        <item>ChartBoost</item>\n        <item>ChartProgressBar</item>\n        <item>Chartbeat</item>\n        <item>ChatKit</item>\n        <item>ChatSecure-Push-Android</item>\n        <item>CheckVersionLib</item>\n        <item>Checker Framework</item>\n        <item>Checker Framework</item>\n        <item>CheckerboardDrawable</item>\n        <item>Checkout</item>\n        <item>Cheetah Ads</item>\n        <item>ChipCloud</item>\n        <item>Chips Input Layout</item>\n        <item>ChipsLayoutManager</item>\n        <item>Chooser</item>\n        <item>Chrome Custom Tabs</item>\n        <item>Chrome Networking Stack</item>\n        <item>Chrome\\'s URL library</item>\n        <item>ChromeCast Java API v2</item>\n        <item>ChromeLikeTabSwitcher</item>\n        <item>ChromeMenu</item>\n        <item>Chromium Base</item>\n        <item>Chromium Build</item>\n        <item>Chuck</item>\n        <item>Chucker</item>\n        <item>Chunk Templates for Java</item>\n        <item>Chunk Templates for Java</item>\n        <item>Cicerone</item>\n        <item>Cifrasoft</item>\n        <item>Cipher.so</item>\n        <item>CircleImageView</item>\n        <item>CircleIndicator</item>\n        <item>CircleMenuView</item>\n        <item>CircleProgress</item>\n        <item>CircleProgressBar</item>\n        <item>Circular Progress Bar</item>\n        <item>CircularImageView</item>\n        <item>CircularProgressBar</item>\n        <item>CircularProgressIndicator</item>\n        <item>CircularReveal</item>\n        <item>CircularSeekBar</item>\n        <item>ClassyShark</item>\n        <item>CleanInsights</item>\n        <item>ClearBlade</item>\n        <item>CleverTap</item>\n        <item>Cling UPnP</item>\n        <item>Cling UPnP</item>\n        <item>Cloud Audit Logs</item>\n        <item>CloudRail SI for Java</item>\n        <item>Cloudmobi</item>\n        <item>Cocos2d-x</item>\n        <item>Code scanner</item>\n        <item>CodeEditor</item>\n        <item>CodeView</item>\n        <item>CodeauxLibPortable</item>\n        <item>Codec2 Android Library</item>\n        <item>Codehaus Plexus</item>\n        <item>Codehaus Plexus</item>\n        <item>Codename One Regex Library</item>\n        <item>Coil</item>\n        <item>Coinswap</item>\n        <item>Collect</item>\n        <item>Colocator</item>\n        <item>Color Picker</item>\n        <item>Color Picker for Android</item>\n        <item>Color Preference</item>\n        <item>Color Preference</item>\n        <item>Color-O-Matic</item>\n        <item>ColorChooser</item>\n        <item>ColorPicker</item>\n        <item>ColorPicker-Android</item>\n        <item>ColorPickerDialog</item>\n        <item>ColorPickerPreference</item>\n        <item>ColorPickerView</item>\n        <item>ColorPickerX</item>\n        <item>ColorSheet</item>\n        <item>Colormath</item>\n        <item>ComScore</item>\n        <item>Comm100</item>\n        <item>CommonLibrary</item>\n        <item>CommonUtils</item>\n        <item>CommonsLibrary</item>\n        <item>CommonsWare MergeAdapter</item>\n        <item>CommonsWare SackOfViewsAdapter</item>\n        <item>CompactCalendarView</item>\n        <item>Compose Colorful Customizable Sliders</item>\n        <item>Compose Destinations</item>\n        <item>Compose Material Dialogs</item>\n        <item>Compose Tooltip</item>\n        <item>Compressor</item>\n        <item>Comscore Analytics</item>\n        <item>Conceal</item>\n        <item>Conceal</item>\n        <item>Concurrent</item>\n        <item>Concurrent Trees</item>\n        <item>Conductor</item>\n        <item>Connect IQ SDK</item>\n        <item>Connect IQ SDK</item>\n        <item>ConnectBot</item>\n        <item>Conscrypt</item>\n        <item>Conscrypt</item>\n        <item>Console</item>\n        <item>Constraint Layout Library</item>\n        <item>Contacts</item>\n        <item>Contentsquare</item>\n        <item>ContextMenu</item>\n        <item>Conversant</item>\n        <item>Conversant</item>\n        <item>Conviva</item>\n        <item>CookieBar 2</item>\n        <item>CoolaData</item>\n        <item>Coordinatorlayout</item>\n        <item>Copper</item>\n        <item>Cordova Advanced HTTP</item>\n        <item>Cordova Advanced HTTP</item>\n        <item>Cordova App Version Plugin</item>\n        <item>Cordova Background Plugin</item>\n        <item>Cordova Badge Plugin</item>\n        <item>Cordova Crosswalk Plugin</item>\n        <item>Cordova Disable HTTP Cache</item>\n        <item>Cordova Download Plugin</item>\n        <item>Cordova Email Plugin</item>\n        <item>Cordova Music Controls Plugin</item>\n        <item>Cordova Native Audio Plugin</item>\n        <item>Cordova Plugin Extension</item>\n        <item>Cordova Push Notification Plugin</item>\n        <item>Cordova SMS Plugin</item>\n        <item>Cordova Screen Orientation Plugin</item>\n        <item>Cordova Social Sharing plugin</item>\n        <item>Cordova Universal Links Plugin</item>\n        <item>Cordova plugin for theme detection</item>\n        <item>Cordova-AES256</item>\n        <item>CordovaClipboard</item>\n        <item>Couchbase Lite</item>\n        <item>Couchbase Lite</item>\n        <item>Coulus Coelib</item>\n        <item>Countly</item>\n        <item>Crash Reporter</item>\n        <item>CrashReporter</item>\n        <item>CrashSDK</item>\n        <item>CrashX</item>\n        <item>Crashlytics</item>\n        <item>Crashlytics</item>\n        <item>Crashlytics</item>\n        <item>Crashlytics</item>\n        <item>Crashlytics</item>\n        <item>Crashy</item>\n        <item>Cream</item>\n        <item>Criteo</item>\n        <item>Critic</item>\n        <item>Criware</item>\n        <item>Cronet Transport for OkHttp and Retrofit</item>\n        <item>CrossfadeDrawerLayout</item>\n        <item>Crossfader</item>\n        <item>Crouton</item>\n        <item>Crowdin Android SDK</item>\n        <item>Crownpeak</item>\n        <item>Crux</item>\n        <item>Crypto</item>\n        <item>Crypto</item>\n        <item>CryptoPrefs</item>\n        <item>CsvReader</item>\n        <item>Cube SDK</item>\n        <item>Cuebiq</item>\n        <item>Cuebiq</item>\n        <item>Currency Picker for Android</item>\n        <item>Curtains</item>\n        <item>Curtains</item>\n        <item>Custom Activity On Crash library</item>\n        <item>Custom Adapter RecyclerView</item>\n        <item>Custom Views</item>\n        <item>Custom Views library</item>\n        <item>CustomBottomSheetBehavior</item>\n        <item>CustomTabsHelper</item>\n        <item>CustomizedTextView</item>\n        <item>Cyanea</item>\n        <item>D8 dexer and R8 shrinker</item>\n        <item>DATE4J</item>\n        <item>DBFlow</item>\n        <item>DMM GAMES ASDK</item>\n        <item>DNSSEC4J</item>\n        <item>DOV-E</item>\n        <item>DPreference</item>\n        <item>Dagger</item>\n        <item>DaoCheng(Thinkyeah)</item>\n        <item>Dart</item>\n        <item>DashClock API</item>\n        <item>DataAutoAccess</item>\n        <item>DataStore</item>\n        <item>DataUtilities</item>\n        <item>Databinding</item>\n        <item>Databox</item>\n        <item>Datadog</item>\n        <item>Date Picker</item>\n        <item>Date Range Picker</item>\n        <item>DateTimePicker</item>\n        <item>Dawin</item>\n        <item>DearOne(LocationValue)</item>\n        <item>DebugDrawer</item>\n        <item>DeepLinkDispatch</item>\n        <item>DeepLinkDispatch</item>\n        <item>Deezer Android SDK</item>\n        <item>Delegated-Scopes-Manager</item>\n        <item>Demdex</item>\n        <item>Demdex</item>\n        <item>DexClassLoader</item>\n        <item>Dexmaker</item>\n        <item>Dexter</item>\n        <item>DiagonalLayout</item>\n        <item>DialogPlus</item>\n        <item>Didomi</item>\n        <item>Digital COVID Certificates: Business Rules</item>\n        <item>Digital Union (shuzilm)</item>\n        <item>Discord Telemetry</item>\n        <item>Discreet App Rate</item>\n        <item>DiscreteScrollView</item>\n        <item>DiscreteSeekBar</item>\n        <item>Disk LRU Cache</item>\n        <item>Dispatch queue</item>\n        <item>Dispatch queue</item>\n        <item>Display</item>\n        <item>Documentfile</item>\n        <item>Doki</item>\n        <item>Donut</item>\n        <item>Doubleclick</item>\n        <item>Downloader</item>\n        <item>Drag &amp; Drop n\\' Swipe Recyclerview</item>\n        <item>Drag Select Recycler View</item>\n        <item>DragLinearLayout</item>\n        <item>DragListView</item>\n        <item>DragNDropList</item>\n        <item>DragSortListView</item>\n        <item>DrawableToolbox</item>\n        <item>Drawerlayout</item>\n        <item>Droidsonroids ReLinker</item>\n        <item>Dropbox Core SDK for Java</item>\n        <item>Dropbox Java SDK</item>\n        <item>Droppy</item>\n        <item>Duapps</item>\n        <item>Duktape</item>\n        <item>DuktapeJava</item>\n        <item>Dynamic Yield</item>\n        <item>DynamicGrid</item>\n        <item>Dynamicanimation</item>\n        <item>Dynatrace</item>\n        <item>Dynatrace</item>\n        <item>Dynatrace</item>\n        <item>ECC-25519</item>\n        <item>EGit</item>\n        <item>EOSIO SDK for Java</item>\n        <item>EOSIO SDK for Java</item>\n        <item>EOSIO SDK for Java</item>\n        <item>EPGpaid</item>\n        <item>EVRYTHNG</item>\n        <item>EZPhotoPicker</item>\n        <item>EZPhotoPicker</item>\n        <item>Easy Rules</item>\n        <item>EasyAdapter</item>\n        <item>EasyBluetoothFrame</item>\n        <item>EasyFonts</item>\n        <item>EasyFonts</item>\n        <item>EasyImage</item>\n        <item>EasyPermissions</item>\n        <item>EasyPermissions-ktx</item>\n        <item>EasyPrefs</item>\n        <item>EasyRecyclerView</item>\n        <item>EasyRest-Desktop</item>\n        <item>Eclipse Core</item>\n        <item>Eclipse Equinox</item>\n        <item>Eclipse JDT</item>\n        <item>Eclipse Jetty</item>\n        <item>Eclipse Paho Android Service</item>\n        <item>Eclipse Platform Text</item>\n        <item>Eclipse Platform Text</item>\n        <item>Eclipse tm4e</item>\n        <item>EdDSA-Java</item>\n        <item>EditTextView</item>\n        <item>Editor</item>\n        <item>Edwards</item>\n        <item>Egloo</item>\n        <item>Ehawk</item>\n        <item>ElasticDragDismissLayout</item>\n        <item>Emarsys Predict</item>\n        <item>Embrace</item>\n        <item>Emma</item>\n        <item>Emoji</item>\n        <item>Emoji Support Lib</item>\n        <item>Emoji Support Lib</item>\n        <item>Emojicon</item>\n        <item>EmphasisTextView</item>\n        <item>Encryption</item>\n        <item>Encryption</item>\n        <item>Enhance</item>\n        <item>EnhancedListView</item>\n        <item>Enro</item>\n        <item>Enro</item>\n        <item>Ensighten</item>\n        <item>Epic</item>\n        <item>Epic Online Services SDK</item>\n        <item>Epic games analytics</item>\n        <item>Epic games analytics</item>\n        <item>Epoxy</item>\n        <item>EpubLib</item>\n        <item>ErgoScript compiler and ErgoTree interpreter</item>\n        <item>ErgoScript compiler and ErgoTree interpreter</item>\n        <item>ErgoScript compiler and ErgoTree interpreter</item>\n        <item>ErgoScript compiler and ErgoTree interpreter</item>\n        <item>ErgoScript compiler and ErgoTree interpreter</item>\n        <item>Error Prone</item>\n        <item>ErrorView</item>\n        <item>Esri ArcGIS</item>\n        <item>Essentials</item>\n        <item>Estimote</item>\n        <item>Eulerian</item>\n        <item>EventBus</item>\n        <item>Events</item>\n        <item>Evidon (now Crownpeak)</item>\n        <item>ExactTarget</item>\n        <item>Exifinterface</item>\n        <item>ExoMedia</item>\n        <item>ExoPlayer</item>\n        <item>ExoPlayerFilter</item>\n        <item>Expandable Layout</item>\n        <item>Expandable RecyclerView</item>\n        <item>ExpandableBottomBar</item>\n        <item>ExpandableFab</item>\n        <item>ExpandableLayout</item>\n        <item>ExpandableTextView</item>\n        <item>ExpansionPanel</item>\n        <item>ExplosionField</item>\n        <item>ExplosionField</item>\n        <item>Expo</item>\n        <item>Exponea</item>\n        <item>Exponea</item>\n        <item>Exponea</item>\n        <item>ExtendedTouchView</item>\n        <item>Extensible Metadata Platform</item>\n        <item>Eyewind</item>\n        <item>Eyewind</item>\n        <item>EzXHelper</item>\n        <item>F-Droid Privileged Extension</item>\n        <item>F.O.X</item>\n        <item>FABProgressCircle</item>\n        <item>FABProgressCircle</item>\n        <item>FABProgressCircle</item>\n        <item>FFImageLoading</item>\n        <item>FFmpegKit</item>\n        <item>FFmpegMediaMetadataRetriever</item>\n        <item>FLUZO</item>\n        <item>FMOD</item>\n        <item>FabButton</item>\n        <item>FabTransitionActivity</item>\n        <item>Fabric</item>\n        <item>Facebook Ads</item>\n        <item>Facebook Analytics</item>\n        <item>Facebook Analytics</item>\n        <item>Facebook Analytics</item>\n        <item>Facebook Audience</item>\n        <item>Facebook Flipper</item>\n        <item>Facebook Gaming Services</item>\n        <item>Facebook Login</item>\n        <item>Facebook Notifications</item>\n        <item>Facebook Places</item>\n        <item>Facebook SDK for Android</item>\n        <item>Facebook SDK for Android</item>\n        <item>Facebook SDK for Android</item>\n        <item>Facebook SDK for Android</item>\n        <item>Facebook SDK for Android</item>\n        <item>Facebook SDK for Android</item>\n        <item>Facebook SDK for Android</item>\n        <item>Facebook SDK for Android</item>\n        <item>Facebook Share</item>\n        <item>Facebook Unity SDK</item>\n        <item>Factual</item>\n        <item>Factual</item>\n        <item>FadingActionBar</item>\n        <item>FancyShowCaseView</item>\n        <item>FancyToast-Android</item>\n        <item>Fancybuttons</item>\n        <item>Fast Android Networking Library</item>\n        <item>FastAdapter</item>\n        <item>FastAdapter</item>\n        <item>FastImage</item>\n        <item>FastParse</item>\n        <item>FastScroll</item>\n        <item>FastScroll-Everywhere</item>\n        <item>FastScroll-RecyclerView</item>\n        <item>FastScrollerAndRecyclerViewFixes</item>\n        <item>FasterXML Jackson</item>\n        <item>Feather</item>\n        <item>Fetch</item>\n        <item>FidZup</item>\n        <item>Fidesmo Nordpol</item>\n        <item>Fig</item>\n        <item>Fiksu</item>\n        <item>Filament</item>\n        <item>File Dialogs</item>\n        <item>File Picker</item>\n        <item>FileCoreLibrary</item>\n        <item>FileDialog</item>\n        <item>FileDownloader</item>\n        <item>FilePicker</item>\n        <item>FilemojiCompat</item>\n        <item>FindBugs</item>\n        <item>FingerPaintView</item>\n        <item>FingerPaintView</item>\n        <item>Fingerprint Authentication Helper</item>\n        <item>FingerprintIdentify</item>\n        <item>Firebase</item>\n        <item>Firebase</item>\n        <item>Firebase</item>\n        <item>Firebase</item>\n        <item>Firebase</item>\n        <item>Firebase</item>\n        <item>Firebase</item>\n        <item>Firebase</item>\n        <item>Firebase</item>\n        <item>Firebase</item>\n        <item>Firebase</item>\n        <item>Firebase</item>\n        <item>Firebase</item>\n        <item>Firebase</item>\n        <item>Firebase</item>\n        <item>Firebase</item>\n        <item>Firebase</item>\n        <item>Firebase Analytics</item>\n        <item>Firebase Analytics</item>\n        <item>Firebase Analytics</item>\n        <item>Firebase Data Transport</item>\n        <item>Firebase Installations</item>\n        <item>Firebase JobDispatcher</item>\n        <item>FirebaseUI for Android</item>\n        <item>FishBun</item>\n        <item>FlatBuffers</item>\n        <item>Flatiron Media</item>\n        <item>FlexInput</item>\n        <item>FlexLayout</item>\n        <item>FlexboxLayout</item>\n        <item>FlexiLogger</item>\n        <item>FlexibleAdapter</item>\n        <item>FlexibleAdapter</item>\n        <item>FlexibleAdapter</item>\n        <item>FlexibleRichTextView</item>\n        <item>FlipView</item>\n        <item>Flipper</item>\n        <item>FloatView</item>\n        <item>Floating Action Button Speed Dial</item>\n        <item>Floating Search View</item>\n        <item>Floating Text Button</item>\n        <item>FloatingActionButton</item>\n        <item>FloatingActionButtons Menu</item>\n        <item>FloatingView</item>\n        <item>Floo</item>\n        <item>Flow Preferences</item>\n        <item>FlowBinding</item>\n        <item>FlowLayout</item>\n        <item>FlowUp</item>\n        <item>Flowsense</item>\n        <item>FluctSDK</item>\n        <item>Flurry Ads</item>\n        <item>Flurry Analytics</item>\n        <item>Flute Music Player Plugin</item>\n        <item>Flutter</item>\n        <item>Flutter</item>\n        <item>Flutter</item>\n        <item>Flutter</item>\n        <item>Flutter</item>\n        <item>Flutter</item>\n        <item>Flutter</item>\n        <item>Flutter Android Lifecycle Plugin</item>\n        <item>Flutter Audio Query</item>\n        <item>Flutter Downloader</item>\n        <item>Flutter Geolocator Plugin</item>\n        <item>Flutter InAppWebView Plugin</item>\n        <item>Flutter Keyboard Visibility</item>\n        <item>Flutter Permission handler Plugin</item>\n        <item>Flutter Screen Wake</item>\n        <item>Flutter Uploader</item>\n        <item>Flutter Workmanager</item>\n        <item>Flutter background_fetch</item>\n        <item>Flutter qrcode reader</item>\n        <item>Flutter-WebRTC</item>\n        <item>FlutterIsolate</item>\n        <item>Flying-Pigeon</item>\n        <item>Flying-Pigeon</item>\n        <item>FollowAnalytics</item>\n        <item>FontIcon Library</item>\n        <item>Footmarks</item>\n        <item>FormValidator</item>\n        <item>Fotoapparat</item>\n        <item>FoxCompat</item>\n        <item>FragNav</item>\n        <item>Fragmentation</item>\n        <item>Fragmentation</item>\n        <item>Fragmentation</item>\n        <item>Frames</item>\n        <item>FreeDrawView</item>\n        <item>FreeRDP Core</item>\n        <item>FreeReflection</item>\n        <item>FreeReflection</item>\n        <item>FreeTTS</item>\n        <item>FreeWheel</item>\n        <item>Fresco</item>\n        <item>Fresco</item>\n        <item>Fresco</item>\n        <item>Fresco</item>\n        <item>Fresco</item>\n        <item>Fresco</item>\n        <item>Fresco</item>\n        <item>Fresco</item>\n        <item>Fresco</item>\n        <item>Fresco</item>\n        <item>Fresco</item>\n        <item>Fresco</item>\n        <item>Fresco</item>\n        <item>Fresco</item>\n        <item>Fresco</item>\n        <item>Fresco</item>\n        <item>Fresco</item>\n        <item>Fresco</item>\n        <item>Fresco</item>\n        <item>Fresco</item>\n        <item>Fresco</item>\n        <item>Fresco</item>\n        <item>Fresco</item>\n        <item>Fresco</item>\n        <item>Fresco</item>\n        <item>Fresco</item>\n        <item>Fresco</item>\n        <item>Fresco</item>\n        <item>Fresco</item>\n        <item>Fresco</item>\n        <item>Fresco</item>\n        <item>FrescoImageViewer</item>\n        <item>Frodo</item>\n        <item>Fuck Storage Access Framework</item>\n        <item>Fuel</item>\n        <item>FullscreenVideoView</item>\n        <item>Fungible Token</item>\n        <item>Fuzzy Date Formatter</item>\n        <item>Fyber</item>\n        <item>Fyber SponsorPay</item>\n        <item>GIPHY Analytics</item>\n        <item>GIPHY Analytics</item>\n        <item>GLES.JS</item>\n        <item>GMobi - Go2Reach (General Mobile Corporation)</item>\n        <item>GMobi - Go2Reach (General Mobile Corporation)</item>\n        <item>GMobi - Go2Reach (General Mobile Corporation)</item>\n        <item>GMobi - Go2Reach (General Mobile Corporation)</item>\n        <item>GMobi - Go2Reach (General Mobile Corporation)</item>\n        <item>GMobi - Go2Reach (General Mobile Corporation)</item>\n        <item>GMobi - Go2Reach (General Mobile Corporation)</item>\n        <item>GMobi - Go2Reach (General Mobile Corporation)</item>\n        <item>GMobi - Go2Reach (General Mobile Corporation)</item>\n        <item>GMobi - Go2Reach (General Mobile Corporation)</item>\n        <item>GMobi - Go2Reach (General Mobile Corporation)</item>\n        <item>GMobi - Go2Reach (General Mobile Corporation)</item>\n        <item>GMobi - Go2Reach (General Mobile Corporation)</item>\n        <item>GMobi - Go2Reach (General Mobile Corporation)</item>\n        <item>GMobi - Go2Reach (General Mobile Corporation)</item>\n        <item>GMobi - Go2Reach (General Mobile Corporation)</item>\n        <item>GMobi - Go2Reach (General Mobile Corporation)</item>\n        <item>GMobi - Go2Reach (General Mobile Corporation)</item>\n        <item>GNU Trove library</item>\n        <item>GOM Factory AdPie</item>\n        <item>GPA KOREA</item>\n        <item>GPShopper</item>\n        <item>GPUImage for Android</item>\n        <item>Gamania Beanfun</item>\n        <item>Game Sparks</item>\n        <item>GameAnalytics</item>\n        <item>Garmin Fit</item>\n        <item>GathererScraper</item>\n        <item>GaugeView</item>\n        <item>Gecko</item>\n        <item>Gemius HeatMap</item>\n        <item>General extensions</item>\n        <item>Geniee</item>\n        <item>Genonbeta Android Framework</item>\n        <item>GeoIP2 Java API</item>\n        <item>GeoMap</item>\n        <item>GeoNature - Sync-mobile</item>\n        <item>GeoNature - Sync-mobile</item>\n        <item>GeoNature - Sync-mobile</item>\n        <item>GeoNature - Sync-mobile</item>\n        <item>GeoPackage Java</item>\n        <item>GeoUniq (Cloud4Win)</item>\n        <item>Geodesy</item>\n        <item>GeographicLib</item>\n        <item>George’s Android Utilities</item>\n        <item>Gesture Recycler</item>\n        <item>GestureViews</item>\n        <item>GifView</item>\n        <item>GigaGet</item>\n        <item>Gigya</item>\n        <item>Gimbal</item>\n        <item>Gio</item>\n        <item>Giphy Android Search Library</item>\n        <item>GithubContributionsView</item>\n        <item>Gitty Reporter</item>\n        <item>Glance</item>\n        <item>GlassFish Jersey</item>\n        <item>Glide</item>\n        <item>Glide SVG</item>\n        <item>Glide Transformations</item>\n        <item>GlidePalette</item>\n        <item>GlideToVectorYou</item>\n        <item>Glispa Connect (Formerly Avocarrot)</item>\n        <item>GloballyDynamic</item>\n        <item>Glympse</item>\n        <item>Goldfinger</item>\n        <item>Google API Client Libraries</item>\n        <item>Google ARCode</item>\n        <item>Google AdMob</item>\n        <item>Google AdMob</item>\n        <item>Google AdMob</item>\n        <item>Google AdMob</item>\n        <item>Google AdMob</item>\n        <item>Google AdMob</item>\n        <item>Google AdMob</item>\n        <item>Google AdMob</item>\n        <item>Google AdMob</item>\n        <item>Google AdMob</item>\n        <item>Google Ads</item>\n        <item>Google Ads</item>\n        <item>Google Analytics</item>\n        <item>Google Analytics</item>\n        <item>Google Analytics</item>\n        <item>Google Analytics Plugin (Cordova)</item>\n        <item>Google Android Net</item>\n        <item>Google App Engine</item>\n        <item>Google App Engine</item>\n        <item>Google App Inventor</item>\n        <item>Google Auth Library For Java OAuth2 HTTP</item>\n        <item>Google Cast</item>\n        <item>Google Cloud Audit</item>\n        <item>Google Cloud Messaging</item>\n        <item>Google Core Libraries for Java 6+</item>\n        <item>Google Drive API</item>\n        <item>Google Firebase Cloud Messaging Cordova Push Plugin</item>\n        <item>Google Fit</item>\n        <item>Google GCM</item>\n        <item>Google Gson</item>\n        <item>Google Guice</item>\n        <item>Google Java API Client Services</item>\n        <item>Google Java API Client Services for AdMob</item>\n        <item>Google Java API Client Services for AdSense</item>\n        <item>Google Java API Client Services for AdSense</item>\n        <item>Google ML Kit</item>\n        <item>Google Maps API</item>\n        <item>Google Maps API</item>\n        <item>Google Maps for Flutter</item>\n        <item>Google Material Design</item>\n        <item>Google Mobile Services</item>\n        <item>Google Mobile Services</item>\n        <item>Google Mobile Services</item>\n        <item>Google Play</item>\n        <item>Google Play Billing Library / Service</item>\n        <item>Google Play Core</item>\n        <item>Google Play OSS-Licenses</item>\n        <item>Google Play Store</item>\n        <item>Google Private Compute Services</item>\n        <item>Google Protocol Buffers</item>\n        <item>Google Tag Manager</item>\n        <item>Google Tag Manager</item>\n        <item>GopenPGP</item>\n        <item>Grab Analytics</item>\n        <item>GradientView</item>\n        <item>GraphView</item>\n        <item>Gravy Analytics</item>\n        <item>GreedyGame</item>\n        <item>GreenDroid</item>\n        <item>GreenRobot</item>\n        <item>GroundTruth</item>\n        <item>GrowingIO</item>\n        <item>Growth Push</item>\n        <item>Growth Push</item>\n        <item>Gson on Fire</item>\n        <item>Guardian Project CacheWord</item>\n        <item>Guardian Project IOCipher</item>\n        <item>Guardian Project IOCipher</item>\n        <item>Guardian Project NetCipher</item>\n        <item>Guardian Project PanicKit</item>\n        <item>HMS Signin</item>\n        <item>HSV-Alpha Color Picker for Android</item>\n        <item>HUAWEI In-App Purchases</item>\n        <item>HabitRPGAndroidWrapper</item>\n        <item>Handy URI Templates</item>\n        <item>HandyGridView</item>\n        <item>Hash Time Locked Contracts</item>\n        <item>Hasher</item>\n        <item>HashtagView</item>\n        <item>Hauler</item>\n        <item>Hawk</item>\n        <item>HawtJNI</item>\n        <item>Headless Android Heap Analyzer</item>\n        <item>Headlong</item>\n        <item>Heap</item>\n        <item>HelloCharts for Android</item>\n        <item>HelpShift</item>\n        <item>Hermes JS Engine</item>\n        <item>Herow</item>\n        <item>HeyTap</item>\n        <item>HeyTap</item>\n        <item>Heyzap (bought by Fyber)</item>\n        <item>Heyzap (bought by Fyber)</item>\n        <item>High Performance Primitive Collections for Java</item>\n        <item>Highlander</item>\n        <item>HighlightJs View</item>\n        <item>HiveMQ MQTT Client</item>\n        <item>Hjson for Java</item>\n        <item>HmsPickerView</item>\n        <item>HockeyApp</item>\n        <item>HokoBlur</item>\n        <item>HoloGraphLibrary</item>\n        <item>Hotmob SDK</item>\n        <item>Houndify</item>\n        <item>Houseads</item>\n        <item>HtmlCleaner</item>\n        <item>HtmlCompose</item>\n        <item>HtmlSpanner</item>\n        <item>HtmlText</item>\n        <item>HtmlTextView for Android</item>\n        <item>Http Request</item>\n        <item>HttpClient Android repackaged</item>\n        <item>HttpClient Android repackaged</item>\n        <item>HuaWeiVerifier</item>\n        <item>Huawei Appmarket</item>\n        <item>Huawei HMF Tasks</item>\n        <item>Huawei Mobile Services</item>\n        <item>Huawei Mobile Services</item>\n        <item>Huawei Mobile Services (HMS) Core</item>\n        <item>Huawei Mobile Services (HMS) Core</item>\n        <item>Huawei Mobile Services (HMS) Core</item>\n        <item>Huawei Mobile Services (HMS) Core</item>\n        <item>Huawei Mobile Services (HMS) Core</item>\n        <item>Huawei Mobile Services (HMS) Core</item>\n        <item>Huawei Mobile Services (HMS) Core</item>\n        <item>Huawei Mobile Services (HMS) Core</item>\n        <item>Huawei Payment</item>\n        <item>Huawei Update SDK</item>\n        <item>Humanize</item>\n        <item>Huq Sourcekit</item>\n        <item>Hutool</item>\n        <item>HyperLog</item>\n        <item>HyperTrack</item>\n        <item>HyperTrack</item>\n        <item>HyperTrack</item>\n        <item>HyprMX</item>\n        <item>I2P Android</item>\n        <item>IAB Open Measurement</item>\n        <item>IAB Open Measurement</item>\n        <item>IAB Open Measurement</item>\n        <item>IAC</item>\n        <item>IBM Digital Analytics</item>\n        <item>IBM Mobile Marketing (Acoustic)</item>\n        <item>IBM Mobile Marketing (Acoustic)</item>\n        <item>IBM Mobile Marketing (Acoustic)</item>\n        <item>IBM Mobile Marketing (Acoustic)</item>\n        <item>ICNA nProtect GameGuard</item>\n        <item>IGG.com</item>\n        <item>IGG.com</item>\n        <item>IGG.com</item>\n        <item>IGG.com</item>\n        <item>IGG.com</item>\n        <item>IGG.com</item>\n        <item>IJKPlayer</item>\n        <item>INFOnline</item>\n        <item>IOTA Java Library</item>\n        <item>IPAddress</item>\n        <item>IPQualityScore</item>\n        <item>IPinfo Java Client Library</item>\n        <item>IQV</item>\n        <item>IQzone</item>\n        <item>IVS Player</item>\n        <item>Icepick</item>\n        <item>Icon picker dialog</item>\n        <item>Icon picker dialog</item>\n        <item>Iconify</item>\n        <item>Iconify</item>\n        <item>Identicon</item>\n        <item>Igexin</item>\n        <item>Image Picker Library</item>\n        <item>Image Picker plugin for Flutter</item>\n        <item>ImagePicker</item>\n        <item>ImageViewTouch for Android</item>\n        <item>ImmersionBar</item>\n        <item>Immutable Collections Library for Kotlin</item>\n        <item>In Loco</item>\n        <item>InAppBrowser for React Native</item>\n        <item>InBrainSurveys SDK</item>\n        <item>InMarket</item>\n        <item>InMobi</item>\n        <item>InMobi</item>\n        <item>Incubed Client</item>\n        <item>Incubed Client</item>\n        <item>Incubed Client</item>\n        <item>Indicator Fast Scroll</item>\n        <item>IndoorAtlas</item>\n        <item>Infer</item>\n        <item>Infinite View Pager</item>\n        <item>InfiniteCycleViewPager</item>\n        <item>Injekt</item>\n        <item>Ink</item>\n        <item>InkPageIndicator</item>\n        <item>Inneractive</item>\n        <item>InputMask</item>\n        <item>Inquiry</item>\n        <item>Inrix</item>\n        <item>Insetter</item>\n        <item>Insider</item>\n        <item>Instabug</item>\n        <item>Instal</item>\n        <item>Instal</item>\n        <item>Instal</item>\n        <item>Instal</item>\n        <item>Instal</item>\n        <item>Instal</item>\n        <item>Instreamatic (Adman)</item>\n        <item>Integral Ad Science</item>\n        <item>IntelliJ IDEA</item>\n        <item>IntelliJ java-decompiler plugin</item>\n        <item>Interchain Service</item>\n        <item>Intercom</item>\n        <item>Intercom Android SDK</item>\n        <item>International Components for Unicode</item>\n        <item>Internet Time Utility</item>\n        <item>Interpolator</item>\n        <item>Intrasonics</item>\n        <item>IntroMi</item>\n        <item>Invertase RNFirebase</item>\n        <item>Ionic Keyboard Plugin for Cordova</item>\n        <item>Ionic Keyboard Plugin for Cordova</item>\n        <item>Ionic Web View for Cordova</item>\n        <item>ItemAnimators</item>\n        <item>J2ObjC</item>\n        <item>J2V8</item>\n        <item>JAAD</item>\n        <item>JADX</item>\n        <item>JAXB API</item>\n        <item>JAudiotagger</item>\n        <item>JBox2d</item>\n        <item>JCIFS</item>\n        <item>JCIP Annotations</item>\n        <item>JCTools</item>\n        <item>JCharset</item>\n        <item>JCodec</item>\n        <item>JCommander</item>\n        <item>JDOM v1</item>\n        <item>JDOM v2</item>\n        <item>JDeferred</item>\n        <item>JFace</item>\n        <item>JLaTeXMath</item>\n        <item>JLargeArrays</item>\n        <item>JLatexMath Android</item>\n        <item>JMustache</item>\n        <item>JNA</item>\n        <item>JNI bindings for Roc Toolkit</item>\n        <item>JNano Commons</item>\n        <item>JOpt Simple</item>\n        <item>JRAW</item>\n        <item>JSON in Java</item>\n        <item>JSONIC</item>\n        <item>JSch - Java Secure Channel</item>\n        <item>JSnappy</item>\n        <item>JSocks</item>\n        <item>JStribog</item>\n        <item>JSword</item>\n        <item>JSword</item>\n        <item>JTS Topology Suite</item>\n        <item>JTS Topology Suite</item>\n        <item>JTar</item>\n        <item>JTidy</item>\n        <item>JTransforms</item>\n        <item>JUnrar</item>\n        <item>JW Player</item>\n        <item>JWTDecode.Android</item>\n        <item>JXMPP</item>\n        <item>JZlib</item>\n        <item>Jackson Json-processor</item>\n        <item>JailMonkey</item>\n        <item>Jakarta ORO</item>\n        <item>Jakarta Regexp</item>\n        <item>Janrain</item>\n        <item>Janrain</item>\n        <item>Janrain</item>\n        <item>Japng</item>\n        <item>Jaspersoft Mobile SDK for Android</item>\n        <item>Java - MorseCoder</item>\n        <item>Java ADB library</item>\n        <item>Java API for Google Analytics</item>\n        <item>Java API for Google Analytics</item>\n        <item>Java API for Google Analytics</item>\n        <item>Java API for Google Analytics</item>\n        <item>Java API for WordNet Searching (JAWS)</item>\n        <item>Java Algebra System (JAS)</item>\n        <item>Java Arithmetics Engine (formerly Arity)</item>\n        <item>Java Code Coverage Library (JaCoCo)</item>\n        <item>Java Components for Mathematics</item>\n        <item>Java Excel API</item>\n        <item>Java Hamcrest</item>\n        <item>Java JWT</item>\n        <item>Java MP4 Parser</item>\n        <item>Java Marine API</item>\n        <item>Java NIO</item>\n        <item>Java Native Runtime constants</item>\n        <item>Java Native Runtime constants</item>\n        <item>Java Option Class</item>\n        <item>Java SemVer</item>\n        <item>Java Service Wrapper</item>\n        <item>Java Streams</item>\n        <item>Java TNEF package</item>\n        <item>Java WebSockets</item>\n        <item>Java concurrent utilities</item>\n        <item>Java-1-Class-Utilities</item>\n        <item>Java.Interop</item>\n        <item>JavaBeans Activation Framework (JAF)</item>\n        <item>JavaBeans(TM) Activation Framework</item>\n        <item>JavaMail API</item>\n        <item>JavaMoney</item>\n        <item>JavaNeoUtil</item>\n        <item>JavaPoet</item>\n        <item>JavaReedSolomon</item>\n        <item>JavaTM API for JSON Processing</item>\n        <item>JavaWriter</item>\n        <item>JavaWriter</item>\n        <item>JavaWuzzy</item>\n        <item>JavaWuzzy</item>\n        <item>JavaX Annotation API</item>\n        <item>JavaX Bluetooth OBEX</item>\n        <item>JavaX Dependency Injection</item>\n        <item>JavaX MID Profile</item>\n        <item>JavaX Servlet API</item>\n        <item>JavaX WebServices RESTful Resources</item>\n        <item>Javassist</item>\n        <item>Jaxen</item>\n        <item>Jayway JsonPath</item>\n        <item>JcifsFile</item>\n        <item>Jellyfin API Client</item>\n        <item>Jellyfin Kotlin SDK</item>\n        <item>JeroMQ</item>\n        <item>JetPref</item>\n        <item>Jetpack Compose</item>\n        <item>Jetpack Compose</item>\n        <item>Jetpack Compose Android Color Picker</item>\n        <item>Jetpack Compose Android Color Picker</item>\n        <item>Jetpack Compose Gestures</item>\n        <item>Jetpack WindowManager Library</item>\n        <item>JiGuang Aurora Mobile JPush</item>\n        <item>JiaoZiVideoPlayer</item>\n        <item>Jitsi Meet SDK</item>\n        <item>JniHelpers</item>\n        <item>Joda Time</item>\n        <item>Joda-Money</item>\n        <item>JsEvaluator</item>\n        <item>Json Simple</item>\n        <item>JsonViewer</item>\n        <item>JsoupXpath</item>\n        <item>JsoupXpath</item>\n        <item>Jumio</item>\n        <item>JumpTap</item>\n        <item>Junit</item>\n        <item>KARTE</item>\n        <item>KIDOZ</item>\n        <item>KISSmetrics Android API</item>\n        <item>KOIN</item>\n        <item>KPermissions</item>\n        <item>KPreferences</item>\n        <item>KToast</item>\n        <item>KValidation</item>\n        <item>Kahlua</item>\n        <item>Kakao AD SDK</item>\n        <item>KakaoTalk Link</item>\n        <item>Katex Mathview</item>\n        <item>Keen</item>\n        <item>Keen Java Clients</item>\n        <item>Keen Java Clients</item>\n        <item>KeenClient-Scala</item>\n        <item>Keepass2Android PluginSDK</item>\n        <item>Keepassdroid</item>\n        <item>KefirBB</item>\n        <item>KenBurnsView</item>\n        <item>Kevel (formerly Adzerk)</item>\n        <item>KeyCzar</item>\n        <item>KeyboardVisibilityEvent</item>\n        <item>Kiama</item>\n        <item>Kiip</item>\n        <item>Klaxon</item>\n        <item>Kochava</item>\n        <item>Kochava</item>\n        <item>Kochava</item>\n        <item>Kodein</item>\n        <item>Koi</item>\n        <item>Komli Mobile (ZestAdz)</item>\n        <item>Konfetti</item>\n        <item>Kontakt</item>\n        <item>Kotlin</item>\n        <item>Kotlin Android Extensions Runtime</item>\n        <item>Kotlin Android Extensions Runtime</item>\n        <item>Kotlin Coroutine Adapter</item>\n        <item>Kotlin Coroutines for Retrofit</item>\n        <item>Kotlin Multiplatform Logging</item>\n        <item>Kotlin Programming Language</item>\n        <item>Kotlin Statistics</item>\n        <item>Kotlin coroutines await extension for OkHttp3</item>\n        <item>Kotlin serialization</item>\n        <item>Kotson: Gson for Kotlin</item>\n        <item>Kovenant</item>\n        <item>Kpan</item>\n        <item>Krate</item>\n        <item>Kronos-Android</item>\n        <item>Krux</item>\n        <item>Kryo</item>\n        <item>Ktor</item>\n        <item>Kuper</item>\n        <item>Kxml2</item>\n        <item>LEDataStream</item>\n        <item>LFilePicker</item>\n        <item>LINE Admolin</item>\n        <item>LINE Ads Five</item>\n        <item>LINE SDK</item>\n        <item>LINE SDK</item>\n        <item>LINE Telemetry</item>\n        <item>LINE Telemetry</item>\n        <item>LINE Telemetry</item>\n        <item>LZ4 Java</item>\n        <item>LZ4 Java</item>\n        <item>LZ4 Java</item>\n        <item>LZMA Streams</item>\n        <item>Lab4Math</item>\n        <item>LabelledSpinner</item>\n        <item>Lambdaworks Codec</item>\n        <item>Landscapist</item>\n        <item>Lantern</item>\n        <item>Lantern MobileSDK</item>\n        <item>Lantern for Android</item>\n        <item>LastAdapter</item>\n        <item>Launch Navigator Cordova/Phonegap Plugin</item>\n        <item>LazyColumn scrollbar compose library</item>\n        <item>LazyThreeTenBp</item>\n        <item>Lazysodium for Android</item>\n        <item>Lazysodium for Java</item>\n        <item>LeadBolt</item>\n        <item>LeadBolt</item>\n        <item>LeadBolt</item>\n        <item>LeakCanary</item>\n        <item>LeakCanary</item>\n        <item>LeakCanary</item>\n        <item>LeanCloud Java SDK</item>\n        <item>LeanPlum</item>\n        <item>Leanback</item>\n        <item>Lenddo</item>\n        <item>Let</item>\n        <item>LevelDB</item>\n        <item>LevelDB JNI</item>\n        <item>LibChecker-Rules-Bundle</item>\n        <item>LibSimprints</item>\n        <item>LibVLC</item>\n        <item>Libidn</item>\n        <item>Librtmp Client for Android</item>\n        <item>LicenseView</item>\n        <item>LicensesDialog</item>\n        <item>Lifecycle</item>\n        <item>Liftoff</item>\n        <item>Ligatus</item>\n        <item>Ligatus</item>\n        <item>Ligatus</item>\n        <item>Lightning Network Daemon</item>\n        <item>Lightweight-Stream-API</item>\n        <item>Linear Layout Manager</item>\n        <item>Lingver</item>\n        <item>LiquidCore</item>\n        <item>LiquidSwipe</item>\n        <item>Lisnr</item>\n        <item>ListViewAnimations</item>\n        <item>LitePal for Android</item>\n        <item>Litho</item>\n        <item>LittleProxy</item>\n        <item>Live Event</item>\n        <item>Live SDK for Android (Legacy)</item>\n        <item>LiveEventBus</item>\n        <item>Loader</item>\n        <item>Loading</item>\n        <item>Locale</item>\n        <item>Localytics</item>\n        <item>Localytics</item>\n        <item>Localytics</item>\n        <item>Locus API</item>\n        <item>Locuslabs</item>\n        <item>LogKit</item>\n        <item>LoganSquare</item>\n        <item>Logback</item>\n        <item>Logger</item>\n        <item>Loggly</item>\n        <item>Loggly</item>\n        <item>Loggly</item>\n        <item>LoopMe</item>\n        <item>Lost (Location Open Source Tracker)</item>\n        <item>Lost (Location Open Source Tracker)</item>\n        <item>LotaData</item>\n        <item>Lotame</item>\n        <item>Lottie for Android</item>\n        <item>Lottie for React Native</item>\n        <item>Loupe</item>\n        <item>LovelyDialog</item>\n        <item>LuaJ</item>\n        <item>Lunar Unity Mobile Console</item>\n        <item>Lynx</item>\n        <item>MAdvertise</item>\n        <item>MAdvertise</item>\n        <item>MAdvertise</item>\n        <item>MDOTM</item>\n        <item>MEGVII</item>\n        <item>ML Kit</item>\n        <item>MMKV</item>\n        <item>MOCA</item>\n        <item>MPAndroidChart</item>\n        <item>MQTT Connection Library</item>\n        <item>MSA Auth for Android</item>\n        <item>MVP-Bakery</item>\n        <item>Madhouse</item>\n        <item>Magic Button</item>\n        <item>MagicIndicator</item>\n        <item>Mail.ru</item>\n        <item>Mail.ru</item>\n        <item>Malverting/Adfrauds</item>\n        <item>Malverting/Adfrauds</item>\n        <item>Malverting/Adfrauds</item>\n        <item>Malverting/Adfrauds</item>\n        <item>Malverting/Adfrauds</item>\n        <item>Malverting/Adfrauds</item>\n        <item>Malverting/Adfrauds</item>\n        <item>Malverting/Adfrauds</item>\n        <item>Malverting/Adfrauds</item>\n        <item>Malverting/Adfrauds</item>\n        <item>Malverting/Adfrauds</item>\n        <item>Malverting/Adfrauds</item>\n        <item>Malverting/Adfrauds</item>\n        <item>Malverting/Adfrauds</item>\n        <item>Malverting/Adfrauds</item>\n        <item>Malverting/Adfrauds</item>\n        <item>Malverting/Adfrauds</item>\n        <item>Malverting/Adfrauds</item>\n        <item>Malverting/Adfrauds#2</item>\n        <item>Malverting/Adfrauds#2</item>\n        <item>Malverting/Adfrauds#2</item>\n        <item>Malverting/Adfrauds#2</item>\n        <item>Malverting/Adfrauds#2</item>\n        <item>Malverting/Adfrauds#2</item>\n        <item>Malverting/Adfrauds#2</item>\n        <item>Malverting/Adfrauds#2</item>\n        <item>Malverting/Adfrauds#2</item>\n        <item>Malverting/Adfrauds#2</item>\n        <item>Malverting/Adfrauds#2</item>\n        <item>Malverting/Adfrauds#2</item>\n        <item>Mantissa</item>\n        <item>MapDB</item>\n        <item>Mapbox</item>\n        <item>Mapbox</item>\n        <item>Mapbox</item>\n        <item>Mapbox Android SDK</item>\n        <item>Mapbox Maps SDK for Android</item>\n        <item>Mapbox SDK Telemetry component</item>\n        <item>Maps SDK for Android</item>\n        <item>MapsForge</item>\n        <item>MarkDown</item>\n        <item>Markdown For Android</item>\n        <item>Markdown4j</item>\n        <item>MarkdownJ</item>\n        <item>MarkdownJ</item>\n        <item>MarkdownText - Jetpack Compose</item>\n        <item>MarkdownView</item>\n        <item>MarkedView</item>\n        <item>Marketo (an Adobe Company)</item>\n        <item>Markwon</item>\n        <item>Markwon</item>\n        <item>Material About</item>\n        <item>Material Arc Menu</item>\n        <item>Material Bottom Navigation Library</item>\n        <item>Material Bottom Navigation Library</item>\n        <item>Material Checklist</item>\n        <item>Material Chip View</item>\n        <item>Material CircularProgressView</item>\n        <item>Material Contextual Action Bar</item>\n        <item>Material DatePicker and TimePicker</item>\n        <item>Material DateTime Picker</item>\n        <item>Material Dialogs</item>\n        <item>Material Favorite Button</item>\n        <item>Material File Picker</item>\n        <item>Material Icon Library</item>\n        <item>Material Menu</item>\n        <item>Material Motion for Jetpack Compose</item>\n        <item>Material Preference</item>\n        <item>Material Ripple Layout</item>\n        <item>Material Spinner</item>\n        <item>Material Tap Target Prompt</item>\n        <item>Material View Pager Dots Indicator</item>\n        <item>Material-Calendar-View</item>\n        <item>Material-ViewPagerIndicator</item>\n        <item>Material-ish Progress</item>\n        <item>MaterialDateRangePicker</item>\n        <item>MaterialDrawer</item>\n        <item>MaterialEditText</item>\n        <item>MaterialIntroTutorial</item>\n        <item>MaterialLibrary</item>\n        <item>MaterialLoadingProgressBar</item>\n        <item>MaterialNumberPicker</item>\n        <item>MaterialPlayPauseView</item>\n        <item>MaterialPreference</item>\n        <item>MaterialPreferenceLibrary</item>\n        <item>MaterialPreferences</item>\n        <item>MaterialProgressBar</item>\n        <item>MaterialRangeBar</item>\n        <item>MaterialRatingBar</item>\n        <item>MaterialScrollBar</item>\n        <item>MaterialSearchView</item>\n        <item>MaterialSeekBarPreference</item>\n        <item>MaterialSheetFab</item>\n        <item>MaterialShowcaseView</item>\n        <item>MaterialStyledDialogs</item>\n        <item>MaterialTabHost</item>\n        <item>MaterialTile</item>\n        <item>MaterialTutorial</item>\n        <item>MaterialViewPager</item>\n        <item>MaterialYouFileExplorer</item>\n        <item>Materialize</item>\n        <item>MathParser.org-mXparser</item>\n        <item>MathView</item>\n        <item>Matisse</item>\n        <item>Matomo (Piwik)</item>\n        <item>Matomo (Piwik)</item>\n        <item>Matomo (Piwik)</item>\n        <item>Matomo (formerly Piwik)</item>\n        <item>Matrix SDK</item>\n        <item>Mavericks</item>\n        <item>MaxHeightScrollView</item>\n        <item>MaxMind DB Reader</item>\n        <item>Media</item>\n        <item>Media Home Video</item>\n        <item>Media2</item>\n        <item>MediaFire Java SDK</item>\n        <item>MediaLib</item>\n        <item>MediaLib</item>\n        <item>MediaLib</item>\n        <item>MediaViewerLibrary</item>\n        <item>Mediarouter</item>\n        <item>MemorizingTrustManager</item>\n        <item>MenuDrawer</item>\n        <item>MessageBubbleView</item>\n        <item>MessagePack for Java</item>\n        <item>Metaps</item>\n        <item>Metrics</item>\n        <item>Mezzomedia AD Platform</item>\n        <item>Mezzomedia AD Platform</item>\n        <item>Mezzomedia AD Platform</item>\n        <item>Mezzomedia AD Platform</item>\n        <item>MiGBase64</item>\n        <item>Microblink</item>\n        <item>Microemulator</item>\n        <item>Microsoft Appcenter Analytics</item>\n        <item>Microsoft Appcenter Crashes</item>\n        <item>Microsoft Authentication Library</item>\n        <item>Microsoft Azure Active Directory Authentication Library</item>\n        <item>Microsoft Azure Analytics</item>\n        <item>Microsoft Band</item>\n        <item>Microsoft Graph-SDK</item>\n        <item>Microsoft Identity library for Android</item>\n        <item>Microsoft MapPoint</item>\n        <item>Microsoft Mobile Center SDK</item>\n        <item>Microsoft Mobile Center SDK</item>\n        <item>Microsoft Visual Studio App Center Analytics</item>\n        <item>Microsoft Visual Studio App Center Analytics</item>\n        <item>Microsoft Visual Studio App Center Crashes</item>\n        <item>Midi Driver</item>\n        <item>Millennial Media</item>\n        <item>Millisecond-Chronometer</item>\n        <item>Mime Craft</item>\n        <item>MinIO Client SDK for Java</item>\n        <item>MinLog</item>\n        <item>MiniDNS</item>\n        <item>Ministro Qt shared libraries</item>\n        <item>Mintegral</item>\n        <item>Mintegral</item>\n        <item>MixPanel</item>\n        <item>MoEngage</item>\n        <item>MoMo</item>\n        <item>MoPub</item>\n        <item>Moat</item>\n        <item>Moat Analytics</item>\n        <item>MobFox</item>\n        <item>MobFox</item>\n        <item>MobPower</item>\n        <item>Mobclick</item>\n        <item>Mobile Engagement</item>\n        <item>Mobile Engagement</item>\n        <item>MobileFFmpeg</item>\n        <item>MobileVisionBarcodeScanner</item>\n        <item>Mobincube</item>\n        <item>Mobiquity Networks</item>\n        <item>Mobius</item>\n        <item>Moblin</item>\n        <item>Mobon SDK</item>\n        <item>Mobvista</item>\n        <item>Mockito Framework</item>\n        <item>ModernAndroidPreferences</item>\n        <item>ModularAdapter</item>\n        <item>Mofiler</item>\n        <item>Mojise</item>\n        <item>MojoHaus AnimalSniffer Maven Plugin</item>\n        <item>Monarchy</item>\n        <item>Monet</item>\n        <item>MonetCompat</item>\n        <item>Moneta</item>\n        <item>MoneyTextView</item>\n        <item>Mono for Android</item>\n        <item>Moodmedia</item>\n        <item>Mopinion</item>\n        <item>Morgoo Packer</item>\n        <item>Mosby</item>\n        <item>Moshi JSON library</item>\n        <item>Moxy</item>\n        <item>Mozilla Charset Detector</item>\n        <item>Mozilla Crashreport</item>\n        <item>Mozilla Rhino</item>\n        <item>Mozilla Rhino</item>\n        <item>Mozilla Telemetry</item>\n        <item>Mozilla Telemetry</item>\n        <item>Mozilla Telemetry</item>\n        <item>Mozilla Telemetry</item>\n        <item>Mozilla Telemetry</item>\n        <item>MuPDF</item>\n        <item>MultiImageSelector</item>\n        <item>MultiLevelListView</item>\n        <item>MultiSelectDialog</item>\n        <item>MultiStateView</item>\n        <item>MultiType</item>\n        <item>MultiType-FilePicker</item>\n        <item>MultiValueSwitch</item>\n        <item>Music Cover View</item>\n        <item>Muzei API</item>\n        <item>MySQL JDBC</item>\n        <item>Myanmar Calendar</item>\n        <item>Mygod Library for Android</item>\n        <item>NDEF Tools for Android</item>\n        <item>NIFCLOUD mobile backend</item>\n        <item>Nachos for Android</item>\n        <item>NameInitialsCircleImageView</item>\n        <item>NanoHTTPD</item>\n        <item>Napier</item>\n        <item>NativeScript CollectionView</item>\n        <item>NativeScript Core Modules Widgets</item>\n        <item>NativeScript Image Picker</item>\n        <item>NativeScript Social Share Plugin</item>\n        <item>NativeScript-Couchbase</item>\n        <item>NativeX</item>\n        <item>Nativescript: Akylas Sqlite</item>\n        <item>Nativescript: Akylas Sqlite</item>\n        <item>NaturalDateFormat</item>\n        <item>Navigation</item>\n        <item>Navigation Bar</item>\n        <item>NeoSocket</item>\n        <item>NetBare</item>\n        <item>NetGuard</item>\n        <item>NetVelocity Passive SDK</item>\n        <item>NetVelocity Passive SDK</item>\n        <item>Netki Wallet Name Resolver</item>\n        <item>Netki Wallet Name Resolver</item>\n        <item>Netki Wallet Name Resolver</item>\n        <item>Netty Project</item>\n        <item>Netty Reactive Streams</item>\n        <item>Network Connection Class</item>\n        <item>New Relic</item>\n        <item>New Relic</item>\n        <item>NewPipe Extractor</item>\n        <item>NewsPic</item>\n        <item>Nexage</item>\n        <item>Nexage</item>\n        <item>Nextcloud Single Sign On</item>\n        <item>Nielsen</item>\n        <item>Nimbus JOSE+JWT</item>\n        <item>Nimbus JOSE+JWT</item>\n        <item>Nine Old Androids</item>\n        <item>Ninja Metics</item>\n        <item>NoDrawable</item>\n        <item>NoNonsense-FilePicker</item>\n        <item>Noah Pass</item>\n        <item>NoboButton</item>\n        <item>Nokia UI API</item>\n        <item>Non-Fungible Token</item>\n        <item>NoobCameraFlash</item>\n        <item>Notification Banner for Android</item>\n        <item>NoxMobi(AiAdMobi)</item>\n        <item>Number Keyboard</item>\n        <item>Number Picker</item>\n        <item>NumberButton</item>\n        <item>NumberPicker</item>\n        <item>NumberPicker for Android</item>\n        <item>NumberPickerPreference</item>\n        <item>NumberPickerView</item>\n        <item>Numbers</item>\n        <item>OAuth2 client</item>\n        <item>ODK Collect</item>\n        <item>ODK JavaRosa</item>\n        <item>OGC API Features JSON Lib</item>\n        <item>ONEstore</item>\n        <item>OPML Parser</item>\n        <item>OSBCP CSS Parser</item>\n        <item>OSGi</item>\n        <item>OSGi Framework</item>\n        <item>OSGi System Bundle</item>\n        <item>ObjectBox</item>\n        <item>ObjectCursor</item>\n        <item>Objenesis</item>\n        <item>OfferToro</item>\n        <item>Ogury</item>\n        <item>Ogury</item>\n        <item>Ogury</item>\n        <item>Ogury</item>\n        <item>Ogury Presage</item>\n        <item>OkDownload</item>\n        <item>OkHttp</item>\n        <item>OkHttp</item>\n        <item>OkHttp okio Framework</item>\n        <item>OkhttpDownloader</item>\n        <item>Olm</item>\n        <item>Omniture</item>\n        <item>Omniture</item>\n        <item>Once</item>\n        <item>OneAdapter</item>\n        <item>OneAudience</item>\n        <item>OneSignal</item>\n        <item>Onetrust</item>\n        <item>OnionKit for Android</item>\n        <item>OnyxAndroidSDK</item>\n        <item>Ooyala</item>\n        <item>Open M3U8</item>\n        <item>OpenBack</item>\n        <item>OpenCV</item>\n        <item>OpenCensus</item>\n        <item>OpenDocument.java</item>\n        <item>OpenJAX Security NaCl</item>\n        <item>OpenJDK</item>\n        <item>OpenLocate</item>\n        <item>OpenLocate</item>\n        <item>OpenMapKit</item>\n        <item>OpenMapKit</item>\n        <item>OpenMeditation</item>\n        <item>OpenMeditation</item>\n        <item>OpenPGP API library</item>\n        <item>OpenStreetMap-Tools for Android</item>\n        <item>OpenTelemetry (OpenCensus, OpenTracing)</item>\n        <item>OpenTelemetry (OpenCensus, OpenTracing)</item>\n        <item>OpenTripPlanner (OTP)</item>\n        <item>OpenUDID</item>\n        <item>OpenUDID</item>\n        <item>OpenUDID Salama Generator</item>\n        <item>OpenVPN for Android</item>\n        <item>OpenX</item>\n        <item>OpenX</item>\n        <item>Openalliance (Huawei ads kit)</item>\n        <item>Openalliance (Huawei ads kit)</item>\n        <item>Openalliance (Huawei ads kit)</item>\n        <item>Opencsv</item>\n        <item>Opencsv</item>\n        <item>OpeningHoursParser</item>\n        <item>Opensignal</item>\n        <item>Opentracker</item>\n        <item>Optimizely</item>\n        <item>Opus for Android</item>\n        <item>Orchid</item>\n        <item>OssLicenseView</item>\n        <item>OtherLevels</item>\n        <item>Otto</item>\n        <item>OutBrain</item>\n        <item>Outbid</item>\n        <item>OverScroll-Everywhere</item>\n        <item>OverScrollBouncy</item>\n        <item>Overflow Pager Indicator widget</item>\n        <item>Overlapping Panels</item>\n        <item>OzTAM</item>\n        <item>PEANUT LABS</item>\n        <item>PEKO</item>\n        <item>PFLockScreen</item>\n        <item>PING place picker</item>\n        <item>PNGJ</item>\n        <item>POKKT</item>\n        <item>PRDownloader</item>\n        <item>PRTree</item>\n        <item>PackageInfo</item>\n        <item>PageIndicatorView</item>\n        <item>PageIndicatorView</item>\n        <item>PageIndicatorView</item>\n        <item>Paging</item>\n        <item>Pago</item>\n        <item>Paho Java Client</item>\n        <item>Palette</item>\n        <item>Pandora</item>\n        <item>Pangle</item>\n        <item>Pangle</item>\n        <item>Pangle</item>\n        <item>Pangle</item>\n        <item>Papaya</item>\n        <item>Papaya</item>\n        <item>Paper</item>\n        <item>PaperParcel</item>\n        <item>Parallax Everywhere</item>\n        <item>ParallaxPagerTransformer</item>\n        <item>Parceler</item>\n        <item>Parcelgen</item>\n        <item>Paris</item>\n        <item>Parse</item>\n        <item>Parse</item>\n        <item>Parse.com</item>\n        <item>Parse.ly</item>\n        <item>ParseRSS</item>\n        <item>Parsely Android SDK</item>\n        <item>PartyTrack</item>\n        <item>PasscodeLock-Android</item>\n        <item>Password EditText</item>\n        <item>Password Safe</item>\n        <item>Pattern Locker</item>\n        <item>PatternLock</item>\n        <item>PatternLockView</item>\n        <item>Pcap4J</item>\n        <item>PdfViewPager</item>\n        <item>PearlDiver</item>\n        <item>PebbleKit Android</item>\n        <item>Pendo</item>\n        <item>Pendo</item>\n        <item>PerfMark</item>\n        <item>PerfMark</item>\n        <item>Permiso</item>\n        <item>PermissionX</item>\n        <item>PermissionsDispatcher</item>\n        <item>PersistentCookieJar for OkHttp 3</item>\n        <item>Persona.ly</item>\n        <item>Phoenix Channel Client for Java and Android</item>\n        <item>PhoneGap NFC Plugin</item>\n        <item>PhoneGap Plugin BarcodeScanner</item>\n        <item>PhotoDraweeView</item>\n        <item>PhotoView</item>\n        <item>PhotoView</item>\n        <item>PhotoViewer Cordova Plugin</item>\n        <item>Phunware Advertising</item>\n        <item>Picasso</item>\n        <item>Picasso</item>\n        <item>Picasso 2 OkHttp 3 Downloader</item>\n        <item>Picasso Transformations</item>\n        <item>PicassoPalette</item>\n        <item>PickNCrop</item>\n        <item>Picker</item>\n        <item>Pilgrim by Foursquare</item>\n        <item>Pilgrim by Foursquare</item>\n        <item>PinLockView</item>\n        <item>Pincrux</item>\n        <item>PingStart</item>\n        <item>PinnedSectionListView</item>\n        <item>Pinterest</item>\n        <item>PiracyChecker</item>\n        <item>PiracyChecker</item>\n        <item>Piwik</item>\n        <item>Pix</item>\n        <item>PixlUI</item>\n        <item>PlaceAutocomplete</item>\n        <item>Placed</item>\n        <item>Placer</item>\n        <item>Play Games Services</item>\n        <item>Play Games Services</item>\n        <item>Play Install Referrer Library</item>\n        <item>Play Install Referrer Library wrapper for React Native</item>\n        <item>Play Services Places Placereport</item>\n        <item>Play Services SafetyNet</item>\n        <item>PlayFab java</item>\n        <item>PlayWidget</item>\n        <item>Playground OSS</item>\n        <item>PlaytestCloud Event Tracking</item>\n        <item>Plexure</item>\n        <item>Plleti</item>\n        <item>Point Inside</item>\n        <item>Polarify</item>\n        <item>Pollfish</item>\n        <item>Pontiflex</item>\n        <item>Port Mapper</item>\n        <item>Posthog</item>\n        <item>PowerMenu</item>\n        <item>PowerSpinner</item>\n        <item>Prebid Mobile</item>\n        <item>PredicIO</item>\n        <item>PredicIO</item>\n        <item>Preference</item>\n        <item>Preview Any File</item>\n        <item>PrimeCalendar</item>\n        <item>Print</item>\n        <item>Process Phoenix</item>\n        <item>Profile Passport</item>\n        <item>Profile Passport</item>\n        <item>ProfileInstaller</item>\n        <item>Progress Button Android</item>\n        <item>ProgressPieView</item>\n        <item>ProgressView</item>\n        <item>Proj4J</item>\n        <item>Project Lombok</item>\n        <item>ProofMode</item>\n        <item>Proton Core Libraries</item>\n        <item>Proximi.io</item>\n        <item>PseudoApkSigner</item>\n        <item>PubMatic</item>\n        <item>PubNative</item>\n        <item>PubNub</item>\n        <item>Public Transport Enabler</item>\n        <item>Pulsate</item>\n        <item>PushSpring</item>\n        <item>Pushbullet API</item>\n        <item>Pusher</item>\n        <item>Pushwoosh</item>\n        <item>Pushy</item>\n        <item>Pyze</item>\n        <item>QBaselib4AS</item>\n        <item>QRCodeReaderView</item>\n        <item>QRGen</item>\n        <item>QRGenerator</item>\n        <item>Qihoo Packer</item>\n        <item>Qihoo Packer</item>\n        <item>Qihoo Packer</item>\n        <item>Qt Project</item>\n        <item>Quadrant Data Acquisition SDK</item>\n        <item>Qualtrics</item>\n        <item>Quantcast</item>\n        <item>Quantumgraph(QGraph)/Appier</item>\n        <item>Quantumgraph(QGraph)/Appier</item>\n        <item>Quick Action</item>\n        <item>QuickBitmap</item>\n        <item>QuickBlox</item>\n        <item>QuickJS</item>\n        <item>QuickScroll</item>\n        <item>Quicklens</item>\n        <item>QuitNow!\\'s cache</item>\n        <item>RN Share Extension</item>\n        <item>RSS Parser</item>\n        <item>RTextEditorView</item>\n        <item>Radar</item>\n        <item>RadioRealButton</item>\n        <item>Radius Networks</item>\n        <item>Rajawali</item>\n        <item>Rakuten Analytics SDK</item>\n        <item>Rakuten Analytics SDK</item>\n        <item>Rakuten Unified Ads</item>\n        <item>Rakuten Unified Ads</item>\n        <item>Random Image Generator</item>\n        <item>RangeBar</item>\n        <item>RangeSeekBar</item>\n        <item>Ratioimageview</item>\n        <item>Raygun</item>\n        <item>ReLinker</item>\n        <item>React Native</item>\n        <item>React Native</item>\n        <item>React Native</item>\n        <item>React Native</item>\n        <item>React Native</item>\n        <item>React Native</item>\n        <item>React Native</item>\n        <item>React Native AES</item>\n        <item>React Native Alarm Notification</item>\n        <item>React Native Async Storage</item>\n        <item>React Native Background Timer</item>\n        <item>React Native Billing</item>\n        <item>React Native Bluetooth Serial</item>\n        <item>React Native Blur</item>\n        <item>React Native Camera</item>\n        <item>React Native Camera</item>\n        <item>React Native Camera</item>\n        <item>React Native Camera</item>\n        <item>React Native Camera</item>\n        <item>React Native Camera Kit</item>\n        <item>React Native Camera Kit</item>\n        <item>React Native Contacts</item>\n        <item>React Native DateTimePicker</item>\n        <item>React Native Encrypted Storage</item>\n        <item>React Native Fingerprint Scanner</item>\n        <item>React Native Gesture Handler</item>\n        <item>React Native Google Signin</item>\n        <item>React Native Image Picker</item>\n        <item>React Native Image Resizer</item>\n        <item>React Native In-App Browser</item>\n        <item>React Native MaskedView</item>\n        <item>React Native Module for CodePush</item>\n        <item>React Native Navigation</item>\n        <item>React Native Navigation Bar Color Change</item>\n        <item>React Native Notifications</item>\n        <item>React Native Orientation</item>\n        <item>React Native Push Notifications</item>\n        <item>React Native Quick Actions</item>\n        <item>React Native Reanimated</item>\n        <item>React Native Restart</item>\n        <item>React Native SQLite 2</item>\n        <item>React Native Search Bar</item>\n        <item>React Native Sensitive Info</item>\n        <item>React Native Shake Event Detector</item>\n        <item>React Native Share Extension</item>\n        <item>React Native Toast</item>\n        <item>React Native Touch ID</item>\n        <item>React Native Twitter Signin</item>\n        <item>React Native WebView</item>\n        <item>React Native Zip Archive</item>\n        <item>React-Native Track-Player</item>\n        <item>ReactNative: Native Tooltips</item>\n        <item>ReactNativeLocalization</item>\n        <item>Reactive Streams</item>\n        <item>ReactiveNetwork</item>\n        <item>ReactiveSensors</item>\n        <item>Reactor Core</item>\n        <item>Reactor Core</item>\n        <item>Reactor Core</item>\n        <item>Readability4J</item>\n        <item>Realm</item>\n        <item>RealtimeBlurView</item>\n        <item>RealtimeBlurView</item>\n        <item>Rebound</item>\n        <item>Receptiv (formerly Mediabrix)</item>\n        <item>Record Keeping</item>\n        <item>Recycler Bubble</item>\n        <item>Recycler Fast Scroll</item>\n        <item>Recycler Fast Scroll</item>\n        <item>RecyclerItemDecoration</item>\n        <item>RecyclerRefreshLayout</item>\n        <item>RecyclerView Animators</item>\n        <item>RecyclerView MultiSelect</item>\n        <item>RecyclerView-FastScroll</item>\n        <item>RecyclerView-FlexibleDivider</item>\n        <item>RecyclerViewFastScroller</item>\n        <item>RecyclerViewSwipeDecorator</item>\n        <item>Recyclerview</item>\n        <item>Recyclical</item>\n        <item>Redberry</item>\n        <item>ReflectASM</item>\n        <item>Reflection</item>\n        <item>RelativePopupWindow</item>\n        <item>Remark</item>\n        <item>RemotePreferences</item>\n        <item>RenderScript Intrinsics Replacement Toolkit</item>\n        <item>Renderers</item>\n        <item>Reprint</item>\n        <item>Repro</item>\n        <item>ResCU</item>\n        <item>ResourceInspection</item>\n        <item>RestFu</item>\n        <item>RestrictionBypass</item>\n        <item>Result</item>\n        <item>Retency</item>\n        <item>Retrofit</item>\n        <item>Reveal</item>\n        <item>Reveal Mobile</item>\n        <item>RevenueCat</item>\n        <item>Revmob</item>\n        <item>RichEditor for Android</item>\n        <item>RichText</item>\n        <item>Rikka Apps Preferences</item>\n        <item>Rikka Apps Widget</item>\n        <item>Rikka HTML lib</item>\n        <item>Rikka Libs</item>\n        <item>Rikka Libs</item>\n        <item>Rikka Libs</item>\n        <item>Rikka Libs</item>\n        <item>Rikka Libs</item>\n        <item>Rikka Lifecycle</item>\n        <item>Ringdroid</item>\n        <item>RippleEffect</item>\n        <item>RjFun</item>\n        <item>RjFun</item>\n        <item>Roboguice</item>\n        <item>Roboguice</item>\n        <item>Rollbar</item>\n        <item>Rome</item>\n        <item>RongCloud</item>\n        <item>RongCloud</item>\n        <item>RongCloud</item>\n        <item>Room</item>\n        <item>Roomigrant</item>\n        <item>Root File Picker</item>\n        <item>RootBeer</item>\n        <item>RootCommands</item>\n        <item>RosettaX</item>\n        <item>Rounded Bottom Sheet</item>\n        <item>RoundedImageView</item>\n        <item>Roximity</item>\n        <item>RtlViewPager</item>\n        <item>Rubicon Project</item>\n        <item>Rubikon Project</item>\n        <item>Rumble</item>\n        <item>RunDo</item>\n        <item>Runtime Permission Library</item>\n        <item>Rx Preferences</item>\n        <item>Rx Preferences</item>\n        <item>Rx Receivers</item>\n        <item>RxBillingService</item>\n        <item>RxBinding</item>\n        <item>RxBinding</item>\n        <item>RxBinding</item>\n        <item>RxBinding</item>\n        <item>RxBus</item>\n        <item>RxCamera</item>\n        <item>RxDogTag</item>\n        <item>RxDownload</item>\n        <item>RxDownloader</item>\n        <item>RxFirebase2</item>\n        <item>RxHttp</item>\n        <item>RxImagePicker</item>\n        <item>RxJava</item>\n        <item>RxJava Replaying Share</item>\n        <item>RxJava2Extensions</item>\n        <item>RxJava2Interop</item>\n        <item>RxJavaProGuardRules</item>\n        <item>RxLifecycle</item>\n        <item>RxLifecycle</item>\n        <item>RxPermissions</item>\n        <item>RxPermissions</item>\n        <item>RxRelay</item>\n        <item>RxRelay</item>\n        <item>RxRetroJsoup</item>\n        <item>RxRetroJsoup</item>\n        <item>RxTool</item>\n        <item>RxTool</item>\n        <item>RxUtils</item>\n        <item>RxkPrefs</item>\n        <item>S4M</item>\n        <item>S4M</item>\n        <item>SAP CDC (Gigya)</item>\n        <item>SAS</item>\n        <item>SAS SDK</item>\n        <item>SAX XMLReader</item>\n        <item>SCViewPager</item>\n        <item>SDKBOX</item>\n        <item>SDL2 for Android</item>\n        <item>SDP</item>\n        <item>SHA-256</item>\n        <item>SK planet Tad</item>\n        <item>SNS SDK(bytedance)</item>\n        <item>SQLBrite</item>\n        <item>SQLBrite</item>\n        <item>SQLBrite</item>\n        <item>SQLCipher for Android</item>\n        <item>SQLDelight</item>\n        <item>SQLite</item>\n        <item>SQLite JDBC Driver</item>\n        <item>SQLiteQB</item>\n        <item>SQLiteToExcel</item>\n        <item>SSNInputView</item>\n        <item>SSP</item>\n        <item>Safe Graph</item>\n        <item>Safe Graph</item>\n        <item>Sailthru</item>\n        <item>Salesforce Marketing Cloud</item>\n        <item>Samsung Accessory SDK</item>\n        <item>Samsung Accessory Service</item>\n        <item>Samsung Experience Support Library</item>\n        <item>Samsung Experience Support Library</item>\n        <item>Samsung Experience Support Library</item>\n        <item>Samsung Experience Support Library</item>\n        <item>Samsung Experience Support Library</item>\n        <item>Samsung Look SDK</item>\n        <item>Samsung Mobile SDK Pass (Fingerprint)</item>\n        <item>Samsung Overlay</item>\n        <item>Samsung Telemetry</item>\n        <item>Samsung Telemetry</item>\n        <item>SandroProxy</item>\n        <item>SandroProxy</item>\n        <item>SaySo Rewards</item>\n        <item>SaySo Rewards</item>\n        <item>Scala</item>\n        <item>Scaloid</item>\n        <item>ScanLibrary</item>\n        <item>Scandit</item>\n        <item>Scarlet</item>\n        <item>Sceneform Maintained SDK for Android</item>\n        <item>Schibsted</item>\n        <item>Scissors</item>\n        <item>Scoop</item>\n        <item>Score Card Research</item>\n        <item>ScoreLoop</item>\n        <item>Screen Brightness</item>\n        <item>Scribe Java Lib</item>\n        <item>ScribeJava</item>\n        <item>Scripting Layer for Android (SL4A)</item>\n        <item>ScrollHmsPicker</item>\n        <item>SearchPreference</item>\n        <item>SearchView</item>\n        <item>SearchableSpinner</item>\n        <item>SectionedRecyclerViewAdapter</item>\n        <item>Secure Remote Password Protocol</item>\n        <item>Seeds Android SDK</item>\n        <item>SeekArc</item>\n        <item>SeekBarPreference</item>\n        <item>Segment</item>\n        <item>Seismic</item>\n        <item>Semver4j</item>\n        <item>Send-Intent</item>\n        <item>Sendbird</item>\n        <item>Sensara</item>\n        <item>Sense360</item>\n        <item>Sensoro</item>\n        <item>Sensoro</item>\n        <item>Sensors Analytics</item>\n        <item>Sentiance</item>\n        <item>Sentry</item>\n        <item>Sentry</item>\n        <item>Sentry SDK for Java</item>\n        <item>Sentry-Android</item>\n        <item>ServerProxy</item>\n        <item>Sesame Shortcuts</item>\n        <item>SettingsCompat</item>\n        <item>SettingsCompat</item>\n        <item>SetupWizardLib</item>\n        <item>SevenZip-Java</item>\n        <item>Seventynine</item>\n        <item>ShadowLayout</item>\n        <item>ShallWeAD</item>\n        <item>ShallWeAD</item>\n        <item>ShapeOfView</item>\n        <item>ShapedImageView</item>\n        <item>Share plugin</item>\n        <item>ShareExtend</item>\n        <item>ShareTarget</item>\n        <item>Sharp</item>\n        <item>Sherlock</item>\n        <item>Shimmer</item>\n        <item>Shimmer for Android</item>\n        <item>ShimmerRecyclerView</item>\n        <item>ShineButton</item>\n        <item>Shizuku</item>\n        <item>Shizuku API</item>\n        <item>Shopkick</item>\n        <item>Shopkick</item>\n        <item>Shortbread</item>\n        <item>ShortcutBadger</item>\n        <item>ShowJava</item>\n        <item>ShowcaseView</item>\n        <item>Shuwei</item>\n        <item>Signal Android</item>\n        <item>Signal Protocol library for Java/Android</item>\n        <item>Signal360</item>\n        <item>Signal360</item>\n        <item>Signal360</item>\n        <item>SignalFrame</item>\n        <item>SignalStrengths</item>\n        <item>SignatureView</item>\n        <item>Signpost Oauth</item>\n        <item>SilverPush</item>\n        <item>SimMetrics</item>\n        <item>Simperium for Android</item>\n        <item>Simple</item>\n        <item>Simple API for CSS</item>\n        <item>Simple Commons</item>\n        <item>Simple Features Java</item>\n        <item>Simple License Display</item>\n        <item>Simple Logging Facade for Java</item>\n        <item>SimpleCropView</item>\n        <item>SimpleDialogFragments</item>\n        <item>SimpleFingerGestures</item>\n        <item>SimpleRtmp</item>\n        <item>SimpleSearchView</item>\n        <item>SimpleStorage</item>\n        <item>SimpleWaveform</item>\n        <item>SingleDateAndTimePicker</item>\n        <item>Singlespot</item>\n        <item>Singular</item>\n        <item>Sino Weibo SDK</item>\n        <item>Situm SDK</item>\n        <item>Sizmek</item>\n        <item>SkeletonLayout</item>\n        <item>Skillz Android Unity</item>\n        <item>SkyTube Components</item>\n        <item>Skyhook</item>\n        <item>Slide To Act</item>\n        <item>SlideActionView</item>\n        <item>SlideAndDragListView</item>\n        <item>SlidingDrawer</item>\n        <item>SlidingMenu</item>\n        <item>SlidingMenu</item>\n        <item>Slidingpanelayout</item>\n        <item>Slidr</item>\n        <item>Smaato</item>\n        <item>Smack</item>\n        <item>Smart</item>\n        <item>Smart Location Library</item>\n        <item>SmartBeat</item>\n        <item>SmartLook</item>\n        <item>SmartRefreshLayout</item>\n        <item>SmartStudy</item>\n        <item>SmartTabLayout</item>\n        <item>SmartyAds</item>\n        <item>SmoothProgressBar</item>\n        <item>SmoothProgressBar</item>\n        <item>SmoothRefreshLayout</item>\n        <item>SnackBar</item>\n        <item>SnackEngage</item>\n        <item>Snacktory</item>\n        <item>Snacky</item>\n        <item>SnakeYAML</item>\n        <item>SnakeYAML Engine</item>\n        <item>Snap Ad Kit</item>\n        <item>Snap Ad Kit</item>\n        <item>Snap Kit SDK</item>\n        <item>Snapchat Login Kit</item>\n        <item>Snapper</item>\n        <item>Snappy</item>\n        <item>SnappyDB</item>\n        <item>SnappySmoothScroller</item>\n        <item>Snowball</item>\n        <item>Snowplow</item>\n        <item>SoLoader</item>\n        <item>Socket.IO-client Java</item>\n        <item>Solar2D (Corona)</item>\n        <item>Sony Xperia Camera</item>\n        <item>Soomla</item>\n        <item>SortedListAdapter</item>\n        <item>SoundHaund Adverts</item>\n        <item>Spackle</item>\n        <item>Spark</item>\n        <item>SparkButton</item>\n        <item>Spectrum</item>\n        <item>Sphinx-4</item>\n        <item>Split</item>\n        <item>SplitView</item>\n        <item>Splitties</item>\n        <item>Splunk MINT</item>\n        <item>Spongy Castle</item>\n        <item>Spoteer Arc</item>\n        <item>Spotify Advertising</item>\n        <item>Spotify Advertising</item>\n        <item>Spotify Advertising</item>\n        <item>Spotify Advertising</item>\n        <item>Spotify Advertising</item>\n        <item>Spotify Advertising</item>\n        <item>Spotify Android SDK</item>\n        <item>Spotify Web API</item>\n        <item>Spotify Web API for Android</item>\n        <item>Spotlight</item>\n        <item>Spots progress dialog</item>\n        <item>Spring Framework</item>\n        <item>SpringIndicator</item>\n        <item>Spyglass</item>\n        <item>Square Cycler</item>\n        <item>Square Logcat</item>\n        <item>Square Metrics</item>\n        <item>SquiDB</item>\n        <item>Squircle IDE</item>\n        <item>StarView Metafile</item>\n        <item>StartApp-SDK</item>\n        <item>Startup</item>\n        <item>StateLayout</item>\n        <item>StatusBarUtil</item>\n        <item>Stax2 API</item>\n        <item>SteemConnect4j</item>\n        <item>Stefl Java Commons</item>\n        <item>StepProgressView</item>\n        <item>StepView</item>\n        <item>Stepper indicator</item>\n        <item>Steppers</item>\n        <item>Stericson RootShell</item>\n        <item>Stericson RootTools Library</item>\n        <item>Stericson RootTools Library</item>\n        <item>Stericson RootTools Library</item>\n        <item>Stetho</item>\n        <item>Stetho-Realm</item>\n        <item>StickerView</item>\n        <item>Sticky Header Grid Layout Manager</item>\n        <item>StickyGridHeaders</item>\n        <item>StickyHeaders</item>\n        <item>StickyListHeaders</item>\n        <item>StorIO</item>\n        <item>StorIO</item>\n        <item>StorageChooser</item>\n        <item>Store</item>\n        <item>StoriesProgressView</item>\n        <item>Stripe Android SDK</item>\n        <item>SublimePicker</item>\n        <item>Submarine</item>\n        <item>SubmitButton</item>\n        <item>Subsampling Scale Image View</item>\n        <item>Substratum Theme Template</item>\n        <item>Sui</item>\n        <item>Sun Mail</item>\n        <item>Sunrise/SunsetLib</item>\n        <item>SunriseSunset</item>\n        <item>SunriseSunsetView</item>\n        <item>Super CSV</item>\n        <item>SuperAwesome</item>\n        <item>SuperAwesome</item>\n        <item>SuperSLiM</item>\n        <item>SuperToasts Library</item>\n        <item>SuperToolTips</item>\n        <item>Supership</item>\n        <item>Supersonic Ads</item>\n        <item>Supersonic Ads</item>\n        <item>Support PreferenceFragment</item>\n        <item>Surface Duo SDK</item>\n        <item>Surface Duo SDK</item>\n        <item>Swagger Codegen</item>\n        <item>SweetAlert</item>\n        <item>SwiFTP</item>\n        <item>Swipe-Button</item>\n        <item>SwipeActionAdapter</item>\n        <item>SwipeBackLayout</item>\n        <item>SwipeCardsView</item>\n        <item>SwipeDeck2</item>\n        <item>SwipeMenuListView</item>\n        <item>SwipeRecyclerView</item>\n        <item>SwipeRevealLayout</item>\n        <item>SwipeSelector</item>\n        <item>SwipeToAction</item>\n        <item>Swiperefreshlayout</item>\n        <item>SwipyRefreshLayout</item>\n        <item>SwipyRefreshLayout</item>\n        <item>Swirl</item>\n        <item>SwitchButton</item>\n        <item>Swrve</item>\n        <item>Syc2Ad</item>\n        <item>Symya Java CAS</item>\n        <item>Sync2Ad</item>\n        <item>Synerise</item>\n        <item>TAPTrack</item>\n        <item>TAmedia</item>\n        <item>TIFF Java</item>\n        <item>TJHello ADEasy</item>\n        <item>TNK Factory</item>\n        <item>TableView</item>\n        <item>Taboola</item>\n        <item>Tag Commander</item>\n        <item>TagCommander (Commanders Act.)</item>\n        <item>TagSoup</item>\n        <item>TalkingData</item>\n        <item>TalkingData</item>\n        <item>TalkingData</item>\n        <item>TalkingData</item>\n        <item>TalkingData</item>\n        <item>TalkingData</item>\n        <item>TalkingData</item>\n        <item>Tamoco</item>\n        <item>Tangram</item>\n        <item>TapIt</item>\n        <item>TapResearch</item>\n        <item>TapResearch</item>\n        <item>TapResearch</item>\n        <item>TapTargetView</item>\n        <item>Tapad</item>\n        <item>Tapad</item>\n        <item>Tapdaq</item>\n        <item>Tapdaq</item>\n        <item>Tape by Square, Inc.</item>\n        <item>Tapjoy</item>\n        <item>Taplytics</item>\n        <item>Tappx</item>\n        <item>Tapstream</item>\n        <item>TarsosDSP</item>\n        <item>Taskbar</item>\n        <item>Tasker</item>\n        <item>Tasker Open Icon Pack</item>\n        <item>Tasker Plugin Library</item>\n        <item>TastyToast</item>\n        <item>Teads</item>\n        <item>Teads</item>\n        <item>Tealeaf</item>\n        <item>Tealium</item>\n        <item>TeamSpeak 3 Java API</item>\n        <item>TedBottomPicker</item>\n        <item>TedBottomPicker</item>\n        <item>TedImagePicker</item>\n        <item>TedKeyboardObserver</item>\n        <item>TedNaverMapClustering</item>\n        <item>TedPermission</item>\n        <item>TedRxOnActivityResult</item>\n        <item>Teemo</item>\n        <item>Teemo</item>\n        <item>Telaria (Tremor Video SDK)</item>\n        <item>TeleQuid</item>\n        <item>Telerik UI for Xamarin</item>\n        <item>Teliver</item>\n        <item>Tencent MTA</item>\n        <item>Tencent Map LBS</item>\n        <item>Tencent Map SDK</item>\n        <item>Tencent Map SDK</item>\n        <item>Tencent MobWin</item>\n        <item>Tencent QQ SDK</item>\n        <item>Tencent QQ SDK</item>\n        <item>Tencent QQ SDK</item>\n        <item>Tencent Social Ads</item>\n        <item>Tencent Stats</item>\n        <item>Tencent Stats</item>\n        <item>Tencent Wechat</item>\n        <item>Tencent Wechat SDK</item>\n        <item>Tencent Wechat SDK</item>\n        <item>Tencent Wechat SDK</item>\n        <item>Tencent Weiyun</item>\n        <item>TencentSearch</item>\n        <item>Tendermint Core</item>\n        <item>Tenjin</item>\n        <item>Tenjin SDK</item>\n        <item>TensorFlow</item>\n        <item>Terminal Emulator for Android</item>\n        <item>Tesseract Tools for Android</item>\n        <item>Tesseract Tools for Android</item>\n        <item>Tesseract4Android</item>\n        <item>TextDrawable</item>\n        <item>TextLayoutBuilder</item>\n        <item>TextViewRichDrawable</item>\n        <item>Textile-J</item>\n        <item>TextureVideoView for Android</item>\n        <item>The Open Toolkit Library</item>\n        <item>The Open Toolkit Library</item>\n        <item>Themable Widget Library</item>\n        <item>Theme</item>\n        <item>ThemedToggleButtonGroup</item>\n        <item>TheoremReach</item>\n        <item>ThinkingData Analytics</item>\n        <item>ThirtyInch</item>\n        <item>ThreeTen Android Backport</item>\n        <item>ThreeTen backport project</item>\n        <item>Ti.SwipeRefreshLayout</item>\n        <item>TiAndroidCanvas</item>\n        <item>Ticker</item>\n        <item>Tiger Types</item>\n        <item>TikTok SDK</item>\n        <item>TikXML</item>\n        <item>TileView3</item>\n        <item>Timber</item>\n        <item>Time4J</item>\n        <item>TimeDatePicker</item>\n        <item>TimeDurationPicker</item>\n        <item>TimePicker</item>\n        <item>Timeline-View</item>\n        <item>TimerX</item>\n        <item>TimerX</item>\n        <item>TimetableUI</item>\n        <item>TimetableView</item>\n        <item>Tinder Ads</item>\n        <item>Tinder Analytics</item>\n        <item>Tinder Analytics</item>\n        <item>Tink</item>\n        <item>Tinker</item>\n        <item>TinyPinyin</item>\n        <item>ToRuntime</item>\n        <item>ToastCompat</item>\n        <item>Toasty</item>\n        <item>TogetherAd</item>\n        <item>Toggle</item>\n        <item>ToggleButtonGroup</item>\n        <item>TokenAutoComplete</item>\n        <item>TokenAutoComplete</item>\n        <item>Tooltips</item>\n        <item>Toothpick</item>\n        <item>Tor Kit</item>\n        <item>TorOnionProxyLibrary-Android</item>\n        <item>TorOnionProxyLibrary-Android</item>\n        <item>TorOnionProxyLibrary-Android</item>\n        <item>TorOnionProxyLibrary-Android</item>\n        <item>TorOnionProxyLibrary-Android</item>\n        <item>Toro</item>\n        <item>TorrentStream-Android</item>\n        <item>TouchImageView</item>\n        <item>Traceur</item>\n        <item>Tracing</item>\n        <item>TradPlus</item>\n        <item>TransCommu Android SDK</item>\n        <item>Transcoder</item>\n        <item>Transition</item>\n        <item>Transition Button Android</item>\n        <item>Transitions Everywhere</item>\n        <item>Transparent text TextView</item>\n        <item>Tray</item>\n        <item>Treasure Data</item>\n        <item>Trikita Minimal Logger</item>\n        <item>Trilead SSH-2 for Java</item>\n        <item>Trillbit</item>\n        <item>TripleLift</item>\n        <item>TripleLift</item>\n        <item>TrustKit Android</item>\n        <item>TrustedIntents</item>\n        <item>TunProxy</item>\n        <item>Tune</item>\n        <item>Tune</item>\n        <item>Tutela</item>\n        <item>Tutucloud</item>\n        <item>Tutucloud</item>\n        <item>TwelveMonkeys ImageIO</item>\n        <item>Twine Data</item>\n        <item>Twitter Kit for Android</item>\n        <item>Twitter MoPub</item>\n        <item>Twitter ads</item>\n        <item>Twitter ads</item>\n        <item>Twitter ads</item>\n        <item>Twitter ads</item>\n        <item>Twitter ads</item>\n        <item>Twitter4J</item>\n        <item>TwoWayNestedScrollView</item>\n        <item>Txtmark</item>\n        <item>TypeSafe Config</item>\n        <item>TypeWriterView</item>\n        <item>UCWeb UC Ads</item>\n        <item>UCWeb UC Ads</item>\n        <item>UI Canvas</item>\n        <item>URL Handler Plugin for Apache Cordova</item>\n        <item>UXCam</item>\n        <item>Uber Analytics</item>\n        <item>Uber Analytics</item>\n        <item>Uber Analytics</item>\n        <item>UltimateRingtonePicker</item>\n        <item>Umeng</item>\n        <item>Umeng Analytics</item>\n        <item>Umeng Common SDK logging</item>\n        <item>Umeng Common SDK logging</item>\n        <item>Umeng Common SDK logging</item>\n        <item>Umeng Feedback</item>\n        <item>Umeng Mobile tracking SDK</item>\n        <item>Umeng Push SDK</item>\n        <item>Umeng Push SDK</item>\n        <item>Umeng Push SDK</item>\n        <item>Umeng Push SDK</item>\n        <item>UnApkm Android</item>\n        <item>Unacast Pure</item>\n        <item>Unacast Pure</item>\n        <item>UniFile</item>\n        <item>UniWebView</item>\n        <item>Unidecode</item>\n        <item>UnifiedNlpApi</item>\n        <item>UniqR</item>\n        <item>Unirest for Java</item>\n        <item>Unity IAP</item>\n        <item>Unity Mobile Notifications</item>\n        <item>Unity3D Android notification plugin</item>\n        <item>Unity3d Ads</item>\n        <item>Unity3d Ads</item>\n        <item>UnityDetectHeadset</item>\n        <item>Universal Image Loader</item>\n        <item>UniversalPreferences</item>\n        <item>Unknown Trackers</item>\n        <item>Unknown Trackers</item>\n        <item>Unknown Trackers</item>\n        <item>Unknown Trackers</item>\n        <item>Unknown Trackers</item>\n        <item>Unknown Trackers</item>\n        <item>Unknown Trackers</item>\n        <item>Unknown Trackers</item>\n        <item>Unknown Trackers</item>\n        <item>Unknown Trackers</item>\n        <item>Unknown Trackers</item>\n        <item>Unknown Trackers</item>\n        <item>Unknown Trackers</item>\n        <item>Unknown Trackers</item>\n        <item>Unknown Trackers</item>\n        <item>Unknown Trackers</item>\n        <item>Unknown Trackers</item>\n        <item>Unknown Trackers</item>\n        <item>Upsight</item>\n        <item>Urbanairship</item>\n        <item>Url Detector</item>\n        <item>Usabilla by Salesforce</item>\n        <item>UsbSerial</item>\n        <item>UsbSerial</item>\n        <item>UsbSerial</item>\n        <item>UsefulViews</item>\n        <item>User Agent Utils</item>\n        <item>UserExperior</item>\n        <item>UserVoice Android SDK</item>\n        <item>Utilities</item>\n        <item>VK SDK for Android</item>\n        <item>VK SDK for Android</item>\n        <item>VKontakte SDK</item>\n        <item>VKontakte SDK</item>\n        <item>VNTNumberPickerPreference</item>\n        <item>VServ</item>\n        <item>VTM</item>\n        <item>VasDolly</item>\n        <item>Vdopia</item>\n        <item>Vdopia</item>\n        <item>Vectaury</item>\n        <item>Vector Icons</item>\n        <item>VectorChildFinder</item>\n        <item>Vectordrawable</item>\n        <item>Veloxity</item>\n        <item>Verint ForeSee</item>\n        <item>Verizon Ads</item>\n        <item>Verizon Ads</item>\n        <item>Verizon Ads</item>\n        <item>Version Compare</item>\n        <item>Vertical Stepper Form Library</item>\n        <item>VerticalSeekBar</item>\n        <item>VerticalViewPager</item>\n        <item>Verve</item>\n        <item>View Binding</item>\n        <item>View Flow for Android</item>\n        <item>ViewBindingPropertyDelegate</item>\n        <item>ViewPager Dots</item>\n        <item>ViewPagerIndicator</item>\n        <item>ViewPagerTransforms</item>\n        <item>ViewPropertyObjectAnimator</item>\n        <item>ViewPump</item>\n        <item>ViewStateStore</item>\n        <item>ViewTooltip</item>\n        <item>Viewpager</item>\n        <item>Virgo Mobile</item>\n        <item>VirtualApp</item>\n        <item>VirtualApp</item>\n        <item>Vivo Push SDK</item>\n        <item>Vodafone NetPerform</item>\n        <item>Volley HTTP library</item>\n        <item>Vosk Speech Recognition Toolkit</item>\n        <item>Vpon</item>\n        <item>Vpon</item>\n        <item>Vpon</item>\n        <item>Vpon</item>\n        <item>Vungle</item>\n        <item>Vungle</item>\n        <item>WCDB</item>\n        <item>WaitingDots</item>\n        <item>WalkMe/Abbi.io</item>\n        <item>WalkMe/Abbi.io</item>\n        <item>WalkMe/Abbi.io</item>\n        <item>WalkMe/Abbi.io</item>\n        <item>WalletConnect</item>\n        <item>Wannads</item>\n        <item>WapStart.Plus1</item>\n        <item>WaveLoadingView</item>\n        <item>WaveLoadingView</item>\n        <item>WeChat Location</item>\n        <item>WeChat Location</item>\n        <item>WeChat Location</item>\n        <item>WeChat Location</item>\n        <item>Web3 Java Ethereum Ðapp API</item>\n        <item>WebIntents plugin for Phonegap</item>\n        <item>WebView for Flutter</item>\n        <item>WebView-GM</item>\n        <item>Webkit</item>\n        <item>Webkit Boundary Interfaces</item>\n        <item>Weborama</item>\n        <item>Webtrekk</item>\n        <item>Webtrends</item>\n        <item>Webtrends</item>\n        <item>Weibo</item>\n        <item>Weibo DeviceID</item>\n        <item>Welcome</item>\n        <item>Westhawk\\'s Java SNMP Stack</item>\n        <item>Weupnp</item>\n        <item>WhatTheStack</item>\n        <item>WheelPicker</item>\n        <item>WheelView-Android</item>\n        <item>Widespace</item>\n        <item>Wire Protocol Buffers</item>\n        <item>WireGuard</item>\n        <item>WireGuard</item>\n        <item>WireGuard</item>\n        <item>WireGuard</item>\n        <item>Wireguard Embedding</item>\n        <item>Wizard Pager</item>\n        <item>WonderPush</item>\n        <item>Woodstox</item>\n        <item>Woopra</item>\n        <item>Woopra SDK for Android</item>\n        <item>Woorlds</item>\n        <item>Wootric</item>\n        <item>WorkManager</item>\n        <item>Workflow</item>\n        <item>Wortise</item>\n        <item>X-Mode</item>\n        <item>X-Mode</item>\n        <item>X-Mode</item>\n        <item>XChange</item>\n        <item>XLog</item>\n        <item>XML Pull</item>\n        <item>XMLBeans</item>\n        <item>XMLBeans</item>\n        <item>XMLUnit</item>\n        <item>XMPCore</item>\n        <item>XMediaNotificationTrackSelector</item>\n        <item>XPermission</item>\n        <item>XPopup</item>\n        <item>XPopup</item>\n        <item>XXPermissions</item>\n        <item>XZ For Java</item>\n        <item>Xamarin</item>\n        <item>Xamarin.Forms</item>\n        <item>Xamarin.Forms</item>\n        <item>Xiaomi Push</item>\n        <item>Xiaomi Push Service</item>\n        <item>Xiaomi Push Service</item>\n        <item>XimpleWare\\'s VTD-XML</item>\n        <item>XposedBridge</item>\n        <item>YCExpandView</item>\n        <item>YOC VIS.X</item>\n        <item>Yahoo!Japan DataShare</item>\n        <item>Yahoo!Japan DataShare</item>\n        <item>Yahoo!Japan DataShare</item>\n        <item>Yahoo!Japan DataShare</item>\n        <item>Yahoo!Japan DataShare</item>\n        <item>Yahoo!Japan DataShare</item>\n        <item>Yahoo!Japan DataShare</item>\n        <item>Yahoo!Japan DataShare</item>\n        <item>YamlBeans</item>\n        <item>Yandex Ad</item>\n        <item>Yandex Disk SDK for Android</item>\n        <item>Yext</item>\n        <item>Yieldlab</item>\n        <item>Yinzcam Sobek</item>\n        <item>Yoadx</item>\n        <item>YotaDevices SDK</item>\n        <item>YouAppi</item>\n        <item>YouTube Analytics Data API</item>\n        <item>YouTube Analytics Data API</item>\n        <item>YouTube Android Player API</item>\n        <item>YouTube Data API</item>\n        <item>Yougoodtech</item>\n        <item>Yougoodtech</item>\n        <item>Youmi</item>\n        <item>YoutubeJExtractor for Android</item>\n        <item>YuMe</item>\n        <item>Yueying Crash SDK</item>\n        <item>Yueying Crash SDK</item>\n        <item>ZBar</item>\n        <item>ZDepthShadowLayout</item>\n        <item>ZIP File System Standalone</item>\n        <item>ZXing (\\'Zebra Crossing\\')</item>\n        <item>ZXing Android Embedded</item>\n        <item>ZXingLite</item>\n        <item>Zapr</item>\n        <item>Zcash Android SDK</item>\n        <item>Zcash Android SDK</item>\n        <item>Zebra</item>\n        <item>Zebra API</item>\n        <item>Zendesk</item>\n        <item>Zendrive</item>\n        <item>Zenjoy</item>\n        <item>Zero Dep Tunnel</item>\n        <item>ZeroTier SDK</item>\n        <item>ZeroTurnaround ZIP Library</item>\n        <item>Zip4j</item>\n        <item>Zoho Analytics</item>\n        <item>ZoomLayout</item>\n        <item>ZoomView</item>\n        <item>Zstd-jni</item>\n        <item>Zucks</item>\n        <item>aFileDialog</item>\n        <item>aLibGlitch</item>\n        <item>aXMLRPC</item>\n        <item>about-page</item>\n        <item>adPOPcorn</item>\n        <item>adPOPcorn</item>\n        <item>adboost</item>\n        <item>amplify</item>\n        <item>andColorPicker</item>\n        <item>android-PullRefreshLayout</item>\n        <item>android-ago</item>\n        <item>android-annotation-lib</item>\n        <item>android-assertion-lib</item>\n        <item>android-betterpickers</item>\n        <item>android-change-log</item>\n        <item>android-code-view</item>\n        <item>android-crop</item>\n        <item>android-dialer</item>\n        <item>android-file-chooser</item>\n        <item>android-filechooser</item>\n        <item>android-gif-drawable</item>\n        <item>android-gogs-client</item>\n        <item>android-identicons</item>\n        <item>android-injection</item>\n        <item>android-issue-reporter</item>\n        <item>android-jsc</item>\n        <item>android-logging-log4j</item>\n        <item>android-multitouch-controller</item>\n        <item>android-process-button</item>\n        <item>android-segmented-control</item>\n        <item>android-speech-diarization</item>\n        <item>android-storage</item>\n        <item>android-storage-devices</item>\n        <item>android-toolbox</item>\n        <item>android-transcoder</item>\n        <item>android-ui</item>\n        <item>android-util</item>\n        <item>android-util</item>\n        <item>android-youtube-player</item>\n        <item>android-youtubeExtractor</item>\n        <item>android-zxingLibrary</item>\n        <item>androidWheelView</item>\n        <item>android_external_themelib</item>\n        <item>androidx.legacy</item>\n        <item>aos-Video</item>\n        <item>aos-Video</item>\n        <item>apache-commons-codec-shaded</item>\n        <item>apk-parser</item>\n        <item>apksig</item>\n        <item>appPlant</item>\n        <item>appTV</item>\n        <item>appgeneration</item>\n        <item>asn-one</item>\n        <item>assets_audio_player</item>\n        <item>async</item>\n        <item>audio-waveform</item>\n        <item>audio_service</item>\n        <item>audio_session</item>\n        <item>autofill_service</item>\n        <item>autolink-java</item>\n        <item>ayeT-Studios</item>\n        <item>background_locator</item>\n        <item>barcodescanner</item>\n        <item>barcodescanner-lib-aar</item>\n        <item>basic-http-client</item>\n        <item>beaconstac/NearBee (MobStac Inc.)</item>\n        <item>betterpickers</item>\n        <item>binance-chain-kit-android</item>\n        <item>biometric_storage</item>\n        <item>bitcoin-lib</item>\n        <item>bitcoin-wallet</item>\n        <item>bitcoinj</item>\n        <item>bitcoinj</item>\n        <item>biweekly</item>\n        <item>bleak</item>\n        <item>brotli</item>\n        <item>brouter</item>\n        <item>btchip-java-api</item>\n        <item>bypasses</item>\n        <item>cache2k Java Caching</item>\n        <item>cache4k</item>\n        <item>cascade</item>\n        <item>cert4android</item>\n        <item>cglib</item>\n        <item>chords</item>\n        <item>chroma</item>\n        <item>circe</item>\n        <item>ckChangeLog</item>\n        <item>cloning library</item>\n        <item>cloudflare-scrape-Android</item>\n        <item>commonmark-java</item>\n        <item>commons-suncalc</item>\n        <item>compose-collapsing-toolbar</item>\n        <item>connectivity</item>\n        <item>cordova-ourcodeworld-filebrowser Plugin</item>\n        <item>cordova-plugin-android-fingerprint-auth</item>\n        <item>cordova-plugin-background-fetch</item>\n        <item>cordova-plugin-browser</item>\n        <item>cordova-plugin-file-opener2</item>\n        <item>cordova-plugin-fingerprint-aio</item>\n        <item>cordova-plugin-foreground-service</item>\n        <item>cordova-plugin-ftp</item>\n        <item>cordova-plugin-intent</item>\n        <item>cordova-plugin-local-notifications</item>\n        <item>cordova-plugin-local-notifications</item>\n        <item>cordova-plugin-native-spinner</item>\n        <item>cordova-plugin-navigationbar-color</item>\n        <item>cordova-plugin-overview</item>\n        <item>cordova-plugin-push-notifications</item>\n        <item>cordova-plugin-qrscanner</item>\n        <item>cordova-plugin-screen-orientation</item>\n        <item>cordova-plugin-snackbar</item>\n        <item>cordova-plugin-websocket</item>\n        <item>cordova-sqlite-storage</item>\n        <item>cordova-support-android-plugin</item>\n        <item>countryboundaries</item>\n        <item>cpdetector</item>\n        <item>croller</item>\n        <item>croller</item>\n        <item>cupboard</item>\n        <item>curve25519-java</item>\n        <item>curvesapi</item>\n        <item>custom bottom sheet</item>\n        <item>cybergarage-upnp</item>\n        <item>cybergarage-upnp</item>\n        <item>cybergarage-upnp</item>\n        <item>cybergarage-upnp</item>\n        <item>cybergarage-upnp</item>\n        <item>cybergarage-upnp</item>\n        <item>darryncampbell-cordova-plugin-intent</item>\n        <item>dav4jvm</item>\n        <item>deltaDNA</item>\n        <item>deploygate</item>\n        <item>device_info</item>\n        <item>device_info_plus</item>\n        <item>dex2jar</item>\n        <item>dexposed</item>\n        <item>dnsjava</item>\n        <item>dnssecjava</item>\n        <item>dom4j</item>\n        <item>dsprofile</item>\n        <item>dynamic_color</item>\n        <item>easyRS</item>\n        <item>eclair</item>\n        <item>edge_detection</item>\n        <item>emoji-java</item>\n        <item>epublib</item>\n        <item>esys_flutter_share</item>\n        <item>exp4j</item>\n        <item>expo-application</item>\n        <item>expo-constants</item>\n        <item>expo-error-recovery</item>\n        <item>expo-file-system</item>\n        <item>expo-font</item>\n        <item>expo-image-loader</item>\n        <item>expo-keep-awake</item>\n        <item>expo-permissions</item>\n        <item>expo-screen-orientation</item>\n        <item>expo-splash-screen</item>\n        <item>expo-sqlite</item>\n        <item>expo-web-browser</item>\n        <item>ext_storage</item>\n        <item>ez-vcard</item>\n        <item>fastjson</item>\n        <item>fineapptech</item>\n        <item>fineapptech</item>\n        <item>fineapptech</item>\n        <item>fineapptech</item>\n        <item>fineboost</item>\n        <item>flexmark-java</item>\n        <item>flutter printing</item>\n        <item>flutter-appbrewery</item>\n        <item>flutter_absolute_path</item>\n        <item>flutter_email_sender</item>\n        <item>flutter_ffmpeg</item>\n        <item>flutter_file_dialog</item>\n        <item>flutter_local_notifications</item>\n        <item>flutter_mailer</item>\n        <item>flutter_native_splash</item>\n        <item>flutter_native_timezone</item>\n        <item>flutter_ringtone_player</item>\n        <item>flutter_secure_storage</item>\n        <item>fluttertoast</item>\n        <item>flymob</item>\n        <item>freej2me</item>\n        <item>froger_mcs</item>\n        <item>frostwire-jlibtorrent</item>\n        <item>ftp4j</item>\n        <item>fullstory</item>\n        <item>fullstory</item>\n        <item>fullstory</item>\n        <item>fullstory</item>\n        <item>fullstory</item>\n        <item>fullstory</item>\n        <item>fyydlin</item>\n        <item>gRPC-Java</item>\n        <item>galimatias</item>\n        <item>gdata-java-client</item>\n        <item>gdx-vfx</item>\n        <item>geocoder</item>\n        <item>github_android_sdk</item>\n        <item>gn_mobile_maps</item>\n        <item>google-analytics-plugin</item>\n        <item>google-diff-match-patch</item>\n        <item>google-java-format</item>\n        <item>gpx-parser</item>\n        <item>graphql-java</item>\n        <item>graphql-java</item>\n        <item>greenDAO</item>\n        <item>greenDAO</item>\n        <item>groupie</item>\n        <item>gson-jodatime-serialisers</item>\n        <item>gst-plugins-bad</item>\n        <item>hCaptcha</item>\n        <item>hk2</item>\n        <item>httpclientandroid</item>\n        <item>httpclientandroidlib</item>\n        <item>i-mobile</item>\n        <item>iCal4j</item>\n        <item>iHarder Base64</item>\n        <item>iText</item>\n        <item>iText 5 Java</item>\n        <item>iText 5 Java</item>\n        <item>ical4android</item>\n        <item>image_native_resizer</item>\n        <item>indeterminate-checkbox</item>\n        <item>ini4j</item>\n        <item>ion</item>\n        <item>iridge popinfo</item>\n        <item>ironSource</item>\n        <item>jBCrypt</item>\n        <item>jFCPlib</item>\n        <item>jISO8601</item>\n        <item>jPastebin</item>\n        <item>jUnit Java Unit Test</item>\n        <item>jackson-coreutils</item>\n        <item>jai-imageio-core</item>\n        <item>java-aes-crypto</item>\n        <item>java-ipfs-http-client</item>\n        <item>java-ipfs-http-client</item>\n        <item>java-ipfs-http-client</item>\n        <item>java-ipfs-http-client</item>\n        <item>java-ipfs-http-client</item>\n        <item>java-libkiwix</item>\n        <item>java-opentimestamps</item>\n        <item>java-string-similarity</item>\n        <item>java-string-similarity</item>\n        <item>java-youtube-downloader</item>\n        <item>jcifs-ng 2.1.1</item>\n        <item>jcifs-ng 2.1.2</item>\n        <item>jcifs-ng 2.1.4</item>\n        <item>jcifs-ng-for-jcifsfile</item>\n        <item>jcodings</item>\n        <item>jffi</item>\n        <item>jmDNS library</item>\n        <item>jnagmp</item>\n        <item>jnr-enxio</item>\n        <item>jnr-ffi</item>\n        <item>jnr-posix</item>\n        <item>jnr-unixsocket</item>\n        <item>jnr-x86asm</item>\n        <item>joda-time-android</item>\n        <item>joni</item>\n        <item>jparsec</item>\n        <item>jsocks</item>\n        <item>json-schema-formats</item>\n        <item>json-schema-validator</item>\n        <item>json-smart-v2</item>\n        <item>json-smart-v2</item>\n        <item>jsonapi-converter</item>\n        <item>jsoup</item>\n        <item>jspoon</item>\n        <item>jtorctl</item>\n        <item>juniversalchardet</item>\n        <item>jurl</item>\n        <item>just_audio</item>\n        <item>jutf7</item>\n        <item>jvm-toxcore-api</item>\n        <item>jvm-toxcore-api</item>\n        <item>jwamp</item>\n        <item>jx</item>\n        <item>k3b-geoHelper</item>\n        <item>k3b-geoHelper</item>\n        <item>k3b-geoHelper</item>\n        <item>k3b-geoHelper library</item>\n        <item>kHttp Android</item>\n        <item>kObjects</item>\n        <item>kaidl</item>\n        <item>kalium</item>\n        <item>kaml</item>\n        <item>keccak</item>\n        <item>keccakj</item>\n        <item>khttp</item>\n        <item>kidsplace_sdk</item>\n        <item>kivy</item>\n        <item>kotlin-csv</item>\n        <item>kotlin-parcelize</item>\n        <item>kotlin-result</item>\n        <item>kotlinx-datetime</item>\n        <item>kotlinx.coroutines</item>\n        <item>kr-scripts</item>\n        <item>kryo-serializers</item>\n        <item>ksoap2-android</item>\n        <item>language-detector</item>\n        <item>last-fm-library</item>\n        <item>launch_review</item>\n        <item>libGDX</item>\n        <item>libRootJava</item>\n        <item>libadblockplus</item>\n        <item>libaums</item>\n        <item>libaxolotl-j2me</item>\n        <item>libdohj library</item>\n        <item>libphonenumber</item>\n        <item>libphonenumber-android</item>\n        <item>librespot-java</item>\n        <item>libselinux-android</item>\n        <item>libsodium-jni</item>\n        <item>libsoftwaresync</item>\n        <item>libsu</item>\n        <item>libsuperuser</item>\n        <item>libwally-core</item>\n        <item>libwebrtc-android</item>\n        <item>local_auth</item>\n        <item>logback-android</item>\n        <item>love-android</item>\n        <item>m3u-parser</item>\n        <item>mCalendarView</item>\n        <item>mParticle</item>\n        <item>mTraction</item>\n        <item>mTraction (mFaaS)</item>\n        <item>maio by i-mobile</item>\n        <item>maps.me Android API</item>\n        <item>material-about-library</item>\n        <item>material-intro</item>\n        <item>material-searchview</item>\n        <item>mediba</item>\n        <item>mediba</item>\n        <item>metadata-extractor</item>\n        <item>microG GmsCore</item>\n        <item>minimal-json</item>\n        <item>mldht</item>\n        <item>mmseg4j</item>\n        <item>money-conversion</item>\n        <item>mongo-java-driver</item>\n        <item>monkeybass</item>\n        <item>moxplatform</item>\n        <item>mp3agic</item>\n        <item>mp4parser</item>\n        <item>mp4parser</item>\n        <item>msg-simple</item>\n        <item>multidexlib2</item>\n        <item>multiline-collapsingtoolbar</item>\n        <item>myTarget</item>\n        <item>myTracker</item>\n        <item>nDPI</item>\n        <item>named-regexp</item>\n        <item>nanojson</item>\n        <item>nativescript-foss-sidedrawer</item>\n        <item>nativescript-imagecropper</item>\n        <item>nativescript-mediafilepicker</item>\n        <item>nativescript-plugin-filepicker</item>\n        <item>nativescript-unit-test-runner</item>\n        <item>nend</item>\n        <item>nend</item>\n        <item>netlib-java</item>\n        <item>netmera</item>\n        <item>network-survey-messaging</item>\n        <item>notils</item>\n        <item>nv-i18n</item>\n        <item>nv-websocket-client</item>\n        <item>okhttp-digest</item>\n        <item>okhttp-signpost</item>\n        <item>onePieceOfCode</item>\n        <item>onion-common</item>\n        <item>onion-common</item>\n        <item>onion-common</item>\n        <item>onion-fec</item>\n        <item>open_file</item>\n        <item>openwig</item>\n        <item>org.w3c.dom</item>\n        <item>ormlite</item>\n        <item>osmapi</item>\n        <item>osmfeatures</item>\n        <item>otr4j</item>\n        <item>overscroll-decor</item>\n        <item>ownCloud Android Library</item>\n        <item>pCloud Java SDK</item>\n        <item>package_info_plus</item>\n        <item>path_provider</item>\n        <item>path_provider_ex</item>\n        <item>pay-me</item>\n        <item>pdf2htmlEX</item>\n        <item>pdfium</item>\n        <item>phonegap-plugin-push</item>\n        <item>pinable</item>\n        <item>pinyin4j-multi-ext</item>\n        <item>pinyin4j-multi-ext</item>\n        <item>play-store-api</item>\n        <item>pollexor</item>\n        <item>predict4java</item>\n        <item>prettytime</item>\n        <item>protoc-gen-zap-java</item>\n        <item>pydroid</item>\n        <item>pyjnius</item>\n        <item>python-for-android</item>\n        <item>quick-chinese-transfer</item>\n        <item>quick_actions</item>\n        <item>re.pack</item>\n        <item>react-native EventSource</item>\n        <item>react-native-actions-shortcuts</item>\n        <item>react-native-background-actions</item>\n        <item>react-native-background-fetch</item>\n        <item>react-native-background-job</item>\n        <item>react-native-background-task</item>\n        <item>react-native-barcode-scanner-google</item>\n        <item>react-native-bars</item>\n        <item>react-native-bluetooth-status</item>\n        <item>react-native-bootsplash</item>\n        <item>react-native-bottom-sheet</item>\n        <item>react-native-config</item>\n        <item>react-native-cookies</item>\n        <item>react-native-default-preference</item>\n        <item>react-native-device-info</item>\n        <item>react-native-document-picker</item>\n        <item>react-native-dominant-color</item>\n        <item>react-native-exception-handler</item>\n        <item>react-native-exit-app</item>\n        <item>react-native-fabric</item>\n        <item>react-native-fcm</item>\n        <item>react-native-fetch-blob</item>\n        <item>react-native-file-access</item>\n        <item>react-native-file-viewer</item>\n        <item>react-native-flag-secure-android</item>\n        <item>react-native-fs</item>\n        <item>react-native-google-place-picker</item>\n        <item>react-native-html-to-pdf-lite</item>\n        <item>react-native-i18n</item>\n        <item>react-native-iap</item>\n        <item>react-native-image-base64</item>\n        <item>react-native-image-crop-picker</item>\n        <item>react-native-immersive</item>\n        <item>react-native-keep-awake</item>\n        <item>react-native-keychain</item>\n        <item>react-native-linear-gradient</item>\n        <item>react-native-local-auth</item>\n        <item>react-native-localize</item>\n        <item>react-native-mail</item>\n        <item>react-native-mmkv-storage</item>\n        <item>react-native-music-control</item>\n        <item>react-native-nfc-manager</item>\n        <item>react-native-overlay</item>\n        <item>react-native-photo-view</item>\n        <item>react-native-recyclerview-list</item>\n        <item>react-native-rsa-native</item>\n        <item>react-native-safe-area-context</item>\n        <item>react-native-scoped-storage</item>\n        <item>react-native-screens</item>\n        <item>react-native-securerandom</item>\n        <item>react-native-securerandom</item>\n        <item>react-native-selectable-text</item>\n        <item>react-native-share</item>\n        <item>react-native-smart-splash-screen</item>\n        <item>react-native-sodium</item>\n        <item>react-native-sound</item>\n        <item>react-native-sound-player</item>\n        <item>react-native-spinkit</item>\n        <item>react-native-splash-screen</item>\n        <item>react-native-svg</item>\n        <item>react-native-text-input-reset</item>\n        <item>react-native-unimodules</item>\n        <item>react-native-version-number</item>\n        <item>react-native-video</item>\n        <item>react-native-video</item>\n        <item>react-native-webrtc</item>\n        <item>react-native-youtube</item>\n        <item>renjin</item>\n        <item>requery</item>\n        <item>restafari</item>\n        <item>retrofit RESTful Library</item>\n        <item>rfc5545-datetime</item>\n        <item>rtmp-rtsp-stream-client-java</item>\n        <item>rtmp-rtsp-stream-client-java</item>\n        <item>rtmp-rtsp-stream-client-java</item>\n        <item>rtmp-rtsp-stream-client-java</item>\n        <item>rtmp-rtsp-stream-client-java</item>\n        <item>rx-utils</item>\n        <item>rxlint</item>\n        <item>sCommon</item>\n        <item>sTooltip</item>\n        <item>sanukin</item>\n        <item>sardine-android</item>\n        <item>sbt-scalapb-plugin</item>\n        <item>scala-logging</item>\n        <item>scodec-bits</item>\n        <item>scorex-util</item>\n        <item>sequence-layout</item>\n        <item>sha</item>\n        <item>sha</item>\n        <item>shapeless</item>\n        <item>share_plus</item>\n        <item>shared_preferences</item>\n        <item>signal-cli</item>\n        <item>signal-service-java</item>\n        <item>simple-chrome-custom-tabs</item>\n        <item>simple-tls</item>\n        <item>sisu-build-api</item>\n        <item>slf4j-android</item>\n        <item>slf4j-android-logger</item>\n        <item>slf4j-timber</item>\n        <item>smali/baksmali</item>\n        <item>smali/baksmali</item>\n        <item>smali/baksmali</item>\n        <item>smali/baksmali</item>\n        <item>snappy-java</item>\n        <item>sonic-ndk</item>\n        <item>sora-editor</item>\n        <item>sphlib</item>\n        <item>sqflite</item>\n        <item>sqlite3-native-library</item>\n        <item>sqlite3.dart</item>\n        <item>sshj</item>\n        <item>stellar-java-mnemonic</item>\n        <item>sticky-headers-recyclerview</item>\n        <item>stock-chart</item>\n        <item>svdrp4j</item>\n        <item>svg android</item>\n        <item>swipe</item>\n        <item>swipe</item>\n        <item>swipe-to-dismiss-undo</item>\n        <item>tAdapter</item>\n        <item>tabtale</item>\n        <item>taskwarrior-java-client</item>\n        <item>telemetry-android</item>\n        <item>thetvdb-java</item>\n        <item>timessquare</item>\n        <item>tinylog 2</item>\n        <item>tmdb-java</item>\n        <item>toml4j</item>\n        <item>toolbar-android</item>\n        <item>toybox</item>\n        <item>tracedroid</item>\n        <item>trakt-java</item>\n        <item>tree-view-list-android</item>\n        <item>twitter-text</item>\n        <item>uCrop</item>\n        <item>unbescape</item>\n        <item>underscore-java</item>\n        <item>upnplibmobile</item>\n        <item>uri-template</item>\n        <item>url_launcher</item>\n        <item>usb-serial-for-android</item>\n        <item>vavi-sound</item>\n        <item>vavi-sound</item>\n        <item>vcard4android</item>\n        <item>vector-compat</item>\n        <item>video_player</item>\n        <item>vinnie</item>\n        <item>vlc-android-sdk</item>\n        <item>wallet-connect-kotlin</item>\n        <item>wc_flutter_share</item>\n        <item>webrtc-android</item>\n        <item>williamchart</item>\n        <item>williamchart</item>\n        <item>wvWare</item>\n        <item>xrates-kit-android</item>\n        <item>yuku-android-util</item>\n        <item>yuku-android-util</item>\n        <item>yuku-android-util</item>\n        <item>yuku-android-util</item>\n        <item>yuku-android-util</item>\n        <item>zBarLibrary</item>\n        <item>zebra-print-android</item>\n        <item>zip-signer</item>\n        <item>zxcvbn4j</item>\n        <item>Λrrow</item>\n        <item>Λrrow</item>\n    </array>\n    <array name=\"lib_types\">\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Map</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Advertisement</item>\n        <item>Utility</item>\n        <item>Development Framework</item>\n        <item>Development Framework</item>\n        <item>Development Framework</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Development Framework</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>UI Component</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Development Framework</item>\n        <item>Advertisement</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Development Framework</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Social Network</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Advertisement</item>\n        <item>Mobile Analytics</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Mobile Analytics</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Mobile Analytics</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Utility</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Advertisement</item>\n        <item>Payment</item>\n        <item>Advertisement</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Mobile Analytics</item>\n        <item>Advertisement</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Mobile Analytics</item>\n        <item>Payment</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>UI Component</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Advertisement</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Advertisement</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Payment</item>\n        <item>Mobile Analytics</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>UI Component</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Development Aid</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Payment</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Payment</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Development Aid</item>\n        <item>Utility</item>\n        <item>App Market</item>\n        <item>App Market</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Development Framework</item>\n        <item>Development Framework</item>\n        <item>Development Framework</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Development Framework</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Payment</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Development Framework</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Development Framework</item>\n        <item>Advertisement</item>\n        <item>Map</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Utility</item>\n        <item>Development Framework</item>\n        <item>Development Framework</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Development Aid</item>\n        <item>Development Aid</item>\n        <item>Development Aid</item>\n        <item>Development Aid</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Advertisement</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Advertisement</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Advertisement</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Development Framework</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Advertisement</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Advertisement</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Advertisement</item>\n        <item>Mobile Analytics</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Advertisement</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Development Aid</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Development Framework</item>\n        <item>Development Framework</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Advertisement</item>\n        <item>Mobile Analytics</item>\n        <item>Map</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Map</item>\n        <item>Advertisement</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Payment</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Advertisement</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Development Aid</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Payment</item>\n        <item>Mobile Analytics</item>\n        <item>Advertisement</item>\n        <item>Mobile Analytics</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>UI Component</item>\n        <item>Advertisement</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Advertisement</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Advertisement</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Advertisement</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Map</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Advertisement</item>\n        <item>UI Component</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Payment</item>\n        <item>Advertisement</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Advertisement</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Game Engine</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Development Aid</item>\n        <item>Advertisement</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Development Framework</item>\n        <item>Development Framework</item>\n        <item>Development Framework</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>UI Component</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>UI Component</item>\n        <item>Mobile Analytics</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Social Network</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Advertisement</item>\n        <item>Mobile Analytics</item>\n        <item>Development Aid</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Game Engine</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>UI Component</item>\n        <item>Development Aid</item>\n        <item>Development Aid</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Advertisement</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Advertisement</item>\n        <item>Utility</item>\n        <item>Development Aid</item>\n        <item>Utility</item>\n        <item>Development Aid</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Advertisement</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Development Aid</item>\n        <item>Advertisement</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Mobile Analytics</item>\n        <item>Development Aid</item>\n        <item>Utility</item>\n        <item>Advertisement</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Development Aid</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Development Framework</item>\n        <item>Mobile Analytics</item>\n        <item>UI Component</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Development Aid</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Development Aid</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Development Framework</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Advertisement</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Development Framework</item>\n        <item>Advertisement</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Advertisement</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Social Network</item>\n        <item>Social Network</item>\n        <item>Social Network</item>\n        <item>Social Network</item>\n        <item>Social Network</item>\n        <item>Social Network</item>\n        <item>Social Network</item>\n        <item>Social Network</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Advertisement</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Development Aid</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Development Aid</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Utility</item>\n        <item>Development Framework</item>\n        <item>Development Framework</item>\n        <item>Development Framework</item>\n        <item>Development Framework</item>\n        <item>Development Framework</item>\n        <item>Development Framework</item>\n        <item>Development Framework</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Advertisement</item>\n        <item>Development Aid</item>\n        <item>Development Aid</item>\n        <item>Development Aid</item>\n        <item>Development Aid</item>\n        <item>Development Aid</item>\n        <item>Development Aid</item>\n        <item>Development Aid</item>\n        <item>Development Aid</item>\n        <item>Development Aid</item>\n        <item>Development Aid</item>\n        <item>Development Aid</item>\n        <item>Development Aid</item>\n        <item>Development Aid</item>\n        <item>Development Aid</item>\n        <item>Development Aid</item>\n        <item>Development Aid</item>\n        <item>Development Aid</item>\n        <item>Development Aid</item>\n        <item>Development Aid</item>\n        <item>Development Aid</item>\n        <item>Development Aid</item>\n        <item>Development Aid</item>\n        <item>Development Aid</item>\n        <item>Development Aid</item>\n        <item>Development Aid</item>\n        <item>Development Aid</item>\n        <item>Development Aid</item>\n        <item>Development Aid</item>\n        <item>Development Aid</item>\n        <item>Development Aid</item>\n        <item>Development Aid</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Utility</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Advertisement</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Advertisement</item>\n        <item>Development Framework</item>\n        <item>Map</item>\n        <item>Map</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Development Aid</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Development Framework</item>\n        <item>Development Framework</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Map</item>\n        <item>Map</item>\n        <item>Map</item>\n        <item>Utility</item>\n        <item>Development Framework</item>\n        <item>Development Framework</item>\n        <item>Development Framework</item>\n        <item>App Market</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>App Market</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Mobile Analytics</item>\n        <item>Advertisement</item>\n        <item>Utility</item>\n        <item>Advertisement</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Payment</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Advertisement</item>\n        <item>Mobile Analytics</item>\n        <item>Advertisement</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>App Market</item>\n        <item>Utility</item>\n        <item>Development Framework</item>\n        <item>Development Framework</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Payment</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Advertisement</item>\n        <item>Utility</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Development Aid</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Utility</item>\n        <item>Development Aid</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Advertisement</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Advertisement</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Advertisement</item>\n        <item>Utility</item>\n        <item>Development Aid</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Development Framework</item>\n        <item>Development Framework</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Development Aid</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Development Framework</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Development Aid</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Development Framework</item>\n        <item>Development Framework</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Advertisement</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Advertisement</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Advertisement</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Advertisement</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Advertisement</item>\n        <item>Utility</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Advertisement</item>\n        <item>UI Component</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Development Aid</item>\n        <item>Development Framework</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Development Aid</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Development Framework</item>\n        <item>Utility</item>\n        <item>Development Aid</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Development Aid</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Advertisement</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Mobile Analytics</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Development Framework</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Advertisement</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Development Framework</item>\n        <item>Development Aid</item>\n        <item>Utility</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Mobile Analytics</item>\n        <item>Development Framework</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Advertisement</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Map</item>\n        <item>Map</item>\n        <item>Mobile Analytics</item>\n        <item>Map</item>\n        <item>Map</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Development Aid</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Development Framework</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Advertisement</item>\n        <item>Mobile Analytics</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Development Framework</item>\n        <item>Utility</item>\n        <item>Map</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Mobile Analytics</item>\n        <item>Payment</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Mobile Analytics</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Development Framework</item>\n        <item>Mobile Analytics</item>\n        <item>Advertisement</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Advertisement</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Development Aid</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Advertisement</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Advertisement</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Development Framework</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Advertisement</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Advertisement</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Advertisement</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Development Framework</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Development Framework</item>\n        <item>Advertisement</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Development Framework</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Map</item>\n        <item>Map</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Utility</item>\n        <item>Map</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Advertisement</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Advertisement</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Payment</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Development Framework</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Development Framework</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Advertisement</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Development Aid</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>UI Component</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>UI Component</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Map</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>UI Component</item>\n        <item>Game Engine</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Advertisement</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Advertisement</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Mobile Analytics</item>\n        <item>Development Aid</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Advertisement</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Development Aid</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Advertisement</item>\n        <item>UI Component</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Development Aid</item>\n        <item>Development Aid</item>\n        <item>Development Aid</item>\n        <item>Development Aid</item>\n        <item>Development Aid</item>\n        <item>Development Aid</item>\n        <item>Development Aid</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Advertisement</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Development Aid</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Advertisement</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Development Framework</item>\n        <item>Development Framework</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Mobile Analytics</item>\n        <item>UI Component</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Payment</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Development Aid</item>\n        <item>Development Aid</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Advertisement</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Development Framework</item>\n        <item>Development Framework</item>\n        <item>Development Framework</item>\n        <item>Development Framework</item>\n        <item>Development Framework</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Development Framework</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Development Aid</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Payment</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Development Aid</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Advertisement</item>\n        <item>UI Component</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Development Aid</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>UI Component</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Advertisement</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Social Network</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Advertisement</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Advertisement</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Development Framework</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Development Framework</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Development Aid</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Advertisement</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Payment</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Mobile Analytics</item>\n        <item>UI Component</item>\n        <item>Mobile Analytics</item>\n        <item>Advertisement</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Advertisement</item>\n        <item>Mobile Analytics</item>\n        <item>Advertisement</item>\n        <item>Utility</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>UI Component</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Mobile Analytics</item>\n        <item>Map</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>UI Component</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Map</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Advertisement</item>\n        <item>Mobile Analytics</item>\n        <item>Development Framework</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Map</item>\n        <item>Map</item>\n        <item>Map</item>\n        <item>Advertisement</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Advertisement</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Social Network</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Map</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Advertisement</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Development Aid</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Advertisement</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Advertisement</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Advertisement</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Utility</item>\n        <item>Development Aid</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Social Network</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Social Network</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>UI Component</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Payment</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Advertisement</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Social Network</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>UI Component</item>\n        <item>Mobile Analytics</item>\n        <item>Map</item>\n        <item>Utility</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Advertisement</item>\n        <item>Mobile Analytics</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Advertisement</item>\n        <item>Development Aid</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Advertisement</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Utility</item>\n        <item>Advertisement</item>\n        <item>Mobile Analytics</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Social Network</item>\n        <item>Mobile Analytics</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Advertisement</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Development Framework</item>\n        <item>Development Framework</item>\n        <item>Development Framework</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Advertisement</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Advertisement</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Advertisement</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Advertisement</item>\n        <item>Development Framework</item>\n        <item>Development Framework</item>\n        <item>Utility</item>\n        <item>Development Framework</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Advertisement</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Development Aid</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Development Aid</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Advertisement</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Development Aid</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Advertisement</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Map</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Development Aid</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Map</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Advertisement</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Advertisement</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Development Aid</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Development Aid</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Development Aid</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Development Aid</item>\n        <item>Development Aid</item>\n        <item>Development Aid</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Development Framework</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Game Engine</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Development Framework</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Mobile Analytics</item>\n        <item>Map</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Utility</item>\n        <item>Development Framework</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Advertisement</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Advertisement</item>\n        <item>Advertisement</item>\n        <item>Utility</item>\n        <item>Mobile Analytics</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Map</item>\n        <item>Map</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Payment</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Advertisement</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>App Market</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Payment</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Development Aid</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Development Aid</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Development Aid</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Development Aid</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Advertisement</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>UI Component</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Utility</item>\n        <item>Development Aid</item>\n        <item>Development Aid</item>\n    </array>\n    <array name=\"lib_website\">\n        <item>https://www.360dialog.com</item>\n        <item>https://www.39geopla.net/</item>\n        <item>https://3bitter.com/</item>\n        <item>https://github.com/4thline/seamless</item>\n        <item>http://sevenzipjbind.sourceforge.net/</item>\n        <item>https://developer.7moor.com/Android_sdk_2/</item>\n        <item>https://developer.7moor.com/Android_sdk_2/</item>\n        <item>https://github.com/jecelyin/920-text-editor-v2</item>\n        <item>https://github.com/jecelyin/920-text-editor-v2</item>\n        <item>https://github.com/jecelyin/920-text-editor-v2</item>\n        <item>https://github.com/react-native-checkbox/react-native-checkbox</item>\n        <item>https://github.com/react-native-clipboard/clipboard</item>\n        <item>https://github.com/react-native-community/react-native-geolocation</item>\n        <item>https://github.com/react-native-community/react-native-netinfo</item>\n        <item>https://github.com/react-native-community/react-native-slider</item>\n        <item>https://www.abtasty.com</item>\n        <item>https://www.acra.ch/</item>\n        <item>https://www.acra.ch/</item>\n        <item>https://acrcloud.com/</item>\n        <item>http://www.achartengine.org/</item>\n        <item>https://adxcorp.kr/</item>\n        <item>https://adxcorp.kr/</item>\n        <item>https://adlibr.com</item>\n        <item>http://adop.cc/</item>\n        <item>https://admanmedia.com/</item>\n        <item>https://github.com/signalapp/AES-GCM-Provider</item>\n        <item>https://github.com/scottyab/AESCrypt-Android</item>\n        <item>https://github.com/aurelhubert/ahbottomnavigation</item>\n        <item>https://github.com/amirzaidi/AIDLBridge</item>\n        <item>https://docs.aihelp.net/</item>\n        <item>https://docs.aihelp.net/</item>\n        <item>https://www.amoad.com</item>\n        <item>https://github.com/SalomonBrys/ANR-WatchDog</item>\n        <item>https://github.com/ant-wireless/ANT-Android-SDKs</item>\n        <item>http://www.antlr2.org/</item>\n        <item>http://www.antlr2.org/</item>\n        <item>https://sourceforge.net/projects/aopalliance/</item>\n        <item>https://github.com/googleapis/api-common-java</item>\n        <item>https://www.apicloud.com/</item>\n        <item>https://github.com/penfeizhou/APNG4Android</item>\n        <item>https://github.com/alibaba/ARouter</item>\n        <item>http://asm.ow2.org/</item>\n        <item>https://github.com/SignalR/SignalR</item>\n        <item>https://www.atinternet.com/en/</item>\n        <item>https://github.com/81813780/AVLoadingIndicatorView</item>\n        <item>https://github.com/aws-amplify/aws-sdk-android</item>\n        <item>https://aws.amazon.com/de/kinesis/</item>\n        <item>https://aws.amazon.com/de/kinesis/</item>\n        <item>https://github.com/aws/aws-sdk-java</item>\n        <item>https://www.aarki.com</item>\n        <item>https://github.com/victorhaggqvist/AboutIt</item>\n        <item>https://github.com/mikepenz/AboutLibraries</item>\n        <item>https://github.com/AriaLyy/MVVM</item>\n        <item>https://github.com/zhaobozhen/libraries</item>\n        <item>https://github.com/mariotaku/AbstractTask</item>\n        <item>https://github.com/accelforce/AccelForceEaster</item>\n        <item>https://github.com/google/accompanist</item>\n        <item>https://www.accountkit.com/</item>\n        <item>https://github.com/F43nd1r/Acrarium</item>\n        <item>https://github.com/ricardoalcocer/actionbarextras</item>\n        <item>https://github.com/JakeWharton/ActionBarSherlock</item>\n        <item>https://github.com/pardom/ActiveAndroid</item>\n        <item>https://github.com/frogermcs/ActivityFrameMetrics</item>\n        <item>https://github.com/DylanCaiCoding/ActivityResultLauncher</item>\n        <item>https://github.com/milosmns/actual-number-picker</item>\n        <item>https://www.actv8me.com/</item>\n        <item>https://www.acuantcorp.com</item>\n        <item>https://supership.jp/business/adgeneration/</item>\n        <item>https://www.ad2iction.com/</item>\n        <item>https://ad4game.com</item>\n        <item>http://www.ad4screen.com/</item>\n        <item>https://www.adadapted.com</item>\n        <item>http://www.adbuddiz.com/abuse\\?hl=fr</item>\n        <item>http://adcolony.com/</item>\n        <item>http://adcolony.com/</item>\n        <item>http://adfalcon.com</item>\n        <item>https://www.daum.net</item>\n        <item>https://adflex.asia</item>\n        <item>https://site.adform.com/</item>\n        <item>https://adgatemedia.com/</item>\n        <item>https://adgem.com/</item>\n        <item>https://adlocus.com</item>\n        <item>https://www.crunchbase.com/organization/admarvel</item>\n        <item>https://github.com/floatinghotpot/cordova-admob-pro</item>\n        <item>https://github.com/floatinghotpot/cordova-admob-pro</item>\n        <item>https://github.com/admuing</item>\n        <item>https://www.ad-tech.vn/en/sdk/</item>\n        <item>https://adtheorent.com</item>\n        <item>https://www.adtiming.com/</item>\n        <item>https://www.adtiming.com/</item>\n        <item>https://adtrial.com/</item>\n        <item>https://www.adview.com/</item>\n        <item>http://www.adwhirl.com</item>\n        <item>https://github.com/sockeqwe/AdapterDelegates</item>\n        <item>https://github.com/microsoft/AdaptiveCards</item>\n        <item>https://github.com/fennifith/AdaptiveIconView</item>\n        <item>https://github.com/fartem/adaptive-recycler-view</item>\n        <item>http://ad-brix.com/</item>\n        <item>https://adcash.com</item>\n        <item>http://adcenix.com</item>\n        <item>http://adchina.io</item>\n        <item>https://www.addapptr.com</item>\n        <item>http://www.made-apps.com/</item>\n        <item>https://adfurikun.jp/adfurikun/</item>\n        <item>https://adfurikun.jp/adfurikun/</item>\n        <item>https://github.com/batoulapps/adhan-java</item>\n        <item>https://www.adincube.com/</item>\n        <item>https://adjoe.io/</item>\n        <item>https://adjoe.io/</item>\n        <item>https://www.adjust.com/</item>\n        <item>https://www.adjust.com/</item>\n        <item>https://github.com/adjust/android_sdk</item>\n        <item>https://www.adjust.com/product/unbotify/</item>\n        <item>https://www.admitad.com</item>\n        <item>http://admixer.co.kr/</item>\n        <item>http://admixer.co.kr/</item>\n        <item>https://admost.com/</item>\n        <item>https://admost.com/</item>\n        <item>https://www.adobe.com/experience-cloud.html</item>\n        <item>https://we-are-adot.com/</item>\n        <item>http://www.adswizz.com/</item>\n        <item>http://adscendmedia.com/</item>\n        <item>http://adscendmedia.com/</item>\n        <item>https://github.com/h6ah4i/android-advancedrecyclerview</item>\n        <item>https://github.com/delight-im/Android-AdvancedWebView</item>\n        <item>https://advangelists.com/</item>\n        <item>https://github.com/Adyen/adyen-android</item>\n        <item>https://www.aerserv.com/</item>\n        <item>https://github.com/afollestad/aesthetic</item>\n        <item>https://github.com/Justson/AgentWeb</item>\n        <item>https://www.agoop.co.jp/</item>\n        <item>https://www.agora.io/en/products/agora-analytics/</item>\n        <item>https://www.agora.io/en/products/agora-analytics/</item>\n        <item>https://github.com/robert-bor/aho-corasick</item>\n        <item>https://lab.secure-d.io/com-aitype-android/</item>\n        <item>https://lab.secure-d.io/com-aitype-android/</item>\n        <item>https://lab.secure-d.io/com-aitype-android/</item>\n        <item>https://lab.secure-d.io/com-aitype-android/</item>\n        <item>https://airbridge.io/</item>\n        <item>https://airpush.com/</item>\n        <item>https://www.akamai.com/</item>\n        <item>https://github.com/Tapadoo/Alerter</item>\n        <item>https://github.com/algolia/algoliasearch-client-java-2</item>\n        <item>https://doc.svr-algorix.com/</item>\n        <item>https://doc.svr-algorix.com/</item>\n        <item>https://doc.svr-algorix.com/</item>\n        <item>https://www.alibabacloud.com/product/message-service</item>\n        <item>https://cn.aliyun.com/product/httpdns</item>\n        <item>https://alibabatech.medium.com/does-your-mobile-say-a-lot-about-you-it-should-and-heres-why-a70b63bf95eb</item>\n        <item>https://www.alibaba.com/</item>\n        <item>https://www.alibaba.com/</item>\n        <item>https://www.alibaba.com/</item>\n        <item>https://www.alibaba.com/</item>\n        <item>https://www.alibaba.com/</item>\n        <item>https://www.alibaba.com/</item>\n        <item>https://www.alibaba.com/</item>\n        <item>https://www.alibaba.com/</item>\n        <item>https://www.alimama.com/</item>\n        <item>https://www.alimama.com/</item>\n        <item>https://global.alipay.com/docs/ac/alipaysdks/sdks</item>\n        <item>https://github.com/fython/AlipayZeroSdk</item>\n        <item>https://github.com/biodranik/Alohalytics</item>\n        <item>https://www.alooma.com</item>\n        <item>https://github.com/myinnos/AlphabetIndex-Fast-Scroll-RecyclerView</item>\n        <item>http://alphonso.tv/</item>\n        <item>https://altbeacon.org</item>\n        <item>https://altbeacon.org</item>\n        <item>https://altbeacon.org</item>\n        <item>https://www.altamob.com/en/index.html</item>\n        <item>https://lbs.amap.com/api/android-location-sdk/locationsummary</item>\n        <item>http://mvnrepository.com/artifact/com.amazonaws</item>\n        <item>http://mvnrepository.com/artifact/com.amazonaws</item>\n        <item>http://mvnrepository.com/artifact/com.amazonaws</item>\n        <item>http://mvnrepository.com/artifact/com.amazonaws</item>\n        <item>http://mvnrepository.com/artifact/com.amazonaws</item>\n        <item>https://github.com/aws-amplify/aws-sdk-android</item>\n        <item>https://developer.amazon.com/public/apis/earn/mobile-ads/docs/quick-start</item>\n        <item>https://developer.amazon.com/public/apis/manage/analytics/docs/analytics-for-android-fire-os</item>\n        <item>https://developer.amazon.com/docs/apps-and-games/sdk-downloads.html</item>\n        <item>https://developer.amazon.com/docs/apps-and-games/sdk-downloads.html</item>\n        <item>https://developer.amazon.com/docs/apps-and-games/sdk-downloads.html</item>\n        <item>https://developer.amazon.com/de/in-app-purchasing</item>\n        <item>https://aws.amazon.com/amplify/</item>\n        <item>https://developer.amazon.com/mobile-associates</item>\n        <item>https://amberweather.com/</item>\n        <item>https://github.com/yukuku/ambilwarna</item>\n        <item>https://amobee.com</item>\n        <item>https://github.com/amplitude/Amplitude-Android</item>\n        <item>https://anagog.com</item>\n        <item>https://nicepeopleatwork.com/</item>\n        <item>https://github.com/iamutkarshtiwari/Ananas</item>\n        <item>https://github.com/yanzhenjie/AndPermission</item>\n        <item>https://github.com/yanzhenjie/AndServer</item>\n        <item>https://github.com/klinker24/Android-3DTouch-PeekView</item>\n        <item>https://github.com/medyo/android-about-page</item>\n        <item>https://developer.android.com/jetpack/androidx</item>\n        <item>https://github.com/johnkil/Android-AppMsg</item>\n        <item>https://github.com/klinker41/article-android</item>\n        <item>http://loopj.com/android-async-http/</item>\n        <item>https://github.com/blandware/android-atleap</item>\n        <item>https://github.com/NordicSemiconductor/Android-BLE-Library</item>\n        <item>https://github.com/AltBeacon/android-beacon-library</item>\n        <item>https://github.com/GoogleChrome/android-browser-helper</item>\n        <item>https://github.com/abdularis/CircularImageView</item>\n        <item>https://github.com/dmytrodanylyk/circular-progress-button</item>\n        <item>https://github.com/JordanRobinson/android-color-picker</item>\n        <item>https://github.com/googlearchive/android-CommitContentSampleIME</item>\n        <item>https://github.com/alexvasilkov/AndroidCommons</item>\n        <item>https://github.com/saschpe/android-customtabs</item>\n        <item>https://github.com/robingenz/capacitor-android-dark-mode-support</item>\n        <item>https://github.com/infinum/android_dbinspector</item>\n        <item>https://github.com/palaima/DebugDrawer</item>\n        <item>https://developer.android.com/training/material/design-library.html</item>\n        <item>https://github.com/jaredrummler/AndroidDeviceNames</item>\n        <item>https://github.com/tslamic/AndroidDeviceNames</item>\n        <item>https://github.com/tslamic/AndroidDeviceNames</item>\n        <item>https://github.com/passy/Android-DirectoryChooser</item>\n        <item>https://github.com/demantz/android-donations-lib</item>\n        <item>https://github.com/daimajia/AnimationEasingFunctions</item>\n        <item>https://github.com/qinci/AndroidEdit</item>\n        <item>https://android.googlesource.com/platform/frameworks/support/+/refs/heads/androidx-main/emoji2/</item>\n        <item>https://github.com/JorgeCastilloPrz/AndroidFillableLoaders</item>\n        <item>https://github.com/Angtrim/Android-Five-Stars-Library</item>\n        <item>https://github.com/ticofab/android-gpx-parser</item>\n        <item>https://github.com/cocoahero/android-geojson</item>\n        <item>https://github.com/Almeros/android-gesture-detectors</item>\n        <item>https://github.com/LarsWerkman/HoloColorPicker</item>\n        <item>https://github.com/ArthurHub/Android-Image-Cropper</item>\n        <item>https://github.com/daimajia/AndroidImageSlider</item>\n        <item>https://github.com/anjlab/android-inapp-billing-v3</item>\n        <item>https://github.com/rbro112/Android-Indefinite-Pager-Indicator</item>\n        <item>https://developer.android.com/studio/run/index.html#instant-run</item>\n        <item>https://android.googlesource.com/platform/frameworks/base/+/HEAD/core/java/com/android/internal/</item>\n        <item>https://developer.android.com/jetpack/androidx/releases/annotation</item>\n        <item>https://developer.android.com/jetpack/androidx/releases/versionedparcelable</item>\n        <item>https://android.googlesource.com/platform/packages/apps/Launcher3/</item>\n        <item>https://android.googlesource.com/platform/packages/apps/Launcher3/</item>\n        <item>https://developer.android.com/jetpack/androidx/releases/hilt</item>\n        <item>https://github.com/LeffelMania/android-midi-lib</item>\n        <item></item>\n        <item>https://code.google.com/archive/p/android-market-api/</item>\n        <item>https://github.com/Pes8/android-material-color-picker-dialog</item>\n        <item>https://github.com/TangoAgency/material-intro-screen</item>\n        <item>https://github.com/stepstone-tech/android-material-stepper</item>\n        <item>https://developer.android.com/jetpack/androidx/releases/multidex</item>\n        <item>https://github.com/vic797/android_native_code_view</item>\n        <item>https://github.com/vic797/android_native_code_view</item>\n        <item>https://github.com/stealthcopter/AndroidNetworkTools</item>\n        <item>https://github.com/SimonVT/android-numberpicker</item>\n        <item>https://github.com/daimajia/NumberProgressBar</item>\n        <item>https://github.com/wuman/android-oauth-client</item>\n        <item>https://github.com/ionull/objectify</item>\n        <item>https://github.com/chyrta/AndroidOnboarder</item>\n        <item>https://developer.android.com/reference/android/content/pm/PackageManager.html</item>\n        <item>https://github.com/astuetz/PagerSlidingTabStrip</item>\n        <item>https://github.com/barteksc/AndroidPdfViewer</item>\n        <item>https://github.com/KieronQuinn/PersistentSearch</item>\n        <item>https://github.com/KieronQuinn/PersistentSearch</item>\n        <item>https://github.com/moxie0/AndroidPinning</item>\n        <item>https://github.com/yigit/android-priority-jobqueue</item>\n        <item>https://github.com/path/android-priority-jobqueue</item>\n        <item>https://github.com/shouldit/android-proxy</item>\n        <item>https://github.com/lorensiuswlt/NewQuickAction</item>\n        <item>https://github.com/EOSIO/eosio-java-android-rpc-provider</item>\n        <item>https://github.com/lzyzsd/AndroidRandomColor</item>\n        <item>https://github.com/Shusshu/Android-RecurrencePicker</item>\n        <item>https://github.com/SpazeDog/rootfw</item>\n        <item>https://github.com/SpazeDog/rootfw</item>\n        <item>https://github.com/NativeScript/android-runtime</item>\n        <item>https://github.com/NativeScript/android-runtime</item>\n        <item>https://github.com/NativeScript/android-runtime</item>\n        <item>https://github.com/klinker41/android-smsmms</item>\n        <item>https://github.com/requery/sqlite-android</item>\n        <item>https://github.com/jgilfelt/android-sqlite-asset-helper</item>\n        <item>https://github.com/jgilfelt/android-sqlite-asset-helper</item>\n        <item>https://github.com/jaredrummler/AndroidShell</item>\n        <item>https://github.com/gcacace/android-signaturepad</item>\n        <item>https://github.com/douglasjunior/android-simple-tooltip</item>\n        <item>https://github.com/klinker24/Android-SimpleVideoView</item>\n        <item>https://github.com/klinker41/android-slidingactivity</item>\n        <item>https://github.com/umano/AndroidSlidingUpPanel</item>\n        <item>http://loopj.com/android-smart-image-view/</item>\n        <item>https://github.com/Muddz/StyleableToast</item>\n        <item>https://android.googlesource.com/platform/frameworks/support/+/refs/heads/androidx-main/customview/</item>\n        <item>https://developer.android.com/tools/extras/support-library.html</item>\n        <item>https://developer.android.com/jetpack/androidx/releases/tvprovider</item>\n        <item>https://developer.android.com/reference/android/support/v13/app/package-summary.html</item>\n        <item>https://developer.android.com/reference/android/support/v4/app/package-summary.html</item>\n        <item>https://developer.android.com/reference/android/support/v7/app/package-summary.html</item>\n        <item>https://github.com/daimajia/AndroidSwipeLayout</item>\n        <item>https://github.com/brnunes/SwipeableRecyclerView</item>\n        <item>https://github.com/BoD/android-switch-backport</item>\n        <item>https://github.com/jgilfelt/SystemBarTint</item>\n        <item>https://github.com/bluejamesbond/TextJustify-Android</item>\n        <item>https://github.com/klinker24/Android-TextView-LinkBuilder</item>\n        <item>https://github.com/sephiroth74/android-target-tooltip</item>\n        <item>https://github.com/kshoji/USB-MIDI-Driver</item>\n        <item>https://github.com/KeenenCharles/AndroidUnplash</item>\n        <item>https://github.com/gotev/android-upload-service</item>\n        <item>https://github.com/daimajia/AndroidViewAnimations</item>\n        <item>https://github.com/JakeWharton/ViewPagerIndicator</item>\n        <item>https://developers.google.com/vision/</item>\n        <item>https://github.com/HugoGresse/AndroidVuMeter</item>\n        <item>https://github.com/badoo/android-weak-handler</item>\n        <item>https://developers.google.com/android/reference/com/google/android/gms/wearable/package-summary</item>\n        <item>https://github.com/alamkanak/Android-Week-View</item>\n        <item>https://github.com/romannurik/Android-WizardPager</item>\n        <item>https://github.com/exxbrain/android-biometric</item>\n        <item>https://github.com/vincentbrison/dualcache</item>\n        <item>https://github.com/vincentbrison/dualcache</item>\n        <item>https://github.com/ApmeM/android-flowlayout</item>\n        <item>https://github.com/andriydruk/RxDNSSD</item>\n        <item>https://github.com/andriydruk/RxDNSSD</item>\n        <item>https://github.com/andriydruk/RxDNSSD</item>\n        <item>https://github.com/liteglue/Android-sqlite-connector</item>\n        <item>https://github.com/mikepenz/Android-ActionItemBadge</item>\n        <item>https://github.com/chrisbanes/Android-BitmapCache</item>\n        <item>https://github.com/Bearded-Hen/Android-Bootstrap</item>\n        <item>https://github.com/sephiroth74/Android-Easing</item>\n        <item>https://github.com/sephiroth74/Android-Exif-Extended</item>\n        <item>https://github.com/zagum/Android-ExpandIcon</item>\n        <item>https://github.com/bosphere/Android-FadingEdgeLayout</item>\n        <item>https://github.com/bosphere/Android-FileLogger</item>\n        <item>https://github.com/DroidNinja/Android-FilePicker</item>\n        <item>https://github.com/mikepenz/Android-Iconics</item>\n        <item>https://github.com/mikepenz/Android-Iconics</item>\n        <item>https://github.com/mikepenz/Android-Iconics</item>\n        <item>https://github.com/mikepenz/Android-Iconics</item>\n        <item>https://github.com/mikepenz/Android-Iconics</item>\n        <item>https://github.com/evernote/android-job</item>\n        <item>https://github.com/klinker41/android-logger</item>\n        <item>https://github.com/jenzz/Android-MaterialPreference</item>\n        <item>https://github.com/tinmegali/simple-mvp</item>\n        <item>https://github.com/ksoichiro/Android-ObservableScrollView</item>\n        <item>https://github.com/Bigkoo/Android-PickerView</item>\n        <item>https://github.com/johnkil/Android-ProgressFragment</item>\n        <item>https://github.com/hotchemi/Android-Rate</item>\n        <item>https://github.com/kobakei/Android-RateThisApp</item>\n        <item>https://github.com/akexorcist/Android-RoundCornerProgressBar</item>\n        <item>https://github.com/yqritc/Android-ScalableVideoView</item>\n        <item>https://github.com/JetradarMobile/android-snowfall</item>\n        <item>https://github.com/ybq/Android-SpinKit</item>\n        <item>https://github.com/evernote/android-state</item>\n        <item>https://github.com/Gericop/Android-Support-Preference-V7-Fix</item>\n        <item>https://github.com/Beyka/Android-TiffBitmapFactory</item>\n        <item>https://github.com/llollox/Android-Toggle-Switch</item>\n        <item>https://github.com/jenzz/Android-UndoBar</item>\n        <item>https://github.com/winsontan520/Android-WVersionManager</item>\n        <item>https://github.com/chemalarrea/Android-wheel</item>\n        <item>https://github.com/androidannotations/androidannotations</item>\n        <item>https://github.com/androidannotations/androidannotations</item>\n        <item>https://github.com/koush/AndroidAsync</item>\n        <item>https://github.com/JessYanCoding/AndroidAutoSize</item>\n        <item>https://github.com/youth5201314/banner</item>\n        <item>https://github.com/TheFinestArtist/AndroidBaseUtils</item>\n        <item>https://github.com/Kunzisoft/AndroidClearChroma</item>\n        <item>https://github.com/JorgeCastilloPrz/AndroidColorX</item>\n        <item>https://github.com/asksven/AndroidCommon</item>\n        <item>https://github.com/didikee/AndroidDonate</item>\n        <item>https://github.com/bullheadandplato/AndroidEqualizer</item>\n        <item>https://github.com/zhanghai/AndroidFastScroll</item>\n        <item>https://github.com/LSPosed/AndroidHiddenApiBypass</item>\n        <item>https://github.com/itsaky/AndroidIDE</item>\n        <item>https://github.com/li-xiaojun/AndroidKTX</item>\n        <item>https://github.com/naman14/TAndroidLame</item>\n        <item>https://github.com/huzongyao/AndroidMagic</item>\n        <item>https://github.com/Zomato/AndroidPhotoFilters</item>\n        <item>https://github.com/AzeeSoft/AndroidPhotoshopColorPicker</item>\n        <item>https://github.com/jaredrummler/AndroidProcesses</item>\n        <item>https://github.com/androidquery/androidquery</item>\n        <item>https://github.com/etsy/AndroidStaggeredGrid</item>\n        <item>https://github.com/ar-android/AndroidSvgLoader</item>\n        <item>https://github.com/bmelnychuk/AndroidTreeView</item>\n        <item>https://github.com/michael-rapp/AndroidUtil</item>\n        <item>https://github.com/Blankj/AndroidUtilCode</item>\n        <item>https://github.com/Tianscar/AndroidUtils</item>\n        <item>https://github.com/skydoves/AndroidVeil</item>\n        <item>https://github.com/danikula/AndroidVideoCache</item>\n        <item>https://developer.android.com/jetpack/androidx</item>\n        <item>https://developer.android.com/jetpack/androidx/releases/car-app</item>\n        <item>https://developer.android.com/tools/extras/support-library.html</item>\n        <item>https://developer.android.com/jetpack/androidx/releases/emoji</item>\n        <item>https://android.googlesource.com/platform/frameworks/support/+/refs/heads/androidx-main/fragment/</item>\n        <item>https://developer.android.com/jetpack/androidx/releases/gridlayout</item>\n        <item>https://github.com/androidx/androidx/tree/androidx-main/inspection</item>\n        <item>https://android.googlesource.com/platform/frameworks/support/+/refs/heads/androidx-localbroadcastmanager-release/localbroadcastmanager/</item>\n        <item>https://developer.android.com/jetpack/androidx/releases/percentlayout</item>\n        <item>https://github.com/takisoft/preferencex-android</item>\n        <item>https://developer.android.com/jetpack/androidx/releases/security</item>\n        <item>https://github.com/android/android-test</item>\n        <item>https://developer.android.com/jetpack/androidx/releases/wear</item>\n        <item>https://developer.android.com/reference/androidx/viewpager2/widget/ViewPager2</item>\n        <item>http://androidplot.com/</item>\n        <item>https://developer.android.com/jetpack/androidx/releases/core</item>\n        <item>https://help.aliyun.com/document_detail/87884.html</item>\n        <item>https://github.com/AlexLiuSheng/AnimSideBar</item>\n        <item>https://github.com/anthonycr/AnimatedProgressBar</item>\n        <item>https://github.com/jaredrummler/AnimatedSvgView</item>\n        <item>https://github.com/jaredrummler/AnimatedSvgView</item>\n        <item>https://github.com/Kotlin/anko</item>\n        <item>https://cloud.google.com/solutions/media-entertainment/\\?a=2</item>\n        <item>https://github.com/sharenowTech/AnyMaps</item>\n        <item>http://www.anysdk.com/</item>\n        <item>http://www.anysdk.com/</item>\n        <item>https://www.anzu.io/</item>\n        <item>https://ant.apache.org/</item>\n        <item>https://commons.apache.org/</item>\n        <item>https://cordova.apache.org/</item>\n        <item>https://felix.apache.org/documentation/index.html</item>\n        <item>https://freemarker.apache.org/</item>\n        <item>https://mina.apache.org/ftpserver-project/index.html</item>\n        <item>https://harmony.apache.org/</item>\n        <item>https://hc.apache.org/</item>\n        <item>https://hc.apache.org/</item>\n        <item>https://jackrabbit.apache.org/jcr/index.html</item>\n        <item>https://james.apache.org/</item>\n        <item>http://logging.apache.org/log4j/</item>\n        <item>https://lucene.apache.org/</item>\n        <item>https://mina.apache.org/mina-project/</item>\n        <item>https://maven.apache.org/scm/</item>\n        <item>https://oltu.apache.org/index.html</item>\n        <item>https://openjpa.apache.org/</item>\n        <item>https://poi.apache.org/</item>\n        <item>https://pig.apache.org/</item>\n        <item>https://velocity.apache.org/index.html</item>\n        <item>https://xml.apache.org/</item>\n        <item>https://xerces.apache.org/</item>\n        <item>https://xerces.apache.org/</item>\n        <item>https://xerces.apache.org/</item>\n        <item>https://xerces.apache.org/</item>\n        <item>http://www.apfloat.org/apfloat_java/</item>\n        <item>https://github.com/iBotPeaches/Apktool</item>\n        <item>https://github.com/iBotPeaches/Apktool</item>\n        <item>https://github.com/iBotPeaches/Apktool</item>\n        <item>https://github.com/iBotPeaches/Apktool</item>\n        <item>https://github.com/iBotPeaches/Apktool</item>\n        <item>https://github.com/jeffshee/Apng2GifAndroid</item>\n        <item>https://github.com/line/apng-drawable</item>\n        <item>https://github.com/apollographql/apollo-android</item>\n        <item>https://github.com/apollographql/apollo-kotlin</item>\n        <item>https://docs.microsoft.com/en-us/appcenter/push/</item>\n        <item>https://appsamurai.com/</item>\n        <item>https://github.com/garretyoder/app-theme-engine</item>\n        <item>https://github.com/kabouzeid/app-theme-helper</item>\n        <item>http://appanalytics.io/</item>\n        <item>https://github.com/openid/AppAuth-Android</item>\n        <item>https://www.appbrain.com/info/help/sdk/index.html</item>\n        <item>https://developer.android.com/jetpack/androidx/releases/appcompat</item>\n        <item>https://sfbx.gitbook.io/appconsent/</item>\n        <item>https://github.com/zhanghai/AppIconLoader</item>\n        <item>https://github.com/ditacristianionut/AppInfoBadge</item>\n        <item>https://github.com/AppIntro/AppIntro</item>\n        <item>https://github.com/thelittlefireman/AppKillerManager</item>\n        <item>https://github.com/grishka/appkit</item>\n        <item>https://support.applink.io/hc/en-us/articles/360021172012-Getting-Started-with-the-React-Native-SDK</item>\n        <item>https://support.applink.io/hc/en-us/articles/360021172012-Getting-Started-with-the-React-Native-SDK</item>\n        <item>https://www.applovin.com/</item>\n        <item>https://tech.yandex.com/metrica-mobile-sdk/</item>\n        <item>http://appmonet.com</item>\n        <item>https://www.appnexus.com/</item>\n        <item>https://github.com/TimotheeJeannin/AppRate</item>\n        <item>https://www.safedk.com/marketplace/sdks/gryphonet-gryphonet</item>\n        <item>https://www.appsee.com/</item>\n        <item>https://github.com/javiersantos/AppUpdater</item>\n        <item>http://www.appvador.com/</item>\n        <item>https://www.appzilo.com/</item>\n        <item>http://www.appcelerator.org/</item>\n        <item>https://docs.appcelerator.com/platform/latest/#!/guide/APS_Analytics_for_Android</item>\n        <item>https://docs.appcelerator.com/platform/latest/#!/guide/APS_Analytics_for_Android</item>\n        <item>https://www.appdynamics.com/</item>\n        <item>http://www.appenda.com</item>\n        <item>https://unknown-website.unknown</item>\n        <item>https://appirits.com/</item>\n        <item>http://www.applause.com/</item>\n        <item>https://github.com/apla/me.apla.cordova.app-preferences</item>\n        <item>https://applift.com/</item>\n        <item>https://www.appnext.com/</item>\n        <item>https://www.appodeal.com</item>\n        <item>https://www.appodeal.com</item>\n        <item>https://appodealstack.com/about/</item>\n        <item>http://AppsFlyer.com/</item>\n        <item>https://appsgeyser.com/</item>\n        <item>https://appsgeyser.com/</item>\n        <item>https://www.apptentive.com/</item>\n        <item>http://www.apptimize.com/</item>\n        <item>https://www.app-visor.com/</item>\n        <item>https://singular.net</item>\n        <item>http://www.apteligent.com/</item>\n        <item>https://developer.android.com/jetpack/androidx/releases/arch</item>\n        <item>https://github.com/smrtyvz/ArchedImageProgressBar</item>\n        <item>https://areametrics.com/</item>\n        <item>https://areametrics.com/</item>\n        <item>https://argparse4j.github.io/</item>\n        <item>https://github.com/android10/arrow</item>\n        <item>https://www.askingpoint.com/blog/document/add-sdk-to-project/</item>\n        <item>https://github.com/afollestad/ason</item>\n        <item>https://github.com/santalu/aspect-ratio-imageview</item>\n        <item>https://github.com/eclipse/org.aspectj</item>\n        <item>https://github.com/afollestad/assent</item>\n        <item>https://gitlab.astian.org/apps-mobiles/astian-libs</item>\n        <item>https://github.com/AsyncHttpClient/async-http-client</item>\n        <item>https://github.com/metalabdesign/AsyncAwait</item>\n        <item>https://github.com/Arasthel/AsyncJobLibrary</item>\n        <item>https://developer.android.com/jetpack/androidx/releases/asynclayoutinflater</item>\n        <item>https://github.com/Musenkishi/Atelier</item>\n        <item>https://github.com/Kotlin/kotlinx.atomicfu</item>\n        <item>https://github.com/fennifith/Attribouter</item>\n        <item>https://github.com/franmontiel/AttributionPresenter</item>\n        <item>https://www.salesforce.com/products/marketing-cloud/data-management/\\?mc=DMP</item>\n        <item>https://github.com/gauravk95/audio-visualizer-android</item>\n        <item>https://github.com/FireZenk/AudioWaves</item>\n        <item>https://github.com/Cleveroad/MusicBobber</item>\n        <item>https://github.com/jaydeepw/audio-wife</item>\n        <item>https://github.com/WrichikBasu/AudioFocusController</item>\n        <item>https://github.com/luanpotter/audioplayers</item>\n        <item>https://github.com/Armen101/AudioRecordView</item>\n        <item>https://github.com/alxrm/audiowave-progressbar</item>\n        <item>https://github.com/kivy/audiostream</item>\n        <item>https://www.adobe.com/privacy/policies/auditude.html</item>\n        <item>https://github.com/google/auto</item>\n        <item>https://github.com/hyb1996/Auto.js</item>\n        <item>https://github.com/uber/AutoDispose</item>\n        <item>https://github.com/uber/AutoDispose</item>\n        <item>https://github.com/AndroidDeveloperLB/AutoFitTextView</item>\n        <item>https://github.com/armcha/AutoLinkTextView</item>\n        <item>https://github.com/frankiesardo/auto-parcel</item>\n        <item>http://ankri.de/autoscale-textview/</item>\n        <item>https://github.com/rharter/auto-value-gson/</item>\n        <item>https://github.com/REggar/auto-value-ignore-hash-equals</item>\n        <item>https://github.com/coreyauger/AutobahnAndroid</item>\n        <item>https://developer.android.com/jetpack/androidx/releases/autofill</item>\n        <item>https://github.com/Automattic/Automattic-Tracks-Android</item>\n        <item>https://github.com/ToniKorin/cordova-plugin-autostart</item>\n        <item>https://github.com/judemanutd/AutoStarter</item>\n        <item>https://github.com/michaelWuensch/avathor-android-library</item>\n        <item>http://avazuinc.com</item>\n        <item>http://avazuinc.com</item>\n        <item>https://www.avocarrot.com/</item>\n        <item>https://github.com/rafaelsetragni/awesome_notifications</item>\n        <item>https://github.com/SumiMakito/AwesomeQRCode</item>\n        <item>https://github.com/ViksaaSkool/AwesomeSplash</item>\n        <item>http://axonix.com/</item>\n        <item>http://axonix.com/</item>\n        <item>https://github.com/Azure/azure-sdk-for-java</item>\n        <item>https://github.com/AnywhereSoftware/B4A</item>\n        <item>https://github.com/AnywhereSoftware/B4J</item>\n        <item>https://github.com/bingoogolapple/BGABanner-Android</item>\n        <item>https://github.com/bingoogolapple/BGAQRCode-Android</item>\n        <item>https://github.com/orogvany/BIP32-Ed25519-java</item>\n        <item>https://github.com/orogvany/BIP32-Ed25519-java</item>\n        <item>https://github.com/NovaCrypto/BIP39</item>\n        <item>https://github.com/bitsofproof/bop-bitcoin-client</item>\n        <item>https://github.com/BottleRocketStudios/Android-Vault</item>\n        <item>https://github.com/CymChad/BaseRecyclerViewAdapterHelper</item>\n        <item>https://github.com/mongodb/mongo-java-driver/tree/master/bson</item>\n        <item>https://www.babator.com/</item>\n        <item>https://www.backelite.com/</item>\n        <item>https://www.backelite.com/</item>\n        <item>https://backendless.com/docs/android/quick_start_guide.html</item>\n        <item>https://backtrace.io</item>\n        <item>https://backtrace.io</item>\n        <item>https://github.com/nekocode/Badge</item>\n        <item>https://github.com/AlexLiuSheng/BadgeView</item>\n        <item>https://app.baidu.com/</item>\n        <item>https://www.baidu.com/</item>\n        <item>https://www.baidu.com/</item>\n        <item>https://developer.baidu.com/</item>\n        <item>http://lbsyun.baidu.com/</item>\n        <item>https://map.baidu.com</item>\n        <item>https://developer.baidu.com/</item>\n        <item>https://developer.baidu.com/</item>\n        <item>http://lbsyun.baidu.com/index.php\\?title=android-navsdk</item>\n        <item>https://github.com/skydoves/Balloon</item>\n        <item>https://github.com/zhpanvip/BannerViewPager</item>\n        <item>https://github.com/barchart/barchart-udt</item>\n        <item>https://github.com/capacitor-community/barcode-scanner</item>\n        <item>https://github.com/kroegerama/barcode-kaiteki</item>\n        <item>http://www.source-code.biz/base64coder/java/</item>\n        <item>https://github.com/razerdp/BasePopup</item>\n        <item>https://github.com/razerdp/BasePopup</item>\n        <item>https://github.com/razerdp/BasePopup</item>\n        <item>https://github.com/razerdp/BasePopup</item>\n        <item>https://batch.com</item>\n        <item>https://www.bazaarvoice.com/</item>\n        <item>https://github.com/patrickfav/bcrypt</item>\n        <item>https://www.beaconbank.jp/signups</item>\n        <item>https://beaconsinspace.com</item>\n        <item>http://beaglebuddy.com/</item>\n        <item>https://mvnrepository.com/artifact/javax.validation/validation-api</item>\n        <item>https://www.beemray.com</item>\n        <item>https://beintoo.com/</item>\n        <item>https://github.com/jhomlala/betterplayer</item>\n        <item>https://github.com/halilozercan/BetterVideoPlayer</item>\n        <item>https://github.com/saket/Better-Link-Movement-Method</item>\n        <item>https://github.com/Lesilva/BetterSpinner</item>\n        <item>https://github.com/eighthave/bho</item>\n        <item>https://github.com/MichaelRocks/bimap</item>\n        <item>https://bidmachine.io/</item>\n        <item>https://github.com/kiprobinson/BigFraction</item>\n        <item>https://github.com/Piasy/BigImageViewer</item>\n        <item>https://github.com/kanchudeep/BikramSambat</item>\n        <item>https://developer.android.com/reference/com/android/billingclient/api/BillingClient</item>\n        <item>https://github.com/binance-chain/java-sdk</item>\n        <item>https://github.com/iamironz/binaryprefs</item>\n        <item>https://github.com/evant/binding-collection-adapter</item>\n        <item>https://github.com/evant/binding-collection-adapter</item>\n        <item>https://developer.android.com/jetpack/androidx/releases/biometric</item>\n        <item>https://bitlabs.ai/</item>\n        <item>https://sourceforge.net/projects/bitcollider/</item>\n        <item>https://sourceforge.net/projects/bitcollider/</item>\n        <item>https://bitly.com/</item>\n        <item>https://github.com/rfksystems/blake2b</item>\n        <item>https://www.blesh.com/</item>\n        <item>https://www.blueconic.com/</item>\n        <item>http://bluecove.org/</item>\n        <item>http://bluekai.com/registry/</item>\n        <item>https://www.bluecats.com/</item>\n        <item>https://github.com/jahirfiquitiva/Blueprint</item>\n        <item>https://github.com/OmarAflak/Bluetooth-Library</item>\n        <item>https://github.com/OmarAflak/Bluetooth-Library</item>\n        <item>https://github.com/Dimezis/BlurView</item>\n        <item>https://github.com/mrousavy/react-native-blurhash</item>\n        <item>https://github.com/wasabeef/Blurry</item>\n        <item>https://github.com/bmob/bmob-android-sdk</item>\n        <item>https://github.com/BoltsFramework/Bolts-Android</item>\n        <item>https://github.com/microsoft/bond</item>\n        <item>https://github.com/roughike/BottomBar</item>\n        <item>https://github.com/javiersantos/BottomDialogs</item>\n        <item>https://github.com/ittianyu/BottomNavigationViewEx</item>\n        <item>https://github.com/soarcn/BottomSheet</item>\n        <item>https://github.com/rubensousa/BottomSheetBuilder</item>\n        <item>https://github.com/philliphsu/BottomSheetPickers</item>\n        <item>https://github.com/SuppSandroB/sandrop/tree/master/projects/BouncyCastle</item>\n        <item>https://github.com/braintree/braintree_android</item>\n        <item>https://branch.io/</item>\n        <item>https://brandio.io/</item>\n        <item>https://github.com/Appboy/appboy-android-sdk</item>\n        <item>https://github.com/fython/BreadcrumbsView</item>\n        <item>https://github.com/afollestad/bridge</item>\n        <item>https://www.brightcove.com</item>\n        <item>https://developer.android.com/jetpack/androidx/releases/browser</item>\n        <item>https://github.com/igalata/Bubble-Picker</item>\n        <item>https://github.com/woxingxiao/BubbleSeekBar</item>\n        <item>https://bugclipper.com/sdk-doc/android/</item>\n        <item>http://www.bugsense.com/</item>\n        <item>https://bugfender.com/</item>\n        <item>https://buglife.com/docs/android</item>\n        <item>https://bugly.qq.com/</item>\n        <item>https://github.com/BuglyDevTeam/Bugly-Android</item>\n        <item>https://docs.bugsee.com/sdk/android/installation/</item>\n        <item>https://github.com/bugsnag/bugsnag-android</item>\n        <item>https://github.com/SpigotMC/BungeeCord</item>\n        <item>https://github.com/JakeWharton/butterknife</item>\n        <item>https://www.usebutton.com</item>\n        <item>https://github.com/subsub/ButtonCustomShadow</item>\n        <item>https://buzzvil.atlassian.net/wiki/spaces/BDG/pages/486834313/BuzzAd-Benefit+Android+SDK</item>\n        <item>https://github.com/Uncodin/bypass</item>\n        <item>https://github.com/raphw/byte-buddy/</item>\n        <item>https://byyd.me</item>\n        <item>https://github.com/LivotovLabs/CamView</item>\n        <item>https://github.com/vRallev/cat</item>\n        <item>https://github.com/peteroupc/CBOR-Java</item>\n        <item>https://github.com/c-rack/cbor-java</item>\n        <item>http://www.benf.org/other/cfr/</item>\n        <item>https://github.com/cryptape/cita</item>\n        <item>https://github.com/gzu-liyujiang/CJKCharsetDetector</item>\n        <item>http://cssparser.sourceforge.net/</item>\n        <item>https://github.com/commonsguy/cwac-anddown</item>\n        <item>https://github.com/bearmingo/cwac-colormixer</item>\n        <item>https://github.com/commonsguy/cwac-layouts</item>\n        <item>https://github.com/commonsguy/cwac-richedit</item>\n        <item>https://github.com/commonsguy/cwac-wakeful</item>\n        <item>https://github.com/commonsguy/cwac-pager</item>\n        <item>https://github.com/pyamsoft/cachify</item>\n        <item>https://github.com/ben-manes/caffeine</item>\n        <item>https://github.com/roomorama/Caldroid</item>\n        <item>https://github.com/roomorama/Caldroid</item>\n        <item>https://github.com/kizitonwose/CalendarView</item>\n        <item>https://github.com/CallControl/Call-Control-DataShare</item>\n        <item>http://calldorado.com</item>\n        <item>https://github.com/DylanCaiCoding/Callbacks</item>\n        <item>https://github.com/AnwarShahriar/Calligrapher</item>\n        <item>https://github.com/InflationX/Calligraphy</item>\n        <item>https://github.com/react-native-community/react-native-cameraroll</item>\n        <item>https://github.com/google/cameraview</item>\n        <item>https://developer.android.com/jetpack/androidx/releases/camera</item>\n        <item>https://github.com/zixpo/candybar</item>\n        <item>https://git.teknorota.com/yekmyk/capacitor</item>\n        <item>https://github.com/moberwasserlechner/capacitor-oauth2</item>\n        <item>https://github.com/ionic-team/capacitor-plugins</item>\n        <item>https://github.com/tchvu3/capacitor-voice-recorder</item>\n        <item>http://caramelads.com/</item>\n        <item>https://github.com/ZieIony/Carbon</item>\n        <item>https://github.com/gabrielemariotti/cardslib</item>\n        <item>https://developers.google.com/cardboard</item>\n        <item>https://github.com/Androguide/cardsui-for-android</item>\n        <item>https://android.googlesource.com/platform/frameworks/support/+/refs/heads/androidx-main/cardview/</item>\n        <item>https://docs.carnival.io/</item>\n        <item>https://docs.carnival.io/</item>\n        <item>https://carto.com</item>\n        <item>https://carto.com</item>\n        <item>https://github.com/CartoDB/mobile-sdk</item>\n        <item>https://github.com/iheartradio/android-cast-companion-library</item>\n        <item>https://github.com/jhomlala/catcher</item>\n        <item>https://typelevel.org/cats/</item>\n        <item>https://caulis.jp/en/</item>\n        <item>https://www.cauly.net</item>\n        <item>https://www.cauly.net</item>\n        <item>https://www.cauly.net</item>\n        <item>https://www.cedexis.com/</item>\n        <item>https://github.com/mariotaku/Chameleon</item>\n        <item>https://github.com/gabrielemariotti/changeloglib</item>\n        <item>https://github.com/MFlisar/changelog</item>\n        <item>https://chaquo.com/chaquopy/</item>\n        <item>https://answers.chartboost.com/en-us/</item>\n        <item>https://github.com/hadiidbouk/ChartProgressBar-Android</item>\n        <item>https://chartbeat.com/</item>\n        <item>https://github.com/stfalcon-studio/ChatKit</item>\n        <item>https://github.com/ChatSecure/ChatSecure-Push-Android</item>\n        <item>https://github.com/AlexLiuSheng/CheckVersionLib</item>\n        <item>https://checkerframework.org/</item>\n        <item>https://checkerframework.org/</item>\n        <item>https://github.com/duanhong169/CheckerboardDrawable</item>\n        <item>https://github.com/serso/android-checkout</item>\n        <item>https://www.cmcm.com/</item>\n        <item>https://github.com/fiskurgit/ChipCloud</item>\n        <item>https://github.com/tylersuehr7/chips-input-layout</item>\n        <item>https://github.com/BelooS/ChipsLayoutManager</item>\n        <item>https://github.com/cyph/cordova-plugin-chooser</item>\n        <item>https://github.com/GoogleChrome/custom-tabs-client</item>\n        <item>https://chromium.googlesource.com/chromium/src/net/</item>\n        <item>https://chromium.googlesource.com/chromium/src/url/</item>\n        <item>https://github.com/vitalidze/chromecast-java-api-v2</item>\n        <item>https://github.com/michael-rapp/ChromeLikeTabSwitcher</item>\n        <item>https://github.com/DeweyReed/ChromeMenu</item>\n        <item>https://chromium.googlesource.com/chromium/src/base/</item>\n        <item>https://chromium.googlesource.com/chromium/src/build/</item>\n        <item>https://github.com/jgilfelt/chuck</item>\n        <item>https://github.com/ChuckerTeam/chucker</item>\n        <item>https://github.com/tomj74/chunk-templates</item>\n        <item>https://github.com/tomj74/chunk-templates</item>\n        <item>https://github.com/terrakok/Cicerone</item>\n        <item>http://cifrasoft.com</item>\n        <item>https://github.com/MEiDIK/Cipher.so</item>\n        <item>https://github.com/hdodenhof/CircleImageView</item>\n        <item>https://github.com/ongakuer/CircleIndicator</item>\n        <item>https://github.com/AlexLiuSheng/CircleMenuView</item>\n        <item>https://github.com/lzyzsd/CircleProgress</item>\n        <item>https://github.com/dinuscxj/CircleProgressBar</item>\n        <item>https://github.com/yuriy-budiyev/circular-progress-bar</item>\n        <item>https://github.com/lopspower/CircularImageView</item>\n        <item>https://github.com/lopspower/CircularProgressBar</item>\n        <item>https://github.com/antonKozyriatskyi/CircularProgressIndicator</item>\n        <item>https://github.com/ozodrukh/CircularReveal</item>\n        <item>https://github.com/tankery/CircularSeekBar</item>\n        <item>https://github.com/google/android-classyshark</item>\n        <item>https://github.com/cleaninsights/cleaninsights-android-sdk/blob/master/cleaninsights-piwik-sdk</item>\n        <item>https://www.clearblade.com</item>\n        <item>https://clevertap.com/</item>\n        <item>https://github.com/4thline/cling</item>\n        <item>https://github.com/4thline/cling</item>\n        <item>https://cloud.google.com/logging/docs/audit</item>\n        <item>https://github.com/CloudRail/cloudrail-si-java-sdk</item>\n        <item>http://www.cloudmobi.net/</item>\n        <item>https://www.cocos2d-x.org/</item>\n        <item>https://github.com/yuriy-budiyev/code-scanner</item>\n        <item>https://github.com/ahmadaghazadeh/CodeEditor</item>\n        <item>https://github.com/kbiakov/CodeView-android</item>\n        <item>https://github.com/telegram-sms/CodeauxLibPortable</item>\n        <item>https://github.com/UstadMobile/Codec2-Android</item>\n        <item>https://codehaus-plexus.github.io/</item>\n        <item>https://codehaus-plexus.github.io/</item>\n        <item>https://github.com/shannah/cn1-regex</item>\n        <item>https://github.com/coil-kt/coil</item>\n        <item>https://github.com/irismod/coinswap</item>\n        <item>https://android.googlesource.com/platform/frameworks/base/+/HEAD/core/java/com/google/android/collect</item>\n        <item>https://developers.colocator.net/</item>\n        <item>https://github.com/QuadFlask/colorpicker</item>\n        <item>https://github.com/chiralcode/Android-Color-Picker</item>\n        <item>https://github.com/kizitonwose/colorpreference</item>\n        <item>https://github.com/kizitonwose/colorpreference</item>\n        <item>https://github.com/GrenderG/Color-O-Matic</item>\n        <item>https://github.com/Kennyc1012/ColorChooser</item>\n        <item>https://github.com/flavienlaurent/colorpicker</item>\n        <item>https://github.com/uucky/ColorPicker-Android</item>\n        <item>https://github.com/fennifith/ColorPickerDialog</item>\n        <item>https://github.com/attenzione/android-ColorPickerPreference</item>\n        <item>https://github.com/danielnilsson9/color-picker-view</item>\n        <item>https://github.com/otakuhqz/ColorPickerX</item>\n        <item>https://github.com/msasikanth/ColorSheet</item>\n        <item>https://github.com/ajalt/colormath</item>\n        <item>https://comscore.com/</item>\n        <item>https://www.comm100.com/platform/livechat/</item>\n        <item>https://github.com/smuyyh/CommonLibary</item>\n        <item>https://github.com/devgianlu/CommonUtils</item>\n        <item>https://github.com/mariotaku/CommonsLibrary</item>\n        <item>https://github.com/commonsguy/cwac-merge</item>\n        <item>https://github.com/commonsguy/cwac-sacklist</item>\n        <item>https://github.com/SundeepK/CompactCalendarView</item>\n        <item>https://github.com/SmartToolFactory/Compose-Colorful-Sliders</item>\n        <item>https://github.com/raamcosta/compose-destinations</item>\n        <item>https://github.com/vanpra/compose-material-dialogs</item>\n        <item>https://github.com/patrickgold/compose-tooltip</item>\n        <item>https://github.com/zetbaitsu/Compressor</item>\n        <item>http://www.comscore.com/</item>\n        <item>https://github.com/facebook/conceal</item>\n        <item>https://github.com/facebook/conceal</item>\n        <item>https://developer.android.com/jetpack/androidx/releases/concurrent</item>\n        <item>https://github.com/npgall/concurrent-trees</item>\n        <item>https://github.com/bluelinelabs/Conductor</item>\n        <item>https://developer.garmin.com/connect-iq/sdk/</item>\n        <item>https://developer.garmin.com/connect-iq/sdk/</item>\n        <item>https://github.com/connectbot/connectbot</item>\n        <item>https://github.com/google/conscrypt</item>\n        <item>https://github.com/google/conscrypt</item>\n        <item>https://github.com/jraska/Console</item>\n        <item>https://github.com/androidx/constraintlayout</item>\n        <item>https://github.com/capacitor-community/contacts</item>\n        <item>https://contentsquare.com/</item>\n        <item>https://github.com/Yalantis/Context-Menu.Android</item>\n        <item>https://www.conversantmedia.com</item>\n        <item>https://www.conversantmedia.com</item>\n        <item>https://www.conviva.com/</item>\n        <item>https://github.com/AviranAbady/CookieBar2</item>\n        <item>https://www.cooladata.com/</item>\n        <item>https://developer.android.com/jetpack/androidx/releases/coordinatorlayout</item>\n        <item>https://github.com/cashapp/copper</item>\n        <item>https://github.com/silkimen/cordova-plugin-advanced-http</item>\n        <item>https://github.com/silkimen/cordova-plugin-advanced-http</item>\n        <item>https://github.com/Rareloop/cordova-plugin-app-version</item>\n        <item>https://github.com/katzer/cordova-plugin-background-mode</item>\n        <item>https://github.com/sanilnaik/de.appplant.cordova.plugin.badge</item>\n        <item>https://github.com/crosswalk-project</item>\n        <item>https://github.com/kroodle/cordova-disable-http-cache</item>\n        <item>https://github.com/Whebcraft/cordova-plugin-downloader</item>\n        <item>https://github.com/katzer/cordova-plugin-email-composer</item>\n        <item>https://github.com/homerours/cordova-music-controls-plugin</item>\n        <item>https://github.com/floatinghotpot/cordova-plugin-nativeaudio</item>\n        <item>https://github.com/floatinghotpot/cordova-plugin-ext</item>\n        <item>https://github.com/Vavoo/PushPlugin</item>\n        <item>https://github.com/cordova-sms/cordova-sms-plugin</item>\n        <item>https://github.com/apache/cordova-plugin-screen-orientation</item>\n        <item>https://github.com/EddyVerbruggen/SocialSharing-PhoneGap-Plugin</item>\n        <item>https://github.com/nordnet/cordova-universal-links-plugin</item>\n        <item>https://github.com/mariusbackes/cordova-plugin-theme-detection</item>\n        <item>https://github.com/Ideas2IT/cordova-aes256</item>\n        <item>https://github.com/VersoSolutions/CordovaClipboard</item>\n        <item>https://github.com/couchbase/couchbase-lite-java-ce-root</item>\n        <item>https://github.com/couchbase/couchbase-lite-java-ce-root</item>\n        <item>https://measurementsys.com/index.php#appdev</item>\n        <item>https://count.ly/</item>\n        <item>https://github.com/sunilpaulmathew/CrashReporter</item>\n        <item>https://github.com/MindorksOpenSource/CrashReporter</item>\n        <item>https://github.com/SummerOak/CrashSDK</item>\n        <item>https://github.com/TutorialsAndroid/crashx</item>\n        <item>https://firebase.google.com/docs/crashlytics/</item>\n        <item>https://firebase.google.com/docs/crashlytics/</item>\n        <item>https://firebase.google.com/docs/crashlytics/</item>\n        <item>https://firebase.google.com/docs/crashlytics/</item>\n        <item>https://firebase.google.com/docs/crashlytics/</item>\n        <item>https://github.com/CraZyLegenD/Crashy</item>\n        <item>http://bach.istc.kobe-u.ac.jp/cream/</item>\n        <item>https://www.criteo.com/</item>\n        <item>https://github.com/inventivtools/inventiv-critic-android</item>\n        <item>https://www.criware.com/en/</item>\n        <item>https://github.com/google/cronet-transport-for-okhttp</item>\n        <item>https://github.com/mikepenz/CrossfadeDrawerLayout</item>\n        <item>https://github.com/mikepenz/Crossfader</item>\n        <item>https://github.com/keyboardsurfer/Crouton</item>\n        <item>https://github.com/crowdin/mobile-sdk-android</item>\n        <item>https://www.crownpeak.com/</item>\n        <item>https://github.com/chimbori/crux</item>\n        <item>https://github.com/wg/crypto</item>\n        <item>https://github.com/wg/crypto</item>\n        <item>https://github.com/AndreaCioccarelli/CryptoPrefs</item>\n        <item>http://javacsv.sourceforge.net/</item>\n        <item>https://github.com/liaohuqiu/cube-sdk</item>\n        <item>http://www.cuebiq.com/</item>\n        <item>http://www.cuebiq.com/</item>\n        <item>https://github.com/midorikocak/currency-picker-android</item>\n        <item>https://github.com/square/curtains</item>\n        <item>https://github.com/square/curtains</item>\n        <item>https://github.com/Ereza/CustomActivityOnCrash</item>\n        <item>https://github.com/FarshidRoohi/CustomAdapterRecyclerview</item>\n        <item>https://github.com/CraZyLegenD/Set-Of-Useful-Kotlin-Extensions-and-Helpers/tree/master/customviews</item>\n        <item>https://github.com/ZarinPal/android-views</item>\n        <item>https://github.com/miguelhincapie/CustomBottomSheetBehavior</item>\n        <item>https://github.com/DreaminginCodeZH/CustomTabsHelper</item>\n        <item>https://github.com/Rajagopalr3/CustomizedTextView</item>\n        <item>https://github.com/jaredrummler/Cyanea</item>\n        <item>https://r8.googlesource.com/r8</item>\n        <item>https://www.date4j.net/</item>\n        <item>https://github.com/Raizlabs/DBFlow</item>\n        <item>https://dmmgames.co.jp/</item>\n        <item>https://github.com/adamfisk/DNSSEC4J</item>\n        <item>https://www.dov-e.com/</item>\n        <item>https://github.com/DozenWang/DPreference</item>\n        <item>https://github.com/square/dagger</item>\n        <item>https://www.thinkyeah.com/main</item>\n        <item>https://github.com/f2prateek/dart</item>\n        <item>http://api.dashclock.com/reference/com/google/android/apps/dashclock/api/package-summary.html</item>\n        <item>https://github.com/ThirtyDegreesRay/DataAutoAccess</item>\n        <item>https://developer.android.com/jetpack/androidx/releases/datastore</item>\n        <item>https://github.com/peteroupc/DataUtilities</item>\n        <item>https://developer.android.com/jetpack/androidx/releases/databinding/</item>\n        <item>https://github.com/databox/databox-java</item>\n        <item>https://www.datadoghq.com/</item>\n        <item>https://github.com/afollestad/date-picker</item>\n        <item>https://github.com/savvisingh/DateRangePicker</item>\n        <item>https://github.com/flavienlaurent/datetimepicker</item>\n        <item>https://click.dawin.tv/poc/#/init</item>\n        <item>https://www.dearone.io/</item>\n        <item>https://github.com/palaima/DebugDrawer</item>\n        <item>https://github.com/airbnb/DeepLinkDispatch</item>\n        <item>https://github.com/airbnb/DeepLinkDispatch</item>\n        <item>https://github.com/deezer/</item>\n        <item>https://github.com/heruoxin/Delegated-Scopes-Manager</item>\n        <item>https://www.adobe.com/data-analytics-cloud/audience-manager.html</item>\n        <item>https://www.adobe.com/data-analytics-cloud/audience-manager.html</item>\n        <item>https://developer.android.com/reference/dalvik/system/package-summary</item>\n        <item>https://github.com/linkedin/dexmaker</item>\n        <item>https://github.com/Karumi/Dexter</item>\n        <item>https://github.com/florent37/DiagonalLayout</item>\n        <item>https://github.com/orhanobut/dialogplus</item>\n        <item>https://www.didomi.io/</item>\n        <item>https://github.com/ehn-dcc-development/dgc-business-rules</item>\n        <item>https://www.shuzilm.cn/</item>\n        <item>https://discord.com/</item>\n        <item>https://github.com/PomepuyN/discreet-app-rate</item>\n        <item>https://github.com/yarolegovich/DiscreteScrollView</item>\n        <item>https://github.com/AnderWeb/discreteSeekBar</item>\n        <item>https://github.com/JakeWharton/DiskLruCache</item>\n        <item>https://github.com/Justson/dispatch-queue</item>\n        <item>https://github.com/Justson/dispatch-queue</item>\n        <item>https://www.display.io/en/</item>\n        <item>https://developer.android.com/jetpack/androidx/releases/documentfile</item>\n        <item>https://github.com/doubledotlabs/doki</item>\n        <item>https://github.com/futuredapp/donut</item>\n        <item>https://www.doubleclickbygoogle.com/</item>\n        <item>https://github.com/Justson/Downloader</item>\n        <item>https://github.com/ernestoyaquello/DragDropSwipeRecyclerview</item>\n        <item>https://github.com/afollestad/drag-select-recyclerview</item>\n        <item>https://github.com/justasm/DragLinearLayout</item>\n        <item>https://github.com/woxblom/DragListView</item>\n        <item>https://github.com/ericharlow/TICEWidgets</item>\n        <item>https://github.com/bauerca/drag-sort-listview</item>\n        <item>https://github.com/duanhong169/DrawableToolbox</item>\n        <item>https://developer.android.com/jetpack/androidx/releases/drawerlayout</item>\n        <item>https://mvnrepository.com/artifact/pl.droidsonroids.relinker</item>\n        <item>https://github.com/dropbox/dropbox-sdk-java</item>\n        <item>https://github.com/gini/dropbox-java-sdk</item>\n        <item>https://github.com/shehabic/Droppy</item>\n        <item>http://ad.duapps.com/</item>\n        <item>https://search.maven.org/artifact/com.squareup.duktape/duktape-android</item>\n        <item>https://github.com/gubaojian/DuktapeJava</item>\n        <item>https://www.dynamicyield.com/</item>\n        <item>https://github.com/askerov/DynamicGrid</item>\n        <item>https://developer.android.com/jetpack/androidx/releases/dynamicanimation</item>\n        <item>https://www.dynatrace.com</item>\n        <item>https://www.dynatrace.com</item>\n        <item>https://www.dynatrace.com</item>\n        <item>https://github.com/vRallev/ECC-25519</item>\n        <item>https://eclipse.org/egit/</item>\n        <item>https://github.com/EOSIO/eosio-java</item>\n        <item>https://github.com/EOSIO/eosio-java</item>\n        <item>https://github.com/EOSIO/eosio-java</item>\n        <item>https://www.epgpaid.de/</item>\n        <item>https://evrythng.com</item>\n        <item>https://github.com/Siclo-Mobile/EZPhotoPicker</item>\n        <item>https://github.com/Siclo-Mobile/EZPhotoPicker</item>\n        <item>https://github.com/j-easy/easy-rules</item>\n        <item>https://github.com/smuyyh/EasyAdapter</item>\n        <item>https://github.com/AlexLiuSheng/EasyBluetoothFrame</item>\n        <item>https://github.com/vsvankhede/EasyFonts</item>\n        <item>https://github.com/vsvankhede/EasyFonts</item>\n        <item>https://github.com/jkwiecien/EasyImage</item>\n        <item>https://github.com/googlesamples/easypermissions</item>\n        <item>https://github.com/VMadalin/easypermissions-ktx</item>\n        <item>https://github.com/Pixplicity/EasyPrefs</item>\n        <item>https://github.com/Jude95/EasyRecyclerView</item>\n        <item>https://github.com/fcopardo/EasyRest-Desktop</item>\n        <item>https://www.eclipse.org/eclipse/platform-core/</item>\n        <item>https://projects.eclipse.org/projects/eclipse.equinox</item>\n        <item>https://projects.eclipse.org/projects/eclipse.jdt</item>\n        <item>https://www.eclipse.org/jetty/</item>\n        <item>https://github.com/eclipse/paho.mqtt.android</item>\n        <item>https://git.eclipse.org/c/platform/eclipse.platform.text.git/tree/org.eclipse.text</item>\n        <item>https://git.eclipse.org/c/platform/eclipse.platform.text.git/tree/org.eclipse.text</item>\n        <item>https://github.com/eclipse/tm4e</item>\n        <item>https://github.com/str4d/ed25519-java</item>\n        <item>https://github.com/gregacucnik/EditTextView</item>\n        <item>https://github.com/billthefarmer/editor</item>\n        <item>https://github.com/halu5071/edwards</item>\n        <item>https://github.com/natario1/Egloo</item>\n        <item>http://en.ehawk.com/</item>\n        <item>https://github.com/Commit451/ElasticDragDismissLayout</item>\n        <item>https://help.emarsys.com/hc/categories/115000670425-Predict</item>\n        <item>https://embrace.io/</item>\n        <item>https://github.com/ngladitz/emma</item>\n        <item>https://github.com/vanniktech/Emoji</item>\n        <item>https://github.com/vIiRuS/emoji-lib</item>\n        <item>https://github.com/vIiRuS/emoji-lib</item>\n        <item>https://github.com/ankushsachdeva/emojicon</item>\n        <item>https://github.com/athkalia/EmphasisTextView</item>\n        <item>https://github.com/simbiose/Encryption</item>\n        <item>https://github.com/simbiose/Encryption</item>\n        <item>https://enhance.co</item>\n        <item>https://github.com/timroes/EnhancedListView</item>\n        <item>https://github.com/isaac-udy/Enro</item>\n        <item>https://github.com/isaac-udy/Enro</item>\n        <item>https://www.ensighten.com/</item>\n        <item>https://github.com/tiann/epic</item>\n        <item>https://dev.epicgames.com/docs/services/en-US/Platforms/Android/index.html</item>\n        <item>https://www.epicgames.com/</item>\n        <item>https://www.epicgames.com/</item>\n        <item>https://github.com/airbnb/epoxy</item>\n        <item>https://github.com/ag2s20150909/EpubLib</item>\n        <item>https://github.com/ScorexFoundation/sigmastate-interpreter</item>\n        <item>https://github.com/ScorexFoundation/sigmastate-interpreter</item>\n        <item>https://github.com/ScorexFoundation/sigmastate-interpreter</item>\n        <item>https://github.com/ScorexFoundation/sigmastate-interpreter</item>\n        <item>https://github.com/ScorexFoundation/sigmastate-interpreter</item>\n        <item>https://github.com/google/error-prone</item>\n        <item>https://github.com/xiprox/ErrorView</item>\n        <item>https://www.arcgis.com/</item>\n        <item>https://github.com/greenrobot/essentials</item>\n        <item>https://estimote.com/</item>\n        <item>https://github.com/EulerianTechnologies/eanalytics-android</item>\n        <item>https://github.com/NickAndroid/EventBus_Android</item>\n        <item>https://github.com/alexvasilkov/Events</item>\n        <item>https://www.evidon.com/</item>\n        <item>http://help.exacttarget.com/en/technical_library/API_Overview/</item>\n        <item>https://developer.android.com/jetpack/androidx/releases/exifinterface</item>\n        <item>https://github.com/brianwernick/ExoMedia</item>\n        <item>https://github.com/google/ExoPlayer</item>\n        <item>https://github.com/MasayukiSuda/ExoPlayerFilter</item>\n        <item>https://github.com/AAkira/ExpandableLayout</item>\n        <item>https://github.com/bignerdranch/expandable-recycler-view</item>\n        <item>https://github.com/st235/ExpandableBottomBar</item>\n        <item>https://github.com/nambicompany/expandable-fab</item>\n        <item>https://github.com/skydoves/ExpandableLayout</item>\n        <item>https://github.com/Manabu-GT/ExpandableTextView</item>\n        <item>https://github.com/florent37/ExpansionPanel</item>\n        <item>https://github.com/tyrantgit/ExplosionField</item>\n        <item>https://github.com/tyrantgit/ExplosionField</item>\n        <item>https://github.com/expo/expo</item>\n        <item>https://exponea.com</item>\n        <item>https://exponea.com</item>\n        <item>https://exponea.com</item>\n        <item>https://github.com/lnikkila/ExtendedTouchView</item>\n        <item>https://www.adobe.com/devnet/xmp.html</item>\n        <item>http://incolor.cc/en/privacy.html</item>\n        <item>http://incolor.cc/en/privacy.html</item>\n        <item>https://github.com/KyuubiRan/EzXHelper</item>\n        <item>https://gitlab.com/fdroid/privileged-extension/</item>\n        <item>https://docs.mobage.com/display/GLHOME</item>\n        <item>https://github.com/JorgeCastilloPrz/FABProgressCircle</item>\n        <item>https://github.com/JorgeCastilloPrz/FABProgressCircle</item>\n        <item>https://github.com/JorgeCastilloPrz/FABProgressCircle</item>\n        <item>https://github.com/luberda-molinet/FFImageLoading</item>\n        <item>https://github.com/tanersener/ffmpeg-kit</item>\n        <item>https://github.com/wseemann/FFmpegMediaMetadataRetriever</item>\n        <item>https://www.fluzo.com/</item>\n        <item>https://fmod.com/</item>\n        <item>https://github.com/ckurtm/FabButton</item>\n        <item>https://github.com/coyarzun89/FabTransitionActivity</item>\n        <item>https://get.fabric.io/</item>\n        <item>https://developers.facebook.com/docs/android</item>\n        <item>https://developers.facebook.com/docs/android</item>\n        <item>https://developers.facebook.com/docs/android</item>\n        <item>https://developers.facebook.com/docs/android</item>\n        <item>https://developers.facebook.com/docs/android/</item>\n        <item>https://fbflipper.com</item>\n        <item>https://github.com/facebook/facebook-android-sdk</item>\n        <item>https://developers.facebook.com/docs/android</item>\n        <item>https://developers.facebook.com/docs/android</item>\n        <item>https://developers.facebook.com/docs/android</item>\n        <item>https://github.com/facebook/facebook-android-sdk</item>\n        <item>https://github.com/facebook/facebook-android-sdk</item>\n        <item>https://github.com/facebook/facebook-android-sdk</item>\n        <item>https://github.com/facebook/facebook-android-sdk</item>\n        <item>https://github.com/facebook/facebook-android-sdk</item>\n        <item>https://github.com/facebook/facebook-android-sdk</item>\n        <item>https://github.com/facebook/facebook-android-sdk</item>\n        <item>https://github.com/facebook/facebook-android-sdk</item>\n        <item>https://developers.facebook.com/docs/android</item>\n        <item>https://developers.facebook.com/docs/unity/</item>\n        <item>https://www.factual.com</item>\n        <item>https://www.factual.com</item>\n        <item>https://github.com/ManuelPeinado/FadingActionBar</item>\n        <item>https://github.com/faruktoptas/FancyShowCaseView</item>\n        <item>https://github.com/Shashank02051997/FancyToast-Android</item>\n        <item>https://github.com/medyo/Fancybuttons</item>\n        <item>https://github.com/amitshekhariitbhu/Fast-Android-Networking</item>\n        <item>https://github.com/mikepenz/FastAdapter</item>\n        <item>https://github.com/mikepenz/FastAdapter</item>\n        <item>https://github.com/DylanVann/react-native-fast-image</item>\n        <item>https://github.com/lihaoyi/fastparse</item>\n        <item>https://github.com/L4Digital/FastScroll</item>\n        <item>https://github.com/Mixiaoxiao/FastScroll-Everywhere</item>\n        <item>https://github.com/jaredrummler/FastScroll-RecyclerView</item>\n        <item>https://github.com/AndroidDeveloperLB/FastScrollerAndRecyclerViewFixes</item>\n        <item>https://github.com/FasterXML/jackson-core</item>\n        <item>https://github.com/zsoltherpai/feather</item>\n        <item>https://github.com/tonyofrancis/Fetch</item>\n        <item>https://www.fidzup.com/</item>\n        <item>https://github.com/fidesmo/nordpol</item>\n        <item>https://github.com/halfhp/fig</item>\n        <item>https://fiksu.com/</item>\n        <item>https://github.com/google/filament</item>\n        <item>https://github.com/RustamG/file-dialogs</item>\n        <item>https://github.com/miguelpruivo/flutter_file_picker</item>\n        <item>https://github.com/archos-sa/aos-FileCoreLibrary</item>\n        <item>https://github.com/donmor/FileDialog</item>\n        <item>https://github.com/lingochamp/FileDownloader</item>\n        <item>https://github.com/TutorialsAndroid/FilePicker</item>\n        <item>https://github.com/c1710/filemojicompat</item>\n        <item>http://findbugs.sourceforge.net/</item>\n        <item>https://github.com/PicnicSupermarket/FingerPaintView</item>\n        <item>https://github.com/PicnicSupermarket/FingerPaintView</item>\n        <item>https://github.com/multidots/android-fingerprint-authentication/</item>\n        <item>https://github.com/uccmawei/FingerprintIdentify</item>\n        <item>https://firebase.google.com/</item>\n        <item>https://firebase.google.com/</item>\n        <item>https://firebase.google.com/</item>\n        <item>https://firebase.google.com/</item>\n        <item>https://firebase.google.com/</item>\n        <item>https://firebase.google.com/</item>\n        <item>https://firebase.google.com/</item>\n        <item>https://firebase.google.com/</item>\n        <item>https://firebase.google.com/</item>\n        <item>https://firebase.google.com/</item>\n        <item>https://firebase.google.com/</item>\n        <item>https://firebase.google.com/</item>\n        <item>https://firebase.google.com/</item>\n        <item>https://firebase.google.com/</item>\n        <item>https://firebase.google.com/</item>\n        <item>https://firebase.google.com/</item>\n        <item>https://firebase.google.com/</item>\n        <item>https://firebase.google.com/</item>\n        <item>https://firebase.google.com/</item>\n        <item>https://firebase.google.com/</item>\n        <item>https://github.com/firebase/firebase-android-sdk/tree/master/transport</item>\n        <item>https://github.com/firebase/firebase-android-sdk/tree/master/firebase-installations</item>\n        <item>https://github.com/firebase/firebase-jobdispatcher-android</item>\n        <item>https://github.com/firebase/FirebaseUI-Android</item>\n        <item>https://github.com/sangcomz/FishBun</item>\n        <item>https://github.com/google/flatbuffers</item>\n        <item>http://flatironmedia.com</item>\n        <item>https://github.com/lytefast/flex-input</item>\n        <item>https://github.com/houxg/FlexLayout</item>\n        <item>https://github.com/google/flexbox-layout</item>\n        <item>https://github.com/projectdelta6/FlexiLogger</item>\n        <item>https://github.com/davideas/FlexibleAdapter</item>\n        <item>https://github.com/davideas/FlexibleAdapter</item>\n        <item>https://github.com/davideas/FlexibleAdapter</item>\n        <item>https://github.com/daquexian/FlexibleRichTextView</item>\n        <item>https://github.com/davideas/FlipView</item>\n        <item>https://github.com/facebook/flipper</item>\n        <item>https://github.com/AlexLiuSheng/FloatView</item>\n        <item>https://github.com/leinardi/FloatingActionButtonSpeedDial</item>\n        <item>https://github.com/arimorty/floatingsearchview</item>\n        <item>https://github.com/dimorinny/floating-text-button</item>\n        <item>https://github.com/futuresimple/android-floating-action-button</item>\n        <item>https://github.com/jahirfiquitiva/FABsMenu</item>\n        <item>https://github.com/recruit-lifestyle/FloatingView</item>\n        <item>https://github.com/drakeet/Floo</item>\n        <item>https://github.com/tfcporciuncula/flow-preferences</item>\n        <item>https://github.com/ReactiveCircus/FlowBinding</item>\n        <item>https://github.com/nex3z/FlowLayout</item>\n        <item>https://github.com/flowupio/FlowUpAndroidSDK</item>\n        <item>https://flowsense.com.br/</item>\n        <item>https://voyagegroup.github.io/FluctSDK-Doc/#/</item>\n        <item>http://www.flurry.com/</item>\n        <item>http://www.flurry.com</item>\n        <item>https://github.com/iampawan/Flute-Music-Player</item>\n        <item>https://flutter.dev/</item>\n        <item>https://flutter.dev/</item>\n        <item>https://flutter.dev/</item>\n        <item>https://flutter.dev/</item>\n        <item>https://flutter.dev/</item>\n        <item>https://flutter.dev/</item>\n        <item>https://flutter.dev/</item>\n        <item>https://github.com/flutter/plugins/tree/master/packages/flutter_plugin_android_lifecycle</item>\n        <item>https://github.com/sc4v3ng3r/flutter_audio_query</item>\n        <item>https://github.com/fluttercommunity/flutter_downloader</item>\n        <item>https://github.com/BaseflowIT/flutter-geolocator/</item>\n        <item>https://github.com/pichillilorenzo/flutter_inappwebview</item>\n        <item>https://github.com/MisterJimson/flutter_keyboard_visibility</item>\n        <item>https://github.com/BaseflowIT/flutter-permission-handler/</item>\n        <item>https://github.com/erickhaendel/flutter_screen_wake</item>\n        <item>https://github.com/fluttercommunity/flutter_uploader</item>\n        <item>https://github.com/vrtdev/flutter_workmanager</item>\n        <item>https://github.com/transistorsoft/flutter_background_fetch</item>\n        <item>https://github.com/bcko/flutter_qrcode_reader</item>\n        <item>https://github.com/flutter-webrtc/flutter-webrtc</item>\n        <item>https://github.com/rmawatson/flutter_isolate</item>\n        <item>https://github.com/Justson/flying-pigeon</item>\n        <item>https://github.com/Justson/flying-pigeon</item>\n        <item>https://www.followanalytics.com</item>\n        <item>https://github.com/shamanland/fonticon</item>\n        <item>https://www.footmarks.com</item>\n        <item>https://github.com/Drabu/FormValidator</item>\n        <item>https://github.com/RedApparat/Fotoapparat</item>\n        <item>https://github.com/Fox2Code/FoxCompat</item>\n        <item>https://github.com/ncapdevi/FragNav</item>\n        <item>https://github.com/YoKeyword/Fragmentation/</item>\n        <item>https://github.com/YoKeyword/Fragmentation/</item>\n        <item>https://github.com/YoKeyword/Fragmentation/</item>\n        <item>https://github.com/jahirfiquitiva/Frames</item>\n        <item>https://github.com/RiccardoMoro/FreeDrawView</item>\n        <item>https://github.com/FreeRDP/FreeRDP</item>\n        <item>https://github.com/tiann/FreeReflection</item>\n        <item>https://github.com/tiann/FreeReflection</item>\n        <item>https://freetts.sourceforge.io/</item>\n        <item>http://freewheel.tv/</item>\n        <item>https://github.com/facebook/fresco/</item>\n        <item>https://github.com/facebook/fresco/</item>\n        <item>https://github.com/facebook/fresco/</item>\n        <item>https://github.com/facebook/fresco/</item>\n        <item>https://github.com/facebook/fresco/</item>\n        <item>https://github.com/facebook/fresco/</item>\n        <item>https://github.com/facebook/fresco/</item>\n        <item>https://github.com/facebook/fresco/</item>\n        <item>https://github.com/facebook/fresco/</item>\n        <item>https://github.com/facebook/fresco/</item>\n        <item>https://github.com/facebook/fresco/</item>\n        <item>https://github.com/facebook/fresco/</item>\n        <item>https://github.com/facebook/fresco/</item>\n        <item>https://github.com/facebook/fresco/</item>\n        <item>https://github.com/facebook/fresco/</item>\n        <item>https://github.com/facebook/fresco/</item>\n        <item>https://github.com/facebook/fresco/</item>\n        <item>https://github.com/facebook/fresco/</item>\n        <item>https://github.com/facebook/fresco/</item>\n        <item>https://github.com/facebook/fresco/</item>\n        <item>https://github.com/facebook/fresco/</item>\n        <item>https://github.com/facebook/fresco/</item>\n        <item>https://github.com/facebook/fresco/</item>\n        <item>https://github.com/facebook/fresco/</item>\n        <item>https://github.com/facebook/fresco/</item>\n        <item>https://github.com/facebook/fresco/</item>\n        <item>https://github.com/facebook/fresco/</item>\n        <item>https://github.com/facebook/fresco/</item>\n        <item>https://github.com/facebook/fresco/</item>\n        <item>https://github.com/facebook/fresco/</item>\n        <item>https://github.com/facebook/fresco/</item>\n        <item>https://github.com/stfalcon-studio/FrescoImageViewer</item>\n        <item>https://github.com/android10/frodo</item>\n        <item>https://github.com/K1rakishou/Fuck-Storage-Access-Framework</item>\n        <item>https://github.com/kittinunf/fuel</item>\n        <item>https://github.com/rtoshiro/FullscreenVideoView</item>\n        <item>https://github.com/irismod/token</item>\n        <item>https://github.com/izacus/FuzzyDateFormatter</item>\n        <item>https://www.fyber.com/</item>\n        <item>http://www.sponsorpay.com/</item>\n        <item>https://giphy.com/</item>\n        <item>https://giphy.com/</item>\n        <item>https://github.com/borisvanschooten/glesjs</item>\n        <item>http://www.generalmobi.com</item>\n        <item>http://www.generalmobi.com</item>\n        <item>http://www.generalmobi.com</item>\n        <item>http://www.generalmobi.com</item>\n        <item>http://www.generalmobi.com</item>\n        <item>http://www.generalmobi.com</item>\n        <item>http://www.generalmobi.com</item>\n        <item>http://www.generalmobi.com</item>\n        <item>http://www.generalmobi.com</item>\n        <item>http://www.generalmobi.com</item>\n        <item>http://www.generalmobi.com</item>\n        <item>http://www.generalmobi.com</item>\n        <item>http://www.generalmobi.com</item>\n        <item>http://www.generalmobi.com</item>\n        <item>http://www.generalmobi.com</item>\n        <item>http://www.generalmobi.com</item>\n        <item>http://www.generalmobi.com</item>\n        <item>http://www.generalmobi.com</item>\n        <item>http://trove.starlight-systems.com/</item>\n        <item>http://www.gomfactory.com</item>\n        <item>http://gpakorea.com/</item>\n        <item>https://www.crunchbase.com/organization/gpshopper</item>\n        <item>https://github.com/CyberAgent/android-gpuimage</item>\n        <item>https://beanfun.com/</item>\n        <item>https://docs.gamesparks.com/sdk-center/android.html</item>\n        <item>https://gameanalytics.com/features</item>\n        <item>https://developer.garmin.com/fit/overview/</item>\n        <item>https://github.com/AEFeinstein/GathererScraper</item>\n        <item>https://github.com/CodeAndMagic/GaugeView</item>\n        <item>https://github.com/mozilla/gecko</item>\n        <item>https://heatmap.gemius.com</item>\n        <item>https://github.com/CraZyLegenD/Set-Of-Useful-Kotlin-Extensions-and-Helpers/tree/master/kotlinextensions</item>\n        <item>https://geniee.co.jp/</item>\n        <item>https://github.com/genonbeta/framework-android</item>\n        <item>https://github.com/maxmind/GeoIP2-java</item>\n        <item>https://github.com/takuseno/GeoMap</item>\n        <item>https://github.com/PnX-SI/gn_mobile_core</item>\n        <item>https://github.com/PnX-SI/gn_mobile_core</item>\n        <item>https://github.com/PnX-SI/gn_mobile_core</item>\n        <item>https://github.com/PnX-SI/gn_mobile_core</item>\n        <item>https://github.com/ngageoint/geopackage-java</item>\n        <item>https://cloud4wi.com/</item>\n        <item>https://github.com/OpenSextant/geodesy</item>\n        <item>https://geographiclib.sourceforge.io/</item>\n        <item>https://github.com/george-steel/android-utils</item>\n        <item>https://github.com/thesurix/gesture-recycler</item>\n        <item>https://github.com/alexvasilkov/GestureViews</item>\n        <item>https://github.com/Cutta/GifView</item>\n        <item>https://github.com/PaperAirplane-Dev-Team/GigaGet</item>\n        <item>https://www.gigya.com/</item>\n        <item>https://gimbal.com/</item>\n        <item>https://gioui.org/</item>\n        <item>https://github.com/klinker24/Android-GiphySearch</item>\n        <item>https://github.com/javierugarte/GithubContributionsView</item>\n        <item>https://github.com/paolorotolo/GittyReporter</item>\n        <item>https://developer.android.com/jetpack/androidx/releases/glance</item>\n        <item>https://mvnrepository.com/artifact/org.glassfish.jersey</item>\n        <item>https://github.com/bumptech/glide</item>\n        <item>https://github.com/qoqa/glide-svg</item>\n        <item>https://github.com/wasabeef/glide-transformations</item>\n        <item>https://github.com/florent37/GlidePalette</item>\n        <item>https://github.com/corouteam/GlideToVectorYou</item>\n        <item>https://www.glispa.com</item>\n        <item>https://github.com/jeppeman/GloballyDynamic</item>\n        <item>https://glympse.com</item>\n        <item>https://github.com/infinum/Android-Goldfinger</item>\n        <item>https://github.com/googleapis/google-api-java-client</item>\n        <item>https://developers.google.com/ar/develop/</item>\n        <item>https://admob.google.com</item>\n        <item>https://admob.google.com</item>\n        <item>https://admob.google.com</item>\n        <item>https://admob.google.com</item>\n        <item>https://admob.google.com</item>\n        <item>https://admob.google.com</item>\n        <item>https://admob.google.com</item>\n        <item>https://admob.google.com</item>\n        <item>https://admob.google.com</item>\n        <item>https://admob.google.com</item>\n        <item>https://www.google.com/ads/</item>\n        <item>https://www.google.com/ads/</item>\n        <item>https://firebase.google.com/docs/analytics/</item>\n        <item>https://firebase.google.com/docs/analytics/</item>\n        <item>https://firebase.google.com/docs/analytics/</item>\n        <item>https://analytics.withgoogle.com/</item>\n        <item>http://developer.android.com/reference/android/net/package-summary.html</item>\n        <item>https://github.com/GoogleCloudPlatform/appengine-java-standard</item>\n        <item>https://github.com/GoogleCloudPlatform/appengine-java-standard</item>\n        <item>https://code.google.com/p/app-inventor-for-android/</item>\n        <item>https://github.com/googleapis/google-auth-library-java</item>\n        <item>https://developers.google.com/android/reference/com/google/android/gms/cast/Cast</item>\n        <item>https://cloud.google.com/logging/docs/audit/understanding-audit-logs</item>\n        <item>https://developers.google.com/android/reference/com/google/android/gms/cloudmessaging/package-summary</item>\n        <item>https://github.com/google/guava</item>\n        <item>https://github.com/googleapis/google-api-java-client-services/tree/main/clients/google-api-services-drive</item>\n        <item>https://github.com/fechanique/cordova-plugin-fcm</item>\n        <item>https://developers.google.com/android/reference/com/google/android/gms/fitness/package-summary</item>\n        <item>https://developers.google.com/cloud-messaging/</item>\n        <item>https://github.com/google/gson</item>\n        <item>https://github.com/google/guice</item>\n        <item>https://github.com/googleapis/google-api-java-client-services</item>\n        <item>https://github.com/googleapis/google-api-java-client-services</item>\n        <item>https://github.com/googleapis/google-api-java-client-services</item>\n        <item>https://github.com/googleapis/google-api-java-client-services</item>\n        <item>https://developers.google.com/ml-kit</item>\n        <item>https://developers.google.com/android/reference/com/google/android/gms/maps/GoogleMap</item>\n        <item>https://developers.google.com/android/reference/com/google/android/gms/maps/GoogleMap</item>\n        <item>https://github.com/flutter/plugins/tree/master/packages/google_maps_flutter/google_maps_flutter</item>\n        <item>https://github.com/material-components/material-components-android</item>\n        <item>https://developers.google.com/android/reference/com/google/android/gms/package-summary</item>\n        <item>https://developers.google.com/android/reference/com/google/android/gms/package-summary</item>\n        <item>https://developers.google.com/android/reference/com/google/android/gms/package-summary</item>\n        <item>https://play.google.com/</item>\n        <item>https://developer.android.com/google/play/billing</item>\n        <item>https://developer.android.com/guide/playcore</item>\n        <item>https://github.com/google/play-services-plugins/tree/master/oss-licenses-plugin</item>\n        <item>https://play.google.com/</item>\n        <item>https://github.com/google/private-compute-services</item>\n        <item>https://github.com/google/protobuf</item>\n        <item>https://www.google.com/analytics/tag-manager/</item>\n        <item>https://www.google.com/analytics/tag-manager/</item>\n        <item>https://github.com/ProtonMail/gopenpgp</item>\n        <item>https://www.grab.com/sg/merchant/food/</item>\n        <item>https://github.com/lopspower/GradientView</item>\n        <item>https://github.com/appsthatmatter/GraphView</item>\n        <item>https://gravyanalytics.com</item>\n        <item>https://greedygame.com/advertiser/</item>\n        <item>https://github.com/cyrilmottier/GreenDroid</item>\n        <item>https://greenrobot.com/about/</item>\n        <item>https://www.groundtruth.com</item>\n        <item>https://growing.io/</item>\n        <item>https://growthpush.com/</item>\n        <item>https://growthpush.com/</item>\n        <item>https://github.com/julman99/gson-fire</item>\n        <item>https://github.com/guardianproject/cacheword</item>\n        <item>https://github.com/guardianproject/IOCipher</item>\n        <item>https://github.com/guardianproject/IOCipher</item>\n        <item>https://github.com/guardianproject/NetCipher</item>\n        <item>https://github.com/guardianproject/PanicKit</item>\n        <item>https://developer.huawei.com/consumer/en/</item>\n        <item>https://github.com/martin-stone/hsv-alpha-color-picker-android</item>\n        <item>https://developer.huawei.com/consumer/en/codelab/HMSInAppPurchase/index.html</item>\n        <item>https://github.com/MagicMicky/HabitRPGAndroidWrapper</item>\n        <item>https://github.com/damnhandy/Handy-URI-Templates</item>\n        <item>https://github.com/huxq17/HandyGridView</item>\n        <item>https://github.com/irismod/htlc</item>\n        <item>https://github.com/ihimanshurawat/Hasher</item>\n        <item>https://github.com/greenfrvr/hashtag-view</item>\n        <item>https://github.com/futuredapp/hauler</item>\n        <item>https://github.com/orhanobut/hawk</item>\n        <item>https://github.com/fusesource/hawtjni</item>\n        <item>https://github.com/square/haha</item>\n        <item>https://github.com/esaulpaugh/headlong</item>\n        <item>https://docs.heapanalytics.com/docs/installation</item>\n        <item>https://github.com/lecho/hellocharts-android</item>\n        <item>https://www.helpshift.com</item>\n        <item>https://github.com/facebook/hermes</item>\n        <item>https://herow.io/</item>\n        <item>https://brand.heytap.com/en/index.html</item>\n        <item>https://brand.heytap.com/en/index.html</item>\n        <item>https://www.heyzap.com</item>\n        <item>https://www.heyzap.com</item>\n        <item>https://github.com/carrotsearch/hppc</item>\n        <item>https://github.com/pyamsoft/highlander</item>\n        <item>https://github.com/PDDStudio/highlightjs-android</item>\n        <item>https://github.com/hivemq/hivemq-mqtt-client</item>\n        <item>https://github.com/hjson/hjson-java</item>\n        <item>https://github.com/DeweyReed/HmsPickerView</item>\n        <item>https://github.com/bitstadium/hockeysdk-android</item>\n        <item>https://github.com/HokoFly/HokoBlur</item>\n        <item>https://github.com/Androguide/HoloGraphLibrary</item>\n        <item>https://www.hot-mob.com/hotmob-sdk/</item>\n        <item>https://www.houndify.com/</item>\n        <item>https://github.com/ItzNotABug/HouseAds</item>\n        <item>http://htmlcleaner.sourceforge.net/</item>\n        <item>https://github.com/ireward/compose-html</item>\n        <item>https://github.com/NightWhistler/HtmlSpanner</item>\n        <item>https://github.com/ch4rl3x/HtmlText</item>\n        <item>https://github.com/SufficientlySecure/html-textview</item>\n        <item>https://github.com/kevinsawicki/http-request</item>\n        <item>https://github.com/smarek/httpclient-android</item>\n        <item>https://github.com/smarek/httpclient-android</item>\n        <item>https://github.com/llew2011/HuaWeiVerifier</item>\n        <item>https://developer.huawei.com/consumer/en/</item>\n        <item></item>\n        <item></item>\n        <item></item>\n        <item>https://developer.huawei.com/consumer/en/hms</item>\n        <item>https://developer.huawei.com/consumer/en/hms</item>\n        <item>https://developer.huawei.com/consumer/en/hms</item>\n        <item>https://developer.huawei.com/consumer/en/hms</item>\n        <item>https://developer.huawei.com/consumer/en/hms</item>\n        <item>https://developer.huawei.com/consumer/en/hms</item>\n        <item>https://developer.huawei.com/consumer/en/hms</item>\n        <item>https://developer.huawei.com/consumer/en/hms</item>\n        <item></item>\n        <item>https://developer.huawei.com/consumer/en/</item>\n        <item>https://github.com/mfornos/humanize</item>\n        <item>https://huq.io/</item>\n        <item>https://github.com/dromara/hutool</item>\n        <item>https://github.com/hypertrack/hyperlog-android</item>\n        <item>http://hypertrack.com</item>\n        <item>http://hypertrack.com</item>\n        <item>http://hypertrack.com</item>\n        <item>https://www.hyprmx.com</item>\n        <item>https://github.com/i2p/i2p.android.base</item>\n        <item>https://iabtechlab.com/</item>\n        <item>https://iabtechlab.com/</item>\n        <item>https://iabtechlab.com/</item>\n        <item>https://iac.com</item>\n        <item>https://www.ibm.com/customer-engagement/coremetrics-software</item>\n        <item>https://acoustic.co/</item>\n        <item>https://acoustic.co/</item>\n        <item>https://acoustic.co/</item>\n        <item>https://acoustic.co/</item>\n        <item>https://inca.co.kr/en/index.html</item>\n        <item>http://igg.com/</item>\n        <item>http://igg.com/</item>\n        <item>http://igg.com/</item>\n        <item>http://igg.com/</item>\n        <item>http://igg.com/</item>\n        <item>http://igg.com/</item>\n        <item>https://github.com/Bilibili/ijkplayer</item>\n        <item>https://www.infonline.de</item>\n        <item>https://github.com/iotaledger/iota.lib.java/</item>\n        <item>https://github.com/seancfoley/IPAddress</item>\n        <item>https://www.ipqualityscore.com</item>\n        <item>https://github.com/ipinfo/java</item>\n        <item>https://github.com/pubnative/iqv-android-sdk-demo</item>\n        <item>https://iqzone.com</item>\n        <item>https://docs.aws.amazon.com/ivs/</item>\n        <item>https://github.com/frankiesardo/icepick</item>\n        <item>https://github.com/maltaisn/icondialoglib</item>\n        <item>https://github.com/maltaisn/icondialoglib</item>\n        <item>https://github.com/JoanZapata/android-iconify</item>\n        <item>https://github.com/JoanZapata/android-iconify</item>\n        <item>https://github.com/donpark/identicon</item>\n        <item>https://www.lookout.com/blog/igexin-malicious-sdk</item>\n        <item>https://github.com/Dhaval2404/ImagePicker</item>\n        <item>https://github.com/flutter/plugins/tree/master/packages/image_picker</item>\n        <item>https://github.com/nguyenhoanglam/ImagePicker</item>\n        <item>https://github.com/sephiroth74/ImageViewZoom</item>\n        <item>https://github.com/gyf-dev/ImmersionBar</item>\n        <item>https://github.com/Kotlin/kotlinx.collections.immutable</item>\n        <item>https://inloco.com.br</item>\n        <item>https://github.com/proyecto26/react-native-inappbrowser</item>\n        <item>https://www.inbrain.ai/</item>\n        <item>https://inmarket.com/</item>\n        <item>http://inmobi.com</item>\n        <item>http://inmobi.com</item>\n        <item>https://github.com/slockit/in3-c/</item>\n        <item>https://github.com/slockit/in3-c/</item>\n        <item>https://github.com/slockit/in3-c/</item>\n        <item>https://github.com/reddit/IndicatorFastScroll</item>\n        <item>http://www.indooratlas.com/</item>\n        <item>https://github.com/facebook/infer</item>\n        <item>https://github.com/antonyt/InfiniteViewPager</item>\n        <item>https://github.com/Devlight/InfiniteCycleViewPager</item>\n        <item>https://github.com/kohesive/injekt</item>\n        <item>https://github.com/simplifycom/ink-android</item>\n        <item>https://github.com/DavidPacioianu/InkPageIndicator</item>\n        <item>https://www.crunchbase.com/organization/inneractive</item>\n        <item>https://github.com/RedMadRobot/input-mask-android</item>\n        <item>https://github.com/afollestad/inquiry</item>\n        <item>http://inrix.com/</item>\n        <item>https://github.com/chrisbanes/insetter</item>\n        <item>https://useinsider.com/</item>\n        <item>https://instabug.com/crash-reporting</item>\n        <item>https://instal.com/</item>\n        <item>https://instal.com/</item>\n        <item>https://instal.com/</item>\n        <item>https://instal.com/</item>\n        <item>https://instal.com/</item>\n        <item>https://instal.com/</item>\n        <item>http://instreamatic.com/</item>\n        <item>https://integralads.com</item>\n        <item>https://github.com/JetBrains/intellij-community</item>\n        <item>https://github.com/JetBrains/intellij-community/tree/master/plugins/java-decompiler</item>\n        <item>https://github.com/irismod/service</item>\n        <item>https://github.com/intercom/intercom-android</item>\n        <item>https://github.com/intercom/intercom-android</item>\n        <item>https://www-01.ibm.com/software/globalization/icu/</item>\n        <item>https://github.com/ethlo/itu</item>\n        <item>https://developer.android.com/jetpack/androidx/releases/interpolator</item>\n        <item>http://www.intrasonics.com/</item>\n        <item>http://intromi.co</item>\n        <item>https://github.com/invertase/react-native-firebase</item>\n        <item>https://github.com/driftyco/ionic-plugin-keyboard</item>\n        <item>https://github.com/driftyco/ionic-plugin-keyboard</item>\n        <item>https://github.com/ionic-team/cordova-plugin-ionic-webview</item>\n        <item>https://github.com/mikepenz/ItemAnimators</item>\n        <item>https://github.com/google/j2objc</item>\n        <item>https://github.com/eclipsesource/j2v8</item>\n        <item>http://jaadec.sourceforge.net/</item>\n        <item>https://github.com/skylot/jadx</item>\n        <item>https://mvnrepository.com/artifact/javax.xml.bind/jaxb-api/2.4.0-b180830.0359</item>\n        <item>http://www.jthink.net/jaudiotagger/</item>\n        <item>https://github.com/jbox2d/jbox2d</item>\n        <item>https://jcifs.samba.org/</item>\n        <item>https://github.com/stephenc/jcip-annotations</item>\n        <item>https://github.com/JCTools/JCTools</item>\n        <item>https://www.freeutils.net/source/jcharset/</item>\n        <item>https://github.com/jcodec/jcodec</item>\n        <item>https://jcommander.org/</item>\n        <item>http://www.jdom.org/</item>\n        <item>http://www.jdom.org/</item>\n        <item>https://github.com/jdeferred/jdeferred</item>\n        <item>https://wiki.eclipse.org/JFace</item>\n        <item>https://github.com/opencollab/jlatexmath</item>\n        <item>https://gitlab.com/ICM-VisLab/JLargeArrays</item>\n        <item>https://github.com/noties/jlatexmath-android</item>\n        <item>https://github.com/samskivert/jmustache</item>\n        <item>https://github.com/java-native-access/jna</item>\n        <item>https://github.com/roc-streaming/roc-java</item>\n        <item>https://github.com/rotilho/jnano-commons</item>\n        <item>https://jopt-simple.github.io/jopt-simple/</item>\n        <item>https://github.com/mattbdean/JRAW</item>\n        <item>https://github.com/stleary/JSON-java</item>\n        <item>https://github.com/hidekatsu-izuno/jsonic</item>\n        <item>http://www.jcraft.com/jsch/</item>\n        <item>https://github.com/Cue/jsnappy</item>\n        <item>https://github.com/kruton/jsocks</item>\n        <item>https://github.com/javabeanz/jstribog</item>\n        <item>https://github.com/crosswire/jsword</item>\n        <item>https://github.com/crosswire/jsword</item>\n        <item>https://sourceforge.net/projects/jts-topo-suite/</item>\n        <item>https://sourceforge.net/projects/jts-topo-suite/</item>\n        <item>https://github.com/kamranzafar/jtar</item>\n        <item>https://github.com/jtidy/jtidy</item>\n        <item>https://github.com/wendykierp/JTransforms</item>\n        <item>https://github.com/edmund-wagner/junrar</item>\n        <item>https://jwplayer.com</item>\n        <item>https://github.com/auth0/JWTDecode.Android</item>\n        <item>https://github.com/igniterealtime/jxmpp</item>\n        <item>http://www.jcraft.com/jzlib/</item>\n        <item>https://github.com/codehaus/jackson</item>\n        <item>https://github.com/GantMan/jail-monkey</item>\n        <item>https://attic.apache.org/projects/jakarta-oro.html</item>\n        <item>https://attic.apache.org/projects/jakarta-regexp.html</item>\n        <item>https://en.wikipedia.org/wiki/Janrain</item>\n        <item>https://en.wikipedia.org/wiki/Janrain</item>\n        <item>https://en.wikipedia.org/wiki/Janrain</item>\n        <item>https://github.com/aellerton/japng</item>\n        <item>https://github.com/Jaspersoft/js-android-sdk</item>\n        <item>https://github.com/TakWolf/Java-MorseCoder</item>\n        <item>https://github.com/tananaev/adblib</item>\n        <item>https://github.com/googleapis/google-api-java-client-services</item>\n        <item>https://github.com/googleapis/google-api-java-client-services</item>\n        <item>https://github.com/googleapis/google-api-java-client-services</item>\n        <item>https://github.com/googleapis/google-api-java-client-services</item>\n        <item>https://github.com/jaytaylor/jaws</item>\n        <item>http://krum.rz.uni-mannheim.de/jas-2.0/</item>\n        <item>https://github.com/hoijui/arity</item>\n        <item>https://github.com/jacoco/jacoco</item>\n        <item>http://math.hws.edu/javamath/</item>\n        <item>http://jexcelapi.sourceforge.net/</item>\n        <item>https://github.com/hamcrest/JavaHamcrest</item>\n        <item>https://github.com/jwtk/jjwt</item>\n        <item>https://github.com/sannies/mp4parser</item>\n        <item>https://github.com/ktuukkan/marine-api</item>\n        <item>https://en.wikipedia.org/wiki/Non-blocking_I/O_(Java)</item>\n        <item>https://github.com/jnr/jnr-constants</item>\n        <item>https://github.com/jnr/jnr-constants</item>\n        <item>https://github.com/guardian/Option</item>\n        <item>https://github.com/zafarkhaja/jsemver</item>\n        <item>https://wrapper.tanukisoftware.com/doc/english/product-overview.html</item>\n        <item>https://developer.android.com/reference/java/util/stream/package-summary</item>\n        <item>http://www.freeutils.net/source/jtnef/</item>\n        <item>https://github.com/TooTallNate/Java-WebSocket</item>\n        <item>https://github.com/rh-id/concurrent-utils</item>\n        <item>https://github.com/andresoviedo/java-utilities</item>\n        <item>https://github.com/xamarin/java.interop</item>\n        <item>http://www.oracle.com/technetwork/java/javase/jaf-135115.html</item>\n        <item>http://java.sun.com/javase/technologies/desktop/javabeans/jaf/index.jsp</item>\n        <item>http://www.oracle.com/technetwork/java/javamail/index.html</item>\n        <item>https://github.com/JavaMoney/jsr354-api</item>\n        <item>https://github.com/FazziCLAY/JavaNeoUtil</item>\n        <item>https://github.com/square/javapoet</item>\n        <item>https://github.com/Backblaze/JavaReedSolomon</item>\n        <item>https://github.com/javaee/jsonp</item>\n        <item>http://github.com/square/javawriter/</item>\n        <item>http://github.com/square/javawriter/</item>\n        <item>https://github.com/xdrop/fuzzywuzzy</item>\n        <item>https://github.com/xdrop/fuzzywuzzy</item>\n        <item>https://github.com/amaembo/jsr-305/tree/master/ri</item>\n        <item>https://docs.oracle.com/javame/config/cldc/opt-pkgs/api/bluetooth/jsr082/javax/obex/package-summary.html</item>\n        <item>https://docs.oracle.com/javaee/6/api/javax/inject/package-summary.html</item>\n        <item>http://docs.oracle.com/javame/config/cldc/ref-impl/midp2.0/jsr118/</item>\n        <item>https://www.jcp.org/en/jsr/detail\\?id=369</item>\n        <item>https://docs.oracle.com/javaee/7/api/javax/ws/rs/package-summary.html</item>\n        <item>https://github.com/jboss-javassist/javassist</item>\n        <item>http://jaxen.org/</item>\n        <item>https://github.com/json-path/JsonPath</item>\n        <item>https://github.com/Sentaroh/JcifsFile</item>\n        <item>https://github.com/jellyfin/jellyfin-apiclient-java</item>\n        <item>https://github.com/jellyfin/jellyfin-sdk-kotlin</item>\n        <item>https://github.com/zeromq/jeromq</item>\n        <item>https://github.com/patrickgold/jetpref</item>\n        <item>https://developer.android.com/jetpack/androidx/releases/compose</item>\n        <item>https://developer.android.com/jetpack/androidx/releases/compose</item>\n        <item>https://github.com/godaddy/compose-color-picker</item>\n        <item>https://github.com/godaddy/compose-color-picker</item>\n        <item>https://github.com/SmartToolFactory/Compose-Extended-Gestures</item>\n        <item>https://android.googlesource.com/platform/frameworks/support/+/refs/heads/androidx-main/window/</item>\n        <item>https://ir.jiguang.cn/corporate-profile</item>\n        <item>https://github.com/lipangit/JiaoZiVideoPlayer</item>\n        <item>https://jitsi.github.io/handbook/docs/dev-guide/dev-guide-android-sdk</item>\n        <item>https://github.com/spotify/JniHelpers</item>\n        <item>http://www.joda.org/joda-time/</item>\n        <item>https://github.com/JodaOrg/joda-money</item>\n        <item>https://github.com/evgenyneu/js-evaluator-for-android</item>\n        <item>https://github.com/fangyidong/json-simple</item>\n        <item>https://github.com/smuyyh/JsonViewer</item>\n        <item>https://github.com/zhegexiaohuozi/JsoupXpath</item>\n        <item>https://github.com/zhegexiaohuozi/JsoupXpath</item>\n        <item>https://www.jumio.com/</item>\n        <item>http://www.millennialmedia.com</item>\n        <item>https://junit.org/junit4/</item>\n        <item>https://karte.io/</item>\n        <item>https://kidoz.net/kidoz-sdk/</item>\n        <item>https://github.com/kissmetrics/KISSmetrics-Android-SDK</item>\n        <item>https://github.com/Ekito/koin</item>\n        <item>https://github.com/fondesa/kpermissions</item>\n        <item>https://github.com/mariotaku/KPreferences</item>\n        <item>https://github.com/onurkagan/KToast</item>\n        <item>https://github.com/deva666/KValidation</item>\n        <item>https://github.com/krka/kahlua2</item>\n        <item>https://developers.kakao.com/</item>\n        <item>http://www.kakao.com/services/api/kakao_link_en</item>\n        <item>https://github.com/lingarajsankaravelu/Katex</item>\n        <item>https://keen.io</item>\n        <item>https://github.com/keenlabs/KeenClient-Java</item>\n        <item>https://github.com/keenlabs/KeenClient-Java</item>\n        <item>https://github.com/keenlabs/KeenClient-Scala</item>\n        <item>https://github.com/PhilippC/keepass2android/tree/master/src/java/Keepass2AndroidPluginSDK2</item>\n        <item>https://github.com/bpellin/keepassdroid</item>\n        <item>https://github.com/kefirfromperm/kefirbb</item>\n        <item>https://github.com/flavioarfaria/KenBurnsView</item>\n        <item>https://www.kevel.co/</item>\n        <item>https://github.com/google/keyczar</item>\n        <item>https://github.com/yshrsmz/KeyboardVisibilityEvent</item>\n        <item>https://github.com/inkytonik/kiama</item>\n        <item>https://www.ninthdecimal.com/</item>\n        <item>https://github.com/cbeust/klaxon</item>\n        <item>https://www.kochava.com/</item>\n        <item>https://www.kochava.com/</item>\n        <item>https://www.kochava.com/</item>\n        <item>https://github.com/Kodein-Framework/Kodein-DI</item>\n        <item>https://github.com/mcxiaoke/kotlin-koi</item>\n        <item>https://www.komli.com/</item>\n        <item>https://github.com/DanielMartinus/Konfetti</item>\n        <item>https://kontakt.io/</item>\n        <item>https://github.com/JetBrains/kotlin</item>\n        <item>https://github.com/JetBrains/kotlin/tree/master/plugins/android-extensions/android-extensions-runtime</item>\n        <item>https://github.com/JetBrains/kotlin/tree/master/plugins/android-extensions/android-extensions-runtime</item>\n        <item>https://github.com/JakeWharton/retrofit2-kotlin-coroutines-adapter</item>\n        <item>https://github.com/gildor/kotlin-coroutines-retrofit</item>\n        <item>https://github.com/LighthouseGames/KmLogging</item>\n        <item>https://github.com/JetBrains/kotlin</item>\n        <item>https://github.com/thomasnield/kotlin-statistics</item>\n        <item>https://github.com/gildor/kotlin-coroutines-okhttp</item>\n        <item>https://github.com/Kotlin/kotlinx.serialization</item>\n        <item>https://github.com/SalomonBrys/Kotson</item>\n        <item>https://github.com/mplatvoet/kovenant</item>\n        <item>https://github.com/2dxgujun/Kpan</item>\n        <item>https://github.com/AutSoft/Krate</item>\n        <item>https://github.com/lyft/Kronos-Android</item>\n        <item>https://www.salesforce.com/products/marketing-cloud/data-management</item>\n        <item>https://github.com/EsotericSoftware/kryo</item>\n        <item>https://github.com/ktorio/ktor</item>\n        <item>https://github.com/jahirfiquitiva/Kuper</item>\n        <item>http://www.kxml.org/</item>\n        <item>http://mindprod.com/products1.html#LEDATASTREAM</item>\n        <item>https://github.com/leonHua/LFilePicker</item>\n        <item>https://line.me/</item>\n        <item>https://www.linebiz.com/lp/line-ads-network/</item>\n        <item>https://developers.line.biz/ja/docs/android-sdk/</item>\n        <item>https://developers.line.biz/ja/docs/android-sdk/</item>\n        <item>https://line.me/en/</item>\n        <item>https://line.me/en/</item>\n        <item>https://line.me/en/</item>\n        <item>https://github.com/lz4/lz4-java</item>\n        <item>https://github.com/lz4/lz4-java</item>\n        <item>https://github.com/lz4/lz4-java</item>\n        <item>https://github.com/league/lzmajio</item>\n        <item>http://www.lab4inf.fh-muenster.de/Lab4Math/</item>\n        <item>https://github.com/guitcastro/LabelledSpinner</item>\n        <item>https://github.com/wg/codec</item>\n        <item>https://github.com/skydoves/landscapist</item>\n        <item>https://github.com/nisrulz/lantern</item>\n        <item>https://github.com/getlantern/lantern</item>\n        <item>https://github.com/getlantern/lantern-mobile</item>\n        <item>https://github.com/nitrico/LastAdapter</item>\n        <item>https://github.com/dpa99c/phonegap-launch-navigator</item>\n        <item>https://github.com/nanihadesuka/LazyColumnScrollbar</item>\n        <item>https://github.com/gabrielittner/lazythreetenbp</item>\n        <item>https://github.com/terl/lazysodium-android</item>\n        <item>https://github.com/terl/lazysodium-java</item>\n        <item>https://www.leadbolt.com</item>\n        <item>https://www.leadbolt.com</item>\n        <item>https://www.leadbolt.com</item>\n        <item>https://github.com/square/leakcanary</item>\n        <item>https://github.com/square/leakcanary</item>\n        <item>https://github.com/square/leakcanary</item>\n        <item>https://github.com/leancloud/java-sdk</item>\n        <item>https://www.leanplum.com/</item>\n        <item>https://developer.android.com/jetpack/androidx/releases/leanback</item>\n        <item>https://www.lenddo.com/</item>\n        <item>https://github.com/canelmas/let</item>\n        <item>https://github.com/dain/leveldb</item>\n        <item>https://github.com/fusesource/leveldbjni</item>\n        <item>https://github.com/zhaobozhen/LibChecker-Rules-Bundle</item>\n        <item>https://github.com/SimPrints/LibSimprints</item>\n        <item>https://code.videolan.org/videolan/vlc-android</item>\n        <item>https://www.gnu.org/software/libidn/javadoc/</item>\n        <item>https://github.com/ant-media/LibRtmp-Client-for-Android</item>\n        <item>https://github.com/LarsWerkman/LicenseView</item>\n        <item>https://github.com/PSDev/LicensesDialog</item>\n        <item>https://developer.android.com/jetpack/androidx/releases/lifecycle</item>\n        <item>https://liftoff.io/</item>\n        <item>http://ligatus.com</item>\n        <item>http://ligatus.com</item>\n        <item>http://ligatus.com</item>\n        <item>https://github.com/lightningnetwork/lnd</item>\n        <item>https://github.com/aNNiMON/Lightweight-Stream-API</item>\n        <item>https://github.com/serso/android-linear-layout-manager</item>\n        <item>https://github.com/YarikSOffice/lingver</item>\n        <item>https://github.com/LiquidPlayer/LiquidCore</item>\n        <item>https://github.com/Chrisvin/LiquidSwipe</item>\n        <item>http://lisnr.com</item>\n        <item>https://github.com/nhaarman/ListViewAnimations</item>\n        <item>https://github.com/LitePalFramework/LitePal</item>\n        <item>https://github.com/facebook/litho</item>\n        <item>https://github.com/adamfisk/LittleProxy</item>\n        <item>https://github.com/hadilq/LiveEvent</item>\n        <item>https://github.com/liveservices/LiveSDK-for-Android</item>\n        <item>https://github.com/JeremyLiao/LiveEventBus</item>\n        <item>https://developer.android.com/jetpack/androidx/releases/loader</item>\n        <item>https://github.com/yanzhenjie/Loading</item>\n        <item>https://github.com/twofortyfouram/android-plugin-client-sdk-for-locale</item>\n        <item>http://localytics.com</item>\n        <item>http://localytics.com</item>\n        <item>http://localytics.com</item>\n        <item>https://github.com/asamm/locus-api</item>\n        <item>http://locuslabs.com/</item>\n        <item>https://github.com/AndreaCioccarelli/LogKit</item>\n        <item>https://github.com/bluelinelabs/LoganSquare</item>\n        <item>http://logback.qos.ch/</item>\n        <item>https://github.com/orhanobut/logger</item>\n        <item>http://loggly.com/</item>\n        <item>http://loggly.com/</item>\n        <item>http://loggly.com/</item>\n        <item>https://loopme.com/</item>\n        <item>https://github.com/mapzen/lost</item>\n        <item>https://github.com/mapzen/lost</item>\n        <item>http://lotadata.com</item>\n        <item>https://www.lotame.com/</item>\n        <item>https://github.com/airbnb/lottie-android</item>\n        <item>https://github.com/react-native-community/lottie-react-native</item>\n        <item>https://github.com/igreenwood/loupe</item>\n        <item>https://github.com/yarolegovich/LovelyDialog</item>\n        <item>https://github.com/luaj/luaj</item>\n        <item>https://github.com/SpaceMadness/lunar-unity-console</item>\n        <item>https://github.com/pedrovgs/Lynx</item>\n        <item>http://madvertise.com</item>\n        <item>http://madvertise.com</item>\n        <item>http://madvertise.com</item>\n        <item>http://mdotm.com/</item>\n        <item>https://www.megvii.com/</item>\n        <item>https://developers.google.com/ml-kit/</item>\n        <item>https://github.com/Tencent/MMKV</item>\n        <item>https://www.mocaplatform.com/</item>\n        <item>https://github.com/PhilJay/MPAndroidChart</item>\n        <item>https://github.com/christianrowlands/android-mqtt-connection-lib</item>\n        <item>https://github.com/OfficeDev/msa-auth-for-android</item>\n        <item>https://github.com/d4rken/mvp-bakery</item>\n        <item>https://www.madhouse-media.com/</item>\n        <item>https://github.com/bloderxd/MagicButton</item>\n        <item>https://github.com/hackware1993/MagicIndicator</item>\n        <item>http://mail.ru</item>\n        <item>http://mail.ru</item>\n        <item>https://there-is-no-website.com</item>\n        <item>https://there-is-no-website.com</item>\n        <item>https://there-is-no-website.com</item>\n        <item>https://there-is-no-website.com</item>\n        <item>https://there-is-no-website.com</item>\n        <item>https://there-is-no-website.com</item>\n        <item>https://there-is-no-website.com</item>\n        <item>https://there-is-no-website.com</item>\n        <item>https://there-is-no-website.com</item>\n        <item>https://there-is-no-website.com</item>\n        <item>https://there-is-no-website.com</item>\n        <item>https://there-is-no-website.com</item>\n        <item>https://there-is-no-website.com</item>\n        <item>https://there-is-no-website.com</item>\n        <item>https://there-is-no-website.com</item>\n        <item>https://there-is-no-website.com</item>\n        <item>https://there-is-no-website.com</item>\n        <item>https://there-is-no-website.com</item>\n        <item>http://there-is-no-website.nowebsite</item>\n        <item>http://there-is-no-website.nowebsite</item>\n        <item>http://there-is-no-website.nowebsite</item>\n        <item>http://there-is-no-website.nowebsite</item>\n        <item>http://there-is-no-website.nowebsite</item>\n        <item>http://there-is-no-website.nowebsite</item>\n        <item>http://there-is-no-website.nowebsite</item>\n        <item>http://there-is-no-website.nowebsite</item>\n        <item>http://there-is-no-website.nowebsite</item>\n        <item>http://there-is-no-website.nowebsite</item>\n        <item>http://there-is-no-website.nowebsite</item>\n        <item>http://there-is-no-website.nowebsite</item>\n        <item>https://spaceroots.org/mantissa-doc/overview-summary.html</item>\n        <item>http://www.mapdb.org/</item>\n        <item>https://www.mapbox.com/</item>\n        <item>https://www.mapbox.com/</item>\n        <item>https://www.mapbox.com/</item>\n        <item>https://www.mapbox.com/android-sdk/</item>\n        <item>https://docs.mapbox.com/android/maps/overview/</item>\n        <item>https://docs.mapbox.com/android/maps/overview/</item>\n        <item>https://github.com/googlemaps/android-maps-utils</item>\n        <item>https://github.com/mapsforge/mapsforge</item>\n        <item>https://github.com/zzhoujay/Markdown</item>\n        <item>https://github.com/falnatsheh/MarkdownView</item>\n        <item>https://code.google.com/archive/p/markdown4j/</item>\n        <item>https://github.com/myabc/markdownj</item>\n        <item>https://github.com/myabc/markdownj</item>\n        <item>https://github.com/jeziellago/compose-markdown</item>\n        <item>https://github.com/tiagohm/MarkdownView</item>\n        <item>https://github.com/mittsuu/MarkedView-for-Android</item>\n        <item>https://marketo.com</item>\n        <item>https://github.com/noties/Markwon</item>\n        <item>https://github.com/noties/Markwon</item>\n        <item>https://github.com/jrvansuita/MaterialAbout</item>\n        <item>https://github.com/saurabharora90/MaterialArcMenu</item>\n        <item>https://github.com/sephiroth74/Material-BottomNavigation</item>\n        <item>https://github.com/sephiroth74/Material-BottomNavigation</item>\n        <item>https://github.com/DamianvdB/MaterialChecklist</item>\n        <item>https://github.com/robertlevonyan/materialChipView</item>\n        <item>https://github.com/rahatarmanahmed/CircularProgressView</item>\n        <item>https://github.com/afollestad/material-cab</item>\n        <item>https://github.com/Gericop/DateTimePicker</item>\n        <item>https://github.com/wdullaer/MaterialDateTimePicker</item>\n        <item>https://github.com/afollestad/material-dialogs</item>\n        <item>https://github.com/IvBaranov/MaterialFavoriteButton</item>\n        <item>https://github.com/nbsp-team/MaterialFilePicker</item>\n        <item>https://github.com/code-mc/material-icon-lib</item>\n        <item>https://github.com/balysv/material-menu</item>\n        <item>https://github.com/fornewid/material-motion-compose</item>\n        <item>https://github.com/consp1racy/android-support-preference</item>\n        <item>https://github.com/balysv/material-ripple</item>\n        <item>https://github.com/jaredrummler/MaterialSpinner</item>\n        <item>https://github.com/sjwall/MaterialTapTargetPrompt</item>\n        <item>https://github.com/tommybuonomo/dotsindicator</item>\n        <item>https://github.com/Applandeo/Material-Calendar-View</item>\n        <item>https://github.com/ronaldsmartin/Material-ViewPagerIndicator</item>\n        <item>https://github.com/pnikosis/materialish-progress</item>\n        <item>https://github.com/borax12/MaterialDateRangePicker</item>\n        <item>https://github.com/mikepenz/MaterialDrawer</item>\n        <item>https://github.com/rengwuxian/MaterialEditText</item>\n        <item>https://github.com/riggaroo/MaterialIntroTutorial</item>\n        <item>https://github.com/rey5137/material</item>\n        <item>https://github.com/lsjwzh/MaterialLoadingProgressBar</item>\n        <item>https://github.com/KasualBusiness/MaterialNumberPicker</item>\n        <item>https://github.com/OHoussein/android-material-play-pause-view</item>\n        <item>https://github.com/RikkaW/MaterialPreference/</item>\n        <item>https://github.com/AndroidDeveloperLB/MaterialPreferenceLibrary</item>\n        <item>https://github.com/yarolegovich/MaterialPreferences</item>\n        <item>https://github.com/zhanghai/MaterialProgressBar</item>\n        <item>https://github.com/oli107/material-range-bar</item>\n        <item>https://github.com/zhanghai/MaterialRatingBar</item>\n        <item>https://github.com/turing-tech/MaterialScrollBar</item>\n        <item>https://github.com/MiguelCatalan/MaterialSearchView</item>\n        <item>https://github.com/MrBIMC/MaterialSeekBarPreference</item>\n        <item>https://github.com/gowong/material-sheet-fab</item>\n        <item>https://github.com/deano2390/MaterialShowcaseView</item>\n        <item>https://github.com/javiersantos/MaterialStyledDialogs</item>\n        <item>https://github.com/yanzm/MaterialTabHost</item>\n        <item>https://github.com/NickAndroid/MaterialTile_Android</item>\n        <item>https://github.com/tanallnight/MaterialTutorial</item>\n        <item>https://github.com/florent37/MaterialViewPager</item>\n        <item>https://github.com/XayahSuSuSu/Android-MaterialYouFileExplorer</item>\n        <item>https://github.com/mikepenz/Materialize</item>\n        <item>https://github.com/mariuszgromada/MathParser.org-mXparser</item>\n        <item>https://github.com/kexanie/MathView</item>\n        <item>https://github.com/zhihu/Matisse</item>\n        <item>https://matomo.org/mobile</item>\n        <item>https://matomo.org/mobile</item>\n        <item>https://matomo.org/mobile</item>\n        <item>https://matomo.org/mobile</item>\n        <item>https://matrix.org/docs/projects/sdk/matrix-org-android-sdk/</item>\n        <item>https://github.com/airbnb/mavericks</item>\n        <item>https://github.com/bskim45/MaxHeightScrollView</item>\n        <item>https://github.com/maxmind/MaxMind-DB-Reader-java</item>\n        <item>https://developer.android.com/jetpack/androidx/releases/media</item>\n        <item>https://developer.android.com/training/home-channels/video</item>\n        <item>https://developer.android.com/jetpack/androidx/releases/media2</item>\n        <item>https://github.com/MediaFire/mediafire-java-sdk</item>\n        <item>https://github.com/archos-sa/aos-MediaLib</item>\n        <item>https://github.com/archos-sa/aos-MediaLib</item>\n        <item>https://github.com/archos-sa/aos-MediaLib</item>\n        <item>https://github.com/mariotaku/MediaViewerLibrary</item>\n        <item>https://developer.android.com/jetpack/androidx/releases/mediarouter</item>\n        <item>https://github.com/ge0rg/MemorizingTrustManager</item>\n        <item>https://github.com/SimonVT/android-menudrawer</item>\n        <item>https://github.com/mariotaku/MessageBubbleView</item>\n        <item>https://github.com/msgpack/msgpack-java</item>\n        <item>http://www.metaps.com</item>\n        <item>http://metrics.dropwizard.io/</item>\n        <item>http://www.mezzomedia.co.kr/m/</item>\n        <item>http://www.mezzomedia.co.kr/m/</item>\n        <item>http://www.mezzomedia.co.kr/m/</item>\n        <item>http://www.mezzomedia.co.kr/m/</item>\n        <item>https://github.com/brsanthu/migbase64</item>\n        <item>https://microblink.com/</item>\n        <item>https://github.com/tisoft/microemu</item>\n        <item>https://docs.microsoft.com/en-us/appcenter/analytics/</item>\n        <item>https://docs.microsoft.com/en-us/appcenter/sdk/</item>\n        <item>https://github.com/AzureAD/microsoft-authentication-library-for-android</item>\n        <item>https://github.com/AzureAD/azure-activedirectory-library-for-android</item>\n        <item>https://github.com/Microsoft/mobile-center-sdk-android </item>\n        <item></item>\n        <item>https://github.com/microsoftgraph/msgraph-sdk-java</item>\n        <item>https://mvnrepository.com/artifact/com.microsoft.identity.client</item>\n        <item>http://www.microsoft.com/mappoint/</item>\n        <item>https://github.com/Microsoft/mobile-center-sdk-android </item>\n        <item>https://github.com/Microsoft/mobile-center-sdk-android </item>\n        <item>https://appcenter.ms/</item>\n        <item>https://appcenter.ms/</item>\n        <item>https://appcenter.ms/</item>\n        <item>https://github.com/billthefarmer/mididriver</item>\n        <item>https://www.millennialmedia.com/</item>\n        <item>https://github.com/antoniom/Millisecond-Chronometer</item>\n        <item>https://github.com/square/mimecraft</item>\n        <item>https://github.com/minio/minio-java</item>\n        <item>https://github.com/EsotericSoftware/minlog</item>\n        <item>https://github.com/rtreffer/minidns</item>\n        <item>https://community.kde.org/Necessitas</item>\n        <item>https://www.mintegral.com/en/</item>\n        <item>https://www.mintegral.com/en/</item>\n        <item>https://mixpanel.com/</item>\n        <item>https://www.moengage.com/</item>\n        <item>https://developers.momo.vn/#/</item>\n        <item>http://www.mopub.com/</item>\n        <item>https://moat.com/analytics</item>\n        <item>https://moat.com/analytics</item>\n        <item>https://www.mobfox.com/</item>\n        <item>https://www.mobfox.com/</item>\n        <item>https://home.mobpowertech.com/</item>\n        <item>https://mobclick.tech/</item>\n        <item>https://docs.microsoft.com/en-us/azure/mobile-engagement/mobile-engagement-android-sdk-overview</item>\n        <item>https://docs.microsoft.com/en-us/azure/mobile-engagement/mobile-engagement-android-sdk-overview</item>\n        <item>https://github.com/tanersener/mobile-ffmpeg</item>\n        <item>https://github.com/KingsMentor/MobileVisionBarcodeScanner/</item>\n        <item>https://mobincube.com/</item>\n        <item>https://mobiquitynetworks.com</item>\n        <item>https://github.com/spotify/mobius</item>\n        <item>http://www.moblin.com</item>\n        <item>https://www.mobonapps.com/</item>\n        <item>https://www.mobvista.com/</item>\n        <item>https://site.mockito.org/</item>\n        <item>https://github.com/Maxr1998/ModernAndroidPreferences</item>\n        <item>https://github.com/xaverkapeller/ModularAdapter</item>\n        <item>http://mofiler.io</item>\n        <item>http://www.mojise.com/main/main.php</item>\n        <item>https://github.com/mojohaus/animal-sniffer</item>\n        <item>https://github.com/Zhuinden/realm-monarchy</item>\n        <item>https://github.com/ProtonAOSP/android_external_themelib</item>\n        <item>https://github.com/KieronQuinn/MonetCompat</item>\n        <item>https://github.com/JavaMoney/jsr354-ri-bp</item>\n        <item>https://github.com/fabiomsr/MoneyTextView</item>\n        <item>https://www.mono-project.com/docs/about-mono/supported-platforms/android/</item>\n        <item>https://us.moodmedia.com/</item>\n        <item>https://mopinion.com</item>\n        <item>https://github.com/DroidPluginTeam/DroidPlugin</item>\n        <item>https://github.com/sockeqwe/mosby</item>\n        <item>https://github.com/square/moshi</item>\n        <item>https://github.com/Arello-Mobile/Moxy</item>\n        <item></item>\n        <item>https://github.com/mozilla-mobile/android-components</item>\n        <item>https://github.com/mozilla/rhino</item>\n        <item>https://github.com/mozilla/rhino</item>\n        <item>https://wiki.mozilla.org/Telemetry</item>\n        <item>https://wiki.mozilla.org/Telemetry</item>\n        <item>https://wiki.mozilla.org/Telemetry</item>\n        <item>https://wiki.mozilla.org/Telemetry</item>\n        <item>https://wiki.mozilla.org/Telemetry</item>\n        <item>https://github.com/ArtifexSoftware/mupdf</item>\n        <item>https://github.com/lovetuzitong/MultiImageSelector</item>\n        <item>https://github.com/open-rnd/android-multi-level-listview</item>\n        <item>https://github.com/abumoallim/Android-Multi-Select-Dialog</item>\n        <item>https://github.com/Kennyc1012/MultiStateView</item>\n        <item>https://github.com/drakeet/MultiType</item>\n        <item>https://github.com/fishwjy/MultiType-FilePicker</item>\n        <item>https://github.com/mariotaku/MultiValueSwitch</item>\n        <item>https://github.com/andremion/Music-Cover-View</item>\n        <item>https://github.com/romannurik/muzei</item>\n        <item></item>\n        <item>https://github.com/chanmratekoko/mmcalendar</item>\n        <item>https://github.com/Mygod/mygod-lib-android</item>\n        <item>https://github.com/skjolber/ndef-tools-for-android</item>\n        <item>https://github.com/NIFCLOUD-mbaas/ncmb_android</item>\n        <item>https://github.com/hootsuite/nachos</item>\n        <item>https://github.com/informramiz/NameInitialsCircleImageView</item>\n        <item>https://github.com/NanoHttpd/nanohttpd</item>\n        <item>https://github.com/AAkira/Napier</item>\n        <item>https://github.com/nativescript-community/ui-collectionview</item>\n        <item>https://github.com/NativeScript/tns-core-modules-widgets</item>\n        <item>https://github.com/nativescript/nativescript-imagepicker</item>\n        <item>https://github.com/tjvantoll/nativescript-social-share</item>\n        <item>https://github.com/triniwiz/nativescript-couchbase-plugin</item>\n        <item>http://www.nativex.com/</item>\n        <item>https://github.com/nativescript-community/sqlite</item>\n        <item>https://github.com/nativescript-community/sqlite</item>\n        <item>https://github.com/ZieIony/NaturalDateFormat</item>\n        <item>https://developer.android.com/jetpack/androidx/releases/navigation</item>\n        <item>https://github.com/hugotomazi/navigation-bar</item>\n        <item>https://github.com/FazziCLAY/NeoSocket</item>\n        <item>https://github.com/MegatronKing/NetBare</item>\n        <item>https://github.com/M66B/NetGuard</item>\n        <item>https://www.netvelocity.net/</item>\n        <item>https://www.netvelocity.net/</item>\n        <item>https://github.com/schildbach/java-wns-resolver</item>\n        <item>https://github.com/schildbach/java-wns-resolver</item>\n        <item>https://github.com/schildbach/java-wns-resolver</item>\n        <item>https://github.com/netty/netty</item>\n        <item>https://github.com/playframework/netty-reactive-streams</item>\n        <item>https://github.com/facebook/network-connection-class</item>\n        <item>http://www.newrelic.com</item>\n        <item>http://www.newrelic.com</item>\n        <item>https://github.com/TeamNewPipe/NewPipeExtractor</item>\n        <item>http://www.newspic.kr/</item>\n        <item>http://nexage.com/</item>\n        <item>http://nexage.com/</item>\n        <item>https://github.com/nextcloud/Android-SingleSignOn</item>\n        <item>https://engineeringportal.nielsen.com/docs/Simplified_SDK_API</item>\n        <item>https://github.com/gesellix/Nimbus-JOSE-JWT</item>\n        <item>https://github.com/gesellix/Nimbus-JOSE-JWT</item>\n        <item>https://github.com/JakeWharton/NineOldAndroids</item>\n        <item>http://www.ninjametrics.com/</item>\n        <item>https://github.com/whataa/noDrawable</item>\n        <item>https://github.com/spacecowboy/NoNonsense-FilePicker</item>\n        <item>https://noahpass.jp/</item>\n        <item>https://github.com/alex31n/NoboButton</item>\n        <item>http://www.j2megame.org/j2meapi/Nokia_UI_API_1_1/</item>\n        <item>https://github.com/irismod/nft</item>\n        <item>https://github.com/Abhi347/NoobCameraFlash</item>\n        <item>https://github.com/shasin89/NotificationBanner</item>\n        <item>https://www.noxmobi.com/</item>\n        <item>https://github.com/davidmigloz/number-keyboard</item>\n        <item>https://github.com/thedoapp/NumberPicker</item>\n        <item>https://github.com/qinci/NumberButton</item>\n        <item>https://github.com/travijuu/NumberPicker</item>\n        <item>https://github.com/lisb/number-picker</item>\n        <item>https://github.com/invissvenska/NumberPickerPreference</item>\n        <item>https://github.com/Carbs0126/NumberPickerView</item>\n        <item>https://github.com/peteroupc/numbers-java</item>\n        <item>https://github.com/danielsz/android-oauth2-client</item>\n        <item>https://github.com/opendatakit/collect</item>\n        <item>https://github.com/opendatakit/javarosa</item>\n        <item>https://github.com/ngageoint/ogc-api-features-json-java</item>\n        <item>https://m.onestore.co.kr/mobilepoc/main/main.omp</item>\n        <item>https://github.com/mdewilde/opml-parser</item>\n        <item>https://github.com/corgrath/osbcp-css-parser</item>\n        <item>https://mvnrepository.com/artifact/org.osgi</item>\n        <item>https://osgi.org/javadoc/r6/core/index.html</item>\n        <item>https://mvnrepository.com/artifact/org.eclipse.platform/org.eclipse.osgi</item>\n        <item>https://github.com/objectbox/objectbox-java</item>\n        <item>https://github.com/mariotaku/ObjectCursor</item>\n        <item>https://github.com/easymock/objenesis</item>\n        <item>http://www.offertoro.com/</item>\n        <item>https://ogury.com/</item>\n        <item>https://ogury.com/</item>\n        <item>https://ogury.com/</item>\n        <item>https://ogury.com/</item>\n        <item>http://www.presage.io/</item>\n        <item>https://github.com/lingochamp/okdownload</item>\n        <item>https://github.com/square/okhttp</item>\n        <item>https://github.com/square/okhttp</item>\n        <item>https://github.com/square/okio</item>\n        <item>https://github.com/li-xiaojun/OkhttpDownloader</item>\n        <item>https://github.com/Evans-Cai/matrix-org_olm</item>\n        <item>https://www.adobe.com/analytics/adobe-analytics-features.html</item>\n        <item>https://www.adobe.com/analytics/adobe-analytics-features.html</item>\n        <item>https://github.com/jonfinerty/Once</item>\n        <item>https://github.com/ironSource/OneAdapter</item>\n        <item>http://www.oneaudience.com/</item>\n        <item>https://onesignal.com/</item>\n        <item>https://www.onetrust.com/</item>\n        <item>https://github.com/scottyab/OnionKit</item>\n        <item>https://github.com/moosewoler/OnyxAndroidSDK</item>\n        <item>https://www.ooyala.com/</item>\n        <item>https://github.com/iheartradio/open-m3u8</item>\n        <item>https://www.openback.com</item>\n        <item>https://opencv.org/</item>\n        <item>https://github.com/census-instrumentation/opencensus-java</item>\n        <item>https://github.com/andiwand/OpenDocument.java</item>\n        <item>https://mvnrepository.com/artifact/org.openjax.security/nacl</item>\n        <item>https://openjdk.java.net/</item>\n        <item>https://www.safegraph.com/</item>\n        <item>https://www.safegraph.com/</item>\n        <item>https://github.com/AmericanRedCross/OpenMapKitAndroid</item>\n        <item>https://github.com/AmericanRedCross/OpenMapKitAndroid</item>\n        <item>https://github.com/OpenMediationProject/OpenMediation</item>\n        <item>https://github.com/OpenMediationProject/OpenMediation</item>\n        <item>https://github.com/open-keychain/openpgp-api</item>\n        <item>https://github.com/osmdroid/osmdroid</item>\n        <item>https://opentelemetry.io/</item>\n        <item>https://opentelemetry.io/</item>\n        <item>https://github.com/opentripplanner/OpenTripPlanner</item>\n        <item>https://github.com/vieux/OpenUDID</item>\n        <item>https://github.com/vieux/OpenUDID</item>\n        <item>https://github.com/vieux/OpenUDID</item>\n        <item>https://github.com/schwabe/ics-openvpn</item>\n        <item>https://www.openx.com/</item>\n        <item>https://www.openx.com/</item>\n        <item>https://developer.huawei.com/consumer/en/codelab/HUAWEIAdsSDK-BannerAds/index.html</item>\n        <item>https://developer.huawei.com/consumer/en/codelab/HUAWEIAdsSDK-BannerAds/index.html</item>\n        <item>https://developer.huawei.com/consumer/en/codelab/HUAWEIAdsSDK-BannerAds/index.html</item>\n        <item>http://opencsv.sourceforge.net/</item>\n        <item>http://opencsv.sourceforge.net/</item>\n        <item>https://github.com/simonpoole/OpeningHoursParser</item>\n        <item>https://www.opensignal.com</item>\n        <item>https://www.opentracker.net/</item>\n        <item>https://www.optimizely.com/</item>\n        <item>https://github.com/louisyonge/opus_android</item>\n        <item>https://subgraph.com/orchid/</item>\n        <item>https://github.com/leonlatsch/OssLicenseView</item>\n        <item>https://www.otherlevels.com/</item>\n        <item>https://github.com/square/otto</item>\n        <item>http://www.outbrain.com/</item>\n        <item>http://www.outbid.io/</item>\n        <item>https://github.com/Mixiaoxiao/OverScroll-Everywhere</item>\n        <item>https://github.com/chthai64/overscroll-bouncy-android</item>\n        <item>https://github.com/intik/overflow-pager-indicator</item>\n        <item>https://github.com/discord/OverlappingPanels</item>\n        <item>https://oztam.com.au/</item>\n        <item>http://web.peanutlabs.com/</item>\n        <item>https://github.com/deva666/Peko</item>\n        <item>https://github.com/thealeksandr/PFLockScreen-Android</item>\n        <item>https://github.com/rtchagas/pingplacepicker</item>\n        <item>https://github.com/leonbloy/pngj</item>\n        <item>https://www.pokkt.com</item>\n        <item>https://github.com/MindorksOpenSource/PRDownloader</item>\n        <item>http://www.khelekore.org/prtree/</item>\n        <item>https://github.com/flutter/plugins/tree/master/packages/package_info</item>\n        <item>https://github.com/romandanylyk/PageIndicatorView</item>\n        <item>https://github.com/romandanylyk/PageIndicatorView</item>\n        <item>https://github.com/romandanylyk/PageIndicatorView</item>\n        <item>https://developer.android.com/jetpack/androidx/releases/paging</item>\n        <item>https://github.com/VasyaFromRussia/pago</item>\n        <item>https://eclipse.org/paho/clients/java/</item>\n        <item>https://developer.android.com/jetpack/androidx/releases/palette</item>\n        <item>https://github.com/whataa/pandora</item>\n        <item>https://www.pangleglobal.com</item>\n        <item>https://www.pangleglobal.com</item>\n        <item>https://www.pangleglobal.com</item>\n        <item>https://www.pangleglobal.com</item>\n        <item>http://en.papayamobile.com</item>\n        <item>http://en.papayamobile.com</item>\n        <item>https://github.com/pilgr/Paper</item>\n        <item>https://github.com/grandstaish/paperparcel</item>\n        <item>https://github.com/Narfss/ParallaxEverywhere</item>\n        <item>https://github.com/xgc1986/ParallaxPagerTransformer</item>\n        <item>https://github.com/johncarl81/parceler</item>\n        <item>https://github.com/Yelp/parcelgen</item>\n        <item>https://github.com/airbnb/paris</item>\n        <item>https://docs.parseplatform.org/android/guide/#analytics</item>\n        <item>https://docs.parseplatform.org/android/guide/#analytics</item>\n        <item>https://github.com/parse-community/Parse-SDK-Android</item>\n        <item>https://www.parse.ly/</item>\n        <item>https://github.com/muhrifqii/ParseRSS</item>\n        <item>https://github.com/Parsely/parsely-android</item>\n        <item>https://partytrack.it/</item>\n        <item>https://github.com/wordpress-mobile/PasscodeLock-Android</item>\n        <item>https://github.com/maksim88/PasswordEditText</item>\n        <item>https://sourceforge.net/projects/passwordsafe/</item>\n        <item>https://github.com/ihsg/PatternLocker</item>\n        <item>https://github.com/DreaminginCodeZH/PatternLock</item>\n        <item>https://github.com/aritraroy/PatternLockView</item>\n        <item>https://github.com/kaitoy/pcap4j</item>\n        <item>https://github.com/voghDev/PdfViewPager</item>\n        <item>https://github.com/iotaledger/PearlDiver</item>\n        <item>https://github.com/pebble/pebble-android-sdk</item>\n        <item>https://www.pendo.io</item>\n        <item>https://www.pendo.io</item>\n        <item>https://github.com/perfmark/perfmark</item>\n        <item>https://github.com/perfmark/perfmark</item>\n        <item>https://github.com/greysonp/permiso</item>\n        <item>https://github.com/guolindev/PermissionX</item>\n        <item>https://github.com/hotchemi/PermissionsDispatcher</item>\n        <item>https://github.com/franmontiel/PersistentCookieJar</item>\n        <item>http://persona.ly/</item>\n        <item>https://github.com/eoinsha/JavaPhoenixChannels</item>\n        <item>https://github.com/chariotsolutions/phonegap-nfc</item>\n        <item>https://github.com/phonegap/phonegap-plugin-barcodescanner</item>\n        <item>https://github.com/ongakuer/PhotoDraweeView</item>\n        <item>https://github.com/chrisbanes/PhotoView</item>\n        <item>https://github.com/chrisbanes/PhotoView</item>\n        <item>https://github.com/sarriaroman/photoviewer</item>\n        <item>http://www.phunware.com/advertising</item>\n        <item>https://github.com/square/picasso</item>\n        <item>https://github.com/square/picasso</item>\n        <item>https://github.com/JakeWharton/picasso2-okhttp3-downloader</item>\n        <item>https://github.com/wasabeef/picasso-transformations</item>\n        <item>https://github.com/florent37/PicassoPalette</item>\n        <item>https://github.com/mariotaku/PickNCrop</item>\n        <item>https://github.com/react-native-community/react-native-picker</item>\n        <item>https://enterprise.foursquare.com/products/pilgrim</item>\n        <item>https://enterprise.foursquare.com/products/pilgrim</item>\n        <item>https://github.com/aritraroy/PinLockView</item>\n        <item>https://www.pincrux.com/</item>\n        <item>http://pingstart.com</item>\n        <item>https://github.com/wefika/pinned-section-listview</item>\n        <item>https://pinterest.com</item>\n        <item>https://github.com/javiersantos/PiracyChecker</item>\n        <item>https://github.com/javiersantos/PiracyChecker</item>\n        <item>https://piwik.org/</item>\n        <item>https://github.com/akshay2211/PixImagePicker</item>\n        <item>https://github.com/neopixl/PixlUI</item>\n        <item>https://github.com/Drabu/PlaceAutocomplete</item>\n        <item>http://placed.com/</item>\n        <item>https://placer.io/</item>\n        <item>https://developers.google.com/games/services/android/quickstart</item>\n        <item>https://developers.google.com/games/services/android/quickstart</item>\n        <item>https://developer.android.com/google/play/installreferrer/library</item>\n        <item>https://github.com/uerceg/play-install-referrer-react-native</item>\n        <item>https://developers.google.com/android/reference/com/google/android/gms/location/places/PlaceReport</item>\n        <item>https://mvnrepository.com/artifact/com.google.android.gms/play-services-safetynet</item>\n        <item>https://api.playfab.com/docs/getting-started/java-getting-started</item>\n        <item>https://github.com/Cleveroad/PlayWidget</item>\n        <item>https://github.com/KLab/PlaygroundOSS</item>\n        <item>https://www.playtestcloud.com</item>\n        <item>https://www.plexure.com/</item>\n        <item>https://www.plleti.com/</item>\n        <item>https://www.pointinside.com/</item>\n        <item>https://www.polarify.co.jp/</item>\n        <item>https://www.pollfish.com</item>\n        <item>http://www.pontiflex.com/</item>\n        <item>https://github.com/offbynull/portmapper</item>\n        <item>https://posthog.com/</item>\n        <item>https://github.com/skydoves/PowerMenu</item>\n        <item>https://github.com/skydoves/PowerSpinner</item>\n        <item>https://prebid.org</item>\n        <item>https://www.predic.io/</item>\n        <item>https://www.predic.io/</item>\n        <item>https://developer.android.com/jetpack/androidx/releases/preference</item>\n        <item>https://github.com/mostafa-mansour1/previewAnyFile</item>\n        <item>https://github.com/aminography/PrimeCalendar</item>\n        <item>https://developer.android.com/jetpack/androidx/releases/print</item>\n        <item>https://github.com/JakeWharton/ProcessPhoenix</item>\n        <item>https://www.blogwatcher.co.jp/</item>\n        <item>https://www.blogwatcher.co.jp/</item>\n        <item>https://developer.android.com/jetpack/androidx/releases/profileinstaller</item>\n        <item>https://github.com/leandroBorgesFerreira/LoadingButtonAndroid</item>\n        <item>https://github.com/FilipPudak/ProgressPieView</item>\n        <item>https://github.com/skydoves/ProgressView</item>\n        <item>https://github.com/locationtech/proj4j</item>\n        <item>https://github.com/rzwitserloot/lombok</item>\n        <item>https://github.com/guardianproject/proofmode</item>\n        <item>https://github.com/ProtonMail/protoncore_android</item>\n        <item>https://proximi.io/</item>\n        <item>https://github.com/Aefyr/PseudoApkSigner</item>\n        <item>https://pubmatic.com/</item>\n        <item>https://pubnative.net/</item>\n        <item>https://pubnub.com</item>\n        <item>https://github.com/schildbach/public-transport-enabler</item>\n        <item>https://pulsate.readme.io/v2.0/docs/installing-sdk-android-studio</item>\n        <item>http://www.pushspring.com/</item>\n        <item>https://docs.pushbullet.com/</item>\n        <item>https://pusher.com/</item>\n        <item>https://www.pushwoosh.com/</item>\n        <item>https://pushy.me/</item>\n        <item>https://pyze.com/</item>\n        <item>https://github.com/QUSEIT/qbaselib</item>\n        <item>https://github.com/dlazaro66/QRCodeReaderView</item>\n        <item>https://github.com/kenglxn/QRGen</item>\n        <item>https://github.com/androidmads/QRGenerator</item>\n        <item>http://www.360.cn/</item>\n        <item>http://www.360.cn/</item>\n        <item>http://www.360.cn/</item>\n        <item>https://www.qt.io/</item>\n        <item>https://docs.quadrant.io/en-gb/sdk-integration-android</item>\n        <item>http://www.qualtrics.com/</item>\n        <item>http://www.quantcast.com</item>\n        <item>https://www.appier.com/</item>\n        <item>https://www.appier.com/</item>\n        <item>https://github.com/piruin/quickaction</item>\n        <item>https://github.com/Tianscar/QuickBitmap</item>\n        <item>https://quickblox.com/</item>\n        <item>https://github.com/cashapp/quickjs-java</item>\n        <item>https://github.com/andraskindler/quickscroll</item>\n        <item>https://github.com/adamw/quicklens</item>\n        <item>https://github.com/Fewlaps/quitnow-cache</item>\n        <item>https://github.com/RocketChat/rn-extensions-share</item>\n        <item>https://github.com/prof18/RSS-Parser</item>\n        <item>https://github.com/jkennethcarino/RTextEditorView</item>\n        <item>https://radar.io/</item>\n        <item>https://github.com/ceryle/RadioRealButton</item>\n        <item>https://www.radiusnetworks.com/</item>\n        <item>https://github.com/Rajawali/Rajawali</item>\n        <item>https://github.com/rakutentech/android-analytics</item>\n        <item>https://github.com/rakutentech/android-analytics</item>\n        <item>https://github.com/rakuten-ads/Rakuten-Ads-Android</item>\n        <item>https://github.com/rakuten-ads/Rakuten-Ads-Android</item>\n        <item>https://github.com/stedi-akk/RandomImageGenerator</item>\n        <item>https://github.com/edmodo/range-bar</item>\n        <item>https://github.com/Jay-Goo/RangeSeekBar</item>\n        <item>https://mvnrepository.com/artifact/com.github.thibseisel/ratioimageview</item>\n        <item>https://raygun.com</item>\n        <item>https://github.com/KeepSafe/ReLinker</item>\n        <item>https://reactnative.dev/</item>\n        <item>https://reactnative.dev/</item>\n        <item>https://reactnative.dev/</item>\n        <item>https://reactnative.dev/</item>\n        <item>https://reactnative.dev/</item>\n        <item>https://reactnative.dev/</item>\n        <item>https://reactnative.dev/</item>\n        <item>https://github.com/tectiv3/react-native-aes</item>\n        <item>https://github.com/emekalites/react-native-alarm-notification</item>\n        <item>https://github.com/react-native-community/react-native-async-storage</item>\n        <item>https://github.com/ocetnik/react-native-background-timer</item>\n        <item>https://github.com/idehub/react-native-billing</item>\n        <item>https://github.com/rusel1989/react-native-bluetooth-serial</item>\n        <item>https://github.com/Kureev/react-native-blur</item>\n        <item>https://github.com/react-native-community/react-native-camera</item>\n        <item>https://github.com/react-native-community/react-native-camera</item>\n        <item>https://github.com/react-native-community/react-native-camera</item>\n        <item>https://github.com/react-native-community/react-native-camera</item>\n        <item>https://github.com/react-native-community/react-native-camera</item>\n        <item>https://github.com/teslamotors/react-native-camera-kit</item>\n        <item>https://github.com/teslamotors/react-native-camera-kit</item>\n        <item>https://github.com/rt2zz/react-native-contacts</item>\n        <item>https://github.com/react-native-datetimepicker/datetimepicker</item>\n        <item>https://github.com/emeraldsanto/react-native-encrypted-storage</item>\n        <item>https://github.com/hieuvp/react-native-fingerprint-scanner</item>\n        <item>https://github.com/kmagiera/react-native-gesture-handler</item>\n        <item>https://github.com/react-native-community/react-native-google-signin</item>\n        <item>https://github.com/react-community/react-native-image-picker</item>\n        <item>https://github.com/bamlab/react-native-image-resizer</item>\n        <item>https://github.com/matei-radu/react-native-in-app-browser</item>\n        <item>https://github.com/react-native-community/react-native-masked-view</item>\n        <item>https://github.com/Microsoft/react-native-code-push</item>\n        <item>https://github.com/wix/react-native-navigation</item>\n        <item>https://github.com/thebylito/react-native-navigation-bar-color</item>\n        <item>https://github.com/wix/react-native-notifications</item>\n        <item>https://github.com/yamill/react-native-orientation</item>\n        <item>https://github.com/zo0r/react-native-push-notification</item>\n        <item>https://github.com/jordanbyron/react-native-quick-actions</item>\n        <item>https://github.com/software-mansion/react-native-reanimated</item>\n        <item>https://github.com/avishayil/react-native-restart</item>\n        <item>https://github.com/craftzdog/react-native-sqlite-2</item>\n        <item>https://github.com/umhan35/react-native-search-bar</item>\n        <item>https://github.com/mCodex/react-native-sensitive-info</item>\n        <item>https://github.com/Doko-Demo-Doa/react-native-shake</item>\n        <item>https://github.com/alinz/react-native-share-extension</item>\n        <item>https://github.com/remobile/react-native-toast</item>\n        <item>https://github.com/naoufal/react-native-touch-id</item>\n        <item>https://github.com/GoldenOwlAsia/react-native-twitter-signin</item>\n        <item>https://github.com/react-native-community/react-native-webview</item>\n        <item>https://github.com/mockingbot/react-native-zip-archive</item>\n        <item>https://github.com/doublesymmetry/react-native-track-player</item>\n        <item>https://github.com/prscX/react-native-tooltips</item>\n        <item>https://github.com/stefalda/ReactNativeLocalization</item>\n        <item>http://www.reactive-streams.org/</item>\n        <item>https://github.com/pwittchen/ReactiveNetwork</item>\n        <item>https://github.com/pwittchen/ReactiveSensors</item>\n        <item>https://github.com/reactor/reactor-core</item>\n        <item>https://github.com/reactor/reactor-core</item>\n        <item>https://github.com/reactor/reactor-core</item>\n        <item>https://github.com/dankito/Readability4J</item>\n        <item>https://github.com/realm/realm-java</item>\n        <item>https://github.com/mmin18/RealtimeBlurView</item>\n        <item>https://github.com/mmin18/RealtimeBlurView</item>\n        <item>https://github.com/facebook/rebound</item>\n        <item>https://www.receptiv.com/</item>\n        <item>https://github.com/irismod/record</item>\n        <item>https://github.com/FutureMind/recycler-fast-scroll</item>\n        <item>https://github.com/plusCubed/recycler-fast-scroll</item>\n        <item>https://github.com/plusCubed/recycler-fast-scroll</item>\n        <item>https://github.com/dinuscxj/RecyclerItemDecoration</item>\n        <item>https://github.com/dinuscxj/RecyclerRefreshLayout</item>\n        <item>https://github.com/wasabeef/recyclerview-animators</item>\n        <item>https://github.com/bignerdranch/recyclerview-multiselect</item>\n        <item>https://github.com/timusus/RecyclerView-FastScroll</item>\n        <item>https://github.com/yqritc/RecyclerView-FlexibleDivider</item>\n        <item>https://github.com/quiph/RecyclerView-FastScroller</item>\n        <item>https://github.com/xabaras/RecyclerViewSwipeDecorator</item>\n        <item>https://github.com/CraZyLegenD/Set-Of-Useful-Kotlin-Extensions-and-Helpers/tree/master/recyclerview</item>\n        <item>https://github.com/afollestad/recyclical</item>\n        <item>http://redberry.cc/</item>\n        <item>https://github.com/EsotericSoftware/reflectasm</item>\n        <item>https://github.com/llew2011/Reflection</item>\n        <item>https://github.com/kakajika/RelativePopupWindow</item>\n        <item>https://github.com/giflw/remark-java</item>\n        <item>https://github.com/apsun/RemotePreferences</item>\n        <item>https://github.com/android/renderscript-intrinsics-replacement-toolkit</item>\n        <item>https://github.com/pedrovgs/Renderers</item>\n        <item>https://github.com/ajalt/reprint</item>\n        <item>https://repro.io/</item>\n        <item>https://github.com/mmazi/rescu</item>\n        <item>https://developer.android.com/jetpack/androidx/releases/resourceinspection</item>\n        <item>https://github.com/mariotaku/RestFu</item>\n        <item>https://github.com/ChickenHook/RestrictionBypass</item>\n        <item>https://github.com/kittinunf/Result</item>\n        <item>http://retency.com/</item>\n        <item>https://github.com/square/retrofit</item>\n        <item>https://revealmobile.com/documentation/</item>\n        <item>https://revealmobile.com/</item>\n        <item>http://revenuecat.com</item>\n        <item>https://www.crunchbase.com/organization/revmob</item>\n        <item>https://github.com/wasabeef/richeditor-android</item>\n        <item>https://github.com/zzhoujay/RichText</item>\n        <item>https://github.com/RikkaApps/RikkaX/tree/master/preference</item>\n        <item>https://github.com/RikkaApps/RikkaX</item>\n        <item>https://github.com/RikkaApps/libraries/tree/master/html</item>\n        <item>https://github.com/RikkaApps/libraries</item>\n        <item>https://github.com/RikkaApps/libraries</item>\n        <item>https://github.com/RikkaApps/libraries</item>\n        <item>https://github.com/RikkaApps/libraries</item>\n        <item>https://github.com/RikkaApps/libraries</item>\n        <item>https://github.com/RikkaApps/RikkaX/tree/master/lifecycle</item>\n        <item>https://github.com/google/ringdroid</item>\n        <item>https://github.com/traex/RippleEffect</item>\n        <item>https://rjfun.github.io/</item>\n        <item>https://rjfun.github.io/</item>\n        <item>https://github.com/roboguice/roboguice</item>\n        <item>https://github.com/roboguice/roboguice</item>\n        <item>https://rollbar.com</item>\n        <item>https://github.com/rometools/rome</item>\n        <item>https://www.rongcloud.cn/</item>\n        <item>https://www.rongcloud.cn/</item>\n        <item>https://www.rongcloud.cn/</item>\n        <item>https://developer.android.com/jetpack/androidx/releases/room</item>\n        <item>https://github.com/MatrixDev/Roomigrant</item>\n        <item>https://github.com/sunilpaulmathew/RootFilePicker</item>\n        <item>https://github.com/scottyab/rootbeer</item>\n        <item>https://github.com/Free-Software-for-Android/RootCommands</item>\n        <item>https://github.com/Fox2Code/RosettaX</item>\n        <item>https://github.com/Deishelon/RoundedBottomSheet</item>\n        <item>https://github.com/vinc3m1/RoundedImageView</item>\n        <item>http://roximity.com/</item>\n        <item>https://github.com/diego-gomez-olvera/RtlViewPager</item>\n        <item>https://rubiconproject.com</item>\n        <item>https://rubiconproject.com/</item>\n        <item>https://rumbleiot.com/predictive-analytics/</item>\n        <item>https://github.com/PPartisan/RunDo</item>\n        <item>https://github.com/mukeshsolanki/App-Runtime-Permissions-Android</item>\n        <item>https://github.com/f2prateek/rx-preferences</item>\n        <item>https://github.com/f2prateek/rx-preferences</item>\n        <item>https://github.com/f2prateek/rx-receivers</item>\n        <item>https://github.com/miguelbcr/RxBillingService</item>\n        <item>https://github.com/JakeWharton/RxBinding</item>\n        <item>https://github.com/JakeWharton/RxBinding</item>\n        <item>https://github.com/JakeWharton/RxBinding</item>\n        <item>https://github.com/JakeWharton/RxBinding</item>\n        <item>https://github.com/AndroidKnife/RxBus</item>\n        <item>https://github.com/ragnraok/RxCamera</item>\n        <item>https://github.com/uber/RxDogTag</item>\n        <item>https://github.com/ssseasonnn/RxDownload</item>\n        <item>https://github.com/esafirm/RxDownloader</item>\n        <item>https://github.com/b3er/RxFirebase2</item>\n        <item>https://github.com/liujingxing/okhttp-RxHttp</item>\n        <item>https://github.com/MLSDev/RxImagePicker</item>\n        <item>https://github.com/ReactiveX/RxJava</item>\n        <item>https://github.com/JakeWharton/RxReplayingShare</item>\n        <item>https://github.com/akarnokd/RxJava2Extensions</item>\n        <item>https://github.com/akarnokd/RxJava2Interop</item>\n        <item>https://github.com/artem-zinnatullin/RxJavaProGuardRules</item>\n        <item>https://github.com/trello/RxLifecycle</item>\n        <item>https://github.com/trello/RxLifecycle</item>\n        <item>https://github.com/tbruyelle/RxPermissions</item>\n        <item>https://github.com/tbruyelle/RxPermissions</item>\n        <item>https://github.com/JakeWharton/RxRelay</item>\n        <item>https://github.com/JakeWharton/RxRelay</item>\n        <item>https://github.com/florent37/RxRetroJsoup</item>\n        <item>https://github.com/florent37/RxRetroJsoup</item>\n        <item>https://github.com/Tamsiree/RxTool</item>\n        <item>https://github.com/Tamsiree/RxTool</item>\n        <item>https://github.com/Tans5/RxUtils</item>\n        <item>https://github.com/afollestad/rxkprefs</item>\n        <item>http://www.s4m.io/</item>\n        <item>http://www.s4m.io/</item>\n        <item>https://www.sap.com/products/crm/customer-data-management.html</item>\n        <item>https://communities.sas.com/t5/SAS-Communities-Library/Building-a-SAS-CI-enabled-mobile-app-for-Android/ta-p/354922</item>\n        <item>https://communities.sas.com/t5/SAS-Communities-Library/Building-a-SAS-CI-enabled-mobile-app-for-Android/ta-p/354922</item>\n        <item>https://developer.android.com/reference/org/xml/sax/package-summary.html</item>\n        <item>https://github.com/sacot41/SCViewPager</item>\n        <item>https://www.sdkbox.com/</item>\n        <item>https://github.com/libsdl-org/SDL</item>\n        <item>https://github.com/intuit/sdp</item>\n        <item>https://github.com/NovaCrypto/SHA256</item>\n        <item>https://www.skplanet.com/eng</item>\n        <item>https://snssdk.com/</item>\n        <item>https://github.com/square/sqlbrite</item>\n        <item>https://github.com/square/sqlbrite</item>\n        <item>https://github.com/square/sqlbrite</item>\n        <item>https://github.com/sqlcipher/android-database-sqlcipher</item>\n        <item>https://github.com/square/sqldelight</item>\n        <item>https://developer.android.com/jetpack/androidx/releases/sqlite</item>\n        <item>https://github.com/xerial/sqlite-jdbc</item>\n        <item>https://github.com/mariotaku/SQLiteQB</item>\n        <item>https://github.com/androidmads/SQLite2XL</item>\n        <item>https://github.com/Drabu/SSNInputView</item>\n        <item>https://github.com/intuit/ssp</item>\n        <item>https://www.safegraph.com/</item>\n        <item>https://www.safegraph.com/</item>\n        <item>https://www.sailthru.com</item>\n        <item>https://www.salesforce.com/products/marketing-cloud/</item>\n        <item>https://developer.samsung.com/galaxy-accessory/overview.html</item>\n        <item>https://developer.samsung.com/mobile#accessory</item>\n        <item>https://github.com/OneUIProject/oneui-core</item>\n        <item>https://github.com/OneUIProject/oneui-core</item>\n        <item>https://github.com/OneUIProject/oneui-core</item>\n        <item>https://github.com/OneUIProject/oneui-core</item>\n        <item>https://github.com/OneUIProject/oneui-core</item>\n        <item>http://developer.samsung.com/galaxy/edge</item>\n        <item>http://developer.samsung.com/onlinedocs/sms/pass/com/samsung/android/sdk/pass/package-summary.html</item>\n        <item>http://developer.samsung.com/java/technical-docs/Samsung-Overlay-Keypad-Overlay-EditField</item>\n        <item>https://www.samsung.com</item>\n        <item>https://www.samsung.com</item>\n        <item>https://github.com/SuppSandroB/sandrop/tree/master/projects/SandroProxyLib</item>\n        <item>https://github.com/SuppSandroB/sandrop/tree/master/projects/SandroProxyLib</item>\n        <item>https://www.saysorewards.com/</item>\n        <item>https://www.saysorewards.com/</item>\n        <item>http://docs.scala-lang.org/</item>\n        <item>https://github.com/pocorall/scaloid</item>\n        <item>https://github.com/jhansireddy/AndroidScannerDemo</item>\n        <item>https://scandit.com</item>\n        <item>https://github.com/Tinder/Scarlet</item>\n        <item>https://github.com/SceneView/sceneform-android</item>\n        <item>http://www.schibsted.com/en/ir/</item>\n        <item>https://github.com/lyft/scissors</item>\n        <item>https://github.com/lyft/scoop</item>\n        <item>http://scorecardresearch.com</item>\n        <item>https://www.scoreloop.com</item>\n        <item>https://github.com/capacitor-community/screen-brightness</item>\n        <item>https://github.com/scribejava/scribejava</item>\n        <item>https://github.com/scribejava/scribejava</item>\n        <item>https://github.com/damonkohler/sl4a</item>\n        <item>https://github.com/DeweyReed/ScrollHmsPicker</item>\n        <item>https://github.com/ByteHamster/SearchPreference</item>\n        <item>https://github.com/lapism/SearchView</item>\n        <item>https://github.com/miteshpithadiya/SearchableSpinner</item>\n        <item>https://github.com/luizgrp/SectionedRecyclerViewAdapter</item>\n        <item>https://docs.jboss.org/jbosssecurity/docs/6.0/security_guide/html/chap-Secure_Remote_Password_Protocol.html</item>\n        <item>https://github.com/therealseeds/seeds-sdk-android</item>\n        <item>https://github.com/neild001/SeekArc</item>\n        <item>https://github.com/0x1306e6d/SeekBarPreference</item>\n        <item>https://segment.com/</item>\n        <item>https://github.com/square/seismic</item>\n        <item>https://github.com/vdurmont/semver4j</item>\n        <item>https://github.com/carsten-klaffke/send-intent</item>\n        <item>https://github.com/sendbird/SendBird-SDK-Android</item>\n        <item>https://www.sensara.tv/</item>\n        <item>https://sense360.com/</item>\n        <item>https://www.sensoro.com/</item>\n        <item>https://www.sensoro.com/</item>\n        <item>https://github.com/sensorsdata/sa-sdk-android</item>\n        <item>https://www.sentiance.com/</item>\n        <item>https://sentry.io/for/android/</item>\n        <item>https://sentry.io/for/android/</item>\n        <item>https://github.com/getsentry/sentry-java</item>\n        <item>https://github.com/joshdholtz/Sentry-Android</item>\n        <item>https://github.com/daneren2005/ServerProxy</item>\n        <item>https://sesame.ninja/</item>\n        <item>https://github.com/czy1121/settingscompat</item>\n        <item>https://github.com/czy1121/settingscompat</item>\n        <item>https://android.googlesource.com/platform/frameworks/opt/setupwizard/</item>\n        <item>https://github.com/dumganhar/SevenZip-Java</item>\n        <item>https://www.seventynine.mobi/</item>\n        <item>https://github.com/Devlight/ShadowLayout</item>\n        <item>http://www.shallwead.com</item>\n        <item>http://www.shallwead.com</item>\n        <item>https://github.com/florent37/ShapeOfView</item>\n        <item>https://github.com/gavinliu/ShapedImageView</item>\n        <item>https://github.com/flutter/plugins/tree/master/packages/share</item>\n        <item>https://github.com/zhouteng0217/ShareExtend</item>\n        <item>https://developer.android.com/jetpack/androidx/releases/sharetarget</item>\n        <item>https://github.com/Pixplicity/sharp</item>\n        <item>https://github.com/ajitsing/Sherlock</item>\n        <item>https://github.com/RomainPiel/Shimmer-android</item>\n        <item>https://github.com/facebook/shimmer-android</item>\n        <item>https://github.com/sharish/ShimmerRecyclerView</item>\n        <item>https://github.com/ChadCSong/ShineButton</item>\n        <item>https://github.com/RikkaApps/Shizuku</item>\n        <item>https://github.com/RikkaApps/Shizuku-API</item>\n        <item>https://shopkick.com</item>\n        <item>https://shopkick.com</item>\n        <item>https://github.com/MatthiasRobbers/shortbread</item>\n        <item>https://github.com/leolin310148/ShortcutBadger</item>\n        <item>https://github.com/niranjan94/show-java</item>\n        <item>https://github.com/amlcurran/ShowcaseView</item>\n        <item>https://www.szshuwei.com/</item>\n        <item>https://github.com/signalapp/Signal-Android</item>\n        <item>https://github.com/WhisperSystems/libsignal-protocol-java</item>\n        <item>http://www.signal360.com</item>\n        <item>http://www.signal360.com</item>\n        <item>http://www.signal360.com</item>\n        <item>https://signalframe.com/</item>\n        <item>https://github.com/TheAndroidMaster/SignalStrengths</item>\n        <item>https://github.com/zahid-ali-shah/SignatureView</item>\n        <item>https://github.com/mttkay/signpost</item>\n        <item>http://silverpush.co/</item>\n        <item>https://github.com/Simmetrics/simmetrics</item>\n        <item>https://github.com/Simperium/simperium-android</item>\n        <item>https://sourceforge.net/projects/simple/</item>\n        <item>https://www.w3.org/Style/CSS/SAC/</item>\n        <item>https://github.com/SimpleMobileTools/Simple-Commons</item>\n        <item>https://github.com/ngageoint/simple-features-java</item>\n        <item>https://github.com/MarcDonald/SimpleLicenseDisplay</item>\n        <item>https://www.slf4j.org/</item>\n        <item>https://github.com/igreenwood/SimpleCropView</item>\n        <item>https://github.com/eltos/SimpleDialogFragments</item>\n        <item>https://github.com/championswimmer/SimpleFingerGestures_Android_Library</item>\n        <item>https://github.com/faucamp/SimpleRtmp</item>\n        <item>https://github.com/Ferfalk/SimpleSearchView</item>\n        <item>https://github.com/anggrayudi/SimpleStorage</item>\n        <item>https://github.com/maxyou/SimpleWaveform</item>\n        <item>https://github.com/florent37/SingleDateAndTimePicker</item>\n        <item>https://www.singlespot.com/</item>\n        <item>https://singular.net/</item>\n        <item>https://open.weibo.com/wiki/SDK/en#Android</item>\n        <item>https://developers.situm.com/</item>\n        <item>https://www.sizmek.com</item>\n        <item>https://github.com/Faltenreich/SkeletonLayout</item>\n        <item>https://www.skillz.com/</item>\n        <item>https://github.com/SkyTubeTeam/components</item>\n        <item>https://www.skyhook.com</item>\n        <item>https://github.com/cortinico/slidetoact</item>\n        <item>https://github.com/fennifith/SlideActionView</item>\n        <item>https://github.com/yydcdut/SlideAndDragListView</item>\n        <item>https://github.com/MoraisIgor/SlidingDrawer</item>\n        <item>https://github.com/jfeinstein10/SlidingMenu</item>\n        <item>https://github.com/jfeinstein10/SlidingMenu</item>\n        <item>https://developer.android.com/jetpack/androidx/releases/slidingpanelayout</item>\n        <item>https://github.com/r0adkll/Slidr</item>\n        <item>https://smaato.com</item>\n        <item>https://github.com/igniterealtime/Smack</item>\n        <item>http://smartadserver.com/</item>\n        <item>https://github.com/mrmans0n/smart-location-lib</item>\n        <item>https://smrtbeat.com/</item>\n        <item>https://www.smartlook.com/</item>\n        <item>https://github.com/scwang90/SmartRefreshLayout</item>\n        <item>https://www.smartstudy.co.kr/en/</item>\n        <item>https://github.com/ogaclejapan/SmartTabLayout</item>\n        <item>https://smartyads.com/</item>\n        <item>https://github.com/castorflex/SmoothProgressBar</item>\n        <item>https://github.com/castorflex/SmoothProgressBar</item>\n        <item>https://github.com/dkzwm/SmoothRefreshLayout</item>\n        <item>https://github.com/Kennyc1012/SnackBar</item>\n        <item>https://github.com/ligi/SnackEngage</item>\n        <item>https://github.com/karussell/snacktory</item>\n        <item>https://github.com/matecode/Snacky</item>\n        <item>https://bitbucket.org/asomov/snakeyaml</item>\n        <item>https://bitbucket.org/asomov/snakeyaml</item>\n        <item>https://kit.snapchat.com/docs/ad-kit</item>\n        <item>https://kit.snapchat.com/docs/ad-kit</item>\n        <item>https://kit.snapchat.com/</item>\n        <item>https://kit.snapchat.com/docs/login-kit</item>\n        <item>https://github.com/chrisbanes/snapper</item>\n        <item>https://github.com/dain/snappy</item>\n        <item>https://github.com/nhachicha/SnappyDB</item>\n        <item>https://github.com/nshmura/SnappySmoothScroller</item>\n        <item>https://github.com/snowballstem/snowball</item>\n        <item>https://snowplowanalytics.com/</item>\n        <item>https://github.com/facebook/SoLoader</item>\n        <item>https://github.com/socketio/socket.io-client-java</item>\n        <item>https://solar2d.com/</item>\n        <item>https://github.com/RizalLovins/Cyber-shot_SemcCameraUI</item>\n        <item>https://soomla.com/</item>\n        <item>https://github.com/xaverkapeller/SortedListAdapter</item>\n        <item>http://www.soundhound.com/</item>\n        <item>https://github.com/twofortyfouram/android-spackle</item>\n        <item>https://github.com/robinhood/spark</item>\n        <item>https://jitpack.io/p/connyduck/sparkbutton</item>\n        <item>https://github.com/the-blue-alliance/spectrum</item>\n        <item>https://github.com/cmusphinx/sphinx4</item>\n        <item>https://www.split.io/</item>\n        <item>https://github.com/k9mail/splitview</item>\n        <item>https://github.com/LouisCAD/Splitties</item>\n        <item>http://docs.splunk.com/Documentation/MintAndroidSDK</item>\n        <item>http://rtyley.github.io/spongycastle/</item>\n        <item>http://spoteer.com/</item>\n        <item>https://ads.spotify.com/en-US/</item>\n        <item>https://ads.spotify.com/en-US/</item>\n        <item>https://ads.spotify.com/en-US/</item>\n        <item>https://ads.spotify.com/en-US/</item>\n        <item>https://ads.spotify.com/en-US/</item>\n        <item>https://ads.spotify.com/en-US/</item>\n        <item>https://github.com/spotify/android-sdk</item>\n        <item>https://kaaes.github.io/spotify-web-api-android/</item>\n        <item>https://github.com/kaaes/spotify-web-api-android</item>\n        <item>https://github.com/wooplr/Spotlight</item>\n        <item>https://github.com/d-max/spots-dialog</item>\n        <item>https://github.com/spring-projects/spring-framework</item>\n        <item>https://github.com/chenupt/SpringIndicator</item>\n        <item>https://github.com/linkedin/Spyglass</item>\n        <item>https://github.com/square/cycler</item>\n        <item>https://github.com/square/logcat</item>\n        <item>https://www.squaremetrics.com</item>\n        <item>https://github.com/yahoo/squidb</item>\n        <item>https://github.com/massivemadness/Squircle-IDE</item>\n        <item>https://github.com/andiwand/svm</item>\n        <item>https://github.com/StartApp-SDK/Documentation/wiki/Android-InApp-Documentation</item>\n        <item>https://developer.android.com/jetpack/androidx/releases/startup</item>\n        <item>https://github.com/li-xiaojun/StateLayout</item>\n        <item>https://github.com/laobie/StatusBarUtil</item>\n        <item>https://github.com/FasterXML/stax2-api</item>\n        <item>https://github.com/hapramp/steemconnect4j</item>\n        <item>https://github.com/andiwand/commons.java</item>\n        <item>https://github.com/params-ing/StepProgressView</item>\n        <item>https://github.com/baoyachi/StepView</item>\n        <item>https://github.com/badoualy/stepper-indicator</item>\n        <item>https://github.com/drozdzynski/Steppers</item>\n        <item>https://github.com/Stericson/RootShell</item>\n        <item>https://github.com/Stericson/RootTools</item>\n        <item>https://github.com/Stericson/RootTools</item>\n        <item>https://github.com/Stericson/RootTools</item>\n        <item>https://github.com/facebook/stetho</item>\n        <item>https://github.com/uPhyca/stetho-realm</item>\n        <item>https://github.com/wuapnjie/StickerView</item>\n        <item>https://github.com/Codewaves/Sticky-Header-Grid</item>\n        <item>https://github.com/TonicArtos/StickyGridHeaders</item>\n        <item>https://github.com/bgogetap/StickyHeaders</item>\n        <item>https://github.com/emilsjolander/StickyListHeaders</item>\n        <item>https://github.com/pushtorefresh/storio</item>\n        <item>https://github.com/pushtorefresh/storio</item>\n        <item>https://github.com/codekidX/storage-chooser</item>\n        <item>https://github.com/NYTimes/Store</item>\n        <item>https://github.com/shts/StoriesProgressView</item>\n        <item>https://github.com/stripe/stripe-android</item>\n        <item>https://github.com/vikramkakkar/SublimePicker</item>\n        <item>https://github.com/skydoves/Submarine</item>\n        <item>https://github.com/Someonewow/SubmitButton</item>\n        <item>https://github.com/davemorrissey/subsampling-scale-image-view</item>\n        <item>https://github.com/substratum/template</item>\n        <item>https://github.com/RikkaApps/Sui</item>\n        <item>https://github.com/eclipse-ee4j/mail/tree/v1.x</item>\n        <item>https://github.com/mikereedell/sunrisesunsetlib-java</item>\n        <item>https://github.com/caarmen/SunriseSunset</item>\n        <item>https://github.com/fennifith/SunriseSunsetView</item>\n        <item>https://github.com/super-csv/super-csv</item>\n        <item>https://www.superawesome.com/</item>\n        <item>https://www.superawesome.com/</item>\n        <item>https://github.com/TonicArtos/SuperSLiM</item>\n        <item>https://github.com/JohnPersano/SuperToasts</item>\n        <item>https://github.com/nhaarman/supertooltips</item>\n        <item>https://supership.jp/</item>\n        <item>https://www.supersonic.com/</item>\n        <item>https://www.supersonic.com/</item>\n        <item>https://github.com/Machinarius/PreferenceFragment-Compat</item>\n        <item>https://github.com/microsoft/surface-duo-sdk</item>\n        <item>https://github.com/microsoft/surface-duo-sdk</item>\n        <item>https://swagger.io/docs/open-source-tools/swagger-codegen/</item>\n        <item>https://github.com/pedant/sweet-alert-dialog</item>\n        <item>https://github.com/qpython-android/qftplib</item>\n        <item>https://github.com/ebanx/swipe-button</item>\n        <item>https://github.com/wdullaer/SwipeActionAdapter</item>\n        <item>https://github.com/ikew0ng/SwipeBackLayout</item>\n        <item>https://github.com/huxq17/SwipeCardsView</item>\n        <item>https://github.com/aaronbond/SwipeDeck2</item>\n        <item>https://github.com/baoyongzhang/SwipeMenuListView</item>\n        <item>https://github.com/yanzhenjie/SwipeRecyclerView</item>\n        <item>https://github.com/chthai64/SwipeRevealLayout</item>\n        <item>https://github.com/roughike/SwipeSelector</item>\n        <item>https://github.com/vcalvello/SwipeToAction</item>\n        <item>https://developer.android.com/jetpack/androidx/releases/swiperefreshlayout</item>\n        <item>https://github.com/omadahealth/SwipyRefreshLayout</item>\n        <item>https://github.com/omadahealth/SwipyRefreshLayout</item>\n        <item>http://swirl.com/</item>\n        <item>https://github.com/kyleduo/SwitchButton</item>\n        <item>https://www.swrve.com/</item>\n        <item>https://www.sync.tv/</item>\n        <item>https://sourceforge.net/projects/matheclipse/</item>\n        <item>https://www.sync2ad.com/</item>\n        <item>https://synerise.com</item>\n        <item>https://taparound.net/services/taptrack/forapps/</item>\n        <item>https://www.tamedia.com.tw/</item>\n        <item>https://github.com/ngageoint/tiff-java</item>\n        <item>https://github.com/TJHello/ADEasy</item>\n        <item>http://www.tnkfactory.com</item>\n        <item>https://github.com/evrencoskun/TableView</item>\n        <item>https://www.taboola.com/</item>\n        <item>https://www.commandersact.com/en/</item>\n        <item>https://www.commandersact.com/</item>\n        <item>https://github.com/orbeon/tagsoup</item>\n        <item>https://www.talkingdata.com/</item>\n        <item>https://www.talkingdata.com/</item>\n        <item>https://www.talkingdata.com/</item>\n        <item>https://www.talkingdata.com/</item>\n        <item>https://www.talkingdata.com/</item>\n        <item>https://www.talkingdata.com/</item>\n        <item>https://www.talkingdata.com/</item>\n        <item>https://www.tamoco.com/</item>\n        <item>https://mapzen.com/documentation/tangram/</item>\n        <item>http://www.phunware.com/advertising</item>\n        <item>https://www.tapresearch.com/</item>\n        <item>https://www.tapresearch.com/</item>\n        <item>https://www.tapresearch.com/</item>\n        <item>https://github.com/KeepSafe/TapTargetView</item>\n        <item>https://www.tapad.com/</item>\n        <item>https://www.tapad.com/</item>\n        <item>https://www.tapdaq.com/</item>\n        <item>https://www.tapdaq.com/</item>\n        <item>https://github.com/square/tape</item>\n        <item>https://www.tapjoy.com/</item>\n        <item>https://taplytics.com</item>\n        <item>https://www.tappx.com/</item>\n        <item>https://github.com/tapstream/tapstream-sdk-android</item>\n        <item>https://github.com/JorenSix/TarsosDSP</item>\n        <item>https://github.com/farmerbb/Taskbar</item>\n        <item>https://tasker.joaoapps.com/developers.html</item>\n        <item>http://ipack.dinglisch.net/</item>\n        <item>https://tasker.joaoapps.com/pluginslibrary.html</item>\n        <item>https://github.com/yadav-rahul/TastyToast</item>\n        <item>https://www.teads.tv</item>\n        <item>https://www.teads.tv</item>\n        <item>https://acoustic.co/products/experience-analytics/</item>\n        <item>https://tealium.com/</item>\n        <item>https://github.com/TheHolyWaffle/TeamSpeak-3-Java-API</item>\n        <item>https://github.com/ParkSangGwon/TedBottomPicker</item>\n        <item>https://github.com/ParkSangGwon/TedBottomPicker</item>\n        <item>https://github.com/ParkSangGwon/TedImagePicker</item>\n        <item>https://github.com/ParkSangGwon/TedKeyboardObserver</item>\n        <item>https://github.com/ParkSangGwon/TedNaverMapClustering</item>\n        <item>https://github.com/ParkSangGwon/TedPermission</item>\n        <item>https://github.com/ParkSangGwon/TedRxOnActivityResult</item>\n        <item>https://www.teemo.co</item>\n        <item>https://www.teemo.co</item>\n        <item>https://support.aerserv.com/hc/en-us/articles/208830026-How-to-Set-Up-Telaria-Formerly-Tremor-Video-SDK-as-an-Ad-Source</item>\n        <item>http://www.telequid.com/</item>\n        <item>https://www.telerik.com/xamarin-ui</item>\n        <item>https://www.teliver.io</item>\n        <item>https://mta.qq.com/</item>\n        <item>https://lbs.qq.com/</item>\n        <item></item>\n        <item></item>\n        <item>https://www.tencent.com/en-us/</item>\n        <item>https://wiki.open.qq.com/index.php\\?title=Android_SDK%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA&amp;oldid=47399</item>\n        <item>https://wiki.open.qq.com/index.php\\?title=Android_SDK%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA&amp;oldid=47399</item>\n        <item>https://wiki.open.qq.com/index.php\\?title=Android_SDK%E7%8E%AF%E5%A2%83%E6%90%AD%E5%BB%BA&amp;oldid=47399</item>\n        <item></item>\n        <item>http://stat.qq.com/</item>\n        <item>http://stat.qq.com/</item>\n        <item>https://open.weixin.qq.com/</item>\n        <item>https://developers.weixin.qq.com/doc/oplatform/Downloads/Android_Resource.html</item>\n        <item>https://developers.weixin.qq.com/doc/oplatform/Downloads/Android_Resource.html</item>\n        <item>https://developers.weixin.qq.com/doc/oplatform/Downloads/Android_Resource.html</item>\n        <item>https://www.weiyun.com</item>\n        <item></item>\n        <item>https://github.com/tendermint/tendermint</item>\n        <item>https://www.tenjin.com/</item>\n        <item>https://docs.tenjin.io/en/send-events/android.html</item>\n        <item>https://github.com/tensorflow/tensorflow/</item>\n        <item>https://github.com/jackpal/Android-Terminal-Emulator</item>\n        <item>https://github.com/rmtheis/tess-two</item>\n        <item>https://github.com/rmtheis/tess-two</item>\n        <item>https://github.com/adaptech-cz/Tesseract4Android</item>\n        <item>https://github.com/amulyakhare/TextDrawable</item>\n        <item>https://github.com/facebookincubator/TextLayoutBuilder</item>\n        <item>https://github.com/a-tolstykh/textview-rich-drawable</item>\n        <item>https://www.openhub.net/p/textile-j</item>\n        <item>https://github.com/sprylab/texturevideoview</item>\n        <item>https://github.com/opentk/opentk</item>\n        <item>https://github.com/opentk/opentk</item>\n        <item>https://github.com/MatthiasMann/twl</item>\n        <item>https://github.com/DeweyReed/Theme</item>\n        <item>https://github.com/Bryanx/themed-toggle-button-group</item>\n        <item>https://www.theoremreach.com/</item>\n        <item>http://www.thinkingdata.cn/</item>\n        <item>https://github.com/grandcentrix/ThirtyInch</item>\n        <item>https://github.com/JakeWharton/ThreeTenABP</item>\n        <item>https://github.com/ThreeTen/threetenbp</item>\n        <item>https://github.com/raymondkam/Ti.SwipeRefreshLayout</item>\n        <item>https://github.com/aalderi/TiAndroidCanvas</item>\n        <item>https://github.com/robinhood/ticker</item>\n        <item>https://mvnrepository.com/artifact/org.jvnet/tiger-types</item>\n        <item>https://developers.tiktok.com/doc</item>\n        <item>https://github.com/Tickaroo/tikxml</item>\n        <item>https://github.com/moagrius/TileView</item>\n        <item>https://github.com/naman14/Timber</item>\n        <item>https://github.com/MenoData/Time4J</item>\n        <item>https://github.com/fennifith/TimeDatePicker</item>\n        <item>https://github.com/svenwiegand/time-duration-picker</item>\n        <item>https://github.com/Sztorm/TimePicker</item>\n        <item>https://github.com/vipulasri/Timeline-View</item>\n        <item>https://github.com/arsvechkarev/TimerX</item>\n        <item>https://github.com/arsvechkarev/TimerX</item>\n        <item>https://github.com/yaoandy107/TimetableUI</item>\n        <item>https://github.com/tlaabs/TimetableView</item>\n        <item>https://www.tinder.com/</item>\n        <item>http://tinder.com</item>\n        <item>http://tinder.com</item>\n        <item>https://github.com/google/tink</item>\n        <item>https://github.com/Tencent/tinker</item>\n        <item>https://github.com/promeG/TinyPinyin</item>\n        <item>https://github.com/NovaCrypto/ToRuntime</item>\n        <item>https://github.com/drakeet/ToastCompat</item>\n        <item>https://github.com/GrenderG/Toasty</item>\n        <item>https://github.com/ifmvo/TogetherAd</item>\n        <item>https://github.com/Angads25/android-toggle</item>\n        <item>https://github.com/nex3z/ToggleButtonGroup</item>\n        <item>https://github.com/splitwise/TokenAutoComplete</item>\n        <item>https://github.com/splitwise/TokenAutoComplete</item>\n        <item>https://github.com/tomergoldst/tooltips</item>\n        <item>https://github.com/stephanenicolas/toothpick</item>\n        <item>https://github.com/horizontalsystems/tor-kit-android</item>\n        <item>https://github.com/05nelsonm/TorOnionProxyLibrary-Android</item>\n        <item>https://github.com/05nelsonm/TorOnionProxyLibrary-Android</item>\n        <item>https://github.com/05nelsonm/TorOnionProxyLibrary-Android</item>\n        <item>https://github.com/05nelsonm/TorOnionProxyLibrary-Android</item>\n        <item>https://github.com/05nelsonm/TorOnionProxyLibrary-Android</item>\n        <item>https://github.com/eneim/toro/</item>\n        <item>https://github.com/TorrentStream/TorrentStream-Android</item>\n        <item>https://github.com/MikeOrtiz/TouchImageView</item>\n        <item>https://github.com/T-Spoon/Traceur</item>\n        <item>https://developer.android.com/jetpack/androidx/releases/tracing</item>\n        <item>https://www.tradplus.com/</item>\n        <item>http://transcommu.yasesprox.com/transcommu/Help/AndroidSdkHelp</item>\n        <item>https://github.com/natario1/Transcoder</item>\n        <item>https://developer.android.com/jetpack/androidx/releases/transition</item>\n        <item>https://github.com/roynx98/transition-button-android</item>\n        <item>https://github.com/andkulikov/Transitions-Everywhere</item>\n        <item>https://github.com/gilvegliach/TransparentTextTextView</item>\n        <item>https://github.com/grandcentrix/tray</item>\n        <item>https://www.treasuredata.com/product/</item>\n        <item>https://github.com/zserge/log</item>\n        <item>https://github.com/jenkinsci/trilead-ssh2</item>\n        <item>https://trillbit.com/</item>\n        <item>https://triplelift.com</item>\n        <item>https://triplelift.com</item>\n        <item>https://github.com/datatheorem/TrustKit-Android</item>\n        <item>https://guardianproject.info/code/trustedintents/</item>\n        <item>https://github.com/raise-isayan/TunProxy</item>\n        <item>https://www.tune.com</item>\n        <item>https://www.tune.com</item>\n        <item>https://www.tutela.com/</item>\n        <item>https://tutucloud.com</item>\n        <item>https://tutucloud.com</item>\n        <item>https://github.com/haraldk/TwelveMonkeys</item>\n        <item>https://www.truedata.co/</item>\n        <item>https://github.com/twitter/twitter-kit-android</item>\n        <item>https://www.mopub.com/</item>\n        <item>https://twitter.com/</item>\n        <item>https://twitter.com/</item>\n        <item>https://twitter.com/</item>\n        <item>https://twitter.com/</item>\n        <item>https://twitter.com/</item>\n        <item>https://github.com/Twitter4J/Twitter4J</item>\n        <item>https://github.com/ultimate-deej/TwoWayNestedScrollView</item>\n        <item>https://github.com/rjeschke/txtmark</item>\n        <item>https://github.com/lightbend/config</item>\n        <item>https://github.com/skymansandy/typewriterview</item>\n        <item>https://ucads.ucweb.com/static/sso/pages/intersso.html</item>\n        <item>https://ucads.ucweb.com/static/sso/pages/intersso.html</item>\n        <item>https://github.com/nativescript-community/ui-canvas</item>\n        <item>https://github.com/hypery2k/cordova-urlhandler-plugin</item>\n        <item>https://uxcam.com/</item>\n        <item>https://uber.com</item>\n        <item>https://uber.com</item>\n        <item>https://uber.com</item>\n        <item>https://github.com/DeweyReed/UltimateRingtonePicker</item>\n        <item>http://www.umeng.com/</item>\n        <item>https://www.umeng.com/analytics</item>\n        <item>https://www.umeng.com/</item>\n        <item>https://www.umeng.com/</item>\n        <item>https://www.umeng.com/</item>\n        <item>http://dev.umeng.com/feedback</item>\n        <item>https://developer.umeng.com/docs/119267/detail/118584</item>\n        <item>https://developer.umeng.com/docs/67966/detail/153908</item>\n        <item>https://developer.umeng.com/docs/67966/detail/153908</item>\n        <item>https://developer.umeng.com/docs/67966/detail/153908</item>\n        <item>https://developer.umeng.com/docs/67966/detail/153908</item>\n        <item>https://github.com/MuntashirAkon/unapkm-android</item>\n        <item>https://www.unacast.com/</item>\n        <item>https://www.unacast.com/</item>\n        <item>https://github.com/seven332/UniFile</item>\n        <item>https://docs.uniwebview.com/</item>\n        <item>https://github.com/xuender/unidecode</item>\n        <item>https://github.com/microg/android_external_UnifiedNlpApi</item>\n        <item>https://github.com/mariotaku/UniqR</item>\n        <item>https://github.com/Mashape/unirest-java</item>\n        <item>https://docs.unity3d.com/ja/2019.4/Manual/com.unity.purchasing.html</item>\n        <item>https://docs.unity3d.com/Packages/com.unity.mobile.notifications\\@1.0</item>\n        <item>https://github.com/Agasper/unity-android-notifications</item>\n        <item>https://unity3d.com/</item>\n        <item>https://unity3d.com/</item>\n        <item>https://github.com/DaVikingCode/UnityDetectHeadset</item>\n        <item>https://github.com/nostra13/Android-Universal-Image-Loader</item>\n        <item>https://github.com/Zookey/UniversalPreferences</item>\n        <item>https://unknown.unknown</item>\n        <item>https://unknown.unknown</item>\n        <item>https://unknown.unknown</item>\n        <item>https://unknown.unknown</item>\n        <item>https://unknown.unknown</item>\n        <item>https://unknown.unknown</item>\n        <item>https://unknown.unknown</item>\n        <item>https://unknown.unknown</item>\n        <item>https://unknown.unknown</item>\n        <item>https://unknown.unknown</item>\n        <item>https://unknown.unknown</item>\n        <item>https://unknown.unknown</item>\n        <item>https://unknown.unknown</item>\n        <item>https://unknown.unknown</item>\n        <item>https://unknown.unknown</item>\n        <item>https://unknown.unknown</item>\n        <item>https://unknown.unknown</item>\n        <item>https://unknown.unknown</item>\n        <item>https://www.upsight.com/</item>\n        <item>https://github.com/urbanairship/android-library</item>\n        <item>https://github.com/linkedin/URL-Detector</item>\n        <item>https://usabilla.com/</item>\n        <item>https://github.com/felHR85/UsbSerial</item>\n        <item>https://github.com/felHR85/UsbSerial</item>\n        <item>https://github.com/felHR85/UsbSerial</item>\n        <item>https://github.com/FarbodSalamat-Zadeh/UsefulViews</item>\n        <item>https://mvnrepository.com/artifact/nl.bitwalker/UserAgentUtils</item>\n        <item>https://www.userexperior.com/</item>\n        <item>https://github.com/uservoice/uservoice-android-sdk</item>\n        <item>https://github.com/Sentaroh/Utilities</item>\n        <item>https://github.com/VKCOM/vk-android-sdk</item>\n        <item>https://github.com/VKCOM/vk-android-sdk</item>\n        <item>https://vksdk.github.io/vk-sdk-android/</item>\n        <item>https://vksdk.github.io/vk-sdk-android/</item>\n        <item>https://github.com/vanniktech/VNTNumberPickerPreference</item>\n        <item>http://www.vserv.com</item>\n        <item>https://github.com/mapsforge/vtm</item>\n        <item>https://github.com/Tencent/VasDolly</item>\n        <item>https://chocolateplatform.com/</item>\n        <item>https://chocolateplatform.com/</item>\n        <item>https://www.vectaury.io/</item>\n        <item>https://github.com/oblador/react-native-vector-icons</item>\n        <item>https://github.com/devendroid/VectorChildFinder</item>\n        <item>https://developer.android.com/jetpack/androidx/releases/vectordrawable</item>\n        <item>http://www.veloxity.net/</item>\n        <item>https://www.foresee.com/</item>\n        <item>https://www.verizonmedia.com/</item>\n        <item>https://www.verizonmedia.com/</item>\n        <item>https://www.verizonmedia.com/</item>\n        <item>https://github.com/G00fY2/version-compare</item>\n        <item>https://github.com/ernestoyaquello/VerticalStepperForm</item>\n        <item>https://github.com/h6ah4i/android-verticalseekbar</item>\n        <item>https://github.com/castorflex/VerticalViewPager</item>\n        <item>https://www.verve.com</item>\n        <item>https://github.com/CraZyLegenD/Set-Of-Useful-Kotlin-Extensions-and-Helpers/tree/master/viewbinding</item>\n        <item>https://github.com/pakerfeldt/android-viewflow</item>\n        <item>https://github.com/kirich1409/ViewBindingPropertyDelegate</item>\n        <item>https://github.com/afollestad/viewpagerdots</item>\n        <item>https://github.com/zhpanvip/viewpagerindicator</item>\n        <item>https://github.com/ToxicBakery/ViewPagerTransforms</item>\n        <item>https://github.com/blipinsk/ViewPropertyObjectAnimator</item>\n        <item>https://github.com/InflationX/ViewPump</item>\n        <item>https://github.com/4face-studi0/ViewStateStore</item>\n        <item>https://github.com/florent37/ViewTooltip</item>\n        <item>https://developer.android.com/jetpack/androidx/releases/viewpager</item>\n        <item>http://virgomobile.com/</item>\n        <item>https://github.com/asLody/VirtualApp</item>\n        <item>https://github.com/asLody/VirtualApp</item>\n        <item>https://developer.vivo.com/home</item>\n        <item>https://www.vodafone.com/</item>\n        <item>https://developer.android.com/training/volley</item>\n        <item>https://github.com/alphacep/vosk-api/</item>\n        <item>https://www.vpon.com/</item>\n        <item>https://www.vpon.com/</item>\n        <item>https://www.vpon.com/</item>\n        <item>https://www.vpon.com/</item>\n        <item>https://vungle.com</item>\n        <item>https://vungle.com</item>\n        <item>https://github.com/Tencent/wcdb</item>\n        <item>https://github.com/tajchert/WaitingDots</item>\n        <item>https://walkme.com</item>\n        <item>https://walkme.com</item>\n        <item>https://walkme.com</item>\n        <item>https://walkme.com</item>\n        <item>https://docs.walletconnect.org/</item>\n        <item>https://wannads.com/</item>\n        <item>https://wapstart.ru/en/</item>\n        <item>https://github.com/tangqi92/WaveLoadingView</item>\n        <item>https://github.com/tangqi92/WaveLoadingView</item>\n        <item>https://wechat.com</item>\n        <item>https://wechat.com</item>\n        <item>https://wechat.com</item>\n        <item>https://wechat.com</item>\n        <item>https://github.com/web3j/web3j</item>\n        <item>https://github.com/InQBarna/WebIntent</item>\n        <item>https://github.com/flutter/plugins/tree/master/packages/webview_flutter</item>\n        <item>https://github.com/wbayer/webview-gm</item>\n        <item>https://developer.android.com/jetpack/androidx/releases/webkit</item>\n        <item>https://chromium.googlesource.com/chromium/src/+/HEAD/android_webview/support_library/boundary_interfaces</item>\n        <item>https://www.weborama.com</item>\n        <item>https://www.webtrekk.com/</item>\n        <item>https://www.webtrends.com/</item>\n        <item>https://www.webtrends.com/</item>\n        <item>http://weibo.com/</item>\n        <item>https://4hou.win/wordpress/\\?author=1190</item>\n        <item>https://github.com/stephentuso/welcome-android</item>\n        <item>https://snmp.westhawk.co.uk/api/</item>\n        <item>https://bitletorg.github.io/weupnp/</item>\n        <item>https://github.com/haroldadmin/WhatTheStack</item>\n        <item>https://github.com/AigeStudio/WheelPicker</item>\n        <item>https://github.com/lantouzi/WheelView-Android</item>\n        <item>http://widespace.com</item>\n        <item>https://github.com/square/wire</item>\n        <item>https://github.com/WireGuard/wireguard-android</item>\n        <item>https://github.com/WireGuard/wireguard-android</item>\n        <item>https://github.com/WireGuard/wireguard-android</item>\n        <item>https://github.com/WireGuard/wireguard-android</item>\n        <item>https://github.com/WireGuard/wireguard-android</item>\n        <item>https://github.com/TechFreak/WizardPager</item>\n        <item>https://www.wonderpush.com/</item>\n        <item>https://github.com/FasterXML/woodstox</item>\n        <item>https://github.com/Woopra/woopra-android-sdk</item>\n        <item>https://github.com/Woopra/woopra-android-sdk</item>\n        <item>http://woorlds.com</item>\n        <item>http://wootric.com</item>\n        <item>https://developer.android.com/jetpack/androidx/releases/work</item>\n        <item>https://github.com/square/workflow</item>\n        <item>https://wortise.com</item>\n        <item>https://xmode.io/</item>\n        <item>https://xmode.io/</item>\n        <item>https://xmode.io/</item>\n        <item>https://knowm.org/open-source/xchange/</item>\n        <item>https://github.com/elvishew/xLog</item>\n        <item>http://www.xmlpull.org/</item>\n        <item>https://xmlbeans.apache.org/index.html</item>\n        <item>https://xmlbeans.apache.org/index.html</item>\n        <item>http://www.xmlunit.org/</item>\n        <item>https://directory.fsf.org/wiki/XMPCore</item>\n        <item>https://github.com/Maxr1998/XMediaNotificationTrackSelector</item>\n        <item>https://github.com/li-xiaojun/XPermission</item>\n        <item>https://github.com/li-xiaojun/XPopup</item>\n        <item>https://github.com/li-xiaojun/XPopup</item>\n        <item>https://github.com/getActivity/XXPermissions</item>\n        <item>http://tukaani.org/xz/java.html</item>\n        <item>https://xamarin.com/</item>\n        <item>https://github.com/xamarin/Xamarin.Forms/</item>\n        <item>https://github.com/xamarin/Xamarin.Forms/</item>\n        <item>http://mipush.global.xiaomi.com/</item>\n        <item>https://dev.mi.com/console/doc/detail\\?pId=1244</item>\n        <item>https://dev.mi.com/console/doc/detail\\?pId=1244</item>\n        <item>https://github.com/dryade/vtd-xml</item>\n        <item>https://github.com/rovo89/XposedBridge</item>\n        <item>https://github.com/yangchong211/YCExpandView</item>\n        <item>https://yoc.com</item>\n        <item>https://www.yahoo.co.jp/</item>\n        <item>https://www.yahoo.co.jp/</item>\n        <item>https://www.yahoo.co.jp/</item>\n        <item>https://www.yahoo.co.jp/</item>\n        <item>https://www.yahoo.co.jp/</item>\n        <item>https://www.yahoo.co.jp/</item>\n        <item>https://www.yahoo.co.jp/</item>\n        <item>https://www.yahoo.co.jp/</item>\n        <item>https://github.com/EsotericSoftware/yamlbeans</item>\n        <item>https://www.yandex.com/</item>\n        <item>https://github.com/yandex-disk/yandex-disk-sdk-java</item>\n        <item>https://www.yext.com/</item>\n        <item>https://yieldlab.com/</item>\n        <item>http://www.yinzcam.com/</item>\n        <item>https://yoadx.com/</item>\n        <item>https://yotaphone.com/ae-en/developer/docs/develop/building-first-app-epd/</item>\n        <item>https://www.youappi.com</item>\n        <item>https://github.com/googleapis/google-api-java-client-services</item>\n        <item>https://github.com/googleapis/google-api-java-client-services</item>\n        <item>https://developers.google.com/youtube/android/player/reference/com/google/android/youtube/player/package-summary</item>\n        <item>https://github.com/googleapis/google-api-java-client-services/tree/main/clients/google-api-services-youtube</item>\n        <item>http://www.yougoodtech.com/</item>\n        <item>http://www.yougoodtech.com/</item>\n        <item>https://www.youmi.net/</item>\n        <item>https://github.com/kotvertolet/youtube-jextractor</item>\n        <item>https://www.appbrain.com/stats/libraries/details/yume/yume</item>\n        <item>https://yueying-docs.effirst.com/</item>\n        <item>https://yueying-docs.effirst.com/</item>\n        <item>https://github.com/ZBar/ZBar</item>\n        <item>https://github.com/sho5nn/ZDepthShadow</item>\n        <item>https://github.com/marschall/zipfilesystem-standalone</item>\n        <item>https://github.com/zxing/zxing</item>\n        <item>https://github.com/journeyapps/zxing-android-embedded</item>\n        <item>https://github.com/jenly1314/ZXingLite</item>\n        <item>https://www.zapr.in/</item>\n        <item>https://github.com/zcash/zcash-android-wallet-sdk</item>\n        <item>https://github.com/zcash/zcash-android-wallet-sdk</item>\n        <item>https://github.com/bcraig/Zebra</item>\n        <item>http://techdocs.zebra.com/link-os/latest/webservices/content/overview-summary.html</item>\n        <item>https://developer.zendesk.com/</item>\n        <item>https://www.zendrive.com/</item>\n        <item>http://www.zenjoy.net/</item>\n        <item>https://github.com/emanuele-f/zdtun</item>\n        <item>https://github.com/zerotier/ZeroTierOne</item>\n        <item>https://github.com/zeroturnaround/zt-zip</item>\n        <item>http://www.lingala.net/zip4j/</item>\n        <item>http://analytics.zoho.com/</item>\n        <item>https://github.com/natario1/ZoomLayout</item>\n        <item>https://github.com/nuclearfog/ZoomView</item>\n        <item>https://github.com/luben/zstd-jni</item>\n        <item>http://zucks.co.jp</item>\n        <item>https://github.com/jfmdev/aFileDialog</item>\n        <item>https://github.com/BoD/aLibGlitch</item>\n        <item>https://github.com/gturri/aXMLRPC</item>\n        <item>https://github.com/PureWriter/about-page</item>\n        <item>https://adpopcorn.com/</item>\n        <item>https://adpopcorn.com/</item>\n        <item>https://www.adboost.sk/</item>\n        <item>https://github.com/stkent/amplify</item>\n        <item>https://github.com/side-codes/andColorPicker</item>\n        <item>https://github.com/baoyongzhang/android-PullRefreshLayout</item>\n        <item>https://github.com/curioustechizen/android-ago</item>\n        <item>https://github.com/twofortyfouram/android-annotation</item>\n        <item>https://github.com/twofortyfouram/android-assertion</item>\n        <item>https://github.com/code-troopers/android-betterpickers</item>\n        <item>https://github.com/koem/android-change-log</item>\n        <item>https://github.com/chen0040/android-code-view</item>\n        <item>https://github.com/jdamcd/android-crop</item>\n        <item>https://github.com/dialogs/android-dialer</item>\n        <item>https://github.com/hedzr/android-file-chooser</item>\n        <item>https://github.com/wcmatthysen/android-filechooser</item>\n        <item>https://github.com/koral--/android-gif-drawable</item>\n        <item>https://github.com/unfoldingWord-dev/android-gogs-client</item>\n        <item>https://github.com/lelloman/android-identicons</item>\n        <item>https://github.com/freefair/injection</item>\n        <item>https://github.com/heinrichreimer/android-issue-reporter</item>\n        <item>https://github.com/react-native-community/jsc-android-buildscripts</item>\n        <item>https://github.com/eetac/android-logging-log4j</item>\n        <item>https://github.com/brk3/android-multitouch-controller</item>\n        <item>https://github.com/dmytrodanylyk/android-process-button</item>\n        <item>https://github.com/Kaopiz/android-segmented-control</item>\n        <item>https://github.com/danieldimatteo/android-speech-diarization</item>\n        <item>https://github.com/sromku/android-storage</item>\n        <item>https://github.com/mhutti1/android-storage-devices</item>\n        <item>https://github.com/Knickedi/android-toolbox</item>\n        <item>https://github.com/ypresto/android-transcoder</item>\n        <item>https://github.com/markushi/android-ui</item>\n        <item>https://github.com/freefair/android-util</item>\n        <item>https://github.com/freefair/android-util</item>\n        <item>https://github.com/PierfrancescoSoffritti/Android-YouTube-Player</item>\n        <item>https://github.com/HaarigerHarald/android-youtubeExtractor</item>\n        <item>https://github.com/yipianfengye/android-zxingLibrary</item>\n        <item>https://github.com/weidongjian/androidWheelView</item>\n        <item>https://github.com/AOSPA/android_external_themelib</item>\n        <item>https://developer.android.com/jetpack/androidx/releases/legacy</item>\n        <item>https://github.com/archos-sa/aos-Video</item>\n        <item>https://github.com/archos-sa/aos-Video</item>\n        <item>https://github.com/ExCiteS/apache-commons-codec-shaded</item>\n        <item>https://github.com/clearthesky/apk-parser</item>\n        <item>https://android.googlesource.com/platform/tools/apksig/</item>\n        <item>http://www.appplant.de/</item>\n        <item>https://www.apptv.com/apptv-android-sdk</item>\n        <item>http://www.appgeneration.com/</item>\n        <item>https://github.com/hierynomus/asn-one</item>\n        <item>https://github.com/florent37/Flutter-AssetsAudioPlayer</item>\n        <item>https://github.com/afollestad/async/</item>\n        <item>https://github.com/derlio/audio-waveform</item>\n        <item>https://github.com/ryanheise/audio_service</item>\n        <item>https://github.com/ryanheise/audio_session</item>\n        <item>https://github.com/authpass/autofill_service</item>\n        <item>https://github.com/robinst/autolink-java</item>\n        <item>https://www.ayetstudios.com</item>\n        <item>https://github.com/rekab-app/background_locator</item>\n        <item>https://github.com/dm77/barcodescanner</item>\n        <item>https://github.com/EddyVerbruggen/barcodescanner-lib-aar</item>\n        <item>https://github.com/turbomanage/basic-http-client</item>\n        <item>https://www.beaconstac.com</item>\n        <item>https://github.com/DreaminginCodeZH/betterpickers</item>\n        <item>https://github.com/horizontalsystems/binance-chain-kit-android</item>\n        <item>https://github.com/authpass/biometric_storage</item>\n        <item>https://github.com/ACINQ/bitcoin-lib</item>\n        <item>https://github.com/bitcoin-wallet/bitcoin-wallet</item>\n        <item>https://github.com/bitcoinj/bitcoinj</item>\n        <item>https://github.com/bitcoinj/bitcoinj</item>\n        <item>https://github.com/mangstadt/biweekly</item>\n        <item>https://github.com/hbldh/bleak</item>\n        <item>https://github.com/google/brotli</item>\n        <item>https://github.com/abrensch/brouter</item>\n        <item>https://github.com/LedgerHQ/btchip-java-api</item>\n        <item>https://github.com/Commit451/bypasses</item>\n        <item>https://github.com/cache2k/cache2k</item>\n        <item>https://github.com/ReactiveCircus/cache4k</item>\n        <item>https://github.com/saket/cascade/</item>\n        <item>https://github.com/bitfireAT/cert4android</item>\n        <item>https://github.com/cglib/cglib</item>\n        <item>https://github.com/chRyNaN/chords</item>\n        <item>https://github.com/ItsPriyesh/chroma</item>\n        <item>https://github.com/circe/circe</item>\n        <item>https://github.com/cketti/ckChangeLog</item>\n        <item>https://github.com/kostaskougios/cloning</item>\n        <item>https://github.com/zhkrb/cloudflare-scrape-Android</item>\n        <item>https://github.com/atlassian/commonmark-java</item>\n        <item>https://github.com/shred/commons-suncalc</item>\n        <item>https://github.com/onebone/compose-collapsing-toolbar</item>\n        <item>https://pub.dev/packages/connectivity</item>\n        <item>https://github.com/ourcodeworld/cordova-ourcodeworld-filebrowser</item>\n        <item>https://github.com/mjwheatley/cordova-plugin-android-fingerprint-auth</item>\n        <item>https://github.com/transistorsoft/cordova-plugin-background-fetch</item>\n        <item>https://github.com/Delagen/cordova-plugin-browser</item>\n        <item>https://github.com/pwlin/cordova-plugin-file-opener2</item>\n        <item>https://github.com/NiklasMerz/cordova-plugin-fingerprint-aio</item>\n        <item>https://github.com/DavidBriglio/cordova-plugin-foreground-service</item>\n        <item>https://libraries.io/github/xfally/cordova-plugin-ftp</item>\n        <item>https://github.com/napolitano/cordova-plugin-intent</item>\n        <item>https://github.com/katzer/cordova-plugin-local-notifications</item>\n        <item>https://github.com/katzer/cordova-plugin-local-notifications</item>\n        <item>https://github.com/greybax/cordova-plugin-native-spinner</item>\n        <item>https://github.com/fagundes/cordova-plugin-navigationbar</item>\n        <item>https://github.com/doctolib/cordova-plugin-overview</item>\n        <item>https://github.com/whiteoctober/cordova-plugin-push-notifications</item>\n        <item>https://github.com/bitpay/cordova-plugin-qrscanner</item>\n        <item>https://github.com/gbenvenuti/cordova-plugin-screen-orientation</item>\n        <item>https://github.com/echonox/cordova-plugin-snackbar</item>\n        <item>https://github.com/knowledgecode/WebSocket-for-Android</item>\n        <item>https://github.com/sahana/eden_mobile/tree/master/plugins/cordova-sqlite-storage</item>\n        <item>https://github.com/chemerisuk/cordova-support-android-plugin</item>\n        <item>https://github.com/westnordost/countryboundaries</item>\n        <item>http://cpdetector.sourceforge.net/</item>\n        <item>https://github.com/harjot-oberai/Croller</item>\n        <item>https://github.com/harjot-oberai/Croller</item>\n        <item>https://github.com/electrolobzik/cupboard</item>\n        <item>https://github.com/WhisperSystems/curve25519-java</item>\n        <item>https://github.com/virtuald/curvesapi</item>\n        <item>https://github.com/hossein-amini/bottom-sheet</item>\n        <item>https://github.com/cybergarage/cybergarage-upnp</item>\n        <item>https://github.com/cybergarage/cybergarage-upnp</item>\n        <item>https://github.com/cybergarage/cybergarage-upnp</item>\n        <item>https://github.com/cybergarage/cybergarage-upnp</item>\n        <item>https://github.com/cybergarage/cybergarage-upnp</item>\n        <item>https://github.com/cybergarage/cybergarage-upnp</item>\n        <item>https://github.com/darryncampbell/darryncampbell-cordova-plugin-intent</item>\n        <item>https://github.com/bitfireAT/dav4jvm</item>\n        <item>https://deltadna.com/</item>\n        <item>https://deploygate.com/</item>\n        <item>https://github.com/flutter/plugins/tree/master/packages/device_info/device_info</item>\n        <item>https://github.com/fluttercommunity/plus_plugins/tree/main/packages/device_info_plus</item>\n        <item>https://github.com/pxb1988/dex2jar</item>\n        <item>https://github.com/alibaba/dexposed</item>\n        <item>https://github.com/dnsjava/dnsjava</item>\n        <item>https://github.com/ibauersachs/dnssecjava</item>\n        <item>https://github.com/dom4j/dom4j</item>\n        <item>https://github.com/inkytonik/dsprofile</item>\n        <item>https://github.com/material-foundation/material-dynamic-color-flutter</item>\n        <item>https://github.com/silvaren/easyrs</item>\n        <item>https://github.com/ACINQ/eclair</item>\n        <item>https://github.com/sawankumarbundelkhandi/edge_detection</item>\n        <item>https://github.com/vdurmont/emoji-java</item>\n        <item>https://github.com/psiegman/epublib</item>\n        <item>https://github.com/esysberlin/esys-flutter-share</item>\n        <item>http://www.objecthunter.net/exp4j/</item>\n        <item>https://github.com/expo/expo/tree/master/packages/expo-application</item>\n        <item>https://github.com/expo/expo/tree/master/packages/expo-constants</item>\n        <item>https://github.com/expo/expo/tree/main/packages/expo-error-recovery</item>\n        <item>https://github.com/expo/expo/tree/master/packages/expo-file-system</item>\n        <item>https://github.com/expo/expo/tree/main/packages/expo-font</item>\n        <item>https://github.com/expo/expo/tree/master/packages/expo-image-loader</item>\n        <item>https://github.com/expo/expo/tree/main/packages/expo-keep-awake</item>\n        <item>https://github.com/expo/expo/tree/master/packages/expo-permissions</item>\n        <item>https://github.com/expo/expo/tree/master/packages/expo-screen-orientation</item>\n        <item>https://github.com/expo/expo/tree/master/packages/expo-splash-screen</item>\n        <item>https://github.com/expo/expo/tree/main/packages/expo-sqlite</item>\n        <item>https://github.com/expo/expo/tree/main/packages/expo-web-browser</item>\n        <item>https://github.com/yasukotelin/ext_storage</item>\n        <item>https://github.com/mangstadt/ez-vcard</item>\n        <item>https://github.com/alibaba/fastjson</item>\n        <item>http://fineapptech.com/</item>\n        <item>http://fineapptech.com/</item>\n        <item>http://fineapptech.com/</item>\n        <item>http://fineapptech.com/</item>\n        <item>http://www.yifants.cn/</item>\n        <item>https://github.com/vsch/flexmark-java</item>\n        <item>https://github.com/DavBfr/dart_pdf</item>\n        <item>https://github.com/alemohamad/flutter-appbrewery</item>\n        <item>https://github.com/KasemJaffer/flutter_absolute_path</item>\n        <item>https://github.com/sidlatau/flutter_email_sender</item>\n        <item>https://github.com/tanersener/flutter-ffmpeg</item>\n        <item>https://github.com/kineapps/flutter_file_dialog/tree/master</item>\n        <item>https://github.com/MaikuB/flutter_local_notifications/</item>\n        <item>https://github.com/taljacobson/flutter_mailer</item>\n        <item>https://github.com/jonbhanson/flutter_native_splash</item>\n        <item>https://github.com/pinkfish/flutter_native_timezone</item>\n        <item>https://github.com/inway/flutter_ringtone_player</item>\n        <item>https://github.com/mogol/flutter_secure_storage</item>\n        <item>https://github.com/PonnamKarthik/FlutterToast</item>\n        <item>https://flymob.com/</item>\n        <item>https://github.com/hex007/freej2me</item>\n        <item>http://frogermcs.github.io/FrameMetrics-realtime-app-smoothness-tracking</item>\n        <item>https://github.com/frostwire/frostwire-jlibtorrent</item>\n        <item>http://www.sauronsoftware.it/projects/ftp4j/</item>\n        <item>https://www.fullstory.com/</item>\n        <item>https://www.fullstory.com/</item>\n        <item>https://www.fullstory.com/</item>\n        <item>https://www.fullstory.com/</item>\n        <item>https://www.fullstory.com/</item>\n        <item>https://www.fullstory.com/</item>\n        <item>https://github.com/mfietz/fyydlin</item>\n        <item>https://github.com/grpc/grpc-java</item>\n        <item>https://github.com/smola/galimatias</item>\n        <item>https://github.com/google/gdata-java-client</item>\n        <item>https://github.com/crashinvaders/gdx-vfx</item>\n        <item>https://github.com/aloisdeniel/flutter_geocoder</item>\n        <item>https://github.com/theapache64/github_android_sdk</item>\n        <item>https://github.com/PnX-SI/gn_mobile_maps</item>\n        <item>https://github.com/danwilson/google-analytics-plugin</item>\n        <item>https://github.com/Andersbakken/google-diff-match-patch</item>\n        <item>https://github.com/google/google-java-format</item>\n        <item>https://github.com/himanshu-soni/gpx-parser</item>\n        <item>https://github.com/graphql-java/graphql-java</item>\n        <item>https://github.com/graphql-java/graphql-java</item>\n        <item>https://github.com/greenrobot/greenDAO</item>\n        <item>https://github.com/greenrobot/greenDAO</item>\n        <item>https://github.com/lisawray/groupie</item>\n        <item>https://github.com/gkopff/gson-jodatime-serialisers</item>\n        <item>https://github.com/GStreamer/gst-plugins-bad</item>\n        <item>https://github.com/hCaptcha/hcaptcha-android-sdk</item>\n        <item>https://github.com/javaee/hk2</item>\n        <item>https://github.com/opendatakit/httpclientandroidlib</item>\n        <item>https://github.com/surespot/httpclientandroidlib</item>\n        <item>https://www2.i-mobile.co.jp/en/index.aspx</item>\n        <item>https://ical4j.github.io/</item>\n        <item>http://iharder.sourceforge.net/current/java/base64/</item>\n        <item>https://github.com/itext/itext7</item>\n        <item>https://github.com/itext/itextpdf</item>\n        <item>https://github.com/itext/itextpdf</item>\n        <item>https://github.com/bitfireAT/ical4android</item>\n        <item>https://github.com/aloisdeniel/image_native_resizer</item>\n        <item>https://github.com/sevar83/indeterminate-checkbox</item>\n        <item>http://ini4j.sourceforge.net/</item>\n        <item>https://github.com/koush/ion</item>\n        <item>https://iridge.jp/</item>\n        <item>https://www.ironsrc.com</item>\n        <item>http://www.mindrot.org/projects/jBCrypt/</item>\n        <item>https://github.com/Bombe/jFCPlib</item>\n        <item>https://github.com/gturri/jISO8601</item>\n        <item>https://github.com/bravobit/jPastebin</item>\n        <item>http://junit.org/</item>\n        <item>https://github.com/fge/jackson-coreutils</item>\n        <item>https://github.com/jai-imageio/jai-imageio-core</item>\n        <item>https://github.com/tozny/java-aes-crypto</item>\n        <item>https://github.com/ipfs-shipyard/java-ipfs-http-client</item>\n        <item>https://github.com/ipfs-shipyard/java-ipfs-http-client</item>\n        <item>https://github.com/ipfs-shipyard/java-ipfs-http-client</item>\n        <item>https://github.com/ipfs-shipyard/java-ipfs-http-client</item>\n        <item>https://github.com/ipfs-shipyard/java-ipfs-http-client</item>\n        <item>https://github.com/kiwix/java-libkiwix</item>\n        <item>https://github.com/opentimestamps/java-opentimestamps</item>\n        <item>https://github.com/tdebatty/java-string-similarity</item>\n        <item>https://github.com/tdebatty/java-string-similarity</item>\n        <item>https://github.com/sealedtx/java-youtube-downloader</item>\n        <item>https://github.com/Sentaroh/jcifsng-211-20190202</item>\n        <item>https://github.com/Sentaroh/jcifsng-212-20190324</item>\n        <item>https://github.com/Sentaroh/jcifsng-214-20200413</item>\n        <item>https://github.com/Sentaroh/jcifs-ng-for-jcifsfile</item>\n        <item>https://github.com/jruby/jcodings</item>\n        <item>https://github.com/jnr/jffi</item>\n        <item>https://github.com/jmdns/jmdns</item>\n        <item>https://github.com/square/jna-gmp</item>\n        <item>https://github.com/jnr/jnr-enxio</item>\n        <item>https://github.com/jnr/jnr-ffi</item>\n        <item>https://github.com/jnr/jnr-posix</item>\n        <item>https://github.com/jnr/jnr-unixsocket</item>\n        <item>https://github.com/jnr/jnr-x86asm</item>\n        <item>https://github.com/dlew/joda-time-android</item>\n        <item>https://github.com/jruby/joni</item>\n        <item>https://github.com/jparsec/jparsec</item>\n        <item>https://github.com/ravn/jsocks</item>\n        <item>https://github.com/fge/json-schema-formats</item>\n        <item>https://github.com/networknt/json-schema-validator</item>\n        <item>https://github.com/netplex/json-smart-v2</item>\n        <item>https://github.com/netplex/json-smart-v2</item>\n        <item>https://github.com/jasminb/jsonapi-converter</item>\n        <item>https://jsoup.org/</item>\n        <item>https://github.com/DroidsOnRoids/jspoon</item>\n        <item>https://github.com/guardianproject/jtorctl</item>\n        <item>https://github.com/albfernandez/juniversalchardet</item>\n        <item>https://github.com/anthonynsimon/jurl</item>\n        <item>https://github.com/ryanheise/just_audio</item>\n        <item>https://sourceforge.net/projects/jutf7/</item>\n        <item>https://github.com/TokTok/jvm-toxcore-api</item>\n        <item>https://github.com/TokTok/jvm-toxcore-api</item>\n        <item>https://github.com/ghetolay/jwamp</item>\n        <item>https://github.com/zeoflow/jx</item>\n        <item>https://github.com/k3b/k3b-geoHelper/</item>\n        <item>https://github.com/k3b/k3b-geoHelper/</item>\n        <item>https://github.com/k3b/k3b-geoHelper/</item>\n        <item>https://github.com/k3b/k3b-geoHelper</item>\n        <item>https://github.com/Karn/khttp-android</item>\n        <item>https://github.com/karlmdavis/kobjects</item>\n        <item>https://github.com/Kr328/kaidl</item>\n        <item>https://github.com/abstractj/kalium</item>\n        <item>https://github.com/charleskorn/kaml</item>\n        <item>https://github.com/jrmelsha/keccak</item>\n        <item>https://github.com/aelstad/keccakj</item>\n        <item>https://github.com/ascclemens/khttp</item>\n        <item>https://kiddoware.com/kids-place-parental-control-for-android-devices/</item>\n        <item>https://kivy.org/</item>\n        <item>https://github.com/doyaaaaaken/kotlin-csv</item>\n        <item>https://github.com/JetBrains/kotlin/tree/cdbfa7fbbc6f31dbcb6264f456bfedee1a85c40b/plugins/parcelize</item>\n        <item>https://github.com/michaelbull/kotlin-result</item>\n        <item>https://github.com/Kotlin/kotlinx-datetime</item>\n        <item>https://github.com/Kotlin/kotlinx.coroutines</item>\n        <item>https://github.com/helloklf/kr-scripts</item>\n        <item>https://github.com/magro/kryo-serializers</item>\n        <item>https://github.com/simpligility/ksoap2-android</item>\n        <item>https://github.com/optimaize/language-detector</item>\n        <item>https://github.com/antoniotari/last-fm-library</item>\n        <item>https://github.com/Purus/launch_review</item>\n        <item>https://github.com/libgdx/libgdx</item>\n        <item>https://github.com/Chainfire/librootjava</item>\n        <item>https://github.com/adblockplus/libadblockplus</item>\n        <item>https://github.com/magnusja/libaums</item>\n        <item>https://github.com/signalapp/libsignal-protocol-java</item>\n        <item>https://github.com/dogecoin/libdohj</item>\n        <item>https://github.com/googlei18n/libphonenumber</item>\n        <item>https://github.com/MichaelRocks/libphonenumber-android</item>\n        <item>https://github.com/librespot-org/librespot-java</item>\n        <item>https://github.com/zhanghai/libselinux-android</item>\n        <item>https://github.com/joshjdevl/libsodium-jni</item>\n        <item>https://github.com/google-research/libsoftwaresync</item>\n        <item>https://github.com/topjohnwu/libsu</item>\n        <item>https://github.com/Chainfire/libsuperuser</item>\n        <item>https://github.com/jgriffiths/libwally-core</item>\n        <item>https://github.com/signalapp/libwebrtc-android</item>\n        <item>https://github.com/flutter/plugins/tree/master/packages/local_auth</item>\n        <item>https://github.com/tony19/logback-android</item>\n        <item>https://github.com/love2d/love-android</item>\n        <item>https://github.com/BjoernPetersen/m3u-parser</item>\n        <item>https://github.com/SpongeBobSun/mCalendarView</item>\n        <item>http://mparticle.com</item>\n        <item>https://www.mtraction.com/</item>\n        <item>https://mtraction.com</item>\n        <item>https://adpf-info.i-mobile.co.jp/en/</item>\n        <item>https://github.com/mapsme/api-android</item>\n        <item>https://github.com/daniel-stoneuk/material-about-library</item>\n        <item>https://github.com/heinrichreimer/material-intro</item>\n        <item>https://github.com/Shahroz16/material-searchview</item>\n        <item>https://www.mediba.jp</item>\n        <item>https://www.mediba.jp</item>\n        <item>https://github.com/drewnoakes/metadata-extractor</item>\n        <item>https://github.com/microg/GmsCore</item>\n        <item>https://github.com/ralfstx/minimal-json</item>\n        <item>https://github.com/the8472/mldht</item>\n        <item>https://github.com/chenlb</item>\n        <item>https://github.com/mikvor/money-conversion</item>\n        <item>https://github.com/mongodb/mongo-java-driver</item>\n        <item>https://github.com/JochenHeizmann/monkeybass</item>\n        <item>https://codeberg.org/moxxy/moxplatform</item>\n        <item>https://github.com/mpatric/mp3agic</item>\n        <item>https://github.com/copiousfreetime/mp4parser</item>\n        <item>https://github.com/copiousfreetime/mp4parser</item>\n        <item>https://github.com/fge/msg-simple</item>\n        <item>https://github.com/DexPatcher/multidexlib2</item>\n        <item>https://github.com/opacapp/multiline-collapsingtoolbar</item>\n        <item>https://target.my.com/</item>\n        <item>https://tracker.my.com/</item>\n        <item>https://github.com/ntop/nDPI</item>\n        <item>https://github.com/tony19/named-regexp</item>\n        <item>https://github.com/mmastrac/nanojson</item>\n        <item>https://gitlab.com/burke-software/nativescript-foss-sidedrawer</item>\n        <item>https://github.com/bthurlow/nativescript-imagecropper</item>\n        <item>https://github.com/jibon57/nativescript-mediafilepicker</item>\n        <item>https://github.com/prabudevarrajan/nativescript-plugin-filepicker</item>\n        <item>https://github.com/NativeScript/nativescript-unit-test-runner</item>\n        <item>https://nend.net/en/</item>\n        <item>https://nend.net/en/</item>\n        <item>https://github.com/fommil/netlib-java</item>\n        <item>https://www.netmera.com/</item>\n        <item>https://github.com/christianrowlands/network-survey-messaging</item>\n        <item>https://github.com/novoda/notils</item>\n        <item>https://github.com/TakahikoKawasaki/nv-i18n</item>\n        <item>https://github.com/TakahikoKawasaki/nv-websocket-client</item>\n        <item>https://github.com/rburgst/okhttp-digest</item>\n        <item>https://github.com/pakerfeldt/okhttp-signpost</item>\n        <item>https://github.com/gsantner/opoc</item>\n        <item>https://github.com/freenet-mobile/onion-common/tree/master/src/main/java/com/onionnetworks</item>\n        <item>https://github.com/freenet-mobile/onion-common/tree/master/src/main/java/com/onionnetworks</item>\n        <item>https://github.com/freenet-mobile/onion-common/tree/master/src/main/java/com/onionnetworks</item>\n        <item>https://github.com/freenet-mobile/onion-fec</item>\n        <item>https://github.com/crazecoder/open_file</item>\n        <item>https://github.com/matejcik/openwig</item>\n        <item>https://docs.oracle.com/javase/7/docs/api/org/w3c/dom/package-summary.html</item>\n        <item>https://github.com/j256/ormlite-android</item>\n        <item>https://github.com/westnordost/osmapi</item>\n        <item>https://github.com/westnordost/osmfeatures</item>\n        <item>https://github.com/jitsi/otr4j</item>\n        <item>https://github.com/EverythingMe/overscroll-decor</item>\n        <item>https://github.com/owncloud/android-library</item>\n        <item>https://github.com/pCloud/pcloud-sdk-java</item>\n        <item>https://github.com/fluttercommunity/plus_plugins/tree/main/packages/package_info_plus</item>\n        <item>https://github.com/flutter/plugins/tree/master/packages/path_provider</item>\n        <item>https://github.com/AmudAnan/flutter_path_provider_ex</item>\n        <item>https://github.com/jberkel/pay-me</item>\n        <item>https://github.com/ViliusSutkus89/pdf2htmlEX-Android</item>\n        <item>https://github.com/mshockwave/PdfiumAndroid</item>\n        <item>https://github.com/phonegap/phonegap-plugin-push</item>\n        <item>http://pinable-dmp.com/</item>\n        <item>https://github.com/FangStarNet/pinyin4j-multi</item>\n        <item>https://github.com/FangStarNet/pinyin4j-multi</item>\n        <item>https://github.com/yeriomin/play-store-api</item>\n        <item>http://square.github.io/pollexor/</item>\n        <item>https://github.com/davidmoten/predict4java</item>\n        <item>https://github.com/ocpsoft/prettytime</item>\n        <item>https://github.com/LN-Zap/protoc-gen-zap-java</item>\n        <item>https://github.com/pyamsoft/pydroid</item>\n        <item>https://github.com/kivy/pyjnius</item>\n        <item>https://github.com/renpy/python-for-android</item>\n        <item>https://github.com/liuyueyi/quick-chinese-transfer</item>\n        <item>https://github.com/flutter/plugins/tree/master/packages/quick_actions/quick_actions</item>\n        <item>https://github.com/callstack/repack</item>\n        <item>https://github.com/JonnyBGod/react-native-eventsource</item>\n        <item>https://github.com/mouselangelo/react-native-actions-shortcuts</item>\n        <item>https://github.com/Rapsssito/react-native-background-actions</item>\n        <item>https://github.com/transistorsoft/react-native-background-fetch</item>\n        <item>https://github.com/vikeri/react-native-background-job</item>\n        <item>https://github.com/jamesisaac/react-native-background-task/</item>\n        <item>https://github.com/ekreutz/react-native-barcode-scanner-google</item>\n        <item>https://github.com/zoontek/react-native-bars</item>\n        <item>https://github.com/solinor/react-native-bluetooth-status</item>\n        <item>https://github.com/zoontek/react-native-bootsplash</item>\n        <item>https://github.com/WhatAKitty/react-native-bottom-sheet</item>\n        <item>https://github.com/luggit/react-native-config</item>\n        <item>https://github.com/joeferraro/react-native-cookies</item>\n        <item>https://github.com/kevinresol/react-native-default-preference</item>\n        <item>https://github.com/rebeccahughes/react-native-device-info</item>\n        <item>https://github.com/Elyx0/react-native-document-picker</item>\n        <item>https://github.com/hu9osaez/react-native-dominant-color</item>\n        <item>https://github.com/master-atul/react-native-exception-handler</item>\n        <item>https://github.com/wumke/react-native-exit-app</item>\n        <item>https://github.com/corymsmith/react-native-fabric</item>\n        <item>https://github.com/evollu/react-native-fcm</item>\n        <item>https://github.com/wkh237/react-native-fetch-blob-package</item>\n        <item>https://github.com/alpha0010/react-native-file-access</item>\n        <item>https://github.com/vinzscam/react-native-file-viewer</item>\n        <item>https://github.com/kristiansorens/react-native-flag-secure-android</item>\n        <item>https://github.com/itinance/react-native-fs</item>\n        <item>https://github.com/zhangtaii/react-native-google-place-picker</item>\n        <item>https://github.com/Onibenjo/react-native-html-to-pdf</item>\n        <item>https://github.com/AlexanderZaytsev/react-native-i18n</item>\n        <item>https://github.com/dooboolab/react-native-iap</item>\n        <item>https://github.com/Snapp-FidMe/react-native-image-base64</item>\n        <item>https://github.com/ivpusic/react-native-image-crop-picker</item>\n        <item>https://github.com/mockingbot/react-native-immersive</item>\n        <item>https://github.com/corbt/react-native-keep-awake</item>\n        <item>https://github.com/oblador/react-native-keychain</item>\n        <item>https://github.com/react-native-community/react-native-linear-gradient</item>\n        <item>https://github.com/tradle/react-native-local-auth</item>\n        <item>https://github.com/zoontek/react-native-localize</item>\n        <item>https://github.com/chirag04/react-native-mail</item>\n        <item>https://github.com/ammarahm-ed/react-native-mmkv-storage</item>\n        <item>https://github.com/tanguyantoine/react-native-music-control</item>\n        <item>https://github.com/whitedogg13/react-native-nfc-manager</item>\n        <item>https://github.com/brentvatne/react-native-overlay</item>\n        <item>https://github.com/alwx/react-native-photo-view</item>\n        <item>https://github.com/godness84/react-native-recyclerview-list</item>\n        <item>https://github.com/amitaymolko/react-native-rsa-native</item>\n        <item>https://github.com/th3rdwave/react-native-safe-area-context</item>\n        <item>https://github.com/ammarahm-ed/react-native-scoped-storage</item>\n        <item>https://github.com/kmagiera/react-native-screens</item>\n        <item>https://github.com/rh389/react-native-securerandom</item>\n        <item>https://github.com/rh389/react-native-securerandom</item>\n        <item>https://github.com/Astrocoders/react-native-selectable-text</item>\n        <item>https://github.com/react-native-share/react-native-share</item>\n        <item>https://github.com/react-native-component/react-native-smart-splash-screen</item>\n        <item>https://github.com/lyubo/react-native-sodium</item>\n        <item>https://github.com/zmxv/react-native-sound</item>\n        <item>https://github.com/johnsonsu/react-native-sound-player</item>\n        <item>https://github.com/maxs15/react-native-spinkit</item>\n        <item>https://github.com/crazycodeboy/react-native-splash-screen</item>\n        <item>https://github.com/react-native-community/react-native-svg</item>\n        <item>https://www.npmjs.com/package/react-native-text-input-reset</item>\n        <item>https://www.npmjs.com/package/\\@unimodules/react-native-adapter</item>\n        <item>https://github.com/APSL/react-native-version-number</item>\n        <item>https://github.com/react-native-community/react-native-video</item>\n        <item>https://github.com/react-native-community/react-native-video</item>\n        <item>https://github.com/react-native-webrtc/react-native-webrtc</item>\n        <item>https://github.com/inProgress-team/react-native-youtube</item>\n        <item>https://github.com/bedatadriven/renjin</item>\n        <item>https://github.com/requery/requery</item>\n        <item>https://github.com/SpartanJ/restafari</item>\n        <item>https://square.github.io/retrofit/</item>\n        <item>https://github.com/dmfs/rfc5545-datetime</item>\n        <item>https://github.com/pedroSG94/rtmp-rtsp-stream-client-java</item>\n        <item>https://github.com/pedroSG94/rtmp-rtsp-stream-client-java</item>\n        <item>https://github.com/pedroSG94/rtmp-rtsp-stream-client-java</item>\n        <item>https://github.com/pedroSG94/rtmp-rtsp-stream-client-java</item>\n        <item>https://github.com/pedroSG94/rtmp-rtsp-stream-client-java</item>\n        <item>https://github.com/rh-id/rx-utils</item>\n        <item>https://github.com/littlerobots/rxlint</item>\n        <item>https://github.com/sunilpaulmathew/sCommon</item>\n        <item>https://github.com/jesualex/sTooltip</item>\n        <item>https://github.com/sanukin39</item>\n        <item>https://github.com/thegrizzlylabs/sardine-android</item>\n        <item>https://github.com/scalapb/sbt-scalapb</item>\n        <item>https://github.com/lightbend/scala-logging</item>\n        <item>https://github.com/scodec/scodec-bits</item>\n        <item>https://github.com/ScorexFoundation/scorex-util</item>\n        <item>https://github.com/transferwise/sequence-layout</item>\n        <item>https://github.com/romus/sha</item>\n        <item>https://github.com/romus/sha</item>\n        <item>https://github.com/milessabin/shapeless</item>\n        <item>https://github.com/fluttercommunity/plus_plugins/tree/main/packages/share_plus/share_plus</item>\n        <item>https://github.com/flutter/plugins/tree/master/packages/shared_preferences</item>\n        <item>https://github.com/AsamK/signal-cli</item>\n        <item>https://github.com/WhisperSystems/libsignal-service-java</item>\n        <item>https://github.com/novoda/simple-chrome-custom-tabs</item>\n        <item>https://github.com/IrineSistiana/simple-tls</item>\n        <item>https://github.com/sonatype/sisu-build-api</item>\n        <item>https://github.com/nomis/slf4j-android</item>\n        <item>https://github.com/PSDev/slf4j-android-logger</item>\n        <item>https://github.com/arcao/slf4j-timber</item>\n        <item>https://github.com/JesusFreke/smali</item>\n        <item>https://github.com/JesusFreke/smali</item>\n        <item>https://github.com/JesusFreke/smali</item>\n        <item>https://github.com/JesusFreke/smali</item>\n        <item>https://github.com/xerial/snappy-java</item>\n        <item>https://github.com/waywardgeek/sonic-ndk</item>\n        <item>https://github.com/Rosemoe/sora-editor</item>\n        <item>https://github.com/aidansteele/sphlib</item>\n        <item>https://github.com/tekartik/sqflite</item>\n        <item>https://github.com/simolus3/sqlite-native-libraries</item>\n        <item>https://github.com/simolus3/sqlite3.dart</item>\n        <item>https://github.com/hierynomus/sshj</item>\n        <item>https://github.com/Soneso/stellar-java-mnemonic</item>\n        <item>https://github.com/timehop/sticky-headers-recyclerview</item>\n        <item>https://github.com/mvberg/stock-chart</item>\n        <item>https://github.com/hampelratte/svdrp4j</item>\n        <item>https://github.com/BigBadaboom/androidsvg</item>\n        <item>https://github.com/pwittchen/swipe</item>\n        <item>https://github.com/pwittchen/swipe</item>\n        <item>https://github.com/hudomju/android-swipe-to-dismiss-undo</item>\n        <item>https://github.com/Tans5/tAdapter</item>\n        <item>https://www.tabtale.com/</item>\n        <item>https://github.com/aaschmid/taskwarrior-java-client</item>\n        <item>https://github.com/mozilla-mobile/telemetry-android</item>\n        <item>https://github.com/UweTrottmann/thetvdb-java</item>\n        <item>https://github.com/square/android-times-square</item>\n        <item>https://github.com/tinylog-org/tinylog</item>\n        <item>https://github.com/UweTrottmann/tmdb-java</item>\n        <item>https://github.com/mwanji/toml4j</item>\n        <item>https://github.com/react-native-community/toolbar-android</item>\n        <item>https://github.com/MuntashirAkon/toybox</item>\n        <item>https://github.com/ligi/tracedroid</item>\n        <item>https://github.com/UweTrottmann/trakt-java</item>\n        <item>https://github.com/Polidea/tree-view-list-android</item>\n        <item>https://github.com/twitter/twitter-text</item>\n        <item>https://github.com/Yalantis/uCrop</item>\n        <item>https://www.unbescape.org/</item>\n        <item>https://github.com/javadev/underscore-java</item>\n        <item>https://github.com/raisercostin/upnplibmobile</item>\n        <item>https://github.com/fge/uri-template</item>\n        <item>https://github.com/flutter/plugins/tree/master/packages/url_launcher</item>\n        <item>https://github.com/mik3y/usb-serial-for-android</item>\n        <item>https://github.com/umjammer/vavi-sound/tree/master/src/main/java/vavi/sound</item>\n        <item>https://github.com/umjammer/vavi-sound/tree/master/src/main/java/vavi/sound</item>\n        <item>https://github.com/bitfireAT/vcard4android</item>\n        <item>https://github.com/wnafee/vector-compat</item>\n        <item>https://pub.dev/packages/video_player</item>\n        <item>https://github.com/mangstadt/vinnie</item>\n        <item>https://github.com/butterproject/vlc-android-sdk</item>\n        <item>https://github.com/TrustWallet/wallet-connect-kotlin</item>\n        <item>https://github.com/aarajput/wc_flutter_share/</item>\n        <item>https://github.com/pristineio/webrtc-android</item>\n        <item>https://github.com/diogobernardino/WilliamChart</item>\n        <item>https://github.com/diogobernardino/WilliamChart</item>\n        <item>https://github.com/ViliusSutkus89/wvWare-Android</item>\n        <item>https://github.com/horizontalsystems/xrates-kit-android</item>\n        <item>https://github.com/yukuku/yuku-android-util</item>\n        <item>https://github.com/yukuku/yuku-android-util</item>\n        <item>https://github.com/yukuku/yuku-android-util</item>\n        <item>https://github.com/yukuku/yuku-android-util</item>\n        <item>https://github.com/yukuku/yuku-android-util</item>\n        <item>https://github.com/bertsir/zBarLibary</item>\n        <item>https://github.com/dimagi/zebra-print-android</item>\n        <item>https://github.com/jereksel/zip-signer</item>\n        <item>https://github.com/nulab/zxcvbn4j</item>\n        <item>https://arrow-kt.io/</item>\n        <item>https://arrow-kt.io/</item>\n    </array>\n</resources>"
  },
  {
    "path": "app/src/main/res/values/native_libs.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<resources>\n    <array name=\"lib_native_signatures\">\n        <item>libbugrpt\\\\.so</item>\n        <item>libjiagu(_a64)\\?\\\\.so|libjiagu(_x64|_x86)\\?\\\\.so|libX86Bridge\\\\.so</item>\n        <item>lib7-Zip-JBinding\\\\.so</item>\n        <item>libapssdk\\\\.so|libAMapSDK_NAVI_.*\\\\.so</item>\n        <item>libhuawei_arengine(_impl|_jni|_ndk)\\?\\\\.so</item>\n        <item>libarcore_sdk_jni\\\\.so</item>\n        <item>libAVPro(Local|Video2Native)\\?\\\\.so|libAudio360(-JNI)\\?\\\\.so</item>\n        <item>libadcolony\\\\.so</item>\n        <item>libagoraSdkCWrapper\\\\.so|libagora-(rtc-sdk|rtc-sdk-jni|core|ffmpeg|soundtouch)\\?\\\\.so|libagora_(ai_denoise|ci|dav1d|fd|jnd|segmentation|super_resolution|video_process)\\?_extension\\\\.so|libagora_(fdkaac|mpg123)\\?\\\\.so</item>\n        <item>libsgavmp\\\\.so|libsgmain\\\\.so|libsgsecuritybody\\\\.so|libsgsgmiddletier\\\\.so|libsgmainso-.*\\\\.so|libsgmiscso-.*\\\\.so|libsgmiddletierso-.*\\\\.so|libsgnocaptchaso-.*\\\\.so|libsgmiddletier\\\\.so|libsgmisc\\\\.so|libsgnocaptcha\\\\.so|libsgsecuritybodyso-.*\\\\.so|libAPSE_.*\\\\.so|libsgavmpso-.*\\\\.so</item>\n        <item>libapssdk\\\\.so|libAMapSDK_NAVI_.*\\\\.so</item>\n        <item>libandfix(_x86)\\?\\\\.so</item>\n        <item>libluajava\\\\.so</item>\n        <item>libchrome_android_linker\\\\.so</item>\n        <item>libCGE(Ext)\\?\\\\.so</item>\n        <item>libtiff\\\\.so</item>\n        <item>libapng-drawable\\\\.so</item>\n        <item>libartemis\\\\.so</item>\n        <item>libbass(_aac|_fx|_ssl)\\?\\\\.so|libbassopus\\\\.so</item>\n        <item>libcocklogic-.*\\\\.so</item>\n        <item>libindoor\\\\.so|liblocSDK.*[0-9](a|b)\\?\\\\.so|libBaiduMapSDK(_base|_map)\\?_.*\\\\.so</item>\n        <item>libbdpush_.*\\\\.so</item>\n        <item>libDexHelper(-x86)\\?\\\\.so|libSecShell(-x86)\\?\\\\.so|libdexjni\\\\.so|libsecexe\\\\.so</item>\n        <item>libbmob\\\\.so</item>\n        <item>libbmob\\\\.so</item>\n        <item>libboost(_filesystem|_system)\\?\\\\.so</item>\n        <item>libboost_multidex\\\\.so</item>\n        <item>libBugly(-rqd|-ext)\\?\\\\.so</item>\n        <item>libbugsnag-(ndk|plugin-android-anr|root-detection|unity)\\?\\\\.so</item>\n        <item>libBurstLinker\\\\.so</item>\n        <item>libc\\\\+\\\\+_shared\\\\.so|libgnustl_shared\\\\.so|libCXXCommonKit\\\\.so</item>\n        <item>libcpuinfo\\\\.so</item>\n        <item>libcardboard_api\\\\.so|libcardboard_api_only_gles2\\\\.so|libcardboard_sdk_jni\\\\.so|libcardboard_unity_jni\\\\.so</item>\n        <item>chaquopy\\\\.so|libcrypto_chaquopy\\\\.so|libssl_chaquopy\\\\.so|libchaquopy_java\\\\.so|chaquopy_android\\\\.so|libsqlite3_chaquopy\\\\.so</item>\n        <item>libchilkat\\\\.so</item>\n        <item>libclash\\\\.so</item>\n        <item>libcomScore\\\\.so</item>\n        <item>libcomScore\\\\.so</item>\n        <item>libconscrypt_jni\\\\.so</item>\n        <item>libcrashlytics(-common|-handler|-trampoline|-envelope)\\?\\\\.so|libFirebaseCppCrashlytics\\\\.so|libunwind-crashlytics\\\\.so</item>\n        <item>libcri_ware_unity\\\\.so|libcri_mana_vpx\\\\.so|libcriafx_roll\\\\.so</item>\n        <item>libcronet.*\\\\.so</item>\n        <item>libndkbitmap\\\\.so</item>\n        <item>libBaiduSpeechSDK\\\\.so|libImgRecognition\\\\.so|libbdEASRAndroid\\\\.so|libbdSpilWakeup\\\\.so|libvad\\\\.dnn\\\\.so</item>\n        <item>libduktape\\\\.so</item>\n        <item>libhyphenate\\\\.so</item>\n        <item>libeasymobile\\\\.so</item>\n        <item>libepic\\\\.so</item>\n        <item>libEOSSDK\\\\.so</item>\n        <item>libav(codec|device|filter|format|util)+\\\\.so|libsw(resample|scale)+\\\\.so|libffmpeg\\\\.so|libffmpeg-android\\\\.so|lib\\\\.\\\\.ffmpeg\\\\.\\\\.so</item>\n        <item>libffmpegkit(_abidetect)\\?\\\\.so</item>\n        <item>libfmod\\\\.so</item>\n        <item>libfilament(-utils)\\?-jni\\\\.so|libgltfio-jni\\\\.so</item>\n        <item>libFirebaseCppMessaging\\\\.so|libFirebaseCppApp-.*\\\\.so|libFirebaseCppRemoteConfig\\\\.so|libFirebaseCppDynamicLinks\\\\.so</item>\n        <item>libapp\\\\.so|libflutter\\\\.so</item>\n        <item>libframesequence\\\\.so</item>\n        <item>libfreetype\\\\.so</item>\n        <item>libbitmaps\\\\.so|libgifimage\\\\.so|libimagepipeline\\\\.so|libmemchunk\\\\.so|libnative-(filters|imagetranscoder|file-access)\\\\.so|libstatic-webp\\\\.so|libwebp(image)\\?\\\\.so</item>\n        <item>libgcanvas(_view)\\?\\\\.so</item>\n        <item>libgpuimage-library\\\\.so</item>\n        <item>libgetuiext3\\\\.so</item>\n        <item>libglean_ffi\\\\.so</item>\n        <item>libglide-webp\\\\.so</item>\n        <item>libgojni\\\\.so</item>\n        <item>libFirebaseCppAnalytics\\\\.so</item>\n        <item>libcardboard_xr_unity\\\\.so|libCardboardXrProvider\\\\.so</item>\n        <item>libgpg\\\\.so</item>\n        <item>libgvr(_audio)\\?\\\\.so|libpanorenderer\\\\.so|libpano_video_renderer\\\\.so</item>\n        <item>libhidapi\\\\.so</item>\n        <item>libhsp3dish\\\\.so</item>\n        <item>libhardcoder\\\\.so</item>\n        <item>libhermes(-executor-.*|-inspector)\\?\\\\.so</item>\n        <item>libflexbox\\\\.so|libhippybridge\\\\.so</item>\n        <item>libed25519\\\\.so|libhpplayae\\\\.so</item>\n        <item>libijkffmpeg\\\\.so|libijkplayer\\\\.so|libijksdl\\\\.so</item>\n        <item>libstub\\\\.so|libcompatible\\\\.so|libcompatible_x86\\\\.so|libengine-hlp\\\\.so|libengine\\\\.so</item>\n        <item>libizuko\\\\.so</item>\n        <item>libjcore.*\\\\.so</item>\n        <item>libjuce_jni\\\\.so</item>\n        <item>libjnidispatch\\\\.so</item>\n        <item>libkoom-java\\\\.so|libkwai-linker\\\\.so</item>\n        <item>libkraken_jsc\\\\.so</item>\n        <item>libmp3lame\\\\.so</item>\n        <item>libleptonica\\\\.so</item>\n        <item>libcurl\\\\.so</item>\n        <item>libraw\\\\.so</item>\n        <item>libmla\\\\.so|libvlc\\\\.so|libvlcjni\\\\.so</item>\n        <item>libavresample\\\\.so</item>\n        <item>libLive2DCubismCore\\\\.so</item>\n        <item>liblog4cpp\\\\.so</item>\n        <item>liblspd\\\\.so</item>\n        <item>liblua\\\\.so</item>\n        <item>libMMANDKSignature\\\\.so</item>\n        <item>libmmkv\\\\.so</item>\n        <item>libMNN(_CL|_Express)\\?\\\\.so|libmnn(kitcore|pybridge|face)+\\\\.so</item>\n        <item>lib39285EFA\\\\.so|libA3AEECD8\\\\.so|libsecsdk\\\\.so|libmsaoaid(auth|sec)\\?\\\\.so</item>\n        <item>libmapbox-gl\\\\.so</item>\n        <item>libmarsxlog\\\\.so</item>\n        <item>libmediainfo\\\\.so</item>\n        <item>libmegazord\\\\.so</item>\n        <item>libwtecdh\\\\.so</item>\n        <item>libmobileffmpeg(_abidetect)\\?\\\\.so</item>\n        <item>libnspr4\\\\.so|libplc4\\\\.so|libplds4\\\\.so</item>\n        <item>libbugrpt\\\\.so</item>\n        <item>libobjectbox(-jni)\\?\\\\.so</item>\n        <item>libolm\\\\.so</item>\n        <item>libopencc\\\\.so</item>\n        <item>libopencv_core\\\\.so|libopencv_imgproc\\\\.so|libopencv_java3\\\\.so|libopencv_java4\\\\.so|libopencv_highgui\\\\.so</item>\n        <item>libcrypto\\\\.so|libopenssl\\\\.so|libssl.*\\\\.so</item>\n        <item>libopenvpn\\\\.so|libopvpnutil\\\\.so|libovpnexec\\\\.so|libjbcrypto\\\\.so</item>\n        <item>libopus(JNI)\\?\\\\.so|libogg\\\\.so|libogg_opus_encoder(_translate)\\?\\\\.so|libopus(V2JNI|file|vadjava)+\\\\.so</item>\n        <item>libQPlayer\\\\.so</item>\n        <item>libbuffer_pg\\\\.so|libfile_lock_pg\\\\.so|libmetasec_ml\\\\.so|libnms\\\\.so|libtobEmbedEncrypt\\\\.so|libpangleflipped\\\\.so</item>\n        <item>libtpnsSecurity\\\\.so|libxguardian\\\\.so</item>\n        <item>libpingpp\\\\.so</item>\n        <item>libQt[1-9].*\\\\.so|libplugins_.*\\\\.so|libqml_Qt(3D)\\?.*\\\\.so</item>\n        <item>libquickjs\\\\.so</item>\n        <item>librapidfuzz\\\\.so</item>\n        <item>librclone\\\\.so</item>\n        <item>libJavaScriptCore\\\\.so|libfolly_(futures|json)\\?\\\\.so|libglog_init\\\\.so|libjsc(executor)\\?\\\\.so|libjsinspector\\\\.so|libjsijniprofiler\\\\.so|libreactnative(blob|jni|jnifb|utilsjni)\\?\\\\.so|libfb(jni)\\?\\\\.so|libreact_(codegen_reactandroidspec|codegen_rncore|nativemodule_core|debug|utils)\\?\\\\.so|libreactperfloggerjni\\\\.so|libreact_render_.*\\\\.so|libreactconfig\\\\.so|librrc_(image|modal|progressbar|root|scrollview|slider|switch|text|textinput|unimplementedview|view)\\?\\\\.so</item>\n        <item>libALBiometricsJni\\\\.so</item>\n        <item>librealm-jni\\\\.so</item>\n        <item>librenpython\\\\.so</item>\n        <item>libRSSupport\\\\.so|librsjni(_androidx)\\?\\\\.so|librs\\\\.(analyze|rotate)\\?\\\\.so</item>\n        <item>librime(_jni)\\?\\\\.so</item>\n        <item>libRongIMLib\\\\.so</item>\n        <item>libtool-checker\\\\.so</item>\n        <item>libspake2\\\\.so</item>\n        <item>libsqlcipher\\\\.so|libstlport_shared\\\\.so|libe_sqlcipher\\\\.so</item>\n        <item>libsqlite\\\\.so|libsqlite3\\\\.so|libsqlite3x\\\\.so|libsqliteX\\\\.so</item>\n        <item>libst_mobile\\\\.so|libstmobile_jni\\\\.so|libyuki-(camera-effect|content|effect|filter)\\?\\\\.so</item>\n        <item>libsentry(-android)\\?\\\\.so</item>\n        <item>libShanYCore\\\\.so</item>\n        <item>libsmsdk\\\\.so</item>\n        <item>libSmartBeatNdk\\\\.so</item>\n        <item>libsodium(-jni)\\?\\\\.so</item>\n        <item>libfire\\\\.so</item>\n        <item>libSpeex\\\\.so</item>\n        <item>libtdjni\\\\.so</item>\n        <item>libtmessages.*\\\\.so</item>\n        <item>libBeacon\\\\.so</item>\n        <item>libWXVoice\\\\.so</item>\n        <item>libsaturn\\\\.so</item>\n        <item>libhttpdns\\\\.so</item>\n        <item>libapm(art|crash|dalvik|ioFake)+\\\\.so</item>\n        <item>libliteavsdk\\\\.so|libtxffmpeg\\\\.so|libtxplayer\\\\.so|libtxsdl\\\\.so</item>\n        <item>libImSDK\\\\.so|libqalcodecwrapper\\\\.so|libqalmsfboot\\\\.so|libwtcrypto\\\\.so</item>\n        <item>libshell-super.*\\\\.so|libshella-.*\\\\.so</item>\n        <item>libtencentloc\\\\.so|libtxmapengine\\\\.so</item>\n        <item>libMtaNativeCrash\\\\.so|libmtanativecrash_v2\\\\.so</item>\n        <item>libtersafe2\\\\.so</item>\n        <item>libxgVipSecurity\\\\.so|libtpnsSecurity\\\\.so|libxguardian\\\\.so</item>\n        <item>libtraeimp-rtmp\\\\.so</item>\n        <item>libtensorflowlite(_gpu)\\?_jni\\\\.so|libtensorflow_jni\\\\.so</item>\n        <item>libtesseract\\\\.so</item>\n        <item>libDXRisk.*\\\\.so</item>\n        <item>lib[Tt]or\\\\.so</item>\n        <item>libtrojan-go\\\\.so</item>\n        <item>libtwilio_video_android_so\\\\.so</item>\n        <item>libCtaApiLib\\\\.so</item>\n        <item>libumeng-spy\\\\.so</item>\n        <item>libentryexpro\\\\.so|libuptsm(addon|addonmi|service)+\\\\.so</item>\n        <item>libil2cpp\\\\.so|libmain\\\\.so|libmono\\\\.so|libunity\\\\.so</item>\n        <item>lib_burst_generated\\\\.so</item>\n        <item>libUE4\\\\.so</item>\n        <item>libjsengine(-api|-loadso|-platform)\\?\\\\.so|libv8\\\\.cr\\\\.so|libv8_libbase\\\\.cr\\\\.so|libv8_libplatform\\\\.cr\\\\.so</item>\n        <item>libarcore_sdk_c\\\\.so</item>\n        <item>libvorbis\\\\.so</item>\n        <item>libwcdb\\\\.so</item>\n        <item>libjingle_peerconnection_so\\\\.so</item>\n        <item>libweexcore\\\\.so|libweexjsb\\\\.so|libweexjss\\\\.so|libweexjssr\\\\.so|libweexjst\\\\.so|libWeexEagle\\\\.so|libWTF\\\\.so</item>\n        <item>libutility\\\\.so|libweibosdkcore\\\\.so|libwind\\\\.so|libsharewind\\\\.so</item>\n        <item>libxa-internal-api\\\\.so|libmono-(native|btls-shared)\\?\\\\.so|libmonodroid(_bundle_app)\\?\\\\.so|libmonosgen-.*\\\\.so|libxamarin-app\\\\.so|libaot-.*\\\\.dll\\\\.so</item>\n        <item>libmibraindec\\\\.so|libmibrainjni\\\\.so|libmibrainsdk\\\\.so|libmibrainvad2\\\\.so</item>\n        <item>libconnectionbase\\\\.so|libmilinkconnection\\\\.so</item>\n        <item>libsdk_patcher_jni\\\\.so</item>\n        <item>libYandexSpeechKitJni.*\\\\.so</item>\n        <item>liblib_fb_fbjni\\\\.so|libyoga\\\\.so|libyouga\\\\.so</item>\n        <item>libyoume_voice_engine\\\\.so</item>\n        <item>libcrashsdk(2)\\?\\\\.so</item>\n        <item>libzbar(jni)\\?\\\\.so</item>\n        <item>libzstd-jni\\\\.so</item>\n        <item>libzstd-jni-.*\\\\.so</item>\n        <item>libpl_droidsonroids_gif\\\\.so</item>\n        <item>libcardioDecider\\\\.so|libcardioRecognizer(_tegra2)\\?\\\\.so</item>\n        <item>libcocos2dcpp\\\\.so</item>\n        <item>libjlibtorrent-.*\\\\.so</item>\n        <item>libgrpc_csharp_ext\\\\.so</item>\n        <item>libglog\\\\.so</item>\n        <item>libgocryptfs(_jni)\\?\\\\.so</item>\n        <item>libmsc\\\\.so</item>\n        <item>libiconv\\\\.so</item>\n        <item>libgdx(-box2d|-freetype)\\?\\\\.so</item>\n        <item>libSDL2(_ttf|_mixer|_image)\\?\\\\.so</item>\n        <item>libyuv(_to_rgb_jni|-decoder)\\?\\\\.so</item>\n        <item>libaria2c\\\\.so</item>\n        <item>libcharset\\\\.so</item>\n        <item>libchrome\\\\.so|libchrome_crashpad_handler\\\\.so|libchromium_android_linker\\\\.so</item>\n        <item>libffi\\\\.so</item>\n        <item>libnss3\\\\.so|libnssckbi\\\\.so|libsoftokn3\\\\.so|libfreebl3\\\\.so</item>\n        <item>libsecp256k1\\\\.so</item>\n        <item>libtorrent4j(-.*)\\?\\\\.so</item>\n        <item>libvpx(V2JNI|YTJNI)\\?\\\\.so</item>\n        <item>libxul\\\\.so</item>\n        <item>libpython.*\\\\.so</item>\n        <item>libstrongswan\\\\.so</item>\n        <item>libucrop\\\\.so</item>\n        <item>libJni_wgs2gcj\\\\.so</item>\n        <item>libxcrash(_dumper)\\?\\\\.so</item>\n        <item>libxhook_lib\\\\.so</item>\n        <item>libxlua\\\\.so</item>\n    </array>\n    <array name=\"lib_native_names\">\n        <item>163 Crash</item>\n        <item>360 Security</item>\n        <item>7-Zip-JBinding</item>\n        <item>AMAP SDK</item>\n        <item>AR Engine</item>\n        <item>ARCore</item>\n        <item>AVPro Video</item>\n        <item>AdColony</item>\n        <item>Agora</item>\n        <item>Alibaba security</item>\n        <item>Amap</item>\n        <item>AndFix</item>\n        <item>AndroLua</item>\n        <item>Android Crazy Linker</item>\n        <item>Android-GPUImage-Plus</item>\n        <item>Android-TiffBitmapFactory</item>\n        <item>ApngDrawable</item>\n        <item>Artemis Engine</item>\n        <item>BASS audio library</item>\n        <item>Baichuan SDK</item>\n        <item>Baidu LBS</item>\n        <item>Baidu Push</item>\n        <item>Bangcle</item>\n        <item>Bmob</item>\n        <item>Bmob Android SDK</item>\n        <item>Boost</item>\n        <item>BoostMultiDex</item>\n        <item>Bugly</item>\n        <item>Bugsnag</item>\n        <item>BurstLinker</item>\n        <item>C++ Shared Library</item>\n        <item>CPU INFOrmation library</item>\n        <item>Cardboard SDK</item>\n        <item>Chaquopy</item>\n        <item>Chilkat</item>\n        <item>Clash Core</item>\n        <item>ComScore</item>\n        <item>Comscore Analytics</item>\n        <item>Conscrypt</item>\n        <item>Crashlytics</item>\n        <item>Criware</item>\n        <item>Cronet</item>\n        <item>DanmakuFlameMaster</item>\n        <item>DuMix</item>\n        <item>Duktape</item>\n        <item>Easemob IM</item>\n        <item>Easy Mobile</item>\n        <item>Epic</item>\n        <item>Epic Online Services SDK</item>\n        <item>FFmpeg</item>\n        <item>FFmpegKit</item>\n        <item>FMOD</item>\n        <item>Filament</item>\n        <item>Firebase Cloud Messaging</item>\n        <item>Flutter</item>\n        <item>FrameSequence</item>\n        <item>FreeType</item>\n        <item>Fresco</item>\n        <item>GCanvas</item>\n        <item>GPUImage</item>\n        <item>Getui</item>\n        <item>Glean</item>\n        <item>GlideWebpDecoder</item>\n        <item>Golang</item>\n        <item>Google Analytics</item>\n        <item>Google Cardboard XR Plugin for Unity</item>\n        <item>Google Play Games plugin for Unity</item>\n        <item>Google VR SDK</item>\n        <item>HIDAPI</item>\n        <item>HSP3Dish</item>\n        <item>HardCoder</item>\n        <item>Hermes JS Engine</item>\n        <item>Hippy</item>\n        <item>Hppplay SDK</item>\n        <item>IJKPlayer</item>\n        <item>INCA nProtect AppGuard</item>\n        <item>Izuko</item>\n        <item>JPush</item>\n        <item>JUCE</item>\n        <item>Java Native Access</item>\n        <item>KOOM</item>\n        <item>Kraken</item>\n        <item>LAME</item>\n        <item>Leptonica</item>\n        <item>LibCurl</item>\n        <item>LibRaw</item>\n        <item>LibVLC</item>\n        <item>Libavresample</item>\n        <item>Live2D Cubism SDK</item>\n        <item>Log for C++</item>\n        <item>Lspatch</item>\n        <item>Lua</item>\n        <item>MMA China SDK</item>\n        <item>MMKV</item>\n        <item>MNN</item>\n        <item>MSA SDK</item>\n        <item>Mapbox GL Native</item>\n        <item>Mars</item>\n        <item>MediaInfoLib</item>\n        <item>Megazord</item>\n        <item>Midas</item>\n        <item>MobileFFmpeg</item>\n        <item>NSPR</item>\n        <item>NetEase Cloud Capture</item>\n        <item>ObjectBox Java</item>\n        <item>Olm</item>\n        <item>OpenCC</item>\n        <item>OpenCV</item>\n        <item>OpenSSL</item>\n        <item>OpenVPN for Android</item>\n        <item>Opus</item>\n        <item>PLDroidPlayer</item>\n        <item>Pangle SDK</item>\n        <item>Pigeon Push</item>\n        <item>Ping++ SDK</item>\n        <item>Qt</item>\n        <item>QuickJS</item>\n        <item>RapidFuzz-Android</item>\n        <item>Rclone</item>\n        <item>React Native</item>\n        <item>Real person certification SDK</item>\n        <item>Realm</item>\n        <item>Ren\\'Py</item>\n        <item>RenderScript</item>\n        <item>Rime Core</item>\n        <item>RongCloud IM SDK</item>\n        <item>RootBeer</item>\n        <item>SPAKE2-Java</item>\n        <item>SQLCipher</item>\n        <item>SQLite</item>\n        <item>SenseME</item>\n        <item>Sentry</item>\n        <item>Shanyan SDK</item>\n        <item>Shumei SDK</item>\n        <item>SmartBeat</item>\n        <item>Sodium</item>\n        <item>Sofire</item>\n        <item>Speex</item>\n        <item>TDLib</item>\n        <item>Telegram APIs</item>\n        <item>Tencent Beacon</item>\n        <item>Tencent Cloud ASR</item>\n        <item>Tencent Cloud CSS SDK</item>\n        <item>Tencent Cloud HTTPDNS</item>\n        <item>Tencent Cloud QAPM</item>\n        <item>Tencent Cloud UGSV SDK</item>\n        <item>Tencent CloudIM SDK</item>\n        <item>Tencent Le Gu</item>\n        <item>Tencent Location SDK</item>\n        <item>Tencent MTA</item>\n        <item>Tencent MTP</item>\n        <item>Tencent TPNS</item>\n        <item>Tencent TRTC</item>\n        <item>TensorFlow Lite</item>\n        <item>Tesseract OCR</item>\n        <item>Top icon inductible verification SDK </item>\n        <item>Tor Android</item>\n        <item>Trojan-Go</item>\n        <item>Twilio Video API</item>\n        <item>URORA SDK</item>\n        <item>Umeng</item>\n        <item>UnionPay SDK</item>\n        <item>Unity</item>\n        <item>Unity Burst</item>\n        <item>Unreal Engine</item>\n        <item>V8 JavaScript engine</item>\n        <item>Virocore</item>\n        <item>Vorbis</item>\n        <item>WCDB</item>\n        <item>WebRTC</item>\n        <item>Weex</item>\n        <item>Weibo SDK</item>\n        <item>Xamarin</item>\n        <item>Xiaoai SDK</item>\n        <item>Xiaomi Game SDK</item>\n        <item>Xiaomi Update SDK</item>\n        <item>Yandex SpeechKit</item>\n        <item>Yoga</item>\n        <item>Youme</item>\n        <item>Yueying Crash SDK</item>\n        <item>ZBar</item>\n        <item>Zstandard</item>\n        <item>Zstd-jni</item>\n        <item>android-gif-drawable</item>\n        <item>card.io SDK for Android</item>\n        <item>cocos2d-cpp</item>\n        <item>frostwire-jlibtorrent</item>\n        <item>gRPC</item>\n        <item>glog</item>\n        <item>gocryptsfs</item>\n        <item>iFlytek SDK</item>\n        <item>iconv</item>\n        <item>libGDX</item>\n        <item>libSDL</item>\n        <item>libYUV</item>\n        <item>libaria2</item>\n        <item>libcharset</item>\n        <item>libchrome</item>\n        <item>libffi</item>\n        <item>libnss</item>\n        <item>libsecp256k1</item>\n        <item>libtorrent4j</item>\n        <item>libvpx</item>\n        <item>libxul</item>\n        <item>python-for-android</item>\n        <item>strongSwan</item>\n        <item>uCrop</item>\n        <item>wgs2gcj</item>\n        <item>xCrash</item>\n        <item>xHook</item>\n        <item>xLua</item>\n    </array>\n    <integer-array name=\"lib_native_is_tracker\">\n        <item>1</item>\n        <item>1</item>\n        <item>0</item>\n        <item>1</item>\n        <item>1</item>\n        <item>0</item>\n        <item>0</item>\n        <item>0</item>\n        <item>1</item>\n        <item>1</item>\n        <item>0</item>\n        <item>0</item>\n        <item>0</item>\n        <item>0</item>\n        <item>0</item>\n        <item>0</item>\n        <item>0</item>\n        <item>0</item>\n        <item>0</item>\n        <item>1</item>\n        <item>1</item>\n        <item>1</item>\n        <item>1</item>\n        <item>1</item>\n        <item>0</item>\n        <item>0</item>\n        <item>0</item>\n        <item>1</item>\n        <item>1</item>\n        <item>0</item>\n        <item>0</item>\n        <item>0</item>\n        <item>0</item>\n        <item>0</item>\n        <item>1</item>\n        <item>1</item>\n        <item>1</item>\n        <item>1</item>\n        <item>0</item>\n        <item>1</item>\n        <item>0</item>\n        <item>0</item>\n        <item>0</item>\n        <item>1</item>\n        <item>0</item>\n        <item>1</item>\n        <item>1</item>\n        <item>0</item>\n        <item>0</item>\n        <item>0</item>\n        <item>0</item>\n        <item>0</item>\n        <item>0</item>\n        <item>0</item>\n        <item>0</item>\n        <item>0</item>\n        <item>0</item>\n        <item>0</item>\n        <item>0</item>\n        <item>0</item>\n        <item>1</item>\n        <item>1</item>\n        <item>0</item>\n        <item>0</item>\n        <item>1</item>\n        <item>0</item>\n        <item>0</item>\n        <item>0</item>\n        <item>0</item>\n        <item>0</item>\n        <item>0</item>\n        <item>0</item>\n        <item>0</item>\n        <item>0</item>\n        <item>0</item>\n        <item>1</item>\n        <item>0</item>\n        <item>1</item>\n        <item>0</item>\n        <item>0</item>\n        <item>0</item>\n        <item>1</item>\n        <item>0</item>\n        <item>0</item>\n        <item>0</item>\n        <item>0</item>\n        <item>0</item>\n        <item>0</item>\n        <item>0</item>\n        <item>0</item>\n        <item>0</item>\n        <item>0</item>\n        <item>1</item>\n        <item>0</item>\n        <item>0</item>\n        <item>1</item>\n        <item>0</item>\n        <item>0</item>\n        <item>0</item>\n        <item>0</item>\n        <item>0</item>\n        <item>0</item>\n        <item>0</item>\n        <item>1</item>\n        <item>0</item>\n        <item>0</item>\n        <item>0</item>\n        <item>0</item>\n        <item>0</item>\n        <item>0</item>\n        <item>0</item>\n        <item>0</item>\n        <item>1</item>\n        <item>1</item>\n        <item>0</item>\n        <item>0</item>\n        <item>0</item>\n        <item>0</item>\n        <item>0</item>\n        <item>0</item>\n        <item>1</item>\n        <item>0</item>\n        <item>0</item>\n        <item>0</item>\n        <item>0</item>\n        <item>1</item>\n        <item>0</item>\n        <item>0</item>\n        <item>0</item>\n        <item>0</item>\n        <item>1</item>\n        <item>1</item>\n        <item>1</item>\n        <item>1</item>\n        <item>1</item>\n        <item>0</item>\n        <item>1</item>\n        <item>0</item>\n        <item>0</item>\n        <item>0</item>\n        <item>1</item>\n        <item>0</item>\n        <item>1</item>\n        <item>1</item>\n        <item>1</item>\n        <item>0</item>\n        <item>1</item>\n        <item>1</item>\n        <item>1</item>\n        <item>1</item>\n        <item>1</item>\n        <item>1</item>\n        <item>0</item>\n        <item>0</item>\n        <item>0</item>\n        <item>1</item>\n        <item>0</item>\n        <item>0</item>\n        <item>0</item>\n        <item>1</item>\n        <item>1</item>\n        <item>0</item>\n        <item>0</item>\n        <item>0</item>\n        <item>0</item>\n        <item>0</item>\n        <item>0</item>\n        <item>0</item>\n        <item>0</item>\n        <item>0</item>\n        <item>0</item>\n        <item>1</item>\n        <item>0</item>\n        <item>0</item>\n        <item>1</item>\n        <item>1</item>\n        <item>0</item>\n        <item>0</item>\n        <item>1</item>\n        <item>1</item>\n        <item>0</item>\n        <item>0</item>\n        <item>0</item>\n        <item>0</item>\n        <item>0</item>\n        <item>0</item>\n        <item>0</item>\n        <item>0</item>\n        <item>0</item>\n        <item>0</item>\n        <item>1</item>\n        <item>0</item>\n        <item>0</item>\n        <item>0</item>\n        <item>0</item>\n        <item>0</item>\n        <item>0</item>\n        <item>0</item>\n        <item>0</item>\n        <item>0</item>\n        <item>0</item>\n        <item>0</item>\n        <item>0</item>\n        <item>0</item>\n        <item>0</item>\n        <item>1</item>\n        <item>0</item>\n        <item>0</item>\n        <item>0</item>\n        <item>0</item>\n        <item>0</item>\n    </integer-array>\n    <array name=\"lib_native_website\">\n        <item>http://crash.163.com/index.do</item>\n        <item>https://jiagu.360.cn/</item>\n        <item>http://sevenzipjbind.sourceforge.net/</item>\n        <item>https://lbs.amap.com/api/android-sdk/summary/</item>\n        <item>https://developer.huawei.com/consumer/cn/doc/development/HMSCore-Guides/introduction-0000001050130900</item>\n        <item>https://developers.google.com/ar/discover/</item>\n        <item>https://renderheads.com/products/avpro-video/</item>\n        <item>http://adcolony.com/</item>\n        <item>https://www.agora.io/en/</item>\n        <item>https://jaq-doc.alibaba.com/docs/doc.htm\\?treeId=243&amp;articleId=106477&amp;docType=1</item>\n        <item>https://lbs.amap.com/api/android-location-sdk/locationsummary</item>\n        <item>https://github.com/alibaba/AndFix</item>\n        <item>https://github.com/mkottman/AndroLua/</item>\n        <item>https://chromium.googlesource.com/chromium/src.git/+/refs/heads/main/third_party/android_crazy_linker</item>\n        <item>https://github.com/wysaid/android-gpuimage-plus</item>\n        <item>https://github.com/Beyka/Android-TiffBitmapFactory</item>\n        <item>https://github.com/line/apng-drawable</item>\n        <item>http://www.ies-net.com/</item>\n        <item>https://www.un4seen.com/bass.html</item>\n        <item>https://open.alitrip.com/docs/doc.htm\\?treeId=29&amp;articleId=102362&amp;docType=1</item>\n        <item>https://lbsyun.baidu.com/</item>\n        <item>http://push.baidu.com/doc/android/api</item>\n        <item>https://www.bangcle.com/products/productindex/</item>\n        <item>http://doc.bmob.cn/</item>\n        <item>https://github.com/bmob/bmob-android-sdk</item>\n        <item>https://www.boost.org/</item>\n        <item>https://github.com/bytedance/BoostMultiDex</item>\n        <item>https://bugly.qq.com/</item>\n        <item>https://github.com/bugsnag/bugsnag-android</item>\n        <item>https://github.com/bilibili/BurstLinker</item>\n        <item>https://developer.android.com/ndk/guides/cpp-support/</item>\n        <item>https://github.com/pytorch/cpuinfo</item>\n        <item>https://developers.google.com/cardboard</item>\n        <item>https://chaquo.com/chaquopy/</item>\n        <item>https://www.chilkatsoft.com/</item>\n        <item>https://github.com/Dreamacro/clash</item>\n        <item>https://comscore.com/</item>\n        <item>http://www.comscore.com/</item>\n        <item>https://github.com/google/conscrypt</item>\n        <item>https://firebase.google.com/docs/crashlytics/</item>\n        <item>https://www.criware.com/en/</item>\n        <item>https://developer.android.com/guide/topics/connectivity/cronet/</item>\n        <item>https://github.com/bilibili/DanmakuFlameMaster/</item>\n        <item>https://github.com/baidu/ar-sdk/</item>\n        <item>https://search.maven.org/artifact/com.squareup.duktape/duktape-android</item>\n        <item>http://docs-im.easemob.com/im/android/sdk/import</item>\n        <item>https://www.easymobile.sglibgames.com/</item>\n        <item>https://github.com/tiann/epic/</item>\n        <item>https://dev.epicgames.com/docs/services/en-US/Platforms/Android/index.html</item>\n        <item>http://www.ffmpeg.org/libavcodec.html</item>\n        <item>https://github.com/tanersener/ffmpeg-kit</item>\n        <item>https://fmod.com/</item>\n        <item>https://github.com/google/filament</item>\n        <item>https://firebase.google.com/docs/cloud-messaging</item>\n        <item>https://flutter.dev/</item>\n        <item>https://android.googlesource.com/platform/frameworks/ex/</item>\n        <item>https://www.freetype.org/</item>\n        <item>https://github.com/facebook/fresco/</item>\n        <item>https://alibaba.github.io/GCanvas/</item>\n        <item>https://github.com/cats-oss/android-gpuimage</item>\n        <item>http://docs.getui.com/getui/start/product/</item>\n        <item>https://github.com/mozilla/glean</item>\n        <item>https://github.com/zjupure/GlideWebpDecoder</item>\n        <item>https://github.com/golang/mobile</item>\n        <item>https://firebase.google.com/docs/analytics/</item>\n        <item>https://github.com/googlevr/cardboard-xr-plugin</item>\n        <item>https://github.com/playgameservices/play-games-plugin-for-unity</item>\n        <item>https://github.com/googlevr/gvr-android-sdk</item>\n        <item>https://github.com/libusb/hidapi</item>\n        <item>https://www.onionsoft.net/hsp/v36en/doclib/hsp3dish_prog.htm</item>\n        <item>https://github.com/Tencent/Hardcoder</item>\n        <item>https://github.com/facebook/hermes</item>\n        <item>https://github.com/Tencent/Hippy/</item>\n        <item>https://cloud.hpplay.cn/</item>\n        <item>https://github.com/Bilibili/ijkplayer</item>\n        <item>https://appguard.nprotect.com/en/index.html</item>\n        <item>https://zhaobozhen.github.io/Anywhere-Docs</item>\n        <item>https://docs.jiguang.cn/jpush/guideline/intro/</item>\n        <item>https://juce.com</item>\n        <item>https://github.com/java-native-access/jna</item>\n        <item>https://github.com/KwaiAppTeam/KOOM</item>\n        <item>https://openkraken.com/</item>\n        <item>https://lame.sourceforge.io/</item>\n        <item>https://github.com/danbloomberg/leptonica</item>\n        <item>https://github.com/curl/curl</item>\n        <item>https://github.com/LibRaw/LibRaw</item>\n        <item>https://code.videolan.org/videolan/vlc-android</item>\n        <item>https://libav.org/documentation/doxygen/master/group__lavr.html</item>\n        <item>https://docs.live2d.com/cubism-sdk-manual/top/</item>\n        <item>https://sourceforge.net/projects/log4cpp/</item>\n        <item>https://github.com/LSPosed/LSPatch</item>\n        <item>https://www.lua.org/</item>\n        <item>http://www.mmachina.cn/assets/mma_doc/index.html</item>\n        <item>https://github.com/Tencent/MMKV</item>\n        <item>https://github.com/alibaba/MNN</item>\n        <item>http://msa-alliance.cn</item>\n        <item>https://github.com/mapbox/mapbox-gl-native</item>\n        <item>https://github.com/Tencent/Mars/</item>\n        <item>https://github.com/MediaArea/MediaInfoLib</item>\n        <item>https://github.com/mozilla/application-services/blob/main/docs/design/megazords.md</item>\n        <item>https://wiki.midas.qq.com/index/index/1/</item>\n        <item>https://github.com/tanersener/mobile-ffmpeg</item>\n        <item>https://www.linuxfromscratch.org/blfs/view/svn/general/nspr.html</item>\n        <item>https://crash.163.com/</item>\n        <item>https://github.com/objectbox/objectbox-java</item>\n        <item>https://github.com/Evans-Cai/matrix-org_olm</item>\n        <item>https://github.com/BYVoid/OpenCC</item>\n        <item>https://opencv.org/</item>\n        <item>https://github.com/openssl/openssl</item>\n        <item>https://github.com/schwabe/ics-openvpn</item>\n        <item>https://gitlab.xiph.org/xiph/opus</item>\n        <item>https://github.com/pili-engineering/PLDroidPlayer</item>\n        <item>https://partner.oceanengine.com/</item>\n        <item>https://xg.qq.com/docs/</item>\n        <item>https://github.com/PingPlusPlus/pingpp-android</item>\n        <item>https://www.qt.io</item>\n        <item>https://github.com/cashapp/quickjs-java</item>\n        <item>https://github.com/MuntashirAkon/rapidfuzz-android</item>\n        <item>https://github.com/rclone/rclone</item>\n        <item>https://reactnative.dev/</item>\n        <item>https://jaq-doc.alibaba.com/docs/doc.htm\\?spm=a313e.7629140.0.0.246751c3G9nvDl&amp;treeId=243&amp;articleId=105524&amp;docType=1</item>\n        <item>https://github.com/realm/realm-java</item>\n        <item>https://github.com/renpy/renpy</item>\n        <item>https://developer.android.com/guide/topics/renderscript/compute/</item>\n        <item>https://github.com/rime/librime</item>\n        <item>https://github.com/sealtalk/sealtalk-android</item>\n        <item>https://github.com/scottyab/rootbeer</item>\n        <item>https://github.com/MuntashirAkon/spake2-java</item>\n        <item>https://github.com/sqlcipher/sqlcipher/</item>\n        <item>https://developer.android.com/jetpack/androidx/releases/sqlite</item>\n        <item>https://www.sensetime.com/en/product-business\\?categoryId=33106&amp;gioNav=1</item>\n        <item>https://sentry.io/for/android/</item>\n        <item>https://shanyan.253.com/</item>\n        <item>https://help.ishumei.com/docs/tw/sdk/overview</item>\n        <item>https://smrtbeat.com/</item>\n        <item>https://github.com/jedisct1/libsodium</item>\n        <item>https://cloud.baidu.com/doc/AFD/s/Ijwvy4s7b</item>\n        <item>https://speex.org/</item>\n        <item>https://core.telegram.org/tdlib/docs/index.html</item>\n        <item>https://core.telegram.org/api</item>\n        <item>https://wiki.open.qq.com/wiki/</item>\n        <item>https://cloud.tencent.com/document/product/1093/52554</item>\n        <item>https://cloud.tencent.com/document/product/267/</item>\n        <item>https://github.com/tencentyun/httpdns-android-sdk</item>\n        <item>https://cloud.tencent.com/document/product/683</item>\n        <item>https://cloud.tencent.com/document/product/584/9453</item>\n        <item>https://cloud.tencent.com/product/im/getting-started/</item>\n        <item>https://cloud.tencent.com/document/product/283</item>\n        <item>https://lbs.qq.com/mobile/androidLocationSDK/androidGeoGuide/androidGeoOverview/</item>\n        <item>https://mta.qq.com/</item>\n        <item>https://cloud.tencent.com/document/product/654/30316</item>\n        <item>https://cloud.tencent.com/product/tpns</item>\n        <item>https://cloud.tencent.com/document/product/647/16788</item>\n        <item>https://www.tensorflow.org/lite</item>\n        <item>https://github.com/tesseract-ocr/tesseract</item>\n        <item>https://www.dingxiang-inc.com/docs/detail/captcha#doc-h3-41</item>\n        <item>https://github.com/guardianproject/tor-android</item>\n        <item>https://github.com/p4gefau1t/trojan-go</item>\n        <item>https://www.twilio.com/video-api</item>\n        <item>https://docs.jiguang.cn/jverification/client/android_guide/</item>\n        <item>http://www.umeng.com/</item>\n        <item>https://open.unionpay.com/</item>\n        <item>https://docs.unity3d.com/Manual/IL2CPP.html</item>\n        <item>https://docs.unity3d.com/Manual/com.unity.burst.html</item>\n        <item>https://docs.unrealengine.com/en-US/index.html</item>\n        <item>https://v8.dev/</item>\n        <item>https://developer.android.com/ndk/guides/cpp-support/</item>\n        <item>https://gitlab.xiph.org/xiph/vorbis</item>\n        <item>https://github.com/Tencent/wcdb</item>\n        <item>https://webrtc.org/</item>\n        <item>https://weex.apache.org/</item>\n        <item>https://github.com/sinaweibosdk/weibo_android_sdk</item>\n        <item>https://xamarin.com/</item>\n        <item>https://xiaoai.mi.com/documents/Home\\?type=/api/doc/render_markdown/Home/</item>\n        <item>https://dev.mi.com/console/app/gamecenter.html</item>\n        <item>https://dev.mi.com/console/doc/detail\\?pId=4/</item>\n        <item>https://cloud.yandex.com/en-ru/docs/speechkit/</item>\n        <item>https://github.com/facebook/yoga/</item>\n        <item>https://youme.im/en/</item>\n        <item>https://yueying-docs.effirst.com/</item>\n        <item>https://github.com/ZBar/ZBar</item>\n        <item>https://github.com/facebook/zstd</item>\n        <item>https://github.com/luben/zstd-jni</item>\n        <item>https://github.com/koral--/android-gif-drawable</item>\n        <item>https://github.com/card-io/card.io-Android-SDK</item>\n        <item>https://github.com/cocos2d-cpp/cocos2d-cpp</item>\n        <item>https://github.com/frostwire/frostwire-jlibtorrent</item>\n        <item>https://github.com/grpc/grpc</item>\n        <item>https://github.com/google/glog/</item>\n        <item>https://github.com/rfjakob/gocryptfs</item>\n        <item>https://www.xfyun.cn/doc/</item>\n        <item>https://www.gnu.org/software/libiconv/</item>\n        <item>https://github.com/libgdx/libgdx</item>\n        <item>https://www.libsdl.org</item>\n        <item>https://chromium.googlesource.com/libyuv/libyuv/</item>\n        <item>https://aria2.github.io/manual/en/html/libaria2.html</item>\n        <item>https://www.haible.de/bruno/packages-libcharset.html</item>\n        <item>https://chromium.googlesource.com/chromiumos/docs/+/master/packages/libchrome.md</item>\n        <item>https://github.com/libffi/libffi</item>\n        <item>https://developer.mozilla.org/en-US/docs/Mozilla/Projects/NSS</item>\n        <item>https://github.com/bitcoin-core/secp256k1</item>\n        <item>https://github.com/aldenml/libtorrent4j</item>\n        <item>https://github.com/webmproject/libvpx/</item>\n        <item>https://wiki.mozilla.org/XUL:Lib_XUL</item>\n        <item>https://github.com/renpy/python-for-android</item>\n        <item>https://github.com/strongswan/strongswan</item>\n        <item>https://github.com/Yalantis/uCrop</item>\n        <item></item>\n        <item>https://github.com/iqiyi/xCrash/</item>\n        <item>https://github.com/iqiyi/xHook</item>\n        <item>https://github.com/Tencent/xLua</item>\n    </array>\n</resources>"
  },
  {
    "path": "app/src/main/res/values/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<resources xmlns:tools=\"http://schemas.android.com/tools\" xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\">\n    <string name=\"_lang_tag\" translatable=\"false\">en</string>\n    <string name=\"uninstall\">Uninstall</string>\n    <string name=\"permissions\">Uses permissions</string>\n    <string name=\"require_no_permission\">No permission required</string>\n    <string name=\"activities\">Activities</string>\n    <string name=\"launch\">Launch</string>\n    <string name=\"refresh\">Refresh</string>\n    <string name=\"no_activities\">No activities</string>\n    <string name=\"receivers\">Receivers</string>\n    <string name=\"no_receivers\">No receivers</string>\n    <string name=\"providers\">Providers</string>\n    <string name=\"no_providers\">No providers</string>\n    <string name=\"launch_mode\">Launch mode</string>\n    <string name=\"task_affinity\">Task affinity</string>\n    <string name=\"sort_by_last_update\">Last update</string>\n    <string name=\"authority\">Authority</string>\n    <string name=\"service\">Services</string>\n    <string name=\"no_service\">No services</string>\n    <string name=\"orientation\">Orientation</string>\n    <string name=\"soft_input\">Soft input mode</string>\n    <string name=\"flags\">Flags</string>\n    <string name=\"grant_uri_permission\">Grant URI permissions</string>\n    <string name=\"path_permissions\">Path permissions</string>\n    <string name=\"read\">Read</string>\n    <string name=\"write\">Write</string>\n    <string name=\"patterns_allowed\">Patterns allowed</string>\n    <string name=\"declared_permission\">Permissions</string>\n    <string name=\"shared_libs\">Shared libs</string>\n    <string name=\"group\">Group</string>\n    <string name=\"uses_feature\">Uses features</string>\n    <string name=\"no_feature\">No features</string>\n    <string name=\"sort_by_shared_user_id\">Shared user ID</string>\n    <string name=\"shared_user_id\">Shared user ID</string>\n    <string name=\"sort_by_sha\">Signature</string>\n    <string name=\"signatures\">Signatures</string>\n    <string name=\"app_signing_signatures\">Signatures</string>\n    <string name=\"app_signing_no_signatures\">No valid signatures</string>\n    <string name=\"configurations\">Configurations</string>\n    <string name=\"no_configurations\">No configurations</string>\n    <string name=\"input_features\">Input features</string>\n    <string name=\"manifest\">Manifest</string>\n    <string name=\"error\">Error</string>\n    <string name=\"loading\">Loading…</string>\n    <string name=\"sort_by_app_label\">App label</string>\n    <string name=\"sort_by_package_name\">Package name</string>\n    <string name=\"sort_by_domain\">User apps first</string>\n    <string name=\"sort_by_target_sdk\">Target SDK</string>\n    <string name=\"sdk\" translatable=\"false\">SDK</string>\n    <string name=\"data_received\">Data received</string>\n    <string name=\"data_transmitted\">Data transmitted</string>\n    <string name=\"data_usage_msg\">Data usage</string>\n    <string name=\"about\">About</string>\n    <string name=\"data_size\">Data</string>\n    <string name=\"cache_size\">Cache</string>\n    <string name=\"obb_size\">Obb</string>\n    <string name=\"media_size\">Media</string>\n    <string name=\"app_not_installed\">App not installed</string>\n    <string name=\"system\">System</string>\n    <string name=\"user\">User</string>\n    <string name=\"sort\">Sort</string>\n    <string name=\"version_name_with_code\">Version <xliff:g id=\"version_name\" example=\"2.5.17\">%1$s</xliff:g> (<xliff:g id=\"version_code\" example=\"365\">%2$d</xliff:g>)</string>\n    <string name=\"app_info\">App info</string>\n    <string name=\"fdroid\" translatable=\"false\">F-Droid</string>\n    <string name=\"system_app\">System app</string>\n    <string name=\"user_app\">User app</string>\n    <string name=\"paths_and_directories\">Paths &amp; directories</string>\n    <string name=\"source_dir\">Source directory</string>\n    <string name=\"data_dir\">Data directory</string>\n    <string name=\"sdk_min\">Min</string>\n    <string name=\"sdk_max\">Target</string>\n    <string name=\"sdk_flags\">Flags</string>\n    <string name=\"more_info\">More info</string>\n    <string name=\"date_installed\">Date installed</string>\n    <string name=\"date_updated\">Date updated</string>\n    <string name=\"installer_app\">Installer app</string>\n    <string name=\"user_id\">User ID</string>\n    <string name=\"main_activity\">Main activity</string>\n    <string name=\"empty_package_name\">Empty package name</string>\n    <string name=\"error_creating_shortcut\">Error creating shortcut</string>\n    <string name=\"error_verbose_pin_shortcut\">Current launcher does not support PinShortcut. Unable to create shortcut.</string>\n    <string name=\"starting_activity\">Starting activity: <xliff:g id=\"activity_name\" example=\".main.MainActivity\">%1$s</xliff:g></string>\n    <string name=\"create_shortcut\">Create shortcut</string>\n    <string name=\"shortcut_name\">Shortcut name</string>\n    <string name=\"package_name\">Package name</string>\n    <string name=\"class_name\">Class name</string>\n    <string name=\"icon_picker\">Icon picker</string>\n    <string name=\"license\">License</string>\n    <string name=\"license_message\" translatable=\"false\"><a href=\"https://www.gnu.org/licenses/gpl-3.0.html\">GNU General\n        Public License v3.0</a></string>\n    <string name=\"copyright_message\" translatable=\"false\">© 2020–2025 <a href=\"https://github.com/MuntashirAkon\">Muntashir Al-Islam</a></string>\n    <string name=\"third_party\">Third-party libraries and icons</string>\n    <string name=\"third_party_message\" translatable=\"false\">-\n        <a href=\"https://github.com/zhanghai/AndroidFastScroll\">AndroidFastScroll</a> (Apache 2.0)\n        \\n- <a href=\"https://github.com/LSPosed/AndroidHiddenApiBypass\">AndroidHiddenApiBypass</a> (Apache 2.0)\n        \\n- <a href=\"https://github.com/MuntashirAkon/apk-parser\">APK-parser</a> (BSD 2-Clause)\n        \\n- <a href=\"https://github.com/MuntashirAkon/apksig-android\">apksig for android</a> (Apache 2.0)\n        \\n- <a href=\"https://github.com/REAndroid/ARSCLib\">ARSCLib</a> (Apache 2.0)\n        \\n- <a href=\"https://github.com/bcgit/bc-java\">Bouncy Castle</a> (MIT)\n        \\n- <a href=\"https://commons.apache.org/proper/commons-compress/\">Commons Compress</a> (Apache 2.0)\n        \\n- <a href=\"https://github.com/dkanada/frost\">Frost</a> Icons (GPLv3.0)\n        \\n- <a href=\"https://github.com/RikkaApps/HiddenApiRefinePlugin\">HiddenApiRefinePlugin</a> (MIT)\n        \\n- <a href=\"https://github.com/skylot/jadx\">JADX</a> (Apache 2.0)\n        \\n- <a href=\"https://github.com/MuntashirAkon/libadb-android\">LibADB</a> (Apache 2.0/GPLv3.0)\n        \\n- <a href=\"https://github.com/topjohnwu/libsu\">libsu</a> (Apache 2.0)\n        \\n- <a href=\"https://github.com/material-components/material-components-android\">Material Components</a> (Apache 2.0)\n        \\n- <a href=\"https://github.com/google/material-design-icons\">Material Design Icons</a> (Apache 2.0)\n        \\n- <a href=\"https://github.com/google/smali\">smali/baksmali</a> (BSD 3-Clause and Apache 2.0)\n        \\n- <a href=\"https://github.com/Rosemoe/sora-editor\">sora-editor</a> (LGPL-2.1)\n        \\n- <a href=\"https://github.com/MuntashirAkon/spake2-java\">SPAKE2 for Java</a> (GPLv3.0)\n        \\n- <a href=\"https://github.com/MuntashirAkon/sun-security-android\">sun.security for Android</a> (GPL-2.0 \\\"Classpath Exception\\\")\n        \\n- <a href=\"https://github.com/MuntashirAkon/unapkm-android\">UnAPKM Android</a> (Apache 2.0)</string>\n    <string name=\"credits\">Credits</string>\n    <string name=\"credits_message\">To the authors of\n        \\n- The Android Open Source Project\n        \\n- <a href=\"https://github.com/zhaobozhen/libraries\">Absinthe\\'s libraries</a>\n        \\n- <a href=\"https://github.com/butzist/ActivityLauncher\">Activity Launcher</a>\n        \\n- <a href=\"https://bitbucket.org/oF2pks/fdroid-applications-info\">Apps_packages Info</a>\n        \\n- <a href=\"https://github.com/zhaobao/AppsMonitor\">AppsMonitor</a>\n        \\n- <a href=\"https://github.com/8enet/AppOpsX\">AppOpsX</a>\n        \\n- <a href=\"https://github.com/gabrielemariotti/changeloglib\">ChangeLog Library</a>\n        \\n- <a href=\"https://bitbucket.org/oF2pks/fdroid-classyshark3xodus\">ClassySharkAndroid</a>\n        \\n- <a href=\"https://github.com/billthefarmer/editor\">Editor</a>\n        \\n- <a href=\"https://github.com/Raival-e/File-Explorer\">File Explorer</a>\n        \\n- <a href=\"https://github.com/nex3z/FlowLayout\">FlowLayout</a>\n        \\n- <a href=\"https://github.com/k3b/intent-intercept\">Intent Intercept</a>\n        \\n- <a href=\"https://github.com/YarikSOffice/lingver\">Lingver</a>\n        \\n- <a href=\"https://github.com/topjohnwu/Magisk\">Magisk</a>\n        \\n- <a href=\"https://github.com/zhanghai/MaterialFiles\">Material Files</a>\n        \\n- <a href=\"https://github.com/pluscubed/matlog\">MatLog</a>\n        \\n- <a href=\"https://github.com/matrix-org/matrix-android-sdk\">Matrix Android SDK</a>\n        \\n- <a href=\"https://github.com/jensstein/oandbackup\">OAndBackup</a>\n        \\n- <a href=\"https://github.com/open-keychain/open-keychain\">Open Keychain</a>\n        \\n- <a href=\"https://github.com/Aefyr/SAI\">SAI</a>\n        \\n- <a href=\"https://github.com/RikkaApps/Shizuku\">Shizuku</a>\n        \\n- <a href=\"https://github.com/eclipse/tm4e\">tm4e</a>\n        \\n- <a href=\"https://github.com/tuyafeng/Watt\">Watt</a></string>\n    <string name=\"word_wrap\">Toggle word wrap</string>\n    <string name=\"class_viewer\">Class viewer</string>\n    <string name=\"toggle_class_listing\">Toggle class listing</string>\n    <plurals name=\"tracker_and_classes\">\n        <item quantity=\"one\">1 tracker with <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g> class</item>\n        <item quantity=\"other\">1 tracker with <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g> classes</item>\n    </plurals>\n    <plurals name=\"two_trackers_and_classes\">\n        <item quantity=\"one\">2 trackers with <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g> classes</item>\n        <item quantity=\"other\">2 trackers with <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g> classes</item>\n    </plurals>\n    <plurals name=\"other_trackers_and_classes\">\n        <item quantity=\"one\"><xliff:g id=\"tracker_no\" example=\"8\">%1$d</xliff:g> trackers with <xliff:g id=\"class_no\" example=\"50\">%2$d</xliff:g> classes</item>\n        <item quantity=\"other\"><xliff:g id=\"tracker_no\" example=\"8\">%1$d</xliff:g> trackers with <xliff:g id=\"class_no\" example=\"50\">%2$d</xliff:g> classes</item>\n    </plurals>\n    <string name=\"found_trackers\">Found trackers:</string>\n    <string name=\"tracker_details\">Tracker details</string>\n    <string name=\"tracker_classes\">Tracker classes</string>\n    <string name=\"all_classes\">All classes</string>\n    <plurals name=\"main_list_date_days\">\n        <item quantity=\"one\"><xliff:g id=\"last_update_date\" example=\"20/10/2020\">%1$s</xliff:g> <xliff:g id=\"day_no\" example=\"5\">%2$d</xliff:g> day</item>\n        <item quantity=\"other\"><xliff:g id=\"last_update_date\" example=\"20/10/2020\">%1$s</xliff:g> <xliff:g id=\"day_no\" example=\"5\">%2$d</xliff:g> days</item>\n    </plurals>\n    <string name=\"no_shared_libs\">No shared libraries</string>\n    <string name=\"no_tracker_class\">No tracker classes</string>\n    <string name=\"app_usage\">App usage</string>\n    <string name=\"usage_weekly\">Weekly</string>\n    <string name=\"usage_today\">Today</string>\n    <string name=\"usage_7_days\">Last 7 days</string>\n    <plurals name=\"usage_months\">\n        <item quantity=\"one\">%1$d mo</item>\n        <item quantity=\"other\">%1$d mos</item>\n    </plurals>\n    <plurals name=\"usage_days\">\n        <item quantity=\"one\">%1$d day</item>\n        <item quantity=\"other\">%1$d days</item>\n    </plurals>\n    <plurals name=\"usage_hours\">\n        <item quantity=\"one\">%1$d hr</item>\n        <item quantity=\"other\">%1$d hrs</item>\n    </plurals>\n    <plurals name=\"usage_minutes\">\n        <item quantity=\"one\">%1$d min</item>\n        <item quantity=\"other\">%1$d mins</item>\n    </plurals>\n    <plurals name=\"usage_seconds\">\n        <item quantity=\"one\">%1$d sec</item>\n        <item quantity=\"other\">%1$d secs</item>\n    </plurals>\n    <string name=\"usage_less_than_a_minute\">Less than a minute</string>\n    <string name=\"go_back\">Go back</string>\n    <string name=\"go\">Go</string>\n    <string name=\"grant_usage_access\">Grant usage access</string>\n    <string name=\"grant_usage_acess_message\">Used to display app usage info.</string>\n    <string name=\"share_apk\">Share APK</string>\n    <string name=\"failed_to_extract_apk_file\">Could not extract APK file</string>\n    <string name=\"menu_remove_rules\">Remove rules</string>\n    <string name=\"menu_apply_rules\">Apply rules</string>\n    <string name=\"search\">Search</string>\n    <string name=\"dev_protected_data_dir\">Device-protected data directory</string>\n    <string name=\"native_library_dir\">Native JNI library directory</string>\n    <string name=\"process_name\">Process name</string>\n    <string name=\"no_code\">No code</string>\n    <string name=\"requested_large_heap\">Large heap</string>\n    <string name=\"updated_app\">Updated</string>\n    <string name=\"debuggable\">Debuggable</string>\n    <string name=\"test_only\">Test only</string>\n    <string name=\"shared_prefs\">Shared prefs</string>\n    <string name=\"databases\">Databases</string>\n    <string name=\"save\">Save</string>\n    <string name=\"discard\">Discard</string>\n    <string name=\"delete\">Delete</string>\n    <string name=\"deleted_successfully\">Deleted</string>\n    <string name=\"deletion_failed\">Deletion failed</string>\n    <string name=\"saved_successfully\">Saved</string>\n    <string name=\"saving_failed\">Saving failed, try again.</string>\n    <string name=\"string_value\">String value</string>\n    <string name=\"long_integer_value\">Long integer value</string>\n    <string name=\"integer_value\">Integer value</string>\n    <string name=\"decimal_value\">Decimal value</string>\n    <string name=\"boolean_value\">Boolean value</string>\n    <string name=\"key_name\">Key name</string>\n    <string name=\"select_type\">Select a type</string>\n    <string name=\"add_item\">Add item</string>\n    <string name=\"done\">Done</string>\n    <string name=\"type_boolean\">True/false</string>\n    <string name=\"type_float\">Decimal number</string>\n    <string name=\"type_int\">Integer</string>\n    <string name=\"type_long\">Long integer</string>\n    <string name=\"type_string\">Characters</string>\n    <string name=\"error_evaluating_input\">Could not evaluate input</string>\n    <string name=\"key_name_cannot_be_null\">Key name cannot be empty</string>\n    <string name=\"disabled_app\">Disabled</string>\n    <string name=\"no_usage_in_this_time_range\">No usage in this time range</string>\n    <string name=\"no_content\">No content</string>\n    <string name=\"view_in_settings\">View in Settings</string>\n    <string name=\"uninstall_app_message\">Do you want to uninstall this app?</string>\n    <string name=\"failed_to_uninstall\">Could not uninstall <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g>.</string>\n    <string name=\"failed_to_uninstall_app\">Uninstallation failed</string>\n    <string name=\"uninstalled_successfully\"><xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g> has been uninstalled.</string>\n    <string name=\"uninstall_system_app_message\">This is a system app. Are you sure want to uninstall this app?</string>\n    <string name=\"stopped\">Stopped</string>\n    <string name=\"disable\">Disable</string>\n    <string name=\"enable\">Enable</string>\n    <string name=\"force_stop\">Force-stop</string>\n    <string name=\"failed_to_stop\">Could not stop <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g>.</string>\n    <string name=\"storage_and_cache\">Storage and cache</string>\n    <string name=\"total_size\">Total</string>\n    <string name=\"app_size\">App</string>\n    <string name=\"app_ops\">App ops</string>\n    <string name=\"no_app_ops\">No app operations</string>\n    <string name=\"failed_to_enable_op\">Could not enable the requested app op</string>\n    <string name=\"failed_to_disable_op\">Could not disable the requested app op</string>\n    <string name=\"rules_not_applied\">Rules are not applied</string>\n    <string name=\"str_logo\">Logo</string>\n    <string name=\"pref_global_blocking_enabled\">Instant component blocking</string>\n    <string name=\"pref_global_blocking_enabled_msg\">Lets you block any component of any app without explicitly turning on blocking for the app.</string>\n    <string name=\"usage_access\">Usage access</string>\n    <string name=\"app_settings\">Settings</string>\n    <string name=\"usage_yesterday\">Yesterday</string>\n    <string name=\"exodus_link\">\\u03b5xodus link</string>\n    <string name=\"second_degree_tracker_note\">² prefix indicates that the trackers are in the <a href=\"https://etip.exodus-privacy.eu.org/\">ETIP stand-by list</a> i.e., whether they are actual trackers are still being investigated.</string>\n    <string name=\"sort_by_blocked_components\">Blocked first</string>\n    <string name=\"external_data_dir\">External data directory</string>\n    <string name=\"external_multiple_data_dir\">External data directory <xliff:g id=\"dir_no\" example=\"1\">%1$d</xliff:g></string>\n    <plurals name=\"no_of_times_opened\">\n        <item quantity=\"one\">%1$d time</item>\n        <item quantity=\"other\">%1$d times</item>\n    </plurals>\n    <string name=\"sort_by_last_used\">Last used</string>\n    <string name=\"sort_by_screen_time\">Screen time</string>\n    <string name=\"sort_by_times_opened\">Times opened</string>\n    <string name=\"sort_by_mobile_data\">Mobile data</string>\n    <string name=\"pref_import_export_blocking_rules\">Import/export blocking rules</string>\n    <string name=\"pref_import_export_blocking_rules_msg\">Import/export rules, import external rules from Watt or Blocker.</string>\n    <string name=\"pref_import_watt\">Import from Watt</string>\n    <string name=\"pref_import_blocker\">Import from Blocker</string>\n    <string name=\"the_import_was_successful\">Imported</string>\n    <string name=\"the_export_was_successful\">Exported</string>\n    <plurals name=\"failed_to_import_files\">\n        <item quantity=\"one\">Could not import %1$d file.</item>\n        <item quantity=\"other\">Could not import %1$d files.</item>\n    </plurals>\n    <string name=\"apk_updater\">APK Updater</string>\n    <string name=\"open_in_aurora_store\" translatable=\"false\">Store</string>\n    <string name=\"running_apps\">Running apps</string>\n    <string name=\"kill_process\">Kill</string>\n    <string name=\"disable_background_run\">Prevent background operation</string>\n    <string name=\"pid_and_ppid\">Process ID: %1$d, Parent process ID: %2$d</string>\n    <string name=\"memory_virtual_memory\">Memory: %1$s, Virtual memory: %2$s</string>\n    <string name=\"user_with_id\">User: <xliff:g id=\"user_id\" example=\"0\">%1$d</xliff:g></string>\n    <string name=\"user_and_uid\">User: <xliff:g id=\"user_name\" example=\"root\">%1$s</xliff:g> (<xliff:g id=\"user_id\" example=\"0\">%2$d</xliff:g>)</string>\n    <string name=\"clear_data\">Clear data</string>\n    <string name=\"backup_restore\">Backup/restore</string>\n    <string name=\"disable_background\">Prevent background operation</string>\n    <string name=\"export_blocking_rules\">Export blocking rules</string>\n    <plurals name=\"alert_failed_to_clear_data\">\n        <item quantity=\"one\">Could not clear data from %1$d app</item>\n        <item quantity=\"other\">Could not clear data from %1$d apps</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_uninstall\">\n        <item quantity=\"one\">Could not uninstall %1$d app</item>\n        <item quantity=\"other\">Could not uninstall %1$d apps</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_disable_background\">\n        <item quantity=\"one\">Could not prevent %1$d app from running in the background</item>\n        <item quantity=\"other\">Could not prevent %1$d apps from running in the background</item>\n    </plurals>\n    <string name=\"the_operation_was_successful\">Done</string>\n    <plurals name=\"alert_failed_to_force_stop\">\n        <item quantity=\"one\">Could not force-stop %1$d app</item>\n        <item quantity=\"other\">Could not force-stop %1$d apps</item>\n    </plurals>\n    <string name=\"toggle_kill_for_system_apps\">Toggle kill system apps</string>\n    <string name=\"permission_name\">Permission name</string>\n    <string name=\"mode\">Mode</string>\n    <string name=\"running\">Running</string>\n    <string name=\"duration\">Duration</string>\n    <string name=\"accept_time\">Accept time</string>\n    <string name=\"reject_time\">Reject time</string>\n    <string name=\"ago\">ago</string>\n    <string name=\"pref_import\">Import</string>\n    <string name=\"pref_export\">Export</string>\n    <string name=\"import_options\">Import options</string>\n    <string name=\"export_options\">Export options</string>\n    <string name=\"import_failed\">Import failed!</string>\n    <string name=\"export_failed\">Export failed!</string>\n    <string name=\"keyboard_type\">Keyboard type</string>\n    <string name=\"navigation\">Navigation</string>\n    <string name=\"touchscreen\">Touchscreen</string>\n    <string name=\"pref_export_msg\">Export blocking rules configured within App Manager to external storage.</string>\n    <string name=\"pref_import_msg\">Import previously exported blocking rules from App Manager.</string>\n    <string name=\"pref_import_watt_msg\">Import blocking rules from Watt, each file containing rules for a single named package as <tt>packagename.xml</tt> etc.</string>\n    <string name=\"pref_import_blocker_msg\">Import blocking rules from Blocker, each file containing rules for a single package.</string>\n    <string name=\"pref_app_theme\">App theme</string>\n    <string name=\"follow_system\">Follow system</string>\n    <string name=\"battery_mode\">Battery mode</string>\n    <string name=\"day\">Day</string>\n    <string name=\"night\">Night</string>\n    <string name=\"select_theme\">Theme</string>\n    <string name=\"apply\">Apply</string>\n    <string name=\"pref_about_msg\">App Manager version, license, credits, etc.</string>\n    <string name=\"version\">Version</string>\n    <string name=\"sort_by_wifi_data\">Wi-Fi data</string>\n    <string name=\"block_trackers\">Block trackers</string>\n    <string name=\"sort_by_component_name\">Component name</string>\n    <string name=\"reset_to_default\">Reset to default</string>\n    <string name=\"deny_dangerous_app_ops\">Deny dangerous app ops</string>\n    <string name=\"sort_by_app_ops_names\">App ops name</string>\n    <string name=\"sort_by_denied_app_ops\">Denied first</string>\n    <string name=\"sort_by_app_ops_values\">App ops value</string>\n    <string name=\"sort_by_permission_names\">Permission name</string>\n    <string name=\"sort_by_dangerous_permissions\">Dangerous first</string>\n    <string name=\"sort_by_denied_permissions\">Denied first</string>\n    <string name=\"deny_dangerous_permissions\">Deny dangerous permissions</string>\n    <string name=\"sort_by_tracker_components\">Trackers first</string>\n    <string name=\"unknown_op\">Unknown operation</string>\n    <plurals name=\"alert_failed_to_disable_trackers\">\n        <item quantity=\"one\">Could not disable trackers from %1$d app</item>\n        <item quantity=\"other\">Could not disable trackers from %1$d apps</item>\n    </plurals>\n    <string name=\"failed_to_grant_permission\">Could not grant permission</string>\n    <string name=\"failed_to_revoke_permission\">Could not revoke permission</string>\n    <string name=\"failed_to_reset_app_ops\">Could not reset app ops</string>\n    <string name=\"failed_to_deny_dangerous_perms\">Could not revoke all dangerous permissions</string>\n    <string name=\"failed_to_deny_dangerous_app_ops\">Could not revoke all dangerous app ops</string>\n    <string name=\"launch_app\">Launch</string>\n    <string name=\"never_ask\">Never ask</string>\n    <string name=\"one_click_ops\">1-click ops</string>\n    <string name=\"changelog\">Changelog</string>\n    <string name=\"external_apk_no_app_op\">External APK does not have any app operations</string>\n    <string name=\"manifest_viewer\">Manifest viewer</string>\n    <plurals name=\"no_of_trackers\">\n        <item quantity=\"one\">%1$d tracker</item>\n        <item quantity=\"other\">%1$d trackers</item>\n    </plurals>\n    <plurals name=\"no_of_components\">\n        <item quantity=\"one\">%1$d component</item>\n        <item quantity=\"other\">%1$d components</item>\n    </plurals>\n    <string name=\"install\">Install</string>\n    <string name=\"update\">Update</string>\n    <string name=\"source_code\">Source code</string>\n    <string name=\"source_code_links\" translatable=\"false\"><a href=\"https://github.com/MuntashirAkon/AppManager\">GitHub</a> •\n        <a href=\"https://codeberg.org/muntashir/AppManager\">Codeberg</a> •\n        <a href=\"https://gitlab.com/muntashir/AppManager\">GitLab</a> •\n        <a href=\"https://0xacab.org/muntashir/AppManager\">Riseup</a> •\n        <a href=\"https://git.sr.ht/~muntashir/AppManager\">sourcehut</a></string>\n    <string name=\"community\">Community</string>\n    <string name=\"community_links\"><a href=\"https://matrix.to/#/#appmanager:matrix.org\">Matrix</a> •\n        <a href=\"https://t.me/AppManagerChannel\">Telegram</a> •\n        <a href=\"https://x.com/AppManagerNews\">Twitter/X</a> •\n        <a href=\"https://floss.social/@appmanager\">Mastodon</a></string>\n    <string name=\"pref_import_existing\">Import existing rules</string>\n    <string name=\"pref_import_existing_msg\">Add components disabled by others apps to App Manager.\n        Be careful when using this tool as there can be many false positives. Choose only the apps you\\'re certain about.</string>\n    <string name=\"clear_cache\">Clear cache</string>\n    <string name=\"block_unblock_trackers_description\">Block or unblock ad and tracking components in all the installed apps</string>\n    <string name=\"block_components_dots\">Block components…</string>\n    <string name=\"block_unblock_components_dots\">Block/unblock components…</string>\n    <string name=\"unblock_components_dots\">Unblock components…</string>\n    <string name=\"block_unblock_components_description\">Block or unblock all components identified by the given signatures</string>\n    <string name=\"deny_app_ops_description\">Set a mode for app operations identified by the constant values, i.e., <tt>63</tt> or <tt>RUN_IN_BACKGROUND</tt></string>\n    <string name=\"clear_data_from_uninstalled_apps\">Clear data from uninstalled apps</string>\n    <string name=\"clear_data_from_uninstalled_apps_description\">Clear data from apps that are uninstalled with <tt>DONT_DELETE_DATA</tt> flag</string>\n    <string name=\"clear_app_cache\">Clear app cache</string>\n    <string name=\"clear_app_cache_description\">Clears the cache of all apps</string>\n    <string name=\"no_tracker_found\">No tracker found</string>\n    <string name=\"failed_packages\">Failed packages</string>\n    <string name=\"input_signatures\">Input signatures</string>\n    <string name=\"input_signatures_description\">Input signatures with spaces, e.g., <tt>com.facebook org.app2 com.app3</tt> etc.</string>\n    <string name=\"filtered_packages\">Filtered packages</string>\n    <string name=\"input_app_ops\">Input app ops</string>\n    <string name=\"input_app_ops_description\">Input app op names and/or constants with spaces, e.g., <tt>WAKE_LOCK 63 72 CAMERA</tt> etc.</string>\n    <string name=\"input_app_ops_description_profile\">Input app op names and/or constants with spaces, e.g., <tt>WAKE_LOCK 63 72 CAMERA</tt> etc. Use <tt>*</tt> to apply for all configured app ops.</string>\n    <string name=\"only_works_in_root_or_adb_mode\">Only works in root or ADB mode</string>\n    <string name=\"failed_to_parse_some_numbers\">Could not parse some numbers</string>\n    <plurals name=\"no_of_splits\">\n        <item quantity=\"one\">%1$d split</item>\n        <item quantity=\"other\">%1$d splits</item>\n    </plurals>\n    <string name=\"termux\">Termux</string>\n    <string name=\"package_name_is_installed_successfully\"><xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g> installed</string>\n    <string name=\"filter\">Filter</string>\n    <string name=\"filter_user_apps\">User apps</string>\n    <string name=\"filter_system_apps\">System apps</string>\n    <string name=\"filter_apps_with_rules\">With rules</string>\n    <string name=\"select_all\">Select all</string>\n    <string name=\"installed_version\">Installed version</string>\n    <string name=\"trackers\">Trackers</string>\n    <string name=\"components\">Components</string>\n    <string name=\"features\">Features</string>\n    <string name=\"whats_new\">What\\'s new</string>\n    <string name=\"blocking_rules\">Blocking rules</string>\n    <string name=\"external_data\">External data</string>\n    <string name=\"internal_data\">Internal data</string>\n    <string name=\"data\">Data</string>\n    <string name=\"backup\">Backup</string>\n    <string name=\"restore\">Restore</string>\n    <string name=\"delete_backup\">Delete backup</string>\n    <string name=\"backup_options\">Backup options</string>\n    <plurals name=\"failed_to_backup_some_apk_files\">\n        <item quantity=\"one\">Could not back up %1$d app</item>\n        <item quantity=\"other\">Could not back up %1$d apps</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_backup\">\n        <item quantity=\"one\">Could not back up %1$d app</item>\n        <item quantity=\"other\">Could not back up %1$d apps</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_restore\">\n        <item quantity=\"one\">Could not restore %1$d app</item>\n        <item quantity=\"other\">Could not restore %1$d apps</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_delete_backup\">\n        <item quantity=\"one\">Could not delete %1$d backup</item>\n        <item quantity=\"other\">Could not delete %1$d backups</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_unblock_trackers\">\n        <item quantity=\"one\">Could not unblock trackers from %1$d app</item>\n        <item quantity=\"other\">Could not unblock trackers from %1$d apps</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_block_components\">\n        <item quantity=\"one\">Could not block components for %1$d app</item>\n        <item quantity=\"other\">Could not block components for %1$d apps</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_unblock_components\">\n        <item quantity=\"one\">Could not unblock components for %1$d app</item>\n        <item quantity=\"other\">Could not unblock components for %1$d apps</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_set_app_ops\">\n        <item quantity=\"one\">Could not set app ops for %1$d app</item>\n        <item quantity=\"other\">Could not set app ops for %1$d apps</item>\n    </plurals>\n    <plurals name=\"backup_exists_are_you_sure\">\n        <item quantity=\"one\">Backup already exists. Are you sure?</item>\n        <item quantity=\"other\">More than one app has a backup already. Are you sure?</item>\n    </plurals>\n    <plurals name=\"classes\">\n        <item quantity=\"one\">%1$d class</item>\n        <item quantity=\"other\">%1$d classes</item>\n    </plurals>\n    <plurals name=\"libraries\">\n        <item quantity=\"one\">%1$d library</item>\n        <item quantity=\"other\">%1$d libraries</item>\n    </plurals>\n    <plurals name=\"missing_signatures\">\n        <item quantity=\"one\">%1$d signature missing</item>\n        <item quantity=\"other\">%1$d signatures missing</item>\n    </plurals>\n    <plurals name=\"app_signing_signature_schemes_pl\">\n        <item quantity=\"one\">Signature scheme</item>\n        <item quantity=\"other\">Signature schemes</item>\n    </plurals>\n    <plurals name=\"verified_with_warning\">\n        <item quantity=\"one\">Verified with %d warning</item>\n        <item quantity=\"other\">Verified with %d warnings</item>\n    </plurals>\n    <string name=\"apply_to_system_apps\">Apply to system apps</string>\n    <string name=\"apply_to_system_apps_question\">Apply to system apps too? Select \\\"No\\\" if unsure.</string>\n    <string name=\"no\">No</string>\n    <string name=\"yes\">Yes</string>\n    <string name=\"skip_signature_checks\">Skip signature checks</string>\n    <string name=\"clear_data_message\">Are you sure want to clear data from this app?</string>\n    <string name=\"clear\">Clear</string>\n    <string name=\"block\">Block</string>\n    <string name=\"unblock\">Unblock</string>\n    <string name=\"block_unblock_trackers\">Block/unblock trackers</string>\n    <string name=\"no_matching_package_found\">Could not find any such app</string>\n    <string name=\"export_icon\">Extract icon</string>\n    <string name=\"open_in_termux\">Open in Termux</string>\n    <string name=\"run_in_termux\">Run in Termux</string>\n    <string name=\"website\">Website</string>\n    <string name=\"website_message\" translatable=\"false\">https://muntashirakon.github.io/AppManager</string>\n    <string name=\"discussions_site\" translatable=\"false\">https://github.com/MuntashirAkon/AppManager/issues</string>\n    <string name=\"pref_remove_all_rules\">Remove all rules</string>\n    <string name=\"pref_remove_all_rules_msg\">Permissions will be granted, app ops and components will return to their default values.</string>\n    <string name=\"are_you_sure\">Are you sure?</string>\n    <string name=\"filter_apps_with_activities\">With activities</string>\n    <string name=\"toggle_default_app_ops\">Toggle default app ops</string>\n    <string name=\"installer_error_aborted\">Installation failed either because it was cancelled or the session was closed unexpectedly</string>\n    <string name=\"installer_error_blocked_device\">device</string>\n    <string name=\"installer_error_blocked\">Installation blocked by <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g></string>\n    <string name=\"installer_error_conflict\">Could not install app because the package name is in use</string>\n    <string name=\"installer_error_incompatible\">The app is incompatible with this device</string>\n    <string name=\"installer_error_bad_apks\">Invalid APK files selected</string>\n    <string name=\"installer_error_storage\">Not enough storage space to install the app</string>\n    <string name=\"installer_error_generic\">Installation failed</string>\n    <string name=\"installer_error_lidl_rom\">Your ROM is incompatible with Rootless Installer.</string>\n    <string name=\"failed_to_fetch_package_info\">Could not fetch package info</string>\n    <string name=\"batch_ops\">Batch operations</string>\n    <string name=\"operation_running\">Operation running…</string>\n    <string name=\"full_stop_tap_to_see_details\">. Tap to see details.</string>\n    <string name=\"try_again\">Try again</string>\n    <string name=\"install_app_message\">Do you want to install this app?</string>\n    <string name=\"reinstall\">Reinstall</string>\n    <string name=\"unblock_trackers\">Unblock trackers</string>\n    <string name=\"package_installer\">Package installer</string>\n    <string name=\"install_in_progress\">Installing…</string>\n    <string name=\"installer_error_security\">Could not access APK files</string>\n    <string name=\"installer_error_session_create\">Could not create an installer session</string>\n    <string name=\"installer_error_session_write\">Could not write to the installer session</string>\n    <string name=\"installer_error_session_commit\">Could not commit the APK files</string>\n    <string name=\"installer_error_session_abandon\">Could not abandon the installer session</string>\n    <string name=\"backup_apk_files\">APK files</string>\n    <string name=\"backup_obb_media\">OBB and media</string>\n    <string name=\"failed_to_extract_obb_files\">Could not extract OBB files</string>\n    <string name=\"obb_files_extracted_successfully\">OBB files extracted</string>\n    <string name=\"backup_multiple\">Back up multiple</string>\n    <string name=\"backup_all_users\">All users</string>\n    <string name=\"pref_app_language\">Language</string>\n    <string name=\"auto\">Auto</string>\n    <string name=\"choose_language\">Change language</string>\n    <string name=\"base_apk\">Base APK</string>\n    <string name=\"split_feature_name\">Feature: <xliff:g id=\"feature_name\" example=\"Visualizer\">%1$s</xliff:g></string>\n    <string name=\"unknown_split_for_feature\"><xliff:g id=\"split_name\" example=\"some_split\">%1$s</xliff:g> for feature <xliff:g id=\"feature_name\" example=\"Visualizer\">%2$s</xliff:g></string>\n    <string name=\"unknown_split_for_base_apk\"><xliff:g id=\"split_name\" example=\"some_split\">%1$s</xliff:g> for base APK</string>\n    <string name=\"density_split_for_feature\"><xliff:g id=\"split_name\" example=\"xxdpi\">%1$s</xliff:g> (<xliff:g id=\"dpi_no\" example=\"480\">%2$d</xliff:g> DPI) resources for feature <xliff:g id=\"feature_name\" example=\"Visualizer\">%3$s</xliff:g></string>\n    <string name=\"density_split_for_base_apk\"><xliff:g id=\"split_name\" example=\"xxdpi\">%1$s</xliff:g> (<xliff:g id=\"dpi_no\" example=\"480\">%2$d</xliff:g> DPI) resources for base APK</string>\n    <string name=\"abi_split_for_feature\"><xliff:g id=\"split_name\" example=\"arm64_v8a\">%1$s</xliff:g> code for <xliff:g id=\"feature_name\" example=\"Visualizer\">%2$s</xliff:g></string>\n    <string name=\"abi_split_for_base_apk\"><xliff:g id=\"split_name\" example=\"arm64_v8a\">%1$s</xliff:g> code for base APK</string>\n    <string name=\"locale_split_for_feature\"><xliff:g id=\"split_name\" example=\"English\">%1$s</xliff:g> locale for feature <xliff:g id=\"feature_name\" example=\"Visualizer\">%2$s</xliff:g></string>\n    <string name=\"locale_split_for_base_apk\"><xliff:g id=\"split_name\" example=\"English\">%1$s</xliff:g> locale for base APK</string>\n    <string name=\"empty\" translatable=\"false\" />\n    <string name=\"_null\" translatable=\"false\">null</string>\n    <string name=\"launch_mode_multiple\">Multiple</string>\n    <string name=\"launch_mode_single_instance\">Single instance</string>\n    <string name=\"launch_mode_single_task\">Single task</string>\n    <string name=\"launch_mode_single_top\">Single top</string>\n    <string name=\"orientation_unspecified\">Unspecified</string>\n    <string name=\"orientation_behind\">Behind</string>\n    <string name=\"orientation_full_sensor\">Full sensor</string>\n    <string name=\"orientation_full_user\">Full user</string>\n    <string name=\"orientation_locked\">Locked</string>\n    <string name=\"orientation_no_sensor\">No sensor</string>\n    <string name=\"orientation_landscape\">Landscape</string>\n    <string name=\"orientation_portrait\">Portrait</string>\n    <string name=\"orientation_reverse_portrait\">Reverse portrait</string>\n    <string name=\"orientation_reverse_landscape\">Reverse landscape</string>\n    <string name=\"orientation_user\">User</string>\n    <string name=\"orientation_sensor_landscape\">Sensor landscape</string>\n    <string name=\"orientation_sensor_portrait\">Sensor portrait</string>\n    <string name=\"orientation_sensor\">Sensor</string>\n    <string name=\"orientation_user_landscape\">User landscape</string>\n    <string name=\"orientation_user_portrait\">User portrait</string>\n    <string name=\"required\">Required</string>\n    <string name=\"_undefined\">Undefined</string>\n    <string name=\"keyboard_no_keys\">No keys</string>\n    <string name=\"keyboard_qwerty\">QWERTY</string>\n    <string name=\"keyboard_12_keys\">12 key</string>\n    <string name=\"navigation_no_nav\">No nav</string>\n    <string name=\"navigation_dial_pad\">Dial pad</string>\n    <string name=\"navigation_trackball\">Trackball</string>\n    <string name=\"navigation_wheel\">Wheel</string>\n    <string name=\"touchscreen_no_touch\">No touch</string>\n    <string name=\"touchscreen_stylus\">Stylus</string>\n    <string name=\"touchscreen_finger\">Finger</string>\n    <string name=\"state_sleeping\">Sleeping</string>\n    <string name=\"state_device_io\">Device I/O</string>\n    <string name=\"state_trace_stop\">Trace stop</string>\n    <string name=\"state_dead\">Dead</string>\n    <string name=\"state_zombie\">Zombie</string>\n    <string name=\"state_parked\">Parked</string>\n    <string name=\"state_idle\">Idle</string>\n    <string name=\"state_wake_kill\">Wake kill</string>\n    <string name=\"state_waking\">Waking</string>\n    <string name=\"state_unknown\">Unknown</string>\n    <string name=\"state_high_priority\">High priority</string>\n    <string name=\"state_low_priority\">Low priority</string>\n    <string name=\"state_locked_memory\">Locked memory</string>\n    <string name=\"state_session_leader\">Session leader</string>\n    <string name=\"state_foreground\">Foreground</string>\n    <string name=\"state_multithreaded\">Multithreaded</string>\n    <string name=\"process_state\">State: <xliff:g id=\"process_state\" example=\"Sleeping\">%1$s</xliff:g></string>\n    <string name=\"process_state_with_extra\">State: <xliff:g id=\"process_state\" example=\"Sleeping\">%1$s</xliff:g> (<xliff:g id=\"state_extra\" example=\"High priority\">%2$s</xliff:g>)</string>\n    <string name=\"downgrade\">Downgrade</string>\n    <string name=\"input_backup_name\">Backup name</string>\n    <string name=\"input_backup_name_description\">Backup name should not start with a digit nor should it contain any spaces. Leave it empty if you want to use current date-time.</string>\n    <string name=\"ok\">OK</string>\n    <string name=\"cancel\">Cancel</string>\n    <string name=\"systemless_app\">Systemless app</string>\n    <string name=\"open_pgp_provider\">OpenPGP provider</string>\n    <string name=\"profiles\">Profiles</string>\n    <string name=\"no_profiles\">No profiles</string>\n    <string name=\"keystore\">KeyStore</string>\n    <string name=\"apply_now\">Apply now…</string>\n    <string name=\"routine_ops\">Routine ops</string>\n    <string name=\"apps\">Apps</string>\n    <string name=\"no_apps\">No apps</string>\n    <string name=\"filter_apps\">Apps</string>\n    <string name=\"sort_by_process_id\">Process ID</string>\n    <string name=\"sort_by_process_name\">Process name</string>\n    <string name=\"sort_by_apps_first\">Apps first</string>\n    <string name=\"sort_by_memory_usage\">Memory usage</string>\n    <string name=\"changes_not_saved\">Changes not saved</string>\n    <string name=\"other\">Other</string>\n    <string name=\"rules\">Rules</string>\n    <string name=\"pref_compression_method\">Compression method</string>\n    <string name=\"pref_backup_flags_msg\">Adding a preset for backup options removes the burden of selecting flags every time you back up/restore.</string>\n    <string name=\"confirm_installation\">Confirm installation</string>\n    <string name=\"allow_open_pgp_operation\">Tap to allow App Manager to use OpenPGP</string>\n    <string name=\"uninstall_updates\">Uninstall updates</string>\n    <string name=\"update_uninstalled_successfully\">Updates for <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g> has been uninstalled.</string>\n    <string name=\"failed_to_uninstall_updates\">Could not uninstall updates for <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g>.</string>\n    <string name=\"sort_by_backup\">Backed up first</string>\n    <string name=\"filter_apps_with_backups\">With backups</string>\n    <string name=\"subject\">Subject</string>\n    <string name=\"issuer\">Issuer</string>\n    <string name=\"issued_date\">Issued date</string>\n    <string name=\"expiry_date\">Expiry date</string>\n    <string name=\"type\">Type</string>\n    <string name=\"validity\">Validity</string>\n    <string name=\"valid\">Valid</string>\n    <string name=\"expired\">Expired</string>\n    <string name=\"not_yet_valid\">Not yet valid</string>\n    <string name=\"serial_no\">Serial number</string>\n    <string name=\"checksums\">Checksums</string>\n    <string name=\"app_signing_signature\">Signature</string>\n    <string name=\"algorithm\">Algorithm</string>\n    <string name=\"public_key\">Public key</string>\n    <string name=\"format\">Format</string>\n    <string name=\"rsa_exponent\">Exponent</string>\n    <string name=\"rsa_modulus\">Modulus</string>\n    <string name=\"dsa_affine_x\">Affine x coordinate</string>\n    <string name=\"dsa_affine_y\">Affine y coordinate</string>\n    <string name=\"critical_exts\">Critical extensions</string>\n    <string name=\"non_critical_exts\">Non-critical extensions</string>\n    <string name=\"usage_access_not_supported\">Could not request usage access, as the corresponding settings page does not exist.</string>\n    <string name=\"do_you_want_to_uninstall_and_install\">Do you want to uninstall and install the app again?</string>\n    <string name=\"app_signing_signature_mismatch_for_system_apps\">Could not install app because a system app with a different signature has this package name.</string>\n    <string name=\"app_data_will_be_lost\">The existing data will be lost.</string>\n    <string name=\"app_signing_install_without_data_loss\">If you have turned off signature verification, you can use the <b>Only install</b> option to install the app without losing data.</string>\n    <string name=\"only_install\">Only install</string>\n    <string name=\"sys_config\">System config</string>\n    <string name=\"scanner\">Scanner</string>\n    <string name=\"no_libs\">No libraries</string>\n    <string name=\"lib_details\">Library details</string>\n    <string name=\"tap_to_see_details\">Tap to see details</string>\n    <string name=\"view_missing_signatures\">Tap to view or send in signatures not yet present in App Manager\\'s database of libraries.</string>\n    <string name=\"copy\">Copy</string>\n    <string name=\"filter_running_apps\">Running apps</string>\n    <string name=\"am_crashed\">App Manager has just crashed</string>\n    <string name=\"tap_to_submit_crash_report\">Tap to submit the crash report.</string>\n    <string name=\"send_crash_report\">Send crash report</string>\n    <string name=\"select_apk\">Select APK</string>\n    <string name=\"conversion_failed\">Conversion failed.</string>\n    <string name=\"in_progress\">In progress</string>\n    <string name=\"un_apkm\">UnApkm</string>\n    <string name=\"input_profile_name\">Profile name</string>\n    <string name=\"input_profile_name_description\">The profile name cannot contain any spaces.</string>\n    <string name=\"new_profile\">New profile</string>\n    <string name=\"duplicate\">Duplicate</string>\n    <string name=\"failed_to_duplicate_profile\">Could not duplicate profile</string>\n    <string name=\"select_user\">Select user</string>\n    <string name=\"encryption\">Encryption</string>\n    <string name=\"pref_encryption_msg\">Encryption for backups.</string>\n    <string name=\"none\">None</string>\n    <string name=\"aes\">AES</string>\n    <string name=\"rsa\">RSA</string>\n    <string name=\"ecc\">Elliptic-curve cryptography</string>\n    <string name=\"send_selected\">Send selected</string>\n    <string name=\"pref_mode_of_operations\">Mode of operation</string>\n    <string name=\"adb_over_tcp\">ADB over TCP</string>\n    <string name=\"allow_routine_ops\">Allow routine ops</string>\n    <string name=\"profile_state\">Profile state</string>\n    <string name=\"allow_routine_ops_msg\">Allow the profile to be used in the routine operations</string>\n    <string name=\"profile_force_stop_msg\">Force-stops apps</string>\n    <string name=\"profile_clear_cache_msg\">Clears the app cache of apps</string>\n    <string name=\"profile_clear_data_msg\">Clears the data of apps</string>\n    <string name=\"profile_block_trackers_msg\">Blocks the trackers in apps</string>\n    <string name=\"profile_state_msg\">Custom on/off state for this profile</string>\n    <string name=\"on\">On</string>\n    <string name=\"off\">Off</string>\n    <string name=\"options\">Options</string>\n    <string name=\"input_permissions\">Input permissions</string>\n    <string name=\"input_permissions_description\">Input permissions with spaces, e.g., <tt>com.permission.GET_ACCOUNTS android.permission.ACCESS_MEDIA_LOCATION</tt> etc. Use <tt>*</tt> to apply for all permissions.</string>\n    <string name=\"choose\">Choose</string>\n    <string name=\"enabled\">Enabled</string>\n    <string name=\"simple\">Simple</string>\n    <string name=\"advanced\">Advanced</string>\n    <string name=\"user_profile_with_id\">Profile: %1$s (%2$d)</string>\n    <string name=\"root\">Root</string>\n    <string name=\"no_root\">No root</string>\n    <string name=\"close\">Close</string>\n    <string name=\"comment\">Comment</string>\n    <string name=\"installer\">Installer</string>\n    <string name=\"install_location\">Install location</string>\n    <string name=\"install_location_internal_only\">Internal only</string>\n    <string name=\"install_location_prefer_external\">Prefer external</string>\n    <string name=\"pref_sign_apk\">Sign APK</string>\n    <string name=\"pref_sign_apk_msg\">Sign APK files before installing them.</string>\n    <string name=\"app_signing_signature_schemes\">Signature schemes</string>\n    <string name=\"apk_signing\">APK signing</string>\n    <string name=\"pref_apk_signing_msg\">Set signature schemes, custom signing key, etc.</string>\n    <string name=\"v1_scheme\">v1 scheme (since Android 1.0)</string>\n    <string name=\"v2_scheme\">v2 scheme (since Android 7.0)</string>\n    <string name=\"v3_scheme\">v3 scheme (since Android 9)</string>\n    <string name=\"v4_scheme\">v4 scheme (since Android 11)</string>\n    <string name=\"pref_signature_schemes_msg\">At least v1 and v2 schemes should be selected for a greater compatibility. v4 scheme requires v2 or v3.</string>\n    <string name=\"verified\">Verified</string>\n    <string name=\"not_verified\">Not verified</string>\n    <string name=\"source_stamp_verified\">SourceStamp verified.</string>\n    <string name=\"source_stamp_verified_and_identified_to_be_from_source\">SourceStamp verified and identified to be from <xliff:g id=\"source\" example=\"Google Play\">%1$s</xliff:g>.</string>\n    <string name=\"splits\">Splits</string>\n    <string name=\"input_keystore_pass\">Input KeyStore password</string>\n    <string name=\"input_keystore_pass_description\">Enter the App Manager KeyStore password. If you\\'re seeing this for the first time, please use a password generator to generate a password and save it in a secure place before inserting it here.</string>\n    <string name=\"input_keystore_pass_msg\">Tap here to enter KeyStore password</string>\n    <string name=\"input_keystore_alias_pass\">Password for alias <b>%1$s</b></string>\n    <string name=\"input_keystore_alias_pass_description\">Insert password for the alias <b>%1$s</b>. You can leave this empty if the password is the same as the KeyStore password.</string>\n    <string name=\"input_keystore_alias_pass_msg\">Tap here to provide password for %1$s</string>\n    <string name=\"no_app_ops_permission\">No permission to display app ops</string>\n    <string name=\"this_action_cannot_be_undone\">This action cannot be undone.</string>\n    <string name=\"keep_data_and_app_signing_signatures\">Keep data and signatures</string>\n    <string name=\"pref_backup_android_keystore\">Back up apps with Android KeyStore</string>\n    <string name=\"pref_backup_android_keystore_msg\">Not all apps will work after being restored. Restoring KeyStore doesn\\'t work on most devices.</string>\n    <string name=\"magisk_hide_enabled\">MagiskHide</string>\n    <string name=\"set_app_op_mode\">Set app op mode</string>\n    <string name=\"filter_apps_with_splits\">With splits</string>\n    <string name=\"value\">Value</string>\n    <string name=\"matching_activities\">Matching activities</string>\n    <string name=\"send_edited_intent\">Send edited Intent</string>\n    <string name=\"activity_result\">Activity result</string>\n    <string name=\"result_code\">Result code</string>\n    <string name=\"action\">Action</string>\n    <string name=\"mime_type\">MIME type</string>\n    <string name=\"uri\">URI</string>\n    <string name=\"category\">Categories</string>\n    <string name=\"extras\">Extras</string>\n    <string name=\"share\">Share</string>\n    <string name=\"resend_intent\">Resend intent</string>\n    <string name=\"interceptor\">Interceptor</string>\n    <string name=\"set_custom_app_op\">Set custom app op</string>\n    <string name=\"about_device\">About the device</string>\n    <string name=\"pref_about_device_msg\">Basic device info including Android system, CPU, GPU, RAM, battery, etc.</string>\n    <string name=\"brand_name\">Brand</string>\n    <string name=\"model\">Model</string>\n    <string name=\"board_name\">Board</string>\n    <string name=\"manufacturer\">Manufacturer</string>\n    <string name=\"kernel\">Kernel</string>\n    <string name=\"security_providers\">Security providers</string>\n    <string name=\"support_architectures\">Supported architectures</string>\n    <string name=\"no_of_cores\">Cores</string>\n    <string name=\"gles_version\">OpenGL ES version</string>\n    <string name=\"vendor\">Vendor</string>\n    <string name=\"memory\">Memory</string>\n    <string name=\"battery_capacity\">Capacity</string>\n    <string name=\"languages\">Languages</string>\n    <string name=\"users\">Users</string>\n    <string name=\"cpu\">CPU</string>\n    <string name=\"graphics\">Graphics</string>\n    <string name=\"battery\">Battery</string>\n    <string name=\"security\">Security</string>\n    <string name=\"set_mode_for_app_ops_dots\">Set mode for app ops…</string>\n    <string name=\"backup_apk_files_description\">Back up APK files from the source directory, including splits.</string>\n    <string name=\"backup_internal_data_description\">Back up internal data folders.</string>\n    <string name=\"backup_external_data_description\">Back up external data folders.</string>\n    <string name=\"backup_obb_media_description\">Back up OBB and media folders.</string>\n    <string name=\"backup_cache_description\">Back up <b>cache</b>, <b>no_cache</b> and <b>no_backup</b> folders.</string>\n    <string name=\"backup_extras\">Extras</string>\n    <string name=\"backup_extras_description\">Back up app permissions, battery saving and data usage options, MagiskHide status, SSAID, etc. <font fgcolor=\"#ff0000\">Depending on the permissions, not all extras can be restored.</font></string>\n    <string name=\"backup_rules_description\">Back up rules configured within App Manager. <font fgcolor=\"#ff0000\">Depending on the permissions, not all rules can be reapplied during restore.</font></string>\n    <string name=\"backup_multiple_description\">Create a separate <i>named</i> backup instead of the base backup.</string>\n    <string name=\"backup_skip_signature_checks_description\">Restore backups that either fail checksum verification or have different APK signatures than their prior backups.</string>\n    <string name=\"patch_level\">Patch level</string>\n    <string name=\"selinux\">SELinux</string>\n    <string name=\"enforcing\">Enforcing</string>\n    <string name=\"permissive\">Permissive</string>\n    <string name=\"hardware\">Hardware</string>\n    <string name=\"screen\">Screen</string>\n    <string name=\"density\">Density</string>\n    <string name=\"size\">Size</string>\n    <string name=\"scaling_factor\">Scaling factor</string>\n    <string name=\"refresh_rate\">Refresh rate</string>\n    <string name=\"window_size\">Window size</string>\n    <string name=\"failed_to_disable_magisk_hide\">Could not disable MagiskHide</string>\n    <string name=\"failed_to_enable_magisk_hide\">Could not enable MagiskHide</string>\n    <string name=\"disable_background_run_description\">Sets <i>Ignore</i> mode for the following app ops: <tt>RUN_IN_BACKGROUND</tt> (from Android 7.0) and <tt>RUN_ANY_IN_BACKGROUND</tt> (from Android 9).</string>\n    <string name=\"pref_backup_restore_msg\">Customise backup/restore.</string>\n    <string name=\"backup_volume\">Backup volume</string>\n    <string name=\"pref_backup_volume_msg\">Select the volume or disk where the backups will be stored.</string>\n    <string name=\"no_volumes_found\">Could not find any volumes with write permission.</string>\n    <string name=\"unencrypted\">Unencrypted</string>\n    <string name=\"encrypted\">Encrypted</string>\n    <string name=\"bootloader\">Bootloader</string>\n    <string name=\"backup_custom_users\">Custom users</string>\n    <string name=\"backup_custom_users_description\">Perform backups only for the specified users</string>\n    <string name=\"backup_all_apps\">Back up all apps</string>\n    <string name=\"backup_all_apps_msg\">Back up all the installed apps.</string>\n    <string name=\"backup_apps_without_backups\">Back up apps without backups</string>\n    <string name=\"backup_apps_without_backups_msg\">Back up apps without any previous backups.</string>\n    <string name=\"verify_and_redo_backups\">Verify and redo backups</string>\n    <string name=\"verify_and_redo_backups_msg\">Check integrity of the previous backups and redo backups for which the integrity check-up fails.</string>\n    <string name=\"redo_existing_backups\">Redo existing backups</string>\n    <string name=\"redo_existing_backups_msg\">Redo backup for installed apps with previous backups.</string>\n    <string name=\"backup_apps_with_changes\">Back up apps with changes</string>\n    <string name=\"backup_apps_with_changes_msg\">Redo backups for apps with changes since the last backup. They include changes in size, version, last launch time.</string>\n    <string name=\"restore_all\">Restore all apps</string>\n    <string name=\"restore_all_msg\">Restore base backup from all backed up apps.</string>\n    <string name=\"restore_not_installed\">Restore not installed apps</string>\n    <string name=\"restore_not_installed_msg\">Restore base backup for apps that are not currently installed.</string>\n    <string name=\"restore_latest\">Restore latest backups</string>\n    <string name=\"restore_latest_msg\">Restore already installed apps whose version codes are higher than the installed version code.</string>\n    <string name=\"backup_msg\">Back up apps with data</string>\n    <string name=\"restore_msg\">Restore apps with data</string>\n    <string name=\"drm_free_apkm_msg\">The APKM file is DRM-free, no need to convert it to APKS.</string>\n    <string name=\"back_up\">Back up</string>\n    <string name=\"internal_storage\">Internal storage</string>\n    <string name=\"external_storage\">External storage</string>\n    <string name=\"sd_card\">SD card</string>\n    <string name=\"unlock_app_manager\">Unlock App Manager</string>\n    <string name=\"screen_lock\">Screen lock</string>\n    <string name=\"screen_lock_msg\">Lock App Manager using Android screen lock</string>\n    <string name=\"type_null\">No value</string>\n    <string name=\"type_component_name\">Component name</string>\n    <string name=\"type_int_array\">Array of integers</string>\n    <string name=\"type_int_array_list\">List of integers</string>\n    <string name=\"type_long_array\">Array of long integers</string>\n    <string name=\"type_long_array_list\">List of long integers</string>\n    <string name=\"type_float_array\">Array of decimal numbers</string>\n    <string name=\"type_float_array_list\">List of decimal numbers</string>\n    <string name=\"type_string_array\">Array of strings</string>\n    <string name=\"type_string_array_list\">List of strings</string>\n    <string name=\"type_uri\">URI</string>\n    <string name=\"no_battery_optimization\">No battery optimization</string>\n    <string name=\"battery_optimization\">Battery optimization</string>\n    <string name=\"enable_battery_optimization\">Enable battery optimization?</string>\n    <string name=\"choose_what_to_do\">Choose what to do.</string>\n    <string name=\"has_net_policy\">Net policy</string>\n    <string name=\"net_policy\">Net policy</string>\n    <string name=\"initializing\">Initializing…</string>\n    <string name=\"add_to_profile\">Add to profile</string>\n    <string name=\"add\">Add</string>\n    <string name=\"os_version\">OS version</string>\n    <string name=\"reverse\">Reverse</string>\n    <string name=\"list_options\">List options</string>\n    <string name=\"ssaid\">SSAID</string>\n    <string name=\"ssaid_info\">SSAID (<tt>Settings.Secure.ANDROID_ID</tt>) is a device identifier assigned to each app (from Android 8 \\\"Oreo\\\" onwards). It is widely used by apps to track users.</string>\n    <string name=\"copied_to_clipboard\">Copied to clipboard.</string>\n    <string name=\"failed_to_change_ssaid\">Could not change SSAID</string>\n    <string name=\"restart_to_reflect_changes\">You must restart the device immediately to use the new changes.</string>\n    <string name=\"installed_apps\">Installed apps</string>\n    <string name=\"enable_disable_features\">Enable/disable features</string>\n    <string name=\"pref_enable_disable_features_msg\">Enable or disable features in App Manager.</string>\n    <string name=\"last_actions\">Last actions</string>\n    <string name=\"isolated\">Isolated</string>\n    <string name=\"screen_lock_not_enabled\">Please pick a screen lock in the Android settings, or clear app data.</string>\n    <string name=\"working_on_adb_mode\">Working on ADB mode</string>\n    <string name=\"verified_using_unreliable_hash\">Verified using unreliable hash</string>\n    <string name=\"specify_custom_name\">Custom</string>\n    <string name=\"installer_app_message\">Select <b>Choose</b> to choose from the installed apps or select <b>Custom</b> to specify a custom package name.</string>\n    <string name=\"uninstalled_apps\">Uninstalled apps</string>\n    <string name=\"filter_apps_without_backups\">Without backups</string>\n    <string name=\"input_key\">Input key (in hexadecimal)</string>\n    <string name=\"generate_key\">Generate</string>\n    <string name=\"failed_to_save_key\">Could not save key.</string>\n    <string name=\"failed_to_initialize_key_store\">Could not initialize App Manager keystore.</string>\n    <string name=\"invalid_aes_key_size\">Invalid key size for AES encryption. Key size can be either 128 or 256 bits.</string>\n    <string name=\"crypto_key_size\">Key size</string>\n    <string name=\"invalid_rsa_key_size\">Invalid key size for RSA encryption. Key size can be 1024, 2048 or 4096 bits.</string>\n    <string name=\"use_default\">Use default</string>\n    <string name=\"key_not_set\">Not set.</string>\n    <string name=\"failed_to_load_key\">Could not load the key.</string>\n    <string name=\"input_key_password\">Key password</string>\n    <string name=\"common_name\">Common name (CN)</string>\n    <string name=\"organization_unit\">Organization unit (OU)</string>\n    <string name=\"organization_name\">Organization name (O)</string>\n    <string name=\"locality_name\">Locality (city) name (L)</string>\n    <string name=\"state_name\">State name (ST)</string>\n    <string name=\"country_name\" tools:ignore=\"TypographyOther\">Country name (C)</string>\n    <string name=\"keystore_file\">KeyStore file</string>\n    <string name=\"keystore_pass\">KeyStore password</string>\n    <string name=\"java_keystore\">Java KeyStore (JKS)</string>\n    <string name=\"bouncy_castle_keystore\">Bouncy Castle KeyStore (BKS)</string>\n    <string name=\"pkcs12_keystore\">PKCS #12 KeyStore (P12)</string>\n    <string name=\"pem_and_pk8\">PEM and PKCS #8 (PK8)</string>\n    <string name=\"pk8_file\">PKCS #8 (PK8) file</string>\n    <string name=\"pem_file\">PEM file</string>\n    <string name=\"import_key\">Import key</string>\n    <string name=\"new_alias_password\">New alias password</string>\n    <string name=\"found_no_alias_in_keystore\">No alias found in the KeyStore!</string>\n    <string name=\"choose_an_alias\">Choose an alias</string>\n    <string name=\"alias_pass\">Alias password</string>\n    <string name=\"failed_to_read_keystore\">Could not read the KeyStore.</string>\n    <string name=\"signing_key\">Signing key</string>\n    <string name=\"expiry_date_cannot_be_empty\">Expiry date cannot be empty.</string>\n    <string name=\"pref_installer_msg\">Configure the behaviours of the app installer.</string>\n    <string name=\"pref_import_backups\">Import backups</string>\n    <string name=\"pref_import_backups_msg\">Import backups from OAndBackup, Swift Backup (3.0–3.2) or Titanium Backup.</string>\n    <string name=\"import_from_oab\">Import from OAndBackup</string>\n    <string name=\"import_from_tb\">Import from Titanium Backup</string>\n    <string name=\"log_viewer\">Log viewer</string>\n    <string name=\"pref_log_viewer_msg\">Configure how logs are displayed.</string>\n    <string name=\"restart_log_viewer_to_see_changes\">Restart log viewer window to see changes.</string>\n    <string name=\"filename\">Filename</string>\n    <string name=\"log_level_debug\">Debug</string>\n    <string name=\"log_level_error\">Error</string>\n    <string name=\"log_level_info\">Info</string>\n    <string name=\"log_level_verbose\">Verbose</string>\n    <string name=\"log_level_warn\">Warn</string>\n    <string name=\"log_level_fatal\">Fatal</string>\n    <string name=\"pref_filter_pattern_default\" translatable=\"false\">ResourceType|memtrack|android.os.Debug|BufferItemConsumer|DPM.*|MDM.*|ChimeraUtils|BatteryExternalStats.*|chatty.*|DisplayPowerController|WidgetHelper|WearableService|DigitalWidget.*|^ANDR-PERF-.*</string>\n    <string name=\"pref_hide_partial_select_help\" translatable=\"false\">pref_hide_partial_select_help</string>\n    <string name=\"pref_include_device_info\" translatable=\"false\">device_info</string>\n    <string name=\"add_filter\">Add filter</string>\n    <string name=\"add_filter_ellipsis\">Add filter…</string>\n    <plurals name=\"file_deletion_confirmation\">\n        <item quantity=\"one\">%d file will be deleted</item>\n        <item quantity=\"other\">%d files will be deleted</item>\n    </plurals>\n    <string name=\"copy_to_clipboard\">Copy to clipboard</string>\n    <string name=\"delete_saved_log\">Delete saved logs</string>\n    <string name=\"dialog_compiling_log\">Compiling log…</string>\n    <string name=\"enter_filename\">Enter filename</string>\n    <string name=\"enter_good_filename\">Please enter a valid filename.</string>\n    <string name=\"filter_choice\">Search by</string>\n    <string name=\"filter_choice_pid\">PID</string>\n    <string name=\"filter_choice_tag\">Tag</string>\n    <string name=\"log_cleared\">Logs cleared</string>\n    <string name=\"log_level\">Log level</string>\n    <string name=\"log_recording_started\">Log recording started.</string>\n    <string name=\"log_saved\">Log saved.</string>\n    <string name=\"manage_saved_logs\">Manage saved logs</string>\n    <string name=\"no_saved_logs\">No saved logs.</string>\n    <string name=\"notification_subtext\">Touch to stop recording</string>\n    <string name=\"notification_ticker\">Log recording started</string>\n    <string name=\"notification_title\">Log recording in progress</string>\n    <string name=\"open\">Open</string>\n    <string name=\"pref_buffer_title\">Log buffer(s)</string>\n    <string name=\"pref_cat_advanced\">Advanced</string>\n    <string name=\"pref_cat_appearance\">Appearance</string>\n    <string name=\"pref_cat_configuration\">Configuration</string>\n    <string name=\"pref_default_log_level_summary\">Log level at startup, when opening files, and when recording.</string>\n    <string name=\"pref_default_log_level_title\">Default log level</string>\n    <string name=\"pref_display_limit_summary\" tools:ignore=\"PluralsCandidate\">Show only the last %1$d logs in order to avoid out of memory errors.</string>\n    <string name=\"pref_display_limit_title\">Log display limit</string>\n    <string name=\"pref_filter_pattern_summary\">Filter out the selected tags from logs.</string>\n    <string name=\"pref_filter_pattern_title\">Filter out tags</string>\n    <string name=\"pref_expanded_by_default_summary\">Show full log text by default.</string>\n    <string name=\"pref_expanded_by_default_title\">Expand by default</string>\n    <string name=\"pref_log_line_period_error\">Please enter an integer between 1 and 1000.</string>\n    <string name=\"pref_log_write_period_summary\" tools:ignore=\"PluralsCandidate\">When recording, write to SD card every %1$d lines.</string>\n    <string name=\"pref_log_write_period_title\">Write period</string>\n    <string name=\"pref_show_timestamp_summary\">Show process id and timestamp when expanded.</string>\n    <string name=\"pref_show_timestamp_title\">Show PID &amp; timestamp</string>\n    <string name=\"record_log\">Record log</string>\n    <string name=\"save_as\">Save as…</string>\n    <string name=\"save_log\">Save log</string>\n    <string name=\"send_log_title\">Send log</string>\n    <string name=\"settings\">Settings</string>\n    <string name=\"start_recording_log\">Record</string>\n    <string name=\"subject_log_report\">Log report</string>\n    <string name=\"text_filter_ellipsis\">Filter…</string>\n    <string name=\"text_filter_text\">Filter text</string>\n    <string name=\"text_include_device_info\">Include device information</string>\n    <string name=\"pref_display_limit_hint\" tools:ignore=\"PluralsCandidate\">Please enter a valid number between %1$d and %2$d.</string>\n    <string name=\"toast_invalid_level\">Invalid level name: %s</string>\n    <string name=\"toast_invalid_selection\">Invalid selection. Please try again.</string>\n    <plurals name=\"toast_log_truncated\">\n        <item quantity=\"one\">Log too large, showing last %d line.</item>\n        <item quantity=\"other\">Log too large, showing last %d lines.</item>\n    </plurals>\n    <string name=\"unable_to_save_log\">Unable to save log. Did you enter a valid filename?</string>\n    <string name=\"widget_recording_in_progress\">Recording…</string>\n    <string name=\"widget_start_recording\">Record\\nLog</string>\n    <string name=\"file\">File</string>\n    <string name=\"expand_all\">Expand all</string>\n    <string name=\"collapse_all\">Collapse all</string>\n    <string name=\"pause_unpause\">Play/pause</string>\n    <string name=\"undo\">Undo</string>\n    <string name=\"omit_sensitive_info\">Omit sensitive info</string>\n    <string name=\"omit_sensitive_info_summary\">Omit sensitive info like web urls, phone numbers or emails.</string>\n    <string name=\"text_include_dmesg\">Include kernel log</string>\n    <string name=\"pref_include_dmesg\" translatable=\"false\">dmesg</string>\n    <string name=\"share_log\">Share</string>\n    <string name=\"view_logs\">View logs</string>\n    <string name=\"running_services\">Running services</string>\n    <string name=\"save_apk\">Save APK</string>\n    <string name=\"profile_save_apk_msg\">Saves APK files in <tt>AppManager/apks</tt></string>\n    <string name=\"failed_to_block_trackers\">Could not block trackers</string>\n    <string name=\"failed_to_unblock_trackers\">Could not unblock trackers</string>\n    <string name=\"trackers_blocked_successfully\">Trackers are now blocked</string>\n    <string name=\"trackers_unblocked_successfully\">Trackers are now unblocked</string>\n    <string name=\"base_backup\">Base backup</string>\n    <string name=\"no_encryption\">No encryption</string>\n    <string name=\"pgp_aes_rsa_encrypted\">%1$s encrypted</string>\n    <string name=\"gz_bz2_compressed\">%1$s compressed</string>\n    <string name=\"latest_backup\">Latest backup</string>\n    <string name=\"pref_import_export_keystore\">Import/export KeyStore</string>\n    <string name=\"pref_import_export_keystore_msg\">Import/export Bouncy Castle KeyStore (BKS) internally used by App Manager.</string>\n    <string name=\"import_keystore\">Import KeyStore</string>\n    <string name=\"confirm_import_keystore\">Are you sure want to replace the existing KeyStore? This action cannot be undone.</string>\n    <string name=\"failed\">Failed</string>\n    <string name=\"pref_rules_msg\">Instant blocking, import/export/remove rules, etc.</string>\n    <string name=\"saf\">SAF</string>\n    <string name=\"pref_layout_direction\">Layout direction</string>\n    <string name=\"orientation_follow_locale\">Follow locale</string>\n    <string name=\"orientation_left_to_right\">Left to right</string>\n    <string name=\"orientation_right_to_left\">Right to left</string>\n    <plurals name=\"alert_failed_to_import_backups\">\n        <item quantity=\"one\">Could not import %1$d backup</item>\n        <item quantity=\"other\">Could not import %1$d backups</item>\n    </plurals>\n    <string name=\"suspended\">Suspended</string>\n    <string name=\"hidden\">Hidden</string>\n    <string name=\"pref_display_changes\">Display changes</string>\n    <string name=\"pref_display_changes_msg\">Display changes in version, trackers, components, permissions, signatures, SDK, etc. in a version controlled manner.</string>\n    <string name=\"no_changes\">No changes</string>\n    <string name=\"netpolicy_reject_background_data\">Reject background data</string>\n    <string name=\"netpolicy_reject_metered_background_data\">Reject background data on metered networks</string>\n    <string name=\"netpolicy_reject_metered_data\">Reject data on metered networks</string>\n    <string name=\"netpolicy_allow_metered_background_data\">Allow background data on metered networks even when Data Saver is on</string>\n    <string name=\"netpolicy_allow_background_data\">Allow background data when Data Saver is on</string>\n    <string name=\"netpolicy_reject_cellular_data\">Reject cellular data</string>\n    <string name=\"netpolicy_reject_vpn_data\">Reject VPN data</string>\n    <string name=\"netpolicy_reject_wifi_data\">Reject Wi-Fi data</string>\n    <string name=\"netpolicy_disable_network_access\">Disable network access</string>\n    <string name=\"wireless_debugging\">Wireless debugging</string>\n    <string name=\"adb_connect\">Connect</string>\n    <string name=\"port_number\">Port</string>\n    <string name=\"adb_connect_port_number_description\">Port number is located under <b>IP address &amp; port</b> section\n        just below the <b>Device name</b> section.</string>\n    <string name=\"port_number_empty\">Port number is empty.</string>\n    <string name=\"port_number_invalid\">Invalid port number.</string>\n    <string name=\"unknown_net_policy\">Unknown netpolicy (%1$s - %2$X)</string>\n    <string name=\"failed_to_prevent_background_run\">Could not prevent %1$s from running in the background</string>\n    <string name=\"help_app_ops_tab\">Click on an item to <b>allow</b> or <b>ignore</b> it. Long click on an item to see other supported modes.</string>\n    <string name=\"help_permissions_tab\">These permissions are defined by this app and cannot be revoked.</string>\n    <string name=\"help_uses_permissions_tab\">Click on an item to <b>grant</b> or <b>revoke</b> it. Only <b>dangerous</b> and <b>development</b> permissions may be granted or revoked.</string>\n    <string name=\"minimum_version\">Min version: %d</string>\n    <string name=\"added_to_queue\">Added to queue</string>\n    <string name=\"pref_selected_users\">Selected users</string>\n    <string name=\"pref_selected_users_msg\">Restrict App Manager to work with the selected users only.</string>\n    <string name=\"permission_flags\">Permission flags</string>\n    <string name=\"saved_filters\">Saved filters</string>\n    <string name=\"error_with_details\">Error: %s</string>\n    <string name=\"notice\">Notice</string>\n    <string name=\"notice_saf\">Unlike the volumes, the selected directory will be used to store all the files related to App Manager, including saved APKs and backups. Storage Access Framework (SAF) is very slow, therefore, you should only use this option when others cannot be used.</string>\n    <string name=\"backup_volume_dialog_description\">Volumes with <tt>/tree</tt> prefix are folders selected using Storage Access Framework (SAF). Except these folders, the default directory for App Manager is a subfolder named <tt>AppManager</tt>.</string>\n    <string name=\"storage\">Storage</string>\n    <string name=\"files\">Files</string>\n    <string name=\"keystore_password_info\">The following is the App Manager KeyStore password. Please store it in a secure place if you\\'re going to back up/restore App Manager KeyStore. <b>This message will not be displayed again.</b></string>\n    <string name=\"keystore_pass_cannot_be_empty\">KeyStore password cannot be empty.</string>\n    <string name=\"invalid_password\">Invalid password, try again.</string>\n    <string name=\"adb_pair\">Pair</string>\n    <string name=\"paired_successfully\">Paired.</string>\n    <string name=\"identifier\">Identifier</string>\n    <string name=\"set_package_name_first\">Set package name first!</string>\n    <string name=\"paste\">Paste</string>\n    <string name=\"user_root\">Use root</string>\n    <string name=\"trim_caches_in_all_apps\">Trim caches in all apps</string>\n    <string name=\"trim_caches_in_all_apps_description\">Deletes cache files from all applications, including the Android system</string>\n    <string name=\"background\">Background</string>\n    <string name=\"staging_apk_files\">Staging…</string>\n    <string name=\"installer_app_installed\">App installed</string>\n    <string name=\"next\">Next</string>\n    <string name=\"pref_block_trackers_msg\">Block tracking components after installing an app using App Manager.</string>\n    <string name=\"pref_always_on_background\">Install in the background</string>\n    <string name=\"pref_always_on_background_msg\">Always install apps in the background and display a notification when finished.</string>\n    <string name=\"type_uri_array\">Array of URIs</string>\n    <string name=\"type_uri_array_list\">List of URIs</string>\n    <string name=\"pref_thread_count\">Parallel execution</string>\n    <string name=\"pref_thread_count_hint\">The value must be between 0 to %1$d where 0 means <i>maximum number of operations at the given time</i>.</string>\n    <plurals name=\"pref_thread_count_msg\">\n        <item quantity=\"one\">Execute at most %1$d operation in parallel</item>\n        <item quantity=\"other\">Execute at most %1$d operations in parallel</item>\n    </plurals>\n    <string name=\"pid\">Process ID</string>\n    <string name=\"running_services_logcat_hint\">Click on an item to open the log viewer with the corresponding process ID as the default filter.</string>\n    <string name=\"import_from_sb\">Import from Swift Backup 3.0 – 3.2</string>\n    <string name=\"pref_import_backups_hint\">Select a directory containing the backup files (Swift Backup/Titanium Backup) or directories (OAndBackup)</string>\n    <string name=\"java\">Java</string>\n    <string name=\"smali\">Smali</string>\n    <string name=\"accessibility_service_description\">Generic accessibility service to carry out certain operations such as clearing cache in no-root mode.</string>\n    <string name=\"explore\">Explore</string>\n    <string name=\"system_partition\">Android root</string>\n    <string name=\"exit_confirmation\">Exit confirmation</string>\n    <string name=\"extract\">Extract</string>\n    <string name=\"replace\">Replace</string>\n    <string name=\"rename\">Rename</string>\n    <string name=\"intent_firewall_and_disable\">IFW + disable</string>\n    <string name=\"intent_firewall\">IFW</string>\n    <string name=\"pref_default_blocking_method\">Default blocking method</string>\n    <string name=\"pref_default_blocking_method_description\">Method to use by default in places where there is no option to select a blocking method.\\n<b>Note:</b> “IFW” does not work with providers, “disable” is used instead.</string>\n    <string name=\"pref_intent_firewall_and_disable_description\">Block components using Intent Firewall as well as disable them. Recommended method for root users.</string>\n    <string name=\"pref_intent_firewall_description\">Block components using Intent Firewall only. Not recommended as some system apps can bypass firewalls.</string>\n    <string name=\"pref_disable_description\">Disable components only. Not recommended for root users since the apps can bypass this. In ADB modes, the test-only apps can be disabled with this method.</string>\n    <string name=\"authenticating\">Authenticating…</string>\n    <string name=\"search_type_contains\">Contains</string>\n    <string name=\"search_type_prefix\">Prefix</string>\n    <string name=\"search_type_suffix\">Suffix</string>\n    <string name=\"search_type_regular_expressions\">Regex</string>\n    <string name=\"toggle_internet\">Use the Internet</string>\n    <string name=\"pref_toggle_internet_msg\">Activate the Internet features in App Manager</string>\n    <string name=\"vt_checking\">VirusTotal: Checking…</string>\n    <string name=\"vt_uploading\">VirusTotal: Uploading…</string>\n    <string name=\"vt_queued\">VirusTotal: Queued</string>\n    <string name=\"vt_failed\">VirusTotal: Failed</string>\n    <string name=\"vt_success\">VirusTotal: %1$d/%2$d</string>\n    <string name=\"vt_scan_date\">Scan date: %1$s</string>\n    <string name=\"vt_permalink\">Permanent link to VirusTotal</string>\n    <string name=\"vt_slowness_warning\">Depending on the Internet speed and load on the server, this may take a while.</string>\n    <string name=\"vt_disclaimer\">VirusTotal and its logos are a trademark of Chronicle LLC. Neither App Manager—the API client—nor its authors are responsible for any data you may send to VirusTotal.</string>\n    <string name=\"pref_vt_apikey\">VirusTotal API Key</string>\n    <string name=\"pref_vt_apikey_description\">An API key enables App Manager to upload APK files to VirusTotal as well as fetch reports. Sign up at https://virustotal.com to get an API key for free.</string>\n    <string name=\"pref_vt_apikey_summary\">Enable scanning APK files via VirusTotal.</string>\n    <string name=\"uses_play_app_signing\">Play app signing</string>\n    <string name=\"uses_play_app_signing_description\">This app contains certain markers that indicate that it <i>might</i> be using <a href=\"https://support.google.com/googleplay/android-developer/answer/9842756\">Play App Signing</a>. With this scheme, the signing keys are stored in Google\\'s servers, and Google is responsible for signing the app. Note that matching signing information is the only way to verify that the app has not been modified by any person other than the developer (and in this case, Google too).</string>\n    <string name=\"scan_in_vt\">Scan in VirusTotal</string>\n    <string name=\"process_id\">Process ID</string>\n    <string name=\"parent_process_id\">Parent process ID</string>\n    <string name=\"virtual_memory\">Virtual memory</string>\n    <string name=\"cpu_percent\">%% CPU</string>\n    <string name=\"cpu_time\">CPU time</string>\n    <string name=\"priority\">Priority</string>\n    <string name=\"threads\">Thread count</string>\n    <string name=\"state\">Process state</string>\n    <string name=\"commandline_args\">Commandline arguments</string>\n    <string name=\"swap\">Swap</string>\n    <string name=\"memory_chart_info\">● %1$s Applications ● %2$s Cached ● %3$s Buffers ● %4$s Free</string>\n    <string name=\"swap_chart_info\">● %1$s Used ● %2$s Free</string>\n    <string name=\"failed_to_change_app_op_mode\">Could not change the app op mode.</string>\n    <string name=\"failed_to_use_the_current_mode_of_operation\">Unable to use the current mode of operation. Falling back to no-root mode for this session.</string>\n    <string name=\"warning_working_on_root_mode\">Warning: Working on root instead of ADB mode.</string>\n    <string name=\"warning_working_on_system_mode\">Warning: Working on system instead of ADB mode.</string>\n    <string name=\"magisk_denylist\">Magisk DenyList</string>\n    <string name=\"failed_to_enable_magisk_deny_list\">Could not enable Magisk DenyList</string>\n    <string name=\"failed_to_disable_magisk_deny_list\">Could not disable Magisk DenyList</string>\n    <string name=\"mode_of_op_with_inferred_mode_of_op\">%1$s (Inferred mode: %2$s)</string>\n    <string name=\"primary_abi\">Primary ABI</string>\n    <string name=\"zygote_preload_name\">Zygote preload name</string>\n    <string name=\"hidden_api_enforcement_policy\">Hidden API enforcement policy</string>\n    <string name=\"hidden_api_enf_default_policy\">Default (based on application type)</string>\n    <string name=\"hidden_api_enf_policy_none\">None (full-access to the hidden API)</string>\n    <string name=\"hidden_api_enf_policy_warn\">Warn (full-access to the hidden API but issues warnings)</string>\n    <string name=\"hidden_api_enf_policy_dark_grey_and_black\">Enforce (dark-grey and black lists)</string>\n    <string name=\"hidden_api_enf_policy_black\">Enforce (blacklists only)</string>\n    <string name=\"binary_32_bit\">32 Bit</string>\n    <string name=\"binary_64_bit\">64 Bit</string>\n    <string name=\"endianness_little_endian\">Little endian</string>\n    <string name=\"endianness_big_endian\">Big endian</string>\n    <string name=\"so_type_shared_library\">Shared library</string>\n    <string name=\"so_type_executable\">Executable</string>\n    <string name=\"file_modified_are_you_sure\">The file was modified. Discard all your changes and exit?</string>\n    <string name=\"save_and_exit\">Save and exit</string>\n    <string name=\"pref_saved_apk_name_format\">Saved APK name format</string>\n    <string name=\"pref_saved_apk_name_format_msg\">The format to be used for naming the APK files when you save them.</string>\n    <string name=\"auth_manager_description\">To launch an Intent from an external app, it is necessary to supply an extra field called <tt>auth</tt>, and it must contain the following key:</string>\n    <string name=\"auth_manager_title\">Authorization manager</string>\n    <string name=\"regenerate_auth_key\">Regenerate authorization key</string>\n    <string name=\"regenerate_auth_key_warning\">Are you sure? All the third-party apps have to be reconfigured with the new authorization key.</string>\n    <string name=\"shortcut_icon\">Shortcut icon</string>\n    <string name=\"sort_by_installation_date\">Installation date</string>\n    <string name=\"backup_volume_unavailable_warning\">The selected backup volume is not currently available. If it is located in an external storage, please insert it, or change the backup volume.</string>\n    <string name=\"change_backup_volume\">Change volume</string>\n    <string name=\"external\">External</string>\n    <string name=\"internal\">Internal</string>\n    <string name=\"tracker\">Tracker</string>\n    <string name=\"input_ssaid_instruction\">SSAID is a %1$d byte hexadecimal number i.e. a string of length %2$d containing 0 to 9 and a to f.</string>\n    <string name=\"screen_time\">Screen time</string>\n    <string name=\"open_in_new_window\">New window</string>\n    <string name=\"type_string_set\">Set of strings</string>\n    <string name=\"pref_vt_prompt_before_uploading\">Display prompt before uploading a file.</string>\n    <string name=\"vt_confirm_uploading_file\">The file was not found in the VirusTotal database. Do you want to upload it?</string>\n    <string name=\"vt_confirm_upload_and_scan\">Yes, upload and scan</string>\n    <string name=\"log_stop_recording\">Stop recording</string>\n    <string name=\"apk_checksums\">APK checksums</string>\n    <string name=\"item_select\">Select</string>\n    <string name=\"app_explorer\">App explorer</string>\n    <string name=\"netpolicy_cannot_be_modified_for_core_apps\">Net policy cannot be modified for Android core apps.</string>\n    <string name=\"open_developer_options_page\">Open developer options page in Android settings</string>\n    <string name=\"pref_pure_black_theme\">Pure black theme</string>\n    <string name=\"pref_pure_black_theme_msg\">Use a completely black background when night mode is enabled.</string>\n    <string name=\"usage_times_opened\">Times opened</string>\n    <string name=\"usage_last_used\">Last used</string>\n    <string name=\"usage_mobile_data\">Mobile data</string>\n    <string name=\"usage_wifi_data\">Wi-Fi data</string>\n    <string name=\"frozen\">Frozen</string>\n    <string name=\"freeze\">Freeze</string>\n    <string name=\"unfreeze\">Unfreeze</string>\n    <string name=\"backup_no_backups_present\">No backups.</string>\n    <string name=\"restore_dots\">Restore…</string>\n    <string name=\"backup_apps_cannot_be_restored\">The following apps cannot be restored because they do not have a base backup:</string>\n    <string name=\"backup_apps_cannot_be_backed_up\">The following apps are not installed and cannot be backed up:</string>\n    <string name=\"restart_device\">Restart device</string>\n    <string name=\"import_backups_warning_delete_backups_after_import\">Delete the backups after importing them to App Manager? Each backup is individually deleted after it is imported with success. Select <b>No</b> if unsure.</string>\n    <string name=\"troubleshooting\">Troubleshooting</string>\n    <string name=\"pref_reload_apps\">Reload apps</string>\n    <string name=\"pref_reload_apps_msg\">Reload the list of apps stored in App Manager database in case of unexpected behaviour.</string>\n    <string name=\"changelog_type_new\">New</string>\n    <string name=\"changelog_type_fix\">Fix</string>\n    <string name=\"changelog_type_improve\">Improve</string>\n    <string name=\"unsupported_split_apk\">Unsupported</string>\n    <string name=\"view_changelog\">Find out what\\'s new in this release</string>\n    <string name=\"sort_by_total_size\">Total size</string>\n    <string name=\"am_command\"><tt>am</tt> command</string>\n    <string name=\"pref_sign_apk_error_signing_key_not_added\">A valid signing key is required for signing an APK file.</string>\n    <string name=\"pref_sign_apk_no_signing_key\">No signing key</string>\n    <string name=\"failed_to_freeze\">Could not freeze <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g>.</string>\n    <string name=\"failed_to_unfreeze\">Could not unfreeze <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g>.</string>\n    <string name=\"freeze_unfreeze\">Freeze/unfreeze</string>\n    <string name=\"profile_freeze_msg\">Freezes or unfreezes apps based on state</string>\n    <string name=\"pref_default_freezing_method\">Default freezing method</string>\n    <string name=\"pref_default_freezing_method_description\">Method to be used by default in places where there is no option to select a freezing method.</string>\n    <string name=\"suspend_app\">Suspend</string>\n    <string name=\"hide_app\">Hide</string>\n    <plurals name=\"alert_failed_to_freeze\">\n        <item quantity=\"one\">Could not freeze %1$d app</item>\n        <item quantity=\"other\">Could not freeze %1$d apps</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_unfreeze\">\n        <item quantity=\"one\">Could not unfreeze %1$d app</item>\n        <item quantity=\"other\">Could not unfreeze %1$d apps</item>\n    </plurals>\n    <string name=\"suspend_app_description\">This is the weakest freezing method. A suspended app may still appear in the launcher but will be grayed out and cannot be launched.</string>\n    <string name=\"disable_app_description\">Recommended freezing method. It disables the app and along with all its components, but all the shortcuts will be lost.</string>\n    <string name=\"hide_app_description\">This method is only recommended for day to day use. A hidden app appears as if it is uninstalled. But the app could reappear if it is reinstalled or updated.</string>\n    <string name=\"sort_by_frozen_app\">Frozen first</string>\n    <string name=\"filter_frozen_apps\">Frozen apps</string>\n    <string name=\"pref_appearance_description\">Theme, orientation, features, etc.</string>\n    <string name=\"pref_privacy\">Privacy</string>\n    <string name=\"pref_privacy_description\">Screen lock, authorization, etc.</string>\n    <string name=\"user_manual\">User manual</string>\n    <string name=\"get_help\">Get help</string>\n    <string name=\"pref_advanced_pref\">Users, APK name format, parallel execution, etc.</string>\n    <string name=\"pref_version_changelog\">Version/changelog</string>\n    <string name=\"file_creation_date\">Created</string>\n    <string name=\"file_modification_date\">Modified</string>\n    <string name=\"file_accessed_date\">Accessed</string>\n    <string name=\"file_open_with\">Open with</string>\n    <string name=\"file_change_open_with\">Change open with</string>\n    <string name=\"file_shortcut_target_file\">Target file</string>\n    <string name=\"file_properties\">Properties</string>\n    <string name=\"file_cut\">Cut</string>\n    <string name=\"fm_always_open_with\">Always open</string>\n    <string name=\"fm_open_with_for_this_file_only\">Only for this file</string>\n    <string name=\"file_open_as\">Open as…</string>\n    <string name=\"file_open_with_custom_activity\">Custom</string>\n    <string name=\"file_open_with_os_default_dialog\">Open with OS-default dialog</string>\n    <string name=\"open_as_text\">Text</string>\n    <string name=\"open_as_image\">Image</string>\n    <string name=\"open_as_video\">Video</string>\n    <string name=\"open_as_archive\">Archive</string>\n    <string name=\"open_as_folder\">Folder</string>\n    <string name=\"open_as_other\">Other</string>\n    <string name=\"delete_filename\">Delete %s</string>\n    <string name=\"confirm_file_deletion\">Yes, delete</string>\n    <string name=\"on_unfreeze_open_application\">Open app after unfreezing</string>\n    <string name=\"on_open_application_no_recents\">Do not show launched app in Recents</string>\n    <string name=\"freeze_on_phone_locked\">Automatically freeze app when the phone is locked</string>\n    <string name=\"tap_to_freeze_app\">Tap to freeze</string>\n    <string name=\"waiting_for_the_phone_to_be_locked\">Waiting for the phone to be locked…</string>\n    <string name=\"action_stop_service\">Stop</string>\n    <string name=\"app_manager_build_expired\">Update required</string>\n    <string name=\"app_manager_build_expired_message\">To ensure the safety of your device and data, the version of App Manager you\\'re using has been retired. You have to update it to the latest version to continue to use it, or uninstall it if no update is available.</string>\n    <string name=\"app_manager_build_expiring_soon_warning\">This version of App Manager will expire very soon. Please update it to the latest version.</string>\n    <string name=\"app_can_write_and_execute_in_same_place\">The app violates <a href=\"https://en.wikipedia.org/wiki/W%5EX\">W^X policy</a> and is capable of writing and executing in the same directory or in the same portion of memory. This allows the execution of arbitrary executables either by the modification of executables embedded within the app or by downloading them from the Internet. Unless this is the intended behaviour of the app (e.g. terminal emulators), it is recommended to find a newer version of the app that targets SDK 29 (Android 10) and later, or find alternatives.</string>\n    <string name=\"renamed_successfully\">Renamed</string>\n    <string name=\"selinux_context\">SELinux context</string>\n    <string name=\"unix_file_permissions\">Mode</string>\n    <string name=\"file_group_id\">Group (GID)</string>\n    <string name=\"file_owner_id\">Owner (UID)</string>\n    <string name=\"calculating_file_size\">Calculating…</string>\n    <string name=\"sort_by_filename\">Name</string>\n    <string name=\"sort_by_last_modified\">Last modified</string>\n    <string name=\"sort_by_file_size\">File size</string>\n    <string name=\"sort_by_file_type\">File type</string>\n    <string name=\"option_display_dot_files\">Dot files</string>\n    <string name=\"option_display_folders_on_top\">Folders on top</string>\n    <string name=\"export_app_list\">Export app list</string>\n    <string name=\"export_app_list_select_format\">Select format for exporting app list</string>\n    <string name=\"export_option_xml\">XML</string>\n    <string name=\"export_option_markdown\">Markdown</string>\n    <string name=\"funding_campaign_dialog_message\">We\\'re running a <b>funding campaign</b> for App Manager for a limited period. Visit <a href=\"https://opencollective.com/app-manager#category-ABOUT\">opencollective.com/app-manager</a> to learn more about the campaign. This notice will not be displayed again, but you can find it in the Settings page during the entire campaign.</string>\n    <string name=\"funding_campaign_text\">We\\'re running a <b>funding campaign</b> for App Manager for a limited period. <a href=\"https://opencollective.com/app-manager#category-ABOUT\">learn more…</a></string>\n    <string name=\"adb_incomplete_usb_debugging_title\">Incomplete USB debugging</string>\n    <string name=\"adb_incomplete_usb_debugging_message\">It looks like USB debugging is not configured properly. Please read <a href=\"https://muntashirakon.github.io/AppManager/#subsec:enable-usb-debugging\">the documentation</a> for additional steps. If you already know the steps, please click “Open” to open the developer options, or click “Close” to continue to use no-root mode.</string>\n    <string name=\"sort_by_data_usage\">Data usage</string>\n    <string name=\"filter_apps_with_keystore\">With KeyStore</string>\n    <string name=\"filter_apps_with_saf\">With SAF</string>\n    <string name=\"filter_apps_with_ssaid\">With SSAID</string>\n    <string name=\"action_continue\">Continue</string>\n    <string name=\"install_for_another_user\">Install for…</string>\n    <string name=\"confirm_uninstallation\">Confirm uninstallation</string>\n    <string name=\"grant_required_permission\">Grant required permission</string>\n    <string name=\"grant_overlay_permission_message\">Allow App Manager to display a floating window on top of all other windows</string>\n    <string name=\"grant_accessibility_permission_for_tracking_window_contents\">Allow App Manager to utilise the accessibility feature to track the contents of the leading window.</string>\n    <string name=\"class_hierarchy\">Hierarchy</string>\n    <string name=\"title_ui_tracker\">UI tracker</string>\n    <string name=\"title_terminal_emulator\">Terminal</string>\n    <string name=\"title_labs_activity\">Labs</string>\n    <string name=\"select_a_dex2oat_compiler_filter\"><tt>dex2oat</tt> compiler filter</string>\n    <string name=\"optimize_option_compile_layouts\">Compile layout resources</string>\n    <string name=\"optimize_option_clear_profile_data\">Clear previous profile data</string>\n    <string name=\"optimize_option_check_profiles\">Consider profile data during DEX optimization</string>\n    <string name=\"optimize_option_force_compilation\">Force compilation even when not required</string>\n    <string name=\"optimize_option_force_dexopt\">Immediately perform DEX optimization</string>\n    <string name=\"title_perform_runtime_optimization_to_apps\">Perform runtime optimization</string>\n    <string name=\"action_run\">Run</string>\n    <string name=\"summary_perform_runtime_optimization_to_apps\">Optimize DEX and (in Android 10 and later) layouts to improve the performance of the applications.</string>\n    <string name=\"action_optimize_app\">Optimize</string>\n    <string name=\"batch_ops_runtime_optimization\">Runtime optimization</string>\n    <string name=\"app_info_tag_open_links\">Open links</string>\n    <string name=\"title_domains_supported_by_the_app\">Supported domains</string>\n    <string name=\"pref_zip_align\">Align APK files</string>\n    <string name=\"pref_zip_align_msg\">Aligning an APK file reduces its memory usage as the files in the APK can be accessed directly without copying the data to RAM. This step is required if <tt>extractNativeLibs</tt> is set to <tt>true</tt>.</string>\n    <plurals name=\"alert_failed_to_optimize_apps\">\n        <item quantity=\"one\">Could not optimize %1$d app</item>\n        <item quantity=\"other\">Could not optimize %1$d apps</item>\n    </plurals>\n    <string name=\"title_code_editor\">Code editor</string>\n    <string name=\"redo\">Redo</string>\n    <string name=\"read_only_file\">Read only file</string>\n    <string name=\"read_only_file_warning\">The changes cannot be written into the file, possibly because it is located in a volume that App Manager has no permission to write to. Do you want to save it in a different place?</string>\n    <string name=\"line_separator\">Line separator</string>\n    <plurals name=\"search_results\">\n        <item quantity=\"one\">%d result</item>\n        <item quantity=\"other\">%d results</item>\n    </plurals>\n    <string name=\"replacement_text\">Replacement</string>\n    <string name=\"action_replace_all\">Replace all</string>\n    <string name=\"search_option_match_case\">Match case</string>\n    <string name=\"search_option_whole_word\">Whole word</string>\n    <string name=\"search_option_regex\">Regex</string>\n    <string name=\"uninstall_app_again_message\">The application was uninstalled without clearing data and signature. Do you want to completely uninstall it?</string>\n    <string name=\"uninstall_app\">Uninstall %1$s</string>\n    <string name=\"debloat_list_type\">List</string>\n    <string name=\"debloat_removal_type\">Type</string>\n    <string name=\"system_app_put_back\">Put back</string>\n    <string name=\"debloater_title\">Debloater</string>\n    <string name=\"debloat_list_aosp\">AOSP</string>\n    <string name=\"debloat_list_oem\">OEM</string>\n    <string name=\"debloat_list_carrier\">Carrier/ISP</string>\n    <string name=\"debloat_list_google\">Google</string>\n    <string name=\"debloat_list_misc\">Miscellany</string>\n    <string name=\"debloat_removal_safe\">Safe</string>\n    <string name=\"debloat_removal_replace\">Replace</string>\n    <string name=\"debloat_removal_caution\">Caution</string>\n    <string name=\"static_shared_library\">Static shared library</string>\n    <string name=\"empty_folder\">Empty</string>\n    <plurals name=\"folder_count\">\n        <item quantity=\"one\">%d folder</item>\n        <item quantity=\"other\">%d folders</item>\n    </plurals>\n    <plurals name=\"file_count\">\n        <item quantity=\"one\">%d file</item>\n        <item quantity=\"other\">%d files</item>\n    </plurals>\n    <string name=\"go_to_path\">Go to…</string>\n    <string name=\"copy_this_path\">Copy path</string>\n    <string name=\"title_audio_player\">Audio player</string>\n    <string name=\"filter_force_stopped_apps\">Stopped apps</string>\n    <string name=\"installing_package\">Installing %1$s…</string>\n    <string name=\"backing_up_app\">Backing up %1$s…</string>\n    <string name=\"restoring_app\">Restoring %1$s…</string>\n    <string name=\"pref_installer_force_dexopt_description\">Perform DEX optimization immediately after installing the app without waiting for the system to do it when the system is idle.</string>\n    <string name=\"folder\">Folder</string>\n    <string name=\"symbolic_link\">Symbolic link</string>\n    <string name=\"create_new_symbolic_link\">New symbolic link</string>\n    <string name=\"symbolic_link_not_supported\">This folder does not support creating a symbolic link.</string>\n    <string name=\"create_new_folder\">New folder</string>\n    <string name=\"create_new_file\">New file</string>\n    <string name=\"enter_symbolic_link_name\">Link name</string>\n    <string name=\"enter_target_path\">Target path</string>\n    <string name=\"invalid_target_path\">Invalid path</string>\n    <string name=\"copy_these_paths\">Copy paths</string>\n    <string name=\"title_confirm_deletion\">Confirm deletion</string>\n    <string name=\"conflict_detected_while_copying\">Conflict detected</string>\n    <string name=\"conflict_detected_while_copying_message\">An item named “%1$s” already exists in this location. Do you want to replace it?</string>\n    <string name=\"copy_keep_both_file\">Keep both</string>\n    <string name=\"copied_successfully\">Copied.</string>\n    <string name=\"moved_successfully\">Moved</string>\n    <string name=\"failed_to_copy_specified_file\">Could not copy “%1$s”.</string>\n    <string name=\"failed_to_delete_specified_file_after_copying\">Could not delete “%1$s” after copying it, possibly due to not enough permission.</string>\n    <string name=\"title_change_selinux_context\">Change SELinux context</string>\n    <string name=\"apply_recursively\">Apply to enclosed files</string>\n    <string name=\"change_owner_uid\">Change owner (UID)</string>\n    <string name=\"change_group_gid\">Change group (GID)</string>\n    <string name=\"change_mode\">Change mode</string>\n    <string name=\"pref_send_notifications_to_connected_devices\">Send notifications to the connected devices</string>\n    <string name=\"pref_send_notification_to_connected_devices_msg\">Set whether to send notifications to connected devices such as wearables.</string>\n    <string name=\"installer_options\">Installer options</string>\n    <string name=\"debloat_removal_safe_short_description\">Safe to remove</string>\n    <string name=\"debloat_removal_caution_short_description\">Exercise caution</string>\n    <string name=\"debloat_removal_replace_short_description\">Replace with alternative</string>\n    <string name=\"title_alternatives_to_bloatware\">Alternatives</string>\n    <string name=\"browse_files\">Browse</string>\n    <string name=\"pref_files_msg\">Configure file manager.</string>\n    <string name=\"pref_files_display_in_launcher\">Display “Files” in app drawer</string>\n    <string name=\"pref_files_remember_last_path\">Remember last opened path and its position</string>\n    <string name=\"pref_files_remember_last_path_msg\">When this option is enabled, opening a new window opens the last opened folder instead of the home folder.</string>\n    <string name=\"pref_set_home\">Set home</string>\n    <string name=\"xposed_module_info\">Xposed module info</string>\n    <string name=\"title_description\">Description</string>\n    <string name=\"module_name\">Module name</string>\n    <string name=\"app_manager_is_running\">App Manager is running</string>\n    <string name=\"tap_to_open_notification_settings\">Tap to hide</string>\n    <string name=\"app_manager_is_unlocked\">App Manager is unlocked</string>\n    <string name=\"action_lock_app\">Lock</string>\n    <string name=\"pref_enable_persistent_session\">Run App Manager in the background</string>\n    <string name=\"pref_enable_persistent_session_msg\">Running App Manager in the background reduces initialisation delay. Useful if you use App Manager frequently.</string>\n    <string name=\"pref_enable_auto_lock\">Automatic lockdown</string>\n    <string name=\"pref_enable_auto_lock_msg\">Lock App Manager when the device is locked.</string>\n    <string name=\"path_does_not_exist\">“%1$s” does not exist</string>\n    <string name=\"path_not_a_folder\">“%1$s” is not a folder</string>\n    <string name=\"scan_report_from_pithus\">Pithus report</string>\n    <string name=\"action_checking\">Checking…</string>\n    <string name=\"report_not_available\">Not available</string>\n    <string name=\"profile_modified_are_you_sure\">The profile was modified. Discard all your changes and exit?</string>\n    <string name=\"apply_profile\">Apply profile “%1$s”</string>\n    <string name=\"choose_a_profile_state\">Select a profile state</string>\n    <string name=\"profile_id\">Profile ID</string>\n    <string name=\"copy_profile_id\">Copy profile ID</string>\n    <string name=\"launch_activity_dialog_title\">Launch activity: action required</string>\n    <string name=\"launch_activity_dialog_message\">App Manager is trying to launch the activity via <b>Search assistant</b> (usually Google Assistant), but it\\'s unable to do so due to insufficient permission. To open the activity, please activate <b>Search assistant</b> manually (which is usually done by long clicking on the Home button). Click on the <b>Close</b> button after you\\'ve finished launching the activity to revert back to the original assistant.</string>\n    <string name=\"finder_title\">Finder</string>\n    <string name=\"select_filter\">Select a filter</string>\n    <string name=\"size_in_bytes\">Size (bytes)</string>\n    <string name=\"invalid_regex\">Invalid regular expression!</string>\n    <string name=\"value_cannot_be_empty\">Value cannot be empty!</string>\n    <string name=\"date\">Date</string>\n    <string name=\"pref_use_vt\">Use VirusTotal</string>\n    <string name=\"virus_total\">VirusTotal</string>\n    <string name=\"pref_use_vt_no_internet\">VirusTotal requires the Internet to operate which isn\\'t enabled. Please enable <a href=\"app-manager://settings/privacy_prefs/toggle_internet\">“Use the Internet”</a> first.</string>\n    <string name=\"pref_use_log_viewer\">Use log viewer</string>\n    <string name=\"pref_installer\">Use the installer</string>\n    <string name=\"pref_cat_general\">General</string>\n    <string name=\"status_remote_server_active\">Remote server is active</string>\n    <string name=\"status_remote_server_inactive\">Remote server is inactive</string>\n    <string name=\"status_remote_services_active\">Remote services are active</string>\n    <string name=\"status_remote_services_inactive\">Remote services are inactive</string>\n    <string name=\"status_connecting\">Connecting…</string>\n    <string name=\"status_connecting_via_mode\">Connecting via %s</string>\n    <string name=\"status_connected_via_mode\">Connected via %s</string>\n    <string name=\"status_not_connected_via_mode\">Could not connect via %s</string>\n    <string name=\"adb_pairing_instruction\">Please navigate to the developer options to enable wireless debugging and generate a pairing code. Click <b>Manual</b> if you\\'ve already opened the developer options.</string>\n    <string name=\"adb_pairing_searching_for_port\">Searching…</string>\n    <string name=\"adb_pairing_stop_searching\">Stop</string>\n    <string name=\"adb_pairing_input_pairing_code\">Pairing code</string>\n    <string name=\"adb_pairing_pairing_code\">Pairing code</string>\n    <string name=\"adb_pairing_found_pairing_service_with_port\">Found a service with port %d</string>\n    <string name=\"adb_pairing_pairing_in_progress\">Pairing…</string>\n    <string name=\"adb_pairing_retry_pairing\">Retry</string>\n    <string name=\"mode_of_op_custom_command_title\">Custom command</string>\n    <string name=\"mode_of_op_custom_command\">If you are unable to use any of the modes, you can run the following command in any supported shell to run App Manager in privileged mode:</string>\n    <string name=\"mode_of_op_alternative_custom_command\">If you get a “permission denied” error with the above command, run the following command instead:</string>\n    <string name=\"sensors\">Sensors</string>\n    <string name=\"tag_sensors_disabled\">Sensors disabled</string>\n    <string name=\"pref_use_system_font\">Use system font</string>\n    <string name=\"pref_use_system_font_msg\">Use the system-default font instead of the material font. <font fgcolor=\"#ff0000\">This is an experimental feature.</font></string>\n    <string name=\"actual_installer\">Actual installer</string>\n    <string name=\"apk_source\">APK source</string>\n    <string name=\"backup_cache\">Cache</string>\n    <string name=\"activity_name\">Activity name</string>\n    <string name=\"available_memory\">Available: %s</string>\n    <string name=\"action_manual\">Manual</string>\n    <string name=\"vulkan_version\">Vulkan version</string>\n    <string name=\"battery_technology\">Technology</string>\n    <string name=\"battery_health\">Health</string>\n    <string name=\"verified_boot\">Verified boot</string>\n    <string name=\"android_verified_bootloader_version\">AVB version</string>\n    <string name=\"op_history\">History</string>\n    <string name=\"no_history\">No history</string>\n    <string name=\"title_confirm_execution\">Confirm execution</string>\n    <string name=\"clear_history\">Clear history</string>\n    <string name=\"favorites\">Favorites</string>\n    <string name=\"add_to_favorites\">Add to favorites</string>\n    <string name=\"item_remove\">Remove</string>\n    <string name=\"item_edit\">Edit</string>\n    <string name=\"remove_filename\">Remove %s</string>\n    <string name=\"advanced_suspend_app\">Advanced suspend</string>\n    <string name=\"advanced_suspend_app_description\">It force-stops and suspends the app to ensure that the app is not running in the background. This method should be preferred over the regular <b>suspend</b> method.</string>\n    <string name=\"freeze_prefer_per_app_option\">Prefer per app option</string>\n    <string name=\"remember_option_for_this_app\">Remember for this app</string>\n    <string name=\"no_overlay_permission\">No permission to display overlays</string>\n    <string name=\"overlay_category\">Category</string>\n    <string name=\"overlay_target\">Target</string>\n    <string name=\"overlay_sdk_version_too_low\">Overlays are not supported.</string>\n    <string name=\"no_overlays\">No overlays</string>\n    <string name=\"sort_by_overlay_names\">Overlay name</string>\n    <string name=\"sort_by_priority\">Priority</string>\n    <string name=\"overlays\">Overlays</string>\n    <string name=\"title_overlay\">Overlay</string>\n    <string name=\"title_shortcut_for_frozen_app\">Frozen app</string>\n    <string name=\"message_shortcut_for_frozen_app\">The app corresponding to the shortcut appears to have been frozen. Unfreeze temporarily and open the shortcut?</string>\n    <string name=\"filters\">Filters</string>\n    <string name=\"icon\">icon</string>\n    <string name=\"preview\">Preview</string>\n    <string name=\"debloat_removal_unsafe\">Unsafe</string>\n    <string name=\"sort_by_cpu_time\">CPU time</string>\n    <string name=\"pref_request_update_ownership\">Request \\\"update ownership\\\"</string>\n    <string name=\"pref_default_package_source\">Default package source</string>\n    <string name=\"pref_set_origin\">Set package origin and URI</string>\n    <string name=\"pref_request_update_ownership_description\">Set the installer app as the \\\"update owner\\\" during the initial installation to prevent other installers from installing the app without user interaction.</string>\n    <string name=\"pref_set_origin_description\">Record the origin or source of the app to be installed, reported by \\\"APK source\\\" in the App Info tab</string>\n    <string name=\"package_source_store\">App store</string>\n    <string name=\"package_source_local_file\">Local file</string>\n    <string name=\"package_source_downloaded_file\">Downloaded file</string>\n    <string name=\"package_source_other\">Other</string>\n    <string name=\"pref_disable_apk_verification\">Disable package verification</string>\n    <string name=\"pref_disable_apk_verification_description\">Ask the installer to skip running the package verifier (e.g., Play Protect) during the installation.</string>\n    <string name=\"adb_data\">ADB data</string>\n    <string name=\"adb_data_description\">Back up data in ADB format. This option supersedes \\\"Internal data\\\" and \\\"External data\\\" options.</string>\n    <string name=\"filter_unfrozen_apps\">Unfrozen apps</string>\n    <string name=\"goto_previous\">Previous</string>\n    <string name=\"usage_this_week\">This week</string>\n    <string name=\"usage_last_week\">Last week</string>\n    <string name=\"bar_chart_content_description\">Bar chart with %d data points.</string>\n    <string name=\"usage_daily_bar_chart_accessibility_description\">Usage at %1$s is %2$.0f minutes. Bar %3$d of %4$d</string>\n    <string name=\"usage_weekly_hours_bar_chart_accessibility_description\">Usage on %1$s is %2$.lf hours. Bar %3$d of %4$d</string>\n    <string name=\"usage_weekly_minutes_bar_chart_accessibility_description\">Usage on %1$s is %2$.0f minutes. Bar %3$d of %4$d</string>\n    <string name=\"usage_bar_chart_y_axis_label_minute\">%.0f min</string>\n    <string name=\"usage_bar_chart_y_axis_label_hour\">%.0f hr</string>\n    <string name=\"usage_bar_chart_tooltip_minutes\">%1$s • %2$.0f minutes</string>\n    <string name=\"usage_bar_chart_tooltip_hours\">%1$s • %2$.1f hours</string>\n    <string name=\"modify_last_modification_time\">Modify last modification time</string>\n    <string name=\"modify_last_access_time\">Modify last access time</string>\n    <string name=\"change_id\">Change ID</string>\n    <string name=\"memory_usage_accessibility_description\">The system is currently using %s memory out of %s, and the amount of available memory is %s. Among the occupied memory, the applications are using %s, %s are cached, and %s are used as memory buffers.</string>\n    <string name=\"memory_usage_unavailable\">Memory usage is unavailable right now.</string>\n    <string name=\"swap_usage_accessibility_description\">The system has allocated %s for swap and currently using %s.</string>\n    <string name=\"selected_items_accessibility_description\">Selected %d out of %d items</string>\n    <string name=\"adb_local_server_port\">ADB local server port</string>\n    <string name=\"waiting_for_wifi\">Waiting for Wi-Fi</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values/styles.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<resources>\n\n    <style name=\"AppTheme.Splash\" parent=\"Theme.SplashScreen\">\n        <item name=\"windowSplashScreenBackground\">?attr/colorSurface</item>\n        <item name=\"windowSplashScreenAnimatedIcon\">@drawable/ic_splash_logo</item>\n        <item name=\"postSplashScreenTheme\">@style/AppTheme</item>\n    </style>\n\n    <style name=\"AppTheme.Splash.Black\" parent=\"AppTheme.Splash\">\n        <item name=\"postSplashScreenTheme\">@style/AppTheme.Black</item>\n    </style>\n\n    <style name=\"AppTheme.AppWidgetContainerParent\" parent=\"AppTheme\">\n        <item name=\"appWidgetRadius\">24dp</item>\n        <item name=\"appWidgetPadding\">16dp</item>\n        <item name=\"appWidgetInnerRadius\">4dp</item>\n    </style>\n\n    <style name=\"AppTheme.AppWidgetContainer\" parent=\"AppTheme.AppWidgetContainerParent\" />\n\n    <style name=\"AppTheme.AppWidgetContainer.IconOnly\" parent=\"AppTheme.AppWidgetContainerParent\">\n        <item name=\"appWidgetPadding\">8dp</item>\n        <item name=\"appWidgetRadius\">8dp</item>\n    </style>\n\n    <style name=\"Widget.AppTheme.AppWidgetOverlay\" parent=\"android:Widget\">\n        <item name=\"android:id\">@android:id/background</item>\n        <item name=\"android:background\">?android:attr/colorBackground</item>\n        <item name=\"android:padding\">?attr/appWidgetPadding</item>\n    </style>\n\n    <style name=\"Widget.AppTheme.AppWidget\" parent=\"Widget.AppTheme.AppWidgetOverlay\" />\n\n    <style name=\"Widget.AppTheme.BarChartView\" parent=\"android:Widget\">\n        <!-- Bar appearance -->\n        <item name=\"barColor\">?attr/colorPrimaryContainer</item>\n        <item name=\"selectedBarColor\">?attr/colorPrimary</item>\n        <item name=\"minBarWidth\">8dp</item>\n        <item name=\"maxBarWidth\">24dp</item>\n        <item name=\"valueOnTopOfBar\">false</item>\n\n        <!-- Grid appearance -->\n        <item name=\"gridColor\">?attr/colorOutline</item>\n        <item name=\"gridStrokeWidth\">1dp</item>\n        <item name=\"gridLineCount\">6</item>\n        <item name=\"gridLabelsOnLeft\">true</item>\n\n        <!-- Label appearance -->\n        <item name=\"textColor\">?attr/colorOutline</item>\n        <item name=\"textSize\">@dimen/font_size_medium</item>\n        <item name=\"yAxisFormat\">@null</item>\n        <item name=\"emptyText\">@string/no_usage_in_this_time_range</item>\n\n        <!-- Touch line appearance -->\n        <item name=\"touchLineColor\">?attr/colorOutline</item>\n        <item name=\"touchLineWidth\">2dp</item>\n\n        <!-- Tooltip appearance -->\n        <item name=\"tooltipBackgroundColor\">?attr/colorSurfaceInverse</item>\n        <item name=\"tooltipTextColor\">?attr/colorOnSurfaceInverse</item>\n        <item name=\"tooltipCornerRadius\">6dp</item>\n    </style>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values/trackers.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<resources>\n    <string-array name=\"tracker_signatures\">\n        <item>com.threesixtydialog.sdk.</item>\n        <item>com.abtasty</item>\n        <item>com.acrcloud</item>\n        <item>com.adxcorp.ads</item>\n        <item>com.adxcorp.nativead</item>\n        <item>com.mocoplex.adlib.</item>\n        <item>com.amoad.</item>\n        <item>com.atinternet.</item>\n        <item>com.aarki</item>\n        <item>com.facebook.accountkit</item>\n        <item>me.actv8</item>\n        <item>com.acuant.acuantcamera</item>\n        <item>com.socdm.d.adgeneration.</item>\n        <item>com.ad4screen.sdk</item>\n        <item>com.adadapted.android.sdk.</item>\n        <item>com.purplebrain.adbuddiz.sdk.</item>\n        <item>com.adcolony.</item>\n        <item>com.jirbo.adcolony.</item>\n        <item>com.noqoush.adfalcon.android.sdk</item>\n        <item>com.kakao.adfit.</item>\n        <item>com.adform.sdk.</item>\n        <item>com.adgatemedia.</item>\n        <item>com.adgem.android.</item>\n        <item>com.adlocus.</item>\n        <item>com.admarvel.</item>\n        <item>com.admuing.danmaku.</item>\n        <item>com.aiming.mdt.</item>\n        <item>com.adtiming.</item>\n        <item>com.adtrial.sdk.</item>\n        <item>com.igaworks.adbrix</item>\n        <item>com.adcash.mobileads.</item>\n        <item>com.adcenix.</item>\n        <item>com.intentsoftware.addapptr.</item>\n        <item>jp.tjkapp.adfurikunsdk.</item>\n        <item>com.glossomads.sdk.</item>\n        <item>com.adincube.sdk.</item>\n        <item>io.adjoe.sdk.</item>\n        <item>io.adjoe.protection.</item>\n        <item>com.adjust.sdk.</item>\n        <item>com.adjust.android.sdk.</item>\n        <item>com.unbotify.mobile.sdk.</item>\n        <item>ru.tachos.admitadstatisticsdk</item>\n        <item>com.admixer</item>\n        <item>net.admixer.sdk</item>\n        <item>admost.sdk.</item>\n        <item>admost.adserver.</item>\n        <item>com.adobe.marketing.mobile</item>\n        <item>com.adotmob</item>\n        <item>.adswizz.</item>\n        <item>com.aerserv.sdk.</item>\n        <item>com.airpush.</item>\n        <item>com.akamai.android.sdk.AkaMap</item>\n        <item>com.adsmogo.</item>\n        <item>com.alimama.</item>\n        <item>org.alohalytics.</item>\n        <item>com.github.aloomaio.androidsdk</item>\n        <item>tv.alphonso.service</item>\n        <item>org.altbeacon.beacon.</item>\n        <item>com.altbeacon.beacon.</item>\n        <item>org.altbeacon.bluetooth.</item>\n        <item>com.altamob.sdk</item>\n        <item>com.amap.api</item>\n        <item>com.amazon.device.ads</item>\n        <item>com.amazon.insights</item>\n        <item>com.amazonaws.mobileconnectors.pinpoint.analytics.</item>\n        <item>com.amazonaws.mobileconnectors.amazonmobileanalytics</item>\n        <item>com.amplifyframework.analytics.</item>\n        <item>com.amazon.device.associates</item>\n        <item>com.amobee.</item>\n        <item>com.amplitude.</item>\n        <item>com.anagog.jedai</item>\n        <item>com.npaw.youbora.</item>\n        <item>com.anvato.androidsdk.</item>\n        <item>com.anysdk.framework.AnalyticsWrapper</item>\n        <item>com.anysdk.framework.AdsWrapper</item>\n        <item>io.appanalytics.sdk</item>\n        <item>com.appbrain.</item>\n        <item>com.applovin</item>\n        <item>com.yandex.metrica.</item>\n        <item>com.monet.</item>\n        <item>com.appnexus.opensdk.</item>\n        <item>com.appsee.</item>\n        <item>com.appvador.ads.</item>\n        <item>com.appcelerator.aps.</item>\n        <item>org.appcelerator.titanium.analytics</item>\n        <item>com.appdynamics.</item>\n        <item>com.applause.android.</item>\n        <item>com.appnext.sdk</item>\n        <item>com.appodeal.ads.</item>\n        <item>com.appodealx.</item>\n        <item>com.explorestack.</item>\n        <item>com.appsflyer.</item>\n        <item>com.appsgeyser.sdk</item>\n        <item>com.appsgeyser.multiTabApp.VideoPlayerActivity</item>\n        <item>com.apptentive.</item>\n        <item>com.apptimize.</item>\n        <item>com.apsalar.sdk.</item>\n        <item>com.crittercism.app.Crittercism</item>\n        <item>com.areametrics.areametricssdk</item>\n        <item>com.areametrics.nosdkandroid</item>\n        <item>com.krux.androidsdk</item>\n        <item>com.auditude.ads</item>\n        <item>com.axonix.android.sdk</item>\n        <item>com.mobclix.android.sdk</item>\n        <item>com.backelite.android.</item>\n        <item>com.backelite.bkdroid.</item>\n        <item>com.baidu.appx</item>\n        <item>com.baidu.location</item>\n        <item>com.baidu.mapapi</item>\n        <item>com.baidu.BaiduMap</item>\n        <item>com.baidu.mobads</item>\n        <item>com.baidu.mobstat</item>\n        <item>com.baidu.navi</item>\n        <item>com.batch.android.</item>\n        <item>com.bazaarvoice.bvandroidsdk</item>\n        <item>com.beaconsinspace.android.beacon.detector.</item>\n        <item>com.beintoo.nucleon</item>\n        <item>io.bidmachine.</item>\n        <item>com.bitly.Bitly</item>\n        <item>com.blesh.sdk.</item>\n        <item>com.blueconic</item>\n        <item>com.bluekai.sdk.</item>\n        <item>com.bluecats.sdk</item>\n        <item>com.parse.bolts</item>\n        <item>io.branch.</item>\n        <item>com.appboy</item>\n        <item>com.brightcove</item>\n        <item>com.bugsense.trace.</item>\n        <item>com.bugfender.sdk.</item>\n        <item>com.tencent.bugly.</item>\n        <item>com.bugsee.library.Bugsee</item>\n        <item>com.bugsnag.</item>\n        <item>com.usebutton.sdk.</item>\n        <item>com.buzzvil.</item>\n        <item>com.calldorado.android</item>\n        <item>com.carnival.sdk</item>\n        <item>com.carnivalmobile</item>\n        <item>com.nutiteq</item>\n        <item>com.carto</item>\n        <item>com.fsn.cauly</item>\n        <item>com.trid.tridad</item>\n        <item>com.cauly.android.ad.</item>\n        <item>com.cedexis</item>\n        <item>com.chartboost.sdk.</item>\n        <item>com.chartbeat.androidsdk</item>\n        <item>com.cmcm.</item>\n        <item>com.cifrasoft.</item>\n        <item>com.clevertap.</item>\n        <item>com.cloudtech.</item>\n        <item>net.crowdconnected.androidcolocator</item>\n        <item>com.comscore.</item>\n        <item>com.conversantmedia</item>\n        <item>com.greystripe.android.</item>\n        <item>com.conviva.</item>\n        <item>com.cooladata.android.</item>\n        <item>coelib.c.couluslibrary</item>\n        <item>ly.count.android.</item>\n        <item>io.fabric.</item>\n        <item>com.crashlytics.</item>\n        <item>com.google.firebase.crashlytics</item>\n        <item>com.google.firebase.crash.</item>\n        <item>io.invertase.firebase.crashlytics.</item>\n        <item>com.criteo.</item>\n        <item>com.cuebiq.cuebiqsdk.model.Collector</item>\n        <item>com.cuebiq.cuebiqsdk.receiver.CoverageReceiver</item>\n        <item>com.dv.DVSDK</item>\n        <item>com.adobe.mobile.Analytics</item>\n        <item>com.adobe.mobile.Config.</item>\n        <item>io.didomi.sdk.</item>\n        <item>io.display.</item>\n        <item>com.duapps.</item>\n        <item>com.dynamicyield.</item>\n        <item>com.dynatrace.android.app</item>\n        <item>com.dynatrace.agent</item>\n        <item>com.dynatrace.tools</item>\n        <item>com.emarsys.predict</item>\n        <item>co.enhance.Enhance</item>\n        <item>com.ensighten.</item>\n        <item>com.esri.arcgisruntime.</item>\n        <item>com.estimote.</item>\n        <item>com.eulerian.android.sdk</item>\n        <item>com.exacttarget.</item>\n        <item>com.infinario.android.infinariosdk.</item>\n        <item>com.exponea.sdk</item>\n        <item>com.sygic.aura.</item>\n        <item>com.fluzo.sdk.</item>\n        <item>com.facebook.ads</item>\n        <item>com.facebook.appevents</item>\n        <item>com.facebook.marketing.</item>\n        <item>com.facebook.CampaignTrackingReceiver</item>\n        <item>com.facebook.audiencenetwork</item>\n        <item>com.facebook.flipper</item>\n        <item>com.facebook.login</item>\n        <item>com.facebook.notifications</item>\n        <item>com.facebook.places</item>\n        <item>com.facebook.share</item>\n        <item>com.factual.engine</item>\n        <item>com.factual.Factual</item>\n        <item>com.fidzup.</item>\n        <item>com.fiksu.asotracking</item>\n        <item>com.google.firebase.analytics.</item>\n        <item>com.google.android.gms.measurement.</item>\n        <item>com.google.firebase.firebase_analytics</item>\n        <item>com.flowsense.flowsensesdk.</item>\n        <item>com.flurry.</item>\n        <item>com.followanalytics.</item>\n        <item>com.footmarks.footmarkssdkm2</item>\n        <item>tv.freewheel.ad.</item>\n        <item>com.fyber.</item>\n        <item>com.sponsorpay</item>\n        <item>com.giphy.sdk.analytics</item>\n        <item>com.giphy.sdk.tracking</item>\n        <item>com.gomfactory.adpie.</item>\n        <item>com.gpshopper</item>\n        <item>com.gameanalytics.sdk</item>\n        <item>com.gemius.sdk</item>\n        <item>jp.co.geniee.gnadsdk.</item>\n        <item>com.gigya.</item>\n        <item>com.gimbal.android</item>\n        <item>com.avocarrot.sdk</item>\n        <item>com.glympse.android.</item>\n        <item>com.google.ads.</item>\n        <item>com.google.android.gms.ads.AdView</item>\n        <item>com.google.android.gms.ads.AdActivity</item>\n        <item>com.google.android.gms.ads.AdRequest</item>\n        <item>com.google.android.gms.ads.mediation</item>\n        <item>com.google.android.gms.ads.doubleclick</item>\n        <item>com.google.android.ads.</item>\n        <item>com.google.unity.ads.</item>\n        <item>com.google.android.gms.admob</item>\n        <item>com.google.firebase.firebase_ads.</item>\n        <item>com.google.android.apps.analytics.</item>\n        <item>com.google.android.gms.analytics.</item>\n        <item>com.google.analytics.</item>\n        <item>com.danielcwilson.plugins.analytics</item>\n        <item>com.google.tagmanager</item>\n        <item>com.google.android.gms.tagmanager</item>\n        <item>com.heapanalytics</item>\n        <item>com.helpshift</item>\n        <item>com.connecthings.herow</item>\n        <item>com.heyzap.sdk.ads.</item>\n        <item>com.heyzap.mediation.</item>\n        <item>net.hockeyapp.</item>\n        <item>com.hound</item>\n        <item>com.huawei.hms.analytics</item>\n        <item>com.huawei.hms.location</item>\n        <item>com.huawei.hms.plugin.analytics</item>\n        <item>com.huawei.hms.plugin.ads</item>\n        <item>com.huawei.updatesdk.</item>\n        <item>com.huawei.agconnect.</item>\n        <item>com.huawei.hms.support.api.push.</item>\n        <item>com.huawei.hms.flutter.analytics.</item>\n        <item>io.huq.sourcekit.</item>\n        <item>com.hypertrack</item>\n        <item>com.hypertracklive.</item>\n        <item>io.hypertrack</item>\n        <item>com.hyprmx.android.sdk.</item>\n        <item>com.iab.omid.library</item>\n        <item>com.prime31.util.IabHelperImpl</item>\n        <item>com.prime31.IAB.</item>\n        <item>com.digitalanalytics.</item>\n        <item>com.ibm.mce.sdk.</item>\n        <item>co.acoustic.mobile.push.sdk.</item>\n        <item>com.xtify.mce.sdk.</item>\n        <item>com.xtify.android.sdk.</item>\n        <item>de.infonline.</item>\n        <item>com.ipqualityscore.</item>\n        <item>com.iqzone</item>\n        <item>com.inlocomedia.android</item>\n        <item>com.inmarket</item>\n        <item>com.inmobi</item>\n        <item>in.inmobi.</item>\n        <item>com.indooratlas.android.sdk</item>\n        <item>com.inneractive.api.ads</item>\n        <item>com.inrix.sdk</item>\n        <item>com.useinsider.insider</item>\n        <item>com.instabug.</item>\n        <item>com.instreamatic</item>\n        <item>com.integralads.avid.library</item>\n        <item>com.longtailvideo.jwplayer.</item>\n        <item>com.janrain.android</item>\n        <item>com.janrain.android.engage</item>\n        <item>com.janrain.android.capture</item>\n        <item>cn.jpush.android</item>\n        <item>com.jumio.MobileSDK</item>\n        <item>com.jumptap.adtag.</item>\n        <item>com.kidoz.sdk</item>\n        <item>com.kissmetrics</item>\n        <item>io.keen.client.</item>\n        <item>me.kiip.sdk</item>\n        <item>com.kochava.base.</item>\n        <item>com.kochava.android.tracker.</item>\n        <item>.kochavaccpa.</item>\n        <item>com.kontakt.sdk.android.</item>\n        <item>com.leanplum.</item>\n        <item>com.lenddo.mobile</item>\n        <item>.LigatusManager</item>\n        <item>.LigatusViewClient</item>\n        <item>com.ligatus.android.adframework</item>\n        <item>com.lisnr.</item>\n        <item>com.localytics.android.</item>\n        <item>com.localytics.androidx</item>\n        <item>com.localytics.react.</item>\n        <item>com.locuslabs.sdk</item>\n        <item>com.github.tony19.timber.loggly</item>\n        <item>com.github.tony19.loggly</item>\n        <item>com.visiware.sync2ad.logger.loggly.</item>\n        <item>com.loopme.</item>\n        <item>com.lotadata.moments.</item>\n        <item>com.lotame.android</item>\n        <item>com.mngads.sdk</item>\n        <item>com.mngads.views</item>\n        <item>com.mngads.</item>\n        <item>com.mdotm.android</item>\n        <item>com.innoquant.moca</item>\n        <item>ru.mail.mrgservice.advertising</item>\n        <item>ru.mail.mrgservice.analytics</item>\n        <item>com.mapbox.mapboxsdk.module.telemetry</item>\n        <item>com.mapbox.mapboxsdk.maps.TelemetryDefinition</item>\n        <item>com.mapbox.android.telemetry.</item>\n        <item>com.marketo.</item>\n        <item>org.piwik</item>\n        <item>org.piwik.mobile</item>\n        <item>org.matomo</item>\n        <item>com.metaps</item>\n        <item>com.codahale.metrics</item>\n        <item>com.microsoft.appcenter.analytics</item>\n        <item>com.microsoft.azure.mobile.analytics</item>\n        <item>com.microsoft.appcenter.crashes</item>\n        <item>com.millennialmedia.</item>\n        <item>com.mintegral.</item>\n        <item>com.mbridge.msdk.</item>\n        <item>com.mixpanel.</item>\n        <item>com.moengage.</item>\n        <item>com.moat.analytics.mobile.</item>\n        <item>com.mobfox.</item>\n        <item>com.adsdk.sdk.</item>\n        <item>com.mobpower.</item>\n        <item>com.ubikod.capptain.</item>\n        <item>com.microsoft.azure.engagement.</item>\n        <item>com.mobvista.</item>\n        <item>com.moodmedia</item>\n        <item>com.mopinion.mopinionsdk</item>\n        <item>org.mozilla.telemetry</item>\n        <item>org.mozilla.gecko.telemetry</item>\n        <item>mozilla.telemetry.glean.</item>\n        <item>org.mozilla.fenix.GleanMetrics</item>\n        <item>org.mozilla.fenix.components.metrics</item>\n        <item>com.nativex</item>\n        <item>com.newrelic.agent.</item>\n        <item>com.newrelic.mobile.</item>\n        <item>com.nexage.android.</item>\n        <item>org.nexage.</item>\n        <item>com.nielsen.app</item>\n        <item>com.offertoro.sdk.</item>\n        <item>io.presage.</item>\n        <item>com.omniture.</item>\n        <item>com.adobe.adms.measurement.</item>\n        <item>com.oneaudience.sdk.</item>\n        <item>com.onesignal.</item>\n        <item>com.ooyala</item>\n        <item>com.openback</item>\n        <item>com.safegraph.</item>\n        <item>com.openlocate</item>\n        <item>io.opencensus</item>\n        <item>io.opentelemetry</item>\n        <item>com.openx.view.plugplay</item>\n        <item>com.openx.android_sdk_openx</item>\n        <item>com.opensignal.datacollection.</item>\n        <item>com.optimizely.</item>\n        <item>com.otherlevels.</item>\n        <item>com.outbrain.</item>\n        <item>au.com.oztam.</item>\n        <item>com.pokkt.sdk.</item>\n        <item>com.bytedance.sdk.openadsdk</item>\n        <item>com.bytedance.tea.crash.</item>\n        <item>com.bytedance.embedapplog.</item>\n        <item>com.bytedance.applog.</item>\n        <item>com.parsely.parselyandroid</item>\n        <item>sdk.insert.io.</item>\n        <item>sdk.pendo.io.</item>\n        <item>ly.persona.sdk</item>\n        <item>com.foursquare.pilgrim</item>\n        <item>com.foursquare.pilgrimsdk.android</item>\n        <item>com.pincrux.</item>\n        <item>com.pingstart.adsdk.</item>\n        <item>com.placed.client</item>\n        <item>com.placer.client.Placer</item>\n        <item>com.playtestcloud.Analytics</item>\n        <item>co.vmob.sdk</item>\n        <item>com.pointinside</item>\n        <item>com.pollfish</item>\n        <item>org.prebid.mobile</item>\n        <item>com.telescope.android</item>\n        <item>io.predic.tracker</item>\n        <item>io.proximi.proximiiolibrary</item>\n        <item>com.pubmatic.sdk</item>\n        <item>net.pubnative</item>\n        <item>com.pushspring.sdk.PushSpring</item>\n        <item>com.pusher.client.</item>\n        <item>com.pushwoosh</item>\n        <item>com.pyze.</item>\n        <item>com.qualtrics.digital.</item>\n        <item>com.quantcast.measurement.service.</item>\n        <item>io.radar.sdk.Radar</item>\n        <item>com.radiusnetworks</item>\n        <item>com.mindscapehq.android.raygun4android</item>\n        <item>com.mediabrix.android</item>\n        <item>io.repro.android.</item>\n        <item>com.retency.sdk.android</item>\n        <item>com.stepleaderdigital.reveal</item>\n        <item>com.revmob.ads.</item>\n        <item>com.rjfun.cordova.ad</item>\n        <item>com.rjfun.cordova.admob</item>\n        <item>com.rollbar.android.</item>\n        <item>com.roximity.sdk.</item>\n        <item>com.rfm.sdk</item>\n        <item>com.sam4mobile.</item>\n        <item>.S4MAnalytic</item>\n        <item>com.skplanet.tad</item>\n        <item>com.salesforce.marketingcloud</item>\n        <item>com.scandit.</item>\n        <item>.schibsted.</item>\n        <item>com.scoreloop.client.android</item>\n        <item>com.segment.analytics.</item>\n        <item>com.sense360.android.</item>\n        <item>com.sensoro.beacon.kit.</item>\n        <item>com.sensoro.cloud</item>\n        <item>com.sensorsdata.analytics.android.sdk</item>\n        <item>com.sentiance.sdk.</item>\n        <item>com.jm.co.shallwead.sdk.</item>\n        <item>com.co.shallwead.sdk.</item>\n        <item>com.shopkick.sdk.api.</item>\n        <item>com.shopkick.fetchers.</item>\n        <item>com.signal360.sdk.core.</item>\n        <item>com.sonicnotify.sdk.core.</item>\n        <item>com.rnsignal360</item>\n        <item>com.wirelessregistry.observersdk.</item>\n        <item>com.silverpush.</item>\n        <item>com.sptproximitykit.</item>\n        <item>com.singular.sdk</item>\n        <item>.sizmek.</item>\n        <item>com.smaato.</item>\n        <item>com.smartadserver.</item>\n        <item>com.smartlook.sdk.smartlook.</item>\n        <item>com.snap.adkit</item>\n        <item>com.snap.appadskit</item>\n        <item>com.snapchat.kit.sdk.SnapLogin</item>\n        <item>com.snowplowanalytics.</item>\n        <item>com.ansca.corona</item>\n        <item>com.soomla.</item>\n        <item>io.split.android.</item>\n        <item>com.splunk.mint</item>\n        <item>com.beaconinside.proximitysdk.ProximityService</item>\n        <item>com.startapp.</item>\n        <item>tv.superawesome.sdk</item>\n        <item>tv.superawesome.lib.</item>\n        <item>com.supersonic.adapters.supersonicads</item>\n        <item>com.supersonicads.sdk</item>\n        <item>com.swirl</item>\n        <item>com.swrve.sdk</item>\n        <item>com.visiware.sync2ad.dmp.</item>\n        <item>com.synerise.sdk</item>\n        <item>com.tnkfactory.ad</item>\n        <item>com.taboola.</item>\n        <item>com.tagcommander.</item>\n        <item>com.talkingdata.sdk.</item>\n        <item>com.tendcloud.tenddata.</item>\n        <item>com.talkingdata.appanalytics.</item>\n        <item>com.talkingdata.adtracking.</item>\n        <item>com.tendcloud.appcpa.</item>\n        <item>com.apptalkingdata.push.</item>\n        <item>com.gametalkingdata.push.</item>\n        <item>com.tamoco.sdk</item>\n        <item>com.tapr.sdk.</item>\n        <item>com.tapr.internal.</item>\n        <item>com.tapr.helpers.</item>\n        <item>com.tapdaq.sdk.</item>\n        <item>com.tapdaq.adapters.</item>\n        <item>com.tapjoy.</item>\n        <item>com.taplytics.sdk</item>\n        <item>com.tappx.sdk.android</item>\n        <item>com.tapstream.sdk</item>\n        <item>tv.teads.</item>\n        <item>teads.tv.</item>\n        <item>com.tl.uic.Tealeaf</item>\n        <item>.tealium.</item>\n        <item>com.databerries.</item>\n        <item>com.geolocstation.</item>\n        <item>com.telequid.</item>\n        <item>com.tencent.mta</item>\n        <item>com.tencent.lbs</item>\n        <item>com.tencent.mobwin</item>\n        <item>com.tencent.stat</item>\n        <item>com.tencent.wxop.stat</item>\n        <item>com.tencent.weiyun</item>\n        <item>com.tenjin.android.</item>\n        <item>cn.thinkingdata.</item>\n        <item>com.tinder.analytics</item>\n        <item>com.tinder.ads</item>\n        <item>com.treasuredata</item>\n        <item>com.tune</item>\n        <item>com.mobileapptracker</item>\n        <item>com.tutelatechnologies.sdk</item>\n        <item>org.lasque.tusdk.core</item>\n        <item>org.lasque.tusdkpulse.core</item>\n        <item>com.twine.sdk</item>\n        <item>com.mopub.</item>\n        <item>com.uxcam.</item>\n        <item>com.ubercab.analytics.</item>\n        <item>com.ubercab.library.metrics.analytics.</item>\n        <item>com.ubercab.client.core.analytics.</item>\n        <item>com.umeng.analytics</item>\n        <item>com.umeng.fb</item>\n        <item>com.pure.internal.</item>\n        <item>com.pure.sdk.</item>\n        <item>com.unity3d.services</item>\n        <item>com.unity3d.ads</item>\n        <item>com.upsight.android</item>\n        <item>com.urbanairship</item>\n        <item>com.userexperior</item>\n        <item>com.vk.sdk.</item>\n        <item>com.vk.api.sdk.</item>\n        <item>com.vdopia.client.android.</item>\n        <item>com.vdopia.ads.</item>\n        <item>io.vectaury.</item>\n        <item>net.veloxity.</item>\n        <item>com.foresee.sdk.ForeSee</item>\n        <item>com.verizon.ads</item>\n        <item>com.verizondigitalmedia.mobile.</item>\n        <item>com.oath.mobile.</item>\n        <item>com.vervewireless.advert.</item>\n        <item>com.virgo.ads.</item>\n        <item>com.vpon.ads</item>\n        <item>com.vpadn.analytics</item>\n        <item>com.vpadn.ads.</item>\n        <item>com.vpadn.widget.</item>\n        <item>com.vungle.publisher.</item>\n        <item>com.vungle.warren.</item>\n        <item>com.tencent.map.geolocation</item>\n        <item>com.tencent.mm.plugin.location.</item>\n        <item>com.tencent.mm.plugin.location_soso.</item>\n        <item>com.tencent.mm.plugin.location_google</item>\n        <item>com.weborama.</item>\n        <item>com.webtrekk.webtrekksdk</item>\n        <item>com.webtrends.mobile.analytics.</item>\n        <item>com.webtrends.mobile.android</item>\n        <item>com.widespace.</item>\n        <item>com.wootric.androidsdk.</item>\n        <item>io.xmode.BcnConfig</item>\n        <item>io.xmode.locationsdk</item>\n        <item>io.mysdk.</item>\n        <item>com.yoc.visx</item>\n        <item>com.yandex.mobile.ads</item>\n        <item>com.yinzcam.sobek</item>\n        <item>com.yoadx.yoadx.</item>\n        <item>com.youappi.sdk.</item>\n        <item>com.yume.android</item>\n        <item>com.redbricklane.zapr</item>\n        <item>com.zendrive.sdk.</item>\n        <item>com.zoho.zanalytics.</item>\n        <item>com.igaworks.adpopcorn</item>\n        <item>com.igaworks.ssp.</item>\n        <item>com.deltadna</item>\n        <item>com.fineboost.</item>\n        <item>com.flymob.sdk.</item>\n        <item>com.fullstory.instrumentation.</item>\n        <item>com.fullstory.util.</item>\n        <item>com.fullstory.jni.</item>\n        <item>com.fullstory.FS</item>\n        <item>com.fullstory.rust.</item>\n        <item>com.fullstory.FSSessionData</item>\n        <item>com.ironsource.</item>\n        <item>com.mparticle</item>\n        <item>jp.maio.sdk.</item>\n        <item>com.mediba.jp</item>\n        <item>mediba.ad.sdk.android.openx</item>\n        <item>com.my.target.</item>\n        <item>com.my.tracker.</item>\n        <item>net.nend.android</item>\n        <item>net.nend.unity.</item>\n        <item>com.geopla.</item>\n        <item>com.threebitter.sdk.</item>\n        <item>com.m7.imkfsdk.</item>\n        <item>com.moor.imkf.</item>\n        <item>org.acra.</item>\n        <item>ch.acra.</item>\n        <item>com.adop.sdk.</item>\n        <item>com.admanmedia.</item>\n        <item>com.ljoy.chatbot.</item>\n        <item>com.aihelp.alice.</item>\n        <item>com.apicloud.</item>\n        <item>com.amazonaws.metrics.</item>\n        <item>com.amazonaws.util.AWSRequestMetrics.</item>\n        <item>com.faendir.acra.</item>\n        <item>com.ad2iction.</item>\n        <item>com.a4gpublisher.</item>\n        <item>mobi.mclick.ad.</item>\n        <item>com.adtech.adtechmobile</item>\n        <item>com.adtheorent.</item>\n        <item>com.kuaiyou.loader.</item>\n        <item>com.adwhirl.</item>\n        <item>com.adchina.android</item>\n        <item>com.adflake</item>\n        <item>com.adscendmedia.sdk.</item>\n        <item>.AdscendFiles.AdscendOffersActivity</item>\n        <item>com.advangelists.</item>\n        <item>jp.co.agoop.</item>\n        <item>io.agora.rtc.</item>\n        <item>io.agora.utils.</item>\n        <item>com.aitype.android</item>\n        <item>com.holly.marge</item>\n        <item>com.bear.data</item>\n        <item>com.mb.num</item>\n        <item>io.airbridge.</item>\n        <item>com.anythink.</item>\n        <item>com.alxad.</item>\n        <item>anythink.</item>\n        <item>com.alibaba.sdk.android.mns</item>\n        <item>com.alibaba.sdk.android.httpdns</item>\n        <item>com.ta.utdid2</item>\n        <item>com.alibaba.analytics.</item>\n        <item>com.aliexpress.module.imsdk.</item>\n        <item>com.aliexpress.module.traffic.DDLAccsService</item>\n        <item>com.aliexpress.module.ugc.adapter.powermsg.PowermsgAccsReceiveService</item>\n        <item>com.aliexpress.sky.user.service.SkyAccsService</item>\n        <item>com.taobao.artc.accs.</item>\n        <item>com.taobao.orange.accssupport.</item>\n        <item>com.taobao.sophix.</item>\n        <item>com.alipay.sdk.</item>\n        <item>com.amberweather.sdk.amberadsdk.</item>\n        <item>anet.channel</item>\n        <item>com.anzu.sdk.</item>\n        <item>com.appsamurai.</item>\n        <item>com.sfbx.appconsent.</item>\n        <item>io.applink.applinkio.AppLinkIO</item>\n        <item>com.applink.security.</item>\n        <item>com.gryphonet</item>\n        <item>com.appzilo.sdk.</item>\n        <item>com.appenda.</item>\n        <item>com.apperhand.device.</item>\n        <item>com.appirits.pusher.</item>\n        <item>com.hf.appliftsdk.</item>\n        <item>com.askingpoint.</item>\n        <item>az.nativead.</item>\n        <item>com.avazu.tracking.</item>\n        <item>com.babator.babatorui.</item>\n        <item>com.backendless.</item>\n        <item>com.github.backtrace-labs.</item>\n        <item>backtraceio.library.</item>\n        <item>com.baidu.crashpad.</item>\n        <item>com.baidu.xenv.</item>\n        <item>jp.beaconbank.</item>\n        <item>com.beemray.</item>\n        <item>ai.bitlabs.sdk.</item>\n        <item>com.braintreepayments.api</item>\n        <item>com.brandio.ads</item>\n        <item>com.bugclipper.android.</item>\n        <item>com.buglife.sdk.</item>\n        <item>com.adfonic.</item>\n        <item>com.caramelads.</item>\n        <item>io.cleaninsights.sdk.piwik.</item>\n        <item>com.clearblade.platform.api.</item>\n        <item>com.contentsquare.android.</item>\n        <item>com.crashsdk.</item>\n        <item>io.inventiv.critic.android</item>\n        <item>com.evidon.</item>\n        <item>cat.ereza.customactivityoncrash</item>\n        <item>com.thinkyeah.common.</item>\n        <item>com.databox.</item>\n        <item>com.datadoghq</item>\n        <item>com.incross.dawin</item>\n        <item>com.locationvalue.</item>\n        <item>io.palaima.debugdrawer.</item>\n        <item>cn.shuzilm.core.</item>\n        <item>com.discord.analytics</item>\n        <item>com.evrythng</item>\n        <item>com.hawk</item>\n        <item>io.embrace.android.embracesdk.</item>\n        <item>.services.analytics.AnalyticsProviderService</item>\n        <item>.services.analytics.HeartbeatJobService</item>\n        <item>com.evidon.</item>\n        <item>com.ew.sdk.adboost.</item>\n        <item>.adboost.</item>\n        <item>jp.appAdForce.android.</item>\n        <item>com.pontiflex.mobile.</item>\n        <item>io.flowup</item>\n        <item>jp.fluct.fluctsdk.</item>\n        <item>com.reach.ActionMonitor</item>\n        <item>com.reach.ActionService</item>\n        <item>com.reach.AdServiceManager</item>\n        <item>com.reach.IActivity</item>\n        <item>com.reach.IBackgroundManager</item>\n        <item>com.reach.IBackgroundService</item>\n        <item>com.reach.IBannerAd</item>\n        <item>com.reach.IConfigService</item>\n        <item>com.reach.IInterstitialAd</item>\n        <item>com.reach.INativeAd</item>\n        <item>com.reach.INativeReceiverProxy</item>\n        <item>com.reach.INativeServiceProxy</item>\n        <item>com.reach.IPushService</item>\n        <item>com.reach.IService</item>\n        <item>com.reach.ITrackService</item>\n        <item>com.reach.OverlayActivity</item>\n        <item>com.reach.PeerActivity</item>\n        <item>com.reach.widget</item>\n        <item>com.gad.sdk.</item>\n        <item>com.gamania.beanfunsdk.</item>\n        <item>com.gamesparks.sdk.</item>\n        <item>com.geouniq.android.</item>\n        <item>com.google.cloud.audit</item>\n        <item>com.google.mlkit</item>\n        <item>com.android.billingclient</item>\n        <item>com.grab.grabidpartnersdk</item>\n        <item>com.timerazor.gravysdk.</item>\n        <item>com.greedygame.legacy</item>\n        <item>com.greenrobot.</item>\n        <item>com.groundtruth.sdk</item>\n        <item>com.growingio.</item>\n        <item>com.growthpush.</item>\n        <item>com.growthbeat.</item>\n        <item>com.heytap.nearx.track</item>\n        <item>com.heytap.msp.</item>\n        <item>com.hotmob.sdk.</item>\n        <item>.houseads</item>\n        <item>com.iac.notification.</item>\n        <item>com.igg.android.ad.</item>\n        <item>com.igg.android.gamecenter.</item>\n        <item>com.igg.libs.</item>\n        <item>com.android.skyunion.ad.</item>\n        <item>com.android.skyunion.statistics.</item>\n        <item>com.skyunion.android.</item>\n        <item>com.iqv.</item>\n        <item>com.igexin.sdk.</item>\n        <item>com.inbrain.sdk.</item>\n        <item>com.instal.mobileads.</item>\n        <item>com.instal.common</item>\n        <item>com.instal.mopub.</item>\n        <item>com.instal.nativeads</item>\n        <item>com.instal.discovery</item>\n        <item>com.instal.userprofile</item>\n        <item>com.intrasonics.</item>\n        <item>com.ad.intromi.</item>\n        <item>io.karte.android.tracker.</item>\n        <item>com.kakao.ad.</item>\n        <item>com.kakao.kakaolink</item>\n        <item>com.adzerk</item>\n        <item>com.zestadz.android.</item>\n        <item>com.linecorp.line.admolin</item>\n        <item>com.five_corp.ad.</item>\n        <item>jp.naver.line.android.analytics.</item>\n        <item>jp.naver.line.android.beacon.</item>\n        <item>com.linecorp.line.analytics.tracking</item>\n        <item>com.apptracker.android.</item>\n        <item>com.pad.android.xappad.</item>\n        <item>com.Leadbolt.</item>\n        <item>io.liftoff.liftoffads.</item>\n        <item>com.megvii.zhimasdk.</item>\n        <item>com.madhouse.android.ads</item>\n        <item>com.deflocculent.fecklessness.</item>\n        <item>.BxcActivity</item>\n        <item>.B2sActivity</item>\n        <item>.MdService</item>\n        <item>.LoReceiver</item>\n        <item>.OxgReceiver</item>\n        <item>.PdsReceiver</item>\n        <item>org.gg.msdns.noroxi.</item>\n        <item>com.shahenshah.mathematics.</item>\n        <item>com.warison.authigene</item>\n        <item>com.apld.av.</item>\n        <item>com.kdeamon.libe.</item>\n        <item>net.fivefive.tek.</item>\n        <item>com.unfreezable.moze.</item>\n        <item>com.kinmall.common.</item>\n        <item>com.cleanmaster.security.heartbleed.</item>\n        <item>com.insight.sdk.</item>\n        <item>coelib.c.couluslibrary.</item>\n        <item>com.cs.bd.ad.</item>\n        <item>com.cs.bd.daemon.</item>\n        <item>com.cs.bd.hicon.</item>\n        <item>com.cs.bd.service.</item>\n        <item>com.cs.bd.receiver.</item>\n        <item>com.cs.bd.buychannel.</item>\n        <item>com.cs.bd.commerce.</item>\n        <item>com.cs.statistic.</item>\n        <item>com.cpcphone.abtestcenter.</item>\n        <item>com.fungame.advertisingsdk</item>\n        <item>com.hz.keep.</item>\n        <item>cn.rs.keepalive.</item>\n        <item>com.mapps.android.</item>\n        <item>com.mz.common.</item>\n        <item>com.mmc.common</item>\n        <item>com.mezzomedia.</item>\n        <item>com.mobclick.android</item>\n        <item>com.mobimento.caponate.ad.</item>\n        <item>com.mobiquitynetworks.</item>\n        <item>com.moblin.pxl.</item>\n        <item>com.mobon.sdk.</item>\n        <item>com.mofiler.android</item>\n        <item>kr.com.mojise.sdk</item>\n        <item>com.morgoo.droidplugin.</item>\n        <item>mozilla.components.lib.crash.service</item>\n        <item>com.inn.passivesdk.</item>\n        <item>com.inn.feedback.</item>\n        <item>kr.newspic.offerwall.</item>\n        <item>com.ninjametrics.</item>\n        <item>jp.noahapps.sdk.</item>\n        <item>com.aiadmobi.sdk.</item>\n        <item>com.mNewsK.sdk.</item>\n        <item>com.ogury.cm.</item>\n        <item>com.ogury.analytics.</item>\n        <item>com.ogury.consent.</item>\n        <item>com.ogury.sdk.</item>\n        <item>com.onetrust.</item>\n        <item>com.openmediation.sdk.</item>\n        <item>com.crosspromotion.sdk</item>\n        <item>org.openudid.</item>\n        <item>org.OpenUDID.</item>\n        <item>com.huawei.openalliance.ad.</item>\n        <item>com.huawei.hms.aaid.</item>\n        <item>com.huawei.hianalytics.</item>\n        <item>net.opentracker.android</item>\n        <item>outbid.com.outbidsdk.</item>\n        <item>com.peanutlabs.plsdk.</item>\n        <item>com.papaya.offer.</item>\n        <item>com.appflood</item>\n        <item>com.parse.Parse</item>\n        <item>com.parse.PushServiceApi</item>\n        <item>it.partytrack.sdk.</item>\n        <item>com.phunware.advertising.</item>\n        <item>com.pinterest.android.pdk.</item>\n        <item>com.playfab.PlayFab</item>\n        <item>com.plleti.offerwall.</item>\n        <item>com.pontiflex.mobile</item>\n        <item>com.posthog.android</item>\n        <item>jp.profilepassport.android.</item>\n        <item>.ppSDK.</item>\n        <item>com.pubnub.api.</item>\n        <item>com.pulsatehq.</item>\n        <item>me.pushy.sdk.</item>\n        <item>com.qihoo.util.</item>\n        <item>com.qihoo360.mobilesafe.loader.</item>\n        <item>com.qihoo360.replugin.</item>\n        <item>data.acquisition.sdk.</item>\n        <item>com.quantumgraph.</item>\n        <item>com.appier.</item>\n        <item>com.rakuten.tech.mobile.analytics.</item>\n        <item>co.jp.rakuten.sdtd.analytics</item>\n        <item>com.rakuten.android.ads</item>\n        <item>com.rakuten.gap.ads</item>\n        <item>com.revenuecat.</item>\n        <item>com.rumble.sdk</item>\n        <item>com.gigya.</item>\n        <item>com.sas.mkt.mobile.sdk.</item>\n        <item>com.sdkbox.</item>\n        <item>com.ss.android.</item>\n        <item>com.sailthru</item>\n        <item>com.samsung.context.sdk.samsunganalytics.</item>\n        <item>com.sec.android.diagmonagent.</item>\n        <item>com.sayso.ui.</item>\n        <item>com.sayso.utils.</item>\n        <item>com.optimizely</item>\n        <item>io.sentry.</item>\n        <item>com.joshdholtz.sentry</item>\n        <item>seventynine.sdk.</item>\n        <item>com.shuwei.location.</item>\n        <item>com.sina.weibo.sdk</item>\n        <item>es.situm.sdk.</item>\n        <item>com.skillz.Skillz</item>\n        <item>com.skyhook.context.Accelerator</item>\n        <item>com.smrtbeat.</item>\n        <item>com.smartyads</item>\n        <item>com.soundhound.android.adverts</item>\n        <item>com.spoteer.arc.</item>\n        <item>com.spotify.mobile.android.ads.</item>\n        <item>com.spotify.music.features.ads.</item>\n        <item>com.spotify.music.ads.</item>\n        <item>com.spotify.ads.</item>\n        <item>com.spotify.music.libs.adbasedondemand.</item>\n        <item>com.spotify.nativeads.</item>\n        <item>jp.supership.vamp.</item>\n        <item>net.taparound.</item>\n        <item>com.taiwanmobile.pt.adp.</item>\n        <item>com.tjhello.ab.</item>\n        <item>com.tapit.</item>\n        <item>com.tapad.adserving</item>\n        <item>com.tapad.tracking</item>\n        <item>com.tremorvideo.sdk.</item>\n        <item>com.teliver.sdk.</item>\n        <item>com.qq.e.tg.</item>\n        <item>com.qq.e.ads.</item>\n        <item>com.qq.e.comm.</item>\n        <item>com.tencent.mm.opensdk</item>\n        <item>com.tencent.connect.</item>\n        <item>.wxapi.</item>\n        <item>theoremreach.com.theoremreach.</item>\n        <item>com.muf.sdk.tiktok.</item>\n        <item>com.matthewchen.togetherad</item>\n        <item>com.tradplus.ads.</item>\n        <item>com.trillbit.</item>\n        <item>com.triplelift.sdk.</item>\n        <item>com.triplelift.tl_sdk.</item>\n        <item>.ads.AdsInfoWebViewActivity</item>\n        <item>.ads.AdsCompanionWebViewActivity</item>\n        <item>.analytics.TweetAnalyticsWebViewActivity</item>\n        <item>com.twitter.android.dogfood.</item>\n        <item>com.twitter.analytics.</item>\n        <item>com.ucweb.union.ads.</item>\n        <item>com.UCMobile.Apollo.</item>\n        <item>com.umeng.commonsdk.stateless</item>\n        <item>com.umeng.commonsdk.statistics</item>\n        <item>com.umeng.socialize.</item>\n        <item>com.umeng.umsdk</item>\n        <item>com.umeng.message</item>\n        <item>com.taobao.accs</item>\n        <item>com.taobao.agoo</item>\n        <item>org.android.agoo</item>\n        <item>.qwapi.adclient.android.view.</item>\n        <item>.MediaPlayerWrapper.</item>\n        <item>.nbpcorp.</item>\n        <item>com.ad.sdk.</item>\n        <item>com.sen.sdk.sen.</item>\n        <item>com.sen.websdk.</item>\n        <item>.service.TrackerService</item>\n        <item>.service.Analytics</item>\n        <item>com.nextapps.naswall.</item>\n        <item>.BannerActivity</item>\n        <item>.InterstitialActivity</item>\n        <item>com.bestgo.adsplugin.</item>\n        <item>com.zero.ta.common.</item>\n        <item>com.zjsoft.baseadlib.</item>\n        <item>de.rocketinternet.android.</item>\n        <item>com.yoc.sdk</item>\n        <item>com.yt.promolib.</item>\n        <item>com.growstarry.</item>\n        <item>com.usabilla.sdk.</item>\n        <item>mobi.vserv.android.adengine.</item>\n        <item>com.vivo.push.sdk.</item>\n        <item>com.vodafone.netperform.runtime.</item>\n        <item>com.walkme.wmads</item>\n        <item>com.walkme.wmanalytics</item>\n        <item>com.walkme.wmcrosspromotion</item>\n        <item>abbi.io.abbisdk.</item>\n        <item>com.wannads.sdk.</item>\n        <item>ru.wapstart.plus1.sdk.</item>\n        <item>com.sina.deviceidjnisdk</item>\n        <item>com.wonderpush</item>\n        <item>com.woopra.tracking.</item>\n        <item>com.woorlds.woorldssdk.</item>\n        <item>com.wortise.</item>\n        <item>com.xiaomi.push</item>\n        <item>com.xiaomi.mipush.</item>\n        <item>jp.co.yahoo.android.yssens.YSSensDataShareService</item>\n        <item>jp.co.yahoo.yconnect.sdk.SharedDataService</item>\n        <item>jp.co.yahoo.android.hssens.HSSensDataShareService</item>\n        <item>jp.co.yahoo.yconnect.sso.ShowPromotionViewActivity</item>\n        <item>jp.co.yahoo.android.haas.AgoopReceiver</item>\n        <item>jp.co.yahoo.android.yssens.YSSensActivityLifecycleContentProvider</item>\n        <item>jp.co.yahoo.android.yssens.YSSensBeaconer</item>\n        <item>jp.co.yahoo.android.yssens.YSSensAnalytics</item>\n        <item>com.yext.locationsdk.</item>\n        <item>com.yieldlab.</item>\n        <item>com.yougood.basebusiness.</item>\n        <item>com.yougoodtech.</item>\n        <item>net.youmi</item>\n        <item>com.uc.crashsdk</item>\n        <item>com.uc2.crashsdk</item>\n        <item>zendesk.</item>\n        <item>com.zenjoy.ads</item>\n        <item>net.zucks.</item>\n        <item>com.ew.sdk.adboost</item>\n        <item>de.appplant.</item>\n        <item>com.apptv.android.</item>\n        <item>com.appgeneration.ituner.ad</item>\n        <item>com.ayetstudios.publishersdk.</item>\n        <item>co.nearbee</item>\n        <item>com.deploygate.sdk.</item>\n        <item>com.fineapptech.fineadscreensdk.</item>\n        <item>com.fineapptech.finechubsdk.</item>\n        <item>com.mfine.sdk.capp.</item>\n        <item>com.fineapptech.finead.</item>\n        <item>com.frogermcs.activityframemetrics</item>\n        <item>jp.co.imobile.sdkads.android.</item>\n        <item>jp.iridge.popinfo.</item>\n        <item>com.mtraction.mtractioninapptracker.</item>\n        <item>com.netmera.</item>\n        <item>jp.pinable.ssbp.</item>\n        <item>com.smixx.fabric.</item>\n        <item>com.tabtale</item>\n    </string-array>\n    <string-array name=\"tracker_names\">\n        <item>360Dialog</item>\n        <item>ABTasty</item>\n        <item>ACRCloud</item>\n        <item>AD(X)</item>\n        <item>AD(X)</item>\n        <item>ADLIB</item>\n        <item>AMoAd</item>\n        <item>ATInternet</item>\n        <item>Aarki</item>\n        <item>AccountKit</item>\n        <item>Actv8me</item>\n        <item>Acuant</item>\n        <item>Ad Generation</item>\n        <item>Ad4Screen</item>\n        <item>AdAdapted</item>\n        <item>AdBuddiz</item>\n        <item>AdColony</item>\n        <item>AdColony</item>\n        <item>AdFalcon</item>\n        <item>AdFit (Daum)</item>\n        <item>AdForm</item>\n        <item>AdGateMedia</item>\n        <item>AdGem</item>\n        <item>AdLocus</item>\n        <item>AdMarvel</item>\n        <item>AdMuing</item>\n        <item>AdTiming</item>\n        <item>AdTiming</item>\n        <item>AdTrial</item>\n        <item>Adbrix</item>\n        <item>Adcash</item>\n        <item>Adcenix</item>\n        <item>Add Apt Tr</item>\n        <item>Adfurikun</item>\n        <item>Adfurikun</item>\n        <item>Adincube</item>\n        <item>Adjoe</item>\n        <item>Adjoe</item>\n        <item>Adjust</item>\n        <item>Adjust</item>\n        <item>Adjust Unbotify</item>\n        <item>Admitad</item>\n        <item>Admixer</item>\n        <item>Admixer</item>\n        <item>Admost</item>\n        <item>Admost</item>\n        <item>Adobe Experience Cloud</item>\n        <item>Adot</item>\n        <item>AdsWizz</item>\n        <item>AerServ</item>\n        <item>Airpush</item>\n        <item>Akamai MAP</item>\n        <item>Alimama (formerly AdsMogo)</item>\n        <item>Alimama (formerly AdsMogo)</item>\n        <item>Alohalytics</item>\n        <item>Alooma</item>\n        <item>Alphonso</item>\n        <item>AltBeacon</item>\n        <item>AltBeacon</item>\n        <item>AltBeacon</item>\n        <item>Altamob</item>\n        <item>Amap</item>\n        <item>Amazon Advertisement</item>\n        <item>Amazon Analytics (Amazon insights)</item>\n        <item>Amazon Analytics (Amazon insights)</item>\n        <item>Amazon Analytics (Amazon insights)</item>\n        <item>Amazon Mobile Analytics (Amplify)</item>\n        <item>Amazon Mobile Associates</item>\n        <item>Amobee</item>\n        <item>Amplitude Android SDK</item>\n        <item>Anagog</item>\n        <item>Analytics by NPAW (Youbora Suite)</item>\n        <item>Anvato (A Google Company)</item>\n        <item>AnySDK</item>\n        <item>AnySDK</item>\n        <item>AppAnalytics</item>\n        <item>AppBrain</item>\n        <item>AppLovin</item>\n        <item>AppMetrica</item>\n        <item>AppMonet</item>\n        <item>AppNexus</item>\n        <item>AppSee</item>\n        <item>AppVador</item>\n        <item>Appcelerator Analytics</item>\n        <item>Appcelerator Analytics</item>\n        <item>Appdynamics</item>\n        <item>Applause</item>\n        <item>Appnext</item>\n        <item>Appodeal</item>\n        <item>Appodeal</item>\n        <item>Appodeal Stack</item>\n        <item>AppsFlyer</item>\n        <item>AppsGeyser</item>\n        <item>AppsGeyser</item>\n        <item>Apptentive</item>\n        <item>Apptimize</item>\n        <item>Apsalar</item>\n        <item>Apteligent by VMWare (formerly Crittercism)</item>\n        <item>Areametrics</item>\n        <item>Areametrics</item>\n        <item>Audience Studio (Krux)</item>\n        <item>Auditude</item>\n        <item>Axonix</item>\n        <item>Axonix</item>\n        <item>Backelite</item>\n        <item>Backelite</item>\n        <item>Baidu APPX</item>\n        <item>Baidu Location</item>\n        <item>Baidu Map</item>\n        <item>Baidu Maps</item>\n        <item>Baidu Mobile Ads</item>\n        <item>Baidu Mobile Stat</item>\n        <item>Baidu Navigation</item>\n        <item>Batch</item>\n        <item>Bazaarvoice</item>\n        <item>BeaconsInSpace (Fysical)</item>\n        <item>Beintoo</item>\n        <item>BidMachine</item>\n        <item>Bitly</item>\n        <item>Blesh</item>\n        <item>BlueConic</item>\n        <item>BlueKai (acquired by Oracle)</item>\n        <item>Bluecats</item>\n        <item>Bolts</item>\n        <item>Branch</item>\n        <item>Braze (formerly Appboy)</item>\n        <item>Brightcove</item>\n        <item>BugSense</item>\n        <item>Bugfender</item>\n        <item>Bugly</item>\n        <item>Bugsee</item>\n        <item>Bugsnag</item>\n        <item>Button</item>\n        <item>BuzzAd Benefit</item>\n        <item>CallDorado</item>\n        <item>Carnival</item>\n        <item>Carnival</item>\n        <item>Carto (formerly Nutiteq)</item>\n        <item>Carto (formerly Nutiteq)</item>\n        <item>Cauly</item>\n        <item>Cauly</item>\n        <item>Cauly</item>\n        <item>Cedexis Radar</item>\n        <item>ChartBoost</item>\n        <item>Chartbeat</item>\n        <item>Cheetah Ads</item>\n        <item>Cifrasoft</item>\n        <item>CleverTap</item>\n        <item>Cloudmobi</item>\n        <item>Colocator</item>\n        <item>ComScore</item>\n        <item>Conversant</item>\n        <item>Conversant</item>\n        <item>Conviva</item>\n        <item>CoolaData</item>\n        <item>Coulus Coelib</item>\n        <item>Countly</item>\n        <item>Crashlytics</item>\n        <item>Crashlytics</item>\n        <item>Crashlytics</item>\n        <item>Crashlytics</item>\n        <item>Crashlytics</item>\n        <item>Criteo</item>\n        <item>Cuebiq</item>\n        <item>Cuebiq</item>\n        <item>DOV-E</item>\n        <item>Demdex</item>\n        <item>Demdex</item>\n        <item>Didomi</item>\n        <item>Display</item>\n        <item>Duapps</item>\n        <item>Dynamic Yield</item>\n        <item>Dynatrace</item>\n        <item>Dynatrace</item>\n        <item>Dynatrace</item>\n        <item>Emarsys Predict</item>\n        <item>Enhance</item>\n        <item>Ensighten</item>\n        <item>Esri ArcGIS</item>\n        <item>Estimote</item>\n        <item>Eulerian</item>\n        <item>ExactTarget</item>\n        <item>Exponea</item>\n        <item>Exponea</item>\n        <item>Exponea</item>\n        <item>FLUZO</item>\n        <item>Facebook Ads</item>\n        <item>Facebook Analytics</item>\n        <item>Facebook Analytics</item>\n        <item>Facebook Analytics</item>\n        <item>Facebook Audience</item>\n        <item>Facebook Flipper</item>\n        <item>Facebook Login</item>\n        <item>Facebook Notifications</item>\n        <item>Facebook Places</item>\n        <item>Facebook Share</item>\n        <item>Factual</item>\n        <item>Factual</item>\n        <item>FidZup</item>\n        <item>Fiksu</item>\n        <item>Firebase Analytics</item>\n        <item>Firebase Analytics</item>\n        <item>Firebase Analytics</item>\n        <item>Flowsense</item>\n        <item>Flurry Analytics</item>\n        <item>FollowAnalytics</item>\n        <item>Footmarks</item>\n        <item>FreeWheel</item>\n        <item>Fyber</item>\n        <item>Fyber SponsorPay</item>\n        <item>GIPHY Analytics</item>\n        <item>GIPHY Analytics</item>\n        <item>GOM Factory AdPie</item>\n        <item>GPShopper</item>\n        <item>GameAnalytics</item>\n        <item>Gemius HeatMap</item>\n        <item>Geniee</item>\n        <item>Gigya</item>\n        <item>Gimbal</item>\n        <item>Glispa Connect (Formerly Avocarrot)</item>\n        <item>Glympse</item>\n        <item>Google AdMob</item>\n        <item>Google AdMob</item>\n        <item>Google AdMob</item>\n        <item>Google AdMob</item>\n        <item>Google AdMob</item>\n        <item>Google AdMob</item>\n        <item>Google AdMob</item>\n        <item>Google AdMob</item>\n        <item>Google AdMob</item>\n        <item>Google AdMob</item>\n        <item>Google Analytics</item>\n        <item>Google Analytics</item>\n        <item>Google Analytics</item>\n        <item>Google Analytics Plugin (Cordova)</item>\n        <item>Google Tag Manager</item>\n        <item>Google Tag Manager</item>\n        <item>Heap</item>\n        <item>HelpShift</item>\n        <item>Herow</item>\n        <item>Heyzap (bought by Fyber)</item>\n        <item>Heyzap (bought by Fyber)</item>\n        <item>HockeyApp</item>\n        <item>Houndify</item>\n        <item>Huawei Mobile Services (HMS) Core</item>\n        <item>Huawei Mobile Services (HMS) Core</item>\n        <item>Huawei Mobile Services (HMS) Core</item>\n        <item>Huawei Mobile Services (HMS) Core</item>\n        <item>Huawei Mobile Services (HMS) Core</item>\n        <item>Huawei Mobile Services (HMS) Core</item>\n        <item>Huawei Mobile Services (HMS) Core</item>\n        <item>Huawei Mobile Services (HMS) Core</item>\n        <item>Huq Sourcekit</item>\n        <item>HyperTrack</item>\n        <item>HyperTrack</item>\n        <item>HyperTrack</item>\n        <item>HyprMX</item>\n        <item>IAB Open Measurement</item>\n        <item>IAB Open Measurement</item>\n        <item>IAB Open Measurement</item>\n        <item>IBM Digital Analytics</item>\n        <item>IBM Mobile Marketing (Acoustic)</item>\n        <item>IBM Mobile Marketing (Acoustic)</item>\n        <item>IBM Mobile Marketing (Acoustic)</item>\n        <item>IBM Mobile Marketing (Acoustic)</item>\n        <item>INFOnline</item>\n        <item>IPQualityScore</item>\n        <item>IQzone</item>\n        <item>In Loco</item>\n        <item>InMarket</item>\n        <item>InMobi</item>\n        <item>InMobi</item>\n        <item>IndoorAtlas</item>\n        <item>Inneractive</item>\n        <item>Inrix</item>\n        <item>Insider</item>\n        <item>Instabug</item>\n        <item>Instreamatic (Adman)</item>\n        <item>Integral Ad Science</item>\n        <item>JW Player</item>\n        <item>Janrain</item>\n        <item>Janrain</item>\n        <item>Janrain</item>\n        <item>JiGuang Aurora Mobile JPush</item>\n        <item>Jumio</item>\n        <item>JumpTap</item>\n        <item>KIDOZ</item>\n        <item>KISSmetrics Android API</item>\n        <item>Keen</item>\n        <item>Kiip</item>\n        <item>Kochava</item>\n        <item>Kochava</item>\n        <item>Kochava</item>\n        <item>Kontakt</item>\n        <item>LeanPlum</item>\n        <item>Lenddo</item>\n        <item>Ligatus</item>\n        <item>Ligatus</item>\n        <item>Ligatus</item>\n        <item>Lisnr</item>\n        <item>Localytics</item>\n        <item>Localytics</item>\n        <item>Localytics</item>\n        <item>Locuslabs</item>\n        <item>Loggly</item>\n        <item>Loggly</item>\n        <item>Loggly</item>\n        <item>LoopMe</item>\n        <item>LotaData</item>\n        <item>Lotame</item>\n        <item>MAdvertise</item>\n        <item>MAdvertise</item>\n        <item>MAdvertise</item>\n        <item>MDOTM</item>\n        <item>MOCA</item>\n        <item>Mail.ru</item>\n        <item>Mail.ru</item>\n        <item>Mapbox</item>\n        <item>Mapbox</item>\n        <item>Mapbox</item>\n        <item>Marketo (an Adobe Company)</item>\n        <item>Matomo (Piwik)</item>\n        <item>Matomo (Piwik)</item>\n        <item>Matomo (Piwik)</item>\n        <item>Metaps</item>\n        <item>Metrics</item>\n        <item>Microsoft Visual Studio App Center Analytics</item>\n        <item>Microsoft Visual Studio App Center Analytics</item>\n        <item>Microsoft Visual Studio App Center Crashes</item>\n        <item>Millennial Media</item>\n        <item>Mintegral</item>\n        <item>Mintegral</item>\n        <item>MixPanel</item>\n        <item>MoEngage</item>\n        <item>Moat</item>\n        <item>MobFox</item>\n        <item>MobFox</item>\n        <item>MobPower</item>\n        <item>Mobile Engagement</item>\n        <item>Mobile Engagement</item>\n        <item>Mobvista</item>\n        <item>Moodmedia</item>\n        <item>Mopinion</item>\n        <item>Mozilla Telemetry</item>\n        <item>Mozilla Telemetry</item>\n        <item>Mozilla Telemetry</item>\n        <item>Mozilla Telemetry</item>\n        <item>Mozilla Telemetry</item>\n        <item>NativeX</item>\n        <item>New Relic</item>\n        <item>New Relic</item>\n        <item>Nexage</item>\n        <item>Nexage</item>\n        <item>Nielsen</item>\n        <item>OfferToro</item>\n        <item>Ogury Presage</item>\n        <item>Omniture</item>\n        <item>Omniture</item>\n        <item>OneAudience</item>\n        <item>OneSignal</item>\n        <item>Ooyala</item>\n        <item>OpenBack</item>\n        <item>OpenLocate</item>\n        <item>OpenLocate</item>\n        <item>OpenTelemetry (OpenCensus, OpenTracing)</item>\n        <item>OpenTelemetry (OpenCensus, OpenTracing)</item>\n        <item>OpenX</item>\n        <item>OpenX</item>\n        <item>Opensignal</item>\n        <item>Optimizely</item>\n        <item>OtherLevels</item>\n        <item>OutBrain</item>\n        <item>OzTAM</item>\n        <item>POKKT</item>\n        <item>Pangle</item>\n        <item>Pangle</item>\n        <item>Pangle</item>\n        <item>Pangle</item>\n        <item>Parse.ly</item>\n        <item>Pendo</item>\n        <item>Pendo</item>\n        <item>Persona.ly</item>\n        <item>Pilgrim by Foursquare</item>\n        <item>Pilgrim by Foursquare</item>\n        <item>Pincrux</item>\n        <item>PingStart</item>\n        <item>Placed</item>\n        <item>Placer</item>\n        <item>PlaytestCloud Event Tracking</item>\n        <item>Plexure</item>\n        <item>Point Inside</item>\n        <item>Pollfish</item>\n        <item>Prebid Mobile</item>\n        <item>PredicIO</item>\n        <item>PredicIO</item>\n        <item>Proximi.io</item>\n        <item>PubMatic</item>\n        <item>PubNative</item>\n        <item>PushSpring</item>\n        <item>Pusher</item>\n        <item>Pushwoosh</item>\n        <item>Pyze</item>\n        <item>Qualtrics</item>\n        <item>Quantcast</item>\n        <item>Radar</item>\n        <item>Radius Networks</item>\n        <item>Raygun</item>\n        <item>Receptiv (formerly Mediabrix)</item>\n        <item>Repro</item>\n        <item>Retency</item>\n        <item>Reveal Mobile</item>\n        <item>Revmob</item>\n        <item>RjFun</item>\n        <item>RjFun</item>\n        <item>Rollbar</item>\n        <item>Roximity</item>\n        <item>Rubicon Project</item>\n        <item>S4M</item>\n        <item>S4M</item>\n        <item>SK planet Tad</item>\n        <item>Salesforce Marketing Cloud</item>\n        <item>Scandit</item>\n        <item>Schibsted</item>\n        <item>ScoreLoop</item>\n        <item>Segment</item>\n        <item>Sense360</item>\n        <item>Sensoro</item>\n        <item>Sensoro</item>\n        <item>Sensors Analytics</item>\n        <item>Sentiance</item>\n        <item>ShallWeAD</item>\n        <item>ShallWeAD</item>\n        <item>Shopkick</item>\n        <item>Shopkick</item>\n        <item>Signal360</item>\n        <item>Signal360</item>\n        <item>Signal360</item>\n        <item>SignalFrame</item>\n        <item>SilverPush</item>\n        <item>Singlespot</item>\n        <item>Singular</item>\n        <item>Sizmek</item>\n        <item>Smaato</item>\n        <item>Smart</item>\n        <item>SmartLook</item>\n        <item>Snap Ad Kit</item>\n        <item>Snap Ad Kit</item>\n        <item>Snapchat Login Kit</item>\n        <item>Snowplow</item>\n        <item>Solar2D (Corona)</item>\n        <item>Soomla</item>\n        <item>Split</item>\n        <item>Splunk MINT</item>\n        <item>Square Metrics</item>\n        <item>StartApp-SDK</item>\n        <item>SuperAwesome</item>\n        <item>SuperAwesome</item>\n        <item>Supersonic Ads</item>\n        <item>Supersonic Ads</item>\n        <item>Swirl</item>\n        <item>Swrve</item>\n        <item>Sync2Ad</item>\n        <item>Synerise</item>\n        <item>TNK Factory</item>\n        <item>Taboola</item>\n        <item>TagCommander (Commanders Act.)</item>\n        <item>TalkingData</item>\n        <item>TalkingData</item>\n        <item>TalkingData</item>\n        <item>TalkingData</item>\n        <item>TalkingData</item>\n        <item>TalkingData</item>\n        <item>TalkingData</item>\n        <item>Tamoco</item>\n        <item>TapResearch</item>\n        <item>TapResearch</item>\n        <item>TapResearch</item>\n        <item>Tapdaq</item>\n        <item>Tapdaq</item>\n        <item>Tapjoy</item>\n        <item>Taplytics</item>\n        <item>Tappx</item>\n        <item>Tapstream</item>\n        <item>Teads</item>\n        <item>Teads</item>\n        <item>Tealeaf</item>\n        <item>Tealium</item>\n        <item>Teemo</item>\n        <item>Teemo</item>\n        <item>TeleQuid</item>\n        <item>Tencent MTA</item>\n        <item>Tencent Map LBS</item>\n        <item>Tencent MobWin</item>\n        <item>Tencent Stats</item>\n        <item>Tencent Stats</item>\n        <item>Tencent Weiyun</item>\n        <item>Tenjin</item>\n        <item>ThinkingData Analytics</item>\n        <item>Tinder Analytics</item>\n        <item>Tinder Analytics</item>\n        <item>Treasure Data</item>\n        <item>Tune</item>\n        <item>Tune</item>\n        <item>Tutela</item>\n        <item>Tutucloud</item>\n        <item>Tutucloud</item>\n        <item>Twine Data</item>\n        <item>Twitter MoPub</item>\n        <item>UXCam</item>\n        <item>Uber Analytics</item>\n        <item>Uber Analytics</item>\n        <item>Uber Analytics</item>\n        <item>Umeng Analytics</item>\n        <item>Umeng Feedback</item>\n        <item>Unacast Pure</item>\n        <item>Unacast Pure</item>\n        <item>Unity3d Ads</item>\n        <item>Unity3d Ads</item>\n        <item>Upsight</item>\n        <item>Urbanairship</item>\n        <item>UserExperior</item>\n        <item>VKontakte SDK</item>\n        <item>VKontakte SDK</item>\n        <item>Vdopia</item>\n        <item>Vdopia</item>\n        <item>Vectaury</item>\n        <item>Veloxity</item>\n        <item>Verint ForeSee</item>\n        <item>Verizon Ads</item>\n        <item>Verizon Ads</item>\n        <item>Verizon Ads</item>\n        <item>Verve</item>\n        <item>Virgo Mobile</item>\n        <item>Vpon</item>\n        <item>Vpon</item>\n        <item>Vpon</item>\n        <item>Vpon</item>\n        <item>Vungle</item>\n        <item>Vungle</item>\n        <item>WeChat Location</item>\n        <item>WeChat Location</item>\n        <item>WeChat Location</item>\n        <item>WeChat Location</item>\n        <item>Weborama</item>\n        <item>Webtrekk</item>\n        <item>Webtrends</item>\n        <item>Webtrends</item>\n        <item>Widespace</item>\n        <item>Wootric</item>\n        <item>X-Mode</item>\n        <item>X-Mode</item>\n        <item>X-Mode</item>\n        <item>YOC VIS.X</item>\n        <item>Yandex Ad</item>\n        <item>Yinzcam Sobek</item>\n        <item>Yoadx</item>\n        <item>YouAppi</item>\n        <item>YuMe</item>\n        <item>Zapr</item>\n        <item>Zendrive</item>\n        <item>Zoho Analytics</item>\n        <item>adPOPcorn</item>\n        <item>adPOPcorn</item>\n        <item>deltaDNA</item>\n        <item>fineboost</item>\n        <item>flymob</item>\n        <item>fullstory</item>\n        <item>fullstory</item>\n        <item>fullstory</item>\n        <item>fullstory</item>\n        <item>fullstory</item>\n        <item>fullstory</item>\n        <item>ironSource</item>\n        <item>mParticle</item>\n        <item>maio by i-mobile</item>\n        <item>mediba</item>\n        <item>mediba</item>\n        <item>myTarget</item>\n        <item>myTracker</item>\n        <item>nend</item>\n        <item>nend</item>\n        <item>²39Geopla</item>\n        <item>²3bitter Beacon</item>\n        <item>²7Moor SDK</item>\n        <item>²7Moor SDK</item>\n        <item>²ACRA</item>\n        <item>²ACRA</item>\n        <item>²ADOP</item>\n        <item>²ADman Media</item>\n        <item>²AIHelp</item>\n        <item>²AIHelp</item>\n        <item>²APICloud</item>\n        <item>²AWS Kinesis</item>\n        <item>²AWS Kinesis</item>\n        <item>²Acrarium</item>\n        <item>²Ad2</item>\n        <item>²Ad4Game</item>\n        <item>²AdFlex</item>\n        <item>²AdTech</item>\n        <item>²AdTheorent</item>\n        <item>²AdView</item>\n        <item>²AdWhirl (AdMob)</item>\n        <item>²Adchina</item>\n        <item>²Adflake</item>\n        <item>²Adscend Media</item>\n        <item>²Adscend Media</item>\n        <item>²Advangelists</item>\n        <item>²Agoop</item>\n        <item>²Agora Analytics</item>\n        <item>²Agora Analytics</item>\n        <item>²Ai.type *Malverting related</item>\n        <item>²Ai.type *Malverting related</item>\n        <item>²Ai.type *Malverting related</item>\n        <item>²Ai.type *Malverting related</item>\n        <item>²Airbridge</item>\n        <item>²Algorix</item>\n        <item>²Algorix</item>\n        <item>²Algorix</item>\n        <item>²Alibaba Cloud Messaging</item>\n        <item>²Alibaba HTTPDNS</item>\n        <item>²Alibaba UserTrack Device IDentity (UTDID)</item>\n        <item>²Alibaba analytics</item>\n        <item>²Alibaba analytics</item>\n        <item>²Alibaba analytics</item>\n        <item>²Alibaba analytics</item>\n        <item>²Alibaba analytics</item>\n        <item>²Alibaba analytics</item>\n        <item>²Alibaba analytics</item>\n        <item>²Alibaba analytics</item>\n        <item>²Alipay SDK</item>\n        <item>²Amber Weather Ad SDK</item>\n        <item>²Anet channel library</item>\n        <item>²Anzu</item>\n        <item>²App Samurai</item>\n        <item>²AppConsent CMP</item>\n        <item>²AppLink.io</item>\n        <item>²AppLink.io</item>\n        <item>²AppRight (by Gryphonet)</item>\n        <item>²AppZilo</item>\n        <item>²Appenda</item>\n        <item>²Apperhand</item>\n        <item>²Appirits</item>\n        <item>²Applift</item>\n        <item>²Askingpoint</item>\n        <item>²Avazu aNative</item>\n        <item>²Avazu aNative</item>\n        <item>²Babator</item>\n        <item>²Backendless</item>\n        <item>²Backtrace</item>\n        <item>²Backtrace</item>\n        <item>²Baidu Crash Reporter</item>\n        <item>²Baidu Crash Reporter</item>\n        <item>²BeaconBank</item>\n        <item>²Beemray</item>\n        <item>²BitLabs</item>\n        <item>²Braintree</item>\n        <item>²Brandio</item>\n        <item>²BugClipper</item>\n        <item>²Buglife</item>\n        <item>²Byyd (Adfonic)</item>\n        <item>²CaramelAds</item>\n        <item>²CleanInsights</item>\n        <item>²ClearBlade</item>\n        <item>²Contentsquare</item>\n        <item>²CrashSDK</item>\n        <item>²Critic</item>\n        <item>²Crownpeak</item>\n        <item>²Custom Activity On Crash library</item>\n        <item>²DaoCheng(Thinkyeah)</item>\n        <item>²Databox</item>\n        <item>²Datadog</item>\n        <item>²Dawin</item>\n        <item>²DearOne(LocationValue)</item>\n        <item>²DebugDrawer</item>\n        <item>²Digital Union (shuzilm)</item>\n        <item>²Discord Telemetry</item>\n        <item>²EVRYTHNG</item>\n        <item>²Ehawk</item>\n        <item>²Embrace</item>\n        <item>²Epic games analytics</item>\n        <item>²Epic games analytics</item>\n        <item>²Evidon (now Crownpeak)</item>\n        <item>²Eyewind</item>\n        <item>²Eyewind</item>\n        <item>²F.O.X</item>\n        <item>²Flatiron Media</item>\n        <item>²FlowUp</item>\n        <item>²FluctSDK</item>\n        <item>²GMobi - Go2Reach (General Mobile Corporation)</item>\n        <item>²GMobi - Go2Reach (General Mobile Corporation)</item>\n        <item>²GMobi - Go2Reach (General Mobile Corporation)</item>\n        <item>²GMobi - Go2Reach (General Mobile Corporation)</item>\n        <item>²GMobi - Go2Reach (General Mobile Corporation)</item>\n        <item>²GMobi - Go2Reach (General Mobile Corporation)</item>\n        <item>²GMobi - Go2Reach (General Mobile Corporation)</item>\n        <item>²GMobi - Go2Reach (General Mobile Corporation)</item>\n        <item>²GMobi - Go2Reach (General Mobile Corporation)</item>\n        <item>²GMobi - Go2Reach (General Mobile Corporation)</item>\n        <item>²GMobi - Go2Reach (General Mobile Corporation)</item>\n        <item>²GMobi - Go2Reach (General Mobile Corporation)</item>\n        <item>²GMobi - Go2Reach (General Mobile Corporation)</item>\n        <item>²GMobi - Go2Reach (General Mobile Corporation)</item>\n        <item>²GMobi - Go2Reach (General Mobile Corporation)</item>\n        <item>²GMobi - Go2Reach (General Mobile Corporation)</item>\n        <item>²GMobi - Go2Reach (General Mobile Corporation)</item>\n        <item>²GMobi - Go2Reach (General Mobile Corporation)</item>\n        <item>²GPA KOREA</item>\n        <item>²Gamania Beanfun</item>\n        <item>²Game Sparks</item>\n        <item>²GeoUniq (Cloud4Win)</item>\n        <item>²Google Cloud Audit</item>\n        <item>²Google ML Kit</item>\n        <item>²Google Play Billing Library / Service</item>\n        <item>²Grab Analytics</item>\n        <item>²Gravy Analytics</item>\n        <item>²GreedyGame</item>\n        <item>²GreenRobot</item>\n        <item>²GroundTruth</item>\n        <item>²GrowingIO</item>\n        <item>²Growth Push</item>\n        <item>²Growth Push</item>\n        <item>²HeyTap</item>\n        <item>²HeyTap</item>\n        <item>²Hotmob SDK</item>\n        <item>²Houseads</item>\n        <item>²IAC</item>\n        <item>²IGG.com</item>\n        <item>²IGG.com</item>\n        <item>²IGG.com</item>\n        <item>²IGG.com</item>\n        <item>²IGG.com</item>\n        <item>²IGG.com</item>\n        <item>²IQV</item>\n        <item>²Igexin</item>\n        <item>²InBrainSurveys SDK</item>\n        <item>²Instal</item>\n        <item>²Instal</item>\n        <item>²Instal</item>\n        <item>²Instal</item>\n        <item>²Instal</item>\n        <item>²Instal</item>\n        <item>²Intrasonics</item>\n        <item>²IntroMi</item>\n        <item>²KARTE</item>\n        <item>²Kakao AD SDK</item>\n        <item>²KakaoTalk Link</item>\n        <item>²Kevel (formerly Adzerk)</item>\n        <item>²Komli Mobile (ZestAdz)</item>\n        <item>²LINE Admolin</item>\n        <item>²LINE Ads Five</item>\n        <item>²LINE Telemetry</item>\n        <item>²LINE Telemetry</item>\n        <item>²LINE Telemetry</item>\n        <item>²LeadBolt</item>\n        <item>²LeadBolt</item>\n        <item>²LeadBolt</item>\n        <item>²Liftoff</item>\n        <item>²MEGVII</item>\n        <item>²Madhouse</item>\n        <item>²Malverting/Adfrauds</item>\n        <item>²Malverting/Adfrauds</item>\n        <item>²Malverting/Adfrauds</item>\n        <item>²Malverting/Adfrauds</item>\n        <item>²Malverting/Adfrauds</item>\n        <item>²Malverting/Adfrauds</item>\n        <item>²Malverting/Adfrauds</item>\n        <item>²Malverting/Adfrauds</item>\n        <item>²Malverting/Adfrauds</item>\n        <item>²Malverting/Adfrauds</item>\n        <item>²Malverting/Adfrauds</item>\n        <item>²Malverting/Adfrauds</item>\n        <item>²Malverting/Adfrauds</item>\n        <item>²Malverting/Adfrauds</item>\n        <item>²Malverting/Adfrauds</item>\n        <item>²Malverting/Adfrauds</item>\n        <item>²Malverting/Adfrauds</item>\n        <item>²Malverting/Adfrauds</item>\n        <item>²Malverting/Adfrauds#2</item>\n        <item>²Malverting/Adfrauds#2</item>\n        <item>²Malverting/Adfrauds#2</item>\n        <item>²Malverting/Adfrauds#2</item>\n        <item>²Malverting/Adfrauds#2</item>\n        <item>²Malverting/Adfrauds#2</item>\n        <item>²Malverting/Adfrauds#2</item>\n        <item>²Malverting/Adfrauds#2</item>\n        <item>²Malverting/Adfrauds#2</item>\n        <item>²Malverting/Adfrauds#2</item>\n        <item>²Malverting/Adfrauds#2</item>\n        <item>²Malverting/Adfrauds#2</item>\n        <item>²Mezzomedia AD Platform</item>\n        <item>²Mezzomedia AD Platform</item>\n        <item>²Mezzomedia AD Platform</item>\n        <item>²Mezzomedia AD Platform</item>\n        <item>²Mobclick</item>\n        <item>²Mobincube</item>\n        <item>²Mobiquity Networks</item>\n        <item>²Moblin</item>\n        <item>²Mobon SDK</item>\n        <item>²Mofiler</item>\n        <item>²Mojise</item>\n        <item>²Morgoo Packer</item>\n        <item>²Mozilla Crashreport</item>\n        <item>²NetVelocity Passive SDK</item>\n        <item>²NetVelocity Passive SDK</item>\n        <item>²NewsPic</item>\n        <item>²Ninja Metics</item>\n        <item>²Noah Pass</item>\n        <item>²NoxMobi(AiAdMobi)</item>\n        <item>²ONEstore</item>\n        <item>²Ogury</item>\n        <item>²Ogury</item>\n        <item>²Ogury</item>\n        <item>²Ogury</item>\n        <item>²Onetrust</item>\n        <item>²OpenMeditation</item>\n        <item>²OpenMeditation</item>\n        <item>²OpenUDID</item>\n        <item>²OpenUDID</item>\n        <item>²Openalliance (Huawei ads kit)</item>\n        <item>²Openalliance (Huawei ads kit)</item>\n        <item>²Openalliance (Huawei ads kit)</item>\n        <item>²Opentracker</item>\n        <item>²Outbid</item>\n        <item>²PEANUT LABS</item>\n        <item>²Papaya</item>\n        <item>²Papaya</item>\n        <item>²Parse</item>\n        <item>²Parse</item>\n        <item>²PartyTrack</item>\n        <item>²Phunware Advertising</item>\n        <item>²Pinterest</item>\n        <item>²PlayFab java</item>\n        <item>²Plleti</item>\n        <item>²Pontiflex</item>\n        <item>²Posthog</item>\n        <item>²Profile Passport</item>\n        <item>²Profile Passport</item>\n        <item>²PubNub</item>\n        <item>²Pulsate</item>\n        <item>²Pushy</item>\n        <item>²Qihoo Packer</item>\n        <item>²Qihoo Packer</item>\n        <item>²Qihoo Packer</item>\n        <item>²Quadrant Data Acquisition SDK</item>\n        <item>²Quantumgraph(QGraph)/Appier</item>\n        <item>²Quantumgraph(QGraph)/Appier</item>\n        <item>²Rakuten Analytics SDK</item>\n        <item>²Rakuten Analytics SDK</item>\n        <item>²Rakuten Unified Ads</item>\n        <item>²Rakuten Unified Ads</item>\n        <item>²RevenueCat</item>\n        <item>²Rumble</item>\n        <item>²SAP CDC (Gigya)</item>\n        <item>²SAS</item>\n        <item>²SDKBOX</item>\n        <item>²SNS SDK(bytedance)</item>\n        <item>²Sailthru</item>\n        <item>²Samsung Telemetry</item>\n        <item>²Samsung Telemetry</item>\n        <item>²SaySo Rewards</item>\n        <item>²SaySo Rewards</item>\n        <item>²Score Card Research</item>\n        <item>²Sentry</item>\n        <item>²Sentry</item>\n        <item>²Seventynine</item>\n        <item>²Shuwei</item>\n        <item>²Sino Weibo SDK</item>\n        <item>²Situm SDK</item>\n        <item>²Skillz Android Unity</item>\n        <item>²Skyhook</item>\n        <item>²SmartBeat</item>\n        <item>²SmartyAds</item>\n        <item>²SoundHaund Adverts</item>\n        <item>²Spoteer Arc</item>\n        <item>²Spotify Advertising</item>\n        <item>²Spotify Advertising</item>\n        <item>²Spotify Advertising</item>\n        <item>²Spotify Advertising</item>\n        <item>²Spotify Advertising</item>\n        <item>²Spotify Advertising</item>\n        <item>²Supership</item>\n        <item>²TAPTrack</item>\n        <item>²TAmedia</item>\n        <item>²TJHello ADEasy</item>\n        <item>²TapIt</item>\n        <item>²Tapad</item>\n        <item>²Tapad</item>\n        <item>²Telaria (Tremor Video SDK)</item>\n        <item>²Teliver</item>\n        <item>²Tencent QQ SDK</item>\n        <item>²Tencent QQ SDK</item>\n        <item>²Tencent QQ SDK</item>\n        <item>²Tencent Wechat SDK</item>\n        <item>²Tencent Wechat SDK</item>\n        <item>²Tencent Wechat SDK</item>\n        <item>²TheoremReach</item>\n        <item>²TikTok SDK</item>\n        <item>²TogetherAd</item>\n        <item>²TradPlus</item>\n        <item>²Trillbit</item>\n        <item>²TripleLift</item>\n        <item>²TripleLift</item>\n        <item>²Twitter ads</item>\n        <item>²Twitter ads</item>\n        <item>²Twitter ads</item>\n        <item>²Twitter ads</item>\n        <item>²Twitter ads</item>\n        <item>²UCWeb UC Ads</item>\n        <item>²UCWeb UC Ads</item>\n        <item>²Umeng Common SDK logging</item>\n        <item>²Umeng Common SDK logging</item>\n        <item>²Umeng Common SDK logging</item>\n        <item>²Umeng Mobile tracking SDK</item>\n        <item>²Umeng Push SDK</item>\n        <item>²Umeng Push SDK</item>\n        <item>²Umeng Push SDK</item>\n        <item>²Umeng Push SDK</item>\n        <item>²Unknown Trackers</item>\n        <item>²Unknown Trackers</item>\n        <item>²Unknown Trackers</item>\n        <item>²Unknown Trackers</item>\n        <item>²Unknown Trackers</item>\n        <item>²Unknown Trackers</item>\n        <item>²Unknown Trackers</item>\n        <item>²Unknown Trackers</item>\n        <item>²Unknown Trackers</item>\n        <item>²Unknown Trackers</item>\n        <item>²Unknown Trackers</item>\n        <item>²Unknown Trackers</item>\n        <item>²Unknown Trackers</item>\n        <item>²Unknown Trackers</item>\n        <item>²Unknown Trackers</item>\n        <item>²Unknown Trackers</item>\n        <item>²Unknown Trackers</item>\n        <item>²Unknown Trackers</item>\n        <item>²Usabilla by Salesforce</item>\n        <item>²VServ</item>\n        <item>²Vivo Push SDK</item>\n        <item>²Vodafone NetPerform</item>\n        <item>²WalkMe/Abbi.io</item>\n        <item>²WalkMe/Abbi.io</item>\n        <item>²WalkMe/Abbi.io</item>\n        <item>²WalkMe/Abbi.io</item>\n        <item>²Wannads</item>\n        <item>²WapStart.Plus1</item>\n        <item>²Weibo DeviceID</item>\n        <item>²WonderPush</item>\n        <item>²Woopra</item>\n        <item>²Woorlds</item>\n        <item>²Wortise</item>\n        <item>²Xiaomi Push Service</item>\n        <item>²Xiaomi Push Service</item>\n        <item>²Yahoo!Japan DataShare</item>\n        <item>²Yahoo!Japan DataShare</item>\n        <item>²Yahoo!Japan DataShare</item>\n        <item>²Yahoo!Japan DataShare</item>\n        <item>²Yahoo!Japan DataShare</item>\n        <item>²Yahoo!Japan DataShare</item>\n        <item>²Yahoo!Japan DataShare</item>\n        <item>²Yahoo!Japan DataShare</item>\n        <item>²Yext</item>\n        <item>²Yieldlab</item>\n        <item>²Yougoodtech</item>\n        <item>²Yougoodtech</item>\n        <item>²Youmi</item>\n        <item>²Yueying Crash SDK</item>\n        <item>²Yueying Crash SDK</item>\n        <item>²Zendesk</item>\n        <item>²Zenjoy</item>\n        <item>²Zucks</item>\n        <item>²adboost</item>\n        <item>²appPlant</item>\n        <item>²appTV</item>\n        <item>²appgeneration</item>\n        <item>²ayeT-Studios</item>\n        <item>²beaconstac/NearBee (MobStac Inc.)</item>\n        <item>²deploygate</item>\n        <item>²fineapptech</item>\n        <item>²fineapptech</item>\n        <item>²fineapptech</item>\n        <item>²fineapptech</item>\n        <item>²froger_mcs</item>\n        <item>²i-mobile</item>\n        <item>²iridge popinfo</item>\n        <item>²mTraction (mFaaS)</item>\n        <item>²netmera</item>\n        <item>²pinable</item>\n        <item>²react-native-fabric</item>\n        <item>²tabtale</item>\n    </string-array>\n</resources>"
  },
  {
    "path": "app/src/main/res/values/word_list.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<resources>\n    <!-- Source https://www.eff.org/files/2016/09/08/eff_short_wordlist_1.txt -->\n    <string-array name=\"word_list\">\n        <item>acid</item>\n        <item>acorn</item>\n        <item>acre</item>\n        <item>acts</item>\n        <item>afar</item>\n        <item>affix</item>\n        <item>aged</item>\n        <item>agent</item>\n        <item>agile</item>\n        <item>aging</item>\n        <item>agony</item>\n        <item>ahead</item>\n        <item>aide</item>\n        <item>aids</item>\n        <item>aim</item>\n        <item>ajar</item>\n        <item>alarm</item>\n        <item>alias</item>\n        <item>alibi</item>\n        <item>alien</item>\n        <item>alike</item>\n        <item>alive</item>\n        <item>aloe</item>\n        <item>aloft</item>\n        <item>aloha</item>\n        <item>alone</item>\n        <item>amend</item>\n        <item>amino</item>\n        <item>ample</item>\n        <item>amuse</item>\n        <item>angel</item>\n        <item>anger</item>\n        <item>angle</item>\n        <item>ankle</item>\n        <item>apple</item>\n        <item>april</item>\n        <item>apron</item>\n        <item>aqua</item>\n        <item>area</item>\n        <item>arena</item>\n        <item>argue</item>\n        <item>arise</item>\n        <item>armed</item>\n        <item>armor</item>\n        <item>army</item>\n        <item>aroma</item>\n        <item>array</item>\n        <item>arson</item>\n        <item>art</item>\n        <item>ashen</item>\n        <item>ashes</item>\n        <item>atlas</item>\n        <item>atom</item>\n        <item>attic</item>\n        <item>audio</item>\n        <item>avert</item>\n        <item>avoid</item>\n        <item>awake</item>\n        <item>award</item>\n        <item>awoke</item>\n        <item>axis</item>\n        <item>bacon</item>\n        <item>badge</item>\n        <item>bagel</item>\n        <item>baggy</item>\n        <item>baked</item>\n        <item>baker</item>\n        <item>balmy</item>\n        <item>banjo</item>\n        <item>barge</item>\n        <item>barn</item>\n        <item>bash</item>\n        <item>basil</item>\n        <item>bask</item>\n        <item>batch</item>\n        <item>bath</item>\n        <item>baton</item>\n        <item>bats</item>\n        <item>blade</item>\n        <item>blank</item>\n        <item>blast</item>\n        <item>blaze</item>\n        <item>bleak</item>\n        <item>blend</item>\n        <item>bless</item>\n        <item>blimp</item>\n        <item>blink</item>\n        <item>bloat</item>\n        <item>blob</item>\n        <item>blog</item>\n        <item>blot</item>\n        <item>blunt</item>\n        <item>blurt</item>\n        <item>blush</item>\n        <item>boast</item>\n        <item>boat</item>\n        <item>body</item>\n        <item>boil</item>\n        <item>bok</item>\n        <item>bolt</item>\n        <item>boned</item>\n        <item>boney</item>\n        <item>bonus</item>\n        <item>bony</item>\n        <item>book</item>\n        <item>booth</item>\n        <item>boots</item>\n        <item>boss</item>\n        <item>botch</item>\n        <item>both</item>\n        <item>boxer</item>\n        <item>breed</item>\n        <item>bribe</item>\n        <item>brick</item>\n        <item>bride</item>\n        <item>brim</item>\n        <item>bring</item>\n        <item>brink</item>\n        <item>brisk</item>\n        <item>broad</item>\n        <item>broil</item>\n        <item>broke</item>\n        <item>brook</item>\n        <item>broom</item>\n        <item>brush</item>\n        <item>buck</item>\n        <item>bud</item>\n        <item>buggy</item>\n        <item>bulge</item>\n        <item>bulk</item>\n        <item>bully</item>\n        <item>bunch</item>\n        <item>bunny</item>\n        <item>bunt</item>\n        <item>bush</item>\n        <item>bust</item>\n        <item>busy</item>\n        <item>buzz</item>\n        <item>cable</item>\n        <item>cache</item>\n        <item>cadet</item>\n        <item>cage</item>\n        <item>cake</item>\n        <item>calm</item>\n        <item>cameo</item>\n        <item>canal</item>\n        <item>candy</item>\n        <item>cane</item>\n        <item>canon</item>\n        <item>cape</item>\n        <item>card</item>\n        <item>cargo</item>\n        <item>carol</item>\n        <item>carry</item>\n        <item>carve</item>\n        <item>case</item>\n        <item>cash</item>\n        <item>cause</item>\n        <item>cedar</item>\n        <item>chain</item>\n        <item>chair</item>\n        <item>chant</item>\n        <item>chaos</item>\n        <item>charm</item>\n        <item>chase</item>\n        <item>cheek</item>\n        <item>cheer</item>\n        <item>chef</item>\n        <item>chess</item>\n        <item>chest</item>\n        <item>chew</item>\n        <item>chief</item>\n        <item>chili</item>\n        <item>chill</item>\n        <item>chip</item>\n        <item>chomp</item>\n        <item>chop</item>\n        <item>chow</item>\n        <item>chuck</item>\n        <item>chump</item>\n        <item>chunk</item>\n        <item>churn</item>\n        <item>chute</item>\n        <item>cider</item>\n        <item>cinch</item>\n        <item>city</item>\n        <item>civic</item>\n        <item>civil</item>\n        <item>clad</item>\n        <item>claim</item>\n        <item>clamp</item>\n        <item>clap</item>\n        <item>clash</item>\n        <item>clasp</item>\n        <item>class</item>\n        <item>claw</item>\n        <item>clay</item>\n        <item>clean</item>\n        <item>clear</item>\n        <item>cleat</item>\n        <item>cleft</item>\n        <item>clerk</item>\n        <item>click</item>\n        <item>cling</item>\n        <item>clink</item>\n        <item>clip</item>\n        <item>cloak</item>\n        <item>clock</item>\n        <item>clone</item>\n        <item>cloth</item>\n        <item>cloud</item>\n        <item>clump</item>\n        <item>coach</item>\n        <item>coast</item>\n        <item>coat</item>\n        <item>cod</item>\n        <item>coil</item>\n        <item>coke</item>\n        <item>cola</item>\n        <item>cold</item>\n        <item>colt</item>\n        <item>coma</item>\n        <item>come</item>\n        <item>comic</item>\n        <item>comma</item>\n        <item>cone</item>\n        <item>cope</item>\n        <item>copy</item>\n        <item>coral</item>\n        <item>cork</item>\n        <item>cost</item>\n        <item>cot</item>\n        <item>couch</item>\n        <item>cough</item>\n        <item>cover</item>\n        <item>cozy</item>\n        <item>craft</item>\n        <item>cramp</item>\n        <item>crane</item>\n        <item>crank</item>\n        <item>crate</item>\n        <item>crave</item>\n        <item>crawl</item>\n        <item>crazy</item>\n        <item>creme</item>\n        <item>crepe</item>\n        <item>crept</item>\n        <item>crib</item>\n        <item>cried</item>\n        <item>crisp</item>\n        <item>crook</item>\n        <item>crop</item>\n        <item>cross</item>\n        <item>crowd</item>\n        <item>crown</item>\n        <item>crumb</item>\n        <item>crush</item>\n        <item>crust</item>\n        <item>cub</item>\n        <item>cult</item>\n        <item>cupid</item>\n        <item>cure</item>\n        <item>curl</item>\n        <item>curry</item>\n        <item>curse</item>\n        <item>curve</item>\n        <item>curvy</item>\n        <item>cushy</item>\n        <item>cut</item>\n        <item>cycle</item>\n        <item>dab</item>\n        <item>dad</item>\n        <item>daily</item>\n        <item>dairy</item>\n        <item>daisy</item>\n        <item>dance</item>\n        <item>dandy</item>\n        <item>darn</item>\n        <item>dart</item>\n        <item>dash</item>\n        <item>data</item>\n        <item>date</item>\n        <item>dawn</item>\n        <item>deaf</item>\n        <item>deal</item>\n        <item>dean</item>\n        <item>debit</item>\n        <item>debt</item>\n        <item>debug</item>\n        <item>decaf</item>\n        <item>decal</item>\n        <item>decay</item>\n        <item>deck</item>\n        <item>decor</item>\n        <item>decoy</item>\n        <item>deed</item>\n        <item>delay</item>\n        <item>denim</item>\n        <item>dense</item>\n        <item>dent</item>\n        <item>depth</item>\n        <item>derby</item>\n        <item>desk</item>\n        <item>dial</item>\n        <item>diary</item>\n        <item>dice</item>\n        <item>dig</item>\n        <item>dill</item>\n        <item>dime</item>\n        <item>dimly</item>\n        <item>diner</item>\n        <item>dingy</item>\n        <item>disco</item>\n        <item>dish</item>\n        <item>disk</item>\n        <item>ditch</item>\n        <item>ditzy</item>\n        <item>dizzy</item>\n        <item>dock</item>\n        <item>dodge</item>\n        <item>doing</item>\n        <item>doll</item>\n        <item>dome</item>\n        <item>donor</item>\n        <item>donut</item>\n        <item>dose</item>\n        <item>dot</item>\n        <item>dove</item>\n        <item>down</item>\n        <item>dowry</item>\n        <item>doze</item>\n        <item>drab</item>\n        <item>drama</item>\n        <item>drank</item>\n        <item>draw</item>\n        <item>dress</item>\n        <item>dried</item>\n        <item>drift</item>\n        <item>drill</item>\n        <item>drive</item>\n        <item>drone</item>\n        <item>droop</item>\n        <item>drove</item>\n        <item>drown</item>\n        <item>drum</item>\n        <item>dry</item>\n        <item>duck</item>\n        <item>duct</item>\n        <item>dude</item>\n        <item>dug</item>\n        <item>duke</item>\n        <item>duo</item>\n        <item>dusk</item>\n        <item>dust</item>\n        <item>duty</item>\n        <item>dwarf</item>\n        <item>dwell</item>\n        <item>eagle</item>\n        <item>early</item>\n        <item>earth</item>\n        <item>easel</item>\n        <item>east</item>\n        <item>eaten</item>\n        <item>eats</item>\n        <item>ebay</item>\n        <item>ebony</item>\n        <item>ebook</item>\n        <item>echo</item>\n        <item>edge</item>\n        <item>eel</item>\n        <item>eject</item>\n        <item>elbow</item>\n        <item>elder</item>\n        <item>elf</item>\n        <item>elk</item>\n        <item>elm</item>\n        <item>elope</item>\n        <item>elude</item>\n        <item>elves</item>\n        <item>email</item>\n        <item>emit</item>\n        <item>empty</item>\n        <item>emu</item>\n        <item>enter</item>\n        <item>entry</item>\n        <item>envoy</item>\n        <item>equal</item>\n        <item>erase</item>\n        <item>error</item>\n        <item>erupt</item>\n        <item>essay</item>\n        <item>etch</item>\n        <item>evade</item>\n        <item>even</item>\n        <item>evict</item>\n        <item>evil</item>\n        <item>evoke</item>\n        <item>exact</item>\n        <item>exit</item>\n        <item>fable</item>\n        <item>faced</item>\n        <item>fact</item>\n        <item>fade</item>\n        <item>fall</item>\n        <item>false</item>\n        <item>fancy</item>\n        <item>fang</item>\n        <item>fax</item>\n        <item>feast</item>\n        <item>feed</item>\n        <item>femur</item>\n        <item>fence</item>\n        <item>fend</item>\n        <item>ferry</item>\n        <item>fetal</item>\n        <item>fetch</item>\n        <item>fever</item>\n        <item>fiber</item>\n        <item>fifth</item>\n        <item>fifty</item>\n        <item>film</item>\n        <item>filth</item>\n        <item>final</item>\n        <item>finch</item>\n        <item>fit</item>\n        <item>five</item>\n        <item>flag</item>\n        <item>flaky</item>\n        <item>flame</item>\n        <item>flap</item>\n        <item>flask</item>\n        <item>fled</item>\n        <item>flick</item>\n        <item>fling</item>\n        <item>flint</item>\n        <item>flip</item>\n        <item>flirt</item>\n        <item>float</item>\n        <item>flock</item>\n        <item>flop</item>\n        <item>floss</item>\n        <item>flyer</item>\n        <item>foam</item>\n        <item>foe</item>\n        <item>fog</item>\n        <item>foil</item>\n        <item>folic</item>\n        <item>folk</item>\n        <item>food</item>\n        <item>fool</item>\n        <item>found</item>\n        <item>fox</item>\n        <item>foyer</item>\n        <item>frail</item>\n        <item>frame</item>\n        <item>fray</item>\n        <item>fresh</item>\n        <item>fried</item>\n        <item>frill</item>\n        <item>frisk</item>\n        <item>from</item>\n        <item>front</item>\n        <item>frost</item>\n        <item>froth</item>\n        <item>frown</item>\n        <item>froze</item>\n        <item>fruit</item>\n        <item>gag</item>\n        <item>gains</item>\n        <item>gala</item>\n        <item>game</item>\n        <item>gap</item>\n        <item>gas</item>\n        <item>gave</item>\n        <item>gear</item>\n        <item>gecko</item>\n        <item>geek</item>\n        <item>gem</item>\n        <item>genre</item>\n        <item>gift</item>\n        <item>gig</item>\n        <item>gills</item>\n        <item>given</item>\n        <item>giver</item>\n        <item>glad</item>\n        <item>glass</item>\n        <item>glide</item>\n        <item>gloss</item>\n        <item>glove</item>\n        <item>glow</item>\n        <item>glue</item>\n        <item>goal</item>\n        <item>going</item>\n        <item>golf</item>\n        <item>gong</item>\n        <item>good</item>\n        <item>gooey</item>\n        <item>goofy</item>\n        <item>gore</item>\n        <item>gown</item>\n        <item>grab</item>\n        <item>grain</item>\n        <item>grant</item>\n        <item>grape</item>\n        <item>graph</item>\n        <item>grasp</item>\n        <item>grass</item>\n        <item>grave</item>\n        <item>gravy</item>\n        <item>gray</item>\n        <item>green</item>\n        <item>greet</item>\n        <item>grew</item>\n        <item>grid</item>\n        <item>grief</item>\n        <item>grill</item>\n        <item>grip</item>\n        <item>grit</item>\n        <item>groom</item>\n        <item>grope</item>\n        <item>growl</item>\n        <item>grub</item>\n        <item>grunt</item>\n        <item>guide</item>\n        <item>gulf</item>\n        <item>gulp</item>\n        <item>gummy</item>\n        <item>guru</item>\n        <item>gush</item>\n        <item>gut</item>\n        <item>guy</item>\n        <item>habit</item>\n        <item>half</item>\n        <item>halo</item>\n        <item>halt</item>\n        <item>happy</item>\n        <item>harm</item>\n        <item>hash</item>\n        <item>hasty</item>\n        <item>hatch</item>\n        <item>hate</item>\n        <item>haven</item>\n        <item>hazel</item>\n        <item>hazy</item>\n        <item>heap</item>\n        <item>heat</item>\n        <item>heave</item>\n        <item>hedge</item>\n        <item>hefty</item>\n        <item>help</item>\n        <item>herbs</item>\n        <item>hers</item>\n        <item>hub</item>\n        <item>hug</item>\n        <item>hula</item>\n        <item>hull</item>\n        <item>human</item>\n        <item>humid</item>\n        <item>hump</item>\n        <item>hung</item>\n        <item>hunk</item>\n        <item>hunt</item>\n        <item>hurry</item>\n        <item>hurt</item>\n        <item>hush</item>\n        <item>hut</item>\n        <item>ice</item>\n        <item>icing</item>\n        <item>icon</item>\n        <item>icy</item>\n        <item>igloo</item>\n        <item>image</item>\n        <item>ion</item>\n        <item>iron</item>\n        <item>islam</item>\n        <item>issue</item>\n        <item>item</item>\n        <item>ivory</item>\n        <item>ivy</item>\n        <item>jab</item>\n        <item>jam</item>\n        <item>jaws</item>\n        <item>jazz</item>\n        <item>jeep</item>\n        <item>jelly</item>\n        <item>jet</item>\n        <item>jiffy</item>\n        <item>job</item>\n        <item>jog</item>\n        <item>jolly</item>\n        <item>jolt</item>\n        <item>jot</item>\n        <item>joy</item>\n        <item>judge</item>\n        <item>juice</item>\n        <item>juicy</item>\n        <item>july</item>\n        <item>jumbo</item>\n        <item>jump</item>\n        <item>junky</item>\n        <item>juror</item>\n        <item>jury</item>\n        <item>keep</item>\n        <item>keg</item>\n        <item>kept</item>\n        <item>kick</item>\n        <item>kilt</item>\n        <item>king</item>\n        <item>kite</item>\n        <item>kitty</item>\n        <item>kiwi</item>\n        <item>knee</item>\n        <item>knelt</item>\n        <item>koala</item>\n        <item>kung</item>\n        <item>ladle</item>\n        <item>lady</item>\n        <item>lair</item>\n        <item>lake</item>\n        <item>lance</item>\n        <item>land</item>\n        <item>lapel</item>\n        <item>large</item>\n        <item>lash</item>\n        <item>lasso</item>\n        <item>last</item>\n        <item>latch</item>\n        <item>late</item>\n        <item>lazy</item>\n        <item>left</item>\n        <item>legal</item>\n        <item>lemon</item>\n        <item>lend</item>\n        <item>lens</item>\n        <item>lent</item>\n        <item>level</item>\n        <item>lever</item>\n        <item>lid</item>\n        <item>life</item>\n        <item>lift</item>\n        <item>lilac</item>\n        <item>lily</item>\n        <item>limb</item>\n        <item>limes</item>\n        <item>line</item>\n        <item>lint</item>\n        <item>lion</item>\n        <item>lip</item>\n        <item>list</item>\n        <item>lived</item>\n        <item>liver</item>\n        <item>lunar</item>\n        <item>lunch</item>\n        <item>lung</item>\n        <item>lurch</item>\n        <item>lure</item>\n        <item>lurk</item>\n        <item>lying</item>\n        <item>lyric</item>\n        <item>mace</item>\n        <item>maker</item>\n        <item>malt</item>\n        <item>mama</item>\n        <item>mango</item>\n        <item>manor</item>\n        <item>many</item>\n        <item>map</item>\n        <item>march</item>\n        <item>mardi</item>\n        <item>marry</item>\n        <item>mash</item>\n        <item>match</item>\n        <item>mate</item>\n        <item>math</item>\n        <item>moan</item>\n        <item>mocha</item>\n        <item>moist</item>\n        <item>mold</item>\n        <item>mom</item>\n        <item>moody</item>\n        <item>mop</item>\n        <item>morse</item>\n        <item>most</item>\n        <item>motor</item>\n        <item>motto</item>\n        <item>mount</item>\n        <item>mouse</item>\n        <item>mousy</item>\n        <item>mouth</item>\n        <item>move</item>\n        <item>movie</item>\n        <item>mower</item>\n        <item>mud</item>\n        <item>mug</item>\n        <item>mulch</item>\n        <item>mule</item>\n        <item>mull</item>\n        <item>mumbo</item>\n        <item>mummy</item>\n        <item>mural</item>\n        <item>muse</item>\n        <item>music</item>\n        <item>musky</item>\n        <item>mute</item>\n        <item>nacho</item>\n        <item>nag</item>\n        <item>nail</item>\n        <item>name</item>\n        <item>nanny</item>\n        <item>nap</item>\n        <item>navy</item>\n        <item>near</item>\n        <item>neat</item>\n        <item>neon</item>\n        <item>nerd</item>\n        <item>nest</item>\n        <item>net</item>\n        <item>next</item>\n        <item>niece</item>\n        <item>ninth</item>\n        <item>nutty</item>\n        <item>oak</item>\n        <item>oasis</item>\n        <item>oat</item>\n        <item>ocean</item>\n        <item>oil</item>\n        <item>old</item>\n        <item>olive</item>\n        <item>omen</item>\n        <item>onion</item>\n        <item>only</item>\n        <item>ooze</item>\n        <item>opal</item>\n        <item>open</item>\n        <item>opera</item>\n        <item>opt</item>\n        <item>otter</item>\n        <item>ouch</item>\n        <item>ounce</item>\n        <item>outer</item>\n        <item>oval</item>\n        <item>oven</item>\n        <item>owl</item>\n        <item>ozone</item>\n        <item>pace</item>\n        <item>pagan</item>\n        <item>pager</item>\n        <item>palm</item>\n        <item>panda</item>\n        <item>panic</item>\n        <item>pants</item>\n        <item>panty</item>\n        <item>paper</item>\n        <item>park</item>\n        <item>party</item>\n        <item>pasta</item>\n        <item>patch</item>\n        <item>path</item>\n        <item>patio</item>\n        <item>payer</item>\n        <item>pecan</item>\n        <item>penny</item>\n        <item>pep</item>\n        <item>perch</item>\n        <item>perky</item>\n        <item>perm</item>\n        <item>pest</item>\n        <item>petal</item>\n        <item>petri</item>\n        <item>petty</item>\n        <item>photo</item>\n        <item>plank</item>\n        <item>plant</item>\n        <item>plaza</item>\n        <item>plead</item>\n        <item>plot</item>\n        <item>plow</item>\n        <item>pluck</item>\n        <item>plug</item>\n        <item>plus</item>\n        <item>poach</item>\n        <item>pod</item>\n        <item>poem</item>\n        <item>poet</item>\n        <item>pogo</item>\n        <item>point</item>\n        <item>poise</item>\n        <item>poker</item>\n        <item>polar</item>\n        <item>polio</item>\n        <item>polka</item>\n        <item>polo</item>\n        <item>pond</item>\n        <item>pony</item>\n        <item>poppy</item>\n        <item>pork</item>\n        <item>poser</item>\n        <item>pouch</item>\n        <item>pound</item>\n        <item>pout</item>\n        <item>power</item>\n        <item>prank</item>\n        <item>press</item>\n        <item>print</item>\n        <item>prior</item>\n        <item>prism</item>\n        <item>prize</item>\n        <item>probe</item>\n        <item>prong</item>\n        <item>proof</item>\n        <item>props</item>\n        <item>prude</item>\n        <item>prune</item>\n        <item>pry</item>\n        <item>pug</item>\n        <item>pull</item>\n        <item>pulp</item>\n        <item>pulse</item>\n        <item>puma</item>\n        <item>punch</item>\n        <item>punk</item>\n        <item>pupil</item>\n        <item>puppy</item>\n        <item>purr</item>\n        <item>purse</item>\n        <item>push</item>\n        <item>putt</item>\n        <item>quack</item>\n        <item>quake</item>\n        <item>query</item>\n        <item>quiet</item>\n        <item>quill</item>\n        <item>quilt</item>\n        <item>quit</item>\n        <item>quota</item>\n        <item>quote</item>\n        <item>rabid</item>\n        <item>race</item>\n        <item>rack</item>\n        <item>radar</item>\n        <item>radio</item>\n        <item>raft</item>\n        <item>rage</item>\n        <item>raid</item>\n        <item>rail</item>\n        <item>rake</item>\n        <item>rally</item>\n        <item>ramp</item>\n        <item>ranch</item>\n        <item>range</item>\n        <item>rank</item>\n        <item>rant</item>\n        <item>rash</item>\n        <item>raven</item>\n        <item>reach</item>\n        <item>react</item>\n        <item>ream</item>\n        <item>rebel</item>\n        <item>recap</item>\n        <item>relax</item>\n        <item>relay</item>\n        <item>relic</item>\n        <item>remix</item>\n        <item>repay</item>\n        <item>repel</item>\n        <item>reply</item>\n        <item>rerun</item>\n        <item>reset</item>\n        <item>rhyme</item>\n        <item>rice</item>\n        <item>rich</item>\n        <item>ride</item>\n        <item>rigid</item>\n        <item>rigor</item>\n        <item>rinse</item>\n        <item>riot</item>\n        <item>ripen</item>\n        <item>rise</item>\n        <item>risk</item>\n        <item>ritzy</item>\n        <item>rival</item>\n        <item>river</item>\n        <item>roast</item>\n        <item>robe</item>\n        <item>robin</item>\n        <item>rock</item>\n        <item>rogue</item>\n        <item>roman</item>\n        <item>romp</item>\n        <item>rope</item>\n        <item>rover</item>\n        <item>royal</item>\n        <item>ruby</item>\n        <item>rug</item>\n        <item>ruin</item>\n        <item>rule</item>\n        <item>runny</item>\n        <item>rush</item>\n        <item>rust</item>\n        <item>rut</item>\n        <item>sadly</item>\n        <item>sage</item>\n        <item>said</item>\n        <item>saint</item>\n        <item>salad</item>\n        <item>salon</item>\n        <item>salsa</item>\n        <item>salt</item>\n        <item>same</item>\n        <item>sandy</item>\n        <item>santa</item>\n        <item>satin</item>\n        <item>sauna</item>\n        <item>saved</item>\n        <item>savor</item>\n        <item>sax</item>\n        <item>say</item>\n        <item>scale</item>\n        <item>scam</item>\n        <item>scan</item>\n        <item>scare</item>\n        <item>scarf</item>\n        <item>scary</item>\n        <item>scoff</item>\n        <item>scold</item>\n        <item>scoop</item>\n        <item>scoot</item>\n        <item>scope</item>\n        <item>score</item>\n        <item>scorn</item>\n        <item>scout</item>\n        <item>scowl</item>\n        <item>scrap</item>\n        <item>scrub</item>\n        <item>scuba</item>\n        <item>scuff</item>\n        <item>sect</item>\n        <item>sedan</item>\n        <item>self</item>\n        <item>send</item>\n        <item>sepia</item>\n        <item>serve</item>\n        <item>set</item>\n        <item>seven</item>\n        <item>shack</item>\n        <item>shade</item>\n        <item>shady</item>\n        <item>shaft</item>\n        <item>shaky</item>\n        <item>sham</item>\n        <item>shape</item>\n        <item>share</item>\n        <item>sharp</item>\n        <item>shed</item>\n        <item>sheep</item>\n        <item>sheet</item>\n        <item>shelf</item>\n        <item>shell</item>\n        <item>shine</item>\n        <item>shiny</item>\n        <item>ship</item>\n        <item>shirt</item>\n        <item>shock</item>\n        <item>shop</item>\n        <item>shore</item>\n        <item>shout</item>\n        <item>shove</item>\n        <item>shown</item>\n        <item>showy</item>\n        <item>shred</item>\n        <item>shrug</item>\n        <item>shun</item>\n        <item>shush</item>\n        <item>shut</item>\n        <item>shy</item>\n        <item>sift</item>\n        <item>silk</item>\n        <item>silly</item>\n        <item>silo</item>\n        <item>sip</item>\n        <item>siren</item>\n        <item>sixth</item>\n        <item>size</item>\n        <item>skate</item>\n        <item>skew</item>\n        <item>skid</item>\n        <item>skier</item>\n        <item>skies</item>\n        <item>skip</item>\n        <item>skirt</item>\n        <item>skit</item>\n        <item>sky</item>\n        <item>slab</item>\n        <item>slack</item>\n        <item>slain</item>\n        <item>slam</item>\n        <item>slang</item>\n        <item>slash</item>\n        <item>slate</item>\n        <item>slaw</item>\n        <item>sled</item>\n        <item>sleek</item>\n        <item>sleep</item>\n        <item>sleet</item>\n        <item>slept</item>\n        <item>slice</item>\n        <item>slick</item>\n        <item>slimy</item>\n        <item>sling</item>\n        <item>slip</item>\n        <item>slit</item>\n        <item>slob</item>\n        <item>slot</item>\n        <item>slug</item>\n        <item>slum</item>\n        <item>slurp</item>\n        <item>slush</item>\n        <item>small</item>\n        <item>smash</item>\n        <item>smell</item>\n        <item>smile</item>\n        <item>smirk</item>\n        <item>smog</item>\n        <item>snack</item>\n        <item>snap</item>\n        <item>snare</item>\n        <item>snarl</item>\n        <item>sneak</item>\n        <item>sneer</item>\n        <item>sniff</item>\n        <item>snore</item>\n        <item>snort</item>\n        <item>snout</item>\n        <item>snowy</item>\n        <item>snub</item>\n        <item>snuff</item>\n        <item>speak</item>\n        <item>speed</item>\n        <item>spend</item>\n        <item>spent</item>\n        <item>spew</item>\n        <item>spied</item>\n        <item>spill</item>\n        <item>spiny</item>\n        <item>spoil</item>\n        <item>spoke</item>\n        <item>spoof</item>\n        <item>spool</item>\n        <item>spoon</item>\n        <item>sport</item>\n        <item>spot</item>\n        <item>spout</item>\n        <item>spray</item>\n        <item>spree</item>\n        <item>spur</item>\n        <item>squad</item>\n        <item>squat</item>\n        <item>squid</item>\n        <item>stack</item>\n        <item>staff</item>\n        <item>stage</item>\n        <item>stain</item>\n        <item>stall</item>\n        <item>stamp</item>\n        <item>stand</item>\n        <item>stank</item>\n        <item>stark</item>\n        <item>start</item>\n        <item>stash</item>\n        <item>state</item>\n        <item>stays</item>\n        <item>steam</item>\n        <item>steep</item>\n        <item>stem</item>\n        <item>step</item>\n        <item>stew</item>\n        <item>stick</item>\n        <item>sting</item>\n        <item>stir</item>\n        <item>stock</item>\n        <item>stole</item>\n        <item>stomp</item>\n        <item>stony</item>\n        <item>stood</item>\n        <item>stool</item>\n        <item>stoop</item>\n        <item>stop</item>\n        <item>storm</item>\n        <item>stout</item>\n        <item>stove</item>\n        <item>straw</item>\n        <item>stray</item>\n        <item>strut</item>\n        <item>stuck</item>\n        <item>stud</item>\n        <item>stuff</item>\n        <item>stump</item>\n        <item>stung</item>\n        <item>stunt</item>\n        <item>suds</item>\n        <item>sugar</item>\n        <item>sulk</item>\n        <item>surf</item>\n        <item>sushi</item>\n        <item>swab</item>\n        <item>swan</item>\n        <item>swarm</item>\n        <item>sway</item>\n        <item>swear</item>\n        <item>sweat</item>\n        <item>sweep</item>\n        <item>swell</item>\n        <item>swept</item>\n        <item>swim</item>\n        <item>swing</item>\n        <item>swipe</item>\n        <item>swirl</item>\n        <item>swoop</item>\n        <item>swore</item>\n        <item>syrup</item>\n        <item>tacky</item>\n        <item>taco</item>\n        <item>tag</item>\n        <item>take</item>\n        <item>tall</item>\n        <item>talon</item>\n        <item>tamer</item>\n        <item>tank</item>\n        <item>taper</item>\n        <item>taps</item>\n        <item>tarot</item>\n        <item>tart</item>\n        <item>task</item>\n        <item>taste</item>\n        <item>tasty</item>\n        <item>taunt</item>\n        <item>thank</item>\n        <item>thaw</item>\n        <item>theft</item>\n        <item>theme</item>\n        <item>thigh</item>\n        <item>thing</item>\n        <item>think</item>\n        <item>thong</item>\n        <item>thorn</item>\n        <item>those</item>\n        <item>throb</item>\n        <item>thud</item>\n        <item>thumb</item>\n        <item>thump</item>\n        <item>thus</item>\n        <item>tiara</item>\n        <item>tidal</item>\n        <item>tidy</item>\n        <item>tiger</item>\n        <item>tile</item>\n        <item>tilt</item>\n        <item>tint</item>\n        <item>tiny</item>\n        <item>trace</item>\n        <item>track</item>\n        <item>trade</item>\n        <item>train</item>\n        <item>trait</item>\n        <item>trap</item>\n        <item>trash</item>\n        <item>tray</item>\n        <item>treat</item>\n        <item>tree</item>\n        <item>trek</item>\n        <item>trend</item>\n        <item>trial</item>\n        <item>tribe</item>\n        <item>trick</item>\n        <item>trio</item>\n        <item>trout</item>\n        <item>truce</item>\n        <item>truck</item>\n        <item>trump</item>\n        <item>trunk</item>\n        <item>try</item>\n        <item>tug</item>\n        <item>tulip</item>\n        <item>tummy</item>\n        <item>turf</item>\n        <item>tusk</item>\n        <item>tutor</item>\n        <item>tutu</item>\n        <item>tux</item>\n        <item>tweak</item>\n        <item>tweet</item>\n        <item>twice</item>\n        <item>twine</item>\n        <item>twins</item>\n        <item>twirl</item>\n        <item>twist</item>\n        <item>uncle</item>\n        <item>uncut</item>\n        <item>undo</item>\n        <item>unify</item>\n        <item>union</item>\n        <item>unit</item>\n        <item>untie</item>\n        <item>upon</item>\n        <item>upper</item>\n        <item>urban</item>\n        <item>used</item>\n        <item>user</item>\n        <item>usher</item>\n        <item>utter</item>\n        <item>value</item>\n        <item>vapor</item>\n        <item>vegan</item>\n        <item>venue</item>\n        <item>verse</item>\n        <item>vest</item>\n        <item>veto</item>\n        <item>vice</item>\n        <item>video</item>\n        <item>view</item>\n        <item>viral</item>\n        <item>virus</item>\n        <item>visa</item>\n        <item>visor</item>\n        <item>vixen</item>\n        <item>vocal</item>\n        <item>voice</item>\n        <item>void</item>\n        <item>volt</item>\n        <item>voter</item>\n        <item>vowel</item>\n        <item>wad</item>\n        <item>wafer</item>\n        <item>wager</item>\n        <item>wages</item>\n        <item>wagon</item>\n        <item>wake</item>\n        <item>walk</item>\n        <item>wand</item>\n        <item>wasp</item>\n        <item>watch</item>\n        <item>water</item>\n        <item>wavy</item>\n        <item>wheat</item>\n        <item>whiff</item>\n        <item>whole</item>\n        <item>whoop</item>\n        <item>wick</item>\n        <item>widen</item>\n        <item>widow</item>\n        <item>width</item>\n        <item>wife</item>\n        <item>wifi</item>\n        <item>wilt</item>\n        <item>wimp</item>\n        <item>wind</item>\n        <item>wing</item>\n        <item>wink</item>\n        <item>wipe</item>\n        <item>wired</item>\n        <item>wiry</item>\n        <item>wise</item>\n        <item>wish</item>\n        <item>wispy</item>\n        <item>wok</item>\n        <item>wolf</item>\n        <item>womb</item>\n        <item>wool</item>\n        <item>woozy</item>\n        <item>word</item>\n        <item>work</item>\n        <item>worry</item>\n        <item>wound</item>\n        <item>woven</item>\n        <item>wrath</item>\n        <item>wreck</item>\n        <item>wrist</item>\n        <item>xerox</item>\n        <item>yahoo</item>\n        <item>yam</item>\n        <item>yard</item>\n        <item>year</item>\n        <item>yeast</item>\n        <item>yelp</item>\n        <item>yield</item>\n        <item>yo</item>\n        <item>yodel</item>\n        <item>yoga</item>\n        <item>yoyo</item>\n        <item>yummy</item>\n        <item>zebra</item>\n        <item>zero</item>\n        <item>zesty</item>\n        <item>zippy</item>\n        <item>zone</item>\n        <item>zoom</item>\n    </string-array>\n</resources>"
  },
  {
    "path": "app/src/main/res/values-ar/disclaimer.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- SPDX-License-Identifier: GPL-3.0-or-later --><resources>\n    <string name=\"disclaimer_header\">اخلاء المسؤوليه</string>\n    <string name=\"disclaimer_footer\">© 2020-2024 منتشر الاسلام</string>\n    <string name=\"disclaimer_exit\">خروج</string>\n    <string name=\"disclaimer_agree\">أنا موافق</string>\n    <string name=\"disclaimer_agree_forever\">لا تظهر هذا مرة أخرى</string>\n    <string name=\"disclaimer_body\">يوفر مدير التطبيقات وظائف الجذر التي قد تضر جهازك إذا تم استخدامه بشكل غير صحيح. مدير التطبيق غير مسؤول عن أي أضرار تم إجراؤها باستخدام هذا التطبيق. إذا كنت لا تدرك تماما كيف يعمل الجذر ثم يجب تجنب استخدام خيارات الجذر حتى كنت على علم تام بالمخاطر.\n\\n\n\\nأي رابط أقدمه إلى التطبيقات والمواقع الأخرى هو لصالح المستخدمين. أنا لست مسؤولا عن أي محتوى قد تجده من خلال الذهاب على الروابط الخارجية.\n\\n\n\\nباستخدام مدير التطبيقات، فإنك تقبل المسؤولية الكاملة عن استخدامك الخاص ولا تقبل أي أضرار أو مطالبات أو قيمة نقدية سيتم منحها بسبب سوء الاستخدام.\n\\n\n\\nباستخدام هذا التطبيق، فإنك تقبل كل المسؤولية استخدامه وتوافق على أنني لست مسؤولا عن أي إجراءات تقوم بها التي لها تأثير سلبي على جهازك.</string>\n</resources>"
  },
  {
    "path": "app/src/main/res/values-ar/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- SPDX-License-Identifier: GPL-3.0-or-later --><resources xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:tools=\"http://schemas.android.com/tools\">\n    <string name=\"_lang_tag\" translatable=\"false\">ar</string>\n    <string name=\"app_signing_install_without_data_loss\">إذا قمت بإيقاف تشغيل التحقق من التوقيع ، يمكنك استخدام خيار <b> تثبيت </b> فقط لتثبيت التطبيق دون فقدان البيانات.</string>\n    <string name=\"ssaid_info\">SSAID (<tt>Settings.Secure.ANDROID_ID</tt>) هو معرف جهاز معين لكل تطبيق (من Android 8 \\\"Oreo\\\" فصاعدا). يتم استخدامه على نطاق واسع من قبل التطبيقات لتتبع المستخدمين.</string>\n    <string name=\"backup_skip_signature_checks_description\">استعادة النسخ الاحتياطية التي تفشل إما التحقق من المجموع الاختباري أو لها توقيعات APK مختلفة عن النسخ الاحتياطية السابقة الخاصة بهم.</string>\n    <string name=\"input_app_ops_description_profile\">أدخل أسماء عمليات التطبيق و / أو الثوابت بمسافات ، على سبيل المثال <tt> WAKE_LOCK 63 72 CAMERA </tt> إلخ. استخدم <tt> * </tt> للتقدم لجميع عمليات التطبيق التي تمت تهيئتها.</string>\n    <string name=\"input_backup_name_description\">يجب ألا يبدأ اسم النسخة الاحتياطية برقم ولا يجب أن يحتوي على مسافات. اتركه فارغًا إذا كنت تريد استخدام التاريخ والوقت الحالي.</string>\n    <string name=\"pref_import_existing_msg\">أضف مكونات تم تعطيلها بواسطة تطبيقات أخرى إلى App Manager. كن حذرا عند استخدام هذه الأداة كما يمكن أن يكون هناك العديد من الإيجابيات الكاذبة. اختر فقط التطبيقات التي تكون متأكدًا بشأنها.</string>\n    <string name=\"input_keystore_pass_description\">أدخل كلمة مرور سجل المفاتيح App Manager. إذا كنت ترى هذا للمرة الأولى، فالرجاء استخدام منشئ كلمة المرور لإنشاء كلمة مرور وحفظها في مكان آمن قبل إدخالها هنا.</string>\n    <string name=\"backup_apps_with_changes_msg\">إعادة النسخ الاحتياطية للتطبيقات مع التغييرات منذ آخر نسخ احتياطي. وهي تشمل التغييرات في الحجم والإصدار ووقت التشغيل الأخير.</string>\n    <string name=\"launch\">تشغيل</string>\n    <string name=\"activities\">الأنشطة</string>\n    <string name=\"require_no_permission\">لا يوجد إذن مطلوب</string>\n    <string name=\"permissions\">يستخدم الأذونات</string>\n    <string name=\"uninstall\">إلغاء التثبيت</string>\n    <string name=\"test_only\">اختبار فقط</string>\n    <string name=\"debuggable\">قابل للتصحيح</string>\n    <string name=\"updated_app\">تم تحديثه</string>\n    <string name=\"requested_large_heap\">كومة كبيرة</string>\n    <string name=\"process_name\">اسم العملية</string>\n    <string name=\"dev_protected_data_dir\">مسار البيانات المحمي بالجهاز</string>\n    <string name=\"native_library_dir\">مسار مكتبة JNI الأصلي</string>\n    <string name=\"search\">بحث</string>\n    <string name=\"menu_apply_rules\">تطبيق القواعد</string>\n    <string name=\"menu_remove_rules\">إزالة القواعد</string>\n    <string name=\"failed_to_extract_apk_file\">تعذر استخراج ملف APK</string>\n    <string name=\"share_apk\">مشاركة APK</string>\n    <string name=\"grant_usage_acess_message\">يستخدم لعرض معلومات استخدام التطبيق.</string>\n    <string name=\"grant_usage_access\">منح حق الوصول إلى الاستخدام</string>\n    <string name=\"go\">اذهب</string>\n    <string name=\"go_back\">عودة</string>\n    <string name=\"usage_less_than_a_minute\">أقل من دقيقة</string>\n    <string name=\"usage_7_days\">آخر ٧ أيام</string>\n    <string name=\"usage_today\">اليوم</string>\n    <string name=\"usage_weekly\">اسبوعي</string>\n    <string name=\"app_usage\">استخدام التطبيق</string>\n    <string name=\"no_tracker_class\">لا توجد فصول تعقب</string>\n    <string name=\"no_shared_libs\">لا توجد مكتبات مشتركة</string>\n    <string name=\"all_classes\">جميع الفئات</string>\n    <string name=\"tracker_classes\">فئات التتبع</string>\n    <string name=\"tracker_details\">تفاصيل برمجيات التتبع</string>\n    <string name=\"found_trackers\">برمجيات التتبع التي تم العثور عليها:</string>\n    <string name=\"toggle_class_listing\">تبديل قائمة الفصل</string>\n    <string name=\"class_viewer\">عارض الفصل</string>\n    <string name=\"word_wrap\">تفعيل التفاف النص</string>\n    <string name=\"credits_message\">لمؤلفي\n\\n- مشروع Android مفتوح المصدر\n\\n- <a href=\"https://github.com/zhaobozhen/libraries\"> مكتبات شراب مسكر </a>\n\\n- <a href=\"https://github.com/butzist/ActivityLauncher\"> مشغل النشاط </a>\n\\n- <a href=\"https://bitbucket.org/oF2pks/fdroid-applications-info\"> معلومات Apps_packages </a>\n\\n- <a href=\"https://github.com/zhaobao/AppsMonitor\"> AppsMonitor </a>\n\\n- <a href=\"https://github.com/8enet/AppOpsX\"> AppOpsX </a>\n\\n- مكتبة سجل التغيير <a href=\"https://github.com/gabrielemariotti/changeloglib\"> </a>\n\\n- <a href=\"https://bitbucket.org/oF2pks/fdroid-classyshark3xodus\"> ClassySharkAndroid </a>\n\\n- محرر <a href=\"https://github.com/billthefarmer/editor\"> </a>\n\\n- <a href=\"https://github.com/Raival-e/File-Explorer\"> مستكشف الملفات </a>\n\\n- <a href=\"https://github.com/nex3z/FlowLayout\"> FlowLayout </a>\n\\n- <a href=\"https://github.com/k3b/intent-intercept\"> اعتراض النية </a>\n\\n- <a href=\"https://github.com/YarikSOffice/lingver\"> Lingver </a>\n\\n- <a href=\"https://github.com/topjohnwu/Magisk\"> Magisk </a>\n\\n- <a href=\"https://github.com/zhanghai/MaterialFiles\"> ملفات المواد </a>\n\\n- <a href=\"https://github.com/pluscubed/matlog\"> MatLog </a>\n\\n- <a href=\"https://github.com/matrix-org/matrix-android-sdk\"> Matrix Android SDK </a>\n\\n- <a href=\"https://github.com/jensstein/oandbackup\"> OAndBackup </a>\n\\n- <a href=\"https://github.com/open-keychain/open-keychain\"> Open Keychain </a>\n\\n- <a href=\"https://github.com/Aefyr/SAI\"> SAI </a>\n\\n- <a href=\"https://github.com/RikkaApps/Shizuku\"> شيزوكو </a>\n\\n- <a href=\"https://github.com/eclipse/tm4e\"> tm4e </a>\n\\n- <a href=\"https://github.com/tuyafeng/Watt\"> واط </a></string>\n    <string name=\"credits\">الإشادات</string>\n    <string name=\"third_party\">مكتبات وأيقونات الطرف الثالث</string>\n    <string name=\"license\">الرخصة</string>\n    <string name=\"icon_picker\">منتقي الأيقونات</string>\n    <string name=\"class_name\">اسم الفصل</string>\n    <string name=\"package_name\">اسم الحزمة</string>\n    <string name=\"shortcut_name\">اسم الاختصار</string>\n    <string name=\"create_shortcut\">إنشاء اختصار</string>\n    <string name=\"starting_activity\">بدء النشاط: <xliff:g id=\"activity_name\" example=\".main.MainActivity\"> %1$s </xliff:g></string>\n    <string name=\"error_verbose_pin_shortcut\">المشغل الحالي لا يدعم تدبيس الإختصار. تعذر إنشاء الاختصار.</string>\n    <string name=\"error_creating_shortcut\">خطأ في إنشاء الاختصار</string>\n    <string name=\"empty_package_name\">اسم الحزمة فارغ</string>\n    <string name=\"main_activity\">النشاط الرئيسي</string>\n    <string name=\"user_id\">معرف المستخدم</string>\n    <string name=\"installer_app\">مثبت بواسطة</string>\n    <string name=\"date_updated\">تاريخ التحديث</string>\n    <string name=\"date_installed\">تاريخ التثبيت</string>\n    <string name=\"more_info\">مزيد من المعلومات</string>\n    <string name=\"sdk_flags\">العلامات</string>\n    <string name=\"sdk_max\">المستهدف</string>\n    <string name=\"sdk_min\">الحد الأدنى</string>\n    <string name=\"data_dir\">مجلد البيانات</string>\n    <string name=\"source_dir\">دليل المصدر</string>\n    <string name=\"paths_and_directories\">المسارات والدلائل</string>\n    <string name=\"user_app\">تطبيق المستخدم</string>\n    <string name=\"system_app\">تطبيق النظام</string>\n    <string name=\"app_info\">معلومات التطبيق</string>\n    <string name=\"version_name_with_code\">الإصدار <xliff:g id=\"version_name\" example=\"2.5.17\"> %1$s </xliff:g> (<xliff:g id=\"version_code\" example=\"365\">%2$d</xliff:g>)</string>\n    <string name=\"sort\">الفرز</string>\n    <string name=\"user\">المستخدم</string>\n    <string name=\"system\">النظام</string>\n    <string name=\"app_not_installed\">التطبيق غير مثبت</string>\n    <string name=\"media_size\">وسائط</string>\n    <string name=\"obb_size\">Obb</string>\n    <string name=\"cache_size\">التخزين المؤقت</string>\n    <string name=\"data_size\">البيانات</string>\n    <string name=\"about\">حول</string>\n    <string name=\"data_usage_msg\">البيانات المستخدمة</string>\n    <string name=\"data_transmitted\">البيانات المرسلة</string>\n    <string name=\"data_received\">البيانات الواردة</string>\n    <string name=\"sort_by_target_sdk\">حزمة التطوير المستهدفه</string>\n    <string name=\"sort_by_domain\">تطبيقات المستخدم أولاً</string>\n    <string name=\"sort_by_package_name\">اسم الحزمة</string>\n    <string name=\"sort_by_app_label\">تسمية التطبيق</string>\n    <string name=\"loading\">جار التحميل…</string>\n    <string name=\"error\">خطأ</string>\n    <string name=\"manifest\">البيان</string>\n    <string name=\"input_features\">ميزات الإدخال</string>\n    <string name=\"no_configurations\">لا توجد تكوينات</string>\n    <string name=\"configurations\">التكوينات</string>\n    <string name=\"app_signing_no_signatures\">لا توجد تواقيع صالحة</string>\n    <string name=\"signatures\">التواقيع</string>\n    <string name=\"sort_by_sha\">التوقيع</string>\n    <string name=\"shared_user_id\">معرف المستخدم المشترك</string>\n    <string name=\"sort_by_shared_user_id\">معرف المستخدم المشترك</string>\n    <string name=\"no_feature\">لا توجد ميزات</string>\n    <string name=\"uses_feature\">المميزات المستخدمه</string>\n    <string name=\"group\">المجموعة</string>\n    <string name=\"shared_libs\">المكتبات المشتركة</string>\n    <string name=\"declared_permission\">الصلاحيات</string>\n    <string name=\"patterns_allowed\">الأنماط المسموح بها</string>\n    <string name=\"write\">كتابه</string>\n    <string name=\"read\">قراءه</string>\n    <string name=\"path_permissions\">مسار الاذونات</string>\n    <string name=\"grant_uri_permission\">منح أذونات URI</string>\n    <string name=\"flags\">الأعلام</string>\n    <string name=\"soft_input\">وضع ادخال النظام</string>\n    <string name=\"orientation\">الاتجاه</string>\n    <string name=\"no_service\">لا توجد خدمات</string>\n    <string name=\"service\">الخدمات</string>\n    <string name=\"authority\">السلطه</string>\n    <string name=\"sort_by_last_update\">آخر تحديث</string>\n    <string name=\"launch_mode\">وضع التشغيل</string>\n    <string name=\"no_providers\">لا يوجد موفرون</string>\n    <string name=\"providers\">الموفرون</string>\n    <string name=\"no_receivers\">لا يوجد مستقبلات</string>\n    <string name=\"receivers\">المستقبلات</string>\n    <string name=\"no_activities\">لا توجد أنشطة</string>\n    <string name=\"refresh\">تحديث</string>\n    <string name=\"no_app_ops\">لا توجد عمليات تطبيق</string>\n    <string name=\"app_size\">التطبيق</string>\n    <string name=\"storage_and_cache\">التخزين وذاكرة التخزين المؤقت</string>\n    <string name=\"failed_to_stop\">لا يمكن ايقافه <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g>.</string>\n    <string name=\"force_stop\">إيقاف إجباري</string>\n    <string name=\"enable\">تفعيل</string>\n    <string name=\"disable\">تعطيل</string>\n    <string name=\"stopped\">متوقف</string>\n    <string name=\"uninstall_system_app_message\">هذا من تطبيقات النظام. هل أنت متأكد من أنك تريد إلغاء تثبيت هذا التطبيق؟</string>\n    <string name=\"uninstalled_successfully\"><xliff:g id=\"app_name\" example=\"App Manager\"> %1$s </xliff:g> تم إلغاء تثبيته.</string>\n    <string name=\"failed_to_uninstall\">تعذر إلغاء التثبيت <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g>.</string>\n    <string name=\"uninstall_app_message\">هل تريد إزالة هذا التطبيق؟</string>\n    <string name=\"view_in_settings\">افتح في الإعدادات</string>\n    <string name=\"no_content\">لا يوجد محتوى</string>\n    <string name=\"no_usage_in_this_time_range\">لا يوجد استخدام في هذا النطاق الزمني</string>\n    <string name=\"disabled_app\">مٌعطل</string>\n    <string name=\"error_evaluating_input\">تعذر تقييم الإدخال</string>\n    <string name=\"type_string\">محارف</string>\n    <string name=\"type_long\">عدد صحيح طويل</string>\n    <string name=\"type_float\">الرقم العشري</string>\n    <string name=\"type_boolean\">صواب/خطأ</string>\n    <string name=\"done\">انتهى</string>\n    <string name=\"add_item\">إضافة عنصر</string>\n    <string name=\"select_type\">حدد نوعًا</string>\n    <string name=\"key_name\">اسم المفتاح</string>\n    <string name=\"decimal_value\">القيمة العشرية</string>\n    <string name=\"string_value\">قيمة السلسلة</string>\n    <string name=\"saving_failed\">فشل الحفظ، حاول مرة أخرى.</string>\n    <string name=\"saved_successfully\">تمَّ الحفظ</string>\n    <string name=\"deletion_failed\">فشل الحذف</string>\n    <string name=\"deleted_successfully\">تم حذفه</string>\n    <string name=\"delete\">احذف</string>\n    <string name=\"discard\">ألغِ</string>\n    <string name=\"save\">احفظ</string>\n    <string name=\"databases\">قواعد البيانات</string>\n    <string name=\"shared_prefs\">الأفضليات المشتركة</string>\n    <string name=\"no_code\">لا يوجد رمز</string>\n    <string name=\"orientation_portrait\">طولي</string>\n    <string name=\"orientation_landscape\">بالعرض</string>\n    <string name=\"orientation_no_sensor\">لا يوجد مستشعر</string>\n    <string name=\"orientation_locked\">مقفل</string>\n    <string name=\"orientation_full_user\">مستخدم كامل</string>\n    <string name=\"orientation_full_sensor\">مستشعر كامل</string>\n    <string name=\"orientation_behind\">وراء</string>\n    <string name=\"orientation_unspecified\">غير محدّد</string>\n    <string name=\"launch_mode_single_top\">أعلى واحد</string>\n    <string name=\"launch_mode_single_task\">مهمة واحدة</string>\n    <string name=\"launch_mode_single_instance\">مثيل واحد</string>\n    <string name=\"launch_mode_multiple\">مضاعفة</string>\n    <string name=\"locale_split_for_base_apk\"><xliff:g id=\"split_name\" example=\"English\"> %1$s </xliff:g> ترجمة APK الأساسية</string>\n    <string name=\"locale_split_for_feature\"><xliff:g id=\"split_name\" example=\"English\"> %1$s </xliff:g> ترجمة للميزة <xliff:g id=\"feature_name\" example=\"Visualizer\">%2$s</xliff:g></string>\n    <string name=\"abi_split_for_base_apk\"><xliff:g id=\"split_name\" example=\"arm64_v8a\"> %1$s </xliff:g> رمز لملف APK الأساسي</string>\n    <string name=\"abi_split_for_feature\"><xliff:g id=\"split_name\" example=\"arm64_v8a\"> %1$s </xliff:g> رمز ل <xliff:g id=\"feature_name\" example=\"Visualizer\"> %2$s </xliff:g></string>\n    <string name=\"density_split_for_base_apk\"><xliff:g id=\"split_name\" example=\"xxdpi\"> %1$s </xliff:g> (<xliff:g id=\"dpi_no\" example=\"480\"> %2$d </xliff:g> موارد DPI) لملف APK الأساسي</string>\n    <string name=\"density_split_for_feature\"><xliff:g id=\"split_name\" example=\"xxdpi\"> %1$s </xliff:g> (<xliff:g id=\"dpi_no\" example=\"480\"> %2$d </xliff:g> موارد DPI) للميزات <xliff:g id=\"feature_name\" example=\"Visualizer\"> %3$s </xliff:g></string>\n    <string name=\"unknown_split_for_base_apk\"><xliff:g id=\"split_name\" example=\"some_split\"> %1$s </xliff:g> لملف APK الأساسي</string>\n    <string name=\"unknown_split_for_feature\"><xliff:g id=\"split_name\" example=\"some_split\"> %1$s </xliff:g> للميزة <xliff:g id=\"feature_name\" example=\"Visualizer\">%2$s</xliff:g></string>\n    <string name=\"split_feature_name\">الميزة: <xliff:g id=\"feature_name\" example=\"Visualizer\">%1$s</xliff:g></string>\n    <string name=\"base_apk\">APK الأساسي</string>\n    <string name=\"choose_language\">تغيير اللغة</string>\n    <string name=\"auto\">تلقائي</string>\n    <string name=\"pref_app_language\">اللغة</string>\n    <string name=\"backup_all_users\">جميع المستخدمين</string>\n    <string name=\"backup_multiple\">نسخ احتياطي متعدد</string>\n    <string name=\"obb_files_extracted_successfully\">ملفات OBB المستخرجة</string>\n    <string name=\"failed_to_extract_obb_files\">تعذر استخراج ملفات OBB</string>\n    <string name=\"backup_obb_media\">OBB و Media</string>\n    <string name=\"backup_apk_files\">ملفات APK</string>\n    <string name=\"installer_error_session_abandon\">تعذر التخلي عن جلسة عمل المثبت</string>\n    <string name=\"installer_error_session_commit\">تعذر تنفيذ ملفات APK</string>\n    <string name=\"installer_error_session_write\">تعذر الكتابة إلى جلسة المثبت</string>\n    <string name=\"installer_error_session_create\">تعذر إنشاء جلسة المثبت</string>\n    <string name=\"installer_error_security\">تعذر الوصول إلى ملفات APK</string>\n    <string name=\"install_in_progress\">جارٍ التثبيت…</string>\n    <string name=\"package_installer\">مثبت الحزمة</string>\n    <string name=\"unblock_trackers\">إلغاء حظر أجهزة المتعقبين</string>\n    <string name=\"reinstall\">اعادة التثبيت</string>\n    <string name=\"install_app_message\">هل تريد تثبيت هذا التطبيق؟</string>\n    <string name=\"try_again\">أعد المحاولة</string>\n    <string name=\"full_stop_tap_to_see_details\">. اضغط للاطلاع على التفاصيل.</string>\n    <string name=\"operation_running\">العملية قيد التشغيل …</string>\n    <string name=\"batch_ops\">عمليات الدُفعات</string>\n    <string name=\"failed_to_fetch_package_info\">تعذر جلب معلومات الحزمة</string>\n    <string name=\"installer_error_lidl_rom\">ROM الخاص بك غير متوافق مع Rootless Installer.</string>\n    <string name=\"installer_error_generic\">فشل التثبيت</string>\n    <string name=\"installer_error_storage\">لا توجد مساحة تخزين كافية لتثبيت التطبيق</string>\n    <string name=\"installer_error_bad_apks\">تم تحديد ملفات APK غير صالحة</string>\n    <string name=\"installer_error_incompatible\">التطبيق غير متوافق مع هذا الجهاز</string>\n    <string name=\"installer_error_conflict\">تعذر تثبيت التطبيق لأن اسم الحزمة قيد الاستخدام</string>\n    <string name=\"installer_error_blocked\">تم حظر التثبيت بواسطة <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g></string>\n    <string name=\"installer_error_blocked_device\">جهاز</string>\n    <string name=\"installer_error_aborted\">فشل التثبيت إما لأنه تم إلغاؤه أو تم إغلاق جلسة العمل بشكل غير متوقع</string>\n    <string name=\"toggle_default_app_ops\">تبديل عمليات التطبيق الافتراضية</string>\n    <string name=\"filter_apps_with_activities\">مع الأنشطة</string>\n    <string name=\"pref_remove_all_rules_msg\">سيتم منح الأذونات، وستعود عمليات التطبيق ومكوناته إلى قيمها الافتراضية.</string>\n    <string name=\"pref_remove_all_rules\">إزالة كافة القواعد</string>\n    <string name=\"website\">الموقع الإلكتروني</string>\n    <string name=\"run_in_termux\">تشغيل في Termux</string>\n    <string name=\"open_in_termux\">فتح في Termux</string>\n    <string name=\"export_icon\">استخراج الأيقونة</string>\n    <string name=\"no_matching_package_found\">تعذر العثور على أي تطبيق من هذا القبيل</string>\n    <string name=\"block_unblock_trackers\">حظر / إلغاء حظر المتعقبين</string>\n    <string name=\"unblock\">إلغاء الحظر</string>\n    <string name=\"block\">حظر</string>\n    <string name=\"clear\">تنظيف</string>\n    <string name=\"clear_data_message\">هل أنت متأكد من أنك تريد مسح البيانات من هذا التطبيق؟</string>\n    <string name=\"skip_signature_checks\">تخطي عمليات التحقق من التوقيع</string>\n    <string name=\"yes\">نعم</string>\n    <string name=\"no\">ﻻ</string>\n    <string name=\"apply_to_system_apps_question\">تنطبق على تطبيقات النظام أيضا؟ حدد \\\"لا\\\" إذا لم تكن متأكدا.</string>\n    <string name=\"apply_to_system_apps\">تطبيق على تطبيقات النظام</string>\n    <plurals name=\"failed_to_backup_some_apk_files\">\n        <item quantity=\"zero\">تعذر نسخ التطبيق %1$d نسخا احتياطية</item>\n        <item quantity=\"one\">تعذر نسخ التطبيق %1$d نسخا احتياطية</item>\n        <item quantity=\"two\">تعذر نسخ التطبيقين %1$d نسخا احتياطية</item>\n        <item quantity=\"few\">تعذر نسخ بعض التطبيقات %1$d نسخا احتياطية</item>\n        <item quantity=\"many\">تعذر نسخ التطبيقات %1$d نسخا احتياطية</item>\n        <item quantity=\"other\">تعذر نسخ التطبيق %1$d نسخا احتياطية</item>\n    </plurals>\n    <string name=\"backup_options\">خيارات النسخ الاحتياطي</string>\n    <string name=\"delete_backup\">حذف النسخة الاحتياطية</string>\n    <string name=\"backup\">النسخ الإحتياطي</string>\n    <string name=\"restore\">استعادة</string>\n    <string name=\"data\">البيانات</string>\n    <string name=\"internal_data\">البيانات الداخلية</string>\n    <string name=\"external_data\">البيانات الخارجية</string>\n    <string name=\"blocking_rules\">قواعد المنع</string>\n    <string name=\"whats_new\">ما الجديد</string>\n    <string name=\"features\">المميزات</string>\n    <string name=\"components\">المكونات</string>\n    <string name=\"trackers\">المقتعقبون</string>\n    <string name=\"installed_version\">النسخة المُثبتة</string>\n    <string name=\"select_all\">اختر الكل</string>\n    <string name=\"filter_apps_with_rules\">مع القواعد</string>\n    <string name=\"filter_system_apps\">تطبيقات النظام</string>\n    <string name=\"filter_user_apps\">تطبيقات المستخدم</string>\n    <string name=\"filter\">عامل التصفية</string>\n    <string name=\"package_name_is_installed_successfully\"><xliff:g id=\"app_name\" example=\"App Manager\"> %1$s </xliff:g> مثبت</string>\n    <string name=\"termux\">ترموكس</string>\n    <string name=\"failed_to_parse_some_numbers\">تعذر تحليل بعض الأرقام</string>\n    <string name=\"only_works_in_root_or_adb_mode\">يعمل فقط في وضع الجذر أو ADB</string>\n    <string name=\"input_app_ops_description\">أدخل أسماء عمليات التطبيق و / أو الثوابت بمسافات ، على سبيل المثال <tt> WAKE_LOCK 63 72 CAMERA </tt> إلخ.</string>\n    <string name=\"input_app_ops\">عمليات إدخال التطبيق</string>\n    <string name=\"filtered_packages\">الحزم المفلترة</string>\n    <string name=\"input_signatures_description\">أدخل التوقيعات بمسافات ، على سبيل المثال <tt> com.facebook org.app2 com.app3 </tt> إلخ.</string>\n    <string name=\"input_signatures\">تواقيع الإدخال</string>\n    <string name=\"failed_packages\">الحزم الفاشلة</string>\n    <string name=\"no_tracker_found\">لم يتم العثور على متعقبات</string>\n    <string name=\"clear_app_cache_description\">مسح ذاكرة التخزين المؤقت لجميع التطبيقات</string>\n    <string name=\"clear_app_cache\">مسح ذاكرة التخزين المؤقت للتطبيق</string>\n    <string name=\"clear_data_from_uninstalled_apps_description\">امسح البيانات من التطبيقات التي تم إلغاء تثبيتها بعلامة <tt> DONT_DELETE_DATA </tt></string>\n    <string name=\"clear_data_from_uninstalled_apps\">مسح البيانات من التطبيقات التي تم إلغاء تثبيتها</string>\n    <string name=\"deny_app_ops_description\">قم بتعيين وضع لعمليات التطبيق التي تحددها القيم الثابتة، أي <tt>63</tt> أو <tt>RUN_IN_BACKGROUND</tt></string>\n    <string name=\"block_components_dots\">حجب المكونات…</string>\n    <string name=\"block_unblock_trackers_description\">حظر أو إلغاء حظر الإعلانات ومكونات التتبع في جميع التطبيقات المثبتة</string>\n    <string name=\"clear_cache\">مسح التخزين المؤقت</string>\n    <string name=\"pref_import_existing\">استيراد القواعد الموجودة</string>\n    <string name=\"source_code_links\"><a href=\"https://github.com/MuntashirAkon/AppManager\">جيتهب</a> • <a href=\"https://gitlab.com/muntashir/AppManager\">جيتلاب</a> • <a href=\"https://0xacab.org/muntashir/AppManager\">ارتق</a> • <a href=\"https://codeberg.org/muntashir/AppManager\">كودبيرق</a></string>\n    <string name=\"source_code\">الشفرة المصدرية</string>\n    <string name=\"update\">إنعاش</string>\n    <string name=\"install\">تثبيت</string>\n    <string name=\"manifest_viewer\">عارض البيان</string>\n    <string name=\"external_apk_no_app_op\">لا يحتوي ملف APK الخارجي على أي عمليات تطبيق</string>\n    <string name=\"changelog\">سجل التغييرات</string>\n    <string name=\"one_click_ops\">عمليات بضغطة واحدة</string>\n    <string name=\"never_ask\">لا تسأل أبدا</string>\n    <string name=\"launch_app\">تشغيل التطبيق</string>\n    <string name=\"failed_to_deny_dangerous_app_ops\">لا يمكن إلغاء جميع عمليات التطبيق الخطرة</string>\n    <string name=\"failed_to_deny_dangerous_perms\">تعذر إبطال كافة الأذونات الخطيرة</string>\n    <string name=\"failed_to_reset_app_ops\">تعذر إعادة تعيين عمليات التطبيق</string>\n    <string name=\"failed_to_revoke_permission\">تعذر إلغاء الأذن</string>\n    <string name=\"failed_to_grant_permission\">تعذر منح الإذن</string>\n    <string name=\"unknown_op\">عملية غير معروفة</string>\n    <string name=\"sort_by_tracker_components\">المتعقبات أولا</string>\n    <string name=\"deny_dangerous_permissions\">رفض الأذونات الخطيرة</string>\n    <string name=\"sort_by_denied_permissions\">المرفوضة أولا</string>\n    <string name=\"sort_by_dangerous_permissions\">الخطيرة أولا</string>\n    <string name=\"sort_by_permission_names\">اسم الإذن</string>\n    <string name=\"sort_by_app_ops_values\">قيمة عمليات التطبيق</string>\n    <string name=\"sort_by_denied_app_ops\">المرفوضة أولا</string>\n    <string name=\"sort_by_app_ops_names\">اسم عمليات التطبيق</string>\n    <string name=\"deny_dangerous_app_ops\">رفض عمليات التطبيق الخطيرة</string>\n    <string name=\"reset_to_default\">إعادة التعيين إلى الوضع الافتراضي</string>\n    <string name=\"sort_by_component_name\">اسم المكون</string>\n    <string name=\"block_trackers\">حجب المتعقبات</string>\n    <string name=\"sort_by_wifi_data\">بيانات شبكة Wi-Fi</string>\n    <string name=\"version\">اﻹصدار</string>\n    <string name=\"pref_about_msg\">إصدار App Manager، الترخيص، الاعتمادات، إلخ.</string>\n    <string name=\"apply\">تطبيق</string>\n    <string name=\"select_theme\">السمة</string>\n    <string name=\"night\">ليلي</string>\n    <string name=\"day\">نهار</string>\n    <string name=\"battery_mode\">وضع البطارية</string>\n    <string name=\"follow_system\">اتبع مظهر النظام</string>\n    <string name=\"pref_app_theme\">مظهر التطبيق</string>\n    <string name=\"pref_import_blocker_msg\">استيراد قواعد الحظر من Blocker، كل ملف يحتوي على قواعد لحزمة واحدة.</string>\n    <string name=\"pref_import_watt_msg\">استيراد قواعد الحظر من Watt، كل ملف يحتوي على قواعد لحزمة واحدة مسماة مثل <tt> packagename.xml </tt> إلخ.</string>\n    <string name=\"pref_import_msg\">استيراد قواعد الحظر التي تم تصديرها مسبقًا من App Manager.</string>\n    <string name=\"pref_export_msg\">تصدير قواعد الحظر التي تم تكوينها داخل App Manager إلى وحدة تخزين خارجية.</string>\n    <string name=\"touchscreen\">شاشة اللمس</string>\n    <string name=\"navigation\">التَّنَقُّل</string>\n    <string name=\"keyboard_type\">نوع لوحة المفاتيح</string>\n    <string name=\"export_failed\">فشل التصدير!</string>\n    <string name=\"import_failed\">فشل الاستيراد!</string>\n    <string name=\"export_options\">خيارات التصدير</string>\n    <string name=\"import_options\">خيارات الاستيراد</string>\n    <string name=\"pref_export\">تصدير</string>\n    <string name=\"pref_import\">استيراد</string>\n    <string name=\"ago\">منذ</string>\n    <string name=\"reject_time\">وقت الرفض</string>\n    <string name=\"accept_time\">وقت القبول</string>\n    <string name=\"duration\">المدة الزمنية</string>\n    <string name=\"running\">يعمل</string>\n    <string name=\"mode\">الوضع</string>\n    <string name=\"permission_name\">اسم الصلاحية</string>\n    <string name=\"toggle_kill_for_system_apps\">تفعيل قتل تطبيقات النظام</string>\n    <string name=\"the_operation_was_successful\">إنتهى</string>\n    <string name=\"export_blocking_rules\">تصدير قواعد الحظر</string>\n    <string name=\"disable_background\">منع التشغيل في الخلفية</string>\n    <string name=\"backup_restore\">النسخ الاحتياطي/ الاستعادة</string>\n    <string name=\"clear_data\">مسح البيانات</string>\n    <string name=\"user_and_uid\">المستخدم: <xliff:g id=\"user_name\" example=\"root\">%1$s</xliff:g> (<xliff:g id=\"user_id\" example=\"0\">%2$d</xliff:g>)</string>\n    <string name=\"user_with_id\">المستخدم: <xliff:g id=\"user_id\" example=\"0\">%1$d</xliff:g></string>\n    <string name=\"memory_virtual_memory\">ذاكرة: %1$s، الذاكرة الظاهرية: %2$s</string>\n    <string name=\"pid_and_ppid\">معرّف العملية: %1$d ، معرّف العملية الأصل: %2$d</string>\n    <string name=\"disable_background_run\">منع التشغيل في الخلفية</string>\n    <string name=\"kill_process\">قتل</string>\n    <string name=\"running_apps\">التطبيقات المشغلة</string>\n    <string name=\"apk_updater\">محدث APK</string>\n    <string name=\"the_export_was_successful\">تمت عملية التصدير</string>\n    <string name=\"the_import_was_successful\">تمَّت عملية الإستيراد</string>\n    <string name=\"pref_import_blocker\">الاستيراد من Blocker</string>\n    <string name=\"pref_import_watt\">استيراد من Watt</string>\n    <string name=\"pref_import_export_blocking_rules_msg\">استيراد / تصدير ، القواعد الخارجية من Watt أو Blocker.</string>\n    <string name=\"pref_import_export_blocking_rules\">استيراد / تصدير قواعد المنع</string>\n    <string name=\"sort_by_mobile_data\">بيانات الجوال</string>\n    <string name=\"sort_by_times_opened\">أوقات الفتح</string>\n    <string name=\"sort_by_screen_time\">وقت الشاشة</string>\n    <string name=\"sort_by_last_used\">آخر أستخدام</string>\n    <string name=\"external_multiple_data_dir\">مسار البيانات الخارجي <xliff:g id=\"dir_no\" example=\"1\">%1$d</xliff:g></string>\n    <string name=\"external_data_dir\">مسار البيانات الخارجية</string>\n    <string name=\"sort_by_blocked_components\">المحظورة أولاً</string>\n    <string name=\"exodus_link\">رابط εxodus</string>\n    <string name=\"usage_yesterday\">في الامس</string>\n    <string name=\"app_settings\">اﻹعدادات</string>\n    <string name=\"usage_access\">الوصول إلى الاستخدام</string>\n    <string name=\"pref_global_blocking_enabled_msg\">يتيح لك حظر أي مكون من أي تطبيق دون تشغيل الحظر بشكل صريح للتطبيق.</string>\n    <string name=\"pref_global_blocking_enabled\">الحظر الفوري للمكونات</string>\n    <string name=\"str_logo\">الشعار</string>\n    <string name=\"rules_not_applied\">لم يتم تطبيق القواعد</string>\n    <string name=\"failed_to_disable_op\">تعذر تعطيل عملية التطبيق المطلوبة</string>\n    <string name=\"failed_to_enable_op\">تعذر تمكين عملية التطبيق المطلوبة</string>\n    <string name=\"app_ops\">عمليات التطبيق</string>\n    <string name=\"total_size\">الإجمالي</string>\n    <string name=\"key_name_cannot_be_null\">لا يمكن أن يكون اسم المفتاح فارغًا</string>\n    <string name=\"type_int\">عدد صحيح</string>\n    <string name=\"boolean_value\">قيمة منطقية</string>\n    <string name=\"integer_value\">قيمة عدد صحيح</string>\n    <string name=\"long_integer_value\">قيمة عدد صحيح طويل</string>\n    <string name=\"app_signing_signatures\">التواقيع</string>\n    <string name=\"task_affinity\">تقارب المهام</string>\n    <string name=\"input_keystore_pass_msg\">اضغط هنا لإدخال كلمة مرور سجل المفاتيح</string>\n    <string name=\"input_keystore_pass\">إدخال كلمة مرور سجل المفاتيح</string>\n    <string name=\"splits\">المقسمة</string>\n    <string name=\"source_stamp_verified\">تم التحقق من SourceStamp.</string>\n    <string name=\"not_verified\">لم يتم التحقق منها</string>\n    <string name=\"verified\">‍تم التأكد منه</string>\n    <string name=\"pref_signature_schemes_msg\">يجب تحديد أنظمة v1 و v2 على الأقل للحصول على توافق أكبر. يتطلب نظام v4 v2 أو v3.</string>\n    <string name=\"v4_scheme\">نظام v4 (منذ Android 11)</string>\n    <string name=\"v3_scheme\">نظام v3 (منذ Android 9)</string>\n    <string name=\"v2_scheme\">نظام v2 (منذ Android 7.0)</string>\n    <string name=\"v1_scheme\">نظام v1 (منذ Android 1.0)</string>\n    <string name=\"pref_apk_signing_msg\">تعيين أنظمة التوقيع، مفتاح توقيع مخصص، إلخ.</string>\n    <string name=\"apk_signing\">توقيع APK</string>\n    <string name=\"app_signing_signature_schemes\">أنظمة التوقيع</string>\n    <string name=\"pref_sign_apk_msg\">قم بتوقيع ملفات APK قبل تثبيتها.</string>\n    <string name=\"pref_sign_apk\">توقيع APK</string>\n    <string name=\"install_location_prefer_external\">تفضل الذاكرة الخارجية</string>\n    <string name=\"install_location_internal_only\">الداخلية فقط</string>\n    <string name=\"install_location\">موقع التثبيت</string>\n    <string name=\"installer\">المثبت</string>\n    <string name=\"comment\">ملاحظة</string>\n    <string name=\"close\">إغلاق</string>\n    <string name=\"no_root\">لا يوجد جذر</string>\n    <string name=\"root\">الجذر</string>\n    <string name=\"user_profile_with_id\">الملف الشخصي: %1$s (%2$d)</string>\n    <string name=\"advanced\">اﻹعدادات المتقدمة</string>\n    <string name=\"simple\">بسيط</string>\n    <string name=\"enabled\">مفعلة</string>\n    <string name=\"choose\">أختر</string>\n    <string name=\"input_permissions_description\">أذونات الإدخال ذات المسافات، على سبيل المثال <tt>com.permission.GET_ACCOUNTS android.permission.ACCESS_MEDIA_LOCATION</tt> إلخ. استخدم <tt>*</tt> للتقدم بطلب للحصول على كافة الأذونات.</string>\n    <string name=\"input_permissions\">أذونات الإدخال</string>\n    <string name=\"options\">الخيارات</string>\n    <string name=\"off\">غير مفعّل</string>\n    <string name=\"on\">يعمل</string>\n    <string name=\"profile_state_msg\">حالة تشغيل/إيقاف مخصصة لملف التعريف هذا</string>\n    <string name=\"profile_block_trackers_msg\">حظر برمجيات التتبع في التطبيقات</string>\n    <string name=\"profile_clear_data_msg\">مسح بيانات التطبيقات</string>\n    <string name=\"profile_clear_cache_msg\">مسح ذاكرة التخزين المؤقت للتطبيقات</string>\n    <string name=\"allow_routine_ops_msg\">السماح باستخدام ملف التعريف في العمليات الروتينية</string>\n    <string name=\"profile_state\">حالة الملف الشخصي</string>\n    <string name=\"allow_routine_ops\">السماح بالعمليات الروتينية</string>\n    <string name=\"adb_over_tcp\">ADB عبر TCP</string>\n    <string name=\"pref_mode_of_operations\">طريقة التشغيل</string>\n    <string name=\"send_selected\">إرسال المحدد</string>\n    <string name=\"rsa\">RSA</string>\n    <string name=\"aes\">AES</string>\n    <string name=\"none\">بدون</string>\n    <string name=\"pref_encryption_msg\">تشفير النسخ الاحتياطية.</string>\n    <string name=\"encryption\">التشفير</string>\n    <string name=\"select_user\">اختر المستخدم</string>\n    <string name=\"failed_to_duplicate_profile\">تعذر تكرار ملف التعريف</string>\n    <string name=\"duplicate\">مكرره</string>\n    <string name=\"new_profile\">ملف تعريف جديد</string>\n    <string name=\"input_profile_name_description\">لا يمكن أن يحتوي اسم ملف التعريف على أية مسافات.</string>\n    <string name=\"input_profile_name\">إسم الوضع</string>\n    <string name=\"un_apkm\">UnApkm تحزيم</string>\n    <string name=\"in_progress\">قيد التقدم</string>\n    <string name=\"conversion_failed\">فشل التحويل.</string>\n    <string name=\"select_apk\">حدد APK</string>\n    <string name=\"send_crash_report\">إرسال تقارير الأعطال</string>\n    <string name=\"tap_to_submit_crash_report\">اضغط لإرسال تقرير الأعطال.</string>\n    <string name=\"am_crashed\">لقد تعطل App Manager للتو</string>\n    <string name=\"filter_running_apps\">التطبيقات المشغلة</string>\n    <string name=\"copy\">انسخ</string>\n    <string name=\"view_missing_signatures\">اضغط لعرض أو إرسال توقيعات لم تكن موجودة بعد في قاعدة بيانات المكتبات الخاصة ب App Manager.</string>\n    <string name=\"tap_to_see_details\">اضغط للاطلاع على التفاصيل</string>\n    <string name=\"lib_details\">تفاصيل المكتبة</string>\n    <string name=\"no_libs\">لا توجد مكتبات</string>\n    <string name=\"sys_config\">تكوين النظام</string>\n    <string name=\"only_install\">تثبيت فقط</string>\n    <string name=\"app_data_will_be_lost\">سيتم فقدان البيانات الموجودة.</string>\n    <string name=\"app_signing_signature_mismatch_for_system_apps\">تعذر تثبيت التطبيق لأن تطبيق نظام يحمل توقيعا مختلفا له اسم الحزمة هذا.</string>\n    <string name=\"do_you_want_to_uninstall_and_install\">هل تريد إلغاء تثبيت التطبيق وتثبيته مرة أخرى؟</string>\n    <string name=\"usage_access_not_supported\">تعذر طلب الوصول إلى الاستخدام، حيث أن صفحة الإعدادات المقابلة غير موجودة.</string>\n    <string name=\"non_critical_exts\">ملحقات غير حرجة</string>\n    <string name=\"critical_exts\">الملحقات الحرجة</string>\n    <string name=\"dsa_affine_y\">تنسيق Affine x</string>\n    <string name=\"dsa_affine_x\">تنسيق Affine x</string>\n    <string name=\"format\">الصيغة</string>\n    <string name=\"public_key\">المفتاح العام</string>\n    <string name=\"algorithm\">الخوارزمية</string>\n    <string name=\"app_signing_signature\">التوقيع</string>\n    <string name=\"checksums\">أرقام التحقق</string>\n    <string name=\"serial_no\">الرقم التسلسلي</string>\n    <string name=\"not_yet_valid\">غير صالح بعد</string>\n    <string name=\"expired\">منتهي الصلاحية</string>\n    <string name=\"validity\">الصحة</string>\n    <string name=\"type\">النوع</string>\n    <string name=\"expiry_date\">تاريخ الانتهاء</string>\n    <string name=\"subject\">الموضوع</string>\n    <string name=\"filter_apps_with_backups\">تم نسخها احتياطيا</string>\n    <string name=\"sort_by_backup\">النسخ الاحتياطي أولاً</string>\n    <string name=\"failed_to_uninstall_updates\">تعذر إلغاء تثبيت التحديثات ل <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g>.</string>\n    <string name=\"uninstall_updates\">إلغاء تثبيت التحديثات</string>\n    <string name=\"allow_open_pgp_operation\">اضغط للسماح App Manager باستخدام OpenPGP</string>\n    <string name=\"confirm_installation\">تأكيد التثبيت</string>\n    <string name=\"pref_backup_flags_msg\">يؤدي إضافة إعداد مسبق لخيارات النسخ الاحتياطي إلى إزالة عبء تحديد العلامات في كل مرة تقوم فيها بالنسخ الاحتياطي / الاستعادة.</string>\n    <string name=\"pref_compression_method\">طريقة الضغط</string>\n    <string name=\"rules\">القواعد</string>\n    <string name=\"other\">ٱخرى</string>\n    <string name=\"changes_not_saved\">لم يتم حفظ التغييرات</string>\n    <string name=\"sort_by_memory_usage\">إستخدام الذاكرة</string>\n    <string name=\"sort_by_apps_first\">التطبيقات أولاً</string>\n    <string name=\"sort_by_process_name\">اسم العملية</string>\n    <string name=\"sort_by_process_id\">معرف العملية</string>\n    <string name=\"filter_apps\">التطبيقات</string>\n    <string name=\"no_apps\">لا توجد تطبيقات</string>\n    <string name=\"apps\">التطبيقات</string>\n    <string name=\"routine_ops\">العمليات الروتينية</string>\n    <string name=\"apply_now\">تطبيق الان…</string>\n    <string name=\"keystore\">مخزن المفتاح</string>\n    <string name=\"no_profiles\">لا توجد ملفات تعريف</string>\n    <string name=\"profiles\">الأوضاع</string>\n    <string name=\"open_pgp_provider\">موفر OpenPGP</string>\n    <string name=\"cancel\">ألغاء</string>\n    <string name=\"ok\">حسنًا</string>\n    <string name=\"input_backup_name\">اسم النسخة الاحتياطية</string>\n    <string name=\"downgrade\">تراجع عن التحديث</string>\n    <string name=\"process_state_with_extra\">الحالة: <xliff:g id=\"process_state\" example=\"Sleeping\"> %1$s </xliff:g> (<xliff:g id=\"state_extra\" example=\"High priority\"> %2$s </xliff:g>)</string>\n    <string name=\"process_state\">الحالة: <xliff:g id=\"process_state\" example=\"Sleeping\"> %1$s </xliff:g></string>\n    <string name=\"state_session_leader\">قائد الجلسة</string>\n    <string name=\"state_low_priority\">أولويّة منخفضة</string>\n    <string name=\"state_high_priority\">أولوية عالية</string>\n    <string name=\"state_unknown\">غير معروف</string>\n    <string name=\"state_idle\">خامل</string>\n    <string name=\"state_zombie\">الكسول</string>\n    <string name=\"state_dead\">ميت</string>\n    <string name=\"state_trace_stop\">إيقاف التتبع</string>\n    <string name=\"state_device_io\">اجهزة الإدخال/إخراج</string>\n    <string name=\"state_sleeping\">متوقّف</string>\n    <string name=\"touchscreen_finger\">إصبع</string>\n    <string name=\"touchscreen_stylus\">القلم</string>\n    <string name=\"touchscreen_no_touch\">لا يحتوي لمس</string>\n    <string name=\"navigation_wheel\">عجلة</string>\n    <string name=\"navigation_dial_pad\">لوحة الاتصال</string>\n    <string name=\"navigation_no_nav\">لا توجد ملاحة</string>\n    <string name=\"keyboard_12_keys\">12 مفتاح</string>\n    <string name=\"keyboard_qwerty\">كويرتي</string>\n    <string name=\"keyboard_no_keys\">لا توجد مفاتيح</string>\n    <string name=\"_undefined\">غير معرف</string>\n    <string name=\"required\">مطلوب</string>\n    <string name=\"orientation_sensor\">المستشعر</string>\n    <string name=\"orientation_user\">المستخدم</string>\n    <string name=\"filter_choice_pid\">معرّف العملية</string>\n    <string name=\"filter_choice_tag\">الوسم</string>\n    <string name=\"log_cleared\">تم محو السجلات</string>\n    <string name=\"log_level\">مستوى السجل</string>\n    <string name=\"log_saved\">تم حفظ السجل.</string>\n    <string name=\"manage_saved_logs\">إدارة السجلات المحفوظة</string>\n    <string name=\"no_saved_logs\">لا توجد سجلات محفوظة.</string>\n    <string name=\"notification_subtext\">المس لإيقاف التسجيل</string>\n    <string name=\"notification_title\">تسجيل السجلات قيد التقدم</string>\n    <string name=\"open\">افتح</string>\n    <string name=\"pref_buffer_title\">سجل المخزن المؤقت (ق)</string>\n    <string name=\"pref_cat_advanced\">إعدادات متقدمة</string>\n    <string name=\"pref_cat_appearance\">المَظْهَر</string>\n    <string name=\"pref_cat_configuration\">التكوين</string>\n    <string name=\"pref_default_log_level_summary\">مستوى السجل عند بدء التشغيل وعند فتح الملفات وعند التسجيل.</string>\n    <string name=\"pref_default_log_level_title\">مستوى السجل الافتراضي</string>\n    <string name=\"pref_display_limit_summary\">اعرض آخر %1$d سجلات فقط لتجنب أخطاء الذاكرة.</string>\n    <string name=\"pref_display_limit_title\">حد عرض السجل</string>\n    <string name=\"pref_filter_pattern_summary\">تصفية العلامات المحددة من السجلات.</string>\n    <string name=\"pref_expanded_by_default_summary\">إظهار نص السجل الكامل بشكل افتراضي.</string>\n    <string name=\"pref_expanded_by_default_title\">قم بالتوسيع افتراضيًا</string>\n    <string name=\"pref_log_line_period_error\">الرجاء إدخال عدد صحيح بين 1 و1000.</string>\n    <string name=\"pref_log_write_period_summary\">عند التسجيل ، اكتب إلى بطاقة SD كل %1$d سطرًا.</string>\n    <string name=\"pref_log_write_period_title\">فترة الكتابة</string>\n    <string name=\"pref_show_timestamp_summary\">إظهار معرف العملية و الطابع الزمني عند توسيعها.</string>\n    <string name=\"pref_show_timestamp_title\">إظهار معرف المنتج والطابع الزمني</string>\n    <string name=\"save_as\">حفظ بإسم …</string>\n    <string name=\"save_log\">حفظ سجل</string>\n    <string name=\"send_log_title\">إرسال السجل</string>\n    <string name=\"settings\">اﻹعدادات</string>\n    <string name=\"start_recording_log\">تسجيل</string>\n    <string name=\"subject_log_report\">تقرير السجل</string>\n    <string name=\"text_filter_ellipsis\">المُرشح…</string>\n    <string name=\"text_filter_text\">تصفية النص</string>\n    <string name=\"text_include_device_info\">قم بتضمين معلومات الجهاز</string>\n    <string name=\"pref_display_limit_hint\">يرجى إدخال رقم صالح بين %1$d و %2$d.</string>\n    <string name=\"toast_invalid_level\">اسم مستوى غير صالح: %s</string>\n    <string name=\"toast_invalid_selection\">اختيار غير صحيح. حاول مرة اخرى.</string>\n    <string name=\"unable_to_save_log\">تعذر حفظ السجل. هل أدخلت اسم ملف صالح؟</string>\n    <string name=\"widget_recording_in_progress\">يسجل…</string>\n    <string name=\"widget_start_recording\">تسجيل\n\\nالسجلات</string>\n    <string name=\"file\">ملفّ</string>\n    <string name=\"expand_all\">توسيع الكل</string>\n    <string name=\"collapse_all\">اطوِ الكل</string>\n    <string name=\"pause_unpause\">تشغيل/وقف</string>\n    <string name=\"undo\">تراجَع</string>\n    <string name=\"omit_sensitive_info\">حذف المعلومات الحساسة</string>\n    <string name=\"omit_sensitive_info_summary\">حذف المعلومات الحساسة مثل عناوين الويب أو أرقام الهواتف أو رسائل البريد الإلكتروني.</string>\n    <string name=\"text_include_dmesg\">تضمين سجل kernel</string>\n    <string name=\"share_log\">مشاركة</string>\n    <string name=\"view_logs\">عرض السجلات</string>\n    <string name=\"running_services\">الخدمات المشغلة</string>\n    <string name=\"save_apk\">حفظ ملف APK</string>\n    <string name=\"profile_save_apk_msg\">يحفظ ملفات APK في <tt> AppManager / apks </tt></string>\n    <string name=\"failed_to_block_trackers\">تعذر حظر برمجيات التتبع</string>\n    <string name=\"failed_to_unblock_trackers\">تعذر إلغاء حظر برمجيات التتبع</string>\n    <string name=\"trackers_blocked_successfully\">تم حظر برمجيات التتبع</string>\n    <string name=\"trackers_unblocked_successfully\">تم إلغاء حظر برمجيات التتبع</string>\n    <string name=\"no_encryption\">لا يوجد تشفير</string>\n    <string name=\"pgp_aes_rsa_encrypted\">%1$s مشفرة</string>\n    <string name=\"gz_bz2_compressed\">%1$s مضغوط</string>\n    <string name=\"latest_backup\">أحدث نسخة احتياطية</string>\n    <string name=\"pref_import_export_keystore\">استيراد / تصدير سجل المفاتيح</string>\n    <string name=\"pref_import_export_keystore_msg\">استيراد / تصدير سجل مفاتيح القلعة النطاطة (BKS) المستخدم داخليًا بواسطة App Manager.</string>\n    <string name=\"import_keystore\">استيراد سجل المفاتيح</string>\n    <string name=\"confirm_import_keystore\">هل أنت متأكد من أنك تريد استبدال سجل المفاتيح الحالي؟ لا يمكن التراجع عن هذا الإجراء.</string>\n    <string name=\"failed\">فشل</string>\n    <string name=\"pref_rules_msg\">حظر فوري، استيراد / تصدير / إزالة القواعد، الخ.</string>\n    <string name=\"saf\">SAF</string>\n    <string name=\"java_keystore\">مخزن المفتاح الجافا (JKS)</string>\n    <string name=\"update_uninstalled_successfully\">التحديثات الخاصة ب <xliff:g id=\"app_name\" example=\"App Manager\"> %1$s </xliff:g>تم إلغاء تثبيتها.</string>\n    <plurals name=\"alert_failed_to_set_app_ops\">\n        <item quantity=\"zero\">تعذر تعيين عمليات التطبيق لتطبيق %1$d</item>\n        <item quantity=\"one\">تعذر تعيين عمليات التطبيق لتطبيق %1$d</item>\n        <item quantity=\"two\">تعذر تعيين عمليات التطبيق لتطبيقات %1$d</item>\n        <item quantity=\"few\">تعذر تعيين عمليات التطبيق لتطبيق %1$d</item>\n        <item quantity=\"many\">تعذر تعيين عمليات التطبيق لتطبيق %1$d</item>\n        <item quantity=\"other\">تعذر تعيين عمليات التطبيق لتطبيق %1$d</item>\n    </plurals>\n    <plurals name=\"toast_log_truncated\">\n        <item quantity=\"zero\">السجل كبير جدًا ، ويظهر آخر %d سطر.</item>\n        <item quantity=\"one\">السجل كبير جدًا ، ويظهر آخر %d سطر.</item>\n        <item quantity=\"two\">السجل كبير جدًا ، ويظهر آخر %d سطر.</item>\n        <item quantity=\"few\">السجل كبير جدًا ، ويظهر آخر %d السطور.</item>\n        <item quantity=\"many\">السجل كبير جدًا ، ويظهر آخر %d سطر.</item>\n        <item quantity=\"other\">السجل كبير جدًا ، ويظهر آخر %d سطر.</item>\n    </plurals>\n    <plurals name=\"file_deletion_confirmation\">\n        <item quantity=\"zero\">%d سيتم حذف الملف</item>\n        <item quantity=\"one\">%d سيتم حذف الملف</item>\n        <item quantity=\"two\">%d سيتم حذف الملف</item>\n        <item quantity=\"few\">%d سيتم حذف الملفات</item>\n        <item quantity=\"many\">%d سيتم حذف الملف</item>\n        <item quantity=\"other\">%d سيتم حذف الملف</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_block_components\">\n        <item quantity=\"zero\">تعذر حظر مكون التطبيق %1$d</item>\n        <item quantity=\"one\">تعذر حظر مكون التطبيق %1$d</item>\n        <item quantity=\"two\">تعذر حظر مكون التطبيق %1$d</item>\n        <item quantity=\"few\">تعذر حظر مكونات التطبيق %1$d</item>\n        <item quantity=\"many\">تعذر حظر مكون التطبيق %1$d</item>\n        <item quantity=\"other\">تعذر حظر مكونات التطبيق %1$d</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_unblock_trackers\">\n        <item quantity=\"zero\">تعذر إلغاء حظر برمجيات التتبع من تطبيق %1$d</item>\n        <item quantity=\"one\">تعذر إلغاء حظر برمجيات التتبع من تطبيق %1$d</item>\n        <item quantity=\"two\">تعذر إلغاء حظر برمجيات التتبع من تطبيق %1$d</item>\n        <item quantity=\"few\">تعذر إلغاء حظر برمجيات التتبع من تطبيق %1$d</item>\n        <item quantity=\"many\">تعذر إلغاء حظر برمجيات التتبع من تطبيق %1$d</item>\n        <item quantity=\"other\">تعذر إلغاء حظر برمجياتِ التتبع من تطبيق %1$d</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_delete_backup\">\n        <item quantity=\"zero\">تعذر حذف %1$d النسخ الاحتياطية</item>\n        <item quantity=\"one\">تعذر حذف %1$d النسخ الاحتياطية</item>\n        <item quantity=\"two\">تعذر حذف %1$d النسخ الاحتياطية</item>\n        <item quantity=\"few\">تعذر حذف %1$d النسخٍ الاحتياطية</item>\n        <item quantity=\"many\">تعذر حذف %1$d النسخ الاحتياطية</item>\n        <item quantity=\"other\">تعذر حذف %1$d النسخ الاحتياطية</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_restore\">\n        <item quantity=\"zero\">تعذر استعادة %1$d تطبيق</item>\n        <item quantity=\"one\">تعذر استعادة %1$d تطبيق</item>\n        <item quantity=\"two\">تعذر استعادة %1$d تطبيق</item>\n        <item quantity=\"few\">تعذر استعادة %1$d التطبيقات</item>\n        <item quantity=\"many\">تعذر استعادة %1$d تطبيق</item>\n        <item quantity=\"other\">تعذر استعادة %1$d تطبيق</item>\n    </plurals>\n    <plurals name=\"backup_exists_are_you_sure\">\n        <item quantity=\"zero\">النسخة الاحتياطية موجودة بالفعل. هل أنت متأكد؟</item>\n        <item quantity=\"one\">النسخة الاحتياطية موجودة بالفعل. هل أنت متأكد؟</item>\n        <item quantity=\"two\">النسخة الاحتياطية موجودة بالفعل. هل أنت متأكد؟</item>\n        <item quantity=\"few\">النسخ الاحتياطية موجودة بالفعل. هل أنت متأكد؟</item>\n        <item quantity=\"many\">النسخة الاحتياطية موجودة بالفعل. هل أنت متأكد؟</item>\n        <item quantity=\"other\">النسخة الاحتياطية موجودة بالفعل. هل أنت متأكد؟</item>\n    </plurals>\n    <plurals name=\"classes\">\n        <item quantity=\"zero\">%1$d فئة</item>\n        <item quantity=\"one\">%1$d فئة</item>\n        <item quantity=\"two\">%1$d فئة</item>\n        <item quantity=\"few\">%1$d فئات</item>\n        <item quantity=\"many\">%1$d فئة</item>\n        <item quantity=\"other\">%1$d فئة</item>\n    </plurals>\n    <plurals name=\"libraries\">\n        <item quantity=\"zero\">%1$d مكتبة</item>\n        <item quantity=\"one\">%1$d مكتبة</item>\n        <item quantity=\"two\">%1$d مكتبة</item>\n        <item quantity=\"few\">%1$d مكتبات</item>\n        <item quantity=\"many\">%1$d مكتبة</item>\n        <item quantity=\"other\">%1$d مكتبة</item>\n    </plurals>\n    <plurals name=\"missing_signatures\">\n        <item quantity=\"zero\">%1$d التوقيع مفقود</item>\n        <item quantity=\"one\">%1$d التوقيع مفقود</item>\n        <item quantity=\"two\">%1$d التوقيع مفقود</item>\n        <item quantity=\"few\">%1$d التوقيعات مفقود</item>\n        <item quantity=\"many\">%1$d التوقيع مفقود</item>\n        <item quantity=\"other\">%1$d التوقيع مفقود</item>\n    </plurals>\n    <plurals name=\"app_signing_signature_schemes_pl\">\n        <item quantity=\"zero\">مخطط التوقيع</item>\n        <item quantity=\"one\">مخطط التوقيع</item>\n        <item quantity=\"two\">مخطط التوقيع</item>\n        <item quantity=\"few\">مخطط التوقيعات</item>\n        <item quantity=\"many\">مخطط التوقيع</item>\n        <item quantity=\"other\">مخطط التوقيع</item>\n    </plurals>\n    <plurals name=\"verified_with_warning\">\n        <item quantity=\"zero\">تم التحقق مع تحذير %d</item>\n        <item quantity=\"one\">تم التحقق مع تحذير %d</item>\n        <item quantity=\"two\">تم التحقق مع تحذير %d</item>\n        <item quantity=\"few\">تم التحقق مع تحذيرات %d</item>\n        <item quantity=\"many\">تم التحقق مع تحذير %d</item>\n        <item quantity=\"other\">تم التحقق مع تحذير %d</item>\n    </plurals>\n    <string name=\"verified_using_unreliable_hash\">تم التحقق باستخدام تجزئة غير موثوقة</string>\n    <plurals name=\"alert_failed_to_backup\">\n        <item quantity=\"zero\">تعذر نسخ تطبيق %1$d احتياطيًا</item>\n        <item quantity=\"one\">تعذر نسخ تطبيق %1$d احتياطيًا</item>\n        <item quantity=\"two\">تعذر نسخ تطبيقات %1$d احتياطيًا</item>\n        <item quantity=\"few\">تعذر نسخ تطبيق %1$d احتياطيًا</item>\n        <item quantity=\"many\">تعذر نسخ تطبيق %1$d احتياطيًا</item>\n        <item quantity=\"other\">تعذر نسخ تطبيق %1$d احتياطيًا</item>\n    </plurals>\n    <plurals name=\"no_of_splits\">\n        <item quantity=\"zero\">%1$d مقسم</item>\n        <item quantity=\"one\">%1$d مقسم</item>\n        <item quantity=\"two\">%1$d مقسم</item>\n        <item quantity=\"few\">%1$d مقسمات</item>\n        <item quantity=\"many\">%1$d مقسم</item>\n        <item quantity=\"other\">%1$d مقسم</item>\n    </plurals>\n    <plurals name=\"no_of_components\">\n        <item quantity=\"zero\">%1$d مكون</item>\n        <item quantity=\"one\">%1$d مكون</item>\n        <item quantity=\"two\">%1$d مكون</item>\n        <item quantity=\"few\">%1$d مكونات</item>\n        <item quantity=\"many\">%1$d مكون</item>\n        <item quantity=\"other\">%1$d مكون</item>\n    </plurals>\n    <string name=\"failed_to_initialize_key_store\">تعذرت تهيئة ملف تخزين مفاتيح App Manager.</string>\n    <string name=\"failed_to_change_ssaid\">تعذر تغيير SSAID</string>\n    <string name=\"screen\">الشَّاشة</string>\n    <string name=\"navigation_trackball\">تراكبال</string>\n    <plurals name=\"failed_to_import_files\">\n        <item quantity=\"zero\">تعذر استيراد ملف %1$d.</item>\n        <item quantity=\"one\">تعذر استيراد ملف %1$d.</item>\n        <item quantity=\"two\">تعذر استيراد ملف %1$d.</item>\n        <item quantity=\"few\">تعذر استيراد الملفات %1$d.</item>\n        <item quantity=\"many\">تعذر استيراد ملف %1$d.</item>\n        <item quantity=\"other\">تعذر استيراد ملف %1$d.</item>\n    </plurals>\n    <plurals name=\"no_of_times_opened\">\n        <item quantity=\"zero\">%1$d وقت</item>\n        <item quantity=\"one\">%1$d وقت</item>\n        <item quantity=\"two\">%1$d وقت</item>\n        <item quantity=\"few\">%1$d اوقات</item>\n        <item quantity=\"many\">%1$d وقت</item>\n        <item quantity=\"other\">%1$d وقت</item>\n    </plurals>\n    <plurals name=\"usage_hours\">\n        <item quantity=\"zero\">%1$d ساعة</item>\n        <item quantity=\"one\">%1$d ساعة</item>\n        <item quantity=\"two\">%1$d ساعة</item>\n        <item quantity=\"few\">%1$d ساعات</item>\n        <item quantity=\"many\">%1$d ساعة</item>\n        <item quantity=\"other\">%1$d ساعة</item>\n    </plurals>\n    <plurals name=\"usage_days\">\n        <item quantity=\"zero\">%1$d يوم</item>\n        <item quantity=\"one\">%1$d يوم</item>\n        <item quantity=\"two\">%1$d يوم</item>\n        <item quantity=\"few\">%1$d ايام</item>\n        <item quantity=\"many\">%1$d يوم</item>\n        <item quantity=\"other\">%1$d يوم</item>\n    </plurals>\n    <plurals name=\"usage_months\">\n        <item quantity=\"zero\">%1$d شهر</item>\n        <item quantity=\"one\">%1$d شهر</item>\n        <item quantity=\"two\">%1$d شهر</item>\n        <item quantity=\"few\">%1$d اشهر</item>\n        <item quantity=\"many\">%1$d شهر</item>\n        <item quantity=\"other\">%1$d شهر</item>\n    </plurals>\n    <plurals name=\"main_list_date_days\">\n        <item quantity=\"zero\"><xliff:g id=\"last_update_date\" example=\"20/10/2020\"> %1$s </xliff:g> <xliff:g id=\"day_no\" example=\"5\"> %2$d </xliff:g> يوم</item>\n        <item quantity=\"one\"><xliff:g id=\"last_update_date\" example=\"20/10/2020\"> %1$s </xliff:g> <xliff:g id=\"day_no\" example=\"5\"> %2$d </xliff:g> يوم</item>\n        <item quantity=\"two\"><xliff:g id=\"last_update_date\" example=\"20/10/2020\"> %1$s </xliff:g> <xliff:g id=\"day_no\" example=\"5\"> %2$d </xliff:g> يوم</item>\n        <item quantity=\"few\"><xliff:g id=\"last_update_date\" example=\"20/10/2020\"> %1$s </xliff:g> <xliff:g id=\"day_no\" example=\"5\"> %2$d </xliff:g> يوم</item>\n        <item quantity=\"many\"><xliff:g id=\"last_update_date\" example=\"20/10/2020\"> %1$s </xliff:g> <xliff:g id=\"day_no\" example=\"5\"> %2$d </xliff:g> ايام</item>\n        <item quantity=\"other\"><xliff:g id=\"last_update_date\" example=\"20/10/2020\"> %1$s </xliff:g> <xliff:g id=\"day_no\" example=\"5\"> %2$d </xliff:g> يوم</item>\n    </plurals>\n    <plurals name=\"no_of_trackers\">\n        <item quantity=\"zero\">%1$d برمجية تعقب</item>\n        <item quantity=\"one\">%1$d برمجية تعقب</item>\n        <item quantity=\"two\">%1$d برمجية تعقب</item>\n        <item quantity=\"few\">%1$d برمجية تعقب</item>\n        <item quantity=\"many\">%1$d برمجيات تعقب</item>\n        <item quantity=\"other\">%1$d برمجية تعقب</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_disable_trackers\">\n        <item quantity=\"zero\">تعذر تعطيل أدوات التتبع من %1$d التطبيق</item>\n        <item quantity=\"one\">تعذر تعطيل أدوات التتبع من %1$d التطبيق</item>\n        <item quantity=\"two\">تعذر تعطيل أدوات التتبع من %1$d التطبيق</item>\n        <item quantity=\"few\">تعذر تعطيل أدوات التتبع من %1$d التطبيق</item>\n        <item quantity=\"many\">تعذر تعطيل أدوات التتبع من %1$d التطبيقات</item>\n        <item quantity=\"other\">تعذر تعطيل أدوات التتبع من %1$d التطبيق</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_force_stop\">\n        <item quantity=\"zero\">تعذر إيقاف التطبيق %1$d بالقوة</item>\n        <item quantity=\"one\">تعذر إيقاف التطبيق %1$d بالقوة</item>\n        <item quantity=\"two\">تعذر إيقاف التطبيق %1$d بالقوة</item>\n        <item quantity=\"few\">تعذر إيقاف التطبيق %1$d بالقوة</item>\n        <item quantity=\"many\">تعذر إيقاف التطبيقات %1$d بالقوة</item>\n        <item quantity=\"other\">تعذر إيقاف التطبيق %1$d بالقوة</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_disable_background\">\n        <item quantity=\"zero\">تعذر منع %1$d التطبيق من العمل في الخلفية</item>\n        <item quantity=\"one\">تعذر منع %1$d التطبيق من العمل في الخلفية</item>\n        <item quantity=\"two\">تعذر منع %1$d التطبيق من العمل في الخلفية</item>\n        <item quantity=\"few\">تعذر منع %1$d التطبيق من العمل في الخلفية</item>\n        <item quantity=\"many\">تعذر منع %1$d التطبيقات من العمل في الخلفية</item>\n        <item quantity=\"other\">تعذر منع %1$d التطبيق من العمل في الخلفية</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_uninstall\">\n        <item quantity=\"zero\">تعذر إلغاء تثبيت %1$d التطبيق</item>\n        <item quantity=\"one\">تعذر إلغاء تثبيت %1$d التطبيق</item>\n        <item quantity=\"two\">تعذر إلغاء تثبيت %1$d التطبيق</item>\n        <item quantity=\"few\">تعذر إلغاء تثبيت %1$d التطبيق</item>\n        <item quantity=\"many\">تعذر إلغاء تثبيت %1$d التطبيقات</item>\n        <item quantity=\"other\">تعذر إلغاء تثبيت %1$d التطبيق</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_clear_data\">\n        <item quantity=\"zero\">تعذر مسح البيانات من %1$d تطبيق</item>\n        <item quantity=\"one\">تعذر مسح البيانات من %1$d تطبيق</item>\n        <item quantity=\"two\">تعذر مسح البيانات من %1$d تطبيق</item>\n        <item quantity=\"few\">تعذر مسح البيانات من %1$d تطبيقات</item>\n        <item quantity=\"many\">تعذر مسح البيانات من %1$d تطبيقات</item>\n        <item quantity=\"other\">تعذر مسح البيانات من %1$d تطبيق</item>\n    </plurals>\n    <plurals name=\"other_trackers_and_classes\">\n        <item quantity=\"zero\"><xliff:g id=\"tracker_no\" example=\"8\"> %1$d </xliff:g> بتتبع مع <xliff:g id=\"class_no\" example=\"50\">%2$d</xliff:g> فصول</item>\n        <item quantity=\"one\"><xliff:g id=\"tracker_no\" example=\"8\"> %1$d </xliff:g> بتتبعات مع <xliff:g id=\"class_no\" example=\"50\">%2$d</xliff:g> فصول</item>\n        <item quantity=\"two\"><xliff:g id=\"tracker_no\" example=\"8\"> %1$d </xliff:g> بتتبعات مع <xliff:g id=\"class_no\" example=\"50\">%2$d</xliff:g> فصول</item>\n        <item quantity=\"few\"><xliff:g id=\"tracker_no\" example=\"8\"> %1$d </xliff:g> بتتبعات مع <xliff:g id=\"class_no\" example=\"50\">%2$d</xliff:g> فصول</item>\n        <item quantity=\"many\"><xliff:g id=\"tracker_no\" example=\"8\"> %1$d </xliff:g> بتتبعات مع <xliff:g id=\"class_no\" example=\"50\">%2$d</xliff:g> فصول</item>\n        <item quantity=\"other\"><xliff:g id=\"tracker_no\" example=\"8\"> %1$d </xliff:g> بتتبعات مع <xliff:g id=\"class_no\" example=\"50\">%2$d</xliff:g> فصول</item>\n    </plurals>\n    <plurals name=\"two_trackers_and_classes\">\n        <item quantity=\"zero\">2 تتبعات مع <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g> فصول</item>\n        <item quantity=\"one\">2 تتبعات مع <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g> فصول</item>\n        <item quantity=\"two\">2 تتبعات مع <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g> فصول</item>\n        <item quantity=\"few\">2 تتبعات مع <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g> فصول</item>\n        <item quantity=\"many\">2 تتبعات مع <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g> فصول</item>\n        <item quantity=\"other\">2 تتبعات مع <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g> فصول</item>\n    </plurals>\n    <plurals name=\"tracker_and_classes\">\n        <item quantity=\"zero\">1 من المتعقب مع <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g> فئة</item>\n        <item quantity=\"one\">1 تعقب مع <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g> فئة</item>\n        <item quantity=\"two\">1 تعقبان مع <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g> فئة</item>\n        <item quantity=\"few\">1 تعقبات مع <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g> فئة</item>\n        <item quantity=\"many\">1 تعقب مع <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g> فئة</item>\n        <item quantity=\"other\">1 تعقب مع <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g> فئة</item>\n    </plurals>\n    <string name=\"are_you_sure\">هل أنت متأكد؟</string>\n    <string name=\"orientation_reverse_portrait\">طولي معكوس</string>\n    <string name=\"orientation_reverse_landscape\">عرضي معكوس</string>\n    <string name=\"orientation_sensor_landscape\">عرضي المستشعر</string>\n    <string name=\"orientation_sensor_portrait\">طولي المستشعر</string>\n    <string name=\"orientation_user_landscape\">عرضي المستخدم</string>\n    <string name=\"orientation_user_portrait\">طولي المستخدم</string>\n    <string name=\"state_parked\">متوقفة</string>\n    <string name=\"state_wake_kill\">قتل الاستيقاظ</string>\n    <string name=\"state_waking\">الاستيقاظ</string>\n    <string name=\"state_locked_memory\">الذاكرة المؤمنة</string>\n    <string name=\"state_foreground\">المقدمة</string>\n    <string name=\"state_multithreaded\">متعدد المهام</string>\n    <string name=\"systemless_app\">تطبيق غير نظامي</string>\n    <string name=\"issuer\">المصدر</string>\n    <string name=\"issued_date\">تاريخ الإصدار</string>\n    <string name=\"valid\">ساري</string>\n    <string name=\"rsa_exponent\">معامل المضاعفة</string>\n    <string name=\"rsa_modulus\">المكونات</string>\n    <string name=\"scanner\">الفاحص</string>\n    <string name=\"ecc\">تشفير المنحنى البيضاوي</string>\n    <string name=\"profile_force_stop_msg\">إيقاف التطبيقات بالقوة</string>\n    <string name=\"backup_apk_files_description\">نسخ ملفات APK احتياطيًا من المسار المصدر ، بما في ذلك التقسيمات.</string>\n    <string name=\"backup_internal_data_description\">نسخ احتياطي لمجلدات البيانات الداخلية.</string>\n    <string name=\"backup_external_data_description\">نسخ احتياطي لمجلدات البيانات الخارجية.</string>\n    <string name=\"backup_obb_media_description\">النسخ الاحتياطي لمجلدات OBB والوسائط.</string>\n    <string name=\"backup_cache_description\">نسخ <b> ذاكرة التخزين المؤقت</b>، <b>no_cache</b> و <b>no_backup</b> المجلدات.</string>\n    <string name=\"backup_extras\">إضافية</string>\n    <string name=\"backup_extras_description\">نسخ احتياطي لصلاحيات التطبيق، وتوفير البطارية وخيارات استخدام البيانات، وحالة MagiskHide، وSSAID، وما إلى ذلك. <font fgcolor=\"#ff0000\">اعتمادًا على الصلاحيات، لا يمكن استعادة جميع الإضافات.</font></string>\n    <string name=\"backup_rules_description\">قواعد النسخ الاحتياطي التي تم تكوينها داخل App Manager. <font fgcolor=\"#ff0000\">اعتمادًا على الصلاحيات، لا يمكن إعادة تطبيق جميع القواعد أثناء الاستعادة.</font></string>\n    <string name=\"backup_multiple_description\">قم بإنشاء نسخة احتياطية منفصلة <i> باسم </i> بدلاً من النسخة الاحتياطية الأساسية.</string>\n    <string name=\"patch_level\">مستوى التصحيح</string>\n    <string name=\"selinux\">امان لينكس المحسن</string>\n    <string name=\"enforcing\">اجباري</string>\n    <string name=\"permissive\">متساهل</string>\n    <string name=\"hardware\">العتاد</string>\n    <string name=\"density\">الكثافة</string>\n    <string name=\"size\">الحجم</string>\n    <string name=\"scaling_factor\">عامل التحجيم</string>\n    <string name=\"refresh_rate\">معدل التحديث</string>\n    <string name=\"window_size\">حجم النافذة</string>\n    <string name=\"failed_to_disable_magisk_hide\">تعذر تعطيل MagiskHide</string>\n    <string name=\"failed_to_enable_magisk_hide\">تعذر تمكين MagiskHide</string>\n    <string name=\"disable_background_run_description\">يضبط وضع <i> تجاهل </i> لعمليات التطبيق التالية: <tt> RUN_IN_BACKGROUND </tt> (من Android 7.0) و <tt> RUN_ANY_IN_BACKGROUND </tt> (من Android 9).</string>\n    <string name=\"pref_backup_restore_msg\">تخصيص النسخ الاحتياطي / الاستعادة.</string>\n    <string name=\"backup_volume\">حجم النسخة الاحتياطية</string>\n    <string name=\"pref_backup_volume_msg\">حدد وحدة التخزين أو القرص حيث سيتم تخزين النسخ الاحتياطية.</string>\n    <string name=\"no_volumes_found\">تعذر العثور على أي وحدات تخزين بإذن الكتابة.</string>\n    <string name=\"unencrypted\">غير مشفر</string>\n    <string name=\"encrypted\">المشفره</string>\n    <string name=\"bootloader\">محمل الاقلاع</string>\n    <string name=\"backup_custom_users\">المستخدمين المخصصين</string>\n    <string name=\"backup_custom_users_description\">إجراء النسخ الاحتياطية للمستخدمين المحددين فقط</string>\n    <string name=\"backup_all_apps\">نسخ جميع التطبيقات احتياطيًا</string>\n    <string name=\"backup_all_apps_msg\">قم بعمل نسخة احتياطية من جميع التطبيقات المثبتة.</string>\n    <string name=\"backup_apps_without_backups\">نسخ احتياطي للتطبيقات التي لاتحتوي على نسخ احتياطية</string>\n    <string name=\"backup_apps_without_backups_msg\">النسخ الاحتياطي للتطبيقات التي لاتحتوي على أي نسخ احتياطية سابقة.</string>\n    <string name=\"verify_and_redo_backups\">تحقق من النسخ الاحتياطية وأعادتها</string>\n    <string name=\"verify_and_redo_backups_msg\">تحقق من سلامة النسخ الاحتياطية السابقة وأعاد النسخ الاحتياطية التي فشل فحص السلامة من أجلها.</string>\n    <string name=\"redo_existing_backups\">إعادة النسخ الاحتياطية الموجودة</string>\n    <string name=\"redo_existing_backups_msg\">إعادة النسخ الاحتياطي للتطبيقات المثبتة مع النسخ الاحتياطية السابقة.</string>\n    <string name=\"backup_apps_with_changes\">نسخة احتياطية للتطبيقات مع التغييرات</string>\n    <string name=\"restore_all\">استعادة جميع التطبيقات</string>\n    <string name=\"restore_all_msg\">استعادة النسخ الاحتياطي الأساسي من جميع التطبيقات الاحتياطية.</string>\n    <string name=\"restore_not_installed\">استعادة التطبيقات غير المثبتة</string>\n    <string name=\"restore_not_installed_msg\">استعادة النسخ الاحتياطي الأساسي للتطبيقات غير المثبتة حاليا.</string>\n    <string name=\"restore_latest\">استعادة أحدث النسخ الاحتياطية</string>\n    <string name=\"restore_latest_msg\">استعادة التطبيقات المثبتة بالفعل والتي تكون رموز إصدارها أعلى من رمز الإصدار الحالي المثبت.</string>\n    <string name=\"backup_msg\">النسخ الاحتياطي لتطبيقات مع بالبيانات</string>\n    <string name=\"restore_msg\">استعادة التطبيقات مع البيانات</string>\n    <string name=\"drm_free_apkm_msg\">ملف APKM خالي من DRM، لا حاجة لتحويله إلى APKS.</string>\n    <string name=\"back_up\">النسخة الإحتياطية</string>\n    <string name=\"internal_storage\">الذاكرة الداخلية</string>\n    <string name=\"external_storage\">التخزين الخارجي</string>\n    <string name=\"sd_card\">بطاقة الذاكرة</string>\n    <string name=\"unlock_app_manager\">إلغاء تأمين App Manager</string>\n    <string name=\"screen_lock\">قفل الشاشة</string>\n    <string name=\"screen_lock_msg\">قفل App Manager باستخدام قفل شاشة أندرويد</string>\n    <string name=\"type_null\">بلا قيمة</string>\n    <string name=\"type_component_name\">اسم المكون</string>\n    <string name=\"type_int_array\">صف من الأعداد الصحيحة</string>\n    <string name=\"type_int_array_list\">قائمة الأعداد الصحيحة</string>\n    <string name=\"type_long_array\">صف من الأعداد الصحيحة الطويلة</string>\n    <string name=\"type_long_array_list\">قائمة بالأعداد الصحيحة الطويلة</string>\n    <string name=\"type_float_array\">صف من الأعداد العشرية</string>\n    <string name=\"type_float_array_list\">قائمة بالأرقام العشرية</string>\n    <string name=\"type_string_array\">صف من السلاسل</string>\n    <string name=\"type_string_array_list\">قائمة السلاسل</string>\n    <string name=\"type_uri\">URI</string>\n    <string name=\"no_battery_optimization\">لا يوجد تحسين للبطارية</string>\n    <string name=\"battery_optimization\">تحسين البطارية</string>\n    <string name=\"enable_battery_optimization\">تمكين تحسين البطارية؟</string>\n    <string name=\"choose_what_to_do\">اختر ما يجب القيام به.</string>\n    <string name=\"has_net_policy\">سياسة الانترنت</string>\n    <string name=\"net_policy\">سياسة الانترنت</string>\n    <string name=\"initializing\">جار التهيئة…</string>\n    <string name=\"add_to_profile\">إضافة إلى ملف التعريف</string>\n    <string name=\"add\">أضِف</string>\n    <string name=\"os_version\">إصدار نظام التشغيل</string>\n    <string name=\"reverse\">عكس</string>\n    <string name=\"list_options\">قائمة الخيارات</string>\n    <string name=\"ssaid\">SSAID</string>\n    <string name=\"copied_to_clipboard\">نُسخ الى الحافظة.</string>\n    <string name=\"restart_to_reflect_changes\">يجب إعادة تشغيل الجهاز مباشرة لاستخدام التغييرات الجديدة.</string>\n    <string name=\"installed_apps\">التطبيقات المثبتة</string>\n    <string name=\"enable_disable_features\">تمكين/تعطيل الميزات</string>\n    <string name=\"pref_enable_disable_features_msg\">تمكين أو تعطيل الميزات في App Manager.</string>\n    <string name=\"last_actions\">الإجراءات الأخيرة</string>\n    <string name=\"isolated\">معزول</string>\n    <string name=\"screen_lock_not_enabled\">يرجى اختيار قفل الشاشة في إعدادات Android، أو مسح بيانات التطبيق.</string>\n    <string name=\"working_on_adb_mode\">يعمل على وضع ADB</string>\n    <string name=\"specify_custom_name\">مُخصّص</string>\n    <string name=\"installer_app_message\">حدد <b> اختر </b> للاختيار من بين التطبيقات المثبتة أو حدد <b> مخصص </b> لتحديد اسم حزمة مخصص.</string>\n    <string name=\"uninstalled_apps\">التطبيقات غير المثبتة</string>\n    <string name=\"filter_apps_without_backups\">بدون نسخ احتياطية</string>\n    <string name=\"input_key\">مفتاح الإدخال (بالنظام الست عشري)</string>\n    <string name=\"generate_key\">انشاء</string>\n    <string name=\"failed_to_save_key\">لا يمكن حفظ المفتاح.</string>\n    <string name=\"invalid_aes_key_size\">حجم المفتاح غير صالح لتشفير AES. يسمح أن يكون حجم المفتاح إما 128 أو 256 بت.</string>\n    <string name=\"crypto_key_size\">حجم المفتاح</string>\n    <string name=\"invalid_rsa_key_size\">حجم المفتاح غير صالح لتشفير RSA. يسمح أن يكون حجم المفتاح 1024 أو 2048 أو 4096 بت.</string>\n    <string name=\"use_default\">استخدم الافتراضيّ</string>\n    <string name=\"key_not_set\">لم يتم تعيينه.</string>\n    <string name=\"failed_to_load_key\">تعذر تحميل المفتاح.</string>\n    <string name=\"input_key_password\">كلمة السر الرئيسية</string>\n    <string name=\"common_name\">الاسم الشائع (CN)</string>\n    <string name=\"organization_unit\">الوحدة التنظيمية (OU)</string>\n    <string name=\"organization_name\">اسم المؤسسة (O)</string>\n    <string name=\"locality_name\">اسم المنطقة (المدينة) (L)</string>\n    <string name=\"state_name\">اسم الدولة (ST)</string>\n    <string name=\"country_name\" tools:ignore=\"TypographyOther\">اسم الدولة (ج)</string>\n    <string name=\"keystore_file\">ملف مخزن المفتاح</string>\n    <string name=\"keystore_pass\">كلمة مرور مخزن المفتاح</string>\n    <string name=\"bouncy_castle_keystore\">سجل مفاتيح قلعة النطاط (BKS)</string>\n    <string name=\"pkcs12_keystore\">PKCS # 12 سجل مفاتيح (P12)</string>\n    <string name=\"pem_and_pk8\">#8 PEM و PKCS (PK8)</string>\n    <string name=\"pk8_file\">ملف #8 PKCS (PK8)</string>\n    <string name=\"pem_file\">ملف PEM</string>\n    <string name=\"import_key\">استيراد المفتاح</string>\n    <string name=\"new_alias_password\">اسم مستعار جديد</string>\n    <string name=\"found_no_alias_in_keystore\">لم يتم العثور على اسم مستعار في سجل المفاتيح!</string>\n    <string name=\"choose_an_alias\">اختر اسمًا مستعارًا</string>\n    <string name=\"alias_pass\">كلمة مرور الاسم المستعار</string>\n    <string name=\"failed_to_read_keystore\">تعذرت قراءة سجل المفاتيح.</string>\n    <string name=\"signing_key\">مفتاح التوقيع</string>\n    <string name=\"expiry_date_cannot_be_empty\">لا يمكن أن يكون تاريخ انتهاء الصلاحية فارغا.</string>\n    <string name=\"pref_installer_msg\">قم بتكوين سلوكيات مثبت التطبيق.</string>\n    <string name=\"log_viewer\">عارض السجل</string>\n    <string name=\"pref_log_viewer_msg\">تكوين كيفية عرض السجلات.</string>\n    <string name=\"restart_log_viewer_to_see_changes\">أعد تشغيل نافذة عارض السجل لرؤية التغييرات.</string>\n    <string name=\"filename\">اسم الملف</string>\n    <string name=\"log_level_debug\">تصحيح</string>\n    <string name=\"log_level_error\">خطأ</string>\n    <string name=\"log_level_info\">معلومات</string>\n    <string name=\"log_level_verbose\">مطوّل</string>\n    <string name=\"log_level_warn\">حذر</string>\n    <string name=\"log_level_fatal\">خطأ قاتل</string>\n    <string name=\"add_filter\">إضافة عامل تصفية</string>\n    <string name=\"add_filter_ellipsis\">إضافة عامل تصفية…</string>\n    <string name=\"copy_to_clipboard\">نسخ إلى الحافظة</string>\n    <string name=\"delete_saved_log\">حذف السجلات المحفوظة</string>\n    <string name=\"dialog_compiling_log\">يتم الآن تجميع السجل…</string>\n    <string name=\"enter_filename\">أدخل اسم ملف</string>\n    <string name=\"enter_good_filename\">الرجاء إدخال اسم ملف صالح.</string>\n    <string name=\"filter_choice\">البحث عبر</string>\n    <string name=\"log_recording_started\">بدأ تسجيل السجل.</string>\n    <string name=\"notification_ticker\">بدأ تسجيل السجل</string>\n    <string name=\"pref_filter_pattern_title\">تصفية العلامات</string>\n    <string name=\"record_log\">تسجيل السجل</string>\n    <string name=\"base_backup\">النسخ الاحتياطي الأساسي</string>\n    <string name=\"orientation_follow_locale\">اتبع اللغة</string>\n    <string name=\"orientation_left_to_right\">من اليسار إلى اليمين</string>\n    <string name=\"orientation_right_to_left\">من اليمين الى اليسار</string>\n    <string name=\"set_mode_for_app_ops_dots\">ضبط الوضع لعمليات التطبيق …</string>\n    <string name=\"security\">الأمن</string>\n    <string name=\"battery\">البطارية</string>\n    <string name=\"graphics\">الرسوميات</string>\n    <string name=\"cpu\">المعالج</string>\n    <string name=\"users\">المستخدمين</string>\n    <string name=\"languages\">اللغات</string>\n    <string name=\"battery_capacity\">السعة</string>\n    <string name=\"memory\">الذاكرة</string>\n    <string name=\"vendor\">المورد</string>\n    <string name=\"gles_version\">إصدار OpenGL ES</string>\n    <string name=\"no_of_cores\">الانوية</string>\n    <string name=\"support_architectures\">المعمارية المدعومة</string>\n    <string name=\"security_providers\">موفرو الأمان</string>\n    <string name=\"kernel\">النواة</string>\n    <string name=\"manufacturer\">الشركه المصنعه</string>\n    <string name=\"board_name\">اللوحة الام</string>\n    <string name=\"model\">النموذج</string>\n    <string name=\"brand_name\">العلامة التجارية</string>\n    <string name=\"pref_about_device_msg\">معلومات الجهاز الأساسية بما في ذلك نظام Android ووحدة المعالجة المركزية ووحدة معالجة الرسومات وذاكرة الوصول العشوائي والبطارية وما إلى ذلك.</string>\n    <string name=\"about_device\">حول الجهاز</string>\n    <string name=\"set_custom_app_op\">تعيين عملية تطبيق مخصصة</string>\n    <string name=\"interceptor\">المعترض</string>\n    <string name=\"resend_intent\">مقصد إعادة الإرسال</string>\n    <string name=\"share\">مشاركة</string>\n    <string name=\"extras\">إضافية</string>\n    <string name=\"category\">الفئات</string>\n    <string name=\"uri\">URI</string>\n    <string name=\"mime_type\">نوع MIME</string>\n    <string name=\"action\">الإجراء</string>\n    <string name=\"result_code\">رمز النتيجة</string>\n    <string name=\"activity_result\">نتيجة النشاط</string>\n    <string name=\"send_edited_intent\">إرسال القصد المحرر</string>\n    <string name=\"matching_activities\">الأنشطة المطابقة</string>\n    <string name=\"value\">القيمة</string>\n    <string name=\"filter_apps_with_splits\">تحتوي تقسيمات</string>\n    <string name=\"set_app_op_mode\">تعيين وضع تشغيل التطبيق</string>\n    <string name=\"magisk_hide_enabled\">MagiskHide</string>\n    <string name=\"pref_backup_android_keystore_msg\">لن تعمل جميع التطبيقات بعد استعادتها. لا تعمل استعادة سجل المفاتيح على معظم الأجهزة.</string>\n    <string name=\"pref_backup_android_keystore\">نسخ التطبيقات احتياطيًا باستخدام سجل مفاتيح اندرويد</string>\n    <string name=\"keep_data_and_app_signing_signatures\">الاحتفاظ بالبيانات والتوقيعات</string>\n    <string name=\"this_action_cannot_be_undone\">لا يمكن التراجع عن هذا الإجراء.</string>\n    <string name=\"no_app_ops_permission\">لا يوجد إذن لعرض عمليات التطبيق</string>\n    <string name=\"input_keystore_alias_pass_msg\">اضغط هنا لتوفير كلمة المرور ل %1$s</string>\n    <string name=\"input_keystore_alias_pass_description\">إدراج كلمة المرور للاسم المستعار <b>%1$s</b>. يمكنك ترك هذا فارغا إذا كانت كلمة المرور هي نفس كلمة مرور سجل المفاتيح.</string>\n    <string name=\"input_keystore_alias_pass\">كلمة المرور للاسم المستعار <b> %1$s </b></string>\n    <string name=\"hidden\">مَخفي</string>\n    <string name=\"suspended\">معلق</string>\n    <string name=\"no_changes\">لا تغييرات</string>\n    <string name=\"pref_display_changes_msg\">عرض التغييرات في الإصدار، برمجيات التتبع، والمكونات، والأذونات، والتوقيعات، والحزمة البرمجية التطويرية، وما إلى ذلك بطريقة النسخة التي تسيطر عليها.</string>\n    <string name=\"pref_display_changes\">عرض التغييرات</string>\n    <string name=\"netpolicy_disable_network_access\">تعطيل الوصول إلى الشبكة</string>\n    <string name=\"netpolicy_reject_wifi_data\">رفض بيانات Wi-Fi</string>\n    <string name=\"netpolicy_reject_vpn_data\">رفض بيانات VPN</string>\n    <string name=\"netpolicy_reject_cellular_data\">رفض البيانات الخلوية</string>\n    <string name=\"netpolicy_allow_background_data\">السماح ببيانات الخلفية عند تشغيل \\\"توفير البيانات\\\"</string>\n    <string name=\"netpolicy_reject_background_data\">ارفض بيانات الخلفية</string>\n    <string name=\"port_number_invalid\">رقم المنفذ غير صحيح.</string>\n    <string name=\"port_number_empty\">رقم المنفذ فارغ.</string>\n    <string name=\"adb_connect_port_number_description\">يوجد رقم المنفذ ضمن <b>عنوان IP &amp; قسم المنفذ</b> أسفل قسم <b>اسم الجهاز</b> مباشرة.</string>\n    <string name=\"port_number\">المنفذ</string>\n    <string name=\"adb_connect\">اتصال</string>\n    <string name=\"wireless_debugging\">التصحيح اللاسلكي</string>\n    <string name=\"unknown_net_policy\">سياسة شبكة غير معروفة (%1$s - %2$X)</string>\n    <string name=\"failed_to_prevent_background_run\">تعذر منع %1$s من العمل في الخلفية</string>\n    <string name=\"community_links\"><a href=\"https://matrix.to/#/#appmanager:matrix.org\">المصفوفة</a> • <a href=\"https://t.me/AppManagerChannel\">تيليقرام</a> • <a href=\"https://x.com/AppManagerNews\">تويتر/X</a> • <a href=\"https://floss.social/@appmanager\">ماستودون</a></string>\n    <string name=\"community\">المجتمع</string>\n    <plurals name=\"alert_failed_to_import_backups\">\n        <item quantity=\"zero\">تعذر استيراد %1$d نسخة احتياطية</item>\n        <item quantity=\"one\">تعذر استيراد %1$d نسخة احتياطية</item>\n        <item quantity=\"two\">تعذر استيراد %1$d نسخة احتياطية</item>\n        <item quantity=\"few\">تعذر استيراد %1$d نسخة احتياطية</item>\n        <item quantity=\"many\">تعذر استيراد %1$d نسخ احتياطية</item>\n        <item quantity=\"other\">تعذر استيراد %1$d نسخة احتياطية</item>\n    </plurals>\n    <string name=\"import_from_tb\">الاستيراد من Titanium Backup</string>\n    <string name=\"import_from_oab\">الاستيراد من OAndBackup</string>\n    <string name=\"pref_import_backups_msg\">استيراد النسخ الاحتياطية من OAndBackup أو Swift Backup (3.0–3.2) أو Titanium Backup.</string>\n    <string name=\"pref_import_backups\">استيراد النسخ الاحتياطية</string>\n    <string name=\"help_uses_permissions_tab\">انقر على بند لمنح <b>منح</b> أو <b>رفض</b>.فقط <b>فقط خطيرة</b> و <b>تطويرية</b> أذونات يمكن أن يكون منحت أو ألغيت.</string>\n    <string name=\"added_to_queue\">إضافة إلى قائمة الانتظار</string>\n    <string name=\"minimum_version\">الإصدار الأدنى: %d</string>\n    <string name=\"help_permissions_tab\">يحدد هذا التطبيق هذه الأذونات ولا يمكن إلغاؤها.</string>\n    <string name=\"help_app_ops_tab\">انقر على عنصر <b>للسماح</b> أو <b>تجاهله</b>. انقر مطولاً على عنصر لرؤية الأوضاع المدعومة الأخرى.</string>\n    <string name=\"saved_filters\">المرشحات المحفوظة</string>\n    <string name=\"permission_flags\">إشارات الصلاحيات</string>\n    <string name=\"pref_selected_users_msg\">تقييد App Manager للعمل مع المستخدمين المحددين فقط.</string>\n    <string name=\"pref_selected_users\">المستخدمون المحددون</string>\n    <string name=\"error_with_details\">خطأ: %s</string>\n    <string name=\"files\">الملفات</string>\n    <string name=\"storage\">التخزين</string>\n    <string name=\"notice_saf\">على عكس وحدات التخزين، سيتم استخدام الدليل المحدد لتخزين كافة الملفات المتعلقة بـApp Manager، بما في ذلك APKs المحفوظة والنسخ الاحتياطية. إطار عمل الوصول إلى التخزين (SAF) بطيء جدا، لذلك، يجب عليك فقط استخدام هذا الخيار عندما لا يمكن استخدام الآخرين.</string>\n    <string name=\"notice\">تنويه</string>\n    <string name=\"paired_successfully\">مقترن.</string>\n    <string name=\"adb_pair\">اقتران</string>\n    <string name=\"invalid_password\">كلمة مرور غير صالحة، حاول مرة أخرى.</string>\n    <string name=\"keystore_pass_cannot_be_empty\">لا يمكن أن تكون كلمة مرور مخزن المفتاح فارغة.</string>\n    <string name=\"keystore_password_info\">فيما يلي كلمة مرور مخزن المفتاح App Manager. يرجى تخزينه في مكان آمن إذا كنت تريد إجراء نسخة احتياطية / استعادة App Manager KeyStore.<b> لن يتم عرض هذه الرسالة مرة أخرى.</b></string>\n    <plurals name=\"pref_thread_count_msg\">\n        <item quantity=\"zero\">قم بتنفيذ على الاقل %1$d عملية او أكثر بالتوازي</item>\n        <item quantity=\"one\">قم بتنفيذ على الاقل %1$d عملية او أكثر بالتوازي</item>\n        <item quantity=\"two\">قم بتنفيذ على الاقل %1$d عملية او أكثر بالتوازي</item>\n        <item quantity=\"few\">قم بتنفيذ على الاقل %1$d عمليات او أكثر بالتوازي</item>\n        <item quantity=\"many\">قم بتنفيذ على الاقل %1$d عمليات او أكثر بالتوازي</item>\n        <item quantity=\"other\">قم بتنفيذ على الاقل %1$d عمليات او أكثر بالتوازي</item>\n    </plurals>\n    <string name=\"running_services_logcat_hint\">انقر فوق عنصر لفتح عارض السجل مع معرف العملية المطابقة كعامل تصفية افتراضي.</string>\n    <string name=\"pid\">معرف العملية</string>\n    <string name=\"pref_thread_count_hint\">يجب أن تكون القيمة بين 0 إلى %1$d حيث تعني 0 <i> الحد الأقصى لعدد العمليات في الوقت المحدد </i>.</string>\n    <string name=\"pref_thread_count\">التنفيذ الموازي</string>\n    <string name=\"type_uri_array_list\">قائمة URIs</string>\n    <string name=\"type_uri_array\">مجموعة من عناوين URIs</string>\n    <string name=\"pref_always_on_background_msg\">قم دائما بتثبيت التطبيقات في الخلفية وعرض تنبيه عند الانتهاء.</string>\n    <string name=\"pref_always_on_background\">تثبيت في الخلفية</string>\n    <string name=\"pref_block_trackers_msg\">حظر مكونات التتبع بعد تثبيت تطبيق باستخدام App Manager.</string>\n    <string name=\"next\">التالي</string>\n    <string name=\"installer_app_installed\">تم تثبيت التطبيق</string>\n    <string name=\"staging_apk_files\">يجهز …</string>\n    <string name=\"background\">الخلفية</string>\n    <string name=\"trim_caches_in_all_apps_description\">حذف ملفات ذاكرة التخزين المؤقت من جميع التطبيقات، بما في ذلك نظام أندرويد</string>\n    <string name=\"trim_caches_in_all_apps\">تقليم ذاكرة التخزين المؤقت في جميع التطبيقات</string>\n    <string name=\"user_root\">استخدم الجذر</string>\n    <string name=\"paste\">لصق</string>\n    <string name=\"set_package_name_first\">تعيين اسم الحزمة أولا!</string>\n    <string name=\"identifier\">المعرف</string>\n    <string name=\"backup_volume_dialog_description\">وحدات التخزين ذات <tt>/tree</tt> بادئة هي المجلدات المحددة باستخدام إطار الوصول التخزين (SAF). باستثناء هذه المجلدات، الدليل الافتراضي لـ App Manager هو مجلد فرعي يسمى <tt>AppManager</tt>.</string>\n    <string name=\"second_degree_tracker_note\">تشير البادئة ² إلى أن المتعقبات موجودة في <a href=\"https://etip.exodus-privacy.eu.org/\"> قائمة ETIP الاحتياطية </a> أي ما إذا كانت متتبعات فعلية لا تزال قيد التحقيق.</string>\n    <string name=\"failed_to_uninstall_app\">فشل إلغاء التثبيت</string>\n    <string name=\"import_from_sb\">الاستيراد من Swift Backup 3.0 - 3.2</string>\n    <string name=\"pref_import_backups_hint\">حدد دليلاً يحتوي على ملفات النسخ الاحتياطي (Swift Backup / Titanium Backup) أو الدلائل (OAndBackup)</string>\n    <string name=\"explore\">استكشف</string>\n    <string name=\"system_partition\">جذر أندرويد</string>\n    <string name=\"exit_confirmation\">تأكيد الخروج</string>\n    <string name=\"replace\">تبديل</string>\n    <string name=\"rename\">إعادة تسمية</string>\n    <string name=\"java\">جافا</string>\n    <string name=\"smali\">سمالي</string>\n    <string name=\"accessibility_service_description\">خدمة الوصول العامة لتنفيذ عمليات معينة مثل مسح ذاكرة التخزين المؤقت في وضع عدم وجود الجذر.</string>\n    <string name=\"extract\">استخرج</string>\n    <string name=\"intent_firewall_and_disable\">IFW + تعطيل</string>\n    <string name=\"pref_default_blocking_method\">أسلوب الحظر الافتراضي</string>\n    <string name=\"pref_intent_firewall_and_disable_description\">حظر المكونات باستخدام Intent Firewall وكذلك تعطيلها. الطريقة الموصى بها لمستخدمي الجذر.</string>\n    <string name=\"pref_disable_description\">تعطيل المكونات فقط. لا يوصى به لمستخدمي الجذر لأن التطبيقات يمكنها تجاوز ذلك. في أوضاع ADB ، يمكن تعطيل تطبيقات الاختبار فقط بهذه الطريقة.</string>\n    <string name=\"search_type_contains\">يحتوي على</string>\n    <string name=\"search_type_prefix\">بادئه</string>\n    <string name=\"search_type_suffix\">لاحقة</string>\n    <string name=\"pref_default_blocking_method_description\">طريقة الاستخدام افتراضيًا في الأماكن التي لا يوجد فيها خيار لتحديد طريقة حظر.\n\\n<b>ملاحظة:</b> \\\"IFW\\\" لا يعمل مع مقدمي الخدمات، يتم استخدام \\\"Disable\\\" بدلاً من ذلك.</string>\n    <string name=\"intent_firewall\">IFW</string>\n    <string name=\"pref_intent_firewall_description\">منع المكونات باستخدام Intent Firewall فقط. لا يوصى به لأن بعض تطبيقات النظام يمكنها تجاوز جدران الحماية.</string>\n    <string name=\"search_type_regular_expressions\">ريجيس</string>\n    <string name=\"authenticating\">مصادقة …</string>\n    <string name=\"toggle_internet\">استخدام الإنترنت</string>\n    <string name=\"vt_failed\">VirusTotal: فشل</string>\n    <string name=\"vt_success\">VirusTotal: %1$d / %2$d</string>\n    <string name=\"vt_scan_date\">تاريخ الفحص: %1$s</string>\n    <string name=\"vt_permalink\">رابط دائم إلى VirusTotal</string>\n    <string name=\"pref_vt_apikey\">مفتاح واجهة برمجة تطبيقات VirusTotal</string>\n    <string name=\"pref_vt_apikey_summary\">تفعيل فحص ملفات APK عبر VirusTotal.</string>\n    <string name=\"scan_in_vt\">فحص في VirusTotal</string>\n    <string name=\"cpu_percent\">٪٪ وحدة المعالجة المركزية</string>\n    <string name=\"cpu_time\">توقيت وحدة المعالجة المركزية</string>\n    <string name=\"priority\">الأولوية</string>\n    <string name=\"threads\">عدد الصفحات</string>\n    <string name=\"state\">حالة العملية</string>\n    <string name=\"commandline_args\">وسيطات سطر الأوامر</string>\n    <string name=\"swap\">مبادلة</string>\n    <string name=\"memory_chart_info\">● %1$s التطبيقات ● %2$s المخزنة مؤقتا ● %3$s مخازن مؤقتة ● %4$s فارغة</string>\n    <string name=\"swap_chart_info\">● %1$s المستخدمة ● %2$s الفارغة</string>\n    <string name=\"failed_to_change_app_op_mode\">تعذر تغيير وضع تشغيل التطبيق.</string>\n    <string name=\"failed_to_use_the_current_mode_of_operation\">غير قادر على استخدام الوضع الحالي للعملية. الرجوع إلى وضع عدم وجود جذر لهذه الجلسة.</string>\n    <string name=\"failed_to_enable_magisk_deny_list\">تعذر تمكين قائمة رفض ماجيسك</string>\n    <string name=\"failed_to_disable_magisk_deny_list\">تعذر تعطيل قائمة رفض ماجيسك</string>\n    <string name=\"mode_of_op_with_inferred_mode_of_op\">%1$s (الطريقة المُشار إليها: %2$s)</string>\n    <string name=\"warning_working_on_root_mode\">تحذير: يعمل بصلاحية الجذر بدلًا من وضع ADB.</string>\n    <string name=\"process_id\">معرف العملية</string>\n    <string name=\"parent_process_id\">معرف العملية الأصل</string>\n    <string name=\"vt_checking\">VirusTotal: جارٍ الفحص…</string>\n    <string name=\"vt_uploading\">VirusTotal: جارٍ الرفع …</string>\n    <string name=\"vt_queued\">VirusTotal: في قائمة الانتظار</string>\n    <string name=\"vt_slowness_warning\">اعتماداً على سرعة الإنترنت وتحميل على الخادم، قد يستغرق ذلك بعض الوقت.</string>\n    <string name=\"vt_disclaimer\">تعد VirusTotal وشعاراتها علامة تجارية مملوكة لشركة Chronicle LLC. لا App Manager - عميل واجهة برمجة التطبيقات - ولا مؤلفوه مسؤولية أي بيانات قد ترسلها إلى VirusTotal.</string>\n    <string name=\"pref_vt_apikey_description\">يمكّن مفتاح واجهة برمجة التطبيقات App Manager من تحميل ملفات APK إلى VirusTotal بالإضافة إلى جلب التقارير. اشترك في https://virustotal.com للحصول على مفتاح API مجانًا.</string>\n    <string name=\"uses_play_app_signing\">تشغيل توقيع التطبيق</string>\n    <string name=\"uses_play_app_signing_description\">يحتوي هذا التطبيق على علامات معينة تشير إلى أنه <i> قد </i> يستخدم <a href=\"https://support.google.com/googleplay/android-developer/answer/9842756\">Play App Signing </a>. مع هذا النظام، يتم تخزين مفاتيح التوقيع في خوادم Google، وجوجل مسؤولة عن توقيع التطبيق. لاحظ أن مطابقة معلومات التوقيع هي الطريقة الوحيدة للتحقق من أن التطبيق لم يتم تعديله من قبل أي شخص آخر غير المطور (وفي هذه الحالة، Google أيضا).</string>\n    <string name=\"virtual_memory\">الذاكرة الظاهرية</string>\n    <string name=\"magisk_denylist\">قائمة رفض ماجيسك</string>\n    <plurals name=\"usage_minutes\">\n        <item quantity=\"zero\">%1$d دقيقة</item>\n        <item quantity=\"one\">%1$d دقائق</item>\n        <item quantity=\"two\">%1$d دقائق</item>\n        <item quantity=\"few\">%1$d دقائق</item>\n        <item quantity=\"many\">%1$d دقائق</item>\n        <item quantity=\"other\">%1$d دقائق</item>\n    </plurals>\n    <plurals name=\"usage_seconds\">\n        <item quantity=\"zero\">%1$d ثانية</item>\n        <item quantity=\"one\">%1$d ثانية</item>\n        <item quantity=\"two\">%1$d ثانيتان</item>\n        <item quantity=\"few\">%1$d ثوان</item>\n        <item quantity=\"many\">%1$d ثوان</item>\n        <item quantity=\"other\">%1$d ثانية</item>\n    </plurals>\n    <string name=\"hidden_api_enf_default_policy\">الافتراضي (استنادا إلى نوع التطبيق)</string>\n    <string name=\"hidden_api_enf_policy_none\">لا شيء (الوصول الكامل إلى واجهة برمجة التطبيقات المخفية)</string>\n    <string name=\"hidden_api_enf_policy_dark_grey_and_black\">فرض (قوائم رمادية داكنة وسوداء)</string>\n    <string name=\"hidden_api_enf_policy_black\">فرض (القوائم السوداء فقط)</string>\n    <string name=\"binary_32_bit\">32 بت</string>\n    <string name=\"binary_64_bit\">64 بت</string>\n    <string name=\"endianness_little_endian\">القليل من Endian</string>\n    <string name=\"endianness_big_endian\">Endian كبير</string>\n    <string name=\"so_type_shared_library\">المكتبة المشتركة</string>\n    <string name=\"so_type_executable\">تنفيذي</string>\n    <string name=\"file_modified_are_you_sure\">تم تعديل الملف. تجاهل كل التغييرات الخاصة بك والخروج؟</string>\n    <string name=\"save_and_exit\">حفظ والخروج</string>\n    <string name=\"primary_abi\">ABI الأساسي</string>\n    <string name=\"zygote_preload_name\">اسم التحميل المسبق ل Zygote</string>\n    <string name=\"hidden_api_enforcement_policy\">سياسة فرض واجهة برمجة التطبيقات المخفية</string>\n    <string name=\"hidden_api_enf_policy_warn\">تحذير (الوصول الكامل إلى API المخفية ولكن يصدر تحذيرات)</string>\n    <string name=\"pref_saved_apk_name_format\">تنسيق اسم APK المحفوظ</string>\n    <string name=\"pref_saved_apk_name_format_msg\">التنسيق الذي سيتم استخدامه لتسمية ملفات APK عند حفظها.</string>\n    <string name=\"shortcut_icon\">رمز الاختصار</string>\n    <string name=\"auth_manager_description\">لبدء Intent من تطبيق خارجي ، من الضروري توفير حقل إضافي يسمى <tt>auth</tt> ، ويجب أن يحتوي على المفتاح التالي:</string>\n    <string name=\"regenerate_auth_key_warning\">هل أنت واثق؟ يجب إعادة تكوين جميع تطبيقات الطرف الثالث باستخدام مفتاح التفويض الجديد.</string>\n    <string name=\"auth_manager_title\">مدير التفويض</string>\n    <string name=\"regenerate_auth_key\">إعادة إنشاء مفتاح المصادقة</string>\n    <string name=\"sort_by_installation_date\">تاريخ التثبيت</string>\n    <string name=\"change_backup_volume\">تغيير السعة</string>\n    <string name=\"external\">خارجي</string>\n    <string name=\"internal\">داخلي</string>\n    <string name=\"tracker\">المتعقب</string>\n    <string name=\"input_ssaid_instruction\">SSAID هو رقم سداسي عشري %1$d بايت أي سلسلة طولها %2$d تحتوي على 0 إلى 9 و a إلى f.</string>\n    <string name=\"screen_time\">وقت الشاشة</string>\n    <string name=\"backup_volume_unavailable_warning\">وحدة تخزين النسخ الاحتياطي المحددة غير متوفرة حاليا. إذا كانت موجودة في وحدة تخزين خارجية ، فيرجى إدخالها أو تغيير وحدة تخزين النسخ الاحتياطي.</string>\n    <string name=\"pref_vt_prompt_before_uploading\">عرض التاكيد قبل تحميل ملف.</string>\n    <string name=\"vt_confirm_upload_and_scan\">نعم ، قم بالتحميل والفحص</string>\n    <string name=\"open_in_new_window\">نافذة جديدة</string>\n    <string name=\"vt_confirm_uploading_file\">لم يتم العثور على الملف في قاعدة بيانات VirusTotal. هل تريد تحميله؟</string>\n    <string name=\"type_string_set\">مجموعة من السلاسل</string>\n    <string name=\"item_select\">تحديد</string>\n    <string name=\"log_stop_recording\">إيقاف التسجيل</string>\n    <string name=\"apk_checksums\">مجاميع APK الاختبارية</string>\n    <string name=\"app_explorer\">متصفح التطبيق</string>\n    <string name=\"netpolicy_cannot_be_modified_for_core_apps\">لا يمكن تعديل سياسة الشبكة لتطبيقات Android الأساسية.</string>\n    <string name=\"pref_pure_black_theme\">نسق أسود نقي</string>\n    <string name=\"pref_pure_black_theme_msg\">استخدم خلفية سوداء تماما عند تمكين الوضع الليلي.</string>\n    <string name=\"open_developer_options_page\">فتح صفحة خيارات مطوري البرامج في إعدادات Android</string>\n    <string name=\"usage_times_opened\">اوقات الفتح</string>\n    <string name=\"usage_last_used\">آخر استخدام</string>\n    <string name=\"usage_mobile_data\">بيانات الهاتف</string>\n    <string name=\"usage_wifi_data\">بيانات واي فاي</string>\n    <string name=\"frozen\">مجمد</string>\n    <string name=\"backup_apps_cannot_be_backed_up\">التطبيقات التالية غير مثبتة ولا يمكن نسخها احتياطيا:</string>\n    <string name=\"restart_device\">إعادة تشغيل الجهاز</string>\n    <string name=\"backup_apps_cannot_be_restored\">لا يمكن استعادة التطبيقات التالية لأنها لا تحتوي على نسخة احتياطية أساسية:</string>\n    <string name=\"freeze\">تجميد</string>\n    <string name=\"unfreeze\">إلغاء التجميد</string>\n    <string name=\"backup_no_backups_present\">لا توجد نسخ احتياطية.</string>\n    <string name=\"restore_dots\">يستعيد…</string>\n    <string name=\"import_backups_warning_delete_backups_after_import\">حذف النسخ الاحتياطية بعد استيرادها إلى App Manager؟ يتم حذف كل نسخة احتياطية بشكل فردي بعد استيرادها بنجاح. حدد <b> No</b> إذا لم تكن متأكدا.</string>\n    <string name=\"troubleshooting\">استكشاف الاخطاء</string>\n    <string name=\"pref_reload_apps\">إعادة تحميل التطبيقات</string>\n    <string name=\"pref_reload_apps_msg\">أعد تحميل قائمة التطبيقات المخزنة في قاعدة بيانات App Manager في حالة حدوث سلوك غير متوقع.</string>\n    <string name=\"changelog_type_new\">جديد</string>\n    <string name=\"changelog_type_fix\">اصلاح</string>\n    <string name=\"changelog_type_improve\">حسن</string>\n    <string name=\"unsupported_split_apk\">غير مدعوم</string>\n    <string name=\"view_changelog\">اكتشف الجديد في هذا الإصدار</string>\n    <string name=\"sort_by_total_size\">الحجم الإجمالي</string>\n    <string name=\"am_command\">الأمر <tt>am</tt></string>\n    <string name=\"pref_sign_apk_error_signing_key_not_added\">مطلوب مفتاح توقيع صالح لتوقيع ملف APK.</string>\n    <string name=\"pref_sign_apk_no_signing_key\">لا يوجد مفتاح توقيع</string>\n    <string name=\"failed_to_unfreeze\">لا يمكن فك التجميد <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g>.</string>\n    <string name=\"freeze_unfreeze\">تجميد/فك التجميد</string>\n    <string name=\"profile_freeze_msg\">التجميد أو فك التجميد علي حسب حالة التطبيق</string>\n    <string name=\"pref_default_freezing_method\">طريقة التجميد الافتراضية</string>\n    <string name=\"suspend_app\">سكون</string>\n    <string name=\"hide_app\">اخفاء</string>\n    <plurals name=\"alert_failed_to_freeze\">\n        <item quantity=\"zero\">تعذر تجميد تطبيق %1$d</item>\n        <item quantity=\"one\">تعذر تجميد تطبيق %1$d</item>\n        <item quantity=\"two\">تعذر تجميد تطبيق %1$d</item>\n        <item quantity=\"few\">تعذر تجميد التطبيقات %1$d</item>\n        <item quantity=\"many\">تعذر تجميد التطبيقات %1$d</item>\n        <item quantity=\"other\">تعذر تجميد تطبيق %1$d</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_unfreeze\">\n        <item quantity=\"zero\">تعذر إلغاء تجميد تطبيق %1$d</item>\n        <item quantity=\"one\">تعذر إلغاء تجميد تطبيق %1$d</item>\n        <item quantity=\"two\">تعذر إلغاء تجميد تطبيق %1$d</item>\n        <item quantity=\"few\">تعذر إلغاء تجميد التطبيقات %1$d</item>\n        <item quantity=\"many\">تعذر إلغاء تجميد تطبيق %1$d</item>\n        <item quantity=\"other\">تعذر إلغاء تجميد تطبيق %1$d</item>\n    </plurals>\n    <string name=\"suspend_app_description\">هذه هي أضعف طريقة تجميد. قد يستمر ظهور تطبيق معلق في المشغل ولكنه سيكون رماديا ولا يمكن تشغيله.</string>\n    <string name=\"disable_app_description\">طريقة التجميد الموصى بها. يقوم بتعطيل التطبيق وجميع مكوناته ، ولكن ستفقد جميع الاختصارات.</string>\n    <string name=\"failed_to_freeze\">لا يمكن التجميد <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g>.</string>\n    <string name=\"sort_by_frozen_app\">المجمدة أولا</string>\n    <string name=\"pref_appearance_description\">السمة ، الاتجاه ، الميزات ، إلخ.</string>\n    <string name=\"pref_privacy\">الخصوصية</string>\n    <string name=\"pref_privacy_description\">قفل الشاشة والترخيص وما إلى ذلك.</string>\n    <string name=\"hide_app_description\">هذه الطريقة موصى بها فقط للاستخدام اليومي. يظهر التطبيق المخفي كما لو تم إلغاء تثبيته. ولكن قد يظهر التطبيق مرة أخرى إذا تمت إعادة تثبيته أو تحديثه.</string>\n    <string name=\"filter_frozen_apps\">التطبيقات المجمدة</string>\n    <string name=\"get_help\">احصل على مساعدة</string>\n    <string name=\"user_manual\">دليل المستخدم</string>\n    <string name=\"pref_advanced_pref\">المستخدمون ، تنسيق اسم APK ، التنفيذ المتوازي ، إلخ.</string>\n    <string name=\"pref_default_freezing_method_description\">طريقة يتم استخدامها بشكل افتراضي في الأماكن التي لا يوجد فيها خيار لتحديد طريقة التجميد.</string>\n    <string name=\"pref_version_changelog\">الإصدار/سجل التغيير</string>\n    <string name=\"file_change_open_with\">التغيير مفتوح في</string>\n    <string name=\"file_properties\">الخصائص</string>\n    <string name=\"file_cut\">قُصَّ</string>\n    <string name=\"fm_always_open_with\">فتح دائما</string>\n    <string name=\"file_creation_date\">تم إنشائه</string>\n    <string name=\"file_modification_date\">تم تعديله</string>\n    <string name=\"file_accessed_date\">تم الوصول إليه</string>\n    <string name=\"file_open_as\">افتح ك…</string>\n    <string name=\"file_open_with_custom_activity\">مُخصّص</string>\n    <string name=\"file_open_with_os_default_dialog\">فتح باستخدام مربع الحوار الافتراضي لنظام التشغيل</string>\n    <string name=\"open_as_text\">النص</string>\n    <string name=\"open_as_image\">صورة</string>\n    <string name=\"open_as_video\">الفيديو</string>\n    <string name=\"open_as_archive\">أرشيف</string>\n    <string name=\"open_as_folder\">المجلد</string>\n    <string name=\"open_as_other\">أخرى</string>\n    <string name=\"delete_filename\">حذف %s</string>\n    <string name=\"confirm_file_deletion\">نعم ، احذف</string>\n    <string name=\"on_unfreeze_open_application\">افتح التطبيق بعد إلغاء التجميد</string>\n    <string name=\"on_open_application_no_recents\">عدم إظهار التطبيق الذي تم إطلاقه في قائمة المهام</string>\n    <string name=\"freeze_on_phone_locked\">تجميد التطبيق تلقائيا عندما يكون الهاتف مقفلا</string>\n    <string name=\"tap_to_freeze_app\">انقر للتجميد</string>\n    <string name=\"waiting_for_the_phone_to_be_locked\">في انتظار قفل الهاتف …</string>\n    <string name=\"action_stop_service\">إيقاف</string>\n    <string name=\"file_shortcut_target_file\">الملف المستهدف</string>\n    <string name=\"file_open_with\">فتح بواسطة</string>\n    <string name=\"fm_open_with_for_this_file_only\">فقط لهذا الملف</string>\n    <string name=\"sort_by_data_usage\">استخدام البيانات</string>\n    <string name=\"filter_apps_with_keystore\">مع تخزين المفاتيح</string>\n    <string name=\"filter_apps_with_saf\">مع SAF</string>\n    <string name=\"filter_apps_with_ssaid\">مع SSAID</string>\n    <string name=\"action_continue\">أستمرار</string>\n    <string name=\"install_for_another_user\">التثبيت لـ …</string>\n    <string name=\"confirm_uninstallation\">تأكيد إلغاء التثبيت</string>\n    <string name=\"grant_required_permission\">الحصول على إذن</string>\n    <string name=\"grant_overlay_permission_message\">السماح لـ App Manager بعرض نافذة عائمة أعلى جميع النوافذ الأخرى</string>\n    <string name=\"grant_accessibility_permission_for_tracking_window_contents\">اسمح لـApp Manager باستخدام ميزة إمكانية الوصول لتتبع محتويات النافذة البادئة.</string>\n    <string name=\"class_hierarchy\">تَسَلسُل</string>\n    <string name=\"title_ui_tracker\">متقفي واجهة المستخدم</string>\n    <string name=\"title_terminal_emulator\">الطرفية</string>\n    <string name=\"title_labs_activity\">المختبرات</string>\n    <string name=\"app_can_write_and_execute_in_same_place\">ينتهك التطبيق <a href=\"https://en.wikipedia.org/wiki/W%5EX\"> سياسة W ^ X </a> ويمكنه الكتابة والتنفيذ في نفس الدليل أو في نفس الجزء من الذاكرة. يتيح ذلك تنفيذ الملفات التنفيذية التعسفية إما عن طريق تعديل الملفات التنفيذية المضمنة داخل التطبيق أو عن طريق تنزيلها من الإنترنت. ما لم يكن هذا هو السلوك المقصود للتطبيق (مثل المحاكيات الطرفية) ، يوصى بالعثور على إصدار أحدث من التطبيق يستهدف SDK 29 (Android 10) والإصدارات الأحدث ، أو البحث عن بدائل.</string>\n    <string name=\"app_manager_build_expired_message\">لضمان سلامة جهازك وبياناتك ، تم إيقاف إصدار App Manager الذي تستخدمه. يجب عليك تحديثه إلى أحدث إصدار لمتابعة استخدامه ، أو إلغاء تثبيته في حالة عدم توفر تحديث.</string>\n    <string name=\"app_manager_build_expiring_soon_warning\">ستنتهي صلاحية هذا الإصدار من App Manager قريبا جدا. يرجى تحديثه إلى أحدث إصدار.</string>\n    <string name=\"renamed_successfully\">أعيدت تسميته</string>\n    <string name=\"selinux_context\">سياق SELinux</string>\n    <string name=\"unix_file_permissions\">الوضع</string>\n    <string name=\"file_group_id\">مجموعة (GID)</string>\n    <string name=\"app_manager_build_expired\">تحتاج إلى تحديث</string>\n    <string name=\"file_owner_id\">المالك (UID)</string>\n    <string name=\"calculating_file_size\">تُجرى عملية الحساب…</string>\n    <string name=\"sort_by_filename\">الاسم</string>\n    <string name=\"sort_by_last_modified\">آخر تعديل</string>\n    <string name=\"sort_by_file_size\">حجم الملف</string>\n    <string name=\"sort_by_file_type\">نوع الملف</string>\n    <string name=\"option_display_dot_files\">ملفات نقطية</string>\n    <string name=\"option_display_folders_on_top\">المجلدات في الأعلى</string>\n    <string name=\"export_app_list\">تصدير قائمة التطبيقات</string>\n    <string name=\"export_app_list_select_format\">حدد تنسيقا لتصدير قائمة التطبيقات</string>\n    <string name=\"export_option_xml\">ملف XML</string>\n    <string name=\"export_option_markdown\">ماركداون</string>\n    <string name=\"funding_campaign_dialog_message\">نحن ندير حملة تمويل <b> </b> App Manager لـ لفترة محدودة. قم بزيارة <a href=\"https://opencollective.com/app-manager#category-ABOUT\"> opencollective.com/app-manager </a> لمعرفة المزيد عن الحملة. لن يتم عرض هذا الإشعار مرة أخرى، ولكن يمكنك العثور عليه في صفحة الإعدادات أثناء الحملة بأكملها.</string>\n    <string name=\"funding_campaign_text\">نحن ندير حملة تمويل <b> </b> لـ App Manager لفترة محدودة. <a href=\"https://opencollective.com/app-manager#category-ABOUT\"> تعرف على المزيد... </a></string>\n    <string name=\"adb_incomplete_usb_debugging_title\">تصحيح أخطاء USB غير مكتمل</string>\n    <string name=\"adb_incomplete_usb_debugging_message\">يبدو أن تصحيح أخطاء USB لم يتم تكوينه بشكل صحيح. يرجى قراءة <a href=\"https://muntashirakon.github.io/AppManager/#subsec:enable-usb-debugging\"> الوثائق </a> للحصول على خطوات إضافية. إذا كنت تعرف الخطوات بالفعل ، فالرجاء النقر فوق \\\"فتح\\\" لفتح خيارات المطور ، أو النقر فوق \\\"إغلاق\\\" لمواصلة استخدام وضع عدم الجذر.</string>\n    <string name=\"select_a_dex2oat_compiler_filter\"><tt> dex2oat </tt> فلتر المجمع</string>\n    <string name=\"optimize_option_compile_layouts\">تجميع موارد التصميم</string>\n    <string name=\"optimize_option_clear_profile_data\">محو بيانات الملف الشخصي السابقة</string>\n    <string name=\"optimize_option_check_profiles\">ضع في اعتبارك بيانات الملف الشخصي أثناء تحسين ديكس</string>\n    <string name=\"optimize_option_force_compilation\">فرض التجميع حتى عندما لا يكون مطلوبا</string>\n    <string name=\"optimize_option_force_dexopt\">إجراء تحسين ديكس على الفور</string>\n    <string name=\"title_perform_runtime_optimization_to_apps\">إجراء تحسين وقت التشغيل</string>\n    <string name=\"action_run\">شغِّل</string>\n    <string name=\"summary_perform_runtime_optimization_to_apps\">قم بتحسين تخطيطات ديكس و (في اندرويد 10 والإصدارات الأحدث) لتحسين أداء التطبيقات.</string>\n    <string name=\"action_optimize_app\">تحسين</string>\n    <string name=\"batch_ops_runtime_optimization\">تحسين وقت التشغيل</string>\n    <plurals name=\"alert_failed_to_optimize_apps\">\n        <item quantity=\"zero\">تعذر تحسين التطبيق %1$d</item>\n        <item quantity=\"one\">تعذر تحسين التطبيق %1$d</item>\n        <item quantity=\"two\">تعذر تحسين التطبيق %1$d</item>\n        <item quantity=\"few\">تعذر تحسين التطبيقات %1$d</item>\n        <item quantity=\"many\">تعذر تحسين التطبيقات %1$d</item>\n        <item quantity=\"other\">تعذر تحسين التطبيق %1$d</item>\n    </plurals>\n    <string name=\"title_domains_supported_by_the_app\">النطاقات المدعومة</string>\n    <string name=\"source_stamp_verified_and_identified_to_be_from_source\">تم التحقق من SourceStamp وتحديده على أنه من <xliff:g id=\"source\" example=\"Google Play\"> %1$s </xliff:g>.</string>\n    <string name=\"app_info_tag_open_links\">افتح الروابط</string>\n    <string name=\"block_unblock_components_dots\">حظر / إلغاء حظر المكونات …</string>\n    <string name=\"unblock_components_dots\">إلغاء حظر المكونات…</string>\n    <string name=\"pref_layout_direction\">اتجاه التخطيط</string>\n    <string name=\"title_code_editor\">محرر التعليمات البرمجية</string>\n    <string name=\"read_only_file\">ملف للقراءة فقط</string>\n    <string name=\"read_only_file_warning\">لا يمكن كتابة التغييرات في الملف، ربما لأنه موجود في وحدة تخزين ليس لدى App Manager إذن للكتابة إليها. هل تريد حفظه في مكان مختلف؟</string>\n    <string name=\"replacement_text\">استبدال</string>\n    <string name=\"action_replace_all\">استبدل الكل</string>\n    <string name=\"search_option_match_case\">مطابقة الحالة</string>\n    <string name=\"search_option_regex\">قيمة السجل</string>\n    <plurals name=\"search_results\">\n        <item quantity=\"zero\">%d النتائج</item>\n        <item quantity=\"one\">%d الناتج</item>\n        <item quantity=\"two\">%d النتيجتين</item>\n        <item quantity=\"few\">%d النتائج</item>\n        <item quantity=\"many\">%d النتائج</item>\n        <item quantity=\"other\">%d النتائج</item>\n    </plurals>\n    <string name=\"debloat_list_type\">القائمة</string>\n    <string name=\"debloat_removal_type\">النوع</string>\n    <string name=\"system_app_put_back\">ارجاع</string>\n    <string name=\"debloater_title\">المنظف</string>\n    <string name=\"debloat_list_aosp\">تطبيقات اندرويد مفتوحة المصدر</string>\n    <string name=\"debloat_list_oem\">برمجيات المصنع</string>\n    <string name=\"debloat_list_carrier\">الناقل / مزود خدمة الإنترنت</string>\n    <string name=\"debloat_list_google\">جوجل</string>\n    <string name=\"debloat_list_misc\">المنوعات</string>\n    <string name=\"debloat_removal_safe\">آمن</string>\n    <string name=\"debloat_removal_replace\">تبديل</string>\n    <string name=\"debloat_removal_caution\">الحذر</string>\n    <string name=\"static_shared_library\">المكتبة المشتركة الثابتة</string>\n    <string name=\"pref_zip_align\">محاذاة ملفات APK</string>\n    <string name=\"block_unblock_components_description\">حظر أو إلغاء حظر جميع المكونات المحددة بواسطة التوقيعات المحددة</string>\n    <string name=\"pref_zip_align_msg\">تؤدي محاذاة ملف APK إلى تقليل استخدام الذاكرة حيث يمكن الوصول إلى الملفات الموجودة في حزمة التطبيق مباشرة دون نسخ البيانات إلى ذاكرة الوصول العشوائي. هذه الخطوة مطلوبة إذا تم ضبط <tt> extractNativeLibs </tt> الى قيمة <tt> صحيح </tt>.</string>\n    <string name=\"redo\">إعادة</string>\n    <string name=\"line_separator\">فاصل الأسطر</string>\n    <string name=\"uninstall_app_again_message\">تم إلغاء تثبيت التطبيق بدون مسح البيانات والتوقيع. هل تريد إلغاء تثبيته بالكامل؟</string>\n    <string name=\"uninstall_app\">إلغاء تثبيت %1$s</string>\n    <string name=\"search_option_whole_word\">الكلمة كلها</string>\n    <plurals name=\"alert_failed_to_unblock_components\">\n        <item quantity=\"zero\">تعذر إلغاء حظر مكون التطبيق %1$d</item>\n        <item quantity=\"one\">تعذر إلغاء حظر مكون التطبيق %1$d</item>\n        <item quantity=\"two\">تعذر إلغاء حظر مكون التطبيقين %1$d</item>\n        <item quantity=\"few\">تعذر إلغاء حظر مكونات التطبيقات %1$d</item>\n        <item quantity=\"many\">تعذر إلغاء حظر مكونات التطبيقات %1$d</item>\n        <item quantity=\"other\">تعذر إلغاء حظر مكونات تطبيقات %1$d</item>\n    </plurals>\n    <string name=\"empty_folder\">فارغ</string>\n    <string name=\"title_audio_player\">مشغل الصوت</string>\n    <string name=\"go_to_path\">الانتقال إلى…</string>\n    <plurals name=\"file_count\">\n        <item quantity=\"zero\">%d ملف</item>\n        <item quantity=\"one\">%d ملف</item>\n        <item quantity=\"two\">%d ملفان</item>\n        <item quantity=\"few\">%d ملفات</item>\n        <item quantity=\"many\">%d ملفات</item>\n        <item quantity=\"other\">%d ملفات</item>\n    </plurals>\n    <string name=\"copy_this_path\">نسخ المسار</string>\n    <plurals name=\"folder_count\">\n        <item quantity=\"zero\">مجلد %d</item>\n        <item quantity=\"one\">مجلد %d</item>\n        <item quantity=\"two\">مجلدان %d</item>\n        <item quantity=\"few\">مجلدات %d</item>\n        <item quantity=\"many\">مجلدات %d</item>\n        <item quantity=\"other\">مجلدات %d</item>\n    </plurals>\n    <string name=\"filter_force_stopped_apps\">التطبيقات المتوقفة</string>\n    <string name=\"warning_working_on_system_mode\">تحذير: العمل على النظام بدلا من وضع ADB.</string>\n    <string name=\"installing_package\">جاري تثبيت %1$s…</string>\n    <string name=\"backing_up_app\">النسخ الاحتياطي %1$s …</string>\n    <string name=\"restoring_app\">استعادة %1$s …</string>\n    <string name=\"folder\">المجلد</string>\n    <string name=\"symbolic_link\">رابط رمزي</string>\n    <string name=\"create_new_symbolic_link\">رابط رمزي جديد</string>\n    <string name=\"symbolic_link_not_supported\">لا يدعم هذا المجلد إنشاء ارتباط رمزي.</string>\n    <string name=\"create_new_folder\">مجلد جديد</string>\n    <string name=\"create_new_file\">ملف جديد</string>\n    <string name=\"enter_symbolic_link_name\">اسم الرابط</string>\n    <string name=\"enter_target_path\">المسار الهدف</string>\n    <string name=\"invalid_target_path\">مسار غير صالح</string>\n    <string name=\"copy_these_paths\">نسخ المسار</string>\n    <string name=\"conflict_detected_while_copying\">تم اكتشاف تعارض</string>\n    <string name=\"copy_keep_both_file\">احتفظ بكليهما</string>\n    <string name=\"copied_successfully\">نسخ.</string>\n    <string name=\"moved_successfully\">تم النقل</string>\n    <string name=\"failed_to_delete_specified_file_after_copying\">تعذر حذف \\\"%1$s\\\" بعد نسخه ، ربما بسبب عدم وجود صلاحيات كافية.</string>\n    <string name=\"change_group_gid\">تغيير المجموعة (GID)</string>\n    <string name=\"change_mode\">بدّل النمط</string>\n    <string name=\"pref_send_notifications_to_connected_devices\">إرسال إشعارات إلى الأجهزة المتصلة</string>\n    <string name=\"pref_send_notification_to_connected_devices_msg\">قم بتعيين ما إذا كنت تريد إرسال إشعارات إلى الأجهزة المتصلة مثل الأجهزة القابلة للارتداء.</string>\n    <string name=\"pref_installer_force_dexopt_description\">قم بإجراء تحسين DEX بعد تثبيت التطبيق دون انتظار قيام النظام بذلك عندما يكون النظام في وضع الخمول.</string>\n    <string name=\"conflict_detected_while_copying_message\">يوجد عنصر باسم \\\"%1$s\\\" بالفعل في هذا الموقع. هل تريد استبداله؟</string>\n    <string name=\"title_confirm_deletion\">تأكيد الحذف</string>\n    <string name=\"failed_to_copy_specified_file\">تعذر نسخ \\\"%1$s\\\".</string>\n    <string name=\"title_change_selinux_context\">تغيير سياق SELinux</string>\n    <string name=\"apply_recursively\">تطبيق على الملفات المرفقة</string>\n    <string name=\"change_owner_uid\">تغيير المالك (UID)</string>\n    <string name=\"report_not_available\">غير متاح</string>\n    <string name=\"installer_options\">خيارات المثبت</string>\n    <string name=\"debloat_removal_safe_short_description\">آمن للإزالة</string>\n    <string name=\"debloat_removal_caution_short_description\">كن حذرا</string>\n    <string name=\"debloat_removal_replace_short_description\">استبدله ببديل</string>\n    <string name=\"title_alternatives_to_bloatware\">البدائل</string>\n    <string name=\"browse_files\">تصفَّح</string>\n    <string name=\"pref_files_msg\">تكوين مدير الملفات.</string>\n    <string name=\"pref_files_display_in_launcher\">عرض \\\"الملفات\\\" في درج التطبيق</string>\n    <string name=\"pref_files_remember_last_path\">تذكر آخر مسار تم فتحه وموقعه</string>\n    <string name=\"pref_files_remember_last_path_msg\">عند تمكين هذا الخيار ، يؤدي فتح نافذة جديدة إلى فتح آخر مجلد مفتوح بدلا من المجلد الرئيسي.</string>\n    <string name=\"pref_set_home\">تعيين الرئيسية</string>\n    <string name=\"xposed_module_info\">معلومات وحدة Xposed</string>\n    <string name=\"title_description\">الوصف</string>\n    <string name=\"module_name\">اسم الوحدة</string>\n    <string name=\"app_manager_is_running\">App Manager قيد التشغيل</string>\n    <string name=\"tap_to_open_notification_settings\">انقر للإخفاء</string>\n    <string name=\"app_manager_is_unlocked\">App Manager غير مؤمن</string>\n    <string name=\"action_lock_app\">قفل</string>\n    <string name=\"pref_enable_persistent_session\">تشغيل App Manager في الخلفية</string>\n    <string name=\"pref_enable_persistent_session_msg\">يؤدي تشغيل App Manager في الخلفية إلى تقليل تأخير التجهيز. مفيد إذا كنت تستخدم App Manager بشكل متكرر.</string>\n    <string name=\"pref_enable_auto_lock\">تأمين تلقائي</string>\n    <string name=\"pref_enable_auto_lock_msg\">قفل App Manager عندما يكون الجهاز مقفلا.</string>\n    <string name=\"path_does_not_exist\">\\\"%1$s\\\" غير موجود</string>\n    <string name=\"path_not_a_folder\">\\\"%1$s\\\" ليس مجلدا</string>\n    <string name=\"scan_report_from_pithus\">تقرير بيثوس</string>\n    <string name=\"action_checking\">التحقق…</string>\n    <string name=\"profile_modified_are_you_sure\">تم تعديل الملف الشخصي. تجاهل كل التغييرات الخاصة بك والخروج؟</string>\n    <string name=\"apply_profile\">تطبيق الملف الشخصي \\\"%1$s\\\"</string>\n    <string name=\"copy_profile_id\">نسخ معرف الملف السخصي</string>\n    <string name=\"profile_id\">معرف الملف الشخصي</string>\n    <string name=\"choose_a_profile_state\">حدد حالة الملف الشخصي</string>\n    <string name=\"pref_toggle_internet_msg\">قم بتنشيط ميزات الإنترنت في App Manager</string>\n    <string name=\"pref_use_vt_no_internet\">يتطلب VirusTotal وجود إنترنت لكي يعمل، وهو أمر غير ممكّن. الرجاء تمكين <a href=\"app-manager://settings/privacy_prefs/toggle_internet\">\\\"استخدام الإنترنت\\\"</a> أولاً.</string>\n    <string name=\"netpolicy_reject_metered_background_data\">رفض بيانات الخلفية على الشبكات المقننة</string>\n    <string name=\"netpolicy_reject_metered_data\">رفض البيانات على الشبكات المقننة</string>\n    <string name=\"netpolicy_allow_metered_background_data\">السماح ببيانات الخلفية على الشبكات المقننة حتى عند تشغيل توفير البيانات</string>\n    <string name=\"launch_activity_dialog_title\">إطلاق النشاط: الإجراء مطلوب</string>\n    <string name=\"launch_activity_dialog_message\">يحاول App Manager تشغيل النشاط عبر <b>مساعد البحث</b> (مساعد Google عادةً)، لكنه غير قادر على القيام بذلك بسبب عدم كفاية الأذونات المطلوبة. لفتح النشاط، يرجى تنشيط <b>مساعد البحث</b> يدويًا (والذي يتم عادةً عن طريق النقر لفترة طويلة على زر الصفحة الرئيسية). انقر فوق الزر <b>إغلاق</b> بعد الانتهاء من تشغيل النشاط للعودة إلى المساعد الأصلي.</string>\n    <string name=\"finder_title\">الباحث</string>\n    <string name=\"select_filter\">اختر مرشحا</string>\n    <string name=\"size_in_bytes\">الحجم (بايت)</string>\n    <string name=\"invalid_regex\">تعبير عادي غير صالح!</string>\n    <string name=\"value_cannot_be_empty\">لا يمكن أن تكون القيمة فارغة!</string>\n    <string name=\"date\">التاريخ</string>\n    <string name=\"pref_use_vt\">استخدم فايروس توتال</string>\n    <string name=\"virus_total\">فايروس توتال</string>\n    <string name=\"pref_use_log_viewer\">استخدم عارض السجل</string>\n    <string name=\"pref_installer\">استخدم المثبت</string>\n    <string name=\"pref_cat_general\">عامّ</string>\n    <string name=\"status_remote_server_active\">الخادم البعيد نشط</string>\n    <string name=\"status_remote_server_inactive\">الخادم البعيد غير نشط</string>\n    <string name=\"status_remote_services_active\">الخدمات البعيدة نشطة</string>\n    <string name=\"status_remote_services_inactive\">الخدمات البعيدة غير نشطة</string>\n    <string name=\"status_connecting\">جارِ الاتصال…</string>\n    <string name=\"status_connecting_via_mode\">الاتصال عبر %s</string>\n    <string name=\"status_connected_via_mode\">متصل عبر %s</string>\n    <string name=\"status_not_connected_via_mode\">تعذر الاتصال عبر %s</string>\n    <string name=\"adb_pairing_instruction\">يرجى الانتقال إلى خيارات مطور البرامج لتمكين التصحيح اللاسلكي وإنشاء رمز إقران. انقر على <b>يدوي</b> إذا كنت قد فتحت بالفعل خيارات مطور البرامج.</string>\n    <string name=\"adb_pairing_searching_for_port\">جار البحث…</string>\n    <string name=\"adb_pairing_stop_searching\">توقَّف</string>\n    <string name=\"adb_pairing_input_pairing_code\">رمز الاقتران</string>\n    <string name=\"adb_pairing_pairing_code\">رمز الاقتران</string>\n    <string name=\"adb_pairing_found_pairing_service_with_port\">تم العثور على خدمة بالمنفذ %d</string>\n    <string name=\"adb_pairing_pairing_in_progress\">قيد الإقتران…</string>\n    <string name=\"mode_of_op_custom_command_title\">أمر مخصص</string>\n    <string name=\"mode_of_op_custom_command\">إذا لم تتمكن من استخدام أي من الأوضاع، فيمكنك تشغيل الأمر التالي باستخدام أي طرفية مدعومة لتشغيل App Manager في الوضع المصرح:</string>\n    <string name=\"adb_pairing_retry_pairing\">حاول مرَّةً أخرى</string>\n    <string name=\"mode_of_op_alternative_custom_command\">إذا تلقيت خطأ \\\"تم رفض الإذن\\\" في الأمر أعلاه، فقم بتشغيل الأمر التالي بدلاً من ذلك:</string>\n    <string name=\"sensors\">المستشعرات</string>\n    <string name=\"tag_sensors_disabled\">المستشعرات معطلة</string>\n    <string name=\"backup_cache\">الملفات المؤقتة</string>\n    <string name=\"pref_use_system_font\">استخدم خط النظام</string>\n    <string name=\"pref_use_system_font_msg\">استخدم الخط الافتراضي للنظام بدلاً من الخط المادي. <font fgcolor=\"#ff0000\">هذه ميزة تجريبية.</font></string>\n    <string name=\"actual_installer\">المثبت الفعلي</string>\n    <string name=\"apk_source\">مصدر التطبيق</string>\n    <string name=\"activity_name\">اسم النشاط</string>\n    <string name=\"vulkan_version\">نسخة فولكان</string>\n    <string name=\"battery_health\">الصحة</string>\n    <string name=\"verified_boot\">تم التحقق من التمهيد</string>\n    <string name=\"android_verified_bootloader_version\">إصدار AVB</string>\n    <string name=\"op_history\">السجل</string>\n    <string name=\"no_history\">لايوجد سجل</string>\n    <string name=\"title_confirm_execution\">تأكيد التنفيذ</string>\n    <string name=\"add_to_favorites\">أضف إلى المفضلة</string>\n    <string name=\"item_remove\">حذف</string>\n    <string name=\"freeze_prefer_per_app_option\">تفضيل خيار لكل تطبيق</string>\n    <string name=\"remember_option_for_this_app\">تذكر لهذا التطبيق</string>\n    <string name=\"remove_filename\">إزالة %s</string>\n    <string name=\"action_manual\">يدوي</string>\n    <string name=\"item_edit\">تعديل</string>\n    <string name=\"battery_technology\">تكنولوجيا</string>\n    <string name=\"advanced_suspend_app\">تعليق متقدم</string>\n    <string name=\"clear_history\">مسح السجل</string>\n    <string name=\"available_memory\">متاح: %s</string>\n    <string name=\"advanced_suspend_app_description\">إنه يفرض إيقاف التطبيق وتعليقه للتأكد من أن التطبيق لا يعمل في الخلفية. يجب تفضيل هذه الطريقة على طريقة <b>التعليق</b> العادية.</string>\n    <string name=\"favorites\">المفضلات</string>\n    <string name=\"no_overlay_permission\">لا تصريح للعرض فوق التطبيقات الأخرى</string>\n    <string name=\"overlay_category\">الفئة</string>\n    <string name=\"overlay_target\">الهدف</string>\n    <string name=\"overlay_sdk_version_too_low\">التراكبات غير مدعومة.</string>\n    <string name=\"no_overlays\">لا توجد تراكبات</string>\n    <string name=\"sort_by_overlay_names\">اسم التراكبات</string>\n    <string name=\"sort_by_priority\">الأولوية</string>\n    <string name=\"overlays\">التراكبات</string>\n    <string name=\"message_shortcut_for_frozen_app\">يبدو أن التطبيق التابع للاختصار قد تم تجميده. هل تريد إلغاء التجميد مؤقتًا وفتح الاختصار ؟</string>\n    <string name=\"title_shortcut_for_frozen_app\">تطبيق مجمد</string>\n    <string name=\"title_overlay\">التراكب</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-ar-rSA/disclaimer.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- SPDX-License-Identifier: GPL-3.0-or-later --><resources>\n    <string name=\"disclaimer_header\">إخلاء المسؤولية</string>\n    <string name=\"disclaimer_footer\">© 2020-2024 منتشر الاسلام</string>\n</resources>"
  },
  {
    "path": "app/src/main/res/values-ar-rSA/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- SPDX-License-Identifier: GPL-3.0-or-later --><resources>\n    <string name=\"uninstall\">إلغاء التثبيت</string>\n    <string name=\"permissions\">إستخدام الأذونات</string>\n    <string name=\"require_no_permission\">لا توجد أذونات مطلوبة</string>\n    <string name=\"activities\">الأنشطة</string>\n    <string name=\"launch\">البدء</string>\n    <string name=\"refresh\">تحديث</string>\n    <string name=\"no_activities\">لا توجد أي أنشطة</string>\n    <string name=\"receivers\">الاستقبال</string>\n    <string name=\"no_receivers\">لا يوجد إستقبال</string>\n    <string name=\"providers\">مقدمي الخدمات</string>\n    <string name=\"no_providers\">لا يوجد مقدمي</string>\n    <string name=\"launch_mode\">وضع التشغيل</string>\n    <!-- &#8230; = ... -->\n    <string name=\"import_options\">خيارات الاستيراد</string>\n    <string name=\"export_options\">خيارات التصدير</string>\n    <string name=\"import_failed\">فشل في الاستيراد!</string>\n    <string name=\"export_failed\">فشل في التصدير!</string>\n    <string name=\"soft_input\">وضع الادخال السهل</string>\n    <string name=\"input_features\">مميزات الادخال</string>\n    <string name=\"no_configurations\">لا يوجد مكونات</string>\n    <string name=\"configurations\">مكونات</string>\n    <string name=\"app_signing_no_signatures\">لا يوجد انطباعات مميزة</string>\n    <string name=\"signatures\">التوقيع المميز</string>\n    <string name=\"sort_by_sha\">ترتيب حسب التوقيع SHA</string>\n    <string name=\"shared_user_id\">رقم تعريف المستخدم المميز المشارك</string>\n    <string name=\"sort_by_shared_user_id\">ترتيب حسب رقم تعريف المستخدم المميز المشارك</string>\n    <string name=\"no_feature\">لايوجد مميزات</string>\n    <string name=\"uses_feature\">مستخدم للمميزات</string>\n    <string name=\"group\">مجموعة</string>\n    <string name=\"shared_libs\">مكتبات رئيسية و مشاركة مع الجميع</string>\n    <string name=\"declared_permission\">أذونات</string>\n    <string name=\"patterns_allowed\">تم السماح بالأنماط</string>\n    <string name=\"write\">كتابة</string>\n    <string name=\"read\">قراءة</string>\n    <string name=\"path_permissions\">مسار الأذونات</string>\n    <string name=\"grant_uri_permission\">السماح للوصول الى مزود المحتوى</string>\n    <string name=\"flags\">محددات</string>\n    <string name=\"orientation\">توجه</string>\n    <string name=\"no_service\">لا يوجد خدمات</string>\n    <string name=\"service\">خدمات</string>\n    <string name=\"authority\">السلطة</string>\n    <string name=\"sort_by_last_update\">آخر تحديث</string>\n    <string name=\"task_affinity\">تقارب المهمة</string>\n</resources>"
  },
  {
    "path": "app/src/main/res/values-az/disclaimer.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources></resources>"
  },
  {
    "path": "app/src/main/res/values-az/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources></resources>"
  },
  {
    "path": "app/src/main/res/values-ban/disclaimer.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources></resources>"
  },
  {
    "path": "app/src/main/res/values-ban/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources></resources>"
  },
  {
    "path": "app/src/main/res/values-be/disclaimer.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"disclaimer_footer\">© 2020–2024 Muntashir Al-Islam</string>\n</resources>"
  },
  {
    "path": "app/src/main/res/values-be/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"uninstall\">Удалiць</string>\n    <string name=\"permissions\">Дазволы</string>\n    <string name=\"require_no_permission\">Не трэба дазволаў</string>\n</resources>"
  },
  {
    "path": "app/src/main/res/values-bn-rBD/disclaimer.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- SPDX-License-Identifier: GPL-3.0-or-later --><resources>\n    <string name=\"disclaimer_header\">অস্বীকৃতি</string>\n    <string name=\"disclaimer_body\">অ্যাপ ম্যানেজার যে রুট ফাংশন গুলো সরবাহ করে তা যদি সঠিকভাবে ব্যবহৃত না হয় তাহলে \n\tআপনার ডিভাইসটির ক্ষতি হতে পারে, অ্যপ ম্যানেজার এ ক্ষতির জন্য দায়ী থাকবে না। রুট কীভাবে কাজ করে সে সম্পর্কে আপনি যদি \n\tপুরোপুরি অবগত না হন তাহলে আপনি রুট অপশন ব্যবহার করা থেকে বিরত থাকুন যতক্ষণ না যতক্ষণ না আপনি ঝুঁকি সম্পর্কে পুরোপুরি\n\t সচেতন হন।\n\n        \\n\\nযে লিংক গুলো আমি সরবাহ করি তা শুধু মাত্র ব্যাবহারকারির সুবিধার জন্য. বাহ্যিক লিঙ্কে গিয়ে আপনি যে কোনও সামগ্রী খুঁজে \n\tপেতে পারেন তার জন্য আমি দায়বদ্ধ নই।\n\n        \\n\\nঅ্যাপ ম্যানেজার ব্যবহার করে, আপনি নিজের ব্যবহারের সম্পূর্ণ দায়িত্ব স্বীকার করেন এছাড়াও স্বীকার করেন যে  কোন ক্ষতি, দাবি \n\tবা আর্থিক মান দেওয়া হবে না অপব্যবহারের  কারণে।\n\n        \\n\\nএই অ্যাপ্লিকেশনটি ব্যবহার করে, আপনি এটি ব্যবহার করে সমস্ত দায় স্বীকার করবেন এবং আমি সহমত আপনার করা কোনও \n\tক্রিয়াকলাপের জন্য আমি দায়বদ্ধ না যা আপনার ডিভাইসে বিরূপ প্রভাব ফেলে।\n\n    </string>\n    <string name=\"disclaimer_footer\">© ২০২০–২০২৪ মুনতাশির আল-ইসলাম</string>\n    <string name=\"disclaimer_agree_forever\">আর প্রদর্শন করবেন না</string>\n    <string name=\"disclaimer_agree\">আমি সম্মতি দিচ্ছি</string>\n    <string name=\"disclaimer_exit\">প্রস্থান</string>\n</resources>"
  },
  {
    "path": "app/src/main/res/values-bn-rBD/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- SPDX-License-Identifier: GPL-3.0-or-later --><resources xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\">\n    <string name=\"uninstall\">আনইনস্টল</string>\n    <string name=\"require_no_permission\">কোন অনুমতির প্রয়োজন নেই</string>\n    <string name=\"activities\">কার্যকলাপ</string>\n    <string name=\"launch\">চালু করুন</string>\n    <string name=\"refresh\">রিফ্রেশ</string>\n    <string name=\"no_activities\">কোন কার্যক্রম নেই</string>\n    <string name=\"sort_by_last_update\">সর্বশেষ আপডেট</string>\n    <string name=\"flags\">ফ্ল্যাগসমূহ</string>\n    <string name=\"grant_uri_permission\">ইউআরআই অনুমতি প্রদান করুন</string>\n    <string name=\"patterns_allowed\">অনুমোদিত প্যাটার্নস</string>\n    <string name=\"declared_permission\">অনুমতি</string>\n    <string name=\"group\">গ্রুপ</string>\n    <string name=\"no_feature\">কোনো ফিচার্স নেই</string>\n    <string name=\"error\">ত্রুটি</string>\n    <string name=\"loading\">লোড হচ্ছে…</string>\n    <string name=\"sort_by_app_label\">আ্যপ লেবেল</string>\n    <string name=\"sort_by_package_name\">প্যাকেজের নাম</string>\n    <string name=\"sort_by_domain\">প্রথমে ব্যবহারকারীর অ্যাপ</string>\n    <string name=\"data_received\">প্রাপ্ত ডাটা</string>\n    <string name=\"data_transmitted\">প্রেরিত ডাটা</string>\n    <string name=\"data_usage_msg\">সর্বশেষ বুট থেকে ডাটা ইউসেজ</string>\n    <string name=\"data_size\">ডাটা</string>\n    <string name=\"cache_size\">ক্যাশ</string>\n    <string name=\"obb_size\">ওব</string>\n    <string name=\"media_size\">মিডিয়া</string>\n    <string name=\"app_not_installed\">অ্যাপটি ইনস্টল হয়নি</string>\n    <string name=\"system\">সিস্টেম</string>\n    <string name=\"user\">ব্যবহারকারী</string>\n    <string name=\"sort\">বাছাই</string>\n    <string name=\"version_name_with_code\">সংস্করণ <xliff:g id=\"version_name\" example=\"2.5.17\">%1$s</xliff:g> (<xliff:g id=\"version_code\" example=\"365\">%2$d</xliff:g>)</string>\n    <string name=\"app_info\">অ্যাপ্লিকেশন তথ্য</string>\n    <string name=\"system_app\">সিস্টেম অ্যাপ</string>\n    <string name=\"user_app\">ব্যবহারকারী অ্যাপ্লিকেশন</string>\n    <string name=\"source_dir\">মূল ডিরেক্টরি</string>\n    <string name=\"data_dir\">ডাটা ডিরেক্টরি</string>\n    <string name=\"sdk_min\">সর্বনিম্ন</string>\n    <string name=\"sdk_max\">সর্বোচ্চ লক্ষ্য</string>\n    <string name=\"sdk_flags\">ফ্ল্যাগসমূহ</string>\n    <string name=\"more_info\">আরো তথ্য</string>\n    <string name=\"date_installed\">ইনস্টলের তারিখ</string>\n    <string name=\"date_updated\">আপডেটের তারিখ</string>\n    <string name=\"user_id\">ব্যবহারকারীর আইডি</string>\n    <string name=\"main_activity\">মূল একটিভিটি</string>\n    <string name=\"empty_package_name\">প্যাকেজের নাম খালি</string>\n    <string name=\"error_verbose_pin_shortcut\">বর্তমান লঞ্চার পিনশোর্টকট সমর্থন করে না। শর্টকাট তৈরি করতে ব্যর্থ।</string>\n    <string name=\"shortcut_name\">শর্টকাটের নাম</string>\n    <string name=\"package_name\">প্যাকেজের নাম</string>\n    <string name=\"license\">লাইসেন্স</string>\n    <string name=\"third_party\">তৃতীয় পক্ষের লাইব্রেরী এবং আইকন</string>\n    <string name=\"credits\">কৃতিত্ব</string>\n    <string name=\"toggle_class_listing\">ক্লাস লিস্টিং টগল করুন</string>\n    <string name=\"found_trackers\">পাওয়া ট্র্যাকার গুলো:</string>\n    <string name=\"tracker_details\">ট্র্যাকারের বিস্তারিত</string>\n    <plurals name=\"main_list_date_days\">\n        <item quantity=\"one\"><xliff:g id=\"last_update_date\" example=\"20/10/2020\">%1$s</xliff:g> <xliff:g id=\"day_no\" example=\"5\">%2$d</xliff:g> দিন</item>\n        <item quantity=\"other\"><xliff:g id=\"last_update_date\" example=\"20/10/2020\">%1$s</xliff:g> <xliff:g id=\"day_no\" example=\"5\">%2$d</xliff:g> দিন</item>\n    </plurals>\n    <string name=\"app_usage\">অ্যাপ ব্যবহারের ডাটা</string>\n    <string name=\"usage_weekly\">সাপ্তাহিক</string>\n    <string name=\"usage_today\">আজ</string>\n    <string name=\"usage_7_days\">গত ৭ দিন</string>\n    <plurals name=\"usage_months\">\n        <item quantity=\"one\">%1$d মাস</item>\n        <item quantity=\"other\">%1$d মাস</item>\n    </plurals>\n    <plurals name=\"usage_days\">\n        <item quantity=\"one\">%1$d দিন</item>\n        <item quantity=\"other\">%1$d দিন</item>\n    </plurals>\n    <plurals name=\"usage_hours\">\n        <item quantity=\"one\">%1$d ঘন্টা</item>\n        <item quantity=\"other\">%1$d ঘন্টা</item>\n    </plurals>\n    <string name=\"usage_less_than_a_minute\">এক মিনিটেরও কম</string>\n    <string name=\"go_back\">পিছনে যান</string>\n    <string name=\"go\">এগিয়ে যান</string>\n    <string name=\"grant_usage_access\">ইউসেজ একসেস প্রদান করুন</string>\n    <string name=\"grant_usage_acess_message\">অ্যাপ্লিকেশন ব্যবহারের ডাটা প্রদর্শনের জন্য ইউসেজ অ্যাক্সেস বাধ্যতামূলক।</string>\n    <string name=\"share_apk\">এপিকে শেয়ার করুন</string>\n    <string name=\"failed_to_extract_apk_file\">এপিকে এক্সট্র্যাক্ট করতে ব্যর্থ</string>\n    <string name=\"menu_remove_rules\">বিধি অপসারণ করুন</string>\n    <string name=\"menu_apply_rules\">বিধি প্রয়োগ করুন</string>\n    <string name=\"search\">অনুসন্ধান</string>\n    <string name=\"dev_protected_data_dir\">ডিভাইস-সুরক্ষিত ডাটা ডিরেক্টরি</string>\n    <string name=\"process_name\">প্রক্রিয়ার নাম</string>\n    <string name=\"no_code\">কোনো কোড নেই</string>\n    <string name=\"updated_app\">আপডেট হয়েছে</string>\n    <string name=\"test_only\">পরীক্ষামূলক</string>\n    <string name=\"databases\">Databases</string>\n    <string name=\"save\">সংরক্ষণ</string>\n    <string name=\"discard\">বাতিল করুন</string>\n    <string name=\"delete\">মুছুন</string>\n    <string name=\"deleted_successfully\">মুছে ফেলা হয়েছে</string>\n    <string name=\"deletion_failed\">মুছতে ব্যর্থ</string>\n    <string name=\"saved_successfully\">সংরক্ষিত</string>\n    <string name=\"saving_failed\">সংরক্ষণ করতে ব্যর্থ, আবার চেষ্টা করুন।</string>\n    <string name=\"string_value\">স্ট্রিংয়ের মান</string>\n    <string name=\"long_integer_value\">দীর্ঘ পূর্ণসংখ্যার মান</string>\n    <string name=\"integer_value\">পূর্ণসংখ্যার মান</string>\n    <string name=\"decimal_value\">দশমিকের মান</string>\n    <string name=\"boolean_value\">বুলিয়ান এর মান</string>\n    <string name=\"select_type\">প্রকার নির্বাচন করুন</string>\n    <string name=\"add_item\">যোগ করুন</string>\n    <string name=\"done\">সম্পন্ন</string>\n    <string name=\"type_float\">দশমিকের মান</string>\n    <string name=\"type_int\">পূর্ণসংখ্যা</string>\n    <string name=\"type_long\">দীর্ঘ পূর্ণসংখ্যা</string>\n    <string name=\"error_evaluating_input\">ইনপুট মূল্যায়নে ব্যর্থ</string>\n    <string name=\"key_name_cannot_be_null\">মূল নামটি খালি থাকতে পারবে না</string>\n    <string name=\"disabled_app\">নিস্ক্রিয় করা</string>\n    <string name=\"view_in_settings\">সেটিংসে দেখুন</string>\n    <string name=\"uninstall_app_message\">আপনি কি এই অ্যাপটি আনইনস্টল করতে চান?</string>\n    <string name=\"failed_to_uninstall\"><xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g> আনইন্সটল করতে ব্যর্থ।</string>\n    <string name=\"uninstalled_successfully\"><xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g> আনইন্সটল করা হয়েছে।</string>\n    <string name=\"uninstall_system_app_message\">এটি একটি সিস্টেম অ্যাপ। আপনি কি এটি আনইনস্টল করার ব্যাপারে নিশ্চিত?</string>\n    <string name=\"stopped\">স্থগিত</string>\n    <string name=\"disable\">নিষ্ক্রিয় করুন</string>\n    <string name=\"enable\">সক্রিয় করুন</string>\n    <string name=\"force_stop\">কাটুন</string>\n    <string name=\"failed_to_stop\"><xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g>টি কাটতে ব্যার্থ.</string>\n    <string name=\"storage_and_cache\">স্টোরেজ এবং ক্যাশে</string>\n    <string name=\"total_size\">মোট</string>\n    <string name=\"app_size\">অ্যাপ</string>\n    <string name=\"app_ops\">অ্যাপ অপ্স</string>\n    <string name=\"no_app_ops\">কোনো অ্যাপ অপারেশন নেই</string>\n    <string name=\"usage_access\">ইউসেজ অ্যাক্সেস</string>\n    <string name=\"app_settings\">সেটিংস</string>\n    <string name=\"usage_yesterday\">গতকাল</string>\n    <string name=\"exodus_link\">\\\\u03b5xodus লিঙ্ক</string>\n    <string name=\"sort_by_blocked_components\">ব্লকড গুলো প্রথমে</string>\n    <string name=\"external_data_dir\">বাহ্যিক ডাটা ডিরেক্টরি</string>\n    <string name=\"external_multiple_data_dir\">বাহ্যিক ডাটা ডিরেক্টরি <xliff:g id=\"dir_no\" example=\"1\">%1$d</xliff:g></string>\n    <plurals name=\"no_of_times_opened\">\n        <item quantity=\"one\">%1$d বার</item>\n        <item quantity=\"other\">%1$d বার</item>\n    </plurals>\n    <string name=\"sort_by_last_used\">সর্বশেষ ব্যবহৃত</string>\n    <string name=\"sort_by_mobile_data\">মোবাইল ডাটা</string>\n    <string name=\"pref_import_export_blocking_rules\">ব্লকিং বিধিগুলো ইম্পোর্ট/এক্সপোর্ট করুন</string>\n    <string name=\"pref_import_watt\">ওয়াট(Watt) থেকে ইম্পোর্ট করুন</string>\n    <string name=\"pref_import_blocker\">ব্লকার থেকে ইম্পোর্ট করুন</string>\n    <string name=\"the_import_was_successful\">ইমপোর্টেড</string>\n    <string name=\"the_export_was_successful\">এক্সপোর্টেড</string>\n    <string name=\"apk_updater\">এপিকে আপডেটর</string>\n    <string name=\"running_apps\">চলমান এপ্স</string>\n    <string name=\"kill_process\">কাটুন</string>\n    <string name=\"pid_and_ppid\">প্রসেস আইডি: %1$d, প্যারেন্ট প্রসেস আইডি: %2$d</string>\n    <string name=\"memory_virtual_memory\">মেমোরি: %1$s, ভার্চুয়াল মেমোরি: %2$s</string>\n    <string name=\"user_and_uid\">ব্যবহারকারী: <xliff:g id=\"user_name\" example=\"root\">%1$s</xliff:g> (<xliff:g id=\"user_id\" example=\"0\">%2$d</xliff:g>)</string>\n    <string name=\"clear_data\">ডাটা মুছুন</string>\n    <string name=\"backup_restore\">ব্যাকআপ/পুনরুদ্ধার</string>\n    <string name=\"export_blocking_rules\">ব্লকিং বিধিগুলো এক্সপোর্ট করুন</string>\n    <plurals name=\"alert_failed_to_clear_data\">\n        <item quantity=\"one\">%1$dটি অ্যাপ থেকে ডাটা মুছতে ব্যর্থ</item>\n        <item quantity=\"other\">%1$dটি অ্যাপ থেকে ডাটা মুছতে ব্যর্থ</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_uninstall\">\n        <item quantity=\"one\">%1$d অ্যাপটি আনইনস্টল করতে ব্যর্থ</item>\n        <item quantity=\"other\">%1$d অ্যাপ গুলো আনইনস্টল করতে ব্যর্থ</item>\n    </plurals>\n    <string name=\"the_operation_was_successful\">সম্পন্ন</string>\n    <string name=\"toggle_kill_for_system_apps\">কিল অপশনটি টগল করুন সিস্টেম অ্যাপগুলোর জন্য</string>\n    <string name=\"permission_name\">অনুমতির নাম</string>\n    <string name=\"mode\">মোড</string>\n    <string name=\"running\">চলমান</string>\n    <string name=\"duration\">সময়সীমা</string>\n    <string name=\"ago\">আগে</string>\n    <string name=\"pref_app_theme\">অ্যাপের থিম</string>\n    <string name=\"follow_system\">সিস্টেমকে অনুসরণ করুন</string>\n    <string name=\"battery_mode\">ব্যাটারি মোড</string>\n    <string name=\"day\">দিন</string>\n    <string name=\"night\">রাত</string>\n    <string name=\"select_theme\">থিম নির্বাচন করুন</string>\n    <string name=\"apply\">প্রয়োগ করুন</string>\n    <string name=\"version\">সংস্করণ</string>\n    <string name=\"sort_by_wifi_data\">ওয়াইফাই ডাটা</string>\n    <string name=\"block_trackers\">ট্র্যাকার গুলো ব্লক করুন</string>\n    <string name=\"reset_to_default\">ডিফল্টে রিসেট করুন</string>\n    <string name=\"sort_by_app_ops_names\">অ্যাপ অপ্সের নাম</string>\n    <string name=\"sort_by_app_ops_values\">অ্যাপ অপ্সের মান</string>\n    <string name=\"sort_by_permission_names\">অনুমতির নাম</string>\n    <string name=\"sort_by_dangerous_permissions\">বিপজ্জনক গুলো প্রথমে</string>\n    <string name=\"sort_by_tracker_components\">প্রথমে ট্র্যাকার</string>\n    <string name=\"unknown_op\">অজানা অপারেশন</string>\n    <plurals name=\"alert_failed_to_disable_trackers\">\n        <item quantity=\"one\">%1$dটি অ্যাপ থেকে ট্র্যাকার নিষ্ক্রিয় করা যায়নি</item>\n        <item quantity=\"other\">%1$dটি অ্যাপ থেকে ট্র্যাকার নিষ্ক্রিয় করা যায়নি</item>\n    </plurals>\n    <string name=\"failed_to_grant_permission\">অনুমতি দেওয়া যায়নি</string>\n    <string name=\"failed_to_revoke_permission\">অনুমতি বাতিল করা যায়নি</string>\n    <string name=\"failed_to_reset_app_ops\">অ্যাপ অপস রিসেট করা যায়নি</string>\n    <string name=\"failed_to_deny_dangerous_perms\">সকল বিপজ্জনক অনুমতি গুলো অগ্রাহ্য করতে ব্যর্থ</string>\n    <string name=\"failed_to_deny_dangerous_app_ops\">সকল বিপজ্জনক অ্যাপ অপস গুলো অগ্রাহ্য করতে ব্যর্থ</string>\n    <string name=\"launch_app\">চালু করুন</string>\n    <string name=\"never_ask\">কখনও জিজ্ঞাসা করবেন না</string>\n    <string name=\"one_click_ops\">১-ক্লিক অপস</string>\n    <string name=\"changelog\">পরিবর্তনসূচী</string>\n    <plurals name=\"no_of_trackers\">\n        <item quantity=\"one\">%1$dটি ট্র্যাকার</item>\n        <item quantity=\"other\">%1$dটি ট্র্যাকার</item>\n    </plurals>\n    <string name=\"install\">ইনস্টল করুন</string>\n    <string name=\"update\">হালনাগাদ</string>\n    <string name=\"source_code\">সোর্স কোড</string>\n    <string name=\"clear_cache\">ক্যাশে মুছুন</string>\n    <string name=\"block_unblock_trackers_description\">সকল ইনস্টলড থাকা অ্যাপ গুলো থেকে বিজ্ঞাপন এবং ট্র্যাকিং উপাদানগুলিকে ব্লক/আনব্লক করুন</string>\n    <string name=\"clear_data_from_uninstalled_apps\">আনইনস্টলড অ্যাপগুলো থেকে ডাটা মুছুন</string>\n    <string name=\"clear_app_cache\">অ্যাপের ক্যাশ পরিষ্কার করুন</string>\n    <string name=\"clear_app_cache_description\">সকল অ্যাপ হতে ক্যাশ মুছে ফেলুন</string>\n    <string name=\"no_tracker_found\">কোনো ট্র্যাকার পাওয়া যায়নি</string>\n    <string name=\"filtered_packages\">ফিল্টার করা প্যাকেজ গুলো</string>\n    <string name=\"input_app_ops\">অ্যাপ অপস এর মান ইনপুট করুন</string>\n    <string name=\"only_works_in_root_or_adb_mode\">শুধুমাত্র রুট অথবা এডিবি মোডে ব্যবহারযোগ্য</string>\n    <string name=\"termux\">টার্মাক্স</string>\n    <string name=\"package_name_is_installed_successfully\"><xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g> সফলভাবে ইনস্টল হয়েছে</string>\n    <string name=\"filter_user_apps\">ব্যবহারকারীর এপ</string>\n    <string name=\"filter_system_apps\">সিস্টেম এপ্স</string>\n    <string name=\"select_all\">সবগুলো নির্বাচন করুন</string>\n    <string name=\"installed_version\">ইনস্টলকৃত সংস্করণ</string>\n    <string name=\"trackers\">ট্র্যাকারসমূহ</string>\n    <string name=\"features\">বৈশিষ্ট্যসমূহ</string>\n    <string name=\"whats_new\">নুতুনত্ব</string>\n    <string name=\"blocking_rules\">ব্লকিং এর বিধিগুলো</string>\n    <string name=\"external_data\">বাহ্যিক ডাটা</string>\n    <string name=\"data\">ডাটা</string>\n    <string name=\"backup\">ব্যাকআপ</string>\n    <string name=\"restore\">পুনরুদ্ধার</string>\n    <string name=\"delete_backup\">ব্যাকআপ মুছুন</string>\n    <plurals name=\"alert_failed_to_backup\">\n        <item quantity=\"one\">%1$d অ্যাপটি ব্যাকআপ করতে ব্যর্থ</item>\n        <item quantity=\"other\">%1$d অ্যাপস গুলো পুনরুদ্ধার করতে ব্যর্থ</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_restore\">\n        <item quantity=\"one\">%1$d অ্যাপটির ব্যাকআপ পুনরুদ্ধার করতে ব্যর্থ</item>\n        <item quantity=\"other\">%1$d অ্যাপস গুলোর ব্যাকআপ পুনরুদ্ধার করতে ব্যর্থ</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_delete_backup\">\n        <item quantity=\"one\">%1$d অ্যাপটির ব্যাকআপ মুছতে করতে ব্যর্থ</item>\n        <item quantity=\"other\">%1$d অ্যাপস গুলোর ব্যাকআপ মুছতে করতে ব্যর্থ</item>\n    </plurals>\n    <string name=\"apply_to_system_apps\">সিস্টেম অ্যাপ্লিকেশনগুলিতে প্রয়োগ করুন</string>\n    <string name=\"apply_to_system_apps_question\">সিস্টেম অ্যাপ গুলোতেও প্রয়োগ করবেন\\? অনিশ্চিত হলে \\'না\\' বাছুন।</string>\n    <string name=\"no\">না</string>\n    <string name=\"yes\">হ্যাঁ</string>\n    <string name=\"clear_data_message\">আপনি কি এই অ্যাপ্লিকেশনটি থেকে ডাটা মুছার বিষয়ে নিশ্চিত\\?</string>\n    <string name=\"clear\">মুছুন</string>\n    <string name=\"block\">ব্লক</string>\n    <string name=\"unblock\">আনব্লক</string>\n    <string name=\"block_unblock_trackers\">ট্র্যাকার গুলো ব্লক/আনব্লক করুন</string>\n    <string name=\"export_icon\">আইকন এক্সট্রাক্ট করুন</string>\n    <string name=\"open_in_termux\">টার্মাকসে খুলুন</string>\n    <string name=\"run_in_termux\">টার্মাক্সে চালান</string>\n    <string name=\"website\">ওয়েবসাইট</string>\n    <string name=\"pref_remove_all_rules\">সব নীতি মুছে ফেলুন</string>\n    <string name=\"are_you_sure\">আপনি কি নিশ্চিত\\?</string>\n    <string name=\"toggle_default_app_ops\">ডিফল্ট অ্যাপ অপস টগল করুন</string>\n    <string name=\"installer_error_blocked_device\">ডিভাইস</string>\n    <string name=\"installer_error_incompatible\">অ্যাপ্লিকেশনটি এই ডিভাইসের জন্য অসমর্থিত</string>\n    <string name=\"installer_error_storage\">অ্যাপ ইনস্টল করার জন্য পর্যাপ্ত জায়গা নেই</string>\n    <string name=\"installer_error_generic\">ইনস্টলেশন ব্যর্থ</string>\n    <string name=\"operation_running\">অপারেশন চলছে…</string>\n    <string name=\"full_stop_tap_to_see_details\">. বিবরণ দেখার জন্য ট্যাপ করুন।</string>\n    <string name=\"try_again\">পুনরায় চেষ্টা করুন</string>\n    <string name=\"install_app_message\">আপনি কি এই অ্যাপটি ইনস্টল করতে চান?</string>\n    <string name=\"reinstall\">পুনরায় ইনস্টল করুন</string>\n    <string name=\"unblock_trackers\">ট্র্যাকারসমূহ আনব্লক করুন</string>\n    <string name=\"install_in_progress\">ইনস্টল হচ্ছে</string>\n    <string name=\"filter_apps_with_rules\">বিধি সহ অ্যাপস</string>\n    <string name=\"failed_to_parse_some_numbers\">কিছু সংখ্যাকে পার্স করতে ব্যর্থ</string>\n    <string name=\"input_signatures\">স্বাক্ষর ইনপুট করুন</string>\n    <string name=\"failed_packages\">ব্যর্থ প্যাকেজগুলো</string>\n    <string name=\"external_apk_no_app_op\">বহিঃস্থ এপিকের কোন অ্যাপ অপারেশন নেই</string>\n    <string name=\"batch_ops\">ব্যাচ অপারেশন</string>\n    <string name=\"installer_error_lidl_rom\">আপনার রম রুটহীন ইনস্টলারটির সাথে অসমর্থিত।</string>\n    <string name=\"installer_error_bad_apks\">অকার্যকর এপিকে ফাইল নির্বাচিত</string>\n    <string name=\"installer_error_conflict\">অ্যাপটি ইনস্টল করতে অক্ষম কারণ এটি একই প্যাকেজ নামের সাথে ইতোমধ্যে ইনস্টল করা একটি অ্যাপের সাথে দ্বন্দ্ব করে</string>\n    <string name=\"installer_error_aborted\">ইনস্টলেশন ব্যর্থ হয়েছে কারণ হয় এটি বাতিল হয়েছে বা সেশনটি অপ্রত্যাশিতভাবে বন্ধ হয়ে গেছে</string>\n    <string name=\"filter_apps_with_activities\">কার্যকলাপসহ অ্যাপস</string>\n    <string name=\"package_installer\">প্যাকেজ ইনস্টলার</string>\n    <string name=\"installer_error_security\">এপিকে ফাইলগুলো অ্যাক্সেস করা যাচ্ছে না</string>\n    <string name=\"installer_error_session_create\">ইনস্টলার সেশন তৈরি করতে ব্যর্থ</string>\n    <string name=\"installer_error_session_abandon\">ইনস্টলার সেশনটি ত্যাগ করতে ব্যর্থ</string>\n    <string name=\"base_apk\">মূল এপিকে</string>\n    <string name=\"split_feature_name\">বৈশিষ্ট্য: <xliff:g id=\"feature_name\" example=\"Visualizer\">%1$s</xliff:g></string>\n    <string name=\"no_content\">কোন বিষয়বস্তু নেই</string>\n    <string name=\"no_usage_in_this_time_range\">এই সময় সীমার মধ্যে কোনো ব্যবহারের ডাটা নেই</string>\n    <string name=\"sort_by_screen_time\">স্ক্রীনের সময়</string>\n    <string name=\"key_name\">মূল নাম</string>\n    <string name=\"touchscreen_finger\">আঙ্গুল</string>\n    <string name=\"touchscreen_stylus\">স্টাইলাস</string>\n    <string name=\"navigation_trackball\">ট্র্যাকবল</string>\n    <string name=\"keyboard_qwerty\">QWERTY</string>\n    <string name=\"_undefined\">অসংজ্ঞায়িত</string>\n    <string name=\"required\">প্রয়োজনীয়</string>\n    <string name=\"orientation_sensor\">সেন্সর</string>\n    <string name=\"orientation_user\">ব্যবহারকারী</string>\n    <string name=\"orientation_portrait\">পোর্ট্রেট</string>\n    <string name=\"orientation_landscape\">ল্যান্ডস্কেপ</string>\n    <string name=\"orientation_locked\">লকড</string>\n    <string name=\"orientation_unspecified\">অনির্দিষ্ট</string>\n    <string name=\"launch_mode_multiple\">একাধিক</string>\n    <string name=\"input_features\">বৈশিষ্ট্যগুলি ইনপুট করুন</string>\n    <string name=\"export_failed\">এক্সপোর্ট করতে ব্যর্থ!</string>\n    <string name=\"reject_time\">প্রত্যাখ্যানের সময়</string>\n    <string name=\"accept_time\">গ্রহণের সময়</string>\n    <plurals name=\"failed_to_import_files\">\n        <item quantity=\"one\">%1$d ফাইলটি ইম্পোর্ট করতে ব্যর্থ।</item>\n        <item quantity=\"other\">%1$d ফাইলগুলো ইম্পোর্ট করতে ব্যর্থ।</item>\n    </plurals>\n    <string name=\"touchscreen\">টাচস্ক্রিন</string>\n    <string name=\"keyboard_type\">কীবোর্ডের ধরন</string>\n    <string name=\"import_failed\">ইম্পোর্ট করতে ব্যর্থ!</string>\n    <string name=\"shared_libs\">শেয়ার্ড লাইব্রেরি সমূহ</string>\n    <string name=\"configurations\">সাজানোর পদ্ধতি</string>\n    <string name=\"read\">পড়ুন</string>\n    <string name=\"task_affinity\">কার্য সখ্যতা</string>\n    <string name=\"launch_mode\">লঞ্চ মোড</string>\n    <string name=\"uses_feature\">ব্যবহৃত ফিচার্স</string>\n    <string name=\"paths_and_directories\">পাথ এবং ডিরেক্টরি</string>\n    <string name=\"block_components_dots\">উপাদানগুলি ব্লক করুন…</string>\n    <string name=\"rules_not_applied\">বিধিগুলো প্রয়োগ করা হয়নি</string>\n    <string name=\"failed_to_disable_op\">অনুরোধকৃত অ্যাপ অপটিকে নিষ্ক্রিয় করা যায়নি</string>\n    <string name=\"no_shared_libs\">কোন শেয়ার্ড লাইব্রেরি নেই</string>\n    <string name=\"all_classes\">সকল ক্লাস</string>\n    <string name=\"class_name\">শ্রেণির নাম</string>\n    <string name=\"installer_app\">যে অ্যাপ দ্বারা ইনস্টলড হয়েছে</string>\n    <string name=\"about\">সম্পর্কে</string>\n    <plurals name=\"alert_failed_to_unblock_trackers\">\n        <item quantity=\"one\">%1$d অ্যাপ থেকে ট্র্যাকারগুলো আনব্লক করতে ব্যর্থ</item>\n        <item quantity=\"other\">%1$d অ্যাপগুলি থেকে ট্র্যাকারগুলো আনব্লক করতে ব্যর্থ</item>\n    </plurals>\n    <plurals name=\"failed_to_backup_some_apk_files\">\n        <item quantity=\"one\">%1$d অ্যাপটি ব্যাকআপ করতে ব্যর্থ</item>\n        <item quantity=\"other\">%1$d অ্যাপগুলো ব্যাকআপ করতে ব্যর্থ</item>\n    </plurals>\n    <string name=\"permissions\">ব্যবহৃত অনুমতিসমূহ</string>\n    <string name=\"choose_language\">ভাষা নির্বাচন করুন</string>\n    <string name=\"auto\">অটো</string>\n    <string name=\"pref_app_language\">ভাষা</string>\n    <string name=\"backup_all_users\">সকল ব্যবহারকারী</string>\n    <string name=\"obb_files_extracted_successfully\">Obb ফাইলগুলি সফলভাবে এক্সট্র্যাক্ট হয়েছে</string>\n    <string name=\"failed_to_extract_obb_files\">Obb ফাইলগুলি এক্সট্র্যাক্ট করতে ব্যর্থ</string>\n    <string name=\"backup_obb_media\">Backup Obb</string>\n    <string name=\"backup_apk_files\">শুধু এপিকে</string>\n    <string name=\"no_matching_package_found\">কোনো প্যাকেজের সাথে মিল পাওয়া যায়নি</string>\n    <string name=\"skip_signature_checks\">স্বাক্ষর চেকগুলি এড়িয়ে যান</string>\n    <string name=\"backup_options\">Backup Options</string>\n    <string name=\"components\">উপাদানগুলো</string>\n    <string name=\"clear_data_from_uninstalled_apps_description\"><tt>DONT_DELETE_DATA</tt> ফ্ল্যাগ দ্বারা আনইনস্টলড অ্যাপগুলো থেকে ডাটা মুছুন</string>\n    <string name=\"manifest_viewer\">ম্যানিফেস্ট ভিউয়ার</string>\n    <string name=\"sort_by_target_sdk\">টার্গেট SDK</string>\n    <string name=\"sort_by_sha\">স্বাক্ষর</string>\n    <string name=\"shared_user_id\">শেয়ার্ড ব্যবহারকারীর আইডি</string>\n    <string name=\"sort_by_shared_user_id\">শেয়ার্ড ব্যবহারকারীর আইডি</string>\n    <string name=\"error_creating_shortcut\">শর্টকাট তৈরি করতে ব্যর্থ</string>\n    <string name=\"app_signing_no_signatures\">কোন স্বাক্ষর নেই</string>\n    <string name=\"signatures\">স্বাক্ষর</string>\n    <string name=\"write\">লিখুন</string>\n    <string name=\"path_permissions\">পথের অনুমতিসমূহ</string>\n    <string name=\"orientation\">দিক</string>\n    <string name=\"shared_prefs\">শেয়ারকৃত প্রিফেস</string>\n    <string name=\"debuggable\">ডিবাগযোগ্য</string>\n    <string name=\"requested_large_heap\">বড় স্তূপ</string>\n    <string name=\"no_tracker_class\">কোনও ট্র্যাকার শ্রেণি নেই</string>\n    <string name=\"tracker_classes\">ট্র্যাকার ক্লাস</string>\n    <string name=\"word_wrap\">শব্দ মোড়ক টগল করুন</string>\n    <string name=\"icon_picker\">আইকন পিকার</string>\n    <string name=\"no_configurations\">কোন কনফিগারেশন নেই</string>\n    <string name=\"deny_dangerous_app_ops\">বিপজ্জনক অ্যাপস অপস গুলো প্রত্যাখ্যান করুন</string>\n    <string name=\"sort_by_component_name\">উপাদানের নাম</string>\n    <string name=\"pref_about_msg\">অ্যাপ ম্যানেজারের সংস্করণ, লাইসেন্স, স্বীকৃতি, etc.</string>\n    <string name=\"pref_global_blocking_enabled\">গ্লোবাল উপাদান ব্লকিং</string>\n    <string name=\"type_boolean\">সত্য/মিথ্যা</string>\n    <string name=\"native_library_dir\">Native JNI Library ডিরেক্টরি</string>\n    <string name=\"create_shortcut\">শর্টকাট তৈরি করুন</string>\n    <string name=\"manifest\">ম্যানিফেস্ট</string>\n    <string name=\"soft_input\">সফট ইনপুট মোড</string>\n    <string name=\"no_service\">কোনো সার্ভিসেস নেই</string>\n    <string name=\"service\">সার্ভিসেস</string>\n    <string name=\"authority\">কর্তৃত্ব</string>\n    <string name=\"no_providers\">কোন প্রদানকারী নেই</string>\n    <string name=\"providers\">প্রদানকারী</string>\n    <string name=\"no_receivers\">কোনও গ্রহণকারী নেই</string>\n    <string name=\"receivers\">গ্রহণকারী</string>\n    <string name=\"orientation_no_sensor\">কোন সেন্সর নেই</string>\n    <string name=\"orientation_sensor_portrait\">সেন্সর পোর্ট্রেট</string>\n    <string name=\"orientation_sensor_landscape\">সেন্সর ল্যান্ডস্কেপ</string>\n    <string name=\"navigation_dial_pad\">ডায়াল প্যাড</string>\n    <string name=\"touchscreen_no_touch\">কোন টাচ নেই</string>\n    <string name=\"navigation\">নেভিগেশন</string>\n    <string name=\"export_options\">অপসন গুলো এক্সপোর্ট করুন</string>\n    <string name=\"import_options\">অপসন গুলো ইম্পোর্ট করুন</string>\n    <string name=\"pref_export\">এক্সপোর্ট</string>\n    <string name=\"pref_import\">ইম্পোর্ট</string>\n    <string name=\"pref_import_export_blocking_rules_msg\">ইম্পোর্ট/এক্সপোর্ট বিধি, ওয়াট বা ব্লকার থেকে বহিঃস্থ বিধি ইম্পোর্ট করুন।</string>\n    <string name=\"str_logo\">লোগো</string>\n    <string name=\"class_viewer\">ক্লাস ভিউয়ার</string>\n    <string name=\"failed_to_enable_op\">অনুরোধকৃত অ্যাপ অপটিকে সক্রিয় করা যায়নি</string>\n    <plurals name=\"other_trackers_and_classes\">\n        <item quantity=\"one\"><xliff:g id=\"tracker_no\" example=\"8\">%1$d</xliff:g>টি ট্র্যাকার এবং <xliff:g id=\"class_no\" example=\"50\">%2$d</xliff:g>টি ক্লাস</item>\n        <item quantity=\"other\"><xliff:g id=\"tracker_no\" example=\"8\">%1$d</xliff:g>টি ট্র্যাকার এবং <xliff:g id=\"class_no\" example=\"50\">%2$d</xliff:g> ক্লাস</item>\n    </plurals>\n    <plurals name=\"two_trackers_and_classes\">\n        <item quantity=\"one\">২টি ট্র্যাকার এবং <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g> ক্লাস</item>\n        <item quantity=\"other\">২টি ট্র্যাকার এবং <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g> ক্লাস</item>\n    </plurals>\n    <plurals name=\"tracker_and_classes\">\n        <item quantity=\"one\">১টি ট্র্যাকার এবং <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g>টি ক্লাস</item>\n        <item quantity=\"other\">১টি ট্র্যাকার এবং <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g>টি ক্লাস</item>\n    </plurals>\n    <string name=\"pref_compression_method\">সংকোচন পদ্ধতি</string>\n    <string name=\"rules\">বিধি গুলো</string>\n    <string name=\"size\">আকার</string>\n    <string name=\"app_signing_signatures\">স্বাক্ষর</string>\n    <plurals name=\"usage_minutes\">\n        <item quantity=\"one\">%1$d মিঃ</item>\n        <item quantity=\"other\">%1$d মিঃ</item>\n    </plurals>\n    <string name=\"type_string\">অক্ষর</string>\n    <string name=\"pref_global_blocking_enabled_msg\">এরি মাধ্যমে আপনি যেকোনো অ্যাপের যেকোনো অংশ ব্লক করতে পারবে, তা করতে নির্দিষ্টভাবে অ্যাপটির জন্য ব্লকিং চালু করতে হবে না।</string>\n    <string name=\"failed_to_uninstall_app\">আনইন্সটল ব্যর্থ হয়েছে</string>\n    <string name=\"sort_by_times_opened\">কতবার খোলা হয়েছে</string>\n</resources>"
  },
  {
    "path": "app/src/main/res/values-cs/disclaimer.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- SPDX-License-Identifier: GPL-3.0-or-later --><resources>\n    <string name=\"disclaimer_header\">Zřeknutí se odpovědnosti</string>\n    <string name=\"disclaimer_body\">App Manager poskytuje funkce root, které mohou při nesprávném použití poškodit vaše zařízení. App manager není zodpovědný za škody způsobené nesprávným používáním této aplikace. Pokud si nejste plně jistí, jak funguje root, měli byste se vyvarovat root možnostem, dokud nebudete plně seznámení s riziky.\n\\n\n\\nJakýkoliv odkaz na jiné aplikace, který poskytnu, je pro dobro uživatele. Nejsem ovšem zodpovědný za jakýkoliv obsah, který můžete naleznout na externích stránkách.\n\\n\n\\nVyužíváním aplikace App Manager přejímáte plnou zodpovědnost za své vlastní užívání a přijímáte, že žádné škody, nároky či peněžní hodnoty nebudou zaslány kvůli nesprávnému užívání aplikace.\n\\n\n\\nVyužíváním této aplikace přejímáte veškerou zodpovědnost na sebe a souhlasíte, že nejsem zodpovědný za jakékoliv vámi vykonané akce, které by mohly mít nepříznivý dopad na vaše zařízení.</string>\n    <string name=\"disclaimer_footer\">© 2020–2024 Muntashir Al-Islam</string>\n</resources>"
  },
  {
    "path": "app/src/main/res/values-cs-rCZ/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- SPDX-License-Identifier: GPL-3.0-or-later --><resources xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:tools=\"http://schemas.android.com/tools\">\n    <string name=\"uninstall\">Odinstalovat</string>\n    <string name=\"require_no_permission\">Nejsou vyžadována žádná oprávnění</string>\n    <string name=\"activities\">Aktivity</string>\n    <string name=\"launch\">Spustit</string>\n    <string name=\"error\">Chyba</string>\n    <string name=\"loading\">Načítání…</string>\n    <!-- &#8230; = ... -->\n    <string name=\"license\">Licence</string>\n    <string name=\"usage_weekly\">Za týden</string>\n    <string name=\"usage_today\">Dnes</string>\n    <string name=\"usage_7_days\">Posledních 7 dní</string>\n    <string name=\"service\">Služby</string>\n    <string name=\"launch_mode\">Režim spuštění</string>\n    <string name=\"no_providers\">Žadné poskytovače</string>\n    <string name=\"providers\">Poskytovače</string>\n    <string name=\"no_activities\">Žádné aktivity</string>\n    <string name=\"refresh\">Obnovit</string>\n    <string name=\"permissions\">Využívá oprávnění</string>\n    <string name=\"input_features\">Funkce pro vstup</string>\n    <string name=\"no_configurations\">Žádné konfigurace</string>\n    <string name=\"configurations\">Konfigurace</string>\n    <string name=\"app_signing_no_signatures\">Žádné platné podpisy</string>\n    <string name=\"app_signing_signatures\">Podpisy</string>\n    <string name=\"signatures\">Podpisy</string>\n    <string name=\"sort_by_sha\">Podpis</string>\n    <string name=\"shared_user_id\">Sdílené ID uživatele</string>\n    <string name=\"sort_by_shared_user_id\">Sdíleného ID uživatele</string>\n    <string name=\"no_feature\">Žádné funkce</string>\n    <string name=\"uses_feature\">Používá funkce</string>\n    <string name=\"group\">Skupina</string>\n    <string name=\"shared_libs\">Sdílené knihovny</string>\n    <string name=\"declared_permission\">Oprávnění</string>\n    <string name=\"patterns_allowed\">Povolené vzory</string>\n    <string name=\"write\">Zapisovat</string>\n    <string name=\"read\">Číst</string>\n    <string name=\"grant_uri_permission\">Udělit URI oprávnění</string>\n    <string name=\"flags\">Vlajky</string>\n    <string name=\"orientation\">Otočení</string>\n    <string name=\"no_service\">Žádné služby</string>\n    <string name=\"authority\">Autorita</string>\n    <string name=\"sort_by_last_update\">Nejnovější aktualizace</string>\n    <string name=\"paths_and_directories\">Cesty a Adresáře</string>\n    <string name=\"data_dir\">Adresář Dat</string>\n    <string name=\"date_updated\">Datum Aktualizace</string>\n    <string name=\"user_app\">Uživatelská aplikace</string>\n    <string name=\"sdk_max\">Cíl</string>\n    <string name=\"starting_activity\">Spouštění aktivity: <xliff:g id=\"activity_name\" example=\".main.MainActivity\">%1$s</xliff:g></string>\n    <string name=\"data_usage_msg\">Využití dat</string>\n    <string name=\"app_not_installed\">Aplikace není nainstalována</string>\n    <string name=\"word_wrap\">Přepnout obtékání slov</string>\n    <string name=\"create_shortcut\">Vytvořit Zástupce</string>\n    <string name=\"class_name\">Název Třídy</string>\n    <string name=\"date_installed\">Datum Instalace</string>\n    <string name=\"user_id\">ID Uživatele</string>\n    <string name=\"error_creating_shortcut\">Chyba vytváření zástupce</string>\n    <string name=\"app_info\">Informace o aplikaci</string>\n    <string name=\"system_app\">Systémová aplikace</string>\n    <string name=\"source_dir\">Adresář Zdroje</string>\n    <string name=\"about\">O aplikaci</string>\n    <string name=\"data_size\">Data</string>\n    <string name=\"cache_size\">Mezipaměť</string>\n    <string name=\"sort_by_package_name\">Název balíčku</string>\n    <string name=\"user\">Uživatel</string>\n    <string name=\"system\">Systém</string>\n    <string name=\"sort\">Setřídit</string>\n    <string name=\"version_name_with_code\">Verze <xliff:g id=\"version_name\" example=\"2.5.17\">%1$s</xliff:g> (<xliff:g id=\"version_code\" example=\"365\">%2$d</xliff:g>)</string>\n    <string name=\"more_info\">Více Info</string>\n    <string name=\"empty_package_name\">Název prázdného balíčku</string>\n    <string name=\"error_verbose_pin_shortcut\">Současný spouštěč nepodporuje funkci PinShortcut. Nelze vytvořit zástupce.</string>\n    <string name=\"package_name\">Název Balíčku</string>\n    <string name=\"shortcut_name\">Nazev Zástupce</string>\n    <string name=\"third_party\">Ikony a Knihovny třetích stran</string>\n    <string name=\"soft_input\">Režim softwarového vstupu</string>\n    <string name=\"no_receivers\">Žádné přijímače</string>\n    <string name=\"receivers\">Přijímače</string>\n    <string name=\"task_affinity\">Příslušnost úlohy</string>\n    <string name=\"sort_by_app_label\">Označení aplikace</string>\n    <string name=\"manifest\">Manifest</string>\n    <string name=\"path_permissions\">Oprávnění k cestán</string>\n    <string name=\"sdk_min\">Min</string>\n    <string name=\"sort_by_domain\">Uživatelské aplikace jako první</string>\n    <string name=\"main_activity\">Hlavní činnosti</string>\n    <string name=\"tracker_details\">Detaily o trackeru</string>\n    <string name=\"tracker_classes\">Třídy trackeru</string>\n    <string name=\"credits_message\">Autorům\n\\n- Otevřený projekt Android\n\\n- <a href=\"https://github.com/butzist/ActivityLauncher\">Spouštěč činností</a>\n\\n- <a href=\"https://bitbucket.org/oF2pks/fdroid-applications-info\">Apps_packages Info</a>\n\\n- <a href=\"https://github.com/zhaobao/AppsMonitor\">AppsMonitor</a>\n\\n- <a href=\"https://github.com/8enet/AppOpsX\">AppOpsX</a>\n\\n- <a href=\"https://github.com/billthefarmer/editor\">Editor</a>\n\\n- <a href=\"https://github.com/k3b/intent-intercept\">Intent Intercept</a>\n\\n- <a href=\"https://github.com/zhanghai/MaterialFiles\">Material Files</a>\n\\n- <a href=\"https://github.com/pluscubed/matlog\">MatLog</a>\n\\n- <a href=\"https://github.com/matrix-org/matrix-android-sdk\">Matrix Android SDK</a>\n\\n- <a href=\"https://github.com/jensstein/oandbackup\">OAndBackup</a>\n\\n- <a href=\"https://github.com/open-keychain/open-keychain\">Open Keychain</a>\n\\n- <a href=\"https://github.com/Aefyr/SAI\">SAI</a>\n\\n- <a href=\"https://github.com/RikkaApps/Shizuku\">Shizuku</a>\n\\n- <a href=\"https://github.com/tuyafeng/Watt\">Watt</a>\n\\nOriginální logo kreditu: <a href=\"https://github.com/Atrate\">Atrate</a> </string>\n    <string name=\"toggle_class_listing\">Přepínač listování třídy</string>\n    <plurals name=\"tracker_and_classes\">\n        <item quantity=\"one\">1 tracker s <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g> třídou</item>\n        <item quantity=\"few\">1 tracker s <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g> třídami</item>\n        <item quantity=\"other\">1 tracker s <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g> třídami</item>\n    </plurals>\n    <string name=\"obb_size\">Obb</string>\n    <string name=\"found_trackers\">Nalezené trackery:</string>\n    <string name=\"all_classes\">Všechny třídy</string>\n    <string name=\"credits\">Kredity</string>\n    <string name=\"icon_picker\">Sběrač ikon</string>\n    <string name=\"sdk_flags\">Příznaky</string>\n    <string name=\"installer_app\">Instalátor aplikace</string>\n    <string name=\"sort_by_target_sdk\">Cílové SDK</string>\n    <string name=\"data_transmitted\">Přenesená data</string>\n    <string name=\"data_received\">Obdržená data</string>\n    <string name=\"media_size\">Média</string>\n    <string name=\"class_viewer\">Zobrazovač třídy</string>\n    <string name=\"open_pgp_provider\">Poskytovatel OpenPGP</string>\n    <string name=\"pref_compression_method\">Metoda komprese</string>\n    <string name=\"filter_apps_with_backups\">Se zálohami</string>\n    <string name=\"no_matching_package_found\">Nepodařilo se najít žádnou takovou aplikaci</string>\n    <string name=\"installed_version\">Nainstalovaná verze</string>\n    <string name=\"disable\">Vypnout</string>\n    <string name=\"backup_obb_media\">OBB a média</string>\n    <string name=\"installer_error_session_create\">Nepodařilo se vytvořit relaci instalačního programu</string>\n    <string name=\"_undefined\">Nedefinováno</string>\n    <string name=\"rsa_exponent\">Exponent</string>\n    <string name=\"filter_running_apps\">Spuštěné aplikace</string>\n    <string name=\"failed_to_duplicate_profile\">Profil nelze duplikovat</string>\n    <string name=\"sort_by_memory_usage\">Využití paměti</string>\n    <string name=\"rsa_modulus\">Modul</string>\n    <string name=\"conversion_failed\">Konverze se nezdařila.</string>\n    <string name=\"test_only\">Pouze test</string>\n    <string name=\"validity\">Platnost</string>\n    <string name=\"pref_backup_flags_msg\">Přidáním předvoleb pro možnosti zálohování odpadá nutnost vybírat příznaky při každém zálohování/obnovení.</string>\n    <string name=\"installer_error_bad_apks\">Vybrané APK soubory jsou neplatné</string>\n    <string name=\"pref_import_existing_msg\">Přidat do App Manageru součásti zakázané jinými aplikacemi. Při používání tohoto nástroje buďte opatrní, protože může dojít k mnoha falešným poplachům.. Vyberte si pouze důvěryhodné aplikace.</string>\n    <string name=\"orientation_reverse_landscape\">Na šířku, obráceně</string>\n    <string name=\"input_profile_name\">Název profilu</string>\n    <string name=\"app_signing_install_without_data_loss\">Pokud jste vypnuli ověřování podpisu, můžete použít možnost <b>Only install</b> k instalaci aplikace bez ztráty dat.</string>\n    <string name=\"unblock\">Odblokovat</string>\n    <string name=\"external_data\">Externí data</string>\n    <plurals name=\"alert_failed_to_clear_data\">\n        <item quantity=\"one\">Nebylo možné vymazat data z %1$d aplikace</item>\n        <item quantity=\"few\">Nebylo možné vymazat data z %1$d aplikací</item>\n        <item quantity=\"other\">Nebylo možné vymazat data z %1$d aplikací</item>\n    </plurals>\n    <string name=\"toggle_kill_for_system_apps\">Přepnout zavírání systémových aplikací</string>\n    <string name=\"dsa_affine_x\">Afinní souřadnice x</string>\n    <string name=\"ecc\">Kryptografie eliptických křivek</string>\n    <string name=\"usage_access_not_supported\">Nepodařilo se požádat o přístup k údajům o využití, protože příslušná stránka nastavení neexistuje.</string>\n    <string name=\"backup_multiple\">Zálohovat více</string>\n    <string name=\"choose_language\">Změnit jazyk</string>\n    <string name=\"subject\">Předmět</string>\n    <string name=\"input_profile_name_description\">Název profilu nesmí obsahovat mezery.</string>\n    <string name=\"export_icon\">Extrahovat ikonu</string>\n    <string name=\"orientation_full_user\">Plný přístup</string>\n    <string name=\"valid\">Platný</string>\n    <string name=\"serial_no\">Sériové číslo</string>\n    <string name=\"touchscreen\">Dotyková obrazovka</string>\n    <string name=\"second_degree_tracker_note\">Předpona ² označuje, že trackery jsou v <a href=\"https://etip.exodus-privacy.eu.org/\"> pohotovostní seznamu ETIP </a>, např. zda se jedná o skutečné trackery, je stále prošetřováno.</string>\n    <string name=\"app_usage\">Použití aplikace</string>\n    <string name=\"checksums\">Kontrolní součty</string>\n    <string name=\"installer_error_storage\">Pro instalaci aplikace není dostatek úložiště</string>\n    <string name=\"enable\">Povolit</string>\n    <string name=\"running\">Spuštěno</string>\n    <string name=\"data\">Data</string>\n    <string name=\"user_and_uid\">Uživatel: <xliff:g id=\"user_name\" example=\"root\">%1$s</xliff:g> (<xliff:g id=\"user_id\" example=\"0\">%2$d</xliff:g>)</string>\n    <string name=\"error_evaluating_input\">Vstup nelze vyhodnotit</string>\n    <string name=\"community_links\"><a href=\"https://t.me/AppManagerChannel\">Kanál na Telegramu</a>•<a href=\"https://twitter.com/AppManagerNews\">Twitter</a></string>\n    <string name=\"reject_time\">Doba odmítnutí</string>\n    <string name=\"native_library_dir\">Nativní adresář knihoven JNI</string>\n    <string name=\"issued_date\">Datum vydání</string>\n    <string name=\"pref_remove_all_rules\">Odebrat všechna pravidla</string>\n    <string name=\"str_logo\">Logo</string>\n    <string name=\"kill_process\">Ukončit</string>\n    <string name=\"apply\">Použít</string>\n    <string name=\"no\">Ne</string>\n    <string name=\"open_in_termux\">Otevřít v Termux</string>\n    <string name=\"installer_error_blocked_device\">Zařízení</string>\n    <string name=\"storage_and_cache\">Úložiště a mezipaměť</string>\n    <string name=\"key_name\">Název klíče</string>\n    <string name=\"app_settings\">Nastavení</string>\n    <string name=\"usage_yesterday\">Včera</string>\n    <string name=\"apk_updater\">APK Updater</string>\n    <string name=\"running_apps\">Spuštěné aplikace</string>\n    <string name=\"export_blocking_rules\">Pravidla blokování exportu</string>\n    <string name=\"ago\">před</string>\n    <string name=\"filter_system_apps\">Systémové aplikace</string>\n    <string name=\"update_uninstalled_successfully\">Aktualizace pro <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g> byly odinstalovány.</string>\n    <string name=\"dsa_affine_y\">Afinní souřadnice y</string>\n    <string name=\"tap_to_submit_crash_report\">Klepnutím odešlete zprávu o selhání.</string>\n    <string name=\"copy\">Kopírovat</string>\n    <string name=\"pref_import\">Importovat</string>\n    <string name=\"backup_apk_files\">Soubory APK</string>\n    <string name=\"locale_split_for_base_apk\"><xliff:g id=\"split_name\" example=\"English\">%1$s</xliff:g> místo pro základní soubor APK</string>\n    <string name=\"orientation_unspecified\">Nespecifikováno</string>\n    <string name=\"no_tracker_found\">Nebyl nalezen žádný trakcer</string>\n    <string name=\"backup_all_users\">Všichni uživatelé</string>\n    <string name=\"pref_import_watt_msg\">Import pravidel blokování z Watt, z nichž každý soubor obsahuje pravidla pro jeden balíček s názvem <tt>packagename.xml</tt> atd.</string>\n    <string name=\"clear_data\">Vymazat údaje</string>\n    <string name=\"other\">Další</string>\n    <string name=\"sort_by_mobile_data\">Mobilní data</string>\n    <string name=\"clear_data_from_uninstalled_apps\">Vymazat data z odinstalovaných aplikací</string>\n    <string name=\"package_name_is_installed_successfully\">Aplikace <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g> byla naistalována</string>\n    <string name=\"new_profile\">Nový profil</string>\n    <string name=\"unknown_op\">Neznámá operace</string>\n    <string name=\"yes\">Ano</string>\n    <string name=\"rules_not_applied\">Pravidla se neuplatňují</string>\n    <string name=\"failed_to_deny_dangerous_perms\">Nepodařilo se zrušit všechna nebezpečná oprávnění</string>\n    <string name=\"deny_app_ops_description\">Nastavení režimu pro operace aplikace identifikované konstantními hodnotami, např. <tt>632</tt> or 3<tt>RUN_IN_BACKGROUND4</tt></string>\n    <string name=\"run_in_termux\">Spustit v Termux</string>\n    <string name=\"failed_to_fetch_package_info\">Nepodařilo se získat informace o balíčku</string>\n    <string name=\"pref_import_existing\">Importovat stávající pravidla</string>\n    <string name=\"filter_apps\">Aplikace</string>\n    <string name=\"add_item\">Přidat položku</string>\n    <string name=\"key_name_cannot_be_null\">Název klíče nemůže být prázdný</string>\n    <string name=\"navigation\">Navigace</string>\n    <string name=\"block_trackers\">Blokovat trackery</string>\n    <string name=\"deny_dangerous_app_ops\">Odmítnout nebezpečné aplikaci</string>\n    <string name=\"source_code\">Zdrojový kód</string>\n    <string name=\"block_unblock_trackers\">Blokovat/odblokovat trackery</string>\n    <string name=\"split_feature_name\">Funkce: <xliff:g id=\"feature_name\" example=\"Visualizer\">%1$s</xliff:g></string>\n    <string name=\"orientation_user_landscape\">Orientace uživatele na šířku</string>\n    <string name=\"cancel\">Zrušit</string>\n    <string name=\"share_apk\">Sdílet APK</string>\n    <string name=\"menu_apply_rules\">Použít pravidla</string>\n    <string name=\"type_string\">Znaky</string>\n    <string name=\"touchscreen_finger\">Prst</string>\n    <string name=\"grant_usage_access\">Udělení přístupu k použití</string>\n    <string name=\"decimal_value\">Desetinná hodnota</string>\n    <string name=\"uninstall_system_app_message\">Jedná se o systémovou aplikaci. Opravdu chcete tuto aplikaci odinstalovat\\?</string>\n    <string name=\"failed_to_stop\">Nepodařilo se zastavit <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g>.</string>\n    <string name=\"sort_by_denied_permissions\">Nejprve odmítnuto</string>\n    <string name=\"backup_options\">Možnosti zálohování</string>\n    <string name=\"profiles\">Profily</string>\n    <string name=\"no_tracker_class\">Žádné třídy trackerů</string>\n    <string name=\"reset_to_default\">Obnovit výchozí</string>\n    <string name=\"external_apk_no_app_op\">Externí soubor APK neprovádí s aplikacemi žádné operace</string>\n    <string name=\"failed_to_uninstall\">Nelze odinstalovat <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g>.</string>\n    <string name=\"installer_error_blocked\">Instalace blokována přes <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g></string>\n    <string name=\"failed_to_parse_some_numbers\">Některá čísla se nepodařilo zpracovat</string>\n    <string name=\"input_backup_name_description\">Název zálohy by neměl začínat číslicí ani by neměl obsahovat mezery. Pokud chcete použít aktuální datum a čas, nechte toto pole prázdné.</string>\n    <string name=\"try_again\">Zkusit znovu</string>\n    <string name=\"skip_signature_checks\">Přeskočit kontroly podpisů</string>\n    <string name=\"accept_time\">Doba schválení</string>\n    <string name=\"follow_system\">Systémově kompatibilní</string>\n    <string name=\"website\">Webová stránka</string>\n    <string name=\"navigation_dial_pad\">Číselník</string>\n    <string name=\"state_high_priority\">S vysokou prioritou</string>\n    <string name=\"issuer\">Vydavatel</string>\n    <string name=\"clear_data_message\">Opravdu chcete vymazat data z této aplikace\\?</string>\n    <string name=\"algorithm\">Algoritmus</string>\n    <string name=\"scanner\">Skener</string>\n    <string name=\"no_app_ops\">Žádné operace aplikace</string>\n    <string name=\"the_import_was_successful\">Importováno</string>\n    <string name=\"launch_mode_single_instance\">Jediná instance</string>\n    <string name=\"keyboard_no_keys\">Žádné klíče</string>\n    <string name=\"process_state_with_extra\">Stát: <xliff:g id=\"process_state\" example=\"Sleeping\">%1$s</xliff:g> (<xliff:g id=\"state_extra\" example=\"High priority\">%2$s</xliff:g>)</string>\n    <string name=\"filtered_packages\">Filtrované balíčky</string>\n    <string name=\"locale_split_for_feature\"><xliff:g id=\"split_name\" example=\"English\">%1$s</xliff:g> místo pro funkci <xliff:g id=\"feature_name\" example=\"Visualizer\">%2$s</xliff:g></string>\n    <string name=\"no_shared_libs\">Žádné sdílené knihovny</string>\n    <string name=\"export_failed\">Export se nezdařil!</string>\n    <string name=\"pref_import_blocker_msg\">Import pravidel blokování z aplikace Blocker, z nichž každé obsahuje pravidla pro jeden balíček.</string>\n    <string name=\"components\">Součásti</string>\n    <string name=\"pref_app_language\">Jazyk</string>\n    <string name=\"boolean_value\">Booleovská hodnota</string>\n    <string name=\"view_missing_signatures\">Klepnutím zobrazíte nebo odešlete podpisy, které ještě nejsou v databázi knihoven App Manageru.</string>\n    <string name=\"external_multiple_data_dir\">Adresář externích dat <xliff:g id=\"dir_no\" example=\"1\">%1$d</xliff:g></string>\n    <string name=\"filter_user_apps\">Uživatelské aplikace</string>\n    <string name=\"keyboard_qwerty\">QWERTY</string>\n    <string name=\"encryption\">Šifrování</string>\n    <string name=\"uninstalled_successfully\">Aplikace <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g> byla odinstalována.</string>\n    <string name=\"disable_background\">Zabránit operacím aplikace na pozadí</string>\n    <string name=\"battery_mode\">Režim baterie</string>\n    <string name=\"sort_by_app_ops_values\">Hodnota operací aplikace</string>\n    <string name=\"trackers\">Trackery</string>\n    <string name=\"touchscreen_no_touch\">Bez dotyku</string>\n    <string name=\"input_signatures\">Vložit podpisy</string>\n    <string name=\"installer_error_session_commit\">Soubory APK se nepodařilo schválit</string>\n    <string name=\"type\">Typ</string>\n    <string name=\"expired\">Platnost skončila</string>\n    <string name=\"failed_to_disable_op\">Nepodařilo se zakázat požadovanou operaci aplikace</string>\n    <string name=\"sort_by_app_ops_names\">Název operace aplikace</string>\n    <string name=\"usage_less_than_a_minute\">Méně než minuta</string>\n    <string name=\"go_back\">Zpět</string>\n    <string name=\"search\">Hledat</string>\n    <string name=\"process_name\">Název procesu</string>\n    <string name=\"no_code\">Žádný kód</string>\n    <string name=\"saving_failed\">Uložení se nezdařilo, zkuste to znovu.</string>\n    <string name=\"type_float\">Desetinné číslo</string>\n    <string name=\"uninstall_app_message\">Chcete tuto aplikaci odinstalovat\\?</string>\n    <string name=\"sort_by_blocked_components\">Blokováno jako první</string>\n    <string name=\"pref_import_blocker\">Import z Blocker</string>\n    <string name=\"disable_background_run\">Zabránit operacím na pozadí</string>\n    <string name=\"memory_virtual_memory\">Paměť: %1$s, Virtuální paměť: %2$s</string>\n    <string name=\"sort_by_dangerous_permissions\">Nejprve nebezpečné</string>\n    <string name=\"clear_app_cache_description\">Vymaže mezipaměť všech aplikací</string>\n    <string name=\"app_size\">Aplikace</string>\n    <string name=\"exodus_link\">Odkaz εxodus</string>\n    <string name=\"pref_import_watt\">Import z Watt</string>\n    <string name=\"mode\">Režim</string>\n    <string name=\"import_failed\">Import se nezdařil!</string>\n    <string name=\"operation_running\">Operace probíhá…</string>\n    <string name=\"state_foreground\">Popředí</string>\n    <string name=\"user_with_id\">Uživatel: <xliff:g id=\"user_id\" example=\"0\">%1$d</xliff:g></string>\n    <string name=\"orientation_full_sensor\">Úplný senzor</string>\n    <string name=\"menu_remove_rules\">Odstranit pravidla</string>\n    <string name=\"no_usage_in_this_time_range\">Žádná použití v tomto časovém rozmezí</string>\n    <string name=\"touchscreen_stylus\">Stylus</string>\n    <string name=\"apply_now\">Přihlásit se nyní…</string>\n    <string name=\"debuggable\">Laditelné</string>\n    <string name=\"databases\">Databáze</string>\n    <string name=\"one_click_ops\">Operace na 1 kliknutí</string>\n    <string name=\"pref_remove_all_rules_msg\">Budou udělena oprávnění, operace a součásti aplikace se vrátí na výchozí hodnoty.</string>\n    <plurals name=\"two_trackers_and_classes\">\n        <item quantity=\"one\">2 trackery s <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g> třídou</item>\n        <item quantity=\"few\">2 trackery s <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g> třídami</item>\n        <item quantity=\"other\">2 trackery s <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g> třídami</item>\n    </plurals>\n    <string name=\"pid_and_ppid\">ID procesu: %1$d, ID nadřazeného procesu: %2$d</string>\n    <plurals name=\"alert_failed_to_force_stop\">\n        <item quantity=\"one\">Nelze vynutit zastavení %1$d aplikace</item>\n        <item quantity=\"few\">Nelze vynutit zastavení %1$d aplikací</item>\n        <item quantity=\"other\">Nelze vynutit zastavení %1$d aplikací</item>\n    </plurals>\n    <string name=\"string_value\">Hodnota řetězce</string>\n    <string name=\"pref_app_theme\">Motiv aplikace</string>\n    <string name=\"type_int\">Celé číslo</string>\n    <string name=\"force_stop\">Vynuceně zastavit</string>\n    <string name=\"backup_restore\">Záloha/Obnovení</string>\n    <string name=\"import_options\">Možnosti importu</string>\n    <string name=\"keyboard_type\">Typ klávesnice</string>\n    <string name=\"version\">Verze</string>\n    <string name=\"day\">Den</string>\n    <string name=\"night\">Noc</string>\n    <string name=\"select_theme\">Motiv</string>\n    <string name=\"pref_about_msg\">Verze App Manageru, licence, autoři, atd.</string>\n    <string name=\"sort_by_component_name\">Název součásti</string>\n    <string name=\"deny_dangerous_permissions\">Odmítnout nebezpečná oprávnění</string>\n    <string name=\"failed_to_grant_permission\">Nepodařilo se udělit oprávnění</string>\n    <string name=\"update\">Aktualizovat</string>\n    <string name=\"community\">Komunita</string>\n    <string name=\"delete_backup\">Odstranit zálohu</string>\n    <plurals name=\"failed_to_import_files\">\n        <item quantity=\"one\">Nebylo možné importovat %1$d soubor.</item>\n        <item quantity=\"few\">Nebylo možné importovat %1$d soubory.</item>\n        <item quantity=\"other\">Nebylo možné importovat %1$d souborů.</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_uninstall\">\n        <item quantity=\"one\">Nebylo možné odinstalovat %1$d aplikaci</item>\n        <item quantity=\"few\">Nebylo možné odinstalovat %1$d aplikace</item>\n        <item quantity=\"other\">Nebylo možné odinstalovat %1$d aplikací</item>\n    </plurals>\n    <plurals name=\"classes\">\n        <item quantity=\"one\">%1$d třída</item>\n        <item quantity=\"few\">%1$d třídy</item>\n        <item quantity=\"other\">%1$d tříd</item>\n    </plurals>\n    <plurals name=\"app_signing_signature_schemes_pl\">\n        <item quantity=\"one\">Podpisové schéma</item>\n        <item quantity=\"few\">Podpisová schémata</item>\n        <item quantity=\"other\">Podpisová schémata</item>\n    </plurals>\n    <string name=\"pref_global_blocking_enabled_msg\">Umožňuje zablokovat jakoukoli součást libovolné aplikace, aniž by bylo výslovně zapnuto blokování aplikace.</string>\n    <string name=\"navigation_no_nav\">Bez navigace</string>\n    <string name=\"no_profiles\">Žádné profily</string>\n    <string name=\"failed_to_revoke_permission\">Nepodařilo se zamítnout oprávnění</string>\n    <string name=\"format\">Formát</string>\n    <string name=\"state_unknown\">Neznámý</string>\n    <string name=\"external_data_dir\">Adresář externích dat</string>\n    <string name=\"block_unblock_trackers_description\">Blokovat nebo odblokovat reklamy a trackery ve všech nainstalovaných aplikacích</string>\n    <string name=\"usage_access\">Přístup k použití</string>\n    <string name=\"failed_to_uninstall_app\">Odinstalace se nezdařila</string>\n    <string name=\"none\">Žádné</string>\n    <string name=\"installer_error_incompatible\">Aplikace není kompatibilní s tímto zařízením</string>\n    <string name=\"internal_data\">Interní data</string>\n    <string name=\"filter_apps_with_rules\">Aplikace s pravidly</string>\n    <string name=\"density_split_for_base_apk\"><xliff:g id=\"split_name\" example=\"xxdpi\">%1$s</xliff:g> (<xliff:g id=\"dpi_no\" example=\"480\">%2$d</xliff:g> DPI) rzdroje pro základní soubor APK</string>\n    <string name=\"only_works_in_root_or_adb_mode\">Funguje pouze v režimu root nebo ADB</string>\n    <string name=\"orientation_user\">Uživatel</string>\n    <string name=\"integer_value\">Celočíselná hodnota</string>\n    <string name=\"sort_by_denied_app_ops\">Nejprve zamítnuto</string>\n    <string name=\"required\">Vyžadováno</string>\n    <string name=\"abi_split_for_base_apk\"><xliff:g id=\"split_name\" example=\"arm64_v8a\">%1$s</xliff:g> kód pro základní soubor APK</string>\n    <string name=\"type_long\">Dlouhé celé číslo</string>\n    <string name=\"orientation_behind\">Za</string>\n    <string name=\"grant_usage_acess_message\">Slouží k zobrazení informací o používání aplikace.</string>\n    <string name=\"discard\">Vyřadit</string>\n    <string name=\"lib_details\">Podrobnosti knihovny</string>\n    <string name=\"pref_export\">Exportovat</string>\n    <string name=\"sort_by_screen_time\">Čas u obrazovky</string>\n    <string name=\"sort_by_times_opened\">Počet otevření</string>\n    <string name=\"installer_error_session_write\">Nepodařilo se psát do relace instalačního programu</string>\n    <string name=\"installer_error_session_abandon\">Nepodařilo se opustit relaci instalačního programu</string>\n    <string name=\"select_type\">Vybrat typ</string>\n    <string name=\"no_apps\">Žádné aplikace</string>\n    <string name=\"disabled_app\">Vypnuto</string>\n    <string name=\"updated_app\">Aktualizováno</string>\n    <string name=\"ok\">OK</string>\n    <string name=\"failed_to_extract_apk_file\">Soubor APK nelze extrahovat</string>\n    <string name=\"no_content\">Žádný obsah</string>\n    <string name=\"sort_by_backup\">Nejprve zálohováno</string>\n    <string name=\"apps\">Aplikace</string>\n    <string name=\"pref_import_export_blocking_rules\">Pravidla blokování importu/exportu</string>\n    <string name=\"reinstall\">Přeinstalovat</string>\n    <string name=\"state_waking\">Probuzení</string>\n    <string name=\"unblock_trackers\">Odblokovat trackery</string>\n    <string name=\"orientation_sensor\">Senzor</string>\n    <string name=\"not_yet_valid\">Zatím neplatné</string>\n    <string name=\"failed_to_reset_app_ops\">Nepodařilo se resetovat operace aplikace</string>\n    <string name=\"filter\">Filtrovat</string>\n    <string name=\"features\">Vlastnosti</string>\n    <string name=\"requested_large_heap\">Velká hromada</string>\n    <string name=\"sort_by_last_used\">Naposledy použito</string>\n    <string name=\"orientation_sensor_portrait\">Senzor na výšku</string>\n    <string name=\"sort_by_wifi_data\">Wi-Fi data</string>\n    <string name=\"failed_to_uninstall_updates\">Nepodařilo se odinstalovat aktualizace pro <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g>.</string>\n    <string name=\"app_data_will_be_lost\">Stávající data budou ztracena.</string>\n    <string name=\"shared_prefs\">Sdílené předvolby</string>\n    <string name=\"duration\">Délka trvání</string>\n    <string name=\"navigation_trackball\">Trackball</string>\n    <string name=\"select_user\">Vybrat uživatele</string>\n    <string name=\"app_ops\">Operace aplikace</string>\n    <plurals name=\"usage_hours\">\n        <item quantity=\"one\">%1$d hodina</item>\n        <item quantity=\"few\">%1$d hodiny</item>\n        <item quantity=\"other\">%1$d hodin</item>\n    </plurals>\n    <plurals name=\"usage_minutes\">\n        <item quantity=\"one\">%1$d minuta</item>\n        <item quantity=\"few\">%1$d minuty</item>\n        <item quantity=\"other\">%1$d minut</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_disable_background\">\n        <item quantity=\"one\">Nebylo možné zabránit spuštění %1$d aplikace na pozadí</item>\n        <item quantity=\"few\">Nebylo možné zabránit spuštění %1$d aplikací na pozadí</item>\n        <item quantity=\"other\">Nebylo možné zabránit spuštění %1$d aplikací na pozadí</item>\n    </plurals>\n    <plurals name=\"no_of_times_opened\">\n        <item quantity=\"one\">%1$d krát</item>\n        <item quantity=\"few\">%1$d krát</item>\n        <item quantity=\"other\">%1$d krát</item>\n    </plurals>\n    <plurals name=\"no_of_components\">\n        <item quantity=\"one\">%1$d součást</item>\n        <item quantity=\"few\">%1$d součásti</item>\n        <item quantity=\"other\">%1$d součástí</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_unblock_trackers\">\n        <item quantity=\"one\">Nepodařilo se blokovat trackery z %1$d aplikace</item>\n        <item quantity=\"few\">Nepodařilo se blokovat trackery ze %1$d aplikací</item>\n        <item quantity=\"other\">Nepodařilo se blokovat trackery ze %1$d aplikací</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_block_components\">\n        <item quantity=\"one\">Nepodařilo se blokovat součásti z %1$d aplikace</item>\n        <item quantity=\"few\">Nepodařilo se blokovat součásti ze %1$d aplikací</item>\n        <item quantity=\"other\">Nepodařilo se blokovat součásti ze %1$d aplikací</item>\n    </plurals>\n    <string name=\"block_unblock_components_dots\">Blokovat/odblokovat součásti…</string>\n    <string name=\"unblock_components_dots\">Odblokovat součásti…</string>\n    <string name=\"block_unblock_components_description\">Blokovat nebo odblokovat všechny součásti identifikované danými podpisy</string>\n    <string name=\"clear_data_from_uninstalled_apps_description\">Vymazat data z aplikací odinstalovaných pomocí příznaku <tt>DONT_DELETE_DATA2</tt></string>\n    <string name=\"clear_app_cache\">Vymazat mezipamět aplikace</string>\n    <string name=\"whats_new\">Co je nového</string>\n    <string name=\"input_signatures_description\">Vložit podpisy s mezerami, např. <tt>com.facebook org.app2 com.app32</tt> atd.</string>\n    <string name=\"apply_to_system_apps\">Použít na systémové aplikace</string>\n    <plurals name=\"alert_failed_to_unblock_components\">\n        <item quantity=\"one\">Nepodařilo se odblokovat součásti z %1$d aplikace</item>\n        <item quantity=\"few\">Nepodařilo se odblokovat součásti ze %1$d aplikací</item>\n        <item quantity=\"other\">Nepodařilo se odblokovat součásti ze %1$d aplikací</item>\n    </plurals>\n    <string name=\"apply_to_system_apps_question\">Použít i na systémové aplikace\\? Pokud si nejste jisti, vyberte možnost \\\"Ne\\\".</string>\n    <string name=\"block\">Blokovat</string>\n    <string name=\"toggle_default_app_ops\">Přepnout výchozí operace aplikace</string>\n    <string name=\"installer_error_aborted\">Instalace se nezdařila, protože byla zrušena nebo byla relace neočekávaně ukončena</string>\n    <string name=\"installer_error_conflict\">Nepodařilo se nainstalovat aplikaci, protože se tento název balíčku se již používá</string>\n    <string name=\"failed_to_extract_obb_files\">Soubory OBB nelze extrahovat</string>\n    <string name=\"obb_files_extracted_successfully\">Soubory OBB byly extrahovány</string>\n    <string name=\"unknown_split_for_base_apk\"><xliff:g id=\"split_name\" example=\"some_split\">%1$s</xliff:g> pro základní soubor APK</string>\n    <string name=\"density_split_for_feature\"><xliff:g id=\"split_name\" example=\"xxdpi\">%1$s</xliff:g> (<xliff:g id=\"dpi_no\" example=\"480\">%2$d</xliff:g> DPI) zdroje pro funkci <xliff:g id=\"feature_name\" example=\"Visualizer\">%3$s</xliff:g></string>\n    <string name=\"abi_split_for_feature\"><xliff:g id=\"split_name\" example=\"arm64_v8a\">%1$s</xliff:g> kód pro <xliff:g id=\"feature_name\" example=\"Visualizer\">%2$s</xliff:g></string>\n    <string name=\"orientation_locked\">Zamknuto</string>\n    <string name=\"orientation_no_sensor\">Bez senzoru</string>\n    <string name=\"orientation_portrait\">Na výšku</string>\n    <string name=\"orientation_reverse_portrait\">Na výšku, obráceně</string>\n    <string name=\"orientation_sensor_landscape\">Senzor na šířku</string>\n    <string name=\"keyboard_12_keys\">klíč 12</string>\n    <string name=\"state_sleeping\">Spící</string>\n    <string name=\"state_device_io\">Vstup/výstup zařízení</string>\n    <string name=\"state_trace_stop\">Zastavit trasování</string>\n    <string name=\"state_dead\">Mrtvý</string>\n    <string name=\"state_idle\">Nečinný</string>\n    <string name=\"state_low_priority\">S nízkou prioritou</string>\n    <string name=\"state_locked_memory\">Paměť uzamčena</string>\n    <string name=\"state_session_leader\">Vedoucí relace</string>\n    <string name=\"input_backup_name\">Název zálohy</string>\n    <string name=\"routine_ops\">Rutinní operace</string>\n    <string name=\"sort_by_process_id\">ID procesu</string>\n    <string name=\"sort_by_process_name\">Název procesu</string>\n    <string name=\"changes_not_saved\">Změny nebyly uloženy</string>\n    <string name=\"rules\">Pravidla</string>\n    <string name=\"confirm_installation\">Potvrdit instalaci</string>\n    <string name=\"allow_open_pgp_operation\">Klepnutím povolíte App Manageru používat OpenPGP</string>\n    <string name=\"uninstall_updates\">Odinstalovat aktualizace</string>\n    <string name=\"app_signing_signature\">Podpis</string>\n    <string name=\"public_key\">Veřejný klíč</string>\n    <string name=\"critical_exts\">Kritická rozšíření</string>\n    <string name=\"non_critical_exts\">Nekritická rozšíření</string>\n    <string name=\"app_signing_signature_mismatch_for_system_apps\">Aplikaci se nepodařilo nainstalovat, protože tento název balíčku má již systémová aplikace s jiným podpisem.</string>\n    <string name=\"sys_config\">Konfigurace systému</string>\n    <string name=\"tap_to_see_details\">Klepnutím zobrazíte podrobnosti</string>\n    <string name=\"am_crashed\">App Manager právě spadl</string>\n    <string name=\"send_crash_report\">Poslat zprávu o selhání</string>\n    <string name=\"in_progress\">Probíhá</string>\n    <string name=\"pref_encryption_msg\">Šifrování záloh.</string>\n    <string name=\"send_selected\">Poslat vybrané</string>\n    <plurals name=\"alert_failed_to_disable_trackers\">\n        <item quantity=\"one\">Nepodařilo se zakázat trackery z %1$d aplikace</item>\n        <item quantity=\"few\">Nepodařilo se zakázat trackery z %1$d aplikací</item>\n        <item quantity=\"other\">Nepodařilo se zakázat trackery z %1$d aplikací</item>\n    </plurals>\n    <plurals name=\"backup_exists_are_you_sure\">\n        <item quantity=\"one\">Záloha již existuje. Jste si jisti\\?</item>\n        <item quantity=\"few\">Existuje záloha pro více než jednu aplikaci. Jste si jisti\\?</item>\n        <item quantity=\"other\">Existuje záloha pro více než jednu aplikaci. Jste si jisti\\?</item>\n    </plurals>\n    <string name=\"auto\">Automaticky</string>\n    <string name=\"state_multithreaded\">Vícevláknový</string>\n    <string name=\"downgrade\">Vrátit na starší verzi</string>\n    <string name=\"do_you_want_to_uninstall_and_install\">Chcete aplikaci odinstalovat a znovu nainstalovat\\?</string>\n    <string name=\"pref_import_msg\">Import dříve exportovaných pravidel blokování z App Manageru.</string>\n    <string name=\"pref_export_msg\">Export pravidel blokování nakonfigurovaných v App Manageru do externího úložiště.</string>\n    <string name=\"launch_app\">Spustit</string>\n    <string name=\"never_ask\">Nikdy se neptat</string>\n    <string name=\"install\">Instalovat</string>\n    <string name=\"block_components_dots\">Blokovat součásti…</string>\n    <string name=\"are_you_sure\">Jste si jistí\\?</string>\n    <string name=\"installer_error_generic\">Instalace se nezdařila</string>\n    <string name=\"full_stop_tap_to_see_details\">. Klepnutím zobrazíte podrobnosti.</string>\n    <string name=\"install_app_message\">Chcete nainstalovat tuto aplikaci\\?</string>\n    <string name=\"launch_mode_multiple\">Mnoho</string>\n    <string name=\"launch_mode_single_task\">Jednotlivý úkol</string>\n    <string name=\"duplicate\">Duplikovat</string>\n    <string name=\"done\">Hotovo</string>\n    <string name=\"filter_apps_with_activities\">S aktivitami</string>\n    <string name=\"dev_protected_data_dir\">Datový adresář chráněný zařízením</string>\n    <string name=\"delete\">Odstranit</string>\n    <string name=\"view_in_settings\">Zobrazit v nastavení</string>\n    <string name=\"total_size\">Celkem</string>\n    <string name=\"select_all\">Vybrat vše</string>\n    <string name=\"state_zombie\">Zombie</string>\n    <string name=\"changelog\">Seznam změn</string>\n    <string name=\"the_export_was_successful\">Exportováno</string>\n    <string name=\"state_parked\">Zaparkovaný</string>\n    <string name=\"orientation_landscape\">Na šířku</string>\n    <string name=\"only_install\">Pouze instalovat</string>\n    <string name=\"saved_successfully\">Uloženo</string>\n    <string name=\"no_libs\">Žádné knihovny</string>\n    <string name=\"failed_to_enable_op\">Nepodařilo se povolit požadovanou operaci aplikace</string>\n    <string name=\"orientation_user_portrait\">Orientace uživatele na výšku</string>\n    <string name=\"backup\">Zálohovat</string>\n    <string name=\"export_options\">Možnosti exportu</string>\n    <string name=\"sort_by_tracker_components\">Nejprve trackery</string>\n    <string name=\"restore\">Obnovit</string>\n    <string name=\"process_state\">Stát: <xliff:g id=\"process_state\" example=\"Sleeping\">%1$s</xliff:g></string>\n    <string name=\"permission_name\">Název oprávnění</string>\n    <string name=\"systemless_app\">Bezsystémová aplikace</string>\n    <string name=\"base_apk\">Základní soubor APK</string>\n    <string name=\"failed_to_deny_dangerous_app_ops\">Nepodařilo se zrušit všechny nebezpečné operace aplikace</string>\n    <string name=\"sort_by_permission_names\">Název oprávnění</string>\n    <string name=\"sort_by_apps_first\">Nejprve aplikace</string>\n    <string name=\"pref_global_blocking_enabled\">Okamžité blokování součásti</string>\n    <string name=\"type_boolean\">Pravda/nepravda</string>\n    <string name=\"long_integer_value\">Dlouhá celočíselná hodnota</string>\n    <string name=\"clear_cache\">Vymazat mezipaměť</string>\n    <string name=\"stopped\">Zastaveno</string>\n    <string name=\"blocking_rules\">Pravidla blokování</string>\n    <string name=\"select_apk\">Vybrat APK</string>\n    <string name=\"save\">Uložit</string>\n    <string name=\"clear\">Vymazat</string>\n    <string name=\"expiry_date\">Platný do</string>\n    <plurals name=\"usage_days\">\n        <item quantity=\"one\">%1$d den</item>\n        <item quantity=\"few\">%1$d dny</item>\n        <item quantity=\"other\">%1$d dní</item>\n    </plurals>\n    <plurals name=\"no_of_trackers\">\n        <item quantity=\"one\">%1$d tracker</item>\n        <item quantity=\"few\">%1$d trackery</item>\n        <item quantity=\"other\">%1$d trackerů</item>\n    </plurals>\n    <string name=\"termux\">Termux</string>\n    <plurals name=\"alert_failed_to_backup\">\n        <item quantity=\"one\">Nepodařilo se zálohovat %1$d aplikaci</item>\n        <item quantity=\"few\">Nepodařilo se zálohovat %1$d aplikace</item>\n        <item quantity=\"other\">Nepodařilo se zálohovat %1$d aplikací</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_set_app_ops\">\n        <item quantity=\"one\">Nepodařilo se nastavit operace z %1$d aplikace</item>\n        <item quantity=\"few\">Nepodařilo se nastavit operace ze %1$d aplikací</item>\n        <item quantity=\"other\">Nepodařilo se nastavit operace ze %1$d aplikací</item>\n    </plurals>\n    <plurals name=\"libraries\">\n        <item quantity=\"one\">%1$d knihovna</item>\n        <item quantity=\"few\">%1$d knihovny</item>\n        <item quantity=\"other\">%1$d knihoven</item>\n    </plurals>\n    <plurals name=\"usage_seconds\">\n        <item quantity=\"one\">%1$d sekunda</item>\n        <item quantity=\"few\">%1$d sekundy</item>\n        <item quantity=\"other\">%1$d sekund</item>\n    </plurals>\n    <plurals name=\"no_of_splits\">\n        <item quantity=\"one\">%1$d rozdělení</item>\n        <item quantity=\"few\">%1$d rozdělení</item>\n        <item quantity=\"other\">%1$d rozdělení</item>\n    </plurals>\n    <plurals name=\"failed_to_backup_some_apk_files\">\n        <item quantity=\"one\">Nepodařilo se zálohovat %1$d aplikaci</item>\n        <item quantity=\"few\">Nepodařilo se zálohovat %1$d aplikace</item>\n        <item quantity=\"other\">Nepodařilo se zálohovat %1$d aplikací</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_delete_backup\">\n        <item quantity=\"one\">Nepodařilo se smazat %1$d aplikaci</item>\n        <item quantity=\"few\">Nepodařilo se smazat %1$d aplikace</item>\n        <item quantity=\"other\">Nepodařilo se smazat %1$d aplikací</item>\n    </plurals>\n    <string name=\"go\">Pokračovat</string>\n    <string name=\"deleted_successfully\">Odstraněno</string>\n    <string name=\"deletion_failed\">Odstranění se nezdařilo</string>\n    <string name=\"the_operation_was_successful\">Hotovo</string>\n    <string name=\"unknown_split_for_feature\"><xliff:g id=\"split_name\" example=\"some_split\">%1$s</xliff:g> pro funkci <xliff:g id=\"feature_name\" example=\"Visualizer\">%2$s</xliff:g></string>\n    <plurals name=\"usage_months\">\n        <item quantity=\"one\">%1$d měsíc</item>\n        <item quantity=\"few\">%1$d měsíce</item>\n        <item quantity=\"other\">%1$d měsíců</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_restore\">\n        <item quantity=\"one\">Nepodařilo se obnovit %1$d aplikaci</item>\n        <item quantity=\"few\">Nepodařilo se obnovit %1$d aplikace</item>\n        <item quantity=\"other\">Nepodařilo se obnovit %1$d aplikací</item>\n    </plurals>\n    <plurals name=\"missing_signatures\">\n        <item quantity=\"one\">%1$d chybějící podpis</item>\n        <item quantity=\"few\">%1$d chybějící podpisy</item>\n        <item quantity=\"other\">%1$d chybějících podpisů</item>\n    </plurals>\n    <string name=\"install_in_progress\">Instaluje se…</string>\n    <string name=\"installer_error_security\">Nepodařilo se získat přístup k souborům APK</string>\n    <plurals name=\"main_list_date_days\">\n        <item quantity=\"one\"><xliff:g id=\"last_update_date\" example=\"20/10/2020\">%1$s</xliff:g> <xliff:g id=\"day_no\" example=\"5\">%2$d</xliff:g> den</item>\n        <item quantity=\"few\"><xliff:g id=\"last_update_date\" example=\"20/10/2020\">%1$s</xliff:g> <xliff:g id=\"day_no\" example=\"5\">%2$d</xliff:g> dny</item>\n        <item quantity=\"other\"><xliff:g id=\"last_update_date\" example=\"20/10/2020\">%1$s</xliff:g> <xliff:g id=\"day_no\" example=\"5\">%2$d</xliff:g> dní</item>\n    </plurals>\n    <plurals name=\"other_trackers_and_classes\">\n        <item quantity=\"one\"><xliff:g id=\"tracker_no\" example=\"8\">%1$d</xliff:g> tracker s <xliff:g id=\"class_no\" example=\"50\">%2$d</xliff:g> třída</item>\n        <item quantity=\"few\"><xliff:g id=\"tracker_no\" example=\"8\">%1$d</xliff:g> trackery s <xliff:g id=\"class_no\" example=\"50\">%2$d</xliff:g> třídy</item>\n        <item quantity=\"other\"><xliff:g id=\"tracker_no\" example=\"8\">%1$d</xliff:g> trackerů s <xliff:g id=\"class_no\" example=\"50\">%2$d</xliff:g> tříd</item>\n    </plurals>\n    <string name=\"pref_import_export_blocking_rules_msg\">Pravidla importu/exportu, import externích pravidel z Watt nebo Blocker.</string>\n    <plurals name=\"verified_with_warning\">\n        <item quantity=\"one\">Ověřeno s %d varováním</item>\n        <item quantity=\"few\">Ověřeno se %d varováními</item>\n        <item quantity=\"other\">Ověřeno se %d varováními</item>\n    </plurals>\n    <string name=\"profile_state\">Stav profilu</string>\n    <string name=\"enabled\">Zapnuto</string>\n    <string name=\"pref_sign_apk\">Podepsat APK</string>\n    <string name=\"input_permissions_description\">Zadejte oprávnění s mezerami, např. <tt>com.permission.GET_ACCOUNTS android.permission.ACCESS_MEDIA_LOCATION2</tt> etc. Použijte <tt>*</tt> abyste požádali o všechna oprávnění.</string>\n    <string name=\"allow_routine_ops\">Povolit rutinní operace</string>\n    <string name=\"options\">Možnosti</string>\n    <string name=\"profile_clear_data_msg\">Vymaže data aplikací</string>\n    <string name=\"install_location_prefer_external\">Preferovat externí</string>\n    <string name=\"profile_clear_cache_msg\">Vymaže mezipaměť aplikací</string>\n    <string name=\"allow_routine_ops_msg\">Povolit použití profilu v rutinních operacích</string>\n    <string name=\"profile_block_trackers_msg\">Zablokuje trackery v aplikacích</string>\n    <string name=\"installer\">Instalátor</string>\n    <string name=\"pref_mode_of_operations\">Režim provozu</string>\n    <string name=\"simple\">Jednoduchý</string>\n    <string name=\"input_permissions\">Zadejte oprávnění</string>\n    <string name=\"advanced\">Pokročilý</string>\n    <string name=\"user_profile_with_id\">Profil: %1$s (%2$d)</string>\n    <string name=\"close\">Zavřít</string>\n    <string name=\"install_location_internal_only\">Pouze interní</string>\n    <string name=\"on\">Na</string>\n    <string name=\"off\">Vypnuto</string>\n    <string name=\"choose\">Vybrat</string>\n    <string name=\"comment\">Komentář</string>\n    <string name=\"profile_state_msg\">Vlastní stav zapnutí/vypnutí tohoto profilu</string>\n    <string name=\"install_location\">Umístění instalace</string>\n    <string name=\"pref_sign_apk_msg\">Podepište soubory APK před jejich instalací.</string>\n</resources>"
  },
  {
    "path": "app/src/main/res/values-da/disclaimer.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"disclaimer_footer\">© 2020–2024 Muntashir Al-Islam</string>\n</resources>"
  },
  {
    "path": "app/src/main/res/values-da/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\">\n    <string name=\"refresh\">Opdater</string>\n    <string name=\"activities\">Aktiviteter</string>\n    <string name=\"no_receivers\">Ingen modtagere</string>\n    <string name=\"providers\">Udbydere</string>\n    <string name=\"uninstall\">Afinstaller</string>\n    <string name=\"no_activities\">Ingen aktiviteter</string>\n    <string name=\"require_no_permission\">Ingen tilladelse påkrævet</string>\n    <string name=\"permissions\">Bruger tilladelser</string>\n    <string name=\"launch\">Start</string>\n    <string name=\"receivers\">Modtagere</string>\n    <string name=\"create_shortcut\">Opret Genvej</string>\n    <string name=\"debuggable\">Kan fejlfindes</string>\n    <string name=\"sort_by_last_used\">Sidst brugt</string>\n    <string name=\"failed_to_reset_app_ops\">Kunne ikke nulstille app-operationer</string>\n    <string name=\"app_signing_no_signatures\">Ingen gyldige signeringer</string>\n    <string name=\"never_ask\">Spørg aldrig</string>\n    <string name=\"shared_user_id\">Delt Bruger-ID</string>\n    <string name=\"read\">Læs</string>\n    <string name=\"shortcut_name\">Genvejsnavn</string>\n    <string name=\"class_name\">Klassenavn</string>\n    <string name=\"disabled_app\">Deaktiveret</string>\n    <string name=\"configurations\">Konfigurationer</string>\n    <string name=\"error_verbose_pin_shortcut\">Nuværende launcher understøtter ikke PinShortcut. Kan ikke oprette genvej.</string>\n    <string name=\"touchscreen\">Touchskærm</string>\n    <string name=\"battery_mode\">Batteritilstand</string>\n    <string name=\"error_evaluating_input\">Kunne ikke evaluere input</string>\n    <string name=\"sdk_min\">Min.</string>\n    <string name=\"uses_feature\">Bruger funktioner</string>\n    <string name=\"version\">Version</string>\n    <string name=\"mode\">Tilstand</string>\n    <string name=\"disable\">Deaktiver</string>\n    <string name=\"paths_and_directories\">Stier &amp; Mapper</string>\n    <string name=\"save\">Gem</string>\n    <string name=\"kill_process\">Dræb</string>\n    <string name=\"data_dir\">Datamappe</string>\n    <string name=\"delete\">Slet</string>\n    <string name=\"failed_to_revoke_permission\">Kunne ikke tilbagekalde tilladelse</string>\n    <string name=\"app_signing_signatures\">Signeringer</string>\n    <string name=\"data_transmitted\">Data sendt</string>\n    <string name=\"usage_yesterday\">I går</string>\n    <string name=\"no_feature\">Ingen funktioner</string>\n    <string name=\"data_size\">Data</string>\n    <string name=\"sdk_flags\">Flag</string>\n    <string name=\"class_viewer\">Klassevisning</string>\n    <string name=\"sort_by_domain\">Brugerapps først</string>\n    <string name=\"grant_uri_permission\">Giv URI-tilladelser</string>\n    <string name=\"error\">Fejl</string>\n    <string name=\"sort_by_package_name\">Pakkenavn</string>\n    <string name=\"data_usage_msg\">Dataforbrug</string>\n    <string name=\"cache_size\">Cache</string>\n    <string name=\"user\">Bruger</string>\n    <string name=\"system_app\">Systemapp</string>\n    <string name=\"user_app\">Brugerapp</string>\n    <string name=\"more_info\">Mere Info</string>\n    <string name=\"date_installed\">Installationsdato</string>\n    <string name=\"date_updated\">Opdateringsdato</string>\n    <string name=\"main_activity\">Hovedaktivitet</string>\n    <string name=\"empty_package_name\">Tomt pakkenavn</string>\n    <string name=\"user_id\">Bruger-ID</string>\n    <string name=\"changelog\">Ændringslog</string>\n    <string name=\"apply\">Anvend</string>\n    <string name=\"app_info\">App-info</string>\n    <string name=\"sort_by_sha\">Signering</string>\n    <string name=\"day\">Dag</string>\n    <string name=\"launch_app\">Start</string>\n    <string name=\"service\">Tjenester</string>\n    <string name=\"done\">Færdig</string>\n    <string name=\"import_failed\">Import mislykkedes!</string>\n    <string name=\"sort_by_shared_user_id\">Delt Bruger-ID</string>\n    <string name=\"found_trackers\">Fandt Trackere:</string>\n    <string name=\"usage_today\">I dag</string>\n    <string name=\"duration\">Varighed</string>\n    <string name=\"system\">System</string>\n    <string name=\"source_dir\">Kildemappe</string>\n    <string name=\"sort_by_mobile_data\">Mobildata</string>\n    <string name=\"no_providers\">Ingen udbydere</string>\n    <string name=\"export_options\">Indstillinger for Eksport</string>\n    <string name=\"pref_export\">Eksport</string>\n    <string name=\"declared_permission\">Tilladelser</string>\n    <string name=\"signatures\">Signeringer</string>\n    <string name=\"loading\">Indlæser…</string>\n    <string name=\"ago\">siden</string>\n    <string name=\"data_received\">Data modtaget</string>\n    <plurals name=\"tracker_and_classes\">\n        <item quantity=\"one\">1 tracker med <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g> klasse</item>\n        <item quantity=\"other\">1 tracker med <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g> klasser</item>\n    </plurals>\n    <plurals name=\"usage_minutes\">\n        <item quantity=\"one\">%1$d min.</item>\n        <item quantity=\"other\">%1$d min.</item>\n    </plurals>\n    <string name=\"patterns_allowed\">Mønstre tilladt</string>\n    <plurals name=\"alert_failed_to_force_stop\">\n        <item quantity=\"one\">Kunne ikke gennemtvinge stop af %1$d app</item>\n        <item quantity=\"other\">Kunne ikke gennemtvinge stop af %1$d apps</item>\n    </plurals>\n    <string name=\"package_name\">Pakkenavn</string>\n    <string name=\"icon_picker\">Ikonvælger</string>\n    <string name=\"third_party\">Tredjepartsbiblioteker og -ikoner</string>\n    <string name=\"credits\">Tak til</string>\n    <string name=\"word_wrap\">Slå ordombrydning til/fra</string>\n    <string name=\"tracker_details\">Trackerdetaljer</string>\n    <string name=\"all_classes\">Alle klasser</string>\n    <string name=\"no_shared_libs\">Ingen delte biblioteker</string>\n    <string name=\"no_tracker_class\">Ingen trackerklasser</string>\n    <string name=\"usage_weekly\">Ugentlig</string>\n    <string name=\"usage_7_days\">Sidste 7 dage</string>\n    <string name=\"usage_less_than_a_minute\">Mindre end et minut</string>\n    <string name=\"go_back\">Gå tilbage</string>\n    <string name=\"share_apk\">Del APK</string>\n    <string name=\"failed_to_extract_apk_file\">Kunne ikke udpakke APK-fil</string>\n    <string name=\"menu_remove_rules\">Fjern regler</string>\n    <string name=\"menu_apply_rules\">Anvend regler</string>\n    <string name=\"search\">Søg</string>\n    <string name=\"process_name\">Procesnavn</string>\n    <string name=\"no_code\">Ingen kode</string>\n    <string name=\"updated_app\">Opdateret</string>\n    <string name=\"discard\">Kassér</string>\n    <string name=\"deleted_successfully\">Slettet</string>\n    <string name=\"deletion_failed\">Sletning mislykkedes</string>\n    <string name=\"saved_successfully\">Gemt</string>\n    <string name=\"select_type\">Vælg en type</string>\n    <string name=\"type_float\">Decimaltal</string>\n    <string name=\"type_long\">Langt heltal</string>\n    <string name=\"no_content\">Intet indhold</string>\n    <string name=\"view_in_settings\">Se i Indstillinger</string>\n    <string name=\"uninstall_system_app_message\">Dette er en systemapp. Er du sikker på, at du vil afinstallere denne app?</string>\n    <string name=\"failed_to_uninstall\">Kunne ikke afinstallere <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g>.</string>\n    <string name=\"uninstalled_successfully\"><xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g> er blevet afinstalleret.</string>\n    <string name=\"stopped\">Stoppet</string>\n    <string name=\"enable\">Aktiver</string>\n    <string name=\"force_stop\">Gennemtving stop</string>\n    <string name=\"failed_to_stop\">Kunne ikke stoppe <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g>.</string>\n    <string name=\"storage_and_cache\">Lager og Cache</string>\n    <string name=\"no_app_ops\">Ingen app-operationer</string>\n    <string name=\"rules_not_applied\">Regler anvendes ikke</string>\n    <string name=\"str_logo\">Logo</string>\n    <string name=\"app_settings\">Indstillinger</string>\n    <string name=\"exodus_link\">εxodus-link</string>\n    <string name=\"external_data_dir\">Ekstern Datamappe</string>\n    <string name=\"external_multiple_data_dir\">Ekstern Datamappe <xliff:g id=\"dir_no\" example=\"1\">%1$d</xliff:g></string>\n    <string name=\"sort_by_screen_time\">Skærmtid</string>\n    <string name=\"pref_import_export_blocking_rules\">Importér/eksportér blokeringsregler</string>\n    <string name=\"pref_import_export_blocking_rules_msg\">Importér/eksportér regler. Importér eksterne regler fra Watt eller Blocker.</string>\n    <string name=\"pref_import_watt\">Importér fra Watt</string>\n    <string name=\"the_import_was_successful\">Importeret</string>\n    <string name=\"the_export_was_successful\">Eksporteret</string>\n    <string name=\"apk_updater\">APK Updater</string>\n    <string name=\"running_apps\">Kørende Apps</string>\n    <string name=\"user_with_id\">Bruger: <xliff:g id=\"user_id\" example=\"0\">%1$d</xliff:g></string>\n    <string name=\"backup_restore\">Backup/Gendan</string>\n    <string name=\"export_blocking_rules\">Eksportér Blokeringsregler</string>\n    <string name=\"running\">Kører</string>\n    <string name=\"pref_import\">Import</string>\n    <string name=\"keyboard_type\">Tastaturtype</string>\n    <string name=\"navigation\">Navigation</string>\n    <string name=\"pref_export_msg\">Eksportér blokeringsregler konfigurerede i App Manager til eksternt lager.</string>\n    <string name=\"pref_import_msg\">Importér tidligere eksporterede blokeringsregler fra App Manager.</string>\n    <string name=\"pref_app_theme\">App-tema</string>\n    <string name=\"night\">Nat</string>\n    <string name=\"select_theme\">Tema</string>\n    <string name=\"pref_about_msg\">App Manager-version, -licens, -kredit osv.</string>\n    <string name=\"block_trackers\">Bloker trackere</string>\n    <string name=\"sort_by_component_name\">Komponentnavn</string>\n    <string name=\"reset_to_default\">Nulstil til standard</string>\n    <string name=\"deny_dangerous_app_ops\">Afvis farlige app-operationer</string>\n    <string name=\"sort_by_denied_app_ops\">Afvist først</string>\n    <string name=\"sort_by_dangerous_permissions\">Farlige først</string>\n    <string name=\"sort_by_denied_permissions\">Afvist først</string>\n    <string name=\"sort_by_tracker_components\">Trackere først</string>\n    <string name=\"unknown_op\">Ukendt Operation</string>\n    <string name=\"failed_to_grant_permission\">Kunne ikke give tilladelse</string>\n    <string name=\"failed_to_deny_dangerous_perms\">Kunne ikke tilbagekalde alle farlige tilladelser</string>\n    <string name=\"failed_to_deny_dangerous_app_ops\">Kunne ikke tilbagekalde alle farlige app-operationer</string>\n    <string name=\"external_apk_no_app_op\">Ekstern APK har ingen app-operationer</string>\n    <string name=\"install\">Installer</string>\n    <string name=\"update\">Opdater</string>\n    <string name=\"source_code\">Kildekode</string>\n    <string name=\"community\">Fællesskab</string>\n    <string name=\"community_links\"><a href=\"https://matrix.to/#/#appmanager:matrix.org\">Matrix</a> • <a href=\"https://t.me/AppManagerChannel\">Telegram</a> • <a href=\"https://twitter.com/AppManagerNews\">X (Twitter)</a></string>\n    <string name=\"pref_import_existing\">Importér eksisterende regler</string>\n    <string name=\"clear_cache\">Ryd Cache</string>\n    <plurals name=\"other_trackers_and_classes\">\n        <item quantity=\"one\"><xliff:g id=\"tracker_no\" example=\"8\">%1$d</xliff:g> trackere med <xliff:g id=\"class_no\" example=\"50\">%2$d</xliff:g> klasser</item>\n        <item quantity=\"other\"><xliff:g id=\"tracker_no\" example=\"8\">%1$d</xliff:g> trackere med <xliff:g id=\"class_no\" example=\"50\">%2$d</xliff:g> klasser</item>\n    </plurals>\n    <plurals name=\"main_list_date_days\">\n        <item quantity=\"one\"><xliff:g id=\"last_update_date\" example=\"20/10/2020\">%1$s</xliff:g> <xliff:g id=\"day_no\" example=\"5\">%2$d</xliff:g> dag</item>\n        <item quantity=\"other\"><xliff:g id=\"last_update_date\" example=\"20/10/2020\">%1$s</xliff:g> <xliff:g id=\"day_no\" example=\"5\">%2$d</xliff:g> dage</item>\n    </plurals>\n    <plurals name=\"usage_seconds\">\n        <item quantity=\"one\">%1$d sek.</item>\n        <item quantity=\"other\">%1$d sek.</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_uninstall\">\n        <item quantity=\"one\">Kunne ikke afinstallere %1$d app</item>\n        <item quantity=\"other\">Kunne ikke afinstallere %1$d apps</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_disable_background\">\n        <item quantity=\"one\">Kunne ikke forhindre %1$d app i at køre i baggrunden</item>\n        <item quantity=\"other\">Kunne ikke forhindre %1$d apps i at køre i baggrunden</item>\n    </plurals>\n    <plurals name=\"no_of_trackers\">\n        <item quantity=\"one\">%1$d tracker</item>\n        <item quantity=\"other\">%1$d trackere</item>\n    </plurals>\n    <plurals name=\"no_of_components\">\n        <item quantity=\"one\">%1$d komponent</item>\n        <item quantity=\"other\">%1$d komponenter</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_clear_data\">\n        <item quantity=\"one\">Kunne ikke rydde data fra %1$d app</item>\n        <item quantity=\"other\">Kunne ikke rydde data fra %1$d apps</item>\n    </plurals>\n    <string name=\"saving_failed\">Lagring mislykkedes. Prøv igen.</string>\n    <string name=\"key_name\">Nøglenavn</string>\n    <string name=\"uninstall_app_message\">Vil du afinstallere denne app?</string>\n    <string name=\"flags\">Flag</string>\n    <string name=\"import_options\">Indstillinger for Import</string>\n    <string name=\"databases\">Databaser</string>\n    <string name=\"no_service\">Ingen tjenester</string>\n    <string name=\"about\">Om</string>\n    <string name=\"sort_by_blocked_components\">Blokeret først</string>\n    <string name=\"tracker_classes\">Trackerklasser</string>\n    <string name=\"type_boolean\">Sandt/falsk</string>\n    <string name=\"export_failed\">Eksport mislykkedes!</string>\n    <string name=\"second_degree_tracker_note\">²-præfikset angiver, at trackerne er på <a href=\"https://etip.exodus-privacy.eu.org/\">ETIP\\'s standby-liste</a>, dvs. at det stadig undersøges, om de er faktiske trackere.</string>\n    <string name=\"app_size\">App</string>\n    <string name=\"no_configurations\">Ingen konfigurationer</string>\n    <string name=\"error_creating_shortcut\">Fejl ved oprettelse af genvej</string>\n    <string name=\"pref_import_blocker\">Importér fra Blocker</string>\n    <string name=\"pref_global_blocking_enabled_msg\">Lader dig blokere enhver komponent i enhver app uden eksplicit at slå blokering til for appen.</string>\n    <string name=\"dev_protected_data_dir\">Enhedsbeskyttet Datamappe</string>\n    <string name=\"failed_to_uninstall_app\">Afinstallation mislykkedes</string>\n    <string name=\"deny_dangerous_permissions\">Afvis farlige tilladelser</string>\n    <string name=\"type_int\">Heltal</string>\n    <string name=\"type_string\">Tegn</string>\n    <string name=\"follow_system\">Følg system</string>\n    <string name=\"key_name_cannot_be_null\">Nøglenavn må ikke være tomt</string>\n    <string name=\"total_size\">I alt</string>\n    <string name=\"clear_data\">Ryd Data</string>\n    <string name=\"one_click_ops\">1-klik-operationer</string>\n    <string name=\"memory_virtual_memory\">Hukommelse: %1$s; Virtuel Hukommelse: %2$s</string>\n    <string name=\"sort_by_wifi_data\">Wi-Fi-data</string>\n    <string name=\"write\">Skriv</string>\n    <plurals name=\"usage_hours\">\n        <item quantity=\"one\">%1$d t.</item>\n        <item quantity=\"other\">%1$d t.</item>\n    </plurals>\n    <string name=\"the_operation_was_successful\">Færdig</string>\n    <string name=\"pref_import_existing_msg\">Føj komponenter, der er deaktiveret af andre apps, til App Manager. Vær forsigtig, når du bruger dette værktøj, da der kan være mange falske positiver. Vælg kun de apps, du er sikker på.</string>\n    <string name=\"sort\">Sortér</string>\n    <plurals name=\"usage_months\">\n        <item quantity=\"one\">%1$d md.</item>\n        <item quantity=\"other\">%1$d mdr.</item>\n    </plurals>\n    <plurals name=\"no_of_times_opened\">\n        <item quantity=\"one\">%1$d gang</item>\n        <item quantity=\"other\">%1$d gange</item>\n    </plurals>\n    <plurals name=\"two_trackers_and_classes\">\n        <item quantity=\"one\">2 trackere med <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g> klasser</item>\n        <item quantity=\"other\">2 trackere med <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g> klasser</item>\n    </plurals>\n    <plurals name=\"failed_to_import_files\">\n        <item quantity=\"one\">Kunne ikke importere %1$d fil.</item>\n        <item quantity=\"other\">Kunne ikke importere %1$d filer.</item>\n    </plurals>\n    <string name=\"credits_message\">Til skaberne af\n        \\n- Android Open Source-projektet\n        \\n- <a href=\"https://github.com/zhaobozhen/libraries\">Absinthe\\'s libraries</a>\n        \\n- <a href=\"https://github.com/butzist/ActivityLauncher\">Activity Launcher</a>\n        \\n- <a href=\"https://bitbucket.org/oF2pks/fdroid-applications-info\">Apps_packages Info</a>\n        \\n- <a href=\"https://github.com/zhaobao/AppsMonitor\">AppsMonitor</a>\n        \\n- <a href=\"https://github.com/8enet/AppOpsX\">AppOpsX</a>\n        \\n- <a href=\"https://github.com/gabrielemariotti/changeloglib\">ChangeLog Library</a>\n        \\n- <a href=\"https://bitbucket.org/oF2pks/fdroid-classyshark3xodus\">ClassySharkAndroid</a>\n        \\n- <a href=\"https://github.com/billthefarmer/editor\">Editor</a>\n        \\n- <a href=\"https://github.com/Raival-e/File-Explorer\">File Explorer</a>\n        \\n- <a href=\"https://github.com/nex3z/FlowLayout\">FlowLayout</a>\n        \\n- <a href=\"https://github.com/k3b/intent-intercept\">Intent Intercept</a>\n        \\n- <a href=\"https://github.com/YarikSOffice/lingver\">Lingver</a>\n        \\n- <a href=\"https://github.com/topjohnwu/Magisk\">Magisk</a>\n        \\n- <a href=\"https://github.com/zhanghai/MaterialFiles\">Material Files</a>\n        \\n- <a href=\"https://github.com/pluscubed/matlog\">MatLog</a>\n        \\n- <a href=\"https://github.com/matrix-org/matrix-android-sdk\">Matrix Android SDK</a>\n        \\n- <a href=\"https://github.com/jensstein/oandbackup\">OAndBackup</a>\n        \\n- <a href=\"https://github.com/open-keychain/open-keychain\">Open Keychain</a>\n        \\n- <a href=\"https://github.com/Aefyr/SAI\">SAI</a>\n        \\n- <a href=\"https://github.com/RikkaApps/Shizuku\">Shizuku</a>\n        \\n- <a href=\"https://github.com/eclipse/tm4e\">tm4e</a>\n        \\n- <a href=\"https://github.com/tuyafeng/Watt\">Watt</a></string>\n    <string name=\"toggle_class_listing\">Slå klassevisning til/fra</string>\n    <plurals name=\"usage_days\">\n        <item quantity=\"one\">%1$d dag</item>\n        <item quantity=\"other\">%1$d dage</item>\n    </plurals>\n    <string name=\"license\">Licens</string>\n    <string name=\"app_not_installed\">App ikke installeret</string>\n    <string name=\"version_name_with_code\">Version <xliff:g id=\"version_name\" example=\"2.5.17\">%1$s</xliff:g> (<xliff:g id=\"version_code\" example=\"365\">%2$d</xliff:g>)</string>\n    <string name=\"user_and_uid\">Bruger: <xliff:g id=\"user_name\" example=\"root\">%1$s</xliff:g> (<xliff:g id=\"user_id\" example=\"0\">%2$d</xliff:g>)</string>\n    <string name=\"source_code_links\"><a href=\"https://github.com/MuntashirAkon/AppManager\">GitHub</a> • <a href=\"https://gitlab.com/muntashir/AppManager\">GitLab</a> • <a href=\"https://0xacab.org/muntashir/AppManager\">Riseup</a> • <a href=\"https://codeberg.org/muntashir/AppManager\">Codeberg</a></string>\n</resources>"
  },
  {
    "path": "app/src/main/res/values-de/disclaimer.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- SPDX-License-Identifier: GPL-3.0-or-later --><resources>\n    <string name=\"disclaimer_header\">Haftungsausschluss</string>\n    <string name=\"disclaimer_body\">App Manager bietet Root-Funktionen, die Ihr Gerät bei unsachgemäßer Verwendung möglicherweise beschädigen können. App Manager ist nicht verantwortlich für Schäden, die durch die Verwendung dieser Anwendung entstehen. Wenn Sie nicht genau wissen, wie Root funktioniert, sollten Sie es vermeiden, Root-Optionen zu verwenden, bis Sie sich der Risiken bewusst sind.\n\\n\n\\nJeder Link, den ich zu anderen Anwendungen und Websites anbiete, dient dem Nutzen des Benutzers. Ich bin nicht verantwortlich für Inhalte, die Sie über externe Links finden können.\n\\n\n\\nDurch die Nutzung von App Manager übernehmen Sie die volle Verantwortung für Ihre eigene Nutzung und akzeptieren, dass keine Schäden, Ansprüche oder Geldwerte aufgrund von Missbrauch gewährt werden.\n\\n\n\\nMit der Nutzung dieser Anwendung übernehmen Sie die volle Verantwortung für die Nutzung und erklären sich damit einverstanden, dass ich keine Verantwortung für Handlungen übernehme, die sich nachteilig auf Ihr Gerät auswirken.</string>\n    <string name=\"disclaimer_footer\">© 2020–2024 Muntashir Al-Islam</string>\n    <string name=\"disclaimer_agree_forever\">Nicht erneut anzeigen</string>\n    <string name=\"disclaimer_agree\">Ich bin einverstanden</string>\n    <string name=\"disclaimer_exit\">Beenden</string>\n</resources>"
  },
  {
    "path": "app/src/main/res/values-de/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- SPDX-License-Identifier: GPL-3.0-or-later --><resources xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:tools=\"http://schemas.android.com/tools\">\n    <string name=\"_lang_tag\" translatable=\"false\">de</string>\n    <string name=\"uninstall\">Deinstallieren</string>\n    <string name=\"permissions\">Verwendet Berechtigungen</string>\n    <string name=\"require_no_permission\">Keine Berechtigungen benötigt</string>\n    <string name=\"activities\">Aktivitäten</string>\n    <string name=\"launch\">Starten</string>\n    <string name=\"refresh\">Neu laden</string>\n    <string name=\"no_activities\">Keine Aktivitäten</string>\n    <string name=\"receivers\">Empfänger</string>\n    <string name=\"no_receivers\">Keine Empfänger</string>\n    <string name=\"providers\">Anbieter</string>\n    <string name=\"no_providers\">Keine Anbieter</string>\n    <string name=\"launch_mode\">Start-Modus</string>\n    <string name=\"task_affinity\">Affinität der Aufgabe</string>\n    <string name=\"sort_by_last_update\">Zuletzt aktualisiert</string>\n    <string name=\"authority\">Autorität</string>\n    <string name=\"service\">Dienste</string>\n    <string name=\"no_service\">Keine Dienste</string>\n    <string name=\"orientation\">Ausrichtung</string>\n    <string name=\"soft_input\">Soft-Input-Modus</string>\n    <string name=\"flags\">Flaggen</string>\n    <string name=\"grant_uri_permission\">URI-Berechtigungen erteilen</string>\n    <string name=\"path_permissions\">Pfad-Berechtigungen</string>\n    <string name=\"read\">Lesen</string>\n    <string name=\"write\">Schreiben</string>\n    <string name=\"patterns_allowed\">Erlaubte Muster</string>\n    <string name=\"declared_permission\">Berechtigungen</string>\n    <string name=\"shared_libs\">Geteilte Bibliotheken</string>\n    <string name=\"group\">Gruppe</string>\n    <string name=\"uses_feature\">Benutzt Funktionalitäten</string>\n    <string name=\"no_feature\">Keine Funktionalitäten</string>\n    <string name=\"sort_by_shared_user_id\">Geteilte Nutzer-ID</string>\n    <string name=\"shared_user_id\">Geteilte Nutzer-ID</string>\n    <string name=\"sort_by_sha\">Signatur</string>\n    <string name=\"signatures\">Signaturen</string>\n    <string name=\"app_signing_no_signatures\">Keine gültigen Signaturen</string>\n    <string name=\"configurations\">Konfigurationen</string>\n    <string name=\"no_configurations\">Keine Konfigurationen</string>\n    <string name=\"input_features\">Eingabe-Funktionalitäten</string>\n    <string name=\"manifest\">Manifest</string>\n    <string name=\"error\">Fehler</string>\n    <string name=\"loading\">Laden…</string>\n    <!-- &#8230; = ... -->\n    <string name=\"sort_by_app_label\">App-Name</string>\n    <string name=\"sort_by_package_name\">Paketname</string>\n    <string name=\"sort_by_domain\">Nutzeranwendungen zuerst</string>\n    <string name=\"sort_by_target_sdk\">Ziel-SDK</string>\n    <string name=\"data_received\">Daten empfangen</string>\n    <string name=\"data_transmitted\">Daten gesendet</string>\n    <string name=\"data_usage_msg\">Datenverbrauch</string>\n    <string name=\"about\">Über</string>\n    <string name=\"data_size\">Daten</string>\n    <string name=\"cache_size\">Cache</string>\n    <string name=\"obb_size\">Obb</string>\n    <string name=\"media_size\">Medien</string>\n    <string name=\"app_not_installed\">App ist nicht installiert</string>\n    <string name=\"system\">System</string>\n    <string name=\"user\">Nutzer</string>\n    <string name=\"sort\">Sortieren</string>\n    <string name=\"version_name_with_code\">Version <xliff:g id=\"version_name\" example=\"2.5.17\">%1$s</xliff:g> (<xliff:g id=\"version_code\" example=\"365\">%2$d</xliff:g>)</string>\n    <string name=\"app_info\">App-Informationen</string>\n    <string name=\"system_app\">System-Anwendung</string>\n    <string name=\"user_app\">Benutzer-Anwendung</string>\n    <string name=\"paths_and_directories\">Pfade &amp; Verzeichnisse</string>\n    <string name=\"source_dir\">Code-Verzeichnis</string>\n    <string name=\"data_dir\">Daten-Verzeichnis</string>\n    <string name=\"sdk_min\">Min.</string>\n    <string name=\"sdk_max\">Ziel</string>\n    <string name=\"sdk_flags\">Flaggen</string>\n    <string name=\"more_info\">Weitere Details</string>\n    <string name=\"date_installed\">Installiert am</string>\n    <string name=\"date_updated\">Aktualisiert am</string>\n    <string name=\"installer_app\">Installationsprogramm</string>\n    <string name=\"user_id\">Nutzer-ID</string>\n    <string name=\"main_activity\">Haupt-Aktivität</string>\n    <string name=\"empty_package_name\">Leerer Paketname</string>\n    <string name=\"error_creating_shortcut\">Konnte Verknüpfung nicht erstellen</string>\n    <string name=\"error_verbose_pin_shortcut\">Der aktuelle Launcher unterstützt PinShortcut nicht. Konnte Verknüpfung nicht erstellen.</string>\n    <string name=\"starting_activity\">Starte Aktivität: <xliff:g id=\"activity_name\" example=\".main.MainActivity\">%1$s</xliff:g></string>\n    <string name=\"create_shortcut\">Verknüpfung erstellen</string>\n    <string name=\"shortcut_name\">Name der Verknüpfung</string>\n    <string name=\"package_name\">Paketname</string>\n    <string name=\"class_name\">Klassenname</string>\n    <string name=\"icon_picker\">Icon-Auswahl</string>\n    <string name=\"license\">Lizenz</string>\n    <string name=\"third_party\">Drittanbieter-Lizenzen und -Icons</string>\n    <string name=\"credits\">Danksagungen</string>\n    <string name=\"credits_message\">An die Autoren von \\n- The Android Open Source Project \\n- <a href=\"https://github.com/zhaobozhen/libraries\">Absinthe\\'s libraries</a> \\n- <a href=\"https://github.com/butzist/ActivityLauncher\">Activity Launcher</a> \\n- <a href=\"https://bitbucket.org/oF2pks/fdroid-applications-info\">Apps_packages Info</a> \\n- <a href=\"https://github.com/zhaobao/AppsMonitor\">AppsMonitor</a> \\n- <a href=\"https://github.com/8enet/AppOpsX\">AppOpsX</a> \\n- <a href=\"https://github.com/gabrielemariotti/changeloglib\">ChangeLog Library</a> \\n- <a href=\"https://bitbucket.org/oF2pks/fdroid-classyshark3xodus\">ClassySharkAndroid</a> \\n- <a href=\"https://github.com/billthefarmer/editor\">Editor</a> \\n- <a href=\"https://github.com/Raival-e/File-Explorer\">File Explorer</a> \\n- <a href=\"https://github.com/nex3z/FlowLayout\">FlowLayout</a> \\n- <a href=\"https://github.com/k3b/intent-intercept\">Intent Intercept</a> \\n- <a href=\"https://github.com/YarikSOffice/lingver\">Lingver</a> \\n- <a href=\"https://github.com/topjohnwu/Magisk\">Magisk</a> \\n- <a href=\"https://github.com/zhanghai/MaterialFiles\">Material Files</a> \\n- <a href=\"https://github.com/pluscubed/matlog\">MatLog</a> \\n- <a href=\"https://github.com/matrix-org/matrix-android-sdk\">Matrix Android SDK</a> \\n- <a href=\"https://github.com/jensstein/oandbackup\">OAndBackup</a> \\n- <a href=\"https://github.com/open-keychain/open-keychain\">Open Keychain</a> \\n- <a href=\"https://github.com/Aefyr/SAI\">SAI</a> \\n- <a href=\"https://github.com/RikkaApps/Shizuku\">Shizuku</a> \\n- <a href=\"https://github.com/eclipse/tm4e\">tm4e</a> \\n- <a href=\"https://github.com/tuyafeng/Watt\">Watt</a></string>\n    <string name=\"word_wrap\">Zeilenumbruch ein-/ausschalten</string>\n    <string name=\"class_viewer\">Klassen-Betrachter</string>\n    <string name=\"toggle_class_listing\">Auflisten von Klassen ein-/ausschalten</string>\n    <string name=\"found_trackers\">Gefundene Verfolger:</string>\n    <string name=\"tracker_details\">Verfolger-Details</string>\n    <string name=\"tracker_classes\">Verfolger-Klassen</string>\n    <string name=\"all_classes\">Alle Klassen</string>\n    <plurals name=\"main_list_date_days\">\n        <item quantity=\"one\"><xliff:g id=\"last_update_date\" example=\"20/10/2020\">%1$s</xliff:g> <xliff:g id=\"day_no\" example=\"5\">%2$d</xliff:g> Tag</item>\n        <item quantity=\"other\"><xliff:g id=\"last_update_date\" example=\"20/10/2020\">%1$s</xliff:g> <xliff:g id=\"day_no\" example=\"5\">%2$d</xliff:g> Tage</item>\n    </plurals>\n    <string name=\"no_shared_libs\">Keine geteilten Bibliotheken</string>\n    <string name=\"no_tracker_class\">Keine Verfolger-Klassen</string>\n    <string name=\"app_usage\">App-Nutzung</string>\n    <string name=\"usage_weekly\">Wöchentlich</string>\n    <string name=\"usage_today\">Heute</string>\n    <string name=\"usage_7_days\">Letzte 7 Tage</string>\n    <plurals name=\"usage_months\">\n        <item quantity=\"one\">%1$d Mt</item>\n        <item quantity=\"other\">%1$d Mte</item>\n    </plurals>\n    <plurals name=\"usage_days\">\n        <item quantity=\"one\">%1$d Tag</item>\n        <item quantity=\"other\">%1$d Tage</item>\n    </plurals>\n    <plurals name=\"usage_hours\">\n        <item quantity=\"one\">%1$d Std</item>\n        <item quantity=\"other\">%1$d Stde</item>\n    </plurals>\n    <string name=\"usage_less_than_a_minute\">Weniger als eine Minute</string>\n    <string name=\"go_back\">Zurück</string>\n    <string name=\"go\">Weiter</string>\n    <string name=\"grant_usage_access\">Zugriff auf Nutzungsdaten erlauben</string>\n    <string name=\"grant_usage_acess_message\">Wird verwendet, um Informationen zur App-Nutzung anzuzeigen.</string>\n    <string name=\"share_apk\">APK teilen</string>\n    <string name=\"failed_to_extract_apk_file\">APK-Extraktion fehlgeschlagen</string>\n    <string name=\"menu_remove_rules\">Regeln entfernen</string>\n    <string name=\"menu_apply_rules\">Regeln anwenden</string>\n    <string name=\"search\">Suchen</string>\n    <string name=\"dev_protected_data_dir\">Geräte-geschütztes Daten-Verzeichnis</string>\n    <string name=\"native_library_dir\">Native-JNI-Bibliotheken-Verzeichnis</string>\n    <string name=\"process_name\">Prozess-Name</string>\n    <string name=\"no_code\">Kein Code</string>\n    <string name=\"requested_large_heap\">Viel Heap-Speicher</string>\n    <string name=\"updated_app\">Aktualisiert</string>\n    <string name=\"debuggable\">Debuggbar</string>\n    <string name=\"test_only\">Nur zum Testen</string>\n    <string name=\"shared_prefs\">Geteilte Einstellungen</string>\n    <string name=\"databases\">Datenbanken</string>\n    <string name=\"save\">Speichern</string>\n    <string name=\"discard\">Verwerfen</string>\n    <string name=\"delete\">Löschen</string>\n    <string name=\"deleted_successfully\">Gelöscht</string>\n    <string name=\"deletion_failed\">Löschen fehlgeschlagen</string>\n    <string name=\"saved_successfully\">Gespeichert</string>\n    <string name=\"saving_failed\">Speichern fehlgeschlagen, versuche es bitte erneut.</string>\n    <string name=\"string_value\">Zeichenkette</string>\n    <string name=\"long_integer_value\">Wert der Ganzzahl (long)</string>\n    <string name=\"integer_value\">Wert der Ganzzahl (int)</string>\n    <string name=\"decimal_value\">Wert der Dezimalzahl</string>\n    <string name=\"boolean_value\">Wahrheitswert</string>\n    <string name=\"key_name\">Schlüssel-Name</string>\n    <string name=\"select_type\">Wähle einen Typ</string>\n    <string name=\"add_item\">Hinzufügen</string>\n    <string name=\"done\">Fertig</string>\n    <string name=\"type_boolean\">Wahr/falsch</string>\n    <string name=\"type_float\">Dezimalzahl</string>\n    <string name=\"type_int\">Ganzzahl (int)</string>\n    <string name=\"type_long\">Ganzzahl (long)</string>\n    <string name=\"type_string\">Zeichen</string>\n    <string name=\"error_evaluating_input\">Konnte Eingabe nicht auswerten</string>\n    <string name=\"key_name_cannot_be_null\">Schlüssel-Name darf nicht leer sein</string>\n    <string name=\"disabled_app\">Deaktiviert</string>\n    <string name=\"no_usage_in_this_time_range\">Keine Nutzung in diesem Zeitraum</string>\n    <string name=\"no_content\">Keine Inhalte</string>\n    <string name=\"view_in_settings\">In Einstellungen öffnen</string>\n    <string name=\"uninstall_app_message\">Möchtest Du diese Anwendung deinstallieren?</string>\n    <string name=\"failed_to_uninstall\">Konnte <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g> nicht deinstallieren.</string>\n    <string name=\"uninstalled_successfully\"><xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g> wurde deinstalliert.</string>\n    <string name=\"uninstall_system_app_message\">Dies ist eine Systemanwendung. Möchtest Du sie wirklich deinstallieren?</string>\n    <string name=\"stopped\">Beendet</string>\n    <string name=\"disable\">Deaktivieren</string>\n    <string name=\"enable\">Aktivieren</string>\n    <string name=\"force_stop\">Erzwungener Stopp</string>\n    <string name=\"failed_to_stop\">Konnte <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g> nicht beenden.</string>\n    <string name=\"storage_and_cache\">Speicher und Cache</string>\n    <string name=\"total_size\">Insgesamt</string>\n    <string name=\"app_size\">Anwendung</string>\n    <string name=\"app_ops\">App-Ops</string>\n    <string name=\"no_app_ops\">Keine App-Operationen</string>\n    <string name=\"failed_to_enable_op\">Konnte die geforderte App Op nicht aktivieren</string>\n    <string name=\"failed_to_disable_op\">Konnte gewünschte App Op nicht entziehen</string>\n    <string name=\"rules_not_applied\">Regeln wurden nicht angewendet</string>\n    <string name=\"str_logo\">Logo</string>\n    <string name=\"pref_global_blocking_enabled\">Sofortige Komponentensperrung</string>\n    <string name=\"pref_global_blocking_enabled_msg\">Erlaubt jede Komponente einer Anwendung zu blockieren, ohne die Blockierung für die Anwendung explizit einzuschalten.</string>\n    <string name=\"usage_access\">Zugriff auf Nutzungsdaten</string>\n    <string name=\"app_settings\">Einstellungen</string>\n    <string name=\"usage_yesterday\">Gestern</string>\n    <string name=\"exodus_link\">\\u03b5xodus-Link</string>\n    <string name=\"sort_by_blocked_components\">Blockierte zuerst</string>\n    <string name=\"external_data_dir\">Externes Daten-Verzeichnis</string>\n    <string name=\"external_multiple_data_dir\">Externes Daten-Verzeichnis <xliff:g id=\"dir_no\" example=\"1\">%1$d</xliff:g></string>\n    <plurals name=\"no_of_times_opened\">\n        <item quantity=\"one\">einmal</item>\n        <item quantity=\"other\">%1$d mal</item>\n    </plurals>\n    <string name=\"sort_by_last_used\">Zuletzt verwendet</string>\n    <string name=\"sort_by_screen_time\">Zeit im Vordergrund</string>\n    <string name=\"sort_by_times_opened\">Anzahl geöffnet</string>\n    <string name=\"sort_by_mobile_data\">Mobile Daten</string>\n    <string name=\"pref_import_export_blocking_rules\">Blockier-Regeln importieren/exportieren</string>\n    <string name=\"pref_import_export_blocking_rules_msg\">Regeln importieren/exportieren, externe Regeln aus Watt oder Blocker importieren.</string>\n    <string name=\"pref_import_watt\">Aus Watt importieren</string>\n    <string name=\"pref_import_blocker\">Aus Blocker importieren</string>\n    <string name=\"the_import_was_successful\">Importiert</string>\n    <string name=\"the_export_was_successful\">Exportiert</string>\n    <plurals name=\"failed_to_import_files\">\n        <item quantity=\"one\">%1$d Datei konnte nicht importiert werden.</item>\n        <item quantity=\"other\">%1$d Dateien konnten nicht importiert werden.</item>\n    </plurals>\n    <string name=\"apk_updater\">APK-Aktualisierung</string>\n    <string name=\"running_apps\">Laufende Anwendungen</string>\n    <string name=\"kill_process\">Beenden erzwingen</string>\n    <string name=\"disable_background_run\">Hintergrundbetrieb verhindern</string>\n    <string name=\"pid_and_ppid\">Prozess-ID: %1$d, ID des übergeordneten Prozesses: %2$d</string>\n    <string name=\"memory_virtual_memory\">RAM: %1$s, virtueller RAM: %2$s</string>\n    <string name=\"user_and_uid\">Benutzer: <xliff:g id=\"user_name\" example=\"root\">%1$s</xliff:g> (<xliff:g id=\"user_id\" example=\"0\">%2$d</xliff:g>)</string>\n    <string name=\"clear_data\">Daten löschen</string>\n    <string name=\"backup_restore\">Sichern/Wiederherstellen</string>\n    <string name=\"disable_background\">Hintergrundbetrieb verhindern</string>\n    <string name=\"export_blocking_rules\">Blockierregeln exportieren</string>\n    <plurals name=\"alert_failed_to_clear_data\">\n        <item quantity=\"one\">Löschen der Daten von %1$d Anwendung nicht möglich</item>\n        <item quantity=\"other\">Löschen der Daten von %1$d Anwendungen nicht möglich</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_uninstall\">\n        <item quantity=\"one\">Deinstallieren von %1$d Anwendung nicht möglich</item>\n        <item quantity=\"other\">Deinstallieren von %1$d Anwendungen nicht möglich</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_disable_background\">\n        <item quantity=\"one\">Konnte die Hintergrundausführung von %1$d Anwendung nicht verhindern</item>\n        <item quantity=\"other\">Konnte die Hintergrundausführung von %1$d Anwendungen nicht verhindern</item>\n    </plurals>\n    <string name=\"the_operation_was_successful\">Erledigt</string>\n    <plurals name=\"alert_failed_to_force_stop\">\n        <item quantity=\"one\">Forciertes Beenden von %1$d Anwendung nicht möglich</item>\n        <item quantity=\"other\">Forciertes Beenden von %1$d Anwendungen nicht möglich</item>\n    </plurals>\n    <string name=\"toggle_kill_for_system_apps\">„Beenden erzwingen“ für System-Anwendungen ein- oder ausschalten</string>\n    <string name=\"permission_name\">Name der Berechtigung</string>\n    <string name=\"mode\">Modus</string>\n    <string name=\"running\">Laufend</string>\n    <string name=\"duration\">Dauer</string>\n    <string name=\"accept_time\">Zeitpunkt freigegeben</string>\n    <string name=\"reject_time\">Zeitpunkt abgelehnt</string>\n    <string name=\"ago\">vor</string>\n    <string name=\"pref_import\">Importieren</string>\n    <string name=\"pref_export\">Exportieren</string>\n    <string name=\"import_options\">Import-Optionen</string>\n    <string name=\"export_options\">Export-Optionen</string>\n    <string name=\"import_failed\">Importieren fehlgeschlagen!</string>\n    <string name=\"export_failed\">Exportieren fehlgeschlagen!</string>\n    <string name=\"keyboard_type\">Tastatur-Typ</string>\n    <string name=\"navigation\">Navigation</string>\n    <string name=\"touchscreen\">Berührungsempfindlicher Bildschirm</string>\n    <string name=\"pref_export_msg\">Exportieren von Blockier-Regeln von App Manager in den externen Speicher.</string>\n    <string name=\"pref_import_msg\">Importieren von zuvor exportierten Blockier-Regeln vom App Manager.</string>\n    <string name=\"pref_import_watt_msg\">Importieren der Blockier-Regeln von Watt; jede Datei enthält Regeln für ein genanntes Paket <tt>paketname.xml</tt> usw.</string>\n    <string name=\"pref_import_blocker_msg\">Importieren von Blockier-Regeln aus Blocker, wobei jede Datei Regeln für ein einzelnes Paket enthält.</string>\n    <string name=\"pref_app_theme\">Farbschema der Anwendung</string>\n    <string name=\"follow_system\">Systemkonform</string>\n    <string name=\"battery_mode\">Energiesparmodus</string>\n    <string name=\"day\">Tag</string>\n    <string name=\"night\">Nacht</string>\n    <string name=\"select_theme\">Farbschema</string>\n    <string name=\"apply\">Anwenden</string>\n    <string name=\"pref_about_msg\">App Manager-Version und -Lizenz, Danksagungen, etc.</string>\n    <string name=\"version\">Version</string>\n    <string name=\"sort_by_wifi_data\">Wlan-Daten</string>\n    <string name=\"block_trackers\">Verfolger blockieren</string>\n    <string name=\"sort_by_component_name\">Komponentennamen</string>\n    <string name=\"reset_to_default\">Standardeinstellungen wiederherstellen</string>\n    <string name=\"deny_dangerous_app_ops\">Gefährliche App Ops entziehen</string>\n    <string name=\"sort_by_app_ops_names\">App Ops-Name</string>\n    <string name=\"sort_by_denied_app_ops\">Entzogene zuerst</string>\n    <string name=\"sort_by_app_ops_values\">App Ops-Wert</string>\n    <string name=\"sort_by_permission_names\">Name der Berechtigung</string>\n    <string name=\"sort_by_dangerous_permissions\">Gefährliche zuerst</string>\n    <string name=\"sort_by_denied_permissions\">Entzogene zuerst</string>\n    <string name=\"deny_dangerous_permissions\">Gefährliche Berechtigungen entziehen</string>\n    <string name=\"sort_by_tracker_components\">Verfolger zuerst</string>\n    <string name=\"unknown_op\">Unbekannte Operation</string>\n    <plurals name=\"alert_failed_to_disable_trackers\">\n        <item quantity=\"one\">Konnte Verfolger von %1$d Anwendung nicht deaktivieren</item>\n        <item quantity=\"other\">Konnte Verfolger von %1$d Anwendungen nicht deaktivieren</item>\n    </plurals>\n    <string name=\"failed_to_grant_permission\">Erteilen der Berechtigung nicht möglich</string>\n    <string name=\"failed_to_revoke_permission\">Entziehen der Berechtigung nicht möglich</string>\n    <string name=\"failed_to_reset_app_ops\">Zurücksetzen der App-Ops nicht möglich</string>\n    <string name=\"failed_to_deny_dangerous_perms\">Entziehen aller gefährlichen Berechtigungen nicht möglich</string>\n    <string name=\"failed_to_deny_dangerous_app_ops\">Entziehen aller gefährlichen App-Ops nicht möglich</string>\n    <string name=\"launch_app\">Starten</string>\n    <string name=\"never_ask\">Niemals fragen</string>\n    <string name=\"one_click_ops\">Ein-Klick-Ops</string>\n    <string name=\"changelog\">Änderungen</string>\n    <string name=\"external_apk_no_app_op\">Eine externe APK hat keine App-Operationen</string>\n    <string name=\"manifest_viewer\">Manifest einsehen</string>\n    <plurals name=\"no_of_trackers\">\n        <item quantity=\"one\">%1$d Verfolger</item>\n        <item quantity=\"other\">%1$d Verfolger</item>\n    </plurals>\n    <string name=\"install\">Installieren</string>\n    <string name=\"update\">Aktualisieren</string>\n    <string name=\"source_code\">Quellcode</string>\n    <string name=\"pref_import_existing\">Existierende Regeln importieren</string>\n    <string name=\"pref_import_existing_msg\">Hinzufügen von Komponenten zum App Manager, die von anderen Anwendungen deaktiviert wurden. Seien Sie bei der Verwendung dieses Tools vorsichtig, da es viele Fehltreffer geben kann. Wählen Sie nur die Anwendungen aus, bei denen Sie sich sicher sind.</string>\n    <string name=\"clear_cache\">Cache leeren</string>\n    <string name=\"block_unblock_trackers_description\">Blockiere oder gebe Verfolger-Komponenten aller installierter Anwendungen frei</string>\n    <string name=\"block_components_dots\">Komponenten blockieren…</string>\n    <string name=\"deny_app_ops_description\">Einstellen eines Modus für App-Operationen, die durch konstante Werte identifiziert werden (z. B. <tt>63</tt> oder <tt>RUN_IN_BACKGROUND</tt>)</string>\n    <string name=\"clear_data_from_uninstalled_apps\">Daten deinstallierter Anwendungen löschen</string>\n    <string name=\"clear_data_from_uninstalled_apps_description\">Daten von Anwendungen, die mit der <tt>DONT_DELETE_DATA</tt>-Flagge deinstalliert wurden, löschen</string>\n    <string name=\"clear_app_cache\">Cache der Anwendung leeren</string>\n    <string name=\"clear_app_cache_description\">Den Cache aller Anwendungen leeren</string>\n    <string name=\"no_tracker_found\">Keine Verfolger gefunden</string>\n    <string name=\"failed_packages\">Pakete mit Fehlern</string>\n    <string name=\"input_signatures\">Signatur(en)</string>\n    <string name=\"input_signatures_description\">Bitte die gewünschten Signaturen mit einer Leerstelle getrennt angeben, z. B. <tt>com.facebook org.app2 com.app3</tt> usw.</string>\n    <string name=\"filtered_packages\">Gefilterte Pakete</string>\n    <string name=\"input_app_ops\">App Ops</string>\n    <string name=\"input_app_ops_description\">Geben Sie App-Op-Namen und/oder Konstanten mit Leerzeichen ein, z. B. <tt>WAKE_LOCK 63 72 CAMERA</tt> etc.</string>\n    <string name=\"only_works_in_root_or_adb_mode\">Nur im Root- oder ADB-Modus verfügbar</string>\n    <string name=\"failed_to_parse_some_numbers\">Einlesen mancher Zahlen nicht möglich</string>\n    <plurals name=\"no_of_splits\">\n        <item quantity=\"one\">%1$d Teil</item>\n        <item quantity=\"other\">%1$d Teile</item>\n    </plurals>\n    <string name=\"termux\">Termux</string>\n    <string name=\"package_name_is_installed_successfully\"><xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g> ist installiert</string>\n    <string name=\"filter\">Filter</string>\n    <string name=\"filter_user_apps\">Benutzer-Anwendungen</string>\n    <string name=\"filter_system_apps\">System-Anwendungen</string>\n    <string name=\"filter_apps_with_rules\">Mit Regeln</string>\n    <string name=\"select_all\">Alle auswählen</string>\n    <string name=\"installed_version\">Installierte Version</string>\n    <string name=\"trackers\">Verfolger</string>\n    <string name=\"components\">Komponenten</string>\n    <string name=\"features\">Funktionalitäten</string>\n    <string name=\"whats_new\">Was gibt\\'s Neues</string>\n    <string name=\"blocking_rules\">Blockierregeln</string>\n    <string name=\"external_data\">Externe Daten</string>\n    <string name=\"data\">Daten</string>\n    <string name=\"backup\">Sichern</string>\n    <string name=\"restore\">Wiederherstellen</string>\n    <string name=\"delete_backup\">Sicherung löschen</string>\n    <string name=\"backup_options\">Sicherungsoptionen</string>\n    <plurals name=\"failed_to_backup_some_apk_files\">\n        <item quantity=\"one\">Erstellen der Sicherung von %1$d Anwendung nicht möglich</item>\n        <item quantity=\"other\">Erstellen der Sicherungen von %1$d Anwendungen nicht möglich</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_backup\">\n        <item quantity=\"one\">Sichern von %1$d APK-Datei nicht möglich</item>\n        <item quantity=\"other\">Sichern von %1$d APK-Dateien nicht möglich</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_restore\">\n        <item quantity=\"one\">Wiederherstellen von %1$d Anwendung nicht möglich</item>\n        <item quantity=\"other\">Wiederherstellen von %1$d Anwendungen nicht möglich</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_delete_backup\">\n        <item quantity=\"one\">Konnte %1$d Sicherung nicht löschen</item>\n        <item quantity=\"other\">Konnte %1$d Sicherungen nicht löschen</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_unblock_trackers\">\n        <item quantity=\"one\">Deaktivieren der Verfolger aus %1$d Anwendung nicht möglich</item>\n        <item quantity=\"other\">Deaktivieren der Verfolger aus %1$d Anwendungen nicht möglich</item>\n    </plurals>\n    <string name=\"apply_to_system_apps\">Auf Systemanwendungen anwenden</string>\n    <string name=\"apply_to_system_apps_question\">Soll dies auch auf Systemanwendungen angewendet werden\\? Im Zweifelsfall „Nein“ auswählen.</string>\n    <string name=\"no\">Nein</string>\n    <string name=\"yes\">Ja</string>\n    <string name=\"skip_signature_checks\">Signaturprüfungen überspringen</string>\n    <string name=\"clear_data_message\">Sollen die Daten dieser Anwendung wirklich gelöscht werden?</string>\n    <string name=\"clear\">Löschen</string>\n    <string name=\"block\">Blockieren</string>\n    <string name=\"unblock\">Freigeben</string>\n    <string name=\"block_unblock_trackers\">Verfolger blockieren/freigeben</string>\n    <string name=\"no_matching_package_found\">Keine übereinstimmende App gefunden</string>\n    <string name=\"export_icon\">Icon extrahieren</string>\n    <string name=\"open_in_termux\">In Termux öffnen</string>\n    <string name=\"run_in_termux\">In Termux ausführen</string>\n    <string name=\"website\">Webseite</string>\n    <string name=\"pref_remove_all_rules\">Alle Regeln entfernen</string>\n    <string name=\"pref_remove_all_rules_msg\">Berechtigungen werden erteilt, Anwendungen und Komponenten werden auf ihre Standardwerte zurückgesetzt.</string>\n    <string name=\"are_you_sure\">Bist du Dir sicher?</string>\n    <string name=\"filter_apps_with_activities\">Mit Aktivitäten</string>\n    <string name=\"toggle_default_app_ops\">Voreingestellte App Ops ein-/ausschalten</string>\n    <string name=\"installer_error_aborted\">Die Installation ist fehlgeschlagen, weil sie entweder abgebrochen oder die Sitzung unerwartet geschlossen wurde</string>\n    <string name=\"installer_error_blocked_device\">Gerät</string>\n    <string name=\"installer_error_blocked\">Installation ist von <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g> blockiert</string>\n    <string name=\"installer_error_conflict\">Die Anwendung konnte nicht installiert werden, weil das Paket verwendet wird</string>\n    <string name=\"installer_error_incompatible\">Anwendung ist nicht mit diesem Gerät kompatibel</string>\n    <string name=\"installer_error_bad_apks\">Ungültige APK-Dateien ausgewählt</string>\n    <string name=\"installer_error_storage\">Nicht genügend Speicherplatz zur Installation verfügbar</string>\n    <string name=\"installer_error_generic\">Installation fehlgeschlagen</string>\n    <string name=\"installer_error_lidl_rom\">Dein ROM ist leider nicht kompatibel mit dem Rootless Installer.</string>\n    <string name=\"failed_to_fetch_package_info\">Laden der Paket-Informationen nicht möglich</string>\n    <string name=\"batch_ops\">Stapelverarbeitung</string>\n    <string name=\"operation_running\">Vorgang erfolgt…</string>\n    <string name=\"full_stop_tap_to_see_details\">. Berühren für mehr Details.</string>\n    <string name=\"try_again\">Erneut versuchen</string>\n    <string name=\"install_app_message\">Möchtest du diese App installieren?</string>\n    <string name=\"reinstall\">Erneut installieren</string>\n    <string name=\"unblock_trackers\">Tracker blockieren</string>\n    <string name=\"package_installer\">Paket-Installer</string>\n    <string name=\"install_in_progress\">Installation wird durchgeführt …</string>\n    <string name=\"installer_error_security\">Konnte nicht auf APK-Dateien zugreifen</string>\n    <string name=\"installer_error_session_create\">Die Installation konnte nicht gestartet werden</string>\n    <string name=\"installer_error_session_write\">Der Schreib-Zugriff für die Installation wurde verweigert</string>\n    <string name=\"installer_error_session_commit\">Fehler beim Übertragen der APK-Dateien</string>\n    <string name=\"installer_error_session_abandon\">Beenden der Installation nicht möglich</string>\n    <string name=\"backup_apk_files\">APK Dateien</string>\n    <string name=\"backup_obb_media\">OBB und Medien</string>\n    <string name=\"failed_to_extract_obb_files\">Extrahieren der OBB-Dateien nicht möglich</string>\n    <string name=\"obb_files_extracted_successfully\">OBB-Dateien entpackt</string>\n    <string name=\"backup_multiple\">Mehrfache Sicherung</string>\n    <string name=\"backup_all_users\">Alle Benutzer</string>\n    <string name=\"pref_app_language\">Sprache</string>\n    <string name=\"auto\">Automatisch</string>\n    <string name=\"choose_language\">Wähle eine Sprache</string>\n    <string name=\"touchscreen_finger\">Finger</string>\n    <string name=\"touchscreen_stylus\">Schreibstift</string>\n    <string name=\"touchscreen_no_touch\">Keine Berührung</string>\n    <string name=\"navigation_wheel\">Rad</string>\n    <string name=\"navigation_trackball\">Trackball</string>\n    <string name=\"navigation_dial_pad\">Ziffernblock wählen</string>\n    <string name=\"navigation_no_nav\">Kein Navigator</string>\n    <string name=\"keyboard_12_keys\">12 Schlüssel</string>\n    <string name=\"keyboard_qwerty\">QWERTY</string>\n    <string name=\"keyboard_no_keys\">Keine Schlüssel</string>\n    <string name=\"_undefined\">nicht definiert</string>\n    <string name=\"required\">Erfordert</string>\n    <string name=\"orientation_sensor\">Sensor</string>\n    <string name=\"orientation_sensor_portrait\">Hochformat erfassen</string>\n    <string name=\"orientation_sensor_landscape\">Querformat erfassen</string>\n    <string name=\"orientation_user\">Nutzer</string>\n    <string name=\"orientation_reverse_landscape\">Querformat drehen</string>\n    <string name=\"orientation_reverse_portrait\">Hochformat drehen</string>\n    <string name=\"orientation_portrait\">Hochformat</string>\n    <string name=\"orientation_landscape\">Querformat</string>\n    <string name=\"orientation_no_sensor\">Kein Sensor</string>\n    <string name=\"orientation_locked\">Gesperrt</string>\n    <string name=\"orientation_full_user\">Vollbenutzer</string>\n    <string name=\"orientation_full_sensor\">Voll-Sensor</string>\n    <string name=\"orientation_behind\">Hinter</string>\n    <string name=\"orientation_unspecified\">Nicht näher bezeichnet</string>\n    <string name=\"launch_mode_single_top\">Einzelne Spitze</string>\n    <string name=\"launch_mode_single_task\">Einzelne Aufgabe</string>\n    <string name=\"launch_mode_single_instance\">Einzelne Instanz</string>\n    <string name=\"launch_mode_multiple\">mehrfach</string>\n    <string name=\"locale_split_for_base_apk\"><xliff:g id=\"split_name\" example=\"English\">%1$s</xliff:g> Lokalisierung für die Basis-APK</string>\n    <string name=\"locale_split_for_feature\"><xliff:g id=\"split_name\" example=\"English\">%1$s</xliff:g> Lokalisierung für <xliff:g id=\"feature_name\" example=\"Visualizer\">%2$s</xliff:g></string>\n    <string name=\"abi_split_for_base_apk\"><xliff:g id=\"split_name\" example=\"arm64_v8a\">%1$s</xliff:g> Code für die Basis-APK</string>\n    <string name=\"abi_split_for_feature\"><xliff:g id=\"split_name\" example=\"arm64_v8a\">%1$s</xliff:g> Code für <xliff:g id=\"feature_name\" example=\"Visualizer\">%2$s</xliff:g></string>\n    <string name=\"density_split_for_base_apk\"><xliff:g id=\"split_name\" example=\"xxdpi\">%1$s</xliff:g> (<xliff:g id=\"dpi_no\" example=\"480\">%2$d</xliff:g> DPI) Ressourcen für die Basis-APK</string>\n    <string name=\"density_split_for_feature\"><xliff:g id=\"split_name\" example=\"xxdpi\">%1$s</xliff:g> (<xliff:g id=\"dpi_no\" example=\"480\">%2$d</xliff:g> DPI) Ressourcen für das Merkmal <xliff:g id=\"feature_name\" example=\"Visualizer\">%3$s</xliff:g></string>\n    <string name=\"base_apk\">Basis-APK</string>\n    <string name=\"unknown_split_for_base_apk\"><xliff:g id=\"split_name\" example=\"some_split\">%1$s</xliff:g> für die Basis-APK</string>\n    <string name=\"unknown_split_for_feature\"><xliff:g id=\"split_name\" example=\"some_split\">%1$s</xliff:g> für Merkmal <xliff:g id=\"feature_name\" example=\"Visualizer\">%2$s</xliff:g></string>\n    <string name=\"split_feature_name\">Merkmal: <xliff:g id=\"feature_name\" example=\"Visualizer\">%1$s</xliff:g></string>\n    <plurals name=\"alert_failed_to_block_components\">\n        <item quantity=\"one\">Komponenten für %1$d Anwendung konnte nicht blockiert werden</item>\n        <item quantity=\"other\">Komponenten für %1$d Anwendungen konnten nicht blockiert werden</item>\n    </plurals>\n    <string name=\"orientation_user_landscape\">Horizontale Ansicht</string>\n    <string name=\"orientation_user_portrait\">Vertikale Ansicht</string>\n    <string name=\"routine_ops\">Routineoperationen</string>\n    <string name=\"apply_now\">Jetzt anwenden…</string>\n    <string name=\"keystore\">Schlüsselspeicher</string>\n    <string name=\"no_profiles\">Keine Profile</string>\n    <string name=\"profiles\">Profile</string>\n    <string name=\"open_pgp_provider\">OpenPGP-Anbieter</string>\n    <string name=\"systemless_app\">Systemlose App</string>\n    <string name=\"cancel\">Abbrechen</string>\n    <string name=\"ok\">okay</string>\n    <string name=\"input_backup_name_description\">Der Name der Sicherung sollte keine Leerzeichen enthalten und nicht mit einer Ziffer beginnen. Lassen Sie ihn leer, wenn Sie das aktuelle Datum und die aktuelle Uhrzeit verwenden möchten.</string>\n    <string name=\"input_backup_name\">Bezeichnung der Sicherung</string>\n    <string name=\"downgrade\">Zurückstufen</string>\n    <string name=\"process_state_with_extra\">Zustand: <xliff:g id=\"process_state\" example=\"Sleeping\">%1$s</xliff:g> (<xliff:g id=\"state_extra\" example=\"High priority\">%2$s</xliff:g>)</string>\n    <string name=\"process_state\">Zustand: <xliff:g id=\"process_state\" example=\"Sleeping\">%1$s</xliff:g></string>\n    <string name=\"state_multithreaded\">mehrfach</string>\n    <string name=\"state_foreground\">Vordergrund</string>\n    <string name=\"state_session_leader\">Sitzungsleiter</string>\n    <string name=\"state_locked_memory\">Gesperrter Speicher</string>\n    <string name=\"state_low_priority\">Geringe Priorität</string>\n    <string name=\"state_high_priority\">Hohe Priorität</string>\n    <string name=\"state_unknown\">unbekannt</string>\n    <string name=\"state_waking\">Aufwachen</string>\n    <string name=\"state_wake_kill\">Aufwachen abbrechen</string>\n    <string name=\"state_idle\">untätig</string>\n    <string name=\"state_parked\">geparkt</string>\n    <string name=\"state_zombie\">Zombie</string>\n    <string name=\"state_dead\">tot</string>\n    <string name=\"state_trace_stop\">Spurensuche stoppen</string>\n    <string name=\"state_device_io\">Gerät I/O</string>\n    <string name=\"state_sleeping\">ruhend</string>\n    <plurals name=\"backup_exists_are_you_sure\">\n        <item quantity=\"one\">Ein Backup ist bereits vorhanden. Sind Sie sicher, dass Sie fortfahren wollen?</item>\n        <item quantity=\"other\">Einige Backups sind bereits vorhanden. Sind Sie sicher, dass Sie fortfahren wollen?</item>\n    </plurals>\n    <string name=\"sort_by_memory_usage\">Speicherauslastung</string>\n    <string name=\"sort_by_apps_first\">Apps zuerst</string>\n    <string name=\"sort_by_process_id\">Prozess-ID</string>\n    <string name=\"sort_by_process_name\">Prozess-Name</string>\n    <string name=\"filter_apps\">Apps</string>\n    <string name=\"no_apps\">Keine Apps</string>\n    <string name=\"apps\">Apps</string>\n    <string name=\"pref_backup_flags_msg\">Durch Hinzufügen von Voreinstellungen für Sicherungsoptionen entfällt die Auswahl von Flags bei jeder Sicherung / Wiederherstellung.</string>\n    <string name=\"pref_compression_method\">Kompressionsverfahren</string>\n    <string name=\"rules\">Regeln</string>\n    <string name=\"other\">Andere</string>\n    <string name=\"changes_not_saved\">Änderungen nicht gespeichert</string>\n    <string name=\"allow_open_pgp_operation\">Klicken Sie hier, um App Manager die Verwendung von OpenPGP zu erlauben</string>\n    <string name=\"confirm_installation\">Installation bestätigen</string>\n    <string name=\"non_critical_exts\">Nicht-kritische Erweiterungen</string>\n    <string name=\"critical_exts\">Kritische Erweiterungen</string>\n    <string name=\"dsa_affine_y\">Affine y-Koordinate</string>\n    <string name=\"dsa_affine_x\">Affine x-Koordinate</string>\n    <string name=\"rsa_modulus\">Modul</string>\n    <string name=\"rsa_exponent\">Vertreter</string>\n    <string name=\"format\">Struktur</string>\n    <string name=\"public_key\">Öffentlicher Schlüssel</string>\n    <string name=\"algorithm\">Algorithmus</string>\n    <string name=\"not_yet_valid\">Noch nicht gültig</string>\n    <string name=\"serial_no\">Seriennummer</string>\n    <string name=\"checksums\">Prüfsummen</string>\n    <string name=\"app_signing_signature\">Signatur</string>\n    <string name=\"issued_date\">Ausgabedatum</string>\n    <string name=\"sort_by_backup\">Zuerst sichern</string>\n    <string name=\"expired\">Abgelaufen</string>\n    <string name=\"valid\">Gültig</string>\n    <string name=\"validity\">Gültigkeit</string>\n    <string name=\"type\">Typ</string>\n    <string name=\"expiry_date\">Verfallsdatum</string>\n    <string name=\"issuer\">Herausgeber</string>\n    <string name=\"subject\">Gegenstand</string>\n    <string name=\"filter_apps_with_backups\">Mit Sicherungen</string>\n    <string name=\"failed_to_uninstall_updates\">Updates für <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g> konnten nicht deinstalliert werden.</string>\n    <string name=\"update_uninstalled_successfully\">Updates für <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g> wurden deinstalliert.</string>\n    <string name=\"uninstall_updates\">Updates deinstallieren</string>\n    <string name=\"only_install\">Nur installieren</string>\n    <string name=\"app_signing_install_without_data_loss\">Wenn Sie die Signaturprüfung deaktiviert haben, können Sie die Option <b>Nur installieren</b> verwenden, um die Anwendung ohne Datenverlust zu installieren.</string>\n    <string name=\"app_data_will_be_lost\">Die vorhandenen Daten gehen dabei verloren.</string>\n    <string name=\"app_signing_signature_mismatch_for_system_apps\">Konnte die Anwendung nicht installieren, weil eine Systemanwendung mit einer anderen Signatur diesen Paketnamen hat.</string>\n    <string name=\"do_you_want_to_uninstall_and_install\">Möchten Sie die Anwendung deinstallieren und erneut installieren\\?</string>\n    <string name=\"usage_access_not_supported\">Konnte keinen Nutzungszugriff anfordern, da die entsprechende Einstellungsseite nicht existiert.</string>\n    <string name=\"sys_config\">Systemkonfiguration</string>\n    <string name=\"tap_to_see_details\">Tippen Sie zum Anzeigen der Details</string>\n    <string name=\"lib_details\">Einzelheiten zur Bibliothek</string>\n    <string name=\"no_libs\">Keine Bibliotheken</string>\n    <string name=\"scanner\">Scanner</string>\n    <plurals name=\"libraries\">\n        <item quantity=\"one\">%1$d Bibliothek</item>\n        <item quantity=\"other\">%1$d Bibliotheken</item>\n    </plurals>\n    <plurals name=\"classes\">\n        <item quantity=\"one\">%1$d Klasse</item>\n        <item quantity=\"other\">%1$d Klassen</item>\n    </plurals>\n    <plurals name=\"other_trackers_and_classes\">\n        <item quantity=\"one\"><xliff:g id=\"tracker_no\" example=\"8\">%1$d</xliff:g> Verfolger mit <xliff:g id=\"class_no\" example=\"50\">%2$d</xliff:g> Klassen</item>\n        <item quantity=\"other\"><xliff:g id=\"tracker_no\" example=\"8\">%1$d</xliff:g> Verfolger mit <xliff:g id=\"class_no\" example=\"50\">%2$d</xliff:g> Klassen</item>\n    </plurals>\n    <plurals name=\"two_trackers_and_classes\">\n        <item quantity=\"one\">2 Verfolger mit <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g> Klasse</item>\n        <item quantity=\"other\">2 Verfolger mit <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g> Klassen</item>\n    </plurals>\n    <plurals name=\"tracker_and_classes\">\n        <item quantity=\"one\">1 Verfolger mit <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g> Klasse</item>\n        <item quantity=\"other\">1 Verfolger mit <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g> Klassen</item>\n    </plurals>\n    <string name=\"copy\">Kopieren</string>\n    <string name=\"view_missing_signatures\">Tippen Sie hier, um Signaturen anzuzeigen oder einzusenden, die in der Bibliotheksdatenbank des App Managers noch nicht vorhanden sind.</string>\n    <plurals name=\"missing_signatures\">\n        <item quantity=\"one\">%1$d Signatur fehlt</item>\n        <item quantity=\"other\">%1$d Signaturen fehlen</item>\n    </plurals>\n    <string name=\"filter_running_apps\">Aktive Anwendungen</string>\n    <string name=\"un_apkm\">UnApkm</string>\n    <string name=\"in_progress\">In Bearbeitung</string>\n    <string name=\"conversion_failed\">Konvertierung fehlgeschlagen.</string>\n    <string name=\"select_apk\">Apk auswählen</string>\n    <string name=\"send_crash_report\">Crash-Bericht senden</string>\n    <string name=\"tap_to_submit_crash_report\">Tippen Sie hier, um den Absturzbericht zu senden.</string>\n    <string name=\"am_crashed\">App Manager ist gerade abgestürzt</string>\n    <string name=\"new_profile\">Neues Profil</string>\n    <string name=\"input_profile_name_description\">Der Profilname darf keine Leerzeichen enthalten.</string>\n    <string name=\"input_profile_name\">Bezeichnung des Profils</string>\n    <string name=\"duplicate\">Kopie</string>\n    <string name=\"send_selected\">Ausgewählte senden</string>\n    <string name=\"ecc\">Kryptographie mit elliptischen Kurven</string>\n    <string name=\"rsa\">RSA</string>\n    <string name=\"aes\">AES</string>\n    <string name=\"none\">Keiner</string>\n    <string name=\"pref_encryption_msg\">Verschlüsselung für Backups.</string>\n    <string name=\"encryption\">Verschlüsselung</string>\n    <string name=\"select_user\">Benutzer auswählen</string>\n    <string name=\"failed_to_duplicate_profile\">Konnte Profil nicht duplizieren</string>\n    <string name=\"enabled\">Aktiviert</string>\n    <string name=\"choose\">Auswählen</string>\n    <string name=\"input_permissions_description\">Geben Sie die Berechtigungen mit Leerzeichen getrennt ein, z.B. <tt>com.permission.GET_ACCOUNTS android.permission.ACCESS_MEDIA_LOCATION</tt> etc., oder verwenden Sie <tt>*</tt> für alle Berechtigungen.</string>\n    <string name=\"input_permissions\">Eingabeberechtigungen</string>\n    <string name=\"options\">Optionen</string>\n    <string name=\"off\">Aus</string>\n    <string name=\"on\">Ein</string>\n    <string name=\"profile_state_msg\">Benutzerdefinierter Ein/Aus-Zustand für dieses Profil</string>\n    <string name=\"profile_block_trackers_msg\">Blockiert die Tracker in Apps</string>\n    <string name=\"profile_clear_data_msg\">Löscht die Daten von Apps</string>\n    <string name=\"profile_clear_cache_msg\">Löscht den App-Cache von Apps</string>\n    <string name=\"profile_force_stop_msg\">Erzwingt das Stoppen von Apps</string>\n    <string name=\"allow_routine_ops_msg\">Erlauben Sie die Verwendung des Profils in den Routineoperationen</string>\n    <string name=\"profile_state\">Profilstatus</string>\n    <string name=\"allow_routine_ops\">Routineoperationen zulassen</string>\n    <string name=\"adb_over_tcp\">ADB über TCP</string>\n    <string name=\"pref_mode_of_operations\">Arbeitsweise</string>\n    <string name=\"user_profile_with_id\">Profil: %1$s (%2$d)</string>\n    <string name=\"advanced\">Erweitert</string>\n    <string name=\"simple\">Einfach</string>\n    <string name=\"close\">Schließen</string>\n    <string name=\"no_root\">kein root</string>\n    <string name=\"root\">Nutzer root</string>\n    <string name=\"install_location_prefer_external\">Externe bevorzugen</string>\n    <string name=\"install_location_internal_only\">Nur intern</string>\n    <string name=\"installer\">Installationsprogramm</string>\n    <string name=\"comment\">Anmerkung</string>\n    <string name=\"install_location\">Installationsort</string>\n    <string name=\"pref_sign_apk_msg\">APK-Dateien vor der Installation signieren.</string>\n    <string name=\"pref_sign_apk\">APK signieren</string>\n    <string name=\"pref_signature_schemes_msg\">Für eine bessere Kompatibilität sollten mindestens v1- und v2-Schemata ausgewählt werden. Für das v4-Schema ist v2 oder v3 erforderlich.</string>\n    <string name=\"v4_scheme\">v4-Schema (seit Android 11)</string>\n    <string name=\"v3_scheme\">v3-Schema (ab Android 9)</string>\n    <string name=\"v2_scheme\">v2-Schema (seit Android 7.0)</string>\n    <string name=\"v1_scheme\">v1-Schema (ab Android 1.0)</string>\n    <string name=\"pref_apk_signing_msg\">Festlegen von Signaturschemata, benutzerdefinierten Signaturschlüsseln usw.</string>\n    <string name=\"apk_signing\">APK-Signierung</string>\n    <string name=\"app_signing_signature_schemes\">Signaturschemata</string>\n    <string name=\"splits\">Teile</string>\n    <string name=\"source_stamp_verified\">Quellenstempel verifiziert.</string>\n    <string name=\"not_verified\">Nicht überprüft</string>\n    <string name=\"verified\">Überprüft</string>\n    <plurals name=\"verified_with_warning\">\n        <item quantity=\"one\">Verifiziert mit %d Warnung</item>\n        <item quantity=\"other\">Verifiziert mit %d Warnungen</item>\n    </plurals>\n    <string name=\"input_keystore_alias_pass_description\">Geben Sie das Passwort für den Alias <b>%1$s</b> ein. Sie können dieses Feld leer lassen, wenn das Kennwort mit dem KeyStore-Kennwort übereinstimmt.</string>\n    <string name=\"input_keystore_alias_pass\">Passwort für den Alias <b>%1$s</b></string>\n    <string name=\"input_keystore_pass_msg\">Tippen Sie hier, um das KeyStore-Passwort einzugeben</string>\n    <string name=\"input_keystore_pass_description\">Geben Sie das Passwort für den App Manager KeyStore ein. Wenn Sie diese Aufforderung zum ersten Mal sehen, erzeugen Sie bitte zunächst mit einem Passwortgenerator ein Passwort und speichern Sie es an einem sicheren Ort, bevor Sie es hier einfügen.</string>\n    <string name=\"input_keystore_pass\">KeyStore-Passwort eingeben</string>\n    <plurals name=\"app_signing_signature_schemes_pl\">\n        <item quantity=\"one\">Signaturschema</item>\n        <item quantity=\"other\">Signaturschemata</item>\n    </plurals>\n    <string name=\"pref_backup_android_keystore\">Sichern von Apps mit Android KeyStore</string>\n    <string name=\"pref_backup_android_keystore_msg\">Nicht alle Apps funktionieren nach der Wiederherstellung. Die Wiederherstellung des KeyStore funktioniert auf den meisten Geräten nicht.</string>\n    <string name=\"keep_data_and_app_signing_signatures\">Daten und Signaturen aufbewahren</string>\n    <string name=\"this_action_cannot_be_undone\">Diese Aktion kann nicht rückgängig gemacht werden.</string>\n    <string name=\"no_app_ops_permission\">Keine Berechtigung zum Anzeigen von App-Ops</string>\n    <string name=\"set_app_op_mode\">App-Op-Modus einstellen</string>\n    <string name=\"magisk_hide_enabled\">MagiskHide</string>\n    <string name=\"set_custom_app_op\">Benutzerdefinierte App Op einstellen</string>\n    <string name=\"interceptor\">Lauschangriff</string>\n    <string name=\"resend_intent\">Absicht erneut senden</string>\n    <string name=\"share\">Teilen</string>\n    <string name=\"extras\">Extras</string>\n    <string name=\"category\">Kategorien</string>\n    <string name=\"uri\">URI</string>\n    <string name=\"mime_type\">MIME-Typ</string>\n    <string name=\"action\">Aktivität</string>\n    <string name=\"result_code\">Ergebniscode</string>\n    <string name=\"activity_result\">Ergebnis der Aktivität</string>\n    <string name=\"send_edited_intent\">Bearbeitete Absicht senden</string>\n    <string name=\"value\">Wert</string>\n    <string name=\"filter_apps_with_splits\">Mit Splits</string>\n    <string name=\"set_mode_for_app_ops_dots\">Modus für App Ops einstellen…</string>\n    <string name=\"security\">Sicherheit</string>\n    <string name=\"battery\">Akku</string>\n    <string name=\"graphics\">Grafik</string>\n    <string name=\"cpu\">CPU</string>\n    <string name=\"users\">Nutzer</string>\n    <string name=\"languages\">Sprachen</string>\n    <string name=\"battery_capacity\">Kapazität</string>\n    <string name=\"memory\">Speicher</string>\n    <string name=\"vendor\">Hersteller</string>\n    <string name=\"gles_version\">OpenGL ES Version</string>\n    <string name=\"no_of_cores\">Kerne</string>\n    <string name=\"support_architectures\">Unterstützte Architekturen</string>\n    <string name=\"security_providers\">Sicherheitsanbieter</string>\n    <string name=\"kernel\">Kernel</string>\n    <string name=\"manufacturer\">Hersteller</string>\n    <string name=\"board_name\">Karte</string>\n    <string name=\"model\">Modell</string>\n    <string name=\"brand_name\">Marke</string>\n    <plurals name=\"alert_failed_to_set_app_ops\">\n        <item quantity=\"one\">Konnte App-Ops für %1$d App nicht setzen</item>\n        <item quantity=\"other\">Konnte App-Ops für %1$d Apps nicht setzen</item>\n    </plurals>\n    <string name=\"pref_about_device_msg\">Grundlegende Geräteinformationen einschließlich Android-System, CPU, GPU, RAM, Akku usw.</string>\n    <string name=\"about_device\">Über das Gerät</string>\n    <string name=\"matching_activities\">Passende Aktivitäten</string>\n    <string name=\"patch_level\">Patch-Level</string>\n    <string name=\"backup_skip_signature_checks_description\">Wiederherstellen von Sicherungen, die entweder die Prüfsummenüberprüfung nicht bestehen oder andere APK-Signaturen haben als die vorherigen Sicherungen.</string>\n    <string name=\"backup_multiple_description\">Erzeugt ein separat <i> benanntes</i> Backup anstelle des Basis-Backups.</string>\n    <string name=\"backup_rules_description\">Im App Manager konfigurierte Regeln sichern.<font fgcolor=\"#ff0000\">Das Wiederherstellen ist je nach Berechtigungen u. U. nicht mit allen Regeln möglich.</font> </string>\n    <string name=\"backup_extras_description\">Sichert die App-Berechtigungen, Batteriespar- und Datennutzungsoptionen, MagiskHide-Status, SSAID usw.<font fgcolor=\"#ff0000\">Je nach Berechtigung können u. U. nicht alle Extras wiederhergegestellt werden.</font> </string>\n    <string name=\"backup_extras\">Extras</string>\n    <string name=\"backup_cache_description\">Die Ordner <b>cache</b>, <b>no_cache</b> und <b>no_backup</b> werden gesichert.</string>\n    <string name=\"backup_obb_media_description\">Sichert die OBB- und Medienordner.</string>\n    <string name=\"backup_external_data_description\">Sichert die externen Datenordner.</string>\n    <string name=\"backup_internal_data_description\">Sichert die Datenordner. Wenn diese Option ausgewählt ist, werden die internen Datenordner standardmäßig gesichert.</string>\n    <string name=\"backup_apk_files_description\">Sichert die APK-Dateien aus dem Quellverzeichnis. <b>Die Quelle</b> muss ausgewählt sein, damit dies funktioniert.</string>\n    <string name=\"backup_custom_users_description\">Backups nur für die angegebenen Benutzer durchführen</string>\n    <string name=\"backup_custom_users\">Benutzerdefinierte Nutzung</string>\n    <string name=\"bootloader\">Startprogramm</string>\n    <string name=\"encrypted\">Verschlüsselt</string>\n    <string name=\"unencrypted\">Unverschlüsselt</string>\n    <string name=\"no_volumes_found\">Es konnten keine Datenträger mit Schreibberechtigung gefunden werden.</string>\n    <string name=\"pref_backup_volume_msg\">Wählen Sie den Datenträger oder das Laufwerk aus, auf dem die Sicherungen gespeichert werden sollen.</string>\n    <string name=\"backup_volume\">Datenträger sichern</string>\n    <string name=\"pref_backup_restore_msg\">Anpassen von Sicherung/ Wiederherstellung.</string>\n    <string name=\"disable_background_run_description\">Setzt den <i>Ignore</i>-Modus für die folgenden App-Ops: <tt>RUN_IN_BACKGROUND</tt> (ab Android 7.0) und <tt>RUN_ANY_IN_BACKGROUND</tt> (ab Android 9).</string>\n    <string name=\"failed_to_enable_magisk_hide\">Konnte MagiskHide nicht aktivieren</string>\n    <string name=\"failed_to_disable_magisk_hide\">Konnte MagiskHide nicht deaktivieren</string>\n    <string name=\"window_size\">Fenstergröße</string>\n    <string name=\"refresh_rate\">Skalierungsfaktor</string>\n    <string name=\"scaling_factor\">Skalierungsfaktor</string>\n    <string name=\"size\">Größe</string>\n    <string name=\"density\">Dichte</string>\n    <string name=\"screen\">Bildschirm</string>\n    <string name=\"hardware\">Hardware</string>\n    <string name=\"permissive\">Zulässig</string>\n    <string name=\"enforcing\">Erzwingen</string>\n    <string name=\"selinux\">SELinux</string>\n    <plurals name=\"no_of_components\">\n        <item quantity=\"one\">%1$d Bestandteil</item>\n        <item quantity=\"other\">%1$d Bestandteile</item>\n    </plurals>\n    <string name=\"drm_free_apkm_msg\">Die APKM-Datei ist DRM-frei, sie muss nicht in APKS konvertiert werden.</string>\n    <string name=\"restore_msg\">Wiederherstellen der Apps mit Daten</string>\n    <string name=\"back_up\">Sicherung</string>\n    <string name=\"verify_and_redo_backups_msg\">Prüfen der Integrität der vorherigen Sicherungen und wiederholen der Sicherungen, bei denen die Integritätsprüfung fehlschlägt.</string>\n    <string name=\"verify_and_redo_backups\">Backups verifizieren und wiederherstellen</string>\n    <string name=\"backup_msg\">Sichern von Apps mit Daten</string>\n    <string name=\"restore_latest_msg\">Bereits installierte Apps wiederherstellen, deren Versionscode höher ist als der installierte Versionscode.</string>\n    <string name=\"restore_latest\">Letzte Backups wiederherstellen</string>\n    <string name=\"restore_not_installed_msg\">Basissicherung für Apps wiederherstellen, die derzeit nicht installiert sind.</string>\n    <string name=\"restore_not_installed\">Nicht installierte Apps wiederherstellen</string>\n    <string name=\"restore_all_msg\">Wiederherstellen des Basis-Backups von allen gesicherten Apps.</string>\n    <string name=\"restore_all\">Alle Apps wiederherstellen</string>\n    <string name=\"backup_apps_with_changes_msg\">Wiederholen der Sicherungen für Apps mit Änderungen seit der letzten Sicherung. Dazu gehören Änderungen in Größe, Version und des letztes Startzeitpunktes.</string>\n    <string name=\"backup_apps_with_changes\">Sichern von Apps mit Änderungen</string>\n    <string name=\"redo_existing_backups_msg\">Wiederholen der Backups für installierte Apps mit vorhergehenden Sicherungen.</string>\n    <string name=\"redo_existing_backups\">Vorhandene Sicherungen wiederherstellen</string>\n    <string name=\"backup_apps_without_backups_msg\">Sichern der Apps ohne vorherige Sicherungen.</string>\n    <string name=\"backup_apps_without_backups\">Sichern der Apps ohne der Sicherungen</string>\n    <string name=\"backup_all_apps_msg\">Sichern aller installierten Apps.</string>\n    <string name=\"backup_all_apps\">Sichern aller Apps</string>\n    <string name=\"list_options\">Optionen auflisten</string>\n    <string name=\"reverse\">Zurücksetzen</string>\n    <string name=\"os_version\">Version des Betriebssystems</string>\n    <string name=\"add\">Hinzufügen</string>\n    <string name=\"add_to_profile\">Zum Profil hinzufügen</string>\n    <string name=\"initializing\">Initialisieren…</string>\n    <string name=\"net_policy\">Netz-Richtlinie</string>\n    <string name=\"has_net_policy\">Netz-Richtlinie</string>\n    <string name=\"choose_what_to_do\">Wähle, was Du tun möchtest.</string>\n    <string name=\"enable_battery_optimization\">Akku-Optimierung einschalten\\?</string>\n    <string name=\"battery_optimization\">Akku-Optimierung</string>\n    <string name=\"no_battery_optimization\">Keine Akku-Optimierung</string>\n    <string name=\"screen_lock_msg\">App Manager mit Android-Bildschirmsperre sperren</string>\n    <string name=\"screen_lock\">Bildschirm sperren</string>\n    <string name=\"unlock_app_manager\">App-Manager freischalten</string>\n    <string name=\"sd_card\">SD-Karte</string>\n    <string name=\"external_storage\">Externer Speicher</string>\n    <string name=\"internal_storage\">Interner Speicher</string>\n    <string name=\"user_with_id\">Nutzer: <xliff:g id=\"user_id\" example=\"0\">%1$d</xliff:g></string>\n    <string name=\"type_float_array_list\">Liste der Dezimalzahlen</string>\n    <string name=\"type_float_array\">Array von Dezimalzahlen</string>\n    <string name=\"type_long_array_list\">Liste von langen Ganzzahlen</string>\n    <string name=\"type_long_array\">Array von langen Ganzzahlen</string>\n    <string name=\"type_string_array\">Array von Zeichenketten</string>\n    <string name=\"type_string_array_list\">Liste von Zeichenketten</string>\n    <string name=\"type_uri\">URI</string>\n    <string name=\"ssaid\">SSAID</string>\n    <string name=\"ssaid_info\">SSAID (<tt>Settings.Secure.ANDROID_ID</tt>) ist eine Gerätekennung, die jeder App (von Android 8 \\\"Oreo\\\" aufwärts) zugewiesen wird. Es wird häufig von Apps verwendet, um Benutzer zu verfolgen.</string>\n    <string name=\"type_int_array_list\">Liste der ganzen Zahlen</string>\n    <string name=\"type_int_array\">Array von Ganzzahlen</string>\n    <string name=\"type_component_name\">Komponentenname</string>\n    <string name=\"type_null\">Kein Wert</string>\n    <string name=\"restart_to_reflect_changes\">Sie müssen das Gerät sofort neu starten, um die neuen Änderungen zu verwenden.</string>\n    <string name=\"failed_to_change_ssaid\">Konnte SSAID nicht ändern</string>\n    <string name=\"copied_to_clipboard\">In die Zwischenablage kopiert.</string>\n    <string name=\"last_actions\">Letzte Aktionen</string>\n    <string name=\"pref_enable_disable_features_msg\">Aktivieren oder Deaktivieren von Funktionen im App-Manager.</string>\n    <string name=\"enable_disable_features\">Aktivieren/Deaktivieren von Funktionen</string>\n    <string name=\"installed_apps\">Installierte Apps</string>\n    <string name=\"screen_lock_not_enabled\">Bitte wählen Sie eine Bildschirmsperre in den Android-Einstellungen aus oder löschen Sie App-Daten.</string>\n    <string name=\"isolated\">Isoliert</string>\n    <string name=\"working_on_adb_mode\">Arbeiten im ADB-Modus</string>\n    <string name=\"input_app_ops_description_profile\">Geben Sie App-Op-Namen und/oder Konstanten mit Leerzeichen (z. B. <tt>WAKE_LOCK 63 72 CAMERA</tt> etc.) ein. Verwenden Sie <tt>*</tt> für alle konfigurierten App-Ops.</string>\n    <string name=\"filter_apps_without_backups\">Ohne Sicherung</string>\n    <string name=\"uninstalled_apps\">Deinstallierte Apps</string>\n    <string name=\"installer_app_message\">Wählen Sie <b>Wählen</b>, um aus den installierten Apps auszuwählen, oder wählen Sie <b>Benutzerdefiniert</b>, um einen eigenen Paketnamen anzugeben.</string>\n    <string name=\"specify_custom_name\">Benutzerdefiniert</string>\n    <string name=\"verified_using_unreliable_hash\">Verifiziert mit unzuverlässigem Hash</string>\n    <string name=\"internal_data\">Interne Daten</string>\n    <string name=\"pref_expanded_by_default_summary\">Zeigt standardmäßig den vollständigen Protokolltext an.</string>\n    <string name=\"pref_filter_pattern_title\">Kennzeichen herausfiltern</string>\n    <string name=\"pref_filter_pattern_summary\">Filtert die ausgewählten Kennzeichen aus den Protokollen heraus.</string>\n    <string name=\"pref_display_limit_title\">Protokollieren der Anzeigegrenze</string>\n    <string name=\"pref_display_limit_summary\">Zeigt nur die letzten %1$d Protokolle an, um Speicherplatzmangel zu vermeiden.</string>\n    <string name=\"pref_default_log_level_title\">Standard-Protokollstufe</string>\n    <string name=\"pref_default_log_level_summary\">Protokollierungsebene beim Start, beim Öffnen von Dateien und bei der Aufzeichnung.</string>\n    <string name=\"pref_cat_configuration\">Konfiguration</string>\n    <string name=\"pref_cat_appearance\">Erscheinungsbild</string>\n    <string name=\"pref_cat_advanced\">Erweitert</string>\n    <string name=\"pref_buffer_title\">Protokollpuffer</string>\n    <string name=\"open\">Öffnen</string>\n    <string name=\"notification_title\">Protokollierung lauft</string>\n    <string name=\"notification_ticker\">Protokollierung gestartet</string>\n    <string name=\"notification_subtext\">Berühren, um die Aufnahme zu stoppen</string>\n    <string name=\"no_saved_logs\">Keine gespeicherten Protokolle.</string>\n    <string name=\"manage_saved_logs\">Gespeicherte Protokolle verwalten</string>\n    <string name=\"filter_choice_tag\">Kennzeichnung</string>\n    <string name=\"log_cleared\">Protokolle gelöscht</string>\n    <string name=\"log_level\">Protokollstufe</string>\n    <string name=\"log_recording_started\">Protokollaufzeichnung gestartet.</string>\n    <string name=\"log_saved\">Protokoll gespeichert.</string>\n    <string name=\"filter_choice_pid\">PID</string>\n    <string name=\"filter_choice\">Suche nach</string>\n    <string name=\"enter_good_filename\">Bitte geben Sie einen gültigen Dateinamen ein.</string>\n    <string name=\"enter_filename\">Dateinamen eingeben</string>\n    <string name=\"dialog_compiling_log\">Log kompilieren…</string>\n    <string name=\"delete_saved_log\">Gespeicherte Protokolle löschen</string>\n    <string name=\"copy_to_clipboard\">In die Zwischenablage kopieren</string>\n    <plurals name=\"file_deletion_confirmation\">\n        <item quantity=\"one\">Die Datei %d wird gelöscht</item>\n        <item quantity=\"other\">Die Dateien %d werden gelöscht</item>\n    </plurals>\n    <string name=\"add_filter_ellipsis\">Filter hinzufügen…</string>\n    <string name=\"add_filter\">Filter hinzufügen</string>\n    <string name=\"log_level_fatal\">Schwerwiegend</string>\n    <string name=\"log_level_warn\">Warnung</string>\n    <string name=\"log_level_verbose\">Ausführlich</string>\n    <string name=\"log_level_info\">Info</string>\n    <string name=\"log_level_error\">Fehler</string>\n    <string name=\"log_level_debug\">Fehlersuche</string>\n    <string name=\"filename\">Dateiname</string>\n    <string name=\"restart_log_viewer_to_see_changes\">Starten Sie das Fenster des Log-Betrachters neu, um die Änderungen zu sehen.</string>\n    <string name=\"log_viewer\">Log-Betrachter</string>\n    <string name=\"pref_log_viewer_msg\">Konfigurieren Sie, wie Protokolle angezeigt werden.</string>\n    <string name=\"pref_installer_msg\">Konfigurieren Sie die Einstellungen für das App-Installationsprogramms.</string>\n    <string name=\"expiry_date_cannot_be_empty\">Das Verfallsdatum kann nicht leer sein.</string>\n    <string name=\"signing_key\">Signierschlüssel</string>\n    <string name=\"failed_to_read_keystore\">Konnte den KeyStore nicht lesen.</string>\n    <string name=\"alias_pass\">Alias-Passwort</string>\n    <string name=\"choose_an_alias\">Wählen Sie einen Alias</string>\n    <string name=\"found_no_alias_in_keystore\">Kein Alias im KeyStore gefunden!</string>\n    <string name=\"new_alias_password\">Neues Alias-Passwort</string>\n    <string name=\"import_key\">Schlüssel importieren</string>\n    <string name=\"pem_file\">PEM Datei</string>\n    <string name=\"pk8_file\">PKCS #8 (PK8) Datei</string>\n    <string name=\"pem_and_pk8\">PEM und PKCS #8 (PK8)</string>\n    <string name=\"pkcs12_keystore\">PKCS #12 Schlüsselspeicher (P12)</string>\n    <string name=\"bouncy_castle_keystore\">Bouncy Castle Schlüsselspeicher (BKS)</string>\n    <string name=\"java_keystore\">Java-Schlüsselspeicher (JKS)</string>\n    <string name=\"keystore_pass\">KeyStore-Passwort</string>\n    <string name=\"keystore_file\">KeyStore-Datei</string>\n    <string name=\"country_name\" tools:ignore=\"TypographyOther\">Name des Landes</string>\n    <string name=\"state_name\">Name des Staates (ST)</string>\n    <string name=\"locality_name\">Ortsname (Stadt)</string>\n    <string name=\"organization_name\">Name der Organisation</string>\n    <string name=\"organization_unit\">Organisationseinheit</string>\n    <string name=\"common_name\">Gebräuchliche Bezeichnung (CN)</string>\n    <string name=\"input_key_password\">Schlüssel-Passwort</string>\n    <string name=\"failed_to_load_key\">Der Schlüssel konnte nicht geladen werden.</string>\n    <string name=\"key_not_set\">Nicht angegeben.</string>\n    <string name=\"use_default\">Standard verwenden</string>\n    <string name=\"invalid_rsa_key_size\">Ungültige Schlüsselgröße für die RSA-Verschlüsselung. Die Schlüsselgröße kann 1024, 2048 oder 4096 Bit betragen.</string>\n    <string name=\"crypto_key_size\">Schlüsselgröße</string>\n    <string name=\"invalid_aes_key_size\">Ungültige Schlüsselgröße für die AES-Verschlüsselung. Die Schlüsselgröße kann entweder 128 oder 256 Bit betragen.</string>\n    <string name=\"failed_to_initialize_key_store\">Der App Manager Keystore konnte nicht initialisiert werden.</string>\n    <string name=\"failed_to_save_key\">Der Schlüssel konnte nicht gespeichert werden.</string>\n    <string name=\"generate_key\">Erzeugen</string>\n    <string name=\"input_key\">Eingabeschlüssel (in hexadezimaler Form)</string>\n    <string name=\"input_keystore_alias_pass_msg\">Tippen Sie hier, um das Passwort für %1$s anzugeben</string>\n    <string name=\"source_code_links\"><a href=\"https://github.com/MuntashirAkon/AppManager\">GitHub</a> • <a href=\"https://gitlab.com/muntashir/AppManager\">GitLab</a> •<a href=\"https://0xacab.org/muntashir/AppManager\">Riseup</a> • <a href=\"https://codeberg.org/muntashir/AppManager\">Codeberg</a></string>\n    <string name=\"app_signing_signatures\">Signaturen</string>\n    <string name=\"orientation_right_to_left\">Von Rechts nach Links</string>\n    <string name=\"orientation_left_to_right\">Von links nach rechts</string>\n    <string name=\"orientation_follow_locale\">Lokale folgen</string>\n    <string name=\"saf\">SAF</string>\n    <string name=\"pref_rules_msg\">Sofortiges Sperren, Importieren/Exportieren/Entfernen von Regeln, etc.</string>\n    <string name=\"failed\">Fehlgeschlagen</string>\n    <string name=\"confirm_import_keystore\">Sind Sie sicher, dass Sie den bestehenden Schlüsselspeicher ersetzen wollen? Diese Aktion kann nicht rückgängig gemacht werden.</string>\n    <string name=\"import_keystore\">Importieren des Schlüsselspeichers</string>\n    <string name=\"pref_import_export_keystore_msg\">Importiert/exportiert den Bouncy Castle KeyStore (BKS), der intern vom App Manager verwendet wird.</string>\n    <string name=\"pref_import_export_keystore\">Importieren/Exportieren des Schlüsselspeichers</string>\n    <string name=\"latest_backup\">Letztes Backup</string>\n    <string name=\"gz_bz2_compressed\">%1$s komprimiert</string>\n    <string name=\"pgp_aes_rsa_encrypted\">%1$s entschlüsselt</string>\n    <string name=\"no_encryption\">Keine Verschlüsselung</string>\n    <string name=\"base_backup\">Basis sichern</string>\n    <string name=\"trackers_unblocked_successfully\">Tracker sind nun entblockt</string>\n    <string name=\"trackers_blocked_successfully\">Tracker sind nun geblockt</string>\n    <string name=\"failed_to_unblock_trackers\">Konnte Tracker nicht entblocken</string>\n    <string name=\"failed_to_block_trackers\">Konnte Tracker nicht blockieren</string>\n    <string name=\"profile_save_apk_msg\">Speichert APK-Dateien in <tt>AppManager/apks</tt></string>\n    <string name=\"save_apk\">APK-Datei speichern</string>\n    <string name=\"running_services\">Aktive Dienste</string>\n    <string name=\"view_logs\">Protokolle anzeigen</string>\n    <string name=\"share_log\">Teilen</string>\n    <string name=\"text_include_dmesg\">Kernel-Log mit einschließen</string>\n    <string name=\"omit_sensitive_info_summary\">Sensible Informationen wie Web-URLs, Telefonnummern oder E-Mails auslassen.</string>\n    <string name=\"omit_sensitive_info\">Sensible Informationen auslassen</string>\n    <string name=\"undo\">Rückgängig machen</string>\n    <string name=\"pause_unpause\">Abspielen/Pause</string>\n    <string name=\"collapse_all\">Alles einklappen</string>\n    <string name=\"expand_all\">Alles aufklappen</string>\n    <string name=\"file\">Datei</string>\n    <string name=\"widget_start_recording\">Aufzeichen\n\\nProtokoll</string>\n    <string name=\"widget_recording_in_progress\">Zeichne auf…</string>\n    <string name=\"unable_to_save_log\">Kann Protokoll nicht speichern. Haben Sie einen gültigen Dateinamen eingegeben\\?</string>\n    <plurals name=\"toast_log_truncated\">\n        <item quantity=\"one\">Protokoll zu groß, zeige letzte %d Zeile.</item>\n        <item quantity=\"other\">Protokoll zu groß, zeige die letzten %d Zeilen.</item>\n    </plurals>\n    <string name=\"toast_invalid_selection\">Ungültige Auswahl. Bitte nochmals versuchen.</string>\n    <string name=\"toast_invalid_level\">Ungültiger Level-Name: %s</string>\n    <string name=\"pref_display_limit_hint\">Bitte eine gültige Zahl zwischen %1$d und %2$d eingeben.</string>\n    <string name=\"text_include_device_info\">Geräteinformationen mit einschließen</string>\n    <string name=\"text_filter_text\">Text filtern</string>\n    <string name=\"text_filter_ellipsis\">Filter…</string>\n    <string name=\"pref_log_write_period_title\">Zeitraum beschreiben</string>\n    <string name=\"pref_log_write_period_summary\">Bei der Aufzeichnung wird jede %1$d Zeile auf die SD-Karte geschrieben.</string>\n    <string name=\"suspended\">Angehalten</string>\n    <string name=\"subject_log_report\">Protokollbericht erstellen</string>\n    <string name=\"start_recording_log\">Aufzeichnen</string>\n    <string name=\"settings\">Einstellungen</string>\n    <string name=\"send_log_title\">Protokoll senden</string>\n    <string name=\"save_log\">Protokoll speichern</string>\n    <string name=\"save_as\">Speichern als…</string>\n    <string name=\"record_log\">Protokoll aufzeichnen</string>\n    <string name=\"pref_show_timestamp_title\">Zeige Pid &amp; Zeitstempel</string>\n    <string name=\"pref_show_timestamp_summary\">Zeige Prozess-ID und Zeitstempel wenn aufgeklappt.</string>\n    <string name=\"pref_log_line_period_error\">Bitte geben Sie eine ganze Zahl zwischen 1 und 1000 ein.</string>\n    <string name=\"pref_expanded_by_default_title\">Standardmäßig aufklappen</string>\n    <string name=\"hidden\">Versteckt</string>\n    <string name=\"no_changes\">Keine Änderungen</string>\n    <string name=\"pref_display_changes_msg\">Änderungen in Version, Tracker, Komponenten, Berechtigungen, Signaturen, SDK usw. versionskontrolliert anzeigen.</string>\n    <string name=\"pref_display_changes\">Änderungen anzeigen</string>\n    <string name=\"netpolicy_disable_network_access\">Netzwerkzugang deaktivieren</string>\n    <string name=\"netpolicy_reject_wifi_data\">Wi-Fi-Daten zurückweisen</string>\n    <string name=\"netpolicy_reject_vpn_data\">VPN-Daten verwerfen</string>\n    <string name=\"netpolicy_reject_cellular_data\">Mobilfunkdaten ablehnen</string>\n    <string name=\"netpolicy_allow_background_data\">Hintergrunddaten zulassen, wenn der Datensparer eingeschaltet ist</string>\n    <string name=\"netpolicy_reject_background_data\">Hintergrunddaten verwerfen</string>\n    <string name=\"port_number_invalid\">Ungültige Portnummer.</string>\n    <string name=\"port_number_empty\">Die Portnummer ist leer.</string>\n    <string name=\"adb_connect_port_number_description\">Die Portnummer befindet sich unter dem <b>IP-Adresse &amp; Port</b>-Abschnitt direkt unter dem Abschnitt <b>Gerätenamen</b>.</string>\n    <string name=\"port_number\">Port</string>\n    <string name=\"adb_connect\">Anschließen</string>\n    <string name=\"wireless_debugging\">Fehlersuche über WLAN</string>\n    <string name=\"unknown_net_policy\">Unbekannte Netz-Richtlinie (%1$s - %2$X)</string>\n    <string name=\"failed_to_prevent_background_run\">Konnte nicht verhindern, dass %1$s im Hintergrund läuft</string>\n    <string name=\"community\">Gemeinschaft</string>\n    <string name=\"community_links\"><a href=\"https://matrix.to/#/#appmanager:matrix.org\">Matrix</a> • <a href=\"https://t.me/AppManagerChannel\">Telegram</a> • <a href=\"https://twitter.com/AppManagerNews\">Twitter</a></string>\n    <plurals name=\"alert_failed_to_import_backups\">\n        <item quantity=\"one\">Konnte %1$d Sicherung nicht importieren</item>\n        <item quantity=\"other\">Konnte %1$d Sicherung en nicht importieren</item>\n    </plurals>\n    <string name=\"import_from_tb\">Importieren aus Titanium Backup</string>\n    <string name=\"import_from_oab\">Importieren von OAndBackup</string>\n    <string name=\"pref_import_backups_msg\">Importieren von Sicherungen aus OAndBackup, Swift Backup (3.0–3.2) oder Titanium Backup.</string>\n    <string name=\"pref_import_backups\">Sicherungen importieren</string>\n    <string name=\"added_to_queue\">Zur Warteschlange hinzugefügt</string>\n    <string name=\"minimum_version\">Minimale Version: %d</string>\n    <string name=\"help_uses_permissions_tab\">Klicken Sie auf eine Berechtigung, um sie <b>zu gewähren</b> oder <b>zu entziehen</b>. Nur <b>gefährliche</b> und <b>Entwicklungs-</b>Berechtigungen können gewährt oder entzogen werden.</string>\n    <string name=\"help_permissions_tab\">Diese Berechtigungen werden von dieser App festgelegt und können nicht widerrufen werden.</string>\n    <string name=\"help_app_ops_tab\">Tippen Sie auf ein Element, um es <b>zuzulassen</b> oder <b>zu ignorieren</b>. Für weitere mögliche Modi halten Sie ein Element gedrückt.</string>\n    <string name=\"error_with_details\">Fehler: %s</string>\n    <string name=\"saved_filters\">Gespeicherte Filter</string>\n    <string name=\"permission_flags\">Berechtigungskennzeichen</string>\n    <string name=\"pref_selected_users_msg\">Beschränken des App Manager auf die ausgewählten Benutzer.</string>\n    <string name=\"pref_selected_users\">Ausgewählte Nutzer</string>\n    <string name=\"files\">Dateien</string>\n    <string name=\"storage\">Speicher</string>\n    <string name=\"notice_saf\">Im Gegensatz zu den Laufwerken wird das ausgewählte Verzeichnis zum Speichern aller mit dem App Manager verbundenen Dateien verwendet, einschließlich gespeicherter APKs und Backups. Das Storage Access Framework (SAF) ist sehr langsam, daher sollte diese Option nur verwendet werden, wenn keine andere zur Verfügung steht.</string>\n    <string name=\"notice\">Benachrichtigung</string>\n    <string name=\"paired_successfully\">Gekoppelt.</string>\n    <string name=\"adb_pair\">Paar</string>\n    <string name=\"invalid_password\">Ungültiges Passwort, versuchen Sie es erneut.</string>\n    <string name=\"keystore_pass_cannot_be_empty\">Das KeyStore-Passwort darf nicht leer sein.</string>\n    <string name=\"keystore_password_info\">Nachfolgend finden Sie das Passwort für den App Manager KeyStore. Bitte bewahren Sie es an einem sicheren Ort auf, wenn Sie den App Manager KeyStore sichern/ wiederherstellen möchten. <b>Diese Meldung wird nicht noch einmal angezeigt.</b></string>\n    <string name=\"running_services_logcat_hint\">Klicken Sie auf ein Element, um die Protokollanzeige mit der entsprechenden Prozess-ID als Standardfilter zu öffnen.</string>\n    <string name=\"pid\">Prozess-ID</string>\n    <plurals name=\"pref_thread_count_msg\">\n        <item quantity=\"one\">Höchstens %1$d Operation parallel ausführen</item>\n        <item quantity=\"other\">Höchstens %1$d Operationen parallel ausführen</item>\n    </plurals>\n    <string name=\"pref_thread_count_hint\">Der Wert muss zwischen 0 und %1$d liegen, wobei 0 die <i>maximale Anzahl von Operationen zum gegebenen Zeitpunkt</i> bedeutet.</string>\n    <string name=\"pref_thread_count\">Parallele Ausführung</string>\n    <string name=\"type_uri_array_list\">Liste der URIs</string>\n    <string name=\"type_uri_array\">Array von URIs</string>\n    <string name=\"pref_always_on_background_msg\">Installiert Anwendungen immer im Hintergrund. Eine Benachrichtigung zeigt an, wenn die Installation fertig ist.</string>\n    <string name=\"pref_always_on_background\">Installieren im Hintergrund</string>\n    <string name=\"pref_block_trackers_msg\">Blockiert nach der Installation einer App mit dem App-Manager deren Tracking-Komponenten.</string>\n    <string name=\"next\">Nächster</string>\n    <string name=\"installer_app_installed\">App ist installiert</string>\n    <string name=\"staging_apk_files\">Ausführen…</string>\n    <string name=\"background\">Hintergrund</string>\n    <string name=\"trim_caches_in_all_apps_description\">Löscht Cache-Dateien von allen Anwendungen, einschließlich des Android-Systems</string>\n    <string name=\"trim_caches_in_all_apps\">Caches in allen Anwendungen reduzieren</string>\n    <string name=\"user_root\">Root verwenden</string>\n    <string name=\"paste\">Einfügen</string>\n    <string name=\"set_package_name_first\">Legen Sie zuerst den Paketnamen fest!</string>\n    <string name=\"identifier\">Kennung</string>\n    <string name=\"backup_volume_dialog_description\">Laufwerke mit dem Präfix <tt>/Baum</tt> sind Ordner, die mit dem Storage Access Framework (SAF) ausgewählt werden. Außer diesen Ordnern ist das Standardverzeichnis für App Manager ein Unterordner namens <tt>AppManager</tt>.</string>\n    <string name=\"second_degree_tracker_note\">² Das Präfix zeigt an, dass die Tracker in der <a href=\"https://etip.exodus-privacy.eu.org/\">ETIP-Bereitschaftsliste</a> stehen, d. h. es wird noch untersucht, ob es sich tatsächlich um Tracker handelt.</string>\n    <string name=\"failed_to_uninstall_app\">Deinstallation fehlgeschlagen</string>\n    <string name=\"java\">Java</string>\n    <string name=\"smali\">Smali</string>\n    <string name=\"accessibility_service_description\">Allgemeiner Zugriffsdienst zur Durchführung bestimmter Vorgänge wie dem Löschen des Cache im No-Root-Modus.</string>\n    <string name=\"explore\">Erkunden Sie</string>\n    <string name=\"system_partition\">Android root</string>\n    <string name=\"exit_confirmation\">Bestätigung der Beendigung</string>\n    <string name=\"extract\">Auszug</string>\n    <string name=\"replace\">Ersetzen</string>\n    <string name=\"rename\">Umbenennen</string>\n    <string name=\"import_from_sb\">Importieren aus Swift Backup 3.0 - 3.2</string>\n    <string name=\"pref_import_backups_hint\">Wählen Sie ein Verzeichnis, das die Sicherungsdateien (Swift Backup/Titanium Backup) oder Verzeichnisse (OAndBackup) enthält</string>\n    <string name=\"intent_firewall_and_disable\">IFW + deaktivieren</string>\n    <string name=\"intent_firewall\">IFW</string>\n    <string name=\"pref_default_blocking_method_description\">Methode, die standardmäßig verwendet wird, wenn es keine Möglichkeit gibt, eine Blockierungsmethode auszuwählen.</string>\n    <string name=\"pref_default_blocking_method\">Standard-Blockierungsmethode</string>\n    <string name=\"pref_disable_description\">Nur Komponenten deaktivieren. Nicht empfohlen für Root-Benutzer, da die Apps dies umgehen können. In ADB-Modi können die reinen Testanwendungen mit dieser Methode deaktiviert werden.</string>\n    <string name=\"authenticating\">Authentifizierung…</string>\n    <string name=\"search_type_contains\">Enthält</string>\n    <string name=\"search_type_suffix\">Suffix</string>\n    <string name=\"search_type_prefix\">Prefix</string>\n    <string name=\"search_type_regular_expressions\">Regulärer Ausdruck</string>\n    <string name=\"pref_intent_firewall_and_disable_description\">Komponenten per Intent Firewall blockieren und deaktivieren. Empfohlene Methode für Root-Benutzer.</string>\n    <string name=\"pref_intent_firewall_description\">Komponenten nur mit Intent Firewall blockieren. Nicht empfohlen, da einige Systemanwendungen Firewalls umgehen können.</string>\n    <plurals name=\"usage_seconds\">\n        <item quantity=\"one\">%1$d Sekunde</item>\n        <item quantity=\"other\">%1$d Sekunden</item>\n    </plurals>\n    <string name=\"vt_checking\">VirusTotal: Überprüft…</string>\n    <string name=\"vt_uploading\">VirusTotal: Hochladen…</string>\n    <string name=\"vt_failed\">VirusTotal: Fehlgeschlagen</string>\n    <string name=\"vt_success\">VirusTotal: %1$d/%2$d</string>\n    <string name=\"vt_scan_date\">Datum des Scans: %1$s</string>\n    <string name=\"vt_slowness_warning\">Je nach Internetgeschwindigkeit und Auslastung des Servers kann dies eine Weile dauern.</string>\n    <string name=\"pref_vt_apikey_summary\">Aktiviert das Scannen von APK-Dateien über VirusTotal.</string>\n    <string name=\"uses_play_app_signing\">Play App-Signatur</string>\n    <string name=\"scan_in_vt\">In VirusTotal scannen</string>\n    <string name=\"parent_process_id\">Übergeordnete Prozess ID</string>\n    <string name=\"priority\">Priorität</string>\n    <string name=\"threads\">Thread Zähler</string>\n    <string name=\"state\">Prozess-Status</string>\n    <string name=\"swap_chart_info\">● %1$s benutzt ● %2$s frei</string>\n    <string name=\"memory_chart_info\">● %1$s Anwendungen ● %2$s Cached ● %3$s Puffer ● %4$s frei</string>\n    <string name=\"magisk_denylist\">Magisk DenyList</string>\n    <string name=\"vt_permalink\">Dauerhafter Link zu VirusTotal</string>\n    <plurals name=\"usage_minutes\">\n        <item quantity=\"one\">%1$d Minute</item>\n        <item quantity=\"other\">%1$d Minuten</item>\n    </plurals>\n    <string name=\"vt_queued\">VirusTotal: Eingereiht</string>\n    <string name=\"pref_vt_apikey_description\">Mit einem API-Schlüssel kann App Manager APK-Dateien zu VirusTotal hochladen und Berichte abrufen. Melden Sie sich unter https://virustotal.com an, um einen kostenlosen API-Schlüssel zu erhalten.</string>\n    <string name=\"toggle_internet\">Nutze das Internet</string>\n    <string name=\"vt_disclaimer\">VirusTotal und seine Logos sind eine Marke von Chronicle LLC. Weder App Manager - der API-Client - noch seine Autoren sind für Daten verantwortlich, die Sie an VirusTotal senden.</string>\n    <string name=\"pref_vt_apikey\">VirusTotal API-Schlüssel</string>\n    <string name=\"uses_play_app_signing_description\">Diese App enthält bestimmte Markierungen, die darauf hinweisen, dass sie <i>möglicherweise</i> die <a href=\"https://support.google.com/googleplay/android-developer/answer/9842756\">Play-App-Signatur</a> verwendet. Bei diesem Schema werden die Signierschlüssel auf den Servern von Google gespeichert und Google ist für das Signieren der App verantwortlich. Beachten Sie, dass übereinstimmende Signaturinformationen die einzige Möglichkeit sind, um zu überprüfen, ob die App von einer anderen Person als dem Entwickler (und in diesem Fall auch von Google) geändert wurde.</string>\n    <string name=\"process_id\">Prozess ID</string>\n    <string name=\"virtual_memory\">Virtueller Speicher</string>\n    <string name=\"cpu_percent\">%% CPU</string>\n    <string name=\"swap\">Swap</string>\n    <string name=\"cpu_time\">CPU-Zeit</string>\n    <string name=\"commandline_args\">Kommandozeilen-Argumente</string>\n    <string name=\"failed_to_change_app_op_mode\">Der Betriebsmodus der App konnte nicht geändert werden.</string>\n    <string name=\"failed_to_use_the_current_mode_of_operation\">Der aktuelle Betriebsmodus kann nicht verwendet werden. Rückkehr zum no-root Modus für diese Sitzung.</string>\n    <string name=\"warning_working_on_root_mode\">Warnung: Arbeiten im Root- statt im ADB-Modus.</string>\n    <string name=\"failed_to_enable_magisk_deny_list\">Magisk DenyList konnte nicht aktiviert werden</string>\n    <string name=\"failed_to_disable_magisk_deny_list\">Magisk DenyList konnte nicht deaktiviert werden</string>\n    <string name=\"mode_of_op_with_inferred_mode_of_op\">%1$s (Abgeleiteter Modus: %2$s)</string>\n    <string name=\"hidden_api_enf_policy_none\">Kein (Vollzugriff auf die versteckte API)</string>\n    <string name=\"primary_abi\">Primäre ABI</string>\n    <string name=\"zygote_preload_name\">Name der Zygote vor dem Laden</string>\n    <string name=\"hidden_api_enforcement_policy\">Versteckte API-Durchsetzungsrichtlinie</string>\n    <string name=\"hidden_api_enf_policy_black\">Erzwingen (nur schwarze Listen)</string>\n    <string name=\"binary_32_bit\">32 Bit</string>\n    <string name=\"binary_64_bit\">64 Bit</string>\n    <string name=\"endianness_big_endian\">Big endian</string>\n    <string name=\"so_type_shared_library\">Gemeinsam genutzte Bibliothek</string>\n    <string name=\"so_type_executable\">Ausführbar</string>\n    <string name=\"save_and_exit\">Speichern und schließen</string>\n    <string name=\"hidden_api_enf_default_policy\">Standard (je nach Anwendungstyp)</string>\n    <string name=\"hidden_api_enf_policy_dark_grey_and_black\">Erzwingen (dunkelgraue und schwarze Listen)</string>\n    <string name=\"endianness_little_endian\">Little endian</string>\n    <string name=\"file_modified_are_you_sure\">Die Datei wurde geändert. Möchten Sie die Bearbeitung beenden und alle Ihre Änderungen verwerfen?</string>\n    <string name=\"hidden_api_enf_policy_warn\">Warnen (voller Zugriff auf die versteckte API, gibt aber Warnungen aus)</string>\n    <string name=\"pref_saved_apk_name_format\">Namensformat des gespeicherten APK</string>\n    <string name=\"pref_saved_apk_name_format_msg\">Das Format, das für die Benennung der APK-Dateien beim Speichern verwendet werden soll.</string>\n    <string name=\"auth_manager_description\">Um ein Intent von einer externen Anwendung aus zu starten, muss ein zusätzliches Feld mit der Bezeichnung <tt>auth</tt> bereitgestellt werden, das den folgenden Schlüssel enthalten muss:</string>\n    <string name=\"auth_manager_title\">Autorisierungsverwalter</string>\n    <string name=\"regenerate_auth_key\">Autorisierungsschlüssel neu erzeugen</string>\n    <string name=\"regenerate_auth_key_warning\">Sind Sie sicher\\? Alle Anwendungen von Drittanbietern müssen mit dem neuen Autorisierungsschlüssel neu konfiguriert werden.</string>\n    <string name=\"shortcut_icon\">Tastaturkürzel</string>\n    <string name=\"change_backup_volume\">Medium wechseln</string>\n    <string name=\"external\">Extern</string>\n    <string name=\"internal\">Intern</string>\n    <string name=\"tracker\">Tracker</string>\n    <string name=\"input_ssaid_instruction\">SSAID ist eine %1$d-Byte-Hexadezimalzahl, d.h. eine Zeichenkette der Länge %2$d mit 0 bis 9 und a bis f.</string>\n    <string name=\"screen_time\">Zeit am Bildschirm</string>\n    <string name=\"backup_volume_unavailable_warning\">Das ausgewählte Sicherungsmedium ist derzeit nicht verfügbar. Wenn es sich auf einem externen Speicher befindet, legen Sie diesen bitte ein oder wählen Sie ein anderes Sicherungsmedium.</string>\n    <string name=\"sort_by_installation_date\">Installationsdatum</string>\n    <string name=\"pref_vt_prompt_before_uploading\">Eingabeaufforderung vor dem Hochladen einer Datei anzeigen.</string>\n    <string name=\"vt_confirm_uploading_file\">Die Datei wurde nicht in der VirusTotal-Datenbank gefunden. Möchten Sie sie hochladen\\?</string>\n    <string name=\"vt_confirm_upload_and_scan\">Ja, hochladen und scannen</string>\n    <string name=\"open_in_new_window\">Neues Fenster</string>\n    <string name=\"type_string_set\">Satz von Zeichenfolgen</string>\n    <string name=\"item_select\">Auswählen</string>\n    <string name=\"log_stop_recording\">Aufnahme stoppen</string>\n    <string name=\"apk_checksums\">APK Prüfsumme</string>\n    <string name=\"app_explorer\">AppExplorer</string>\n    <string name=\"netpolicy_cannot_be_modified_for_core_apps\">Die Netz-Richtlinie kann für Android-Kernanwendungen nicht geändert werden.</string>\n    <string name=\"pref_pure_black_theme\">Rein schwarzes Thema</string>\n    <string name=\"open_developer_options_page\">Öffnen Sie die Seite mit den Entwickleroptionen in den Android-Einstellungen</string>\n    <string name=\"pref_pure_black_theme_msg\">Verwendet einen komplett schwarzen Hintergrund, wenn der Nachtmodus aktiviert ist.</string>\n    <string name=\"usage_wifi_data\">Wi-Fi-Daten</string>\n    <string name=\"usage_mobile_data\">Mobile Daten</string>\n    <string name=\"usage_times_opened\">Geöffnete Zeiten</string>\n    <string name=\"usage_last_used\">Zuletzt benutzt</string>\n    <string name=\"frozen\">Eingefroren</string>\n    <string name=\"freeze\">einfrieren</string>\n    <string name=\"unfreeze\">auftauen</string>\n    <string name=\"backup_no_backups_present\">Keine backups.</string>\n    <string name=\"restore_dots\">wiederherstellen…</string>\n    <string name=\"backup_apps_cannot_be_restored\">Die folgenden Apps können nicht wiederhergestellt werden, da sie über kein Basis-Backup verfügen:</string>\n    <string name=\"backup_apps_cannot_be_backed_up\">Die folgenden Apps sind nicht installiert und können nicht gesichert werden:</string>\n    <string name=\"restart_device\">Gerät neustarten</string>\n    <string name=\"import_backups_warning_delete_backups_after_import\">Backups löschen, nachdem sie in App Manager importiert wurden\\? Jedes Backup wird nach erfolgreichem Import einzeln gelöscht. Wählen Sie <b>Nein</b>, wenn Sie sich nicht sicher sind.</string>\n    <string name=\"pref_reload_apps_msg\">Bei unerwartetem Verhalten aktualisieren Sie hier die Liste der in der App-Manager-Datenbank gespeicherten Anwendungen.</string>\n    <string name=\"changelog_type_fix\">Lösung</string>\n    <string name=\"troubleshooting\">Fehlerbehebung</string>\n    <string name=\"pref_reload_apps\">Apps neu laden</string>\n    <string name=\"changelog_type_new\">Neu</string>\n    <string name=\"changelog_type_improve\">Verbessern</string>\n    <string name=\"unsupported_split_apk\">Nicht unterstützt</string>\n    <string name=\"view_changelog\">Erfahren Sie, was in dieser Version neu ist</string>\n    <string name=\"pref_sign_apk_no_signing_key\">Kein Signaturschlüssel</string>\n    <string name=\"sort_by_total_size\">Gesamtgröße</string>\n    <string name=\"am_command\"><tt>am</tt> Befehl</string>\n    <string name=\"pref_sign_apk_error_signing_key_not_added\">Zum Signieren einer APK-Datei ist ein gültiger Signaturschlüssel erforderlich.</string>\n    <string name=\"hide_app\">Verbergen</string>\n    <string name=\"pref_appearance_description\">Thema, Ausrichtung, Funktionen, usw.</string>\n    <string name=\"pref_version_changelog\">Version/Änderungsprotokoll</string>\n    <plurals name=\"alert_failed_to_unfreeze\">\n        <item quantity=\"one\">Konnte die Anwendung %1$d nicht freigeben</item>\n        <item quantity=\"other\">Konnte %1$d Anwendungen nicht freigeben</item>\n    </plurals>\n    <string name=\"sort_by_frozen_app\">Eingefrorenes zuerst</string>\n    <string name=\"pref_privacy_description\">Bildschirmsperre, Autorisierung usw.</string>\n    <string name=\"user_manual\">Benutzerhandbuch</string>\n    <string name=\"get_help\">Hilfe erhalten</string>\n    <string name=\"pref_advanced_pref\">Benutzer, APK-Namensformat, parallele Ausführung, usw.</string>\n    <string name=\"pref_default_freezing_method\">Standardmethode zum Einfrieren</string>\n    <string name=\"suspend_app\">Aussetzen</string>\n    <string name=\"failed_to_freeze\">Konnte <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g> nicht einfrieren.</string>\n    <string name=\"freeze_unfreeze\">Einfrieren/Freigeben</string>\n    <plurals name=\"alert_failed_to_freeze\">\n        <item quantity=\"one\">Konnte %1$d Anwendung nicht einfrieren</item>\n        <item quantity=\"other\">Konnte %1$d Anwendungen nicht einfrieren</item>\n    </plurals>\n    <string name=\"filter_frozen_apps\">Eingefrorene Apps</string>\n    <string name=\"failed_to_unfreeze\">Konnte nicht <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g> freigeben.</string>\n    <string name=\"pref_default_freezing_method_description\">Methode, die standardmäßig an Stellen verwendet wird, an denen keine Option zur Auswahl einer Einfriermethode vorhanden ist.</string>\n    <string name=\"profile_freeze_msg\">Friert Anwendungen je nach Status ein oder gibt sie frei</string>\n    <string name=\"suspend_app_description\">Dies ist die schwächste Methode des Einfrierens. Eine angehaltene App kann immer noch im Launcher angezeigt werden, ist aber ausgegraut und kann nicht gestartet werden.</string>\n    <string name=\"hide_app_description\">Diese Methode wird nur für den alltäglichen Gebrauch empfohlen. Eine ausgeblendete App erscheint, als wäre sie deinstalliert. Die App kann jedoch wieder erscheinen, wenn sie neu installiert oder aktualisiert wird.</string>\n    <string name=\"disable_app_description\">Empfohlene Methode zum Einfrieren. Es deaktiviert die App und alle ihre Komponenten, aber alle Verknüpfungen gehen verloren.</string>\n    <string name=\"pref_privacy\">Privatsphäre</string>\n    <string name=\"confirm_file_deletion\">Ja, löschen</string>\n    <string name=\"file_properties\">Eigenschaften</string>\n    <string name=\"open_as_image\">Bild</string>\n    <string name=\"fm_open_with_for_this_file_only\">Nur für diese Datei</string>\n    <string name=\"file_open_with_os_default_dialog\">Öffnen mit BS-Standarddialog</string>\n    <string name=\"open_as_text\">Text</string>\n    <string name=\"open_as_video\">Video</string>\n    <string name=\"fm_always_open_with\">Immer öffnen</string>\n    <string name=\"open_as_archive\">Archiv</string>\n    <string name=\"file_creation_date\">Erstellt</string>\n    <string name=\"file_modification_date\">Geändert</string>\n    <string name=\"file_accessed_date\">Zugegriffen</string>\n    <string name=\"file_open_with\">Öffnen mit</string>\n    <string name=\"file_shortcut_target_file\">Zieldatei</string>\n    <string name=\"file_cut\">Ausschneiden</string>\n    <string name=\"file_open_as\">Öffnen als…</string>\n    <string name=\"open_as_folder\">Ordner</string>\n    <string name=\"open_as_other\">Andere</string>\n    <string name=\"delete_filename\">%s löschen</string>\n    <string name=\"action_stop_service\">Stopp</string>\n    <string name=\"freeze_on_phone_locked\">App automatisch einfrieren, wenn das Telefon gesperrt ist</string>\n    <string name=\"file_open_with_custom_activity\">Benutzerdefiniert</string>\n    <string name=\"on_unfreeze_open_application\">App nach dem Auftauen öffnen</string>\n    <string name=\"on_open_application_no_recents\">Gestartete App nicht in „Letzte“ anzeigen</string>\n    <string name=\"tap_to_freeze_app\">Antippen zum Einfrieren</string>\n    <string name=\"waiting_for_the_phone_to_be_locked\">Warten, bis das Telefon gesperrt wird …</string>\n    <string name=\"file_change_open_with\">Wechseln zu öffnen mit</string>\n    <string name=\"renamed_successfully\">Umbenannt</string>\n    <string name=\"calculating_file_size\">Berechne …</string>\n    <string name=\"sort_by_filename\">Name</string>\n    <string name=\"funding_campaign_dialog_message\">Wir unternehmen eine <b>Spendenaktion</b> für den App Manager für einen begrenzten Zeitraum. Besuche <a href=\"https://opencollective.com/app-manager#category-ABOUT\">opencollective.com/app-manager</a>, um mehr über die Aktion zu erfahren. Diese Benachrichtigung wird nicht mehr angezeigt, aber du kannst sie in der Einstellungsseite während des gesamten Spendenaktionszeitraums finden.</string>\n    <string name=\"sort_by_data_usage\">Datenbenutzung</string>\n    <string name=\"filter_apps_with_keystore\">Mit KeyStore</string>\n    <string name=\"filter_apps_with_saf\">Mit SAF</string>\n    <string name=\"filter_apps_with_ssaid\">Mit SSAID</string>\n    <string name=\"action_continue\">Weiter</string>\n    <string name=\"install_for_another_user\">Installieren für …</string>\n    <string name=\"confirm_uninstallation\">Deinstallation bestätigen</string>\n    <string name=\"grant_required_permission\">Die erforderliche Berechtigung gewähren</string>\n    <string name=\"grant_overlay_permission_message\">App Manager erlauben, ein schwebendes Fenster über allen anderen Fenstern anzuzeigen</string>\n    <string name=\"grant_accessibility_permission_for_tracking_window_contents\">App Manager erlauben, die Bedienungshilfefunktion zu benutzen, um die Inhalte des Hauptfensters zu verfolgen.</string>\n    <string name=\"class_hierarchy\">Hierarchie</string>\n    <string name=\"title_ui_tracker\">UI-Tracker</string>\n    <string name=\"title_terminal_emulator\">Terminal</string>\n    <string name=\"title_labs_activity\">Labor</string>\n    <string name=\"app_manager_build_expired\">Aktualisierung erfordert</string>\n    <string name=\"app_manager_build_expired_message\">Um die Sicherheit Ihres Gerätes und Ihrer Daten zu gewährleisten, wurde die von Ihnen benutzte Version des App-Managers zurückgezogen. Sie müssen ihn auf die neueste Version aktualisieren, um ihn weiterhin benutzen zu können, oder ihn deinstallieren, wenn keine Aktualisierung verfügbar ist.</string>\n    <string name=\"app_manager_build_expiring_soon_warning\">Diese Version des App Managers wird bald ablaufen. Bitte aktualisieren Sie ihn auf die neueste Version.</string>\n    <string name=\"selinux_context\">SELinux-Kontext</string>\n    <string name=\"unix_file_permissions\">Modus</string>\n    <string name=\"file_group_id\">Gruppe (GID)</string>\n    <string name=\"file_owner_id\">Besitzer (UID)</string>\n    <string name=\"sort_by_last_modified\">Zuletzt verändert</string>\n    <string name=\"sort_by_file_size\">Dateigröße</string>\n    <string name=\"sort_by_file_type\">Dateityp</string>\n    <string name=\"option_display_folders_on_top\">Ordner oben</string>\n    <string name=\"export_app_list\">App-Liste exportieren</string>\n    <string name=\"export_app_list_select_format\">Format für den Export der App-Liste auswählen</string>\n    <string name=\"export_option_xml\">XML</string>\n    <string name=\"export_option_markdown\">Markdown</string>\n    <string name=\"option_display_dot_files\">Versteckte Dateien</string>\n    <string name=\"funding_campaign_text\">Wir unternehmen gerade eine <b>Spendenaktion</b> für den App Manager für einen begrenzten Zeitraum. <a href=\"https://opencollective.com/app-manager#category-ABOUT\">mehr erfahren …</a></string>\n    <string name=\"adb_incomplete_usb_debugging_title\">Unvollständiges USB-Debugging</string>\n    <string name=\"adb_incomplete_usb_debugging_message\">Es scheint, dass USB-Debugging nicht korrekt eingestellt ist. Bitte lies <a href=\"https://muntashirakon.github.io/AppManager/#subsec:enable-usb-debugging\">die englische Dokumentation</a> für weitere Schritte. Wenn du schon weißt, wie es geht, tippe auf „Öffnen“, um die Entwickleroptionen zu öffnen, oder „Schließen“, um weiterhin den Nicht-Root-Modus zu benutzen.</string>\n    <string name=\"source_stamp_verified_and_identified_to_be_from_source\">Quellstempel verifiziert und identifiziert als von <xliff:g id=\"source\" example=\"Google Play\">%1$s</xliff:g>.</string>\n    <string name=\"optimize_option_force_dexopt\">DEX-Optimierung sofort durchführen</string>\n    <string name=\"action_optimize_app\">Optimieren</string>\n    <string name=\"title_perform_runtime_optimization_to_apps\">Laufzeitoptimierung durchführen</string>\n    <string name=\"optimize_option_clear_profile_data\">Frühere Profildaten löschen</string>\n    <string name=\"optimize_option_check_profiles\">Profildaten bei der DEX-Optimierung berücksichtigen</string>\n    <string name=\"optimize_option_force_compilation\">Kompilierung erzwingen, auch wenn sie nicht erforderlich ist</string>\n    <string name=\"batch_ops_runtime_optimization\">Laufzeitoptimierung</string>\n    <string name=\"action_run\">Ausführen</string>\n    <plurals name=\"alert_failed_to_optimize_apps\">\n        <item quantity=\"one\">Konnte %1$d App nicht optimieren</item>\n        <item quantity=\"other\">Konnte %1$d Apps nicht optimieren</item>\n    </plurals>\n    <string name=\"app_info_tag_open_links\">Links öffnen</string>\n    <string name=\"title_domains_supported_by_the_app\">Unterstützte Domänen</string>\n    <string name=\"block_unblock_components_description\">Alle Komponenten, die durch die angegebenen Signaturen identifiziert werden, blockieren oder freigeben</string>\n    <string name=\"unblock_components_dots\">Komponenten freigeben…</string>\n    <string name=\"block_unblock_components_dots\">Komponenten blockieren/freigeben…</string>\n    <string name=\"pref_layout_direction\">Layout-Richtung</string>\n    <string name=\"warning_working_on_system_mode\">Achtung: Es wird im system modus anstatt dem ADB modus gearbeited.</string>\n    <plurals name=\"alert_failed_to_unblock_components\">\n        <item quantity=\"one\">Konnte Komponenten von %1$d nicht entsperren</item>\n        <item quantity=\"other\">Konnte Komponenten von %1$d Apps nicht entsperren</item>\n    </plurals>\n    <string name=\"netpolicy_reject_metered_background_data\">Hintergrund Datennutzung in Mobilfunknetzwerken ablehnen</string>\n    <string name=\"netpolicy_reject_metered_data\">Daten in Mobilfunknetzwerken zurückweisen</string>\n    <string name=\"netpolicy_allow_metered_background_data\">Hintergrunddatennutzung in Mobilfunknetzwerken erlauben, selbst wenn der Datensparmodus aktiv ist</string>\n    <string name=\"pref_toggle_internet_msg\">Internet Fähigkeiten von App Manager aktivieren</string>\n    <string name=\"read_only_file\">Datei nur zum Lesen</string>\n    <string name=\"pref_zip_align\">APK-Dateien ausrichten</string>\n    <string name=\"title_code_editor\">Code-Editor</string>\n    <string name=\"redo\">Wiederholen</string>\n    <string name=\"line_separator\">Zeilentrennzeichen</string>\n    <string name=\"search_option_regex\">Regulärer Ausdruck</string>\n    <string name=\"uninstall_app_again_message\">Die Anwendung wurde deinstalliert, ohne Daten und Signatur zu löschen. Möchten Sie die Anwendung vollständig deinstallieren?</string>\n    <string name=\"uninstall_app\">%1$s deinstallieren</string>\n    <string name=\"debloat_list_type\">Liste</string>\n    <string name=\"debloat_list_aosp\">AOSP</string>\n    <string name=\"debloat_list_carrier\">Netzbetreiber/IDA</string>\n    <string name=\"debloat_list_google\">Google</string>\n    <string name=\"debloat_removal_safe\">Sicher</string>\n    <string name=\"debloat_removal_type\">Typ</string>\n    <string name=\"debloat_list_oem\">OEM</string>\n    <string name=\"debloat_removal_replace\">Ersetzen</string>\n    <string name=\"debloat_removal_caution\">Vorsicht</string>\n    <string name=\"static_shared_library\">Statische gemeinsame Bibliothek</string>\n    <string name=\"replacement_text\">Ersatz</string>\n    <string name=\"action_replace_all\">Alle ersetzen</string>\n    <string name=\"search_option_match_case\">Groß-/Kleinschreibung beachten</string>\n    <string name=\"go_to_path\">Gehe zu…</string>\n    <string name=\"copy_this_path\">Pfad kopieren</string>\n    <string name=\"title_audio_player\">Audioabspieler</string>\n    <string name=\"backing_up_app\">%1$s wird gesichert…</string>\n    <string name=\"restoring_app\">%1$s wird wiederhergestellt…</string>\n    <string name=\"folder\">Ordner</string>\n    <string name=\"installing_package\">%1$s wird installiert…</string>\n    <string name=\"create_new_folder\">Neuer Ordner</string>\n    <string name=\"create_new_symbolic_link\">Neue symbolische Verknüpfung</string>\n    <string name=\"symbolic_link_not_supported\">Dieser Ordner unterstützt nicht die Erstellung einer symbolischen Verknüpfung.</string>\n    <string name=\"create_new_file\">Neue Datei</string>\n    <string name=\"enter_symbolic_link_name\">Verknüpfungsname</string>\n    <string name=\"enter_target_path\">Zielpfad</string>\n    <string name=\"invalid_target_path\">Ungültiger Pfad</string>\n    <string name=\"copy_these_paths\">Pfade kopieren</string>\n    <string name=\"moved_successfully\">Verschoben</string>\n    <string name=\"failed_to_copy_specified_file\">„%1$s“ konnte nicht kopiert werden.</string>\n    <string name=\"title_change_selinux_context\">SELinux-Kontext ändern</string>\n    <string name=\"change_group_gid\">Gruppe (GID) ändern</string>\n    <string name=\"pref_send_notifications_to_connected_devices\">Benachrichtigungen an die verbundenen Geräte senden</string>\n    <plurals name=\"folder_count\">\n        <item quantity=\"one\">%d Ordner</item>\n        <item quantity=\"other\">%d Ordner</item>\n    </plurals>\n    <plurals name=\"file_count\">\n        <item quantity=\"one\">%d Datei</item>\n        <item quantity=\"other\">%d Dateien</item>\n    </plurals>\n    <string name=\"filter_force_stopped_apps\">Gestoppte Apps</string>\n    <string name=\"copy_keep_both_file\">Beide behalten</string>\n    <string name=\"copied_successfully\">Kopiert.</string>\n    <string name=\"debloat_removal_safe_short_description\">Sicher zu entfernen</string>\n    <string name=\"debloat_removal_replace_short_description\">Mit Alternative ersetzen</string>\n    <string name=\"path_does_not_exist\">„%1$s“ existiert nicht</string>\n    <string name=\"path_not_a_folder\">„%1$s“ ist kein Ordner</string>\n    <string name=\"conflict_detected_while_copying\">Konflikt erkannt</string>\n    <string name=\"title_confirm_deletion\">Löschung bestätigen</string>\n    <string name=\"apply_recursively\">Auf eingeschlossene Dateien anwenden</string>\n    <string name=\"change_owner_uid\">Eigentümer (UID) ändern</string>\n    <string name=\"search_option_whole_word\">Ganzes Wort</string>\n    <string name=\"symbolic_link\">Symbolische Verknüpfung</string>\n    <string name=\"installer_options\">Optionen für das Installationsprogramm</string>\n    <string name=\"debloat_removal_caution_short_description\">Vorsicht walten lassen</string>\n    <string name=\"title_alternatives_to_bloatware\">Alternativen</string>\n    <string name=\"browse_files\">Durchsuchen</string>\n    <string name=\"pref_files_msg\">Dateimanager konfigurieren.</string>\n    <string name=\"title_description\">Beschreibung</string>\n    <string name=\"module_name\">Modulname</string>\n    <string name=\"action_lock_app\">Sperren</string>\n    <string name=\"action_checking\">Wird überprüft…</string>\n    <string name=\"report_not_available\">Nicht verfügbar</string>\n    <string name=\"apply_profile\">Profil „%1$s“ anwenden</string>\n    <string name=\"size_in_bytes\">Größe (Bytes)</string>\n    <string name=\"invalid_regex\">Ungültiger regulärer Ausdruck!</string>\n    <string name=\"value_cannot_be_empty\">Wert darf nicht leer sein!</string>\n    <string name=\"date\">Datum</string>\n    <string name=\"pref_use_vt\">VirusTotal verwenden</string>\n    <string name=\"virus_total\">VirusTotal</string>\n    <string name=\"pref_use_log_viewer\">Protokollbetrachter verwenden</string>\n    <string name=\"pref_installer\">Installationsprogramm verwenden</string>\n    <string name=\"pref_cat_general\">Allgemein</string>\n    <string name=\"status_connecting\">Wird verbunden…</string>\n    <string name=\"status_connecting_via_mode\">Wird über %s verbunden</string>\n    <string name=\"status_connected_via_mode\">Über %s verbunden</string>\n    <string name=\"adb_pairing_input_pairing_code\">Kopplungscode</string>\n    <string name=\"adb_pairing_pairing_in_progress\">Wird gekoppelt…</string>\n    <string name=\"adb_pairing_retry_pairing\">Erneut versuchen</string>\n    <string name=\"mode_of_op_custom_command_title\">Benutzerdefinierter Befehl</string>\n    <string name=\"adb_pairing_searching_for_port\">Wird gesucht…</string>\n    <string name=\"adb_pairing_stop_searching\">Stopp</string>\n    <string name=\"adb_pairing_pairing_code\">Kopplungscode</string>\n    <plurals name=\"search_results\">\n        <item quantity=\"one\">%d Ergebnis</item>\n        <item quantity=\"other\">%d Ergebnisse</item>\n    </plurals>\n    <string name=\"pref_enable_persistent_session\">Starte App Manager im Hintergrund</string>\n    <string name=\"pref_enable_persistent_session_msg\">App Manager im Hintergrund auszuführen reduziert die Verzögerung bei der Initialisierung. Nützlich, wenn App Manager häufig verwendet wird.</string>\n    <string name=\"pref_enable_auto_lock\">Automatische Sperrung</string>\n    <string name=\"pref_enable_auto_lock_msg\">Sperre App Manager, wenn das Gerät gesperrt wird.</string>\n    <string name=\"optimize_option_compile_layouts\">Kompiliere Layout ressourcen</string>\n    <string name=\"select_a_dex2oat_compiler_filter\"><tt>dex2oat</tt> compiler Filter</string>\n    <string name=\"summary_perform_runtime_optimization_to_apps\">Optimiere DEX und Layouts (in Android 10 oder später) um die Anwendungsperformance zu verbessern.</string>\n    <string name=\"pref_zip_align_msg\">Die Ausrichtung einer APK Datei reduziert ihren Speicherverbrauch, da dies direkten Zugriff auf ihre Dateien erlaubt, ohne diese in den Arbeitsspeicher kopieren zu müssen. Dies ist nötig, wenn <tt>extractNativeLibs</tt> <tt>true</tt> ist.</string>\n    <string name=\"read_only_file_warning\">Die Änderungen können nicht in die Datei geschrieben werden, möglicherweise da App Manager nicht über die nötigen Berechtigungen verfügt. Soll die Datei woanders gespeichert werden?</string>\n    <string name=\"system_app_put_back\">Zurücklegen</string>\n    <string name=\"debloater_title\">Debloater</string>\n    <string name=\"debloat_list_misc\">Verschiedenes</string>\n    <string name=\"empty_folder\">Leer</string>\n    <string name=\"tap_to_open_notification_settings\">Tippe zum verstecken</string>\n    <string name=\"app_manager_is_unlocked\">App Manager ist entsperrt</string>\n    <string name=\"app_manager_is_running\">App Manager läuft</string>\n    <string name=\"launch_activity_dialog_title\">Starte Aktivität: Aktion benötigt</string>\n    <string name=\"scan_report_from_pithus\">Pithus Bericht</string>\n    <string name=\"profile_modified_are_you_sure\">Das Profil wurde verändert. Möchtest du wirklich deine Änderungen zu verwerfen und verlassen?</string>\n    <string name=\"choose_a_profile_state\">Wähle einen Profilzustand</string>\n    <string name=\"profile_id\">Profil ID</string>\n    <string name=\"copy_profile_id\">Kopiere Profil ID</string>\n    <string name=\"remember_option_for_this_app\">Speichere für die App</string>\n    <string name=\"app_can_write_and_execute_in_same_place\">Die App verstösst gegen die <a href=\"https://en.wikipedia.org/wiki/W%5EX\">W^X Regel</a> und kann im selben Ordner oder Speicher schreiben und ausführen. Dadurch kann Fremdcode aus der App oder dem Internet ausgeführt werden. Für Apps die für Android SDK 29 (Android 10) oder höher konzipiert sind wird empfohlen eine Alternative zu finden, sofern es sich nicht um notwendiges App verhalten handelt (z.B. ein einem Terminal Emulator).</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-el/disclaimer.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"disclaimer_body\">O App Manager προσφέρει δυνατότητες root που μπορεί να βλάψουν την συσκευή σας αν χρησιμοποιηθούν λάθος. O App Manager δε φέρει καμία ευθύνη για οποιοδήποτε βλάβη που συνέβη χρησιμοποιώντας την εφαρμογή. Αν δε γνωρίζετε πλήρως πως δουλεύει το root, τότε να αποφύγετε τη χρήση root ρυθμίσεων μέχρι να έχετε πλήρη γνώση των κινδύνων.\n\\n\n\\nΟποιοδήποτε σύνδεσμο παρέχω για άλλες εφαρμογές και ιστοσελίδες είναι προς όφελος των χρηστών. Δεν φέρω ευθύνη για οποιοδήποτε περιεχόμενο μπορεί να βρείτε με τη χρήση εξωτερικών συνδέσμων.\n\\n\n\\nΧρησιμοποιώντας τον App Manager, αποδέχεστε πλήρη ευθύνη του τρόπου χρήσης σας και αποδέχεστε ότι ότι δε θα δωθεί αποζημίωση οποιουδήποτε τύπου εξαιτίας κακής χρήσης.\n\\n\n\\nΧρησιμοποιώντας την εφαρμογή, αποδέχεστε πλήρη ευθύνη χρησιμοποιώντας τη και συμφωνείτε ότι δεν είμαι υπεύθυνος για οποιαδήποτε πράξη που θα πάρετε η οποία θα έχει κακό αντίκτυπο στη συσκευή σας.</string>\n    <string name=\"disclaimer_exit\">Έξοδος</string>\n    <string name=\"disclaimer_header\">Αποποίηση ευθυνών</string>\n    <string name=\"disclaimer_footer\">© 2020–2024 Muntashir Al-Islam</string>\n    <string name=\"disclaimer_agree_forever\">Να μην εμφανιστεί ξανά</string>\n    <string name=\"disclaimer_agree\">Συμφωνώ</string>\n</resources>"
  },
  {
    "path": "app/src/main/res/values-el/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\">\n    <string name=\"service\">Υπηρεσίες</string>\n    <string name=\"no_receivers\">Χωρίς παραλήπτες</string>\n    <string name=\"providers\">Πάροχοι</string>\n    <string name=\"no_providers\">Κανένας πάροχος</string>\n    <string name=\"launch_mode\">Λειτουργία εκκίνησης</string>\n    <string name=\"task_affinity\">Συγγένεια έργων</string>\n    <string name=\"sort_by_last_update\">Τελευταία ενημέρωση</string>\n    <string name=\"authority\">Εξουσία</string>\n    <string name=\"no_service\">Καμία υπηρεσία</string>\n    <string name=\"orientation\">Προσανατολισμός</string>\n    <string name=\"group\">Ομάδα</string>\n    <string name=\"error\">Σφάλμα</string>\n    <string name=\"write\">Εγγραφή</string>\n    <string name=\"shared_libs\">Κοινές βιβλιοθήκες</string>\n    <string name=\"grant_uri_permission\">Χορήγηση αδειών URI</string>\n    <string name=\"path_permissions\">Άδειες διαδρομής</string>\n    <string name=\"patterns_allowed\">Επιτρεπτά μοτίβα</string>\n    <string name=\"declared_permission\">Άδειες</string>\n    <string name=\"uses_feature\">Χρησιμοποιεί δυνατότητες</string>\n    <string name=\"no_feature\">Καμία δυνατότητα</string>\n    <string name=\"app_signing_signatures\">Υπογραφές</string>\n    <string name=\"app_signing_no_signatures\">Χωρίς έγκυρη υπογραφή</string>\n    <string name=\"sort_by_shared_user_id\">Κοινό ID χρήστη</string>\n    <string name=\"signatures\">Υπογραφές</string>\n    <string name=\"shared_user_id\">Κοινό ID χρήστη</string>\n    <string name=\"sort_by_sha\">Υπογραφή</string>\n    <string name=\"configurations\">Διαμορφώσεις</string>\n    <string name=\"input_features\">Δυνατότητες εισόδου</string>\n    <string name=\"manifest\">Μανιφέστο</string>\n    <string name=\"loading\">Φορτώνει…</string>\n    <string name=\"sort_by_app_label\">Όνομα εφαρμογής</string>\n    <string name=\"sort_by_domain\">Πρώτα εφαρμογές χρήστη</string>\n    <string name=\"tracker_classes\">Κλάσεις ανιχνευτή</string>\n    <string name=\"sort_by_target_sdk\">Επιθυμητό SDK</string>\n    <string name=\"data_received\">Ελήφθησαν δεδομένα</string>\n    <string name=\"data_transmitted\">Μεταδόθηκαν δεδομένα</string>\n    <string name=\"data_usage_msg\">Χρήση δεδομένων</string>\n    <string name=\"cache_size\">Κρυφή μνήμη</string>\n    <string name=\"obb_size\">Obb</string>\n    <string name=\"app_not_installed\">Η εφαρμογή δεν έχει εγκατασταθεί</string>\n    <string name=\"media_size\">Πολυμέσα</string>\n    <string name=\"system\">Σύστημα</string>\n    <string name=\"user_app\">Εφαρμογή χρήστη</string>\n    <string name=\"user\">Χρήστης</string>\n    <string name=\"sort\">Ταξινόμηση</string>\n    <string name=\"version_name_with_code\">Έκδοση <xliff:g id=\"version_name\" example=\"2.5.17\">%1$s</xliff:g> (<xliff:g id=\"version_code\" example=\"365\">%2$d</xliff:g>)</string>\n    <string name=\"app_info\">Πληροφορίες εφαρμογής</string>\n    <string name=\"system_app\">Εφαρμογή συστήματος</string>\n    <string name=\"paths_and_directories\">Διαδρομές &amp; Φάκελοι</string>\n    <string name=\"source_dir\">Φάκελος πηγής</string>\n    <string name=\"more_info\">Περισσότερες πληροφορίες</string>\n    <string name=\"sdk_flags\">Επισημάνσεις</string>\n    <string name=\"data_dir\">Φάκελος Δεδομένων</string>\n    <string name=\"sdk_min\">Ελαχ</string>\n    <string name=\"main_activity\">Κύρια Δραστηριότητα</string>\n    <string name=\"sdk_max\">Επιθυμητό</string>\n    <string name=\"user_id\">ID χρήστη</string>\n    <string name=\"class_name\">Όνομα Κλάσης</string>\n    <string name=\"empty_package_name\">Κενό όνομα πακέτου</string>\n    <string name=\"error_creating_shortcut\">Σφάλμα δημιουργίας συντόμευσης</string>\n    <string name=\"error_verbose_pin_shortcut\">Ο τρέχων εκκινητής δεν υποστηρίζει PinShortcut. Αδυναμία δημιουργίας συντόμευσης.</string>\n    <string name=\"starting_activity\">Εκκίνηση δραστηριότητας: <xliff:g id=\"activity_name\" example=\".main.MainActivity\">%1$s</xliff:g></string>\n    <string name=\"shortcut_name\">Όνομα Συντόμευσης</string>\n    <string name=\"package_name\">Όνομα Πακέτου</string>\n    <string name=\"icon_picker\">Επιλογέας Εικονίδιου</string>\n    <plurals name=\"tracker_and_classes\">\n        <item quantity=\"one\">1 ανιχνευτής με <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g> κλάση</item>\n        <item quantity=\"other\">1 ανιχνευτής με <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g> κλάσεις</item>\n    </plurals>\n    <string name=\"all_classes\">Όλες οι κλάσεις</string>\n    <string name=\"sort_by_package_name\">Όνομα πακέτου</string>\n    <plurals name=\"other_trackers_and_classes\">\n        <item quantity=\"one\"><xliff:g id=\"tracker_no\" example=\"8\">%1$d</xliff:g> ανιχνευτές με <xliff:g id=\"class_no\" example=\"50\">%2$d</xliff:g> κλάσεις</item>\n        <item quantity=\"other\"><xliff:g id=\"tracker_no\" example=\"8\">%1$d</xliff:g> ανιχνευτές με <xliff:g id=\"class_no\" example=\"50\">%2$d</xliff:g> κλάσεις</item>\n    </plurals>\n    <string name=\"tracker_details\">Λεπτομέρειες Ανιχνευτή</string>\n    <string name=\"no_shared_libs\">Καμία κοινή βιβλιοθήκη</string>\n    <string name=\"app_usage\">Χρήση Εφαρμογής</string>\n    <plurals name=\"main_list_date_days\">\n        <item quantity=\"one\"><xliff:g id=\"last_update_date\" example=\"20/10/2020\">%1$s</xliff:g> <xliff:g id=\"day_no\" example=\"5\">%2$d</xliff:g> μέρα</item>\n        <item quantity=\"other\"><xliff:g id=\"last_update_date\" example=\"20/10/2020\">%1$s</xliff:g> <xliff:g id=\"day_no\" example=\"5\">%2$d</xliff:g> μέρες</item>\n    </plurals>\n    <string name=\"usage_7_days\">Τελευταίες 7 μέρες</string>\n    <string name=\"usage_today\">Σήμερα</string>\n    <string name=\"no_tracker_class\">Χωρίς κλάσεις ανιχνευτή</string>\n    <string name=\"usage_weekly\">Εβδομαδιαία</string>\n    <string name=\"go\">Πάμε</string>\n    <string name=\"go_back\">Πίσω</string>\n    <string name=\"usage_less_than_a_minute\">Λιγότερο από ένα λεπτό</string>\n    <string name=\"grant_usage_access\">Χορήγηση Πρόσβασης Χρήσης</string>\n    <string name=\"save\">Αποθήκευση</string>\n    <string name=\"shared_prefs\">Κοινές Προτιμήσεις</string>\n    <string name=\"native_library_dir\">Φάκελος Βιβλιοθήκης Native JNI</string>\n    <string name=\"string_value\">Τιμή συμβολοσειράς</string>\n    <string name=\"type_string\">Χαρακτήρες</string>\n    <string name=\"key_name_cannot_be_null\">Το όνομα κλειδιού δε μπορεί να είναι κενό</string>\n    <string name=\"add_item\">Προσθήκη αντικειμένου</string>\n    <string name=\"no_content\">Χωρίς περιεχόμενο</string>\n    <string name=\"failed_to_uninstall\">Δεν ήταν δυνατή η απεγκατάσταση <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g>.</string>\n    <string name=\"uninstall_system_app_message\">Πρόκειται για εφαρμογή συστήματος. Θέλετε σίγουρα να την απεγκαταστήσετε;</string>\n    <string name=\"uninstall\">Απεγκατάσταση</string>\n    <string name=\"permissions\">Άδειες χρησης</string>\n    <string name=\"require_no_permission\">Δεν απαιτείται άδεια</string>\n    <string name=\"activities\">Δραστηριότητες</string>\n    <string name=\"launch\">Εκκίνηση</string>\n    <string name=\"refresh\">Ανανέωση</string>\n    <string name=\"no_activities\">Καμία δραστηριότητα</string>\n    <string name=\"receivers\">Παραλήπτες</string>\n    <string name=\"soft_input\">Λειτουργία τυπικής εισόδου</string>\n    <string name=\"flags\">Επισημάνσεις</string>\n    <string name=\"read\">Ανάγνωση</string>\n    <string name=\"no_configurations\">Καμία διαμόρφωση</string>\n    <string name=\"about\">Σχετικά</string>\n    <string name=\"data_size\">Δεδομένα</string>\n    <string name=\"date_installed\">Ημερομηνία εγκατάστασης</string>\n    <string name=\"date_updated\">Ημερομηνία ενημέρωσης</string>\n    <string name=\"installer_app\">Εφαρμογή εγκατάστασης</string>\n    <string name=\"create_shortcut\">Δημιουργία Συντόμευσης</string>\n    <string name=\"license\">Άδεια</string>\n    <string name=\"third_party\">Βιβλιοθήκες και Εικονίδια τρίτου μέρους</string>\n    <plurals name=\"two_trackers_and_classes\">\n        <item quantity=\"one\">2 ανιχνευτές με <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g> κλάσεις</item>\n        <item quantity=\"other\">2 ανιχνευτές με <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g> κλάσεις</item>\n    </plurals>\n    <plurals name=\"usage_months\">\n        <item quantity=\"one\">%1$d μήνας</item>\n        <item quantity=\"other\">%1$d μήνες</item>\n    </plurals>\n    <plurals name=\"usage_days\">\n        <item quantity=\"one\">%1$d μέρα</item>\n        <item quantity=\"other\">%1$d μέρες</item>\n    </plurals>\n    <plurals name=\"usage_hours\">\n        <item quantity=\"one\">%1$d ώρα</item>\n        <item quantity=\"other\">%1$d ώρες</item>\n    </plurals>\n    <plurals name=\"usage_minutes\">\n        <item quantity=\"one\">%1$d λεπτό</item>\n        <item quantity=\"other\">%1$d λεπτά</item>\n    </plurals>\n    <plurals name=\"usage_seconds\">\n        <item quantity=\"one\">%1$d δλ</item>\n        <item quantity=\"other\">%1$d δλ</item>\n    </plurals>\n    <string name=\"failed_to_stop\">Δε σταμάτησε <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g>.</string>\n    <string name=\"storage_and_cache\">Χώρος αποθήκευσης και Κρυφή μνήμη</string>\n    <string name=\"total_size\">Σύνολο</string>\n    <string name=\"app_size\">Εφαρμογή</string>\n    <string name=\"grant_usage_acess_message\">Χρησιμοποιείται για εμφάνιση πληροφορίων χρήσης εφαρμογής.</string>\n    <string name=\"share_apk\">Κοινοποίηση APK</string>\n    <string name=\"failed_to_extract_apk_file\">Δεν ήταν δυνατή η εξαγωγή αρχείου APK</string>\n    <string name=\"menu_remove_rules\">Αφαίρεση κανόνων</string>\n    <string name=\"menu_apply_rules\">Εφαρμογή κανόνων</string>\n    <string name=\"search\">Αναζήτηση</string>\n    <string name=\"dev_protected_data_dir\">Φάκελος Δεδομένων προστατευόμενων απ\\' τη συσκευή</string>\n    <string name=\"process_name\">Όνομα Διεργασίας</string>\n    <string name=\"no_code\">Χωρίς κώδικα</string>\n    <string name=\"requested_large_heap\">Μεγάλος σωρός</string>\n    <string name=\"updated_app\">Ενημερωμένο</string>\n    <string name=\"debuggable\">Δυνατότητα εντοπισμού σφαλμάτων</string>\n    <string name=\"test_only\">Μόνο για τεστ</string>\n    <string name=\"databases\">Βάσεις δεδομένων</string>\n    <string name=\"discard\">Απόρριψη</string>\n    <string name=\"delete\">Διαγραφή</string>\n    <string name=\"deleted_successfully\">Διαγράφηκε</string>\n    <string name=\"deletion_failed\">Η διαγραφή απέτυχε</string>\n    <string name=\"saved_successfully\">Αποθηκεύτηκε</string>\n    <string name=\"saving_failed\">Η αποθήκευση απέτυχε, προσπαθήστε ξανά.</string>\n    <string name=\"integer_value\">Τιμή ακεραίου</string>\n    <string name=\"decimal_value\">Τιμή δεκαδικού</string>\n    <string name=\"boolean_value\">δυαδική τιμή</string>\n    <string name=\"key_name\">Όνομα Κλειδιού</string>\n    <string name=\"select_type\">Επιλογή τύπου</string>\n    <string name=\"done\">Έγινε</string>\n    <string name=\"type_boolean\">Αληθής/ψευδής</string>\n    <string name=\"type_float\">Δεκαδικός Αριθμός</string>\n    <string name=\"type_int\">Ακέραιος</string>\n    <string name=\"type_long\">Μεγάλος ακέραιος</string>\n    <string name=\"error_evaluating_input\">Δεν είναι δυνατή η εκτίμηση της εισόδου</string>\n    <string name=\"disabled_app\">Απενεργοποιήθηκε</string>\n    <string name=\"no_usage_in_this_time_range\">Καμία χρήση αυτό το χρονικό διάστημα</string>\n    <string name=\"view_in_settings\">Εμφάνιση στις Ρυθμίσεις</string>\n    <string name=\"uninstall_app_message\">Θέλετε να απεγκαταστήσετε την εφαρμογή;</string>\n    <string name=\"failed_to_uninstall_app\">Η απεγκατάσταση απέτυχε</string>\n    <string name=\"uninstalled_successfully\"><xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g> έχει απεγκατασταθεί.</string>\n    <string name=\"stopped\">Σταμάτησε</string>\n    <string name=\"disable\">Απενεργοποίηση</string>\n    <string name=\"enable\">Ενεργοποίηση</string>\n    <string name=\"credits\">Εύσημα</string>\n    <string name=\"credits_message\">Στους δημιουργούς των \\n- The Android Open Source Project \\n- <a href=\"https://github.com/zhaobozhen/libraries\">Absinthe\\'s libraries</a> \\n- <a href=\"https://github.com/butzist/ActivityLauncher\">Activity Launcher</a> \\n- <a href=\"https://bitbucket.org/oF2pks/fdroid-applications-info\">Apps_packages Info</a> \\n- <a href=\"https://github.com/zhaobao/AppsMonitor\">AppsMonitor</a> \\n- <a href=\"https://github.com/8enet/AppOpsX\">AppOpsX</a> \\n- <a href=\"https://github.com/gabrielemariotti/changeloglib\">ChangeLog Library</a> \\n- <a href=\"https://bitbucket.org/oF2pks/fdroid-classyshark3xodus\">ClassySharkAndroid</a> \\n- <a href=\"https://github.com/billthefarmer/editor\">Editor</a> \\n- <a href=\"https://github.com/Raival-e/File-Explorer\">File Explorer</a> \\n- <a href=\"https://github.com/nex3z/FlowLayout\">FlowLayout</a> \\n- <a href=\"https://github.com/k3b/intent-intercept\">Intent Intercept</a> \\n- <a href=\"https://github.com/YarikSOffice/lingver\">Lingver</a> \\n- <a href=\"https://github.com/topjohnwu/Magisk\">Magisk</a> \\n- <a href=\"https://github.com/zhanghai/MaterialFiles\">Material Files</a> \\n- <a href=\"https://github.com/pluscubed/matlog\">MatLog</a> \\n- <a href=\"https://github.com/matrix-org/matrix-android-sdk\">Matrix Android SDK</a> \\n- <a href=\"https://github.com/jensstein/oandbackup\">OAndBackup</a> \\n- <a href=\"https://github.com/open-keychain/open-keychain\">Open Keychain</a> \\n- <a href=\"https://github.com/Aefyr/SAI\">SAI</a> \\n- <a href=\"https://github.com/RikkaApps/Shizuku\">Shizuku</a> \\n- <a href=\"https://github.com/eclipse/tm4e\">tm4e</a> \\n- <a href=\"https://github.com/tuyafeng/Watt\">Watt</a></string>\n    <string name=\"word_wrap\">Επιλογή αναδίπλωσης λέξης</string>\n    <string name=\"class_viewer\">Προβολέας Κλάσης</string>\n    <string name=\"toggle_class_listing\">Επιλογή Απαρίθμησης Κλάσεων</string>\n    <string name=\"found_trackers\">Βρέθηκαν Ανιχνευτές:</string>\n    <string name=\"force_stop\">Επιβολή διακοπής</string>\n    <string name=\"usage_access\">Πρόσβαση χρήσης</string>\n    <string name=\"app_ops\">App Ops</string>\n    <string name=\"no_app_ops\">Χωρίς ενέργειες εφαρμογής</string>\n    <string name=\"failed_to_enable_op\">Δεν ήταν δυνατή η ενεργοποίηση ενέργειας της εφαρμογής</string>\n    <string name=\"failed_to_disable_op\">Δεν ήταν δυνατή η απενεργοποίηση της ενέργειας της εφαρμογής</string>\n    <string name=\"rules_not_applied\">Οι κανόνες δεν εφαρμόζονται</string>\n    <string name=\"str_logo\">Λογότυπο</string>\n    <string name=\"pref_global_blocking_enabled\">Άμεσος αποκλεισμός στοιχείου</string>\n    <string name=\"pref_global_blocking_enabled_msg\">Επιτρέπει τον αποκλεισμό οποιοδήποτε στοιχείου οποιασδήποτε εφαρμογής χωρίς να αποκλείσει την εφαρμογή.</string>\n    <string name=\"app_settings\">Ρυθμίσεις</string>\n    <string name=\"usage_yesterday\">Χθές</string>\n    <string name=\"long_integer_value\">Τιμή μεγάλου ακεραίου</string>\n    <string name=\"exodus_link\">Σύνδεσμος εxodus</string>\n    <string name=\"sort_by_blocked_components\">Πρώτα τα αποκλεισμένα</string>\n    <string name=\"external_data_dir\">Φάκελος Εξωτερικών Δεδομένων</string>\n    <string name=\"external_multiple_data_dir\">Φάκελος Εξωτερικών Δεδομένων <xliff:g id=\"dir_no\" example=\"1\">%1$d</xliff:g></string>\n    <string name=\"second_degree_tracker_note\">Το πρόθεμα ² υποδηλώνει ότι οι ιχνηλάτες βρίσκονται στον <a href=\"https://etip.exodus-privacy.eu.org/\">κατάλογο αναμονής ETIP</a>, δηλ. αν είναι πραγματικοί ιχνηλάτες, εξακολουθεί να ερευνάται.</string>\n</resources>"
  },
  {
    "path": "app/src/main/res/values-eo/disclaimer.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- SPDX-License-Identifier: GPL-3.0-or-later --><resources>\n    <string name=\"disclaimer_body\">App Manager ofertas funkciojn de ĉefuzanto, kiuj eble povus damaĝi vian aparaton se ili estas malĝuste uzataj. App Manager ne respondecas pri iuj ajn damaĝoj kaŭzitaj de la uzo de ĉi tiu aplikaĵo. Se vi ne plene konscias pri la funkcioj de ĉefuzanto, vi evitu uzi ĉefuzantajn opciojn ĝis vi plene konscias pri la riskoj.\n\\n\n\\nĈiu ajn ligilo provizata de mi al aliaj aplikaĵoj kaj retejoj estas por la utilo de la uzanto. Mi ne respondecas pri iu ajn enhavo, kiun vi eble trovos per eksteraj ligiloj.\n\\n\n\\nUzante App Manager, vi akceptas plenan respondecon pri via propra uzado kaj akceptas, ke neniu damaĝo estos kompensita pro misuzo.\n\\n\n\\nUzante ĉi tiun aplikaĵon, vi akceptas ĉian respondecon uzi ĝin kaj konsentas, ke mi ne respondecas pri iuj ajn agoj, kiujn vi faros, kiuj malutiligos vian aparaton.</string>\n    <string name=\"disclaimer_exit\">Eliri</string>\n    <string name=\"disclaimer_agree\">Mi Konsentas</string>\n    <string name=\"disclaimer_agree_forever\">Ne montri ĉi tion denove</string>\n    <string name=\"disclaimer_footer\">© 2020–2024 Muntashir Al-Islam</string>\n    <string name=\"disclaimer_header\">MALGARANTIO</string>\n</resources>"
  },
  {
    "path": "app/src/main/res/values-eo/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- SPDX-License-Identifier: GPL-3.0-or-later --><resources xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\">\n    <string name=\"paths_and_directories\">Vojoj kaj Dosierujoj</string>\n    <string name=\"user_app\">Uzanta aplikaĵo</string>\n    <string name=\"system_app\">Operaciuma aplikaĵo</string>\n    <string name=\"app_info\">Aplikaĵinformoj</string>\n    <string name=\"sort\">Ordigi</string>\n    <string name=\"user\">Uzanto</string>\n    <string name=\"system\">Operaciuma</string>\n    <string name=\"app_not_installed\">Aplikaĵo ne instalita</string>\n    <string name=\"data_size\">Datumo</string>\n    <string name=\"about\">Pri</string>\n    <string name=\"data_transmitted\">Sendita datumo</string>\n    <string name=\"data_received\">Ricevita datumo</string>\n    <string name=\"sort_by_package_name\">Pakaĵnomo</string>\n    <string name=\"sort_by_app_label\">Aplikaĵa prinoto</string>\n    <string name=\"error\">Eraro</string>\n    <string name=\"group\">Grupo</string>\n    <string name=\"launch_mode\">Lanĉada reĝimo</string>\n    <string name=\"launch\">Lanĉi</string>\n    <string name=\"uninstall\">Malinstali</string>\n    <string name=\"class_name\">Nomo de Klaso</string>\n    <string name=\"icon_picker\">Ikonelektilo</string>\n    <string name=\"third_party\">Triapartiaj Bibliotekoj kaj Ikonoj</string>\n    <string name=\"all_classes\">Ĉiuj klasoj</string>\n    <string name=\"license\">Permesilo</string>\n    <string name=\"authority\">Aŭtoritato</string>\n    <string name=\"orientation_sensor\">Sentilo</string>\n    <string name=\"orientation_user\">Uzanto</string>\n    <string name=\"orientation_reverse_landscape\">Renversita horizontala</string>\n    <string name=\"orientation_reverse_portrait\">Renversita vertikala</string>\n    <string name=\"orientation_portrait\">Vertikala</string>\n    <string name=\"orientation_landscape\">Horizontala</string>\n    <string name=\"orientation_no_sensor\">Neniu sentilo</string>\n    <string name=\"orientation_locked\">Ŝlosita</string>\n    <string name=\"orientation_full_user\">Plena uzanto</string>\n    <string name=\"orientation_full_sensor\">Plena sentilo</string>\n    <string name=\"orientation_unspecified\">Ne specifita</string>\n    <string name=\"orientation\">Orientiĝo</string>\n    <string name=\"sort_by_permission_names\">Nomo de permeso</string>\n    <string name=\"permission_name\">Nomo de Permeso</string>\n    <string name=\"declared_permission\">Permesoj</string>\n    <string name=\"path_permissions\">Dosierindikaj permesoj</string>\n    <string name=\"no_service\">Neniu servo</string>\n    <string name=\"service\">Servoj</string>\n    <string name=\"write\">Skribi</string>\n    <string name=\"state_multithreaded\">Plurfadena</string>\n    <string name=\"read\">Legi</string>\n    <string name=\"sdk_flags\">Flagoj</string>\n    <string name=\"flags\">Flagoj</string>\n    <string name=\"activity_result\">Rezulto de aktiveco</string>\n    <string name=\"matching_activities\">Kongruaj aktivecoj</string>\n    <string name=\"filter_apps_with_activities\">Aplikaĵoj kun aktivecoj</string>\n    <string name=\"credits_message\">Al la aŭtoroj de \\n- The Android Open Source Project \\n- <a href=\"https://github.com/zhaobozhen/libraries\">Absinthe\\'s libraries</a> \\n- <a href=\"https://github.com/butzist/ActivityLauncher\">Activity Launcher</a> \\n- <a href=\"https://bitbucket.org/oF2pks/fdroid-applications-info\">Apps_packages Info</a> \\n- <a href=\"https://github.com/zhaobao/AppsMonitor\">AppsMonitor</a> \\n- <a href=\"https://github.com/8enet/AppOpsX\">AppOpsX</a> \\n- <a href=\"https://github.com/gabrielemariotti/changeloglib\">ChangeLog Library</a> \\n- <a href=\"https://bitbucket.org/oF2pks/fdroid-classyshark3xodus\">ClassySharkAndroid</a> \\n- <a href=\"https://github.com/billthefarmer/editor\">Editor</a> \\n- <a href=\"https://github.com/Raival-e/File-Explorer\">File Explorer</a> \\n- <a href=\"https://github.com/nex3z/FlowLayout\">FlowLayout</a> \\n- <a href=\"https://github.com/k3b/intent-intercept\">Intent Intercept</a> \\n- <a href=\"https://github.com/YarikSOffice/lingver\">Lingver</a> \\n- <a href=\"https://github.com/topjohnwu/Magisk\">Magisk</a> \\n- <a href=\"https://github.com/zhanghai/MaterialFiles\">Material Files</a> \\n- <a href=\"https://github.com/pluscubed/matlog\">MatLog</a> \\n- <a href=\"https://github.com/matrix-org/matrix-android-sdk\">Matrix Android SDK</a> \\n- <a href=\"https://github.com/jensstein/oandbackup\">OAndBackup</a> \\n- <a href=\"https://github.com/open-keychain/open-keychain\">Open Keychain</a> \\n- <a href=\"https://github.com/Aefyr/SAI\">SAI</a> \\n- <a href=\"https://github.com/RikkaApps/Shizuku\">Shizuku</a> \\n- <a href=\"https://github.com/eclipse/tm4e\">tm4e</a> \\n- <a href=\"https://github.com/tuyafeng/Watt\">Watt</a></string>\n    <string name=\"starting_activity\">Komencante aktivecon: <xliff:g id=\"activity_name\" example=\".main.MainActivity\">%1$s</xliff:g></string>\n    <string name=\"main_activity\">Ĉefaktiveco</string>\n    <string name=\"no_activities\">Neniu aktiveco</string>\n    <string name=\"activities\">Aktivecoj</string>\n    <string name=\"require_no_permission\">Neniu permeso necesas</string>\n    <string name=\"permissions\">Uzas permesojn</string>\n    <string name=\"no_feature\">Neniuj funkcioj</string>\n    <string name=\"uses_feature\">Uzas funkciojn</string>\n    <string name=\"no_providers\">Neniuj provizantoj</string>\n    <string name=\"receivers\">Riceviloj</string>\n    <string name=\"no_receivers\">Neniuj riceviloj</string>\n    <string name=\"providers\">Provizantoj</string>\n    <string name=\"sort_by_last_update\">Laste ĝisdatigita</string>\n    <string name=\"signatures\">Subskriboj</string>\n    <string name=\"sort_by_sha\">Subskribo</string>\n    <string name=\"refresh\">Aktualigi</string>\n</resources>"
  },
  {
    "path": "app/src/main/res/values-es/disclaimer.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- SPDX-License-Identifier: GPL-3.0-or-later --><resources>\n    <string name=\"disclaimer_header\">DESCARGO DE RESPONSABILIDAD</string>\n    <string name=\"disclaimer_exit\">Salir</string>\n    <string name=\"disclaimer_agree\">Estoy de acuerdo</string>\n    <string name=\"disclaimer_agree_forever\">No vuelvas a mostrar esto</string>\n    <string name=\"disclaimer_footer\">© 2020–2024 Muntashir Al-Islam</string>\n    <string name=\"disclaimer_body\">App Manager ofrece funcionalidades de root que podrían dañar tu dispositivo si se usan incorrectamente. App Manager no se hace responsable de los daños causados por el uso de esta aplicación. Si no eres plenamente consciente de cómo el root trabaja, entonces debes evitar usar opciones de root hasta que seas plenamente consciente de los riesgos.\n\\n\n\\nCualquier enlace que se proporcione a otras aplicaciones y sitios web es para el beneficio de los usuarios. No me hago responsable de ningún contenido que pueda encontrar en los enlaces externos.\n\\n\n\\nAl utilizar App Manager, aceptas la plena responsabilidad de tu propio uso y no aceptas ningún tipo de daño, reclamación o valor monetario debido al mal uso.\n\\n\n\\nAl usar esta aplicación, aceptas toda la responsabilidad de su uso y aceptas que no soy responsable de ninguna acción que realices y que tenga un efecto adverso en tu dispositivo.</string>\n</resources>"
  },
  {
    "path": "app/src/main/res/values-es-rES/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- SPDX-License-Identifier: GPL-3.0-or-later --><resources xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:tools=\"http://schemas.android.com/tools\">\n    <string name=\"_lang_tag\" translatable=\"false\">es-ES</string>\n    <string name=\"uninstall\">Desinstalar</string>\n    <string name=\"permissions\">Usa permisos</string>\n    <string name=\"require_no_permission\">No se requiere permiso</string>\n    <string name=\"activities\">Actividades</string>\n    <string name=\"launch\">Iniciar</string>\n    <string name=\"refresh\">Actualizar</string>\n    <string name=\"no_activities\">Sin actividades</string>\n    <string name=\"receivers\">Receptores</string>\n    <string name=\"no_receivers\">Sin receptores</string>\n    <string name=\"providers\">Proveedores</string>\n    <string name=\"no_providers\">Sin proveedores</string>\n    <string name=\"launch_mode\">Modo de inicio</string>\n    <string name=\"task_affinity\">Afinidad de tareas</string>\n    <string name=\"sort_by_last_update\">Última actualización</string>\n    <string name=\"authority\">Autoridad</string>\n    <string name=\"service\">Servicios</string>\n    <string name=\"no_service\">Sin servicios</string>\n    <string name=\"orientation\">Orientación</string>\n    <string name=\"soft_input\">Modo de entrada suave</string>\n    <string name=\"flags\">Banderas</string>\n    <string name=\"grant_uri_permission\">Conceder permisos URI</string>\n    <string name=\"path_permissions\">Permisos de ruta</string>\n    <string name=\"read\">Leer</string>\n    <string name=\"write\">Escribir</string>\n    <string name=\"patterns_allowed\">Patrones permitidos</string>\n    <string name=\"declared_permission\">Permisos</string>\n    <string name=\"shared_libs\">Bibliotecas compartidas</string>\n    <string name=\"group\">Grupo</string>\n    <string name=\"no_feature\">Sin funciones</string>\n    <string name=\"sort_by_shared_user_id\">ID de usuario compartido</string>\n    <string name=\"shared_user_id\">ID de usuario compartido</string>\n    <string name=\"sort_by_sha\">Firma</string>\n    <string name=\"signatures\">Firmas</string>\n    <string name=\"app_signing_no_signatures\">Sin firmas válidas</string>\n    <string name=\"configurations\">Configuraciones</string>\n    <string name=\"no_configurations\">Sin configuraciones</string>\n    <string name=\"input_features\">Funciones de entrada</string>\n    <string name=\"error\">Error</string>\n    <string name=\"loading\">Cargando…</string>\n    <!-- &#8230; = ... -->\n    <string name=\"credits_message\">A los autores del \\n- The Android Open Source Project \\n- <a href=\"https://github.com/zhaobozhen/libraries\">Absinthe\\'s libraries</a> \\n- <a href=\"https://github.com/butzist/ActivityLauncher\">Activity Launcher</a> \\n- <a href=\"https://bitbucket.org/oF2pks/fdroid-applications-info\">Apps_packages Info</a> \\n- <a href=\"https://github.com/zhaobao/AppsMonitor\">AppsMonitor</a> \\n- <a href=\"https://github.com/8enet/AppOpsX\">AppOpsX</a> \\n- <a href=\"https://github.com/gabrielemariotti/changeloglib\">ChangeLog Library</a> \\n- <a href=\"https://bitbucket.org/oF2pks/fdroid-classyshark3xodus\">ClassySharkAndroid</a> \\n- <a href=\"https://github.com/billthefarmer/editor\">Editor</a> \\n- <a href=\"https://github.com/Raival-e/File-Explorer\">File Explorer</a> \\n- <a href=\"https://github.com/nex3z/FlowLayout\">FlowLayout</a> \\n- <a href=\"https://github.com/k3b/intent-intercept\">Intent Intercept</a> \\n- <a href=\"https://github.com/YarikSOffice/lingver\">Lingver</a> \\n- <a href=\"https://github.com/topjohnwu/Magisk\">Magisk</a> \\n- <a href=\"https://github.com/zhanghai/MaterialFiles\">Material Files</a> \\n- <a href=\"https://github.com/pluscubed/matlog\">MatLog</a> \\n- <a href=\"https://github.com/matrix-org/matrix-android-sdk\">Matrix Android SDK</a> \\n- <a href=\"https://github.com/jensstein/oandbackup\">OAndBackup</a> \\n- <a href=\"https://github.com/open-keychain/open-keychain\">Open Keychain</a> \\n- <a href=\"https://github.com/Aefyr/SAI\">SAI</a> \\n- <a href=\"https://github.com/RikkaApps/Shizuku\">Shizuku</a> \\n- <a href=\"https://github.com/eclipse/tm4e\">tm4e</a> \\n- <a href=\"https://github.com/tuyafeng/Watt\">Watt</a></string>\n    <string name=\"word_wrap\">Alternar ajuste de texto</string>\n    <string name=\"touchscreen\">Pantalla táctil</string>\n    <string name=\"navigation\">Navegación</string>\n    <string name=\"export_failed\">¡Exportación fallida!</string>\n    <string name=\"import_failed\">¡Importación fallida!</string>\n    <string name=\"export_options\">Exportar opciones</string>\n    <string name=\"import_options\">Importar opciones</string>\n    <string name=\"pref_export\">Exportar</string>\n    <string name=\"pref_import\">Importar</string>\n    <string name=\"duration\">Duración</string>\n    <string name=\"running\">Ejecutándose</string>\n    <string name=\"mode\">Modo</string>\n    <string name=\"permission_name\">Nombre del permiso</string>\n    <string name=\"export_blocking_rules\">Exportar reglas de bloqueo</string>\n    <string name=\"disable_background\">Evitar operación en segundo plano</string>\n    <string name=\"clear_data\">Limpiar datos</string>\n    <string name=\"user_and_uid\">Usuario: <xliff:g id=\"user_name\" example=\"root\">%1$s</xliff:g> (<xliff:g id=\"user_id\" example=\"0\">%2$d</xliff:g>)</string>\n    <string name=\"disable_background_run\">Evitar la operación en segundo plano</string>\n    <string name=\"kill_process\">Forzar finalización</string>\n    <string name=\"running_apps\">Aplicaciones en ejecución</string>\n    <string name=\"the_export_was_successful\">Exportado</string>\n    <string name=\"the_import_was_successful\">Importado</string>\n    <string name=\"pref_import_blocker\">Importar desde Blocker</string>\n    <string name=\"pref_import_watt\">Importar desde Watt</string>\n    <string name=\"pref_import_export_blocking_rules_msg\">Importar/Exportar reglas, importar reglas externas desde Watt o Blocker.</string>\n    <string name=\"pref_import_export_blocking_rules\">Reglas de bloqueo de importación/exportación</string>\n    <string name=\"sort_by_mobile_data\">Datos móviles</string>\n    <string name=\"sort_by_screen_time\">Tiempo en pantalla</string>\n    <string name=\"sort_by_last_used\">Último uso</string>\n    <string name=\"external_data_dir\">Directorio de datos externos</string>\n    <string name=\"sort_by_blocked_components\">Bloqueadas primero</string>\n    <string name=\"exodus_link\">Enlace de εxodus</string>\n    <string name=\"usage_yesterday\">Ayer</string>\n    <string name=\"app_settings\">Configuración</string>\n    <string name=\"usage_access\">Acceso al uso</string>\n    <string name=\"pref_global_blocking_enabled_msg\">Le permite bloquear cualquier componente de cualquier aplicación sin bloquear esta explícitamente.</string>\n    <string name=\"pref_global_blocking_enabled\">Bloqueo instantáneo de componentes</string>\n    <string name=\"str_logo\">Logo</string>\n    <string name=\"rules_not_applied\">No se aplican las reglas</string>\n    <string name=\"app_ops\">Operaciones de aplicación</string>\n    <string name=\"app_size\">Aplicación</string>\n    <string name=\"total_size\">Total</string>\n    <string name=\"storage_and_cache\">Almacenamiento y antememoria</string>\n    <string name=\"enable\">Activar</string>\n    <string name=\"disable\">Desactivar</string>\n    <string name=\"stopped\">Detenido</string>\n    <string name=\"uninstall_system_app_message\">Esta es una aplicación del sistema. ¿Confirma que quiere desinstalarla\\?</string>\n    <string name=\"uninstalled_successfully\">Se ha desinstalado <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g>.</string>\n    <string name=\"uninstall_app_message\">¿Quiere desinstalar esta aplicación\\?</string>\n    <string name=\"no_content\">Sin contenido</string>\n    <string name=\"no_usage_in_this_time_range\">No hay uso en este rango de tiempo</string>\n    <string name=\"disabled_app\">Desactivado</string>\n    <string name=\"key_name_cannot_be_null\">El nombre de la clave no puede quedar vacío</string>\n    <string name=\"error_evaluating_input\">No se pudo evaluar la entrada</string>\n    <string name=\"type_string\">Caracteres</string>\n    <string name=\"type_float\">Número decimal</string>\n    <string name=\"type_boolean\">Verdadero/falso</string>\n    <string name=\"done\">Hecho</string>\n    <string name=\"add_item\">Añadir elemento</string>\n    <string name=\"select_type\">Seleccione un tipo</string>\n    <string name=\"key_name\">Nombre de la clave</string>\n    <string name=\"string_value\">Valor de cadena</string>\n    <string name=\"saving_failed\">Falló el guardado; inténtelo de nuevo.</string>\n    <string name=\"saved_successfully\">Guardado</string>\n    <string name=\"deletion_failed\">Falló la eliminación</string>\n    <string name=\"deleted_successfully\">Borrado</string>\n    <string name=\"delete\">Eliminar</string>\n    <string name=\"discard\">Descartar</string>\n    <string name=\"save\">Guardar</string>\n    <string name=\"databases\">Bases de datos</string>\n    <string name=\"shared_prefs\">Preferencias compartidas</string>\n    <string name=\"test_only\">Solo prueba</string>\n    <string name=\"debuggable\">Depurable</string>\n    <string name=\"updated_app\">Actualizado</string>\n    <string name=\"requested_large_heap\">Montón grande</string>\n    <string name=\"no_code\">Sin código</string>\n    <string name=\"process_name\">Nombre del proceso</string>\n    <string name=\"native_library_dir\">Directorio de la biblioteca nativa JNI</string>\n    <string name=\"dev_protected_data_dir\">Directorio de datos protegido por dispositivo</string>\n    <string name=\"search\">Buscar</string>\n    <string name=\"menu_apply_rules\">Aplicar reglas</string>\n    <string name=\"menu_remove_rules\">Quitar reglas</string>\n    <string name=\"failed_to_extract_apk_file\">No se pudo extraer el archivo APK</string>\n    <string name=\"share_apk\">Compartir APK</string>\n    <string name=\"grant_usage_acess_message\">Se utiliza para mostrar datos de uso de las aplicaciones.</string>\n    <string name=\"grant_usage_access\">Conceder acceso de uso</string>\n    <string name=\"go\">Ir</string>\n    <string name=\"go_back\">Volver</string>\n    <string name=\"usage_less_than_a_minute\">Menos de un minuto</string>\n    <plurals name=\"usage_hours\">\n        <item quantity=\"one\">%1$d hora</item>\n        <item quantity=\"many\">%1$d horas</item>\n        <item quantity=\"other\">%1$d horas</item>\n    </plurals>\n    <plurals name=\"usage_days\">\n        <item quantity=\"one\">%1$d día</item>\n        <item quantity=\"many\">%1$d días</item>\n        <item quantity=\"other\">%1$d días</item>\n    </plurals>\n    <plurals name=\"usage_months\">\n        <item quantity=\"one\">%1$d mes</item>\n        <item quantity=\"many\">%1$d meses</item>\n        <item quantity=\"other\">%1$d meses</item>\n    </plurals>\n    <string name=\"usage_7_days\">Últimos 7 días</string>\n    <string name=\"usage_today\">Hoy</string>\n    <string name=\"usage_weekly\">Semanal</string>\n    <string name=\"app_usage\">Uso de aplicaciones</string>\n    <string name=\"no_tracker_class\">No hay clases de seguimiento</string>\n    <string name=\"no_shared_libs\">Sin bibliotecas compartidas</string>\n    <plurals name=\"main_list_date_days\">\n        <item quantity=\"one\"><xliff:g id=\"last_update_date\" example=\"20/10/2020\">%1$s</xliff:g> <xliff:g id=\"day_no\" example=\"5\">%2$d</xliff:g> día</item>\n        <item quantity=\"many\"><xliff:g id=\"last_update_date\" example=\"20/10/2020\">%1$s</xliff:g> <xliff:g id=\"day_no\" example=\"5\">%2$d</xliff:g> días</item>\n        <item quantity=\"other\"><xliff:g id=\"last_update_date\" example=\"20/10/2020\">%1$s</xliff:g> <xliff:g id=\"day_no\" example=\"5\">%2$d</xliff:g> días</item>\n    </plurals>\n    <string name=\"all_classes\">Todas las clases</string>\n    <string name=\"tracker_classes\">Classes del rastreador</string>\n    <string name=\"tracker_details\">Detalles del rastreador</string>\n    <string name=\"found_trackers\">Rastreadores encontrados:</string>\n    <plurals name=\"other_trackers_and_classes\">\n        <item quantity=\"one\"><xliff:g id=\"tracker_no\" example=\"8\">%1$d</xliff:g> rastreador con <xliff:g id=\"class_no\" example=\"50\">%2$d</xliff:g> clases</item>\n        <item quantity=\"many\"><xliff:g id=\"tracker_no\" example=\"8\">%1$d</xliff:g> rastreadores con <xliff:g id=\"class_no\" example=\"50\">%2$d</xliff:g> clases</item>\n        <item quantity=\"other\"><xliff:g id=\"tracker_no\" example=\"8\">%1$d</xliff:g> rastreadores con <xliff:g id=\"class_no\" example=\"50\">%2$d</xliff:g> clases</item>\n    </plurals>\n    <plurals name=\"two_trackers_and_classes\">\n        <item quantity=\"one\">2 rastreadores con <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g> clases</item>\n        <item quantity=\"many\">Varios rastreadores <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g> clases</item>\n        <item quantity=\"other\">Varios rastreadores <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g> clases</item>\n    </plurals>\n    <plurals name=\"tracker_and_classes\">\n        <item quantity=\"one\">1 rastreador con <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g> clase</item>\n        <item quantity=\"many\">Varios rastreadores con <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g> clases</item>\n        <item quantity=\"other\">Varios rastreadores con <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g> clases</item>\n    </plurals>\n    <string name=\"toggle_class_listing\">Alternar catalogación de clase</string>\n    <string name=\"class_viewer\">Visor de clases</string>\n    <string name=\"credits\">Créditos</string>\n    <string name=\"third_party\">Bibliotecas e iconos de terceros</string>\n    <string name=\"license\">Licencia</string>\n    <string name=\"icon_picker\">Selector de iconos</string>\n    <string name=\"class_name\">Nombre de la Clase</string>\n    <string name=\"package_name\">Nombre del paquete</string>\n    <string name=\"shortcut_name\">Nombre del atajo (shortcut)</string>\n    <string name=\"create_shortcut\">Crear un atajo (shortcut)</string>\n    <string name=\"starting_activity\">Inicio de la actividad: <xliff:g id=\"activity_name\" example=\".main.MainActivity\">%1$s</xliff:g></string>\n    <string name=\"error_verbose_pin_shortcut\">El iniciador actual no admite PinShortcut. No se puede crear el atajo.</string>\n    <string name=\"error_creating_shortcut\">Error al crear un atajo (shortcut)</string>\n    <string name=\"empty_package_name\">Nombre del paquete vacío</string>\n    <string name=\"main_activity\">Actividad Principal</string>\n    <string name=\"user_id\">ID de usuario</string>\n    <string name=\"installer_app\">Aplicación instaladora</string>\n    <string name=\"date_updated\">Fecha de actualización</string>\n    <string name=\"date_installed\">Fecha de instalación</string>\n    <string name=\"more_info\">Más información</string>\n    <string name=\"sdk_flags\">Flags</string>\n    <string name=\"sdk_max\">Objetivo Máx</string>\n    <string name=\"sdk_min\">Min</string>\n    <string name=\"data_dir\">Directorio de datos</string>\n    <string name=\"source_dir\">Directorio fuente</string>\n    <string name=\"paths_and_directories\">Rutas &amp; Directorios</string>\n    <string name=\"user_app\">Aplicaciones del usuario</string>\n    <string name=\"system_app\">Aplicaciones del sistema</string>\n    <string name=\"app_info\">Información de la aplicación</string>\n    <string name=\"version_name_with_code\">Versión <xliff:g id=\"version_name\" example=\"2.5.17\">%1$s</xliff:g> (<xliff:g id=\"version_code\" example=\"365\">%2$d</xliff:g>)</string>\n    <string name=\"sort\">Clasificar</string>\n    <string name=\"user\">Usuario</string>\n    <string name=\"system\">Sistema</string>\n    <string name=\"app_not_installed\">Aplicación no instalada</string>\n    <string name=\"media_size\">Medios</string>\n    <string name=\"obb_size\">Obb</string>\n    <string name=\"cache_size\">Antememoria</string>\n    <string name=\"data_size\">Datos</string>\n    <string name=\"about\">Acerca de</string>\n    <string name=\"data_usage_msg\">Uso de datos</string>\n    <string name=\"data_transmitted\">Datos transmitidos</string>\n    <string name=\"data_received\">Datos recibidos</string>\n    <string name=\"sort_by_target_sdk\">SDK objetivo</string>\n    <string name=\"sort_by_domain\">Aplics. de usuario primero</string>\n    <string name=\"sort_by_package_name\">Nombre del paquete</string>\n    <string name=\"sort_by_app_label\">Etiqueta de aplicación</string>\n    <string name=\"manifest\">Manifiesto</string>\n    <string name=\"_undefined\">Indefinido</string>\n    <string name=\"required\">Requerido</string>\n    <string name=\"orientation_sensor\">Sensor de orientación</string>\n    <string name=\"orientation_user\">Usuario</string>\n    <string name=\"orientation_portrait\">Vertical</string>\n    <string name=\"orientation_no_sensor\">Sin sensor</string>\n    <string name=\"orientation_locked\">Bloqueado</string>\n    <string name=\"orientation_full_user\">Usuario completo</string>\n    <string name=\"orientation_full_sensor\">Sensor completo</string>\n    <string name=\"orientation_unspecified\">No especificado</string>\n    <string name=\"launch_mode_single_task\">Única tarea</string>\n    <string name=\"launch_mode_single_instance\">Única instancia</string>\n    <string name=\"launch_mode_multiple\">Múltiple</string>\n    <string name=\"base_apk\">APK de base</string>\n    <string name=\"choose_language\">Cambiar idioma</string>\n    <string name=\"auto\">Automático</string>\n    <string name=\"pref_app_language\">Idioma</string>\n    <string name=\"backup_all_users\">Todos los usuarios</string>\n    <string name=\"backup_multiple\">Respaldo múltiple</string>\n    <string name=\"obb_files_extracted_successfully\">Se extrajeron los archivos OBB</string>\n    <string name=\"failed_to_extract_obb_files\">No se pudieron extraer los archivos OBB</string>\n    <string name=\"backup_obb_media\">OBB y multimedia</string>\n    <string name=\"backup_apk_files\">Archivos APK</string>\n    <string name=\"installer_error_session_abandon\">No se pudo abandonar la sesión del instalador</string>\n    <string name=\"installer_error_session_create\">No se pudo crear una sesión de instalación</string>\n    <string name=\"installer_error_security\">No se pudo acceder a los archivos APK</string>\n    <string name=\"install_in_progress\">Instalando…</string>\n    <string name=\"package_installer\">Instalador de paquetes</string>\n    <string name=\"unblock_trackers\">Desbloquear rastreadores</string>\n    <string name=\"reinstall\">Reinstalar</string>\n    <string name=\"install_app_message\">Quieres instalar esta app\\?</string>\n    <string name=\"try_again\">Prueba de nuevo</string>\n    <string name=\"full_stop_tap_to_see_details\">Toca para ver detalles.</string>\n    <string name=\"operation_running\">Operación ejecutándose…</string>\n    <string name=\"batch_ops\">Operaciones por lotes (Batch)</string>\n    <string name=\"failed_to_fetch_package_info\">No se pudo obtener la información del paquete</string>\n    <string name=\"installer_error_generic\">Instalación fallida</string>\n    <string name=\"installer_error_storage\">No hay suficiente espacio de almacenamiento para instalar la app</string>\n    <string name=\"installer_error_bad_apks\">Se seleccionaron archivos APK no válidos</string>\n    <string name=\"installer_error_incompatible\">La app es incompatible con este dispositivo</string>\n    <string name=\"installer_error_conflict\">No se pudo instalar la app porque el nombre del paquete está en uso</string>\n    <string name=\"installer_error_blocked\">Instalación bloqueada por <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g></string>\n    <string name=\"installer_error_blocked_device\">dispositivo</string>\n    <string name=\"installer_error_aborted\">La instalación falló porque se canceló o la sesión se cerró inesperadamente</string>\n    <string name=\"toggle_default_app_ops\">Alternar operaciones de aplicación predeterminadas</string>\n    <string name=\"filter_apps_with_activities\">Con actividades</string>\n    <string name=\"are_you_sure\">¿Lo confirma\\?</string>\n    <string name=\"pref_remove_all_rules_msg\">Se otorgarán permisos, las operaciones de las apps y los componentes volverán a los valores predeterminados.</string>\n    <string name=\"pref_remove_all_rules\">Quitar todas las reglas</string>\n    <string name=\"website\">Sitio web</string>\n    <string name=\"run_in_termux\">Ejecutar en Termux</string>\n    <string name=\"open_in_termux\">Abrir en Termux</string>\n    <string name=\"export_icon\">Extraer icono</string>\n    <string name=\"no_matching_package_found\">No se encontró ninguna aplicación de esas</string>\n    <string name=\"block_unblock_trackers\">Bloquear/desbloquear rastreadores</string>\n    <string name=\"unblock\">Desbloquear</string>\n    <string name=\"block\">Bloquear</string>\n    <string name=\"clear\">Limpiar</string>\n    <string name=\"clear_data_message\">¿Confirma que quiere vaciar los datos de esta aplicación\\?</string>\n    <string name=\"skip_signature_checks\">Omitir comprobación de firmas</string>\n    <string name=\"yes\">Sí</string>\n    <string name=\"no\">No</string>\n    <string name=\"apply_to_system_apps_question\">¿Quiere aplicarlo también a las aplicaciones del sistema\\? Seleccione «No» si no está seguro.</string>\n    <string name=\"apply_to_system_apps\">Aplicar a aplicaciones del sistema</string>\n    <plurals name=\"app_signing_signature_schemes_pl\">\n        <item quantity=\"one\">Sistema de firma</item>\n        <item quantity=\"many\">Sistemas de firmas</item>\n        <item quantity=\"other\">Sistemas de firmas</item>\n    </plurals>\n    <plurals name=\"backup_exists_are_you_sure\">\n        <item quantity=\"one\">La copia de respaldo ya existe. ¿Quiere continuar\\?</item>\n        <item quantity=\"many\">Más de una aplicación ya tiene una copia de seguridad. ¿Estás seguro\\?</item>\n        <item quantity=\"other\">Más de una aplicación ya tiene una copia de seguridad. ¿Estás seguro\\?</item>\n    </plurals>\n    <string name=\"backup_options\">Opciones de respaldo</string>\n    <string name=\"delete_backup\">Eliminar respaldo</string>\n    <string name=\"backup\">Respaldo</string>\n    <string name=\"data\">Datos</string>\n    <string name=\"external_data\">Datos externos</string>\n    <string name=\"blocking_rules\">Reglas de bloqueo</string>\n    <string name=\"whats_new\">Novedades</string>\n    <string name=\"features\">Funciones</string>\n    <string name=\"components\">Componentes</string>\n    <string name=\"trackers\">Rastreadores</string>\n    <string name=\"installed_version\">Versión instalada</string>\n    <string name=\"select_all\">Seleccionar todo</string>\n    <string name=\"filter_apps_with_rules\">Aplicaciones con reglas</string>\n    <string name=\"filter_system_apps\">Aplicaciones del sistema</string>\n    <string name=\"filter_user_apps\">Aplicaciones de usuario</string>\n    <string name=\"filter\">Filtro</string>\n    <string name=\"package_name_is_installed_successfully\">Se instaló <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g></string>\n    <string name=\"termux\">Termux</string>\n    <string name=\"failed_to_parse_some_numbers\">No se pudo analizar algunos números</string>\n    <string name=\"only_works_in_root_or_adb_mode\">Sólo funcionan en modo root o ADB</string>\n    <string name=\"filtered_packages\">Paquetes filtrados</string>\n    <string name=\"input_signatures_description\">Firmas de entrada con espacios, por ejemplo <tt>com.facebook org.app2 com.app3</tt> etc.</string>\n    <string name=\"input_signatures\">Firmas de entrada</string>\n    <string name=\"failed_packages\">Paquetes fallidos</string>\n    <string name=\"no_tracker_found\">Sin rastreadores encontrados</string>\n    <string name=\"clear_app_cache_description\">Vaciar antememoria de todas las aplicaciones</string>\n    <string name=\"clear_app_cache\">Vaciar antememoria de aplicación</string>\n    <string name=\"clear_data_from_uninstalled_apps\">Limpiar datos de aplicaciones desinstaladas</string>\n    <string name=\"deny_app_ops_description\">Establecer un modo para las operaciones de las aplicaciones identificadas por los valores constantes, es decir, <tt>63</tt> o <tt>RUN_IN_BACKGROUND</tt></string>\n    <string name=\"block_components_dots\">Bloquear componentes…</string>\n    <string name=\"block_unblock_trackers_description\">Bloquear o desbloquear componentes de anuncios o rastreo en todas las aplicaciones instaladas</string>\n    <string name=\"clear_cache\">Vaciar antememoria</string>\n    <string name=\"pref_import_existing_msg\">Añada componentes desactivados por otras aplicaciones al Gestor de aplicaciones. Tenga cuidado al utilizar esta herramienta, dado que puede haber muchos falsos positivos. Elija solo aquellas aplicaciones de las que tenga certeza.</string>\n    <string name=\"pref_import_existing\">Importar reglas existentes</string>\n    <string name=\"source_code\">Código fuente</string>\n    <string name=\"update\">Actualizar</string>\n    <string name=\"install\">Instalar</string>\n    <plurals name=\"no_of_trackers\">\n        <item quantity=\"one\">%1$d rastreador</item>\n        <item quantity=\"many\">%1$d rastreadores</item>\n        <item quantity=\"other\">%1$d rastreadores</item>\n    </plurals>\n    <string name=\"manifest_viewer\">Visor de manifiestos</string>\n    <string name=\"external_apk_no_app_op\">El APK externo no tiene ninguna operación de aplicación</string>\n    <string name=\"changelog\">Lista de cambios</string>\n    <string name=\"one_click_ops\">Operaciones de 1-Click</string>\n    <string name=\"never_ask\">No volver a preguntar</string>\n    <string name=\"launch_app\">Lanzar</string>\n    <string name=\"failed_to_deny_dangerous_app_ops\">No se pudieron revocar todas las app ops peligrosas</string>\n    <string name=\"failed_to_deny_dangerous_perms\">No se pudieron revocar todos los permisos peligrosos</string>\n    <string name=\"failed_to_reset_app_ops\">No se pudo resetear las app ops</string>\n    <string name=\"failed_to_revoke_permission\">No se pudo revocar el permiso</string>\n    <string name=\"failed_to_grant_permission\">No se pudo conceder el permiso</string>\n    <plurals name=\"alert_failed_to_disable_trackers\">\n        <item quantity=\"one\">No se pudieron desactivar los rastreadores de %1$d aplicación</item>\n        <item quantity=\"many\">No se han podido desactivar los rastreadores de %1$d aplicaciones</item>\n        <item quantity=\"other\">No se pudieron desactivar los rastreadores de %1$d aplicaciones</item>\n    </plurals>\n    <string name=\"unknown_op\">Operación desconocida</string>\n    <string name=\"sort_by_tracker_components\">Rastreadores primero</string>\n    <string name=\"deny_dangerous_permissions\">Denegar permisos peligrosos</string>\n    <string name=\"sort_by_denied_permissions\">Denegado primero</string>\n    <string name=\"sort_by_dangerous_permissions\">Peligroso primero</string>\n    <string name=\"sort_by_permission_names\">Nombre del permiso</string>\n    <string name=\"sort_by_app_ops_values\">Valor de las app ops</string>\n    <string name=\"sort_by_denied_app_ops\">Denegado primero</string>\n    <string name=\"sort_by_app_ops_names\">Nombre de las app ops</string>\n    <string name=\"deny_dangerous_app_ops\">Denegar app ops peligrosas</string>\n    <string name=\"reset_to_default\">Restablecer valor predeterminado</string>\n    <string name=\"sort_by_component_name\">Nombre del componente</string>\n    <string name=\"block_trackers\">Bloquear rastreadores</string>\n    <string name=\"sort_by_wifi_data\">Datos Wi-Fi</string>\n    <string name=\"version\">Versión</string>\n    <string name=\"pref_about_msg\">Versión, licencia y créditos del Gestor de aplicaciones.</string>\n    <string name=\"apply\">Aplicar</string>\n    <string name=\"select_theme\">Tema</string>\n    <string name=\"night\">Nocturno</string>\n    <string name=\"day\">Diurno</string>\n    <string name=\"battery_mode\">Modo de batería</string>\n    <string name=\"follow_system\">Según el sistema</string>\n    <string name=\"pref_app_theme\">Tema de la aplicación</string>\n    <string name=\"pref_import_blocker_msg\">Importar reglas de bloqueo desde Blocker, cada archivo contiene reglas para un solo paquete.</string>\n    <string name=\"pref_import_watt_msg\">Importar reglas de bloqueo desde Watt, cada archivo que contiene las reglas para un solo paquete nombrado como <tt>packagename.xml</tt> etc.</string>\n    <string name=\"pref_import_msg\">Importar reglas de bloqueo previamente exportadas desde el Gestor de aplicaciones.</string>\n    <string name=\"pref_export_msg\">Exportar reglas de bloqueo configuradas en el Gestor de aplicaciones al almacenamiento externo.</string>\n    <string name=\"keyboard_type\">Tipo de teclado</string>\n    <string name=\"the_operation_was_successful\">Hecho</string>\n    <plurals name=\"alert_failed_to_clear_data\">\n        <item quantity=\"one\">No se ha podido borrar el dato de la aplicación %1$d</item>\n        <item quantity=\"many\">No se han podido borrar los datos de la aplicación %1$d</item>\n        <item quantity=\"other\">No se han podido borrar los datos de la aplicación %1$d</item>\n    </plurals>\n    <string name=\"backup_restore\">Respaldo/restauración</string>\n    <string name=\"memory_virtual_memory\">Memoria: %1$s, memoria virtual: %2$s</string>\n    <plurals name=\"failed_to_import_files\">\n        <item quantity=\"one\">No se ha podido importar el fichero %1$d.</item>\n        <item quantity=\"many\">No se han podido importar los ficheros %1$d.</item>\n        <item quantity=\"other\">No se han podido importar los ficheros %1$d.</item>\n    </plurals>\n    <string name=\"sort_by_times_opened\">Veces abierto</string>\n    <string name=\"no_app_ops\">No hay operaciones de aplicación</string>\n    <string name=\"force_stop\">Forzar detención</string>\n    <string name=\"view_in_settings\">Ver en Configuración</string>\n    <string name=\"choose\">Elegir</string>\n    <string name=\"profile_block_trackers_msg\">Bloquea los rastreadores en las aplicaciones</string>\n    <string name=\"profile_clear_data_msg\">Vacía los datos de las aplicaciones</string>\n    <string name=\"profile_force_stop_msg\">Fuerza la detención de las aplicaciones</string>\n    <string name=\"input_profile_name\">Nombre del perfil</string>\n    <string name=\"input_profile_name_description\">El nombre de perfil no puede contener ningún espacio.</string>\n    <string name=\"tap_to_see_details\">Toque para ver detalles</string>\n    <string name=\"no_apps\">Ninguna aplicación</string>\n    <string name=\"touchscreen_no_touch\">Sin tocar</string>\n    <string name=\"navigation_trackball\">Bola de desplazamiento</string>\n    <string name=\"locale_split_for_feature\"><xliff:g id=\"split_name\" example=\"English\">%1$s</xliff:g> lugar para la función <xliff:g id=\"feature_name\" example=\"Visualizer\">%2$s</xliff:g></string>\n    <string name=\"density_split_for_feature\"><xliff:g id=\"split_name\" example=\"xxdpi\">%1$s</xliff:g> (<xliff:g id=\"dpi_no\" example=\"480\">%2$d</xliff:g> DPI) recursos para la función <xliff:g id=\"feature_name\" example=\"Visualizer\">%3$s</xliff:g></string>\n    <string name=\"split_feature_name\">Función: <xliff:g id=\"feature_name\" example=\"Visualizer\">%1$s</xliff:g></string>\n    <plurals name=\"alert_failed_to_block_components\">\n        <item quantity=\"one\">No se han podido bloquear los componentes de la aplicación %1$d</item>\n        <item quantity=\"many\">No se han podido bloquear componentes para %1$d aplicaciones</item>\n        <item quantity=\"other\">No se han podido bloquear componentes para %1$d aplicaciones</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_unblock_trackers\">\n        <item quantity=\"one\">No se han podido desbloquear los rastreadores de la aplicación %1$d</item>\n        <item quantity=\"many\">No se han podido desbloquear los rastreadores de %1$d aplicaciones</item>\n        <item quantity=\"other\">No se han podido desbloquear los rastreadores de %1$d aplicaciones</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_delete_backup\">\n        <item quantity=\"one\">No se ha podido eliminar la copia de seguridad %1$d</item>\n        <item quantity=\"many\">No se han podido eliminar %1$d copias de seguridad</item>\n        <item quantity=\"other\">No se han podido eliminar %1$d copias de seguridad</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_restore\">\n        <item quantity=\"one\">No se ha podido restaurar la aplicación %1$d</item>\n        <item quantity=\"many\">No se han podido restaurar %1$d aplicaciones</item>\n        <item quantity=\"other\">No se han podido restaurar %1$d aplicaciones</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_backup\">\n        <item quantity=\"one\">No se pudo respaldar %1$d aplicación</item>\n        <item quantity=\"many\">No se ha podido hacer una copia de seguridad de %1$d aplicaciones</item>\n        <item quantity=\"other\">No se ha podido hacer una copia de seguridad de %1$d aplicaciones</item>\n    </plurals>\n    <plurals name=\"failed_to_backup_some_apk_files\">\n        <item quantity=\"one\">No se ha podido hacer una copia de seguridad de la aplicación %1$d</item>\n        <item quantity=\"many\">No se han podido hacer una copias de seguridad de %1$d aplicaciones</item>\n        <item quantity=\"other\">No se han podido hacer una copias de seguridad de %1$d aplicaciones</item>\n    </plurals>\n    <string name=\"restore\">Restaurar</string>\n    <string name=\"input_app_ops_description\">Introducir nombre y/o constantes de la app op con espacios, por ejemplo <tt>WAKE_LOCK 63 72 CAMERA</tt> etc.</string>\n    <plurals name=\"alert_failed_to_disable_background\">\n        <item quantity=\"one\">No se pudo evitar que la app %1$d se ejecutara en segundo plano</item>\n        <item quantity=\"many\">No se pudo evitar que %1$d aplicaciones se ejecutaran en segundo plano</item>\n        <item quantity=\"other\">No se pudo evitar que la apps %1$d se ejecutaran en segundo plano</item>\n    </plurals>\n    <string name=\"uses_feature\">Objetivos de las funciones</string>\n    <plurals name=\"no_of_splits\">\n        <item quantity=\"one\">%1$d dividido</item>\n        <item quantity=\"many\">%1$d divididos</item>\n        <item quantity=\"other\">%1$d divididos</item>\n    </plurals>\n    <string name=\"launch_mode_single_top\">Parte superior</string>\n    <string name=\"installer_error_lidl_rom\">Su ROM no es compatible con Rootless Installer.</string>\n    <string name=\"reject_time\">Tiempo de rechazo</string>\n    <string name=\"accept_time\">Tiempo de aceptación</string>\n    <string name=\"toggle_kill_for_system_apps\">Cambiar las aplicaciones matadas del sistema</string>\n    <string name=\"pid_and_ppid\">Id. de proceso: %1$d, id. de proceso primario: %2$d</string>\n    <plurals name=\"no_of_times_opened\">\n        <item quantity=\"one\">%1$d vez</item>\n        <item quantity=\"many\">%1$d veces</item>\n        <item quantity=\"other\">%1$d veces</item>\n    </plurals>\n    <string name=\"input_permissions_description\">Permisos de acceso con espacios, p. ej. <tt>com.permission.GET_ACCOUNTS android.permission.ACCESS_MEDIA_LOCATION</tt> etc. Usa <tt>*</tt> para solicitar todos los permisos.</string>\n    <string name=\"input_permissions\">Permisos de entrada</string>\n    <string name=\"profile_clear_cache_msg\">Vacía la antememoria de las aplicaciones</string>\n    <string name=\"allow_routine_ops_msg\">Permitir que el perfil se utilice en las operaciones de rutinarias</string>\n    <string name=\"profile_state\">Estado del perfil</string>\n    <string name=\"allow_routine_ops\">Permitir ops rutinarias</string>\n    <string name=\"adb_over_tcp\">ADB sobre TCP</string>\n    <string name=\"pref_mode_of_operations\">Modo de operación</string>\n    <string name=\"send_selected\">Enviar seleccionado</string>\n    <string name=\"ecc\">Criptografía de curva elíptica</string>\n    <string name=\"rsa\">RSA</string>\n    <string name=\"aes\">AES</string>\n    <string name=\"none\">Ninguno</string>\n    <string name=\"pref_encryption_msg\">Cifrado para los respaldos.</string>\n    <string name=\"encryption\">Cifrado</string>\n    <string name=\"select_user\">Seleccionar usuario</string>\n    <string name=\"failed_to_duplicate_profile\">No se pudo duplicar el perfil</string>\n    <string name=\"duplicate\">Duplicar</string>\n    <string name=\"new_profile\">Perfil nuevo</string>\n    <string name=\"un_apkm\">UnApkm</string>\n    <string name=\"in_progress\">En proceso</string>\n    <string name=\"conversion_failed\">Falló la conversión.</string>\n    <string name=\"select_apk\">Seleccionar APK</string>\n    <string name=\"send_crash_report\">Enviar informe de error</string>\n    <string name=\"tap_to_submit_crash_report\">Toque para enviar un informe de error.</string>\n    <string name=\"am_crashed\">El Gestor de aplicaciones se cerró inesperadamente</string>\n    <string name=\"filter_running_apps\">Aplicaciones en ejecución</string>\n    <string name=\"copy\">Copiar</string>\n    <string name=\"view_missing_signatures\">Pulsa para ver o enviar firmas que aún no están presentes en la base de datos de bibliotecas del App Manager.</string>\n    <string name=\"lib_details\">Detalles de la biblioteca</string>\n    <string name=\"no_libs\">Sin bibliotecas</string>\n    <string name=\"scanner\">Escáner</string>\n    <string name=\"sys_config\">Configuración del sistema</string>\n    <string name=\"only_install\">Solo instalar</string>\n    <string name=\"app_signing_install_without_data_loss\">Si desactivó la verificación de firmas, puede utilizar la opción <b>Solo instalar</b> para instalar la aplicación sin perder datos.</string>\n    <string name=\"app_data_will_be_lost\">Se perderán los datos existentes.</string>\n    <string name=\"app_signing_signature_mismatch_for_system_apps\">No se pudo instalar la aplicación porque una aplicación del sistema con una firma diferente tiene este nombre de paquete.</string>\n    <string name=\"do_you_want_to_uninstall_and_install\">¿Quiere desinstalar e instalar la aplicación de nuevo\\?</string>\n    <string name=\"usage_access_not_supported\">No se pudo solicitar el acceso al uso, ya que la página de configuración correspondiente no existe.</string>\n    <string name=\"non_critical_exts\">Extensiones no cruciales</string>\n    <string name=\"critical_exts\">Extensiones cruciales</string>\n    <string name=\"dsa_affine_y\">Afinar coordenada y</string>\n    <string name=\"dsa_affine_x\">Afinar coordenada x</string>\n    <string name=\"rsa_modulus\">Módulo</string>\n    <string name=\"rsa_exponent\">Exponente</string>\n    <string name=\"format\">Formato</string>\n    <string name=\"public_key\">Clave pública</string>\n    <string name=\"algorithm\">Algoritmo</string>\n    <string name=\"app_signing_signature\">Firma</string>\n    <string name=\"checksums\">Sumas de comprobación</string>\n    <string name=\"serial_no\">Número de serie</string>\n    <string name=\"not_yet_valid\">No es válida aún</string>\n    <string name=\"expired\">Caducada</string>\n    <string name=\"valid\">Válida</string>\n    <string name=\"validity\">Vigencia</string>\n    <string name=\"type\">Tipo</string>\n    <string name=\"expiry_date\">Fecha de caducidad</string>\n    <string name=\"issued_date\">Fecha de emisión</string>\n    <string name=\"issuer\">Emisor</string>\n    <string name=\"subject\">Asunto</string>\n    <string name=\"filter_apps_with_backups\">Con copia de respaldo</string>\n    <string name=\"sort_by_backup\">Respaldadas primero</string>\n    <string name=\"failed_to_uninstall_updates\">No se pudieron desinstalar las actualizaciones de <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g>.</string>\n    <string name=\"update_uninstalled_successfully\">Se desinstalaron las actualizaciones de <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g>.</string>\n    <string name=\"uninstall_updates\">Desinstalar actualizaciones</string>\n    <string name=\"allow_open_pgp_operation\">Toque para permitir al Gestor de aplicaciones utilizar OpenPGP</string>\n    <string name=\"confirm_installation\">Confirmar instalación</string>\n    <string name=\"pref_backup_flags_msg\">Al añadir un reajuste para las opciones del respaldo se elimina la carga de seleccionar flags cada vez que se hace un Respaldar/Restaurar.</string>\n    <string name=\"pref_compression_method\">Método de compresión</string>\n    <string name=\"rules\">Reglas</string>\n    <string name=\"other\">Otros</string>\n    <string name=\"changes_not_saved\">Cambios no guardados</string>\n    <string name=\"sort_by_memory_usage\">Uso de memoria</string>\n    <string name=\"sort_by_apps_first\">Aplicaciones primero</string>\n    <string name=\"sort_by_process_name\">Nombre del proceso</string>\n    <string name=\"sort_by_process_id\">Id. del proceso</string>\n    <string name=\"filter_apps\">Aplicaciones</string>\n    <string name=\"apps\">Aplicaciones</string>\n    <string name=\"routine_ops\">Operaciones rutinarias</string>\n    <string name=\"apply_now\">Aplicar ahora…</string>\n    <string name=\"keystore\">Almacén de claves</string>\n    <string name=\"no_profiles\">Sin perfiles</string>\n    <string name=\"profiles\">Perfiles</string>\n    <string name=\"open_pgp_provider\">Proveedor de OpenPGP</string>\n    <string name=\"systemless_app\">Aplicación no de sistema</string>\n    <string name=\"cancel\">Cancelar</string>\n    <string name=\"ok\">Aceptar</string>\n    <string name=\"input_backup_name_description\">El nombre del respaldo no debe empezar con un dígito ni debe contener ningún espacio. Déjelo vacío si quiere usar la fecha y hora actuales.</string>\n    <string name=\"input_backup_name\">Nombre del respaldo</string>\n    <string name=\"downgrade\">Desactualizar</string>\n    <string name=\"process_state_with_extra\">Estado: <xliff:g id=\"process_state\" example=\"Sleeping\">%1$s</xliff:g> (<xliff:g id=\"state_extra\" example=\"High priority\">%2$s</xliff:g>)</string>\n    <string name=\"process_state\">Estado: <xliff:g id=\"process_state\" example=\"Sleeping\">%1$s</xliff:g></string>\n    <string name=\"state_multithreaded\">Multiproceso</string>\n    <string name=\"state_foreground\">Primer plano</string>\n    <string name=\"state_session_leader\">Líder de la sesión</string>\n    <string name=\"state_locked_memory\">Memoria bloqueada</string>\n    <string name=\"state_low_priority\">Baja prioridad</string>\n    <string name=\"state_high_priority\">Alta prioridad</string>\n    <string name=\"state_unknown\">Desconocido</string>\n    <string name=\"state_waking\">Despertando</string>\n    <string name=\"state_wake_kill\">Matar el despertar</string>\n    <string name=\"state_idle\">Inactivo</string>\n    <string name=\"state_parked\">Estacionado</string>\n    <string name=\"state_zombie\">Zombie</string>\n    <string name=\"state_dead\">Muerto</string>\n    <string name=\"state_trace_stop\">Parar rastro</string>\n    <string name=\"state_device_io\">Dispositivo I/O</string>\n    <string name=\"state_sleeping\">Durmiendo</string>\n    <string name=\"touchscreen_finger\">Dedo</string>\n    <string name=\"touchscreen_stylus\">Stylus (lápiz óptico)</string>\n    <string name=\"navigation_wheel\">Rueda</string>\n    <string name=\"navigation_dial_pad\">Teclado de marcación</string>\n    <string name=\"navigation_no_nav\">Sin navegación</string>\n    <string name=\"keyboard_12_keys\">12 claves</string>\n    <string name=\"keyboard_qwerty\">QWERTY</string>\n    <string name=\"keyboard_no_keys\">Sin teclas</string>\n    <string name=\"orientation_user_portrait\">Retrato del usuario</string>\n    <string name=\"orientation_user_landscape\">Escenario del usuario</string>\n    <string name=\"orientation_sensor_portrait\">Sensor del retrato</string>\n    <string name=\"orientation_sensor_landscape\">Sensor panorámico</string>\n    <string name=\"orientation_reverse_landscape\">Escenario invertido</string>\n    <string name=\"orientation_reverse_portrait\">Retrato invertido</string>\n    <string name=\"orientation_landscape\">Horizontal</string>\n    <string name=\"orientation_behind\">Detrás</string>\n    <string name=\"locale_split_for_base_apk\"><xliff:g id=\"split_name\" example=\"English\">%1$s</xliff:g> lugar para la base APK</string>\n    <string name=\"abi_split_for_base_apk\"><xliff:g id=\"split_name\" example=\"arm64_v8a\">%1$s</xliff:g> código para la base APK</string>\n    <string name=\"abi_split_for_feature\"><xliff:g id=\"split_name\" example=\"arm64_v8a\">%1$s</xliff:g> código para <xliff:g id=\"feature_name\" example=\"Visualizer\">%2$s</xliff:g></string>\n    <string name=\"density_split_for_base_apk\"><xliff:g id=\"split_name\" example=\"xxdpi\">%1$s</xliff:g> (<xliff:g id=\"dpi_no\" example=\"480\">%2$d</xliff:g> DPI) recursos para la base APK</string>\n    <string name=\"unknown_split_for_base_apk\"><xliff:g id=\"split_name\" example=\"some_split\">%1$s</xliff:g> para base APK</string>\n    <string name=\"unknown_split_for_feature\"><xliff:g id=\"split_name\" example=\"some_split\">%1$s</xliff:g> para característica <xliff:g id=\"feature_name\" example=\"Visualizer\">%2$s</xliff:g></string>\n    <string name=\"installer_error_session_commit\">No se pudo confirmar los archivos APK</string>\n    <string name=\"installer_error_session_write\">No se pudo escribir en la sesión del instalador</string>\n    <plurals name=\"verified_with_warning\">\n        <item quantity=\"one\">Verificado con la advertencia de %d</item>\n        <item quantity=\"many\">Verificado con las advertencias de %d</item>\n        <item quantity=\"other\">Verificado con las advertencias de %d</item>\n    </plurals>\n    <plurals name=\"missing_signatures\">\n        <item quantity=\"one\">Falta la firma %1$d</item>\n        <item quantity=\"many\">Faltan %1$d firmas</item>\n        <item quantity=\"other\">Faltan %1$d firmas</item>\n    </plurals>\n    <plurals name=\"libraries\">\n        <item quantity=\"one\">Biblioteca %1$d</item>\n        <item quantity=\"many\">bibliotecas %1$d</item>\n        <item quantity=\"other\">bibliotecas %1$d</item>\n    </plurals>\n    <plurals name=\"classes\">\n        <item quantity=\"one\">Clase %1$d</item>\n        <item quantity=\"many\">Clases %1$d</item>\n        <item quantity=\"other\">Clases %1$d</item>\n    </plurals>\n    <string name=\"input_app_ops\">Introducir app ops</string>\n    <string name=\"clear_data_from_uninstalled_apps_description\">Limpiar datos desde las aplicaciones que son desinstaladas con <tt>DONT_DELETE_DATA</tt> flag</string>\n    <string name=\"ago\">hace</string>\n    <plurals name=\"alert_failed_to_force_stop\">\n        <item quantity=\"one\">No se pudo forzar la detención de %1$d aplicación</item>\n        <item quantity=\"many\">No se pudo forzar la detención de %1$d aplicaciones</item>\n        <item quantity=\"other\">No se pudo forzar la detención de %1$d aplicaciones</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_uninstall\">\n        <item quantity=\"one\">No se ha podido desinstalar %1$d app</item>\n        <item quantity=\"many\">No se han podido desinstalar %1$d aplicaciones</item>\n        <item quantity=\"other\">No se han podido desinstalar %1$d aplicaciones</item>\n    </plurals>\n    <string name=\"apk_updater\">Actualizador APK</string>\n    <string name=\"external_multiple_data_dir\">Directorio de datos externos <xliff:g id=\"dir_no\" example=\"1\">%1$d</xliff:g></string>\n    <string name=\"failed_to_disable_op\">No se pudo deshabilitar la app op solicitada</string>\n    <string name=\"failed_to_enable_op\">No se pudo activar la app op solicitada</string>\n    <string name=\"failed_to_stop\">No se pudo detener <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g>.</string>\n    <string name=\"failed_to_uninstall\">No se pudo desinstalar <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g>.</string>\n    <string name=\"type_long\">Entero largo</string>\n    <string name=\"type_int\">Entero</string>\n    <string name=\"boolean_value\">Valor booleano</string>\n    <string name=\"decimal_value\">Valor decimal</string>\n    <string name=\"integer_value\">Valor de entero</string>\n    <string name=\"long_integer_value\">Valor de entero largo</string>\n    <string name=\"set_custom_app_op\">Configurar app op personalizada</string>\n    <string name=\"resend_intent\">Reenviar Intent</string>\n    <string name=\"share\">Compartir</string>\n    <string name=\"extras\">Extras</string>\n    <string name=\"category\">Categorías</string>\n    <string name=\"uri\">URI</string>\n    <string name=\"mime_type\">Tipo MIME</string>\n    <string name=\"action\">Acción</string>\n    <string name=\"result_code\">Código de resultado</string>\n    <string name=\"activity_result\">Resultado de la actividad</string>\n    <string name=\"send_edited_intent\">Enviar intent editada</string>\n    <string name=\"matching_activities\">Actividades de emparejamiento</string>\n    <string name=\"value\">Valor</string>\n    <string name=\"filter_apps_with_splits\">Con splits</string>\n    <string name=\"set_app_op_mode\">Configurar el mode de app ops</string>\n    <string name=\"magisk_hide_enabled\">MagiskHide</string>\n    <string name=\"pref_backup_android_keystore_msg\">No todas las aplicaciones funcionarán después de una restauración. Restaurar KeyStore no funciona en la mayoría de los dispositivos.</string>\n    <string name=\"pref_backup_android_keystore\">Respaldar aplicaciones con el almacén de claves de Android</string>\n    <string name=\"keep_data_and_app_signing_signatures\">Mantener datos y firmas</string>\n    <string name=\"this_action_cannot_be_undone\">Esta acción no puede deshacerse.</string>\n    <string name=\"no_app_ops_permission\">No tiene permitido mostrar las operaciones de aplicación</string>\n    <string name=\"input_keystore_alias_pass_description\">Inserte la contraseña del alias <b>%1$s</b>. Puede dejarla vacía si la contraseña es la misma que la del almacén de claves.</string>\n    <string name=\"input_keystore_alias_pass\">Contraseña del alias <b>%1$s</b></string>\n    <string name=\"input_keystore_pass_msg\">Toque aquí para introducir la contraseña del almacén de claves</string>\n    <string name=\"input_keystore_pass_description\">Proporcione la contraseña del almacén de claves del Gestor de aplicaciones. Si esta es la primera vez que ve esto, sírvase de un generador de contraseñas para crear una y guárdela en un lugar seguro antes de introducirla aquí.</string>\n    <string name=\"input_keystore_pass\">Introduzca la contraseña del almacén de claves</string>\n    <string name=\"splits\">Partes</string>\n    <string name=\"source_stamp_verified\">SourceStamp (Sello de la fuente) verificado.</string>\n    <string name=\"not_verified\">No verificado</string>\n    <string name=\"verified\">Verificado</string>\n    <string name=\"pref_signature_schemes_msg\">Se deben seleccionar al menos los esquemas v1 y v2 para una mayor compatibilidad. El esquema v4 requiere v2 o v3.</string>\n    <string name=\"v4_scheme\">Esquema v4 (desde Android 11)</string>\n    <string name=\"v3_scheme\">Esquema v3 (desde Android 9.0)</string>\n    <string name=\"v2_scheme\">Esquema v2 (desde Android 7.0)</string>\n    <string name=\"v1_scheme\">Esquema v1 (desde Android 1.0)</string>\n    <string name=\"pref_apk_signing_msg\">Establecer esquema de firmas, clave de firma personalizada, etc.</string>\n    <string name=\"apk_signing\">Firma de APK</string>\n    <string name=\"pref_sign_apk_msg\">Firme los archivos APK antes de instalarlos.</string>\n    <string name=\"pref_sign_apk\">Firmar APK</string>\n    <string name=\"install_location_prefer_external\">Preferir externa</string>\n    <string name=\"install_location_internal_only\">Solo interna</string>\n    <string name=\"install_location\">Ubicación de la instalación</string>\n    <string name=\"installer\">Instalador</string>\n    <string name=\"comment\">Comentario</string>\n    <string name=\"close\">Cerrar</string>\n    <string name=\"no_root\">No root</string>\n    <string name=\"root\">Raíz (root)</string>\n    <string name=\"user_profile_with_id\">Perfil: %1$s (%2$d)</string>\n    <string name=\"advanced\">Avanzado</string>\n    <string name=\"simple\">Sencillo</string>\n    <string name=\"enabled\">Activado</string>\n    <string name=\"options\">Opciones</string>\n    <string name=\"off\">Apagado</string>\n    <string name=\"on\">Encendido</string>\n    <string name=\"profile_state_msg\">Estado personalizado de encendido/apagado para este perfil</string>\n    <string name=\"interceptor\">Interceptador</string>\n    <string name=\"backup_internal_data_description\">Hacer copia de respaldo de las carpetas de datos internos.</string>\n    <string name=\"backup_apk_files_description\">Respaldo solo de los archivos APK del directorio de origen, «splits» incluidos.</string>\n    <string name=\"backup_obb_media_description\">Respaldo de OBB y multimedia.</string>\n    <string name=\"board_name\">Placa</string>\n    <string name=\"drm_free_apkm_msg\">El archivo APKM no tiene DRM; no hay necesidad de convertirlo en APKS.</string>\n    <string name=\"restore_msg\">Restaurar aplicaciones con datos</string>\n    <string name=\"backup_msg\">Respaldar aplicaciones con datos</string>\n    <string name=\"restore_latest_msg\">Restaurar las aplicaciones ya instaladas cuyos códigos de versión superan los de la versión instalada.</string>\n    <string name=\"restore_latest\">Restaurar respaldos más recientes</string>\n    <string name=\"restore_not_installed_msg\">Restaurar la copia de base de las aplicaciones que no están instaladas actualmente.</string>\n    <string name=\"restore_not_installed\">Restaurar aplicaciones no instaladas</string>\n    <string name=\"restore_all_msg\">Restaurar la copia de base de todas las aplicaciones respaldadas.</string>\n    <string name=\"restore_all\">Restaurar todas las aplicaciones</string>\n    <string name=\"backup_apps_with_changes_msg\">Rehacer las copias de respaldo de las aplicaciones con los cambios desde la última copia. Incluyen cambios en el tamaño, la versión, la última hora de inicio.</string>\n    <string name=\"backup_apps_with_changes\">Respaldo de aplicaciones con cambios</string>\n    <string name=\"redo_existing_backups_msg\">Rehacer copia de respaldo para aplicaciones instaladas sin copias previas.</string>\n    <string name=\"redo_existing_backups\">Rehacer copias existentes</string>\n    <string name=\"verify_and_redo_backups_msg\">Verificar la integridad de los respaldos anteriores y rehacer las copias de seguridad en las que falle el control de integridad.</string>\n    <string name=\"verify_and_redo_backups\">Verificar y rehacer copias de respaldo</string>\n    <string name=\"backup_apps_without_backups_msg\">Respaldo de aplicaciones sin ninguna copia de seguridad previa.</string>\n    <string name=\"backup_apps_without_backups\">Respaldo de aplicaciones sin copias de seguridad</string>\n    <string name=\"backup_all_apps_msg\">Respaldo de todas las aplicaciones instaladas.</string>\n    <string name=\"backup_all_apps\">Respaldo de todas las apps</string>\n    <string name=\"backup_custom_users_description\">Realizar copias solo para los usuarios especificados</string>\n    <string name=\"backup_custom_users\">Usuarios personalizados</string>\n    <string name=\"bootloader\">Gestor de arranque</string>\n    <string name=\"encrypted\">Cifrado</string>\n    <string name=\"unencrypted\">Sin cifrado</string>\n    <string name=\"no_volumes_found\">No se pudo encontrar ningún volumen con permiso de escritura.</string>\n    <string name=\"pref_backup_volume_msg\">Seleccione el volumen o el disco donde se almacenarán las copias.</string>\n    <string name=\"backup_volume\">Volumen de copia de respaldo</string>\n    <string name=\"pref_backup_restore_msg\">Personalizar copia de respaldo/restauración.</string>\n    <string name=\"disable_background_run_description\">Establece el modo <i>ignorar</i> para las siguientes aplicaciones: <tt>RUN_IN_BACKGROUND</tt> (del Androide 7.0) y <tt>RUN_ANY_IN_BACKGROUND</tt> (desde Android 9).</string>\n    <string name=\"failed_to_enable_magisk_hide\">No se pudo activar MagiskHide</string>\n    <string name=\"failed_to_disable_magisk_hide\">No se pudo desactivar MagiskHide</string>\n    <string name=\"window_size\">Tamaño de ventana</string>\n    <string name=\"refresh_rate\">Tasa de actualización</string>\n    <string name=\"scaling_factor\">Factor de escalada</string>\n    <string name=\"size\">Tamaño</string>\n    <string name=\"density\">Densidad</string>\n    <string name=\"screen\">Pantalla</string>\n    <string name=\"hardware\">Hardware</string>\n    <string name=\"permissive\">Permisivo</string>\n    <string name=\"enforcing\">Enforzando</string>\n    <string name=\"selinux\">SELinux</string>\n    <string name=\"patch_level\">Nivel del parche</string>\n    <string name=\"backup_skip_signature_checks_description\">Para restaurar respaldos que o fallan en la verificación del checksum o tiene firmas diferentes APK diferente a los respaldos anteriores.</string>\n    <string name=\"backup_multiple_description\">Crear una copia de respaldo <i>con nombre</i> en lugar del respaldo de base.</string>\n    <string name=\"backup_rules_description\">Back up de reglas configuradas en App Manager.</string>\n    <string name=\"backup_extras_description\">Respaldos de los permisos de las aplicaciones, ahorro de batería, y opciones de uso de datos, estado de MagiskHide, SSAID, etc.</string>\n    <string name=\"backup_extras\">Extras</string>\n    <string name=\"backup_cache_description\">Respaldar carpetas <b>cache</b>, <b>no_cache</b> y <b>no_backup</b>.</string>\n    <string name=\"backup_external_data_description\">Hacer una copia de respaldo de las carpetas de datos externos.</string>\n    <string name=\"set_mode_for_app_ops_dots\">Establecer modo para las app ops…</string>\n    <string name=\"security\">Seguridad</string>\n    <string name=\"battery\">Batería</string>\n    <string name=\"graphics\">Gráficos</string>\n    <string name=\"cpu\">CPU</string>\n    <string name=\"users\">Usuarios</string>\n    <string name=\"languages\">Idiomas</string>\n    <string name=\"battery_capacity\">Capacidad</string>\n    <string name=\"memory\">Memoria</string>\n    <string name=\"vendor\">Proveedor</string>\n    <string name=\"gles_version\">Versión de OpenGL ES</string>\n    <string name=\"no_of_cores\">Núcleos</string>\n    <string name=\"support_architectures\">Arquitecturas admitidas</string>\n    <string name=\"security_providers\">Proveedores de seguridad</string>\n    <string name=\"kernel\">Kernel</string>\n    <string name=\"manufacturer\">Fabricante</string>\n    <string name=\"model\">Modelo</string>\n    <string name=\"brand_name\">Marca</string>\n    <string name=\"pref_about_device_msg\">Información básica del dispositivo, como el sistema Android, la CPU, la GPU, la RAM, la batería, etc.</string>\n    <string name=\"about_device\">Acerca del dispositivo</string>\n    <string name=\"app_signing_signature_schemes\">Esquemas de la firma</string>\n    <plurals name=\"alert_failed_to_set_app_ops\">\n        <item quantity=\"one\">No se han podido establecer las operaciones de la aplicación %1$d</item>\n        <item quantity=\"many\">No se han podido establecer las operaciones para %1$d aplicaciones</item>\n        <item quantity=\"other\">No se han podido establecer las operaciones para %1$d aplicaciones</item>\n    </plurals>\n    <plurals name=\"no_of_components\">\n        <item quantity=\"one\">%1$d componente</item>\n        <item quantity=\"many\">%1$d componentes</item>\n        <item quantity=\"other\">%1$d componentes</item>\n    </plurals>\n    <string name=\"installer_app_message\">Seleccione <b>Elegir</b> para escoger de entre las aplicaciones instaladas, o bien, <b>Personalizado</b> para especificar un nombre de paquete personalizado.</string>\n    <string name=\"specify_custom_name\">Personalizado</string>\n    <string name=\"verified_using_unreliable_hash\">Verificado con una suma no fidedigna</string>\n    <string name=\"working_on_adb_mode\">Trabajando en modo ADB</string>\n    <string name=\"screen_lock_not_enabled\">Elija un bloqueo de pantalla en la configuración de Android o elimine los datos de la aplicación.</string>\n    <string name=\"isolated\">Aislado</string>\n    <string name=\"last_actions\">Últimas acciones</string>\n    <string name=\"pref_enable_disable_features_msg\">Activar o desactivar funciones en el gestor de aplicaciones.</string>\n    <string name=\"input_app_ops_description_profile\">\"Introducir los nombres de las operaciones de aplicación y/o las constantes con espacios, por ejemplo, <tt>WAKE_LOCK  63 72 CAMERA</tt>, etc. Utiliza <tt>*</tt> para aplicar todas las operaciones de aplicación configuradas.\"</string>\n    <string name=\"user_with_id\">Usuario: <xliff:g id=\"user_id\" example=\"0\">%1$d</xliff:g></string>\n    <string name=\"net_policy\">Directiva de la red</string>\n    <string name=\"has_net_policy\">Directiva de la red</string>\n    <string name=\"choose_what_to_do\">Elija qué hacer.</string>\n    <string name=\"enable_battery_optimization\">¿Permitir optimización de batería\\?</string>\n    <string name=\"battery_optimization\">Optimización de batería</string>\n    <string name=\"no_battery_optimization\">Sin optimización de batería</string>\n    <string name=\"type_uri\">URI</string>\n    <string name=\"type_string_array_list\">Lista de cadenas</string>\n    <string name=\"type_string_array\">Matriz de cadenas</string>\n    <string name=\"type_float_array_list\">Lista de números decimales</string>\n    <string name=\"type_float_array\">Matriz de números decimales</string>\n    <string name=\"type_long_array_list\">Lista de enteros largos</string>\n    <string name=\"type_long_array\">Matriz de enteros largos</string>\n    <string name=\"type_int_array_list\">Lista de enteros</string>\n    <string name=\"type_int_array\">Matriz de enteros</string>\n    <string name=\"type_component_name\">Nombre del componente</string>\n    <string name=\"type_null\">Sin valor</string>\n    <string name=\"screen_lock_msg\">Bloquear App Manager usando Android bloqueo de pantalla</string>\n    <string name=\"screen_lock\">Bloqueo de pantalla</string>\n    <string name=\"unlock_app_manager\">Desbloquear gestor de aplicaciones</string>\n    <string name=\"sd_card\">Tarjeta SD</string>\n    <string name=\"external_storage\">Almacenamiento externo</string>\n    <string name=\"filter_apps_without_backups\">Sin copias de respaldo</string>\n    <string name=\"uninstalled_apps\">Aplicaciones desinstaladas</string>\n    <string name=\"enable_disable_features\">Activar/desactivar funciones</string>\n    <string name=\"installed_apps\">Aplicaciones instaladas</string>\n    <string name=\"restart_to_reflect_changes\">Debe reiniciar inmediatamente el dispositivo para que surtan efecto los cambios.</string>\n    <string name=\"failed_to_change_ssaid\">No se pudo modificar el SSAID</string>\n    <string name=\"copied_to_clipboard\">Se copió en el portapapeles.</string>\n    <string name=\"ssaid_info\">SSAID (<tt>Settings.Secure.ANDROID_ID</tt>) es un identificador de dispositivo asignado a cada aplicación (desde Android 8 «Oreo»). Es ampliamente utilizado por aplicaciones para rastrear usuarios.</string>\n    <string name=\"ssaid\">SSAID</string>\n    <string name=\"list_options\">Lista de opciones</string>\n    <string name=\"reverse\">Revertir</string>\n    <string name=\"os_version\">Versión del SO</string>\n    <string name=\"add\">Añadir</string>\n    <string name=\"add_to_profile\">Añadir al perfil</string>\n    <string name=\"initializing\">Inicializando…</string>\n    <string name=\"internal_storage\">Almacenamiento interno</string>\n    <string name=\"back_up\">Respaldo</string>\n    <string name=\"internal_data\">Datos internos</string>\n    <string name=\"app_signing_signatures\">Firmas</string>\n    <string name=\"collapse_all\">Contraer todo</string>\n    <string name=\"expand_all\">Expandir todo</string>\n    <string name=\"unable_to_save_log\">No se puede guardar el registro. ¿Escribió un nombre de archivo válido\\?</string>\n    <string name=\"pref_display_limit_hint\">Introduzca un número válido entre %1$d y %2$d.</string>\n    <string name=\"toast_invalid_level\">El nombre del nivel no es válido: %s</string>\n    <string name=\"omit_sensitive_info\">Omitir información confidencial</string>\n    <string name=\"undo\">Deshacer</string>\n    <string name=\"pause_unpause\">Reproducir/pausar</string>\n    <string name=\"file\">Archivo</string>\n    <string name=\"widget_start_recording\">Grabar\n\\nregistro</string>\n    <string name=\"widget_recording_in_progress\">Grabando…</string>\n    <plurals name=\"toast_log_truncated\">\n        <item quantity=\"one\">Registro demasiado grande, mostrando la última línea %d.</item>\n        <item quantity=\"many\">Registro demasiado grande, mostrando las últimas %d líneas.</item>\n        <item quantity=\"other\">Registro demasiado grande, mostrando las últimas %d líneas.</item>\n    </plurals>\n    <string name=\"toast_invalid_selection\">La selección no es válida. Inténtelo de nuevo.</string>\n    <string name=\"gz_bz2_compressed\">Comprimido con %1$s</string>\n    <string name=\"pgp_aes_rsa_encrypted\">Cifrado con %1$s</string>\n    <string name=\"text_include_device_info\">Incluir información del dispositivo</string>\n    <string name=\"text_filter_text\">Filtrar texto</string>\n    <string name=\"text_filter_ellipsis\">Filtrar…</string>\n    <string name=\"subject_log_report\">Informe de registro</string>\n    <string name=\"start_recording_log\">Grabar</string>\n    <string name=\"settings\">Configuración</string>\n    <string name=\"send_log_title\">Enviar registro</string>\n    <string name=\"save_log\">Guardar registro</string>\n    <string name=\"save_as\">Guardar como…</string>\n    <string name=\"record_log\">Grabar registro</string>\n    <string name=\"pref_show_timestamp_title\">Mostrar PID y cronomarcador</string>\n    <string name=\"no_encryption\">Sin cifrado</string>\n    <string name=\"base_backup\">Copia de respaldo de base</string>\n    <string name=\"trackers_unblocked_successfully\">Los rastreadores ahora están desbloqueados</string>\n    <string name=\"trackers_blocked_successfully\">Los rastreadores ahora están bloqueados</string>\n    <string name=\"pref_default_log_level_title\">Nivel de registro predeterminado</string>\n    <string name=\"pref_cat_configuration\">Configuración</string>\n    <string name=\"pref_cat_appearance\">Apariencia</string>\n    <string name=\"pref_cat_advanced\">Avanzado</string>\n    <string name=\"notification_subtext\">Toque para dejar de grabar</string>\n    <string name=\"log_level\">Nivel de registro</string>\n    <string name=\"enter_good_filename\">Proporcione un nombre de archivo válido.</string>\n    <string name=\"orientation_follow_locale\">Según la conf. regional</string>\n    <string name=\"orientation_right_to_left\">De derecha a izquierda</string>\n    <string name=\"orientation_left_to_right\">De izquierda a derecha</string>\n    <string name=\"confirm_import_keystore\">¿Confirma que quiere reemplazar el almacén de claves actual\\? Esta acción no puede deshacerse.</string>\n    <string name=\"import_keystore\">Importar almacén de claves</string>\n    <string name=\"pref_import_export_keystore\">Importar/exportar almacén de claves</string>\n    <string name=\"latest_backup\">Copia de respaldo más reciente</string>\n    <string name=\"failed_to_unblock_trackers\">No se pudieron desbloquear los rastreadores</string>\n    <string name=\"failed_to_block_trackers\">No se pudieron bloquear los rastreadores</string>\n    <string name=\"profile_save_apk_msg\">Guarda los archivos APK en <tt>AppManager/apks</tt></string>\n    <string name=\"save_apk\">Guardar APK</string>\n    <string name=\"running_services\">Servicios en ejecución</string>\n    <string name=\"view_logs\">Ver registros</string>\n    <string name=\"share_log\">Compartir</string>\n    <string name=\"pk8_file\">Archivo PKCS n.º 8 (PK8)</string>\n    <string name=\"pem_and_pk8\">PEM y PKCS n.º 8 (PK8)</string>\n    <string name=\"pkcs12_keystore\">Almacén de claves PKCS n.º 12 (P12)</string>\n    <string name=\"filter_choice_tag\">Etiqueta</string>\n    <string name=\"filter_choice_pid\">PID</string>\n    <string name=\"filter_choice\">Buscar por</string>\n    <string name=\"dialog_compiling_log\">Compilando registro…</string>\n    <string name=\"restart_log_viewer_to_see_changes\">Reinicie la ventana del visor de registros para ver los cambios.</string>\n    <string name=\"pref_log_viewer_msg\">Configure la manera en que se muestran los registros.</string>\n    <string name=\"log_viewer\">Visor de registros</string>\n    <string name=\"source_code_links\"><a href=\"https://github.com/MuntashirAkon/AppManager\">GitHub</a> - <a href=\"https://gitlab.com/muntashir/AppManager\">GitLab</a> - <a href=\"https://0xacab.org/muntashir/AppManager\">Riseup</a> - <a href=\"https://codeberg.org/muntashir/AppManager\">Codeberg</a></string>\n    <string name=\"new_alias_password\">Contraseña de alias nuevo</string>\n    <string name=\"bouncy_castle_keystore\">Almacén de claves Bouncy Castle (BKS)</string>\n    <string name=\"invalid_rsa_key_size\">El tamaño de la clave no es válido para el cifrado RSA. Este puede ser de 1024, 2048 o 4096 bits.</string>\n    <string name=\"invalid_aes_key_size\">El tamaño de la clave no es válido para el cifrado AES. Este puede ser de 128 o de 256 bits.</string>\n    <string name=\"country_name\" tools:ignore=\"TypographyOther\">Nombre de país (C)</string>\n    <string name=\"state_name\">Nombre de estado/provincia (ST)</string>\n    <string name=\"locality_name\">Nombre de localidad (ciudad) (L)</string>\n    <string name=\"organization_name\">Nombre de organización (O)</string>\n    <string name=\"organization_unit\">Unidad organizativa (OU)</string>\n    <string name=\"common_name\">Nombre común (CN)</string>\n    <string name=\"input_key_password\">Contraseña de clave</string>\n    <string name=\"failed_to_load_key\">No se pudo cargar la clave.</string>\n    <string name=\"key_not_set\">No se ha definido.</string>\n    <string name=\"use_default\">Utilizar predeterminado</string>\n    <string name=\"crypto_key_size\">Tamaño de clave</string>\n    <string name=\"input_keystore_alias_pass_msg\">Toque aquí para proporcionar la contraseña de %1$s</string>\n    <string name=\"input_key\">Clave de entrada (en hexadecimal)</string>\n    <string name=\"failed_to_initialize_key_store\">No se pudo iniciar el almacén de claves del Gestor de aplicaciones.</string>\n    <string name=\"failed_to_save_key\">No se pudo guardar la clave.</string>\n    <string name=\"generate_key\">Generar</string>\n    <string name=\"java_keystore\">Almacén de claves Java (JKS)</string>\n    <string name=\"keystore_pass\">Contraseña del almacén de claves</string>\n    <string name=\"keystore_file\">Archivo de almacén de claves</string>\n    <string name=\"import_key\">Importar clave</string>\n    <string name=\"pem_file\">Archivo PEM</string>\n    <string name=\"found_no_alias_in_keystore\">¡No se encontró ningún alias en el almacén de claves!</string>\n    <string name=\"alias_pass\">Contraseña del alias</string>\n    <string name=\"choose_an_alias\">Elija un alias</string>\n    <string name=\"failed_to_read_keystore\">No se pudo consultar el almacén de claves.</string>\n    <string name=\"pref_installer_msg\">Configure los comportamientos del instalador de aplicaciones.</string>\n    <string name=\"expiry_date_cannot_be_empty\">La fecha de caducidad no puede quedar vacía.</string>\n    <string name=\"signing_key\">Clave de firma</string>\n    <string name=\"delete_saved_log\">Eliminar registros guardados</string>\n    <string name=\"copy_to_clipboard\">Copiar en el portapapeles</string>\n    <plurals name=\"file_deletion_confirmation\">\n        <item quantity=\"one\">Se eliminará %d archivo</item>\n        <item quantity=\"many\">Se eliminarán %d archivos</item>\n        <item quantity=\"other\">Se eliminarán %d archivos</item>\n    </plurals>\n    <string name=\"add_filter_ellipsis\">Añadir filtro…</string>\n    <string name=\"add_filter\">Añadir filtro</string>\n    <string name=\"log_level_fatal\">Grave</string>\n    <string name=\"log_level_warn\">Aviso</string>\n    <string name=\"log_level_verbose\">Detallado</string>\n    <string name=\"log_level_info\">Información</string>\n    <string name=\"log_level_error\">Error</string>\n    <string name=\"log_level_debug\">Depuración</string>\n    <string name=\"filename\">Nombre de archivo</string>\n    <string name=\"pref_show_timestamp_summary\">Mostrar identificador de proceso y cronomarcador al expandir.</string>\n    <string name=\"pref_log_write_period_summary\">Al grabar, escribir en la tarjeta SD cada %1$d renglones.</string>\n    <string name=\"pref_log_write_period_title\">Período de escritura</string>\n    <string name=\"pref_display_limit_title\">Límite de visualización de registro</string>\n    <string name=\"pref_display_limit_summary\">Mostrar únicamente los últimos %1$d registros para evitar errores de agotamiento de memoria.</string>\n    <string name=\"pref_expanded_by_default_title\">Expandir de manera predeterminada</string>\n    <string name=\"pref_expanded_by_default_summary\">Mostrar de manera predeterminada todo el texto del registro.</string>\n    <string name=\"pref_log_line_period_error\">Introduzca un entero entre 1 y 1000.</string>\n    <string name=\"pref_rules_msg\">Bloqueo instantáneo, importación/exportación/eliminación de reglas, etc.</string>\n    <string name=\"no_changes\">Ningún cambio</string>\n    <string name=\"notification_title\">Grabación de registros en curso</string>\n    <string name=\"notification_ticker\">Comenzó la grabación de los registros</string>\n    <string name=\"no_saved_logs\">Ningún registro guardado.</string>\n    <string name=\"manage_saved_logs\">Gestionar registros guardados</string>\n    <string name=\"log_saved\">Se guardó el registro.</string>\n    <string name=\"log_recording_started\">Comenzó la grabación de los registros.</string>\n    <string name=\"log_cleared\">Se vaciaron los registros</string>\n    <string name=\"enter_filename\">Introducir nombre de archivo</string>\n    <string name=\"omit_sensitive_info_summary\">Omite información delicada, como URL, números telefónicos y direcciones de correo.</string>\n    <string name=\"text_include_dmesg\">Incluir registro de núcleo</string>\n    <string name=\"pref_import_export_keystore_msg\">Importar o exportar el Bouncy Castle KeyStore (BKS) que el Gestor de aplicaciones utiliza internamente.</string>\n    <string name=\"pref_display_changes_msg\">Mostrar cambios en versión, rastreadores, componentes, permisos, firmas, SDK, etc., de forma compatible con el control de versiones.</string>\n    <string name=\"pref_display_changes\">Mostrar cambios</string>\n    <string name=\"hidden\">Oculto</string>\n    <string name=\"suspended\">Suspendido</string>\n    <string name=\"netpolicy_allow_background_data\">Permitir datos en 2.º plano cuando se active el Ahorrador de datos</string>\n    <string name=\"netpolicy_reject_background_data\">Rechazar datos en segundo plano</string>\n    <string name=\"netpolicy_reject_cellular_data\">Rechazar datos de red móvil</string>\n    <string name=\"netpolicy_reject_vpn_data\">Rechazar datos por VPN</string>\n    <string name=\"netpolicy_reject_wifi_data\">Rechazar datos wifi</string>\n    <string name=\"netpolicy_disable_network_access\">Desactivar acceso a redes</string>\n    <string name=\"wireless_debugging\">Depuración inalámbrica</string>\n    <string name=\"adb_connect\">Conectar</string>\n    <string name=\"port_number\">Puerto</string>\n    <string name=\"adb_connect_port_number_description\">El número de puerto se localiza en la sección <b>Dirección IP y puerto</b>, justo por debajo de la sección <b>Nombre de dispositivo</b>.</string>\n    <string name=\"port_number_empty\">El número de puerto está vacío.</string>\n    <string name=\"port_number_invalid\">Número de puerto no válido.</string>\n    <string name=\"unknown_net_policy\">Directiva de red desconocida (%1$s - %2$X)</string>\n    <string name=\"pref_buffer_title\">Buffer de registros</string>\n    <string name=\"failed\">Fallido</string>\n    <string name=\"pref_filter_pattern_title\">Filtrar etiquetas</string>\n    <string name=\"pref_filter_pattern_summary\">Filtrar las siguientes etiquetas seleccionadas de los registros.</string>\n    <string name=\"pref_default_log_level_summary\">Nivel de registro al inicio, al abrir archivos y al grabar.</string>\n    <string name=\"open\">Abierto</string>\n    <string name=\"import_from_oab\">Importar desde OAndBackup</string>\n    <string name=\"pref_import_backups_msg\">Importe copias de respaldo desde OAndBackup, Swift Backup (3.0–3.2) o Titanium Backup.</string>\n    <string name=\"pref_import_backups\">Importar copias de respaldo</string>\n    <string name=\"community_links\"><a href=\"https://t.me/AppManagerChannel\">Canal de Telegram</a> - <a href=\"https://twitter.com/AppManagerNews\">Twitter</a></string>\n    <string name=\"community\">Comunidad</string>\n    <plurals name=\"alert_failed_to_import_backups\">\n        <item quantity=\"one\">No se ha podido importar la copia de seguridad %1$d</item>\n        <item quantity=\"many\">No se han podido importar %1$d copias de seguridad</item>\n        <item quantity=\"other\">No se han podido importar %1$d copias de seguridad</item>\n    </plurals>\n    <string name=\"import_from_tb\">Importar desde Titanium Backup</string>\n    <string name=\"notice_saf\">A diferencia de los volúmenes, el directorio escogido se usará para almacenar todos los archivos relacionados con App Manager, incluyendo APKs y respaldos guardados. El framework de acceso al almacenamiento (SAF) es muy lento, por lo cual se recomienda usar esta opción solo cuando otras no puedan ser utilizadas.</string>\n    <string name=\"help_uses_permissions_tab\">Pulse en un elemento para <b>concederlo</b> o <b>revocarlo</b>. Solo los permisos <b>peligrosos</b> y <b>de desarrollo</b> se pueden conceder o revocar.</string>\n    <string name=\"help_permissions_tab\">Estos permisos los define esta aplicación y no pueden revocarse.</string>\n    <string name=\"help_app_ops_tab\">Pulse en un elemento para <b>permitirlo</b> o <b>ignorarlo</b>. Mantenga pulsado el elemento para ver otros modos admitidos.</string>\n    <string name=\"minimum_version\">Versión mín.: %d</string>\n    <string name=\"added_to_queue\">Se añadió a la cola</string>\n    <string name=\"pref_selected_users\">Usuarios seleccionados</string>\n    <string name=\"pref_selected_users_msg\">Restringe App Manager para que funcione sólo con los usuarios seleccionados.</string>\n    <string name=\"permission_flags\">Marcas de permiso</string>\n    <string name=\"error_with_details\">Error: %s</string>\n    <string name=\"saved_filters\">Filtros guardados</string>\n    <string name=\"notice\">Aviso</string>\n    <string name=\"files\">Archivos</string>\n    <string name=\"storage\">Almacenamiento</string>\n    <string name=\"failed_to_prevent_background_run\">No se pudo evitar que %1$s se ejecutase en segundo plano</string>\n    <string name=\"saf\">SAF</string>\n    <string name=\"paired_successfully\">Emparejado.</string>\n    <string name=\"keystore_password_info\">Esta es la contraseña del Almacén de claves del Gestor de aplicaciones. Guárdela en un lugar seguro si va a crear o restaurar copias de respaldo del Almacén de claves. <b>Este mensaje no volverá a aparecer.</b></string>\n    <string name=\"keystore_pass_cannot_be_empty\">La contraseña del almacén de claves no puede quedar vacía.</string>\n    <string name=\"invalid_password\">La contraseña no es válida. Vuelva a intentarlo.</string>\n    <string name=\"adb_pair\">Emparejar</string>\n    <string name=\"running_services_logcat_hint\">Pulsa en un ítem para abrir el visor de registro con el ID del proceso correspondiente como filtro por defecto.</string>\n    <string name=\"pid\">ID del proceso</string>\n    <plurals name=\"pref_thread_count_msg\">\n        <item quantity=\"one\">Ejecutar como máximo %1$d operación en paralelo</item>\n        <item quantity=\"many\">Ejecutar como máximo %1$d operaciones en paralelo</item>\n        <item quantity=\"other\">Ejecutar como máximo %1$d operaciones en paralelo</item>\n    </plurals>\n    <string name=\"pref_thread_count_hint\">El valor debe estar entre 0 y %1$d donde 0 significa <i>número máximo de operaciones en un momento dado</i>.</string>\n    <string name=\"pref_thread_count\">Ejecución paralela</string>\n    <string name=\"type_uri_array_list\">Lista de URIs</string>\n    <string name=\"type_uri_array\">Matriz de URIs</string>\n    <string name=\"pref_always_on_background_msg\">Siempre instalar aplicaciones en segundo plano y mostrar una notificación al terminar.</string>\n    <string name=\"pref_always_on_background\">Instalar en segundo plano</string>\n    <string name=\"pref_block_trackers_msg\">Bloquear componentes de rastreo al instalar una aplicación a través de App Manager.</string>\n    <string name=\"next\">Siguiente</string>\n    <string name=\"installer_app_installed\">Aplicación instalada</string>\n    <string name=\"staging_apk_files\">Preparando…</string>\n    <string name=\"background\">Segundo plano</string>\n    <string name=\"trim_caches_in_all_apps_description\">Borrar archivos de antememoria de todas las aplicaciones, incluyendo los del sistema Android</string>\n    <string name=\"trim_caches_in_all_apps\">Recortar antememoria en todas las aplicaciones</string>\n    <string name=\"user_root\">Usar root</string>\n    <string name=\"paste\">Pegar</string>\n    <string name=\"set_package_name_first\">¡Elija un nombre para el paquete primero!</string>\n    <string name=\"identifier\">Identificador</string>\n    <string name=\"second_degree_tracker_note\">² prefijo indica que los rastreadores están en la <a href=\"https://etip.exodus-privacy.eu.org/\">lista de espera de ETIP</a> p. ej. todavía se está investigando si son en realidad rastreadores.</string>\n    <string name=\"failed_to_uninstall_app\">Desinstalación fallida</string>\n    <string name=\"backup_volume_dialog_description\">Volúmenes con prefijo <tt>tree</tt> son carpetas seleccionadas mediante el framework de acceso al almacenamiento (SAF). Exceptuando estas carpetas, el directorio por defecto para App Manager es una subcarpeta llamada <tt>AppManager</tt>.</string>\n    <string name=\"java\">Java</string>\n    <string name=\"smali\">Smali</string>\n    <string name=\"accessibility_service_description\">Servicio genérico de accesibilidad para realizar ciertas operaciones como limpiar caché en modo no-root.</string>\n    <string name=\"explore\">Explorar</string>\n    <string name=\"system_partition\">Root Android</string>\n    <string name=\"exit_confirmation\">Confirmación de salida</string>\n    <string name=\"extract\">Extraer</string>\n    <string name=\"replace\">Reemplazar</string>\n    <string name=\"rename\">Renombrar</string>\n    <string name=\"import_from_sb\">Importar desde Swift Backup 3.0 – 3.2</string>\n    <string name=\"pref_import_backups_hint\">Seleccione un directorio que contenga los archivos de copia de seguridad (Swift Backup/Titanium Backup) o directorios (OAndBackup)</string>\n    <string name=\"pref_default_blocking_method\">Método de bloqueo por defecto</string>\n    <string name=\"intent_firewall_and_disable\">IFW + deshabilitar</string>\n    <string name=\"authenticating\">Autenticando…</string>\n    <string name=\"search_type_contains\">Incluye</string>\n    <string name=\"search_type_prefix\">Prefijo</string>\n    <string name=\"search_type_suffix\">Sufijo</string>\n    <string name=\"search_type_regular_expressions\">Expresión regular</string>\n    <string name=\"pref_default_blocking_method_description\">Método a usar por defecto en lugares donde no hay opción para escoger un método de bloqueo.</string>\n    <string name=\"pref_intent_firewall_and_disable_description\">Bloquea componentes usando Intent Firewall así como también los deshabilita. Método recomendado para usuarios root.</string>\n    <string name=\"pref_intent_firewall_description\">Bloquea componentes usando sólo Intent Firewall. No se recomienda ya que algunas apps del sistema pueden eludir firewalls.</string>\n    <string name=\"pref_disable_description\">Deshabilita sólo los componentes. No se recomienda a usuarios root ya que las apps pueden eludir esto. En modo ADB, las aplicaciones de prueba se pueden deshabilitar con este método.</string>\n    <string name=\"intent_firewall\">IFW</string>\n    <plurals name=\"usage_seconds\">\n        <item quantity=\"one\">%1$d segundo</item>\n        <item quantity=\"many\">%1$d segundos</item>\n        <item quantity=\"other\">%1$d segundos</item>\n    </plurals>\n    <string name=\"toggle_internet\">Usar el Internet</string>\n    <string name=\"vt_checking\">VirusTotal: Comprobando…</string>\n    <string name=\"vt_uploading\">VirusTotal: Subiendo…</string>\n    <string name=\"vt_success\">VirusTotal: %1$d/%2$d</string>\n    <string name=\"vt_scan_date\">Fecha de escaneo: %1$s</string>\n    <string name=\"vt_slowness_warning\">Dependiendo de la velocidad de Internet y la carga del servidor, esto podría tardar un rato.</string>\n    <string name=\"pref_vt_apikey\">Clave API de VirusTotal</string>\n    <string name=\"pref_vt_apikey_description\">Una clave API permite a App Manager subir archivos APK a VirusTotal, así como también obtener informes de este. Regístrese en https://virustotal.com para obtener una clave API de forma gratuita.</string>\n    <string name=\"uses_play_app_signing\">Firma de Aplicaciones Play</string>\n    <string name=\"scan_in_vt\">Escanear en VirusTotal</string>\n    <string name=\"process_id\">ID de proceso</string>\n    <string name=\"virtual_memory\">Memoria Virtual</string>\n    <string name=\"cpu_percent\">%% CPU</string>\n    <string name=\"cpu_time\">Tiempo de CPU</string>\n    <string name=\"priority\">Prioridad</string>\n    <string name=\"state\">Estado del proceso</string>\n    <string name=\"commandline_args\">Argumentos de línea de comando</string>\n    <string name=\"swap\">Intercambiar</string>\n    <string name=\"memory_chart_info\">● %1$s Aplicaciones ● %2$s En caché ● %3$s Buffers ● %4$s Libre</string>\n    <string name=\"swap_chart_info\">● %1$s usado ● %2$s sin usar</string>\n    <string name=\"failed_to_use_the_current_mode_of_operation\">No es posible usar el modo de operación actual. Volviendo a modo no-root para esta sesión.</string>\n    <string name=\"warning_working_on_root_mode\">Advertencia: Se está trabajando en root en lugar de modo ADB.</string>\n    <string name=\"magisk_denylist\">Lista de bloqueo Magisk</string>\n    <string name=\"failed_to_enable_magisk_deny_list\">No se pudo habilitar Magisk DenyList</string>\n    <string name=\"mode_of_op_with_inferred_mode_of_op\">%1$s (Modo inferido: %2$s)</string>\n    <string name=\"vt_permalink\">Enlace permanente a VirusTotal</string>\n    <string name=\"vt_queued\">VirusTotal: En cola</string>\n    <string name=\"vt_failed\">VirusTotal: Fallido</string>\n    <string name=\"pref_vt_apikey_summary\">Habilitar escaneo de archivos APK vía VirusTotal.</string>\n    <string name=\"vt_disclaimer\">VirusTotal y sus logotipos son una marca registrada de Chronicle LLC. Ni App Manager -el cliente de la API- ni sus autores son responsables de los datos que puedas enviar a VirusTotal.</string>\n    <string name=\"failed_to_change_app_op_mode\">No se pudo cambiar el modo de operación de la aplicación.</string>\n    <string name=\"failed_to_disable_magisk_deny_list\">No se pudo deshabilitar Magisk DenyList</string>\n    <plurals name=\"usage_minutes\">\n        <item quantity=\"one\">%1$d minuto</item>\n        <item quantity=\"many\">%1$d minutos</item>\n        <item quantity=\"other\">%1$d minutos</item>\n    </plurals>\n    <string name=\"uses_play_app_signing_description\">Está aplicación contiene algunos marcadores que indican que <i>posiblemente</i> usen <a href=\"https://support.google.com/googleplay/android-developer/answer/9842756\">Play App Signing</a>. Con este mecanismo, las claves de inicio son guardadas en los servidores de Google, y Google es el responsable por el inicio de sesión en la app. Tenga en cuenta que emparejar la información de inicio es la única forma de verificar que la app no fue modificada por una persona diferente al desarrollador (y en este caso, también Google).</string>\n    <string name=\"parent_process_id\">ID del proceso padre</string>\n    <string name=\"threads\">Número de hilos</string>\n    <string name=\"hidden_api_enf_policy_dark_grey_and_black\">Cumplimiento (listas negras y gris oscuro)</string>\n    <string name=\"hidden_api_enf_policy_warn\">Advertencia (acceso completo a la API oculta, pero emite advertencias)</string>\n    <string name=\"binary_64_bit\">64 Bit</string>\n    <string name=\"endianness_little_endian\">Byte menos significativo</string>\n    <string name=\"endianness_big_endian\">Byte más significativo</string>\n    <string name=\"so_type_executable\">Ejecutable</string>\n    <string name=\"primary_abi\">Interfaz binaria de aplicación (ABI) primaria</string>\n    <string name=\"zygote_preload_name\">Nombre de precarga de Zygote</string>\n    <string name=\"hidden_api_enf_default_policy\">Valor predeterminado (según el tipo de aplicación)</string>\n    <string name=\"hidden_api_enf_policy_none\">Ninguno (acceso completo a la API oculta)</string>\n    <string name=\"hidden_api_enforcement_policy\">Política de aplicación de la API oculta</string>\n    <string name=\"hidden_api_enf_policy_black\">Cumplimiento (sólo listas negras)</string>\n    <string name=\"binary_32_bit\">32 Bit</string>\n    <string name=\"so_type_shared_library\">Biblioteca dinámica</string>\n    <string name=\"file_modified_are_you_sure\">El archivo fue modificado. ¿Quiere descartar todos los cambios y salir\\?</string>\n    <string name=\"save_and_exit\">Guardar y salir</string>\n    <string name=\"pref_saved_apk_name_format\">Formato del nombre del APK guardado</string>\n    <string name=\"auth_manager_description\">Para lanzar un Intent desde una app externa, es necesario suministrar un campo extra llamado <tt>auth</tt>, y debe contener la siguiente clave:</string>\n    <string name=\"auth_manager_title\">Gestor de autorizaciones</string>\n    <string name=\"regenerate_auth_key\">Regenerar la clave de autorización</string>\n    <string name=\"shortcut_icon\">Icono de acceso directo</string>\n    <string name=\"pref_saved_apk_name_format_msg\">El formato que se utilizará para nombrar los archivos APK cuando los guarde.</string>\n    <string name=\"regenerate_auth_key_warning\">¿Está seguro\\? Todas las aplicaciones de terceros tienen que ser reconfiguradas con la nueva clave de autorización.</string>\n    <string name=\"sort_by_installation_date\">Fecha de instalación</string>\n    <string name=\"backup_volume_unavailable_warning\">El volumen de copia de seguridad seleccionado no está disponible. Si está ubicado en un almacenamiento externo, por favor conéctelo, o cambie el nombre del volumen.</string>\n    <string name=\"input_ssaid_instruction\">SSAID es un número hexadecimal, cuyo tamaño en bytes es de %1$d, por ejemplo, una cadena de texto de tamaño %2$d, que contiene números del 0 al 9 y de las letras a hasta la f.</string>\n    <string name=\"change_backup_volume\">Cambiar volumen</string>\n    <string name=\"external\">Externo</string>\n    <string name=\"internal\">Interno</string>\n    <string name=\"tracker\">Rastreador</string>\n    <string name=\"screen_time\">Tiempo en Pantalla</string>\n    <string name=\"open_in_new_window\">Nueva ventana</string>\n    <string name=\"type_string_set\">Conjunto de cadenas</string>\n    <string name=\"vt_confirm_uploading_file\">El archivo no fue encontrado en la base de datos de VirusTotal. Desea subir el archivo\\?</string>\n    <string name=\"vt_confirm_upload_and_scan\">Si, subir y escanear</string>\n    <string name=\"log_stop_recording\">Detener grabación</string>\n    <string name=\"apk_checksums\">Suma de verificación APK</string>\n    <string name=\"item_select\">Elegir</string>\n    <string name=\"pref_vt_prompt_before_uploading\">Mostrar aviso antes de iniciar la subida del archivo.</string>\n    <string name=\"app_explorer\">Explorador de apps</string>\n    <string name=\"netpolicy_cannot_be_modified_for_core_apps\">La politica de Net no puede ser modificada para las aplicaciones core de Android.</string>\n    <string name=\"frozen\">Congelada</string>\n    <string name=\"freeze\">Congelar</string>\n    <string name=\"unfreeze\">Descongelar</string>\n    <string name=\"backup_no_backups_present\">Sin respaldos.</string>\n    <string name=\"restore_dots\">Restaurar…</string>\n    <string name=\"unsupported_split_apk\">Sin soporte</string>\n    <string name=\"pref_pure_black_theme\">Tema negro puro</string>\n    <string name=\"view_changelog\">Descubra las novedades de esta versión</string>\n    <string name=\"backup_apps_cannot_be_restored\">Las siguientes aplicaciones no se pueden restaurar porque no tienen una copia de seguridad:</string>\n    <string name=\"backup_apps_cannot_be_backed_up\">Las siguientes aplicaciones no están instaladas y no se puede realizar una copia de seguridad:</string>\n    <string name=\"sort_by_total_size\">Tamaño total</string>\n    <string name=\"pref_sign_apk_error_signing_key_not_added\">Se requiere una clave válida para firmar un archivo APK.</string>\n    <string name=\"pref_sign_apk_no_signing_key\">No se puede firmar la clave de acceso</string>\n    <string name=\"usage_times_opened\">Veces abierto</string>\n    <string name=\"usage_last_used\">Último uso</string>\n    <string name=\"usage_mobile_data\">Datos móviles</string>\n    <string name=\"usage_wifi_data\">Datos Wi-Fi</string>\n    <string name=\"open_developer_options_page\">Abrir opciones de desarrollador en los ajustes de Android</string>\n    <string name=\"pref_pure_black_theme_msg\">Usa un fondo completamente negro cuando el modo nocturno está activado.</string>\n    <string name=\"restart_device\">Reiniciar dispositivo</string>\n    <string name=\"import_backups_warning_delete_backups_after_import\">¿Eliminar las copias de seguridad después de importarlas al Administrador de aplicaciones\\? Cada copia de seguridad se elimina individualmente después de importarla con éxito. Seleccione <b>No</b> sino está seguro.</string>\n    <string name=\"troubleshooting\">Solución de problemas</string>\n    <string name=\"pref_reload_apps\">Recargar aplicaciones</string>\n    <string name=\"pref_reload_apps_msg\">Vuelva a cargar la lista de aplicaciones almacenadas en la base de datos del Administrador de aplicaciones en caso de comportamiento inesperado.</string>\n    <string name=\"changelog_type_new\">Nuevo</string>\n    <string name=\"changelog_type_fix\">Corregir</string>\n    <string name=\"changelog_type_improve\">Mejorar</string>\n    <string name=\"am_command\"><tt>comando am</tt></string>\n    <string name=\"failed_to_unfreeze\">No se pudo descongelar <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g>.</string>\n    <string name=\"freeze_unfreeze\">Congelar/descongelar</string>\n    <string name=\"profile_freeze_msg\">Congela o descongela las aplicaciones en función de su estado</string>\n    <string name=\"pref_default_freezing_method\">Método de congelación por defecto</string>\n    <string name=\"pref_default_freezing_method_description\">Método que se utilizará por defecto en los lugares en los que no hay opción de seleccionar un método de congelación.</string>\n    <string name=\"suspend_app\">Suspender</string>\n    <string name=\"hide_app\">Ocultar</string>\n    <plurals name=\"alert_failed_to_freeze\">\n        <item quantity=\"one\">No se pudo congelar la aplicación %1$d</item>\n        <item quantity=\"many\">No se pudieron congelar %1$d aplicaciones</item>\n        <item quantity=\"other\">No se pudieron congelar %1$d aplicaciones</item>\n    </plurals>\n    <string name=\"suspend_app_description\">Este es el método de congelación más débil. Una aplicación suspendida puede seguir apareciendo en el lanzador, pero aparecerá en gris y no se podrá iniciar.</string>\n    <string name=\"disable_app_description\">Método de congelación recomendado. Deshabilita la aplicación y todos sus componentes, pero se perderán todos los accesos directos.</string>\n    <string name=\"hide_app_description\">Este método solo se recomienda para el uso diario. Una aplicación oculta aparece como si estuviera desinstalada. Pero la aplicación podría reaparecer si está instalada o actualizada.</string>\n    <string name=\"sort_by_frozen_app\">Congelado primero</string>\n    <string name=\"filter_frozen_apps\">Aplicaciones congeladas</string>\n    <string name=\"pref_appearance_description\">Tema, orientación, características, etc.</string>\n    <string name=\"pref_privacy\">Privacidad</string>\n    <string name=\"pref_advanced_pref\">Usuarios, formato del nombre del APK, ejecución paralela, etc.</string>\n    <string name=\"pref_version_changelog\">Versión/registro de cambios</string>\n    <string name=\"failed_to_freeze\">No se ha podido congelar <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g>.</string>\n    <string name=\"user_manual\">Manual de usuario</string>\n    <string name=\"get_help\">Consigue ayuda</string>\n    <plurals name=\"alert_failed_to_unfreeze\">\n        <item quantity=\"one\">No se pudo descongelar la aplicación %1$d</item>\n        <item quantity=\"many\">No se pudieron descongelar %1$d aplicaciones</item>\n        <item quantity=\"other\">No se pudieron descongelar %1$d aplicaciones</item>\n    </plurals>\n    <string name=\"pref_privacy_description\">Bloqueo de pantalla, autorización, etc.</string>\n    <string name=\"file_creation_date\">Creado</string>\n    <string name=\"file_modification_date\">Modificado</string>\n    <string name=\"file_open_with\">Abrir con</string>\n    <string name=\"file_accessed_date\">Accesado</string>\n    <string name=\"file_change_open_with\">Cambie abrir con</string>\n    <string name=\"file_shortcut_target_file\">Documento objectivo</string>\n    <string name=\"file_properties\">Propiedades</string>\n    <string name=\"file_cut\">Cortar</string>\n    <string name=\"fm_always_open_with\">Siempre abierto</string>\n    <string name=\"fm_open_with_for_this_file_only\">Solo abierto para este documento</string>\n    <string name=\"file_open_as\">Abrir como…</string>\n    <string name=\"open_as_text\">Texto</string>\n    <string name=\"open_as_image\">Imagen</string>\n    <string name=\"open_as_video\">Video</string>\n    <string name=\"open_as_archive\">Archivo</string>\n    <string name=\"open_as_folder\">Carpeta</string>\n    <string name=\"open_as_other\">Otro</string>\n    <string name=\"action_stop_service\">Parar</string>\n    <string name=\"delete_filename\">Eliminar %s</string>\n    <string name=\"confirm_file_deletion\">Sí, eliminar</string>\n    <string name=\"on_open_application_no_recents\">No mostrar aplicaciones en recientes</string>\n    <string name=\"file_open_with_custom_activity\">Personalizar</string>\n    <string name=\"on_unfreeze_open_application\">Abrir aplicaciones despues de descongelar</string>\n    <string name=\"file_open_with_os_default_dialog\">Abrir con dialogo por defecto del Sistema Operativo</string>\n    <string name=\"freeze_on_phone_locked\">Congelar automáticamente la aplicación cuando el teléfono está bloqueado</string>\n    <string name=\"tap_to_freeze_app\">Tocar para congelar</string>\n    <string name=\"waiting_for_the_phone_to_be_locked\">Esperando a que el teléfono se bloquee…</string>\n    <string name=\"app_can_write_and_execute_in_same_place\">La aplicación infringe la <a href=\"https://es.wikipedia.org/wiki/W%5EX\"> Politica W^X</a> y es capaz de escribir y ejecutar en el mismo directorio o en la misma parte de memoria. Esto permite la ejecución de ejecutables arbitrarios, ya sea modificando los ejecutables integrados en la aplicación o descargándolos de Internet. A menos que este sea el comportamiento previsto de la aplicación (p. ej., emuladores de terminal), se recomienda buscar una versión más reciente de la aplicación que apunte al SDK 29 (Android 10) y versiones posteriores, o buscar alternativas.</string>\n    <string name=\"sort_by_filename\">Nombre</string>\n    <string name=\"file_owner_id\">Propio (UID)</string>\n    <string name=\"calculating_file_size\">Calculando…</string>\n    <string name=\"sort_by_file_size\">Tamaño del archivo</string>\n    <string name=\"export_app_list_select_format\">Seleccione el formato para exportar la lista de aplicaciones</string>\n    <string name=\"file_group_id\">Grupo (GID)</string>\n    <string name=\"option_display_dot_files\">Archivos de respaldo</string>\n    <string name=\"option_display_folders_on_top\">Carpetas en la parte superior</string>\n    <string name=\"sort_by_last_modified\">Última modificación</string>\n    <string name=\"sort_by_file_type\">Tipo de archivo</string>\n    <string name=\"export_app_list\">Exportar lista de aplicaciones</string>\n    <string name=\"export_option_xml\">XML</string>\n    <string name=\"funding_campaign_text\">Estamos ejecutando una <b>campaña de financiación</b> para App Manager por un período limitado. <a href=\"https://opencollective.com/app-manager#category-ABOUT\">más información...</a></string>\n    <string name=\"adb_incomplete_usb_debugging_message\">Parece que la depuración de USB no está configurada correctamente. Lea <a href=\"https://muntashirakon.github.io/AppManager/#subsec:enable-usb-debugging\">la documentación</a> para conocer los pasos adicionales. Si ya conoce los pasos, haga clic en \\\"Abrir\\\" para abrir las opciones de desarrollador, o haga clic en \\\"Cerrar\\\" para continuar usando el Root.</string>\n    <string name=\"funding_campaign_dialog_message\">Nosotros estamos ejecutando una <b>campaña de financiación</b> para App Manager por un período limitado. Visita <a href=\"https://opencollective.com/app-manager#category-ABOUT\">opencollective.com/app-manager</a> para saber más sobre la campaña. Este aviso no se volverá a mostrar, pero puede encontrarlo en la página Configuración durante toda la campaña.</string>\n    <string name=\"title_ui_tracker\">Rastreador de interfaz de usuario</string>\n    <string name=\"title_terminal_emulator\">Terminal</string>\n    <string name=\"class_hierarchy\">Jerarquía</string>\n    <string name=\"title_labs_activity\">Laboratorios</string>\n    <string name=\"export_option_markdown\">Reducción</string>\n    <string name=\"adb_incomplete_usb_debugging_title\">Depuración USB incompleta</string>\n    <string name=\"sort_by_data_usage\">Uso de datos</string>\n    <string name=\"filter_apps_with_keystore\">Con almacén de claves</string>\n    <string name=\"filter_apps_with_saf\">Con SAF</string>\n    <string name=\"filter_apps_with_ssaid\">Con SSAID</string>\n    <string name=\"action_continue\">Continuar</string>\n    <string name=\"install_for_another_user\">Instalar para…</string>\n    <string name=\"confirm_uninstallation\">Confirmar desinstalación</string>\n    <string name=\"grant_required_permission\">Otorgar el permiso requerido</string>\n    <string name=\"grant_overlay_permission_message\">Permitir que App Manager muestre una ventana flotante</string>\n    <string name=\"grant_accessibility_permission_for_tracking_window_contents\">Permita que App Manager utilice la función de accesibilidad para rastrear el contenido de la ventana principal.</string>\n    <string name=\"app_manager_build_expired\">Actualización requerida</string>\n    <string name=\"app_manager_build_expired_message\">Para garantizar la seguridad de su dispositivo y sus datos, se retiró la versión de App Manager que estába utilizando. Tienes que actualizarlo a la última versión para seguir usándolo, o desinstalarlo si no hay actualización disponible.</string>\n    <string name=\"app_manager_build_expiring_soon_warning\">Esta versión de App Manager caducará muy pronto. Actualícelo a la última versión.</string>\n    <string name=\"renamed_successfully\">Renombrado</string>\n    <string name=\"selinux_context\">contexto de SELinux</string>\n    <string name=\"unix_file_permissions\">Modo</string>\n    <string name=\"select_a_dex2oat_compiler_filter\"><tt>dex2oat</tt> filtro del compilador</string>\n    <string name=\"optimize_option_compile_layouts\">Compilar los recursos de diseño</string>\n    <string name=\"optimize_option_clear_profile_data\">Borrar datos de perfil anteriores</string>\n    <string name=\"optimize_option_check_profiles\">Considere datos de perfil durante la optimización DEX</string>\n    <string name=\"optimize_option_force_compilation\">Forzar la compilacion aunque no sea necesario</string>\n    <string name=\"optimize_option_force_dexopt\">Realizar inmediatamente la optimización DEX</string>\n    <string name=\"title_perform_runtime_optimization_to_apps\">Realizar optimización del tiempo de ejecución</string>\n    <string name=\"action_run\">Iniciar</string>\n    <string name=\"summary_perform_runtime_optimization_to_apps\">Optimice DEX y diseños (en Android 10 y versiones posteriores) para mejorar el rendimiento de las aplicaciones.</string>\n    <string name=\"action_optimize_app\">Optimización</string>\n    <string name=\"batch_ops_runtime_optimization\">Optimización del tiempo de ejecución</string>\n    <plurals name=\"alert_failed_to_optimize_apps\">\n        <item quantity=\"one\">No se han podido optimizar %1$d aplicacion</item>\n        <item quantity=\"many\">No se han podido optimizar %1$d aplicaciones</item>\n        <item quantity=\"other\">No se han podido optimizar %1$d aplicaciones</item>\n    </plurals>\n    <string name=\"app_info_tag_open_links\">Open links</string>\n    <string name=\"title_domains_supported_by_the_app\">Dominios soportados</string>\n    <string name=\"block_unblock_components_dots\">Bloquear/desbloquear componentes…</string>\n    <string name=\"unblock_components_dots\">Desbloquear componentes…</string>\n    <string name=\"block_unblock_components_description\">Bloquear o desbloquear todos los componentes identificados por las firmas dadas</string>\n    <plurals name=\"alert_failed_to_unblock_components\">\n        <item quantity=\"one\">No se pudo desbloquear los componentes para %1$d app</item>\n        <item quantity=\"many\">No se pudieron desbloquear los componentes para %1$d app</item>\n        <item quantity=\"other\"></item>\n    </plurals>\n</resources>"
  },
  {
    "path": "app/src/main/res/values-fa/disclaimer.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- SPDX-License-Identifier: GPL-3.0-or-later --><resources>\n    <string name=\"disclaimer_exit\">خروج</string>\n    <string name=\"disclaimer_agree\">قبول می‌کنم</string>\n    <string name=\"disclaimer_agree_forever\">دیگر این را نشان نده</string>\n    <string name=\"disclaimer_footer\">© 2020-2024 منتشر الاسلام</string>\n    <string name=\"disclaimer_body\">App Manager امکانات مبتنی بر روت ارائه می‌دهد که اگر اشتباه استفاده شوند ممکن است به دستگاه شما آسیب برسانند. App Manager مسئول هیچ آسیبی که با استفاده از این برنامه وارد شود نیست. اگر شما کاملا از نحوه کار روت آگاه نیستید، تا زمانی که کاملا از ریسک ها آگاه شوید باید از استفاده از گزینه های روت دوری کنید.\n\\n\n\\nهر لینکی که به برنامه ها و سایت های دیگر ارائه می‌دهم، برای منفعت کاربر است. من مسئول هیچ محتوایی که ممکن است با رفتن به لینک های خارجی پیدا کنید نیستم.\n\\n\n\\nبا استفاده از App Manager، شما تماما مسئولیت استفاده شخصی خود را قبول می‌کنید و قبول می‌کنید هیچ آسیب، ادعا یا ارزش مالی‌ای به‌خاطر استفاده غلط وارد نخواهد بود.\n\\n\n\\nبا استفاده از App Manager، شما تمام مسئولیت استفاده از آن را قبول می‌کنید و قبول می‌کنید من مسئول هیچ عملی که شما انجام دهید و باعث تاثیری ناسازگار بر دستگاه شما شود، نخواهم داشت.</string>\n    <string name=\"disclaimer_header\">سلب مسئولیت</string>\n</resources>"
  },
  {
    "path": "app/src/main/res/values-fa/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- SPDX-License-Identifier: GPL-3.0-or-later --><resources xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:tools=\"http://schemas.android.com/tools\">\n    <string name=\"_lang_tag\" translatable=\"false\">fa</string>\n    <string name=\"external_multiple_data_dir\">دایرکتوری داده‌های خارجی <xliff:g id=\"dir_no\" example=\"1\">%1$d</xliff:g></string>\n    <string name=\"external_data_dir\">دایرکتوری داده های خارجی</string>\n    <string name=\"sort_by_blocked_components\">اول مسدود</string>\n    <string name=\"exodus_link\">پیوند εxodus</string>\n    <string name=\"usage_yesterday\">دیروز</string>\n    <string name=\"app_settings\">تنظیمات</string>\n    <string name=\"usage_access\">دسترسی به استفاده</string>\n    <string name=\"pref_global_blocking_enabled_msg\">به شما اجازه می دهد تا هر جزء از هر برنامه ای را مسدود کنید بدون اینکه به صراحت مسدود کردن برنامه را روشن کنید.</string>\n    <string name=\"pref_global_blocking_enabled\">مسدود کردن اجزای فوری جهانی</string>\n    <string name=\"str_logo\">لوگو</string>\n    <string name=\"rules_not_applied\">قوانین اعمال نمی شوند</string>\n    <string name=\"failed_to_disable_op\">قادر به فعال کردن عملیات برنامه درخواست شده نبود</string>\n    <string name=\"failed_to_enable_op\">قادر به فعال کردن عملیات برنامه درخواست شده نبود</string>\n    <string name=\"no_app_ops\">بدون عملیات برنامه</string>\n    <string name=\"app_ops\">عملیات برنامه</string>\n    <string name=\"app_size\">برنامه</string>\n    <string name=\"total_size\">مجموع</string>\n    <string name=\"storage_and_cache\">ذخیره سازی و حافظه پنهان</string>\n    <string name=\"failed_to_stop\">نتوانست <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g> را متوقف کند.</string>\n    <string name=\"force_stop\">توقف اجباری</string>\n    <string name=\"enable\">فعال کن</string>\n    <string name=\"disable\">غیرفعال کردن</string>\n    <string name=\"stopped\">متوقف</string>\n    <string name=\"uninstall_system_app_message\">این یک برنامه سیستم است. آیا مطمئن هستید که می خواهید این برنامه را حذف کنید؟</string>\n    <string name=\"uninstalled_successfully\"><xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g> حذف شده است.</string>\n    <string name=\"failed_to_uninstall\">نتوانست <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g> را حذف کند.</string>\n    <string name=\"uninstall_app_message\">آیا می خواهید این برنامه را حذف کنید؟</string>\n    <string name=\"view_in_settings\">مشاهده در تنظیمات</string>\n    <string name=\"no_content\">بدون محتوا</string>\n    <string name=\"no_usage_in_this_time_range\">بدون استفاده در این محدوده زمانی</string>\n    <string name=\"disabled_app\">غیرفعال</string>\n    <string name=\"key_name_cannot_be_null\">نام کلید نمی تواند خالی باشد</string>\n    <string name=\"error_evaluating_input\">نتوانست ورودی را ارزیابی کند</string>\n    <string name=\"type_string\">کاراکتر‌ها</string>\n    <string name=\"type_long\">عدد صحیح طولانی</string>\n    <string name=\"type_int\">عدد صحیح</string>\n    <string name=\"type_float\">عدد اعشاری</string>\n    <string name=\"type_boolean\">درست/نادرست</string>\n    <string name=\"done\">انجام شد</string>\n    <string name=\"add_item\">افزودن مورد</string>\n    <string name=\"select_type\">نوعی را انتخاب کنید</string>\n    <string name=\"key_name\">نام کلید</string>\n    <string name=\"boolean_value\">ارزش بولی</string>\n    <string name=\"decimal_value\">ارزش اعشاری</string>\n    <string name=\"integer_value\">مقدار عدد صحیح</string>\n    <string name=\"long_integer_value\">مقدار صحیح طولانی</string>\n    <string name=\"string_value\">مقدار رشته</string>\n    <string name=\"saving_failed\">ذخیره نشد ، دوباره امتحان کنید.</string>\n    <string name=\"saved_successfully\">ذخیره شد</string>\n    <string name=\"deletion_failed\">پاک‌سازی شکست خورد</string>\n    <string name=\"deleted_successfully\">پاک شد</string>\n    <string name=\"delete\">پاک کن</string>\n    <string name=\"save\">ذخیره کن</string>\n    <string name=\"discard\">دور بینداز</string>\n    <string name=\"databases\">پایگاه داده‌ها</string>\n    <string name=\"shared_prefs\">Perf های به اشتراک گذاشته شده</string>\n    <string name=\"test_only\">تنها تست</string>\n    <string name=\"debuggable\">قابل اشکال‌زدایی</string>\n    <string name=\"updated_app\">به‌روز شده</string>\n    <string name=\"requested_large_heap\">پشته بزرگ</string>\n    <string name=\"no_code\">بدون کد</string>\n    <string name=\"process_name\">نام فرآیند</string>\n    <string name=\"native_library_dir\">دایرکتوری کتابخانه JNI بومی</string>\n    <string name=\"dev_protected_data_dir\">دایرکتوری داده های محافظت شده توسط دستگاه</string>\n    <string name=\"search\">جست‌وجو</string>\n    <string name=\"menu_apply_rules\">اعمال قوانین</string>\n    <string name=\"menu_remove_rules\">حذف قوانین</string>\n    <string name=\"failed_to_extract_apk_file\">نتوانست فایل APK را استخراج کند</string>\n    <string name=\"share_apk\">اشتراک گذاری APK</string>\n    <string name=\"grant_usage_acess_message\">برای نمایش اطلاعات استفاده از برنامه ، رهگیری مصرف آن اجباری است.</string>\n    <string name=\"grant_usage_access\">دسترسی استفاده را کسب کنید</string>\n    <string name=\"go\">برو</string>\n    <string name=\"go_back\">برگرد عقب</string>\n    <string name=\"usage_less_than_a_minute\">کمتر از یک دقیقه</string>\n    <plurals name=\"usage_hours\">\n        <item quantity=\"one\">%1$d ساعت</item>\n        <item quantity=\"other\">%1$d ساعت</item>\n    </plurals>\n    <plurals name=\"usage_days\">\n        <item quantity=\"one\">%1$d روز</item>\n        <item quantity=\"other\">%1$d روز</item>\n    </plurals>\n    <plurals name=\"usage_months\">\n        <item quantity=\"one\">%1$d ماه</item>\n        <item quantity=\"other\">%1$d ماه</item>\n    </plurals>\n    <string name=\"usage_7_days\">7 روز گذشته</string>\n    <string name=\"usage_today\">امروز</string>\n    <string name=\"usage_weekly\">هفتگی</string>\n    <string name=\"app_usage\">استفاده از برنامه</string>\n    <string name=\"no_tracker_class\">بدون کلاس های ردیاب</string>\n    <string name=\"no_shared_libs\">بدون کتابخانه مشترک</string>\n    <plurals name=\"main_list_date_days\">\n        <item quantity=\"one\"><xliff:g id=\"last_update_date\" example=\"20/10/2020\"> %1$s </xliff:g> <xliff:g id=\"day_no\" example=\"5\"> %2$d </xliff:g> روز</item>\n        <item quantity=\"other\"><xliff:g id=\"last_update_date\" example=\"20/10/2020\"> %1$s </xliff:g> <xliff:g id=\"day_no\" example=\"5\"> %2$d </xliff:g> روز‌</item>\n    </plurals>\n    <string name=\"all_classes\">همه کلاس‌ها</string>\n    <string name=\"tracker_classes\">کلاس های ردیاب</string>\n    <string name=\"tracker_details\">جزئیات ردیاب</string>\n    <string name=\"ecc\">رمزنگاری منحنی بیضوی</string>\n    <string name=\"found_trackers\">ردیاب‌های یافت شده:</string>\n    <plurals name=\"other_trackers_and_classes\">\n        <item quantity=\"one\"><xliff:g id=\"tracker_no\" example=\"8\"> %1$d </xliff:g> ردیاب با کلاس‌های <xliff:g id=\"class_no\" example=\"50\"> %2$d </xliff:g></item>\n        <item quantity=\"other\"><xliff:g id=\"tracker_no\" example=\"8\"> %1$d </xliff:g> ردیاب با کلاس‌های <xliff:g id=\"class_no\" example=\"50\"> %2$d </xliff:g></item>\n    </plurals>\n    <plurals name=\"two_trackers_and_classes\">\n        <item quantity=\"one\">2 ردیاب با کلاس‌های <xliff:g id=\"class_no\" example=\"50\"> %1$d </xliff:g></item>\n        <item quantity=\"other\">2 ردیاب با کلاس‌های <xliff:g id=\"class_no\" example=\"50\"> %1$d </xliff:g></item>\n    </plurals>\n    <plurals name=\"tracker_and_classes\">\n        <item quantity=\"one\">1 ردیاب با کلاس <xliff:g id=\"class_no\" example=\"50\"> %1$d </xliff:g></item>\n        <item quantity=\"other\">1 ردیاب با کلاس‌های <xliff:g id=\"class_no\" example=\"50\"> %1$d </xliff:g></item>\n    </plurals>\n    <string name=\"toggle_class_listing\">تغییر وضع لیست کردن کلاس</string>\n    <string name=\"class_viewer\">بیننده کلاس</string>\n    <string name=\"word_wrap\">تغییر وضعیت کلمه</string>\n    <string name=\"credits_message\">به نویسندگان\n\\n- پروژه متن باز اندروید\n\\n- <a href=\"https://github.com/zhaobozhen/libraries\">Absinthe\\'s libraries</a>\n\\n- <a href=\"https://github.com/butzist/ActivityLauncher\">Activity Launcher</a>\n\\n- <a href=\"https://bitbucket.org/oF2pks/fdroid-applications-info\">اطلاعات بسته های برنامه ها </a>\n\\n- <a href=\"https://github.com/zhaobao/AppsMonitor\">نظارت بر برنامه ها</a>\n\\n- <a href=\"https://github.com/8enet/AppOpsX\">برنامه OpsX</a>\n\\n- <a href=\"https://github.com/gabrielemariotti/changeloglib\">کتابخانه گزارش تغییر</a>\n\\n- <a href=\"https://bitbucket.org/oF2pks/fdroid-classyshark3xodus\">ClassySharkAndroid</a>\n\\n- <a href=\"https://github.com/billthefarmer/editor\">ویرایشگر</a>\n\\n- <a href=\"https://github.com/Raival-e/File-Explorer\">مدیرفایل</a>\n\\n- <a href=\"https://github.com/nex3z/FlowLayout\">FlowLayout</a>\n\\n- <a href=\"https://github.com/k3b/intent-intercept\">Intent Intercept</a>\n\\n- <a href=\"https://github.com/YarikSOffice/lingver\">Lingver</a>\n\\n- <a href=\"https://github.com/topjohnwu/Magisk\">Magisk</a>\n\\n- <a href=\"https://github.com/zhanghai/MaterialFiles\">فایل های متریال</a>\n\\n- <a href=\"https://github.com/pluscubed/matlog\">MatLog</a>\n\\n- <a href=\"https://github.com/matrix-org/matrix-android-sdk\">Matrix Android SDK</a>\n\\n- <a href=\"https://github.com/jensstein/oandbackup\">OAndBackup</a>\n\\n- <a href=\"https://github.com/open-keychain/open-keychain\">Open Keychain</a>\n\\n- <a href=\"https://github.com/Aefyr/SAI\">SAI</a>\n\\n- <a href=\"https://github.com/RikkaApps/Shizuku\">Shizuku</a>\n\\n- <a href=\"https://github.com/eclipse/tm4e\">tm4e</a>\n\\n- <a href=\"https://github.com/tuyafeng/Watt\">Watt</a></string>\n    <string name=\"credits\">اعتبارات</string>\n    <string name=\"third_party\">کتابخانه‌ها و آیکون های شخص سوم</string>\n    <string name=\"license\">لایسنس</string>\n    <string name=\"icon_picker\">انتخاب‌گر آیکون</string>\n    <string name=\"class_name\">نام کلاس</string>\n    <string name=\"package_name\">نام بسته</string>\n    <string name=\"shortcut_name\">نام میانبر</string>\n    <string name=\"create_shortcut\">ساخت میانبر</string>\n    <string name=\"starting_activity\">شروع فعالیت:<xliff:g id=\"activity_name\" example=\".main.MainActivity\">%1$s</xliff:g></string>\n    <string name=\"error_verbose_pin_shortcut\">راه انداز کنونی از PinShortcut پشتیبانی نمی‌کند. ایجاد میانبر امکان‌پذیر نیست.</string>\n    <string name=\"error_creating_shortcut\">خطا در ایجاد میانبر</string>\n    <string name=\"empty_package_name\">نام بسته خالی</string>\n    <string name=\"main_activity\">فعالیت اصلی</string>\n    <string name=\"user_id\">شناسه کاربر</string>\n    <string name=\"installer_app\">برنامه نصب کننده</string>\n    <string name=\"date_updated\">تاریخ به‌روزرسانی</string>\n    <string name=\"date_installed\">تاریخ نصب شده</string>\n    <string name=\"more_info\">اطلاعات بیشتر</string>\n    <string name=\"sdk_flags\">پرچم‌ها</string>\n    <string name=\"sdk_max\">هدف</string>\n    <string name=\"sdk_min\">کمترین</string>\n    <string name=\"data_dir\">پوشه دیتا</string>\n    <string name=\"source_dir\">پوشه منبع</string>\n    <string name=\"paths_and_directories\">مسیرها و پوشه ها</string>\n    <string name=\"user_app\">برنامه کاربر</string>\n    <string name=\"system_app\">برنامه سیستمی</string>\n    <string name=\"app_info\">اطلاعات برنامه</string>\n    <string name=\"version_name_with_code\">نسخه <xliff:g id=\"version_name\" example=\"2.5.17\">%1$s</xliff:g> (<xliff:g id=\"version_code\" example=\"365\">%2$d</xliff:g>)</string>\n    <string name=\"sort\">مرتب سازی</string>\n    <string name=\"user\">کاربر</string>\n    <string name=\"system\">سیستم</string>\n    <string name=\"app_not_installed\">برنامه نصب نشده است</string>\n    <string name=\"media_size\">رسانه</string>\n    <string name=\"obb_size\">Obb</string>\n    <string name=\"cache_size\">حافظه پنهان</string>\n    <string name=\"data_size\">داده‌ها</string>\n    <string name=\"about\">درباره</string>\n    <string name=\"data_usage_msg\">مصرف دیتا</string>\n    <string name=\"data_transmitted\">داده‌ها منتقل شدند</string>\n    <string name=\"data_received\">داده ها دریافت شدند</string>\n    <string name=\"sort_by_target_sdk\">کیت نرم افزاری هدف</string>\n    <string name=\"sort_by_domain\">برنامه های کاربر در ابتدای لیست</string>\n    <string name=\"sort_by_package_name\">نام بسته</string>\n    <string name=\"sort_by_app_label\">برچسب برنامه</string>\n    <string name=\"loading\">درحال بارگذاری…</string>\n    <string name=\"error\">خطا</string>\n    <string name=\"manifest\">مانیفست</string>\n    <string name=\"input_features\">ویژگی های ورودی</string>\n    <string name=\"no_configurations\">پیکربندی موجود نیست</string>\n    <string name=\"configurations\">پیکربندی‌ها</string>\n    <string name=\"app_signing_no_signatures\">امضاهای معتبر موجود نیست</string>\n    <string name=\"signatures\">امضاها</string>\n    <string name=\"sort_by_sha\">امضا</string>\n    <string name=\"shared_user_id\">شناسه کاربر مشترک</string>\n    <string name=\"sort_by_shared_user_id\">شناسه کاربری مشترک</string>\n    <string name=\"no_feature\">هیچ ویژگی موجود نیست</string>\n    <string name=\"uses_feature\">از این ویژگی ها استفاده می کند</string>\n    <string name=\"group\">گروه</string>\n    <string name=\"shared_libs\">کتابخانه های مشترک</string>\n    <string name=\"declared_permission\">مجوزها</string>\n    <string name=\"patterns_allowed\">الگوها مجاز هستند</string>\n    <string name=\"write\">نوشتن</string>\n    <string name=\"read\">خواندن</string>\n    <string name=\"path_permissions\">مجوزهای مسیر</string>\n    <string name=\"grant_uri_permission\">مجوزهای URI را فعال کنید</string>\n    <string name=\"flags\">پرچم ها</string>\n    <string name=\"soft_input\">حالت ورودی نرم</string>\n    <string name=\"orientation\">جهت</string>\n    <string name=\"no_service\">سرویسی موجود نیست</string>\n    <string name=\"service\">سرویس ها</string>\n    <string name=\"authority\">مسئول</string>\n    <string name=\"sort_by_last_update\">آخرین به‌روزرسانی</string>\n    <string name=\"task_affinity\">ترکیب وظایف</string>\n    <string name=\"launch_mode\">حالت اجرا</string>\n    <string name=\"no_providers\">ارائه دهنده ای موجود نیست</string>\n    <string name=\"providers\">ارائه دهندگان</string>\n    <string name=\"no_receivers\">گیرنده ای موجود نیست</string>\n    <string name=\"receivers\">گیرنده ها</string>\n    <string name=\"no_activities\">فعالیتی موجود نیست</string>\n    <string name=\"refresh\">تازه سازی</string>\n    <string name=\"launch\">اجرا</string>\n    <string name=\"activities\">فعالیت ها</string>\n    <string name=\"require_no_permission\">مجوزی لازم نیست</string>\n    <string name=\"permissions\">از مجوزها استفاده می کند</string>\n    <string name=\"uninstall\">حذف نصب</string>\n    <string name=\"export_blocking_rules\">قوانین مسدود سازی را صادر کن</string>\n    <string name=\"disable_background\">غیر فعال کردن پیش گیری از عملیات پس زمینه</string>\n    <string name=\"backup_restore\">پشتیبان گیری/بازیابی</string>\n    <string name=\"clear_data\">پاک کردن داده‌ها</string>\n    <string name=\"user_and_uid\">کاربر:<xliff:g id=\"user_name\" example=\"root\">%1$s</xliff:g>(<xliff:g id=\"user_id\" example=\"0\">%2$d</xliff:g>)</string>\n    <string name=\"memory_virtual_memory\">حافظه: %1$s، از نوع مجازی: %2$s</string>\n    <string name=\"pid_and_ppid\">شناسه فرآیند: %1$d ، شناسه فرآیند والد: %2$d</string>\n    <string name=\"disable_background_run\">غیرفعال کردن جلوگیری از فعالیت پس‌زمینه</string>\n    <string name=\"kill_process\">بکش</string>\n    <string name=\"running_apps\">برنامه های در حال اجرا</string>\n    <string name=\"apk_updater\">به‌روزرسان APK</string>\n    <plurals name=\"failed_to_import_files\">\n        <item quantity=\"one\">نتوانست %1$d پرونده را وارد کند.</item>\n        <item quantity=\"other\">نتوانست %1$d پرونده را وارد کند.</item>\n    </plurals>\n    <string name=\"the_export_was_successful\">صادر شد</string>\n    <string name=\"the_import_was_successful\">وارد شد</string>\n    <string name=\"pref_import_blocker\">وارد کردن از Blocker</string>\n    <string name=\"pref_import_watt\">وارد کردن از Watt</string>\n    <string name=\"pref_import_export_blocking_rules_msg\">وارد/صادر کردن قوانین، قوانین خارجی را از Watt یا Blocker وارد کنید.</string>\n    <string name=\"pref_import_export_blocking_rules\">وارد/استخراج قوانین مسدود سازی</string>\n    <string name=\"sort_by_mobile_data\">داده های موبایل</string>\n    <string name=\"sort_by_times_opened\">دفعات باز کردن</string>\n    <string name=\"sort_by_screen_time\">زمان نمایش</string>\n    <string name=\"sort_by_last_used\">آخرین استفاده</string>\n    <plurals name=\"no_of_times_opened\">\n        <item quantity=\"one\">%1$d بار</item>\n        <item quantity=\"other\">%1$d بار</item>\n    </plurals>\n    <string name=\"toggle_kill_for_system_apps\">کشتن برنامه های سیستم را تغییر وضع بده</string>\n    <plurals name=\"alert_failed_to_force_stop\">\n        <item quantity=\"one\">نتوانست %1$d برنامه را اجبارا متوقف کند</item>\n        <item quantity=\"other\">نتوانست %1$d برنامه را اجبارا متوقف کند</item>\n    </plurals>\n    <string name=\"the_operation_was_successful\">انجام شد</string>\n    <plurals name=\"alert_failed_to_disable_background\">\n        <item quantity=\"one\">نتوانست از اجرای %1$d برنامه در پس‌زمینه جلوگیری کند</item>\n        <item quantity=\"other\">نتوانست از اجرای %1$d برنامه در پس‌زمینه جلوگیری کند</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_uninstall\">\n        <item quantity=\"one\">نتوانست %1$d برنامه را پاک کند</item>\n        <item quantity=\"other\">نتوانست %1$d برنامه را پاک کند</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_clear_data\">\n        <item quantity=\"one\">نتوانست داده های %1$d برنامه را پاک کند</item>\n        <item quantity=\"other\">نتوانست داده های %1$d برنامه را پاک کند</item>\n    </plurals>\n    <string name=\"pref_import_existing\">قوانین موجود را وارد کن</string>\n    <string name=\"source_code\">کد منبع</string>\n    <string name=\"update\">به‌روزرسانی کن</string>\n    <string name=\"install\">نصب کن</string>\n    <plurals name=\"no_of_trackers\">\n        <item quantity=\"one\">%1$d ردیاب</item>\n        <item quantity=\"other\">%1$d ردیاب</item>\n    </plurals>\n    <string name=\"manifest_viewer\">مشاهده‌گر مانیفست</string>\n    <string name=\"external_apk_no_app_op\">فایل های نصبی خارجی هیچ عملیات برنامه ای ندارد</string>\n    <string name=\"changelog\">گزارش تغییرات</string>\n    <string name=\"one_click_ops\">عملیات یک کلیکی</string>\n    <string name=\"never_ask\">دیگر نپرس</string>\n    <string name=\"launch_app\">اجرا کن</string>\n    <string name=\"failed_to_deny_dangerous_app_ops\">نتوانست تمام فعالیت برنامه‌های خطرناک را فسخ کند</string>\n    <string name=\"failed_to_deny_dangerous_perms\">نتوانست تمام مجوز‌های خطرناک را فسخ کند</string>\n    <string name=\"failed_to_reset_app_ops\">نتوانست عملیات برنامه را بازنشانی کند</string>\n    <string name=\"failed_to_revoke_permission\">نتوانست مجوز را فسخ کند</string>\n    <string name=\"failed_to_grant_permission\">نتوانست مجوز بگیرد</string>\n    <plurals name=\"alert_failed_to_disable_trackers\">\n        <item quantity=\"one\">نتوانست ردیاب‌ها را از %1$d برنامه غیرفعال کند</item>\n        <item quantity=\"other\">نتوانست ردیاب‌ها را از %1$d برنامه غیرفعال کند</item>\n    </plurals>\n    <string name=\"unknown_op\">عملیات ناشناخته</string>\n    <string name=\"sort_by_tracker_components\">اول ردیاب ها</string>\n    <string name=\"deny_dangerous_permissions\">مجوز های خطرناک را رد کن</string>\n    <string name=\"sort_by_denied_permissions\">اول رد شده</string>\n    <string name=\"sort_by_dangerous_permissions\">اول خطرناک</string>\n    <string name=\"sort_by_permission_names\">نام مجوز</string>\n    <string name=\"sort_by_app_ops_values\">مقدار عملیات برنامه</string>\n    <string name=\"sort_by_denied_app_ops\">اول رد شده</string>\n    <string name=\"sort_by_app_ops_names\">نام عملیات برنامه</string>\n    <string name=\"deny_dangerous_app_ops\">عملیات برنامه های خطرناک را رد کن</string>\n    <string name=\"reset_to_default\">به پیشفرض بازگردان</string>\n    <string name=\"sort_by_component_name\">نام جز</string>\n    <string name=\"block_trackers\">ردیاب ها را مسدود کن</string>\n    <string name=\"sort_by_wifi_data\">داده وای فای</string>\n    <string name=\"version\">نسخه</string>\n    <string name=\"pref_about_msg\">نسخه مدیر برنامه، پروانه، اعتبار، و غیره.</string>\n    <string name=\"apply\">اعمال کن</string>\n    <string name=\"select_theme\">تم</string>\n    <string name=\"night\">شب</string>\n    <string name=\"day\">روز</string>\n    <string name=\"battery_mode\">حالت باتری</string>\n    <string name=\"follow_system\">از سیستم پیروی کن</string>\n    <string name=\"pref_app_theme\">تم برنامه</string>\n    <string name=\"pref_import_blocker_msg\">قوانین مسدودسازی را، هر فایل حاوی قوانینی یک package، از Blocker وارد کن.</string>\n    <string name=\"pref_import_watt_msg\">قوانین مسدود کردن را از Watt وارد کنید، هر فایل حاوی قوانینی برای یک بسته با نام به عنوان <tt>packagename.xml</tt> و غیره است.</string>\n    <string name=\"pref_import_msg\">قوانین مسدود سازی پیشتر صادر شده از مدیر برنامه را وارد کن.</string>\n    <string name=\"pref_export_msg\">قوانین مسدود سازی پیکربندی شده از داخل مدیر برنامه را به حافظه خارجی صادر کن.</string>\n    <string name=\"touchscreen\">صفحه لمسی</string>\n    <string name=\"navigation\">ناوبری</string>\n    <string name=\"keyboard_type\">نوع صفحه کلید</string>\n    <string name=\"export_failed\">صادر کردن شکست خورد!</string>\n    <string name=\"import_failed\">وارد کردن شکست خورد!</string>\n    <string name=\"export_options\">گزینه های صادر کردن</string>\n    <string name=\"import_options\">گزینه های وارد کردن</string>\n    <string name=\"pref_export\">صادر کن</string>\n    <string name=\"pref_import\">وارد کن</string>\n    <string name=\"ago\">گذشته</string>\n    <string name=\"reject_time\">زمان رد کردن</string>\n    <string name=\"accept_time\">زمان قبول کردن</string>\n    <string name=\"duration\">مدت</string>\n    <string name=\"running\">درحال اجرا</string>\n    <string name=\"mode\">حالت</string>\n    <string name=\"permission_name\">نام مجوز</string>\n    <string name=\"backup_options\">گزینه های پشتیبان‌گیری</string>\n    <string name=\"delete_backup\">حذف پشتیبان</string>\n    <string name=\"restore\">بازیابی</string>\n    <string name=\"backup\">پشتیبان</string>\n    <string name=\"data\">داده‌ها</string>\n    <string name=\"external_data\">داده خارجی</string>\n    <string name=\"blocking_rules\">قوانین مسدود کردن</string>\n    <string name=\"whats_new\">موارد جدید</string>\n    <string name=\"features\">ویژگی‌ها</string>\n    <string name=\"components\">اجزاء</string>\n    <string name=\"trackers\">ردیاب‌ها</string>\n    <string name=\"installed_version\">نسخه نصب شده</string>\n    <string name=\"select_all\">انتخاب همه</string>\n    <string name=\"filter_apps_with_rules\">برنامه‌های دارای قوانین</string>\n    <string name=\"filter_system_apps\">برنامه‌های سیستم</string>\n    <string name=\"filter_user_apps\">برنامه‌های کاربر</string>\n    <string name=\"filter\">صافی</string>\n    <string name=\"package_name_is_installed_successfully\"><xliff:g id=\"app_name\" example=\"App Manager\"> %1$s </xliff:g> نصب شده</string>\n    <string name=\"termux\">ترماکس</string>\n    <plurals name=\"no_of_splits\">\n        <item quantity=\"one\">%1$d قسمت</item>\n        <item quantity=\"other\">%1$d قسمت</item>\n    </plurals>\n    <string name=\"failed_to_parse_some_numbers\">تجزیه برخی از اعداد امکان پذیر نیست</string>\n    <string name=\"only_works_in_root_or_adb_mode\">فقط در حالت روت یا ADB کار می‌کند</string>\n    <string name=\"input_app_ops_description\">نام‌های عملیات برنامه و/یا ثابت‌ها را با فاصله وارد کنید، به عنوان مثال. <tt>WAKE_LOCK 63 72 CAMERA</tt> و غیره</string>\n    <string name=\"input_app_ops\">عملیات برنامه ورودی</string>\n    <string name=\"filtered_packages\">بسته‌های فیلتر شده</string>\n    <string name=\"input_signatures_description\">وارد کردن امضا با فاصله به عنوان مثال <tt> com.facebook org.app2 com.app3 </tt> و غیره.</string>\n    <string name=\"input_signatures\">امضاهای ورودی</string>\n    <string name=\"failed_packages\">بسته‌های ناموفق</string>\n    <string name=\"no_tracker_found\">هیچ ردیابی یافت نشد</string>\n    <string name=\"clear_app_cache_description\">حافظه پنهان همه برنامه ها را پاک می کند</string>\n    <string name=\"clear_app_cache\">پاک کردن حافظه پنهان برنامه</string>\n    <string name=\"clear_data_from_uninstalled_apps\">داده برنامه های حذف‌نصب شده را پاک کن</string>\n    <string name=\"block_components_dots\">مسدود کردن اجزا…</string>\n    <string name=\"block_unblock_trackers_description\">مسدود کردن یا رفع انسداد اجزای تبلیغات و ردیابی در همه برنامه های نصب شده</string>\n    <string name=\"clear_cache\">پاک کردن حافظه پنهان</string>\n    <string name=\"pref_import_existing_msg\">اجزای غیرفعال شده توسط سایر برنامه ها را به مدیر برنامه اضافه کن. زمانی از این ابزار استفاده می‌کنید مراقب باشید که ممکن است مثبت کاذب های بسیاری موجود باشد. تنها برنامه هایی را انتخاب کنید که از آنها اطمینان دارید.</string>\n    <string name=\"deny_app_ops_description\">حالتی را برای عملیات برنامه تعیین کنید که با مقادیر ثابت مشخص شده است، یعنی <tt>63</tt> یا <tt>RUN_IN_BACKGROUND</tt></string>\n    <string name=\"installer_error_session_create\">نتوانست یک جلسه نصب کننده ایجاد کند</string>\n    <string name=\"installer_error_security\">نمی‌توان به فایل های نصبی دسترسی پیدا کرد</string>\n    <string name=\"install_in_progress\">درحال نصب…</string>\n    <string name=\"package_installer\">نصب کننده بسته</string>\n    <string name=\"unblock_trackers\">رفع انسداد ردیاب‌ها</string>\n    <string name=\"reinstall\">نصب مجدد</string>\n    <string name=\"install_app_message\">آیا می خواهید این برنامه را نصب کنید؟</string>\n    <string name=\"try_again\">دوباره تلاش کنید</string>\n    <string name=\"full_stop_tap_to_see_details\">. برای دیدن جزئیات ضربه بزنید.</string>\n    <string name=\"operation_running\">عمليات در حال اجرا …</string>\n    <string name=\"batch_ops\">عملیات دسته‌ای</string>\n    <string name=\"failed_to_fetch_package_info\">نتوانست اطلاعات بسته را واکشی کند</string>\n    <string name=\"installer_error_lidl_rom\">رام شما با نصب بدون روت ناسازگار است.</string>\n    <string name=\"installer_error_generic\">نصب ناموفق بود</string>\n    <string name=\"installer_error_storage\">فضای ذخیره سازی ناکافی برای نصب برنامه</string>\n    <string name=\"installer_error_bad_apks\">فایلهای APK نامعتبر انتخاب شده‌اند</string>\n    <string name=\"installer_error_incompatible\">برنامه با این دستگاه ناسازگار است</string>\n    <string name=\"installer_error_conflict\">برنامه نصب نشد زیرا نام بسته در حال استفاده است</string>\n    <string name=\"installer_error_blocked\">نصب توسط <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g> مسدود شده است</string>\n    <string name=\"installer_error_blocked_device\">دستگاه</string>\n    <string name=\"installer_error_aborted\">نصب انجام نشد زیرا لغو شد یا جلسه به طور غیرمنتظره بسته شد</string>\n    <string name=\"toggle_default_app_ops\">عملیات برنامه پیش‌فرض را تغییر بده</string>\n    <string name=\"filter_apps_with_activities\">برنامه ها با فعالیت شان</string>\n    <string name=\"are_you_sure\">آیا مطمئن هستید؟</string>\n    <string name=\"pref_remove_all_rules_msg\">مجوزها اعطا می شوند، عملیات و اجزای برنامه به مقادیر پیش فرض خود باز می گردند.</string>\n    <string name=\"pref_remove_all_rules\">حذف تمام قوانین</string>\n    <string name=\"website\">وب‌سایت</string>\n    <string name=\"run_in_termux\">اجرا در ترماکس</string>\n    <string name=\"open_in_termux\">باز‌کردن در ترماکس</string>\n    <string name=\"export_icon\">استخراج نماد</string>\n    <string name=\"no_matching_package_found\">هیچ بسته منطبقی یافت نشد ,چنین برنامه‌ای پیدا نشد</string>\n    <string name=\"block_unblock_trackers\">مسدود کردن/رفع انسداد ردیاب‌ها</string>\n    <string name=\"unblock\">رفع انسداد</string>\n    <string name=\"block\">مسدودسازی</string>\n    <string name=\"clear\">پاک‌کردن</string>\n    <string name=\"clear_data_message\">آیا مطمئن هستید که می‌خواهید داده‌ها را از این برنامه پاک کنید؟</string>\n    <string name=\"skip_signature_checks\">از بررسی‌ امضا رد شوید</string>\n    <string name=\"yes\">آره</string>\n    <string name=\"no\">نه</string>\n    <string name=\"apply_to_system_apps_question\">برای برنامه‌های سیستم نیز اعمال شود؟ اگر مطمئن نیستید \\\"نه\\\" را انتخاب کنید.</string>\n    <string name=\"apply_to_system_apps\">اعمال بر روی برنامه‌های سیستم</string>\n    <plurals name=\"verified_with_warning\">\n        <item quantity=\"one\">تایید شده با %d هشدار</item>\n        <item quantity=\"other\">تایید شده با %d هشدار</item>\n    </plurals>\n    <plurals name=\"app_signing_signature_schemes_pl\">\n        <item quantity=\"one\">طرح امضا</item>\n        <item quantity=\"other\">طروح امضا</item>\n    </plurals>\n    <plurals name=\"missing_signatures\">\n        <item quantity=\"one\">%1$d امضا ناموجود</item>\n        <item quantity=\"other\">%1$d امضا ناموجود</item>\n    </plurals>\n    <plurals name=\"libraries\">\n        <item quantity=\"one\">%1$d کتابخانه</item>\n        <item quantity=\"other\">%1$d کتابخانه ها</item>\n    </plurals>\n    <plurals name=\"classes\">\n        <item quantity=\"one\">%1$d کلاس</item>\n        <item quantity=\"other\">%1$d کلاس</item>\n    </plurals>\n    <plurals name=\"backup_exists_are_you_sure\">\n        <item quantity=\"one\">فایل پشتیبان موجود است. آیا اطمینان دارید؟</item>\n        <item quantity=\"other\">پشتیبان‌گیری برای بیش از یک برنامه وجود دارد. بیش از یک برنامه از قبل یک نسخه پشتیبان دارد. آیا اطمینان دارید؟</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_set_app_ops\">\n        <item quantity=\"one\">نتوانست عملیات برنامه را برای %1$d برنامه تنظیم کند</item>\n        <item quantity=\"other\">نتوانست عملیات برنامه را برای %1$d برنامه تنظیم کند</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_block_components\">\n        <item quantity=\"one\">نتوانست اجزای %1$d برنامه را مسدود کند</item>\n        <item quantity=\"other\">نتوانست اجزای %1$d برنامه را مسدود کند</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_unblock_trackers\">\n        <item quantity=\"one\">نتوانست ردیاب‌ها‌ را از %1$d برنامه مسدود کند</item>\n        <item quantity=\"other\">نتوانست ردیاب‌ها‌ را از %1$d برنامه مسدود کند</item>\n    </plurals>\n    <plurals name=\"no_of_components\">\n        <item quantity=\"one\">%1$d قسمت</item>\n        <item quantity=\"other\">%1$d اجزا</item>\n    </plurals>\n    <string name=\"user_with_id\">کاربر: <xliff:g id=\"user_id\" example=\"0\">%1$d</xliff:g></string>\n    <plurals name=\"alert_failed_to_delete_backup\">\n        <item quantity=\"one\">نتوانست %1$d پشتیبان را پاک کند</item>\n        <item quantity=\"other\">نتوانست %1$d پشتیبان را پاک کند</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_restore\">\n        <item quantity=\"one\">نتوانست %1$d برنامه را بازیابی کند</item>\n        <item quantity=\"other\">نتوانست %1$d برنامه را بازیابی کند</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_backup\">\n        <item quantity=\"one\">نتوانست از %1$d برنامه پشتیبان بگیرد</item>\n        <item quantity=\"other\">نتوانست از %1$d برنامه پشتیبان بگیرد</item>\n    </plurals>\n    <plurals name=\"failed_to_backup_some_apk_files\">\n        <item quantity=\"one\">نتوانست از %1$d برنامه پشتیبان بگیرد</item>\n        <item quantity=\"other\">نتوانست از %1$d برنامه پشتیبان بگیرد</item>\n    </plurals>\n    <string name=\"clear_data_from_uninstalled_apps_description\">پاک کردن اطلاعات برنامه هایی که حذف نصب شده‌اند<tt> با عنوان </tt> اطلاعات را حذف نکنید</string>\n    <string name=\"app_signing_signatures\">امضاها</string>\n    <string name=\"apps\">برنامه ها</string>\n    <string name=\"valid\">معتبر</string>\n    <string name=\"install_location\">محل نصب</string>\n    <string name=\"kernel\">هسته</string>\n    <string name=\"security_providers\">ارائه دهندگان امنیت</string>\n    <string name=\"profile_save_apk_msg\">فایل های APK را ذخیره می‌کند در <tt> مدیر برنامه/ برنامه ها</tt></string>\n    <string name=\"dsa_affine_y\">نسبت مختصات y</string>\n    <string name=\"root\">روت</string>\n    <string name=\"close\">بستن</string>\n    <string name=\"input_keystore_pass_msg\">برای وارد کردن رمز فروشگاه کلید اینجا را ضربه بزنید</string>\n    <string name=\"no_app_ops_permission\">هیچ مجوزی برای نمایش عملیات برنامه وجود ندارد</string>\n    <string name=\"orientation_user_landscape\">چشم انداز کاربر</string>\n    <string name=\"toast_invalid_level\">نام سطح نامعتبر: %s</string>\n    <string name=\"collapse_all\">جمع کردن همه</string>\n    <string name=\"widget_recording_in_progress\">در حال ضبط…</string>\n    <string name=\"undo\">برگشت</string>\n    <string name=\"omit_sensitive_info\">اطلاعات حساس را حذف کنید</string>\n    <string name=\"text_include_dmesg\">شامل گزارشات هسته هم شود</string>\n    <string name=\"omit_sensitive_info_summary\">اطلاعات حساس مانند آدرس وب، شماره تلفن یا ایمیل را حذف کنید.</string>\n    <string name=\"failed_to_unblock_trackers\">ردیاب ها رفع انسداد نشدند</string>\n    <plurals name=\"alert_failed_to_import_backups\">\n        <item quantity=\"one\">%1$d نسخه پشتیبان وارد نشد</item>\n        <item quantity=\"other\">%1$d نسخه پشتیبان ها وارد نشد</item>\n    </plurals>\n    <string name=\"failed\">شکست خورد</string>\n    <string name=\"pref_import_export_keystore_msg\">وارد/خارج , فروشگاه کلید قلعه فنری به صورت داخلی توسط مدیریت برنامه استفاده می‌شود.</string>\n    <string name=\"confirm_import_keystore\">آیا مطمئن هستید که می خواهید فروشگاه کلید موجود را جایگزین کنید؟ این عمل قابل بازگشت نیست.</string>\n    <string name=\"suspended\">معلق</string>\n    <string name=\"hidden\">مخفی</string>\n    <string name=\"pref_display_changes\">نمایش تغییرات</string>\n    <string name=\"netpolicy_reject_background_data\">داده های پس زمینه را رد کنید</string>\n    <string name=\"adb_connect\">متصل</string>\n    <string name=\"added_to_queue\">به صف اضافه شد</string>\n    <string name=\"help_uses_permissions_tab\">برای <b>اعطا</b> یا <b>لغو</b> روی یک مورد کلیک کنید. فقط مجوزهای <b>خطرناک</b> و <b>توسعه</b> ممکن است اعطا یا لغو شوند.</string>\n    <string name=\"minimum_version\">حداقل نسخه: %d</string>\n    <string name=\"pref_selected_users\">کابران انتخاب شده</string>\n    <string name=\"pref_selected_users_msg\">مدیر برنامه را محدود کنید تا فقط با کاربران انتخاب شده کار کند.</string>\n    <string name=\"permission_flags\">پرچم های مجوز</string>\n    <string name=\"saved_filters\">فیلتر های ذخیره شده</string>\n    <string name=\"has_net_policy\">سیاست حریم خصوصی</string>\n    <string name=\"enable_disable_features\">فعال و غیرفعال کردن ویژگی ها</string>\n    <string name=\"v4_scheme\">‌طرح نسخه 4(از اندروید 11)</string>\n    <string name=\"pref_signature_schemes_msg\">حداقل طرح های 1 و 2 باید برای سازگاری بیشتر انتخاب شوند. طرح 4 به 2 یا 3 نیاز دارد.</string>\n    <string name=\"verified\">تایید شده است</string>\n    <string name=\"not_verified\">تأیید نشده است</string>\n    <string name=\"pref_import_backups_msg\">پشتیبان‌گیری را از ٱن دی بک آپ، سویفت بک آپ (3.0–3.2) یا تیتانیوم بک‌آپ وارد کنید.</string>\n    <string name=\"add_filter_ellipsis\">افزودن فیلتر…</string>\n    <string name=\"pref_log_viewer_msg\">نحوه نمایش گزارش‌ها را پیکربندی کنید.</string>\n    <string name=\"pref_import_backups\">وارد کردن پشتیبان گیری ها</string>\n    <string name=\"import_from_oab\">وارد کردن پشتیبان گیری از ۰و بک آپ</string>\n    <string name=\"import_from_tb\">وارد کردن پشتیبان گیری از تیتانیوم بک‌آپ</string>\n    <string name=\"pref_filter_pattern_title\">فیلتر کردن برچسب ها</string>\n    <string name=\"pref_log_line_period_error\">لطفا یک عدد صحیح بین 1 تا 1000 وارد کنید.</string>\n    <string name=\"save_log\">ذخیره گزارش</string>\n    <string name=\"start_recording_log\">ضبط</string>\n    <string name=\"pref_expanded_by_default_summary\">نشان دادن متن کامل گزارش به صورت پیش فرض.</string>\n    <string name=\"issuer\">استخراج کننده</string>\n    <string name=\"profiles\">حالت ها</string>\n    <string name=\"backup_extras\">اضافی</string>\n    <string name=\"patch_level\">مرحله وصله</string>\n    <string name=\"specify_custom_name\">سفارشی</string>\n    <string name=\"expiry_date\">تاریخ انقضا</string>\n    <string name=\"select_apk\">انتخاب برنامه</string>\n    <string name=\"state_wake_kill\">بیدار شد بکشش</string>\n    <string name=\"off\">خاموش</string>\n    <string name=\"options\">گزینه ها</string>\n    <string name=\"installer_error_session_abandon\">نمی توان قسمت نصب را رها کرد</string>\n    <string name=\"obb_files_extracted_successfully\">فایل های دیتا استخراج شدند</string>\n    <string name=\"process_state\">دولت: <xliff:g id=\"process_state\" example=\"Sleeping\">%1$s</xliff:g></string>\n    <string name=\"input_backup_name\">نام فایل پشتیبان</string>\n    <string name=\"filter_apps\">برنامه ها</string>\n    <string name=\"sort_by_process_id\">مشخصات روند</string>\n    <string name=\"sort_by_process_name\">نام روند</string>\n    <string name=\"sort_by_memory_usage\">حافظه استفاده شده</string>\n    <string name=\"changes_not_saved\">تغییرات ذخیره نشدند</string>\n    <string name=\"other\">دیگر</string>\n    <string name=\"pref_compression_method\">حالت های فشرده سازی</string>\n    <string name=\"checksums\">چک جمع ها</string>\n    <string name=\"algorithm\">الگوریتم</string>\n    <string name=\"format\">قالب</string>\n    <string name=\"rsa_exponent\">توان</string>\n    <string name=\"dsa_affine_x\">نسبت مختصات x</string>\n    <string name=\"critical_exts\">پسوندهای بحرانی</string>\n    <string name=\"non_critical_exts\">برنامه های افزودنی غیر بحرانی</string>\n    <string name=\"usage_access_not_supported\">نمی‌توان دسترسی به دادها را درخواست کرد، زیرا صفحه تنظیمات مربوط به آن پیدا نمی‌شود.</string>\n    <string name=\"do_you_want_to_uninstall_and_install\">آیا می خواهید دوباره برنامه را حذف و نصب کنید؟</string>\n    <string name=\"app_data_will_be_lost\">داده های موجود از بین خواهند رفت.</string>\n    <string name=\"app_signing_install_without_data_loss\">اگر تأیید امضا را خاموش کرده‌اید، می‌توانید از <b>فقط نصب </b> گزینه ای برای نصب برنامه بدون از دست دادن اطلاعات استفاده کنید.</string>\n    <string name=\"scanner\">اسکنر</string>\n    <string name=\"no_libs\">بدون کتابخانه</string>\n    <string name=\"lib_details\">جزئیات کتابخانه</string>\n    <string name=\"view_missing_signatures\">برای مشاهده یا ارسال امضا هایی که هنوز در پایگاه داده کتابخانه‌های مدیریت برنامه وجود ندارند، ضربه بزنید.</string>\n    <string name=\"send_crash_report\">ارسال گزارش خرابی</string>\n    <string name=\"conversion_failed\">گفتگو ناموفق بود.</string>\n    <string name=\"in_progress\">درحال انجام</string>\n    <string name=\"un_apkm\">بدون apkm</string>\n    <string name=\"input_profile_name\">نام حالت</string>\n    <string name=\"input_profile_name_description\">نام حالت نمی تواند حاوی هیچ فاصله ای باشد.</string>\n    <string name=\"duplicate\">تکراری</string>\n    <string name=\"none\">هیچ یک</string>\n    <string name=\"profile_block_trackers_msg\">ردیاب‌ها را در برنامه‌ها مسدود می‌کند</string>\n    <string name=\"profile_state_msg\">وضعیت روشن/خاموش سفارشی برای این حالت</string>\n    <string name=\"tap_to_submit_crash_report\">برای ارسال گزارش خرابی ضربه بزنید.</string>\n    <string name=\"enabled\">فعال شد</string>\n    <string name=\"simple\">ساده</string>\n    <string name=\"advanced\">پیشرفته</string>\n    <string name=\"user_profile_with_id\">حالت: %1$s (%2$d)</string>\n    <string name=\"no_root\">بدون روت</string>\n    <string name=\"comment\">اظهار نظر</string>\n    <string name=\"installer\">نصب کننده</string>\n    <string name=\"install_location_internal_only\">فقط حافظه داخلی</string>\n    <string name=\"apk_signing\">درحال امضا زدن برنامه</string>\n    <string name=\"pref_apk_signing_msg\">طرح های امضا، کلید امضای سفارشی و غیره را تنظیم کنید.</string>\n    <string name=\"v1_scheme\">طرح نسخه 1 (از اندروید 1.0)</string>\n    <string name=\"v2_scheme\">طرح نسخه 2 (از اندروید 7.0)</string>\n    <string name=\"source_stamp_verified\">مهر منبع تأیید شد.</string>\n    <string name=\"input_keystore_alias_pass\">رمز مستعار <b>%1$s</b></string>\n    <string name=\"input_keystore_alias_pass_description\">رمز عبور را برای نام مستعار <b>%1$s</b> وارد کنید. اگر رمز عبور با رمز عبور فروشگاه کلید یکی باشد، می توانید آن را خالی بگذارید.</string>\n    <string name=\"input_keystore_alias_pass_msg\">برای ارائه رمز عبور برای %1$s اینجا ضربه بزنید</string>\n    <string name=\"pref_backup_android_keystore_msg\">همه برنامه ها پس از بازیابی کار نمی کنند. بازیابی فروشگاه کلید در اکثر دستگاه ها کار نمی کند.</string>\n    <string name=\"set_app_op_mode\">حالت عملیات برنامه را تنظیم کنید</string>\n    <string name=\"filter_apps_with_splits\">با اسپلیت ها</string>\n    <string name=\"value\">ارزش</string>\n    <string name=\"matching_activities\">فعالیت های مشابه</string>\n    <string name=\"send_edited_intent\">مقصد ویرایش شده را ارسال کنید</string>\n    <string name=\"activity_result\">نتایج فعالیت</string>\n    <string name=\"result_code\">نتیجه کد</string>\n    <string name=\"share\">اشتراک</string>\n    <string name=\"set_custom_app_op\">تنظیمات برنامه سفارشی</string>\n    <string name=\"about_device\">درباره دستگاه</string>\n    <string name=\"pref_about_device_msg\">اطلاعات پایه مانند نسخه سیستم اندروید، پردازنده، گرافیک، حافظه رم، باتری و …</string>\n    <string name=\"board_name\">مادربورد</string>\n    <string name=\"manufacturer\">سازنده</string>\n    <string name=\"gles_version\">OpenGL ES نسخه</string>\n    <string name=\"vendor\">فروشنده</string>\n    <string name=\"memory\">حافظه</string>\n    <string name=\"battery_capacity\">ظرفیت</string>\n    <string name=\"users\">کاربران</string>\n    <string name=\"cpu\">پردازنده</string>\n    <string name=\"graphics\">گرافیک</string>\n    <string name=\"security\">امنیت</string>\n    <string name=\"set_mode_for_app_ops_dots\">تنظیم حالت برای عملیات برنامه…</string>\n    <string name=\"backup_internal_data_description\">از پوشه های داده داخلی نسخه پشتیبان تهیه کنید.</string>\n    <string name=\"backup_external_data_description\">از پوشه های داده خارجی نسخه پشتیبان تهیه کنید.</string>\n    <string name=\"backup_cache_description\">پشتیبان گیری <b>کش</b>, <b>بدون کش</b> و <b>بدون پشتیبان گیری</b> پوشه ها.</string>\n    <string name=\"backup_multiple_description\">به جای پشتیبان گیری پایه، یک نسخه پشتیبان <i>با نام</i> جداگانه ایجاد کنید.</string>\n    <string name=\"size\">اندازه</string>\n    <string name=\"scaling_factor\">تعداد قسمت ها</string>\n    <string name=\"refresh_rate\">نرخ نوسازی</string>\n    <string name=\"pref_backup_volume_msg\">حجم یا محلی را که نسخه های پشتیبان در آن ذخیره می شوند انتخاب کنید.</string>\n    <string name=\"no_volumes_found\">هیچ حافظه ای با اجازه نوشتن اطلاعات یافت نشد.</string>\n    <string name=\"backup_apk_files_description\">از فایل‌های نصبی از کد منبع ها، از جمله اسپلیت ها، نسخه پشتیبان تهیه کنید.</string>\n    <string name=\"backup_rules_description\">از قوانین پیکربندی شده در مدیریت برنامه نسخه پشتیبان تهیه کنید.</string>\n    <string name=\"backup_apps_without_backups\">پشتیبان گیری برنامه ها بدون پشتیبان گرفتن</string>\n    <string name=\"backup_apps_with_changes\">پشتیبان گیری برنامه ها با تغییرات</string>\n    <string name=\"restore_all\">بازگردانی تمامی برنامه ها</string>\n    <string name=\"restore_all_msg\">پشتیبان‌گیری پایه برنامه ها را از همه برنامه‌های پشتیبان‌گیری شده بازیابی کنید.</string>\n    <string name=\"drm_free_apkm_msg\">فایل APKM بدون DRM است، نیازی به تبدیل آن به APKS نیست.</string>\n    <string name=\"back_up\">پشتیبان گیری</string>\n    <string name=\"unlock_app_manager\">باز کردن قفل مدیریت برنامه</string>\n    <string name=\"restore_msg\">بازیابی برنامه ها و اطلاعات شان</string>\n    <string name=\"backup_all_apps_msg\">پشتیبان گیری از تمامی برنامه های نصب شده.</string>\n    <string name=\"no_battery_optimization\">بدون بهینه سازی باتری</string>\n    <string name=\"battery_optimization\">بهینه سازی باتری</string>\n    <string name=\"enable_battery_optimization\">فعال کردن بهینه سازی باتری؟</string>\n    <string name=\"type_string_array\">آرایه رشته ها</string>\n    <string name=\"type_string_array_list\">لیست رشته ها</string>\n    <string name=\"type_uri\">تعیین کننده هویت لینک</string>\n    <string name=\"last_actions\">آخرین عمل ها</string>\n    <string name=\"use_default\">استفاده از پیش فرض</string>\n    <string name=\"locality_name\">نام محله و شهر</string>\n    <string name=\"state_name\">نام ایالت</string>\n    <string name=\"country_name\" tools:ignore=\"TypographyOther\">نام کشور</string>\n    <string name=\"java_keystore\">کلید فروشگاه جاوا</string>\n    <string name=\"bouncy_castle_keystore\">فروشگاه کلید قلعه فنری</string>\n    <string name=\"pk8_file\">PKCS #8 (PK8) فایل</string>\n    <string name=\"pem_file\">PEM فایل</string>\n    <string name=\"log_level_verbose\">پرمخاطب</string>\n    <string name=\"add_filter\">افزودن فیلتر</string>\n    <string name=\"import_key\">وارد کردن کلید</string>\n    <string name=\"new_alias_password\">رمز نام مستعار جدید</string>\n    <string name=\"found_no_alias_in_keystore\">هیچ نام مستعاری در فروشگاه کلید یافت نشد!</string>\n    <string name=\"log_viewer\">نمایشگر ورود به سیستم</string>\n    <string name=\"subject_log_report\">ارسال گزارشات</string>\n    <string name=\"widget_start_recording\">گرفتن\n\\nگزارش</string>\n    <string name=\"file\">فایل</string>\n    <string name=\"expand_all\">گسترش همه</string>\n    <string name=\"pref_installer_msg\">عمل های نصب کننده برنامه را پیکربندی کنید.</string>\n    <string name=\"backup_all_apps\">پشتیبان گیری از تمام برنامه ها</string>\n    <string name=\"am_crashed\">مدیریت برنامه خراب شد</string>\n    <string name=\"failed_to_extract_obb_files\">نمی‌توان فایل دیتا را استخراج کرد</string>\n    <string name=\"pref_app_language\">زبان</string>\n    <string name=\"choose_language\">تغییر زبان</string>\n    <string name=\"base_apk\">برنامه اصلی</string>\n    <string name=\"split_feature_name\">ویژگی ها: <xliff:g id=\"feature_name\" example=\"Visualizer\">%1$s</xliff:g></string>\n    <string name=\"unknown_split_for_base_apk\"><xliff:g id=\"split_name\" example=\"some_split\">%1$s</xliff:g> برای فایل اصلی</string>\n    <string name=\"orientation_full_sensor\">سنسور کامل</string>\n    <string name=\"orientation_full_user\">کاربر کامل</string>\n    <string name=\"orientation_portrait\">پرتره</string>\n    <string name=\"orientation_reverse_portrait\">پرتره معکوس</string>\n    <string name=\"orientation_reverse_landscape\">منظره معکوس</string>\n    <string name=\"orientation_user_portrait\">پرتره کاربر</string>\n    <string name=\"state_trace_stop\">توقف ردیابی</string>\n    <string name=\"navigation_dial_pad\">صفحه شماره گیری</string>\n    <string name=\"navigation_trackball\">توپ ردیابی</string>\n    <string name=\"state_device_io\">دستگاه I/O</string>\n    <string name=\"state_dead\">مرده</string>\n    <string name=\"state_zombie\">زامبی</string>\n    <string name=\"state_parked\">پارک شده</string>\n    <string name=\"state_idle\">بیکار</string>\n    <string name=\"state_waking\">بیدار شدن</string>\n    <string name=\"state_low_priority\">اولویت پایین</string>\n    <string name=\"state_locked_memory\">حافظه قفل شده</string>\n    <string name=\"process_state_with_extra\">دولت: <xliff:g id=\"process_state\" example=\"Sleeping\">%1$s</xliff:g> (<xliff:g id=\"state_extra\" example=\"High priority\">%2$s</xliff:g>)</string>\n    <string name=\"ok\">باشه</string>\n    <string name=\"cancel\">لغو</string>\n    <string name=\"systemless_app\">برنامه مستقل از سیستم</string>\n    <string name=\"apply_now\">هم اکنون اعمال…</string>\n    <string name=\"no_apps\">بدون برنامه</string>\n    <string name=\"update_uninstalled_successfully\">بروز رسانی برای <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g> حذف شد.</string>\n    <string name=\"issued_date\">داده های استخراج شده</string>\n    <string name=\"only_install\">فقط نصب</string>\n    <string name=\"sys_config\">پیکربندی سیستم</string>\n    <string name=\"select_user\">انتخاب کاربر</string>\n    <string name=\"encryption\">رمزگذاری</string>\n    <string name=\"aes\">رمزگذاری پیشرفته</string>\n    <string name=\"rsa\">سیستم رمزگذاری</string>\n    <string name=\"send_selected\">ارسال مورد انتخاب شده</string>\n    <string name=\"pref_mode_of_operations\">حالت عملکرد</string>\n    <string name=\"adb_over_tcp\">ADB برای انتقال اطلاعات</string>\n    <string name=\"allow_routine_ops\">عملیات روتین را مجاز کنید</string>\n    <string name=\"profile_state\">وضعیت حالت</string>\n    <string name=\"allow_routine_ops_msg\">اجازه دهید حالت در عملیات معمولی استفاده شود</string>\n    <string name=\"profile_force_stop_msg\">توقف اجباری برنامه ها</string>\n    <string name=\"profile_clear_cache_msg\">پاک کردن حافظه کش برنامه ها</string>\n    <string name=\"profile_clear_data_msg\">پاک کردن داده های برنامه ها</string>\n    <string name=\"choose\">انتخاب</string>\n    <string name=\"install_location_prefer_external\">حافظه خارجی را ترجیح دهید</string>\n    <string name=\"keep_data_and_app_signing_signatures\">داده ها و امضاها را نگه دارید</string>\n    <string name=\"this_action_cannot_be_undone\">این عمل قابل بازگشت نیست.</string>\n    <string name=\"pref_backup_android_keystore\">با کلید فروشگاه اندروید از برنامه ها نسخه پشتیبان تهیه کنید</string>\n    <string name=\"magisk_hide_enabled\">مخفی کردن مجیسک</string>\n    <string name=\"action\">عمل</string>\n    <string name=\"mime_type\">نوع برنامه های افزودنی ایمیل چند منظوره</string>\n    <string name=\"extras\">موارد اضافی</string>\n    <string name=\"model\">مدل</string>\n    <string name=\"support_architectures\">معماری های پشتیبانی شده</string>\n    <string name=\"no_of_cores\">هسته ها</string>\n    <string name=\"window_size\">اندازه پنجره</string>\n    <string name=\"backup_obb_media_description\">پشتیبان گرفتن از دیتا و پوشه های رسانه.</string>\n    <string name=\"backup_volume\">حجم پشتیبان</string>\n    <string name=\"pref_backup_restore_msg\">سفارشی سازی پشتیبان گیری/بازگردانی.</string>\n    <string name=\"unencrypted\">رمزگشایی شده</string>\n    <string name=\"encrypted\">رمزگذاری شده</string>\n    <string name=\"bootloader\">بوت لودر</string>\n    <string name=\"backup_custom_users\">کابران سفارشی</string>\n    <string name=\"redo_existing_backups\">پشتیبان‌گیری‌های موجود را دوباره انجام دهید</string>\n    <string name=\"external_storage\">حافظه خارجی</string>\n    <string name=\"sd_card\">کارت حافظه</string>\n    <string name=\"screen_lock\">قفل صفحه</string>\n    <string name=\"screen_lock_msg\">قفل کردن مدیریت برنامه با استفاده از قفل صفحه</string>\n    <string name=\"type_null\">بدون ارزش</string>\n    <string name=\"type_long_array\">آرایه ای از اعداد صحیح بلند</string>\n    <string name=\"net_policy\">سیاست های حریم خصوصی</string>\n    <string name=\"os_version\">نسخه سیستم عامل</string>\n    <string name=\"reverse\">معکوس</string>\n    <string name=\"ssaid\">تنظیمات امن اندروید</string>\n    <string name=\"restart_to_reflect_changes\">برای استفاده از تغییرات جدید باید فوراً دستگاه را راه اندازی مجدد کنید.</string>\n    <string name=\"pref_enable_disable_features_msg\">فعال و غیرفعال کردن ویژگی ها در مدیریت برنامه.</string>\n    <string name=\"verified_using_unreliable_hash\">با استفاده از هش نامعتبر تأیید شد</string>\n    <string name=\"installer_app_message\"><b>انتخاب</b> را برای انتخاب از بین برنامه های نصب شده انتخاب کنید یا <b>سفارشی</b> را برای تعیین نام بسته سفارشی انتخاب کنید.</string>\n    <string name=\"invalid_rsa_key_size\">اندازه کلید برای رمزگذاری سیستم نامعتبر است. اندازه کلید می تواند 1024، 2048 یا 4096 بیت باشد.</string>\n    <string name=\"common_name\">نام متداول</string>\n    <string name=\"pem_and_pk8\">PEM و PKCS #8 (PK8)</string>\n    <string name=\"choose_an_alias\">نام مستعار را انتخاب کنید</string>\n    <string name=\"alias_pass\">رمز نام مستعار</string>\n    <string name=\"failed_to_read_keystore\">نمی‌توان کلید فروشگاه را خواند.</string>\n    <string name=\"failed_to_block_trackers\">ردیاب‌ها مسدود نشدند</string>\n    <string name=\"latest_backup\">آخرین پشتیبان گیری</string>\n    <string name=\"filter_apps_with_backups\">با پشتیبان گیری ها</string>\n    <string name=\"pref_encryption_msg\">رمزگذاری فایل‌های پشتیبان.</string>\n    <string name=\"installer_error_session_write\">نمی توان در قسمت نصب کننده چیزی نوشت</string>\n    <string name=\"initializing\">در حال راه اندازی…</string>\n    <string name=\"add_to_profile\">اضافه کردن به حالت</string>\n    <string name=\"choose_what_to_do\">انتخاب کنید که چه کار انجام دهد.</string>\n    <string name=\"add\">اضافه</string>\n    <string name=\"ssaid_info\">SSAID (<tt>Settings.Secure.ANDROID_ID</tt>) یک شناسه دستگاه است که به هر برنامه اختصاص داده شده است (از اندروید 8 به بعد). این به طور گسترده توسط برنامه ها برای ردیابی کاربران استفاده می شود.</string>\n    <string name=\"copied_to_clipboard\">کپی شد.</string>\n    <string name=\"installed_apps\">برنامه های نصب شده</string>\n    <string name=\"wireless_debugging\">اشکال زدایی بي سيم</string>\n    <string name=\"base_backup\">پشتیبان گیری از بنیاد</string>\n    <string name=\"no_encryption\">بدون رمزگذاری</string>\n    <string name=\"pgp_aes_rsa_encrypted\">%1$s رمزگذاری شد</string>\n    <string name=\"uninstalled_apps\">برنامه های حذف شده</string>\n    <string name=\"no_profiles\">بدون حالت</string>\n    <string name=\"category\">دسته بندی ها</string>\n    <string name=\"internal_storage\">حافظه داخلی</string>\n    <string name=\"splits\">اسپلیت ها</string>\n    <string name=\"manage_saved_logs\">مدیریت گزارشات ذخیره شده</string>\n    <string name=\"log_saved\">گزارش ذخیره شد.</string>\n    <string name=\"share_log\">اشتراک</string>\n    <string name=\"pref_rules_msg\">مسدود کردن فوری، وارد/خارج/حذف قوانین و غیره.</string>\n    <string name=\"density_split_for_feature\"><xliff:g id=\"split_name\" example=\"xxdpi\">%1$s</xliff:g> (<xliff:g id=\"dpi_no\" example=\"480\">%2$d</xliff:g> اندازه صفحه) کد ها برای ویژگی <xliff:g id=\"feature_name\" example=\"Visualizer\">%3$s</xliff:g></string>\n    <string name=\"confirm_installation\">نصب را تایید کنید</string>\n    <string name=\"uninstall_updates\">حذف نصب بروزرسانی ها</string>\n    <string name=\"type\">نوع</string>\n    <string name=\"enforcing\">اجرا کردن</string>\n    <string name=\"permissive\">مجاز</string>\n    <string name=\"hardware\">سخت افزار</string>\n    <string name=\"screen\">صفحه</string>\n    <string name=\"density\">تراکم</string>\n    <string name=\"type_component_name\">نام قسمت</string>\n    <string name=\"type_int_array\">آرایه اعداد صحیح</string>\n    <string name=\"type_int_array_list\">لیست اعداد صحیح</string>\n    <string name=\"type_long_array_list\">لیست اعداد صحیح بلند</string>\n    <string name=\"type_float_array\">آرایه اعداد اعشاری</string>\n    <string name=\"type_float_array_list\">فهرست اعداد اعشاری</string>\n    <string name=\"filename\">نام فایل</string>\n    <string name=\"log_level_warn\">هشدار</string>\n    <string name=\"log_level_fatal\">مهلک</string>\n    <string name=\"restart_log_viewer_to_see_changes\">برای مشاهده تغییرات، پنجره نمایشگر ورود به سیستم را مجددا راه اندازی کنید.</string>\n    <string name=\"text_filter_ellipsis\">فیلتر…</string>\n    <string name=\"saf\">خالص</string>\n    <string name=\"list_options\">فهرست گزینه ها</string>\n    <string name=\"failed_to_change_ssaid\">نمی‌توان تنظیمات امن اندروید را تغییر داد</string>\n    <string name=\"isolated\">جدا شده</string>\n    <string name=\"working_on_adb_mode\">در حالت ADB کار می‌کند</string>\n    <string name=\"filter_apps_without_backups\">بدون پشتیبان گیری</string>\n    <string name=\"input_key\">کلید ورودی (در hexadecimal)</string>\n    <string name=\"generate_key\">تولید می کنند</string>\n    <string name=\"failed_to_initialize_key_store\">ذخیره کلید مدیریت برنامه راه اندازی نشد.</string>\n    <string name=\"crypto_key_size\">اندازه کلید</string>\n    <string name=\"key_not_set\">تنظیم نشده.</string>\n    <string name=\"input_key_password\">کلید رمز</string>\n    <string name=\"invalid_aes_key_size\">اندازه کلید برای رمزگذاری پیشرفته نامعتبر است. اندازه کلید می تواند 128 یا 256 بیت باشد.</string>\n    <string name=\"failed_to_load_key\">نمی‌توان کلید را بارگذاری کرد.</string>\n    <string name=\"organization_name\">نام سازمان</string>\n    <string name=\"organization_unit\">واحد سازمانی</string>\n    <string name=\"netpolicy_reject_vpn_data\">رد داده های فیلترشکن</string>\n    <string name=\"netpolicy_reject_wifi_data\">رد دادهای وای فای</string>\n    <string name=\"notice\">توجه</string>\n    <string name=\"failed_to_prevent_background_run\">نمی‌توان از اجرای %1$s در پس‌زمینه جلوگیری کرد</string>\n    <string name=\"second_degree_tracker_note\">² پیشوند نشان می دهد که ردیاب ها در <a href=\"https://etip.exodus-privacy.eu.org/\">لیست آماده به کار ETIP</a> i.e. آیا آنها ردیاب واقعی هستند هنوز در حال بررسی است.</string>\n    <string name=\"failed_to_uninstall_app\">حذف نصب ناموفق بود</string>\n    <string name=\"community\">انجمن</string>\n    <string name=\"community_links\"><a href=\"https://matrix.to/#/#appmanager:matrix.org\">Matrix</a> • <a href=\"https://t.me/AppManagerChannel\">تلگرام</a> • <a href=\"https://twitter.com/AppManagerNews\">توییتر</a></string>\n    <string name=\"input_app_ops_description_profile\">نام‌های عملیات برنامه و/یا بقیه را با فاصله وارد کنید، به عنوان مثال.. <tt>قفل کردن دوربین ۶۳ ۷۲ </tt> و غیره. استفاده <tt>*</tt> برای درخواست برای همه عملیات برنامه های پیکربندی شده.</string>\n    <string name=\"internal_data\">داده های داخلی</string>\n    <string name=\"installer_error_session_commit\">نمی‌توان فایل‌های نصبی را اجرا کرد</string>\n    <string name=\"backup_apk_files\">فایل های نصبی</string>\n    <string name=\"backup_obb_media\">دیتا و رسانه</string>\n    <string name=\"backup_multiple\">پشتیبان گیری چندگانه‌</string>\n    <string name=\"backup_all_users\">تمامی کاربران</string>\n    <string name=\"auto\">خودکار</string>\n    <plurals name=\"file_deletion_confirmation\">\n        <item quantity=\"one\">%d فایل حذف خواهد شد</item>\n        <item quantity=\"other\">%d فایل ها حذف خواهد شد</item>\n    </plurals>\n    <string name=\"abi_split_for_feature\"><xliff:g id=\"split_name\" example=\"arm64_v8a\">%1$s</xliff:g> کد برای <xliff:g id=\"feature_name\" example=\"Visualizer\">%2$s</xliff:g></string>\n    <string name=\"abi_split_for_base_apk\"><xliff:g id=\"split_name\" example=\"arm64_v8a\">%1$s</xliff:g> کد برای برنامه اصلی</string>\n    <string name=\"locale_split_for_base_apk\"><xliff:g id=\"split_name\" example=\"English\">%1$s</xliff:g> محل برنامه اصلی</string>\n    <string name=\"launch_mode_single_instance\">نمونه واحد</string>\n    <string name=\"launch_mode_single_task\">یک وظیفه</string>\n    <string name=\"launch_mode_single_top\">یک ضربه</string>\n    <string name=\"orientation_unspecified\">نامشخص</string>\n    <string name=\"orientation_behind\">پشت</string>\n    <string name=\"orientation_locked\">قفل شد</string>\n    <string name=\"orientation_no_sensor\">بدون سنسور</string>\n    <string name=\"orientation_landscape\">چشم انداز</string>\n    <string name=\"orientation_user\">کاربر</string>\n    <string name=\"orientation_sensor_landscape\">منظره حسگر</string>\n    <string name=\"orientation_sensor_portrait\">پرتره حسگر</string>\n    <string name=\"orientation_sensor\">حسگر</string>\n    <string name=\"required\">ضروری</string>\n    <string name=\"_undefined\">تعریف نشده</string>\n    <string name=\"keyboard_no_keys\">بدون کلید</string>\n    <string name=\"keyboard_qwerty\">QWERTY</string>\n    <string name=\"keyboard_12_keys\">۱۲ کلید</string>\n    <string name=\"navigation_no_nav\">بدون جهت یابی</string>\n    <string name=\"navigation_wheel\">چرخ</string>\n    <string name=\"touchscreen_no_touch\">بدون لمس</string>\n    <string name=\"touchscreen_finger\">انگشت</string>\n    <string name=\"state_sleeping\">در حال خواب</string>\n    <string name=\"state_unknown\">ناشناخته</string>\n    <string name=\"state_high_priority\">اولویت بالا</string>\n    <string name=\"state_session_leader\">رهبر جلسه</string>\n    <string name=\"state_foreground\">پیش زمینه</string>\n    <string name=\"state_multithreaded\">چند رشته ای</string>\n    <string name=\"adb_pair\">جفت کردن</string>\n    <string name=\"backup_volume_dialog_description\">حجم ها, با پیشوند <tt>/سه</tt> پوشه هایی هستند که با استفاده از چارچوب دسترسی به فضای ذخیره سازی انتخاب شده اند. به جز این پوشه ها، فهرست پیش فرض مدیریت برنامه یک زیرپوشه به نام <tt>مدیریت برنامه</tt> است.</string>\n    <string name=\"log_level_debug\">اشکال زدایی</string>\n    <string name=\"log_level_error\">خطا</string>\n    <string name=\"log_level_info\">اطلاعات</string>\n    <string name=\"copy_to_clipboard\">کپی شد</string>\n    <string name=\"enter_filename\">وارد کردن نام فایل</string>\n    <string name=\"enter_good_filename\">لطفا یک نام فایل معتبر وارد کنید.</string>\n    <string name=\"filter_choice\">جستجو بر اساس</string>\n    <string name=\"filter_choice_pid\">PID</string>\n    <string name=\"filter_choice_tag\">برچسب زدن</string>\n    <string name=\"log_cleared\">گزارشات پاک شدند</string>\n    <string name=\"notification_subtext\">برای متوقف شدن لمس کنید</string>\n    <string name=\"no_saved_logs\">هیچ گزارش ذخیره شده‌ای یافت نشد.</string>\n    <plurals name=\"toast_log_truncated\">\n        <item quantity=\"one\">گزارش خیلی بزرگ است، آخرین %d خط را نشان می دهد.</item>\n        <item quantity=\"other\">گزارش خیلی بزرگ است, آخرین%dخط را نشان می دهد.</item>\n    </plurals>\n    <string name=\"open\">بازکردن</string>\n    <string name=\"pref_cat_advanced\">پیشرفته</string>\n    <string name=\"pref_cat_appearance\">ظاهر</string>\n    <string name=\"pref_cat_configuration\">پیکربندی</string>\n    <string name=\"pref_default_log_level_title\">سطح گزارش پیش فرض</string>\n    <string name=\"pref_display_limit_title\">محدودیت نمایش گزارش</string>\n    <string name=\"pref_filter_pattern_summary\">برچسب های انتخاب شده را از گزارشات پاک کنید.</string>\n    <string name=\"pref_log_write_period_summary\" tools:ignore=\"PluralsCandidate\">هنگام ضبط، هر %1$d خط را روی کارت حافظه بنویسید.</string>\n    <string name=\"pref_log_write_period_title\">دوره نوشتن</string>\n    <string name=\"pref_show_timestamp_title\">نشان دادن pid و مهر زمان</string>\n    <string name=\"record_log\">ضبط گزارش</string>\n    <string name=\"save_as\">ذخیره در…</string>\n    <string name=\"settings\">تنظیمات</string>\n    <string name=\"text_filter_text\">متن فیلتر</string>\n    <string name=\"text_include_device_info\">شامل اطلاعات دستگاه</string>\n    <string name=\"pref_display_limit_hint\" tools:ignore=\"PluralsCandidate\">لطفاً یک عدد معتبر بین %1$d و %2$d وارد کنید.</string>\n    <string name=\"port_number_empty\">شماره پورت خالی است.</string>\n    <string name=\"pause_unpause\">پخش/توقف</string>\n    <string name=\"trackers_blocked_successfully\">اکنون ردیاب ها مسدود شده اند</string>\n    <string name=\"trackers_unblocked_successfully\">اکنون ردیاب ها رفع انسداد شده اند</string>\n    <string name=\"gz_bz2_compressed\">%1$s فشرده شد</string>\n    <string name=\"import_keystore\">وارد کردن کلید فروشگاه</string>\n    <string name=\"orientation_follow_locale\">داخلی را دنبال کنید</string>\n    <string name=\"orientation_left_to_right\">چپ به راست</string>\n    <string name=\"pref_display_changes_msg\">تغییرات نسخه، ردیاب ها، اجزا، مجوزها، امضاها، کیت نرم افزاری و غیره را به صورت کنترل شده نمایش دهید.</string>\n    <string name=\"port_number_invalid\">شماره درگاه اشتباه.</string>\n    <string name=\"paired_successfully\">جفت شد.</string>\n    <string name=\"error_with_details\">خطا:%s</string>\n    <string name=\"storage\">ذخیره سازی</string>\n    <string name=\"files\">فایل ها</string>\n    <string name=\"keystore_password_info\">رمز عبور فروشگاه کلید مدیریت برنامه در زیر آمده است. اگر می‌خواهید از فروشگاه کلید مدیریت برنامه پشتیبان‌گیری یا بازیابی کنید، لطفاً آن را در مکانی امن ذخیره کنید. <b>این پیام دیگر نمایش داده نخواهد شد.</b></string>\n    <string name=\"invalid_password\">رمز اشتباه، از دوباره تلاش کنید.</string>\n    <string name=\"identifier\">مشخص کننده</string>\n    <string name=\"set_package_name_first\">ابتدا نام بسته را تنظیم کنید!</string>\n    <string name=\"keystore_pass_cannot_be_empty\">رمز عبور فروشگاه کلید نمی تواند خالی باشد.</string>\n    <string name=\"background\">پس زمینه</string>\n    <string name=\"staging_apk_files\">در حال اجرا…</string>\n    <string name=\"installer_app_installed\">برنامه نصب شد</string>\n    <string name=\"next\">بعدی</string>\n    <string name=\"pref_always_on_background\">نصب در پس زمینه</string>\n    <string name=\"pref_always_on_background_msg\">همیشه برنامه‌ها را در پس‌زمینه نصب کنید و پس از اتمام یک اعلان نمایش دهید.</string>\n    <string name=\"type_uri_array\">آرایه ای از لینک ها</string>\n    <string name=\"type_uri_array_list\">لیستی از لینک ها</string>\n    <string name=\"pref_thread_count\">اجرای موازی</string>\n    <plurals name=\"pref_thread_count_msg\">\n        <item quantity=\"one\">حداکثر %1$d عملیات را به صورت موازی اجرا کنید</item>\n        <item quantity=\"other\">حداکثر %1$d عملیات را به صورت موازی اجرا کنید</item>\n    </plurals>\n    <string name=\"pid\">شناسه فرآیند</string>\n    <string name=\"running_services_logcat_hint\">روی یک مورد کلیک کنید تا نمایشگر گزارش با شناسه فرآیند مربوطه به عنوان فیلتر پیش فرض باز شود.</string>\n    <string name=\"pref_import_backups_hint\">فهرست حاوی فایل های پشتیبان (برنامه سویفت بک آپ / برنامه تیتانیوم بک‌آپ) یا فهرست های (برنامه و بک آپ) را انتخاب کنید</string>\n    <string name=\"java\">جاوا</string>\n    <string name=\"smali\">اسمالی</string>\n    <string name=\"accessibility_service_description\">سرویس دسترسی عمومی برای انجام عملیات خاصی مانند پاک کردن حافظه پنهان در حالت بدون ریشه.</string>\n    <string name=\"explore\">جستجو</string>\n    <string name=\"system_partition\">روت اندروید</string>\n    <string name=\"exit_confirmation\">تایید خروج</string>\n    <string name=\"extract\">استخراج</string>\n    <string name=\"replace\">جاگذاری</string>\n    <string name=\"rename\">تغییر نام</string>\n    <string name=\"send_log_title\">ارسال گزارش</string>\n    <string name=\"pref_expanded_by_default_title\">به صورت پیش فرض باز کنید</string>\n    <string name=\"toast_invalid_selection\">انتخاب نامعتبر است. لطفا دوباره تلاش کنید.</string>\n    <string name=\"pref_display_limit_summary\" tools:ignore=\"PluralsCandidate\">فقط آخرین %1$d گزارش را نمایش دهید تا از خطاهای حافظه جلوگیری شود.</string>\n    <string name=\"unable_to_save_log\">گزارش ذخیره نشد. آیا نام فایل معتبری وارد کردید؟</string>\n    <string name=\"view_logs\">دیدن گزارشات</string>\n    <string name=\"running_services\">سرویس های در حال اجرا</string>\n    <string name=\"port_number\">درگاه</string>\n    <string name=\"routine_ops\">عملیات روتین</string>\n    <string name=\"source_code_links\">گیت هاب: https://github.com/MuntashirAkon/AppManager\n\\nگیت لب: https://gitlab.com/muntashir/AppManager\n\\nریسویپ: https://0xacab.org/muntashir/AppManager\n\\nپل کد: https://codeberg.org/muntashir/AppManager</string>\n    <string name=\"locale_split_for_feature\"><xliff:g id=\"split_name\" example=\"English\">%1$s</xliff:g>محل ویژگی <xliff:g id=\"feature_name\" example=\"Visualizer\">%2$s</xliff:g></string>\n    <string name=\"sort_by_apps_first\">برنامه های اول</string>\n    <string name=\"rules\">قوانین</string>\n    <string name=\"unknown_split_for_feature\"><xliff:g id=\"split_name\" example=\"some_split\">%1$s</xliff:g> برای ویژگی<xliff:g id=\"feature_name\" example=\"Visualizer\">%2$s</xliff:g></string>\n    <string name=\"density_split_for_base_apk\"><xliff:g id=\"split_name\" example=\"xxdpi\">%1$s</xliff:g> (<xliff:g id=\"dpi_no\" example=\"480\">%2$d</xliff:g> اندازه صفحه) برای برنامه اصلی</string>\n    <string name=\"launch_mode_multiple\">چندگانه</string>\n    <string name=\"touchscreen_stylus\">قلم</string>\n    <string name=\"downgrade\">پایین آوردن نسخه</string>\n    <string name=\"input_backup_name_description\">نام پشتیبان نباید با یک رقم شروع شود و همچنین نباید دارای فاصله باشد. اگر می‌خواهید از تاریخ و زمان فعلی استفاده کنید، آن را خالی بگذارید.</string>\n    <string name=\"keystore\">فروشگاه کلید</string>\n    <string name=\"app_signing_signature\">امضا</string>\n    <string name=\"open_pgp_provider\">ارائه دهنده OpenPGP</string>\n    <string name=\"sort_by_backup\">اول پشتیبان گیری کنید</string>\n    <string name=\"pref_backup_flags_msg\">افزودن یک پیش‌ تنظیم برای گزینه‌های پشتیبان، پرچم‌ها را هر بار که پشتیبان‌گیری/بازیابی می‌کنید، از بین می‌برد.</string>\n    <string name=\"allow_open_pgp_operation\">برای اجازه دادن به مدیریت برنامه برای استفاده از OpenPGP ضربه بزنید</string>\n    <string name=\"failed_to_uninstall_updates\">نمی‌توان بروزرسانی را نصب کرد برای <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g>.</string>\n    <string name=\"subject\">موضوع</string>\n    <string name=\"validity\">اعتبار</string>\n    <string name=\"expired\">منقضی شده</string>\n    <string name=\"not_yet_valid\">هنوز معتبر نیست</string>\n    <string name=\"serial_no\">شماره سریال</string>\n    <string name=\"rsa_modulus\">ماژول ها</string>\n    <string name=\"public_key\">کلید های عمومی</string>\n    <string name=\"app_signing_signature_mismatch_for_system_apps\">برنامه نصب نشد زیرا یک برنامه سیستمی متفاوت با همین امضای بسته وجود دارد.</string>\n    <string name=\"filter_running_apps\">برنامه های در حال اجرا</string>\n    <string name=\"copy\">کپی</string>\n    <string name=\"tap_to_see_details\">برای دیدن جزئیات ضربه بزنید</string>\n    <string name=\"input_permissions\">مجوزهای ورودی</string>\n    <string name=\"pref_sign_apk\">امضا برنامه</string>\n    <string name=\"app_signing_signature_schemes\">طرح های امضا</string>\n    <string name=\"resend_intent\">ارسال مجدد قصد</string>\n    <string name=\"brand_name\">برند</string>\n    <string name=\"pref_sign_apk_msg\">امضای فایل های برنامه قبل نصب آنها.</string>\n    <string name=\"new_profile\">حالت جدید</string>\n    <string name=\"failed_to_duplicate_profile\">حالت تکراری نمیشه</string>\n    <string name=\"v3_scheme\">طرح نسخه 3 (از اندروید 9)</string>\n    <string name=\"uri\">لینک</string>\n    <string name=\"on\">روشن</string>\n    <string name=\"backup_extras_description\">از مجوزهای برنامه گزینه‌ های صرفه‌ جویی در باتری و وضعیت استفاده از داده و پنهان کردن magisk و SSAID و ... نسخه پشتیبان تهیه کنید <font fgcolor=\"#ff0000\">بسته به مجوز ها همه موارد اضافی قابل بازیابی نیستند</font></string>\n    <string name=\"backup_skip_signature_checks_description\">پشتیبان‌گیری‌هایی را بازیابی کنید که یا در تأیید جمع‌بندی ناموفق هستند یا دارای امضاهای برنامه متفاوتی نسبت به نسخه‌های پشتیبان قبلی هستند.</string>\n    <string name=\"verify_and_redo_backups_msg\">یکپارچگی پشتیبان‌گیری‌های قبلی را بررسی کنید و پشتیبان‌گیری‌هایی را که بررسی یکپارچگی انجام نداده‌اند، دوباره انجام دهید.</string>\n    <string name=\"restore_not_installed_msg\">پشتیبان‌گیری پایه را برای برنامه‌هایی که در حال حاضر نصب نشده‌اند بازیابی کنید.</string>\n    <string name=\"input_keystore_pass\">رمز ورود کلید فروشگاه</string>\n    <string name=\"input_keystore_pass_description\">رمز عبور فروشگاه مدیریت برنامه را وارد کنید. اگر برای اولین بار است که می بینید، لطفاً از یک تولید کننده رمز عبور برای ایجاد رمز عبور استفاده کنید و قبل از درج آن در اینجا، آن را در مکانی امن ذخیره کنید.</string>\n    <string name=\"interceptor\">رهگیر</string>\n    <string name=\"languages\">زبان ها</string>\n    <string name=\"battery\">باتری</string>\n    <string name=\"restore_not_installed\">بازیابی برنامه های نصب نشده</string>\n    <string name=\"restore_latest\">بازگردانی آخرین پشتیبان گیری</string>\n    <string name=\"failed_to_disable_magisk_hide\">نمی‌توان مخفی کردن مجیسک را غیر فعال کرد</string>\n    <string name=\"selinux\">لینوکس</string>\n    <string name=\"failed_to_enable_magisk_hide\">نمی‌توان مجیسک را مخفی کرد</string>\n    <string name=\"disable_background_run_description\">حالت <i>نادیده گرفتن</i> را برای عملیات برنامه زیر تنظیم می کند: <tt>RUN_IN_BACKGROUND</tt> (از اندروید 7.0) و <tt>RUN_ANY_IN_BACKGROUND</tt> (از اندروید 9).</string>\n    <string name=\"backup_custom_users_description\">فقط برای کاربران مشخص شده نسخه پشتیبان تهیه کنید</string>\n    <string name=\"backup_apps_without_backups_msg\">پشتیبان گیری برنامه ها بدون هیچ پشتیبان گیری قبلی.</string>\n    <string name=\"verify_and_redo_backups\">پشتیبان‌گیری را تأیید و دوباره انجام دهید</string>\n    <string name=\"redo_existing_backups_msg\">پشتیبان‌گیری را برای برنامه‌های نصب‌شده با نسخه‌های پشتیبان قبلی دوباره انجام دهید.</string>\n    <string name=\"backup_apps_with_changes_msg\">پشتیبان‌گیری‌های برنامه‌ها را با تغییراتی از آخرین نسخه پشتیبان انجام دهید. آنها شامل تغییرات در اندازه، نسخه، آخرین زمان راه اندازی هستند.</string>\n    <string name=\"pref_buffer_title\">بافرهای ورود به سیستم</string>\n    <string name=\"screen_lock_not_enabled\">قفل صفحه را در تنظیمات اندروید انتخاب کنید یا داده های برنامه را پاک کنید.</string>\n    <string name=\"notification_title\">درحال گزارش گرفتن</string>\n    <string name=\"pref_show_timestamp_summary\">وقتی باز شد، شناسه فرآیند و مهر زمانی را نشان دهید.</string>\n    <string name=\"delete_saved_log\">گزارشات ذخیره شده را حذف کنید</string>\n    <string name=\"log_level\">مرحله گزارش</string>\n    <string name=\"signing_key\">کلید امضا</string>\n    <string name=\"keystore_file\">فایل کلید فروشگاه</string>\n    <string name=\"keystore_pass\">رمز کلید فروشگاه</string>\n    <string name=\"pkcs12_keystore\">PKCS #12 فروشگاه کلید (P12)</string>\n    <string name=\"expiry_date_cannot_be_empty\">تاریخ انقضا نمی تواند خالی باشد.</string>\n    <string name=\"dialog_compiling_log\">در حال تدوین گزارش…</string>\n    <string name=\"notification_ticker\">گزارش گرفتن شروع شد</string>\n    <string name=\"pref_default_log_level_summary\">سطح گزارش هنگام راه اندازی، هنگام باز کردن فایل ها و هنگام ضبط.</string>\n    <string name=\"log_recording_started\">گزارش گرفتن شروع شد.</string>\n    <string name=\"save_apk\">ذخیره فایل نصبی</string>\n    <string name=\"pref_import_export_keystore\">وارد/خارج کردن کلید فروشگاه</string>\n    <string name=\"netpolicy_allow_background_data\">وقتی ذخیره اینترنت روشن است، داده‌های پس‌زمینه را مجاز کنید</string>\n    <string name=\"no_changes\">بدون تغیرات</string>\n    <string name=\"orientation_right_to_left\">راست به چپ</string>\n    <string name=\"netpolicy_reject_cellular_data\">رد داده های سلولی</string>\n    <string name=\"netpolicy_disable_network_access\">غیرفعال کردن دسترسی به اینترنت</string>\n    <string name=\"adb_connect_port_number_description\">شماره پورت در قسمت <b>آدرس IP و پورت</b> درست زیر بخش <b>نام دستگاه</b> قرار دارد.</string>\n    <string name=\"user_root\">استفاده از روت</string>\n    <string name=\"trim_caches_in_all_apps_description\">فایل های کش را از همه برنامه ها از جمله سیستم اندروید حذف می کند</string>\n    <string name=\"unknown_net_policy\">حریم خصوصی ناشناخته (%1$s - %2$X)</string>\n    <string name=\"help_permissions_tab\">این مجوزها توسط این برنامه تعریف شده و قابل لغو نیستند.</string>\n    <string name=\"help_app_ops_tab\">روی یک مورد کلیک کنید تا آن را <b>اجازه دهید</b> یا <b>نادیده بگیرید</b>. برای مشاهده سایر حالت های پشتیبانی شده روی یک مورد کلیک کنید.</string>\n    <string name=\"pref_block_trackers_msg\">پس از نصب برنامه با استفاده از مدیریت برنامه، اجزای ردیابی را مسدود کنید.</string>\n    <string name=\"pref_thread_count_hint\">مقدار باید بین 0 تا %1$d باشد که 0 به معنای <i>حداکثر تعداد عملیات در زمان معین</i> است.</string>\n    <string name=\"notice_saf\">برخلاف حجم‌ها، فهرست راهنما انتخاب‌شده برای ذخیره همه فایل‌های مربوط به مدیریت برنامه ، از جمله فایل‌های نصبی ذخیره‌شده و نسخه‌های پشتیبان استفاده می‌شود. چارچوب دسترسی به فضای ذخیره سازی بسیار کند است، بنابراین، شما باید این کار را انجام دهید.</string>\n    <string name=\"paste\">جاگذاری</string>\n    <string name=\"trim_caches_in_all_apps\">کش ها را در همه برنامه ها برش دهید</string>\n    <string name=\"backup_msg\">پشتیبان گیری برنامه ها و اطلاعات شان</string>\n    <string name=\"import_from_sb\">وارد کردن از سویفت بک آپ 3.0 – 3.2</string>\n    <string name=\"restore_latest_msg\">برنامه‌های نصب‌شده‌ای را که کد نسخه‌شان بالاتر از کد نسخه نصب‌شده است، بازیابی کنید.</string>\n    <string name=\"input_permissions_description\">مجوزهای ورودی با فاصله، به عنوان مثال. <tt>com.permission.GET_ACCOUNTS android.permission.ACCESS_MEDIA_LOCATION</tt> و غیره. از <tt>*</tt> برای درخواست همه مجوز ها استفاده کنید.</string>\n    <string name=\"failed_to_save_key\">نمی‌توان کلید را ذخیره کرد.</string>\n    <plurals name=\"usage_minutes\">\n        <item quantity=\"one\">%1$d دقیقه</item>\n        <item quantity=\"other\">%1$d دقیقه</item>\n    </plurals>\n    <plurals name=\"usage_seconds\">\n        <item quantity=\"one\">%1$d ثانیه</item>\n        <item quantity=\"other\">%1$d ثانیه</item>\n    </plurals>\n    <string name=\"authenticating\">در حال تایید…</string>\n    <string name=\"search_type_prefix\">پیشوند</string>\n    <string name=\"pref_vt_apikey\">کلید VirusTotal API</string>\n    <string name=\"pref_default_blocking_method\">روش پیش فرض مسدودسازی</string>\n    <string name=\"search_type_contains\">شامل</string>\n    <string name=\"vt_uploading\">VirusTotal: در حال بارگذاری…</string>\n    <string name=\"vt_success\">ویروس‌توتال: %1$d/%2$d</string>\n    <string name=\"vt_scan_date\">تاریخ اسکن: %1$s</string>\n    <string name=\"vt_permalink\">لینک دائمی به VirusTotal</string>\n    <string name=\"vt_slowness_warning\">با توجه به سرعت اینترنت و ترافیک سرور ممکن است کمی طول بکشد.</string>\n    <string name=\"search_type_suffix\">پسوند</string>\n    <string name=\"pref_default_blocking_method_description\">روشی برای استفاده پیش فرض در مکان هایی که گزینه ای برای انتخاب روش مسدود کردن وجود ندارد\\n<b>توجه :</b> \\\"IFW\\\" با ارائه دهندگان کار نمی کند به جای آن از \\\"غیرفعال\\\" استفاده می شود</string>\n    <string name=\"toggle_internet\">استفاده از اینترنت</string>\n    <string name=\"vt_failed\">VirusTotal: ناموفق بود</string>\n    <string name=\"vt_checking\">VirusTotal: در حال بررسی…</string>\n    <string name=\"intent_firewall\">IFW</string>\n    <string name=\"pref_disable_description\">فقط اجزا را غیرفعال کنید برای کاربران روت توصیه نمی شود زیرا برنامه ها می توانند این را دور بزنند. در حالت‌های ADB، فقط برنامه های test-only را میتوان با این روش غیرفعال کرد.</string>\n    <string name=\"pref_intent_firewall_description\">اجزاء را فقط با استفاده از فایروال Intent مسدود کنید. توصیه نمی شود زیرا برخی از برنامه های سیستم می توانند فایروال ها را دور بزنند.</string>\n    <string name=\"intent_firewall_and_disable\">IFW + غیرفعال کردن</string>\n    <string name=\"pref_intent_firewall_and_disable_description\">کامپوننت ها را با استفاده از فایروال Intent مسدود کنید و همچنین آنها را غیرفعال کنید. روش پیشنهادی برای کاربران با دسترسی روت.</string>\n    <string name=\"uses_play_app_signing\">واردشدن به گوگل پلی</string>\n    <string name=\"parent_process_id\">شناسه فرآیند والد</string>\n    <string name=\"threads\">تعداد رشته‌‌ها</string>\n    <string name=\"cpu_percent\">%% پردازنده</string>\n    <string name=\"process_id\">شناسه فرایند</string>\n    <string name=\"virtual_memory\">حافظه مجازی</string>\n    <string name=\"pref_vt_apikey_summary\">اسکن فایل های APK از طریق VirusTotal را فعال کنید.</string>\n    <string name=\"scan_in_vt\">آنالیز در VirusTotal</string>\n    <string name=\"commandline_args\">آرگومان‌های خط فرمان</string>\n    <string name=\"search_type_regular_expressions\">رجکس</string>\n    <string name=\"cpu_time\">زمان پردازنده</string>\n    <string name=\"state\">وضعیت پردازنده</string>\n    <string name=\"failed_to_change_app_op_mode\">امکان تغییر حالت عملکرد برنامه وجود ندارد.</string>\n    <string name=\"failed_to_use_the_current_mode_of_operation\">امکان استفاده از حالت عملکرد فعلی وجود ندارد. برای این جلسه به حالت غیر روت برگردید.</string>\n    <string name=\"priority\">اولویت</string>\n    <string name=\"swap_chart_info\">● %1$s استفاده شده ● %2$s آزاد</string>\n    <string name=\"binary_64_bit\">64 بیت</string>\n    <string name=\"auth_manager_title\">مدیر مجوز</string>\n    <string name=\"regenerate_auth_key\">بازسازی کلید مجوز</string>\n    <string name=\"suspend_app\">ساسپند</string>\n    <string name=\"hide_app\">پنهان</string>\n    <string name=\"endianness_little_endian\">اندیان کوچک</string>\n    <string name=\"endianness_big_endian\">ادیان بزرگ</string>\n    <string name=\"save_and_exit\">ذخیره و خروج</string>\n    <string name=\"vt_queued\">VirusTotal: در صف</string>\n    <string name=\"binary_32_bit\">32 بیت</string>\n    <string name=\"so_type_executable\">قابل اجرا</string>\n    <string name=\"pref_saved_apk_name_format\">فرمت نام APK ذخیره شد</string>\n    <string name=\"app_explorer\">کاوشگر برنامه</string>\n    <string name=\"action_optimize_app\">بهینه‌سازی</string>\n    <string name=\"app_info_tag_open_links\">باز کردن پیوندها</string>\n    <string name=\"title_domains_supported_by_the_app\">دامنه های پشتیبانی شده</string>\n    <string name=\"so_type_shared_library\">کتابخانه اشتراک گذاری شده</string>\n    <string name=\"batch_ops_runtime_optimization\">زمان اجرای بهینه سازی</string>\n    <string name=\"action_run\">اجرا</string>\n    <string name=\"hidden_api_enf_policy_warn\">هشدار (دسترسی کامل به API مخفی اما هشدار صادر می کند)</string>\n    <string name=\"memory_chart_info\">● %1$s برنامه‌ها ● %2$s ذخیره شده ● %3$s بافرها ● %4$s رایگان</string>\n    <string name=\"sort_by_installation_date\">تاریخ نصب</string>\n    <string name=\"swap\">تعویض</string>\n    <string name=\"hidden_api_enforcement_policy\">خط مشی اجرای مخفی API</string>\n    <string name=\"hidden_api_enf_default_policy\">پیش فرض (بر اساس نوع برنامه)</string>\n    <string name=\"hidden_api_enf_policy_none\">هیچکدام (دسترسی کامل به API مخفی)</string>\n    <string name=\"block_unblock_components_dots\">مسدود کردن / بازگشایی مجوز ها…</string>\n    <string name=\"block_unblock_components_description\">مسدود کردن یا بازگشایی همه مجوز های شناسایی شده توسط امضا های داده شده</string>\n    <string name=\"unblock_components_dots\">بازگشایی مجوز ها…</string>\n    <plurals name=\"alert_failed_to_unblock_components\">\n        <item quantity=\"one\">انسداد اجزای %1$d برنامه رفع نشد</item>\n        <item quantity=\"other\">انسداد اجزای %1$d برنامه رفع نشد</item>\n    </plurals>\n    <string name=\"pref_privacy\">حریم خصوصی</string>\n    <string name=\"troubleshooting\">رفع اشکال</string>\n    <string name=\"changelog_type_improve\">بهبود</string>\n    <string name=\"pref_version_changelog\">نسخه/تغییرات</string>\n    <string name=\"calculating_file_size\">محاسبه…</string>\n    <string name=\"replacement_text\">جای‌گذاری</string>\n    <string name=\"debloat_list_carrier\">خدمات رسان/ISP</string>\n    <string name=\"file_shortcut_target_file\">پرونده هدف</string>\n    <string name=\"debloat_removal_safe\">امن</string>\n    <string name=\"delete_filename\">پاک کردن %s</string>\n    <string name=\"confirm_file_deletion\">بله، پاک کن</string>\n    <string name=\"file_owner_id\">مالک (UID)</string>\n    <string name=\"sort_by_last_modified\">آخرین تغییر یافته</string>\n    <string name=\"adb_pairing_searching_for_port\">در حال جستجو…</string>\n    <string name=\"adb_pairing_stop_searching\">ایست</string>\n    <string name=\"install_for_another_user\">نصب کردن برای…</string>\n    <string name=\"debloat_removal_replace_short_description\">جایگزین کردن</string>\n    <string name=\"status_connecting_via_mode\">در حال اتصال با %s</string>\n    <string name=\"restoring_app\">بازگردانی %1$s…</string>\n    <string name=\"status_connected_via_mode\">متصل با %s</string>\n    <string name=\"adb_pairing_instruction\">لطفاً به گزینه های توسعه دهنده بروید تا اشکال زدایی بی سیم را فعال کنید و یک شماره جفت سازی ایجاد کنید.</string>\n    <string name=\"unix_file_permissions\">حالت</string>\n    <string name=\"open_as_folder\">پوشه</string>\n    <string name=\"freeze_unfreeze\">انجماد/رفع انجماد</string>\n    <string name=\"primary_abi\">ABI اولیه</string>\n    <string name=\"restore_dots\">بازگردانی…</string>\n    <string name=\"pref_pure_black_theme\">پوسته کاملا سیاه</string>\n    <string name=\"apk_checksums\">بررسی های APK</string>\n    <string name=\"external\">خارجی</string>\n    <string name=\"sort_by_frozen_app\">اول منجمد شده</string>\n    <string name=\"sort_by_filename\">نام</string>\n    <string name=\"file_group_id\">گروه (GID)</string>\n    <string name=\"title_terminal_emulator\">خط فرمان</string>\n    <string name=\"title_labs_activity\">آزمایشی ها</string>\n    <string name=\"debloat_removal_replace\">جای‌گذاری</string>\n    <string name=\"open_in_new_window\">پنجره جدید</string>\n    <string name=\"log_stop_recording\">پایان ضبط کردن</string>\n    <string name=\"restart_device\">باز راه‌اندازی دستگاه</string>\n    <string name=\"sort_by_total_size\">حجم کل</string>\n    <string name=\"file_change_open_with\">تنظیم بازکردن با</string>\n    <string name=\"file_open_with\">بازکردن با</string>\n    <string name=\"fm_always_open_with\">همیشه باز کن</string>\n    <string name=\"file_open_as\">بازکردن به عنوان…</string>\n    <string name=\"file_properties\">ویژگی ها</string>\n    <string name=\"file_cut\">برش</string>\n    <string name=\"on_unfreeze_open_application\">بازکردن برنامه پس از رفع انجماد</string>\n    <string name=\"export_option_xml\">XML</string>\n    <string name=\"export_option_markdown\">Markdown</string>\n    <string name=\"export_app_list\">استخراج فهرست برنامه</string>\n    <string name=\"search_option_regex\">عبارات منظم(Regex)</string>\n    <string name=\"search_option_match_case\">موارد منطبق</string>\n    <string name=\"folder\">پوشه</string>\n    <string name=\"copied_successfully\">رونوشت شد.</string>\n    <string name=\"moved_successfully\">جابه‌جا شد</string>\n    <string name=\"change_group_gid\">تنظیم گروه (GID)</string>\n    <string name=\"change_mode\">تنظیم حالت</string>\n    <plurals name=\"file_count\">\n        <item quantity=\"one\"/>\n        <item quantity=\"other\"/>\n    </plurals>\n    <string name=\"shortcut_icon\">نماد میانبر</string>\n    <string name=\"sort_by_data_usage\">مصرف داده</string>\n    <string name=\"pref_layout_direction\">جهت چیدمان</string>\n    <string name=\"internal\">داخلی</string>\n    <string name=\"magisk_denylist\">فهرست نادیده‌گیری مجیسک</string>\n    <string name=\"item_select\">انتخاب</string>\n    <string name=\"frozen\">انجماد</string>\n    <string name=\"usage_times_opened\">مرتبه باز شده</string>\n    <string name=\"usage_last_used\">آخرین استفاده</string>\n    <string name=\"usage_mobile_data\">داده های همراه</string>\n    <string name=\"usage_wifi_data\">داده های وای-فای</string>\n    <string name=\"pref_reload_apps\">بارگذاری دوباره برنامه ها</string>\n    <string name=\"file_modification_date\">دستکاری شده</string>\n    <string name=\"file_accessed_date\">دسترسی یافت</string>\n    <string name=\"file_open_with_custom_activity\">سفارشی</string>\n    <string name=\"open_as_other\">دیگر</string>\n    <string name=\"user_manual\">راهنمای کاربر</string>\n    <string name=\"get_help\">کمک گرفتن</string>\n    <string name=\"fm_open_with_for_this_file_only\">تنها برای این پرونده</string>\n    <string name=\"action_stop_service\">ایست</string>\n    <string name=\"renamed_successfully\">تغییر نام یافت</string>\n    <string name=\"confirm_uninstallation\">تایید پاک‌کردن</string>\n    <plurals name=\"search_results\">\n        <item quantity=\"one\"/>\n        <item quantity=\"other\"/>\n    </plurals>\n    <string name=\"debloat_list_type\">فهرست</string>\n    <string name=\"empty_folder\">خالی</string>\n    <string name=\"go_to_path\">برو به…</string>\n    <string name=\"uninstall_app\">پاک‌کردن %1$s</string>\n    <string name=\"copy_this_path\">رونوشت مسیر</string>\n    <string name=\"backing_up_app\"/>\n    <string name=\"create_new_folder\">پوشه جدید</string>\n    <string name=\"create_new_file\">پرونده جدید</string>\n    <string name=\"installer_options\">گزینه های نصب کننده</string>\n    <string name=\"debloat_removal_safe_short_description\">امن برای پاک‌کردن</string>\n    <string name=\"title_alternatives_to_bloatware\">جایگزین ها</string>\n    <string name=\"browse_files\">مرور</string>\n    <string name=\"pref_files_msg\">پیکربندی مدیریت پرونده.</string>\n    <string name=\"pref_files_display_in_launcher\">نمایش \\\"پرونده ها\\\" در کشو برنامه ها</string>\n    <string name=\"pref_set_home\">تنظیم خانه</string>\n    <string name=\"title_description\">توضیحات</string>\n    <string name=\"module_name\">نام ماژول</string>\n    <string name=\"xposed_module_info\">درباره ماژول Xposed</string>\n    <string name=\"action_lock_app\">قفل</string>\n    <string name=\"app_manager_is_unlocked\">قفل App Manager باز شده</string>\n    <string name=\"tap_to_open_notification_settings\">برای پنهان سازی ضربه بزنید</string>\n    <string name=\"app_manager_is_running\">App Manager در حال اجرا است</string>\n    <string name=\"action_checking\">در حال بررسی…</string>\n    <string name=\"report_not_available\">در دسترس نیست</string>\n    <string name=\"screen_time\">زمان صفحه</string>\n    <string name=\"filter_frozen_apps\">برنامه های منجمد</string>\n    <string name=\"file_open_with_os_default_dialog\">بازکردن با پیشفرض سیستم عامل</string>\n    <string name=\"open_as_text\">متن</string>\n    <string name=\"open_as_image\">تصویر</string>\n    <string name=\"open_as_video\">ویدیو</string>\n    <string name=\"open_as_archive\">بایگانی</string>\n    <string name=\"option_display_folders_on_top\">پوشه ها در بالا</string>\n    <string name=\"tracker\">ردیاب</string>\n    <string name=\"unfreeze\">منجمد نکن</string>\n    <string name=\"changelog_type_new\">جدید</string>\n    <string name=\"changelog_type_fix\">حل</string>\n    <string name=\"unsupported_split_apk\">پشتیبانی نشده</string>\n    <string name=\"freeze\">رفع انجماد</string>\n    <string name=\"file_creation_date\">ساخته شد</string>\n    <string name=\"change_backup_volume\">تنطیم صدا</string>\n    <string name=\"backup_no_backups_present\">بدون پشتیبان.</string>\n    <string name=\"app_manager_build_expired\">به‌روزرسانی نیاز است</string>\n    <string name=\"tap_to_freeze_app\">برای انجماد ضربه بزنید</string>\n    <string name=\"action_continue\">ادامه</string>\n    <string name=\"class_hierarchy\">سلسله مراتب</string>\n    <string name=\"redo\">بازگردانی</string>\n    <string name=\"sort_by_file_size\">حجم پرونده</string>\n    <string name=\"sort_by_file_type\">نوع پرونده</string>\n    <string name=\"title_ui_tracker\">ردیاب رابط کاربری</string>\n    <string name=\"title_code_editor\">ویرایشگر کد</string>\n    <string name=\"grant_required_permission\">گرفتن دسترسی های مورد نیاز</string>\n    <string name=\"read_only_file\">پرونده تنها خواندنی</string>\n    <string name=\"debloat_removal_type\">نوع</string>\n    <string name=\"debloat_list_aosp\">اندروید خام</string>\n    <string name=\"debloat_list_oem\">OEM</string>\n    <string name=\"debloat_list_google\">گوگل</string>\n    <string name=\"debloat_list_misc\">متفرقه</string>\n    <string name=\"debloat_removal_caution\">باند</string>\n    <string name=\"finder_title\">جستجوگر</string>\n    <string name=\"action_replace_all\">جایگزینی همه</string>\n    <string name=\"system_app_put_back\">بازگشت به عقب</string>\n    <string name=\"title_audio_player\">پخش کننده صدا</string>\n    <string name=\"filter_force_stopped_apps\">برنامه های ایستاده</string>\n    <string name=\"installing_package\"/>\n    <string name=\"enter_target_path\">مسیر هدف</string>\n    <string name=\"invalid_target_path\">مسیر نامعتبر</string>\n    <string name=\"copy_these_paths\">رونوشت مسیر ها</string>\n    <string name=\"copy_keep_both_file\">حفظ هردو</string>\n    <string name=\"profile_id\">شناسه نمایه</string>\n    <string name=\"change_owner_uid\">تنظیم مالک (UID)</string>\n    <string name=\"copy_profile_id\">رونوشت شناسه نمایه</string>\n    <string name=\"select_filter\">یک فیلتر انتخاب کنید</string>\n    <string name=\"enter_symbolic_link_name\">نام پیوند</string>\n    <string name=\"date\">تاریخ</string>\n    <string name=\"virus_total\">ویروس‌توتال</string>\n    <string name=\"pref_cat_general\">عمومی</string>\n    <string name=\"status_connecting\">در حال اتصال…</string>\n    <string name=\"adb_pairing_pairing_in_progress\">جفت شدن…</string>\n    <string name=\"adb_pairing_retry_pairing\">تلاش دوباره</string>\n    <string name=\"size_in_bytes\">حجم (بایت)</string>\n    <string name=\"pref_use_vt\">استفاده از ویروس‌توتال</string>\n    <string name=\"adb_pairing_input_pairing_code\">شماره جفت‌سازی</string>\n    <string name=\"adb_pairing_pairing_code\">شماره جفت‌سازی</string>\n    <string name=\"mode_of_op_custom_command_title\">دستور سفارشی</string>\n    <string name=\"pref_installer\">استفاده از نصب کننده</string>\n    <string name=\"pref_use_log_viewer\">استفاده از نمایشگر Log</string>\n    <string name=\"value_cannot_be_empty\">مقدار نمیتواند خالی باشد!</string>\n    <string name=\"invalid_regex\">عبارات منظم نامعتبر!</string>\n    <plurals name=\"folder_count\">\n        <item quantity=\"one\"/>\n        <item quantity=\"other\"/>\n    </plurals>\n    <string name=\"netpolicy_allow_metered_background_data\">حتی زمانی که صرفه جویی داده روشن است به داده‌ های پس‌ زمینه در شبکه‌ های اندازه‌گیری شده اجازه دهید</string>\n    <string name=\"netpolicy_reject_metered_data\">رد داده ها در شبکه های اندازه گیری شده</string>\n    <string name=\"vt_disclaimer\">VirusTotal و نماد های آن علامت تجاری Chronicle LLC هستند نه مدیر برنامه - کلاینت API - و نه نویسندگان آن در قبال داده‌ هایی که ممکن است به VirusTotal ارسال کنید مسئولیتی ندارند</string>\n    <string name=\"uses_play_app_signing_description\">این برنامه دارای نشانگر های خاصی است که نشان می دهد &lt;i&gt;ممکن است&lt;/i&gt; از &lt;a href=\\\"https://support.google.com/googleplay/android-developer/answer/9842756\\\"&gt;امضای برنامه Play&lt;/i&gt; استفاده کند a&gt; با این طرح کلید های امضا در سرور های گوگل ذخیره می شوند و گوگل مسئولیت امضای برنامه را بر عهده دارد توجه داشته باشید که تطبیق اطلاعات امضا تنها راه برای تایید این است که برنامه توسط شخص دیگری غیر از توسعه‌دهنده (و در این مورد گوگل) تغییر داده نشده</string>\n    <string name=\"pref_vt_apikey_description\">یک کلید API به مدیر برنامه امکان می‌دهد فایل‌ های APK را به VirusTotal آپلود کند و همچنین گزارش‌ ها را واکشی کند برای دریافت رایگان کلید API در https://virustotal.com ثبت نام کنید</string>\n    <string name=\"warning_working_on_root_mode\">هشدار : کار کردن با روت به جای حالت ADB</string>\n    <string name=\"failed_to_enable_magisk_deny_list\">لیست رد Magisk فعال نشده</string>\n    <string name=\"mode_of_op_with_inferred_mode_of_op\">%1$s (حالت استنباط شده : %2$s)</string>\n    <string name=\"failed_to_disable_magisk_deny_list\">لیست رد Magisk غیرفعال نشد</string>\n    <string name=\"warning_working_on_system_mode\">هشدار : کارکردن سیستم به جای حالت ADB</string>\n    <string name=\"zygote_preload_name\">نام پیش بارگذاری Zygote</string>\n    <string name=\"netpolicy_reject_metered_background_data\">داده های پس زمینه را در شبکه های اندازه گیری رد کنید</string>\n    <string name=\"pref_toggle_internet_msg\">ویژگی های اینترنت را در مدیر برنامه فعال کنید</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-fr/disclaimer.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- SPDX-License-Identifier: GPL-3.0-or-later --><resources>\n    <string name=\"disclaimer_header\">Limitation de responsabilité</string>\n    <string name=\"disclaimer_exit\">Quitter</string>\n    <string name=\"disclaimer_agree\">J\\'accepte</string>\n    <string name=\"disclaimer_agree_forever\">Ne plus afficher</string>\n    <string name=\"disclaimer_footer\">© 2020–2024 Muntashir Al-Islam</string>\n    <string name=\"disclaimer_body\">App Manager propose des fonctions racines qui pourraient éventuellement endommager votre appareil en cas d\\'utilisation inappropriée. App Manager n’est pas responsable des dommages liés à l’utilisation de cette application. Si vous ne maîtrisez pas le fonctionnement des racines, vous devriez éviter d’utiliser les options racines tant que vous n\\'êtes pas pleinement conscient des risques.\n\\n\n\\nTout lien fourni vers d’autres applications et sites web est destiné à aider les utilisateurs. Je ne suis pas responsable du contenu que vous pourrez trouver en suivant ces liens.\n\\n\n\\nEn utilisant App Manager, vous acceptez l’entière responsabilité de son utilisation et n’engagerez aucune action en réparation de dommage lié à une mauvaise utilisation.\n\\n\n\\nEn utilisant cette application, vous acceptez toute responsabilité liée à son usage et conviendrez que je ne suis pas responsable des effets indésirables engendrés sur votre appareil.</string>\n</resources>"
  },
  {
    "path": "app/src/main/res/values-fr/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- SPDX-License-Identifier: GPL-3.0-or-later --><resources xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:tools=\"http://schemas.android.com/tools\">\n    <string name=\"_lang_tag\" translatable=\"false\">fr</string>\n    <string name=\"uninstall\">Désinstaller</string>\n    <string name=\"cache_size\">Cache</string>\n    <string name=\"data_size\">Données</string>\n    <string name=\"about\">À propos</string>\n    <string name=\"data_usage_msg\">Données d\\'utilisation</string>\n    <string name=\"data_transmitted\">Données envoyées</string>\n    <string name=\"data_received\">Données reçues</string>\n    <string name=\"sort_by_target_sdk\">Cible SDK</string>\n    <string name=\"sort_by_domain\">Applications utilisateur en premier</string>\n    <string name=\"sort_by_package_name\">Nom du paquet</string>\n    <string name=\"sort_by_app_label\">Nom de l\\'application</string>\n    <string name=\"loading\">Chargement…</string>\n    <string name=\"error\">Erreur</string>\n    <string name=\"manifest\">Manifeste</string>\n    <string name=\"input_features\">Fonctionnalités d\\'entrée</string>\n    <string name=\"no_configurations\">Aucune configuration</string>\n    <string name=\"configurations\">Configurations</string>\n    <string name=\"app_signing_no_signatures\">Aucune signature valide</string>\n    <string name=\"signatures\">Signatures</string>\n    <string name=\"sort_by_sha\">Signature</string>\n    <string name=\"shared_user_id\">Identifiant utilisateur partagé</string>\n    <string name=\"sort_by_shared_user_id\">Identifiant utilisateur partagé</string>\n    <string name=\"no_feature\">Aucune fonctionnalité</string>\n    <string name=\"uses_feature\">Utilise les fonctionnalités</string>\n    <string name=\"group\">Groupe</string>\n    <string name=\"shared_libs\">Bibliothèques partagées</string>\n    <string name=\"declared_permission\">Autorisations</string>\n    <string name=\"patterns_allowed\">Motifs autorisés</string>\n    <string name=\"write\">Écrire</string>\n    <string name=\"read\">Lire</string>\n    <string name=\"path_permissions\">Autorisations de chemin d\\'accès</string>\n    <string name=\"grant_uri_permission\">Autoriser l\\'accès aux URI</string>\n    <string name=\"flags\">Drapeaux</string>\n    <string name=\"soft_input\">Mode de saisie logicielle</string>\n    <string name=\"orientation\">Orientation</string>\n    <string name=\"no_service\">Aucun service</string>\n    <string name=\"service\">Services</string>\n    <string name=\"authority\">Autorité</string>\n    <string name=\"sort_by_last_update\">Dernière mise à jour</string>\n    <string name=\"task_affinity\">Affinité de la tâche</string>\n    <string name=\"launch_mode\">Mode de lancement</string>\n    <string name=\"no_providers\">Aucun fournisseur</string>\n    <string name=\"providers\">Fournisseurs</string>\n    <string name=\"no_receivers\">Aucun récepteur</string>\n    <string name=\"receivers\">Récepteurs</string>\n    <string name=\"no_activities\">Aucune activité</string>\n    <string name=\"refresh\">Actualiser</string>\n    <string name=\"launch\">Lancer</string>\n    <string name=\"activities\">Activités</string>\n    <string name=\"require_no_permission\">Aucune autorisation requise</string>\n    <string name=\"permissions\">Utilise les autorisations</string>\n    <string name=\"installer_app\">Installeur App</string>\n    <string name=\"scanner\">Analyseur</string>\n    <string name=\"sort\">Trier</string>\n    <string name=\"obb_size\">Obb</string>\n    <string name=\"close\">Fermer</string>\n    <string name=\"no_root\">Pas de root</string>\n    <string name=\"root\">Root</string>\n    <string name=\"user_profile_with_id\">Profil : %1$s (%2$d)</string>\n    <string name=\"advanced\">Avancé</string>\n    <string name=\"simple\">Simple</string>\n    <string name=\"enabled\">Activé</string>\n    <string name=\"choose\">Sélectionner</string>\n    <string name=\"input_permissions_description\">Autorisations séparées par des espaces, ex : <tt>com.permission.GET_ACCOUNTS android.permission.ACCESS_MEDIA_LOCATION</tt> etc. Utilise <tt>*</tt> pour appliquer toutes les permissions.</string>\n    <string name=\"input_permissions\">Autorisations</string>\n    <string name=\"options\">Options</string>\n    <string name=\"off\">Désactivé</string>\n    <string name=\"on\">Activé</string>\n    <string name=\"profile_state_msg\">État activé/désactivé personnalisé pour ce profil</string>\n    <string name=\"profile_block_trackers_msg\">Bloque les traqueurs dans les applications</string>\n    <string name=\"profile_clear_data_msg\">Efface les données des applications</string>\n    <string name=\"profile_clear_cache_msg\">Efface le cache des applications</string>\n    <string name=\"profile_force_stop_msg\">Arrêt forcé des application</string>\n    <string name=\"profile_state\">État du profil</string>\n    <string name=\"adb_over_tcp\">ADB via TCP</string>\n    <string name=\"pref_mode_of_operations\">Type d\\'opération</string>\n    <string name=\"ecc\">Cryptographie à courbe elliptique</string>\n    <string name=\"rsa\">RSA</string>\n    <string name=\"aes\">AES</string>\n    <string name=\"none\">Aucun</string>\n    <string name=\"pref_encryption_msg\">Chiffrement des sauvegardes.</string>\n    <string name=\"encryption\">Chiffrement</string>\n    <string name=\"select_user\">Sélectionner l\\'utilisateur</string>\n    <string name=\"failed_to_duplicate_profile\">Impossible de dupliquer le profil</string>\n    <string name=\"duplicate\">Dupliquer</string>\n    <string name=\"new_profile\">Nouveau profil</string>\n    <string name=\"input_profile_name_description\">Le nom du profil ne peut pas contenir d\\'espaces.</string>\n    <string name=\"input_profile_name\">Nom du profil</string>\n    <string name=\"un_apkm\">UnApkm</string>\n    <string name=\"in_progress\">En cours</string>\n    <string name=\"conversion_failed\">Échec de la conversion.</string>\n    <string name=\"select_apk\">Sélectionner le fichier APK</string>\n    <string name=\"send_crash_report\">Envoyer le rapport de plantage</string>\n    <string name=\"tap_to_submit_crash_report\">Appuyez pour envoyer le rapport de plantage.</string>\n    <string name=\"am_crashed\">App Manager vient de planter</string>\n    <string name=\"filter_running_apps\">Applications en cours d\\'exécution</string>\n    <string name=\"copy\">Copier</string>\n    <string name=\"view_missing_signatures\">Appuyez pour visualiser ou envoyer des signatures pas encore présantes dans la base de données ou les bibliothèques de App Manager.</string>\n    <string name=\"tap_to_see_details\">Appuyez pour voir les détails</string>\n    <string name=\"lib_details\">Informations sur la bibliothèque</string>\n    <string name=\"no_libs\">Aucune bibliothèque</string>\n    <string name=\"sys_config\">Configuration du système</string>\n    <string name=\"only_install\">Installation seule</string>\n    <string name=\"app_signing_install_without_data_loss\">Si vous avez désactivé la vérification des signatures, vous pouvez utiliser l\\'option <b>Installation seule</b> pour installer l\\'application sans perdre de données.</string>\n    <string name=\"app_data_will_be_lost\">Les données existantes seront perdues.</string>\n    <string name=\"app_signing_signature_mismatch_for_system_apps\">Impossible d\\'installer l\\'application car une application système avec une signature différente possède déjà ce nom de paquet.</string>\n    <string name=\"do_you_want_to_uninstall_and_install\">Voulez-vous désinstaller et installer à nouveau l\\'application \\?</string>\n    <string name=\"usage_access_not_supported\">Impossible de demander l\\'accès aux données d\\'utilisation, puisque la page correspondante des paramètres n\\'existe pas.</string>\n    <string name=\"non_critical_exts\">Extensions non critiques</string>\n    <string name=\"critical_exts\">Extensions critiques</string>\n    <string name=\"dsa_affine_y\">Coordonnée y de la fonction affine</string>\n    <string name=\"dsa_affine_x\">Coordonnée x de la fonction affine</string>\n    <string name=\"rsa_modulus\">Modulo</string>\n    <string name=\"rsa_exponent\">Exposant</string>\n    <string name=\"format\">Format</string>\n    <string name=\"public_key\">Clé publique</string>\n    <string name=\"algorithm\">Algorithme</string>\n    <string name=\"app_signing_signature\">Signature</string>\n    <string name=\"checksums\">Sommes de contrôle</string>\n    <string name=\"serial_no\">Numéro de série</string>\n    <string name=\"not_yet_valid\">Pas encore valide</string>\n    <string name=\"expired\">Expiré</string>\n    <string name=\"valid\">Valide</string>\n    <string name=\"validity\">Validité</string>\n    <string name=\"type\">Type</string>\n    <string name=\"expiry_date\">Date d\\'expiration</string>\n    <string name=\"subject\">Sujet</string>\n    <string name=\"filter_apps_with_backups\">Avec sauvegardes</string>\n    <string name=\"sort_by_backup\">Sauvegardé en premier</string>\n    <string name=\"failed_to_uninstall_updates\">Impossible d\\'installer les mises à jour pour <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g>.</string>\n    <string name=\"update_uninstalled_successfully\">Les mises à jour de <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g> ont été installées.</string>\n    <string name=\"uninstall_updates\">Désinstaller les mises à jour</string>\n    <string name=\"allow_open_pgp_operation\">Tapez pour autoriser App Manager à utiliser OpenPGP</string>\n    <string name=\"confirm_installation\">Confirmer l\\'installation</string>\n    <string name=\"pref_backup_flags_msg\">Ajouter un préréglage pour les options de sauvegarde évite de devoir sélectionner les drapeaux souhaités à chaque sauvegarde/restauration.</string>\n    <string name=\"pref_compression_method\">Méthode de compression</string>\n    <string name=\"rules\">Règles</string>\n    <string name=\"other\">Autre</string>\n    <string name=\"changes_not_saved\">Modifications non enregistrées</string>\n    <string name=\"sort_by_memory_usage\">Utilisation de la mémoire</string>\n    <string name=\"sort_by_apps_first\">Applications en premier</string>\n    <string name=\"sort_by_process_id\">Identifiant du processus</string>\n    <string name=\"sort_by_process_name\">Nom du processus</string>\n    <string name=\"filter_apps\">Applications</string>\n    <string name=\"no_apps\">Aucune application</string>\n    <string name=\"apps\">Applications</string>\n    <string name=\"apply_now\">Appliquer maintenant…</string>\n    <string name=\"no_profiles\">Aucun profil</string>\n    <string name=\"profiles\">Profils</string>\n    <string name=\"open_pgp_provider\">Fournisseur OpenPGP</string>\n    <string name=\"cancel\">Annuler</string>\n    <string name=\"ok\">OK</string>\n    <string name=\"input_backup_name_description\">Le nom de la sauvegarde ne doit ni commencer par un chiffre ni contenir d\\'espaces. Laissez-le vide si vous souhaitez utiliser la date et l\\'heure actuelles.</string>\n    <string name=\"input_backup_name\">Nom de la sauvegarde</string>\n    <string name=\"downgrade\">Rétrograder</string>\n    <string name=\"process_state_with_extra\">État : <xliff:g id=\"process_state\" example=\"Sleeping\">%1$s</xliff:g> (<xliff:g id=\"state_extra\" example=\"High priority\">%2$s</xliff:g>)</string>\n    <string name=\"process_state\">État : <xliff:g id=\"process_state\" example=\"Sleeping\">%1$s</xliff:g></string>\n    <string name=\"state_multithreaded\">Multi-fils</string>\n    <string name=\"state_foreground\">Premier plan</string>\n    <string name=\"state_locked_memory\">Mémoire verrouillée</string>\n    <string name=\"state_low_priority\">Priorité basse</string>\n    <string name=\"state_high_priority\">Priorité haute</string>\n    <string name=\"state_unknown\">Inconnu</string>\n    <string name=\"state_idle\">Veille</string>\n    <string name=\"state_parked\">Garé</string>\n    <string name=\"state_zombie\">Zombie</string>\n    <string name=\"state_dead\">Mort</string>\n    <string name=\"state_device_io\">Entrée/Sortie</string>\n    <string name=\"state_sleeping\">Veille</string>\n    <string name=\"touchscreen_finger\">Doigt</string>\n    <string name=\"touchscreen_stylus\">Stylet</string>\n    <string name=\"navigation_wheel\">Molette</string>\n    <string name=\"navigation_trackball\">Boule de commande</string>\n    <string name=\"navigation_dial_pad\">Pavé numérique</string>\n    <string name=\"navigation_no_nav\">Pas de navigation</string>\n    <string name=\"keyboard_12_keys\">12 touches</string>\n    <string name=\"keyboard_qwerty\">QWERTY</string>\n    <string name=\"keyboard_no_keys\">Aucune clé</string>\n    <string name=\"_undefined\">Non défini</string>\n    <string name=\"required\">Requis</string>\n    <string name=\"orientation_sensor\">Capteur</string>\n    <string name=\"orientation_user\">Utilisateur</string>\n    <string name=\"orientation_reverse_landscape\">Paysage inversé</string>\n    <string name=\"orientation_reverse_portrait\">Portrait inversé</string>\n    <string name=\"orientation_portrait\">Portrait</string>\n    <string name=\"orientation_landscape\">Paysage</string>\n    <string name=\"orientation_locked\">Verrouillé</string>\n    <string name=\"orientation_unspecified\">Non spécifié</string>\n    <string name=\"launch_mode_single_task\">Tâche unique</string>\n    <string name=\"launch_mode_single_instance\">Instance unique</string>\n    <string name=\"launch_mode_multiple\">Multiple</string>\n    <string name=\"locale_split_for_base_apk\">Langue <xliff:g id=\"split_name\" example=\"English\">%1$s</xliff:g> pour l\\'APK de base</string>\n    <string name=\"locale_split_for_feature\">Langue <xliff:g id=\"split_name\" example=\"English\">%1$s</xliff:g> pour la fonctionnalité <xliff:g id=\"feature_name\" example=\"Visualizer\">%2$s</xliff:g></string>\n    <string name=\"abi_split_for_base_apk\"><xliff:g id=\"split_name\" example=\"arm64_v8a\">%1$s</xliff:g> code pour l\\'APK de base</string>\n    <string name=\"abi_split_for_feature\"><xliff:g id=\"split_name\" example=\"arm64_v8a\">%1$s</xliff:g> code pour <xliff:g id=\"feature_name\" example=\"Visualizer\">%2$s</xliff:g></string>\n    <string name=\"density_split_for_base_apk\"><xliff:g id=\"split_name\" example=\"xxdpi\">%1$s</xliff:g> (<xliff:g id=\"dpi_no\" example=\"480\">%2$d</xliff:g> DPI) ressources pour l\\'APK de base</string>\n    <string name=\"density_split_for_feature\"><xliff:g id=\"split_name\" example=\"xxdpi\">%1$s</xliff:g> (<xliff:g id=\"dpi_no\" example=\"480\">%2$d</xliff:g> DPI) ressources pour la fonctionnalité <xliff:g id=\"feature_name\" example=\"Visualizer\">%3$s</xliff:g></string>\n    <string name=\"unknown_split_for_base_apk\"><xliff:g id=\"split_name\" example=\"some_split\">%1$s</xliff:g> pour l\\'APK de base</string>\n    <string name=\"unknown_split_for_feature\"><xliff:g id=\"split_name\" example=\"some_split\">%1$s</xliff:g> pour la fonctionnalité <xliff:g id=\"feature_name\" example=\"Visualizer\">%2$s</xliff:g></string>\n    <string name=\"split_feature_name\">Fonctionnalité : <xliff:g id=\"feature_name\" example=\"Visualizer\">%1$s</xliff:g></string>\n    <string name=\"base_apk\">APK de base</string>\n    <string name=\"choose_language\">Modifier la langue</string>\n    <string name=\"auto\">Auto</string>\n    <string name=\"pref_app_language\">Langue</string>\n    <string name=\"backup_all_users\">Tous les utilisateurs</string>\n    <string name=\"backup_multiple\">Sauvegarde multiple</string>\n    <string name=\"obb_files_extracted_successfully\">Fichiers OBB extraits</string>\n    <string name=\"failed_to_extract_obb_files\">Impossible d\\'extraire les fichiers OBB</string>\n    <string name=\"backup_obb_media\">OBB et Médias</string>\n    <string name=\"backup_apk_files\">Fichiers APK</string>\n    <string name=\"installer_error_session_abandon\">Impossible d\\'abandonner la session d\\'installation</string>\n    <string name=\"installer_error_session_commit\">Impossible de valider les fichiers APK</string>\n    <string name=\"installer_error_session_write\">Impossible d\\'écrire dans la session d\\'installation</string>\n    <string name=\"installer_error_session_create\">Impossible de créer un session d\\'installation</string>\n    <string name=\"installer_error_security\">Impossible d\\'accéder aux fichiers APK</string>\n    <string name=\"install_in_progress\">Installation…</string>\n    <string name=\"package_installer\">Installeur de paquets</string>\n    <string name=\"unblock_trackers\">Débloquer les traqueurs</string>\n    <string name=\"reinstall\">Réinstaller</string>\n    <string name=\"install_app_message\">Voulez-vous installer cette application \\?</string>\n    <string name=\"try_again\">Veuillez réessayer</string>\n    <string name=\"full_stop_tap_to_see_details\">. Appuyez pour voir les détails.</string>\n    <string name=\"operation_running\">Opération en cours d\\'exécution…</string>\n    <string name=\"failed_to_fetch_package_info\">Impossible de récupérer les informations du paquet</string>\n    <string name=\"installer_error_lidl_rom\">Votre ROM n\\'est pas compatible avec Rootless Installer.</string>\n    <string name=\"installer_error_generic\">Échec de l\\'installation</string>\n    <string name=\"installer_error_storage\">Pas assez d\\'espace de stockage pour installer l\\'application</string>\n    <string name=\"installer_error_bad_apks\">Fichiers APK sélectionnés invalides</string>\n    <string name=\"installer_error_incompatible\">L\\'application n\\'est pas compatible avec cet appareil</string>\n    <string name=\"installer_error_conflict\">Impossible d\\'installer l\\'application car le nom du paquet est en cours d\\'utilisation</string>\n    <string name=\"installer_error_blocked\">Installation bloquée par <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g></string>\n    <string name=\"installer_error_blocked_device\">appareil</string>\n    <string name=\"installer_error_aborted\">L\\'installation a échoué, soit elle a été annulée, ou alors la session a été fermée de manière inattendue</string>\n    <string name=\"filter_apps_with_activities\">Avec des activités</string>\n    <string name=\"are_you_sure\">Êtes-vous sûr \\?</string>\n    <string name=\"pref_remove_all_rules\">Supprimer toutes les règles</string>\n    <string name=\"website\">Site Web</string>\n    <string name=\"run_in_termux\">Exécuter dans Termux</string>\n    <string name=\"open_in_termux\">Ouvrir dans Termux</string>\n    <string name=\"export_icon\">Extraire l\\'icône</string>\n    <string name=\"no_matching_package_found\">Aucune application correspondante n\\'a pu être trouvée</string>\n    <string name=\"block_unblock_trackers\">Bloquer/Débloquer les traqueurs</string>\n    <string name=\"unblock\">Débloquer</string>\n    <string name=\"block\">Bloquer</string>\n    <string name=\"clear\">Effacer</string>\n    <string name=\"clear_data_message\">Êtes-vous sûr de vouloir effacer les données de cette application \\?</string>\n    <string name=\"skip_signature_checks\">Ignorer la vérification des signatures</string>\n    <string name=\"yes\">Oui</string>\n    <string name=\"no\">Non</string>\n    <string name=\"apply_to_system_apps_question\">Appliquer également aux applications système \\? Sélectionnez « Non » si vous n\\'êtes pas sûr.</string>\n    <string name=\"apply_to_system_apps\">Appliquer aux applications système</string>\n    <plurals name=\"missing_signatures\">\n        <item quantity=\"one\">%1$d signature manquante</item>\n        <item quantity=\"many\">%1$d signatures manquantes</item>\n        <item quantity=\"other\">%1$d signatures manquantes</item>\n    </plurals>\n    <plurals name=\"libraries\">\n        <item quantity=\"one\">%1$d bibliothèque</item>\n        <item quantity=\"many\">%1$d bibliothèques</item>\n        <item quantity=\"other\">%1$d bibliothèques</item>\n    </plurals>\n    <plurals name=\"classes\">\n        <item quantity=\"one\">%1$d classe</item>\n        <item quantity=\"many\">%1$d classes</item>\n        <item quantity=\"other\">%1$d classes</item>\n    </plurals>\n    <plurals name=\"backup_exists_are_you_sure\">\n        <item quantity=\"one\">Une sauvegarde existe déjà. Êtes-vous sûr ?</item>\n        <item quantity=\"many\">Une sauvegarde existe déjà pour plus d\\'une application. Êtes-vous sûr ?</item>\n        <item quantity=\"other\">Une sauvegarde existe déjà pour plus d\\'une application. Êtes-vous sûr ?</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_block_components\">\n        <item quantity=\"one\">Impossible de bloquer les composants d\\'%1$d application</item>\n        <item quantity=\"many\">Impossible de bloquer les composants de %1$d applications</item>\n        <item quantity=\"other\">Impossible de bloquer les composants de %1$d applications</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_unblock_trackers\">\n        <item quantity=\"one\">Impossible de débloquer les traqueurs d\\'%1$d application</item>\n        <item quantity=\"many\">Impossible de débloquer les traqueurs de %1$d applications</item>\n        <item quantity=\"other\">Impossible de débloquer les traqueurs de %1$d applications</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_delete_backup\">\n        <item quantity=\"one\">Impossible de supprimer %1$d sauvegarde</item>\n        <item quantity=\"many\">Impossible de supprimer %1$d sauvegardes</item>\n        <item quantity=\"other\">Impossible de supprimer %1$d sauvegardes</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_restore\">\n        <item quantity=\"one\">Impossible de restaurer %1$d application</item>\n        <item quantity=\"many\">Impossible de restaurer %1$d applications</item>\n        <item quantity=\"other\">Impossible de restaurer %1$d applications</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_backup\">\n        <item quantity=\"one\">Impossible de sauvegarder %1$d application</item>\n        <item quantity=\"many\">Impossible de sauvegarder %1$d applications</item>\n        <item quantity=\"other\">Impossible de sauvegarder %1$d applications</item>\n    </plurals>\n    <plurals name=\"failed_to_backup_some_apk_files\">\n        <item quantity=\"one\">Impossible de sauvegarder %1$d application</item>\n        <item quantity=\"many\">Impossible de sauvegarder %1$d applications</item>\n        <item quantity=\"other\">Impossible de sauvegarder %1$d applications</item>\n    </plurals>\n    <string name=\"backup_options\">Options de sauvegarde</string>\n    <string name=\"delete_backup\">Supprimer la sauvegarde</string>\n    <string name=\"restore\">Restaurer</string>\n    <string name=\"backup\">Sauvegarder</string>\n    <string name=\"data\">Données</string>\n    <string name=\"external_data\">Données externes</string>\n    <string name=\"blocking_rules\">Règles de blocage</string>\n    <string name=\"whats_new\">Quoi de neuf</string>\n    <string name=\"features\">Fonctionnalités</string>\n    <string name=\"components\">Composants</string>\n    <string name=\"trackers\">Traqueurs</string>\n    <string name=\"installed_version\">Version installée</string>\n    <string name=\"select_all\">Tout sélectionner</string>\n    <string name=\"filter_apps_with_rules\">Applications avec des règles</string>\n    <string name=\"filter_system_apps\">Applications système</string>\n    <string name=\"filter_user_apps\">Applications utilisateur</string>\n    <string name=\"package_name_is_installed_successfully\"><xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g> installé</string>\n    <string name=\"termux\">Termux</string>\n    <string name=\"only_works_in_root_or_adb_mode\">Fonctionne uniquement en mode root ou ADB</string>\n    <string name=\"input_app_ops\">Opérations de l\\'application</string>\n    <string name=\"filtered_packages\">Paquets filtrés</string>\n    <string name=\"input_signatures_description\">Signatures séparées par des espaces, ex : <tt>com.facebook org.app2 com.app3</tt> etc.</string>\n    <string name=\"input_signatures\">Signatures</string>\n    <string name=\"no_tracker_found\">Aucun traqueur trouvé</string>\n    <string name=\"clear_app_cache_description\">Effacer le cache de toutes les applications</string>\n    <string name=\"clear_app_cache\">Effacer le cache de l\\'application</string>\n    <string name=\"clear_data_from_uninstalled_apps_description\">Effacer les données des applications désinstallées avec le drapeau <tt>DONT_DELETE_DATA</tt></string>\n    <string name=\"clear_data_from_uninstalled_apps\">Effacer les données des applications désinstallées</string>\n    <string name=\"block_components_dots\">Bloquer les composants…</string>\n    <string name=\"block_unblock_trackers_description\">Bloquer ou débloquer les composants de publicité et de suivi dans toutes les applications installées</string>\n    <string name=\"clear_cache\">Effacer le cache</string>\n    <string name=\"pref_import_existing\">Importer des règles existantes</string>\n    <string name=\"source_code\">Code source</string>\n    <string name=\"update\">Mettre à jour</string>\n    <string name=\"install\">Installer</string>\n    <plurals name=\"no_of_trackers\">\n        <item quantity=\"one\">%1$d traqueur</item>\n        <item quantity=\"many\">%1$d traqueurs</item>\n        <item quantity=\"other\">%1$d traqueurs</item>\n    </plurals>\n    <string name=\"manifest_viewer\">Visualiseur de fichier manifeste</string>\n    <string name=\"external_apk_no_app_op\">Le fichier APK externe ne contient aucune opération</string>\n    <string name=\"changelog\">Notes de version</string>\n    <string name=\"one_click_ops\">1 - Opérations de clic</string>\n    <string name=\"never_ask\">Ne plus me demander</string>\n    <string name=\"launch_app\">Lancer</string>\n    <string name=\"failed_to_deny_dangerous_app_ops\">Impossible de révoquer toutes les opérations dangereuses de l\\'application</string>\n    <string name=\"failed_to_deny_dangerous_perms\">Impossible de révoquer toutes les autorisations dangereuses</string>\n    <string name=\"failed_to_reset_app_ops\">Impossible de réinitialiser les opérations de l\\'application</string>\n    <string name=\"failed_to_revoke_permission\">Impossible de révoquer l\\'autorisation</string>\n    <string name=\"failed_to_grant_permission\">Autorisation impossible</string>\n    <plurals name=\"alert_failed_to_disable_trackers\">\n        <item quantity=\"one\">Impossible de désactiver les traqueurs d\\'%1$d application</item>\n        <item quantity=\"many\">Impossible de désactiver les traqueurs de %1$d applications</item>\n        <item quantity=\"other\">Impossible de désactiver les traqueurs de %1$d applications</item>\n    </plurals>\n    <string name=\"unknown_op\">Opération inconnue</string>\n    <string name=\"sort_by_tracker_components\">Traqueurs en premier</string>\n    <string name=\"deny_dangerous_permissions\">Refuser les autorisations dangereuses</string>\n    <string name=\"sort_by_denied_permissions\">Refusées en premier</string>\n    <string name=\"sort_by_dangerous_permissions\">Dangereuses en premier</string>\n    <string name=\"sort_by_permission_names\">Nom de l\\'autorisation</string>\n    <string name=\"reset_to_default\">Réintialiser les valeurs par défaut</string>\n    <string name=\"sort_by_component_name\">Nom du composant</string>\n    <string name=\"block_trackers\">Bloquer les traqueurs</string>\n    <string name=\"sort_by_wifi_data\">Données Wi-Fi</string>\n    <string name=\"version\">Version</string>\n    <string name=\"pref_about_msg\">Version de App Manager, licence, crédits, etc.</string>\n    <string name=\"apply\">Appliquer</string>\n    <string name=\"select_theme\">Thème</string>\n    <string name=\"night\">Sombre</string>\n    <string name=\"day\">Clair</string>\n    <string name=\"follow_system\">Système</string>\n    <string name=\"pref_app_theme\">Thème de l\\'application</string>\n    <string name=\"pref_import_blocker_msg\">Importer des règles de blocage depuis Blocker, chaque fichier contenant les règles d\\'un seul paquet.</string>\n    <string name=\"pref_import_watt_msg\">Importer des règles de blocage depuis Watt, chaque fichier contenant des règles pour un seul paquet nommé tel que <tt>nomdupaquet.xml</tt> etc.</string>\n    <string name=\"pref_import_msg\">Importer des règles de blocage précédemment exportées depuis App Manager.</string>\n    <string name=\"pref_export_msg\">Exporter les règles de blocage configurées depuis App Manager vers le stockage externe.</string>\n    <string name=\"touchscreen\">Écran tactile</string>\n    <string name=\"navigation\">Navigation</string>\n    <string name=\"keyboard_type\">Saisie du clavier</string>\n    <string name=\"export_failed\">Échec de l\\'exportation !</string>\n    <string name=\"import_failed\">Échec de l\\'import !</string>\n    <string name=\"export_options\">Options d\\'exportation</string>\n    <string name=\"import_options\">Options d\\'importation</string>\n    <string name=\"pref_export\">Exporter</string>\n    <string name=\"pref_import\">Importer</string>\n    <string name=\"duration\">Durée</string>\n    <string name=\"running\">En cours d\\'exécution</string>\n    <string name=\"mode\">Mode</string>\n    <string name=\"permission_name\">Nom de l\\'autorisation</string>\n    <plurals name=\"alert_failed_to_force_stop\">\n        <item quantity=\"one\">Impossible de forcer l\\'arrêt d\\'%1$d application</item>\n        <item quantity=\"many\">Impossible de forcer l\\'arrêt de %1$d applications</item>\n        <item quantity=\"other\">Impossible de forcer l\\'arrêt de %1$d applications</item>\n    </plurals>\n    <string name=\"the_operation_was_successful\">Terminé</string>\n    <plurals name=\"alert_failed_to_disable_background\">\n        <item quantity=\"one\">Impossible de désactiver l\\'exécution en arrière-plan pour %1$d application</item>\n        <item quantity=\"many\">Impossible de désactiver l\\'exécution en arrière-plan pour %1$d applications</item>\n        <item quantity=\"other\">Impossible de désactiver l\\'exécution en arrière-plan pour %1$d applications</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_uninstall\">\n        <item quantity=\"one\">Impossible de désinstaller %1$d application</item>\n        <item quantity=\"many\">Impossible de désinstaller %1$d applications</item>\n        <item quantity=\"other\">Impossible de désinstaller %1$d applications</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_clear_data\">\n        <item quantity=\"one\">Impossible d\\'effacer les données d\\'%1$d application</item>\n        <item quantity=\"many\">Impossible d\\'effacer les données de %1$d applications</item>\n        <item quantity=\"other\">Impossible d\\'effacer les données de %1$d applications</item>\n    </plurals>\n    <string name=\"export_blocking_rules\">Exporter les règles de blocage</string>\n    <string name=\"disable_background\">Désactiver l\\'exécution en arrière-plan</string>\n    <string name=\"backup_restore\">Sauvegarder/Restaurer</string>\n    <string name=\"clear_data\">Effacer les données</string>\n    <string name=\"user_and_uid\">Utilisateur : <xliff:g id=\"user_name\" example=\"root\">%1$s</xliff:g> (<xliff:g id=\"user_id\" example=\"0\">%2$d</xliff:g>)</string>\n    <string name=\"memory_virtual_memory\">Mémoire : %1$s, Mémoire virtuelle : %2$s</string>\n    <string name=\"pid_and_ppid\">Identifiant du processus : %1$d, Identifiant du processus parent : %2$d</string>\n    <string name=\"disable_background_run\">Empêcher le fonctionnement en arrière-plan</string>\n    <string name=\"kill_process\">Tuer</string>\n    <string name=\"running_apps\">Applications en cours d\\'exécution</string>\n    <string name=\"apk_updater\">Mise à jour d\\'APK</string>\n    <plurals name=\"failed_to_import_files\">\n        <item quantity=\"one\">Impossible d\\'importer %1$d fichier.</item>\n        <item quantity=\"many\">Impossible d\\'importe %1$d fichiers.</item>\n        <item quantity=\"other\">Impossible d\\'importe %1$d fichiers.</item>\n    </plurals>\n    <string name=\"the_export_was_successful\">Exporté</string>\n    <string name=\"the_import_was_successful\">Importé</string>\n    <string name=\"pref_import_export_blocking_rules\">Importer/exporter des règles de blocage</string>\n    <string name=\"sort_by_mobile_data\">Données mobiles</string>\n    <string name=\"sort_by_times_opened\">Nombre d\\'ouvertures</string>\n    <string name=\"sort_by_screen_time\">Temps d\\'écran</string>\n    <string name=\"sort_by_last_used\">Dernière utilisation</string>\n    <plurals name=\"no_of_times_opened\">\n        <item quantity=\"one\">%1$d fois</item>\n        <item quantity=\"many\">%1$d fois</item>\n        <item quantity=\"other\">%1$d fois</item>\n    </plurals>\n    <string name=\"sort_by_blocked_components\">Bloquées en premier</string>\n    <string name=\"exodus_link\">Lien εxodus</string>\n    <string name=\"usage_yesterday\">Hier</string>\n    <string name=\"app_settings\">Paramètres</string>\n    <string name=\"usage_access\">Accès aux données d\\'utilisation</string>\n    <string name=\"str_logo\">Logo</string>\n    <string name=\"rules_not_applied\">Les règles ne sont pas appliquées</string>\n    <string name=\"app_size\">Application</string>\n    <string name=\"total_size\">Total</string>\n    <string name=\"storage_and_cache\">Stockage et cache</string>\n    <string name=\"failed_to_stop\">Impossible d\\'arrêter <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g>.</string>\n    <string name=\"force_stop\">Forcer l\\'arrêt</string>\n    <string name=\"enable\">Activer</string>\n    <string name=\"disable\">Désactiver</string>\n    <string name=\"stopped\">Arrêté</string>\n    <string name=\"uninstall_system_app_message\">C\\'est une application système. Êtes-vous sûr de vouloir désinstaller cette application \\?</string>\n    <string name=\"uninstalled_successfully\"><xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g> a bien été désinstallé.</string>\n    <string name=\"failed_to_uninstall\">Impossible de désinstaller <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g>.</string>\n    <string name=\"uninstall_app_message\">Voulez-vous désinstaller cette application \\?</string>\n    <string name=\"view_in_settings\">Voir dans les paramètres</string>\n    <string name=\"no_content\">Pas de contenu</string>\n    <string name=\"no_usage_in_this_time_range\">Aucune utilisation pendant cette periode</string>\n    <string name=\"disabled_app\">Désactivé</string>\n    <string name=\"key_name_cannot_be_null\">Le nom de clé ne peut pas être vide</string>\n    <string name=\"error_evaluating_input\">Impossible d\\'évaluer la saisie</string>\n    <string name=\"error_verbose_pin_shortcut\">Le lanceur actuel ne prend pas en charge l\\'épinglage des raccourcis. Impossible de créer un raccourci.</string>\n    <string name=\"type_string\">Caractères</string>\n    <string name=\"type_long\">Nombre entier long</string>\n    <string name=\"type_int\">Nombre entier</string>\n    <string name=\"type_float\">Nombre à virgule</string>\n    <string name=\"type_boolean\">Vrai/Faux</string>\n    <string name=\"done\">Terminé</string>\n    <string name=\"add_item\">Ajouter un élément</string>\n    <string name=\"select_type\">Sélectionnez un type</string>\n    <string name=\"key_name\">Nom de clé</string>\n    <string name=\"boolean_value\">Booléen</string>\n    <string name=\"decimal_value\">Nombre à virgule</string>\n    <string name=\"integer_value\">Nombre entier</string>\n    <string name=\"long_integer_value\">Nombre entier long</string>\n    <string name=\"string_value\">Chaîne</string>\n    <string name=\"saving_failed\">Échec de l\\'enregistrement, veuillez réessayer.</string>\n    <string name=\"saved_successfully\">Enregistré</string>\n    <string name=\"deletion_failed\">Échec de la suppression</string>\n    <string name=\"deleted_successfully\">Supprimé</string>\n    <string name=\"delete\">Supprimer</string>\n    <string name=\"discard\">Annuler</string>\n    <string name=\"save\">Enregistrer</string>\n    <string name=\"databases\">Bases de données</string>\n    <string name=\"shared_prefs\">Préférences partagées</string>\n    <string name=\"test_only\">Test uniquement</string>\n    <string name=\"debuggable\">Débogable</string>\n    <string name=\"updated_app\">Mis à jour</string>\n    <string name=\"no_code\">Pas de code</string>\n    <string name=\"process_name\">Nom du processus</string>\n    <string name=\"search\">Rechercher</string>\n    <string name=\"menu_apply_rules\">Appliquer les règles</string>\n    <string name=\"menu_remove_rules\">Supprimer les règles</string>\n    <string name=\"failed_to_extract_apk_file\">Impossible d\\'extraire le fichier APK</string>\n    <string name=\"share_apk\">Partager l\\'APK</string>\n    <string name=\"grant_usage_acess_message\">Utilisé pour afficher des informations sur l\\'utilisation de l\\'application.</string>\n    <string name=\"grant_usage_access\">Autoriser l\\'accès aux données d\\'utilisation</string>\n    <string name=\"go\">Aller</string>\n    <string name=\"go_back\">Retour</string>\n    <string name=\"usage_less_than_a_minute\">Il y a moins d\\'une minute</string>\n    <plurals name=\"usage_hours\">\n        <item quantity=\"one\">%1$d heure</item>\n        <item quantity=\"many\">%1$d heures</item>\n        <item quantity=\"other\">%1$d heures</item>\n    </plurals>\n    <plurals name=\"usage_days\">\n        <item quantity=\"one\">%1$d jour</item>\n        <item quantity=\"many\">%1$d jours</item>\n        <item quantity=\"other\">%1$d jours</item>\n    </plurals>\n    <plurals name=\"usage_months\">\n        <item quantity=\"one\">%1$d mois</item>\n        <item quantity=\"many\">%1$d mois</item>\n        <item quantity=\"other\">%1$d mois</item>\n    </plurals>\n    <string name=\"usage_7_days\">Les 7 derniers jours</string>\n    <string name=\"usage_today\">Aujourd\\'hui</string>\n    <string name=\"usage_weekly\">Semaine dernière</string>\n    <string name=\"app_usage\">Utilisation de l\\'application</string>\n    <string name=\"no_tracker_class\">Aucune classe de traqueur</string>\n    <string name=\"no_shared_libs\">Aucune bibliothèque partagée</string>\n    <plurals name=\"main_list_date_days\">\n        <item quantity=\"one\"><xliff:g id=\"last_update_date\" example=\"20/10/2020\">%1$s</xliff:g> <xliff:g id=\"day_no\" example=\"5\">%2$d</xliff:g> jour</item>\n        <item quantity=\"many\"><xliff:g id=\"last_update_date\" example=\"20/10/2020\">%1$s</xliff:g> <xliff:g id=\"day_no\" example=\"5\">%2$d</xliff:g> jours</item>\n        <item quantity=\"other\"><xliff:g id=\"last_update_date\" example=\"20/10/2020\">%1$s</xliff:g> <xliff:g id=\"day_no\" example=\"5\">%2$d</xliff:g> jours</item>\n    </plurals>\n    <string name=\"all_classes\">Toutes les classes</string>\n    <string name=\"tracker_classes\">Classes du traqueur</string>\n    <string name=\"tracker_details\">Détails du traqueur</string>\n    <string name=\"found_trackers\">Traqueurs trouvés :</string>\n    <plurals name=\"other_trackers_and_classes\">\n        <item quantity=\"one\"><xliff:g id=\"tracker_no\" example=\"8\">%1$d</xliff:g> traqueurs avec les classes <xliff:g id=\"class_no\" example=\"50\">%2$d</xliff:g></item>\n        <item quantity=\"many\"><xliff:g id=\"tracker_no\" example=\"8\">%1$d</xliff:g> traqueurs avec les classes <xliff:g id=\"class_no\" example=\"50\">%2$d</xliff:g></item>\n        <item quantity=\"other\"><xliff:g id=\"tracker_no\" example=\"8\">%1$d</xliff:g> traqueurs avec les classes <xliff:g id=\"class_no\" example=\"50\">%2$d</xliff:g></item>\n    </plurals>\n    <plurals name=\"two_trackers_and_classes\">\n        <item quantity=\"one\">2 traqueurs avec la classe <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g></item>\n        <item quantity=\"many\">2 traqueurs avec les classes <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g></item>\n        <item quantity=\"other\">2 traqueurs avec les classes <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g></item>\n    </plurals>\n    <plurals name=\"tracker_and_classes\">\n        <item quantity=\"one\">1 traqueur avec la classe <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g></item>\n        <item quantity=\"many\">1 traqueur avec les classes <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g></item>\n        <item quantity=\"other\">1 traqueur avec les classes <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g></item>\n    </plurals>\n    <string name=\"toggle_class_listing\">Activer/Désactiver l\\'affichage en liste des classes</string>\n    <string name=\"class_viewer\">Visualiseur de classe</string>\n    <string name=\"word_wrap\">Activer/Désactiver la coupure de mots</string>\n    <string name=\"credits_message\">Aux auteurs de :\n\\n- Le projet Android open-source\n\\n- <a href=\"https://github.com/zhaobozhen/libraries\">Absinthe\\'s Libraries</a>\n\\n- <a href=\"https://github.com/butzist/ActivityLauncher\">Activity Launcher</a>\n\\n- <a href=\"https://bitbucket.org/oF2pks/fdroid-applications-info\">Apps_packages Info</a>\n\\n- <a href=\"https://github.com/zhaobao/AppsMonitor\">AppsMonitor</a>\n\\n- <a href=\"https://github.com/8enet/AppOpsX\">AppOpsX</a>\n\\n- <a href=\"https://github.com/gabrielemariotti/changeloglib\">ChangeLog Library</a>\n\\n- <a href=\"https://bitbucket.org/oF2pks/fdroid-classyshark3xodus\">ClassySharkAndroid</a>\n\\n- <a href=\"https://github.com/billthefarmer/editor\">Editor</a>\n\\n- <a href=\"https://github.com/Raival-e/File-Explorer\">File Explorer</a>\n\\n- <a href=\"https://github.com/nex3z/FlowLayout\">FlowLayout</a>\n\\n- <a href=\"https://github.com/k3b/intent-intercept\">Intent Intercept</a>\n\\n- <a href=\"https://github.com/YarikSOffice/lingver\">Lingver</a>\n\\n- <a href=\"https://github.com/topjohnwu/Magisk\">Magisk</a>\n\\n- <a href=\"https://github.com/zhanghai/MaterialFiles\">Material Files</a>\n\\n- <a href=\"https://github.com/pluscubed/matlog\">MatLog</a>\n\\n- <a href=\"https://github.com/matrix-org/matrix-android-sdk\">Matrix Android SDK</a>\n\\n- <a href=\"https://github.com/jensstein/oandbackup\">OAndBackup</a>\n\\n- <a href=\"https://github.com/open-keychain/open-keychain\">Open Keychain</a>\n\\n- <a href=\"https://github.com/Aefyr/SAI\">SAI</a>\n\\n- <a href=\"https://github.com/RikkaApps/Shizuku\">Shizuku</a>\n\\n- <a href=\"https://github.com/eclipse/tm4e\">tm4e</a>\n\\n- <a href=\"https://github.com/tuyafeng/Watt\">Watt</a></string>\n    <string name=\"credits\">Crédits</string>\n    <string name=\"third_party\">Bibliothèques tierces et icônes</string>\n    <string name=\"license\">Licence</string>\n    <string name=\"icon_picker\">Sélecteur d\\'icône</string>\n    <string name=\"class_name\">Nom de classe</string>\n    <string name=\"package_name\">Nom du paquet</string>\n    <string name=\"shortcut_name\">Nom du raccourci</string>\n    <string name=\"create_shortcut\">Créer un raccourci</string>\n    <string name=\"starting_activity\">Démarrage de l\\'activité : <xliff:g id=\"activity_name\" example=\".main.MainActivity\">%1$s</xliff:g></string>\n    <string name=\"error_creating_shortcut\">Erreur lors de la création du raccourci</string>\n    <string name=\"empty_package_name\">Nom du paquet vide</string>\n    <string name=\"main_activity\">Activité principale</string>\n    <string name=\"user_id\">Identifiant utilisateur</string>\n    <string name=\"date_updated\">Date de mise à jour</string>\n    <string name=\"date_installed\">Date d\\'installation</string>\n    <string name=\"more_info\">Plus d\\'informations</string>\n    <string name=\"sdk_flags\">Drapeaux</string>\n    <string name=\"sdk_max\">Cible</string>\n    <string name=\"sdk_min\">Min</string>\n    <string name=\"source_dir\">Répertoire source</string>\n    <string name=\"paths_and_directories\">Chemins d\\'accès et répertoires</string>\n    <string name=\"data_dir\">Répertoire de données</string>\n    <string name=\"user_app\">Application utilisateur</string>\n    <string name=\"system_app\">Application système</string>\n    <string name=\"app_info\">Informations sur l\\'application</string>\n    <string name=\"version_name_with_code\">Version <xliff:g id=\"version_name\" example=\"2.5.17\">%1$s</xliff:g> (<xliff:g id=\"version_code\" example=\"365\">%2$d</xliff:g>)</string>\n    <string name=\"user\">Utilisateur</string>\n    <string name=\"system\">Système</string>\n    <string name=\"app_not_installed\">Application non installée</string>\n    <string name=\"media_size\">Média</string>\n    <string name=\"external_data_dir\">Répertoire de données externes</string>\n    <string name=\"dev_protected_data_dir\">Répertoire de données protégé par l\\'appareil</string>\n    <string name=\"pref_global_blocking_enabled_msg\">Permet de bloquer tout composant d\\'une application sans la bloquer directement.</string>\n    <string name=\"pref_global_blocking_enabled\">Blocage instantané des composants</string>\n    <string name=\"failed_to_disable_op\">Impossible de désactiver l\\'autorisation demandée</string>\n    <string name=\"failed_to_enable_op\">Impossible d\\'activer l\\'autorisation demandée</string>\n    <string name=\"ago\">il y a</string>\n    <string name=\"reject_time\">Temps de rejet</string>\n    <string name=\"accept_time\">Temps d\\'acceptation</string>\n    <string name=\"pref_import_blocker\">Importer depuis Blocker</string>\n    <string name=\"pref_import_watt\">Importer depuis Watt</string>\n    <string name=\"external_multiple_data_dir\">Répertoire de données externes <xliff:g id=\"dir_no\" example=\"1\">%1$d</xliff:g></string>\n    <string name=\"sort_by_denied_app_ops\">Refusées en premier</string>\n    <string name=\"deny_dangerous_app_ops\">Refuser les autorisations dangereuses</string>\n    <string name=\"sort_by_app_ops_names\">Nom de l\\'autorisation</string>\n    <string name=\"sort_by_app_ops_values\">Valeur de l\\'autorisation</string>\n    <string name=\"native_library_dir\">Répertoire de bibliothèques natives JNI</string>\n    <string name=\"orientation_full_sensor\">Capteur complet</string>\n    <string name=\"orientation_behind\">Arrière</string>\n    <string name=\"batch_ops\">Opérations par lots</string>\n    <plurals name=\"verified_with_warning\">\n        <item quantity=\"one\">Vérifié avec %d avertissement</item>\n        <item quantity=\"many\">Vérifié avec %d avertissements</item>\n        <item quantity=\"other\">Vérifié avec %d avertissements</item>\n    </plurals>\n    <string name=\"filter\">Filtre</string>\n    <string name=\"failed_to_parse_some_numbers\">Ne peut pas analyser certains nombres</string>\n    <string name=\"failed_packages\">Paquets en echec</string>\n    <string name=\"pref_import_existing_msg\">Ajouter des composants désactivés par les autres applis à App Manager. Faites attention en utilisant cet outil car il peut y avoir de nombreux faux positifs. Ne choisissez que les applis dont vous êtes certain.</string>\n    <string name=\"battery_mode\">Mode de batterie</string>\n    <string name=\"pref_import_export_blocking_rules_msg\">Importer/exporter des règles, importer des règles depuis Watt ou Blocker.</string>\n    <plurals name=\"no_of_components\">\n        <item quantity=\"one\">%1$d composant</item>\n        <item quantity=\"many\">%1$d composants</item>\n        <item quantity=\"other\">%1$d composants</item>\n    </plurals>\n    <string name=\"user_with_id\">Utilisateur : <xliff:g id=\"user_id\" example=\"0\">%1$d</xliff:g></string>\n    <string name=\"no_app_ops\">Aucune opération d\\'application</string>\n    <string name=\"os_version\">Version du système d\\'exploitation</string>\n    <string name=\"restore_latest_msg\">Restaurer les applications déjà installées dont les codes de version sont supérieurs au code de version installée.</string>\n    <string name=\"extras\">Extras</string>\n    <string name=\"category\">Catégories</string>\n    <string name=\"board_name\">Carte mère</string>\n    <string name=\"model\">Modèle</string>\n    <string name=\"brand_name\">Marque</string>\n    <string name=\"vendor\">Vendeur</string>\n    <string name=\"support_architectures\">Architectures supportées</string>\n    <string name=\"security_providers\">Prestataires de sécurité</string>\n    <string name=\"kernel\">Kernel</string>\n    <string name=\"manufacturer\">Fabriquant</string>\n    <string name=\"graphics\">Visuels</string>\n    <string name=\"cpu\">CPU</string>\n    <string name=\"users\">Utilisateurs</string>\n    <string name=\"languages\">Langages</string>\n    <string name=\"battery_capacity\">Capacité</string>\n    <string name=\"memory\">Mémoire</string>\n    <string name=\"gles_version\">Version OpenGL ES</string>\n    <string name=\"no_of_cores\">Coeurs</string>\n    <string name=\"security\">Sûreté</string>\n    <string name=\"battery\">Batterie</string>\n    <string name=\"interceptor\">Intercepteur</string>\n    <string name=\"installer\">Installeur</string>\n    <string name=\"comment\">Commentaire</string>\n    <string name=\"install_location_prefer_external\">Préférer en externe</string>\n    <string name=\"install_location\">Emplacement de l\\'installation</string>\n    <string name=\"install_location_internal_only\">Uniquement interne</string>\n    <string name=\"resend_intent\">Renvoyer l\\'Intent</string>\n    <string name=\"value\">Valeur</string>\n    <string name=\"mime_type\">Type MIME</string>\n    <string name=\"action\">Action</string>\n    <string name=\"result_code\">Code de résultat</string>\n    <string name=\"activity_result\">Résultat de l\\'activité</string>\n    <string name=\"uri\">URI</string>\n    <string name=\"share\">Partager</string>\n    <string name=\"about_device\">À propos de l\\'appareil</string>\n    <string name=\"toggle_kill_for_system_apps\">Activer/désactiver l\\'arrêt forcé des applications système</string>\n    <string name=\"app_ops\">Opérations de l\\'appli</string>\n    <string name=\"internal_data\">Données internes</string>\n    <string name=\"requested_large_heap\">Grand tas</string>\n    <string name=\"source_code_links\"><a href=\"https://github.com/MuntashirAkon/AppManager\">GitHub</a> • <a href=\"https://gitlab.com/muntashir/AppManager\">GitLab</a> • <a href=\"https://0xacab.org/muntashir/AppManager\">Riseup</a> • <a href=\"https://codeberg.org/muntashir/AppManager\">Codeberg</a></string>\n    <string name=\"omit_sensitive_info_summary\">Omettez les informations sensibles comme les URL, les numéros de téléphone ou les adresses courriel.</string>\n    <string name=\"app_signing_signatures\">Signatures</string>\n    <plurals name=\"alert_failed_to_set_app_ops\">\n        <item quantity=\"one\">Impossible de définir les opérations d\\'application pour %1$d application</item>\n        <item quantity=\"many\">Impossible de définir les opérations d\\'application pour %1$d applications</item>\n        <item quantity=\"other\">Impossible de définir les opérations d\\'application pour %1$d applications</item>\n    </plurals>\n    <string name=\"input_app_ops_description_profile\">Saisissez les noms ou les constantes d\\'opérations d\\'application avec des espaces, par exemple <tt>WAKE_LOCK 63 72 CAMERA</tt>. Utilisez <tt>*</tt> pour appliquer toutes les opérations d\\'application configurées.</string>\n    <string name=\"input_app_ops_description\">Saisissez les noms ou les constantes d\\'opérations d\\'application avec des espaces, par exemple <tt>WAKE_LOCK 63 72 CAMERA</tt> etc.</string>\n    <string name=\"deny_app_ops_description\">Définir un mode pour les opérations de l\\'application identifiées par les valeurs constante, par exemple <tt>63</tt> ou <tt>RUN_IN_BACKGROUND</tt></string>\n    <string name=\"pref_remove_all_rules_msg\">Les autorisations seront accordées, les opérations et les composants de l\\'application retrouveront leurs valeurs par défaut.</string>\n    <plurals name=\"app_signing_signature_schemes_pl\">\n        <item quantity=\"one\">Schéma de signature</item>\n        <item quantity=\"many\">Schémas de signature</item>\n        <item quantity=\"other\">Schémas de signature</item>\n    </plurals>\n    <string name=\"orientation_sensor_landscape\">Capteur mode paysage</string>\n    <string name=\"text_include_device_info\">Inclure les informations de l\\'appareil</string>\n    <string name=\"record_log\">Journaux d\\'enregistrement</string>\n    <string name=\"disable_background_run_description\">Défini le mode <i>Ignore</i> pour les opérations d\\'application suivantes : <tt>RUN_IN_BACKGROUND</tt> (depuis Android 7.0) et <tt>RUN_ANY_IN_BACKGROUND</tt> (depuis Android 9).</string>\n    <string name=\"community_links\"><a href=\"https://matrix.to/#/#appmanager:matrix.org\">Matrix</a> • <a href=\"https://t.me/AppManagerChannel\">Telegram</a> • <a href=\"https://x.com/AppManagerNews\">Twitter/X</a> • <a href=\"https://floss.social/@appmanager\">Mastodon</a></string>\n    <string name=\"community\">Communauté</string>\n    <string name=\"pref_selected_users_msg\">Restreindre l\\'utilisation d\\'App Manager aux seuls utilisateurs sélectionnés.</string>\n    <string name=\"backup_extras_description\">Sauvegardez les autorisations de l\\'application, les options d\\'économie de batterie et d\\'utilisation des données, le statut MagiskHide, SSAID, etc. <font fgcolor=\"#ff0000\">En fonction des autorisations, tous les extras ne peuvent pas être restaurés.</font></string>\n    <string name=\"backup_extras\">Extras</string>\n    <string name=\"backup_cache_description\">Sauvegarder les dossiers <b>cache</b>, <b>no_cache</b> et <b>no_backup</b>.</string>\n    <string name=\"backup_obb_media_description\">Sauvegarder les répertoires OBB et média.</string>\n    <string name=\"backup_external_data_description\">Sauvegarder les répertoires de données externes.</string>\n    <string name=\"backup_internal_data_description\">Sauvegarder les répertoires de données internes.</string>\n    <string name=\"backup_apk_files_description\">Sauvegarder les fichiers APK depuis le répertoire source, incluant les divisions.</string>\n    <string name=\"pref_about_device_msg\">Informations de base sur l\\'appareil, notamment le système Android, le processeur, le processeur graphique, la mémoire vive, la batterie, etc.</string>\n    <string name=\"magisk_hide_enabled\">MagiskHide</string>\n    <string name=\"pref_backup_android_keystore_msg\">Certaines applications pourront ne pas fonctionner après avoir été restaurées. Restaurer le magasin de clés ne fonctionne pas sur la majorité des appareils.</string>\n    <string name=\"keep_data_and_app_signing_signatures\">Conserver les données et les signatures</string>\n    <string name=\"this_action_cannot_be_undone\">Cette action ne peut pas être annulée.</string>\n    <string name=\"input_keystore_alias_pass_msg\">Appuyez ici pour fournir le mot de passe pour %1$s</string>\n    <string name=\"input_keystore_alias_pass_description\">Entrez le mot de passe pour l\\'alias <b>%1$s</b>. Vous pouvez laisser le champ vide si le mot de passe est le même que celui du magasin de clés.</string>\n    <string name=\"input_keystore_alias_pass\">Mot de passe pour l\\'alias <b>%1$s</b></string>\n    <string name=\"input_keystore_pass_msg\">Appuyez ici pour entrer le mot de passe du magasin de clés</string>\n    <string name=\"input_keystore_pass_description\">Entrez le mot de passe du magasin de clés d\\'App Manager. Si vous voyez ceci pour la première fois, veuillez s\\'il vous plaît utiliser un générateur de mots de passe pour en générer un et le sauvegarder dans un endroit sécurisé avant de l\\'insérer ici.</string>\n    <string name=\"input_keystore_pass\">Saisissez le mot de passe du magasin de clés</string>\n    <string name=\"not_verified\">Non vérifié</string>\n    <string name=\"verified\">Vérifié</string>\n    <string name=\"pref_signature_schemes_msg\">Les schémas v1 et v2 doivent être choisis pour une meilleure compatibilité. Le schéma v4 requiert un schéma v2 ou v3.</string>\n    <string name=\"v4_scheme\">Schéma v4 (depuis Android 11)</string>\n    <string name=\"v3_scheme\">Schéma v3 (depuis Android 9)</string>\n    <string name=\"v2_scheme\">Schéma v2 (depuis Android 7.0)</string>\n    <string name=\"v1_scheme\">Schéma v1 (depuis Android 1.0)</string>\n    <string name=\"pref_apk_signing_msg\">Définir les schémas de signature, la clé de signature personnalisée, etc.</string>\n    <string name=\"apk_signing\">Signature de l\\'APK</string>\n    <string name=\"pref_sign_apk_msg\">Signer les fichiers APK avant de les installer.</string>\n    <string name=\"pref_sign_apk\">Signer l\\'APK</string>\n    <string name=\"allow_routine_ops_msg\">Autoriser le profil à être utilisé dans les opérations de routine</string>\n    <string name=\"send_selected\">Envoyer la sélection</string>\n    <string name=\"issued_date\">Date d\\'émission</string>\n    <string name=\"issuer\">Émetteur</string>\n    <string name=\"state_waking\">Réveil</string>\n    <string name=\"state_trace_stop\">Arrêt du traçage</string>\n    <string name=\"orientation_no_sensor\">Aucun capteur</string>\n    <string name=\"backup_rules_description\">Règles de sauvegarde configurées dans App Manager. <font fgcolor=\"#ff0000\">En fonction des autorisations, toutes les règles ne peuvent pas être réappliquées lors de la restauration.</font></string>\n    <string name=\"alias_pass\">Mot de passe de l\\'alias</string>\n    <string name=\"choose_an_alias\">Choisissez un alias</string>\n    <string name=\"new_alias_password\">Nouveau mot de passe d\\'alias</string>\n    <string name=\"import_key\">Importer la clé</string>\n    <string name=\"pem_file\">Fichier PEM</string>\n    <string name=\"pk8_file\">Fichier PKCS #8 (PK8)</string>\n    <string name=\"pem_and_pk8\">PEM and PKCS #8 (PK8)</string>\n    <string name=\"pkcs12_keystore\">Magasin de clefs PKCS #12 (P12)</string>\n    <string name=\"type_long_array\">Tableau d\\'entiers longs</string>\n    <string name=\"type_int_array_list\">Liste d\\'entiers</string>\n    <string name=\"type_int_array\">Tableau d\\'entiers</string>\n    <string name=\"type_component_name\">Nom du composant</string>\n    <string name=\"screen_lock\">Verrouillage d\\'écran</string>\n    <string name=\"sd_card\">Carte SD</string>\n    <string name=\"external_storage\">Stockage externe</string>\n    <string name=\"internal_storage\">Stockage interne</string>\n    <string name=\"back_up\">Sauvegarder</string>\n    <string name=\"drm_free_apkm_msg\">Le format APKM est libre de DRM, il est inutile de le convertir en APKS.</string>\n    <string name=\"restore_msg\">Restaurer des applications avec les données</string>\n    <string name=\"backup_msg\">Sauvegarder les applications avec les données</string>\n    <string name=\"restore_latest\">Restaurer les dernières sauvegardes</string>\n    <string name=\"restore_not_installed\">Restaurer les applications non installées</string>\n    <string name=\"restore_all\">Restaurer toutes les applications</string>\n    <string name=\"redo_existing_backups_msg\">Refaire les sauvegardes pour les applications installées avec une précédente sauvegarde.</string>\n    <string name=\"redo_existing_backups\">Refaire les sauvegardes existantes</string>\n    <string name=\"verify_and_redo_backups\">Vérifier et refaire les sauvegardes</string>\n    <string name=\"backup_apps_without_backups_msg\">Sauvegarder les applications qui n\\'ont pas de précédente sauvegarde.</string>\n    <string name=\"backup_apps_without_backups\">Sauvegarder les applications sans sauvegardes</string>\n    <string name=\"backup_all_apps_msg\">Sauvegarder toutes les applications installées.</string>\n    <string name=\"backup_all_apps\">Sauvegarder toutes les applications</string>\n    <string name=\"window_size\">Taille de la fenêtre</string>\n    <string name=\"refresh_rate\">Fréquence de rafraîchissement</string>\n    <string name=\"size\">Taille</string>\n    <string name=\"density\">Densité</string>\n    <string name=\"hardware\">Matériel</string>\n    <string name=\"selinux\">SELinux</string>\n    <string name=\"splits\">Divisions</string>\n    <string name=\"allow_routine_ops\">Autoriser les opérations de routine</string>\n    <string name=\"routine_ops\">Opérations de routine</string>\n    <string name=\"touchscreen_no_touch\">Pas de tactile</string>\n    <string name=\"bouncy_castle_keystore\">Magasin de clefs Bouncy Castle (BKS)</string>\n    <string name=\"java_keystore\">Magasin de clefs Java (JKS)</string>\n    <string name=\"failed_to_load_key\">Impossible de charger la clé.</string>\n    <string name=\"key_not_set\">Non défini.</string>\n    <string name=\"use_default\">Utiliser la valeur par défaut</string>\n    <string name=\"invalid_rsa_key_size\">Taille de clé invalide pour le chiffrement RSA. La longueur de clé doit être 1024, 2048 ou 4096 bits.</string>\n    <string name=\"generate_key\">Générer une clé</string>\n    <string name=\"filter_apps_without_backups\">Sans sauvegardes</string>\n    <string name=\"uninstalled_apps\">Application désinstallées</string>\n    <string name=\"verified_using_unreliable_hash\">Vérifié à l\\'aide d\\'un hachage non fiable</string>\n    <string name=\"working_on_adb_mode\">Fonctionne en mode ADB</string>\n    <string name=\"last_actions\">Dernières actions</string>\n    <string name=\"pref_enable_disable_features_msg\">Activer ou désactiver des fonctionnalités dans App Manager.</string>\n    <string name=\"enable_disable_features\">Activer/désactiver des fonctionnalités</string>\n    <string name=\"installed_apps\">Applications installées</string>\n    <string name=\"failed_to_change_ssaid\">Impossible de changer SSAID</string>\n    <string name=\"ssaid\">SSAID</string>\n    <string name=\"list_options\">Lister les options</string>\n    <string name=\"reverse\">Inverser</string>\n    <string name=\"add\">Ajouter</string>\n    <string name=\"add_to_profile\">Ajouter au profil</string>\n    <string name=\"initializing\">Initialisation…</string>\n    <string name=\"choose_what_to_do\">Choisissez quoi faire.</string>\n    <string name=\"enable_battery_optimization\">Activer l\\'optimisation de batterie \\?</string>\n    <string name=\"type_uri\">URI</string>\n    <string name=\"type_string_array_list\">Liste des chaînes de caractères</string>\n    <string name=\"type_string_array\">Tableau de chaînes de caractères</string>\n    <string name=\"type_float_array_list\">Liste de nombres décimaux</string>\n    <string name=\"type_float_array\">Tableau de nombres décimaux</string>\n    <string name=\"type_long_array_list\">Liste d\\'entiers longs</string>\n    <string name=\"keystore\">Magasin de clés</string>\n    <string name=\"input_key_password\">Mot de passe maître</string>\n    <string name=\"invalid_aes_key_size\">Taille de clé invalide pour le chiffrement AES. La clé doit avoir une longueur de 128 ou 256 bits.</string>\n    <string name=\"orientation_full_user\">Utilisateur complet</string>\n    <string name=\"next\">Suivant</string>\n    <string name=\"installer_app_installed\">Application installée</string>\n    <string name=\"paste\">Coller</string>\n    <string name=\"paired_successfully\">Couplé.</string>\n    <string name=\"invalid_password\">Mot de passe invalide, réessayez.</string>\n    <string name=\"pref_log_viewer_msg\">Configurer l\\'affichage des journaux.</string>\n    <string name=\"files\">Fichiers</string>\n    <string name=\"storage\">Stockage</string>\n    <string name=\"notice\">Notification</string>\n    <string name=\"error_with_details\">Erreur : %s</string>\n    <string name=\"saved_filters\">Filtres enregistrés</string>\n    <string name=\"pref_selected_users\">Utilisateurs sélectionnés</string>\n    <string name=\"minimum_version\">Version minimale : %d</string>\n    <string name=\"help_permissions_tab\">Ces permissions sont définies par cette application et ne peuvent être révoquées.</string>\n    <string name=\"unknown_net_policy\">Politique réseau inconnue (%1$s - %2$X)</string>\n    <string name=\"port_number_invalid\">Le numéro de port est incorrect.</string>\n    <string name=\"port_number_empty\">Le numéro de port est vide.</string>\n    <string name=\"adb_connect_port_number_description\">Le numéro de port est situé dans la section <b>adresse IP &amp; port</b>, juste en dessous de la section <b>Nom de l\\'appareil</b>.</string>\n    <string name=\"port_number\">Port</string>\n    <string name=\"adb_connect\">Connecter</string>\n    <string name=\"netpolicy_disable_network_access\">Désactiver les accès réseau</string>\n    <string name=\"netpolicy_reject_wifi_data\">Rejeter les données Wi-Fi</string>\n    <string name=\"netpolicy_reject_vpn_data\">Rejeter les données VPN</string>\n    <string name=\"netpolicy_reject_cellular_data\">Rejeter les données cellulaires</string>\n    <string name=\"netpolicy_allow_background_data\">Autoriser les données d\\'arrière-plan quand l\\'Enregistreur de Données est activé</string>\n    <string name=\"netpolicy_reject_background_data\">Rejeter les données d\\'arrière-plan</string>\n    <string name=\"hidden\">Caché</string>\n    <plurals name=\"alert_failed_to_import_backups\">\n        <item quantity=\"one\">Impossible d\\'importer la sauvegarde %1$d</item>\n        <item quantity=\"many\">Impossible d\\'importer les sauvegardes %1$d</item>\n        <item quantity=\"other\">Impossible d\\'importer les sauvegardes %1$d</item>\n    </plurals>\n    <string name=\"orientation_right_to_left\">De droite à gauche</string>\n    <string name=\"orientation_left_to_right\">De gauche à droite</string>\n    <string name=\"failed\">Échec</string>\n    <string name=\"confirm_import_keystore\">Voulez-vous vraiment remplacer le magasin de clés existant \\? Cette action ne pourra pas être annulée.</string>\n    <string name=\"import_keystore\">Importer le magasin de clés</string>\n    <string name=\"pref_import_export_keystore_msg\">Importer/Exporter le Bouncy Castle KeyStore (BKS) utilisé en interne par App Manager.</string>\n    <string name=\"pref_import_export_keystore\">Importer/Exporter le magasin de clés</string>\n    <string name=\"latest_backup\">Dernière sauvegarde</string>\n    <string name=\"gz_bz2_compressed\">%1$s compressé</string>\n    <string name=\"pgp_aes_rsa_encrypted\">%1$s chiffré</string>\n    <string name=\"no_encryption\">Pas de chiffrement</string>\n    <string name=\"base_backup\">Sauvegarde de base</string>\n    <string name=\"trackers_unblocked_successfully\">Les pisteurs sont maintenant débloqués</string>\n    <string name=\"trackers_blocked_successfully\">Les pisteurs sont maintenant bloqués</string>\n    <string name=\"failed_to_unblock_trackers\">Impossible de débloquer les pisteurs</string>\n    <string name=\"failed_to_block_trackers\">Impossible de bloquer les pisteurs</string>\n    <string name=\"profile_save_apk_msg\">Enregistrer les fichiers APK dans <tt>AppManager/apks</tt></string>\n    <string name=\"save_apk\">Enregistrer l\\'APK</string>\n    <string name=\"running_services\">Services en cours d\\'exécution</string>\n    <string name=\"view_logs\">Voir les journaux</string>\n    <string name=\"share_log\">Partager</string>\n    <string name=\"omit_sensitive_info\">Omettre les informations sensibles</string>\n    <string name=\"undo\">Annuler</string>\n    <string name=\"pause_unpause\">Lecture/Pause</string>\n    <string name=\"expand_all\">Tout développer</string>\n    <string name=\"file\">Fichier</string>\n    <string name=\"widget_start_recording\">Enregistrer\n\\nJournal</string>\n    <string name=\"widget_recording_in_progress\">Enregistrement en cours…</string>\n    <string name=\"unable_to_save_log\">Impossible d\\'enregistrer le journal. Avez-vous entré un nom de fichier valide \\?</string>\n    <plurals name=\"toast_log_truncated\">\n        <item quantity=\"one\">Journal trop grand, affichage de la %d dernière ligne.</item>\n        <item quantity=\"many\">Journal trop grand, affichage des %d dernières lignes.</item>\n        <item quantity=\"other\">Journal trop grand, affichage des %d dernières lignes.</item>\n    </plurals>\n    <string name=\"toast_invalid_selection\">Sélection invalide. Veuillez réessayer s.v.p.</string>\n    <string name=\"toast_invalid_level\">Nom de niveau invalide : %s</string>\n    <string name=\"pref_display_limit_hint\" tools:ignore=\"PluralsCandidate\">Veuillez entrer un nombre valide compris entre %1$d et %2$d.</string>\n    <string name=\"subject_log_report\">Rapports</string>\n    <string name=\"start_recording_log\">Enregistrer</string>\n    <string name=\"settings\">Paramètres</string>\n    <string name=\"send_log_title\">Envoyer le journal</string>\n    <string name=\"save_log\">Enregistrer le journal</string>\n    <string name=\"save_as\">Enregistrer sous…</string>\n    <string name=\"pref_show_timestamp_summary\">Afficher l\\'identifiant du processus et l\\'horodatage lorsque développé.</string>\n    <string name=\"pref_log_write_period_summary\" tools:ignore=\"PluralsCandidate\">Lors de l\\'enregistrement, écrire sur la carte SD toutes les %1$d lignes.</string>\n    <string name=\"pref_filter_pattern_title\">Filtrer les étiquettes</string>\n    <string name=\"pref_filter_pattern_summary\">Filtrer les étiquettes sélectionnées depuis les journaux.</string>\n    <string name=\"pref_display_limit_title\">Limite d\\'affichage des journaux</string>\n    <string name=\"pref_default_log_level_title\">Niveau de journalisation par défaut</string>\n    <string name=\"pref_default_log_level_summary\">Niveau de journalisation au démarrage, lors de l\\'ouverture , et de l\\'enregistrement de fichiers.</string>\n    <string name=\"pref_buffer_title\">Tampon(s) de journalisation</string>\n    <string name=\"open\">Ouvrir</string>\n    <string name=\"notification_title\">Enregistrement du journal en cours</string>\n    <string name=\"notification_ticker\">L\\'enregistrement du journal a démarré</string>\n    <string name=\"notification_subtext\">Touchez pour arrêter l\\'enregistrement</string>\n    <string name=\"manage_saved_logs\">Gérer les journaux sauvegardés</string>\n    <string name=\"log_saved\">Journal sauvegardé.</string>\n    <string name=\"log_recording_started\">L’enregistrement du journal a commencé.</string>\n    <string name=\"log_level\">Niveau de journalisation</string>\n    <string name=\"log_cleared\">Journaux supprimés</string>\n    <string name=\"filter_choice_pid\">PID</string>\n    <string name=\"filter_choice\">Rechercher par</string>\n    <string name=\"copy_to_clipboard\">Copier dans le presse-papier</string>\n    <plurals name=\"file_deletion_confirmation\">\n        <item quantity=\"one\">Le fichier %d sera supprimé</item>\n        <item quantity=\"many\">Les fichiers %d seront supprimés</item>\n        <item quantity=\"other\">Les fichiers %d seront supprimés</item>\n    </plurals>\n    <string name=\"add_filter_ellipsis\">Ajout de filtre…</string>\n    <string name=\"add_filter\">Ajouter un filtre</string>\n    <string name=\"log_level_fatal\">Fatal</string>\n    <string name=\"log_level_info\">Information</string>\n    <string name=\"log_level_error\">Erreur</string>\n    <string name=\"log_level_debug\">Déboguer</string>\n    <string name=\"log_viewer\">Visualiseur de journaux</string>\n    <string name=\"import_from_tb\">Importer depuis Titanium Backup</string>\n    <string name=\"import_from_oab\">Importer depuis OAndBackup</string>\n    <string name=\"pref_import_backups_msg\">Importer les sauvegardes depuis OAndBackup, Swift Backup (3.0–3.2) ou Titanium Backup.</string>\n    <string name=\"pref_import_backups\">Importer les sauvegardes</string>\n    <string name=\"orientation_user_portrait\">Mode portrait</string>\n    <string name=\"failed_to_uninstall_app\">La désinstallation a échoué</string>\n    <string name=\"toggle_default_app_ops\">Basculer vers les opérations d\\'application par défaut</string>\n    <string name=\"state_session_leader\">Chef de session</string>\n    <string name=\"second_degree_tracker_note\">Le préfixe ² indique que les trackers sont dans la <a href=\"https://etip.exodus-privacy.eu.org/\">liste d\\'attente ETIP</a>, c\\'est-à-dire qu\\'il s\\'agit toujours de trackers réels.</string>\n    <plurals name=\"no_of_splits\">\n        <item quantity=\"one\">%1$d division</item>\n        <item quantity=\"many\">%1$d divisions</item>\n        <item quantity=\"other\">%1$d divisions</item>\n    </plurals>\n    <string name=\"launch_mode_single_top\">Partie supérieure</string>\n    <string name=\"orientation_user_landscape\">Mode paysage</string>\n    <string name=\"orientation_sensor_portrait\">Capteur mode portrait</string>\n    <string name=\"state_wake_kill\">Désactiver le réveil</string>\n    <string name=\"systemless_app\">Appli sans système</string>\n    <string name=\"source_stamp_verified\">Timbre source vérifié.</string>\n    <string name=\"no_app_ops_permission\">Pas de permission pour afficher les opérations d\\'application</string>\n    <string name=\"app_signing_signature_schemes\">Schémas de signature</string>\n    <string name=\"pref_backup_android_keystore\">Sauvegarder les applications avec le magasin de clés Android</string>\n    <string name=\"set_app_op_mode\">Définir le mode d\\'opération d\\'application</string>\n    <string name=\"filter_apps_with_splits\">Avec séparateurs</string>\n    <string name=\"matching_activities\">Activités correspondantes</string>\n    <string name=\"screen\">Écran</string>\n    <string name=\"failed_to_disable_magisk_hide\">Impossible de désactiver MagiskHide</string>\n    <string name=\"enforcing\">Forcer</string>\n    <string name=\"backup_multiple_description\">Créer une sauvegarde séparée <i>nommée</i> à la place de la sauvegarde de base.</string>\n    <string name=\"backup_skip_signature_checks_description\">Restaurer les sauvegardes qui ont échoué au test de somme de contrôle ou qui ont des signatures d\\'APK différentes par rapport à leur précédente sauvegarde.</string>\n    <string name=\"patch_level\">Niveau de correctif</string>\n    <string name=\"scaling_factor\">Facteur d\\'échelonnage</string>\n    <string name=\"set_custom_app_op\">Définir une opération d\\'application personnalisée</string>\n    <string name=\"set_mode_for_app_ops_dots\">Définir le mode pour les opérations d\\'application…</string>\n    <string name=\"permissive\">Facultatif</string>\n    <string name=\"failed_to_enable_magisk_hide\">Impossible d\\'activer MagiskHide</string>\n    <string name=\"pref_backup_restore_msg\">Personnaliser la sauvegarder/restauration.</string>\n    <string name=\"backup_volume\">Volume de sauvegarde</string>\n    <string name=\"pref_backup_volume_msg\">Sélectionnez le volume ou le disque où sauvegarder.</string>\n    <string name=\"unencrypted\">Non chiffré</string>\n    <string name=\"encrypted\">Chiffré</string>\n    <string name=\"backup_custom_users\">Utilisateurs personnalisés</string>\n    <string name=\"backup_custom_users_description\">N\\'effectuer les sauvegardes que pour les utilisateurs spécifiés</string>\n    <string name=\"no_volumes_found\">Impossible de trouver un volume avec des droits d\\'écriture.</string>\n    <string name=\"bootloader\">Chargeur de démarrage</string>\n    <string name=\"verify_and_redo_backups_msg\">Vérifiez l\\'intégrité des sauvegardes précédentes et refaites les sauvegardes pour lesquelles le contrôle d\\'intégrité a échoué.</string>\n    <string name=\"backup_apps_with_changes\">Sauvegarder les applications avec changements</string>\n    <string name=\"backup_apps_with_changes_msg\">Refaire les sauvegardes pour les applications avec des modifications depuis la dernière sauvegarde. Ceci inclus les changements de taille et de version, et la date de la dernière exécution.</string>\n    <string name=\"restore_all_msg\">Restaurer les sauvegardes de base pour toutes les applications sauvegardées.</string>\n    <string name=\"screen_lock_msg\">Verrouiller App Manager en utilisant le verrouillage d\\'écran Android</string>\n    <string name=\"no_battery_optimization\">Pas d\\'optimisation de batterie</string>\n    <string name=\"unlock_app_manager\">Déverrouiller App Manager</string>\n    <string name=\"type_null\">Pas de valeur</string>\n    <string name=\"restore_not_installed_msg\">Restaurer la sauvegarde de base pour les applications qui ne sont pas actuellement installées.</string>\n    <string name=\"battery_optimization\">Optimisation de batterie</string>\n    <string name=\"has_net_policy\">Politique réseau</string>\n    <string name=\"net_policy\">politique réseau</string>\n    <string name=\"ssaid_info\">SSAID (<tt>Settings.Secure.ANDROID_ID</tt>) est un identifiant d\\'appareil attribué à chaque application (à partir d\\'Android 8 \\\"Oreo\\\"). Il est largement utilisé par les applications pour pister les utilisateurs.</string>\n    <string name=\"copied_to_clipboard\">Copier vers le presse-papier.</string>\n    <string name=\"restart_to_reflect_changes\">Vous devez redémarrer l\\'appareil immédiatement pour profiter des modifications récentes.</string>\n    <string name=\"isolated\">Isolé</string>\n    <string name=\"screen_lock_not_enabled\">Veuillez choisir un écran de verrouillage dans les paramètres Android, ou effacer les données de cette application.</string>\n    <string name=\"specify_custom_name\">Personnalisé</string>\n    <string name=\"installer_app_message\">Sélectionnez <b>Choisir</b> pour choisir depuis les applications installées, ou sélectionnez <b>Personnaliser</b> pour définir le nom de paquet à utiliser.</string>\n    <string name=\"input_key\">Touche de saisie (en hexadécimal)</string>\n    <string name=\"failed_to_initialize_key_store\">Impossible d\\'initialiser le magasin de clés de App Manager.</string>\n    <string name=\"failed_to_save_key\">La clé n\\'a pu être enregistrée.</string>\n    <string name=\"expiry_date_cannot_be_empty\">La date d\\'expiration ne peut être vide.</string>\n    <string name=\"failed_to_read_keystore\">Impossible de lire le magasin de clés.</string>\n    <string name=\"enter_good_filename\">Veuillez saisir un nom de fichier valide.</string>\n    <string name=\"pref_always_on_background\">Installation en arrière-plan</string>\n    <string name=\"found_no_alias_in_keystore\">Aucun alias trouvé dans le magasin de clés !</string>\n    <string name=\"keystore_pass_cannot_be_empty\">Le mot de passe KeyStore ne peut être vide.</string>\n    <string name=\"trim_caches_in_all_apps\">Réduire le cache de toutes les applications</string>\n    <string name=\"pref_rules_msg\">Blocage instantané, importer/exporter/supprimer des règles, etc.</string>\n    <string name=\"pref_expanded_by_default_summary\">Afficher le texte complet du journal par défaut.</string>\n    <string name=\"pref_installer_msg\">Configurer le comportement de l\\'installeur d\\'application.</string>\n    <string name=\"common_name\">Nom Commun (Common Name)</string>\n    <string name=\"organization_unit\">Unité d\\'organisation (Organization Unit)</string>\n    <string name=\"organization_name\">Nom de l\\'organisation (O)</string>\n    <string name=\"crypto_key_size\">Taille de la clé</string>\n    <string name=\"import_from_sb\">Importer depuis Swift Backup 3.0 – 3.2</string>\n    <string name=\"java\">Java</string>\n    <string name=\"smali\">Smali</string>\n    <string name=\"explore\">Explorer</string>\n    <string name=\"exit_confirmation\">Confirmation pour quitter</string>\n    <string name=\"extract\">Extraire</string>\n    <string name=\"replace\">Remplacer</string>\n    <string name=\"rename\">Renommer</string>\n    <string name=\"locality_name\">Nom de la localité (ville) (L)</string>\n    <string name=\"state_name\">Nom de la région (ST)</string>\n    <string name=\"filename\">Nom du fichier</string>\n    <string name=\"keystore_pass\">Mot de passe du magasin de clés</string>\n    <string name=\"keystore_file\">Fichier de magasin de clés</string>\n    <string name=\"signing_key\">Clé de signature</string>\n    <string name=\"log_level_verbose\">Détaillé</string>\n    <string name=\"country_name\" tools:ignore=\"TypographyOther\">Nom du Pays (C)</string>\n    <string name=\"restart_log_viewer_to_see_changes\">Redémarrer la fenêtre du visualiseur de journaux pour voir les changements.</string>\n    <string name=\"delete_saved_log\">Supprimer les journaux sauvegardés</string>\n    <string name=\"log_level_warn\">Avertissement</string>\n    <string name=\"dialog_compiling_log\">Compilation du journal …</string>\n    <string name=\"enter_filename\">Entrez le nom du fichier</string>\n    <string name=\"filter_choice_tag\">Étiquette</string>\n    <string name=\"no_saved_logs\">Aucun journal sauvegardé.</string>\n    <string name=\"pref_cat_configuration\">Configuration</string>\n    <string name=\"pref_display_limit_summary\" tools:ignore=\"PluralsCandidate\">N\\'afficher que les %1$d derniers journaux pour éviter la saturation de la mémoire.</string>\n    <string name=\"pref_cat_appearance\">Apparence</string>\n    <string name=\"pref_cat_advanced\">Avancé</string>\n    <string name=\"pref_expanded_by_default_title\">Développer par défaut</string>\n    <string name=\"pref_log_line_period_error\">Veuillez entrer un entier compris entre 1 et 1000.</string>\n    <string name=\"pref_log_write_period_title\">Fréquence d\\'écriture</string>\n    <string name=\"collapse_all\">Tout réduire</string>\n    <string name=\"text_include_dmesg\">Inclure le journal du noyau</string>\n    <string name=\"pref_show_timestamp_title\">Afficher le Pid &amp; l\\'horodatage</string>\n    <string name=\"text_filter_ellipsis\">Filtre…</string>\n    <string name=\"text_filter_text\">Filtrer le texte</string>\n    <string name=\"suspended\">Interrompu</string>\n    <string name=\"orientation_follow_locale\">Suivre les paramètres régionaux</string>\n    <string name=\"pref_display_changes\">Afficher les modifications</string>\n    <string name=\"saf\">SAF</string>\n    <string name=\"pref_display_changes_msg\">Afficher les changements de version, pisteurs, composants, permissions, signatures, SDK, etc. par version.</string>\n    <string name=\"no_changes\">Pas de changements</string>\n    <string name=\"wireless_debugging\">Débogage sans fil</string>\n    <string name=\"help_app_ops_tab\">Cliquez sur un élément pour <b>l\\'autoriser</b> ou <b>l\\'ignorer</b>. Cliquez longuement sur un élément pour voir les autres modes supportés.</string>\n    <string name=\"failed_to_prevent_background_run\">Impossible d\\'empêcher %1$s de s\\'exécuter en arrière-plan</string>\n    <string name=\"permission_flags\">Indicateurs d\\'autorisation</string>\n    <string name=\"added_to_queue\">Ajouté à la file d\\'attente</string>\n    <string name=\"help_uses_permissions_tab\">Cliquez sur un élément pour <b>l\\'accorder</b> ou <b>le révoquer</b>. Seules les permissions <b>dangereuses</b> et <b>développement</b> peuvent être accordées ou révoquées.</string>\n    <string name=\"notice_saf\">Contrairement aux volumes, le répertoire sélectionné sera utilisé pour stocker tous les fichiers en relation avec App Manager, y compris les APK enregistrés et les sauvegardes. Le Storage Access Framework (SAF) étant très lent, ne l\\'utilisez qu\\'en dernier recours.</string>\n    <string name=\"backup_volume_dialog_description\">Les volumes avec le préfixe <tt>/tree</tt> sont des dossiers sélectionnés à l\\'aide de Storage Access Framework (SAF). À l\\'exception de ces dossiers, le répertoire par défaut d\\'App Manager est un sous-dossier nommé <tt>AppManager</tt>.</string>\n    <string name=\"keystore_password_info\">Ceci est le mot de passe du KeyStore. Veillez à le stocker dans un endroit sûr si vous souhaitez sauvegarder/restaurer le KeyStore depuis App Manager. <b>Ce message ne s\\'affichera plus.</b></string>\n    <string name=\"adb_pair\">Appairer</string>\n    <string name=\"identifier\">Identifiant</string>\n    <string name=\"set_package_name_first\">Veuillez définir le nom du package d\\'abord !</string>\n    <string name=\"user_root\">Administrateur Racine</string>\n    <string name=\"trim_caches_in_all_apps_description\">Supprime les fichiers de cache de toutes les applications ainsi que du système Android</string>\n    <string name=\"background\">Arrière-plan</string>\n    <string name=\"staging_apk_files\">Préparation…</string>\n    <string name=\"pref_block_trackers_msg\">Bloquer les pisteurs dès l\\'installation d\\'une application depuis App Manager.</string>\n    <string name=\"pref_always_on_background_msg\">Toujours installer les applications en arrière-plan et afficher une notification quand terminé.</string>\n    <string name=\"type_uri_array\">Liste d\\'URL</string>\n    <string name=\"type_uri_array_list\">Liste d\\'URLs</string>\n    <string name=\"pref_thread_count\">Exécution en parallèle</string>\n    <string name=\"pref_thread_count_hint\">La valeur doit être comprise entre 0 et %1$d ; si 0, cela correspond au <i>nombre maximum d\\'opérations à un instant donné</i>.</string>\n    <plurals name=\"pref_thread_count_msg\">\n        <item quantity=\"one\">Exécuter au plus %1$d opération en parallèle</item>\n        <item quantity=\"many\">Exécuter au plus %1$d opérations en parallèle</item>\n        <item quantity=\"other\">Exécuter au plus %1$d opérations en parallèle</item>\n    </plurals>\n    <string name=\"pid\">Identifiant du processus</string>\n    <string name=\"running_services_logcat_hint\">Cliquez sur un élément pour ouvrir la visionneuse de journaux avec par défaut le filtrage activé à partir de cet identifiant de processus.</string>\n    <string name=\"pref_import_backups_hint\">Choisissez un dossier contenant les fichiers (pour Swift Backup ou Titanium Backup) ou les dossiers (pour OAndBackup) de sauvegarde</string>\n    <string name=\"system_partition\">Administrateur d\\'Android</string>\n    <string name=\"send_edited_intent\">Envoyer l\\'intention modifiée</string>\n    <string name=\"accessibility_service_description\">Le service d\\'accessibilité générique pour gérer certaines opérations comme le vidage du cache en mode non administrateur.</string>\n    <string name=\"search_type_regular_expressions\">Expression régulière</string>\n    <string name=\"pref_default_blocking_method\">Méthode de blocage par défaut</string>\n    <string name=\"search_type_contains\">Contient</string>\n    <string name=\"search_type_suffix\">Suffixe</string>\n    <string name=\"search_type_prefix\">Préfixe</string>\n    <string name=\"authenticating\">Authentification…</string>\n    <string name=\"pref_default_blocking_method_description\">Méthode à utiliser par défaut dans les endroits où il n\\'y a pas d\\'option pour sélectionner une méthode de blocage.\\n<b>Note :</b> \\\"IFW\\\" ne fonctionne pas avec les fournisseurs, \\\"désactiver\\\" est utilisé à la place.</string>\n    <string name=\"toggle_internet\">Utiliser Internet</string>\n    <string name=\"vt_checking\">VirusTotal : Vérification…</string>\n    <string name=\"vt_uploading\">VirusTotal : Envoi en cours…</string>\n    <string name=\"vt_queued\">VirusTotal : En attente</string>\n    <string name=\"vt_failed\">VirusTotal : Échec</string>\n    <string name=\"vt_success\">VirusTotal : %1$d/%2$d</string>\n    <string name=\"vt_scan_date\">Date d\\'analyse : %1$s</string>\n    <string name=\"vt_permalink\">Lien permanent vers VirusTotal</string>\n    <string name=\"vt_disclaimer\">VirusTotal et ses logos sont une marque déposée de Chronicle LLC. Ni App Manager, le client de l\\'API, ni ses auteurs ne sont responsables des données que vous pouvez envoyer à VirusTotal.</string>\n    <string name=\"pref_vt_apikey\">Clé d\\'API de VirusTotal</string>\n    <string name=\"pref_vt_apikey_description\">Une clé d\\'API permet à App Manager de télécharger des fichiers APK vers VirusTotal et de récupérer des rapports. Inscrivez-vous sur https://virustotal.com pour obtenir une clé d\\'API gratuitement.</string>\n    <string name=\"pref_vt_apikey_summary\">Activer l\\'analyse des fichiers APK via VirusTotal.</string>\n    <string name=\"uses_play_app_signing\">Connexion à Google Play</string>\n    <string name=\"scan_in_vt\">Analyser sur VirusTotal</string>\n    <string name=\"process_id\">Identifiant du processus</string>\n    <string name=\"virtual_memory\">Mémoire virtuelle</string>\n    <string name=\"cpu_percent\">%% CPU</string>\n    <string name=\"priority\">Priorité</string>\n    <string name=\"memory_chart_info\">● %1$s Applications ● %2$s Cache ● %3$s Mémoire tampon ● %4$s Libre</string>\n    <string name=\"swap_chart_info\">● %1$s Utilisé ● %2$s Libre</string>\n    <string name=\"magisk_denylist\">Magisk DenyList</string>\n    <string name=\"failed_to_enable_magisk_deny_list\">Impossible d\\'activer Magisk DenyList</string>\n    <string name=\"swap\">Échange</string>\n    <plurals name=\"usage_minutes\">\n        <item quantity=\"one\">%1$d min</item>\n        <item quantity=\"many\">%1$d mins</item>\n        <item quantity=\"other\">%1$d mins</item>\n    </plurals>\n    <plurals name=\"usage_seconds\">\n        <item quantity=\"one\">%1$d sec</item>\n        <item quantity=\"many\">%1$d secs</item>\n        <item quantity=\"other\">%1$d secs</item>\n    </plurals>\n    <string name=\"vt_slowness_warning\">En fonction de la vitesse de connexion Internet et de la charge du serveur, ceci peut prendre un moment.</string>\n    <string name=\"uses_play_app_signing_description\">Cette application contient certains marqueurs qui indiquent qu\\'elle <i>pourrait</i> utiliser le système de <a href=\"https://support.google.com/googleplay/android-developer/answer/9842756\">connexion à Google Play</a>. Avec ce système, les clés de signature sont stockées sur les serveurs de Google, qui est responsable de la signature de l\\'application. Notez que la correspondance des informations de signature est le seul moyen de vérifier que l\\'application n\\'a pas été modifiée par une tierce personne à l\\'exception du développeur (et dans ce cas, de Google également).</string>\n    <string name=\"cpu_time\">Heure du CPU</string>\n    <string name=\"parent_process_id\">Identifiant du processus parent</string>\n    <string name=\"threads\">Nombre de fils</string>\n    <string name=\"state\">État du processus</string>\n    <string name=\"commandline_args\">Arguments en ligne de commande</string>\n    <string name=\"failed_to_disable_magisk_deny_list\">Impossible de désactiver Magisk DenyList</string>\n    <string name=\"intent_firewall\">IFW</string>\n    <string name=\"intent_firewall_and_disable\">IFW + désactiver</string>\n    <string name=\"pref_intent_firewall_and_disable_description\">Bloquez les composants à l\\'aide du pare-feu intentionnel et désactivez-les. Méthode recommandée pour les utilisateurs root.</string>\n    <string name=\"failed_to_change_app_op_mode\">Impossible de changer le mode de fonctionnement de l\\'application.</string>\n    <string name=\"pref_intent_firewall_description\">Bloquer les composants en utilisant uniquement le pare-feu Intent. Non recommandé car certaines applications système peuvent contourner les pare-feu.</string>\n    <string name=\"pref_disable_description\">Désactivez uniquement les composants. Non recommandé pour les utilisateurs root car les applications peuvent contourner cette méthode. Dans les modes ADB, les applications de test uniquement peuvent être désactivées avec cette méthode.</string>\n    <string name=\"tracker\">Traqueur</string>\n    <string name=\"shortcut_icon\">Icône du raccourci</string>\n    <string name=\"sort_by_installation_date\">Date d\\'installation</string>\n    <string name=\"vt_confirm_upload_and_scan\">Oui, envoyer et scanner</string>\n    <string name=\"binary_32_bit\">32 bits</string>\n    <string name=\"binary_64_bit\">64 bits</string>\n    <string name=\"so_type_shared_library\">Bibliothèque partagée</string>\n    <string name=\"external\">Externe</string>\n    <string name=\"item_select\">Sélectionner</string>\n    <string name=\"change_backup_volume\">Changer le volume</string>\n    <string name=\"screen_time\">Temps à l\\'écran</string>\n    <string name=\"open_in_new_window\">Nouvelle fenêtre</string>\n    <string name=\"log_stop_recording\">Arrêter l\\'enregistrement</string>\n    <string name=\"so_type_executable\">Exécutable</string>\n    <string name=\"save_and_exit\">Enregistrer et quitter</string>\n    <string name=\"internal\">Interne</string>\n    <string name=\"app_explorer\">Explorateur d\\'applications</string>\n    <string name=\"pref_saved_apk_name_format\">Nom du format de l\\'APK enregistré</string>\n    <string name=\"warning_working_on_root_mode\">Avertissement : Travail en mode racine au lieu du mode ADB.</string>\n    <string name=\"hidden_api_enf_policy_none\">Aucun (accès total à l\\'API cachée)</string>\n    <string name=\"hidden_api_enf_policy_warn\">Attention (accès total à l\\'API cachée mais avec des avertissements)</string>\n    <string name=\"failed_to_use_the_current_mode_of_operation\">Impossible d\\'utiliser le mode d\\'opération actuel. Retour au mode non racine pour cette session.</string>\n    <string name=\"mode_of_op_with_inferred_mode_of_op\">%1$s (Mode déduit : %2$s)</string>\n    <string name=\"zygote_preload_name\">Nom du préchargement de Zygote</string>\n    <string name=\"hidden_api_enf_default_policy\">Par défaut (basé sur le type d\\'application)</string>\n    <string name=\"file_modified_are_you_sure\">Le fichier a été modifié. Voulez-vous annuler toutes vos modifications et quitter \\?</string>\n    <string name=\"primary_abi\">ABI primaire</string>\n    <string name=\"pref_saved_apk_name_format_msg\">Le format à utiliser pour nommer les fichiers APK lorsque vous les enregistrez.</string>\n    <string name=\"open_developer_options_page\">Ouvrir la page des options de développeur dans les préférences Android</string>\n    <string name=\"vt_confirm_uploading_file\">Ce fichier n\\'a pas été trouvé dans la base VirusTotal. Voulez-vous l\\'envoyer \\?</string>\n    <string name=\"pref_vt_prompt_before_uploading\">Afficher une confirmation avec l\\'envoyer un fichier.</string>\n    <string name=\"pref_pure_black_theme_msg\">Utilise un arrière-plan complètement noir quand le thème sombre est actif.</string>\n    <string name=\"pref_pure_black_theme\">Thème noir pur</string>\n    <string name=\"apk_checksums\">Checksums de l\\'APK</string>\n    <string name=\"regenerate_auth_key\">Regénérer la clé d\\'autorisation</string>\n    <string name=\"hidden_api_enf_policy_dark_grey_and_black\">Impose (listes gris foncé et noire)</string>\n    <string name=\"backup_volume_unavailable_warning\">Le volume de sauvegarde sélectionné n\\'est pas disponible actuellement. S\\'il est dans un stockage externe, veuillez insérer celui-ci, ou changer de volume de sauvegarde.</string>\n    <string name=\"type_string_set\">Ensemble de chaines de caractères</string>\n    <string name=\"regenerate_auth_key_warning\">Êtes-vous sûr \\? Toutes les applications tiers doivent être reconfigurées avec la nouvelle clé d\\'authentification.</string>\n    <string name=\"auth_manager_title\">Gestionnaire d\\'autorisation</string>\n    <string name=\"hidden_api_enf_policy_black\">Impose (liste noire seulement)</string>\n    <string name=\"input_ssaid_instruction\">Le SSAID est un nombre hexadécimal de %1$d octets, c\\'est-à-dire une chaine de %2$d caractères uniquement de 0 à 9 et de a à f.</string>\n    <string name=\"auth_manager_description\">Pour lancer un Intent depuis une application externe, il est nécessaire de fournir un champ supplémentaire nommé <tt>auth</tt>, qui doit contenir les clés suivantes :</string>\n    <string name=\"frozen\">Gelé</string>\n    <string name=\"freeze\">Geler</string>\n    <string name=\"unfreeze\">Dégeler</string>\n    <string name=\"backup_no_backups_present\">Pas de sauvegarde.</string>\n    <string name=\"restore_dots\">Restaurer…</string>\n    <string name=\"backup_apps_cannot_be_restored\">Les applications suivantes ne peuvent pas être restaurées car elles n\\'ont pas de sauvegarde de base :</string>\n    <string name=\"backup_apps_cannot_be_backed_up\">Les applications suivantes ne sont pas installées et ne peuvent pas être sauvegardées :</string>\n    <string name=\"restart_device\">Redémarrez votre appareil</string>\n    <string name=\"import_backups_warning_delete_backups_after_import\">Supprimer les sauvegardes après les avoir importées dans App Manager \\? Chaque sauvegarde est supprimée individuellement après avoir été importée avec succès. Sélectionnez <b>Non</b> en cas de doute.</string>\n    <string name=\"endianness_big_endian\">Big endian (Gros-boutiste)</string>\n    <string name=\"hidden_api_enforcement_policy\">Politique d\\'application de l\\'API masquée</string>\n    <string name=\"endianness_little_endian\">Little endian (Petit boutiste)</string>\n    <string name=\"netpolicy_cannot_be_modified_for_core_apps\">La stratégie réseau ne peut pas être modifiée pour les applications principales d\\'Android.</string>\n    <string name=\"usage_last_used\">Dernière utilisation</string>\n    <string name=\"usage_mobile_data\">Données mobiles</string>\n    <string name=\"usage_wifi_data\">Données Wi-Fi</string>\n    <string name=\"usage_times_opened\">Nombre d\\'ouvertures</string>\n    <string name=\"pref_reload_apps\">Recharger les applications</string>\n    <string name=\"troubleshooting\">Problèmes</string>\n    <string name=\"changelog_type_improve\">Amélioré</string>\n    <string name=\"pref_reload_apps_msg\">Recharge la liste des applications enregistrées dans la base du Gestionnaire d\\'Applications en cas de comportement inattendu.</string>\n    <string name=\"changelog_type_new\">Nouveau</string>\n    <string name=\"changelog_type_fix\">Corrigé</string>\n    <string name=\"unsupported_split_apk\">Non pris en charge</string>\n    <string name=\"view_changelog\">Découvrez les nouveautés</string>\n    <string name=\"sort_by_total_size\">Taille totale</string>\n    <string name=\"pref_sign_apk_error_signing_key_not_added\">Une clé de signature valide est nécessaire pour signer un fichier APK.</string>\n    <string name=\"pref_sign_apk_no_signing_key\">Aucune clé de signature</string>\n    <string name=\"am_command\">Commande <tt>am</tt></string>\n    <string name=\"hide_app\">Masquer</string>\n    <string name=\"user_manual\">Manuel utilisateur</string>\n    <string name=\"get_help\">Obtenir de l\\'aide</string>\n    <string name=\"pref_privacy\">Confidentialité</string>\n    <string name=\"pref_version_changelog\">Version/Journal des modifications</string>\n    <string name=\"freeze_unfreeze\">Geler/dégeler</string>\n    <string name=\"pref_default_freezing_method_description\">Méthode à utiliser par défaut dans les endroits où il n\\'y a pas d\\'option pour sélectionner une méthode de congélation.</string>\n    <string name=\"suspend_app\">Suspendre</string>\n    <plurals name=\"alert_failed_to_freeze\">\n        <item quantity=\"one\">Impossible de geler l\\'appli %1$d</item>\n        <item quantity=\"many\">Impossible de geler les applis %1$d</item>\n        <item quantity=\"other\">Impossible de geler les applis %1$d</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_unfreeze\">\n        <item quantity=\"one\">Impossible de dégeler l\\'appli %1$d</item>\n        <item quantity=\"many\">Impossible de dégeler les applis %1$d</item>\n        <item quantity=\"other\">Impossible de dégeler les applis %1$d</item>\n    </plurals>\n    <string name=\"suspend_app_description\">C\\'est la méthode de congélation la plus faible. Une application suspendue peut toujours apparaître dans le lanceur mais sera grisée et ne pourra pas être lancée.</string>\n    <string name=\"disable_app_description\">Méthode de congélation recommandée. Il désactive l\\'application et ainsi que tous ses composants, mais tous les raccourcis seront perdus.</string>\n    <string name=\"hide_app_description\">Cette méthode n\\'est recommandée que pour une utilisation quotidienne. Une application masquée apparaît comme si elle était désinstallée. Mais l\\'application peut réapparaître si elle est réinstallée ou mise à jour.</string>\n    <string name=\"sort_by_frozen_app\">Gelé en premier</string>\n    <string name=\"filter_frozen_apps\">Applications gelées</string>\n    <string name=\"pref_appearance_description\">Thème, orientation, fonctionnalités, etc.</string>\n    <string name=\"pref_privacy_description\">Verrouillage de l\\'écran, autorisation, etc.</string>\n    <string name=\"pref_advanced_pref\">Utilisateurs, format de nom APK, exécution parallèle, etc.</string>\n    <string name=\"failed_to_freeze\">Impossible de geler <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g>.</string>\n    <string name=\"failed_to_unfreeze\">Impossible de dégeler <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g>.</string>\n    <string name=\"profile_freeze_msg\">Gèle ou dégèle les applis en fonction de leur état</string>\n    <string name=\"pref_default_freezing_method\">Méthode de gel par défaut</string>\n    <string name=\"file_creation_date\">Crée</string>\n    <string name=\"file_modification_date\">Modifiée</string>\n    <string name=\"file_open_with\">Ouvrir avec</string>\n    <string name=\"file_change_open_with\">Changer \\\"Ouvrir avec\\\"</string>\n    <string name=\"file_shortcut_target_file\">Fichier cible</string>\n    <string name=\"file_properties\">Propriétés</string>\n    <string name=\"file_cut\">Couper</string>\n    <string name=\"fm_always_open_with\">Toujours ouvrir</string>\n    <string name=\"fm_open_with_for_this_file_only\">Uniquement pour ce fichier</string>\n    <string name=\"file_open_as\">Ouvert en tant que…</string>\n    <string name=\"file_open_with_custom_activity\">Personnalisé</string>\n    <string name=\"file_accessed_date\">Accédé</string>\n    <string name=\"file_open_with_os_default_dialog\">Ouvrir avec la boîte de dialogue par défaut du système d\\'exploitation</string>\n    <string name=\"open_as_text\">Texte</string>\n    <string name=\"open_as_image\">Image</string>\n    <string name=\"open_as_video\">Vidéo</string>\n    <string name=\"open_as_other\">Autres</string>\n    <string name=\"delete_filename\">Supprimer %s</string>\n    <string name=\"confirm_file_deletion\">Oui, supprimer</string>\n    <string name=\"on_unfreeze_open_application\">Ouvrir l\\'app après le déblocage</string>\n    <string name=\"open_as_archive\">Archives</string>\n    <string name=\"open_as_folder\">Dossier</string>\n    <string name=\"on_open_application_no_recents\">Ne pas afficher l\\'application lancée dans Récents</string>\n    <string name=\"freeze_on_phone_locked\">Geler automatiquement l\\'application lorsque le téléphone est verrouillé</string>\n    <string name=\"tap_to_freeze_app\">Appuyez pour geler</string>\n    <string name=\"waiting_for_the_phone_to_be_locked\">En attente que le téléphone soit verrouillé…</string>\n    <string name=\"action_stop_service\">Arrêter</string>\n    <string name=\"unix_file_permissions\">Mode</string>\n    <string name=\"renamed_successfully\">Renommé</string>\n    <string name=\"selinux_context\">Contexte de SELinux</string>\n    <string name=\"block_unblock_components_dots\">Bloquer ou débloquer des composants…</string>\n    <string name=\"unblock_components_dots\">Débloquer des composants…</string>\n    <string name=\"block_unblock_components_description\">Bloquer ou débloquer tous les composants identifiés par la même signature</string>\n    <string name=\"uninstall_app\">Désinstaller %1$s</string>\n    <string name=\"debloat_list_type\">Liste</string>\n    <string name=\"debloat_removal_type\">Type</string>\n    <string name=\"system_app_put_back\">Remettre</string>\n    <string name=\"debloater_title\">Débloqueur</string>\n    <string name=\"debloat_list_aosp\">AOSP</string>\n    <string name=\"debloat_list_oem\">Fabricant</string>\n    <string name=\"debloat_list_carrier\">Opérateur/FAI</string>\n    <string name=\"debloat_list_google\">Google</string>\n    <string name=\"debloat_list_misc\">Recueil</string>\n    <string name=\"debloat_removal_safe\">Sécurisé</string>\n    <string name=\"debloat_removal_replace\">Remplacer</string>\n    <string name=\"debloat_removal_caution\">Attention</string>\n    <string name=\"source_stamp_verified_and_identified_to_be_from_source\">Le SourceStamp est vérifié et provient de <xliff:g id=\"source\" example=\"Google Play\">%1$s</xliff:g>.</string>\n    <string name=\"app_manager_build_expiring_soon_warning\">Cette version d\\'App Manager expire bientôt. Veuillez installer la version la plus récente.</string>\n    <string name=\"app_manager_build_expired\">Mise à jour requise</string>\n    <string name=\"file_group_id\">Groupe (GID)</string>\n    <string name=\"file_owner_id\">Propriétaire (UID)</string>\n    <plurals name=\"alert_failed_to_unblock_components\">\n        <item quantity=\"one\">Impossible de débloquer les composants pour %1$d application</item>\n        <item quantity=\"many\">Impossible de débloquer les composants pour %1$d applications</item>\n        <item quantity=\"other\">Impossible de débloquer les composants pour %1$d applications</item>\n    </plurals>\n    <string name=\"app_can_write_and_execute_in_same_place\">Cette application enfreint la <a href=\"https://en.wikipedia.org/wiki/W%5EX\">politique W^X</a> et peut écrire et exécuter dans le même dossier ou la même partie de mémoire. Ceci autorise l\\'exécution d\\'exécutables arbitraires soit par la modification des exécutables inclus dans l\\'application ou en les téléchargeant depuis Internet. Sauf si c\\'est le comportement attendu de l\\'application (ex. émulateurs de terminal), il est recommendé de trouver une version plus récente de l\\'application prévue pour SDK 29 (Android 10) et ultérieur, ou de trouver des alternatives.</string>\n    <string name=\"app_manager_build_expired_message\">Pour assurer la sécurité de votre appareil et de vos données, la version d\\'App Manager que vous utilisez est arrivée à expiration. Vous devez installer la version la plus récente pour continuer à l\\'utiliser, ou désinstaller cette version si aucune autre n\\'est disponible.</string>\n    <string name=\"static_shared_library\">Librairie statique partagée</string>\n    <string name=\"uninstall_app_again_message\">Cette application a été désinstallée sans que les données et la signature soient supprimées. Souhaitez vous la désinstaller complètement \\?</string>\n    <string name=\"sort_by_filename\">Nom</string>\n    <string name=\"install_for_another_user\">Installer pour…</string>\n    <string name=\"title_labs_activity\">Laboratoire</string>\n    <string name=\"action_continue\">Continuer</string>\n    <string name=\"sort_by_file_size\">Taille du fichier</string>\n    <string name=\"filter_apps_with_keystore\">Avec KeyStore</string>\n    <string name=\"filter_apps_with_saf\">Avec SAF</string>\n    <string name=\"title_terminal_emulator\">Terminal</string>\n    <string name=\"optimize_option_check_profiles\">Tenir compte des données de profil lors de l\\'optimisation DEX</string>\n    <string name=\"title_perform_runtime_optimization_to_apps\">Effectuer l\\'optimisation de l\\'exécution</string>\n    <string name=\"batch_ops_runtime_optimization\">Optimisation du temps d\\'exécution</string>\n    <string name=\"app_info_tag_open_links\">Ouvrir liens</string>\n    <string name=\"title_domains_supported_by_the_app\">Domaines pris en charge</string>\n    <string name=\"pref_zip_align\">Aligner les fichiers APK</string>\n    <string name=\"redo\">Refaire</string>\n    <string name=\"read_only_file\">Fichier en lecture seule</string>\n    <string name=\"action_replace_all\">Tout remplacer</string>\n    <string name=\"search_option_match_case\">Cas de correspondance</string>\n    <string name=\"search_option_whole_word\">Mot entier</string>\n    <string name=\"search_option_regex\">Expression régulière</string>\n    <string name=\"empty_folder\">Vide</string>\n    <string name=\"backing_up_app\">Sauvegarde à %1$s…</string>\n    <string name=\"restoring_app\">Restauration à %1$s…</string>\n    <string name=\"symbolic_link\">Lien symbolique</string>\n    <string name=\"create_new_symbolic_link\">Nouveau lien symbolique</string>\n    <string name=\"symbolic_link_not_supported\">Ce dossier ne prend pas en charge la création d\\'un lien symbolique.</string>\n    <string name=\"invalid_target_path\">Chemin invalide</string>\n    <string name=\"copy_these_paths\">Chemins copiés</string>\n    <string name=\"title_confirm_deletion\">Confirmer la suppression</string>\n    <string name=\"moved_successfully\">Déplacé</string>\n    <string name=\"copied_successfully\">Copié.</string>\n    <string name=\"failed_to_delete_specified_file_after_copying\">Impossible de supprimer “%1$s” après l\\'avoir copié, probablement dû à des permissions insuffisantes.</string>\n    <string name=\"title_change_selinux_context\">Modifier le contexte de SELinux</string>\n    <string name=\"export_app_list\">Exporter une liste d\\'applications</string>\n    <string name=\"export_option_xml\">XML</string>\n    <plurals name=\"search_results\">\n        <item quantity=\"one\">%d résultat</item>\n        <item quantity=\"many\">%d résultats</item>\n        <item quantity=\"other\">%d résultats</item>\n    </plurals>\n    <string name=\"option_display_dot_files\">Fichier de points</string>\n    <string name=\"class_hierarchy\">Hiérarchie</string>\n    <string name=\"optimize_option_force_dexopt\">Effectuer immédiatement l’optimisation DEX</string>\n    <string name=\"title_code_editor\">Éditeur de code</string>\n    <string name=\"title_audio_player\">Lecteur audio</string>\n    <plurals name=\"alert_failed_to_optimize_apps\">\n        <item quantity=\"one\">Impossible d\\'optimiser l\\'application %1$d</item>\n        <item quantity=\"many\">Impossible d\\'optimiser les applications %1$d</item>\n        <item quantity=\"other\">Impossible d\\'optimiser les applications %1$d</item>\n    </plurals>\n    <string name=\"pref_enable_persistent_session_msg\">L’exécution du gestionnaire d\\'application en arrière-plan réduit le délai d’initialisation. Utile si vous utilisez fréquemment le gestionnaire d\\'application.</string>\n    <string name=\"action_checking\">Vérification…</string>\n    <string name=\"report_not_available\">Pas disponible</string>\n    <string name=\"pref_layout_direction\">Orientation de la mise en page</string>\n    <string name=\"option_display_folders_on_top\">Dossier en haut</string>\n    <string name=\"export_app_list_select_format\">Sélectionnez le format d\\'exportation de la liste des applications</string>\n    <string name=\"action_optimize_app\">Optimiser</string>\n    <string name=\"line_separator\">Séparateur de lignes</string>\n    <string name=\"pref_send_notification_to_connected_devices_msg\">Définissez s\\'il faut envoyer des notifications aux appareils connectés tels que les objets connectés qui se portent sur soi.</string>\n    <string name=\"installer_options\">Options de l\\'installateur</string>\n    <string name=\"debloat_removal_caution_short_description\">Soyez prudent</string>\n    <string name=\"pref_set_home\">Définir l\\'accueil</string>\n    <string name=\"xposed_module_info\">Informations du Module Xposed</string>\n    <string name=\"tap_to_open_notification_settings\">Appuyez pour masquer</string>\n    <string name=\"pref_enable_auto_lock\">Verrouillage automatique</string>\n    <string name=\"path_does_not_exist\">\\\"%1$s\\\" n\\'existe pas</string>\n    <string name=\"path_not_a_folder\">“%1$s” n\\'est pas un dossier</string>\n    <string name=\"pref_enable_auto_lock_msg\">Verrouiller le gestionnaire d\\'application lorsque l\\'appareil est verrouillé.</string>\n    <string name=\"optimize_option_compile_layouts\">Compiler les ressources de mise en page</string>\n    <string name=\"sort_by_data_usage\">Utilisation des données</string>\n    <string name=\"grant_overlay_permission_message\">Autoriser App Manager à afficher une fenêtre flottante au-dessus de toutes les autres fenêtres</string>\n    <string name=\"select_a_dex2oat_compiler_filter\">Filtre du compilateur <tt>dex2oat</tt></string>\n    <string name=\"optimize_option_force_compilation\">­Forcer la compilation même si cela n\\'est pas nécessaire</string>\n    <plurals name=\"folder_count\">\n        <item quantity=\"one\">%d dossier</item>\n        <item quantity=\"many\">%d dossiers</item>\n        <item quantity=\"other\">%d dossiers</item>\n    </plurals>\n    <string name=\"browse_files\">Parcourir</string>\n    <string name=\"pref_files_msg\">Configurer le gestionnaire de fichiers.</string>\n    <string name=\"module_name\">Nom du module</string>\n    <string name=\"funding_campaign_text\">Nous menons une <b>campagne de financement</b> pour App Manager pour une durée limitée. <a href=\"https://opencollective.com/app-manager#category-ABOUT\">en savoir plus…</a></string>\n    <string name=\"filter_apps_with_ssaid\">Avec SSAID</string>\n    <string name=\"warning_working_on_system_mode\">Avertissement : Travailler sur le système au lieu du mode ADB.</string>\n    <string name=\"calculating_file_size\">Calcul en cours…</string>\n    <string name=\"grant_required_permission\">Accorder l\\'autorisation requise</string>\n    <string name=\"netpolicy_reject_metered_background_data\">Rejeter les données d\\'arrière-plan sur les réseaux mesurés</string>\n    <string name=\"netpolicy_reject_metered_data\">Rejeter les données sur les réseaux payants</string>\n    <string name=\"netpolicy_allow_metered_background_data\">Autoriser les données en arrière-plan sur les réseaux limités même lorsque la sauvegarde de données est activé</string>\n    <string name=\"pref_toggle_internet_msg\">Activer les fonctionnalités Internet dans App Manager</string>\n    <string name=\"create_new_file\">Nouveau fichier</string>\n    <string name=\"sort_by_last_modified\">Dernière modification</string>\n    <string name=\"export_option_markdown\">Markdown</string>\n    <string name=\"funding_campaign_dialog_message\">Nous menons une <b>campagne de financement</b> pour App Manager pour une durée limitée. Visitez <a href=\"https://opencollective.com/app-manager#category-ABOUT\">opencollective.com/app-manager</a> pour en savoir plus sur la campagne. Cet avis ne sera plus affiché, mais vous pourrez le retrouver dans la page Paramètres pendant toute la campagne.</string>\n    <string name=\"sort_by_file_type\">Type du fichier</string>\n    <string name=\"adb_incomplete_usb_debugging_title\">Débogage USB incomplet</string>\n    <string name=\"adb_incomplete_usb_debugging_message\">Il semble que le débogage USB ne soit pas configuré correctement. Veuillez lire <a href=\"https://muntashirakon.github.io/AppManager/#subsec:enable-usb-debugging\">la documentation</a> pour connaître les étapes supplémentaires. Si vous connaissez déjà les étapes, veuillez cliquer sur « Ouvrir » pour ouvrir les options du développeur, ou cliquez sur « Fermer » pour continuer à utiliser le mode sans root.</string>\n    <string name=\"confirm_uninstallation\">Confirmer la désinstallation</string>\n    <string name=\"grant_accessibility_permission_for_tracking_window_contents\">Autorisez App Manager à utiliser la fonctionnalité d’accessibilité pour suivre le contenu de la fenêtre principale.</string>\n    <string name=\"action_run\">Exécuter</string>\n    <plurals name=\"file_count\">\n        <item quantity=\"one\">%d fichier</item>\n        <item quantity=\"many\">%d fichiers</item>\n        <item quantity=\"other\">%d fichiers</item>\n    </plurals>\n    <string name=\"optimize_option_clear_profile_data\">Effacer les données de profil précédentes</string>\n    <string name=\"title_ui_tracker\">Tracker UI</string>\n    <string name=\"summary_perform_runtime_optimization_to_apps\">Optimisez les mises en page DEX et (sous Android 10 et versions ultérieures) pour améliorer les performances des applications.</string>\n    <string name=\"pref_zip_align_msg\">L\\'alignement d\\'un fichier APK réduit son utilisation de la mémoire car les fichiers de l\\'APK sont accessibles directement sans copier les données dans la RAM. Cette étape est requise si <tt>extractNativeLibs</tt> est défini sur <tt>true</tt>.</string>\n    <string name=\"replacement_text\">Remplacement</string>\n    <string name=\"go_to_path\">Aller à…</string>\n    <string name=\"copy_this_path\">Copier le chemin</string>\n    <string name=\"filter_force_stopped_apps\">Applications arrêtées</string>\n    <string name=\"installing_package\">Installation à %1$s…</string>\n    <string name=\"pref_installer_force_dexopt_description\">Effectuez l\\'optimisation DEX immédiatement après l\\'installation de l\\'application sans attendre que le système le fasse lorsqu\\'il est inactif.</string>\n    <string name=\"folder\">Dossier</string>\n    <string name=\"create_new_folder\">Nouveau dossier</string>\n    <string name=\"enter_symbolic_link_name\">Nom du lien</string>\n    <string name=\"enter_target_path\">Chemin cible</string>\n    <string name=\"conflict_detected_while_copying_message\">Un élément nommé «%1$s» existe déjà à cet emplacement. Voulez-vous le remplacer ?</string>\n    <string name=\"change_owner_uid\">Changer de propriétaire (UID)</string>\n    <string name=\"change_mode\">Changer le mode</string>\n    <string name=\"conflict_detected_while_copying\">Conflit détecté</string>\n    <string name=\"copy_keep_both_file\">Garder les deux</string>\n    <string name=\"pref_send_notifications_to_connected_devices\">Envoyer des notifications aux appareils connectés</string>\n    <string name=\"debloat_removal_replace_short_description\">Remplacer par une alternative</string>\n    <string name=\"title_alternatives_to_bloatware\">Alternatives</string>\n    <string name=\"pref_files_display_in_launcher\">Afficher \\\"Fichiers\\\" dans la liste d\\'applications</string>\n    <string name=\"pref_files_remember_last_path\">Se souvenir du dernier chemin ouvert et de sa position</string>\n    <string name=\"title_description\">Description</string>\n    <string name=\"app_manager_is_running\">Le gestionnaire d\\'applications est en cours d\\'exécution</string>\n    <string name=\"app_manager_is_unlocked\">Le gestionnaire d\\'applications est déverrouillé</string>\n    <string name=\"action_lock_app\">Verrouiller</string>\n    <string name=\"pref_enable_persistent_session\">Exécuter App Manager en arrière-plan</string>\n    <string name=\"profile_modified_are_you_sure\">Le profil a été modifié. Annuler toutes vos modifications et quitter ?</string>\n    <string name=\"apply_profile\">Appliquer le profil \\\"%1$s\\\"</string>\n    <string name=\"choose_a_profile_state\">Sélectionnez un état de profil</string>\n    <string name=\"profile_id\">ID du profil</string>\n    <string name=\"copy_profile_id\">Copier l\\'ID du profil</string>\n    <string name=\"read_only_file_warning\">Les modifications ne peuvent pas être écrites dans le fichier, peut-être parce qu\\'il se trouve dans un volume sur lequel App Manager n\\'est pas autorisé à écrire. Voulez-vous l\\'enregistrer à un autre endroit ?</string>\n    <string name=\"change_group_gid\">Changer de groupe (GID)</string>\n    <string name=\"invalid_regex\">Expression régulière invalide !</string>\n    <string name=\"value_cannot_be_empty\">La valeur ne peut être vide !</string>\n    <string name=\"date\">Date</string>\n    <string name=\"pref_use_vt\">Utiliser VirusTotal</string>\n    <string name=\"pref_use_log_viewer\">Utiliser le Visualiseur de journaux</string>\n    <string name=\"pref_installer\">Utiliser l\\'installeur</string>\n    <string name=\"pref_cat_general\">Général</string>\n    <string name=\"status_remote_server_active\">Le serveur distant est actif</string>\n    <string name=\"status_remote_services_inactive\">Les services distants sont inactifs</string>\n    <string name=\"status_connecting\">Connexion…</string>\n    <string name=\"status_connecting_via_mode\">Connexion via %s</string>\n    <string name=\"status_not_connected_via_mode\">Connexion impossible via %s</string>\n    <string name=\"adb_pairing_searching_for_port\">Recherche en cours…</string>\n    <string name=\"adb_pairing_stop_searching\">Arrêter</string>\n    <string name=\"sensors\">Capteurs</string>\n    <string name=\"tag_sensors_disabled\">Capteurs désactivés</string>\n    <string name=\"apk_source\">Source APK</string>\n    <string name=\"mode_of_op_alternative_custom_command\">Si vous obtenez une erreur \\\"Permission refusée\\\" avec la commande ci-dessus, lancez la commande suivante à la place :</string>\n    <string name=\"scan_report_from_pithus\">Rapport Pithus</string>\n    <string name=\"launch_activity_dialog_title\">Lancement d\\'activité : action requise</string>\n    <string name=\"select_filter\">Sélectionner un filtre</string>\n    <string name=\"failed_to_copy_specified_file\">Impossible de copier \\\"%1$s\\\".</string>\n    <string name=\"apply_recursively\">Appliquer aux fichiers joints</string>\n    <string name=\"size_in_bytes\">Taille (octet)</string>\n    <string name=\"launch_activity_dialog_message\">App Manager essaie de lancer l\\'activité via l\\'<b>Assistant de recherche</b> (usuellement Google Assistant), mais n\\'y parvient pas dû à des permissions insuffisantes. Pour ouvrir l\\'activité, merci d\\'activer l\\'<b>Assistant de recherche</b> manuellement (en général via un long clic sur le bouton d\\'accueil). Cliquer sur le bouton <b>Fermer</b> lorsque vous avez fini de lancer l\\'activité pour retourner sur l\\'assistant original.</string>\n    <string name=\"pref_use_vt_no_internet\">VirusTotal a besoin d\\'accéder à Internet, ce qui n\\'est pas le cas. Merci d\\'activer <a href=\"app-manager://settings/privacy_prefs/toggle_internet\">Utiliser Internet</a> d\\'abord.</string>\n    <string name=\"status_remote_server_inactive\">Le serveur distant est inactif</string>\n    <string name=\"status_remote_services_active\">Les services distants sont actifs</string>\n    <string name=\"status_connected_via_mode\">Connecté via %s</string>\n    <string name=\"adb_pairing_pairing_code\">Code de couplage</string>\n    <string name=\"adb_pairing_instruction\">Merci d\\'accéder aux options développeurs pour activer le débogage sans fil et générer un code de couplage.</string>\n    <string name=\"adb_pairing_input_pairing_code\">Code de couplage</string>\n    <string name=\"adb_pairing_found_pairing_service_with_port\">Service trouvé avec le port %d</string>\n    <string name=\"adb_pairing_pairing_in_progress\">Couplage…</string>\n    <string name=\"mode_of_op_custom_command_title\">Commande personnalisée</string>\n    <string name=\"mode_of_op_custom_command\">S\\'il est impossible d\\'utiliser l\\'un de ces modes, vous pouvez exécuter la commande suivante dans un terminal avec accès privilégié pour lancer App Manager :</string>\n    <string name=\"adb_pairing_retry_pairing\">Réessayer</string>\n    <string name=\"pref_use_system_font\">Utiliser la police système</string>\n    <string name=\"pref_use_system_font_msg\">Utiliser la police Material système par défaut. <font fgcolor=\"#ff0000\">Ceci est une fonctionnalité expérimentale.</font></string>\n    <string name=\"backup_cache\">Cache</string>\n    <string name=\"add_to_favorites\">Ajouter aux favoris</string>\n    <string name=\"advanced_suspend_app_description\">Cela force l\\'arrêt et suspend l\\'application pour s\\'assurer qu\\'elle ne tourne pas en arrière-plan. Cette méthode devrait être préférée par rapport à la méthode normale <b>suspendre</b>.</string>\n    <string name=\"no_history\">Historique vide</string>\n    <string name=\"battery_technology\">Technologie</string>\n    <string name=\"battery_health\">Santé</string>\n    <string name=\"virus_total\">VirusTotal</string>\n    <string name=\"available_memory\">Disponible : %s</string>\n    <string name=\"op_history\">Historique</string>\n    <string name=\"title_confirm_execution\">Confirmer l\\'exécution</string>\n    <string name=\"clear_history\">Effacer l\\'historique</string>\n    <string name=\"favorites\">Favoris</string>\n    <string name=\"item_remove\">Retirer</string>\n    <string name=\"item_edit\">Éditer</string>\n    <string name=\"remove_filename\">Retirer %s</string>\n    <string name=\"advanced_suspend_app\">Suspension avancée</string>\n    <string name=\"vulkan_version\">Version de Vulkan</string>\n    <string name=\"pref_files_remember_last_path_msg\">Lorsque cette option est activée, ouvrir une nouvelle fenêtre ouvre la dernière page ouverte à la place de la page d\\'accueil.</string>\n    <string name=\"title_shortcut_for_frozen_app\">Application gelée</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-hi/disclaimer.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- SPDX-License-Identifier: GPL-3.0-or-later --><resources>\n    <string name=\"disclaimer_header\">अस्वीकरण</string>\n    <string name=\"disclaimer_exit\">निकास</string>\n    <string name=\"disclaimer_agree\">मैं सहमत हूँ</string>\n    <string name=\"disclaimer_agree_forever\">यह फिर से न दिखाएँ</string>\n    <string name=\"disclaimer_footer\">© 2020–2024 मुंतशिर अल-इस्लाम</string>\n    <string name=\"disclaimer_body\">ऐप मैनेजर रूट फ़ंक्शन प्रदान करता है जो संभवतः गलत तरीके से उपयोग किए जाने पर आपके डिवाइस को नुकसान पहुंचा सकता है। ऐप मैनेजर इस एप्लिकेशन का उपयोग करके किए गए किसी भी नुकसान के लिए जिम्मेदार नहीं है। यदि आप पूरी तरह से रुट कैसे काम करता है के बारे में पता नहीं है तो आप रूट विकल्प का उपयोग करने से बचना चाहिए जब तक आप जोखिम के बारे में पूरी तरह से समझ नही जाते ।\n\\n\n\\nमेरे द्वारा अन्य ऐप्स और वेबसाइटों पर जाने वाला कोई भी लिंक उपयोगकर्ताओं के लाभ के लिए है। मैं बाहरी लिंक पर जाने से आपको मिलने वाली किसी भी सामग्री के लिए जिम्मेदार नहीं हूं।\n\\n\n\\nऐप मैनेजर का उपयोग करके, आप अपने स्वयं के उपयोग की पूरी जिम्मेदारी स्वीकार करते हैं और स्वीकार करते हैं कि दुरुपयोग के कारण कोई हर्जाना, दावा या मौद्रिक मूल्य नहीं दिया जाएगा।\n\\n\n\\nइस एप्लिकेशन का उपयोग करके, आप इसका उपयोग करके सभी जिम्मेदारी स्वीकार करते हैं और सहमत हैं कि मैं आपके द्वारा किए गए किसी भी कार्य के लिए जिम्मेदार नहीं हूं जिसका आपके डिवाइस पर प्रतिकूल प्रभाव पड़ता हो।</string>\n</resources>"
  },
  {
    "path": "app/src/main/res/values-hi/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- SPDX-License-Identifier: GPL-3.0-or-later --><resources xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:tools=\"http://schemas.android.com/tools\">\n    <string name=\"_lang_tag\" translatable=\"false\">hi</string>\n    <string name=\"deny_app_ops_description\">ऐप संचालन के लिए एक मोड सेट करें जो निरंतर मानों द्वारा पहचाना जाता है, अर्थात <tt>63</tt> या <tt>RUN_IN_BACKGROUND</tt></string>\n    <string name=\"block_components_dots\">कंपोनेंट ब्लॉक करें…</string>\n    <string name=\"block_unblock_trackers_description\">सभी इंस्टॉल किए गए ऐप्स में से विज्ञापन और ट्रैकिंग कंपोनेंट को ब्लॉक या अनब्लॉक करें</string>\n    <string name=\"clear_cache\">कैश साफ़ करें</string>\n    <string name=\"pref_import_existing_msg\">ऐप मैनेजर में अन्य ऐप्स द्वारा बंद किए कंपोनेंट जोड़ें। इस टूल का उपयोग करते समय सावधान रहें क्योंकि कई झूठी सकारात्मक हो सकती हैं। केवल उन्हीं ऐप्लिकेशन को चुनें जिनके बारे में आप कुछ निश्चित हैं।</string>\n    <string name=\"pref_import_existing\">मौजूदा रूल्स को आयात करें</string>\n    <string name=\"source_code\">सोर्स कोड</string>\n    <string name=\"update\">अपडेट</string>\n    <string name=\"install\">इनस्टॉल करें</string>\n    <plurals name=\"no_of_trackers\">\n        <item quantity=\"one\">%1$d ट्रैकर</item>\n        <item quantity=\"other\">%1$d ट्रैकर्स</item>\n    </plurals>\n    <string name=\"manifest_viewer\">मेनिफेस्ट दर्शक</string>\n    <string name=\"external_apk_no_app_op\">बाहरी APK में कोई ऐप संचालन नहीं है</string>\n    <string name=\"changelog\">बदलाव लॉग</string>\n    <string name=\"one_click_ops\">1-क्लिक ऑप्स</string>\n    <string name=\"never_ask\">कभी मत पूछें</string>\n    <string name=\"launch_app\">प्रारंभ करें</string>\n    <string name=\"failed_to_deny_dangerous_app_ops\">सभी खतरनाक ऐप ऑप्स को रद्द नहीं कर सके</string>\n    <string name=\"failed_to_deny_dangerous_perms\">सभी खतरनाक अनुमतियां रद्द नहीं कर सके</string>\n    <string name=\"failed_to_reset_app_ops\">ऐप ऑप्स रीसेट नहीं कर सके</string>\n    <string name=\"failed_to_revoke_permission\">अनुमति रद्द नहीं कर सके</string>\n    <string name=\"failed_to_grant_permission\">अनुमति नहीं दे सके</string>\n    <string name=\"unknown_op\">अज्ञात ऑपरेशन</string>\n    <string name=\"sort_by_tracker_components\">पहले ट्रैकर्स</string>\n    <string name=\"deny_dangerous_permissions\">खतरनाक अनुमतियाँ अस्वीकार करें</string>\n    <string name=\"sort_by_denied_app_ops\">पहले अस्वीकृत</string>\n    <string name=\"sort_by_denied_permissions\">पहले अस्वीकृत</string>\n    <string name=\"sort_by_dangerous_permissions\">पहले खतरनाक</string>\n    <string name=\"sort_by_permission_names\">अनुमति का नाम</string>\n    <string name=\"sort_by_app_ops_values\">ऐप ऑप्स वैल्यू</string>\n    <string name=\"sort_by_app_ops_names\">ऐप ऑप्स नाम</string>\n    <string name=\"deny_dangerous_app_ops\">खतरनाक ऐप ऑप्स अस्वीकार करें</string>\n    <string name=\"reset_to_default\">डिफ़ॉल्ट पर रीसेट</string>\n    <string name=\"sort_by_component_name\">कम्पोनेंट का नाम</string>\n    <string name=\"block_trackers\">ट्रैकर्स ब्लॉक करें</string>\n    <string name=\"sort_by_wifi_data\">वाई-फाई डेटा</string>\n    <string name=\"version\">संस्करण</string>\n    <string name=\"pref_about_msg\">ऐप मैनेजर संस्करण, लाइसेंस, क्रेडिट इत्यादि।</string>\n    <string name=\"apply\">लागू करें</string>\n    <string name=\"select_theme\">रात</string>\n    <string name=\"night\">रात</string>\n    <string name=\"day\">दिन</string>\n    <string name=\"battery_mode\">बैटरी मोड</string>\n    <string name=\"follow_system\">सिस्टम के अनुसार</string>\n    <string name=\"pref_app_theme\">ऐप थीम</string>\n    <string name=\"pref_import_blocker_msg\">ब्लॉकर से ब्लॉकिंग रूल्स आयात करें, प्रत्येक फाइल जो एक पैकेज के रूल्स समाविष्ट करती है।</string>\n    <string name=\"pref_import_watt_msg\">वाट से ब्लॉकिंग रूल्स आयात करें, प्रत्येक फाइल जो एक पैकेज नाम जैसे कि <tt>packagename.xml</tt> के रूल्स समाविष्ट करती है।</string>\n    <string name=\"pref_import_msg\">ऐप मैनेजर से पहले निर्यात किए गए ब्लॉकिंग नियमों को आयात करें।</string>\n    <string name=\"pref_export_msg\">ऐप मैनेजर में कॉन्फ़िगर किए गए ब्लॉकिंग नियमों को एक्सटर्नल स्टोरेज में निर्यात करें।</string>\n    <string name=\"touchscreen\">टचस्क्रीन</string>\n    <string name=\"navigation\">नेविगेशन</string>\n    <string name=\"keyboard_type\">कीबोर्ड प्रकार</string>\n    <string name=\"export_failed\">निर्यात विफल रहा!</string>\n    <string name=\"import_failed\">आयात विफल रहा!</string>\n    <string name=\"export_options\">निर्यात विकल्प</string>\n    <string name=\"import_options\">आयात विकल्प</string>\n    <string name=\"pref_export\">निर्यात</string>\n    <string name=\"pref_import\">आयात</string>\n    <string name=\"ago\">पहले</string>\n    <string name=\"reject_time\">अस्वीकार समय</string>\n    <string name=\"accept_time\">स्वीकार समय</string>\n    <string name=\"duration\">अवधि</string>\n    <string name=\"running\">चल रहे</string>\n    <string name=\"mode\">मोड</string>\n    <string name=\"permission_name\">अनुमति नाम</string>\n    <string name=\"toggle_kill_for_system_apps\">टॉगल किल सिस्टम एप्स</string>\n    <plurals name=\"alert_failed_to_force_stop\">\n        <item quantity=\"one\">%1$d ऐप को जबरदस्ती बंद नहीं किया जा सका</item>\n        <item quantity=\"other\">%1$d ऐप्स को जबरदस्ती बंद नहीं किया जा सका</item>\n    </plurals>\n    <string name=\"the_operation_was_successful\">हो गया</string>\n    <plurals name=\"alert_failed_to_disable_background\">\n        <item quantity=\"one\">%1$d ऐप को बैकग्राउंड में चलने से नहीं रोक सका</item>\n        <item quantity=\"other\">%1$d ऐप्स को बैकग्राउंड चलने से नहीं रोक सका</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_uninstall\">\n        <item quantity=\"one\">%1$d ऐप को अनइंस्टॉल नहीं कर सका</item>\n        <item quantity=\"other\">%1$d ऐप्स को अनइंस्टॉल नहीं कर सका</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_clear_data\">\n        <item quantity=\"one\">%1$d ऐप से डेटा नहीं मिटा सका</item>\n        <item quantity=\"other\">%1$d ऐप्स से डेटा नहीं मिटा सका</item>\n    </plurals>\n    <string name=\"export_blocking_rules\">ब्लॉकिंग रूल्स को निर्यात करें</string>\n    <string name=\"disable_background\">बैकग्राउंड में चलने ना दे</string>\n    <string name=\"backup_restore\">बैकअप/रिस्टोर</string>\n    <string name=\"clear_data\">डाटा मिटायें</string>\n    <string name=\"user_and_uid\">यूज़र: <xliff:g id=\"user_name\" example=\"root\">%1$s</xliff:g> (<xliff:g id=\"user_id\" example=\"0\">%2$d</xliff:g>)</string>\n    <string name=\"memory_virtual_memory\">मेमोरी: %1$s, वर्चुअल मेमोरी: %2$s</string>\n    <string name=\"pid_and_ppid\">प्रोसेस आईडी: %1$d, पैरेंट प्रोसेस आईडी: %2$d</string>\n    <string name=\"disable_background_run\">बैकग्राउंड कार्रवाई रोकें</string>\n    <string name=\"kill_process\">जबरदस्ती रोकें</string>\n    <string name=\"running_apps\">चल रहे ऐप</string>\n    <string name=\"apk_updater\">एपीके अपडेटर</string>\n    <plurals name=\"failed_to_import_files\">\n        <item quantity=\"one\">%1$d फ़ाइल आयात नहीं कर सका।</item>\n        <item quantity=\"other\">%1$d फ़ाइलें आयात नहीं कर सके।</item>\n    </plurals>\n    <string name=\"the_export_was_successful\">निर्यात सफल हुआ</string>\n    <string name=\"the_import_was_successful\">आयात सफल हुआ</string>\n    <string name=\"pref_import_blocker\">ब्लॉकर से आयात करें</string>\n    <string name=\"pref_import_watt\">वाट से आयात करें</string>\n    <string name=\"pref_import_export_blocking_rules_msg\">रूल्स का आयात/निर्यात करें, बाहरी रूल्स का वाट और ब्लॉकर से आयात करें।</string>\n    <string name=\"pref_import_export_blocking_rules\">ब्लॉकिंग नियमों का आयात/निर्यात</string>\n    <string name=\"sort_by_mobile_data\">मोबाइल डेटा</string>\n    <string name=\"sort_by_times_opened\">कितनी बार खोला</string>\n    <string name=\"sort_by_screen_time\">स्क्रीन समय</string>\n    <string name=\"sort_by_last_used\">अंतिम उपयोग</string>\n    <plurals name=\"no_of_times_opened\">\n        <item quantity=\"one\">%1$d बार</item>\n        <item quantity=\"other\">%1$d बार</item>\n    </plurals>\n    <string name=\"external_multiple_data_dir\">एक्सटर्नल डेटा डायरेक्टरी <xliff:g id=\"dir_no\" example=\"1\">%1$d</xliff:g></string>\n    <string name=\"external_data_dir\">एक्सटर्नल डेटा डायरेक्टरी</string>\n    <string name=\"sort_by_blocked_components\">पहले ब्लॉक्ड किये हुए</string>\n    <string name=\"exodus_link\">εxodus लिंक</string>\n    <string name=\"usage_yesterday\">पिछले दिन</string>\n    <string name=\"app_settings\">सेटिंग्स</string>\n    <string name=\"usage_access\">इस्तेमाल का एक्सेस</string>\n    <string name=\"pref_global_blocking_enabled_msg\">आप एप्लिकेशन को ब्लॉक किए बिना किसी भी एप्लिकेशन के किसी भी कंपोनेंट को ब्लॉक कर सकते हैं।</string>\n    <string name=\"pref_global_blocking_enabled\">तत्काल कंपोनेंट ब्लॉकिंग</string>\n    <string name=\"str_logo\">लोगो</string>\n    <string name=\"rules_not_applied\">रूल्स लागू नहीं हैं</string>\n    <string name=\"failed_to_disable_op\">अनुरोध किए गए ऐप ऑप को बंद नहीं किया जा सका</string>\n    <string name=\"failed_to_enable_op\">अनुरोध किए गए ऐप ऑप को चालू नहीं किया जा सका</string>\n    <string name=\"no_app_ops\">कोई ऐप ऑपेरशन नहीं</string>\n    <string name=\"app_ops\">ऐप ऑप्स</string>\n    <string name=\"app_size\">ऐप</string>\n    <string name=\"total_size\">कुल</string>\n    <string name=\"storage_and_cache\">स्टोरेज और कैश</string>\n    <string name=\"failed_to_stop\"><xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g> को नहीं रोक सके।</string>\n    <string name=\"force_stop\">ज़बरदस्ती रोकें</string>\n    <string name=\"enable\">चालू करें</string>\n    <string name=\"disable\">बंद करें</string>\n    <string name=\"stopped\">रोका गया</string>\n    <string name=\"uninstall_system_app_message\">यह एक सिस्टम ऐप है। क्या आप सुनिश्चित हैं कि इस ऐप को अनइंस्टॉल करना चाहते हैं\\?</string>\n    <string name=\"uninstalled_successfully\"><xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g> को अनइंस्टॉल किया गया।</string>\n    <string name=\"failed_to_uninstall\"><xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g> को अनइंस्टॉल नहीं कर सके।</string>\n    <string name=\"uninstall_app_message\">क्या आप इस ऐप को अनइंस्टॉल करना चाहते हैं\\?</string>\n    <string name=\"view_in_settings\">सेटिंग में देखें</string>\n    <string name=\"no_content\">कोई सामग्री नहीं</string>\n    <string name=\"no_usage_in_this_time_range\">इस समय सीमा में कोई उपयोग नहीं</string>\n    <string name=\"disabled_app\">बंद है</string>\n    <string name=\"key_name_cannot_be_null\">कुंजी नाम रिक्त नहीं हो सकता</string>\n    <string name=\"error_evaluating_input\">इनपुट का मूल्यांकन नहीं किया जा सका</string>\n    <string name=\"type_string\">वर्ण</string>\n    <string name=\"type_long\">लॉन्ग इन्टिजर</string>\n    <string name=\"type_int\">इन्टिजर</string>\n    <string name=\"type_float\">डेसीमल संख्या</string>\n    <string name=\"type_boolean\">ट्रू/फाल्स</string>\n    <string name=\"done\">हो गया</string>\n    <string name=\"add_item\">आइटम जोड़ें</string>\n    <string name=\"select_type\">एक प्रकार का चयन करें</string>\n    <string name=\"key_name\">की नाम</string>\n    <string name=\"boolean_value\">बूलियन वैल्यू</string>\n    <string name=\"decimal_value\">डेसीमल वैल्यू</string>\n    <string name=\"integer_value\">इन्टिजर वैल्यू</string>\n    <string name=\"long_integer_value\">लॉन्ग इन्टिजर वैल्यू</string>\n    <string name=\"string_value\">स्ट्रिंग वैल्यू</string>\n    <string name=\"saving_failed\">सेव करना विफल हुआ, पुनः प्रयास करें।</string>\n    <string name=\"saved_successfully\">सेव किया गया</string>\n    <string name=\"deletion_failed\">मिटाना विफल हुआ</string>\n    <string name=\"deleted_successfully\">मिटाए गए</string>\n    <string name=\"delete\">मिटाएँ</string>\n    <string name=\"discard\">रद्द करें</string>\n    <string name=\"save\">सेव करें</string>\n    <string name=\"databases\">डाटाबेस</string>\n    <string name=\"shared_prefs\">साझा प्रैफरेंसेज</string>\n    <string name=\"test_only\">केवल टेस्ट</string>\n    <string name=\"debuggable\">डीबग कर सकते हैं</string>\n    <string name=\"updated_app\">अपडेट किया गया</string>\n    <string name=\"requested_large_heap\">बड़ी हीप</string>\n    <string name=\"no_code\">कोई कोड नहीं</string>\n    <string name=\"process_name\">प्रोसेस का नाम</string>\n    <string name=\"native_library_dir\">नेटिव JNI लाइब्रेरी डायरेक्टरी</string>\n    <string name=\"dev_protected_data_dir\">डिवाइस-संरक्षित डेटा डायरेक्टरी</string>\n    <string name=\"search\">खोजें</string>\n    <string name=\"menu_apply_rules\">रूल्स लागू करें</string>\n    <string name=\"menu_remove_rules\">रूल्स हटाएँ</string>\n    <string name=\"failed_to_extract_apk_file\">एपीके फाइल एक्सट्रैक्ट नहीं कर सका</string>\n    <string name=\"share_apk\">एपीके शेयर करें</string>\n    <string name=\"grant_usage_acess_message\">इसका उपयोग एप्लिकेशन उपयोग जानकारी प्रदर्शित करने के लिए किया जाता है।</string>\n    <string name=\"grant_usage_access\">इस्तेमाल एक्सेस की अनुमति दें</string>\n    <string name=\"go\">जाएँ</string>\n    <string name=\"go_back\">पीछे जाएँ</string>\n    <string name=\"usage_less_than_a_minute\">एक मिनट से भी कम</string>\n    <plurals name=\"usage_hours\">\n        <item quantity=\"one\">%1$d घंटा</item>\n        <item quantity=\"other\">%1$d घंटे</item>\n    </plurals>\n    <plurals name=\"usage_days\">\n        <item quantity=\"one\">%1$d दिन</item>\n        <item quantity=\"other\">%1$d दिन</item>\n    </plurals>\n    <plurals name=\"usage_months\">\n        <item quantity=\"one\">%1$d महीना</item>\n        <item quantity=\"other\">%1$d महीने</item>\n    </plurals>\n    <string name=\"usage_7_days\">पिछले 7 दिन</string>\n    <string name=\"usage_today\">आज</string>\n    <string name=\"usage_weekly\">साप्ताहिक</string>\n    <string name=\"app_usage\">ऐप उपयोग</string>\n    <string name=\"no_tracker_class\">कोई ढूँढ़ने वाला क्लास नहीं मिला</string>\n    <string name=\"no_shared_libs\">कोई साझा लाइब्रेरी नहीं</string>\n    <plurals name=\"main_list_date_days\">\n        <item quantity=\"one\"><xliff:g id=\"last_update_date\" example=\"20/10/2020\">%1$s</xliff:g> <xliff:g id=\"day_no\" example=\"5\">%2$d</xliff:g> दिन</item>\n        <item quantity=\"other\"><xliff:g id=\"last_update_date\" example=\"20/10/2020\">%1$s</xliff:g> <xliff:g id=\"day_no\" example=\"5\">%2$d</xliff:g> दिन</item>\n    </plurals>\n    <string name=\"all_classes\">सभी क्लासेज</string>\n    <string name=\"tracker_classes\">ट्रैकर क्लासेज</string>\n    <string name=\"tracker_details\">ट्रैकर विवरण</string>\n    <string name=\"found_trackers\">ट्रैकर्स मिले:</string>\n    <string name=\"toggle_class_listing\">टॉगल वर्ग सूचीकरण</string>\n    <string name=\"class_viewer\">क्लास दर्शक</string>\n    <string name=\"word_wrap\">वर्ड व्रैप चालू/बंद करें</string>\n    <string name=\"credits_message\">निम्न प्रोजेक्ट के लेखकों के लिए\n\\n- एंड्रॉएड ओपन सोर्स प्रोजेक्ट\n\\n- <a href=\"https://github.com/zhaobozhen/libraries\">Absinthe\\'s libraries</a>\n\\n- <a href=\"https://github.com/butzist/ActivityLauncher\">Activity Launcher</a>\n\\n- <a href=\"https://bitbucket.org/oF2pks/fdroid-applications-info\">Apps_packages Info</a>\n\\n- <a href=\"https://github.com/zhaobao/AppsMonitor\">AppsMonitor</a>\n\\n- <a href=\"https://github.com/8enet/AppOpsX\">AppOpsX</a>\n\\n- <a href=\"https://github.com/gabrielemariotti/changeloglib\">ChangeLog Library</a>\n\\n- <a href=\"https://bitbucket.org/oF2pks/fdroid-classyshark3xodus\">ClassySharkAndroid</a>\n\\n- <a href=\"https://github.com/billthefarmer/editor\">Editor</a>\n\\n- <a href=\"https://github.com/Raival-e/File-Explorer\">File Explorer</a>\n\\n- <a href=\"https://github.com/nex3z/FlowLayout\">FlowLayout</a>\n\\n- <a href=\"https://github.com/k3b/intent-intercept\">Intent Intercept</a>\n\\n- <a href=\"https://github.com/YarikSOffice/lingver\">Lingver</a>\n\\n- <a href=\"https://github.com/topjohnwu/Magisk\">Magisk</a>\n\\n- <a href=\"https://github.com/zhanghai/MaterialFiles\">Material Files</a>\n\\n- <a href=\"https://github.com/pluscubed/matlog\">MatLog</a>\n\\n- <a href=\"https://github.com/matrix-org/matrix-android-sdk\">Matrix Android SDK</a>\n\\n- <a href=\"https://github.com/jensstein/oandbackup\">OAndBackup</a>\n\\n- <a href=\"https://github.com/open-keychain/open-keychain\">Open Keychain</a>\n\\n- <a href=\"https://github.com/Aefyr/SAI\">SAI</a>\n\\n- <a href=\"https://github.com/RikkaApps/Shizuku\">Shizuku</a>\n\\n- <a href=\"https://github.com/eclipse/tm4e\">tm4e</a>\n\\n- <a href=\"https://github.com/tuyafeng/Watt\">Watt</a> </string>\n    <string name=\"credits\">श्रेय</string>\n    <string name=\"third_party\">थर्ड पार्टी लाइब्रेरी और आइकन्स</string>\n    <string name=\"license\">लाइसेंस</string>\n    <string name=\"icon_picker\">आइकन पिकर</string>\n    <string name=\"class_name\">क्लास का नाम</string>\n    <string name=\"package_name\">पैकेज का नाम</string>\n    <string name=\"shortcut_name\">शॉर्टकट का नाम</string>\n    <string name=\"create_shortcut\">शॉर्टकट बनाएं</string>\n    <string name=\"starting_activity\">एक्टिविटी शुरू: <xliff:g id=\"activity_name\" example=\".main.MainActivity\">%1$s</xliff:g></string>\n    <string name=\"error_verbose_pin_shortcut\">वर्तमान लांचर PinShortcut का समर्थन नहीं करता है। शॉर्टकट बनाने में असमर्थ।</string>\n    <string name=\"error_creating_shortcut\">शॉर्टकट बनाने में त्रुटि</string>\n    <string name=\"empty_package_name\">पैकेज का नाम खाली है</string>\n    <string name=\"main_activity\">मुख्य एक्टिविटी</string>\n    <string name=\"user_id\">यूज़र आईडी</string>\n    <string name=\"installer_app\">जिस ऐप से इंस्टाल किया</string>\n    <string name=\"date_installed\">इंस्टॉल तिथि</string>\n    <string name=\"date_updated\">अपडेट तिथि</string>\n    <string name=\"more_info\">अधिक जानकारी</string>\n    <string name=\"sdk_flags\">फ्लैग्स</string>\n    <string name=\"sdk_max\">लक्ष्य</string>\n    <string name=\"sdk_min\">न्यूनतम</string>\n    <string name=\"data_dir\">डेटा डायरेक्टरी</string>\n    <string name=\"source_dir\">स्रोत डायरेक्टरी</string>\n    <string name=\"paths_and_directories\">पथ और डायरेक्ट्रीज</string>\n    <string name=\"user_app\">यूजर ऐप</string>\n    <string name=\"system_app\">सिस्टम ऐप</string>\n    <string name=\"app_info\">ऐप जानकारी</string>\n    <string name=\"version_name_with_code\">संस्करण <xliff:g id=\"version_name\" example=\"2.5.17\">%1$s</xliff:g> (<xliff:g id=\"version_code\" example=\"365\">%2$d</xliff:g>)</string>\n    <string name=\"sort\">प्रकार</string>\n    <string name=\"user\">उपयोगकर्ता</string>\n    <string name=\"system\">सिस्टम</string>\n    <string name=\"app_not_installed\">ऐप इंस्टॉल नहीं किया गया</string>\n    <string name=\"media_size\">मीडिया</string>\n    <string name=\"obb_size\">ओबीबी</string>\n    <string name=\"cache_size\">कैश</string>\n    <string name=\"data_size\">डेटा</string>\n    <string name=\"about\">ऐप के बारे में</string>\n    <string name=\"data_usage_msg\">डेटा का उपयोग</string>\n    <string name=\"data_transmitted\">प्रेषित डेटा</string>\n    <string name=\"data_received\">प्राप्त डेटा</string>\n    <string name=\"sort_by_target_sdk\">टार्गेट एसडीके</string>\n    <string name=\"sort_by_domain\">पहले उपयोगकर्ता ऐप्स</string>\n    <string name=\"sort_by_package_name\">पैकेज नाम</string>\n    <string name=\"sort_by_app_label\">ऐप लेबल</string>\n    <string name=\"loading\">लोड हो रहा है…</string>\n    <string name=\"error\">त्रुटि</string>\n    <string name=\"manifest\">मेनिफेस्ट</string>\n    <string name=\"input_features\">इनपुट फीचर्स</string>\n    <string name=\"no_configurations\">कोई कॉन्फ़िगरेशन नहीं</string>\n    <string name=\"configurations\">कॉन्फ़िगरेशन</string>\n    <string name=\"app_signing_no_signatures\">कोई मान्य हस्ताक्षर नहीं</string>\n    <string name=\"signatures\">हस्ताक्षर</string>\n    <string name=\"sort_by_sha\">हस्ताक्षर</string>\n    <string name=\"shared_user_id\">साझी गई यूज़र आईडी</string>\n    <string name=\"sort_by_shared_user_id\">साझी गई यूज़र आईडी</string>\n    <string name=\"no_feature\">कोई फ़ीचर नहीं</string>\n    <string name=\"uses_feature\">फीचर्स उपयोग</string>\n    <string name=\"group\">समूह</string>\n    <string name=\"shared_libs\">साझी गईं लाइब्रेरी</string>\n    <string name=\"declared_permission\">अनुमतियाँ</string>\n    <plurals name=\"failed_to_backup_some_apk_files\">\n        <item quantity=\"one\">%1$d ऐप का बैकअप नहीं हुआ</item>\n        <item quantity=\"other\">%1$d ऐप्स का बैकअप नहीं हुआ</item>\n    </plurals>\n    <string name=\"backup_options\">बैकअप विकल्प</string>\n    <string name=\"delete_backup\">बैकअप हटाएं</string>\n    <string name=\"restore\">रिस्टोर</string>\n    <string name=\"backup\">बैकअप</string>\n    <string name=\"data\">डेटा</string>\n    <string name=\"external_data\">एक्सटर्नल डेटा</string>\n    <string name=\"blocking_rules\">ब्लॉकिंग रूल्स</string>\n    <string name=\"whats_new\">नया क्या है</string>\n    <string name=\"features\">फीचर्स</string>\n    <string name=\"components\">कंपोनेंट्स</string>\n    <string name=\"trackers\">ट्रैकर्स</string>\n    <string name=\"installed_version\">इंस्टॉल्ड संस्करण</string>\n    <string name=\"select_all\">सभी का चयन करें</string>\n    <string name=\"filter_apps_with_rules\">नियमों के साथ</string>\n    <string name=\"filter_system_apps\">सिस्टम ऐप्स</string>\n    <string name=\"filter_user_apps\">यूज़र ऐप्स</string>\n    <string name=\"filter\">फ़िल्टर</string>\n    <string name=\"package_name_is_installed_successfully\"><xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g> इंस्टॉल पूर्ण हुआ</string>\n    <string name=\"termux\">टर्मक्स</string>\n    <plurals name=\"no_of_splits\">\n        <item quantity=\"one\">%1$d स्प्लिट</item>\n        <item quantity=\"other\">%1$d स्प्लिट्स</item>\n    </plurals>\n    <string name=\"failed_to_parse_some_numbers\">कुछ नंबर पार्स नहीं कर सके</string>\n    <string name=\"only_works_in_root_or_adb_mode\">केवल रूट या एडीबी मोड में काम करता है</string>\n    <string name=\"input_app_ops_description\">ऐप ऑप कांस्टेंट को रिक्त स्थान के साथ के साथ लिखें, उदाहरण के लिए (<tt>WAKE_LOCK 63 72 CAMERA</tt>) आदि। आप कोष्ठक के तहत ऐप ऑप्स टैब में ऐप ऑप कांस्टेंट पा सकते हैं।</string>\n    <string name=\"input_app_ops\">इनपुट ऐप ऑप्स</string>\n    <string name=\"filtered_packages\">फ़िल्टर किए गए पैकेज</string>\n    <string name=\"input_signatures_description\">रिक्त स्थान के साथ इनपुट हस्ताक्षर, उदाहरण के लिए <tt>com.facebook org.app2 com.app3</tt> आदि।</string>\n    <string name=\"input_signatures\">इनपुट हस्ताक्षर</string>\n    <string name=\"failed_packages\">असफल पैकेज</string>\n    <string name=\"no_tracker_found\">कोई ट्रैकर नहीं मिला</string>\n    <string name=\"clear_app_cache_description\">सभी ऐप्स के कैश को साफ करता है</string>\n    <string name=\"clear_app_cache\">ऐप कैश साफ करें</string>\n    <string name=\"clear_data_from_uninstalled_apps_description\"><tt>DONT_DELETE_DATA</tt> फ्लैग के साथ अनइंस्टॉल किए गए एप्लिकेशन से डेटा साफ़ करें</string>\n    <string name=\"clear_data_from_uninstalled_apps\">अनइंस्टॉल किए गए ऐप्स से डेटा साफ़ करें</string>\n    <string name=\"patterns_allowed\">पैटर्न अनुमति</string>\n    <string name=\"write\">लिखें</string>\n    <string name=\"read\">पढ़ें</string>\n    <string name=\"path_permissions\">पथ अनुमतियाँ</string>\n    <string name=\"grant_uri_permission\">URI अनुमति प्रदान करें</string>\n    <string name=\"flags\">फ्लैग्स</string>\n    <string name=\"soft_input\">सॉफ्ट इनपुट मोड</string>\n    <string name=\"orientation\">ओरिएंटेशन</string>\n    <string name=\"no_service\">कोई सर्विसेज़ नहीं</string>\n    <string name=\"service\">सर्विसेज़</string>\n    <string name=\"authority\">प्राधिकारी</string>\n    <string name=\"sort_by_last_update\">अंतिम अपडेट</string>\n    <string name=\"task_affinity\">कार्य संबंध</string>\n    <string name=\"launch_mode\">लॉन्च मोड</string>\n    <string name=\"no_providers\">कोई प्रोवाइडर नहीं</string>\n    <string name=\"providers\">प्रोवाइडर</string>\n    <string name=\"no_receivers\">कोई रिसीवर नहीं</string>\n    <string name=\"receivers\">रिसीवर</string>\n    <string name=\"no_activities\">कोई एक्टिविटी नहीं</string>\n    <string name=\"refresh\">रीफ़्रेश करें</string>\n    <string name=\"launch\">प्रारंभ करें</string>\n    <string name=\"activities\">एक्टिविटी</string>\n    <string name=\"require_no_permission\">अनुमति की आवश्यकता नहीं</string>\n    <string name=\"permissions\">अनुमतियों का उपयोग</string>\n    <string name=\"uninstall\">अनइंस्टॉल करें</string>\n    <string name=\"app_signing_install_without_data_loss\">यदि आपने सिग्नेचर वेरिफिकेशन बंद कर रखा है, तो आप बिना डेटा खोए ऐप इंस्टॉल करने के लिए <b>केवल इंस्टॉल</b> विकल्प का उपयोग कर सकते हैं।</string>\n    <string name=\"no\">नहीं</string>\n    <string name=\"keyboard_no_keys\">कोई कुंजी नहीं</string>\n    <string name=\"navigation_no_nav\">कोई नेविगेशन नहीं</string>\n    <string name=\"pref_backup_flags_msg\">बैकअप विकल्पों के लिए एक प्रीसेट जोड़ने से जब आप बैकअप/रिस्टोर करते हैं तो आपको बार बार फ्लैग्स के चयन करने का झंझट नहीं होगा।</string>\n    <string name=\"state_dead\">मृत</string>\n    <string name=\"sys_config\">सिस्टम कॉन्फ़िग</string>\n    <string name=\"only_install\">केवल इंस्टॉल</string>\n    <string name=\"app_data_will_be_lost\">मौजूदा डाटा खत्म हो जाएगा।</string>\n    <string name=\"app_signing_signature_mismatch_for_system_apps\">ऐप इंस्टॉल नहीं कर सके क्योंकि इंस्टॉल किया गया ऐप अलग हस्ताक्षर वाला एक सिस्टम ऐप है।</string>\n    <string name=\"do_you_want_to_uninstall_and_install\">क्या आप ऐप को फिर से अनइंस्टॉल और इंस्टॉल करना चाहते हैं\\?</string>\n    <string name=\"usage_access_not_supported\">उपयोग पहुंच का अनुरोध नहीं किया जा सका, क्योंकि संबंधित सेटिंग पृष्ठ मौजूद नहीं है।</string>\n    <string name=\"non_critical_exts\">नॉन-क्रिटिकल एक्सटेंशन्स</string>\n    <string name=\"critical_exts\">क्रिटिकल एक्सटेंशन</string>\n    <string name=\"dsa_affine_y\">ऐफ़िन वाई समन्वय</string>\n    <string name=\"dsa_affine_x\">एफ़िन एक्स समन्वय</string>\n    <string name=\"rsa_modulus\">मापांक</string>\n    <string name=\"rsa_exponent\">प्रतिपादक</string>\n    <string name=\"format\">स्वरूप</string>\n    <string name=\"public_key\">सार्वजनिक कुंजी</string>\n    <string name=\"algorithm\">एल्गोरिथ्म</string>\n    <string name=\"app_signing_signature\">हस्ताक्षर</string>\n    <string name=\"checksums\">चेकसम्स</string>\n    <string name=\"serial_no\">सीरियल क्रमांक</string>\n    <string name=\"not_yet_valid\">अभी तक मान्य नहीं है</string>\n    <string name=\"expired\">समय सीमा समाप्त</string>\n    <string name=\"valid\">मान्य</string>\n    <string name=\"validity\">वैधता</string>\n    <string name=\"type\">प्रकार</string>\n    <string name=\"expiry_date\">समाप्ति तिथि</string>\n    <string name=\"issued_date\">जारी दिनांक</string>\n    <string name=\"issuer\">जारीकर्ता</string>\n    <string name=\"subject\">विषय</string>\n    <string name=\"filter_apps_with_backups\">बैकअप के संग</string>\n    <string name=\"sort_by_backup\">पहले बैकअप लिया</string>\n    <string name=\"failed_to_uninstall_updates\"><xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g> के अपडेट को अनइंस्टॉल नहीं कर सके।</string>\n    <string name=\"update_uninstalled_successfully\"><xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g> के अपडेट को अनइंस्टॉल कर दिया गया है।</string>\n    <string name=\"uninstall_updates\">अप्डेट्स अनइंस्टॉल करें</string>\n    <string name=\"allow_open_pgp_operation\">ऐप मैनेजर को ओपनपीजीपी का उपयोग करने की अनुमति देने के लिए टैप करें</string>\n    <string name=\"confirm_installation\">इंस्टालेशन की पुष्टि करें</string>\n    <string name=\"pref_compression_method\">कंप्रेशन विधि</string>\n    <string name=\"rules\">रूल्स</string>\n    <string name=\"other\">अन्य</string>\n    <string name=\"changes_not_saved\">परिवर्तन सहेजे नहीं गए</string>\n    <string name=\"sort_by_memory_usage\">मेमोरी उपयोग</string>\n    <string name=\"sort_by_apps_first\">पहले ऐप्स</string>\n    <string name=\"sort_by_process_name\">प्रोसेस नाम</string>\n    <string name=\"sort_by_process_id\">प्रोसेस आइडी</string>\n    <string name=\"filter_apps\">ऐप्स</string>\n    <string name=\"no_apps\">कोई ऐप नहीं</string>\n    <string name=\"apps\">ऐप्स</string>\n    <string name=\"routine_ops\">रूटीन ऑप्स</string>\n    <string name=\"apply_now\">अभी लागू करें…</string>\n    <string name=\"keystore\">कीस्टोर</string>\n    <string name=\"no_profiles\">कोई प्रोफाइल्स नहीं</string>\n    <string name=\"profiles\">प्रोफाइल्स</string>\n    <string name=\"open_pgp_provider\">ओपनपीजीपी प्रोवाइडर</string>\n    <string name=\"systemless_app\">सिस्टमलेस ऐप</string>\n    <string name=\"cancel\">रद्द करें</string>\n    <string name=\"ok\">ठीक है</string>\n    <string name=\"input_backup_name_description\">बैकअप नाम एक अंक से शुरू नहीं होना चाहिए और न ही इसमें कोई रिक्त स्थान होने चाहिए। यदि आप वर्तमान तिथि-समय का उपयोग करना चाहते हैं तो इसे खाली छोड़ दें।</string>\n    <string name=\"input_backup_name\">बैकअप नाम</string>\n    <string name=\"downgrade\">डाउनग्रेड</string>\n    <string name=\"process_state_with_extra\">स्तिथि: <xliff:g id=\"process_state\" example=\"Sleeping\">%1$s</xliff:g> (<xliff:g id=\"state_extra\" example=\"High priority\">%2$s</xliff:g>)</string>\n    <string name=\"process_state\">स्तिथि: <xliff:g id=\"process_state\" example=\"Sleeping\">%1$s</xliff:g></string>\n    <string name=\"state_multithreaded\">बहुआयामी</string>\n    <string name=\"state_foreground\">अग्रभूमि</string>\n    <string name=\"state_session_leader\">सेशन लीडर</string>\n    <string name=\"state_locked_memory\">लॉक्ड मेमोरी</string>\n    <string name=\"state_low_priority\">कम प्राथमिकता</string>\n    <string name=\"state_high_priority\">उच्च प्राथमिकता</string>\n    <string name=\"state_unknown\">अज्ञात</string>\n    <string name=\"state_waking\">वेकिंग</string>\n    <string name=\"state_wake_kill\">वेक किल</string>\n    <string name=\"state_idle\">आइडल</string>\n    <string name=\"state_parked\">पार्क</string>\n    <string name=\"state_zombie\">ज़ोंबी</string>\n    <string name=\"state_trace_stop\">ट्रेस बंद</string>\n    <string name=\"state_device_io\">डिवाइस I/O</string>\n    <string name=\"state_sleeping\">स्लीपिंग</string>\n    <string name=\"touchscreen_finger\">उंगली</string>\n    <string name=\"touchscreen_stylus\">स्टायलस</string>\n    <string name=\"touchscreen_no_touch\">कोई टच नहीं</string>\n    <string name=\"navigation_wheel\">व्हील</string>\n    <string name=\"navigation_trackball\">ट्रैकबॉल</string>\n    <string name=\"navigation_dial_pad\">डायल पैड</string>\n    <string name=\"keyboard_12_keys\">12 कुंजी</string>\n    <string name=\"keyboard_qwerty\">QWERTY</string>\n    <string name=\"_undefined\">अनिर्धारित</string>\n    <string name=\"required\">आवश्यक</string>\n    <string name=\"orientation_user_portrait\">यूज़र सीधा</string>\n    <string name=\"orientation_user_landscape\">यूजर आड़ा</string>\n    <string name=\"orientation_sensor\">सेंसर</string>\n    <string name=\"orientation_sensor_portrait\">सेंसर सीधा</string>\n    <string name=\"orientation_sensor_landscape\">सेंसर आड़ा</string>\n    <string name=\"orientation_user\">यूज़र</string>\n    <string name=\"orientation_reverse_landscape\">उल्टी तरफ से आड़ा</string>\n    <string name=\"orientation_reverse_portrait\">उल्टी तरफ से सीधा</string>\n    <string name=\"orientation_landscape\">आड़ा</string>\n    <string name=\"orientation_portrait\">सीधा</string>\n    <string name=\"orientation_no_sensor\">कोई सेंसर नहीं</string>\n    <string name=\"orientation_locked\">लॉक्ड</string>\n    <string name=\"orientation_full_user\">पूर्ण यूज़र</string>\n    <string name=\"orientation_full_sensor\">पूर्ण सेंसर</string>\n    <string name=\"orientation_behind\">पीछे</string>\n    <string name=\"orientation_unspecified\">अनिर्दिष्ट</string>\n    <string name=\"launch_mode_single_top\">एक टॉप</string>\n    <string name=\"launch_mode_single_task\">एक टास्क</string>\n    <string name=\"launch_mode_single_instance\">एक इंस्टैंस</string>\n    <string name=\"launch_mode_multiple\">एकाधिक</string>\n    <string name=\"locale_split_for_base_apk\"><xliff:g id=\"split_name\" example=\"English\">%1$s</xliff:g> बेस एपीके के लिए भाषा</string>\n    <string name=\"locale_split_for_feature\"><xliff:g id=\"split_name\" example=\"English\">%1$s</xliff:g> भाषा के लिए <xliff:g id=\"feature_name\" example=\"Visualizer\">%2$s</xliff:g></string>\n    <string name=\"abi_split_for_base_apk\">बेस एपीके के लिए <xliff:g id=\"split_name\" example=\"arm64_v8a\">%1$s</xliff:g> कोड</string>\n    <string name=\"abi_split_for_feature\"><xliff:g id=\"split_name\" example=\"arm64_v8a\">%1$s</xliff:g> कोड के लिए <xliff:g id=\"feature_name\" example=\"Visualizer\">%2$s</xliff:g></string>\n    <string name=\"density_split_for_base_apk\"><xliff:g id=\"split_name\" example=\"xxdpi\">%1$s</xliff:g> (<xliff:g id=\"dpi_no\" example=\"480\">%2$d</xliff:g> डीपीआई) बेस एपीके के लिए संसाधन</string>\n    <string name=\"density_split_for_feature\"><xliff:g id=\"split_name\" example=\"xxdpi\">%1$s</xliff:g> (<xliff:g id=\"dpi_no\" example=\"480\">%2$d</xliff:g> डीपीआई) फीचर के लिए संसाधन <xliff:g id=\"feature_name\" example=\"Visualizer\">%3$s</xliff:g></string>\n    <string name=\"unknown_split_for_base_apk\">बेस एपीके के लिए <xliff:g id=\"split_name\" example=\"some_split\">%1$s</xliff:g></string>\n    <string name=\"unknown_split_for_feature\"><xliff:g id=\"split_name\" example=\"some_split\">%1$s</xliff:g> के लिए फ़ीचर <xliff:g id=\"feature_name\" example=\"Visualizer\">%2$s</xliff:g></string>\n    <string name=\"split_feature_name\">फ़ीचर: <xliff:g id=\"feature_name\" example=\"Visualizer\">%1$s</xliff:g></string>\n    <string name=\"base_apk\">बेस एपीके</string>\n    <string name=\"choose_language\">भाषा बदलें</string>\n    <string name=\"auto\">स्वतः</string>\n    <string name=\"pref_app_language\">भाषा</string>\n    <string name=\"backup_all_users\">सभी यूज़र्स</string>\n    <string name=\"backup_multiple\">कई का बैकअप लें</string>\n    <string name=\"obb_files_extracted_successfully\">ओबीबी फाइलों का एक्सट्रैक्शन सफल हुआ</string>\n    <string name=\"failed_to_extract_obb_files\">ओबीबी फाइलें एक्सट्रेक्ट नहीं कर सके</string>\n    <string name=\"backup_obb_media\">ओबीबी और मीडिया</string>\n    <string name=\"backup_apk_files\">एपीके फाईलें</string>\n    <string name=\"installer_error_session_abandon\">इंस्टॉलर सत्र को नहीं छोड़ सकते</string>\n    <string name=\"installer_error_session_commit\">एपीके फाइलें कमिट नहीं कर सके</string>\n    <string name=\"installer_error_session_write\">इंस्टॉलर सत्र में नहीं लिख सके</string>\n    <string name=\"installer_error_session_create\">इंस्टॉलर सत्र नहीं बना सके</string>\n    <string name=\"installer_error_security\">एपीके फाइल्स को एक्सेस नहीं कर सके</string>\n    <string name=\"install_in_progress\">इंस्टॉल की जा रही है…</string>\n    <string name=\"package_installer\">पैकेज इंस्टॉलर</string>\n    <string name=\"unblock_trackers\">ट्रैकर्स को अनब्लॉक करें</string>\n    <string name=\"reinstall\">पुनः इंस्टॉल करें</string>\n    <string name=\"install_app_message\">क्या आप यह ऐप इंस्टॉल करना चाहते हैं\\?</string>\n    <string name=\"try_again\">पुन: प्रयास करें</string>\n    <string name=\"full_stop_tap_to_see_details\">। विवरण देखने के लिए टैप करें।</string>\n    <string name=\"operation_running\">ऑपेरशन चल रहा है…</string>\n    <string name=\"batch_ops\">बैच ऑपरेशन्स</string>\n    <string name=\"failed_to_fetch_package_info\">पैकेज जानकारी प्राप्त नहीं कर सके</string>\n    <string name=\"installer_error_lidl_rom\">आपकी रोम रूटलेस इंस्टॉलर के साथ असंगत है।</string>\n    <string name=\"installer_error_generic\">इंस्टालेशन विफल रहा</string>\n    <string name=\"installer_error_storage\">ऐप को इंस्टॉल करने के लिए पर्याप्त स्टोरेज स्पेस नहीं है</string>\n    <string name=\"installer_error_bad_apks\">अमान्य एपीके फ़ाइलें चयनित</string>\n    <string name=\"installer_error_incompatible\">यह ऐप इस डिवाइस के साथ असंगत है</string>\n    <string name=\"installer_error_conflict\">ऐप इंस्टॉल नहीं किया जा सका क्योंकि पैकेज का नाम उपयोग में है</string>\n    <string name=\"installer_error_blocked\">इंस्टालेशन को <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g> के द्वारा ब्लॉक किया गया</string>\n    <string name=\"installer_error_blocked_device\">डिवाइस</string>\n    <string name=\"installer_error_aborted\">इंस्टॉल विफल रहा क्योंकि या तो यह रद्द कर दिया गया था, या सत्र अप्रत्याशित रूप से बंद हो गया था</string>\n    <string name=\"toggle_default_app_ops\">डिफ़ॉल्ट ऐप ऑप्स को टॉगल करें</string>\n    <string name=\"filter_apps_with_activities\">गतिविधियों के साथ</string>\n    <string name=\"are_you_sure\">क्या आप सुनिश्चित हैं\\?</string>\n    <string name=\"pref_remove_all_rules_msg\">अनुमतियां प्रदान की जाएंगी, ऐप ऑप्स और घटक अपने डिफ़ॉल्ट मानों पर वापस आ जाएंगे।</string>\n    <string name=\"pref_remove_all_rules\">सभी रूल्स हटाएँ</string>\n    <string name=\"website\">वेबसाइट</string>\n    <string name=\"run_in_termux\">टर्मक्स में चलाएं</string>\n    <string name=\"open_in_termux\">टर्मक्स में खोलें</string>\n    <string name=\"export_icon\">आइकॉन निकालें</string>\n    <string name=\"no_matching_package_found\">ऐसा कोई ऐप नहीं मिला</string>\n    <string name=\"block_unblock_trackers\">ट्रेकर्स को ब्लॉक/अनब्लॉक करें</string>\n    <string name=\"unblock\">अनब्लॉक करें</string>\n    <string name=\"block\">ब्लॉक करें</string>\n    <string name=\"clear\">साफ़ करें</string>\n    <string name=\"clear_data_message\">क्या आप सुनिश्चित हैं कि इस ऐप का डेटा साफ़ करना चाहते हैं\\?</string>\n    <string name=\"skip_signature_checks\">हस्ताक्षर चेक छोड़ें</string>\n    <string name=\"yes\">हाँ</string>\n    <string name=\"apply_to_system_apps_question\">सिस्टम ऐप्स पर भी लागू करें\\? यदि अनिश्चित हैं तो \\\"नहीं\\\" का चयन करें।</string>\n    <string name=\"apply_to_system_apps\">सिस्टम ऐप्स पर लागू करें</string>\n    <plurals name=\"backup_exists_are_you_sure\">\n        <item quantity=\"one\">बैकअप मौजूद है। क्या आपको यकीन है\\?</item>\n        <item quantity=\"other\">एक से अधिक ऐप के लिए पहले से बैकअप मौजूद है। क्या आपको यकीन है\\?</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_block_components\">\n        <item quantity=\"one\">%1$d ऐप के कंपोनेंट्स को ब्लॉक नहीं किया जा सका</item>\n        <item quantity=\"other\">%1$d ऐप्स के कंपोनेंट्स को ब्लॉक नहीं किया जा सका</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_unblock_trackers\">\n        <item quantity=\"one\">%1$d ऐप से ट्रैकर्स को बंद नहीं कर सके</item>\n        <item quantity=\"other\">%1$d ऐप्स से ट्रैकर्स को बंद नहीं कर सके</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_delete_backup\">\n        <item quantity=\"one\">%1$d बैकअप को हटा नहीं सके</item>\n        <item quantity=\"other\">%1$d बैकअप्स को हटा नहीं सके</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_restore\">\n        <item quantity=\"one\">%1$d ऐप को रिस्टोर नहीं किया जा सका</item>\n        <item quantity=\"other\">%1$d ऐप्स को रिस्टोर नहीं किया जा सका</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_backup\">\n        <item quantity=\"one\">%1$d ऐप का बैकअप नहीं ले सका</item>\n        <item quantity=\"other\">%1$d ऐप्स का बैकअप नहीं ले सके</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_disable_trackers\">\n        <item quantity=\"one\">%1$d ऐप से ट्रैकर्स को बंद नहीं कर सके</item>\n        <item quantity=\"other\">%1$d ऐप्स से ट्रैकर्स को बंद नहीं कर सके</item>\n    </plurals>\n    <plurals name=\"tracker_and_classes\">\n        <item quantity=\"one\">1 ट्रैकर <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g> क्लास के साथ</item>\n        <item quantity=\"other\">1 ट्रैकर <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g> क्लासेस के साथ</item>\n    </plurals>\n    <string name=\"copy\">कॉपी करें</string>\n    <string name=\"view_missing_signatures\">ऐप मैनेजर लाइब्रेरी के डेटाबेस में हस्ताक्षर देखने या भेजने के लिए टैप करें जो अभी तक मौजूद नहीं है।</string>\n    <string name=\"tap_to_see_details\">विवरण देखने के लिए टैप करें</string>\n    <string name=\"lib_details\">लाइब्रेरी विवरण</string>\n    <string name=\"no_libs\">कोई लाइब्रेरी नहीं</string>\n    <string name=\"scanner\">स्कैनर</string>\n    <plurals name=\"missing_signatures\">\n        <item quantity=\"one\">%1$d हस्ताक्षर अनुपलब्ध</item>\n        <item quantity=\"other\">%1$d हस्ताक्षर अनुपलब्ध</item>\n    </plurals>\n    <plurals name=\"libraries\">\n        <item quantity=\"one\">%1$d लाइब्रेरी</item>\n        <item quantity=\"other\">%1$d लाइब्रेरीज़</item>\n    </plurals>\n    <plurals name=\"classes\">\n        <item quantity=\"one\">%1$d क्लास</item>\n        <item quantity=\"other\">%1$d क्लासेस</item>\n    </plurals>\n    <plurals name=\"other_trackers_and_classes\">\n        <item quantity=\"one\"><xliff:g id=\"tracker_no\" example=\"8\">%1$d</xliff:g> ट्रैकर्स <xliff:g id=\"class_no\" example=\"50\">%2$d</xliff:g> क्लासेस के साथ</item>\n        <item quantity=\"other\"><xliff:g id=\"tracker_no\" example=\"8\">%1$d</xliff:g> ट्रैकर्स <xliff:g id=\"class_no\" example=\"50\">%2$d</xliff:g> क्लासेस के साथ</item>\n    </plurals>\n    <plurals name=\"two_trackers_and_classes\">\n        <item quantity=\"one\">2 ट्रैकर्स <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g> क्लासेस के साथ</item>\n        <item quantity=\"other\">2 ट्रेकर्स <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g> क्लासेस के साथ</item>\n    </plurals>\n    <string name=\"filter_running_apps\">चल रहे ऐप्स</string>\n    <string name=\"un_apkm\">UnApkm</string>\n    <string name=\"in_progress\">प्रगति पर है</string>\n    <string name=\"conversion_failed\">बदलाव करने में त्रुटि हुई।</string>\n    <string name=\"select_apk\">एपीके चुनें</string>\n    <string name=\"backup_apk_files_description\">डेटा डायरेक्टरी से केवल एपीके फ़ाइलों का बैकअप करें। इसके काम करने के लिए <b> स्रोत </b> चुना जाना चाहिए।</string>\n    <string name=\"set_mode_for_app_ops_dots\">ऐप ऑप्स के लिए मोड सेट करें …</string>\n    <string name=\"security\">सिक्योरिटी</string>\n    <string name=\"battery\">बैटरी</string>\n    <string name=\"graphics\">ग्राफिक्स</string>\n    <string name=\"cpu\">सीपीयू</string>\n    <string name=\"users\">यूज़र्स</string>\n    <string name=\"languages\">भाषाएँ</string>\n    <string name=\"battery_capacity\">क्षमता</string>\n    <string name=\"memory\">मेमोरी</string>\n    <string name=\"vendor\">वेंडर</string>\n    <string name=\"gles_version\">ओपन जीएल ईएस संस्करण</string>\n    <string name=\"no_of_cores\">कोर</string>\n    <string name=\"support_architectures\">समर्थित आर्किटेक्चर</string>\n    <string name=\"security_providers\">सुरक्षा प्रदाता</string>\n    <string name=\"kernel\">कर्नल</string>\n    <string name=\"manufacturer\">निर्माता</string>\n    <string name=\"board_name\">बोर्ड</string>\n    <string name=\"model\">मॉडल</string>\n    <string name=\"brand_name\">ब्रांड</string>\n    <string name=\"pref_about_device_msg\">डिवाइस की बुनियादी जानकारी जैसे एंड्रॉयड सिस्टम, सीपीयू, जीपीयू, रैम, बैटरी आदि।</string>\n    <string name=\"about_device\">डिवाइस के बारे में</string>\n    <string name=\"set_custom_app_op\">कस्टम ऐप ऑप सेट करें</string>\n    <string name=\"interceptor\">इंटरसेप्टर</string>\n    <string name=\"resend_intent\">इंटेंट फिर से</string>\n    <string name=\"share\">शेयर</string>\n    <string name=\"extras\">एक्स्ट्रास</string>\n    <string name=\"category\">श्रेणियां</string>\n    <string name=\"uri\">यूआरआई</string>\n    <string name=\"mime_type\">माइम प्रकार</string>\n    <string name=\"result_code\">परिणाम</string>\n    <string name=\"activity_result\">एक्टिविटी परिणाम</string>\n    <string name=\"send_edited_intent\">संपादित इंटेंट</string>\n    <string name=\"matching_activities\">मिली गतिविधियां</string>\n    <string name=\"value\">मान</string>\n    <string name=\"filter_apps_with_splits\">स्प्लिट्स वाले</string>\n    <string name=\"set_app_op_mode\">ऐप ऑप मोड सेट</string>\n    <string name=\"magisk_hide_enabled\">मैजिस्कहाइड</string>\n    <string name=\"pref_backup_android_keystore_msg\">कुछ ऐप्स रिस्टोर के बाद काम नहीं करेंगे। कीस्टोर को रिस्टोर करना अधिकांश डिवाइस पर काम नहीं करता है।</string>\n    <string name=\"pref_backup_android_keystore\">एंड्रॉइड कीस्टोर वाले ऐप्स को बैकअप करें</string>\n    <string name=\"keep_data_and_app_signing_signatures\">डेटा और हस्ताक्षर रखें</string>\n    <string name=\"this_action_cannot_be_undone\">इस एक्शन को वापस नहीं किया जा सकता।</string>\n    <string name=\"no_app_ops_permission\">ऐप ऑप्स प्रदर्शित करने की अनुमति नहीं</string>\n    <string name=\"input_keystore_alias_pass_description\">उपनाम <b> %1$s </b> के लिए पासवर्ड डालें। यदि आपका पासवर्ड कीस्टोर पासवर्ड के समान है, तो आप इसे खाली छोड़ सकते हैं।</string>\n    <string name=\"input_keystore_alias_pass\">उपनाम के लिए पासवर्ड <b>%1$s</b></string>\n    <string name=\"input_keystore_pass_msg\">कीस्टोर पासवर्ड डालने के लिए यहां टैप करें</string>\n    <string name=\"input_keystore_pass_description\">ऐप मैनेजर कीस्टोर पासवर्ड डालें। यदि आप इसे पहली बार देख रहे हैं, तो कृपया पासवर्ड उत्पन्न करने के लिए पासवर्ड जनरेटर का उपयोग करें और इसे यहां डालने से पहले सुरक्षित स्थान पर सहेजें।</string>\n    <string name=\"input_keystore_pass\">कीस्टोर पासवर्ड डालें</string>\n    <string name=\"splits\">स्प्लिट्स</string>\n    <string name=\"source_stamp_verified\">सोर्सस्टाम्प सत्यापित।</string>\n    <string name=\"not_verified\">सत्यापित नहीं</string>\n    <string name=\"verified\">सत्यापित</string>\n    <string name=\"pref_signature_schemes_msg\">कम से कम v1 और v2 को चुना जाना चाहिए अधिक कम्पेटिबिलिटी के लिए। v4 स्कीम के लिए v2 या v3 आवश्यक हैं।</string>\n    <string name=\"v4_scheme\">v4 स्कीम (एंड्रॉइड 11 के बाद से)</string>\n    <string name=\"v3_scheme\">v3 स्कीम (एंड्रॉइड 9 के बाद से)</string>\n    <string name=\"v2_scheme\">v2 स्कीम (एंड्रॉइड 7.0 के बाद से)</string>\n    <string name=\"v1_scheme\">v1 स्कीम (एंड्रॉइड 1.0 के बाद से)</string>\n    <string name=\"pref_apk_signing_msg\">सिग्नेचर स्कीम्स, कस्टम साइनिंग कुंजी आदि सेट करें।</string>\n    <string name=\"apk_signing\">एपीके साइनिंग</string>\n    <string name=\"pref_sign_apk_msg\">इंस्टॉल करने से पहले एपीके फाइल्स को साइन करें।</string>\n    <string name=\"pref_sign_apk\">साइन एपीके</string>\n    <string name=\"install_location_prefer_external\">एक्सटर्नल को वरीयता</string>\n    <string name=\"install_location_internal_only\">केवल इंटरनल</string>\n    <string name=\"install_location\">इंस्टॉल</string>\n    <string name=\"installer\">इंस्टालर</string>\n    <string name=\"comment\">कमेंट</string>\n    <string name=\"close\">बंद करे</string>\n    <string name=\"no_root\">नो</string>\n    <string name=\"root\">रुट</string>\n    <string name=\"user_profile_with_id\">प्रोफाइल: %1$s (%2$d)</string>\n    <string name=\"advanced\">एडवांस्ड</string>\n    <string name=\"simple\">सरल</string>\n    <string name=\"enabled\">सक्षम</string>\n    <string name=\"choose\">चुनें</string>\n    <string name=\"input_permissions_description\">रिक्त स्थान के साथ इनपुट अनुमतियां, उदा. <tt>com.permission.GET_ACCOUNTS android.permission.ACCESS_MEDIA_LOCATION</tt> आदि। सभी अनुमतियों के लिए आवेदन करने के लिए <tt>*</tt> का उपयोग करें।</string>\n    <string name=\"input_permissions\">अनुमतियाँ इनपुट</string>\n    <string name=\"options\">विकल्प</string>\n    <string name=\"off\">बंद</string>\n    <string name=\"on\">चालू करे</string>\n    <string name=\"profile_state_msg\">इस प्रोफ़ाइल के लिए कस्टम ऑन/ऑफ स्तिथि</string>\n    <string name=\"profile_block_trackers_msg\">ऐप्स में ट्रैकर्स को ब्लॉक करता है</string>\n    <string name=\"profile_clear_data_msg\">ऐप्स का डेटा साफ़ करता है</string>\n    <string name=\"profile_clear_cache_msg\">ऐप्स के ऐप कैश को साफ़ करता है</string>\n    <string name=\"profile_force_stop_msg\">फोर्स-स्टॉप ऐप्स</string>\n    <string name=\"allow_routine_ops_msg\">रूटीन ऑपरेशंस में प्रोफाइल का इस्तेमाल करने की अनुमति दें</string>\n    <string name=\"profile_state\">प्रोफाइल स्तिथि</string>\n    <string name=\"allow_routine_ops\">रूटीन ऑप्स की अनुमति दें</string>\n    <string name=\"adb_over_tcp\">टीसीपी पर एडीबी</string>\n    <string name=\"pref_mode_of_operations\">ऑपरेशन का तरीका</string>\n    <string name=\"send_selected\">चयनित भेजें</string>\n    <string name=\"ecc\">एलिप्टिक-कर्व क्रिप्टोग्राफी</string>\n    <string name=\"rsa\">RSA</string>\n    <string name=\"aes\">AES</string>\n    <string name=\"none\">कोई नहीं</string>\n    <string name=\"pref_encryption_msg\">बैकअप के लिए एन्क्रिप्शन।</string>\n    <string name=\"encryption\">एन्क्रिप्शन</string>\n    <string name=\"select_user\">यूज़र चुनें</string>\n    <string name=\"failed_to_duplicate_profile\">प्रोफाइल डुप्लीकेट नहीं कर सका</string>\n    <string name=\"duplicate\">डुप्लीकेट</string>\n    <string name=\"new_profile\">नई प्रोफ़ाइल</string>\n    <string name=\"input_profile_name_description\">प्रोफाइल नाम में कोई भी खाली स्थान नहीं हो सकता है।</string>\n    <string name=\"input_profile_name\">प्रोफाइल नाम</string>\n    <string name=\"send_crash_report\">क्रैश रिपोर्ट भेजें</string>\n    <string name=\"tap_to_submit_crash_report\">क्रैश रिपोर्ट सबमिट करने के लिए टैप करें।</string>\n    <string name=\"am_crashed\">ऐप मैनेजर क्रैश हो गया</string>\n    <plurals name=\"verified_with_warning\">\n        <item quantity=\"one\">%d चेतावनी के साथ सत्यापित</item>\n        <item quantity=\"other\">%d चेतावनियों के साथ सत्यापित</item>\n    </plurals>\n    <plurals name=\"app_signing_signature_schemes_pl\">\n        <item quantity=\"one\">सिग्नेचर स्कीम</item>\n        <item quantity=\"other\">सिग्नेचर स्कीम्स</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_set_app_ops\">\n        <item quantity=\"one\">%1$d ऐप के लिए ऐप ऑप्स सेट नहीं हो सका</item>\n        <item quantity=\"other\">%1$d ऐप के लिए ऐप ऑप्स सेट नहीं हो</item>\n    </plurals>\n    <plurals name=\"no_of_components\">\n        <item quantity=\"one\">%1$d कंपोनेंट</item>\n        <item quantity=\"other\">%1$d</item>\n    </plurals>\n    <string name=\"failed_to_enable_magisk_hide\">MagiskHide चालू नहीं हो सका</string>\n    <string name=\"failed_to_disable_magisk_hide\">MagiskHide बंद नहीं हो</string>\n    <string name=\"window_size\">विंडो साइज</string>\n    <string name=\"refresh_rate\">रिफ्रेश रेट</string>\n    <string name=\"scaling_factor\">स्केलिंग फैक्टर</string>\n    <string name=\"density\">डेंसिटी</string>\n    <string name=\"hardware\">हार्डवेयर</string>\n    <string name=\"permissive\">पर्मिसिव</string>\n    <string name=\"enforcing\">इंफ़ोरसिंग</string>\n    <string name=\"selinux\">सेलिनक्स</string>\n    <string name=\"patch_level\">पैच स्तर</string>\n    <string name=\"backup_skip_signature_checks_description\">उन बैकअप को पुनर्स्थापित करें जो या तो चेकसम सत्यापन को विफल करते हैं या उनके पिछले बैकअप की तुलना में भिन्न एपीके हस्ताक्षर हैं।</string>\n    <string name=\"backup_multiple_description\">बेस बैकअप के बजाय एक अलग <i>नामित</i> बैकअप बनाएं।</string>\n    <string name=\"backup_rules_description\">ऐप मैनेजर के भीतर कॉन्फ़िगर किए गए नियमों का बैकअप लें। <font fgcolor=\"#ff0000\">अनुमतियों के आधार पर, पुनर्स्थापना के दौरान सभी नियमों को दोबारा लागू नहीं किया जा सकता है।</font> </string>\n    <string name=\"backup_extras_description\">ऐप अनुमतियां, बैटरी की बचत, डेटा उपयोग विकल्प, मैजिस्कहाइड स्थिति, SSAID, आदि बैकअप करें। <font fgcolor=\"#ff0000\"> अनुमतियों के आधार पर, सभी अतिरिक्त सुविधाएं बहाल नहीं की जा सकतीं।</font></string>\n    <string name=\"backup_extras\">एक्स्ट्रास</string>\n    <string name=\"backup_cache_description\"><b>cache</b>, <b>no_cache</b> और <b>no_backup</b> फ़ोल्डर का बैकअप न करें।</string>\n    <string name=\"backup_obb_media_description\">ओबीबी और मीडिया फ़ोल्डर्स बैकअप करें।</string>\n    <string name=\"backup_external_data_description\">बाहरी डेटा फ़ोल्डरों का बैकअप लें।</string>\n    <string name=\"backup_internal_data_description\">डेटा फ़ोल्डर्स बैकअप करें। अगर चयनित किया तो इंटरनल डेटा फ़ोल्डर्स को भी बैकअप किया जाएगा।</string>\n    <string name=\"user_with_id\">यूजर: <xliff:g id=\"user_id\" example=\"0\">%1$d</xliff:g></string>\n    <string name=\"app_signing_signatures\">हस्ताक्षर</string>\n    <string name=\"pref_default_log_level_summary\">लॉग स्तर शुरुआत पर, फाइलें खोलते समय और रिकॉर्डिंग करते समय।</string>\n    <string name=\"pref_cat_configuration\">कॉन्फ़िगरेशन</string>\n    <string name=\"pref_cat_appearance\">दिखावट</string>\n    <plurals name=\"usage_seconds\">\n        <item quantity=\"one\">%1$d सेकंड</item>\n        <item quantity=\"other\">%1$d सेकंड</item>\n    </plurals>\n    <string name=\"text_filter_text\">टैक्सट को फ़िल्टर करें</string>\n    <string name=\"send_log_title\">इस्तेमाल की जानकारी भेजो</string>\n    <string name=\"start_recording_log\">अभिलेख</string>\n    <string name=\"text_filter_ellipsis\">फिल्टर…</string>\n    <string name=\"swap\">विनिमय</string>\n    <string name=\"settings\">समायोजन</string>\n    <plurals name=\"usage_minutes\">\n        <item quantity=\"one\">%1$d मिनट</item>\n        <item quantity=\"other\">%1$d मिनट</item>\n    </plurals>\n    <string name=\"subject_log_report\">इस्तेमाल का विवरण</string>\n    <string name=\"community\">कम्युनिटी</string>\n    <string name=\"community_links\"><a href=\"https://matrix.to/#/#appmanager:matrix.org\">मैट्रिक्स</a> • <a href=\"https://t.me/AppManagerChannel\">टेलीग्राम</a> • <a href=\"https://twitter.com/AppManagerNews\">ट्विटर</a></string>\n    <string name=\"failed_to_uninstall_app\">अनइंस्टॉल विफल</string>\n    <string name=\"input_keystore_alias_pass_msg\">%1$s के लिए पासवर्ड प्रदान करने के लिए यहाँ टैप करें</string>\n    <string name=\"internal_data\">आंतरिक डेटा</string>\n    <string name=\"pref_backup_volume_msg\">उस वॉल्यूम या डिस्क का चयन करें जहां बैकअप स्टोर की जाएंगी।</string>\n    <string name=\"size\">आकार</string>\n    <string name=\"screen\">स्क्रीन</string>\n    <string name=\"action\">कार्रवाई</string>\n    <string name=\"disable_background_run_description\">निम्नलिखित ऐप ऑप्स के लिए <i>अनदेखा</i> मोड सेट करता है: <tt>RUN_IN_BACKGROUND</tt> (Android 7.0 से) और <tt>RUN_ANY_IN_BACKGROUND</tt> (Android 9 से)।</string>\n    <string name=\"input_app_ops_description_profile\">इनपुट ऐप सेशन नाम और/या रिक्त स्थान के साथ स्थिरांक, उदा। <tt>WAKE_LOCK 63 72 CAMERA</tt> आदि। सभी कॉन्फ़िगर किए गए ऐप ऑप्स के लिए आवेदन करने के लिए <tt>*</tt> का उपयोग करें।</string>\n    <string name=\"app_signing_signature_schemes\">हस्ताक्षर योजनाएं</string>\n    <string name=\"pref_backup_restore_msg\">बैकअप/पुनर्स्थापना अनुकूलित करें।</string>\n    <string name=\"source_code_links\"><a href=\"https://github.com/MuntashirAkon/AppManager\">GitHub</a> • <a href=\"https://gitlab.com/muntashir/AppManager\">GitLab</a> • <a href=\"https://0xacab.org/muntashir/AppManager\">Riseup</a> • <a href=\"https://codeberg.org/muntashir/AppManager\">Codeberg</a></string>\n    <string name=\"no_volumes_found\">लिखित अनुमति के साथ कोई वॉल्यूम नहीं मिला।</string>\n    <string name=\"backup_volume\">बैकअप वॉल्यूम</string>\n    <string name=\"encrypted\">एन्क्रिप्टेड</string>\n    <string name=\"unencrypted\">अनएन्क्रिप्टड</string>\n    <string name=\"backup_apps_with_changes_msg\">पिछले बैकअप के बाद से परिवर्तनों वाले ऐप्स के लिए बैकअप फिर से करें। उनमें आकार, संस्करण, अंतिम लॉन्च समय में परिवर्तन शामिल हैं।</string>\n    <string name=\"enable_battery_optimization\">बैटरी अनुकूलन सक्षम करें\\?</string>\n    <string name=\"backup_apps_without_backups\">बैकअप के बिना ऐप्स का बैकअप लें</string>\n    <string name=\"redo_existing_backups\">मौजूदा बैकअप फिर से करें</string>\n    <string name=\"redo_existing_backups_msg\">पिछले बैकअप के साथ इंस्टॉल किए गए ऐप्स के लिए बैकअप फिर से करें।</string>\n    <string name=\"backup_apps_with_changes\">परिवर्तनों के साथ ऐप्स का बैकअप लें</string>\n    <string name=\"restore_latest\">नवीनतम बैकअप पुनर्स्थापित करें</string>\n    <string name=\"restore_not_installed_msg\">उन ऐप्स के लिए बेस बैकअप पुनर्स्थापित करें जो वर्तमान में इंस्टॉल नहीं हैं।</string>\n    <string name=\"backup_msg\">डेटा के साथ ऐप्स का बैकअप लें</string>\n    <string name=\"drm_free_apkm_msg\">एपीकेएम फाइल डीआरएम मुक्त है, इसे एपीकेएस में बदलने की जरूरत नहीं है।</string>\n    <string name=\"choose_what_to_do\">चुनें कि क्या करना है।</string>\n    <string name=\"add_to_profile\">प्रोफ़ाइल में जोड़ें</string>\n    <string name=\"enable_disable_features\">सुविधाएँ सक्षम/अक्षम करें</string>\n    <string name=\"pref_enable_disable_features_msg\">ऐप मैनेजर में सुविधाओं को सक्षम या अक्षम करें।</string>\n    <string name=\"input_key\">इनपुट कुंजी (हेक्साडेसिमल में)</string>\n    <string name=\"installer_app_message\">इंस्टॉल किए गए ऐप्स में से चुनने के लिए <b> चुनें </b> चुनें या कस्टम पैकेज नाम निर्दिष्ट करने के लिए <b> कस्टम </b> का चयन करें।</string>\n    <string name=\"key_not_set\">निर्धारित नहीं है।</string>\n    <string name=\"internal_storage\">आंतरिक स्टोरेज</string>\n    <string name=\"battery_optimization\">बैटरी अनुकूलन</string>\n    <string name=\"installed_apps\">इंस्टॉल किए गए ऐप्स</string>\n    <string name=\"uninstalled_apps\">अनइंस्टॉल किए गए ऐप्स</string>\n    <string name=\"add\">जोड़ें</string>\n    <string name=\"unlock_app_manager\">ऐप मैनेजर अनलॉक करें</string>\n    <string name=\"backup_custom_users_description\">केवल निर्दिष्ट उपयोगकर्ताओं के लिए बैकअप निष्पादित करें</string>\n    <string name=\"type_long_array_list\">लंबे पूर्णांकों की सूची</string>\n    <string name=\"restore_all_msg\">सभी बैकअप किए गए ऐप्स से आधार(बेस) बैकअप पुनर्स्थापित करें।</string>\n    <string name=\"type_string_array_list\">स्ट्रिंग्स की सूची</string>\n    <string name=\"failed_to_initialize_key_store\">ऐप मैनेजर कीस्टोर को प्रारंभ नहीं किया जा सका।</string>\n    <string name=\"type_long_array\">लंबे पूर्णांकों की सरणी</string>\n    <string name=\"copied_to_clipboard\">क्लिपबोर्ड पर कॉपी किया गया.</string>\n    <string name=\"no_battery_optimization\">कोई बैटरी अनुकूलन नहीं</string>\n    <string name=\"list_options\">सूची विकल्प</string>\n    <string name=\"os_version\">ओएस संस्करण</string>\n    <string name=\"verify_and_redo_backups_msg\">पिछले बैकअप की अखंडता की जाँच करें और बैकअप को फिर से करें जिसके लिए अखंडता जाँच विफल हो जाती है।</string>\n    <string name=\"invalid_rsa_key_size\">आरएसए एन्क्रिप्शन के लिए अमान्य कुंजी आकार। कुंजी आकार 1024, 2048 या 4096 बिट्स हो सकता है।</string>\n    <string name=\"type_int_array\">पूर्णांकों की सरणी</string>\n    <string name=\"backup_all_apps\">सभी ऐप्स का बैकअप करें</string>\n    <string name=\"restore_msg\">डेटा के साथ ऐप्स को पुनर्स्थापित करें</string>\n    <string name=\"filter_apps_without_backups\">बैकअप के बिना</string>\n    <string name=\"verified_using_unreliable_hash\">अविश्वसनीय हैश का उपयोग करके सत्यापित किया गया</string>\n    <string name=\"backup_apps_without_backups_msg\">बिना किसी पिछले बैकअप के ऐप्स का बैकअप लें।</string>\n    <string name=\"type_component_name\">घटक का नाम</string>\n    <string name=\"backup_all_apps_msg\">सभी इंस्टॉल किए गए ऐप्स का बैकअप लें।</string>\n    <string name=\"restore_all\">सभी ऐप्स को पुनर्स्थापित करें</string>\n    <string name=\"restore_latest_msg\">पहले से इंस्टॉल किए गए ऐप्स को पुनर्स्थापित करें जिनके संस्करण कोड इंस्टॉल किए गए संस्करण कोड से अधिक हैं।</string>\n    <string name=\"crypto_key_size\">कुंजी आकार</string>\n    <string name=\"bootloader\">बूटलोडर</string>\n    <string name=\"type_float_array_list\">दशमलव संख्याओं की सूची</string>\n    <string name=\"verify_and_redo_backups\">बैकअप सत्यापित करें और फिर से करें</string>\n    <string name=\"failed_to_change_ssaid\">एसएसएआईडी को नहीं बदला जा सका</string>\n    <string name=\"backup_custom_users\">कस्टम उपयोगकर्ता</string>\n    <string name=\"sd_card\">एसडी कार्ड</string>\n    <string name=\"type_null\">कोई वैल्यू नहीं</string>\n    <string name=\"type_int_array_list\">पूर्णांकों की सूची</string>\n    <string name=\"reverse\">रिवर्स</string>\n    <string name=\"isolated\">पृथक</string>\n    <string name=\"specify_custom_name\">कस्टम</string>\n    <string name=\"type_string_array\">स्ट्रिंग्स की सरणी</string>\n    <string name=\"initializing\">प्रारंभ किया जा रहा है…</string>\n    <string name=\"last_actions\">अंतिम क्रियाएँ</string>\n    <string name=\"restore_not_installed\">इंस्टॉल नहीं किए गए ऐप्स को पुनर्स्थापित करें</string>\n    <string name=\"type_float_array\">दशमलव संख्याओं की सरणी</string>\n    <string name=\"has_net_policy\">नेट नीति</string>\n    <string name=\"net_policy\">नेट नीति</string>\n    <string name=\"ssaid\">एसएसएआईडी</string>\n    <string name=\"ssaid_info\">SSAID (<tt> Settings.Secure.ANDROID_ID</tt>) एक उपकरण पहचानकर्ता है जिसे प्रत्येक ऐप को सौंपा गया है (Android 8 \\\"Oreo\\\" से आगे)। यह उपयोगकर्ताओं को ट्रैक करने के लिए ऐप्स द्वारा व्यापक रूप से उपयोग किया जाता है।</string>\n    <string name=\"restart_to_reflect_changes\">आपको तुरंत नए बदलावों का उपयोग करने के लिए डिवाइस को पुनरारंभ करना होगा।</string>\n    <string name=\"screen_lock_not_enabled\">कृपया एंड्रॉइड सेटिंग्स में स्क्रीन लॉक चुनें, या ऐप डेटा साफ़ करें।</string>\n    <string name=\"invalid_aes_key_size\">एइएस एन्क्रिप्शन के लिए अमान्य कुंजी आकार। कुंजी आकार या तो 128 या 256 बिट्स हो सकता है।</string>\n    <string name=\"use_default\">डिफ़ॉल्ट उपयोग करें</string>\n    <string name=\"failed_to_load_key\">कुंजी लोड नहीं की जा सकी।</string>\n    <string name=\"screen_lock\">स्क्रीन लॉक</string>\n    <string name=\"screen_lock_msg\">एंड्राइड स्क्रीन लॉक का उपयोग करके ऐप मैनेजर लॉक करें</string>\n    <string name=\"back_up\">बैकअप</string>\n    <string name=\"working_on_adb_mode\">ADB मोड पर कार्य कर रहा है</string>\n    <string name=\"type_uri\">यूआरआई</string>\n    <string name=\"failed_to_save_key\">कुंजी सहेजी नहीं जा सकी।</string>\n    <string name=\"generate_key\">उत्पन्न करें</string>\n    <string name=\"external_storage\">बाहरी स्टोरेज</string>\n    <string name=\"pref_import_backups_msg\">ओएंडबैकअप, स्विफ्ट बैकअप (3.0-3.2) या टाइटेनियम बैकअप से बैकअप आयात करें।</string>\n    <string name=\"pref_import_backups\">बैकअप आयात करें</string>\n    <string name=\"keystore_pass\">कीस्टोर पासवर्ड</string>\n    <string name=\"locality_name\">इलाके (शहर) का नाम (एल)</string>\n    <string name=\"pkcs12_keystore\">पीकेसीएस # 12 कीस्टोर (पी 12)</string>\n    <string name=\"country_name\" tools:ignore=\"TypographyOther\">देश का नाम (सी)</string>\n    <string name=\"new_alias_password\">नया उपनाम पासवर्ड</string>\n    <string name=\"keystore_file\">कीस्टोर फ़ाइल</string>\n    <string name=\"java_keystore\">जावा कीस्टोर (जेकेएस)</string>\n    <string name=\"signing_key\">हस्ताक्षर कुंजी</string>\n    <string name=\"expiry_date_cannot_be_empty\">समाप्ति तिथि रिक्त नहीं हो सकता.</string>\n    <string name=\"pref_installer_msg\">ऐप इंस्टॉलर के व्यवहार को कॉन्फ़िगर करें।</string>\n    <string name=\"pk8_file\">पीकेसीएस # 8 (पीके 8) फाइल</string>\n    <string name=\"log_level_warn\">चेतावनी दें</string>\n    <string name=\"import_key\">आयात कुंजी</string>\n    <string name=\"log_viewer\">लॉग व्यूअर</string>\n    <string name=\"log_level_error\">त्रुटि</string>\n    <string name=\"import_from_oab\">ओएंडबैकअप से आयात करें</string>\n    <string name=\"found_no_alias_in_keystore\">कीस्टोर में कोई उपनाम नहीं मिला!</string>\n    <string name=\"import_from_tb\">टाइटेनियम बैकअप से आयात करें</string>\n    <string name=\"log_level_debug\">डीबग</string>\n    <string name=\"pref_log_viewer_msg\">कॉन्फ़िगर करें कि लॉग कैसे प्रदर्शित हों।</string>\n    <string name=\"log_level_verbose\">शब्दाडंबरपूर्ण</string>\n    <string name=\"bouncy_castle_keystore\">बाउंसी कैसल कीस्टोर (बीकेएस)</string>\n    <string name=\"pem_file\">पीईएम फ़ाइल</string>\n    <string name=\"alias_pass\">उपनाम पासवर्ड</string>\n    <string name=\"state_name\">राज्य का नाम (एसटी)</string>\n    <string name=\"failed_to_read_keystore\">कीस्टोर नहीं पढ़ सका।</string>\n    <string name=\"pem_and_pk8\">पीईएम और पीकेसीएस # 8 (पीके 8)</string>\n    <string name=\"input_key_password\">कुंजी पासवर्ड</string>\n    <string name=\"organization_unit\">संगठन इकाई (ओयू)</string>\n    <string name=\"organization_name\">संगठन का नाम (ओ)</string>\n    <string name=\"restart_log_viewer_to_see_changes\">परिवर्तन देखने के लिए लॉग व्यूअर विंडो पुनरारंभ करें।</string>\n    <string name=\"filename\">फ़ाइल का नाम</string>\n    <string name=\"log_level_info\">जानकारी</string>\n    <string name=\"choose_an_alias\">उपनाम चुनें</string>\n    <string name=\"common_name\">सामान्य नाम (सीएन)</string>\n    <string name=\"filter_choice_tag\">टैग</string>\n    <string name=\"log_cleared\">लॉग साफ़ किए गए</string>\n    <string name=\"copy_to_clipboard\">क्लिपबोर्ड पर कापी करें</string>\n    <string name=\"open\">खोलें</string>\n    <string name=\"filter_choice\">खोज से</string>\n    <string name=\"filter_choice_pid\">PID</string>\n    <string name=\"second_degree_tracker_note\">² उपसर्ग इंगित करता है कि ट्रैकर <a href=\"https://etip.exodus-privacy.eu.org/\">ETIP स्टैंड-बाय सूची</a> में हैं, यानी वे वास्तविक ट्रैकर हैं या नहीं, इसकी अभी भी जांच की जा रही है।</string>\n    <string name=\"add_filter\">फ़िल्टर जोड़ें</string>\n    <string name=\"add_filter_ellipsis\">फ़िल्टर जोड़ें…</string>\n    <string name=\"dialog_compiling_log\">लॉग संकलित किया जा रहा है…</string>\n    <string name=\"enter_filename\">फ़ाइल नाम दर्ज करें</string>\n    <string name=\"notification_subtext\">रिकॉर्डिंग रोकने के लिए स्पर्श करें</string>\n    <string name=\"notification_ticker\">लॉग रिकॉर्डिंग प्रारंभ हुई</string>\n    <string name=\"pref_buffer_title\">लॉग बफ़र (ओं)</string>\n    <string name=\"pref_cat_advanced\">उन्नत</string>\n    <string name=\"notification_title\">लॉग रिकॉर्डिंग प्रगति पर है</string>\n    <string name=\"log_level_fatal\">घातक</string>\n    <string name=\"enter_good_filename\">कृपया कोई मान्य फ़ाइल नाम दर्ज करें।</string>\n    <string name=\"delete_saved_log\">सहेजे गए लॉग हटाएँ</string>\n    <string name=\"pref_block_trackers_msg\">ऐप मैनेजर का उपयोग करके ऐप इंस्टॉल करने के बाद ट्रैकिंग घटकों को ब्लॉक करें।</string>\n    <string name=\"pref_default_log_level_title\">डिफ़ॉल्ट लॉग स्तर</string>\n    <plurals name=\"file_deletion_confirmation\">\n        <item quantity=\"one\">%d फ़ाइल हटा दी जाएगी</item>\n        <item quantity=\"other\">%d फ़ाइलें हटा दी जाएगी</item>\n    </plurals>\n    <string name=\"next\">अगला</string>\n    <string name=\"log_recording_started\">लॉग का लिखना शुरू है.</string>\n    <string name=\"log_saved\">लॉगो का बचत हुआ है.</string>\n    <string name=\"no_saved_logs\">लॉगस नहीं है.</string>\n    <string name=\"manage_saved_logs\">बचाया गए हुए लॉगस को मैनेज करे</string>\n    <string name=\"log_level\">लॉग स्तर</string>\n    <string name=\"source_stamp_verified_and_identified_to_be_from_source\">सोर्स स्टैम्प <xliff:g id=\"source\" example=\"Google Play\">%1$s</xliff:g> से है ऐसा पहचाना और सत्यापित किया गया है।</string>\n    <string name=\"pref_display_limit_summary\" tools:ignore=\"PluralsCandidate\">सिर्फ पिछले %1$d लॉगस दिखाओ ताकि \\'आउट ऑफ मेमोरी\\' से बचे.</string>\n    <string name=\"pref_filter_pattern_title\">टॉगस छान निकाले</string>\n    <string name=\"pref_display_limit_title\">लॉगस का प्रदर्शन सीमा</string>\n    <string name=\"pref_filter_pattern_summary\">चुनित टाॅगस को जान निकले.</string>\n    <string name=\"pref_show_timestamp_title\">Pid और समय चिन्ह को दिखाएं</string>\n    <string name=\"pref_expanded_by_default_summary\">शुरू से हर लॉग को पूरा दिखाओ.</string>\n    <plurals name=\"toast_log_truncated\">\n        <item quantity=\"one\">लोग बहुत बड़ा था, सिर्फ अंत का %d पंक्ति दिखेगा.</item>\n        <item quantity=\"other\">लोग बहुत बड़ा था, सिर्फ अंत के %d पंक्तियाँ दिखेगा.</item>\n    </plurals>\n    <string name=\"pref_log_line_period_error\">1 और 1000 के बीच कोई पूर्ण अंक डालिए.</string>\n    <string name=\"pref_expanded_by_default_title\">शुरू से पुलाओ</string>\n    <string name=\"save_log\">लॉग सेव करे</string>\n    <string name=\"file\">फाईल</string>\n    <string name=\"omit_sensitive_info\">गुप्त डेटा को छोड़ो</string>\n    <string name=\"undo\">वापसी</string>\n    <string name=\"collapse_all\">सब सिकोड़े</string>\n    <string name=\"save_as\">ऐसे सेव करे…</string>\n    <string name=\"unable_to_save_log\">लॉग सेव नहीं हुआ है. क्या फाईल का नाम सही था\\?</string>\n    <string name=\"expand_all\">सब पुलाओ</string>\n    <string name=\"pref_log_write_period_summary\" tools:ignore=\"PluralsCandidate\">रिकॉर्डिंग के समय, हर %1$d लाइन के बाद SD कार्ड में दर्ज कीजिए.</string>\n    <string name=\"text_include_device_info\">यंत्र का जानकारी जोड़ों</string>\n    <string name=\"widget_recording_in_progress\">रिकॉर्डिंग चालू है…</string>\n    <string name=\"pref_show_timestamp_summary\">फूलने पर प्रक्रिया पहचान अंक और संबंधित समय चिन्ह को दिखाएं.</string>\n    <string name=\"record_log\">लॉग को रिकार्ड करे</string>\n    <string name=\"toast_invalid_level\">ये नाम मान्य नहीं है: %s</string>\n    <string name=\"toast_invalid_selection\">गलत चुनाव. वापिस चुनिए.</string>\n    <string name=\"pause_unpause\">चलाओ/रूकाओ</string>\n    <string name=\"pref_log_write_period_title\">लिखने की कालावधि</string>\n    <string name=\"pref_display_limit_hint\" tools:ignore=\"PluralsCandidate\">%1$d और %2$d के बीच कोई पूर्ण अंक डालिए.</string>\n    <string name=\"widget_start_recording\">रिकॉर्ड\n\\nलॉग</string>\n    <string name=\"view_logs\">लॉग्स देखे</string>\n    <string name=\"share_log\">भेजे</string>\n    <string name=\"action_checking\">जाँच की जा रही है…</string>\n    <string name=\"report_not_available\">उपलब्ध नहीं है</string>\n    <string name=\"latest_backup\">नवीनतम बैकअप</string>\n    <string name=\"hidden\">छिपा हुआ</string>\n    <string name=\"confirm_import_keystore\">क्या आप निश्चित रूप से मौजूदा कीस्टोर को बदलना चाहते हैं? इस क्रिया को पूर्ववत नहीं किया जा सकता।</string>\n    <string name=\"netpolicy_reject_wifi_data\">वाई-फ़ाई डेटा अस्वीकार करें</string>\n    <plurals name=\"alert_failed_to_unblock_components\">\n        <item quantity=\"one\">%1$d ऐप के लिए घटकों को अनब्लॉक नहीं किया जा सका</item>\n        <item quantity=\"other\">%1$d ऐप्स के लिए घटकों को अनब्लॉक नहीं किया जा सका</item>\n    </plurals>\n    <string name=\"failed\">असफल</string>\n    <plurals name=\"alert_failed_to_import_backups\">\n        <item quantity=\"one\">%1$d बैकअप आयात नहीं किया जा सका</item>\n        <item quantity=\"other\">%1$d बैकअप आयात नहीं किए जा सके</item>\n    </plurals>\n    <string name=\"netpolicy_reject_metered_background_data\">मीटर्ड नेटवर्क पर पृष्ठभूमि डेटा अस्वीकार करें</string>\n    <string name=\"netpolicy_reject_metered_data\">मीटर्ड नेटवर्क पर डेटा अस्वीकार करें</string>\n    <string name=\"netpolicy_allow_metered_background_data\">डेटा सेवर चालू होने पर भी मीटर्ड नेटवर्क पर पृष्ठभूमि डेटा की अनुमति दें</string>\n    <string name=\"orientation_left_to_right\">बाएँ से दाएँ</string>\n    <string name=\"block_unblock_components_dots\">घटकों को ब्लॉक/अनब्लॉक करें…</string>\n    <string name=\"unblock_components_dots\">घटकों को अनब्लॉक करें…</string>\n    <string name=\"block_unblock_components_description\">दिए गए हस्ताक्षरों द्वारा पहचाने गए सभी घटकों को ब्लॉक या अनब्लॉक करें</string>\n    <string name=\"omit_sensitive_info_summary\">वेब यूआरएल, फ़ोन नंबर या ईमेल जैसी संवेदनशील जानकारी छोड़ दें।</string>\n    <string name=\"text_include_dmesg\">कर्नेल लॉग शामिल करें</string>\n    <string name=\"failed_to_block_trackers\">ट्रैकर्स को ब्लॉक नहीं किया जा सका</string>\n    <string name=\"failed_to_unblock_trackers\">ट्रैकर्स को अनब्लॉक नहीं किया जा सका</string>\n    <string name=\"trackers_blocked_successfully\">ट्रैकर्स अब ब्लॉक कर दिए गए हैं</string>\n    <string name=\"pgp_aes_rsa_encrypted\">%1$s एन्क्रिप्ट किया गया</string>\n    <string name=\"trackers_unblocked_successfully\">ट्रैकर्स अब अनब्लॉक हो गए हैं</string>\n    <string name=\"base_backup\">बेस बैकअप</string>\n    <string name=\"no_encryption\">कोई एनक्रिप्शन नहीं</string>\n    <string name=\"gz_bz2_compressed\">%1$s संकुचित</string>\n    <string name=\"pref_rules_msg\">तत्काल अवरोधन, आयात/निर्यात/नियम निकालें आदि।</string>\n    <string name=\"pref_layout_direction\">लेआउट की दिशा</string>\n    <string name=\"orientation_follow_locale\">लोकेल का पालन करें</string>\n    <string name=\"pref_display_changes\">बदलाव प्रदर्शित करें</string>\n    <string name=\"pref_display_changes_msg\">संस्करण, ट्रैकर्स, घटकों, अनुमतियों, हस्ताक्षरों, SDK आदि में परिवर्तनों को संस्करण नियंत्रित तरीके से प्रदर्शित करें।</string>\n    <string name=\"no_changes\">कोई परिवर्तन नहीं</string>\n    <string name=\"port_number\">पोर्ट</string>\n    <string name=\"unknown_net_policy\">अज्ञात नेटपॉलिसी (%1$s - %2$X)</string>\n    <string name=\"failed_to_prevent_background_run\">%1$s को पृष्ठभूमि में चलने से रोका नहीं जा सका</string>\n    <string name=\"suspended\">निलंबित</string>\n    <string name=\"port_number_empty\">पोर्ट संख्या रिक्त है।</string>\n    <string name=\"netpolicy_disable_network_access\">नेटवर्क पहुँच अक्षम करें</string>\n    <string name=\"adb_connect\">जुड़ें</string>\n    <string name=\"pref_import_export_keystore_msg\">ऐप मैनेजर द्वारा आंतरिक रूप से उपयोग किए जाने वाले बाउंसी कैसल कीस्टोर (बीकेएस) को आयात/निर्यात करें।</string>\n    <string name=\"import_keystore\">कीस्टोर आयात करें</string>\n    <string name=\"orientation_right_to_left\">दाएँ से बाएँ</string>\n    <string name=\"running_services\">चलित सेवाएं</string>\n    <string name=\"save_apk\">APK सहेजें</string>\n    <string name=\"pref_import_export_keystore\">कीस्टोर आयात/निर्यात</string>\n    <string name=\"netpolicy_reject_background_data\">पृष्ठभूमि डेटा अस्वीकार करें</string>\n    <string name=\"netpolicy_allow_background_data\">डेटा सेवर चालू होने पर पृष्ठभूमि डेटा की अनुमति दें</string>\n    <string name=\"wireless_debugging\">वायरलेस डिबगिंग</string>\n    <string name=\"help_app_ops_tab\">किसी आइटम को <b>अनुमति</b> देने या <b>अनदेखा</b> करने के लिए उस पर क्लिक करें। अन्य समर्थित मोड देखने के लिए किसी आइटम पर लंबे समय तक क्लिक करें।</string>\n    <string name=\"help_permissions_tab\">ये अनुमतियाँ इस ऐप द्वारा निर्धारित की गई हैं और इन्हें रद्द नहीं किया जा सकता।</string>\n    <string name=\"port_number_invalid\">अमान्य पोर्ट संख्या।</string>\n    <string name=\"netpolicy_reject_cellular_data\">सेलुलर डेटा अस्वीकार करें</string>\n    <string name=\"netpolicy_reject_vpn_data\">वीपीएन डेटा अस्वीकार करें</string>\n    <string name=\"notice\">सूचना</string>\n    <string name=\"profile_save_apk_msg\"><tt>AppManager/apks</tt> में APK फ़ाइलें सहेजता है</string>\n    <string name=\"help_uses_permissions_tab\">किसी आइटम को <b>अनुमति</b> देने या <b>निरस्त</b> करने के लिए उस पर क्लिक करें। केवल <b>ख़तरनाक</b> और <b>विकास</b> अनुमतियाँ ही दी या रद्द की जा सकती हैं।</string>\n    <string name=\"added_to_queue\">कतार में जोड़ा गया</string>\n    <string name=\"saved_filters\">सहेजे गए फ़िल्टर</string>\n    <string name=\"error_with_details\">त्रुटि : %s</string>\n    <string name=\"pref_selected_users_msg\">App Manager को केवल चयनित उपयोगकर्ताओं के साथ काम करने के लिए प्रतिबंधित करें।</string>\n    <string name=\"notice_saf\">वॉल्यूम के विपरीत, चयनित निर्देशिका का उपयोग ऐप मैनेजर से संबंधित सभी फ़ाइलों को संग्रहीत करने के लिए किया जाएगा, जिसमें सहेजे गए APK और बैकअप शामिल हैं। स्टोरेज एक्सेस फ्रेमवर्क (SAF) बहुत धीमा है इसलिए आपको इस विकल्प का उपयोग केवल तभी करना चाहिए जब अन्य का उपयोग नहीं किया जा सकता है।</string>\n    <string name=\"pref_selected_users\">चयनित उपयोगकर्ता</string>\n    <string name=\"files\">फ़ाइलें</string>\n    <string name=\"paste\">पेस्ट करें</string>\n    <string name=\"storage\">स्टोरेज</string>\n    <string name=\"backup_volume_dialog_description\"><tt>/tree</tt> उपसर्ग वाले वॉल्यूम स्टोरेज एक्सेस फ़्रेमवर्क (SAF) का उपयोग करके चुने गए फ़ोल्डर हैं। इन फ़ोल्डरों को छोड़कर, ऐप मैनेजर के लिए डिफ़ॉल्ट निर्देशिका <tt>AppManager</tt> नामक एक सबफ़ोल्डर है।</string>\n    <string name=\"adb_pair\">जोड़ा</string>\n    <string name=\"paired_successfully\">जोड़ा गया।</string>\n    <string name=\"set_package_name_first\">पहले पैकेज का नाम निर्धारित करें!</string>\n    <string name=\"keystore_password_info\">निम्नलिखित ऐप मैनेजर कीस्टोर पासवर्ड है। यदि आप ऐप मैनेजर कीस्टोर का बैकअप/पुनर्स्थापना करने जा रहे हैं तो कृपया इसे सुरक्षित स्थान पर संग्रहीत करें। <b>यह संदेश फिर से प्रदर्शित नहीं किया जाएगा।</b></string>\n    <string name=\"keystore_pass_cannot_be_empty\">कीस्टोर पासवर्ड खाली नहीं हो सकता।</string>\n    <string name=\"invalid_password\">अमान्य पासवर्ड, पुन: प्रयास करें।</string>\n    <string name=\"identifier\">पहचानकर्ता</string>\n    <string name=\"trim_caches_in_all_apps_description\">एंड्रॉइड सिस्टम सहित सभी एप्लिकेशन से कैशे फ़ाइलें हटा देता है</string>\n    <string name=\"minimum_version\">न्यूनतम संस्करण: %d</string>\n    <string name=\"permission_flags\">अनुमति ध्वज</string>\n    <string name=\"background\">पृष्ठभूमि</string>\n    <string name=\"adb_connect_port_number_description\">पोर्ट नंबर <b>आईपी पता और पोर्ट</b> अनुभाग के अंतर्गत <b>डिवाइस नाम</b> अनुभाग के ठीक नीचे स्थित है।</string>\n    <string name=\"java\">जावा</string>\n    <string name=\"rename\">नाम बदलें</string>\n    <string name=\"pref_default_blocking_method\">डिफ़ॉल्ट अवरोधन विधि</string>\n    <string name=\"search_type_suffix\">प्रत्यय</string>\n    <string name=\"search_type_regular_expressions\">नियमित अभिव्यक्ति</string>\n    <string name=\"vt_checking\">वायरसटोटल: जाँच हो रही है…</string>\n    <string name=\"vt_failed\">वायरसटोटल: विफल</string>\n    <string name=\"vt_success\">वायरसटोटल: %1$d/%2$d</string>\n    <string name=\"toggle_internet\">इंटरनेट का प्रयोग करें</string>\n    <string name=\"pref_thread_count\">समानांतर क्रियान्वयन</string>\n    <string name=\"running_services_logcat_hint\">डिफ़ॉल्ट फ़िल्टर के रूप में संबंधित प्रक्रिया आईडी के साथ लॉग व्यूअर खोलने के लिए किसी आइटम पर क्लिक करें।</string>\n    <string name=\"import_from_sb\">स्विफ्ट बैकअप 3.0 – 3.2 से आयात करें</string>\n    <string name=\"smali\">स्मालि</string>\n    <string name=\"extract\">निकालें</string>\n    <string name=\"search_type_contains\">शामिल है</string>\n    <string name=\"vt_uploading\">वायरसटोटल: अपलोड हो रहा है…</string>\n    <string name=\"vt_slowness_warning\">इंटरनेट की गति और सर्वर पर लोड के आधार पर इसमें कुछ समय लग सकता है।</string>\n    <string name=\"search_type_prefix\">उपसर्ग</string>\n    <string name=\"replace\">प्रतिस्थापन</string>\n    <string name=\"exit_confirmation\">प्रस्थान की पुष्टि</string>\n    <string name=\"vt_scan_date\">स्कैन तिथि: %1$s</string>\n    <string name=\"vt_permalink\">वायरसटोटल का स्थायी लिंक</string>\n    <string name=\"explore\">अन्वेषण करें</string>\n    <string name=\"system_partition\">एंड्रॉइड रूट</string>\n    <string name=\"pref_default_blocking_method_description\">डिफ़ॉल्ट रूप से उन जगहों पर उपयोग की जाने वाली विधि जहाँ अवरोधन विधि चुनने का कोई विकल्प नहीं है।\\n<b>नोट:</b> “IFW” प्रदाताओं के साथ काम नहीं करता है, इसके बजाय “अक्षम” का उपयोग किया जाता है।</string>\n    <string name=\"authenticating\">प्रमाणिकरण…</string>\n    <string name=\"pid\">प्रक्रिया आईडी</string>\n    <string name=\"pref_thread_count_hint\">मान 0 से %1$d के बीच होना चाहिए, जहाँ 0 का अर्थ है <i>दिए गए समय पर संचालन की अधिकतम संख्या</i>।</string>\n    <string name=\"pref_import_backups_hint\">बैकअप फ़ाइलें (स्विफ्ट बैकअप/टाइटेनियम बैकअप) या निर्देशिकाएँ (OAndBackup) वाली निर्देशिका का चयन करें</string>\n    <string name=\"pref_intent_firewall_and_disable_description\">इंटेंट फ़ायरवॉल का उपयोग करके घटकों को ब्लॉक करें और साथ ही उन्हें अक्षम भी करें। रूट उपयोगकर्ताओं के लिए अनुशंसित विधि।</string>\n    <string name=\"pref_disable_description\">केवल घटकों को अक्षम करें। रूट उपयोगकर्ताओं के लिए अनुशंसित नहीं है क्योंकि ऐप्स इसे बायपास कर सकते हैं। ADB मोड में, केवल परीक्षण वाले ऐप्स को इस विधि से अक्षम किए जा सकते हैं।</string>\n    <string name=\"pref_toggle_internet_msg\">ऐप मैनेजर में इंटरनेट सुविधाएँ सक्रिय करें</string>\n    <string name=\"vt_queued\">वायरसटोटल: अपलोड हो रहा है</string>\n    <plurals name=\"pref_thread_count_msg\">\n        <item quantity=\"one\">अधिकतम %1$d ऑपरेशन को समानांतर रूप से निष्पादित करें</item>\n        <item quantity=\"other\">अधिकतम %1$d ऑपरेशन समानांतर रूप से निष्पादित करें</item>\n    </plurals>\n</resources>"
  },
  {
    "path": "app/src/main/res/values-hu/disclaimer.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- SPDX-License-Identifier: GPL-3.0-or-later --><resources>\n    <string name=\"disclaimer_body\">App Manager offers root functions that could possibly harm your device if used incorrectly. App Manager is not responsible for any damages made by using this application. If you are not fully aware of how root works then you should avoid using root options until you are fully aware of the risks.\n\\n\n\\nAny link I provide to other apps and websites is for the users benefit. I am not responsible for any content you may find by going on external links.\n\\n\n\\nBy using App Manager, you accept full responsibility of your own usage and accept no damages, claims or monetary value will be given due to misuse.\n\\n\n\\nBy using this application, you accept all responsibility using it and agree that I am not responsible for any actions you make that has an adverse effect on your device.</string>\n    <string name=\"disclaimer_footer\">© 2020–2024 Muntashir Al-Islam</string>\n    <string name=\"disclaimer_agree\">Elfogadom</string>\n    <string name=\"disclaimer_exit\">Kilépés</string>\n    <string name=\"disclaimer_agree_forever\">Soha többet ne mutassa</string>\n    <string name=\"disclaimer_header\">Felelősség kizárása</string>\n</resources>"
  },
  {
    "path": "app/src/main/res/values-hu/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- SPDX-License-Identifier: GPL-3.0-or-later --><resources xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\">\n    <string name=\"error\">Hiba</string>\n    <string name=\"no_configurations\">Nincsenek konfigurációk</string>\n    <string name=\"configurations\">Konfigurációk</string>\n    <string name=\"sort_by_shared_user_id\">Megosztott felhasználói azonosító</string>\n    <string name=\"no_feature\">Nincsenek funkciók</string>\n    <string name=\"group\">Csoport</string>\n    <string name=\"declared_permission\">Engedélyek</string>\n    <string name=\"write\">Ír</string>\n    <string name=\"read\">Olvas</string>\n    <string name=\"orientation\">Orientáció</string>\n    <string name=\"service\">Szolgáltatások</string>\n    <string name=\"sort_by_last_update\">Utolsó frissítés</string>\n    <string name=\"no_activities\">Nincs aktivitás</string>\n    <string name=\"refresh\">Frissítés</string>\n    <string name=\"activities\">Tevékenségek</string>\n    <string name=\"require_no_permission\">Nem szükséges engedély</string>\n    <string name=\"no_service\">Nincs szolgáltatás</string>\n    <string name=\"authority\">Hatóság</string>\n    <string name=\"task_affinity\">Feladat affinitás</string>\n    <string name=\"launch_mode\">Indító mód</string>\n    <string name=\"no_providers\">Nincs szolgáltató</string>\n    <string name=\"providers\">Szolgáltatók</string>\n    <string name=\"no_receivers\">Nincs fogadó</string>\n    <string name=\"receivers\">Fogadók</string>\n    <string name=\"launch\">Indítás</string>\n    <string name=\"permissions\">Engedélyeket használ</string>\n    <string name=\"uninstall\">Eltávolítás</string>\n    <plurals name=\"other_trackers_and_classes\">\n        <item quantity=\"one\"><xliff:g id=\"tracker_no\" example=\"8\">%1$d</xliff:g> nyomkövető a(z) <xliff:g id=\"class_no\" example=\"50\">%2$d</xliff:g> osztályokban</item>\n        <item quantity=\"other\"><xliff:g id=\"tracker_no\" example=\"8\">%1$d</xliff:g> nyomkövető a(z) <xliff:g id=\"class_no\" example=\"50\">%2$d</xliff:g> osztályokban</item>\n    </plurals>\n    <plurals name=\"two_trackers_and_classes\">\n        <item quantity=\"one\">2 nyomkövető a(z) <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g> osztályban</item>\n        <item quantity=\"other\">2 nyomkövető a(z) <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g> osztályokban</item>\n    </plurals>\n    <plurals name=\"tracker_and_classes\">\n        <item quantity=\"one\">1 nyomkövető a(z) <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g> osztályban</item>\n        <item quantity=\"other\">1 nyomkövető a(z) <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g> osztályokban</item>\n    </plurals>\n    <string name=\"toggle_class_listing\">Osztály listázó váltás</string>\n    <string name=\"class_viewer\">Osztály betekintő</string>\n    <string name=\"word_wrap\">Sortörés kapcsoló</string>\n    <string name=\"credits\">Köszönet</string>\n    <string name=\"license\">Licenc</string>\n    <string name=\"icon_picker\">Ikon választó</string>\n    <string name=\"class_name\">Osztály név</string>\n    <string name=\"package_name\">Csomagnév</string>\n    <string name=\"shortcut_name\">Parancsikon neve</string>\n    <string name=\"create_shortcut\">Parancsikon létrehozás</string>\n    <string name=\"starting_activity\">Kezdő tevékenység: <xliff:g id=\"activity_name\" example=\".main.MainActivity\">%1$s</xliff:g></string>\n    <string name=\"error_verbose_pin_shortcut\">A jelenlegi indító nem támogatja a PinShortcut-ot. Nem lehet létrehozni a linket.</string>\n    <string name=\"error_creating_shortcut\">Parancsikon létrehozási hiba</string>\n    <string name=\"empty_package_name\">Üres csomagnév</string>\n    <string name=\"main_activity\">Fő tevékenység</string>\n    <string name=\"user_id\">Felh. azonosító</string>\n    <string name=\"installer_app\">Telepítő app</string>\n    <string name=\"date_updated\">Frissítés ideje</string>\n    <string name=\"date_installed\">Telepítés dátuma</string>\n    <string name=\"more_info\">Több infó</string>\n    <string name=\"sdk_flags\">Zászlók</string>\n    <string name=\"sdk_max\">Cél</string>\n    <string name=\"sdk_min\">Min.</string>\n    <string name=\"data_dir\">Adat könyvtár</string>\n    <string name=\"source_dir\">Forrás könyvtár</string>\n    <string name=\"paths_and_directories\">Útvonalak &amp; Könyvtárak</string>\n    <string name=\"user_app\">Felhasználói app</string>\n    <string name=\"system_app\">Rendszer app</string>\n    <string name=\"app_info\">App infó</string>\n    <string name=\"version_name_with_code\">Verzió <xliff:g id=\"version_name\" example=\"2.5.17\">%1$s</xliff:g> (<xliff:g id=\"version_code\" example=\"365\">%2$d</xliff:g>)</string>\n    <string name=\"sort\">Rendez</string>\n    <string name=\"user\">Felhasználó</string>\n    <string name=\"system\">Rendszer</string>\n    <string name=\"app_not_installed\">Az app nincs telepítve</string>\n    <string name=\"media_size\">Média</string>\n    <string name=\"obb_size\">Obb</string>\n    <string name=\"cache_size\">Cache</string>\n    <string name=\"data_size\">Adat</string>\n    <string name=\"about\">Rólunk</string>\n    <string name=\"data_usage_msg\">Adat használat</string>\n    <string name=\"data_transmitted\">Továbbított adat</string>\n    <string name=\"data_received\">Fogadott adat</string>\n    <string name=\"sort_by_target_sdk\">Cél SDK</string>\n    <string name=\"sort_by_domain\">Felh. appok előre</string>\n    <string name=\"sort_by_package_name\">Csomagnév</string>\n    <string name=\"sort_by_app_label\">App címke</string>\n    <string name=\"loading\">Betöltés…</string>\n    <string name=\"patterns_allowed\">Engedélyezett minták</string>\n    <string name=\"signatures\">Aláírások</string>\n    <string name=\"sort_by_sha\">Aláírás</string>\n    <string name=\"third_party\">Harmadik-féltől származó könyvtárak és ikonok</string>\n    <string name=\"all_classes\">Összes osztály</string>\n    <string name=\"no_shared_libs\">Nincsenek megosztott könyvtárak</string>\n    <string name=\"shared_libs\">Megosztott könyvtárak</string>\n    <string name=\"grant_uri_permission\">URI engedélyek megadása</string>\n    <string name=\"found_trackers\">Talált nyomkövetők:</string>\n    <string name=\"type_string\">Karakterek</string>\n    <string name=\"menu_remove_rules\">Szabályok eltávolítása</string>\n    <string name=\"pref_import_existing\">Már meglévő szabályok importálása</string>\n    <plurals name=\"alert_failed_to_clear_data\">\n        <item quantity=\"one\">Nem sikerült törölni az adatot %1$d appból</item>\n        <item quantity=\"other\">Nem sikerült törölni az adatot %1$d appból</item>\n    </plurals>\n    <string name=\"never_ask\">Soha ne kérdezze</string>\n    <string name=\"tracker_details\">Trekker jellemzői</string>\n    <string name=\"no_usage_in_this_time_range\">Nincs használat ebben az időtartományban</string>\n    <string name=\"uninstall_app_message\">Le akarja törölni ezt az appot\\?</string>\n    <string name=\"disable\">Letiltás</string>\n    <string name=\"storage_and_cache\">Tárhely és gyorsítótár</string>\n    <string name=\"usage_access\">Használati engedély</string>\n    <string name=\"exodus_link\">εxodus link</string>\n    <string name=\"sort_by_blocked_components\">Először blokkolva</string>\n    <string name=\"pref_import_export_blocking_rules\">Blokkoló szabályok importálása/exportálása</string>\n    <string name=\"launch_app\">Megnyitás</string>\n    <string name=\"add_item\">Adjon hozzá egy elemet</string>\n    <string name=\"usage_less_than_a_minute\">Kevesebb mint egy perce</string>\n    <string name=\"permission_name\">Engedély neve</string>\n    <string name=\"export_options\">Opciók exportálása</string>\n    <string name=\"failed_to_reset_app_ops\">Nem sikerült az app oppokat visszaállítani</string>\n    <string name=\"mode\">Mód</string>\n    <string name=\"stopped\">Leállított</string>\n    <string name=\"dev_protected_data_dir\">Eszköz által védett adat könyvtár</string>\n    <string name=\"app_signing_no_signatures\">Nincsenek megfelelő aláírások</string>\n    <string name=\"input_features\">Input funkciók</string>\n    <string name=\"tracker_classes\">Trekker osztályai</string>\n    <string name=\"key_name_cannot_be_null\">Kukcs neve nem lehet üres</string>\n    <string name=\"navigation\">Navigáció</string>\n    <string name=\"pref_import_existing_msg\">Komponensek hozzáadása, amik le lettek tiltva más appok által. Legyen óvatos amikor ezt a funkciót használja, mert gyakoriak a téves pozitív eredmények. Csak azt az appot válassza ki amiben biztos.</string>\n    <string name=\"app_usage\">App felhasználása</string>\n    <string name=\"search\">Keresés</string>\n    <string name=\"total_size\">Teljes</string>\n    <string name=\"databases\">Adatbázisok</string>\n    <string name=\"no_app_ops\">Nincsenek app műveletek</string>\n    <string name=\"force_stop\">Kényszerleállítás</string>\n    <string name=\"pref_global_blocking_enabled_msg\">Lehetővé teszi egy app bármely kompononsének letiltását anélkül, hogy az egész appot letiltaná.</string>\n    <string name=\"usage_yesterday\">Tegnap</string>\n    <string name=\"pref_import_watt\">Importálás Wattból</string>\n    <string name=\"reset_to_default\">Alapbeállítás visszaállítása</string>\n    <string name=\"failed_to_grant_permission\">Nem sikerült az engedélyek megadása</string>\n    <string name=\"community\">Közösség</string>\n    <string name=\"clear_cache\">Gyorsítótár törlése</string>\n    <string name=\"uses_feature\">Funkciókat használ</string>\n    <string name=\"shared_user_id\">Megosztott felhasználó ID</string>\n    <string name=\"integer_value\">Egész érték</string>\n    <string name=\"decimal_value\">Decimális érték</string>\n    <string name=\"boolean_value\">Logikai érték</string>\n    <string name=\"pref_import_export_blocking_rules_msg\">Szabályok importálása/exportálása, importáljon külső szabályokat Wattból vagy Blockerből.</string>\n    <string name=\"backup_restore\">Biztonsági mentés/ visszaállítás</string>\n    <string name=\"pref_import_blocker_msg\">Blokkolási szabályok importálása Blockerből, minden egyes fájl tartalmaz szabályokat egy csomagnak.</string>\n    <string name=\"one_click_ops\">1-klikk oppok</string>\n    <string name=\"external_apk_no_app_op\">A külső APKnak nincsen app művelete</string>\n    <string name=\"manifest_viewer\">Bizonylat megnézése</string>\n    <string name=\"install\">Telepítés</string>\n    <string name=\"clear_data\">Adat törlése</string>\n    <string name=\"sort_by_app_ops_values\">App oppok értéke</string>\n    <string name=\"sort_by_denied_permissions\">Tagadott először</string>\n    <string name=\"failed_to_extract_apk_file\">Nem sikerült kinyerni az APK fájlt</string>\n    <string name=\"sort_by_screen_time\">Használati idő</string>\n    <string name=\"duration\">Időtartam</string>\n    <string name=\"share_apk\">APK megosztása</string>\n    <string name=\"str_logo\">Logó</string>\n    <string name=\"discard\">Elvetés</string>\n    <string name=\"unknown_op\">Nem ismert műveletek</string>\n    <string name=\"no_code\">Nincs kód</string>\n    <string name=\"type_boolean\">Igaz/hamis</string>\n    <string name=\"app_size\">App</string>\n    <string name=\"apk_updater\">APK frissítő</string>\n    <string name=\"ago\">óta</string>\n    <string name=\"updated_app\">Frissített</string>\n    <string name=\"rules_not_applied\">A szabályok nincsenek alkalmazva</string>\n    <string name=\"sort_by_app_ops_names\">App oppok neve</string>\n    <string name=\"saved_successfully\">Mentett</string>\n    <string name=\"kill_process\">Megszakítás</string>\n    <string name=\"saving_failed\">Mentés sikertelen, próbálja újra.</string>\n    <string name=\"sort_by_tracker_components\">Trekkerek először</string>\n    <string name=\"pref_import_blocker\">Importálás Blockerből</string>\n    <string name=\"the_operation_was_successful\">Kész</string>\n    <string name=\"sort_by_dangerous_permissions\">Veszélyes először</string>\n    <string name=\"deny_dangerous_permissions\">Veszélyes engedély tagadása</string>\n    <string name=\"no_tracker_class\">Nincsenek trekker osztályok</string>\n    <string name=\"usage_weekly\">Hetente</string>\n    <string name=\"pref_global_blocking_enabled\">Instant komponens blokkolás</string>\n    <string name=\"usage_7_days\">Az elmúlt 7 napban</string>\n    <string name=\"keyboard_type\">Billentyűzet típusa</string>\n    <string name=\"changelog\">Változások</string>\n    <string name=\"select_theme\">Téma</string>\n    <string name=\"flags\">Zászlók</string>\n    <string name=\"requested_large_heap\">Nagy kupac</string>\n    <string name=\"import_options\">Opciók importálása</string>\n    <string name=\"deleted_successfully\">Törölt</string>\n    <string name=\"deletion_failed\">Törlés sikertelen</string>\n    <string name=\"accept_time\">Idő elfogadása</string>\n    <string name=\"app_settings\">Beállítások</string>\n    <string name=\"running\">Futó</string>\n    <string name=\"pref_app_theme\">App téma</string>\n    <string name=\"long_integer_value\">Hosszú egész érték</string>\n    <string name=\"delete\">Törlés</string>\n    <string name=\"pref_export_msg\">Blokkoló szabályok exportálása -amit az App Manager konfigurált- a külső tárhelybe.</string>\n    <string name=\"pref_import_msg\">Előzőleg az App Managerből exportált blokkoló szabályok importálása.</string>\n    <string name=\"user_with_id\">Felhasználó: <xliff:g id=\"user_id\" example=\"0\">%1$d</xliff:g></string>\n    <string name=\"failed_to_uninstall_app\">Eltávolítás sikertelen</string>\n    <string name=\"failed_to_deny_dangerous_app_ops\">Nem sikerült visszavonni minden veszélyes app oppot</string>\n    <string name=\"go_back\">Vissza</string>\n    <string name=\"user_and_uid\">Felhasználó: <xliff:g id=\"user_name\" example=\"root\">%1$s</xliff:g> (<xliff:g id=\"user_id\" example=\"0\">%2$d</xliff:g>)</string>\n    <string name=\"disabled_app\">Letiltott</string>\n    <string name=\"import_failed\">Nem sikerült importálni!</string>\n    <string name=\"sort_by_times_opened\">Ennyiszer megnyitva</string>\n    <string name=\"done\">Kész</string>\n    <string name=\"the_import_was_successful\">Importálva</string>\n    <string name=\"test_only\">Csak teszt</string>\n    <string name=\"key_name\">Kulcs név</string>\n    <string name=\"view_in_settings\">Nézze meg a beállításokban</string>\n    <string name=\"uninstall_system_app_message\">Ez egy rendszer app. Biztosan el akarja távolítani\\?</string>\n    <string name=\"deny_dangerous_app_ops\">Veszélyes app oppok tagadása</string>\n    <string name=\"failed_to_disable_op\">Nem sikerült a kiválasztott app oppot letiltani</string>\n    <string name=\"version\">Verziók</string>\n    <string name=\"failed_to_revoke_permission\">Nem sikerült visszavenni az engedélyeket</string>\n    <string name=\"failed_to_deny_dangerous_perms\">Nem sikerült az összes veszélyes engedélyt visszavonni</string>\n    <string name=\"type_long\">Hosszú egész</string>\n    <string name=\"menu_apply_rules\">Szabályok alkalmazása</string>\n    <string name=\"type_float\">Decimális szám</string>\n    <string name=\"external_multiple_data_dir\">Külső adat könyvtár <xliff:g id=\"dir_no\" example=\"1\">%1$d</xliff:g></string>\n    <string name=\"update\">Frissítés</string>\n    <string name=\"source_code\">Forráskód</string>\n    <plurals name=\"usage_days\">\n        <item quantity=\"one\"></item>\n        <item quantity=\"other\"></item>\n    </plurals>\n    <string name=\"export_blocking_rules\">Blokkoló szabályok exportálása</string>\n    <string name=\"reject_time\">Idő elutasítása</string>\n    <string name=\"follow_system\">Rendszer témájának követése</string>\n    <string name=\"toggle_kill_for_system_apps\">Rendszer appok leállításának ki/bekapcsolása</string>\n    <string name=\"pref_import\">Importálás</string>\n    <string name=\"pref_export\">Exportálás</string>\n    <string name=\"export_failed\">Nem sikerült exportálni!</string>\n    <string name=\"touchscreen\">Érintőképernyő</string>\n    <string name=\"battery_mode\">Akkumlátor mód</string>\n    <string name=\"pref_about_msg\">App Manager verzió, licensz, alkotók, stb.</string>\n    <string name=\"day\">Nappali</string>\n    <string name=\"night\">Éjszakai</string>\n    <string name=\"sort_by_denied_app_ops\">Először tagadva</string>\n    <string name=\"pref_import_watt_msg\">Blokkolási szabályok importálása Wattból, minden egyes fájl tartalmaz szabályokat egy csomaghoz <tt>packagename.xml</tt> stb. néven.</string>\n    <string name=\"sort_by_wifi_data\">Wi-Fi adat</string>\n    <string name=\"apply\">Alkalmaz</string>\n    <string name=\"block_trackers\">Trekkerek blokkolása</string>\n    <string name=\"sort_by_permission_names\">Engedély neve</string>\n    <string name=\"sort_by_component_name\">Komponens neve</string>\n    <string name=\"source_code_links\"><a href=\"https://github.com/MuntashirAkon/AppManager\">GitHub</a> • <a href=\"https://gitlab.com/muntashir/AppManager\">GitLab</a> • \n\\n<a href=\"https://0xacab.org/muntashir/AppManager\">Riseup</a> • <a href=\"https://codeberg.org/muntashir/AppManager\">Codeberg</a></string>\n    <string name=\"block_unblock_trackers_description\">A hirdetések és trekkerek blokkolása és engedélyezése minden telepített appban</string>\n    <string name=\"community_links\"><a href=\"https://t.me/AppManagerChannel\">Telegram csatorna</a> • <a href=\"https://twitter.com/AppManagerNews\">Twitter</a></string>\n    <string name=\"block_components_dots\">Komponensek blokkolása…</string>\n    <string name=\"usage_today\">Ma</string>\n    <string name=\"app_signing_signatures\">Aláírások</string>\n    <string name=\"path_permissions\">Útvonal engedélyek</string>\n    <string name=\"manifest\">Nyilatkozat</string>\n    <string name=\"grant_usage_acess_message\">App használati információk megadására.</string>\n    <string name=\"process_name\">Folyamat név</string>\n    <string name=\"failed_to_enable_op\">Nem sikerült a kiválasztott app oppot engedélyezni</string>\n    <string name=\"debuggable\">Debuggolható</string>\n    <string name=\"error_evaluating_input\">Nem sikerült kiértékelni a bemenetet</string>\n    <string name=\"enable\">Engedélyezés</string>\n    <string name=\"save\">Mentés</string>\n    <string name=\"string_value\">String érték</string>\n    <string name=\"select_type\">Válasszon ki egy típust</string>\n    <string name=\"type_int\">Egész</string>\n    <string name=\"failed_to_uninstall\"></string>\n    <string name=\"no_content\">Nincs tartalom</string>\n    <string name=\"sort_by_last_used\">Legutóbb használva</string>\n    <string name=\"app_ops\">App oppok</string>\n    <string name=\"sort_by_mobile_data\">Mobil internet</string>\n    <string name=\"external_data_dir\">Külső adat könyvtár</string>\n    <string name=\"the_export_was_successful\">Exportálva</string>\n    <plurals name=\"failed_to_import_files\">\n        <item quantity=\"one\">Nem sikerült importálni %1$d fájlt.</item>\n        <item quantity=\"other\">Nem sikerült importálni %1$d fájlt .</item>\n    </plurals>\n    <string name=\"running_apps\">Futó appok</string>\n    <string name=\"disable_background_run\">Háttérbeli műveletek megakadályozása</string>\n    <string name=\"memory_virtual_memory\">Memória: %1$s, Virtuális Memória: %2$s</string>\n    <plurals name=\"alert_failed_to_uninstall\">\n        <item quantity=\"one\">Nem sikerült eltávolítani %1$d appot</item>\n        <item quantity=\"other\">Nem sikerült eltávolítani %1$d appot</item>\n    </plurals>\n    <string name=\"disable_background\">Háttérbeli művelet megakadályozása</string>\n    <plurals name=\"usage_months\">\n        <item quantity=\"one\"></item>\n        <item quantity=\"other\"></item>\n    </plurals>\n    <string name=\"grant_usage_access\">Használati engedély megadása</string>\n</resources>"
  },
  {
    "path": "app/src/main/res/values-in-rID/disclaimer.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- SPDX-License-Identifier: GPL-3.0-or-later --><resources>\n    <string name=\"disclaimer_header\">Penafian</string>\n    <string name=\"disclaimer_body\">App Manager menawarkan fungsi root yang dapat merusak perangkat Anda jika digunakan dengan tidak benar. App Manager tidak bertanggung jawab atas kerusakan yang disebabkan oleh penggunaan aplikasi ini. Jika Anda tidak sepenuhnya memahami cara kerja root, sebaiknya hindari menggunakan opsi root hingga Anda benar-benar memahami risikonya.\\n\\nSetiap tautan yang saya berikan ke aplikasi dan situs web lain adalah untuk manfaat pengguna. Saya tidak bertanggung jawab atas konten yang mungkin Anda temui melalui tautan eksternal.\\n\\nDengan menggunakan App Manager, Anda menerima tanggung jawab penuh atas penggunaan Anda sendiri dan menerima bahwa tidak ada kerusakan, klaim, atau nilai moneter yang akan diberikan akibat penyalahgunaan.\\n\\nDengan menggunakan aplikasi ini, Anda menerima semua tanggung jawab saat menggunakannya dan setuju bahwa saya tidak bertanggung jawab atas tindakan yang Anda lakukan yang berdampak buruk pada perangkat Anda.</string>\n    <string name=\"disclaimer_footer\">© 2020–2024 Muntashir Al-Islam</string>\n    <string name=\"disclaimer_agree_forever\">Jangan pernah tampilkan ini lagi</string>\n    <string name=\"disclaimer_agree\">Saya Setuju</string>\n    <string name=\"disclaimer_exit\">Keluar</string>\n</resources>"
  },
  {
    "path": "app/src/main/res/values-in-rID/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- SPDX-License-Identifier: GPL-3.0-or-later --><resources xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:tools=\"http://schemas.android.com/tools\">\n    <string name=\"_lang_tag\" translatable=\"false\">id</string>\n    <string name=\"uninstall\">Copot pemasangan</string>\n    <string name=\"permissions\">Memerlukan Izin</string>\n    <string name=\"require_no_permission\">Tidak memerlukan izin</string>\n    <string name=\"activities\">Aktivitas</string>\n    <string name=\"launch\">Luncurkan</string>\n    <string name=\"refresh\">Muat ulang</string>\n    <string name=\"no_activities\">Tidak ada aktifitas</string>\n    <string name=\"installer_error_blocked_device\">Perangkat</string>\n    <string name=\"receivers\">Penerima</string>\n    <string name=\"starting_activity\">Aktifitas baru dimulai: <xliff:g id=\"activity_name\" example=\".main.MainActivity\">%1$s</xliff:g></string>\n    <string name=\"error_verbose_pin_shortcut\">Peluncur saat ini tidak mendukung Pinshortcut. Tidak dapat membuat pintasan.</string>\n    <string name=\"error_creating_shortcut\">Kesalahan dalam membuat pintasan</string>\n    <string name=\"main_activity\">Aktifitas utama</string>\n    <string name=\"user_id\">ID pengguna</string>\n    <string name=\"installer_app\">Pemasang Aplikasi</string>\n    <string name=\"date_updated\">Tanggal di-update</string>\n    <string name=\"date_installed\">Tanggal terinstall</string>\n    <string name=\"more_info\">Informasi lainnya</string>\n    <string name=\"data_dir\">Direktori data</string>\n    <string name=\"source_dir\">Direktori sumber</string>\n    <string name=\"paths_and_directories\">Path &amp; direktori</string>\n    <string name=\"user_app\">Aplikasi pengguna</string>\n    <string name=\"system_app\">Aplikasi sistem</string>\n    <string name=\"app_info\">Info aplikasi</string>\n    <string name=\"sort\">Urutkan</string>\n    <string name=\"user\">Pengguna</string>\n    <string name=\"system\">Sistem</string>\n    <string name=\"app_not_installed\">App tidak terinstall</string>\n    <string name=\"obb_size\">Ukuran obb</string>\n    <string name=\"cache_size\">Cache</string>\n    <string name=\"data_size\">Data</string>\n    <string name=\"about\">Tentang</string>\n    <string name=\"data_usage_msg\">Penggunaan data</string>\n    <string name=\"data_transmitted\">Data ditransmisikan</string>\n    <string name=\"data_received\">Data diterima</string>\n    <string name=\"sort_by_domain\">App pengguna terlebih dulu</string>\n    <string name=\"sort_by_package_name\">Nama paket</string>\n    <string name=\"sort_by_app_label\">Label App</string>\n    <string name=\"loading\">Memuat…</string>\n    <string name=\"error\">Kesalahan</string>\n    <string name=\"manifest\">Manifes</string>\n    <string name=\"input_features\">Fitur masukan</string>\n    <string name=\"no_configurations\">Tidak ada konfigurasi</string>\n    <string name=\"configurations\">Konfigurasi</string>\n    <string name=\"app_signing_no_signatures\">Tidak ada tanda tangan yang valid</string>\n    <string name=\"sort_by_sha\">Tanda tangan</string>\n    <string name=\"shared_user_id\">ID pengguna yang dibagikan</string>\n    <string name=\"sort_by_shared_user_id\">ID Pengguna yang Dibagikan</string>\n    <string name=\"no_feature\">Tidak ada fitur</string>\n    <string name=\"uses_feature\">Fitur yang digunakan</string>\n    <string name=\"declared_permission\">Izin</string>\n    <string name=\"patterns_allowed\">pola diperbolehkan</string>\n    <string name=\"write\">Tulis</string>\n    <string name=\"read\">Baca</string>\n    <string name=\"orientation\">Orientasi</string>\n    <string name=\"no_service\">Tidak ada layanan</string>\n    <string name=\"service\">Layanan</string>\n    <string name=\"authority\">Otoritas</string>\n    <string name=\"sort_by_last_update\">Pembaruan terakhir</string>\n    <string name=\"launch_mode\">Mode peluncuran</string>\n    <string name=\"no_providers\">Tidak ada penyedia</string>\n    <string name=\"providers\">Penyedia</string>\n    <string name=\"no_receivers\">Tidak ada penerima</string>\n    <string name=\"os_version\">Versi OS</string>\n    <string name=\"copied_to_clipboard\">Disalin ke papanklip.</string>\n    <string name=\"pref_enable_disable_features_msg\">Hidupkan atau matikan fitur di App Manager.</string>\n    <string name=\"sort_by_app_ops_names\">Nama aplikasi ops</string>\n    <string name=\"deny_dangerous_app_ops\">Tolak aplikasi berbahaya</string>\n    <string name=\"reset_to_default\">Setel ulang ke default</string>\n    <string name=\"sort_by_component_name\">Nama komponen</string>\n    <string name=\"block_trackers\">Blokir tracker</string>\n    <string name=\"sort_by_wifi_data\">Data Wi-Fi</string>\n    <string name=\"version\">Versi</string>\n    <string name=\"pref_about_msg\">Versi, lisensi, kredit, dll App Manager.</string>\n    <string name=\"apply\">Terapkan</string>\n    <string name=\"select_theme\">Tema</string>\n    <string name=\"night\">Malam</string>\n    <string name=\"day\">Hari</string>\n    <string name=\"unknown_split_for_base_apk\"><xliff:g id=\"split_name\" example=\"some_split\">%1$s</xliff:g> untuk base APK</string>\n    <string name=\"unknown_split_for_feature\"><xliff:g id=\"split_name\" example=\"some_split\">%1$s</xliff:g>untuk fitur<xliff:g id=\"feature_name\" example=\"Visualizer\">%2$s</xliff:g></string>\n    <string name=\"split_feature_name\">Fitur:<xliff:g id=\"feature_name\" example=\"Visualizer\">%1$s</xliff:g></string>\n    <string name=\"base_apk\">Basis APK</string>\n    <string name=\"choose_language\">Ubah bahasa</string>\n    <string name=\"auto\">Otomatis</string>\n    <string name=\"pref_app_language\">Bahasa</string>\n    <string name=\"pref_import\">Impor</string>\n    <string name=\"touchscreen\">Layar sentuh</string>\n    <string name=\"navigation\">Navigasi</string>\n    <string name=\"keyboard_type\">Tipe Papan ketik</string>\n    <string name=\"export_failed\">Ekspor gagal!</string>\n    <string name=\"import_failed\">Impor gagal!</string>\n    <string name=\"export_options\">Pilihan Ekspor</string>\n    <string name=\"import_options\">Pilihan impor</string>\n    <string name=\"pref_export\">Ekspor</string>\n    <string name=\"pref_compression_method\">Metode kompresi</string>\n    <string name=\"str_logo\">Logo</string>\n    <string name=\"rules_not_applied\">Aturan tidak dapat diterapkan</string>\n    <string name=\"failed_to_disable_op\">Tidak dapat menon-aktifkan permintaan operasi aplikasi</string>\n    <string name=\"failed_to_enable_op\">Tidak dapat mengaktifkan permintaan operasi aplikasi</string>\n    <string name=\"no_app_ops\">Tidak ada operasi aplikasi</string>\n    <string name=\"app_ops\">Operasi Aplikasi</string>\n    <string name=\"app_size\">Aplikasi</string>\n    <string name=\"total_size\">Total</string>\n    <string name=\"storage_and_cache\">Penyimpanan dan Cache</string>\n    <string name=\"failed_to_stop\">Tidak dapat menghentikan <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g>.</string>\n    <string name=\"force_stop\">Paksa-berhenti</string>\n    <string name=\"enable\">Aktifkan</string>\n    <string name=\"disable\">Non-aktifkan</string>\n    <string name=\"stopped\">Dihentikan</string>\n    <string name=\"uninstall_system_app_message\">Ini adalah aplikasi sistem. Apakah Anda yakin ingin mencopot aplikasi ini\\?</string>\n    <string name=\"uninstalled_successfully\"><xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g> telah dicopot.</string>\n    <string name=\"failed_to_uninstall\">Tidak dapt mencopot <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g>.</string>\n    <string name=\"uninstall_app_message\">Apakah Anda ingin mencopot aplikasi ini\\?</string>\n    <string name=\"view_in_settings\">Tinjau pada Pengaturan</string>\n    <string name=\"no_content\">Tidak ada isi</string>\n    <string name=\"no_usage_in_this_time_range\">Tidak ada penggunaan pada jarak waktu ini</string>\n    <string name=\"disabled_app\">Dinon-aktifkan</string>\n    <string name=\"key_name_cannot_be_null\">Nama key tidak boleh kosong</string>\n    <string name=\"error_evaluating_input\">Tidak dapat evaluasi masukan</string>\n    <string name=\"type_string\">Karakter</string>\n    <string name=\"type_long\">Integer panjang</string>\n    <string name=\"type_int\">Integer</string>\n    <string name=\"type_float\">Nomor Desimal</string>\n    <string name=\"type_boolean\">Benar/salah</string>\n    <string name=\"done\">Selesai</string>\n    <string name=\"add_item\">Tambahkan item</string>\n    <string name=\"select_type\">Pilih jenis</string>\n    <string name=\"key_name\">Nama Key</string>\n    <string name=\"boolean_value\">Nilai Boolean</string>\n    <string name=\"decimal_value\">Nilai desimal</string>\n    <string name=\"integer_value\">Nilai integer</string>\n    <string name=\"long_integer_value\">Nilai integer panjang</string>\n    <string name=\"string_value\">Nilai string</string>\n    <string name=\"saving_failed\">Simpan gagal, coba lagi.</string>\n    <string name=\"saved_successfully\">Tersimpan</string>\n    <string name=\"deletion_failed\">Hapus gagal</string>\n    <string name=\"deleted_successfully\">Terhapus</string>\n    <string name=\"delete\">Hapus</string>\n    <string name=\"discard\">Buang</string>\n    <string name=\"save\">Simpan</string>\n    <string name=\"databases\">Database</string>\n    <string name=\"shared_prefs\">Preferensi Bersama</string>\n    <string name=\"test_only\">Hanya uji saja</string>\n    <string name=\"debuggable\">Dapat di-debug</string>\n    <string name=\"updated_app\">Diperbarui</string>\n    <string name=\"requested_large_heap\">Tumpukan besar</string>\n    <string name=\"no_code\">Tidak ada kode</string>\n    <string name=\"process_name\">Nama Proses</string>\n    <string name=\"native_library_dir\">Direktori Library JNI Asli</string>\n    <string name=\"dev_protected_data_dir\">Direktori Data yang dilindungi Perangkat</string>\n    <string name=\"search\">Cari</string>\n    <string name=\"menu_apply_rules\">Terapkan aturan</string>\n    <string name=\"menu_remove_rules\">Hapus aturan</string>\n    <string name=\"failed_to_extract_apk_file\">Tidak dapat mengekstrak berkas APK</string>\n    <string name=\"share_apk\">Bagikan APK</string>\n    <string name=\"grant_usage_acess_message\">Digunakan untuk menampilkan info penggunaan aplikasi.</string>\n    <string name=\"grant_usage_access\">Berikan Akses Penggunaan</string>\n    <string name=\"go\">Pindah ke layar Pengaturan</string>\n    <string name=\"go_back\">Kembali</string>\n    <string name=\"usage_less_than_a_minute\">Kurang dari semenit</string>\n    <plurals name=\"usage_hours\">\n        <item quantity=\"other\">%1$d jam</item>\n    </plurals>\n    <plurals name=\"usage_days\">\n        <item quantity=\"other\">%1$d hari</item>\n    </plurals>\n    <plurals name=\"usage_months\">\n        <item quantity=\"other\">%1$d bulan</item>\n    </plurals>\n    <string name=\"usage_7_days\">7 hari terakhir</string>\n    <string name=\"usage_today\">Hari ini</string>\n    <string name=\"usage_weekly\">Mingguan</string>\n    <string name=\"app_usage\">Pengunaan Aplikasi</string>\n    <string name=\"no_tracker_class\">Tidak ada kelas pelacak</string>\n    <string name=\"no_shared_libs\">Tidak ada library bersama</string>\n    <plurals name=\"main_list_date_days\">\n        <item quantity=\"other\"><xliff:g id=\"last_update_date\" example=\"20/10/2020\">%1$s</xliff:g> <xliff:g id=\"day_no\" example=\"5\">%2$d</xliff:g> hari</item>\n    </plurals>\n    <string name=\"all_classes\">Semua class</string>\n    <string name=\"tracker_classes\">Class tracker</string>\n    <string name=\"tracker_details\">Rincian tracker</string>\n    <string name=\"found_trackers\">Tracker ditemukan:</string>\n    <plurals name=\"other_trackers_and_classes\">\n        <item quantity=\"other\"><xliff:g id=\"tracker_no\" example=\"8\">%1$d</xliff:g> tracker dengan <xliff:g id=\"class_no\" example=\"50\">%2$d</xliff:g> class</item>\n    </plurals>\n    <plurals name=\"two_trackers_and_classes\">\n        <item quantity=\"other\">2 trackers dengan <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g> class</item>\n    </plurals>\n    <plurals name=\"tracker_and_classes\">\n        <item quantity=\"other\">1 trackers dengan <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g> class</item>\n    </plurals>\n    <string name=\"toggle_class_listing\">Alihkan Pendaftar Class</string>\n    <string name=\"class_viewer\">Peninjau Class</string>\n    <string name=\"word_wrap\">alihkan word wrap</string>\n    <string name=\"credits_message\">Kepada pembuat/pemilik dari \\n- The Android Open Source Project \\n- <a href=\"https://github.com/zhaobozhen/libraries\">Absinthe\\'s libraries</a> \\n- <a href=\"https://github.com/butzist/ActivityLauncher\">Activity Launcher</a> \\n- <a href=\"https://bitbucket.org/oF2pks/fdroid-applications-info\">Apps_packages Info</a> \\n- <a href=\"https://github.com/zhaobao/AppsMonitor\">AppsMonitor</a> \\n- <a href=\"https://github.com/8enet/AppOpsX\">AppOpsX</a> \\n- <a href=\"https://github.com/gabrielemariotti/changeloglib\">ChangeLog Library</a> \\n- <a href=\"https://bitbucket.org/oF2pks/fdroid-classyshark3xodus\">ClassySharkAndroid</a> \\n- <a href=\"https://github.com/billthefarmer/editor\">Editor</a> \\n- <a href=\"https://github.com/Raival-e/File-Explorer\">File Explorer</a> \\n- <a href=\"https://github.com/nex3z/FlowLayout\">FlowLayout</a> \\n- <a href=\"https://github.com/k3b/intent-intercept\">Intent Intercept</a> \\n- <a href=\"https://github.com/YarikSOffice/lingver\">Lingver</a> \\n- <a href=\"https://github.com/topjohnwu/Magisk\">Magisk</a> \\n- <a href=\"https://github.com/zhanghai/MaterialFiles\">Material Files</a> \\n- <a href=\"https://github.com/pluscubed/matlog\">MatLog</a> \\n- <a href=\"https://github.com/matrix-org/matrix-android-sdk\">Matrix Android SDK</a> \\n- <a href=\"https://github.com/jensstein/oandbackup\">OAndBackup</a> \\n- <a href=\"https://github.com/open-keychain/open-keychain\">Open Keychain</a> \\n- <a href=\"https://github.com/Aefyr/SAI\">SAI</a> \\n- <a href=\"https://github.com/RikkaApps/Shizuku\">Shizuku</a> \\n- <a href=\"https://github.com/eclipse/tm4e\">tm4e</a> \\n- <a href=\"https://github.com/tuyafeng/Watt\">Watt</a></string>\n    <string name=\"credits\">Pembuat</string>\n    <string name=\"third_party\">Pustakaan dan Ikon Pihak-Ketiga</string>\n    <string name=\"license\">Lisensi</string>\n    <string name=\"icon_picker\">Pengambil Ikon</string>\n    <string name=\"class_name\">Nama Class</string>\n    <string name=\"package_name\">Nama Package</string>\n    <string name=\"shortcut_name\">Nama Pintasan</string>\n    <string name=\"create_shortcut\">Buat Pintasan</string>\n    <string name=\"empty_package_name\">Nama package kosong</string>\n    <string name=\"sdk_flags\">Bendera</string>\n    <string name=\"sdk_max\">Target</string>\n    <string name=\"sdk_min\">Minimal</string>\n    <string name=\"version_name_with_code\">Versi <xliff:g id=\"version_name\" example=\"2.5.17\">%1$s</xliff:g> (<xliff:g id=\"version_code\" example=\"365\">%2$d</xliff:g>)</string>\n    <string name=\"media_size\">Media</string>\n    <string name=\"sort_by_target_sdk\">Target untuk SDK</string>\n    <string name=\"signatures\">Tanda tangan</string>\n    <string name=\"group\">Grup</string>\n    <string name=\"shared_libs\">Libs berbagi</string>\n    <string name=\"path_permissions\">Perizinan path</string>\n    <string name=\"grant_uri_permission\">Berikan izin URI</string>\n    <string name=\"flags\">Tanda</string>\n    <string name=\"soft_input\">Mode masukan lunak</string>\n    <string name=\"task_affinity\">Afinitas Tugas</string>\n    <string name=\"app_settings\">Pengaturan</string>\n    <string name=\"usage_access\">Akses pemakaian</string>\n    <string name=\"pref_global_blocking_enabled_msg\">Memungkinkan anda untuk memblokir komponen apapun tanpa harus menghidupkan pemblokir untuk aplikasi.</string>\n    <string name=\"backup_restore\">Cadangkan/Pulihkan</string>\n    <string name=\"clear_data\">Bersihkan Data</string>\n    <string name=\"user_with_id\">Pengguna: <xliff:g id=\"user_id\" example=\"0\">%1$d</xliff:g></string>\n    <string name=\"memory_virtual_memory\">Memori: %1$s, Memori Virtual: %2$s</string>\n    <string name=\"pid_and_ppid\">Proses ID: %1$d, Proses ID Utama: %2$d</string>\n    <string name=\"disable_background_run\">Nonaktifkan Berjalan di Latar Belakang</string>\n    <string name=\"kill_process\">Hentikan</string>\n    <string name=\"running_apps\">Aplikasi Berjalan</string>\n    <string name=\"apk_updater\">Pengupdate APK</string>\n    <plurals name=\"failed_to_import_files\">\n        <item quantity=\"other\">Tak dapat memulihkan file %1$d.</item>\n    </plurals>\n    <string name=\"the_export_was_successful\">Tercadangkan</string>\n    <string name=\"the_import_was_successful\">Terpulihkan</string>\n    <string name=\"pref_import_blocker\">Pulihkan dari Penghalang</string>\n    <string name=\"pref_import_watt\">Pulihkan dari Watt</string>\n    <string name=\"pref_import_export_blocking_rules_msg\">Aturan Pencadangan/Pemulihan, Pulihkan Aturan Eksternal dari Watt atau Penghalang.</string>\n    <string name=\"pref_import_export_blocking_rules\">Aturan Halangan Pencadangan/Pemulihan</string>\n    <string name=\"sort_by_mobile_data\">Data Seluler</string>\n    <string name=\"sort_by_times_opened\">Kali dibuka</string>\n    <string name=\"sort_by_screen_time\">Waktu Layar</string>\n    <string name=\"sort_by_last_used\">Terakhir kali dipakai</string>\n    <plurals name=\"no_of_times_opened\">\n        <item quantity=\"other\">%1$d kali</item>\n    </plurals>\n    <string name=\"external_data_dir\">Penyimpanan Data Eksternal</string>\n    <string name=\"sort_by_blocked_components\">Dihalang Pertama</string>\n    <string name=\"exodus_link\">Link εxodus</string>\n    <string name=\"usage_yesterday\">Kemarin</string>\n    <string name=\"pref_global_blocking_enabled\">Pemblokiran komponen secara instan</string>\n    <string name=\"toggle_kill_for_system_apps\">Hidupkan Penghentikan aplikasi sistem</string>\n    <plurals name=\"alert_failed_to_force_stop\">\n        <item quantity=\"other\">Tak dapat memaksa penghentikan aplikasi %1$d</item>\n    </plurals>\n    <string name=\"the_operation_was_successful\">Selesai</string>\n    <plurals name=\"alert_failed_to_disable_background\">\n        <item quantity=\"other\">Tidak dapat mencegah aplikasi %1$d dari berjalan di latar belakang</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_uninstall\">\n        <item quantity=\"other\">Tak dapat menghapus aplikasi %1$d</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_clear_data\">\n        <item quantity=\"other\">Tidak dapat membersihkan data dari aplikasi %1$d</item>\n    </plurals>\n    <string name=\"export_blocking_rules\">Ekspor Aturan Penghalang</string>\n    <string name=\"disable_background\">Nonaktifkan Latar Belakang</string>\n    <string name=\"user_and_uid\">Pengguna:<xliff:g id=\"user_name\" example=\"root\">%1$s</xliff:g> (<xliff:g id=\"user_id\" example=\"0\">%2$d</xliff:g>)</string>\n    <string name=\"external_multiple_data_dir\">Penyimpanan Data Eksternal<xliff:g id=\"dir_no\" example=\"1\">%1$d</xliff:g></string>\n    <string name=\"sort_by_tracker_components\">Pelacak terlebih dulu</string>\n    <string name=\"deny_dangerous_permissions\">Tolak izin yang berbahaya</string>\n    <string name=\"sort_by_denied_permissions\">Ditolak terlebih dahulu</string>\n    <string name=\"sort_by_dangerous_permissions\">Berbahaya terlebih dahulu</string>\n    <string name=\"sort_by_permission_names\">Nama perizinan</string>\n    <string name=\"sort_by_app_ops_values\">Nilai operasi Aplikasi</string>\n    <string name=\"sort_by_denied_app_ops\">ditolak terlebih dahulu</string>\n    <string name=\"battery_mode\">Mode Baterai</string>\n    <string name=\"follow_system\">Ikuti Sistem</string>\n    <string name=\"pref_app_theme\">Tema Aplikasi</string>\n    <string name=\"pref_import_blocker_msg\">Impor peraturan pemblokir dari Blocker, setiap file mengandung peraturan dari sebuah paket.</string>\n    <string name=\"pref_import_watt_msg\">Impor peraturan penghadang dari Watt, setiap file mengandung peraturan dari sebuah paket ternama seperti <tt>packagename.xml</tt> dan lain sebagainya.</string>\n    <string name=\"pref_import_msg\">Impor peraturan penghadang yang baru saja di ekspor dari Manager Aplikasi.</string>\n    <string name=\"pref_export_msg\">Ekspor peraturan penghadang yang telah dikonfigurasi dengan Manager Aplikasi pada penyimpanan eksternal.</string>\n    <string name=\"ago\">lalu</string>\n    <string name=\"reject_time\">Tolak Waktu</string>\n    <string name=\"accept_time\">Terima Waktu</string>\n    <string name=\"duration\">Durasi</string>\n    <string name=\"running\">Berjalan</string>\n    <string name=\"mode\">Mode</string>\n    <string name=\"permission_name\">Nama Perizinan</string>\n    <string name=\"backup_external_data_description\">Cadangkan folder data eksternal.</string>\n    <string name=\"backup_apk_files_description\">Cadangkan hanya berkas APK dari direktori sumber. <b>Sumber</b> harus dipilih untuk ini dapat segera berfungsi.</string>\n    <string name=\"no_of_cores\">Core</string>\n    <string name=\"input_permissions_description\">Masukkan izin dengan spasi, mis. <tt>com.permission.GET_ACCOUNTS android.permission.ACCESS_MEDIA_LOCATION</tt> dll. Gunakan <tt>*</tt> untuk menetapkan pada semua izin.</string>\n    <string name=\"app_signing_install_without_data_loss\">Jika Anda telah mematikan verifikasi tanda tangan, Anda dapat menggunakan opsi <b> Hanya pasang </b> untuk memasang aplikasi tanpa kehilangan data.</string>\n    <string name=\"checksums\">Pemeriksa digit</string>\n    <string name=\"downgrade\">Turun grade</string>\n    <string name=\"process_state_with_extra\">Status: <xliff:g id=\"process_state\" example=\"Sleeping\">%1$s</xliff:g> (<xliff:g id=\"state_extra\" example=\"High priority\">%2$s</xliff:g>)</string>\n    <string name=\"state_multithreaded\">Multi thread</string>\n    <string name=\"state_foreground\">Layardepan</string>\n    <string name=\"state_parked\">Diparkirkan</string>\n    <string name=\"touchscreen_stylus\">Stilus</string>\n    <string name=\"navigation_dial_pad\">Pad Panggilan</string>\n    <string name=\"abi_split_for_base_apk\"><xliff:g id=\"split_name\" example=\"arm64_v8a\">%1$s</xliff:g> kode untuk basis APK</string>\n    <string name=\"density_split_for_base_apk\"><xliff:g id=\"split_name\" example=\"xxdpi\">%1$s</xliff:g> (<xliff:g id=\"dpi_no\" example=\"480\">%2$d</xliff:g> DPI) sumber untuk basis APK</string>\n    <string name=\"density_split_for_feature\"><xliff:g id=\"split_name\" example=\"xxdpi\">%1$s</xliff:g> (<xliff:g id=\"dpi_no\" example=\"480\">%2$d</xliff:g> DPI) sumber untuk fitur <xliff:g id=\"feature_name\" example=\"Visualizer\">%3$s</xliff:g></string>\n    <string name=\"installer_error_blocked\">Pemasangan diblokir oleh <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g></string>\n    <plurals name=\"verified_with_warning\">\n        <item quantity=\"other\">Diverifikasi dengan %d peringatan</item>\n    </plurals>\n    <plurals name=\"missing_signatures\">\n        <item quantity=\"other\">tanda tangan %1$d hilang</item>\n    </plurals>\n    <plurals name=\"libraries\">\n        <item quantity=\"other\">Pustaka %1$d</item>\n    </plurals>\n    <plurals name=\"classes\">\n        <item quantity=\"other\">kelas %1$d</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_set_app_ops\">\n        <item quantity=\"other\">Tidak dapat mengatur operasi aplikasi untuk %1$d aplikasi</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_block_components\">\n        <item quantity=\"other\">Tidak dapat memblokir komponen untuk %1$d aplikasi</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_unblock_trackers\">\n        <item quantity=\"other\">Tidak bisa membuka blokir pelacak dari %1$d aplikasi</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_delete_backup\">\n        <item quantity=\"other\">Tidak bisa menghapus %1$d cadangan</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_restore\">\n        <item quantity=\"other\">Tidak dapat memulihkan %1$d aplikasi</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_backup\">\n        <item quantity=\"other\">Tidak dapat mencadangkan %1$d aplikasi</item>\n    </plurals>\n    <plurals name=\"failed_to_backup_some_apk_files\">\n        <item quantity=\"other\">Tidak dapat mencadangkan %1$d aplikasi</item>\n    </plurals>\n    <string name=\"input_signatures_description\">Masukkan tanda tangan dengan spasi, mis. <tt>com.facebook org.app2 com.app3</tt> dll.</string>\n    <string name=\"clear_data_from_uninstalled_apps_description\">Hapus data dari aplikasi yang dicopot pemasangannya dengan tanda <tt>DONT_DELETE_DATA</tt></string>\n    <string name=\"deny_app_ops_description\">Tetapkan mode untuk operasi aplikasi yang diidentifikasi oleh nilai konstan, seperti <tt>63</tt> atau <tt>RUN_IN_BACKGROUND</tt></string>\n    <string name=\"block_components_dots\">Blok komponen…</string>\n    <string name=\"filter_apps_without_backups\">Tanpa cadangan</string>\n    <string name=\"uninstalled_apps\">Aplikasi yang dihapus</string>\n    <string name=\"installer_app_message\">Pilih <b>Pilih</b> untuk memilih dari aplikasi yang diinstal atau pilih <b>Kustom</b> untuk menentukan nama paket khusus.</string>\n    <string name=\"specify_custom_name\">Kustom</string>\n    <string name=\"verified_using_unreliable_hash\">Terverifikasi menggunakan hash yang tidak dapat diandalkan</string>\n    <string name=\"working_on_adb_mode\">Bekerja pada mode ADB</string>\n    <string name=\"screen_lock_not_enabled\">Silahkan pilih sebuah layar kunci di pengaturan Android, atau bersihkan data aplikasi.</string>\n    <string name=\"isolated\">Terpencil</string>\n    <string name=\"last_actions\">Tindakan terakhir</string>\n    <string name=\"enable_disable_features\">Aktifkan/nonaktifkan fitur</string>\n    <string name=\"installed_apps\">Aplikasi yang diinstal</string>\n    <string name=\"restart_to_reflect_changes\">Anda harus memulai ulang/restart perangkat segera untuk menggunakan perubahan terbaru.</string>\n    <string name=\"failed_to_change_ssaid\">Tidak dapat mengubah SSAID</string>\n    <string name=\"ssaid_info\">SSAID (<tt>Settings.Secure.ANDROID_ID</tt>) adalah pengidentifikasi perangkat yang ditugaskan ke setiap aplikasi (dari Android 8 \\\"Oreo\\\" keatas). Ini banyak digunakan oleh aplikasi untuk melacak pengguna.</string>\n    <string name=\"ssaid\">SSAID</string>\n    <string name=\"list_options\">Daftar opsi</string>\n    <string name=\"reverse\">Membalikkan</string>\n    <string name=\"add\">Menambahkan</string>\n    <string name=\"add_to_profile\">Tambahkan ke profil</string>\n    <string name=\"initializing\">Inisialisasi …</string>\n    <string name=\"net_policy\">Kebijakan net</string>\n    <string name=\"has_net_policy\">Kebijakan net</string>\n    <string name=\"choose_what_to_do\">Pilih apa yang harus dilakukan.</string>\n    <string name=\"enable_battery_optimization\">Aktifkan optimalisasi baterai\\?</string>\n    <string name=\"battery_optimization\">Optimalisasi Baterai</string>\n    <string name=\"no_battery_optimization\">Tidak ada optimalisasi baterai</string>\n    <string name=\"type_uri\">URI</string>\n    <string name=\"type_string_array_list\">Daftar string</string>\n    <string name=\"type_string_array\">Array of string</string>\n    <string name=\"type_float_array_list\">Daftar angka desimal</string>\n    <string name=\"type_float_array\">Array angka desimal</string>\n    <string name=\"type_long_array_list\">Daftar bilangan bulat panjang</string>\n    <string name=\"type_long_array\">Array bilangan bulat panjang</string>\n    <string name=\"type_int_array_list\">Daftar bilangan bulat</string>\n    <string name=\"type_int_array\">Array of Integers</string>\n    <string name=\"type_component_name\">Nama komponen</string>\n    <string name=\"type_null\">Tidak bernilai</string>\n    <string name=\"screen_lock_msg\">Lock App Manager menggunakan Android Screen Lock</string>\n    <string name=\"screen_lock\">Pengunci layar</string>\n    <string name=\"unlock_app_manager\">Buka kunci App Manager</string>\n    <string name=\"sd_card\">Kartu SD</string>\n    <string name=\"external_storage\">Penyimpanan luar</string>\n    <string name=\"internal_storage\">Penyimpanan internal</string>\n    <string name=\"back_up\">Cadangkan</string>\n    <string name=\"drm_free_apkm_msg\">File APKM bebas DRM, tidak perlu mengubahnya menjadi APK.</string>\n    <string name=\"restore_msg\">Kembalikan aplikasi dengan data</string>\n    <string name=\"backup_msg\">Cadangkan aplikasi dengan data</string>\n    <string name=\"restore_latest_msg\">Memulihkan aplikasi yang sudah diinstal yang kode versinya lebih tinggi dari kode versi yang diinstal.</string>\n    <string name=\"restore_latest\">Kembalikan cadangan terbaru</string>\n    <string name=\"restore_not_installed_msg\">Pulihkan cadangan dasar untuk aplikasi yang saat ini tidak diinstal.</string>\n    <string name=\"restore_not_installed\">Pulihkan aplikasi tidak diinstal</string>\n    <string name=\"restore_all_msg\">Pulihkan cadangan dasar dari semua aplikasi yang didukung.</string>\n    <string name=\"restore_all\">Kembalikan semua aplikasi</string>\n    <string name=\"backup_apps_with_changes_msg\">Redo backup untuk aplikasi dengan perubahan sejak cadangan terakhir. Mereka termasuk perubahan ukuran, versi, waktu peluncuran terakhir.</string>\n    <string name=\"backup_apps_with_changes\">Cadangkan aplikasi dengan perubahan</string>\n    <string name=\"redo_existing_backups_msg\">Ulangi cadangan untuk aplikasi yang diinstal dengan cadangan sebelumnya.</string>\n    <string name=\"redo_existing_backups\">Redo backup yang ada</string>\n    <string name=\"verify_and_redo_backups_msg\">Periksa integritas dari cadangan sebelumnya dan kembalikan/redo cadangan di mana pemeriksaan integritasnya gagal.</string>\n    <string name=\"verify_and_redo_backups\">Verifikasi dan Redo Backups</string>\n    <string name=\"backup_apps_without_backups_msg\">Cadangkan aplikasi tanpa cadangan sebelumnya.</string>\n    <string name=\"backup_apps_without_backups\">Cadangkan aplikasi tanpa cadangan</string>\n    <string name=\"backup_all_apps_msg\">Cadangkan semua aplikasi yang diinstal.</string>\n    <string name=\"backup_all_apps\">Cadangkan semua aplikasi</string>\n    <string name=\"backup_custom_users_description\">Lakukan cadangan hanya untuk pengguna yang ditentukan</string>\n    <string name=\"backup_custom_users\">Pengguna Kustom</string>\n    <string name=\"bootloader\">Bootloader</string>\n    <string name=\"encrypted\">Terenkripsi</string>\n    <string name=\"unencrypted\">Tidak terenkripsi</string>\n    <string name=\"no_volumes_found\">Tidak dapat menemukan volume dengan izin tulis.</string>\n    <string name=\"pref_backup_volume_msg\">Pilih volume atau disk di mana cadangan akan disimpan.</string>\n    <string name=\"backup_volume\">Volume cadangan</string>\n    <string name=\"pref_backup_restore_msg\">Kustomisasi cadangan/pemulihan.</string>\n    <string name=\"disable_background_run_description\">Mengatur mode <i> Abaikan </i> untuk operasi aplikasi berikut: <tt>RUN_IN_BACKGROUND</tt> (dari Android 7.0) dan <tt>RUN_ANY_IN_BACKGROUD</tt> (dari Android 9).</string>\n    <string name=\"failed_to_enable_magisk_hide\">Tidak dapat mengaktifkan Magiskhide</string>\n    <string name=\"failed_to_disable_magisk_hide\">Tidak dapat menonaktifkan Magiskhide</string>\n    <string name=\"window_size\">Ukuran jendela</string>\n    <string name=\"refresh_rate\">Refresh Rate</string>\n    <string name=\"scaling_factor\">Faktor Penskalaan</string>\n    <string name=\"size\">Ukuran</string>\n    <string name=\"density\">Massa jenis</string>\n    <string name=\"screen\">Layar</string>\n    <string name=\"hardware\">Perangkat keras</string>\n    <string name=\"permissive\">Permisif</string>\n    <string name=\"enforcing\">Menegakkan</string>\n    <string name=\"selinux\">Selinux</string>\n    <string name=\"patch_level\">Tingkat tambalan</string>\n    <string name=\"backup_skip_signature_checks_description\">Pulihkan cadangan yang gagal dikarenakan kegagalan verifikasi checksum atau memiliki tanda tangan APK yang berbeda dari apa yang telah dicadangkan sebelumnya.</string>\n    <string name=\"backup_multiple_description\">Buat sebuah cadangan terpisah <i>dinamai</i> cadangan daripada cadangan basis.</string>\n    <string name=\"backup_rules_description\">Aturan cadangan dikonfigurasi dalam manajer aplikasi. <font fgcolor=\"#ff0000\">Tergantung pada perizinan, tidak semua aturan dapat di aplikasikan kembali setelah di pulihkan.</font></string>\n    <string name=\"backup_extras_description\">Cadangkan izin aplikasi, penghemat baterai dan opsi penggunaan data, status MagiskHide, SSAID, dll. <font fgcolor=\"#ff0000\">Tergantung pada perizinan, Tidak semua pilihan dapat di pulihkan.</font></string>\n    <string name=\"backup_extras\">Ekstra</string>\n    <string name=\"backup_cache_description\">Cadangkan folder <b>cache</b>, <b>no_cache</b> dan <b>no_backup</b>.</string>\n    <string name=\"backup_obb_media_description\">Cadangkan Folder OBB dan Media.</string>\n    <string name=\"backup_internal_data_description\">Cadangkan folder data. Jika dipilih, folder data internal akan dicadangkan secara default.</string>\n    <string name=\"set_mode_for_app_ops_dots\">Atur Mode untuk Ops Aplikasi …</string>\n    <string name=\"security\">Keamanan</string>\n    <string name=\"battery\">Baterai</string>\n    <string name=\"graphics\">Grafik</string>\n    <string name=\"cpu\">CPU</string>\n    <string name=\"users\">Pengguna</string>\n    <string name=\"languages\">Bahasa</string>\n    <string name=\"battery_capacity\">Kapasitas</string>\n    <string name=\"memory\">Penyimpanan</string>\n    <string name=\"vendor\">Penjaja</string>\n    <string name=\"gles_version\">Versi OpenGL ES</string>\n    <string name=\"support_architectures\">Arsitektur yang didukung</string>\n    <string name=\"security_providers\">Penyedia Keamanan</string>\n    <string name=\"kernel\">Inti</string>\n    <string name=\"manufacturer\">Pabrikan</string>\n    <string name=\"board_name\">Naik</string>\n    <string name=\"model\">Model</string>\n    <string name=\"brand_name\">Merek</string>\n    <string name=\"pref_about_device_msg\">Info perangkat dasar termasuk sistem Android, CPU, GPU, RAM, baterai, dll.</string>\n    <string name=\"about_device\">Tentang perangkat</string>\n    <string name=\"set_custom_app_op\">Atur aplikasi Kustom OP</string>\n    <string name=\"interceptor\">Pencegat</string>\n    <string name=\"resend_intent\">Kirim ulang niat</string>\n    <string name=\"share\">Bagikan</string>\n    <string name=\"extras\">Ekstra</string>\n    <string name=\"category\">Kategori</string>\n    <string name=\"uri\">URI</string>\n    <string name=\"mime_type\">Jenis MIME</string>\n    <string name=\"action\">Tindakan</string>\n    <string name=\"result_code\">Kode hasil</string>\n    <string name=\"activity_result\">Hasil Aktivitas</string>\n    <string name=\"send_edited_intent\">Kirim niat yang diedit</string>\n    <string name=\"matching_activities\">Kegiatan yang cocok</string>\n    <string name=\"value\">Nilai</string>\n    <string name=\"filter_apps_with_splits\">Dengan pembagi</string>\n    <string name=\"set_app_op_mode\">Atur Mode Op Aplikasi</string>\n    <string name=\"magisk_hide_enabled\">Magiskhide</string>\n    <string name=\"pref_backup_android_keystore_msg\">Tidak semua aplikasi akan bekerja setelah dipulihkan. Memulihkan KeyStore tidak berfungsi pada sebagian besar perangkat.</string>\n    <string name=\"pref_backup_android_keystore\">Cadangkan aplikasi dengan KeyStore Android</string>\n    <string name=\"keep_data_and_app_signing_signatures\">Simpan data dan tanda tangan</string>\n    <string name=\"this_action_cannot_be_undone\">Tindakan ini tidak bisa dibatalkan.</string>\n    <string name=\"no_app_ops_permission\">Tidak ada izin untuk menampilkan ops aplikasi</string>\n    <string name=\"input_keystore_alias_pass_description\">Masukkan kata sandi untuk alias <b>%1$s</b>. Anda dapat meninggalkan ini kosong jika kata sandi sama dengan kata sandi keystore.</string>\n    <string name=\"input_keystore_alias_pass\">Kata sandi untuk alias <b>%1$s</b></string>\n    <string name=\"input_keystore_pass_msg\">Ketuk di sini untuk memasukkan kata sandi KeyStore</string>\n    <string name=\"input_keystore_pass_description\">Masukkan kata sandi KeyStore App Manager. Jika Anda melihat ini untuk pertama kalinya, silakan gunakan generator kata sandi untuk menghasilkan sebuah kata sandi dan menyimpannya di tempat yang aman sebelum memasukkannya ke sini.</string>\n    <string name=\"input_keystore_pass\">Password keystore input</string>\n    <string name=\"splits\">Terbagi</string>\n    <string name=\"source_stamp_verified\">SourceRamp memverifikasi.</string>\n    <string name=\"not_verified\">Tidak diverifikasi</string>\n    <string name=\"verified\">Diverifikasi</string>\n    <string name=\"pref_signature_schemes_msg\">Setidaknya skema V1 dan V2 harus dipilih untuk kompatibilitas yang lebih besar. Skema V4 membutuhkan V2 atau V3.</string>\n    <string name=\"v4_scheme\">Skema V4 (sejak Android 11)</string>\n    <string name=\"v3_scheme\">Skema V3 (sejak Android 9)</string>\n    <string name=\"v2_scheme\">Skema V2 (sejak Android 7.0)</string>\n    <string name=\"v1_scheme\">Skema V1 (sejak Android 1.0)</string>\n    <string name=\"pref_apk_signing_msg\">Atur skema tanda tangan, kunci penandatanganan kustom, dll.</string>\n    <string name=\"apk_signing\">Tanda tangan apk</string>\n    <string name=\"app_signing_signature_schemes\">Skema tanda tangan</string>\n    <string name=\"pref_sign_apk_msg\">Tandatangani file APK sebelum memasangnya.</string>\n    <string name=\"pref_sign_apk\">Tanda APK</string>\n    <string name=\"install_location_prefer_external\">Memilih eksternal</string>\n    <string name=\"install_location_internal_only\">Hanya internal</string>\n    <string name=\"install_location\">Lokasi Pemasangan</string>\n    <string name=\"installer\">Pemasangan</string>\n    <string name=\"comment\">Komentar</string>\n    <string name=\"close\">Tutup</string>\n    <string name=\"no_root\">Tanpa Root</string>\n    <string name=\"root\">Root</string>\n    <string name=\"user_profile_with_id\">Profil: %1$s (%2$d)</string>\n    <string name=\"advanced\">Maju</string>\n    <string name=\"simple\">Sederhana</string>\n    <string name=\"enabled\">Diaktifkan</string>\n    <string name=\"choose\">Memilih</string>\n    <string name=\"input_permissions\">Izin Input</string>\n    <string name=\"options\">Pilihan</string>\n    <string name=\"off\">Mati</string>\n    <string name=\"on\">Di</string>\n    <string name=\"profile_state_msg\">Status kustom On/Off untuk profil ini</string>\n    <string name=\"profile_block_trackers_msg\">Blokir pelacak dalam aplikasi</string>\n    <string name=\"profile_clear_data_msg\">Bersihkan data dari aplikasi</string>\n    <string name=\"profile_clear_cache_msg\">Bersihkan cache aplikasi dari berbagai aplikasi</string>\n    <string name=\"profile_force_stop_msg\">Paksa-berhenti aplikasi</string>\n    <string name=\"allow_routine_ops_msg\">Izinkan profil digunakan dalam operasi rutin</string>\n    <string name=\"profile_state\">Status Profil</string>\n    <string name=\"allow_routine_ops\">Izinkan oprs rutin</string>\n    <string name=\"adb_over_tcp\">ADB Over TCP</string>\n    <string name=\"pref_mode_of_operations\">Modus operasi</string>\n    <string name=\"send_selected\">Kirim Terpilih</string>\n    <string name=\"ecc\">Kriptografi kurva eliptik</string>\n    <string name=\"rsa\">RSA</string>\n    <string name=\"aes\">AES</string>\n    <string name=\"none\">Tidak ada</string>\n    <string name=\"pref_encryption_msg\">Enkripsi untuk cadangan.</string>\n    <string name=\"encryption\">Enkripsi</string>\n    <string name=\"select_user\">Pilih Pengguna</string>\n    <string name=\"failed_to_duplicate_profile\">Tidak dapat menduplikasi profil</string>\n    <string name=\"duplicate\">Duplikat</string>\n    <string name=\"new_profile\">Profil baru</string>\n    <string name=\"input_profile_name_description\">Nama profil tidak dapat berisi spasi apa pun.</string>\n    <string name=\"input_profile_name\">Nama profil</string>\n    <string name=\"un_apkm\">UNAPKM</string>\n    <string name=\"in_progress\">Sedang berlangsung</string>\n    <string name=\"conversion_failed\">Konversi gagal.</string>\n    <string name=\"select_apk\">Pilih APK</string>\n    <string name=\"send_crash_report\">Kirim Laporan Kecelakaan</string>\n    <string name=\"tap_to_submit_crash_report\">Ketuk untuk mengirimkan laporan kerusakan.</string>\n    <string name=\"am_crashed\">App Manager baru saja crash</string>\n    <string name=\"filter_running_apps\">Aplikasi yang sedang berjalan</string>\n    <string name=\"copy\">Salinan</string>\n    <string name=\"view_missing_signatures\">Ketuk untuk melihat atau mengirim tanda tangan belum ada di database Perpustakaan App Manager.</string>\n    <string name=\"tap_to_see_details\">Ketuk untuk melihat detail</string>\n    <string name=\"lib_details\">Detail Perpustakaan</string>\n    <string name=\"no_libs\">Tidak ada perpustakaan</string>\n    <string name=\"scanner\">Pemindai</string>\n    <string name=\"sys_config\">Konfigurasi Sistem</string>\n    <string name=\"only_install\">Hanya instal</string>\n    <string name=\"app_data_will_be_lost\">Data yang ada akan hilang.</string>\n    <string name=\"app_signing_signature_mismatch_for_system_apps\">Tidak dapat menginstal aplikasi karena aplikasi sistem dengan tanda tangan yang berbeda memiliki nama paket ini.</string>\n    <string name=\"do_you_want_to_uninstall_and_install\">Apakah Anda ingin menghapus dan menginstal aplikasi lagi\\?</string>\n    <string name=\"usage_access_not_supported\">Tidak dapat meminta akses penggunaan, karena halaman pengaturan yang sesuai tidak ada.</string>\n    <string name=\"non_critical_exts\">Ekstensi non-kritis</string>\n    <string name=\"critical_exts\">Ekstensi Kritis</string>\n    <string name=\"dsa_affine_y\">Affine Y Koordinat</string>\n    <string name=\"dsa_affine_x\">Affine x koordinat</string>\n    <string name=\"rsa_modulus\">Modulus</string>\n    <string name=\"rsa_exponent\">Eksponen</string>\n    <string name=\"format\">Format</string>\n    <string name=\"public_key\">Kunci Publik</string>\n    <string name=\"algorithm\">Algoritma</string>\n    <string name=\"app_signing_signature\">Tanda tangan</string>\n    <string name=\"serial_no\">Nomor seri</string>\n    <string name=\"not_yet_valid\">Belum valid</string>\n    <string name=\"expired\">Kedaluwarsa</string>\n    <string name=\"valid\">Sah</string>\n    <string name=\"validity\">Keabsahan</string>\n    <string name=\"type\">Tipe</string>\n    <string name=\"expiry_date\">Tanggal kadaluarsa</string>\n    <string name=\"issued_date\">Tanggal Dikeluarkan</string>\n    <string name=\"issuer\">Penerbit</string>\n    <string name=\"subject\">Subyek</string>\n    <string name=\"filter_apps_with_backups\">Dengan cadangan</string>\n    <string name=\"sort_by_backup\">Dicaadangkan terlebih dulu</string>\n    <string name=\"failed_to_uninstall_updates\">Tidak dapat mencopot pembaruan untuk <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g>.</string>\n    <string name=\"update_uninstalled_successfully\">Pembaruan untuk <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g> telah dicopot.</string>\n    <string name=\"uninstall_updates\">Copot Pembaruan</string>\n    <string name=\"allow_open_pgp_operation\">Tekan untuk mengizinkan App Manager menggunakan OpenPGP</string>\n    <string name=\"confirm_installation\">Konfirmasi Pemasangan</string>\n    <string name=\"pref_backup_flags_msg\">Menambahkan sebuah preset untuk opsi cadangan akan menghapus beban pemilihan bendera setiap kali Anda cadangkan/pulihkan.</string>\n    <string name=\"rules\">Aturan</string>\n    <string name=\"other\">Lain</string>\n    <string name=\"changes_not_saved\">Perubahan tidak disimpan</string>\n    <string name=\"sort_by_memory_usage\">Penggunaan memori</string>\n    <string name=\"sort_by_apps_first\">Aplikasi pertama</string>\n    <string name=\"sort_by_process_name\">Nama proses</string>\n    <string name=\"sort_by_process_id\">ID Proses</string>\n    <string name=\"filter_apps\">Aplikasi</string>\n    <string name=\"no_apps\">Tidak ada aplikasi</string>\n    <string name=\"apps\">Aplikasi</string>\n    <string name=\"routine_ops\">Operasi rutin</string>\n    <string name=\"apply_now\">Terapkan sekarang…</string>\n    <string name=\"keystore\">Keystore</string>\n    <string name=\"no_profiles\">Tanpa Profil</string>\n    <string name=\"profiles\">Profil</string>\n    <string name=\"open_pgp_provider\">Penyedia OpenPGP</string>\n    <string name=\"systemless_app\">Aplikasi tanpa Sistem</string>\n    <string name=\"cancel\">Batal</string>\n    <string name=\"ok\">Oke</string>\n    <string name=\"input_backup_name_description\">Nama cadangan tidak boleh dimulai dengan digit atau harus mengandung spasi. Biarkan kosong jika Anda ingin menggunakan waktu tanggal saat ini.</string>\n    <string name=\"input_backup_name\">Nama cadangan</string>\n    <string name=\"process_state\">Status: <xliff:g id=\"process_state\" example=\"Sleeping\">%1$s</xliff:g></string>\n    <string name=\"state_session_leader\">Pemimpin sesi</string>\n    <string name=\"state_locked_memory\">Memori yang terkunci</string>\n    <string name=\"state_low_priority\">Prioritas rendah</string>\n    <string name=\"state_high_priority\">Prioritas utama</string>\n    <string name=\"state_unknown\">Tidak Dikenal</string>\n    <string name=\"state_waking\">Bangun</string>\n    <string name=\"state_wake_kill\">Bangun membunuh</string>\n    <string name=\"state_idle\">Diam</string>\n    <string name=\"state_zombie\">Zombie</string>\n    <string name=\"state_dead\">Mati</string>\n    <string name=\"state_trace_stop\">Trace Stop</string>\n    <string name=\"state_device_io\">Perangkat I/O</string>\n    <string name=\"state_sleeping\">Tidur</string>\n    <string name=\"touchscreen_finger\">Jari</string>\n    <string name=\"touchscreen_no_touch\">Tidak ada sentuhan</string>\n    <string name=\"navigation_wheel\">Roda</string>\n    <string name=\"navigation_trackball\">Trackball</string>\n    <string name=\"navigation_no_nav\">Tidak NAV</string>\n    <string name=\"keyboard_12_keys\">12 kunci</string>\n    <string name=\"keyboard_qwerty\">QWERTY</string>\n    <string name=\"keyboard_no_keys\">Tidak ada kunci</string>\n    <string name=\"_undefined\">Tidak terdefinisi</string>\n    <string name=\"required\">Yg dibutuhkan</string>\n    <string name=\"orientation_user_portrait\">Potret Pengguna</string>\n    <string name=\"orientation_user_landscape\">Pemandangan pengguna</string>\n    <string name=\"orientation_sensor\">Sensor</string>\n    <string name=\"orientation_sensor_portrait\">Potret Sensor</string>\n    <string name=\"orientation_sensor_landscape\">Lanskap sensor</string>\n    <string name=\"orientation_user\">Pengguna</string>\n    <string name=\"orientation_reverse_landscape\">Balikkan lanskap</string>\n    <string name=\"orientation_reverse_portrait\">Potret terbalik</string>\n    <string name=\"orientation_portrait\">Potret</string>\n    <string name=\"orientation_landscape\">Pemandangan</string>\n    <string name=\"orientation_no_sensor\">Tidak sensor</string>\n    <string name=\"orientation_locked\">Terkunci</string>\n    <string name=\"orientation_full_user\">Pengguna penuh</string>\n    <string name=\"orientation_full_sensor\">Sensor penuh</string>\n    <string name=\"orientation_behind\">Dibelakang</string>\n    <string name=\"orientation_unspecified\">Tidak ditentukan</string>\n    <string name=\"launch_mode_single_top\">Single Top</string>\n    <string name=\"launch_mode_single_task\">Tugas tunggal</string>\n    <string name=\"launch_mode_single_instance\">Contoh tunggal</string>\n    <string name=\"launch_mode_multiple\">Ganda</string>\n    <string name=\"locale_split_for_base_apk\"><xliff:g id=\"split_name\" example=\"English\">%1$s</xliff:g> lokal untuk basis APK</string>\n    <string name=\"locale_split_for_feature\"><xliff:g id=\"split_name\" example=\"English\">%1$s</xliff:g> lokal untuk fitur <xliff:g id=\"feature_name\" example=\"Visualizer\">%2$s</xliff:g></string>\n    <string name=\"abi_split_for_feature\"><xliff:g id=\"split_name\" example=\"arm64_v8a\">%1$s</xliff:g> code for <xliff:g id=\"feature_name\" example=\"Visualizer\">%2$s</xliff:g></string>\n    <string name=\"backup_all_users\">Semua pengguna</string>\n    <string name=\"backup_multiple\">Cadangkan banyak</string>\n    <string name=\"obb_files_extracted_successfully\">File OBB diekstraksi</string>\n    <string name=\"failed_to_extract_obb_files\">Tidak dapat mengekstrak file OBB</string>\n    <string name=\"backup_obb_media\">OBB dan media</string>\n    <string name=\"backup_apk_files\">Berkas APK</string>\n    <string name=\"installer_error_session_abandon\">Tidak bisa meninggalkan sesi installer</string>\n    <string name=\"installer_error_session_commit\">Tidak dapat melakukan file APK</string>\n    <string name=\"installer_error_session_write\">Tidak bisa menulis ke sesi installer</string>\n    <string name=\"installer_error_session_create\">Tidak dapat membuat sesi installer</string>\n    <string name=\"installer_error_security\">Tidak dapat mengakses file APK</string>\n    <string name=\"install_in_progress\">Pemasangan…</string>\n    <string name=\"package_installer\">Penginstal Paket</string>\n    <string name=\"unblock_trackers\">Buka blokir pelacak</string>\n    <string name=\"reinstall\">Instal ulang</string>\n    <string name=\"install_app_message\">Apakah kamu ingin menginstal aplikasi ini\\?</string>\n    <string name=\"try_again\">Coba lagi</string>\n    <string name=\"full_stop_tap_to_see_details\">Ketuk untuk melihat detail.</string>\n    <string name=\"operation_running\">Operasi berjalan …</string>\n    <string name=\"batch_ops\">Operasi batch</string>\n    <string name=\"failed_to_fetch_package_info\">Tidak dapat mengambil info paket</string>\n    <string name=\"installer_error_lidl_rom\">ROM Anda tidak kompatibel dengan instaler Rootless.</string>\n    <string name=\"installer_error_generic\">Instalasi gagal</string>\n    <string name=\"installer_error_storage\">Tidak cukup ruang penyimpanan untuk menginstal aplikasi</string>\n    <string name=\"installer_error_bad_apks\">File APK tidak valid yang dipilih</string>\n    <string name=\"installer_error_incompatible\">Aplikasi ini tidak kompatibel dengan perangkat ini</string>\n    <string name=\"installer_error_conflict\">Tidak dapat memasang aplikasi karena nama paket sedang digunakan</string>\n    <string name=\"installer_error_aborted\">Instalasi gagal karena dibatalkan atau sesi ditutup secara tak terduga</string>\n    <string name=\"toggle_default_app_ops\">Beralih op aplikasi default</string>\n    <string name=\"filter_apps_with_activities\">Dengan aktivitas</string>\n    <string name=\"are_you_sure\">Apakah Anda yakin\\?</string>\n    <string name=\"pref_remove_all_rules_msg\">Izin akan diberikan, Ops aplikasi dan komponen akan kembali ke nilai default mereka.</string>\n    <string name=\"pref_remove_all_rules\">Hapus semua aturan</string>\n    <string name=\"website\">Situs web</string>\n    <string name=\"run_in_termux\">Jalankan di Termusx</string>\n    <string name=\"open_in_termux\">Buka di Termusx</string>\n    <string name=\"export_icon\">Ikon ekstrak</string>\n    <string name=\"no_matching_package_found\">Tidak ditemukan aplikasi apapun seperti itu</string>\n    <string name=\"block_unblock_trackers\">Blok / Buka Blokir Pelacak</string>\n    <string name=\"unblock\">Buka blokir</string>\n    <string name=\"block\">Blok</string>\n    <string name=\"clear\">Bersih</string>\n    <string name=\"clear_data_message\">Apakah kamu yakin ingin menghapus data dari aplikasi ini\\?</string>\n    <string name=\"skip_signature_checks\">Lewati pemeriksaan tanda tangan</string>\n    <string name=\"yes\">Iya</string>\n    <string name=\"no\">Tidak</string>\n    <string name=\"apply_to_system_apps_question\">Terapkan untuk aplikasi sistem juga\\? Pilih \\\"Tidak\\\" jika tidak yakin.</string>\n    <string name=\"apply_to_system_apps\">Berlaku untuk aplikasi sistem</string>\n    <plurals name=\"app_signing_signature_schemes_pl\">\n        <item quantity=\"other\">Skema tanda tangan</item>\n    </plurals>\n    <plurals name=\"backup_exists_are_you_sure\">\n        <item quantity=\"other\">Lebih dari satu aplikasi telah memiliki cadangan. Apakah Anda yakin\\?</item>\n    </plurals>\n    <string name=\"backup_options\">Opsi cadangan</string>\n    <string name=\"delete_backup\">Hapus cadangan</string>\n    <string name=\"restore\">Mengembalikan</string>\n    <string name=\"backup\">Cadangan</string>\n    <string name=\"data\">Data</string>\n    <string name=\"external_data\">Data eksternal</string>\n    <string name=\"blocking_rules\">Memblokir aturan</string>\n    <string name=\"whats_new\">Apa yang baru</string>\n    <string name=\"features\">Fitur</string>\n    <string name=\"components\">Komponen</string>\n    <string name=\"trackers\">Pelacak</string>\n    <string name=\"installed_version\">Versi yang diinstal</string>\n    <string name=\"select_all\">Pilih Semua</string>\n    <string name=\"filter_apps_with_rules\">Aplikasi dengan aturan</string>\n    <string name=\"filter_system_apps\">Aplikasi Sistem</string>\n    <string name=\"filter_user_apps\">Aplikasi Pengguna</string>\n    <string name=\"filter\">Filter</string>\n    <string name=\"package_name_is_installed_successfully\"><xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g> terpasang</string>\n    <string name=\"termux\">Termux</string>\n    <plurals name=\"no_of_splits\">\n        <item quantity=\"other\">Pembagian %1$d</item>\n    </plurals>\n    <string name=\"failed_to_parse_some_numbers\">Tidak dapat menguraikan beberapa angka</string>\n    <string name=\"only_works_in_root_or_adb_mode\">Hanya bekerja dalam mode root atau ADB</string>\n    <string name=\"input_app_ops_description_profile\">Masukkan nama oprs aplikasi dan/atau konstanta dengan spasi, mis. <tt>WAKE_LOCK 63 72 CAMERA</tt> dll. Gunakan <tt>*</tt> untuk menerapkan pada semua ops aplikasi yang dikonfigurasi.</string>\n    <string name=\"input_app_ops_description\">Masukkan nama oprs aplikasi dan/atau konstanta dengan spasi, mis. <tt>WAKE_LOCK 63 72 CAMERA</tt> dll.</string>\n    <string name=\"input_app_ops\">Input oprs aplikasi</string>\n    <string name=\"filtered_packages\">Paket terfilter</string>\n    <string name=\"input_signatures\">Masukkan tanda tangan</string>\n    <string name=\"failed_packages\">Paket Gagal</string>\n    <string name=\"no_tracker_found\">Tidak ada pelacak yang ditemukan</string>\n    <string name=\"clear_app_cache_description\">Kosongkan cache dari semua aplikasi</string>\n    <string name=\"clear_app_cache\">Kosongkan Cache App</string>\n    <string name=\"clear_data_from_uninstalled_apps\">Hapus data dari aplikasi yang telah dicopot pemasangannya</string>\n    <string name=\"block_unblock_trackers_description\">Blokir atau buka blokir iklan dan komponen pelacakan di semua aplikasi yang dipasang</string>\n    <string name=\"clear_cache\">Kosongkan Cache</string>\n    <string name=\"pref_import_existing_msg\">Tambahkan komponen yang dinonaktifkan oleh aplikasi lain ke App Manager. Hati-hati saat menggunakan alat ini karena ada banyak false-positif. Pilih hanya aplikasi yang Anda pasti.</string>\n    <string name=\"pref_import_existing\">Impor aturan yang ada</string>\n    <string name=\"source_code\">Kode Sumber</string>\n    <string name=\"update\">Pembaruan</string>\n    <string name=\"install\">Pasang</string>\n    <plurals name=\"no_of_components\">\n        <item quantity=\"other\">Komponen %1$d</item>\n    </plurals>\n    <plurals name=\"no_of_trackers\">\n        <item quantity=\"other\">Pelacak %1$d</item>\n    </plurals>\n    <string name=\"manifest_viewer\">Penampil Manifest</string>\n    <string name=\"external_apk_no_app_op\">APK Eksternal tidak mempunyai operasi aplikasi apapun</string>\n    <string name=\"changelog\">Log Perubahan</string>\n    <string name=\"one_click_ops\">Operasi 1 Kali Klik</string>\n    <string name=\"never_ask\">Jangan pernah tanya</string>\n    <string name=\"launch_app\">Luncurkan</string>\n    <string name=\"failed_to_deny_dangerous_app_ops\">Tidak dapat mencabut semua operasi aplikasi yang berbahaya</string>\n    <string name=\"failed_to_deny_dangerous_perms\">Tidak dapat mencabut semua izin yang berbahaya</string>\n    <string name=\"failed_to_reset_app_ops\">Tidak dapat menset ulang operasi aplikasi</string>\n    <string name=\"failed_to_revoke_permission\">Tidak dapat mencabut izin</string>\n    <string name=\"failed_to_grant_permission\">Tidak dapat memberikan izin</string>\n    <plurals name=\"alert_failed_to_disable_trackers\">\n        <item quantity=\"other\">Tidak dapat menonaktifkan pelacak dari aplikasi %1$d</item>\n    </plurals>\n    <string name=\"unknown_op\">Operasi Tidak Diketahui</string>\n    <string name=\"internal_data\">Data internal</string>\n    <string name=\"pref_installer_msg\">Konfigurasikan tingkah dari pemasang aplikasi.</string>\n    <string name=\"expiry_date_cannot_be_empty\">Tangal kadaluarsa tidak bisa kosong.</string>\n    <string name=\"signing_key\">Kunci tanda masuk/sign</string>\n    <string name=\"failed_to_read_keystore\">Tidak dapat membaca KeyStore.</string>\n    <string name=\"alias_pass\">Kata sandi samaran/alias</string>\n    <string name=\"choose_an_alias\">Pilih sebuah samaran/alias</string>\n    <string name=\"found_no_alias_in_keystore\">Tidak ditemukan samaran/alias dalam KeyStore!</string>\n    <string name=\"new_alias_password\">Kata sandi samaran baru/alias</string>\n    <string name=\"import_key\">Impor kunci</string>\n    <string name=\"pem_file\">Berkas PEM</string>\n    <string name=\"pk8_file\">Berkas PKCS #8 (PK8)</string>\n    <string name=\"pem_and_pk8\">PEM dan PKCS #8 (PK8)</string>\n    <string name=\"pkcs12_keystore\">KeyStore PKCS #12 (P12)</string>\n    <string name=\"bouncy_castle_keystore\">KeyStore Bouncy Castle (BKS)</string>\n    <string name=\"java_keystore\">KeyStore Java (JKS)</string>\n    <string name=\"keystore_pass\">Kata sandi KeyStore</string>\n    <string name=\"keystore_file\">Berkas KeyStore</string>\n    <string name=\"country_name\" tools:ignore=\"TypographyOther\">Nama negara (C)</string>\n    <string name=\"state_name\">Nama provinsi (ST)</string>\n    <string name=\"locality_name\">Nama pelokalan (kota) (L)</string>\n    <string name=\"organization_name\">Nama organisasi (O)</string>\n    <string name=\"organization_unit\">Unit organisasi (OU)</string>\n    <string name=\"common_name\">Nama umum (CN)</string>\n    <string name=\"input_key_password\">Kata sandi kunci</string>\n    <string name=\"failed_to_load_key\">Tidak dapat memuat kunci.</string>\n    <string name=\"key_not_set\">Tidak diatur.</string>\n    <string name=\"use_default\">Gunakan bawaan/default</string>\n    <string name=\"invalid_rsa_key_size\">Ukuran kunci yang tidak valid untuk enskripsi RSA. Ukuran kunci dapat berupa 1024, 204, atau 4096 bit.</string>\n    <string name=\"crypto_key_size\">Ukuran kunci</string>\n    <string name=\"invalid_aes_key_size\">Ukuran kunci yang tidak valid untuk enskripsi AES. Ukuran kunci dapat berupa 128 atau 256 bit.</string>\n    <string name=\"failed_to_initialize_key_store\">Tidak dapat meng-inisialisasi keystore App Manager.</string>\n    <string name=\"failed_to_save_key\">Tidak dapat menyimpan kunci.</string>\n    <string name=\"generate_key\">Hasilkan</string>\n    <string name=\"input_key\">Kunci input (dalam heksadesimal)</string>\n    <string name=\"input_keystore_alias_pass_msg\">Ketuk disini untuk menyediakan kata sandi untuk %1$s</string>\n    <string name=\"source_code_links\"></string>\n    <string name=\"trackers_unblocked_successfully\">Pelacak sekarang dibatalkan diblokir</string>\n    <string name=\"trackers_blocked_successfully\">Pelacak sekarang diblokir</string>\n    <string name=\"failed_to_unblock_trackers\">Tidak dapat batal memblokir pelacak</string>\n    <string name=\"failed_to_block_trackers\">Tidak dapat memblokir pelacak</string>\n    <string name=\"profile_save_apk_msg\">Simpan berkas APK di <tt>AppManager/apks</tt></string>\n    <string name=\"save_apk\">Simpan APK</string>\n    <string name=\"running_services\">Menjalankan Layanan</string>\n    <string name=\"view_logs\">Lihat catatan log</string>\n    <string name=\"share_log\">Bagikan</string>\n    <string name=\"text_include_dmesg\">termasuk log kernel</string>\n    <string name=\"omit_sensitive_info_summary\">Hilangkan informasi sensitif seperti alamat url web, nomor telepon atau email.</string>\n    <string name=\"omit_sensitive_info\">Hilangkan informasi sensitif</string>\n    <string name=\"undo\">Kembalikan</string>\n    <string name=\"pause_unpause\">Putar/Jeda</string>\n    <string name=\"collapse_all\">Perkecil Semua</string>\n    <string name=\"expand_all\">Perluas Semua</string>\n    <string name=\"file\">Berkas</string>\n    <string name=\"widget_start_recording\">Rekam\n\\nLog</string>\n    <string name=\"widget_recording_in_progress\">Merekam…</string>\n    <string name=\"unable_to_save_log\">Tidak dapat menyimpan catatan log. Apakah Anda memasukkan sebuah nama berkas yang valid\\?</string>\n    <plurals name=\"toast_log_truncated\">\n        <item quantity=\"other\">Catatan log terlalu besar, menampilkan baris %d terakhir.</item>\n    </plurals>\n    <string name=\"toast_invalid_selection\">Pilihan tidak valid. Silahkan coba lagi.</string>\n    <string name=\"toast_invalid_level\">Nama tingkat yang tidak valid: %s</string>\n    <string name=\"pref_display_limit_hint\">Silahkan masukkan sebuah nomor yang valid antara %1$d dan %2$d.</string>\n    <string name=\"text_include_device_info\">Termasuk informasi perangkat</string>\n    <string name=\"text_filter_text\">Teks filter</string>\n    <string name=\"text_filter_ellipsis\">Filter…</string>\n    <string name=\"subject_log_report\">Laporan catatan log</string>\n    <string name=\"start_recording_log\">Rekam</string>\n    <string name=\"settings\">Pengaturan</string>\n    <string name=\"send_log_title\">Kirim Log</string>\n    <string name=\"save_log\">Simpan Log</string>\n    <string name=\"save_as\">Simpan Sebagai…</string>\n    <string name=\"record_log\">Rekam Log</string>\n    <string name=\"pref_show_timestamp_title\">Tampilkan Pid &amp; Perekam waktu/Timestamp</string>\n    <string name=\"pref_show_timestamp_summary\">Tampilkan ID proses dan perekam waktu/timestamp ketika diperluas.</string>\n    <string name=\"pref_log_write_period_title\">Periode Tulis</string>\n    <string name=\"pref_log_write_period_summary\">Ketika merekam, tulis ke kartu SD setiap %1$d baris.</string>\n    <string name=\"pref_log_line_period_error\">Silahkan masukkan bilangan bulat antara 1 dan 1000.</string>\n    <string name=\"pref_expanded_by_default_title\">Perluas secara Bawaan</string>\n    <string name=\"pref_expanded_by_default_summary\">Tampilkan teks lengkap log secara bawaan.</string>\n    <string name=\"pref_filter_pattern_title\">Filter Semua Tag</string>\n    <string name=\"pref_filter_pattern_summary\">Filter semua tag yang dipilih dari catatan log.</string>\n    <string name=\"pref_display_limit_title\">Batas Tampilan Log</string>\n    <string name=\"pref_display_limit_summary\">Hanya tamplkan log %1$d terakhir agar menghindari kesalahan kehabisan memori.</string>\n    <string name=\"pref_default_log_level_title\">Tingkat Log Bawaan</string>\n    <string name=\"pref_default_log_level_summary\">Tingkat log pada saat mulai, ketika membuka berkas, dan ketika melakukan perekaman.</string>\n    <string name=\"pref_cat_configuration\">Konfigurasi</string>\n    <string name=\"pref_cat_appearance\">Tampilan</string>\n    <string name=\"pref_cat_advanced\">Lanjutan</string>\n    <string name=\"pref_buffer_title\">Buffer Log()</string>\n    <string name=\"open\">Buka</string>\n    <string name=\"notification_title\">Perekaman catatan log sedang berlangsung</string>\n    <string name=\"notification_ticker\">Perekaman catatan log dimulai</string>\n    <string name=\"notification_subtext\">Sentuh untuk menghentikan rekaman</string>\n    <string name=\"no_saved_logs\">Riwayat log tidak ditemukan.</string>\n    <string name=\"manage_saved_logs\">Kelola Log Tersimpan</string>\n    <string name=\"log_saved\">Log disimpan.</string>\n    <string name=\"log_recording_started\">Perekaman catatan log dimulai.</string>\n    <string name=\"log_level\">Tingkat Log</string>\n    <string name=\"log_cleared\">Log dibersihkan</string>\n    <string name=\"filter_choice_tag\">Tag</string>\n    <string name=\"filter_choice_pid\">PID</string>\n    <string name=\"filter_choice\">Cari berdasarkan</string>\n    <string name=\"enter_good_filename\">Silahkan masukkan nama berkas yang valid.</string>\n    <string name=\"enter_filename\">Masukkan nama berkas</string>\n    <string name=\"dialog_compiling_log\">Mengumpulkan catatan log…</string>\n    <string name=\"delete_saved_log\">Hapus Log Tersimpan</string>\n    <string name=\"copy_to_clipboard\">Salin ke papanklip</string>\n    <string name=\"add_filter_ellipsis\">Tambah Filter…</string>\n    <string name=\"add_filter\">Tambah Filter</string>\n    <string name=\"log_level_fatal\">Fatal</string>\n    <string name=\"log_level_warn\">Mengingatkan</string>\n    <string name=\"log_level_verbose\">Penjelasan</string>\n    <string name=\"log_level_info\">Informasi</string>\n    <string name=\"log_level_error\">Kesalahan</string>\n    <string name=\"log_level_debug\">Debug</string>\n    <string name=\"filename\">Nama berkas</string>\n    <string name=\"restart_log_viewer_to_see_changes\">Mulai ulang jendela penampil log untuk melihat perubahan.</string>\n    <string name=\"pref_log_viewer_msg\">Konfigurasikan bagaimana catatan log ditampilkan.</string>\n    <string name=\"log_viewer\">Penampil Log</string>\n    <string name=\"saf\">SAF</string>\n    <string name=\"pref_rules_msg\">Blokir instan, impor/ekspor/hapus aturan, dll.</string>\n    <string name=\"failed\">Gagal</string>\n    <string name=\"confirm_import_keystore\">Apakah Anda yakin ingin mengganti KeyStore saat ini\\? Tindakan ini tidak dapat dikembalikan.</string>\n    <string name=\"import_keystore\">Impor KeyStore</string>\n    <string name=\"pref_import_export_keystore_msg\">Impor/ekspor Bouncy Castle KeyStore (BKS) secara internal yang dipakai oleh App Manager.</string>\n    <string name=\"pref_import_export_keystore\">Impor/ekspor KeyStore</string>\n    <string name=\"latest_backup\">Cadangan terbaru</string>\n    <string name=\"gz_bz2_compressed\">%1$s dikompresi</string>\n    <string name=\"pgp_aes_rsa_encrypted\">%1$s dienskripsi</string>\n    <string name=\"no_encryption\">Tidak ada enskripsi</string>\n    <string name=\"base_backup\">Cadangan basis</string>\n    <string name=\"app_signing_signatures\">Signatur</string>\n    <string name=\"orientation_right_to_left\">Kanan ke kiri</string>\n    <string name=\"orientation_left_to_right\">Kiri ke kanan</string>\n    <string name=\"orientation_follow_locale\">Ikuti bahasa lokal</string>\n    <plurals name=\"file_deletion_confirmation\">\n        <item quantity=\"other\">Berkas %d akan dihapus</item>\n    </plurals>\n    <string name=\"hidden\">Tersembunyi</string>\n    <string name=\"suspended\">Ditangguhkan</string>\n    <string name=\"pref_display_changes_msg\">Tampilkan perubahan dalam versi, pelacak, komponen, perizinan, tanda tangan (signature), SDK, dll. di sebuah bentuk versi yang terkontrol.</string>\n    <string name=\"no_changes\">Tidak ada perubahan</string>\n    <string name=\"pref_display_changes\">Tampilkan perubahan</string>\n    <string name=\"netpolicy_disable_network_access\">Nonaktifkan akses jaringan</string>\n    <string name=\"netpolicy_reject_wifi_data\">Tolak data Wi-Fi</string>\n    <string name=\"netpolicy_reject_vpn_data\">Tolak data VPN</string>\n    <string name=\"netpolicy_reject_cellular_data\">Tolak data seluler</string>\n    <string name=\"netpolicy_allow_background_data\">Izinkan data di latar belakang saat Penghemat Data aktif</string>\n    <string name=\"netpolicy_reject_background_data\">Tolak data di latar belakang</string>\n    <string name=\"wireless_debugging\">Debug nirkabel</string>\n    <string name=\"port_number_invalid\">Nomor port tidak valid.</string>\n    <string name=\"port_number_empty\">Nomor port kosong.</string>\n    <string name=\"adb_connect_port_number_description\">Nomor port terdapat dibawah bagian <b>Alamat IP &amp; port</b> tepat dibawah bagian <b>Nama perangkat</b>.</string>\n    <string name=\"port_number\">Port</string>\n    <string name=\"adb_connect\">Hbungkan</string>\n    <string name=\"unknown_net_policy\">Netpolicy yang tidak dikenal (%1$s - %2$X)</string>\n    <string name=\"failed_to_prevent_background_run\">Tidak dapat mencegah %1$s untuk berjalan di latar belakang</string>\n    <string name=\"community_links\"></string>\n    <string name=\"community\">Komunitas</string>\n    <plurals name=\"alert_failed_to_import_backups\">\n        <item quantity=\"other\">Tidak dapat mengimpor %1$d cadangan</item>\n    </plurals>\n    <string name=\"import_from_tb\">Impor dari Titanium Backup</string>\n    <string name=\"import_from_oab\">Impor dari OAndBackup</string>\n    <string name=\"pref_import_backups_msg\">Impor cadangan dari OAndBAckup,Swift Backup (3.0–3.2) atau Titanium Backup.</string>\n    <string name=\"pref_import_backups\">Impor cadangan</string>\n    <string name=\"minimum_version\">Versi minimum: %d</string>\n    <string name=\"help_permissions_tab\">Perizinan ini ditetapkan oleh aplikasi ini dan tidak dapat dicabut izin nya.</string>\n    <string name=\"help_uses_permissions_tab\">Klik pada sebuah item untuk <b>mengabulkan</b> atau <b>mencabut</b> izin nya. Hanya perizinan yang <b>berbahaya</b> dan <b>pengembangan</b> yang dapat dikabulkan atau dicabut izin.</string>\n    <string name=\"help_app_ops_tab\">Klik pada sebuah item untuk <b>mengizinkan</b> atau <b>imengabaikan</b> nya. Klik lama pada sebuah item untuk melihat mode yang didukung lainnya.</string>\n    <string name=\"added_to_queue\">Ditambahkan ke antreran</string>\n    <string name=\"pref_selected_users_msg\">Batasi App Manager untuk bekerja dengan pengguna terpilih saja.</string>\n    <string name=\"pref_selected_users\">Pengguna yang dipilih</string>\n    <string name=\"permission_flags\">Bendera izin</string>\n    <string name=\"files\">Dokumen</string>\n    <string name=\"storage\">Penyimpanan</string>\n    <string name=\"notice\">Pemberitahuan</string>\n    <string name=\"error_with_details\">Eror:%s</string>\n    <string name=\"saved_filters\">Filter tersimpan</string>\n    <string name=\"notice_saf\">Tidak seperti volume, direktori yang dipilih akan digunakan untuk menyimpan seluruh file yang berhubungan dengan App Manager, termasuk APK yang disimpan dan backup. Storage Access Framework (SAF) sangat lambat, untuk itu, anda sebaiknya hanya menggunakan opsi ini ketika yang lain tidak dapat digunakan.</string>\n    <plurals name=\"usage_minutes\">\n        <item quantity=\"other\">%1$d menit</item>\n    </plurals>\n    <string name=\"keystore_pass_cannot_be_empty\">Kata sandi KeyStore tidak boleh kosong.</string>\n    <string name=\"invalid_password\">Kata sandi tidak valid, coba lagi.</string>\n    <string name=\"trim_caches_in_all_apps_description\">Menghapus file cache dari semua aplikasi, termasuk sistem android</string>\n    <string name=\"search_type_suffix\">Akhiran</string>\n    <string name=\"search_type_regular_expressions\">ekspresi reguler</string>\n    <string name=\"vt_permalink\">Tautan permanen ke VirusTotal</string>\n    <string name=\"cpu_time\">Waktu CPU</string>\n    <string name=\"priority\">Prioritas</string>\n    <string name=\"state\">Status Proses</string>\n    <string name=\"swap\">Menukar</string>\n    <string name=\"swap_chart_info\">● %1$s Digunakan ● %2$s bebas</string>\n    <string name=\"failed_to_use_the_current_mode_of_operation\">Tidak dapat menggunakan mode operasi saat ini. Kembali ke mode tanpa root untuk sesi ini.</string>\n    <string name=\"failed_to_enable_magisk_deny_list\">Tak bisa mengaktifkan Magisk DenyList</string>\n    <plurals name=\"usage_seconds\">\n        <item quantity=\"other\">%1$d detik</item>\n    </plurals>\n    <string name=\"backup_volume_dialog_description\">Volume dengan <tt>/tree</tt> adalah folder yang dipilih menggunakan Storage Access Framework (SAF). Kecuali folder ini, direktori default untuk App Manager adalah subfolder bernama <tt>AppManager</tt>.</string>\n    <string name=\"user_root\">Gunakan root</string>\n    <string name=\"pid\">ID Proses</string>\n    <string name=\"keystore_password_info\">Berikut ini adalah kata sandi App Manager KeyStore. Harap simpan di tempat yang aman jika Anda akan mencadangkan/memulihkan App Manager KeyStore. <b> Pesan ini tidak akan ditampilkan lagi. </b></string>\n    <string name=\"running_services_logcat_hint\">Klik item untuk membuka penampil log dengan ID proses yang sesuai sebagai filter default.</string>\n    <string name=\"vt_uploading\">VirusTotal: Mengunggah…</string>\n    <string name=\"adb_pair\">Pasangan</string>\n    <string name=\"vt_success\">TotalVirus: %1$d/%2$d</string>\n    <string name=\"next\">Berikutnya</string>\n    <string name=\"pref_always_on_background\">Instal di latar belakang</string>\n    <string name=\"pref_block_trackers_msg\">Blokir komponen pelacak setelah menginstal aplikasi menggunakan Manajer Aplikasi.</string>\n    <string name=\"pref_thread_count\">Eksekusi paralel</string>\n    <plurals name=\"pref_thread_count_msg\">\n        <item quantity=\"other\">Jalankan paling banyak operasi %1$d secara paralel</item>\n    </plurals>\n    <string name=\"explore\">Menjelajahi</string>\n    <string name=\"accessibility_service_description\">Layanan aksesibilitas generik untuk melakukan operasi tertentu seperti membersihkan cache dalam mode tanpa root.</string>\n    <string name=\"system_partition\">Android root</string>\n    <string name=\"pref_intent_firewall_description\">Blokir komponen hanya menggunakan Intent Firewall. Tidak disarankan karena beberapa aplikasi sistem dapat melewati firewall.</string>\n    <string name=\"vt_queued\">VirusTotal: Antrian</string>\n    <string name=\"uses_play_app_signing\">Putar Penandatanganan Aplikasi</string>\n    <string name=\"scan_in_vt\">Pindai di VirusTotal</string>\n    <string name=\"parent_process_id\">ID Proses Induk</string>\n    <string name=\"pref_disable_description\">Nonaktifkan komponen saja. Tidak disarankan untuk pengguna root karena aplikasi dapat melewati ini. Dalam mode ADB, aplikasi hanya uji dapat dinonaktifkan dengan metode ini.</string>\n    <string name=\"search_type_prefix\">Awalan</string>\n    <string name=\"toggle_internet\">Gunakan Internet</string>\n    <string name=\"vt_checking\">VirusTotal: Memeriksa…</string>\n    <string name=\"vt_scan_date\">Tanggal pemindaian: %1$s</string>\n    <string name=\"vt_slowness_warning\">Tergantung pada kecepatan internet dan beban pada server, ini mungkin memakan waktu cukup lama.</string>\n    <string name=\"process_id\">ID Proses</string>\n    <string name=\"cpu_percent\">%% CPU</string>\n    <string name=\"threads\">Jumlah Thread</string>\n    <string name=\"vt_disclaimer\">VirusTotal dan logonya adalah merek dagang dari Chronicle LLC. Baik App Manager—klien API—maupun penulisnya tidak bertanggung jawab atas data apa pun yang mungkin Anda kirim ke VirusTotal.</string>\n    <string name=\"pref_vt_apikey_description\">Kunci API memungkinkan App Manager untuk mengunggah file APK ke VirusTotal serta mengambil laporan. Daftar di https://virustotal.com untuk mendapatkan kunci API secara gratis.</string>\n    <string name=\"pref_vt_apikey_summary\">Aktifkan pemindaian file APK melalui VirusTotal.</string>\n    <string name=\"virtual_memory\">Memori Virtual</string>\n    <string name=\"uses_play_app_signing_description\">Aplikasi ini berisi penanda tertentu yang menunjukkan bahwa <i>mungkin</i> menggunakan <a href=\"https://support.google.com/googleplay/android-developer/answer/9842756\">Play App Signing</a>. Dengan skema ini, kunci penandatanganan disimpan di server Google, dan Google bertanggung jawab untuk menandatangani aplikasi. Perhatikan bahwa informasi penandatanganan yang cocok adalah satu-satunya cara untuk memverifikasi bahwa aplikasi belum dimodifikasi oleh orang lain selain pengembang (dan dalam hal ini, Google juga).</string>\n    <string name=\"warning_working_on_root_mode\">Peringatan: Bekerja pada root alih-alih mode ADB.</string>\n    <string name=\"failed_to_disable_magisk_deny_list\">Tidak dapat menonaktifkan Magisk DenyList</string>\n    <string name=\"commandline_args\">Argumen baris perintah</string>\n    <string name=\"hidden_api_enf_policy_dark_grey_and_black\">Terapkan (daftar abu-abu gelap dan hitam)</string>\n    <string name=\"memory_chart_info\">● %1$s Aplikasi ● %2$s Di-cache ● Buffer %3$s ● %4$s bebas</string>\n    <string name=\"mode_of_op_with_inferred_mode_of_op\">%1$s (Mode yang disimpulkan: %2$s)</string>\n    <string name=\"failed_to_change_app_op_mode\">Tak bisa mengubah mode app op.</string>\n    <string name=\"primary_abi\">ABI utama</string>\n    <string name=\"hidden_api_enforcement_policy\">Kebijakan penegakan API tersembunyi</string>\n    <string name=\"so_type_shared_library\">Pustaka bersama</string>\n    <string name=\"endianness_little_endian\">Little endian</string>\n    <string name=\"so_type_executable\">Dapat dieksekusi</string>\n    <string name=\"file_modified_are_you_sure\">File tersebut telah dimodifikasi. Buang semua perubahan Anda dan keluar\\?</string>\n    <string name=\"save_and_exit\">Simpan dan keluar</string>\n    <string name=\"paired_successfully\">dipasangkan.</string>\n    <string name=\"failed_to_uninstall_app\">Pencabutan instalasi gagal</string>\n    <string name=\"second_degree_tracker_note\">²awalan mengindikasikan bahwa pelacak ada di dalam <a href=\"https://etip.exodus-privacy.eu.org/\">ETIP stand-by list</a> i.e apakah mereka adalah benar pelacak sedang diinvestigasi.</string>\n    <string name=\"background\">Latar belakang</string>\n    <string name=\"staging_apk_files\">Pementasan…</string>\n    <string name=\"intent_firewall_and_disable\">IFW + nonaktifkan</string>\n    <string name=\"intent_firewall\">IFW</string>\n    <string name=\"pref_default_blocking_method\">Metode pemblokiran default</string>\n    <string name=\"pref_default_blocking_method_description\">Metode untuk digunakan secara default di tempat-tempat di mana tidak ada opsi untuk memilih metode pemblokiran.</string>\n    <string name=\"pref_intent_firewall_and_disable_description\">Blokir komponen menggunakan Intent Firewall serta nonaktifkan. Metode yang direkomendasikan untuk pengguna root.</string>\n    <string name=\"identifier\">pengenal</string>\n    <string name=\"set_package_name_first\">Tetapkan nama paket terlebih dahulu!</string>\n    <string name=\"paste\">Tempel</string>\n    <string name=\"trim_caches_in_all_apps\">Pangkas cache di semua aplikasi</string>\n    <string name=\"installer_app_installed\">Aplikasi terpasang</string>\n    <string name=\"pref_always_on_background_msg\">Selalu instal aplikasi di latar belakang dan tampilkan notifikasi jika sudah selesai.</string>\n    <string name=\"type_uri_array\">Array URI</string>\n    <string name=\"type_uri_array_list\">Daftar URI</string>\n    <string name=\"pref_thread_count_hint\">Nilainya harus antara 0 hingga %1$d di mana 0 berarti <i>jumlah operasi maksimum pada waktu tertentu</i>.</string>\n    <string name=\"import_from_sb\">Impor dari Swift Backup 3.0 – 3.2</string>\n    <string name=\"pref_import_backups_hint\">Pilih direktori yang berisi file cadangan (Swift Backup/Titanium Backup) atau direktori (OAndBackup)</string>\n    <string name=\"java\">Java</string>\n    <string name=\"smali\">Smali</string>\n    <string name=\"exit_confirmation\">Konfirmasi keluar</string>\n    <string name=\"extract\">Ekstrak</string>\n    <string name=\"replace\">Mengganti</string>\n    <string name=\"rename\">Ubah nama</string>\n    <string name=\"authenticating\">Otentikasi…</string>\n    <string name=\"search_type_contains\">Mengandung</string>\n    <string name=\"vt_failed\">VirusTotal: Gagal</string>\n    <string name=\"pref_vt_apikey\">Kunci API VirusTotal</string>\n    <string name=\"magisk_denylist\">Daftar Penolakan Magisk</string>\n    <string name=\"zygote_preload_name\">Nama preload zigot</string>\n    <string name=\"hidden_api_enf_default_policy\">Default (berdasarkan jenis aplikasi)</string>\n    <string name=\"hidden_api_enf_policy_none\">Tidak ada (akses penuh ke API tersembunyi)</string>\n    <string name=\"hidden_api_enf_policy_warn\">Peringatan(akses penuh ke API tersembunyi tetapi peringatkan masalah)</string>\n    <string name=\"hidden_api_enf_policy_black\">Terapkan (hanya daftar hitam)</string>\n    <string name=\"binary_32_bit\">32 Bit</string>\n    <string name=\"binary_64_bit\">64 Bit</string>\n    <string name=\"endianness_big_endian\">big endian</string>\n    <string name=\"auth_manager_title\">Manajer otorisasi</string>\n    <string name=\"regenerate_auth_key_warning\">and yakin\\? semua aplikasi pihak ketiga harus terkonfigurasi dengan authorization key.</string>\n    <string name=\"regenerate_auth_key\">menyusun ulang authorization key</string>\n    <string name=\"auth_manager_description\">Untuk menjalankan Intent melalui aplikasi eksternal, harus membentuk extra field bernama <tt>auth</tt> terlebih dahulu, dan harus mencantumkan key berikut ini:</string>\n    <string name=\"sort_by_installation_date\">tanggal pemasangan</string>\n    <string name=\"item_select\">Pilih</string>\n    <string name=\"log_stop_recording\">berhentilah merekam</string>\n    <string name=\"shortcut_icon\">ikon pintasan</string>\n    <string name=\"external\">eksternal</string>\n    <string name=\"internal\">Internal</string>\n    <string name=\"tracker\">pelacak</string>\n    <string name=\"screen_time\">waktu tayang</string>\n    <string name=\"open_in_new_window\">jendela baru</string>\n    <string name=\"vt_confirm_upload_and_scan\">Benar, unggah dan pindai</string>\n    <string name=\"unfreeze\">Cairkan</string>\n    <string name=\"backup_no_backups_present\">tidak ada cadangan.</string>\n    <string name=\"restore_dots\">Memulihkan…</string>\n    <string name=\"frozen\">Dibekukan</string>\n    <string name=\"freeze\">Diam</string>\n    <string name=\"backup_apps_cannot_be_restored\">Aplikasi berikut tidak dapat dipulihkan karena tidak memiliki cadangan dasar:</string>\n    <string name=\"backup_apps_cannot_be_backed_up\">Aplikasi berikut tidak diinstal dan tidak dapat dicadangkan:</string>\n    <string name=\"restart_device\">Memulai ulang perangkat</string>\n    <string name=\"netpolicy_cannot_be_modified_for_core_apps\">Kebijakan Net tidak dapat diubah untuk aplikasi inti Android.</string>\n    <string name=\"import_backups_warning_delete_backups_after_import\">Hapus cadangan setelah mengimpornya ke Manajer Aplikasi\\? Setiap cadangan dihapus satu per satu setelah berhasil diimpor. Pilih <b>Tidak</b> jika tidak yakin.</string>\n    <string name=\"change_backup_volume\">ubah volume</string>\n    <string name=\"pref_saved_apk_name_format\">Format Nama APK disimpan</string>\n    <string name=\"open_developer_options_page\">Buka halaman opsi pengembang di pengaturan Android</string>\n    <string name=\"pref_pure_black_theme\">tema Pure black</string>\n    <string name=\"pref_pure_black_theme_msg\">Gunakan latar belakang yang benar-benar hitam saat mode malam diaktifkan.</string>\n    <string name=\"pref_saved_apk_name_format_msg\">Format akan digunakan untuk menamai file APK saat Anda menyimpannya.</string>\n    <string name=\"input_ssaid_instruction\">SSAID adalah %1$d byte angka heksadesimal yaitu string dengan panjang %2$d yang berisi 0 hingga 9 dan a hingga f.</string>\n    <string name=\"apk_checksums\">APK Checksum</string>\n    <string name=\"backup_volume_unavailable_warning\">Volume cadangan yang dipilih saat ini tidak tersedia. Jika terletak di penyimpanan eksternal, silakan masukkan, atau ubah volume cadangan.</string>\n    <string name=\"pref_vt_prompt_before_uploading\">Tampilkan pengingat sebelum mengunggah file.</string>\n    <string name=\"vt_confirm_uploading_file\">File tidak ditemukan di database VirusTotal. Apakah Anda ingin mengunggahnya\\?</string>\n    <string name=\"type_string_set\">atur string</string>\n    <string name=\"usage_times_opened\">Waktu dibuka</string>\n    <string name=\"usage_last_used\">terakhir digunakan</string>\n    <string name=\"usage_mobile_data\">data seluler</string>\n    <string name=\"usage_wifi_data\">data Wi-Fi</string>\n    <string name=\"app_explorer\">Penjelajah Aplikasi</string>\n    <string name=\"unsupported_split_apk\">Tidak didukung</string>\n    <string name=\"view_changelog\">Cari tahu apa yang baru dalam rilis ini</string>\n    <string name=\"changelog_type_new\">Baru</string>\n    <string name=\"pref_reload_apps\">Muat ulang aplikasi</string>\n    <string name=\"pref_reload_apps_msg\">Muat ulang daftar aplikasi yang disimpan di database Manajer Aplikasi jika terjadi perilaku tak terduga.</string>\n    <string name=\"troubleshooting\">Penyelesaian masalah</string>\n    <string name=\"failed_to_freeze\">Tidak dapat membekukan <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g>.</string>\n    <string name=\"failed_to_unfreeze\">Tidak dapat mencairkan <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g>.</string>\n    <string name=\"freeze_unfreeze\">Bekukan/cairkan</string>\n    <string name=\"suspend_app\">Menangguhkan</string>\n    <string name=\"hide_app\">Sembunyikan</string>\n    <string name=\"hide_app_description\">Metode ini hanya disarankan untuk penggunaan sehari-hari. Sebuah aplikasi tersembunyi muncul seolah-olah itu dihapus. Tetapi aplikasi dapat muncul kembali jika diinstal ulang atau diperbarui.</string>\n    <string name=\"pref_appearance_description\">Tema, orientasi, fitur, dll.</string>\n    <string name=\"pref_privacy\">Privasi</string>\n    <string name=\"pref_privacy_description\">Kunci layar, otorisasi, dll.</string>\n    <string name=\"user_manual\">Panduan pengguna</string>\n    <string name=\"get_help\">Dapatkan bantuan</string>\n    <string name=\"pref_advanced_pref\">Pengguna, format nama APK, eksekusi paralel, dll.</string>\n    <string name=\"pref_version_changelog\">Versi/Changelog</string>\n    <string name=\"changelog_type_fix\">Memperbaiki</string>\n    <string name=\"sort_by_total_size\">Ukuran keseluruhan</string>\n    <string name=\"am_command\"><tt>am</tt> perintah</string>\n    <string name=\"changelog_type_improve\">Memperbaiki</string>\n    <string name=\"open_as_archive\">Arsip</string>\n    <string name=\"open_as_folder\">Folder</string>\n    <string name=\"block_unblock_components_dots\">Blokir/Buka Blokir Komponen…</string>\n    <string name=\"unblock_components_dots\">Buka blokir komponen…</string>\n    <string name=\"warning_working_on_system_mode\">Peringatan: Bekerja pada sistem alih-alih mode ADB.</string>\n    <plurals name=\"alert_failed_to_freeze\">\n        <item quantity=\"other\">Gagal membekukan aplikasi %1$d</item>\n    </plurals>\n    <string name=\"optimize_option_clear_profile_data\">Hapus data profil sebelumnya</string>\n    <string name=\"open_as_image\">Gambar</string>\n    <string name=\"confirm_file_deletion\">Iya, hapus</string>\n    <string name=\"on_unfreeze_open_application\">Buka aplikasi setelah pencairan</string>\n    <string name=\"block_unblock_components_description\">Blokir atau buka blokir seluruh komponen yang diidentifikasi berdasarkan tanda tangan yang diberikan</string>\n    <string name=\"source_stamp_verified_and_identified_to_be_from_source\">SourceStamp telah diverifikasi dan diidentifikasi berasal dari <xliff:g id=\"source\" example=\"Google Play\">%1$s</xliff:g>.</string>\n</resources>"
  },
  {
    "path": "app/src/main/res/values-it-rIT/disclaimer.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- SPDX-License-Identifier: GPL-3.0-or-later --><resources>\n    <string name=\"disclaimer_header\">Dichiarazione di non responsabilità</string>\n    <string name=\"disclaimer_footer\">© 2020–2024 Muntashir Al-Islam</string>\n    <string name=\"disclaimer_agree_forever\">Non mostrare più</string>\n    <string name=\"disclaimer_agree\">Accetto</string>\n    <string name=\"disclaimer_exit\">Esci</string>\n    <string name=\"disclaimer_body\">App Manager offre funzioni di root che potrebbero danneggiare il dispositivo se utilizzato in modo non corretto. App Manager non è responsabile per eventuali danni causati dall\\'utilizzo di questa applicazione. Se non si è pienamente consapevoli di come funziona il root, allora si dovrebbe evitare di utilizzare le opzioni di root fino a quando non si è pienamente informati dei possibili rischi.\n\\n\n\\nQualsiasi link che fornisco ad altre applicazioni e siti web è a beneficio degli utenti. Non sono responsabile dei contenuti che potreste trovare andando su link esterni.\n\\n\n\\nUtilizzando App Manager, l\\'utente si assume la piena responsabilità del proprio utilizzo e accetta che non sarà preso in considerazione alcun reclamo per un danneggiamento del dispositivo a causa di un uso improprio del programma.\n\\n\n\\nUtilizzando questa applicazione, l\\'utente si assume ogni responsabilità per il suo utilizzo e accetta che io non sono responsabile per qualsiasi azione da parte sua che abbia un effetto negativo sul suo dispositivo.</string>\n</resources>"
  },
  {
    "path": "app/src/main/res/values-it-rIT/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- SPDX-License-Identifier: GPL-3.0-or-later --><resources xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:tools=\"http://schemas.android.com/tools\">\n    <string name=\"_lang_tag\" translatable=\"false\">it</string>\n    <string name=\"uninstall\">Disinstalla</string>\n    <string name=\"require_no_permission\">Nessun permesso richiesto</string>\n    <string name=\"activities\">Attività</string>\n    <string name=\"launch\">Avvia</string>\n    <string name=\"refresh\">Aggiorna</string>\n    <string name=\"no_activities\">Nessuna attività</string>\n    <string name=\"receivers\">Ricevitori</string>\n    <string name=\"no_receivers\">Nessun ricevitore</string>\n    <string name=\"providers\">Fornitori</string>\n    <string name=\"no_providers\">Nessun fornitore</string>\n    <string name=\"service\">Servizi</string>\n    <string name=\"no_service\">Nessun servizio</string>\n    <string name=\"orientation\">Orientamento</string>\n    <string name=\"group\">Gruppo</string>\n    <string name=\"sort_by_sha\">Firma</string>\n    <string name=\"signatures\">Firme</string>\n    <string name=\"app_signing_no_signatures\">Nessuna firma valida</string>\n    <string name=\"configurations\">Configurazioni</string>\n    <string name=\"no_configurations\">Nessuna configurazione</string>\n    <!-- &#8230; = ... -->\n    <string name=\"sort_by_package_name\">Nome pacchetto</string>\n    <string name=\"cache_size\">Cache</string>\n    <string name=\"obb_size\">Obb</string>\n    <string name=\"system_app\">Applicazione di sistema</string>\n    <string name=\"user_app\">Applicazione utente</string>\n    <string name=\"sdk_min\">Min</string>\n    <string name=\"sdk_max\">Obiettivo</string>\n    <string name=\"more_info\">Ulteriori informazioni</string>\n    <string name=\"date_installed\">Data installazione</string>\n    <string name=\"date_updated\">Data aggiornamento</string>\n    <string name=\"user_id\">ID utente</string>\n    <string name=\"license\">Licenza</string>\n    <string name=\"usage_today\">Oggi</string>\n    <string name=\"usage_7_days\">Ultimi 7 giorni</string>\n    <string name=\"search\">Cerca</string>\n    <string name=\"process_name\">Nome processo</string>\n    <string name=\"requested_large_heap\">Heap grande</string>\n    <string name=\"databases\">Database</string>\n    <string name=\"save\">Salva</string>\n    <string name=\"disabled_app\">Disabilitato</string>\n    <string name=\"disable\">Disabilita</string>\n    <string name=\"enable\">Abilita</string>\n    <string name=\"force_stop\">Arresto forzato</string>\n    <string name=\"str_logo\">Logo</string>\n    <string name=\"pref_import\">Importa</string>\n    <string name=\"pref_export\">Esporta</string>\n    <string name=\"import_failed\">Importazione non riuscita!</string>\n    <string name=\"export_failed\">Esportazione non riuscita!</string>\n    <string name=\"keyboard_type\">Tipo tastiera</string>\n    <string name=\"navigation\">Navigazione</string>\n    <string name=\"touchscreen\">Touch screen</string>\n    <string name=\"pref_app_theme\">Tema app</string>\n    <string name=\"battery_mode\">Modalità batteria</string>\n    <string name=\"day\">Giorno</string>\n    <string name=\"night\">Notte</string>\n    <string name=\"select_theme\">Tema</string>\n    <string name=\"apply\">Applica</string>\n    <string name=\"version\">Versione</string>\n    <string name=\"block_trackers\">Blocca tracker</string>\n    <string name=\"never_ask\">Non chiedere mai</string>\n    <string name=\"install\">Installa</string>\n    <string name=\"sort_by_last_update\">Ultimo aggiornamento</string>\n    <string name=\"rules_not_applied\">Regole non applicate</string>\n    <string name=\"failed_to_disable_op\">Impossibile disattivare l\\'operazione app richiesta</string>\n    <string name=\"failed_to_enable_op\">Impossibile attivare l\\'operazione app richiesta</string>\n    <string name=\"no_app_ops\">Nessuna operazione app</string>\n    <string name=\"app_ops\">Operazioni app</string>\n    <string name=\"total_size\">Totale</string>\n    <string name=\"failed_to_stop\">Impossibile arrestare <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g>.</string>\n    <string name=\"stopped\">Fermato</string>\n    <string name=\"uninstall_system_app_message\">Questa è un app di sistema. Sei sicuro di volerla disinstallare\\?</string>\n    <string name=\"uninstalled_successfully\"><xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g> è stato disinstallato.</string>\n    <string name=\"failed_to_uninstall\">Impossibile disinstallare <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g>.</string>\n    <string name=\"uninstall_app_message\">Vuoi disinstallare questa app\\?</string>\n    <string name=\"view_in_settings\">Visualizza in Impostazioni</string>\n    <string name=\"no_content\">Nessun contenuto</string>\n    <string name=\"key_name_cannot_be_null\">Il nome chiave non può essere vuoto</string>\n    <string name=\"error_evaluating_input\">Impossibile valutare input</string>\n    <string name=\"type_int\">Intero</string>\n    <string name=\"type_float\">Numero decimale</string>\n    <string name=\"type_boolean\">Vero o falso</string>\n    <string name=\"done\">Fatto</string>\n    <string name=\"add_item\">Aggiungi elemento</string>\n    <string name=\"select_type\">Seleziona tipo</string>\n    <string name=\"boolean_value\">Valore booleano</string>\n    <string name=\"decimal_value\">Valore decimale</string>\n    <string name=\"integer_value\">Valore intero</string>\n    <string name=\"string_value\">Valore stringa</string>\n    <string name=\"saving_failed\">Salvataggio fallito, riprova.</string>\n    <string name=\"saved_successfully\">Salvato</string>\n    <string name=\"deletion_failed\">Eliminazione non riuscita</string>\n    <string name=\"deleted_successfully\">Eliminato</string>\n    <string name=\"delete\">Elimina</string>\n    <string name=\"discard\">Scarta</string>\n    <string name=\"shared_prefs\">Preferenze condivise</string>\n    <string name=\"test_only\">Solo test</string>\n    <string name=\"debuggable\">Debuggabile</string>\n    <string name=\"updated_app\">Aggiornato</string>\n    <string name=\"no_code\">Nessun codice</string>\n    <string name=\"dev_protected_data_dir\">Directory dati protetta dal dispositivo</string>\n    <string name=\"menu_apply_rules\">Applica regole</string>\n    <string name=\"menu_remove_rules\">Rimuovi regole</string>\n    <string name=\"failed_to_extract_apk_file\">Impossibile estrarre il file APK</string>\n    <string name=\"share_apk\">Condividi APK</string>\n    <string name=\"grant_usage_acess_message\">Utilizzato per visualizzare le informazioni sull\\'utilizzo dell\\'app.</string>\n    <string name=\"grant_usage_access\">Concedi l\\'accesso all\\'utilizzo</string>\n    <string name=\"go\">Vai</string>\n    <string name=\"go_back\">Torna indietro</string>\n    <string name=\"usage_less_than_a_minute\">Meno di un minuto</string>\n    <plurals name=\"usage_hours\">\n        <item quantity=\"one\">%1$d ora</item>\n        <item quantity=\"many\">%1$d ore</item>\n        <item quantity=\"other\">%1$d ore</item>\n    </plurals>\n    <plurals name=\"usage_days\">\n        <item quantity=\"one\">%1$d giorno</item>\n        <item quantity=\"many\">%1$d giorni</item>\n        <item quantity=\"other\">%1$d giorni</item>\n    </plurals>\n    <plurals name=\"usage_months\">\n        <item quantity=\"one\">%1$d mese</item>\n        <item quantity=\"many\">%1$d mesi</item>\n        <item quantity=\"other\">%1$d mesi</item>\n    </plurals>\n    <string name=\"usage_weekly\">Settimanale</string>\n    <string name=\"app_usage\">Utilizzo app</string>\n    <string name=\"no_tracker_class\">Nessuna classe tracker</string>\n    <string name=\"all_classes\">Tutte le classi</string>\n    <string name=\"tracker_classes\">Classi tracker</string>\n    <string name=\"tracker_details\">Dettagli tracker</string>\n    <string name=\"found_trackers\">Trova tracker:</string>\n    <string name=\"no_shared_libs\">Nessuna libreria condivisa</string>\n    <string name=\"third_party\">Librerie e icone di terze parti</string>\n    <string name=\"class_name\">Nome classe</string>\n    <string name=\"package_name\">Nome pacchetto</string>\n    <string name=\"error_verbose_pin_shortcut\">Il launcher corrente non supporta PinShortcut. Impossibile creare una scorciatoia.</string>\n    <string name=\"shared_user_id\">ID utente condiviso</string>\n    <string name=\"sort_by_shared_user_id\">ID utente condiviso</string>\n    <string name=\"grant_uri_permission\">Concedi autorizzazioni URI</string>\n    <string name=\"path_permissions\">Percorso autorizzazioni</string>\n    <string name=\"task_affinity\">Affinità attività</string>\n    <string name=\"data_dir\">Directory dati</string>\n    <string name=\"source_dir\">Directory sorgente</string>\n    <string name=\"paths_and_directories\">Percorsi e directory</string>\n    <string name=\"app_info\">Informazioni app</string>\n    <string name=\"version_name_with_code\">Versione <xliff:g id=\"version_name\" example=\"2.5.17\">%1$s</xliff:g><xliff:g id=\"version_code\" example=\"365\">%2$d</xliff:g></string>\n    <string name=\"sort\">Ordina</string>\n    <string name=\"user\">Utente</string>\n    <string name=\"system\">Sistema</string>\n    <string name=\"app_not_installed\">App non installata</string>\n    <string name=\"media_size\">Media</string>\n    <string name=\"data_size\">Dati</string>\n    <string name=\"data_usage_msg\">Utilizzo dati</string>\n    <string name=\"data_transmitted\">Dati inviati</string>\n    <string name=\"data_received\">Dati ricevuti</string>\n    <string name=\"sort_by_app_label\">Etichetta app</string>\n    <string name=\"loading\">Caricamento…</string>\n    <string name=\"error\">Errore</string>\n    <string name=\"shared_libs\">Librerie condivise</string>\n    <string name=\"declared_permission\">Autorizzazioni</string>\n    <string name=\"patterns_allowed\">Modelli ammessi</string>\n    <string name=\"write\">Scrivi</string>\n    <string name=\"read\">Leggi</string>\n    <string name=\"launch_mode\">Modalità di avvio</string>\n    <string name=\"permissions\">Permessi utente</string>\n    <string name=\"clear_data_from_uninstalled_apps\">Cancella dati dalle app disinstallate</string>\n    <string name=\"deny_app_ops_description\">Imposta una modalità per le operazioni dell\\'app identificate dai valori costanti, ad esempio <tt>63</tt> o <tt>RUN_IN_BACKGROUND</tt></string>\n    <string name=\"block_components_dots\">Blocca componenti…</string>\n    <string name=\"block_unblock_trackers_description\">Blocca o sblocca i componenti pubblicitari e di monitoraggio in tutte le app installate</string>\n    <string name=\"clear_cache\">Svuota Cache</string>\n    <string name=\"pref_import_existing_msg\">Aggiungi componenti disabilitati da altre app ad App Manager. Fai attenzione quando usi questo strumento perché possono esserci molti falsi positivi. Scegli solo le app di cui sei certo.</string>\n    <string name=\"pref_import_existing\">Importa regole esistenti</string>\n    <string name=\"source_code\">Codice sorgente</string>\n    <string name=\"update\">Aggiorna</string>\n    <plurals name=\"no_of_trackers\">\n        <item quantity=\"one\">%1$d tracker</item>\n        <item quantity=\"many\">%1$d tracker</item>\n        <item quantity=\"other\">%1$d tracker</item>\n    </plurals>\n    <string name=\"manifest_viewer\">Visualizzatore manifesto</string>\n    <string name=\"external_apk_no_app_op\">L\\'APK esterno non prevede operazioni sull\\'app</string>\n    <string name=\"launch_app\">Avvio</string>\n    <string name=\"failed_to_deny_dangerous_app_ops\">Impossibile revocare tutte le operazioni pericolose dell\\'app</string>\n    <string name=\"failed_to_deny_dangerous_perms\">Impossibile revocare tutte le autorizzazioni pericolose</string>\n    <string name=\"failed_to_reset_app_ops\">Impossibile ripristinare operazioni app</string>\n    <string name=\"failed_to_revoke_permission\">Impossibile revocare autorizzazione</string>\n    <string name=\"failed_to_grant_permission\">Impossibile concedere autorizzazione</string>\n    <plurals name=\"alert_failed_to_disable_trackers\">\n        <item quantity=\"one\">Impossibile disabilitare i tracker da %1$d app</item>\n        <item quantity=\"many\">Impossibile disabilitare i tracker da %1$d app</item>\n        <item quantity=\"other\">Impossibile disabilitare i tracker da %1$d app</item>\n    </plurals>\n    <string name=\"sort_by_permission_names\">Nome autorizzazione</string>\n    <string name=\"deny_dangerous_permissions\">Nega autorizzazioni pericolose</string>\n    <string name=\"unknown_op\">Operazione sconosciuta</string>\n    <string name=\"sort_by_app_ops_names\">Nome operazioni app</string>\n    <string name=\"deny_dangerous_app_ops\">Nega operazioni pericolose app</string>\n    <string name=\"reset_to_default\">Riporta alle condizioni originali</string>\n    <string name=\"sort_by_component_name\">Nome componenti</string>\n    <string name=\"sort_by_wifi_data\">Dati Wi-Fi</string>\n    <string name=\"pref_about_msg\">Versione di App Manager, licenza, crediti, ecc.</string>\n    <string name=\"pref_import_blocker_msg\">Importa regole di blocco da Blocker, ogni file contiene regole per un singolo pacchetto.</string>\n    <string name=\"pref_import_watt_msg\">Importa regole di blocco da Watt, ogni file contiene regole per un singolo pacchetto denominato come <tt>nomepacchetto.xml</tt> ecc.</string>\n    <string name=\"pref_import_msg\">Importa regole di blocco precedentemente esportate da App Manager.</string>\n    <string name=\"pref_export_msg\">Esporta regole di blocco configurate in App Manager in una memoria esterna.</string>\n    <string name=\"export_options\">Opzioni esportazione</string>\n    <string name=\"import_options\">Opzioni importazione</string>\n    <string name=\"duration\">Durata</string>\n    <string name=\"running\">In esecuzione</string>\n    <string name=\"mode\">Modalità</string>\n    <string name=\"permission_name\">Nome autorizzazione</string>\n    <plurals name=\"alert_failed_to_force_stop\">\n        <item quantity=\"one\">Impossibile forzare arresto di%1$d app</item>\n        <item quantity=\"many\">Impossibile forzare arresto di%1$d app</item>\n        <item quantity=\"other\">Impossibile forzare arresto di%1$d app</item>\n    </plurals>\n    <string name=\"the_operation_was_successful\">Fatto</string>\n    <plurals name=\"alert_failed_to_disable_background\">\n        <item quantity=\"one\">Impossibile impedire l\\'esecuzione in background di %1$d app</item>\n        <item quantity=\"many\">Impossibile impedire l\\'esecuzione in background di %1$d app</item>\n        <item quantity=\"other\">Impossibile impedire l\\'esecuzione in background di %1$d app</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_uninstall\">\n        <item quantity=\"one\">Impossibile disinstallare %1$d app</item>\n        <item quantity=\"many\">Impossibile disinstallare %1$d app</item>\n        <item quantity=\"other\">Impossibile disinstallare %1$d app</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_clear_data\">\n        <item quantity=\"one\">Impossibile cancellare i dati da %1$d app</item>\n        <item quantity=\"many\">Impossibile cancellare i dati da %1$d app</item>\n        <item quantity=\"other\">Impossibile cancellare i dati da %1$d app</item>\n    </plurals>\n    <string name=\"export_blocking_rules\">Esporta regole di blocco</string>\n    <string name=\"disable_background\">Impedisci operazioni in background</string>\n    <string name=\"backup_restore\">Backup e ripristino</string>\n    <string name=\"clear_data\">Elimina dati</string>\n    <string name=\"user_and_uid\">Utente: <xliff:g id=\"user_name\" example=\"root\">%1$s</xliff:g> (<xliff:g id=\"user_id\" example=\"0\">%2$d</xliff:g>)</string>\n    <string name=\"memory_virtual_memory\">Memoria: %1$s, Memoria virtuale: %2$s</string>\n    <string name=\"pid_and_ppid\">ID processo: %1$d, ID processo padre: %2$d</string>\n    <string name=\"disable_background_run\">Impedisci operazioni in background</string>\n    <string name=\"kill_process\">Forza arresto</string>\n    <string name=\"running_apps\">App attive</string>\n    <string name=\"apk_updater\">Aggiornamento APK</string>\n    <plurals name=\"failed_to_import_files\">\n        <item quantity=\"one\">Impossibile importare %1$d file.</item>\n        <item quantity=\"many\">Impossibile importare %1$d file.</item>\n        <item quantity=\"other\">Impossibile importare %1$d file.</item>\n    </plurals>\n    <string name=\"the_export_was_successful\">Esportato</string>\n    <string name=\"the_import_was_successful\">Importato</string>\n    <string name=\"pref_import_blocker\">Importa da Blocker</string>\n    <string name=\"pref_import_watt\">Importa da Watt</string>\n    <string name=\"pref_import_export_blocking_rules_msg\">Importa o esporta regole, importa regole esterne da Watt o Blocker.</string>\n    <string name=\"pref_import_export_blocking_rules\">Importa o esporta regole di blocco</string>\n    <string name=\"sort_by_mobile_data\">Dati mobili</string>\n    <string name=\"sort_by_times_opened\">Numero di volte aperto</string>\n    <string name=\"sort_by_screen_time\">Tempo sullo schermo</string>\n    <string name=\"sort_by_last_used\">Ultimo utilizzo</string>\n    <plurals name=\"no_of_times_opened\">\n        <item quantity=\"one\">%1$d volta</item>\n        <item quantity=\"many\">%1$d volte</item>\n        <item quantity=\"other\">%1$d volte</item>\n    </plurals>\n    <string name=\"external_multiple_data_dir\">Directory dati esterni <xliff:g id=\"dir_no\" example=\"1\">%1$d</xliff:g></string>\n    <string name=\"external_data_dir\">Directory dati esterni</string>\n    <string name=\"exodus_link\">Link εxodus</string>\n    <string name=\"usage_yesterday\">Ieri</string>\n    <string name=\"app_settings\">Impostazioni</string>\n    <string name=\"usage_access\">Accesso all\\'utilizzo</string>\n    <string name=\"pref_global_blocking_enabled\">Blocco istantaneo componenti</string>\n    <string name=\"pref_global_blocking_enabled_msg\">Ti consente di bloccare qualsiasi componente di qualsiasi app senza attivare esplicitamente il blocco per l\\'app.</string>\n    <string name=\"app_size\">App</string>\n    <string name=\"no_usage_in_this_time_range\">Nessun utilizzo in questo intervallo di tempo</string>\n    <string name=\"type_string\">Caratteri</string>\n    <string name=\"type_long\">Intero lungo</string>\n    <string name=\"long_integer_value\">Valore intero lungo</string>\n    <string name=\"native_library_dir\">Directory della libreria JNI nativa</string>\n    <plurals name=\"main_list_date_days\">\n        <item quantity=\"one\"><xliff:g id=\"last_update_date\" example=\"20/10/2020\">%1$s</xliff:g> <xliff:g id=\"day_no\" example=\"5\">%2$d</xliff:g> giorno</item>\n        <item quantity=\"many\"><xliff:g id=\"last_update_date\" example=\"20/10/2020\">%1$s</xliff:g> <xliff:g id=\"day_no\" example=\"5\">%2$d</xliff:g> giorni</item>\n        <item quantity=\"other\"><xliff:g id=\"last_update_date\" example=\"20/10/2020\">%1$s</xliff:g> <xliff:g id=\"day_no\" example=\"5\">%2$d</xliff:g> giorni</item>\n    </plurals>\n    <plurals name=\"other_trackers_and_classes\">\n        <item quantity=\"one\"><xliff:g id=\"tracker_no\" example=\"8\">%1$d</xliff:g> tracker con <xliff:g id=\"class_no\" example=\"50\">%2$d</xliff:g> classi</item>\n        <item quantity=\"many\"><xliff:g id=\"tracker_no\" example=\"8\">%1$d</xliff:g> tracker con <xliff:g id=\"class_no\" example=\"50\">%2$d</xliff:g> classi</item>\n        <item quantity=\"other\"><xliff:g id=\"tracker_no\" example=\"8\">%1$d</xliff:g> tracker con <xliff:g id=\"class_no\" example=\"50\">%2$d</xliff:g> classi</item>\n    </plurals>\n    <plurals name=\"two_trackers_and_classes\">\n        <item quantity=\"one\">2 tracker con <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g> classe</item>\n        <item quantity=\"many\">2 tracker con <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g> classi</item>\n        <item quantity=\"other\">2 tracker con <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g> classi</item>\n    </plurals>\n    <plurals name=\"tracker_and_classes\">\n        <item quantity=\"one\">1 tracker con <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g> classe</item>\n        <item quantity=\"many\">1 tracker con <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g> classi</item>\n        <item quantity=\"other\">1 tracker con <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g> classi</item>\n    </plurals>\n    <string name=\"toggle_class_listing\">Attiva o disattiva elenco classi</string>\n    <string name=\"class_viewer\">Visualizzatore classi</string>\n    <string name=\"credits_message\">Agli autori di\n\\n- Il progetto open source Android\n\\n- <a href=\"https://github.com/zhaobozhen/libraries\">Absinthe\\'s libraries</a>\n\\n- <a href=\"https://github.com/butzist/ActivityLauncher\">Activity Launcher</a>\n\\n- <a href=\"https://bitbucket.org/oF2pks/fdroid-applications-info\">Apps_packages Info</a>\n\\n- <a href=\"https://github.com/zhaobao/AppsMonitor\">AppsMonitor</a>\n\\n- <a href=\"https://github.com/8enet/AppOpsX\">AppOpsX</a>\n\\n- <a href=\"https://github.com/gabrielemariotti/changeloglib\">ChangeLog Library</a>\n\\n- <a href=\"https://bitbucket.org/oF2pks/fdroid-classyshark3xodus\">ClassySharkAndroid</a>\n\\n- <a href=\"https://github.com/billthefarmer/editor\">Editor</a>\n\\n- <a href=\"https://github.com/Raival-e/File-Explorer\">File Explorer</a>\n\\n- <a href=\"https://github.com/nex3z/FlowLayout\">FlowLayout</a>\n\\n- <a href=\"https://github.com/k3b/intent-intercept\">Intent Intercept</a>\n\\n- <a href=\"https://github.com/YarikSOffice/lingver\">Lingver</a>\n\\n- <a href=\"https://github.com/topjohnwu/Magisk\">Magisk</a>\n\\n- <a href=\"https://github.com/zhanghai/MaterialFiles\">Material Files</a>\n\\n- <a href=\"https://github.com/pluscubed/matlog\">MatLog</a>\n\\n- <a href=\"https://github.com/matrix-org/matrix-android-sdk\">Matrix Android SDK</a>\n\\n- <a href=\"https://github.com/jensstein/oandbackup\">OAndBackup</a>\n\\n- <a href=\"https://github.com/open-keychain/open-keychain\">Open Keychain</a>\n\\n- <a href=\"https://github.com/Aefyr/SAI\">SAI</a>\n\\n- <a href=\"https://github.com/RikkaApps/Shizuku\">Shizuku</a>\n\\n- <a href=\"https://github.com/eclipse/tm4e\">tm4e</a>\n\\n- <a href=\"https://github.com/tuyafeng/Watt\">Watt</a></string>\n    <string name=\"credits\">Crediti</string>\n    <string name=\"sdk_flags\">Flag</string>\n    <string name=\"sort_by_domain\">Prima le app utente</string>\n    <string name=\"manifest\">Manifesto</string>\n    <string name=\"flags\">Flag</string>\n    <string name=\"sort_by_target_sdk\">SDK di destinazione</string>\n    <string name=\"icon_picker\">Selettore icone</string>\n    <string name=\"shortcut_name\">Nome scorciatoia</string>\n    <string name=\"create_shortcut\">Crea scorciatoia</string>\n    <string name=\"starting_activity\">Attività iniziale: <xliff:g id=\"activity_name\" example=\".main.MainActivity\">%1$s</xliff:g></string>\n    <string name=\"empty_package_name\">Nome pacchetto vuoto</string>\n    <string name=\"main_activity\">Attività principale</string>\n    <string name=\"installer_app\">App di installazione</string>\n    <string name=\"about\">Informazioni su</string>\n    <string name=\"input_features\">Input funzionalità</string>\n    <string name=\"no_feature\">Nessuna funzionalità</string>\n    <string name=\"uses_feature\">Utilizza funzionalità</string>\n    <string name=\"soft_input\">Modalità ingresso soft</string>\n    <string name=\"authority\">Autorità</string>\n    <string name=\"storage_and_cache\">Archiviazione e cache</string>\n    <string name=\"error_creating_shortcut\">Errore nel creare scorciatoia</string>\n    <string name=\"word_wrap\">Attiva o disattiva ritorno a capo automatico</string>\n    <string name=\"app_signing_signatures\">Firme</string>\n    <string name=\"filename\">Nome file</string>\n    <string name=\"choose\">Scegli</string>\n    <string name=\"installer_app_message\">Seleziona <b>Scegli</b> per scegliere tra le app installate o seleziona <b>Personalizzata</b> per specificare un nome di pacchetto personalizzato.</string>\n    <string name=\"specify_custom_name\">Personalizzato</string>\n    <string name=\"verified_using_unreliable_hash\">Verificato utilizzando hash inaffidabile</string>\n    <string name=\"installed_apps\">App installate</string>\n    <string name=\"restart_to_reflect_changes\">È necessario riavviare immediatamente il dispositivo per utilizzare le nuove modifiche.</string>\n    <string name=\"failed_to_change_ssaid\">Impossibile modificare SSAID</string>\n    <string name=\"copied_to_clipboard\">Copiato negli appunti.</string>\n    <string name=\"ssaid_info\">SSAID (<tt>Settings.Secure.ANDROID_ID</tt>) è un identificatore di dispositivo assegnato a ciascuna app (da Android 8 \\\"Oreo\\\" in poi). È ampiamente utilizzato dalle app per tenere traccia degli utenti.</string>\n    <string name=\"ssaid\">SSAID</string>\n    <string name=\"os_version\">Versione sistema operativo</string>\n    <string name=\"support_architectures\">Architetture supportate</string>\n    <string name=\"security\">Sicurezza</string>\n    <string name=\"battery\">Batteria</string>\n    <string name=\"cpu\">CPU</string>\n    <string name=\"users\">Utenti</string>\n    <string name=\"languages\">Lingue</string>\n    <string name=\"battery_capacity\">Capacità</string>\n    <string name=\"memory\">Memoria</string>\n    <string name=\"gles_version\">Versione di OpenGL ES</string>\n    <string name=\"no_of_cores\">Core</string>\n    <string name=\"about_device\">Informazioni sul dispositivo</string>\n    <string name=\"pref_about_device_msg\">Informazioni di base sul dispositivo, tra cui sistema Android, CPU, GPU, RAM, batteria, ecc.</string>\n    <string name=\"brand_name\">Marchio</string>\n    <string name=\"model\">Modello</string>\n    <string name=\"board_name\">Scheda</string>\n    <string name=\"manufacturer\">Produttore</string>\n    <string name=\"kernel\">Kernel</string>\n    <string name=\"share\">Condividi</string>\n    <string name=\"app_signing_signature_mismatch_for_system_apps\">Impossibile installare l\\'app perché un\\'app di sistema con una firma diversa ha questo nome di pacchetto.</string>\n    <string name=\"do_you_want_to_uninstall_and_install\">Vuoi disinstallare e installare nuovamente l\\'app\\?</string>\n    <string name=\"usage_access_not_supported\">Impossibile richiedere l\\'accesso all\\'utilizzo, poiché la pagina delle impostazioni corrispondente non esiste.</string>\n    <string name=\"serial_no\">Numero di serie</string>\n    <string name=\"uninstall_updates\">Disinstalla aggiornamenti</string>\n    <string name=\"no_apps\">Nessuna app</string>\n    <string name=\"cancel\">Annulla</string>\n    <string name=\"ok\">OK</string>\n    <string name=\"input_backup_name_description\">Il nome del backup non deve iniziare con una cifra né contenere spazi. Lascialo vuoto se desideri utilizzare la data e l\\'ora corrente.</string>\n    <string name=\"input_backup_name\">Nome backup</string>\n    <string name=\"keyboard_qwerty\">QWERTY</string>\n    <string name=\"orientation_user\">Utente</string>\n    <string name=\"orientation_reverse_landscape\">Paesaggio (capovolto)</string>\n    <string name=\"orientation_reverse_portrait\">Ritratto (capovolto)</string>\n    <string name=\"orientation_portrait\">Verticale</string>\n    <string name=\"orientation_landscape\">Orizzontale</string>\n    <string name=\"auto\">Automatica</string>\n    <string name=\"choose_language\">Cambia lingua</string>\n    <string name=\"pref_app_language\">Lingua</string>\n    <string name=\"backup_all_users\">Tutti gli utenti</string>\n    <string name=\"failed_to_extract_obb_files\">Impossibile estrarre i file OBB</string>\n    <string name=\"obb_files_extracted_successfully\">File OBB estratti</string>\n    <string name=\"backup_apk_files\">File APK</string>\n    <string name=\"installer_error_security\">Impossibile accedere ai file APK</string>\n    <string name=\"install_in_progress\">Installazione…</string>\n    <string name=\"unblock_trackers\">Sblocca tracker</string>\n    <string name=\"reinstall\">Reinstalla</string>\n    <string name=\"install_app_message\">Vuoi installare questa app\\?</string>\n    <string name=\"try_again\">Riprova</string>\n    <string name=\"batch_ops\">Operazioni batch</string>\n    <string name=\"installer_error_lidl_rom\">La tua ROM non è compatibile con Rootless Installer.</string>\n    <string name=\"installer_error_generic\">Installazione fallita</string>\n    <string name=\"installer_error_storage\">Spazio di archiviazione insufficiente per installare l\\'app</string>\n    <string name=\"installer_error_bad_apks\">Selezionati file APK non validi</string>\n    <string name=\"installer_error_incompatible\">L\\'app non è compatibile con questo dispositivo</string>\n    <string name=\"installer_error_blocked_device\">dispositivo</string>\n    <string name=\"website\">Sito web</string>\n    <string name=\"run_in_termux\">Esegui in Termux</string>\n    <string name=\"open_in_termux\">Apri con Termux</string>\n    <string name=\"export_icon\">Estrai icona</string>\n    <string name=\"no_matching_package_found\">Impossibile trovare un\\'app del genere</string>\n    <string name=\"block_unblock_trackers\">Blocca o sblocca tracker</string>\n    <string name=\"clear_data_message\">Sei sicuro di voler cancellare i dati da questa app\\?</string>\n    <string name=\"skip_signature_checks\">Salta controlli firme</string>\n    <string name=\"yes\">Sì</string>\n    <string name=\"no\">No</string>\n    <string name=\"apply_to_system_apps_question\">Applico anche alle app di sistema\\? Seleziona \\\"No\\\" se non sei sicuro.</string>\n    <plurals name=\"missing_signatures\">\n        <item quantity=\"one\">%1$d firma mancante</item>\n        <item quantity=\"many\">%1$d firme mancanti</item>\n        <item quantity=\"other\">%1$d firme mancanti</item>\n    </plurals>\n    <plurals name=\"libraries\">\n        <item quantity=\"one\">%1$d libreria</item>\n        <item quantity=\"many\">%1$d librerie</item>\n        <item quantity=\"other\">%1$d librerie</item>\n    </plurals>\n    <plurals name=\"classes\">\n        <item quantity=\"one\">%1$d classe</item>\n        <item quantity=\"many\">%1$d classi</item>\n        <item quantity=\"other\">%1$d classi</item>\n    </plurals>\n    <plurals name=\"backup_exists_are_you_sure\">\n        <item quantity=\"one\">Il backup esiste già. Sei sicuro\\?</item>\n        <item quantity=\"many\">Più di un\\'app ha già un backup. Sei sicuro\\?</item>\n        <item quantity=\"other\">Più di un\\'app ha già un backup. Sei sicuro\\?</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_delete_backup\">\n        <item quantity=\"one\">Impossibile eliminare %1$d backup</item>\n        <item quantity=\"many\">Impossibile eliminare %1$d backup</item>\n        <item quantity=\"other\">Impossibile eliminare %1$d backup</item>\n    </plurals>\n    <string name=\"delete_backup\">Elimina backup</string>\n    <string name=\"restore\">Ripristino</string>\n    <string name=\"whats_new\">Cosa c\\'è di nuovo</string>\n    <string name=\"installed_version\">Versione installata</string>\n    <string name=\"select_all\">Seleziona tutto</string>\n    <string name=\"filter_system_apps\">App sistema</string>\n    <string name=\"filter_user_apps\">App utente</string>\n    <string name=\"filter\">Filtra</string>\n    <string name=\"termux\">Termux</string>\n    <string name=\"failed_to_parse_some_numbers\">Impossibile analizzare alcuni numeri</string>\n    <string name=\"only_works_in_root_or_adb_mode\">Funziona solo in modalità root o ADB</string>\n    <string name=\"filtered_packages\">Pacchetti filtrati</string>\n    <string name=\"no_tracker_found\">Nessun tracker trovato</string>\n    <string name=\"clear_app_cache_description\">Svuota cache tutte le app</string>\n    <string name=\"source_code_links\"><a href=\"https://github.com/MuntashirAkon/AppManager\">GitHub</a> • <a href=\"https://gitlab.com/muntashir/AppManager\">GitLab</a> • <a href=\"https://0xacab.org/muntashir/AppManager\">Riseup</a> • <a href=\"https://codeberg.org/muntashir/AppManager\">Codeberg</a></string>\n    <plurals name=\"no_of_components\">\n        <item quantity=\"one\">%1$d componente</item>\n        <item quantity=\"many\">%1$d componenti</item>\n        <item quantity=\"other\">%1$d componenti</item>\n    </plurals>\n    <string name=\"changelog\">Registro delle modifiche</string>\n    <string name=\"follow_system\">Segui sistema</string>\n    <string name=\"ago\">fa</string>\n    <string name=\"user_with_id\">Utente: <xliff:g id=\"user_id\" example=\"0\">%1$d</xliff:g></string>\n    <string name=\"keep_data_and_app_signing_signatures\">Conserva dati e firme</string>\n    <string name=\"key_name\">Nome chiave</string>\n    <plurals name=\"usage_seconds\">\n        <item quantity=\"one\">%1$d secondo</item>\n        <item quantity=\"many\">%1$d secondi</item>\n        <item quantity=\"other\">%1$d secondi</item>\n    </plurals>\n    <string name=\"failed_to_uninstall_app\">Disinstallazione non riuscita</string>\n    <plurals name=\"usage_minutes\">\n        <item quantity=\"one\">%1$d minuto</item>\n        <item quantity=\"many\">%1$d minuti</item>\n        <item quantity=\"other\">%1$d minuti</item>\n    </plurals>\n    <string name=\"sort_by_blocked_components\">Prima i bloccati</string>\n    <string name=\"no_changes\">Nessun cambiamento</string>\n    <string name=\"netpolicy_disable_network_access\">Disabilita accesso alla rete</string>\n    <string name=\"port_number\">Porta</string>\n    <string name=\"failed_to_prevent_background_run\">Impossibile impedire l\\'esecuzione di %1$s in background</string>\n    <string name=\"minimum_version\">Versione minima: %d</string>\n    <string name=\"pref_selected_users_msg\">Restringi il funzionamento di App Manager solo agli utenti selezionati.</string>\n    <string name=\"notice\">Avviso</string>\n    <string name=\"notice_saf\">A differenza dei volumi, la directory selezionata verrà utilizzata per archiviare tutti i file relativi ad App Manager, inclusi APK e backup salvati. Storage Access Framework (SAF) è molto lento, pertanto dovresti usare questa opzione solo quando non è possibile usarne altre.</string>\n    <string name=\"adb_pair\">Associa</string>\n    <string name=\"identifier\">Identificatore</string>\n    <string name=\"set_package_name_first\">Imposta prima il nome del pacchetto!</string>\n    <string name=\"exit_confirmation\">Conferma uscita</string>\n    <string name=\"vt_slowness_warning\">A seconda della velocità di Internet e del carico sul server, l\\'operazione potrebbe richiedere del tempo.</string>\n    <string name=\"vt_disclaimer\">VirusTotal e i suoi loghi sono un marchio di Chronicle LLC. Né App Manager, il client API, né i suoi autori sono responsabili per i dati che potresti inviare a VirusTotal.</string>\n    <string name=\"confirm_installation\">Conferma installazione</string>\n    <string name=\"sort_by_backup\">Prima con backup</string>\n    <string name=\"checksums\">Checksum</string>\n    <string name=\"not_yet_valid\">Non ancora valido</string>\n    <string name=\"sort_by_tracker_components\">Prima i tracker</string>\n    <string name=\"expiry_date\">Data di scadenza</string>\n    <string name=\"port_number_invalid\">Numero porta non valido.</string>\n    <string name=\"select_apk\">Seleziona APK</string>\n    <string name=\"duplicate\">Duplica</string>\n    <string name=\"sort_by_dangerous_permissions\">Pericolosi per primi</string>\n    <string name=\"sort_by_denied_permissions\">Negati per primi</string>\n    <string name=\"changes_not_saved\">Modifiche non salvate</string>\n    <string name=\"new_profile\">Nuovo profilo</string>\n    <string name=\"rsa\">RSA</string>\n    <string name=\"sort_by_memory_usage\">Memoria utilizzata</string>\n    <string name=\"other\">Altro</string>\n    <string name=\"rsa_modulus\">Modulo</string>\n    <string name=\"format\">Formato</string>\n    <string name=\"rsa_exponent\">Esponente</string>\n    <string name=\"critical_exts\">Estensioni critiche</string>\n    <string name=\"non_critical_exts\">Estensioni non critiche</string>\n    <string name=\"conversion_failed\">Conversione fallita.</string>\n    <string name=\"select_user\">Seleziona utente</string>\n    <string name=\"adb_over_tcp\">ADB su TCP</string>\n    <string name=\"send_selected\">Invia selezionato</string>\n    <string name=\"on\">Acceso</string>\n    <string name=\"invalid_password\">Password non valida, riprova.</string>\n    <string name=\"base_backup\">Backup di base</string>\n    <string name=\"subject\">Oggetti</string>\n    <string name=\"issuer\">Emittente</string>\n    <string name=\"issued_date\">Data di emissione</string>\n    <string name=\"validity\">Validità</string>\n    <string name=\"adb_connect\">Connetti</string>\n    <string name=\"app_signing_install_without_data_loss\">Se hai disattivato la verifica della firma, puoi utilizzare l\\'opzione <b>Installa solo</b> per installare l\\'app senza perdere dati.</string>\n    <string name=\"only_install\">Installa soltanto</string>\n    <string name=\"view_missing_signatures\">Tocca per visualizzare o inviare firme non ancora presenti nel database delle librerie di App Manager.</string>\n    <string name=\"am_crashed\">App Manager si è appena arrestato in modo anomalo</string>\n    <string name=\"in_progress\">In corso</string>\n    <string name=\"input_profile_name\">Nome profilo</string>\n    <string name=\"security_providers\">Fornitori di sicurezza</string>\n    <string name=\"trackers_unblocked_successfully\">I tracker sono ora sbloccati</string>\n    <string name=\"no_encryption\">Nessuna crittografia</string>\n    <string name=\"pgp_aes_rsa_encrypted\">%1$s crittografato</string>\n    <string name=\"saved_filters\">Filtri salvati</string>\n    <string name=\"error_with_details\">Errore: %s</string>\n    <string name=\"staging_apk_files\">Preparazione…</string>\n    <string name=\"installer_app_installed\">App installata</string>\n    <string name=\"next\">Prossimo</string>\n    <string name=\"type_uri_array\">Matrice URI</string>\n    <string name=\"java\">Java</string>\n    <string name=\"clear_data_from_uninstalled_apps_description\">Cancella dati dalle app disinstallate con il flag <tt>DONT_DELETE_DATA</tt></string>\n    <string name=\"sort_by_process_id\">ID Processo</string>\n    <string name=\"tap_to_see_details\">Tocca per vedere i dettagli</string>\n    <string name=\"accept_time\">Tempo per accettare</string>\n    <string name=\"reject_time\">Tempo per rifiutare</string>\n    <string name=\"sort_by_denied_app_ops\">Negati per primi</string>\n    <string name=\"one_click_ops\">Operazioni con un clic</string>\n    <string name=\"failed_packages\">Pacchetti falliti</string>\n    <string name=\"no_profiles\">Nessun profilo</string>\n    <string name=\"apply_now\">Applica ora…</string>\n    <string name=\"routine_ops\">Operazioni di routine</string>\n    <string name=\"sort_by_process_name\">Nome processo</string>\n    <string name=\"sort_by_apps_first\">Prima le app</string>\n    <string name=\"pref_compression_method\">Metodo di compressione</string>\n    <string name=\"allow_open_pgp_operation\">Tocca per permettere ad App Manager di usare OpenPGP</string>\n    <string name=\"update_uninstalled_successfully\">Gli aggiornamenti per <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g> sono stati disinstallati.</string>\n    <string name=\"filter_apps_with_backups\">Con backup</string>\n    <string name=\"type\">Tipo</string>\n    <string name=\"valid\">Valido</string>\n    <string name=\"expired\">Scaduto</string>\n    <string name=\"app_signing_signature\">Firma</string>\n    <string name=\"copy\">Copia</string>\n    <string name=\"filter_running_apps\">App in esecuzione</string>\n    <string name=\"tap_to_submit_crash_report\">Tocca per inviare il rapporto sull\\'arresto anomalo.</string>\n    <string name=\"send_crash_report\">Invia rapporto di arresto anomalo</string>\n    <string name=\"input_profile_name_description\">Il nome del profilo non può contenere spazi.</string>\n    <string name=\"failed_to_duplicate_profile\">Impossibile duplicare profilo</string>\n    <string name=\"pref_encryption_msg\">Crittografa backup.</string>\n    <string name=\"none\">Nessuno</string>\n    <string name=\"allow_routine_ops\">Permetti operazioni di routine</string>\n    <string name=\"profile_state\">Stato del profilo</string>\n    <string name=\"allow_routine_ops_msg\">Consenti utilizzo del profilo nelle operazioni di routine</string>\n    <string name=\"profile_force_stop_msg\">Arresto forzata app</string>\n    <string name=\"profile_clear_cache_msg\">Pulisci cache app</string>\n    <string name=\"profile_clear_data_msg\">Pulisci dati app</string>\n    <string name=\"profile_block_trackers_msg\">Blocca tracker nelle app</string>\n    <string name=\"profile_state_msg\">Stato on/off personalizzato per questo profilo</string>\n    <string name=\"off\">Spento</string>\n    <string name=\"options\">Opzioni</string>\n    <string name=\"category\">Categorie</string>\n    <string name=\"share_log\">Condividi</string>\n    <string name=\"view_logs\">Visualizza log</string>\n    <string name=\"failed_to_block_trackers\">Impossibile bloccare i tracker</string>\n    <string name=\"failed_to_unblock_trackers\">Impossibile sbloccare i tracker</string>\n    <string name=\"trackers_blocked_successfully\">I tracker sono ora bloccati</string>\n    <string name=\"gz_bz2_compressed\">%1$s compresso</string>\n    <string name=\"latest_backup\">Ultimo backup</string>\n    <string name=\"pref_import_export_keystore\">Importa/esporta KeyStore</string>\n    <string name=\"import_keystore\">Importa KeyStore</string>\n    <string name=\"failed\">Fallito</string>\n    <string name=\"pref_rules_msg\">Blocco istantaneo, regole di importazione/esportazione/rimozione, ecc.</string>\n    <string name=\"orientation_follow_locale\">Segui localizzazione</string>\n    <string name=\"orientation_left_to_right\">Da sinistra a destra</string>\n    <string name=\"orientation_right_to_left\">Da destra a sinistra</string>\n    <string name=\"hidden\">Nascosto</string>\n    <string name=\"pref_display_changes\">Mostra cambiamenti</string>\n    <string name=\"netpolicy_reject_background_data\">Rifiuta dati in background</string>\n    <string name=\"netpolicy_reject_cellular_data\">Rifiuta dati cellulare</string>\n    <string name=\"netpolicy_reject_vpn_data\">Rifiuta dati VPN</string>\n    <string name=\"netpolicy_reject_wifi_data\">Rifiuta dati Wi-Fi</string>\n    <string name=\"wireless_debugging\">Debug wireless</string>\n    <string name=\"adb_connect_port_number_description\">Il numero della porta si trova nella sezione <b>Indirizzo IP &amp; porta</b> appena sotto la sezione <b>Nome dispositivo</b>.</string>\n    <string name=\"help_app_ops_tab\">Fare clic su un elemento per <b>allow</b> o <b>ignore</b>. Fai clic a lungo su un elemento per vedere altre modalità supportate.</string>\n    <string name=\"pref_selected_users\">Utenti selezionati</string>\n    <string name=\"permission_flags\">Flag autorizzazioni</string>\n    <string name=\"files\">File</string>\n    <string name=\"keystore_pass_cannot_be_empty\">La password KeyStore non può essere vuota.</string>\n    <string name=\"paired_successfully\">Accoppiato.</string>\n    <string name=\"user_root\">Usa root</string>\n    <string name=\"trim_caches_in_all_apps\">Regola cache in tutte le app</string>\n    <string name=\"trim_caches_in_all_apps_description\">Elimina i file della cache da tutte le applicazioni, incluso il sistema Android</string>\n    <string name=\"pref_block_trackers_msg\">Blocca i componenti di rilevamento dopo l\\'installazione di un\\'app tramite App Manager.</string>\n    <string name=\"pref_always_on_background\">Installa in background</string>\n    <string name=\"pref_always_on_background_msg\">Installa sempre le app in background e visualizza una notifica al termine.</string>\n    <string name=\"type_uri_array_list\">Elenco URI</string>\n    <string name=\"pref_thread_count\">Esecuzione parallela</string>\n    <string name=\"pref_thread_count_hint\">Il valore deve essere compreso tra 0 e %1$d dove 0 significa <i>numero massimo di operazioni in un dato momento</i>.</string>\n    <string name=\"pid\">ID processo</string>\n    <string name=\"running_services_logcat_hint\">Fai clic su un elemento per aprire il visualizzatore di log con l\\'ID processo corrispondente come filtro predefinito.</string>\n    <string name=\"import_from_sb\">Importa da Swift Backup 3.0 - 3.2</string>\n    <string name=\"explore\">Esplora</string>\n    <string name=\"pref_default_blocking_method_description\">Metodo da usare per impostazione predefinita in luoghi in cui non è disponibile alcuna opzione per selezionare un metodo di blocco.\n\\n<b>Nota:</b> \\\"IFW\\\" non funziona con i fornitori, viene invece utilizzato \\\"disable\\\".</string>\n    <string name=\"pref_intent_firewall_and_disable_description\">Blocca i componenti utilizzando Intent Firewall e disabilitali. Metodo consigliato per utenti root.</string>\n    <string name=\"pref_intent_firewall_description\">Blocca i componenti utilizzando solo Intent Firewall. Non consigliato in quanto alcune app di sistema possono aggirare i firewall.</string>\n    <string name=\"pref_disable_description\">Disabilita solo i componenti. Non consigliato per utenti root poiché le app possono ignorarlo. Nelle modalità ADB, le app di solo test possono essere disabilitate con questo metodo.</string>\n    <string name=\"authenticating\">Autenticazione…</string>\n    <string name=\"search_type_contains\">Contiene</string>\n    <string name=\"save_and_exit\">Salva e chiudi</string>\n    <string name=\"search_type_suffix\">Suffisso</string>\n    <string name=\"toggle_internet\">Usa Internet</string>\n    <string name=\"vt_scan_date\">Data scansione: %1$s</string>\n    <string name=\"vt_permalink\">Link permanente a VirusTotal</string>\n    <string name=\"pref_saved_apk_name_format\">Formato nome APK salvato</string>\n    <string name=\"pref_saved_apk_name_format_msg\">Il formato da utilizzare per denominare i file APK quando li salvi.</string>\n    <string name=\"auth_manager_title\">Gestione autorizzazioni</string>\n    <string name=\"regenerate_auth_key\">Rigenera chiave di autorizzazione</string>\n    <string name=\"regenerate_auth_key_warning\">Sei sicuro\\? Tutte le app di terze parti devono essere riconfigurate con la nuova chiave di autorizzazione.</string>\n    <string name=\"shortcut_icon\">Icona collegamento</string>\n    <string name=\"so_type_executable\">Eseguibile</string>\n    <string name=\"second_degree_tracker_note\">Il prefisso ² indica che i tracker si trovano nell\\'<a href=\"https://etip.exodus-privacy.eu.org/\">elenco di attesa ETIP</a>, ad es. se si tratta di tracker effettivi, saranno ancora oggetto di indagine.</string>\n    <string name=\"interceptor\">Intercettatore</string>\n    <string name=\"file_modified_are_you_sure\">Il file è stato modificato. Annullo tutte le modifiche ed esco\\?</string>\n    <string name=\"auth_manager_description\">Per avviare un Intento da un\\'app esterna, è necessario fornire un campo aggiuntivo chiamato <tt>auth</tt> e deve contenere la seguente chiave:</string>\n    <string name=\"backup_volume_unavailable_warning\">Il volume di backup selezionato non è attualmente disponibile. Se si trova in una memoria esterna, inserirlo o modificare il volume di backup.</string>\n    <string name=\"community\">Comunità</string>\n    <string name=\"rules\">Regole</string>\n    <string name=\"pref_mode_of_operations\">Modalità di funzionamento</string>\n    <string name=\"public_key\">Chiave pubblica</string>\n    <string name=\"clear_app_cache\">Pulisci cache app</string>\n    <string name=\"sys_config\">Configurazione sistema</string>\n    <string name=\"keystore\">KeyStore</string>\n    <string name=\"pref_backup_flags_msg\">L\\'aggiunta di un predefinito per le opzioni di backup rimuove l\\'onere di selezionare le flag ogni volta che si fa il backup o il ripristino.</string>\n    <string name=\"failed_to_uninstall_updates\">Impossibile disinstallare gli aggiornamenti per <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g>.</string>\n    <string name=\"algorithm\">Algoritmo</string>\n    <string name=\"scanner\">Scanner</string>\n    <string name=\"no_libs\">Nessuna libreria</string>\n    <string name=\"lib_details\">Dettagli libreria</string>\n    <string name=\"encryption\">Crittografia</string>\n    <string name=\"ecc\">Crittografia a curva ellittica</string>\n    <string name=\"extras\">Extra</string>\n    <string name=\"running_services\">Servizi in esecuzione</string>\n    <string name=\"save_apk\">Salva APK</string>\n    <string name=\"profile_save_apk_msg\">Salva i file APK in <tt>AppManager/apks</tt></string>\n    <string name=\"pref_import_export_keystore_msg\">Importa/esporta Bouncy Castle KeyStore (BKS) utilizzato internamente da App Manager.</string>\n    <string name=\"suspended\">Sospeso</string>\n    <string name=\"confirm_import_keystore\">Sei sicuro di voler sostituire il KeyStore esistente\\? Questa azione non può essere annullata.</string>\n    <plurals name=\"alert_failed_to_import_backups\">\n        <item quantity=\"one\">Impossibile importare %1$d backup</item>\n        <item quantity=\"many\">Impossibile importare %1$d backup</item>\n        <item quantity=\"other\">Impossibile importare %1$d backup</item>\n    </plurals>\n    <string name=\"help_permissions_tab\">Queste autorizzazioni sono definite da questa app e non possono essere revocate.</string>\n    <string name=\"pref_display_changes_msg\">Visualizza le modifiche a versione, tracker, componenti, autorizzazioni, firme, SDK, ecc. in modo controllato dalla versione.</string>\n    <string name=\"netpolicy_allow_background_data\">Consenti dati in background quando Risparmio dati è attivo</string>\n    <string name=\"port_number_empty\">Numero porta vuoto.</string>\n    <string name=\"unknown_net_policy\">Politica di rete sconosciuta (%1$s - %2$X)</string>\n    <string name=\"help_uses_permissions_tab\">Fare clic su un elemento per <b>concedere</b> o <b>revocarlo</b>. Solo le autorizzazioni <b>pericolose</b> e <b>sviluppo</b> possono essere concesse o revocate.</string>\n    <string name=\"added_to_queue\">Aggiunto alla coda</string>\n    <string name=\"storage\">Archiviazione</string>\n    <string name=\"backup_volume_dialog_description\">I volumi con il prefisso <tt>/tree</tt> sono cartelle selezionate utilizzando Storage Access Framework (SAF). Ad eccezione di queste cartelle, la directory predefinita per App Manager è una sottocartella denominata <tt>AppManager</tt>.</string>\n    <string name=\"keystore_password_info\">La seguente è la password del KeyStore di App Manager. Conservala in un luogo sicuro se hai intenzione di fare il backup o il ripristino del KeyStore di App Manager. <b>Questo messaggio non verrà più visualizzato.</b></string>\n    <string name=\"paste\">Incolla</string>\n    <string name=\"rename\">Rinomina</string>\n    <string name=\"vt_queued\">VirusTotal: in coda</string>\n    <string name=\"replace\">Sostituisci</string>\n    <string name=\"search_type_prefix\">Prefisso</string>\n    <string name=\"system_partition\">Android root</string>\n    <string name=\"pref_import_backups_hint\">Seleziona una directory contenente i file di backup (Swift Backup/Titanium Backup) o le directory (OAndBackup)</string>\n    <string name=\"accessibility_service_description\">Servizio di accessibilità generico per eseguire determinate operazioni come svuotare la cache in modalità no root.</string>\n    <string name=\"vt_checking\">VirusTotal: controllo…</string>\n    <string name=\"extract\">Estrai</string>\n    <string name=\"pref_default_blocking_method\">Metodo di blocco predefinito</string>\n    <string name=\"vt_uploading\">VirusTotal: caricamento in corso…</string>\n    <string name=\"vt_failed\">VirusTotal: fallito</string>\n    <string name=\"vt_success\">VirusTotal: %1$d/%2$d</string>\n    <string name=\"sort_by_installation_date\">Data di installazione</string>\n    <string name=\"change_backup_volume\">Cambia volume</string>\n    <string name=\"external\">Esterno</string>\n    <string name=\"internal\">Interno</string>\n    <string name=\"input_ssaid_instruction\">SSAID è un numero esadecimale di byte %1$d, ovvero una stringa di lunghezza %2$d contenente da 0 a 9 e da a a f.</string>\n    <string name=\"screen_time\">Tempo schermo</string>\n    <plurals name=\"pref_thread_count_msg\">\n        <item quantity=\"one\">Esegui al massimo %1$d operazione in parallelo</item>\n        <item quantity=\"many\">Esegui al massimo %1$d operazioni in parallelo</item>\n        <item quantity=\"other\">Esegui al massimo %1$d operazioni in parallelo</item>\n    </plurals>\n    <string name=\"community_links\"><a href=\"https://matrix.to/#/#appmanager:matrix.org\">Matrix</a> • <a href=\"https://t.me/AppManagerChannel\">Telegram</a> • <a href=\"https://twitter.com/AppManagerNews\">Twitter</a></string>\n    <string name=\"pref_remove_all_rules\">Rimuovi tutte le regole</string>\n    <string name=\"installer_error_session_abandon\">Impossibile abbandonare la sessione di installazione</string>\n    <string name=\"unencrypted\">Non crittografato</string>\n    <string name=\"backup_apps_without_backups\">Esegui il backup delle app senza backup</string>\n    <string name=\"verify_and_redo_backups_msg\">Verifica l\\'integrità dei backup precedenti e ripete i backup per i quali il controllo dell\\'integrità non riesce.</string>\n    <string name=\"backup_apps_with_changes_msg\">Ripeti i backup per le app con le modifiche dall\\'ultimo backup. Include modifiche alle dimensioni, alla versione, all\\'ora dell\\'ultimo avvio.</string>\n    <string name=\"restore_all_msg\">Ripristina il backup di base da tutte le app di cui è stato eseguito il backup.</string>\n    <string name=\"external_storage\">Memoria esterna</string>\n    <string name=\"internal_storage\">Memoria interna</string>\n    <string name=\"sd_card\">Scheda SD</string>\n    <string name=\"type_long_array\">Vettore di interi lunghi</string>\n    <string name=\"type_float_array\">Matrice di numeri decimali</string>\n    <string name=\"failed_to_initialize_key_store\">Impossibile inizializzare il keystore di App Manager.</string>\n    <string name=\"use_default\">Usa predefinita</string>\n    <string name=\"components\">Componenti</string>\n    <string name=\"installer_error_conflict\">Impossibile installare l\\'app perché il nome del pacchetto è in uso</string>\n    <string name=\"state_dead\">Morto</string>\n    <string name=\"close\">Chiudi</string>\n    <string name=\"state_trace_stop\">Ferma traccia</string>\n    <string name=\"state_zombie\">Zombie</string>\n    <string name=\"root\">Root</string>\n    <string name=\"backup_all_apps_msg\">Esegui il backup di tutte le app installate.</string>\n    <string name=\"features\">Funzionalità</string>\n    <string name=\"unblock\">Sblocca</string>\n    <string name=\"vendor\">Venditore</string>\n    <string name=\"backup_all_apps\">Esegui il backup di tutte le app</string>\n    <string name=\"downgrade\">Downgrade</string>\n    <string name=\"orientation_full_sensor\">Sensore completo</string>\n    <string name=\"systemless_app\">App senza sistema</string>\n    <string name=\"sort_by_app_ops_values\">Valore operazioni app</string>\n    <string name=\"input_signatures\">Inserisci firme</string>\n    <string name=\"input_signatures_description\">Inserisci firme con spazi, per esempio <tt>com.facebook org.app2 com.app3</tt> etc.</string>\n    <string name=\"input_app_ops_description\">Immetti nomi delle operazioni dell\\'app e/o le costanti con spazi, ad es. <tt>WAKE_LOCK 63 72 CAMERA</tt> ecc.</string>\n    <string name=\"package_name_is_installed_successfully\"><xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g> installato</string>\n    <string name=\"blocking_rules\">Regole di blocco</string>\n    <string name=\"trackers\">Tracker</string>\n    <string name=\"external_data\">Dati esterni</string>\n    <string name=\"internal_data\">Dati interni</string>\n    <string name=\"data\">Dati</string>\n    <string name=\"backup\">Backup</string>\n    <plurals name=\"alert_failed_to_set_app_ops\">\n        <item quantity=\"one\">Impossibile impostare le operazioni dell\\'app per %1$d app</item>\n        <item quantity=\"many\">Impossibile impostare le operazioni dell\\'app per %1$d app</item>\n        <item quantity=\"other\">Impossibile impostare le operazioni dell\\'app per %1$d app</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_block_components\">\n        <item quantity=\"one\">Impossibile bloccare i componenti da %1$d app</item>\n        <item quantity=\"many\">Impossibile bloccare i componenti da %1$d app</item>\n        <item quantity=\"other\">Impossibile bloccare i componenti da %1$d app</item>\n    </plurals>\n    <plurals name=\"app_signing_signature_schemes_pl\">\n        <item quantity=\"one\">Schema firma</item>\n        <item quantity=\"many\">Schemi firme</item>\n        <item quantity=\"other\">Schemi firme</item>\n    </plurals>\n    <plurals name=\"verified_with_warning\">\n        <item quantity=\"one\">Verificato con %d avviso</item>\n        <item quantity=\"many\">Verificato con %d avvisi</item>\n        <item quantity=\"other\">Verificato con %d avvisi</item>\n    </plurals>\n    <string name=\"apply_to_system_apps\">Applica alle app di sistema</string>\n    <string name=\"clear\">Pulisci</string>\n    <string name=\"block\">Blocca</string>\n    <string name=\"pref_remove_all_rules_msg\">Le autorizzazioni verranno concesse, le operazioni e i componenti dell\\'app torneranno ai valori predefiniti.</string>\n    <string name=\"are_you_sure\">Sei sicuro\\?</string>\n    <string name=\"filter_apps_with_activities\">Con attività</string>\n    <string name=\"toggle_default_app_ops\">Attiva o disattiva operazioni app predefinite</string>\n    <string name=\"installer_error_aborted\">L\\'installazione non è riuscita perché è stata annullata o perché la sessione è stata chiusa in modo imprevisto</string>\n    <string name=\"failed_to_fetch_package_info\">Impossibile recuperare informazioni pacchetto</string>\n    <string name=\"operation_running\">Operazione in corso…</string>\n    <string name=\"full_stop_tap_to_see_details\">. Tocca per vedere i dettagli.</string>\n    <string name=\"package_installer\">Installatore pacchetto</string>\n    <string name=\"installer_error_session_create\">Impossibile creare una sessione di installazione</string>\n    <string name=\"installer_error_session_write\">Impossibile scrivere nella sessione di installazione</string>\n    <string name=\"installer_error_session_commit\">Impossibile eseguire il commit dei file APK</string>\n    <string name=\"backup_obb_media\">OBB e media</string>\n    <string name=\"backup_multiple\">Backup multiplo</string>\n    <string name=\"split_feature_name\">Funzionalità: <xliff:g id=\"feature_name\" example=\"Visualizer\">%1$s</xliff:g></string>\n    <string name=\"unknown_split_for_base_apk\"><xliff:g id=\"split_name\" example=\"some_split\">%1$s</xliff:g> per APK base</string>\n    <string name=\"density_split_for_base_apk\"><xliff:g id=\"split_name\" example=\"xxdpi\">%1$s</xliff:g> (<xliff:g id=\"dpi_no\" example=\"480\">%2$d</xliff:g> DPI) risorse per APK base</string>\n    <string name=\"locale_split_for_base_apk\"><xliff:g id=\"split_name\" example=\"English\">%1$s</xliff:g> localizzazione per APK base</string>\n    <string name=\"launch_mode_multiple\">Multipli</string>\n    <string name=\"launch_mode_single_instance\">Istanza singola</string>\n    <string name=\"orientation_behind\">Dietro</string>\n    <string name=\"orientation_full_user\">Utente completo</string>\n    <string name=\"orientation_sensor_landscape\">Sensore panorama</string>\n    <string name=\"orientation_user_portrait\">Ritratto utente</string>\n    <string name=\"required\">Richiesto</string>\n    <string name=\"_undefined\">Non definito</string>\n    <string name=\"keyboard_12_keys\">12 chiavi</string>\n    <string name=\"navigation_no_nav\">Nessuna navigazione</string>\n    <string name=\"navigation_trackball\">Trackball</string>\n    <string name=\"navigation_wheel\">Ruota</string>\n    <string name=\"touchscreen_no_touch\">Nessun tocco</string>\n    <string name=\"state_sleeping\">Dormendo</string>\n    <string name=\"state_device_io\">I/O dispositivo</string>\n    <string name=\"state_parked\">Parcheggiato</string>\n    <string name=\"state_idle\">Inattivo</string>\n    <string name=\"state_wake_kill\">Uccidi sveglia</string>\n    <string name=\"state_unknown\">Sconosciuto</string>\n    <string name=\"state_high_priority\">Priorità alta</string>\n    <string name=\"state_low_priority\">Priorità bassa</string>\n    <string name=\"state_locked_memory\">Memoria bloccata</string>\n    <string name=\"state_session_leader\">Leader sessione</string>\n    <string name=\"state_foreground\">Primo Piano</string>\n    <string name=\"state_multithreaded\">Multithread</string>\n    <string name=\"process_state_with_extra\">Stato: <xliff:g id=\"process_state\" example=\"Sleeping\">%1$s</xliff:g>(<xliff:g id=\"state_extra\" example=\"High priority\">%2$s</xliff:g>)</string>\n    <string name=\"open_pgp_provider\">Fornitore OpenPGP</string>\n    <string name=\"profiles\">Profili</string>\n    <string name=\"apps\">Applicazioni</string>\n    <string name=\"filter_apps\">Applicazioni</string>\n    <string name=\"dsa_affine_x\">Coordinata x affine</string>\n    <string name=\"dsa_affine_y\">Coordinata y affine</string>\n    <string name=\"un_apkm\">UnApkm</string>\n    <string name=\"aes\">AES</string>\n    <string name=\"input_permissions\">Autorizzazioni input</string>\n    <string name=\"input_permissions_description\">Autorizzazioni di input con spazi, ad es. <tt>com.permission.GET_ACCOUNTS android.permission.ACCESS_MEDIA_LOCATION</tt> ecc. Usa <tt>*</tt> per richiedere tutte le autorizzazioni.</string>\n    <string name=\"simple\">Semplice</string>\n    <string name=\"advanced\">Avanzato</string>\n    <string name=\"no_root\">No root</string>\n    <string name=\"comment\">Commento</string>\n    <string name=\"installer\">Installer</string>\n    <string name=\"pref_sign_apk\">Firma APK</string>\n    <string name=\"pref_sign_apk_msg\">Firma file APK prima di installarli.</string>\n    <string name=\"app_signing_signature_schemes\">Schemi firma</string>\n    <string name=\"apk_signing\">Firma APK</string>\n    <string name=\"pref_apk_signing_msg\">Imposta schemi firma, chiave firma personalizzata, etc.</string>\n    <string name=\"v1_scheme\">Schema v1 (da Android 1.0)</string>\n    <string name=\"v2_scheme\">Schema v2 (da Android 7.0)</string>\n    <string name=\"v3_scheme\">Schema v3 (da Android 9)</string>\n    <string name=\"v4_scheme\">Schema v4 (da Android 11)</string>\n    <string name=\"pref_signature_schemes_msg\">Almeno gli schemi v1 e v2 dovrebbero essere selezionati per una maggiore compatibilità. Lo schema v4 richiede v2 o v3.</string>\n    <string name=\"verified\">Verificato</string>\n    <string name=\"not_verified\">Non verificato</string>\n    <string name=\"source_stamp_verified\">SourceStamp verificato.</string>\n    <string name=\"input_keystore_pass_description\">Inserisci la password KeyStore di App Manager. Se stai leggendo questo per la prima volta, per favore usa un generatore di password per generare una password e salvala in un posto sicuro prima di inserirla qui.</string>\n    <string name=\"input_keystore_alias_pass\">Password per alias <b>%1$s</b></string>\n    <string name=\"no_app_ops_permission\">Nessuna autorizzazione per visualizzare le operazioni dell\\'app</string>\n    <string name=\"this_action_cannot_be_undone\">Questa azione non può essere annullata.</string>\n    <string name=\"pref_backup_android_keystore\">Esegui il backup delle app con Android KeyStore</string>\n    <string name=\"pref_backup_android_keystore_msg\">Non tutte le app funzioneranno dopo il ripristino. Il ripristino di KeyStore non funziona sulla maggior parte dei dispositivi.</string>\n    <string name=\"magisk_hide_enabled\">MagiskHide</string>\n    <string name=\"set_app_op_mode\">Imposta modalità operativa app</string>\n    <string name=\"filter_apps_with_splits\">Con divisioni</string>\n    <string name=\"value\">Valore</string>\n    <string name=\"matching_activities\">Attività corrispondenti</string>\n    <string name=\"action\">Azione</string>\n    <string name=\"mime_type\">Tipo MIME</string>\n    <string name=\"uri\">URI</string>\n    <string name=\"resend_intent\">Invia di nuovo Intent</string>\n    <string name=\"set_custom_app_op\">Imposta operazione app personalizzata</string>\n    <string name=\"backup_apk_files_description\">Esegui il backup dei file APK dalla directory di origine, incluse le divisioni.</string>\n    <string name=\"backup_internal_data_description\">Esegui il backup delle cartelle dati interne.</string>\n    <string name=\"backup_external_data_description\">Esegui il backup di cartelle dati esterne.</string>\n    <string name=\"backup_obb_media_description\">Esegui il backup di OBB e delle cartelle multimediali.</string>\n    <string name=\"backup_cache_description\">Esegui il backup delle cartelle <b>cache</b>, <b>no_cache</b> e <b>no_backup</b>.</string>\n    <string name=\"backup_extras\">Extra</string>\n    <string name=\"backup_skip_signature_checks_description\">Ripristina i backup che non superano la verifica del checksum o hanno firme APK diverse rispetto ai backup precedenti.</string>\n    <string name=\"patch_level\">Livello patch</string>\n    <string name=\"screen\">Schermo</string>\n    <string name=\"density\">Densità</string>\n    <string name=\"size\">Dimensione</string>\n    <string name=\"scaling_factor\">Fattore di scalabilità</string>\n    <string name=\"refresh_rate\">Frequenza aggiornamento</string>\n    <string name=\"failed_to_enable_magisk_hide\">Impossibile abilitare MagiskHide</string>\n    <string name=\"backup_volume\">Volume di backup</string>\n    <string name=\"verify_and_redo_backups\">Verifica e ripeti i backup</string>\n    <string name=\"redo_existing_backups\">Ripeti i backup esistenti</string>\n    <string name=\"redo_existing_backups_msg\">Ripeti il backup per le app installate con backup precedenti.</string>\n    <string name=\"restore_all\">Ripristina tutte le app</string>\n    <string name=\"restore_not_installed\">Ripristina app non installate</string>\n    <string name=\"backup_msg\">Esegui il backup delle app con i dati</string>\n    <string name=\"restore_msg\">Ripristina app con dati</string>\n    <string name=\"screen_lock\">Blocco schermo</string>\n    <string name=\"type_long_array_list\">Elenco di interi lunghi</string>\n    <string name=\"type_string_array\">Matrice di stringhe</string>\n    <string name=\"type_string_array_list\">Elenco di stringhe</string>\n    <string name=\"no_battery_optimization\">Nessuna ottimizzazione batteria</string>\n    <string name=\"battery_optimization\">Ottimizzazione batteria</string>\n    <string name=\"enable_battery_optimization\">Abilito ottimizzazione della batteria\\?</string>\n    <string name=\"initializing\">Inizializzando…</string>\n    <string name=\"add_to_profile\">Aggiungi al profilo</string>\n    <string name=\"list_options\">Elenco opzioni</string>\n    <string name=\"last_actions\">Ultime azioni</string>\n    <string name=\"isolated\">Isolato</string>\n    <string name=\"screen_lock_not_enabled\">Scegli un blocco schermo nelle impostazioni di Android o cancella i dati dell\\'app.</string>\n    <string name=\"filter_apps_without_backups\">Senza backup</string>\n    <string name=\"input_key\">Inserisci chiave (in esadecimale)</string>\n    <string name=\"generate_key\">Genera</string>\n    <string name=\"crypto_key_size\">Dimensione chiave</string>\n    <string name=\"invalid_rsa_key_size\">Dimensione chiave non valida per la crittografia RSA. La dimensione della chiave può essere 1024, 2048 o 4096 bit.</string>\n    <string name=\"failed_to_load_key\">Impossibile caricare la chiave.</string>\n    <string name=\"selinux\">SELinux</string>\n    <string name=\"enforcing\">Enforcing</string>\n    <string name=\"permissive\">Permissive</string>\n    <string name=\"hardware\">Hardware</string>\n    <string name=\"launch_mode_single_task\">Attività singola</string>\n    <string name=\"orientation_locked\">Bloccato</string>\n    <string name=\"orientation_no_sensor\">Nessun sensore</string>\n    <string name=\"orientation_sensor_portrait\">Sensore ritratto</string>\n    <string name=\"orientation_sensor\">Sensore</string>\n    <string name=\"keyboard_no_keys\">Nessuna chiave</string>\n    <string name=\"touchscreen_stylus\">Stilo</string>\n    <string name=\"touchscreen_finger\">Dito</string>\n    <string name=\"app_data_will_be_lost\">I dati esistenti andranno persi.</string>\n    <string name=\"graphics\">Grafica</string>\n    <string name=\"set_mode_for_app_ops_dots\">Imposta modalità per operazioni app…</string>\n    <string name=\"failed_to_save_key\">Impossibile salvare la chiave.</string>\n    <string name=\"restore_latest\">Ripristina gli ultimi backup</string>\n    <string name=\"uninstalled_apps\">App disinstallate</string>\n    <string name=\"filter_apps_with_rules\">Con regole</string>\n    <string name=\"input_app_ops\">Inserisci operazioni applicazione</string>\n    <string name=\"installer_error_blocked\">Installazione bloccata da <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g></string>\n    <plurals name=\"alert_failed_to_backup\">\n        <item quantity=\"one\">Impossibile eseguire il backup di %1$d app</item>\n        <item quantity=\"many\">Impossibile eseguire il backup di %1$d app</item>\n        <item quantity=\"other\">Impossibile eseguire il backup di %1$d app</item>\n    </plurals>\n    <string name=\"backup_options\">Opzioni backup</string>\n    <string name=\"base_apk\">APK base</string>\n    <string name=\"process_state\">Stato: <xliff:g id=\"process_state\" example=\"Sleeping\">%1$s</xliff:g></string>\n    <plurals name=\"failed_to_backup_some_apk_files\">\n        <item quantity=\"one\">Impossibile eseguire il backup di %1$d app</item>\n        <item quantity=\"many\">Impossibile eseguire il backup di %1$d app</item>\n        <item quantity=\"other\">Impossibile eseguire il backup di %1$d app</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_restore\">\n        <item quantity=\"one\">Impossibile ripristinare %1$d app</item>\n        <item quantity=\"many\">Impossibile ripristinare %1$d app</item>\n        <item quantity=\"other\">Impossibile ripristinare %1$d app</item>\n    </plurals>\n    <string name=\"enabled\">Abilitato</string>\n    <string name=\"install_location_prefer_external\">Preferisci esterni</string>\n    <string name=\"backup_multiple_description\">Crea un backup separato denominato <i>named</i> invece del backup di base.</string>\n    <string name=\"backup_extras_description\">Esegui il backup delle autorizzazioni delle app, del risparmio della batteria e delle opzioni di utilizzo dei dati, lo stato di MagiskHide, SSAID, etc. <font fgcolor=\"#ff0000\">A seconda delle autorizzazioni, non tutti gli extra possono essere ripristinati.</font></string>\n    <string name=\"backup_rules_description\">Esegui il backup delle regole configurate in App Manager. <font fgcolor=\"#ff0000\">A seconda delle autorizzazioni, non tutte le regole possono essere riapplicate durante il ripristino.</font></string>\n    <string name=\"unlock_app_manager\">Sblocca App Manager</string>\n    <string name=\"screen_lock_msg\">Blocca App Manager utilizzando il blocco schermo Android</string>\n    <string name=\"type_component_name\">Nome componente</string>\n    <string name=\"type_null\">Nessun valore</string>\n    <string name=\"type_int_array\">Matrice di interi</string>\n    <string name=\"type_int_array_list\">Lista di interi</string>\n    <string name=\"has_net_policy\">Politica di rete</string>\n    <string name=\"net_policy\">Politica di rete</string>\n    <string name=\"organization_unit\">Unità organizzativa (UO)</string>\n    <string name=\"input_key_password\">Password chiave</string>\n    <string name=\"organization_name\">Nome organizzazione (O)</string>\n    <string name=\"common_name\">Nome comune (CN)</string>\n    <string name=\"orientation_user_landscape\">Panorama utente</string>\n    <string name=\"navigation_dial_pad\">Tastiera telefono</string>\n    <string name=\"install_location\">Posizione di installazione</string>\n    <string name=\"splits\">Divisioni</string>\n    <string name=\"input_keystore_pass\">Immetti password KeyStore</string>\n    <string name=\"failed_to_disable_magisk_hide\">Impossibile disabilitare MagiskHide</string>\n    <string name=\"type_uri\">URI</string>\n    <string name=\"reverse\">Inverti</string>\n    <string name=\"enable_disable_features\">Abilita o disabilita funzionalità</string>\n    <string name=\"invalid_aes_key_size\">Dimensione chiave non valida per la crittografia AES. La dimensione della chiave può essere 128 o 256 bit.</string>\n    <plurals name=\"alert_failed_to_unblock_trackers\">\n        <item quantity=\"one\">Impossibile sbloccare i tracker da %1$d app</item>\n        <item quantity=\"many\">Impossibile sbloccare i tracker da %1$d app</item>\n        <item quantity=\"other\">Impossibile sbloccare i tracker da %1$d app</item>\n    </plurals>\n    <string name=\"toggle_kill_for_system_apps\">Attiva o disattiva arresto app di sistema</string>\n    <string name=\"add\">Aggiungi</string>\n    <plurals name=\"no_of_splits\">\n        <item quantity=\"one\">%1$d diviso</item>\n        <item quantity=\"many\">%1$d divisi</item>\n        <item quantity=\"other\">%1$d divisi</item>\n    </plurals>\n    <string name=\"input_app_ops_description_profile\">Immetti nomi delle operazioni dell\\'app e/o le costanti con spazi, ad es. <tt>WAKE_LOCK 63 72 CAMERA</tt> ecc. Usa <tt>*</tt> per richiedere tutte le operazioni app configurate.</string>\n    <string name=\"abi_split_for_feature\"><xliff:g id=\"split_name\" example=\"arm64_v8a\">%1$s</xliff:g> codice per <xliff:g id=\"feature_name\" example=\"Visualizer\">%2$s</xliff:g></string>\n    <string name=\"locale_split_for_feature\"><xliff:g id=\"split_name\" example=\"English\">%1$s</xliff:g> localizzazione per funzionalità <xliff:g id=\"feature_name\" example=\"Visualizer\">%2$s</xliff:g></string>\n    <string name=\"state_waking\">Svegliando</string>\n    <string name=\"density_split_for_feature\"><xliff:g id=\"split_name\" example=\"xxdpi\">%1$s</xliff:g> (<xliff:g id=\"dpi_no\" example=\"480\">%2$d</xliff:g> DPI) risorse per funzionalità <xliff:g id=\"feature_name\" example=\"Visualizer\">%3$s</xliff:g></string>\n    <string name=\"abi_split_for_base_apk\"><xliff:g id=\"split_name\" example=\"arm64_v8a\">%1$s</xliff:g> codice per APK base</string>\n    <string name=\"launch_mode_single_top\">Top singolo</string>\n    <string name=\"orientation_unspecified\">Non specificato</string>\n    <string name=\"install_location_internal_only\">Solo interni</string>\n    <string name=\"restore_not_installed_msg\">Ripristina il backup di base per le app che non sono attualmente installate.</string>\n    <string name=\"encrypted\">Crittografato</string>\n    <string name=\"backup_custom_users\">Utenti personalizzati</string>\n    <string name=\"backup_apps_without_backups_msg\">Esegui il backup delle app senza backup precedenti.</string>\n    <string name=\"user_profile_with_id\">Profilo: %1$s (%2$d)</string>\n    <string name=\"input_keystore_pass_msg\">Tocca qui per inserire la password KeyStore</string>\n    <string name=\"input_keystore_alias_pass_description\">Inserisci la password per l\\'alias <b>%1$s</b>. Puoi lasciare vuoto se la password è la stessa della password KeyStore.</string>\n    <string name=\"input_keystore_alias_pass_msg\">Tocca qui per fornire la password per %1$s</string>\n    <string name=\"send_edited_intent\">Invia intento modificato</string>\n    <string name=\"activity_result\">Risultato attività</string>\n    <string name=\"result_code\">Codice risultato</string>\n    <string name=\"disable_background_run_description\">Imposta modalità <i>Ignora</i> per le seguenti operazioni dell\\'app: <tt>RUN_IN_BACKGROUND</tt> (da Android 7.0) e <tt>RUN_ANY_IN_BACKGROUND</tt> (da Android 9).</string>\n    <string name=\"pref_backup_restore_msg\">Personalizza backup e ripristino.</string>\n    <string name=\"window_size\">Dimensione finestra</string>\n    <string name=\"pref_backup_volume_msg\">Seleziona il volume o il disco in cui verranno archiviati i backup.</string>\n    <string name=\"no_volumes_found\">Impossibile trovare volumi con autorizzazione di scrittura.</string>\n    <string name=\"backup_custom_users_description\">Esegui backup solo per gli utenti specificati</string>\n    <string name=\"bootloader\">Bootloader</string>\n    <string name=\"backup_apps_with_changes\">Esegui il backup delle app con le modifiche</string>\n    <string name=\"restore_latest_msg\">Ripristina le app già installate i cui codici di versione sono superiori al codice di versione installato.</string>\n    <string name=\"drm_free_apkm_msg\">Il file APKM è privo di DRM, non è necessario convertirlo in APKS.</string>\n    <string name=\"back_up\">Salva</string>\n    <string name=\"pref_enable_disable_features_msg\">Abilita o disabilita funzionalità di App Manager.</string>\n    <string name=\"choose_what_to_do\">Scegli cosa fare.</string>\n    <string name=\"type_float_array_list\">Elenco di numeri decimali</string>\n    <string name=\"working_on_adb_mode\">Lavorando sulla modalità ADB</string>\n    <string name=\"key_not_set\">Non impostata.</string>\n    <string name=\"unknown_split_for_feature\"><xliff:g id=\"split_name\" example=\"some_split\">%1$s</xliff:g> per funzionalità <xliff:g id=\"feature_name\" example=\"Visualizer\">%2$s</xliff:g></string>\n    <string name=\"tracker\">Tracker</string>\n    <string name=\"vt_confirm_uploading_file\">Il file non è stato trovato nel database di VirusTotal. Vuoi caricarlo\\?</string>\n    <string name=\"alias_pass\">Password alias</string>\n    <string name=\"pref_log_viewer_msg\">Configura modalità di visualizzazione dei registri.</string>\n    <string name=\"log_level_verbose\">Prolisso</string>\n    <string name=\"log_level_warn\">Avvisi</string>\n    <string name=\"delete_saved_log\">Elimina registri salvati</string>\n    <string name=\"log_cleared\">Log cancellati</string>\n    <string name=\"log_recording_started\">Registrazione log iniziata.</string>\n    <string name=\"log_saved\">Log salvato.</string>\n    <string name=\"no_saved_logs\">Nessun log salvato.</string>\n    <string name=\"notification_subtext\">Toccare per interrompere la registrazione</string>\n    <string name=\"notification_ticker\">Registrazione log avviata</string>\n    <string name=\"pref_filter_pattern_title\">Filtra tag</string>\n    <string name=\"pref_expanded_by_default_summary\">Mostra testo completo del log per impostazione predefinita.</string>\n    <string name=\"pref_log_write_period_summary\" tools:ignore=\"PluralsCandidate\">Durante la registrazione, scrivi sulla scheda SD ogni %1$d righe.</string>\n    <string name=\"expand_all\">Espandi Tutti</string>\n    <string name=\"background\">Sfondo</string>\n    <string name=\"smali\">Smali</string>\n    <string name=\"uses_play_app_signing\">Riproduci firma dell\\'app</string>\n    <string name=\"process_id\">ID processo</string>\n    <string name=\"pem_file\">File PEM</string>\n    <string name=\"import_key\">Importa chiave</string>\n    <string name=\"new_alias_password\">Nuova password alias</string>\n    <string name=\"save_as\">Salva come…</string>\n    <string name=\"send_log_title\">Invia log</string>\n    <string name=\"add_filter\">Aggiungi filtro</string>\n    <string name=\"start_recording_log\">Registra</string>\n    <string name=\"state_name\">Nome Stato (ST)</string>\n    <string name=\"locality_name\">Nome località (città) (L)</string>\n    <string name=\"country_name\" tools:ignore=\"TypographyOther\">Nome paese (C)</string>\n    <string name=\"keystore_file\">File KeyStore</string>\n    <string name=\"keystore_pass\">Password KeyStore</string>\n    <string name=\"java_keystore\">Java KeyStore (JKS)</string>\n    <string name=\"bouncy_castle_keystore\">KeyStore Bouncy Castle (BKS)</string>\n    <string name=\"found_no_alias_in_keystore\">Nessun alias trovato nel KeyStore!</string>\n    <string name=\"choose_an_alias\">Scegli un alias</string>\n    <string name=\"pref_import_backups_msg\">Importa backup da OAndBackup, Swift Backup (3.0–3.2) o Titanium Backup.</string>\n    <string name=\"import_from_oab\">Importa da OAndBackup</string>\n    <string name=\"restart_log_viewer_to_see_changes\">Riavvia la finestra del visualizzatore di log per vedere le modifiche.</string>\n    <string name=\"log_level_debug\">Debug</string>\n    <string name=\"log_level_error\">Errore</string>\n    <string name=\"log_level_info\">Informazioni</string>\n    <string name=\"log_level_fatal\">Fatale</string>\n    <string name=\"add_filter_ellipsis\">Aggiungi filtro…</string>\n    <string name=\"enter_filename\">Inserisci il nome del file</string>\n    <string name=\"copy_to_clipboard\">Copia negli appunti</string>\n    <string name=\"dialog_compiling_log\">Compilazione log…</string>\n    <string name=\"open\">Apri</string>\n    <string name=\"log_level\">Livello log</string>\n    <string name=\"pref_buffer_title\">Buffer(s) log</string>\n    <string name=\"pref_default_log_level_title\">Livello log predefinito</string>\n    <string name=\"pref_display_limit_summary\" tools:ignore=\"PluralsCandidate\">Mostra solo gli ultimi log %1$d per evitare errori di memoria insufficiente.</string>\n    <string name=\"pref_log_line_period_error\">Inserisci un numero intero compreso tra 1 e 1000.</string>\n    <string name=\"pref_log_write_period_title\">Scrivi periodo</string>\n    <string name=\"pref_show_timestamp_summary\">Mostra ID processo e timestamp quando espansa.</string>\n    <string name=\"pref_show_timestamp_title\">Mostra Pid e timestamp</string>\n    <string name=\"record_log\">Registra log</string>\n    <string name=\"widget_start_recording\">Registra\n\\nLog</string>\n    <string name=\"pause_unpause\">Play/Pausa</string>\n    <string name=\"undo\">Annulla</string>\n    <string name=\"file\">File</string>\n    <string name=\"collapse_all\">Comprimi tutto</string>\n    <string name=\"intent_firewall\">IFW</string>\n    <string name=\"pref_vt_apikey\">Chiave API VirusTotal</string>\n    <string name=\"parent_process_id\">ID processo padre</string>\n    <string name=\"virtual_memory\">Memoria virtuale</string>\n    <string name=\"cpu_percent\">%% CPU</string>\n    <string name=\"cpu_time\">Tempo CPU</string>\n    <string name=\"state\">Stato processo</string>\n    <string name=\"priority\">Priorità</string>\n    <string name=\"failed_to_change_app_op_mode\">Impossibile modificare la modalità operativa dell\\'app.</string>\n    <string name=\"commandline_args\">Argomenti da linea di comando</string>\n    <string name=\"memory_chart_info\">● %1$s Applicazioni ● %2$s Nella cache ● %3$s Nel buffer ● %4$s Libero</string>\n    <string name=\"swap_chart_info\">● %1$s Usato ● %2$s Libero</string>\n    <string name=\"swap\">Swap</string>\n    <string name=\"failed_to_use_the_current_mode_of_operation\">Impossibile utilizzare la modalità di funzionamento corrente. Ritorno alla modalità senza root per questa sessione.</string>\n    <string name=\"warning_working_on_root_mode\">Avvertenza: stai lavorando in modalità root anziché in modalità ADB.</string>\n    <string name=\"failed_to_disable_magisk_deny_list\">Impossibile disabilitare Magisk DenyList</string>\n    <string name=\"mode_of_op_with_inferred_mode_of_op\">%1$s (Modalità dedotta: %2$s)</string>\n    <string name=\"hidden_api_enf_policy_black\">Enforce (solo liste nere)</string>\n    <string name=\"open_in_new_window\">Nuova finestra</string>\n    <string name=\"type_string_set\">Set di stringhe</string>\n    <string name=\"pref_vt_prompt_before_uploading\">Visualizza prompt prima di caricare un file.</string>\n    <string name=\"vt_confirm_upload_and_scan\">Sì, carica e scansiona</string>\n    <string name=\"log_stop_recording\">Ferma registrazione</string>\n    <string name=\"apk_checksums\">Checksum APK</string>\n    <string name=\"item_select\">Seleziona</string>\n    <plurals name=\"toast_log_truncated\">\n        <item quantity=\"one\">Log troppo grande, mostra l\\'ultima riga %d.</item>\n        <item quantity=\"many\">Log troppo grande, mostra le ultime %d righe .</item>\n        <item quantity=\"other\">Log troppo grande, mostra le ultime %d righe .</item>\n    </plurals>\n    <plurals name=\"file_deletion_confirmation\">\n        <item quantity=\"one\">%d file verrà eliminato</item>\n        <item quantity=\"many\">%d file verranno eliminati</item>\n        <item quantity=\"other\">%d file verranno eliminati</item>\n    </plurals>\n    <string name=\"expiry_date_cannot_be_empty\">La data di scadenza non può essere vuota.</string>\n    <string name=\"pref_installer_msg\">Configura comportamenti del programma di installazione dell\\'app.</string>\n    <string name=\"failed_to_read_keystore\">Impossibile leggere il KeyStore.</string>\n    <string name=\"signing_key\">Chiave di firma</string>\n    <string name=\"pref_import_backups\">Importa backup</string>\n    <string name=\"log_viewer\">Visualizzatore registro</string>\n    <string name=\"filter_choice\">Cerca per</string>\n    <string name=\"filter_choice_pid\">PID</string>\n    <string name=\"pref_cat_advanced\">Avanzate</string>\n    <string name=\"pref_cat_appearance\">Aspetto</string>\n    <string name=\"pref_cat_configuration\">Configurazione</string>\n    <string name=\"text_filter_text\">Filtra testo</string>\n    <string name=\"save_log\">Salva log</string>\n    <string name=\"settings\">Impostazioni</string>\n    <string name=\"subject_log_report\">Rapporto log</string>\n    <string name=\"text_filter_ellipsis\">Filtro…</string>\n    <string name=\"filter_choice_tag\">Tag</string>\n    <string name=\"primary_abi\">ABI primario</string>\n    <string name=\"hidden_api_enf_default_policy\">Predefinito (in base al tipo di applicazione)</string>\n    <string name=\"enter_good_filename\">Inserisci un nome file valido.</string>\n    <string name=\"manage_saved_logs\">Gestisci log salvati</string>\n    <string name=\"notification_title\">Registrazione log in corso</string>\n    <string name=\"pref_default_log_level_summary\">Livello log all\\'avvio, all\\'apertura di file e durante la registrazione.</string>\n    <string name=\"pref_display_limit_title\">Limite visualizzazione log</string>\n    <string name=\"pref_filter_pattern_summary\">Filtra tag selezionati dai log.</string>\n    <string name=\"pref_expanded_by_default_title\">Espandi per impostazione predefinita</string>\n    <string name=\"text_include_device_info\">Includi informazioni dispositivo</string>\n    <string name=\"pref_display_limit_hint\" tools:ignore=\"PluralsCandidate\">Immetti un numero valido compreso tra %1$d e %2$d.</string>\n    <string name=\"toast_invalid_level\">Nome livello non valido: %s</string>\n    <string name=\"toast_invalid_selection\">Selezione non valida. Per favore riprova.</string>\n    <string name=\"unable_to_save_log\">Impossibile salvare il log. Hai inserito un nome file valido\\?</string>\n    <string name=\"widget_recording_in_progress\">Registrando…</string>\n    <string name=\"omit_sensitive_info\">Ometti informazioni sensibili</string>\n    <string name=\"omit_sensitive_info_summary\">Ometti informazioni sensibili come URL web, numeri di telefono o e-mail.</string>\n    <string name=\"text_include_dmesg\">Includi log del kernel</string>\n    <string name=\"saf\">SAF</string>\n    <string name=\"failed_to_enable_magisk_deny_list\">Impossibile abilitare Magisk DenyList</string>\n    <string name=\"magisk_denylist\">DenyList di Magisk</string>\n    <string name=\"zygote_preload_name\">Nome precaricamento Zygote</string>\n    <string name=\"hidden_api_enforcement_policy\">Criterio di applicazione dell\\'API nascosta</string>\n    <string name=\"hidden_api_enf_policy_none\">Nessuno (accesso completo all\\'API nascosta)</string>\n    <string name=\"hidden_api_enf_policy_warn\">Avvisa (accesso completo all\\'API nascosta ma emette avvisi)</string>\n    <string name=\"hidden_api_enf_policy_dark_grey_and_black\">Enforce (liste grigie e nere)</string>\n    <string name=\"binary_32_bit\">32 Bit</string>\n    <string name=\"binary_64_bit\">64 Bit</string>\n    <string name=\"endianness_little_endian\">Little endian</string>\n    <string name=\"endianness_big_endian\">Big endian</string>\n    <string name=\"pref_vt_apikey_description\">Una chiave API consente a App Manager di caricare i file APK su VirusTotal e di recuperare i rapporti. Iscriviti su https://virustotal.com per ottenere gratuitamente una chiave API.</string>\n    <string name=\"search_type_regular_expressions\">Espressione regolare</string>\n    <string name=\"pref_vt_apikey_summary\">Abilita la scansione file APK tramite VirusTotal.</string>\n    <string name=\"threads\">Conteggio thread</string>\n    <string name=\"so_type_shared_library\">Libreria condivisa</string>\n    <string name=\"scan_in_vt\">Scansiona su VirusTotal</string>\n    <string name=\"app_explorer\">Esplora app</string>\n    <string name=\"pem_and_pk8\">PEM e PKCS #8 (PK8)</string>\n    <string name=\"pk8_file\">File PKCS #8 (PK8)</string>\n    <string name=\"import_from_tb\">Importa da Titanium Backup</string>\n    <string name=\"pkcs12_keystore\">PKCS #12 KeyStore (P12)</string>\n    <string name=\"intent_firewall_and_disable\">IFW + disabilita</string>\n    <string name=\"uses_play_app_signing_description\">Questa app contiene alcuni indicatori che indicano che <i>potrebbe</i> utilizzare <a href=\"https://support.google.com/googleplay/android-developer/answer/9842756\">Firma app Play</a>. Con questo schema, le chiavi di firma vengono archiviate nei server di Google e Google è responsabile della firma dell\\'app. Tieni presente che la corrispondenza delle informazioni sulla firma è l\\'unico modo per verificare che l\\'app non sia stata modificata da persone diverse dallo sviluppatore (e in questo caso anche da Google).</string>\n    <string name=\"netpolicy_cannot_be_modified_for_core_apps\">Il criterio di rete non può essere modificato per le app principali di Android.</string>\n    <string name=\"pref_pure_black_theme_msg\">Usa uno sfondo completamente nero quando è abilitata la modalità notturna.</string>\n    <string name=\"open_developer_options_page\">Apri la pagina delle opzioni dello sviluppatore nelle impostazioni di Android</string>\n    <string name=\"pref_pure_black_theme\">Tema nero puro</string>\n    <string name=\"usage_mobile_data\">Dati mobili</string>\n    <string name=\"usage_wifi_data\">Dati Wi-Fi</string>\n    <string name=\"usage_times_opened\">Numero di volte che è stata aperta</string>\n    <string name=\"usage_last_used\">Ultimo uso</string>\n    <string name=\"frozen\">Congelata</string>\n    <string name=\"freeze\">Congela</string>\n    <string name=\"unfreeze\">Scongela</string>\n    <string name=\"backup_no_backups_present\">Nessun backup.</string>\n    <string name=\"restore_dots\">Ripristina…</string>\n    <string name=\"backup_apps_cannot_be_restored\">Le seguenti app non possono essere ripristinate perché non dispongono di un backup di base:</string>\n    <string name=\"backup_apps_cannot_be_backed_up\">Le seguenti app non sono installate e non è possibile eseguire il backup:</string>\n    <string name=\"restart_device\">Riavvia dispositivo</string>\n    <string name=\"import_backups_warning_delete_backups_after_import\">Elimino i backup dopo averli importati in App Manager\\? Ogni backup viene eliminato singolarmente dopo essere stato importato con successo. Se non sei sicuro, seleziona <b>No</b>.</string>\n    <string name=\"troubleshooting\">Risoluzione problemi</string>\n    <string name=\"pref_reload_apps\">Ricarica app</string>\n    <string name=\"pref_reload_apps_msg\">Ricarica l\\'elenco delle app archiviate nel database di App Manager in caso di comportamenti imprevisti.</string>\n    <string name=\"changelog_type_new\">Nuovo</string>\n    <string name=\"changelog_type_fix\">Corretto</string>\n    <string name=\"changelog_type_improve\">Migliorato</string>\n    <string name=\"unsupported_split_apk\">Non supportato</string>\n    <string name=\"view_changelog\">Scopri le novità di questa versione</string>\n    <string name=\"sort_by_total_size\">Dimensione totale</string>\n    <string name=\"am_command\">Comando <tt>am</tt></string>\n    <string name=\"pref_sign_apk_no_signing_key\">Nessuna chiave per firmare</string>\n    <string name=\"pref_sign_apk_error_signing_key_not_added\">Per firmare un file APK è necessaria una chiave di firma valida.</string>\n    <string name=\"suspend_app_description\">Questo è il metodo di congelamento più debole. Un\\'app sospesa potrebbe ancora essere visualizzata nel programma di avvio, ma sarà disattivata e non potrà essere avviata.</string>\n    <string name=\"pref_advanced_pref\">Utenti, formato del nome APK, esecuzione parallela, ecc.</string>\n    <string name=\"failed_to_unfreeze\">Impossibile scongelare <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g>.</string>\n    <string name=\"failed_to_freeze\">Impossibile congelare <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g>.</string>\n    <string name=\"pref_default_freezing_method_description\">Metodo da utilizzare per impostazione predefinita quando non è disponibile l\\'opzione per selezionare un metodo di congelamento.</string>\n    <string name=\"suspend_app\">Sospendi</string>\n    <string name=\"freeze_unfreeze\">Congela/scongela</string>\n    <string name=\"profile_freeze_msg\">Congela o scongela le app in base allo stato</string>\n    <string name=\"pref_default_freezing_method\">Metodo di congelamento predefinito</string>\n    <string name=\"hide_app\">Nascondi</string>\n    <plurals name=\"alert_failed_to_freeze\">\n        <item quantity=\"one\">Impossibile congelare l\\'app %1$d</item>\n        <item quantity=\"many\">Impossibile congelare le app %1$d</item>\n        <item quantity=\"other\">Impossibile congelare le app %1$d</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_unfreeze\">\n        <item quantity=\"one\">Impossibile scongelare l\\'app %1$d</item>\n        <item quantity=\"many\">Impossibile scongelare le app %1$d</item>\n        <item quantity=\"other\">Impossibile scongelare le app %1$d</item>\n    </plurals>\n    <string name=\"disable_app_description\">Metodo di congelamento consigliato. Disabilita l\\'app e insieme a tutti i suoi componenti, ma tutte le scorciatoie andranno perse.</string>\n    <string name=\"hide_app_description\">Questo metodo è consigliato solo per l\\'uso quotidiano. Un\\'app nascosta appare come se fosse disinstallata. Ma l\\'app potrebbe riapparire se viene reinstallata o aggiornata.</string>\n    <string name=\"filter_frozen_apps\">App congelate</string>\n    <string name=\"sort_by_frozen_app\">Prima congelata</string>\n    <string name=\"pref_appearance_description\">Tema, orientamento, caratteristiche, ecc.</string>\n    <string name=\"pref_privacy\">Privacy</string>\n    <string name=\"user_manual\">Manuale utente</string>\n    <string name=\"get_help\">Ottieni aiuto</string>\n    <string name=\"pref_privacy_description\">Blocco schermo, autorizzazione, ecc.</string>\n    <string name=\"pref_version_changelog\">Versione/Registro delle modifiche</string>\n    <string name=\"file_creation_date\">Creato</string>\n    <string name=\"file_modification_date\">Modificato</string>\n    <string name=\"file_accessed_date\">Accesso</string>\n    <string name=\"file_open_with\">Apri con</string>\n    <string name=\"file_change_open_with\">Cambia apri con</string>\n    <string name=\"file_shortcut_target_file\">File target</string>\n    <string name=\"file_properties\">Proprietà</string>\n    <string name=\"file_cut\">Taglia</string>\n    <string name=\"fm_always_open_with\">Apri sempre</string>\n    <string name=\"fm_open_with_for_this_file_only\">Solo per questo file</string>\n    <string name=\"file_open_as\">Apri come…</string>\n    <string name=\"file_open_with_custom_activity\">Personalizzata</string>\n    <string name=\"file_open_with_os_default_dialog\">Apri con la finestra di dialogo predefinita del sistema</string>\n    <string name=\"open_as_text\">Testo</string>\n    <string name=\"open_as_image\">Immagine</string>\n    <string name=\"open_as_video\">Video</string>\n    <string name=\"open_as_archive\">Archivio</string>\n    <string name=\"open_as_folder\">Cartella</string>\n    <string name=\"open_as_other\">Altro</string>\n    <string name=\"delete_filename\">Elimina %s</string>\n    <string name=\"confirm_file_deletion\">Sì, elimina</string>\n    <string name=\"on_unfreeze_open_application\">Apri l\\'app dopo averla scongelata</string>\n    <string name=\"freeze_on_phone_locked\">Congela automaticamente l\\'app quando il telefono è bloccato</string>\n    <string name=\"on_open_application_no_recents\">Non mostrare l\\'app aperta nei Recenti</string>\n    <string name=\"tap_to_freeze_app\">Tocca per congelare</string>\n    <string name=\"waiting_for_the_phone_to_be_locked\">Aspettando che il telefono venga bloccato…</string>\n    <string name=\"action_stop_service\">Stop</string>\n    <string name=\"app_can_write_and_execute_in_same_place\">L\\'app viola la <a href=\"https://en.wikipedia.org/wiki/W%5EX\">W^X policy</a> ed è in grado di scrivere ed eseguire nella stessa directory o nella stessa porzione di memoria. Ciò consente l\\'esecuzione di eseguibili arbitrari modificando gli eseguibili incorporati nell\\'app o scaricandoli da Internet. A meno che questo non sia il comportamento previsto dell\\'app (ad es. emulatori di terminale), si consiglia di trovare una versione più recente dell\\'app destinata all\\'SDK 29 (Android 10) e versioni successive o di trovare alternative.</string>\n    <string name=\"sort_by_data_usage\">Utilizzo dati</string>\n    <string name=\"filter_apps_with_keystore\">Con KeyStore</string>\n    <string name=\"filter_apps_with_saf\">Con SAF</string>\n    <string name=\"filter_apps_with_ssaid\">Con SSAID</string>\n    <string name=\"action_continue\">Continua</string>\n    <string name=\"install_for_another_user\">Installa per…</string>\n    <string name=\"confirm_uninstallation\">Conferma disinstallazione</string>\n    <string name=\"grant_required_permission\">Concedi l\\'autorizzazione richiesta</string>\n    <string name=\"grant_overlay_permission_message\">Consenti a App Manager di visualizzare una finestra mobile sopra tutte le altre finestre</string>\n    <string name=\"grant_accessibility_permission_for_tracking_window_contents\">Consenti a App Manager di utilizzare la funzione di accessibilità per tenere traccia dei contenuti della finestra principale.</string>\n    <string name=\"class_hierarchy\">Gerarchia</string>\n    <string name=\"title_ui_tracker\">Tracciamento UI</string>\n    <string name=\"title_terminal_emulator\">Terminale</string>\n    <string name=\"title_labs_activity\">Laboratori</string>\n    <string name=\"app_manager_build_expired\">Aggiornamento richiesto</string>\n    <string name=\"app_manager_build_expired_message\">Per garantire la sicurezza del tuo dispositivo e dei tuoi dati, la versione di App Manager che stai utilizzando è stata ritirata. Devi aggiornarlo all\\'ultima versione per continuare a usarlo o disinstallarlo se non è disponibile alcun aggiornamento.</string>\n    <string name=\"app_manager_build_expiring_soon_warning\">Questa versione di App Manager scadrà molto presto. Si prega di aggiornarlo all\\'ultima versione.</string>\n    <string name=\"renamed_successfully\">Rinominato</string>\n    <string name=\"selinux_context\">Contesto SELinux</string>\n    <string name=\"unix_file_permissions\">Modalità</string>\n    <string name=\"file_group_id\">Gruppo (GID)</string>\n    <string name=\"file_owner_id\">Proprietario (UID)</string>\n    <string name=\"calculating_file_size\">Calcolo in corso…</string>\n    <string name=\"sort_by_filename\">Nome</string>\n    <string name=\"sort_by_last_modified\">Ultima modifica</string>\n    <string name=\"sort_by_file_size\">Dimensione file</string>\n    <string name=\"sort_by_file_type\">Tipo file</string>\n    <string name=\"option_display_folders_on_top\">Cartelle in alto</string>\n    <string name=\"export_app_list\">Esporta elenco app</string>\n    <string name=\"export_app_list_select_format\">Seleziona il formato per l\\'esportazione dell\\'elenco delle app</string>\n    <string name=\"export_option_xml\">XML</string>\n    <string name=\"export_option_markdown\">Contrassegno</string>\n    <string name=\"funding_campaign_dialog_message\">Stiamo pubblicando una <b>campagna di finanziamento</b> per App Manager per un periodo limitato. Visita <a href=\"https://opencollective.com/app-manager#category-ABOUT\">opencollective.com/app-manager</a> per saperne di più sulla campagna. Questo avviso non verrà più visualizzato, ma puoi trovarlo nella pagina Impostazioni durante l\\'intera campagna.</string>\n    <string name=\"funding_campaign_text\">Stiamo pubblicando una <b>campagna di finanziamento</b> per App Manager per un periodo limitato. <a href=\"https://opencollective.com/app-manager#category-ABOUT\">scopri di più…</a></string>\n    <string name=\"option_display_dot_files\">File di punti</string>\n    <string name=\"adb_incomplete_usb_debugging_title\">Debug USB incompleto</string>\n    <string name=\"adb_incomplete_usb_debugging_message\">Sembra che il debug USB non sia configurato correttamente. Si prega di leggere <a href=\"https://muntashirakon.github.io/AppManager/#subsec:enable-usb-debugging\">la documentazione</a> per ulteriori passaggi. Se conosci già i passaggi, fai clic su \\\"Apri\\\" per aprire le opzioni sviluppatore oppure fai clic su \\\"Chiudi\\\" per continuare a utilizzare la modalità no-root.</string>\n    <string name=\"select_a_dex2oat_compiler_filter\"><tt>dex2oat</tt> filtro compilatore</string>\n    <string name=\"optimize_option_clear_profile_data\">Cancella dati del profilo precedente</string>\n    <string name=\"optimize_option_check_profiles\">Considera dati del profilo durante l\\'ottimizzazione DEX</string>\n    <string name=\"optimize_option_force_compilation\">Forza compilazione anche quando non richiesta</string>\n    <string name=\"optimize_option_force_dexopt\">Esegui immediatamente l\\'ottimizzazione DEX</string>\n    <string name=\"optimize_option_compile_layouts\">Compila risorse di layout</string>\n    <string name=\"title_perform_runtime_optimization_to_apps\">Esegui ottimizzazione runtime</string>\n    <string name=\"action_run\">Esegui</string>\n    <string name=\"summary_perform_runtime_optimization_to_apps\">Ottimizza DEX e (in Android 10 e versioni successive) layout per migliorare le prestazioni delle applicazioni.</string>\n    <string name=\"action_optimize_app\">Ottimizza</string>\n    <string name=\"batch_ops_runtime_optimization\">Ottimizzazione runtime</string>\n    <plurals name=\"alert_failed_to_optimize_apps\">\n        <item quantity=\"one\">Impossibile ottimizzare l\\'app %1$d</item>\n        <item quantity=\"many\">Impossibile ottimizzare le app %1$d</item>\n        <item quantity=\"other\">Impossibile ottimizzare le app %1$d</item>\n    </plurals>\n    <string name=\"title_domains_supported_by_the_app\">Domini supportati</string>\n    <string name=\"app_info_tag_open_links\">Apri link</string>\n    <string name=\"source_stamp_verified_and_identified_to_be_from_source\">SourceStamp verificato e identificato da <xliff:g id=\"source\" example=\"Google Play\">%1$s</xliff:g>.</string>\n    <string name=\"block_unblock_components_dots\">Blocca/sblocca componenti…</string>\n    <string name=\"unblock_components_dots\">Sblocca componenti…</string>\n    <string name=\"block_unblock_components_description\">Blocca o sblocca tutti i componenti identificati dalle firme fornite</string>\n    <string name=\"pref_zip_align\">Allinea file APK</string>\n    <string name=\"title_code_editor\">Editor codice</string>\n    <string name=\"redo\">Rifai</string>\n    <string name=\"replacement_text\">Sostituzione</string>\n    <string name=\"read_only_file\">File di sola lettura</string>\n    <string name=\"line_separator\">Separatore righe</string>\n    <plurals name=\"search_results\">\n        <item quantity=\"one\">%d risultato</item>\n        <item quantity=\"many\">%d risultati</item>\n        <item quantity=\"other\">%d risultati</item>\n    </plurals>\n    <string name=\"action_replace_all\">Sostituisci tutto</string>\n    <string name=\"search_option_match_case\">Caso di corrispondenza</string>\n    <string name=\"search_option_whole_word\">Parola intera</string>\n    <string name=\"search_option_regex\">Espressione regolare</string>\n    <string name=\"uninstall_app_again_message\">L\\'applicazione è stata disinstallata senza cancellare i dati e la firma. Vuoi disinstallarla completamente\\?</string>\n    <string name=\"uninstall_app\">Disinstalla %1$s</string>\n    <string name=\"debloat_list_type\">Elenco</string>\n    <string name=\"debloat_removal_type\">Tipo</string>\n    <string name=\"system_app_put_back\">Rimetti a posto</string>\n    <string name=\"debloater_title\">Debloater</string>\n    <string name=\"debloat_list_aosp\">AOSP</string>\n    <string name=\"debloat_list_oem\">OEM</string>\n    <string name=\"debloat_list_carrier\">Operatore/ISP</string>\n    <string name=\"debloat_list_google\">Google</string>\n    <string name=\"debloat_removal_replace\">Sostituisci</string>\n    <string name=\"debloat_removal_caution\">Attenzione</string>\n    <string name=\"static_shared_library\">Libreria condivisa statica</string>\n    <plurals name=\"alert_failed_to_unblock_components\">\n        <item quantity=\"one\">Impossibile sbloccare i componenti per %1$d app</item>\n        <item quantity=\"many\">Impossibile sbloccare i componenti per %1$d app</item>\n        <item quantity=\"other\">Impossibile sbloccare i componenti per %1$d app</item>\n    </plurals>\n    <string name=\"pref_layout_direction\">Direzione disposizione</string>\n    <string name=\"pref_zip_align_msg\">L\\'allineamento di un file APK ne riduce l\\'utilizzo della memoria poiché è possibile accedere direttamente ai file nell\\'APK senza copiare i dati nella RAM. Questo passaggio è necessario se <tt>extractNativeLibs</tt> è impostato su <tt>true</tt>.</string>\n    <string name=\"read_only_file_warning\">Le modifiche non possono essere scritte nel file, probabilmente perché si trova in un volume su cui App Manager non ha il permesso di scrivere. Vuoi salvarlo in un posto diverso\\?</string>\n    <string name=\"debloat_list_misc\">Miscellanea</string>\n    <string name=\"debloat_removal_safe\">Sicuro</string>\n    <string name=\"filter_force_stopped_apps\">App fermate</string>\n    <plurals name=\"file_count\">\n        <item quantity=\"one\">%d file</item>\n        <item quantity=\"many\">%d file</item>\n        <item quantity=\"other\">%d file</item>\n    </plurals>\n    <string name=\"empty_folder\">Vuoto</string>\n    <plurals name=\"folder_count\">\n        <item quantity=\"one\">%d cartella</item>\n        <item quantity=\"many\">%d cartelle</item>\n        <item quantity=\"other\">%d cartelle</item>\n    </plurals>\n    <string name=\"go_to_path\">Vai a…</string>\n    <string name=\"copy_this_path\">Copia percorso</string>\n    <string name=\"title_audio_player\">Lettore audio</string>\n    <string name=\"installing_package\">Installazione di %1$s…</string>\n    <string name=\"backing_up_app\">Backup di %1$s…</string>\n    <string name=\"restoring_app\">Ripristino di %1$s…</string>\n    <string name=\"pref_installer_force_dexopt_description\">Esegui l\\'ottimizzazione DEX subito dopo aver installato l\\'app senza attendere che il sistema lo esegua quando il sistema è inattivo.</string>\n    <string name=\"folder\">Cartella</string>\n    <string name=\"symbolic_link\">Collegamento simbolico</string>\n    <string name=\"create_new_symbolic_link\">Nuovo collegamento simbolico</string>\n    <string name=\"create_new_folder\">Nuova cartella</string>\n    <string name=\"create_new_file\">Nuovo file</string>\n    <string name=\"enter_symbolic_link_name\">Nome collegamento</string>\n    <string name=\"enter_target_path\">Percorso di destinazione</string>\n    <string name=\"invalid_target_path\">Percorso non valido</string>\n    <string name=\"copy_these_paths\">Copia percorsi</string>\n    <string name=\"title_confirm_deletion\">Conferma eliminazione</string>\n    <string name=\"conflict_detected_while_copying\">Rilevato conflitto</string>\n    <string name=\"conflict_detected_while_copying_message\">Un elemento chiamato \\\"%1$s\\\" esiste già in questa posizione. Vuoi sostituirlo\\?</string>\n    <string name=\"copy_keep_both_file\">Mantieni entrambi</string>\n    <string name=\"copied_successfully\">Copiato.</string>\n    <string name=\"moved_successfully\">Spostato</string>\n    <string name=\"failed_to_delete_specified_file_after_copying\">Impossibile eliminare \\\"%1$s\\\" dopo averlo copiato, probabilmente a causa di un\\'autorizzazione insufficiente.</string>\n    <string name=\"title_change_selinux_context\">Cambia il contesto di SELinux</string>\n    <string name=\"apply_recursively\">Applica ai file inclusi</string>\n    <string name=\"change_owner_uid\">Cambia proprietario (UID)</string>\n    <string name=\"change_group_gid\">Cambia gruppo (GID)</string>\n    <string name=\"change_mode\">Cambia modalità</string>\n    <string name=\"pref_send_notification_to_connected_devices_msg\">Imposta se inviare notifiche ai dispositivi connessi come i dispositivi indossabili.</string>\n    <string name=\"warning_working_on_system_mode\">Avviso: sto operando in modalità sistema invece che in modalità ADB.</string>\n    <string name=\"symbolic_link_not_supported\">Questa cartella non supporta la creazione di un collegamento simbolico.</string>\n    <string name=\"failed_to_copy_specified_file\">Impossibile copiare \\\"%1$s\\\".</string>\n    <string name=\"pref_send_notifications_to_connected_devices\">Invia notifiche ai dispositivi connessi</string>\n    <string name=\"debloat_removal_safe_short_description\">Sicuro da rimuovere</string>\n    <string name=\"debloat_removal_caution_short_description\">Presta attenzione</string>\n    <string name=\"debloat_removal_replace_short_description\">Sostituisci con alternativa</string>\n    <string name=\"title_alternatives_to_bloatware\">Alternative</string>\n    <string name=\"pref_files_msg\">Configura file manager.</string>\n    <string name=\"pref_files_display_in_launcher\">Visualizza \\\"File\\\" nel cassetto delle app</string>\n    <string name=\"pref_files_remember_last_path\">Ricorda l\\'ultimo percorso aperto e la sua posizione</string>\n    <string name=\"pref_set_home\">Imposta principale</string>\n    <string name=\"xposed_module_info\">Informazioni sul modulo Xposed</string>\n    <string name=\"title_description\">Descrizione</string>\n    <string name=\"tap_to_open_notification_settings\">Tocca per nascondere</string>\n    <string name=\"action_lock_app\">Blocca</string>\n    <string name=\"pref_enable_persistent_session\">Esegui App Manager in background</string>\n    <string name=\"pref_files_remember_last_path_msg\">Quando questa opzione è abilitata, aprendo una nuova finestra viene aperta l\\'ultima cartella aperta anziché la cartella principale.</string>\n    <string name=\"installer_options\">Opzioni installazione</string>\n    <string name=\"browse_files\">Sfoglia</string>\n    <string name=\"module_name\">Nome modulo</string>\n    <string name=\"app_manager_is_running\">App Manager è in esecuzione</string>\n    <string name=\"app_manager_is_unlocked\">App Manager è sbloccata</string>\n    <string name=\"pref_enable_persistent_session_msg\">L\\'esecuzione di App Manager in background riduce il ritardo di inizializzazione. Utile se usi spesso App Manager.</string>\n    <string name=\"pref_enable_auto_lock\">Blocco automatico</string>\n    <string name=\"pref_enable_auto_lock_msg\">Blocca App Manager quando il dispositivo è bloccato.</string>\n    <string name=\"path_does_not_exist\">\\\"%1$s\\\" non esiste</string>\n    <string name=\"path_not_a_folder\">\\\"%1$s\\\" non è una cartella</string>\n    <string name=\"scan_report_from_pithus\">Rapporto Pithus</string>\n    <string name=\"action_checking\">Controllo…</string>\n    <string name=\"report_not_available\">Non disponibile</string>\n    <string name=\"profile_modified_are_you_sure\">Il profilo è stato modificato. Annullare tutte le modifiche ed uscire\\?</string>\n    <string name=\"apply_profile\">Applica profilo “%1$s”</string>\n    <string name=\"copy_profile_id\">Copia ID profilo</string>\n    <string name=\"profile_id\">ID profilo</string>\n    <string name=\"choose_a_profile_state\">Seleziona stato del profilo</string>\n    <string name=\"netpolicy_reject_metered_background_data\">Rifiuta dati in background sulle reti a consumo</string>\n    <string name=\"netpolicy_reject_metered_data\">Rifiuta dati sulle reti a consumo</string>\n    <string name=\"netpolicy_allow_metered_background_data\">Consenti dati in background su reti a consumo anche quando è attivo il Risparmio dati</string>\n    <string name=\"pref_toggle_internet_msg\">Attiva funzionalità Internet in Gestione app</string>\n    <string name=\"launch_activity_dialog_message\">App Manager sta tentando di avviare l\\'attività tramite <b>Assistente di ricerca</b> (solitamente Assistente Google), ma non è in grado di farlo a causa di autorizzazioni insufficienti. Per aprire l\\'attività, attiva manualmente l\\'<b>Assistente di ricerca</b> (di solito facendo clic a lungo sul pulsante Home). Fai clic sul pulsante <b>Chiudi</b> dopo aver finito di avviare l\\'attività per tornare all\\'assistente originale.</string>\n    <string name=\"select_filter\">Seleziona un filtro</string>\n    <string name=\"size_in_bytes\">Dimensioni (byte)</string>\n    <string name=\"invalid_regex\">Espressione regolare non valida!</string>\n    <string name=\"value_cannot_be_empty\">Il valore non può essere vuoto!</string>\n    <string name=\"date\">Data</string>\n    <string name=\"pref_use_vt\">Usa VirusTotal</string>\n    <string name=\"virus_total\">VirusTotal</string>\n    <string name=\"finder_title\">Trovatore</string>\n    <string name=\"launch_activity_dialog_title\">Attività di lancio: azione richiesta</string>\n    <string name=\"pref_use_vt_no_internet\">VirusTotal richiede il funzionamento di Internet, che non è abilitato. Abilita prima <a href=\"app-manager://settings/privacy_prefs/toggle_internet\">\\\"Usa Internet\\\"</a>.</string>\n    <string name=\"pref_use_log_viewer\">Usa visualizzatore registro</string>\n    <string name=\"pref_installer\">Usa programma di installazione</string>\n    <string name=\"pref_cat_general\">Generale</string>\n    <string name=\"status_remote_server_active\">Il server remoto è attivo</string>\n    <string name=\"status_remote_server_inactive\">Il server remoto è inattivo</string>\n    <string name=\"status_remote_services_active\">I servizi remoti sono attivi</string>\n    <string name=\"status_remote_services_inactive\">I servizi remoti sono inattivi</string>\n    <string name=\"status_connecting\">Connessione…</string>\n    <string name=\"status_connecting_via_mode\">Connessione tramite %s</string>\n    <string name=\"status_connected_via_mode\">Connesso tramite %s</string>\n    <string name=\"status_not_connected_via_mode\">Impossibile connettersi tramite %s</string>\n    <string name=\"adb_pairing_instruction\">Vai alle opzioni sviluppatore per abilitare il debug wireless e generare un codice di accoppiamento. Fai clic su <b>Manuale</b> se hai già aperto le opzioni sviluppatore.</string>\n    <string name=\"adb_pairing_searching_for_port\">Ricerca…</string>\n    <string name=\"adb_pairing_stop_searching\">Ferma</string>\n    <string name=\"adb_pairing_input_pairing_code\">Codice abbinamento</string>\n    <string name=\"adb_pairing_pairing_code\">Codice abbinamento</string>\n    <string name=\"adb_pairing_found_pairing_service_with_port\">Trovato un servizio con porta %d</string>\n    <string name=\"adb_pairing_pairing_in_progress\">Accoppiamento…</string>\n    <string name=\"adb_pairing_retry_pairing\">Riprova</string>\n    <string name=\"mode_of_op_custom_command_title\">Comando personalizzato</string>\n    <string name=\"mode_of_op_custom_command\">Se non riesci a utilizzare nessuna delle modalità, puoi eseguire il comando seguente in qualsiasi shell supportata per eseguire App Manager in modalità privilegiata:</string>\n    <string name=\"mode_of_op_alternative_custom_command\">Se ricevi un errore di \\\"autorizzazione negata\\\" con il comando precedente, esegui invece il comando seguente:</string>\n    <string name=\"sensors\">Sensori</string>\n    <string name=\"tag_sensors_disabled\">Sensori disabilitati</string>\n    <string name=\"pref_use_system_font\">Usa font di sistema</string>\n    <string name=\"pref_use_system_font_msg\">Usa il font predefinito del sistema invece del font material. <font fgcolor=\"#ff0000\">Questa è una funzionalità sperimentale.</font></string>\n    <string name=\"apk_source\">Sorgente APK</string>\n    <string name=\"backup_cache\">Cache</string>\n    <string name=\"actual_installer\">Installatore effettivo</string>\n    <string name=\"activity_name\">Nome attività</string>\n</resources>"
  },
  {
    "path": "app/src/main/res/values-iw/disclaimer.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"disclaimer_body\">App Manager מציע פונקציות שורש שעלולות להזיק למכשיר שלך אם נעשה בו שימוש לא נכון. מנהל האפליקציות אינו אחראי לכל נזק שנגרם על ידי שימוש באפליקציה זו. אם אינך מודע לחלוטין לאופן הפעולה של שורש, עליך להימנע משימוש באפשרויות שורש עד שתהיה מודע לחלוטין לסיכונים.\n\\n\n\\n כל קישור שאני מספק לאפליקציות ואתרים אחרים הוא לטובת המשתמשים. אני לא אחראי לכל תוכן שאתה עשוי למצוא בקישורים חיצוניים.\n\\n\n\\n על ידי שימוש ב-App Manager, אתה מקבל אחריות מלאה על השימוש שלך ולא מקבל שום נזק, תביעות או ערך כספי עקב שימוש לרעה.\n\\n\n\\n על ידי שימוש באפליקציה זו, אתה מקבל את כל האחריות לשימוש בה ומסכים שאינני אחראי לכל פעולות שאתה מבצע שיש להן השפעה שלילית על המכשיר שלך.</string>\n    <string name=\"disclaimer_header\">כתב ויתור</string>\n    <string name=\"disclaimer_footer\">© 2020–2024 מונטשיר אל-איסלאם</string>\n    <string name=\"disclaimer_agree_forever\">לעולם אל תראה את זה שוב</string>\n    <string name=\"disclaimer_agree\">אני מסכים</string>\n    <string name=\"disclaimer_exit\">יציאה</string>\n</resources>"
  },
  {
    "path": "app/src/main/res/values-iw/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\">\n    <string name=\"read\">לקרוא</string>\n    <string name=\"write\">לכתוב</string>\n    <string name=\"no_receivers\">אין מקלטים</string>\n    <string name=\"providers\">ספקים</string>\n    <string name=\"no_providers\">אין ספקים</string>\n    <string name=\"launch_mode\">מצב הפעלה</string>\n    <string name=\"task_affinity\">זיקה למשימה</string>\n    <string name=\"app_signing_signatures\">חתימות</string>\n    <string name=\"soft_input\">מצב קלט רך</string>\n    <string name=\"no_feature\">אין תכונות</string>\n    <string name=\"launch\">להריץ</string>\n    <string name=\"orientation\">נטייה</string>\n    <string name=\"shared_libs\">ליבות משותפות</string>\n    <string name=\"authority\">רשות</string>\n    <string name=\"permissions\">משתמש בהרשאות</string>\n    <string name=\"no_service\">אין שירות</string>\n    <string name=\"patterns_allowed\">דפוסים מותרים</string>\n    <string name=\"group\">קבוצה</string>\n    <string name=\"configurations\">תצורות</string>\n    <string name=\"flags\">דגלים</string>\n    <string name=\"sort_by_sha\">חתימה</string>\n    <string name=\"shared_user_id\">שתף מזהה משתמש</string>\n    <string name=\"service\">שירות</string>\n    <string name=\"no_activities\">אין פעילויות</string>\n    <string name=\"signatures\">חתימות</string>\n    <string name=\"app_signing_no_signatures\">אין חתימות תקפות</string>\n    <string name=\"declared_permission\">הרשאות</string>\n    <string name=\"input_features\">תכונות קלט</string>\n    <string name=\"refresh\">רענן</string>\n    <string name=\"uses_feature\">משתמש בתכונות</string>\n    <string name=\"path_permissions\">הרשאות נתיב</string>\n    <string name=\"require_no_permission\">אין צורך באישור</string>\n    <string name=\"receivers\">מקלטים</string>\n    <string name=\"uninstall\">הסר התקנה</string>\n    <string name=\"grant_uri_permission\">הענק הרשאות URI</string>\n    <string name=\"no_configurations\">אין תצורות</string>\n    <string name=\"activities\">פעילויות</string>\n    <string name=\"sort_by_shared_user_id\">שתף מזהה משתמש</string>\n    <string name=\"sort_by_last_update\">העדכון אחרון</string>\n    <string name=\"word_wrap\">החלף את גלישת מילים</string>\n    <string name=\"class_viewer\">מציג כיתה</string>\n    <string name=\"found_trackers\">נמצאו עוקבים:</string>\n    <string name=\"tracker_details\">פרטי הגשש</string>\n    <string name=\"tracker_classes\">גשש שיעורים</string>\n    <string name=\"all_classes\">כל השיעורים</string>\n    <string name=\"no_shared_libs\">אין ספריות משותפות</string>\n    <string name=\"type_boolean\">אמת/שקר</string>\n    <string name=\"databases\">מאגרי מידע</string>\n    <string name=\"credits\">קרדיט</string>\n    <string name=\"share_apk\">שתף APK</string>\n    <string name=\"sort\">סוג</string>\n    <string name=\"sort_by_domain\">אפליקציות משתמש תחילה</string>\n    <string name=\"version_name_with_code\">גירסא <xliff:g id=\"version_name\" example=\"2.5.17\">%1$s</xliff:g> (<xliff:g id=\"version_code\" example=\"365\">%2$d</xliff:g>)</string>\n    <string name=\"sort_by_target_sdk\">יעד SDK</string>\n    <string name=\"data_received\">המידע התקבל</string>\n    <string name=\"data_transmitted\">נתונים מועברים</string>\n    <string name=\"data_usage_msg\">שימוש בנתונים</string>\n    <string name=\"app_info\">מידע אפליקציה</string>\n    <string name=\"user_app\">אפליקציית משתמש</string>\n    <string name=\"source_dir\">ספריית מקורות</string>\n    <string name=\"sdk_flags\">דגלים</string>\n    <string name=\"date_installed\">תאריך ההתקנה</string>\n    <string name=\"date_updated\">תאריך עדכון</string>\n    <string name=\"installer_app\">התקן אפליקציה</string>\n    <string name=\"shortcut_name\">שם קיצור דרך</string>\n    <string name=\"class_name\">שם הכיתה</string>\n    <string name=\"icon_picker\">בוחר אייקונים</string>\n    <string name=\"go_back\">חזור אחורה</string>\n    <string name=\"license\">רשיון</string>\n    <string name=\"no_tracker_class\">אין שיעורי גשש</string>\n    <string name=\"usage_7_days\">7 ימים אחרונים</string>\n    <plurals name=\"usage_hours\">\n        <item quantity=\"one\">%1$d שעה</item>\n        <item quantity=\"two\">%1$d שעות</item>\n        <item quantity=\"many\">%1$d שעות</item>\n        <item quantity=\"other\">%1$d שעה</item>\n    </plurals>\n    <string name=\"grant_usage_access\">הענק גישת שימוש</string>\n    <string name=\"menu_apply_rules\">החל כללים</string>\n    <string name=\"search\">חפש</string>\n    <string name=\"test_only\">בדיקה בלבד</string>\n    <string name=\"shared_prefs\">העדפות משותפים</string>\n    <string name=\"save\">שמור</string>\n    <string name=\"discard\">להשליך</string>\n    <string name=\"no_code\">אין קוד</string>\n    <string name=\"boolean_value\">ערך בוליאני</string>\n    <string name=\"string_value\">ערך מחרוזת</string>\n    <string name=\"done\">סיים</string>\n    <string name=\"select_type\">בחר סוג</string>\n    <string name=\"more_info\">עוד מידע</string>\n    <string name=\"user\">משתמש</string>\n    <string name=\"process_name\">שם התהליך</string>\n    <string name=\"dev_protected_data_dir\">ספריית נתונים מוגנת במכשיר</string>\n    <string name=\"package_name\">שם חבילה</string>\n    <string name=\"deletion_failed\">המחיקה נכשלה</string>\n    <string name=\"go\">לך</string>\n    <string name=\"paths_and_directories\">נתיבים ותקיות</string>\n    <string name=\"about\">אודות</string>\n    <string name=\"sdk_max\">יעד</string>\n    <string name=\"data_size\">נתונים</string>\n    <string name=\"sort_by_app_label\">תווית אפליקציה</string>\n    <string name=\"menu_remove_rules\">הסר כללים</string>\n    <string name=\"debuggable\">ניתן לניפוי באגים</string>\n    <string name=\"user_id\">משתמש ID</string>\n    <string name=\"app_usage\">שימוש באפליקציה</string>\n    <string name=\"usage_today\">היום</string>\n    <string name=\"usage_less_than_a_minute\">פחות מדקה</string>\n    <string name=\"saving_failed\">השמירה נכשלה, נסה שוב.</string>\n    <string name=\"system\">מערכת</string>\n    <string name=\"integer_value\">ערך מספר שלם</string>\n    <string name=\"manifest\">מניפסט</string>\n    <string name=\"data_dir\">ספריית נתונים</string>\n    <string name=\"cache_size\">מטמון</string>\n    <string name=\"system_app\">אפליקציות מערכת</string>\n    <string name=\"key_name_cannot_be_null\">שם המפתח לא יכול להיות ריק</string>\n    <string name=\"error_creating_shortcut\">שגיאה ביצירת קיצור דרך</string>\n    <string name=\"media_size\">מדיה</string>\n    <string name=\"long_integer_value\">ערך מספר שלם ארוך</string>\n    <string name=\"grant_usage_acess_message\">משמש להצגת מידע שימוש באפליקציה.</string>\n    <string name=\"updated_app\">מעודכן</string>\n    <string name=\"app_not_installed\">האפליקציה לא מותקנת</string>\n    <string name=\"loading\">טוען…</string>\n    <string name=\"native_library_dir\">ספריית הספרייה המקורית של JNI</string>\n    <string name=\"requested_large_heap\">ערימה גדולה</string>\n    <string name=\"error\">שגיאה</string>\n    <string name=\"key_name\">שם מפתח</string>\n    <string name=\"sdk_min\">מינימום</string>\n    <string name=\"decimal_value\">ערך עשרוני</string>\n    <string name=\"saved_successfully\">נשמר</string>\n    <string name=\"empty_package_name\">שם חבילה ריקה</string>\n    <plurals name=\"usage_seconds\">\n        <item quantity=\"one\">%1$d שניה</item>\n        <item quantity=\"two\">%1$d שניות</item>\n        <item quantity=\"many\">%1$d שניה</item>\n        <item quantity=\"other\">%1$d שניות</item>\n    </plurals>\n    <string name=\"error_evaluating_input\">לא ניתן להעריך קלט</string>\n    <string name=\"create_shortcut\">צור קיצור דרך</string>\n    <string name=\"type_float\">מספר עשרוני</string>\n    <string name=\"type_long\">מספר שלם ארוך</string>\n    <string name=\"type_string\">תווים</string>\n    <string name=\"toggle_class_listing\">החלף את רישום הכיתה</string>\n    <string name=\"error_verbose_pin_shortcut\">המשגר הנוכחי אינו תומך ב-PinShortcut. לא ניתן ליצור קיצור דרך.</string>\n    <string name=\"third_party\">ספריות ואייקונים של צד שלישי</string>\n    <string name=\"sort_by_package_name\">שם חבילה</string>\n    <string name=\"obb_size\">Obb</string>\n    <string name=\"main_activity\">פעילות עיקרית</string>\n    <string name=\"add_item\">הוסף פריט</string>\n    <string name=\"type_int\">מספר שלם</string>\n    <string name=\"delete\">מחק</string>\n    <string name=\"deleted_successfully\">נמחק</string>\n    <string name=\"usage_weekly\">שבועי</string>\n    <string name=\"failed_to_extract_apk_file\">לא ניתן היה לחלץ קובץ APK</string>\n    <plurals name=\"usage_minutes\">\n        <item quantity=\"one\">%1$d דקה</item>\n        <item quantity=\"two\">%1$d דקות</item>\n        <item quantity=\"many\">%1$d דקה</item>\n        <item quantity=\"other\">%1$d דקות</item>\n    </plurals>\n    <plurals name=\"usage_days\">\n        <item quantity=\"one\">%1$d יום</item>\n        <item quantity=\"two\">%1$d ימים</item>\n        <item quantity=\"many\">%1$d יום</item>\n        <item quantity=\"other\">%1$d ימים</item>\n    </plurals>\n    <plurals name=\"usage_months\">\n        <item quantity=\"one\">%1$d חודש</item>\n        <item quantity=\"two\">%1$d חודשים</item>\n        <item quantity=\"many\">%1$d חודש</item>\n        <item quantity=\"other\">%1$d חודשים</item>\n    </plurals>\n    <string name=\"starting_activity\">התחלת פעילות:<xliff:g id=\"activity_name\" example=\".main.MainActivity\">%1$s</xliff:g></string>\n    <string name=\"credits_message\">לכותבי \\n- פרויקט הקוד הפתוח של אנדרואיד \\n- <a href=\"https://github.com/zhaobozhen/libraries\">Absinthe\\'s libraries</a> \\n- <a href=\"https://github.com/butzist/ActivityLauncher\">Activity Launcher</a> \\n- <a href=\"https://bitbucket.org/oF2pks/fdroid-applications-info\">Apps_packages Info</a> \\n- <a href=\"https://github.com/zhaobao/AppsMonitor\">AppsMonitor</a> \\n- <a href=\"https://github.com/8enet/AppOpsX\">AppOpsX</a> \\n- <a href=\"https://github.com/gabrielemariotti/changeloglib\">ChangeLog Library</a> \\n- <a href=\"https://bitbucket.org/oF2pks/fdroid-classyshark3xodus\">ClassySharkAndroid</a> \\n- <a href=\"https://github.com/billthefarmer/editor\">Editor</a> \\n- <a href=\"https://github.com/Raival-e/File-Explorer\">File Explorer</a> \\n- <a href=\"https://github.com/nex3z/FlowLayout\">FlowLayout</a> \\n- <a href=\"https://github.com/k3b/intent-intercept\">Intent Intercept</a> \\n- <a href=\"https://github.com/YarikSOffice/lingver\">Lingver</a> \\n- <a href=\"https://github.com/topjohnwu/Magisk\">Magisk</a> \\n- <a href=\"https://github.com/zhanghai/MaterialFiles\">Material Files</a> \\n- <a href=\"https://github.com/pluscubed/matlog\">MatLog</a> \\n- <a href=\"https://github.com/matrix-org/matrix-android-sdk\">Matrix Android SDK</a> \\n- <a href=\"https://github.com/jensstein/oandbackup\">OAndBackup</a> \\n- <a href=\"https://github.com/open-keychain/open-keychain\">Open Keychain</a> \\n- <a href=\"https://github.com/Aefyr/SAI\">SAI</a> \\n- <a href=\"https://github.com/RikkaApps/Shizuku\">Shizuku</a> \\n- <a href=\"https://github.com/eclipse/tm4e\">tm4e</a> \\n- <a href=\"https://github.com/tuyafeng/Watt\">Watt</a></string>\n    <plurals name=\"tracker_and_classes\">\n        <item quantity=\"one\"></item>\n        <item quantity=\"two\"></item>\n        <item quantity=\"other\"></item>\n    </plurals>\n    <string name=\"failed_to_stop\">לא ניתן היה לעצור את <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g>.</string>\n    <string name=\"view_in_settings\">‌הצג בהגדרות</string>\n    <string name=\"disable\">השבת</string>\n    <string name=\"enable\">אפשר</string>\n    <string name=\"no_content\">ללא תוכן</string>\n    <string name=\"no_usage_in_this_time_range\">אין שימוש בטווח הזמן הזה</string>\n    <string name=\"force_stop\">עצור בכוח</string>\n    <string name=\"disabled_app\">כבה</string>\n    <string name=\"uninstall_app_message\">האם ברצונך להסיר את ההתקנה של האפליקציה הזו\\?</string>\n    <string name=\"failed_to_uninstall_app\">הסרת ההתקנה נכשלה</string>\n    <string name=\"uninstall_system_app_message\">זוהי אפליקציית מערכת. האם אתה בטוח שברצונך להסיר את ההתקנה של האפליקציה הזו\\?</string>\n    <string name=\"storage_and_cache\">אחסון ומטמון</string>\n    <string name=\"stopped\">נעצר</string>\n    <string name=\"failed_to_uninstall\">לא ניתן להסיר את ההתקנה <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g>.</string>\n    <string name=\"total_size\">סך הכל</string>\n    <string name=\"app_size\">אפליקציה</string>\n    <string name=\"uninstalled_successfully\"><xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g> הוסר.</string>\n    <plurals name=\"two_trackers_and_classes\">\n        <item quantity=\"one\"></item>\n        <item quantity=\"two\"></item>\n        <item quantity=\"other\"></item>\n    </plurals>\n</resources>"
  },
  {
    "path": "app/src/main/res/values-ja/disclaimer.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- SPDX-License-Identifier: GPL-3.0-or-later --><resources>\n    <string name=\"disclaimer_header\">免責事項</string>\n    <string name=\"disclaimer_body\">App Managerは、誤って使用するとデバイスに害を及ぼす可能性のあるルート機能を提供します。 App Managerは、このアプリケーションを使用して生じたいかなる損害についても責任を負いません。 リスクを完全に理解できない場合はRootオプションの使用をお控えください\n\\n\n\\n提供されている他のアプリやウェブサイトへのリンクはユーザーの利益のために提供していますが、 私はその内容について責任を負いません\n\\n\n\\nApp Managerを使用することによって、一切の損害の責任は利用者に存在し、 一切の保証や賠償請求は受け付けないことに同意します。\n\\n\n\\nこのアプリケーションを使用することによって あなた自身の操作によって生じる 一切の悪影響について保証が行われないことに同意します。</string>\n    <string name=\"disclaimer_footer\">© 2020–2024 Muntashir Al-Islam</string>\n    <string name=\"disclaimer_agree_forever\">二度と表示しない</string>\n    <string name=\"disclaimer_agree\">同意する</string>\n    <string name=\"disclaimer_exit\">終了</string>\n</resources>"
  },
  {
    "path": "app/src/main/res/values-ja/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- SPDX-License-Identifier: GPL-3.0-or-later --><resources xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:tools=\"http://schemas.android.com/tools\">\n    <string name=\"_lang_tag\" translatable=\"false\">ja</string>\n    <string name=\"uninstall\">アンインストール</string>\n    <string name=\"permissions\">アプリ権限</string>\n    <string name=\"require_no_permission\">権限が要求されていません</string>\n    <string name=\"activities\">アクティビティ</string>\n    <string name=\"launch\">起動</string>\n    <string name=\"refresh\">更新</string>\n    <string name=\"no_activities\">アクティビティがありません</string>\n    <string name=\"receivers\">レシーバ</string>\n    <string name=\"no_receivers\">レシーバがありません</string>\n    <string name=\"providers\">プロバイダ</string>\n    <string name=\"no_providers\">プロバイダがありません</string>\n    <string name=\"launch_mode\">起動モード</string>\n    <string name=\"task_affinity\">タスク親和性</string>\n    <string name=\"sort_by_last_update\">最後の更新</string>\n    <string name=\"authority\">認証局</string>\n    <string name=\"service\">サービス</string>\n    <string name=\"no_service\">サービスがありません</string>\n    <string name=\"orientation\">画面方向</string>\n    <string name=\"soft_input\">ソフトキーボード入力モード</string>\n    <string name=\"flags\">フラグ</string>\n    <string name=\"grant_uri_permission\">URI権限の許可</string>\n    <string name=\"path_permissions\">パス権限</string>\n    <string name=\"read\">読み込み</string>\n    <string name=\"write\">書き込み</string>\n    <string name=\"patterns_allowed\">パターンは許可されました</string>\n    <string name=\"declared_permission\">権限</string>\n    <string name=\"shared_libs\">共有ライブラリ</string>\n    <string name=\"group\">グループ</string>\n    <string name=\"uses_feature\">機能</string>\n    <string name=\"no_feature\">機能は要求されていません</string>\n    <string name=\"sort_by_shared_user_id\">共有UID</string>\n    <string name=\"shared_user_id\">共有UID</string>\n    <string name=\"sort_by_sha\">署名</string>\n    <string name=\"signatures\">シグネチャ</string>\n    <string name=\"app_signing_no_signatures\">有効な署名がありません</string>\n    <string name=\"configurations\">構成</string>\n    <string name=\"no_configurations\">構成は見つかりませんでした</string>\n    <string name=\"input_features\">入力機能</string>\n    <string name=\"manifest\">マニフェスト</string>\n    <string name=\"error\">エラー</string>\n    <string name=\"loading\">読み込み中…</string>\n    <string name=\"sort_by_app_label\">アプリ名</string>\n    <string name=\"sort_by_package_name\">パッケージ名</string>\n    <string name=\"sort_by_domain\">ユーザーアプリを優先</string>\n    <string name=\"sort_by_target_sdk\">ターゲットSDK</string>\n    <string name=\"data_received\">受信したデータ</string>\n    <string name=\"data_transmitted\">転送したデータ</string>\n    <string name=\"data_usage_msg\">データ使用量</string>\n    <string name=\"about\">概要</string>\n    <string name=\"data_size\">データ</string>\n    <string name=\"cache_size\">キャッシュ</string>\n    <string name=\"obb_size\">OBB</string>\n    <string name=\"media_size\">メディア</string>\n    <string name=\"app_not_installed\">アプリはインストールされていません</string>\n    <string name=\"system\">システム</string>\n    <string name=\"user\">ユーザー</string>\n    <string name=\"sort\">並び替え</string>\n    <string name=\"version_name_with_code\">バージョン <xliff:g id=\"version_name\" example=\"2.5.17\">%1$s</xliff:g> (<xliff:g id=\"version_code\" example=\"365\">%2$d</xliff:g>)</string>\n    <string name=\"app_info\">アプリ情報</string>\n    <string name=\"system_app\">システムアプリ</string>\n    <string name=\"user_app\">ユーザーアプリ</string>\n    <string name=\"paths_and_directories\">パスとディレクトリ</string>\n    <string name=\"source_dir\">APKの保存場所</string>\n    <string name=\"data_dir\">データの保存場所</string>\n    <string name=\"sdk_min\">最小</string>\n    <string name=\"sdk_max\">ターゲット</string>\n    <string name=\"sdk_flags\">フラグ</string>\n    <string name=\"more_info\">詳細情報</string>\n    <string name=\"date_installed\">インストール日</string>\n    <string name=\"date_updated\">アップデート日</string>\n    <string name=\"installer_app\">インストーラアプリ</string>\n    <string name=\"user_id\">ユーザーID</string>\n    <string name=\"main_activity\">メインアクティビティ</string>\n    <string name=\"empty_package_name\">空のパッケージ名</string>\n    <string name=\"error_creating_shortcut\">ショートカットの作成中にエラーが発生しました</string>\n    <string name=\"error_verbose_pin_shortcut\">現在のホームアプリはショートカットに対応していません。ショートカットが作成できませんでした。</string>\n    <string name=\"starting_activity\">次のアクティビティを起動します: <xliff:g id=\"activity_name\" example=\".main.MainActivity\">%1$s</xliff:g></string>\n    <string name=\"create_shortcut\">ｼｮｰﾄｶｯﾄを作成</string>\n    <string name=\"shortcut_name\">ショートカート名</string>\n    <string name=\"package_name\">パッケージ名</string>\n    <string name=\"class_name\">クラス名</string>\n    <string name=\"icon_picker\">アイコンを選択</string>\n    <string name=\"license\">ライセンス</string>\n    <string name=\"third_party\">サードパーティのライブラリとアイコン</string>\n    <string name=\"credits\">謝辞</string>\n    <string name=\"credits_message\"></string>\n    <string name=\"word_wrap\">ワードラップを切り替え</string>\n    <string name=\"class_viewer\">クラスビューワ</string>\n    <string name=\"toggle_class_listing\">クラスの表示を切り替え</string>\n    <plurals name=\"tracker_and_classes\">\n        <item quantity=\"other\">1個のトラッカーに<xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g>個のクラス</item>\n    </plurals>\n    <plurals name=\"two_trackers_and_classes\">\n        <item quantity=\"other\">2個のトラッカーに<xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g>個のクラス</item>\n    </plurals>\n    <plurals name=\"other_trackers_and_classes\">\n        <item quantity=\"other\"><xliff:g id=\"tracker_no\" example=\"8\">%1$d</xliff:g>個のトラッカーに<xliff:g id=\"class_no\" example=\"50\">%2$d</xliff:g>個のクラス</item>\n    </plurals>\n    <string name=\"found_trackers\">見つかったトラッカー:</string>\n    <string name=\"tracker_details\">トラッカーの詳細</string>\n    <string name=\"tracker_classes\">トラッカーのクラス</string>\n    <string name=\"all_classes\">全てのクラス</string>\n    <plurals name=\"main_list_date_days\">\n        <item quantity=\"other\"><xliff:g id=\"last_update_date\" example=\"20/10/2020\">%1$s</xliff:g> <xliff:g id=\"day_no\" example=\"5\">%2$d</xliff:g>日</item>\n    </plurals>\n    <string name=\"no_shared_libs\">共有ライブラリはありません</string>\n    <string name=\"no_tracker_class\">トラッカーのクラスは見つかりませんでした</string>\n    <string name=\"app_usage\">アプリの使用状況</string>\n    <string name=\"usage_weekly\">週</string>\n    <string name=\"usage_today\">今日</string>\n    <string name=\"usage_7_days\">最終７日間で</string>\n    <plurals name=\"usage_months\">\n        <item quantity=\"other\">%1$d 月</item>\n    </plurals>\n    <plurals name=\"usage_days\">\n        <item quantity=\"other\">%1$d 日</item>\n    </plurals>\n    <plurals name=\"usage_hours\">\n        <item quantity=\"other\">%1$d 時間</item>\n    </plurals>\n    <string name=\"usage_less_than_a_minute\">１分以下</string>\n    <string name=\"go_back\">戻る</string>\n    <string name=\"go\">設定画面に移動</string>\n    <string name=\"grant_usage_access\">使用状況へのアクセスを許可</string>\n    <string name=\"grant_usage_acess_message\">アプリの使用状況を表示するために利用されます。</string>\n    <string name=\"share_apk\">APKを共有</string>\n    <string name=\"failed_to_extract_apk_file\">APKファイルを抽出できませんでした</string>\n    <string name=\"menu_remove_rules\">ルールを除去</string>\n    <string name=\"menu_apply_rules\">ルールを反映</string>\n    <string name=\"search\">検索</string>\n    <string name=\"dev_protected_data_dir\">保護されたデータの保存場所</string>\n    <string name=\"native_library_dir\">ネイティブJNIライブラリの保存場所</string>\n    <string name=\"process_name\">プロセス名</string>\n    <string name=\"no_code\">コードがありません</string>\n    <string name=\"requested_large_heap\">ラージヒープ</string>\n    <string name=\"updated_app\">更新済み</string>\n    <string name=\"debuggable\">デバッグ可能</string>\n    <string name=\"test_only\">テストのみ</string>\n    <string name=\"shared_prefs\">共有設定</string>\n    <string name=\"databases\">データベース</string>\n    <string name=\"save\">保存</string>\n    <string name=\"discard\">破棄</string>\n    <string name=\"delete\">削除</string>\n    <string name=\"deleted_successfully\">削除しました</string>\n    <string name=\"deletion_failed\">削除に失敗しました</string>\n    <string name=\"saved_successfully\">保存しました</string>\n    <string name=\"saving_failed\">保存に失敗しました。再試行します。</string>\n    <string name=\"string_value\">文字列</string>\n    <string name=\"long_integer_value\">長整数値</string>\n    <string name=\"integer_value\">整数値</string>\n    <string name=\"decimal_value\">十進数値</string>\n    <string name=\"boolean_value\">真偽値</string>\n    <string name=\"key_name\">キーの名前</string>\n    <string name=\"select_type\">タイプを選択</string>\n    <string name=\"add_item\">アイテムを追加</string>\n    <string name=\"done\">完了</string>\n    <string name=\"type_boolean\">真/偽</string>\n    <string name=\"type_float\">十進数の数字</string>\n    <string name=\"type_int\">整数</string>\n    <string name=\"type_long\">長整数</string>\n    <string name=\"type_string\">文字列</string>\n    <string name=\"error_evaluating_input\">入力されたデータを評価できません</string>\n    <string name=\"key_name_cannot_be_null\">キーの名前は空にできません</string>\n    <string name=\"disabled_app\">無効</string>\n    <string name=\"no_usage_in_this_time_range\">この期間に使用されていません</string>\n    <string name=\"no_content\">コンテンツがありません</string>\n    <string name=\"view_in_settings\">設定画面で開く</string>\n    <string name=\"uninstall_app_message\">このアプリをアンインストールしますか？</string>\n    <string name=\"failed_to_uninstall\"><xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g>のアプリをアンストールできませんでした。</string>\n    <string name=\"uninstalled_successfully\"><xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g>はアンインストールされました。</string>\n    <string name=\"uninstall_system_app_message\">このアプリはシステムアプリです。本当にアンインストールしますか？</string>\n    <string name=\"stopped\">停止</string>\n    <string name=\"disable\">無効化</string>\n    <string name=\"enable\">有効化</string>\n    <string name=\"force_stop\">強制終了</string>\n    <string name=\"failed_to_stop\"><xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g>を停止できませんでした。</string>\n    <string name=\"storage_and_cache\">ストレージとキャッシュ</string>\n    <string name=\"total_size\">合計</string>\n    <string name=\"app_size\">アプリ本体</string>\n    <string name=\"app_ops\">AppOps</string>\n    <string name=\"no_app_ops\">AppOpsがありません</string>\n    <string name=\"failed_to_enable_op\">権限を有効化できませんでした</string>\n    <string name=\"failed_to_disable_op\">権限を無効化できませんでした</string>\n    <string name=\"rules_not_applied\">ルールはまだ反映されていません</string>\n    <string name=\"str_logo\">ロゴ</string>\n    <string name=\"pref_global_blocking_enabled\">インスタントブロッキングを有効化</string>\n    <string name=\"pref_global_blocking_enabled_msg\">手動でアプリごとにブロックを有効にしなくても自動的に全てのアプリでコンポーネントブロッキングを有効化します。</string>\n    <string name=\"usage_access\">使用状況へのアクセス</string>\n    <string name=\"app_settings\">設定</string>\n    <string name=\"usage_yesterday\">昨日</string>\n    <string name=\"exodus_link\">\\u03b5xodusのリンク</string>\n    <string name=\"sort_by_blocked_components\">ブロック済みのものを優先</string>\n    <string name=\"external_data_dir\">外部データディレクトリ</string>\n    <string name=\"external_multiple_data_dir\">外部データの場所 <xliff:g id=\"dir_no\" example=\"1\">%1$d</xliff:g></string>\n    <plurals name=\"no_of_times_opened\">\n        <item quantity=\"other\">%1$d 時間</item>\n    </plurals>\n    <string name=\"sort_by_last_used\">最終起動</string>\n    <string name=\"sort_by_screen_time\">使用時間</string>\n    <string name=\"sort_by_times_opened\">起動回数</string>\n    <string name=\"sort_by_mobile_data\">モバイルデータ量</string>\n    <string name=\"pref_import_export_blocking_rules\">ブロッキングルールをインポート/エクスポート</string>\n    <string name=\"pref_import_export_blocking_rules_msg\">WattやBlockerからルールをインポート/エクスポート</string>\n    <string name=\"pref_import_watt\">Wattからインポート</string>\n    <string name=\"pref_import_blocker\">Blockerからインポート</string>\n    <string name=\"the_import_was_successful\">インポートしました</string>\n    <string name=\"the_export_was_successful\">エクスポートしました</string>\n    <plurals name=\"failed_to_import_files\">\n        <item quantity=\"other\">%1$d 個のファイルをインポートできませんでした。</item>\n    </plurals>\n    <string name=\"apk_updater\">APKアップデータ</string>\n    <string name=\"running_apps\">実行中のアプリ</string>\n    <string name=\"kill_process\">停止</string>\n    <string name=\"disable_background_run\">ﾊﾞｯｸｸﾞﾗｳﾝﾄﾞ実行を防止</string>\n    <string name=\"pid_and_ppid\">プロセスID: %1$d, 親プロセスID: %2$d</string>\n    <string name=\"memory_virtual_memory\">メモリ: %1$s, 仮想メモリ: %2$s</string>\n    <string name=\"user_and_uid\">ユーザー: <xliff:g id=\"user_name\" example=\"root\">%1$s</xliff:g> (<xliff:g id=\"user_id\" example=\"0\">%2$d</xliff:g>)</string>\n    <string name=\"clear_data\">データを消去</string>\n    <string name=\"backup_restore\">バックアップ/復元</string>\n    <string name=\"disable_background\">バックグラウンド実行を防止</string>\n    <string name=\"export_blocking_rules\">ﾙｰﾙをｴｸｽﾎﾟｰﾄ</string>\n    <plurals name=\"alert_failed_to_clear_data\">\n        <item quantity=\"other\">%1$d 個のアプリからデータを消去できませんでした</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_uninstall\">\n        <item quantity=\"other\">%1$d 個のアプリをアンインストールできませんでした</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_disable_background\">\n        <item quantity=\"other\">%1$d 個のアプリのバックグラウンド実行を無効にできませんでした</item>\n    </plurals>\n    <string name=\"the_operation_was_successful\">完了</string>\n    <plurals name=\"alert_failed_to_force_stop\">\n        <item quantity=\"other\">%1$d 個のアプリを強制終了できませんでした</item>\n    </plurals>\n    <string name=\"toggle_kill_for_system_apps\">ｼｽﾃﾑｱﾌﾟﾘをｷﾙするか切り替え</string>\n    <string name=\"permission_name\">パーミッション名</string>\n    <string name=\"mode\">モード</string>\n    <string name=\"running\">実行中</string>\n    <string name=\"duration\">使用した時間</string>\n    <string name=\"accept_time\">許可した時間</string>\n    <string name=\"reject_time\">拒否した時間</string>\n    <string name=\"ago\">前</string>\n    <string name=\"pref_import\">インポート</string>\n    <string name=\"pref_export\">エクスポート</string>\n    <string name=\"import_options\">設定をインポート</string>\n    <string name=\"export_options\">設定をエクスポート</string>\n    <string name=\"import_failed\">インポート失敗!</string>\n    <string name=\"export_failed\">エクスポート失敗!</string>\n    <string name=\"keyboard_type\">キーボードタイプ</string>\n    <string name=\"navigation\">ナビゲーション</string>\n    <string name=\"touchscreen\">タッチスクリーン</string>\n    <string name=\"pref_export_msg\">App Managerのブロッキングルールを内部ストレージにエクスポートします。</string>\n    <string name=\"pref_import_msg\">以前エクスポートしたファイルからApp Managerのブロッキングルールをインポートします。</string>\n    <string name=\"pref_import_watt_msg\">Wattからブロッキングルールをインポートします。各アプリごとに「パッケージ名.xml」の形式でルールが保存されています。</string>\n    <string name=\"pref_import_blocker_msg\">Blockerからブロッキングルールをインポートします。アプリごとにルールが保存されています。</string>\n    <string name=\"pref_app_theme\">アプリテーマ</string>\n    <string name=\"follow_system\">システム標準</string>\n    <string name=\"battery_mode\">節電モード</string>\n    <string name=\"day\">ライトテーマ</string>\n    <string name=\"night\">ナイトテーマ</string>\n    <string name=\"select_theme\">テーマ</string>\n    <string name=\"apply\">反映</string>\n    <string name=\"pref_about_msg\">App Managerのバージョン、ライセンス、謝辞など</string>\n    <string name=\"version\">バージョン</string>\n    <string name=\"sort_by_wifi_data\">Wi-Fiデータ</string>\n    <string name=\"block_trackers\">トラッカーをブロック</string>\n    <string name=\"sort_by_component_name\">コンポーネント名</string>\n    <string name=\"reset_to_default\">ﾃﾞﾌｫﾙﾄに戻す</string>\n    <string name=\"deny_dangerous_app_ops\">危険なアプリ権限を拒否</string>\n    <string name=\"sort_by_app_ops_names\">権限名順</string>\n    <string name=\"sort_by_denied_app_ops\">拒否したものを優先</string>\n    <string name=\"sort_by_app_ops_values\">アプリ権限の値順</string>\n    <string name=\"sort_by_permission_names\">パーミッション名</string>\n    <string name=\"sort_by_dangerous_permissions\">危険なものを優先</string>\n    <string name=\"sort_by_denied_permissions\">拒否したものを優先</string>\n    <string name=\"deny_dangerous_permissions\">危険な権限を拒否</string>\n    <string name=\"sort_by_tracker_components\">トラッカーを優先</string>\n    <string name=\"unknown_op\">未知の操作</string>\n    <plurals name=\"alert_failed_to_disable_trackers\">\n        <item quantity=\"other\">%1$d 個のアプリからトラッカーを無効化できませんでした</item>\n    </plurals>\n    <string name=\"failed_to_grant_permission\">権限を許可できませんでした</string>\n    <string name=\"failed_to_revoke_permission\">権限を拒否できませんでした</string>\n    <string name=\"failed_to_reset_app_ops\">AppOpsをリセットできませんでした</string>\n    <string name=\"failed_to_deny_dangerous_perms\">全ての危険な権限を拒否することができませんでした</string>\n    <string name=\"failed_to_deny_dangerous_app_ops\">全ての危険なAppOpsを拒否することができませんでした</string>\n    <string name=\"launch_app\">起動</string>\n    <string name=\"never_ask\">二度と表示しない</string>\n    <string name=\"one_click_ops\">ワンタップ一括処理</string>\n    <string name=\"changelog\">更新履歴</string>\n    <string name=\"external_apk_no_app_op\">この外部APKにはAppOpsはありません</string>\n    <string name=\"manifest_viewer\">マニフェストビューワ</string>\n    <plurals name=\"no_of_trackers\">\n        <item quantity=\"other\">%1$d 個のトラッカー</item>\n    </plurals>\n    <plurals name=\"no_of_components\">\n        <item quantity=\"other\">%1$d 個のコンポーネント</item>\n    </plurals>\n    <string name=\"install\">インストール</string>\n    <string name=\"update\">アップデート</string>\n    <string name=\"source_code\">ソースコード</string>\n    <string name=\"source_code_links\">GitHub: https://github.com/MuntashirAkon/AppManager\n\\nGitLab: https://gitlab.com/muntashir/AppManager\n\\nRiseup: https://0xacab.org/muntashir/AppManager\n\\nCodeberg: https://codeberg.org/muntashir/AppManager</string>\n    <string name=\"pref_import_existing\">既存のルールをインポート</string>\n    <string name=\"pref_import_existing_msg\">他のアプリによって無効にされたコンポーネントを追加します。\n        多くのご検知が発生する場合があるのでご注意ください。 </string>\n    <string name=\"clear_cache\">キャッシュを消去</string>\n    <string name=\"block_unblock_trackers_description\">全てのインストールされたアプリから広告やトラッカーのコンポーネントをブロック/ブロック解除</string>\n    <string name=\"block_components_dots\">コンポーネントをブロック…</string>\n    <string name=\"deny_app_ops_description\">「63」や「RUN_IN_BACKGROUND」といった形式で与えられる値からアプリのAppOpsのモードを設定します。</string>\n    <string name=\"clear_data_from_uninstalled_apps\">アンインストール済みアプリのデータを消去</string>\n    <string name=\"clear_data_from_uninstalled_apps_description\">「DONT_DELETE_DATA」フラグのあるアプリのデータを消去します</string>\n    <string name=\"clear_app_cache\">アプリキャッシュを消去</string>\n    <string name=\"clear_app_cache_description\">全てのアプリのキャッシュを消去</string>\n    <string name=\"no_tracker_found\">トラッカーは見つかりませんでした</string>\n    <string name=\"failed_packages\">失敗したパッケージ</string>\n    <string name=\"input_signatures\">定義シグネチャ</string>\n    <string name=\"input_signatures_description\">入力する定義シグネチャは「com.facebook org.app2 com.app3」のように半角スペース区切りで指定してください</string>\n    <string name=\"filtered_packages\">フィルタ済みのパッケージ</string>\n    <string name=\"input_app_ops\">AppOpsを指定</string>\n    <string name=\"input_app_ops_description\">AppOpsの名前かその値を「WAKE_LOCK 63 72 CAMERA」のようにスペース区切りで指定してください。</string>\n    <string name=\"only_works_in_root_or_adb_mode\">RootかADBモードでのみ動作します</string>\n    <string name=\"failed_to_parse_some_numbers\">いくつかをパースできませんでした</string>\n    <plurals name=\"no_of_splits\">\n        <item quantity=\"other\">%1$d splits</item>\n    </plurals>\n    <string name=\"termux\">Termux</string>\n    <string name=\"package_name_is_installed_successfully\"><xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g> インストール済み</string>\n    <string name=\"filter\">フィルタ</string>\n    <string name=\"filter_user_apps\">ユーザーアプリ</string>\n    <string name=\"filter_system_apps\">システムアプリ</string>\n    <string name=\"filter_apps_with_rules\">ルールを適用済み</string>\n    <string name=\"select_all\">全て選択</string>\n    <string name=\"installed_version\">インストール済みのバージョン</string>\n    <string name=\"trackers\">トラッカー</string>\n    <string name=\"components\">コンポーネント</string>\n    <string name=\"features\">機能</string>\n    <string name=\"whats_new\">最新情報</string>\n    <string name=\"blocking_rules\">ブロッキングルール</string>\n    <string name=\"external_data\">外部データ</string>\n    <string name=\"data\">データ</string>\n    <string name=\"backup\">バックアップ</string>\n    <string name=\"restore\">復元</string>\n    <string name=\"delete_backup\">バックアップを削除</string>\n    <string name=\"backup_options\">バックアップオプション</string>\n    <plurals name=\"failed_to_backup_some_apk_files\">\n        <item quantity=\"other\">%1$d 個のアプリをバックアップできませんでした</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_backup\">\n        <item quantity=\"other\">%1$d 個のアプリをバックアップできませんでした</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_restore\">\n        <item quantity=\"other\">%1$d 個のアプリを復元できませんでした</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_delete_backup\">\n        <item quantity=\"other\">%1$d 個のバックアップを削除できませんでした</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_unblock_trackers\">\n        <item quantity=\"other\">%1$d 個のアプリからトラッカーのブロック解除ができませんでした</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_block_components\">\n        <item quantity=\"other\">%1$d 個のアプリのコンポーネントをブロックできませんでした</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_set_app_ops\">\n        <item quantity=\"other\">%1$d 個のアプリのAppOpsを設定できませんでした</item>\n    </plurals>\n    <plurals name=\"backup_exists_are_you_sure\">\n        <item quantity=\"other\">２つ以上のアプリに既存のバックアップがあります。宜しいですか？</item>\n    </plurals>\n    <plurals name=\"classes\">\n        <item quantity=\"other\">%1$d 個のクラス</item>\n    </plurals>\n    <plurals name=\"libraries\">\n        <item quantity=\"other\">%1$d 個のライブラリ</item>\n    </plurals>\n    <plurals name=\"missing_signatures\">\n        <item quantity=\"other\">%1$d 個のシグネチャが不明</item>\n    </plurals>\n    <plurals name=\"app_signing_signature_schemes_pl\">\n        <item quantity=\"other\">署名方式</item>\n    </plurals>\n    <plurals name=\"verified_with_warning\">\n        <item quantity=\"other\">検証済み、 %d 個の警告</item>\n    </plurals>\n    <string name=\"apply_to_system_apps\">システムアプリにも反映</string>\n    <string name=\"apply_to_system_apps_question\">システムアプリにも反映しますか？不要な場合 \\\"いいえ\\\" を選択してください</string>\n    <string name=\"no\">いいえ</string>\n    <string name=\"yes\">はい</string>\n    <string name=\"skip_signature_checks\">署名チェックをスキップ</string>\n    <string name=\"clear_data_message\">本当にこのアプリのデータを消去して宜しいですか？</string>\n    <string name=\"clear\">消去</string>\n    <string name=\"block\">ブロック</string>\n    <string name=\"unblock\">ブロック解除</string>\n    <string name=\"block_unblock_trackers\">ﾄﾗｯｶｰをﾌﾞﾛｯｸ/ﾌﾞﾛｯｸ解除</string>\n    <string name=\"no_matching_package_found\">一致するアプリが見つかりませんでした</string>\n    <string name=\"export_icon\">アイコンを抽出</string>\n    <string name=\"open_in_termux\">Termuxで開く</string>\n    <string name=\"run_in_termux\">Termuxで実行</string>\n    <string name=\"website\">ウェブサイト</string>\n    <string name=\"pref_remove_all_rules\">全てのルールを消去</string>\n    <string name=\"pref_remove_all_rules_msg\">権限は全て許可され、AppOpsとコンポーネントは標準の値に戻されます。</string>\n    <string name=\"are_you_sure\">本当に宜しいですか？</string>\n    <string name=\"filter_apps_with_activities\">アクティビティが存在するアプリ</string>\n    <string name=\"toggle_default_app_ops\">標準のAppOpsを切り替え</string>\n    <string name=\"installer_error_aborted\">キャンセルされたか、予期せずにセッションが中断されたためインストールに失敗しました</string>\n    <string name=\"installer_error_blocked_device\">端末</string>\n    <string name=\"installer_error_blocked\">インストールは <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g> によってブロックされました</string>\n    <string name=\"installer_error_conflict\">このパッケージ名は競合するためアプリをインストールできませんでした</string>\n    <string name=\"installer_error_incompatible\">このアプリはこの端末に互換性がありません</string>\n    <string name=\"installer_error_bad_apks\">無効か、破損したAPKが選択されました</string>\n    <string name=\"installer_error_storage\">このアプリをインストールするのに十分なストレージ容量がありません</string>\n    <string name=\"installer_error_generic\">インストールに失敗しました</string>\n    <string name=\"installer_error_lidl_rom\">あなたが使用しているROMはルートレスインストーラに対応していません。</string>\n    <string name=\"failed_to_fetch_package_info\">パッケージ情報を取得できませんでした</string>\n    <string name=\"batch_ops\">バッチ処理</string>\n    <string name=\"operation_running\">処理を実行中…</string>\n    <string name=\"full_stop_tap_to_see_details\">. タップして詳細を表示.</string>\n    <string name=\"try_again\">再試行</string>\n    <string name=\"install_app_message\">このアプリをインストールしますか？</string>\n    <string name=\"reinstall\">再インストール</string>\n    <string name=\"unblock_trackers\">トラッカーをブロック解除</string>\n    <string name=\"package_installer\">パッケージインストーラ</string>\n    <string name=\"install_in_progress\">インストール中…</string>\n    <string name=\"installer_error_security\">APKファイルにアクセスできませんでした</string>\n    <string name=\"installer_error_session_create\">インストーラセッションを作成できませんでした</string>\n    <string name=\"installer_error_session_write\">インストーラセッションに書き込みができませんでした</string>\n    <string name=\"installer_error_session_commit\">APKファイルをコミットできませんでした</string>\n    <string name=\"installer_error_session_abandon\">インストーラセッションを中止できませんでした</string>\n    <string name=\"backup_apk_files\">APKファイル</string>\n    <string name=\"backup_obb_media\">OBBとメディア</string>\n    <string name=\"failed_to_extract_obb_files\">OBBファイルを抽出できませんでした</string>\n    <string name=\"obb_files_extracted_successfully\">OBBファイルは抽出されました</string>\n    <string name=\"backup_multiple\">複数バックアップ</string>\n    <string name=\"backup_all_users\">全てのユーザー</string>\n    <string name=\"pref_app_language\">言語</string>\n    <string name=\"auto\">自動</string>\n    <string name=\"choose_language\">言語を変更</string>\n    <string name=\"base_apk\">Base APK</string>\n    <string name=\"split_feature_name\">機能: <xliff:g id=\"feature_name\" example=\"Visualizer\">%1$s</xliff:g></string>\n    <string name=\"unknown_split_for_feature\"><xliff:g id=\"split_name\" example=\"some_split\">%1$s</xliff:g> for feature <xliff:g id=\"feature_name\" example=\"Visualizer\">%2$s</xliff:g></string>\n    <string name=\"unknown_split_for_base_apk\"><xliff:g id=\"split_name\" example=\"some_split\">%1$s</xliff:g> for base APK</string>\n    <string name=\"density_split_for_feature\"><xliff:g id=\"split_name\" example=\"xxdpi\">%1$s</xliff:g> (<xliff:g id=\"dpi_no\" example=\"480\">%2$d</xliff:g> DPI) resources for feature <xliff:g id=\"feature_name\" example=\"Visualizer\">%3$s</xliff:g></string>\n    <string name=\"density_split_for_base_apk\"><xliff:g id=\"split_name\" example=\"xxdpi\">%1$s</xliff:g> (<xliff:g id=\"dpi_no\" example=\"480\">%2$d</xliff:g> DPI) resources for base APK</string>\n    <string name=\"abi_split_for_feature\"><xliff:g id=\"feature_name\" example=\"Visualizer\">%2$s</xliff:g>の <xliff:g id=\"split_name\" example=\"arm64_v8a\">%1$s</xliff:g> ネイティブコード</string>\n    <string name=\"abi_split_for_base_apk\">ベースAPKの<xliff:g id=\"split_name\" example=\"arm64_v8a\">%1$s</xliff:g> ネイティブコード</string>\n    <string name=\"locale_split_for_feature\">機能 <xliff:g id=\"feature_name\" example=\"Visualizer\">%2$s</xliff:g>の <xliff:g id=\"split_name\" example=\"English\">%1$s</xliff:g> 言語データ</string>\n    <string name=\"locale_split_for_base_apk\">ベースAPKの<xliff:g id=\"split_name\" example=\"English\">%1$s</xliff:g>言語データ</string>\n    <string name=\"launch_mode_multiple\">複数</string>\n    <string name=\"launch_mode_single_instance\">単一インスタンス</string>\n    <string name=\"launch_mode_single_task\">単一タスク</string>\n    <string name=\"launch_mode_single_top\">スタックトップ</string>\n    <string name=\"orientation_unspecified\">未定義</string>\n    <string name=\"orientation_behind\">Behind</string>\n    <string name=\"orientation_full_sensor\">全センサー</string>\n    <string name=\"orientation_full_user\">全ユーザー</string>\n    <string name=\"orientation_locked\">ロック</string>\n    <string name=\"orientation_no_sensor\">センサーなし</string>\n    <string name=\"orientation_landscape\">横向き</string>\n    <string name=\"orientation_portrait\">通常</string>\n    <string name=\"orientation_reverse_portrait\">横向き(反対）</string>\n    <string name=\"orientation_reverse_landscape\">逆向き</string>\n    <string name=\"orientation_user\">ユーザー</string>\n    <string name=\"orientation_sensor_landscape\">センサー横向き</string>\n    <string name=\"orientation_sensor_portrait\">センサー縦</string>\n    <string name=\"orientation_sensor\">センサー</string>\n    <string name=\"orientation_user_landscape\">ユーザー横向き</string>\n    <string name=\"orientation_user_portrait\">ユーザー縦</string>\n    <string name=\"required\">必須</string>\n    <string name=\"_undefined\">未定義</string>\n    <string name=\"keyboard_no_keys\">キーなし</string>\n    <string name=\"keyboard_qwerty\">QWERTY</string>\n    <string name=\"keyboard_12_keys\">12キー</string>\n    <string name=\"navigation_no_nav\">ナビバーなし</string>\n    <string name=\"navigation_dial_pad\">数字パッド</string>\n    <string name=\"navigation_trackball\">トラックボール</string>\n    <string name=\"navigation_wheel\">ホイール</string>\n    <string name=\"touchscreen_no_touch\">タッチなし</string>\n    <string name=\"touchscreen_stylus\">スタイラス</string>\n    <string name=\"touchscreen_finger\">指</string>\n    <string name=\"state_sleeping\">休止中</string>\n    <string name=\"state_device_io\">デバイス入出力</string>\n    <string name=\"state_trace_stop\">Trace stop</string>\n    <string name=\"state_dead\">停止</string>\n    <string name=\"state_zombie\">Zombie</string>\n    <string name=\"state_parked\">Parked</string>\n    <string name=\"state_idle\">アイドル状態</string>\n    <string name=\"state_wake_kill\">Wake kill</string>\n    <string name=\"state_waking\">起動中</string>\n    <string name=\"state_unknown\">不明</string>\n    <string name=\"state_high_priority\">高優先度</string>\n    <string name=\"state_low_priority\">低優先度</string>\n    <string name=\"state_locked_memory\">Locked memory</string>\n    <string name=\"state_session_leader\">Session leader</string>\n    <string name=\"state_foreground\">フォアグラウンド</string>\n    <string name=\"state_multithreaded\">Multithreaded</string>\n    <string name=\"process_state\">状態: <xliff:g id=\"process_state\" example=\"Sleeping\">%1$s</xliff:g></string>\n    <string name=\"process_state_with_extra\">状態: <xliff:g id=\"process_state\" example=\"Sleeping\">%1$s</xliff:g> (<xliff:g id=\"state_extra\" example=\"High priority\">%2$s</xliff:g>)</string>\n    <string name=\"downgrade\">ダウングレード</string>\n    <string name=\"input_backup_name\">バックアップ名</string>\n    <string name=\"input_backup_name_description\">バックアップ名は数字や空白文字で始められません。項目を空にすると現在時刻が使用されます。</string>\n    <string name=\"ok\">OK</string>\n    <string name=\"cancel\">キャンセル</string>\n    <string name=\"systemless_app\">システムレスアプリ</string>\n    <string name=\"open_pgp_provider\">OpenPGPプロバイダ</string>\n    <string name=\"profiles\">プロファイル</string>\n    <string name=\"no_profiles\">プロファイルがありません</string>\n    <string name=\"keystore\">キーストア</string>\n    <string name=\"apply_now\">今すぐ反映…</string>\n    <string name=\"routine_ops\">規則的操作</string>\n    <string name=\"apps\">アプリ</string>\n    <string name=\"no_apps\">アプリがありません</string>\n    <string name=\"filter_apps\">アプリ</string>\n    <string name=\"sort_by_process_id\">プロセスID</string>\n    <string name=\"sort_by_process_name\">プロセス名</string>\n    <string name=\"sort_by_apps_first\">アプリを優先</string>\n    <string name=\"sort_by_memory_usage\">メモリ使用状況</string>\n    <string name=\"changes_not_saved\">変更は保存されていません</string>\n    <string name=\"other\">その他</string>\n    <string name=\"rules\">ルール</string>\n    <string name=\"pref_compression_method\">圧縮方式</string>\n    <string name=\"pref_backup_flags_msg\">バックアップオプションのプリセットを追加すると、バックアップ/復元するたびにフラグを選択する必要がなくなります。</string>\n    <string name=\"confirm_installation\">インストールを確認</string>\n    <string name=\"allow_open_pgp_operation\">タップしてAppManagerにOpenPGPの利用を許可する</string>\n    <string name=\"uninstall_updates\">アップデートをアンインストール</string>\n    <string name=\"update_uninstalled_successfully\"><xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g> のアップデートは正常に削除されました</string>\n    <string name=\"failed_to_uninstall_updates\"><xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g> のアップデートが削除できませんでした</string>\n    <string name=\"sort_by_backup\">バックアップ済みを優先</string>\n    <string name=\"filter_apps_with_backups\">バックアップ済みアプリ</string>\n    <string name=\"subject\">識別子</string>\n    <string name=\"issuer\">要求者</string>\n    <string name=\"issued_date\">要求日</string>\n    <string name=\"expiry_date\">失効日</string>\n    <string name=\"type\">タイプ</string>\n    <string name=\"validity\">妥当性</string>\n    <string name=\"valid\">有効</string>\n    <string name=\"expired\">失効済み</string>\n    <string name=\"not_yet_valid\">まだ有効ではありません</string>\n    <string name=\"serial_no\">シリアルナンバー</string>\n    <string name=\"checksums\">チェックサム</string>\n    <string name=\"app_signing_signature\">アプリ署名</string>\n    <string name=\"algorithm\">アルゴリズム</string>\n    <string name=\"public_key\">公開鍵</string>\n    <string name=\"format\">フォーマット</string>\n    <string name=\"rsa_exponent\">指数</string>\n    <string name=\"rsa_modulus\">モジュール</string>\n    <string name=\"dsa_affine_x\">アフィンX座標</string>\n    <string name=\"dsa_affine_y\">アフィンY座標</string>\n    <string name=\"critical_exts\">重要な拡張</string>\n    <string name=\"non_critical_exts\">非重要な拡張</string>\n    <string name=\"usage_access_not_supported\">該当する設定ページが存在しないため使用状況へのアクセスを要求できませんでした。</string>\n    <string name=\"do_you_want_to_uninstall_and_install\">アンインストール後再度インストールしますか？</string>\n    <string name=\"app_signing_signature_mismatch_for_system_apps\">異なるアプリ署名のシステムアプリが同じパッケージ名のため、アプリをインストールできませんでした。</string>\n    <string name=\"app_data_will_be_lost\">既存のデータは失われます。</string>\n    <string name=\"app_signing_install_without_data_loss\">署名認証をオフにしている場合、データを失うこと無く <b>インストール</b> オプションが使用できます。</string>\n    <string name=\"only_install\">インストール</string>\n    <string name=\"sys_config\">システムコンフィグ</string>\n    <string name=\"scanner\">スキャナー</string>\n    <string name=\"no_libs\">ライブラリがありません</string>\n    <string name=\"lib_details\">ライブラリ詳細</string>\n    <string name=\"tap_to_see_details\">タップして詳細を見る</string>\n    <string name=\"view_missing_signatures\">タップしてApp Managerのライブラリデータベースに登録されていないシグネチャを確認/送信する</string>\n    <string name=\"copy\">コピー</string>\n    <string name=\"filter_running_apps\">起動中のアプリ</string>\n    <string name=\"am_crashed\">AppManagerはクラッシュしました</string>\n    <string name=\"tap_to_submit_crash_report\">タップしてクラッシュレポートを送信します</string>\n    <string name=\"send_crash_report\">クラッシュレポートを送信</string>\n    <string name=\"select_apk\">APKを選択</string>\n    <string name=\"conversion_failed\">変換失敗</string>\n    <string name=\"in_progress\">処理中</string>\n    <string name=\"un_apkm\">UnApkm</string>\n    <string name=\"input_profile_name\">プロファイル名</string>\n    <string name=\"input_profile_name_description\">プロファイル名に空白文字を含むことはできません</string>\n    <string name=\"new_profile\">新しいプロファイル</string>\n    <string name=\"duplicate\">複製</string>\n    <string name=\"failed_to_duplicate_profile\">プロファイルを複製できませんでした</string>\n    <string name=\"select_user\">ユーザーを選択</string>\n    <string name=\"encryption\">暗号化</string>\n    <string name=\"pref_encryption_msg\">バックアップを暗号化する</string>\n    <string name=\"none\">なし</string>\n    <string name=\"aes\">AES</string>\n    <string name=\"rsa\">RSA</string>\n    <string name=\"ecc\">楕円曲線暗号</string>\n    <string name=\"send_selected\">選択したものを送信</string>\n    <string name=\"pref_mode_of_operations\">動作モード</string>\n    <string name=\"adb_over_tcp\">ADB over TCP</string>\n    <string name=\"allow_routine_ops\">規則的操作を許可</string>\n    <string name=\"profile_state\">プロファイルの状態</string>\n    <string name=\"allow_routine_ops_msg\">規則的操作をプロファイルで使用することを許可します</string>\n    <string name=\"profile_force_stop_msg\">アプリを強制終了する</string>\n    <string name=\"profile_clear_cache_msg\">アプリのキャッシュを自動的にクリアする</string>\n    <string name=\"profile_clear_data_msg\">アプリのデータは自動的に消去する</string>\n    <string name=\"profile_block_trackers_msg\">アプリからトラッカーを自動的にブロックする</string>\n    <string name=\"profile_state_msg\">このプロファイルのオンオフ状態を切り替えます。</string>\n    <string name=\"on\">On</string>\n    <string name=\"off\">Off</string>\n    <string name=\"options\">オプション</string>\n    <string name=\"input_permissions\">権限を指定</string>\n    <string name=\"input_permissions_description\">「com.permission.GET_ACCOUNTS android.permission.ACCESS_MEDIA_LOCATION」のようにアプリ権限を半角スペース区切りで指定してください。「*」はワイルドカードとして機能します。</string>\n    <string name=\"choose\">選択</string>\n    <string name=\"enabled\">有効</string>\n    <string name=\"simple\">シンプル</string>\n    <string name=\"advanced\">高度な設定</string>\n    <string name=\"user_profile_with_id\">プロファイル: %1$s (%2$d)</string>\n    <string name=\"root\">Root</string>\n    <string name=\"no_root\">非Root</string>\n    <string name=\"close\">閉じる</string>\n    <string name=\"comment\">コメント</string>\n    <string name=\"installer\">インストーラ</string>\n    <string name=\"install_location\">インストール場所</string>\n    <string name=\"install_location_internal_only\">内部ストレージのみ</string>\n    <string name=\"install_location_prefer_external\">外部ストレージを優先</string>\n    <string name=\"pref_sign_apk\">APKを署名</string>\n    <string name=\"pref_sign_apk_msg\">インストールする前にAPKを署名します</string>\n    <string name=\"app_signing_signature_schemes\">署名方式</string>\n    <string name=\"apk_signing\">APKの署名</string>\n    <string name=\"pref_apk_signing_msg\">署名方式やカスタム署名鍵を設定します。</string>\n    <string name=\"v1_scheme\">v1 スキーム (Android 1.0〜)</string>\n    <string name=\"v2_scheme\">v2 スキーム (Android 7.0〜)</string>\n    <string name=\"v3_scheme\">v3 スキーム (Android 9〜)</string>\n    <string name=\"v4_scheme\">v4 スキーム (Android 11〜)</string>\n    <string name=\"pref_signature_schemes_msg\">互換性のため最低でもv1とv2のスキームを選択することをお勧めします。 v4スキームはv2とv3が必須です。</string>\n    <string name=\"verified\">検証済み</string>\n    <string name=\"not_verified\">未検証</string>\n    <string name=\"source_stamp_verified\">SourceStampは検証されました</string>\n    <string name=\"splits\">Splits</string>\n    <string name=\"input_keystore_pass\">キーストアのパスワードを入力</string>\n    <string name=\"input_keystore_pass_description\">App Managerのキーストアパスワードを入力してください。これが初めて表示される場合は、パスワードジェネレータを使用してパスワードを生成し、ここに挿入する前に安全な場所に保存してください。</string>\n    <string name=\"input_keystore_pass_msg\">タップしてキーストアのパスワードを入力してください</string>\n    <string name=\"input_keystore_alias_pass\">エイリアス <b>%1$s</b> のパスワード</string>\n    <string name=\"input_keystore_alias_pass_description\">エイリアス <b>%1$s</b>のパスワードを入力してください。キーストアに登録してあるパスワードと共通の場合この項目を空にすることができます。</string>\n    <string name=\"no_app_ops_permission\">AppOpsを表示するための権限がありません</string>\n    <string name=\"this_action_cannot_be_undone\">この操作はやり直しできません</string>\n    <string name=\"keep_data_and_app_signing_signatures\">データと署名を保持する</string>\n    <string name=\"pref_backup_android_keystore\">Androidキーストアを含めてバックアップ</string>\n    <string name=\"pref_backup_android_keystore_msg\">リストア後、全てのアプリが正常動作するとは限りません。キーストアの復元はほとんどの端末で動作しません。</string>\n    <string name=\"magisk_hide_enabled\">MagiskHide</string>\n    <string name=\"set_app_op_mode\">アプリ操作モードを設定</string>\n    <string name=\"filter_apps_with_splits\">分割データを含むアプリ</string>\n    <string name=\"value\">値</string>\n    <string name=\"matching_activities\">一致するアクティビティ</string>\n    <string name=\"send_edited_intent\">改変済みｲﾝﾃﾝﾄを送信</string>\n    <string name=\"activity_result\">実行結果</string>\n    <string name=\"result_code\">結果コード</string>\n    <string name=\"action\">動作</string>\n    <string name=\"mime_type\">MIMEタイプ</string>\n    <string name=\"uri\">URI</string>\n    <string name=\"category\">カテゴリ</string>\n    <string name=\"extras\">その他</string>\n    <string name=\"share\">共有</string>\n    <string name=\"resend_intent\">インテントを再送信</string>\n    <string name=\"interceptor\">インタセプター</string>\n    <string name=\"set_custom_app_op\">カスタムAppOpsを適用</string>\n    <string name=\"about_device\">端末情報</string>\n    <string name=\"pref_about_device_msg\">Androidシステム、CPU、GPU、RAM、バッテリーなどのデバイス情報</string>\n    <string name=\"brand_name\">ブランド</string>\n    <string name=\"model\">機種</string>\n    <string name=\"board_name\">ボード名</string>\n    <string name=\"manufacturer\">製造元</string>\n    <string name=\"kernel\">カーネル</string>\n    <string name=\"security_providers\">セキュリティプロバイダー</string>\n    <string name=\"support_architectures\">対応しているアーキテクチャ</string>\n    <string name=\"no_of_cores\">コア数</string>\n    <string name=\"gles_version\">OpenGL ESバージョン</string>\n    <string name=\"vendor\">ベンター</string>\n    <string name=\"memory\">メモリ</string>\n    <string name=\"battery_capacity\">容量</string>\n    <string name=\"languages\">言語</string>\n    <string name=\"users\">ユーザー</string>\n    <string name=\"cpu\">CPU</string>\n    <string name=\"graphics\">グラフィック</string>\n    <string name=\"battery\">バッテリー</string>\n    <string name=\"security\">セキュリティ</string>\n    <string name=\"set_mode_for_app_ops_dots\">AppOpsモードをセット…</string>\n    <string name=\"backup_apk_files_description\">APKファイルのみをバックアップします <b>ソース</b> を指定する必要があります。</string>\n    <string name=\"backup_internal_data_description\">データフォルダをバックアップします。選択した場合内部データフォルダのバックアップは標準で有効になります。</string>\n    <string name=\"backup_external_data_description\">外部データフォルダをバックアップします。</string>\n    <string name=\"backup_obb_media_description\">OBBとmediaフォルダをバックアップします</string>\n    <string name=\"backup_cache_description\">「no_cache」と「no_backup」フォルダのキャッシュをバックアップしません。</string>\n    <string name=\"backup_extras\">その他</string>\n    <string name=\"backup_extras_description\">アプリ権限、バッテリーセーバー設定、データ使用設定、MagiskHideの状態、SSAIDをバックアップします。</string>\n    <string name=\"backup_rules_description\">App Manager内で構成されたルールをバックアップします。</string>\n    <string name=\"backup_multiple_description\">基本バックアップの代わりに<i>名前付き</i>バックアップを作成する</string>\n    <string name=\"backup_skip_signature_checks_description\">チェックサム認証に失敗したり、インストール済みのものと異なる署名を持つバックアップを復元します。</string>\n    <string name=\"patch_level\">セキュリティパッチレベル</string>\n    <string name=\"selinux\">SELinux</string>\n    <string name=\"enforcing\">Enforcing</string>\n    <string name=\"permissive\">Permissive</string>\n    <string name=\"hardware\">ハードウェア</string>\n    <string name=\"screen\">画面</string>\n    <string name=\"density\">密度</string>\n    <string name=\"size\">サイズ</string>\n    <string name=\"scaling_factor\">倍率</string>\n    <string name=\"refresh_rate\">リフレッシュレート</string>\n    <string name=\"window_size\">ウィンドウサイズ</string>\n    <string name=\"failed_to_disable_magisk_hide\">MagiskHideを無効にできませんでした</string>\n    <string name=\"failed_to_enable_magisk_hide\">MagiskHideを有効化できませんでした</string>\n    <string name=\"disable_background_run_description\">次のAppOpsに <i>Ignore</i> モードを設定します: <tt>RUN_IN_BACKGROUND</tt> (Android 7.0〜) and <tt>RUN_ANY_IN_BACKGROUND</tt> (Android 9〜).</string>\n    <string name=\"pref_backup_restore_msg\">バックアップ/復元に関する設定</string>\n    <string name=\"backup_volume\">バックアップを保存するボリューム</string>\n    <string name=\"pref_backup_volume_msg\">バックアップを保存するディスクやボリュームを選択します。</string>\n    <string name=\"no_volumes_found\">書き込み権限のあるボリュームを見つけることができませんでした</string>\n    <string name=\"unencrypted\">暗号化されていません</string>\n    <string name=\"encrypted\">暗号化されています</string>\n    <string name=\"bootloader\">ブートローダー</string>\n    <string name=\"backup_custom_users\">カスタムユーザー</string>\n    <string name=\"backup_custom_users_description\">指定したユーザーにのみバックアップを実行します</string>\n    <string name=\"backup_all_apps\">全てのアプリをバックアップ</string>\n    <string name=\"backup_all_apps_msg\">全てのインストール済みアプリをバックアップします。</string>\n    <string name=\"backup_apps_without_backups\">新しくバックアップ</string>\n    <string name=\"backup_apps_without_backups_msg\">以前のバックアップ無しでアプリをバックアップします。</string>\n    <string name=\"verify_and_redo_backups\">検証してバックアップをやり直す。</string>\n    <string name=\"verify_and_redo_backups_msg\">バックアップの完全性をチェックし、チェックに失敗したアプリのバックアップを再試行します。</string>\n    <string name=\"redo_existing_backups\">既存のバックアップをやり直す</string>\n    <string name=\"redo_existing_backups_msg\">以前バックアップしたインストール済みアプリのバックアップをやり直します。</string>\n    <string name=\"backup_apps_with_changes\">変更を含めてアプリをバックアップする</string>\n    <string name=\"backup_apps_with_changes_msg\">以前のバックアップから変更を含めてやり直します。サイズ、バージョン、最後の起動時間なども含まれます。</string>\n    <string name=\"restore_all\">全てのアプリを復元</string>\n    <string name=\"restore_all_msg\">全ての保存されたアプリバックアップを復元します。</string>\n    <string name=\"restore_not_installed\">インストールされていないアプリを復元</string>\n    <string name=\"restore_not_installed_msg\">現在インストールされていないアプリのアプリバックアップを復元します。</string>\n    <string name=\"restore_latest\">最新のアプリバックアップを復元</string>\n    <string name=\"restore_latest_msg\">既にインストールされているアプリよりもバージョンが高いものを復元します。</string>\n    <string name=\"backup_msg\">アプリデータを含めてバックアップする</string>\n    <string name=\"restore_msg\">アプリデータを含めて復元する</string>\n    <string name=\"drm_free_apkm_msg\">このAPKMファイルはDRMフリーです。APKSに変換する必要はありません。</string>\n    <string name=\"back_up\">バックアップ</string>\n    <string name=\"screen_lock_msg\">App Managerの起動時に認証を要求するようにする</string>\n    <string name=\"net_policy\">ネット接続ポリシー</string>\n    <string name=\"has_net_policy\">ﾈｯﾄ接続ﾎﾟﾘｼｰ</string>\n    <string name=\"list_options\">表示オプション</string>\n    <string name=\"initializing\">読み込み中…</string>\n    <string name=\"os_version\">OSバージョン</string>\n    <string name=\"add\">追加</string>\n    <string name=\"add_to_profile\">ﾌﾟﾛﾌｧｲﾙに追加</string>\n    <string name=\"reverse\">順序を反転</string>\n    <string name=\"choose_what_to_do\">実行する操作を選択してください</string>\n    <string name=\"enable_battery_optimization\">電池の最適化を有効にしますか？</string>\n    <string name=\"battery_optimization\">電池の最適化</string>\n    <string name=\"no_battery_optimization\">電池の最適化が無効</string>\n    <string name=\"unlock_app_manager\">App Managerのロック解除</string>\n    <string name=\"screen_lock\">画面ロック</string>\n    <string name=\"sd_card\">SDカード</string>\n    <string name=\"external_storage\">外部ストレージ</string>\n    <string name=\"internal_storage\">内部ストレージ</string>\n    <string name=\"restart_to_reflect_changes\">今すぐに設定を反映するには再起動する必要があります</string>\n    <string name=\"type_float_array_list\">10進数値のリスト</string>\n    <string name=\"type_float_array\">10進数値の配列</string>\n    <string name=\"type_long_array\">長整数値の配列</string>\n    <string name=\"failed_to_change_ssaid\">SSAIDを変更できませんでした</string>\n    <string name=\"copied_to_clipboard\">クリップボードにコピーされました。</string>\n    <string name=\"ssaid_info\">SSAID (<tt>Settings.Secure.ANDROID_ID</tt>) はAndroid8 Oreo以降でそれぞれのアプリごとに関連付けられた識別子です、よくユーザーを追跡するのに使用されています。</string>\n    <string name=\"ssaid\">SSAID</string>\n    <string name=\"type_uri\">URI</string>\n    <string name=\"type_string_array_list\">文字列のリスト</string>\n    <string name=\"type_string_array\">文字列の配列</string>\n    <string name=\"type_long_array_list\">長整数型のリスト</string>\n    <string name=\"type_int_array_list\">整数値のリスト</string>\n    <string name=\"type_int_array\">整数の配列</string>\n    <string name=\"type_component_name\">コンポーネント名</string>\n    <string name=\"type_null\">値がありません</string>\n    <string name=\"user_with_id\">ユーザー:<xliff:g id=\"user_id\" example=\"0\">%1$d</xliff:g></string>\n    <string name=\"installed_apps\">インストール済みのアプリ</string>\n    <string name=\"isolated\">隔離済み</string>\n    <string name=\"working_on_adb_mode\">ADBモードで使用中</string>\n    <string name=\"screen_lock_not_enabled\">Androidの設定で画面ロックを有効にするか、このアプリのデータを消去してください。</string>\n    <string name=\"last_actions\">最終アクション</string>\n    <string name=\"pref_enable_disable_features_msg\">AppManagerの機能を有効化または無効化します。</string>\n    <string name=\"enable_disable_features\">機能の有効化/無効化</string>\n    <string name=\"input_app_ops_description_profile\">AppOpsの名前かその識別値を「WAKE_LOCK 63 72 CAMERA」のようにスペース区切りで指定してください。「*」はワイルドカードとして使用できます。</string>\n    <string name=\"installer_app_message\"><b>選択</b> をタップしてインストール済みのアプリを選択するか、<b>カスタム</b> で任意のパッケージ名を指定します。</string>\n    <string name=\"specify_custom_name\">カスタム</string>\n    <string name=\"verified_using_unreliable_hash\">信頼できないハッシュで検証済み</string>\n    <string name=\"filter_apps_without_backups\">バックアップされていないアプリ</string>\n    <string name=\"uninstalled_apps\">未インストールのアプリ</string>\n    <string name=\"internal_data\">内蔵データ</string>\n    <string name=\"input_keystore_alias_pass_msg\">タップしてキーストア %1$s のパスワードを入力</string>\n    <string name=\"invalid_rsa_key_size\">RSA暗号鍵のキーサイズが無効です。キーサイズは1024ビット、2048ビット、4096ビットのいずれかを使用できます。</string>\n    <string name=\"crypto_key_size\">キーサイズ</string>\n    <string name=\"invalid_aes_key_size\">AES暗号鍵のキーサイズが無効です。キーサイズは128ビットまたは256ビットのいずれかを使用できます。</string>\n    <string name=\"failed_to_save_key\">キーを保存できませんでした。</string>\n    <string name=\"input_key\">キーを入力 (16進数値）</string>\n    <string name=\"pref_installer_msg\">App Managerインストーラの動作を設定します。</string>\n    <string name=\"pk8_file\">PKCS #8 (PK8) ファイル</string>\n    <string name=\"pem_and_pk8\">PEM/PKCS #8 (PK8)</string>\n    <string name=\"pkcs12_keystore\">PKCS #12 キーストア (P12)</string>\n    <string name=\"bouncy_castle_keystore\">Bouncy Castle キーストア (BKS)</string>\n    <string name=\"java_keystore\">Javaキーストア (JKS)</string>\n    <string name=\"country_name\" tools:ignore=\"TypographyOther\">国名 (C)</string>\n    <string name=\"state_name\">都道府県名 (ST)</string>\n    <string name=\"locality_name\">市町村名 (L)</string>\n    <string name=\"organization_name\">組織名 (O)</string>\n    <string name=\"organization_unit\">組織単位名 (OU)</string>\n    <string name=\"common_name\">コモンネーム (CN)</string>\n    <string name=\"failed_to_load_key\">キー情報の読み込みに失敗しました。</string>\n    <string name=\"key_not_set\">設定されていません</string>\n    <string name=\"use_default\">規定</string>\n    <string name=\"expiry_date_cannot_be_empty\">失効日は空白にできません。</string>\n    <string name=\"signing_key\">署名鍵</string>\n    <string name=\"failed_to_read_keystore\">キーストアの読み込みに失敗しました。</string>\n    <string name=\"alias_pass\">エイリアスのパスワード</string>\n    <string name=\"choose_an_alias\">エイリアスを選択</string>\n    <string name=\"found_no_alias_in_keystore\">キーストア内にエイリアスが見つかりませんでした!</string>\n    <string name=\"new_alias_password\">新規エイリアスのパスワード</string>\n    <string name=\"import_key\">キーをインポート</string>\n    <string name=\"pem_file\">PEMファイル</string>\n    <string name=\"keystore_pass\">キーストアのパスワード</string>\n    <string name=\"keystore_file\">キーストアのファイル</string>\n    <string name=\"input_key_password\">キーのパスワード</string>\n    <string name=\"failed_to_initialize_key_store\">App Managerのキーストアを構成できませんでした。</string>\n    <string name=\"generate_key\">生成</string>\n    <string name=\"pref_default_log_level_title\">既定のログレベル</string>\n    <string name=\"pref_cat_configuration\">構成</string>\n    <string name=\"pref_cat_appearance\">外観</string>\n    <string name=\"pref_cat_advanced\">高度な設定</string>\n    <string name=\"pref_buffer_title\">ログのバッファ</string>\n    <string name=\"open\">開く</string>\n    <string name=\"notification_title\">ログの記録が進行中です</string>\n    <string name=\"notification_ticker\">ログの記録が開始されました</string>\n    <string name=\"notification_subtext\">タップして記録を停止</string>\n    <string name=\"no_saved_logs\">保存済みのログが見つかりませんでした。</string>\n    <string name=\"trackers_unblocked_successfully\">トラッカーのブロックは解除されました</string>\n    <string name=\"manage_saved_logs\">保存したログを削除</string>\n    <string name=\"log_saved\">ログを保存しました。</string>\n    <string name=\"log_recording_started\">ログの記録が開始されました。</string>\n    <string name=\"log_level\">ログレベル</string>\n    <string name=\"log_cleared\">ログを消去しました</string>\n    <string name=\"filter_choice_tag\">タグ</string>\n    <string name=\"filter_choice_pid\">PID</string>\n    <string name=\"filter_choice\">次で検索</string>\n    <string name=\"enter_good_filename\">有効なファイル名を指定してください。</string>\n    <string name=\"enter_filename\">ファイル名を入力</string>\n    <string name=\"dialog_compiling_log\">ログを生成中…</string>\n    <string name=\"delete_saved_log\">保存したログを消去</string>\n    <string name=\"copy_to_clipboard\">クリップボードにコピー</string>\n    <string name=\"add_filter_ellipsis\">フィルタを追加…</string>\n    <string name=\"add_filter\">フィルタを追加</string>\n    <string name=\"log_level_fatal\">Fatal</string>\n    <string name=\"log_level_warn\">Warn</string>\n    <string name=\"log_level_verbose\">Verbose</string>\n    <string name=\"log_level_info\">Info</string>\n    <string name=\"log_level_error\">Error</string>\n    <string name=\"log_level_debug\">Debug</string>\n    <string name=\"filename\">ファイル名</string>\n    <string name=\"pref_log_viewer_msg\">ログの表示方法を設定します</string>\n    <string name=\"log_viewer\">ログビューワ</string>\n    <string name=\"widget_start_recording\">ログを\n\\n記録</string>\n    <string name=\"unable_to_save_log\">ログを保存できませんでした。有効なファイル名を指定していますか？</string>\n    <plurals name=\"toast_log_truncated\">\n        <item quantity=\"other\">ログが大きすぎます。最後の%d行のみ表示されます。</item>\n    </plurals>\n    <string name=\"toast_invalid_selection\">無効な選択です。再試行してください。</string>\n    <string name=\"latest_backup\">最終バックアップ</string>\n    <string name=\"gz_bz2_compressed\">%1$s 圧縮済み</string>\n    <string name=\"pgp_aes_rsa_encrypted\">%1$s 暗号化済み</string>\n    <string name=\"no_encryption\">暗号化しない</string>\n    <string name=\"base_backup\">ベースバックアップ</string>\n    <string name=\"trackers_blocked_successfully\">トラッカーはブロックされました</string>\n    <string name=\"failed_to_unblock_trackers\">トラッカーをブロック解除できませんでした</string>\n    <string name=\"failed_to_block_trackers\">トラッカーをブロックできませんでした</string>\n    <string name=\"profile_save_apk_msg\"><tt>AppManager/apks</tt>内にAPKファイルを保存する</string>\n    <string name=\"save_apk\">APKを保存</string>\n    <string name=\"running_services\">実行中のサービス</string>\n    <string name=\"view_logs\">ログを確認</string>\n    <string name=\"omit_sensitive_info_summary\">URL、電話番号、Eメールなどの機密情報をログから除外します</string>\n    <string name=\"omit_sensitive_info\">機密情報を表示しない</string>\n    <string name=\"undo\">元に戻す</string>\n    <string name=\"toast_invalid_level\">無効なレベル名: %s</string>\n    <string name=\"pref_display_limit_hint\">%1$d〜%2$dの間で有効な数値を指定してください。</string>\n    <string name=\"text_filter_ellipsis\">フィルタ…</string>\n    <string name=\"subject_log_report\">ログレポート</string>\n    <string name=\"send_log_title\">ログを送信</string>\n    <string name=\"save_log\">ログを保存</string>\n    <string name=\"save_as\">保存する…</string>\n    <string name=\"record_log\">ログを記録</string>\n    <string name=\"pref_show_timestamp_title\">PIDとタイムスタンプを表示</string>\n    <string name=\"pref_show_timestamp_summary\">ログの拡張時にプロセスIDとタイムスタンプを表示する</string>\n    <string name=\"pref_log_write_period_title\">自動的に書き込む期間</string>\n    <string name=\"pref_log_write_period_summary\">記録中に%1$d行ごとに自動的に保存します。</string>\n    <string name=\"pref_log_line_period_error\">1から1000の間で整数の値を指定してください。</string>\n    <string name=\"pref_expanded_by_default_title\">標準でログを拡張</string>\n    <string name=\"pref_expanded_by_default_summary\">標準でログテキスト全体を表示</string>\n    <string name=\"pref_filter_pattern_title\">ログ中からタグを除外</string>\n    <string name=\"pref_filter_pattern_summary\">ログ中から正規表現で指定したタグを除外します</string>\n    <string name=\"pref_display_limit_title\">ログ表示数の制限</string>\n    <string name=\"pref_display_limit_summary\">メモリエラーを防ぐため、最後の%1$d件のログのみを表示します。</string>\n    <string name=\"pref_default_log_level_summary\">起動時、ファイルを開くとき、記録するときの既定のログレベルを設定します。</string>\n    <string name=\"restart_log_viewer_to_see_changes\">変更を反映するにはログビューワのウィンドウを再起動してください。</string>\n    <string name=\"text_filter_text\">フィルタテキスト</string>\n    <string name=\"expand_all\">全て展開</string>\n    <string name=\"collapse_all\">すべて折りたたむ</string>\n    <string name=\"pause_unpause\">開始/中断</string>\n    <string name=\"settings\">設定</string>\n    <string name=\"text_include_dmesg\">カーネルログを含める</string>\n    <string name=\"text_include_device_info\">デバイス情報を含める</string>\n    <string name=\"share_log\">共有</string>\n    <string name=\"widget_recording_in_progress\">記録中…</string>\n    <string name=\"start_recording_log\">記録を開始</string>\n    <string name=\"file\">ファイル</string>\n    <string name=\"app_signing_signatures\">アプリ署名</string>\n    <string name=\"failed\">失敗</string>\n    <string name=\"confirm_import_keystore\">既存のキーストアを上書きしてもよろしいですか？この操作はやり直しできません。</string>\n    <string name=\"import_keystore\">キーストアをインポート</string>\n    <string name=\"pref_import_export_keystore_msg\">App Manager内で使用される Bouncy Castle キーストアをインポート/エクスポートします。</string>\n    <string name=\"pref_import_export_keystore\">キーストアをインポート/エクスポート</string>\n    <string name=\"pref_rules_msg\">インスタントブロッキング、ルールのインポート/エクスポート/削除 等の操作を行います</string>\n    <string name=\"saf\">SAF</string>\n    <plurals name=\"file_deletion_confirmation\">\n        <item quantity=\"other\">%d 個のファイルを削除しようとしています</item>\n    </plurals>\n    <string name=\"orientation_right_to_left\">右から左（RTL方向）</string>\n    <string name=\"orientation_left_to_right\">左から右（LTR方向）</string>\n    <string name=\"orientation_follow_locale\">言語設定に従う</string>\n    <string name=\"pref_display_changes_msg\">バージョン、トラッカー、コンポーネント、権限、署名、SDKなどの変更点を表示します。</string>\n    <string name=\"hidden\">隠匿</string>\n    <string name=\"port_number_invalid\">ポート番号が無効です。</string>\n    <string name=\"port_number_empty\">ポート番号が空白です。</string>\n    <string name=\"adb_connect_port_number_description\">ポート番号は<b>デバイス名</b>セクション下部の<b>IPアドレス&amp;ポート</b>内に記載されています。</string>\n    <string name=\"port_number\">ポート番号</string>\n    <string name=\"adb_connect\">接続</string>\n    <string name=\"wireless_debugging\">ワイヤレスデバッグ</string>\n    <string name=\"netpolicy_disable_network_access\">ネット接続を無効化</string>\n    <string name=\"netpolicy_reject_wifi_data\">WiFi通信を拒否</string>\n    <string name=\"netpolicy_reject_vpn_data\">VPN通信を拒否</string>\n    <string name=\"netpolicy_reject_cellular_data\">モバイル通信の利用を拒否</string>\n    <string name=\"netpolicy_allow_background_data\">データーセーバーが有効の場合もバックグラウンドデータを許可</string>\n    <string name=\"netpolicy_reject_background_data\">バックグラウンドデーターを拒否</string>\n    <string name=\"no_changes\">変更なし</string>\n    <string name=\"pref_display_changes\">変更を表示</string>\n    <string name=\"suspended\">休止中</string>\n    <string name=\"help_uses_permissions_tab\">項目をタップして<b>許可</b>または<b>拒否</b>できます。<b>dangerous</b>及び<b>development</b>パーミッションのみ許可/拒否できます。</string>\n    <string name=\"help_permissions_tab\">これらの権限はアプリ内部で定義されており、許可を取り消すことはできません。</string>\n    <string name=\"failed_to_prevent_background_run\">%1$sのバックグラウンド実行を防止できませんでした</string>\n    <string name=\"added_to_queue\">キューに追加されました</string>\n    <string name=\"minimum_version\">最小バージョン:%d</string>\n    <string name=\"help_app_ops_tab\">項目をタップして<b>許可</b>または<b>拒否</b>できます。長押しすることで他の対応するオプションが選択できます。</string>\n    <string name=\"unknown_net_policy\">未知のネットポリシー(%1$s - %2$X)</string>\n    <plurals name=\"alert_failed_to_import_backups\">\n        <item quantity=\"other\">%1$d個のバックアップをインポートできませんでした</item>\n    </plurals>\n    <string name=\"import_from_tb\">Titanium Backupからインポート</string>\n    <string name=\"import_from_oab\">OAndBackupからインポート</string>\n    <string name=\"pref_import_backups_msg\">OAndBackup、Swift Backup (v3.0〜3.2)またはTitanium Backupからバックアップファイルをインポートします</string>\n    <string name=\"pref_import_backups\">バックアップをインポート</string>\n    <string name=\"community_links\">Telegram: https://t.me/AppManagerChannel\n\\nTwitter: https://twitter.com/AppManagerNews</string>\n    <string name=\"community\">コミュニティ</string>\n    <string name=\"error_with_details\">エラー:%s</string>\n    <string name=\"saved_filters\">保存されたフィルタ</string>\n    <string name=\"permission_flags\">権限フラグ</string>\n    <string name=\"pref_selected_users_msg\">App Managerは選択されたユーザーにのみ動作するようになります。</string>\n    <string name=\"pref_selected_users\">ユーザーの選択</string>\n    <string name=\"notice\">通知</string>\n    <string name=\"notice_saf\">選択したディレクトリには、保存されたAPKやバックアップなど、App Managerに関連するすべてのファイルが保存されます。Storage Access Framework（SAF）は非常に低速であるため、他のオプションが使用できない場合にのみこのオプションを使用してください。</string>\n    <string name=\"files\">ファイル</string>\n    <string name=\"storage\">ストレージ</string>\n    <string name=\"paired_successfully\">ペア完了</string>\n    <string name=\"adb_pair\">ペア</string>\n    <string name=\"invalid_password\">無効なパスワードです、再試行してください。</string>\n    <string name=\"keystore_pass_cannot_be_empty\">キーストアのパスワードは空白にすることができません。</string>\n    <string name=\"keystore_password_info\">こちらは、App Managerのキーストアのパスワードです。キーストアのバックアップ/リストアを行う場合は、安全な場所に保管してください。<b>このメッセージは再度表示されません</b></string>\n    <string name=\"failed_to_uninstall_app\">アンインストール失敗</string>\n    <string name=\"second_degree_tracker_note\">接頭辞「²」はトラッカーが<a href=\"https://etip.exodus-privacy.eu.org/\">ETIP 未承認リスト</a> にあることを示しています。つまり実際のトラッカーであるかは調査中で、Exodusの標準リストにはまだ登録されていないということです。</string>\n    <string name=\"backup_volume_dialog_description\">接頭辞が<tt>/tree</tt>のボリュームは、Storage Access Framework（SAF）で選択されたフォルダです。これらのフォルダーを除き、App Managerのデフォルトのディレクトリは、<tt>AppManager</tt>という名前のサブフォルダーになります。</string>\n    <string name=\"set_package_name_first\">最初にパッケージ名を指定してください！</string>\n    <string name=\"paste\">貼り付け</string>\n    <string name=\"user_root\">Root権限を使用</string>\n    <string name=\"trim_caches_in_all_apps\">全アプリのキャッシュをクリア</string>\n    <string name=\"trim_caches_in_all_apps_description\">Androidシステム自体を含む全てのキャッシュファイルを削除します</string>\n    <string name=\"background\">バックグラウンド</string>\n    <string name=\"installer_app_installed\">アプリはインストールされました</string>\n    <string name=\"next\">次へ</string>\n    <string name=\"pref_block_trackers_msg\">App Managerでアプリをインストールした後、自動的にトラッカーコンポーネントをブロックします。</string>\n    <string name=\"pref_always_on_background\">バックグラウンドでインストールする</string>\n    <string name=\"pref_always_on_background_msg\">常にバックグラウンドでアプリをインストールし、完了時に通知を行うようにします。</string>\n    <string name=\"type_uri_array\">URLの配列</string>\n    <string name=\"type_uri_array_list\">URLのリスト</string>\n    <string name=\"pref_thread_count\">並列処理</string>\n    <string name=\"pref_thread_count_hint\">値は0から%1$dまでで指定してください。<i>0に設定すると常に最高まで並列処理されます。</i></string>\n    <plurals name=\"pref_thread_count_msg\">\n        <item quantity=\"other\">最大%1$dプロセスまで並列実行します</item>\n    </plurals>\n    <string name=\"pid\">プロセスID</string>\n    <string name=\"identifier\">識別子</string>\n    <string name=\"staging_apk_files\">待機中…</string>\n    <string name=\"running_services_logcat_hint\">項目をタップすると、対応するプロセスIDをデフォルトのフィルターとしてログビューアーが開きます。</string>\n    <string name=\"pref_import_backups_hint\">バックアップファイル（Swift Backup/Titanium Backup）またはディレクトリ（OAndBackup）を選択します</string>\n    <string name=\"import_from_sb\">Swift Backup(v3.0〜3.2) からインポート</string>\n    <string name=\"rename\">名前を変更</string>\n    <string name=\"java\">Java</string>\n    <string name=\"smali\">Smali</string>\n    <string name=\"accessibility_service_description\">非ルートモードでキャッシュをクリアするなどの操作を行うためのアクセシビリティサービスです。</string>\n    <string name=\"explore\">エクスプローラ</string>\n    <string name=\"extract\">展開</string>\n    <string name=\"replace\">置き換え</string>\n    <string name=\"system_partition\">Androidルート</string>\n    <string name=\"intent_firewall_and_disable\">IFW + 無効化</string>\n    <string name=\"intent_firewall\">IFW</string>\n    <string name=\"pref_intent_firewall_and_disable_description\">コンポーネントをインテントファイアウォールを使用してブロックすると同時に、無効化します。Rootユーザーにお勧めの方法です。</string>\n    <string name=\"pref_intent_firewall_description\">インテントファイアウォールのみを使用してコンポーネントをブロックします。システムアプリの中にはこれを回避するものがあるため、推奨しません。</string>\n    <string name=\"pref_disable_description\">コンポーネントを無効化のみ行います。アプリはこれを回避できるため、Rootユーザーにはお勧めしません。ADBモードでは、テスト用アプリをこの方式で無効にすることができます。</string>\n    <string name=\"authenticating\">認証中…</string>\n    <string name=\"search_type_prefix\">接頭辞</string>\n    <string name=\"search_type_suffix\">接尾辞</string>\n    <string name=\"search_type_regular_expressions\">正規表現</string>\n    <string name=\"search_type_contains\">通常</string>\n    <string name=\"exit_confirmation\">終了の確認</string>\n    <string name=\"pref_default_blocking_method\">規定のブロッキング方法</string>\n    <string name=\"pref_default_blocking_method_description\">コンポーネントのブロッキングに規定で利用される方法を指定します。</string>\n    <string name=\"vt_uploading\">VirusTotal: アップロード中…</string>\n    <string name=\"vt_queued\">VirusTotal: キューに追加済み</string>\n    <string name=\"vt_success\">VirusTotal: %1$d/%2$d</string>\n    <string name=\"vt_scan_date\">スキャン日時: %1$s</string>\n    <string name=\"vt_permalink\">VirusTotalへのリンク</string>\n    <string name=\"pref_vt_apikey_summary\">VirusTotalによるAPKのスキャンを有効にします。</string>\n    <string name=\"uses_play_app_signing\">Playアプリ署名</string>\n    <string name=\"parent_process_id\">親プロセスID</string>\n    <string name=\"swap\">スワップ</string>\n    <string name=\"swap_chart_info\">● %1$s 使用済み ● %2$s 利用可能</string>\n    <string name=\"failed_to_change_app_op_mode\">AppOpsモードを変更できませんでした。</string>\n    <string name=\"failed_to_disable_magisk_deny_list\">Magisk DenyListを無効化できませんでした</string>\n    <string name=\"mode_of_op_with_inferred_mode_of_op\">%1$s (現在のモード: %2$s)</string>\n    <plurals name=\"usage_seconds\">\n        <item quantity=\"other\">%1$d 秒</item>\n    </plurals>\n    <string name=\"vt_failed\">VirusTotal: 失敗</string>\n    <string name=\"vt_slowness_warning\">インターネットの速度やサーバーの処理に速度は依存します。これには少し時間がかかります。</string>\n    <plurals name=\"usage_minutes\">\n        <item quantity=\"other\">%1$d 分</item>\n    </plurals>\n    <string name=\"toggle_internet\">インターネット接続の使用</string>\n    <string name=\"vt_checking\">VirusTotal: スキャン中…</string>\n    <string name=\"pref_vt_apikey\">VirusTotal APIキー</string>\n    <string name=\"scan_in_vt\">VirusTotalでスキャン</string>\n    <string name=\"process_id\">プロセスID</string>\n    <string name=\"virtual_memory\">仮想メモリ</string>\n    <string name=\"cpu_percent\">%% CPU</string>\n    <string name=\"cpu_time\">CPU時間</string>\n    <string name=\"priority\">優先度</string>\n    <string name=\"state\">プロセスの状態</string>\n    <string name=\"threads\">スレッド数</string>\n    <string name=\"commandline_args\">コマンド引数</string>\n    <string name=\"memory_chart_info\">● %1$s アプリケーション ● %2$s キャッシュ ● %3$s バッファ ● %4$s 利用可能</string>\n    <string name=\"magisk_denylist\">Magisk DenyList</string>\n    <string name=\"failed_to_enable_magisk_deny_list\">Magisk DenyListを有効化できませんでした</string>\n    <string name=\"vt_disclaimer\">VirusTotalおよびそのロゴは、Chronicle LLCの商標です。APIクライアントであるApp Managerおよびその作成者は、あなたがVirusTotalに送信するいかなるデータについても責任を負いません。</string>\n    <string name=\"warning_working_on_root_mode\">警告: ADBモードではなくRootモードにて動作しています。</string>\n    <string name=\"pref_vt_apikey_description\">APIキーは、App ManagerがAPKファイルをVirusTotalにアップロードし、レポートを取得するために必要です。https://virustotal.com にサインアップして、無料でAPI キーを取得できます。</string>\n    <string name=\"uses_play_app_signing_description\">このアプリには<a href=\"https://support.google.com/googleplay/android-developer/answer/9842756\">Playアプリ署名</a>を使用している<i>可能性</i>のある識別子があります。この方式では、署名鍵はGoogleのサーバーに保管され、Googleがアプリへの署名に責任を持ちます。なお、署名情報の照合は、アプリが開発者以外（この場合はGoogleも）によって変更されていないことを確認する唯一の方法です。</string>\n    <string name=\"failed_to_use_the_current_mode_of_operation\">現在の動作モードを使用できません。このセッションでは非Rootモードに切り替えられます。</string>\n    <string name=\"hidden_api_enf_default_policy\">規定（アプリケーションタイプに基づく）</string>\n    <string name=\"hidden_api_enf_policy_warn\">警告 (Hidden APIにフルアクセスできるが、警告を発します)</string>\n    <string name=\"binary_32_bit\">32 Bit</string>\n    <string name=\"binary_64_bit\">64 Bit</string>\n    <string name=\"endianness_little_endian\">リトルエンディアン</string>\n    <string name=\"so_type_shared_library\">共有ライブラリ</string>\n    <string name=\"save_and_exit\">保存して終了</string>\n    <string name=\"zygote_preload_name\">Zygoteプリロード名</string>\n    <string name=\"hidden_api_enforcement_policy\">Hidden API 適用ポリシー</string>\n    <string name=\"so_type_executable\">実行可能</string>\n    <string name=\"hidden_api_enf_policy_none\">なし（Hidden APIにフルアクセス可能）</string>\n    <string name=\"hidden_api_enf_policy_black\">Enforce (ブラックリストのみ)</string>\n    <string name=\"file_modified_are_you_sure\">このファイルは編集されています。すべての変更を破棄して終了しますか？</string>\n    <string name=\"primary_abi\">プライマリABI</string>\n    <string name=\"hidden_api_enf_policy_dark_grey_and_black\">Enforce (ダークグレー/ブラックリスト)</string>\n    <string name=\"endianness_big_endian\">ビッグエンディアン</string>\n    <string name=\"pref_saved_apk_name_format\">保存するAPKのファイル名</string>\n    <string name=\"pref_saved_apk_name_format_msg\">APKファイルを保存する際のファイル名形式を指定します。</string>\n    <string name=\"auth_manager_title\">認証マネージャ</string>\n    <string name=\"regenerate_auth_key\">認証キーを再生成</string>\n    <string name=\"regenerate_auth_key_warning\">すべての外部アプリは、新しい認証キーで再設定する必要があります。本当に宜しいですか？</string>\n    <string name=\"shortcut_icon\">ショートカットアイコン</string>\n    <string name=\"auth_manager_description\">外部アプリからインテントによって起動するには、<tt>auth</tt>というフィールドを追加する必要があり、それには次のキーが含まれていなければなりません:</string>\n    <string name=\"sort_by_installation_date\">インストール日時</string>\n    <string name=\"netpolicy_cannot_be_modified_for_core_apps\">ネットポリシーは、Androidコアアプリでは変更できません。</string>\n</resources>"
  },
  {
    "path": "app/src/main/res/values-ko/disclaimer.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- SPDX-License-Identifier: GPL-3.0-or-later --><resources>\n    <string name=\"disclaimer_header\">면책 조항</string>\n    <string name=\"disclaimer_footer\">© 2020–2024 Muntashir Al-Islam</string>\n    <string name=\"disclaimer_agree_forever\">다시 표시하지 않음</string>\n    <string name=\"disclaimer_exit\">종료</string>\n    <string name=\"disclaimer_agree\">동의합니다</string>\n    <string name=\"disclaimer_body\">앱 관리자는 잘못 사용하면 기기에 손상을 줄 수 있는 루트 기능을 제공합니다. 앱 관리자는 이 응용프로그램을 사용하여 발생한 모든 손해에 대해 책임을 지지 않습니다. 루트가 작동하는 방식을 완전히 알지 못하는 경우 위험을 완전히 인식할 때까지 루트 옵션을 사용하지 않아야 합니다.\n\\n\n\\n내가 다른 앱과 웹사이트에 제공하는 모든 링크는 사용자를 위한 것입니다. 외부 링크로 이동하여 찾을 수 있는 콘텐츠에 대해 책임을 지지 않습니다.\n\\n\n\\n앱 관리자를 사용함으로써 귀하는 자신의 사용에 대한 전적인 책임을 져야 하며 오용으로 인한 손해, 청구 또는 금전적 가치가 제공되지 않음을 수락합니다.\n\\n\n\\n이 응용프로그램을 사용함으로써 귀하는 이 응용프로그램을 사용하는 모든 책임을 수락하고 귀하의 장치에 부정적인 영향을 미치는 모든 행동에 대해 제가 책임을 지지 않는다는 데 동의하는 것입니다.</string>\n</resources>"
  },
  {
    "path": "app/src/main/res/values-ko/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- SPDX-License-Identifier: GPL-3.0-or-later --><resources xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:tools=\"http://schemas.android.com/tools\">\n    <string name=\"_lang_tag\" translatable=\"false\">ko</string>\n    <string name=\"uses_feature\">기능 사용</string>\n    <string name=\"group\">그룹</string>\n    <string name=\"shared_libs\">공유된 라이브러리</string>\n    <string name=\"declared_permission\">권한</string>\n    <string name=\"patterns_allowed\">패턴 허용됨</string>\n    <string name=\"write\">쓰기</string>\n    <string name=\"read\">읽기</string>\n    <string name=\"path_permissions\">경로 권한</string>\n    <string name=\"grant_uri_permission\">URI 권한 부여</string>\n    <string name=\"flags\">플래그</string>\n    <string name=\"soft_input\">소프트 입력 모드</string>\n    <string name=\"orientation\">취향</string>\n    <string name=\"no_service\">서비스 없음</string>\n    <string name=\"service\">서비스</string>\n    <string name=\"sort_by_last_update\">마지막 업데이트</string>\n    <string name=\"launch_mode\">실행 모드</string>\n    <string name=\"no_providers\">제공자 없음</string>\n    <string name=\"providers\">제공자</string>\n    <string name=\"no_receivers\">수신자 없음</string>\n    <string name=\"receivers\">수신자</string>\n    <string name=\"no_activities\">활동 없음</string>\n    <string name=\"refresh\">새로 고침</string>\n    <string name=\"launch\">실행</string>\n    <string name=\"activities\">액티비티</string>\n    <string name=\"require_no_permission\">권한이 필요하지 않음</string>\n    <string name=\"permissions\">사용 권한</string>\n    <string name=\"uninstall\">삭제</string>\n    <string name=\"authority\">권한</string>\n    <string name=\"sort_by_package_name\">패키지 이름</string>\n    <string name=\"sort_by_app_label\">앱 레이블</string>\n    <string name=\"loading\">불러오는 중…</string>\n    <string name=\"error\">오류</string>\n    <string name=\"manifest\">나타내기</string>\n    <string name=\"input_features\">기능 입력</string>\n    <string name=\"configurations\">구성</string>\n    <string name=\"no_feature\">기능 없음</string>\n    <string name=\"shared_user_id\">공유된 사용자 ID</string>\n    <string name=\"sort_by_shared_user_id\">공유된 사용자 ID</string>\n    <string name=\"task_affinity\">작업 선호도</string>\n    <string name=\"no_configurations\">구성 없음</string>\n    <string name=\"app_signing_no_signatures\">유효한 서명 없음</string>\n    <string name=\"app_signing_signatures\">서명</string>\n    <string name=\"signatures\">서명</string>\n    <string name=\"sort_by_sha\">서명</string>\n    <string name=\"data_usage_msg\">데이터 사용량</string>\n    <string name=\"about\">정보</string>\n    <string name=\"sort_by_domain\">사용자 앱 우선</string>\n    <string name=\"sort_by_target_sdk\">대상 SDK</string>\n    <string name=\"data_received\">수신된 데이터</string>\n    <string name=\"data_transmitted\">전송된 데이터</string>\n    <string name=\"data_size\">데이터</string>\n    <string name=\"cache_size\">캐시</string>\n    <string name=\"system\">시스템</string>\n    <string name=\"user\">사용자</string>\n    <string name=\"sort\">정렬</string>\n    <string name=\"media_size\">미디어</string>\n    <string name=\"app_not_installed\">앱 설치되지 않음</string>\n    <string name=\"obb_size\">Obb</string>\n    <plurals name=\"usage_minutes\">\n        <item quantity=\"other\">%1$d분</item>\n    </plurals>\n    <plurals name=\"usage_seconds\">\n        <item quantity=\"other\">%1$d초</item>\n    </plurals>\n    <string name=\"no_usage_in_this_time_range\">이 시간 범위 내 사용량 없음</string>\n    <string name=\"error_verbose_pin_shortcut\">현재 홈 화면은 핀바로가기를 지원하지 않습니다. 바로가기를 만들 수 없습니다.</string>\n    <string name=\"create_shortcut\">바로가기 만들기</string>\n    <string name=\"shortcut_name\">바로가기 이름</string>\n    <string name=\"word_wrap\">단어 줄 바꿈 전환</string>\n    <string name=\"toggle_class_listing\">클래스 목록 전환</string>\n    <string name=\"no_shared_libs\">공유된 라이브러리 없음</string>\n    <string name=\"usage_yesterday\">어제</string>\n    <string name=\"version_name_with_code\">버전 <xliff:g id=\"version_name\" example=\"2.5.17\">%1$s</xliff:g> (<xliff:g id=\"version_code\" example=\"365\">%2$d</xliff:g>)</string>\n    <string name=\"system_app\">시스템 앱</string>\n    <string name=\"user_app\">사용자 앱</string>\n    <string name=\"paths_and_directories\">경로 및 디렉터리</string>\n    <string name=\"source_dir\">원본 디렉터리</string>\n    <string name=\"data_dir\">데이터 디렉터리</string>\n    <string name=\"sdk_max\">대상 SDK 버전</string>\n    <string name=\"more_info\">더보기</string>\n    <string name=\"date_installed\">설치된 날짜</string>\n    <string name=\"date_updated\">업데이트된 날짜</string>\n    <string name=\"installer_app\">설치 프로그램</string>\n    <string name=\"user_id\">사용자 ID</string>\n    <string name=\"main_activity\">기본 액티비티</string>\n    <string name=\"sdk_flags\">플래그</string>\n    <string name=\"empty_package_name\">빈 패키지 이름</string>\n    <string name=\"error_creating_shortcut\">바로가기 생성 중 오류</string>\n    <string name=\"package_name\">패키지 이름</string>\n    <string name=\"class_name\">클래스 이름</string>\n    <string name=\"icon_picker\">아이콘 선택기</string>\n    <string name=\"license\">라이선스</string>\n    <string name=\"tracker_details\">추적기 세부정보</string>\n    <string name=\"tracker_classes\">추적기 클래스</string>\n    <string name=\"all_classes\">모든 클래스</string>\n    <plurals name=\"main_list_date_days\">\n        <item quantity=\"other\"><xliff:g id=\"last_update_date\" example=\"20/10/2020\">%1$s</xliff:g> <xliff:g id=\"day_no\" example=\"5\">%2$d</xliff:g>일</item>\n    </plurals>\n    <string name=\"go\">이동</string>\n    <string name=\"no_tracker_class\">추적기 클래스 없음</string>\n    <string name=\"app_usage\">앱 사용량</string>\n    <string name=\"usage_today\">오늘</string>\n    <string name=\"usage_7_days\">최근 7일</string>\n    <plurals name=\"usage_months\">\n        <item quantity=\"other\">%1$d개월</item>\n    </plurals>\n    <plurals name=\"usage_days\">\n        <item quantity=\"other\">%1$d일</item>\n    </plurals>\n    <plurals name=\"usage_hours\">\n        <item quantity=\"other\">%1$d시간</item>\n    </plurals>\n    <string name=\"usage_less_than_a_minute\">1분 미만</string>\n    <string name=\"go_back\">뒤로 이동</string>\n    <string name=\"grant_usage_access\">사용량 접근권한 부여</string>\n    <string name=\"sort_by_memory_usage\">메모리 사용량</string>\n    <string name=\"pref_backup_flags_msg\">백업 옵션에 대한 프리셋을 추가하면 백업/복원할 때마다 플래그를 선택해야 하는 부담이 제거됩니다.</string>\n    <string name=\"credits\">크레딧</string>\n    <string name=\"found_trackers\">발견된 추적기:</string>\n    <string name=\"backup_extras_description\">앱 권한, 배터리 절약 및 데이터 사용량 옵션, MagiskHide 상태, SSAID 등을 백업하기.\n\\n<font fgcolor=\"#ff0000\">권한에 따라 일부 옵션은 복원되지 않을 수 있습니다.</font> </string>\n    <string name=\"permission_flags\">권한 플래그</string>\n    <string name=\"clear_data_from_uninstalled_apps_description\"><tt>DONT_DELETE_DATA</tt> 플래그로 제거된 앱에서 데이터 삭제</string>\n    <string name=\"usage_access_not_supported\">해당 설정 페이지가 존재하지 않아 사용량 접근권한을 요청할 수 없습니다.</string>\n    <string name=\"starting_activity\">다음 액티비티를 시작하는 중: <xliff:g id=\"activity_name\" example=\".main.MainActivity\">%1$s</xliff:g></string>\n    <string name=\"third_party\">서드 파티 라이브러리 및 아이콘</string>\n    <plurals name=\"tracker_and_classes\">\n        <item quantity=\"other\"><xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g> 클래스가 있는 추적기 1개</item>\n    </plurals>\n    <string name=\"credits_message\">다음 제작자들에게 \\n- 안드로이드 오픈 소스 프로젝트 (AOSP) \\n- <a href=\"https://github.com/zhaobozhen/libraries\">Absinthe\\'s libraries</a> \\n- <a href=\"https://github.com/butzist/ActivityLauncher\">Activity Launcher</a> \\n- <a href=\"https://bitbucket.org/oF2pks/fdroid-applications-info\">Apps_packages Info</a> \\n- <a href=\"https://github.com/zhaobao/AppsMonitor\">AppsMonitor</a> \\n- <a href=\"https://github.com/8enet/AppOpsX\">AppOpsX</a> \\n- <a href=\"https://github.com/gabrielemariotti/changeloglib\">ChangeLog Library</a> \\n- <a href=\"https://bitbucket.org/oF2pks/fdroid-classyshark3xodus\">ClassySharkAndroid</a> \\n- <a href=\"https://github.com/billthefarmer/editor\">Editor</a> \\n- <a href=\"https://github.com/Raival-e/File-Explorer\">File Explorer</a> \\n- <a href=\"https://github.com/nex3z/FlowLayout\">FlowLayout</a> \\n- <a href=\"https://github.com/k3b/intent-intercept\">Intent Intercept</a> \\n- <a href=\"https://github.com/YarikSOffice/lingver\">Lingver</a> \\n- <a href=\"https://github.com/topjohnwu/Magisk\">Magisk</a> \\n- <a href=\"https://github.com/zhanghai/MaterialFiles\">Material Files</a> \\n- <a href=\"https://github.com/pluscubed/matlog\">MatLog</a> \\n- <a href=\"https://github.com/matrix-org/matrix-android-sdk\">Matrix Android SDK</a> \\n- <a href=\"https://github.com/jensstein/oandbackup\">OAndBackup</a> \\n- <a href=\"https://github.com/open-keychain/open-keychain\">Open Keychain</a> \\n- <a href=\"https://github.com/Aefyr/SAI\">SAI</a> \\n- <a href=\"https://github.com/RikkaApps/Shizuku\">Shizuku</a> \\n- <a href=\"https://github.com/eclipse/tm4e\">tm4e</a> \\n- <a href=\"https://github.com/tuyafeng/Watt\">Watt</a></string>\n    <string name=\"class_viewer\">클래스 뷰어</string>\n    <plurals name=\"two_trackers_and_classes\">\n        <item quantity=\"other\"><xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g> 클래스가 있는 추적기 2개</item>\n    </plurals>\n    <plurals name=\"other_trackers_and_classes\">\n        <item quantity=\"other\"><xliff:g id=\"class_no\" example=\"50\">%2$d</xliff:g> 클래스가 있는 <xliff:g id=\"tracker_no\" example=\"8\">%1$d</xliff:g>개 추적기</item>\n    </plurals>\n    <string name=\"grant_usage_acess_message\">앱 사용량 정보를 표시하는 데 사용됩니다.</string>\n    <string name=\"usage_weekly\">매주</string>\n    <string name=\"usage_access\">사용량 접근 권한</string>\n    <string name=\"app_info\">앱 정보</string>\n    <string name=\"uninstall_app_message\">앱을 삭제하시겠습니까\\?</string>\n    <string name=\"failed_to_extract_apk_file\">APK 파일을 추출할 수 없습니다</string>\n    <string name=\"share_apk\">APK 공유</string>\n    <string name=\"saving_failed\">저장 실패, 다시 시도해보기.</string>\n    <string name=\"string_value\">문자열 값</string>\n    <string name=\"native_library_dir\">기본 JNI 라이브러리 저장소</string>\n    <string name=\"no_code\">코드 없음</string>\n    <string name=\"databases\">데이터 베이스</string>\n    <string name=\"integer_value\">정수 값</string>\n    <string name=\"type_string\">캐릭터</string>\n    <string name=\"no_content\">연결할 수 없음</string>\n    <string name=\"rules_not_applied\">규칙이 적용되지 않음</string>\n    <string name=\"dev_protected_data_dir\">장치-보호된 데이터 저장소</string>\n    <string name=\"process_name\">프로세스 이름</string>\n    <string name=\"save\">저장</string>\n    <string name=\"saved_successfully\">저장하기</string>\n    <string name=\"failed_to_disable_op\">요청한 작업을 비활성화 할 수 없습니다</string>\n    <string name=\"str_logo\">로고</string>\n    <string name=\"sdk_min\">최소 SDK 버전</string>\n    <string name=\"menu_remove_rules\">규칙 삭제</string>\n    <string name=\"menu_apply_rules\">규칙 적용</string>\n    <string name=\"search\">검색</string>\n    <string name=\"updated_app\">업데이트</string>\n    <string name=\"debuggable\">디버깅 활성화</string>\n    <string name=\"test_only\">테스트 전용</string>\n    <string name=\"shared_prefs\">공유 설정</string>\n    <string name=\"deleted_successfully\">삭제</string>\n    <string name=\"deletion_failed\">삭제 실패</string>\n    <string name=\"long_integer_value\">긴 정수 값</string>\n    <string name=\"decimal_value\">10진수 값</string>\n    <string name=\"select_type\">타입 선택</string>\n    <string name=\"add_item\">아이템 추가</string>\n    <string name=\"done\">완료</string>\n    <string name=\"disabled_app\">비정상적</string>\n    <string name=\"view_in_settings\">설정 보기</string>\n    <string name=\"failed_to_uninstall\"><xliff:g id=\"app_name\" example=\"앱 관리자\">%1$s</xliff:g> 를 제거할 수 없습니다.</string>\n    <string name=\"uninstall_system_app_message\">시스템에서 사용되는 앱입니다. 정말 제거 하시겠습니까\\?</string>\n    <string name=\"stopped\">중지됨</string>\n    <string name=\"disable\">비활성화</string>\n    <string name=\"enable\">활성화</string>\n    <string name=\"force_stop\">강제 중지</string>\n    <string name=\"app_size\">앱</string>\n    <string name=\"app_ops\">앱 설정</string>\n    <string name=\"no_app_ops\">앱에 작업이 없음</string>\n    <string name=\"failed_to_uninstall_app\">제거를 실패</string>\n    <string name=\"total_size\">전체 앱 크기</string>\n    <string name=\"storage_and_cache\">저장공간과 캐시</string>\n    <string name=\"failed_to_enable_op\">요청한 작업을 활성화 할 수 없음</string>\n    <string name=\"pref_global_blocking_enabled\">구성요소 차단</string>\n    <string name=\"discard\">사용하지 않음</string>\n    <string name=\"delete\">삭제</string>\n    <string name=\"boolean_value\">참, 거짓 볼륨</string>\n    <string name=\"type_boolean\">참/거짓</string>\n    <string name=\"type_int\">정수</string>\n    <string name=\"error_evaluating_input\">입력을 확인할 수 없음</string>\n    <string name=\"key_name_cannot_be_null\">키 열쇠를 채워야 합니다</string>\n    <string name=\"key_name\">열쇠 이름</string>\n    <string name=\"type_float\">10 진수</string>\n    <string name=\"type_long\">롱 타입 정수</string>\n    <string name=\"sort_by_last_used\">마지막 사용</string>\n    <string name=\"app_settings\">설정</string>\n    <string name=\"pref_import_export_blocking_rules\">차단 규칙 불러오기/내보내기</string>\n    <string name=\"running_apps\">실행 중인 앱</string>\n    <string name=\"sort_by_times_opened\">열린 횟수</string>\n    <string name=\"the_import_was_successful\">불러오기 성공</string>\n    <string name=\"the_export_was_successful\">내보내기 성공</string>\n    <string name=\"external_data_dir\">외부 데이터 디렉터리</string>\n    <string name=\"uninstalled_successfully\"><xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g>가 성공적으로 제거되었습니다.</string>\n    <string name=\"pid_and_ppid\">프로세스 ID: %1$d, 상위 프로세스 ID: %2$d</string>\n    <string name=\"pref_import_export_blocking_rules_msg\">규칙 가져오기/내보내기, Watt 또는 Blocker에서 외부 규칙 가져오기.</string>\n    <plurals name=\"failed_to_import_files\">\n        <item quantity=\"other\">%1$d 파일들을 가져올 수 없습니다.</item>\n    </plurals>\n    <string name=\"sort_by_blocked_components\">우선 차단</string>\n    <string name=\"exodus_link\">εxodus 링크</string>\n    <plurals name=\"no_of_times_opened\">\n        <item quantity=\"other\">%1$d 번</item>\n    </plurals>\n    <string name=\"sort_by_mobile_data\">모바일 데이터 사용량</string>\n    <string name=\"kill_process\">종료</string>\n    <string name=\"second_degree_tracker_note\">² 접두사는 트래커들이 <a href=\"https://etip.exodus-privacy.eu.org/\">대기자 명단</a> 에 있음을 나타냅니다. 즉, 실제로 여전히 조사 중인 트래커들인지 여부를 확인합니다.</string>\n    <string name=\"pref_global_blocking_enabled_msg\">앱에 대한 차단을 명시적으로 설정하지 않고 앱의 구성 요소를 차단할 수 있도록 합니다.</string>\n    <string name=\"pref_import_watt\">Watt에서 가져오기</string>\n    <string name=\"pref_import_blocker\">Blocker에서 가져오기</string>\n    <string name=\"sort_by_screen_time\">상영 시간</string>\n    <string name=\"apk_updater\">APK Updater</string>\n    <string name=\"memory_virtual_memory\">메모: %1$s, 가상 메모리: %2$s</string>\n    <string name=\"external_multiple_data_dir\">외부 데이터 디렉토리 <xliff:g id=\"dir_no\" example=\"1\">%1$d</xliff:g></string>\n    <string name=\"disable_background_run\">백그라운드 작업 방지</string>\n    <string name=\"filter\">필터링하기</string>\n    <string name=\"sort_by_dangerous_permissions\">위험 우선</string>\n    <string name=\"sort_by_app_ops_values\">앱 권한 값</string>\n    <string name=\"sort_by_permission_names\">권한 이름</string>\n    <string name=\"sort_by_tracker_components\">트래커 우선</string>\n    <string name=\"unknown_op\">알 수 없는 작업</string>\n    <string name=\"failed_to_deny_dangerous_app_ops\">모든 위험한 앱들 권한 박탈 실패</string>\n    <string name=\"launch_app\">실행</string>\n    <string name=\"external_apk_no_app_op\">외부 APK는 앱 작업이 없습니다</string>\n    <string name=\"never_ask\">다시 물어보지 않기</string>\n    <string name=\"one_click_ops\">원클릭 권한</string>\n    <string name=\"changelog\">변경 로그</string>\n    <string name=\"installed_version\">설치된 버전</string>\n    <string name=\"trackers\">트래커</string>\n    <string name=\"features\">기능</string>\n    <string name=\"whats_new\">새소식</string>\n    <plurals name=\"backup_exists_are_you_sure\">\n        <item quantity=\"other\">하나 이상의 앱이 이미 백업을 갖고 있습니다. 진행 하시겠습니까\\?</item>\n    </plurals>\n    <string name=\"block_unblock_trackers\">트래커 차단/차단 해제</string>\n    <string name=\"export_icon\">아이콘 추출</string>\n    <string name=\"pref_remove_all_rules\">모든 규칙 삭제</string>\n    <string name=\"import_failed\">가져오기 실패!</string>\n    <string name=\"block_trackers\">트래커 차단</string>\n    <plurals name=\"no_of_components\">\n        <item quantity=\"other\">%1$d 구성요소</item>\n    </plurals>\n    <string name=\"clear_app_cache_description\">모든 앱의 캐시를 삭제합니다</string>\n    <plurals name=\"failed_to_backup_some_apk_files\">\n        <item quantity=\"other\">%1$d 앱 백업이 실패했습니다</item>\n    </plurals>\n    <string name=\"installer_error_incompatible\">이 장치는 이 앱과 호환되지 않습니다</string>\n    <string name=\"installer_error_conflict\">패키지 이름이 이미 사용 중이므로 앱을 설치할 수 없습니다</string>\n    <string name=\"reset_to_default\">기본값로 초기화</string>\n    <string name=\"deny_dangerous_app_ops\">위험한 앱 권한 거부</string>\n    <string name=\"failed_to_reset_app_ops\">앱 권한 초기화 실패</string>\n    <string name=\"manifest_viewer\">뷰어 표시</string>\n    <string name=\"install\">설치</string>\n    <string name=\"update\">업데이트</string>\n    <string name=\"input_app_ops_description\">띄어쓰기 포함 앱 권한 이름 그리고/또는 상수값 입력, 예) <tt>WAKE_LOCK 63 72 CAMERA</tt> 등.</string>\n    <string name=\"clear_cache\">캐시 삭제</string>\n    <string name=\"input_signatures\">서명 입력</string>\n    <string name=\"apply\">적용</string>\n    <string name=\"night\">밤</string>\n    <string name=\"sort_by_denied_permissions\">우선 거부</string>\n    <string name=\"internal_data\">내부 데이터</string>\n    <string name=\"ago\">전</string>\n    <plurals name=\"alert_failed_to_disable_background\">\n        <item quantity=\"other\">%1$d 앱 백그라운드 재생 방지 실패</item>\n    </plurals>\n    <string name=\"toggle_kill_for_system_apps\">시스템 종료 앱 전환</string>\n    <string name=\"backup_restore\">백업/복구</string>\n    <string name=\"running\">실행 중</string>\n    <plurals name=\"no_of_trackers\">\n        <item quantity=\"other\">%1$d 트래커</item>\n    </plurals>\n    <string name=\"reject_time\">거절 시간</string>\n    <string name=\"export_options\">내보내기 옵션</string>\n    <string name=\"export_failed\">내보내기 실패!</string>\n    <string name=\"the_operation_was_successful\">완료</string>\n    <string name=\"touchscreen\">터치스크린</string>\n    <string name=\"keyboard_type\">키보드 타입</string>\n    <string name=\"navigation\">탐색</string>\n    <string name=\"pref_export_msg\">앱 매니저 내에서 설정된 차단 규칙을 외부 장치로 내보내기.</string>\n    <string name=\"pref_import_msg\">이전에 앱 매니저에서 내보낸 차단 규칙을 가져오기.</string>\n    <string name=\"pref_import_blocker_msg\">Blocker에서 차단 규칙 가져오기, 각 파일은 단일 패키지에 대한 규칙을 포함한다.</string>\n    <plurals name=\"alert_failed_to_disable_trackers\">\n        <item quantity=\"other\">%1$d 앱에서 트래커 비활성화 실패</item>\n    </plurals>\n    <string name=\"sort_by_denied_app_ops\">우선 거부</string>\n    <string name=\"source_code\">소스 코드</string>\n    <string name=\"community_links\"><a href=\"https://matrix.to/#/#appmanager:matrix.org\">Matrix</a> • <a href=\"https://t.me/AppManagerChannel\">Telegram 채널</a> • <a href=\"https://twitter.com/AppManagerNews\">트위터</a></string>\n    <string name=\"pref_import_existing\">기존 규칙 가져오기</string>\n    <string name=\"block_unblock_trackers_description\">설치된 모든 앱에서 광고 및 트래킹 구성 요소 차단 또는 차단 해제</string>\n    <string name=\"deny_app_ops_description\">다음 상수값으로 식별되는 앱 작업 모드 설정하기, <tt>63</tt> 또는 <tt>RUN_IN_BACKGROUND</tt></string>\n    <string name=\"clear_app_cache\">앱 캐시 삭제</string>\n    <string name=\"no_tracker_found\">트래커가 발견되지 않았습니다</string>\n    <string name=\"community\">커뮤니티</string>\n    <string name=\"clear_data_from_uninstalled_apps\">제거한 앱 데이터 삭제</string>\n    <string name=\"termux\">Termux</string>\n    <string name=\"package_name_is_installed_successfully\"><xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g> 설치 완료</string>\n    <string name=\"filter_apps_with_rules\">규칙있는 앱</string>\n    <string name=\"failed_to_parse_some_numbers\">일부 숫자 파싱 실패</string>\n    <string name=\"filter_system_apps\">시스템 앱</string>\n    <string name=\"blocking_rules\">차단 규칙</string>\n    <string name=\"external_data\">외부 데이터</string>\n    <string name=\"restore\">복구</string>\n    <string name=\"backup_options\">백업 옵션</string>\n    <plurals name=\"alert_failed_to_backup\">\n        <item quantity=\"other\">%1$d 앱 백업이 실패했습니다</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_restore\">\n        <item quantity=\"other\">%1$d 앱 복구 실패했습니다</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_delete_backup\">\n        <item quantity=\"other\">%1$d 백업 삭제 실패했습니다</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_unblock_trackers\">\n        <item quantity=\"other\">%1$d 앱에서 트래커 차단 해제 실패했습니다</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_block_components\">\n        <item quantity=\"other\">%1$d 앱 구성 요소 차단 실패했습니다</item>\n    </plurals>\n    <plurals name=\"missing_signatures\">\n        <item quantity=\"other\">%1$d 서명 누락</item>\n    </plurals>\n    <plurals name=\"app_signing_signature_schemes_pl\">\n        <item quantity=\"other\">서명 방식</item>\n    </plurals>\n    <plurals name=\"verified_with_warning\">\n        <item quantity=\"other\">%d개 경고와 검증</item>\n    </plurals>\n    <string name=\"no\">아니오</string>\n    <string name=\"pref_remove_all_rules_msg\">권한이 부여되고, 앱 권한과 구성 요소는 기본값으로 초기화 됩니다.</string>\n    <string name=\"are_you_sure\">확실하십니까\\?</string>\n    <string name=\"installer_error_aborted\">설치가 취소되었거나 세션이 예기치 않게 닫혀서 설치에 실패했습니다</string>\n    <string name=\"installer_error_blocked\"><xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g>에 의해 설치 차단</string>\n    <string name=\"installer_error_blocked_device\">장치</string>\n    <string name=\"installer_error_bad_apks\">유효하지 않은 APK 파일이 선택 되었습니다</string>\n    <plurals name=\"alert_failed_to_set_app_ops\">\n        <item quantity=\"other\">%1$d 앱 권한 설정에 실패했습니다</item>\n    </plurals>\n    <string name=\"pref_about_msg\">앱 매니저 버전, 라이선스, 크레딧, 등.</string>\n    <string name=\"follow_system\">시스템 따르기</string>\n    <string name=\"select_theme\">테마</string>\n    <string name=\"apply_to_system_apps_question\">시스템 앱에도 적용하시겠습니까\\? 불확실한 경우 \\'아니오\\'를 선택하십시오.</string>\n    <string name=\"clear_data_message\">이 앱에서 데이터를 삭제하시겠습니까\\?</string>\n    <string name=\"clear\">삭제</string>\n    <string name=\"apply_to_system_apps\">시스템 앱에 적용</string>\n    <string name=\"pref_export\">내보내기</string>\n    <string name=\"failed_to_stop\"><xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g>를 정지할 수 없습니다.</string>\n    <string name=\"unblock\">차단 해제</string>\n    <string name=\"failed_to_revoke_permission\">권한 박탈 실패</string>\n    <string name=\"pref_import_watt_msg\">Watt에서 차단 규칙 가져오기, 각 파일은 이름이 지정된 단일 패키지 <tt>packagename.xml</tt> 등에 대한 규칙을 포함한다.</string>\n    <string name=\"pref_import_existing_msg\">다른 이들의 앱에서 비활성화 된 구성요소를 앱 매니저에 추가합니다. 이 기능 사용시 거짓 긍정이 많이 발생할 수 있으므로 주의하십시오. 확실한 앱만 선택하십시오.</string>\n    <string name=\"import_options\">가져오기 옵션</string>\n    <string name=\"website\">웹사이트</string>\n    <string name=\"pref_app_theme\">앱 테마</string>\n    <string name=\"failed_to_deny_dangerous_perms\">모든 위험한 권한 박탈 실패</string>\n    <string name=\"open_in_termux\">Termux에서 열기</string>\n    <string name=\"clear_data\">데이터 삭제</string>\n    <string name=\"sort_by_component_name\">구성요소 이름</string>\n    <string name=\"skip_signature_checks\">서명 검증 건너뛰기</string>\n    <string name=\"toggle_default_app_ops\">기본 앱 권한 설정</string>\n    <string name=\"deny_dangerous_permissions\">위험한 권한 거부</string>\n    <string name=\"input_app_ops\">앱 권한 입력</string>\n    <string name=\"input_app_ops_description_profile\">띄어쓰기 포함 앱 권한 이름 그리고/또는 상수값 입력, 예) <tt>WAKE_LOCK 63 72 CAMERA</tt> 등. 설정된 모든 앱에 적용하기 위해서는 <tt>*</tt> 를 사용하십시오.</string>\n    <string name=\"version\">버전</string>\n    <string name=\"delete_backup\">백업 삭제</string>\n    <string name=\"no_matching_package_found\">해당 앱을 찾을 수 없습니다</string>\n    <string name=\"backup\">백업</string>\n    <string name=\"block\">차단</string>\n    <string name=\"sort_by_app_ops_names\">앱 권한 이름</string>\n    <string name=\"filter_user_apps\">사용자 앱</string>\n    <string name=\"run_in_termux\">Termux에서 실행</string>\n    <string name=\"sort_by_wifi_data\">와이파이 데이터</string>\n    <string name=\"failed_packages\">실패한 패키지</string>\n    <plurals name=\"alert_failed_to_clear_data\">\n        <item quantity=\"other\">%1$d 앱에서 데이터 삭제 실패</item>\n    </plurals>\n    <string name=\"data\">데이터</string>\n    <plurals name=\"alert_failed_to_uninstall\">\n        <item quantity=\"other\">%1$d 앱 제거 실패</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_force_stop\">\n        <item quantity=\"other\">%1$d 앱 강제 종료 실패</item>\n    </plurals>\n    <string name=\"failed_to_grant_permission\">권한 부여 실패</string>\n    <string name=\"day\">낮</string>\n    <string name=\"input_signatures_description\">띄어쓰기 포함 서명 입력, 예) <tt>com.facebook org.app2 com.app3</tt> 등.</string>\n    <string name=\"only_works_in_root_or_adb_mode\">루트 또는 ADB 모드에서만 작동합니다</string>\n    <string name=\"pref_import\">가져오기</string>\n    <string name=\"disable_background\">백그라운드 작업 방지</string>\n    <string name=\"select_all\">전체 선택</string>\n    <string name=\"permission_name\">권한 이름</string>\n    <string name=\"user_and_uid\">사용자: <xliff:g id=\"user_name\" example=\"root\">%1$s</xliff:g> (<xliff:g id=\"user_id\" example=\"0\">%2$d</xliff:g>)</string>\n    <string name=\"components\">구성 요소</string>\n    <string name=\"user_with_id\">사용자: <xliff:g id=\"user_id\" example=\"0\">%1$d</xliff:g></string>\n    <string name=\"yes\">예</string>\n    <string name=\"mode\">모드</string>\n    <string name=\"accept_time\">수락 시간</string>\n    <string name=\"filtered_packages\">필터링된 패키지</string>\n    <string name=\"export_blocking_rules\">차단 규칙 내보내기</string>\n    <string name=\"duration\">실행 시간</string>\n    <string name=\"battery_mode\">배터리 모드</string>\n    <string name=\"block_components_dots\">구성 요소 차단…</string>\n    <string name=\"installer_error_generic\">설치 실패</string>\n    <string name=\"failed_to_fetch_package_info\">패키지 정보를 가져올 수 없습니다</string>\n    <string name=\"installer_error_session_create\">설치 관리자 세션을 생성할 수 없습니다</string>\n    <string name=\"backup_obb_media\">OBB랑 미디어</string>\n    <string name=\"unknown_split_for_base_apk\"><xliff:g id=\"split_name\" example=\"some_split\">%1$s</xliff:g> 기본 APK를 위해</string>\n    <string name=\"installer_error_session_write\">설치 관리자 세션에 작성할 수 없습니다</string>\n    <string name=\"base_apk\">기본 APK</string>\n    <string name=\"unknown_split_for_feature\"><xliff:g id=\"split_name\" example=\"some_split\">%1$s</xliff:g> 다음 기능을 위해 <xliff:g id=\"feature_name\" example=\"Visualizer\">%2$s</xliff:g></string>\n    <string name=\"density_split_for_feature\"><xliff:g id=\"split_name\" example=\"xxdpi\">%1$s</xliff:g> (<xliff:g id=\"dpi_no\" example=\"480\">%2$d</xliff:g> DPI) 다음 기능을 위한 자원 <xliff:g id=\"feature_name\" example=\"Visualizer\">%3$s</xliff:g></string>\n    <string name=\"operation_running\">작업 실행 중…</string>\n    <string name=\"abi_split_for_base_apk\"><xliff:g id=\"split_name\" example=\"arm64_v8a\">%1$s</xliff:g> 기본 APK를 위한 코드</string>\n    <string name=\"pref_app_language\">언어</string>\n    <string name=\"installer_error_storage\">앱을 설치할 공간이 부족합니다</string>\n    <string name=\"installer_error_lidl_rom\">ROM이 Rootless Installer와 호환되지 않습니다.</string>\n    <string name=\"reinstall\">재설치</string>\n    <string name=\"installer_error_session_commit\">APK 파일을 커밋할 수 없습니다</string>\n    <string name=\"failed_to_extract_obb_files\">OBB 파일 추출 실패</string>\n    <string name=\"batch_ops\">일괄 작업</string>\n    <string name=\"installer_error_security\">APK 파일에 접근할 수 없습니다</string>\n    <string name=\"obb_files_extracted_successfully\">OBB 파일 추출 성공</string>\n    <string name=\"backup_all_users\">모든 사용자</string>\n    <string name=\"density_split_for_base_apk\"><xliff:g id=\"split_name\" example=\"xxdpi\">%1$s</xliff:g> (<xliff:g id=\"dpi_no\" example=\"480\">%2$d</xliff:g> DPI) 기본 APK를 위한 자원</string>\n    <string name=\"abi_split_for_feature\"><xliff:g id=\"split_name\" example=\"arm64_v8a\">%1$s</xliff:g> 다음 기능을 위한 코드 <xliff:g id=\"feature_name\" example=\"Visualizer\">%2$s</xliff:g></string>\n    <string name=\"locale_split_for_feature\"><xliff:g id=\"split_name\" example=\"English\">%1$s</xliff:g> 다음 기능을 위한 로캘 <xliff:g id=\"feature_name\" example=\"Visualizer\">%2$s</xliff:g></string>\n    <string name=\"backup_multiple\">여러 개 백업</string>\n    <string name=\"full_stop_tap_to_see_details\">. 세부 정보 표시.</string>\n    <string name=\"try_again\">재시도</string>\n    <string name=\"install_app_message\">앱을 설치하시겠습니까\\?</string>\n    <string name=\"package_installer\">패키지 설치 관리자</string>\n    <string name=\"install_in_progress\">설치 중…</string>\n    <string name=\"backup_apk_files\">APK 파일</string>\n    <string name=\"locale_split_for_base_apk\"><xliff:g id=\"split_name\" example=\"English\">%1$s</xliff:g> 기본 APK를 위한 로캘</string>\n    <string name=\"installer_error_session_abandon\">설치 관리자 세션을 종료할 수 없습니다</string>\n    <string name=\"choose_language\">언어 변경</string>\n    <string name=\"unblock_trackers\">트래커 차단 해제</string>\n    <string name=\"launch_mode_multiple\">여러개</string>\n    <string name=\"auto\">자동</string>\n    <string name=\"split_feature_name\">기능: <xliff:g id=\"feature_name\" example=\"Visualizer\">%1$s</xliff:g></string>\n    <string name=\"backup_all_apps\">모든 앱 백업</string>\n    <string name=\"rules\">규칙</string>\n    <string name=\"os_version\">운영체제 버전</string>\n    <plurals name=\"classes\">\n        <item quantity=\"other\">클래스 %1$d개</item>\n    </plurals>\n    <string name=\"encrypted\">암호화됨</string>\n    <string name=\"no_volumes_found\">쓰기 권한이 있는 볼륨을 찾을 수 없습니다.</string>\n    <string name=\"unencrypted\">암호화되지 않음</string>\n    <string name=\"bootloader\">부트로더</string>\n    <string name=\"backup_apps_without_backups\">백업이 존재하지 않는 앱 백업하기</string>\n    <plurals name=\"no_of_splits\">\n        <item quantity=\"other\">%1$d개로 분할됨</item>\n    </plurals>\n    <plurals name=\"libraries\">\n        <item quantity=\"other\">라이브러리 %1$d개</item>\n    </plurals>\n    <string name=\"orientation_unspecified\">지정되지 않음</string>\n    <string name=\"pref_backup_volume_msg\">백업이 저장될 볼륨 또는 디스크를 선택하십시오.</string>\n    <string name=\"launch_mode_single_task\">단일 작업</string>\n    <string name=\"source_code_links\"><a href=\"https://github.com/MuntashirAkon/AppManager\">깃허브</a> • <a href=\"https://gitlab.com/muntashir/AppManager\">GitLab</a> • <a href=\"https://0xacab.org/muntashir/AppManager\">Riseup</a> • <a href=\"https://codeberg.org/muntashir/AppManager\">Codeberg</a></string>\n    <string name=\"orientation_full_sensor\">전체 센서</string>\n    <string name=\"orientation_full_user\">전체 사용자</string>\n    <string name=\"orientation_no_sensor\">센서 없음</string>\n    <string name=\"orientation_sensor\">센서</string>\n    <string name=\"orientation_sensor_portrait\">센서 세로</string>\n    <string name=\"launch_mode_single_instance\">단일 인스턴스</string>\n    <string name=\"action_stop_service\">중지</string>\n    <string name=\"save_as\">다른 이름으로 저장…</string>\n    <string name=\"swap\">바꾸다</string>\n    <string name=\"type_float_array\">십진수 배열</string>\n    <string name=\"type_string_array_list\">문자열 목록</string>\n    <string name=\"choose_an_alias\">에일리어스 선택</string>\n    <string name=\"open\">열기</string>\n    <string name=\"pref_buffer_title\">로그 버퍼(들)</string>\n    <string name=\"screen_lock\">화면 잠금</string>\n    <string name=\"type_uri\">URI 통합 자원 식별자</string>\n    <string name=\"invalid_aes_key_size\">AES 암호화에 대한 키 크기가 잘못되었습니다. 키 크기는 128비트 또는 256비트일 수 있습니다.</string>\n    <string name=\"crypto_key_size\">키 크기</string>\n    <string name=\"import_from_tb\">티타늄 백업에서 가져오기</string>\n    <string name=\"log_viewer\">로그 뷰어</string>\n    <string name=\"log_level_info\">정보</string>\n    <string name=\"orientation_user\">사용자</string>\n    <string name=\"required\">요구사항</string>\n    <string name=\"_undefined\">정의되지 않음</string>\n    <string name=\"fm_open_with_for_this_file_only\">이 파일에 대해서만</string>\n    <string name=\"open_as_image\">사진</string>\n    <string name=\"file_properties\">특성</string>\n    <string name=\"open_as_video\">비디오</string>\n    <string name=\"on_unfreeze_open_application\">고정 해제 후 앱 열기</string>\n    <string name=\"suspend_app_description\">이것은 가장 약한 고정 방법입니다. 중지된 앱이 홈 화면에 계속 나타날 수 있지만 회색으로 표시되어 실행할 수 없습니다.</string>\n    <string name=\"pref_reload_apps_msg\">예기치 않은 동작이 발생할 경우 App Manager 데이터베이스에 저장된 앱 목록을 다시 로드합니다.</string>\n    <string name=\"pref_saved_apk_name_format_msg\">APK 파일을 저장할 때 이름을 지정하는 데 사용되는 형식입니다.</string>\n    <string name=\"file_modified_are_you_sure\">파일이 수정되었습니다. 모든 변경 사항을 취소하고 종료하시겠습니까\\?</string>\n    <string name=\"failed_to_enable_magisk_deny_list\">Magisk 거부 목록을 사용하도록 설정할 수 없습니다</string>\n    <string name=\"hidden_api_enforcement_policy\">숨겨진 API 시행 정책</string>\n    <string name=\"add\">추가</string>\n    <string name=\"type_component_name\">구성 요소 이름</string>\n    <string name=\"type_int_array\">정수 배열</string>\n    <string name=\"type_int_array_list\">정수 목록</string>\n    <string name=\"keystore_pass\">KeyStore 암호</string>\n    <string name=\"log_level\">로그 레벨</string>\n    <string name=\"pref_installer_msg\">앱 설치 관리자의 동작을 구성합니다.</string>\n    <string name=\"pref_import_backups\">백업 가져오기</string>\n    <string name=\"import_from_oab\">OAndBackup에서 가져오기</string>\n    <string name=\"log_level_verbose\">세부정보</string>\n    <string name=\"collapse_all\">모두 접기</string>\n    <string name=\"expand_all\">모두 펼치기</string>\n    <string name=\"omit_sensitive_info_summary\">웹 URL, 전화 번호 또는 이메일과 같은 민감한 정보는 생략합니다.</string>\n    <string name=\"running_services\">서비스 실행</string>\n    <string name=\"pref_import_export_keystore_msg\">앱 관리자가 내부적으로 사용하는 BKS(Bouncy Castle KeyStore) 가져오기/내보내기.</string>\n    <string name=\"pref_import_export_keystore\">KeyStore 가져오기/내보내기</string>\n    <string name=\"import_keystore\">키 저장소 가져오기</string>\n    <string name=\"pref_display_changes\">변경사항 표시</string>\n    <string name=\"netpolicy_reject_cellular_data\">셀룰러 데이터 거부</string>\n    <string name=\"confirm_import_keystore\">기존 KeyStore를 바꾸시겠습니까\\? 이 작업은 취소할 수 없습니다.</string>\n    <string name=\"orientation_right_to_left\">오른쪽에서 왼쪽으로</string>\n    <string name=\"port_number\">포트</string>\n    <string name=\"files\">파일 탐색기</string>\n    <string name=\"port_number_invalid\">포트 번호가 잘못되었습니다.</string>\n    <string name=\"pref_block_trackers_msg\">앱 관리자를 사용하여 앱 설치 후 구성 요소 추적을 차단합니다.</string>\n    <string name=\"search_type_regular_expressions\">정규식</string>\n    <string name=\"vt_queued\">VirusTotal: 대기중</string>\n    <string name=\"type_uri_array\">URI 배열</string>\n    <string name=\"pref_thread_count_hint\">값은 0에서 %1$d 사이여야 합니다. 여기서 0은 <i>주어진 시간에 최대 작업 수</i>를 의미합니다.</string>\n    <plurals name=\"pref_thread_count_msg\">\n        <item quantity=\"other\">최대 %1$d개의 작업을 병렬로 실행합니다</item>\n    </plurals>\n    <string name=\"pid\">프로세스 ID</string>\n    <string name=\"smali\">Smali</string>\n    <string name=\"cpu_time\">CPU 시간</string>\n    <string name=\"magisk_denylist\">Magisk 거부 목록</string>\n    <string name=\"vt_success\">바이러스 총계: %1$d/%2$d</string>\n    <string name=\"vt_scan_date\">검색 날짜: %1$s</string>\n    <string name=\"vt_slowness_warning\">인터넷 속도와 서버의 부하에 따라 시간이 걸릴 수 있습니다.</string>\n    <string name=\"pref_vt_apikey\">VirusTotal API 키</string>\n    <string name=\"pref_vt_apikey_summary\">VirusTotal을 통한 APK 파일 검색을 활성화합니다.</string>\n    <string name=\"uses_play_app_signing\">앱 서명 실행</string>\n    <string name=\"hidden_api_enf_policy_warn\">경고(숨겨진 API에 대한 전체 액세스이지만 경고 발생)</string>\n    <string name=\"binary_64_bit\">64비트</string>\n    <string name=\"endianness_little_endian\">리틀엔디언</string>\n    <string name=\"endianness_big_endian\">빅엔디언</string>\n    <string name=\"so_type_shared_library\">공유 라이브러리</string>\n    <string name=\"mode_of_op_with_inferred_mode_of_op\">%1$s(추상 모드: %2$s)</string>\n    <string name=\"hidden_api_enf_default_policy\">기본값(응용 프로그램 유형 기준)</string>\n    <string name=\"pref_saved_apk_name_format\">저장된 APK 이름 형식</string>\n    <string name=\"regenerate_auth_key\">인증 키 재생성</string>\n    <string name=\"so_type_executable\">실행 가능한</string>\n    <string name=\"save_and_exit\">저장 후 종료</string>\n    <string name=\"open_in_new_window\">새 창</string>\n    <string name=\"type_string_set\">문자열 집합</string>\n    <string name=\"app_explorer\">앱 탐색기</string>\n    <string name=\"sort_by_installation_date\">설치일자</string>\n    <string name=\"tracker\">트래커</string>\n    <string name=\"screen_time\">스크린 타임</string>\n    <string name=\"pref_pure_black_theme\">퓨어 블랙 테마</string>\n    <string name=\"freeze\">고정</string>\n    <string name=\"unfreeze\">고정 해제</string>\n    <string name=\"backup_no_backups_present\">백업이 없습니다.</string>\n    <string name=\"restore_dots\">복구 …</string>\n    <string name=\"pref_pure_black_theme_msg\">야간 모드가 활성화된 경우 완전히 검은색 배경을 사용합니다.</string>\n    <string name=\"usage_last_used\">마지막으로 사용된</string>\n    <string name=\"usage_mobile_data\">모바일 데이터</string>\n    <string name=\"usage_wifi_data\">와이파이 데이터</string>\n    <string name=\"frozen\">고정된</string>\n    <string name=\"unsupported_split_apk\">지원하지 않는</string>\n    <string name=\"view_changelog\">이 배포의 새로운 기능 확인</string>\n    <string name=\"am_command\"><tt>am</tt> 명령</string>\n    <string name=\"pref_sign_apk_error_signing_key_not_added\">APK 파일에 서명하려면 유효한 서명 키가 필요합니다.</string>\n    <string name=\"backup_apps_cannot_be_restored\">다음 앱은 기본 백업이 없으므로 복원할 수 없습니다:</string>\n    <string name=\"backup_apps_cannot_be_backed_up\">다음 앱이 설치되어 있지 않으므로 백업할 수 없습니다:</string>\n    <string name=\"restart_device\">장치 재시작</string>\n    <string name=\"import_backups_warning_delete_backups_after_import\">백업을 App Manager로 가져온 후 삭제하시겠습니까\\? 각 백업은 성공적으로 가져온 후에 개별적으로 삭제됩니다. 확실하지 않으면 <b>아니오</b>를 선택하십시오.</string>\n    <string name=\"pref_sign_apk_no_signing_key\">서명 키 없음</string>\n    <string name=\"failed_to_freeze\"><xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g>.를 중지할 수 없습니다.</string>\n    <string name=\"failed_to_unfreeze\"><xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g>를 해제할 수 없습니다.</string>\n    <string name=\"freeze_unfreeze\">고정/해제</string>\n    <string name=\"profile_freeze_msg\">상태에 따라 앱을 고정하거나 고정 해제</string>\n    <string name=\"pref_default_freezing_method\">기본 고정 방법</string>\n    <string name=\"pref_default_freezing_method_description\">고정 방법을 선택할 수 있는 옵션이 없는 위치에서 기본적으로 사용되는 방법입니다.</string>\n    <string name=\"suspend_app\">중지</string>\n    <string name=\"disable_app_description\">권장되는 방법입니다. 앱과 모든 구성 요소를 비활성화 하지만 바로 가기가 손실됩니다.</string>\n    <string name=\"hide_app_description\">이 방법은 일상적인 사용에만 권장됩니다. 숨겨진 앱이 제거된 것처럼 나타납니다. 그러나 앱이 다시 설치되거나 업데이트되면 다시 나타날 수 있습니다.</string>\n    <string name=\"sort_by_frozen_app\">고정된 앱</string>\n    <string name=\"filter_frozen_apps\">고정된 앱</string>\n    <string name=\"pref_appearance_description\">테마, 방향, 기능 등.</string>\n    <string name=\"hide_app\">숨겨진</string>\n    <plurals name=\"alert_failed_to_unfreeze\">\n        <item quantity=\"other\">%1$d개 앱의 고정을 해제할 수 없습니다</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_freeze\">\n        <item quantity=\"other\">%1$d개 앱의 고정할 수 없습니다</item>\n    </plurals>\n    <string name=\"pref_privacy\">보안</string>\n    <string name=\"pref_privacy_description\">화면 잠금, 인증 관리 등.</string>\n    <string name=\"user_manual\">사용자 매뉴얼</string>\n    <string name=\"get_help\">도움말</string>\n    <string name=\"pref_advanced_pref\">사용자, APK 이름 형식, 병렬 실행 등.</string>\n    <string name=\"pref_version_changelog\">버전/변경된로그</string>\n    <string name=\"vt_failed\">VirusTotal: 실패</string>\n    <string name=\"vt_disclaimer\">VirusTotal 및 해당 로고는 Chronicle LLC의 상표입니다. App Manager(API 클라이언트)와 작성자는 사용자가 VirusTotal로 전송할 수 있는 데이터에 대해 책임지지 않습니다.</string>\n    <string name=\"notice\">공지</string>\n    <string name=\"pref_display_changes_msg\">버전, 추적기, 구성 요소, 권한, 서명, SDK 등의 변경 사항을 버전 제어 방식으로 표시합니다.</string>\n    <string name=\"pref_rules_msg\">즉각적인 차단, 규칙 가져오기/내보내기/제거 등.</string>\n    <string name=\"notice_saf\">볼륨과 달리 선택한 디렉터리는 저장된 APK 및 백업을 포함하여 App Manager와 관련된 모든 파일을 저장하는 데 사용됩니다. SAF(Storage Access Framework)는 매우 느리므로 다른 옵션을 사용할 수 없는 경우에만 이 옵션을 사용해야 합니다.</string>\n    <string name=\"keystore_pass_cannot_be_empty\">KeyStore 암호는 비워 둘 수 없습니다.</string>\n    <string name=\"filter_choice\">검색 기준</string>\n    <string name=\"log_saved\">로그가 저장되었습니다.</string>\n    <string name=\"notification_subtext\">누르면 기록을 중지할 수 있습니다</string>\n    <string name=\"notification_ticker\">로그 기록 시작</string>\n    <string name=\"record_log\">기록 로그</string>\n    <string name=\"pref_show_timestamp_summary\">확장 시 프로세스 ID 및 타임스탬프를 표시합니다.</string>\n    <string name=\"text_filter_ellipsis\">필터…</string>\n    <string name=\"start_recording_log\">기록</string>\n    <string name=\"organization_unit\">조직 단위(OU)</string>\n    <string name=\"error_with_details\">오류: %s</string>\n    <string name=\"key_not_set\">결정되지 않음.</string>\n    <string name=\"organization_name\">조직 이름(O)</string>\n    <string name=\"keystore_file\">KeyStore 파일</string>\n    <string name=\"pkcs12_keystore\">PKCS #12 키 저장소(P12)</string>\n    <string name=\"pem_and_pk8\">PEM 및 PKCS #8(PK8)</string>\n    <string name=\"new_alias_password\">새 에일리어스 암호</string>\n    <string name=\"found_no_alias_in_keystore\">KeyStore에서 에일리어스을 찾을 수 없습니다!</string>\n    <string name=\"alias_pass\">에일리어스 암호</string>\n    <string name=\"pref_log_viewer_msg\">로그 표시 방법을 구성합니다.</string>\n    <string name=\"restart_log_viewer_to_see_changes\">로그 뷰어 창을 다시 시작하여 변경 내용을 확인합니다.</string>\n    <string name=\"filename\">파일이름</string>\n    <string name=\"screen_lock_msg\">Android 화면 잠금을 사용하여 App Manager 잠금</string>\n    <string name=\"battery_optimization\">배터리 최적화</string>\n    <string name=\"has_net_policy\">넷 정책</string>\n    <string name=\"initializing\">초기화중…</string>\n    <string name=\"add_to_profile\">프로필에 추가</string>\n    <string name=\"copied_to_clipboard\">클립보드에 복사되었습니다.</string>\n    <string name=\"restart_to_reflect_changes\">새 변경 사항을 사용하려면 장치를 즉시 다시 시작해야 합니다.</string>\n    <string name=\"installed_apps\">설치된 앱</string>\n    <string name=\"failed_to_read_keystore\">KeyStore를 읽을 수 없습니다.</string>\n    <string name=\"pgp_aes_rsa_encrypted\">%1$s 암호화됨</string>\n    <string name=\"user_root\">루트 사용</string>\n    <string name=\"choose_what_to_do\">수행할 작업을 선택합니다.</string>\n    <string name=\"latest_backup\">최신 백업</string>\n    <string name=\"trim_caches_in_all_apps\">모든 앱에서 캐시 트리밍</string>\n    <string name=\"java_keystore\">Java KeyStore(JKS)</string>\n    <string name=\"gz_bz2_compressed\">%1$s 압축됨</string>\n    <string name=\"vt_permalink\">VirusTotal에 대한 영구 링크</string>\n    <string name=\"send_log_title\">로그 전송</string>\n    <string name=\"explore\">탐색</string>\n    <string name=\"help_permissions_tab\">이 권한은 이 앱에서 정의한 것이므로 취소할 수 없습니다.</string>\n    <string name=\"vt_checking\">VirusTotal: 확인중…</string>\n    <string name=\"intent_firewall_and_disable\">IFW + 비활성화</string>\n    <string name=\"failed_to_unblock_trackers\">추적기를 차단 해제할 수 없습니다</string>\n    <string name=\"file\">파일</string>\n    <string name=\"scan_in_vt\">바이러스 총 검색 수</string>\n    <string name=\"toggle_internet\">인터넷 사용</string>\n    <string name=\"failed_to_load_key\">키를 로드할 수 없습니다.</string>\n    <string name=\"type_long_array\">긴 정수 배열</string>\n    <string name=\"type_long_array_list\">긴 정수 리스트</string>\n    <string name=\"filter_apps_without_backups\">백업 없음</string>\n    <string name=\"add_filter_ellipsis\">필터 추가…</string>\n    <string name=\"expiry_date_cannot_be_empty\">만료 날짜는 비워 둘 수 없습니다.</string>\n    <string name=\"pref_import_backups_msg\">OandBackup, Swift Backup(3.0–3.2) 또는 Titanium Backup에서 백업을 가져옵니다.</string>\n    <string name=\"last_actions\">마지막 작업</string>\n    <string name=\"screen_lock_not_enabled\">안드로이드 설정에서 화면 잠금을 선택하거나 앱 데이터를 지우십시오.</string>\n    <string name=\"netpolicy_cannot_be_modified_for_core_apps\">Android 핵심 앱의 경우 Net 정책을 수정할 수 없습니다.</string>\n    <string name=\"log_level_fatal\">주의</string>\n    <string name=\"no_battery_optimization\">배터리 최적화 없음</string>\n    <string name=\"enable_battery_optimization\">배터리 최적화를 사용하시겠습니까\\?</string>\n    <string name=\"enable_disable_features\">기능 사용/사용하지 않음</string>\n    <string name=\"pref_enable_disable_features_msg\">앱 관리자에서 기능을 사용하거나 사용하지 않도록 설정합니다.</string>\n    <string name=\"isolated\">고립된</string>\n    <string name=\"working_on_adb_mode\">ADB 모드에서 작업 중</string>\n    <string name=\"installer_app_message\">설치된 앱에서 선택하려면 <b>Choose</b>을 선택하고, 사용자 지정 패키지 이름을 지정하려면 <b>Custom</b>을 선택합니다.</string>\n    <string name=\"input_key\">입력 키(16진수)</string>\n    <string name=\"failed_to_save_key\">키를 저장할 수 없습니다.</string>\n    <string name=\"failed_to_initialize_key_store\">앱 관리자 KeyStore를 초기화 할 수 없습니다.</string>\n    <string name=\"locality_name\">지역(도시)명(L)</string>\n    <string name=\"common_name\">공용 이름(CN)</string>\n    <string name=\"state_name\">상태 이름(ST)</string>\n    <string name=\"country_name\" tools:ignore=\"TypographyOther\">국가명(C)</string>\n    <string name=\"pem_file\">PEM 파일</string>\n    <string name=\"import_key\">키 가져오기</string>\n    <string name=\"signing_key\">서명 키</string>\n    <string name=\"enter_good_filename\">올바른 파일 이름을 입력하십시오.</string>\n    <string name=\"add_filter\">필터 추가</string>\n    <string name=\"dialog_compiling_log\">로그를 컴파일하는 중…</string>\n    <string name=\"background\">배경</string>\n    <string name=\"no_saved_logs\">저장된 로그가 없습니다.</string>\n    <string name=\"settings\">설정</string>\n    <string name=\"toast_invalid_level\">잘못된 레벨 이름: %s</string>\n    <string name=\"saf\">SAF</string>\n    <string name=\"log_recording_started\">로그 기록이 시작되었습니다.</string>\n    <string name=\"text_include_device_info\">장치 정보 포함</string>\n    <string name=\"failed_to_change_ssaid\">SSAID를 변경할 수 없습니다</string>\n    <string name=\"use_default\">기본값 사용</string>\n    <string name=\"log_cleared\">로그가 지워짐</string>\n    <string name=\"pause_unpause\">재생/일시 중지</string>\n    <string name=\"regenerate_auth_key_warning\">확실합니까\\? 모든 타사 앱을 새 인증 키로 재구성해야 합니다.</string>\n    <string name=\"pref_default_log_level_summary\">시작할 때, 파일을 열 때, 기록할 때 로그 수준.</string>\n    <string name=\"shortcut_icon\">바로 가기 아이콘</string>\n    <string name=\"exit_confirmation\">종료확인</string>\n    <string name=\"binary_32_bit\">32비트</string>\n    <string name=\"state\">프로세스 상태</string>\n    <string name=\"failed_to_disable_magisk_deny_list\">Magisk DenyList를 사용하지 않도록 설정할 수 없습니다</string>\n    <string name=\"failed_to_change_app_op_mode\">앱 모드를 변경할 수 없습니다.</string>\n    <string name=\"port_number_empty\">포트 번호가 비어 있습니다.</string>\n    <string name=\"pref_display_limit_title\">로그 표시 제한</string>\n    <string name=\"widget_recording_in_progress\">기록중…</string>\n    <string name=\"pref_log_line_period_error\">1에서 1000 사이의 정수를 입력하십시오.</string>\n    <string name=\"threads\">스레드 수</string>\n    <string name=\"set_package_name_first\">패키지 이름을 먼저 설정하십시오!</string>\n    <string name=\"profile_save_apk_msg\">APK 파일을 <tt>AppManager/apps</tt>에 저장합니다</string>\n    <string name=\"pref_display_limit_hint\" tools:ignore=\"PluralsCandidate\">%1$d에서 %2$d 사이의 올바른 숫자를 입력하십시오.</string>\n    <string name=\"log_level_error\">오류</string>\n    <string name=\"pref_disable_description\">구성 요소만 비활성화합니다. 앱이 이를 무시할 수 있으므로 루트 사용자에게는 권장되지 않습니다. ADB 모드에서는 이 방법으로 테스트 전용 앱을 비활성화할 수 있습니다.</string>\n    <string name=\"enter_filename\">파일명을 입력하세요</string>\n    <string name=\"invalid_rsa_key_size\">RSA 암호화에 대한 키 크기가 잘못되었습니다. 키 크기는 1024, 2048 또는 4096비트일 수 있습니다.</string>\n    <string name=\"accessibility_service_description\">no-root 모드에서 캐시 지우기와 같은 특정 작업을 수행하기 위한 일반 접근성 서비스입니다.</string>\n    <string name=\"manage_saved_logs\">저장된 로그 관리</string>\n    <string name=\"type_uri_array_list\">URI 목록</string>\n    <string name=\"priority\">우선순위</string>\n    <string name=\"storage\">저장소</string>\n    <string name=\"netpolicy_reject_background_data\">백그라운드 데이터 거부</string>\n    <string name=\"process_id\">프로세스 ID</string>\n    <string name=\"pref_vt_apikey_description\">API 키를 사용하면 App Manager가 APK 파일을 VirusTotal에 업로드하고 보고서를 가져올 수 있습니다. API 키를 무료로 받으려면 https://virustotal.com에서 가입하십시오.</string>\n    <string name=\"notification_title\">로그 기록 진행 중</string>\n    <string name=\"open_developer_options_page\">Android 설정에서 개발자 옵션 페이지 열기</string>\n    <string name=\"paste\">복사</string>\n    <string name=\"pref_display_limit_summary\" tools:ignore=\"PluralsCandidate\">메모리 부족 오류를 방지하기 위해 마지막 %1$d 로그만 표시합니다.</string>\n    <string name=\"pref_thread_count\">병렬 실행</string>\n    <string name=\"installer_app_installed\">앱 설치됨</string>\n    <string name=\"failed\">실패함</string>\n    <string name=\"primary_abi\">주요 ABI</string>\n    <string name=\"adb_connect\">연결</string>\n    <string name=\"vt_uploading\">VirusTotal: 업로드중…</string>\n    <string name=\"pref_selected_users\">선택한 사용자</string>\n    <string name=\"rename\">이름 변경</string>\n    <string name=\"pref_show_timestamp_title\">Pid 및 타임스탬프 표시</string>\n    <string name=\"help_uses_permissions_tab\">항목을 클릭하여 <b>부여</b>하거나 <b>취소</b>합니다. <b>위험</b> 및 <b>개발</b> 허가만 부여하거나 취소할 수 있습니다.</string>\n    <string name=\"bouncy_castle_keystore\">Bouncy Castle 키 저장소 (BKS)</string>\n    <string name=\"pk8_file\">PKCS #8(PK8) 파일</string>\n    <string name=\"reverse\">반대</string>\n    <string name=\"failed_to_prevent_background_run\">%1$s이(가) 백그라운드에서 실행되는 것을 차단할 수 없습니다</string>\n    <string name=\"hidden_api_enf_policy_dark_grey_and_black\">실행(어두운 회색 및 검은색 목록)</string>\n    <string name=\"pref_always_on_background_msg\">항상 백그라운드에 앱을 설치하고 완료되면 알림을 표시합니다.</string>\n    <string name=\"no_encryption\">암호화 없음</string>\n    <string name=\"type_null\">값이 없음</string>\n    <string name=\"filter_choice_pid\">프로세스 아이디</string>\n    <string name=\"share_log\">공유</string>\n    <string name=\"ssaid_info\">SSAID(<tt>Settings.Secure.ANDROID_아이디(ID)</tt>는 안드로이드 8 오레오 이후의 각 앱에 할당된 장치 식별자이다. 사용자를 추적하기 위해 앱에서 널리 사용된다.</string>\n    <string name=\"change_backup_volume\">볼륨 변경</string>\n    <string name=\"failed_to_block_trackers\">추적기를 차단할 수 없습니다</string>\n    <string name=\"keystore_password_info\">다음은 App Manager KeyStore 암호입니다. App Manager KeyStore를 백업/복원하려면 안전한 장소에 보관하십시오. <b>이 메시지는 다시 표시되지 않습니다.</b></string>\n    <string name=\"netpolicy_reject_vpn_data\">VPN 데이터 거부</string>\n    <string name=\"replace\">대체</string>\n    <string name=\"running_services_logcat_hint\">항목을 클릭하여 해당 프로세스 ID를 기본 필터로 사용하여 로그 뷰어를 엽니다.</string>\n    <string name=\"system_partition\">안드로이드 루트</string>\n    <string name=\"extract\">압축풀기</string>\n    <string name=\"type_float_array_list\">십진수 리스트</string>\n    <string name=\"netpolicy_reject_wifi_data\">Wi-Fi 데이터 거부</string>\n    <string name=\"verified_using_unreliable_hash\">신뢰할 수 없는 해시를 사용하여 확인됨</string>\n    <string name=\"net_policy\">넷 정책</string>\n    <string name=\"delete_saved_log\">저장된 로그 삭제</string>\n    <string name=\"pref_import_backups_hint\">백업 파일이 들어 있는 디렉터리(Swift Backup/Titanium Backup) 또는 디렉터리(O And Backup)를 선택하십시오</string>\n    <string name=\"log_level_debug\">디버그</string>\n    <string name=\"java\">Java</string>\n    <string name=\"unknown_net_policy\">알 수 없는 넷 정책(%1$s - %2$X)</string>\n    <string name=\"list_options\">목록 옵션</string>\n    <string name=\"ssaid\">SSAID</string>\n    <string name=\"text_include_dmesg\">커널 로그 포함</string>\n    <string name=\"save_log\">로그 저장</string>\n    <string name=\"pref_default_blocking_method_description\">차단 방법을 선택할 수 있는 옵션이 없는 위치에서 기본적으로 사용할 방법입니다.</string>\n    <string name=\"generate_key\">생성</string>\n    <string name=\"memory_chart_info\">● %1$s 어플리케이션 ● %2$s 캐시됨 ● %3$s 버퍼 ● %4$s 사용가능</string>\n    <string name=\"backup_volume_dialog_description\">접두사가 <tt>/tree</tt>인 볼륨은 SAF(Storage Access Framework)를 사용하여 선택한 폴더입니다. 이러한 폴더를 제외한 App Manager의 기본 디렉터리는 <tt>AppManager</tt>라는 하위 폴더입니다.</string>\n    <string name=\"backup_volume_unavailable_warning\">선택한 백업 볼륨을 현재 사용할 수 없습니다. 외부 저장소에 있는 경우 삽입하거나 백업 볼륨을 변경하십시오.</string>\n    <string name=\"adb_connect_port_number_description\">포트 번호는 <b> 아래에 있습니다.<b>장치 이름</b> 섹션 바로 아래의 IP 주소 &amp; 포트 </b> 섹션입니다.</string>\n    <string name=\"paired_successfully\">연결됨.</string>\n    <string name=\"pref_always_on_background\">백그라운드에 설치</string>\n    <plurals name=\"alert_failed_to_import_backups\">\n        <item quantity=\"other\">%1$d 백업을 가져올 수 없습니다</item>\n    </plurals>\n    <string name=\"pref_default_blocking_method\">기본 차단 방법</string>\n    <string name=\"search_type_prefix\">접두사</string>\n    <string name=\"toast_invalid_selection\">잘못된 선택입니다. 다시 시도하십시오.</string>\n    <string name=\"type_string_array\">문자열 배열</string>\n    <string name=\"uninstalled_apps\">제거된 앱</string>\n    <string name=\"hidden_api_enf_policy_black\">시행(블랙리스트만 해당)</string>\n    <string name=\"swap_chart_info\">● %1$s 사용 ● %2$s 자유롭게</string>\n    <string name=\"wireless_debugging\">무선 디버깅</string>\n    <string name=\"omit_sensitive_info\">민감한 정보 생략</string>\n    <string name=\"added_to_queue\">대기열에 추가됨</string>\n    <string name=\"pref_expanded_by_default_summary\">기본적으로 전체 로그 텍스트를 표시합니다.</string>\n    <string name=\"input_key_password\">키 암호</string>\n    <string name=\"import_from_sb\">Swift 백업 3.0 – 3.2에서 가져오기</string>\n    <string name=\"pref_cat_advanced\">고급</string>\n    <string name=\"pref_cat_configuration\">배열</string>\n    <string name=\"pref_default_log_level_title\">기본 로그 수준</string>\n    <string name=\"pref_filter_pattern_title\">태그 필터링</string>\n    <string name=\"pref_expanded_by_default_title\">기본으로 확장</string>\n    <string name=\"undo\">실행 취소</string>\n    <string name=\"text_filter_text\">텍스트 필터링</string>\n    <plurals name=\"toast_log_truncated\">\n        <item quantity=\"other\">로그가 너무 커서 마지막 %d줄이 표시됩니다.</item>\n    </plurals>\n    <string name=\"unable_to_save_log\">로그를 저장할 수 없습니다. 올바른 파일 이름을 입력했습니까\\?</string>\n    <string name=\"widget_start_recording\">기록\n\\n로그</string>\n    <string name=\"save_apk\">APK 저장</string>\n    <string name=\"view_logs\">로그 보기</string>\n    <string name=\"trackers_blocked_successfully\">이제 추적기가 차단되었습니다</string>\n    <string name=\"base_backup\">기본 백업</string>\n    <string name=\"trackers_unblocked_successfully\">이제 추적기의 차단이 해제되었습니다</string>\n    <string name=\"no_changes\">변화 없음</string>\n    <string name=\"netpolicy_allow_background_data\">데이터 절약 모드가 켜져 있을 때 백그라운드 데이터 허용</string>\n    <string name=\"intent_firewall\">IFW</string>\n    <string name=\"invalid_password\">암호가 잘못되었습니다. 다시 시도하십시오.</string>\n    <string name=\"identifier\">식별자</string>\n    <string name=\"trim_caches_in_all_apps_description\">Android 시스템을 포함한 모든 애플리케이션에서 캐시 파일 삭제</string>\n    <string name=\"next\">다음</string>\n    <string name=\"pref_selected_users_msg\">앱 관리자가 선택한 사용자와만 작동하도록 제한합니다.</string>\n    <string name=\"cpu_percent\">%% CPU</string>\n    <string name=\"virtual_memory\">가상 메모리</string>\n    <string name=\"pref_vt_prompt_before_uploading\">파일을 업로드하기 전에 프롬프트를 표시합니다.</string>\n    <string name=\"hidden_api_enf_policy_none\">없음(숨겨진 API에 대한 전체 액세스)</string>\n    <string name=\"commandline_args\">명령줄 인수</string>\n    <string name=\"external\">외부의</string>\n    <string name=\"auth_manager_description\">외부 앱에서 Intent를 실행하려면 <tt>auth</tt>라는 추가 필드를 제공해야 하며 다음 키를 포함해야 합니다:</string>\n    <string name=\"vt_confirm_upload_and_scan\">예, 업로드 및 스캔</string>\n    <string name=\"vt_confirm_uploading_file\">VirusTotal 데이터베이스에서 파일을 찾을 수 없습니다. 업로드하시겠습니까\\?</string>\n    <string name=\"log_stop_recording\">기록 중지</string>\n    <string name=\"item_select\">선택</string>\n    <string name=\"filter_choice_tag\">태그</string>\n    <string name=\"orientation_left_to_right\">왼쪽에서 오른쪽으로</string>\n    <string name=\"suspended\">일시중지</string>\n    <string name=\"hidden\">숨겨진</string>\n    <string name=\"warning_working_on_root_mode\">경고: ADB 모드 대신 루트에서 작업 중입니다.</string>\n    <string name=\"internal\">내부의</string>\n    <string name=\"input_ssaid_instruction\">SSAID는 %1$d 바이트 16진수 숫자, 즉 0~9 및 a~f를 포함하는 길이 %2$d의 문자열이다.</string>\n    <plurals name=\"file_deletion_confirmation\">\n        <item quantity=\"other\">%d개의 파일이 삭제됩니다</item>\n    </plurals>\n    <string name=\"log_level_warn\">경고</string>\n    <string name=\"copy_to_clipboard\">클립보드에 복사</string>\n    <string name=\"pref_filter_pattern_summary\">로그에서 선택한 태그를 필터링합니다.</string>\n    <string name=\"pref_log_write_period_summary\" tools:ignore=\"PluralsCandidate\">기록할 때 %1$d 줄마다 SD 카드에 기록하십시오.</string>\n    <string name=\"pref_log_write_period_title\">쓰는 기간</string>\n    <string name=\"subject_log_report\">로그 기록</string>\n    <string name=\"help_app_ops_tab\">항목을 클릭하여 <b>허용</b>하거나 <b>무시</b>하십시오. 지원되는 다른 모드를 보려면 항목을 길게 클릭하십시오.</string>\n    <string name=\"netpolicy_disable_network_access\">네트워크 액세스 사용 안 함</string>\n    <string name=\"adb_pair\">페어링</string>\n    <string name=\"minimum_version\">최소 버전: %d</string>\n    <string name=\"saved_filters\">저장된 필터</string>\n    <string name=\"search_type_contains\">포함하다</string>\n    <string name=\"search_type_suffix\">접미사</string>\n    <string name=\"pref_intent_firewall_and_disable_description\">의도된 방화벽을 사용하여 구성 요소를 차단하고 사용하지 않도록 설정합니다. 루트 사용자에게 권장되는 방법입니다.</string>\n    <string name=\"pref_intent_firewall_description\">의도된 방화벽만 사용하여 구성 요소를 차단합니다. 일부 시스템 앱은 방화벽을 우회할 수 있으므로 권장하지 않습니다.</string>\n    <string name=\"authenticating\">인증 중…</string>\n    <string name=\"failed_to_use_the_current_mode_of_operation\">현재 작동 모드를 사용할 수 없습니다. 이 세션에 대해 루트 없음 모드로 되돌리는 중입니다.</string>\n    <string name=\"parent_process_id\">부모 프로세스 ID</string>\n    <string name=\"uses_play_app_signing_description\">이 앱에는 <i>아마</i> <a href=\"https://support.google.com/googleplay/android-developer/answer/9842756\">Play App Signing</a>를 사용하고 있음을 나타내는 특정 마커가 포함되어 있습니다. 이 방식으로 서명 키는 구글의 서버에 저장되며, 구글은 앱에 서명할 책임이 있습니다. 서명 정보를 일치시키면 앱이 개발자 이외의 다른 사용자에 의해 수정되지 않았음을 확인할 수 있습니다(이 경우 Google도 마찬가지입니다).</string>\n    <string name=\"auth_manager_title\">권한 부여 관리자</string>\n    <string name=\"sort_by_total_size\">전체 크기</string>\n    <string name=\"file_modification_date\">수정된</string>\n    <string name=\"file_accessed_date\">접근</string>\n    <string name=\"file_open_with\">로 열기</string>\n    <string name=\"file_shortcut_target_file\">대상 파일</string>\n    <string name=\"file_creation_date\">생성 날짜</string>\n    <string name=\"file_open_as\">다른 앱에서 열기…</string>\n    <string name=\"file_open_with_custom_activity\">커스텀</string>\n    <string name=\"file_open_with_os_default_dialog\">기본 선택 화면으로 열기</string>\n    <string name=\"open_as_text\">텍스트</string>\n    <string name=\"open_as_folder\">폴더</string>\n    <string name=\"open_as_other\">그 외</string>\n    <string name=\"delete_filename\">%s 삭제</string>\n    <string name=\"confirm_file_deletion\">네, 삭제하겠습니다</string>\n    <string name=\"on_open_application_no_recents\">최근에 실행된 앱 표시 안 함</string>\n    <string name=\"open_as_archive\">보관소</string>\n    <string name=\"file_cut\">자르기</string>\n    <string name=\"fm_always_open_with\">항상 오픈</string>\n    <string name=\"waiting_for_the_phone_to_be_locked\">핸드폰이 잠길 때까지 기다리는 중…</string>\n    <string name=\"freeze_on_phone_locked\">핸드폰이 잠겨 있을 때 자동으로 앱 중지</string>\n    <string name=\"tap_to_freeze_app\">고정하기 위해 탭하기</string>\n    <string name=\"changelog_type_improve\">개선</string>\n    <string name=\"troubleshooting\">문제 해결</string>\n    <string name=\"pref_reload_apps\">앱 다시 로드</string>\n    <string name=\"changelog_type_new\">새로운</string>\n    <string name=\"changelog_type_fix\">수정</string>\n    <string name=\"send_edited_intent\">수정된 의도 전송</string>\n    <string name=\"ecc\">타원-곡선 암호학</string>\n    <string name=\"send_selected\">선택한 것 전송</string>\n    <string name=\"profile_state\">개요 상태</string>\n    <string name=\"pref_mode_of_operations\">작동 모드</string>\n    <string name=\"profile_clear_cache_msg\">앱 캐시의 앱 삭제</string>\n    <string name=\"pref_sign_apk_msg\">APK 파일을 설치하기 전에 서명하십시오.</string>\n    <string name=\"manufacturer\">제조업체</string>\n    <string name=\"kernel\">커널</string>\n    <string name=\"set_mode_for_app_ops_dots\">앱 모드 설정 옵션…</string>\n    <string name=\"scaling_factor\">크기 요소</string>\n    <string name=\"refresh_rate\">새로고침 빈도</string>\n    <string name=\"failed_to_disable_magisk_hide\">MagiskHide를 비활성화 할 수 없음</string>\n    <string name=\"backup_apps_without_backups_msg\">이전 백업 없이 앱을 백업합니다.</string>\n    <string name=\"restore_latest_msg\">버전 코드가 설치된 버전 코드보다 높은 이미 설치된 앱을 복원합니다.</string>\n    <string name=\"backup_msg\">데이터로 앱 백업</string>\n    <string name=\"back_up\">백업</string>\n    <string name=\"restore_msg\">데이터를 사용하여 앱 복원</string>\n    <string name=\"profile_force_stop_msg\">앱 강제 중지</string>\n    <string name=\"profile_state_msg\">이 프로필의 사용자 지정 켜기/끄기 상태</string>\n    <string name=\"on\">켜다</string>\n    <string name=\"off\">끄다</string>\n    <string name=\"choose\">선택</string>\n    <string name=\"v2_scheme\">v2 방식(Android 7.0 이후)</string>\n    <string name=\"splits\">분할</string>\n    <string name=\"input_keystore_alias_pass\">에일리어스에 대한 암호 <b>%1$s</b></string>\n    <string name=\"this_action_cannot_be_undone\">이 작업은 취소할 수 없습니다.</string>\n    <string name=\"screen\">화면</string>\n    <string name=\"in_progress\">진행 중</string>\n    <string name=\"duplicate\">복제</string>\n    <string name=\"v1_scheme\">v1 방식(Android 1.0 이후)</string>\n    <string name=\"pref_sign_apk\">APK 서명</string>\n    <string name=\"cpu\">CPU</string>\n    <string name=\"options\">옵션들</string>\n    <string name=\"simple\">단순한</string>\n    <string name=\"verified\">확인됨</string>\n    <string name=\"about_device\">디바이스 정보</string>\n    <string name=\"restore_not_installed_msg\">현재 설치되지 않은 앱의 기본 백업을 복원합니다.</string>\n    <string name=\"backup_all_apps_msg\">설치된 모든 앱을 백업합니다.</string>\n    <string name=\"restore_latest\">최신 백업 복원</string>\n    <string name=\"failed_to_enable_magisk_hide\">MagiskHide를 활성화 할 수 없음</string>\n    <string name=\"action\">조치</string>\n    <string name=\"pref_encryption_msg\">백업을 위한 암호화.</string>\n    <string name=\"profile_block_trackers_msg\">앱에서 추적기를 차단</string>\n    <string name=\"input_permissions\">입력 권한</string>\n    <string name=\"user_profile_with_id\">프로필: %1$s (%2$d)</string>\n    <string name=\"root\">루트</string>\n    <string name=\"installer\">설치 프로그램</string>\n    <string name=\"app_signing_signature_schemes\">서명 방식</string>\n    <string name=\"apk_signing\">APK 서명</string>\n    <string name=\"v3_scheme\">v3 방식(Android 9 이후)</string>\n    <string name=\"not_verified\">확인되지 않음</string>\n    <string name=\"source_stamp_verified\">소스 스탬프가 확인되었습니다.</string>\n    <string name=\"filter_apps_with_splits\">분할 포함</string>\n    <string name=\"matching_activities\">매칭 활동</string>\n    <string name=\"activity_result\">활동결과</string>\n    <string name=\"value\">값</string>\n    <string name=\"uri\">URI 통합 자원 식별자</string>\n    <string name=\"resend_intent\">재전송 의도</string>\n    <string name=\"set_custom_app_op\">사용자 지정 앱 설정 옵션</string>\n    <string name=\"backup_apk_files_description\">분할을 포함하여 원본 디렉터리에서 APK 파일을 백업합니다.</string>\n    <string name=\"brand_name\">브랜드</string>\n    <string name=\"backup_internal_data_description\">내부 데이터 폴더를 백업합니다.</string>\n    <string name=\"backup_cache_description\"><b>캐시</b>, <b>캐시_없음</b> 및 <b>백업_없음</b> 폴더를 백업합니다.</string>\n    <string name=\"model\">모델</string>\n    <string name=\"enforcing\">시행</string>\n    <string name=\"permissive\">관대한</string>\n    <string name=\"hardware\">하드웨어</string>\n    <string name=\"density\">밀도</string>\n    <string name=\"size\">크기</string>\n    <string name=\"restore_all\">모든 앱 복원</string>\n    <string name=\"restore_all_msg\">백업된 모든 앱에서 기본 백업을 복원합니다.</string>\n    <string name=\"disable_background_run_description\">다음 앱에 대해 <i>무시</i>모드를 설정합니다. <tt>RUN_IN_BACKGROUND </tt> (Android 7.0에서) 및 <tt>RUN_ANY_ IN_BACKGROUND</tt>(Android 9에서).</string>\n    <string name=\"verify_and_redo_backups\">백업 확인 및 다시 실행</string>\n    <string name=\"pref_backup_android_keystore\">Android KeyStore로 앱 백업</string>\n    <string name=\"battery_capacity\">용량</string>\n    <string name=\"users\">사용자들</string>\n    <string name=\"sd_card\">SD카드</string>\n    <string name=\"patch_level\">패치 수준</string>\n    <string name=\"backup_volume\">백업 볼륨</string>\n    <string name=\"battery\">배터리</string>\n    <string name=\"keep_data_and_app_signing_signatures\">데이터 및 서명 보관</string>\n    <string name=\"input_keystore_alias_pass_description\">에일리어스에 대한 암호 <b>%1$s</b>를 삽입하십시오. 암호가 KeyStore 암호와 동일한 경우 이 값을 비워 둘 수 있습니다.</string>\n    <string name=\"aes\">AES</string>\n    <string name=\"rsa\">RSA</string>\n    <string name=\"security\">보안</string>\n    <string name=\"allow_routine_ops\">루틴 작업 허용 옵션</string>\n    <string name=\"redo_existing_backups\">기존 백업 다시 실행</string>\n    <string name=\"pref_backup_restore_msg\">백업/복원을 사용자 정의합니다.</string>\n    <string name=\"languages\">언어</string>\n    <string name=\"extras\">엑스트라</string>\n    <string name=\"backup_apps_with_changes\">변경 사항이 있는 앱 백업</string>\n    <string name=\"category\">분류</string>\n    <string name=\"internal_storage\">내부 저장소</string>\n    <string name=\"vendor\">판매 회사</string>\n    <string name=\"unlock_app_manager\">앱 관리자 잠금 해제</string>\n    <string name=\"select_user\">사용자 선택</string>\n    <string name=\"backup_rules_description\">App Manager 내에서 설정된 백업 규칙입니다. <font fgcolor=\"ff0000\">권한에 따라 일부 규칙은 복원되지 않을 수 있습니다.</font> </string>\n    <string name=\"redo_existing_backups_msg\">이전 백업이 있는 설치된 앱에 대해 백업을 다시 실행합니다.</string>\n    <string name=\"magisk_hide_enabled\">MagiskHide</string>\n    <string name=\"security_providers\">보안 제공업체</string>\n    <string name=\"external_storage\">외부 저장소</string>\n    <string name=\"result_code\">결과코드</string>\n    <string name=\"profile_clear_data_msg\">앱의 데이터를 삭제</string>\n    <string name=\"pref_signature_schemes_msg\">호환성을 높이려면 v1 및 v2 스키마를 적어도 하나 이상 선택해야 합니다. v4 방식에는 v2 또는 v3이 필요합니다.</string>\n    <string name=\"restore_not_installed\">설치되지 않은 앱 복원</string>\n    <string name=\"share\">공유</string>\n    <string name=\"backup_apps_with_changes_msg\">마지막 백업 이후 변경된 앱에 대해 백업을 다시 실행합니다. 그 백업은 크기, 버전, 마지막 출시 시간의 변화를 포함합니다.</string>\n    <string name=\"input_permissions_description\">공백이 있는 입력 권한(예: <tt>com.permission.GET_Accounts Android.permission.ACCESS_MEDIA_LOCATION</tt> 등 모든 권한을 적용하려면 <tt>*</tt>를 사용하십시오.</string>\n    <string name=\"backup_custom_users\">사용자 지정 사용자</string>\n    <string name=\"drm_free_apkm_msg\">APKM 파일은 DRM이 없으므로 APKS로 변환할 필요가 없습니다.</string>\n    <string name=\"no_of_cores\">코어들</string>\n    <string name=\"memory\">메모리</string>\n    <string name=\"set_app_op_mode\">앱 모드 설정</string>\n    <string name=\"backup_extras\">엑스트라</string>\n    <string name=\"backup_obb_media_description\">OBB 및 미디어 폴더를 백업합니다.</string>\n    <string name=\"gles_version\">OpenGL ES 버전</string>\n    <string name=\"verify_and_redo_backups_msg\">이전 백업의 무결성을 확인하고 무결성 검사가 실패한 백업을 다시 실행하십시오.</string>\n    <string name=\"support_architectures\">지원되는 아키텍처</string>\n    <string name=\"adb_over_tcp\">TCP를 통한 ADB</string>\n    <string name=\"backup_external_data_description\">외부 데이터 폴더를 백업합니다.</string>\n    <string name=\"input_keystore_alias_pass_msg\">%1$s에 대한 암호를 제공하려면 여기를 누르십시오</string>\n    <string name=\"backup_custom_users_description\">지정된 사용자에 대해서만 백업 수행</string>\n    <string name=\"pref_backup_android_keystore_msg\">복원 후 일부 앱이 작동하지 않습니다. KeyStore 복원은 대부분의 장치에서 작동하지 않습니다.</string>\n    <string name=\"backup_skip_signature_checks_description\">체크섬 확인에 실패하거나 이전 백업과 다른 APK 서명을 가진 백업을 복원합니다.</string>\n    <string name=\"selinux\">SELinux</string>\n    <string name=\"backup_multiple_description\">기본 백업 대신 별도의 <i>이름</i>이 지정된 백업을 생성합니다.</string>\n    <string name=\"no_app_ops_permission\">앱을 표시할 수 있는 권한이 없습니다</string>\n    <string name=\"mime_type\">MIME 유형</string>\n    <string name=\"pref_about_device_msg\">Android 시스템, CPU, GPU, RAM, 배터리 등을 포함한 기본 장치 정보.</string>\n    <string name=\"graphics\">그래픽스</string>\n    <string name=\"allow_routine_ops_msg\">일상적인 작업에서 프로필 사용 허용</string>\n    <string name=\"pref_apk_signing_msg\">서명 체계, 사용자 지정 서명 키 등을 설정합니다.</string>\n    <string name=\"enabled\">활성화</string>\n    <string name=\"advanced\">발전된</string>\n    <string name=\"no_root\">루트 없음</string>\n    <string name=\"close\">닫음</string>\n    <string name=\"comment\">주석</string>\n    <string name=\"install_location_prefer_external\">외부 선호</string>\n    <string name=\"install_location\">설치 위치</string>\n    <string name=\"install_location_internal_only\">내부 전용</string>\n    <string name=\"v4_scheme\">v4 방식(Android 11 이후)</string>\n    <string name=\"input_keystore_pass\">KeyStore 암호 입력</string>\n    <string name=\"input_keystore_pass_description\">App Manager KeyStore 암호를 입력합니다. 처음 보는 경우 암호 생성기를 사용하여 암호를 생성하고 여기에 암호를 삽입하기 전에 안전한 장소에 저장하십시오.</string>\n    <string name=\"input_keystore_pass_msg\">KeyStore 암호를 입력하려면 여기를 누르십시오</string>\n    <string name=\"encryption\">암호화</string>\n    <string name=\"none\">없음</string>\n    <string name=\"input_profile_name\">프로필 이름</string>\n    <string name=\"input_profile_name_description\">프로필 이름에 공백을 사용할 수 없습니다.</string>\n    <string name=\"new_profile\">새로운 프로필</string>\n    <string name=\"failed_to_duplicate_profile\">프로필을 복제할 수 없습니다</string>\n    <string name=\"window_size\">윈도우 크기</string>\n    <string name=\"orientation_user_landscape\">사용자 가로</string>\n    <string name=\"state_unknown\">미지 상태</string>\n    <string name=\"state_high_priority\">높은 우선순위</string>\n    <string name=\"state_session_leader\">세션 리더</string>\n    <string name=\"state_foreground\">포그라운드</string>\n    <string name=\"state_multithreaded\">멀티스레드</string>\n    <string name=\"orientation_reverse_landscape\">뒤집어 가로</string>\n    <string name=\"state_device_io\">장치 입출력</string>\n    <string name=\"keyboard_qwerty\">QWERTY</string>\n    <string name=\"orientation_landscape\">가로</string>\n    <string name=\"orientation_portrait\">세로</string>\n    <string name=\"orientation_reverse_portrait\">뒤집어 세로</string>\n    <string name=\"orientation_sensor_landscape\">센서 가로</string>\n    <string name=\"state_trace_stop\">트레이스 정지</string>\n    <string name=\"state_idle\">유휴</string>\n    <string name=\"state_low_priority\">낮은 우선순위</string>\n    <string name=\"state_locked_memory\">잠긴 메모리</string>\n    <string name=\"touchscreen_no_touch\">잠금</string>\n    <string name=\"input_backup_name_description\">백업 이름은 숫자로 시작할 수 없고 공백을 포함할 수 없습니다. 현재 날짜-시간을 사용하려면 비워 두십시오.</string>\n    <string name=\"touchscreen_stylus\">스타일러스</string>\n    <string name=\"ok\">OK</string>\n    <string name=\"keyboard_12_keys\">12키</string>\n    <string name=\"touchscreen_finger\">손가락</string>\n    <string name=\"downgrade\">다운그레이드</string>\n    <string name=\"process_state_with_extra\">상태: <xliff:g id=\"process_state\" example=\"Sleeping\">%1$s</xliff:g> (<xliff:g id=\"state_extra\" example=\"High priority\">%2$s</xliff:g>)</string>\n    <string name=\"input_backup_name\">백업 이름</string>\n    <string name=\"orientation_user_portrait\">사용자 세로</string>\n    <string name=\"navigation_dial_pad\">다이얼 패드</string>\n    <string name=\"state_sleeping\">절전 모드</string>\n    <string name=\"process_state\">상태: <xliff:g id=\"process_state\" example=\"Sleeping\">%1$s</xliff:g></string>\n    <string name=\"cancel\">취소</string>\n    <string name=\"update_uninstalled_successfully\"><xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g>의 업데이트가 제거되었습니다.</string>\n    <string name=\"subject\">대상</string>\n    <string name=\"format\">형식</string>\n    <string name=\"rsa_exponent\">지수</string>\n    <string name=\"rsa_modulus\">계수</string>\n    <string name=\"do_you_want_to_uninstall_and_install\">앱을 제거하고 다시 설치하시겠습니까\\?</string>\n    <string name=\"app_signing_install_without_data_loss\">서명 인증을 해제한 경우, <b>설치만</b> 옵션을 선택하여 데이터 손실 없이 앱을 설치할 수 있습니다.</string>\n    <string name=\"only_install\">설치만</string>\n    <string name=\"no_libs\">라이브러리 없음</string>\n    <string name=\"lib_details\">라이브러리 세부사항</string>\n    <string name=\"tap_to_see_details\">눌러서 세부 정보 보기</string>\n    <string name=\"navigation_no_nav\">내비게이션 없음</string>\n    <string name=\"other\">기타</string>\n    <string name=\"sort_by_process_id\">프로세스 ID</string>\n    <string name=\"pref_compression_method\">압축 방식</string>\n    <string name=\"tap_to_submit_crash_report\">충돌 보고서를 제출하려면 누르십시오.</string>\n    <string name=\"changes_not_saved\">변경사항 저장 안 됨</string>\n    <string name=\"sort_by_backup\">백업 완료 우선</string>\n    <string name=\"app_signing_signature_mismatch_for_system_apps\">서명이 다른 시스템 앱이 동일한 패키지 이름을 사용 중이므로 앱을 설치할 수 없습니다.</string>\n    <string name=\"sys_config\">시스템 구성</string>\n    <string name=\"state_waking\">깨우기</string>\n    <string name=\"systemless_app\">시스템 독립 앱</string>\n    <string name=\"open_pgp_provider\">OpenPGP 공급자</string>\n    <string name=\"select_apk\">APK 선택</string>\n    <string name=\"conversion_failed\">변환 실패.</string>\n    <string name=\"orientation_follow_locale\">로케일 따르기</string>\n    <string name=\"staging_apk_files\">준비 중…</string>\n    <string name=\"keystore\">Key스토어</string>\n    <string name=\"uninstall_updates\">업데이트 제거</string>\n    <string name=\"profiles\">프로필</string>\n    <string name=\"filter_apps_with_activities\">활성화</string>\n    <string name=\"launch_mode_single_top\">싱글 탑</string>\n    <string name=\"orientation_locked\">잠금</string>\n    <string name=\"navigation_trackball\">트랙 볼</string>\n    <string name=\"navigation_wheel\">휠</string>\n    <string name=\"state_dead\">종료</string>\n    <string name=\"keyboard_no_keys\">Key 없음</string>\n    <string name=\"state_parked\">주차</string>\n    <string name=\"state_wake_kill\">깨우기 죽임</string>\n    <string name=\"routine_ops\">루틴 ops</string>\n    <string name=\"apps\">앱</string>\n    <string name=\"filter_apps\">앱</string>\n    <string name=\"sort_by_process_name\">프로세스 이름</string>\n    <string name=\"allow_open_pgp_operation\">App Manager가 OpenPGP를 사용하도록 허용</string>\n    <string name=\"sort_by_apps_first\">앱 우선</string>\n    <string name=\"expiry_date\">유통기한</string>\n    <string name=\"expired\">만료</string>\n    <string name=\"checksums\">체크섬</string>\n    <string name=\"public_key\">공유 키</string>\n    <string name=\"dsa_affine_x\">아핀 x 좌표</string>\n    <string name=\"dsa_affine_y\">아핀 y 좌표</string>\n    <string name=\"non_critical_exts\">중요하지 않은 확장프로그램</string>\n    <string name=\"copy\">복사</string>\n    <string name=\"filter_running_apps\">실행 중인 앱</string>\n    <string name=\"send_crash_report\">충돌 보고서 보내기</string>\n    <string name=\"un_apkm\">UnApkm</string>\n    <string name=\"interceptor\">인터셉터</string>\n    <string name=\"no_profiles\">프로필 없음</string>\n    <string name=\"filter_apps_with_backups\">백업 존재</string>\n    <string name=\"failed_to_uninstall_updates\"><xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g>의 업데이트 제거를 할 수 없습니다.</string>\n    <string name=\"serial_no\">시리얼 번호</string>\n    <string name=\"type\">종류</string>\n    <string name=\"critical_exts\">중요 확장프로그램</string>\n    <string name=\"specify_custom_name\">커스텀</string>\n    <string name=\"app_signing_signature\">서명</string>\n    <string name=\"not_yet_valid\">아직 유효하지 않음</string>\n    <string name=\"board_name\">보드</string>\n    <string name=\"orientation_behind\">거꾸로</string>\n    <string name=\"app_data_will_be_lost\">기존 데이터가 손실됩니다.</string>\n    <string name=\"zygote_preload_name\">자이고트 사전로딩 이름</string>\n    <string name=\"algorithm\">알고리즘</string>\n    <string name=\"pref_cat_appearance\">모습</string>\n    <string name=\"apk_checksums\">APK 체크섬</string>\n    <string name=\"valid\">유효</string>\n    <string name=\"usage_times_opened\">열린 횟수</string>\n    <string name=\"validity\">유효성</string>\n    <string name=\"apply_now\">지금 적용…</string>\n    <string name=\"no_apps\">앱 없음</string>\n    <string name=\"requested_large_heap\">큰 heap</string>\n    <string name=\"confirm_installation\">설치 확인</string>\n    <string name=\"state_zombie\">좀비</string>\n    <string name=\"issued_date\">발행일</string>\n    <string name=\"issuer\">발행자</string>\n    <string name=\"scanner\">스캐너</string>\n    <string name=\"view_missing_signatures\">App Manager의 라이브러리 데이터베이스에 아직 저장되지 않은 서명을 보거나 보내려면 누르십시오.</string>\n    <string name=\"am_crashed\">App Manager이 충돌이 발생했습니다</string>\n    <string name=\"file_change_open_with\">연결 프로그램 변경</string>\n    <string name=\"sort_by_filename\">이름</string>\n    <string name=\"app_manager_build_expired\">업데이트 필요</string>\n    <string name=\"sort_by_last_modified\">최근 수정</string>\n    <string name=\"sort_by_file_size\">파일 크기</string>\n    <string name=\"sort_by_file_type\">파일 종류</string>\n    <string name=\"app_manager_build_expired_message\">디바이스와 데이터의 안전을 위해, 이 앱 버전이 만료되었습니다. 계속 사용하려면 업데이트해야 합니다. 업데이트가 불가능하다면 앱을 제거하세요.</string>\n    <string name=\"calculating_file_size\">크기 계산 중…</string>\n    <string name=\"export_option_xml\">XML</string>\n    <string name=\"grant_overlay_permission_message\">App Manager가 다른 앱 위에 표시하도록 허용해 주세요</string>\n    <string name=\"line_separator\">개행 문자</string>\n    <string name=\"block_unblock_components_dots\">구성 요소 차단/해제…</string>\n    <string name=\"unblock_components_dots\">구성 요소 차단 해제…</string>\n    <string name=\"app_manager_build_expiring_soon_warning\">이 App Manager 버전은 곧 만료됩니다. 최신 버전으로 업데이트해주세요.</string>\n    <string name=\"grant_required_permission\">필요한 권한 부여하기</string>\n    <string name=\"optimize_option_force_dexopt\">Dex 최적화 수행하기</string>\n    <string name=\"title_perform_runtime_optimization_to_apps\">ART 최적화 수행하기</string>\n    <string name=\"empty_folder\">파일이 없습니다</string>\n    <plurals name=\"folder_count\">\n        <item quantity=\"other\">폴더 %d개</item>\n    </plurals>\n    <plurals name=\"file_count\">\n        <item quantity=\"other\">파일 %d개</item>\n    </plurals>\n    <string name=\"create_new_file\">새 파일 만들기</string>\n    <string name=\"create_new_folder\">새 폴더 만들기</string>\n    <string name=\"copied_successfully\">복사되었습니다.</string>\n    <string name=\"block_unblock_components_description\">서명과 일치하는 모든 구성 요소 차단 또는 해제하기</string>\n    <plurals name=\"alert_failed_to_unblock_components\">\n        <item quantity=\"other\">앱 %1$d개의 구성 요소를 차단 해제할 수 없습니다</item>\n    </plurals>\n    <string name=\"app_can_write_and_execute_in_same_place\">앱이 <a href=\"https://en.wikipedia.org/wiki/W%5EX\">W^X 정책</a>을 위반하며 동일한 디렉토리 또는 메모리의 동일한 위치에서 작성하고 실행할 수 있습니다. 이를 통해 앱 내에 포함된 실행 파일을 수정하거나 인터넷에서 다운로드하여 임의의 실행 파일을 실행할 수 있습니다. 이것이 앱의 의도된 동작(예: 터미널 에뮬레이터)이 아닌 한 SDK 29(Android 10) 이상을 대상으로 하는 앱의 최신 버전을 찾거나 대안을 찾는 것을 권장합니다.</string>\n    <string name=\"change_owner_uid\">소유자 (UID) 변경하기</string>\n    <string name=\"pref_layout_direction\">레이아웃 방향</string>\n    <string name=\"option_display_dot_files\">숨김 파일</string>\n    <string name=\"export_app_list\">앱 목록 내보내기</string>\n    <string name=\"export_option_markdown\">Markdown 문법</string>\n    <string name=\"change_group_gid\">그룹 (GID) 변경하기</string>\n</resources>"
  },
  {
    "path": "app/src/main/res/values-lv/disclaimer.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"disclaimer_header\">Brīdinājums</string>\n    <string name=\"disclaimer_footer\">© 2020–2025 Muntashir Al-Islam</string>\n    <string name=\"disclaimer_agree_forever\">Nekad vairs nerādīt</string>\n    <string name=\"disclaimer_agree\">Piekrītu</string>\n    <string name=\"disclaimer_exit\">Iziet</string>\n    <string name=\"disclaimer_body\">App Manager piedāvā funkcijas ar root tiesībām, kas varētu kaitēt jūsu ierīcei, ja tās izmanto nepareizi. App Manager nav atbildīgs par jebkādiem nodarītiem kaitējumiem, izmantojot šo lietotni. Ja jūs neesiet pilnībā informēti kādus potenciālus riskus un draudus nes root tiesības, jums vajadzētu izvairīties izmantot funkcijas ar root tiesībām līdz brīdim, kamēr esiet pilnībā izpratuši un apzinājušies tā riskus.\\n\\nJebkuru saiti, ko piedāvāju uz kādu lietotni un tīmekļa vietni, ir priekš lietotāja papildus zināšanas ieguvums. Es nenesu nekādu atbildību par jebkādu saturu, ko šīs ārējās saites iekļauj, apmeklējot tās.\\n\\nIzmantojot App Manager, jūs uzņematies pilnu atbildību par tā lietošanu un nepieprasīsiet nekādu zaudējumu vai naudas kompensāciju un neveiksiet pretenzijas prasību nepareizas izmantošanas rezultātā.\\n\\nIzmantojot šo lietotni, jūs uzņematies visu atbildību par tās lietošanu un piekrītat, ka lietotnes izstrādātājs nav atbildīgs par jebkādu jūsu darbību, kas var nelabvēlīgi ietekmēt jūsu ierīci.</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-lv/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\">\n    <plurals name=\"usage_seconds\">\n        <item quantity=\"zero\">%1$d sekundes</item>\n        <item quantity=\"one\">%1$d sekundi</item>\n        <item quantity=\"other\">%1$d sekundes</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_uninstall\">\n        <item quantity=\"zero\">Nevarēja noņemt %1$d lietotnes</item>\n        <item quantity=\"one\">Nevarēja noņemt %1$d lietotni</item>\n        <item quantity=\"other\">Nevarēja noņemt %1$d lietotnes</item>\n    </plurals>\n    <string name=\"permissions\">Izmantotās atļaujas</string>\n    <string name=\"require_no_permission\">Nepieprasa atļauju</string>\n    <string name=\"activities\">Darbības</string>\n    <string name=\"uninstall\">Noņemt</string>\n    <string name=\"launch\">Palaist</string>\n    <string name=\"found_trackers\">Atrastie izsekotāji:</string>\n    <string name=\"no_tracker_class\">Nav izsekotāja klases</string>\n    <string name=\"tracker_details\">Informācija par izsekotāju</string>\n    <string name=\"tracker_classes\">Izsekotāja klases</string>\n    <string name=\"all_classes\">Visas klases</string>\n    <plurals name=\"main_list_date_days\">\n        <item quantity=\"zero\"><xliff:g id=\"last_update_date\" example=\"20/10/2020\">%1$s</xliff:g> <xliff:g id=\"day_no\" example=\"5\">%2$d</xliff:g> dienas</item>\n        <item quantity=\"one\"><xliff:g id=\"last_update_date\" example=\"20/10/2020\">%1$s</xliff:g> <xliff:g id=\"day_no\" example=\"5\">%2$d</xliff:g> diena</item>\n        <item quantity=\"other\"><xliff:g id=\"last_update_date\" example=\"20/10/2020\">%1$s</xliff:g> <xliff:g id=\"day_no\" example=\"5\">%2$d</xliff:g> dienas</item>\n    </plurals>\n    <string name=\"app_usage\">Lietotņu lietojums</string>\n    <string name=\"usage_today\">Šodienas</string>\n    <string name=\"usage_7_days\">Pēdējās 7 dienās</string>\n    <string name=\"usage_less_than_a_minute\">Mazāk par minūti</string>\n    <string name=\"go_back\">Iet atpakaļ</string>\n    <string name=\"go\">Atļaut (Aiziet)</string>\n    <string name=\"grant_usage_access\">Piešķiriet lietošanas vēstures piekļuvi</string>\n    <string name=\"grant_usage_acess_message\">Izmanto, lai parādītu informāciju par lietotņu lietojumu.</string>\n    <string name=\"share_apk\">Kopīgot APK</string>\n    <string name=\"failed_to_extract_apk_file\">Neizdevās iegūt APK failu</string>\n    <string name=\"menu_remove_rules\">Noņemt noteikumus</string>\n    <string name=\"menu_apply_rules\">Piemērot (izmantot) noteikumus</string>\n    <string name=\"search\">Meklēt</string>\n    <string name=\"native_library_dir\">Dzimtā JNI bibliotēku mape</string>\n    <string name=\"process_name\">Procesa nosaukums</string>\n    <string name=\"no_code\">Nav koda</string>\n    <string name=\"requested_large_heap\">Daudz (liela) kaudzes atmiņas</string>\n    <string name=\"updated_app\">Atjaunināta</string>\n    <string name=\"debuggable\">Atkļūdojama</string>\n    <string name=\"test_only\">Tikai pārbaudei</string>\n    <string name=\"shared_prefs\">Kopīgie iestatījumi</string>\n    <string name=\"databases\">Datubāzes</string>\n    <string name=\"save\">Saglabāt</string>\n    <string name=\"discard\">Atcelt</string>\n    <string name=\"delete\">Dzēst</string>\n    <string name=\"uninstall_app_message\">Vai vēlaties noņemt šo lietotni?</string>\n    <string name=\"failed_to_uninstall\">Nevarēja noņemt <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g> lietotni.</string>\n    <string name=\"failed_to_uninstall_app\">Nevarēja noņemt</string>\n    <string name=\"uninstalled_successfully\"><xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g> lietotne veiksmīgi noņemta.</string>\n    <string name=\"uninstall_system_app_message\">Šī ir sistēmas lietotne. Vai tiešām vēlaties noņemt šo lietotni?</string>\n    <string name=\"clear_data_from_uninstalled_apps\">Dzēst noņemto lietotņu datus</string>\n    <string name=\"clear_data_from_uninstalled_apps_description\">Dzēš lietotņu datus, kas noņemtas ar <tt>DONT_DELETE_DATA</tt> atzīmi</string>\n    <string name=\"uninstall_updates\">Noņemt atjauninājumus</string>\n    <string name=\"update_uninstalled_successfully\">Lietotnes <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g> atjauninājumi veiksmīgi noņemti.</string>\n    <string name=\"failed_to_uninstall_updates\">Nevarēja noņemt lietotnes <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g> atjauninājumus.</string>\n    <string name=\"do_you_want_to_uninstall_and_install\">Vai vēlaties noņemt un atkal uzstādīt lietotni?</string>\n    <string name=\"uninstalled_apps\">Noņemtās lietotnes</string>\n    <string name=\"confirm_uninstallation\">Apstiprinu noņemšanu</string>\n    <string name=\"uninstall_app_again_message\">Lietotne tika noņemta bez datu un paraksta dzēšanas. Vai vēlaties to pilnībā noņemt?</string>\n    <string name=\"uninstall_app\">Noņemt %1$s</string>\n    <string name=\"refresh\">Atsvaidzināt</string>\n    <string name=\"sort_by_last_update\">Pēdējo reizi atjaunināta</string>\n    <string name=\"signatures\">Paraksti</string>\n    <string name=\"sort_by_sha\">Paraksta</string>\n    <string name=\"app_signing_signatures\">Paraksti</string>\n    <string name=\"app_signing_no_signatures\">Nav derīgu parakstu</string>\n    <string name=\"error\">Kļūda</string>\n    <string name=\"sort_by_app_label\">Lietotnes nosaukuma</string>\n    <string name=\"sort_by_target_sdk\">Mērķa SDK versijas</string>\n    <string name=\"about\">Par lietotni</string>\n    <string name=\"app_not_installed\">Lietotne nav uzstādīta</string>\n    <string name=\"sort\">Kārtot pēc</string>\n    <string name=\"system_app\">Sistēmas lietotne</string>\n    <string name=\"user_app\">Lietotāja lietotne</string>\n    <string name=\"shared_libs\">Koplietotās bibliotēkas</string>\n    <string name=\"group\">Grupa</string>\n    <string name=\"declared_permission\">Atļaujas</string>\n    <string name=\"loading\">Ielādē…</string>\n    <string name=\"sort_by_shared_user_id\">Vispārīgā (koplietotā) lietotāja identifikatora</string>\n    <string name=\"sort_by_last_used\">Pēdējo reizi lietota</string>\n    <string name=\"sort_by_installation_date\">Uzstādīšanas datuma</string>\n    <string name=\"sort_by_package_name\">Lietotnes unikālā nosaukuma</string>\n    <string name=\"sort_by_domain\">Lietotāja lietotnes augšgalā</string>\n    <string name=\"sort_by_memory_usage\">Izmantotās atmiņas apjoma</string>\n    <string name=\"sort_by_apps_first\">Lietotnes augšgalā</string>\n    <string name=\"sort_by_process_name\">Procesa nosaukuma</string>\n    <string name=\"sort_by_process_id\">Procesa ID</string>\n    <string name=\"sort_by_backup\">Dublētās augšgalā</string>\n    <string name=\"sort_by_total_size\">Kopējā izmēra</string>\n    <string name=\"sort_by_frozen_app\">Iesaldētās augšgalā</string>\n    <string name=\"sort_by_data_usage\">Izmantotā datu apjoma</string>\n    <string name=\"sort_by_overlay_names\">Pārklājuma nosaukuma</string>\n    <string name=\"sort_by_priority\">Prioritātes</string>\n    <string name=\"sort_by_blocked_components\">Bloķētās augšgalā</string>\n    <string name=\"source_code_links\"><a href=\"https://github.com/MuntashirAkon/AppManager\">GitHub</a> • <a href=\"https://gitlab.com/muntashir/AppManager\">GitLab</a> • <a href=\"https://0xacab.org/muntashir/AppManager\">Riseup</a> • <a href=\"https://codeberg.org/muntashir/AppManager\">Codeberg</a>﻿</string>\n    <string name=\"sort_by_screen_time\">Lietošanas ilguma</string>\n    <string name=\"sort_by_times_opened\">Atvēršanas skaita</string>\n    <string name=\"sort_by_mobile_data\">Izmantotā mobilo datu apjoma</string>\n    <string name=\"sort_by_wifi_data\">Izmantotā Wi-Fi datu apjoma</string>\n    <string name=\"pref_about_msg\">App Manager versija, licence, pateicības, saites utt.</string>\n    <string name=\"sort_by_component_name\">Komponenta nosaukuma</string>\n    <string name=\"sort_by_app_ops_names\">Lietotnes darbību nosaukuma</string>\n    <string name=\"sort_by_app_ops_values\">Lietotnes darbību vērtības</string>\n    <string name=\"sort_by_permission_names\">Atļaujas nosaukuma</string>\n    <string name=\"sort_by_dangerous_permissions\">Bīstamās augšgalā</string>\n    <string name=\"sort_by_tracker_components\">Izsekotājus augšgalā</string>\n    <string name=\"sort_by_denied_app_ops\">Liegtās darbības augšgalā</string>\n    <string name=\"sort_by_denied_permissions\">Liegtajām atļaujām augšgalā</string>\n    <string name=\"community_links\"><a href=\"https://matrix.to/#/#appmanager:matrix.org\">Matrix</a> • <a href=\"https://t.me/AppManagerChannel\">Telegram</a> • <a href=\"https://x.com/AppManagerNews\">Twitter/X</a> • <a href=\"https://floss.social/@appmanager\">Mastodon</a>﻿</string>\n    <string name=\"about_device\">Par ierīci</string>\n    <string name=\"pref_about_device_msg\">Pamatinformācija par ierīci - Android versija, CPU, GPU, RAM, baterija utt.</string>\n    <string name=\"last_actions\">Nesenās darbības</string>\n    <string name=\"sort_by_filename\">Nosaukuma</string>\n    <string name=\"sort_by_last_modified\">Pēdējo reizi modificēts</string>\n    <string name=\"sort_by_file_size\">Faila izmēra</string>\n    <string name=\"sort_by_file_type\">Faila tipa</string>\n    <string name=\"credits_message\">Pateicība izstrādātājiem:\\n- The Android Open Source Project \\n- <a href=\"https://github.com/zhaobozhen/libraries\">Absinthe\\'s libraries</a> \\n- <a href=\"https://github.com/butzist/ActivityLauncher\">Activity Launcher</a> \\n- <a href=\"https://bitbucket.org/oF2pks/fdroid-applications-info\">Apps_packages Info</a> \\n- <a href=\"https://github.com/zhaobao/AppsMonitor\">AppsMonitor</a> \\n- <a href=\"https://github.com/8enet/AppOpsX\">AppOpsX</a> \\n- <a href=\"https://github.com/gabrielemariotti/changeloglib\">ChangeLog Library</a> \\n- <a href=\"https://bitbucket.org/oF2pks/fdroid-classyshark3xodus\">ClassySharkAndroid</a> \\n- <a href=\"https://github.com/billthefarmer/editor\">Editor</a> \\n- <a href=\"https://github.com/Raival-e/File-Explorer\">File Explorer</a> \\n- <a href=\"https://github.com/nex3z/FlowLayout\">FlowLayout</a> \\n- <a href=\"https://github.com/k3b/intent-intercept\">Intent Intercept</a> \\n- <a href=\"https://github.com/YarikSOffice/lingver\">Lingver</a> \\n- <a href=\"https://github.com/topjohnwu/Magisk\">Magisk</a> \\n- <a href=\"https://github.com/zhanghai/MaterialFiles\">Material Files</a> \\n- <a href=\"https://github.com/pluscubed/matlog\">MatLog</a> \\n- <a href=\"https://github.com/matrix-org/matrix-android-sdk\">Matrix Android SDK</a> \\n- <a href=\"https://github.com/jensstein/oandbackup\">OAndBackup</a> \\n- <a href=\"https://github.com/open-keychain/open-keychain\">Open Keychain</a> \\n- <a href=\"https://github.com/Aefyr/SAI\">SAI</a> \\n- <a href=\"https://github.com/RikkaApps/Shizuku\">Shizuku</a> \\n- <a href=\"https://github.com/eclipse/tm4e\">tm4e</a> \\n- <a href=\"https://github.com/tuyafeng/Watt\">Watt</a></string>\n    <plurals name=\"usage_hours\">\n        <item quantity=\"zero\">%1$d stundas</item>\n        <item quantity=\"one\">%1$d stundu</item>\n        <item quantity=\"other\">%1$d stundas</item>\n    </plurals>\n    <plurals name=\"usage_days\">\n        <item quantity=\"zero\">%1$d dienas</item>\n        <item quantity=\"one\">%1$d dienu</item>\n        <item quantity=\"other\">%1$d dienas</item>\n    </plurals>\n    <plurals name=\"usage_months\">\n        <item quantity=\"zero\">%1$d mēnešus</item>\n        <item quantity=\"one\">%1$d mēnesi</item>\n        <item quantity=\"other\">%1$d mēnešus</item>\n    </plurals>\n    <plurals name=\"usage_minutes\">\n        <item quantity=\"zero\">%1$d minūtes</item>\n        <item quantity=\"one\">%1$d minūti</item>\n        <item quantity=\"other\">%1$d minūtes</item>\n    </plurals>\n    <string name=\"data_usage_msg\">Izmantotais datu apjoms</string>\n    <string name=\"package_name\">Lietotnes unikālais nosaukums</string>\n    <string name=\"license\">Licence</string>\n    <string name=\"usage_weekly\">Nedēļas</string>\n    <string name=\"usage_access\">Piekļuve lietojumu datiem</string>\n    <string name=\"usage_yesterday\">Vakardienas</string>\n    <string name=\"usage_times_opened\">Atvēršanas skaita</string>\n    <string name=\"usage_last_used\">Pēdējo reizi lietota</string>\n    <string name=\"usage_mobile_data\">Izmantotā mobilo datu apjoma</string>\n    <string name=\"usage_wifi_data\">Izmantotā Wi-Fi datu apjoma</string>\n    <string name=\"installer_app\">Uzstādīšanas lietotne</string>\n    <string name=\"empty_package_name\">Tuksš lietotnes unikālais nosaukums</string>\n    <string name=\"no_usage_in_this_time_range\">Šajā laika diapazonā nav lietojumu datu</string>\n    <string name=\"installer_error_storage\">Nav pietiekami daudz krātuves vietas, lai uzstādītu lietotni</string>\n    <string name=\"installer_error_generic\">Uzstādīšana neizdevās</string>\n    <string name=\"usage_access_not_supported\">Nevarēja pieprasīt atļauju piekļūt lietošanas vēsturei, jo attiecīgā iestatījumu sadaļa neeksistē.</string>\n    <string name=\"installer\">Uzstādīšana</string>\n    <string name=\"installer_app_message\">Noklikšķiniet uz <b>Atlasīt</b>, lai izmantotu kādu no uzstādītajām lietotnēm, vai <b>Pielāgots</b>, lai ievadītu savu lietotnes unikālo nosaukumu.</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-nb-rNO/disclaimer.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- SPDX-License-Identifier: GPL-3.0-or-later --><resources>\n    <string name=\"disclaimer_footer\">© 2020–2024 Muntashir Al-Islam</string>\n    <string name=\"disclaimer_header\">ANSVARSFRASKRIVELSE</string>\n    <string name=\"disclaimer_exit\">Avslutt</string>\n    <string name=\"disclaimer_agree\">Jeg samtykker</string>\n    <string name=\"disclaimer_agree_forever\">Aldri vis dette igjen</string>\n    <string name=\"disclaimer_body\">App Manager tilbyr rot-funksjoner som kan skade enheten din hvis de brukes feil. App Manager er ikke ansvarlig for skader som følge av din bruk av programmet. Hvis du ikke er klar over hvordan superbrukertilgang virker, bør du unngå å bruke rot-funksjoner til du er klar over risikoene.\n\\n\n\\nAlle lenker til andre programmer og nettsider er der for å tjene brukerne. Jeg er ikke ansvarlig for innhold du måtte finne ved å bruke eksterne lenker.\n\\n\n\\nVed å bruke App Manager godtar du det fulle ansvaret for din egen bruk, og godtar at ingen garanti, krav eller erstatning vil bli gitt som følge av feil bruk.\n\\n\n\\nVed å bruke programmet, godtar du alt ansvar ved å bruke det, og godtar at jeg ikke er ansvarlig for noe du måtte foreta deg som kan ha en skadelig effekt på din enhet.</string>\n</resources>"
  },
  {
    "path": "app/src/main/res/values-nb-rNO/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- SPDX-License-Identifier: GPL-3.0-or-later --><resources xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:tools=\"http://schemas.android.com/tools\">\n    <string name=\"_lang_tag\" translatable=\"false\">nb-NO</string>\n    <string name=\"choose_language\">Endre språk</string>\n    <string name=\"auto\">Automatisk</string>\n    <string name=\"pref_app_language\">Språk</string>\n    <string name=\"backup_all_users\">Alle brukere</string>\n    <string name=\"installer_error_security\">Får ikke tilgang til APK-filer</string>\n    <string name=\"failed_to_fetch_package_info\">Kunne ikke hente pakkeinfo</string>\n    <string name=\"installer_error_generic\">Installasjon mislyktes</string>\n    <string name=\"installer_error_storage\">Utilstrekkelig lagringsplass igjen til installering av programmet</string>\n    <string name=\"installer_error_bad_apks\">Ugyldige APK-filer valgt</string>\n    <string name=\"installer_error_incompatible\">Programmet er ukompatibelt med enheten</string>\n    <string name=\"installer_error_blocked\">Installasjon blokkert av <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g></string>\n    <string name=\"filter_apps_with_activities\">Med aktiviteter</string>\n    <string name=\"are_you_sure\">Er du sikker\\?</string>\n    <string name=\"pref_remove_all_rules\">Fjern alle regler</string>\n    <string name=\"website\">Nettside</string>\n    <string name=\"run_in_termux\">Kjør i Termux</string>\n    <string name=\"open_in_termux\">Åpne i Termux</string>\n    <string name=\"backup_restore\">Sikkerhetskopier/gjenopprett</string>\n    <string name=\"clear_data\">Tøm data</string>\n    <string name=\"user_and_uid\">Bruker: <xliff:g id=\"user_name\" example=\"root\">%1$s</xliff:g> (<xliff:g id=\"user_id\" example=\"0\">%2$d</xliff:g>)</string>\n    <string name=\"memory_virtual_memory\">Minne: %1$s, virtuelt minne: %2$s</string>\n    <string name=\"kill_process\">Drep</string>\n    <string name=\"running_apps\">Kjørende programmer</string>\n    <string name=\"apk_updater\">APK-oppdaterer</string>\n    <string name=\"usage_yesterday\">I går</string>\n    <string name=\"app_settings\">Innstillinger</string>\n    <string name=\"app_size\">Program</string>\n    <string name=\"stopped\">Stoppet</string>\n    <string name=\"uninstall_system_app_message\">Dette er et systemprogram. Er du sikker på at du vil avinstallere dette programmet\\?</string>\n    <string name=\"uninstalled_successfully\"><xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g> har blitt avinstallert.</string>\n    <string name=\"failed_to_uninstall\">Klarte ikke å avinstallere <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g>.</string>\n    <string name=\"uninstall_app_message\">Ønsker du å avinstallere dette programmet\\?</string>\n    <string name=\"view_in_settings\">Vis i innstillinger</string>\n    <string name=\"disabled_app\">Avskrudd</string>\n    <string name=\"type_string\">Tegn</string>\n    <string name=\"type_long\">Heltall (long)</string>\n    <string name=\"type_int\">Heltall</string>\n    <string name=\"done\">Ferdig</string>\n    <string name=\"add_item\">Legg til element</string>\n    <string name=\"select_type\">Velg en type</string>\n    <string name=\"search\">Søk</string>\n    <string name=\"credits\">Bidragsytere</string>\n    <string name=\"third_party\">Tredjepartsbibliotek og ikoner</string>\n    <string name=\"license\">Lisens</string>\n    <string name=\"icon_picker\">Ikonvelger</string>\n    <string name=\"class_name\">Klassenavn</string>\n    <string name=\"package_name\">Pakkenavn</string>\n    <string name=\"shortcut_name\">Snarveisnavn</string>\n    <string name=\"create_shortcut\">Opprett snarvei</string>\n    <string name=\"error_verbose_pin_shortcut\">Nåværende oppstarter støtter ikke PinShortcut. Klarte ikke å opprette snarvei.</string>\n    <string name=\"error_creating_shortcut\">Klarte ikke å opprette snarvei</string>\n    <string name=\"empty_package_name\">Tomt pakkenavn</string>\n    <string name=\"main_activity\">Hovedaktivitet</string>\n    <string name=\"user_id\">Bruker-ID</string>\n    <string name=\"installer_app\">Installasjonsprogram</string>\n    <string name=\"date_updated\">Dato oppdatert</string>\n    <string name=\"date_installed\">Dato installert</string>\n    <string name=\"more_info\">Mer info</string>\n    <string name=\"sdk_flags\">Flagg</string>\n    <string name=\"sdk_max\">Mål</string>\n    <string name=\"sdk_min\">Min.</string>\n    <string name=\"data_dir\">Datamappe</string>\n    <string name=\"source_dir\">Kildemappe</string>\n    <string name=\"paths_and_directories\">Stier og mapper</string>\n    <string name=\"user_app\">Brukerprogram</string>\n    <string name=\"system_app\">Systemprogram</string>\n    <string name=\"app_info\">Programinfo</string>\n    <string name=\"version_name_with_code\">Versjon <xliff:g id=\"version_name\" example=\"2.5.17\">%1$s</xliff:g> (<xliff:g id=\"version_code\" example=\"365\">%2$d</xliff:g>)</string>\n    <string name=\"sort\">Sorter</string>\n    <string name=\"user\">Bruker</string>\n    <string name=\"system\">System</string>\n    <string name=\"app_not_installed\">Program ikke installert</string>\n    <string name=\"media_size\">Media</string>\n    <string name=\"cache_size\">Hurtiglager</string>\n    <string name=\"data_size\">Data</string>\n    <string name=\"about\">Om</string>\n    <string name=\"data_usage_msg\">Databruk</string>\n    <string name=\"data_transmitted\">Data overført</string>\n    <string name=\"data_received\">Data mottatt</string>\n    <string name=\"sort_by_target_sdk\">Mål-SDK</string>\n    <string name=\"sort_by_package_name\">Pakkenavn</string>\n    <string name=\"sort_by_app_label\">Progametikett</string>\n    <string name=\"loading\">Laster inn …</string>\n    <string name=\"error\">Feil</string>\n    <string name=\"manifest\">Manifest</string>\n    <string name=\"input_features\">Inndatafunksjoner</string>\n    <string name=\"no_configurations\">Ingen oppsett</string>\n    <string name=\"configurations\">Oppsett</string>\n    <string name=\"app_signing_no_signatures\">Ingen gyldige signaturer</string>\n    <string name=\"signatures\">Signaturer</string>\n    <string name=\"sort_by_sha\">Signatur</string>\n    <string name=\"shared_user_id\">Delt bruker-ID</string>\n    <string name=\"sort_by_shared_user_id\">Delt bruker-ID</string>\n    <string name=\"no_feature\">Ingen funksjoner</string>\n    <string name=\"group\">Gruppe</string>\n    <string name=\"shared_libs\">Delte bibliotek</string>\n    <string name=\"declared_permission\">Tilganger</string>\n    <string name=\"patterns_allowed\">Mønster tillat</string>\n    <string name=\"write\">Skriv</string>\n    <string name=\"read\">Les</string>\n    <string name=\"path_permissions\">Sti-tilganger</string>\n    <string name=\"grant_uri_permission\">Innvilg URI-tilganger</string>\n    <string name=\"flags\">Flagg</string>\n    <string name=\"orientation\">Retning</string>\n    <string name=\"no_service\">Ingen tjenester</string>\n    <string name=\"service\">Tjenester</string>\n    <string name=\"sort_by_last_update\">Siste oppdatering</string>\n    <string name=\"launch_mode\">Startmodus</string>\n    <string name=\"no_providers\">Ingen tilbydere</string>\n    <string name=\"providers\">Tilbydere</string>\n    <string name=\"no_receivers\">Ingen mottagere</string>\n    <string name=\"receivers\">Mottagere</string>\n    <string name=\"no_activities\">Ingen aktiviteter</string>\n    <string name=\"refresh\">Gjenoppfrisk</string>\n    <string name=\"launch\">Start</string>\n    <string name=\"activities\">Aktiviteter</string>\n    <string name=\"require_no_permission\">Ingen tilganger kreves</string>\n    <string name=\"uninstall\">Avinstaller</string>\n    <string name=\"orientation_sensor_portrait\">Sensor stående</string>\n    <string name=\"orientation_sensor_landscape\">Sensor liggende</string>\n    <string name=\"orientation_user_portrait\">Bruker stående</string>\n    <string name=\"orientation_user_landscape\">Bruker liggende</string>\n    <string name=\"orientation_user\">Bruker</string>\n    <string name=\"orientation_reverse_landscape\">Omvendt liggende</string>\n    <string name=\"orientation_reverse_portrait\">Omvendt stående</string>\n    <string name=\"orientation_portrait\">Stående</string>\n    <string name=\"orientation_landscape\">Liggende</string>\n    <string name=\"required\">Påkrevd</string>\n    <string name=\"keyboard_qwerty\">QWERTY</string>\n    <string name=\"_undefined\">Udefinert</string>\n    <string name=\"keyboard_no_keys\">Ingen taster</string>\n    <string name=\"navigation_wheel\">Hjul</string>\n    <string name=\"navigation_trackball\">Rulleball</string>\n    <string name=\"touchscreen_stylus\">Pekepenn</string>\n    <string name=\"touchscreen_finger\">Finger</string>\n    <string name=\"orientation_sensor\">Sensor</string>\n    <string name=\"backup\">Sikkerhetskopier</string>\n    <string name=\"data\">Data</string>\n    <string name=\"external_data\">Ekstern data</string>\n    <string name=\"blocking_rules\">Blokkeringsregler</string>\n    <string name=\"whats_new\">Hva er nytt\\?</string>\n    <string name=\"features\">Funksjoner</string>\n    <string name=\"components\">Komponenter</string>\n    <string name=\"trackers\">Sporere</string>\n    <string name=\"installed_version\">Installert versjon</string>\n    <string name=\"select_all\">Velg alle</string>\n    <string name=\"filter_apps_with_rules\">Programmer med regler</string>\n    <string name=\"filter_system_apps\">Systemprogrammer</string>\n    <string name=\"filter_user_apps\">Brukerprogrammer</string>\n    <string name=\"authority\">Autoritet</string>\n    <string name=\"permissions\">Brukstilganger</string>\n    <string name=\"key_name\">Nøkkelnavn</string>\n    <string name=\"integer_value\">Heltallsverdi</string>\n    <string name=\"string_value\">Streng-verdi</string>\n    <string name=\"saving_failed\">Lagring mislyktes, prøv igjen.</string>\n    <string name=\"saved_successfully\">Lagret</string>\n    <string name=\"deletion_failed\">Sletting mislyktes</string>\n    <string name=\"deleted_successfully\">Slettet</string>\n    <string name=\"delete\">Slett</string>\n    <string name=\"discard\">Forkast</string>\n    <string name=\"save\">Lagre</string>\n    <string name=\"databases\">Databaser</string>\n    <string name=\"touchscreen_no_touch\">Ingen berøring</string>\n    <string name=\"obb_files_extracted_successfully\">OBB-filer pakket ut</string>\n    <string name=\"failed_to_extract_obb_files\">Kunne ikke pakke ut OBB-filer</string>\n    <string name=\"backup_obb_media\">OBB og media</string>\n    <string name=\"backup_apk_files\">APK-filer</string>\n    <string name=\"unblock_trackers\">Avblokker sporere</string>\n    <string name=\"reinstall\">Reinstaller</string>\n    <string name=\"install_app_message\">Ønsker du å installere dette programmet\\?</string>\n    <string name=\"try_again\">Prøv igjen</string>\n    <string name=\"export_icon\">Pakk ut ikon</string>\n    <string name=\"unblock\">Avblokker</string>\n    <string name=\"block\">Blokker</string>\n    <string name=\"clear\">Tøm</string>\n    <string name=\"skip_signature_checks\">Hopp over signatursjekker</string>\n    <string name=\"yes\">Ja</string>\n    <string name=\"no\">Nei</string>\n    <plurals name=\"alert_failed_to_delete_backup\">\n        <item quantity=\"one\">Kunne ikke slette %1$d sikkerhetskopi</item>\n        <item quantity=\"other\">Kunne ikke slette %1$d sikkerhetskopier</item>\n    </plurals>\n    <string name=\"delete_backup\">Slett sikkerhetskopi</string>\n    <string name=\"restore\">Gjenopprett</string>\n    <string name=\"block_components_dots\">Blokker komponenter …</string>\n    <string name=\"clear_cache\">Tøm hurtiglager</string>\n    <string name=\"source_code\">Kildekode</string>\n    <string name=\"changelog\">Endringslogg</string>\n    <string name=\"never_ask\">Aldri spør</string>\n    <string name=\"launch_app\">Kjør</string>\n    <string name=\"failed_to_revoke_permission\">Kunne ikke tilbakekalle tilgang</string>\n    <string name=\"failed_to_grant_permission\">Kunne ikke innvilge tilgang</string>\n    <string name=\"sort_by_tracker_components\">Sporere først</string>\n    <string name=\"unknown_op\">Ukjent operasjon</string>\n    <string name=\"deny_dangerous_permissions\">Nekt farlige tilganger</string>\n    <string name=\"sort_by_denied_permissions\">Nektet først</string>\n    <string name=\"sort_by_dangerous_permissions\">Farlige først</string>\n    <string name=\"sort_by_permission_names\">Tilgangsnavn</string>\n    <string name=\"reset_to_default\">Tilbakestill til forvalg</string>\n    <string name=\"sort_by_component_name\">Komponentnavn</string>\n    <string name=\"block_trackers\">Blokker sporere</string>\n    <string name=\"sort_by_wifi_data\">Wi-Fi-data</string>\n    <string name=\"version\">Versjon</string>\n    <string name=\"apply\">Bruk</string>\n    <string name=\"select_theme\">Drakt</string>\n    <string name=\"night\">Natt</string>\n    <string name=\"day\">Dag</string>\n    <string name=\"battery_mode\">Batterimodus</string>\n    <string name=\"follow_system\">Følg system</string>\n    <string name=\"pref_app_theme\">Programdrakt</string>\n    <string name=\"touchscreen\">Pekeskjerm</string>\n    <string name=\"navigation\">Navigasjon</string>\n    <string name=\"keyboard_type\">Tastaturtype</string>\n    <string name=\"duration\">Varighet</string>\n    <string name=\"running\">Kjører</string>\n    <string name=\"mode\">Modus</string>\n    <string name=\"permission_name\">Tilgangsnavn</string>\n    <string name=\"the_operation_was_successful\">Ferdig</string>\n    <plurals name=\"alert_failed_to_uninstall\">\n        <item quantity=\"one\">Kunne ikke avinstallere %1$d program</item>\n        <item quantity=\"other\">Kunne ikke avinstallere %1$d programmer</item>\n    </plurals>\n    <plurals name=\"failed_to_import_files\">\n        <item quantity=\"one\">Kunne ikke importere %1$d fil.</item>\n        <item quantity=\"other\">Kunne ikke importere %1$d filer.</item>\n    </plurals>\n    <string name=\"pref_import_blocker\">Importer fra Blocker</string>\n    <string name=\"pref_import_watt\">Importer fra Watt</string>\n    <string name=\"sort_by_mobile_data\">Mobildata</string>\n    <string name=\"sort_by_times_opened\">Ganger åpnet</string>\n    <string name=\"sort_by_screen_time\">Skjermtid</string>\n    <string name=\"usage_access\">Brukstilgang</string>\n    <string name=\"str_logo\">Logo</string>\n    <string name=\"no_code\">Ingen kode</string>\n    <string name=\"process_name\">Prosessnavn</string>\n    <string name=\"dev_protected_data_dir\">Enhetsbeskyttet datamappe</string>\n    <string name=\"menu_apply_rules\">Legg til relger</string>\n    <string name=\"menu_remove_rules\">Fjern regler</string>\n    <string name=\"failed_to_extract_apk_file\">Kunne ikke hente ut APK-fil</string>\n    <string name=\"share_apk\">Del APK</string>\n    <string name=\"grant_usage_access\">Innvilg brukstilgang</string>\n    <string name=\"go_back\">Gå tilbake</string>\n    <string name=\"usage_less_than_a_minute\">Mindre enn ett minutt</string>\n    <plurals name=\"usage_hours\">\n        <item quantity=\"one\">%1$d t</item>\n        <item quantity=\"other\">%1$d t</item>\n    </plurals>\n    <plurals name=\"usage_days\">\n        <item quantity=\"one\">%1$d dag</item>\n        <item quantity=\"other\">%1$d dager</item>\n    </plurals>\n    <string name=\"usage_7_days\">Siste 7 dager</string>\n    <string name=\"sort_by_memory_usage\">Minnebruk</string>\n    <string name=\"sort_by_apps_first\">Programmer først</string>\n    <string name=\"sort_by_process_name\">Prosessnavn</string>\n    <string name=\"sort_by_process_id\">Prosess-ID</string>\n    <string name=\"filter_apps\">Programmer</string>\n    <string name=\"no_apps\">Ingen programmer</string>\n    <string name=\"apps\">Programmer</string>\n    <string name=\"apply_now\">Bruk nå…</string>\n    <string name=\"no_profiles\">Ingen profiler</string>\n    <string name=\"profiles\">Profiler</string>\n    <string name=\"open_pgp_provider\">OpenPGP-tilbyder</string>\n    <string name=\"cancel\">Avbryt</string>\n    <string name=\"ok\">OK</string>\n    <string name=\"input_backup_name\">Sikkerhetskopinavn</string>\n    <string name=\"downgrade\">Nedgrader</string>\n    <string name=\"process_state_with_extra\">Tilstand: <xliff:g id=\"process_state\" example=\"Sleeping\">%1$s</xliff:g> (<xliff:g id=\"state_extra\" example=\"High priority\">%2$s</xliff:g>)</string>\n    <string name=\"process_state\">Tilstand: <xliff:g id=\"process_state\" example=\"Sleeping\">%1$s</xliff:g></string>\n    <string name=\"state_high_priority\">Høy prioritet</string>\n    <string name=\"state_foreground\">Forgrunn</string>\n    <string name=\"state_low_priority\">Lav prioritet</string>\n    <string name=\"state_unknown\">Ukjent</string>\n    <string name=\"state_locked_memory\">Låst minne</string>\n    <string name=\"state_idle\">Ledig</string>\n    <string name=\"state_parked\">Parkert</string>\n    <string name=\"state_dead\">Død</string>\n    <string name=\"state_device_io\">Enhets-I/O</string>\n    <string name=\"orientation_no_sensor\">Ingen sensor</string>\n    <string name=\"orientation_locked\">Låst</string>\n    <string name=\"unknown_split_for_feature\"><xliff:g id=\"split_name\" example=\"some_split\">%1$s</xliff:g> for funksjonen <xliff:g id=\"feature_name\" example=\"Visualizer\">%2$s</xliff:g></string>\n    <string name=\"split_feature_name\">Funksjon: <xliff:g id=\"feature_name\" example=\"Visualizer\">%1$s</xliff:g></string>\n    <string name=\"installer_error_session_create\">Kunne ikke opprette installasjonsøkt</string>\n    <string name=\"install_in_progress\">Installasjon underveis</string>\n    <string name=\"package_installer\">Pakke-installerer</string>\n    <string name=\"installer_error_blocked_device\">enhet</string>\n    <string name=\"clear_data_message\">Er du sikker på at du vil tømme data fra dette programmet\\?</string>\n    <string name=\"apply_to_system_apps_question\">Bruk også for systemprogrammer\\? Velg \\\"Nei\\\" hvis du er usikker.</string>\n    <string name=\"apply_to_system_apps\">Bruk for systemprogrammer</string>\n    <plurals name=\"alert_failed_to_restore\">\n        <item quantity=\"one\">Kunne ikke gjenopprette %1$d program</item>\n        <item quantity=\"other\">Kunne ikke gjenopprette %1$d programmer</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_backup\">\n        <item quantity=\"one\">Kunne ikke sikkerhetskopiere %1$d program</item>\n        <item quantity=\"other\">Kunne ikke sikkerhetskopiere %1$d programmer</item>\n    </plurals>\n    <plurals name=\"failed_to_backup_some_apk_files\">\n        <item quantity=\"one\">Kunne ikke sikkerhetskopiere %1$d program</item>\n        <item quantity=\"other\">Kunne ikke sikkerhetskopiere %1$d programmer</item>\n    </plurals>\n    <string name=\"backup_options\">Sikkerhetskopieringsinnstillinger</string>\n    <string name=\"package_name_is_installed_successfully\"><xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g> installert</string>\n    <string name=\"termux\">Termux</string>\n    <string name=\"pref_import_existing\">Importer eksisterende regler</string>\n    <string name=\"update\">Oppdater</string>\n    <string name=\"install\">Installer</string>\n    <plurals name=\"no_of_trackers\">\n        <item quantity=\"one\">%1$d sporer</item>\n        <item quantity=\"other\">%1$d sporere</item>\n    </plurals>\n    <string name=\"export_failed\">Ekportering mislyktes!</string>\n    <string name=\"import_failed\">Importering mislyktes!</string>\n    <string name=\"export_options\">Eksporteringsinnstillinger</string>\n    <string name=\"import_options\">Importeringsinnstillinger</string>\n    <string name=\"pref_export\">Eksport</string>\n    <string name=\"pref_import\">Import</string>\n    <string name=\"ago\">siden</string>\n    <string name=\"pid_and_ppid\">Prosess-ID: %1$d. Foreldreprosess-ID: %2$d</string>\n    <string name=\"disable_background_run\">Forhindre bakgrunnskjøring</string>\n    <string name=\"the_export_was_successful\">Eksportert</string>\n    <string name=\"the_import_was_successful\">Importert</string>\n    <string name=\"pref_import_export_blocking_rules_msg\">Importer/eksporter regler, importer eksterne regler fra Watt eller Blocker.</string>\n    <string name=\"pref_import_export_blocking_rules\">Importer/eksporter blokkeringsregler</string>\n    <string name=\"sort_by_last_used\">Sist brukt</string>\n    <plurals name=\"no_of_times_opened\">\n        <item quantity=\"one\">%1$d gang</item>\n        <item quantity=\"other\">%1$d ganger</item>\n    </plurals>\n    <string name=\"external_multiple_data_dir\">Ekstern datamappe <xliff:g id=\"dir_no\" example=\"1\">%1$d</xliff:g></string>\n    <string name=\"external_data_dir\">Ekstern datamappe</string>\n    <string name=\"sort_by_blocked_components\">Blokkerte først</string>\n    <string name=\"exodus_link\">εxodus-lenke</string>\n    <string name=\"failed_to_stop\">Kunne ikke stoppe <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g>.</string>\n    <string name=\"force_stop\">Tving stopp</string>\n    <string name=\"enable\">Skru på</string>\n    <string name=\"disable\">Skru av</string>\n    <string name=\"no_content\">Mangler innhold</string>\n    <string name=\"boolean_value\">Boolsk verdi</string>\n    <string name=\"decimal_value\">Desimalverdi</string>\n    <string name=\"updated_app\">Oppdatert</string>\n    <string name=\"go\">Start</string>\n    <string name=\"usage_today\">I dag</string>\n    <string name=\"usage_weekly\">Ukentlig</string>\n    <string name=\"app_usage\">Programbruk</string>\n    <string name=\"no_tracker_class\">Ingen sporer-klasser</string>\n    <string name=\"no_shared_libs\">Ingen delte biblioteker</string>\n    <plurals name=\"main_list_date_days\">\n        <item quantity=\"one\"><xliff:g id=\"last_update_date\" example=\"20/10/2020\">%1$s</xliff:g> <xliff:g id=\"day_no\" example=\"5\">%2$d</xliff:g> dag</item>\n        <item quantity=\"other\"><xliff:g id=\"last_update_date\" example=\"20/10/2020\">%1$s</xliff:g> <xliff:g id=\"day_no\" example=\"5\">%2$d</xliff:g> dager</item>\n    </plurals>\n    <string name=\"all_classes\">Alle klasser</string>\n    <string name=\"tracker_classes\">Sporer-klasser</string>\n    <string name=\"tracker_details\">Sporer-detaljer</string>\n    <string name=\"select_apk\">Velg APK</string>\n    <string name=\"send_crash_report\">Send krasjrapport</string>\n    <string name=\"filter_running_apps\">Kjørende programmer</string>\n    <string name=\"copy\">Kopier</string>\n    <string name=\"tap_to_see_details\">Trykk for å se detaljer</string>\n    <string name=\"lib_details\">Biblioteksdetaljer</string>\n    <string name=\"no_libs\">Ingen bibliotek</string>\n    <string name=\"scanner\">Skanner</string>\n    <string name=\"sys_config\">Systemoppsett</string>\n    <string name=\"app_data_will_be_lost\">Eksisterende data vil gå tapt.</string>\n    <string name=\"do_you_want_to_uninstall_and_install\">Ønsker du å avinstallere og installere programmet igjen\\?</string>\n    <string name=\"format\">Format</string>\n    <string name=\"public_key\">Offentlig nøkkel</string>\n    <string name=\"algorithm\">Algoritme</string>\n    <string name=\"app_signing_signature\">Signatur</string>\n    <string name=\"checksums\">Sjekksummer</string>\n    <string name=\"serial_no\">Serienummer</string>\n    <string name=\"not_yet_valid\">Ikke gyldig enda</string>\n    <string name=\"expired\">Utløpt</string>\n    <string name=\"valid\">Gyldig</string>\n    <string name=\"validity\">Gyldighet</string>\n    <string name=\"type\">Type</string>\n    <string name=\"expiry_date\">Utløpsdato</string>\n    <string name=\"issued_date\">Utstedelsesdato</string>\n    <string name=\"issuer\">Utsteder</string>\n    <string name=\"abi_split_for_feature\"><xliff:g id=\"split_name\" example=\"arm64_v8a\">%1$s</xliff:g> kode for <xliff:g id=\"feature_name\" example=\"Visualizer\">%2$s</xliff:g></string>\n    <plurals name=\"missing_signatures\">\n        <item quantity=\"one\">%1$d signatur mangler</item>\n        <item quantity=\"other\">%1$d signaturer mangler</item>\n    </plurals>\n    <plurals name=\"libraries\">\n        <item quantity=\"one\">%1$d bibliotek</item>\n        <item quantity=\"other\">%1$d bibliotek</item>\n    </plurals>\n    <plurals name=\"classes\">\n        <item quantity=\"one\">%1$d klasse</item>\n        <item quantity=\"other\">%1$d klasser</item>\n    </plurals>\n    <string name=\"failed_to_parse_some_numbers\">Noen tall kunne ikke tolkes</string>\n    <string name=\"clear_data_from_uninstalled_apps_description\">Tøm data fra avinstallerte programmer med <tt>DONT_DELETE_DATA</tt>-flagg</string>\n    <string name=\"clear_data_from_uninstalled_apps\">Tøm data fra avinstallerte programmer</string>\n    <string name=\"no_usage_in_this_time_range\">Ingen bruk i dette tidsrommet</string>\n    <string name=\"key_name_cannot_be_null\">Nøkkelnavn kan ikke stå tomt</string>\n    <string name=\"type_float\">Desimaltall</string>\n    <string name=\"shared_prefs\">Delte innstillinger</string>\n    <string name=\"test_only\">Kun for test</string>\n    <string name=\"debuggable\">Avlusbar</string>\n    <string name=\"credits_message\">Til utviklerne av\n\\n- Android Open Source-prosjektet\n\\n- <a href=\"https://github.com/butzist/ActivityLauncher\">Activity Launcher</a>\n\\n- <a href=\"https://bitbucket.org/oF2pks/fdroid-applications-info\">Apps_packages Info</a>\n\\n- <a href=\"https://github.com/zhaobao/AppsMonitor\">AppsMonitor</a>\n\\n- <a href=\"https://github.com/8enet/AppOpsX\">AppOpsX</a>\n\\n- <a href=\"https://github.com/billthefarmer/editor\">Editor</a>\n\\n- <a href=\"https://github.com/k3b/intent-intercept\">Intent Intercept</a>\n\\n- <a href=\"https://github.com/zhanghai/MaterialFiles\">Material Files</a>\n\\n- <a href=\"https://github.com/pluscubed/matlog\">MatLog</a>\n\\n- <a href=\"https://github.com/matrix-org/matrix-android-sdk\">Matrix Android SDK</a>\n\\n- <a href=\"https://github.com/jensstein/oandbackup\">OAndBackup</a>\n\\n- <a href=\"https://github.com/open-keychain/open-keychain\">Open Keychain</a>\n\\n- <a href=\"https://github.com/Aefyr/SAI\">SAI</a>\n\\n- <a href=\"https://github.com/RikkaApps/Shizuku\">Shizuku</a>\n\\n- <a href=\"https://github.com/tuyafeng/Watt\">Watt</a>\n\\nLogohenvisning: <a href=\"https://github.com/Atrate\">Atrate</a>. </string>\n    <string name=\"close\">Lukk</string>\n    <string name=\"user_profile_with_id\">Profil: %1$s (%2$d)</string>\n    <string name=\"advanced\">Avansert</string>\n    <string name=\"choose\">Velg</string>\n    <string name=\"options\">Innstillinger</string>\n    <string name=\"off\">Avslått</string>\n    <string name=\"on\">Påslått</string>\n    <string name=\"profile_state\">Profiltilstand</string>\n    <string name=\"rsa\">RSA</string>\n    <string name=\"aes\">AES</string>\n    <string name=\"encryption\">Kryptering</string>\n    <string name=\"select_user\">Velg bruker</string>\n    <string name=\"new_profile\">Ny profil</string>\n    <string name=\"input_profile_name_description\">Profilnavnet kan ikke inneholde mellomrom.</string>\n    <string name=\"input_profile_name\">Profilnavn</string>\n    <string name=\"full_stop_tap_to_see_details\">. Trykk for å se detaljer.</string>\n    <string name=\"no_matching_package_found\">Kunne ikke funne noe slik program</string>\n    <string name=\"failed_packages\">Feilede pakker</string>\n    <string name=\"no_tracker_found\">Fant ingen sporer</string>\n    <string name=\"clear_app_cache_description\">Tøm hurtiglager for alle programmer</string>\n    <string name=\"clear_app_cache\">Tøm programhurtiglager</string>\n    <plurals name=\"alert_failed_to_force_stop\">\n        <item quantity=\"one\">Kunne ikke påtvinge stopp av %1$d program</item>\n        <item quantity=\"other\">Kunne ikke påtvinge stopp av %1$d programmer</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_clear_data\">\n        <item quantity=\"one\">Kunne ikke tømme data fra %1$d program</item>\n        <item quantity=\"other\">Kunne ikke tømme data fra %1$d programmer</item>\n    </plurals>\n    <string name=\"export_blocking_rules\">Eksporter blokkeringsregler</string>\n    <string name=\"disable_background\">Forhindre bakgrunnskjøring</string>\n    <string name=\"found_trackers\">Fant disse sporerne:</string>\n    <plurals name=\"other_trackers_and_classes\">\n        <item quantity=\"one\"><xliff:g id=\"tracker_no\" example=\"8\">%1$d</xliff:g> sporere med <xliff:g id=\"class_no\" example=\"50\">%2$d</xliff:g> klasser</item>\n        <item quantity=\"other\"><xliff:g id=\"tracker_no\" example=\"8\">%1$d</xliff:g> sporere med <xliff:g id=\"class_no\" example=\"50\">%2$d</xliff:g> klasser</item>\n    </plurals>\n    <plurals name=\"two_trackers_and_classes\">\n        <item quantity=\"one\">2 sporere med <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g> klasser</item>\n        <item quantity=\"other\">2 sporere med <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g> klasser</item>\n    </plurals>\n    <plurals name=\"tracker_and_classes\">\n        <item quantity=\"one\">1 sporer med <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g> klasse</item>\n        <item quantity=\"other\">1 sporer med <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g> klasser</item>\n    </plurals>\n    <string name=\"word_wrap\">Veksle linjebryting</string>\n    <string name=\"starting_activity\">Startaktivitet: <xliff:g id=\"activity_name\" example=\".main.MainActivity\">%1$s</xliff:g></string>\n    <string name=\"pref_sign_apk_msg\">Signer APK-filer før de installeres</string>\n    <string name=\"pref_sign_apk\">Signer APK</string>\n    <string name=\"adb_over_tcp\">ADB over TCP</string>\n    <string name=\"pref_mode_of_operations\">Operasjonsmodus</string>\n    <string name=\"send_selected\">Send valgte</string>\n    <string name=\"ecc\">Elliptisk kurve-kryptografi</string>\n    <string name=\"un_apkm\">UnApkm</string>\n    <string name=\"in_progress\">Underveis</string>\n    <string name=\"subject\">Emne</string>\n    <string name=\"confirm_installation\">Bekreft installasjon</string>\n    <string name=\"rules\">Regler</string>\n    <string name=\"changes_not_saved\">Endringer ble ikke lagret</string>\n    <string name=\"state_multithreaded\">Flertrådet</string>\n    <string name=\"launch_mode_single_task\">Enkelt oppgave</string>\n    <string name=\"installer_error_session_abandon\">Kunne ikke forlate installasjonsøkten</string>\n    <string name=\"installer_error_session_write\">Kunne ikke skrive til installasjonsøkt</string>\n    <string name=\"operation_running\">Operasjon kjører …</string>\n    <plurals name=\"alert_failed_to_block_components\">\n        <item quantity=\"one\">Kunne ikke blokkere komponenter for %1$d program</item>\n        <item quantity=\"other\">Kunne ikke blokkere komponenter for %1$d programmer</item>\n    </plurals>\n    <string name=\"manifest_viewer\">Manifest-viser</string>\n    <string name=\"rules_not_applied\">Regler ikke tillagt</string>\n    <string name=\"not_verified\">Ikke bekreftet</string>\n    <string name=\"verified\">Bekreftet</string>\n    <string name=\"pref_compression_method\">Kompresjonsmetode</string>\n    <string name=\"task_affinity\">Oppgavetilknytning</string>\n    <string name=\"systemless_app\">Systemløst program</string>\n    <string name=\"filter_apps_without_backups\">Programmer uten sikkerhetskopier</string>\n    <string name=\"uninstalled_apps\">Avinstallerte programmer</string>\n    <string name=\"isolated\">Isolert</string>\n    <string name=\"installed_apps\">Installerte programmer</string>\n    <string name=\"failed_to_change_ssaid\">Kunne ikke endre SSAID</string>\n    <string name=\"os_version\">OS-versjon</string>\n    <string name=\"add\">Legg til</string>\n    <string name=\"type_uri\">URI</string>\n    <string name=\"type_string_array_list\">Strengliste</string>\n    <string name=\"type_component_name\">Komponentnavn</string>\n    <string name=\"type_null\">Ingen verdi</string>\n    <string name=\"back_up\">Sikkerhetskopier …</string>\n    <string name=\"restore_all\">Gjenopprett alle programmer</string>\n    <string name=\"backup_apps_with_changes\">Sikkerhetskopier programmer med endringer</string>\n    <string name=\"redo_existing_backups\">Gjenta eksisterende sikkerhetskopier</string>\n    <string name=\"verify_and_redo_backups\">Bekreft og gjenta sikkerhetskopier</string>\n    <string name=\"backup_apps_without_backups_msg\">Sikkerhetskopier alle programmer uten tidligere sikkerhetskopier.</string>\n    <string name=\"backup_apps_without_backups\">Sikkerhetskopier alle programmer uten sikkerhetskopier</string>\n    <string name=\"backup_all_apps_msg\">Sikkerhetskopier alle installerte programmer.</string>\n    <string name=\"backup_all_apps\">Sikkerhetskopier alle brukere</string>\n    <string name=\"bootloader\">Oppstartslaster</string>\n    <string name=\"encrypted\">Kryptert</string>\n    <string name=\"unencrypted\">Ukryptert</string>\n    <string name=\"size\">Størrelse</string>\n    <string name=\"security\">Sikkerhet</string>\n    <string name=\"battery\">Batteri</string>\n    <string name=\"graphics\">Grafikk</string>\n    <string name=\"cpu\">Prosessor</string>\n    <string name=\"users\">Brukere</string>\n    <string name=\"languages\">Språk</string>\n    <string name=\"battery_capacity\">Kapasitet</string>\n    <string name=\"memory\">Minne</string>\n    <string name=\"no_of_cores\">Kjerner</string>\n    <string name=\"support_architectures\">Støttede arkitekturer</string>\n    <string name=\"security_providers\">Sikkerhetstilbydere</string>\n    <string name=\"manufacturer\">Fabrikant</string>\n    <string name=\"kernel\">Kjerne</string>\n    <string name=\"model\">Modell</string>\n    <string name=\"brand_name\">Merke</string>\n    <string name=\"about_device\">Om enheten</string>\n    <string name=\"share\">Del</string>\n    <string name=\"category\">Kategorier</string>\n    <string name=\"uri\">URI</string>\n    <string name=\"action\">Handling</string>\n    <string name=\"value\">Verdi</string>\n    <string name=\"keep_data_and_app_signing_signatures\">Behold data og signaturer</string>\n    <string name=\"apk_signing\">APK-signering</string>\n    <string name=\"comment\">Kommentar</string>\n    <string name=\"pref_encryption_msg\">Legg til knryptering for sikkerhetskopier.</string>\n    <string name=\"tap_to_submit_crash_report\">Trykk for å sende inn krasjrapporten.</string>\n    <string name=\"am_crashed\">App Manager har akkurat krasjet</string>\n    <string name=\"only_install\">Kun installer</string>\n    <string name=\"app_signing_signature_mismatch_for_system_apps\">Kunne ikke installere program fordi et systemprogram med en annen signatur har dette pakkenavnet.</string>\n    <string name=\"allow_open_pgp_operation\">Klikk for å tillate App Manager å bruke OpenPGP</string>\n    <string name=\"storage_and_cache\">Lagring og huriglagring</string>\n    <string name=\"user_with_id\">Bruker: <xliff:g id=\"user_id\" example=\"0\">%1$d</xliff:g></string>\n    <string name=\"pref_global_blocking_enabled_msg\">Lar deg blokkere enhver komponent i enhver app uten å måtte skru på blokkering for appen.</string>\n    <string name=\"pref_global_blocking_enabled\">Umiddelbar komponent-blokkering</string>\n    <string name=\"failed_to_disable_op\">Kunne ikke skru av forespurt app-operasjon</string>\n    <string name=\"failed_to_enable_op\">Kunne ikke sette i verk forespurt app-operasjon</string>\n    <string name=\"no_app_ops\">Ingen app-operasjoner</string>\n    <string name=\"app_ops\">App-operasjoner</string>\n    <string name=\"total_size\">Total</string>\n    <string name=\"error_evaluating_input\">Kunne ikke vurdere inngang</string>\n    <string name=\"type_boolean\">Sant/usant</string>\n    <string name=\"long_integer_value\">Lang heltallsverdi</string>\n    <string name=\"requested_large_heap\">Stor haug</string>\n    <string name=\"native_library_dir\">Innfødt JNL Bibliotekmappe</string>\n    <string name=\"grant_usage_acess_message\">Brukt til å vise info om bruk av program.</string>\n    <plurals name=\"usage_months\">\n        <item quantity=\"one\">%1$d md</item>\n        <item quantity=\"other\">%1$d md</item>\n    </plurals>\n    <string name=\"toggle_class_listing\">Endre klasseliste</string>\n    <string name=\"class_viewer\">Klasse-betrakter</string>\n    <string name=\"obb_size\">Obb</string>\n    <string name=\"sort_by_domain\">Bruker-programmer først</string>\n    <string name=\"uses_feature\">Brukerfunksjoner</string>\n    <string name=\"soft_input\">Soft Input modus</string>\n    <plurals name=\"no_of_components\">\n        <item quantity=\"one\">%1$d komponent</item>\n        <item quantity=\"other\">%1$d komponenter</item>\n    </plurals>\n    <string name=\"external_apk_no_app_op\">Ekstern APK har ikke noen app-operasjoner</string>\n    <string name=\"one_click_ops\">Ett-klikk Ops</string>\n    <string name=\"failed_to_deny_dangerous_app_ops\">Kunne ikke tilbakekalle alle farlige app-operasjoner</string>\n    <string name=\"failed_to_deny_dangerous_perms\">Kunne ikke tilbakekalle alle farlige tillatelser</string>\n    <string name=\"failed_to_reset_app_ops\">Kunne ikke tilbakestille app-operasjoner</string>\n    <plurals name=\"alert_failed_to_disable_trackers\">\n        <item quantity=\"one\">Kunne ikke deaktivere sporere fra %1$d app</item>\n        <item quantity=\"other\">Kunne ikke deaktivere sporere fra %1$d apper</item>\n    </plurals>\n    <string name=\"sort_by_app_ops_values\">App-operasjonsverdi</string>\n    <string name=\"sort_by_denied_app_ops\">Nektet først</string>\n    <string name=\"sort_by_app_ops_names\">App-operasjonsnavn</string>\n    <string name=\"deny_dangerous_app_ops\">Nekt farlige app-operasjoner</string>\n    <string name=\"pref_about_msg\">App-manager versjon, lisens, kreditter, osv.</string>\n    <string name=\"pref_import_blocker_msg\">Importer blokkerings-regler fra Blocker, hver fil inneholder regler for en enkelt pakke.</string>\n    <string name=\"pref_import_watt_msg\">Importer blokkerings-regler fra Watt, hver fil inneholder regler for en enkelt navngitt pakke som <tt>packagename.xml</tt> osv.</string>\n    <string name=\"pref_import_msg\">Importer tidligere eksporterte blokkerings-regler fra App-manager.</string>\n    <string name=\"pref_export_msg\">Eksporter blokkerings-regler innstilt innen App-manager til ekstern lagring.</string>\n    <string name=\"reject_time\">Avvis tid</string>\n    <string name=\"accept_time\">Godkjenn tid</string>\n    <string name=\"toggle_kill_for_system_apps\">Aktiver eller deaktiver tvungen avslutning av system-apper</string>\n    <plurals name=\"alert_failed_to_disable_background\">\n        <item quantity=\"one\">Kufnne ikke hindre ett program fra å kjøre i bakgrunnen</item>\n        <item quantity=\"other\">Kunne ikke hindre %1$d programmer fra å kjøre i bakgrunnen</item>\n    </plurals>\n    <string name=\"failed_to_uninstall_updates\">Kunne ikke avinstallere oppgraderinger for <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g>.</string>\n    <string name=\"abi_split_for_base_apk\"><xliff:g id=\"split_name\" example=\"arm64_v8a\">%1$s</xliff:g> kode for grunn-APK</string>\n    <string name=\"unknown_split_for_base_apk\"><xliff:g id=\"split_name\" example=\"some_split\">%1$s</xliff:g> for grunn-APK</string>\n    <string name=\"pref_enable_disable_features_msg\">Skru på eller av funksjoner i App Manager.</string>\n    <string name=\"enable_disable_features\">Skru på/av funksjoner</string>\n    <string name=\"ssaid\">SSAID</string>\n    <string name=\"initializing\">Starter …</string>\n    <string name=\"choose_what_to_do\">Velg foretagende.</string>\n    <string name=\"drm_free_apkm_msg\">APKM-filen er DRM-fri, og det er unødvendig å konvertere den til APKS.</string>\n    <string name=\"restore_msg\">Gjenopprett programmer med data</string>\n    <string name=\"backup_msg\">Sikkerhetskopier programmer med data</string>\n    <string name=\"redo_existing_backups_msg\">Gjenta sikkerhetskopi for installerte programmer med tidligere sikkerhetskopier.</string>\n    <string name=\"backup_custom_users_description\">Utfør sikkerhetskopier kun for de angitte brukerne</string>\n    <string name=\"pref_backup_restore_msg\">Tilpass sikkerhetskopiering/gjenoppretting.</string>\n    <string name=\"density\">Pikseltetthet</string>\n    <string name=\"patch_level\">Feilfiks-nivå</string>\n    <string name=\"backup_multiple_description\">Opprett egen <i>navngitt</i> sikkerhetskopi istedenfor grunn-sikkerhetskopien.</string>\n    <string name=\"backup_rules_description\">Sikkerhetskopier regler satt opp i App Manager.</string>\n    <string name=\"backup_external_data_description\">Sikkerhetskopier eksterne datamapper.</string>\n    <string name=\"backup_internal_data_description\">Sikkerhetskopier interne datamapper.</string>\n    <string name=\"pref_about_device_msg\">Grunnleggende enhetsinfo, inkludert Android-system, prosessor, GPU, minne, batteri, osv.</string>\n    <string name=\"set_custom_app_op\">Sett egendefinert app-operasjon</string>\n    <string name=\"mime_type\">Media-type</string>\n    <string name=\"result_code\">Resulterende kode</string>\n    <string name=\"non_critical_exts\">Ikke-kritiske utvidelser</string>\n    <string name=\"critical_exts\">Kritiske utvidelser</string>\n    <string name=\"deny_app_ops_description\">Sett et modus for app-operasjoner identifisert av de faste verdiene, f.eks. <tt>63</tt> eller <tt>RUN_IN_BACKGROUND</tt></string>\n    <string name=\"disable_background_run_description\">Setter <i>ignorert</i>-modus for følgende app-operasjoner: <tt>RUN_IN_BACKGROUND</tt> (fra Android 7.0) og <tt>RUN_ANY_IN_BACKGROUND</tt> (fra Android 9).</string>\n    <string name=\"set_mode_for_app_ops_dots\">Sett modus for app-operasjoner …</string>\n    <string name=\"no_app_ops_permission\">Ingen tilganger for visning av app-operasjoner</string>\n    <string name=\"toggle_default_app_ops\">Veksle forvalgte app-operasjoner</string>\n    <string name=\"pref_remove_all_rules_msg\">Tilganger vil bli innvilget, app-operasjoner og komponenter vil tilbakestilles til sine forvalgte verdier.</string>\n    <plurals name=\"alert_failed_to_set_app_ops\">\n        <item quantity=\"one\">Kunne ikke sette app-operasjoner for ett program</item>\n        <item quantity=\"other\">Kunne ikke sette app-operasjoner for %1$d programmer</item>\n    </plurals>\n    <string name=\"input_app_ops\">Skriv inn app-operasjoner</string>\n    <string name=\"uninstall_updates\">Avinstaller oppgraderinger</string>\n    <string name=\"state_session_leader\">Øktleder</string>\n    <string name=\"navigation_no_nav\">Ingen navigasjon</string>\n    <string name=\"orientation_full_user\">Fullbruker</string>\n    <string name=\"orientation_full_sensor\">Full-sensor</string>\n    <string name=\"base_apk\">Grunn-APK</string>\n    <string name=\"only_works_in_root_or_adb_mode\">Fungerer kun i rot- eller ADB-modus</string>\n    <string name=\"backup_apk_files_description\">Sikkerhetskopier APK-filer med kildemappe, inkludert oppdelinger.</string>\n    <string name=\"filter_apps_with_splits\">Med oppdelinger</string>\n    <string name=\"splits\">Oppdelinger</string>\n    <plurals name=\"no_of_splits\">\n        <item quantity=\"one\">%1$d oppdeling</item>\n        <item quantity=\"other\">%1$d oppdelinger</item>\n    </plurals>\n    <string name=\"magisk_hide_enabled\">MagiskHide</string>\n    <string name=\"this_action_cannot_be_undone\">Denne handlingen kan ikke angres.</string>\n    <string name=\"input_keystore_alias_pass_msg\">Trykk her for å angi passord for %1$s</string>\n    <string name=\"input_keystore_alias_pass\">Passord for alias <b>%1$s</b></string>\n    <string name=\"no_root\">Ingen rot-tilgang</string>\n    <string name=\"root\">Rot-tilgang</string>\n    <string name=\"simple\">Enkel</string>\n    <string name=\"enabled\">Påskrudd</string>\n    <string name=\"profile_block_trackers_msg\">Blokker sporerne i programmer</string>\n    <string name=\"profile_clear_data_msg\">Tømmer programmers data</string>\n    <string name=\"profile_clear_cache_msg\">Tømmer programmers hurtiglagre</string>\n    <string name=\"profile_force_stop_msg\">Tvinger avslutning av programmer</string>\n    <string name=\"none\">Ingen</string>\n    <string name=\"failed_to_duplicate_profile\">Kunne ikke duplisere profil</string>\n    <string name=\"duplicate\">Dupliser</string>\n    <string name=\"conversion_failed\">Konvertering mislyktes.</string>\n    <string name=\"filter_apps_with_backups\">Med sikkerhetskopier</string>\n    <string name=\"sort_by_backup\">Sikkerhetskopiert først</string>\n    <string name=\"orientation_unspecified\">Ikke angitt</string>\n    <string name=\"launch_mode_single_instance\">Enkel instans</string>\n    <string name=\"launch_mode_multiple\">Flere</string>\n    <string name=\"backup_multiple\">Sikkerhetskopier flere</string>\n    <string name=\"installer_error_conflict\">Kunne ikke installere program fordi pakkenavnet er i bruk</string>\n    <string name=\"block_unblock_trackers\">Blokker/avblokker sporere</string>\n    <plurals name=\"verified_with_warning\">\n        <item quantity=\"one\">Bekreftet med én advarselk</item>\n        <item quantity=\"other\">Bekreftet med %d advarsler</item>\n    </plurals>\n    <string name=\"filter\">Filtrer</string>\n    <string name=\"filtered_packages\">Filtrerte pakker</string>\n    <string name=\"block_unblock_trackers_description\">Blokker eller avblokker reklame- og sporingskomponenter i alle de installerte programmene</string>\n    <string name=\"pref_import_existing_msg\">Legg til komponenter avskrudd av andre programmer i App Manager. Vær forsiktig med dette verktøyet, siden det kan være mange falske positiver. Velg kun programmene du er sikker på.</string>\n    <string name=\"source_code_links\">GitHub: https://github.com/MuntashirAkon/AppManager\n\\nGitLab: https://gitlab.com/muntashir/AppManager\n\\nRiseup: https://0xacab.org/muntashir/AppManager\n\\nCodeberg: https://codeberg.org/muntashir/AppManager</string>\n    <string name=\"alias_pass\">Alias-passord</string>\n    <string name=\"choose_an_alias\">Velg et alias</string>\n    <string name=\"new_alias_password\">Nytt alias-passord</string>\n    <string name=\"import_key\">Importer nøkkel</string>\n    <string name=\"pem_file\">PEM-fil</string>\n    <string name=\"input_key_password\">Nøkkelpassord</string>\n    <string name=\"failed_to_load_key\">Kunne ikke laste inn nøkkelen.</string>\n    <string name=\"key_not_set\">Ikke satt.</string>\n    <string name=\"use_default\">Bruk forvalg</string>\n    <string name=\"crypto_key_size\">Nøkkelstørrelse</string>\n    <string name=\"failed_to_save_key\">Kunne ikke lagre nøkkel.</string>\n    <string name=\"generate_key\">Generer</string>\n    <string name=\"specify_custom_name\">Egendefinert</string>\n    <string name=\"last_actions\">Nylige handlinger</string>\n    <string name=\"copied_to_clipboard\">Kopiert til utklippstavle.</string>\n    <string name=\"enable_battery_optimization\">Skru på batterioptimisering\\?</string>\n    <string name=\"battery_optimization\">Batterioptimisering</string>\n    <string name=\"no_battery_optimization\">Ingen batterioptimisering</string>\n    <string name=\"type_float_array_list\">Liste over desimaltall</string>\n    <string name=\"screen_lock\">Skjermlås</string>\n    <string name=\"unlock_app_manager\">Lås opp App Manager</string>\n    <string name=\"sd_card\">SD-kort</string>\n    <string name=\"external_storage\">Eksternlagring</string>\n    <string name=\"internal_storage\">Internlagring</string>\n    <string name=\"restore_not_installed\">Gjenopprett ikke-installerte programmer</string>\n    <string name=\"backup_custom_users\">Egendefinerte brukere</string>\n    <string name=\"failed_to_enable_magisk_hide\">Kunne ikke skru på MagiskHide</string>\n    <string name=\"failed_to_disable_magisk_hide\">Kunne ikke skru av MagiskHide</string>\n    <string name=\"window_size\">Vindusstørrelse</string>\n    <string name=\"refresh_rate\">Oppfriskningsrate</string>\n    <string name=\"scaling_factor\">Skaleringsfaktor</string>\n    <string name=\"screen\">Skjerm</string>\n    <string name=\"hardware\">Maskinvare</string>\n    <string name=\"permissive\">Forlatelig</string>\n    <string name=\"enforcing\">Påtvingende</string>\n    <string name=\"selinux\">SELinux</string>\n    <string name=\"backup_obb_media_description\">Sikkerhetskopier OBB- og mediamapper.</string>\n    <string name=\"gles_version\">OpenGL ES-versjon</string>\n    <string name=\"install_location_prefer_external\">Foretrekk ekstern</string>\n    <string name=\"install_location_internal_only\">Kun intern</string>\n    <plurals name=\"alert_failed_to_unblock_trackers\">\n        <item quantity=\"one\">Kunne ikke avblokkere sporere fra ett program</item>\n        <item quantity=\"other\">Kunne ikke avblokkere sporere fra %1$d programmer</item>\n    </plurals>\n    <string name=\"internal_data\">Intern data</string>\n    <string name=\"omit_sensitive_info\">Utelat sensitiv info</string>\n    <string name=\"undo\">Angre</string>\n    <string name=\"pause_unpause\">Spill av/pause</string>\n    <string name=\"collapse_all\">Fold sammen alle</string>\n    <string name=\"expand_all\">Utvid alle</string>\n    <string name=\"file\">Fil</string>\n    <string name=\"settings\">Innstillinger</string>\n    <string name=\"send_log_title\">Send logg</string>\n    <string name=\"save_log\">Lagre logg</string>\n    <string name=\"save_as\">Lagre som …</string>\n    <string name=\"pref_expanded_by_default_title\">Utvid som forvalg</string>\n    <string name=\"pref_cat_configuration\">Oppsett</string>\n    <string name=\"pref_cat_appearance\">Utseende</string>\n    <string name=\"pref_cat_advanced\">Avansert</string>\n    <string name=\"manage_saved_logs\">Håndter lagrede logger</string>\n    <string name=\"log_saved\">Logg lagret.</string>\n    <string name=\"filter_choice_tag\">Etikett</string>\n    <string name=\"filter_choice_pid\">PID</string>\n    <string name=\"filter_choice\">Søk etter</string>\n    <string name=\"enter_good_filename\">Skriv inn et gyldig filnavn.</string>\n    <string name=\"enter_filename\">Skriv inn filnavn …</string>\n    <string name=\"delete_saved_log\">Slett lagrede logger</string>\n    <string name=\"copy_to_clipboard\">Kopier til utklippstavle</string>\n    <string name=\"keystore_pass\">Nøkkellager-passord</string>\n    <string name=\"keystore_file\">Nøkkellager-fil</string>\n    <string name=\"failed_to_initialize_key_store\">Kunne ikke starte App Manager KeyStore.</string>\n    <string name=\"add_to_profile\">Legg til i profil</string>\n    <string name=\"latest_backup\">Siste sikkerhetskopi</string>\n    <string name=\"gz_bz2_compressed\">%1$s sammenpakket</string>\n    <string name=\"pgp_aes_rsa_encrypted\">%1$s kryptert</string>\n    <string name=\"no_encryption\">Ingen kryptering</string>\n    <string name=\"trackers_unblocked_successfully\">Sporere er nå avblokkert</string>\n    <string name=\"trackers_blocked_successfully\">Sporere er nå blokkert</string>\n    <string name=\"failed_to_unblock_trackers\">Kunne ikke avblokkere sporere</string>\n    <string name=\"failed_to_block_trackers\">Kunne ikke blokkere sporere</string>\n    <string name=\"save_apk\">Lagre APK</string>\n    <string name=\"running_services\">Kjørende tjenester</string>\n    <string name=\"view_logs\">Vis loggføring</string>\n    <string name=\"share_log\">Del</string>\n    <string name=\"text_include_device_info\">Inkluder enhetsinfo</string>\n    <string name=\"text_filter_text\">Filtertekst</string>\n    <string name=\"text_filter_ellipsis\">Filtrer …</string>\n    <string name=\"subject_log_report\">Loggrapport</string>\n    <string name=\"dialog_compiling_log\">Kompilerer logg …</string>\n    <plurals name=\"file_deletion_confirmation\">\n        <item quantity=\"one\">Én fil vil bli slettet</item>\n        <item quantity=\"other\">%d filer vil bli slettet</item>\n    </plurals>\n    <string name=\"add_filter_ellipsis\">Legg til filter …</string>\n    <string name=\"add_filter\">Legg til filter</string>\n    <string name=\"allow_routine_ops_msg\">Tillat at profilen brukes i rutineoperasjonene</string>\n    <string name=\"allow_routine_ops\">Tillat rutineoperasjoner</string>\n    <string name=\"locale_split_for_base_apk\"><xliff:g id=\"split_name\" example=\"English\">%1$s</xliff:g> lokalitet for grunn-APK</string>\n    <string name=\"locale_split_for_feature\"><xliff:g id=\"split_name\" example=\"English\">%1$s</xliff:g> lokalitet for funksjonen <xliff:g id=\"feature_name\" example=\"Visualizer\">%2$s</xliff:g></string>\n    <string name=\"density_split_for_feature\"><xliff:g id=\"split_name\" example=\"xxdpi\">%1$s</xliff:g> (<xliff:g id=\"dpi_no\" example=\"480\">%2$d</xliff:g> DPI) ressurser for funksjonen <xliff:g id=\"feature_name\" example=\"Visualizer\">%3$s</xliff:g></string>\n    <string name=\"density_split_for_base_apk\"><xliff:g id=\"split_name\" example=\"xxdpi\">%1$s</xliff:g> (<xliff:g id=\"dpi_no\" example=\"480\">%2$d</xliff:g> DPI) ressurser for grunn-APK</string>\n    <string name=\"app_signing_signatures\">Signaturer</string>\n    <string name=\"invalid_rsa_key_size\">Ugyldig nøkkelstørrelse for RSA-kryptering. Nøkkelstørrelse kan enten være 1024, 2048, eller 4096 biter.</string>\n    <string name=\"invalid_aes_key_size\">Ugyldig nøkkelstørrelse for AES-kryptering. Nøkkelstørrelse kan enten være 128 eller 256 biter.</string>\n    <string name=\"screen_lock_not_enabled\">Velg en skjermlås i Android-innstillingene, eller tøm programdata.</string>\n    <string name=\"restart_to_reflect_changes\">Du må starte enheten på nytt umiddelbart for å bruke de nye endringene.</string>\n    <string name=\"ssaid_info\">SSAID (<tt>Settings.Secure.ANDROID_ID</tt>) er en enhetsidentifikator som tildeles hvert program (fra Android 8 «Oreo» osv). Det brukes ofte til å spore brukere.</string>\n    <string name=\"restore_latest_msg\">Gjenopprett allerede installerte programmer som har versjonskoder høyere enn allerede installert versjon.</string>\n    <string name=\"pref_backup_volume_msg\">Velg dataområdet eller disken der sikkerhetskopier skal lagres.</string>\n    <string name=\"backup_skip_signature_checks_description\">Gjenopprett sikkerhetskopier som enten ikke passerer sjekksumsbekreftelse, eller har forskjellige APK-signaturer enn deres tidligere sikkerhetskopier.</string>\n    <string name=\"backup_volume\">Sikkerhetskopier dataområde</string>\n    <string name=\"backup_extras_description\">Sikkerhetskopier programtilganger, batterisparings- og databruksinnstillinger, MagiskHide-status, SSAID, osv.</string>\n    <string name=\"app_signing_install_without_data_loss\">Hvis du har skrudd av signaturbekreftelse kan du bruke <b>Kun installer</b>-valget for å installere programmet uten å miste data.</string>\n    <string name=\"usage_access_not_supported\">Kunne ikke forespørre brukstilgang. Tilhørende innstillingsside finnes ikke.</string>\n    <string name=\"rsa_exponent\">Eksponent</string>\n    <string name=\"pref_backup_flags_msg\">Å legge til en forhåndsinnstilling for sikkerhetskopivalg lar deg unngå å velge flagg hver gang du sikkerhetskopierer/gjenoppretter.</string>\n    <string name=\"routine_ops\">Rutineoperasjoner</string>\n    <string name=\"state_sleeping\">Sover</string>\n    <string name=\"keyboard_12_keys\">12-taster</string>\n    <string name=\"orientation_behind\">Bak</string>\n    <string name=\"installer_error_lidl_rom\">Ditt ROM er ikke kompatibelt med Rootless Installer.</string>\n    <string name=\"installer_error_aborted\">Installasjon mislyktes enten fordi den ble avbrutt, eller fordi økten ble lukket uventet</string>\n    <string name=\"unable_to_save_log\">Klarte ikke å lagre logg. Skrev du inn et gyldig filnavn\\?</string>\n    <string name=\"omit_sensitive_info_summary\">Unnlat sensitiv info som vev-nettadresser, telefonnummer eller e-postadresser.</string>\n    <string name=\"text_include_dmesg\">Inkluder kjerne-logg</string>\n    <string name=\"profile_save_apk_msg\">Lagrer APK-filer i <tt>AppManager/apks</tt></string>\n    <string name=\"pref_rules_msg\">Umiddelbar blokkering, importer/eksporter/fjern regler, osv.</string>\n    <string name=\"failed\">Mislykket</string>\n    <string name=\"orientation_follow_locale\">Følg systemspråk</string>\n    <string name=\"hidden\">Skjult</string>\n    <string name=\"orientation_right_to_left\">Høyre til venstre</string>\n    <string name=\"orientation_left_to_right\">Venstre til høyre</string>\n    <string name=\"base_backup\">Grunn-sikkerhetskopi</string>\n    <string name=\"widget_start_recording\">Før opp\n\\nlogg</string>\n    <string name=\"widget_recording_in_progress\">Fører opp …</string>\n    <string name=\"toast_invalid_selection\">Ugyldig utvalg. Prøv igjen.</string>\n    <string name=\"toast_invalid_level\">Ugyldig nivånavn: %s</string>\n    <string name=\"pref_display_limit_hint\">Skriv inn et gyldig tall mellom %1$d og %2$d.</string>\n    <string name=\"pref_show_timestamp_title\">Vis PID og tidsstempel</string>\n    <string name=\"log_level\">Loggingsnivå</string>\n    <string name=\"log_cleared\">Loggføring tømt</string>\n    <string name=\"log_level_fatal\">Kritisk</string>\n    <string name=\"log_level_warn\">Advar</string>\n    <string name=\"log_level_info\">Info</string>\n    <string name=\"log_level_error\">Feil</string>\n    <string name=\"log_level_debug\">Avlusing</string>\n    <string name=\"filename\">Filnavn</string>\n    <string name=\"pk8_file\">PKCS #8 (PK8)-fil</string>\n    <string name=\"pem_and_pk8\">PEM og PKCS #8 (PK8)</string>\n    <string name=\"screen_lock_msg\">Lås App Manager ved bruk av Android-skjermlås</string>\n    <plurals name=\"app_signing_signature_schemes_pl\">\n        <item quantity=\"one\">Signaturkoding</item>\n        <item quantity=\"other\">Signaturkodinger</item>\n    </plurals>\n    <string name=\"pref_log_viewer_msg\">Sett opp visning av loggføring.</string>\n    <string name=\"log_viewer\">Loggviser</string>\n    <string name=\"signing_key\">Signeringsnøkkel</string>\n    <string name=\"country_name\" tools:ignore=\"TypographyOther\">Landsnavn (C)</string>\n    <string name=\"organization_name\">Organisasjonsnavn (O)</string>\n    <string name=\"organization_unit\">Organisasjonsenhet (OU)</string>\n    <string name=\"common_name\">Vanlig navn (CN)</string>\n    <string name=\"verified_using_unreliable_hash\">Bekreftet ved bruk av upålitelig sjekksum</string>\n    <string name=\"type_int_array_list\"/>\n    <string name=\"restore_latest\">Gjenopprett siste sikkerhetskopier</string>\n    <string name=\"restore_not_installed_msg\">Gjenopprett grunn-sikkerhetskopi for programmer som ikke er installert nå.</string>\n    <string name=\"restore_all_msg\">Gjenopprett grunn-sikkerhetskopi fra alle sikkerhetskopierte programmer.</string>\n    <string name=\"no_volumes_found\">Fant ingen dataområder med skrivetilgang.</string>\n    <string name=\"backup_cache_description\">Sikkerhetskopier <b>cache</b>, <b>no_cache</b> og <b>no_backup</b> mappene.</string>\n    <string name=\"activity_result\">Aktivitetsresultat</string>\n    <string name=\"v4_scheme\">v4-koding (siden Android 11)</string>\n    <string name=\"v3_scheme\">v3-koding (siden Android 9)</string>\n    <string name=\"v2_scheme\">v2-koding (siden Android 7.0)</string>\n    <string name=\"v1_scheme\">v1-koding (siden Android 1.0)</string>\n    <string name=\"pref_apk_signing_msg\">Sett signaturkoding, egendefinert signeringsnøkkel, osv.</string>\n    <string name=\"app_signing_signature_schemes\">Signaturkoding</string>\n    <string name=\"install_location\">Installasjonssted</string>\n    <string name=\"profile_state_msg\">Egendefinert av/på -tilstand for denne profilen.</string>\n    <string name=\"update_uninstalled_successfully\">Oppgraderinger for <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g> har blitt avinstallert.</string>\n    <string name=\"other\">Annet</string>\n    <plurals name=\"backup_exists_are_you_sure\">\n        <item quantity=\"one\">Sikkerhetskopi finnes allerede. Er du sikker\\?</item>\n        <item quantity=\"other\">Mer enn ett program har en sikkerhetskopi allerede. Er du sikker\\?</item>\n    </plurals>\n    <string name=\"no_changes\">Ingen endringer</string>\n    <string name=\"pref_log_line_period_error\">Skriv inn et heltall mellom 1 og 1000.</string>\n    <string name=\"pref_expanded_by_default_summary\">Vis full loggtekst som forvalg.</string>\n    <string name=\"community\">Gemenskap</string>\n    <string name=\"installer_error_session_commit\">Kunne ikke sende inn APK-filene</string>\n    <string name=\"community_links\">Telegram: https://t.me/AppManagerChannel\n\\nTwitter: https://twitter.com/AppManagerNews</string>\n    <string name=\"pref_display_changes\">Vis endringer</string>\n    <plurals name=\"alert_failed_to_import_backups\">\n        <item quantity=\"one\">Kunne ikke importere %1$d sikkerhetskopi</item>\n        <item quantity=\"other\">Kunne ikke importere %1$d sikkerhetskopier</item>\n    </plurals>\n    <string name=\"pref_log_write_period_title\">Skriveperiode</string>\n    <string name=\"pref_selected_users\">Valgte brukere</string>\n    <string name=\"added_to_queue\">Lagt til i kø</string>\n    <string name=\"saved_filters\">Lagrede filter</string>\n    <string name=\"permission_flags\">Tilgangsflagg</string>\n    <string name=\"pref_default_log_level_title\">Forvalgt loggføringsnivå</string>\n    <string name=\"import_from_tb\">Importer fra Titanium Backup</string>\n    <string name=\"import_from_oab\">Importer fra OAndBackup</string>\n    <string name=\"pref_import_backups\">Importer sikkerhetskopier</string>\n    <string name=\"expiry_date_cannot_be_empty\">Utløpsdato kan ikke stå tom.</string>\n    <string name=\"pid\">Prosess-ID</string>\n    <string name=\"pref_always_on_background\">Installer i bakgrunnen</string>\n    <string name=\"next\">Neste</string>\n    <string name=\"port_number_invalid\">Ugyldig portnummer.</string>\n    <string name=\"netpolicy_disable_network_access\">Skru av nettverkstilgang</string>\n    <string name=\"netpolicy_reject_wifi_data\">Avslå Wi-Fi-data</string>\n    <string name=\"netpolicy_reject_vpn_data\">Avslå VPN-data</string>\n    <string name=\"pref_import_backups_msg\">Importer sikkerhetskopier fra OAndBackup, Swift Backup (3.0–3.2) eller Titanium Backup.</string>\n    <string name=\"port_number\">Port</string>\n    <string name=\"minimum_version\">Min. versjon: %d</string>\n    <string name=\"working_on_adb_mode\">Arbeider i ADB-modus</string>\n    <string name=\"log_level_verbose\">Sirlig</string>\n    <string name=\"open\">Åpne</string>\n    <string name=\"input_signatures\">Signaturer</string>\n    <string name=\"no_saved_logs\">Fant ingen lagrede logger.</string>\n    <string name=\"input_signatures_description\">Mellomromsinndelte programsignaturer , f.eks. <tt>org.y20k.transistor com.program2</tt> osv.</string>\n    <string name=\"keystore\">Nøkkellager</string>\n    <string name=\"java_keystore\">Java-nøkkellager (JKS)</string>\n    <string name=\"found_no_alias_in_keystore\">Fant ingen alias i nøkkellager.</string>\n    <string name=\"wireless_debugging\">Trådløs avlusning</string>\n    <string name=\"adb_connect\">Koble til</string>\n    <string name=\"notice\">Merknad</string>\n    <string name=\"failed_to_uninstall_app\">Avinstallasjon mislyktes</string>\n    <string name=\"storage\">Lagring</string>\n    <string name=\"error_with_details\">Feil: %s</string>\n    <string name=\"files\">Filer</string>\n    <string name=\"keystore_pass_cannot_be_empty\">Nøkkellager-passord kan ikke være tomt.</string>\n    <string name=\"identifier\">Identifikator</string>\n    <string name=\"paste\">Lim inn</string>\n    <string name=\"background\">Bakgrunn</string>\n    <string name=\"installer_app_installed\">Program installert</string>\n    <string name=\"pref_thread_count\">Parallell kjøring</string>\n    <string name=\"java\">Java</string>\n    <string name=\"system_partition\">Android-rot</string>\n    <string name=\"exit_confirmation\">Avslutt bekreftelse</string>\n    <string name=\"extract\">Pakk ut</string>\n    <string name=\"replace\">Erstatt</string>\n    <string name=\"rename\">Gi nytt navn</string>\n    <string name=\"type_uri_array_list\">Liste over URI-er</string>\n    <string name=\"pkcs12_keystore\">PKCS #12-nøkkellager (P12)</string>\n    <string name=\"failed_to_read_keystore\">Kunne ikke lese nøkkellageret.</string>\n    <string name=\"pref_installer_msg\">Sett opp programinstallatør-adferd</string>\n    <string name=\"bouncy_castle_keystore\">Bouncy Castle-nøkkellager (BKS)</string>\n    <string name=\"restart_log_viewer_to_see_changes\">Start loggviservinduet på ny for å vise endringer.</string>\n    <string name=\"notification_ticker\">Loggføring startet</string>\n    <string name=\"notification_title\">Loggfører …</string>\n    <string name=\"notification_subtext\">Trykk for å stoppe opptak</string>\n    <string name=\"port_number_empty\">Portnummeret er tomt.</string>\n    <string name=\"adb_connect_port_number_description\">Portnummer er å finne under <b>IP-adresse og port</b>-delen, rett nedenfor <b>Enhetsnavn</b>.</string>\n    <string name=\"help_app_ops_tab\">Klikk på et element for å <b>tillate</b> eller <b>ignorere</b> det. Lang-trykk på et element for å se dets andre støttede modi.</string>\n    <string name=\"help_permissions_tab\">Disse tilgangene defineres av dette programmet og kan ikke tilbakekalles.</string>\n    <string name=\"failed_to_prevent_background_run\">Kunne ikke forhindre %1$s fra å kjøre i bakgrunnen</string>\n    <string name=\"user_root\">Bruk rot-tilgang</string>\n    <string name=\"import_from_sb\">Importer fra Swift Backup 3.0 – 3.2</string>\n    <string name=\"pref_thread_count_hint\">Verdien må være mellom 0 og %1$d der 0 betyr <i>maksimalt antall operasjoner ved angitt tidspunkt</i>.</string>\n    <string name=\"smali\">Smali</string>\n    <string name=\"explore\">Utforsk</string>\n    <string name=\"pref_filter_pattern_title\">Filtrer ut etiketter</string>\n    <string name=\"pref_log_write_period_summary\" tools:ignore=\"PluralsCandidate\">Skriv til SD-kort ved opptak for hver %1$d linje.</string>\n    <string name=\"pref_show_timestamp_summary\">Vis prosess-ID og tidsstempel når utvidet.</string>\n    <string name=\"search_type_contains\">Inneholder</string>\n    <string name=\"toggle_internet\">Bruk Internett</string>\n    <string name=\"vt_checking\">VirusTotal: Sjekker …</string>\n    <string name=\"vt_uploading\">VirusTotal: Laster opp …</string>\n    <string name=\"vt_queued\">VirusTotal: I kø</string>\n    <string name=\"vt_failed\">VirusTotal: Mislykket</string>\n    <string name=\"process_id\">Prosess-ID</string>\n    <string name=\"parent_process_id\">Overordnet prosess-ID</string>\n    <string name=\"virtual_memory\">Virtuelt minne</string>\n    <string name=\"cpu_time\">Prosessortid</string>\n    <string name=\"priority\">Prioritet</string>\n    <string name=\"threads\">Trådantall</string>\n    <string name=\"state\">Behandlingstilstand</string>\n    <string name=\"commandline_args\">Kommandolinjeargumenter</string>\n    <string name=\"swap\">Sidevekslingsfil</string>\n    <string name=\"swap_chart_info\">● %1$s brukt ● %2$s ledig</string>\n    <string name=\"hidden_api_enf_default_policy\">Forvalg (basert på programtype)</string>\n    <string name=\"hidden_api_enf_policy_none\">Ingen (full tilgang til det skjulte API-et)</string>\n    <string name=\"binary_32_bit\">32-biter</string>\n    <string name=\"binary_64_bit\">64-biter</string>\n    <string name=\"so_type_shared_library\">Delt bibliotek</string>\n    <string name=\"so_type_executable\">Kjørbar</string>\n    <plurals name=\"usage_seconds\">\n        <item quantity=\"one\">%1$d sek.</item>\n        <item quantity=\"other\">%1$d sek.</item>\n    </plurals>\n    <plurals name=\"usage_minutes\">\n        <item quantity=\"one\">%1$d min.</item>\n        <item quantity=\"other\">%1$d min.</item>\n    </plurals>\n    <string name=\"pref_filter_pattern_summary\">Filtrer ut de valgte etikettene fra logger.</string>\n    <plurals name=\"toast_log_truncated\">\n        <item quantity=\"one\">Loggen er for stor. Viser siste linje.</item>\n        <item quantity=\"other\">Loggen er for stor. Viser de siste %d linjene.</item>\n    </plurals>\n    <string name=\"vt_scan_date\">Skanningsdato: %1$s</string>\n    <string name=\"vt_permalink\">Permanent lenke til VirusTotal</string>\n    <string name=\"pref_import_backups_hint\">Velg en mappe som inneholder sikkerhetskopifilene (Swift Backup/Titanium Backup) eller mapper (OAndBackup)</string>\n    <string name=\"vt_success\">VirusTotal: %1$d/%2$d</string>\n    <string name=\"pref_vt_apikey\">API-nøkkel for VirusTotal</string>\n    <string name=\"save_and_exit\">Lagre og avslutt</string>\n    <string name=\"input_backup_name_description\">Sikkerhetskopiens skal ikke begynne med et siffer og skal heller ikke inneholde mellomrom. La den stå tom hvis du vil bruke gjeldende dato-klokkeslett.</string>\n    <string name=\"dsa_affine_x\">Affint x koordinat</string>\n    <string name=\"state_waking\">Våkne, vekke</string>\n    <string name=\"rsa_modulus\">Modulus</string>\n    <string name=\"dsa_affine_y\">Affint y koordinat</string>\n    <string name=\"source_stamp_verified\">Kildestempel godkjent.</string>\n    <string name=\"state_trace_stop\">Sporingstopp</string>\n    <string name=\"batch_ops\">Partielle handlinger, partielle operasjoner</string>\n    <string name=\"view_missing_signatures\">Trykk for å se eller sende inn signaturer som ennå ikke finnes i App Managers database med biblioteker.</string>\n    <string name=\"state_zombie\">Zombie</string>\n    <string name=\"input_permissions\">Inndata tillatelser</string>\n    <string name=\"installer\">Installer</string>\n    <string name=\"matching_activities\">Samsvarende aktiviteter</string>\n    <string name=\"extras\">Ekstra</string>\n    <string name=\"net_policy\">Nettpraksis</string>\n    <string name=\"pref_block_trackers_msg\">Blokker sporingskomponenter etter å ha installert et program ved bruk av App Manager.</string>\n    <string name=\"authenticating\">Identitetsbekrefter …</string>\n    <plurals name=\"alert_failed_to_freeze\">\n        <item quantity=\"one\">Kunne ikke fryse %1$d program</item>\n        <item quantity=\"other\">Kunne ikke fryse %1$d programmer</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_unfreeze\">\n        <item quantity=\"one\">Kunne ikke tine %1$d program</item>\n        <item quantity=\"other\">Kunne ikke tine %1$d programmer</item>\n    </plurals>\n    <string name=\"failed_to_change_app_op_mode\">Kunne ikke endre program-op-modus.</string>\n    <string name=\"input_keystore_pass_msg\">Trykk her for å skrive inn nøkkellager-passord</string>\n    <string name=\"trim_caches_in_all_apps_description\">Sletter hurtiglagringsfiler fra alle programmer, inkludert Android-systemet</string>\n    <string name=\"vt_confirm_upload_and_scan\">Ja, last opp og skann</string>\n    <string name=\"pref_backup_android_keystore\">Sikkerhetskopier programmer med Android-nøkkellageret</string>\n    <string name=\"import_keystore\">Importer nøkkellager</string>\n    <string name=\"pref_import_export_keystore\">Importer/eksporter nøkkellager</string>\n    <string name=\"confirm_import_keystore\">Vil du erstatte nøkkellageret\\? Dette kan ikke angres.</string>\n    <string name=\"netpolicy_allow_background_data\">Tillat bakgrunnsdata når datalagring er på</string>\n    <string name=\"netpolicy_reject_cellular_data\">Avslå mobildata</string>\n    <string name=\"trim_caches_in_all_apps\">Beskjær hurtiglagre i alle programmer</string>\n    <string name=\"adb_pair\">Sammenkoble</string>\n    <string name=\"pref_always_on_background_msg\">Alltid installer programmer i bakgrunnen og vis en merknad ved fullføring.</string>\n    <string name=\"pref_intent_firewall_description\">Blokker komponenter kun ved bruk av intensjonsbrannmur. Ikke anbefalt siden noen programmer kan ta seg forbi brannmurer.</string>\n    <string name=\"pref_saved_apk_name_format\">Lagre APK-navneformat</string>\n    <string name=\"endianness_big_endian\">Viktigeste (byte) først</string>\n    <string name=\"endianness_little_endian\">Minst viktige (byte) først</string>\n    <string name=\"hidden_api_enf_policy_black\">Påtving (kun svartelister)</string>\n    <string name=\"hidden_api_enf_policy_dark_grey_and_black\">Påtving (mørke-grå og svartelister)</string>\n    <string name=\"memory_chart_info\">● %1$s Programmer ● %2$s Hurtiglagret ● %3$s Mellomlagre ● %4$s Ledig</string>\n    <string name=\"screen_time\">Skjermtid</string>\n    <string name=\"sort_by_installation_date\">Installasjonsdato</string>\n    <string name=\"tracker\">Sporer</string>\n    <string name=\"item_select\">Velg</string>\n    <string name=\"apk_checksums\">APK-sjekksummer</string>\n    <string name=\"log_stop_recording\">Stopp opptak</string>\n    <string name=\"frozen\">Fryst</string>\n    <string name=\"usage_wifi_data\">Wi-Fi-data</string>\n    <string name=\"usage_mobile_data\">Mobildata</string>\n    <string name=\"usage_last_used\">Sist brukt</string>\n    <string name=\"usage_times_opened\">Ganger åpnet</string>\n    <string name=\"freeze\">Frys</string>\n    <string name=\"restore_dots\">Gjenopprett …</string>\n    <string name=\"backup_no_backups_present\">Ingen sikkerhetskopier.</string>\n    <string name=\"unfreeze\">Tin</string>\n    <string name=\"backup_apps_cannot_be_backed_up\">Følgende programmer er ikke installerte og kunne ikke sikkerhetskopieres:</string>\n    <string name=\"restart_device\">Omstart av enheten</string>\n    <string name=\"changelog_type_new\">Ny</string>\n    <string name=\"changelog_type_fix\">Fiks</string>\n    <string name=\"changelog_type_improve\">Forbedret</string>\n    <string name=\"pref_sign_apk_no_signing_key\">Ingen signeringsnøkkel</string>\n    <string name=\"failed_to_freeze\">Kunne ikke fryse <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g>.</string>\n    <string name=\"freeze_unfreeze\">Frys/tin</string>\n    <string name=\"failed_to_unfreeze\">Kunne ikke tine <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g>.</string>\n    <string name=\"profile_freeze_msg\">Fryser eller tiner programmer basert på tilstand</string>\n    <string name=\"pref_default_freezing_method\">Forvalgt frysningsmetode</string>\n    <string name=\"pref_default_freezing_method_description\">Metode å bruke som forvalg der det ikke er noe alternativ å velge frysningsmetode.</string>\n    <string name=\"hide_app\">Skjul</string>\n    <string name=\"pref_privacy_description\">Skjermlås, identitetsbekreftelse, osv.</string>\n    <string name=\"pref_privacy\">Personvern</string>\n    <string name=\"pref_appearance_description\">Drakt, sideretning, funksjoner, osv.</string>\n    <string name=\"filter_frozen_apps\">Fryste programmer</string>\n    <string name=\"sort_by_frozen_app\">Fryste først</string>\n    <string name=\"pref_version_changelog\">Versjon/endringslogg</string>\n    <string name=\"get_help\">Få hjelp</string>\n    <string name=\"user_manual\">Brukermanual</string>\n    <string name=\"unknown_net_policy\">Ukjent nettpraksis (%1$s - %2$X)</string>\n    <string name=\"pref_pure_black_theme\">Svart drakt</string>\n    <string name=\"input_app_ops_description\">Skriv inn programnavn og/eller konstanter inndelt med mellomrom, f.eks. <tt>WAKE_LOCK 63 72 CAMERA</tt> osv.</string>\n    <string name=\"shortcut_icon\">Snarveisikon</string>\n    <string name=\"resend_intent\">Send intensjon igjen</string>\n    <string name=\"input_keystore_pass\">Skriv inn nøkkellager-passord</string>\n    <string name=\"set_package_name_first\">Sett pakkenavn først.</string>\n    <string name=\"pref_backup_android_keystore_msg\">Ikke alle programmer fungerer etter å ha blitt gjenopprettet. Å gjenopprette nøkkellageret fungerer ikke på de fleste enheter.</string>\n    <string name=\"set_app_op_mode\">Sett program-op-modus</string>\n    <string name=\"invalid_password\">Ugyldig passord. Prøv igjen.</string>\n    <string name=\"input_permissions_description\">Skriv inn tilganger inndelt med mellomrom, f.eks. <tt>com.permission.GET_ACCOUNTS android.permission.ACCESS_MEDIA_LOCATION</tt> osv. Bruk <tt>*</tt> for å bruke for alle tilganger.</string>\n    <string name=\"has_net_policy\">Nettpraksis</string>\n    <string name=\"input_keystore_alias_pass_description\">Skriv inn passord for aliaset <b>%1$s</b>. Du kan la dette stå tomt hvis passordet er det samme som nøkkellager-passordet.</string>\n    <string name=\"input_app_ops_description_profile\">Skriv inn op-navn og/eller konstanter, inndelt med mellomrom, f.eks. <tt>WAKE_LOCK 63 72 CAMERA</tt> osv. Bruk <tt>*</tt> for å bruke for allle oppsatte program-op-er.</string>\n    <string name=\"input_keystore_pass_description\">Skriv inn nøkkellagerpassordet for App Manager. Hvis du ser dette for første gang bør du bruke en passordgenerator for å lage et trygt passord og lagre det på en sikker plass før du limer det inn her.</string>\n    <string name=\"paired_successfully\">Sammenkoblet.</string>\n    <string name=\"netpolicy_reject_background_data\">Avslå bakgrunnsdata</string>\n    <string name=\"pref_import_export_keystore_msg\">Importer/eksporter Bouncy Castle-nøkkellageret (BKS) som brukes internt av App Manager.</string>\n    <string name=\"send_edited_intent\">Send redigert intensjon</string>\n    <string name=\"warning_working_on_root_mode\">Advarsel: Arbeider i rot-modus istedenfor ADB-modus.</string>\n    <string name=\"cpu_percent\">%% prosessorbruk</string>\n    <string name=\"pref_default_blocking_method_description\">Metode å bruke som forvalg der det ikke er noe alternativ for å velge en blokkeringsmetode.</string>\n    <string name=\"pref_default_blocking_method\">Forvalgt blokkeringsmetode</string>\n    <string name=\"pref_intent_firewall_and_disable_description\">Blokker komponenter ved bruk av intensjonsbrannmur og skru dem av. Anbefalt metode for rot-tilstandsbrukere.</string>\n    <string name=\"search_type_suffix\">Endelse</string>\n    <string name=\"search_type_regular_expressions\">Regulært uttrykk</string>\n    <string name=\"open_developer_options_page\">Åpne utviklervalg i Android-innstillingene</string>\n    <string name=\"view_changelog\">Finn ut hva som er nytt i denne utgaven</string>\n    <string name=\"unsupported_split_apk\">Ustøttet</string>\n    <string name=\"sort_by_total_size\">Total størrelse</string>\n    <string name=\"am_command\">Kommandoen <tt>am</tt></string>\n    <string name=\"open_in_new_window\">Nytt vindu</string>\n    <string name=\"internal\">Intern</string>\n    <string name=\"external\">Ekstern</string>\n    <string name=\"change_backup_volume\">Endre dataområde</string>\n    <string name=\"help_uses_permissions_tab\">Klikk på et element for å <b>innvilge</b> eller <b>tilbakekalle</b> det. Kun tilgangene <b>farlig</b> og <b>utvikling</b> kan innvilges eller tilbakekalles.</string>\n    <string name=\"keystore_password_info\">Dette er App Manager-passordet for nøkkellageret. Lagre det på et sikkert sted hvis du vil sikkerhetskopiere/gjenopprette App Manager-nøkkellageret.<b>Denne meldingen vil ikke bli vist igjen.</b></string>\n    <string name=\"state_name\">Tilstandsnavn (ST)</string>\n    <string name=\"troubleshooting\">Feilsøking</string>\n    <string name=\"pref_advanced_pref\">Brukere, APK-navneformat, samkjøring, osv.</string>\n    <string name=\"pref_sign_apk_error_signing_key_not_added\">En gyldig signeringsnøkkel kreves for å signere en APK-fil.</string>\n    <string name=\"app_info_tag_open_links\">Åpne lenker</string>\n    <string name=\"file_open_as\">Åpne som …</string>\n    <string name=\"block_unblock_components_dots\">Blokker/avblokker komponenter …</string>\n    <string name=\"unblock_components_dots\">Avblokker komponenter …</string>\n    <string name=\"backup_extras\">Ekstra</string>\n    <string name=\"file_open_with_custom_activity\">Egendefinert</string>\n    <string name=\"open_as_text\">Tekst</string>\n    <string name=\"open_as_image\">Bilde</string>\n    <string name=\"open_as_video\">Video</string>\n    <string name=\"open_as_archive\">Arkiv</string>\n    <string name=\"open_as_folder\">Mappe</string>\n    <string name=\"open_as_other\">Annet</string>\n    <string name=\"delete_filename\">Slett %s</string>\n    <string name=\"action_stop_service\">Stopp</string>\n    <string name=\"export_app_list\">Eksporter programliste</string>\n    <string name=\"export_option_markdown\">Markdown</string>\n    <string name=\"export_app_list_select_format\">Velg format for eksportering av programliste</string>\n    <string name=\"export_option_xml\">XML</string>\n    <string name=\"redo\">Gjenta</string>\n    <string name=\"debloat_removal_type\">Type</string>\n    <string name=\"debloat_list_aosp\">AOSP</string>\n    <string name=\"debloat_list_misc\">Ymse</string>\n    <string name=\"installing_package\">Installerer %1$s …</string>\n    <string name=\"backing_up_app\">Sikkerhetskopierer %1$s …</string>\n    <string name=\"create_new_symbolic_link\">Ny symbolsk lenke</string>\n    <string name=\"create_new_folder\">Ny mappe</string>\n    <string name=\"create_new_file\">Ny fil</string>\n    <string name=\"enter_symbolic_link_name\">Lenkenavn</string>\n    <string name=\"enter_target_path\">Målsti</string>\n    <string name=\"copy_these_paths\">Kopier stier</string>\n    <string name=\"conflict_detected_while_copying\">Konflikt oppdaget</string>\n    <string name=\"copied_successfully\">Kopiert.</string>\n    <string name=\"failed_to_copy_specified_file\">Kunne ikke kopiere «%1$s».</string>\n    <string name=\"change_mode\">Endre modus</string>\n    <plurals name=\"search_results\">\n        <item quantity=\"one\">%d resultat</item>\n        <item quantity=\"other\">%d resultater</item>\n    </plurals>\n    <string name=\"title_audio_player\">Lydspiller</string>\n    <string name=\"copy_this_path\">Kopier sti</string>\n    <string name=\"filter_force_stopped_apps\">Stoppede programmer</string>\n    <string name=\"file_open_with_os_default_dialog\">Åpne med OS-forvalgt dialog</string>\n    <string name=\"confirm_file_deletion\">Ja, slett</string>\n    <string name=\"action_run\">Kjør</string>\n    <string name=\"invalid_target_path\">Ugyldig sti</string>\n    <plurals name=\"folder_count\">\n        <item quantity=\"one\">%d mappe</item>\n        <item quantity=\"other\">%d mapper</item>\n    </plurals>\n    <string name=\"title_domains_supported_by_the_app\">Støttede domener</string>\n    <string name=\"action_replace_all\">Erstatt alle</string>\n    <string name=\"uninstall_app\">Avinstaller %1$s</string>\n    <string name=\"title_confirm_deletion\">Bekreft sletting</string>\n    <string name=\"debloat_removal_replace\">Erstatt</string>\n    <plurals name=\"file_count\">\n        <item quantity=\"one\">%d fil</item>\n        <item quantity=\"other\">%d filer</item>\n    </plurals>\n    <string name=\"restoring_app\">Gjenoppretter %1$s …</string>\n    <string name=\"folder\">Mappe</string>\n    <string name=\"symbolic_link\">Symbolsk lenke</string>\n    <string name=\"moved_successfully\">Flyttet</string>\n</resources>"
  },
  {
    "path": "app/src/main/res/values-night-v31/styles.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<resources>\n\n    <style name=\"AppTheme.AppWidgetContainerParent\" parent=\"@android:style/Theme.DeviceDefault.DayNight\">\n        <item name=\"appWidgetRadius\">@android:dimen/system_app_widget_background_radius</item>\n        <item name=\"appWidgetPadding\">16dp</item>\n        <item name=\"appWidgetInnerRadius\">@android:dimen/system_app_widget_inner_radius</item>\n    </style>\n\n</resources>"
  },
  {
    "path": "app/src/main/res/values-nl/disclaimer.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"disclaimer_body\">App Manager biedt rootfuncties die mogelijk schadelijk kunnen zijn voor uw apparaat bij onjuist gebruik. App Manager is niet verantwoordelijk voor eventuele schade die wordt veroorzaakt door het gebruik van deze applicatie. Als u niet volledig op de hoogte bent van hoe root werkt, dient u het gebruik van rootopties te vermijden totdat u volledig op de hoogte bent van de risico\\'s.\\n\\nElke link die ik naar andere apps en websites verstrek, is voor het gemak van de gebruiker. Ik ben niet verantwoordelijk voor de content die u via externe links kunt vinden.\\n\\nDoor App Manager te gebruiken aanvaardt u de volledige verantwoordelijkheid voor uw eigen gebruik en aanvaardt u dat er geen schade, claims of geldelijke waarde wordt gegeven als gevolg van misbruik.\\n\\nDoor deze applicatie te gebruiken, aanvaardt u alle verantwoordelijkheid voor het gebruik ervan en gaat u ermee akkoord dat ik niet verantwoordelijk ben voor eventuele acties die u onderneemt en die een nadelig effect hebben op uw apparaat.</string>\n    <string name=\"disclaimer_header\">Disclaimer</string>\n    <string name=\"disclaimer_footer\">© 2020–2024 Muntashir Al-Islam</string>\n    <string name=\"disclaimer_agree_forever\">Laat dit nooit meer zien</string>\n    <string name=\"disclaimer_agree\">Ik ga akkoord</string>\n    <string name=\"disclaimer_exit\">Afsluiten</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-nl/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:tools=\"http://schemas.android.com/tools\">\n    <string name=\"not_yet_valid\">Nog niet geldig</string>\n    <string name=\"data_size\">Data</string>\n    <string name=\"system\">Systeem</string>\n    <string name=\"about\">Over</string>\n    <string name=\"data_dir\">Gegevensdirectory</string>\n    <string name=\"manifest\">Manifest</string>\n    <string name=\"uninstall\">Deïnstalleren</string>\n    <string name=\"permissions\">Gebruikt machtigingen</string>\n    <string name=\"require_no_permission\">Geen toestemming nodig</string>\n    <string name=\"activities\">Activiteiten</string>\n    <string name=\"launch\">Starten</string>\n    <string name=\"refresh\">Verversen</string>\n    <string name=\"no_activities\">Geen activiteiten</string>\n    <string name=\"receivers\">Ontvangers</string>\n    <string name=\"no_receivers\">Geen ontvangers</string>\n    <string name=\"providers\">Providers</string>\n    <string name=\"no_providers\">Geen providers</string>\n    <string name=\"launch_mode\">Startmodus</string>\n    <string name=\"sort_by_last_update\">Laatste update</string>\n    <string name=\"service\">Services</string>\n    <string name=\"no_service\">Geen services</string>\n    <string name=\"orientation\">Oriëntatie</string>\n    <string name=\"flags\">Vlaggen</string>\n    <string name=\"grant_uri_permission\">URI-machtigingen verlenen</string>\n    <string name=\"task_affinity\">Taakaffiniteit</string>\n    <string name=\"authority\">Autoriteit</string>\n    <string name=\"soft_input\">Zachte inputmodus</string>\n    <string name=\"path_permissions\">Padmachtigingen</string>\n    <string name=\"read\">Lezen</string>\n    <string name=\"write\">Schrijven</string>\n    <string name=\"patterns_allowed\">Patronen toegestaan</string>\n    <string name=\"declared_permission\">Machtigingen</string>\n    <string name=\"shared_libs\">Gedeelde bibliotheken</string>\n    <string name=\"group\">Groep</string>\n    <string name=\"uses_feature\">Gebruikte functies</string>\n    <string name=\"no_feature\">Geen functies</string>\n    <string name=\"sort_by_shared_user_id\">Gedeelde gebruikers-ID</string>\n    <string name=\"shared_user_id\">Gedeelde gebruikers-ID</string>\n    <string name=\"sort_by_sha\">Handtekening</string>\n    <string name=\"signatures\">Handtekeningen</string>\n    <string name=\"app_signing_signatures\">Handtekeningen</string>\n    <string name=\"app_signing_no_signatures\">Geen geldige handtekeningen</string>\n    <string name=\"configurations\">Configuraties</string>\n    <string name=\"no_configurations\">Geen configuraties</string>\n    <string name=\"input_features\">Invoermogelijkheden</string>\n    <string name=\"loading\">Laden…</string>\n    <string name=\"sort_by_package_name\">Naam pakket</string>\n    <string name=\"sort_by_domain\">Gebruikersapps eerst</string>\n    <string name=\"data_received\">Data ontvangen</string>\n    <string name=\"data_transmitted\">Data verstuurd</string>\n    <string name=\"data_usage_msg\">Datagebruik</string>\n    <string name=\"obb_size\">Obb</string>\n    <string name=\"media_size\">Media</string>\n    <string name=\"app_not_installed\">App niet geïnstalleerd</string>\n    <string name=\"user\">Gebruiker</string>\n    <string name=\"sort\">Sorteren</string>\n    <string name=\"app_info\">App-info</string>\n    <string name=\"system_app\">Systeem-app</string>\n    <string name=\"user_app\">Gebruikersapp</string>\n    <string name=\"paths_and_directories\">Paden en mappen</string>\n    <string name=\"source_dir\">Bronmap</string>\n    <string name=\"sdk_min\">Min</string>\n    <string name=\"sdk_max\">Target</string>\n    <string name=\"sdk_flags\">Vlaggen</string>\n    <string name=\"more_info\">Meer info</string>\n    <string name=\"date_updated\">Datum bijgewerkt</string>\n    <string name=\"installer_app\">Installatie-app</string>\n    <string name=\"main_activity\">Hoofdactiviteit</string>\n    <string name=\"empty_package_name\">Lege pakketnaam</string>\n    <string name=\"error_verbose_pin_shortcut\">De huidige launcher ondersteunt geen PinShortcut. Kan geen snelkoppeling maken.</string>\n    <string name=\"create_shortcut\">Snelkoppeling maken</string>\n    <string name=\"shortcut_name\">Naam snelkoppeling</string>\n    <string name=\"package_name\">Pakketnaam</string>\n    <string name=\"class_name\">Class naam</string>\n    <string name=\"icon_picker\">Pictogramkiezer</string>\n    <string name=\"license\">Licentie</string>\n    <string name=\"third_party\">Bibliotheken en pictogrammen van derden</string>\n    <string name=\"credits\">Credits</string>\n    <string name=\"word_wrap\">Schakel tekstomloop in</string>\n    <string name=\"class_viewer\">Class Viewer</string>\n    <plurals name=\"tracker_and_classes\">\n        <item quantity=\"one\">1 tracker met <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g> klasse</item>\n        <item quantity=\"other\">1 tracker met <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g> klassen</item>\n    </plurals>\n    <string name=\"found_trackers\">Gevonden trackers</string>\n    <string name=\"tracker_details\">Trackergegevens</string>\n    <string name=\"tracker_classes\">Tracker classes</string>\n    <string name=\"all_classes\">Alle classes</string>\n    <string name=\"no_shared_libs\">Geen gedeelde bibliotheken</string>\n    <string name=\"usage_weekly\">Wekelijks</string>\n    <string name=\"usage_today\">Vandaag</string>\n    <string name=\"usage_7_days\">Laatste 7 dagen</string>\n    <plurals name=\"usage_months\">\n        <item quantity=\"one\">%1$d maand</item>\n        <item quantity=\"other\">%1$d maanden</item>\n    </plurals>\n    <plurals name=\"usage_days\">\n        <item quantity=\"one\">%1$d dag</item>\n        <item quantity=\"other\">%1$d dagen</item>\n    </plurals>\n    <plurals name=\"usage_hours\">\n        <item quantity=\"one\">%1$d uur</item>\n        <item quantity=\"other\">%1$d uren</item>\n    </plurals>\n    <plurals name=\"usage_minutes\">\n        <item quantity=\"one\">%1$d minuut</item>\n        <item quantity=\"other\">%1$d minuten</item>\n    </plurals>\n    <plurals name=\"usage_seconds\">\n        <item quantity=\"one\">%1$d seconde</item>\n        <item quantity=\"other\">%1$d seconden</item>\n    </plurals>\n    <string name=\"usage_less_than_a_minute\">Minder dan een minuut</string>\n    <string name=\"go_back\">Ga terug</string>\n    <string name=\"go\">Ga</string>\n    <string name=\"grant_usage_access\">Gebruikstoegang verlenen</string>\n    <string name=\"grant_usage_acess_message\">Wordt gebruikt om informatie over app-gebruik weer te geven.</string>\n    <string name=\"share_apk\">Deel APK</string>\n    <string name=\"failed_to_extract_apk_file\">APK-bestand kon niet worden uitgepakt</string>\n    <string name=\"menu_remove_rules\">Verwijder regels</string>\n    <string name=\"menu_apply_rules\">Regels toepassen</string>\n    <string name=\"search\">Zoeken</string>\n    <string name=\"dev_protected_data_dir\">Apparaatbeveiligde gegevensdirectory</string>\n    <string name=\"native_library_dir\">Native JNI-bibliotheekdirectory</string>\n    <string name=\"process_name\">Procesnaam</string>\n    <string name=\"no_code\">Geen code</string>\n    <string name=\"requested_large_heap\">Grote hoop</string>\n    <string name=\"updated_app\">Bijgewerkt</string>\n    <string name=\"debuggable\">Foutopsporing mogelijk</string>\n    <string name=\"test_only\">Alleen testen</string>\n    <string name=\"shared_prefs\">Gedeelde voorkeuren</string>\n    <string name=\"databases\">Databases</string>\n    <string name=\"save\">Opslaan</string>\n    <string name=\"discard\">Annuleren</string>\n    <string name=\"delete\">Verwijderen</string>\n    <string name=\"deleted_successfully\">Verwijderd</string>\n    <string name=\"deletion_failed\">Verwijderen mislukt</string>\n    <string name=\"string_value\">Stringwaarde</string>\n    <string name=\"long_integer_value\">Lange gehele getallenwaarde</string>\n    <string name=\"integer_value\">Gehele waarde</string>\n    <string name=\"boolean_value\">Booleanwaarde</string>\n    <string name=\"key_name\">Sleutelnaam</string>\n    <string name=\"add_item\">Item toevoegen</string>\n    <string name=\"type_boolean\">Waar/onwaar</string>\n    <string name=\"type_float\">Decimaal getal</string>\n    <string name=\"type_int\">Geheel getal</string>\n    <string name=\"type_long\">Lang geheel getal</string>\n    <string name=\"type_string\">Karakters</string>\n    <string name=\"error_evaluating_input\">Kan invoer niet evalueren</string>\n    <string name=\"no_usage_in_this_time_range\">Geen gebruik in deze periode</string>\n    <string name=\"no_content\">Geen inhoud</string>\n    <string name=\"view_in_settings\">Bekijk in Instellingen</string>\n    <string name=\"uninstall_app_message\">Wilt u deze app verwijderen?</string>\n    <string name=\"failed_to_uninstall\">Kan <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g> niet verwijderen.</string>\n    <string name=\"failed_to_uninstall_app\">Verwijderen mislukt</string>\n    <string name=\"uninstall_system_app_message\">Dit is een systeem-app. Weet u zeker dat u deze app wilt verwijderen?</string>\n    <string name=\"stopped\">Gestopt</string>\n    <string name=\"disable\">Uitschakelen</string>\n    <string name=\"enable\">Inschakelen</string>\n    <string name=\"force_stop\">Geforceerd stoppen</string>\n    <string name=\"storage_and_cache\">Opslag en cache</string>\n    <string name=\"total_size\">Totale</string>\n    <string name=\"app_size\">App</string>\n    <string name=\"app_ops\">App Ops</string>\n    <string name=\"no_app_ops\">Geen app operations</string>\n    <string name=\"failed_to_enable_op\">Kan de gevraagde app op niet inschakelen</string>\n    <string name=\"failed_to_disable_op\">Kan de gevraagde app op niet uitschakelen</string>\n    <string name=\"str_logo\">Logo</string>\n    <string name=\"pref_global_blocking_enabled\">Directe componentblokkering</string>\n    <string name=\"pref_global_blocking_enabled_msg\">Hiermee kunt u elk onderdeel van een app blokkeren zonder de blokkering expliciet in te schakelen voor de app.</string>\n    <string name=\"usage_access\">Gebruikstoegang</string>\n    <string name=\"usage_yesterday\">Gisteren</string>\n    <string name=\"exodus_link\">εxodus-link</string>\n    <string name=\"sort_by_blocked_components\">Geblokkeerd eerst</string>\n    <string name=\"external_data_dir\">Externe gegevensdirectory</string>\n    <string name=\"external_multiple_data_dir\">Externe gegevensdirectory <xliff:g id=\"dir_no\" example=\"1\">%1$d</xliff:g></string>\n    <plurals name=\"no_of_times_opened\">\n        <item quantity=\"one\">%1$d keer</item>\n        <item quantity=\"other\">%1$d keer</item>\n    </plurals>\n    <string name=\"sort_by_last_used\">Laatst gebruikt</string>\n    <string name=\"sort_by_screen_time\">Schermtijd</string>\n    <string name=\"pref_import_watt\">Importeer vanuit Watt</string>\n    <string name=\"pref_import_blocker\">Importeer vanuit Blocker</string>\n    <string name=\"the_import_was_successful\">Geïmporteerd</string>\n    <string name=\"the_export_was_successful\">Geëxporteerd</string>\n    <plurals name=\"failed_to_import_files\">\n        <item quantity=\"one\">Kan %1$d bestand niet importeren.</item>\n        <item quantity=\"other\">Kan %1$d bestanden niet importeren.</item>\n    </plurals>\n    <string name=\"apk_updater\">APK Updater</string>\n    <string name=\"running_apps\">Actieve apps</string>\n    <string name=\"kill_process\">Sluit</string>\n    <string name=\"disable_background_run\">Verhinder achtergrondactiviteit</string>\n    <string name=\"pid_and_ppid\">Proces-ID: %1$d, bovenliggend proces-ID: %2$d</string>\n    <string name=\"memory_virtual_memory\">Geheugen: %1$s, virtueel geheugen: %2$s</string>\n    <string name=\"user_with_id\">Gebruiker: <xliff:g id=\"user_id\" example=\"0\">%1$d</xliff:g></string>\n    <string name=\"user_and_uid\">Gebruiker: <xliff:g id=\"user_name\" example=\"root\">%1$s</xliff:g> (<xliff:g id=\"user_id\" example=\"0\">%2$d</xliff:g>)</string>\n    <string name=\"clear_data\">Wis data</string>\n    <string name=\"backup_restore\">Back-up/Herstellen</string>\n    <string name=\"disable_background\">Verhinder achtergrondactiviteit</string>\n    <string name=\"export_blocking_rules\">Blokkeerregels exporteren</string>\n    <plurals name=\"alert_failed_to_clear_data\">\n        <item quantity=\"one\">Kan gegevens van %1$d app niet wissen</item>\n        <item quantity=\"other\">Kan gegevens van %1$d apps niet wissen</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_disable_background\">\n        <item quantity=\"one\">Kan niet verhinderen dat %1$d app op de achtergrond wordt uitgevoerd</item>\n        <item quantity=\"other\">Kan niet verhinderen dat %1$d apps op de achtergrond wordt uitgevoerd</item>\n    </plurals>\n    <string name=\"the_operation_was_successful\">Gereed</string>\n    <string name=\"toggle_kill_for_system_apps\">Kill systeemapps</string>\n    <string name=\"pref_import\">Importeren</string>\n    <string name=\"pref_export\">Exporteren</string>\n    <string name=\"import_options\">Importopties</string>\n    <string name=\"export_options\">Exportopties</string>\n    <string name=\"import_failed\">Importeren mislukt!</string>\n    <string name=\"export_failed\">Exporteren mislukt!</string>\n    <string name=\"keyboard_type\">Type toetsenbord</string>\n    <string name=\"navigation\">Navigatie</string>\n    <string name=\"pref_import_blocker_msg\">Importeer blokkeerregels uit Blocker, waarbij elk bestand regels voor één pakket bevat.</string>\n    <string name=\"pref_app_theme\">App-thema</string>\n    <string name=\"follow_system\">Systeem volgen</string>\n    <string name=\"battery_mode\">Batterijmodus</string>\n    <string name=\"day\">Dag</string>\n    <string name=\"night\">Nacht</string>\n    <string name=\"select_theme\">Thema</string>\n    <string name=\"apply\">Toepassen</string>\n    <string name=\"pref_about_msg\">App Manager-versie, licentie, credits, etc.</string>\n    <string name=\"version\">Versie</string>\n    <string name=\"sort_by_wifi_data\">Wi-Fi-gegevens</string>\n    <string name=\"block_trackers\">Trackers blokkeren</string>\n    <string name=\"sort_by_component_name\">Naam van component</string>\n    <string name=\"deny_dangerous_app_ops\">Weiger gevaarlijke app ops</string>\n    <string name=\"sort_by_app_ops_names\">Naam van app ops</string>\n    <string name=\"sort_by_denied_app_ops\">Geweigerd eerst</string>\n    <string name=\"sort_by_dangerous_permissions\">Gevaarlijk eerst</string>\n    <string name=\"deny_dangerous_permissions\">Gevaarlijke machtigingen weigeren</string>\n    <string name=\"sort_by_tracker_components\">Trackers eerst</string>\n    <string name=\"unknown_op\">Onbekende bewerking</string>\n    <string name=\"failed_to_grant_permission\">Kan machtiging niet verlenen</string>\n    <string name=\"failed_to_revoke_permission\">Kan machtiging niet intrekken</string>\n    <string name=\"failed_to_reset_app_ops\">Kan app ops niet resetten</string>\n    <string name=\"failed_to_deny_dangerous_app_ops\">Kan niet alle gevaarlijke app ops intrekken</string>\n    <string name=\"launch_app\">Starten</string>\n    <string name=\"never_ask\">Nooit vragen</string>\n    <string name=\"one_click_ops\">1-klik-bewerkingen</string>\n    <string name=\"changelog\">Wijzigingsoverzicht</string>\n    <string name=\"external_apk_no_app_op\">Externe APK heeft geen app ops</string>\n    <string name=\"manifest_viewer\">Manifest Viewer</string>\n    <plurals name=\"no_of_trackers\">\n        <item quantity=\"one\">%1$d tracker</item>\n        <item quantity=\"other\">%1$d trackers</item>\n    </plurals>\n    <plurals name=\"no_of_components\">\n        <item quantity=\"one\">%1$d component</item>\n        <item quantity=\"other\">%1$d componenten</item>\n    </plurals>\n    <string name=\"install\">Installeren</string>\n    <string name=\"update\">Bijwerken</string>\n    <string name=\"clear_cache\">Cache wissen</string>\n    <string name=\"block_unblock_trackers_description\">Advertentie- en trackingcomponenten in alle geïnstalleerde apps blokkeren of deblokkeren</string>\n    <string name=\"block_components_dots\">Blokkeer componenten…</string>\n    <string name=\"block_unblock_components_dots\">Blokkeren/deblokkeren componenten…</string>\n    <string name=\"unblock_components_dots\">Deblokkeer componenten…</string>\n    <string name=\"block_unblock_components_description\">Blokkeer of deblokkeer alle componenten die door de opgegeven handtekeningen worden geïdentificeerd</string>\n    <string name=\"deny_app_ops_description\">Stel een modus in voor app ops die worden geïdentificeerd door de constante waarden, zoals <tt>63</tt> of <tt>RUN_IN_BACKGROUND</tt></string>\n    <string name=\"clear_data_from_uninstalled_apps\">Wis gegevens van verwijderde apps</string>\n    <string name=\"clear_data_from_uninstalled_apps_description\">Wis gegevens van apps die zijn verwijderd met de vlag <tt>DONT_DELETE_DATA</tt></string>\n    <string name=\"clear_app_cache\">Wis app-cache</string>\n    <string name=\"clear_app_cache_description\">Wist de cache van alle apps</string>\n    <string name=\"no_tracker_found\">Geen tracker gevonden</string>\n    <string name=\"failed_packages\">Mislukte pakketten</string>\n    <string name=\"input_signatures\">Invoerhandtekeningen</string>\n    <string name=\"input_signatures_description\">Voer handtekeningen in met spaties, bijvoorbeeld <tt>com.facebook org.app2 com.app3</tt> etc.</string>\n    <string name=\"filtered_packages\">Gefilterde pakketten</string>\n    <string name=\"input_app_ops\">Invoer app ops</string>\n    <string name=\"input_app_ops_description\">Voer namen van app ops en/of constanten in met spaties, bijvoorbeeld <tt>WAKE_LOCK 63 72 CAMERA</tt> etc.</string>\n    <string name=\"input_app_ops_description_profile\">Voer namen van app ops en/of constanten in met spaties, bijvoorbeeld <tt>WAKE_LOCK 63 72 CAMERA</tt> enz. Gebruik <tt>*</tt> om dit toe te passen op alle geconfigureerde app ops.</string>\n    <string name=\"only_works_in_root_or_adb_mode\">Werkt alleen in root- of ADB-modus</string>\n    <string name=\"failed_to_parse_some_numbers\">Kan sommige getallen niet parseren</string>\n    <plurals name=\"no_of_splits\">\n        <item quantity=\"one\">%1$d split</item>\n        <item quantity=\"other\">%1$d splits</item>\n    </plurals>\n    <string name=\"termux\">Termux</string>\n    <string name=\"package_name_is_installed_successfully\"><xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g> geïnstalleerd</string>\n    <string name=\"filter\">Filter</string>\n    <string name=\"filter_system_apps\">Systeem-apps</string>\n    <string name=\"filter_user_apps\">Gebruikersapps</string>\n    <string name=\"filter_apps_with_rules\">Met regels</string>\n    <string name=\"select_all\">Selecteer alles</string>\n    <string name=\"installed_version\">Geïnstalleerde versie</string>\n    <string name=\"trackers\">Trackers</string>\n    <string name=\"components\">Componenten</string>\n    <string name=\"features\">Functies</string>\n    <string name=\"data\">Data</string>\n    <string name=\"restore\">Herstel</string>\n    <string name=\"delete_backup\">Verwijder back-up</string>\n    <string name=\"backup_options\">Back-up opties</string>\n    <plurals name=\"failed_to_backup_some_apk_files\">\n        <item quantity=\"one\">Kan geen back-up maken van %1$d app</item>\n        <item quantity=\"other\">Kan geen back-up maken van %1$d apps</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_restore\">\n        <item quantity=\"one\">Kan %1$d app niet herstellen</item>\n        <item quantity=\"other\">Kan %1$d apps niet herstellen</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_delete_backup\">\n        <item quantity=\"one\">Kan %1$d back-up niet verwijderen</item>\n        <item quantity=\"other\">Kan %1$d back-ups niet verwijderen</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_unblock_trackers\">\n        <item quantity=\"one\">Kan trackers van %1$d app niet deblokkeren</item>\n        <item quantity=\"other\">Kan trackers van %1$d apps niet deblokkeren</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_unblock_components\">\n        <item quantity=\"one\">Kan componenten van %1$d app niet deblokkeren</item>\n        <item quantity=\"other\">Kan componenten van %1$d apps niet deblokkeren</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_set_app_ops\">\n        <item quantity=\"one\">Kan geen app ops instellen voor %1$d app</item>\n        <item quantity=\"other\">Kan geen app ops instellen voor %1$d apps</item>\n    </plurals>\n    <plurals name=\"classes\">\n        <item quantity=\"one\">%1$d class</item>\n        <item quantity=\"other\">%1$d classes</item>\n    </plurals>\n    <plurals name=\"libraries\">\n        <item quantity=\"one\">%1$d bibliotheek</item>\n        <item quantity=\"other\">%1$d bibliotheken</item>\n    </plurals>\n    <plurals name=\"missing_signatures\">\n        <item quantity=\"one\">%1$d handtekening ontbreekt</item>\n        <item quantity=\"other\">%1$d handtekeningen ontbreken</item>\n    </plurals>\n    <plurals name=\"app_signing_signature_schemes_pl\">\n        <item quantity=\"one\">Handtekeningschema</item>\n        <item quantity=\"other\">Handtekeningschema\\'s</item>\n    </plurals>\n    <plurals name=\"verified_with_warning\">\n        <item quantity=\"one\">Geverifieerd met %d waarschuwing</item>\n        <item quantity=\"other\">Geverifieerd met %d waarschuwingen</item>\n    </plurals>\n    <string name=\"apply_to_system_apps\">Toepassen op systeem-apps</string>\n    <string name=\"apply_to_system_apps_question\">Ook toepassen op systeem-apps? Selecteer \\\"Nee\\\" als u het niet zeker weet.</string>\n    <string name=\"no\">Nee</string>\n    <string name=\"yes\">Ja</string>\n    <string name=\"skip_signature_checks\">Handtekeningcontroles overslaan</string>\n    <string name=\"clear_data_message\">Weet u zeker dat u de gegevens van deze app wilt wissen?</string>\n    <string name=\"clear\">Wissen</string>\n    <string name=\"block\">Blokkeren</string>\n    <string name=\"unblock\">Deblokkeren</string>\n    <string name=\"block_unblock_trackers\">Blokkeer/deblokkeer trackers</string>\n    <string name=\"no_matching_package_found\">Kon zo\\'n app niet vinden</string>\n    <string name=\"export_icon\">Extraheer pictogram</string>\n    <string name=\"open_in_termux\">Openen in Termux</string>\n    <string name=\"run_in_termux\">Uitvoeren in Termux</string>\n    <string name=\"website\">Website</string>\n    <string name=\"pref_remove_all_rules\">Verwijder alle regels</string>\n    <string name=\"pref_remove_all_rules_msg\">Machtigingen worden verleend, app ops en componenten worden teruggezet naar hun standaardwaarden.</string>\n    <string name=\"are_you_sure\">Weet je het zeker?</string>\n    <string name=\"filter_apps_with_activities\">Met activiteiten</string>\n    <string name=\"toggle_default_app_ops\">Standaard app ops in-/uitschakelen</string>\n    <string name=\"installer_error_aborted\">Installatie mislukt omdat deze is geannuleerd of omdat de sessie onverwacht is beëindigd</string>\n    <string name=\"installer_error_conflict\">Kan de app niet installeren omdat de pakketnaam al in gebruik is</string>\n    <string name=\"installer_error_bad_apks\">Ongeldige APK-bestanden geselecteerd</string>\n    <string name=\"installer_error_storage\">Onvoldoende opslagruimte om de app te installeren</string>\n    <string name=\"installer_error_generic\">Installatie mislukt</string>\n    <string name=\"installer_error_lidl_rom\">Uw ROM is niet compatibel met Rootless Installer.</string>\n    <string name=\"batch_ops\">Batchbewerkingen</string>\n    <string name=\"operation_running\">Bewerking bezig…</string>\n    <string name=\"full_stop_tap_to_see_details\">. Tik om details te bekijken.</string>\n    <string name=\"try_again\">Probeer opnieuw</string>\n    <string name=\"reinstall\">Opnieuw installeren</string>\n    <string name=\"unblock_trackers\">Trackers deblokkeren</string>\n    <string name=\"package_installer\">Pakketinstallateur</string>\n    <string name=\"install_in_progress\">Installeren…</string>\n    <string name=\"installer_error_security\">Kan geen toegang krijgen tot APK-bestanden</string>\n    <string name=\"installer_error_session_create\">Kan geen installatiesessie maken</string>\n    <string name=\"installer_error_session_commit\">Kan de APK-bestanden niet vastleggen</string>\n    <string name=\"installer_error_session_write\">Kan niet naar de installatiesessie schrijven</string>\n    <string name=\"backup_apk_files\">APK-bestanden</string>\n    <string name=\"obb_files_extracted_successfully\">OBB-bestanden uitgepakt</string>\n    <string name=\"backup_multiple\">Maak meerdere backups</string>\n    <string name=\"backup_all_users\">Alle gebruikers</string>\n    <string name=\"auto\">Automatisch</string>\n    <string name=\"choose_language\">Taal wijzigen</string>\n    <string name=\"base_apk\">Basis-APK</string>\n    <string name=\"launch_mode_single_instance\">Eén exemplaar</string>\n    <string name=\"launch_mode_single_task\">Enkele taak</string>\n    <string name=\"launch_mode_single_top\">Enkele top</string>\n    <string name=\"orientation_unspecified\">Niet gespecificeerd</string>\n    <string name=\"orientation_behind\">Achter</string>\n    <string name=\"orientation_full_sensor\">Volledige sensor</string>\n    <string name=\"orientation_full_user\">Volledige gebruiker</string>\n    <string name=\"orientation_locked\">Vergrendeld</string>\n    <string name=\"orientation_reverse_portrait\">Omgekeerd portret</string>\n    <string name=\"orientation_reverse_landscape\">Omgekeerd landschap</string>\n    <string name=\"orientation_sensor_landscape\">Sensor landschap</string>\n    <string name=\"orientation_sensor_portrait\">Sensor portret</string>\n    <string name=\"orientation_sensor\">Sensor</string>\n    <string name=\"orientation_user_portrait\">Gebruiker portret</string>\n    <string name=\"required\">Vereist</string>\n    <string name=\"_undefined\">Ongedefinieerd</string>\n    <string name=\"keyboard_no_keys\">Geen keys</string>\n    <string name=\"keyboard_qwerty\">QWERTY</string>\n    <string name=\"navigation_dial_pad\">Nummers</string>\n    <string name=\"navigation_trackball\">Trackball</string>\n    <string name=\"navigation_wheel\">Wiel</string>\n    <string name=\"touchscreen_no_touch\">Geen touch</string>\n    <string name=\"state_sleeping\">Slaapstand</string>\n    <string name=\"state_device_io\">Apparaat I/O</string>\n    <string name=\"state_zombie\">Zombie</string>\n    <string name=\"state_parked\">Geparkeerd</string>\n    <string name=\"state_idle\">Inactief</string>\n    <string name=\"state_unknown\">Onbekend</string>\n    <string name=\"state_high_priority\">Hoge prioriteit</string>\n    <string name=\"state_low_priority\">Lage prioriteit</string>\n    <string name=\"state_locked_memory\">Vergrendeld geheugen</string>\n    <string name=\"state_foreground\">Voorgrond</string>\n    <string name=\"state_multithreaded\">Multithreaded</string>\n    <string name=\"downgrade\">Downgraden</string>\n    <string name=\"input_backup_name\">Back-upnaam</string>\n    <string name=\"ok\">OK</string>\n    <string name=\"cancel\">Annuleren</string>\n    <string name=\"open_pgp_provider\">OpenPGP Provider</string>\n    <string name=\"profiles\">Profielen</string>\n    <string name=\"no_profiles\">Geen profielen</string>\n    <string name=\"apply_now\">Toepassen…</string>\n    <string name=\"apps\">Apps</string>\n    <string name=\"no_apps\">Geen apps</string>\n    <string name=\"filter_apps\">Apps</string>\n    <string name=\"sort_by_process_id\">Proces-ID</string>\n    <string name=\"sort_by_process_name\">Procesnaam</string>\n    <string name=\"sort_by_apps_first\">Apps eerst</string>\n    <string name=\"sort_by_memory_usage\">Geheugengebruik</string>\n    <string name=\"changes_not_saved\">Wijzigingen niet opgeslagen</string>\n    <string name=\"other\">Anders</string>\n    <string name=\"rules\">Regels</string>\n    <string name=\"pref_compression_method\">Compressiemethode</string>\n    <string name=\"pref_backup_flags_msg\">Door een voorinstelling voor back-upopties toe te voegen, hoeft u geen vlaggen meer te selecteren telkens wanneer u een back-up maakt of herstelt.</string>\n    <string name=\"confirm_installation\">Installatie bevestigen</string>\n    <string name=\"allow_open_pgp_operation\">Tik om toe te staan dat App Manager OpenPGP gebruikt</string>\n    <string name=\"uninstall_updates\">Updates verwijderen</string>\n    <string name=\"failed_to_uninstall_updates\">Kan updates voor <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g> niet verwijderen.</string>\n    <string name=\"sort_by_backup\">Geback-upt eerst</string>\n    <string name=\"filter_apps_with_backups\">Met back-ups</string>\n    <string name=\"expiry_date\">Vervaldatum</string>\n    <string name=\"type\">Type</string>\n    <string name=\"validity\">Geldigheid</string>\n    <string name=\"subject\">Onderwerp</string>\n    <string name=\"issuer\">Uitgever</string>\n    <string name=\"issued_date\">Uitgiftedatum</string>\n    <string name=\"checksums\">Checksums</string>\n    <string name=\"app_signing_signature\">Handtekening</string>\n    <string name=\"public_key\">Publieke sleutel</string>\n    <string name=\"format\">Indeling</string>\n    <string name=\"critical_exts\">Kritieke extensies</string>\n    <string name=\"usage_access_not_supported\">Kan geen gebruikstoegang aanvragen, omdat de bijbehorende instellingenpagina niet bestaat.</string>\n    <string name=\"rsa_exponent\">Exponent</string>\n    <string name=\"rsa_modulus\">Modulus</string>\n    <string name=\"dsa_affine_x\">Affiene x-coördinaat</string>\n    <string name=\"dsa_affine_y\">Affiene y-coördinaat</string>\n    <string name=\"app_signing_signature_mismatch_for_system_apps\">Kan de app niet installeren omdat een systeemapp met een andere handtekening deze pakketnaam heeft.</string>\n    <string name=\"app_data_will_be_lost\">De bestaande gegevens gaan verloren.</string>\n    <string name=\"only_install\">Alleen installeren</string>\n    <string name=\"select_user\">Gebruiker selecteren</string>\n    <string name=\"pref_encryption_msg\">Versleuteling voor back-ups.</string>\n    <string name=\"none\">Geen</string>\n    <string name=\"aes\">AES</string>\n    <string name=\"rsa\">RSA</string>\n    <string name=\"ecc\">Elliptische curve-cryptografie</string>\n    <string name=\"send_selected\">Geselecteerde verzenden</string>\n    <string name=\"pref_mode_of_operations\">Werkingswijze</string>\n    <string name=\"adb_over_tcp\">ADB over TCP</string>\n    <string name=\"allow_routine_ops\">Sta routineoperaties toe</string>\n    <string name=\"profile_state\">Profielstatus</string>\n    <string name=\"profile_clear_cache_msg\">Wist de app-cache van apps</string>\n    <string name=\"profile_clear_data_msg\">Wist de gegevens van apps</string>\n    <string name=\"profile_block_trackers_msg\">Blokkeert trackers in apps</string>\n    <string name=\"profile_state_msg\">Aangepaste aan/uit-status voor dit profiel</string>\n    <string name=\"off\">Uit</string>\n    <string name=\"options\">Opties</string>\n    <string name=\"input_permissions\">Invoermachtigingen</string>\n    <string name=\"decimal_value\">Decimale waarde</string>\n    <string name=\"pref_import_export_blocking_rules\">Importeer/exporteer blokkeerregels</string>\n    <string name=\"second_degree_tracker_note\">² voorvoegsel geeft aan dat de trackers in de <a href=\"https://etip.exodus-privacy.eu.org/\">ETIP stand-by lijst</a> staan, d.w.z. of het daadwerkelijke trackers zijn, wordt nog onderzocht.</string>\n    <string name=\"sort_by_app_ops_values\">App ops-waarde</string>\n    <string name=\"credits_message\">Aan de auteurs van\\n- Het Android Open Source Project\\n- <a href=\"https://github.com/zhaobozhen/libraries\">De bibliotheken van Absinthe</a>\\n- <a href=\"https://github.com/butzist/ActivityLauncher\">Activity Launcher</a>\\n- <a href=\"https://bitbucket.org/oF2pks/fdroid-applications-info\">Apps_packages Info</a>\\n- <a href=\"https://github.com/zhaobao/AppsMonitor\">AppsMonitor</a>\\n- <a href=\"https://github.com/8enet/AppOpsX\">AppOpsX</a>\\n- <a href=\"https://github.com/gabrielemarioti/changeloglib\">ChangeLog-bibliotheek</a>\\n- <a href=\"https://bitbucket.org/oF2pks/fdroid-classyshark3xodus\">ClassySharkAndroid</a>\\n- <a href=\"https://github.com/billthefarmer/editor\">Editor</a>\\n- <a href=\"https://github.com/Raival-e/File-Explorer\">Bestandsverkenner</a>\\n- <a href=\"https://github.com/nex3z/FlowLayout\">FlowLayout</a>\\n- <a href=\"https://github.com/k3b/intent-intercept\">Intent Intercept</a>\\n- <a href=\"https://github.com/YarikSOffice/lingver\">Lingver</a>\\n- <a href=\"https://github.com/topjohnwu/Magisk\">Magisk</a>\\n- <a href=\"https://github.com/zhanghai/MaterialFiles\">Material Files</a>\\n- <a href=\"https://github.com/pluscubed/matlog\">MatLog</a>\\n- <a href=\"https://github.com/matrix-org/matrix-android-sdk\">Matrix Android SDK</a>\\n- <a href=\"https://github.com/jensstein/oandbackup\">OAndBackup</a>\\n- <a href=\"https://github.com/open-keychain/open-keychain\">Open Keychain</a>\\n- <a href=\"https://github.com/Aefyr/SAI\">SAI</a>\\n- <a href=\"https://github.com/RikkaApps/Shizuku\">Shizuku</a>\\n- <a href=\"https://github.com/eclipse/tm4e\">tm4e</a>\\n- <a href=\"https://github.com/tuyafeng/Watt\">Watt</a></string>\n    <plurals name=\"two_trackers_and_classes\">\n        <item quantity=\"one\">2 trackers met <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g> klassen</item>\n        <item quantity=\"other\">2 trackers met <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g> klassen</item>\n    </plurals>\n    <string name=\"done\">Gereed</string>\n    <string name=\"reset_to_default\">Resetten naar standaard</string>\n    <string name=\"source_code\">Broncode</string>\n    <string name=\"navigation_no_nav\">Geen navigatie</string>\n    <string name=\"pref_import_existing_msg\">Voeg componenten aan App Manager toe die door andere apps zijn uitgeschakeld. Wees voorzichtig bij het gebruik van deze tool, aangezien er veel valse positieven kunnen zijn. Kies alleen de apps waarvan u zeker bent.</string>\n    <string name=\"pref_app_language\">Taal</string>\n    <string name=\"sort_by_mobile_data\">Mobiele data</string>\n    <string name=\"date_installed\">Installatiedatum</string>\n    <string name=\"sort_by_times_opened\">Aantal keren geopend</string>\n    <string name=\"internal_data\">Interne gegevens</string>\n    <string name=\"error\">Fout</string>\n    <string name=\"sort_by_app_label\">App-label</string>\n    <string name=\"pref_import_watt_msg\">Importeer blokkeerregels uit Watt, waarbij elk bestand regels bevat voor één pakket als <tt>packagename.xml</tt> etc.</string>\n    <string name=\"pref_import_export_blocking_rules_msg\">Importeer/exporteer regels, externe regels importeren vanuit Watt of Blocker.</string>\n    <plurals name=\"main_list_date_days\">\n        <item quantity=\"one\"><xliff:g id=\"last_update_date\" example=\"20/10/2020\">%1$s</xliff:g> <xliff:g id=\"day_no\" example=\"5\">%2$d</xliff:g> dag</item>\n        <item quantity=\"other\"><xliff:g id=\"last_update_date\" example=\"20/10/2020\">%1$s</xliff:g> <xliff:g id=\"day_no\" example=\"5\">%2$d</xliff:g> dagen</item>\n    </plurals>\n    <string name=\"cache_size\">Cache</string>\n    <string name=\"error_creating_shortcut\">Fout bij maken van snelkoppeling</string>\n    <string name=\"user_id\">Gebruikers-ID</string>\n    <string name=\"installer_error_incompatible\">De app is niet compatibel met dit apparaat</string>\n    <string name=\"select_type\">Selecteer een type</string>\n    <string name=\"uninstalled_successfully\"><xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g> is verwijderd.</string>\n    <plurals name=\"other_trackers_and_classes\">\n        <item quantity=\"one\"><xliff:g id=\"tracker_no\" example=\"8\">%1$d</xliff:g> tracker met <xliff:g id=\"class_no\" example=\"50\">%2$d</xliff:g> klasse</item>\n        <item quantity=\"other\"><xliff:g id=\"tracker_no\" example=\"8\">%1$d</xliff:g> trackers met <xliff:g id=\"class_no\" example=\"50\">%2$d</xliff:g> klassen</item>\n    </plurals>\n    <string name=\"rules_not_applied\">Regels zijn niet toegepast</string>\n    <string name=\"touchscreen_stylus\">Stylus</string>\n    <string name=\"no_tracker_class\">Geen tracker classes</string>\n    <string name=\"failed_to_deny_dangerous_perms\">Kan niet alle gevaarlijke machtigingen intrekken</string>\n    <string name=\"pref_import_existing\">Importeer bestaande regels</string>\n    <string name=\"app_usage\">App-gebruik</string>\n    <string name=\"orientation_portrait\">Portret</string>\n    <string name=\"saved_successfully\">Opgeslagen</string>\n    <string name=\"running\">Actief</string>\n    <string name=\"installer_error_session_abandon\">Kan de installatiesessie niet verlaten</string>\n    <string name=\"orientation_user\">Gebruiker</string>\n    <string name=\"saving_failed\">Opslaan mislukt, probeer het opnieuw.</string>\n    <string name=\"disabled_app\">Uitgeschakeld</string>\n    <string name=\"failed_to_fetch_package_info\">Kan pakketgegevens niet ophalen</string>\n    <string name=\"non_critical_exts\">Niet-kritieke extensies</string>\n    <string name=\"serial_no\">Serienummer</string>\n    <string name=\"sort_by_denied_permissions\">Geweigerd eerst</string>\n    <string name=\"key_name_cannot_be_null\">Sleutelnaam mag niet leeg zijn</string>\n    <string name=\"touchscreen\">Touchscreen</string>\n    <plurals name=\"alert_failed_to_backup\">\n        <item quantity=\"one\">Kan geen back-up maken van %1$d app</item>\n        <item quantity=\"other\">Kan geen back-up maken van %1$d apps</item>\n    </plurals>\n    <string name=\"external_data\">Externe gegevens</string>\n    <string name=\"split_feature_name\">Functie: <xliff:g id=\"feature_name\" example=\"Visualizer\">%1$s</xliff:g></string>\n    <string name=\"failed_to_stop\">Kan <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g> niet stoppen.</string>\n    <string name=\"algorithm\">Algoritme</string>\n    <string name=\"valid\">Geldig</string>\n    <plurals name=\"alert_failed_to_block_components\">\n        <item quantity=\"one\">Kan componenten van %1$d app niet blokkeren</item>\n        <item quantity=\"other\">Kan componenten van %1$d apps niet blokkeren</item>\n    </plurals>\n    <string name=\"expired\">Vervallen</string>\n    <string name=\"source_code_links\"><a href=\"https://github.com/MuntashirAkon/AppManager\">GitHub</a> • <a href=\"https://gitlab.com/muntashir/AppManager\">GitLab</a> • <a href=\"https://0xacab.org/muntashir/AppManager\">Riseup</a> • <a href=\"https://codeberg.org/muntashir/AppManager\">Codeberg</a></string>\n    <string name=\"backup_obb_media\">OBB en Media</string>\n    <string name=\"do_you_want_to_uninstall_and_install\">Wilt u de app verwijderen en opnieuw installeren?</string>\n    <plurals name=\"alert_failed_to_disable_trackers\">\n        <item quantity=\"one\">Kan trackers van %1$d app niet uitschakelen</item>\n        <item quantity=\"other\">Kan trackers van %1$d apps niet uitschakelen</item>\n    </plurals>\n    <string name=\"mode\">Modus</string>\n    <string name=\"app_settings\">Instellingen</string>\n    <string name=\"ago\">geleden</string>\n    <string name=\"community\">Community</string>\n    <string name=\"launch_mode_multiple\">Meerdere</string>\n    <string name=\"community_links\"><a href=\"https://matrix.to/#/#appmanager:matrix.org\">Matrix</a> • <a href=\"https://t.me/AppManagerChannel\">Telegram</a> • <a href=\"https://x.com/AppManagerNews\">Twitter/X</a> • <a href=\"https://floss.social/@appmanager\">Mastodon</a></string>\n    <string name=\"orientation_no_sensor\">Geen sensor</string>\n    <string name=\"keyboard_12_keys\">12 toetsen</string>\n    <string name=\"accept_time\">Accepteer tijd</string>\n    <string name=\"pref_import_msg\">Importeer eerder geëxporteerde blokkeerregels uit App Manager.</string>\n    <plurals name=\"alert_failed_to_uninstall\">\n        <item quantity=\"one\">Kan %1$d app niet verwijderen</item>\n        <item quantity=\"other\">Kan %1$d apps niet verwijderen</item>\n    </plurals>\n    <string name=\"duration\">Duur</string>\n    <plurals name=\"alert_failed_to_force_stop\">\n        <item quantity=\"one\">Kan %1$d app niet geforceerd stoppen</item>\n        <item quantity=\"other\">Kan %1$d apps niet geforceerd stoppen</item>\n    </plurals>\n    <string name=\"permission_name\">Naam van machtiging</string>\n    <string name=\"pref_export_msg\">Exporteer blokkeerregels van App Manager naar externe opslag.</string>\n    <string name=\"orientation_landscape\">Landschap</string>\n    <string name=\"reject_time\">Afwijzingstijd</string>\n    <string name=\"blocking_rules\">Blokkeerregels</string>\n    <string name=\"failed_to_extract_obb_files\">Kan OBB-bestanden niet uitpakken</string>\n    <string name=\"whats_new\">Wat is er nieuw</string>\n    <string name=\"install_app_message\">Wil je deze app installeren?</string>\n    <string name=\"touchscreen_finger\">Vinger</string>\n    <string name=\"update_uninstalled_successfully\">Updates voor <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g> zijn verwijderd.</string>\n    <string name=\"sort_by_permission_names\">Naam van machtiging</string>\n    <string name=\"installer_error_blocked_device\">apparaat</string>\n    <string name=\"backup\">Back-up</string>\n    <plurals name=\"backup_exists_are_you_sure\">\n        <item quantity=\"one\">Back-up bestaat al. Weet u het zeker?</item>\n        <item quantity=\"other\">Meerdere apps hebben al een back-up. Weet u het zeker?</item>\n    </plurals>\n    <string name=\"installer_error_blocked\">Installatie geblokkeerd door <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g></string>\n    <string name=\"orientation_user_landscape\">Gebruiker landschap</string>\n    <string name=\"input_backup_name_description\">De back-upnaam mag niet met een cijfer beginnen en mag ook geen spaties bevatten. Laat het leeg als u de huidige datum en tijd wilt gebruiken.</string>\n    <string name=\"lib_details\">Details van bibliotheek</string>\n    <string name=\"filter_running_apps\">Actieve apps</string>\n    <string name=\"send_crash_report\">Verzend crashrapport</string>\n    <string name=\"select_apk\">Selecteer APK</string>\n    <string name=\"duplicate\">Duplicaat</string>\n    <string name=\"scanner\">Scanner</string>\n    <string name=\"encryption\">Encryptie</string>\n    <string name=\"sys_config\">Systeemconfiguratie</string>\n    <string name=\"tap_to_submit_crash_report\">Tik om het crashrapport te verzenden.</string>\n    <string name=\"conversion_failed\">Conversie mislukt.</string>\n    <string name=\"on\">Aan</string>\n    <string name=\"profile_force_stop_msg\">Stopt apps geforceerd</string>\n    <string name=\"view_missing_signatures\">Tik om handtekeningen te bekijken of in te sturen die nog niet in de database van App Manager staan.</string>\n    <string name=\"failed_to_duplicate_profile\">Kan profiel niet dupliceren</string>\n    <string name=\"no_libs\">Geen bibliotheken</string>\n    <string name=\"tap_to_see_details\">Tik om details te zien</string>\n    <string name=\"copy\">Kopiëren</string>\n    <string name=\"allow_routine_ops_msg\">Sta toe dat het profiel gebruikt kan worden in routinematige bewerkingen</string>\n    <string name=\"app_signing_install_without_data_loss\">Als u handtekeningverificatie heeft uitgeschakeld, kunt u de optie <b>Alleen installeren</b> gebruiken om de app te installeren zonder gegevensverlies.</string>\n    <string name=\"un_apkm\">UnApkm</string>\n    <string name=\"new_profile\">Nieuw profiel</string>\n    <string name=\"am_crashed\">App Manager is zojuist gecrasht</string>\n    <string name=\"input_profile_name\">Naam profiel</string>\n    <string name=\"input_profile_name_description\">De profielnaam mag geen spaties bevatten.</string>\n    <string name=\"in_progress\">In uitvoering</string>\n    <string name=\"input_permissions_description\">Invoermachtigingen met spaties, b.v. <tt>com.permission.GET_ACCOUNTS android.permission.ACCESS_MEDIA_LOCATION</tt> etc. Gebruik <tt>*</tt> om alle rechten aan te vragen.</string>\n    <string name=\"choose\">Kies</string>\n    <string name=\"enabled\">Ingeschakeld</string>\n    <string name=\"simple\">Eenvoudig</string>\n    <string name=\"advanced\">Geavanceerd</string>\n    <string name=\"user_profile_with_id\">Profiel: %1$s (%2$d)</string>\n    <string name=\"root\">Root</string>\n    <string name=\"no_root\">Geen root</string>\n    <string name=\"close\">Sluiten</string>\n    <string name=\"comment\">Opmerking</string>\n    <string name=\"installer\">Installateur</string>\n    <string name=\"install_location\">Installatielocatie</string>\n    <string name=\"install_location_internal_only\">Alleen intern</string>\n    <string name=\"install_location_prefer_external\">Geef de voorkeur aan extern</string>\n    <string name=\"pref_sign_apk\">APK ondertekenen</string>\n    <string name=\"pref_sign_apk_msg\">Onderteken APK-bestanden voor het installeren.</string>\n    <string name=\"app_signing_signature_schemes\">Handtekeningschema\\'s</string>\n    <string name=\"apk_signing\">APK-ondertekening</string>\n    <string name=\"pref_apk_signing_msg\">Stel handtekeningschema\\'s, aangepaste ondertekeningssleutel, enz. in.</string>\n    <string name=\"v1_scheme\">v1-schema (sinds Android 1.0)</string>\n    <string name=\"v2_scheme\">v2-schema (sinds Android 7.0)</string>\n    <string name=\"v3_scheme\">v3-schema (sinds Android 9)</string>\n    <string name=\"v4_scheme\">v4-schema (sinds Android 11)</string>\n    <string name=\"pref_signature_schemes_msg\">Voor een betere compatibiliteit dienen minimaal de schema\\'s v1 en v2 te worden geselecteerd. Voor het v4-schema is v2 of v3 vereist.</string>\n    <string name=\"verified\">Geverifieerd</string>\n    <string name=\"not_verified\">Niet geverifieerd</string>\n    <string name=\"source_stamp_verified\">SourceStamp geverifieerd.</string>\n    <string name=\"source_stamp_verified_and_identified_to_be_from_source\">SourceStamp geverifieerd en geïdentificeerd als afkomstig van <xliff:g id=\"source\" example=\"Google Play\">%1$s</xliff:g>.</string>\n    <string name=\"splits\">Splits</string>\n    <string name=\"input_keystore_pass\">Invoer KeyStore-wachtwoord</string>\n    <string name=\"input_keystore_pass_msg\">Tik hier om KeyStore-wachtwoord in te voeren</string>\n    <string name=\"input_keystore_alias_pass\">Wachtwoord voor alias <b>%1$s</b></string>\n    <string name=\"input_keystore_alias_pass_description\">Voer wachtwoord in voor de alias <b>%1$s</b>. U kunt dit leeg laten als het wachtwoord hetzelfde is als het KeyStore-wachtwoord.</string>\n    <string name=\"input_keystore_alias_pass_msg\">Tik hier om een wachtwoord op te geven voor %1$s</string>\n    <string name=\"no_app_ops_permission\">Geen toestemming om app-ops weer te geven</string>\n    <string name=\"this_action_cannot_be_undone\">Deze actie kan niet ongedaan gemaakt worden.</string>\n    <string name=\"pref_backup_android_keystore_msg\">Niet alle apps werken nadat ze zijn hersteld. Het herstellen van KeyStore werkt op de meeste apparaten niet.</string>\n    <string name=\"set_app_op_mode\">Stel app op-modus in</string>\n    <string name=\"filter_apps_with_splits\">Met splits</string>\n    <string name=\"value\">Waarde</string>\n    <string name=\"matching_activities\">Overeenkomende activiteiten</string>\n    <string name=\"activity_result\">Resultaat van de activiteit</string>\n    <string name=\"result_code\">Resultaatcode</string>\n    <string name=\"action\">Actie</string>\n    <string name=\"mime_type\">MIME-type</string>\n    <string name=\"uri\">URI</string>\n    <string name=\"share\">Delen</string>\n    <string name=\"interceptor\">Onderschepper</string>\n    <string name=\"set_custom_app_op\">Aangepaste app op instellen</string>\n    <string name=\"about_device\">Over het apparaat</string>\n    <string name=\"pref_about_device_msg\">Basisinformatie over het apparaat, zoals het Android-systeem, CPU, GPU, RAM, batterij, enz.</string>\n    <string name=\"brand_name\">Merk</string>\n    <string name=\"board_name\">Bord</string>\n    <string name=\"manufacturer\">Fabrikant</string>\n    <string name=\"security_providers\">Beveiligingsaanbieders</string>\n    <string name=\"support_architectures\">Ondersteunde architectuur</string>\n    <string name=\"no_of_cores\">Kernen</string>\n    <string name=\"gles_version\">OpenGL ES-versie</string>\n    <string name=\"memory\">Geheugen</string>\n    <string name=\"battery_capacity\">Capaciteit</string>\n    <string name=\"languages\">Talen</string>\n    <string name=\"users\">Gebruikers</string>\n    <string name=\"cpu\">CPU</string>\n    <string name=\"graphics\">Graphics</string>\n    <string name=\"battery\">Batterij</string>\n    <string name=\"security\">Beveiliging</string>\n    <string name=\"set_mode_for_app_ops_dots\">Stel modus in voor app ops…</string>\n    <string name=\"backup_internal_data_description\">Back-up interne gegevensmappen.</string>\n    <string name=\"backup_obb_media_description\">Back-up OBB- en mediamappen.</string>\n    <string name=\"backup_cache_description\">Back-up van de mappen <b>cache</b>, <b>no_cache</b> en <b>no_backup</b>.</string>\n    <string name=\"backup_extras\">Extra\\'s</string>\n    <string name=\"backup_rules_description\">Back-up configuratieregels van App Manager. <font fgcolor=\"#ff0000\">Afhankelijk van de machtigingen kunnen niet alle regels opnieuw worden toegepast tijdens het herstellen.</font></string>\n    <string name=\"backup_multiple_description\">Maak een aparte <i>benoemde</i> backup in plaats van de basisbackup.</string>\n    <string name=\"backup_skip_signature_checks_description\">Herstel back-ups die de checksumverificatie niet doorstaan of die andere APK-handtekeningen hebben dan de vorige back-ups.</string>\n    <string name=\"enforcing\">Afdwingen</string>\n    <string name=\"permissive\">Toestaan</string>\n    <string name=\"hardware\">Hardware</string>\n    <string name=\"size\">Afmeting</string>\n    <string name=\"scaling_factor\">Schaalfactor</string>\n    <string name=\"refresh_rate\">Verversingssnelheid</string>\n    <string name=\"window_size\">Venstergrootte</string>\n    <string name=\"failed_to_enable_magisk_hide\">Kan MagiskHide niet inschakelen</string>\n    <string name=\"pref_backup_restore_msg\">Pas back-up/herstel aan.</string>\n    <string name=\"backup_volume\">Back-upvolume</string>\n    <string name=\"pref_backup_volume_msg\">Selecteer het volume of de schijf waar de back-ups worden opgeslagen.</string>\n    <string name=\"no_volumes_found\">Kan geen volumes met schrijfrechten vinden.</string>\n    <string name=\"unencrypted\">Niet-versleuteld</string>\n    <string name=\"encrypted\">Versleuteld</string>\n    <string name=\"backup_custom_users\">Custom gebruikers</string>\n    <string name=\"backup_custom_users_description\">Back-ups alleen uitvoeren voor de opgegeven gebruikers</string>\n    <string name=\"backup_all_apps\">Back-up van alle apps</string>\n    <string name=\"backup_all_apps_msg\">Back-up van alle geïnstalleerde apps.</string>\n    <string name=\"backup_apps_without_backups\">Back-up apps zonder back-up</string>\n    <string name=\"backup_apps_without_backups_msg\">Back-up van apps zonder vorige back-ups.</string>\n    <string name=\"verify_and_redo_backups\">Back-ups verifiëren en opnieuw uitvoeren</string>\n    <string name=\"verify_and_redo_backups_msg\">Controleer de integriteit van de vorige back-ups en voer de back-ups waarvan de integriteitscontrole mislukt, opnieuw uit.</string>\n    <string name=\"redo_existing_backups_msg\">Back-up opnieuw uitvoeren voor geïnstalleerde apps met bestaande back-ups.</string>\n    <string name=\"backup_apps_with_changes\">Back-up maken van apps met wijzigingen</string>\n    <string name=\"restore_all\">Herstel alle apps</string>\n    <string name=\"restore_all_msg\">Herstel de basisback-up van alle apps waarvan een back-up is gemaakt.</string>\n    <string name=\"restore_not_installed_msg\">Herstel de basisback-up voor apps die momenteel niet zijn geïnstalleerd.</string>\n    <string name=\"backup_msg\">Back-up maken van apps met gegevens</string>\n    <string name=\"restore_msg\">Herstel apps met gegevens</string>\n    <string name=\"drm_free_apkm_msg\">Het APKM-bestand is DRM-vrij en hoeft niet naar APKS te worden geconverteerd.</string>\n    <string name=\"back_up\">Back-up</string>\n    <string name=\"internal_storage\">Interne opslagruimte</string>\n    <string name=\"sd_card\">SD-kaart</string>\n    <string name=\"failed_to_disable_magisk_hide\">Kan MagiskHide niet uitschakelen</string>\n    <string name=\"restore_not_installed\">Herstel niet-geïnstalleerde apps</string>\n    <string name=\"backup_apk_files_description\">Back-up APK-bestanden uit de bronmap, inclusief splits.</string>\n    <string name=\"restore_latest_msg\">Herstel reeds geïnstalleerde apps waarvan de versiecodes hoger zijn dan de geïnstalleerde versiecode.</string>\n    <string name=\"backup_external_data_description\">Back-up externe gegevensmappen.</string>\n    <string name=\"extras\">Extra\\'s</string>\n    <string name=\"keep_data_and_app_signing_signatures\">Bewaar gegevens en handtekeningen</string>\n    <string name=\"disable_background_run_description\">Stelt de <i>Negeer</i>-modus in voor de volgende app ops: <tt>RUN_IN_BACKGROUND</tt> (vanaf Android 7.0) en <tt>RUN_ANY_IN_BACKGROUND</tt> (vanaf Android 9).</string>\n    <string name=\"selinux\">SELinux</string>\n    <string name=\"bootloader\">Bootloader</string>\n    <string name=\"restore_latest\">Herstel meest recente back-ups</string>\n    <string name=\"external_storage\">Externe opslagruimte</string>\n    <string name=\"pref_backup_android_keystore\">Back-up apps met Android KeyStore</string>\n    <string name=\"category\">Categorieën</string>\n    <string name=\"backup_extras_description\">Back-up van app-machtigingen, batterijbesparings- en dataverbruikopties, MagiskHide-status, SSAID, enz. <font fgcolor=\"#ff0000\">Afhankelijk van de machtigingen kunnen niet alle extra\\'s worden hersteld.</font></string>\n    <string name=\"screen\">Scherm</string>\n    <string name=\"model\">Model</string>\n    <string name=\"vendor\">Leverancier</string>\n    <string name=\"density\">Dichtheid</string>\n    <string name=\"kernel\">Kernel</string>\n    <string name=\"patch_level\">Patch-niveau</string>\n    <string name=\"redo_existing_backups\">Bestaande back-ups opnieuw uitvoeren</string>\n    <string name=\"input_keystore_pass_description\">Voer het KeyStore-wachtwoord van App Manager in. Als u dit voor het eerst ziet, gebruik dan een wachtwoordgenerator om een wachtwoord te genereren en bewaar dit op een veilige plek voordat u het hier invoert.</string>\n    <string name=\"magisk_hide_enabled\">MagiskHide</string>\n    <string name=\"backup_apps_with_changes_msg\">Maak back-ups opnieuw voor apps met wijzigingen sinds de laatste back-up. Denk hierbij aan wijzigingen in grootte, versie en laatste starttijd.</string>\n    <string name=\"pref_vt_apikey_summary\">Scannen van APK-bestanden via VirusTotal inschakelen.</string>\n    <string name=\"failed_to_disable_magisk_deny_list\">Kan Magisk DenyList niet uitschakelen</string>\n    <string name=\"bouncy_castle_keystore\">Bouncy Castle KeyStore (BKS)</string>\n    <string name=\"last_actions\">Laatste acties</string>\n    <string name=\"installer_app_message\">Selecteer <b>Kiezen</b> om een keuze te maken uit de geïnstalleerde apps of selecteer <b>Aangepast</b> om een aangepaste pakketnaam op te geven.</string>\n    <plurals name=\"toast_log_truncated\">\n        <item quantity=\"one\">Log te groot, laatste %d regel wordt weergegeven.</item>\n        <item quantity=\"other\">Log te groot, laatste %d regels worden weergegeven.</item>\n    </plurals>\n    <string name=\"failed_to_load_key\">Kan de sleutel niet laden.</string>\n    <string name=\"pref_installer_msg\">Configureer het gedrag van het app-installateur.</string>\n    <string name=\"log_level_info\">Info</string>\n    <string name=\"pref_cat_appearance\">Uiterlijk</string>\n    <string name=\"pref_rules_msg\">Direct blokkeren, import/export/verwijder regels, etc.</string>\n    <string name=\"pref_default_blocking_method_description\">Methode die standaard wordt gebruikt op plaatsen waar er geen optie is om een blokkeermethode te selecteren.\\n<b>Opmerking:</b> \\\"IFW\\\" werkt niet met providers, in plaats daarvan wordt \\\"uitschakelen\\\" gebruikt.</string>\n    <string name=\"tracker\">Tracker</string>\n    <string name=\"pref_log_write_period_title\">Schrijfperiode</string>\n    <string name=\"text_include_device_info\">Apparaatgegevens opnemen</string>\n    <string name=\"omit_sensitive_info_summary\">Laat gevoelige informatie weg, zoals web-URL\\'s, telefoonnummers of e-mails.</string>\n    <string name=\"toast_invalid_selection\">Ongeldige selectie. Probeer het opnieuw.</string>\n    <string name=\"pref_always_on_background_msg\">Installeer apps altijd op de achtergrond en geef een melding wanneer ze klaar zijn.</string>\n    <string name=\"help_permissions_tab\">Deze rechten worden gedefinieerd door deze app en kunnen niet worden ingetrokken.</string>\n    <string name=\"minimum_version\">Min. versie: %d</string>\n    <string name=\"saved_filters\">Opgeslagen filters</string>\n    <string name=\"explore\">Verkennen</string>\n    <string name=\"invalid_password\">Ongeldig wachtwoord. Probeer opnieuw.</string>\n    <string name=\"pref_thread_count_hint\">De waarde moet tussen 0 en %1$d liggen, waarbij 0 het <i>maximale aantal bewerkingen op het gegeven tijdstip</i> betekent.</string>\n    <string name=\"authenticating\">Authenticeren…</string>\n    <string name=\"vt_uploading\">VirusTotal: Uploaden…</string>\n    <string name=\"so_type_shared_library\">Gedeelde bibliotheek</string>\n    <string name=\"endianness_little_endian\">Little endian</string>\n    <string name=\"system_partition\">Android-root</string>\n    <string name=\"pref_vt_apikey\">VirusTotal API-sleutel</string>\n    <string name=\"uses_play_app_signing_description\">Deze app bevat bepaalde markeringen die aangeven dat deze <i>mogelijk</i> gebruikmaakt van <a href=\"https://support.google.com/googleplay/android-developer/answer/9842756\">Play App Signing</a>. Bij deze methode worden de ondertekeningssleutels opgeslagen op de servers van Google en is Google verantwoordelijk voor de ondertekening van de app. Houd er rekening mee dat het matchen van ondertekeningsgegevens de enige manier is om te verifiëren dat de app niet is gewijzigd door iemand anders dan de ontwikkelaar (en in dit geval ook Google).</string>\n    <string name=\"binary_32_bit\">32 Bit</string>\n    <string name=\"save_and_exit\">Opslaan en afsluiten</string>\n    <string name=\"pref_saved_apk_name_format_msg\">De indeling die moet worden gebruikt voor de naamgeving van de APK-bestanden wanneer u ze opslaat.</string>\n    <string name=\"regenerate_auth_key_warning\">Weet je het zeker? Alle apps van derden moeten opnieuw worden geconfigureerd met de nieuwe autorisatiesleutel.</string>\n    <string name=\"open_in_new_window\">Nieuw venster</string>\n    <string name=\"import_backups_warning_delete_backups_after_import\">De back-ups verwijderen nadat u ze in App Manager heeft geïmporteerd? Elke back-up wordt afzonderlijk verwijderd nadat deze succesvol is geïmporteerd. Selecteer <b>Nee</b> als u het niet zeker weet.</string>\n    <plurals name=\"alert_failed_to_optimize_apps\">\n        <item quantity=\"one\">Kan %1$d app niet optimaliseren</item>\n        <item quantity=\"other\">Kan %1$d apps niet optimaliseren</item>\n    </plurals>\n    <string name=\"pref_enable_auto_lock_msg\">App Manager vergrendelen als het apparaat is vergrendeld.</string>\n    <string name=\"fm_always_open_with\">Altijd openen</string>\n    <string name=\"debloat_list_google\">Google</string>\n    <string name=\"export_app_list_select_format\">Selecteer indeling voor het exporteren van de applijst</string>\n    <string name=\"redo\">Opnieuw uitvoeren</string>\n    <string name=\"funding_campaign_dialog_message\">Voor een korte periode voeren we een <b>financieringscampagne</b> voor App Manager. Ga naar <a href=\"https://opencollective.com/app-manager#category-ABOUT\">opencollective.com/app-manager</a> voor meer informatie over de campagne. Deze melding wordt niet nogmaals weergegeven, maar is gedurende de gehele campagne wel te vinden op de pagina Instellingen.</string>\n    <string name=\"action_continue\">Verder</string>\n    <string name=\"app_info_tag_open_links\">Open links</string>\n    <string name=\"pref_zip_align_msg\">Het uitlijnen van een APK-bestand vermindert het geheugengebruik, omdat de bestanden in de APK direct toegankelijk zijn zonder de gegevens naar het RAM-geheugen te kopiëren. Deze stap is vereist als <tt>extractNativeLibs</tt> is ingesteld op <tt>true</tt>.</string>\n    <plurals name=\"alert_failed_to_unfreeze\">\n        <item quantity=\"one\">Kan %1$d app niet ontdooien</item>\n        <item quantity=\"other\">Kan %1$d apps niet ontdooien</item>\n    </plurals>\n    <string name=\"confirm_uninstallation\">Bevestig verwijdering</string>\n    <string name=\"browse_files\">Bladeren</string>\n    <string name=\"vt_confirm_uploading_file\">Het bestand is niet gevonden in de VirusTotal-database. Wilt u het uploaden?</string>\n    <string name=\"usage_times_opened\">Keren geopend</string>\n    <string name=\"suspend_app\">Opschorten</string>\n    <string name=\"hide_app\">Verbergen</string>\n    <string name=\"uninstall_app\">Verwijder %1$s</string>\n    <string name=\"title_domains_supported_by_the_app\">Ondersteunde domeinen</string>\n    <string name=\"uninstall_app_again_message\">De app is verwijderd zonder de gegevens en handtekening te wissen. Wilt u de app volledig verwijderen?</string>\n    <string name=\"module_name\">Modulenaam</string>\n    <string name=\"debloat_list_carrier\">Provider/ISP</string>\n    <string name=\"replacement_text\">Vervanging</string>\n    <string name=\"system_app_put_back\">Terugzetten</string>\n    <string name=\"grant_required_permission\">Verleen de vereiste rechten</string>\n    <string name=\"read_only_file\">Alleen-lezen bestand</string>\n    <string name=\"mode_of_op_custom_command\">Als u geen van de modi kunt gebruiken, kunt u de volgende opdracht uitvoeren in een ondersteunde shell om App Manager in de bevoorrechte modus uit te voeren:</string>\n    <string name=\"advanced_suspend_app_description\">Het stopt de app geforceerd en schort deze op om ervoor te zorgen dat de app niet op de achtergrond draait. Deze methode verdient de voorkeur boven de reguliere <b>opschortings</b> methode.</string>\n    <string name=\"hide_app_description\">Deze methode wordt alleen aanbevolen voor dagelijks gebruik. Een verborgen app wordt weergegeven alsof deze is verwijderd. Maar de app kan opnieuw verschijnen als deze opnieuw wordt geïnstalleerd of bijgewerkt.</string>\n    <string name=\"file_open_as\">Open als…</string>\n    <string name=\"app_manager_build_expired_message\">Om de veiligheid van uw apparaat en gegevens te garanderen, is de versie van App Manager die u gebruikt, buiten werking gesteld. U moet het bijwerken naar de nieuwste versie om het te kunnen blijven gebruiken, of het verwijderen als er geen update beschikbaar is.</string>\n    <string name=\"pref_zip_align\">APK-bestanden uitlijnen</string>\n    <string name=\"debloat_removal_type\">Type</string>\n    <string name=\"title_change_selinux_context\">Wijzig SELinux-context</string>\n    <string name=\"app_can_write_and_execute_in_same_place\">De app schendt het <a href=\"https://en.wikipedia.org/wiki/W%5EX\">W^X-policy</a> en kan in dezelfde directory of in hetzelfde geheugengedeelte schrijven en uitvoeren. Hierdoor kunnen willekeurige uitvoerbare bestanden worden uitgevoerd, hetzij door de wijziging van uitvoerbare bestanden die in de app zijn ingebed, hetzij door ze van internet te downloaden. Tenzij dit het beoogde gedrag van de app is (bijv. terminal-emulators), is het raadzaam een nieuwere versie van de app te zoeken die SDK 29 (Android 10) en later ondersteunt, of alternatieven te zoeken.</string>\n    <string name=\"mode_of_op_custom_command_title\">Aangepaste opdracht</string>\n    <string name=\"action_optimize_app\">Optimaliseren</string>\n    <string name=\"select_filter\">Selecteer een filter</string>\n    <plurals name=\"search_results\">\n        <item quantity=\"one\">%d resultaat</item>\n        <item quantity=\"other\">%d resultaten</item>\n    </plurals>\n    <string name=\"search_option_match_case\">Match zoekopdracht</string>\n    <string name=\"search_option_regex\">Regex</string>\n    <string name=\"pref_enable_persistent_session_msg\">Het uitvoeren van App Manager op de achtergrond vermindert de vertraging bij opstarten. Handig als u App Manager veelvuldig gebruikt.</string>\n    <string name=\"pref_enable_auto_lock\">Automatische vergrendeling</string>\n    <string name=\"funding_campaign_text\">Voor een korte periode voeren we een <b>financieringscampagne</b> voor App Manager. <a href=\"https://opencollective.com/app-manager#category-ABOUT\">learn more…</a></string>\n    <string name=\"action_replace_all\">Alles vervangen</string>\n    <string name=\"adb_incomplete_usb_debugging_message\">Het lijkt erop dat USB-foutopsporing niet correct is geconfigureerd. Lees <a href=\"https://muntashirakon.github.io/AppManager/#subsec:enable-usb-debugging\">de documentatie</a> voor aanvullende stappen. Als u de stappen al kent, klik dan op \\\"Openen\\\" om de ontwikkelaarsopties te openen of klik op \\\"Sluiten\\\" om de no-rootmodus te blijven gebruiken.</string>\n    <string name=\"pref_files_remember_last_path_msg\">Wanneer deze optie is ingeschakeld, wordt bij het openen van een nieuw venster de laatst geopende map geopend in plaats van de thuismap.</string>\n    <string name=\"install_for_another_user\">Installeer voor…</string>\n    <string name=\"debloater_title\">Debloater</string>\n    <string name=\"debloat_list_misc\">Diversen</string>\n    <string name=\"grant_overlay_permission_message\">Sta toe dat App Manager een zwevend venster boven alle andere vensters weergeeft</string>\n    <string name=\"debloat_list_oem\">OEM</string>\n    <string name=\"batch_ops_runtime_optimization\">Runtime-optimalisatie</string>\n    <string name=\"title_code_editor\">Code-editor</string>\n    <string name=\"search_option_whole_word\">Hele woord</string>\n    <string name=\"debloat_list_aosp\">AOSP</string>\n    <string name=\"debloat_list_type\">Lijst</string>\n    <string name=\"debloat_removal_safe\">Veilig</string>\n    <string name=\"enter_symbolic_link_name\">Linknaam</string>\n    <string name=\"copy_these_paths\">Kopieer paden</string>\n    <string name=\"finder_title\">Vinder</string>\n    <string name=\"app_manager_is_running\">App Manager is actief</string>\n    <string name=\"title_confirm_execution\">Uitvoering bevestigen</string>\n    <string name=\"clear_history\">Geschiedenis wissen</string>\n    <string name=\"pref_enable_disable_features_msg\">Functies in App Manager in- of uitschakelen.</string>\n    <string name=\"netpolicy_reject_wifi_data\">Wi-Fi weigeren</string>\n    <string name=\"uses_play_app_signing\">Play App-ondertekening</string>\n    <string name=\"vt_queued\">VirusTotal: In de wachtrij</string>\n    <string name=\"pkcs12_keystore\">PKCS #12 KeyStore (P12)</string>\n    <string name=\"use_default\">Standaard gebruiken</string>\n    <string name=\"pref_log_viewer_msg\">Configureer hoe logs worden weergegeven.</string>\n    <plurals name=\"alert_failed_to_import_backups\">\n        <item quantity=\"one\">Kan %1$d back-up niet importeren</item>\n        <item quantity=\"other\">Kan %1$d back-ups niet importeren</item>\n    </plurals>\n    <string name=\"toast_invalid_level\">Ongeldige niveaunaam: %s</string>\n    <string name=\"no_changes\">Geen wijzigingen</string>\n    <string name=\"open\">Openen</string>\n    <string name=\"pref_buffer_title\">Logboekbuffer(s)</string>\n    <string name=\"type_uri_array\">Reeks van URI\\'s</string>\n    <string name=\"primary_abi\">Primaire ABI</string>\n    <string name=\"filter_choice_pid\">PID</string>\n    <string name=\"binary_64_bit\">64 Bit</string>\n    <string name=\"hidden_api_enf_policy_dark_grey_and_black\">Handhaven (donkergrijze en zwarte lijsten)</string>\n    <string name=\"isolated\">Geïsoleerd</string>\n    <string name=\"restart_log_viewer_to_see_changes\">Herstart het logboekweergavevenster om de wijzigingen te zien.</string>\n    <string name=\"log_saved\">Logboek opgeslagen.</string>\n    <string name=\"netpolicy_reject_vpn_data\">VPN weigeren</string>\n    <string name=\"pref_display_limit_hint\" tools:ignore=\"PluralsCandidate\">Voer een geldig getal in tussen %1$d en %2$d.</string>\n    <string name=\"log_level_error\">Fout</string>\n    <string name=\"netpolicy_reject_cellular_data\">Mobiele data weigeren</string>\n    <plurals name=\"pref_thread_count_msg\">\n        <item quantity=\"one\">Voer maximaal %1$d bewerking tegelijkertijd uit</item>\n        <item quantity=\"other\">Voer maximaal %1$d bewerkingen tegelijkertijd uit</item>\n    </plurals>\n    <string name=\"sort_by_target_sdk\">Target-SDK</string>\n    <string name=\"version_name_with_code\">Versie <xliff:g id=\"version_name\" example=\"2.5.17\">%1$s</xliff:g> (<xliff:g id=\"version_code\" example=\"365\">%2$d</xliff:g>)</string>\n    <string name=\"starting_activity\">Start activiteit: <xliff:g id=\"activity_name\" example=\".main.MainActivity\">%1$s</xliff:g></string>\n    <string name=\"toggle_class_listing\">Schakel class listing in/uit</string>\n    <string name=\"unknown_split_for_feature\"><xliff:g id=\"split_name\" example=\"some_split\">%1$s</xliff:g> voor functie <xliff:g id=\"feature_name\" example=\"Visualizer\">%2$s</xliff:g></string>\n    <string name=\"unknown_split_for_base_apk\"><xliff:g id=\"split_name\" example=\"some_split\">%1$s</xliff:g> voor basis-APK</string>\n    <string name=\"density_split_for_feature\"><xliff:g id=\"split_name\" example=\"xxdpi\">%1$s</xliff:g> (<xliff:g id=\"dpi_no\" example=\"480\">%2$d</xliff:g> DPI) bronnen voor functie <xliff:g id=\"feature_name\" example=\"Visualizer\">%3$s</xliff:g></string>\n    <string name=\"density_split_for_base_apk\"><xliff:g id=\"split_name\" example=\"xxdpi\">%1$s</xliff:g> (<xliff:g id=\"dpi_no\" example=\"480\">%2$d</xliff:g> DPI) bronnen voor basis-APK</string>\n    <string name=\"abi_split_for_feature\"><xliff:g id=\"split_name\" example=\"arm64_v8a\">%1$s</xliff:g> code voor <xliff:g id=\"feature_name\" example=\"Visualizer\">%2$s</xliff:g></string>\n    <string name=\"abi_split_for_base_apk\"><xliff:g id=\"split_name\" example=\"arm64_v8a\">%1$s</xliff:g> code voor basis-APK</string>\n    <string name=\"locale_split_for_feature\"><xliff:g id=\"split_name\" example=\"English\">%1$s</xliff:g> landinstelling voor functie <xliff:g id=\"feature_name\" example=\"Visualizer\">%2$s</xliff:g></string>\n    <string name=\"locale_split_for_base_apk\"><xliff:g id=\"split_name\" example=\"English\">%1$s</xliff:g> landinstelling voor basis-APK</string>\n    <string name=\"process_state\">Status: <xliff:g id=\"process_state\" example=\"Sleeping\">%1$s</xliff:g></string>\n    <string name=\"process_state_with_extra\">Status: <xliff:g id=\"process_state\" example=\"Sleeping\">%1$s</xliff:g> (<xliff:g id=\"state_extra\" example=\"High priority\">%2$s</xliff:g>)</string>\n    <string name=\"systemless_app\">Systeemloze app</string>\n    <string name=\"state_trace_stop\">Trace stop</string>\n    <string name=\"state_dead\">Dead</string>\n    <string name=\"state_wake_kill\">Wake kill</string>\n    <string name=\"state_waking\">Waking</string>\n    <string name=\"state_session_leader\">Sessieleider</string>\n    <string name=\"keystore\">KeyStore</string>\n    <string name=\"routine_ops\">Routine ops</string>\n    <string name=\"send_edited_intent\">Verstuur bewerkte intentie</string>\n    <string name=\"resend_intent\">Intentie opnieuw verzenden</string>\n    <string name=\"unlock_app_manager\">Ontgrendel App Manager</string>\n    <string name=\"screen_lock\">Schermvergrendeling</string>\n    <string name=\"screen_lock_msg\">Vergrendel App Manager met Android-schermvergrendeling</string>\n    <string name=\"type_null\">Geen waarde</string>\n    <string name=\"type_component_name\">Naam van component</string>\n    <string name=\"type_int_array\">Reeks gehele getallen</string>\n    <string name=\"type_int_array_list\">Lijst met gehele getallen</string>\n    <string name=\"type_long_array\">Reeks lange gehele getallen</string>\n    <string name=\"type_long_array_list\">Lijst met lange gehele getallen</string>\n    <string name=\"type_float_array\">Reeks decimale getallen</string>\n    <string name=\"type_float_array_list\">Lijst met decimale getallen</string>\n    <string name=\"type_string_array\">Reeks van strings</string>\n    <string name=\"type_string_array_list\">Lijst van strings</string>\n    <string name=\"type_uri\">URI</string>\n    <string name=\"no_battery_optimization\">Geen batterijoptimalisatie</string>\n    <string name=\"battery_optimization\">Batterijoptimalisatie</string>\n    <string name=\"enable_battery_optimization\">Batterijoptimalisatie inschakelen?</string>\n    <string name=\"choose_what_to_do\">Kies wat te doen.</string>\n    <string name=\"has_net_policy\">Internetbeleid</string>\n    <string name=\"net_policy\">Internetbeleid</string>\n    <string name=\"initializing\">Initialiseren…</string>\n    <string name=\"add_to_profile\">Toevoegen aan profiel</string>\n    <string name=\"add\">Toevoegen</string>\n    <string name=\"os_version\">OS-versie</string>\n    <string name=\"reverse\">Terugdraaien</string>\n    <string name=\"list_options\">Opties weergeven</string>\n    <string name=\"ssaid\">SSAID</string>\n    <string name=\"ssaid_info\">SSAID (<tt>Settings.Secure.ANDROID_ID</tt>) is een apparaat-ID die aan elke app is toegewezen (vanaf Android 8 \\\"Oreo\\\" en later). Het wordt veel gebruikt door apps om gebruikers te volgen.</string>\n    <string name=\"copied_to_clipboard\">Gekopieerd naar klembord.</string>\n    <string name=\"failed_to_change_ssaid\">Kan SSAID niet wijzigen</string>\n    <string name=\"restart_to_reflect_changes\">U moet het apparaat onmiddellijk herstarten om de nieuwe wijzigingen te gebruiken.</string>\n    <string name=\"installed_apps\">Geïnstalleerde apps</string>\n    <string name=\"enable_disable_features\">Functies in-/uitschakelen</string>\n    <string name=\"screen_lock_not_enabled\">Kies een schermvergrendeling in de Android-instellingen of wis de app-gegevens.</string>\n    <string name=\"working_on_adb_mode\">Er wordt gewerkt aan de ADB-modus</string>\n    <string name=\"verified_using_unreliable_hash\">Geverifieerd met onbetrouwbare hash</string>\n    <string name=\"specify_custom_name\">Aangepast</string>\n    <string name=\"uninstalled_apps\">Verwijderde apps</string>\n    <string name=\"filter_apps_without_backups\">Zonder back-ups</string>\n    <string name=\"input_key\">Invoersleutel (in hexadecimaal)</string>\n    <string name=\"generate_key\">Genereer</string>\n    <string name=\"failed_to_save_key\">Kan sleutel niet opslaan.</string>\n    <string name=\"failed_to_initialize_key_store\">Kan App Manager-keystore niet initialiseren.</string>\n    <string name=\"invalid_aes_key_size\">Ongeldige sleutelgrootte voor AES-encryptie. De sleutelgrootte kan 128 of 256 bits bedragen.</string>\n    <string name=\"crypto_key_size\">Sleutelgrootte</string>\n    <string name=\"invalid_rsa_key_size\">Ongeldige sleutelgrootte voor RSA-encryptie. De sleutelgrootte kan 1024, 2048 of 4096 bits bedragen.</string>\n    <string name=\"key_not_set\">Niet ingesteld.</string>\n    <string name=\"input_key_password\">Sleutelwachtwoord</string>\n    <string name=\"common_name\">Algemene naam (CN)</string>\n    <string name=\"organization_unit\">Organisatie-eenheid (OU)</string>\n    <string name=\"organization_name\">Organisatienaam (O)</string>\n    <string name=\"locality_name\">Plaatsnaam (stad) (L)</string>\n    <string name=\"state_name\">Naam van staat (ST)</string>\n    <string name=\"country_name\" tools:ignore=\"TypographyOther\">Landnaam (C)</string>\n    <string name=\"keystore_file\">KeyStore-bestand</string>\n    <string name=\"keystore_pass\">KeyStore-wachtwoord</string>\n    <string name=\"java_keystore\">Java KeyStore (JKS)</string>\n    <string name=\"pem_and_pk8\">PEM en PKCS #8 (PK8)</string>\n    <string name=\"pk8_file\">PKCS #8 (PK8) bestand</string>\n    <string name=\"pem_file\">PEM bestand</string>\n    <string name=\"import_key\">Importeer sleutel</string>\n    <string name=\"new_alias_password\">Nieuw aliaswachtwoord</string>\n    <string name=\"found_no_alias_in_keystore\">Geen alias gevonden in de KeyStore!</string>\n    <string name=\"choose_an_alias\">Kies een alias</string>\n    <string name=\"alias_pass\">Alias-wachtwoord</string>\n    <string name=\"failed_to_read_keystore\">Kon de KeyStore niet lezen.</string>\n    <string name=\"signing_key\">Ondertekeningssleutel</string>\n    <string name=\"expiry_date_cannot_be_empty\">Vervaldatum mag niet leeg zijn.</string>\n    <string name=\"pref_import_backups\">Back-ups importeren</string>\n    <string name=\"pref_import_backups_msg\">Importeer back-ups van OAndBackup, Swift Backup (3.0–3.2) of Titanium Backup.</string>\n    <string name=\"import_from_oab\">Importeren vanuit OAndBackup</string>\n    <string name=\"import_from_tb\">Importeren vanuit Titanium Backup</string>\n    <string name=\"log_viewer\">Logboekviewer</string>\n    <string name=\"filename\">Bestandsnaam</string>\n    <string name=\"log_level_debug\">Foutopsporing</string>\n    <string name=\"log_level_verbose\">Uitgebreid</string>\n    <string name=\"log_level_warn\">Waarschuwen</string>\n    <string name=\"log_level_fatal\">Fataal</string>\n    <string name=\"add_filter\">Filter toevoegen</string>\n    <string name=\"add_filter_ellipsis\">Filter toevoegen…</string>\n    <plurals name=\"file_deletion_confirmation\">\n        <item quantity=\"one\">%d bestand wordt verwijderd</item>\n        <item quantity=\"other\">%d bestanden worden verwijderd</item>\n    </plurals>\n    <string name=\"copy_to_clipboard\">Kopiëren naar klembord</string>\n    <string name=\"delete_saved_log\">Verwijder opgeslagen logboeken</string>\n    <string name=\"dialog_compiling_log\">Logboek compileren…</string>\n    <string name=\"enter_filename\">Voer bestandsnaam in</string>\n    <string name=\"enter_good_filename\">Voer een geldige bestandsnaam in.</string>\n    <string name=\"filter_choice\">Zoeken op</string>\n    <string name=\"filter_choice_tag\">Label</string>\n    <string name=\"log_cleared\">Logboeken gewist</string>\n    <string name=\"log_level\">Logniveau</string>\n    <string name=\"log_recording_started\">Logboekregistratie gestart.</string>\n    <string name=\"manage_saved_logs\">Beheer opgeslagen logs</string>\n    <string name=\"no_saved_logs\">Geen opgeslagen logs.</string>\n    <string name=\"notification_subtext\">Tik om de opname te stoppen</string>\n    <string name=\"notification_ticker\">Logboekregistratie gestart</string>\n    <string name=\"notification_title\">Logboekregistratie is bezig</string>\n    <string name=\"pref_cat_advanced\">Geavanceerd</string>\n    <string name=\"pref_cat_configuration\">Configuratie</string>\n    <string name=\"pref_default_log_level_summary\">Logniveau bij opstarten, bij het openen van bestanden en bij opnemen.</string>\n    <string name=\"pref_default_log_level_title\">Standaard logniveau</string>\n    <string name=\"pref_display_limit_summary\" tools:ignore=\"PluralsCandidate\">Toon alleen de laatste %1$d logs om fouten met onvoldoende geheugen te voorkomen.</string>\n    <string name=\"pref_display_limit_title\">Weergavelimiet logbestanden</string>\n    <string name=\"pref_filter_pattern_summary\">Filter de geselecteerde tags uit de logs.</string>\n    <string name=\"pref_filter_pattern_title\">Tags filteren</string>\n    <string name=\"pref_expanded_by_default_summary\">Toon standaard de volledige logtekst.</string>\n    <string name=\"pref_expanded_by_default_title\">Standaard uitvouwen</string>\n    <string name=\"pref_log_line_period_error\">Voer een geheel getal tussen 1 en 1000 in.</string>\n    <string name=\"pref_log_write_period_summary\" tools:ignore=\"PluralsCandidate\">Schrijf tijdens het opnemen elke %1$d regels naar de SD-kaart.</string>\n    <string name=\"pref_show_timestamp_summary\">Toon proces-ID en tijdstempel wanneer uitgevouwen.</string>\n    <string name=\"pref_show_timestamp_title\">Toon Pid en tijdstempel</string>\n    <string name=\"record_log\">Opnamelogboek</string>\n    <string name=\"save_as\">Opslaan als…</string>\n    <string name=\"save_log\">Logboek opslaan</string>\n    <string name=\"send_log_title\">Verstuur logboek</string>\n    <string name=\"settings\">Instellingen</string>\n    <string name=\"start_recording_log\">Opnemen</string>\n    <string name=\"subject_log_report\">Logboekrapport</string>\n    <string name=\"text_filter_ellipsis\">Filteren…</string>\n    <string name=\"text_filter_text\">Filter tekst</string>\n    <string name=\"unable_to_save_log\">Kan logboek niet opslaan. Heeft u een geldige bestandsnaam ingevoerd?</string>\n    <string name=\"widget_recording_in_progress\">Opnemen…</string>\n    <string name=\"widget_start_recording\">Log</string>\n    <string name=\"file\">Bestand</string>\n    <string name=\"expand_all\">Alles uitvouwen</string>\n    <string name=\"collapse_all\">Alles samenvouwen</string>\n    <string name=\"pause_unpause\">Afspelen/Pauzeren</string>\n    <string name=\"undo\">Ongedaan maken</string>\n    <string name=\"omit_sensitive_info\">Gevoelige informatie weglaten</string>\n    <string name=\"text_include_dmesg\">Inclusief kernellogboek</string>\n    <string name=\"share_log\">Delen</string>\n    <string name=\"view_logs\">Bekijk logs</string>\n    <string name=\"running_services\">Actieve services</string>\n    <string name=\"save_apk\">APK opslaan</string>\n    <string name=\"profile_save_apk_msg\">Bewaart APK-bestanden in <tt>AppManager/apks</tt></string>\n    <string name=\"failed_to_block_trackers\">Kan trackers niet blokkeren</string>\n    <string name=\"failed_to_unblock_trackers\">Kan trackers niet deblokkeren</string>\n    <string name=\"trackers_blocked_successfully\">Trackers zijn nu geblokkeerd</string>\n    <string name=\"trackers_unblocked_successfully\">Trackers zijn nu gedeblokkeerd</string>\n    <string name=\"base_backup\">Basis back-up</string>\n    <string name=\"no_encryption\">Geen encryptie</string>\n    <string name=\"pgp_aes_rsa_encrypted\">%1$s versleuteld</string>\n    <string name=\"gz_bz2_compressed\">%1$s gecomprimeerd</string>\n    <string name=\"latest_backup\">Laatste back-up</string>\n    <string name=\"pref_import_export_keystore\">KeyStore importeren/exporteren</string>\n    <string name=\"pref_import_export_keystore_msg\">Importeer/exporteer Bouncy Castle KeyStore (BKS) intern gebruikt door App Manager.</string>\n    <string name=\"import_keystore\">Importeer KeyStore</string>\n    <string name=\"confirm_import_keystore\">Weet u zeker dat u de huidige KeyStore wilt vervangen? Deze actie kan niet ongedaan gemaakt worden.</string>\n    <string name=\"failed\">Mislukt</string>\n    <string name=\"saf\">SAF</string>\n    <string name=\"pref_layout_direction\">Richting lay-out</string>\n    <string name=\"orientation_follow_locale\">Volg de landinstelling</string>\n    <string name=\"orientation_left_to_right\">Links naar rechts</string>\n    <string name=\"orientation_right_to_left\">Rechts naar links</string>\n    <string name=\"suspended\">Opgeschort</string>\n    <string name=\"hidden\">Verborgen</string>\n    <string name=\"pref_display_changes\">Wijzigingen weergeven</string>\n    <string name=\"pref_display_changes_msg\">Geef wijzigingen in versie, trackers, componenten, rechten, handtekeningen, SDK, etc. op een versiegestuurde manier weer.</string>\n    <string name=\"netpolicy_reject_background_data\">Weigeren achtergronddata</string>\n    <string name=\"netpolicy_reject_metered_background_data\">Weiger achtergrondgegevens op gemeten netwerken</string>\n    <string name=\"netpolicy_reject_metered_data\">Weiger data op gemeten netwerken</string>\n    <string name=\"netpolicy_allow_metered_background_data\">Sta achtergrondgegevens toe op gemeten netwerken, zelfs als Databesparing is ingeschakeld</string>\n    <string name=\"netpolicy_allow_background_data\">Achtergrondgegevens toestaan wanneer Databesparing is ingeschakeld</string>\n    <string name=\"netpolicy_disable_network_access\">Netwerktoegang uitschakelen</string>\n    <string name=\"wireless_debugging\">Draadloze foutopsporing</string>\n    <string name=\"adb_connect\">Verbinden</string>\n    <string name=\"port_number\">Poort</string>\n    <string name=\"adb_connect_port_number_description\">Het poortnummer bevindt zich onder <b>IP-adres &amp; port</b>-sectie net onder de <b>Apparaatnaam</b>-sectie.</string>\n    <string name=\"port_number_empty\">Poortnummer is leeg.</string>\n    <string name=\"port_number_invalid\">Ongeldig poortnummer.</string>\n    <string name=\"unknown_net_policy\">Onbekend netwerkbeleid (%1$s - %2$X)</string>\n    <string name=\"failed_to_prevent_background_run\">Kan niet voorkomen dat %1$s op de achtergrond draait</string>\n    <string name=\"help_app_ops_tab\">Klik op een item om het <b>toe te staan</b> of <b>te negeren</b>. Klik lang op een item om andere ondersteunde modi te bekijken.</string>\n    <string name=\"help_uses_permissions_tab\">Klik op een item om het te <b>verlenen</b> of <b>in te trekken</b>. Alleen <b>gevaarlijke</b> en <b>ontwikkelings</b> rechten kunnen worden verleend of ingetrokken.</string>\n    <string name=\"added_to_queue\">Toegevoegd aan wachtrij</string>\n    <string name=\"pref_selected_users\">Geselecteerde gebruikers</string>\n    <string name=\"pref_selected_users_msg\">Laat App Manager alleen voor geselecteerde gebruikers werken.</string>\n    <string name=\"permission_flags\">Toestemmingsvlaggen</string>\n    <string name=\"error_with_details\">Fout: %s</string>\n    <string name=\"notice\">Kennisgeving</string>\n    <string name=\"notice_saf\">In tegenstelling tot de volumes wordt de geselecteerde directory gebruikt om alle bestanden met betrekking tot App Manager op te slaan, inclusief opgeslagen APK\\'s en back-ups. Storage Access Framework (SAF) is erg traag, daarom moet u deze optie alleen gebruiken als andere niet kunnen worden gebruikt.</string>\n    <string name=\"backup_volume_dialog_description\">Volumes met het voorvoegsel <tt>/tree</tt> zijn mappen die zijn geselecteerd met Storage Access Framework (SAF). Behalve deze mappen is de standaardmap voor App Manager een submap met de naam <tt>AppManager</tt>.</string>\n    <string name=\"storage\">Opslag</string>\n    <string name=\"files\">Bestanden</string>\n    <string name=\"keystore_password_info\">Hieronder volgt het App Manager KeyStore-wachtwoord. Bewaar dit op een veilige plek als u een back-up van de App Manager KeyStore wilt maken of de app wilt herstellen. <b>Dit bericht wordt niet opnieuw weergegeven.</b></string>\n    <string name=\"keystore_pass_cannot_be_empty\">KeyStore-wachtwoord mag niet leeg zijn.</string>\n    <string name=\"adb_pair\">Koppel</string>\n    <string name=\"identifier\">Identifier</string>\n    <string name=\"set_package_name_first\">Geef eerst de pakketnaam op!</string>\n    <string name=\"paste\">Plakken</string>\n    <string name=\"user_root\">Gebruik root</string>\n    <string name=\"trim_caches_in_all_apps\">Trim cache van alle apps</string>\n    <string name=\"trim_caches_in_all_apps_description\">Verwijdert cachebestanden van alle applicaties, inclusief het Android-systeem</string>\n    <string name=\"background\">Achtergrond</string>\n    <string name=\"staging_apk_files\">Voorbereiden…</string>\n    <string name=\"installer_app_installed\">App geïnstalleerd</string>\n    <string name=\"next\">Volgende</string>\n    <string name=\"pref_block_trackers_msg\">Trackingcomponenten blokkeren na app-installatie middels App Manager.</string>\n    <string name=\"pref_always_on_background\">Installeer op de achtergrond</string>\n    <string name=\"paired_successfully\">Gekoppeld.</string>\n    <string name=\"type_uri_array_list\">Lijst van URI\\'s</string>\n    <string name=\"pref_thread_count\">Parallelle uitvoering</string>\n    <string name=\"pid\">Proces-ID</string>\n    <string name=\"running_services_logcat_hint\">Klik op een item om de logviewer te openen met de bijbehorende proces-ID als standaardfilter.</string>\n    <string name=\"import_from_sb\">Importeren uit Swift Backup 3.0 - 3.2</string>\n    <string name=\"pref_import_backups_hint\">Selecteer een map die de back-upbestanden (Swift Backup/Titanium Backup) of -mappen (OAndBackup) bevat</string>\n    <string name=\"java\">Java</string>\n    <string name=\"smali\">Smali</string>\n    <string name=\"accessibility_service_description\">Algemene toegankelijkheidsservice om bepaalde bewerkingen uit te voeren, zoals het wissen van de cache in de modus zonder root.</string>\n    <string name=\"exit_confirmation\">Afsluitbevestiging</string>\n    <string name=\"extract\">Uitpakken</string>\n    <string name=\"replace\">Vervangen</string>\n    <string name=\"rename\">Hernoemen</string>\n    <string name=\"intent_firewall_and_disable\">IFW + uitschakelen</string>\n    <string name=\"intent_firewall\">IFW</string>\n    <string name=\"pref_default_blocking_method\">Standaard blokkeermethode</string>\n    <string name=\"pref_intent_firewall_and_disable_description\">Blokkeer componenten met Intent Firewall en schakel ze uit. Aanbevolen methode voor rootgebruikers.</string>\n    <string name=\"pref_intent_firewall_description\">Blokkeer componenten alleen met behulp van Intent Firewall. Niet aanbevolen omdat sommige systeemapps firewalls kunnen omzeilen.</string>\n    <string name=\"pref_disable_description\">Schakel alleen componenten uit. Niet aanbevolen voor rootgebruikers omdat de apps dit kunnen omzeilen. In ADB-modi kunnen de test-only apps met deze methode worden uitgeschakeld.</string>\n    <string name=\"search_type_contains\">Bevat</string>\n    <string name=\"search_type_prefix\">Voorvoegsel</string>\n    <string name=\"search_type_suffix\">Achtervoegsel</string>\n    <string name=\"search_type_regular_expressions\">Regex</string>\n    <string name=\"toggle_internet\">Gebruik het internet</string>\n    <string name=\"pref_toggle_internet_msg\">Activeer de internetfuncties in App Manager</string>\n    <string name=\"vt_checking\">VirusTotal: Controleren…</string>\n    <string name=\"vt_failed\">VirusTotal: Mislukt</string>\n    <string name=\"vt_success\">VirusTotal: %1$d/%2$d</string>\n    <string name=\"vt_scan_date\">Scandatum: %1$s</string>\n    <string name=\"vt_permalink\">Vaste link naar VirusTotal</string>\n    <string name=\"vt_slowness_warning\">Afhankelijk van de internetsnelheid en de serverbelasting kan dit enige tijd duren.</string>\n    <string name=\"vt_disclaimer\">VirusTotal en de bijbehorende logo\\'s zijn een handelsmerk van Chronicle LLC. Noch App Manager (de API-client) noch de auteurs zijn verantwoordelijk voor de gegevens die u naar VirusTotal verzendt.</string>\n    <string name=\"pref_vt_apikey_description\">Met een API-sleutel kan App Manager APK-bestanden uploaden naar VirusTotal en rapporten ophalen. Meld u aan op https://virustotal.com om een gratis API-sleutel te ontvangen.</string>\n    <string name=\"scan_in_vt\">Scan in VirusTotal</string>\n    <string name=\"process_id\">Proces-ID</string>\n    <string name=\"parent_process_id\">Bovenliggende proces-ID</string>\n    <string name=\"virtual_memory\">Virtueel geheugen</string>\n    <string name=\"cpu_percent\">%% CPU</string>\n    <string name=\"cpu_time\">CPU-tijd</string>\n    <string name=\"priority\">Prioriteit</string>\n    <string name=\"threads\">Thread Count</string>\n    <string name=\"state\">Processtatus</string>\n    <string name=\"commandline_args\">Opdrachtregelargumenten</string>\n    <string name=\"swap\">Wisselen</string>\n    <string name=\"memory_chart_info\">● %1$s Toepassingen ● %2$s Gecached ● %3$s Buffers ● %4$s Beschikbaar</string>\n    <string name=\"swap_chart_info\">● %1$s Gebruikt ● %2$s Beschikbaar</string>\n    <string name=\"failed_to_change_app_op_mode\">Kan de app op modus niet wijzigen.</string>\n    <string name=\"failed_to_use_the_current_mode_of_operation\">Kan de huidige bedieningsmodus niet gebruiken. Voor deze sessie wordt teruggevallen op de no-rootmodus.</string>\n    <string name=\"warning_working_on_root_mode\">Waarschuwing: Werkt in root-modus in plaats van in ADB-modus.</string>\n    <string name=\"warning_working_on_system_mode\">Waarschuwing: Werkt op het systeem in plaats van in de ADB-modus.</string>\n    <string name=\"magisk_denylist\">Magisk DenyList</string>\n    <string name=\"failed_to_enable_magisk_deny_list\">Kan Magisk DenyList niet inschakelen</string>\n    <string name=\"mode_of_op_with_inferred_mode_of_op\">%1$s (Afgeleide modus: %2$s)</string>\n    <string name=\"zygote_preload_name\">Zygote voorgeladen naam</string>\n    <string name=\"hidden_api_enforcement_policy\">Verborgen API-handhavingsbeleid</string>\n    <string name=\"hidden_api_enf_default_policy\">Standaard (gebaseerd op applicatietype)</string>\n    <string name=\"hidden_api_enf_policy_none\">Geen (volledige toegang tot de verborgen API)</string>\n    <string name=\"hidden_api_enf_policy_warn\">Waarschuwen (volledige toegang tot de verborgen API, maar geeft waarschuwingen)</string>\n    <string name=\"hidden_api_enf_policy_black\">Handhaven (alleen zwarte lijsten)</string>\n    <string name=\"endianness_big_endian\">Big endian</string>\n    <string name=\"so_type_executable\">Uitvoerbaar</string>\n    <string name=\"file_modified_are_you_sure\">Het bestand is gewijzigd. Al uw wijzigingen negeren en afsluiten?</string>\n    <string name=\"pref_saved_apk_name_format\">Opgeslagen APK-naamindeling</string>\n    <string name=\"auth_manager_description\">Om een Intent vanuit een externe app te starten, is het nodig om een extra veld met de naam <tt>auth</tt> op te geven. Dit veld moet de volgende sleutel bevatten:</string>\n    <string name=\"auth_manager_title\">Autorisatiemanager</string>\n    <string name=\"regenerate_auth_key\">Autorisatiesleutel opnieuw genereren</string>\n    <string name=\"shortcut_icon\">Snelkoppelingspictogram</string>\n    <string name=\"sort_by_installation_date\">Installatiedatum</string>\n    <string name=\"backup_volume_unavailable_warning\">Het geselecteerde back-upvolume is momenteel niet beschikbaar. Als het zich op een externe opslag bevindt, plaats het dan of wijzig het back-upvolume.</string>\n    <string name=\"change_backup_volume\">Volume wijzigen</string>\n    <string name=\"external\">Extern</string>\n    <string name=\"internal\">Intern</string>\n    <string name=\"input_ssaid_instruction\">SSAID is een hexadecimaal getal van %1$d bytes: een reeks met %2$d tekens die de getallen 0 tot en met 9 en letters a tot en met f bevat.</string>\n    <string name=\"screen_time\">Schermtijd</string>\n    <string name=\"type_string_set\">Set van strings</string>\n    <string name=\"pref_vt_prompt_before_uploading\">Toon prompt voordat een bestand wordt geüpload.</string>\n    <string name=\"vt_confirm_upload_and_scan\">Ja, upload en scan</string>\n    <string name=\"log_stop_recording\">Opname stoppen</string>\n    <string name=\"apk_checksums\">APK-checksums</string>\n    <string name=\"item_select\">Selecteren</string>\n    <string name=\"app_explorer\">App-verkenner</string>\n    <string name=\"netpolicy_cannot_be_modified_for_core_apps\">Het netwerkbeleid voor Android-kern-apps kan niet worden gewijzigd.</string>\n    <string name=\"open_developer_options_page\">Open de pagina met ontwikkelaarsopties in de Android-instellingen</string>\n    <string name=\"pref_pure_black_theme\">Puur zwart thema</string>\n    <string name=\"pref_pure_black_theme_msg\">Gebruik een volledig zwarte achtergrond als de nachtmodus is ingeschakeld.</string>\n    <string name=\"usage_last_used\">Laatst gebruikt</string>\n    <string name=\"usage_mobile_data\">Mobiele data</string>\n    <string name=\"usage_wifi_data\">Wi-Fi data</string>\n    <string name=\"frozen\">Bevroren</string>\n    <string name=\"freeze\">Bevries</string>\n    <string name=\"unfreeze\">Ontdooi</string>\n    <string name=\"backup_no_backups_present\">Geen back-ups.</string>\n    <string name=\"restore_dots\">Herstellen…</string>\n    <string name=\"backup_apps_cannot_be_restored\">De volgende apps kunnen niet worden hersteld omdat ze geen basisback-up hebben:</string>\n    <string name=\"backup_apps_cannot_be_backed_up\">De volgende apps zijn niet geïnstalleerd en kunnen niet worden geback-upt:</string>\n    <string name=\"restart_device\">Apparaat opnieuw opstarten</string>\n    <string name=\"troubleshooting\">Probleemoplossing</string>\n    <string name=\"pref_reload_apps\">Apps opnieuw laden</string>\n    <string name=\"pref_reload_apps_msg\">Laad de lijst met apps die zijn opgeslagen in de App Manager-database opnieuw in geval van onverwacht gedrag.</string>\n    <string name=\"changelog_type_new\">Nieuw</string>\n    <string name=\"changelog_type_fix\">Opgelost</string>\n    <string name=\"changelog_type_improve\">Verbeterd</string>\n    <string name=\"unsupported_split_apk\">Niet ondersteund</string>\n    <string name=\"view_changelog\">Ontdek wat er nieuw is in deze versie</string>\n    <string name=\"sort_by_total_size\">Totale grootte</string>\n    <string name=\"am_command\"><tt>am</tt> command</string>\n    <string name=\"pref_sign_apk_error_signing_key_not_added\">Voor het ondertekenen van een APK-bestand is een geldige ondertekeningssleutel vereist.</string>\n    <string name=\"pref_sign_apk_no_signing_key\">Geen ondertekeningssleutel</string>\n    <string name=\"freeze_unfreeze\">Bevriezen/ontdooien</string>\n    <string name=\"pref_default_freezing_method_description\">Methode die standaard moet worden gebruikt op plaatsen waar er geen optie is om een bevriezingsmethode te selecteren.</string>\n    <plurals name=\"alert_failed_to_freeze\">\n        <item quantity=\"one\">Kan %1$d app niet bevriezen</item>\n        <item quantity=\"other\">Kan %1$d apps niet bevriezen</item>\n    </plurals>\n    <string name=\"suspend_app_description\">Dit is de zwakste manier om een app te bevriezen. Een opgeschorte app kan nog steeds in de launcher verschijnen, maar is grijs en kan niet worden gestart.</string>\n    <string name=\"disable_app_description\">Aanbevolen bevriezingsmethode. Het schakelt de app uit samen met al zijn componenten, maar alle snelkoppelingen gaan verloren.</string>\n    <string name=\"sort_by_frozen_app\">Bevroren eerst</string>\n    <string name=\"filter_frozen_apps\">Bevroren apps</string>\n    <string name=\"pref_appearance_description\">Thema, oriëntatie, functies, etc.</string>\n    <string name=\"pref_privacy\">Privacy</string>\n    <string name=\"pref_privacy_description\">Schermvergrendeling, autorisatie, etc.</string>\n    <string name=\"user_manual\">Gebruikershandleiding</string>\n    <string name=\"get_help\">Hulp krijgen</string>\n    <string name=\"pref_advanced_pref\">Gebruikers, APK-naamindeling, parallelle uitvoering, etc.</string>\n    <string name=\"pref_version_changelog\">Versie/Wijzigingslogboek</string>\n    <string name=\"file_creation_date\">Gecreëerd</string>\n    <string name=\"file_modification_date\">Gewijzigd</string>\n    <string name=\"file_accessed_date\">Geopend</string>\n    <string name=\"file_open_with\">Open met</string>\n    <string name=\"file_change_open_with\">Verander open met</string>\n    <string name=\"file_shortcut_target_file\">Doelbestand</string>\n    <string name=\"file_properties\">Eigenschappen</string>\n    <string name=\"file_cut\">Knippen</string>\n    <string name=\"fm_open_with_for_this_file_only\">Alleen voor dit bestand</string>\n    <string name=\"file_open_with_custom_activity\">Aangepast</string>\n    <string name=\"failed_to_freeze\">Kan <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g> niet bevriezen.</string>\n    <string name=\"profile_freeze_msg\">Bevriest of ontdooit apps op basis van de status</string>\n    <string name=\"failed_to_unfreeze\">Kan <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g> niet ontdooien.</string>\n    <string name=\"pref_default_freezing_method\">Standaard bevriezingsmethode</string>\n    <string name=\"file_open_with_os_default_dialog\">Openen met standaarddialoogvenster van het besturingssysteem</string>\n    <string name=\"open_as_text\">Tekst</string>\n    <string name=\"open_as_image\">Afbeelding</string>\n    <string name=\"open_as_video\">Video</string>\n    <string name=\"open_as_archive\">Archief</string>\n    <string name=\"open_as_folder\">Map</string>\n    <string name=\"open_as_other\">Anders</string>\n    <string name=\"delete_filename\">Verwijder %s</string>\n    <string name=\"confirm_file_deletion\">Ja, verwijder</string>\n    <string name=\"on_unfreeze_open_application\">Open de app na het ontdooien</string>\n    <string name=\"on_open_application_no_recents\">Laat de gestarte app niet zien in Recente apps</string>\n    <string name=\"freeze_on_phone_locked\">Apps automatisch bevriezen wanneer de telefoon vergrendeld is</string>\n    <string name=\"tap_to_freeze_app\">Tik om te bevriezen</string>\n    <string name=\"waiting_for_the_phone_to_be_locked\">Wachten tot de telefoon vergrendeld is…</string>\n    <string name=\"action_stop_service\">Stop</string>\n    <string name=\"app_manager_build_expired\">Update vereist</string>\n    <string name=\"app_manager_build_expiring_soon_warning\">Deze versie van App Manager verloopt binnenkort. Update het alstublieft naar de nieuwste versie.</string>\n    <string name=\"renamed_successfully\">Hernoemd</string>\n    <string name=\"selinux_context\">SELinux-context</string>\n    <string name=\"unix_file_permissions\">Modus</string>\n    <string name=\"file_group_id\">Groep (GID)</string>\n    <string name=\"file_owner_id\">Eigenaar (GID)</string>\n    <string name=\"calculating_file_size\">Berekenen…</string>\n    <string name=\"sort_by_filename\">Naam</string>\n    <string name=\"sort_by_last_modified\">Laatst gewijzigd</string>\n    <string name=\"sort_by_file_size\">Bestandsgrootte</string>\n    <string name=\"sort_by_file_type\">Bestandstype</string>\n    <string name=\"option_display_dot_files\">Dot-bestanden</string>\n    <string name=\"option_display_folders_on_top\">Mappen bovenaan</string>\n    <string name=\"export_app_list\">Exporteer app-lijst</string>\n    <string name=\"export_option_xml\">XML</string>\n    <string name=\"export_option_markdown\">Markdown</string>\n    <string name=\"adb_incomplete_usb_debugging_title\">Onvolledige USB-foutopsporing</string>\n    <string name=\"sort_by_data_usage\">Datagebruik</string>\n    <string name=\"filter_apps_with_keystore\">Met KeyStore</string>\n    <string name=\"filter_apps_with_saf\">Met SAF</string>\n    <string name=\"filter_apps_with_ssaid\">Met SSAID</string>\n    <string name=\"grant_accessibility_permission_for_tracking_window_contents\">Geef App Manager toestemming om de toegankelijkheidsfunctie te gebruiken om de inhoud van het hoofdvenster bij te houden.</string>\n    <string name=\"class_hierarchy\">Hiërarchie</string>\n    <string name=\"title_ui_tracker\">UI-tracker</string>\n    <string name=\"title_terminal_emulator\">Terminal</string>\n    <string name=\"title_labs_activity\">Labs</string>\n    <string name=\"select_a_dex2oat_compiler_filter\"><tt>dex2oat</tt> compilerfilter</string>\n    <string name=\"optimize_option_compile_layouts\">Compileer lay-outbronnen</string>\n    <string name=\"optimize_option_clear_profile_data\">Wis vorige profielgegevens</string>\n    <string name=\"optimize_option_check_profiles\">Houd rekening met profielgegevens tijdens DEX-optimalisatie</string>\n    <string name=\"optimize_option_force_compilation\">Compilatie forceren, zelfs als dit niet nodig is</string>\n    <string name=\"optimize_option_force_dexopt\">Direct DEX-optimalisatie uitvoeren</string>\n    <string name=\"title_perform_runtime_optimization_to_apps\">Runtime-optimalisatie uitvoeren</string>\n    <string name=\"action_run\">Uitvoeren</string>\n    <string name=\"summary_perform_runtime_optimization_to_apps\">Optimaliseer DEX en (in Android 10 en later) lay-outs om de prestaties van de applicaties te verbeteren.</string>\n    <string name=\"read_only_file_warning\">De wijzigingen kunnen niet naar het bestand worden geschreven, mogelijk omdat het zich op een volume bevindt waarvoor App Manager geen schrijfrechten heeft. Wilt u het op een andere locatie opslaan?</string>\n    <string name=\"line_separator\">Lijnscheidingsteken</string>\n    <string name=\"debloat_removal_replace\">Vervangen</string>\n    <string name=\"debloat_removal_caution\">Let op</string>\n    <string name=\"static_shared_library\">Statische gedeelde bibliotheek</string>\n    <string name=\"empty_folder\">Leeg</string>\n    <plurals name=\"folder_count\">\n        <item quantity=\"one\">%d map</item>\n        <item quantity=\"other\">%d mappen</item>\n    </plurals>\n    <plurals name=\"file_count\">\n        <item quantity=\"one\">%d bestand</item>\n        <item quantity=\"other\">%d bestanden</item>\n    </plurals>\n    <string name=\"go_to_path\">Ga naar…</string>\n    <string name=\"copy_this_path\">Pad kopiëren</string>\n    <string name=\"title_audio_player\">Audiospeler</string>\n    <string name=\"filter_force_stopped_apps\">Gestopte apps</string>\n    <string name=\"restoring_app\">%1$s herstellen…</string>\n    <string name=\"pref_installer_force_dexopt_description\">Voer DEX-optimalisatie direct uit nadat u de app hebt geïnstalleerd, zonder te wachten totdat het systeem dit doet wanneer het inactief is.</string>\n    <string name=\"folder\">Map</string>\n    <string name=\"symbolic_link\">Symbolische link</string>\n    <string name=\"create_new_symbolic_link\">Nieuwe symbolische link</string>\n    <string name=\"installing_package\">%1$s installeren…</string>\n    <string name=\"backing_up_app\">Back-up maken van %1$s…</string>\n    <string name=\"symbolic_link_not_supported\">Deze map ondersteunt het maken van een symbolische link niet.</string>\n    <string name=\"create_new_folder\">Nieuwe map</string>\n    <string name=\"create_new_file\">Nieuw bestand</string>\n    <string name=\"enter_target_path\">Doelpad</string>\n    <string name=\"invalid_target_path\">Ongeldig pad</string>\n    <string name=\"title_confirm_deletion\">Verwijdering bevestigen</string>\n    <string name=\"conflict_detected_while_copying\">Conflict gedetecteerd</string>\n    <string name=\"conflict_detected_while_copying_message\">Er bestaat al een item met de naam “%1$s” op deze locatie. Wilt u deze vervangen?</string>\n    <string name=\"copy_keep_both_file\">Bewaar beide</string>\n    <string name=\"moved_successfully\">Verplaatst</string>\n    <string name=\"failed_to_copy_specified_file\">Kon “%1$s” niet kopiëren.</string>\n    <string name=\"failed_to_delete_specified_file_after_copying\">Kon “%1$s” niet verwijderen na het kopiëren, mogelijk vanwege ontoereikende rechten.</string>\n    <string name=\"apply_recursively\">Toepassen op ingesloten bestanden</string>\n    <string name=\"change_owner_uid\">Wijzig eigenaar (UID)</string>\n    <string name=\"change_group_gid\">Wijzig groep (GID)</string>\n    <string name=\"change_mode\">Wijzig modus</string>\n    <string name=\"pref_send_notifications_to_connected_devices\">Stuur meldingen naar de aangesloten apparaten</string>\n    <string name=\"pref_send_notification_to_connected_devices_msg\">Stel in of meldingen naar verbonden apparaten, zoals wearables, moeten worden verzonden.</string>\n    <string name=\"installer_options\">Installatieopties</string>\n    <string name=\"debloat_removal_safe_short_description\">Veilig te verwijderen</string>\n    <string name=\"debloat_removal_caution_short_description\">Wees voorzichtig</string>\n    <string name=\"debloat_removal_replace_short_description\">Vervangen met alternatief</string>\n    <string name=\"title_alternatives_to_bloatware\">Alternatieven</string>\n    <string name=\"pref_files_msg\">Configureer bestandsbeheerder.</string>\n    <string name=\"pref_files_display_in_launcher\">\\\"Bestanden\\\" weergeven in de app-lade</string>\n    <string name=\"pref_files_remember_last_path\">Onthoud het laatst geopende pad en de positie daarvan</string>\n    <string name=\"pref_set_home\">Thuis instellen</string>\n    <string name=\"xposed_module_info\">Xposed Module-informatie</string>\n    <string name=\"title_description\">Beschrijving</string>\n    <string name=\"copied_successfully\">Gekopieerd.</string>\n    <string name=\"tap_to_open_notification_settings\">Tik om te verbergen</string>\n    <string name=\"app_manager_is_unlocked\">App Manager is ontgrendeld</string>\n    <string name=\"action_lock_app\">Vergrendel</string>\n    <string name=\"pref_enable_persistent_session\">Voer App Manager op de achtergrond uit</string>\n    <string name=\"path_does_not_exist\">“%1$s” bestaat niet</string>\n    <string name=\"path_not_a_folder\">“%1$s” is geen map</string>\n    <string name=\"scan_report_from_pithus\">Pithus-rapport</string>\n    <string name=\"action_checking\">Controleren…</string>\n    <string name=\"report_not_available\">Niet beschikbaar</string>\n    <string name=\"profile_modified_are_you_sure\">Het profiel is gewijzigd. Al uw wijzigingen negeren en afsluiten?</string>\n    <string name=\"apply_profile\">Profiel “%1$s” toepassen</string>\n    <string name=\"choose_a_profile_state\">Selecteer een profielstatus</string>\n    <string name=\"profile_id\">Profiel-ID</string>\n    <string name=\"copy_profile_id\">Kopieer profiel-ID</string>\n    <string name=\"launch_activity_dialog_title\">Startactiviteit: actie vereist</string>\n    <string name=\"launch_activity_dialog_message\">App Manager probeert de activiteit te starten via de <b>Zoekassistent</b> (meestal Google Assistent), maar dit lukt niet vanwege onvoldoende rechten. Om de activiteit te openen, activeert u de <b>Zoekassistent</b> handmatig (wat meestal wordt gedaan door lang op de Home-knop te klikken). Klik op de knop <b>Sluiten</b> nadat u klaar bent met het starten van de activiteit om terug te keren naar de oorspronkelijke assistent.</string>\n    <string name=\"size_in_bytes\">Grootte (bytes)</string>\n    <string name=\"invalid_regex\">Ongeldige reguliere expressie!</string>\n    <string name=\"value_cannot_be_empty\">Waarde kan niet leeg zijn!</string>\n    <string name=\"date\">Datum</string>\n    <string name=\"pref_use_vt\">Gebruik VirusTotal</string>\n    <string name=\"virus_total\">VirusTotal</string>\n    <string name=\"pref_use_vt_no_internet\">VirusTotal vereist internettoegang. Dit is niet ingeschakeld. Schakel eerst <a href=\"app-manager://settings/privacy_prefs/toggle_internet\">\\\"Internet gebruiken\\\"</a> in.</string>\n    <string name=\"pref_use_log_viewer\">Gebruik Logviewer</string>\n    <string name=\"pref_installer\">Gebruik het installatieprogramma</string>\n    <string name=\"pref_cat_general\">Algemeen</string>\n    <string name=\"status_remote_server_active\">Externe server is actief</string>\n    <string name=\"status_remote_server_inactive\">Externe server is inactief</string>\n    <string name=\"status_remote_services_active\">Externe services zijn actief</string>\n    <string name=\"status_remote_services_inactive\">Externe services zijn inactief</string>\n    <string name=\"status_connecting\">Verbinden…</string>\n    <string name=\"status_connecting_via_mode\">Verbinden via %s</string>\n    <string name=\"status_connected_via_mode\">Verbonden via %s</string>\n    <string name=\"status_not_connected_via_mode\">Kan geen verbinding maken via %s</string>\n    <string name=\"adb_pairing_instruction\">Ga naar de ontwikkelaarsopties om draadloze foutopsporing in te schakelen en een koppelingscode te genereren. Klik op <b>Handmatig</b> als u de ontwikkelaarsopties al hebt geopend.</string>\n    <string name=\"adb_pairing_searching_for_port\">Zoeken…</string>\n    <string name=\"adb_pairing_stop_searching\">Stop</string>\n    <string name=\"adb_pairing_input_pairing_code\">Koppelingscode</string>\n    <string name=\"adb_pairing_pairing_code\">Koppelingscode</string>\n    <string name=\"adb_pairing_found_pairing_service_with_port\">Service gevonden met poort %d</string>\n    <string name=\"adb_pairing_pairing_in_progress\">Koppelen…</string>\n    <string name=\"adb_pairing_retry_pairing\">Opnieuw proberen</string>\n    <string name=\"mode_of_op_alternative_custom_command\">Als u bij de bovenstaande opdracht de foutmelding \\'machtiging geweigerd\\' krijgt, voer dan de volgende opdracht uit:</string>\n    <string name=\"sensors\">Sensoren</string>\n    <string name=\"tag_sensors_disabled\">Sensoren uitgeschakeld</string>\n    <string name=\"pref_use_system_font\">Gebruik systeemlettertype</string>\n    <string name=\"pref_use_system_font_msg\">Gebruik het standaardsysteemlettertype in plaats van het Material lettertype. <font fgcolor=\"#ff0000\">Dit is een experimentele functie.</font></string>\n    <string name=\"actual_installer\">Werkelijke installateur</string>\n    <string name=\"apk_source\">APK-bron</string>\n    <string name=\"backup_cache\">Cache</string>\n    <string name=\"activity_name\">Activiteitsnaam</string>\n    <string name=\"available_memory\">Beschikbaar: %s</string>\n    <string name=\"action_manual\">Aangepast</string>\n    <string name=\"vulkan_version\">Vulkan-versie</string>\n    <string name=\"battery_technology\">Technologie</string>\n    <string name=\"battery_health\">Gezondheid</string>\n    <string name=\"android_verified_bootloader_version\">AVB-versie</string>\n    <string name=\"op_history\">Geschiedenis</string>\n    <string name=\"no_history\">Geen geschiedenis</string>\n    <string name=\"favorites\">Favorieten</string>\n    <string name=\"add_to_favorites\">Toevoegen aan favorieten</string>\n    <string name=\"item_remove\">Verwijderen</string>\n    <string name=\"item_edit\">Bewerken</string>\n    <string name=\"remove_filename\">Verwijder %s</string>\n    <string name=\"advanced_suspend_app\">Geavanceerde opschorting</string>\n    <string name=\"freeze_prefer_per_app_option\">Voorkeursoptie per app</string>\n    <string name=\"remember_option_for_this_app\">Onthoud voor deze app</string>\n    <string name=\"no_overlay_permission\">Geen toestemming om overlays weer te geven</string>\n    <string name=\"overlay_category\">Categorie</string>\n    <string name=\"verified_boot\">Geverifieerde boot</string>\n    <string name=\"overlay_target\">Doel</string>\n    <string name=\"overlay_sdk_version_too_low\">Overlays worden niet ondersteund.</string>\n    <string name=\"no_overlays\">Geen overlays</string>\n    <string name=\"sort_by_overlay_names\">Overlay-naam</string>\n    <string name=\"sort_by_priority\">Prioriteit</string>\n    <string name=\"overlays\">Overlays</string>\n    <string name=\"title_overlay\">Overlay</string>\n    <string name=\"title_shortcut_for_frozen_app\">Bevroren app</string>\n    <string name=\"message_shortcut_for_frozen_app\">De app die bij de snelkoppeling hoort, lijkt vastgelopen te zijn. Tijdelijk ontdooien en de snelkoppeling openen?</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-pl/disclaimer.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- SPDX-License-Identifier: GPL-3.0-or-later --><resources>\n    <string name=\"disclaimer_exit\">Wyjdź</string>\n    <string name=\"disclaimer_agree\">Zgadzam się</string>\n    <string name=\"disclaimer_agree_forever\">Nie pokazuj więcej tego okna</string>\n    <string name=\"disclaimer_footer\">© 2020-2024 Muntashir Al-Islam</string>\n    <string name=\"disclaimer_header\">Zastrzeżenie</string>\n    <string name=\"disclaimer_body\">Menedżer aplikacji oferuje funkcje root, która może uszkodzić urządzenie, jeśli jest używana nieprawidłowo. Menedżer aplikacji nie ponosi odpowiedzialności za jakiekolwiek szkody wyrządzone za pomocą tej aplikacji. Jeśli nie jesteś w pełni świadomy tego, jak działa root, należy unikać korzystania z opcji root, dopóki nie jesteś w pełni świadom ryzyka.\n\\n\n\\nKażdy link, który podaję innym aplikacjom i stronom internetowym, jest dla użytkowników. Nie ponosimy odpowiedzialności za treści, które możesz znaleźć, przechodząc na linki zewnętrzne.\n\\n\n\\nKorzystając z Menedżera aplikacji, przyjmujesz pełną odpowiedzialność za własne użycie i nie akceptujesz żadnych szkód, roszczeń ani wartości pieniężnej z powodu niewłaściwego użycia.\n\\n\n\\nKorzystając z tej aplikacji, przyjmujesz na siebie wszelką odpowiedzialność za korzystanie z niej i zgadzasz się, że nie jesteśmy odpowiedzialni za jakiekolwiek działania podejmowane przez ciebie ,które mają negatywny wpływ na Twoje urządzenie.</string>\n</resources>"
  },
  {
    "path": "app/src/main/res/values-pl/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- SPDX-License-Identifier: GPL-3.0-or-later --><resources xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:tools=\"http://schemas.android.com/tools\">\n    <string name=\"_lang_tag\" translatable=\"false\">pl</string>\n    <string name=\"user_id\">ID użytkownika</string>\n    <string name=\"date_updated\">Data aktualizacji</string>\n    <string name=\"date_installed\">Data instalacji</string>\n    <string name=\"more_info\">Więcej informacji</string>\n    <string name=\"sdk_flags\">Flagi</string>\n    <string name=\"sdk_max\">Cel</string>\n    <string name=\"sdk_min\">Minimum</string>\n    <string name=\"data_dir\">Katalog danych</string>\n    <string name=\"source_dir\">Katalog źródłowy</string>\n    <string name=\"paths_and_directories\">Ścieżki i katalogi</string>\n    <string name=\"user_app\">Aplikacja użytkownika</string>\n    <string name=\"system_app\">Aplikacja systemowa</string>\n    <string name=\"app_info\">Informacje o aplikacji</string>\n    <string name=\"version_name_with_code\">Wersja <xliff:g id=\"version_name\" example=\"2.5.17\">%1$s</xliff:g> (<xliff:g id=\"version_code\" example=\"365\">%2$d</xliff:g>)</string>\n    <string name=\"sort\">Sortuj</string>\n    <string name=\"system\">Systemowe</string>\n    <string name=\"sort_by_app_label\">Etykieta aplikacji</string>\n    <string name=\"loading\">Ładowanie…</string>\n    <string name=\"error\">Błąd</string>\n    <string name=\"manifest\">Manifest</string>\n    <string name=\"no_configurations\">Brak konfiguracji</string>\n    <string name=\"configurations\">Konfiguracje</string>\n    <string name=\"app_signing_no_signatures\">Brak sygnatur</string>\n    <string name=\"signatures\">Sygnatury</string>\n    <string name=\"sort_by_sha\">Sygnatura</string>\n    <string name=\"shared_user_id\">Współdzielony identyfikator użytkownika</string>\n    <string name=\"sort_by_shared_user_id\">Współdzielony identyfikator użytkownika</string>\n    <string name=\"no_feature\">Brak funkcji</string>\n    <string name=\"uses_feature\">Korzysta z funkcji</string>\n    <string name=\"group\">Grupa</string>\n    <string name=\"shared_libs\">Współdzielone biblioteki</string>\n    <string name=\"declared_permission\">Uprawnienia</string>\n    <string name=\"write\">Zapis</string>\n    <string name=\"read\">Odczyt</string>\n    <string name=\"path_permissions\">Uprawnienia ścieżki</string>\n    <string name=\"grant_uri_permission\">Przyznaj uprawnienia URI</string>\n    <string name=\"flags\">Flagi</string>\n    <string name=\"task_affinity\">Koligacja zadania</string>\n    <string name=\"launch_mode\">Tryb uruchamiania</string>\n    <string name=\"require_no_permission\">Nie jest wymagane żadne uprawnienie</string>\n    <string name=\"installer_error_lidl_rom\">Twój ROM jest niekompatybilny z instalatorem niewymagającym roota.</string>\n    <string name=\"installer_error_generic\">Instalacja nie powiodła się</string>\n    <string name=\"installer_error_storage\">Nie ma wystarczającej ilości miejsca do zainstalowania aplikacji</string>\n    <string name=\"installer_error_bad_apks\">Wybrano nieprawidłowe pliki APK</string>\n    <string name=\"installer_error_incompatible\">Ta aplikacja jest niekompatybilna z tym urządzeniem</string>\n    <string name=\"installer_error_conflict\">Nie można zainstalować aplikacji, ta nazwa pakietu jest już w użyciu</string>\n    <string name=\"installer_error_blocked\">Instalacja zablokowana przez <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g></string>\n    <string name=\"installer_error_blocked_device\">urządzenie</string>\n    <string name=\"installer_error_aborted\">Instalacja nie powiodła się, ponieważ została anulowana lub sesja została nieoczekiwanie zamknięta</string>\n    <string name=\"toggle_default_app_ops\">Przełącz domyślne app ops</string>\n    <string name=\"are_you_sure\">Czy jesteś pewien\\?</string>\n    <string name=\"pref_remove_all_rules_msg\">Uprawnienia zostaną przyznane, funkcje aplikacji i komponenty powrócą do wartości domyślnych.</string>\n    <string name=\"pref_remove_all_rules\">Usuń wszystkie reguły</string>\n    <string name=\"website\">Strona internetowa</string>\n    <string name=\"run_in_termux\">Uruchom w Termux</string>\n    <string name=\"open_in_termux\">Otwórz w Termux</string>\n    <string name=\"block_unblock_trackers\">Zablokuj/odblokuj elementy śledzące</string>\n    <string name=\"unblock\">Odblokuj</string>\n    <string name=\"block\">Blokuj</string>\n    <string name=\"clear\">Wyczyść</string>\n    <string name=\"clear_data_message\">Czy na pewno chcesz wyczyścić dane tej aplikacji\\?</string>\n    <string name=\"skip_signature_checks\">Pomiń sprawdzanie podpisów</string>\n    <string name=\"yes\">Tak</string>\n    <string name=\"clear_app_cache_description\">Czyści pamięć podręczną wszystkich aplikacji</string>\n    <plurals name=\"alert_failed_to_clear_data\">\n        <item quantity=\"one\">Nie można wyczyścić danych %1$d aplikacji</item>\n        <item quantity=\"few\">Nie można wyczyścić danych %1$d aplikacji</item>\n        <item quantity=\"many\">Nie można wyczyścić danych %1$d aplikacji</item>\n        <item quantity=\"other\">Nie można wyczyścić danych %1$d aplikacji</item>\n    </plurals>\n    <string name=\"export_blocking_rules\">Eksportuj reguły blokowania</string>\n    <string name=\"disable_background\">Wyłącz działanie w tle</string>\n    <string name=\"backup_restore\">Tworzenie/przywracanie kopii zapasowych</string>\n    <string name=\"clear_data\">Wyczyść dane</string>\n    <string name=\"user_and_uid\">Użytkownik: <xliff:g id=\"user_name\" example=\"root\">%1$s</xliff:g> (<xliff:g id=\"user_id\" example=\"0\">%2$d</xliff:g>)</string>\n    <string name=\"memory_virtual_memory\">Pamięć: %1$s, Pamięć wirtualna: %2$s</string>\n    <string name=\"pid_and_ppid\">Identyfikator procesu: %1$d, identyfikator procesu nadrzędnego: %2$d</string>\n    <string name=\"disable_background_run\">Wyłącz działanie w tle</string>\n    <string name=\"running_apps\">Uruchomione aplikacje</string>\n    <string name=\"permissions\">Użycie uprawnień</string>\n    <string name=\"app_settings\">Ustawienia</string>\n    <string name=\"pref_global_blocking_enabled\">Globalne blokowanie komponentów</string>\n    <string name=\"str_logo\">Logo</string>\n    <string name=\"orientation_locked\">Zablokowany</string>\n    <string name=\"orientation_unspecified\">Nieokreślony</string>\n    <string name=\"launch_mode_single_task\">Pojedyncze zadanie</string>\n    <string name=\"abi_split_for_feature\"><xliff:g id=\"split_name\" example=\"arm64_v8a\">%1$s</xliff:g> kod dla <xliff:g id=\"feature_name\" example=\"Visualizer\">%2$s</xliff:g></string>\n    <string name=\"unknown_split_for_base_apk\"><xliff:g id=\"split_name\" example=\"some_split\">%1$s</xliff:g> dla podstawowego pliku APK</string>\n    <string name=\"unknown_split_for_feature\"><xliff:g id=\"split_name\" example=\"some_split\">%1$s</xliff:g> dla funkcji <xliff:g id=\"feature_name\" example=\"Visualizer\">%2$s</xliff:g></string>\n    <string name=\"split_feature_name\">Funkcja: <xliff:g id=\"feature_name\" example=\"Visualizer\">%1$s</xliff:g></string>\n    <string name=\"base_apk\">Podstawowy plik APK</string>\n    <string name=\"choose_language\">Zmień język</string>\n    <string name=\"pref_app_language\">Język</string>\n    <string name=\"backup_all_users\">Wszyscy użytkownicy</string>\n    <string name=\"backup_multiple\">Utwórz kopię zapasową wielu</string>\n    <string name=\"backup_obb_media\">OBB i Media</string>\n    <string name=\"backup_apk_files\">Pliki APK</string>\n    <string name=\"installer_error_session_commit\">Nie udało się zatwierdzić plików APK</string>\n    <string name=\"installer_error_session_write\">Nie można zapisać do sesji instalatora</string>\n    <string name=\"installer_error_session_create\">Nie można utworzyć sesji instalatora</string>\n    <string name=\"installer_error_security\">Nie uzyskano dostępu do plików APK</string>\n    <string name=\"install_in_progress\">Instalowanie…</string>\n    <string name=\"license\">Licencja</string>\n    <string name=\"class_name\">Nazwa klasy</string>\n    <string name=\"shortcut_name\">Nazwa skrótu</string>\n    <string name=\"orientation\">Orientacja</string>\n    <string name=\"no_service\">Brak usług</string>\n    <string name=\"service\">Usługi</string>\n    <string name=\"sort_by_last_update\">Data ostatniej aktualizacji</string>\n    <string name=\"refresh\">Odśwież</string>\n    <string name=\"launch\">Uruchom</string>\n    <string name=\"uninstall\">Odinstaluj</string>\n    <string name=\"failed_to_grant_permission\">Nie udało się udzielić uprawnienia</string>\n    <string name=\"deny_dangerous_permissions\">Odmów niebezpiecznych uprawnień</string>\n    <string name=\"sort_by_denied_permissions\">Najpierw odmówione</string>\n    <string name=\"sort_by_dangerous_permissions\">Najpierw niebezpieczne</string>\n    <string name=\"sort_by_permission_names\">Nazwa uprawnienia</string>\n    <string name=\"sort_by_app_ops_values\">Wartość App ops</string>\n    <string name=\"orientation_no_sensor\">Brak czujnika</string>\n    <string name=\"orientation_user\">Użytkownika</string>\n    <string name=\"orientation_sensor\">Czujnik</string>\n    <string name=\"required\">Wymagane</string>\n    <string name=\"_undefined\">Nieokreślony</string>\n    <string name=\"keyboard_no_keys\">Brak klawiszy</string>\n    <string name=\"keyboard_qwerty\">QWERTY</string>\n    <string name=\"navigation_no_nav\">Brak nawigacji</string>\n    <string name=\"navigation_dial_pad\">Klawiatura wybierania numerów</string>\n    <string name=\"navigation_trackball\">Trackball</string>\n    <string name=\"touchscreen_stylus\">Rysik</string>\n    <string name=\"state_sleeping\">Uśpiony</string>\n    <string name=\"state_zombie\">Zombie</string>\n    <string name=\"state_idle\">Bezczynny</string>\n    <string name=\"state_unknown\">NIeznany</string>\n    <string name=\"state_high_priority\">Wysoki priorytet</string>\n    <string name=\"state_low_priority\">Niski priorytet</string>\n    <string name=\"state_multithreaded\">Wielowątkowy</string>\n    <string name=\"process_state\">Stan: <xliff:g id=\"process_state\" example=\"Sleeping\">%1$s</xliff:g></string>\n    <string name=\"process_state_with_extra\">Stan: <xliff:g id=\"process_state\" example=\"Sleeping\">%1$s</xliff:g> (<xliff:g id=\"state_extra\" example=\"High priority\">%2$s</xliff:g>)</string>\n    <string name=\"downgrade\">Zmiana wersji na starszą</string>\n    <string name=\"input_backup_name\">Nazwa kopii zapasowej</string>\n    <string name=\"input_backup_name_description\">Nazwa kopii zapasowej nie powinna zaczynać się od cyfry ani zawierać spacji. Pozostaw to pole puste, jeśli chcesz używać bieżącej daty i godziny.</string>\n    <string name=\"ok\">OK</string>\n    <string name=\"cancel\">Anuluj</string>\n    <string name=\"open_pgp_provider\">Aplikacja OpenPGP</string>\n    <string name=\"profiles\">Profile</string>\n    <string name=\"no_profiles\">Brak profili</string>\n    <string name=\"keystore\">KeyStore</string>\n    <string name=\"apply_now\">Zastosuj…</string>\n    <string name=\"routine_ops\">Rutynowe operacje</string>\n    <string name=\"apps\">Aplikacje</string>\n    <string name=\"no_apps\">Brak aplikacji</string>\n    <string name=\"filter_apps\">Aplikacje</string>\n    <string name=\"sort_by_process_id\">Identyfikator procesu</string>\n    <string name=\"sort_by_process_name\">Nazwa procesu</string>\n    <string name=\"sort_by_apps_first\">Najpierw aplikacje</string>\n    <string name=\"sort_by_memory_usage\">Wykorzystanie pamięci</string>\n    <string name=\"changes_not_saved\">Zmiany nie zostały zapisane</string>\n    <string name=\"other\">Inne</string>\n    <string name=\"rules\">Zasady</string>\n    <string name=\"pref_compression_method\">Metoda kompresji</string>\n    <string name=\"filter_user_apps\">Aplikacje użytkownika</string>\n    <string name=\"filter\">Filtruj</string>\n    <string name=\"obb_files_extracted_successfully\">Wyodrębniono pliki OBB</string>\n    <plurals name=\"alert_failed_to_uninstall\">\n        <item quantity=\"one\">Nie udało się odinstalować %1$d aplikacji</item>\n        <item quantity=\"few\">Nie udało się odinstalować %1$d aplikacji</item>\n        <item quantity=\"many\">Nie udało się odinstalować %1$d aplikacji</item>\n        <item quantity=\"other\">Nie udało się odinstalować %1$d aplikacji</item>\n    </plurals>\n    <plurals name=\"failed_to_import_files\">\n        <item quantity=\"one\">Nie udało się zaimportować %1$d pliku.</item>\n        <item quantity=\"few\">Nie udało się zaimportować %1$d plików.</item>\n        <item quantity=\"many\">Nie udało się zaimportować %1$d plików.</item>\n        <item quantity=\"other\">Nie udało się zaimportować %1$d plików.</item>\n    </plurals>\n    <string name=\"the_export_was_successful\">Wyeksportowano</string>\n    <string name=\"the_import_was_successful\">Importowano</string>\n    <string name=\"install_app_message\">Czy chcesz zainstalować tę aplikację\\?</string>\n    <string name=\"try_again\">Spróbuj ponownie</string>\n    <string name=\"full_stop_tap_to_see_details\">. Naciśnij, aby wyświetlić szczegóły.</string>\n    <string name=\"operation_running\">Praca w toku…</string>\n    <string name=\"apply_to_system_apps_question\">Zastosować też do aplikacji systemowych\\? Wybierz „Nie”, jeśli nie masz pewności.</string>\n    <string name=\"apply_to_system_apps\">Zastosuj do aplikacji systemowych</string>\n    <plurals name=\"alert_failed_to_block_components\">\n        <item quantity=\"one\">Nie udało się zablokować komponentów dla %1$d aplikacji</item>\n        <item quantity=\"few\">Nie udało się zablokować komponentów dla %1$d aplikacji</item>\n        <item quantity=\"many\">Nie udało się zablokować komponentów dla %1$d aplikacji</item>\n        <item quantity=\"other\">Nie udało się zablokować komponentów dla %1$d aplikacji</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_unblock_trackers\">\n        <item quantity=\"one\">Nie można odblokować elementów śledzących w %1$d aplikacji</item>\n        <item quantity=\"few\">Nie można odblokować elementów śledzących w %1$d aplikacjach</item>\n        <item quantity=\"many\">Nie można odblokować elementów śledzących w %1$d aplikacjach</item>\n        <item quantity=\"other\">Nie można odblokować elementów śledzących w %1$d aplikacjach</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_delete_backup\">\n        <item quantity=\"one\">Nie można usunąć %1$d kopii zapasowej</item>\n        <item quantity=\"few\">Nie można usunąć %1$d kopii zapasowych</item>\n        <item quantity=\"many\">Nie można usunąć %1$d kopii zapasowych</item>\n        <item quantity=\"other\">Nie można usunąć %1$d kopii zapasowych</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_restore\">\n        <item quantity=\"one\">Nie można przywrócić %1$d aplikacji</item>\n        <item quantity=\"few\">Nie można przywrócić %1$d aplikacji</item>\n        <item quantity=\"many\">Nie można przywrócić %1$d aplikacji</item>\n        <item quantity=\"other\">Nie można przywrócić %1$d aplikacji</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_backup\">\n        <item quantity=\"one\">Nie można utworzyć kopii zapasowej %1$d aplikacji</item>\n        <item quantity=\"few\">Nie można utworzyć kopii zapasowej %1$d aplikacji</item>\n        <item quantity=\"many\">Nie można utworzyć kopii zapasowej %1$d aplikacji</item>\n        <item quantity=\"other\">Nie można utworzyć kopii zapasowej %1$d aplikacji</item>\n    </plurals>\n    <plurals name=\"failed_to_backup_some_apk_files\">\n        <item quantity=\"one\">Nie można utworzyć kopii zapasowej %1$d aplikacji</item>\n        <item quantity=\"few\">Nie można utworzyć kopii zapasowej %1$d aplikacji</item>\n        <item quantity=\"many\">Nie można utworzyć kopii zapasowej %1$d aplikacji</item>\n        <item quantity=\"other\">Nie można utworzyć kopii zapasowej %1$d aplikacji</item>\n    </plurals>\n    <string name=\"backup_options\">Opcje tworzenia kopii zapasowych</string>\n    <string name=\"delete_backup\">Usuń kopię zapasową</string>\n    <string name=\"data\">Dane</string>\n    <string name=\"installed_version\">Zainstalowana wersja</string>\n    <string name=\"select_all\">Zaznacz wszystko</string>\n    <string name=\"filter_apps_with_rules\">Z regułami</string>\n    <string name=\"filter_system_apps\">Aplikacje systemowe</string>\n    <string name=\"blocking_rules\">Reguły blokowania</string>\n    <string name=\"whats_new\">Co nowego</string>\n    <string name=\"components\">Komponenty</string>\n    <string name=\"trackers\">Elementy śledzące</string>\n    <string name=\"reset_to_default\">Przywróć ustawienia domyślne</string>\n    <string name=\"sort_by_component_name\">Nazwa komponentu</string>\n    <string name=\"block_trackers\">Blokuj elementy śledzące</string>\n    <string name=\"version\">Wersja</string>\n    <string name=\"pref_about_msg\">Wersja App Manager, licencja, autorzy itp.</string>\n    <string name=\"apply\">Zastosuj</string>\n    <string name=\"select_theme\">Motyw</string>\n    <string name=\"night\">Noc</string>\n    <string name=\"day\">Dzień</string>\n    <string name=\"follow_system\">Zgodny z systemowym</string>\n    <string name=\"pref_app_theme\">Motyw aplikacji</string>\n    <string name=\"class_viewer\">Przeglądarka klas</string>\n    <string name=\"word_wrap\">Przełącz zawijanie słów</string>\n    <string name=\"credits_message\">Do autorów\n\\n- Projektu Android Open Source (AOSP)\n\\n- <a href=\"https://github.com/zhaobozhen/libraries\">Absinthe\\'s libraries</a>\n\\n- <a href=\"https://github.com/butzist/ActivityLauncher\">Activity Launcher</a>\n\\n- <a href=\"https://bitbucket.org/oF2pks/fdroid-applications-info\">Apps_packages Info</a>\n\\n- <a href=\"https://github.com/zhaobao/AppsMonitor\">AppsMonitor</a>\n\\n- <a href=\"https://github.com/8enet/AppOpsX\">AppOpsX</a>\n\\n- <a href=\"https://github.com/gabrielemariotti/changeloglib\">ChangeLog Library</a>\n\\n- <a href=\"https://bitbucket.org/oF2pks/fdroid-classyshark3xodus\">ClassySharkAndroid</a>\n\\n- <a href=\"https://github.com/billthefarmer/editor\">Editor</a>\n\\n- <a href=\"https://github.com/nex3z/FlowLayout\">FlowLayout</a>\n\\n- <a href=\"https://github.com/k3b/intent-intercept\">Intent Intercept</a>\n\\n- <a href=\"https://github.com/YarikSOffice/lingver\">Lingver</a>\n\\n- <a href=\"https://github.com/topjohnwu/Magisk\">Magisk</a>\n\\n- <a href=\"https://github.com/zhanghai/MaterialFiles\">Material Files</a>\n\\n- <a href=\"https://github.com/pluscubed/matlog\">MatLog</a>\n\\n- <a href=\"https://github.com/matrix-org/matrix-android-sdk\">Matrix Android SDK</a>\n\\n- <a href=\"https://github.com/jensstein/oandbackup\">OAndBackup</a>\n\\n- <a href=\"https://github.com/open-keychain/open-keychain\">Open Keychain</a>\n\\n- <a href=\"https://github.com/Aefyr/SAI\">SAI</a>\n\\n- <a href=\"https://github.com/RikkaApps/Shizuku\">Shizuku</a>\n\\n- <a href=\"https://github.com/tuyafeng/Watt\">Watt</a> </string>\n    <string name=\"icon_picker\">Selektor ikon</string>\n    <string name=\"create_shortcut\">Utwórz skrót</string>\n    <string name=\"error_creating_shortcut\">Wystąpił błąd podczas tworzenia skrótu</string>\n    <string name=\"app_not_installed\">Aplikacja nie jest zainstalowana</string>\n    <string name=\"obb_size\">Obb</string>\n    <string name=\"cache_size\">Pamięć podręczna</string>\n    <string name=\"data_size\">Dane</string>\n    <string name=\"about\">O programie</string>\n    <string name=\"data_usage_msg\">Użycie danych</string>\n    <string name=\"data_transmitted\">Wysłane dane</string>\n    <string name=\"data_received\">Odebrane dane</string>\n    <string name=\"sort_by_target_sdk\">Docelowy SDK</string>\n    <string name=\"sort_by_domain\">Najpierw aplikacje użytkownika</string>\n    <string name=\"only_install\">Tylko zainstaluj</string>\n    <string name=\"app_data_will_be_lost\">Istniejące dane zostaną utracone.</string>\n    <string name=\"app_signing_signature_mismatch_for_system_apps\">Nie można było zainstalować aplikacji, ponieważ zainstalowana aplikacja jest aplikacją systemową z inną sygnaturą.</string>\n    <string name=\"do_you_want_to_uninstall_and_install\">Czy chcesz odinstalować i ponownie zainstalować aplikację\\?</string>\n    <string name=\"usage_access_not_supported\">Nie można żądać dostępu do danych użytkowania, ponieważ nie istnieje odpowiednia strona ustawień.</string>\n    <string name=\"rsa_exponent\">Wykładnik</string>\n    <string name=\"format\">Format</string>\n    <string name=\"public_key\">Klucz publiczny</string>\n    <string name=\"algorithm\">Algorytm</string>\n    <string name=\"checksums\">Sumy kontrolne</string>\n    <string name=\"serial_no\">Numer seryjny</string>\n    <string name=\"validity\">Ważność</string>\n    <string name=\"type\">Typ</string>\n    <string name=\"filter_apps_with_backups\">Z kopią zapasową</string>\n    <string name=\"failed_to_uninstall_updates\">Nie można odinstalować aktualizacji dla <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g>.</string>\n    <string name=\"update_uninstalled_successfully\">Aktualizacje dla <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g> zostały odinstalowane.</string>\n    <string name=\"uninstall_updates\">Odinstaluj aktualizacje</string>\n    <string name=\"allow_open_pgp_operation\">Dotknij, aby zezwolić App Manager na używanie OpenPGP</string>\n    <string name=\"confirm_installation\">Potwierdź instalację</string>\n    <string name=\"error_evaluating_input\">Nie można ewaluować danych wejściowych</string>\n    <string name=\"type_string\">Znaki</string>\n    <string name=\"type_long\">Długa liczba całkowita</string>\n    <string name=\"type_int\">Liczba całkowita</string>\n    <string name=\"type_float\">Liczba dziesiętna</string>\n    <string name=\"done\">Gotowe</string>\n    <string name=\"add_item\">Dodaj element</string>\n    <string name=\"select_type\">Wybierz typ</string>\n    <string name=\"key_name\">Nazwa klucza</string>\n    <string name=\"boolean_value\">Wartość logiczna (Boolean)</string>\n    <string name=\"decimal_value\">Wartość dziesiętna</string>\n    <string name=\"saving_failed\">Zapisywanie nie powiodło się, spróbuj ponownie.</string>\n    <string name=\"saved_successfully\">Zapisano</string>\n    <string name=\"deletion_failed\">Usunięcie nie powiodło się</string>\n    <string name=\"deleted_successfully\">Usunięto</string>\n    <string name=\"delete\">Usuń</string>\n    <string name=\"discard\">Odrzuć</string>\n    <string name=\"save\">Zapisz</string>\n    <string name=\"databases\">Bazy danych</string>\n    <string name=\"debuggable\">Debugowalna</string>\n    <string name=\"updated_app\">Zaktualizowany</string>\n    <string name=\"requested_large_heap\">Duży heap</string>\n    <string name=\"no_code\">Brak kodu</string>\n    <string name=\"process_name\">Nazwa procesu</string>\n    <string name=\"native_library_dir\">Natywny katalog bibliotek JNI</string>\n    <string name=\"search\">Szukaj</string>\n    <string name=\"menu_apply_rules\">Zastosuj reguły</string>\n    <string name=\"menu_remove_rules\">Usuń reguły</string>\n    <string name=\"failed_to_extract_apk_file\">Nie udało się wyodrębnić pliku APK</string>\n    <string name=\"share_apk\">Udostępnij plik APK</string>\n    <string name=\"go_back\">Wróć</string>\n    <string name=\"usage_less_than_a_minute\">Mniej niż minuta</string>\n    <plurals name=\"usage_hours\">\n        <item quantity=\"one\">%1$d godz</item>\n        <item quantity=\"few\">%1$d godz</item>\n        <item quantity=\"many\">%1$d godz</item>\n        <item quantity=\"other\">%1$d godz</item>\n    </plurals>\n    <plurals name=\"usage_days\">\n        <item quantity=\"one\">%1$d dzień</item>\n        <item quantity=\"few\">%1$d dni</item>\n        <item quantity=\"many\">%1$d dni</item>\n        <item quantity=\"other\">%1$d dni</item>\n    </plurals>\n    <plurals name=\"usage_months\">\n        <item quantity=\"one\">%1$d mies.</item>\n        <item quantity=\"few\">%1$d mies.</item>\n        <item quantity=\"many\">%1$d mies.</item>\n        <item quantity=\"other\">%1$d mies.</item>\n    </plurals>\n    <string name=\"usage_7_days\">Ostatnie 7 dni</string>\n    <string name=\"usage_today\">Dziś</string>\n    <string name=\"usage_weekly\">Tygodniowe</string>\n    <string name=\"app_usage\">Użycie aplikacji</string>\n    <string name=\"no_tracker_class\">Brak klas śledzących</string>\n    <string name=\"no_shared_libs\">Brak współdzielonych bibliotek</string>\n    <plurals name=\"main_list_date_days\">\n        <item quantity=\"one\"><xliff:g id=\"last_update_date\" example=\"20/10/2020\">%1$s</xliff:g> <xliff:g id=\"day_no\" example=\"5\">%2$d</xliff:g> dzień</item>\n        <item quantity=\"few\"><xliff:g id=\"last_update_date\" example=\"20/10/2020\">%1$s</xliff:g> <xliff:g id=\"day_no\" example=\"5\">%2$d</xliff:g> dni</item>\n        <item quantity=\"many\"><xliff:g id=\"last_update_date\" example=\"20/10/2020\">%1$s</xliff:g> <xliff:g id=\"day_no\" example=\"5\">%2$d</xliff:g> dni</item>\n        <item quantity=\"other\"><xliff:g id=\"last_update_date\" example=\"20/10/2020\">%1$s</xliff:g> <xliff:g id=\"day_no\" example=\"5\">%2$d</xliff:g> dni</item>\n    </plurals>\n    <string name=\"all_classes\">Wszystkie klasy</string>\n    <string name=\"expired\">Wygasły</string>\n    <string name=\"valid\">Ważny</string>\n    <string name=\"expiry_date\">Data ważności</string>\n    <string name=\"issued_date\">Data wydania</string>\n    <string name=\"no_content\">Brak zawartości</string>\n    <string name=\"no_usage_in_this_time_range\">Brak użycia w tym zakresie czasowym</string>\n    <string name=\"key_name_cannot_be_null\">Nazwa klucza nie może być pusta</string>\n    <string name=\"storage_and_cache\">Dane i pamięć podręczna</string>\n    <string name=\"failed_to_stop\">Nie udało się zatrzymać <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g>.</string>\n    <string name=\"force_stop\">Wymuś zatrzymanie</string>\n    <string name=\"enable\">Włącz</string>\n    <string name=\"uninstall_system_app_message\">To jest aplikacja systemowa. Czy na pewno chcesz odinstalować tę aplikację\\?</string>\n    <string name=\"uninstalled_successfully\">Aplikacja <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g> została odinstalowana.</string>\n    <string name=\"uninstall_app_message\">Czy chcesz odinstalować tę aplikację\\?</string>\n    <string name=\"view_in_settings\">Wyświetl w ustawieniach</string>\n    <string name=\"disabled_app\">Wyłączona</string>\n    <string name=\"kill_process\">Zakończ</string>\n    <string name=\"pref_import_blocker\">Importuj z Blocker</string>\n    <string name=\"pref_import_watt\">Importuj z Watt</string>\n    <string name=\"pref_import_export_blocking_rules\">Importuj/eksportuj reguły blokowania</string>\n    <string name=\"sort_by_mobile_data\">Dane komórkowe</string>\n    <string name=\"sort_by_last_used\">Ostatnio używane</string>\n    <string name=\"toggle_class_listing\">Pokaż/ukryj listę klas</string>\n    <string name=\"credits\">Podziękowania</string>\n    <string name=\"third_party\">Biblioteki i ikony osób trzecich</string>\n    <string name=\"no_receivers\">Brak odbiorników</string>\n    <string name=\"no_activities\">Brak działań</string>\n    <string name=\"only_works_in_root_or_adb_mode\">Działa tylko w trybie root lub ADB</string>\n    <string name=\"no_tracker_found\">Nie znaleziono elementów śledzących</string>\n    <string name=\"failed_packages\">Nieudane pakiety</string>\n    <string name=\"clear_app_cache\">Wyczyść pamięć podręczną aplikacji</string>\n    <string name=\"clear_data_from_uninstalled_apps_description\">Wyczyść dane z aplikacji, które zostały odinstalowywane z flagą <tt>DONT_DELETE_DATA</tt></string>\n    <string name=\"clear_data_from_uninstalled_apps\">Wyczyść dane odinstalowanych aplikacji</string>\n    <string name=\"block_components_dots\">Zablokuj komponenty…</string>\n    <string name=\"block_unblock_trackers_description\">Zablokuj lub odblokuj komponenty śledzące i reklamy we wszystkich zainstalowanych aplikacjach</string>\n    <string name=\"clear_cache\">Wyczyść pamięć podręczną</string>\n    <string name=\"pref_import_existing_msg\">Dodawanie składników wyłączonych przez inne aplikacje do App Manager. Zachowaj ostrożność podczas korzystania z tego narzędzia, ponieważ może wystąpić wiele fałszywych alarmów. Wybierz aplikacje godne zaufania.</string>\n    <string name=\"pref_import_existing\">Importuj istniejące reguły</string>\n    <string name=\"source_code\">Kod źródłowy</string>\n    <string name=\"update\">Zaktualizuj</string>\n    <string name=\"install\">Zainstaluj</string>\n    <plurals name=\"no_of_trackers\">\n        <item quantity=\"one\">%1$d element śledzący</item>\n        <item quantity=\"few\">%1$d elementy śledzące</item>\n        <item quantity=\"many\">%1$d elementów śledzących</item>\n        <item quantity=\"other\">%1$d elementów śledzących</item>\n    </plurals>\n    <string name=\"manifest_viewer\">Przeglądarka manifestów</string>\n    <string name=\"changelog\">Lista zmian</string>\n    <string name=\"one_click_ops\">Operacje 1-Click</string>\n    <string name=\"never_ask\">Nigdy nie pytaj</string>\n    <string name=\"launch_app\">Uruchom</string>\n    <string name=\"auto\">Auto</string>\n    <string name=\"failed_to_extract_obb_files\">Nie można wyodrębnić plików OBB</string>\n    <string name=\"installer_error_session_abandon\">Nie udało się porzucić sesji instalatora</string>\n    <string name=\"unblock_trackers\">Odblokuj elementy śledzące</string>\n    <string name=\"reinstall\">Zainstaluj ponownie</string>\n    <string name=\"close\">Zamknij</string>\n    <string name=\"no_root\">Brak roota</string>\n    <string name=\"root\">Root</string>\n    <string name=\"user_profile_with_id\">Profil: %1$s (%2$d)</string>\n    <string name=\"advanced\">Zaawansowane</string>\n    <string name=\"simple\">Proste</string>\n    <string name=\"enabled\">Włączone</string>\n    <string name=\"choose\">Wybierz</string>\n    <string name=\"options\">Opcje</string>\n    <string name=\"on\">Wł.</string>\n    <string name=\"off\">Wył.</string>\n    <string name=\"profile_block_trackers_msg\">Blokuje elementy śledzące w aplikacjach</string>\n    <string name=\"allow_routine_ops_msg\">Pozwól, aby profil był używany w rutynowych operacjach</string>\n    <string name=\"adb_over_tcp\">ADB przez TCP</string>\n    <string name=\"pref_mode_of_operations\">Tryb pracy</string>\n    <string name=\"send_selected\">Wyślij wybrane</string>\n    <string name=\"ecc\">Kryptografia krzywych eliptycznych (ECC)</string>\n    <string name=\"rsa\">RSA</string>\n    <string name=\"aes\">AES</string>\n    <string name=\"none\">Brak</string>\n    <string name=\"pref_encryption_msg\">Dodaj szyfrowanie do kopii zapasowych.</string>\n    <string name=\"encryption\">Szyfrowanie</string>\n    <string name=\"select_user\">Wybierz użytkownika</string>\n    <string name=\"failed_to_duplicate_profile\">Nie udało się zduplikować profilu</string>\n    <string name=\"duplicate\">Duplikuj</string>\n    <string name=\"new_profile\">Nowy profil</string>\n    <string name=\"install_location\">Miejsce instalacji</string>\n    <string name=\"installer\">Instalator</string>\n    <string name=\"comment\">Komentarz</string>\n    <string name=\"app_signing_signature_schemes\">Schematy podpisów</string>\n    <string name=\"pref_sign_apk_msg\">Podpisz pliki APK przed ich zainstalowaniem.</string>\n    <string name=\"pref_sign_apk\">Podpisz plik APK</string>\n    <string name=\"pref_signature_schemes_msg\">Aby zapewnić większą kompatybilność, należy wybrać co najmniej schematy v1 i v2. Schemat v4 wymaga wersji v2 lub v3.</string>\n    <string name=\"v4_scheme\">schemat v4 (od Android 11)</string>\n    <string name=\"v3_scheme\">schemat v3 (od Android 9)</string>\n    <string name=\"v2_scheme\">schemat v2 (od Android 7.0)</string>\n    <string name=\"v1_scheme\">schemat v1 (od Android 1.0)</string>\n    <string name=\"pref_apk_signing_msg\">Ustaw schematy podpisywania, niestandardowy klucz, itp.</string>\n    <string name=\"apk_signing\">Podpisywanie APK</string>\n    <string name=\"app_size\">Aplikacja</string>\n    <string name=\"failed_to_enable_op\">Nie można włączyć pożądanej funkcji App Op</string>\n    <string name=\"no_app_ops\">Brak operacji</string>\n    <string name=\"app_ops\">Działania aplikacji</string>\n    <string name=\"disable\">Wyłącz</string>\n    <string name=\"failed_to_uninstall\">Nie można usunąć <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g>.</string>\n    <string name=\"integer_value\">Wartość liczby całkowitej</string>\n    <string name=\"long_integer_value\">Długa wartość liczby całkowitej</string>\n    <string name=\"string_value\">Wartość ciągu</string>\n    <string name=\"shared_prefs\">Udostępnione Prefs</string>\n    <string name=\"test_only\">Tylko test</string>\n    <string name=\"dev_protected_data_dir\">Chroniony Katalog Danych</string>\n    <string name=\"grant_usage_acess_message\">Służy do wyświetlania informacji o użyciu aplikacji.</string>\n    <string name=\"grant_usage_access\">Przyznaj Dostęp do Użytkowania</string>\n    <string name=\"go\">Idź</string>\n    <string name=\"tracker_classes\">Klasy elementów śledzących</string>\n    <string name=\"tracker_details\">Szczegóły elementu śledzącego</string>\n    <string name=\"found_trackers\">Znaleziono elementów śledzących:</string>\n    <string name=\"package_name\">Nazwa Pakietu</string>\n    <string name=\"error_verbose_pin_shortcut\">Obecny launcher nie wspiera PinShortcut. Brak możliwości utworzenia skrótu.</string>\n    <string name=\"empty_package_name\">Pusta nazwa pakietu</string>\n    <string name=\"main_activity\">Aktywność główna</string>\n    <string name=\"installer_app\">Instalator</string>\n    <string name=\"user\">Użytkownik</string>\n    <string name=\"media_size\">Media</string>\n    <string name=\"sort_by_package_name\">Nazwa pakietu</string>\n    <string name=\"input_features\">Funkcje wejściowe</string>\n    <string name=\"patterns_allowed\">Dozwolone wzorce</string>\n    <string name=\"no_providers\">Brak dostawców</string>\n    <string name=\"providers\">Dostawcy</string>\n    <string name=\"activities\">Aktywności</string>\n    <string name=\"stopped\">Zatrzymane</string>\n    <string name=\"type_boolean\">Prawda/fałsz</string>\n    <string name=\"set_mode_for_app_ops_dots\">Ustaw tryb dla operacji aplikacji…</string>\n    <string name=\"security\">Zabezpieczenia</string>\n    <string name=\"battery\">Bateria</string>\n    <string name=\"graphics\">Karta graficzna</string>\n    <string name=\"cpu\">Procesor</string>\n    <string name=\"users\">Użytkownicy</string>\n    <string name=\"languages\">Języki</string>\n    <string name=\"battery_capacity\">Pojemność</string>\n    <string name=\"memory\">Pamięć</string>\n    <string name=\"gles_version\">Wersja OpenGL ES</string>\n    <string name=\"no_of_cores\">Rdzenie</string>\n    <string name=\"support_architectures\">Wspomagane architektury</string>\n    <string name=\"security_providers\">Dostawcy zabezpieczeń</string>\n    <string name=\"kernel\">Kernel</string>\n    <string name=\"manufacturer\">Producent</string>\n    <string name=\"model\">Model</string>\n    <string name=\"brand_name\">Marka</string>\n    <string name=\"pref_about_device_msg\">Podstawowe informacje o urządzeniu, w tym o systemie Android, CPU, GPU, RAM, baterii, itp.</string>\n    <string name=\"about_device\">Informacje o urządzeniu</string>\n    <string name=\"interceptor\">Przechwytywanie</string>\n    <string name=\"share\">Udostępnij</string>\n    <string name=\"drm_free_apkm_msg\">Plik APKM jest wolny od DRM, nie ma potrzeby konwertowania go na APKS.</string>\n    <string name=\"restore_msg\">Przywróć aplikacje z danymi</string>\n    <string name=\"backup_msg\">Twórz kopie zapasowe aplikacji z danymi</string>\n    <string name=\"restore_latest\">Przywróć najnowsze kopie zapasowe</string>\n    <string name=\"restore_not_installed_msg\">Przywróć podstawową kopię zapasową dla aplikacji, które nie są obecnie zainstalowane.</string>\n    <string name=\"restore_not_installed\">Przywróć niezainstalowane aplikacje</string>\n    <string name=\"restore_all_msg\">Przywróć podstawową kopię zapasową ze wszystkich kopii zapasowych aplikacji.</string>\n    <string name=\"restore_all\">Przywróć wszystkie aplikacje</string>\n    <string name=\"backup_apps_with_changes_msg\">Wykonaj ponownie kopie zapasowe dla aplikacji ze zmianami od czasu ostatniej kopii zapasowej. Obejmują one zmiany w rozmiarze, wersji, czasie ostatniego uruchomienia.</string>\n    <string name=\"redo_existing_backups_msg\">Wykonaj ponownie kopię zapasową dla zainstalowanych aplikacji z poprzednimi kopiami zapasowymi.</string>\n    <string name=\"redo_existing_backups\">Ponów istniejące kopie zapasowe</string>\n    <string name=\"verify_and_redo_backups_msg\">Sprawdź integralność poprzednich kopii zapasowych i wykonaj ponownie kopie zapasowe, dla których sprawdzanie integralności nie uda się.</string>\n    <string name=\"verify_and_redo_backups\">Zweryfikuj i ponów kopie zapasowe</string>\n    <string name=\"backup_apps_without_backups_msg\">Utwórz kopie zapasowe aplikacji bez wcześniejszych kopii zapasowych.</string>\n    <string name=\"backup_apps_without_backups\">Utwórz kopie zapasowe aplikacji bez kopii zapasowych</string>\n    <string name=\"backup_all_apps_msg\">Utwórz kopię zapasową wszystkich zainstalowanych aplikacji.</string>\n    <string name=\"backup_all_apps\">Utwórz kopię zapasową wszystkich aplikacji</string>\n    <string name=\"backup_custom_users_description\">Wykonuj kopie zapasowe tylko dla określonych użytkowników</string>\n    <string name=\"backup_custom_users\">Użytkownicy niestandardowi</string>\n    <string name=\"bootloader\">Program rozruchowy</string>\n    <string name=\"encrypted\">Zaszyfrowane</string>\n    <string name=\"unencrypted\">Niezaszyfrowane</string>\n    <string name=\"no_volumes_found\">Nie można odnaleźć żadnych woluminów z uprawnieniami do zapisu.</string>\n    <string name=\"pref_backup_volume_msg\">Wybierz wolumin lub dysk, na którym będą przechowywane kopie zapasowe.</string>\n    <string name=\"pref_backup_restore_msg\">Dostosuj kopię zapasową/przywracanie.</string>\n    <string name=\"failed_to_enable_magisk_hide\">Nie można włączyć MagiskHide</string>\n    <string name=\"backup_cache_description\">Utwórz kopię zapasową folderów <b>cache</b>, <b>no_cache</b> i <b>no_backup</b>.</string>\n    <string name=\"backup_obb_media_description\">Utwórz kopię zapasową folderów OBB i media.</string>\n    <string name=\"resend_intent\">Wyślij intent ponownie</string>\n    <string name=\"category\">Kategorie</string>\n    <string name=\"type_component_name\">Nazwa komponentu</string>\n    <string name=\"screen_lock_msg\">Zablokuj App Manager za pomocą blokady ekranu systemu Android</string>\n    <string name=\"screen_lock\">Blokada ekranu</string>\n    <string name=\"unlock_app_manager\">Odblokuj App Manager</string>\n    <string name=\"sd_card\">Karta SD</string>\n    <string name=\"external_storage\">Pamięć zewnętrzna</string>\n    <string name=\"restart_to_reflect_changes\">Zrestartuj urządzenie, aby zastosować zmiany.</string>\n    <string name=\"failed_to_change_ssaid\">Nie udało się zmienić SSAID</string>\n    <string name=\"copied_to_clipboard\">Skopiowano do schowka.</string>\n    <string name=\"ssaid_info\">SSAID (<tt>Settings.Secure.ANDROID_ID</tt>) jest identyfikatorem urządzenia przypisanym do każdej aplikacji (od Android 8 \\\"Oreo\\\" wzwyż). Jest on szeroko wykorzystywany przez aplikacje do śledzenia użytkowników.</string>\n    <string name=\"ssaid\">SSAID</string>\n    <string name=\"os_version\">Wersja systemu operacyjnego</string>\n    <string name=\"add\">Dodaj</string>\n    <string name=\"add_to_profile\">Dodaj do profilu</string>\n    <string name=\"initializing\">Inicjalizacja…</string>\n    <string name=\"enable_battery_optimization\">Włączyć optymalizację baterii\\?</string>\n    <string name=\"type_uri\">URI</string>\n    <string name=\"receivers\">Odbiorniki</string>\n    <string name=\"backup_extras_description\">Utwórz kopię zapasową uprawnień aplikacji, oszczędzania baterii, opcji wykorzystania danych, statusu MagiskHide, SSAID itp. <font fgcolor=\"#ff0000\">W zależności od uprawnień, nie wszystkie dodatki mogą zostać przywrócone.</font></string>\n    <string name=\"backup_internal_data_description\">Utwórz kopię zapasową folderów danych. Jeśli ta opcja jest wybrana, kopie zapasowe wewnętrznych folderów danych zostaną utworzone.</string>\n    <string name=\"window_size\">Rozmiar okna</string>\n    <string name=\"refresh_rate\">Częstotliwość odświeżania</string>\n    <string name=\"scaling_factor\">Współczynnik skalowania</string>\n    <string name=\"size\">Rozmiar</string>\n    <string name=\"screen\">Ekran</string>\n    <string name=\"selinux\">SELinux</string>\n    <string name=\"patch_level\">Poziom łatki</string>\n    <string name=\"external_data_dir\">Zewnętrzny katalog danych</string>\n    <string name=\"sort_by_blocked_components\">Najpierw zablokowane</string>\n    <string name=\"usage_yesterday\">Wczoraj</string>\n    <string name=\"usage_access\">Dostęp do danych użytkowania</string>\n    <string name=\"total_size\">Łącznie</string>\n    <string name=\"list_options\">Opcje listy</string>\n    <string name=\"choose_what_to_do\">Wybierz, co chcesz zrobić.</string>\n    <string name=\"battery_optimization\">Optymalizacja baterii</string>\n    <string name=\"no_battery_optimization\">Brak optymalizacji baterii</string>\n    <string name=\"type_float_array_list\">Lista liczb dziesiętnych</string>\n    <string name=\"screen_lock_not_enabled\">Wybierz opcję blokady ekranu w ustawieniach systemu Android lub wyczyść dane aplikacji.</string>\n    <string name=\"last_actions\">Ostatnie działania</string>\n    <string name=\"enable_disable_features\">Włączanie/wyłączanie funkcji</string>\n    <string name=\"installed_apps\">Zainstalowane aplikacje</string>\n    <string name=\"app_signing_signature\">Sygnatura</string>\n    <string name=\"not_yet_valid\">Jeszcze nie obowiązuje</string>\n    <string name=\"issuer\">Wystawiony przez</string>\n    <string name=\"orientation_reverse_landscape\">Pozioma, odwrócona</string>\n    <string name=\"orientation_reverse_portrait\">Pionowa, odwrócona</string>\n    <string name=\"orientation_portrait\">Pionowa</string>\n    <string name=\"orientation_landscape\">Pozioma</string>\n    <string name=\"input_profile_name_description\">Nazwa profilu nie może zawierać żadnych spacji.</string>\n    <string name=\"input_profile_name\">Nazwa profilu</string>\n    <string name=\"conversion_failed\">Konwersja nie powiodła się.</string>\n    <string name=\"select_apk\">Wybierz plik APK</string>\n    <string name=\"input_permissions_description\">Wprowadź uprawnienia ze spacjami, np. <tt>com.permission.GET_ACCOUNTS android.permission.ACCESS_MEDIA_LOCATION</tt> itd. Użyj <tt>*</tt> aby zastosować dla wszystkich uprawnień.</string>\n    <string name=\"input_permissions\">Wprowadź uprawnienia</string>\n    <string name=\"profile_state_msg\">Stan włączenia/wyłączenia dla tego profilu</string>\n    <string name=\"profile_clear_data_msg\">Dane aplikacji zostaną wyczyszczone</string>\n    <string name=\"profile_clear_cache_msg\">Pamięć podręczna aplikacji zostanie wyczyszczona</string>\n    <string name=\"profile_force_stop_msg\">Jeśli ta opcja jest włączona, aplikacje zostaną zatrzymane</string>\n    <string name=\"profile_state\">Stan profilu</string>\n    <string name=\"not_verified\">Nie zweryfikowane</string>\n    <string name=\"verified\">Zweryfikowane</string>\n    <string name=\"install_location_prefer_external\">Preferuj pamięć zewnętrzną</string>\n    <string name=\"install_location_internal_only\">Tylko pamięć wewnętrzna</string>\n    <string name=\"in_progress\">W toku</string>\n    <string name=\"uri\">URI</string>\n    <string name=\"mime_type\">Typ MIME</string>\n    <string name=\"action\">Działanie</string>\n    <string name=\"result_code\">Kod wyniku</string>\n    <string name=\"send_edited_intent\">Wyślij edytowany Intent</string>\n    <string name=\"value\">Wartość</string>\n    <string name=\"set_app_op_mode\">Ustaw tryb App Ops</string>\n    <string name=\"magisk_hide_enabled\">MagiskHide</string>\n    <string name=\"pref_backup_android_keystore_msg\">Nie wszystkie aplikacje będą działać po przywróceniu. Przywracanie KeyStore nie działa na większości urządzeń.</string>\n    <string name=\"pref_backup_android_keystore\">Twórz kopie zapasowe aplikacji używających Android KeyStore</string>\n    <string name=\"backup_multiple_description\">Utwórz oddzielną kopię zapasową <i> o nazwie</i> zamiast podstawowej kopii zapasowej.</string>\n    <string name=\"backup_rules_description\">Utwórz kopię zapasową reguł skonfigurowanych w App Manager. <font fgcolor=\"#ff0000\">W zależności od uprawnień, nie wszystkie reguły można ponownie zastosować podczas przywracania.</font></string>\n    <string name=\"backup_external_data_description\">Utwórz kopię zapasową zewnętrznych folderów danych.</string>\n    <string name=\"backup_apk_files_description\">Utwórz kopię zapasową tylko plików APK z katalogu źródłowego. <b>Źródło</b> musi być wybrane, aby to zadziałało.</string>\n    <string name=\"vendor\">Producent</string>\n    <string name=\"set_custom_app_op\">Ustaw własną operację aplikacji</string>\n    <string name=\"type_string_array_list\">Lista ciągów znaków</string>\n    <string name=\"type_string_array\">Tablica ciągów znaków</string>\n    <string name=\"type_float_array\">Tablica liczb dziesiętnych</string>\n    <string name=\"navigation\">Nawigacja</string>\n    <string name=\"keyboard_type\">Typ klawiatury</string>\n    <string name=\"export_failed\">Eksportowanie nie powiodło się!</string>\n    <string name=\"import_failed\">Importowanie nie powiodło się!</string>\n    <string name=\"export_options\">Opcje Eksportu</string>\n    <string name=\"import_options\">Opcje importu</string>\n    <string name=\"pref_export\">Eksportuj</string>\n    <string name=\"pref_import\">Importuj</string>\n    <string name=\"ago\">temu</string>\n    <string name=\"duration\">Czas trwania</string>\n    <string name=\"running\">Uruchomiona</string>\n    <string name=\"mode\">Tryb</string>\n    <string name=\"permission_name\">Nazwa uprawnienia</string>\n    <plurals name=\"alert_failed_to_force_stop\">\n        <item quantity=\"one\">Nie udało się wymusić zatrzymania %1$d aplikacji</item>\n        <item quantity=\"few\">Nie udało się wymusić zatrzymania %1$d aplikacji</item>\n        <item quantity=\"many\">Nie udało się wymusić zatrzymania %1$d aplikacji</item>\n        <item quantity=\"other\">Nie udało się wymusić zatrzymania %1$d aplikacji</item>\n    </plurals>\n    <string name=\"the_operation_was_successful\">Gotowe</string>\n    <plurals name=\"alert_failed_to_disable_background\">\n        <item quantity=\"one\">Nie udało się zablokować działania %1$d aplikacji w tle</item>\n        <item quantity=\"few\">Nie udało się zablokować działania %1$d aplikacji w tle</item>\n        <item quantity=\"many\">Nie udało się zablokować działania %1$d aplikacji w tle</item>\n        <item quantity=\"other\">Nie udało się zablokować działania %1$d aplikacji w tle</item>\n    </plurals>\n    <string name=\"deny_dangerous_app_ops\">Odmów niebezpiecznych app ops</string>\n    <string name=\"sort_by_wifi_data\">Dane Wi-Fi</string>\n    <string name=\"unknown_op\">Nieznane działanie</string>\n    <string name=\"sort_by_tracker_components\">Najpierw elementy śledzące</string>\n    <string name=\"sort_by_denied_app_ops\">Najpierw odmówione</string>\n    <string name=\"sort_by_app_ops_names\">Nazwa App op</string>\n    <string name=\"filter_apps_without_backups\">Bez kopii zapasowych</string>\n    <string name=\"uninstalled_apps\">Odinstalowane aplikacje</string>\n    <string name=\"specify_custom_name\">Własna</string>\n    <string name=\"verified_using_unreliable_hash\">Zweryfikowano za pomocą niemiarodajnego hashu</string>\n    <string name=\"working_on_adb_mode\">Praca w trybie ADB</string>\n    <string name=\"pref_enable_disable_features_msg\">Włącz lub wyłącz funkcje w App Manager.</string>\n    <string name=\"type_long_array_list\">Lista długich liczb całkowitych</string>\n    <string name=\"type_long_array\">Tablica długich liczb całkowitych</string>\n    <string name=\"type_int_array_list\">Lista liczb całkowitych</string>\n    <string name=\"type_null\">Brak wartości</string>\n    <string name=\"internal_storage\">Pamięć wewnętrzna</string>\n    <string name=\"failed_to_revoke_permission\">Nie udało się odmówić uprawnienia</string>\n    <plurals name=\"alert_failed_to_disable_trackers\">\n        <item quantity=\"one\">Nie udało się wyłączyć elementów śledzących w %1$d aplikacji</item>\n        <item quantity=\"few\">Nie udało się wyłączyć elementów śledzących w %1$d aplikacjach</item>\n        <item quantity=\"many\">Nie udało się wyłączyć elementów śledzących z %1$d aplikacjach</item>\n        <item quantity=\"other\">Nie udało się wyłączyć elementów śledzących z %1$d aplikacjach</item>\n    </plurals>\n    <string name=\"input_keystore_pass_msg\">Dotknij tutaj, aby podać hasło KeyStore</string>\n    <string name=\"splits\">Podziały</string>\n    <string name=\"source_stamp_verified\">SourceStamp zweryfikowany.</string>\n    <string name=\"allow_routine_ops\">Zezwalaj na rutynowe operacje</string>\n    <string name=\"un_apkm\">UnApkm</string>\n    <string name=\"pref_import_export_blocking_rules_msg\">Importuj/eksportuj reguły, importuj zewnętrzne reguły z Watt lub Blocker.</string>\n    <plurals name=\"no_of_times_opened\">\n        <item quantity=\"one\">%1$d raz</item>\n        <item quantity=\"few\">%1$d razy</item>\n        <item quantity=\"many\">%1$d razy</item>\n        <item quantity=\"other\">%1$d razy</item>\n    </plurals>\n    <string name=\"exodus_link\">Link εxodus</string>\n    <string name=\"input_app_ops\">Wprowadź operacje aplikacji</string>\n    <string name=\"filtered_packages\">Filtrowane pakiety</string>\n    <string name=\"input_signatures_description\">Wprowadź sygnatury ze spacjami, np. <tt>com.facebook org.app2 com.app3</tt> itp.</string>\n    <string name=\"input_signatures\">Wprowadź sygnatury</string>\n    <string name=\"lib_details\">Szczegóły biblioteki</string>\n    <string name=\"no_libs\">Brak bibliotek</string>\n    <string name=\"failed_to_fetch_package_info\">Nie można uzyskać informacji o module</string>\n    <string name=\"filter_apps_with_activities\">z aktywnościami</string>\n    <string name=\"export_icon\">Wyodrębnij ikonę</string>\n    <string name=\"no\">Nie</string>\n    <plurals name=\"no_of_components\">\n        <item quantity=\"one\">%1$d komponent</item>\n        <item quantity=\"few\">%1$d komponenty</item>\n        <item quantity=\"many\">%1$d komponenty</item>\n        <item quantity=\"other\">%1$d komponenty</item>\n    </plurals>\n    <string name=\"failed_to_deny_dangerous_perms\">Nie udało się cofnąć wszystkich niebezpiecznych uprawnień</string>\n    <plurals name=\"verified_with_warning\">\n        <item quantity=\"one\">Zweryfikowano z ostrzeżeniem %d</item>\n        <item quantity=\"few\">Zweryfikowano z ostrzeżeniami %d</item>\n        <item quantity=\"many\">Zweryfikowano z ostrzeżeniami %d</item>\n        <item quantity=\"other\">Zweryfikowano z ostrzeżeniami %d</item>\n    </plurals>\n    <plurals name=\"app_signing_signature_schemes_pl\">\n        <item quantity=\"one\">Schemat podpisu</item>\n        <item quantity=\"few\">Schematy podpisów</item>\n        <item quantity=\"many\">Schematy podpisów</item>\n        <item quantity=\"other\">Schematy podpisów</item>\n    </plurals>\n    <plurals name=\"missing_signatures\">\n        <item quantity=\"one\">%1$d brak podpisu</item>\n        <item quantity=\"few\">%1$d brak podpisów</item>\n        <item quantity=\"many\">%1$d brak podpisów</item>\n        <item quantity=\"other\">%1$d brak podpisów</item>\n    </plurals>\n    <plurals name=\"libraries\">\n        <item quantity=\"one\">%1$d biblioteka</item>\n        <item quantity=\"few\">%1$d bibliotek</item>\n        <item quantity=\"many\">%1$d bibliotek</item>\n        <item quantity=\"other\">%1$d bibliotek</item>\n    </plurals>\n    <plurals name=\"backup_exists_are_you_sure\">\n        <item quantity=\"one\">Istnieje kopia zapasowa. Czy jesteś pewien\\?</item>\n        <item quantity=\"few\">Istnieje kopia zapasowa dla więcej niż jednej aplikacji. Czy jesteś pewien\\?</item>\n        <item quantity=\"many\">Istnieje kopia zapasowa dla więcej niż jednej aplikacji. Czy jesteś pewien\\?</item>\n        <item quantity=\"other\">Istnieje kopia zapasowa dla więcej niż jednej aplikacji. Czy jesteś pewien\\?</item>\n    </plurals>\n    <plurals name=\"classes\">\n        <item quantity=\"one\">%1$d klasa</item>\n        <item quantity=\"few\">%1$d klasy</item>\n        <item quantity=\"many\">%1$d klasy</item>\n        <item quantity=\"other\">%1$d klasy</item>\n    </plurals>\n    <string name=\"restore\">Przywróć</string>\n    <string name=\"backup\">Kopia zapasowa</string>\n    <string name=\"external_data\">Dane zewnętrzne</string>\n    <string name=\"features\">Funkcje</string>\n    <string name=\"package_name_is_installed_successfully\">Zainstalowano <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g></string>\n    <string name=\"termux\">Termux</string>\n    <string name=\"deny_app_ops_description\">Określ sposób działania aplikacji określony przez stałe wartości, np. <tt>63</tt> lub <tt>RUN_IN_BACKGROUND</tt></string>\n    <string name=\"external_apk_no_app_op\">Zewnętrzny APK nie wykonuje żadnych operacji na aplikacjach</string>\n    <string name=\"failed_to_deny_dangerous_app_ops\">Nie udało się cofnąć wszystkich niebezpiecznych operacji tej aplikacji</string>\n    <string name=\"failed_to_reset_app_ops\">Nie udało się zresetować ustawień aplikacji</string>\n    <string name=\"pref_import_blocker_msg\">Importuj reguły filtrowania z Blockera, z których każdy zawiera reguły dla pojedynczego modułu.</string>\n    <string name=\"pref_import_watt_msg\">Importuj reguły blokowania z Watt, każdy plik zawierający reguły dla pojedyńczego pakietu o nazwie <tt>packagename.xml</tt> itp.</string>\n    <string name=\"pref_import_msg\">Importuj wcześniej wyeksportowane reguły blokowania z App Manager.</string>\n    <string name=\"pref_export_msg\">Eksportuj reguły blokowania skonfigurowane w App Manager do pamięci zewnętrznej.</string>\n    <string name=\"touchscreen\">Ekran dotykowy</string>\n    <string name=\"reject_time\">Czas odrzucenia</string>\n    <string name=\"accept_time\">Czas zatwierdzenia</string>\n    <string name=\"toggle_kill_for_system_apps\">Przełącz zamykanie aplikacji systemowych</string>\n    <string name=\"user_with_id\">Użytkownik: <xliff:g id=\"user_id\" example=\"0\">%1$d</xliff:g></string>\n    <string name=\"apk_updater\">APK Updater</string>\n    <string name=\"sort_by_times_opened\">Ilości otwarć</string>\n    <string name=\"sort_by_screen_time\">Czas ekranowy</string>\n    <string name=\"external_multiple_data_dir\">Zewnętrzny katalog danych <xliff:g id=\"dir_no\" example=\"1\">%1$d</xliff:g></string>\n    <string name=\"pref_global_blocking_enabled_msg\">Umożliwia blokowanie dowolnego komponentu dowolnej aplikacji bez konieczności blokowania aplikacji wprost.</string>\n    <string name=\"rules_not_applied\">Reguły nie zostały wprowadzone</string>\n    <string name=\"failed_to_disable_op\">Nie udało się wyłączyć OP zażądanej aplikacji</string>\n    <plurals name=\"other_trackers_and_classes\">\n        <item quantity=\"one\"><xliff:g id=\"tracker_no\" example=\"8\">%1$d</xliff:g> element śledzący z <xliff:g id=\"class_no\" example=\"50\">%2$d</xliff:g> klasami</item>\n        <item quantity=\"few\"><xliff:g id=\"tracker_no\" example=\"8\">%1$d</xliff:g> elementy śledzące z <xliff:g id=\"class_no\" example=\"50\">%2$d</xliff:g> klasami</item>\n        <item quantity=\"many\"><xliff:g id=\"tracker_no\" example=\"8\">%1$d</xliff:g> elementów śledzących z <xliff:g id=\"class_no\" example=\"50\">%2$d</xliff:g> klasami</item>\n        <item quantity=\"other\"><xliff:g id=\"tracker_no\" example=\"8\">%1$d</xliff:g> elementów śledzących z <xliff:g id=\"class_no\" example=\"50\">%2$d</xliff:g> klasami</item>\n    </plurals>\n    <plurals name=\"two_trackers_and_classes\">\n        <item quantity=\"one\">2 elementy śledzące z <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g> klasami</item>\n        <item quantity=\"few\">2 elementy śledzące z <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g> klasami</item>\n        <item quantity=\"many\">2 elementy śledzące z <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g> klasami</item>\n        <item quantity=\"other\">2 elementy śledzące z <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g> klasami</item>\n    </plurals>\n    <plurals name=\"tracker_and_classes\">\n        <item quantity=\"one\">1 element śledzący z <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g> klasą</item>\n        <item quantity=\"few\">1 element śledzący z <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g> klasami</item>\n        <item quantity=\"many\">1 element śledzący z <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g> klasami</item>\n        <item quantity=\"other\">1 element śledzący z <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g> klasami</item>\n    </plurals>\n    <string name=\"starting_activity\">Rozpoczynanie aktywności: <xliff:g id=\"activity_name\" example=\".main.MainActivity\">%1$s</xliff:g></string>\n    <string name=\"keep_data_and_app_signing_signatures\">Zachowaj dane i sygnatury</string>\n    <string name=\"this_action_cannot_be_undone\">Ta operacja nie może być cofnięta.</string>\n    <string name=\"input_keystore_alias_pass_description\">Wprowadź hasło dla aliasu <b>%1$s</b>. Możesz pozostawić to pole puste, jeśli hasło jest takie samo jak hasło KeyStore.</string>\n    <string name=\"input_keystore_alias_pass\">Hasło dla aliasu <b>%1$s</b></string>\n    <string name=\"tap_to_see_details\">Naciśnij, aby zobaczyć szczegóły</string>\n    <string name=\"backup_apps_with_changes\">Stwórz kopie zapasowe aplikacji ze zmianami</string>\n    <string name=\"isolated\">Odizolowana</string>\n    <string name=\"reverse\">Odwrócona</string>\n    <string name=\"sort_by_backup\">Najpierw z wykonanymi kopiami</string>\n    <string name=\"pref_backup_flags_msg\">Dodanie ustawień wstępnych dla opcji tworzenia kopii zapasowych eliminuje konieczność wybierania flag przy każdym tworzeniu kopii zapasowej/przywracaniu danych.</string>\n    <string name=\"input_keystore_pass\">Wprowadź hasło KeyStore</string>\n    <string name=\"send_crash_report\">Wyślij raport o awarii</string>\n    <string name=\"tap_to_submit_crash_report\">Dotknij, aby przesłać raport o awarii.</string>\n    <string name=\"filter_running_apps\">Uruchomione aplikacje</string>\n    <string name=\"no_matching_package_found\">Nie znaleziono pasujących modułów</string>\n    <plurals name=\"alert_failed_to_set_app_ops\">\n        <item quantity=\"one\">Błąd w ustawieniu operacji dla %1$d aplikacji</item>\n        <item quantity=\"few\">Błąd w ustawieniu operacji dla %1$d aplikacji</item>\n        <item quantity=\"many\">Błąd w ustawieniu operacji dla %1$d aplikacji</item>\n        <item quantity=\"other\">Błąd w ustawieniu operacji dla %1$d aplikacji</item>\n    </plurals>\n    <string name=\"internal_data\">Dane wewnętrzne</string>\n    <string name=\"failed_to_parse_some_numbers\">Nie można przetworzyć niektórych liczb</string>\n    <string name=\"input_app_ops_description_profile\">Wprowadź nazwy operacji aplikacji i/lub stałe ze spacjami, np. <tt>WAKE_LOCK 63 72 CAMERA</tt> itp. Użyj <tt>*</tt>, aby zastosować zmiany wszystkich skonfigurowanych operacji aplikacji.</string>\n    <string name=\"input_app_ops_description\">Wprowadź nazwy operacji aplikacji i/lub stałe ze spacjami, np. <tt>WAKE_LOCK 63 72 CAMERA</tt> itp.</string>\n    <string name=\"battery_mode\">Tryb wykorzystania baterii</string>\n    <string name=\"app_signing_signatures\">Sygnatury</string>\n    <string name=\"soft_input\">Tryb delikatnego wprowadzenia</string>\n    <string name=\"authority\">Autorytet</string>\n    <string name=\"community_links\"><a href=\"https://matrix.to/#/#appmanager:matrix.org\">Matrix</a> • <a href=\"https://t.me/AppManagerChannel\">Telegram</a> • <a href=\"https://x.com/AppManagerNews\">Twitter/X</a> • <a href=\"https://floss.social/@appmanager\">Mastodon</a></string>\n    <string name=\"community\">Społeczność</string>\n    <string name=\"source_code_links\"><a href=\"https://github.com/MuntashirAkon/AppManager\">GitHub</a> • <a href=\"https://gitlab.com/muntashir/AppManager\">GitLab</a> • <a href=\"https://0xacab.org/muntashir/AppManager\">Riseup</a> • <a href=\"https://codeberg.org/muntashir/AppManager\">Codeberg</a></string>\n    <string name=\"subject\">Temat</string>\n    <string name=\"state_foreground\">Procesy w tle</string>\n    <string name=\"state_locked_memory\">Pamięć zablokowana</string>\n    <string name=\"state_device_io\">I/O urządzenia</string>\n    <string name=\"touchscreen_finger\">Palec</string>\n    <string name=\"touchscreen_no_touch\">Blokada dotyku</string>\n    <string name=\"navigation_wheel\">Nawigacja</string>\n    <string name=\"orientation_user_portrait\">Orientacja pionowa użytkownika</string>\n    <string name=\"orientation_user_landscape\">Orientacja pozioma użytkownika</string>\n    <string name=\"orientation_sensor_portrait\">Orientacja pionowa ekranu</string>\n    <string name=\"orientation_sensor_landscape\">Orientacja pozioma ekranu</string>\n    <string name=\"orientation_full_user\">Pełny dostęp</string>\n    <string name=\"orientation_full_sensor\">Wszystkie czujniki</string>\n    <string name=\"launch_mode_multiple\">Wiele</string>\n    <string name=\"package_installer\">Instalator pakietów</string>\n    <string name=\"paired_successfully\">Sparowany.</string>\n    <string name=\"pid\">Identyfikator procesu</string>\n    <plurals name=\"pref_thread_count_msg\">\n        <item quantity=\"one\">Wykonuj co najwyżej %1$d operację równolegle</item>\n        <item quantity=\"few\">Wykonuj co najwyżej %1$d operacje równolegle</item>\n        <item quantity=\"many\">Wykonuj co najwyżej %1$d operacji równolegle</item>\n        <item quantity=\"other\">Wykonuj co najwyżej %1$d operacji równolegle</item>\n    </plurals>\n    <string name=\"pref_thread_count_hint\">Wartość musi być pomiędzy 0 a %1$d gdzie 0 znaczy <i> maksymalnej liczby operacji w danym czasie</i>.</string>\n    <string name=\"pref_thread_count\">Wykonanie równoległe</string>\n    <string name=\"type_uri_array_list\">Lista URIs</string>\n    <string name=\"type_uri_array\">Tablica URIs</string>\n    <string name=\"pref_always_on_background_msg\">Zawsze instaluj aplikacje w tle i wyświetl powiadomienia po skończeniu.</string>\n    <string name=\"pref_always_on_background\">Instaluj w tle</string>\n    <string name=\"pref_block_trackers_msg\">Zablokuj komponenty śledzące po zainstalowaniu aplikacji używając aplikacji App Manager.</string>\n    <string name=\"next\">Następny</string>\n    <string name=\"installer_app_installed\">Aplikacja zainstalowana</string>\n    <string name=\"staging_apk_files\">Inscenizacja…</string>\n    <string name=\"background\">Tło</string>\n    <string name=\"type_int_array\">Tablica liczb całkowitych</string>\n    <string name=\"back_up\">Wykonaj kopię zapasową</string>\n    <string name=\"restore_latest_msg\">Przywróć już zainstalowane aplikacje których kody wersji są wyższe niż zainstalowany kod wersji.</string>\n    <string name=\"enforcing\">Wymuszanie</string>\n    <string name=\"backup_extras\">Dodatki</string>\n    <string name=\"board_name\">Płyta główna</string>\n    <string name=\"extras\">Dodatki</string>\n    <string name=\"filter_apps_with_splits\">Z podziałami</string>\n    <string name=\"input_keystore_pass_description\">Wprowadź hasło KeyStore. Jeżeli widzisz to po raz pierwszy, użyj generatora hasła i zapisz je w bezpiecznym miejscu zanim wprowadzisz je tutaj.</string>\n    <string name=\"copy\">Kopiuj</string>\n    <string name=\"launch_mode_single_instance\">Pojedyncza instancja</string>\n    <string name=\"batch_ops\">Operacje wsadowe</string>\n    <string name=\"failed_to_uninstall_app\">Odinstalowanie nie powiodło się</string>\n    <string name=\"hardware\">Sprzęt</string>\n    <string name=\"permissive\">Dozwolony</string>\n    <string name=\"activity_result\">Wynik działań</string>\n    <string name=\"matching_activities\">Dopasowywanie działań</string>\n    <string name=\"am_crashed\">App Manager przestał działać</string>\n    <string name=\"backup_skip_signature_checks_description\">Przywróć kopie zapasowe, które albo nie przejdą weryfikacji sumy kontrolnej, albo mają inne podpisy APK niż ich poprzednie kopie zapasowe.</string>\n    <string name=\"no_app_ops_permission\">Brak uprawnień do wyświetlania operacji aplikacji</string>\n    <string name=\"input_keystore_alias_pass_msg\">Kliknij tutaj aby wprowadzić hasło dla %1$s</string>\n    <string name=\"view_missing_signatures\">Dotknij, aby wyświetlić lub wysłać podpisy, które nie znajdują się jeszcze w bazie danych bibliotek App Managera.</string>\n    <string name=\"scanner\">Skaner</string>\n    <string name=\"sys_config\">Konfiguracja systemu</string>\n    <string name=\"app_signing_install_without_data_loss\">Jeśli wyłączono weryfikację podpisu, można użyć opcji <b>Tylko zainstaluj</b>, aby zainstalować aplikację bez utraty danych.</string>\n    <string name=\"non_critical_exts\">Rozszerzenia niekrytyczne</string>\n    <string name=\"critical_exts\">Rozszerzenia krytyczne</string>\n    <string name=\"dsa_affine_y\">Współrzędna afiniczna y</string>\n    <string name=\"dsa_affine_x\">Współrzędna afiniczna x</string>\n    <string name=\"rsa_modulus\">Moduł</string>\n    <string name=\"systemless_app\">Aplikacja bezsystemowa</string>\n    <string name=\"state_waking\">Wzbudzanie</string>\n    <string name=\"state_wake_kill\">Wzbudź zabij</string>\n    <string name=\"state_session_leader\">Lider sesji</string>\n    <string name=\"state_parked\">Zaparkowany</string>\n    <string name=\"state_dead\">Martwy</string>\n    <string name=\"state_trace_stop\">Zatrzymaj ślad</string>\n    <string name=\"keyboard_12_keys\">12 klawiszowa</string>\n    <string name=\"launch_mode_single_top\">Pojedynczy główny</string>\n    <string name=\"locale_split_for_base_apk\"><xliff:g id=\"split_name\" example=\"English\">%1$s</xliff:g> miejsce dla bazowego APK</string>\n    <string name=\"locale_split_for_feature\"><xliff:g id=\"split_name\" example=\"English\">%1$s</xliff:g> miejsce dla funkcji <xliff:g id=\"feature_name\" example=\"Visualizer\">%2$s</xliff:g></string>\n    <string name=\"density_split_for_base_apk\"><xliff:g id=\"split_name\" example=\"xxdpi\">%1$s</xliff:g> (<xliff:g id=\"dpi_no\" example=\"480\">%2$d</xliff:g> DPI) zasoby dla bazowego APK</string>\n    <string name=\"abi_split_for_base_apk\"><xliff:g id=\"split_name\" example=\"arm64_v8a\">%1$s</xliff:g> kod dla bazowego APK</string>\n    <string name=\"density_split_for_feature\"><xliff:g id=\"split_name\" example=\"xxdpi\">%1$s</xliff:g> (<xliff:g id=\"dpi_no\" example=\"480\">%2$d</xliff:g> DPI) zasoby dla funkcji <xliff:g id=\"feature_name\" example=\"Visualizer\">%3$s</xliff:g></string>\n    <plurals name=\"no_of_splits\">\n        <item quantity=\"one\">%1$d podział</item>\n        <item quantity=\"few\">%1$d podziały</item>\n        <item quantity=\"many\">%1$d podziałów</item>\n        <item quantity=\"other\">%1$d podziałów</item>\n    </plurals>\n    <string name=\"second_degree_tracker_note\">² prefiks wskazuje, że trackery znajdują się w <a href=\"https://etip.exodus-privacy.eu.org/\">Lista rezerwowa ETIP </a> np. to, czy są to rzeczywiste urządzenia śledzące, jest nadal badane.</string>\n    <string name=\"orientation_behind\">Z tyłu</string>\n    <string name=\"running_services_logcat_hint\">Dotknij elementu, aby otworzyć log viewer z odpowiednim identyfikatorem procesu jako domyślnym filtrem.</string>\n    <string name=\"trim_caches_in_all_apps_description\">Usuwa pliki pamięci podręcznej ze wszystkich aplikacji, również w systemie Android</string>\n    <string name=\"trim_caches_in_all_apps\">Przytnij pamięć podręczną we wszystkich aplikacjach</string>\n    <string name=\"user_root\">Użyj roota</string>\n    <string name=\"paste\">Wklej</string>\n    <string name=\"set_package_name_first\">Najpierw ustaw nazwę pakietu!</string>\n    <string name=\"identifier\">Identyfikator</string>\n    <string name=\"adb_pair\">Paruj</string>\n    <string name=\"invalid_password\">Nieprawidłowe hasło, spróbuj ponownie.</string>\n    <string name=\"keystore_pass_cannot_be_empty\">Hasło KeyStore nie może być puste.</string>\n    <string name=\"keystore_password_info\">Poniżej znajduje się hasło do KeyStore. Przechowuj je w bezpiecznym miejscu, jeżeli zamierzasz wykonać kopię zapasową/przywrócić KeyStore w App Manager. <b>Ten komunikat nie będzie wyświetlany ponownie.</b></string>\n    <string name=\"files\">Pliki</string>\n    <string name=\"storage\">Pamięć</string>\n    <string name=\"backup_volume_dialog_description\">Woluminy z prefiksem <tt>/tree</tt> to foldery wybrane za pomocą Storage Access Framework (SAF). Oprócz tych folderów domyślnym katalogiem App Managera jest podfolder o nazwie <tt>AppManager</tt>.</string>\n    <string name=\"notice_saf\">W przeciwieństwie do woluminów, wybrany katalog będzie używany do przechowywania wszystkich plików związanych z App Manager, w tym zapisanych pakietów APK i kopii zapasowych. Storage Access Framework (SAF) jest bardzo powolny, dlatego należy używać tej opcji tylko wtedy, gdy nie można użyć innych.</string>\n    <string name=\"notice\">Notyfikacja</string>\n    <string name=\"error_with_details\">Błąd: %s</string>\n    <string name=\"saved_filters\">Zapisane filtry</string>\n    <string name=\"permission_flags\">Flagi uprawnień</string>\n    <string name=\"pref_selected_users_msg\">Ogranicz App Manager do pracy tylko z wybranymi użytkownikami.</string>\n    <string name=\"pref_selected_users\">Wybrani użytkownicy</string>\n    <string name=\"added_to_queue\">Dodano do kolejki</string>\n    <string name=\"minimum_version\">Minimalna wersja: %d</string>\n    <string name=\"help_uses_permissions_tab\">Dotknij elementu, aby go <b>zatwierdzić</b> lub <b>unieważnić</b>. Tylko <b>niebezpieczne</b> i <b>rozwojowe</b> uprawnienia mogą zostać przyznane lub cofnięte.</string>\n    <string name=\"help_permissions_tab\">Te uprawnienia są zdefiniowane przez tę aplikację i nie można ich cofnąć.</string>\n    <string name=\"help_app_ops_tab\">Dotknij elementu, aby <b>zezwolić</b> lub <b>zignorować</b> go. Długo przytrzymaj element, aby zobaczyć inne obsługiwane tryby.</string>\n    <string name=\"failed_to_prevent_background_run\">Nie można zapobiec %1$s działania w tle</string>\n    <string name=\"unknown_net_policy\">Nieznane reguły sieciowe (%1$s - %2$X)</string>\n    <string name=\"port_number_invalid\">Nieprawidłowy numer portu.</string>\n    <string name=\"port_number_empty\">Numer portu jest pusty.</string>\n    <string name=\"adb_connect_port_number_description\">Numer portu znajduje się w sekcji <b>adres IP &amp; port</b> tuż pod sekcją <b>Nazwa urządzenia</b>.</string>\n    <string name=\"port_number\">Port</string>\n    <string name=\"adb_connect\">Połącz</string>\n    <string name=\"wireless_debugging\">Bezprzewodowe debugowanie</string>\n    <string name=\"netpolicy_disable_network_access\">Wyłącz dostęp do sieci</string>\n    <string name=\"netpolicy_reject_vpn_data\">Odrzuć dane VPN</string>\n    <string name=\"netpolicy_reject_wifi_data\">Odrzuć dane Wi-Fi</string>\n    <string name=\"netpolicy_reject_cellular_data\">Odrzuć dane komórkowe</string>\n    <string name=\"netpolicy_allow_background_data\">Zezwalaj na dane w tle, gdy Oszczędzanie danych jest włączone</string>\n    <string name=\"netpolicy_reject_background_data\">Odrzuć dane w tle</string>\n    <string name=\"no_changes\">Bez zmian</string>\n    <string name=\"pref_display_changes_msg\">Wyświetla zmiany w wersji, elementy śledzące, komponenty, uprawnienia, sygnatury, SDK, itp. w sposób kontrolowany przez wersję.</string>\n    <string name=\"pref_display_changes\">Wyświetl zmiany</string>\n    <string name=\"hidden\">Ukryty</string>\n    <string name=\"suspended\">Zawieszono</string>\n    <plurals name=\"alert_failed_to_import_backups\">\n        <item quantity=\"one\">Nie można zaimportować %1$d kopii zapasowej</item>\n        <item quantity=\"few\">Nie można zaimportować %1$d kopii zapasowych</item>\n        <item quantity=\"many\">Nie można zaimportować %1$d kopii zapasowych</item>\n        <item quantity=\"other\">Nie można zaimportować %1$d kopii zapasowych</item>\n    </plurals>\n    <string name=\"orientation_right_to_left\">Od prawej do lewej</string>\n    <string name=\"orientation_left_to_right\">Od lewej do prawej</string>\n    <string name=\"orientation_follow_locale\">Śledź lokalizację</string>\n    <string name=\"saf\">SAF</string>\n    <string name=\"pref_rules_msg\">Natychmiastowe blokowanie: importowania/eksportowania/usuwania reguł, itp.</string>\n    <string name=\"failed\">Nie powiodło się</string>\n    <string name=\"confirm_import_keystore\">Czy na pewno chcesz zastąpić istniejący KeyStore\\? Tej czynności nie można cofnąć.</string>\n    <string name=\"import_keystore\">Importuj KeyStore</string>\n    <string name=\"pref_import_export_keystore_msg\">Importuj/eksportuj Bouncy Castle KeyStore (BKS) wewnętrznie używany przez App Manager.</string>\n    <string name=\"pref_import_export_keystore\">Importuj/eksportuj KeyStore</string>\n    <string name=\"latest_backup\">Najnowsza kopia zapasowa</string>\n    <string name=\"pgp_aes_rsa_encrypted\">%1$s zaszyfrowano</string>\n    <string name=\"gz_bz2_compressed\">%1$s skompresowano</string>\n    <string name=\"no_encryption\">Brak szyfrowania</string>\n    <string name=\"base_backup\">Podstawowa kopia zapasowa</string>\n    <string name=\"trackers_unblocked_successfully\">Elementy śledzące są teraz odblokowane</string>\n    <string name=\"trackers_blocked_successfully\">Elementy śledzące są teraz zablokowane</string>\n    <string name=\"failed_to_unblock_trackers\">Nie udało się odblokować elementów śledzących</string>\n    <string name=\"failed_to_block_trackers\">Nie udało się zablokować elementów śledzących</string>\n    <string name=\"profile_save_apk_msg\">Zapisuje pliki APK w <tt>AppManager/apks</tt></string>\n    <string name=\"save_apk\">Zapisz APK</string>\n    <string name=\"running_services\">Usługi uruchomione</string>\n    <string name=\"view_logs\">Wyświetl dzienniki</string>\n    <string name=\"share_log\">Udostępnij</string>\n    <string name=\"text_include_dmesg\">Dołącz dziennik jądra</string>\n    <string name=\"omit_sensitive_info_summary\">Pomiń poufne informacje, takie jak adresy URL, numery telefonów lub e-maile.</string>\n    <string name=\"omit_sensitive_info\">Pomiń poufne informacje</string>\n    <string name=\"undo\">Cofnij</string>\n    <string name=\"pause_unpause\">Odtwórz/Wstrzymaj</string>\n    <string name=\"collapse_all\">Zwiń wszystko</string>\n    <string name=\"expand_all\">Rozwiń wszystko</string>\n    <string name=\"file\">Plik</string>\n    <string name=\"widget_start_recording\">Rejestruj\n\\nDziennik</string>\n    <string name=\"widget_recording_in_progress\">Rejestrowanie…</string>\n    <string name=\"unable_to_save_log\">Nie można zapisać dziennika. Czy podano poprawną nazwę pliku\\?</string>\n    <plurals name=\"toast_log_truncated\">\n        <item quantity=\"one\">Dziennik jest zbyt duży, pokazuje ostatnią %d linię.</item>\n        <item quantity=\"few\">Dziennik jest zbyt duży, pokazuje ostatnie %d linie.</item>\n        <item quantity=\"many\">Dziennik jest zbyt duży, pokazuje ostatnich %d linii.</item>\n        <item quantity=\"other\">Dziennik jest zbyt duży, pokazuje ostatnich %d linii.</item>\n    </plurals>\n    <string name=\"toast_invalid_selection\">Nieprawidłowy wybór. Spróbuj ponownie.</string>\n    <string name=\"toast_invalid_level\">Nieprawidłowa nazwa poziomu: %s</string>\n    <string name=\"pref_display_limit_hint\" tools:ignore=\"PluralsCandidate\">Wprowadź prawidłową liczbę od %1$d do %2$d.</string>\n    <string name=\"text_include_device_info\">Dołącz informacje o urządzeniu</string>\n    <string name=\"text_filter_text\">Filtruj tekst</string>\n    <string name=\"text_filter_ellipsis\">Filtr…</string>\n    <string name=\"subject_log_report\">Raport dziennika</string>\n    <string name=\"start_recording_log\">Rejestruj</string>\n    <string name=\"settings\">Ustawienia</string>\n    <string name=\"send_log_title\">Wyślij dziennik</string>\n    <string name=\"save_log\">Zapisz dziennik</string>\n    <string name=\"save_as\">Zapisz jako…</string>\n    <string name=\"record_log\">Dziennik rekordów</string>\n    <string name=\"pref_show_timestamp_title\">Pokaż Pid i sygnaturę czasu</string>\n    <string name=\"pref_show_timestamp_summary\">Pokaż identyfikator procesu i sygnaturę czasową po rozwinięciu.</string>\n    <string name=\"pref_log_write_period_title\">Okres zapisu</string>\n    <string name=\"pref_log_write_period_summary\" tools:ignore=\"PluralsCandidate\">Podczas rejestrowania zapisuj na karcie SD każdą %1$d linię.</string>\n    <string name=\"pref_log_line_period_error\">Proszę wpisać liczbę całkowitą z przedziału od 1 do 1000.</string>\n    <string name=\"pref_expanded_by_default_title\">Domyślne rozwijaj</string>\n    <string name=\"pref_expanded_by_default_summary\">Domyślnie pokazuj pełny tekst dziennika.</string>\n    <string name=\"pref_filter_pattern_title\">Odfiltruj znaczniki</string>\n    <string name=\"pref_filter_pattern_summary\">Odfiltruj wybrane znaczniki z dzienników.</string>\n    <string name=\"pref_display_limit_title\">Limit wyświetlania dziennika</string>\n    <string name=\"pref_display_limit_summary\" tools:ignore=\"PluralsCandidate\">Pokaż tylko ostatnie dzienniki %1$d, aby uniknąć błędów braku pamięci.</string>\n    <string name=\"pref_default_log_level_title\">Domyślny poziom dziennika</string>\n    <string name=\"pref_default_log_level_summary\">Poziom dziennika podczas uruchamiania, otwierania plików i rejestrowania.</string>\n    <string name=\"pref_cat_configuration\">Konfiguracja</string>\n    <string name=\"pref_cat_appearance\">Wygląd</string>\n    <string name=\"pref_cat_advanced\">Zaawansowane</string>\n    <string name=\"pref_buffer_title\">Bufor(y) dziennika</string>\n    <string name=\"open\">Otwórz</string>\n    <string name=\"notification_title\">Rejestrowanie dziennika w toku</string>\n    <string name=\"notification_ticker\">Rozpoczęto rejestrowanie dziennika</string>\n    <string name=\"notification_subtext\">Dotknij, aby zatrzymać rejestrowanie</string>\n    <string name=\"no_saved_logs\">Brak zapisanych dzienników.</string>\n    <string name=\"manage_saved_logs\">Zarządzaj zapisanymi dziennikami</string>\n    <string name=\"log_saved\">Zapisano dziennik.</string>\n    <string name=\"log_recording_started\">Rozpoczęto rejestrowanie dziennika.</string>\n    <string name=\"log_level\">Poziom dziennika</string>\n    <string name=\"log_cleared\">Dzienniki wyczyszczone</string>\n    <string name=\"filter_choice_tag\">Znacznik</string>\n    <string name=\"filter_choice_pid\">PID</string>\n    <string name=\"filter_choice\">Szukaj według</string>\n    <string name=\"enter_good_filename\">Podaj poprawną nazwę pliku.</string>\n    <string name=\"enter_filename\">Wpisz nazwę pliku</string>\n    <string name=\"dialog_compiling_log\">Kompilacja dziennika…</string>\n    <string name=\"delete_saved_log\">Usuń zapisane dzienniki</string>\n    <string name=\"copy_to_clipboard\">Skopuj do schowka</string>\n    <plurals name=\"file_deletion_confirmation\">\n        <item quantity=\"one\">%d plik zostanie usunięty</item>\n        <item quantity=\"few\">%d plik zostaną usunięte</item>\n        <item quantity=\"many\">%d plik zostanie usuniętych</item>\n        <item quantity=\"other\">%d plik zostanie usuniętych</item>\n    </plurals>\n    <string name=\"add_filter_ellipsis\">Dodaj filtr…</string>\n    <string name=\"add_filter\">Dodaj filtr</string>\n    <string name=\"log_level_fatal\">Błąd krytyczny</string>\n    <string name=\"log_level_warn\">Ostrzeżenie</string>\n    <string name=\"log_level_verbose\">Drobiazgowy</string>\n    <string name=\"log_level_info\">Informacje</string>\n    <string name=\"log_level_error\">Bład</string>\n    <string name=\"log_level_debug\">Debugowanie</string>\n    <string name=\"filename\">Nazwa pliku</string>\n    <string name=\"restart_log_viewer_to_see_changes\">Uruchom ponownie okno log viewer, aby zobaczyć zmiany.</string>\n    <string name=\"pref_log_viewer_msg\">Skonfiguruj sposób wyświetlania dzienników.</string>\n    <string name=\"log_viewer\">Przeglądarka dziennika</string>\n    <string name=\"import_from_tb\">Importuj z Titanium Backup</string>\n    <string name=\"import_from_oab\">Importuj z OAndBackup</string>\n    <string name=\"pref_import_backups_msg\">Importuj kopie zapasowe z programów OAndBackup, Swift Backup (3.0-3.2) lub Titanium Backup.</string>\n    <string name=\"pref_import_backups\">Importuj kopie zapasowe</string>\n    <string name=\"pref_installer_msg\">Skonfiguruj zachowanie instalatora aplikacji.</string>\n    <string name=\"expiry_date_cannot_be_empty\">Data ważności nie może być pusta.</string>\n    <string name=\"signing_key\">Klucz podpisujący</string>\n    <string name=\"failed_to_read_keystore\">Nie można odczytać KeyStore.</string>\n    <string name=\"alias_pass\">Hasło aliasu</string>\n    <string name=\"choose_an_alias\">Wybierz alias</string>\n    <string name=\"found_no_alias_in_keystore\">Nie znaleziono aliasu w KeyStore!</string>\n    <string name=\"pkcs12_keystore\">PKCS #12 KeyStore (P12)</string>\n    <string name=\"keystore_pass\">Hasło KeyStore</string>\n    <string name=\"bouncy_castle_keystore\">Bouncy Castle KeyStore (BKS)</string>\n    <string name=\"java_keystore\">Java KeyStore (JKS)</string>\n    <string name=\"keystore_file\">Plik KeyStore</string>\n    <string name=\"failed_to_initialize_key_store\">Nie można zainicjować keystore App Managera.</string>\n    <string name=\"new_alias_password\">Nowe hasło aliasu</string>\n    <string name=\"import_key\">Importuj klucz</string>\n    <string name=\"pem_file\">Plik PEM</string>\n    <string name=\"pk8_file\">Plik PKCS #8 (PK8)</string>\n    <string name=\"pem_and_pk8\">PEM i PKCS #8 (PK8)</string>\n    <string name=\"country_name\" tools:ignore=\"TypographyOther\">Nazwa kraju (C)</string>\n    <string name=\"state_name\">Nazwa stanu (ST)</string>\n    <string name=\"locality_name\">Miejscowość (miasto) nazwa (L)</string>\n    <string name=\"organization_name\">Nazwa organizacji (O)</string>\n    <string name=\"organization_unit\">Jednostka organizacyjna (OU)</string>\n    <string name=\"common_name\">Nazwa zwyczajowa (CN)</string>\n    <string name=\"input_key_password\">Hasło klucza</string>\n    <string name=\"failed_to_load_key\">Nie można załadować klucza.</string>\n    <string name=\"key_not_set\">Nie ustawiono.</string>\n    <string name=\"use_default\">Użyj domyślnego</string>\n    <string name=\"invalid_rsa_key_size\">Nieprawidłowy rozmiar klucza dla szyfrowania RSA. Rozmiar klucza może wynosić 1024, 2048 lub 4096 bitów.</string>\n    <string name=\"crypto_key_size\">Rozmiar klucza</string>\n    <string name=\"invalid_aes_key_size\">Nieprawidłowy rozmiar klucza dla szyfrowania AES. Rozmiar klucza może wynosić 128 lub 256 bitów.</string>\n    <string name=\"failed_to_save_key\">Nie można zapisać klucza.</string>\n    <string name=\"generate_key\">Wygeneruj</string>\n    <string name=\"input_key\">Klucz wejściowy (w systemie szesnastkowym)</string>\n    <string name=\"installer_app_message\">Zaznacz <b>Wybierz</b>, aby wybrać spośród zainstalowanych aplikacji lub zaznacz <b>Własny</b>, aby określić własną nazwę pakietu.</string>\n    <string name=\"net_policy\">Reguły sieciowe</string>\n    <string name=\"has_net_policy\">Polityka netto</string>\n    <string name=\"backup_volume\">Miejsce zapisu</string>\n    <string name=\"failed_to_disable_magisk_hide\">Nie można wyłączyć MagiskHide</string>\n    <string name=\"disable_background_run_description\">Ustawia tryb <i>Ignoruj</i> dla następujących operacji aplikacji: <tt>RUN_IN_BACKGROUND</tt> (z Androida 7.0) i <tt>RUN_ANY_IN_BACKGROUND</tt> (z Androida 9).</string>\n    <string name=\"density\">Gęstość</string>\n    <plurals name=\"usage_minutes\">\n        <item quantity=\"one\">%1$d min.</item>\n        <item quantity=\"few\">%1$d min.</item>\n        <item quantity=\"many\">%1$d min.</item>\n        <item quantity=\"other\">%1$d min.</item>\n    </plurals>\n    <plurals name=\"usage_seconds\">\n        <item quantity=\"one\">%1$d sek.</item>\n        <item quantity=\"few\">%1$d sek.</item>\n        <item quantity=\"many\">%1$d sek.</item>\n        <item quantity=\"other\">%1$d sek.</item>\n    </plurals>\n    <string name=\"java\">Java</string>\n    <string name=\"smali\">Smali</string>\n    <string name=\"import_from_sb\">Importuj z Swift Backup 3.0 – 3.2</string>\n    <string name=\"pref_import_backups_hint\">Wybierz katalog zawierający pliki kopii zapasowych (Swift Backup/Titanium Backup) lub katalogi (OAndBackup)</string>\n    <string name=\"extract\">Wyodrębnij</string>\n    <string name=\"replace\">Zastąp</string>\n    <string name=\"rename\">Zmień nazwę</string>\n    <string name=\"intent_firewall_and_disable\">IFW + wyłącz</string>\n    <string name=\"intent_firewall\">IFW</string>\n    <string name=\"pref_default_blocking_method\">Domyślna metoda blokowania</string>\n    <string name=\"authenticating\">Uwierzytelnianie…</string>\n    <string name=\"toggle_internet\">Użyj internetu</string>\n    <string name=\"search_type_suffix\">Przyrostek</string>\n    <string name=\"search_type_regular_expressions\">Regex</string>\n    <string name=\"vt_success\">VirusTotal: %1$d/%2$d</string>\n    <string name=\"pref_default_blocking_method_description\">Metoda domyślnie stosowana w miejscach, w których nie ma możliwości wybrania metody blokowania.\n\\n<b>Uwaga:</b> \\\"IFW\\\" nie działa z dostawcami, zamiast tego używane jest \\\"wyłączono\\\".</string>\n    <string name=\"search_type_contains\">Zawiera</string>\n    <string name=\"pref_intent_firewall_and_disable_description\">Blokowanie składników za pomocą zapory sieciowej oraz ich wyłączanie. Metoda zalecana dla użytkowników z uprawnieniami roota.</string>\n    <string name=\"pref_intent_firewall_description\">Blokuj komponenty tylko za pomocą umyślnej zapory sieciowej. Nie jest to zalecane, ponieważ niektóre aplikacje systemowe mogą omijać zapory.</string>\n    <string name=\"pref_disable_description\">Wyłącz tylko komponenty. Metoda niezalecana dla użytkowników z rootem, ponieważ aplikacje mogą ją obejść. W trybach ADB za pomocą tej metody można wyłączyć tylko aplikacje testowe.</string>\n    <string name=\"search_type_prefix\">Przedrostek</string>\n    <string name=\"vt_checking\">VirusTotal: Sprawdzanie…</string>\n    <string name=\"vt_uploading\">VirusTotal: Przesyłanie…</string>\n    <string name=\"vt_queued\">VirusTotal: W kolejce</string>\n    <string name=\"vt_failed\">VirusTotal: Niepowodzenie</string>\n    <string name=\"explore\">Eksploruj</string>\n    <string name=\"system_partition\">Android root</string>\n    <string name=\"exit_confirmation\">Potwierdzenie wyjścia</string>\n    <string name=\"vt_permalink\">Stałe łącze do VirusTotal</string>\n    <string name=\"pref_vt_apikey\">Klucz API VirusTotal</string>\n    <string name=\"scan_in_vt\">Skanuj w VirusTotal</string>\n    <string name=\"process_id\">Identyfikator procesu</string>\n    <string name=\"parent_process_id\">Identyfikator procesu macierzystego</string>\n    <string name=\"warning_working_on_root_mode\">Ostrzeżenie: Praca w trybie roota zamiast w trybie ADB.</string>\n    <string name=\"failed_to_use_the_current_mode_of_operation\">Nie można użyć bieżącego trybu pracy. Powrócono do trybu bez-roota dla tej sesji.</string>\n    <string name=\"magisk_denylist\">Lista odrzuceń Magiska</string>\n    <string name=\"failed_to_enable_magisk_deny_list\">Nie można włączyć funkcji Listy odrzuceń Magiska</string>\n    <string name=\"mode_of_op_with_inferred_mode_of_op\">%1$s (Tryb wnioskowany: %2$s)</string>\n    <string name=\"failed_to_disable_magisk_deny_list\">Nie można wyłączyć Listy odrzuceń Magiska</string>\n    <string name=\"pref_saved_apk_name_format_msg\">Format, który będzie używany do nadawania nazw plikom APK podczas ich zapisywania.</string>\n    <string name=\"shortcut_icon\">Ikona skrótu</string>\n    <string name=\"external\">Zewnętrzny</string>\n    <string name=\"primary_abi\">Podstawowy ABI</string>\n    <string name=\"zygote_preload_name\">Nazwa wstępnego ładowania Zygote</string>\n    <string name=\"binary_64_bit\">64 Bit</string>\n    <string name=\"endianness_little_endian\">Cienkokońcowość</string>\n    <string name=\"vt_scan_date\">Data skanowania: %1$s</string>\n    <string name=\"vt_disclaimer\">VirusTotal i jego logo są znakami towarowymi firmy Chronicle LLC. Ani App Manager - klient API - ani jego autorzy nie ponoszą odpowiedzialności za żadne dane przesyłane do VirusTotal.</string>\n    <string name=\"uses_play_app_signing_description\">Ta aplikacja zawiera pewne znaczniki, które wskazują, że <i>może</i>używać <a href=\"https://support.google.com/googleplay/android-developer/answer/9842756\">podpisywania aplikacji Play</a>. W tym schemacie klucze podpisywania są przechowywane na serwerach Google, które jest odpowiedzialne za podpisywanie aplikacji. Należy pamiętać, że dopasowanie informacji o podpisie jest jedynym sposobem sprawdzenia, czy aplikacja nie została zmodyfikowana przez osobę inną niż twórca (a w tym przypadku również Google).</string>\n    <string name=\"open_in_new_window\">Nowe okno</string>\n    <string name=\"sort_by_installation_date\">Data instalacji</string>\n    <string name=\"auth_manager_description\">Aby uruchomić intencję z zewnętrznej aplikacji, konieczne jest dostarczenie dodatkowego pola o nazwie <tt>auth</tt>, które musi zawierać następujący klucz:</string>\n    <string name=\"auth_manager_title\">Menedżer autoryzacji</string>\n    <string name=\"backup_volume_unavailable_warning\">Wybrany wolumin kopii zapasowej nie jest obecnie dostępny. Jeśli znajduje się on w zewnętrznej pamięci masowej, włóż ją lub zmień wolumin kopii zapasowej.</string>\n    <string name=\"pref_vt_prompt_before_uploading\">Wyświetl monit przed przesłaniem pliku.</string>\n    <string name=\"input_ssaid_instruction\">SSAID jest %1$d bajtową liczbą szesnastkową, tj. ciągiem o długości %2$d zawierającym od 0 do 9 i od a do f.</string>\n    <string name=\"vt_confirm_uploading_file\">Plik nie został odnaleziony w bazie danych VirusTotal. Czy chcesz go przesłać\\?</string>\n    <string name=\"vt_confirm_upload_and_scan\">Tak, prześlij i zeskanuj</string>\n    <string name=\"regenerate_auth_key\">Ponownie wygeneruj klucz autoryzacji</string>\n    <string name=\"regenerate_auth_key_warning\">Czy na pewno\\? Wszystkie aplikacje innych firm muszą zostać ponownie skonfigurowane przy użyciu nowego klucza autoryzacji.</string>\n    <string name=\"internal\">Wewnętrzny</string>\n    <string name=\"change_backup_volume\">Zmień wolumin</string>\n    <string name=\"screen_time\">Czas ekranowy</string>\n    <string name=\"tracker\">Element śledzący</string>\n    <string name=\"type_string_set\">Zestaw ciągów</string>\n    <string name=\"accessibility_service_description\">Ogólna usługa dostępności umożliwiająca wykonywanie pewnych operacji, takich jak czyszczenie pamięci podręcznej w trybie bez-roota.</string>\n    <string name=\"vt_slowness_warning\">W zależności od szybkości Internetu i obciążenia serwera może to trochę potrwać.</string>\n    <string name=\"pref_vt_apikey_description\">Klucz API umożliwia App Manager przesyłanie plików APK do VirusTotal, a także pobieranie raportów. Zarejestruj się na stronie https://virustotal.com, aby otrzymać klucz API za darmo.</string>\n    <string name=\"pref_vt_apikey_summary\">Włącz skanowanie plików APK za pomocą VirusTotal.</string>\n    <string name=\"uses_play_app_signing\">Podpisywanie aplikacji Play</string>\n    <string name=\"virtual_memory\">Pamięć wirtualna</string>\n    <string name=\"cpu_percent\">%% CPU</string>\n    <string name=\"cpu_time\">Czas CPU</string>\n    <string name=\"priority\">Priorytet</string>\n    <string name=\"threads\">Liczba wątków</string>\n    <string name=\"state\">Stan procesu</string>\n    <string name=\"commandline_args\">Argumenty wiersza poleceń</string>\n    <string name=\"swap\">Zamień</string>\n    <string name=\"memory_chart_info\">● %1$s Aplikacje ● %2$s Zbuforowano ● %3$s Bufory ● %4$s Wolne</string>\n    <string name=\"swap_chart_info\">● %1$s Użyto ● %2$s Wolne</string>\n    <string name=\"failed_to_change_app_op_mode\">Nie można zmienić trybu pracy aplikacji.</string>\n    <string name=\"hidden_api_enforcement_policy\">Ukryte zasady wymuszania interfejsu API</string>\n    <string name=\"hidden_api_enf_default_policy\">Domyślnie (na podstawie typu aplikacji)</string>\n    <string name=\"hidden_api_enf_policy_none\">Brak (pełny dostęp do ukrytego interfejsu API)</string>\n    <string name=\"hidden_api_enf_policy_warn\">Ostrzegaj (pełny dostęp do ukrytego interfejsu API, ale wysyła ostrzeżenia)</string>\n    <string name=\"hidden_api_enf_policy_dark_grey_and_black\">Egzekwuj (ciemnoszare i czarne listy)</string>\n    <string name=\"hidden_api_enf_policy_black\">Egzekwuj (tylko czarne listy)</string>\n    <string name=\"binary_32_bit\">32 Bit</string>\n    <string name=\"endianness_big_endian\">Grubokońcowość</string>\n    <string name=\"so_type_shared_library\">Biblioteka wspólna</string>\n    <string name=\"so_type_executable\">Wykonywalny</string>\n    <string name=\"file_modified_are_you_sure\">Plik został zmodyfikowany. Odrzucić wszystkie zmiany i wyjść\\?</string>\n    <string name=\"save_and_exit\">Zapisz i wyjdź</string>\n    <string name=\"pref_saved_apk_name_format\">Format zapisanej nazwy APK</string>\n    <string name=\"item_select\">Wybierz</string>\n    <string name=\"apk_checksums\">Sumy kontrolne APK</string>\n    <string name=\"log_stop_recording\">Zatrzymaj nagrywanie</string>\n    <string name=\"app_explorer\">App Explorer</string>\n    <string name=\"netpolicy_cannot_be_modified_for_core_apps\">Zasad sieciowych nie można modyfikować dla systemowych aplikacji Android.</string>\n    <string name=\"pref_pure_black_theme\">Motyw czysta czerń</string>\n    <string name=\"pref_pure_black_theme_msg\">Użycie całkowicie czarnego tła, gdy tryb nocny jest włączony.</string>\n    <string name=\"open_developer_options_page\">Otwórz stronę opcji programisty w ustawieniach Androida</string>\n    <string name=\"usage_last_used\">Ostatnio użyto</string>\n    <string name=\"usage_mobile_data\">Dane komórkowe</string>\n    <string name=\"usage_wifi_data\">Dane Wi-Fi</string>\n    <string name=\"usage_times_opened\">Czasy otwarć</string>\n    <string name=\"frozen\">Zamrożono</string>\n    <string name=\"freeze\">Zamroź</string>\n    <string name=\"unfreeze\">Odmroź</string>\n    <string name=\"backup_no_backups_present\">Brak kopii zapasowych.</string>\n    <string name=\"restore_dots\">Przywróć…</string>\n    <string name=\"restart_device\">Uruchom ponownie urządzenie</string>\n    <string name=\"backup_apps_cannot_be_backed_up\">Następujące aplikacje nie są zainstalowane i nie można wykonać ich kopii zapasowej:</string>\n    <string name=\"import_backups_warning_delete_backups_after_import\">Czy usuwać kopie zapasowe po zaimportowaniu ich do App Managera\\? Każda kopia zapasowa jest osobno usuwana po pomyślnym zaimportowaniu. Wybierz <b>Nie</b> jeśli nie masz pewności.</string>\n    <string name=\"backup_apps_cannot_be_restored\">Następujące aplikacje nie mogą być przywrócone, ponieważ nie mają podstawowej kopii zapasowej:</string>\n    <string name=\"troubleshooting\">Rozwiązywanie problemów</string>\n    <string name=\"pref_reload_apps\">Odśwież aplikacje</string>\n    <string name=\"pref_reload_apps_msg\">Odśwież listę aplikacji przechowywanych w bazie danych App Manager, w przypadku nieoczekiwanego zachowania.</string>\n    <string name=\"changelog_type_new\">Nowy</string>\n    <string name=\"changelog_type_fix\">Napraw</string>\n    <string name=\"changelog_type_improve\">Polepsz</string>\n    <string name=\"unsupported_split_apk\">Nieobsługiwany</string>\n    <string name=\"view_changelog\">Dowiedz się, co nowego w tej wersji</string>\n    <string name=\"sort_by_total_size\">Całkowity rozmiar</string>\n    <string name=\"am_command\">Polecenie <tt>am</tt></string>\n    <string name=\"pref_sign_apk_no_signing_key\">Brak klucza podpisującego</string>\n    <string name=\"pref_sign_apk_error_signing_key_not_added\">Do podpisania pliku APK wymagany jest ważny klucz podpisujący.</string>\n    <string name=\"disable_app_description\">Zalecana metoda zamrażania. Wyłącza aplikację wraz ze wszystkimi jej składnikami, ale wszystkie skróty zostaną utracone.</string>\n    <string name=\"hide_app_description\">Ta metoda jest zalecana tylko do codziennego użytku. Ukryta aplikacja pojawia się tak, jakby była odinstalowana. Ale aplikacja może pojawić się ponownie, jeśli zostanie ponownie zainstalowana lub zaktualizowana.</string>\n    <string name=\"pref_advanced_pref\">Użytkownicy, format nazwy APK, równoległe wykonywanie itp.</string>\n    <string name=\"pref_version_changelog\">Wersja/Lista zmian</string>\n    <string name=\"get_help\">Uzyskaj pomoc</string>\n    <string name=\"user_manual\">Podręcznik użytkownika</string>\n    <string name=\"failed_to_freeze\">Nie można zamrozić <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g>.</string>\n    <string name=\"suspend_app_description\">Jest to najsłabsza metoda zamrażania. Zawieszona aplikacja może nadal pojawiać się w launcherze, ale będzie wyszarzona i nie będzie można jej uruchomić.</string>\n    <plurals name=\"alert_failed_to_freeze\">\n        <item quantity=\"one\">Nie można zamrozić %1$d aplikacji</item>\n        <item quantity=\"few\">Nie można zamrozić %1$d aplikacji</item>\n        <item quantity=\"many\">Nie można zamrozić %1$d aplikacji</item>\n        <item quantity=\"other\">Nie można zamrozić %1$d aplikacji</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_unfreeze\">\n        <item quantity=\"one\">Nie można odmrozić %1$d aplikacji</item>\n        <item quantity=\"few\">Nie można odmrozić %1$d aplikacji</item>\n        <item quantity=\"many\">Nie można odmrozić %1$d aplikacji</item>\n        <item quantity=\"other\">Nie można odmrozić %1$d aplikacji</item>\n    </plurals>\n    <string name=\"freeze_unfreeze\">Zamróź/odmróź</string>\n    <string name=\"profile_freeze_msg\">Zamraża lub odmraża aplikacje na podstawie ich stanu</string>\n    <string name=\"pref_default_freezing_method\">Domyślna metoda mrożenia</string>\n    <string name=\"pref_default_freezing_method_description\">Metoda stosowana domyślnie w miejscach, gdzie nie ma możliwości wyboru metody zamrażania.</string>\n    <string name=\"suspend_app\">Zawieś</string>\n    <string name=\"hide_app\">Ukryj</string>\n    <string name=\"sort_by_frozen_app\">Najpierw zamrożone</string>\n    <string name=\"filter_frozen_apps\">Zamrożone aplikacje</string>\n    <string name=\"pref_appearance_description\">Motyw, orientacja, funkcje itp.</string>\n    <string name=\"pref_privacy\">Prywatność</string>\n    <string name=\"pref_privacy_description\">Blokada ekranu, autoryzacja itp.</string>\n    <string name=\"failed_to_unfreeze\">Nie można odmrozić <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g>.</string>\n    <string name=\"confirm_file_deletion\">Tak, usuń</string>\n    <string name=\"freeze_on_phone_locked\">Automatycznie zamrażaj aplikację, gdy telefon jest zablokowany</string>\n    <string name=\"file_creation_date\">Utworzono</string>\n    <string name=\"file_modification_date\">Zmodyfikowano</string>\n    <string name=\"file_accessed_date\">Użyto</string>\n    <string name=\"file_open_with\">Otwórz za pomocą</string>\n    <string name=\"file_change_open_with\">Zmień otwórz za pomocą</string>\n    <string name=\"file_shortcut_target_file\">Plik docelowy</string>\n    <string name=\"file_properties\">Właściwości</string>\n    <string name=\"file_cut\">Wytnij</string>\n    <string name=\"fm_always_open_with\">Zawsze otwieraj</string>\n    <string name=\"fm_open_with_for_this_file_only\">Tylko dla tego pliku</string>\n    <string name=\"file_open_as\">Otwórz jako…</string>\n    <string name=\"file_open_with_custom_activity\">Własny</string>\n    <string name=\"file_open_with_os_default_dialog\">Otwórz w domyślnym oknie dialogowym systemu operacyjnego</string>\n    <string name=\"open_as_text\">Tekst</string>\n    <string name=\"open_as_image\">Obraz</string>\n    <string name=\"open_as_video\">Wideo</string>\n    <string name=\"open_as_archive\">Archiwum</string>\n    <string name=\"open_as_folder\">Katalog</string>\n    <string name=\"open_as_other\">Inne</string>\n    <string name=\"delete_filename\">Usuń %s</string>\n    <string name=\"on_unfreeze_open_application\">Otwórz aplikację po odmrożeniu</string>\n    <string name=\"on_open_application_no_recents\">Nie pokazuj uruchomionej aplikacji w Ostatnich</string>\n    <string name=\"tap_to_freeze_app\">Dotknij, aby zamrozić</string>\n    <string name=\"waiting_for_the_phone_to_be_locked\">Oczekiwanie na zablokowanie telefonu…</string>\n    <string name=\"action_stop_service\">Zatrzymaj</string>\n    <string name=\"app_can_write_and_execute_in_same_place\">Aplikacja narusza zasady <a href=\"https://en.wikipedia.org/wiki/W%5EX\">W^X </a> i może zapisywać i wykonywać w tym samym katalogu lub w tej samej części pamięci. Pozwala to na uruchamianie dowolnych plików wykonywalnych zarówno poprzez modyfikację plików wykonywalnych osadzonych w aplikacji, jak i pobieranie ich z Internetu. O ile nie jest to zamierzone działanie aplikacji (np. emulatory terminali), zaleca się znalezienie nowszej wersji aplikacji zaprojektowanej dla SDK 29 (Android 10) i nowszych lub znalezienie alternatyw.</string>\n    <string name=\"filter_apps_with_keystore\">Z KeyStore</string>\n    <string name=\"filter_apps_with_saf\">Z SAF</string>\n    <string name=\"filter_apps_with_ssaid\">Z SSAID</string>\n    <string name=\"action_continue\">Kontynuuj</string>\n    <string name=\"class_hierarchy\">Hierarchia</string>\n    <string name=\"title_ui_tracker\">Element śledzący interfejs użytkownika</string>\n    <string name=\"renamed_successfully\">Zmieniono nazwę</string>\n    <string name=\"selinux_context\">Kontekst SELinuksa</string>\n    <string name=\"unix_file_permissions\">Tryb</string>\n    <string name=\"calculating_file_size\">Obliczanie…</string>\n    <string name=\"export_option_markdown\">Markdown (formatowanie tekstu)</string>\n    <string name=\"funding_campaign_dialog_message\">Prowadzimy <b>kampanię finansowania</b> dla aplikacji App Manager przez ograniczony czas. Odwiedź stronę <a href=\"https://opencollective.com/app-manager#category-ABOUT\">opencollective.com/app-manager</a>, aby dowiedzieć się więcej o kampanii. To powiadomienie nie zostanie wyświetlone ponownie, ale można je znaleźć na stronie ustawień podczas trwania kampanii.</string>\n    <string name=\"sort_by_data_usage\">Użycie danych</string>\n    <string name=\"install_for_another_user\">Zainstaluj dla…</string>\n    <string name=\"confirm_uninstallation\">Potwierdź odinstalowanie</string>\n    <string name=\"grant_required_permission\">Udziel wymaganego pozwolenia</string>\n    <string name=\"grant_overlay_permission_message\">Pozwól, aby App Manager wyświetlał pływające okno nad wszystkimi innymi oknami</string>\n    <string name=\"title_terminal_emulator\">Terminal</string>\n    <string name=\"title_labs_activity\">Laboratoria</string>\n    <string name=\"grant_accessibility_permission_for_tracking_window_contents\">Zezwól Menedżerowi aplikacji na korzystanie z funkcji ułatwień dostępu w celu śledzenia zawartości głównego okna.</string>\n    <string name=\"app_manager_build_expired\">Wymagana jest aktualizacja</string>\n    <string name=\"app_manager_build_expiring_soon_warning\">Ta wersja App Managera niedługo wygaśnie. Proszę zaktualizować ją do najnowszej wersji.</string>\n    <string name=\"sort_by_filename\">Nazwa</string>\n    <string name=\"file_group_id\">Grupa (GID)</string>\n    <string name=\"file_owner_id\">Właściciel (UID)</string>\n    <string name=\"sort_by_last_modified\">Ostatnio zmodyfikowane</string>\n    <string name=\"sort_by_file_size\">Rozmiar pliku</string>\n    <string name=\"sort_by_file_type\">Typ pliku</string>\n    <string name=\"option_display_dot_files\">Ukryte pliki</string>\n    <string name=\"option_display_folders_on_top\">Foldery na górze</string>\n    <string name=\"app_manager_build_expired_message\">Aby zapewnić bezpieczeństwo Twojego urządzenia i danych, wersja App Managera, z której korzystasz, została wycofana. Musisz zaktualizować ją do najnowszej wersji, aby nadal z niej korzystać, lub odinstalować ją, jeśli nie jest dostępna żadna aktualizacja.</string>\n    <string name=\"export_option_xml\">XML</string>\n    <string name=\"export_app_list\">Eksportuj listę aplikacji</string>\n    <string name=\"export_app_list_select_format\">Wybierz format eksportu listy aplikacji</string>\n    <string name=\"adb_incomplete_usb_debugging_title\">Niekompletne debugowanie USB</string>\n    <string name=\"funding_campaign_text\">Prowadzimy <b>kampanię finansowania</b> dla App Managera przez ograniczony okres. <a href=\"https://opencollective.com/app-manager#category-ABOUT\">dowiedz się więcej...</a></string>\n    <string name=\"adb_incomplete_usb_debugging_message\">Wygląda na to, że debugowanie USB nie jest skonfigurowane prawidłowo. Proszę przeczytać <a href=\"https://muntashirakon.github.io/AppManager/#subsec:enable-usb-debugging\">dokumentację</a> w celu uzyskania dodatkowych kroków. Jeśli znasz już te kroki, kliknij \\\"Otwórz\\\", aby otworzyć opcje deweloperskie, lub kliknij \\\"Zamknij\\\", aby kontynuować korzystanie z trybu no-root.</string>\n    <string name=\"select_a_dex2oat_compiler_filter\"><tt>dex2oat</tt> filtr kompilatora</string>\n    <string name=\"optimize_option_compile_layouts\">Skompiluj zasoby układu</string>\n    <string name=\"optimize_option_clear_profile_data\">Wyczyść poprzednie dane profilu</string>\n    <string name=\"optimize_option_force_compilation\">Wymuś kompilację, nawet jeśli nie jest wymagana</string>\n    <string name=\"optimize_option_force_dexopt\">Natychmiast wykonaj optymalizację DEX</string>\n    <string name=\"title_perform_runtime_optimization_to_apps\">Przeprowadź optymalizację środowiska wykonawczego</string>\n    <string name=\"action_run\">Uruchom</string>\n    <string name=\"summary_perform_runtime_optimization_to_apps\">Zoptymalizuj DEX oraz (w systemie Android 10 i nowszych) układy, aby poprawić wydajność aplikacji.</string>\n    <string name=\"action_optimize_app\">Optymalizuj</string>\n    <string name=\"batch_ops_runtime_optimization\">Optymalizacja środowiska wykonawczego</string>\n    <string name=\"optimize_option_check_profiles\">Uwzględnij dane profilu podczas optymalizacji DEX</string>\n    <plurals name=\"alert_failed_to_optimize_apps\">\n        <item quantity=\"one\">Nie udało się zoptymalizować aplikacji %1$d</item>\n        <item quantity=\"few\">Nie udało się zoptymalizować aplikacji %1$d</item>\n        <item quantity=\"many\">Nie udało się zoptymalizować aplikacji %1$d</item>\n        <item quantity=\"other\">Nie udało się zoptymalizować aplikacji %1$d</item>\n    </plurals>\n    <string name=\"title_domains_supported_by_the_app\">Obsługiwane domeny</string>\n    <string name=\"app_info_tag_open_links\">Otwórz linki</string>\n    <string name=\"source_stamp_verified_and_identified_to_be_from_source\">SourceStamp zweryfikowany i zidentyfikowany jako pochodzący z <xliff:g id=\"source\" example=\"Google Play\">%1$s</xliff:g>.</string>\n    <string name=\"block_unblock_components_dots\">Blokowanie/odblokowywanie komponentów…</string>\n    <string name=\"unblock_components_dots\">Odblokuj komponenty…</string>\n    <string name=\"block_unblock_components_description\">Blokuj lub odblokowuj wszystkie komponenty zidentyfikowane przez podane sygnatury</string>\n    <plurals name=\"alert_failed_to_unblock_components\">\n        <item quantity=\"one\">Nie można odblokować komponentów dla %1$d aplikacji</item>\n        <item quantity=\"few\">Nie można odblokować komponentów dla %1$d aplikacji</item>\n        <item quantity=\"many\">Nie można odblokować komponentów dla %1$d aplikacji</item>\n        <item quantity=\"other\">Nie można odblokować komponentów dla %1$d aplikacji</item>\n    </plurals>\n    <string name=\"pref_layout_direction\">Kierunek układu</string>\n    <string name=\"pref_zip_align\">Wyrównaj pliki APK</string>\n    <string name=\"title_code_editor\">Edytor kodu</string>\n    <string name=\"redo\">Ponów</string>\n    <string name=\"read_only_file\">Plik tylko do odczytu</string>\n    <string name=\"line_separator\">Separator liniowy</string>\n    <string name=\"replacement_text\">Zamiennik</string>\n    <string name=\"action_replace_all\">Zastąp wszystko</string>\n    <string name=\"search_option_match_case\">Uwzględnij wielkość liter</string>\n    <string name=\"search_option_whole_word\">Całe słowo</string>\n    <string name=\"search_option_regex\">Regex</string>\n    <string name=\"uninstall_app_again_message\">Aplikacja została odinstalowana bez wyczyszczenia danych i podpisu. Czy chcesz ją całkowicie odinstalować\\?</string>\n    <string name=\"debloat_list_type\">Lista</string>\n    <string name=\"debloat_removal_type\">Rodzaj</string>\n    <string name=\"system_app_put_back\">Odłóż</string>\n    <string name=\"debloat_list_aosp\">AOSP</string>\n    <string name=\"debloat_list_oem\">OEM</string>\n    <string name=\"debloat_list_carrier\">Operator/dostawca usług internetowych</string>\n    <string name=\"debloat_list_google\">Google</string>\n    <string name=\"debloat_list_misc\">Składanka</string>\n    <string name=\"debloat_removal_safe\">Bezpieczny</string>\n    <string name=\"debloat_removal_replace\">Zastąp</string>\n    <string name=\"debloat_removal_caution\">Uwaga</string>\n    <string name=\"static_shared_library\">Statyczna biblioteka współdzielona</string>\n    <plurals name=\"search_results\">\n        <item quantity=\"one\">%d wynik</item>\n        <item quantity=\"few\">%d wyniki</item>\n        <item quantity=\"many\">%d wyników</item>\n        <item quantity=\"other\">%d wyników</item>\n    </plurals>\n    <string name=\"pref_zip_align_msg\">Wyrównywanie pliku APK zmniejsza zużycie pamięci, ponieważ pliki w pliku APK są dostępne bezpośrednio bez kopiowania danych do pamięci RAM. Ten krok jest wymagany, jeśli <tt>extractNativeLibs</tt> jest ustawiona na <tt>true</tt>.</string>\n    <string name=\"read_only_file_warning\">Zmiany nie mogą zostać zapisane w pliku, prawdopodobnie dlatego, że znajduje się on w woluminie, do którego zapisu nie ma uprawnień menedżer aplikacji. Chcesz zapisać go w innym miejscu\\?</string>\n    <string name=\"uninstall_app\">Odinstaluj %1$s</string>\n    <string name=\"debloater_title\">Debloater</string>\n    <string name=\"empty_folder\">Pusty</string>\n    <string name=\"go_to_path\">Idź do…</string>\n    <string name=\"copy_this_path\">Skopiuj ścieżkę</string>\n    <string name=\"title_audio_player\">Odtwarzacz audio</string>\n    <plurals name=\"folder_count\">\n        <item quantity=\"one\">%d katalog</item>\n        <item quantity=\"few\">%d katalogi</item>\n        <item quantity=\"many\">%d katalogów</item>\n        <item quantity=\"other\">%d katalogów</item>\n    </plurals>\n    <plurals name=\"file_count\">\n        <item quantity=\"one\">%d plik</item>\n        <item quantity=\"few\">%d pliki</item>\n        <item quantity=\"many\">%d plików</item>\n        <item quantity=\"other\">%d plików</item>\n    </plurals>\n    <string name=\"filter_force_stopped_apps\">Zatrzymane aplikacje</string>\n    <string name=\"restoring_app\">Przywracanie %1$s…</string>\n    <string name=\"folder\">Folder</string>\n    <string name=\"symbolic_link\">Dowiązanie symboliczne</string>\n    <string name=\"create_new_symbolic_link\">Nowe dowiązanie symboliczne</string>\n    <string name=\"create_new_folder\">Nowy folder</string>\n    <string name=\"create_new_file\">Nowy plik</string>\n    <string name=\"enter_symbolic_link_name\">Nazwa łącza</string>\n    <string name=\"enter_target_path\">Ścieżka docelowa</string>\n    <string name=\"copy_these_paths\">Skopiuj ścieżki</string>\n    <string name=\"title_confirm_deletion\">Potwierdź usunięcie</string>\n    <string name=\"copy_keep_both_file\">Zachowaj oba</string>\n    <string name=\"copied_successfully\">Skopiowano.</string>\n    <string name=\"moved_successfully\">Przeniesiono</string>\n    <string name=\"failed_to_delete_specified_file_after_copying\">Nie można usunąć „%1$s” po skopiowaniu, prawdopodobnie z powodu braku wystarczających uprawnień.</string>\n    <string name=\"title_change_selinux_context\">Zmiana kontekstu SELinuksa</string>\n    <string name=\"change_group_gid\">Zmień grupę (GID)</string>\n    <string name=\"change_mode\">Zmień tryb</string>\n    <string name=\"pref_send_notifications_to_connected_devices\">Wysyłaj powiadomienia do podłączonych urządzeń</string>\n    <string name=\"pref_send_notification_to_connected_devices_msg\">Ustaw, czy chcesz wysyłać powiadomienia do podłączonych urządzeń, takich jak urządzenia do noszenia.</string>\n    <string name=\"pref_installer_force_dexopt_description\">Przeprowadź optymalizację DEX natychmiast po zainstalowaniu aplikacji, nie czekając, aż system to zrobi, gdy jest bezczynny.</string>\n    <string name=\"warning_working_on_system_mode\">Ostrzeżenie: Praca w systemie zamiast w trybie ADB.</string>\n    <string name=\"backing_up_app\">Tworzenie kopii zapasowej %1$s…</string>\n    <string name=\"installing_package\">Instalowanie %1$s…</string>\n    <string name=\"symbolic_link_not_supported\">Ten folder nie obsługuje tworzenia dowiązania symbolicznego.</string>\n    <string name=\"failed_to_copy_specified_file\">Nie można skopiować \\\"%1$s\\\".</string>\n    <string name=\"invalid_target_path\">Nieprawidłowa ścieżka</string>\n    <string name=\"conflict_detected_while_copying_message\">Element o nazwie „%1$s” już istnieje w tej lokalizacji. Czy chcesz go nadpisać\\?</string>\n    <string name=\"conflict_detected_while_copying\">Wykryto konflikt</string>\n    <string name=\"apply_recursively\">Zastosuj do załączonych plików</string>\n    <string name=\"change_owner_uid\">Zmień właściciela (UID)</string>\n    <string name=\"debloat_removal_replace_short_description\">Zastąp alternatywą</string>\n    <string name=\"installer_options\">Opcje instalatora</string>\n    <string name=\"debloat_removal_safe_short_description\">Można bezpiecznie usunąć</string>\n    <string name=\"debloat_removal_caution_short_description\">Zachowaj ostrożność</string>\n    <string name=\"title_alternatives_to_bloatware\">Alternatywy</string>\n    <string name=\"browse_files\">Przeglądaj</string>\n    <string name=\"pref_files_msg\">Skonfiguruj menedżera plików.</string>\n    <string name=\"pref_files_display_in_launcher\">Wyświetl \\\"Pliki\\\" w szufladzie aplikacji</string>\n    <string name=\"pref_files_remember_last_path\">Zapamiętaj ostatnio otwartą ścieżkę i jej pozycję</string>\n    <string name=\"pref_files_remember_last_path_msg\">Gdy ta opcja jest włączona, otwarcie nowego okna powoduje otwarcie ostatnio otwieranego folderu zamiast folderu domowego.</string>\n    <string name=\"pref_set_home\">Ustaw ścieżkę początkową</string>\n    <string name=\"xposed_module_info\">Informacje o module Xposed</string>\n    <string name=\"title_description\">Opis</string>\n    <string name=\"module_name\">Nazwa modułu</string>\n    <string name=\"app_manager_is_running\">App Manager jest uruchomiony</string>\n    <string name=\"tap_to_open_notification_settings\">Dotknij, aby ukryć</string>\n    <string name=\"app_manager_is_unlocked\">App Manager jest odblokowany</string>\n    <string name=\"action_lock_app\">Zablokuj</string>\n    <string name=\"pref_enable_persistent_session\">Uruchom App Manager w tle</string>\n    <string name=\"pref_enable_persistent_session_msg\">Uruchamianie App Manager w tle zmniejsza opóźnienie inicjalizacji. Przydatne, jeśli często korzystasz z aplikacji App Manager.</string>\n    <string name=\"pref_enable_auto_lock\">Automatyczne blokowanie</string>\n    <string name=\"pref_enable_auto_lock_msg\">Zablokuj App Manager, gdy urządzenie jest zablokowane.</string>\n    <string name=\"path_does_not_exist\">“%1$s” nie istnieje</string>\n    <string name=\"path_not_a_folder\">„%1$s” nie jest folderem</string>\n    <string name=\"scan_report_from_pithus\">Raport Pithusa</string>\n    <string name=\"action_checking\">Sprawdzanie…</string>\n    <string name=\"report_not_available\">Niedostępne</string>\n    <string name=\"profile_modified_are_you_sure\">Profil został zmodyfikowany. Odrzucić wszystkie zmiany i wyjść\\?</string>\n    <string name=\"apply_profile\">Zastosuj profil \\\"%1$s\\\"</string>\n    <string name=\"copy_profile_id\">Skopiuj identyfikator profilu</string>\n    <string name=\"profile_id\">Identyfikator profilu</string>\n    <string name=\"choose_a_profile_state\">Wybierz stan profilu</string>\n    <string name=\"netpolicy_reject_metered_background_data\">Odrzucaj dane podstawowe w sieciach pomiarowych</string>\n    <string name=\"pref_toggle_internet_msg\">Aktywuj funkcje internetowe w App Manager</string>\n    <string name=\"launch_activity_dialog_message\">App Manager próbuje uruchomić aktywność za pośrednictwem <b>asystenta wyszukiwania</b> (zwykle Asystenta Google), ale nie może tego zrobić z powodu niewystarczających uprawnień. Aby otworzyć aktywność, należy ręcznie aktywować <b>asystenta wyszukiwania</b> (co zwykle odbywa się poprzez przytrzymanie przycisku Ekran główny). Dotknij <b>Zamknij</b> po zakończeniu uruchamiania aktywności, aby powrócić do oryginalnego asystenta.</string>\n    <string name=\"status_remote_services_active\">Usługi zdalne są aktywne</string>\n    <string name=\"status_remote_services_inactive\">Usługi zdalne są nieaktywne</string>\n    <string name=\"status_connecting\">Łączenie…</string>\n    <string name=\"status_not_connected_via_mode\">Nie udało się połączyć przez %s</string>\n    <string name=\"adb_pairing_instruction\">Przejdź do opcji programisty, aby włączyć debugowanie bezprzewodowe i wygenerować kod parowania.Kliknij <b>Ręcznie</b>, jeśli masz otwarte już opcje programisty.</string>\n    <string name=\"adb_pairing_pairing_in_progress\">Parowanie…</string>\n    <string name=\"adb_pairing_retry_pairing\">Ponów</string>\n    <string name=\"netpolicy_reject_metered_data\">Odrzucaj dane w sieciach z pomiarem</string>\n    <string name=\"netpolicy_allow_metered_background_data\">Zezwalaj na transmisję danych w tle w sieciach z pomiarem, nawet gdy włączone jest oszczędzanie danych</string>\n    <string name=\"launch_activity_dialog_title\">Uruchom aktywność: Wymagane działanie</string>\n    <string name=\"finder_title\">Wyszukiwarka</string>\n    <string name=\"select_filter\">Wybierz filtr</string>\n    <string name=\"size_in_bytes\">Rozmiar (bajty)</string>\n    <string name=\"invalid_regex\">Nieprawidłowe wyrażenie regularne!</string>\n    <string name=\"value_cannot_be_empty\">Wartość nie może być pusta!</string>\n    <string name=\"date\">Data</string>\n    <string name=\"pref_use_vt\">Używaj VirusTotal</string>\n    <string name=\"virus_total\">VirusTotal</string>\n    <string name=\"pref_use_vt_no_internet\">VirusTotal wymaga do działania Internetu, który nie jest włączony. Najpierw włącz opcję <a href=\"app-manager://settings/privacy_prefs/toggle_internet\">\\\"Korzystaj z Internetu\\\"</a>.</string>\n    <string name=\"pref_use_log_viewer\">Korzystaj z przeglądarki dziennika</string>\n    <string name=\"pref_installer\">Używaj instalatora</string>\n    <string name=\"pref_cat_general\">Ogólne</string>\n    <string name=\"status_remote_server_active\">Zdalny serwer jest aktywny</string>\n    <string name=\"status_remote_server_inactive\">Zdalny serwer jest nieaktywny</string>\n    <string name=\"status_connecting_via_mode\">Łączenie przez %s</string>\n    <string name=\"status_connected_via_mode\">Połączono przez %s</string>\n    <string name=\"adb_pairing_searching_for_port\">Wyszukiwanie…</string>\n    <string name=\"adb_pairing_stop_searching\">Zatrzymaj</string>\n    <string name=\"adb_pairing_input_pairing_code\">Kod parowania</string>\n    <string name=\"adb_pairing_pairing_code\">Kod parowania</string>\n    <string name=\"adb_pairing_found_pairing_service_with_port\">Znaleziono usługę z portem %d</string>\n    <string name=\"mode_of_op_custom_command_title\">Własna komenda</string>\n    <string name=\"mode_of_op_custom_command\">Jeśli nie możesz użyć żadnego z trybów, możesz uruchomić następujące polecenie w dowolnej obsługiwanej powłoce, aby uruchomić App Manager w trybie uprzywilejowanym:</string>\n    <string name=\"mode_of_op_alternative_custom_command\">Jeśli po wykonaniu powyższego polecenia pojawi się błąd \\\"odmowa uprawnień\\\", uruchom następujące polecenie:</string>\n    <string name=\"sensors\">Czujniki</string>\n    <string name=\"tag_sensors_disabled\">Czujniki wyłączone</string>\n    <string name=\"pref_use_system_font\">Używaj czcionki systemowej</string>\n    <string name=\"pref_use_system_font_msg\">Używa domyślnej czcionki systemowej zamiast czcionki material.<font fgcolor=\"#ff0000\"> Jest to funkcja eksperymentalna.</font></string>\n    <string name=\"actual_installer\">Obecny instalator</string>\n    <string name=\"apk_source\">Źródło APK</string>\n    <string name=\"backup_cache\">Pamięć podręczna</string>\n    <string name=\"activity_name\">Nazwa aktywności</string>\n    <string name=\"available_memory\">Dostępne: %s</string>\n    <string name=\"action_manual\">Ręcznie</string>\n    <string name=\"vulkan_version\">Wersja Vulkan</string>\n    <string name=\"battery_technology\">Technologia</string>\n    <string name=\"battery_health\">Zdrowie</string>\n    <string name=\"verified_boot\">Zweryfikowany rozruch</string>\n    <string name=\"android_verified_bootloader_version\">Wersja AVB</string>\n    <string name=\"op_history\">Historia</string>\n    <string name=\"no_history\">Brak historii</string>\n    <string name=\"title_confirm_execution\">Potwierdź wykonanie</string>\n    <string name=\"clear_history\">Wyczyść historię</string>\n    <string name=\"favorites\">Ulubione</string>\n    <string name=\"add_to_favorites\">Dodaj do ulubionych</string>\n    <string name=\"item_remove\">Usuń</string>\n    <string name=\"item_edit\">Edytuj</string>\n    <string name=\"remove_filename\">Usuń %s</string>\n    <string name=\"advanced_suspend_app\">Zaawansowane wstrzymanie</string>\n    <string name=\"advanced_suspend_app_description\">Wymusza ona zatrzymanie i zawieszenie aplikacji, aby upewnić się, że nie działa ona w tle. Ta metoda powinna być preferowana w stosunku do zwykłej metody <b>wstrzymania</b>.</string>\n    <string name=\"freeze_prefer_per_app_option\">Preferowana opcja dla każdej aplikacji</string>\n    <string name=\"remember_option_for_this_app\">Zapamiętaj dla tej aplikacji</string>\n    <string name=\"no_overlay_permission\">Brak uprawnień do wyświetlania nakładek</string>\n    <string name=\"overlay_category\">Kategoria</string>\n    <string name=\"overlay_target\">Cel</string>\n    <string name=\"overlay_sdk_version_too_low\">Nakładki nie są obsługiwane.</string>\n    <string name=\"no_overlays\">Brak nakładek</string>\n    <string name=\"sort_by_overlay_names\">Nazwa nakładki</string>\n    <string name=\"sort_by_priority\">Priorytet</string>\n    <string name=\"overlays\">Nakładki</string>\n    <string name=\"title_shortcut_for_frozen_app\">Zamrożona aplikacja</string>\n    <string name=\"title_overlay\">Nakładka</string>\n    <string name=\"message_shortcut_for_frozen_app\">Wygląda na to, że aplikacja odpowiadająca skrótowi została zamrożona. Odblokować tymczasowo i otworzyć skrót?</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-pt/disclaimer.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- SPDX-License-Identifier: GPL-3.0-or-later --><resources>\n    <string name=\"disclaimer_exit\">Sair</string>\n    <string name=\"disclaimer_agree\">Eu concordo</string>\n    <string name=\"disclaimer_agree_forever\">Nunca mostrar novamente</string>\n    <string name=\"disclaimer_footer\">© 2020–2024 Muntashir Al-Islam</string>\n    <string name=\"disclaimer_body\">O App Manager oferece funções de root que podem eventualmente prejudicar o seu dispositivo, se for utilizado incorretamente. O App Manager não é responsável por quaisquer danos causados pela utilização desta aplicação. Se não estiver totalmente consciente de como o modo root funciona, então deve evitar utilizar essas opções até estar plenamente consciente dos riscos.\n\\n\n\\nQualquer link que eu forneça para outras aplicações e sites é para o benefício dos utilizadores. Não sou responsável por qualquer conteúdo que possa encontrar através de links externos.\n\\n\n\\nAo utilizar o App Manager, aceita total responsabilidade pela sua utilização e não aceita compensação por danos, reclamações ou valores monetários devido à utilização indevida.\n\\n\n\\nAo utilizar esta aplicação, aceita toda a responsabilidade ao utilizá-la e concorda que eu não sou responsável por qualquer ação que faça e que tenha um efeito adverso sobre o seu dispositivo.</string>\n    <string name=\"disclaimer_header\">Aviso</string>\n</resources>"
  },
  {
    "path": "app/src/main/res/values-pt/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- SPDX-License-Identifier: GPL-3.0-or-later --><resources xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:tools=\"http://schemas.android.com/tools\">\n    <string name=\"_lang_tag\" translatable=\"false\">pt</string>\n    <string name=\"choose_language\">Mudar idioma</string>\n    <string name=\"pref_app_language\">Idioma</string>\n    <string name=\"backup_all_users\">Todos os utilizadores</string>\n    <string name=\"backup_multiple\">Backup múltiplo</string>\n    <string name=\"obb_files_extracted_successfully\">Ficheiros OBB extraídos</string>\n    <string name=\"failed_to_extract_obb_files\">Não foi possível extrair ficheiros OBB</string>\n    <string name=\"backup_apk_files\">Ficheiros APK</string>\n    <string name=\"installer_error_session_abandon\">A sessão de instalação não pôde ser abandonada</string>\n    <string name=\"installer_error_session_commit\">Não foi possível fazer o commit dos ficheiros APK</string>\n    <string name=\"installer_error_session_write\">Não foi possível gravar na sessão de instalação</string>\n    <string name=\"installer_error_session_create\">Não foi possível criar uma sessão de instalação</string>\n    <string name=\"installer_error_security\">Não foi possível aceder aos ficheiros APK</string>\n    <string name=\"install_in_progress\">A instalar…</string>\n    <string name=\"package_installer\">Instalador de pacotes</string>\n    <string name=\"unblock_trackers\">Desbloquear rastreadores</string>\n    <string name=\"reinstall\">Reinstalar</string>\n    <string name=\"install_app_message\">Deseja instalar a app\\?</string>\n    <string name=\"try_again\">Tentar novamente</string>\n    <string name=\"full_stop_tap_to_see_details\">. Toque para ver detalhes.</string>\n    <string name=\"operation_running\">Operação em execução…</string>\n    <string name=\"batch_ops\">Operações em lote</string>\n    <string name=\"failed_to_fetch_package_info\">Não foi possível obter informações do pacote</string>\n    <string name=\"installer_error_lidl_rom\">A sua ROM é incompatível com o Rootless Installer.</string>\n    <string name=\"installer_error_generic\">A instalação falhou</string>\n    <string name=\"installer_error_storage\">Não há espaço suficiente no armazenamento para instalar a app</string>\n    <string name=\"installer_error_bad_apks\">Os ficheiros APK são inválidos</string>\n    <string name=\"installer_error_incompatible\">Está app é não é compatível com o seu aparelho</string>\n    <string name=\"installer_error_conflict\">Não foi possível instalar a app porque está a ser utilizada</string>\n    <string name=\"installer_error_blocked\">Instalação bloqueada por <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g></string>\n    <string name=\"installer_error_blocked_device\">aparelho</string>\n    <string name=\"installer_error_aborted\">A instalação falhou porque foi cancelada ou a sessão foi encerrada inesperadamente</string>\n    <string name=\"toggle_default_app_ops\">Repor app ops</string>\n    <string name=\"filter_apps_with_activities\">Com atividades</string>\n    <string name=\"are_you_sure\">Tem a certeza\\?</string>\n    <string name=\"pref_remove_all_rules_msg\">As permissões serão concedidas, as operações das aplicações e dos componentes retornarão aos valores de origem.</string>\n    <string name=\"pref_remove_all_rules\">Remover todas as regras</string>\n    <string name=\"website\">Site</string>\n    <string name=\"run_in_termux\">Executar no Termux</string>\n    <string name=\"open_in_termux\">Abrir no Termux</string>\n    <string name=\"export_icon\">Extrair ícone</string>\n    <string name=\"no_matching_package_found\">Não foi possível encontrar nenhuma app deste tipo</string>\n    <string name=\"block_unblock_trackers\">Bloquear/desbloquear rastreadores</string>\n    <string name=\"unblock\">Desbloquear</string>\n    <string name=\"block\">Bloquear</string>\n    <string name=\"clear\">Limpar</string>\n    <string name=\"clear_data_message\">Tem certeza que deseja eliminar os dados desta app\\?</string>\n    <string name=\"skip_signature_checks\">Ignorar verificação de assinatura</string>\n    <string name=\"yes\">Sim</string>\n    <string name=\"no\">Não</string>\n    <string name=\"apply_to_system_apps_question\">Aplicar também às apps do sistema\\? Selecione \\\"Não\\\" se não tiver certeza.</string>\n    <string name=\"apply_to_system_apps\">Aplicar às apps do sistema</string>\n    <plurals name=\"alert_failed_to_block_components\">\n        <item quantity=\"one\">Não foi possível bloquear os componentes da %1$d app</item>\n        <item quantity=\"many\">Não foi possível bloquear os componentes das %1$d apps</item>\n        <item quantity=\"other\">Não foi possível bloquear os componentes das %1$d apps</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_unblock_trackers\">\n        <item quantity=\"one\">Não foi possível desbloquear os rastreadores da %1$d app</item>\n        <item quantity=\"many\">Não foi possível desbloquear os rastreadores das %1$d apps</item>\n        <item quantity=\"other\">Não foi possível desbloquear os rastreadores das %1$d apps</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_delete_backup\">\n        <item quantity=\"one\">Não foi possível eliminar a %1$d cópia de segurança</item>\n        <item quantity=\"many\">Não foi possível eliminar as %1$d cópias de segurança</item>\n        <item quantity=\"other\">Não foi possível eliminar as %1$d cópias de segurança</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_restore\">\n        <item quantity=\"one\">Não foi possível restaurar a %1$d app</item>\n        <item quantity=\"many\">Não foi possível restaurar as %1$d apps</item>\n        <item quantity=\"other\">Não foi possível restaurar as %1$d apps</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_backup\">\n        <item quantity=\"one\">Não foi possível fazer o backup da %1$d app</item>\n        <item quantity=\"many\">Não foi possível fazer o backup das %1$d apps</item>\n        <item quantity=\"other\">Não foi possível fazer o backup das %1$d apps</item>\n    </plurals>\n    <plurals name=\"failed_to_backup_some_apk_files\">\n        <item quantity=\"one\">Não foi possível fazer backup da %1$da app</item>\n        <item quantity=\"many\">Não foi possível fazer o backup das %1$d apps</item>\n        <item quantity=\"other\">Não foi possível fazer o backup das %1$d apps</item>\n    </plurals>\n    <string name=\"backup_options\">Opções de backup</string>\n    <string name=\"delete_backup\">Eliminar cópia de segurança</string>\n    <string name=\"restore\">Restaurar</string>\n    <string name=\"backup\">Backup</string>\n    <string name=\"data\">Dados</string>\n    <string name=\"external_data\">Dados externos</string>\n    <string name=\"sort_by_denied_app_ops\">Negadas</string>\n    <string name=\"sort_by_app_ops_names\">Nome das operações da app</string>\n    <string name=\"deny_dangerous_app_ops\">Negar operações de apps perigosas</string>\n    <string name=\"reset_to_default\">Restaurar à predefinição</string>\n    <string name=\"sort_by_component_name\">Nome do componente</string>\n    <string name=\"block_trackers\">Bloquear rastreadores</string>\n    <string name=\"sort_by_wifi_data\">Dados Wi-Fi</string>\n    <string name=\"version\">Versão</string>\n    <string name=\"pref_about_msg\">Versão, licenças e créditos do App Manager.</string>\n    <string name=\"apply\">Aplicar</string>\n    <string name=\"select_theme\">Tema</string>\n    <string name=\"night\">Noite</string>\n    <string name=\"day\">Dia</string>\n    <string name=\"battery_mode\">Modo bateria</string>\n    <string name=\"follow_system\">Seguir o sistema</string>\n    <string name=\"pref_app_theme\">Temas</string>\n    <string name=\"pref_import_blocker_msg\">Importar regras de bloqueio do Blocker, cada ficheiro contém regras de um único pacote.</string>\n    <string name=\"pref_import_watt_msg\">Importar regras de bloqueio do Watt, cada ficheiro contem regras para um único pacote nomeado como <tt>packagename.xml</tt> etc.</string>\n    <string name=\"pref_import_msg\">Importar regras de bloqueio anteriormente guardadas.</string>\n    <string name=\"pref_export_msg\">Exportar regras de bloqueio desta app para o armazenamento externo.</string>\n    <string name=\"navigation\">Navegação</string>\n    <string name=\"keyboard_type\">Tipo de teclado</string>\n    <string name=\"export_failed\">Falha ao exportar!</string>\n    <string name=\"import_failed\">Falha ao importar!</string>\n    <string name=\"export_options\">Opções de exportação</string>\n    <string name=\"import_options\">Opções de importação</string>\n    <string name=\"pref_export\">Exportar</string>\n    <string name=\"pref_import\">Importar</string>\n    <string name=\"ago\">atrás</string>\n    <string name=\"duration\">Duração</string>\n    <string name=\"running\">Em execução</string>\n    <string name=\"mode\">Modo</string>\n    <string name=\"permission_name\">Nome de Permissão</string>\n    <string name=\"toggle_kill_for_system_apps\">Alternar a paragem das apps de sistema</string>\n    <plurals name=\"alert_failed_to_force_stop\">\n        <item quantity=\"one\">Não foi possível forçar a paragem da %1$d app</item>\n        <item quantity=\"many\">Não foi possível forçar a paragem das %1$d apps</item>\n        <item quantity=\"other\">Não foi possível forçar a paragem das %1$d apps</item>\n    </plurals>\n    <string name=\"the_operation_was_successful\">Concluido</string>\n    <plurals name=\"alert_failed_to_disable_background\">\n        <item quantity=\"one\">Não foi possível impedir a execução da %1$d app em segundo plano</item>\n        <item quantity=\"many\">Não foi possível impedir a execução das %1$d apps em segundo plano</item>\n        <item quantity=\"other\">Não foi possível impedir a execução das %1$d apps em segundo plano</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_uninstall\">\n        <item quantity=\"one\">Não foi possível desinstalar %1$d app</item>\n        <item quantity=\"many\">Não foi possível desinstalar %1$d apps</item>\n        <item quantity=\"other\">Não foi possível desinstalar %1$d apps</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_clear_data\">\n        <item quantity=\"one\">Não foi possível limpar os dados da %1$d app</item>\n        <item quantity=\"many\">Não foi possível limpar os dados das %1$d apps</item>\n        <item quantity=\"other\">Não foi possível limpar os dados das %1$d apps</item>\n    </plurals>\n    <string name=\"export_blocking_rules\">Exportar regras de bloqueio</string>\n    <string name=\"disable_background\">Impedir operação em segundo plano</string>\n    <string name=\"backup_restore\">Backup/restauro</string>\n    <string name=\"clear_data\">Limpar dados</string>\n    <string name=\"user_and_uid\">Utilizador: <xliff:g id=\"user_name\" example=\"root\">%1$s</xliff:g> (<xliff:g id=\"user_id\" example=\"0\">%2$d</xliff:g>)</string>\n    <string name=\"memory_virtual_memory\">Memória: %1$s; Memória virtual: %2$s</string>\n    <string name=\"pid_and_ppid\">ID do processo: %1$d, ID do processo parental: %2$d</string>\n    <string name=\"disable_background_run\">Desativar a operação em segundo plano</string>\n    <string name=\"kill_process\">Forçar paragem</string>\n    <string name=\"running_apps\">Em execução</string>\n    <string name=\"apk_updater\">Atualizador de APK</string>\n    <plurals name=\"failed_to_import_files\">\n        <item quantity=\"one\">Não foi possível importar %1$d ficheiro.</item>\n        <item quantity=\"many\">Não foi possível importar %1$d ficheiros.</item>\n        <item quantity=\"other\">Não foi possível importar %1$d ficheiros.</item>\n    </plurals>\n    <string name=\"the_export_was_successful\">Exportado</string>\n    <string name=\"the_import_was_successful\">Importado</string>\n    <string name=\"pref_import_blocker\">Importar do Blocker</string>\n    <string name=\"pref_import_watt\">Importar do Watt</string>\n    <string name=\"pref_import_export_blocking_rules_msg\">Importar/exportar regras, importar regras externas do Watt ou do Blocker.</string>\n    <string name=\"pref_import_export_blocking_rules\">Importar/exportar regras de bloqueio</string>\n    <string name=\"sort_by_mobile_data\">Dados móveis</string>\n    <string name=\"sort_by_times_opened\">Vezes utilizado</string>\n    <string name=\"sort_by_screen_time\">Tempo de ecrã</string>\n    <string name=\"sort_by_last_used\">Última utilização</string>\n    <plurals name=\"no_of_times_opened\">\n        <item quantity=\"one\">%1$d vez</item>\n        <item quantity=\"many\">%1$d vezes</item>\n        <item quantity=\"other\">%1$d vezes</item>\n    </plurals>\n    <string name=\"external_multiple_data_dir\">Diretório de dados externo<xliff:g id=\"dir_no\" example=\"1\">%1$d</xliff:g></string>\n    <string name=\"external_data_dir\">Diretório de dados externo</string>\n    <string name=\"sort_by_blocked_components\">bloqueados</string>\n    <string name=\"exodus_link\">Ligação ao εxodus</string>\n    <string name=\"usage_yesterday\">Ontem</string>\n    <string name=\"app_settings\">Configurações</string>\n    <string name=\"usage_access\">Acesso de utilização</string>\n    <string name=\"pref_global_blocking_enabled_msg\">Permite bloquear qualquer componente de qualquer app sem ligar explicitamente o bloqueio da mesma.</string>\n    <string name=\"pref_global_blocking_enabled\">Bloquear componentes de imediato</string>\n    <string name=\"str_logo\">Logo</string>\n    <string name=\"rules_not_applied\">Regras não aplicadas</string>\n    <string name=\"failed_to_disable_op\">Não foi possível desativar a operação</string>\n    <string name=\"failed_to_enable_op\">Não foi possível ativar a app</string>\n    <string name=\"no_app_ops\">Nenhuma operação das aplicações</string>\n    <string name=\"app_ops\">Operações da app</string>\n    <string name=\"app_size\">App</string>\n    <string name=\"total_size\">Total</string>\n    <string name=\"storage_and_cache\">Armazenamento e Cache</string>\n    <string name=\"failed_to_stop\">Não foi possível parar<xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g>.</string>\n    <string name=\"force_stop\">Forçar paragem</string>\n    <string name=\"enable\">Ativar</string>\n    <string name=\"disable\">Desativar</string>\n    <string name=\"stopped\">Parado</string>\n    <string name=\"uninstall_system_app_message\">Esta é uma aplicação de sistema. Tem a certeza que deseja desinstalar esta app\\?</string>\n    <string name=\"uninstalled_successfully\"><xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g> foi desinstalada.</string>\n    <string name=\"failed_to_uninstall\">Não foi possível desinstalar <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g>.</string>\n    <string name=\"uninstall_app_message\">Deseja desinstalar esta app\\?</string>\n    <string name=\"view_in_settings\">Ver nas configurações</string>\n    <string name=\"no_content\">Sem conteúdo</string>\n    <string name=\"no_usage_in_this_time_range\">Nenhuma utilização neste intervalo de tempo</string>\n    <string name=\"disabled_app\">Desativado</string>\n    <string name=\"key_name_cannot_be_null\">O nome da chave não pode estar vazio</string>\n    <string name=\"error_evaluating_input\">Não foi possível avaliar a entrada</string>\n    <string name=\"type_string\">Caracteres</string>\n    <string name=\"type_long\">Inteiro longo</string>\n    <string name=\"type_int\">Inteiro</string>\n    <string name=\"type_float\">Número decimal</string>\n    <string name=\"type_boolean\">Verdadeiro/Falso</string>\n    <string name=\"done\">Concluido</string>\n    <string name=\"add_item\">Adicionar item</string>\n    <string name=\"select_type\">Selecione um tipo</string>\n    <string name=\"key_name\">Nome da Chave</string>\n    <string name=\"boolean_value\">Valor lógico</string>\n    <string name=\"decimal_value\">Valor decimal</string>\n    <string name=\"integer_value\">Valor inteiro</string>\n    <string name=\"long_integer_value\">Valor inteiro longo</string>\n    <string name=\"string_value\">Valor da cadeia</string>\n    <string name=\"saving_failed\">Falha ao gravar, tente novamente.</string>\n    <string name=\"saved_successfully\">Guardado</string>\n    <string name=\"deletion_failed\">Falha ao eliminar</string>\n    <string name=\"deleted_successfully\">Eliminado</string>\n    <string name=\"delete\">Eliminar</string>\n    <string name=\"discard\">Descartar</string>\n    <string name=\"save\">Guardar</string>\n    <string name=\"databases\">Base de dados</string>\n    <string name=\"shared_prefs\">Preferências partilhadas</string>\n    <string name=\"test_only\">Apenas teste</string>\n    <string name=\"debuggable\">Depurável</string>\n    <string name=\"updated_app\">Atualizada</string>\n    <string name=\"requested_large_heap\">Grande pilha</string>\n    <string name=\"no_code\">Sem código</string>\n    <string name=\"process_name\">Nome do processo</string>\n    <string name=\"native_library_dir\">Diretório Nativo da Biblioteca JNI</string>\n    <string name=\"dev_protected_data_dir\">Diretório de dados protegido pelo aparelho</string>\n    <string name=\"search\">Procurar</string>\n    <string name=\"menu_apply_rules\">Aplicar regras</string>\n    <string name=\"menu_remove_rules\">Remover regras</string>\n    <string name=\"failed_to_extract_apk_file\">Não foi possível extrair o ficheiro</string>\n    <string name=\"share_apk\">Partilhar APK</string>\n    <string name=\"grant_usage_acess_message\">Utilizado para mostrar informações da utilização das apps.</string>\n    <string name=\"grant_usage_access\">Permitir acesso de utilização</string>\n    <string name=\"go\">Avançar</string>\n    <string name=\"go_back\">Voltar</string>\n    <string name=\"usage_less_than_a_minute\">Há menos de um minuto</string>\n    <plurals name=\"usage_hours\">\n        <item quantity=\"one\">%1$d hora</item>\n        <item quantity=\"many\">%1$d horas</item>\n        <item quantity=\"other\">%1$d horas</item>\n    </plurals>\n    <plurals name=\"usage_days\">\n        <item quantity=\"one\">%1$d dia</item>\n        <item quantity=\"many\">%1$d dias</item>\n        <item quantity=\"other\">%1$d dias</item>\n    </plurals>\n    <plurals name=\"usage_months\">\n        <item quantity=\"one\">%1$d mês</item>\n        <item quantity=\"many\">%1$d meses</item>\n        <item quantity=\"other\">%1$d meses</item>\n    </plurals>\n    <string name=\"usage_7_days\">Últimos 7 dias</string>\n    <string name=\"usage_today\">Hoje</string>\n    <string name=\"usage_weekly\">Semanal</string>\n    <string name=\"app_usage\">Utilização das aplicações</string>\n    <string name=\"no_tracker_class\">Rastreadores sem classe</string>\n    <string name=\"no_shared_libs\">Sem bibliotecas partilhadas</string>\n    <plurals name=\"main_list_date_days\">\n        <item quantity=\"one\"><xliff:g id=\"last_update_date\" example=\"20/10/2020\">%1$s</xliff:g> <xliff:g id=\"day_no\" example=\"5\">%2$d</xliff:g> dia</item>\n        <item quantity=\"many\"><xliff:g id=\"last_update_date\" example=\"20/10/2020\">%1$s</xliff:g> <xliff:g id=\"day_no\" example=\"5\">%2$d</xliff:g> dias</item>\n        <item quantity=\"other\"><xliff:g id=\"last_update_date\" example=\"20/10/2020\">%1$s</xliff:g> <xliff:g id=\"day_no\" example=\"5\">%2$d</xliff:g> dias</item>\n    </plurals>\n    <string name=\"all_classes\">Todas as classes</string>\n    <string name=\"tracker_classes\">Classe do rastreador</string>\n    <string name=\"tracker_details\">Detalhes do rastreador</string>\n    <string name=\"found_trackers\">Rastreadores encontrados:</string>\n    <string name=\"toggle_class_listing\">Alternar a lista de classes</string>\n    <string name=\"class_viewer\">Visualizar classes</string>\n    <string name=\"word_wrap\">Alternar quebra de linha</string>\n    <string name=\"credits_message\">Aos autores de\n\\n- The Android Open Source Project\n\\n- <a href=\"https://github.com/zhaobozhen/libraries\">Absinthe\\'s libraries</a>\n\\n- <a href=\"https://github.com/butzist/ActivityLauncher\">Activity Launcher</a>\n\\n- <a href=\"https://bitbucket.org/oF2pks/fdroid-applications-info\">Apps_packages Info</a>\n\\n- <a href=\"https://github.com/zhaobao/AppsMonitor\">AppsMonitor</a>\n\\n- <a href=\"https://github.com/8enet/AppOpsX\">AppOpsX</a>\n\\n- <a href=\"https://github.com/gabrielemariotti/changeloglib\">ChangeLog Library</a>\n\\n- <a href=\"https://bitbucket.org/oF2pks/fdroid-classyshark3xodus\">ClassySharkAndroid</a>\n\\n- <a href=\"https://github.com/billthefarmer/editor\">Editor</a>\n\\n- <a href=\"https://github.com/Raival-e/File-Explorer\">File Explorer</a>\n\\n- <a href=\"https://github.com/nex3z/FlowLayout\">FlowLayout</a>\n\\n- <a href=\"https://github.com/k3b/intent-intercept\">Intent Intercept</a>\n\\n- <a href=\"https://github.com/YarikSOffice/lingver\">Lingver</a>\n\\n- <a href=\"https://github.com/topjohnwu/Magisk\">Magisk</a>\n\\n- <a href=\"https://github.com/zhanghai/MaterialFiles\">Material Files</a>\n\\n- <a href=\"https://github.com/pluscubed/matlog\">MatLog</a>\n\\n- <a href=\"https://github.com/matrix-org/matrix-android-sdk\">Matrix Android SDK</a>\n\\n- <a href=\"https://github.com/jensstein/oandbackup\">OAndBackup</a>\n\\n- <a href=\"https://github.com/open-keychain/open-keychain\">Open Keychain</a>\n\\n- <a href=\"https://github.com/Aefyr/SAI\">SAI</a>\n\\n- <a href=\"https://github.com/RikkaApps/Shizuku\">Shizuku</a>\n\\n- <a href=\"https://github.com/eclipse/tm4e\">tm4e</a>\n\\n- <a href=\"https://github.com/tuyafeng/Watt\">Watt</a> </string>\n    <string name=\"credits\">Créditos</string>\n    <string name=\"third_party\">Bibliotecas e ícones de terceiros</string>\n    <string name=\"license\">Licença</string>\n    <string name=\"icon_picker\">Selecionar ícone</string>\n    <string name=\"class_name\">Nome da classe</string>\n    <string name=\"package_name\">Nome do pacote</string>\n    <string name=\"shortcut_name\">Nome do atalho</string>\n    <string name=\"create_shortcut\">Criar atalho</string>\n    <string name=\"starting_activity\">A iniciar atividade: <xliff:g id=\"activity_name\" example=\".main.MainActivity\">%1$s</xliff:g></string>\n    <string name=\"error_verbose_pin_shortcut\">O iniciador atual não suporta PinShortcut. Não foi possível criar o atalho.</string>\n    <string name=\"error_creating_shortcut\">Erro ao criar atalho</string>\n    <string name=\"empty_package_name\">Pacote sem nome</string>\n    <string name=\"main_activity\">Atividade principal</string>\n    <string name=\"user_id\">ID do utilizador</string>\n    <string name=\"installer_app\">Aplicação do instalador</string>\n    <string name=\"date_updated\">Data da atualização</string>\n    <string name=\"date_installed\">Data da instalação</string>\n    <string name=\"more_info\">Mais informações</string>\n    <string name=\"sdk_flags\">Flags</string>\n    <string name=\"sdk_max\">Destino</string>\n    <string name=\"sdk_min\">Min</string>\n    <string name=\"data_dir\">Diretório de dados</string>\n    <string name=\"source_dir\">Diretório de origem</string>\n    <string name=\"paths_and_directories\">Caminhos e diretórios</string>\n    <string name=\"user_app\">App do utilizador</string>\n    <string name=\"system_app\">App do sistema</string>\n    <string name=\"app_info\">Informações da aplicação</string>\n    <string name=\"version_name_with_code\">Versão <xliff:g id=\"version_name\" example=\"2.5.17\">%1$s</xliff:g> (<xliff:g id=\"version_code\" example=\"365\">%2$d</xliff:g>)</string>\n    <string name=\"sort\">Ordenar</string>\n    <string name=\"user\">Utilizador</string>\n    <string name=\"system\">Sistema</string>\n    <string name=\"app_not_installed\">Aplicação não instalada</string>\n    <string name=\"media_size\">Media</string>\n    <string name=\"obb_size\">Obb</string>\n    <string name=\"cache_size\">Cache</string>\n    <string name=\"data_size\">Dados</string>\n    <string name=\"about\">Sobre</string>\n    <string name=\"data_usage_msg\">Utilização de dados</string>\n    <string name=\"data_transmitted\">Dados enviados</string>\n    <string name=\"data_received\">Dados recebidos</string>\n    <string name=\"sort_by_target_sdk\">SDK de destino</string>\n    <string name=\"sort_by_domain\">Aplicações do utilizador</string>\n    <string name=\"sort_by_package_name\">Nome do pacote</string>\n    <string name=\"sort_by_app_label\">Rótulo da aplicação</string>\n    <string name=\"loading\">A carregar…</string>\n    <string name=\"error\">Erro</string>\n    <string name=\"manifest\">Manifesto</string>\n    <string name=\"input_features\">Recursos de introdução</string>\n    <string name=\"no_configurations\">Nenhuma configuração</string>\n    <string name=\"configurations\">Configurações</string>\n    <string name=\"app_signing_no_signatures\">Sem assinatura válida</string>\n    <string name=\"signatures\">Assinaturas</string>\n    <string name=\"sort_by_sha\">Assinatura</string>\n    <string name=\"blocking_rules\">Regras de bloqueio</string>\n    <string name=\"whats_new\">Novidades</string>\n    <string name=\"features\">Funcionalidades</string>\n    <string name=\"components\">Componentes</string>\n    <string name=\"trackers\">Rastreadores</string>\n    <string name=\"installed_version\">Versão instalada</string>\n    <string name=\"select_all\">Selecionar todos</string>\n    <string name=\"filter_apps_with_rules\">Com regras</string>\n    <string name=\"filter_system_apps\">Apps do sistema</string>\n    <string name=\"filter_user_apps\">Apps do utilizador</string>\n    <string name=\"filter\">Filtro</string>\n    <string name=\"package_name_is_installed_successfully\"><xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g> instalado</string>\n    <plurals name=\"no_of_splits\">\n        <item quantity=\"one\">%1$d APK</item>\n        <item quantity=\"many\">%1$d APKs</item>\n        <item quantity=\"other\">%1$d APKs</item>\n    </plurals>\n    <string name=\"failed_to_parse_some_numbers\">Não foi possível analisar alguns números</string>\n    <string name=\"only_works_in_root_or_adb_mode\">Funciona somente no modo Root ou ADB</string>\n    <string name=\"filtered_packages\">Pacotes filtrados</string>\n    <string name=\"input_signatures_description\">assinaturas de entrada com espaços, ex. <tt>com.facebook org.app2 com.app3</tt> etc.</string>\n    <string name=\"input_signatures\">Assinaturas de entrada</string>\n    <string name=\"failed_packages\">Pacotes que falharam</string>\n    <string name=\"no_tracker_found\">Nenhum rastreador encontrado</string>\n    <string name=\"clear_app_cache_description\">Limpar o cache de todas as apps</string>\n    <string name=\"clear_app_cache\">Limpar cache da app</string>\n    <string name=\"clear_data_from_uninstalled_apps_description\">Limpar dados das apps que foram desinstaladas com <tt>DONT_DELETE_DATA</tt></string>\n    <string name=\"clear_data_from_uninstalled_apps\">Limpar dados das apps desinstaladas</string>\n    <string name=\"block_components_dots\">Bloquear componentes…</string>\n    <string name=\"block_unblock_trackers_description\">Bloquear ou desbloquear componentes com anúncios e rastreamento em todos as aplicações instaladas</string>\n    <string name=\"clear_cache\">Limpar cache</string>\n    <string name=\"pref_import_existing_msg\">Adicione componentes desativados por outras aplicações ao App Manager. Tenha cuidado ao usar esta ferramenta, pois podem haver muitos falsos positivos. Escolha apenas as aplicações sobre as quais tenha certeza.</string>\n    <string name=\"pref_import_existing\">Importar regras guardadas</string>\n    <string name=\"source_code\">Código fonte</string>\n    <string name=\"update\">Atualizar</string>\n    <string name=\"install\">Instalar</string>\n    <plurals name=\"no_of_trackers\">\n        <item quantity=\"one\">%1$d rastreador</item>\n        <item quantity=\"many\">%1$d rastreadores</item>\n        <item quantity=\"other\">%1$d rastreadores</item>\n    </plurals>\n    <string name=\"manifest_viewer\">Visualizar manifesto</string>\n    <string name=\"external_apk_no_app_op\">APKs externos não possuem nenhuma operação da app</string>\n    <string name=\"never_ask\">Nunca perguntar</string>\n    <string name=\"launch_app\">Iniciar</string>\n    <string name=\"failed_to_deny_dangerous_app_ops\">Não foi possível negar todas as operações de apps perigosas</string>\n    <string name=\"failed_to_deny_dangerous_perms\">Não foi possível negar todas as permissões perigosas</string>\n    <string name=\"failed_to_reset_app_ops\">Não foi possível redefinir as operações da app</string>\n    <string name=\"failed_to_revoke_permission\">Não foi possível revogar a permissão</string>\n    <string name=\"failed_to_grant_permission\">Permissão não concedida</string>\n    <plurals name=\"alert_failed_to_disable_trackers\">\n        <item quantity=\"one\">Não foi possível desativar os rastreadores da %1$d app</item>\n        <item quantity=\"many\">Não foi possível desativar os rasteadores das %1$d apps</item>\n        <item quantity=\"other\">Não foi possível desativar os rasteadores das %1$d apps</item>\n    </plurals>\n    <string name=\"unknown_op\">Operação desconhecida</string>\n    <string name=\"sort_by_tracker_components\">Rastreadores</string>\n    <string name=\"deny_dangerous_permissions\">Negar permissões perigosas</string>\n    <string name=\"sort_by_denied_permissions\">Rejeitadas</string>\n    <string name=\"sort_by_dangerous_permissions\">Perigosas</string>\n    <string name=\"sort_by_permission_names\">Nome da permissão</string>\n    <string name=\"sort_by_app_ops_values\">Valor das operações da app</string>\n    <string name=\"shared_user_id\">ID de utilizador partilhado</string>\n    <string name=\"sort_by_shared_user_id\">ID de utilizador partilhado</string>\n    <string name=\"no_feature\">Sem recursos</string>\n    <string name=\"uses_feature\">Recursos utilizados</string>\n    <string name=\"group\">Grupo</string>\n    <string name=\"shared_libs\">Bibliotecas partilhadas</string>\n    <string name=\"declared_permission\">Permissões</string>\n    <string name=\"patterns_allowed\">Padrões permitidos</string>\n    <string name=\"write\">Escrever</string>\n    <string name=\"read\">Ler</string>\n    <string name=\"path_permissions\">Caminho para permissões</string>\n    <string name=\"grant_uri_permission\">Conceder permissões de URI</string>\n    <string name=\"flags\">Bandeiras</string>\n    <string name=\"soft_input\">Modo de introdução suave</string>\n    <string name=\"orientation\">Orientação</string>\n    <string name=\"no_service\">Nenhum serviço</string>\n    <string name=\"service\">Serviços</string>\n    <string name=\"authority\">Autoridade</string>\n    <string name=\"sort_by_last_update\">Última atualização</string>\n    <string name=\"task_affinity\">Afinidade de tarefas</string>\n    <string name=\"launch_mode\">Modo de inicialização</string>\n    <string name=\"no_providers\">Nenhum fornecedor</string>\n    <string name=\"providers\">Fornecedores</string>\n    <string name=\"no_receivers\">Nenhum recetor</string>\n    <string name=\"receivers\">Recetores</string>\n    <string name=\"no_activities\">Nenhuma atividade</string>\n    <string name=\"refresh\">Atualizar</string>\n    <string name=\"launch\">Iniciar</string>\n    <string name=\"activities\">Atividades</string>\n    <string name=\"require_no_permission\">Nenhuma permissão necessária</string>\n    <string name=\"permissions\">Utiliza permissões</string>\n    <string name=\"uninstall\">Desinstalar</string>\n    <string name=\"battery\">Bateria</string>\n    <string name=\"graphics\">Gráficos</string>\n    <string name=\"users\">Utilizadores</string>\n    <string name=\"languages\">Idiomas</string>\n    <string name=\"battery_capacity\">Capacidade</string>\n    <string name=\"memory\">Memória</string>\n    <string name=\"manufacturer\">Fabricante</string>\n    <string name=\"model\">Modelo</string>\n    <string name=\"brand_name\">Marca</string>\n    <string name=\"about_device\">Sobre o aparelho</string>\n    <string name=\"share\">Partilhar</string>\n    <string name=\"action\">Ação</string>\n    <string name=\"activity_result\">Resultado da atividade</string>\n    <string name=\"value\">Valor</string>\n    <string name=\"this_action_cannot_be_undone\">Esta ação não pode ser desfeita.</string>\n    <string name=\"not_verified\">Não verificado</string>\n    <string name=\"verified\">Verificado</string>\n    <string name=\"install_location_internal_only\">Apenas interno</string>\n    <string name=\"install_location\">Local de instalação</string>\n    <string name=\"installer\">Instalador</string>\n    <string name=\"comment\">Comentário</string>\n    <string name=\"close\">Fechar</string>\n    <string name=\"advanced\">Avançado</string>\n    <string name=\"simple\">Simples</string>\n    <string name=\"enabled\">Ativado</string>\n    <string name=\"choose\">Escolher</string>\n    <string name=\"options\">Opções</string>\n    <string name=\"off\">Desligado</string>\n    <string name=\"on\">Ligado</string>\n    <string name=\"profile_clear_data_msg\">Limpa os dados de apps</string>\n    <string name=\"profile_state\">Estado do perfil</string>\n    <string name=\"pref_mode_of_operations\">Modo de operação</string>\n    <string name=\"none\">Nenhum</string>\n    <string name=\"select_user\">Selecionar utilizador</string>\n    <string name=\"failed_to_duplicate_profile\">Não foi possível duplicar o perfil</string>\n    <string name=\"duplicate\">Duplicado</string>\n    <string name=\"new_profile\">Novo perfil</string>\n    <string name=\"input_profile_name_description\">O nome do perfil não pode conter quaisquer espaços.</string>\n    <string name=\"input_profile_name\">Nome do perfil</string>\n    <string name=\"in_progress\">Em progresso</string>\n    <string name=\"conversion_failed\">A conversão falhou.</string>\n    <string name=\"tap_to_submit_crash_report\">Toque para submeter o relatório do acidente.</string>\n    <string name=\"copy\">Copiar</string>\n    <string name=\"only_install\">Apenas instalar</string>\n    <string name=\"app_data_will_be_lost\">Os dados existentes serão perdidos.</string>\n    <string name=\"app_signing_signature_mismatch_for_system_apps\">Não foi possível instalar uma aplicação porque existe uma aplicação do sistema com uma assinatura diferente que tem o mesmo nome.</string>\n    <string name=\"do_you_want_to_uninstall_and_install\">Deseja desinstalar e instalar novamente a aplicação\\?</string>\n    <string name=\"usage_access_not_supported\">Não foi possível solicitar o acesso de utilização, uma vez que a página de definições correspondente não existe.</string>\n    <string name=\"non_critical_exts\">Extensões não críticas</string>\n    <string name=\"critical_exts\">Extensões Críticas</string>\n    <string name=\"rsa_exponent\">Exponente</string>\n    <string name=\"format\">Formato</string>\n    <string name=\"public_key\">Chave pública</string>\n    <string name=\"algorithm\">Algoritmo</string>\n    <string name=\"app_signing_signature\">Assinatura</string>\n    <string name=\"serial_no\">Número de série</string>\n    <string name=\"not_yet_valid\">Ainda não validado</string>\n    <string name=\"expired\">Expirado</string>\n    <string name=\"valid\">Válido</string>\n    <string name=\"validity\">Validade</string>\n    <string name=\"type\">Tipo</string>\n    <string name=\"expiry_date\">Data que expira</string>\n    <string name=\"issued_date\">Data de emissão</string>\n    <string name=\"uninstall_updates\">Desinstalar atualizações</string>\n    <string name=\"confirm_installation\">Confirmar instalação</string>\n    <string name=\"pref_compression_method\">Método de compressão</string>\n    <string name=\"rules\">Regras</string>\n    <string name=\"other\">Outro</string>\n    <string name=\"changes_not_saved\">Alterações não guardadas</string>\n    <string name=\"sort_by_memory_usage\">Utilização de memória</string>\n    <string name=\"sort_by_process_name\">Nome do processo</string>\n    <string name=\"apply_now\">Aplicar agora…</string>\n    <string name=\"no_profiles\">Sem perfis</string>\n    <string name=\"profiles\">Perfis</string>\n    <string name=\"cancel\">Cancelar</string>\n    <string name=\"input_backup_name_description\">O nome do backup não deve começar com um dígito nem deve conter qualquer espaço. Deixe-o vazio se quiser usar a data-hora atual.</string>\n    <string name=\"input_backup_name\">Nome do backup</string>\n    <string name=\"state_session_leader\">Líder da sessão</string>\n    <string name=\"state_locked_memory\">Memória bloqueada</string>\n    <string name=\"state_low_priority\">Baixa prioridade</string>\n    <string name=\"state_high_priority\">Alta prioridade</string>\n    <string name=\"state_unknown\">Desconhecido</string>\n    <string name=\"state_parked\">Estacionado</string>\n    <string name=\"state_dead\">Parado</string>\n    <string name=\"state_sleeping\">Adormecido</string>\n    <string name=\"touchscreen_finger\">Dedo</string>\n    <string name=\"touchscreen_no_touch\">Sem toque</string>\n    <string name=\"navigation_wheel\">Roda</string>\n    <string name=\"keyboard_no_keys\">Sem chaves</string>\n    <string name=\"_undefined\">Indefinido</string>\n    <string name=\"required\">Obrigatório</string>\n    <string name=\"orientation_user_portrait\">Retrato do utilizador</string>\n    <string name=\"orientation_user_landscape\">Paisagem do utilizador</string>\n    <string name=\"orientation_user\">Utilizador</string>\n    <string name=\"orientation_reverse_landscape\">Paisagem invertida</string>\n    <string name=\"orientation_reverse_portrait\">Retrato invertido</string>\n    <string name=\"orientation_portrait\">Retrato</string>\n    <string name=\"orientation_landscape\">Paisagem</string>\n    <string name=\"orientation_no_sensor\">Sem sensor</string>\n    <string name=\"orientation_locked\">Bloqueado</string>\n    <string name=\"orientation_full_user\">Utilizador completo</string>\n    <string name=\"orientation_full_sensor\">Sensor completo</string>\n    <string name=\"orientation_behind\">Atrás</string>\n    <string name=\"orientation_unspecified\">Não especificado</string>\n    <string name=\"launch_mode_single_task\">Tarefa única</string>\n    <string name=\"launch_mode_single_instance\">Instância única</string>\n    <plurals name=\"app_signing_signature_schemes_pl\">\n        <item quantity=\"one\">Esquema da assinatura</item>\n        <item quantity=\"many\">Esquemas de assinatura</item>\n        <item quantity=\"other\">Esquemas de assinatura</item>\n    </plurals>\n    <plurals name=\"missing_signatures\">\n        <item quantity=\"one\">%1$d assinatura em falta</item>\n        <item quantity=\"many\">%1$d assinaturas em falta</item>\n        <item quantity=\"other\">%1$d assinaturas em falta</item>\n    </plurals>\n    <string name=\"touchscreen\">Ecrã tátil</string>\n    <string name=\"reject_time\">Tempo de Rejeição</string>\n    <string name=\"accept_time\">Tempo de aceitação</string>\n    <plurals name=\"tracker_and_classes\">\n        <item quantity=\"one\">1 rasteador com <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g> class</item>\n        <item quantity=\"many\">1 rasteador com <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g> classes</item>\n        <item quantity=\"other\">1 rasteador com <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g> classes</item>\n    </plurals>\n    <string name=\"backup_internal_data_description\">Fazer backup de pastas de dados internos.</string>\n    <string name=\"backup_apk_files_description\">Fazer backup de ficheiros APK do diretório de origem, e incluir divisões.</string>\n    <plurals name=\"toast_log_truncated\">\n        <item quantity=\"one\">Registo grande demais, a mostrar a última %d linha.</item>\n        <item quantity=\"many\">Registo grande demais, a mostrar as últimas %d linhas.</item>\n        <item quantity=\"other\">Registo grande demais, a mostrar as últimas %d linhas.</item>\n    </plurals>\n    <string name=\"hidden\">Oculto</string>\n    <string name=\"suspended\">Suspenso</string>\n    <string name=\"orientation_right_to_left\">Da direita para a esquerda</string>\n    <string name=\"orientation_left_to_right\">Da esquerda para a direita</string>\n    <string name=\"orientation_follow_locale\">Seguir o local</string>\n    <string name=\"saf\">SAF</string>\n    <string name=\"pref_rules_msg\">Bloqueio imediato, importação/exportação/remoção de regras, etc.</string>\n    <string name=\"failed\">Falhou</string>\n    <string name=\"confirm_import_keystore\">Tem certeza de que deseja substituir o KeyStore existente\\? Esta ação não pode ser desfeita.</string>\n    <string name=\"import_keystore\">Importar KeyStore</string>\n    <string name=\"pref_import_export_keystore_msg\">Importar/exportar Bouncy Castle KeyStore (BKS) usado internamente pelo App Manager.</string>\n    <string name=\"pref_import_export_keystore\">Importar/exportar KeyStore</string>\n    <string name=\"latest_backup\">Backup mais recente</string>\n    <string name=\"gz_bz2_compressed\">%1$s comprimido</string>\n    <string name=\"pgp_aes_rsa_encrypted\">%1$s criptografado</string>\n    <string name=\"no_encryption\">Sem criptografia</string>\n    <string name=\"base_backup\">Backup base</string>\n    <string name=\"trackers_unblocked_successfully\">Os rastreadores estão agora desbloqueados</string>\n    <string name=\"trackers_blocked_successfully\">Os rastreadores estão agora bloqueados</string>\n    <string name=\"failed_to_unblock_trackers\">Não foi possível desbloquear os rastreadores</string>\n    <string name=\"failed_to_block_trackers\">Não foi possível bloquear os rastreadores</string>\n    <string name=\"profile_save_apk_msg\">Salva ficheiros APK em <tt>AppManager/apks</tt></string>\n    <string name=\"save_apk\">Salvar APK</string>\n    <string name=\"running_services\">Serviços em Execução</string>\n    <string name=\"view_logs\">Ver registos</string>\n    <string name=\"share_log\">Partilhar</string>\n    <string name=\"text_include_dmesg\">Incluir o registo do kernel</string>\n    <string name=\"omit_sensitive_info_summary\">Omitir informações sensíveis como urls da Web, números de telefone ou e-mails.</string>\n    <string name=\"omit_sensitive_info\">Omitir informações sensíveis</string>\n    <string name=\"undo\">Desfazer</string>\n    <string name=\"pause_unpause\">Tocar/Pausar</string>\n    <string name=\"collapse_all\">Colapsar Tudo</string>\n    <string name=\"expand_all\">Expandir Tudo</string>\n    <string name=\"file\">Ficheiro</string>\n    <string name=\"widget_start_recording\">Gravar\n\\nRegisto</string>\n    <string name=\"widget_recording_in_progress\">Gravando…</string>\n    <string name=\"unable_to_save_log\">Não é possível gravar o registo. Inseriu um nome de ficheiro válido\\?</string>\n    <string name=\"toast_invalid_selection\">Seleção inválida. Por favor, tente de novo.</string>\n    <string name=\"toast_invalid_level\">Nome de nível inválido: %s</string>\n    <string name=\"pref_display_limit_hint\">Digite um número válido entre %1$d e %2$d.</string>\n    <string name=\"text_include_device_info\">Incluir informações do aparelho</string>\n    <string name=\"text_filter_text\">Texto do filtro</string>\n    <string name=\"text_filter_ellipsis\">Filtro…</string>\n    <string name=\"subject_log_report\">Relatório de registo</string>\n    <string name=\"start_recording_log\">Gravar</string>\n    <string name=\"settings\">Configurações</string>\n    <string name=\"send_log_title\">Enviar registo</string>\n    <string name=\"save_log\">Gravar registo</string>\n    <string name=\"save_as\">Gravar como…</string>\n    <string name=\"record_log\">Gravar registo</string>\n    <string name=\"pref_show_timestamp_title\">Mostrar Pid e Timestamp</string>\n    <string name=\"pref_show_timestamp_summary\">Mostrar id de processo e horário quando expandido.</string>\n    <string name=\"pref_log_write_period_title\">Período de Gravação</string>\n    <string name=\"pref_log_write_period_summary\">Ao gravar, grave no cartão SD a cada %1$d linhas.</string>\n    <string name=\"pref_log_line_period_error\">Por favor, digite um número inteiro entre 1 e 1000.</string>\n    <string name=\"pref_expanded_by_default_title\">Expandir por padrão</string>\n    <string name=\"pref_expanded_by_default_summary\">Mostrar texto de registo completo por padrão.</string>\n    <string name=\"pref_filter_pattern_title\">Filtrar Tags</string>\n    <string name=\"pref_filter_pattern_summary\">Filtrar as tags selecionadas a partir dos registos.</string>\n    <string name=\"pref_display_limit_title\">Limite de exibição de registo</string>\n    <string name=\"pref_display_limit_summary\">Mostrar apenas os últimos %1$d logs para evitar erros de memória.</string>\n    <string name=\"pref_default_log_level_title\">Nível de registo padrão</string>\n    <string name=\"pref_default_log_level_summary\">Nível de registo na inicialização, ao abrir ficheiros e ao gravar.</string>\n    <string name=\"pref_cat_configuration\">Configuração</string>\n    <string name=\"pref_cat_appearance\">Aparência</string>\n    <string name=\"pref_cat_advanced\">Avançado</string>\n    <string name=\"pref_buffer_title\">Buffer de registo(s)</string>\n    <string name=\"open\">Abrir</string>\n    <string name=\"notification_title\">Gravação de registo em andamento</string>\n    <string name=\"notification_ticker\">Gravação de registo iniciada</string>\n    <string name=\"notification_subtext\">Toque para parar de gravar</string>\n    <string name=\"no_saved_logs\">Nenhum registro salvo.</string>\n    <string name=\"manage_saved_logs\">Gerir registos gravados</string>\n    <string name=\"log_saved\">Registo gravado.</string>\n    <string name=\"log_recording_started\">A gravação do registo começou.</string>\n    <string name=\"log_level\">Nível de registo</string>\n    <string name=\"log_cleared\">Registos limpos</string>\n    <string name=\"filter_choice_tag\">Tag</string>\n    <string name=\"filter_choice_pid\">PID</string>\n    <string name=\"filter_choice\">Pesquisar por</string>\n    <string name=\"enter_good_filename\">Por favor, digite um nome de ficheiro válido.</string>\n    <string name=\"enter_filename\">Digite nome de ficheiro</string>\n    <string name=\"dialog_compiling_log\">A compilar o registo…</string>\n    <string name=\"delete_saved_log\">Eliminar registos gravados</string>\n    <string name=\"copy_to_clipboard\">Copiar para área de transferência</string>\n    <plurals name=\"file_deletion_confirmation\">\n        <item quantity=\"one\">%d ficheiro será eliminado</item>\n        <item quantity=\"many\">%d ficheiros serão eliminados</item>\n        <item quantity=\"other\">%d ficheiros serão eliminados</item>\n    </plurals>\n    <string name=\"add_filter_ellipsis\">Adicionar filtro…</string>\n    <string name=\"add_filter\">Adicionar filtro</string>\n    <string name=\"log_level_fatal\">Fatal</string>\n    <string name=\"log_level_warn\">Aviso</string>\n    <string name=\"log_level_verbose\">Prolixo</string>\n    <string name=\"log_level_info\">Informação</string>\n    <string name=\"log_level_error\">Erro</string>\n    <string name=\"log_level_debug\">Depurar</string>\n    <string name=\"filename\">Nome do ficheiro</string>\n    <string name=\"restart_log_viewer_to_see_changes\">Reinicie a janela do visualizador de registo para ver as alterações.</string>\n    <string name=\"pref_log_viewer_msg\">Configurar como os registos são exibidos.</string>\n    <string name=\"log_viewer\">Visualizador de registo</string>\n    <string name=\"pref_installer_msg\">Configurar comportamentos do instalador de apps.</string>\n    <string name=\"expiry_date_cannot_be_empty\">A data de validade não pode estar vazia.</string>\n    <string name=\"signing_key\">Assinando chave</string>\n    <string name=\"failed_to_read_keystore\">Não foi possível ler a KeyStore.</string>\n    <string name=\"alias_pass\">Palavra-passe do alias</string>\n    <string name=\"choose_an_alias\">Escolha um alias</string>\n    <string name=\"found_no_alias_in_keystore\">Nenhum alias encontrado na KeyStore!</string>\n    <string name=\"new_alias_password\">Nova palavra-passe de alias</string>\n    <string name=\"import_key\">Importar chave</string>\n    <string name=\"pem_file\">Ficheiro PEM</string>\n    <string name=\"pk8_file\">Ficheiro PKCS #8 (PK8)</string>\n    <string name=\"pem_and_pk8\">PEM e PKCS #8 (PK8)</string>\n    <string name=\"pkcs12_keystore\">PKCS #12 KeyStore (P12)</string>\n    <string name=\"bouncy_castle_keystore\">Bouncy Castle KeyStore (BKS)</string>\n    <string name=\"java_keystore\">Java KeyStore (JKS)</string>\n    <string name=\"keystore_pass\">Palavra-passe da keyStore</string>\n    <string name=\"keystore_file\">Ficheiro KeyStore</string>\n    <string name=\"country_name\" tools:ignore=\"TypographyOther\">Nome do país (C)</string>\n    <string name=\"state_name\">Nome do Estado (ST)</string>\n    <string name=\"locality_name\">Localidade (cidade (city)) nome (L)</string>\n    <string name=\"organization_name\">Nome da organização (O)</string>\n    <string name=\"organization_unit\">Unidade de organização (OU)</string>\n    <string name=\"common_name\">Nome comum (CN)</string>\n    <string name=\"input_key_password\">Palavra-passe da chave</string>\n    <string name=\"failed_to_load_key\">Não foi possível carregar a chave.</string>\n    <string name=\"key_not_set\">Não inserida.</string>\n    <string name=\"use_default\">Usar padrão</string>\n    <string name=\"invalid_rsa_key_size\">Tamanho da chave inválida para criptografia RSA. O tamanho da chave pode ser 1024, 2048 ou 4096 bits.</string>\n    <string name=\"crypto_key_size\">Tamanho da chave</string>\n    <string name=\"invalid_aes_key_size\">Tamanho da chave inválida para criptografia AES. O tamanho da chave pode ser de 128 ou 256 bits.</string>\n    <string name=\"failed_to_initialize_key_store\">Não foi possível inicializar a keystore do App Manager.</string>\n    <string name=\"failed_to_save_key\">Não foi possível gravar a chave.</string>\n    <string name=\"generate_key\">Gerar</string>\n    <string name=\"input_key\">Insira uma chave (em hexadecimal)</string>\n    <string name=\"filter_apps_without_backups\">Sem backups</string>\n    <string name=\"uninstalled_apps\">Apps desinstaladas</string>\n    <string name=\"installer_app_message\">Selecione <b>Escolher</b> para escolher entre os apps instalados ou selecione <b>Personalizado</b> para especificar um nome de pacote personalizado.</string>\n    <string name=\"specify_custom_name\">Personalizado</string>\n    <string name=\"verified_using_unreliable_hash\">Verificado usando hash não confiável</string>\n    <string name=\"working_on_adb_mode\">Trabalhando no modo ADB</string>\n    <string name=\"screen_lock_not_enabled\">Por favor, escolha um bloqueio de ecrã nas configurações do Android ou limpe os dados do app.</string>\n    <string name=\"isolated\">Isolado</string>\n    <string name=\"last_actions\">Últimas ações</string>\n    <string name=\"pref_enable_disable_features_msg\">Ativar ou desativar funções no App Manager.</string>\n    <string name=\"enable_disable_features\">Ativar/desativar funções</string>\n    <string name=\"installed_apps\">Apps instaladas</string>\n    <string name=\"restart_to_reflect_changes\">Deve reiniciar o aparelho imediatamente para usar as novas alterações.</string>\n    <string name=\"failed_to_change_ssaid\">Não foi possível mudar o SSAID</string>\n    <string name=\"copied_to_clipboard\">Copiado à área de transferência.</string>\n    <string name=\"ssaid_info\">SSAID (<tt>Settings.Secure.ANDROID_ID</tt>) é um identificador de aparelho atribuído a cada app (do Android 8 \\\"Oreo\\\" em diante). É amplamente utilizado por apps para rastrear utilizadores.</string>\n    <string name=\"ssaid\">SSAID</string>\n    <string name=\"list_options\">Opções de lista</string>\n    <string name=\"reverse\">Inverter</string>\n    <string name=\"os_version\">Versão do SO</string>\n    <string name=\"add\">Adicionar</string>\n    <string name=\"add_to_profile\">Adicionar ao perfil</string>\n    <string name=\"initializing\">Iniciando…</string>\n    <string name=\"net_policy\">Política de rede</string>\n    <string name=\"has_net_policy\">Política de rede</string>\n    <string name=\"choose_what_to_do\">Escolha o que fazer.</string>\n    <string name=\"enable_battery_optimization\">Ativar otimização de bateria\\?</string>\n    <string name=\"battery_optimization\">Otimização de bateria</string>\n    <string name=\"no_battery_optimization\">Nenhuma otimização de bateria</string>\n    <string name=\"type_uri\">URI</string>\n    <string name=\"type_string_array_list\">Lista de cadeias</string>\n    <string name=\"type_string_array\">Matriz de cadeias</string>\n    <string name=\"type_float_array_list\">Lista de números decimais</string>\n    <string name=\"type_float_array\">Matriz de números decimais</string>\n    <string name=\"type_long_array_list\">Lista de números inteiros longos</string>\n    <string name=\"type_long_array\">Matriz de números inteiros longos</string>\n    <string name=\"type_int_array_list\">Lista de números inteiros</string>\n    <string name=\"type_int_array\">Matriz de números inteiros</string>\n    <string name=\"type_component_name\">Nome do Componente</string>\n    <string name=\"type_null\">Nenhum valor</string>\n    <string name=\"screen_lock_msg\">Bloqueie o App Manager usando o bloqueio de ecrã do Android</string>\n    <string name=\"screen_lock\">Bloqueio de ecrã</string>\n    <string name=\"unlock_app_manager\">Desbloquear App Manager</string>\n    <string name=\"sd_card\">Cartão SD</string>\n    <string name=\"external_storage\">Armazenamento Externo</string>\n    <string name=\"internal_storage\">Armazenamento Interno</string>\n    <string name=\"back_up\">Fazer backup</string>\n    <string name=\"drm_free_apkm_msg\">O ficheiro APKM é DRM-free, não há necessidade de convertê-lo em APKS.</string>\n    <string name=\"restore_msg\">Restaurar apps com dados</string>\n    <string name=\"backup_msg\">Fazer backup de apps com dados</string>\n    <string name=\"restore_latest_msg\">Restaure apps já instaladas cujos códigos de versão são superiores ao código de versão instalado.</string>\n    <string name=\"restore_latest\">Restaurar backups mais recentes</string>\n    <string name=\"restore_not_installed_msg\">Restaure o backup base para apps que não estão instalados no momento.</string>\n    <string name=\"restore_not_installed\">Restaurar apps não instalados</string>\n    <string name=\"restore_all_msg\">Restaure o backup base de todas as apps com backup.</string>\n    <string name=\"restore_all\">Restaurar todas as apps</string>\n    <string name=\"backup_apps_with_changes_msg\">Refaça backups para apps com mudanças desde o último backup. Elas incluem mudanças de tamanho, versão, última vez que foi iniciado.</string>\n    <string name=\"backup_apps_with_changes\">Fazer backup de apps com mudanças</string>\n    <string name=\"redo_existing_backups_msg\">Refaça o backup para apps instalados com backups anteriores.</string>\n    <string name=\"redo_existing_backups\">Refazer backups existentes</string>\n    <string name=\"verify_and_redo_backups_msg\">Verifique a integridade dos backups anteriores e refaça os backups para os quais o check-up de integridade falhou.</string>\n    <string name=\"verify_and_redo_backups\">Verificar e refazer backups</string>\n    <string name=\"backup_apps_without_backups_msg\">Fazer backup de apps sem nenhum backup anterior.</string>\n    <string name=\"backup_apps_without_backups\">Fazer backup de apps sem backups</string>\n    <string name=\"backup_all_apps_msg\">Fazer backup de todos as apps instaladas.</string>\n    <string name=\"backup_all_apps\">Fazer backup de todas as apps</string>\n    <string name=\"backup_custom_users_description\">Realizar backups apenas para os utilizadores especificados</string>\n    <string name=\"backup_custom_users\">Utilizadores personalizados</string>\n    <string name=\"bootloader\">Bootloader</string>\n    <string name=\"encrypted\">Criptografado</string>\n    <string name=\"unencrypted\">Não criptografado</string>\n    <string name=\"no_volumes_found\">Não foi possível encontrar nenhum volume com permissão de gravação.</string>\n    <string name=\"pref_backup_volume_msg\">Selecione o volume ou o disco onde os backups serão armazenados.</string>\n    <string name=\"backup_volume\">Volume do Backup</string>\n    <string name=\"pref_backup_restore_msg\">Personalizar backup/restauração.</string>\n    <string name=\"disable_background_run_description\">Define o modo <i>ignore</i> para as seguintes operações de app: <tt>RUN_IN_BACKGROUND</tt> (do Android 7.0) e <tt>RUN_ANY_IN_BACKGROUND</tt> (do Android 9).</string>\n    <string name=\"failed_to_enable_magisk_hide\">O MagiskHide não pôde ser ativado</string>\n    <string name=\"failed_to_disable_magisk_hide\">O MagiskHide não pôde ser desativado</string>\n    <string name=\"window_size\">Tamanho da janela</string>\n    <string name=\"refresh_rate\">Taxa de atualização</string>\n    <string name=\"scaling_factor\">Fator de dimensionamento</string>\n    <string name=\"size\">Tamanho</string>\n    <string name=\"density\">Densidade</string>\n    <string name=\"screen\">Ecrã</string>\n    <string name=\"hardware\">Hardware</string>\n    <string name=\"permissive\">Permissivo</string>\n    <string name=\"enforcing\">Enforcing</string>\n    <string name=\"selinux\">SELinux</string>\n    <string name=\"patch_level\">Nível do Patch</string>\n    <string name=\"backup_skip_signature_checks_description\">Restaure backups que falham na verificação do checksum ou têm assinaturas de APK diferentes dos backups anteriores deles.</string>\n    <string name=\"backup_multiple_description\">Crie um backup <i>nomeado</i> ao invés do backup base.</string>\n    <string name=\"backup_rules_description\">Faça o backup de regras configuradas dentro do App Manager. <font fgcolor=\"#ff0000\">A depender das permissões, nem todas as regras podem ser reaplicadas durante a restauração.</font></string>\n    <string name=\"backup_extras_description\">Faça o backup das permissões da app, opções de economia de bateria e uso de dados, estado do MagiskHide, SSAID, etc. <font fgcolor=\"#ff0000\">A depender das permissões, nem todos os extras podem ser restaurados.</font></string>\n    <string name=\"backup_extras\">Extras</string>\n    <string name=\"backup_cache_description\">Faz o backup das pastas <b>cache</b>, <b>no_cache</b> e <b>no_backup</b>.</string>\n    <string name=\"backup_obb_media_description\">Faça o backup das pastas OBB e de mídia.</string>\n    <string name=\"backup_external_data_description\">Faça o backup de pastas de dados externas.</string>\n    <string name=\"set_mode_for_app_ops_dots\">Definir modo para operações de app…</string>\n    <string name=\"security\">Segurança</string>\n    <string name=\"cpu\">CPU</string>\n    <string name=\"vendor\">Fornecedor</string>\n    <string name=\"gles_version\">Versão do OpenGL ES</string>\n    <string name=\"no_of_cores\">Núcleos</string>\n    <string name=\"support_architectures\">Arquiteturas suportadas</string>\n    <string name=\"security_providers\">Provedores de segurança</string>\n    <string name=\"kernel\">Kernel</string>\n    <string name=\"board_name\">Placa</string>\n    <string name=\"pref_about_device_msg\">Informações básicas do aparelho, incluindo Sistema Android, CPU, GPU, RAM, bateria, etc.</string>\n    <string name=\"set_custom_app_op\">Definir a operação de app personalizada</string>\n    <string name=\"interceptor\">Interceptador</string>\n    <string name=\"resend_intent\">Reenviar Intenção</string>\n    <string name=\"extras\">Extras</string>\n    <string name=\"category\">Categorias</string>\n    <string name=\"uri\">URI</string>\n    <string name=\"mime_type\">Tipo de MIME</string>\n    <string name=\"result_code\">Código resultante</string>\n    <string name=\"send_edited_intent\">Enviar intenção editada</string>\n    <string name=\"matching_activities\">Atividades correspondentes</string>\n    <string name=\"filter_apps_with_splits\">Com divisões</string>\n    <string name=\"set_app_op_mode\">Definir o modo da operação de app</string>\n    <string name=\"magisk_hide_enabled\">MagiskHide</string>\n    <string name=\"pref_backup_android_keystore_msg\">Nem todas as apps funcionarão após serem restaurados. Restaurar o KeyStore não funciona na maioria dos aparelhos.</string>\n    <string name=\"pref_backup_android_keystore\">Backup de apps com Android KeyStore</string>\n    <string name=\"keep_data_and_app_signing_signatures\">Mantenha os dados e assinaturas</string>\n    <string name=\"no_app_ops_permission\">Sem permissão para mostrar as operações de app</string>\n    <string name=\"input_keystore_alias_pass_msg\">Toque aqui para fornecer uma palavra-passe para %1$s</string>\n    <string name=\"input_keystore_alias_pass_description\">Insirir palavra-passe para o alias <b>%1$s</b>. Pode deixar isso vazio se a palavra-passe for a mesma da palavra-passe do KeyStore.</string>\n    <string name=\"input_keystore_alias_pass\">Palavra-passe para alias <b>%1$s</b></string>\n    <string name=\"input_keystore_pass_msg\">Toque aqui para digitar a palavra-passe do KeyStore</string>\n    <string name=\"input_keystore_pass_description\">Digite a palavra-passe do KeyStore do App Manager. Se ve isto pela primeira vez, use um gerador de palavras-passe para gerar uma palavra-passe e salve-a num lugar seguro antes de inseri-la aqui.</string>\n    <string name=\"input_keystore_pass\">Inserir palavra-passe do KeyStore</string>\n    <string name=\"splits\">Divisões</string>\n    <string name=\"source_stamp_verified\">SourceStamp verificado.</string>\n    <string name=\"pref_signature_schemes_msg\">Pelo menos os esquemas v1 e v2 devem ser selecionados para uma maior compatibilidade. O esquema v4 requer o v2 ou v3.</string>\n    <string name=\"v4_scheme\">Esquema v4 (desde o Android 11)</string>\n    <string name=\"v3_scheme\">Esquema v3 (desde o Android 9)</string>\n    <string name=\"v2_scheme\">Esquema v2 (desde o Android 7.0)</string>\n    <string name=\"v1_scheme\">Esquema v1 (desde o Android 1.0)</string>\n    <string name=\"pref_apk_signing_msg\">Definir esquemas de assinatura, chave de assinatura personalizada, etc.</string>\n    <string name=\"apk_signing\">Assinatura do APK</string>\n    <string name=\"app_signing_signature_schemes\">Esquemas de assinatura</string>\n    <string name=\"pref_sign_apk_msg\">Assinar ficheiros APK antes de instalá-los.</string>\n    <string name=\"pref_sign_apk\">Assinar APK</string>\n    <string name=\"install_location_prefer_external\">Preferir externo</string>\n    <string name=\"no_root\">Sem root</string>\n    <string name=\"root\">Root</string>\n    <string name=\"user_profile_with_id\">Perfil: %1$s (%2$d)</string>\n    <string name=\"input_permissions_description\">Insira permissões com espaços, p. ex. <tt>com.permission.GET_ACCOUNTS android.permission.ACCESS_MEDIA_LOCATION</tt> etc. Use <tt>*</tt> para solicitar todas as permissões.</string>\n    <string name=\"input_permissions\">Inserir permissões</string>\n    <string name=\"profile_state_msg\">Estado de ligado/desligado personalizado para este perfil</string>\n    <string name=\"profile_block_trackers_msg\">Bloqueia os rasteadores nas apps</string>\n    <string name=\"profile_clear_cache_msg\">Limpa o cache de app dos apps</string>\n    <string name=\"profile_force_stop_msg\">Força a parada de apps</string>\n    <string name=\"allow_routine_ops_msg\">Permitir que o perfil seja usado nas operações de rotina</string>\n    <string name=\"allow_routine_ops\">Permitir operações de rotina</string>\n    <string name=\"adb_over_tcp\">ADB sobre TCP</string>\n    <string name=\"send_selected\">Enviar selecionado</string>\n    <string name=\"ecc\">Criptografia de curva elíptica</string>\n    <string name=\"rsa\">RSA</string>\n    <string name=\"aes\">AES</string>\n    <string name=\"pref_encryption_msg\">Criptografia para backups.</string>\n    <string name=\"encryption\">Criptografia</string>\n    <string name=\"un_apkm\">UnApkm</string>\n    <string name=\"select_apk\">Selecionar APK</string>\n    <string name=\"send_crash_report\">Enviar relatório de paragem</string>\n    <string name=\"am_crashed\">O App Manager acabou de parar</string>\n    <string name=\"filter_running_apps\">Apps em execução</string>\n    <string name=\"view_missing_signatures\">Toque para visualizar ou enviar assinaturas ainda não presentes no banco de dados de bibliotecas do App Manager.</string>\n    <string name=\"tap_to_see_details\">Toque para ver detalhes</string>\n    <string name=\"lib_details\">Detalhes da biblioteca</string>\n    <string name=\"no_libs\">Nenhuma biblioteca</string>\n    <string name=\"scanner\">Analisador</string>\n    <string name=\"sys_config\">Configurações do Sistema</string>\n    <string name=\"app_signing_install_without_data_loss\">Se desligou a verificação de assinatura, pode usar a opção <b>Apenas instalar</b> para instalar a app sem perder dados.</string>\n    <string name=\"dsa_affine_y\">Atribuir coordenada y</string>\n    <string name=\"dsa_affine_x\">Atribuir coordenada x</string>\n    <string name=\"rsa_modulus\">Módulo</string>\n    <string name=\"checksums\">Checksums</string>\n    <string name=\"issuer\">Emissor</string>\n    <string name=\"subject\">Assunto</string>\n    <string name=\"filter_apps_with_backups\">Com backups</string>\n    <string name=\"sort_by_backup\">Com backup</string>\n    <string name=\"failed_to_uninstall_updates\">Não foi possível desinstalar as atualizações da app <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g>.</string>\n    <string name=\"update_uninstalled_successfully\">As atualizações da app <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g> foram desinstaladas.</string>\n    <string name=\"allow_open_pgp_operation\">Toque para permitir que o App Manager use o OpenPGP</string>\n    <string name=\"pref_backup_flags_msg\">Adicionar uma predefinição para opções de cópias de segurança remove o incómodo de selecionar flags de cada vez que faz cópias de segurança/restaura.</string>\n    <string name=\"sort_by_apps_first\">Apps primeiro</string>\n    <string name=\"sort_by_process_id\">ID do processo</string>\n    <string name=\"filter_apps\">Apps</string>\n    <string name=\"no_apps\">Nenhuma app</string>\n    <string name=\"apps\">Apps</string>\n    <string name=\"routine_ops\">Operações de rotina</string>\n    <string name=\"keystore\">KeyStore</string>\n    <string name=\"open_pgp_provider\">Provedor OpenPGP</string>\n    <string name=\"systemless_app\">App sem sistema</string>\n    <string name=\"ok\">OK</string>\n    <string name=\"downgrade\">Downgrade</string>\n    <string name=\"process_state_with_extra\">Estado: <xliff:g id=\"process_state\" example=\"Sleeping\">%1$s</xliff:g> (<xliff:g id=\"state_extra\" example=\"High priority\">%2$s</xliff:g>)</string>\n    <string name=\"process_state\">Estado: <xliff:g id=\"process_state\" example=\"Sleeping\">%1$s</xliff:g></string>\n    <string name=\"state_multithreaded\">Multitarefa</string>\n    <string name=\"state_foreground\">Primeiro plano</string>\n    <string name=\"state_waking\">Acordando</string>\n    <string name=\"state_wake_kill\">Encerrar ao iniciar</string>\n    <string name=\"state_idle\">Parado</string>\n    <string name=\"state_zombie\">Zombie</string>\n    <string name=\"state_trace_stop\">Rastreamento parado</string>\n    <string name=\"state_device_io\">I/O do aparelho</string>\n    <string name=\"touchscreen_stylus\">Caneta</string>\n    <string name=\"navigation_trackball\">Trackball</string>\n    <string name=\"navigation_dial_pad\">Teclado numérico</string>\n    <string name=\"navigation_no_nav\">Sem navegação</string>\n    <string name=\"keyboard_12_keys\">12 teclas</string>\n    <string name=\"keyboard_qwerty\">QWERTY</string>\n    <string name=\"orientation_sensor\">Sensor</string>\n    <string name=\"orientation_sensor_portrait\">Retrato, seguindo o sensor</string>\n    <string name=\"orientation_sensor_landscape\">Paisagem, seguindo o sensor</string>\n    <string name=\"launch_mode_single_top\">Topo único</string>\n    <string name=\"launch_mode_multiple\">Vários</string>\n    <string name=\"locale_split_for_base_apk\"><xliff:g id=\"split_name\" example=\"English\">%1$s</xliff:g> para o APK base</string>\n    <string name=\"locale_split_for_feature\">Idioma <xliff:g id=\"split_name\" example=\"English\">%1$s</xliff:g> para a função <xliff:g id=\"feature_name\" example=\"Visualizer\">%2$s</xliff:g></string>\n    <string name=\"abi_split_for_base_apk\">Código <xliff:g id=\"split_name\" example=\"arm64_v8a\">%1$s</xliff:g> para o APK base</string>\n    <string name=\"abi_split_for_feature\">Código <xliff:g id=\"split_name\" example=\"arm64_v8a\">%1$s</xliff:g> para <xliff:g id=\"feature_name\" example=\"Visualizer\">%2$s</xliff:g></string>\n    <string name=\"density_split_for_base_apk\">Recursos de <xliff:g id=\"split_name\" example=\"xxdpi\">%1$s</xliff:g> (<xliff:g id=\"dpi_no\" example=\"480\">%2$d</xliff:g> DPI) para o APK base</string>\n    <string name=\"density_split_for_feature\">Recursos de <xliff:g id=\"split_name\" example=\"xxdpi\">%1$s</xliff:g> (<xliff:g id=\"dpi_no\" example=\"480\">%2$d</xliff:g> DPI) para a função <xliff:g id=\"feature_name\" example=\"Visualizer\">%3$s</xliff:g></string>\n    <string name=\"unknown_split_for_base_apk\"><xliff:g id=\"split_name\" example=\"some_split\">%1$s</xliff:g> para o APK base</string>\n    <string name=\"unknown_split_for_feature\"><xliff:g id=\"split_name\" example=\"some_split\">%1$s</xliff:g> para a função <xliff:g id=\"feature_name\" example=\"Visualizer\">%2$s</xliff:g></string>\n    <string name=\"split_feature_name\">Função: <xliff:g id=\"feature_name\" example=\"Visualizer\">%1$s</xliff:g></string>\n    <string name=\"base_apk\">APK Base</string>\n    <string name=\"auto\">Automático</string>\n    <string name=\"backup_obb_media\">OBB e Mídia</string>\n    <plurals name=\"verified_with_warning\">\n        <item quantity=\"one\">Verificado com %d aviso</item>\n        <item quantity=\"many\">Verificadas com %d avisos</item>\n        <item quantity=\"other\">Verificadas com %d avisos</item>\n    </plurals>\n    <plurals name=\"libraries\">\n        <item quantity=\"one\">%1$d biblioteca</item>\n        <item quantity=\"many\">%1$d bibliotecas</item>\n        <item quantity=\"other\">%1$d bibliotecas</item>\n    </plurals>\n    <plurals name=\"classes\">\n        <item quantity=\"one\">%1$d classe</item>\n        <item quantity=\"many\">%1$d classes</item>\n        <item quantity=\"other\">%1$d classes</item>\n    </plurals>\n    <plurals name=\"backup_exists_are_you_sure\">\n        <item quantity=\"one\">O backup já existe. Tem a certeza\\?</item>\n        <item quantity=\"many\">Várias aplicações já tem um backup. Tem certeza\\?</item>\n        <item quantity=\"other\">Várias aplicações já tem um backup. Tem certeza\\?</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_set_app_ops\">\n        <item quantity=\"one\">%1$d Não foi possível configurar a operação da app selecionada</item>\n        <item quantity=\"many\">%1$d Não foi possível configurar a operação das apps selecionadas</item>\n        <item quantity=\"other\">%1$d Não foi possível configurar a operação das apps selecionadas</item>\n    </plurals>\n    <string name=\"internal_data\">Dados internos</string>\n    <string name=\"termux\">Termux</string>\n    <string name=\"input_app_ops_description_profile\">Insira nomes de operações de aplicações e/ou constantes com espaços, p. ex. <tt>WAKE_LOCK 63 72 CAMERA</tt> etc. Use <tt>*</tt> para solicitar todas as operações de aplicações configuradas.</string>\n    <string name=\"input_app_ops_description\">Insira nomes e/ou constantes de operações de aplicações com espaços, por exemplo <tt>WAKE_LOCK 63 72 CAMERA</tt> etc.</string>\n    <string name=\"input_app_ops\">Inserir operações na app</string>\n    <string name=\"deny_app_ops_description\">Defina um modo para as operações da aplicação identificadas pelos valores das constantes, ou seja, <tt>63</tt> ou <tt>RUN_IN_BACKGROUND</tt></string>\n    <string name=\"source_code_links\"><a href=\"https://github.com/MuntashirAkon/AppManager\">GitHub</a> • <a href=\"https://gitlab.com/muntashir/AppManager\">GitLab</a> • <a href=\"https://0xacab.org/muntashir/AppManager\">Riseup</a> • <a href=\"https://codeberg.org/muntashir/AppManager\">Codeberg</a></string>\n    <plurals name=\"no_of_components\">\n        <item quantity=\"one\">%1$d componente</item>\n        <item quantity=\"many\">%1$d componentes</item>\n        <item quantity=\"other\">%1$d componentes</item>\n    </plurals>\n    <string name=\"changelog\">Histórico de Atualizações</string>\n    <string name=\"one_click_ops\">Operações num Clique</string>\n    <string name=\"user_with_id\">Utilizador: <xliff:g id=\"user_id\" example=\"0\">%1$d</xliff:g></string>\n    <plurals name=\"other_trackers_and_classes\">\n        <item quantity=\"one\"><xliff:g id=\"tracker_no\" example=\"8\">%1$d</xliff:g> rasteadores com classes <xliff:g id=\"class_no\" example=\"50\">%2$d</xliff:g></item>\n        <item quantity=\"many\"><xliff:g id=\"tracker_no\" example=\"8\">%1$d</xliff:g> rasteadores com classes <xliff:g id=\"class_no\" example=\"50\">%2$d</xliff:g></item>\n        <item quantity=\"other\"><xliff:g id=\"tracker_no\" example=\"8\">%1$d</xliff:g> rasteadores com classes <xliff:g id=\"class_no\" example=\"50\">%2$d</xliff:g></item>\n    </plurals>\n    <plurals name=\"two_trackers_and_classes\">\n        <item quantity=\"one\">2 rasteadores <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g>com classes</item>\n        <item quantity=\"many\">2 rasteadores <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g>com classes</item>\n        <item quantity=\"other\">2 rasteadores <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g>com classes</item>\n    </plurals>\n    <string name=\"app_signing_signatures\">Assinaturas</string>\n    <string name=\"no_changes\">Sem modificações</string>\n    <string name=\"pref_display_changes_msg\">Mostrar alterações na versão, rasteadores, componentes, permissões, assinaturas, SDK, etc. de uma forma controlada de versão.</string>\n    <string name=\"pref_display_changes\">Mostrar alterações</string>\n    <string name=\"failed_to_prevent_background_run\">Não foi possível evitar que %1$s fosse executado em segundo plano</string>\n    <string name=\"unknown_net_policy\">Política de rede desconhecida (%1$s - %2$X)</string>\n    <string name=\"port_number_invalid\">Número de porta inválido.</string>\n    <string name=\"port_number_empty\">O número da porta está vazio.</string>\n    <string name=\"adb_connect_port_number_description\">O número da porta está localizado no <b> endereço IP e porta </b> logo abaixo da seção <b> Nome do dispositivo </b>.</string>\n    <string name=\"port_number\">Porta</string>\n    <string name=\"adb_connect\">Conectar</string>\n    <string name=\"wireless_debugging\">Depuração de erros Wi-Fi</string>\n    <string name=\"netpolicy_disable_network_access\">Desativar acesso à rede</string>\n    <string name=\"netpolicy_reject_wifi_data\">Rejeitar dados Wi-Fi</string>\n    <string name=\"netpolicy_reject_vpn_data\">Rejeitar dados VPN</string>\n    <string name=\"netpolicy_reject_cellular_data\">Rejeitar dados móveis</string>\n    <string name=\"netpolicy_allow_background_data\">Permitir dados em segundo plano quando o Data Saver estiver ativado</string>\n    <string name=\"netpolicy_reject_background_data\">Rejeitar dados em segundo plano</string>\n    <plurals name=\"alert_failed_to_import_backups\">\n        <item quantity=\"one\">Não foi possível importar %1$d cópia de segurança</item>\n        <item quantity=\"many\">Não foi possível importar %1$d cópias de segurança</item>\n        <item quantity=\"other\">Não foi possível importar %1$d cópias de segurança</item>\n    </plurals>\n    <string name=\"import_from_tb\">Importar de Titanium Backup</string>\n    <string name=\"import_from_oab\">Importar de OAndBackup</string>\n    <string name=\"pref_import_backups_msg\">Importar cópias de segurança de OAndBackup, Swift Backup (3.0–3.2) ou Titanium Backup.</string>\n    <string name=\"pref_import_backups\">Importar cópias de segurança</string>\n    <string name=\"community_links\"><a href=\"https://matrix.to/#/#appmanager:matrix.org\">Matrix</a> • <a href=\"https://t.me/AppManagerChannel\">Telegram</a> • <a href=\"https://twitter.com/AppManagerNews\">Twitter</a></string>\n    <string name=\"community\">Comunidade</string>\n    <string name=\"added_to_queue\">Adicionado à fila</string>\n    <string name=\"minimum_version\">Versão mínima: %d</string>\n    <string name=\"help_uses_permissions_tab\">Clique num item para <b>conceder</b> ou <b>revogar</b>. Apenas as permissões <b>perigosas</b> e de <b>desenvolvimento</b> podem ser concedidas ou revogadas.</string>\n    <string name=\"help_permissions_tab\">Estas permissões são definidas por esta aplicação e não podem ser revogadas.</string>\n    <string name=\"help_app_ops_tab\">Clique num item para <b>permitir</b> ou <b>ignorar</b>. Clique longo sobre um item para ver outros modos suportados.</string>\n    <string name=\"saved_filters\">Filtros guardados</string>\n    <string name=\"permission_flags\">Bandeiras de permissão</string>\n    <string name=\"pref_selected_users_msg\">Restringir o App Manager a trabalhar apenas com os utilizadores selecionados.</string>\n    <string name=\"pref_selected_users\">Utilizadores selecionados</string>\n    <string name=\"error_with_details\">Erro: %s</string>\n    <string name=\"files\">Ficheiros</string>\n    <string name=\"storage\">Armazenamento</string>\n    <string name=\"notice_saf\">Ao contrário dos volumes, o diretório selecionado será usado para armazenar todos os ficheiros relacionados com o App Manager, incluindo APKs e cópias de segurança guardadas. O Storage Access Framework (SAF) é muito lento, por isso só deve usar esta opção quando outras não puderem ser usadas.</string>\n    <string name=\"notice\">Aviso</string>\n    <string name=\"paired_successfully\">Pareado.</string>\n    <string name=\"adb_pair\">Parear</string>\n    <string name=\"invalid_password\">Palavra-passe inválida, tente novamente.</string>\n    <string name=\"keystore_pass_cannot_be_empty\">A palavra-passe da KeyStore não pode estar vazia.</string>\n    <string name=\"keystore_password_info\">Segue-se a palavra-passe da App Manager KeyStore. Por favor guarde-a num local seguro se fizer uma cópia de segurança/restaurar a App Manager KeyStore. <b>Esta mensagem não será mostrada novamente.</b></string>\n    <string name=\"type_uri_array_list\">Lista de URLs</string>\n    <string name=\"pref_block_trackers_msg\">Bloqueia os componentes de rastreio após instalar um Aplicativo usando o gerenciador.</string>\n    <string name=\"running_services_logcat_hint\">Clique em um item para abrir a tela de registro com o ID de processo correspondente como filtro principal.</string>\n    <string name=\"pid\">ID do processo</string>\n    <plurals name=\"pref_thread_count_msg\">\n        <item quantity=\"one\">Executar no máximo %1$d operação em paralelo</item>\n        <item quantity=\"many\">Executar no máximo %1$d operações em paralelo</item>\n        <item quantity=\"other\">Executar no máximo %1$d operações em paralelo</item>\n    </plurals>\n    <string name=\"pref_thread_count_hint\">O valor deve estar entre 0 e %1$d onde 0 significa <i> que o número máximo de operações no dado momento</i>.</string>\n    <string name=\"pref_thread_count\">Execução paralela</string>\n    <string name=\"pref_always_on_background_msg\">Sempre instalar aplicativos em segundo plano e mostrar notificação quando concluído.</string>\n    <string name=\"pref_always_on_background\">Instalar em segundo plano</string>\n    <string name=\"next\">Próximo</string>\n    <string name=\"installer_app_installed\">Aplicativo instalado</string>\n    <string name=\"staging_apk_files\">Aguardando arquivos de aplicativo…</string>\n    <string name=\"background\">Segundo plano</string>\n    <string name=\"trim_caches_in_all_apps_description\">Apaga ficheiros de cache de todas as aplicações, incluindo sistema android</string>\n    <string name=\"trim_caches_in_all_apps\">Ajustar caches em todas as aplicações</string>\n    <string name=\"user_root\">Usar root</string>\n    <string name=\"paste\">Colar</string>\n    <string name=\"set_package_name_first\">Defina primeiro o nome do pacote!</string>\n    <string name=\"identifier\">Identificador</string>\n    <string name=\"backup_volume_dialog_description\">Volumes com o prefixo <tt>/tree</tt> são pastas selecionadas usando o Storage Access Framework (SAF). Excetuando estas pastas, o diretório padrão do App Manager é uma subpasta chamada <tt>AppManager</tt>.</string>\n    <string name=\"second_degree_tracker_note\">²prefixo indica que os rastreadores estão na <a href=\"https://etip.exodus-privacy.eu.org/\">Lista de espera ETIP</a>, ou seja, que são rastreadores que ainda estão a ser investigados.</string>\n    <string name=\"failed_to_uninstall_app\">Não foi possível desinstalar</string>\n    <string name=\"type_uri_array\">Matriz de URIs</string>\n    <string name=\"import_from_sb\">Importar de Swift Backup 3.0 – 3.2</string>\n    <string name=\"pref_import_backups_hint\">Selecione um diretório que contém os ficheiros da cópia de segurança (Swift Backup / Titanium Backup) ou diretórios (OAndBackup)</string>\n    <string name=\"java\">Java</string>\n    <string name=\"smali\">Smali</string>\n    <string name=\"accessibility_service_description\">Serviço genérico de acessibilidade para realizar determinadas operações, como a compensação de cache no modo no-root.</string>\n    <string name=\"explore\">Explorar</string>\n    <string name=\"system_partition\">Raiz do Android</string>\n    <string name=\"exit_confirmation\">Confirmação de saída</string>\n    <string name=\"replace\">Substituir</string>\n    <string name=\"rename\">Alterar nome</string>\n    <string name=\"extract\">Extrair</string>\n    <string name=\"intent_firewall_and_disable\">IFW + desativar</string>\n    <string name=\"intent_firewall\">IFW</string>\n    <string name=\"pref_default_blocking_method\">Método de bloqueio padrão</string>\n    <string name=\"pref_default_blocking_method_description\">Método a ser usado por padrão em locais onde não há opção de selecionar um método de bloqueio.\\n<b>Nota:</b> \\\"IFW\\\" não funciona com provedores, \\\"desabilitar\\\" é usado no lugar.</string>\n    <string name=\"pref_intent_firewall_and_disable_description\">Bloquear componentes usando o Firewall Intent, assim como desativá-os. Método recomendado para utilizadores root.</string>\n    <string name=\"pref_intent_firewall_description\">Bloquear componentes usando apenas Firewall Intent. Não recomendado, pois, algumas apps do sistema podem contornar firewalls.</string>\n    <string name=\"authenticating\">A autenticar…</string>\n    <string name=\"search_type_contains\">Contém</string>\n    <string name=\"search_type_prefix\">Prefixo</string>\n    <string name=\"search_type_suffix\">Sufixo</string>\n    <string name=\"search_type_regular_expressions\">Regex</string>\n    <string name=\"pref_disable_description\">Desativar apenas componentes. Não recomendado para utilizadores root, pois as apps podem contorná-lo. Nos modos ADB, as aps somente de teste podem ser desativados com este método.</string>\n    <plurals name=\"usage_minutes\">\n        <item quantity=\"one\">%1$d min</item>\n        <item quantity=\"many\">%1$d mins</item>\n        <item quantity=\"other\">%1$d mins</item>\n    </plurals>\n    <plurals name=\"usage_seconds\">\n        <item quantity=\"one\">%1$d segundo</item>\n        <item quantity=\"many\">%1$d segundos</item>\n        <item quantity=\"other\">%1$d segundos</item>\n    </plurals>\n    <string name=\"vt_checking\">VirusTotal: a verificar…</string>\n    <string name=\"vt_queued\">VirusTotal: na fila</string>\n    <string name=\"vt_failed\">VirusTotal: falhou</string>\n    <string name=\"vt_success\">VirusTotal: %1$d/%2$d</string>\n    <string name=\"vt_scan_date\">Data da análise: %1$s</string>\n    <string name=\"pref_vt_apikey\">Chave de API do VirusTotal</string>\n    <string name=\"pref_vt_apikey_description\">Uma chave de API permite que o App Manager envie ficheiros de APK para o VirusTotal e possa receber relatórios. Crie uma conta em https://virustotal.com para obter uma chave de API gratuita.</string>\n    <string name=\"pref_vt_apikey_summary\">Ativar a análise de ficheiros APK no VirusTotal.</string>\n    <string name=\"scan_in_vt\">Analisar no VirusTotal</string>\n    <string name=\"process_id\">ID do processo</string>\n    <string name=\"cpu_time\">Tempo de CPU</string>\n    <string name=\"state\">Estado do processo</string>\n    <string name=\"commandline_args\">Argumentos de linha de comando</string>\n    <string name=\"memory_chart_info\">● %1$s aplicações ● %2$s em cache ● %3$s buffers ● %4$s livre</string>\n    <string name=\"swap_chart_info\">● %1$s usado ● %2$s livre</string>\n    <string name=\"vt_uploading\">VirusTotal: a enviar…</string>\n    <string name=\"vt_permalink\">Hiperligação permanente para o VirusTotal</string>\n    <string name=\"vt_slowness_warning\">Dependendo da velocidade da Internet e da carga no servidor, isto pode demorar.</string>\n    <string name=\"vt_disclaimer\">VirusTotal e os logotipos dele são uma marca registada da Chronicle LLC. Nem o App Manager - o cliente da API - nem os seus autores são responsáveis por quaisquer dados que possa enviar para a VirusTotal.</string>\n    <string name=\"parent_process_id\">ID do processo pai</string>\n    <string name=\"cpu_percent\">%% CPU</string>\n    <string name=\"uses_play_app_signing\">Assinatura Play App</string>\n    <string name=\"priority\">Prioridade</string>\n    <string name=\"virtual_memory\">Memória virtual</string>\n    <string name=\"toggle_internet\">Usar a Internet</string>\n    <string name=\"threads\">Número de threads</string>\n    <string name=\"swap\">Swap</string>\n    <string name=\"failed_to_change_app_op_mode\">Não foi possível alterar o modo de operação da aplicação.</string>\n    <string name=\"failed_to_use_the_current_mode_of_operation\">Não é possível usar o modo de operação atual. A voltar ao modo sem root para esta sessão.</string>\n    <string name=\"warning_working_on_root_mode\">Aviso: a executar com root em vez do modo ADB.</string>\n    <string name=\"magisk_denylist\">Magisk DenyList</string>\n    <string name=\"failed_to_enable_magisk_deny_list\">Não foi possível ativar a Magisk DenyList</string>\n    <string name=\"uses_play_app_signing_description\">Esta aplicação contém certos marcadores que indicam que <i>pode</i> estar a usar <a href=\"https://support.google.com/googleplay/android-developer/answer/9842756\">Play App Signing</a>. Com esse esquema, as chaves de assinatura são armazenadas nos servidores do Google, e o Google é responsável por assinar a aplicação. Note que as informações de assinatura correspondentes são a única forma de verificar se a aplicação não foi alterada por outra pessoa que não o programador (e neste caso o Google também).</string>\n    <string name=\"failed_to_disable_magisk_deny_list\">Não foi possível desativar a Magisk DenyList</string>\n    <string name=\"mode_of_op_with_inferred_mode_of_op\">%1$s (modo inferido: %2$s)</string>\n    <string name=\"save_and_exit\">Guardar e sair</string>\n    <string name=\"file_modified_are_you_sure\">O ficheiro foi modificado. Descartar todas as suas alterações e sair\\?</string>\n    <string name=\"so_type_shared_library\">Biblioteca partilhada</string>\n    <string name=\"hidden_api_enf_default_policy\">Padrão (com base no tipo de aplicação)</string>\n    <string name=\"primary_abi\">Índice Primário de Variação Absoluta</string>\n    <string name=\"hidden_api_enf_policy_none\">Nenhuma (acesso total à API oculta)</string>\n    <string name=\"zygote_preload_name\">Nome de pré-carregamento do Zygote</string>\n    <string name=\"hidden_api_enforcement_policy\">Política de aplicação de API oculta</string>\n    <string name=\"hidden_api_enf_policy_warn\">Avisar (acesso total à API oculta, mas emite avisos)</string>\n    <string name=\"hidden_api_enf_policy_dark_grey_and_black\">Forçar (listas cinza-escuro e negras)</string>\n    <string name=\"hidden_api_enf_policy_black\">Forçar (apenas listas negras)</string>\n    <string name=\"binary_32_bit\">32 Bit</string>\n    <string name=\"binary_64_bit\">64 Bit</string>\n    <string name=\"change_backup_volume\">Alterar volume</string>\n    <string name=\"pref_saved_apk_name_format\">Nome do formato APK salvo</string>\n    <string name=\"pref_saved_apk_name_format_msg\">O formato usado para nomear os ficheiros APK ao gravá-los.</string>\n    <string name=\"sort_by_installation_date\">Data de instalação</string>\n    <string name=\"external\">Externo</string>\n    <string name=\"so_type_executable\">Executável</string>\n    <string name=\"auth_manager_title\">Gerente de autorização</string>\n    <string name=\"backup_volume_unavailable_warning\">O volume de backup selecionado não está disponível no momento. Se estiver localizado em um armazenamento externo, insira-o ou altere o volume de backup.</string>\n    <string name=\"internal\">Interno</string>\n    <string name=\"netpolicy_cannot_be_modified_for_core_apps\">A política de rede não pode ser alterada para as aplicações centrais do Android.</string>\n    <string name=\"auth_manager_description\">Para iniciar um Intent a partir de uma aplicação externa, é necessário fornecer um campo extra chamado <tt>auth</tt> e deve conter a seguinte chave:</string>\n    <string name=\"regenerate_auth_key\">Regenerar chave de autorização</string>\n    <string name=\"shortcut_icon\">Ícone do atalho</string>\n    <string name=\"regenerate_auth_key_warning\">Tem certeza\\? Todas as aplicações de terceiros têm de ser reconfiguradas com a nova chave de autorização.</string>\n    <string name=\"input_ssaid_instruction\">SSAID é um número hexadecimal de byte %1$d, ou seja, uma cadeia de comprimento %2$d contendo 0 a 9 e \\\"a\\\" a \\\"f\\\".</string>\n    <string name=\"vt_confirm_upload_and_scan\">Sim, enviar e analisar</string>\n    <string name=\"screen_time\">Tempo de ecrã</string>\n    <string name=\"vt_confirm_uploading_file\">O ficheiro não foi encontrado na base de dados do VirusTotal. Quer enviá-lo\\?</string>\n    <string name=\"endianness_little_endian\">Little endian</string>\n    <string name=\"endianness_big_endian\">Big endian</string>\n    <string name=\"log_stop_recording\">Parar o registo de eventos</string>\n    <string name=\"tracker\">Rastreador</string>\n    <string name=\"pref_vt_prompt_before_uploading\">Mostrar o aviso antes de enviar um ficheiro.</string>\n    <string name=\"apk_checksums\">Checksums do APK</string>\n    <string name=\"item_select\">Selecionar</string>\n    <string name=\"open_in_new_window\">Nova janela</string>\n    <string name=\"type_string_set\">Conjunto de cadeias</string>\n    <string name=\"app_explorer\">Explorador de aplicações</string>\n    <string name=\"frozen\">Congelado</string>\n    <string name=\"freeze\">Congelar</string>\n    <string name=\"unfreeze\">Descongelar</string>\n    <string name=\"restore_dots\">Restaurar…</string>\n    <string name=\"backup_apps_cannot_be_backed_up\">As seguintes apps não estão instaladas nem podem ser armazenadas em backups:</string>\n    <string name=\"restart_device\">Reiniciar o dispositivo</string>\n    <string name=\"pref_pure_black_theme\">Tema escuro puro</string>\n    <string name=\"backup_no_backups_present\">Sem backups.</string>\n    <string name=\"import_backups_warning_delete_backups_after_import\">Apagar os backups após importar para o App Manager\\? O backup é apagado individualmente após ter sido importado com sucesso. Selecione <b>Não</b> se não tiver certeza.</string>\n    <string name=\"open_developer_options_page\">Abrir opções de desenvolvedor nas configurações do Android</string>\n    <string name=\"backup_apps_cannot_be_restored\">As seguintes apps não podem ser restauradas por não terem base de backup:</string>\n    <string name=\"pref_pure_black_theme_msg\">Utiliza o tema totalmente preto quando o modo noturno está ligado.</string>\n    <string name=\"usage_last_used\">Usado recentemente</string>\n    <string name=\"usage_mobile_data\">Dados moveis</string>\n    <string name=\"usage_wifi_data\">Dados Wi-Fi</string>\n    <string name=\"usage_times_opened\">Vezes aberto</string>\n    <string name=\"pref_reload_apps_msg\">Recarregar a lista de apps armazenados na base de dados do App Manager no caso de ocorrer algo inesperado.</string>\n    <string name=\"troubleshooting\">Resolver problemas</string>\n    <string name=\"pref_reload_apps\">Recarregar apps</string>\n    <string name=\"changelog_type_new\">Novo</string>\n    <string name=\"changelog_type_fix\">Reparar</string>\n    <string name=\"changelog_type_improve\">Melhorar</string>\n    <string name=\"unsupported_split_apk\">Não suportado</string>\n    <string name=\"view_changelog\">Descubra o que há de novo nesta versão</string>\n    <string name=\"sort_by_total_size\">Tamanho total</string>\n    <string name=\"am_command\"><tt>am</tt> comando</string>\n    <string name=\"pref_sign_apk_error_signing_key_not_added\">É necessário uma chave válida para assinar um ficheiro APK.</string>\n    <string name=\"pref_sign_apk_no_signing_key\">Sem chave de assinatura</string>\n    <string name=\"suspend_app\">Suspender</string>\n    <string name=\"hide_app\">Ocultar</string>\n    <string name=\"disable_app_description\">Método de congelamento recomendado. Ele desativa a aplicação e todos os seus componentes, mas todos os atalhos serão perdidos.</string>\n    <string name=\"sort_by_frozen_app\">Congeladas primeiro</string>\n    <string name=\"filter_frozen_apps\">Aplicações congeladas</string>\n    <string name=\"pref_appearance_description\">Tema, orientação, recursos, etc.</string>\n    <string name=\"pref_privacy\">Privacidade</string>\n    <string name=\"failed_to_unfreeze\">Não foi possível congelar <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g>.</string>\n    <string name=\"failed_to_freeze\">Não foi possível congelar <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g>.</string>\n    <string name=\"pref_default_freezing_method_description\">Método a ser usado por padrão em locais onde não há opção de selecionar um método de congelamento.</string>\n    <plurals name=\"alert_failed_to_freeze\">\n        <item quantity=\"one\">N0ão foi possível congelar %1$d app</item>\n        <item quantity=\"many\">Não foi possível congelar %1$d apps</item>\n        <item quantity=\"other\">Não foi possível congelar %1$d apps</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_unfreeze\">\n        <item quantity=\"one\">Não foi possível descongelar %1$d app</item>\n        <item quantity=\"many\">Não foi possível descongelar %1$d apps</item>\n        <item quantity=\"other\">Não foi possível descongelar %1$d apps</item>\n    </plurals>\n    <string name=\"suspend_app_description\">Este é o método de congelamento mais fraco. Uma aplicação suspensa ainda pode aparecer no launcher, mas ficará cinzento e não poderá ser iniciada.</string>\n    <string name=\"hide_app_description\">Este método é recomendado apenas para uso diário. Uma aplicação oculta aparece como se estivesse desinstalada. Mas a aplicação pode reaparecer se for reinstalada ou atualizada.</string>\n    <string name=\"user_manual\">Manual do utilizador</string>\n    <string name=\"get_help\">Obter ajuda</string>\n    <string name=\"pref_privacy_description\">Bloqueio de ecrã, autorização, etc.</string>\n    <string name=\"pref_advanced_pref\">Utilizadores, formato de nome do APK, execução paralela etc.</string>\n    <string name=\"pref_version_changelog\">Versão/Registo de alterações</string>\n    <string name=\"freeze_unfreeze\">Congelar/Descongelar</string>\n    <string name=\"profile_freeze_msg\">Congelar ou descongelar aplicações baseada no estado</string>\n    <string name=\"pref_default_freezing_method\">Método de congelação por defeito</string>\n    <string name=\"file_accessed_date\">Acedido</string>\n    <string name=\"file_open_with\">Abrir com</string>\n    <string name=\"file_change_open_with\">Alterar abrir com</string>\n    <string name=\"file_shortcut_target_file\">Ficheiro de destino</string>\n    <string name=\"file_open_as\">Abrir como…</string>\n    <string name=\"file_open_with_custom_activity\">Personalizado</string>\n    <string name=\"file_open_with_os_default_dialog\">Abrir com a caixa de diálogo padrão do SO</string>\n    <string name=\"open_as_text\">Texto</string>\n    <string name=\"file_properties\">Propriedades</string>\n    <string name=\"file_cut\">Cortar</string>\n    <string name=\"fm_always_open_with\">Sempre aberto</string>\n    <string name=\"fm_open_with_for_this_file_only\">Apenas para este ficheiro</string>\n    <string name=\"open_as_image\">Imagem</string>\n    <string name=\"open_as_video\">Vídeo</string>\n    <string name=\"open_as_folder\">Pasta</string>\n    <string name=\"open_as_other\">Outro</string>\n    <string name=\"on_unfreeze_open_application\">Abrir a app após o descongelamento</string>\n    <string name=\"delete_filename\">Apagar %s</string>\n    <string name=\"confirm_file_deletion\">Sim, apagar</string>\n    <string name=\"on_open_application_no_recents\">Não mostrar a app iniciada nos Recentes</string>\n    <string name=\"freeze_on_phone_locked\">Congelar a app automaticamente quando o telefone estiver bloqueado</string>\n    <string name=\"tap_to_freeze_app\">Toque para congelar</string>\n    <string name=\"waiting_for_the_phone_to_be_locked\">À espera que o telefone seja bloqueado…</string>\n    <string name=\"action_stop_service\">Parar</string>\n    <string name=\"file_creation_date\">Criado</string>\n    <string name=\"open_as_archive\">Arquivo</string>\n    <string name=\"file_modification_date\">Modificado</string>\n    <string name=\"sort_by_data_usage\">Utilização de dados</string>\n    <string name=\"adb_incomplete_usb_debugging_message\">Parece que a depuração USB não está configurada corretamente. Leia <a href=\"https://muntashirakon.github.io/AppManager/#subsec:enable-usb-debugging\">a documentação</a> para obter etapas adicionais. Se já conhece as etapas, clique em \\\"Abrir\\\" para abrir as opções de programador ou clique em \\\"Fechar\\\" para continuar a usar o modo \\\"no-root\\\".</string>\n    <string name=\"grant_accessibility_permission_for_tracking_window_contents\">Permita que o App Manager use o recurso de acessibilidade para rastrear o conteúdo da janela principal.</string>\n    <string name=\"app_manager_build_expired_message\">Para garantir a segurança do seu dispositivo e dos seus dados, a versão do App Manager que está a utilizar foi desativada. Tem de atualizá-lo para a versão mais recente para continuar a usá-lo ou desinstalá-lo se não estiver disponível nenhuma atualização.</string>\n    <string name=\"app_manager_build_expired\">Necessário atualizar</string>\n    <string name=\"app_can_write_and_execute_in_same_place\">A aplicação viola a <a href=\"https://en.wikipedia.org/wiki/W%5EX\">política W^X </a> e é capaz de gravar e executar no mesmo diretório ou na mesma parte da memória. Isto permite a execução de executáveis arbitrários pela modificação de executáveis incorporados na aplicação ou descarregando-os da Internet. A não ser que esse seja o comportamento pretendido da aplicação (por exemplo, emuladores de terminal), recomenda-se encontrar uma versão mais recente da aplicação que tenha como alvo o SDK 29 (Android 10) e posterior, ou encontrar alternativas.</string>\n    <string name=\"filter_apps_with_saf\">Com SAF</string>\n    <string name=\"option_display_folders_on_top\">Pastas no topo</string>\n    <string name=\"funding_campaign_dialog_message\">Estamos a realizar uma <b>campanha de financiamento</b> para o App Manager por um período limitado. Visite <a href=\"https://opencollective.com/app-manager#category-ABOUT\">opencollective.com/app-manager</a> para saber mais sobre a campanha. Este aviso não será mostrado novamente, mas poderá encontrá-lo no ecrã \\\"Configurações\\\" durante toda a campanha.</string>\n    <string name=\"filter_apps_with_keystore\">Com KeyStore</string>\n    <string name=\"filter_apps_with_ssaid\">Com SSAID</string>\n    <string name=\"action_continue\">Continuar</string>\n    <string name=\"install_for_another_user\">Instalar para…</string>\n    <string name=\"confirm_uninstallation\">Confirmar desinstalação</string>\n    <string name=\"grant_required_permission\">Conceder permissão necessária</string>\n    <string name=\"grant_overlay_permission_message\">Permitir que o App Manager mostre uma janela flutuante sobre todas as outras janelas</string>\n    <string name=\"class_hierarchy\">Hierarquia</string>\n    <string name=\"title_ui_tracker\">Rastreador de IU</string>\n    <string name=\"title_terminal_emulator\">Terminal</string>\n    <string name=\"title_labs_activity\">Labs</string>\n    <string name=\"app_manager_build_expiring_soon_warning\">Esta versão do App Manager expirará muito em breve. Atualize-o para a versão mais recente.</string>\n    <string name=\"renamed_successfully\">Nome alterado</string>\n    <string name=\"selinux_context\">Contexto SELinux</string>\n    <string name=\"unix_file_permissions\">Modo</string>\n    <string name=\"file_group_id\">Grupo (GID)</string>\n    <string name=\"file_owner_id\">Proprietário (UID)</string>\n    <string name=\"calculating_file_size\">A calcular…</string>\n    <string name=\"sort_by_filename\">Nome</string>\n    <string name=\"sort_by_last_modified\">Última alteração</string>\n    <string name=\"sort_by_file_size\">Tamanho do ficheiro</string>\n    <string name=\"sort_by_file_type\">Tipo de ficheiro</string>\n    <string name=\"option_display_dot_files\">Ficheiros dot</string>\n    <string name=\"export_app_list\">Exportar lista de aplicações</string>\n    <string name=\"export_app_list_select_format\">Selecione o formato para exportar a lista de aplicações</string>\n    <string name=\"export_option_xml\">XML</string>\n    <string name=\"export_option_markdown\">Markdown</string>\n    <string name=\"funding_campaign_text\">Estamos a realizar uma <b>campanha de financiamento</b> para o App Manager por um período limitado. <a href=\"https://opencollective.com/app-manager#category-ABOUT\">Mais informações…</a></string>\n    <string name=\"adb_incomplete_usb_debugging_title\">Depuração USB incompleta</string>\n    <string name=\"optimize_option_clear_profile_data\">Limpar dados de perfil anteriores</string>\n    <string name=\"optimize_option_check_profiles\">Considere os dados de perfil durante a otimização DEX</string>\n    <string name=\"optimize_option_force_compilation\">Forçar compilação mesmo quando não for necessário</string>\n    <string name=\"optimize_option_force_dexopt\">Executar imediatamente a otimização DEX</string>\n    <string name=\"title_perform_runtime_optimization_to_apps\">Executar a otimização de tempo de execução</string>\n    <string name=\"action_run\">Iniciar</string>\n    <string name=\"summary_perform_runtime_optimization_to_apps\">Otimize a disposição DEX (no Android 10 e posterior) para melhorar o desempenho das aplicações.</string>\n    <string name=\"action_optimize_app\">Otimizar</string>\n    <string name=\"select_a_dex2oat_compiler_filter\"><tt>dex2oat</tt> compilar filtro</string>\n    <string name=\"optimize_option_compile_layouts\">Compilar a disposição dos recursos</string>\n    <string name=\"batch_ops_runtime_optimization\">Otimização do tempo de execução</string>\n    <plurals name=\"alert_failed_to_optimize_apps\">\n        <item quantity=\"one\">Não foi possível optimizar a %1$d app</item>\n        <item quantity=\"many\">Não foi possível optimizar as %1$d apps</item>\n        <item quantity=\"other\">Não foi possível optimizar as %1$d apps</item>\n    </plurals>\n    <string name=\"search_option_match_case\">Correspondente</string>\n    <string name=\"search_option_whole_word\">Palavra completa</string>\n    <string name=\"search_option_regex\">Regex</string>\n    <string name=\"uninstall_app_again_message\">A aplicação foi desinstalada sem limpar os dados e assinatura. Deseja desinstar completamente\\?</string>\n    <string name=\"uninstall_app\">Desinstalar %1$s</string>\n    <string name=\"debloat_list_type\">Lista</string>\n    <string name=\"debloat_removal_type\">Tipo</string>\n    <string name=\"system_app_put_back\">Adiar</string>\n    <string name=\"debloater_title\">Debloater</string>\n    <string name=\"debloat_list_aosp\">AOSP</string>\n    <string name=\"debloat_list_oem\">OEM</string>\n    <string name=\"debloat_list_carrier\">Operadora/ISP</string>\n    <string name=\"debloat_list_google\">Google</string>\n    <string name=\"debloat_list_misc\">Miscelânea</string>\n    <string name=\"debloat_removal_safe\">Seguro</string>\n    <string name=\"debloat_removal_replace\">Repor</string>\n    <string name=\"debloat_removal_caution\">Cuidado</string>\n    <string name=\"static_shared_library\">Livraria partilhada estática</string>\n    <string name=\"empty_folder\">Vazio</string>\n    <string name=\"go_to_path\">Ir para…</string>\n    <string name=\"copy_this_path\">Copiar caminho</string>\n    <string name=\"title_audio_player\">Tocador de Áudio</string>\n    <plurals name=\"file_count\">\n        <item quantity=\"one\">%d ficheiro</item>\n        <item quantity=\"many\">%d ficheiros</item>\n        <item quantity=\"other\">%d ficheiros</item>\n    </plurals>\n    <plurals name=\"folder_count\">\n        <item quantity=\"one\">%d pasta</item>\n        <item quantity=\"many\">%d pastas</item>\n        <item quantity=\"other\">%d outras pastas</item>\n    </plurals>\n    <string name=\"block_unblock_components_description\">Bloquear ou desbloquear todos os componentes identificados pelas assinaturas fornecidas</string>\n    <string name=\"unblock_components_dots\">Desbloquear componentes…</string>\n    <string name=\"block_unblock_components_dots\">Bloquear/Desbloquear componentes…</string>\n    <string name=\"pref_zip_align\">Alinhar ficheiros APK</string>\n    <string name=\"title_code_editor\">Editor de Código</string>\n    <string name=\"filter_force_stopped_apps\">Parar apps</string>\n    <string name=\"restoring_app\">Restaurando %1$s…</string>\n    <string name=\"folder\">Pasta</string>\n    <string name=\"create_new_folder\">Nova pasta</string>\n    <string name=\"title_confirm_deletion\">Confirmar exclusão</string>\n    <string name=\"conflict_detected_while_copying\">Conflito detectado</string>\n    <string name=\"copy_keep_both_file\">Manter ambos</string>\n    <string name=\"change_mode\">Alterar modo</string>\n    <string name=\"installing_package\">Instalando %1$s…</string>\n    <string name=\"redo\">Refazer</string>\n    <string name=\"line_separator\">Separador de linha</string>\n    <plurals name=\"search_results\">\n        <item quantity=\"one\">%d resultado</item>\n        <item quantity=\"many\">%d resultados</item>\n        <item quantity=\"other\">%d resultados</item>\n    </plurals>\n    <string name=\"backing_up_app\">Fazendo backup de %1$s…</string>\n    <string name=\"symbolic_link\">Link simbólico</string>\n    <string name=\"create_new_symbolic_link\">Novo link simbólico</string>\n    <string name=\"create_new_file\">Novo ficheiro</string>\n    <string name=\"invalid_target_path\">Caminho inválido</string>\n    <string name=\"enter_symbolic_link_name\">Nome do link</string>\n    <string name=\"enter_target_path\">Caminho de destino</string>\n    <string name=\"copy_these_paths\">Copiar caminhos</string>\n    <string name=\"moved_successfully\">Movido</string>\n    <string name=\"copied_successfully\">Copiado.</string>\n    <plurals name=\"alert_failed_to_unblock_components\">\n        <item quantity=\"one\">Não foi possível desbloquear componentes para %1$d app</item>\n        <item quantity=\"many\">Não foi possível desbloquear componentes para %1$d apps</item>\n        <item quantity=\"other\">Não foi possível desbloquear componentes para %1$d apps</item>\n    </plurals>\n    <string name=\"source_stamp_verified_and_identified_to_be_from_source\">SourceStamp verificado e identificado como sendo de <xliff:g id=\"source\" example=\"Google Play\">%1$s</xliff:g>.</string>\n    <string name=\"pref_layout_direction\">Direção do layout</string>\n    <string name=\"warning_working_on_system_mode\">Aviso: Trabalhando no modo sistema em vez do modo ADB.</string>\n    <string name=\"app_info_tag_open_links\">Abrir links</string>\n    <string name=\"installer_options\">Opções do instalador</string>\n    <string name=\"debloat_removal_safe_short_description\">Seguro para remover</string>\n    <string name=\"debloat_removal_caution_short_description\">Tenha cautela</string>\n    <string name=\"title_domains_supported_by_the_app\">Domínios Suportados</string>\n    <string name=\"read_only_file\">Ficheiro somente leitura</string>\n    <string name=\"read_only_file_warning\">As alterações não podem ser gravadas no ficheiro, possivelmente porque está localizado num volume no qual o App Manager não tem permissão para gravar. Quer gravá-lo num lugar diferente?</string>\n    <string name=\"replacement_text\">Substituição</string>\n    <string name=\"action_replace_all\">Substituir Todos</string>\n    <string name=\"conflict_detected_while_copying_message\">Um item chamado \\\"%1$s\\\" já existe nesse local. Deseja substituí-lo?</string>\n    <string name=\"pref_installer_force_dexopt_description\">Realizar a otimização DEX imediatamente após a instalação do aplicativo, sem esperar que o sistema o faça quando estiver ocioso.</string>\n    <string name=\"symbolic_link_not_supported\">Esta pasta não suporta a criação de um link simbólico.</string>\n    <string name=\"failed_to_copy_specified_file\">Não foi possível copiar “%1$s”.</string>\n    <string name=\"pref_toggle_internet_msg\">Ativar os recursos de Internet no App Manager</string>\n    <string name=\"netpolicy_allow_metered_background_data\">Permitir dados em segundo plano em redes tarifadas, mesmo com o Economizador de Dados ativado</string>\n    <string name=\"netpolicy_reject_metered_background_data\">Rejeitar dados em segundo plano em redes tarifadas</string>\n    <string name=\"pref_send_notifications_to_connected_devices\">Enviar notificações para os dispositivos conectados</string>\n    <string name=\"pref_send_notification_to_connected_devices_msg\">Definir se notificações serão enviadas aos dispositivos conectados, como vestíveis.</string>\n    <string name=\"debloat_removal_replace_short_description\">Substituir por alternativa</string>\n    <string name=\"pref_files_msg\">Configurar o gestor de ficheiros.</string>\n    <string name=\"xposed_module_info\">Informações do Módulo XPosed</string>\n    <string name=\"module_name\">Nome do módulo</string>\n    <string name=\"app_manager_is_running\">O App Manager está em execução</string>\n    <string name=\"status_remote_services_inactive\">Os serviços remotos estão inativos</string>\n    <string name=\"status_connecting\">A conectar…</string>\n    <string name=\"adb_pairing_instruction\">Por favor navegue às opções de desenvolvedor para habilitar a depuração sem fio e gerar um código de pareamento.</string>\n    <string name=\"sensors\">Sensores</string>\n    <string name=\"tag_sensors_disabled\">Sensores desabilitados</string>\n    <string name=\"pref_use_system_font\">Usar fonte do sistema</string>\n    <string name=\"pref_use_system_font_msg\">Usar a fonte padrão do sistema ao invés da fonte material. <font fgcolor=\"#ff0000\">Este é um recurso experimental.</font></string>\n    <string name=\"mode_of_op_alternative_custom_command\">Se receber um erro de \\\"permissão negada\\\" com o comando acima, execute o seguinte comando no lugar:</string>\n    <string name=\"activity_name\">Nome da Atividade</string>\n    <string name=\"path_not_a_folder\">“%1$s” não é uma pasta</string>\n    <string name=\"profile_id\">ID do perfil</string>\n    <string name=\"launch_activity_dialog_title\">Atividade de Execução: Ação Requerida</string>\n    <string name=\"virus_total\">VirusTotal</string>\n    <string name=\"pref_use_log_viewer\">Usar o Leitor de Registo</string>\n    <string name=\"pref_installer\">Usar o instalador</string>\n    <string name=\"pref_cat_general\">Geral</string>\n    <string name=\"status_remote_server_active\">O servidor remoto está ativo</string>\n    <string name=\"status_remote_server_inactive\">O servidor remoto está inativo</string>\n    <string name=\"status_remote_services_active\">Os serviços remotos estão ativos</string>\n    <string name=\"status_connecting_via_mode\">A conectar via %s</string>\n    <string name=\"status_connected_via_mode\">Conectado via %s</string>\n    <string name=\"status_not_connected_via_mode\">Não foi possível conectar via %s</string>\n    <string name=\"adb_pairing_searching_for_port\">A buscar…</string>\n    <string name=\"adb_pairing_pairing_code\">Código de pareamento</string>\n    <string name=\"adb_pairing_pairing_in_progress\">A parear…</string>\n    <string name=\"mode_of_op_custom_command_title\">Comando Personalizado</string>\n    <string name=\"title_change_selinux_context\">Mudar contexto do SELinux</string>\n    <string name=\"apply_recursively\">Aplicar aos ficheiros contidos</string>\n    <string name=\"change_owner_uid\">Mudar proprietário (UID)</string>\n    <string name=\"pref_files_display_in_launcher\">Exibir \\\"Ficheiros\\\" no lançador de apps</string>\n    <string name=\"pref_files_remember_last_path\">Lembrar o último caminho aberto e a sua posição</string>\n    <string name=\"tap_to_open_notification_settings\">Toque para ocultar</string>\n    <string name=\"action_lock_app\">Bloquear</string>\n    <string name=\"pref_enable_persistent_session\">Executar o App Manager em segundo plano</string>\n    <string name=\"pref_enable_auto_lock_msg\">Bloquear o App Manager quando o dispositivo estiver bloqueado.</string>\n    <string name=\"apply_profile\">Aplicar perfil “%1$s”</string>\n    <string name=\"pref_use_vt\">Usar VirusTotal</string>\n    <string name=\"pref_set_home\">Definir início</string>\n    <string name=\"title_description\">Descrição</string>\n    <string name=\"backup_cache\">Cache</string>\n    <string name=\"scan_report_from_pithus\">Relatório Pithus</string>\n    <string name=\"path_does_not_exist\">“%1$s” não existe</string>\n    <string name=\"adb_pairing_stop_searching\">Parar</string>\n    <string name=\"choose_a_profile_state\">Selecionar um estado de perfil</string>\n    <string name=\"pref_enable_auto_lock\">Bloqueio automático</string>\n    <string name=\"title_alternatives_to_bloatware\">Alternativas</string>\n    <string name=\"pref_zip_align_msg\">Alinhar um ficheiro APK reduz seu uso de memória já que os dados dentro do APK podem ser acessados diretamente sem copiar-se para a RAM. Esse passo é necessário se <tt>extractNativeLibs</tt> estiver ajustado como <tt>true</tt>.</string>\n    <string name=\"action_checking\">A verificar…</string>\n    <string name=\"app_manager_is_unlocked\">O App Manager está desbloqueado</string>\n    <string name=\"report_not_available\">Não disponível</string>\n    <string name=\"apk_source\">Origem do APK</string>\n    <string name=\"launch_activity_dialog_message\">O App Manager está a tentar executar a atividade através do <b>assistente de busca</b> (como o Google Assistant), mas é incapaz de o fazer por permissão insuficiente. Para abrir a atividade, por favor ative o <b>assistente de busca</b> manualmente (geralmente ao fazer um clique longo no botão Home). Clique no botão <b>Fechar</b> depois de terminar a execução da atividade para retornar ao assistente original.</string>\n    <string name=\"mode_of_op_custom_command\">Se não conseguir usar nenhum dos modos, pode executar o seguinte comando em qualquer shell compatível para abrir o App Manager em modo privilefiado:</string>\n    <string name=\"actual_installer\">Instalador Real</string>\n    <string name=\"profile_modified_are_you_sure\">O perfil foi modificado. Descartar todas as mudanças e sair?</string>\n    <string name=\"finder_title\">Localizador</string>\n    <string name=\"select_filter\">Selecione um filtro</string>\n    <string name=\"size_in_bytes\">Tamanho (bytes)</string>\n    <string name=\"invalid_regex\">Expressão regular inválida!</string>\n    <string name=\"value_cannot_be_empty\">O valor não pode ser vazio!</string>\n    <string name=\"date\">Data</string>\n    <string name=\"browse_files\">Navegar</string>\n    <string name=\"change_group_gid\">Mudar grupo (GID)</string>\n    <string name=\"failed_to_delete_specified_file_after_copying\">Não foi possível eliminar “%1$s” depois de copiado, possivelmente devido à falta de permissões suficientes.</string>\n    <string name=\"pref_files_remember_last_path_msg\">Quando esta opção estiver habilitada, abrir uma nova janela abre a última pasta aberta ao invés da pasta inicial.</string>\n    <string name=\"adb_pairing_found_pairing_service_with_port\">Encontrado um serviço com a porta %d</string>\n    <string name=\"pref_enable_persistent_session_msg\">Executar o App Manager em segundo plano reduz o tempo de inicialização. É útil se usa o App Manager frequentemente.</string>\n    <string name=\"copy_profile_id\">Copiar ID do perfil</string>\n    <string name=\"netpolicy_reject_metered_data\">Rejeitar dados em redes mensuradas</string>\n    <string name=\"pref_use_vt_no_internet\">VirusTotal requer conexão à Internet, atualmente indisponível. Por favor habilite <a href=\"app-manager://settings/privacy_prefs/toggle_internet\">“Usar a Internet”</a> primeiro.</string>\n    <string name=\"adb_pairing_retry_pairing\">Tentar novamente</string>\n    <string name=\"adb_pairing_input_pairing_code\">Código de pareamento</string>\n</resources>"
  },
  {
    "path": "app/src/main/res/values-pt-rBR/disclaimer.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- SPDX-License-Identifier: GPL-3.0-or-later --><resources>\n    <string name=\"disclaimer_header\">Isenção de responsabilidade</string>\n    <string name=\"disclaimer_body\">O App Manager oferece funções Root que podem eventualmente prejudicar o seu dispositivo, se utilizado incorretamente. O App Manager não é responsável por quaisquer danos causados pela utilização desta aplicação. Se não estiver totalmente consciente de como o modo Root funciona, então você deve evitar utilizar essas opções até estar plenamente consciente dos riscos.\n\\n\n\\nQualquer link que eu forneça para outros aplicativos e websites é para o benefício dos usuários. Eu não sou responsável por qualquer conteúdo que você possa encontrar através de links externos.\n\\n\n\\nAo utilizar o App Manager, você aceita total responsabilidade por seu próprio uso e não aceita danos, reclamações ou valor monetário será dado devido ao uso indevido.\n\\n\n\\nAo utilizar este aplicativo, você aceita toda a responsabilidade de usá-lo e concorda que eu não sou responsável por qualquer ação que você faça e que tenha um efeito adverso sobre seu dispositivo.</string>\n    <string name=\"disclaimer_footer\">© 2020–2024 Muntashir Al-Islam</string>\n    <string name=\"disclaimer_agree_forever\">Nunca mostrar novamente</string>\n    <string name=\"disclaimer_agree\">Eu Concordo</string>\n    <string name=\"disclaimer_exit\">Sair</string>\n</resources>"
  },
  {
    "path": "app/src/main/res/values-pt-rBR/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- SPDX-License-Identifier: GPL-3.0-or-later --><resources xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:tools=\"http://schemas.android.com/tools\">\n    <string name=\"_lang_tag\" translatable=\"false\">pt-BR</string>\n    <string name=\"uninstall\">Desinstalar</string>\n    <string name=\"permissions\">Uso das permissões</string>\n    <string name=\"require_no_permission\">Sem permissões exigidas</string>\n    <string name=\"activities\">Atividades</string>\n    <string name=\"launch\">Iniciar</string>\n    <string name=\"refresh\">Atualizar</string>\n    <string name=\"no_activities\">Nenhuma atividade</string>\n    <string name=\"no_receivers\">Nenhum receptor</string>\n    <string name=\"no_providers\">Nenhum provedor</string>\n    <string name=\"launch_mode\">Modo de inicialização</string>\n    <string name=\"sort_by_last_update\">Última atualização</string>\n    <string name=\"authority\">Autoridade</string>\n    <string name=\"service\">Serviços</string>\n    <string name=\"no_service\">Nenhum serviço</string>\n    <string name=\"orientation\">Orientação</string>\n    <string name=\"grant_uri_permission\">Conceder permissões de URI</string>\n    <string name=\"path_permissions\">Permissões do caminho</string>\n    <string name=\"read\">Ler</string>\n    <string name=\"write\">Escrever</string>\n    <string name=\"patterns_allowed\">Padrões permitidos</string>\n    <string name=\"declared_permission\">Permissões</string>\n    <string name=\"group\">Grupo</string>\n    <string name=\"uses_feature\">Funções utilizadas</string>\n    <string name=\"no_feature\">Nenhuma função</string>\n    <string name=\"sort_by_sha\">Assinatura</string>\n    <string name=\"signatures\">Assinaturas</string>\n    <string name=\"app_signing_no_signatures\">Nenhuma assinatura válida</string>\n    <string name=\"configurations\">Configurações</string>\n    <string name=\"no_configurations\">Nenhuma configuração</string>\n    <string name=\"error\">Erro</string>\n    <string name=\"loading\">Carregando…</string>\n    <!-- &#8230; = ... -->\n    <string name=\"sort_by_app_label\">Rótulo do aplicativo</string>\n    <string name=\"sort_by_package_name\">Nome do pacote</string>\n    <string name=\"sort_by_domain\">Aplicativos do usuário primeiro</string>\n    <string name=\"data_received\">Dados recebidos</string>\n    <string name=\"data_transmitted\">Dados transmitidos</string>\n    <string name=\"data_usage_msg\">Uso de dados</string>\n    <string name=\"about\">Sobre</string>\n    <string name=\"data_size\">Dados</string>\n    <string name=\"cache_size\">Cache</string>\n    <string name=\"media_size\">Mídia</string>\n    <string name=\"app_not_installed\">Aplicativo não instalado</string>\n    <string name=\"system\">Sistema</string>\n    <string name=\"user\">Usuário</string>\n    <string name=\"sort\">Ordenar</string>\n    <string name=\"version_name_with_code\">Versão <xliff:g id=\"version_name\" example=\"2.5.17\">%1$s</xliff:g> (<xliff:g id=\"version_code\" example=\"365\">%2$d</xliff:g>)</string>\n    <string name=\"app_info\">Informações do Aplicativo</string>\n    <string name=\"system_app\">Aplicativo do Sistema</string>\n    <string name=\"user_app\">Aplicativo do Usuário</string>\n    <string name=\"paths_and_directories\">Caminhos &amp; Diretórios</string>\n    <string name=\"source_dir\">Diretório de Origem</string>\n    <string name=\"data_dir\">Diretório de Dados</string>\n    <string name=\"sdk_min\">Mín</string>\n    <string name=\"sdk_max\">Alvo</string>\n    <string name=\"more_info\">Mais Informações</string>\n    <string name=\"date_installed\">Data de Instalação</string>\n    <string name=\"date_updated\">Data de Atualização</string>\n    <string name=\"installer_app\">Aplicativo Instalador</string>\n    <string name=\"user_id\">ID do Usuário</string>\n    <string name=\"main_activity\">Atividade Principal</string>\n    <string name=\"empty_package_name\">Nome do pacote vazio</string>\n    <string name=\"error_creating_shortcut\">Erro ao criar atalho</string>\n    <string name=\"error_verbose_pin_shortcut\">O launcher atual não aceita PinShortcut. Não foi possível criar o atalho.</string>\n    <string name=\"starting_activity\">Iniciando atividade: <xliff:g id=\"activity_name\" example=\".main.MainActivity\">%1$s</xliff:g></string>\n    <string name=\"create_shortcut\">Criar Atalho</string>\n    <string name=\"shortcut_name\">Nome do Atalho</string>\n    <string name=\"package_name\">Nome do Pacote</string>\n    <string name=\"class_name\">Nome da Classe</string>\n    <string name=\"icon_picker\">Seletor de Ícone</string>\n    <string name=\"license\">Licença</string>\n    <string name=\"third_party\">Bibliotecas e Ícones de terceiros</string>\n    <string name=\"credits\">Créditos</string>\n    <string name=\"credits_message\">Aos autores do \\n- The Android Open Source Project \\n- <a href=\"https://github.com/zhaobozhen/libraries\">Absinthe\\'s libraries</a> \\n- <a href=\"https://github.com/butzist/ActivityLauncher\">Activity Launcher</a> \\n- <a href=\"https://bitbucket.org/oF2pks/fdroid-applications-info\">Apps_packages Info</a> \\n- <a href=\"https://github.com/zhaobao/AppsMonitor\">AppsMonitor</a> \\n- <a href=\"https://github.com/8enet/AppOpsX\">AppOpsX</a> \\n- <a href=\"https://github.com/gabrielemariotti/changeloglib\">ChangeLog Library</a> \\n- <a href=\"https://bitbucket.org/oF2pks/fdroid-classyshark3xodus\">ClassySharkAndroid</a> \\n- <a href=\"https://github.com/billthefarmer/editor\">Editor</a> \\n- <a href=\"https://github.com/Raival-e/File-Explorer\">File Explorer</a> \\n- <a href=\"https://github.com/nex3z/FlowLayout\">FlowLayout</a> \\n- <a href=\"https://github.com/k3b/intent-intercept\">Intent Intercept</a> \\n- <a href=\"https://github.com/YarikSOffice/lingver\">Lingver</a> \\n- <a href=\"https://github.com/topjohnwu/Magisk\">Magisk</a> \\n- <a href=\"https://github.com/zhanghai/MaterialFiles\">Material Files</a> \\n- <a href=\"https://github.com/pluscubed/matlog\">MatLog</a> \\n- <a href=\"https://github.com/matrix-org/matrix-android-sdk\">Matrix Android SDK</a> \\n- <a href=\"https://github.com/jensstein/oandbackup\">OAndBackup</a> \\n- <a href=\"https://github.com/open-keychain/open-keychain\">Open Keychain</a> \\n- <a href=\"https://github.com/Aefyr/SAI\">SAI</a> \\n- <a href=\"https://github.com/RikkaApps/Shizuku\">Shizuku</a> \\n- <a href=\"https://github.com/eclipse/tm4e\">tm4e</a> \\n- <a href=\"https://github.com/tuyafeng/Watt\">Watt</a></string>\n    <string name=\"word_wrap\">Alternar quebra de palavra</string>\n    <string name=\"class_viewer\">Visualizador de Classe</string>\n    <string name=\"toggle_class_listing\">Alternar Lista de Classes</string>\n    <string name=\"found_trackers\">Rastreadores Encontrados:</string>\n    <string name=\"tracker_details\">Detalhes do reastreador</string>\n    <string name=\"tracker_classes\">Classes rastreadoras</string>\n    <string name=\"all_classes\">Todas as classes</string>\n    <plurals name=\"main_list_date_days\">\n        <item quantity=\"one\"><xliff:g id=\"last_update_date\" example=\"20/10/2020\">%1$s</xliff:g> <xliff:g id=\"day_no\" example=\"5\">%2$d</xliff:g> dia</item>\n        <item quantity=\"many\"><xliff:g id=\"last_update_date\" example=\"20/10/2020\">%1$s</xliff:g> <xliff:g id=\"day_no\" example=\"5\">%2$d</xliff:g> dias</item>\n        <item quantity=\"other\"><xliff:g id=\"last_update_date\" example=\"20/10/2020\">%1$s</xliff:g> <xliff:g id=\"day_no\" example=\"5\">%2$d</xliff:g> dias</item>\n    </plurals>\n    <string name=\"no_shared_libs\">Nenhuma biblioteca compartilhada</string>\n    <string name=\"no_tracker_class\">Nenhuma classe rastreadora</string>\n    <string name=\"app_usage\">Uso de Aplicativos</string>\n    <string name=\"usage_weekly\">Semanal</string>\n    <string name=\"usage_today\">Hoje</string>\n    <string name=\"usage_7_days\">Últimos 7 dias</string>\n    <plurals name=\"usage_months\">\n        <item quantity=\"one\">%1$d mês</item>\n        <item quantity=\"many\">%1$d meses</item>\n        <item quantity=\"other\">%1$d meses</item>\n    </plurals>\n    <plurals name=\"usage_days\">\n        <item quantity=\"one\">%1$d dia</item>\n        <item quantity=\"many\">%1$d dias</item>\n        <item quantity=\"other\">%1$d dias</item>\n    </plurals>\n    <plurals name=\"usage_hours\">\n        <item quantity=\"one\">%1$d hora</item>\n        <item quantity=\"many\">%1$d horas</item>\n        <item quantity=\"other\">%1$d horas</item>\n    </plurals>\n    <string name=\"usage_less_than_a_minute\">Menos de um minuto</string>\n    <string name=\"go_back\">Voltar</string>\n    <string name=\"go\">Ir</string>\n    <string name=\"grant_usage_access\">Conceder Acesso ao Uso</string>\n    <string name=\"grant_usage_acess_message\">Usado para exibir informações de uso do aplicativo.</string>\n    <string name=\"share_apk\">Compartilhar APK</string>\n    <string name=\"failed_to_extract_apk_file\">O arquivo APK não pôde ser extraído</string>\n    <string name=\"menu_remove_rules\">Remover regras</string>\n    <string name=\"menu_apply_rules\">Aplicar regras</string>\n    <string name=\"search\">Buscar</string>\n    <string name=\"dev_protected_data_dir\">Diretório de dados protegidos pelo dispositivo</string>\n    <string name=\"process_name\">Nome do Processo</string>\n    <string name=\"no_code\">Nenhum código</string>\n    <string name=\"updated_app\">Atualizado</string>\n    <string name=\"test_only\">Apenas teste</string>\n    <string name=\"databases\">Bancos de dados</string>\n    <string name=\"save\">Salvar</string>\n    <string name=\"discard\">Descartar</string>\n    <string name=\"delete\">Excluir</string>\n    <string name=\"deleted_successfully\">Excluído</string>\n    <string name=\"deletion_failed\">Falha ao excluir</string>\n    <string name=\"saved_successfully\">Salvo</string>\n    <string name=\"saving_failed\">Falha ao salvar, tente novamente.</string>\n    <string name=\"string_value\">Valor da string</string>\n    <string name=\"integer_value\">Valor do número inteiro</string>\n    <string name=\"decimal_value\">Valor decimal</string>\n    <string name=\"boolean_value\">Valor booleano</string>\n    <string name=\"select_type\">Selecione um tipo</string>\n    <string name=\"add_item\">Adicionar item</string>\n    <string name=\"done\">Feito</string>\n    <string name=\"type_boolean\">Verdadeiro/Falso</string>\n    <string name=\"type_float\">Número Decimal</string>\n    <string name=\"type_int\">Número inteiro</string>\n    <string name=\"type_string\">Caracteres</string>\n    <string name=\"disabled_app\">Desativado</string>\n    <string name=\"no_usage_in_this_time_range\">Nenhum uso nesse intervalo de tempo</string>\n    <string name=\"no_content\">Nenhum conteúdo</string>\n    <string name=\"view_in_settings\">Ver nas Configurações</string>\n    <string name=\"uninstall_app_message\">Você deseja desinstalar este aplicativo\\?</string>\n    <string name=\"failed_to_uninstall\"><xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g> não pôde ser desinstalado.</string>\n    <string name=\"uninstalled_successfully\"><xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g> foi desinstalado.</string>\n    <string name=\"uninstall_system_app_message\">Este é um aplicativo do sistema. Tem certeza que deseja desinstalá-lo\\?</string>\n    <string name=\"stopped\">Parado</string>\n    <string name=\"disable\">Desativar</string>\n    <string name=\"enable\">Ativar</string>\n    <string name=\"force_stop\">Forçar parada</string>\n    <string name=\"failed_to_stop\"><xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g> não pôde ser parado.</string>\n    <string name=\"storage_and_cache\">Armazenamento e Cache</string>\n    <string name=\"total_size\">Total</string>\n    <string name=\"app_size\">Aplicativo</string>\n    <string name=\"app_ops\">Operações de Aplicativo</string>\n    <string name=\"no_app_ops\">Nenhuma operação de aplicativo</string>\n    <string name=\"failed_to_enable_op\">A operação de aplicativo solicitada não pôde ser ativada</string>\n    <string name=\"failed_to_disable_op\">A operação de aplicativo solicitada não pôde ser desativada</string>\n    <string name=\"pref_global_blocking_enabled\">Bloqueio imediato de componentes</string>\n    <string name=\"pref_global_blocking_enabled_msg\">Permite bloquear qualquer componente de qualquer aplicativo sem ligar explicitamente o bloqueio para o aplicativo.</string>\n    <string name=\"usage_access\">Acesso ao uso</string>\n    <string name=\"app_settings\">Configurações</string>\n    <string name=\"usage_yesterday\">Ontem</string>\n    <string name=\"exodus_link\">Link do εxodus</string>\n    <string name=\"sort_by_blocked_components\">Bloqueado primeiro</string>\n    <string name=\"external_data_dir\">Diretório de Dados Externo</string>\n    <string name=\"external_multiple_data_dir\">Diretório de Dados Externo <xliff:g id=\"dir_no\" example=\"1\">%1$d</xliff:g></string>\n    <plurals name=\"no_of_times_opened\">\n        <item quantity=\"one\">%1$d vez</item>\n        <item quantity=\"many\">%1$d vezes</item>\n        <item quantity=\"other\">%1$d vezes</item>\n    </plurals>\n    <string name=\"sort_by_last_used\">Último usado</string>\n    <string name=\"sort_by_screen_time\">Tempo de tela</string>\n    <string name=\"sort_by_times_opened\">Vezes abertas</string>\n    <string name=\"sort_by_mobile_data\">Dados móveis</string>\n    <string name=\"pref_import_export_blocking_rules\">Importar/exportar regras de bloqueio</string>\n    <string name=\"pref_import_export_blocking_rules_msg\">Importar/exportar regras, importar regras externas do Watt ou Blocker.</string>\n    <string name=\"pref_import_watt\">Importar do Watt</string>\n    <string name=\"pref_import_blocker\">Importar do Blocker</string>\n    <string name=\"the_import_was_successful\">Importado</string>\n    <string name=\"the_export_was_successful\">Exportado</string>\n    <plurals name=\"failed_to_import_files\">\n        <item quantity=\"one\">%1$d arquivo não pôde ser importado.</item>\n        <item quantity=\"many\">%1$d arquivos não puderam ser importados.</item>\n        <item quantity=\"other\">%1$d arquivos não puderam ser importados.</item>\n    </plurals>\n    <string name=\"apk_updater\">APK Updater</string>\n    <string name=\"running_apps\">Aplicativos em Execução</string>\n    <string name=\"kill_process\">Encerrar</string>\n    <string name=\"disable_background_run\">Deter a operação em segundo plano</string>\n    <string name=\"pid_and_ppid\">ID do processo: %1$d; ID do processo principal: %2$d</string>\n    <string name=\"memory_virtual_memory\">Memória: %1$s, Memória Virtual: %2$s</string>\n    <string name=\"user_and_uid\">Usuário: <xliff:g id=\"user_name\" example=\"root\">%1$s</xliff:g> (<xliff:g id=\"user_id\" example=\"0\">%2$d</xliff:g>)</string>\n    <string name=\"clear_data\">Limpar Dados</string>\n    <string name=\"backup_restore\">Backup/Restauração</string>\n    <string name=\"disable_background\">Impedir a operação em segundo plano</string>\n    <string name=\"export_blocking_rules\">Exportar Regras de Bloqueio</string>\n    <plurals name=\"alert_failed_to_clear_data\">\n        <item quantity=\"one\">%1$d aplicativo não pôde ter os dados limpos</item>\n        <item quantity=\"many\">%1$d aplicativos não puderam ter os dados limpos</item>\n        <item quantity=\"other\">%1$d aplicativos não puderam ter os dados limpos</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_uninstall\">\n        <item quantity=\"one\">%1$d aplicativo não pôde ser desinstalado</item>\n        <item quantity=\"many\">%1$d aplicativos não puderam ser desinstalados</item>\n        <item quantity=\"other\">%1$d aplicativos não puderam ser desinstalados</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_disable_background\">\n        <item quantity=\"one\">Inapto de deter %1$d aplicativo de executar em segundo plano</item>\n        <item quantity=\"many\">Inapto de deter %1$d aplicativos de executar em segundo plano</item>\n        <item quantity=\"other\">Inapto de deter %1$d aplicativos de executar em segundo plano</item>\n    </plurals>\n    <string name=\"the_operation_was_successful\">Feito</string>\n    <plurals name=\"alert_failed_to_force_stop\">\n        <item quantity=\"one\">%1$d aplicativo não pôde ser forçado a parar</item>\n        <item quantity=\"many\">%1$d aplicativos não puderam ser forçados a parar</item>\n        <item quantity=\"other\">%1$d aplicativos não puderam ser forçados a parar</item>\n    </plurals>\n    <string name=\"toggle_kill_for_system_apps\">Alternar encerramento de aplicativos de sistema</string>\n    <string name=\"permission_name\">Nome da Permissão</string>\n    <string name=\"mode\">Modo</string>\n    <string name=\"running\">Executando</string>\n    <string name=\"duration\">Duração</string>\n    <string name=\"ago\">atrás</string>\n    <string name=\"pref_import\">Importar</string>\n    <string name=\"pref_export\">Exportar</string>\n    <string name=\"import_options\">Opções de Importação</string>\n    <string name=\"export_options\">Opções de Exportação</string>\n    <string name=\"import_failed\">Falha ao importar!</string>\n    <string name=\"export_failed\">Falha ao exportar!</string>\n    <string name=\"keyboard_type\">Tipo de Teclado</string>\n    <string name=\"navigation\">Navegação</string>\n    <string name=\"pref_export_msg\">Exportar regras de bloqueio configuradas no App Manager para o armazenamento externo.</string>\n    <string name=\"pref_import_msg\">Importar regras de bloqueio exportadas anteriormente do App Manager.</string>\n    <string name=\"pref_import_watt_msg\">Importar regras de bloqueio do Watt, cada arquivo contendo regras para um único pacote nomeado como <tt>packagename.xml</tt>, etc.</string>\n    <string name=\"pref_import_blocker_msg\">Importar regras de bloqueio do Blocker. Cada arquivo contém regras para um único pacote.</string>\n    <string name=\"pref_app_theme\">Tema do aplicativo</string>\n    <string name=\"follow_system\">Seguir o sistema</string>\n    <string name=\"battery_mode\">Modo de bateria</string>\n    <string name=\"day\">Dia</string>\n    <string name=\"night\">Noite</string>\n    <string name=\"select_theme\">Tema</string>\n    <string name=\"apply\">Aplicar</string>\n    <string name=\"pref_about_msg\">Versão, licenças, créditos, etc. do App Manager.</string>\n    <string name=\"version\">Versão</string>\n    <string name=\"sort_by_wifi_data\">Dados Wi-Fi</string>\n    <string name=\"block_trackers\">Bloquear rastreadores</string>\n    <string name=\"sort_by_component_name\">Nome do componente</string>\n    <string name=\"reset_to_default\">Restaurar ao padrão</string>\n    <string name=\"deny_dangerous_app_ops\">Negar operações de aplicativo perigosas</string>\n    <string name=\"sort_by_app_ops_names\">Nome das operações de aplicativo</string>\n    <string name=\"sort_by_denied_app_ops\">Negado primeiro</string>\n    <string name=\"sort_by_app_ops_values\">Valor das operações de aplicativo</string>\n    <string name=\"sort_by_permission_names\">Nome da permissão</string>\n    <string name=\"sort_by_dangerous_permissions\">Perigoso primeiro</string>\n    <string name=\"sort_by_denied_permissions\">Bloqueado primeiro</string>\n    <string name=\"deny_dangerous_permissions\">Negar permissões perigosas</string>\n    <string name=\"sort_by_tracker_components\">Rastreadores primeiro</string>\n    <string name=\"unknown_op\">Operação Desconhecida</string>\n    <plurals name=\"alert_failed_to_disable_trackers\">\n        <item quantity=\"one\">%1$d aplicativo não pôde ter os rastreadores desativados</item>\n        <item quantity=\"many\">%1$d aplicativos não puderam ter os rastreadores desativados</item>\n        <item quantity=\"other\">%1$d aplicativos não puderam ter os rastreadores desativados</item>\n    </plurals>\n    <string name=\"failed_to_grant_permission\">A permissão não pôde ser concedida</string>\n    <string name=\"failed_to_revoke_permission\">A permissão não pôde ser revogada</string>\n    <string name=\"failed_to_reset_app_ops\">Não foi possível redefinir as operações de aplicativo</string>\n    <string name=\"failed_to_deny_dangerous_perms\">Não foi possível negar todas as permissões perigosas</string>\n    <string name=\"failed_to_deny_dangerous_app_ops\">Não foi possível negar todas as operações de aplicativo perigosas</string>\n    <string name=\"launch_app\">Iniciar</string>\n    <string name=\"never_ask\">Nunca perguntar</string>\n    <string name=\"external_apk_no_app_op\">APKs externos não possuem nenhuma operação de aplicativo</string>\n    <string name=\"manifest_viewer\">Visualizador de Manifest</string>\n    <plurals name=\"no_of_trackers\">\n        <item quantity=\"one\">%1$d rastreador</item>\n        <item quantity=\"many\">%1$d rastreadores</item>\n        <item quantity=\"other\">%1$d rastreadores</item>\n    </plurals>\n    <string name=\"install\">Instalar</string>\n    <string name=\"update\">Atualizar</string>\n    <string name=\"source_code\">Código Fonte</string>\n    <string name=\"pref_import_existing\">Importar regras existentes</string>\n    <string name=\"pref_import_existing_msg\">Adicione componentes desativados por outros aplicativos ao App Manager. Tenha cuidado ao usar essa ferramenta, pois podem haver muitos falsos positivos. Escolha apenas os aplicativos sobre os quais você tem certeza.</string>\n    <string name=\"clear_cache\">Limpar Cache</string>\n    <string name=\"block_unblock_trackers_description\">Bloquear ou desbloquear componentes de propagandas e rastreamento em todos os aplicativos instalados</string>\n    <string name=\"block_components_dots\">Bloquear componentes…</string>\n    <string name=\"clear_data_from_uninstalled_apps\">Limpar dados dos aplicativos desinstalados</string>\n    <string name=\"clear_data_from_uninstalled_apps_description\">Limpar dados dos aplicativos que foram desinstalados com a flag <tt>DONT_DELETE_DATA</tt></string>\n    <string name=\"clear_app_cache\">Limpar cache do aplicativo</string>\n    <string name=\"clear_app_cache_description\">Limpar o cache de todos os aplicativos</string>\n    <string name=\"no_tracker_found\">Nenhum rastreador encontrado</string>\n    <string name=\"failed_packages\">Pacotes falhados</string>\n    <string name=\"input_signatures_description\">Insira assinaturas com espaços, p. ex. <tt>com.facebook org.app2 com.app3</tt> etc.</string>\n    <string name=\"filtered_packages\">Pacotes filtrados</string>\n    <string name=\"only_works_in_root_or_adb_mode\">Funciona apenas no modo Root ou ADB</string>\n    <string name=\"failed_to_parse_some_numbers\">Não foi possível analisar alguns números</string>\n    <plurals name=\"no_of_splits\">\n        <item quantity=\"one\">%1$d divisão</item>\n        <item quantity=\"many\">%1$d divisões</item>\n        <item quantity=\"other\">%1$d divisões</item>\n    </plurals>\n    <string name=\"package_name_is_installed_successfully\"><xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g> instalado</string>\n    <string name=\"filter\">Filtrar</string>\n    <string name=\"filter_user_apps\">Aplicativos do usuário</string>\n    <string name=\"filter_system_apps\">Aplicativos do sistema</string>\n    <string name=\"filter_apps_with_rules\">Aplicativos com regras</string>\n    <string name=\"select_all\">Selecionar Tudo</string>\n    <string name=\"installed_version\">Versão Instalada</string>\n    <string name=\"trackers\">Rastreadores</string>\n    <string name=\"components\">Componentes</string>\n    <string name=\"features\">Funções</string>\n    <string name=\"whats_new\">Novidades</string>\n    <string name=\"blocking_rules\">Regras de bloqueio</string>\n    <string name=\"external_data\">Dados externos</string>\n    <string name=\"data\">Dados</string>\n    <string name=\"backup\">Backup</string>\n    <string name=\"restore\">Restaurar</string>\n    <string name=\"delete_backup\">Excluir backup</string>\n    <string name=\"backup_options\">Opções de Backup</string>\n    <plurals name=\"failed_to_backup_some_apk_files\">\n        <item quantity=\"one\">%1$d aplicativo não pôde ter o backup feito</item>\n        <item quantity=\"many\">%1$d aplicativos não puderam ter o backup feito</item>\n        <item quantity=\"other\">%1$d aplicativos não puderam ter o backup feito</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_backup\">\n        <item quantity=\"one\">%1$d aplicativo não pôde ter o backup feito</item>\n        <item quantity=\"many\">%1$d aplicativos não puderam ter o backup feito</item>\n        <item quantity=\"other\">%1$d aplicativos não puderam ter o backup feito</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_restore\">\n        <item quantity=\"one\">%1$d aplicativo não pôde ser restaurado</item>\n        <item quantity=\"many\">%1$d aplicativos não puderam ser restaurados</item>\n        <item quantity=\"other\">%1$d aplicativos não puderam ser restaurados</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_delete_backup\">\n        <item quantity=\"one\">%1$d backup não pôde ser excluído</item>\n        <item quantity=\"many\">%1$d backups não puderam ser excluídos</item>\n        <item quantity=\"other\">%1$d backups não puderam ser excluídos</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_unblock_trackers\">\n        <item quantity=\"one\">%1$d aplicativo não pôde ter os rastreadores desbloqueados</item>\n        <item quantity=\"many\">%1$d aplicativos não puderam ter os rastreadores desbloqueados</item>\n        <item quantity=\"other\">%1$d aplicativos não puderam ter os rastreadores desbloqueados</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_block_components\">\n        <item quantity=\"one\">%1$d aplicativo não pôde ter os componentes bloqueados</item>\n        <item quantity=\"many\">%1$d aplicativos não puderam ter os componentes bloqueados</item>\n        <item quantity=\"other\">%1$d aplicativos não puderam ter os componentes bloqueados</item>\n    </plurals>\n    <string name=\"apply_to_system_apps\">Aplicar aos aplicativos do sistema</string>\n    <string name=\"apply_to_system_apps_question\">Aplicar aos aplicativos do sistema também\\? Selecione \\\"Não\\\" se não tiver certeza.</string>\n    <string name=\"no\">Não</string>\n    <string name=\"yes\">Sim</string>\n    <string name=\"skip_signature_checks\">Pular verificação de assinatura</string>\n    <string name=\"clear_data_message\">Tem certeza que deseja deletar os dados desse aplicativo\\?</string>\n    <string name=\"clear\">Limpar</string>\n    <string name=\"block\">Bloquear</string>\n    <string name=\"unblock\">Desbloquear</string>\n    <string name=\"block_unblock_trackers\">Bloquear/desbloquear rastreadores</string>\n    <string name=\"no_matching_package_found\">Não foi possível encontrar nenhum aplicativo desse tipo</string>\n    <string name=\"export_icon\">Extrair Ícone</string>\n    <string name=\"open_in_termux\">Abrir no Termux</string>\n    <string name=\"run_in_termux\">Executar no Termux</string>\n    <string name=\"website\">Site</string>\n    <string name=\"pref_remove_all_rules\">Remover todas as regras</string>\n    <string name=\"pref_remove_all_rules_msg\">As permissões serão concedidas, as operações de aplicativo e os componentes voltarão a seus valores padrão.</string>\n    <string name=\"are_you_sure\">Tem certeza?</string>\n    <string name=\"filter_apps_with_activities\">Com atividades</string>\n    <string name=\"toggle_default_app_ops\">Alternar operações de aplicativo padrões</string>\n    <string name=\"installer_error_aborted\">A instalação falhou ou porque foi cancelada ou a sessão foi encerrada inesperadamente</string>\n    <string name=\"installer_error_blocked_device\">dispositivo</string>\n    <string name=\"installer_error_blocked\">Instalação bloqueada por <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g></string>\n    <string name=\"installer_error_conflict\">Não foi possível instalar o aplicativo porque o nome do pacote está em uso</string>\n    <string name=\"installer_error_incompatible\">O aplicativo é incompatível com esse dispositivo</string>\n    <string name=\"installer_error_bad_apks\">Arquivos APK inválidos selecionados</string>\n    <string name=\"installer_error_storage\">Não há espaço suficiente no armazenamento para instalar esse aplicativo</string>\n    <string name=\"installer_error_generic\">Falha na instalação</string>\n    <string name=\"installer_error_lidl_rom\">Sua ROM é incompatível com o Instalador Rootless.</string>\n    <string name=\"failed_to_fetch_package_info\">Não foi possível obter informações do pacote</string>\n    <string name=\"batch_ops\">Operações em Lote</string>\n    <string name=\"operation_running\">Operação em execução…</string>\n    <string name=\"full_stop_tap_to_see_details\">. Toque para ver detalhes.</string>\n    <string name=\"try_again\">Tentar novamente</string>\n    <string name=\"install_app_message\">Você deseja instalar este app?</string>\n    <string name=\"reinstall\">Reinstalar</string>\n    <string name=\"unblock_trackers\">Desbloquear rastreadores</string>\n    <string name=\"package_installer\">Instalador de Pacotes</string>\n    <string name=\"install_in_progress\">Instalando…</string>\n    <string name=\"installer_error_security\">Não foi possível acessar os arquivos APK</string>\n    <string name=\"installer_error_session_create\">Uma sessão de instalação não pôde ser criada</string>\n    <string name=\"installer_error_session_write\">Não foi possível gravar na sessão de instalação</string>\n    <string name=\"installer_error_session_commit\">O commit dos arquivos APK não pôde ser feito</string>\n    <string name=\"installer_error_session_abandon\">A sessão de instalação não pôde ser abandonada</string>\n    <string name=\"backup_apk_files\">Arquivos APK</string>\n    <string name=\"failed_to_extract_obb_files\">Não foi possível extrair arquivos OBB</string>\n    <string name=\"obb_files_extracted_successfully\">Arquivos OBB extraídos</string>\n    <string name=\"backup_multiple\">Backup múltiplo</string>\n    <string name=\"backup_all_users\">Todos os usuários</string>\n    <string name=\"pref_app_language\">Idioma</string>\n    <string name=\"choose_language\">Mudar idioma</string>\n    <string name=\"shared_prefs\">Preferências Compartilhadas</string>\n    <string name=\"debuggable\">Depurável</string>\n    <string name=\"requested_large_heap\">Grande heap</string>\n    <string name=\"native_library_dir\">Diretório Nativo da Biblioteca JNI</string>\n    <string name=\"sdk_flags\">Flags</string>\n    <string name=\"obb_size\">Obb</string>\n    <string name=\"sort_by_target_sdk\">SDK alvo</string>\n    <string name=\"manifest\">Manifesto</string>\n    <string name=\"input_features\">Inserir funções</string>\n    <string name=\"shared_user_id\">ID de Usuário Compartilhado</string>\n    <string name=\"sort_by_shared_user_id\">ID de Usuário compartilhado</string>\n    <string name=\"shared_libs\">Bibliotecas compartilhadas</string>\n    <string name=\"flags\">Flags</string>\n    <string name=\"soft_input\">Modo de entrada suave</string>\n    <string name=\"task_affinity\">Afinidade de tarefas</string>\n    <string name=\"providers\">Provedores</string>\n    <string name=\"receivers\">Receptores</string>\n    <string name=\"str_logo\">Logo</string>\n    <string name=\"rules_not_applied\">Regras não são aplicadas</string>\n    <string name=\"key_name_cannot_be_null\">O nome da chave não pode estar vazio</string>\n    <string name=\"error_evaluating_input\">Não foi possível avaliar a entrada</string>\n    <string name=\"input_signatures\">Inserir assinaturas</string>\n    <string name=\"type_long\">Número inteiro longo</string>\n    <string name=\"key_name\">Nome da Chave</string>\n    <string name=\"long_integer_value\">Valor do número inteiro longo</string>\n    <plurals name=\"backup_exists_are_you_sure\">\n        <item quantity=\"one\">O backup já existe. Tem certeza\\?</item>\n        <item quantity=\"many\">Mais de um aplicativo já tem um backup. Tem certeza\\?</item>\n        <item quantity=\"other\">Mais de um aplicativo já tem um backup. Tem certeza\\?</item>\n    </plurals>\n    <string name=\"pref_backup_flags_msg\">Adicionar uma predefinição para opções de backup remove o fardo de selecionar flags toda vez que você faz backup/restaura.</string>\n    <string name=\"reject_time\">Tempo de Rejeição</string>\n    <string name=\"accept_time\">Tempo de Aceitação</string>\n    <string name=\"deny_app_ops_description\">Defina um modo para as operações de aplicativo identificadas pelos valores das constantes, ou seja, <tt>63</tt> ou <tt>RUN_IN_BACKGROUND</tt></string>\n    <string name=\"changelog\">Histórico de Atualizações</string>\n    <string name=\"one_click_ops\">Operações em 1 Clique</string>\n    <string name=\"touchscreen\">Tela sensível ao toque</string>\n    <string name=\"no_libs\">Nenhuma biblioteca</string>\n    <string name=\"no_apps\">Nenhum aplicativo</string>\n    <string name=\"state_unknown\">Desconhecido</string>\n    <string name=\"keyboard_no_keys\">Nenhuma tecla</string>\n    <string name=\"orientation_no_sensor\">Nenhum sensor</string>\n    <plurals name=\"other_trackers_and_classes\">\n        <item quantity=\"one\"><xliff:g id=\"tracker_no\" example=\"8\">%1$d</xliff:g> rastreadores com <xliff:g id=\"class_no\" example=\"50\">%2$d</xliff:g> classes</item>\n        <item quantity=\"many\"><xliff:g id=\"tracker_no\" example=\"8\">%1$d</xliff:g> rastreadores com <xliff:g id=\"class_no\" example=\"50\">%2$d</xliff:g> classes</item>\n        <item quantity=\"other\"><xliff:g id=\"tracker_no\" example=\"8\">%1$d</xliff:g> rastreadores com <xliff:g id=\"class_no\" example=\"50\">%2$d</xliff:g> classes</item>\n    </plurals>\n    <plurals name=\"two_trackers_and_classes\">\n        <item quantity=\"one\">2 rastreadores com <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g> classes</item>\n        <item quantity=\"many\">2 rastreadores com <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g> classes</item>\n        <item quantity=\"other\">2 rastreadores com <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g> classes</item>\n    </plurals>\n    <plurals name=\"tracker_and_classes\">\n        <item quantity=\"one\">1 rastreador com <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g> classe</item>\n        <item quantity=\"many\">1 rastreador com <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g> classes</item>\n        <item quantity=\"other\">1 rastreador com <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g> classes</item>\n    </plurals>\n    <string name=\"termux\">Termux</string>\n    <string name=\"split_feature_name\">Função: <xliff:g id=\"feature_name\" example=\"Visualizer\">%1$s</xliff:g></string>\n    <string name=\"base_apk\">APK Base</string>\n    <string name=\"auto\">Automático</string>\n    <string name=\"backup_obb_media\">OBB e Mídia</string>\n    <plurals name=\"missing_signatures\">\n        <item quantity=\"one\">%1$d assinatura ausente</item>\n        <item quantity=\"many\">%1$d assinaturas ausentes</item>\n        <item quantity=\"other\">%1$d assinaturas ausentes</item>\n    </plurals>\n    <plurals name=\"libraries\">\n        <item quantity=\"one\">%1$d biblioteca</item>\n        <item quantity=\"many\">%1$d bibliotecas</item>\n        <item quantity=\"other\">%1$d bibliotecas</item>\n    </plurals>\n    <plurals name=\"classes\">\n        <item quantity=\"one\">%1$d classe</item>\n        <item quantity=\"many\">%1$d classes</item>\n        <item quantity=\"other\">%1$d classes</item>\n    </plurals>\n    <string name=\"type\">Tipo</string>\n    <string name=\"validity\">Validade</string>\n    <string name=\"valid\">Válido</string>\n    <string name=\"expired\">Expirado</string>\n    <string name=\"not_yet_valid\">Ainda não é válido</string>\n    <string name=\"serial_no\">Número de Série</string>\n    <string name=\"checksums\">Checksums</string>\n    <string name=\"app_signing_signature\">Assinatura</string>\n    <string name=\"algorithm\">Algoritmo</string>\n    <string name=\"public_key\">Chave Pública</string>\n    <string name=\"format\">Formato</string>\n    <string name=\"rsa_exponent\">Expoente</string>\n    <string name=\"expiry_date\">Data de validade</string>\n    <string name=\"issued_date\">Data de emissão</string>\n    <string name=\"issuer\">Emissor</string>\n    <string name=\"subject\">Assunto</string>\n    <string name=\"filter_apps_with_backups\">Com backups</string>\n    <string name=\"sort_by_backup\">Com backup primeiro</string>\n    <string name=\"failed_to_uninstall_updates\">Não foi possível desinstalar as atualizações do aplicativo <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g>.</string>\n    <string name=\"update_uninstalled_successfully\">As atualizações do aplicativo <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g> foram desinstaladas.</string>\n    <string name=\"uninstall_updates\">Desinstalar Atualizações</string>\n    <string name=\"allow_open_pgp_operation\">Toque para permitir que o App Manager use o OpenPGP</string>\n    <string name=\"confirm_installation\">Confirmar instalação</string>\n    <string name=\"pref_compression_method\">Método de compressão</string>\n    <string name=\"rules\">Regras</string>\n    <string name=\"other\">Outros</string>\n    <string name=\"changes_not_saved\">Mudanças não salvas</string>\n    <string name=\"sort_by_memory_usage\">Uso de memória</string>\n    <string name=\"sort_by_apps_first\">Aplicativos primeiro</string>\n    <string name=\"sort_by_process_name\">Nome do processo</string>\n    <string name=\"sort_by_process_id\">ID do processo</string>\n    <string name=\"filter_apps\">Aplicativos</string>\n    <string name=\"apps\">Aplicativos</string>\n    <string name=\"apply_now\">Aplicar agora…</string>\n    <string name=\"no_profiles\">Nenhum perfil</string>\n    <string name=\"open_pgp_provider\">Provedor OpenPGP</string>\n    <string name=\"cancel\">Cancelar</string>\n    <string name=\"ok\">OK</string>\n    <string name=\"input_backup_name_description\">O nome do backup não deve começar com um dígito nem deve conter qualquer espaço. Deixe-o vazio se quiser usar a data-hora atual.</string>\n    <string name=\"input_backup_name\">Nome do backup</string>\n    <string name=\"downgrade\">Downgrade</string>\n    <string name=\"process_state_with_extra\">Estado: <xliff:g id=\"process_state\" example=\"Sleeping\">%1$s</xliff:g> (<xliff:g id=\"state_extra\" example=\"High priority\">%2$s</xliff:g>)</string>\n    <string name=\"process_state\">Estado: <xliff:g id=\"process_state\" example=\"Sleeping\">%1$s</xliff:g></string>\n    <string name=\"state_foreground\">Primeiro plano</string>\n    <string name=\"state_session_leader\">Líder da sessão</string>\n    <string name=\"state_locked_memory\">Memória trancada</string>\n    <string name=\"orientation_locked\">Bloqueado</string>\n    <string name=\"state_low_priority\">Baixa prioridade</string>\n    <string name=\"state_high_priority\">Alta prioridade</string>\n    <string name=\"dsa_affine_y\">Atribuir coordenada y</string>\n    <string name=\"dsa_affine_x\">Atribuir coordenada x</string>\n    <string name=\"rsa_modulus\">Módulo</string>\n    <string name=\"critical_exts\">Extensões Críticas</string>\n    <string name=\"non_critical_exts\">Extensões Não-críticas</string>\n    <string name=\"usage_access_not_supported\">Não foi possível solicitar o acesso ao uso, pois a página de configurações correspondente não existe.</string>\n    <string name=\"do_you_want_to_uninstall_and_install\">Deseja desinstalar e instalar o aplicativo novamente\\?</string>\n    <string name=\"app_signing_signature_mismatch_for_system_apps\">Não foi possível instalar o aplicativo porque um aplicativo do sistema com uma assinatura diferente tem esse nome de pacote.</string>\n    <string name=\"app_data_will_be_lost\">Os dados existentes serão perdidos.</string>\n    <string name=\"app_signing_install_without_data_loss\">Se você desligou a verificação de assinatura, você pode usar a opção <b>Apenas instalar</b> para instalar o aplicativo sem perder dados.</string>\n    <string name=\"only_install\">Apenas Instalar</string>\n    <string name=\"sys_config\">Configurações do Sistema</string>\n    <string name=\"scanner\">Scanner</string>\n    <string name=\"lib_details\">Detalhes da biblioteca</string>\n    <string name=\"tap_to_see_details\">Toque para ver detalhes</string>\n    <string name=\"view_missing_signatures\">Toque para visualizar ou enviar assinaturas ainda não presentes no banco de dados de bibliotecas do App Manager.</string>\n    <string name=\"copy\">Copiar</string>\n    <string name=\"filter_running_apps\">Aplicativos em execução</string>\n    <string name=\"profiles\">Perfis</string>\n    <string name=\"state_idle\">Ocioso</string>\n    <string name=\"state_device_io\">I/O do dispositivo</string>\n    <string name=\"touchscreen_finger\">Dedo</string>\n    <string name=\"touchscreen_stylus\">Caneta</string>\n    <string name=\"touchscreen_no_touch\">Sem touch</string>\n    <string name=\"navigation_wheel\">Roda</string>\n    <string name=\"navigation_trackball\">Trackball</string>\n    <string name=\"navigation_dial_pad\">Discador</string>\n    <string name=\"navigation_no_nav\">Sem nav</string>\n    <string name=\"keyboard_12_keys\">12 teclas</string>\n    <string name=\"keyboard_qwerty\">QWERTY</string>\n    <string name=\"_undefined\">Indefinido</string>\n    <string name=\"required\">Exigido</string>\n    <string name=\"orientation_user_portrait\">Retrato, seguindo o usuário</string>\n    <string name=\"orientation_user_landscape\">Paisagem, seguindo o usuário</string>\n    <string name=\"orientation_sensor\">Sensor</string>\n    <string name=\"orientation_sensor_portrait\">Retrato, seguindo o sensor</string>\n    <string name=\"orientation_sensor_landscape\">Paisagem, seguindo o sensor</string>\n    <string name=\"orientation_user\">Usuário</string>\n    <string name=\"orientation_reverse_landscape\">Paisagem invertida</string>\n    <string name=\"orientation_reverse_portrait\">Retrato invertido</string>\n    <string name=\"orientation_portrait\">Retrato</string>\n    <string name=\"orientation_landscape\">Paisagem</string>\n    <string name=\"orientation_full_user\">Usuário completo</string>\n    <string name=\"orientation_full_sensor\">Sensor completo</string>\n    <string name=\"orientation_behind\">Atrás</string>\n    <string name=\"orientation_unspecified\">Não especificado</string>\n    <string name=\"launch_mode_single_top\">Top único</string>\n    <string name=\"launch_mode_single_task\">Tarefa única</string>\n    <string name=\"launch_mode_single_instance\">Instância única</string>\n    <string name=\"launch_mode_multiple\">Vários</string>\n    <string name=\"locale_split_for_base_apk\">Idioma <xliff:g id=\"split_name\" example=\"English\">%1$s</xliff:g> para o APK base</string>\n    <string name=\"abi_split_for_base_apk\">Código <xliff:g id=\"split_name\" example=\"arm64_v8a\">%1$s</xliff:g> para o APK base</string>\n    <string name=\"density_split_for_base_apk\">Recursos de <xliff:g id=\"split_name\" example=\"xxdpi\">%1$s</xliff:g> (<xliff:g id=\"dpi_no\" example=\"480\">%2$d</xliff:g> DPI) para o APK base</string>\n    <string name=\"locale_split_for_feature\">Idioma <xliff:g id=\"split_name\" example=\"English\">%1$s</xliff:g> para a função <xliff:g id=\"feature_name\" example=\"Visualizer\">%2$s</xliff:g></string>\n    <string name=\"abi_split_for_feature\">Código <xliff:g id=\"split_name\" example=\"arm64_v8a\">%1$s</xliff:g> para <xliff:g id=\"feature_name\" example=\"Visualizer\">%2$s</xliff:g></string>\n    <string name=\"density_split_for_feature\">Recursos de <xliff:g id=\"split_name\" example=\"xxdpi\">%1$s</xliff:g> (<xliff:g id=\"dpi_no\" example=\"480\">%2$d</xliff:g> DPI) para a função <xliff:g id=\"feature_name\" example=\"Visualizer\">%3$s</xliff:g></string>\n    <string name=\"unknown_split_for_feature\"><xliff:g id=\"split_name\" example=\"some_split\">%1$s</xliff:g> para a função <xliff:g id=\"feature_name\" example=\"Visualizer\">%2$s</xliff:g></string>\n    <string name=\"unknown_split_for_base_apk\"><xliff:g id=\"split_name\" example=\"some_split\">%1$s</xliff:g> para o APK base</string>\n    <string name=\"routine_ops\">Operações de rotina</string>\n    <string name=\"input_app_ops_description\">Insira nomes e/ou constantes de operações de aplicativo com espaços, por exemplo <tt>WAKE_LOCK 63 72 CAMERA</tt> etc.</string>\n    <string name=\"input_app_ops\">Inserir operações de aplicativo</string>\n    <string name=\"state_waking\">Acordando</string>\n    <string name=\"state_parked\">Estacionado</string>\n    <string name=\"state_wake_kill\">Encerrado ao acordar</string>\n    <string name=\"state_zombie\">Zumbi</string>\n    <string name=\"state_dead\">Morto</string>\n    <string name=\"state_trace_stop\">Rastreamento parado</string>\n    <string name=\"state_sleeping\">Dormindo</string>\n    <string name=\"state_multithreaded\">Multithreaded</string>\n    <string name=\"systemless_app\">Aplicativo sem Sistema</string>\n    <string name=\"keystore\">KeyStore</string>\n    <string name=\"send_crash_report\">Enviar relatório de travamento</string>\n    <string name=\"tap_to_submit_crash_report\">Toque para enviar o relatório de travamento.</string>\n    <string name=\"am_crashed\">O App Manager acabou de travar</string>\n    <string name=\"select_apk\">Selecionar APK</string>\n    <string name=\"un_apkm\">UnApkm</string>\n    <string name=\"in_progress\">Em andamento</string>\n    <string name=\"conversion_failed\">Falha na conversão.</string>\n    <string name=\"duplicate\">Duplicar</string>\n    <string name=\"new_profile\">Novo perfil</string>\n    <string name=\"input_profile_name_description\">O nome do perfil não pode conter espaços.</string>\n    <string name=\"input_profile_name\">Nome do perfil</string>\n    <string name=\"pref_encryption_msg\">Criptografia para backups.</string>\n    <string name=\"ecc\">Criptografia de curva elíptica</string>\n    <string name=\"rsa\">RSA</string>\n    <string name=\"aes\">AES</string>\n    <string name=\"none\">Nenhuma</string>\n    <string name=\"encryption\">Criptografia</string>\n    <string name=\"select_user\">Selecionar usuário</string>\n    <string name=\"failed_to_duplicate_profile\">Não foi possível duplicar o perfil</string>\n    <string name=\"send_selected\">Enviar selecionado</string>\n    <string name=\"input_permissions_description\">Insira permissões com espaços, p. ex. <tt>com.permission.GET_ACCOUNTS android.permission.ACCESS_MEDIA_LOCATION</tt> etc. Use <tt>*</tt> para solicitar todas as permissões.</string>\n    <string name=\"input_permissions\">Inserir permissões</string>\n    <string name=\"enabled\">Ativado</string>\n    <string name=\"choose\">Escolher</string>\n    <string name=\"options\">Opções</string>\n    <string name=\"off\">Desligado</string>\n    <string name=\"on\">Ligado</string>\n    <string name=\"profile_state_msg\">Estado de ligado/desligado personalizado para este perfil</string>\n    <string name=\"profile_block_trackers_msg\">Bloqueia os rastreadores nos aplicativos</string>\n    <string name=\"profile_clear_data_msg\">Limpa os dados dos aplicativos</string>\n    <string name=\"profile_clear_cache_msg\">Limpa o cache de aplicativo dos aplicativos</string>\n    <string name=\"profile_force_stop_msg\">Força a parada dos aplicativos</string>\n    <string name=\"allow_routine_ops_msg\">Permitir que o perfil seja usado nas operações de rotina</string>\n    <string name=\"profile_state\">Estado do perfil</string>\n    <string name=\"allow_routine_ops\">Permitir operações de rotina</string>\n    <string name=\"adb_over_tcp\">ADB sobre TCP</string>\n    <string name=\"pref_mode_of_operations\">Modo de operação</string>\n    <string name=\"user_profile_with_id\">Perfil: %1$s (%2$d)</string>\n    <string name=\"advanced\">Avançado</string>\n    <string name=\"simple\">Simples</string>\n    <string name=\"close\">Fechar</string>\n    <string name=\"no_root\">Sem root</string>\n    <string name=\"root\">Root</string>\n    <string name=\"install_location\">Local de Instalação</string>\n    <string name=\"install_location_prefer_external\">Preferir externo</string>\n    <string name=\"install_location_internal_only\">Somente interno</string>\n    <string name=\"installer\">Instalador</string>\n    <string name=\"comment\">Comentário</string>\n    <string name=\"pref_sign_apk_msg\">Assinar arquivos APK antes de instalá-los.</string>\n    <string name=\"pref_sign_apk\">Assinar APK</string>\n    <string name=\"pref_signature_schemes_msg\">Pelo menos os esquemas v1 e v2 devem ser selecionados para uma maior compatibilidade. O esquema v4 requer o v2 ou v3.</string>\n    <string name=\"v4_scheme\">Esquema v4 (desde o Android 11)</string>\n    <string name=\"v3_scheme\">Esquema v3 (desde o Android 9)</string>\n    <string name=\"v1_scheme\">Esquema v1 (desde o Android 1.0)</string>\n    <string name=\"v2_scheme\">Esquema v2 (desde o Android 7.0)</string>\n    <string name=\"pref_apk_signing_msg\">Definir esquemas de assinatura, chave de assinatura personalizada, etc.</string>\n    <string name=\"apk_signing\">Assinatura do APK</string>\n    <string name=\"app_signing_signature_schemes\">Esquemas de assinatura</string>\n    <string name=\"source_stamp_verified\">SourceStamp verificado.</string>\n    <string name=\"splits\">Divisões</string>\n    <string name=\"not_verified\">Não verificado</string>\n    <string name=\"verified\">Verificado</string>\n    <plurals name=\"verified_with_warning\">\n        <item quantity=\"one\">Verificado com %d alerta</item>\n        <item quantity=\"many\">Verificado com %d alertas</item>\n        <item quantity=\"other\">Verificado com %d alertas</item>\n    </plurals>\n    <plurals name=\"app_signing_signature_schemes_pl\">\n        <item quantity=\"one\">Esquema de assinatura</item>\n        <item quantity=\"many\">Esquemas de assinatura</item>\n        <item quantity=\"other\">Esquemas de assinatura</item>\n    </plurals>\n    <string name=\"input_keystore_pass_description\">Insere a senha do KeyStore do App Manager. Se é tua primeira vez vendo isto, use um gerador de senha para gerar uma e salve-a num lugar seguro antes de inseri-la aqui.</string>\n    <string name=\"input_keystore_alias_pass_description\">Insirir senha para o alias <b>%1$s</b>. Você pode deixar isso vazio se a senha for a mesma da senha do KeyStore.</string>\n    <string name=\"input_keystore_alias_pass\">Senha para alias <b>%1$s</b></string>\n    <string name=\"input_keystore_pass_msg\">Toque aqui para digitar a senha do KeyStore</string>\n    <string name=\"input_keystore_pass\">Inserir senha do KeyStore</string>\n    <string name=\"no_app_ops_permission\">Sem permissão para mostrar as operações de aplicativo</string>\n    <string name=\"keep_data_and_app_signing_signatures\">Mantenha os dados e assinaturas</string>\n    <string name=\"pref_backup_android_keystore\">Backup de aplicativos com Android KeyStore</string>\n    <string name=\"pref_backup_android_keystore_msg\">Nem todos os aplicativos funcionarão após serem restaurados. Restaurar o KeyStore não funciona na maioria dos dispositivos.</string>\n    <string name=\"this_action_cannot_be_undone\">Esta ação não pode ser desfeita.</string>\n    <string name=\"set_app_op_mode\">Definir o modo da operação de aplicativo</string>\n    <string name=\"magisk_hide_enabled\">MagiskHide</string>\n    <string name=\"interceptor\">Interceptador</string>\n    <string name=\"resend_intent\">Reenviar Intenção</string>\n    <string name=\"share\">Compartilhar</string>\n    <string name=\"extras\">Extras</string>\n    <string name=\"category\">Categorias</string>\n    <string name=\"uri\">URI</string>\n    <string name=\"mime_type\">Tipo de MIME</string>\n    <string name=\"action\">Ação</string>\n    <string name=\"result_code\">Código resultante</string>\n    <string name=\"activity_result\">Resultado da atividade</string>\n    <string name=\"send_edited_intent\">Enviar intenção editada</string>\n    <string name=\"matching_activities\">Atividades correspondentes</string>\n    <string name=\"value\">Valor</string>\n    <string name=\"filter_apps_with_splits\">Com divisões</string>\n    <string name=\"set_custom_app_op\">Definir a operação de aplicativo personalizada</string>\n    <string name=\"battery\">Bateria</string>\n    <string name=\"graphics\">Gráficos</string>\n    <string name=\"cpu\">CPU</string>\n    <string name=\"users\">Usuários</string>\n    <string name=\"languages\">Idiomas</string>\n    <string name=\"battery_capacity\">Capacidade</string>\n    <string name=\"memory\">Memória RAM</string>\n    <string name=\"vendor\">Fornecedor</string>\n    <string name=\"gles_version\">Versão do OpenGL ES</string>\n    <string name=\"no_of_cores\">Núcleos</string>\n    <string name=\"support_architectures\">Arquiteturas suportadas</string>\n    <string name=\"security_providers\">Provedores de segurança</string>\n    <string name=\"kernel\">Kernel</string>\n    <string name=\"manufacturer\">Fabricante</string>\n    <string name=\"board_name\">Placa</string>\n    <string name=\"model\">Modelo</string>\n    <string name=\"brand_name\">Marca</string>\n    <string name=\"pref_about_device_msg\">Informações básicas do dispositivo, incluindo Sistema Android, CPU, GPU, RAM, bateria, etc.</string>\n    <string name=\"about_device\">Sobre o dispositivo</string>\n    <plurals name=\"alert_failed_to_set_app_ops\">\n        <item quantity=\"one\">%1$d aplicativo não pôde ter operações de aplicativo definidas</item>\n        <item quantity=\"many\">%1$d aplicativos não puderam ter operações de aplicativo definidas</item>\n        <item quantity=\"other\">%1$d aplicativos não puderam ter operações de aplicativo definidas</item>\n    </plurals>\n    <string name=\"set_mode_for_app_ops_dots\">Definir modo para operações de aplicativo…</string>\n    <string name=\"security\">Segurança</string>\n    <string name=\"backup_apk_files_description\">Faça o backup apenas dos arquivos APK do diretório de origem. <b>Origem</b> deve ser selecionado para que isso funcione.</string>\n    <string name=\"patch_level\">Nível do Patch</string>\n    <string name=\"backup_skip_signature_checks_description\">Restaure backups que falham na verificação do checksum ou têm assinaturas de APK diferentes de seus backups anteriores.</string>\n    <string name=\"backup_multiple_description\">Crie um backup <i>nomeado</i> ao invés do backup base.</string>\n    <string name=\"backup_rules_description\">Faça backup de regras configuradas dentro do App Manager. <font fgcolor=\"#ff0000\">Dependendo das permissões, nem todas as regras podem ser reaplicadas durante a restauração.</font></string>\n    <string name=\"backup_extras_description\">Faça backup das permissões do aplicativo, opções de economia de bateria e uso de dados, status do MagiskHide, SSAID, etc. <font fgcolor=\"#ff0000\">Dependendo das permissões, nem todos os extras podem ser restaurados.</font></string>\n    <string name=\"backup_extras\">Extras</string>\n    <string name=\"backup_cache_description\">Faz o backup das pastas <b>cache</b>, <b>no_cache</b> e <b>no_backup</b>.</string>\n    <string name=\"backup_obb_media_description\">Faça o backup das pastas OBB e de mídia.</string>\n    <string name=\"backup_external_data_description\">Faça o backup de pastas de dados externas.</string>\n    <string name=\"backup_internal_data_description\">Faça o backup de pastas de dados. Se selecionado, as pastas de dados internas serão copiadas por padrão.</string>\n    <string name=\"permissive\">Permissivo</string>\n    <string name=\"enforcing\">Enforcing</string>\n    <string name=\"window_size\">Tamanho da janela</string>\n    <string name=\"refresh_rate\">Taxa de atualização</string>\n    <string name=\"scaling_factor\">Fator de dimensionamento</string>\n    <string name=\"size\">Tamanho</string>\n    <string name=\"density\">Densidade</string>\n    <string name=\"screen\">Tela</string>\n    <string name=\"hardware\">Hardware</string>\n    <string name=\"selinux\">SELinux</string>\n    <string name=\"failed_to_enable_magisk_hide\">O MagiskHide não pôde ser ativado</string>\n    <string name=\"failed_to_disable_magisk_hide\">O MagiskHide não pôde ser desativado</string>\n    <string name=\"disable_background_run_description\">Define o modo <i>ignore</i> para as seguintes operações de aplicativo: <tt>RUN_IN_BACKGROUND</tt> (do Android 7.0) e <tt>RUN_ANY_IN_BACKGROUND</tt> (do Android 9).</string>\n    <plurals name=\"no_of_components\">\n        <item quantity=\"one\">%1$d componente</item>\n        <item quantity=\"many\">%1$d componentes</item>\n        <item quantity=\"other\">%1$d componentes</item>\n    </plurals>\n    <string name=\"backup_custom_users_description\">Realizar backups apenas para os usuários especificados</string>\n    <string name=\"backup_custom_users\">Usuários personalizados</string>\n    <string name=\"bootloader\">Bootloader</string>\n    <string name=\"unencrypted\">Não criptografado</string>\n    <string name=\"encrypted\">Criptografado</string>\n    <string name=\"no_volumes_found\">Não foi possível encontrar nenhum volume com permissão de gravação.</string>\n    <string name=\"pref_backup_volume_msg\">Selecione o volume ou o disco onde os backups serão armazenados.</string>\n    <string name=\"backup_volume\">Volume do Backup</string>\n    <string name=\"pref_backup_restore_msg\">Personalizar backup/restauração.</string>\n    <string name=\"drm_free_apkm_msg\">O arquivo APKM é DRM-free, não há necessidade de convertê-lo em APKS.</string>\n    <string name=\"restore_msg\">Restaurar aplicativos com dados</string>\n    <string name=\"backup_msg\">Fazer backup de aplicativos com dados</string>\n    <string name=\"restore_latest_msg\">Restaure aplicativos já instalados cujos códigos de versão são superiores ao código de versão instalado.</string>\n    <string name=\"restore_latest\">Restaurar backups mais recentes</string>\n    <string name=\"restore_not_installed_msg\">Restaure o backup base para aplicativos que não estão instalados no momento.</string>\n    <string name=\"restore_not_installed\">Restaurar aplicativos não instalados</string>\n    <string name=\"restore_all_msg\">Restaure o backup base de todos os aplicativos com backup.</string>\n    <string name=\"restore_all\">Restaurar todos os aplicativos</string>\n    <string name=\"backup_apps_with_changes_msg\">Refaça backups para aplicativos com mudanças desde o último backup. Elas incluem mudanças de tamanho, versão, última vez que foi iniciado.</string>\n    <string name=\"backup_apps_with_changes\">Fazer backup de aplicativos com mudanças</string>\n    <string name=\"backup_apps_without_backups\">Fazer backup de aplicativos sem backups</string>\n    <string name=\"redo_existing_backups_msg\">Refaça o backup para aplicativos instalados com backups anteriores.</string>\n    <string name=\"redo_existing_backups\">Refazer backups existentes</string>\n    <string name=\"verify_and_redo_backups_msg\">Verifique a integridade dos backups anteriores e refaça os backups para os quais o check-up de integridade falhou.</string>\n    <string name=\"verify_and_redo_backups\">Verificar e refazer backups</string>\n    <string name=\"backup_apps_without_backups_msg\">Fazer backup de aplicativos sem nenhum backup anterior.</string>\n    <string name=\"backup_all_apps\">Fazer backup de todos os aplicativos</string>\n    <string name=\"backup_all_apps_msg\">Fazer backup de todos os aplicativos instalados.</string>\n    <string name=\"back_up\">Fazer backup</string>\n    <string name=\"list_options\">Opções de lista</string>\n    <string name=\"reverse\">Inverter</string>\n    <string name=\"os_version\">Versão do SO</string>\n    <string name=\"add\">Adicionar</string>\n    <string name=\"add_to_profile\">Adicionar ao perfil</string>\n    <string name=\"initializing\">Iniciando…</string>\n    <string name=\"net_policy\">Política de rede</string>\n    <string name=\"has_net_policy\">Política de rede</string>\n    <string name=\"choose_what_to_do\">Escolha o que fazer.</string>\n    <string name=\"enable_battery_optimization\">Ativar otimização de bateria\\?</string>\n    <string name=\"no_battery_optimization\">Nenhuma otimização de bateria</string>\n    <string name=\"battery_optimization\">Otimização de bateria</string>\n    <string name=\"screen_lock_msg\">Bloqueie o App Manager usando o bloqueio de tela do Android</string>\n    <string name=\"screen_lock\">Bloqueio de Tela</string>\n    <string name=\"unlock_app_manager\">Desbloquear App Manager</string>\n    <string name=\"sd_card\">Cartão SD</string>\n    <string name=\"external_storage\">Armazenamento Externo</string>\n    <string name=\"internal_storage\">Armazenamento Interno</string>\n    <string name=\"restart_to_reflect_changes\">Você deve reiniciar o dispositivo imediatamente para usar as novas alterações.</string>\n    <string name=\"failed_to_change_ssaid\">Não foi possível mudar o SSAID</string>\n    <string name=\"copied_to_clipboard\">Copiado para a área de transferência.</string>\n    <string name=\"ssaid_info\">SSAID (<tt>Settings.Secure.ANDROID_ID</tt>) é um identificador de dispositivo atribuído a cada aplicativo (do Android 8 \\\"Oreo\\\" em diante). É amplamente utilizado por aplicativos para rastrear usuários.</string>\n    <string name=\"ssaid\">SSAID</string>\n    <string name=\"type_uri\">URI</string>\n    <string name=\"type_string_array_list\">Lista de strings</string>\n    <string name=\"type_string_array\">Matriz de strings</string>\n    <string name=\"type_float_array_list\">Lista de números decimais</string>\n    <string name=\"type_float_array\">Matriz de números decimais</string>\n    <string name=\"type_long_array_list\">Lista de números inteiros longos</string>\n    <string name=\"type_long_array\">Matriz de números inteiros longos</string>\n    <string name=\"type_int_array_list\">Lista de números inteiros</string>\n    <string name=\"type_int_array\">Matriz de números inteiros</string>\n    <string name=\"type_component_name\">Nome do Componente</string>\n    <string name=\"type_null\">Nenhum valor</string>\n    <string name=\"user_with_id\">Usuário: <xliff:g id=\"user_id\" example=\"0\">%1$d</xliff:g></string>\n    <string name=\"installed_apps\">Aplicativos instalados</string>\n    <string name=\"last_actions\">Últimas ações</string>\n    <string name=\"pref_enable_disable_features_msg\">Ativar ou desativar funções no App Manager.</string>\n    <string name=\"enable_disable_features\">Ativar/desativar funções</string>\n    <string name=\"isolated\">Isolado</string>\n    <string name=\"screen_lock_not_enabled\">Por favor, escolha um bloqueio de tela nas configurações do Android ou limpe os dados do aplicativo.</string>\n    <string name=\"input_app_ops_description_profile\">Insira nomes de operações de aplicativo e/ou constantes com espaços, p. ex. <tt>WAKE_LOCK 63 72 CAMERA</tt> etc. Use <tt>*</tt> para solicitar todas as operações de aplicativo configuradas.</string>\n    <string name=\"working_on_adb_mode\">Trabalhando no modo ADB</string>\n    <string name=\"verified_using_unreliable_hash\">Verificado usando hash não confiável</string>\n    <string name=\"installer_app_message\">Selecione <b>Escolher</b> para escolher entre os aplicativos instalados ou selecione <b>Personalizado</b> para especificar um nome de pacote personalizado.</string>\n    <string name=\"specify_custom_name\">Personalizado</string>\n    <string name=\"filter_apps_without_backups\">Sem backups</string>\n    <string name=\"uninstalled_apps\">Aplicativos desinstalados</string>\n    <string name=\"internal_data\">Dados internos</string>\n    <string name=\"pkcs12_keystore\">PKCS #12 KeyStore (P12)</string>\n    <string name=\"source_code_links\"><a href=\"https://github.com/MuntashirAkon/AppManager\">GitHub</a> • <a href=\"https://gitlab.com/muntashir/AppManager\">GitLab</a> • <a href=\"https://0xacab.org/muntashir/AppManager\">Riseup</a> • <a href=\"https://codeberg.org/muntashir/AppManager\">Codeberg</a></string>\n    <string name=\"bouncy_castle_keystore\">Bouncy Castle KeyStore (BKS)</string>\n    <string name=\"input_key\">Insira uma chave (em hexadecimal)</string>\n    <string name=\"expiry_date_cannot_be_empty\">A data de validade não pode estar vazia.</string>\n    <string name=\"signing_key\">Assinando chave</string>\n    <string name=\"failed_to_read_keystore\">Não foi possível ler a KeyStore.</string>\n    <string name=\"alias_pass\">Senha do alias</string>\n    <string name=\"choose_an_alias\">Escolha um alias</string>\n    <string name=\"found_no_alias_in_keystore\">Nenhum alias encontrado na KeyStore!</string>\n    <string name=\"new_alias_password\">Nova senha de alias</string>\n    <string name=\"import_key\">Importar chave</string>\n    <string name=\"pem_file\">Arquivo PEM</string>\n    <string name=\"pk8_file\">Arquivo PKCS #8 (PK8)</string>\n    <string name=\"pem_and_pk8\">PEM e PKCS #8 (PK8)</string>\n    <string name=\"java_keystore\">Java KeyStore (JKS)</string>\n    <string name=\"keystore_pass\">Senha da keyStore</string>\n    <string name=\"keystore_file\">Arquivo KeyStore</string>\n    <string name=\"country_name\" tools:ignore=\"TypographyOther\">Nome do país (C)</string>\n    <string name=\"locality_name\">Localidade (cidade (city)) nome (L)</string>\n    <string name=\"state_name\">Nome do Estado (ST)</string>\n    <string name=\"organization_name\">Nome da organização (O)</string>\n    <string name=\"organization_unit\">Unidade de organização (OU)</string>\n    <string name=\"common_name\">Nome comum (CN)</string>\n    <string name=\"input_key_password\">Senha da chave</string>\n    <string name=\"failed_to_load_key\">Não foi possível carregar a chave.</string>\n    <string name=\"key_not_set\">Não inserida.</string>\n    <string name=\"use_default\">Usar padrão</string>\n    <string name=\"invalid_rsa_key_size\">Tamanho da chave inválida para criptografia RSA. O tamanho da chave pode ser 1024, 2048 ou 4096 bits.</string>\n    <string name=\"crypto_key_size\">Tamanho da chave</string>\n    <string name=\"invalid_aes_key_size\">Tamanho da chave inválida para criptografia AES. O tamanho da chave pode ser de 128 ou 256 bits.</string>\n    <string name=\"failed_to_initialize_key_store\">Não foi possível inicializar a keystore do App Manager.</string>\n    <string name=\"failed_to_save_key\">Não foi possível salvar a chave.</string>\n    <string name=\"generate_key\">Gerar</string>\n    <string name=\"input_keystore_alias_pass_msg\">Toque aqui para fornecer uma senha para %1$s</string>\n    <string name=\"pref_installer_msg\">Configurar comportamentos do instalador de aplicativos.</string>\n    <string name=\"filter_choice_tag\">Tag</string>\n    <string name=\"filter_choice_pid\">PID</string>\n    <string name=\"add_filter_ellipsis\">Adicionar Filtro…</string>\n    <string name=\"log_viewer\">Visualizador de Registro</string>\n    <string name=\"trackers_unblocked_successfully\">Os rastreadores estão agora desbloqueados</string>\n    <string name=\"trackers_blocked_successfully\">Os rastreadores estão agora bloqueados</string>\n    <string name=\"failed_to_unblock_trackers\">Não foi possível desbloquear os rastreadores</string>\n    <string name=\"failed_to_block_trackers\">Não foi possível bloquear os rastreadores</string>\n    <string name=\"profile_save_apk_msg\">Salva arquivos APK em <tt>AppManager/apks</tt></string>\n    <string name=\"save_apk\">Salvar APK</string>\n    <string name=\"running_services\">Serviços em Execução</string>\n    <string name=\"view_logs\">Ver registros</string>\n    <string name=\"share_log\">Compartilhar</string>\n    <string name=\"text_include_dmesg\">Incluir o registro do kernel</string>\n    <string name=\"omit_sensitive_info_summary\">Omitir informações sensíveis como urls da Web, números de telefone ou e-mails.</string>\n    <string name=\"omit_sensitive_info\">Omitir informações sensíveis</string>\n    <string name=\"undo\">Desfazer</string>\n    <string name=\"pause_unpause\">Tocar/Pausar</string>\n    <string name=\"collapse_all\">Colapsar Tudo</string>\n    <string name=\"expand_all\">Expandir Tudo</string>\n    <string name=\"file\">Arquivo</string>\n    <string name=\"widget_start_recording\">Gravar\n\\nRegistro</string>\n    <string name=\"widget_recording_in_progress\">Gravando…</string>\n    <string name=\"unable_to_save_log\">Não é possível salvar o registro. Você inseriu um nome de arquivo válido\\?</string>\n    <plurals name=\"toast_log_truncated\">\n        <item quantity=\"one\">Registro muito grande, mostrando última %d linha.</item>\n        <item quantity=\"many\">Registro muito grande, mostrando últimas %d linhas.</item>\n        <item quantity=\"other\">Registro muito grande, mostrando últimas %d linhas.</item>\n    </plurals>\n    <string name=\"toast_invalid_selection\">Seleção inválida. Por favor, tente de novo.</string>\n    <string name=\"toast_invalid_level\">Nome de nível inválido: %s</string>\n    <string name=\"pref_display_limit_hint\">Digite um número válido entre %1$d e %2$d.</string>\n    <string name=\"text_include_device_info\">Incluir informações do dispositivo</string>\n    <string name=\"text_filter_text\">Texto do filtro</string>\n    <string name=\"text_filter_ellipsis\">Filtro…</string>\n    <string name=\"subject_log_report\">Relatório de registro</string>\n    <string name=\"start_recording_log\">Gravar</string>\n    <string name=\"settings\">Configurações</string>\n    <string name=\"send_log_title\">Enviar Registro</string>\n    <string name=\"record_log\">Gravar Registro</string>\n    <string name=\"save_log\">Salvar Registro</string>\n    <string name=\"save_as\">Salvar como…</string>\n    <string name=\"pref_show_timestamp_title\">Mostrar Pid e Timestamp</string>\n    <string name=\"pref_show_timestamp_summary\">Mostrar id de processo e horário quando expandido.</string>\n    <string name=\"pref_log_write_period_title\">Período de Gravação</string>\n    <string name=\"pref_log_write_period_summary\">Ao gravar, grave no cartão SD a cada %1$d linhas.</string>\n    <string name=\"pref_log_line_period_error\">Por favor, digite um número inteiro entre 1 e 1000.</string>\n    <string name=\"pref_expanded_by_default_title\">Expandir por Padrão</string>\n    <string name=\"pref_expanded_by_default_summary\">Mostrar texto de registro completo por padrão.</string>\n    <string name=\"pref_filter_pattern_title\">Filtrar Tags</string>\n    <string name=\"pref_filter_pattern_summary\">Filtrar as tags selecionadas a partir dos registros.</string>\n    <string name=\"pref_display_limit_title\">Limite de exibição de registro</string>\n    <string name=\"pref_display_limit_summary\">Mostrar apenas os últimos %1$d logs para evitar erros de memória.</string>\n    <string name=\"pref_default_log_level_title\">Nível de registro padrão</string>\n    <string name=\"pref_default_log_level_summary\">Nível de registro na inicialização, ao abrir arquivos e ao gravar.</string>\n    <string name=\"pref_cat_configuration\">Configuração</string>\n    <string name=\"pref_cat_appearance\">Aparência</string>\n    <string name=\"pref_cat_advanced\">Avançado</string>\n    <string name=\"pref_buffer_title\">Buffer de registro(s)</string>\n    <string name=\"open\">Abrir</string>\n    <string name=\"notification_title\">Gravação de registro em andamento</string>\n    <string name=\"notification_ticker\">Gravação de registro iniciada</string>\n    <string name=\"notification_subtext\">Toque para parar de gravar</string>\n    <string name=\"no_saved_logs\">Nenhum registro salvo.</string>\n    <string name=\"manage_saved_logs\">Gerenciar Registros Salvos</string>\n    <string name=\"log_saved\">Registro salvo.</string>\n    <string name=\"log_recording_started\">A gravação do registro começou.</string>\n    <string name=\"log_level\">Nível de registro</string>\n    <string name=\"log_cleared\">Registros limpos</string>\n    <string name=\"filter_choice\">Pesquisar por</string>\n    <string name=\"enter_filename\">Digite nome de arquivo</string>\n    <string name=\"enter_good_filename\">Por favor, digite um nome de arquivo válido.</string>\n    <string name=\"dialog_compiling_log\">Compilando registro…</string>\n    <string name=\"delete_saved_log\">Excluir Registros Salvos</string>\n    <string name=\"copy_to_clipboard\">Copiar para área de transferência</string>\n    <string name=\"add_filter\">Adicionar filtro</string>\n    <string name=\"log_level_fatal\">Fatal</string>\n    <string name=\"log_level_warn\">Aviso</string>\n    <string name=\"log_level_verbose\">Prolixo</string>\n    <string name=\"log_level_info\">Informação</string>\n    <string name=\"log_level_error\">Erro</string>\n    <string name=\"log_level_debug\">Depurar</string>\n    <string name=\"filename\">Nome do arquivo</string>\n    <string name=\"restart_log_viewer_to_see_changes\">Reinicie a janela do visualizador de registro para ver as alterações.</string>\n    <string name=\"pref_log_viewer_msg\">Configurar como os registros são exibidos.</string>\n    <string name=\"failed\">Falhou</string>\n    <string name=\"confirm_import_keystore\">Você tem certeza de que deseja substituir o KeyStore existente\\? Esta ação não pode ser desfeita.</string>\n    <string name=\"import_keystore\">Importar KeyStore</string>\n    <string name=\"pref_import_export_keystore_msg\">Importar/exportar Bouncy Castle KeyStore (BKS) usado internamente pelo App Manager.</string>\n    <string name=\"pref_import_export_keystore\">Importar/exportar KeyStore</string>\n    <string name=\"latest_backup\">Backup mais recente</string>\n    <string name=\"gz_bz2_compressed\">%1$s comprimido</string>\n    <string name=\"pgp_aes_rsa_encrypted\">%1$s criptografado</string>\n    <string name=\"no_encryption\">Sem criptografia</string>\n    <string name=\"base_backup\">Backup base</string>\n    <string name=\"app_signing_signatures\">Assinaturas</string>\n    <string name=\"pref_rules_msg\">Bloqueio imediato, importação/exportação/remoção de regras, etc.</string>\n    <string name=\"saf\">SAF</string>\n    <string name=\"orientation_right_to_left\">Da direita para a esquerda</string>\n    <string name=\"orientation_left_to_right\">Da esquerda para a direita</string>\n    <string name=\"orientation_follow_locale\">Seguir o local</string>\n    <plurals name=\"file_deletion_confirmation\">\n        <item quantity=\"one\">%d arquivo será excluído</item>\n        <item quantity=\"many\">%d arquivos serão excluídos</item>\n        <item quantity=\"other\">%d arquivos serão excluídos</item>\n    </plurals>\n    <string name=\"hidden\">Oculto</string>\n    <string name=\"suspended\">Suspenso</string>\n    <string name=\"no_changes\">Nenhuma mudança</string>\n    <string name=\"pref_display_changes_msg\">Mostrar mudanças na versão, rastreadores, componentes, permissões, assinaturas, SDK, etc. de forma controlada por versão.</string>\n    <string name=\"pref_display_changes\">Mostrar mudanças</string>\n    <string name=\"netpolicy_reject_cellular_data\">Rejeitar dados móveis</string>\n    <string name=\"netpolicy_disable_network_access\">Desativar o acesso à rede</string>\n    <string name=\"netpolicy_reject_wifi_data\">Rejeitar dados Wi-Fi</string>\n    <string name=\"netpolicy_reject_vpn_data\">Rejeitar dados VPN</string>\n    <string name=\"netpolicy_allow_background_data\">Permitir dados em segundo plano quando o Salvar Dados estiver ligado</string>\n    <string name=\"netpolicy_reject_background_data\">Rejeitar dados em segundo plano</string>\n    <string name=\"adb_connect_port_number_description\">O número de porta está localizado abaixo da seção <b>endereço IP &amp; porta</b> logo abaixo da seção <b>Nome do dispositivo</b>.</string>\n    <string name=\"port_number_invalid\">Número de porta inválido.</string>\n    <string name=\"port_number_empty\">O número de porta está vazio.</string>\n    <string name=\"port_number\">Porta</string>\n    <string name=\"adb_connect\">Conectar</string>\n    <string name=\"wireless_debugging\">Depuração sem fio</string>\n    <string name=\"unknown_net_policy\">Política de rede desconhecida (%1$s - %2$X)</string>\n    <string name=\"failed_to_prevent_background_run\">Inapto de deter %1$s de executar em segundo plano</string>\n    <string name=\"community_links\"><a href=\"https://matrix.to/#/#appmanager:matrix.org\">Matrix</a> • <a href=\"https://t.me/AppManagerChannel\">Telegram</a> • <a href=\"https://twitter.com/AppManagerNews\">Twitter</a></string>\n    <string name=\"community\">Comunidade</string>\n    <plurals name=\"alert_failed_to_import_backups\">\n        <item quantity=\"one\">%1$d backup não pôde ser importado</item>\n        <item quantity=\"many\">%1$d backups não puderam ser importados</item>\n        <item quantity=\"other\">%1$d backups não puderam ser importados</item>\n    </plurals>\n    <string name=\"import_from_tb\">Importar do Titanium Backup</string>\n    <string name=\"import_from_oab\">Importar do OAndBackup</string>\n    <string name=\"pref_import_backups_msg\">Importar backups do OAndBackup, Swift Backup (3.0–3.2) ou Titanium Backup.</string>\n    <string name=\"pref_import_backups\">Importar backups</string>\n    <string name=\"help_app_ops_tab\">Clique num item para o <b>permitir</b> ou <b>ignorar</b>. Aperte e segure num item para ver outros modos oferecidos.</string>\n    <string name=\"help_permissions_tab\">Essas permissões são definidas por este aplicativo e não podem ser revogadas.</string>\n    <string name=\"help_uses_permissions_tab\">Clique num item para o <b>conceder</b> ou <b>revogar</b> . Apenas permissões <b>perigosas</b> e de <b>desenvolvimento</b> podem ser concedidas ou revogadas.</string>\n    <string name=\"minimum_version\">Versão min: %d</string>\n    <string name=\"added_to_queue\">Adicionado à fila</string>\n    <string name=\"saved_filters\">Filtros salvos</string>\n    <string name=\"permission_flags\">Bandeiras de permissão</string>\n    <string name=\"pref_selected_users_msg\">Restringir o App Manager a trabalhar apenas com os usuários selecionados.</string>\n    <string name=\"pref_selected_users\">Usuários selecionados</string>\n    <string name=\"error_with_details\">Erro: %s</string>\n    <string name=\"files\">Arquivos</string>\n    <string name=\"storage\">Armazenamento</string>\n    <string name=\"notice_saf\">Ao contrário dos volumes, o diretório selecionado será usado para armazenar todos os arquivos relacionados ao App Manager, incluindo APKs salvos e backups. O SAF (Storage Access Framework) é muito lento, portanto, você só deve usar essa opção quando outras não puderem ser usadas.</string>\n    <string name=\"notice\">Perceba</string>\n    <string name=\"paired_successfully\">Pareado.</string>\n    <string name=\"adb_pair\">Parear</string>\n    <string name=\"invalid_password\">Senha inválida, tente novamente.</string>\n    <string name=\"keystore_pass_cannot_be_empty\">A senha do KeyStore não pode estar vazia.</string>\n    <string name=\"keystore_password_info\">Esta é a senha do KeyStore do App Manager. Guarde-a num local seguro se fizer backup/restaurar a KeyStore do App Manager. <b>Esta mensagem não voltará a exibir-se.</b></string>\n    <string name=\"running_services_logcat_hint\">Clique em um item para abrir o visualizador de log com o ID do processo correspondente como o filtro padrão.</string>\n    <string name=\"pid\">ID do processo</string>\n    <plurals name=\"pref_thread_count_msg\">\n        <item quantity=\"one\">Execute no máximo %1$d operação em paralelo</item>\n        <item quantity=\"many\">Execute no máximo %1$d operações em paralelo</item>\n        <item quantity=\"other\">Execute no máximo %1$d operações em paralelo</item>\n    </plurals>\n    <string name=\"pref_thread_count_hint\">O valor deve estar entre 0 e %1$d onde 0 significa <i>número máximo de operações em determinado momento</i>.</string>\n    <string name=\"backup_volume_dialog_description\">Volumes com o prefixo <tt>/tree</tt> são pastas selecionadas usando o Storage Access Framework (SAF). Exceto essas pastas, o diretório padrão do App Manager é uma subpasta chamada <tt>AppManager</tt>.</string>\n    <string name=\"second_degree_tracker_note\">O prefixo ² indica que os rastreadores estão na <a href=\"https://etip.exodus-privacy.eu.org/\">Lista de espera ETIP</a>, ou seja, se eles são rastreadores reais ainda estão sendo investigados.</string>\n    <string name=\"pref_thread_count\">Execução paralela</string>\n    <string name=\"type_uri_array_list\">Lista de URIs</string>\n    <string name=\"type_uri_array\">Matriz de URIs</string>\n    <string name=\"pref_always_on_background_msg\">Sempre instalar aplicativos em segundo plano e exibir uma notificação quando terminar.</string>\n    <string name=\"pref_block_trackers_msg\">Bloquear os componentes de rastreamento após instalar um aplicativo usando o App Manager.</string>\n    <string name=\"pref_always_on_background\">Instalar em segundo plano</string>\n    <string name=\"next\">Próximo</string>\n    <string name=\"installer_app_installed\">Aplicativo instalado</string>\n    <string name=\"staging_apk_files\">Preparando…</string>\n    <string name=\"background\">Segundo plano</string>\n    <string name=\"trim_caches_in_all_apps_description\">Exclui arquivos de cache de todos os aplicativos, incluindo o sistema Android</string>\n    <string name=\"trim_caches_in_all_apps\">Cortar caches em todos os aplicativos</string>\n    <string name=\"user_root\">Usar root</string>\n    <string name=\"paste\">Colar</string>\n    <string name=\"set_package_name_first\">Defina o nome do pacote primeiro!</string>\n    <string name=\"identifier\">Identificador</string>\n    <string name=\"failed_to_uninstall_app\">A desinstalação falhou</string>\n    <string name=\"java\">Java</string>\n    <string name=\"explore\">Explorar</string>\n    <string name=\"exit_confirmation\">Confirmação de saída</string>\n    <string name=\"extract\">Extrair</string>\n    <string name=\"replace\">Substituir</string>\n    <string name=\"rename\">Renomear</string>\n    <string name=\"import_from_sb\">Importar de Swift Backup 3.0 – 3.2</string>\n    <string name=\"pref_import_backups_hint\">Selecione um diretório contendo os arquivos de backup (Swift Backup / Titanium Backup) ou diretórios (OAndBackup)</string>\n    <string name=\"smali\">Smali</string>\n    <string name=\"system_partition\">Root Android</string>\n    <string name=\"accessibility_service_description\">Serviço de acessibilidade genérico para realizar certas operações, como limpar o cache no modo.</string>\n    <string name=\"authenticating\">Autenticando …</string>\n    <string name=\"pref_intent_firewall_and_disable_description\">Bloqueie componentes usando o Intent Firewall e também desative-os. Método recomendado para usuários root.</string>\n    <string name=\"pref_intent_firewall_description\">Bloqueie componentes usando apenas o Intent Firewall. Não recomendado, pois alguns aplicativos do sistema podem contornar firewalls.</string>\n    <string name=\"search_type_regular_expressions\">Expressões regulares</string>\n    <string name=\"pref_default_blocking_method\">Método de bloqueio padrão</string>\n    <string name=\"search_type_contains\">Contém</string>\n    <string name=\"search_type_suffix\">Sufixo</string>\n    <string name=\"search_type_prefix\">Prefixo</string>\n    <string name=\"pref_default_blocking_method_description\">Método a ser usado por padrão em locais onde não há opção de selecionar um método de bloqueio.\\n<b>Nota:</b> \\\"IFW\\\" não funciona com provedores, \\\"desabilitar\\\" é usado no lugar.</string>\n    <string name=\"intent_firewall_and_disable\">IFW + desativar</string>\n    <string name=\"intent_firewall\">IFW</string>\n    <string name=\"pref_disable_description\">Desative apenas componentes. Não recomendado para usuários root, pois os aplicativos podem contornar isso. Nos modos ADB, os aplicativos somente de teste podem ser desabilitados com este método.</string>\n    <plurals name=\"usage_minutes\">\n        <item quantity=\"one\">%1$d min</item>\n        <item quantity=\"many\">%1$d mins</item>\n        <item quantity=\"other\">%1$d mins</item>\n    </plurals>\n    <string name=\"vt_checking\">VirusTotal: Verificando…</string>\n    <string name=\"vt_queued\">VirusTotal: Enfileirado</string>\n    <string name=\"vt_success\">VirusTotal: %1$d/%2$d</string>\n    <string name=\"vt_permalink\">Link permanente para VirusTotal</string>\n    <string name=\"pref_vt_apikey_summary\">Ative a verificação de arquivos APK via VirusTotal.</string>\n    <string name=\"uses_play_app_signing\">Assinatura de Aplicativos do Google Play</string>\n    <string name=\"scan_in_vt\">Verificar no VirusTotal</string>\n    <string name=\"cpu_percent\">%% CPU</string>\n    <string name=\"state\">Estado do Processo</string>\n    <string name=\"swap\">Swap</string>\n    <string name=\"swap_chart_info\">● %1$s Usado ● %2$s Livre</string>\n    <string name=\"warning_working_on_root_mode\">Aviso: Trabalhando com root em vez do modo ADB.</string>\n    <string name=\"magisk_denylist\">Lista de Negações do Magisk</string>\n    <string name=\"mode_of_op_with_inferred_mode_of_op\">%1$s (Modo inferido: %2$s)</string>\n    <string name=\"vt_slowness_warning\">Dependendo da velocidade da Internet e da carga no servidor, isso pode demorar um pouco.</string>\n    <string name=\"process_id\">ID do Processo</string>\n    <plurals name=\"usage_seconds\">\n        <item quantity=\"one\">%1$d seg</item>\n        <item quantity=\"many\">%1$d segs</item>\n        <item quantity=\"other\">%1$d segs</item>\n    </plurals>\n    <string name=\"toggle_internet\">Usar a internet</string>\n    <string name=\"vt_uploading\">VirusTotal: Enviando…</string>\n    <string name=\"vt_failed\">VirusTotal: Falhou</string>\n    <string name=\"vt_scan_date\">Data da verificação: %1$s</string>\n    <string name=\"pref_vt_apikey\">Chave de API do VirusTotal</string>\n    <string name=\"parent_process_id\">ID do Processo Pai</string>\n    <string name=\"virtual_memory\">Memória Virtual</string>\n    <string name=\"cpu_time\">Tempo de CPU</string>\n    <string name=\"vt_disclaimer\">VirusTotal e seus logotipos são uma marca registrada da Chronicle LLC. Nem o App Manager—o cliente da API—nem seus autores são responsáveis por quaisquer dados que você possa enviar ao VirusTotal.</string>\n    <string name=\"priority\">Prioridade</string>\n    <string name=\"pref_vt_apikey_description\">Uma chave de API permite que o App Manager carregue arquivos APK para o VirusTotal, além de buscar relatórios. Inscreva-se em https://virustotal.com para obter uma chave de API gratuitamente.</string>\n    <string name=\"commandline_args\">Argumentos da linha de comando</string>\n    <string name=\"failed_to_change_app_op_mode\">Não foi possível alterar o modo operacional do aplicativo.</string>\n    <string name=\"uses_play_app_signing_description\">Este aplicativo contém certos marcadores que indicam que ele <i>poderia</i> estar usando a <a href=\"https://support.google.com/googleplay/android-developer/answer/9842756\">Assinatura de Aplicativos do Google Play</a>. Com esse esquema, as chaves de assinatura são armazenadas nos servidores do Google, e o Google é responsável por assinar o aplicativo. Observe que as informações de assinatura correspondentes são a única maneira de verificar se o aplicativo não foi modificado por outra pessoa que não seja o desenvolvedor (e, neste caso, o Google também).</string>\n    <string name=\"threads\">Contagem de Threads</string>\n    <string name=\"memory_chart_info\">● %1$s Aplicativos ● %2$s Em Cache ● %3$s Buffers ● %4$s Livre</string>\n    <string name=\"failed_to_use_the_current_mode_of_operation\">Não é possível usar o modo de operação atual. Voltando ao modo sem root para esta sessão.</string>\n    <string name=\"failed_to_enable_magisk_deny_list\">Não foi possível ativar a Lista de Negações do Magisk</string>\n    <string name=\"failed_to_disable_magisk_deny_list\">Não foi possível desativar a Lista de Negações do Magisk</string>\n    <string name=\"hidden_api_enforcement_policy\">Política de aplicação de API oculta</string>\n    <string name=\"binary_64_bit\">64 Bit</string>\n    <string name=\"endianness_big_endian\">Big endian</string>\n    <string name=\"so_type_shared_library\">Biblioteca compartilhada</string>\n    <string name=\"so_type_executable\">Executável</string>\n    <string name=\"file_modified_are_you_sure\">O arquivo foi modificado. Descartar todas as suas alterações e sair\\?</string>\n    <string name=\"save_and_exit\">Salvar e sair</string>\n    <string name=\"hidden_api_enf_policy_black\">Enforce (somente listas negras)</string>\n    <string name=\"hidden_api_enf_policy_dark_grey_and_black\">Enforce (listas cinza-escuro e negras)</string>\n    <string name=\"hidden_api_enf_default_policy\">Padrão (com base no tipo de aplicativo)</string>\n    <string name=\"hidden_api_enf_policy_none\">None (acesso total à API oculta)</string>\n    <string name=\"binary_32_bit\">32 Bit</string>\n    <string name=\"primary_abi\">ABI primária</string>\n    <string name=\"zygote_preload_name\">Nome de pré-carregamento do Zygote</string>\n    <string name=\"endianness_little_endian\">Little endian</string>\n    <string name=\"hidden_api_enf_policy_warn\">Warn (acesso total à API oculta, mas emite alertas)</string>\n    <string name=\"pref_saved_apk_name_format\">Formato de Nome de APK Salvo</string>\n    <string name=\"pref_saved_apk_name_format_msg\">O formato a ser usado para nomear os arquivos APK ao salvá-los.</string>\n    <string name=\"auth_manager_description\">Para iniciar um Intent a partir de um aplicativo externo, é necessário fornecer um campo extra chamado <tt>auth</tt>, e deve conter a seguinte chave:</string>\n    <string name=\"auth_manager_title\">Gerenciador de Autorização</string>\n    <string name=\"regenerate_auth_key\">Regenerar chave de autorização</string>\n    <string name=\"regenerate_auth_key_warning\">Tem certeza\\? Todos os aplicativos de terceiros precisam ser reconfigurados com a nova chave de autorização.</string>\n    <string name=\"shortcut_icon\">Ícone de Atalho</string>\n    <string name=\"external\">Externo</string>\n    <string name=\"backup_volume_unavailable_warning\">O volume de backup selecionado não está disponível no momento. Se estiver localizado em um armazenamento externo, insira-o ou altere o volume de backup.</string>\n    <string name=\"sort_by_installation_date\">Data de instalação</string>\n    <string name=\"change_backup_volume\">Alterar volume</string>\n    <string name=\"internal\">Interno</string>\n    <string name=\"tracker\">Rastreador</string>\n    <string name=\"input_ssaid_instruction\">SSAID é um número hexadecimal de byte %1$d, ou seja, uma string de comprimento %2$d contendo 0 a 9 e a a f.</string>\n    <string name=\"screen_time\">Tempo de Tela</string>\n    <string name=\"open_in_new_window\">Nova janela</string>\n    <string name=\"type_string_set\">Conjunto de strings</string>\n    <string name=\"pref_vt_prompt_before_uploading\">Exibe o prompt antes de carregar um arquivo.</string>\n    <string name=\"vt_confirm_uploading_file\">O arquivo não foi encontrado no banco de dados do VirusTotal. Deseja carregá-lo\\?</string>\n    <string name=\"vt_confirm_upload_and_scan\">Sim, faça upload e escaneie</string>\n    <string name=\"apk_checksums\">Somas de verificação de APK</string>\n    <string name=\"item_select\">Selecionar</string>\n    <string name=\"log_stop_recording\">Parar gravação</string>\n    <string name=\"app_explorer\">Explorador de Aplicativos</string>\n    <string name=\"netpolicy_cannot_be_modified_for_core_apps\">A política de rede não pode ser modificada para aplicativos principais do Android.</string>\n    <string name=\"freeze\">Congelar</string>\n    <string name=\"frozen\">Congelado</string>\n    <string name=\"unfreeze\">Descongelar</string>\n    <string name=\"backup_no_backups_present\">Sem backups.</string>\n    <string name=\"restore_dots\">Restaurar…</string>\n    <string name=\"backup_apps_cannot_be_restored\">Os seguintes aplicativos não podem ser restaurados porque não possuem um backup básico:</string>\n    <string name=\"backup_apps_cannot_be_backed_up\">Os seguintes aplicativos não estão instalados e não podem ser armazenados em backup:</string>\n    <string name=\"restart_device\">Reiniciar dispositivo</string>\n    <string name=\"import_backups_warning_delete_backups_after_import\">Excluir os backups depois de importá-los para o App Manager\\? Cada backup é excluído individualmente após ser importado com sucesso. Selecione <b>Não</b> se não tiver certeza.</string>\n    <string name=\"open_developer_options_page\">Abrir a página de opções do desenvolvedor nas configurações do Android</string>\n    <string name=\"pref_pure_black_theme\">tema preto puro</string>\n    <string name=\"pref_pure_black_theme_msg\">Use um fundo completamente preto quando o modo noturno estiver ativado.</string>\n    <string name=\"usage_times_opened\">Vezes aberto</string>\n    <string name=\"usage_last_used\">Usado por último</string>\n    <string name=\"usage_mobile_data\">Dados móveis</string>\n    <string name=\"usage_wifi_data\">Dados Wi-Fi</string>\n    <string name=\"unsupported_split_apk\">Não suportado</string>\n    <string name=\"view_changelog\">Descubra o que há de novo nesta versão</string>\n    <string name=\"pref_reload_apps_msg\">Recarregue a lista de apps armazenados na base de dados do App Manager caso ocorra algo inesperado.</string>\n    <string name=\"changelog_type_fix\">Corrigir</string>\n    <string name=\"changelog_type_improve\">Melhorar</string>\n    <string name=\"sort_by_total_size\">Tamanho total</string>\n    <string name=\"am_command\">comando <tt>am</tt></string>\n    <string name=\"pref_sign_apk_error_signing_key_not_added\">É necessário uma chave válida para assinar um ficheiro APK.</string>\n    <string name=\"pref_sign_apk_no_signing_key\">Sem chave de assinatura</string>\n    <string name=\"troubleshooting\">Solução de problemas</string>\n    <string name=\"pref_reload_apps\">Recarregar apps</string>\n    <string name=\"changelog_type_new\">Novo</string>\n    <string name=\"suspend_app_description\">Este é o método de congelamento mais fraco. Um aplicativo suspenso ainda pode aparecer no iniciador, mas ficará esmaecido e não poderá ser iniciado.</string>\n    <string name=\"hide_app_description\">Este método é recomendado apenas para uso diário. Um aplicativo oculto aparece como se estivesse desinstalado. Mas o aplicativo pode reaparecer se for reinstalado ou atualizado.</string>\n    <string name=\"pref_appearance_description\">Tema, orientação, recursos, etc.</string>\n    <string name=\"failed_to_freeze\">Não foi possível congelar <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g>.</string>\n    <string name=\"failed_to_unfreeze\">Não foi possível descongelar <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g>.</string>\n    <string name=\"freeze_unfreeze\">Congelar/descongelar</string>\n    <string name=\"profile_freeze_msg\">Congela ou descongela aplicativos com base no estado</string>\n    <string name=\"pref_default_freezing_method\">Método de congelamento padrão</string>\n    <string name=\"pref_default_freezing_method_description\">Método a ser usado por padrão em locais onde não há opção de selecionar um método de congelamento.</string>\n    <string name=\"suspend_app\">Suspender</string>\n    <string name=\"hide_app\">Esconder</string>\n    <plurals name=\"alert_failed_to_freeze\">\n        <item quantity=\"one\">Não foi possível congelar %1$d aplicativo</item>\n        <item quantity=\"many\">Não foi possível congelar %1$d aplicativos</item>\n        <item quantity=\"other\">Não foi possível congelar %1$d aplicativos</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_unfreeze\">\n        <item quantity=\"one\">Não foi possível descongelar %1$d aplicativo</item>\n        <item quantity=\"many\">Não foi possível descongelar %1$d aplicativos</item>\n        <item quantity=\"other\">Não foi possível descongelar %1$d aplicativos</item>\n    </plurals>\n    <string name=\"disable_app_description\">Método de congelamento recomendado. Ele desativa o aplicativo e todos os seus componentes, mas todos os atalhos serão perdidos.</string>\n    <string name=\"sort_by_frozen_app\">Congelado primeiro</string>\n    <string name=\"filter_frozen_apps\">Aplicativos congelados</string>\n    <string name=\"pref_privacy\">Privacidade</string>\n    <string name=\"pref_privacy_description\">Bloqueio de tela, autorização, etc.</string>\n    <string name=\"user_manual\">Manual do usuário</string>\n    <string name=\"get_help\">Obter ajuda</string>\n    <string name=\"pref_advanced_pref\">Usuários, formato de nome do APK, execução paralela, etc.</string>\n    <string name=\"pref_version_changelog\">Versão/Registro de alterações</string>\n    <string name=\"fm_open_with_for_this_file_only\">Apenas para este arquivo</string>\n    <string name=\"file_modification_date\">Modificado</string>\n    <string name=\"file_accessed_date\">Acessado</string>\n    <string name=\"file_creation_date\">Criado</string>\n    <string name=\"file_open_as\">Abrir como…</string>\n    <string name=\"file_open_with_custom_activity\">Personalizado</string>\n    <string name=\"open_as_video\">Vídeo</string>\n    <string name=\"open_as_archive\">Arquivo</string>\n    <string name=\"open_as_folder\">Pasta</string>\n    <string name=\"open_as_other\">Outro</string>\n    <string name=\"delete_filename\">Apagar %s</string>\n    <string name=\"confirm_file_deletion\">Sim, apagar</string>\n    <string name=\"on_unfreeze_open_application\">Abrir app após o descongelamento</string>\n    <string name=\"file_open_with\">Abrir com</string>\n    <string name=\"file_shortcut_target_file\">Arquivo de destino</string>\n    <string name=\"file_properties\">Propriedades</string>\n    <string name=\"file_cut\">Cortar</string>\n    <string name=\"fm_always_open_with\">Sempre abrir</string>\n    <string name=\"open_as_text\">Texto</string>\n    <string name=\"open_as_image\">Imagem</string>\n    <string name=\"renamed_successfully\">Renomeado</string>\n    <string name=\"sort_by_data_usage\">Uso de dados</string>\n    <string name=\"confirm_uninstallation\">Confirmar desinstalação</string>\n    <string name=\"action_optimize_app\">Otimizar</string>\n    <string name=\"app_manager_build_expired\">Atualização necessária</string>\n    <string name=\"action_stop_service\">Parar</string>\n    <string name=\"tap_to_freeze_app\">Toque para congelar</string>\n    <string name=\"unix_file_permissions\">Modo</string>\n    <string name=\"file_owner_id\">Proprietário (UID)</string>\n    <string name=\"calculating_file_size\">Calculando…</string>\n    <string name=\"sort_by_filename\">Nome</string>\n    <string name=\"sort_by_last_modified\">Última alteração</string>\n    <string name=\"sort_by_file_size\">Tamanho do arquivo</string>\n    <string name=\"sort_by_file_type\">Tipo de arquivo</string>\n    <string name=\"file_open_with_os_default_dialog\">Abrir com a caixa de diálogo padrão do SO</string>\n    <string name=\"freeze_on_phone_locked\">Congelar o app automaticamente quando o telefone estiver bloqueado</string>\n    <string name=\"on_open_application_no_recents\">Não mostrar o app iniciado nos Recentes</string>\n    <string name=\"file_change_open_with\">Alterar abrir com</string>\n    <string name=\"waiting_for_the_phone_to_be_locked\">Esperando que o telefone seja bloqueado…</string>\n    <string name=\"option_display_folders_on_top\">Pastas no topo</string>\n    <string name=\"export_app_list\">Exportar lista de aplicações</string>\n    <string name=\"action_continue\">Continuar</string>\n    <string name=\"title_terminal_emulator\">Terminal</string>\n    <string name=\"grant_required_permission\">Conceder permissão necessária</string>\n    <string name=\"filter_apps_with_ssaid\">Com SSAID</string>\n    <string name=\"filter_apps_with_saf\">Com SAF</string>\n    <string name=\"filter_apps_with_keystore\">Com KeyStore</string>\n    <string name=\"install_for_another_user\">Instalar para…</string>\n    <string name=\"title_labs_activity\">Labs</string>\n    <string name=\"action_run\">Iniciar</string>\n    <string name=\"optimize_option_clear_profile_data\">Limpar dados de perfil anteriores</string>\n    <string name=\"optimize_option_force_compilation\">Forçar compilação mesmo quando não for necessário</string>\n    <string name=\"selinux_context\">Contexto SELinux</string>\n    <string name=\"file_group_id\">Grupo (GID)</string>\n    <string name=\"app_manager_build_expiring_soon_warning\">Esta versão do App Manager expirará muito em breve. Atualize-o para a versão mais recente.</string>\n    <string name=\"adb_incomplete_usb_debugging_title\">Depuração USB incompleta</string>\n    <string name=\"class_hierarchy\">Hierarquia</string>\n    <string name=\"title_perform_runtime_optimization_to_apps\">Executar a otimização de tempo de execução</string>\n    <string name=\"app_manager_build_expired_message\">Para garantir a segurança do seu dispositivo e dos seus dados, a versão do App Manager em uso foi desativada. Você tem de atualizá-lo para a versão mais recente para continuar a usá-lo ou desinstalá-lo se não estiver disponível nenhuma atualização.</string>\n    <string name=\"batch_ops_runtime_optimization\">Otimização do tempo de execução</string>\n    <string name=\"export_option_markdown\">Markdown</string>\n    <string name=\"export_app_list_select_format\">Selecione o formato para exportar a lista de aplicativos</string>\n    <string name=\"title_domains_supported_by_the_app\">Domínios suportados</string>\n    <string name=\"app_info_tag_open_links\">Abrir links</string>\n    <string name=\"source_stamp_verified_and_identified_to_be_from_source\">SourceStamp verificado e identificado como sendo de <xliff:g id=\"source\" example=\"Google Play\">%1$s</xliff:g>.</string>\n    <string name=\"netpolicy_reject_metered_background_data\">Rejeitar dados de segundo plano em redes mensuradas</string>\n    <string name=\"netpolicy_reject_metered_data\">Rejeitar dados em redes mensuradas</string>\n    <string name=\"netpolicy_allow_metered_background_data\">Permitir dados de segundo plano em redes mensuradas mesmo quando a Economia de Dados estiver ligada</string>\n    <string name=\"unblock_components_dots\">Desbloquear componentes…</string>\n    <string name=\"block_unblock_components_dots\">Bloquear/Desbloquear componentes…</string>\n    <string name=\"warning_working_on_system_mode\">Aviso: Trabalhando no modo sistema em vez do modo ADB.</string>\n    <plurals name=\"alert_failed_to_unblock_components\">\n        <item quantity=\"one\">Não foi possível desbloquear componentes para %1$d app</item>\n        <item quantity=\"many\">Não foi possível desbloquear componentes para %1$d apps</item>\n        <item quantity=\"other\">Não foi possível desbloquear componentes para %1$d apps</item>\n    </plurals>\n    <string name=\"block_unblock_components_description\">Bloquear ou desbloquear todos os componentes identificados pelas assinaturas fornecidas</string>\n    <string name=\"pref_layout_direction\">Direção do layout</string>\n    <string name=\"pref_toggle_internet_msg\">Ativar os recursos de Internet no App Manager</string>\n</resources>"
  },
  {
    "path": "app/src/main/res/values-ro/disclaimer.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"disclaimer_footer\">© 2020–2024 Muntashir Al-Islam</string>\n    <string name=\"disclaimer_agree_forever\">Nu mai arăta asta niciodată</string>\n    <string name=\"disclaimer_agree\">Sunt de acord</string>\n    <string name=\"disclaimer_exit\">Ieșire</string>\n    <string name=\"disclaimer_header\">Declinare a răspunderii</string>\n    <string name=\"disclaimer_body\">Managerul de aplicații oferă funcții de acces root care ar putea dăuna dispozitivului dacă sunt utilizate incorect. Managerul de aplicații nu este responsabil pentru nicio daună produsă prin utilizarea acestei aplicații. Dacă nu știi pe deplin cum funcționează accesul root, atunci ar trebui să eviți să utilizezi opțiunile root până când ești pe deplin conștient de riscuri.\n\\n\n\\nOrice link pe care îl ofer către alte aplicații și site-uri web este în beneficiul utilizatorilor. Nu sunt responsabil pentru niciun conținut pe care îl poți găsi accesând link-uri externe.\n\\n\n\\nFolosind App Manager, accepți întreaga responsabilitate pentru propria utilizare și nu soliciți daune sau valoare monetară, nu ai pretenții din cauza utilizării.</string>\n</resources>"
  },
  {
    "path": "app/src/main/res/values-ro/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\">\n    <string name=\"_lang_tag\" translatable=\"false\">ro</string>\n    <string name=\"input_features\">Introducere caracteristici</string>\n    <string name=\"permissions\">Folosește permisiunile</string>\n    <string name=\"service\">Servicii</string>\n    <string name=\"no_service\">Fără servicii</string>\n    <string name=\"orientation\">Orientare</string>\n    <string name=\"activities\">Activități</string>\n    <string name=\"media_size\">Media</string>\n    <string name=\"launch\">Pornire</string>\n    <string name=\"declared_permission\">Permisiuni</string>\n    <string name=\"user_id\">ID Utilizator</string>\n    <string name=\"about\">Despre</string>\n    <string name=\"installer_app\">Aplicație instalare</string>\n    <string name=\"data_size\">Date</string>\n    <string name=\"sdk_min\">Minim</string>\n    <string name=\"date_installed\">Dată instalare</string>\n    <string name=\"obb_size\">Obb</string>\n    <string name=\"system\">Sistem</string>\n    <string name=\"user\">Utilizator</string>\n    <string name=\"sdk_max\">Țintă</string>\n    <string name=\"class_name\">Nume Clasă</string>\n    <string name=\"toggle_class_listing\">Activează Listare Clase</string>\n    <string name=\"uninstall\">Dezinstalare</string>\n    <string name=\"require_no_permission\">Nu necesită permisiuni</string>\n    <string name=\"refresh\">Reîmprospătare</string>\n    <string name=\"no_activities\">Fără activități</string>\n    <string name=\"receivers\">Receptori</string>\n    <string name=\"no_receivers\">Fără receptori</string>\n    <string name=\"providers\">Prestatori</string>\n    <string name=\"no_providers\">Fără prestatori</string>\n    <string name=\"launch_mode\">Mod pornire</string>\n    <string name=\"task_affinity\">Afinitate sarcină</string>\n    <string name=\"sort_by_last_update\">Ultima actualizare</string>\n    <string name=\"authority\">Autoritate</string>\n    <string name=\"soft_input\">Mod introducere ușor</string>\n    <string name=\"grant_uri_permission\">Acordă permisiuni URI</string>\n    <string name=\"path_permissions\">Permisiuni cale</string>\n    <string name=\"read\">Citește</string>\n    <string name=\"write\">Scrie</string>\n    <string name=\"patterns_allowed\">Tipar permis</string>\n    <string name=\"shared_libs\">Librării comune</string>\n    <string name=\"group\">Grup</string>\n    <string name=\"uses_feature\">Folosește caracteristicile</string>\n    <string name=\"no_feature\">Fără caracteristici</string>\n    <string name=\"sort_by_shared_user_id\">ID Utilizator Comun</string>\n    <string name=\"shared_user_id\">ID Utilizator Comun</string>\n    <string name=\"sort_by_sha\">Semnătură</string>\n    <string name=\"signatures\">Semnături</string>\n    <string name=\"app_signing_signatures\">Semnături</string>\n    <string name=\"app_signing_no_signatures\">Fără semnături valide</string>\n    <string name=\"configurations\">Configurații</string>\n    <string name=\"no_configurations\">Fără configurații</string>\n    <string name=\"manifest\">Manifest</string>\n    <string name=\"error\">Eroare</string>\n    <string name=\"loading\">Încărcare…</string>\n    <string name=\"sort_by_app_label\">Etichetă aplicație</string>\n    <string name=\"sort_by_package_name\">Nume pachet</string>\n    <string name=\"sort_by_domain\">Aplicații utilizator</string>\n    <string name=\"sort_by_target_sdk\">SDK țintă</string>\n    <string name=\"data_received\">Date primite</string>\n    <string name=\"data_transmitted\">Date trimise</string>\n    <string name=\"data_usage_msg\">Utilizare date</string>\n    <string name=\"cache_size\">Cache</string>\n    <string name=\"app_not_installed\">Aplicație neinstalată</string>\n    <string name=\"sort\">Sortează</string>\n    <string name=\"app_info\">Informații aplicație</string>\n    <string name=\"system_app\">Aplicație sistem</string>\n    <string name=\"user_app\">Aplicație utilizator</string>\n    <string name=\"paths_and_directories\">Căi &amp; Directorii</string>\n    <string name=\"source_dir\">Directoriu sursă</string>\n    <string name=\"data_dir\">Directoriu date</string>\n    <string name=\"sdk_flags\">Marcaje</string>\n    <string name=\"more_info\">Mai multe informații</string>\n    <string name=\"date_updated\">Dată Actualizare</string>\n    <string name=\"main_activity\">Activitate Principală</string>\n    <string name=\"empty_package_name\">Nume pachet lipsă</string>\n    <string name=\"error_creating_shortcut\">Eroare creare scurtătură</string>\n    <string name=\"error_verbose_pin_shortcut\">Aplicația curentă nu suportă PinShortcut. Nu s-a putut crea scurtătură.</string>\n    <string name=\"create_shortcut\">Crează Scurtătură</string>\n    <string name=\"shortcut_name\">Nume Scurtătură</string>\n    <string name=\"package_name\">Nume Pachet</string>\n    <string name=\"icon_picker\">Selectare Iconiță</string>\n    <string name=\"license\">Licență</string>\n    <string name=\"third_party\">Librării și Iconițe Terțe</string>\n    <string name=\"credits\">Credite</string>\n    <string name=\"word_wrap\">Activează limitare cuvinte</string>\n    <string name=\"class_viewer\">Vizualizare Clasă</string>\n    <string name=\"flags\">Marcaje</string>\n    <string name=\"version_name_with_code\">Versiune <xliff:g id=\"version_name\" example=\"2.5.17\">%1$s</xliff:g> (<xliff:g id=\"version_code\" example=\"365\">%2$d</xliff:g> )</string>\n    <string name=\"starting_activity\">Activitate de pornire: <xliff:g id=\"activity_name\" example=\".main.MainActivity\">%1$s</xliff:g></string>\n    <plurals name=\"usage_days\">\n        <item quantity=\"one\">%1$d zi</item>\n        <item quantity=\"few\">%1$d zile</item>\n        <item quantity=\"other\">%1$d zile</item>\n    </plurals>\n    <string name=\"usage_today\">Astăzi</string>\n    <string name=\"usage_7_days\">Ultimele 7 zile</string>\n    <plurals name=\"usage_hours\">\n        <item quantity=\"one\">%1$d oră</item>\n        <item quantity=\"few\">%1$d ore</item>\n        <item quantity=\"other\">%1$d ore</item>\n    </plurals>\n    <plurals name=\"usage_minutes\">\n        <item quantity=\"one\">%1$d minut</item>\n        <item quantity=\"few\">%1$d minute</item>\n        <item quantity=\"other\">%1$d minute</item>\n    </plurals>\n    <plurals name=\"usage_seconds\">\n        <item quantity=\"one\">%1$d secundă</item>\n        <item quantity=\"few\">%1$d secunde</item>\n        <item quantity=\"other\">%1$d secunde</item>\n    </plurals>\n    <string name=\"menu_remove_rules\">Eliminare reguli</string>\n    <string name=\"grant_usage_acess_message\">Se utilizează pentru afișarea informațiilor despre utilizarea aplicațiilor.</string>\n    <string name=\"grant_usage_access\">Acordați acces la utilizare</string>\n    <string name=\"menu_apply_rules\">Aplicare reguli</string>\n    <string name=\"go\">Accesare</string>\n    <string name=\"go_back\">Înapoi</string>\n    <string name=\"usage_less_than_a_minute\">Mai puțin de un minut</string>\n    <string name=\"search\">Căutare</string>\n    <string name=\"failed_to_extract_apk_file\">Nu a putut extrage fișierul APK</string>\n    <string name=\"share_apk\">Partajare APK</string>\n    <string name=\"usage_weekly\">Săptămânal</string>\n    <string name=\"app_usage\">Utilizare aplicații</string>\n    <plurals name=\"usage_months\">\n        <item quantity=\"one\">%1$d lună</item>\n        <item quantity=\"few\">%1$d luni</item>\n        <item quantity=\"other\">%1$d luni</item>\n    </plurals>\n    <string name=\"no_shared_libs\">Nu există biblioteci partajate</string>\n    <string name=\"no_tracker_class\">Nu există clase de urmăritori</string>\n    <plurals name=\"no_of_times_opened\">\n        <item quantity=\"one\">%1$d timp</item>\n        <item quantity=\"few\">%1$d timpi</item>\n        <item quantity=\"other\">%1$d timpi</item>\n    </plurals>\n    <plurals name=\"two_trackers_and_classes\">\n        <item quantity=\"one\">2 urmăritori cu clasele <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g></item>\n        <item quantity=\"few\">2 urmăritori cu clasele <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g></item>\n        <item quantity=\"other\">2 urmăritori cu clasele <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g></item>\n    </plurals>\n    <string name=\"credits_message\">Pentru autorii:\n\\n- Proiectul Android Open Source\n\\n- <a href=\"https://github.com/zhaobozhen/libraries\">Absinthe\\'s libraries</a>\n\\n- <a href=\"https://github.com/butzist/ActivityLauncher\">Activity Launcher</a>\n\\n- <a href=\"https://bitbucket.org/oF2pks/fdroid-applications-info\">Apps_packages Info</a>\n\\n- <a href=\"https://github.com/zhaobao/AppsMonitor\">AppsMonitor</a>\n\\n- <a href=\"https://github.com/8enet/AppOpsX\">AppOpsX</a>\n\\n- <a href=\"https://github.com/gabrielemariotti/changeloglib\">ChangeLog Library</a>\n\\n- <a href=\"https://bitbucket.org/oF2pks/fdroid-classyshark3xodus\">ClassySharkAndroid</a>\n\\n- <a href=\"https://github.com/billthefarmer/editor\">Editor</a>\n\\n- <a href=\"https://github.com/Raival-e/File-Explorer\">File Explorer</a>\n\\n- <a href=\"https://github.com/nex3z/FlowLayout\">FlowLayout</a>\n\\n- <a href=\"https://github.com/k3b/intent-intercept\">Intent Intercept</a>\n\\n- <a href=\"https://github.com/YarikSOffice/lingver\">Lingver</a>\n\\n- <a href=\"https://github.com/topjohnwu/Magisk\">Magisk</a>\n\\n- <a href=\"https://github.com/zhanghai/MaterialFiles\">Material Files</a>\n\\n- <a href=\"https://github.com/pluscubed/matlog\">MatLog</a>\n\\n- <a href=\"https://github.com/matrix-org/matrix-android-sdk\">Matrix Android SDK</a>\n\\n- <a href=\"https://github.com/jensstein/oandbackup\">OAndBackup</a>\n\\n- <a href=\"https://github.com/open-keychain/open-keychain\">Open Keychain</a>\n\\n- <a href=\"https://github.com/Aefyr/SAI\">SAI</a>\n\\n- <a href=\"https://github.com/RikkaApps/Shizuku\">Shizuku</a>\n\\n- <a href=\"https://github.com/eclipse/tm4e\">tm4e</a>\n\\n- <a href=\"https://github.com/tuyafeng/Watt\">Watt</a> </string>\n    <plurals name=\"other_trackers_and_classes\">\n        <item quantity=\"one\"><xliff:g id=\"tracker_no\" example=\"8\">%1$d</xliff:g> urmăritor cu clasele <xliff:g id=\"class_no\" example=\"50\">%2$d</xliff:g></item>\n        <item quantity=\"few\"><xliff:g id=\"tracker_no\" example=\"8\">%1$d</xliff:g> urmăritori cu clasele <xliff:g id=\"class_no\" example=\"50\">%2$d</xliff:g></item>\n        <item quantity=\"other\"><xliff:g id=\"tracker_no\" example=\"8\">%1$d</xliff:g> urmăritori cu clasele <xliff:g id=\"class_no\" example=\"50\">%2$d</xliff:g> classes</item>\n    </plurals>\n    <plurals name=\"main_list_date_days\">\n        <item quantity=\"one\"><xliff:g id=\"last_update_date\" example=\"20/10/2020\">%1$s</xliff:g> <xliff:g id=\"day_no\" example=\"5\">%2$d</xliff:g> zi</item>\n        <item quantity=\"few\"><xliff:g id=\"last_update_date\" example=\"20/10/2020\">%1$s</xliff:g> <xliff:g id=\"day_no\" example=\"5\">%2$d</xliff:g> zile</item>\n        <item quantity=\"other\"><xliff:g id=\"last_update_date\" example=\"20/10/2020\">%1$s</xliff:g> <xliff:g id=\"day_no\" example=\"5\">%2$d</xliff:g> zile</item>\n    </plurals>\n    <string name=\"filter\">Filtrare</string>\n    <string name=\"exodus_link\">Link εxodus</string>\n    <string name=\"no_app_ops\">Fără operațiuni aplicații</string>\n    <string name=\"updated_app\">Actualizat</string>\n    <string name=\"filter_user_apps\">Aplicații utilizator</string>\n    <string name=\"no_apps\">Fără aplicații</string>\n    <string name=\"ecc\">Criptografie în curbă eliptică</string>\n    <string name=\"orientation_sensor_portrait\">Senzor portret</string>\n    <string name=\"import_failed\">Importare eșuată!</string>\n    <string name=\"clear_app_cache\">Șterge memoria cache a aplicației</string>\n    <string name=\"pref_about_msg\">Versiunea App Manager, licență, credite, etc.</string>\n    <string name=\"disable\">Dezactivat</string>\n    <string name=\"deny_dangerous_app_ops\">Refuzați operațiile periculoase ale aplicațiilor</string>\n    <string name=\"format\">Format</string>\n    <string name=\"enable\">Activat</string>\n    <string name=\"native_library_dir\">Directorul nativ al bibliotecii JNI</string>\n    <string name=\"saving_failed\">Salvarea a eșuat, încearcă din nou.</string>\n    <string name=\"done\">Realizat</string>\n    <string name=\"type_float\">Număr decimal</string>\n    <string name=\"type_string\">Caractere</string>\n    <string name=\"error_evaluating_input\">Nu s-a putut evalua intrarea</string>\n    <string name=\"key_name_cannot_be_null\">Numele Cheie nu poate fi gol</string>\n    <string name=\"disabled_app\">Dezactivat</string>\n    <string name=\"no_usage_in_this_time_range\">Nici o utilizare în acest interval de timp</string>\n    <string name=\"view_in_settings\">Vizualizați în Setări</string>\n    <string name=\"uninstall_app_message\">Dorești să dezinstalezi această aplicație\\?</string>\n    <string name=\"total_size\">Total</string>\n    <string name=\"app_settings\">Setări</string>\n    <string name=\"str_logo\">Logo</string>\n    <string name=\"sort_by_blocked_components\">Blocat primul</string>\n    <string name=\"sort_by_times_opened\">Timpii de deschidere</string>\n    <string name=\"running_apps\">Aplicații în curs de execuție</string>\n    <string name=\"kill_process\">Ucide</string>\n    <string name=\"backup_restore\">Copie de rezervă/Restaurare</string>\n    <string name=\"disable_background\">Previne funcționarea în fundal</string>\n    <string name=\"the_operation_was_successful\">Finalizat</string>\n    <string name=\"toggle_kill_for_system_apps\">Comutare pentru a opri aplicațiile de sistem</string>\n    <string name=\"running\">Rulare</string>\n    <string name=\"accept_time\">Timpul de acceptare</string>\n    <string name=\"export_failed\">Exportare eșuată!</string>\n    <string name=\"keyboard_type\">Tip tastatură</string>\n    <string name=\"navigation\">Navigare</string>\n    <string name=\"touchscreen\">Ecran tactil</string>\n    <string name=\"pref_export_msg\">Exportă regulile de blocare configurate în App Manager în memoria externă.</string>\n    <string name=\"pref_app_theme\">Tema aplicației</string>\n    <string name=\"sort_by_app_ops_names\">Numele aplicației de operare</string>\n    <string name=\"deny_dangerous_permissions\">Respinge permisiunile periculoase</string>\n    <string name=\"sort_by_tracker_components\">Urmăritori mai întâi</string>\n    <string name=\"launch_app\">Lansare</string>\n    <string name=\"changelog\">Schimbări</string>\n    <string name=\"community\">Comunitate</string>\n    <string name=\"pref_import_existing\">Importă regulile existente</string>\n    <string name=\"input_app_ops\">Aplicații ops de intrare</string>\n    <string name=\"backup\">Copie de rezervă</string>\n    <string name=\"restore\">Restaurare</string>\n    <string name=\"apply_to_system_apps\">Se aplică la aplicațiile de sistem</string>\n    <string name=\"no\">Nu</string>\n    <string name=\"delete_backup\">Șterge copia de rezervă</string>\n    <string name=\"yes\">Da</string>\n    <string name=\"installer_error_blocked_device\">dispozitiv</string>\n    <string name=\"batch_ops\">Operațiuni în loturi</string>\n    <string name=\"installer_error_session_write\">Nu s-a putut scrie în sesiunea de instalare</string>\n    <string name=\"orientation_reverse_landscape\">Portret inversat</string>\n    <string name=\"orientation_sensor_landscape\">Senzor peisaj</string>\n    <string name=\"required\">Necesar</string>\n    <string name=\"keyboard_no_keys\">Fără chei</string>\n    <string name=\"navigation_wheel\">Rotiță</string>\n    <string name=\"keyboard_qwerty\">QWERTY</string>\n    <string name=\"keyboard_12_keys\">12 taste</string>\n    <string name=\"touchscreen_finger\">Deget</string>\n    <string name=\"state_idle\">Inactiv</string>\n    <string name=\"state_wake_kill\">Wake kill</string>\n    <string name=\"ok\">OK</string>\n    <string name=\"input_backup_name\">Nume Backup</string>\n    <string name=\"apps\">Aplicații</string>\n    <string name=\"pref_compression_method\">Metoda de compresie</string>\n    <string name=\"issued_date\">Data emiterii</string>\n    <string name=\"serial_no\">Număr de serie</string>\n    <string name=\"rsa_modulus\">Modulul</string>\n    <string name=\"app_data_will_be_lost\">Datele existente vor fi pierdute.</string>\n    <string name=\"view_missing_signatures\">Apasă pentru a vizualiza sau a trimite semnături care nu sunt încă prezente în baza de date a librăriilor din App Manager.</string>\n    <string name=\"input_profile_name\">Numele profilului</string>\n    <string name=\"new_profile\">Profil nou</string>\n    <string name=\"duplicate\">Duplicat</string>\n    <string name=\"enabled\">Activat</string>\n    <string name=\"advanced\">Avansat</string>\n    <plurals name=\"alert_failed_to_disable_trackers\">\n        <item quantity=\"one\">Nu a fost posibilă dezactivarea urmăritorilor din %1$d aplicație</item>\n        <item quantity=\"few\">Nu a fost posibilă dezactivarea urmăritorilor din %1$d aplicații</item>\n        <item quantity=\"other\">Nu a fost posibilă dezactivarea urmăritorilor din %1$d aplicații</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_backup\">\n        <item quantity=\"one\">Nu s-a putut face backup pentru %1$d aplicație</item>\n        <item quantity=\"few\">Nu s-a putut face backup pentru %1$d aplicații</item>\n        <item quantity=\"other\">Nu s-a putut face backup pentru %1$d aplicații</item>\n    </plurals>\n    <string name=\"installer_error_bad_apks\">Fișiere APK invalide selectate</string>\n    <string name=\"select_user\">Selectare utilizator</string>\n    <string name=\"install_location_prefer_external\">Se preferă extern</string>\n    <string name=\"package_installer\">Instalator de pachete</string>\n    <string name=\"state_foreground\">Prim-plan</string>\n    <string name=\"input_permissions_description\">Introdu permisiuni cu spații, de exemplu <tt>com.permission.GET_ACCOUNTS android.permission.ACCESS_MEDIA_LOCATION</tt> etc. Se utilizează <tt>*</tt> pentru a aplica pentru toate permisiunile.</string>\n    <string name=\"public_key\">Cheia publică</string>\n    <string name=\"install_in_progress\">Se instalează…</string>\n    <string name=\"add_item\">Adaugă articol</string>\n    <string name=\"app_ops\">Operațiuni aplicații</string>\n    <string name=\"filtered_packages\">Pachete filtrate</string>\n    <string name=\"launch_mode_multiple\">Multiplu</string>\n    <string name=\"string_value\">Valoare string</string>\n    <string name=\"sort_by_dangerous_permissions\">Periculos mai întâi</string>\n    <string name=\"no_tracker_found\">Nu s-a găsit niciun urmăritor</string>\n    <string name=\"installer_error_conflict\">Nu s-a putut instala aplicația deoarece numele pachetului este în uz</string>\n    <string name=\"profile_state\">Starea profilului</string>\n    <string name=\"pref_export\">Export</string>\n    <string name=\"orientation_user_landscape\">Utilizator peisaj</string>\n    <string name=\"type_int\">Integer</string>\n    <string name=\"full_stop_tap_to_see_details\">. Apasă pentru a vedea detaliile.</string>\n    <string name=\"mode\">Mod</string>\n    <string name=\"orientation_behind\">În spate</string>\n    <string name=\"manifest_viewer\">Manifest Visualizator</string>\n    <string name=\"input_signatures_description\">Semnături de intrare cu spații, de exemplu <tt>com.facebook org.app2 com.app3</tt> etc.</string>\n    <string name=\"pref_encryption_msg\">Encriptare pentru backup-uri.</string>\n    <string name=\"integer_value\">Valoare Integer</string>\n    <string name=\"stopped\">Oprit</string>\n    <string name=\"data\">Date</string>\n    <string name=\"state_multithreaded\">Procese multiple</string>\n    <string name=\"filter_apps\">Aplicații</string>\n    <string name=\"website\">Site web</string>\n    <string name=\"failed_to_deny_dangerous_app_ops\">Nu s-au putut revoca toate aplicațiile de operare periculoase</string>\n    <string name=\"density_split_for_base_apk\"><xliff:g id=\"split_name\" example=\"xxdpi\">%1$s</xliff:g> (<xliff:g id=\"dpi_no\" example=\"480\">%2$d</xliff:g> DPI) resurse pentru APK-ul de bază</string>\n    <string name=\"un_apkm\">UnApkm</string>\n    <string name=\"input_profile_name_description\">Numele profilului nu poate conține spații.</string>\n    <string name=\"comment\">Comentariu</string>\n    <string name=\"clear\">Șterge</string>\n    <string name=\"installer_error_storage\">Nu există suficient spațiu de stocare pentru a instala aplicația</string>\n    <string name=\"tap_to_see_details\">Apasă pentru a vedea detalii</string>\n    <string name=\"aes\">AES</string>\n    <string name=\"pref_mode_of_operations\">Modul de operare</string>\n    <string name=\"clear_data\">Șterge datele</string>\n    <string name=\"night\">Noapte</string>\n    <string name=\"launch_mode_single_task\">Sarcină unică</string>\n    <string name=\"state_high_priority\">Prioritate înaltă</string>\n    <string name=\"locale_split_for_feature\"><xliff:g id=\"split_name\" example=\"English\">%1$s</xliff:g> local pentru caracteristica <xliff:g id=\"feature_name\" example=\"Visualizer\">%2$s</xliff:g></string>\n    <string name=\"orientation_portrait\">Portret</string>\n    <string name=\"decimal_value\">Valoare decimală</string>\n    <string name=\"installer_error_session_abandon\">Nu s-a putut abandona sesiunea de instalare</string>\n    <string name=\"pref_app_language\">Limba</string>\n    <string name=\"pref_remove_all_rules_msg\">Permisiunile vor fi acordate, iar operațiunile și componentele aplicației vor reveni la valorile lor implicite.</string>\n    <string name=\"density_split_for_feature\"><xliff:g id=\"split_name\" example=\"xxdpi\">%1$s</xliff:g> (<xliff:g id=\"dpi_no\" example=\"480\">%2$d</xliff:g> DPI) resurse pentru caracteristica <xliff:g id=\"feature_name\" example=\"Visualizer\">%3$s</xliff:g></string>\n    <string name=\"valid\">Valid</string>\n    <string name=\"send_crash_report\">Trimite raportul de blocare</string>\n    <string name=\"process_name\">Numele procesului</string>\n    <string name=\"pref_import_watt_msg\">Importă reguli de blocare din Watt, fiecare fișier conținând reguli pentru un singur pachet numit <tt>packagename.xml</tt> etc.</string>\n    <string name=\"package_name_is_installed_successfully\"><xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g> instalat</string>\n    <plurals name=\"no_of_components\">\n        <item quantity=\"one\">%1$d componentă</item>\n        <item quantity=\"few\">%1$d componente</item>\n        <item quantity=\"other\">%1$d componente</item>\n    </plurals>\n    <string name=\"skip_signature_checks\">Omite verificările prin semnătură</string>\n    <string name=\"installer_error_blocked\">Instalare blocată de <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g></string>\n    <string name=\"installer_error_generic\">Instalarea a eșuat</string>\n    <string name=\"pref_sign_apk\">Semnează APK</string>\n    <string name=\"sort_by_wifi_data\">Date Wi-Fi</string>\n    <string name=\"debuggable\">Depanabil</string>\n    <string name=\"pref_import_export_blocking_rules\">Reguli de blocare a importurilor/exporturilor</string>\n    <string name=\"pref_import_watt\">Import din Watt</string>\n    <string name=\"components\">Componente</string>\n    <string name=\"state_low_priority\">Prioritate scăzută</string>\n    <string name=\"cancel\">Anulare</string>\n    <string name=\"adb_over_tcp\">ADB peste TCP</string>\n    <string name=\"failed_to_stop\">Nu s-a putut opri <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g>.</string>\n    <string name=\"simple\">Simplu</string>\n    <string name=\"v2_scheme\">Schema v2 (de la Android 7.0)</string>\n    <string name=\"source_stamp_verified\">SourceStamp verificat.</string>\n    <string name=\"sort_by_screen_time\">Timpul în fața ecranului</string>\n    <string name=\"reset_to_default\">Resetare la valorile implicite</string>\n    <string name=\"only_install\">Instalare exclusivă</string>\n    <string name=\"scanner\">Scaner</string>\n    <string name=\"navigation_no_nav\">Fără nav</string>\n    <string name=\"test_only\">Doar test</string>\n    <string name=\"no_matching_package_found\">Nu s-a putut găsi nici o astfel de aplicație</string>\n    <string name=\"failed_to_fetch_package_info\">Nu s-au putut prelua informații despre pachet</string>\n    <string name=\"unblock_trackers\">Deblocare urmăritori</string>\n    <string name=\"allow_open_pgp_operation\">Apasă pentru a permite App Manager să utilizeze OpenPGP</string>\n    <string name=\"installer\">Installer</string>\n    <string name=\"pid_and_ppid\">ID proces: %1$d, ID proces părinte: %2$d</string>\n    <string name=\"only_works_in_root_or_adb_mode\">Funcționează numai în modul root sau ADB</string>\n    <string name=\"features\">Caracteristici</string>\n    <string name=\"backup_all_users\">Toți utilizatorii</string>\n    <string name=\"input_permissions\">Permisiuni de intrare</string>\n    <string name=\"clear_app_cache_description\">Șterge memoria cache a tuturor aplicațiilor</string>\n    <string name=\"navigation_trackball\">Bilă de căutare</string>\n    <string name=\"process_state\">Stare: <xliff:g id=\"process_state\" example=\"Sleeping\">%1$s</xliff:g></string>\n    <string name=\"am_crashed\">App Manager s-a blocat</string>\n    <string name=\"long_integer_value\">Valoare Integer lungă</string>\n    <string name=\"apply\">Aplicare</string>\n    <string name=\"block_unblock_trackers\">Blochează/deblochează urmăritori</string>\n    <string name=\"orientation_user\">Utilizator</string>\n    <string name=\"non_critical_exts\">Extensii non-critice</string>\n    <string name=\"select_apk\">Selectează APK</string>\n    <string name=\"profile_clear_data_msg\">Șterge datele aplicațiilor</string>\n    <string name=\"options\">Opțiuni</string>\n    <string name=\"sort_by_last_used\">Ultima utilizare</string>\n    <string name=\"apk_updater\">APK Updater</string>\n    <string name=\"never_ask\">Nu întreba niciodată</string>\n    <string name=\"operation_running\">Operațiune în desfășurare…</string>\n    <string name=\"state_zombie\">Zombie</string>\n    <string name=\"other\">Altele</string>\n    <string name=\"profile_block_trackers_msg\">Blochează urmăritorii din aplicații</string>\n    <string name=\"sort_by_component_name\">Numele componentei</string>\n    <string name=\"failed_to_uninstall_updates\">Nu s-au putut dezinstala actualizările pentru <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g>.</string>\n    <string name=\"allow_routine_ops_msg\">Permite utilizarea profilului în operațiunile de rutină</string>\n    <string name=\"requested_large_heap\">Teanc mare</string>\n    <string name=\"failed_to_enable_op\">Nu s-a putut activa operațiunea de aplicație solicitată</string>\n    <string name=\"orientation_reverse_portrait\">Portret inversat</string>\n    <string name=\"select_type\">Selectează un tip</string>\n    <string name=\"external_data_dir\">Director de date externe</string>\n    <string name=\"failed_to_deny_dangerous_perms\">Nu s-au putut revoca toate permisiunile periculoase</string>\n    <string name=\"failed_packages\">Pachete eșuate</string>\n    <string name=\"saved_successfully\">Salvat</string>\n    <string name=\"sort_by_app_ops_values\">Valoarea aplicației de operarare</string>\n    <string name=\"sort_by_process_id\">ID Proces</string>\n    <string name=\"pref_backup_flags_msg\">Adăugarea unei preselecții pentru opțiunile de backup elimină sarcina de a selecta indicatori de fiecare dată când efectuați un backup sau o restaurare.</string>\n    <string name=\"verified\">Verificat</string>\n    <string name=\"orientation_sensor\">Senzor</string>\n    <string name=\"state_waking\">Se trezește</string>\n    <string name=\"downgrade\">Retrogradare</string>\n    <string name=\"encryption\">Encriptare</string>\n    <string name=\"failed_to_revoke_permission\">Nu s-a putut revoca permisiunea</string>\n    <string name=\"boolean_value\">Valoare booleană</string>\n    <string name=\"split_feature_name\">Caracteristică: <xliff:g id=\"feature_name\" example=\"Visualizer\">%1$s</xliff:g></string>\n    <string name=\"abi_split_for_base_apk\"><xliff:g id=\"split_name\" example=\"arm64_v8a\">%1$s</xliff:g> cod pentru APK-ul de bază</string>\n    <string name=\"toggle_default_app_ops\">Comutare aplicații de operare implicite</string>\n    <string name=\"orientation_full_sensor\">Senzor complet</string>\n    <string name=\"sort_by_process_name\">Nume Proces</string>\n    <string name=\"in_progress\">În curs de desfășurare</string>\n    <string name=\"failed_to_duplicate_profile\">Nu s-a putut duplica profilul</string>\n    <string name=\"source_code\">Cod Sursă</string>\n    <string name=\"rsa\">RSA</string>\n    <string name=\"choose\">Alege</string>\n    <string name=\"no_code\">Fără cod</string>\n    <string name=\"select_theme\">Temă</string>\n    <string name=\"no_content\">Fără conținut</string>\n    <string name=\"user_and_uid\">Utilizator: <xliff:g id=\"user_name\" example=\"root\">%1$s</xliff:g> (<xliff:g id=\"user_id\" example=\"0\">%2$d</xliff:g>)</string>\n    <string name=\"disable_background_run\">Împiedică funcționarea în fundal</string>\n    <string name=\"sort_by_denied_app_ops\">Respins primul</string>\n    <string name=\"sort_by_denied_permissions\">Respins mai întâi</string>\n    <string name=\"installer_error_incompatible\">Aplicația este incompatibilă cu acest dispozitiv</string>\n    <string name=\"input_backup_name_description\">Numele backup-ului nu trebuie să înceapă cu o cifră și nici să conțină spații. Lăsați-l gol dacă doriți să utilizați data-ora curentă.</string>\n    <string name=\"user_profile_with_id\">Profil: %1$s (%2$d)</string>\n    <string name=\"community_links\"><a href=\"https://matrix.to/#/#appmanager:matrix.org\">Matrix</a> • <a href=\"https://t.me/AppManagerChannel\">Telegram</a> • <a href=\"https://twitter.com/AppManagerNews\">Twitter</a></string>\n    <string name=\"unblock\">Deblochează</string>\n    <string name=\"sort_by_backup\">Mai întâi copiile Backup</string>\n    <string name=\"failed_to_grant_permission\">Nu s-a putut acorda permisiunea</string>\n    <string name=\"usage_access_not_supported\">Nu s-a putut solicita accesul pentru utilizare, deoarece pagina de setări corespunzătoare nu există.</string>\n    <string name=\"v1_scheme\">Schema v1 (de la Android 1.0)</string>\n    <string name=\"permission_name\">Numele permisiunii</string>\n    <string name=\"block_trackers\">Blocare urmăritori</string>\n    <string name=\"uninstall_updates\">Dezinstalare actualizări</string>\n    <string name=\"pref_apk_signing_msg\">Setare schemelor de semnătură, a cheii de semnare personalizate etc.</string>\n    <string name=\"deleted_successfully\">Șters</string>\n    <string name=\"close\">Închide</string>\n    <string name=\"user_with_id\">Utilizator: <xliff:g id=\"user_id\" example=\"0\">%1$d</xliff:g></string>\n    <string name=\"clear_data_from_uninstalled_apps\">Șterge datele din aplicațiile dezinstalate</string>\n    <string name=\"whats_new\">Noutăți</string>\n    <string name=\"backup_obb_media\">OBB și Media</string>\n    <string name=\"not_yet_valid\">Nu este încă valid</string>\n    <string name=\"external_multiple_data_dir\">Director de date externe <xliff:g id=\"dir_no\" example=\"1\">%1$d</xliff:g></string>\n    <string name=\"v3_scheme\">Schema v3 (de la Android 9)</string>\n    <string name=\"type_boolean\">Adevărat/Fals</string>\n    <string name=\"export_blocking_rules\">Reguli de blocare a exporturilor</string>\n    <string name=\"block_unblock_trackers_description\">Blocare sau deblocare componente publicitare și de urmărire în toate aplicațiile instalate</string>\n    <string name=\"state_session_leader\">Liderul sesiunii</string>\n    <string name=\"rsa_exponent\">Exponent</string>\n    <string name=\"source_code_links\"><a href=\"https://github.com/MuntashirAkon/AppManager\">GitHub</a> • <a href=\"https://gitlab.com/muntashir/AppManager\">GitLab</a> • <a href=\"https://0xacab.org/muntashir/AppManager\">Riseup</a> • <a href=\"https://codeberg.org/muntashir/AppManager\">Codeberg</a></string>\n    <string name=\"blocking_rules\">Reguli de blocare</string>\n    <string name=\"orientation_unspecified\">Nespecificat</string>\n    <string name=\"apply_to_system_apps_question\">Se aplică și la aplicațiile de sistem\\? Selectează \\\"Nu\\\" dacă nu ești sigur.</string>\n    <string name=\"state_trace_stop\">Oprire traseu</string>\n    <string name=\"app_signing_signature_schemes\">Scheme de semnătură</string>\n    <string name=\"uninstall_system_app_message\">Este o aplicație de sistem. Ești sigur că vrei să dezinstalezi această aplicație\\?</string>\n    <string name=\"duration\">Durată</string>\n    <string name=\"installed_version\">Versiune instalată</string>\n    <string name=\"state_unknown\">Necunoscut</string>\n    <string name=\"expiry_date\">Data expirării</string>\n    <string name=\"profile_force_stop_msg\">Oprire forțată a aplicațiilor</string>\n    <string name=\"pref_import\">Import</string>\n    <string name=\"_undefined\">Nedefinit</string>\n    <string name=\"not_verified\">Nu s-a verificat</string>\n    <string name=\"pref_import_msg\">Importă regulile de blocare exportate anterior din App Manager.</string>\n    <string name=\"open_pgp_provider\">Furnizor OpenPGP</string>\n    <string name=\"dsa_affine_y\">Coordonata Affine y</string>\n    <string name=\"are_you_sure\">Ești sigur\\?</string>\n    <string name=\"obb_files_extracted_successfully\">Fișiere OBB extrase</string>\n    <string name=\"lib_details\">Detalii Librării</string>\n    <string name=\"state_parked\">Parcat</string>\n    <string name=\"force_stop\">Oprire forțată</string>\n    <string name=\"usage_access\">Acces de utilizare</string>\n    <string name=\"profiles\">Profile</string>\n    <string name=\"changes_not_saved\">Schimbările nu sunt salvate</string>\n    <string name=\"state_device_io\">Dispozitiv I/O</string>\n    <string name=\"auto\">Auto</string>\n    <string name=\"systemless_app\">Aplicație fără sistem</string>\n    <string name=\"profile_clear_cache_msg\">Șterge memoria cache a aplicațiilor</string>\n    <string name=\"deny_app_ops_description\">Setează un mod pentru operațiunile aplicației identificate prin valorile constantelor, de exemplu <tt>63</tt> sau <tt>RUN_IN_BACKGROUND</tt></string>\n    <string name=\"uninstalled_successfully\"><xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g> a fost dezinstalat.</string>\n    <string name=\"filter_system_apps\">Aplicații de sistem</string>\n    <string name=\"orientation_no_sensor\">Fără senzor</string>\n    <string name=\"orientation_landscape\">Peisaj</string>\n    <string name=\"expired\">Expirat</string>\n    <string name=\"dsa_affine_x\">Coordonata Affine x</string>\n    <string name=\"sort_by_mobile_data\">Date mobile</string>\n    <string name=\"termux\">Termux</string>\n    <string name=\"orientation_user_portrait\">Utilizator portret</string>\n    <string name=\"issuer\">Emitent</string>\n    <string name=\"launch_mode_single_instance\">Instanță unică</string>\n    <string name=\"v4_scheme\">Schema v4 (de la Android 11)</string>\n    <string name=\"no_libs\">Fără librării</string>\n    <string name=\"install_location\">Locația de instalare</string>\n    <string name=\"discard\">Renunță</string>\n    <string name=\"the_import_was_successful\">Importat</string>\n    <string name=\"reject_time\">Timpul de respingere</string>\n    <string name=\"reinstall\">Reinstalare</string>\n    <string name=\"installer_error_security\">Nu s-au putut accesa fișierele APK</string>\n    <string name=\"routine_ops\">Operațiuni de rutină</string>\n    <string name=\"copy\">Copiază</string>\n    <string name=\"pref_sign_apk_msg\">Semnează fișierele APK înainte de a le instala.</string>\n    <string name=\"app_signing_install_without_data_loss\">Dacă ai dezactivat verificarea semnăturii, poți utiliza opțiunea <b>Instalare exclusivă</b> pentru a instala aplicația fără a pierde date.</string>\n    <string name=\"failed_to_extract_obb_files\">Nu s-au putut extrage fișierele OBB</string>\n    <string name=\"orientation_locked\">Blocat</string>\n    <string name=\"no_profiles\">Nu există profile</string>\n    <string name=\"keystore\">KeyStore</string>\n    <string name=\"installer_error_session_create\">Nu s-a putut crea o sesiune de instalare</string>\n    <string name=\"conversion_failed\">Conversia a eșuat.</string>\n    <string name=\"unknown_split_for_feature\"><xliff:g id=\"split_name\" example=\"some_split\">%1$s</xliff:g> pentru caracteristica <xliff:g id=\"feature_name\" example=\"Visualizer\">%2$s</xliff:g></string>\n    <string name=\"version\">Versiune</string>\n    <string name=\"installer_error_aborted\">Instalarea a eșuat fie pentru că a fost anulată, fie pentru că sesiunea a fost închisă în mod neașteptat</string>\n    <string name=\"install_app_message\">Vrei să instalezi această aplicație\\?</string>\n    <string name=\"pref_import_blocker_msg\">Importă reguli de blocare din Blocker, fiecare fișier conținând reguli pentru un singur pachet.</string>\n    <string name=\"failed_to_reset_app_ops\">Nu s-a putut reseta aplicația de operare</string>\n    <string name=\"storage_and_cache\">Stocare și memorie cache</string>\n    <string name=\"the_export_was_successful\">Exportat</string>\n    <string name=\"failed_to_uninstall_app\">Dezinstalare eșuată</string>\n    <string name=\"second_degree_tracker_note\">Prefixul ² indică faptul că urmăritorii se află în <a href=\"https://etip.exodus-privacy.eu.org/\">Lista de așteptare ETIP</a>, adică încă se investighează dacă aceștia sunt urmăritori reali.</string>\n    <string name=\"pref_import_existing_msg\">Adăugare componente dezactivat de alte aplicații în App Manager. Atenție la utilizarea acestui instrument, deoarece pot exista multe rezultate fals pozitive. Alege doar aplicațiile de care ești sigur.</string>\n    <string name=\"block_components_dots\">Blocare componente…</string>\n    <string name=\"filter_apps_with_activities\">Cu activități</string>\n    <string name=\"one_click_ops\">Operațiuni cu 1 clic</string>\n    <string name=\"databases\">Baze de date</string>\n    <string name=\"external_data\">Date externe</string>\n    <string name=\"export_icon\">Pictograma Extragere</string>\n    <string name=\"orientation_full_user\">Utilizator complet</string>\n    <string name=\"usage_yesterday\">Ieri</string>\n    <string name=\"select_all\">Selectează tot</string>\n    <string name=\"install_location_internal_only\">Numai pentru uz intern</string>\n    <string name=\"failed_to_disable_op\">Nu s-a putut dezactiva operațiunea de aplicație solicitată</string>\n    <string name=\"clear_data_from_uninstalled_apps_description\">Șterge datele din aplicațiile care sunt dezinstalate cu indicatorul <tt>DONT_DELETE_DATA</tt></string>\n    <string name=\"input_signatures\">Semnături de intrare</string>\n    <string name=\"do_you_want_to_uninstall_and_install\">Vrei să dezinstalezi și să instalezi din nou aplicația\\?</string>\n    <string name=\"profile_state_msg\">Stare de pornire/oprire personalizată pentru acest profil</string>\n    <string name=\"no_root\">Fără root</string>\n    <string name=\"none\">Nu există</string>\n    <string name=\"save\">Salvează</string>\n    <string name=\"base_apk\">APK de bază</string>\n    <string name=\"state_locked_memory\">Memorie blocată</string>\n    <string name=\"pref_global_blocking_enabled\">Blocaj instantaneu al componentelor</string>\n    <string name=\"process_state_with_extra\">Stare: <xliff:g id=\"process_state\" example=\"Sleeping\">%1$s</xliff:g> (<xliff:g id=\"state_extra\" example=\"High priority\">%2$s</xliff:g>)</string>\n    <string name=\"ago\">în urmă</string>\n    <string name=\"import_options\">Opțiuni de importare</string>\n    <string name=\"export_options\">Opțiuni de exportare</string>\n    <string name=\"sort_by_permission_names\">Numele permisiunii</string>\n    <string name=\"state_dead\">Mort</string>\n    <string name=\"rules\">Reguli</string>\n    <string name=\"follow_system\">Sistem de urmărire</string>\n    <string name=\"clear_cache\">Șterge memoria cache</string>\n    <string name=\"open_in_termux\">Deschide în Termux</string>\n    <string name=\"installer_error_session_commit\">Nu s-au putut comite fișierele APK</string>\n    <string name=\"sort_by_memory_usage\">Utilizarea memoriei</string>\n    <string name=\"battery_mode\">Mod baterie</string>\n    <string name=\"app_size\">Aplicație</string>\n    <string name=\"trackers\">Urmăritori</string>\n    <string name=\"run_in_termux\">Rulează în Termux</string>\n    <string name=\"backup_multiple\">Backup multiplu</string>\n    <string name=\"unknown_split_for_base_apk\"><xliff:g id=\"split_name\" example=\"some_split\">%1$s</xliff:g> pentru APK-ul de bază</string>\n    <string name=\"dev_protected_data_dir\">Director de date protejat de dispozitiv</string>\n    <string name=\"shared_prefs\">Pref comune</string>\n    <string name=\"pref_global_blocking_enabled_msg\">Vă permite să blocați orice componentă a oricărei aplicații fără a activa în mod explicit blocarea pentru aplicația respectivă.</string>\n    <string name=\"navigation_dial_pad\">Tastatura telefonică</string>\n    <string name=\"apk_signing\">Semnătura APK</string>\n    <string name=\"type_long\">Integer Lung</string>\n    <string name=\"pref_import_blocker\">Import din Blocker</string>\n    <string name=\"day\">Zi</string>\n    <string name=\"external_apk_no_app_op\">APK extern nu are nicio aplicație de operare</string>\n    <string name=\"failed_to_parse_some_numbers\">Nu s-au putut analiza unele numere</string>\n    <string name=\"touchscreen_no_touch\">Fără touch</string>\n    <string name=\"state_sleeping\">Adormit</string>\n    <string name=\"confirm_installation\">Confirmare instalare</string>\n    <string name=\"filter_apps_with_backups\">Cu backup-uri</string>\n    <string name=\"critical_exts\">Extensii critice</string>\n    <string name=\"pref_signature_schemes_msg\">Cel puțin schemele v1 și v2 ar trebui să fie selectate pentru o mai mare compatibilitate. Schema v4 necesită v2 sau v3.</string>\n    <string name=\"type\">Tip</string>\n    <string name=\"validity\">Validitate</string>\n    <string name=\"app_signing_signature_mismatch_for_system_apps\">Nu s-a putut instala aplicația deoarece o aplicație de sistem cu o semnătură diferită are acest nume de pachet.</string>\n    <string name=\"filter_running_apps\">Aplicații în execuție</string>\n    <string name=\"rules_not_applied\">Regulile nu sunt aplicate</string>\n    <string name=\"abi_split_for_feature\"><xliff:g id=\"split_name\" example=\"arm64_v8a\">%1$s</xliff:g> cod pentru <xliff:g id=\"feature_name\" example=\"Visualizer\">%2$s</xliff:g></string>\n    <string name=\"locale_split_for_base_apk\"><xliff:g id=\"split_name\" example=\"English\">%1$s</xliff:g> local pentru APK-ul de bază</string>\n    <string name=\"choose_language\">Schimbă limba</string>\n    <string name=\"key_name\">Nume Cheie</string>\n    <string name=\"filter_apps_with_rules\">Cu reguli</string>\n    <string name=\"touchscreen_stylus\">Stylus (creion)</string>\n    <string name=\"tap_to_submit_crash_report\">Apasă pentru a trimite raportul de blocare.</string>\n    <string name=\"launch_mode_single_top\">Top unic</string>\n    <string name=\"algorithm\">Algoritm</string>\n    <string name=\"deletion_failed\">Ștergerea a eșuat</string>\n    <string name=\"delete\">Șterge</string>\n    <string name=\"try_again\">Încearcă din nou</string>\n    <string name=\"sys_config\">Configurare sistem</string>\n    <string name=\"root\">Root</string>\n    <string name=\"input_app_ops_description\">Aplicații op de intrare și/sau constante cu spații, ex. <tt>WAKE_LOCK 63 72 CAMERA</tt> etc.</string>\n    <string name=\"block\">Blochează</string>\n    <string name=\"pref_remove_all_rules\">Eliminarea tuturor regulilor</string>\n    <string name=\"clear_data_message\">Ești sigur că vrei să ștergi datele din această aplicație\\?</string>\n    <string name=\"backup_options\">Opțiuni copii de rezervă</string>\n    <string name=\"off\">Oprit</string>\n    <string name=\"failed_to_uninstall\">Nu s-a putut dezinstala <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g>.</string>\n    <string name=\"sort_by_apps_first\">Mai întâi aplicațiile</string>\n    <plurals name=\"tracker_and_classes\">\n        <item quantity=\"one\">1 urmăritor cu clasa <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g></item>\n        <item quantity=\"few\">1 urmăritor cu clasele <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g></item>\n        <item quantity=\"other\">1 urmăritor cu clasele <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g></item>\n    </plurals>\n    <plurals name=\"alert_failed_to_restore\">\n        <item quantity=\"one\">Nu s-a putut restaura %1$d aplicație</item>\n        <item quantity=\"few\">Nu s-au putut restaura %1$d aplicații</item>\n        <item quantity=\"other\">Nu s-au putut restaura %1$d aplicații</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_delete_backup\">\n        <item quantity=\"one\">Nu s-a putut șterge %1$d backup</item>\n        <item quantity=\"few\">Nu s-au putut șterge %1$d backup-uri</item>\n        <item quantity=\"other\">Nu s-au putut șterge %1$d backup-uri</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_unblock_trackers\">\n        <item quantity=\"one\">Nu s-au putut debloca urmăritorii din %1$d aplicație</item>\n        <item quantity=\"few\">Nu s-au putut debloca urmăritorii din %1$d aplicații</item>\n        <item quantity=\"other\">Nu s-au putut debloca urmăritorii din %1$d aplicații</item>\n    </plurals>\n    <plurals name=\"classes\">\n        <item quantity=\"one\">%1$d clasă</item>\n        <item quantity=\"few\">%1$d clase</item>\n        <item quantity=\"other\">%1$d clase</item>\n    </plurals>\n    <plurals name=\"libraries\">\n        <item quantity=\"one\">%1$d librărie</item>\n        <item quantity=\"few\">%1$d librării</item>\n        <item quantity=\"other\">%1$d librării</item>\n    </plurals>\n    <plurals name=\"missing_signatures\">\n        <item quantity=\"one\">%1$d semnătură lipsește</item>\n        <item quantity=\"few\">%1$d semnături lipsesc</item>\n        <item quantity=\"other\">%1$d semnături lipsesc</item>\n    </plurals>\n    <plurals name=\"verified_with_warning\">\n        <item quantity=\"one\">Verificat cu %d avertisment</item>\n        <item quantity=\"few\">Verificat cu %d avertismente</item>\n        <item quantity=\"other\">Verificat cu %d avertismente</item>\n    </plurals>\n    <plurals name=\"failed_to_import_files\">\n        <item quantity=\"one\">Nu s-a putut importa %1$d fișier.</item>\n        <item quantity=\"few\">Nu s-au putut importa %1$d fișiere.</item>\n        <item quantity=\"other\">Nu s-au putut importa %1$d fișiere.</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_uninstall\">\n        <item quantity=\"one\">Nu s-a putut dezinstala %1$d aplicație</item>\n        <item quantity=\"few\">Nu s-au putut dezinstala %1$d aplicații</item>\n        <item quantity=\"other\">Nu s-au putut dezinstala %1$d aplicații</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_disable_background\">\n        <item quantity=\"one\">Nu s-a putut împiedica rularea în fundal a %1$d aplicație</item>\n        <item quantity=\"few\">Nu s-a putut împiedica rularea în fundal a %1$d aplicații</item>\n        <item quantity=\"other\">Nu s-a putut împiedica rularea în fundal a %1$d aplicații</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_set_app_ops\">\n        <item quantity=\"one\">Nu s-au putut seta operațiunile aplicației pentru %1$d aplicație</item>\n        <item quantity=\"few\">Nu s-au putut seta operațiunile aplicației pentru %1$d aplicații</item>\n        <item quantity=\"other\">Nu s-au putut seta operațiunile aplicației pentru %1$d aplicații</item>\n    </plurals>\n    <string name=\"memory_virtual_memory\">Memorie: %1$s, Memorie virtuală: %2$s</string>\n    <string name=\"pref_import_export_blocking_rules_msg\">Import/export de reguli, import de reguli externe din Watt sau Blocker.</string>\n    <string name=\"unknown_op\">Operațiune necunoscută</string>\n    <string name=\"input_app_ops_description_profile\">Aplicații op de intrare și/sau constante cu spații, ex. <tt>WAKE_LOCK 63 72 CAMERA</tt> etc. Folosește <tt>*</tt> pentru a aplica pentru toate aplicațiile ops configurate.</string>\n    <plurals name=\"backup_exists_are_you_sure\">\n        <item quantity=\"one\">Există deja un backup. Ești sigur\\?</item>\n        <item quantity=\"few\">Mai mult de o aplicație are deja un backup. Ești sigur\\?</item>\n        <item quantity=\"other\">Mai mult de o aplicație are deja un backup. Ești sigur\\?</item>\n    </plurals>\n    <string name=\"installer_error_lidl_rom\">ROM-ul tău este incompatibil cu Rootless Installer.</string>\n    <string name=\"backup_apk_files\">Fișiere APK</string>\n    <string name=\"apply_now\">Aplică acum…</string>\n    <string name=\"update_uninstalled_successfully\">Actualizările pentru <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g> au fost dezinstalate.</string>\n    <string name=\"send_selected\">Trimite selectat</string>\n    <string name=\"allow_routine_ops\">Permite operații de rutină</string>\n    <plurals name=\"alert_failed_to_clear_data\">\n        <item quantity=\"one\">Nu s-au putut șterge datele din %1$d aplicație</item>\n        <item quantity=\"few\">Nu s-au putut șterge datele din %1$d aplicații</item>\n        <item quantity=\"other\">Nu s-au putut șterge datele din %1$d aplicații</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_force_stop\">\n        <item quantity=\"one\">Nu s-a putut opri forțat %1$d aplicație</item>\n        <item quantity=\"few\">Nu s-au putut opri forțat %1$d aplicații</item>\n        <item quantity=\"other\">Nu s-au putut opri forțat %1$d aplicații</item>\n    </plurals>\n    <plurals name=\"no_of_trackers\">\n        <item quantity=\"one\">%1$d urmăritor</item>\n        <item quantity=\"few\">%1$d urmăritori</item>\n        <item quantity=\"other\">%1$d urmăritori</item>\n    </plurals>\n    <plurals name=\"no_of_splits\">\n        <item quantity=\"one\">%1$d împărțit</item>\n        <item quantity=\"few\">%1$d împărțiți</item>\n        <item quantity=\"other\">%1$d împărțiți</item>\n    </plurals>\n    <plurals name=\"failed_to_backup_some_apk_files\">\n        <item quantity=\"one\">Nu s-a putut face backup pentru %1$d aplicație</item>\n        <item quantity=\"few\">Nu s-a putut face backup pentru %1$d aplicații</item>\n        <item quantity=\"other\">Nu s-a putut face backup pentru %1$d aplicații</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_block_components\">\n        <item quantity=\"one\">Nu s-au putut bloca componentele pentru %1$d aplicație</item>\n        <item quantity=\"few\">Nu s-au putut bloca componentele pentru %1$d aplicații</item>\n        <item quantity=\"other\">Nu s-au putut bloca componentele pentru %1$d aplicații</item>\n    </plurals>\n    <plurals name=\"app_signing_signature_schemes_pl\">\n        <item quantity=\"one\">Schema de semnătură</item>\n        <item quantity=\"few\">Scheme de semnături</item>\n        <item quantity=\"other\">Scheme de semnături</item>\n    </plurals>\n    <string name=\"all_classes\">Toate clasele</string>\n    <string name=\"found_trackers\">Am găsit urmăritori:</string>\n    <string name=\"tracker_details\">Detalii urmăritor</string>\n    <string name=\"tracker_classes\">Clase urmăritor</string>\n    <string name=\"update\">Actualizare</string>\n    <string name=\"install\">Instalare</string>\n    <string name=\"internal_data\">Date interne</string>\n    <string name=\"subject\">Subiect</string>\n    <string name=\"checksums\">Checksums</string>\n    <string name=\"app_signing_signature\">Semnătură</string>\n    <string name=\"on\">Pornit</string>\n    <string name=\"this_action_cannot_be_undone\">Această acțiune nu poate fi anulată.</string>\n    <string name=\"keep_data_and_app_signing_signatures\">Păstrarea datelor și semnăturilor</string>\n    <string name=\"no_app_ops_permission\">Nu aveți permisiunea de a afișa operațiunile aplicației</string>\n    <string name=\"splits\">Despărțiri</string>\n    <string name=\"input_keystore_pass\">Introdu parola KeyStore</string>\n    <string name=\"input_keystore_pass_msg\">Atinge aici pentru a introduce parola KeyStore</string>\n    <string name=\"block_unblock_components_dots\">Blocare/deblocare componente…</string>\n    <string name=\"unblock_components_dots\">Deblocare componente…</string>\n    <string name=\"block_unblock_components_description\">Blochează sau deblochează toate componentele identificate prin semnăturile date</string>\n    <plurals name=\"alert_failed_to_unblock_components\">\n        <item quantity=\"one\">Nu s-au putut debloca componentele pentru %1$d aplicație</item>\n        <item quantity=\"few\">Nu s-au putut debloca componentele pentru %1$d aplicații</item>\n        <item quantity=\"other\">Nu s-au putut debloca componentele pentru %1$d aplicații</item>\n    </plurals>\n    <string name=\"input_keystore_alias_pass\">Parola pentru alias <b>%1$s</b></string>\n    <string name=\"source_stamp_verified_and_identified_to_be_from_source\">SourceStamp verificat și identificat ca fiind din <xliff:g id=\"source\" example=\"Google Play\">%1$s</xliff:g>.</string>\n    <string name=\"input_keystore_alias_pass_msg\">Apasă aici pentru a furniza parola pentru %1$s</string>\n    <string name=\"input_keystore_pass_description\">Introdu parola App Manager KeyStore. Dacă vezi acest lucru pentru prima dată, utilizează un generator de parole pentru a genera o parolă și salveaz-o într-un loc sigur înainte de a o introduce aici.</string>\n    <string name=\"input_keystore_alias_pass_description\">Introdu parola pentru alias-ul <b>%1$s</b>. Lasă spațiu gol dacă parola este aceeași cu parola KeyStore.</string>\n</resources>"
  },
  {
    "path": "app/src/main/res/values-ru-rRU/disclaimer.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- SPDX-License-Identifier: GPL-3.0-or-later --><resources>\n    <string name=\"disclaimer_header\">Предупреждение</string>\n    <string name=\"disclaimer_body\">App Manager предлагает функции, которые могут выполняться с помощью root-прав, которые могут нанести вред вашему устройству при неправильном использовании. App Manager не несет ответственности за любой ущерб, нанесенный при использовании этого приложения. Если вы не полностью осведомлены о том, как работает root, вам следует избегать использования параметров root, пока вы полностью не осознаете риски.\n\\n\n\\nЛюбая ссылка, которую я предоставляю на другие приложения и веб-сайты, предназначена для пользователей. Я не несу ответственности за любой контент, который вы можете найти, перейдя по внешним ссылкам.\n\\n\n\\nИспользуя App Manager, вы принимаете на себя полную ответственность за собственное использование и не принимаете никаких убытков, претензий или денежной оценки в результате неправильного использования.\n\\n\n\\nИспользуя это приложение, вы принимаете на себя всю ответственность за его использование и соглашаетесь с тем, что я не несу ответственности за любые ваши действия, которые могут негативно повлиять на ваше устройство.</string>\n    <string name=\"disclaimer_footer\">© 2020–2022 Muntashir Al-Islam</string>\n    <string name=\"disclaimer_agree_forever\">Не показывать снова</string>\n    <string name=\"disclaimer_agree\">Принять</string>\n    <string name=\"disclaimer_exit\">Выход</string>\n</resources>"
  },
  {
    "path": "app/src/main/res/values-ru-rRU/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- SPDX-License-Identifier: GPL-3.0-or-later --><resources xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:tools=\"http://schemas.android.com/tools\">\n    <string name=\"_lang_tag\" translatable=\"false\">ru-RU</string>\n    <string name=\"uninstall\">Удалить</string>\n    <string name=\"permissions\">Используемые разрешения</string>\n    <string name=\"require_no_permission\">Не требует разрешений</string>\n    <string name=\"activities\">Активити</string>\n    <string name=\"launch\">Запуск</string>\n    <string name=\"refresh\">Обновить</string>\n    <string name=\"no_activities\">Нет активити</string>\n    <string name=\"receivers\">Приемники</string>\n    <string name=\"no_receivers\">Нет приемников</string>\n    <string name=\"providers\">Поставщики</string>\n    <string name=\"no_providers\">Нет поставщиков</string>\n    <string name=\"launch_mode\">Режим запуска</string>\n    <string name=\"task_affinity\">Сочетание задачи</string>\n    <string name=\"sort_by_last_update\">Последнее обновление</string>\n    <string name=\"authority\">Права</string>\n    <string name=\"service\">Службы</string>\n    <string name=\"no_service\">Нет служб</string>\n    <string name=\"orientation\">Ориентация</string>\n    <string name=\"soft_input\">Режим мягкого ввода</string>\n    <string name=\"flags\">Флаги</string>\n    <string name=\"grant_uri_permission\">Предоставьте разрешения URI</string>\n    <string name=\"path_permissions\">Разрешения пути</string>\n    <string name=\"read\">Чтение</string>\n    <string name=\"write\">Запись</string>\n    <string name=\"patterns_allowed\">Графические ключи разрешены</string>\n    <string name=\"declared_permission\">Разрешения</string>\n    <string name=\"shared_libs\">Общие библиотеки</string>\n    <string name=\"group\">Группа</string>\n    <string name=\"uses_feature\">Используемые функции</string>\n    <string name=\"no_feature\">Нет функций</string>\n    <string name=\"sort_by_shared_user_id\">Общий идентификатор пользователя</string>\n    <string name=\"shared_user_id\">Общий идентификатор пользователя</string>\n    <string name=\"sort_by_sha\">Подпись</string>\n    <string name=\"signatures\">Подписи</string>\n    <string name=\"app_signing_no_signatures\">Нет действительных подписей</string>\n    <string name=\"configurations\">Конфигурации</string>\n    <string name=\"no_configurations\">Нет конфигураций</string>\n    <string name=\"input_features\">Функции ввода</string>\n    <string name=\"manifest\">Манифест</string>\n    <string name=\"error\">Error</string>\n    <string name=\"loading\">Загрузка…</string>\n    <!-- &#8230; = ... -->\n    <string name=\"sort_by_app_label\">Название приложения</string>\n    <string name=\"sort_by_package_name\">Имя пакета</string>\n    <string name=\"sort_by_domain\">Сначала пользовательские</string>\n    <string name=\"sort_by_target_sdk\">Целевая версия SDK</string>\n    <string name=\"data_received\">Данных получено</string>\n    <string name=\"data_transmitted\">Данных отправлено</string>\n    <string name=\"data_usage_msg\">Использование данных</string>\n    <string name=\"about\">О приложении</string>\n    <string name=\"data_size\">Данные</string>\n    <string name=\"cache_size\">Кэш</string>\n    <string name=\"obb_size\">Obb</string>\n    <string name=\"media_size\">Медиа</string>\n    <string name=\"app_not_installed\">Приложение не установлено</string>\n    <string name=\"system\">Системные</string>\n    <string name=\"user\">Пользователь</string>\n    <string name=\"sort\">Сортировка</string>\n    <string name=\"version_name_with_code\">Версия <xliff:g id=\"version_name\" example=\"2.5.17\">%1$s</xliff:g> (<xliff:g id=\"version_code\" example=\"365\">%2$d</xliff:g>)</string>\n    <string name=\"app_info\">О приложении</string>\n    <string name=\"system_app\">Системное</string>\n    <string name=\"user_app\">Пользовательское</string>\n    <string name=\"paths_and_directories\">Пути и каталоги</string>\n    <string name=\"source_dir\">Исходный каталог</string>\n    <string name=\"data_dir\">Каталог данных</string>\n    <string name=\"sdk_min\">мин. версия</string>\n    <string name=\"sdk_max\">Целевая версия</string>\n    <string name=\"sdk_flags\">Флаги</string>\n    <string name=\"more_info\">Подробнее</string>\n    <string name=\"date_installed\">Дата установки</string>\n    <string name=\"date_updated\">Дата обновления</string>\n    <string name=\"installer_app\">Установщик приложения</string>\n    <string name=\"user_id\">Идентификатор пользователя</string>\n    <string name=\"main_activity\">Главное активити</string>\n    <string name=\"empty_package_name\">Пустое имя пакета</string>\n    <string name=\"error_creating_shortcut\">Ошибка при создании ярлыка</string>\n    <string name=\"error_verbose_pin_shortcut\">Текущий лончер не поддерживает закрепление ярлыков. Невозможно создать ярлык.</string>\n    <string name=\"starting_activity\">Стартовое активити: <xliff:g id=\"activity_name\" example=\".main.MainActivity\">%1$s</xliff:g></string>\n    <string name=\"create_shortcut\">Создать ярлык</string>\n    <string name=\"shortcut_name\">Название ярлыка</string>\n    <string name=\"package_name\">Имя пакета</string>\n    <string name=\"class_name\">Название класса</string>\n    <string name=\"icon_picker\">Выбор иконок</string>\n    <string name=\"license\">Лицензия</string>\n    <string name=\"third_party\">Сторонние библиотеки и значки</string>\n    <string name=\"credits\">Авторы</string>\n    <string name=\"credits_message\">Благодарность авторам:\n\\n- Android Open Source Project\n\\n- <a href=\"https://github.com/zhaobozhen/libraries\">Absinthe\\'s libraries</a>\n\\n- <a href=\"https://github.com/butzist/ActivityLauncher\">Activity Launcher</a>\n\\n- <a href=\"https://bitbucket.org/oF2pks/fdroid-applications-info\">Apps_packages Info</a>\n\\n- <a href=\"https://github.com/zhaobao/AppsMonitor\">AppsMonitor</a>\n\\n- <a href=\"https://github.com/8enet/AppOpsX\">AppOpsX</a>\n\\n- <a href=\"https://github.com/gabrielemariotti/changeloglib\">ChangeLog Library</a>\n\\n- <a href=\"https://bitbucket.org/oF2pks/fdroid-classyshark3xodus\">ClassySharkAndroid</a>\n\\n- <a href=\"https://github.com/billthefarmer/editor\">Editor</a>\n\\n- <a href=\"https://github.com/Raival-e/File-Explorer\">File Explorer</a>\n\\n- <a href=\"https://github.com/nex3z/FlowLayout\">FlowLayout</a>\n\\n- <a href=\"https://github.com/k3b/intent-intercept\">Intent Intercept</a>\n\\n- <a href=\"https://github.com/YarikSOffice/lingver\">Lingver</a>\n\\n- <a href=\"https://github.com/topjohnwu/Magisk\">Magisk</a>\n\\n- <a href=\"https://github.com/zhanghai/MaterialFiles\">Material Files</a>\n\\n- <a href=\"https://github.com/pluscubed/matlog\">MatLog</a>\n\\n- <a href=\"https://github.com/matrix-org/matrix-android-sdk\">Matrix Android SDK</a>\n\\n- <a href=\"https://github.com/jensstein/oandbackup\">OAndBackup</a>\n\\n- <a href=\"https://github.com/open-keychain/open-keychain\">Open Keychain</a>\n\\n- <a href=\"https://github.com/Aefyr/SAI\">SAI</a>\n\\n- <a href=\"https://github.com/RikkaApps/Shizuku\">Shizuku</a>\n\\n- <a href=\"https://github.com/tuyafeng/Watt\">Watt</a>\n\\nАвтор оригинального логотипа: <a href=\"https://github.com/Atrate\">Atrate</a>. </string>\n    <string name=\"word_wrap\">Перенос слов</string>\n    <string name=\"class_viewer\">Просмотр классов</string>\n    <string name=\"toggle_class_listing\">Переключить список классов</string>\n    <string name=\"found_trackers\">Найденные трекеры:</string>\n    <string name=\"tracker_details\">О трекере</string>\n    <string name=\"tracker_classes\">Классы трекера</string>\n    <string name=\"all_classes\">Все классы</string>\n    <plurals name=\"main_list_date_days\">\n        <item quantity=\"one\"><xliff:g id=\"last_update_date\" example=\"20/10/2020\">%1$s</xliff:g><xliff:g id=\"day_no\" example=\"5\">%2$d</xliff:g> день</item>\n        <item quantity=\"few\"><xliff:g id=\"last_update_date\" example=\"20/10/2020\">%1$s</xliff:g><xliff:g id=\"day_no\" example=\"5\">%2$d</xliff:g> дня</item>\n        <item quantity=\"many\"><xliff:g id=\"last_update_date\" example=\"20/10/2020\">%1$s</xliff:g><xliff:g id=\"day_no\" example=\"5\">%2$d</xliff:g> дней</item>\n        <item quantity=\"other\"><xliff:g id=\"last_update_date\" example=\"20/10/2020\">%1$s</xliff:g><xliff:g id=\"day_no\" example=\"5\">%2$d</xliff:g> дней</item>\n    </plurals>\n    <string name=\"no_shared_libs\">Нет общих библиотек</string>\n    <string name=\"no_tracker_class\">Нет классов трекера</string>\n    <string name=\"app_usage\">Использование приложений</string>\n    <string name=\"usage_weekly\">Еженедельно</string>\n    <string name=\"usage_today\">Сегодня</string>\n    <string name=\"usage_7_days\">Последние 7 дней</string>\n    <plurals name=\"usage_months\">\n        <item quantity=\"one\">%1$d месяц</item>\n        <item quantity=\"few\">%1$d месяца</item>\n        <item quantity=\"many\">%1$d месяцев</item>\n        <item quantity=\"other\">%1$d месяцев</item>\n    </plurals>\n    <plurals name=\"usage_days\">\n        <item quantity=\"one\">%1$d день</item>\n        <item quantity=\"few\">%1$d дня</item>\n        <item quantity=\"many\">%1$d дней</item>\n        <item quantity=\"other\">%1$d дней</item>\n    </plurals>\n    <plurals name=\"usage_hours\">\n        <item quantity=\"one\">%1$d час</item>\n        <item quantity=\"few\">%1$d часа</item>\n        <item quantity=\"many\">%1$d часов</item>\n        <item quantity=\"other\">%1$d часов</item>\n    </plurals>\n    <string name=\"usage_less_than_a_minute\">Меньше минуты</string>\n    <string name=\"go_back\">Вернуться</string>\n    <string name=\"go\">Разрешить</string>\n    <string name=\"grant_usage_access\">Предоставьте доступ к истории использования</string>\n    <string name=\"grant_usage_acess_message\">Используется для отображения информации об использовании приложений.</string>\n    <string name=\"share_apk\">Поделиться APK</string>\n    <string name=\"failed_to_extract_apk_file\">Не удалось извлечь файл APK</string>\n    <string name=\"menu_remove_rules\">Удалить правила</string>\n    <string name=\"menu_apply_rules\">Применить правила</string>\n    <string name=\"search\">Поиск</string>\n    <string name=\"dev_protected_data_dir\">Каталог данных, защищенных устройством</string>\n    <string name=\"native_library_dir\">Нативная директория библиотеки JNI</string>\n    <string name=\"process_name\">Название процесса</string>\n    <string name=\"no_code\">Нет кода</string>\n    <string name=\"requested_large_heap\">Большая куча</string>\n    <string name=\"updated_app\">Обновлено</string>\n    <string name=\"debuggable\">Отлаживаемое</string>\n    <string name=\"test_only\">Только тест</string>\n    <string name=\"shared_prefs\">Общие настройки</string>\n    <string name=\"databases\">Базы данных</string>\n    <string name=\"save\">Сохранить</string>\n    <string name=\"discard\">Отклонить</string>\n    <string name=\"delete\">Удалить</string>\n    <string name=\"deleted_successfully\">Удалено</string>\n    <string name=\"deletion_failed\">Сбой удаления</string>\n    <string name=\"saved_successfully\">Сохранено</string>\n    <string name=\"saving_failed\">Ошибка сохранения, повторите попытку.</string>\n    <string name=\"string_value\">Строковое значение</string>\n    <string name=\"long_integer_value\">Длинное целое значение</string>\n    <string name=\"integer_value\">Целое значение</string>\n    <string name=\"decimal_value\">Десятичное значение</string>\n    <string name=\"boolean_value\">Логическое значение</string>\n    <string name=\"key_name\">Название ключа</string>\n    <string name=\"select_type\">Выберите тип</string>\n    <string name=\"add_item\">Добавить элемент</string>\n    <string name=\"done\">Готово</string>\n    <string name=\"type_boolean\">Верно/неверно</string>\n    <string name=\"type_float\">Десятичное число</string>\n    <string name=\"type_int\">Целое число</string>\n    <string name=\"type_long\">Длинное целое число</string>\n    <string name=\"type_string\">Символы</string>\n    <string name=\"error_evaluating_input\">Не удалось оценить ввод</string>\n    <string name=\"key_name_cannot_be_null\">Название ключа не может быть пустым</string>\n    <string name=\"disabled_app\">Отключено</string>\n    <string name=\"no_usage_in_this_time_range\">Нет статистики использования в этом временном диапазоне</string>\n    <string name=\"no_content\">Нет содержания</string>\n    <string name=\"view_in_settings\">Показать в настройках</string>\n    <string name=\"uninstall_app_message\">Вы хотите удалить это приложение?</string>\n    <string name=\"failed_to_uninstall\">Не удалось удалить <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g>.</string>\n    <string name=\"uninstalled_successfully\"><xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g> было удалено.</string>\n    <string name=\"uninstall_system_app_message\">Это системное приложение. Вы уверены, что хотите удалить его?</string>\n    <string name=\"stopped\">Остановлено</string>\n    <string name=\"disable\">Отключить</string>\n    <string name=\"enable\">Включить</string>\n    <string name=\"force_stop\">Остановить принудительно</string>\n    <string name=\"failed_to_stop\">Не удалось остановить <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g>.</string>\n    <string name=\"storage_and_cache\">Хранилище и кэш</string>\n    <string name=\"total_size\">Всего</string>\n    <string name=\"app_size\">Приложение</string>\n    <string name=\"app_ops\">Операции приложения</string>\n    <string name=\"no_app_ops\">Нет операций приложения</string>\n    <string name=\"failed_to_enable_op\">Не удалось включить запрошенную операцию приложения</string>\n    <string name=\"failed_to_disable_op\">Не удалось отключить запрошенную операцию приложения</string>\n    <string name=\"rules_not_applied\">Правила не применены</string>\n    <string name=\"str_logo\">Логотип</string>\n    <string name=\"pref_global_blocking_enabled\">Мгновенная блокировка компонентов</string>\n    <string name=\"pref_global_blocking_enabled_msg\">Позволяет вам блокировать любой компонент любого приложения без явного включения блокировки для приложения.</string>\n    <string name=\"usage_access\">Доступ к истории использования</string>\n    <string name=\"app_settings\">Настройки</string>\n    <string name=\"usage_yesterday\">Вчера</string>\n    <string name=\"exodus_link\">Ссылка на \\u03b5xodus</string>\n    <string name=\"sort_by_blocked_components\">Сначала заблокированные</string>\n    <string name=\"external_data_dir\">Внешний каталог данных</string>\n    <string name=\"external_multiple_data_dir\">Внешний каталог данных <xliff:g id=\"dir_no\" example=\"1\">%1$d</xliff:g></string>\n    <plurals name=\"no_of_times_opened\">\n        <item quantity=\"one\">%1$d раз</item>\n        <item quantity=\"few\">%1$d раза</item>\n        <item quantity=\"many\">%1$d раз</item>\n        <item quantity=\"other\">%1$d раз</item>\n    </plurals>\n    <string name=\"sort_by_last_used\">Последнее использование</string>\n    <string name=\"sort_by_screen_time\">Время использования</string>\n    <string name=\"sort_by_times_opened\">Количество запусков</string>\n    <string name=\"sort_by_mobile_data\">Мобильные данные</string>\n    <string name=\"pref_import_export_blocking_rules\">Импорт/экспорт правил блокировки</string>\n    <string name=\"pref_import_export_blocking_rules_msg\">Импорт/экспорт правил, импорт внешних правил из Watt или Blocker.</string>\n    <string name=\"pref_import_watt\">Импорт из Watt</string>\n    <string name=\"pref_import_blocker\">Импорт из Blocker</string>\n    <string name=\"the_import_was_successful\">Импортировано</string>\n    <string name=\"the_export_was_successful\">Экспортировано</string>\n    <plurals name=\"failed_to_import_files\">\n        <item quantity=\"one\">Ошибка импортирования %1$d файла.</item>\n        <item quantity=\"few\">Ошибка импортирования %1$d файлов.</item>\n        <item quantity=\"many\">Ошибка импортирования %1$d файлов.</item>\n        <item quantity=\"other\">Ошибка импортирования %1$d файлов.</item>\n    </plurals>\n    <string name=\"apk_updater\">APK Updater</string>\n    <string name=\"running_apps\">Работающие приложения</string>\n    <string name=\"kill_process\">Закрыть</string>\n    <string name=\"disable_background_run\">Предотвращение работы в фоне</string>\n    <string name=\"pid_and_ppid\">Идентификатор процесса: %1$d, идентификатор родительского процесса: %2$d</string>\n    <string name=\"memory_virtual_memory\">Память: %1$s, виртуальная память: %2$s</string>\n    <string name=\"user_and_uid\">Пользователь: <xliff:g id=\"user_name\" example=\"root\">%1$s</xliff:g> (<xliff:g id=\"user_id\" example=\"0\">%2$d</xliff:g>)</string>\n    <string name=\"clear_data\">Очистить данные</string>\n    <string name=\"backup_restore\">Резервное копирование/восстановление</string>\n    <string name=\"disable_background\">Предотвратить фоновую работу</string>\n    <string name=\"export_blocking_rules\">Экспортировать правила блокировки</string>\n    <plurals name=\"alert_failed_to_clear_data\">\n        <item quantity=\"one\">Не удалось очистить данные %1$d приложения</item>\n        <item quantity=\"few\">Не удалось очистить данные %1$d приложений</item>\n        <item quantity=\"many\">Не удалось очистить данные %1$d приложений</item>\n        <item quantity=\"other\">Не удалось очистить данные %1$d приложений</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_uninstall\">\n        <item quantity=\"one\">Не удалось удалить %1$d приложение</item>\n        <item quantity=\"few\">Не удалось удалить %1$d приложения</item>\n        <item quantity=\"many\">Не удалось удалить %1$d приложений</item>\n        <item quantity=\"other\">Не удалось удалить %1$d приложений</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_disable_background\">\n        <item quantity=\"one\">Не удалось предотвратить работу в фоне для %1$d приложения</item>\n        <item quantity=\"few\">Не удалось предотвратить работу в фоне для %1$d приложений</item>\n        <item quantity=\"many\">Не удалось предотвратить работу в фоне для %1$d приложений</item>\n        <item quantity=\"other\">Не удалось предотвратить работу в фоне для %1$d приложений</item>\n    </plurals>\n    <string name=\"the_operation_was_successful\">Готово</string>\n    <plurals name=\"alert_failed_to_force_stop\">\n        <item quantity=\"one\">Не удалось принудительно остановить %1$d приложение</item>\n        <item quantity=\"few\">Не удалось принудительно остановить %1$d приложения</item>\n        <item quantity=\"many\">Не удалось принудительно остановить %1$d приложений</item>\n        <item quantity=\"other\">Не удалось принудительно остановить %1$d приложений</item>\n    </plurals>\n    <string name=\"toggle_kill_for_system_apps\">Вкл/выкл закрытие системных приложений</string>\n    <string name=\"permission_name\">Имя разрешения</string>\n    <string name=\"mode\">Режим</string>\n    <string name=\"running\">Работающие</string>\n    <string name=\"duration\">Длительность</string>\n    <string name=\"accept_time\">Время подтверждения</string>\n    <string name=\"reject_time\">Время отклонения</string>\n    <string name=\"ago\">назад</string>\n    <string name=\"pref_import\">Импорт</string>\n    <string name=\"pref_export\">Экспорт</string>\n    <string name=\"import_options\">Параметры импорта</string>\n    <string name=\"export_options\">Параметры экспорта</string>\n    <string name=\"import_failed\">Не удалось импортировать!</string>\n    <string name=\"export_failed\">Не удалось экспортировать!</string>\n    <string name=\"keyboard_type\">Тип клавиатуры</string>\n    <string name=\"navigation\">Навигация</string>\n    <string name=\"touchscreen\">Сенсорный экран</string>\n    <string name=\"pref_export_msg\">Экспортировать правила блокировки, настроенные в App Manager на внешнее хранилище.</string>\n    <string name=\"pref_import_msg\">Импортировать ранее экспортированные правила блокировки из App Manager.</string>\n    <string name=\"pref_import_watt_msg\">Импортировать правила блокировки из Watt, каждый файл содержит правила для одного названного пакета как <tt>packagename.xml</tt> и т. д.</string>\n    <string name=\"pref_import_blocker_msg\">Импортировать правила блокировки из Blocker, каждый файл содержит правила для одного пакета.</string>\n    <string name=\"pref_app_theme\">Тема приложения</string>\n    <string name=\"follow_system\">Согласно системным настройкам</string>\n    <string name=\"battery_mode\">Режим батареи</string>\n    <string name=\"day\">Светлая тема</string>\n    <string name=\"night\">Темная тема</string>\n    <string name=\"select_theme\">Тема</string>\n    <string name=\"apply\">Применить</string>\n    <string name=\"pref_about_msg\">Версия App Manager, лицензия, авторы и т. д.</string>\n    <string name=\"version\">Версия</string>\n    <string name=\"sort_by_wifi_data\">Данные Wi-Fi</string>\n    <string name=\"block_trackers\">Блокировать трекеры</string>\n    <string name=\"sort_by_component_name\">Название компонента</string>\n    <string name=\"reset_to_default\">Сброс по умолчанию</string>\n    <string name=\"deny_dangerous_app_ops\">Отклонить опасные операции приложения</string>\n    <string name=\"sort_by_app_ops_names\">Имена операций приложения</string>\n    <string name=\"sort_by_denied_app_ops\">Сначала отклоненные</string>\n    <string name=\"sort_by_app_ops_values\">Значение операций приложения</string>\n    <string name=\"sort_by_permission_names\">Имя разрешения</string>\n    <string name=\"sort_by_dangerous_permissions\">Сначала опасные</string>\n    <string name=\"sort_by_denied_permissions\">Сначала отклоненные</string>\n    <string name=\"deny_dangerous_permissions\">Отклонить опасные разрешения</string>\n    <string name=\"sort_by_tracker_components\">Сначала трекеры</string>\n    <string name=\"unknown_op\">Неизвестная операция</string>\n    <plurals name=\"alert_failed_to_disable_trackers\">\n        <item quantity=\"one\">Не удалось отключить трекеры в %1$d приложении</item>\n        <item quantity=\"few\">Не удалось отключить трекеры в %1$d приложениях</item>\n        <item quantity=\"many\">Не удалось отключить трекеры в %1$d приложениях</item>\n        <item quantity=\"other\">Не удалось отключить трекеры в %1$d приложениях</item>\n    </plurals>\n    <string name=\"failed_to_grant_permission\">Не удалось предоставить разрешение</string>\n    <string name=\"failed_to_revoke_permission\">Не удалось отозвать разрешение</string>\n    <string name=\"failed_to_reset_app_ops\">Не удалось сбросить операции приложения</string>\n    <string name=\"failed_to_deny_dangerous_perms\">Не удалось запретить все опасные разрешения</string>\n    <string name=\"failed_to_deny_dangerous_app_ops\">Не удалось запретить все опасные операции приложения</string>\n    <string name=\"launch_app\">Запустить</string>\n    <string name=\"never_ask\">Никогда не спрашивать</string>\n    <string name=\"one_click_ops\">Операции в один клик</string>\n    <string name=\"changelog\">Список изменений</string>\n    <string name=\"external_apk_no_app_op\">Внешний APK не имеет операций с приложением</string>\n    <string name=\"manifest_viewer\">Просмотр манифеста</string>\n    <plurals name=\"no_of_trackers\">\n        <item quantity=\"one\">%1$d трекер</item>\n        <item quantity=\"few\">%1$d трекера</item>\n        <item quantity=\"many\">%1$d трекеров</item>\n        <item quantity=\"other\">%1$d трекеров</item>\n    </plurals>\n    <string name=\"install\">Установить</string>\n    <string name=\"update\">Обновить</string>\n    <string name=\"source_code\">Исходный код</string>\n    <string name=\"pref_import_existing\">Импорт существующих правил</string>\n    <string name=\"pref_import_existing_msg\">Добавить компоненты, отключенные другими приложениями, в App Manager. Будьте осторожны при использовании этого инструмента, так как может быть много ложных срабатываний. Выбирайте только те приложения, в которых вы уверены.</string>\n    <string name=\"clear_cache\">Очистить кэш</string>\n    <string name=\"block_unblock_trackers_description\">Блокировать или разблокировать рекламу и компоненты трекеров во всех установленных приложениях</string>\n    <string name=\"block_components_dots\">Блокировать компоненты…</string>\n    <string name=\"deny_app_ops_description\">Установите режим для операций приложения, определяемых постоянными значениями, например <tt>63</tt> или <tt>RUN_IN_BACKGROUND</tt></string>\n    <string name=\"clear_data_from_uninstalled_apps\">Очистить данные удаленных приложений</string>\n    <string name=\"clear_data_from_uninstalled_apps_description\">Очистить данные приложений, которые были удалены с помощью флага <tt>DONT_DELETE_DATA</tt></string>\n    <string name=\"clear_app_cache\">Очистить кэш приложения</string>\n    <string name=\"clear_app_cache_description\">Очистить кэш всех приложений</string>\n    <string name=\"no_tracker_found\">Трекеров не найдено</string>\n    <string name=\"failed_packages\">Сбойные пакеты</string>\n    <string name=\"input_signatures\">Ввод подписей</string>\n    <string name=\"input_signatures_description\">Введите подписи с пробелами, например <tt>com.facebook org.app2 com.app3</tt> и т. д.</string>\n    <string name=\"filtered_packages\">Отфильтрованные пакеты</string>\n    <string name=\"input_app_ops\">Ввод операций приложения</string>\n    <string name=\"input_app_ops_description\">Введите имена операций приложения и/или константы с пробелами, например <tt>WAKE_LOCK 63 72 CAMERA</tt> и т.д.</string>\n    <string name=\"only_works_in_root_or_adb_mode\">Доступно только в режиме root или ADB</string>\n    <string name=\"failed_to_parse_some_numbers\">Не удалось разобрать некоторые числа</string>\n    <plurals name=\"no_of_splits\">\n        <item quantity=\"one\">%1$d часть</item>\n        <item quantity=\"few\">%1$d части</item>\n        <item quantity=\"many\">%1$d частей</item>\n        <item quantity=\"other\">%1$d частей</item>\n    </plurals>\n    <string name=\"termux\">Termux</string>\n    <string name=\"package_name_is_installed_successfully\"><xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g> установлено</string>\n    <string name=\"filter\">Фильтр</string>\n    <string name=\"filter_user_apps\">Пользовательские приложения</string>\n    <string name=\"filter_system_apps\">Системные приложения</string>\n    <string name=\"filter_apps_with_rules\">С правилами</string>\n    <string name=\"select_all\">Выбрать все</string>\n    <string name=\"installed_version\">Установленная версия</string>\n    <string name=\"trackers\">Трекеры</string>\n    <string name=\"components\">Компоненты</string>\n    <string name=\"features\">Функции</string>\n    <string name=\"whats_new\">Что нового</string>\n    <string name=\"blocking_rules\">Правила блокировки</string>\n    <string name=\"external_data\">Внешние данные</string>\n    <string name=\"data\">Данные</string>\n    <string name=\"backup\">Бекап</string>\n    <string name=\"restore\">Восстановление</string>\n    <string name=\"delete_backup\">Удалить резервную копию</string>\n    <string name=\"backup_options\">Параметры резервного копирования</string>\n    <plurals name=\"failed_to_backup_some_apk_files\">\n        <item quantity=\"one\">Не удалось создать резервную копию %1$d файла APK</item>\n        <item quantity=\"few\">Не удалось создать резервную копию %1$d файлов APK</item>\n        <item quantity=\"many\">Не удалось создать резервную копию %1$d файлов APK</item>\n        <item quantity=\"other\">Не удалось создать резервную копию %1$d файлов APK</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_backup\">\n        <item quantity=\"one\">Не удалось создать резервную копию %1$d приложения</item>\n        <item quantity=\"few\">Не удалось создать резервную копию %1$d приложений</item>\n        <item quantity=\"many\">Не удалось создать резервную копию %1$d приложений</item>\n        <item quantity=\"other\">Не удалось создать резервную копию %1$d приложений</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_restore\">\n        <item quantity=\"one\">Не удалось восстановить резервную копию %1$d приложения</item>\n        <item quantity=\"few\">Не удалось восстановить резервную копию %1$d приложений</item>\n        <item quantity=\"many\">Не удалось восстановить резервную копию %1$d приложений</item>\n        <item quantity=\"other\">Не удалось восстановить резервную копию %1$d приложений</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_delete_backup\">\n        <item quantity=\"one\">Не удалось удалить %1$d резервную копию</item>\n        <item quantity=\"few\">Не удалось удалить %1$d резервные копии</item>\n        <item quantity=\"many\">Не удалось удалить %1$d резервных копий</item>\n        <item quantity=\"other\">Не удалось удалить %1$d резервных копий</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_unblock_trackers\">\n        <item quantity=\"one\">Не удалось разблокировать трекеры в %1$d приложении</item>\n        <item quantity=\"few\">Не удалось разблокировать трекеры в %1$d приложениях</item>\n        <item quantity=\"many\">Не удалось разблокировать трекеры в %1$d приложениях</item>\n        <item quantity=\"other\">Не удалось разблокировать трекеры в %1$d приложениях</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_block_components\">\n        <item quantity=\"one\">Не удалось заблокировать компоненты %1$d приложения</item>\n        <item quantity=\"few\">Не удалось заблокировать компоненты %1$d приложений</item>\n        <item quantity=\"many\">Не удалось заблокировать компоненты %1$d приложений</item>\n        <item quantity=\"other\">Не удалось заблокировать компоненты %1$d приложений</item>\n    </plurals>\n    <string name=\"apply_to_system_apps\">Применить к системным приложениям</string>\n    <string name=\"apply_to_system_apps_question\">Применить и к системным приложениям\\? Если не уверены, выберите \\\"Нет\\\".</string>\n    <string name=\"no\">Нет</string>\n    <string name=\"yes\">Да</string>\n    <string name=\"skip_signature_checks\">Пропустить проверку подписи</string>\n    <string name=\"clear_data_message\">Вы действительно хотите очистить данные этого приложения?</string>\n    <string name=\"clear\">Очистить</string>\n    <string name=\"block\">Заблокировать</string>\n    <string name=\"unblock\">Разблокировать</string>\n    <string name=\"block_unblock_trackers\">Блокировать/разблокировать трекеры</string>\n    <string name=\"no_matching_package_found\">Не удалось найти такое приложение</string>\n    <string name=\"export_icon\">Извлечь значок</string>\n    <string name=\"open_in_termux\">Открыть в Termux</string>\n    <string name=\"run_in_termux\">Запустить в Termux</string>\n    <string name=\"website\">Веб-сайт</string>\n    <string name=\"pref_remove_all_rules\">Удаление всех правил</string>\n    <string name=\"pref_remove_all_rules_msg\">Разрешения будут предоставлены, операциям приложения и компонентам вернутся значения по умолчанию.</string>\n    <string name=\"are_you_sure\">Вы уверены\\?</string>\n    <string name=\"filter_apps_with_activities\">С активити</string>\n    <string name=\"toggle_default_app_ops\">Переключение операций приложения по умолчанию</string>\n    <string name=\"installer_error_aborted\">Установка не удалась, потому что она была отменена, или сеанс был неожиданно закрыт</string>\n    <string name=\"installer_error_blocked_device\">устройством</string>\n    <string name=\"installer_error_blocked\">Установка заблокирована <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g></string>\n    <string name=\"installer_error_conflict\">Не удалось установить приложение, так как имя пакета используется</string>\n    <string name=\"installer_error_incompatible\">Приложение несовместимо с этим устройством</string>\n    <string name=\"installer_error_bad_apks\">Выбраны недопустимые файлы APK</string>\n    <string name=\"installer_error_storage\">Недостаточно места для установки приложения</string>\n    <string name=\"installer_error_generic\">Ошибка установки</string>\n    <string name=\"installer_error_lidl_rom\">Ваша прошивка несовместима с без-root установщиком .</string>\n    <string name=\"failed_to_fetch_package_info\">Не удалось получить информацию о пакете</string>\n    <string name=\"batch_ops\">Пакетные операции</string>\n    <string name=\"operation_running\">Выполнение операции…</string>\n    <string name=\"full_stop_tap_to_see_details\">. Нажмите, чтобы увидеть детали.</string>\n    <string name=\"try_again\">Попробуйте снова</string>\n    <string name=\"install_app_message\">Вы хотите установить это приложение?</string>\n    <string name=\"reinstall\">Переустановить</string>\n    <string name=\"unblock_trackers\">Разблокировать трекеры</string>\n    <string name=\"package_installer\">Установщик пакетов</string>\n    <string name=\"install_in_progress\">Установка…</string>\n    <string name=\"installer_error_security\">Нет доступа к файлам APK</string>\n    <string name=\"installer_error_session_create\">Не удалось создать сеанс установщика</string>\n    <string name=\"installer_error_session_write\">Не удалось записать в сеанс установщика</string>\n    <string name=\"installer_error_session_commit\">Не удалось зафиксировать файлы APK</string>\n    <string name=\"installer_error_session_abandon\">Не удалось прервать сеанс установщика</string>\n    <string name=\"backup_apk_files\">Файлы APK</string>\n    <string name=\"backup_obb_media\">OBB и Медиа</string>\n    <string name=\"failed_to_extract_obb_files\">Не удалось извлечь файлы OBB</string>\n    <string name=\"obb_files_extracted_successfully\">Файлы OBB извлечены</string>\n    <string name=\"backup_multiple\">Создание нескольких резервных копий</string>\n    <string name=\"backup_all_users\">Все пользователи</string>\n    <string name=\"pref_app_language\">Язык</string>\n    <string name=\"auto\">Авто</string>\n    <string name=\"choose_language\">Изменить язык</string>\n    <string name=\"launch_mode_single_top\">Единственный сверху</string>\n    <string name=\"touchscreen_finger\">Палец</string>\n    <string name=\"touchscreen_stylus\">Стилус</string>\n    <string name=\"touchscreen_no_touch\">Без касаний</string>\n    <string name=\"navigation_wheel\">Колесо</string>\n    <string name=\"navigation_trackball\">Трекбол</string>\n    <string name=\"navigation_dial_pad\">Циферблат</string>\n    <string name=\"navigation_no_nav\">Нет навигации</string>\n    <string name=\"keyboard_12_keys\">12 клавиш</string>\n    <string name=\"keyboard_qwerty\">QWERTY</string>\n    <string name=\"keyboard_no_keys\">Без клавиш</string>\n    <string name=\"_undefined\">Неопределённый</string>\n    <string name=\"required\">Требуется</string>\n    <string name=\"orientation_user_portrait\">Пользовательская портретная</string>\n    <string name=\"orientation_user_landscape\">Пользовательская альбомная</string>\n    <string name=\"orientation_sensor\">По датчику</string>\n    <string name=\"orientation_sensor_portrait\">Портретная по датчику</string>\n    <string name=\"orientation_sensor_landscape\">Альбомная по датчику</string>\n    <string name=\"orientation_user\">Пользовательская</string>\n    <string name=\"orientation_reverse_landscape\">Перевёрнутая альбомная</string>\n    <string name=\"orientation_reverse_portrait\">Перевёрнутый портрет</string>\n    <string name=\"orientation_portrait\">Портретная</string>\n    <string name=\"orientation_full_sensor\">Полностью по датчику</string>\n    <string name=\"orientation_no_sensor\">Без датчика</string>\n    <string name=\"orientation_landscape\">Альбомная</string>\n    <string name=\"orientation_full_user\">Полностью пользовательская</string>\n    <string name=\"orientation_locked\">Заблокированая</string>\n    <string name=\"orientation_behind\">Позади</string>\n    <string name=\"orientation_unspecified\">Неопределенная</string>\n    <string name=\"launch_mode_single_task\">Одна задача</string>\n    <string name=\"launch_mode_single_instance\">Единичный экземпляр</string>\n    <string name=\"launch_mode_multiple\">Несколько</string>\n    <string name=\"locale_split_for_base_apk\"><xliff:g id=\"split_name\" example=\"English\">%1$s</xliff:g> язык для базового APK</string>\n    <string name=\"locale_split_for_feature\"><xliff:g id=\"split_name\" example=\"English\">%1$s</xliff:g> язык для <xliff:g id=\"feature_name\" example=\"Visualizer\">%2$s</xliff:g></string>\n    <string name=\"abi_split_for_base_apk\"><xliff:g id=\"split_name\" example=\"arm64_v8a\">%1$s</xliff:g> код для базового APK</string>\n    <string name=\"abi_split_for_feature\"><xliff:g id=\"split_name\" example=\"arm64_v8a\">%1$s</xliff:g> код для <xliff:g id=\"feature_name\" example=\"Visualizer\">%2$s</xliff:g></string>\n    <string name=\"density_split_for_base_apk\"><xliff:g id=\"split_name\" example=\"xxdpi\">%1$s</xliff:g> (<xliff:g id=\"dpi_no\" example=\"480\">%2$d</xliff:g> DPI) ресурсы для базового APK</string>\n    <string name=\"density_split_for_feature\"><xliff:g id=\"split_name\" example=\"xxdpi\">%1$s</xliff:g> (<xliff:g id=\"dpi_no\" example=\"480\">%2$d</xliff:g> DPI) ресурсы для функции <xliff:g id=\"feature_name\" example=\"Visualizer\">%3$s</xliff:g></string>\n    <string name=\"unknown_split_for_base_apk\"><xliff:g id=\"split_name\" example=\"some_split\">%1$s</xliff:g> для базового APK</string>\n    <string name=\"unknown_split_for_feature\"><xliff:g id=\"split_name\" example=\"some_split\">%1$s</xliff:g> для функции <xliff:g id=\"feature_name\" example=\"Visualizer\">%2$s</xliff:g></string>\n    <string name=\"split_feature_name\">Функции: <xliff:g id=\"feature_name\" example=\"Visualizer\">%1$s</xliff:g></string>\n    <string name=\"base_apk\">Базовый APK</string>\n    <string name=\"routine_ops\">Повторяющиеся операции</string>\n    <string name=\"no_profiles\">Нет профилей</string>\n    <string name=\"open_pgp_provider\">Поставщик OpenPGP</string>\n    <string name=\"input_backup_name_description\">Имя резервной копии не должно начинаться с цифры и содержать пробелы. Оставьте это поле пустым, если хотите использовать текущую дату и время.</string>\n    <string name=\"downgrade\">Понизить</string>\n    <string name=\"process_state_with_extra\">Состояние: <xliff:g id=\"process_state\" example=\"Sleeping\">%1$s</xliff:g> (<xliff:g id=\"state_extra\" example=\"High priority\">%2$s</xliff:g>)</string>\n    <string name=\"process_state\">Состояние: <xliff:g id=\"process_state\" example=\"Sleeping\">%1$s</xliff:g></string>\n    <string name=\"state_multithreaded\">Многопоточный</string>\n    <string name=\"state_unknown\">Неизвестный</string>\n    <string name=\"state_idle\">Простой</string>\n    <string name=\"state_zombie\">Зомби</string>\n    <string name=\"state_dead\">Мёртвый</string>\n    <string name=\"state_sleeping\">Спящий</string>\n    <string name=\"apply_now\">Применить сейчас…</string>\n    <string name=\"profiles\">Профили</string>\n    <string name=\"cancel\">Отмена</string>\n    <string name=\"ok\">ОК</string>\n    <string name=\"input_backup_name\">Имя резервной копии</string>\n    <string name=\"state_foreground\">Передний план</string>\n    <string name=\"state_low_priority\">Низкий приоритет</string>\n    <string name=\"state_high_priority\">Высокий приоритет</string>\n    <string name=\"sort_by_memory_usage\">Использование памяти</string>\n    <string name=\"sort_by_apps_first\">Приложения в первую очередь</string>\n    <string name=\"sort_by_process_name\">Имя процесса</string>\n    <string name=\"sort_by_process_id\">ID процесса</string>\n    <string name=\"filter_apps\">Приложения</string>\n    <string name=\"no_apps\">Нет приложений</string>\n    <string name=\"apps\">Приложения</string>\n    <plurals name=\"backup_exists_are_you_sure\">\n        <item quantity=\"one\">Резервная копия существует. Вы уверены\\?</item>\n        <item quantity=\"few\">Резервная копия существует для более чем одного приложения. Вы уверены\\?</item>\n        <item quantity=\"many\">Резервная копия существует для более чем одного приложения. Вы уверены\\?</item>\n        <item quantity=\"other\">Резервная копия существует для более чем одного приложения. Вы уверены\\?</item>\n    </plurals>\n    <string name=\"changes_not_saved\">Изменения не сохранены</string>\n    <string name=\"rules\">Правила</string>\n    <string name=\"pref_compression_method\">Метод сжатия</string>\n    <string name=\"pref_backup_flags_msg\">Добавление предустановки для параметров резервного копирования избавляет от необходимости выбора флагов при каждом резервном копировании/восстановлении.</string>\n    <string name=\"state_trace_stop\">Остановить отслеживание</string>\n    <string name=\"confirm_installation\">Подтвердить установку</string>\n    <string name=\"allow_open_pgp_operation\">Нажмите, чтобы разрешить AM использовать OpenPGP</string>\n    <string name=\"uninstall_updates\">Удалить обновления</string>\n    <string name=\"update_uninstalled_successfully\">Обновления <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g> были удалены.</string>\n    <string name=\"failed_to_uninstall_updates\">Не удалось удалить обновления <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g>.</string>\n    <string name=\"filter_apps_with_backups\">С резервными копиями</string>\n    <string name=\"issued_date\">Дата выпуска</string>\n    <string name=\"expiry_date\">Срок действия</string>\n    <string name=\"type\">Тип</string>\n    <string name=\"validity\">Срок действия</string>\n    <string name=\"valid\">Действительный</string>\n    <string name=\"expired\">Истёк</string>\n    <string name=\"not_yet_valid\">Ещё недействительный</string>\n    <string name=\"serial_no\">Серийный номер</string>\n    <string name=\"checksums\">Контрольные суммы</string>\n    <string name=\"app_signing_signature\">Подпись</string>\n    <string name=\"algorithm\">Алгоритм</string>\n    <string name=\"public_key\">Публичный ключ</string>\n    <string name=\"format\">Формат</string>\n    <string name=\"critical_exts\">Критические расширения</string>\n    <string name=\"non_critical_exts\">Некритические расширения</string>\n    <string name=\"other\">Другое</string>\n    <string name=\"state_locked_memory\">Заблокированная память</string>\n    <string name=\"usage_access_not_supported\">Не удалось запросить разрешение на доступ к истории использования, так как соответствующая страница настроек не существует.</string>\n    <string name=\"do_you_want_to_uninstall_and_install\">Вы хотите удалить и снова установить приложение\\?</string>\n    <string name=\"app_signing_signature_mismatch_for_system_apps\">Не удалось установить приложение, поскольку системное приложение с другой подписью имеет такое же имя пакета.</string>\n    <string name=\"app_data_will_be_lost\">Существующие данные будут потеряны.</string>\n    <string name=\"only_install\">Только установка</string>\n    <string name=\"app_signing_install_without_data_loss\">Если у вас отключена проверка подписи, вы можете использовать параметр <b>«Только установка»</b>, чтобы установить приложение без потери данных.</string>\n    <string name=\"sort_by_backup\">Сначала резервные копии</string>\n    <string name=\"state_session_leader\">Лидер сессии</string>\n    <string name=\"sys_config\">Конфигурация системы</string>\n    <string name=\"rsa_modulus\">Модуль</string>\n    <string name=\"rsa_exponent\">Экспонента</string>\n    <string name=\"issuer\">Издатель</string>\n    <string name=\"subject\">Тема</string>\n    <string name=\"copy\">Копировать</string>\n    <string name=\"view_missing_signatures\">Нажмите, чтобы просмотреть или отправить подписи, которых еще нет в базе библиотек App Manager.</string>\n    <string name=\"tap_to_see_details\">Нажмите, чтобы увидеть подробности</string>\n    <string name=\"lib_details\">Подробности библиотеки</string>\n    <string name=\"no_libs\">Нет библиотек</string>\n    <string name=\"scanner\">Сканер</string>\n    <plurals name=\"missing_signatures\">\n        <item quantity=\"one\">%1$d подпись отсутствует</item>\n        <item quantity=\"few\">%1$d подписи отсутствует</item>\n        <item quantity=\"many\">%1$d подписей отсутствует</item>\n        <item quantity=\"other\">%1$d подписей отсутствует</item>\n    </plurals>\n    <plurals name=\"libraries\">\n        <item quantity=\"one\">%1$d библиотека</item>\n        <item quantity=\"few\">%1$d библиотеки</item>\n        <item quantity=\"many\">%1$d библиотек</item>\n        <item quantity=\"other\">%1$d библиотек</item>\n    </plurals>\n    <plurals name=\"classes\">\n        <item quantity=\"one\">%1$d класс</item>\n        <item quantity=\"few\">%1$d класса</item>\n        <item quantity=\"many\">%1$d классов</item>\n        <item quantity=\"other\">%1$d классов</item>\n    </plurals>\n    <plurals name=\"other_trackers_and_classes\">\n        <item quantity=\"one\"><xliff:g id=\"tracker_no\" example=\"8\">%1$d</xliff:g> трекер с <xliff:g id=\"class_no\" example=\"50\">%2$d</xliff:g> классами</item>\n        <item quantity=\"few\"><xliff:g id=\"tracker_no\" example=\"8\">%1$d</xliff:g> трекера с <xliff:g id=\"class_no\" example=\"50\">%2$d</xliff:g> классами</item>\n        <item quantity=\"many\"><xliff:g id=\"tracker_no\" example=\"8\">%1$d</xliff:g> трекеров с <xliff:g id=\"class_no\" example=\"50\">%2$d</xliff:g> классами</item>\n        <item quantity=\"other\"><xliff:g id=\"tracker_no\" example=\"8\">%1$d</xliff:g> трекеров с <xliff:g id=\"class_no\" example=\"50\">%2$d</xliff:g> классами</item>\n    </plurals>\n    <plurals name=\"two_trackers_and_classes\">\n        <item quantity=\"one\">2 трекера с <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g> классом</item>\n        <item quantity=\"few\">2 трекера с <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g> классами</item>\n        <item quantity=\"many\">2 трекера с <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g> классами</item>\n        <item quantity=\"other\">2 трекера с <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g> классами</item>\n    </plurals>\n    <plurals name=\"tracker_and_classes\">\n        <item quantity=\"one\">1 трекер с <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g> классом</item>\n        <item quantity=\"few\">1 трекер с <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g> классами</item>\n        <item quantity=\"many\">1 трекер с <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g> классами</item>\n        <item quantity=\"other\">1 трекер с <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g> классами</item>\n    </plurals>\n    <string name=\"tap_to_submit_crash_report\">Нажмите, чтобы отправить отчет о сбое.</string>\n    <string name=\"send_crash_report\">Отправить отчет о сбое</string>\n    <string name=\"select_apk\">Выбрать APK</string>\n    <string name=\"systemless_app\">Внесистемное приложение</string>\n    <string name=\"duplicate\">Дублировать</string>\n    <string name=\"new_profile\">Новый профиль</string>\n    <string name=\"input_profile_name_description\">Название профиля не может содержать пробелов.</string>\n    <string name=\"input_profile_name\">Название профиля</string>\n    <string name=\"in_progress\">В процессе</string>\n    <string name=\"conversion_failed\">Преобразование не удалось.</string>\n    <string name=\"am_crashed\">Произошло падение App Manager</string>\n    <string name=\"filter_running_apps\">Работающие приложения</string>\n    <string name=\"dsa_affine_y\">Аффина координаты y</string>\n    <string name=\"dsa_affine_x\">Аффинная координата x</string>\n    <string name=\"state_waking\">Пробуждение</string>\n    <string name=\"state_wake_kill\">Отключение пробуждения</string>\n    <string name=\"state_parked\">Оформлено</string>\n    <string name=\"state_device_io\">Ввод/вывод устройства</string>\n    <string name=\"rsa\">RSA</string>\n    <string name=\"aes\">AES</string>\n    <string name=\"un_apkm\">Распаковать Apkm</string>\n    <string name=\"ecc\">Эллиптическая криптография (ЕСС)</string>\n    <string name=\"none\">Без шифрования</string>\n    <string name=\"pref_encryption_msg\">Шифрование резервных копий.</string>\n    <string name=\"encryption\">Шифрование</string>\n    <string name=\"select_user\">Выбрать пользователя</string>\n    <string name=\"failed_to_duplicate_profile\">Не удалось продублировать профиль</string>\n    <string name=\"send_selected\">Отправить выбранный</string>\n    <string name=\"install_location\">Место установки</string>\n    <string name=\"installer\">Установщик</string>\n    <string name=\"comment\">Комментарий</string>\n    <string name=\"close\">Закрыть</string>\n    <string name=\"no_root\">Без-ROOT</string>\n    <string name=\"root\">ROOT</string>\n    <string name=\"user_profile_with_id\">Профиль: %1$s (%2$d)</string>\n    <string name=\"advanced\">Расширенный</string>\n    <string name=\"simple\">Простой</string>\n    <string name=\"enabled\">Включено</string>\n    <string name=\"choose\">Выбрать</string>\n    <string name=\"options\">Параметры</string>\n    <string name=\"off\">ВЫКЛ</string>\n    <string name=\"on\">ВКЛ</string>\n    <string name=\"profile_block_trackers_msg\">Блокирование трекеров в приложениях</string>\n    <string name=\"profile_clear_data_msg\">Очистка данных приложений</string>\n    <string name=\"profile_clear_cache_msg\">Очистка кеш приложений</string>\n    <string name=\"profile_force_stop_msg\">Принудительная остановка приложений</string>\n    <string name=\"profile_state\">Состояние профиля</string>\n    <string name=\"adb_over_tcp\">ADB через TCP</string>\n    <string name=\"pref_mode_of_operations\">Режим работы</string>\n    <string name=\"allow_routine_ops_msg\">Разрешить использовать профиль в повторяющихся операциях</string>\n    <string name=\"allow_routine_ops\">Разрешить повторяющиеся операции</string>\n    <string name=\"splits\">Сплиты</string>\n    <string name=\"source_stamp_verified\">SourceStamp подтвержден.</string>\n    <string name=\"verified\">Подтверждённый</string>\n    <string name=\"not_verified\">Не подтверждено</string>\n    <string name=\"pref_signature_schemes_msg\">Для большей совместимости следует выбрать как минимум схемы v1 и v2. Схема v4 требует v2 или v3.</string>\n    <string name=\"v4_scheme\">Схема v4 (начиная с Android 11)</string>\n    <string name=\"v3_scheme\">Схема v3 (начиная с Android 9)</string>\n    <string name=\"v2_scheme\">Схема v2 (начиная с Android 7.0)</string>\n    <string name=\"v1_scheme\">Схема v1 (начиная с Android 1.0)</string>\n    <string name=\"pref_apk_signing_msg\">Установка схемы подписи, пользовательские ключи подписи и т.д.</string>\n    <string name=\"apk_signing\">Подписание APK</string>\n    <string name=\"pref_sign_apk_msg\">Подписать APK-файлы перед их установкой.</string>\n    <string name=\"pref_sign_apk\">Подписать APK</string>\n    <string name=\"install_location_prefer_external\">Предпочтительно внешняя память</string>\n    <string name=\"install_location_internal_only\">Только внутренняя память</string>\n    <string name=\"profile_state_msg\">Настраиваемое состояние включения/выключения для этого профиля</string>\n    <plurals name=\"verified_with_warning\">\n        <item quantity=\"one\">Проверено с %d предупреждением</item>\n        <item quantity=\"few\">Проверено с %d предупреждениями</item>\n        <item quantity=\"many\">Проверено с %d предупреждениями</item>\n        <item quantity=\"other\">Проверено с %d предупреждениями</item>\n    </plurals>\n    <string name=\"input_permissions\">Ввод разрешений</string>\n    <string name=\"input_permissions_description\">Введите разрешения с пробелами, например <tt>com.permission.GET_ACCOUNTS android.permission.ACCESS_MEDIA_LOCATION</tt> и т.п. Используйте <tt>*</tt>, чтобы подать заявку на все разрешения.</string>\n    <plurals name=\"app_signing_signature_schemes_pl\">\n        <item quantity=\"one\">Схема подписи</item>\n        <item quantity=\"few\">Схемы подписи</item>\n        <item quantity=\"many\">Схемы подписи</item>\n        <item quantity=\"other\">Схемы подписи</item>\n    </plurals>\n    <string name=\"input_keystore_pass_msg\">Нажмите здесь, чтобы ввести пароль хранилища ключей</string>\n    <string name=\"input_keystore_pass_description\">Введите пароль хранилища ключей App Manager. Если вы видите это впервые, используйте генератор паролей, чтобы сгенерировать пароль и сохранить его в безопасном месте, прежде чем вставлять его здесь.</string>\n    <string name=\"input_keystore_pass\">Введите пароль хранилища ключей</string>\n    <string name=\"input_keystore_alias_pass_description\">Вставьте пароль для псевдонима <b>%1$s</b>. Вы можете оставить это поле пустым, если пароль совпадает с паролем хранилища ключей.</string>\n    <string name=\"input_keystore_alias_pass\">Пароль для псевдонима <b>%1$s</b></string>\n    <string name=\"no_app_ops_permission\">Нет разрешения на отображение операций приложения</string>\n    <string name=\"pref_backup_android_keystore_msg\">Не все приложения будут работать после восстановления. Восстановление хранилища ключей не работает на большинстве устройств.</string>\n    <string name=\"pref_backup_android_keystore\">Резервное копирование приложений с хранилищем ключей Android</string>\n    <string name=\"keep_data_and_app_signing_signatures\">Сохранить данные и подписи</string>\n    <string name=\"this_action_cannot_be_undone\">Это действие не может быть отменено.</string>\n    <string name=\"set_app_op_mode\">Установить режим работы приложения</string>\n    <string name=\"value\">Значение</string>\n    <string name=\"interceptor\">Перехватчик</string>\n    <string name=\"resend_intent\">Повторная отправка намерения</string>\n    <string name=\"share\">Поделиться</string>\n    <string name=\"extras\">Extras</string>\n    <string name=\"category\">Категории</string>\n    <string name=\"mime_type\">MIME-тип</string>\n    <string name=\"action\">Действие</string>\n    <string name=\"result_code\">Результат кода</string>\n    <string name=\"activity_result\">Результат активити</string>\n    <string name=\"send_edited_intent\">Отправить измененное намерение</string>\n    <string name=\"matching_activities\">Соответствующие активити</string>\n    <string name=\"filter_apps_with_splits\">Разделенные (сплиты)</string>\n    <string name=\"set_custom_app_op\">Пользовательская настройка операции приложения</string>\n    <string name=\"cpu\">Процессор</string>\n    <string name=\"battery\">Аккумулятор</string>\n    <string name=\"graphics\">Графика</string>\n    <string name=\"users\">Пользователи</string>\n    <string name=\"languages\">Языки</string>\n    <string name=\"battery_capacity\">Ёмкость</string>\n    <string name=\"memory\">Память</string>\n    <string name=\"vendor\">Поставщик</string>\n    <string name=\"gles_version\">Версия OpenGL ES</string>\n    <string name=\"no_of_cores\">Ядра</string>\n    <string name=\"support_architectures\">Поддерживаемые архитектуры</string>\n    <string name=\"security_providers\">Провайдер безопасности</string>\n    <string name=\"kernel\">Ядро</string>\n    <string name=\"manufacturer\">Производитель</string>\n    <string name=\"board_name\">Системная плата</string>\n    <string name=\"model\">Модель</string>\n    <string name=\"brand_name\">Марка</string>\n    <string name=\"pref_about_device_msg\">Основная информация об устройстве, включая версию Android, ЦП, ГП, ОЗУ, аккумулятор и т. д.</string>\n    <string name=\"about_device\">Об устройстве</string>\n    <string name=\"uri\">URI</string>\n    <string name=\"magisk_hide_enabled\">MagiskHide</string>\n    <string name=\"keystore\">Хранилище ключей</string>\n    <string name=\"security\">Безопасность</string>\n    <string name=\"patch_level\">Обновление системы безопасности Андроид</string>\n    <string name=\"backup_skip_signature_checks_description\">Восстановление резервных копий, которые либо не прошли проверку контрольных сумм, либо имеют подписи, отличные от предыдущих резервных копий APK.</string>\n    <string name=\"backup_multiple_description\">Создание отдельной резервной копии, с <i>именем</i> , которое отличается от основного наименования бекапа.</string>\n    <string name=\"backup_rules_description\">Резервное копирование правил, настроенных в App Manager.<font fgcolor=\"#ff0000\">В зависимости от разрешений не все правила можно повторно применить во время восстановления.</font> </string>\n    <string name=\"backup_extras_description\">Резервное копирование разрешений приложений, параметров экономии заряда батареи и использования данных, состояние MagiskHide, SSAID и т.д. <font fgcolor=\"#ff0000\">В зависимости от разрешений не все extras можно восстановить.</font> </string>\n    <string name=\"backup_extras\">Дополнительно</string>\n    <string name=\"backup_cache_description\">Резервное копирование папок <b>cache</b>, <b>no_cache</b> и <b>no_backup</b>.</string>\n    <string name=\"backup_obb_media_description\">Резервное копирование OBB и папок с медиафайлами.</string>\n    <string name=\"backup_external_data_description\">Резервное копирование внешних папок данных.</string>\n    <string name=\"backup_internal_data_description\">Резервное копирование папок с данными. Если выбран этот параметр, по умолчанию будут созданы резервные копии внутренних папок с данными.</string>\n    <string name=\"backup_apk_files_description\">Резервное копирование APK файлов из исходного каталога, включая сплиты.</string>\n    <string name=\"permissive\">Permissive</string>\n    <string name=\"enforcing\">Enforcing</string>\n    <string name=\"window_size\">Размер окна</string>\n    <string name=\"size\">Размер</string>\n    <string name=\"hardware\">Модель</string>\n    <plurals name=\"alert_failed_to_set_app_ops\">\n        <item quantity=\"one\">Не удалось настроить операции приложения %1$d приложения</item>\n        <item quantity=\"few\">Не удалось настроить операции приложения %1$d приложений</item>\n        <item quantity=\"many\">Не удалось настроить операции приложения %1$d приложений</item>\n        <item quantity=\"other\">Не удалось настроить операции приложения %1$d приложений</item>\n    </plurals>\n    <string name=\"refresh_rate\">Частота обновления</string>\n    <string name=\"scaling_factor\">Коэффициент масштабирования</string>\n    <string name=\"density\">Плотность пикселей</string>\n    <string name=\"screen\">Экран</string>\n    <string name=\"set_mode_for_app_ops_dots\">Установить режим операций приложения…</string>\n    <string name=\"failed_to_enable_magisk_hide\">Не удалось включить MagiskHide</string>\n    <string name=\"failed_to_disable_magisk_hide\">Не удалось отключить MagiskHide</string>\n    <string name=\"disable_background_run_description\">Устанавливает режим <i>ignore</i> для следующих операций приложения: <tt>RUN_IN_BACKGROUND</tt> (с Android 7.0) и <tt>RUN_ANY_IN_BACKGROUND</tt> (с Android 9).</string>\n    <plurals name=\"no_of_components\">\n        <item quantity=\"one\">%1$d компонент</item>\n        <item quantity=\"few\">%1$d компонента</item>\n        <item quantity=\"many\">%1$d компонентов</item>\n        <item quantity=\"other\">%1$d компонентов</item>\n    </plurals>\n    <string name=\"backup_custom_users_description\">Выполнять резервное копирование только для указанных пользователей</string>\n    <string name=\"encrypted\">Зашифрованный</string>\n    <string name=\"unencrypted\">Незашифрованный</string>\n    <string name=\"pref_backup_restore_msg\">Настройка резервного копирования/восстановления.</string>\n    <string name=\"no_volumes_found\">Не удалось найти тома с разрешением на запись.</string>\n    <string name=\"pref_backup_volume_msg\">Выберите том или диск, на котором будут храниться резервные копии.</string>\n    <string name=\"backup_volume\">Том резервных копий</string>\n    <string name=\"verify_and_redo_backups\">Проверить и повторить резервное копирование</string>\n    <string name=\"backup_apps_without_backups_msg\">Резервное копирование приложений без каких-либо предыдущих резервных копий.</string>\n    <string name=\"backup_apps_without_backups\">Резервное копирование приложений без резервных копий</string>\n    <string name=\"backup_all_apps\">Резервное копирование всех приложений</string>\n    <string name=\"app_signing_signature_schemes\">Схемы подписи</string>\n    <string name=\"back_up\">Резервное копирование</string>\n    <string name=\"drm_free_apkm_msg\">Файл APKM не содержит DRM, не требуется его конвертация в APKS.</string>\n    <string name=\"restore_msg\">Восстановление приложений с данными</string>\n    <string name=\"backup_msg\">Резервное копирование приложений с данными</string>\n    <string name=\"restore_latest_msg\">Восстановление уже установленных приложений, коды версий которых выше, чем код установленной версии.</string>\n    <string name=\"restore_latest\">Восстановление последних резервных копий</string>\n    <string name=\"restore_not_installed_msg\">Восстановление базовой резервной копии приложений не установленных в настоящее время.</string>\n    <string name=\"restore_not_installed\">Восстановить не установленные приложения</string>\n    <string name=\"restore_all_msg\">Восстановление базовой резервной копии из всех резервных копий приложений.</string>\n    <string name=\"restore_all\">Восстановление всех приложений</string>\n    <string name=\"backup_apps_with_changes_msg\">Повторить резервное копирование для приложений с изменениями с момента последнего резервного копирования. Они включают изменения в размере, версии, времени последнего запуска.</string>\n    <string name=\"backup_apps_with_changes\">Резервное копирование приложений с изменениями</string>\n    <string name=\"redo_existing_backups_msg\">Повторить резервное копирование установленных приложений с предыдущими резервными копиями.</string>\n    <string name=\"redo_existing_backups\">Повторное резервное копирование существующих</string>\n    <string name=\"verify_and_redo_backups_msg\">Проверить целостность предыдущих резервных копий и повторить резервное копирование не прошедших проверку целостности.</string>\n    <string name=\"backup_all_apps_msg\">Резервное копирование всех установленных приложений.</string>\n    <string name=\"bootloader\">Загрузчик</string>\n    <string name=\"selinux\">SELinux</string>\n    <string name=\"net_policy\">Сетевая политика</string>\n    <string name=\"has_net_policy\">Сетевая политика</string>\n    <string name=\"list_options\">Параметры списка</string>\n    <string name=\"reverse\">Обратный порядок</string>\n    <string name=\"os_version\">Версия ОС</string>\n    <string name=\"add\">Добавить</string>\n    <string name=\"add_to_profile\">Добавить в профиль</string>\n    <string name=\"initializing\">Инициализация…</string>\n    <string name=\"choose_what_to_do\">Выберите действие.</string>\n    <string name=\"enable_battery_optimization\">Включить экономию заряда батареи\\?</string>\n    <string name=\"battery_optimization\">Экономия заряда батареи</string>\n    <string name=\"no_battery_optimization\">Без оптимизации энергопотребления</string>\n    <string name=\"screen_lock_msg\">Блокировать App Manager с помощью блокировки экрана Android</string>\n    <string name=\"screen_lock\">Блокировка экрана</string>\n    <string name=\"unlock_app_manager\">Разблокировать App Manager</string>\n    <string name=\"sd_card\">SD-карта</string>\n    <string name=\"external_storage\">Внешнее хранилище</string>\n    <string name=\"internal_storage\">Внутреннее хранилище</string>\n    <string name=\"type_null\">Нет значения</string>\n    <string name=\"backup_custom_users\">Выбор пользователей</string>\n    <string name=\"user_with_id\">Пользователь: <xliff:g id=\"user_id\" example=\"0\">%1$d</xliff:g></string>\n    <string name=\"restart_to_reflect_changes\">Вы должны немедленно перезагрузить устройство, чтобы использовать новые изменения.</string>\n    <string name=\"failed_to_change_ssaid\">Не удалось изменить SSAID</string>\n    <string name=\"copied_to_clipboard\">Скопировано в буфер обмена.</string>\n    <string name=\"ssaid_info\">SSAID (<tt>Settings.Secure.ANDROID_ID</tt>) - это идентификатор устройства, присвоенный каждому приложению (начиная с Android Oreo и выше). Он широко используется приложениями для отслеживания пользователей.</string>\n    <string name=\"type_string_array_list\">Список строк</string>\n    <string name=\"type_string_array\">Массив строк</string>\n    <string name=\"type_float_array_list\">Список десятичных чисел</string>\n    <string name=\"type_float_array\">Массив десятичных чисел</string>\n    <string name=\"type_long_array_list\">Список длинных целых чисел</string>\n    <string name=\"type_long_array\">Массив длинных целых чисел</string>\n    <string name=\"type_int_array_list\">Список целых чисел</string>\n    <string name=\"type_int_array\">Массив целых чисел</string>\n    <string name=\"type_component_name\">Имя компонента</string>\n    <string name=\"installed_apps\">Установленные приложения</string>\n    <string name=\"last_actions\">Последние действия</string>\n    <string name=\"pref_enable_disable_features_msg\">Включить или отключить функции в App Manager.</string>\n    <string name=\"enable_disable_features\">Включение/отключение функций</string>\n    <string name=\"ssaid\">SSAID</string>\n    <string name=\"type_uri\">URI</string>\n    <string name=\"isolated\">Изолированно</string>\n    <string name=\"screen_lock_not_enabled\">Включите блокировку экрана в настройках Android или очистите данные приложения.</string>\n    <string name=\"input_app_ops_description_profile\">Введите имена операций приложения и/или константы с пробелами, например <tt>WAKE_LOCK 63 72 CAMERA</tt> и т.д. Используйте <tt>*</tt> для применения ко всем настроенным операциям приложения.</string>\n    <string name=\"working_on_adb_mode\">Работа в режиме ADB</string>\n    <string name=\"verified_using_unreliable_hash\">Проверено с использованием ненадежного хеша</string>\n    <string name=\"filter_apps_without_backups\">Без резервных копий</string>\n    <string name=\"uninstalled_apps\">Удаленные приложения</string>\n    <string name=\"installer_app_message\">Нажмите <b>выбрать</b> для использования одного из установленных приложений, или нажмите <b>пользовательское</b>, чтобы ввести имя пользовательского пакета.</string>\n    <string name=\"specify_custom_name\">Пользовательское</string>\n    <string name=\"internal_data\">Внутренние данные</string>\n    <string name=\"source_code_links\"><a href=\"https://github.com/MuntashirAkon/AppManager\">GitHub</a> - <a href=\"https://gitlab.com/muntashir/AppManager\">GitLab</a> - <a href=\"https://0xacab.org/muntashir/AppManager\">Riseup</a> - <a href=\"https://codeberg.org/muntashir/AppManager\">Codeberg</a></string>\n    <string name=\"expiry_date_cannot_be_empty\">Срок действия не может быть пустым.</string>\n    <string name=\"signing_key\">Ключ подписи</string>\n    <string name=\"failed_to_read_keystore\">Не удалось прочитать хранилище ключей.</string>\n    <string name=\"alias_pass\">Пароль псевдонима</string>\n    <string name=\"choose_an_alias\">Выберите псевдоним</string>\n    <string name=\"found_no_alias_in_keystore\">В хранилище ключей не найдено псевдонимов!</string>\n    <string name=\"new_alias_password\">Новый пароль псевдонима</string>\n    <string name=\"import_key\">Импортировать ключ</string>\n    <string name=\"pem_file\">PEM-файл</string>\n    <string name=\"pem_and_pk8\">PEM и PKCS #8 (PK8)</string>\n    <string name=\"keystore_file\">Файл хранилища ключей</string>\n    <string name=\"java_keystore\">Хранилище ключей Java (JKS)</string>\n    <string name=\"keystore_pass\">Пароль хранилища ключей</string>\n    <string name=\"country_name\" tools:ignore=\"TypographyOther\">Название страны (C)</string>\n    <string name=\"state_name\">Название государства (ST)</string>\n    <string name=\"locality_name\">Название населенного пункта (города) (L)</string>\n    <string name=\"organization_name\">Название организации (O)</string>\n    <string name=\"organization_unit\">Подразделение организации (OU)</string>\n    <string name=\"common_name\">Общее имя (CN)</string>\n    <string name=\"input_key_password\">Пароль ключа</string>\n    <string name=\"failed_to_load_key\">Не удалось загрузить ключ.</string>\n    <string name=\"key_not_set\">Не задано.</string>\n    <string name=\"use_default\">По умолчанию</string>\n    <string name=\"invalid_rsa_key_size\">Неверный размер ключа для шифрования RSA. Размер ключа может составлять 1024, 2048 или 4096 бит.</string>\n    <string name=\"crypto_key_size\">Размер ключа</string>\n    <string name=\"invalid_aes_key_size\">Неверный размер ключа для AES шифрования. Размер ключа может быть 128 или 256 бит.</string>\n    <string name=\"failed_to_initialize_key_store\">Не удалось инициализировать хранилище ключей App Manager.</string>\n    <string name=\"failed_to_save_key\">Не удалось сохранить ключ.</string>\n    <string name=\"generate_key\">Генерировать</string>\n    <string name=\"input_key\">Ввод ключа (в шестнадцатеричном формате)</string>\n    <string name=\"input_keystore_alias_pass_msg\">Нажмите здесь, чтобы ввести пароль для %1$s</string>\n    <string name=\"pref_installer_msg\">Настройка поведения установщика приложения.</string>\n    <string name=\"pk8_file\">Файл PKCS #8 (PK8)</string>\n    <string name=\"trackers_unblocked_successfully\">Трекеры разблокированы</string>\n    <string name=\"trackers_blocked_successfully\">Трекеры заблокированы</string>\n    <string name=\"failed_to_unblock_trackers\">Не удалось разблокировать трекеры</string>\n    <string name=\"failed_to_block_trackers\">Не удалось заблокировать трекеры</string>\n    <string name=\"profile_save_apk_msg\">Сохраняет файлы APK в <tt>AppManager/apks</tt></string>\n    <string name=\"save_apk\">Сохранить APK</string>\n    <string name=\"running_services\">Работающие службы</string>\n    <string name=\"view_logs\">Просмотр логов</string>\n    <string name=\"share_log\">Поделиться</string>\n    <string name=\"text_include_dmesg\">Включить журнал ядра</string>\n    <string name=\"omit_sensitive_info_summary\">Пропустить конфиденциальную информацию, такую как веб-адрес, телефонные номера или электронную почту.</string>\n    <string name=\"omit_sensitive_info\">Пропустить конфиденциальную информацию</string>\n    <string name=\"undo\">Отменить действие</string>\n    <string name=\"pause_unpause\">Воспроизведение/пауза</string>\n    <string name=\"collapse_all\">Свернуть все</string>\n    <string name=\"expand_all\">Раскрыть всё</string>\n    <string name=\"file\">Файл</string>\n    <string name=\"widget_start_recording\">Запись\n\\nЛог</string>\n    <string name=\"widget_recording_in_progress\">Запись…</string>\n    <string name=\"unable_to_save_log\">Невозможно сохранить лог. Вы ввели действительное имя файла\\?</string>\n    <plurals name=\"toast_log_truncated\">\n        <item quantity=\"one\">Лог слишком большой, показано последнюю %d строку.</item>\n        <item quantity=\"few\">Лог слишком большой, показано последние %d строки.</item>\n        <item quantity=\"many\">Лог слишком большой, показано последние %d строк.</item>\n        <item quantity=\"other\">Лог слишком большой, показано последние %d строк.</item>\n    </plurals>\n    <string name=\"toast_invalid_selection\">Неверный выбор. Пожалуйста, попробуйте еще раз.</string>\n    <string name=\"toast_invalid_level\">Недействительное имя уровня: %s</string>\n    <string name=\"pref_display_limit_hint\">Введите действительный номер между %1$d и %2$d.</string>\n    <string name=\"text_include_device_info\">Включить информацию об устройстве</string>\n    <string name=\"text_filter_text\">Фильтр текста</string>\n    <string name=\"text_filter_ellipsis\">Фильтр…</string>\n    <string name=\"subject_log_report\">Отчет лога</string>\n    <string name=\"start_recording_log\">Запись</string>\n    <string name=\"settings\">Настройки</string>\n    <string name=\"send_log_title\">Отправить лог</string>\n    <string name=\"save_log\">Сохранить лог</string>\n    <string name=\"save_as\">Сохранить как…</string>\n    <string name=\"record_log\">Запись лога</string>\n    <string name=\"pref_show_timestamp_title\">Показывать Pid &amp; Timestamp</string>\n    <string name=\"pref_show_timestamp_summary\">Показывать PID and Timestamp при разворачивании лога.</string>\n    <string name=\"pref_log_write_period_title\">Период записи</string>\n    <string name=\"pref_log_write_period_summary\">Записывать на SD-карту каждые %1$d строк.</string>\n    <string name=\"pref_log_line_period_error\">Пожалуйста, введите целое число от 1 до 1000.</string>\n    <string name=\"pref_expanded_by_default_title\">Раскрывать по умолчанию</string>\n    <string name=\"pref_expanded_by_default_summary\">По умолчанию отображается полный текст лога.</string>\n    <string name=\"pref_filter_pattern_title\">Отфильтровать теги</string>\n    <string name=\"pref_filter_pattern_summary\">Отфильтровать выбранные теги из логов.</string>\n    <string name=\"pref_display_limit_title\">Лимит отображения лога</string>\n    <string name=\"pref_display_limit_summary\">Показывать только последние %1$d логов, чтобы избежать ошибок нехватки памяти.</string>\n    <string name=\"pref_default_log_level_title\">Уровень лога по умолчанию</string>\n    <string name=\"pref_default_log_level_summary\">Уровень лога при запуске, открытии файлов и при записи.</string>\n    <string name=\"pref_cat_configuration\">Конфигурация</string>\n    <string name=\"pref_cat_appearance\">Внешний вид</string>\n    <string name=\"pref_cat_advanced\">Дополнительно</string>\n    <string name=\"pref_buffer_title\">Буфер лога(в)</string>\n    <string name=\"open\">Открыть</string>\n    <string name=\"notification_title\">Запись лога в процессе</string>\n    <string name=\"notification_ticker\">Начата запись лога</string>\n    <string name=\"notification_subtext\">Нажмите, чтобы остановить запись</string>\n    <string name=\"no_saved_logs\">Нет сохраненных логов.</string>\n    <string name=\"manage_saved_logs\">Управление сохраненными логами</string>\n    <string name=\"log_saved\">Лог сохранен.</string>\n    <string name=\"log_recording_started\">Началась запись лога.</string>\n    <string name=\"log_level\">Уровень логирования</string>\n    <string name=\"log_cleared\">Логи очищены</string>\n    <string name=\"filter_choice_tag\">Тег</string>\n    <string name=\"filter_choice_pid\">PID</string>\n    <string name=\"filter_choice\">Искать по</string>\n    <string name=\"enter_good_filename\">Пожалуйста, введите действительное имя файла.</string>\n    <string name=\"enter_filename\">Введите имя файла</string>\n    <string name=\"dialog_compiling_log\">Составление лога…</string>\n    <string name=\"delete_saved_log\">Удалить сохраненные логи</string>\n    <string name=\"copy_to_clipboard\">Скопировать в буфер обмена</string>\n    <string name=\"add_filter_ellipsis\">Добавить фильтр…</string>\n    <string name=\"add_filter\">Добавить фильтр</string>\n    <string name=\"log_level_fatal\">Fatal</string>\n    <string name=\"log_level_warn\">Warn</string>\n    <string name=\"log_level_verbose\">Verbose</string>\n    <string name=\"log_level_info\">Info</string>\n    <string name=\"log_level_error\">Error</string>\n    <string name=\"log_level_debug\">Debug</string>\n    <string name=\"filename\">Имя файла</string>\n    <string name=\"restart_log_viewer_to_see_changes\">Перезапустите окно просмотра логов, чтобы увидеть изменения.</string>\n    <string name=\"pref_log_viewer_msg\">Настройка отображения логов.</string>\n    <string name=\"log_viewer\">Просмотр логов</string>\n    <string name=\"latest_backup\">Последняя резервная копия</string>\n    <string name=\"gz_bz2_compressed\">%1$s сжато</string>\n    <string name=\"pgp_aes_rsa_encrypted\">%1$s зашифровано</string>\n    <string name=\"no_encryption\">Без шифрования</string>\n    <string name=\"base_backup\">Базовая резервная копия</string>\n    <string name=\"failed\">Сбой</string>\n    <string name=\"confirm_import_keystore\">Вы уверены, что хотите заменить существующее хранилище ключей\\? Это действие нельзя отменить.</string>\n    <string name=\"import_keystore\">Импортировать хранилище ключей</string>\n    <string name=\"pref_import_export_keystore_msg\">Импорт/экспорт Bouncy Castle KeyStore (BKS), используемых внутри App Manager.</string>\n    <string name=\"pref_import_export_keystore\">Импорт/экспорт хранилища ключей</string>\n    <string name=\"app_signing_signatures\">Подписи</string>\n    <string name=\"pref_rules_msg\">Мгновенная блокировка, импорт/экспорт/удаление правил и т. д.</string>\n    <string name=\"orientation_right_to_left\">Справа налево</string>\n    <string name=\"orientation_left_to_right\">Слева направо</string>\n    <string name=\"orientation_follow_locale\">В соответствии с локалью</string>\n    <plurals name=\"file_deletion_confirmation\">\n        <item quantity=\"one\">%d файл будет удален</item>\n        <item quantity=\"few\">%d файла будет удалено</item>\n        <item quantity=\"many\">%d файлов будет удалено</item>\n        <item quantity=\"other\">%d файлов будет удалено</item>\n    </plurals>\n    <string name=\"bouncy_castle_keystore\">Bouncy Castle KeyStore (BKS)</string>\n    <string name=\"suspended\">Приостановлено</string>\n    <string name=\"hidden\">Скрыто</string>\n    <string name=\"no_changes\">Без изменений</string>\n    <string name=\"pref_display_changes_msg\">Отображение изменений версии, трекеров, компонентов, разрешений, подписей, SDK и т.д., в режиме контроля версий.</string>\n    <string name=\"pref_display_changes\">Отображение изменений</string>\n    <string name=\"netpolicy_disable_network_access\">Отключить доступ к сети</string>\n    <string name=\"netpolicy_reject_wifi_data\">Отклонить Wi-Fi передачу данных</string>\n    <string name=\"netpolicy_reject_vpn_data\">Отклонить VPN передачу данных</string>\n    <string name=\"netpolicy_reject_cellular_data\">Отклонить передачу мобильных данных</string>\n    <string name=\"netpolicy_allow_background_data\">Разрешить фоновую передачу данных, когда включена экономия трафика</string>\n    <string name=\"netpolicy_reject_background_data\">Отклонить фоновую передачу данных</string>\n    <string name=\"pkcs12_keystore\">Хранилище ключей PKCS #12 (P12)</string>\n    <string name=\"saf\">SAF</string>\n    <string name=\"port_number_invalid\">Недействительный номер порта.</string>\n    <string name=\"port_number_empty\">Номер порта пуст.</string>\n    <string name=\"adb_connect_port_number_description\">Номер порта расположен в разделе <b>IP-адрес &amp; порт</b>, чуть ниже раздела <b>Имя устройства</b>.</string>\n    <string name=\"port_number\">Порт</string>\n    <string name=\"adb_connect\">Подключение</string>\n    <string name=\"wireless_debugging\">Беспроводная отладка</string>\n    <string name=\"unknown_net_policy\">Неизвестная сетевая политика (%1$s - %2$X)</string>\n    <string name=\"failed_to_prevent_background_run\">Не удалось предотвратить работу в фоне для приложения %1$s</string>\n    <string name=\"community\">Сообщество</string>\n    <string name=\"community_links\"><a href=\"https://matrix.to/#/#appmanager:matrix.org\">Matrix</a> • <a href=\"https://t.me/AppManagerChannel\">Telegram</a> • <a href=\"https://twitter.com/AppManagerNews\">Twitter</a></string>\n    <plurals name=\"alert_failed_to_import_backups\">\n        <item quantity=\"one\">Не удалось импортировать %1$d резервную копию</item>\n        <item quantity=\"few\">Не удалось импортировать %1$d резервных копии</item>\n        <item quantity=\"many\">Не удалось импортировать %1$d резервных копий</item>\n        <item quantity=\"other\">Не удалось импортировать %1$d резервных копий</item>\n    </plurals>\n    <string name=\"import_from_tb\">Импорт из Titanium Backup</string>\n    <string name=\"import_from_oab\">Импорт из OAndBackup</string>\n    <string name=\"pref_import_backups_msg\">Импорт резервных копий из OAndBackup, Swift Backup (3.0–3.2) или Titanium Backup.</string>\n    <string name=\"pref_import_backups\">Импорт резервных копий</string>\n    <string name=\"help_permissions_tab\">Эти разрешения определяются этим приложением и не могут быть отозваны.</string>\n    <string name=\"added_to_queue\">Добавлено в очередь</string>\n    <string name=\"minimum_version\">Мин. версия: %d</string>\n    <string name=\"help_uses_permissions_tab\">Нажмите на элемент, чтобы <b>предоставить</b> или <b>отозвать</b> разрешение. Только разрешения уровня <b>опасный</b> и <b>разработка</b> могут быть предоставлены или отозваны.</string>\n    <string name=\"help_app_ops_tab\">Нажмите на элемент, чтобы установить режим <b>allow/разрешить</b> или <b>ignore/игнорировать</b>. Долгое нажатие позволяет увидеть другие поддерживаемые режимы.</string>\n    <string name=\"saved_filters\">Сохраненные фильтры</string>\n    <string name=\"permission_flags\">Флаги разрешений</string>\n    <string name=\"pref_selected_users_msg\">Разрешить App Manager работу только с выбранными пользователями.</string>\n    <string name=\"pref_selected_users\">Выбранные пользователи</string>\n    <string name=\"error_with_details\">Ошибка: %s</string>\n    <string name=\"files\">Файлы</string>\n    <string name=\"storage\">Хранилище</string>\n    <string name=\"notice_saf\">В отличие от томов, выбранный каталог будет использоваться для хранения всех файлов, связанных с App Manager, включая сохраненные APK и резервные копии. Storage Access Framework (SAF) работает очень медленно, поэтому вы должны использовать этот вариант только тогда, когда другие не могут быть использованы.</string>\n    <string name=\"notice\">Уведомление</string>\n    <string name=\"keystore_password_info\">Ниже приведен пароль хранилища ключей App Manager. Пожалуйста, храните его в надежном месте, если вы собираетесь делать резервное копирование/восстановление хранилища ключей App Manager. <b>Это сообщение не будет отображаться снова.</b></string>\n    <string name=\"paired_successfully\">Подключено.</string>\n    <string name=\"adb_pair\">Подключить</string>\n    <string name=\"invalid_password\">Неправильный пароль, попробуйте ещё раз.</string>\n    <string name=\"keystore_pass_cannot_be_empty\">Пароль хранилища ключей не может быть пустым.</string>\n    <string name=\"background\">В фоне</string>\n    <string name=\"running_services_logcat_hint\">Нажмите на элемент, чтобы открыть \\\"Просмотр логов\\\", используя соответствующий идентификатор процесса в качестве фильтра по умолчанию.</string>\n    <string name=\"pid\">Идентификатор процесса</string>\n    <plurals name=\"pref_thread_count_msg\">\n        <item quantity=\"one\">Параллельное выполнение не более %1$d операции</item>\n        <item quantity=\"few\">Параллельное выполнение не более %1$d операций</item>\n        <item quantity=\"many\">Параллельное выполнение не более %1$d операций</item>\n        <item quantity=\"other\">Параллельное выполнение не более %1$d операций</item>\n    </plurals>\n    <string name=\"pref_thread_count_hint\">Значение должно быть от 0 до %1$d, где 0 означает <i>максимальное количество операций в данный момент времени</i>.</string>\n    <string name=\"pref_thread_count\">Параллельное выполнение</string>\n    <string name=\"type_uri_array_list\">Список URI</string>\n    <string name=\"type_uri_array\">Массив URI</string>\n    <string name=\"pref_always_on_background_msg\">Всегда устанавливать приложения в фоновом режиме и выводить уведомление по завершении операции.</string>\n    <string name=\"pref_always_on_background\">Установить в фоновом режиме</string>\n    <string name=\"pref_block_trackers_msg\">Блокирование компонентов трекеров после установки приложения через App Manager.</string>\n    <string name=\"next\">Следующий</string>\n    <string name=\"installer_app_installed\">Приложение установлено</string>\n    <string name=\"staging_apk_files\">Подготовка…</string>\n    <string name=\"trim_caches_in_all_apps_description\">Удаление кеш файлов со всех приложений, включая систему Android</string>\n    <string name=\"trim_caches_in_all_apps\">Очистка кэша во всех приложениях</string>\n    <string name=\"user_root\">Использовать root</string>\n    <string name=\"paste\">Вставить</string>\n    <string name=\"set_package_name_first\">Сначала установите имя пакета!</string>\n    <string name=\"identifier\">Идентификатор</string>\n    <string name=\"backup_volume_dialog_description\">Тома с префиксом <tt>/tree</tt> это папки, выбранные с помощью Storage Access Framework (SAF). Кроме этих папок, каталог по умолчанию для App Manager это подпапка с именем <tt>AppManager</tt>.</string>\n    <string name=\"second_degree_tracker_note\">² префикс указывает на то, что трекеры находятся в списке ожидания <a href=\"https://etip.exodus-privacy.eu.org/\"> ETIP</a>, т. е. являются ли они настоящими трекерами, все еще исследуется.</string>\n    <string name=\"failed_to_uninstall_app\">Не получилось удалить</string>\n    <string name=\"import_from_sb\">Импорт из Swift Backup 3.0 – 3.2</string>\n    <string name=\"java\">Java</string>\n    <string name=\"smali\">Smali</string>\n    <string name=\"explore\">Анализировать</string>\n    <string name=\"system_partition\">Корень системного раздела</string>\n    <string name=\"exit_confirmation\">Подтверждение выхода</string>\n    <string name=\"extract\">Извлечь</string>\n    <string name=\"replace\">Заменить</string>\n    <string name=\"rename\">Переименовать</string>\n    <string name=\"pref_import_backups_hint\">Выберите каталог, содержащий файлы (Swift Backup/Titanium Backup) или каталоги (OAndBackup) резервных копий</string>\n    <string name=\"accessibility_service_description\">Общая служба специальных возможностей для выполнения определенных операций, таких как очистка кеша в режиме без-root.</string>\n    <string name=\"pref_default_blocking_method\">Метод блокировки по умолчанию</string>\n    <string name=\"pref_intent_firewall_and_disable_description\">Блокировка компонентов с помощью Intent Firewall и также отключения. Рекомендуемый метод для root пользователей.</string>\n    <string name=\"authenticating\">Аутентификация…</string>\n    <string name=\"search_type_contains\">cодержит</string>\n    <string name=\"search_type_prefix\">префикс</string>\n    <string name=\"search_type_suffix\">суффикс</string>\n    <string name=\"intent_firewall_and_disable\">IFW + отключение</string>\n    <string name=\"search_type_regular_expressions\">регулярные выражения</string>\n    <string name=\"pref_disable_description\">Только отключение компонентов. Не рекомендуется для root пользователей, поскольку приложения могут обходить этот метод блокировки. С помощью этого метода можно отключить только тестовые приложения в режиме ADB.</string>\n    <string name=\"pref_default_blocking_method_description\">Метод, используемый по умолчанию там, где нет возможности выбора метода блокировки.</string>\n    <string name=\"pref_intent_firewall_description\">Блокировка компонентов с использованием только Intent Firewall. Не рекомендуется, поскольку некоторые системные приложения могут обходить этот метод блокировки.</string>\n    <string name=\"intent_firewall\">IFW</string>\n    <string name=\"failed_to_change_app_op_mode\">Не удалось изменить режим работы приложения.</string>\n    <string name=\"toggle_internet\">Использовать интернет</string>\n    <string name=\"vt_success\">VirusTotal: %1$d/%2$d</string>\n    <string name=\"vt_scan_date\">Дата сканирования: %1$s</string>\n    <string name=\"vt_permalink\">Постоянная ссылка на VirusTotal</string>\n    <string name=\"vt_queued\">VirusTotal: в очереди</string>\n    <string name=\"vt_failed\">VirusTotal: сбой</string>\n    <string name=\"pref_vt_apikey\">VirusTotal API-ключ</string>\n    <string name=\"pref_vt_apikey_summary\">Включить сканирование файлов APK через VirusTotal.</string>\n    <string name=\"scan_in_vt\">Сканирование в VirusTotal</string>\n    <string name=\"process_id\">Идентификатор процесса</string>\n    <string name=\"parent_process_id\">Идентификатор родительского процесса</string>\n    <string name=\"virtual_memory\">Виртуальная память</string>\n    <string name=\"cpu_percent\">%% ЦП</string>\n    <string name=\"cpu_time\">Процессорное время</string>\n    <string name=\"priority\">Приоритет</string>\n    <string name=\"state\">Состояние процесса</string>\n    <string name=\"commandline_args\">Аргументы командной строки</string>\n    <string name=\"swap\">Своп</string>\n    <string name=\"memory_chart_info\">● %1$s Приложения ● %2$s Кэшированные ● %3$s Буфер ● %4$s Свободно</string>\n    <string name=\"swap_chart_info\">● %1$s Используется ● %2$s Свободно</string>\n    <string name=\"failed_to_use_the_current_mode_of_operation\">Невозможно использовать текущий режим работы. Возврат к режиму без-root для этого сеанса.</string>\n    <string name=\"warning_working_on_root_mode\">Предупреждение: работа в режиме root вместо режима ADB.</string>\n    <string name=\"magisk_denylist\">Magisk DenyList</string>\n    <string name=\"failed_to_enable_magisk_deny_list\">Не удалось включить Magisk DenyList</string>\n    <plurals name=\"usage_seconds\">\n        <item quantity=\"one\">%1$d секунда</item>\n        <item quantity=\"few\">%1$d секунды</item>\n        <item quantity=\"many\">%1$d секунд</item>\n        <item quantity=\"other\">%1$d секунд</item>\n    </plurals>\n    <plurals name=\"usage_minutes\">\n        <item quantity=\"one\">%1$d минута</item>\n        <item quantity=\"few\">%1$d минуты</item>\n        <item quantity=\"many\">%1$d минут</item>\n        <item quantity=\"other\">%1$d минут</item>\n    </plurals>\n    <string name=\"vt_checking\">VirusTotal: проверка…</string>\n    <string name=\"vt_uploading\">VirusTotal: загрузка…</string>\n    <string name=\"vt_slowness_warning\">В зависимости от скорости интернета и нагрузки на сервер, это может занять некоторое время.</string>\n    <string name=\"pref_vt_apikey_description\">API-ключ позволяет App Manager загружать APK-файлы на VirusTotal, а также получать отчеты. Зарегистрируйтесь на сайте https://virustotal.com, чтобы получить API-ключ бесплатно.</string>\n    <string name=\"vt_disclaimer\">VirusTotal и его логотипы являются торговой маркой компании Chronicle LLC. Ни App Manager - клиент API, ни его авторы не несут ответственности за любые данные, которые вы можете отправить в VirusTotal.</string>\n    <string name=\"uses_play_app_signing_description\">Это приложение содержит определенные маркеры, указывающие на то, что оно <i>возможно</i> использует <a href=\"https://support.google.com/googleplay/android-developer/answer/9842756\">Play App Signing</a>. В этой схеме ключи подписи хранятся на серверах Google, и Google несет ответственность за подписание приложения. Обратите внимание, что соответствие информации о подписи — это единственный способ убедиться, что приложение не было изменено кем-либо, кроме разработчика (и в данном случае также Google).</string>\n    <string name=\"threads\">Количество потоков</string>\n    <string name=\"mode_of_op_with_inferred_mode_of_op\">%1$s (предполагаемый режим: %2$s)</string>\n    <string name=\"failed_to_disable_magisk_deny_list\">Не удалось отключить Magisk DenyList</string>\n    <string name=\"primary_abi\">Главный ABI</string>\n    <string name=\"hidden_api_enforcement_policy\">Политика применения скрытых API</string>\n    <string name=\"hidden_api_enf_default_policy\">По умолчанию (основано на типе приложения)</string>\n    <string name=\"hidden_api_enf_policy_none\">Ничего (полный доступ к скрытым API)</string>\n    <string name=\"hidden_api_enf_policy_warn\">Предупреждение (полный доступ к скрытым API, но с выдачей предупреждения)</string>\n    <string name=\"binary_32_bit\">32 бит</string>\n    <string name=\"uses_play_app_signing\">Подпись Play App</string>\n    <string name=\"zygote_preload_name\">Название предварительной загрузки Zygot</string>\n    <string name=\"binary_64_bit\">64 бит</string>\n    <string name=\"so_type_shared_library\">Общая библиотека</string>\n    <string name=\"so_type_executable\">Исполняемый файл</string>\n    <string name=\"save_and_exit\">Сохранить и выйти</string>\n    <string name=\"file_modified_are_you_sure\">Файл был изменен. Сбросить все изменения и выйти\\?</string>\n    <string name=\"hidden_api_enf_policy_dark_grey_and_black\">Принудительно (темно-серый и черный списки)</string>\n    <string name=\"hidden_api_enf_policy_black\">Принудительно (только черные списки)</string>\n    <string name=\"endianness_big_endian\">От старшего к младшему</string>\n    <string name=\"endianness_little_endian\">От младшего к старшему</string>\n    <string name=\"regenerate_auth_key_warning\">Вы уверены\\? Все сторонние приложения должны быть перенастроены с использованием нового ключа авторизации.</string>\n    <string name=\"pref_saved_apk_name_format\">Формат имени сохраненного APK</string>\n    <string name=\"pref_saved_apk_name_format_msg\">Формат, который будет использоваться для названия файлов APK при их сохранении.</string>\n    <string name=\"auth_manager_description\">Чтобы запустить Intent из внешнего приложения, необходимо указать дополнительное поле с именем <tt>auth</tt>, и оно должно содержать следующий ключ:</string>\n    <string name=\"auth_manager_title\">Менеджер авторизации</string>\n    <string name=\"regenerate_auth_key\">Пересоздать ключ авторизации</string>\n    <string name=\"shortcut_icon\">Значок быстрого доступа</string>\n    <string name=\"sort_by_installation_date\">Дата установки</string>\n    <string name=\"change_backup_volume\">Изменить том</string>\n    <string name=\"external\">Внешний</string>\n    <string name=\"internal\">Внутренний</string>\n    <string name=\"tracker\">Трекер</string>\n    <string name=\"screen_time\">Время работа экрана</string>\n    <string name=\"input_ssaid_instruction\">SSAID - это шестнадцатеричное число длиной %1$d байт, то есть строка длиной %2$d, содержащая от 0 до 9 и от a до f.</string>\n    <string name=\"backup_volume_unavailable_warning\">Выбранный том резервных копий в настоящее время недоступен. Если он находится на внешнем накопителе, подключите его или измените том для резервных копий.</string>\n    <string name=\"open_in_new_window\">Новое окно</string>\n    <string name=\"vt_confirm_uploading_file\">Файл не найден в базе данных VirusTotal. Вы хотите загрузить его\\?</string>\n    <string name=\"vt_confirm_upload_and_scan\">Да, загрузить и просканировать</string>\n    <string name=\"type_string_set\">Набор строк</string>\n    <string name=\"pref_vt_prompt_before_uploading\">Показывать подсказку перед загрузкой файла.</string>\n    <string name=\"log_stop_recording\">Остановить запись</string>\n    <string name=\"apk_checksums\">Контрольные суммы APK</string>\n    <string name=\"item_select\">Выбрать</string>\n    <string name=\"netpolicy_cannot_be_modified_for_core_apps\">Сетевую политику нельзя изменить для приложений ОС Android.</string>\n    <string name=\"open_developer_options_page\">Откройте страницу \\\"Для разработчиков\\\" в настройках вашего устройства</string>\n    <string name=\"usage_last_used\">Последнее использование</string>\n    <string name=\"pref_pure_black_theme\">Полностью черная тема</string>\n    <string name=\"pref_pure_black_theme_msg\">Использовать полностью черный фон, когда включен ночной режим.</string>\n    <string name=\"usage_mobile_data\">Мобильные данные</string>\n    <string name=\"usage_times_opened\">Количество запусков</string>\n    <string name=\"usage_wifi_data\">Wi-Fi данные</string>\n    <string name=\"app_explorer\">Обозреватель приложений</string>\n    <string name=\"frozen\">Заморожено</string>\n    <string name=\"freeze\">Заморозить</string>\n    <string name=\"unfreeze\">Разморозить</string>\n    <string name=\"backup_no_backups_present\">Нет резервных копий.</string>\n    <string name=\"restore_dots\">Восстановление…</string>\n    <string name=\"backup_apps_cannot_be_restored\">Следующие приложения не могут быть восстановлены, потому что у них нет базовой резервной копии:</string>\n    <string name=\"backup_apps_cannot_be_backed_up\">Следующие приложения не установлены и их резервное копирование невозможно:</string>\n    <string name=\"restart_device\">Перезагрузить устройство</string>\n    <string name=\"import_backups_warning_delete_backups_after_import\">Удалить резервные копии после их импорта в App Manager\\? Каждая резервная копия удаляется отдельно после успешного импорта. Выберите <b>Нет</b>, если не уверены.</string>\n    <string name=\"troubleshooting\">Устранение неполадок</string>\n    <string name=\"pref_reload_apps\">Перезагрузить приложения</string>\n    <string name=\"pref_reload_apps_msg\">Перезагрузка списка приложений, хранящихся в базе данных App Manager, в случае неожиданного поведения.</string>\n    <string name=\"changelog_type_new\">Новое</string>\n    <string name=\"changelog_type_fix\">Исправления</string>\n    <string name=\"changelog_type_improve\">Улучшения</string>\n    <string name=\"unsupported_split_apk\">Не поддерживается</string>\n    <string name=\"view_changelog\">Узнайте, что нового в этом релизе</string>\n    <string name=\"sort_by_total_size\">Общий размер</string>\n    <string name=\"am_command\">Команда <tt>am</tt></string>\n    <string name=\"pref_sign_apk_no_signing_key\">Нет ключа подписи</string>\n    <string name=\"pref_sign_apk_error_signing_key_not_added\">Для подписи APK-файла требуется действительный ключ подписи.</string>\n    <string name=\"freeze_unfreeze\">Заморозка/разморозка</string>\n    <string name=\"failed_to_freeze\">Не удалось заморозить <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g> .</string>\n    <plurals name=\"alert_failed_to_freeze\">\n        <item quantity=\"one\">Не удалось заморозить %1$d приложение</item>\n        <item quantity=\"few\">Не удалось заморозить %1$d приложения</item>\n        <item quantity=\"many\">Не удалось заморозить %1$d приложений</item>\n        <item quantity=\"other\">Не удалось заморозить %1$d приложений</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_unfreeze\">\n        <item quantity=\"one\">Не удалось разморозить %1$d приложение</item>\n        <item quantity=\"few\">Не удалось разморозить %1$d приложения</item>\n        <item quantity=\"many\">Не удалось разморозить %1$d приложений</item>\n        <item quantity=\"other\">Не удалось разморозить %1$d приложений</item>\n    </plurals>\n    <string name=\"suspend_app_description\">Это самый слабый метод замораживания. Приостановленное приложение может по-прежнему отображаться в лончере, но будет выделено серым цветом и не может быть запущено.</string>\n    <string name=\"sort_by_frozen_app\">Сначала замороженные</string>\n    <string name=\"filter_frozen_apps\">Замороженные приложения</string>\n    <string name=\"get_help\">Получить помощь</string>\n    <string name=\"failed_to_unfreeze\">Не удалось разморозить <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g> .</string>\n    <string name=\"profile_freeze_msg\">Заморозка или разморозка приложения в зависимости от состояния</string>\n    <string name=\"hide_app\">Скрыть</string>\n    <string name=\"hide_app_description\">Этот метод рекомендуется только для ежедневного использования. Скрытое приложение выглядит так, как будто оно удалено. Но оно может появиться снова, если его переустановить или обновить.</string>\n    <string name=\"pref_appearance_description\">Тема, ориентация, функции и т.д.</string>\n    <string name=\"pref_privacy\">Конфиденциальность</string>\n    <string name=\"pref_privacy_description\">Блокировка экрана, авторизация и т.д.</string>\n    <string name=\"user_manual\">Руководство пользователя</string>\n    <string name=\"pref_version_changelog\">Версия/Журнал изменений</string>\n    <string name=\"pref_default_freezing_method\">Метод заморозки по умолчанию</string>\n    <string name=\"suspend_app\">Приостановить</string>\n    <string name=\"pref_default_freezing_method_description\">Метод, который будет использоваться по умолчанию в местах, где нет возможности выбрать метод заморозки.</string>\n    <string name=\"disable_app_description\">Рекомендуемый метод заморозки. Он отключает приложение и вместе с ним все его компоненты, но все ярлыки будут потеряны.</string>\n    <string name=\"pref_advanced_pref\">Пользователи, формат имени APK, параллельное выполнение и т.д.</string>\n    <string name=\"file_modification_date\">Изменено</string>\n    <string name=\"file_open_with\">Открыть с помощью</string>\n    <string name=\"file_shortcut_target_file\">Целевой файл</string>\n    <string name=\"file_change_open_with\">Изменить открыть с помощью</string>\n    <string name=\"file_cut\">Вырезать</string>\n    <string name=\"file_open_as\">Открыть с помощью…</string>\n    <string name=\"open_as_text\">Текст</string>\n    <string name=\"open_as_image\">Изображение</string>\n    <string name=\"open_as_video\">Видео</string>\n    <string name=\"file_open_with_os_default_dialog\">Открыть с диалоговым окном ОС по умолчанию</string>\n    <string name=\"open_as_archive\">Архив</string>\n    <string name=\"open_as_folder\">Папка</string>\n    <string name=\"open_as_other\">Другое</string>\n    <string name=\"delete_filename\">Удалить %s</string>\n    <string name=\"on_unfreeze_open_application\">Запустить приложение после разморозки</string>\n    <string name=\"freeze_on_phone_locked\">Автоматически заморозить приложение, когда телефон заблокирован</string>\n    <string name=\"tap_to_freeze_app\">Нажмите, чтобы заморозить</string>\n    <string name=\"waiting_for_the_phone_to_be_locked\">Ожидание блокировки телефона…</string>\n    <string name=\"action_stop_service\">Остановить</string>\n    <string name=\"file_creation_date\">Создано</string>\n    <string name=\"file_accessed_date\">Доступ</string>\n    <string name=\"file_properties\">Свойства</string>\n    <string name=\"confirm_file_deletion\">Да, удалить</string>\n    <string name=\"on_open_application_no_recents\">Не показывать запущенное приложение в Недавних</string>\n    <string name=\"fm_always_open_with\">Всегда открывать</string>\n    <string name=\"fm_open_with_for_this_file_only\">Только для этого файла</string>\n    <string name=\"file_open_with_custom_activity\">Пользовательский</string>\n    <string name=\"grant_overlay_permission_message\">Разрешить App Manager отображать плавающее окно поверх всех остальных окон</string>\n    <string name=\"grant_accessibility_permission_for_tracking_window_contents\">Позволяет App Manager использовать специальные возможности для отслеживания содержимого ведущего окна.</string>\n    <string name=\"title_ui_tracker\">UI трекер</string>\n    <string name=\"title_terminal_emulator\">Терминал</string>\n    <string name=\"title_labs_activity\">Лаборатория</string>\n    <string name=\"app_manager_build_expired\">Требуется обновление</string>\n    <string name=\"app_manager_build_expired_message\">Версия App Manager, которую вы используете, устарела. Чтобы обеспечить безопасность вашего устройства и данных, вы должны обновить приложение до последней версии, чтобы продолжить использовать его, или удалить его, если обновление недоступно.</string>\n    <string name=\"app_manager_build_expiring_soon_warning\">Срок действия этой версии App Manager скоро истечет. Пожалуйста, обновите приложение до последней версии.</string>\n    <string name=\"renamed_successfully\">Переименовано</string>\n    <string name=\"selinux_context\">SELinux контекст</string>\n    <string name=\"unix_file_permissions\">Режим</string>\n    <string name=\"file_group_id\">Группа (GID)</string>\n    <string name=\"file_owner_id\">Владелец (UID)</string>\n    <string name=\"calculating_file_size\">Вычисление…</string>\n    <string name=\"sort_by_filename\">Имя</string>\n    <string name=\"sort_by_last_modified\">Последнее изменение</string>\n    <string name=\"sort_by_file_size\">Размер файла</string>\n    <string name=\"sort_by_file_type\">Тип файла</string>\n    <string name=\"option_display_dot_files\">Скрытые файлы</string>\n    <string name=\"option_display_folders_on_top\">Папки сверху</string>\n    <string name=\"export_app_list\">Экспорт списка приложений</string>\n    <string name=\"export_app_list_select_format\">Выбор формата для экспорта списка приложений</string>\n    <string name=\"funding_campaign_text\">Мы проводим <b>кампанию по сбору средств</b> для App Manager в течение ограниченного периода времени.\n\\n<a href=\"https://opencollective.com/app-manager#category-ABOUT\">узнать подробнее...</a></string>\n    <string name=\"adb_incomplete_usb_debugging_title\">Незавершенная отладка по USB</string>\n    <string name=\"confirm_uninstallation\">Подтвердить удаление</string>\n    <string name=\"action_continue\">Продолжить</string>\n    <string name=\"grant_required_permission\">Предоставить необходимое разрешение</string>\n    <string name=\"install_for_another_user\">Установить для…</string>\n    <string name=\"app_can_write_and_execute_in_same_place\">Это приложение нарушает <a href=\"https://en.wikipedia.org/wiki/W%5EX\">политику W^X</a> и может выполнять запись и выполнение в том же каталоге или в той же части памяти. Это позволяет выполнять произвольные исполняемые файлы либо путем модификации исполняемых файлов, встроенных в приложение, либо путем их загрузки из Интернета. Если это не является предполагаемым поведением приложения (например, эмуляторы терминала), рекомендуется найти более новую версию приложения, предназначенную для SDK 29 (Android 10) и более поздних версий, или поискать альтернативы.</string>\n    <string name=\"filter_apps_with_keystore\">С хранилищем ключей</string>\n    <string name=\"export_option_markdown\">Markdown</string>\n    <string name=\"export_option_xml\">XML</string>\n    <string name=\"funding_campaign_dialog_message\">Мы проводим <b>кампанию по сбору средств</b> для App Manager в течение ограниченного периода времени. Посетите <a href=\"https://opencollective.com/app-manager#category-ABOUT\">opencollective.com/app-manager</a>, чтобы узнать больше о кампании. Это уведомление больше не будет отображаться, но вы можете найти его на странице настроек в течение всей кампании.</string>\n    <string name=\"filter_apps_with_saf\">С SAF</string>\n    <string name=\"sort_by_data_usage\">Использование данных</string>\n    <string name=\"adb_incomplete_usb_debugging_message\">Похоже, отладка по USB не настроена должным образом. Прочтите <a href=\"https://muntashirakon.github.io/AppManager/#subsec:enable-usb-debugging\">документацию</a>, чтобы узнать о дополнительных шагах. Если вы уже известен процесс, нажмите «Открыть», чтобы открыть параметры разработчика, или нажмите «Закрыть», чтобы продолжить использовать режим без полномочий root.</string>\n    <string name=\"class_hierarchy\">Иерархия</string>\n    <string name=\"filter_apps_with_ssaid\">С SSAID</string>\n    <string name=\"optimize_option_clear_profile_data\">Очистка данных предыдущего профиля</string>\n    <string name=\"select_a_dex2oat_compiler_filter\">Фильтр компилятора <tt>dex2oat</tt></string>\n    <string name=\"optimize_option_compile_layouts\">Компиляция ресурсов макета</string>\n    <string name=\"optimize_option_check_profiles\">Учитывать данные профиля во время оптимизации DEX</string>\n    <string name=\"optimize_option_force_compilation\">Принудительная компиляция, даже если она не требуется</string>\n    <string name=\"action_optimize_app\">Оптимизировать</string>\n    <string name=\"batch_ops_runtime_optimization\">Оптимизация среды выполнения</string>\n    <string name=\"summary_perform_runtime_optimization_to_apps\">Оптимизация DEX и (в Android 10 и более поздних версиях) макетов для повышения производительности приложений.</string>\n    <string name=\"action_run\">Пуск</string>\n    <string name=\"optimize_option_force_dexopt\">Немедленное выполнение оптимизации DEX</string>\n    <string name=\"title_perform_runtime_optimization_to_apps\">Оптимизация среды выполнения</string>\n    <plurals name=\"alert_failed_to_optimize_apps\">\n        <item quantity=\"one\">Не удалось оптимизировать %1$d приложение</item>\n        <item quantity=\"few\">Не удалось оптимизировать %1$d приложения</item>\n        <item quantity=\"many\">Не удалось оптимизировать %1$d приложений</item>\n        <item quantity=\"other\">Не удалось оптимизировать %1$d приложений</item>\n    </plurals>\n    <string name=\"app_info_tag_open_links\">Открываемые ссылки</string>\n    <string name=\"source_stamp_verified_and_identified_to_be_from_source\">SourceStamp проверен и идентифицирован как принадлежащий <xliff:g id=\"source\" example=\"Google Play\">%1$s</xliff:g> .</string>\n    <string name=\"title_domains_supported_by_the_app\">Поддерживаемые домены</string>\n    <string name=\"pref_zip_align\">Выравнивание APK-файлов</string>\n    <string name=\"block_unblock_components_dots\">Блокировать/разблокировать компоненты…</string>\n    <string name=\"unblock_components_dots\">Разблокировать компоненты…</string>\n    <string name=\"block_unblock_components_description\">Блокировать или разблокировать все компоненты, идентифицированные данными подписями</string>\n    <string name=\"pref_layout_direction\">Направление текста</string>\n    <string name=\"title_code_editor\">Редактор кода</string>\n    <string name=\"redo\">Повторить</string>\n    <string name=\"read_only_file_warning\">Изменения не могут быть записаны в файл, возможно, из-за того, что он находится в томе, на запись в который у App Manager нет разрешения. Сохранить его в другом месте\\?</string>\n    <string name=\"line_separator\">Разделитель строк</string>\n    <plurals name=\"search_results\">\n        <item quantity=\"one\">%d результат</item>\n        <item quantity=\"few\">%d результата</item>\n        <item quantity=\"many\">%d результатов</item>\n        <item quantity=\"other\">%d результатов</item>\n    </plurals>\n    <string name=\"replacement_text\">Заменить</string>\n    <string name=\"action_replace_all\">Заменить все</string>\n    <string name=\"search_option_match_case\">Учитывать регистр</string>\n    <string name=\"search_option_whole_word\">Целое слово</string>\n    <string name=\"search_option_regex\">Регулярное выражение</string>\n    <string name=\"uninstall_app_again_message\">Приложение было удалено без очистки данных и подписи. Хотите полностью удалить его\\?</string>\n    <string name=\"uninstall_app\">Удалить %1$s</string>\n    <string name=\"debloat_list_type\">Список</string>\n    <string name=\"debloat_removal_type\">Тип</string>\n    <string name=\"system_app_put_back\">Вернуть</string>\n    <string name=\"debloat_list_misc\">Разное</string>\n    <string name=\"debloat_removal_replace\">Замена</string>\n    <string name=\"debloat_removal_caution\">Осторожно</string>\n    <string name=\"debloat_removal_safe\">Безопасно</string>\n    <string name=\"static_shared_library\">Статическая общая библиотека</string>\n    <plurals name=\"alert_failed_to_unblock_components\">\n        <item quantity=\"one\">Не удалось разблокировать компоненты приложения %1$d</item>\n        <item quantity=\"few\">Не удалось разблокировать компоненты приложений %1$d</item>\n        <item quantity=\"many\">Не удалось разблокировать компоненты приложений %1$d</item>\n        <item quantity=\"other\">Не удалось разблокировать компоненты приложений %1$d</item>\n    </plurals>\n    <string name=\"pref_zip_align_msg\">Выравнивание APK-файла снижает использование памяти, поскольку к файлам в APK можно обращаться напрямую, не копируя данные в ОЗУ. Этот шаг необходим, если для параметра <tt>extractNativeLibs</tt> задано значение <tt>true</tt>.</string>\n    <string name=\"read_only_file\">Файл только для чтения</string>\n    <string name=\"debloat_list_google\">Google</string>\n    <string name=\"debloater_title\">Деблоатер</string>\n    <string name=\"debloat_list_aosp\">AOSP</string>\n    <string name=\"debloat_list_oem\">OEM</string>\n    <string name=\"debloat_list_carrier\">Оператор связи/интернет-провайдер</string>\n    <plurals name=\"folder_count\">\n        <item quantity=\"one\">%d папка</item>\n        <item quantity=\"few\">%d папки</item>\n        <item quantity=\"many\">%d папок</item>\n        <item quantity=\"other\">%d папок</item>\n    </plurals>\n    <plurals name=\"file_count\">\n        <item quantity=\"one\">%%d файл</item>\n        <item quantity=\"few\">%d файла</item>\n        <item quantity=\"many\">%d файлов</item>\n        <item quantity=\"other\">%d файлов</item>\n    </plurals>\n    <string name=\"filter_force_stopped_apps\">Остановленные приложения</string>\n    <string name=\"empty_folder\">Пусто</string>\n    <string name=\"go_to_path\">Перейти к…</string>\n    <string name=\"copy_this_path\">Копировать путь</string>\n    <string name=\"title_audio_player\">Аудиоплеер</string>\n    <string name=\"backing_up_app\">Резервное копирование %1$s…</string>\n    <string name=\"restoring_app\">Восстановление %1$s…</string>\n    <string name=\"folder\">Папка</string>\n    <string name=\"create_new_symbolic_link\">Новая символическая ссылка</string>\n    <string name=\"symbolic_link_not_supported\">Эта папка не поддерживает создание символической ссылки.</string>\n    <string name=\"create_new_folder\">Новая папка</string>\n    <string name=\"create_new_file\">Новый файл</string>\n    <string name=\"title_confirm_deletion\">Подтвердить удаление</string>\n    <string name=\"copy_keep_both_file\">Сохранить оба</string>\n    <string name=\"copied_successfully\">Скопировано</string>\n    <string name=\"moved_successfully\">Перемещено</string>\n    <string name=\"failed_to_copy_specified_file\">Не удалось скопировать “%1$s”.</string>\n    <string name=\"apply_recursively\">Применить к вложенным файлам</string>\n    <string name=\"change_owner_uid\">Изменить владельца (UID)</string>\n    <string name=\"change_group_gid\">Изменить группу (GID)</string>\n    <string name=\"warning_working_on_system_mode\">Предупреждение: работа в системе, а не в режиме ADB.</string>\n    <string name=\"pref_installer_force_dexopt_description\">Выполнить оптимизацию DEX сразу после установки приложения, не дожидаясь, пока система сделает это во время простоя.</string>\n    <string name=\"symbolic_link\">Символическая ссылка</string>\n    <string name=\"enter_symbolic_link_name\">Название ссылки</string>\n    <string name=\"installing_package\">Установка %1$s…</string>\n    <string name=\"enter_target_path\">Целевой путь</string>\n    <string name=\"invalid_target_path\">Неверный путь</string>\n    <string name=\"copy_these_paths\">Копировать пути</string>\n    <string name=\"conflict_detected_while_copying\">Обнаружен конфликт</string>\n    <string name=\"conflict_detected_while_copying_message\">В этом расположении уже существует элемент с именем «%1$s». Вы хотите заменить его\\?</string>\n    <string name=\"title_change_selinux_context\">Изменение контекста SELinux</string>\n    <string name=\"change_mode\">Изменить режим</string>\n    <string name=\"failed_to_delete_specified_file_after_copying\">Не удалось удалить «%1$s» после его копирования, возможно, из-за отсутствия прав.</string>\n    <string name=\"pref_send_notifications_to_connected_devices\">Отправка уведомлений на подключенные устройства</string>\n    <string name=\"pref_send_notification_to_connected_devices_msg\">Укажите, следует ли отправлять уведомления на подключенные устройства, такие как носимые устройства.</string>\n    <string name=\"installer_options\">Опции установщика</string>\n    <string name=\"debloat_removal_safe_short_description\">Безопасно для удаления</string>\n    <string name=\"debloat_removal_caution_short_description\">Соблюдайте осторожность</string>\n    <string name=\"debloat_removal_replace_short_description\">Заменить на альтернативный вариант</string>\n    <string name=\"title_alternatives_to_bloatware\">Альтернативы</string>\n    <string name=\"browse_files\">Посмотреть</string>\n    <string name=\"pref_files_msg\">Настроить файловый менеджер.</string>\n    <string name=\"pref_files_remember_last_path\">Запомнить последний открытый путь и его позицию</string>\n    <string name=\"pref_files_display_in_launcher\">Отображение \\\"Файлов\\\" на панели приложений</string>\n    <string name=\"pref_files_remember_last_path_msg\">Если эта опция включена, то при открытии нового окна вместо домашней папки открывается последняя открытая папка.</string>\n    <string name=\"xposed_module_info\">Информация о модуле Xposed</string>\n    <string name=\"title_description\">Описание</string>\n    <string name=\"pref_set_home\">Сделать домашней</string>\n    <string name=\"module_name\">Название модуля</string>\n    <string name=\"app_manager_is_running\">App Manager запущен</string>\n    <string name=\"tap_to_open_notification_settings\">Нажмите, чтобы скрыть</string>\n    <string name=\"app_manager_is_unlocked\">App Manager разблокирован</string>\n    <string name=\"action_lock_app\">Блокировка</string>\n    <string name=\"pref_enable_persistent_session\">Запуск App Manager в фоновом режиме</string>\n    <string name=\"pref_enable_persistent_session_msg\">Запуск App Manager в фоновом режиме уменьшает задержку инициализации. Полезно, если вы часто используете App Manager.</string>\n    <string name=\"pref_enable_auto_lock\">Автоматическая блокировка</string>\n    <string name=\"pref_enable_auto_lock_msg\">Блокировка App Manager\\'а при заблокированном устройстве.</string>\n    <string name=\"path_does_not_exist\">“%1$s” не существует</string>\n    <string name=\"path_not_a_folder\">“%1$s” не является папкой</string>\n    <string name=\"scan_report_from_pithus\">Отчет Pithus</string>\n    <string name=\"action_checking\">Проверка…</string>\n    <string name=\"report_not_available\">Не доступно</string>\n    <string name=\"profile_modified_are_you_sure\">Профиль был изменен. Отменить все изменения и выйти\\?</string>\n    <string name=\"apply_profile\">Применить профиль “%1$s”</string>\n    <string name=\"copy_profile_id\">Скопировать идентификатор профиля</string>\n    <string name=\"profile_id\">ID профиля</string>\n    <string name=\"choose_a_profile_state\">Выберите состояние профиля</string>\n    <string name=\"netpolicy_reject_metered_data\">Отклонять данные в сетях с лимитным тарифным планом</string>\n    <string name=\"netpolicy_allow_metered_background_data\">Разрешить фоновую передачу данных в сетях с лимитным трафиком, даже если включена функция экономии трафика</string>\n    <string name=\"pref_toggle_internet_msg\">Активируйте интернет возможности в App Manager</string>\n    <string name=\"launch_activity_dialog_title\">Запуск Активити: Требуется Действие</string>\n    <string name=\"pref_use_log_viewer\">Использовать средство просмотра логов</string>\n    <string name=\"netpolicy_reject_metered_background_data\">Отклонить фоновые данные в сетях с лимитным трафиком</string>\n    <string name=\"mode_of_op_custom_command\">Если вы не можете использовать ни один из режимов, вы можете запустить следующую команду в любой поддерживаемой оболочке, чтобы запустить диспетчер приложений в привилегированном режиме:</string>\n    <string name=\"pref_use_vt\">Используйте VirusTotal</string>\n    <string name=\"pref_use_vt_no_internet\">Для работы VirusTotal требуется Интернет, который не включен. Сначала включите <a href=\"app-manager://settings/privacy_prefs/toggle_internet\">\\\"Использовать Интернет\\\"</a>.</string>\n    <string name=\"status_remote_server_inactive\">Удаленный сервер неактивен</string>\n    <string name=\"status_remote_services_active\">Удаленные сервисы активны</string>\n    <string name=\"status_remote_services_inactive\">Удаленные сервисы неактивны</string>\n    <string name=\"status_connecting_via_mode\">Подключение через %s</string>\n    <string name=\"adb_pairing_pairing_code\">Код сопряжения</string>\n    <string name=\"status_connected_via_mode\">Подключено через %s</string>\n    <string name=\"status_not_connected_via_mode\">Не удалось подключиться через %s</string>\n    <string name=\"adb_pairing_instruction\">Перейдите к параметрам разработчика, чтобы включить беспроводную отладку и сгенерировать код сопряжения.</string>\n    <string name=\"adb_pairing_found_pairing_service_with_port\">Найден сервис с портом %d</string>\n    <string name=\"adb_pairing_stop_searching\">Стоп</string>\n    <string name=\"adb_pairing_searching_for_port\">Идет поиск…</string>\n    <string name=\"adb_pairing_input_pairing_code\">Код сопряжения</string>\n    <string name=\"select_filter\">Выберите фильтр</string>\n    <string name=\"size_in_bytes\">Размер (байты)</string>\n    <string name=\"invalid_regex\">Недопустимое регулярное выражение!</string>\n    <string name=\"value_cannot_be_empty\">Значение не может быть пустым!</string>\n    <string name=\"date\">Дата</string>\n    <string name=\"pref_installer\">Используйте установщик</string>\n    <string name=\"pref_cat_general\">Главное</string>\n    <string name=\"status_remote_server_active\">Удаленный сервер активен</string>\n    <string name=\"finder_title\">Поисковик</string>\n    <string name=\"status_connecting\">Подключение…</string>\n    <string name=\"adb_pairing_pairing_in_progress\">Сопряжение…</string>\n    <string name=\"adb_pairing_retry_pairing\">Повтор</string>\n    <string name=\"mode_of_op_custom_command_title\">Пользовательская команда</string>\n    <string name=\"virus_total\">VirusTotal</string>\n    <string name=\"sensors\">Датчики</string>\n    <string name=\"tag_sensors_disabled\">Датчики отключены</string>\n    <string name=\"apk_source\">Источник APK</string>\n    <string name=\"actual_installer\">Фактический установщик</string>\n    <string name=\"pref_use_system_font\">Использовать системный шрифт</string>\n    <string name=\"mode_of_op_alternative_custom_command\">Если при выполнении вышеуказанной команды вы получите ошибку «разрешение отклонено», выполните следующую команду:</string>\n    <string name=\"activity_name\">Имя активити</string>\n    <string name=\"pref_use_system_font_msg\">Использовать системный шрифт по умолчанию вместо material шрифта. <font fgcolor=\"#ff0000\">Это экспериментальная функция.</font></string>\n    <string name=\"backup_cache\">Кэш</string>\n    <string name=\"launch_activity_dialog_message\">App Manager пытается запустить активити через <b>Поисковый помощник</b> (обычно Google Assistant), но не может этого сделать из-за недостаточного разрешения. Для запуска активити, включите <b>Поисковый помощник</b> вручную (обычно это делается долгим нажатием на кнопку Домой). Нажмите на кнопку <b>Закрыть</b> после завершения запуска активити, чтобы вернуться к исходному помощнику.</string>\n</resources>"
  },
  {
    "path": "app/src/main/res/values-si/disclaimer.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- SPDX-License-Identifier: GPL-3.0-or-later --><resources>\n    <string name=\"disclaimer_footer\">© 2020–2024 Muntashir Al-Islam</string>\n</resources>"
  },
  {
    "path": "app/src/main/res/values-si/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- SPDX-License-Identifier: GPL-3.0-or-later --><resources>\n    <string name=\"service\">සේවාවන්</string>\n    <string name=\"authority\">අධිකාරිය</string>\n    <string name=\"no_service\">සේවාවන් නොමැත</string>\n    <string name=\"orientation\">දිශානතිය</string>\n    <string name=\"soft_input\">මෘදු ආදාන ක්‍රමය</string>\n    <string name=\"flags\">කොඩි</string>\n</resources>"
  },
  {
    "path": "app/src/main/res/values-sq/disclaimer.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"disclaimer_header\">Mohim përgjegjësie</string>\n    <string name=\"disclaimer_agree\">Une Pranoj</string>\n    <string name=\"disclaimer_exit\">Dalje</string>\n    <string name=\"disclaimer_footer\">© 2020–2024 Muntashir Al-Islam</string>\n    <string name=\"disclaimer_agree_forever\">Mos e shfaq më kurrë këtë</string>\n    <string name=\"disclaimer_body\">Menaxheri i aplikacionit ofron funksione rrënjësore që mund të dëmtojnë pajisjen tuaj nëse përdoret gabimisht. Menaxheri i aplikacionit nuk është përgjegjës për çdo dëmtim të shkaktuar nga përdorimi i këtij aplikacioni. Nëse nuk jeni plotësisht të vetëdijshëm se si funksionon root, atëherë duhet të shmangni përdorimin e opsioneve root derisa të jeni plotësisht të vetëdijshëm për rreziqet.\n\\n\n\\nÇdo lidhje që unë ofroj me aplikacione dhe faqe interneti të tjera është për përfitimin e përdoruesve. Unë nuk jam përgjegjës për çdo përmbajtje që mund të gjeni duke shkuar në lidhje të jashtme.\n\\n\n\\nDuke përdorur \\\"App Manager\\\", ju pranoni përgjegjësinë e plotë të përdorimit tuaj dhe nuk pranoni asnjë dëmtim, pretendim ose vlerë monetare për shkak të keqpërdorimit.\n\\n\n\\nDuke përdorur këtë aplikacion, ju pranoni të gjithë përgjegjësinë duke e përdorur atë dhe pranoni që unë nuk jam përgjegjës për çdo veprim që bëni që ka një efekt negativ në pajisjen tuaj.</string>\n</resources>"
  },
  {
    "path": "app/src/main/res/values-sq/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\">\n    <string name=\"refresh\">Rifresko</string>\n    <string name=\"receivers\">Marrësit</string>\n    <string name=\"no_activities\">Asnjë Aktivitet</string>\n    <string name=\"no_receivers\">Asnjë Marrës</string>\n    <string name=\"activities\">Aktivitete</string>\n    <string name=\"uninstall\">Fshi</string>\n    <string name=\"class_name\">Emri i klasës</string>\n    <string name=\"uses_feature\">Përdorimi veçorive</string>\n    <string name=\"system\">Sistemi</string>\n    <string name=\"data_received\">Të dhënat e marra</string>\n    <string name=\"app_info\">Info app</string>\n    <string name=\"date_installed\">Data instalimit</string>\n    <string name=\"error_creating_shortcut\">Gabim në krijimin e shkurtores</string>\n    <string name=\"path_permissions\">Lejet e rrugës</string>\n    <string name=\"starting_activity\">Starting activity: <xliff:g id=\"activity_name\" example=\".main.MainActivity\">%1$s</xliff:g></string>\n    <string name=\"media_size\">Media</string>\n    <string name=\"no_service\">S\\'ka shërbime</string>\n    <string name=\"main_activity\">Aktiviteti kryesor</string>\n    <string name=\"empty_package_name\">Emri bosh i paketës</string>\n    <string name=\"declared_permission\">Lejet</string>\n    <string name=\"require_no_permission\">Nuk kerkohet leje</string>\n    <string name=\"sort_by_target_sdk\">SDK e synuar</string>\n    <string name=\"providers\">Ofruesit</string>\n    <string name=\"sdk_min\">Min</string>\n    <string name=\"app_signing_signatures\">Firmat</string>\n    <string name=\"task_affinity\">Afiniteti i detyrës</string>\n    <string name=\"data_transmitted\">Të dhënat e transmetuara</string>\n    <string name=\"flags\">flamuj</string>\n    <string name=\"error\">Gabim</string>\n    <string name=\"user_id\">ID i përdoruesit</string>\n    <string name=\"sort_by_shared_user_id\">ID i shpërndare i përdoruesit</string>\n    <string name=\"data_dir\">Direktoria te Dhenave</string>\n    <string name=\"obb_size\">Obb</string>\n    <string name=\"no_providers\">S\\'ka ofrues</string>\n    <string name=\"create_shortcut\">Krijo shkurtore</string>\n    <string name=\"orientation\">Orientimi</string>\n    <string name=\"sort_by_package_name\">Emri i paketës</string>\n    <string name=\"sort_by_domain\">App të user-it së pari</string>\n    <string name=\"user\">Përdoruesi</string>\n    <string name=\"user_app\">App te përdoruesit</string>\n    <string name=\"app_not_installed\">Aplikacioni nuk është i instaluar</string>\n    <string name=\"about\">Rreth</string>\n    <string name=\"paths_and_directories\">Rrugët &amp; Direktoritë</string>\n    <string name=\"data_size\">Të dhënat</string>\n    <string name=\"sdk_flags\">Flamuj</string>\n    <string name=\"app_signing_no_signatures\">S\\'ka Firmë te vlefshme</string>\n    <string name=\"sdk_max\">Synimi</string>\n    <string name=\"sort_by_last_update\">Përditësimi i fundit</string>\n    <string name=\"authority\">Autoriteti</string>\n    <string name=\"cache_size\">Cache</string>\n    <string name=\"package_name\">Emri Paketes</string>\n    <string name=\"shared_user_id\">ID i shpërndare i përdoruesit</string>\n    <string name=\"no_configurations\">S\\'ka konfigurime</string>\n    <string name=\"shortcut_name\">Emri Shkurtores</string>\n    <string name=\"data_usage_msg\">Përdorim i të dhënave</string>\n    <string name=\"loading\">Po ngarkohet…</string>\n    <string name=\"installer_app\">Instalues App</string>\n    <string name=\"sort\">Rendit</string>\n    <string name=\"system_app\">App te sistemit</string>\n    <string name=\"sort_by_sha\">Firma</string>\n    <string name=\"sort_by_app_label\">Etiketa e aplikacionit</string>\n    <string name=\"manifest\">Manifest</string>\n    <string name=\"launch\">Lanço</string>\n    <string name=\"service\">Shërbimet</string>\n    <string name=\"more_info\">Më shumë Info</string>\n    <string name=\"date_updated\">Data përditësimit</string>\n    <string name=\"permissions\">Lejet e perdorura</string>\n    <string name=\"write\">Shkruan</string>\n    <string name=\"no_feature\">S\\'ka veçori</string>\n    <string name=\"input_features\">Vecorite e inpu-tit</string>\n    <string name=\"launch_mode\">Modaliteti lançimit</string>\n    <string name=\"soft_input\">Modaliteti input butë</string>\n    <string name=\"read\">Lexon</string>\n    <string name=\"patterns_allowed\">Modelet e lejuara</string>\n    <string name=\"group\">Grupi</string>\n    <string name=\"signatures\">Firmat</string>\n    <string name=\"configurations\">Konfigurimet</string>\n    <string name=\"source_dir\">Direktoria e burimit</string>\n    <string name=\"error_verbose_pin_shortcut\">Lëshuesi aktual nuk e mbështet PinShortcut. Nuk mund të krijohet shkurtore.</string>\n    <string name=\"credits\">Kreditë</string>\n    <string name=\"grant_uri_permission\">Jepni lejet URI</string>\n    <string name=\"shared_libs\">Librarite e shpërndara</string>\n    <string name=\"version_name_with_code\">Versioni <xliff:g id=\"version_name\" example=\"2.5.17\">%1$s</xliff:g> (<xliff:g id=\"version_code\" example=\"365\">%2$d</xliff:g>)</string>\n    <string name=\"icon_picker\">Zgjedhësi i ikonave</string>\n    <string name=\"license\">Liçensë</string>\n    <string name=\"third_party\">Librarite dhe ikonat e palëve të treta</string>\n    <string name=\"word_wrap\">Ndrysho mbështjelljen e fjalës</string>\n    <string name=\"credits_message\"></string>\n    <string name=\"key_name_cannot_be_null\">Emri i çelës nuk mund të jetë bosh</string>\n    <string name=\"pref_import_blocker\">Importo nga Blocker</string>\n    <string name=\"disable_background_run\">Parandaloni funksionimin ne sfond</string>\n    <string name=\"usage_weekly\">Javore</string>\n    <string name=\"storage_and_cache\">Magazinimi dhe cache</string>\n    <string name=\"total_size\">Totali</string>\n    <string name=\"app_size\">Aplikacioni</string>\n    <string name=\"apk_updater\">Përditësuesi i APK-së</string>\n    <string name=\"kill_process\">Vrite</string>\n    <string name=\"pid_and_ppid\">ID-ja e procesit: %1$d, ID e procesit prind: %2$d</string>\n    <string name=\"disable_background\">Parandalo funksionimin ne sfond</string>\n    <string name=\"running\">Në ekzekutim</string>\n    <string name=\"duration\">Kohëzgjatja</string>\n    <string name=\"accept_time\">Prano Kohen</string>\n    <string name=\"import_failed\">Importi dështoi!</string>\n    <string name=\"export_failed\">Eksporti dështoi</string>\n    <string name=\"keyboard_type\">Lloji i tastierës</string>\n    <string name=\"touchscreen\">Ekran me prekje</string>\n    <string name=\"force_stop\">Ndalo me forcë</string>\n    <string name=\"view_in_settings\">Shiko te Cilësimet</string>\n    <string name=\"add_item\">Shto artikull</string>\n    <string name=\"day\">Ditë</string>\n    <string name=\"failed_to_extract_apk_file\">Skedari APK nuk mund të estraktohet</string>\n    <string name=\"menu_remove_rules\">Hiç rregullat</string>\n    <string name=\"menu_apply_rules\">Apliko rregullat</string>\n    <string name=\"dev_protected_data_dir\">Vëndodhja e të dhënave e mbrojtur nga pajisja</string>\n    <string name=\"process_name\">Emri i procesit</string>\n    <string name=\"saving_failed\">Ruajtja dëahtoj, provo sërisht</string>\n    <string name=\"type_int\">I plotë</string>\n    <string name=\"uninstall_app_message\">Dëshiron ta ç\\'instalosh këtë aplikacion\\?</string>\n    <string name=\"failed_to_uninstall_app\">C\\'instalimi dështoj</string>\n    <string name=\"pref_global_blocking_enabled_msg\">Ju lejon të bllokoni çdo komponent të çdo aplikacioni pa aktivizuar në mënyrë të qartë bllokimin për aplikacionin.</string>\n    <string name=\"memory_virtual_memory\">Memoria: %1$s, memoria virtuale: %2$s</string>\n    <string name=\"the_operation_was_successful\">U krye</string>\n    <string name=\"toggle_kill_for_system_apps\">Aktivizo vrasjen e aplikacioneve të sistemit</string>\n    <string name=\"usage_today\">Sot</string>\n    <string name=\"usage_7_days\">7 ditët e fundit</string>\n    <string name=\"native_library_dir\">Vëndndodhja e Librarisë Native JNI</string>\n    <string name=\"no_code\">S\\'ka kode</string>\n    <string name=\"updated_app\">Përditësuar</string>\n    <string name=\"shared_prefs\">Preferencat e shperndara</string>\n    <string name=\"integer_value\">Vlera e plotë</string>\n    <string name=\"decimal_value\">Vlera deçimale</string>\n    <string name=\"done\">U krye</string>\n    <string name=\"type_boolean\">E vërtetë / e rreme</string>\n    <string name=\"uninstalled_successfully\"><xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g> është çinstaluar.</string>\n    <string name=\"stopped\">Ndaluar</string>\n    <string name=\"disable\">Ç\\'aktivizo</string>\n    <string name=\"app_ops\">Operacinet e aplikacionit</string>\n    <string name=\"exodus_link\">Lidhja për εxodus</string>\n    <string name=\"sort_by_screen_time\">Koha e ekranit</string>\n    <string name=\"user_and_uid\">Perdorues: <xliff:g id=\"user_name\" example=\"root\">%1$s</xliff:g> (<xliff:g id=\"user_id\" example=\"0\">%2$d</xliff:g>)</string>\n    <string name=\"pref_import_export_blocking_rules\">Rregullat e bllokimit të import/eksportit</string>\n    <string name=\"the_export_was_successful\">I eksportuar</string>\n    <plurals name=\"failed_to_import_files\">\n        <item quantity=\"one\">%1$d skedar nuk mund të importohej.</item>\n        <item quantity=\"other\">%1$d skedaret nuk mund të importohej.</item>\n    </plurals>\n    <string name=\"backup_restore\">Rekupero/Rivendos</string>\n    <string name=\"export_blocking_rules\">eksporto rregullat e bllokimit</string>\n    <string name=\"export_options\">Opsionet e Eksportit</string>\n    <string name=\"pref_app_theme\">Emri aplikacionit</string>\n    <string name=\"battery_mode\">Modaliteti i baterisë</string>\n    <string name=\"block_trackers\">Blloko gjurmuesit</string>\n    <string name=\"sort_by_component_name\">Emri komponetëve</string>\n    <string name=\"external_data_dir\">Vedndodhja e të dhënave të jashtme</string>\n    <string name=\"user_with_id\">Prdorues: <xliff:g id=\"user_id\" example=\"0\">%1$d</xliff:g></string>\n    <string name=\"import_options\">Opsionet e Importit</string>\n    <string name=\"pref_import_msg\">Importoni rregullat e bllokimit të eksportuara më parë nga \\\"Menaxheri i aplikacionit\\\".</string>\n    <string name=\"pref_import_watt_msg\">Importoni rregullat e bllokimit nga Watt, çdo skedar përmban rregulla për një paketë të vetme të emërtuar si <tt>packagename.xml</tt> etj.</string>\n    <string name=\"version\">Versioni</string>\n    <string name=\"grant_usage_acess_message\">Përdoret për të shfaqur informacionin e përdorimit të app-it</string>\n    <string name=\"search\">Kërko</string>\n    <string name=\"follow_system\">Ndiqni sistemin</string>\n    <string name=\"ago\">më parë</string>\n    <string name=\"pref_import\">Importo</string>\n    <string name=\"deny_dangerous_app_ops\">Moho funksionet e rrezikshme të aplikacionit</string>\n    <string name=\"databases\">Baza e të dhënave</string>\n    <string name=\"long_integer_value\">Vlera e gjatë e plotë</string>\n    <string name=\"usage_access\">Qasja e përdorimit</string>\n    <string name=\"pref_about_msg\">Versioni i menaxherit të aplikacionit, licenca, kreditet, etj.</string>\n    <string name=\"navigation\">Navigimi</string>\n    <string name=\"pref_import_watt\">Importo nga Watt</string>\n    <string name=\"night\">Natë</string>\n    <string name=\"pref_import_export_blocking_rules_msg\">Rregullat e importit/eksportit, importoni rregullat e jashtme nga Watt ose Blocker.</string>\n    <string name=\"pref_import_blocker_msg\">Importoni rregullat e bllokimit nga Blocker, çdo skedar përmban rregulla për një paketë të vetme.</string>\n    <string name=\"select_theme\">Tema</string>\n    <string name=\"pref_export_msg\">Eksporto rregullat e bllokimit të konfiguruara brenda Menaxherit të Aplikacioneve në hapësirën ruajtëse të jashtme.</string>\n    <string name=\"error_evaluating_input\">Imput-i nuk mund të vlerësohej</string>\n    <string name=\"test_only\">Vetëm test</string>\n    <string name=\"boolean_value\">Vlera Boolean</string>\n    <string name=\"type_float\">Numer deçimal</string>\n    <string name=\"str_logo\">Logoja</string>\n    <string name=\"no_content\">S\\'ka përmbajtje</string>\n    <string name=\"sort_by_last_used\">Përdorur për herë të fundit</string>\n    <string name=\"grant_usage_access\">Lejo aksesin e përdorimit</string>\n    <string name=\"saved_successfully\">U ruajt</string>\n    <string name=\"reset_to_default\">Rivendos si ishte më parë</string>\n    <string name=\"share_apk\">Shpërnda APK-në</string>\n    <string name=\"sort_by_times_opened\">Kohët u hapën</string>\n    <string name=\"select_type\">Zgjidh tipin</string>\n    <string name=\"uninstall_system_app_message\">Ky është një aplikacion sistemi. Je i sigurt që dëshiron ta ç\\'instalosh këtë aplikacion\\?</string>\n    <string name=\"pref_global_blocking_enabled\">Bllokim i menjëhershëm i komponentëve</string>\n    <string name=\"rules_not_applied\">Rregullat nuk jane te aplikuara</string>\n    <string name=\"save\">Ruaj</string>\n    <string name=\"type_long\">i plotë i gjatë</string>\n    <string name=\"string_value\">Vlerat e vargut</string>\n    <string name=\"sort_by_wifi_data\">Të dhënat Wi-Fi</string>\n    <string name=\"sort_by_app_ops_names\">Emri i funksioneve të aplikacionit</string>\n    <string name=\"deleted_successfully\">E fshirë</string>\n    <string name=\"failed_to_uninstall\">Could not uninstall <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g>.</string>\n    <string name=\"failed_to_disable_op\">Operacioni i aplikacionit të kërkuar nuk mund të ç,tivizohet</string>\n    <string name=\"second_degree_tracker_note\">² prefiksi tregon se gjurmuesit janë në <a href=\"https://etip.exodus-privacy.eu.org/\">ETIP stand-by list</a> i.e. nëse ata janë gjurmues të vërtetë janë ende duke u hetuar.</string>\n    <string name=\"delete\">Fshije</string>\n    <string name=\"no_usage_in_this_time_range\">Nuk ka përdorim në këtë interval kohor</string>\n    <string name=\"debuggable\">Debuggable</string>\n    <string name=\"sort_by_mobile_data\">Të dhënat celulare</string>\n    <string name=\"failed_to_stop\">Nuk mund të ndalohet <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g>.</string>\n    <string name=\"sort_by_blocked_components\">Të blllokuarat se pari</string>\n    <string name=\"requested_large_heap\">Grumbull i madh</string>\n    <string name=\"failed_to_enable_op\">Operacioni i aplikacionit të kërkuar nuk mund të aktivizohet</string>\n    <string name=\"sort_by_denied_app_ops\">Të mohuarat së pari</string>\n    <string name=\"type_string\">Karakteret</string>\n    <string name=\"no_app_ops\">Asnjë operacion aplikacioni</string>\n    <string name=\"apply\">Apliko</string>\n    <string name=\"disabled_app\">Ç\\'aktivizuar</string>\n    <string name=\"deletion_failed\">Fshirja dështoi</string>\n    <string name=\"the_import_was_successful\">I importuar</string>\n    <string name=\"go_back\">Kthehu mbrapa</string>\n    <string name=\"permission_name\">Emri i lejes</string>\n    <string name=\"go\">Shko</string>\n    <string name=\"mode\">Modaliteti</string>\n    <plurals name=\"usage_hours\">\n        <item quantity=\"one\">%1$d hr</item>\n        <item quantity=\"other\">%1$d hrs</item>\n    </plurals>\n    <plurals name=\"tracker_and_classes\">\n        <item quantity=\"one\">1 tracker with <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g> class</item>\n        <item quantity=\"other\">1 tracker with <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g> classes</item>\n    </plurals>\n    <plurals name=\"two_trackers_and_classes\">\n        <item quantity=\"one\">2 trackers with <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g> classes</item>\n        <item quantity=\"other\">2 trackers with <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g> classes</item>\n    </plurals>\n    <plurals name=\"main_list_date_days\">\n        <item quantity=\"one\"><xliff:g id=\"last_update_date\" example=\"20/10/2020\">%1$s</xliff:g> <xliff:g id=\"day_no\" example=\"5\">%2$d</xliff:g> day</item>\n        <item quantity=\"other\"><xliff:g id=\"last_update_date\" example=\"20/10/2020\">%1$s</xliff:g> <xliff:g id=\"day_no\" example=\"5\">%2$d</xliff:g> days</item>\n    </plurals>\n    <plurals name=\"usage_seconds\">\n        <item quantity=\"one\">%1$d sec</item>\n        <item quantity=\"other\">%1$d secs</item>\n    </plurals>\n    <plurals name=\"no_of_times_opened\">\n        <item quantity=\"one\">%1$d koh</item>\n        <item quantity=\"other\">%1$d kohet</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_clear_data\">\n        <item quantity=\"one\">Nuk mund të pastrohen të dhënat nga aplikacioni %1$d</item>\n        <item quantity=\"other\">Nuk mund të pastrohen të dhënat nga %1$d aplikacionet</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_force_stop\">\n        <item quantity=\"one\">Aplikacioni %1$d nuk mund të ndalohet me forcë</item>\n        <item quantity=\"other\">Aplikacionet %1$d nuk mund të ndalohen me forcë</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_uninstall\">\n        <item quantity=\"one\">%1$d aplikacioni nuk mund të çinstalohet</item>\n        <item quantity=\"other\">%1$d aplikacionet nuk mund të çinstalohen</item>\n    </plurals>\n    <plurals name=\"usage_minutes\">\n        <item quantity=\"one\">%1$d min</item>\n        <item quantity=\"other\">%1$d mins</item>\n    </plurals>\n    <string name=\"usage_less_than_a_minute\">Më pak se një minutë</string>\n    <string name=\"discard\">Hidhe</string>\n    <string name=\"usage_yesterday\">Dje</string>\n    <string name=\"app_usage\">Përdorimi aplikacionit</string>\n    <string name=\"key_name\">Emri kyç</string>\n    <string name=\"enable\">Aktivizo</string>\n    <string name=\"external_multiple_data_dir\">Vendndodhja e të dhënave të jashtme <xliff:g id=\"dir_no\" example=\"1\">%1$d</xliff:g></string>\n    <string name=\"app_settings\">Cilësimet</string>\n    <string name=\"running_apps\">Aplikacionet ne ekzekutim</string>\n    <string name=\"clear_data\">Pastro te dhënat</string>\n    <plurals name=\"alert_failed_to_disable_background\">\n        <item quantity=\"one\">Nuk mund të parandalohet %1$d aplikacioni që ekzekutohet në sfond</item>\n        <item quantity=\"other\">Nuk mund të parandalohen %1$d aplikacionet që ekzekutohen në sfond</item>\n    </plurals>\n    <string name=\"reject_time\">Refuzo kohën</string>\n    <string name=\"pref_export\">Eksporto</string>\n    <string name=\"class_viewer\">Shikuesi i klasës</string>\n    <string name=\"toggle_class_listing\">Aktivizo/Ç\\'aktivizo listën e klasave</string>\n    <string name=\"found_trackers\">Gjurmuesit e gjetur:</string>\n    <string name=\"tracker_details\">Detajet e gjurmuesit</string>\n    <string name=\"tracker_classes\">Klasat e gjrmuesit</string>\n    <string name=\"all_classes\">Të gjitha klasat</string>\n    <string name=\"no_shared_libs\">S\\'ka librari te shperndara</string>\n    <string name=\"no_tracker_class\">S\\'ka klasa gjurmuesi</string>\n    <plurals name=\"other_trackers_and_classes\">\n        <item quantity=\"one\"><xliff:g id=\"tracker_no\" example=\"8\">%1$d</xliff:g> trackers with <xliff:g id=\"class_no\" example=\"50\">%2$d</xliff:g> classes</item>\n        <item quantity=\"other\"><xliff:g id=\"tracker_no\" example=\"8\">%1$d</xliff:g> trackers with <xliff:g id=\"class_no\" example=\"50\">%2$d</xliff:g> classes</item>\n    </plurals>\n    <plurals name=\"usage_months\">\n        <item quantity=\"one\">%1$d mo</item>\n        <item quantity=\"other\">%1$d mos</item>\n    </plurals>\n    <plurals name=\"usage_days\">\n        <item quantity=\"one\">%1$d day</item>\n        <item quantity=\"other\">%1$d days</item>\n    </plurals>\n    <string name=\"external_apk_no_app_op\">APK-ja e jashtme nuk ka asnje veprim aplikacioni</string>\n    <string name=\"install\">Instaloje</string>\n    <plurals name=\"no_of_trackers\">\n        <item quantity=\"one\">Gjurmuesi %1$d</item>\n        <item quantity=\"other\">Gjurmuesat %1$d</item>\n    </plurals>\n    <plurals name=\"no_of_components\">\n        <item quantity=\"one\">Përbërësi %1$d</item>\n        <item quantity=\"other\">Përbërësit %1$d</item>\n    </plurals>\n    <string name=\"failed_to_deny_dangerous_perms\">Num munda t\\'i heq të gjitha lejet e rrezikshme</string>\n    <string name=\"sort_by_denied_permissions\">Të refuzuarat në fillim</string>\n    <string name=\"deny_dangerous_permissions\">Refuzoji lejet e rrezikshme</string>\n    <string name=\"unknown_op\">Veprim i panjohur</string>\n    <string name=\"failed_to_reset_app_ops\">Nuk munda t\\'i zeroj opset e aplikacionit</string>\n    <string name=\"launch_app\">Lançoje</string>\n    <string name=\"changelog\">Regjistri i ndryshimeve</string>\n    <string name=\"source_code\">Kodi i burimit</string>\n    <string name=\"never_ask\">Mos pyet kurrë</string>\n    <string name=\"one_click_ops\">Opse me 1 klikim</string>\n    <string name=\"manifest_viewer\">Shikuesi i manifestuar</string>\n    <string name=\"failed_to_deny_dangerous_app_ops\">Nuk munda t\\'i heq të gjitha opset e rrezikshme të aplikacionit</string>\n    <string name=\"sort_by_dangerous_permissions\">Të rrezikshmet në fillim</string>\n    <string name=\"failed_to_grant_permission\">Num munda t\\'i jap lejen</string>\n    <string name=\"sort_by_app_ops_values\">Vlera ops e aplikacionit</string>\n    <string name=\"failed_to_revoke_permission\">Nuk munda t\\'i heq lejen</string>\n    <string name=\"sort_by_permission_names\">Emri i lejes</string>\n    <plurals name=\"alert_failed_to_disable_trackers\">\n        <item quantity=\"one\">Nuk munda t\\'i heq gjurmuesit nga aplikacioni %1$d</item>\n        <item quantity=\"other\">Nuk munda t\\'i heq gjurmuesit nga aplikacionet %1$d</item>\n    </plurals>\n    <string name=\"update\">Përditësoje</string>\n    <string name=\"sort_by_tracker_components\">Gjurmuesit në fillim</string>\n</resources>"
  },
  {
    "path": "app/src/main/res/values-sv/disclaimer.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"disclaimer_footer\">© 2020–2024 Muntashir Al-Islam</string>\n</resources>"
  },
  {
    "path": "app/src/main/res/values-sv/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"permissions\">användarbehörigheter</string>\n    <string name=\"uninstall\">avinstallera</string>\n    <string name=\"launch\">starta</string>\n    <string name=\"no_service\">inga tjänster</string>\n    <string name=\"group\">grupp</string>\n    <string name=\"no_receivers\">inga mottagare</string>\n    <string name=\"service\">tjänst</string>\n    <string name=\"launch_mode\">startläge</string>\n    <string name=\"error\">fel</string>\n    <string name=\"authority\">auktoritet</string>\n    <string name=\"receivers\">mottagare</string>\n    <string name=\"write\">skriv</string>\n    <string name=\"providers\">leverantörer</string>\n    <string name=\"read\">läs</string>\n    <string name=\"no_providers\">inga leverantörer</string>\n    <string name=\"require_no_permission\">inga behörigheter krävs</string>\n    <string name=\"refresh\">uppdatera</string>\n    <string name=\"activities\">aktiviteter</string>\n    <string name=\"signatures\">signaturer</string>\n    <string name=\"no_activities\">inga aktiviteter</string>\n    <string name=\"sort_by_last_update\">senaste uppdateringen</string>\n    <string name=\"settings\">Inställningar</string>\n    <string name=\"flags\">Flaggor</string>\n    <string name=\"patterns_allowed\">tillåtna mönster</string>\n    <string name=\"source_code\">Källkod</string>\n    <string name=\"app_signing_signatures\">Signaturer</string>\n    <string name=\"app_signing_no_signatures\">Inga giltiga signaturer</string>\n    <string name=\"shared_user_id\">Delat användar-ID</string>\n    <string name=\"sort_by_shared_user_id\">Delat användar-ID</string>\n    <string name=\"orientation\">Orientering</string>\n    <string name=\"sort_by_sha\">Signatur</string>\n    <string name=\"declared_permission\">Behörigheter</string>\n    <string name=\"uses_feature\">Använder funktioner</string>\n    <string name=\"configurations\">Konfigurationer</string>\n    <string name=\"shared_libs\">Delade bibliotek</string>\n    <string name=\"path_permissions\">Sökvägsbehörigheter</string>\n    <string name=\"no_feature\">Inga funktioner</string>\n    <string name=\"no_configurations\">Inga konfigurationer</string>\n    <string name=\"loading\">Laddar…</string>\n    <string name=\"user\">Användare</string>\n    <string name=\"sort\">Sortera</string>\n    <string name=\"system_app\">Systemapp</string>\n    <string name=\"user_app\">Användarapp</string>\n    <string name=\"license\">Licens</string>\n</resources>"
  },
  {
    "path": "app/src/main/res/values-tr-rTR/disclaimer.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- SPDX-License-Identifier: GPL-3.0-or-later --><resources>\n    <string name=\"disclaimer_agree\">Kabul Ediyorum</string>\n    <string name=\"disclaimer_exit\">Çıkış</string>\n    <string name=\"disclaimer_body\">App Manager, yanlış kullanıldığında aygıtınıza zarar verebilecek root işlevleri sunar. App Manager, bu uygulama kullanılarak yapılan herhangi bir zarardan sorumlu değildir. Root işlevlerinin nasıl çalıştığını tam olarak bilmiyorsanız, risklerin tam olarak farkına varana kadar root seçeneklerini kullanmaktan kaçınmalısınız.\n\\n\n\\nDiğer uygulamalara ve web sitelerine sağladığım herhangi bir bağlantı, kullanıcılara yardım etmek içindir. Dış bağlantılara giderek bulabileceğiniz hiçbir içerikten sorumlu değilim.\n\\n\n\\nApp Manager kullanarak kendi kullanımınızın tüm sorumluluğunu kabul edersiniz ve kötüye kullanım nedeniyle hiçbir hasar, hak talebi veya parasal değer verilmeyeceğini kabul edersiniz.\n\\n\n\\nBu uygulamayı kullanarak onu kullanmanın tüm sorumluluğunu üzerinize alırsınız ve aygıtınızı olumsuz yönde etkileyen herhangi bir eylemden sorumlu olmadığımı kabul edersiniz.</string>\n    <string name=\"disclaimer_agree_forever\">Bunu bir daha gösterme</string>\n    <string name=\"disclaimer_footer\">© 2020–2024 Muntashir Al-Islam</string>\n    <string name=\"disclaimer_header\">Sorumluluk Reddi</string>\n</resources>"
  },
  {
    "path": "app/src/main/res/values-tr-rTR/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- SPDX-License-Identifier: GPL-3.0-or-later --><resources xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:tools=\"http://schemas.android.com/tools\">\n    <string name=\"_lang_tag\" translatable=\"false\">tr-TR</string>\n    <string name=\"uninstall\">Uygulamayı Kaldır</string>\n    <string name=\"permissions\">Kullanılan izinler</string>\n    <string name=\"require_no_permission\">İzin gerektirmez</string>\n    <string name=\"activities\">Etkinlikler</string>\n    <string name=\"launch\">Başlat</string>\n    <string name=\"refresh\">Yenile</string>\n    <string name=\"no_activities\">Etkinlik yok</string>\n    <string name=\"receivers\">Alıcılar</string>\n    <string name=\"no_receivers\">Alıcılar yok</string>\n    <string name=\"providers\">Sağlayıcılar</string>\n    <string name=\"no_providers\">Sağlayıcı yok</string>\n    <string name=\"launch_mode\">Başlatma Modu</string>\n    <string name=\"task_affinity\">Görev İlgisi</string>\n    <string name=\"sort_by_last_update\">Son güncelleme</string>\n    <string name=\"authority\">Yetki</string>\n    <string name=\"service\">Hizmetler</string>\n    <string name=\"no_service\">Servis yok</string>\n    <string name=\"orientation\">Yönlendirme</string>\n    <string name=\"soft_input\">Yumuşak giriş modu</string>\n    <string name=\"flags\">İşaretler</string>\n    <string name=\"grant_uri_permission\">URI izinlerini ver</string>\n    <string name=\"path_permissions\">Yol İzinleri</string>\n    <string name=\"read\">Oku</string>\n    <string name=\"write\">Yaz</string>\n    <string name=\"patterns_allowed\">İzin verilen desenler</string>\n    <string name=\"declared_permission\">İzinler</string>\n    <string name=\"shared_libs\">Paylaşılan kütüphaneler</string>\n    <string name=\"group\">Grup</string>\n    <string name=\"uses_feature\">Kullanılan özellikler</string>\n    <string name=\"no_feature\">Özellik yok</string>\n    <string name=\"sort_by_shared_user_id\">Paylaşılan kullanıcı kimliği</string>\n    <string name=\"shared_user_id\">Paylaşılan kullanıcı kimliği</string>\n    <string name=\"sort_by_sha\">İmza</string>\n    <string name=\"signatures\">İmzalar</string>\n    <string name=\"app_signing_no_signatures\">Geçerli imza yok</string>\n    <string name=\"configurations\">Yapılandırmalar</string>\n    <string name=\"no_configurations\">Yapılandırma yok</string>\n    <string name=\"input_features\">Giriş özellikleri</string>\n    <string name=\"manifest\">Bildirim</string>\n    <string name=\"error\">Hata</string>\n    <string name=\"loading\">Yükleniyor…</string>\n    <string name=\"sort_by_app_label\">Uygulama etiketleri</string>\n    <string name=\"sort_by_package_name\">Paket adı</string>\n    <string name=\"sort_by_domain\">Önce kullanıcı uygulamaları</string>\n    <string name=\"data_received\">Alınan veriler</string>\n    <string name=\"data_transmitted\">İletilen veriler</string>\n    <string name=\"data_usage_msg\">Veri kullanımı</string>\n    <string name=\"about\">Hakkında</string>\n    <string name=\"data_size\">Kullanıcı Verisi</string>\n    <string name=\"cache_size\">Önbellek</string>\n    <string name=\"obb_size\">Obb</string>\n    <string name=\"media_size\">Ortam</string>\n    <string name=\"app_not_installed\">Uygulama kurulu değil</string>\n    <string name=\"system\">Sistem</string>\n    <string name=\"user\">Kullanıcı</string>\n    <string name=\"sort\">Sıralama</string>\n    <string name=\"version_name_with_code\">Sürüm <xliff:g id=\"version_name\" example=\"2.5.17\">%1$s</xliff:g> (<xliff:g id=\"version_code\" example=\"365\">%2$d</xliff:g>)</string>\n    <string name=\"app_info\">Uygulama Bilgisi</string>\n    <string name=\"system_app\">Sistem uygulamaları</string>\n    <string name=\"user_app\">Kullanıcı uygulaması</string>\n    <string name=\"source_dir\">Kaynak Dizin</string>\n    <string name=\"data_dir\">Veri Dizini</string>\n    <string name=\"sdk_min\">En az</string>\n    <string name=\"sdk_max\">Hedef</string>\n    <string name=\"sdk_flags\">İşaretler</string>\n    <string name=\"more_info\">Daha Fazla Bilgi</string>\n    <string name=\"date_installed\">Kurulum Tarihi</string>\n    <string name=\"date_updated\">Güncellenme tarihi</string>\n    <string name=\"installer_app\">Uygulama Kurucu</string>\n    <string name=\"user_id\">Kullanıcı ID</string>\n    <string name=\"main_activity\">Asıl Faaliyet</string>\n    <string name=\"empty_package_name\">Boş paket adı</string>\n    <string name=\"error_creating_shortcut\">Kısayol oluşturulurken hata oluştu</string>\n    <string name=\"error_verbose_pin_shortcut\">Geçerli başlatıcısı \\\"PinShortcut\\\" özelliğini desteklemiyor. Kısayol oluşturulamıyor.</string>\n    <string name=\"grant_usage_acess_message\">Uygulama kullanım bilgilerini görüntülemek için kullanılır.</string>\n    <string name=\"share_apk\">APK\\'yi Paylaş</string>\n    <string name=\"failed_to_extract_apk_file\">APK dosyası çıkarılamadı</string>\n    <string name=\"menu_remove_rules\">Kuralları Kaldır</string>\n    <string name=\"menu_apply_rules\">Kuralları Uygula</string>\n    <string name=\"search\">Arama</string>\n    <string name=\"dev_protected_data_dir\">Aygıt Korumalı Veri Dizini</string>\n    <string name=\"native_library_dir\">Yerel JNI Kütüphane dizini</string>\n    <string name=\"process_name\">İşlem adı</string>\n    <string name=\"no_code\">Kod yok</string>\n    <string name=\"requested_large_heap\">Büyük metin</string>\n    <string name=\"updated_app\">Güncelleme</string>\n    <string name=\"select_all\">Tümünü Seç</string>\n    <string name=\"installed_version\">Kurulu Sürüm</string>\n    <string name=\"trackers\">İzleyiciler</string>\n    <string name=\"components\">Bileşenler</string>\n    <string name=\"features\">Özellikler</string>\n    <string name=\"whats_new\">Yenilikler</string>\n    <string name=\"blocking_rules\">Engelleme kuralları</string>\n    <string name=\"external_data\">Harici veri</string>\n    <string name=\"data\">Veri</string>\n    <string name=\"backup\">Yedekleme</string>\n    <string name=\"restore\">Geri Yükle</string>\n    <string name=\"delete_backup\">Yedeklemeyi sil</string>\n    <string name=\"backup_options\">Yedekleme Seçenekleri</string>\n    <string name=\"apply_to_system_apps\">Sistem uygulamalarına Uygula</string>\n    <string name=\"apply_to_system_apps_question\">Sistem uygulamaları için de geçerli mi\\? Emin değilseniz \\\"Hayır\\\"ı seçin.</string>\n    <string name=\"no\">Hayır</string>\n    <string name=\"yes\">Evet</string>\n    <string name=\"skip_signature_checks\">İmza denetimlerini atla</string>\n    <string name=\"clear_data_message\">Bu uygulamadan verileri temizlemek istediğinizden emin misiniz?</string>\n    <string name=\"clear\">Temizle</string>\n    <string name=\"third_party\">Üçüncü Parti Kütüphaneler ve Simgeler</string>\n    <string name=\"license\">Lisans</string>\n    <string name=\"icon_picker\">Simge Seçici</string>\n    <string name=\"class_name\">Sınıf Adı</string>\n    <string name=\"package_name\">Paket Adı</string>\n    <string name=\"shortcut_name\">Kısayol Adı</string>\n    <string name=\"export_icon\">Simgeyi Çıkar</string>\n    <string name=\"state_multithreaded\">Çoklu kullanım</string>\n    <string name=\"state_low_priority\">Düşük öncelikli</string>\n    <string name=\"state_high_priority\">Yüksek öncelikli</string>\n    <string name=\"state_foreground\">Ön planda</string>\n    <string name=\"state_session_leader\">Oturum lideri</string>\n    <string name=\"state_locked_memory\">Kilitli bellek</string>\n    <string name=\"state_unknown\">Bilinmeyen</string>\n    <string name=\"state_waking\">Uykuda</string>\n    <string name=\"state_wake_kill\">Uyanma iptali</string>\n    <string name=\"state_idle\">Boşta</string>\n    <string name=\"state_parked\">Beklemede</string>\n    <string name=\"state_zombie\">Zombi</string>\n    <string name=\"state_dead\">Ölü</string>\n    <string name=\"state_trace_stop\">İzleme durdurma</string>\n    <string name=\"state_device_io\">Aygıt G/Ç</string>\n    <string name=\"state_sleeping\">Uykuda</string>\n    <string name=\"non_critical_exts\">Kritik Olmayan Uzantılar</string>\n    <string name=\"critical_exts\">Kritik Uzantılar</string>\n    <string name=\"dsa_affine_y\">Afin y koordinatı</string>\n    <string name=\"dsa_affine_x\">Afin x koordinatı</string>\n    <string name=\"rsa_modulus\">Modüler</string>\n    <string name=\"rsa_exponent\">Üs</string>\n    <string name=\"format\">Biçim</string>\n    <string name=\"public_key\">Ortak Anahtar</string>\n    <string name=\"algorithm\">Algoritma</string>\n    <string name=\"app_signing_signature\">İmza</string>\n    <string name=\"checksums\">Sağlama toplamları</string>\n    <string name=\"serial_no\">Seri Numarası</string>\n    <string name=\"not_yet_valid\">Henüz geçerli değil</string>\n    <string name=\"expired\">Süresi doldu</string>\n    <string name=\"valid\">Geçerli</string>\n    <string name=\"validity\">Geçerlilik</string>\n    <string name=\"type\">Tür</string>\n    <string name=\"expiry_date\">Bitiş tarihi</string>\n    <string name=\"issued_date\">Veriliş tarihi</string>\n    <string name=\"issuer\">Veren</string>\n    <string name=\"subject\">Konu</string>\n    <string name=\"filter_apps_with_backups\">Yedekleri olan</string>\n    <string name=\"sort_by_backup\">Önce yedeklenen</string>\n    <string name=\"failed_to_uninstall_updates\"><xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g> için güncellemeler kaldırılamadı.</string>\n    <string name=\"update_uninstalled_successfully\"><xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g> için güncellemeler kaldırıldı.</string>\n    <string name=\"uninstall_updates\">Güncellemeleri Kaldır</string>\n    <string name=\"allow_open_pgp_operation\">App Manager\\'in OpenPGP\\'yi kullanmasına izin vermek için dokunun</string>\n    <string name=\"confirm_installation\">Kurulumu onayla</string>\n    <string name=\"pref_backup_flags_msg\">Yedekleme seçenekleri için bir ön ayar eklemek, her yedekleme/geri yükleme işleminizde işaretleri seçme yükünü ortadan kaldırır.</string>\n    <string name=\"pref_compression_method\">Sıkıştırma yöntemi</string>\n    <string name=\"rules\">Kurallar</string>\n    <string name=\"other\">Diğer</string>\n    <string name=\"changes_not_saved\">Değişiklikler kaydedilmedi</string>\n    <string name=\"sort_by_memory_usage\">Bellek kullanımı</string>\n    <string name=\"sort_by_apps_first\">Önce uygulamalar</string>\n    <string name=\"sort_by_process_name\">İşlem adı</string>\n    <string name=\"sort_by_process_id\">İşlem kimliği</string>\n    <string name=\"filter_apps\">Uygulamalar</string>\n    <string name=\"no_apps\">Uygulama yok</string>\n    <string name=\"apps\">Uygulamalar</string>\n    <string name=\"routine_ops\">Rutin işlemler</string>\n    <string name=\"apply_now\">Şimdi uygula…</string>\n    <string name=\"keystore\">KeyStore</string>\n    <string name=\"no_profiles\">Profil yok</string>\n    <string name=\"profiles\">Profiller</string>\n    <string name=\"open_pgp_provider\">OpenPGP Sağlayıcısı</string>\n    <string name=\"systemless_app\">Sistemsiz Uygulama</string>\n    <string name=\"cancel\">İptal</string>\n    <string name=\"ok\">Tamam</string>\n    <string name=\"input_backup_name_description\">Yedek adı bir rakamla başlamamalı ve boşluk karakterleri içermemelidir. Geçerli tarih-saati kullanmak istiyorsanız boş bırakın.</string>\n    <string name=\"input_backup_name\">Yedek adı</string>\n    <string name=\"downgrade\">Sürüm düşür</string>\n    <string name=\"process_state_with_extra\">Durum: <xliff:g id=\"process_state\" example=\"Sleeping\">%1$s</xliff:g> (<xliff:g id=\"state_extra\" example=\"High priority\">%2$s</xliff:g>)</string>\n    <string name=\"process_state\">Durum: <xliff:g id=\"process_state\" example=\"Sleeping\">%1$s</xliff:g></string>\n    <string name=\"touchscreen_finger\">Parmak</string>\n    <string name=\"touchscreen_stylus\">Kalem</string>\n    <string name=\"touchscreen_no_touch\">Dokunma yok</string>\n    <string name=\"navigation_wheel\">Tekerlek</string>\n    <string name=\"navigation_trackball\">Trackball</string>\n    <string name=\"navigation_dial_pad\">Tuş takımı</string>\n    <string name=\"navigation_no_nav\">Gezinme yok</string>\n    <string name=\"keyboard_12_keys\">12 tuş</string>\n    <string name=\"keyboard_no_keys\">Tuş yok</string>\n    <string name=\"keyboard_qwerty\">QWERTY</string>\n    <string name=\"_undefined\">Tanımsız</string>\n    <string name=\"required\">Gerekli</string>\n    <string name=\"orientation_user_portrait\">Kullanıcı dikey</string>\n    <string name=\"orientation_user_landscape\">Kullanıcı yatay</string>\n    <string name=\"orientation_sensor\">Sensör</string>\n    <string name=\"orientation_sensor_portrait\">Sensör dikey</string>\n    <string name=\"orientation_sensor_landscape\">Sensör yatay</string>\n    <string name=\"orientation_user\">Kullanıcı</string>\n    <string name=\"orientation_reverse_landscape\">Ters yatay</string>\n    <string name=\"orientation_reverse_portrait\">Ters dikey</string>\n    <string name=\"orientation_portrait\">Dikey</string>\n    <string name=\"orientation_landscape\">Yatay</string>\n    <string name=\"orientation_no_sensor\">Sensör yok</string>\n    <string name=\"orientation_locked\">Kilitli</string>\n    <string name=\"orientation_full_user\">Tam kullanıcı</string>\n    <string name=\"orientation_full_sensor\">Tam sensör</string>\n    <string name=\"orientation_behind\">Arkasında</string>\n    <string name=\"orientation_unspecified\">Belirtilmemiş</string>\n    <string name=\"launch_mode_single_top\">Tek üst</string>\n    <string name=\"launch_mode_single_task\">Tek görev</string>\n    <string name=\"launch_mode_single_instance\">Tek örnek</string>\n    <string name=\"launch_mode_multiple\">Çoklu</string>\n    <string name=\"locale_split_for_base_apk\">Temel APK için <xliff:g id=\"split_name\" example=\"English\">%1$s</xliff:g> yerel ayarı</string>\n    <string name=\"locale_split_for_feature\"><xliff:g id=\"feature_name\" example=\"Visualizer\">%2$s</xliff:g> özelliği için <xliff:g id=\"split_name\" example=\"English\">%1$s</xliff:g> yerel ayarı</string>\n    <string name=\"abi_split_for_base_apk\">Temel APK için <xliff:g id=\"split_name\" example=\"arm64_v8a\">%1$s</xliff:g> kodu</string>\n    <string name=\"abi_split_for_feature\"><xliff:g id=\"feature_name\" example=\"Visualizer\">%2$s</xliff:g> için <xliff:g id=\"split_name\" example=\"arm64_v8a\">%1$s</xliff:g> kodu</string>\n    <string name=\"density_split_for_base_apk\">Temel APK için <xliff:g id=\"split_name\" example=\"xxdpi\">%1$s</xliff:g> (<xliff:g id=\"dpi_no\" example=\"480\">%2$d</xliff:g> DPI) kaynakları</string>\n    <string name=\"density_split_for_feature\"><xliff:g id=\"feature_name\" example=\"Visualizer\">%3$s</xliff:g> özelliği için <xliff:g id=\"split_name\" example=\"xxdpi\">%1$s</xliff:g> (<xliff:g id=\"dpi_no\" example=\"480\">%2$d</xliff:g> DPI) kaynakları</string>\n    <string name=\"unknown_split_for_base_apk\">Temel APK için <xliff:g id=\"split_name\" example=\"some_split\">%1$s</xliff:g></string>\n    <string name=\"unknown_split_for_feature\"><xliff:g id=\"feature_name\" example=\"Visualizer\">%2$s</xliff:g> özelliği için <xliff:g id=\"split_name\" example=\"some_split\">%1$s</xliff:g></string>\n    <string name=\"base_apk\">Temel APK</string>\n    <string name=\"choose_language\">Dili değiştir</string>\n    <string name=\"auto\">Otomatik</string>\n    <string name=\"pref_app_language\">Dil</string>\n    <string name=\"backup_all_users\">Tüm kullanıcılar</string>\n    <string name=\"backup_multiple\">Çoklu yedekleme</string>\n    <string name=\"obb_files_extracted_successfully\">OBB dosyaları çıkarıldı</string>\n    <string name=\"failed_to_extract_obb_files\">OBB dosyaları çıkarılamadı</string>\n    <string name=\"backup_obb_media\">OBB ve Ortam</string>\n    <string name=\"backup_apk_files\">APK dosyaları</string>\n    <string name=\"installer_error_session_abandon\">Kurulum oturumu terk edilemedi</string>\n    <string name=\"installer_error_session_commit\">APK dosyaları işlenemedi</string>\n    <string name=\"installer_error_session_write\">Kurucu oturumuna yazılamadı</string>\n    <string name=\"installer_error_session_create\">Kurucu oturumu oluşturulamadı</string>\n    <string name=\"installer_error_security\">APK dosyalarına erişilemedi</string>\n    <string name=\"install_in_progress\">Kuruluyor…</string>\n    <string name=\"package_installer\">Paket Kurucu</string>\n    <string name=\"unblock_trackers\">İzleyicilerin engelini kaldır</string>\n    <string name=\"reinstall\">Yeniden kur</string>\n    <string name=\"install_app_message\">Bu uygulamayı kurmak istiyor musunuz\\?</string>\n    <string name=\"try_again\">Tekrar dene</string>\n    <string name=\"full_stop_tap_to_see_details\">. Ayrıntıları görmek için dokunun.</string>\n    <string name=\"operation_running\">İşlem gerçekleştiriliyor…</string>\n    <string name=\"batch_ops\">Toplu İşlemler</string>\n    <string name=\"failed_to_fetch_package_info\">Paket bilgileri alınamadı</string>\n    <string name=\"installer_error_lidl_rom\">ROM\\'unuz Rootless Installer ile uyumlu değil.</string>\n    <string name=\"installer_error_generic\">Kurulum başarısız oldu</string>\n    <string name=\"installer_error_storage\">Uygulamayı kurmak için yeterli depolama alanı yok</string>\n    <string name=\"installer_error_bad_apks\">Geçersiz APK dosyaları seçildi</string>\n    <string name=\"installer_error_incompatible\">Uygulama bu aygıtla uyumlu değil</string>\n    <string name=\"installer_error_conflict\">Paket adı kullanımda olduğundan uygulama kurulamadı</string>\n    <string name=\"installer_error_blocked\">Kurulum <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g> tarafından engellendi</string>\n    <string name=\"installer_error_blocked_device\">aygıt</string>\n    <string name=\"installer_error_aborted\">İptal edildiği için veya oturum beklenmedik şekilde kapandığı için kurulum başarısız oldu</string>\n    <string name=\"toggle_default_app_ops\">Öntanımlı uygulama işlemlerini değiştir</string>\n    <string name=\"filter_apps_with_activities\">Etkinlikleri olan</string>\n    <string name=\"are_you_sure\">Emin misiniz\\?</string>\n    <string name=\"pref_remove_all_rules_msg\">İzinler verilecek, uygulama işlemleri ve bileşenleri öntanımlı değerlerine dönecektir.</string>\n    <string name=\"pref_remove_all_rules\">Tüm kuralları kaldır</string>\n    <string name=\"website\">Web sitesi</string>\n    <string name=\"run_in_termux\">Termux\\'ta çalıştır</string>\n    <string name=\"open_in_termux\">Termux\\'ta aç</string>\n    <string name=\"no_matching_package_found\">Böyle bir uygulama bulunamadı</string>\n    <string name=\"block_unblock_trackers\">İzleyicileri engelle/engelini kaldır</string>\n    <string name=\"unblock\">Engeli kaldır</string>\n    <string name=\"block\">Engelle</string>\n    <plurals name=\"backup_exists_are_you_sure\">\n        <item quantity=\"one\">Yedek zaten var. Emin misiniz\\?</item>\n        <item quantity=\"other\">Birden fazla uygulamanın zaten yedeği var. Emin misiniz\\?</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_block_components\">\n        <item quantity=\"one\">%1$d uygulama için bileşenler engellenemedi</item>\n        <item quantity=\"other\">%1$d uygulama için bileşenler engellenemedi</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_unblock_trackers\">\n        <item quantity=\"one\">%1$d uygulamadan izleyicilerin engeli kaldırılamadı</item>\n        <item quantity=\"other\">%1$d uygulamadan izleyicilerin engeli kaldırılamadı</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_delete_backup\">\n        <item quantity=\"one\">%1$d yedek silinemedi</item>\n        <item quantity=\"other\">%1$d yedek silinemedi</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_restore\">\n        <item quantity=\"one\">%1$d uygulama geri yüklenemedi</item>\n        <item quantity=\"other\">%1$d uygulama geri yüklenemedi</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_backup\">\n        <item quantity=\"one\">%1$d uygulama yedeklenemedi</item>\n        <item quantity=\"other\">%1$d uygulama yedeklenemedi</item>\n    </plurals>\n    <plurals name=\"failed_to_backup_some_apk_files\">\n        <item quantity=\"one\">%1$d uygulama yedeklenemedi</item>\n        <item quantity=\"other\">%1$d uygulama yedeklenemedi</item>\n    </plurals>\n    <string name=\"filter_apps_with_rules\">Kurallara sahip uygulamalar</string>\n    <string name=\"filter_system_apps\">Sistem uygulamaları</string>\n    <string name=\"filter_user_apps\">Kullanıcı uygulamaları</string>\n    <string name=\"filter\">Filtrele</string>\n    <string name=\"package_name_is_installed_successfully\"><xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g> kuruldu</string>\n    <string name=\"termux\">Termux</string>\n    <plurals name=\"no_of_splits\">\n        <item quantity=\"one\">%1$d bölüm</item>\n        <item quantity=\"other\">%1$d bölüm</item>\n    </plurals>\n    <string name=\"failed_to_parse_some_numbers\">Bazı numaralar ayrıştırılamadı</string>\n    <string name=\"only_works_in_root_or_adb_mode\">Yalnızca root veya ADB modunda çalışır</string>\n    <string name=\"input_app_ops_description\">Uygulama işlemi adlarını ve/veya sabitlerini aralarında boşluk olacak şekilde girin, örn. <tt>WAKE_LOCK 63 72 CAMERA</tt> gibi.</string>\n    <string name=\"starting_activity\">Başlangıç etkinliği: <xliff:g id=\"activity_name\" example=\".main.MainActivity\">%1$s</xliff:g></string>\n    <string name=\"input_app_ops\">Uygulama işlemlerini gir</string>\n    <string name=\"filtered_packages\">Filtrelenmiş paketler</string>\n    <string name=\"input_signatures_description\">İmzaları aralarında boşluk olacak şekilde girin, örn. <tt>com.facebook org.app2 com.app3</tt> gibi.</string>\n    <string name=\"input_signatures\">İmzaları gir</string>\n    <string name=\"failed_packages\">Başarısız paketler</string>\n    <string name=\"no_tracker_found\">İzleyici bulunamadı</string>\n    <string name=\"clear_app_cache_description\">Tüm uygulamaların önbelleğini temizler</string>\n    <string name=\"clear_app_cache\">Uygulama önbelleğini temizle</string>\n    <string name=\"clear_data_from_uninstalled_apps_description\"><tt>DONT_DELETE_DATA</tt> işaretiyle kaldırılan uygulamaların verilerini temizle</string>\n    <string name=\"clear_data_from_uninstalled_apps\">Kaldırılan uygulamaların verilerini temizle</string>\n    <string name=\"deny_app_ops_description\">Sabit değerlerle tanımlanan uygulama işlemleri için bir mod ayarlayın, örn. <tt>63</tt> veya <tt>RUN_IN_BACKGROUND</tt></string>\n    <string name=\"block_components_dots\">Bileşenleri engelle…</string>\n    <string name=\"block_unblock_trackers_description\">Tüm kurulu uygulamalarda reklam ve izleme bileşenlerini engelleyin veya engelini kaldırın</string>\n    <string name=\"clear_cache\">Önbelleği Temizle</string>\n    <string name=\"pref_import_existing_msg\">Diğer uygulamalar tarafından devre dışı bırakılan bileşenleri App Manager\\'e ekleyin. Çok sayıda yanlış pozitif olabileceğinden bu aracı kullanırken dikkatli olun. Yalnızca emin olduğunuz uygulamaları seçin.</string>\n    <string name=\"pref_import_existing\">Var olan kuralları içe aktar</string>\n    <string name=\"source_code\">Kaynak Kodları</string>\n    <string name=\"update\">Güncelle</string>\n    <string name=\"install\">Kur</string>\n    <plurals name=\"no_of_trackers\">\n        <item quantity=\"one\">%1$d izleyici</item>\n        <item quantity=\"other\">%1$d izleyici</item>\n    </plurals>\n    <string name=\"manifest_viewer\">Bildirim Görüntüleyici</string>\n    <string name=\"external_apk_no_app_op\">Harici APK\\'nın herhangi bir uygulama işlemi yok</string>\n    <string name=\"changelog\">Değişiklikler</string>\n    <string name=\"one_click_ops\">Tek Tık İşlemleri</string>\n    <string name=\"never_ask\">Asla sorma</string>\n    <string name=\"launch_app\">Başlat</string>\n    <string name=\"failed_to_deny_dangerous_app_ops\">Tüm tehlikeli uygulama işlemleri iptal edilemedi</string>\n    <string name=\"failed_to_deny_dangerous_perms\">Tüm tehlikeli izinleri iptal edilemedi</string>\n    <string name=\"failed_to_reset_app_ops\">Uygulama işlemleri sıfırlanamadı</string>\n    <string name=\"failed_to_revoke_permission\">İzin iptal edilemedi</string>\n    <string name=\"failed_to_grant_permission\">İzin verilemedi</string>\n    <plurals name=\"alert_failed_to_disable_trackers\">\n        <item quantity=\"one\">%1$d uygulamadan izleyiciler devre dışı bırakılamadı</item>\n        <item quantity=\"other\">%1$d uygulamadan izleyiciler devre dışı bırakılamadı</item>\n    </plurals>\n    <string name=\"unknown_op\">Bilinmeyen İşlem</string>\n    <string name=\"sort_by_tracker_components\">Önce izleyiciler</string>\n    <string name=\"deny_dangerous_permissions\">Tehlikeli izinleri reddet</string>\n    <string name=\"sort_by_denied_permissions\">Önce reddedilen</string>\n    <string name=\"sort_by_dangerous_permissions\">Önce tehlikeli</string>\n    <string name=\"sort_by_permission_names\">İzin adı</string>\n    <string name=\"sort_by_app_ops_values\">Uygulama işlemi değeri</string>\n    <string name=\"sort_by_denied_app_ops\">Önce reddedilen</string>\n    <string name=\"sort_by_app_ops_names\">Uygulama işlemi adı</string>\n    <string name=\"deny_dangerous_app_ops\">Tehlikeli uygulama işlemlerini reddet</string>\n    <string name=\"reset_to_default\">Öntanımlı değere sıfırla</string>\n    <string name=\"sort_by_component_name\">Bileşen adı</string>\n    <string name=\"block_trackers\">İzleyicileri engelle</string>\n    <string name=\"sort_by_wifi_data\">Wi-Fi verisi</string>\n    <string name=\"version\">Sürüm</string>\n    <string name=\"pref_about_msg\">App Manager sürümü, lisansı, katkıda bulunanlar, vs.</string>\n    <string name=\"apply\">Uygula</string>\n    <string name=\"select_theme\">Tema</string>\n    <string name=\"night\">Gece</string>\n    <string name=\"day\">Gündüz</string>\n    <string name=\"battery_mode\">Pil modu</string>\n    <string name=\"follow_system\">Sisteme uy</string>\n    <string name=\"pref_app_theme\">Uygulama teması</string>\n    <string name=\"pref_import_blocker_msg\">Engelleme kurallarını Blocker\\'dan içe aktarın, her dosya tek bir paket için kurallar içerir.</string>\n    <string name=\"pref_import_watt_msg\">Engelleme kurallarını Watt\\'tan içe aktarın, her dosya <tt>paket_adı.xml</tt> şeklinde adlandırılmış olarak tek bir paket için kurallar içerir.</string>\n    <string name=\"pref_import_msg\">App Manager\\'den daha önce dışa aktarılan engelleme kurallarını içe aktarın.</string>\n    <string name=\"pref_export_msg\">App Manager içinde yapılandırılan engelleme kurallarını harici depolamaya aktarın.</string>\n    <string name=\"touchscreen\">Dokunmatik ekran</string>\n    <string name=\"navigation\">Gezinme</string>\n    <string name=\"keyboard_type\">Klavye Türü</string>\n    <string name=\"export_failed\">Dışa aktarma başarısız oldu!</string>\n    <string name=\"import_failed\">İçe aktarma başarısız oldu!</string>\n    <string name=\"export_options\">Dışa Aktarma Seçenekleri</string>\n    <string name=\"import_options\">İçe Aktarma Seçenekleri</string>\n    <string name=\"pref_export\">Dışa Aktar</string>\n    <string name=\"pref_import\">İçe Aktar</string>\n    <string name=\"ago\">önce</string>\n    <string name=\"reject_time\">Reddetme Zamanı</string>\n    <string name=\"accept_time\">Kabul Etme Zamanı</string>\n    <string name=\"duration\">Süre</string>\n    <string name=\"running\">Çalışıyor</string>\n    <string name=\"mode\">Mod</string>\n    <string name=\"permission_name\">İzin Adı</string>\n    <string name=\"toggle_kill_for_system_apps\">Sistem uygulamalarını sonlandırmayı etkinleştir/devre dışı bırak</string>\n    <plurals name=\"alert_failed_to_force_stop\">\n        <item quantity=\"one\">%1$d uygulama durmaya zorlanamadı</item>\n        <item quantity=\"other\">%1$d uygulama durmaya zorlanamadı</item>\n    </plurals>\n    <string name=\"the_operation_was_successful\">Bitti</string>\n    <plurals name=\"alert_failed_to_disable_background\">\n        <item quantity=\"one\">%1$d uygulamanın arka planda çalışması engellenemedi</item>\n        <item quantity=\"other\">%1$d uygulamanın arka planda çalışması engellenemedi</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_uninstall\">\n        <item quantity=\"one\">%1$d uygulama kaldırılamadı</item>\n        <item quantity=\"other\">%1$d uygulama kaldırılamadı</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_clear_data\">\n        <item quantity=\"one\">%1$d uygulamadan veriler temizlenemedi</item>\n        <item quantity=\"other\">%1$d uygulamadan veriler temizlenemedi</item>\n    </plurals>\n    <string name=\"sort_by_blocked_components\">Önce engellenen</string>\n    <string name=\"error_evaluating_input\">Giriş değerlendirilemedi</string>\n    <string name=\"shared_prefs\">Paylaşılan Tercihler</string>\n    <string name=\"test_only\">Yalnızca test</string>\n    <string name=\"debuggable\">Hata ayıklanabilir</string>\n    <string name=\"go\">Git</string>\n    <string name=\"split_feature_name\">Özellik: <xliff:g id=\"feature_name\" example=\"Visualizer\">%1$s</xliff:g></string>\n    <string name=\"export_blocking_rules\">Engelleme Kurallarını Dışa Aktar</string>\n    <string name=\"disable_background\">Arka planda çalışmayı engelle</string>\n    <string name=\"backup_restore\">Yedekle/Geri Yükle</string>\n    <string name=\"clear_data\">Verileri Temizle</string>\n    <string name=\"user_and_uid\">Kullanıcı: <xliff:g id=\"user_name\" example=\"root\">%1$s</xliff:g> (<xliff:g id=\"user_id\" example=\"0\">%2$d</xliff:g>)</string>\n    <string name=\"memory_virtual_memory\">Bellek: %1$s, Sanal Bellek: %2$s</string>\n    <string name=\"pid_and_ppid\">İşlem Kimliği: %1$d, Üst İşlem Kimliği: %2$d</string>\n    <string name=\"disable_background_run\">Arka planda çalışmayı engelle</string>\n    <string name=\"kill_process\">Sonlandır</string>\n    <string name=\"running_apps\">Çalışan Uygulamalar</string>\n    <string name=\"apk_updater\">APK Güncelleyici</string>\n    <plurals name=\"failed_to_import_files\">\n        <item quantity=\"one\">%1$d dosya içe aktarılamadı.</item>\n        <item quantity=\"other\">%1$d dosya içe aktarılamadı.</item>\n    </plurals>\n    <string name=\"the_export_was_successful\">Dışa aktarıldı</string>\n    <string name=\"the_import_was_successful\">İçe aktarıldı</string>\n    <string name=\"pref_import_blocker\">Blocker\\'dan içe aktar</string>\n    <string name=\"pref_import_watt\">Watt\\'tan içe aktar</string>\n    <string name=\"pref_import_export_blocking_rules_msg\">Kuralları içe/dışa aktarın, Watt veya Blocker\\'dan harici kuralları içe aktarın.</string>\n    <string name=\"pref_import_export_blocking_rules\">Engelleme kurallarını içe/dışa aktar</string>\n    <string name=\"sort_by_mobile_data\">Mobil veri</string>\n    <string name=\"sort_by_times_opened\">Açılma sayısı</string>\n    <string name=\"sort_by_screen_time\">Ekran süresi</string>\n    <string name=\"sort_by_last_used\">Son kullanma</string>\n    <plurals name=\"no_of_times_opened\">\n        <item quantity=\"one\">%1$d defa</item>\n        <item quantity=\"other\">%1$d defa</item>\n    </plurals>\n    <string name=\"external_multiple_data_dir\">Harici Veri Dizini <xliff:g id=\"dir_no\" example=\"1\">%1$d</xliff:g></string>\n    <string name=\"external_data_dir\">Harici Veri Dizini</string>\n    <string name=\"exodus_link\">εxodus Bağlantısı</string>\n    <string name=\"usage_yesterday\">Dün</string>\n    <string name=\"app_settings\">Ayarlar</string>\n    <string name=\"usage_access\">Kullanım erişimi</string>\n    <string name=\"pref_global_blocking_enabled_msg\">Uygulama için açıkça engellemeyi açmadan herhangi bir uygulamanın herhangi bir bileşenini engellemenize izin verir.</string>\n    <string name=\"pref_global_blocking_enabled\">Anında bileşen engelleme</string>\n    <string name=\"str_logo\">Logo</string>\n    <string name=\"rules_not_applied\">Kurallar uygulanmadı</string>\n    <string name=\"failed_to_disable_op\">İstenen uygulama işlemi devre dışı bırakılamadı</string>\n    <string name=\"failed_to_enable_op\">İstenen uygulama işlemi etkinleştirilemedi</string>\n    <string name=\"no_app_ops\">Uygulama işlemi yok</string>\n    <string name=\"app_ops\">Uygulama İşlemleri</string>\n    <string name=\"app_size\">Uygulama</string>\n    <string name=\"total_size\">Toplam</string>\n    <string name=\"storage_and_cache\">Depolama ve Önbellek</string>\n    <string name=\"failed_to_stop\"><xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g> durdurulamadı.</string>\n    <string name=\"force_stop\">Zorla durdur</string>\n    <string name=\"enable\">Etkinleştir</string>\n    <string name=\"disable\">Devre dışı bırak</string>\n    <string name=\"stopped\">Durduruldu</string>\n    <string name=\"uninstall_system_app_message\">Bu bir sistem uygulamasıdır. Bu uygulamayı kaldırmak istediğinizden emin misiniz\\?</string>\n    <string name=\"uninstalled_successfully\"><xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g> kaldırıldı.</string>\n    <string name=\"failed_to_uninstall\"><xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g> kaldırılamadı.</string>\n    <string name=\"uninstall_app_message\">Bu uygulamayı kaldırmak istiyor musunuz\\?</string>\n    <string name=\"view_in_settings\">Ayarlarda görüntüle</string>\n    <string name=\"no_content\">İçerik yok</string>\n    <string name=\"no_usage_in_this_time_range\">Bu zaman aralığında kullanım yok</string>\n    <string name=\"disabled_app\">Devre dışı</string>\n    <string name=\"key_name_cannot_be_null\">Anahtar adı boş olamaz</string>\n    <string name=\"type_string\">Karakterler</string>\n    <string name=\"type_long\">Uzun tam sayı</string>\n    <string name=\"type_int\">Tam sayı</string>\n    <string name=\"type_float\">Ondalık sayı</string>\n    <string name=\"type_boolean\">Doğru/yanlış</string>\n    <string name=\"done\">Bitti</string>\n    <string name=\"add_item\">Öge ekle</string>\n    <string name=\"select_type\">Bir tür seçin</string>\n    <string name=\"key_name\">Anahtar Adı</string>\n    <string name=\"boolean_value\">Boole değeri</string>\n    <string name=\"decimal_value\">Ondalık sayı değeri</string>\n    <string name=\"integer_value\">Tam sayı değeri</string>\n    <string name=\"long_integer_value\">Uzun tam sayı değeri</string>\n    <string name=\"string_value\">Dizge değeri</string>\n    <string name=\"saving_failed\">Kaydetme başarısız oldu, tekrar deneyin.</string>\n    <string name=\"saved_successfully\">Kaydedildi</string>\n    <string name=\"deletion_failed\">Silinemedi</string>\n    <string name=\"deleted_successfully\">Silindi</string>\n    <string name=\"delete\">Sil</string>\n    <string name=\"discard\">At</string>\n    <string name=\"save\">Kaydet</string>\n    <string name=\"databases\">Veri tabanları</string>\n    <string name=\"grant_usage_access\">Kullanım Erişimi Ver</string>\n    <string name=\"go_back\">Geri git</string>\n    <string name=\"usage_less_than_a_minute\">Bir dakikadan az</string>\n    <plurals name=\"usage_hours\">\n        <item quantity=\"one\">%1$d sa</item>\n        <item quantity=\"other\">%1$d sa</item>\n    </plurals>\n    <plurals name=\"usage_days\">\n        <item quantity=\"one\">%1$d gün</item>\n        <item quantity=\"other\">%1$d gün</item>\n    </plurals>\n    <plurals name=\"usage_months\">\n        <item quantity=\"one\">%1$d ay</item>\n        <item quantity=\"other\">%1$d ay</item>\n    </plurals>\n    <string name=\"usage_7_days\">Son 7 gün</string>\n    <string name=\"usage_today\">Bugün</string>\n    <string name=\"usage_weekly\">Haftalık</string>\n    <string name=\"app_usage\">Uygulama Kullanımı</string>\n    <string name=\"no_tracker_class\">İzleyici sınıflar yok</string>\n    <string name=\"no_shared_libs\">Paylaşılan kütüphane yok</string>\n    <plurals name=\"main_list_date_days\">\n        <item quantity=\"one\"><xliff:g id=\"last_update_date\" example=\"20/10/2020\">%1$s</xliff:g> <xliff:g id=\"day_no\" example=\"5\">%2$d</xliff:g> gün</item>\n        <item quantity=\"other\"><xliff:g id=\"last_update_date\" example=\"20/10/2020\">%1$s</xliff:g> <xliff:g id=\"day_no\" example=\"5\">%2$d</xliff:g> gün</item>\n    </plurals>\n    <string name=\"all_classes\">Tüm sınıflar</string>\n    <string name=\"tracker_classes\">İzleyici sınıfları</string>\n    <string name=\"tracker_details\">İzleyici ayrıntıları</string>\n    <string name=\"found_trackers\">Bulunan İzleyiciler:</string>\n    <string name=\"toggle_class_listing\">Sınıf Listesini Aç/Kapat</string>\n    <string name=\"class_viewer\">Sınıf Görüntüleyici</string>\n    <string name=\"word_wrap\">Sözcük kaydırmayı aç/kapat</string>\n    <string name=\"credits_message\">Aşağıdaki projelerin yazarlarına: \n\\n- The Android Open Source Project \n\\n- <a href=\"https://github.com/zhaobozhen/libraries\">Absinthe\\'s libraries</a> \n\\n- <a href=\"https://github.com/butzist/ActivityLauncher\">Activity Launcher</a> \n\\n- <a href=\"https://bitbucket.org/oF2pks/fdroid-applications-info\">Apps_packages Info</a> \n\\n- <a href=\"https://github.com/zhaobao/AppsMonitor\">AppsMonitor</a> \n\\n- <a href=\"https://github.com/8enet/AppOpsX\">AppOpsX</a> \n\\n- <a href=\"https://github.com/gabrielemariotti/changeloglib\">ChangeLog Library</a> \n\\n- <a href=\"https://bitbucket.org/oF2pks/fdroid-classyshark3xodus\">ClassySharkAndroid</a> \n\\n- <a href=\"https://github.com/billthefarmer/editor\">Editor</a> \n\\n- <a href=\"https://github.com/Raival-e/File-Explorer\">File Explorer</a> \n\\n- <a href=\"https://github.com/nex3z/FlowLayout\">FlowLayout</a> \n\\n- <a href=\"https://github.com/k3b/intent-intercept\">Intent Intercept</a> \n\\n- <a href=\"https://github.com/YarikSOffice/lingver\">Lingver</a> \n\\n- <a href=\"https://github.com/topjohnwu/Magisk\">Magisk</a> \n\\n- <a href=\"https://github.com/zhanghai/MaterialFiles\">Material Files</a> \n\\n- <a href=\"https://github.com/pluscubed/matlog\">MatLog</a> \n\\n- <a href=\"https://github.com/matrix-org/matrix-android-sdk\">Matrix Android SDK</a> \n\\n- <a href=\"https://github.com/jensstein/oandbackup\">OAndBackup</a> \n\\n- <a href=\"https://github.com/open-keychain/open-keychain\">Open Keychain</a> \n\\n- <a href=\"https://github.com/Aefyr/SAI\">SAI</a> \n\\n- <a href=\"https://github.com/RikkaApps/Shizuku\">Shizuku</a> \n\\n- <a href=\"https://github.com/eclipse/tm4e\">tm4e</a> \n\\n- <a href=\"https://github.com/tuyafeng/Watt\">Watt</a></string>\n    <string name=\"credits\">Teşekkürler</string>\n    <string name=\"paths_and_directories\">Yollar ve Dizinler</string>\n    <string name=\"create_shortcut\">Kısayol Oluştur</string>\n    <string name=\"sort_by_target_sdk\">Hedef SDK</string>\n    <string name=\"only_install\">Yalnızca Kur</string>\n    <string name=\"app_signing_install_without_data_loss\">İmza doğrulamayı kapattıysanız, uygulamayı veri kaybetmeden kurmak için <b>Yalnızca kur</b> seçeneğini kullanabilirsiniz.</string>\n    <string name=\"app_data_will_be_lost\">Mevcut veriler kaybolacak.</string>\n    <string name=\"app_signing_signature_mismatch_for_system_apps\">Farklı imzaya sahip bir sistem uygulaması bu paket adına sahip olduğu için uygulama kurulamadı.</string>\n    <string name=\"do_you_want_to_uninstall_and_install\">Uygulamayı kaldırıp tekrar kurmak istiyor musunuz\\?</string>\n    <string name=\"usage_access_not_supported\">İlgili ayarlar sayfası olmadığı için kullanım erişimi istenemedi.</string>\n    <string name=\"sys_config\">Sistem Yapılandırması</string>\n    <string name=\"copy\">Kopyala</string>\n    <string name=\"view_missing_signatures\">Henüz App Manager\\'ın kütüphane veri tabanında bulunmayan imzaları görüntülemek veya göndermek için dokunun.</string>\n    <string name=\"tap_to_see_details\">Ayrıntıları görmek için dokunun</string>\n    <string name=\"lib_details\">Kütüphane Ayrıntıları</string>\n    <string name=\"no_libs\">Kütüphane yok</string>\n    <string name=\"scanner\">Tarayıcı</string>\n    <plurals name=\"missing_signatures\">\n        <item quantity=\"one\">%1$d imza eksik</item>\n        <item quantity=\"other\">%1$d imza eksik</item>\n    </plurals>\n    <plurals name=\"libraries\">\n        <item quantity=\"one\">%1$d kütüphane</item>\n        <item quantity=\"other\">%1$d kütüphane</item>\n    </plurals>\n    <plurals name=\"classes\">\n        <item quantity=\"one\">%1$d sınıf</item>\n        <item quantity=\"other\">%1$d sınıf</item>\n    </plurals>\n    <plurals name=\"other_trackers_and_classes\">\n        <item quantity=\"one\"><xliff:g id=\"class_no\" example=\"50\">%2$d</xliff:g> sınıfla <xliff:g id=\"tracker_no\" example=\"8\">%1$d</xliff:g> izleyici</item>\n        <item quantity=\"other\"><xliff:g id=\"class_no\" example=\"50\">%2$d</xliff:g> sınıfla <xliff:g id=\"tracker_no\" example=\"8\">%1$d</xliff:g> izleyici</item>\n    </plurals>\n    <plurals name=\"two_trackers_and_classes\">\n        <item quantity=\"one\"><xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g> sınıfla 2 izleyici</item>\n        <item quantity=\"other\"><xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g> sınıfla 2 izleyici</item>\n    </plurals>\n    <plurals name=\"tracker_and_classes\">\n        <item quantity=\"one\"><xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g> sınıfla 1 izleyici</item>\n        <item quantity=\"other\"><xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g> sınıfla 1 izleyici</item>\n    </plurals>\n    <string name=\"filter_running_apps\">Çalışan uygulamalar</string>\n    <string name=\"select_apk\">APK seç</string>\n    <string name=\"send_crash_report\">Çökme bildirimi gönder</string>\n    <string name=\"tap_to_submit_crash_report\">Çökme bildirimini göndermek için dokunun.</string>\n    <string name=\"am_crashed\">App Manager az önce çöktü</string>\n    <string name=\"un_apkm\">UnApkm</string>\n    <string name=\"in_progress\">Devam ediyor</string>\n    <string name=\"conversion_failed\">Dönüştürme başarısız oldu.</string>\n    <string name=\"new_profile\">Yeni profil</string>\n    <string name=\"input_profile_name_description\">Profil adı boşluk içeremez.</string>\n    <string name=\"input_profile_name\">Profil adı</string>\n    <string name=\"duplicate\">Kopyala</string>\n    <string name=\"ecc\">Eliptik eğri şifrelemesi</string>\n    <string name=\"rsa\">RSA</string>\n    <string name=\"aes\">AES</string>\n    <string name=\"none\">Yok</string>\n    <string name=\"pref_encryption_msg\">Yedeklemeler için şifreleme.</string>\n    <string name=\"encryption\">Şifreleme</string>\n    <string name=\"select_user\">Kullanıcı seç</string>\n    <string name=\"failed_to_duplicate_profile\">Profil kopyalanamadı</string>\n    <string name=\"send_selected\">Seçileni gönder</string>\n    <string name=\"user_profile_with_id\">Profil: %1$s (%2$d)</string>\n    <string name=\"advanced\">Gelişmiş</string>\n    <string name=\"simple\">Basit</string>\n    <string name=\"enabled\">Etkin</string>\n    <string name=\"choose\">Seç</string>\n    <string name=\"input_permissions_description\">İzinleri aralarında boşluk olacak şekilde girin, örn. <tt>com.permission.GET_ACCOUNTS android.permission.ACCESS_MEDIA_LOCATION</tt> gibi. Tüm izinlere uygulamak için <tt>*</tt> kullanın.</string>\n    <string name=\"input_permissions\">Giriş izinleri</string>\n    <string name=\"options\">Seçenekler</string>\n    <string name=\"off\">Kapalı</string>\n    <string name=\"on\">Açık</string>\n    <string name=\"profile_state_msg\">Bu profil için özel açık/kapalı durumu</string>\n    <string name=\"profile_block_trackers_msg\">Uygulamalardaki izleyicileri engeller</string>\n    <string name=\"profile_clear_data_msg\">Uygulamaların verilerini temizler</string>\n    <string name=\"profile_clear_cache_msg\">Uygulamaların uygulama önbelleğini temizler</string>\n    <string name=\"profile_force_stop_msg\">Uygulamaları zorla durdurur</string>\n    <string name=\"allow_routine_ops_msg\">Profilin rutin işlemlerde kullanılmasına izin ver</string>\n    <string name=\"profile_state\">Profil durumu</string>\n    <string name=\"allow_routine_ops\">Rutin işlemlere izin ver</string>\n    <string name=\"adb_over_tcp\">TCP üzerinden ADB</string>\n    <string name=\"pref_mode_of_operations\">İşlem modu</string>\n    <string name=\"close\">Kapat</string>\n    <string name=\"no_root\">Root yok</string>\n    <string name=\"root\">Root</string>\n    <string name=\"install_location_prefer_external\">Harici tercih et</string>\n    <string name=\"install_location_internal_only\">Yalnızca dahili</string>\n    <string name=\"install_location\">Kurulum konumu</string>\n    <string name=\"installer\">Kurucu</string>\n    <string name=\"comment\">Yorum</string>\n    <string name=\"pref_sign_apk_msg\">Kurmadan önce APK dosyalarını imzalayın.</string>\n    <string name=\"pref_sign_apk\">APK imzala</string>\n    <string name=\"pref_signature_schemes_msg\">Daha fazla uyumluluk için en az v1 ve v2 şemaları seçilmelidir. v4 şeması, v2 veya v3 gerektirir.</string>\n    <string name=\"v4_scheme\">v4 şeması (Android 11\\'den beri)</string>\n    <string name=\"v3_scheme\">v3 şeması (Android 9\\'dan beri)</string>\n    <string name=\"v2_scheme\">v2 şeması (Android 7.0\\'dan beri)</string>\n    <string name=\"v1_scheme\">v1 şeması (Android 1.0\\'dan beri)</string>\n    <string name=\"pref_apk_signing_msg\">İmza şemaları, özel imzalama anahtarı vs. ayarlayın.</string>\n    <string name=\"apk_signing\">APK imzalama</string>\n    <string name=\"app_signing_signature_schemes\">İmza şemaları</string>\n    <string name=\"splits\">Bölümler</string>\n    <string name=\"source_stamp_verified\">SourceStamp doğrulandı.</string>\n    <string name=\"not_verified\">Doğrulanmadı</string>\n    <string name=\"verified\">Doğrulandı</string>\n    <plurals name=\"verified_with_warning\">\n        <item quantity=\"one\">%d uyarıyla doğrulandı</item>\n        <item quantity=\"other\">%d uyarıyla doğrulandı</item>\n    </plurals>\n    <plurals name=\"app_signing_signature_schemes_pl\">\n        <item quantity=\"one\">İmza şeması</item>\n        <item quantity=\"other\">İmza şemaları</item>\n    </plurals>\n    <string name=\"input_keystore_alias_pass_description\"><b>%1$s</b> takma adı için parolayı girin. Parola, KeyStore parolasıyla aynıysa bunu boş bırakabilirsiniz.</string>\n    <string name=\"input_keystore_alias_pass\"><b>%1$s</b> takma adı için parola</string>\n    <string name=\"input_keystore_pass_msg\">KeyStore parolasını girmek için buraya dokunun</string>\n    <string name=\"input_keystore_pass_description\">App Manager KeyStore parolasını girin. Bunu ilk kez görüyorsanız, lütfen bir parola oluşturucu kullanarak bir parola oluşturun ve buraya girmeden önce güvenli bir yere kaydedin.</string>\n    <string name=\"input_keystore_pass\">KeyStore parolasını gir</string>\n    <string name=\"no_app_ops_permission\">Uygulama işlemlerini görüntüleme izni yok</string>\n    <string name=\"pref_backup_android_keystore_msg\">Geri yüklendikten sonra bazı uygulamalar çalışmayacaktır. KeyStore\\'u geri yüklemek çoğu aygıtta çalışmaz.</string>\n    <string name=\"pref_backup_android_keystore\">Android KeyStore ile uygulamaları yedekle</string>\n    <string name=\"keep_data_and_app_signing_signatures\">Verileri ve imzaları sakla</string>\n    <string name=\"this_action_cannot_be_undone\">Bu eylem geri alınamaz.</string>\n    <string name=\"set_app_op_mode\">Uygulama çalışma modunu ayarla</string>\n    <string name=\"magisk_hide_enabled\">MagiskHide</string>\n    <string name=\"interceptor\">Önleyici</string>\n    <string name=\"resend_intent\">Intent\\'i yeniden gönder</string>\n    <string name=\"share\">Paylaş</string>\n    <string name=\"extras\">Ekstralar</string>\n    <string name=\"category\">Kategoriler</string>\n    <string name=\"uri\">URI</string>\n    <string name=\"mime_type\">MIME türü</string>\n    <string name=\"action\">Eylem</string>\n    <string name=\"result_code\">Sonuç kodu</string>\n    <string name=\"activity_result\">Etkinlik sonucu</string>\n    <string name=\"send_edited_intent\">Düzenlenen Intent\\'i gönder</string>\n    <string name=\"matching_activities\">Eşleşen etkinlikler</string>\n    <string name=\"value\">Değer</string>\n    <string name=\"filter_apps_with_splits\">Bölümleri olan</string>\n    <string name=\"set_custom_app_op\">Özel uygulama işlemi ayarla</string>\n    <string name=\"battery\">Pil</string>\n    <string name=\"graphics\">Grafikler</string>\n    <string name=\"cpu\">CPU</string>\n    <string name=\"users\">Kullanıcılar</string>\n    <string name=\"languages\">Diller</string>\n    <string name=\"battery_capacity\">Kapasite</string>\n    <string name=\"memory\">Bellek</string>\n    <string name=\"vendor\">Satıcı</string>\n    <string name=\"gles_version\">OpenGL ES sürümü</string>\n    <string name=\"no_of_cores\">Çekirdekler (CPU)</string>\n    <string name=\"support_architectures\">Desteklenen mimariler</string>\n    <string name=\"security_providers\">Güvenlik sağlayıcıları</string>\n    <string name=\"kernel\">Çekirdek (kernel)</string>\n    <string name=\"manufacturer\">Üretici</string>\n    <string name=\"board_name\">Ana kart</string>\n    <string name=\"model\">Model</string>\n    <string name=\"brand_name\">Marka</string>\n    <string name=\"pref_about_device_msg\">Android sistemi, CPU, GPU, RAM, pil vs. içeren temel aygıt bilgileri.</string>\n    <string name=\"about_device\">Aygıt hakkında</string>\n    <string name=\"set_mode_for_app_ops_dots\">Uygulama işlemleri için mod ayarla…</string>\n    <string name=\"security\">Güvenlik</string>\n    <plurals name=\"alert_failed_to_set_app_ops\">\n        <item quantity=\"one\">%1$d uygulama için uygulama işlemleri ayarlanamadı</item>\n        <item quantity=\"other\">%1$d uygulama için uygulama işlemleri ayarlanamadı</item>\n    </plurals>\n    <string name=\"patch_level\">Yama seviyesi</string>\n    <string name=\"backup_skip_signature_checks_description\">Sağlama toplamı doğrulamasında başarısız olan veya önceki yedeklerinden farklı APK imzalarına sahip yedekleri geri yükleyin.</string>\n    <string name=\"backup_multiple_description\">Temel yedekleme yerine ayrı bir <i>adlandırılmış</i> yedekleme oluşturun.</string>\n    <string name=\"backup_rules_description\">Uygulama Yöneticisi içinde yapılandırılan kuralları yedekleyin. <font fgcolor=\"#ff0000\">İzinlere bağlı olarak, geri yükleme sırasında tüm kurallar yeniden uygulanamayabilir.</font></string>\n    <string name=\"backup_extras_description\">Uygulama izinlerini, pil tasarrufu ve veri kullanım seçeneklerini, MagiskHide durumunu, SSAID vs. yedekleyin. <font fgcolor=\"#ff0000\">İzinlere bağlı olarak, tüm ekler geri yüklenemez.</font></string>\n    <string name=\"backup_extras\">Ekstralar</string>\n    <string name=\"backup_cache_description\"><b>Önbellek</b>, <b>no_cache</b> ve <b>no_backup</b> klasörlerini yedekleyin.</string>\n    <string name=\"backup_obb_media_description\">OBB ve medya klasörlerini yedekleyin.</string>\n    <string name=\"backup_external_data_description\">Harici veri klasörlerini yedekleyin.</string>\n    <string name=\"backup_internal_data_description\">Veri klasörlerini yedekleyin. Seçilirse, dahili veri klasörleri öntanımlı olarak yedeklenecektir.</string>\n    <string name=\"backup_apk_files_description\">Kaynak dizinden yalnızca APK dosyalarını yedekleyin. Bunun çalışması için <b>kaynak</b> seçilmelidir.</string>\n    <string name=\"window_size\">Pencere boyutu</string>\n    <string name=\"refresh_rate\">Yenileme hızı</string>\n    <string name=\"scaling_factor\">Ölçekleme katsayısı</string>\n    <string name=\"size\">Boyut</string>\n    <string name=\"density\">Yoğunluk</string>\n    <string name=\"screen\">Ekran</string>\n    <string name=\"hardware\">Donanım</string>\n    <string name=\"permissive\">İzin veren</string>\n    <string name=\"enforcing\">Zorunlu</string>\n    <string name=\"selinux\">SELinux</string>\n    <string name=\"failed_to_enable_magisk_hide\">MagiskHide etkinleştirilemedi</string>\n    <string name=\"failed_to_disable_magisk_hide\">MagiskHide devre dışı bırakılamadı</string>\n    <string name=\"disable_background_run_description\">Şu uygulama işlemleri için <i>Yok say</i> modunu ayarlar: <tt>RUN_IN_BACKGROUND</tt> (Android 7.0\\'dan) ve <tt>RUN_ANY_IN_BACKGROUND</tt> (Android 9\\'dan).</string>\n    <plurals name=\"no_of_components\">\n        <item quantity=\"one\">%1$d bileşen</item>\n        <item quantity=\"other\">%1$d bileşen</item>\n    </plurals>\n    <string name=\"backup_custom_users_description\">Yalnızca belirtilen kullanıcılar için yedekleme gerçekleştirin</string>\n    <string name=\"backup_custom_users\">Özel kullanıcılar</string>\n    <string name=\"bootloader\">Önyükleyici</string>\n    <string name=\"encrypted\">Şifreli</string>\n    <string name=\"unencrypted\">Şifrelenmemiş</string>\n    <string name=\"no_volumes_found\">Yazma iznine sahip herhangi bir birim bulunamadı.</string>\n    <string name=\"pref_backup_volume_msg\">Yedeklemelerin depolanacağı birimi veya diski seçin.</string>\n    <string name=\"backup_volume\">Yedekleme Birimi</string>\n    <string name=\"pref_backup_restore_msg\">Yedeklemeyi/geri yüklemeyi özelleştirin.</string>\n    <string name=\"back_up\">Yedekle</string>\n    <string name=\"drm_free_apkm_msg\">APKM dosyası DRM içermez, onu APKS\\'ye dönüştürmeye gerek yoktur.</string>\n    <string name=\"restore_msg\">Verileri olan uygulamaları geri yükleyin</string>\n    <string name=\"backup_msg\">Verileri olan uygulamaları yedekleyin</string>\n    <string name=\"restore_latest_msg\">Sürüm kodları kurulu sürüm kodundan daha yüksek olan önceden kurulan uygulamaları geri yükleyin.</string>\n    <string name=\"restore_latest\">En son yedeklemeleri geri yükle</string>\n    <string name=\"restore_not_installed_msg\">Şu anda kurulu olmayan uygulamalar için temel yedeklemeyi geri yükleyin.</string>\n    <string name=\"restore_not_installed\">Kurulu olmayan uygulamaları geri yükle</string>\n    <string name=\"restore_all_msg\">Yedeklenen tüm uygulamalardan temel yedeklemeyi geri yükleyin.</string>\n    <string name=\"restore_all\">Tüm uygulamaları geri yükle</string>\n    <string name=\"backup_apps_with_changes_msg\">Son yedeklemeden bu yana değişiklik olan uygulamalar için yedeklemeleri yeniden yapın. Boyut, sürüm ve son başlatma zamanındaki değişiklikleri içerir.</string>\n    <string name=\"backup_apps_with_changes\">Değişiklikleri olan uygulamaları yedekle</string>\n    <string name=\"redo_existing_backups_msg\">Önceki yedeklemeleri olan kurulu uygulamalar için yedeklemeyi yeniden yapın.</string>\n    <string name=\"redo_existing_backups\">Var olan yedeklemeleri yeniden yap</string>\n    <string name=\"verify_and_redo_backups_msg\">Önceki yedeklemelerin bütünlüğünü denetleyin ve bütünlük denetiminin başarısız olduğu yedeklemeleri yeniden yapın.</string>\n    <string name=\"verify_and_redo_backups\">Yedeklemeleri doğrula ve yeniden yap</string>\n    <string name=\"backup_apps_without_backups_msg\">Önceki yedeklemesi olmayan uygulamaları yedekleyin.</string>\n    <string name=\"backup_apps_without_backups\">Yedeklemesi olmayan uygulamaları yedekle</string>\n    <string name=\"backup_all_apps_msg\">Kurulu tüm uygulamaları yedekleyin.</string>\n    <string name=\"backup_all_apps\">Tüm uygulamaları yedekle</string>\n    <string name=\"list_options\">Seçenekleri listele</string>\n    <string name=\"reverse\">Ters</string>\n    <string name=\"os_version\">İşletim sistemi sürümü</string>\n    <string name=\"add\">Ekle</string>\n    <string name=\"add_to_profile\">Profile ekle</string>\n    <string name=\"initializing\">Başlatılıyor…</string>\n    <string name=\"net_policy\">Ağ politikası</string>\n    <string name=\"has_net_policy\">Ağ politikası</string>\n    <string name=\"choose_what_to_do\">Ne yapılacağını seç.</string>\n    <string name=\"enable_battery_optimization\">Pil iyileştirmesi etkinleştirilsin mi\\?</string>\n    <string name=\"battery_optimization\">Pil iyileştirmesi</string>\n    <string name=\"no_battery_optimization\">Pil iyileştirmesi yok</string>\n    <string name=\"screen_lock_msg\">Android ekran kilidini kullanarak App Manager\\'i kilitleyin</string>\n    <string name=\"screen_lock\">Ekran Kilidi</string>\n    <string name=\"unlock_app_manager\">App Manager\\'in kilidini aç</string>\n    <string name=\"sd_card\">SD Kart</string>\n    <string name=\"external_storage\">Harici Depolama</string>\n    <string name=\"internal_storage\">Dahili Depolama</string>\n    <string name=\"restart_to_reflect_changes\">Yeni değişiklikleri kullanmak için aygıtı hemen yeniden başlatmalısınız.</string>\n    <string name=\"failed_to_change_ssaid\">SSAID değiştirilemedi</string>\n    <string name=\"copied_to_clipboard\">Panoya kopyalandı.</string>\n    <string name=\"ssaid_info\">SSAID (<tt>Settings.Secure.ANDROID_ID</tt>), (Android 8 \\\"Oreo\\\" ve sonrasında) her uygulamaya atanan bir aygıt tanımlayıcısıdır. Kullanıcıları izlemek için uygulamalar tarafından yaygın olarak kullanılır.</string>\n    <string name=\"ssaid\">SSAID</string>\n    <string name=\"type_uri\">URI</string>\n    <string name=\"type_string_array_list\">Dizge listesi</string>\n    <string name=\"type_string_array\">Dizge dizisi</string>\n    <string name=\"type_float_array_list\">Ondalık sayı listesi</string>\n    <string name=\"type_float_array\">Ondalık sayı dizisi</string>\n    <string name=\"type_long_array_list\">Uzun tam sayı listesi</string>\n    <string name=\"type_long_array\">Uzun tam sayı dizisi</string>\n    <string name=\"type_int_array_list\">Tam sayı listesi</string>\n    <string name=\"type_int_array\">Tam sayı dizisi</string>\n    <string name=\"type_component_name\">Bileşen Adı</string>\n    <string name=\"type_null\">Değer yok</string>\n    <string name=\"user_with_id\">Kullanıcı: <xliff:g id=\"user_id\" example=\"0\">%1$d</xliff:g></string>\n    <string name=\"installed_apps\">Kurulu uygulamalar</string>\n    <string name=\"last_actions\">Son eylemler</string>\n    <string name=\"pref_enable_disable_features_msg\">App Manager\\'da özellikleri etkinleştirin veya devre dışı bırakın.</string>\n    <string name=\"enable_disable_features\">Özellikleri etkinleştir/devre dışı bırak</string>\n    <string name=\"isolated\">Yalıtıldı</string>\n    <string name=\"screen_lock_not_enabled\">Lütfen Android ayarlarından bir ekran kilidi seçin veya uygulama verilerini temizleyin.</string>\n    <string name=\"input_app_ops_description_profile\">Uygulama işlem adlarını ve/veya sabitleri aralarında boşluk olacak şekilde girin, örn. <tt>WAKE_LOCK 63 72 CAMERA</tt> gibi. Tüm yapılandırılmış uygulama işlemlerine uygulamak için <tt>*</tt> kullanın.</string>\n    <string name=\"working_on_adb_mode\">ADB modunda çalışma</string>\n    <string name=\"verified_using_unreliable_hash\">Güvenilir olmayan sağlama kullanılarak doğrulandı</string>\n    <string name=\"installer_app_message\">Kurulu uygulamalar arasından seçmek için <b>Seç</b>, özel bir paket adı belirtmek için <b>Özel</b> seçeneğini seçin.</string>\n    <string name=\"specify_custom_name\">Özel</string>\n    <string name=\"filter_apps_without_backups\">Yedeği olmayan</string>\n    <string name=\"uninstalled_apps\">Kaldırılan uygulamalar</string>\n    <string name=\"internal_data\">Dahili veri</string>\n    <string name=\"expiry_date_cannot_be_empty\">Bitiş tarihi boş olamaz.</string>\n    <string name=\"signing_key\">İmzalama anahtarı</string>\n    <string name=\"failed_to_read_keystore\">KeyStore okunamadı.</string>\n    <string name=\"alias_pass\">Takma ad parolası</string>\n    <string name=\"choose_an_alias\">Bir takma ad seçin</string>\n    <string name=\"found_no_alias_in_keystore\">KeyStore\\'da takma ad bulunamadı!</string>\n    <string name=\"new_alias_password\">Yeni takma ad parolası</string>\n    <string name=\"import_key\">Anahtarı içe aktar</string>\n    <string name=\"pem_file\">PEM dosyası</string>\n    <string name=\"pk8_file\">PKCS #8 (PK8) dosyası</string>\n    <string name=\"pem_and_pk8\">PEM ve PKCS #8 (PK8)</string>\n    <string name=\"pkcs12_keystore\">PKCS #12 KeyStore (P12)</string>\n    <string name=\"bouncy_castle_keystore\">Bouncy Castle KeyStore (BKS)</string>\n    <string name=\"java_keystore\">Java KeyStore (JKS)</string>\n    <string name=\"keystore_pass\">KeyStore parolası</string>\n    <string name=\"keystore_file\">KeyStore dosyası</string>\n    <string name=\"country_name\" tools:ignore=\"TypographyOther\">Ülke adı (C)</string>\n    <string name=\"state_name\">Eyalet adı (ST)</string>\n    <string name=\"locality_name\">Yer (şehir) adı (L)</string>\n    <string name=\"organization_name\">Kuruluş adı (O)</string>\n    <string name=\"organization_unit\">Kuruluş birimi (OU)</string>\n    <string name=\"common_name\">Yaygın ad (CN)</string>\n    <string name=\"input_key_password\">Anahtar parolası</string>\n    <string name=\"failed_to_load_key\">Anahtar yüklenemedi.</string>\n    <string name=\"key_not_set\">Ayarlanmadı.</string>\n    <string name=\"use_default\">Öntanımlı değeri kullan</string>\n    <string name=\"invalid_rsa_key_size\">RSA şifrelemesi için geçersiz anahtar boyutu. Anahtar boyutu 1024, 2048 veya 4096 bit olabilir.</string>\n    <string name=\"crypto_key_size\">Anahtar boyutu</string>\n    <string name=\"invalid_aes_key_size\">AES şifrelemesi için geçersiz anahtar boyutu. Anahtar boyutu 128 veya 256 bit olabilir.</string>\n    <string name=\"failed_to_initialize_key_store\">App Manager anahtar deposu başlatılamadı.</string>\n    <string name=\"failed_to_save_key\">Anahtar kaydedilemedi.</string>\n    <string name=\"generate_key\">Oluştur</string>\n    <string name=\"input_key\">Anahtarı girin (onaltılık olarak)</string>\n    <string name=\"input_keystore_alias_pass_msg\">%1$s parolasını girmek için buraya dokunun</string>\n    <string name=\"source_code_links\"><a href=\"https://github.com/MuntashirAkon/AppManager\">GitHub</a> • <a href=\"https://gitlab.com/muntashir/AppManager\">GitLab</a> • <a href=\"https://0xacab.org/muntashir/AppManager\">Riseup</a> • <a href=\"https://codeberg.org/muntashir/AppManager\">Codeberg</a></string>\n    <string name=\"pref_installer_msg\">Uygulama kurucusunun davranışlarını yapılandırın.</string>\n    <string name=\"trackers_unblocked_successfully\">İzleyicilerin engeli artık kaldırıldı</string>\n    <string name=\"trackers_blocked_successfully\">İzleyiciler artık engellendi</string>\n    <string name=\"failed_to_unblock_trackers\">İzleyicilerin engeli kaldırılamadı</string>\n    <string name=\"failed_to_block_trackers\">İzleyiciler engellenemedi</string>\n    <string name=\"profile_save_apk_msg\">APK dosyalarını <tt>AppManager/apks</tt> konumuna kaydeder</string>\n    <string name=\"save_apk\">APK dosyasını kaydet</string>\n    <string name=\"running_services\">Çalışan Hizmetler</string>\n    <string name=\"view_logs\">Günlükleri görüntüle</string>\n    <string name=\"share_log\">Paylaş</string>\n    <string name=\"text_include_dmesg\">Çekirdek günlüğünü dahil et</string>\n    <string name=\"omit_sensitive_info_summary\">Web URL\\'leri, telefon numaraları veya e-posta adresleri gibi hassas bilgileri atla.</string>\n    <string name=\"omit_sensitive_info\">Hassas bilgileri atla</string>\n    <string name=\"undo\">Geri al</string>\n    <string name=\"pause_unpause\">Oynat/Duraklat</string>\n    <string name=\"collapse_all\">Tümünü Daralt</string>\n    <string name=\"expand_all\">Tümünü Genişlet</string>\n    <string name=\"file\">Dosya</string>\n    <string name=\"widget_start_recording\">Günlük\n\\nKaydı</string>\n    <string name=\"widget_recording_in_progress\">Kaydediliyor…</string>\n    <string name=\"unable_to_save_log\">Günlük kaydedilemiyor. Geçerli bir dosya adı girdiniz mi\\?</string>\n    <plurals name=\"toast_log_truncated\">\n        <item quantity=\"one\">Günlük çok büyük, son %d satır gösteriliyor.</item>\n        <item quantity=\"other\">Günlük çok büyük, son %d satır gösteriliyor.</item>\n    </plurals>\n    <string name=\"toast_invalid_selection\">Geçersiz seçim. Lütfen tekrar deneyin.</string>\n    <string name=\"toast_invalid_level\">Geçersiz seviye adı: %s</string>\n    <string name=\"pref_display_limit_hint\">Lütfen %1$d ile %2$d arasında geçerli bir sayı girin.</string>\n    <string name=\"text_include_device_info\">Aygıt bilgilerini dahil et</string>\n    <string name=\"text_filter_text\">Metni filtrele</string>\n    <string name=\"text_filter_ellipsis\">Filtre…</string>\n    <string name=\"subject_log_report\">Günlük raporu</string>\n    <string name=\"start_recording_log\">Kayıt</string>\n    <string name=\"settings\">Ayarlar</string>\n    <string name=\"send_log_title\">Günlüğü Gönder</string>\n    <string name=\"save_log\">Günlüğü Kaydet</string>\n    <string name=\"save_as\">Farklı Kaydet…</string>\n    <string name=\"record_log\">Günlük Kaydı</string>\n    <string name=\"pref_show_timestamp_title\">PID ve Zaman Damgasını Göster</string>\n    <string name=\"pref_show_timestamp_summary\">Genişletildiğinde işlem kimliğini ve zaman damgasını göster.</string>\n    <string name=\"pref_log_write_period_title\">Yazma Aralığı</string>\n    <string name=\"pref_log_write_period_summary\">Kayıt yaparken, her %1$d satırda bir SD karta yaz.</string>\n    <string name=\"pref_log_line_period_error\">Lütfen 1 ile 1000 arasında bir tam sayı girin.</string>\n    <string name=\"pref_expanded_by_default_title\">Öntanımlı Olarak Genişlet</string>\n    <string name=\"pref_expanded_by_default_summary\">Öntanımlı olarak tam günlük metnini göster.</string>\n    <string name=\"pref_filter_pattern_title\">Etiketleri Filtrele</string>\n    <string name=\"pref_filter_pattern_summary\">Günlüklerden seçilen etiketleri filtrele.</string>\n    <string name=\"pref_display_limit_title\">Günlük Görüntüleme Sınırı</string>\n    <string name=\"pref_display_limit_summary\">Yetersiz bellek hatalarını önlemek için yalnızca son %1$d günlüğü göster.</string>\n    <string name=\"pref_default_log_level_title\">Öntanımlı Günlük Seviyesi</string>\n    <string name=\"pref_default_log_level_summary\">Başlangıçta, dosyaları açarken ve kayıt sırasında günlük seviyesi.</string>\n    <string name=\"pref_cat_configuration\">Yapılandırma</string>\n    <string name=\"pref_cat_appearance\">Görünüm</string>\n    <string name=\"pref_cat_advanced\">Gelişmiş</string>\n    <string name=\"pref_buffer_title\">Günlük Arabellek(ler)i</string>\n    <string name=\"open\">Aç</string>\n    <string name=\"notification_title\">Günlük kaydı devam ediyor</string>\n    <string name=\"notification_ticker\">Günlük kaydı başladı</string>\n    <string name=\"notification_subtext\">Kaydı durdurmak için dokunun</string>\n    <string name=\"no_saved_logs\">Kaydedilen günlük yok.</string>\n    <string name=\"manage_saved_logs\">Kaydedilen Günlükleri Yönet</string>\n    <string name=\"log_saved\">Günlük kaydedildi.</string>\n    <string name=\"log_recording_started\">Günlük kaydı başladı.</string>\n    <string name=\"log_level\">Günlük Seviyesi</string>\n    <string name=\"log_cleared\">Günlükler temizlendi</string>\n    <string name=\"filter_choice_tag\">Etiket</string>\n    <string name=\"filter_choice_pid\">PID</string>\n    <string name=\"filter_choice\">Arama ölçütü</string>\n    <string name=\"enter_good_filename\">Lütfen geçerli bir dosya adı girin.</string>\n    <string name=\"enter_filename\">Dosya adını girin</string>\n    <string name=\"dialog_compiling_log\">Günlük derleniyor…</string>\n    <string name=\"delete_saved_log\">Kaydedilen Günlükleri Sil</string>\n    <string name=\"copy_to_clipboard\">Panoya kopyala</string>\n    <string name=\"add_filter_ellipsis\">Filtre Ekle…</string>\n    <string name=\"add_filter\">Filtre Ekle</string>\n    <string name=\"log_level_fatal\">Ölümcül</string>\n    <string name=\"log_level_warn\">Uyarı</string>\n    <string name=\"log_level_verbose\">Ayrıntılı</string>\n    <string name=\"log_level_info\">Bilgi</string>\n    <string name=\"log_level_error\">Hata</string>\n    <string name=\"log_level_debug\">Hata ayıklama</string>\n    <string name=\"filename\">Dosya adı</string>\n    <string name=\"restart_log_viewer_to_see_changes\">Değişiklikleri görmek için günlük görüntüleyici penceresini yeniden başlatın.</string>\n    <string name=\"pref_log_viewer_msg\">Günlüklerin nasıl görüntüleneceğini yapılandırın.</string>\n    <string name=\"log_viewer\">Günlük Görüntüleyici</string>\n    <string name=\"latest_backup\">En son yedekleme</string>\n    <string name=\"gz_bz2_compressed\">%1$s ile sıkıştırıldı</string>\n    <string name=\"pgp_aes_rsa_encrypted\">%1$s ile şifrelendi</string>\n    <string name=\"no_encryption\">Şifreleme yok</string>\n    <string name=\"base_backup\">Temel yedekleme</string>\n    <string name=\"failed\">Başarısız oldu</string>\n    <string name=\"confirm_import_keystore\">Var olan KeyStore\\'u değiştirmek istediğinizden emin misiniz\\? Bu eylem geri alınamaz.</string>\n    <string name=\"import_keystore\">KeyStore\\'u içe aktar</string>\n    <string name=\"pref_import_export_keystore_msg\">App Manager tarafından dahili olarak kullanılan Bouncy Castle KeyStore\\'u (BKS) içe/dışa aktarın.</string>\n    <string name=\"pref_import_export_keystore\">KeyStore\\'u içe/dışa aktar</string>\n    <string name=\"app_signing_signatures\">İmzalar</string>\n    <string name=\"pref_rules_msg\">Anında engelleme, kuralları içe/dışa aktarma/kaldırma vs.</string>\n    <string name=\"saf\">SAF</string>\n    <string name=\"orientation_right_to_left\">Sağdan sola</string>\n    <string name=\"orientation_left_to_right\">Soldan sağa</string>\n    <string name=\"orientation_follow_locale\">Yerel ayarı takip et</string>\n    <plurals name=\"file_deletion_confirmation\">\n        <item quantity=\"one\">%d dosya silinecek</item>\n        <item quantity=\"other\">%d dosya silinecek</item>\n    </plurals>\n    <string name=\"hidden\">Gizli</string>\n    <string name=\"suspended\">Askıya alındı</string>\n    <string name=\"no_changes\">Değişiklik yok</string>\n    <string name=\"pref_display_changes_msg\">Sürüm, izleyiciler, bileşenler, izinler, imzalar, SDK, vb.\\'deki değişiklikleri sürüm denetimi ile görüntüleyin.</string>\n    <string name=\"pref_display_changes\">Değişiklikleri görüntüle</string>\n    <string name=\"netpolicy_disable_network_access\">Ağ erişimini devre dışı bırak</string>\n    <string name=\"netpolicy_reject_wifi_data\">Wi-Fi verilerini reddet</string>\n    <string name=\"netpolicy_reject_vpn_data\">VPN verilerini reddet</string>\n    <string name=\"netpolicy_reject_cellular_data\">Hücresel verileri reddet</string>\n    <string name=\"netpolicy_allow_background_data\">Veri Tasarrufu açıkken arka plan verilerine izin ver</string>\n    <string name=\"netpolicy_reject_background_data\">Arka plan verilerini reddet</string>\n    <string name=\"port_number_invalid\">Geçersiz bağlantı noktası numarası.</string>\n    <string name=\"port_number_empty\">Bağlantı noktası numarası boş.</string>\n    <string name=\"adb_connect_port_number_description\">Bağlantı noktası numarası, <b>Aygıt adı</b> bölümünün hemen altındaki <b>IP adresi &amp; bağlantı noktası</b> bölümünün altında bulunur.</string>\n    <string name=\"port_number\">Bağlantı noktası</string>\n    <string name=\"adb_connect\">Bağlan</string>\n    <string name=\"wireless_debugging\">Kablosuz hata ayıklama</string>\n    <string name=\"unknown_net_policy\">Bilinmeyen ağ politikası (%1$s - %2$X)</string>\n    <string name=\"failed_to_prevent_background_run\">%1$s arka planda çalışması engellenemedi</string>\n    <string name=\"community_links\"><a href=\"https://matrix.to/#/#appmanager:matrix.org\">Matrix</a> • <a href=\"https://t.me/AppManagerChannel\">Telegram</a> • <a href=\"https://twitter.com/AppManagerNews\">Twitter</a></string>\n    <string name=\"community\">Topluluk</string>\n    <plurals name=\"alert_failed_to_import_backups\">\n        <item quantity=\"one\">%1$d yedek içe aktarılamadı</item>\n        <item quantity=\"other\">%1$d yedek içe aktarılamadı</item>\n    </plurals>\n    <string name=\"import_from_tb\">Titanium Backup\\'tan içe aktar</string>\n    <string name=\"import_from_oab\">OAndBackup\\'tan içe aktar</string>\n    <string name=\"pref_import_backups_msg\">OAndBackup, Swift Backup (3.0–3.2) veya Titanium Backup\\'tan yedekleri içe aktarın.</string>\n    <string name=\"pref_import_backups\">Yedekleri içe aktar</string>\n    <string name=\"added_to_queue\">Sıraya eklendi</string>\n    <string name=\"minimum_version\">En düşük sürüm: %d</string>\n    <string name=\"help_uses_permissions_tab\"><b>Vermek</b> veya <b>iptal etmek</b> için bir ögeye tıklayın. Yalnızca <b>tehlikeli</b> ve <b>geliştirme</b> izinleri verilebilir veya iptal edilebilir.</string>\n    <string name=\"help_permissions_tab\">Bu izinler bu uygulama tarafından tanımlanır ve iptal edilemez.</string>\n    <string name=\"help_app_ops_tab\"><b>İzin vermek</b> veya <b>yok saymak</b> için bir ögeye tıklayın. Desteklenen diğer modları görmek için bir ögeye uzun tıklayın.</string>\n    <string name=\"saved_filters\">Kaydedilen filtreler</string>\n    <string name=\"permission_flags\">İzin işaretleri</string>\n    <string name=\"pref_selected_users_msg\">App Manager\\'i yalnızca seçilen kullanıcılarla çalışacak şekilde kısıtlayın.</string>\n    <string name=\"pref_selected_users\">Seçilen kullanıcılar</string>\n    <string name=\"error_with_details\">Hata: %s</string>\n    <string name=\"notice_saf\">Birimlerin aksine, seçilen dizin, kaydedilmiş APK\\'lar ve yedekler dahil olmak üzere App Manager ile ilgili tüm dosyaları depolamak için kullanılacaktır. Depolama Erişim Sistemi (SAF) çok yavaştır, bu nedenle bu seçeneği yalnızca diğerleri kullanılamadığında kullanmalısınız.</string>\n    <string name=\"files\">Dosyalar</string>\n    <string name=\"storage\">Depolama</string>\n    <string name=\"notice\">Dikkat</string>\n    <string name=\"paired_successfully\">Eşleştirildi.</string>\n    <string name=\"adb_pair\">Eşleştir</string>\n    <string name=\"invalid_password\">Geçersiz parola, tekrar deneyin.</string>\n    <string name=\"keystore_pass_cannot_be_empty\">KeyStore parolası boş olamaz.</string>\n    <string name=\"keystore_password_info\">Aşağıdaki, App Manager KeyStore parolasıdır. App Manager KeyStore\\'u yedekleyecek/geri yükleyecekseniz lütfen güvenli bir yerde saklayın. <b>Bu mesaj tekrar görüntülenmeyecek.</b></string>\n    <string name=\"running_services_logcat_hint\">Öntanımlı filtre olarak karşılık gelen işlem kimliğiyle günlük görüntüleyiciyi açmak için bir ögeye tıklayın.</string>\n    <string name=\"pid\">İşlem kimliği</string>\n    <plurals name=\"pref_thread_count_msg\">\n        <item quantity=\"one\">Paralel olarak en fazla %1$d işlem çalıştır</item>\n        <item quantity=\"other\">Paralel olarak en fazla %1$d işlem çalıştır</item>\n    </plurals>\n    <string name=\"pref_thread_count_hint\">Değer 0 ila %1$d arasında olmalıdır; burada 0, <i>belirli bir zamandaki azami işlem sayısı</i> anlamına gelir.</string>\n    <string name=\"pref_thread_count\">Paralel çalıştırma</string>\n    <string name=\"type_uri_array_list\">URI\\'lerin listesi</string>\n    <string name=\"type_uri_array\">URI\\'lerin dizisi</string>\n    <string name=\"pref_always_on_background_msg\">Uygulamaları her zaman arka planda kur ve bittiğinde bir bildirim görüntüle.</string>\n    <string name=\"pref_always_on_background\">Arka planda kur</string>\n    <string name=\"pref_block_trackers_msg\">App Manager kullanarak bir uygulama kurduktan sonra izleme bileşenlerini engelle.</string>\n    <string name=\"next\">İleri</string>\n    <string name=\"installer_app_installed\">Uygulama kuruldu</string>\n    <string name=\"staging_apk_files\">Hazırlanıyor…</string>\n    <string name=\"background\">Arka plan</string>\n    <string name=\"trim_caches_in_all_apps_description\">Android sistemi dahil tüm uygulamalardan önbellek dosyalarını siler</string>\n    <string name=\"trim_caches_in_all_apps\">Tüm uygulamalarda önbellekleri kırp</string>\n    <string name=\"user_root\">Root kullan</string>\n    <string name=\"paste\">Yapıştır</string>\n    <string name=\"set_package_name_first\">Önce paket adını ayarlayın!</string>\n    <string name=\"identifier\">Tanımlayıcı</string>\n    <string name=\"backup_volume_dialog_description\"><tt>/tree</tt> ön ekine sahip birimler, Depolama Erişim Sistemi (SAF) kullanılarak seçilen klasörlerdir. Bu klasörler dışında, App Manager için öntanımlı dizin <tt>AppManager</tt> adlı bir alt klasördür.</string>\n    <string name=\"second_degree_tracker_note\">² ön eki, izleyicilerin <a href=\"https://etip.exodus-privacy.eu.org/\">ETIP bekleme listesinde</a> olduğunu gösterir, yani gerçek izleyiciler olup olmadıkları hala araştırılmaktadır.</string>\n    <string name=\"failed_to_uninstall_app\">Kaldırma başarısız oldu</string>\n    <string name=\"import_from_sb\">Swift Backup 3.0 – 3.2\\'den içe aktar</string>\n    <string name=\"java\">Java</string>\n    <string name=\"smali\">Smali</string>\n    <string name=\"accessibility_service_description\">Root yok modunda önbelleği temizleme gibi belirli işlemleri gerçekleştirmek için genel erişilebilirlik hizmeti.</string>\n    <string name=\"explore\">Keşfet</string>\n    <string name=\"system_partition\">Android kökü</string>\n    <string name=\"exit_confirmation\">Çıkış onayı</string>\n    <string name=\"pref_import_backups_hint\">Yedekleme dosyalarını (Swift Backup/Titanium Backup) veya dizinlerini (OAndBackup) içeren bir dizin seçin</string>\n    <string name=\"extract\">Çıkart</string>\n    <string name=\"replace\">Değiştir</string>\n    <string name=\"rename\">Yeniden adlandır</string>\n    <string name=\"intent_firewall_and_disable\">IFW + devre dışı bırak</string>\n    <string name=\"intent_firewall\">IFW</string>\n    <string name=\"pref_default_blocking_method\">Öntanımlı engelleme yöntemi</string>\n    <string name=\"pref_default_blocking_method_description\">Engelleme yöntemi seçme seçeneğinin olmadığı yerlerde öntanımlı olarak kullanılacak yöntem.\n\\n<b>Not:</b> “IFW” sağlayıcılarla çalışmaz, bunun yerine “devre dışı bırak” kullanılır.</string>\n    <string name=\"pref_intent_firewall_description\">Bileşenleri yalnızca Intent Firewall kullanarak engelle. Bazı sistem uygulamaları güvenlik duvarlarını atlayabildiğinden tavsiye edilmez.</string>\n    <string name=\"authenticating\">Kimlik doğrulanıyor…</string>\n    <string name=\"search_type_contains\">İçerir</string>\n    <string name=\"search_type_prefix\">Ön ek</string>\n    <string name=\"search_type_suffix\">Son ek</string>\n    <string name=\"search_type_regular_expressions\">Düzenli ifade</string>\n    <string name=\"pref_intent_firewall_and_disable_description\">Intent Firewall kullanarak bileşenleri engelle ve devre dışı bırak. Root kullanıcıları için tavsiye edilen yöntemdir.</string>\n    <string name=\"pref_disable_description\">Yalnızca bileşenleri devre dışı bırak. Uygulamalar bunu atlayabildiğinden root kullanıcıları için tavsiye edilmez. ADB modlarında, yalnızca test amaçlı uygulamalar bu yöntemle devre dışı bırakılabilir.</string>\n    <plurals name=\"usage_minutes\">\n        <item quantity=\"one\">%1$d dak</item>\n        <item quantity=\"other\">%1$d dak</item>\n    </plurals>\n    <string name=\"vt_failed\">VirusTotal: Başarısız oldu</string>\n    <string name=\"toggle_internet\">İnterneti kullan</string>\n    <string name=\"vt_uploading\">VirusTotal: Karşıya yükleniyor…</string>\n    <string name=\"vt_queued\">VirusTotal: Sıraya alındı</string>\n    <string name=\"vt_success\">VirusTotal: %1$d/%2$d</string>\n    <string name=\"pref_vt_apikey\">VirusTotal API Anahtarı</string>\n    <string name=\"pref_vt_apikey_description\">Bir API anahtarı, App Manager\\'in APK dosyalarını VirusTotal\\'a yüklemesini ve raporları almasını sağlar. Ücretsiz bir API anahtarı almak için https://virustotal.com adresinde kaydolun.</string>\n    <string name=\"pref_vt_apikey_summary\">APK dosyalarını VirusTotal ile taramayı etkinleştirin.</string>\n    <string name=\"uses_play_app_signing\">Play Uygulama İmzalama</string>\n    <string name=\"scan_in_vt\">VirusTotal\\'da Tara</string>\n    <string name=\"process_id\">İşlem Kimliği</string>\n    <string name=\"parent_process_id\">Üst İşlem Kimliği</string>\n    <string name=\"virtual_memory\">Sanal Bellek</string>\n    <string name=\"cpu_percent\">%% CPU</string>\n    <string name=\"cpu_time\">CPU Süresi</string>\n    <string name=\"priority\">Öncelik</string>\n    <string name=\"threads\">İş Parcacığı Sayısı</string>\n    <string name=\"state\">İşlem Durumu</string>\n    <string name=\"commandline_args\">Komut satırı argümanları</string>\n    <string name=\"swap\">Takas</string>\n    <string name=\"memory_chart_info\">● %1$s Uygulama ● %2$s Önbellek ● %3$s Arabellekler ● %4$s Boş</string>\n    <string name=\"swap_chart_info\">● %1$s Kullanılan ● %2$s Boş</string>\n    <string name=\"failed_to_change_app_op_mode\">Uygulama çalışma modu değiştirilemedi.</string>\n    <string name=\"failed_to_use_the_current_mode_of_operation\">Geçerli çalışma modu kullanılamıyor. Bu oturum için root olmayan moda geri dönülüyor.</string>\n    <string name=\"warning_working_on_root_mode\">Uyarı: ADB modu yerine root ile çalışılıyor.</string>\n    <string name=\"magisk_denylist\">Magisk Reddetme Listesi</string>\n    <string name=\"failed_to_disable_magisk_deny_list\">Magisk Reddetme Listesi devre dışı bırakılamadı</string>\n    <string name=\"mode_of_op_with_inferred_mode_of_op\">%1$s (Çıkarılan mod: %2$s)</string>\n    <plurals name=\"usage_seconds\">\n        <item quantity=\"one\">%1$d sn</item>\n        <item quantity=\"other\">%1$d sn</item>\n    </plurals>\n    <string name=\"vt_checking\">VirusTotal: Denetleniyor…</string>\n    <string name=\"vt_permalink\">VirusTotal için kalıcı bağlantı</string>\n    <string name=\"vt_slowness_warning\">İnternet hızına ve sunucudaki yüke bağlı olarak bu biraz zaman alabilir.</string>\n    <string name=\"vt_disclaimer\">VirusTotal ve logoları Chronicle LLC\\'nin ticari markasıdır. Ne App Manager (API istemcisi) ne de yazarları VirusTotal\\'a gönderebileceğiniz hiçbir veriden sorumlu değildir.</string>\n    <string name=\"uses_play_app_signing_description\">Bu uygulama, <a href=\"https://support.google.com/googleplay/android-developer/answer/9842756\">Play Uygulama İmzalama</a> kullanıyor <i>olabileceğini</i> gösteren belirli işaretler içeriyor. Bu şemayla, imzalama anahtarları Google\\'ın sunucularında saklanır ve uygulamanın imzalanmasından Google sorumludur. İmzalama bilgilerinin eşleşmesinin, uygulamanın geliştiricisi (ve bu durumda Google) dışında herhangi bir kişi tarafından değiştirilmediğini doğrulamanın tek yolu olduğunu unutmayın.</string>\n    <string name=\"vt_scan_date\">Tarama tarihi: %1$s</string>\n    <string name=\"failed_to_enable_magisk_deny_list\">Magisk Reddetme Listesi etkinleştirilemedi</string>\n    <string name=\"hidden_api_enforcement_policy\">Gizli API zorunluluk politikası</string>\n    <string name=\"hidden_api_enf_policy_none\">Yok (gizli API\\'ye tam erişim)</string>\n    <string name=\"hidden_api_enf_policy_dark_grey_and_black\">Zorunlu (koyu gri ve kara listeler)</string>\n    <string name=\"binary_32_bit\">32 Bit</string>\n    <string name=\"endianness_little_endian\">Little endian</string>\n    <string name=\"endianness_big_endian\">Big endian</string>\n    <string name=\"so_type_shared_library\">Paylaşılan kütüphane</string>\n    <string name=\"save_and_exit\">Kaydet ve çık</string>\n    <string name=\"hidden_api_enf_policy_warn\">Uyar (gizli API\\'ye tam erişim ancak uyarı verir)</string>\n    <string name=\"zygote_preload_name\">Zygote ön yükleme adı</string>\n    <string name=\"so_type_executable\">Çalıştırılabilir dosya</string>\n    <string name=\"file_modified_are_you_sure\">Dosya değiştirildi. Tüm değişikliklerinizi iptal edip çıkılsın mı\\?</string>\n    <string name=\"hidden_api_enf_policy_black\">Zorunlu (yalnızca kara listeler)</string>\n    <string name=\"primary_abi\">Birincil ABI</string>\n    <string name=\"hidden_api_enf_default_policy\">Öntanımlı (uygulama türüne göre)</string>\n    <string name=\"binary_64_bit\">64 Bit</string>\n    <string name=\"pref_saved_apk_name_format\">Kaydedilen APK Adı Biçimi</string>\n    <string name=\"auth_manager_title\">Yetkilendirme Yöneticisi</string>\n    <string name=\"regenerate_auth_key\">Yetkilendirme anahtarını yeniden oluştur</string>\n    <string name=\"shortcut_icon\">Kısayol Simgesi</string>\n    <string name=\"pref_saved_apk_name_format_msg\">APK dosyalarını kaydettiğinizde adlandırmak için kullanılacak biçim.</string>\n    <string name=\"auth_manager_description\">Bir Intent\\'i harici bir uygulamadan başlatmak için, <tt>auth</tt> adlı ek bir alan sağlamak gereklidir ve şu anahtarı içermelidir:</string>\n    <string name=\"regenerate_auth_key_warning\">Emin misiniz\\? Tüm üçüncü taraf uygulamaların yeni yetkilendirme anahtarıyla yeniden yapılandırılması gerekir.</string>\n    <string name=\"sort_by_installation_date\">Kurulum tarihi</string>\n    <string name=\"backup_volume_unavailable_warning\">Seçilen yedekleme birimi şu anda kullanılabilir değil. Harici bir depolama biriminde bulunuyorsa, lütfen onu takın veya yedekleme birimini değiştirin.</string>\n    <string name=\"change_backup_volume\">Birimi değiştir</string>\n    <string name=\"external\">Harici</string>\n    <string name=\"tracker\">İzleyici</string>\n    <string name=\"input_ssaid_instruction\">SSAID, %1$d bayt bir onaltılık sayıdır, yani 0\\'dan 9\\'a rakamlar ve a, b, c, d, e ve f harflerini içeren %2$d uzunluğunda bir dizgedir.</string>\n    <string name=\"screen_time\">Ekran Süresi</string>\n    <string name=\"internal\">Dahili</string>\n    <string name=\"open_in_new_window\">Yeni pencere</string>\n    <string name=\"type_string_set\">Dizge kümesi</string>\n    <string name=\"pref_vt_prompt_before_uploading\">Dosyayı karşıya yüklemeden önce sor.</string>\n    <string name=\"vt_confirm_upload_and_scan\">Evet, yükle ve tara</string>\n    <string name=\"vt_confirm_uploading_file\">Dosya, VirusTotal veri tabanında bulunamadı. Karşıya yüklemek istiyor musunuz\\?</string>\n    <string name=\"log_stop_recording\">Kaydı durdur</string>\n    <string name=\"apk_checksums\">APK Sağlama Toplamları</string>\n    <string name=\"item_select\">Seç</string>\n    <string name=\"app_explorer\">Uygulama Gezgini</string>\n    <string name=\"netpolicy_cannot_be_modified_for_core_apps\">Ağ politikası, çekirdek Android uygulamaları için değiştirilemez.</string>\n    <string name=\"pref_pure_black_theme_msg\">Gece modu etkinleştirildiğinde tamamen siyah bir arka plan kullanın.</string>\n    <string name=\"pref_pure_black_theme\">Saf siyah tema</string>\n    <string name=\"open_developer_options_page\">Android ayarlarında geliştirici seçenekleri sayfasını açın</string>\n    <string name=\"usage_times_opened\">Açılma sayısı</string>\n    <string name=\"usage_last_used\">Son kullanma</string>\n    <string name=\"usage_mobile_data\">Mobil veri</string>\n    <string name=\"usage_wifi_data\">Wi-Fi verisi</string>\n    <string name=\"restore_dots\">Geri yükle…</string>\n    <string name=\"backup_apps_cannot_be_restored\">Aşağıdaki uygulamalar, temel yedekleri olmadığı için geri yüklenemiyor:</string>\n    <string name=\"restart_device\">Aygıtı yeniden başlat</string>\n    <string name=\"frozen\">Donduruldu</string>\n    <string name=\"freeze\">Dondur</string>\n    <string name=\"unfreeze\">Çöz</string>\n    <string name=\"import_backups_warning_delete_backups_after_import\">Yedekler App Manager\\'a aktarıldıktan sonra silinsin mi\\? Her yedek başarılı bir şekilde içe aktarıldıktan sonra ayrı ayrı silinir. Emin değilseniz <b>Hayır</b> seçeneğini seçin.</string>\n    <string name=\"backup_no_backups_present\">Yedekleme yok.</string>\n    <string name=\"backup_apps_cannot_be_backed_up\">Aşağıdaki uygulamalar kurulu değil ve yedeklenemiyor:</string>\n    <string name=\"pref_reload_apps_msg\">Beklenmedik davranış durumunda App Manager veri tabanında depolanan uygulamaların listesini yeniden yükleyin.</string>\n    <string name=\"changelog_type_new\">Yeni</string>\n    <string name=\"changelog_type_fix\">Düzeltme</string>\n    <string name=\"changelog_type_improve\">İyileştirme</string>\n    <string name=\"pref_reload_apps\">Uygulamaları yeniden yükle</string>\n    <string name=\"troubleshooting\">Sorun giderme</string>\n    <string name=\"unsupported_split_apk\">Desteklenmiyor</string>\n    <string name=\"view_changelog\">Bu sürümdeki yenilikleri öğrenin</string>\n    <string name=\"sort_by_total_size\">Toplam boyut</string>\n    <string name=\"am_command\"><tt>am</tt> komutu</string>\n    <string name=\"pref_sign_apk_error_signing_key_not_added\">Bir APK dosyasını imzalamak için geçerli bir imzalama anahtarı gereklidir.</string>\n    <string name=\"pref_sign_apk_no_signing_key\">İmzalama anahtarı yok</string>\n    <string name=\"failed_to_freeze\"><xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g> dondurulamadı.</string>\n    <string name=\"freeze_unfreeze\">Dondur/çöz</string>\n    <string name=\"profile_freeze_msg\">Uygulamaları duruma göre dondurur veya çözer</string>\n    <string name=\"suspend_app\">Askıya al</string>\n    <plurals name=\"alert_failed_to_unfreeze\">\n        <item quantity=\"one\">%1$d uygulama çözülemedi</item>\n        <item quantity=\"other\">%1$d uygulama çözülemedi</item>\n    </plurals>\n    <string name=\"sort_by_frozen_app\">Önce dondurulan</string>\n    <string name=\"filter_frozen_apps\">Dondurulan uygulamalar</string>\n    <string name=\"pref_version_changelog\">Sürüm/Değişiklik günlüğü</string>\n    <string name=\"hide_app\">Gizle</string>\n    <string name=\"failed_to_unfreeze\"><xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g> çözülemedi.</string>\n    <string name=\"pref_default_freezing_method\">Öntanımlı dondurma yöntemi</string>\n    <string name=\"pref_default_freezing_method_description\">Bir dondurma yöntemi seçme seçeneğinin olmadığı yerlerde öntanımlı olarak kullanılacak yöntem.</string>\n    <plurals name=\"alert_failed_to_freeze\">\n        <item quantity=\"one\">%1$d uygulama dondurulamadı</item>\n        <item quantity=\"other\">%1$d uygulama dondurulamadı</item>\n    </plurals>\n    <string name=\"suspend_app_description\">Bu en zayıf dondurma yöntemidir. Askıya alınan bir uygulama başlatıcıda görünmeye devam edebilir ancak gri renkte olur ve başlatılamaz.</string>\n    <string name=\"disable_app_description\">Tavsiye edilen dondurma yöntemi. Uygulamayı ve tüm bileşenlerini devre dışı bırakır, ancak tüm kısayollar kaybolacaktır.</string>\n    <string name=\"hide_app_description\">Bu yöntem yalnızca günlük kullanım için tavsiye edilir. Gizli bir uygulama kaldırılmış gibi görünür. Ancak uygulama yeniden kurulursa veya güncellenirse yeniden görünebilir.</string>\n    <string name=\"pref_privacy\">Gizlilik</string>\n    <string name=\"pref_appearance_description\">Tema, yönlendirme, özellikler, vb.</string>\n    <string name=\"pref_privacy_description\">Ekran kilidi, yetkilendirme, vb.</string>\n    <string name=\"user_manual\">Kullanıcı kılavuzu</string>\n    <string name=\"get_help\">Yardım alın</string>\n    <string name=\"pref_advanced_pref\">Kullanıcılar, APK adı biçimi, paralel çalıştırma, vb.</string>\n    <string name=\"file_modification_date\">Değiştirildi</string>\n    <string name=\"file_open_with\">Birlikte aç</string>\n    <string name=\"file_change_open_with\">Birlikte açmayı değiştir</string>\n    <string name=\"file_shortcut_target_file\">Hedef dosya</string>\n    <string name=\"file_cut\">Kes</string>\n    <string name=\"fm_open_with_for_this_file_only\">Yalnızca bu dosya için</string>\n    <string name=\"file_open_as\">Farklı aç…</string>\n    <string name=\"file_open_with_os_default_dialog\">İşletim sistemi öntanımlı iletişim kutusu ile aç</string>\n    <string name=\"open_as_text\">Metin</string>\n    <string name=\"open_as_image\">Resim</string>\n    <string name=\"open_as_video\">Video</string>\n    <string name=\"open_as_archive\">Arşiv</string>\n    <string name=\"delete_filename\">%s sil</string>\n    <string name=\"confirm_file_deletion\">Evet, sil</string>\n    <string name=\"on_unfreeze_open_application\">Çözdükten sonra uygulamayı aç</string>\n    <string name=\"tap_to_freeze_app\">Dondurmak için dokunun</string>\n    <string name=\"action_stop_service\">Durdur</string>\n    <string name=\"file_accessed_date\">Erişildi</string>\n    <string name=\"file_creation_date\">Oluşturuldu</string>\n    <string name=\"file_properties\">Özellikler</string>\n    <string name=\"fm_always_open_with\">Her zaman aç</string>\n    <string name=\"file_open_with_custom_activity\">Özel</string>\n    <string name=\"open_as_folder\">Klasör</string>\n    <string name=\"freeze_on_phone_locked\">Telefon kilitlendiğinde uygulamayı otomatik olarak dondur</string>\n    <string name=\"waiting_for_the_phone_to_be_locked\">Telefonun kilitlenmesi bekleniyor…</string>\n    <string name=\"open_as_other\">Diğer</string>\n    <string name=\"on_open_application_no_recents\">Başlatılan uygulamayı son kullanılanlarda gösterme</string>\n    <string name=\"sort_by_data_usage\">Veri kullanımı</string>\n    <string name=\"filter_apps_with_keystore\">KeyStore ile</string>\n    <string name=\"filter_apps_with_saf\">SAF ile</string>\n    <string name=\"filter_apps_with_ssaid\">SSAID ile</string>\n    <string name=\"action_continue\">Devam et</string>\n    <string name=\"export_app_list_select_format\">Uygulama listesini dışa aktarmak için biçim seçin</string>\n    <string name=\"install_for_another_user\">Şunun için kur…</string>\n    <string name=\"adb_incomplete_usb_debugging_message\">USB Hata Ayıklama düzgün yapılandırılmamış gibi görünüyor. Lütfen ek adımlar için <a href=\"https://muntashirakon.github.io/AppManager/#subsec:enable-usb-debugging\">belgelendirmeyi</a> okuyun. Adımları zaten biliyorsanız, lütfen geliştirici seçeneklerini açmak için “Aç” düğmesine, veya root yok modunu kullanmaya devam etmek için “Kapat” düğmesine tıklayın.</string>\n    <string name=\"grant_overlay_permission_message\">App Manager\\'in diğer tüm pencerelerin üstünde kayan bir pencere görüntülemesine izin verin</string>\n    <string name=\"grant_required_permission\">Gerekli izni ver</string>\n    <string name=\"option_display_dot_files\">Noktayla başlayan dosyalar</string>\n    <string name=\"export_option_markdown\">Markdown</string>\n    <string name=\"export_app_list\">Uygulama listesini dışa aktar</string>\n    <string name=\"export_option_xml\">XML</string>\n    <string name=\"option_display_folders_on_top\">Klasörler üstte</string>\n    <string name=\"adb_incomplete_usb_debugging_title\">Eksik USB Hata Ayıklama</string>\n    <string name=\"funding_campaign_dialog_message\">Sınırlı bir süre boyunca App Manager için bir <b>fonlama kampanyası</b> yapıyoruz. Kampanya hakkında daha fazla bilgi edinmek için <a href=\"https://opencollective.com/app-manager#category-ABOUT\">opencollective.com/app-manager</a> adresini ziyaret edin. Bu bildirim bir daha gösterilmeyecektir, ancak tüm kampanya süresince Ayarlar sayfasında bulabilirsiniz.</string>\n    <string name=\"funding_campaign_text\">Sınırlı bir süre boyunca App Manager için bir <b>fonlama kampanyası</b> yapıyoruz. <a href=\"https://opencollective.com/app-manager#category-ABOUT\">Daha fazla bilgi edinin…</a></string>\n    <string name=\"confirm_uninstallation\">Kaldırma işlemini onayla</string>\n    <string name=\"class_hierarchy\">Hiyerarşi</string>\n    <string name=\"title_ui_tracker\">Kullanıcı Arayüzü İzleyici</string>\n    <string name=\"grant_accessibility_permission_for_tracking_window_contents\">App Manager\\'ın öndeki pencerenin içeriğini izlemek için erişilebilirlik özelliğini kullanmasına izin verin.</string>\n    <string name=\"title_terminal_emulator\">Terminal</string>\n    <string name=\"title_labs_activity\">Laboratuvarlar</string>\n    <string name=\"app_manager_build_expired\">Güncelleme Gerekli</string>\n    <string name=\"app_manager_build_expired_message\">Aygıtınızın ve verilerinizin güvenliğini sağlamak için, kullanmakta olduğunuz App Manager sürümü kullanımdan kaldırıldı. Kullanmaya devam etmek için en son sürüme güncellemeniz veya güncelleme yoksa kaldırmanız gerekir.</string>\n    <string name=\"app_manager_build_expiring_soon_warning\">App Manager\\'ın bu sürümünün süresi çok yakında dolacak. Lütfen en son sürüme güncelleyin.</string>\n    <string name=\"app_can_write_and_execute_in_same_place\">Uygulama <a href=\"https://en.wikipedia.org/wiki/W%5EX\">W^X politikasını</a> ihlal ediyor ve aynı dizinde veya belleğin aynı bölümünde yazma ve çalıştırma yeteneğine sahiptir. Bu, uygulama içine gömülü çalıştırılabilir dosyaların değiştirilmesi ya da internetten indirilmesi yoluyla herhangi bir dosyanın çalıştırılmasına izin verir. Uygulamanın amaçlanan davranışı bu olmadığı sürece (örn. terminal öykünücüleri), uygulamanın SDK 29 (Android 10) ve sonrasını hedefleyen daha yeni bir sürümünü veya alternatiflerini bulmanız tavsiye edilir.</string>\n    <string name=\"renamed_successfully\">Yeniden adlandırıldı</string>\n    <string name=\"selinux_context\">SELinux bağlamı</string>\n    <string name=\"unix_file_permissions\">Mod</string>\n    <string name=\"file_group_id\">Grup (GID)</string>\n    <string name=\"file_owner_id\">Sahip (UID)</string>\n    <string name=\"calculating_file_size\">Hesaplanıyor…</string>\n    <string name=\"sort_by_filename\">Ad</string>\n    <string name=\"sort_by_last_modified\">Son değiştirilme</string>\n    <string name=\"sort_by_file_size\">Dosya boyutu</string>\n    <string name=\"sort_by_file_type\">Dosya türü</string>\n    <string name=\"select_a_dex2oat_compiler_filter\"><tt>dex2oat</tt> derleyici filtresi</string>\n    <string name=\"optimize_option_clear_profile_data\">Önceki profil verilerini temizle</string>\n    <string name=\"optimize_option_check_profiles\">DEX iyileştirmesi sırasında profil verilerini göz önünde bulundur</string>\n    <string name=\"optimize_option_force_dexopt\">DEX iyileştirmesini hemen gerçekleştir</string>\n    <string name=\"title_perform_runtime_optimization_to_apps\">Çalışma zamanı iyileştirmesi gerçekleştir</string>\n    <string name=\"action_run\">Çalıştır</string>\n    <string name=\"summary_perform_runtime_optimization_to_apps\">Uygulamaların performansını artırmak için DEX\\'i ve (Android 10 ve sonraki sürümlerde) düzenleri iyileştirin.</string>\n    <string name=\"action_optimize_app\">İyileştir</string>\n    <string name=\"batch_ops_runtime_optimization\">Çalışma zamanı iyileştirmesi</string>\n    <string name=\"optimize_option_compile_layouts\">Düzen kaynaklarını derle</string>\n    <string name=\"optimize_option_force_compilation\">Gerekli olmadığında bile derlemeye zorla</string>\n    <plurals name=\"alert_failed_to_optimize_apps\">\n        <item quantity=\"one\">%1$d uygulama iyileştirilemedi</item>\n        <item quantity=\"other\">%1$d uygulama iyileştirilemedi</item>\n    </plurals>\n    <string name=\"title_domains_supported_by_the_app\">Desteklenen Etki Alanları</string>\n    <string name=\"app_info_tag_open_links\">Açık bağlantılar</string>\n    <string name=\"source_stamp_verified_and_identified_to_be_from_source\">SourceStamp doğrulandı ve <xliff:g id=\"source\" example=\"Google Play\">%1$s</xliff:g> kaynağından olduğu belirlendi.</string>\n    <string name=\"block_unblock_components_description\">Verilen imzalarla tanımlanan tüm bileşenleri engelleyin veya engelini kaldırın</string>\n    <string name=\"warning_working_on_system_mode\">Uyarı: ADB modu yerine sistem üzerinde çalışıyor.</string>\n    <plurals name=\"alert_failed_to_unblock_components\">\n        <item quantity=\"one\">%1$d uygulama için bileşenlerin engellemesi kaldırılamadı</item>\n        <item quantity=\"other\">%1$d uygulamalar için bileşenlerin engellemesi kaldırılamadı</item>\n    </plurals>\n    <string name=\"unblock_components_dots\">Bileşenlerin engellemesini kaldırın…</string>\n    <string name=\"block_unblock_components_dots\">Bileşenleri engelle/engelini kaldır…</string>\n    <string name=\"pref_layout_direction\">Düzen yönü</string>\n    <string name=\"title_alternatives_to_bloatware\">Alternatifler</string>\n    <string name=\"browse_files\">Göz at</string>\n    <string name=\"pref_files_msg\">Dosya yöneticisini yapılandır.</string>\n    <string name=\"pref_files_remember_last_path\">Son açılan yol ve konumunu hatırla</string>\n    <string name=\"pref_files_remember_last_path_msg\">Bu seçenek etkinleştirildiğinde, yeni bir pencere açıldığında ev klasörü yerine son açılan klasör açılır.</string>\n    <string name=\"pref_set_home\">Ev klasörünü ayarla</string>\n    <string name=\"pref_enable_auto_lock\">Otomatik kilitlenme</string>\n    <string name=\"debloat_list_misc\">Çeşitli</string>\n    <string name=\"title_code_editor\">Kod Düzenleyici</string>\n    <string name=\"read_only_file_warning\">Uygulama Yöneticisi, dosyanın bulunduğu konumda yazma yetkisine sahip olmadığı için değişiklikler dosyaya aktarılamıyor. Farklı bir konuma kaydetmek ister misiniz?</string>\n    <string name=\"pref_enable_auto_lock_msg\">AYgıt kilitlendiğinde Uygulama Yöneticisi\\'ni kilitle.</string>\n    <string name=\"profile_modified_are_you_sure\">Profil değiştirildi. Tüm değişiklikler iptal edilsin ve çıkılsın mı?</string>\n    <string name=\"pref_zip_align_msg\">Bir APK dosyasını hizalamak, APK içindeki dosyalara verileri RAM\\'a kopyalamadan doğrudan erişilebilmesini sağlayarak bellek kullanımını azaltır. Bu adım, <tt>extractNativeLibs</tt> <tt>true</tt> olarak ayarlanmışsa gereklidir.</string>\n    <string name=\"replacement_text\">Değişim</string>\n    <string name=\"search_option_match_case\">Büyük/küçük harf eşleştir</string>\n    <string name=\"search_option_whole_word\">Bütün sözcük</string>\n    <string name=\"search_option_regex\">Düzenli ifade</string>\n    <string name=\"uninstall_app\">%1$s kaldır</string>\n    <string name=\"debloat_list_type\">Liste</string>\n    <string name=\"debloat_removal_type\">Tür</string>\n    <string name=\"system_app_put_back\">Geri koy</string>\n    <string name=\"debloater_title\">Temizleyici</string>\n    <string name=\"debloat_list_carrier\">Operatör/İnternet Servis Sağlayıcısı</string>\n    <string name=\"debloat_list_google\">Google</string>\n    <string name=\"debloat_removal_safe\">Güvenli</string>\n    <string name=\"debloat_removal_caution\">Dikkat</string>\n    <string name=\"static_shared_library\">Statik paylaşımlı kütüphane</string>\n    <string name=\"installing_package\">%1$s kuruluyor…</string>\n    <string name=\"backing_up_app\">%1$s yedekleniyor…</string>\n    <string name=\"restoring_app\">%1$s geri yükleniyor…</string>\n    <string name=\"pref_installer_force_dexopt_description\">DEX iyileştirmesini, sistem boştayken sistemin yapmasını beklemeden uygulamayı kurduktan hemen sonra gerçekleştirin.</string>\n    <string name=\"folder\">Klasör</string>\n    <string name=\"symbolic_link\">Sembolik bağlantı</string>\n    <string name=\"create_new_symbolic_link\">Yeni sembolik bağlantı</string>\n    <string name=\"title_confirm_deletion\">Silme işlemini onayla</string>\n    <string name=\"copy_keep_both_file\">İkisini de tut</string>\n    <string name=\"copied_successfully\">Kopyalandı.</string>\n    <string name=\"title_change_selinux_context\">SELinux bağlamını değiştir</string>\n    <string name=\"apply_recursively\">Kapsanan dosyalara uygula</string>\n    <string name=\"pref_send_notifications_to_connected_devices\">Bağlı aygıtlara bildirim gönder</string>\n    <plurals name=\"search_results\">\n        <item quantity=\"one\">%d sonuç</item>\n        <item quantity=\"other\">%d sonuç</item>\n    </plurals>\n    <string name=\"create_new_file\">Yeni dosya</string>\n    <string name=\"pref_zip_align\">APK dosyalarını hizala</string>\n    <string name=\"path_not_a_folder\">“%1$s” bir klasör değil</string>\n    <string name=\"action_checking\">Denetleniyor…</string>\n    <string name=\"report_not_available\">Kullanılabilir değil</string>\n    <string name=\"symbolic_link_not_supported\">Bu klasör sembolik bağlantı oluşturmayı desteklemiyor.</string>\n    <string name=\"redo\">Geri Al</string>\n    <plurals name=\"folder_count\">\n        <item quantity=\"one\">%d klasör</item>\n        <item quantity=\"other\">%d klasör</item>\n    </plurals>\n    <string name=\"action_replace_all\">Tümünü Değiştir</string>\n    <string name=\"uninstall_app_again_message\">Uygulama verileri ve imzası temizlenmeden kaldırıldı. Tamamen kaldırmak istiyor musunuz?</string>\n    <string name=\"create_new_folder\">Yeni klasör</string>\n    <string name=\"moved_successfully\">Taşındı</string>\n    <string name=\"pref_files_display_in_launcher\">Uygulama çekmecesinde “Dosyalar” uygulamasını göster</string>\n    <string name=\"tap_to_open_notification_settings\">Gizlemek için dokun</string>\n    <string name=\"action_lock_app\">Kilitle</string>\n    <string name=\"path_does_not_exist\">“%1$s” mevcut değil</string>\n    <string name=\"scan_report_from_pithus\">Pithus raporu</string>\n    <string name=\"empty_folder\">Boş</string>\n    <string name=\"go_to_path\">Git…</string>\n    <string name=\"apply_profile\">“%1$s” profilini uygula</string>\n    <string name=\"choose_a_profile_state\">Bir profil durumu seçin</string>\n    <string name=\"profile_id\">Profil kimliği</string>\n    <string name=\"copy_profile_id\">Profil kimliğini kopyala</string>\n    <string name=\"line_separator\">Satır ayırıcı</string>\n    <string name=\"debloat_list_aosp\">AOSP</string>\n    <string name=\"read_only_file\">Salt okunur dosya</string>\n    <string name=\"debloat_list_oem\">OEM</string>\n    <string name=\"debloat_removal_replace\">Değiştir</string>\n    <plurals name=\"file_count\">\n        <item quantity=\"one\">%d dosya</item>\n        <item quantity=\"other\">%d dosya</item>\n    </plurals>\n    <string name=\"copy_this_path\">Yolu kopyala</string>\n    <string name=\"title_audio_player\">Ses Oynatıcı</string>\n    <string name=\"filter_force_stopped_apps\">Durdurulan uygulamalar</string>\n    <string name=\"enter_symbolic_link_name\">Bağlantı adı</string>\n    <string name=\"enter_target_path\">Hedef yol</string>\n    <string name=\"invalid_target_path\">Geçersiz yol</string>\n    <string name=\"copy_these_paths\">Yolları kopyala</string>\n    <string name=\"conflict_detected_while_copying\">Çakışma tespit edildi</string>\n    <string name=\"conflict_detected_while_copying_message\">Bu konumda zaten \\\"%1$s\\\" adında bir öge var. Onu değiştirmek istiyor musunuz?</string>\n    <string name=\"failed_to_copy_specified_file\">“%1$s” kopyalanamadı.</string>\n    <string name=\"failed_to_delete_specified_file_after_copying\">Muhtemelen yeterli izin olmaması nedeniyle kopyalandıktan sonra \\\"%1$s\\\" silinemedi.</string>\n    <string name=\"change_owner_uid\">Sahibi (UID) değiştir</string>\n    <string name=\"change_group_gid\">Grubu (GID) değiştir</string>\n    <string name=\"change_mode\">Modu değiştir</string>\n    <string name=\"pref_send_notification_to_connected_devices_msg\">Giyilebilir aygıtlar gibi bağlı aygıtlara bildirim gönderip göndermemeyi ayarlayın.</string>\n    <string name=\"installer_options\">Kurulum seçenekleri</string>\n    <string name=\"debloat_removal_safe_short_description\">Güvenli bir şekilde kaldırılabilir</string>\n    <string name=\"debloat_removal_caution_short_description\">Dikkatli olun</string>\n    <string name=\"debloat_removal_replace_short_description\">Alternatif ile değiştirin</string>\n    <string name=\"xposed_module_info\">Xposed Modül Bilgisi</string>\n    <string name=\"title_description\">Açıklama</string>\n    <string name=\"module_name\">Modül adı</string>\n    <string name=\"app_manager_is_running\">Uygulama Yöneticisi çalışıyor</string>\n    <string name=\"app_manager_is_unlocked\">Uygulama Yöneticisi kilidi açıldı</string>\n    <string name=\"pref_enable_persistent_session\">Uygulama Yöneticisini arka planda çalıştır</string>\n    <string name=\"pref_enable_persistent_session_msg\">Uygulama Yöneticisi\\'ni arka planda çalıştırmak, başlatma gecikmesini azaltır. Uygulama Yöneticisi\\'ni sık sık kullanıyorsanız faydalıdır.</string>\n    <string name=\"netpolicy_reject_metered_data\">Kotalı ağlarda verileri reddet</string>\n    <string name=\"netpolicy_allow_metered_background_data\">Veri Tasarrufu açıkken bile kotalı ağlarda arka plan verilerine izin ver</string>\n    <string name=\"pref_toggle_internet_msg\">Uygulama Yöneticisi\\'nde İnternet özelliklerini etkinleştir</string>\n    <string name=\"finder_title\">Bulucu</string>\n    <string name=\"launch_activity_dialog_message\">Uygulama Yöneticisi, <b>Arama yardımcısı</b> (genellikle Google Yardımcı) aracılığıyla etkinliği başlatmaya çalışıyor, ancak yetersiz izin nedeniyle bunu yapamıyor. Etkinliği açmak için lütfen <b>Arama yardımcısını</b> elle etkinleştirin (bu genellikle Ana Ekran düğmesine uzun tıklayarak yapılır). Orijinal yardımcıya geri dönmek için etkinliği başlatmayı bitirdikten sonra <b>Kapat</b> düğmesine tıklayın.</string>\n    <string name=\"select_filter\">Filtre seç</string>\n    <string name=\"size_in_bytes\">Boyut (bayt)</string>\n    <string name=\"invalid_regex\">Geçersiz düzenli ifade!</string>\n    <string name=\"value_cannot_be_empty\">Değer boş olamaz!</string>\n    <string name=\"date\">Tarih</string>\n    <string name=\"pref_use_vt\">VirusTotal Kullan</string>\n    <string name=\"virus_total\">VirusTotal</string>\n    <string name=\"pref_use_log_viewer\">Günlük Görüntüleyici Kullan</string>\n    <string name=\"pref_installer\">Kurucuyu kullan</string>\n    <string name=\"mode_of_op_custom_command_title\">Özel Komut</string>\n    <string name=\"mode_of_op_custom_command\">Modlardan herhangi birini kullanamıyorsanız, Uygulama Yöneticisi\\'ni ayrıcalıklı modda çalıştırmak için desteklenen herhangi bir kabukta şu komutu çalıştırabilirsiniz:</string>\n    <string name=\"netpolicy_reject_metered_background_data\">Kotalı ağlarda arka plan verilerini reddet</string>\n    <string name=\"launch_activity_dialog_title\">Etkinlik Başlat: Eylem Gerekli</string>\n    <string name=\"pref_use_vt_no_internet\">VirusTotal\\'ın çalışması için internet gerekli ancak etkin değil. Lütfen önce <a href=\"app-manager://settings/privacy_prefs/toggle_internet\">“İnterneti kullan”</a> seçeneğini etkinleştirin.</string>\n    <string name=\"pref_cat_general\">Genel</string>\n    <string name=\"status_remote_server_active\">Uzak sunucu etkin</string>\n    <string name=\"status_remote_services_active\">Uzak hizmetler etkin</string>\n    <string name=\"adb_pairing_searching_for_port\">Aranıyor…</string>\n    <string name=\"adb_pairing_pairing_in_progress\">Eşleştiriliyor…</string>\n    <string name=\"status_remote_server_inactive\">Uzak sunucu etkin değil</string>\n    <string name=\"status_remote_services_inactive\">Uzak hizmetler etkin değil</string>\n    <string name=\"adb_pairing_stop_searching\">Durdur</string>\n    <string name=\"adb_pairing_input_pairing_code\">Eşleştirme kodu</string>\n    <string name=\"adb_pairing_found_pairing_service_with_port\">%d bağlantı noktasıyla bir hizmet bulundu</string>\n    <string name=\"status_connecting\">Bağlanıyor…</string>\n    <string name=\"status_connecting_via_mode\">%s ile bağlanıyor</string>\n    <string name=\"status_connected_via_mode\">%s ile bağlandı</string>\n    <string name=\"status_not_connected_via_mode\">%s ile bağlanamadı</string>\n    <string name=\"adb_pairing_instruction\">Kablosuz hata ayıklamayı etkinleştirmek ve bir eşleştirme kodu oluşturmak için lütfen geliştirici seçeneklerine gidin.</string>\n    <string name=\"adb_pairing_pairing_code\">Eşleştirme kodu</string>\n    <string name=\"adb_pairing_retry_pairing\">Yeniden dene</string>\n    <string name=\"mode_of_op_alternative_custom_command\">Yukarıdaki komutla “permission denied” hatası alırsanız, bunun yerine şu komutu çalıştırın:</string>\n    <string name=\"sensors\">Sensörler</string>\n    <string name=\"tag_sensors_disabled\">Sensörler devre dışı</string>\n    <string name=\"pref_use_system_font_msg\">Material yazı tipi yerine sistem öntanımlı yazı tipini kullan. <font fgcolor=\"#ff0000\">Bu deneysel bir özelliktir.</font></string>\n    <string name=\"actual_installer\">Gerçek Kurucu</string>\n    <string name=\"backup_cache\">Önbellek</string>\n    <string name=\"pref_use_system_font\">Sistem yazı tipini kullan</string>\n    <string name=\"apk_source\">APK Kaynağı</string>\n</resources>"
  },
  {
    "path": "app/src/main/res/values-uk/disclaimer.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- SPDX-License-Identifier: GPL-3.0-or-later --><resources>\n    <string name=\"disclaimer_exit\">Вийти</string>\n    <string name=\"disclaimer_agree\">Погоджуюся</string>\n    <string name=\"disclaimer_agree_forever\">Ніколи не показувати це знову</string>\n    <string name=\"disclaimer_body\">App Manager надає root-функції, що можуть зашкодити вашому пристрою при неправильному використанні. App Manager не несе відповідальності за жодні збитки, завдані при використанні цього додатку. Якщо ви не до кінця усвідомлюєте, як працює root, уникайте використання root-функцій, поки не усвідомите ризики повністю.\n\\n\n\\nБудь-які мої посилання на інші додатки та вебсайти додано для зручності користувача. Я не несу відповідальності за жоден вміст, який ви можете знайти за зовнішніми посиланнями.\n\\n\n\\nВикористовуючи App Manager, ви несете повну відповідальність за власне використання й погоджуєтесь на відсутність відшкодування збитків, претензій або грошової вартості через неправильне використання.\n\\n\n\\nВикористовуючи цей додаток, ви берете на себе всю відповідальність за її використання та погоджуєтесь, що я не несу відповідальності за жодні ваші дії, які негативно впливають на ваш пристрій.</string>\n    <string name=\"disclaimer_header\">Відмова від відповідальності</string>\n    <string name=\"disclaimer_footer\">© 2020–2024 Muntashir Al-Islam</string>\n</resources>"
  },
  {
    "path": "app/src/main/res/values-uk-rUA/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- SPDX-License-Identifier: GPL-3.0-or-later --><resources xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:tools=\"http://schemas.android.com/tools\">\n    <string name=\"_lang_tag\" translatable=\"false\">uk-UA</string>\n    <string name=\"uninstall\">Видалити</string>\n    <string name=\"activities\">Activities</string>\n    <string name=\"launch\">Запустити</string>\n    <string name=\"refresh\">Оновити</string>\n    <string name=\"providers\">Провайдери</string>\n    <string name=\"no_providers\">Немає провайдерів</string>\n    <string name=\"launch_mode\">Режим запуску</string>\n    <string name=\"sort_by_last_update\">Останнє оновлення</string>\n    <string name=\"service\">Служби</string>\n    <string name=\"no_service\">Немає служб</string>\n    <string name=\"read\">Читання</string>\n    <string name=\"write\">Запис</string>\n    <string name=\"patterns_allowed\">Графічні ключі дозволено</string>\n    <string name=\"declared_permission\">Дозволи</string>\n    <string name=\"group\">Група</string>\n    <string name=\"sort_by_sha\">Підпис</string>\n    <string name=\"signatures\">Підписи</string>\n    <string name=\"app_signing_no_signatures\">Немає дійсних підписів</string>\n    <string name=\"configurations\">Конфігурації</string>\n    <string name=\"manifest\">Маніфест</string>\n    <string name=\"error\">Помилка</string>\n    <string name=\"loading\">Завантаження…</string>\n    <string name=\"about\">Про додаток</string>\n    <string name=\"cache_size\">Кеш</string>\n    <string name=\"obb_size\">Obb</string>\n    <string name=\"error_creating_shortcut\">Помилка створення ярлика</string>\n    <string name=\"create_shortcut\">Створити ярлик</string>\n    <string name=\"class_name\">Назва класу</string>\n    <string name=\"license\">Ліцензія</string>\n    <string name=\"third_party\">Сторонні бібліотеки та іконки</string>\n    <string name=\"credits\">Автори</string>\n    <string name=\"toggle_default_app_ops\">Перемкнути app ops за замовчуванням</string>\n    <string name=\"pref_remove_all_rules_msg\">Дозволи буде надано, app ops та компоненти повернуться до значень за замовчуванням.</string>\n    <plurals name=\"no_of_splits\">\n        <item quantity=\"one\">%1$d спліт</item>\n        <item quantity=\"few\">%1$d спліти</item>\n        <item quantity=\"many\">%1$d сплітів</item>\n        <item quantity=\"other\">%1$d сплітів</item>\n    </plurals>\n    <string name=\"input_app_ops_description\">Введіть імена та/або константи app op із пробілами, наприклад <tt>WAKE_LOCK 63 72 CAMERA</tt> тощо.</string>\n    <string name=\"input_app_ops\">Введення app ops</string>\n    <string name=\"external_apk_no_app_op\">Зовнішній файл .apk не має жодних операцій з додатками</string>\n    <string name=\"failed_to_deny_dangerous_app_ops\">Не вдалося відкликати всі небезпечні app ops</string>\n    <string name=\"failed_to_reset_app_ops\">Не вдалося провести скидання app ops</string>\n    <string name=\"sort_by_app_ops_values\">Значення app ops</string>\n    <string name=\"sort_by_app_ops_names\">Назва app ops</string>\n    <string name=\"deny_dangerous_app_ops\">Заборонити небезпечні app ops</string>\n    <string name=\"failed_to_enable_op\">Сталася помилка під час спроби надати дозвіл</string>\n    <string name=\"no_app_ops\">Немає операцій з дозволами</string>\n    <string name=\"app_ops\">App Ops</string>\n    <string name=\"sys_config\">Конфігурація системи</string>\n    <string name=\"only_install\">Лише встановити</string>\n    <string name=\"app_signing_install_without_data_loss\">Якщо ви вимкнули перевірку підпису, ви можете використовувати опцію <b>Лише встановити</b>, для встановлення додатку без втрати даних.</string>\n    <string name=\"app_data_will_be_lost\">Існуючі дані будуть втрачені.</string>\n    <string name=\"app_signing_signature_mismatch_for_system_apps\">Не вдалося встановити додаток, оскільки встановлений додаток є системним, з іншим підписом.</string>\n    <string name=\"do_you_want_to_uninstall_and_install\">Ви хочете видалити і знову встановити додаток \\?</string>\n    <string name=\"usage_access_not_supported\">Не вдалося запросити доступ до використання, оскільки відповідна сторінка налаштувань не існує.</string>\n    <string name=\"non_critical_exts\">Некритичні розширення</string>\n    <string name=\"critical_exts\">Критичні розширення</string>\n    <string name=\"rsa_modulus\">Модуль</string>\n    <string name=\"rsa_exponent\">Експонента</string>\n    <string name=\"format\">Формат</string>\n    <string name=\"public_key\">Відкритий ключ</string>\n    <string name=\"algorithm\">Алгоритм</string>\n    <string name=\"app_signing_signature\">Підпис</string>\n    <string name=\"checksums\">Контрольна сума</string>\n    <string name=\"serial_no\">Серійний номер</string>\n    <string name=\"not_yet_valid\">Ще не дійсний</string>\n    <string name=\"expired\">Закінчений</string>\n    <string name=\"valid\">Дійсний</string>\n    <string name=\"validity\">Строк дії</string>\n    <string name=\"type\">Тип</string>\n    <string name=\"issued_date\">Дата видачі</string>\n    <string name=\"issuer\">Видавець</string>\n    <string name=\"filter_apps_with_backups\">З резервними копіями</string>\n    <string name=\"sort_by_backup\">Спочатку резервні копії</string>\n    <string name=\"failed_to_uninstall_updates\">Не вдалося видалити оновлення <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g>.</string>\n    <string name=\"update_uninstalled_successfully\">Оновлення <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g> було видалено.</string>\n    <string name=\"uninstall_updates\">Видалити оновлення</string>\n    <string name=\"allow_open_pgp_operation\">Натисніть, щоб дозволити App Manager використовувати OpenPGP</string>\n    <string name=\"confirm_installation\">Підтвердьте встановлення</string>\n    <string name=\"pref_backup_flags_msg\">Додавання попередньо встановлених параметрів резервного копіювання позбавляє від необхідності вибору пунктів під час кожного резервного копіювання/відновлення.</string>\n    <string name=\"pref_compression_method\">Метод стиснення</string>\n    <string name=\"rules\">Правила</string>\n    <string name=\"other\">Інше</string>\n    <string name=\"changes_not_saved\">Зміни не збережено</string>\n    <string name=\"sort_by_memory_usage\">Використання пам\\'яті</string>\n    <string name=\"sort_by_apps_first\">Додатки в першу чергу</string>\n    <string name=\"sort_by_process_name\">Ім\\'я процесу</string>\n    <string name=\"sort_by_process_id\">Ідентифікатор процесу</string>\n    <string name=\"filter_apps\">Додатки</string>\n    <string name=\"no_apps\">Немає додатків</string>\n    <string name=\"apps\">Додатки</string>\n    <string name=\"routine_ops\">Регулярні операції</string>\n    <string name=\"apply_now\">Застосувати зараз…</string>\n    <string name=\"keystore\">Сховище ключів</string>\n    <string name=\"no_profiles\">Немає профілів</string>\n    <string name=\"profiles\">Профілі</string>\n    <string name=\"open_pgp_provider\">Постачальник OpenPGP</string>\n    <string name=\"systemless_app\">Позасистемний додаток</string>\n    <string name=\"cancel\">Скасувати</string>\n    <string name=\"ok\">ОК</string>\n    <string name=\"input_backup_name_description\">Ім\\'я резервної копії не повинно починатися з цифри і не повинно містити пробілів. Залиште поле порожнім, якщо ви хочете використовувати поточну дату-час.</string>\n    <string name=\"input_backup_name\">Ім\\'я резервної копії</string>\n    <string name=\"downgrade\">Понизити версію</string>\n    <string name=\"process_state_with_extra\">Стан: <xliff:g id=\"process_state\" example=\"Sleeping\">%1$s</xliff:g> (<xliff:g id=\"state_extra\" example=\"High priority\">%2$s</xliff:g>)</string>\n    <string name=\"process_state\">Стан: <xliff:g id=\"process_state\" example=\"Sleeping\">%1$s</xliff:g></string>\n    <string name=\"state_multithreaded\">Багатопотокові</string>\n    <string name=\"state_foreground\">Передній план</string>\n    <string name=\"state_session_leader\">Лідер сесії</string>\n    <string name=\"state_locked_memory\">Заблокована пам\\'ять</string>\n    <string name=\"state_low_priority\">Низький пріоритет</string>\n    <string name=\"state_high_priority\">Високий пріоритет</string>\n    <string name=\"state_unknown\">Невідомий</string>\n    <string name=\"state_idle\">Очікування</string>\n    <string name=\"state_zombie\">Зомбі</string>\n    <string name=\"state_dead\">Мертвий</string>\n    <string name=\"state_sleeping\">Сплячий</string>\n    <string name=\"touchscreen_finger\">Палець</string>\n    <string name=\"touchscreen_stylus\">Стилус</string>\n    <string name=\"touchscreen_no_touch\">Без дотику</string>\n    <string name=\"navigation_wheel\">Колесо</string>\n    <string name=\"navigation_trackball\">Трекбол</string>\n    <string name=\"navigation_dial_pad\">Цифрова клавішна панель</string>\n    <string name=\"navigation_no_nav\">Немає навігації</string>\n    <string name=\"keyboard_12_keys\">12 клавіш</string>\n    <string name=\"keyboard_qwerty\">QWERTY</string>\n    <string name=\"keyboard_no_keys\">Немає ключів</string>\n    <string name=\"_undefined\">Невизначено</string>\n    <string name=\"orientation_user\">Користувача</string>\n    <string name=\"orientation_reverse_landscape\">Зворотня горизонтальна</string>\n    <string name=\"orientation_reverse_portrait\">Зворотня вертикальна</string>\n    <string name=\"orientation_portrait\">Вертикальна</string>\n    <string name=\"orientation_landscape\">Горизонтальна</string>\n    <string name=\"orientation_locked\">Заблоковано</string>\n    <string name=\"orientation_behind\">Позаду</string>\n    <string name=\"orientation_unspecified\">Невизначено</string>\n    <string name=\"launch_mode_single_task\">Єдине завдання</string>\n    <string name=\"launch_mode_single_instance\">Один екземпляр</string>\n    <string name=\"launch_mode_multiple\">Кілька</string>\n    <string name=\"locale_split_for_base_apk\"><xliff:g id=\"split_name\" example=\"English\">%1$s</xliff:g> локаль основного АРК</string>\n    <string name=\"locale_split_for_feature\"><xliff:g id=\"split_name\" example=\"English\">%1$s</xliff:g> локаль <xliff:g id=\"feature_name\" example=\"Visualizer\">%2$s</xliff:g></string>\n    <string name=\"abi_split_for_base_apk\"><xliff:g id=\"split_name\" example=\"arm64_v8a\">%1$s</xliff:g> код для основного АРК</string>\n    <string name=\"abi_split_for_feature\"><xliff:g id=\"split_name\" example=\"arm64_v8a\">%1$s</xliff:g> код <xliff:g id=\"feature_name\" example=\"Visualizer\">%2$s</xliff:g></string>\n    <string name=\"density_split_for_base_apk\"><xliff:g id=\"split_name\" example=\"xxdpi\">%1$s</xliff:g> (<xliff:g id=\"dpi_no\" example=\"480\">%2$d</xliff:g> DPI) ресурсів для основного АРК</string>\n    <string name=\"density_split_for_feature\"><xliff:g id=\"split_name\" example=\"xxdpi\">%1$s</xliff:g> (<xliff:g id=\"dpi_no\" example=\"480\">%2$d</xliff:g> DPI) ресурси для функції <xliff:g id=\"feature_name\" example=\"Visualizer\">%3$s</xliff:g></string>\n    <string name=\"unknown_split_for_base_apk\"><xliff:g id=\"split_name\" example=\"some_split\">%1$s</xliff:g> основного АРК</string>\n    <string name=\"unknown_split_for_feature\"><xliff:g id=\"split_name\" example=\"some_split\">%1$s</xliff:g> для функції <xliff:g id=\"feature_name\" example=\"Visualizer\">%2$s</xliff:g></string>\n    <string name=\"split_feature_name\">Функції: <xliff:g id=\"feature_name\" example=\"Visualizer\">%1$s</xliff:g></string>\n    <string name=\"base_apk\">Основний файл .apk</string>\n    <string name=\"choose_language\">Змінити мову</string>\n    <string name=\"auto\">Авто</string>\n    <string name=\"pref_app_language\">Мова</string>\n    <string name=\"backup_all_users\">Всі користувачі</string>\n    <string name=\"backup_multiple\">Резервне копіювання декількох</string>\n    <string name=\"obb_files_extracted_successfully\">Файли OBB витягнуто</string>\n    <string name=\"failed_to_extract_obb_files\">Не вдалося витягти файли OBB</string>\n    <string name=\"backup_obb_media\">OBB та медіа</string>\n    <string name=\"backup_apk_files\">Файли APK</string>\n    <string name=\"installer_error_session_abandon\">Не вдалося перервати сеанс програми встановлення</string>\n    <string name=\"installer_error_session_commit\">Не вдалося зафіксувати файли .apk</string>\n    <string name=\"installer_error_session_write\">Не вдалося записати до сеансу програми встановлення</string>\n    <string name=\"installer_error_session_create\">Не вдалося створити сеанс програми встановлення</string>\n    <string name=\"installer_error_security\">Не вдається отримати доступ до файлів .apk</string>\n    <string name=\"install_in_progress\">Встановлення…</string>\n    <string name=\"package_installer\">Інсталятор пакетів</string>\n    <string name=\"unblock_trackers\">Розблокування трекерів</string>\n    <string name=\"reinstall\">Перевстановлення</string>\n    <string name=\"install_app_message\">Ви хочете встановити цей додаток\\?</string>\n    <string name=\"try_again\">Спробуйте ще раз</string>\n    <string name=\"full_stop_tap_to_see_details\">. Торкніться, щоб переглянути деталі.</string>\n    <string name=\"operation_running\">Операція запущена…</string>\n    <string name=\"batch_ops\">Пакетні операції</string>\n    <string name=\"failed_to_fetch_package_info\">Не вдалося отримати відомості про пакет</string>\n    <string name=\"installer_error_lidl_rom\">Ваша прошивка несумісна з без-ROOT-овим інсталятором.</string>\n    <string name=\"installer_error_generic\">Помилка встановлення</string>\n    <string name=\"installer_error_storage\">Недостатньо місця для встановлення додатку</string>\n    <string name=\"installer_error_bad_apks\">Вибрано пошкоджені файли .apk</string>\n    <string name=\"installer_error_incompatible\">Додаток несумісний з цим пристроєм</string>\n    <string name=\"installer_error_blocked\">Встановленя заблоковано <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g></string>\n    <string name=\"installer_error_blocked_device\">пристрій</string>\n    <string name=\"installer_error_aborted\">Помилка встановлення, оскільки воно було скасовано або сеанс було несподівано закрито</string>\n    <string name=\"filter_apps_with_activities\">Додатки з activities</string>\n    <string name=\"are_you_sure\">Ви впевнені\\?</string>\n    <string name=\"pref_remove_all_rules\">Видалити всі правила</string>\n    <string name=\"website\">Веб-сайт</string>\n    <string name=\"run_in_termux\">Запустити в Termux</string>\n    <string name=\"open_in_termux\">Відкрити в Termux</string>\n    <string name=\"export_icon\">Витягти іконку</string>\n    <string name=\"no_matching_package_found\">Не вдалося знайти такий додаток</string>\n    <string name=\"block_unblock_trackers\">Заблокувати/розблокувати трекери</string>\n    <string name=\"unblock\">Розблокувати</string>\n    <string name=\"block\">Блокувати</string>\n    <string name=\"clear\">Очистити</string>\n    <string name=\"failed_packages\">Збійні пакети</string>\n    <string name=\"deny_app_ops_description\">Встановити режим операцій програм, визначені константами, наприклад <tt>63</tt> або <tt>RUN_IN_BACKGROUND</tt></string>\n    <string name=\"manifest_viewer\">Переглядач маніфесту</string>\n    <string name=\"never_ask\">Не запитувати</string>\n    <string name=\"unknown_op\">Невідома операція</string>\n    <string name=\"sort_by_tracker_components\">Спочатку трекери</string>\n    <string name=\"sort_by_denied_permissions\">Спочатку заборонені</string>\n    <string name=\"sort_by_denied_app_ops\">Спочатку заборонені</string>\n    <string name=\"keyboard_type\">Тип клавіатури</string>\n    <string name=\"reject_time\">Час відхилення</string>\n    <string name=\"accept_time\">Час підтвердження</string>\n    <string name=\"pref_global_blocking_enabled_msg\">Дозволяє блокувати будь-який компонент будь-якого додатку, не вмикаючи явно блокування додатку.</string>\n    <string name=\"rules_not_applied\">Правила не застосовані</string>\n    <string name=\"error_evaluating_input\">Не вдалося оцінити вхідні дані</string>\n    <string name=\"shared_prefs\">Спільні налаштування</string>\n    <plurals name=\"main_list_date_days\">\n        <item quantity=\"one\"><xliff:g id=\"last_update_date\" example=\"20/10/2020\">%1$s</xliff:g> <xliff:g id=\"day_no\" example=\"5\">%2$d</xliff:g> день</item>\n        <item quantity=\"few\"><xliff:g id=\"last_update_date\" example=\"20/10/2020\">%1$s</xliff:g> <xliff:g id=\"day_no\" example=\"5\">%2$d</xliff:g> дні</item>\n        <item quantity=\"many\"><xliff:g id=\"last_update_date\" example=\"20/10/2020\">%1$s</xliff:g> <xliff:g id=\"day_no\" example=\"5\">%2$d</xliff:g> днів</item>\n        <item quantity=\"other\"><xliff:g id=\"last_update_date\" example=\"20/10/2020\">%1$s</xliff:g> <xliff:g id=\"day_no\" example=\"5\">%2$d</xliff:g> днів</item>\n    </plurals>\n    <string name=\"main_activity\">Головне аctivity</string>\n    <string name=\"sdk_max\">Цільова</string>\n    <string name=\"sdk_min\">Мін.</string>\n    <string name=\"path_permissions\">Шляхи дозволів</string>\n    <string name=\"authority\">Права</string>\n    <string name=\"restore\">Відновити</string>\n    <string name=\"clear_data_message\">Ви впевнені, що хочете очистити дані цього додатка\\?</string>\n    <string name=\"skip_signature_checks\">Пропустити перевірку підписів</string>\n    <string name=\"yes\">Так</string>\n    <string name=\"no\">Ні</string>\n    <string name=\"apply_to_system_apps_question\">Застосувати до системних додатків теж\\? Виберіть \\\"Ні\\\", якщо не впевнені.</string>\n    <string name=\"apply_to_system_apps\">Застосувати до системних додатків</string>\n    <plurals name=\"backup_exists_are_you_sure\">\n        <item quantity=\"one\">Резервна копія існує. Ви впевнені\\?</item>\n        <item quantity=\"few\">Більше одного додатка вже має резервну копію. Ви впевнені\\?</item>\n        <item quantity=\"many\">Більше одного додатка вже має резервну копію. Ви впевнені\\?</item>\n        <item quantity=\"other\">Більше одного додатка вже має резервну копію. Ви впевнені\\?</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_block_components\">\n        <item quantity=\"one\">Не вдалося заблокувати компоненти в %1$d додатку</item>\n        <item quantity=\"few\">Не вдалося заблокувати компоненти в %1$d додатках</item>\n        <item quantity=\"many\">Не вдалося заблокувати компоненти в %1$d додатках</item>\n        <item quantity=\"other\">Не вдалося заблокувати компоненти в %1$d додатках</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_delete_backup\">\n        <item quantity=\"one\">Не вдалося видалити %1$d резервну копію</item>\n        <item quantity=\"few\">Не вдалося видалити %1$d резервні копії</item>\n        <item quantity=\"many\">Не вдалося видалити %1$d резервні копії</item>\n        <item quantity=\"other\">Не вдалося видалити %1$d резервні копії</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_restore\">\n        <item quantity=\"one\">Не вдалося відновити %1$d додаток</item>\n        <item quantity=\"few\">Не вдалося відновити %1$d додатки</item>\n        <item quantity=\"many\">Не вдалося відновити %1$d додатків</item>\n        <item quantity=\"other\">Не вдалося відновити %1$d додатків</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_backup\">\n        <item quantity=\"one\">Не вдалося зробити резервну копію %1$d додатка</item>\n        <item quantity=\"few\">Не вдалося зробити резервну копію %1$d додатків</item>\n        <item quantity=\"many\">Не вдалося зробити резервну копію %1$d додатків</item>\n        <item quantity=\"other\">Не вдалося зробити резервну копію %1$d додатків</item>\n    </plurals>\n    <plurals name=\"failed_to_backup_some_apk_files\">\n        <item quantity=\"one\">Не вдалося зробити резервну копію %1$d додатка</item>\n        <item quantity=\"few\">Не вдалося зробити резервну копію %1$d додатків</item>\n        <item quantity=\"many\">Не вдалося зробити резервну копію %1$d додатків</item>\n        <item quantity=\"other\">Не вдалося зробити резервну копію %1$d додатків</item>\n    </plurals>\n    <string name=\"backup_options\">Параметри резервного копіювання</string>\n    <string name=\"delete_backup\">Видалити резервну копію</string>\n    <string name=\"backup\">Резервна копія</string>\n    <string name=\"data\">Дані</string>\n    <string name=\"external_data\">Зовнішні дані</string>\n    <string name=\"blocking_rules\">Правила блокування</string>\n    <string name=\"whats_new\">Що нового</string>\n    <string name=\"features\">Функції</string>\n    <string name=\"components\">Компоненти</string>\n    <string name=\"trackers\">Трекери</string>\n    <string name=\"installed_version\">Установлена версія</string>\n    <string name=\"select_all\">Вибрати все</string>\n    <string name=\"filter_apps_with_rules\">Додатки з правилами</string>\n    <string name=\"filter_system_apps\">Системні додатки</string>\n    <string name=\"filter_user_apps\">Користувацькі додатки</string>\n    <string name=\"filter\">Фільтр</string>\n    <string name=\"package_name_is_installed_successfully\"><xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g> встановлено</string>\n    <string name=\"termux\">Termux</string>\n    <string name=\"failed_to_parse_some_numbers\">Не вдалося проаналізувати деякі цифри</string>\n    <string name=\"only_works_in_root_or_adb_mode\">Працює лише в режимі ROOT або ADB</string>\n    <string name=\"filtered_packages\">Відфільтровані пакети</string>\n    <string name=\"input_signatures_description\">Ввести підписи з пробілами, наприклад <tt>com.facebook org.app2 com.app3</tt> тощо.</string>\n    <string name=\"input_signatures\">Введення підписів</string>\n    <string name=\"no_tracker_found\">Не знайдено жодного трекера</string>\n    <string name=\"clear_app_cache_description\">Очищення кешу всіх додатків</string>\n    <string name=\"clear_app_cache\">Очищення кешу додатків</string>\n    <string name=\"clear_data_from_uninstalled_apps_description\">Очистити дані видалених додатків, котрі відмічені прапорцем <tt>DONT_DELETE_DATA</tt></string>\n    <string name=\"block_unblock_trackers_description\">Блокування або розблокування реклами і компонентів трекерів в усіх встановлених додатках</string>\n    <string name=\"clear_cache\">Очистити кеш</string>\n    <string name=\"pref_import_existing_msg\">Додати до App Manager компоненти, вимкнені іншими додатками. Будьте обережні при використанні цього інструменту, оскільки може бути багато помилково-позитивних результатів. Виберіть лише додатки, в котрих ви впевнені.</string>\n    <string name=\"pref_import_existing\">Імпорт існуючих правил</string>\n    <string name=\"source_code\">Вихідний код</string>\n    <string name=\"update\">Оновлення</string>\n    <string name=\"install\">Установити</string>\n    <plurals name=\"no_of_trackers\">\n        <item quantity=\"one\">%1$d трекер</item>\n        <item quantity=\"few\">%1$d трекери</item>\n        <item quantity=\"many\">%1$d трекерів</item>\n        <item quantity=\"other\">%1$d трекерів</item>\n    </plurals>\n    <string name=\"changelog\">Список змін</string>\n    <string name=\"one_click_ops\">Операції в 1 клік</string>\n    <string name=\"launch_app\">Запустити</string>\n    <string name=\"failed_to_deny_dangerous_perms\">Не вдалося відкликати всі небезпечні дозволи</string>\n    <string name=\"failed_to_revoke_permission\">Не вдалося відкликати дозвіл</string>\n    <string name=\"failed_to_grant_permission\">Не вдалося надати дозвіл</string>\n    <plurals name=\"alert_failed_to_disable_trackers\">\n        <item quantity=\"one\">Не вдалося вимкнути трекери в %1$d додатку</item>\n        <item quantity=\"few\">Не вдалося вимкнути трекери в %1$d додатках</item>\n        <item quantity=\"many\">Не вдалося вимкнути трекери в %1$d додатках</item>\n        <item quantity=\"other\">Не вдалося вимкнути трекери в %1$d додатках</item>\n    </plurals>\n    <string name=\"deny_dangerous_permissions\">Заборонити небезпечні дозволи</string>\n    <string name=\"sort_by_dangerous_permissions\">Спочатку небезпечні</string>\n    <string name=\"sort_by_permission_names\">Ім\\'я дозволу</string>\n    <string name=\"reset_to_default\">Відновити за замовчуванням</string>\n    <string name=\"sort_by_component_name\">Ім\\'я компонента</string>\n    <string name=\"block_trackers\">Блокувати трекери</string>\n    <string name=\"sort_by_wifi_data\">Дані Wi-Fi</string>\n    <string name=\"version\">Версія</string>\n    <string name=\"pref_about_msg\">Версія App Manager, ліцензія, подяки, тощо.</string>\n    <string name=\"apply\">Застосувати</string>\n    <string name=\"select_theme\">Тема</string>\n    <string name=\"night\">Ніч</string>\n    <string name=\"day\">День</string>\n    <string name=\"battery_mode\">Режим батареї</string>\n    <string name=\"pref_app_theme\">Тема додатку</string>\n    <string name=\"pref_import_blocker_msg\">Імпорт правил блокування з Blocker, кожен файл містить правила для одного пакета.</string>\n    <string name=\"pref_import_watt_msg\">Імпортуйте правила блокування з Watt, кожен файл, що містить правила для однієї назви пакета як <tt>packagename.xml</tt> тощо.</string>\n    <string name=\"pref_import_msg\">Імпортуйте раніше експортовані правила блокування з App Manager.</string>\n    <string name=\"pref_export_msg\">Експортувати правила блокування, налаштованих в App Manager, у зовнішнє сховище.</string>\n    <string name=\"touchscreen\">Сенсорний екран</string>\n    <string name=\"navigation\">Навігація</string>\n    <string name=\"export_failed\">Не вдалося експортувати!</string>\n    <string name=\"import_failed\">Не вдалося імпортувати!</string>\n    <string name=\"export_options\">Експорт параметрів</string>\n    <string name=\"import_options\">Імпорт параметрів</string>\n    <string name=\"pref_export\">Експорт</string>\n    <string name=\"pref_import\">Імпорт</string>\n    <string name=\"ago\">тому</string>\n    <string name=\"duration\">Тривалість</string>\n    <string name=\"running\">Запущено</string>\n    <string name=\"mode\">Режим</string>\n    <string name=\"permission_name\">Ім\\'я дозволу</string>\n    <string name=\"toggle_kill_for_system_apps\">Перемикач вбивства системних додатків</string>\n    <plurals name=\"alert_failed_to_force_stop\">\n        <item quantity=\"one\">Не вдалося примусово зупинити %1$d додаток</item>\n        <item quantity=\"few\">Не вдалося примусово зупинити %1$d додатки</item>\n        <item quantity=\"many\">Не вдалося примусово зупинити %1$d додатків</item>\n        <item quantity=\"other\">Не вдалося примусово зупинити %1$d додатків</item>\n    </plurals>\n    <string name=\"the_operation_was_successful\">Завершено</string>\n    <plurals name=\"alert_failed_to_disable_background\">\n        <item quantity=\"one\">Не вдалося запобігти роботу в фоновому режимі %1$d додатку</item>\n        <item quantity=\"few\">Не вдалося запобігти роботу в фоновому режимі %1$d додаткам</item>\n        <item quantity=\"many\">Не вдалося запобігти роботу в фоновому режимі %1$d додаткам</item>\n        <item quantity=\"other\">Не вдалося запобігти роботу в фоновому режимі %1$d додаткам</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_uninstall\">\n        <item quantity=\"one\">Не вдалося видалити %1$d додаток</item>\n        <item quantity=\"few\">Не вдалося видалити %1$d додатки</item>\n        <item quantity=\"many\">Не вдалося видалити %1$d додатків</item>\n        <item quantity=\"other\">Не вдалося видалити %1$d додатків</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_clear_data\">\n        <item quantity=\"one\">Не вдалося очистити дані %1$d додатку</item>\n        <item quantity=\"few\">Не вдалося очистити дані %1$d додатків</item>\n        <item quantity=\"many\">Не вдалося очистити дані %1$d додатків</item>\n        <item quantity=\"other\">Не вдалося очистити дані %1$d додатків</item>\n    </plurals>\n    <string name=\"export_blocking_rules\">Експорт правил блокування</string>\n    <string name=\"disable_background\">Запобігання фонових операцій</string>\n    <string name=\"backup_restore\">Резервне копіювання/відновлення</string>\n    <string name=\"clear_data\">Очистити дані</string>\n    <string name=\"user_and_uid\">Користувач: <xliff:g id=\"user_name\" example=\"root\">%1$s</xliff:g> (<xliff:g id=\"user_id\" example=\"0\">%2$d</xliff:g>)</string>\n    <string name=\"memory_virtual_memory\">Пам\\'ять: %1$s, Віртуальна пам\\'ять: %2$s</string>\n    <string name=\"disable_background_run\">Запобігання роботи в фоні</string>\n    <string name=\"kill_process\">Вбити</string>\n    <string name=\"running_apps\">Запущені служби</string>\n    <plurals name=\"failed_to_import_files\">\n        <item quantity=\"one\">Не вдалося імпортувати %1$d файл.</item>\n        <item quantity=\"few\">Не вдалося імпортувати %1$d файли.</item>\n        <item quantity=\"many\">Не вдалося імпортувати %1$d файлів.</item>\n        <item quantity=\"other\">Не вдалося імпортувати %1$d файлів.</item>\n    </plurals>\n    <string name=\"the_export_was_successful\">Експортовано</string>\n    <string name=\"the_import_was_successful\">Імпортовано</string>\n    <string name=\"pref_import_blocker\">Імпорт з Blocker</string>\n    <string name=\"pref_import_watt\">Імпорт з Watt</string>\n    <string name=\"pref_import_export_blocking_rules\">Імпорт/експорт правил блокування</string>\n    <string name=\"sort_by_mobile_data\">Мобільні дані</string>\n    <string name=\"sort_by_times_opened\">Кількість запусків</string>\n    <string name=\"sort_by_screen_time\">Час роботи екрану</string>\n    <string name=\"sort_by_last_used\">Останнє використання</string>\n    <plurals name=\"no_of_times_opened\">\n        <item quantity=\"one\">%1$d раз</item>\n        <item quantity=\"few\">%1$d рази</item>\n        <item quantity=\"many\">%1$d раз</item>\n        <item quantity=\"other\">%1$d раз</item>\n    </plurals>\n    <string name=\"external_multiple_data_dir\">Каталог зовнішніх даних <xliff:g id=\"dir_no\" example=\"1\">%1$d</xliff:g></string>\n    <string name=\"external_data_dir\">Каталог зовнішніх даних</string>\n    <string name=\"sort_by_blocked_components\">Спочатку заблоковані</string>\n    <string name=\"exodus_link\">εxodus посилання</string>\n    <string name=\"usage_yesterday\">Вчора</string>\n    <string name=\"app_settings\">Налаштування</string>\n    <string name=\"usage_access\">Доступ до статистики використання</string>\n    <string name=\"pref_global_blocking_enabled\">Миттєве блокування компонентів</string>\n    <string name=\"str_logo\">Логотип</string>\n    <string name=\"app_size\">Додаток</string>\n    <string name=\"total_size\">Всього</string>\n    <string name=\"storage_and_cache\">Сховище і кеш</string>\n    <string name=\"failed_to_stop\">Не вдалося зупинити <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g>.</string>\n    <string name=\"force_stop\">Зупинити примусово</string>\n    <string name=\"enable\">Ввімкнути</string>\n    <string name=\"disable\">Вимкнути</string>\n    <string name=\"stopped\">Зупинено</string>\n    <string name=\"uninstall_system_app_message\">Це системний додаток. Ви впевнені, що хочете видалити його\\?</string>\n    <string name=\"uninstalled_successfully\"><xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g> видалено.</string>\n    <string name=\"failed_to_uninstall\">Не вдалося видалити <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g>.</string>\n    <string name=\"uninstall_app_message\">Видалити цей додаток\\?</string>\n    <string name=\"view_in_settings\">Переглянути в налаштуваннях</string>\n    <string name=\"no_content\">Немає вмісту</string>\n    <string name=\"no_usage_in_this_time_range\">Немає використання в цьому часовому діапазоні</string>\n    <string name=\"disabled_app\">Відключено</string>\n    <string name=\"key_name_cannot_be_null\">Ім\\'я ключа не може бути порожнім</string>\n    <string name=\"type_string\">Символів</string>\n    <string name=\"type_long\">Довге ціле число</string>\n    <string name=\"type_int\">Ціле число</string>\n    <string name=\"type_float\">Десяткове число</string>\n    <string name=\"type_boolean\">Правда/хибність</string>\n    <string name=\"done\">Завершено</string>\n    <string name=\"add_item\">Додати елемент</string>\n    <string name=\"select_type\">Виберіть тип</string>\n    <string name=\"key_name\">Назва ключа</string>\n    <string name=\"boolean_value\">Логічне значення</string>\n    <string name=\"decimal_value\">Десяткове значення</string>\n    <string name=\"expiry_date\">Придатний до</string>\n    <string name=\"orientation_user_portrait\">Вертикальна, користувацька</string>\n    <string name=\"installer_error_conflict\">Не вдається встановити додаток, оскільки встановлений вже має цю назву пакета</string>\n    <plurals name=\"alert_failed_to_unblock_trackers\">\n        <item quantity=\"one\">Не вдалося розблокувати трекери в %1$d додатку</item>\n        <item quantity=\"few\">Не вдалося розблокувати трекери в %1$d додатках</item>\n        <item quantity=\"many\">Не вдалося розблокувати трекери в %1$d додатках</item>\n        <item quantity=\"other\">Не вдалося розблокувати трекери в %1$d додатках</item>\n    </plurals>\n    <string name=\"clear_data_from_uninstalled_apps\">Очистити дані видалених додатків</string>\n    <string name=\"block_components_dots\">Блокування компонентів …</string>\n    <string name=\"follow_system\">Як в системі</string>\n    <string name=\"pid_and_ppid\">Ідентифікатор процесу: %1$d, ідентифікатор батьківського процесу: %2$d</string>\n    <string name=\"pref_import_export_blocking_rules_msg\">Імпорт/Експорт правил, імпорт зовнішніх правил з Watt або Blocker.</string>\n    <string name=\"failed_to_disable_op\">Сталася помилка під час спроби заборонити дозвіл</string>\n    <string name=\"debuggable\">Налагоджується</string>\n    <string name=\"installer_app\">Встановник додатків</string>\n    <string name=\"sort_by_package_name\">Ім’я пакету</string>\n    <string name=\"require_no_permission\">Не вимагає дозволів</string>\n    <string name=\"required\">Вимагається</string>\n    <string name=\"subject\">Тема</string>\n    <string name=\"state_waking\">Пробудження</string>\n    <string name=\"state_trace_stop\">Трасування зупинки</string>\n    <string name=\"sdk_flags\">Прапорці</string>\n    <string name=\"flags\">Прапорці</string>\n    <string name=\"soft_input\">Режим \\\"софт\\\" введення</string>\n    <string name=\"task_affinity\">Спорідненість завдань</string>\n    <string name=\"orientation_user_landscape\">Користувацька, горизонтальна</string>\n    <string name=\"orientation_sensor\">Датник</string>\n    <string name=\"orientation_sensor_portrait\">Вертикальна по датнику</string>\n    <string name=\"orientation_sensor_landscape\">Горизонтальна по датнику</string>\n    <string name=\"orientation_no_sensor\">Без датника</string>\n    <string name=\"orientation_full_user\">Повністю користувацька</string>\n    <string name=\"orientation_full_sensor\">Повністю згідно датника</string>\n    <string name=\"integer_value\">Ціле значення</string>\n    <string name=\"long_integer_value\">Довге ціле значення</string>\n    <string name=\"string_value\">Значення рядка</string>\n    <string name=\"saving_failed\">Помилка збереження. Повторіть спробу.</string>\n    <string name=\"saved_successfully\">Збережено</string>\n    <string name=\"deletion_failed\">Видалення не вдалося</string>\n    <string name=\"deleted_successfully\">Видалено</string>\n    <string name=\"delete\">Видалити</string>\n    <string name=\"discard\">Відхилити</string>\n    <string name=\"save\">Зберегти</string>\n    <string name=\"databases\">Бази даних</string>\n    <string name=\"test_only\">Тільки тест</string>\n    <string name=\"updated_app\">Оновлено</string>\n    <string name=\"requested_large_heap\">Великий розмір heap</string>\n    <string name=\"no_code\">Немає коду</string>\n    <string name=\"process_name\">Назва процесу</string>\n    <string name=\"native_library_dir\">Рідний каталог бібліотеки JNI</string>\n    <string name=\"dev_protected_data_dir\">Каталог даних, захищений пристроєм</string>\n    <string name=\"search\">Пошук</string>\n    <string name=\"menu_apply_rules\">Застосувати правила</string>\n    <string name=\"menu_remove_rules\">Видалити правила</string>\n    <string name=\"failed_to_extract_apk_file\">Не вдалося видобути файл APK</string>\n    <string name=\"share_apk\">Поділитися APK</string>\n    <string name=\"grant_usage_acess_message\">Використовується для відображення інформації про використання додатка.</string>\n    <string name=\"grant_usage_access\">Надати доступ до статистики використання</string>\n    <string name=\"go\">Далі</string>\n    <string name=\"go_back\">← Назад</string>\n    <string name=\"usage_less_than_a_minute\">Менше хвилини</string>\n    <plurals name=\"usage_hours\">\n        <item quantity=\"one\">%1$d година</item>\n        <item quantity=\"few\">%1$d години</item>\n        <item quantity=\"many\">%1$d годин</item>\n        <item quantity=\"other\">%1$d годин</item>\n    </plurals>\n    <plurals name=\"usage_days\">\n        <item quantity=\"one\">%1$d день</item>\n        <item quantity=\"few\">%1$d дні</item>\n        <item quantity=\"many\">%1$d днів</item>\n        <item quantity=\"other\">%1$d днів</item>\n    </plurals>\n    <plurals name=\"usage_months\">\n        <item quantity=\"one\">%1$d місяць</item>\n        <item quantity=\"few\">%1$d місяці</item>\n        <item quantity=\"many\">%1$d місяців</item>\n        <item quantity=\"other\">%1$d місяців</item>\n    </plurals>\n    <string name=\"usage_7_days\">За останні 7 днів</string>\n    <string name=\"usage_today\">Сьогодні</string>\n    <string name=\"usage_weekly\">Щотижня</string>\n    <string name=\"app_usage\">Використання додатків</string>\n    <string name=\"no_tracker_class\">Немає класів трекера</string>\n    <string name=\"no_shared_libs\">Немає спільних бібліотек</string>\n    <string name=\"all_classes\">Всі класи</string>\n    <string name=\"tracker_classes\">Класи трекера</string>\n    <string name=\"tracker_details\">Відомості про трекер</string>\n    <string name=\"found_trackers\">Знайдені трекери:</string>\n    <string name=\"toggle_class_listing\">Переключити перелік класів</string>\n    <string name=\"class_viewer\">Переглядач класів</string>\n    <string name=\"word_wrap\">Переключити перенесення слів</string>\n    <string name=\"credits_message\">Подяка розробникам \\n- The Android Open Source Project \\n- <a href=\"https://github.com/zhaobozhen/libraries\">Absinthe\\'s libraries</a> \\n- <a href=\"https://github.com/butzist/ActivityLauncher\">Activity Launcher</a> \\n- <a href=\"https://bitbucket.org/oF2pks/fdroid-applications-info\">Apps_packages Info</a> \\n- <a href=\"https://github.com/zhaobao/AppsMonitor\">AppsMonitor</a> \\n- <a href=\"https://github.com/8enet/AppOpsX\">AppOpsX</a> \\n- <a href=\"https://github.com/gabrielemariotti/changeloglib\">ChangeLog Library</a> \\n- <a href=\"https://bitbucket.org/oF2pks/fdroid-classyshark3xodus\">ClassySharkAndroid</a> \\n- <a href=\"https://github.com/billthefarmer/editor\">Editor</a> \\n- <a href=\"https://github.com/Raival-e/File-Explorer\">File Explorer</a> \\n- <a href=\"https://github.com/nex3z/FlowLayout\">FlowLayout</a> \\n- <a href=\"https://github.com/k3b/intent-intercept\">Intent Intercept</a> \\n- <a href=\"https://github.com/YarikSOffice/lingver\">Lingver</a> \\n- <a href=\"https://github.com/topjohnwu/Magisk\">Magisk</a> \\n- <a href=\"https://github.com/zhanghai/MaterialFiles\">Material Files</a> \\n- <a href=\"https://github.com/pluscubed/matlog\">MatLog</a> \\n- <a href=\"https://github.com/matrix-org/matrix-android-sdk\">Matrix Android SDK</a> \\n- <a href=\"https://github.com/jensstein/oandbackup\">OAndBackup</a> \\n- <a href=\"https://github.com/open-keychain/open-keychain\">Open Keychain</a> \\n- <a href=\"https://github.com/Aefyr/SAI\">SAI</a> \\n- <a href=\"https://github.com/RikkaApps/Shizuku\">Shizuku</a> \\n- <a href=\"https://github.com/eclipse/tm4e\">tm4e</a> \\n- <a href=\"https://github.com/tuyafeng/Watt\">Watt</a></string>\n    <string name=\"icon_picker\">Вибір іконки</string>\n    <string name=\"package_name\">Назва пакету</string>\n    <string name=\"shortcut_name\">Назва ярлика</string>\n    <string name=\"starting_activity\">Стартове activity: <xliff:g id=\"activity_name\" example=\".main.MainActivity\">%1$s</xliff:g></string>\n    <string name=\"error_verbose_pin_shortcut\">Поточний лаунчер не підтримує прикріплення ярликів. Неможливо створили ярлик.</string>\n    <string name=\"no_activities\">Немає activities</string>\n    <string name=\"empty_package_name\">Порожнє імя пакету</string>\n    <string name=\"user_id\">Ідентифікатор користувача</string>\n    <string name=\"date_updated\">Дата оновлення</string>\n    <string name=\"date_installed\">Дата встановлення</string>\n    <string name=\"more_info\">Докладніше</string>\n    <string name=\"source_dir\">Каталог-джерело</string>\n    <string name=\"data_dir\">Каталоги даних</string>\n    <string name=\"paths_and_directories\">Шлях і каталоги</string>\n    <string name=\"user_app\">Додаток користувача</string>\n    <string name=\"system_app\">Системний додаток</string>\n    <string name=\"app_info\">Про додаток</string>\n    <string name=\"version_name_with_code\">Версія <xliff:g id=\"version_name\" example=\"2.5.17\">%1$s</xliff:g> (<xliff:g id=\"version_code\" example=\"365\">%2$d</xliff:g>)</string>\n    <string name=\"sort\">Сортування</string>\n    <string name=\"user\">Користувацькі</string>\n    <string name=\"system\">Системні</string>\n    <string name=\"app_not_installed\">Додаток не встановлено</string>\n    <string name=\"input_features\">Функції введення</string>\n    <string name=\"shared_user_id\">Спільний ідентифікатор користувача</string>\n    <string name=\"sort_by_shared_user_id\">Спільний ідентифікатор користувача</string>\n    <string name=\"no_feature\">Немає функцій</string>\n    <string name=\"uses_feature\">Використовує функції</string>\n    <string name=\"shared_libs\">Спільні бібліотеки</string>\n    <string name=\"media_size\">Медіа</string>\n    <string name=\"data_size\">Дані</string>\n    <string name=\"data_usage_msg\">Використання даних</string>\n    <string name=\"data_transmitted\">Даних відправлено</string>\n    <string name=\"data_received\">Даних отримано</string>\n    <string name=\"sort_by_target_sdk\">Цільова SDK</string>\n    <string name=\"sort_by_domain\">Спочатку користувацькі додатки</string>\n    <string name=\"sort_by_app_label\">Назва додатку</string>\n    <string name=\"no_configurations\">Немає конфігурацій</string>\n    <string name=\"grant_uri_permission\">Надати дозволи URI</string>\n    <string name=\"orientation\">Орієнтація</string>\n    <string name=\"no_receivers\">Немає ресіверів</string>\n    <string name=\"receivers\">Ресівери</string>\n    <string name=\"permissions\">Використовує дозволи</string>\n    <string name=\"filter_running_apps\">Запущені служби</string>\n    <string name=\"copy\">Копіювати</string>\n    <string name=\"view_missing_signatures\">Торкніться, щоб переглянути або надіслати підписи, котрі наразі відстутні в базі даних бібліотек App Manager.</string>\n    <string name=\"tap_to_see_details\">Торкніться, щоб переглянути деталі</string>\n    <string name=\"lib_details\">Відомості про бібліотеку</string>\n    <string name=\"no_libs\">Немає бібліотек</string>\n    <string name=\"scanner\">Сканер</string>\n    <plurals name=\"missing_signatures\">\n        <item quantity=\"one\">%1$d підпис відсутній</item>\n        <item quantity=\"few\">%1$d підписи відсутні</item>\n        <item quantity=\"many\">%1$d підписів відсутньо</item>\n        <item quantity=\"other\">%1$d підписів відсутньо</item>\n    </plurals>\n    <plurals name=\"libraries\">\n        <item quantity=\"one\">%1$d бібліотека</item>\n        <item quantity=\"few\">%1$d бібліотеки</item>\n        <item quantity=\"many\">%1$d бібліотек</item>\n        <item quantity=\"other\">%1$d бібліотек</item>\n    </plurals>\n    <plurals name=\"classes\">\n        <item quantity=\"one\">%1$d клас</item>\n        <item quantity=\"few\">%1$d класи</item>\n        <item quantity=\"many\">%1$d класів</item>\n        <item quantity=\"other\">%1$d класів</item>\n    </plurals>\n    <plurals name=\"other_trackers_and_classes\">\n        <item quantity=\"one\"><xliff:g id=\"tracker_no\" example=\"8\">%1$d</xliff:g> трекер з <xliff:g id=\"class_no\" example=\"50\">%2$d</xliff:g> класами</item>\n        <item quantity=\"few\"><xliff:g id=\"tracker_no\" example=\"8\">%1$d</xliff:g> трекери з <xliff:g id=\"class_no\" example=\"50\">%2$d</xliff:g> класами</item>\n        <item quantity=\"many\"><xliff:g id=\"tracker_no\" example=\"8\">%1$d</xliff:g> трекерів з <xliff:g id=\"class_no\" example=\"50\">%2$d</xliff:g> класами</item>\n        <item quantity=\"other\"><xliff:g id=\"tracker_no\" example=\"8\">%1$d</xliff:g> трекерів з <xliff:g id=\"class_no\" example=\"50\">%2$d</xliff:g> класами</item>\n    </plurals>\n    <plurals name=\"two_trackers_and_classes\">\n        <item quantity=\"one\">2 трекери з <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g> класами</item>\n        <item quantity=\"few\">2 трекери з <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g> класами</item>\n        <item quantity=\"many\">2 трекери з <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g> класами</item>\n        <item quantity=\"other\">2 трекери з <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g> класами</item>\n    </plurals>\n    <plurals name=\"tracker_and_classes\">\n        <item quantity=\"one\">1 трекер з <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g> класом</item>\n        <item quantity=\"few\">1 трекер з <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g> класами</item>\n        <item quantity=\"many\">1 трекер з <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g> класами</item>\n        <item quantity=\"other\">1 трекер з <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g> класами</item>\n    </plurals>\n    <string name=\"am_crashed\">App Manager аварійно завершив роботу</string>\n    <string name=\"duplicate\">Дублікат</string>\n    <string name=\"new_profile\">Новий профіль</string>\n    <string name=\"input_profile_name_description\">Назва профілю не повинна містити пробілу.</string>\n    <string name=\"input_profile_name\">Назва профілю</string>\n    <string name=\"in_progress\">В процесі</string>\n    <string name=\"conversion_failed\">Не вдалося виконати перетворення.</string>\n    <string name=\"select_apk\">Виберіть APK</string>\n    <string name=\"send_crash_report\">Надіслати звіт про аварійне завершення роботи</string>\n    <string name=\"tap_to_submit_crash_report\">Торкніться, щоб надіслати звіт про аварійне завершення роботи.</string>\n    <string name=\"none\">Без шифрування</string>\n    <string name=\"ecc\">Еліптична криптографія (ЕСС)</string>\n    <string name=\"pref_encryption_msg\">Шифрування резервних копій.</string>\n    <string name=\"encryption\">Шифрування</string>\n    <string name=\"select_user\">Виберіть користувача</string>\n    <string name=\"failed_to_duplicate_profile\">Не вдалося дублювати профіль</string>\n    <string name=\"user_profile_with_id\">Профіль: %1$s (%2$d)</string>\n    <string name=\"choose\">Вибрати</string>\n    <string name=\"options\">Параметри</string>\n    <string name=\"profile_state\">Стан профілю</string>\n    <string name=\"adb_over_tcp\">ADB через TCP</string>\n    <string name=\"pref_mode_of_operations\">Режим роботи</string>\n    <string name=\"send_selected\">Надіслати вибране</string>\n    <string name=\"profile_block_trackers_msg\">Блокування трекерів в додатках</string>\n    <string name=\"profile_clear_data_msg\">Очищення даних додатків</string>\n    <string name=\"profile_clear_cache_msg\">Очищення кешу додатків</string>\n    <string name=\"profile_force_stop_msg\">Примусова зупинка додатків</string>\n    <string name=\"install_location\">Місце встановлення</string>\n    <string name=\"installer\">Інсталятор</string>\n    <string name=\"comment\">Коментар</string>\n    <string name=\"close\">Закрити</string>\n    <string name=\"no_root\">Без-ROOT</string>\n    <string name=\"root\">ROOT</string>\n    <string name=\"advanced\">Розширений</string>\n    <string name=\"simple\">Простий</string>\n    <string name=\"enabled\">Увімкнено</string>\n    <string name=\"off\">ВИМК.</string>\n    <string name=\"on\">Увімкнено</string>\n    <string name=\"splits\">Спліти</string>\n    <string name=\"source_stamp_verified\">SourceStamp підтверджено.</string>\n    <string name=\"not_verified\">Не підтверджено</string>\n    <string name=\"verified\">Підтверджено</string>\n    <string name=\"pref_signature_schemes_msg\">Для більшої сумісності слід вибрати принаймні схеми v1 та v2. Схема v4 вимагає v2 або v3.</string>\n    <string name=\"v4_scheme\">Схема v4 (з Android 11)</string>\n    <string name=\"v3_scheme\">Схема v3 (з Android 9)</string>\n    <string name=\"v2_scheme\">Схема v2 (з Android 7.0)</string>\n    <string name=\"v1_scheme\">Схема v1 (з Android 1.0)</string>\n    <string name=\"pref_apk_signing_msg\">Налаштування схеми підписування, кастомний ключ підписування тощо.</string>\n    <string name=\"apk_signing\">Підписування APK</string>\n    <string name=\"pref_sign_apk_msg\">Підписати файли APK перед їх встановленням.</string>\n    <string name=\"pref_sign_apk\">Підписування APK</string>\n    <string name=\"install_location_prefer_external\">Надати перевагу зовнішній пам’яті</string>\n    <string name=\"install_location_internal_only\">Тільки внутрішня пам’ять</string>\n    <string name=\"profile_state_msg\">Налаштований стан увімкнення/вимкнення для цього профілю</string>\n    <string name=\"allow_routine_ops_msg\">Дозволити використання профілю в регулярних операціях</string>\n    <string name=\"allow_routine_ops\">Дозволити регулярні операції</string>\n    <plurals name=\"verified_with_warning\">\n        <item quantity=\"one\">Підтверджено з %d попередженням</item>\n        <item quantity=\"few\">Підтверджено з %d попередженнями</item>\n        <item quantity=\"many\">Підтверджено з %d попередженнями</item>\n        <item quantity=\"other\">Підтверджено з %d попередженнями</item>\n    </plurals>\n    <string name=\"input_keystore_alias_pass_description\">Вставте пароль для псевдоніма <b>%1$s</b>. Ви можете залишити це поле порожнім, якщо пароль збігається з паролем сховища ключів.</string>\n    <string name=\"input_keystore_alias_pass\">Пароль для псевдоніма <b>%1$s</b></string>\n    <string name=\"input_keystore_pass_msg\">Натисніть тут, щоб ввести пароль сховища ключів</string>\n    <string name=\"input_keystore_pass_description\">Ввести пароль сховища ключів App Manager. Якщо ви бачите це вперше, будь ласка, використовуйте генератор паролів для створення пароля та збереження його в безпечному місці, перш ніж вставити його тут.</string>\n    <string name=\"input_keystore_pass\">Введіть пароль сховища ключів</string>\n    <plurals name=\"app_signing_signature_schemes_pl\">\n        <item quantity=\"one\">Схема підпису</item>\n        <item quantity=\"few\">Схема підписів</item>\n        <item quantity=\"many\">Схема підписів</item>\n        <item quantity=\"other\">Схема підписів</item>\n    </plurals>\n    <string name=\"input_permissions_description\">Введення дозволів з пробілами, наприклад <tt>com.permission.GET_ACCOUNTS android.permission.ACCESS_MEDIA_LOCATION</tt> тощо. Використайте <tt>*</tt> щоб застосувати до всіх дозволів.</string>\n    <string name=\"input_permissions\">Введення дозволів</string>\n    <string name=\"no_app_ops_permission\">Немає дозволу на відображення app ops</string>\n    <string name=\"pref_backup_android_keystore_msg\">Не всі додатки працюватимуть після відновлення. Відновлення сховища ключів не працює на більшості пристроїв.</string>\n    <string name=\"pref_backup_android_keystore\">Резервне копіювання додатків зі сховищем ключів Android</string>\n    <string name=\"keep_data_and_app_signing_signatures\">Зберегти дані і підписи</string>\n    <string name=\"this_action_cannot_be_undone\">Цю операцію неможливо скасувати.</string>\n    <string name=\"filter_apps_with_splits\">Додатки з сплітами</string>\n    <string name=\"battery\">Акумулятор</string>\n    <string name=\"value\">Значення</string>\n    <string name=\"failed_to_enable_magisk_hide\">Не вдалося увімкнути MagiskHide</string>\n    <string name=\"failed_to_disable_magisk_hide\">Не вдалося вимкнути MagiskHide</string>\n    <string name=\"refresh_rate\">Частота оновлення</string>\n    <string name=\"scaling_factor\">Коефіцієнт масштабування</string>\n    <string name=\"size\">Розмір</string>\n    <string name=\"density\">Щільність пікселів</string>\n    <string name=\"screen\">Екран</string>\n    <string name=\"hardware\">Модель</string>\n    <string name=\"selinux\">Стан SELinux</string>\n    <string name=\"backup_skip_signature_checks_description\">Відновлення резервних копій, котрі не працюють через помилку перевірки контрольної суми або мають інший підпис APK, ніж підпис резервної копії.</string>\n    <string name=\"backup_multiple_description\">Створити окрему <i>іменовану</i> резервну копію замість основної резервної копії.</string>\n    <string name=\"backup_rules_description\">Резервне копіювання правил, налаштованих в App Manager.</string>\n    <string name=\"backup_extras_description\">Резервне копіювання дозволів, економії заряду, опцій використання даних, стану MagiskHide, SSAID, тощо.</string>\n    <string name=\"backup_extras\">Додатково</string>\n    <string name=\"backup_cache_description\">Резервне копіювання тек <b>cache</b>, <b>no_cache</b> та <b>no_backup</b>.</string>\n    <string name=\"backup_obb_media_description\">Резервне копіювання файлів OBB та тек медіа.</string>\n    <string name=\"backup_external_data_description\">Резервне копіювання зовнішніх тек даних.</string>\n    <string name=\"backup_internal_data_description\">Резервне копіювання тек даних. Якщо вибрати цей параметр, за замовчуванням буде створено резервні копії внутрішніх тек даних.</string>\n    <string name=\"backup_apk_files_description\">Резервне копіювання лише файлів apk з вихідного каталогу. Для цього слід вибрати <b>Джерело</b>.</string>\n    <string name=\"security\">Безпека</string>\n    <string name=\"graphics\">Графіка</string>\n    <string name=\"cpu\">ЦП</string>\n    <string name=\"users\">Користувачі</string>\n    <string name=\"languages\">Мови</string>\n    <string name=\"battery_capacity\">Ємність</string>\n    <string name=\"memory\">Пам\\'ять</string>\n    <string name=\"no_of_cores\">Ядра</string>\n    <string name=\"support_architectures\">Підтримувані архітектури</string>\n    <string name=\"kernel\">Ядро</string>\n    <string name=\"manufacturer\">Виробник</string>\n    <string name=\"board_name\">Системна плата</string>\n    <string name=\"model\">Модель</string>\n    <string name=\"brand_name\">Бренд</string>\n    <string name=\"pref_about_device_msg\">Основні відомості про пристрій, систему Android, процесор, графічний процесор, оперативну пам\\'ять, акумулятор тощо.</string>\n    <string name=\"about_device\">Про пристрій</string>\n    <string name=\"interceptor\">Перехоплювач</string>\n    <string name=\"resend_intent\">Повторно відправити intent</string>\n    <string name=\"share\">Поділитися</string>\n    <string name=\"extras\">Extras</string>\n    <string name=\"category\">Категорії</string>\n    <string name=\"mime_type\">MIME-тип</string>\n    <string name=\"action\">Дія</string>\n    <string name=\"result_code\">Код результату</string>\n    <string name=\"activity_result\">Результат activity</string>\n    <string name=\"send_edited_intent\">Надіслати відредагований intent</string>\n    <string name=\"matching_activities\">Відповідні activities</string>\n    <string name=\"window_size\">Розмір вікна</string>\n    <string name=\"security_providers\">Постачальники безпеки</string>\n    <string name=\"un_apkm\">Розпакування Apkm</string>\n    <plurals name=\"no_of_components\">\n        <item quantity=\"one\">%1$d компонент</item>\n        <item quantity=\"few\">%1$d компоненти</item>\n        <item quantity=\"many\">%1$d компонентів</item>\n        <item quantity=\"other\">%1$d компонентів</item>\n    </plurals>\n    <string name=\"disable_background_run_description\">Встановленя режиму <i>ignore</i> для app ops: <tt>RUN_IN_BACKGROUND</tt> (з Android7.0) і <tt>RUN_ANY_IN_BACKGROUND</tt> (з Android 9).</string>\n    <string name=\"set_mode_for_app_ops_dots\">Установити режим для app ops…</string>\n    <plurals name=\"alert_failed_to_set_app_ops\">\n        <item quantity=\"one\">Не вдалося встановити app ops %1$d додатка</item>\n        <item quantity=\"few\">Не вдалося встановити app ops %1$d додатків</item>\n        <item quantity=\"many\">Не вдалося встановити app ops %1$d додатків</item>\n        <item quantity=\"other\">Не вдалося встановити app ops %1$d додатків</item>\n    </plurals>\n    <string name=\"backup_custom_users_description\">Виконувати резервне копіювання лише для вказаних користувачів</string>\n    <string name=\"encrypted\">Зашифровано</string>\n    <string name=\"unencrypted\">Незашифрований</string>\n    <string name=\"no_volumes_found\">Не вдалося знайти томи з дозволом на запис.</string>\n    <string name=\"pref_backup_volume_msg\">Виберіть том або диск, на якому будуть зберігатися резервні копії.</string>\n    <string name=\"backup_volume\">Том резервного копіювання</string>\n    <string name=\"pref_backup_restore_msg\">Налаштування резервного копіювання/відновлення.</string>\n    <string name=\"set_app_op_mode\">Встановити режим роботи додатка</string>\n    <string name=\"list_options\">Параметри списку</string>\n    <string name=\"reverse\">Зворотний</string>\n    <string name=\"os_version\">Версія ОС</string>\n    <string name=\"add\">Додати</string>\n    <string name=\"add_to_profile\">Додати до профілю</string>\n    <string name=\"initializing\">Ініціалізація…</string>\n    <string name=\"choose_what_to_do\">Виберіть, що робити.</string>\n    <string name=\"screen_lock_msg\">Блокувати App Manager за допомогою блокування екрану Android</string>\n    <string name=\"screen_lock\">Блокування екрана</string>\n    <string name=\"unlock_app_manager\">Розблокувати App Manager</string>\n    <string name=\"sd_card\">SD-карта</string>\n    <string name=\"external_storage\">Зовнішнє сховище</string>\n    <string name=\"internal_storage\">Внутрішня пам’ять</string>\n    <string name=\"back_up\">Резервне копіювання</string>\n    <string name=\"drm_free_apkm_msg\">Файл APKM не має DRM, не потрібно конвертувати його в APKS.</string>\n    <string name=\"restore_msg\">Відновлення додатків із даними</string>\n    <string name=\"backup_msg\">Резервне копіювання додатків із даними</string>\n    <string name=\"restore_latest_msg\">Відновлення вже встановлених додатків, коди версій котрих вищий, ніж код встановлених.</string>\n    <string name=\"restore_latest\">Відновлення останніх резервних копій</string>\n    <string name=\"restore_not_installed_msg\">Відновлення основної резервної копії не встановленних додатків.</string>\n    <string name=\"restore_not_installed\">Відновити невстановлені додатки</string>\n    <string name=\"restore_all_msg\">Відновити основну резервну копію усіх резервних копій додатків.</string>\n    <string name=\"restore_all\">Відновлення всіх додатків</string>\n    <string name=\"backup_apps_with_changes_msg\">Повторити резервне копіювання додатків, які змінилися після останнього резервного копіювання. Вони включають зміни в розмірі, версії, часі останнього запуску.</string>\n    <string name=\"backup_apps_with_changes\">Резервне копіювання додатків із змінами</string>\n    <string name=\"redo_existing_backups_msg\">Повторити резервне копіювання встановлених додатків з попередніми резервними копіями.</string>\n    <string name=\"redo_existing_backups\">Повторно створити наявні резервні копії</string>\n    <string name=\"verify_and_redo_backups_msg\">Перевірка ціліснісності попередніх резервних копій та повторне резервне копіювання тих, котрі не пройшли перевірку цілісності.</string>\n    <string name=\"verify_and_redo_backups\">Перевірка та повторне створення резервних копій</string>\n    <string name=\"backup_apps_without_backups_msg\">Резервне копіювання додатків без попередніх резервних копій.</string>\n    <string name=\"backup_apps_without_backups\">Резервне копіювання додатків без резервних копій</string>\n    <string name=\"backup_all_apps_msg\">Резервне копіювання всіх встановлених додатків.</string>\n    <string name=\"backup_all_apps\">Резервне копіювання всіх додатків</string>\n    <string name=\"app_signing_signature_schemes\">Схема підпису</string>\n    <string name=\"restart_to_reflect_changes\">Вам потрібно негайно перезапустити пристрій, щоб відобразити зміни.</string>\n    <string name=\"failed_to_change_ssaid\">Не вдалося змінити SSAID</string>\n    <string name=\"copied_to_clipboard\">Скопійовано до буфера обміну.</string>\n    <string name=\"ssaid_info\">SSAID (<tt>Settings.Secure.ANDROID_ID</tt>) - це ідентифікатор пристрою, призначений кожному додатку (з Android Oreo і вище). Він широко використовується додатками для відстеження користувачів.</string>\n    <string name=\"net_policy\">Політика мережі</string>\n    <string name=\"has_net_policy\">Політика мережі</string>\n    <string name=\"type_string_array_list\">Список рядків</string>\n    <string name=\"type_string_array\">Масив рядків</string>\n    <string name=\"type_float_array_list\">Список десяткових чисел</string>\n    <string name=\"type_float_array\">Масив десяткових чисел</string>\n    <string name=\"type_long_array_list\">Список довгих цілих чисел</string>\n    <string name=\"type_long_array\">Масив довгих цілих чисел</string>\n    <string name=\"type_int_array_list\">Список цілих чисел</string>\n    <string name=\"type_int_array\">Масив цілих чисел</string>\n    <string name=\"type_component_name\">Ім\\'я компонента</string>\n    <string name=\"enable_battery_optimization\">Увімкнути оптимізацію енергоспоживання\\?</string>\n    <string name=\"battery_optimization\">Оптимізація енергоспоживання</string>\n    <string name=\"no_battery_optimization\">Без оптимізації енергоспоживання</string>\n    <string name=\"patch_level\">Оновлення безпеки Андроїд</string>\n    <string name=\"type_null\">Немає значення</string>\n    <string name=\"vendor\">Постачальник</string>\n    <string name=\"set_custom_app_op\">Користувацьке налаштування app op</string>\n    <string name=\"user_with_id\">Користувач: <xliff:g id=\"user_id\" example=\"0\">%1$d</xliff:g></string>\n    <string name=\"last_actions\">Останні дії</string>\n    <string name=\"pref_enable_disable_features_msg\">Увімкніть або вимкніть функції в App Manager.</string>\n    <string name=\"enable_disable_features\">Увімкнути/вимкнути функції</string>\n    <string name=\"installed_apps\">Встановлені додатки</string>\n    <string name=\"backup_custom_users\">Вибір користувачів</string>\n    <string name=\"isolated\">Ізольовано</string>\n    <string name=\"working_on_adb_mode\">Робота в режимі ADB</string>\n    <string name=\"screen_lock_not_enabled\">Виберіть блокування екрана в налаштуваннях Android або очистіть дані додатку.</string>\n    <string name=\"input_app_ops_description_profile\">Введіть імена та/або константи додатків із пробілами, наприклад <tt>WAKE_LOCK 63 72 CAMERA</tt> тощо. Використовуйте <tt>*</tt>, щоб застосувати до всіх налаштованих app ops.</string>\n    <string name=\"installer_app_message\">Натисніть <b>вибрати</b> для використання одного з встановлених додатків, або натисніть <b>користувацький</b>, щоб вказати власне ім\\'я пакета.</string>\n    <string name=\"filter_apps_without_backups\">Додатки без резервних копій</string>\n    <string name=\"uninstalled_apps\">Видалені додатки</string>\n    <string name=\"specify_custom_name\">Користувацький</string>\n    <string name=\"verified_using_unreliable_hash\">Перевірено за допомогою ненадійного хешу</string>\n    <string name=\"internal_data\">Внутрішні дані</string>\n    <string name=\"pref_installer_msg\">Налаштуйте поведінку встановника додатків.</string>\n    <string name=\"expiry_date_cannot_be_empty\">Дата закінчення терміну дії не може бути порожньою.</string>\n    <string name=\"signing_key\">Ключ підпису</string>\n    <string name=\"failed_to_read_keystore\">Не вдалося прочитати сховище ключів.</string>\n    <string name=\"alias_pass\">Пароль псевдоніма</string>\n    <string name=\"choose_an_alias\">Виберіть псевдонім</string>\n    <string name=\"found_no_alias_in_keystore\">Не знайдено псевдонім у сховищі ключів!</string>\n    <string name=\"new_alias_password\">Новий пароль псевдоніма</string>\n    <string name=\"import_key\">Імпорт ключа</string>\n    <string name=\"pem_file\">Файл PEM</string>\n    <string name=\"pk8_file\">Файл PKCS #8 (PK8)</string>\n    <string name=\"pem_and_pk8\">PEM та PKCS # 8 (PK8)</string>\n    <string name=\"keystore_pass\">Пароль сховища ключів</string>\n    <string name=\"keystore_file\">Файл сховища ключів</string>\n    <string name=\"country_name\" tools:ignore=\"TypographyOther\">Назва країни (C)</string>\n    <string name=\"state_name\">Назва держави (ST)</string>\n    <string name=\"locality_name\">Назва (міста) місцевості (L)</string>\n    <string name=\"organization_name\">Назва організації (O)</string>\n    <string name=\"organization_unit\">Підрозділ організації (OU)</string>\n    <string name=\"common_name\">Загальне ім\\'я (CN)</string>\n    <string name=\"input_key_password\">Пароль ключа</string>\n    <string name=\"failed_to_load_key\">Не вдалося завантажити ключ.</string>\n    <string name=\"key_not_set\">Не встановлено.</string>\n    <string name=\"use_default\">Використовувати за замовчуванням</string>\n    <string name=\"invalid_rsa_key_size\">Неприпустимий розмір ключа для RSA шифрування. Розмір ключа може бути 1024, 2048 або 4096 біт.</string>\n    <string name=\"crypto_key_size\">Розмір ключа</string>\n    <string name=\"invalid_aes_key_size\">Неприпустимий розмір ключа для шифрування AES. Розмір ключа може бути як 128 або 256 біт.</string>\n    <string name=\"failed_to_initialize_key_store\">Не вдалося ініціалізувати сховище ключів App Manager.</string>\n    <string name=\"failed_to_save_key\">Не вдалося зберегти ключ.</string>\n    <string name=\"generate_key\">Створити</string>\n    <string name=\"input_key\">Ввід ключа (в шістнадцятковій системі числення)</string>\n    <string name=\"gles_version\">Версія OpenGL ES</string>\n    <string name=\"input_keystore_alias_pass_msg\">Натисніть тут, щоб вказати пароль для %1$s</string>\n    <string name=\"app_signing_signatures\">Підписи</string>\n    <string name=\"pref_log_write_period_title\">Період запису</string>\n    <string name=\"pref_log_write_period_summary\">Під час запису записувати на SD-карту кожні %1$d рядків.</string>\n    <string name=\"pref_log_line_period_error\">Введіть ціле число від 1 до 1000.</string>\n    <string name=\"pref_expanded_by_default_title\">Розгорнути за замовчуванням</string>\n    <string name=\"pref_expanded_by_default_summary\">Показувати повний текст логу за замовчуванням.</string>\n    <string name=\"pref_filter_pattern_title\">Відфільтруйте теги</string>\n    <string name=\"pref_filter_pattern_summary\">Відфільтрувати вибрані теги в логах.</string>\n    <string name=\"pref_display_limit_title\">Ліміт відображення логу</string>\n    <string name=\"pref_display_limit_summary\">Відображати лише останні %1$d логів, щоб уникнути помилок переповнення пам\\'яті.</string>\n    <string name=\"pref_default_log_level_title\">Рівень логу за замовчуванням</string>\n    <string name=\"pref_default_log_level_summary\">Рівень логу під час запуску, під час відкриття файлів та під час запису.</string>\n    <string name=\"pref_cat_configuration\">Налаштування</string>\n    <string name=\"pref_cat_appearance\">Зовнішній вигляд</string>\n    <string name=\"pref_cat_advanced\">Розширені</string>\n    <string name=\"pref_buffer_title\">Буфер логу</string>\n    <string name=\"open\">Відкрити</string>\n    <string name=\"notification_title\">Триває запис логу</string>\n    <string name=\"notification_ticker\">Запис логу розпочато</string>\n    <string name=\"notification_subtext\">Торкніться, щоб зупинити запис</string>\n    <string name=\"no_saved_logs\">Немає збережених журналів.</string>\n    <string name=\"manage_saved_logs\">Керування збереженими логами</string>\n    <string name=\"log_saved\">Лог збережено.</string>\n    <string name=\"log_recording_started\">Розпочато запис логу.</string>\n    <string name=\"log_level\">Рівень логу</string>\n    <string name=\"log_cleared\">Логи очищено</string>\n    <string name=\"filter_choice_tag\">Тег</string>\n    <string name=\"filter_choice\">Шукати за</string>\n    <string name=\"enter_good_filename\">Введіть дійсну назву файлу.</string>\n    <string name=\"enter_filename\">Введіть назву файлу</string>\n    <string name=\"dialog_compiling_log\">Компіляція логу…</string>\n    <string name=\"delete_saved_log\">Видалити збережені логи</string>\n    <string name=\"copy_to_clipboard\">Скопіювати в буфер обміну</string>\n    <string name=\"add_filter_ellipsis\">Додати фільтр…</string>\n    <string name=\"add_filter\">Додати фільтр</string>\n    <string name=\"filename\">Назва файлу</string>\n    <string name=\"restart_log_viewer_to_see_changes\">Перезапустіть вікно перегляду логів, щоб побачити зміни.</string>\n    <string name=\"pref_log_viewer_msg\">Налаштування способу відображення логів.</string>\n    <string name=\"log_viewer\">Перегляд логів</string>\n    <string name=\"pref_rules_msg\">Миттєве блокування, імпорт/експорт/видалення правил і т.д.</string>\n    <string name=\"failed\">Невдача</string>\n    <string name=\"confirm_import_keystore\">Ви дійсно бажаєте замінити наявне сховище ключів\\? Цю дію не можна скасувати.</string>\n    <string name=\"import_keystore\">Імпорт сховища ключів</string>\n    <string name=\"pref_import_export_keystore_msg\">Імпорт/експорт Bouncy Castle KeyStore (BKS), який використовується App Manager.</string>\n    <string name=\"pref_import_export_keystore\">Імпорт/експорт сховища ключів</string>\n    <string name=\"latest_backup\">Останнє резервне копіювання</string>\n    <string name=\"gz_bz2_compressed\">%1$s стиснутий</string>\n    <string name=\"pgp_aes_rsa_encrypted\">%1$s зашифровано</string>\n    <string name=\"no_encryption\">Без шифрування</string>\n    <string name=\"base_backup\">Основна резервна копія</string>\n    <string name=\"trackers_unblocked_successfully\">Тепер трекери розблоковано</string>\n    <string name=\"trackers_blocked_successfully\">Тепер трекери заблоковані</string>\n    <string name=\"failed_to_unblock_trackers\">Не вдалося розблокувати трекери</string>\n    <string name=\"failed_to_block_trackers\">Не вдалося заблокувати трекери</string>\n    <string name=\"profile_save_apk_msg\">Зберігає файли APK у <tt>AppManager/apks</tt></string>\n    <string name=\"save_apk\">Зберегти файл .apk</string>\n    <string name=\"running_services\">Запущені служби</string>\n    <string name=\"view_logs\">Перегляд логів</string>\n    <string name=\"share_log\">Поділитись</string>\n    <string name=\"text_include_dmesg\">Включити журнал ядра</string>\n    <string name=\"omit_sensitive_info_summary\">Пропускати конфіденційну інформацію, наприклад веб-адреси, номери телефонів або електронну пошту.</string>\n    <string name=\"omit_sensitive_info\">Пропустити конфіденційну інформацію</string>\n    <string name=\"undo\">Повернути</string>\n    <string name=\"pause_unpause\">Відтворення/пауза</string>\n    <string name=\"collapse_all\">Згорнути все</string>\n    <string name=\"expand_all\">Розгорнути все</string>\n    <string name=\"file\">Файл</string>\n    <string name=\"widget_start_recording\">Запис\n\\nЛог</string>\n    <string name=\"widget_recording_in_progress\">Запис…</string>\n    <string name=\"unable_to_save_log\">Не вдалося зберегти лог. Ви ввели дійсне ім\\'я файлу\\?</string>\n    <plurals name=\"toast_log_truncated\">\n        <item quantity=\"one\">Лог занадто великий, відображається останній %d рядок.</item>\n        <item quantity=\"few\">Лог занадто великий, відображаються останні %d рядки.</item>\n        <item quantity=\"many\">Лог занадто великий, відображаються останні %d рядків.</item>\n        <item quantity=\"other\">Лог занадто великий, відображаються останні %d рядків.</item>\n    </plurals>\n    <string name=\"toast_invalid_selection\">Неприпустиме виділення. Повторіть спробу.</string>\n    <string name=\"toast_invalid_level\">Неприпустиме ім\\'я рівня: %s</string>\n    <string name=\"pref_display_limit_hint\">Введіть дійсне число між %1$d і %2$d.</string>\n    <string name=\"text_include_device_info\">Включити відомості про пристрій</string>\n    <string name=\"text_filter_text\">Фільтрувати текст</string>\n    <string name=\"text_filter_ellipsis\">Фільтр…</string>\n    <string name=\"subject_log_report\">Звіт логу</string>\n    <string name=\"start_recording_log\">Запис</string>\n    <string name=\"settings\">Налаштування</string>\n    <string name=\"send_log_title\">Надіслати лог</string>\n    <string name=\"save_log\">Зберегти лог</string>\n    <string name=\"save_as\">Зберегти як…</string>\n    <string name=\"record_log\">Запис логу</string>\n    <string name=\"pref_show_timestamp_title\">Показати pid і timestamp</string>\n    <string name=\"pref_show_timestamp_summary\">Показувати process id та timestamp при розгортанні.</string>\n    <string name=\"orientation_right_to_left\">Справа наліво</string>\n    <string name=\"orientation_left_to_right\">Зліва направо</string>\n    <string name=\"orientation_follow_locale\">Згідно системної мови</string>\n    <plurals name=\"file_deletion_confirmation\">\n        <item quantity=\"one\">%d файл буде видалено</item>\n        <item quantity=\"few\">%d файли буде видалено</item>\n        <item quantity=\"many\">%d файлів буде видалено</item>\n        <item quantity=\"other\">%d файлів буде видалено</item>\n    </plurals>\n    <string name=\"launch_mode_single_top\">Один зверху</string>\n    <string name=\"source_code_links\"><a href=\"https://github.com/MuntashirAkon/AppManager\">GitHub</a> •\n        <a href=\"https://gitlab.com/muntashir/AppManager\">GitLab</a> •\n        <a href=\"https://0xacab.org/muntashir/AppManager\">Riseup</a> •\n        <a href=\"https://codeberg.org/muntashir/AppManager\">Codeberg</a></string>\n    <string name=\"apk_updater\">APK Updater</string>\n    <string name=\"enforcing\">Enforcing</string>\n    <string name=\"uri\">URI</string>\n    <string name=\"rsa\">RSA</string>\n    <string name=\"aes\">AES</string>\n    <string name=\"dsa_affine_y\">Аффінна координата y</string>\n    <string name=\"dsa_affine_x\">Аффінна координата x</string>\n    <string name=\"magisk_hide_enabled\">MagiskHide</string>\n    <string name=\"state_wake_kill\">Wake kill</string>\n    <string name=\"netpolicy_disable_network_access\">Заборонити передачу даних</string>\n    <string name=\"netpolicy_reject_wifi_data\">Заборонити Wi-Fi передачу</string>\n    <string name=\"netpolicy_reject_vpn_data\">Заборонити VPN передачу</string>\n    <string name=\"netpolicy_reject_cellular_data\">Заборонити мобільні дані</string>\n    <string name=\"netpolicy_allow_background_data\">Дозволити передачу у фоновому режимі, коли ввімкнено заощадження трафіку</string>\n    <string name=\"netpolicy_reject_background_data\">Заборонити дані у фоні</string>\n    <string name=\"state_parked\">Припарковано</string>\n    <string name=\"state_device_io\">Пристрій вводу/виводу</string>\n    <string name=\"no_changes\">Без змін</string>\n    <string name=\"pref_display_changes_msg\">Показати зміни у версіях, трекерах, компонентах, дозволах, підписах, SDK, і т.д. в режимі контролю версій.</string>\n    <string name=\"pref_display_changes\">Показати зміни</string>\n    <string name=\"hidden\">Приховано</string>\n    <string name=\"suspended\">Призупинено</string>\n    <string name=\"saf\">SAF</string>\n    <string name=\"filter_choice_pid\">PID</string>\n    <string name=\"log_level_fatal\">Fatal</string>\n    <string name=\"log_level_warn\">Warn</string>\n    <string name=\"log_level_verbose\">Verbose</string>\n    <string name=\"log_level_info\">Info</string>\n    <string name=\"log_level_error\">Error</string>\n    <string name=\"log_level_debug\">Debug</string>\n    <string name=\"pkcs12_keystore\">PKCS #12 KeyStore (P12)</string>\n    <string name=\"bouncy_castle_keystore\">Bouncy Castle KeyStore (BKS)</string>\n    <string name=\"java_keystore\">Java KeyStore (JKS)</string>\n    <string name=\"bootloader\">Bootloader</string>\n    <string name=\"permissive\">Permissive</string>\n    <string name=\"ssaid\">SSAID</string>\n    <string name=\"type_uri\">URI</string>\n    <string name=\"port_number_invalid\">Недійсний номер порту.</string>\n    <string name=\"port_number_empty\">Номер порту порожній.</string>\n    <string name=\"adb_connect_port_number_description\">Номер порту знаходиться в розділі <b>IP-адреса&amp; порт</b> трохи нижче розділу <b>Назва пристрою</b>.</string>\n    <string name=\"port_number\">Порт</string>\n    <string name=\"adb_connect\">З\\'єднання</string>\n    <string name=\"wireless_debugging\">Бездротове налагодження</string>\n    <string name=\"unknown_net_policy\">Невідома мережна політика (%1$s - %2$X)</string>\n    <string name=\"failed_to_prevent_background_run\">Не вдалося запобігти роботу в фоновому режимі додатку %1$s</string>\n    <string name=\"community\">Спільнота</string>\n    <plurals name=\"alert_failed_to_import_backups\">\n        <item quantity=\"one\">Не вдалося імпортувати %1$d резервну копію</item>\n        <item quantity=\"few\">Не вдалося імпортувати %1$d резервні копії</item>\n        <item quantity=\"many\">Не вдалося імпортувати %1$d резервних копій</item>\n        <item quantity=\"other\">Не вдалося імпортувати %1$d резервних копій</item>\n    </plurals>\n    <string name=\"import_from_tb\">Імпорт з Titanium Backup</string>\n    <string name=\"import_from_oab\">Імпорт із OAndBackup</string>\n    <string name=\"pref_import_backups_msg\">Імпорт резервних копій з OAndBackup, Swift Backup (3.0–3.2) абоTitanium Backup.</string>\n    <string name=\"pref_import_backups\">Імпорт резервних копій</string>\n    <string name=\"added_to_queue\">Додано в чергу</string>\n    <string name=\"minimum_version\">Мінімальна версія: %d</string>\n    <string name=\"help_uses_permissions_tab\">Натисніть на елемент, щоб <b>надати</b> або <b>відкликати</b>. Лише дозволи рівня <b>небезпечний</b> та <b>розробка</b> можуть бути надані або відкликані.</string>\n    <string name=\"help_permissions_tab\">Ці дозволи визначаються цією програмою, і їх не можна відкликати.</string>\n    <string name=\"help_app_ops_tab\">Натисніть на елемент, щоб <b>дозволити</b> або <b>ігнорувати</b>. Натисніть і тримайте елемент, щоб побачити інші підтримувані режими.</string>\n    <string name=\"permission_flags\">Прапорці дозволів</string>\n    <string name=\"pref_selected_users_msg\">Обмежити роботу App Manager лише з вибраними користувачами.</string>\n    <string name=\"pref_selected_users\">Вибрані користувачі</string>\n    <string name=\"files\">Файли</string>\n    <string name=\"storage\">Сховище</string>\n    <string name=\"notice_saf\">На відміну від томів, обраний каталог буде використовуватися для зберігання всіх файлів, пов\\'язаних з App Manager, включаючи збережені APK і резервні копії. Storage Access Framework (SAF) працює дуже повільно, тому ви повинні використовувати цей варіант тільки тоді, коли інші не можуть бути використані.</string>\n    <string name=\"notice\">Сповіщення</string>\n    <string name=\"error_with_details\">Помилка: %s</string>\n    <string name=\"saved_filters\">Збережені фільтри</string>\n    <string name=\"community_links\"><a href=\"https://t.me/AppManagerChannel\">Telegram канал</a> • <a href=\"https://twitter.com/AppManagerNews\">Twitter</a></string>\n    <string name=\"paired_successfully\">Сполучено.</string>\n    <string name=\"adb_pair\">Сполука</string>\n    <string name=\"invalid_password\">Недійсний пароль, повторіть спробу.</string>\n    <string name=\"keystore_pass_cannot_be_empty\">Пароль сховища ключів не може бути порожнім.</string>\n    <string name=\"keystore_password_info\">Нижче наведено пароль сховища ключів App Manager. Збережіть його в захищеному місці, якщо ви збираєтеся створити резервну копію/відновлювати сховище ключів App Manager. <b>Це повідомлення більше не відображатиметься.</b></string>\n    <string name=\"staging_apk_files\">Підготовка…</string>\n    <string name=\"running_services_logcat_hint\">Натисніть на елемент, щоб відкрити \\\"Перегляд логів\\\", використовуючи відповідний ідентифікатор процесу в ролі фільтра за замовчуванням.</string>\n    <string name=\"pid\">Ідентифікатор процесу</string>\n    <plurals name=\"pref_thread_count_msg\">\n        <item quantity=\"one\">Виконувати не більше %1$d операції паралельно</item>\n        <item quantity=\"few\">Виконувати не більше %1$d операцій паралельно</item>\n        <item quantity=\"many\">Виконувати не більше %1$d операцій паралельно</item>\n        <item quantity=\"other\">Виконувати не більше %1$d операцій паралельно</item>\n    </plurals>\n    <string name=\"pref_thread_count_hint\">Значення має бути від 0 до %1$d, де 0 означає <i>максимальна кількість операцій у даний час</i>.</string>\n    <string name=\"pref_thread_count\">Паралельне виконання</string>\n    <string name=\"type_uri_array_list\">Список URI</string>\n    <string name=\"type_uri_array\">Масив URI</string>\n    <string name=\"pref_always_on_background_msg\">Завжди встановлювати додатки у фоновому режимі та відображати сповіщення по завершенні процесу.</string>\n    <string name=\"pref_always_on_background\">Встановити у фоновому режимі</string>\n    <string name=\"pref_block_trackers_msg\">Блокування трекерів після встановлення додатку за допомогою App Manager.</string>\n    <string name=\"next\">Далі</string>\n    <string name=\"installer_app_installed\">Додаток встановлено</string>\n    <string name=\"background\">Фон</string>\n    <string name=\"trim_caches_in_all_apps_description\">Видаляє файли кеш усіх додатків, включаючи систему Android</string>\n    <string name=\"trim_caches_in_all_apps\">Видалення кеш у всіх додатках</string>\n    <string name=\"user_root\">Використовувати root</string>\n    <string name=\"paste\">Вставити</string>\n    <string name=\"set_package_name_first\">Спочатку встановіть назву пакета!</string>\n    <string name=\"identifier\">Ідентифікатор</string>\n    <string name=\"backup_volume_dialog_description\">Томи з префіксом <tt>/tree</tt> є теками, вибраними за допомогою Storage Access Framework (SAF). За винятком цих тек, каталог за замовчуванням для App Manager є підтекою з назвою <tt>AppManager</tt>.</string>\n    <string name=\"second_degree_tracker_note\">Префікс ² вказує на те, що трекери знаходяться в списку очікування <a href=\"https://etip.exodus-privacy.eu.org/\">ETIP</a>, тобто чи є вони фактичними трекерами, все ще досліджується.</string>\n    <string name=\"failed_to_uninstall_app\">Не вдалося видалити</string>\n    <string name=\"exit_confirmation\">Підтвердження виходу</string>\n    <string name=\"import_from_sb\">Імпорт із Swift Backup 3.0 – 3.2</string>\n    <string name=\"pref_import_backups_hint\">Виберіть каталог, що містить файли (Swift Backup/Titanium Backup) або каталоги (OAndBackup) резервних копій</string>\n    <string name=\"accessibility_service_description\">Загальна служба спеціальних можливостей для виконання певних операцій, таких як очищення кеша в режимі без-root.</string>\n    <string name=\"explore\">Аналіз</string>\n    <string name=\"system_partition\">Корінь системного розділу</string>\n    <string name=\"java\">Java</string>\n    <string name=\"smali\">smali</string>\n    <string name=\"extract\">Розпакувати</string>\n    <string name=\"replace\">Замінити</string>\n    <string name=\"rename\">Переіменувати</string>\n    <string name=\"pref_default_blocking_method\">Метод блокування за замовчуванням</string>\n    <string name=\"pref_intent_firewall_and_disable_description\">Блокування компонентів за допомогою Intent Firewall і також вимкнення. Рекомендований метод для root користувачів .</string>\n    <string name=\"pref_disable_description\">Лише вимкнення компонентів. Не рекомендується root користувачам, оскільки програми можуть обійти це блокування. У режимі ADB за допомогою цього методу можна вимкнути програми лише для тестування.</string>\n    <string name=\"search_type_contains\">містить</string>\n    <string name=\"search_type_suffix\">суфікс</string>\n    <string name=\"search_type_regular_expressions\">регулярний вираз</string>\n    <string name=\"intent_firewall_and_disable\">IFW + вимкнення</string>\n    <string name=\"pref_default_blocking_method_description\">Метод, який використовується за замовчуванням там, де немає можливості вибрати метод блокування.</string>\n    <string name=\"search_type_prefix\">префікс</string>\n    <string name=\"pref_intent_firewall_description\">Блокування компонентів лише за допомогою Intent Firewall. Не рекомендується, оскільки деякі системні програми можуть обходити цей метод блокування.</string>\n    <string name=\"intent_firewall\">IFW</string>\n    <string name=\"authenticating\">Автентифікація…</string>\n    <plurals name=\"usage_seconds\">\n        <item quantity=\"one\">%1$d с</item>\n        <item quantity=\"few\">%1$d с</item>\n        <item quantity=\"many\">%1$d с</item>\n        <item quantity=\"other\">%1$d с</item>\n    </plurals>\n    <string name=\"toggle_internet\">Використовувати інтернет</string>\n    <string name=\"vt_checking\">VirusTotal: перевірка…</string>\n    <string name=\"vt_queued\">VirusTotal: у черзі</string>\n    <string name=\"vt_failed\">VirusTotal: збій</string>\n    <string name=\"vt_success\">VirusTotal: %1$d/%2$d</string>\n    <string name=\"vt_scan_date\">Дата сканування: %1$s</string>\n    <string name=\"pref_vt_apikey\">Ключ API VirusTotal</string>\n    <string name=\"pref_vt_apikey_description\">Ключ API дозволяє App Manager завантажувати файли APK до VirusTotal, а також отримувати звіти. Зареєструйтеся в https://virustotal.com, щоб отримати ключ API безкоштовно.</string>\n    <string name=\"pref_vt_apikey_summary\">Увімкнути сканування файлів APK через VirusTotal.</string>\n    <string name=\"process_id\">Ідентифікатор процесу</string>\n    <string name=\"parent_process_id\">Ідентифікатор батьківського процесу</string>\n    <string name=\"virtual_memory\">Віртуальна пам\\'ять</string>\n    <string name=\"cpu_percent\">%% ЦП</string>\n    <string name=\"cpu_time\">Час ЦП</string>\n    <string name=\"priority\">Пріоритет</string>\n    <string name=\"threads\">Кількість потоків</string>\n    <string name=\"state\">Стан процесу</string>\n    <string name=\"commandline_args\">Аргументи командного рядка</string>\n    <string name=\"memory_chart_info\">● Програми %1$s ● %2$s Кешовано ● %3$s Буфер ● %4$s Вільно</string>\n    <string name=\"swap_chart_info\">● %1$s Використовується ● %2$s Вільно</string>\n    <string name=\"failed_to_change_app_op_mode\">Не вдалося змінити режим app op.</string>\n    <string name=\"warning_working_on_root_mode\">Попередження: робота в root-режимі замість режиму ADB.</string>\n    <string name=\"failed_to_disable_magisk_deny_list\">Не вдалося ввімкнути Magisk DenyList</string>\n    <string name=\"mode_of_op_with_inferred_mode_of_op\">%1$s (імовірний режим: %2$s)</string>\n    <string name=\"scan_in_vt\">Сканування в VirusTotal</string>\n    <plurals name=\"usage_minutes\">\n        <item quantity=\"one\">%1$d хв</item>\n        <item quantity=\"few\">%1$d хв</item>\n        <item quantity=\"many\">%1$d хв</item>\n        <item quantity=\"other\">%1$d хв</item>\n    </plurals>\n    <string name=\"vt_uploading\">VirusTotal: завантаження…</string>\n    <string name=\"vt_permalink\">Постійне посилання на VirusTotal</string>\n    <string name=\"vt_slowness_warning\">Залежно від швидкості Інтернету та навантаження на сервер, це може зайняти деякий час.</string>\n    <string name=\"vt_disclaimer\">VirusTotal та його логотипи є торговою маркою Chronicle LLC. Ні App Manager — клієнт API, ні його автори не несуть відповідальності за будь-які дані, які ви можете надіслати до VirusTotal.</string>\n    <string name=\"uses_play_app_signing_description\">Ця програма містить певні маркери, які вказують на те, що вона <i>можливо </i> використовує <a href=\"https://support.google.com/googleplay/android-developer/answer/9842756\">Підпис Play App</a>. За цією схемою ключі підпису зберігаються на серверах Google, і Google відповідає за підписання програми. Зауважте, що відповідність інформації підпису — це єдиний спосіб переконатися, що додаток не був змінений кимось іншим, окрім розробника (а в цьому випадку також Google).</string>\n    <string name=\"failed_to_use_the_current_mode_of_operation\">Не вдалося використати поточний режим роботи. Повернення до режиму без-root для цього сеансу.</string>\n    <string name=\"failed_to_enable_magisk_deny_list\">Не вдалося ввімкнути Magisk DenyList</string>\n    <string name=\"uses_play_app_signing\">Підпис Play App</string>\n    <string name=\"swap\">Підкачка</string>\n    <string name=\"magisk_denylist\">Magisk DenyList</string>\n    <string name=\"primary_abi\">Головний ABI</string>\n    <string name=\"zygote_preload_name\">Назва підвантаження Zygote</string>\n    <string name=\"hidden_api_enforcement_policy\">Політика контролю прихованого API</string>\n    <string name=\"hidden_api_enf_default_policy\">За замовчуванням (залежно від типу додатку)</string>\n    <string name=\"hidden_api_enf_policy_none\">Вимкнено (повний доступ до прихованого API)</string>\n    <string name=\"hidden_api_enf_policy_warn\">М\\'яко (повний доступ до прихованого API з попередженнями)</string>\n    <string name=\"hidden_api_enf_policy_black\">Строго (лише списки блокування)</string>\n    <string name=\"binary_32_bit\">32 біти</string>\n    <string name=\"binary_64_bit\">64 біти</string>\n    <string name=\"endianness_little_endian\">Від молодшого (LE)</string>\n    <string name=\"endianness_big_endian\">Від старшого (BE)</string>\n    <string name=\"so_type_shared_library\">Спільна бібліотека</string>\n    <string name=\"so_type_executable\">Виконуваний файл</string>\n    <string name=\"file_modified_are_you_sure\">Файл було змінено. Відкинути всі ваші зміни й вийти\\?</string>\n    <string name=\"save_and_exit\">Зберегти та вийти</string>\n    <string name=\"hidden_api_enf_policy_dark_grey_and_black\">Строго (списки обмеження й блокування)</string>\n    <string name=\"auth_manager_title\">Менеджер авторизації</string>\n    <string name=\"regenerate_auth_key\">Перестворити ключ авторизації</string>\n    <string name=\"regenerate_auth_key_warning\">Точно\\? Всі сторонні додатки доведеться переналаштувати на використання нового ключа авторизації.</string>\n    <string name=\"shortcut_icon\">Значок запуску</string>\n    <string name=\"auth_manager_description\">Щоб запустити Intent зі стороннього додатка, обов\\'язково зазначте додатковим полем <tt>auth</tt> такий ключ:</string>\n    <string name=\"pref_saved_apk_name_format\">Формат назви збережених APK</string>\n    <string name=\"pref_saved_apk_name_format_msg\">Формат, який буде використано для іменування при збереженні APK-файлів.</string>\n    <string name=\"change_backup_volume\">Змінити том</string>\n    <string name=\"external\">Зовнішній</string>\n    <string name=\"internal\">Внутрішній</string>\n    <string name=\"tracker\">Трекер</string>\n    <string name=\"input_ssaid_instruction\">SSAID — це %1$d-байтне шістнадцяткове число, тобто %2$d-символьний рядок із цифр від 0 до 9 та/або літер від a до f.</string>\n    <string name=\"sort_by_installation_date\">Дата встановлення</string>\n    <string name=\"backup_volume_unavailable_warning\">Обраний том резервного копіювання наразі недоступний. Якщо його розміщено в зовнішньому сховищі, будь ласка, під\\'єднайте це сховище чи оберіть інший том резервного копіювання.</string>\n    <string name=\"screen_time\">Екранний час</string>\n    <string name=\"open_in_new_window\">Нове вікно</string>\n    <string name=\"type_string_set\">Набір рядків</string>\n    <string name=\"vt_confirm_uploading_file\">Файл не знайдено в базі даних VirusTotal. Ви хочете його завантажити\\?</string>\n    <string name=\"vt_confirm_upload_and_scan\">Так, завантажити та сканувати</string>\n    <string name=\"pref_vt_prompt_before_uploading\">Відобразити запит перед завантаженням файлу.</string>\n    <string name=\"log_stop_recording\">Зупинити записування</string>\n    <string name=\"apk_checksums\">Контрольні суми APK</string>\n    <string name=\"item_select\">Обрати</string>\n    <string name=\"app_explorer\">Дослідження додатків</string>\n    <string name=\"netpolicy_cannot_be_modified_for_core_apps\">Неможливо змінити мережеву політику системних додатків Android.</string>\n    <string name=\"pref_pure_black_theme\">Цілковито чорна тема</string>\n    <string name=\"pref_pure_black_theme_msg\">Використовувати повністю чорне тло, коли ввімкнено нічний режим.</string>\n    <string name=\"open_developer_options_page\">Відкрийте сторінку параметрів розробника в налаштуваннях Android</string>\n    <string name=\"usage_times_opened\">Кількість відкривань</string>\n    <string name=\"usage_last_used\">Останнє використання</string>\n    <string name=\"usage_mobile_data\">Мобільні дані</string>\n    <string name=\"usage_wifi_data\">Дані Wi-Fi</string>\n    <string name=\"backup_no_backups_present\">Немає запасних копій.</string>\n    <string name=\"restore_dots\">Відновити…</string>\n    <string name=\"backup_apps_cannot_be_restored\">Наступні додатки неможливо відновити, оскільки вони не мають основної резервної копії:</string>\n    <string name=\"backup_apps_cannot_be_backed_up\">Наступні додатки не встановлені, тому неможливо створити їх резервну копію:</string>\n    <string name=\"restart_device\">Перезапустити пристрій</string>\n    <string name=\"import_backups_warning_delete_backups_after_import\">Видалити запасні копії після їх імпорту у App Manager\\? Кожна запасна копія видаляється окремо після її успішного імпорту. Виберіть <b>Ні</b>, якщо не впевнені.</string>\n    <string name=\"frozen\">Заморожено</string>\n    <string name=\"freeze\">Заморозити</string>\n    <string name=\"unfreeze\">Розморозити</string>\n    <string name=\"troubleshooting\">Вирішення проблем</string>\n    <string name=\"changelog_type_new\">Нове</string>\n    <string name=\"changelog_type_fix\">Виправлення</string>\n    <string name=\"changelog_type_improve\">Поліпшення</string>\n    <string name=\"pref_reload_apps\">Перезавантажити додатки</string>\n    <string name=\"pref_reload_apps_msg\">Перезавантажувати список додатків, що зберігаються в базі даних App Manager, у разі неочікуваної поведінки.</string>\n    <string name=\"unsupported_split_apk\">Не підтримується</string>\n    <string name=\"view_changelog\">Дізнайтеся, що нового в цьому випуску</string>\n    <string name=\"sort_by_total_size\">Загальний розмір</string>\n    <string name=\"am_command\"><tt>am</tt> команда</string>\n    <string name=\"pref_sign_apk_no_signing_key\">Немає ключа підписання</string>\n    <string name=\"pref_sign_apk_error_signing_key_not_added\">Для підписання APK-файлу необхідний прийнятний ключ підпису.</string>\n    <string name=\"suspend_app\">Призупинити</string>\n    <string name=\"hide_app\">Приховати</string>\n    <string name=\"failed_to_unfreeze\">Не вдалося розморозити <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g>.</string>\n    <string name=\"failed_to_freeze\">Не вдалося заморозити <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g>.</string>\n    <string name=\"pref_default_freezing_method\">Спосіб заморозки за замовчуванням</string>\n    <string name=\"pref_default_freezing_method_description\">Спосіб котрий буде використано за замовчуванням в місцях, де немає можливості вибрати метод заморозки.</string>\n    <plurals name=\"alert_failed_to_freeze\">\n        <item quantity=\"one\">Не вдалося заморозити %1$d додаток</item>\n        <item quantity=\"few\">Не вдалося заморозити %1$d додатки</item>\n        <item quantity=\"many\">Не вдалося заморозити %1$d додатків</item>\n        <item quantity=\"other\">Не вдалося заморозити %1$d додатків</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_unfreeze\">\n        <item quantity=\"one\">Не вдалося розморозити %1$d додаток</item>\n        <item quantity=\"few\">Не вдалося розморозити %1$d додатки</item>\n        <item quantity=\"many\">Не вдалося розморозити %1$d додатків</item>\n        <item quantity=\"other\">Не вдалося розморозити %1$d додатків</item>\n    </plurals>\n    <string name=\"disable_app_description\">Рекомендований спосіб заморозки. Він відключає додаток разом з усіма його компонентами, але всі ярлики будуть втрачені.</string>\n    <string name=\"pref_appearance_description\">Тема, орієнтація, особливості тощо.</string>\n    <string name=\"freeze_unfreeze\">Заморозка/розморозка</string>\n    <string name=\"profile_freeze_msg\">Заморозка або розморозка додатку, в залежності від стану</string>\n    <string name=\"suspend_app_description\">Це найслабший метод заморозки. Призупинений додаток все ще може відображатися в панелі запуску, але він буде виділений сірим кольором і не може бути запущеним.</string>\n    <string name=\"hide_app_description\">Цей метод рекомендується лише для щоденного використання. Прихований додаток виглядає так, ніби його видалено. Але він може з\\'явитися знову, після перевстановлення або оновлення.</string>\n    <string name=\"sort_by_frozen_app\">Спочатку заморожені</string>\n    <string name=\"filter_frozen_apps\">Заморожені програми</string>\n    <string name=\"pref_privacy\">Конфіденційність</string>\n    <string name=\"pref_privacy_description\">Блокування екрану, авторизація тощо.</string>\n    <string name=\"user_manual\">Керівництво користувача</string>\n    <string name=\"get_help\">Отримати допомогу</string>\n    <string name=\"pref_advanced_pref\">Користувачі, формат імені APK, паралельне виконання тощо.</string>\n    <string name=\"pref_version_changelog\">Версія/Журнал змін</string>\n    <string name=\"file_creation_date\">Створено</string>\n    <string name=\"file_modification_date\">Змінено</string>\n    <string name=\"file_accessed_date\">Доступ</string>\n    <string name=\"file_open_with\">Відкрити з</string>\n    <string name=\"file_shortcut_target_file\">Цільовий файл</string>\n    <string name=\"open_as_other\">Інше</string>\n    <string name=\"file_open_with_os_default_dialog\">Відкрити з діалоговим вікном ОС за замовчуванням</string>\n    <string name=\"on_unfreeze_open_application\">Відкрити додаток після розморозки</string>\n    <string name=\"waiting_for_the_phone_to_be_locked\">Очікування блокування телефону…</string>\n    <string name=\"open_as_text\">Текст</string>\n    <string name=\"delete_filename\">Видалити %s</string>\n    <string name=\"file_change_open_with\">Змінити відкрити з</string>\n    <string name=\"file_properties\">Властивості</string>\n    <string name=\"fm_open_with_for_this_file_only\">Тільки для цього файлу</string>\n    <string name=\"file_open_as\">Відкрити як…</string>\n    <string name=\"file_open_with_custom_activity\">Власний</string>\n    <string name=\"open_as_image\">Зображення</string>\n    <string name=\"confirm_file_deletion\">Так, видалити</string>\n    <string name=\"freeze_on_phone_locked\">Автоматично заморожувати додаток, коли телефон заблокований</string>\n    <string name=\"file_cut\">Вирізати</string>\n    <string name=\"fm_always_open_with\">Завжди відкривати</string>\n    <string name=\"open_as_video\">Відео</string>\n    <string name=\"open_as_archive\">Архів</string>\n    <string name=\"open_as_folder\">Папка</string>\n    <string name=\"on_open_application_no_recents\">Не показувати запущений додаток в Недавніх</string>\n    <string name=\"tap_to_freeze_app\">Торкніться, щоб заморозити</string>\n    <string name=\"action_stop_service\">Стоп</string>\n    <string name=\"sort_by_data_usage\">Використання даних</string>\n    <string name=\"grant_overlay_permission_message\">Дозволити App Manager показувати плаваюче вікно поверх всіх інших вікон</string>\n    <string name=\"grant_accessibility_permission_for_tracking_window_contents\">Дозволити App Manager використовувати функцію спеціальних можливостей для відстеження вмісту головного вікна.</string>\n    <string name=\"class_hierarchy\">Ієрархія</string>\n    <string name=\"title_ui_tracker\">UI трекер</string>\n    <string name=\"title_terminal_emulator\">Термінал</string>\n    <string name=\"title_labs_activity\">Лабораторія</string>\n    <string name=\"app_manager_build_expiring_soon_warning\">Термін дії цієї версії App Manager дуже скоро закінчиться. Оновіть додаток до останньої версії.</string>\n    <string name=\"renamed_successfully\">Перейменовано</string>\n    <string name=\"selinux_context\">Контекст SELinux</string>\n    <string name=\"unix_file_permissions\">Режим</string>\n    <string name=\"file_group_id\">Група (GID)</string>\n    <string name=\"file_owner_id\">Власник (UID)</string>\n    <string name=\"calculating_file_size\">Розрахунок…</string>\n    <string name=\"sort_by_filename\">Ім’я</string>\n    <string name=\"sort_by_last_modified\">Востаннє змінено</string>\n    <string name=\"sort_by_file_size\">Розмір файлу</string>\n    <string name=\"sort_by_file_type\">Тип файлу</string>\n    <string name=\"option_display_dot_files\">Dot файли</string>\n    <string name=\"option_display_folders_on_top\">Папки зверху</string>\n    <string name=\"export_app_list\">Експорт списку додатків</string>\n    <string name=\"export_app_list_select_format\">Виберіть формат для експорту списку додатків</string>\n    <string name=\"export_option_xml\">XML</string>\n    <string name=\"export_option_markdown\">Markdown</string>\n    <string name=\"funding_campaign_text\">Ми проводимо <b>кампанію фінансування</b> App Manager протягом обмеженого періоду. <a href=\"https://opencollective.com/app-manager#category-ABOUT\">дізнатися більше…</a></string>\n    <string name=\"adb_incomplete_usb_debugging_title\">Незавершене налагодження USB</string>\n    <string name=\"app_manager_build_expired_message\">Для забезпечення безпеки вашого пристрою та даних, версія App Manager, якою ви користуєтеся, знята з експлуатації. Вам потрібно оновити його до останньої версії, щоб продовжити використання, або видалити його, якщо оновлення недоступне.</string>\n    <string name=\"app_can_write_and_execute_in_same_place\">Додаток порушує <a href=\"https://en.wikipedia.org/wiki/W%5EX\">політику W^X</a> і може проводити запис та виконання в тому самому каталозі або в тій самій частині пам\\'яті. Це дозволяє виконувати довільні виконувані файли шляхом модифікації виконуваних файлів, вбудованих у програму, або шляхом їх завантаження з Інтернету. Якщо це не передбачена поведінка програми (наприклад, емулятори терміналу), рекомендується знайти новішу версію програми, яка націлена на SDK 29 (Android 10) і пізніших, або знайти альтернативи.</string>\n    <string name=\"funding_campaign_dialog_message\">Ми проводимо <b>кампанію фінансування</b> App Manager протягом обмеженого періоду. Перейдіть на сторінку<a href=\"https://opencollective.com/app-manager#category-ABOUT\"> opencollective.com/app-manager</a>, щоб дізнатися більше про кампанію. Це сповіщення більше не відображатиметься, але ви можете знайти його на сторінці налаштувань протягом усієї кампанії.</string>\n    <string name=\"app_manager_build_expired\">Потрібне оновлення</string>\n    <string name=\"filter_apps_with_saf\">З SAF</string>\n    <string name=\"filter_apps_with_ssaid\">З SSAID</string>\n    <string name=\"action_continue\">Продовжити</string>\n    <string name=\"confirm_uninstallation\">Підтвердити видалення</string>\n    <string name=\"adb_incomplete_usb_debugging_message\">Схоже, налагодження USB налаштовано неправильно. Будь ласка<a href=\"https://muntashirakon.github.io/AppManager/#subsec:enable-usb-debugging\">, ознайомтеся з документацією</a> для додаткових кроків. Якщо ви вже знаєте кроки, натисніть \\\"Відкрити\\\", щоб відкрити параметри розробника, або натисніть \\\"Закрити\\\", щоб продовжити використовувати режим без root-прав.</string>\n    <string name=\"filter_apps_with_keystore\">З сховищем ключів</string>\n    <string name=\"install_for_another_user\">Встановити для…</string>\n    <string name=\"grant_required_permission\">Надати необхідний дозвіл</string>\n    <string name=\"optimize_option_clear_profile_data\">Очистка даних попереднього профілю</string>\n    <string name=\"select_a_dex2oat_compiler_filter\">Фільтр компілятора <tt>dex2oat</tt></string>\n    <string name=\"optimize_option_compile_layouts\">Компіляція ресурсів макета</string>\n    <string name=\"optimize_option_check_profiles\">Враховувати дані профілю під час оптимізації DEX</string>\n    <string name=\"optimize_option_force_compilation\">Примусова компіляція, навіть якщо вона не потрібна</string>\n    <string name=\"optimize_option_force_dexopt\">Негайне виконання оптимізації DEX</string>\n    <string name=\"title_perform_runtime_optimization_to_apps\">Виконати оптимізацію середовища виконання</string>\n    <string name=\"action_run\">Старт</string>\n    <plurals name=\"alert_failed_to_optimize_apps\">\n        <item quantity=\"one\">Не вдалося оптимізувати %1$d додаток</item>\n        <item quantity=\"few\">Не вдалося оптимізувати %1$d додатки</item>\n        <item quantity=\"many\">Не вдалося оптимізувати %1$d додатків</item>\n        <item quantity=\"other\">Не вдалося оптимізувати %1$d додатків</item>\n    </plurals>\n    <string name=\"action_optimize_app\">Оптимізувати</string>\n    <string name=\"batch_ops_runtime_optimization\">Оптимізація середовища виконання</string>\n    <string name=\"summary_perform_runtime_optimization_to_apps\">Оптимізація DEX і (в Android 10 і пізніших версіях) макетів, щоб підвищити продуктивність роботи додатків.</string>\n    <string name=\"app_info_tag_open_links\">Відкриті посилання</string>\n    <string name=\"source_stamp_verified_and_identified_to_be_from_source\">SourceStamp перевірено та ідентифіковано як джерело з <xliff:g id=\"source\" example=\"Google Play\">%1$s</xliff:g> .</string>\n    <string name=\"unblock_components_dots\">Розблокувати компоненти…</string>\n    <string name=\"pref_zip_align\">Вирівняти APK файли</string>\n    <string name=\"title_code_editor\">Редактор коду</string>\n    <string name=\"read_only_file\">Файл тільки для читання</string>\n    <string name=\"line_separator\">Роздільник рядків</string>\n    <string name=\"replacement_text\">Заміна</string>\n    <string name=\"action_replace_all\">Замінити все</string>\n    <string name=\"search_option_match_case\">З урахуванням регістру</string>\n    <string name=\"search_option_whole_word\">Ціле слово</string>\n    <string name=\"search_option_regex\">регулярний вираз</string>\n    <string name=\"system_app_put_back\">Повернути назад</string>\n    <string name=\"debloat_list_carrier\">Оператор/провайдер</string>\n    <string name=\"debloat_list_misc\">Різне</string>\n    <string name=\"debloat_removal_caution\">З обережністю</string>\n    <plurals name=\"alert_failed_to_unblock_components\">\n        <item quantity=\"one\">Не вдалося розблокувати компоненти %1$d додатку</item>\n        <item quantity=\"few\">Не вдалося розблокувати компоненти %1$d додатків</item>\n        <item quantity=\"many\">Не вдалося розблокувати компоненти %1$d додатків</item>\n        <item quantity=\"other\">Не вдалося розблокувати компоненти %1$d додатків</item>\n    </plurals>\n    <plurals name=\"search_results\">\n        <item quantity=\"one\">%d результат</item>\n        <item quantity=\"few\">%d результатів</item>\n        <item quantity=\"many\">%d результатів</item>\n        <item quantity=\"other\">%d результатів</item>\n    </plurals>\n    <string name=\"uninstall_app\">Видалити %1$s</string>\n    <string name=\"uninstall_app_again_message\">Додаток було видалено без очищення даних і підпису. Ви хочете повністю видалити його\\?</string>\n    <string name=\"debloat_removal_type\">Тип</string>\n    <string name=\"block_unblock_components_dots\">Блокування/розблокування компонентів…</string>\n    <string name=\"block_unblock_components_description\">Заблокувати або розблокувати всі компоненти, визначені наданими підписами</string>\n    <string name=\"pref_layout_direction\">Напрямок макета</string>\n    <string name=\"title_domains_supported_by_the_app\">Підтримувані домени</string>\n    <string name=\"debloat_list_type\">Список</string>\n    <string name=\"debloat_removal_safe\">Безпечно</string>\n    <string name=\"debloat_removal_replace\">Заміна</string>\n    <string name=\"static_shared_library\">Статична спільна бібліотека</string>\n    <string name=\"redo\">Повторити</string>\n    <string name=\"read_only_file_warning\">Зміни не можуть бути записані до файлу, можливо, тому що він знаходиться в томі, на який App Manager не має дозволу на запис. Ви хочете зберегти його в іншому місці\\?</string>\n    <string name=\"pref_zip_align_msg\">Вирівнювання APK-файлу зменшує використання пам\\'яті, оскільки до файлів APK можна звертатися безпосередньо, без копіювання даних до оперативної пам\\'яті. Цей крок обовʼязковий, якщо для параметра <tt>extractNativeLibs</tt> встановлено значення <tt>true</tt>.</string>\n    <plurals name=\"folder_count\">\n        <item quantity=\"one\">%d папка</item>\n        <item quantity=\"few\">%d папки</item>\n        <item quantity=\"many\">%d папок</item>\n        <item quantity=\"other\">%d папок</item>\n    </plurals>\n    <plurals name=\"file_count\">\n        <item quantity=\"one\">%d файл</item>\n        <item quantity=\"few\">%d файли</item>\n        <item quantity=\"many\">%d файлів</item>\n        <item quantity=\"other\">%d файлів</item>\n    </plurals>\n    <string name=\"filter_force_stopped_apps\">Зупинені додатки</string>\n    <string name=\"empty_folder\">Порожньо</string>\n    <string name=\"go_to_path\">Перейти до…</string>\n    <string name=\"copy_this_path\">Скопіювати шлях</string>\n    <string name=\"title_audio_player\">Аудіоплеєр</string>\n    <string name=\"debloater_title\">Debloater</string>\n    <string name=\"warning_working_on_system_mode\">Попередження: робота в системному режимі замість режиму ADB.</string>\n    <string name=\"installing_package\">Встановлення %1$s…</string>\n    <string name=\"backing_up_app\">Резервне копіювання %1$s…</string>\n    <string name=\"restoring_app\">Відновлення %1$s…</string>\n    <string name=\"pref_installer_force_dexopt_description\">Виконувати DEX-оптимізацію відразу після встановлення програми, не чекаючи, поки система зробить це, під час простою.</string>\n    <string name=\"folder\">Папка</string>\n    <string name=\"symbolic_link\">Символічне посилання</string>\n    <string name=\"create_new_symbolic_link\">Нове символічне посилання</string>\n    <string name=\"symbolic_link_not_supported\">Ця папка не підтримує створення символічного посилання.</string>\n    <string name=\"create_new_file\">Новий файл</string>\n    <string name=\"enter_symbolic_link_name\">Назва посилання</string>\n    <string name=\"enter_target_path\">Цільовий шлях</string>\n    <string name=\"copy_these_paths\">Скопіювати шляхи</string>\n    <string name=\"conflict_detected_while_copying\">Виявлено конфлікт</string>\n    <string name=\"copy_keep_both_file\">Зберегти обидва</string>\n    <string name=\"copied_successfully\">Скопійовано.</string>\n    <string name=\"moved_successfully\">Переміщено</string>\n    <string name=\"title_change_selinux_context\">Зміна контексту SELinux</string>\n    <string name=\"change_owner_uid\">Зміна власника (UID)</string>\n    <string name=\"change_group_gid\">Зміна групи (GID)</string>\n    <string name=\"change_mode\">Змінити режим</string>\n    <string name=\"apply_recursively\">Застосувати до вкладених файлів</string>\n    <string name=\"create_new_folder\">Нова папка</string>\n    <string name=\"invalid_target_path\">Недійсний шлях</string>\n    <string name=\"failed_to_copy_specified_file\">Не вдалося скопіювати \\\"%1$s\\\".</string>\n    <string name=\"title_confirm_deletion\">Підтвердити видалення</string>\n    <string name=\"conflict_detected_while_copying_message\">Елемент з назвою \\\"%1$s\\\" вже існує у цьому місці. Хочете замінити його\\?</string>\n    <string name=\"failed_to_delete_specified_file_after_copying\">Не вдалося видалити \\\"%1$s\\\" після копіювання, можливо, через недостатній дозвіл.</string>\n    <string name=\"pref_send_notifications_to_connected_devices\">Надіслати повідомлення на підключені пристрої</string>\n    <string name=\"pref_send_notification_to_connected_devices_msg\">Встановіть, чи надсилати сповіщення на підключені пристрої, наприклад переносні пристрої.</string>\n</resources>"
  },
  {
    "path": "app/src/main/res/values-v31/styles.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<resources>\n\n    <style name=\"AppTheme.AppWidgetContainerParent\" parent=\"@android:style/Theme.DeviceDefault.DayNight\">\n        <item name=\"appWidgetRadius\">@android:dimen/system_app_widget_background_radius</item>\n        <item name=\"appWidgetPadding\">16dp</item>\n        <item name=\"appWidgetInnerRadius\">@android:dimen/system_app_widget_inner_radius</item>\n    </style>\n\n    <style name=\"Widget.AppTheme.AppWidget\" parent=\"Widget.AppTheme.AppWidgetOverlay\">\n        <item name=\"android:clipToOutline\">true</item>\n    </style>\n\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-vi/disclaimer.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- SPDX-License-Identifier: GPL-3.0-or-later --><resources>\n    <string name=\"disclaimer_footer\">© 2020–2024 Muntashir Al-Islam</string>\n    <string name=\"disclaimer_body\">Trình quản lý ứng dụng cung cấp các chức năng root có thể gây hại cho thiết bị của bạn nếu sử dụng không đúng cách. Trình quản lý ứng dụng không chịu trách nhiệm về bất kỳ thiệt hại nào do sử dụng ứng dụng này. Nếu bạn không nhận thức đầy đủ về cách thức hoạt động của root thì bạn nên tránh sử dụng các tùy chọn root cho đến khi bạn nhận thức đầy đủ về các rủi ro.\n\\n\n\\nBất kỳ liên kết nào tôi cung cấp cho các ứng dụng và trang web khác đều vì lợi ích của người dùng. Tôi không chịu trách nhiệm về bất kỳ nội dung nào bạn có thể tìm thấy bằng cách truy cập vào các liên kết bên ngoài.\n\\n\n\\nBằng cách sử dụng Trình quản lý ứng dụng, bạn chấp nhận hoàn toàn trách nhiệm về việc sử dụng của mình và không chấp nhận thiệt hại, khiếu nại hoặc giá trị tiền tệ sẽ được đưa ra do sử dụng sai mục đích.\n\\n\n\\nBằng cách sử dụng ứng dụng này, bạn chấp nhận mọi trách nhiệm khi sử dụng nó và đồng ý rằng tôi không chịu trách nhiệm về bất kỳ hành động nào bạn thực hiện có ảnh hưởng xấu đến thiết bị của bạn.</string>\n    <string name=\"disclaimer_exit\">Thoát</string>\n    <string name=\"disclaimer_agree\">Tôi đồng ý</string>\n    <string name=\"disclaimer_agree_forever\">Không bao giờ hiển thị cái này nữa</string>\n    <string name=\"disclaimer_header\">Từ chối trách nhiệm</string>\n</resources>"
  },
  {
    "path": "app/src/main/res/values-vi/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- SPDX-License-Identifier: GPL-3.0-or-later --><resources xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:tools=\"http://schemas.android.com/tools\">\n    <string name=\"_lang_tag\" translatable=\"false\">vi</string>\n    <string name=\"path_permissions\">Quyền đường dẫn</string>\n    <string name=\"grant_uri_permission\">Cấp quyền cho URI</string>\n    <string name=\"flags\">Cờ</string>\n    <string name=\"soft_input\">Chế độ đầu vào mềm</string>\n    <string name=\"orientation\">Sự định hướng</string>\n    <string name=\"no_service\">Không có dịch vụ</string>\n    <string name=\"service\">Dịch vụ</string>\n    <string name=\"authority\">Thẩm quyền</string>\n    <string name=\"sort_by_last_update\">Cập nhật cuối cùng</string>\n    <string name=\"task_affinity\">Mối quan hệ công việc</string>\n    <string name=\"launch_mode\">Chế độ khởi chạy</string>\n    <string name=\"no_providers\">Không có nhà cung cấp</string>\n    <string name=\"providers\">Nhà cung cấp</string>\n    <string name=\"no_receivers\">Không có người nhận</string>\n    <string name=\"receivers\">Người nhận</string>\n    <string name=\"no_activities\">Không có hoạt động</string>\n    <string name=\"refresh\">Làm mới</string>\n    <string name=\"launch\">Khởi chạy</string>\n    <string name=\"activities\">Hoạt động</string>\n    <string name=\"require_no_permission\">Không yêu cầu quyền</string>\n    <string name=\"permissions\">Sử dụng quyền</string>\n    <string name=\"uninstall\">Gỡ cài đặt</string>\n    <string name=\"configurations\">Cấu hình</string>\n    <string name=\"app_signing_no_signatures\">Không có chữ ký hợp lệ</string>\n    <string name=\"signatures\">Chữ ký</string>\n    <string name=\"sort_by_sha\">Chữ ký</string>\n    <string name=\"shared_user_id\">ID người dùng được chia sẻ</string>\n    <string name=\"sort_by_shared_user_id\">ID người dùng được chia sẻ</string>\n    <string name=\"no_feature\">Không có tính năng</string>\n    <string name=\"uses_feature\">Sử dụng các tính năng</string>\n    <string name=\"group\">Nhóm</string>\n    <string name=\"shared_libs\">Lib được chia sẻ</string>\n    <string name=\"declared_permission\">Quyền</string>\n    <string name=\"patterns_allowed\">Các mẫu được phép</string>\n    <string name=\"write\">Viết</string>\n    <string name=\"read\">Đọc</string>\n    <string name=\"filter_apps_without_backups\">Không có bản sao lưu</string>\n    <string name=\"uninstalled_apps\">Các ứng dụng đã gỡ cài đặt</string>\n    <string name=\"specify_custom_name\">Tuỳ chỉnh</string>\n    <string name=\"list_options\">Liệt kê các tùy chọn</string>\n    <string name=\"reverse\">Đảo ngược</string>\n    <string name=\"os_version\">Phiên bản HĐH</string>\n    <string name=\"enable_disable_features\">Bật/tắt các tính năng</string>\n    <string name=\"working_on_adb_mode\">Đang hoạt động trong chế độ ADB</string>\n    <string name=\"screen_lock_not_enabled\">Vui lòng chọn một khóa màn hình trong thiết đặt Android hoặc dọn dẹp dữ liệu ứng dụng.</string>\n    <string name=\"isolated\">Bị cô lập</string>\n    <string name=\"installed_apps\">Các ứng dụng đã cài đặt</string>\n    <string name=\"restart_to_reflect_changes\">Bạn phải khởi động lại thiết bị ngay lập tức để sử dụng các thay đổi mới.</string>\n    <string name=\"failed_to_change_ssaid\">Không thể thay đổi SSAID</string>\n    <string name=\"copied_to_clipboard\">Đã sao chép vào bộ nhớ.</string>\n    <string name=\"icon_picker\">Trình chọn biểu tượng</string>\n    <string name=\"package_name\">Tên gói</string>\n    <string name=\"shortcut_name\">Tên lối tắt</string>\n    <string name=\"create_shortcut\">Tạo lối tắt</string>\n    <string name=\"license\">Giấy phép</string>\n    <string name=\"date_updated\">Ngày cập nhật</string>\n    <string name=\"date_installed\">Ngày cài đặt</string>\n    <string name=\"more_info\">Thêm thông tin</string>\n    <string name=\"error_creating_shortcut\">Lỗi khi tạo lối tắt</string>\n    <string name=\"user_app\">Ứng dụng người dùng</string>\n    <string name=\"system_app\">Ứng dụng hệ thống</string>\n    <string name=\"app_info\">Thông tin ứng dụng</string>\n    <string name=\"user\">Người dùng</string>\n    <string name=\"system\">Hệ thống</string>\n    <string name=\"app_not_installed\">Ứng dụng không được cài đặt</string>\n    <string name=\"reset_to_default\">Đặt lại về mặc định</string>\n    <string name=\"deny_dangerous_app_ops\">Từ chối hoạt động ứng dụng nguy hiểm</string>\n    <string name=\"sort_by_app_ops_names\">Tên hoạt động ứng dụng</string>\n    <string name=\"sort_by_denied_app_ops\">Bị từ chối trước</string>\n    <string name=\"sort_by_app_ops_values\">Giá trị hoạt động ứng dụng</string>\n    <string name=\"sort_by_permission_names\">Tên quyền</string>\n    <string name=\"sort_by_dangerous_permissions\">Nguy hiểm trước</string>\n    <string name=\"sort_by_denied_permissions\">Bị từ chối trước</string>\n    <string name=\"deny_dangerous_permissions\">Từ chối các quyền nguy hiểm</string>\n    <string name=\"sort_by_tracker_components\">Trình theo dõi trước</string>\n    <string name=\"unknown_op\">Hoạt động không xác định</string>\n    <plurals name=\"alert_failed_to_disable_trackers\">\n        <item quantity=\"other\">Không thể vô hiệu hóa trình theo dõi từ ứng dụng %1$d</item>\n    </plurals>\n    <string name=\"failed_to_grant_permission\">Không thể cấp quyền</string>\n    <string name=\"no_configurations\">Không có cấu hình</string>\n    <string name=\"input_features\">Các tính năng nhập vào</string>\n    <string name=\"sort_by_target_sdk\">SDK mục tiêu</string>\n    <string name=\"data_usage_msg\">Sử dụng dữ liệu</string>\n    <string name=\"data_transmitted\">Dữ liệu đã truyền đi</string>\n    <string name=\"data_received\">Dữ liệu đã nhận</string>\n    <string name=\"error_verbose_pin_shortcut\">Launcher hiện tại không hỗ trợ PinShortcut. Không thể tạo lối tắt.</string>\n    <string name=\"empty_package_name\">Tên gói trống</string>\n    <string name=\"main_activity\">Hoạt động chính</string>\n    <string name=\"user_id\">ID người dùng</string>\n    <string name=\"installer_app\">Ứng dụng cài đặt</string>\n    <string name=\"sdk_flags\">Cờ</string>\n    <string name=\"sdk_max\">Mục tiêu</string>\n    <string name=\"sdk_min\">Thấp nhất</string>\n    <string name=\"filter_running_apps\">Ứng dụng đang chạy</string>\n    <string name=\"trackers\">Trình theo dõi</string>\n    <string name=\"installed_version\">Phiên bản đã cài đặt</string>\n    <string name=\"select_all\">Chọn tất cả</string>\n    <string name=\"security\">Bảo mật</string>\n    <string name=\"battery\">Pin</string>\n    <string name=\"encrypted\">Đã mã hoá</string>\n    <string name=\"no_matching_package_found\">Không thể tìm thấy bất kỳ ứng dụng nào như vậy</string>\n    <string name=\"block_unblock_trackers\">Chặn/bỏ chặn trình theo dõi</string>\n    <string name=\"unblock\">Bỏ chặn</string>\n    <string name=\"block\">Chặn</string>\n    <string name=\"one_click_ops\">Hoạt động một chạm</string>\n    <string name=\"never_ask\">Không bao giờ hỏi</string>\n    <string name=\"simple\">Đơn giản</string>\n    <string name=\"add\">Thêm</string>\n    <string name=\"the_operation_was_successful\">Đã xong</string>\n    <plurals name=\"alert_failed_to_disable_background\">\n        <item quantity=\"other\">Không thể ngăn chặn %1$d ứng dụng chạy trong nền</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_uninstall\">\n        <item quantity=\"other\">Không thể gỡ cài đặt %1$d ứng dụng</item>\n    </plurals>\n    <string name=\"copy\">Sao chép</string>\n    <string name=\"close\">Đóng</string>\n    <string name=\"no_root\">Không có root</string>\n    <string name=\"root\">Root</string>\n    <string name=\"user_profile_with_id\">Cấu hình: %1$s (%2$d)</string>\n    <string name=\"advanced\">Nâng cao</string>\n    <string name=\"enabled\">Đã bật</string>\n    <string name=\"choose\">Chọn</string>\n    <string name=\"clear_data_from_uninstalled_apps\">Dọn dữ liệu khỏi các ứng dụng đã gỡ cài đặt</string>\n    <string name=\"users\">Người dùng</string>\n    <string name=\"languages\">Ngôn ngữ</string>\n    <string name=\"manufacturer\">Nhà sản xuất</string>\n    <string name=\"magisk_hide_enabled\">MagiskHide</string>\n    <string name=\"string_value\">Giá trị xâu</string>\n    <string name=\"saving_failed\">Lưu thất bại, hãy thử lại.</string>\n    <string name=\"saved_successfully\">Đã lưu</string>\n    <string name=\"deletion_failed\">Xóa không được</string>\n    <string name=\"deleted_successfully\">Đã xoá</string>\n    <string name=\"delete\">Xóa</string>\n    <string name=\"backup_restore\">Sao lưu/Khôi phục</string>\n    <string name=\"sort_by_wifi_data\">Dữ liệu Wi-Fi</string>\n    <string name=\"state_unknown\">Chưa biết</string>\n    <string name=\"state_waking\">Đang thức giấc</string>\n    <string name=\"state_dead\">Đã chết</string>\n    <string name=\"state_device_io\">I/O Thiết bị</string>\n    <string name=\"state_sleeping\">Đang ngủ</string>\n    <string name=\"state_locked_memory\">Bộ nhớ bị khoá</string>\n    <string name=\"state_low_priority\">Ưu tiên thấp</string>\n    <string name=\"state_high_priority\">Ưu tiên cao</string>\n    <string name=\"failed_to_stop\">Không thể dừng <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g>.</string>\n    <string name=\"force_stop\">Buộc dừng</string>\n    <string name=\"enable\">Bật</string>\n    <string name=\"disable\">Tắt</string>\n    <string name=\"stopped\">Đã dừng</string>\n    <string name=\"termux\">Termux</string>\n    <plurals name=\"alert_failed_to_force_stop\">\n        <item quantity=\"other\">Không thể buộc dừng %1$d ứng dụng</item>\n    </plurals>\n    <string name=\"version_name_with_code\">Phiên bản <xliff:g id=\"version_name\" example=\"2.5.17\">%1$s</xliff:g> (<xliff:g id=\"version_code\" example=\"365\">%2$d</xliff:g>)</string>\n    <string name=\"sort\">Sắp xếp</string>\n    <string name=\"obb_size\">Obb</string>\n    <string name=\"cache_size\">Bộ nhớ đệm</string>\n    <string name=\"data_size\">Dữ liệu</string>\n    <string name=\"about\">Giới thiệu</string>\n    <string name=\"error\">Lỗi</string>\n    <string name=\"sort_by_domain\">Ứng dụng người dùng trước</string>\n    <string name=\"sort_by_package_name\">Tên gói</string>\n    <string name=\"sort_by_app_label\">Nhãn ứng dụng</string>\n    <string name=\"loading\">Đang tải…</string>\n    <string name=\"search\">Tìm kiếm</string>\n    <string name=\"menu_apply_rules\">Áp dụng các quy tắc</string>\n    <string name=\"menu_remove_rules\">Loại bỏ các quy tắc</string>\n    <string name=\"failed_to_extract_apk_file\">Không thể trích xuất tệp APK</string>\n    <string name=\"share_apk\">Chia sẻ APK</string>\n    <string name=\"grant_usage_acess_message\">Được sử dụng để hiển thị thông tin sử dụng ứng dụng.</string>\n    <string name=\"grant_usage_access\">Cấp quyền truy cập dữ liệu sử dụng</string>\n    <string name=\"go_back\">Quay lại</string>\n    <string name=\"usage_less_than_a_minute\">Ít hơn một phút</string>\n    <plurals name=\"usage_hours\">\n        <item quantity=\"other\">%1$d tiếng</item>\n    </plurals>\n    <plurals name=\"usage_days\">\n        <item quantity=\"other\">%1$d ngày</item>\n    </plurals>\n    <plurals name=\"usage_months\">\n        <item quantity=\"other\">%1$d tháng</item>\n    </plurals>\n    <string name=\"usage_7_days\">7 ngày cuối</string>\n    <string name=\"usage_today\">Hôm nay</string>\n    <string name=\"usage_weekly\">Hàng tuần</string>\n    <string name=\"app_usage\">Sử dụng ứng dụng</string>\n    <string name=\"no_shared_libs\">Không có thư viện được chia sẻ</string>\n    <plurals name=\"main_list_date_days\">\n        <item quantity=\"other\"><xliff:g id=\"last_update_date\" example=\"20/10/2020\">%1$s</xliff:g><xliff:g id=\"day_no\" example=\"5\">%2$d</xliff:g> ngày</item>\n    </plurals>\n    <string name=\"found_trackers\">Trình theo dõi đã thấy:</string>\n    <string name=\"credits\">Ghi nhận</string>\n    <string name=\"third_party\">Thư viện và biểu tượng bên thứ ba</string>\n    <string name=\"tracker_details\">Chi tiết trình theo dõi</string>\n    <string name=\"version\">Phiên bản</string>\n    <string name=\"pref_about_msg\">Phiên bản App Manager, giấy phép, ghi nhận, v.v.</string>\n    <string name=\"apply\">Áp dụng</string>\n    <string name=\"select_theme\">Chủ đề</string>\n    <string name=\"night\">Đêm</string>\n    <string name=\"day\">Ngày</string>\n    <string name=\"battery_mode\">Chế độ pin</string>\n    <string name=\"follow_system\">Theo hệ thống</string>\n    <string name=\"pref_app_theme\">Chủ đề ứng dụng</string>\n    <string name=\"pref_import_msg\">Nhập các quy tắc chặn đã được xuất trước từ App Manager.</string>\n    <string name=\"pref_export_msg\">Xuất các quy tắc chặn đã thiết lập trong App Manager ra bộ nhớ ngoài.</string>\n    <string name=\"touchscreen\">Màn hình cảm ứng</string>\n    <string name=\"navigation\">Điều hướng</string>\n    <string name=\"keyboard_type\">Loại bàn phím</string>\n    <string name=\"export_failed\">Xuất thất bại!</string>\n    <string name=\"import_failed\">Nhập thất bại!</string>\n    <string name=\"export_options\">Tuỳ chọn xuất</string>\n    <string name=\"import_options\">Tuỳ chọn nhập</string>\n    <string name=\"pref_export\">Xuất</string>\n    <string name=\"pref_import\">Nhập</string>\n    <string name=\"ago\">trước</string>\n    <string name=\"duration\">Thời gian</string>\n    <string name=\"running\">Đang chạy</string>\n    <string name=\"mode\">Chế độ</string>\n    <string name=\"permission_name\">Tên quyền</string>\n    <string name=\"toggle_kill_for_system_apps\">Bật/tắt giết ứng dụng hệ thống</string>\n    <plurals name=\"alert_failed_to_clear_data\">\n        <item quantity=\"other\">Không thể xoá dữ liệu của %1$d ứng dụng</item>\n    </plurals>\n    <string name=\"export_blocking_rules\">Xuất các quy tắc chặn</string>\n    <string name=\"disable_background\">Ngăn chặn hoạt động trong nền</string>\n    <string name=\"clear_data\">Dọn sạch dữ liệu</string>\n    <string name=\"user_and_uid\">Người dùng: <xliff:g id=\"user_name\" example=\"root\">%1$s</xliff:g> (<xliff:g id=\"user_id\" example=\"0\">%2$d</xliff:g>)</string>\n    <string name=\"user_with_id\">Người dùng: <xliff:g id=\"user_id\" example=\"0\">%1$d</xliff:g></string>\n    <string name=\"memory_virtual_memory\">Bộ nhớ: %1$s, bộ nhớ ảo: %2$s</string>\n    <string name=\"pid_and_ppid\">ID tiến trình: %1$d, ID tiến trình mẹ: %2$d</string>\n    <string name=\"disable_background_run\">Ngăn chặn hoạt động trong nền</string>\n    <string name=\"kill_process\">Giết</string>\n    <string name=\"running_apps\">Ứng dụng đang chạy</string>\n    <string name=\"apk_updater\">APK Updater</string>\n    <plurals name=\"failed_to_import_files\">\n        <item quantity=\"other\">Không thể nhập %1$d tệp.</item>\n    </plurals>\n    <string name=\"the_export_was_successful\">Đã xuất</string>\n    <string name=\"the_import_was_successful\">Đã nhập</string>\n    <string name=\"pref_import_blocker\">Nhập từ Blocker</string>\n    <string name=\"pref_import_watt\">Nhập từ Watt</string>\n    <string name=\"pref_import_export_blocking_rules\">Nhập/xuất các quy tắc chặn</string>\n    <string name=\"sort_by_mobile_data\">Dữ liệu di động</string>\n    <string name=\"sort_by_times_opened\">Số lần mở</string>\n    <string name=\"sort_by_screen_time\">Thời gian màn hình</string>\n    <string name=\"sort_by_last_used\">Lần sử dụng cuối</string>\n    <plurals name=\"no_of_times_opened\">\n        <item quantity=\"other\">%1$d lần</item>\n    </plurals>\n    <string name=\"external_multiple_data_dir\">Thư mục dữ liệu ngoài <xliff:g id=\"dir_no\" example=\"1\">%1$d</xliff:g></string>\n    <string name=\"external_data_dir\">Thư mục dữ liệu ngoài</string>\n    <string name=\"sort_by_blocked_components\">Đã chặn trước</string>\n    <string name=\"exodus_link\">Liên kết εxodus</string>\n    <string name=\"usage_yesterday\">Hôm qua</string>\n    <string name=\"app_settings\">Thiết đặt</string>\n    <string name=\"usage_access\">Truy cập dữ liệu sử dụng</string>\n    <string name=\"pref_global_blocking_enabled_msg\">Để cho bạn chặn bất kỳ thành phần nào của bất kỳ ứng dụng nào mà không bật việc chặn cho ứng dụng một cách rõ ràng.</string>\n    <string name=\"pref_global_blocking_enabled\">Chặn thành phần ngay lập tức</string>\n    <string name=\"str_logo\">Logo</string>\n    <string name=\"rules_not_applied\">Các quy tắc không được áp dụng</string>\n    <string name=\"failed_to_disable_op\">Không thể tắt hoạt động ứng dụng được yêu cầu</string>\n    <string name=\"failed_to_enable_op\">Không thể bật hoạt động ứng dụng được yêu cầu</string>\n    <string name=\"no_app_ops\">Không có hoạt động ứng dụng</string>\n    <string name=\"app_ops\">Hoạt động ứng dụng</string>\n    <string name=\"app_size\">Ứng dụng</string>\n    <string name=\"total_size\">Tổng</string>\n    <string name=\"storage_and_cache\">Bộ nhớ và Bộ nhớ đệm</string>\n    <string name=\"uninstall_system_app_message\">Đây là một ứng dụng hệ thống. Bạn có chắc muốn gỡ cài đặt ứng dụng này không\\?</string>\n    <string name=\"failed_to_uninstall\">Không thể gỡ cài đặt <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g>.</string>\n    <string name=\"uninstall_app_message\">Bạn có muốn gỡ cài đặt ứng dụng này không\\?</string>\n    <string name=\"view_in_settings\">Xem trong Thiết đặt</string>\n    <string name=\"no_content\">Không có nội dung</string>\n    <string name=\"disabled_app\">Đã tắt</string>\n    <string name=\"error_evaluating_input\">Không thể đánh giá đầu vào</string>\n    <string name=\"type_string\">Kí tự</string>\n    <string name=\"type_boolean\">Đúng/sai</string>\n    <string name=\"done\">Xong</string>\n    <string name=\"add_item\">Thêm mục</string>\n    <string name=\"select_type\">Chọn một loại</string>\n    <string name=\"discard\">Bỏ</string>\n    <string name=\"save\">Lưu</string>\n    <string name=\"databases\">Cơ sở dữ liệu</string>\n    <string name=\"test_only\">Chỉ thử nghiệm</string>\n    <string name=\"debuggable\">Có thể gỡ lỗi</string>\n    <string name=\"updated_app\">Đã cập nhật</string>\n    <string name=\"no_code\">Không có mã</string>\n    <string name=\"process_name\">Tên tiến trình</string>\n    <string name=\"dev_protected_data_dir\">Thư mục dữ liệu được thiết bị bảo vệ</string>\n    <string name=\"data_dir\">Thư mục dữ liệu</string>\n    <string name=\"source_dir\">Thư mục nguồn</string>\n    <string name=\"paths_and_directories\">Đường dẫn &amp; Thư mục</string>\n    <string name=\"changelog\">Nhật ký thay đổi</string>\n    <string name=\"source_code\">Mã nguồn</string>\n    <string name=\"update\">Cập nhật</string>\n    <string name=\"clear_app_cache\">Dọn sạch bộ nhớ đệm ứng dụng</string>\n    <string name=\"failed_to_parse_some_numbers\">Không thể xử lý một số chữ số</string>\n    <string name=\"filter_apps_with_rules\">Với các quy tắc</string>\n    <string name=\"filter_system_apps\">Ứng dụng hệ thống</string>\n    <string name=\"filter_user_apps\">Ứng dụng người dùng</string>\n    <string name=\"filter\">Lọc</string>\n    <string name=\"blocking_rules\">Quy tắc chặn</string>\n    <string name=\"whats_new\">Có gì mới</string>\n    <string name=\"features\">Tính năng</string>\n    <string name=\"components\">Thành phần</string>\n    <string name=\"backup_options\">Tuỳ chọn sao lưu</string>\n    <string name=\"delete_backup\">Xóa bản sao lưu</string>\n    <string name=\"restore\">Khôi phục</string>\n    <string name=\"backup\">Sao lưu</string>\n    <string name=\"data\">Dữ liệu</string>\n    <string name=\"external_data\">Dữ liệu ngoài</string>\n    <plurals name=\"classes\">\n        <item quantity=\"other\">%1$d lớp</item>\n    </plurals>\n    <plurals name=\"backup_exists_are_you_sure\">\n        <item quantity=\"other\">Nhiều ứng dụng đã có bản sao lưu. Bạn có chắc không\\?</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_set_app_ops\">\n        <item quantity=\"other\">Không thể đặt hoạt động ứng dụng cho %1$d ứng dụng</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_block_components\">\n        <item quantity=\"other\">Không thể chặn thành phần của %1$d ứng dụng</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_unblock_trackers\">\n        <item quantity=\"other\">Không thể bỏ chặn trình theo dõi của %1$d ứng dụng</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_delete_backup\">\n        <item quantity=\"other\">Không thể xoá %1$d bản sao lưu</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_restore\">\n        <item quantity=\"other\">Không thể khôi phục %1$d ứng dụng</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_backup\">\n        <item quantity=\"other\">Không thể sao lưu %1$d ứng dụng</item>\n    </plurals>\n    <plurals name=\"failed_to_backup_some_apk_files\">\n        <item quantity=\"other\">Không thể sao lưu %1$d ứng dụng</item>\n    </plurals>\n    <string name=\"touchscreen_finger\">Ngón tay</string>\n    <string name=\"orientation_sensor\">Cảm biến</string>\n    <string name=\"manifest\">Manifest</string>\n    <string name=\"reject_time\">Thời gian từ chối</string>\n    <string name=\"accept_time\">Thời gian chấp nhận</string>\n    <string name=\"pref_import_export_blocking_rules_msg\">Nhập/xuất các quy tắc, nhập các quy tắc ngoài từ Watt hoặc Blocker.</string>\n    <string name=\"uninstalled_successfully\">Đã gỡ cài đặt <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g>.</string>\n    <string name=\"no_usage_in_this_time_range\">Không có dữ liệu sử dụng trong phạm vi thời gian này</string>\n    <string name=\"no_tracker_class\">Không có class của trình theo dõi</string>\n    <string name=\"all_classes\">Tất cả class</string>\n    <string name=\"tracker_classes\">Các class của trình theo dõi</string>\n    <plurals name=\"other_trackers_and_classes\">\n        <item quantity=\"other\"><xliff:g id=\"tracker_no\" example=\"8\">%1$d</xliff:g> trình theo dõi có <xliff:g id=\"class_no\" example=\"50\">%2$d</xliff:g> class</item>\n    </plurals>\n    <plurals name=\"two_trackers_and_classes\">\n        <item quantity=\"other\">2 trình theo dõi có <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g> class</item>\n    </plurals>\n    <plurals name=\"tracker_and_classes\">\n        <item quantity=\"other\">1 trình theo dõi có <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g> class</item>\n    </plurals>\n    <string name=\"toggle_class_listing\">Bật/tắt danh sách class</string>\n    <string name=\"class_viewer\">Trình xem class</string>\n    <string name=\"class_name\">Tên Class</string>\n    <string name=\"media_size\">Phương tiện</string>\n    <string name=\"input_app_ops_description\">Nhập tên hoạt động ứng dụng và/hoặc hằng số có dấu cách, ví dụ <tt>WAKE_LOCK 63 72 CAMERA</tt> v.v.</string>\n    <string name=\"input_app_ops\">Nhập hoạt động ứng dụng</string>\n    <string name=\"filtered_packages\">Gói đã lọc</string>\n    <string name=\"input_signatures_description\">Nhập các chữ ký có dấu cách, ví dụ <tt>com.facebook org.app2 com.app3</tt> v.v.</string>\n    <string name=\"input_signatures\">Nhập chữ ký</string>\n    <string name=\"failed_packages\">Gói thất bại</string>\n    <string name=\"no_tracker_found\">Không tìm thấy trình theo dõi nào</string>\n    <string name=\"clear_app_cache_description\">Dọn sạch bộ nhớ đệm của mọi ứng dụng</string>\n    <string name=\"credits_message\">Gửi các tác giả của\n\\n- Dự án mã nguồn mở Android\n\\n- <a href=\"https://github.com/zhaobozhen/libraries\">Absinthe\\'s libraries</a>\n\\n- <a href=\"https://github.com/butzist/ActivityLauncher\">Activity Launcher</a>\n\\n- <a href=\"https://bitbucket.org/oF2pks/fdroid-applications-info\">Apps_packages Info</a>\n\\n- <a href=\"https://github.com/zhaobao/AppsMonitor\">AppsMonitor</a>\n\\n- <a href=\"https://github.com/8enet/AppOpsX\">AppOpsX</a>\n\\n- <a href=\"https://github.com/gabrielemariotti/changeloglib\">ChangeLog Library</a>\n\\n- <a href=\"https://bitbucket.org/oF2pks/fdroid-classyshark3xodus\">ClassySharkAndroid</a>\n\\n- <a href=\"https://github.com/billthefarmer/editor\">Editor</a>\n\\n- <a href=\"https://github.com/Raival-e/File-Explorer\">File Explorer</a>\n\\n- <a href=\"https://github.com/nex3z/FlowLayout\">FlowLayout</a>\n\\n- <a href=\"https://github.com/k3b/intent-intercept\">Intent Intercept</a>\n\\n- <a href=\"https://github.com/YarikSOffice/lingver\">Lingver</a>\n\\n- <a href=\"https://github.com/topjohnwu/Magisk\">Magisk</a>\n\\n- <a href=\"https://github.com/zhanghai/MaterialFiles\">Material Files</a>\n\\n- <a href=\"https://github.com/pluscubed/matlog\">MatLog</a>\n\\n- <a href=\"https://github.com/matrix-org/matrix-android-sdk\">Matrix Android SDK</a>\n\\n- <a href=\"https://github.com/jensstein/oandbackup\">OAndBackup</a>\n\\n- <a href=\"https://github.com/open-keychain/open-keychain\">Open Keychain</a>\n\\n- <a href=\"https://github.com/Aefyr/SAI\">SAI</a>\n\\n- <a href=\"https://github.com/RikkaApps/Shizuku\">Shizuku</a>\n\\n- <a href=\"https://github.com/eclipse/tm4e\">tm4e</a>\n\\n- <a href=\"https://github.com/tuyafeng/Watt\">Watt</a></string>\n    <string name=\"starting_activity\">Hoạt động bắt đầu: <xliff:g id=\"activity_name\" example=\".main.MainActivity\">%1$s</xliff:g></string>\n    <string name=\"clear_data_message\">Bạn có chắc muốn xoá dữ liệu của ứng dụng này không\\?</string>\n    <string name=\"clear_data_from_uninstalled_apps_description\">Dọn sạch dữ liệu khỏi các ứng dụng được gỡ cài đặt bằng cờ <tt>DUNG_XOA_DU_LIEU</tt></string>\n    <string name=\"block_components_dots\">Chặn thành phần…</string>\n    <string name=\"block_unblock_trackers_description\">Chặn hoặc bỏ chặn các thành phần quảng cáo và theo dõi trong tất cả ứng dụng đã cài đặt</string>\n    <string name=\"go\">Đi</string>\n    <string name=\"clear_cache\">Dọn bộ nhớ đệm</string>\n    <string name=\"install\">Cài đặt</string>\n    <plurals name=\"no_of_components\">\n        <item quantity=\"other\">%1$d thành phần</item>\n    </plurals>\n    <plurals name=\"no_of_trackers\">\n        <item quantity=\"other\">%1$d trình theo dõi</item>\n    </plurals>\n    <string name=\"manifest_viewer\">Trình xem Manifest</string>\n    <string name=\"external_apk_no_app_op\">APK ngoài không có bất kỳ hoạt động ứng dụng nào</string>\n    <string name=\"launch_app\">Chạy</string>\n    <string name=\"failed_to_deny_dangerous_app_ops\">Không thể thu hồi tất cả hoạt động ứng dụng nguy hiểm</string>\n    <string name=\"failed_to_deny_dangerous_perms\">Không thể thu hồi tất cả quyền nguy hiểm</string>\n    <string name=\"failed_to_reset_app_ops\">Không thể đặt lại hoạt động ứng dụng</string>\n    <string name=\"failed_to_revoke_permission\">Không thể thu hồi quyền</string>\n    <string name=\"sort_by_component_name\">Tên thành phần</string>\n    <string name=\"block_trackers\">Chặn trình theo dõi</string>\n    <string name=\"pref_installer_msg\">Thiết lập hành vi của trình cài đặt ứng dụng.</string>\n    <string name=\"expiry_date_cannot_be_empty\">Ngày hết hạn không thể trống.</string>\n    <string name=\"signing_key\">Mã ký</string>\n    <string name=\"app_signing_signatures\">Chữ ký</string>\n    <string name=\"backup_rules_description\">Sao lưu các quy tắc được định cấu hình trong App Manager. <font fgcolor=\"#ff0000\">Tùy thuộc vào quyền, không phải tất cả quy tắc đều có thể được áp dụng lại trong quá trình khôi phục.</font></string>\n    <string name=\"backup_extras_description\">Sao lưu các quyền của ứng dụng, các tùy chọn tiết kiệm pin và sử dụng dữ liệu, trạng thái MagiskHide, SSAID, v.v. <font fgcolor=\"#ff0000\">Tùy thuộc vào các quyền, không phải tất cả các tính năng bổ sung đều có thể được khôi phục.</font></string>\n    <string name=\"backup_extras\">Bổ sung</string>\n    <string name=\"backup_cache_description\">Sao lưu các thư mục <b>cache</b>, <b>no_cache</b> và <b>no_backup</b>.</string>\n    <string name=\"backup_obb_media_description\">Sao lưu OBB và các thư mục phương tiện.</string>\n    <string name=\"backup_external_data_description\">Sao lưu các thư mục dữ liệu ở ngoài.</string>\n    <string name=\"backup_internal_data_description\">Sao lưu các thư mục dữ liệu ở trong.</string>\n    <string name=\"backup_apk_files_description\">Sao lưu các tệp APK từ thư mục nguồn, bao gồm cả các tệp tách.</string>\n    <string name=\"set_mode_for_app_ops_dots\">Đặt chế độ cho hoạt động ứng dụng…</string>\n    <string name=\"graphics\">Đồ hoạ</string>\n    <string name=\"cpu\">CPU</string>\n    <string name=\"pref_sign_apk_msg\">Ký các tệp APK trước khi cài đặt chúng.</string>\n    <string name=\"pref_sign_apk\">Ký APK</string>\n    <string name=\"install_location_prefer_external\">Ưu tiên ở ngoài</string>\n    <string name=\"install_location_internal_only\">Chỉ ở trong</string>\n    <string name=\"install_location\">Vị trí cài đặt</string>\n    <string name=\"installer\">Trình cài đặt</string>\n    <string name=\"comment\">Bình luận</string>\n    <string name=\"orientation_unspecified\">Chưa chỉ định</string>\n    <string name=\"orientation_behind\">Phía sau</string>\n    <string name=\"orientation_locked\">Đã khoá</string>\n    <string name=\"orientation_full_user\">Đầy đủ người dùng</string>\n    <string name=\"orientation_full_sensor\">Đầy đủ cảm biến</string>\n    <string name=\"launch_mode_single_task\">Một công việc</string>\n    <string name=\"launch_mode_multiple\">Nhiều</string>\n    <string name=\"locale_split_for_base_apk\"><xliff:g id=\"split_name\" example=\"English\">%1$s</xliff:g> ngôn ngữ cho APK cơ sở</string>\n    <string name=\"locale_split_for_feature\"><xliff:g id=\"split_name\" example=\"English\">%1$s</xliff:g> ngôn ngữ cho tính năng <xliff:g id=\"feature_name\" example=\"Visualizer\">%2$s</xliff:g></string>\n    <string name=\"abi_split_for_base_apk\"><xliff:g id=\"split_name\" example=\"arm64_v8a\">%1$s</xliff:g> mã cho APK cơ sở</string>\n    <string name=\"abi_split_for_feature\"><xliff:g id=\"split_name\" example=\"arm64_v8a\">%1$s</xliff:g> mã cho <xliff:g id=\"feature_name\" example=\"Visualizer\">%2$s</xliff:g></string>\n    <string name=\"density_split_for_base_apk\"><xliff:g id=\"split_name\" example=\"xxdpi\">%1$s</xliff:g> (<xliff:g id=\"dpi_no\" example=\"480\">%2$d</xliff:g> DPI) tài nguyên cho APK cơ sở</string>\n    <string name=\"density_split_for_feature\"><xliff:g id=\"split_name\" example=\"xxdpi\">%1$s</xliff:g> (<xliff:g id=\"dpi_no\" example=\"480\">%2$d</xliff:g> DPI) tài nguyên cho tính năng <xliff:g id=\"feature_name\" example=\"Visualizer\">%3$s</xliff:g></string>\n    <string name=\"unknown_split_for_base_apk\"><xliff:g id=\"split_name\" example=\"some_split\">%1$s</xliff:g> cho APK cơ sở</string>\n    <string name=\"unknown_split_for_feature\"><xliff:g id=\"split_name\" example=\"some_split\">%1$s</xliff:g> cho tính năng <xliff:g id=\"feature_name\" example=\"Visualizer\">%2$s</xliff:g></string>\n    <string name=\"split_feature_name\">Tính năng: <xliff:g id=\"feature_name\" example=\"Visualizer\">%1$s</xliff:g></string>\n    <string name=\"base_apk\">APK cơ sở</string>\n    <string name=\"choose_language\">Đổi ngôn ngữ</string>\n    <string name=\"auto\">Tự động</string>\n    <string name=\"pref_app_language\">Ngôn ngữ</string>\n    <string name=\"backup_all_users\">Tất cả người dùng</string>\n    <string name=\"backup_multiple\">Sao lưu nhiều</string>\n    <string name=\"obb_files_extracted_successfully\">Đã trích xuất tệp OBB</string>\n    <string name=\"failed_to_extract_obb_files\">Không thể trích xuất tệp OBB</string>\n    <string name=\"orientation_no_sensor\">Không có cảm biến</string>\n    <string name=\"orientation_landscape\">Ngang</string>\n    <string name=\"_undefined\">Chưa định nghĩa</string>\n    <string name=\"required\">Bắt buộc</string>\n    <string name=\"orientation_user_portrait\">Dọc theo người dùng</string>\n    <string name=\"orientation_user_landscape\">Ngang theo người dùng</string>\n    <string name=\"orientation_sensor_portrait\">Dọc theo cảm biến</string>\n    <string name=\"orientation_sensor_landscape\">Ngang theo cảm biến</string>\n    <string name=\"orientation_user\">Người dùng</string>\n    <string name=\"orientation_reverse_landscape\">Ngang đảo ngược</string>\n    <string name=\"orientation_reverse_portrait\">Dọc đảo ngược</string>\n    <string name=\"orientation_portrait\">Dọc</string>\n    <string name=\"navigation_no_nav\">Không có điều hướng</string>\n    <string name=\"keyboard_12_keys\">12 phím</string>\n    <string name=\"keyboard_qwerty\">QWERTY</string>\n    <string name=\"keyboard_no_keys\">Không có phím</string>\n    <string name=\"shared_prefs\">Cài đặt dùng chung</string>\n    <string name=\"word_wrap\">Bật/tắt gói gọn từ</string>\n    <string name=\"installer_error_session_write\">Không thể ghi vào phiên làm việc của trình cài đặt</string>\n    <string name=\"installer_error_session_create\">Không thể tạo một phiên làm việc của trình cài đặt</string>\n    <string name=\"installer_error_security\">Không thể truy cập các tệp APK</string>\n    <string name=\"install_in_progress\">Đang cài đặt…</string>\n    <string name=\"package_installer\">Trình cài đặt gói</string>\n    <string name=\"unblock_trackers\">Bỏ chặn trình theo dõi</string>\n    <string name=\"reinstall\">Cài đặt lại</string>\n    <string name=\"install_app_message\">Bạn có muốn cài đặt ứng dụng này không\\?</string>\n    <string name=\"try_again\">Thử lại</string>\n    <string name=\"full_stop_tap_to_see_details\">. Nhấn để xem chi tiết.</string>\n    <string name=\"operation_running\">Hoạt động đang chạy…</string>\n    <string name=\"batch_ops\">Hoạt động hàng loạt</string>\n    <string name=\"failed_to_fetch_package_info\">Không thể lấy thông tin gói</string>\n    <string name=\"installer_error_lidl_rom\">ROM của bạn không tương thích với Trình cài đặt không dùng root.</string>\n    <string name=\"installer_error_generic\">Cài đặt thất bại</string>\n    <string name=\"installer_error_storage\">Không đủ dung lương bộ nhớ để cài đặt ứng dụng</string>\n    <string name=\"installer_error_bad_apks\">Đã chọn các tệp APK không hợp lệ</string>\n    <string name=\"installer_error_incompatible\">Ứng dụng không tương thích với thiết bị</string>\n    <string name=\"installer_error_conflict\">Không thể cài đặt ứng dụng vì tên gói đang được sử dụng</string>\n    <string name=\"installer_error_blocked\">Cài đặt bị <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g> chặn</string>\n    <string name=\"installer_error_blocked_device\">thiết bị</string>\n    <string name=\"installer_error_aborted\">Cài đặt không thành công vì nó đã bị hủy hoặc phiên bị đóng đột ngột</string>\n    <string name=\"toggle_default_app_ops\">Bật/tắt hoạt động ứng dụng mặc định</string>\n    <string name=\"filter_apps_with_activities\">Có hoạt động</string>\n    <string name=\"are_you_sure\">Bạn có chắc không\\?</string>\n    <string name=\"pref_remove_all_rules_msg\">Các quyền sẽ được cấp, các hoạt động ứng dụng và thành phần sẽ trở về giá trị ban đầu của chúng.</string>\n    <string name=\"pref_remove_all_rules\">Loại bỏ mọi quy tắc</string>\n    <string name=\"website\">Trang web</string>\n    <string name=\"run_in_termux\">Chạy trong Termux</string>\n    <string name=\"open_in_termux\">Mở trong Termux</string>\n    <string name=\"export_icon\">Trích xuất biểu tượng</string>\n    <string name=\"clear\">Dọn sạch</string>\n    <string name=\"skip_signature_checks\">Bỏ qua kiểm tra chữ ký</string>\n    <string name=\"yes\">Có</string>\n    <string name=\"no\">Không</string>\n    <string name=\"apply_to_system_apps_question\">Cũng áp dụng cho các ứng dụng hệ thống\\? Hãy chọn \\\"Không\\\" nếu không chắc.</string>\n    <string name=\"apply_to_system_apps\">Áp dụng cho các ứng dụng hệ thống</string>\n    <plurals name=\"verified_with_warning\">\n        <item quantity=\"other\">Đã xác minh với %d cảnh báo</item>\n    </plurals>\n    <plurals name=\"missing_signatures\">\n        <item quantity=\"other\">%1$d chữ ký bị thiếu</item>\n    </plurals>\n    <plurals name=\"libraries\">\n        <item quantity=\"other\">%1$d thư viện</item>\n    </plurals>\n    <string name=\"internal_data\">Dữ liệu nội bộ</string>\n    <string name=\"package_name_is_installed_successfully\">Đã cài đặt <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g></string>\n    <plurals name=\"no_of_splits\">\n        <item quantity=\"other\">%1$d tách</item>\n    </plurals>\n    <string name=\"only_works_in_root_or_adb_mode\">Chỉ hoạt động trong chế độ root hoặc ADB</string>\n    <string name=\"input_app_ops_description_profile\">Nhập tên hoạt động ứng dụng và/hoặc hằng số có dấu cách, vd: <tt>WAKE_LOCK 63 72 CAMERA</tt>, v.v. Sử dụng <tt>*</tt> để áp dụng cho tất cả hoạt động ứng dụng đã thiết lập.</string>\n    <string name=\"deny_app_ops_description\">Đặt một chế độ cho hoạt động ứng dụng được nhận dạng bởi các giá trị hằng số, vd: <tt>63</tt> hoặc <tt>RUN_IN_BACKGROUND</tt></string>\n    <string name=\"pref_import_existing_msg\">Thêm các thành phần bị các ứng dụng khác tắt vào App Manager. Hãy cẩn thận khi sử dụng công cụ này vì có thể có nhiều mục dương tính sai. Chỉ chọn các ứng dụng mà bạn chắc chắn về chúng.</string>\n    <string name=\"pref_import_existing\">Nhập các quy tắc đang tồn tại</string>\n    <string name=\"backup_skip_signature_checks_description\">Khôi phục các bản sao lưu xác minh mã kiểm tra thất bại hoặc có chữ ký APK khác với các bản sao lưu trước của chúng.</string>\n    <string name=\"backup_multiple_description\">Tạo một bản sao lưu <i>được đặt tên</i> riêng thay vì bản sao lưu cơ sở.</string>\n    <string name=\"battery_capacity\">Dung lượng</string>\n    <string name=\"memory\">Bộ nhớ</string>\n    <string name=\"vendor\">Người tạo</string>\n    <string name=\"gles_version\">Phiên bản OpenGL ES</string>\n    <string name=\"no_of_cores\">Lõi</string>\n    <string name=\"support_architectures\">Kiến trúc được hỗ trợ</string>\n    <string name=\"security_providers\">Nhà cung cấp bảo mật</string>\n    <string name=\"kernel\">Kernel</string>\n    <string name=\"board_name\">Bảng mạch</string>\n    <string name=\"model\">Mẫu</string>\n    <string name=\"brand_name\">Hãng</string>\n    <string name=\"pref_about_device_msg\">Thông tin thiết bị cơ bản bao gồm hệ thống Android, CPU, GPU, RAM, pin, v.v.</string>\n    <string name=\"about_device\">Về thiết bị</string>\n    <string name=\"set_custom_app_op\">Đặt hoạt động ứng dụng tùy chỉnh</string>\n    <string name=\"interceptor\">Trình can thiệp</string>\n    <string name=\"resend_intent\">Gửi lại Intent</string>\n    <string name=\"share\">Chia sẻ</string>\n    <string name=\"extras\">Bổ sung</string>\n    <string name=\"category\">Thể loại</string>\n    <string name=\"uri\">URI</string>\n    <string name=\"mime_type\">Loại MIME</string>\n    <string name=\"action\">Hành động</string>\n    <string name=\"result_code\">Mã kết quả</string>\n    <string name=\"activity_result\">Kết quả hoạt động</string>\n    <string name=\"send_edited_intent\">Gửi Intent đã chỉnh sửa</string>\n    <string name=\"matching_activities\">Hoạt động trùng khớp</string>\n    <string name=\"value\">Giá trị</string>\n    <string name=\"filter_apps_with_splits\">Có tách</string>\n    <string name=\"set_app_op_mode\">Đặt chế độ hoạt động ứng dụng</string>\n    <string name=\"pref_backup_android_keystore_msg\">Không phải tất cả ứng dụng sẽ hoạt động sau khi được khôi phục. Việc khôi phục KeyStore không hoạt động trên đa số thiết bị.</string>\n    <string name=\"pref_backup_android_keystore\">Sao lưu các ứng dụng bằng Android KeyStore</string>\n    <string name=\"keep_data_and_app_signing_signatures\">Giữ dữ liệu và chữ ký</string>\n    <string name=\"this_action_cannot_be_undone\">Hành động này không thể được hoàn tác.</string>\n    <string name=\"no_app_ops_permission\">Không có quyền để hiển thị hoạt động ứng dụng</string>\n    <string name=\"input_keystore_alias_pass_msg\">Nhấn vào đây để cung cấp mật khẩu cho %1$s</string>\n    <string name=\"input_keystore_alias_pass_description\">Nhập mật khẩu cho bí danh <b>%1$s</b>. Bạn có thể để trống nếu mật khẩu y hệt như mật khẩu KeyStore.</string>\n    <string name=\"input_keystore_alias_pass\">Mật khẩu cho bí danh <b>%1$s</b></string>\n    <string name=\"input_keystore_pass_msg\">Nhấn vào đây để nhập mật khẩu KeyStore</string>\n    <string name=\"input_keystore_pass_description\">Nhập mật khẩu KeyStore của App Manager. Nếu bạn đang thấy điều này lần đầu tiên, hãy vui lòng sử dụng một trình tạo mật khẩu để tạo một mật khẩu và lưu nó trong một nơi bảo mật trước khi chèn nó vào đây.</string>\n    <string name=\"input_keystore_pass\">Nhập mật khẩu KeyStore</string>\n    <string name=\"splits\">Tách</string>\n    <string name=\"source_stamp_verified\">SourceStamp đã được xác minh.</string>\n    <string name=\"not_verified\">Không được xác minh</string>\n    <string name=\"verified\">Đã xác minh</string>\n    <string name=\"pref_signature_schemes_msg\">Ít nhất các đề án v1 và v2 nên được chọn để có sự tương thích tốt hơn. Đề án v4 yêu cầu v2 hoặc v3.</string>\n    <string name=\"v4_scheme\">Đề án v4 (từ Android 11)</string>\n    <string name=\"v3_scheme\">Đề án v3 (từ Android 9)</string>\n    <string name=\"v2_scheme\">Đề án v2 (từ Android 7.0)</string>\n    <string name=\"v1_scheme\">Đề án v1 (từ Android 1.0)</string>\n    <string name=\"pref_apk_signing_msg\">Đặt đề án chữ ký, mã ký tùy chỉnh, v.v.</string>\n    <string name=\"apk_signing\">Ký APK</string>\n    <string name=\"app_signing_signature_schemes\">Đề án chữ ký</string>\n    <string name=\"source_code_links\"><a href=\"https://github.com/MuntashirAkon/AppManager\">GitHub</a> • <a href=\"https://gitlab.com/muntashir/AppManager\">GitLab</a> • <a href=\"https://0xacab.org/muntashir/AppManager\">Riseup</a> • <a href=\"https://codeberg.org/muntashir/AppManager\">Codeberg</a></string>\n    <string name=\"key_name_cannot_be_null\">Tên mã không thể trống</string>\n    <string name=\"key_name\">Tên mã</string>\n    <string name=\"boolean_value\">Giá trị sự thật</string>\n    <string name=\"requested_large_heap\">Bộ nhớ lớn</string>\n    <string name=\"net_policy\">Chính sách mạng</string>\n    <string name=\"has_net_policy\">Chính sách mạng</string>\n    <string name=\"unknown_net_policy\">Chính sách mạng không xác định (%1$s - %2$X)</string>\n    <string name=\"port_number_invalid\">Số cổng không hợp lệ.</string>\n    <string name=\"port_number_empty\">Số cổng trống.</string>\n    <string name=\"adb_connect_port_number_description\">Số cổng nằm trong <b>địa chỉ IP &amp; cổng</b> ngay bên dưới phần <b>Tên thiết bị</b>.</string>\n    <string name=\"port_number\">Cổng</string>\n    <string name=\"adb_connect\">Kết nối</string>\n    <string name=\"wireless_debugging\">Gỡ lỗi không dây</string>\n    <string name=\"netpolicy_disable_network_access\">Tắt quyền truy cập mạng</string>\n    <string name=\"netpolicy_reject_wifi_data\">Từ chối dữ liệu Wi-Fi</string>\n    <string name=\"netpolicy_reject_vpn_data\">Từ chối dữ liệu VPN</string>\n    <string name=\"netpolicy_reject_cellular_data\">Từ chối dữ liệu di động</string>\n    <string name=\"netpolicy_allow_background_data\">Cho phép dữ liệu trong nền khi Trình tiết kiệm dữ liệu đang bật</string>\n    <string name=\"netpolicy_reject_background_data\">Từ chối dữ liệu trong nền</string>\n    <string name=\"no_changes\">Không có thay đổi</string>\n    <string name=\"pref_display_changes_msg\">Hiển thị các thay đổi về phiên bản, trình theo dõi, thành phần, quyền, chữ ký, SDK, v.v. theo một cách được kiểm soát phiên bản.</string>\n    <string name=\"pref_display_changes\">Hiển thị các thay đổi</string>\n    <string name=\"hidden\">Bị ẩn</string>\n    <string name=\"suspended\">Đã dừng lại</string>\n    <string name=\"orientation_right_to_left\">Phải sang trái</string>\n    <string name=\"orientation_left_to_right\">Trái sang phải</string>\n    <string name=\"orientation_follow_locale\">Theo ngôn ngữ</string>\n    <string name=\"saf\">SAF</string>\n    <string name=\"pref_rules_msg\">Chặn ngay lập tức, nhập/xuất/xoá các quy tắc, v.v.</string>\n    <string name=\"failed\">Thất bại</string>\n    <string name=\"confirm_import_keystore\">Bạn có chắc bạn muốn thay thế KeyStore đang tồn tại không\\? Hành động này không thể được hoàn tác.</string>\n    <string name=\"import_keystore\">Nhập KeyStore</string>\n    <string name=\"pref_import_export_keystore_msg\">Nhập/xuất Bouncy Castle KeyStore (BKS) được App Manager sử dụng nội bộ.</string>\n    <string name=\"pref_import_export_keystore\">Nhập/xuất KeyStore</string>\n    <string name=\"latest_backup\">Bản sao lưu mới nhất</string>\n    <string name=\"gz_bz2_compressed\">Đã nén %1$s</string>\n    <string name=\"pgp_aes_rsa_encrypted\">Đã mã hoá %1$s</string>\n    <string name=\"no_encryption\">Không có mã hoá</string>\n    <string name=\"base_backup\">Bản sao lưu cơ sở</string>\n    <string name=\"trackers_unblocked_successfully\">Trình theo dõi bây giờ đã được bỏ chặn</string>\n    <string name=\"trackers_blocked_successfully\">Trình theo dõi bây giờ đã bị chặn</string>\n    <string name=\"failed_to_unblock_trackers\">Không thể bỏ chặn trình theo dõi</string>\n    <string name=\"failed_to_block_trackers\">Không thể chặn trình theo dõi</string>\n    <string name=\"profile_save_apk_msg\">Lưu các tệp APK trong <tt>AppManager/apks</tt></string>\n    <string name=\"save_apk\">Lưu APK</string>\n    <string name=\"running_services\">Dịch vụ đang chạy</string>\n    <string name=\"view_logs\">Xem nhật ký</string>\n    <string name=\"share_log\">Chia sẻ</string>\n    <string name=\"text_include_dmesg\">Bao gồm nhật ký của kernel</string>\n    <string name=\"omit_sensitive_info_summary\">Bỏ đi thông tin nhạy cảm như URL web, số điện thoại hoặc email.</string>\n    <string name=\"omit_sensitive_info\">Bỏ đi thông tin nhạy cảm</string>\n    <string name=\"undo\">Hoàn tác</string>\n    <string name=\"pause_unpause\">Phát/Tạm dừng</string>\n    <string name=\"collapse_all\">Thu gọn tất cả</string>\n    <string name=\"expand_all\">Mở rộng tất cả</string>\n    <string name=\"file\">Tệp</string>\n    <string name=\"widget_start_recording\">Ghi lại\n\\nNhật ký</string>\n    <string name=\"widget_recording_in_progress\">Đang ghi lại…</string>\n    <string name=\"unable_to_save_log\">Không thể lưu nhật ký. Bạn đã nhập tên tệp hợp lệ chưa\\?</string>\n    <plurals name=\"toast_log_truncated\">\n        <item quantity=\"other\">Nhật ký quá lớn, đang hiện %d dòng cuối.</item>\n    </plurals>\n    <string name=\"toast_invalid_selection\">Lựa chọn không hợp lệ. Vui lòng thử lại.</string>\n    <string name=\"toast_invalid_level\">Tên cấp độ không hợp lệ: %s</string>\n    <string name=\"pref_display_limit_hint\" tools:ignore=\"PluralsCandidate\">Vui lòng nhập một con số hợp lệ ở giữa %1$d và %2$d.</string>\n    <string name=\"text_include_device_info\">Bao gồm thông tin thiết bị</string>\n    <string name=\"text_filter_text\">Lọc văn bản</string>\n    <string name=\"text_filter_ellipsis\">Lọc…</string>\n    <string name=\"subject_log_report\">Báo cáo nhật ký</string>\n    <string name=\"start_recording_log\">Ghi lại</string>\n    <string name=\"settings\">Thiết đặt</string>\n    <string name=\"send_log_title\">Gửi nhật ký</string>\n    <string name=\"save_log\">Lưu nhật ký</string>\n    <string name=\"save_as\">Lưu dưới dạng…</string>\n    <string name=\"record_log\">Ghi lại nhật ký</string>\n    <string name=\"pref_show_timestamp_title\">Hiện PID &amp; Dấu thời gian</string>\n    <string name=\"pref_show_timestamp_summary\">Hiện ID tiến trình và dấu thời gian khi được mở rộng.</string>\n    <string name=\"pref_log_write_period_title\">Khoảng ghi</string>\n    <string name=\"pref_log_write_period_summary\" tools:ignore=\"PluralsCandidate\">Khi ghi lại, ghi vào thẻ SD mỗi %1$d dòng.</string>\n    <string name=\"pref_log_line_period_error\">Vui lòng nhập một số nguyên ở giữa 1 và 1000.</string>\n    <string name=\"pref_expanded_by_default_title\">Mở rộng theo mặc định</string>\n    <string name=\"pref_expanded_by_default_summary\">Hiện văn bản nhật ký đầy đủ theo mặc định.</string>\n    <string name=\"pref_filter_pattern_title\">Lọc ra các thẻ</string>\n    <string name=\"pref_filter_pattern_summary\">Lọc ra các thẻ được chọn khỏi nhật ký.</string>\n    <string name=\"pref_display_limit_title\">Giới hạn hiển thị nhật ký</string>\n    <string name=\"pref_display_limit_summary\" tools:ignore=\"PluralsCandidate\">Chỉ hiện %1$d nhật ký cuối để tránh lỗi hết bộ nhớ.</string>\n    <string name=\"pref_default_log_level_title\">Cấp độ nhật ký mặc định</string>\n    <string name=\"pref_default_log_level_summary\">Cấp độ nhật ký khi khởi động, khi mở các tệp, và khi ghi lại.</string>\n    <string name=\"pref_cat_configuration\">Thiết lập</string>\n    <string name=\"pref_cat_appearance\">Ngoại hình</string>\n    <string name=\"pref_cat_advanced\">Nâng cao</string>\n    <string name=\"pref_buffer_title\">Bộ đệm nhật ký</string>\n    <string name=\"open\">Mở</string>\n    <string name=\"notification_title\">Đang ghi lại nhật ký</string>\n    <string name=\"notification_ticker\">Đã bắt đầu ghi lại nhật ký</string>\n    <string name=\"notification_subtext\">Chạm để dừng ghi lại</string>\n    <string name=\"no_saved_logs\">Không có nhật ký đã lưu.</string>\n    <string name=\"manage_saved_logs\">Quản lý nhật ký đã lưu</string>\n    <string name=\"log_saved\">Đã lưu nhật ký.</string>\n    <string name=\"log_recording_started\">Đã bắt đầu ghi lại nhật ký.</string>\n    <string name=\"log_level\">Cấp độ nhật ký</string>\n    <string name=\"log_cleared\">Đã xoá nhật ký</string>\n    <string name=\"filter_choice_tag\">Thẻ</string>\n    <string name=\"filter_choice_pid\">PID</string>\n    <string name=\"filter_choice\">Tìm kiếm theo</string>\n    <string name=\"enter_good_filename\">Vui lòng nhập tên tệp hợp lệ.</string>\n    <string name=\"enter_filename\">Nhập tên tệp</string>\n    <string name=\"dialog_compiling_log\">Đang biên dịch nhật ký…</string>\n    <string name=\"delete_saved_log\">Xóa nhật ký đã lưu</string>\n    <string name=\"copy_to_clipboard\">Sao chép vào bộ nhớ tạm</string>\n    <plurals name=\"file_deletion_confirmation\">\n        <item quantity=\"other\">%d tệp sẽ bị xoá</item>\n    </plurals>\n    <string name=\"add_filter_ellipsis\">Thêm bộ lọc…</string>\n    <string name=\"add_filter\">Thêm bộ lọc</string>\n    <string name=\"log_level_fatal\">Nguy hiểm</string>\n    <string name=\"log_level_warn\">Cảnh báo</string>\n    <string name=\"log_level_verbose\">Chi tiết</string>\n    <string name=\"log_level_info\">Thông tin</string>\n    <string name=\"log_level_error\">Lỗi</string>\n    <string name=\"log_level_debug\">Gỡ lỗi</string>\n    <string name=\"filename\">Tên tệp</string>\n    <string name=\"restart_log_viewer_to_see_changes\">Khởi động lại cửa sổ trình xem nhật ký để thấy các thay đổi.</string>\n    <string name=\"pref_log_viewer_msg\">Thiết lập cách nhật ký được hiển thị.</string>\n    <string name=\"log_viewer\">Trình xem nhật ký</string>\n    <string name=\"failed_to_read_keystore\">Không thể đọc KeyStore.</string>\n    <string name=\"alias_pass\">Mật khẩu bí danh</string>\n    <string name=\"choose_an_alias\">Chọn một bí danh</string>\n    <string name=\"found_no_alias_in_keystore\">Không tìm thấy bí danh nào trong KeyStore!</string>\n    <string name=\"new_alias_password\">Mật khẩu bí danh mới</string>\n    <string name=\"import_key\">Nhập mã khoá</string>\n    <string name=\"pem_file\">Tệp PEM</string>\n    <string name=\"pk8_file\">Tệp PKCS #8 (PK8)</string>\n    <string name=\"pem_and_pk8\">PEM và PKCS #8 (PK8)</string>\n    <string name=\"pkcs12_keystore\">PKCS #12 KeyStore (P12)</string>\n    <string name=\"bouncy_castle_keystore\">Kho khóa lâu đài Bouncy (BKS)</string>\n    <string name=\"java_keystore\">Kho khóa Java (JKS)</string>\n    <string name=\"keystore_pass\">Mật khẩu KeyStore</string>\n    <string name=\"keystore_file\">Tệp KeyStore</string>\n    <string name=\"country_name\" tools:ignore=\"TypographyOther\">Tên quốc gia (C)</string>\n    <string name=\"state_name\">Tên tiểu bang (ST)</string>\n    <string name=\"locality_name\">Tên địa phương (thành phố) (L)</string>\n    <string name=\"organization_name\">Tên tổ chức (O)</string>\n    <string name=\"organization_unit\">Đơn vị tổ chức (OU)</string>\n    <string name=\"common_name\">Tên phổ biến (CN)</string>\n    <string name=\"input_key_password\">Mật khẩu mã khoá</string>\n    <string name=\"failed_to_load_key\">Không thể tải mã khoá.</string>\n    <string name=\"key_not_set\">Không được đặt.</string>\n    <string name=\"use_default\">Sử dụng mặc định</string>\n    <string name=\"invalid_rsa_key_size\">Kích cỡ mã khoá không hợp lệ cho mã hoá RSA. Kích cỡ mã khoá có thể là 1024, 2048 hoặc 4096 bit.</string>\n    <string name=\"crypto_key_size\">Kích cỡ mã khoá</string>\n    <string name=\"invalid_aes_key_size\">Kích cỡ mã khoá không hợp lệ cho mã hoá AES. Kích cỡ mã khoá có thể là 128 hoặc 256 bit.</string>\n    <string name=\"failed_to_initialize_key_store\">Không thể khởi tạo KeyStore của App Manager.</string>\n    <string name=\"failed_to_save_key\">Không thể lưu mã khoá.</string>\n    <string name=\"generate_key\">Tạo</string>\n    <string name=\"last_actions\">Những hành động cuối</string>\n    <string name=\"pref_enable_disable_features_msg\">Bật hoặc tắt các tính năng trong App Manager.</string>\n    <string name=\"ssaid_info\">SSAID (<tt>Settings.Secure.ANDROID_ID</tt>) là một mã nhận dạng thiết bị được phân cho mỗi ứng dụng (từ Android 8 \\\"Oreo\\\" trở đi). Nó được các ứng dụng sử dụng rộng rãi để theo dõi người dùng.</string>\n    <string name=\"ssaid\">SSAID</string>\n    <string name=\"add_to_profile\">Thêm vào hồ sơ</string>\n    <string name=\"initializing\">Đang khởi tạo…</string>\n    <string name=\"choose_what_to_do\">Chọn điều để làm.</string>\n    <string name=\"enable_battery_optimization\">Bật tối ưu hoá pin\\?</string>\n    <string name=\"battery_optimization\">Tối ưu hoá pin</string>\n    <string name=\"no_battery_optimization\">Không có tối ưu hoá pin</string>\n    <string name=\"type_uri\">URI</string>\n    <string name=\"type_string_array_list\">Danh sách xâu</string>\n    <string name=\"type_string_array\">Mảng xâu</string>\n    <string name=\"type_float_array_list\">Danh sách số thập phân</string>\n    <string name=\"type_float_array\">Mảng số thập phân</string>\n    <string name=\"type_long_array_list\">Danh sách số nguyên dài</string>\n    <string name=\"type_long_array\">Mảng số nguyên dài</string>\n    <string name=\"type_int_array_list\">Danh sách số nguyên</string>\n    <string name=\"type_int_array\">Mảng số nguyên</string>\n    <string name=\"type_component_name\">Tên thành phần</string>\n    <string name=\"type_null\">Không có giá trị</string>\n    <string name=\"screen_lock_msg\">Khoá App Manager bằng khoá màn hình của Android</string>\n    <string name=\"screen_lock\">Khoá màn hình</string>\n    <string name=\"unlock_app_manager\">Mở khoá App Manager</string>\n    <string name=\"sd_card\">Thẻ SD</string>\n    <string name=\"external_storage\">Bộ nhớ ngoài</string>\n    <string name=\"internal_storage\">Bộ nhớ trong</string>\n    <string name=\"back_up\">Sao lưu</string>\n    <string name=\"drm_free_apkm_msg\">Tệp APKM này không có DRM, không cần chuyển đổi nó thành APKS.</string>\n    <string name=\"restore_msg\">Khôi phục các ứng dụng có dữ liệu</string>\n    <string name=\"backup_msg\">Sao lưu các ứng dụng có dữ liệu</string>\n    <string name=\"restore_latest_msg\">Khôi phục các ứng dụng đã cài đặt mà mã phiên bản của chúng cao hơn mã phiên bản đã cài đặt.</string>\n    <string name=\"restore_latest\">Khôi phục các bản sao lưu mới nhất</string>\n    <string name=\"restore_not_installed_msg\">Khôi phục bản sao lưu cơ sở cho các ứng dụng hiện không được cài đặt.</string>\n    <string name=\"restore_not_installed\">Khôi phục các ứng dụng không được cài đặt</string>\n    <string name=\"restore_all_msg\">Khôi phục bản sao lưu cơ sở từ tất cả ứng dụng đã sao lưu.</string>\n    <string name=\"restore_all\">Khôi phục tất cả ứng dụng</string>\n    <string name=\"backup_apps_with_changes_msg\">Làm lại bản sao lưu cho các ứng dụng có các thay đổi từ bản sao lưu trước. Chúng bao gồm các thay đổi về kích cỡ, phiên bản, lần chạy cuối.</string>\n    <string name=\"backup_apps_with_changes\">Sao lưu các ứng dụng có các thay đổi</string>\n    <string name=\"redo_existing_backups_msg\">Làm lại bản sao lưu cho các ứng dụng đã cài đặt có các bản sao lưu trước.</string>\n    <string name=\"redo_existing_backups\">Làm lại các bản sao lưu đang tồn tại</string>\n    <string name=\"verify_and_redo_backups_msg\">Kiểm tra tính nguyên vẹn của các bản sao lưu trước và làm lại bản sao lưu mà kiểm tra tính nguyên vẹn bị thất bại.</string>\n    <string name=\"verify_and_redo_backups\">Xác minh và làm lại bản sao lưu</string>\n    <string name=\"backup_apps_without_backups_msg\">Sao lưu các ứng dụng không có bất kỳ bản sao lưu trước nào.</string>\n    <string name=\"backup_apps_without_backups\">Sao lưu các ứng dụng không có bản sao lưu</string>\n    <string name=\"backup_all_apps_msg\">Sao lưu tất cả ứng dụng đã cài đặt.</string>\n    <string name=\"backup_all_apps\">Sao lưu tất cả ứng dụng</string>\n    <string name=\"backup_custom_users_description\">Thực hiện các bản sao lưu chỉ cho những người dùng được chỉ định</string>\n    <string name=\"backup_custom_users\">Người dùng tùy chỉnh</string>\n    <string name=\"bootloader\">Bootloader</string>\n    <string name=\"unencrypted\">Không được mã hoá</string>\n    <string name=\"no_volumes_found\">Không thể tìm thấy bất kỳ ổ đĩa nào có quyền ghi.</string>\n    <string name=\"pref_backup_volume_msg\">Đặt ổ đĩa nơi các bản sao lưu sẽ được lưu trữ.</string>\n    <string name=\"backup_volume\">Ổ đĩa sao lưu</string>\n    <string name=\"pref_backup_restore_msg\">Tuỳ biến sao lưu/khôi phục.</string>\n    <string name=\"disable_background_run_description\">Đặt chế độ <i>Bỏ qua</i> cho các hoạt động ứng dụng sau: <tt>RUN_IN_BACKGROUND</tt> (từ Android 7.0) và <tt>RUN_ANY_IN_BACKGROUND</tt> (từ Android 9).</string>\n    <string name=\"failed_to_enable_magisk_hide\">Không thể bật MagiskHide</string>\n    <string name=\"failed_to_disable_magisk_hide\">Không thể tắt MagiskHide</string>\n    <string name=\"window_size\">Kích thước cửa sổ</string>\n    <string name=\"refresh_rate\">Tốc độ làm mới</string>\n    <string name=\"scaling_factor\">Yếu tố chia tỉ lệ</string>\n    <string name=\"size\">Kích cỡ</string>\n    <string name=\"density\">Độ dày đặc</string>\n    <string name=\"screen\">Màn hình</string>\n    <string name=\"hardware\">Phần cứng</string>\n    <string name=\"permissive\">Cho phép</string>\n    <string name=\"enforcing\">Thực thi</string>\n    <string name=\"selinux\">SELinux</string>\n    <string name=\"patch_level\">Cấp độ bản vá</string>\n    <string name=\"encryption\">Mã hoá</string>\n    <string name=\"select_user\">Chọn người dùng</string>\n    <string name=\"failed_to_duplicate_profile\">Không thể nhân bản cấu hình</string>\n    <string name=\"duplicate\">Nhân bản</string>\n    <string name=\"new_profile\">Cấu hình mới</string>\n    <string name=\"input_profile_name_description\">Tên cấu hình không thể chứa dấu cách.</string>\n    <string name=\"input_profile_name\">Tên cấu hình</string>\n    <string name=\"select_apk\">Chọn APK</string>\n    <string name=\"send_crash_report\">Gửi báo cáo dừng đột ngột</string>\n    <string name=\"tap_to_submit_crash_report\">Nhấn để gửi đi báo cáo dừng đột ngột.</string>\n    <string name=\"am_crashed\">App Manager vừa bị dừng đột ngột</string>\n    <string name=\"un_apkm\">UnApkm</string>\n    <string name=\"in_progress\">Đang thực hiện</string>\n    <string name=\"conversion_failed\">Chuyển đổi thất bại.</string>\n    <string name=\"pref_backup_flags_msg\">Việc thêm một thiết lập trước cho các tùy chọn sao lưu sẽ xoá đi gánh nặng phải chọn các thuộc tính mỗi lần bạn sao lưu/khôi phục.</string>\n    <string name=\"pref_compression_method\">Phương pháp nén</string>\n    <string name=\"rules\">Quy tắc</string>\n    <string name=\"format\">Định dạng</string>\n    <string name=\"public_key\">Mã khoá công khai</string>\n    <string name=\"algorithm\">Thuật toán</string>\n    <string name=\"app_signing_signature\">Chữ ký</string>\n    <string name=\"checksums\">Mã kiểm tra</string>\n    <string name=\"serial_no\">Số sê-ri</string>\n    <string name=\"not_yet_valid\">Chưa hợp lệ</string>\n    <string name=\"expired\">Đã hết hạn</string>\n    <string name=\"valid\">Hợp lệ</string>\n    <string name=\"validity\">Tính hợp lệ</string>\n    <string name=\"type\">Loại</string>\n    <string name=\"expiry_date\">Ngày hết hạn</string>\n    <string name=\"issued_date\">Ngày cấp</string>\n    <string name=\"issuer\">Người cấp</string>\n    <string name=\"filter_apps_with_backups\">Có bản sao lưu</string>\n    <string name=\"sort_by_backup\">Đã sao lưu trước</string>\n    <string name=\"failed_to_uninstall_updates\">Không thể gỡ cài đặt các bản cập nhật của <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g>.</string>\n    <string name=\"update_uninstalled_successfully\">Các bản cập nhật của <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g> đã được gỡ cài đặt.</string>\n    <string name=\"uninstall_updates\">Gỡ cài đặt các bản cập nhật</string>\n    <string name=\"allow_open_pgp_operation\">Nhấn để cho phép App Manager sử dụng OpenPGP</string>\n    <string name=\"confirm_installation\">Xác nhận cài đặt</string>\n    <string name=\"view_missing_signatures\">Nhấn để xem hoặc gửi đi các chữ ký chưa có trong cơ sở dữ liệu các thư viện của App Manager.</string>\n    <string name=\"tap_to_see_details\">Nhấn để xem chi tiết</string>\n    <string name=\"lib_details\">Chi tiết thư viện</string>\n    <string name=\"backup_obb_media\">OBB và Phương tiện</string>\n    <string name=\"backup_apk_files\">Các tệp APK</string>\n    <string name=\"installer_error_session_abandon\">Không thể bỏ phiên làm việc trình cài đặt</string>\n    <plurals name=\"app_signing_signature_schemes_pl\">\n        <item quantity=\"other\">Đề án chữ ký</item>\n    </plurals>\n    <string name=\"pref_import_blocker_msg\">Nhập các quy tắc chặn từ Blocker, mỗi tệp chứa các quy tắc cho một gói.</string>\n    <string name=\"pref_import_watt_msg\">Nhập các quy tắc chặn từ Watt, mỗi tệp chứa các quy tắc cho một gói được đặt tên dưới dạng <tt>packagename.xml</tt>, v.v.</string>\n    <string name=\"type_long\">Số nguyên dài</string>\n    <string name=\"type_int\">Số nguyên</string>\n    <string name=\"type_float\">Số thập phân</string>\n    <string name=\"decimal_value\">Giá trị thập phân</string>\n    <string name=\"integer_value\">Giá trị số nguyên</string>\n    <string name=\"long_integer_value\">Giá trị số nguyên dài</string>\n    <string name=\"no_libs\">Không có thư viện</string>\n    <string name=\"scanner\">Trình quét</string>\n    <string name=\"sys_config\">Thiết lập hệ thống</string>\n    <string name=\"only_install\">Chỉ cài đặt</string>\n    <string name=\"app_signing_install_without_data_loss\">Nếu bạn đã tắt xác minh chữ ký, bạn có thể sử dụng tùy chọn <b>Chỉ cài đặt</b> để cài đặt ứng dụng mà không mất dữ liệu.</string>\n    <string name=\"app_data_will_be_lost\">Dữ liệu hiện có sẽ bị mất.</string>\n    <string name=\"app_signing_signature_mismatch_for_system_apps\">Không thể cài đặt ứng dụng vì một ứng dụng hệ thống có chữ ký khác cũng có tên gói này.</string>\n    <string name=\"do_you_want_to_uninstall_and_install\">Bạn có muốn gỡ cài đặt và cài đặt ứng dụng lại không\\?</string>\n    <string name=\"usage_access_not_supported\">Không thể yêu cầu truy cập dữ liệu sử dụng, vì trang cài đặt tương ứng không tồn tại.</string>\n    <string name=\"subject\">Đối tượng</string>\n    <string name=\"other\">Khác</string>\n    <string name=\"changes_not_saved\">Các thay đổi chưa được lưu</string>\n    <string name=\"sort_by_memory_usage\">Sử dụng bộ nhớ</string>\n    <string name=\"sort_by_apps_first\">Ứng dụng trước</string>\n    <string name=\"sort_by_process_name\">Tên tiến trình</string>\n    <string name=\"sort_by_process_id\">ID tiến trình</string>\n    <string name=\"filter_apps\">Ứng dụng</string>\n    <string name=\"no_apps\">Không có ứng dụng</string>\n    <string name=\"apps\">Ứng dụng</string>\n    <string name=\"routine_ops\">Hoạt động thường ngày</string>\n    <string name=\"apply_now\">Áp dụng ngay…</string>\n    <string name=\"keystore\">KeyStore</string>\n    <string name=\"no_profiles\">Không có cấu hình</string>\n    <string name=\"profiles\">Cấu hình</string>\n    <string name=\"open_pgp_provider\">Nhà cung cấp OpenPGP</string>\n    <string name=\"systemless_app\">Ứng dụng không dùng hệ thống</string>\n    <string name=\"cancel\">Hủy bỏ</string>\n    <string name=\"ok\">OK</string>\n    <string name=\"input_backup_name_description\">Tên bản sao lưu không nên bắt đầu bằng một chữ số và cũng không nên chứa dấu cách. Để trống nếu bạn muốn sử dụng ngày-giờ hiện tại.</string>\n    <string name=\"input_backup_name\">Tên bản sao lưu</string>\n    <string name=\"downgrade\">Hạ cấp</string>\n    <string name=\"process_state_with_extra\">Trạng thái: <xliff:g id=\"process_state\" example=\"Sleeping\">%1$s</xliff:g> (<xliff:g id=\"state_extra\" example=\"High priority\">%2$s</xliff:g>)</string>\n    <string name=\"process_state\">Trạng thái: <xliff:g id=\"process_state\" example=\"Sleeping\">%1$s</xliff:g></string>\n    <string name=\"state_multithreaded\">Nhiều tiến trình</string>\n    <string name=\"state_foreground\">Ở trước</string>\n    <string name=\"state_session_leader\">Lãnh đạo phiên làm việc</string>\n    <string name=\"state_idle\">Không hoạt động</string>\n    <string name=\"failed_to_prevent_background_run\">Không thể ngăn chặn %1$s chạy trong nền</string>\n    <string name=\"state_parked\">Đã đỗ lại</string>\n    <string name=\"state_zombie\">Zombie</string>\n    <string name=\"state_trace_stop\">Dừng dấu vết</string>\n    <string name=\"touchscreen_stylus\">Bút cảm ứng</string>\n    <string name=\"touchscreen_no_touch\">Không có cảm ứng</string>\n    <string name=\"navigation_wheel\">Con lăn</string>\n    <string name=\"navigation_trackball\">Bi lăn điều khiển</string>\n    <string name=\"navigation_dial_pad\">Bàn phím số</string>\n    <string name=\"launch_mode_single_top\">Một hoạt động ở trên</string>\n    <string name=\"launch_mode_single_instance\">Một bản sao</string>\n    <string name=\"installer_error_session_commit\">Không thể hành động với các tệp APK</string>\n    <string name=\"community_links\"><a href=\"https://matrix.to/#/#appmanager:matrix.org\">Matrix</a> • <a href=\"https://t.me/AppManagerChannel\">Telegram</a> • <a href=\"https://twitter.com/AppManagerNews\">Twitter</a></string>\n    <string name=\"community\">Cộng đồng</string>\n    <string name=\"native_library_dir\">Thư mục thư viện JNI gốc</string>\n    <string name=\"input_key\">Nhập mã (ở hệ thập lục phân)</string>\n    <string name=\"installer_app_message\">Chọn <b>Chọn</b> để chọn từ các ứng dụng đã cài đặt hoặc chọn <b>Tùy chỉnh</b> để chỉ định tên gói tùy chỉnh.</string>\n    <string name=\"verified_using_unreliable_hash\">Đã xác minh bằng hash không đáng tin cậy</string>\n    <string name=\"input_permissions_description\">Nhập các quyền có dấu cách, vd: <tt>com.permission.GET_ACCOUNTS android.permission.ACCESS_MEDIA_LOCATION</tt> v.v. Sử dụng <tt>*</tt> để áp dụng cho tất cả quyền.</string>\n    <string name=\"input_permissions\">Nhập các quyền</string>\n    <string name=\"options\">Tuỳ chọn</string>\n    <string name=\"off\">Tắt</string>\n    <string name=\"on\">Bật</string>\n    <string name=\"profile_state_msg\">Trạng thái bật/tắt tùy chỉnh cho cấu hình này</string>\n    <string name=\"profile_block_trackers_msg\">Chặn các trình theo dõi trong các ứng dụng</string>\n    <string name=\"profile_clear_data_msg\">Dọn dẹp dữ liệu của các ứng dụng</string>\n    <string name=\"profile_clear_cache_msg\">Dọn dẹp bộ nhớ đệm của các ứng dụng</string>\n    <string name=\"profile_force_stop_msg\">Buộc dừng các ứng dụng</string>\n    <string name=\"allow_routine_ops_msg\">Cho phép cấu hình được sử dụng trong các hoạt động thường ngày</string>\n    <string name=\"profile_state\">Trạng thái cấu hình</string>\n    <string name=\"allow_routine_ops\">Cho phép các hoạt động thường ngày</string>\n    <string name=\"adb_over_tcp\">ADB qua TCP</string>\n    <string name=\"pref_mode_of_operations\">Chế độ hoạt động</string>\n    <string name=\"send_selected\">Gửi mục đã chọn</string>\n    <string name=\"ecc\">Mã hoá đường cong elip</string>\n    <string name=\"rsa\">RSA</string>\n    <string name=\"aes\">AES</string>\n    <string name=\"none\">Không có</string>\n    <string name=\"pref_encryption_msg\">Mã hoá cho các bản sao lưu.</string>\n    <string name=\"non_critical_exts\">Phần mở rộng không quan trọng</string>\n    <string name=\"critical_exts\">Phần mở rộng quan trọng</string>\n    <string name=\"dsa_affine_y\">Gán toạ độ y</string>\n    <string name=\"dsa_affine_x\">Gán toạ độ x</string>\n    <string name=\"rsa_modulus\">Mô-đun</string>\n    <string name=\"rsa_exponent\">Người thực hiện</string>\n    <string name=\"state_wake_kill\">Dừng thức dậy</string>\n    <plurals name=\"alert_failed_to_import_backups\">\n        <item quantity=\"other\">Không thể nhập %1$d bản sao lưu</item>\n    </plurals>\n    <string name=\"import_from_tb\">Nhập từ Titanium Backup</string>\n    <string name=\"import_from_oab\">Nhập từ OAndBackup</string>\n    <string name=\"pref_import_backups_msg\">Nhập bản sao lưu từ OAndBackup,Swift Backup(3.0 -3.2) hoặc Titanium Backup.</string>\n    <string name=\"pref_import_backups\">Nhập bản sao lưu</string>\n    <string name=\"added_to_queue\">Đã thêm vào hàng chờ</string>\n    <string name=\"minimum_version\">Phiên bản tối thiểu: %d</string>\n    <string name=\"help_uses_permissions_tab\">Nhấn vào một mục để <b>cấp</b> hoặc <b>thu hồi</b> nó. Chỉ có các quyền <b>nguy hiểm</b> và <b>phát triển</b> mới có thể được cấp hoặc thu hồi.</string>\n    <string name=\"help_permissions_tab\">Các quyền này được ứng dụng này định nghĩa và không thể được thu hồi.</string>\n    <string name=\"help_app_ops_tab\">Nhấn vào một mục để <b>cho phép</b> hoặc <b>bỏ qua</b> nó. Nhấn giữ một mục để thấy các chế độ được hỗ trợ khác.</string>\n    <string name=\"saved_filters\">Bộ lọc đã lưu</string>\n    <string name=\"permission_flags\">Thuộc tính quyền</string>\n    <string name=\"pref_selected_users_msg\">Giới hạn App Manager chỉ hoạt động với những người dùng đã chọn.</string>\n    <string name=\"pref_selected_users\">Người dùng đã chọn</string>\n    <string name=\"error_with_details\">Lỗi: %s</string>\n    <string name=\"files\">Tệp</string>\n    <string name=\"storage\">Bộ nhớ</string>\n    <string name=\"notice_saf\">Không giống các kho, thư mục được chọn sẽ được sử dụng để lưu trữ tất cả tệp liên quan đến App Manager, bao gồm cả các tệp APK đã lưu và các bản sao lưu. Storage Access Framework (SAF) rất là chậm, do đó bạn chỉ nên sử dụng tùy chọn này khi những tùy chọn khác không thể sử dụng được.</string>\n    <string name=\"notice\">Thông báo</string>\n    <string name=\"paired_successfully\">Đã ghép đôi.</string>\n    <string name=\"adb_pair\">Ghép đôi</string>\n    <string name=\"invalid_password\">Mật khẩu không hợp lệ, hãy thử lại.</string>\n    <string name=\"keystore_pass_cannot_be_empty\">Mật khẩu KeyStore không thể trống.</string>\n    <string name=\"keystore_password_info\">Đây là mật khẩu KeyStore của App Manager. Vui lòng lưu trữ nó ở một nơi bảo mật nếu bạn có kế hoạch sao lưu/khôi phục KeyStore của App Manager. <b>Thông báo này sẽ không được hiển thị lại.</b></string>\n    <string name=\"running_services_logcat_hint\">Nhấn vào một mục để mở trình xem nhật ký với ID tiến trình tương ứng là bộ lọc mặc định.</string>\n    <string name=\"pid\">ID tiến trình</string>\n    <plurals name=\"pref_thread_count_msg\">\n        <item quantity=\"other\">Thực thi tối đa %1$d hoạt động song song</item>\n    </plurals>\n    <string name=\"pref_thread_count_hint\">Giá trị phải ở giữa 0 và %1$d, 0 có nghĩa là <i>số hoạt động tối đa tại một thời điểm</i>.</string>\n    <string name=\"pref_thread_count\">Thực thi song song</string>\n    <string name=\"type_uri_array_list\">Danh sách các URI</string>\n    <string name=\"type_uri_array\">Mảng các URI</string>\n    <string name=\"pref_always_on_background_msg\">Luôn cài đặt ứng dụng trong nền và hiển thị thông báo khi hoàn tất.</string>\n    <string name=\"pref_always_on_background\">Cài đặt trong nền</string>\n    <string name=\"pref_block_trackers_msg\">Chặn các thành phần theo dõi sau khi cài đặt một ứng dụng bằng App Manager.</string>\n    <string name=\"next\">Tiếp</string>\n    <string name=\"installer_app_installed\">Đã cài đặt ứng dụng</string>\n    <string name=\"staging_apk_files\">Đang chuẩn bị…</string>\n    <string name=\"background\">Nền</string>\n    <string name=\"trim_caches_in_all_apps_description\">Xóa các tệp bộ nhớ đệm khỏi tất cả ứng dụng, bao gồm cả hệ thống Android</string>\n    <string name=\"trim_caches_in_all_apps\">Xóa bớt bộ nhớ đệm trong tất cả ứng dụng</string>\n    <string name=\"user_root\">Sử dụng root</string>\n    <string name=\"paste\">Dán</string>\n    <string name=\"set_package_name_first\">Hãy đặt tên gói trước tiên!</string>\n    <string name=\"identifier\">Định danh</string>\n    <string name=\"backup_volume_dialog_description\">Các kho có tiền tố <tt>/tree</tt> là các thư mục được chọn bằng Storage Access Framework (SAF). Trừ các thư mục đó ra, thư mục mặc định của App Manager là một thư mục con có tên là <tt>AppManager</tt>.</string>\n    <string name=\"second_degree_tracker_note\">Tiền tố ² có nghĩa là trình theo dõi đang ở trong <a href=\"https://etip.exodus-privacy.eu.org/\">danh sách chờ của ETIP</a>, vd: việc chúng có phải là trình theo dõi thật hay không vẫn đang được điều tra.</string>\n    <string name=\"failed_to_uninstall_app\">Gỡ cài đặt thất bại</string>\n    <string name=\"explore\">Truy cập</string>\n    <string name=\"system_partition\">Android root</string>\n    <string name=\"exit_confirmation\">Xác nhận thoát</string>\n    <string name=\"extract\">Giải nén</string>\n    <string name=\"replace\">Thay thế</string>\n    <string name=\"rename\">Đổi tên</string>\n    <string name=\"java\">Java</string>\n    <string name=\"smali\">Smali</string>\n    <string name=\"accessibility_service_description\">Cho phép truy cập và sử dụng dịch vụ để thực hiện một số công việc như dọn cache trên thiết bị chưa root.</string>\n    <string name=\"pref_import_backups_hint\">Chọn thư mục chứa bản sao từ(Swift Backup/Titanium Backup) hoặc thư mục(OAndBackup)</string>\n    <string name=\"import_from_sb\">Nhập bản sao từ Swift Backup 3.0 – 3.2</string>\n    <string name=\"intent_firewall_and_disable\">IFW + tắt</string>\n    <string name=\"pref_default_blocking_method\">Phương pháp chặn mặc định</string>\n    <string name=\"pref_default_blocking_method_description\">Phương pháp được sử dụng theo mặc định ở những nơi không có tùy chọn để chọn phương pháp chặn.\n\\n<b>Lưu ý:</b> “IFW” không hoạt động với các nhà cung cấp, thay vào đó, “vô hiệu hóa” được sử dụng.</string>\n    <string name=\"pref_disable_description\">Chỉ tắt các thành phần. Không được khuyên dùng cho người dùng root vì các ứng dụng có thể vượt qua việc này. Ở chế độ ADB, các ứng dụng chỉ thử có thể được tắt bằng phương pháp này.</string>\n    <string name=\"intent_firewall\">IFW</string>\n    <string name=\"pref_intent_firewall_and_disable_description\">Chặn các thành phần bằng Intent Firewall và tắt chúng. Phương pháp này được khuyên dùng cho người dùng root.</string>\n    <string name=\"pref_intent_firewall_description\">Chặn các thành phần chỉ bằng Intent Firewall. Không được khuyên dùng vì một số ứng dụng hệ thống có thể vượt qua tường lửa.</string>\n    <string name=\"authenticating\">Đang xác thực…</string>\n    <string name=\"search_type_contains\">Chứa</string>\n    <string name=\"search_type_prefix\">Tiền tố</string>\n    <string name=\"search_type_suffix\">Hậu tố</string>\n    <string name=\"search_type_regular_expressions\">Biểu thức thường</string>\n    <string name=\"state\">Trạng thái quá trình</string>\n    <string name=\"vt_checking\">VirusTotal: Đang kiểm tra…</string>\n    <string name=\"vt_uploading\">VirusTotal: Đang tải lên…</string>\n    <plurals name=\"usage_seconds\">\n        <item quantity=\"other\">%1$d giây</item>\n    </plurals>\n    <string name=\"vt_queued\">VirusTotal: Đã thêm vào hàng đợi</string>\n    <string name=\"vt_failed\">VirusTotal: Thất bại</string>\n    <string name=\"vt_success\">VirusTotal: %1$d/%2$d</string>\n    <string name=\"vt_scan_date\">Ngày quét: %1$s</string>\n    <string name=\"vt_permalink\">Liên kết vĩnh viễn cho VirusTotal</string>\n    <string name=\"vt_slowness_warning\">Sẽ tốn một khoảng thời gian phụ thuộc vào tốc độ Internet và khả năng xử lý của máy chủ.</string>\n    <string name=\"pref_vt_apikey\">Khoá API VirusTotal</string>\n    <string name=\"pref_vt_apikey_summary\">Bật quét virus bằng VirusTotal.</string>\n    <string name=\"uses_play_app_signing\">Chữ ký Google Play</string>\n    <string name=\"scan_in_vt\">Quét bằng VirusTotal</string>\n    <string name=\"process_id\">ID quá trình</string>\n    <string name=\"parent_process_id\">ID quá trình chính</string>\n    <string name=\"virtual_memory\">Bộ nhớ ảo</string>\n    <string name=\"cpu_percent\">%% CPU</string>\n    <string name=\"cpu_time\">Thời gian CPU</string>\n    <string name=\"priority\">Ưu tiên</string>\n    <string name=\"threads\">Số đề</string>\n    <string name=\"commandline_args\">Đối số dòng lệnh</string>\n    <string name=\"swap\">Tráo đổi</string>\n    <string name=\"swap_chart_info\">● %1$s đã sử dụng ● %2$s còn trống</string>\n    <string name=\"warning_working_on_root_mode\">Cảnh báo: Hoạt động bằng root thay vì ADB.</string>\n    <string name=\"magisk_denylist\">Danh sách Từ chối Magisk</string>\n    <string name=\"failed_to_enable_magisk_deny_list\">Không thể bật Magisk DenyList</string>\n    <string name=\"failed_to_disable_magisk_deny_list\">Không thể tắt Magisk DenyList</string>\n    <string name=\"mode_of_op_with_inferred_mode_of_op\">%1$s (Chế độ xử lý: %2$s)</string>\n    <string name=\"toggle_internet\">Sử dụng Internet</string>\n    <plurals name=\"usage_minutes\">\n        <item quantity=\"other\">%1$d phút</item>\n    </plurals>\n    <string name=\"vt_disclaimer\">VirusTotal và logo của nó là một thương hiệu của Chronicle LLC. App Manager — API client — cũng như nhà phát triển đều không chịu trách nhiệm về bất kỳ dữ liệu nào bạn đã có thể gửi tới VirusTotal.</string>\n    <string name=\"pref_vt_apikey_description\">Khóa API cho phép App Manager tải tệp APK lên VirusTotal cũng như tạo báo cáo. Đăng ký tại https://virustotal.com để nhận khóa API miễn phí.</string>\n    <string name=\"memory_chart_info\">● %1$s Quá trình ● %2$s đã sử dụng ● %3$s Buffers ● %4$s còn trống</string>\n    <string name=\"uses_play_app_signing_description\">Ứng dụng này chứa một số đánh dấu cho thấy rằng <i>nó có thể</i> đang sử dụng <a href=\"https://support.google.com/googleplay/android-developer/answer/9842756\">Chữ ký Google Play</a>. Với cơ chế này, các khóa ký được lưu trữ trong máy chủ của Google và Google chịu trách nhiệm ký ứng dụng. Lưu ý rằng thông tin chữ ký hợp lệ là cách duy nhất để xác minh rằng ứng dụng chưa bị sửa đổi bởi bất kỳ người nào khác ngoài nhà phát triển (và trong trường hợp này, Google cũng vậy).</string>\n    <string name=\"failed_to_change_app_op_mode\">Không thể thay đổi chế độ ủy quyền ứng dụng.</string>\n    <string name=\"failed_to_use_the_current_mode_of_operation\">Không thể sử dụng chế độ hoạt động hiện tại. Quay lại chế độ không root cho phiên này.</string>\n    <string name=\"primary_abi\">ABI chính</string>\n    <string name=\"zygote_preload_name\">Tên tải trước Zygote</string>\n    <string name=\"hidden_api_enforcement_policy\">Chính sách thực thi API ẩn</string>\n    <string name=\"binary_32_bit\">32 Bit</string>\n    <string name=\"endianness_little_endian\">Little endian</string>\n    <string name=\"so_type_shared_library\">Thư viện dùng chung</string>\n    <string name=\"save_and_exit\">Lưu và thoát</string>\n    <string name=\"hidden_api_enf_policy_none\">Không có (truy cập đầy đủ API ẩn)</string>\n    <string name=\"hidden_api_enf_policy_dark_grey_and_black\">Thực thi (danh sách cấm và gần cấm)</string>\n    <string name=\"hidden_api_enf_policy_warn\">Cảnh báo (truy cập đầy đủ API ẩn nhưng đưa ra cảnh báo)</string>\n    <string name=\"so_type_executable\">Thực thi</string>\n    <string name=\"file_modified_are_you_sure\">Tệp đã được sửa đổi. Bỏ tất cả thay đổi và thoát\\?</string>\n    <string name=\"hidden_api_enf_default_policy\">Mặc định (dựa trên loại ứng dụng)</string>\n    <string name=\"hidden_api_enf_policy_black\">Thực thi (chỉ danh sách cấm)</string>\n    <string name=\"binary_64_bit\">64 Bit</string>\n    <string name=\"endianness_big_endian\">Big endian</string>\n    <string name=\"pref_saved_apk_name_format\">Định dạng tên tệp APK đã lưu</string>\n    <string name=\"auth_manager_description\">Để chạy Intent từ một ứng dụng ngoài, bạn cần nhập thêm một trường gọi là <tt>auth</tt>, và nó phải chứa mã sau:</string>\n    <string name=\"auth_manager_title\">Quản lý ủy quyền</string>\n    <string name=\"regenerate_auth_key\">Tạo lại mã ủy quyền</string>\n    <string name=\"shortcut_icon\">Biểu tượng lối tắt</string>\n    <string name=\"pref_saved_apk_name_format_msg\">Định dạng được sử dụng để đặt tên tệp APK khi bạn lưu chúng.</string>\n    <string name=\"regenerate_auth_key_warning\">Bạn có chắc không\\? Tất cả ứng dụng bên thứ ba phải được thiết lập lại bằng mã ủy quyền mới.</string>\n    <string name=\"sort_by_installation_date\">Thời gian cài đặt</string>\n    <string name=\"backup_volume_unavailable_warning\">Ổ đĩa sao lưu đã chọn hiện không khả dụng. Nếu nó nằm trong bộ nhớ ngoài, vui lòng lắp nó vào hoặc thay đổi ổ đĩa sao lưu.</string>\n    <string name=\"change_backup_volume\">Thay đổi ổ đĩa</string>\n    <string name=\"external\">Ngoài</string>\n    <string name=\"internal\">Trong</string>\n    <string name=\"input_ssaid_instruction\">SSAID là số thập lục phân %1$d byte, tức là một chuỗi có độ dài %2$d chứa 0 đến 9 và a đến f.</string>\n    <string name=\"screen_time\">Thời gian sử dụng Màn hình</string>\n    <string name=\"tracker\">Trình theo dõi</string>\n    <string name=\"open_in_new_window\">Cửa sổ mới</string>\n    <string name=\"type_string_set\">Tập hợp xâu</string>\n    <string name=\"pref_vt_prompt_before_uploading\">Hỏi trước khi tải tệp lên.</string>\n    <string name=\"vt_confirm_uploading_file\">Tệp không có trong cơ sở dữ liệu của VirusTotal. Bạn có muốn tải tệp lên không\\?</string>\n    <string name=\"vt_confirm_upload_and_scan\">Có, tải lên và quét</string>\n    <string name=\"frozen\">Đã đóng băng</string>\n    <string name=\"restore_dots\">Khôi phục…</string>\n    <string name=\"backup_apps_cannot_be_restored\">Các ứng dụng sau không thể được khôi phục vì chúng không có bản sao lưu cơ sở:</string>\n    <string name=\"backup_apps_cannot_be_backed_up\">Các ứng dụng sau không được cài đặt và không thể được sao lưu:</string>\n    <string name=\"restart_device\">Khởi động lại thiết bị</string>\n    <string name=\"import_backups_warning_delete_backups_after_import\">Xóa các bản sao lưu sau khi nhập vào App Manager\\? Mỗi bản sao lưu được xóa lần lượt sau khi nhập thành công. Hãy chọn <b>Không</b> nếu không chắc.</string>\n    <string name=\"log_stop_recording\">Dừng ghi</string>\n    <string name=\"apk_checksums\">Mã kiểm tra APK</string>\n    <string name=\"item_select\">Chọn</string>\n    <string name=\"pref_pure_black_theme\">Chế độ đen tuyền</string>\n    <string name=\"pref_pure_black_theme_msg\">Sử dụng nền đen khi bật chế độ ban đêm.</string>\n    <string name=\"netpolicy_cannot_be_modified_for_core_apps\">Không thể thay đổi chính sách mạng cho các ứng dụng cốt lõi của Android.</string>\n    <string name=\"open_developer_options_page\">Mở trang tùy chọn nhà phát triển trong thiết đặt Android</string>\n    <string name=\"app_explorer\">Khám phá ứng dụng</string>\n    <string name=\"backup_no_backups_present\">Không có bản sao lưu.</string>\n    <string name=\"unfreeze\">Rã đông</string>\n    <string name=\"freeze\">Đóng băng</string>\n    <string name=\"usage_times_opened\">Số lần mở</string>\n    <string name=\"usage_last_used\">Sử dụng lần cuối</string>\n    <string name=\"usage_mobile_data\">Dữ liệu di động</string>\n    <string name=\"usage_wifi_data\">Dữ liệu Wi-Fi</string>\n    <string name=\"unsupported_split_apk\">Không được hỗ trợ</string>\n    <string name=\"view_changelog\">Tìm hiểu những gì mới trong bản phát hành này</string>\n    <string name=\"pref_sign_apk_error_signing_key_not_added\">Bắt buộc phải có mã khoá ký hợp lệ để ký tệp APK.</string>\n    <string name=\"troubleshooting\">Xử lý sự cố</string>\n    <string name=\"pref_reload_apps\">Tải lại các ứng dụng</string>\n    <string name=\"pref_reload_apps_msg\">Tải lại danh sách ứng dụng được lưu trong cơ sở dữ liệu của App Manager trong trường hợp xảy ra hành vi không mong đợi.</string>\n    <string name=\"changelog_type_new\">Mới</string>\n    <string name=\"changelog_type_fix\">Sửa</string>\n    <string name=\"changelog_type_improve\">Cải thiện</string>\n    <string name=\"sort_by_total_size\">Tổng kích cỡ</string>\n    <string name=\"am_command\">Lệnh <tt>am</tt></string>\n    <string name=\"pref_sign_apk_no_signing_key\">Không có mã ký</string>\n    <string name=\"freeze_unfreeze\">Đóng băng/ngừng đóng băng</string>\n    <string name=\"pref_default_freezing_method\">Phương pháp đóng băng mặc định</string>\n    <string name=\"suspend_app\">Ngừng</string>\n    <string name=\"hide_app\">Ẩn</string>\n    <plurals name=\"alert_failed_to_freeze\">\n        <item quantity=\"other\">Không thể đóng băng %1$d ứng dụng</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_unfreeze\">\n        <item quantity=\"other\">Không thể ngừng đóng băng %1$d ứng dụng</item>\n    </plurals>\n    <string name=\"disable_app_description\">Phương pháp đóng băng được khuyên dùng. Phương pháp này tắt ứng dụng và tất cả thành phần của nó, nhưng tất cả lối tắt sẽ bị mất.</string>\n    <string name=\"filter_frozen_apps\">Ứng dụng đã đóng băng</string>\n    <string name=\"user_manual\">Hướng dẫn sử dụng cho người dùng</string>\n    <string name=\"get_help\">Tìm sự giúp đỡ</string>\n    <string name=\"pref_advanced_pref\">Người dùng, định dạng tên tệp APK, thực thi song song, v.v.</string>\n    <string name=\"pref_version_changelog\">Phiên bản/Nhật ký thay đổi</string>\n    <string name=\"failed_to_freeze\">Không thể đóng băng <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g>.</string>\n    <string name=\"profile_freeze_msg\">Đóng băng hoặc ngừng đóng băng các ứng dụng dựa trên trạng thái</string>\n    <string name=\"suspend_app_description\">Đây là phương pháp đóng băng yếu nhất. Ứng dụng bị ngừng có thể vẫn hiện trên launcher nhưng sẽ bị bôi xám và không thể khởi chạy.</string>\n    <string name=\"pref_privacy_description\">Khóa màn hình, ủy quyền, v.v.</string>\n    <string name=\"pref_default_freezing_method_description\">Phương pháp được sử dụng mặc định ở những nơi không có lựa chọn phương pháp đóng băng.</string>\n    <string name=\"hide_app_description\">Phương pháp này chỉ được khuyên dùng cho việc sử dụng hàng ngày. Ứng dụng bị ẩn trông như là bị gỡ cài đặt, nhưng có thể xuất hiện lại nếu được cài đặt lại hoặc cập nhật.</string>\n    <string name=\"sort_by_frozen_app\">Đã đóng băng trước</string>\n    <string name=\"pref_privacy\">Riêng tư</string>\n    <string name=\"pref_appearance_description\">Chủ đề, hướng xoay, tính năng, v.v.</string>\n    <string name=\"file_creation_date\">Đã tạo</string>\n    <string name=\"freeze_on_phone_locked\">Tự động đóng băng ứng dụng khi điện thoại bị khóa</string>\n    <string name=\"failed_to_unfreeze\">Không thể ngừng đóng băng <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g>.</string>\n    <string name=\"file_modification_date\">Đã sửa đổi</string>\n    <string name=\"file_accessed_date\">Đã truy cập</string>\n    <string name=\"file_open_with\">Mở bằng</string>\n    <string name=\"file_change_open_with\">Đổi việc mở bằng</string>\n    <string name=\"file_shortcut_target_file\">Tệp mục tiêu</string>\n    <string name=\"file_properties\">Thuộc tính</string>\n    <string name=\"file_cut\">Cắt</string>\n    <string name=\"fm_always_open_with\">Luôn mở</string>\n    <string name=\"fm_open_with_for_this_file_only\">Chỉ đối với tệp này</string>\n    <string name=\"file_open_as\">Mở dưới dạng…</string>\n    <string name=\"file_open_with_custom_activity\">Tùy chỉnh</string>\n    <string name=\"file_open_with_os_default_dialog\">Mở bằng hộp thoại mặc định của HĐH</string>\n    <string name=\"open_as_text\">Văn bản</string>\n    <string name=\"open_as_image\">Hình ảnh</string>\n    <string name=\"open_as_video\">Video</string>\n    <string name=\"open_as_archive\">Tệp nén</string>\n    <string name=\"open_as_folder\">Thư mục</string>\n    <string name=\"open_as_other\">Khác</string>\n    <string name=\"delete_filename\">Xóa %s</string>\n    <string name=\"confirm_file_deletion\">Có, xóa đi</string>\n    <string name=\"on_unfreeze_open_application\">Mở ứng dụng sau khi ngừng đóng băng</string>\n    <string name=\"on_open_application_no_recents\">Không hiện ứng dụng đã khởi chạy ở mục Gần đây</string>\n    <string name=\"tap_to_freeze_app\">Nhấn để đóng băng</string>\n    <string name=\"waiting_for_the_phone_to_be_locked\">Đang đợi điện thoại khóa…</string>\n    <string name=\"action_stop_service\">Dừng</string>\n    <string name=\"funding_campaign_dialog_message\">Chúng tôi đang chạy <b>chiến dịch tài trợ</b> cho App Manager trong một khoảng thời gian giới hạn. Truy cập <a href=\"https://opencollective.com/app-manager#category-ABOUT\">opencollective.com/app-manager</a> để tìm hiểu thêm về chiến dịch. Thông báo này sẽ không được hiển thị lại, nhưng bạn có thể tìm thấy nó trong trang Thiết đặt trong toàn bộ chiến dịch.</string>\n    <string name=\"adb_incomplete_usb_debugging_message\">Có vẻ như Gỡ lỗi USB không được định cấu hình đúng cách. Vui lòng đọc <a href=\"https://muntashirakon.github.io/AppManager/#subsec:enable-usb-debugging\">tài liệu</a> để biết các bước bổ sung. Nếu bạn đã biết các bước, vui lòng nhấp vào “Mở” để mở tùy chọn nhà phát triển hoặc nhấp vào “Đóng” để tiếp tục sử dụng chế độ không root.</string>\n    <string name=\"sort_by_data_usage\">Dữ liệu đã dùng</string>\n    <string name=\"filter_apps_with_keystore\">Với KeyStore</string>\n    <string name=\"filter_apps_with_saf\">Với SAF</string>\n    <string name=\"filter_apps_with_ssaid\">Với SSAID</string>\n    <string name=\"action_continue\">Tiếp tục</string>\n    <string name=\"install_for_another_user\">Cài đặt cho…</string>\n    <string name=\"confirm_uninstallation\">Xác nhận gỡ cài đặt</string>\n    <string name=\"grant_required_permission\">Cấp quyền cần thiết</string>\n    <string name=\"grant_overlay_permission_message\">Cho phép App Manager hiển thị một cửa sổ nổi trên tất cả các cửa sổ khác</string>\n    <string name=\"grant_accessibility_permission_for_tracking_window_contents\">Cho phép App Manager sử dụng tính năng trợ năng để theo dõi nội dung của cửa sổ chính.</string>\n    <string name=\"class_hierarchy\">Hệ thống cấp bậc</string>\n    <string name=\"title_ui_tracker\">Trình theo dõi giao diện người dùng</string>\n    <string name=\"title_terminal_emulator\">Terminal</string>\n    <string name=\"title_labs_activity\">Phòng thí nghiệm</string>\n    <string name=\"select_a_dex2oat_compiler_filter\"><tt>dex2oat</tt> bộ lọc trình biên dịch</string>\n    <string name=\"optimize_option_compile_layouts\">Biên dịch tài nguyên bố trí</string>\n    <string name=\"optimize_option_clear_profile_data\">Xóa hồ sơ trước đây</string>\n    <string name=\"optimize_option_check_profiles\">Xem xét dữ liệu hồ sơ trong quá trình tối ưu hóa DEX</string>\n    <string name=\"optimize_option_force_compilation\">Buộc biên dịch ngay cả khi không cần thiết</string>\n    <string name=\"optimize_option_force_dexopt\">Ngay lập tức thực hiện tối ưu hóa DEX</string>\n    <string name=\"title_perform_runtime_optimization_to_apps\">Thực hiện tối ưu hóa thời gian chạy</string>\n    <string name=\"action_run\">Chạy</string>\n    <string name=\"summary_perform_runtime_optimization_to_apps\">Tối ưu hóa bố cục DEX và (trong Android 10 trở lên) để cải thiện hiệu suất của ứng dụng.</string>\n    <string name=\"action_optimize_app\">Tối ưu hóa</string>\n    <string name=\"batch_ops_runtime_optimization\">Tối ưu hóa thời gian chạy</string>\n    <plurals name=\"alert_failed_to_optimize_apps\">\n        <item quantity=\"other\">Không thể tối ưu hóa %1$d ứng dụng</item>\n    </plurals>\n    <string name=\"app_manager_build_expired\">Cần cập nhật</string>\n    <string name=\"renamed_successfully\">Đã đổi tên</string>\n    <string name=\"selinux_context\">Ngữ cảnh SELinux</string>\n    <string name=\"unix_file_permissions\">Cách thức</string>\n    <string name=\"file_group_id\">Nhóm (GID)</string>\n    <string name=\"file_owner_id\">Chủ sở hữu (UID)</string>\n    <string name=\"calculating_file_size\">Đang tính…</string>\n    <string name=\"app_manager_build_expired_message\">Để đảm bảo an toàn cho thiết bị và dữ liệu của bạn, phiên bản App Manager bạn đang sử dụng đã ngừng hoạt động. Bạn phải cập nhật lên phiên bản mới nhất để tiếp tục sử dụng hoặc gỡ cài đặt nếu không có bản cập nhật.</string>\n    <string name=\"app_manager_build_expiring_soon_warning\">Phiên bản App Manager này sẽ sớm hết hạn. Vui lòng cập nhật nó lên phiên bản mới nhất.</string>\n    <string name=\"sort_by_filename\">Tên</string>\n    <string name=\"app_can_write_and_execute_in_same_place\">Ứng dụng vi phạm <a href=\"https://en.wikipedia.org/wiki/W%5EX\">chính sách W^X</a> và có khả năng viết và thực thi trong cùng một thư mục hoặc trong cùng một phần của bộ nhớ. Điều này cho phép thực thi các tệp thực thi tùy ý bằng cách sửa đổi các tệp thực thi được nhúng trong ứng dụng hoặc bằng cách tải chúng xuống từ Internet. Trừ khi đây là hành vi dự định của ứng dụng (ví dụ: trình giả lập thiết bị đầu cuối), bạn nên tìm phiên bản mới hơn của ứng dụng nhắm mục tiêu SDK 29 (Android 10) trở lên hoặc tìm các giải pháp thay thế.</string>\n    <string name=\"sort_by_last_modified\">Sửa đổi gần đây</string>\n    <string name=\"sort_by_file_size\">Cỡ tệp</string>\n    <string name=\"sort_by_file_type\">Loại tệp</string>\n    <string name=\"option_display_dot_files\">Tệp ẩn</string>\n    <string name=\"option_display_folders_on_top\">Thư mục trên đầu</string>\n    <string name=\"export_app_list\">Xuất danh sách ứng dụng</string>\n    <string name=\"export_app_list_select_format\">Chọn định dạng xuất danh sách ứng dụng</string>\n    <string name=\"export_option_xml\">XML</string>\n    <string name=\"export_option_markdown\">Markdown</string>\n    <string name=\"adb_incomplete_usb_debugging_title\">Gỡ lỗi USB chưa hoàn thành</string>\n    <string name=\"funding_campaign_text\">Chúng tôi đang chạy <b>chiến dịch tài trợ</b> cho App Manager trong một khoảng thời gian giới hạn. <a href=\"https://opencollective.com/app-manager#category-ABOUT\">tìm hiểu thêm…</a></string>\n    <string name=\"source_stamp_verified_and_identified_to_be_from_source\">SourceStamp đã được xác minh và xác định là từ <xliff:g id=\"source\" example=\"Google Play\">%1$s</xliff:g>.</string>\n    <string name=\"title_domains_supported_by_the_app\">Miền được hỗ trợ</string>\n    <string name=\"block_unblock_components_dots\">Chặn/bỏ chặn các thành phần…</string>\n    <string name=\"unblock_components_dots\">Bỏ chặn các thành phần…</string>\n    <string name=\"block_unblock_components_description\">Chặn hoặc bỏ chặn tất cả các thành phần được xác định bởi các chữ ký đã cho</string>\n    <string name=\"pref_layout_direction\">Hướng bố trí</string>\n    <string name=\"app_info_tag_open_links\">Mở liên kết</string>\n    <string name=\"pref_zip_align\">Căn chỉnh tệp APK</string>\n    <string name=\"pref_zip_align_msg\">Việc căn chỉnh tệp APK giúp giảm mức sử dụng bộ nhớ vì có thể truy cập trực tiếp các tệp trong APK mà không cần sao chép dữ liệu vào RAM. Bước này là bắt buộc nếu <tt>extractNativeLibs</tt> được đặt thành <tt>true</tt>.</string>\n    <string name=\"title_code_editor\">Trình chỉnh sửa mã</string>\n    <string name=\"redo\">Làm lại</string>\n    <string name=\"read_only_file\">Tập tin chỉ đọc</string>\n    <string name=\"read_only_file_warning\">Không thể ghi các thay đổi vào tệp, có thể do tệp nằm trong ổ đĩa mà App Manager không có quyền ghi vào. Bạn có muốn lưu nó ở một nơi khác không\\?</string>\n    <string name=\"line_separator\">Dấu tách dòng</string>\n    <string name=\"action_replace_all\">Thay thế tất cả</string>\n    <string name=\"search_option_whole_word\">Cả từ</string>\n    <string name=\"uninstall_app_again_message\">Ứng dụng đã được gỡ cài đặt mà không xóa dữ liệu và chữ ký. Bạn có muốn gỡ cài đặt hoàn toàn không\\?</string>\n    <plurals name=\"search_results\">\n        <item quantity=\"other\">%d kết quả</item>\n    </plurals>\n    <string name=\"replacement_text\">Thay thế</string>\n    <string name=\"uninstall_app\">Gỡ cài đặt %1$s</string>\n    <string name=\"debloat_list_type\">Danh sách</string>\n    <string name=\"system_app_put_back\">Để lại chỗ cũ</string>\n    <string name=\"debloat_list_carrier\">Nhà cung cấp dịch vụ/ISP</string>\n    <string name=\"debloat_list_misc\">Linh tinh</string>\n    <string name=\"debloat_removal_safe\">An toàn</string>\n    <string name=\"debloat_removal_replace\">Thay thế</string>\n    <string name=\"debloat_removal_caution\">Cẩn trọng</string>\n    <string name=\"filter_force_stopped_apps\">Ứng dụng đã dừng</string>\n    <string name=\"debloat_removal_type\">Kiểu</string>\n    <string name=\"empty_folder\">Trống</string>\n    <plurals name=\"folder_count\">\n        <item quantity=\"other\">%d thư mục</item>\n    </plurals>\n    <plurals name=\"file_count\">\n        <item quantity=\"other\">%d tệp</item>\n    </plurals>\n    <string name=\"go_to_path\">Đi đến…</string>\n    <string name=\"copy_this_path\">Sao chép đường dẫn</string>\n    <string name=\"title_audio_player\">Máy nghe nhạc</string>\n    <plurals name=\"alert_failed_to_unblock_components\">\n        <item quantity=\"other\">Không thể bỏ chặn các thành phần cho ứng dụng %1$d</item>\n    </plurals>\n    <string name=\"static_shared_library\">Thư viện chia sẻ tĩnh</string>\n    <string name=\"warning_working_on_system_mode\">Cảnh báo: Làm việc trên hệ thống thay vì chế độ ADB.</string>\n    <string name=\"search_option_match_case\">Khớp chữ hoa chữ thường</string>\n    <string name=\"search_option_regex\">Biểu thức chính quy</string>\n    <string name=\"debloater_title\">Debloater</string>\n    <string name=\"debloat_list_oem\">OEM</string>\n    <string name=\"debloat_list_google\">Google</string>\n    <string name=\"debloat_list_aosp\">AOSP</string>\n    <string name=\"installing_package\">Đang cài đặt %1$s…</string>\n    <string name=\"backing_up_app\">Đang sao lưu %1$s…</string>\n    <string name=\"restoring_app\">Đang khôi phục %1$s…</string>\n    <string name=\"pref_installer_force_dexopt_description\">Thực hiện tối ưu hóa DEX ngay sau khi cài đặt ứng dụng mà không cần đợi hệ thống thực hiện khi hệ thống không hoạt động.</string>\n    <string name=\"folder\">Thư mục</string>\n    <string name=\"symbolic_link\">Liên kết tượng trưng</string>\n    <string name=\"create_new_symbolic_link\">Liên kết tượng trưng mới</string>\n    <string name=\"symbolic_link_not_supported\">Thư mục này không hỗ trợ tạo liên kết tượng trưng.</string>\n    <string name=\"create_new_folder\">Thư mục mới</string>\n    <string name=\"create_new_file\">Tập tin mới</string>\n    <string name=\"enter_symbolic_link_name\">Tên liên kết</string>\n    <string name=\"enter_target_path\">Đường dẫn mục tiêu</string>\n    <string name=\"invalid_target_path\">Đường dẫn không hợp lệ</string>\n    <string name=\"copy_these_paths\">Sao chép đường dẫn</string>\n    <string name=\"title_confirm_deletion\">Xác nhận xóa</string>\n    <string name=\"conflict_detected_while_copying\">Đã phát hiện xung đột</string>\n    <string name=\"copy_keep_both_file\">Giữ cả hai</string>\n    <string name=\"copied_successfully\">Đã sao chép.</string>\n    <string name=\"moved_successfully\">Đã chuyển</string>\n    <string name=\"failed_to_copy_specified_file\">Không thể sao chép “%1$s”.</string>\n    <string name=\"title_change_selinux_context\">Thay đổi bối cảnh SELinux</string>\n    <string name=\"apply_recursively\">Áp dụng cho các tập tin đính kèm</string>\n    <string name=\"change_owner_uid\">Đổi chủ (UID)</string>\n    <string name=\"change_group_gid\">Đổi nhóm (GID)</string>\n    <string name=\"change_mode\">Đổi chế độ</string>\n    <string name=\"pref_send_notifications_to_connected_devices\">Gửi thông báo đến các thiết bị được kết nối</string>\n    <string name=\"pref_send_notification_to_connected_devices_msg\">Đặt có gửi thông báo đến các thiết bị được kết nối chẳng hạn như thiết bị đeo được hay không.</string>\n    <string name=\"conflict_detected_while_copying_message\">Một mục có tên “%1$s” đã tồn tại ở vị trí này. Bạn có muốn thay thế nó\\?</string>\n    <string name=\"failed_to_delete_specified_file_after_copying\">Không thể xóa “%1$s” sau khi sao chép, có thể do không đủ quyền.</string>\n    <string name=\"debloat_removal_safe_short_description\">An toàn để loại bỏ</string>\n    <string name=\"installer_options\">Tùy chọn trình cài đặt</string>\n    <string name=\"title_alternatives_to_bloatware\">Lựa chọn thay thế</string>\n    <string name=\"pref_files_display_in_launcher\">Hiển thị “Tệp” trong ngăn kéo ứng dụng</string>\n    <string name=\"debloat_removal_replace_short_description\">Thay thế bằng thay thế</string>\n    <string name=\"browse_files\">Duyệt</string>\n    <string name=\"pref_files_msg\">Định cấu hình trình quản lý tệp.</string>\n    <string name=\"pref_files_remember_last_path_msg\">Khi tùy chọn này được bật, việc mở một cửa sổ mới sẽ mở thư mục được mở lần cuối thay vì thư mục chính.</string>\n    <string name=\"app_manager_is_unlocked\">App Manager đã được mở khóa</string>\n    <string name=\"pref_enable_auto_lock\">Tự động khóa</string>\n    <string name=\"pref_enable_persistent_session_msg\">Chạy App Manager trong nền giúp giảm độ trễ khởi tạo. Hữu ích nếu bạn sử dụng App Manager thường xuyên.</string>\n    <string name=\"debloat_removal_caution_short_description\">Chú ý khi tập luyện</string>\n    <string name=\"pref_files_remember_last_path\">Ghi nhớ đường dẫn được mở lần cuối và vị trí của nó</string>\n    <string name=\"pref_set_home\">Đặt trang chủ</string>\n    <string name=\"xposed_module_info\">Thông tin mô-đun Xposed</string>\n    <string name=\"title_description\">Mô tả</string>\n    <string name=\"module_name\">Tên mô-đun</string>\n    <string name=\"tap_to_open_notification_settings\">Nhấn để ẩn</string>\n    <string name=\"app_manager_is_running\">App Manager đang chạy</string>\n    <string name=\"action_lock_app\">Khóa</string>\n    <string name=\"pref_enable_persistent_session\">Chạy App Manager trong nền</string>\n    <string name=\"path_does_not_exist\">“%1$s” không tồn tại</string>\n    <string name=\"pref_enable_auto_lock_msg\">Khóa App Manager khi thiết bị đã khóa.</string>\n    <string name=\"path_not_a_folder\">“%1$s” không phải là một thư mục</string>\n    <string name=\"scan_report_from_pithus\">Báo cáo Pithus</string>\n    <string name=\"action_checking\">Đang kiểm tra…</string>\n    <string name=\"report_not_available\">Không có sẵn</string>\n    <string name=\"profile_modified_are_you_sure\">Hồ sơ đã được sửa đổi. Hủy tất cả thay đổi của bạn và thoát\\?</string>\n    <string name=\"apply_profile\">Áp dụng hồ sơ “%1$s”</string>\n    <string name=\"copy_profile_id\">Sao chép ID hồ sơ</string>\n    <string name=\"profile_id\">ID hồ sơ</string>\n    <string name=\"choose_a_profile_state\">Chọn trạng thái hồ sơ</string>\n    <string name=\"pref_toggle_internet_msg\">Kích hoạt các tính năng Internet trong App Manager</string>\n    <string name=\"launch_activity_dialog_title\">Khởi chạy hoạt động: Hành động bắt buộc</string>\n    <string name=\"finder_title\">Trình tìm kiếm</string>\n    <string name=\"select_filter\">Chọn một bộ lọc</string>\n    <string name=\"value_cannot_be_empty\">Giá trị không thể trống!</string>\n    <string name=\"date\">Ngày tháng</string>\n    <string name=\"size_in_bytes\">Kích thước (byte)</string>\n    <string name=\"invalid_regex\">Biểu thức chính quy không hợp lệ!</string>\n    <string name=\"virus_total\">VirusTotal</string>\n    <string name=\"pref_use_vt\">Sử dụng VirusTotal</string>\n    <string name=\"pref_cat_general\">Tổng quan</string>\n    <string name=\"pref_use_log_viewer\">Sử dụng Trình xem nhật ký</string>\n    <string name=\"pref_installer\">Sử dụng trình cài đặt</string>\n    <string name=\"adb_pairing_searching_for_port\">Đang tìm kiếm…</string>\n    <string name=\"adb_pairing_pairing_code\">Mã ghép nối</string>\n    <string name=\"adb_pairing_stop_searching\">Dừng</string>\n    <string name=\"adb_pairing_input_pairing_code\">Mã ghép nối</string>\n    <string name=\"mode_of_op_custom_command_title\">Lệnh tùy chỉnh</string>\n    <string name=\"adb_pairing_found_pairing_service_with_port\">Đã tìm thấy dịch vụ có cổng %d</string>\n    <string name=\"adb_pairing_retry_pairing\">Thử lại</string>\n    <string name=\"adb_pairing_pairing_in_progress\">Đang ghép nối…</string>\n    <string name=\"mode_of_op_custom_command\">Nếu không thể sử dụng bất kỳ chế độ nào, bạn có thể chạy lệnh sau trong bất kỳ shell nào được hỗ trợ để chạy App Manager ở chế độ đặc quyền:</string>\n    <string name=\"launch_activity_dialog_message\">App Manager đang cố gắng khởi chạy hoạt động thông qua <b>Trợ lý tìm kiếm</b> (thường là Trợ lý Google), nhưng không thể thực hiện được do không có đủ quyền. Để mở hoạt động, vui lòng kích hoạt <b>Trợ lý tìm kiếm</b> theo cách thủ công (việc này thường được thực hiện bằng cách nhấp và giữ nút Trang chủ). Nhấp vào nút <b>Đóng</b> sau khi bạn khởi chạy xong hoạt động để quay lại trợ lý ban đầu.</string>\n    <string name=\"pref_use_vt_no_internet\">VirusTotal yêu cầu Internet để hoạt động nhưng Internet chưa được kích hoạt. Trước tiên, hãy bật <a href=\"app-manager://settings/privacy_prefs/toggle_internet\">“Sử dụng Internet”</a>.</string>\n    <string name=\"netpolicy_reject_metered_background_data\">Từ chối dữ liệu nền trên mạng có đồng hồ đo</string>\n    <string name=\"netpolicy_reject_metered_data\">Từ chối dữ liệu trên mạng có đồng hồ đo</string>\n    <string name=\"netpolicy_allow_metered_background_data\">Cho phép dữ liệu nền trên mạng có đồng hồ đo ngay cả khi Trình tiết kiệm dữ liệu đang bật</string>\n    <string name=\"status_remote_server_active\">Máy chủ từ xa đang hoạt động</string>\n    <string name=\"status_remote_server_inactive\">Máy chủ từ xa không hoạt động</string>\n    <string name=\"status_remote_services_active\">Dịch vụ từ xa đang hoạt động</string>\n    <string name=\"status_remote_services_inactive\">Dịch vụ từ xa không hoạt động</string>\n    <string name=\"status_connecting\">Đang kết nối…</string>\n    <string name=\"status_connecting_via_mode\">Đang kết nối qua %s</string>\n    <string name=\"status_connected_via_mode\">Đã kết nối qua %s</string>\n    <string name=\"status_not_connected_via_mode\">Không thể kết nối qua %s</string>\n    <string name=\"adb_pairing_instruction\">Vui lòng điều hướng đến tùy chọn nhà phát triển để bật gỡ lỗi không dây và tạo mã ghép nối.</string>\n    <string name=\"mode_of_op_alternative_custom_command\">Nếu bạn gặp lỗi “quyền bị từ chối” với lệnh trên, thay vào đó hãy chạy lệnh sau:</string>\n    <string name=\"sensors\">Cảm biến</string>\n    <string name=\"tag_sensors_disabled\">Cảm biến bị vô hiệu hóa</string>\n    <string name=\"pref_use_system_font\">Sử dụng phông chữ hệ thống</string>\n    <string name=\"actual_installer\">Trình cài đặt thực tế</string>\n    <string name=\"apk_source\">Nguồn APK</string>\n    <string name=\"backup_cache\">Bộ nhớ đệm</string>\n    <string name=\"activity_name\">Tên hoạt động</string>\n</resources>"
  },
  {
    "path": "app/src/main/res/values-zh-rCN/disclaimer.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- SPDX-License-Identifier: GPL-3.0-or-later --><resources>\n    <string name=\"disclaimer_header\">免责声明</string>\n    <string name=\"disclaimer_body\">App Manager 提供的与 root 权限相关的操作可能会对设备造成损害，App Manager 不对任何因使用不当而造成的损害负责。\n\\n\n\\n如果你不清楚 root 相关知识和风险，请勿使用该应用内与 root 有关的选项和（或）操作。\n\\n\n\\n我提供的所有其他应用和网站链接仅为方便用户浏览，不对这些链接所指向的内容负责。\n\\n\n\\n使用 App Manager 则表示你已同意该免责声明并自己承担相应责任，且知晓我不会因你对设备进行的任操作所带来的任何负面影响负责。</string>\n    <string name=\"disclaimer_footer\">© 2020–2024 Muntashir Al-Islam</string>\n    <string name=\"disclaimer_agree_forever\">不再显示</string>\n    <string name=\"disclaimer_agree\">我已阅读并同意免责声明</string>\n    <string name=\"disclaimer_exit\">退出</string>\n</resources>"
  },
  {
    "path": "app/src/main/res/values-zh-rCN/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- SPDX-License-Identifier: GPL-3.0-or-later --><resources xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:tools=\"http://schemas.android.com/tools\">\n    <string name=\"_lang_tag\" translatable=\"false\">zh-CN</string>\n    <string name=\"uninstall\">卸载</string>\n    <string name=\"permissions\">权限</string>\n    <string name=\"require_no_permission\">无需权限</string>\n    <string name=\"activities\">活动</string>\n    <string name=\"launch\">打开</string>\n    <string name=\"refresh\">刷新</string>\n    <string name=\"no_activities\">无活动</string>\n    <string name=\"receivers\">广播接收器</string>\n    <string name=\"no_receivers\">无广播接收器</string>\n    <string name=\"providers\">内容提供器</string>\n    <string name=\"no_providers\">无提供器</string>\n    <string name=\"launch_mode\">启动模式</string>\n    <string name=\"task_affinity\">任务关联</string>\n    <string name=\"sort_by_last_update\">最后更新</string>\n    <string name=\"authority\">授权</string>\n    <string name=\"service\">服务</string>\n    <string name=\"no_service\">无服务</string>\n    <string name=\"orientation\">屏幕旋转</string>\n    <string name=\"soft_input\">软键盘输入模式</string>\n    <string name=\"flags\">标志(Flags)</string>\n    <string name=\"grant_uri_permission\">授予 URI 权限</string>\n    <string name=\"path_permissions\">路径授权</string>\n    <string name=\"read\">读取</string>\n    <string name=\"write\">写入</string>\n    <string name=\"patterns_allowed\">允许的模式</string>\n    <string name=\"declared_permission\">自定义权限</string>\n    <string name=\"shared_libs\">共享库</string>\n    <string name=\"group\">群组</string>\n    <string name=\"uses_feature\">功能声明</string>\n    <string name=\"no_feature\">无</string>\n    <string name=\"sort_by_shared_user_id\">共享用户ID</string>\n    <string name=\"shared_user_id\">共享用户ID</string>\n    <string name=\"sort_by_sha\">签名</string>\n    <string name=\"signatures\">签名</string>\n    <string name=\"app_signing_no_signatures\">无有效签名</string>\n    <string name=\"configurations\">配置</string>\n    <string name=\"no_configurations\">无配置</string>\n    <string name=\"input_features\">输入特性</string>\n    <string name=\"manifest\">应用清单（Manifest）</string>\n    <string name=\"error\">错误</string>\n    <string name=\"loading\">加载中…</string>\n    <!-- &#8230; = ... -->\n    <string name=\"sort_by_app_label\">应用程序标签</string>\n    <string name=\"sort_by_package_name\">包名</string>\n    <string name=\"sort_by_domain\">用户应用优先</string>\n    <string name=\"sort_by_target_sdk\">目标 SDK</string>\n    <string name=\"data_received\">已接收的数据</string>\n    <string name=\"data_transmitted\">已发送数据</string>\n    <string name=\"data_usage_msg\">数据使用量</string>\n    <string name=\"about\">关于</string>\n    <string name=\"data_size\">数据</string>\n    <string name=\"cache_size\">缓存</string>\n    <string name=\"obb_size\">数据包</string>\n    <string name=\"media_size\">媒体</string>\n    <string name=\"app_not_installed\">应用未安装</string>\n    <string name=\"system\">系统</string>\n    <string name=\"user\">用户</string>\n    <string name=\"sort\">排序</string>\n    <string name=\"version_name_with_code\">版本<xliff:g id=\"version_name\" example=\"2.5.17\">%1$s</xliff:g> (<xliff:g id=\"version_code\" example=\"365\">%2$d</xliff:g>)</string>\n    <string name=\"app_info\">应用信息</string>\n    <string name=\"system_app\">系统应用</string>\n    <string name=\"user_app\">用户应用</string>\n    <string name=\"paths_and_directories\">路径 &amp; 目录</string>\n    <string name=\"source_dir\">资源目录</string>\n    <string name=\"data_dir\">数据目录</string>\n    <string name=\"sdk_min\">最低</string>\n    <string name=\"sdk_max\">目标</string>\n    <string name=\"sdk_flags\">标志位(Flags)</string>\n    <string name=\"more_info\">更多信息</string>\n    <string name=\"date_installed\">安装时间</string>\n    <string name=\"date_updated\">更新时间</string>\n    <string name=\"installer_app\">安装来源</string>\n    <string name=\"user_id\">用户 ID</string>\n    <string name=\"main_activity\">主活动</string>\n    <string name=\"empty_package_name\">包名为空</string>\n    <string name=\"error_creating_shortcut\">无法创建快捷方式</string>\n    <string name=\"error_verbose_pin_shortcut\">当前启动器尚不支持 “PinShortcut”。无法创建快捷方式。</string>\n    <string name=\"starting_activity\">启动活动: <xliff:g id=\"activity_name\" example=\".main.MainActivity\">%1$s</xliff:g></string>\n    <string name=\"create_shortcut\">创建快捷方式</string>\n    <string name=\"shortcut_name\">快捷方式名称</string>\n    <string name=\"package_name\">应用包名</string>\n    <string name=\"class_name\">类名</string>\n    <string name=\"icon_picker\">选择图标</string>\n    <string name=\"license\">许可协议</string>\n    <string name=\"third_party\">第三方库和图标</string>\n    <string name=\"credits\">鸣谢</string>\n    <string name=\"credits_message\">感谢下列项目作者：\n\\n- The Android Open Source Project \n\\n- <a href=\"https://github.com/zhaobozhen/libraries\">Absinthe\\'s libraries</a> \n\\n- <a href=\"https://github.com/butzist/ActivityLauncher\">Activity Launcher</a> \n\\n- <a href=\"https://bitbucket.org/oF2pks/fdroid-applications-info\">Apps_packages Info</a> \n\\n- <a href=\"https://github.com/zhaobao/AppsMonitor\">AppsMonitor</a> \n\\n- <a href=\"https://github.com/8enet/AppOpsX\">AppOpsX</a> \n\\n- <a href=\"https://github.com/gabrielemariotti/changeloglib\">ChangeLog Library</a> \n\\n- <a href=\"https://bitbucket.org/oF2pks/fdroid-classyshark3xodus\">ClassySharkAndroid</a> \n\\n- <a href=\"https://github.com/billthefarmer/editor\">Editor</a> \n\\n- <a href=\"https://github.com/Raival-e/File-Explorer\">File Explorer</a> \n\\n- <a href=\"https://github.com/nex3z/FlowLayout\">FlowLayout</a> \n\\n- <a href=\"https://github.com/k3b/intent-intercept\">Intent Intercept</a> \n\\n- <a href=\"https://github.com/YarikSOffice/lingver\">Lingver</a> \n\\n- <a href=\"https://github.com/topjohnwu/Magisk\">Magisk</a> \n\\n- <a href=\"https://github.com/zhanghai/MaterialFiles\">Material Files</a> \n\\n- <a href=\"https://github.com/pluscubed/matlog\">MatLog</a> \n\\n- <a href=\"https://github.com/matrix-org/matrix-android-sdk\">Matrix Android SDK</a> \n\\n- <a href=\"https://github.com/jensstein/oandbackup\">OAndBackup</a> \n\\n- <a href=\"https://github.com/open-keychain/open-keychain\">Open Keychain</a> \n\\n- <a href=\"https://github.com/Aefyr/SAI\">SAI</a> \n\\n- <a href=\"https://github.com/RikkaApps/Shizuku\">Shizuku</a> \n\\n- <a href=\"https://github.com/eclipse/tm4e\">tm4e</a> \n\\n- <a href=\"https://github.com/tuyafeng/Watt\">Watt</a></string>\n    <string name=\"word_wrap\">自动换行</string>\n    <string name=\"class_viewer\">类查看器</string>\n    <string name=\"toggle_class_listing\">切换类列表</string>\n    <string name=\"found_trackers\">已找到跟踪器:</string>\n    <string name=\"tracker_details\">跟踪器详细信息</string>\n    <string name=\"tracker_classes\">跟踪器类</string>\n    <string name=\"all_classes\">全部类型</string>\n    <plurals name=\"main_list_date_days\">\n        <item quantity=\"other\"><xliff:g id=\"last_update_date\" example=\"20/10/2020\">%1$s</xliff:g> <xliff:g id=\"day_no\" example=\"5\">%2$d</xliff:g> 天</item>\n    </plurals>\n    <string name=\"no_shared_libs\">无共享库</string>\n    <string name=\"no_tracker_class\">无跟踪器类</string>\n    <string name=\"app_usage\">应用使用情况</string>\n    <string name=\"usage_weekly\">每周</string>\n    <string name=\"usage_today\">今天</string>\n    <string name=\"usage_7_days\">最近七天</string>\n    <plurals name=\"usage_months\">\n        <item quantity=\"other\">%1$d 个月</item>\n    </plurals>\n    <plurals name=\"usage_days\">\n        <item quantity=\"other\">%1$d 天</item>\n    </plurals>\n    <plurals name=\"usage_hours\">\n        <item quantity=\"other\">%1$d 小时</item>\n    </plurals>\n    <string name=\"usage_less_than_a_minute\">不足一分钟</string>\n    <string name=\"go_back\">返回</string>\n    <string name=\"go\">前往</string>\n    <string name=\"grant_usage_access\">授予使用情况访问权限</string>\n    <string name=\"grant_usage_acess_message\">用于展示应用程序的使用信息。</string>\n    <string name=\"share_apk\">分享 APK</string>\n    <string name=\"failed_to_extract_apk_file\">无法提取 APK 文件</string>\n    <string name=\"menu_remove_rules\">删除规则</string>\n    <string name=\"menu_apply_rules\">应用规则</string>\n    <string name=\"search\">搜索</string>\n    <string name=\"dev_protected_data_dir\">受设备保护的数据目录</string>\n    <string name=\"native_library_dir\">原生 JNI 库目录</string>\n    <string name=\"process_name\">进程名称</string>\n    <string name=\"no_code\">无代码</string>\n    <string name=\"requested_large_heap\">大堆内存(Large heap)</string>\n    <string name=\"updated_app\">已更新</string>\n    <string name=\"debuggable\">可调试</string>\n    <string name=\"test_only\">仅测试</string>\n    <string name=\"shared_prefs\">共享首选项(Shared Prefs)</string>\n    <string name=\"databases\">数据库</string>\n    <string name=\"save\">保存</string>\n    <string name=\"discard\">放弃</string>\n    <string name=\"delete\">刪除</string>\n    <string name=\"deleted_successfully\">已删除</string>\n    <string name=\"deletion_failed\">刪除失败</string>\n    <string name=\"saved_successfully\">已保存</string>\n    <string name=\"saving_failed\">保存失败，请再试一次。</string>\n    <string name=\"string_value\">字符串</string>\n    <string name=\"long_integer_value\">长整数值</string>\n    <string name=\"integer_value\">整数值</string>\n    <string name=\"decimal_value\">浮点数/十进制数</string>\n    <string name=\"boolean_value\">布尔值</string>\n    <string name=\"key_name\">键名</string>\n    <string name=\"select_type\">选择一个类型</string>\n    <string name=\"add_item\">新增项目</string>\n    <string name=\"done\">已完成</string>\n    <string name=\"type_boolean\">布尔值(Boolean)</string>\n    <string name=\"type_float\">浮点数(Decimal Number/Float)</string>\n    <string name=\"type_int\">整型(Integer)</string>\n    <string name=\"type_long\">长整型(Long integer)</string>\n    <string name=\"type_string\">字符串(Characters/String)</string>\n    <string name=\"error_evaluating_input\">无法验证输入</string>\n    <string name=\"key_name_cannot_be_null\">键名不能为空</string>\n    <string name=\"disabled_app\">已禁用</string>\n    <string name=\"no_usage_in_this_time_range\">在此时间范围内没有使用</string>\n    <string name=\"no_content\">没有内容</string>\n    <string name=\"view_in_settings\">在设置中查看</string>\n    <string name=\"uninstall_app_message\">要卸载此应用吗？</string>\n    <string name=\"failed_to_uninstall\">无法卸载 <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g>.</string>\n    <string name=\"uninstalled_successfully\"><xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g> 已被卸载.</string>\n    <string name=\"uninstall_system_app_message\">这是一个系统应用。您确定要为当前用户卸载此应用吗？</string>\n    <string name=\"stopped\">已停止</string>\n    <string name=\"disable\">禁用</string>\n    <string name=\"enable\">启用</string>\n    <string name=\"force_stop\">强行停止</string>\n    <string name=\"failed_to_stop\">无法停用 <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g>.</string>\n    <string name=\"storage_and_cache\">存储和缓存</string>\n    <string name=\"total_size\">总计</string>\n    <string name=\"app_size\">应用程序</string>\n    <string name=\"app_ops\">App Ops</string>\n    <string name=\"no_app_ops\">无 AppOps 权限</string>\n    <string name=\"failed_to_enable_op\">无法启用请求的 AppOps 权限</string>\n    <string name=\"failed_to_disable_op\">无法禁用请求的 AppOps</string>\n    <string name=\"rules_not_applied\">规则未被应用</string>\n    <string name=\"str_logo\">Logo</string>\n    <string name=\"pref_global_blocking_enabled\">即时组件拦截</string>\n    <string name=\"pref_global_blocking_enabled_msg\">允许您拦截任何应用程序的任何组件，而无需拦截该应用程序。</string>\n    <string name=\"usage_access\">使用情况访问权限</string>\n    <string name=\"app_settings\">设置</string>\n    <string name=\"usage_yesterday\">昨天</string>\n    <string name=\"exodus_link\">\\u03b5xodus 链接</string>\n    <string name=\"sort_by_blocked_components\">已拦截组件优先</string>\n    <string name=\"external_data_dir\">外部资料目录</string>\n    <string name=\"external_multiple_data_dir\">外部数据目录 <xliff:g id=\"dir_no\" example=\"1\">%1$d</xliff:g></string>\n    <plurals name=\"no_of_times_opened\">\n        <item quantity=\"other\">%1$d 次</item>\n    </plurals>\n    <string name=\"sort_by_last_used\">上次使用</string>\n    <string name=\"sort_by_screen_time\">屏幕开启时间</string>\n    <string name=\"sort_by_times_opened\">打开次数</string>\n    <string name=\"sort_by_mobile_data\">移动数据</string>\n    <string name=\"pref_import_export_blocking_rules\">导入/导出阻止规则</string>\n    <string name=\"pref_import_export_blocking_rules_msg\">导入/导出规则，从 Watt 或 Blocker 导入外部规则。</string>\n    <string name=\"pref_import_watt\">从 Watt 导入</string>\n    <string name=\"pref_import_blocker\">从 Blocker 导入</string>\n    <string name=\"the_import_was_successful\">已导入</string>\n    <string name=\"the_export_was_successful\">已导出</string>\n    <plurals name=\"failed_to_import_files\">\n        <item quantity=\"other\">无法导入 %1$d 个文件。</item>\n    </plurals>\n    <string name=\"apk_updater\">APK 更新器</string>\n    <string name=\"running_apps\">正在运行的应用</string>\n    <string name=\"kill_process\">终止</string>\n    <string name=\"disable_background_run\">防止后台操作</string>\n    <string name=\"pid_and_ppid\">进程ID: %1$d, 父进程 ID: %2$d</string>\n    <string name=\"memory_virtual_memory\">内存: %1$s, 虚拟内存: %2$s</string>\n    <string name=\"user_and_uid\">用户: <xliff:g id=\"user_name\" example=\"root\">%1$s</xliff:g> (<xliff:g id=\"user_id\" example=\"0\">%2$d</xliff:g>)</string>\n    <string name=\"clear_data\">删除数据</string>\n    <string name=\"backup_restore\">备份/还原</string>\n    <string name=\"disable_background\">防止后台操作</string>\n    <string name=\"export_blocking_rules\">导出屏蔽规则</string>\n    <plurals name=\"alert_failed_to_clear_data\">\n        <item quantity=\"other\">无法清除数据从%1$d个应用</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_uninstall\">\n        <item quantity=\"other\">无法卸载%1$d个应用</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_disable_background\">\n        <item quantity=\"other\">无法阻止%1$d个应用在后台运行</item>\n    </plurals>\n    <string name=\"the_operation_was_successful\">操作成功</string>\n    <plurals name=\"alert_failed_to_force_stop\">\n        <item quantity=\"other\">无法强制停止%1$d个应用</item>\n    </plurals>\n    <string name=\"toggle_kill_for_system_apps\">切换杀死系统应用程序</string>\n    <string name=\"permission_name\">权限名称</string>\n    <string name=\"mode\">模式</string>\n    <string name=\"running\">运行中</string>\n    <string name=\"duration\">持续时间</string>\n    <string name=\"accept_time\">接受的时间</string>\n    <string name=\"reject_time\">拒绝的时间</string>\n    <string name=\"ago\">之前</string>\n    <string name=\"pref_import\">导入</string>\n    <string name=\"pref_export\">导出</string>\n    <string name=\"import_options\">导出选项</string>\n    <string name=\"export_options\">导入选项</string>\n    <string name=\"import_failed\">导入失败 ！</string>\n    <string name=\"export_failed\">导出失败 ！</string>\n    <string name=\"keyboard_type\">键盘类型</string>\n    <string name=\"navigation\">网站链接</string>\n    <string name=\"touchscreen\">触摸屏</string>\n    <string name=\"pref_export_msg\">导出应用管理器中配置的阻止规则到外部存储。</string>\n    <string name=\"pref_import_msg\">导入先前从应用管理器导出的拦截规则。</string>\n    <string name=\"pref_import_watt_msg\">从 Watt 导入阻止规则，每个文件都包含针对单个命名包的规则，诸如 <tt> packagename.xml</tt>等。</string>\n    <string name=\"pref_import_blocker_msg\">从 Blocker 导入拦截规则，每个文件包含单个软件包的规则。</string>\n    <string name=\"pref_app_theme\">应用主题</string>\n    <string name=\"follow_system\">跟随系统</string>\n    <string name=\"battery_mode\">电量模式</string>\n    <string name=\"day\">日间模式</string>\n    <string name=\"night\">夜间</string>\n    <string name=\"select_theme\">主题</string>\n    <string name=\"apply\">应用</string>\n    <string name=\"pref_about_msg\">应用程序管理器版本、许可、致谢等。</string>\n    <string name=\"version\">版本</string>\n    <string name=\"sort_by_wifi_data\">Wi-Fi 数据</string>\n    <string name=\"block_trackers\">屏蔽所有跟踪器</string>\n    <string name=\"sort_by_component_name\">组件名称</string>\n    <string name=\"reset_to_default\">重置为默认值</string>\n    <string name=\"deny_dangerous_app_ops\">拒绝危险的AppOps权限</string>\n    <string name=\"sort_by_app_ops_names\">AppOps 名称</string>\n    <string name=\"sort_by_denied_app_ops\">优先拒绝</string>\n    <string name=\"sort_by_app_ops_values\">AppOps 值</string>\n    <string name=\"sort_by_permission_names\">权限名称</string>\n    <string name=\"sort_by_dangerous_permissions\">危险优先</string>\n    <string name=\"sort_by_denied_permissions\">拒绝优先</string>\n    <string name=\"deny_dangerous_permissions\">拒绝有危险的权限</string>\n    <string name=\"sort_by_tracker_components\">跟踪器优先</string>\n    <string name=\"unknown_op\">未知的操作</string>\n    <plurals name=\"alert_failed_to_disable_trackers\">\n        <item quantity=\"other\">无法禁用来自%1$d个应用的跟踪器</item>\n    </plurals>\n    <string name=\"failed_to_grant_permission\">无法授予权限</string>\n    <string name=\"failed_to_revoke_permission\">无法拒绝权限</string>\n    <string name=\"failed_to_reset_app_ops\">无法重置 App ops 权限</string>\n    <string name=\"failed_to_deny_dangerous_perms\">无法拒绝所有危险权限</string>\n    <string name=\"failed_to_deny_dangerous_app_ops\">无法撤消所有危险的 app ops 权限</string>\n    <string name=\"launch_app\">启动</string>\n    <string name=\"never_ask\">从不询问</string>\n    <string name=\"one_click_ops\">一键操作</string>\n    <string name=\"changelog\">更新日志</string>\n    <string name=\"external_apk_no_app_op\">外部 APK 没有任何 AppOps 权限</string>\n    <string name=\"manifest_viewer\">清单查看器</string>\n    <plurals name=\"no_of_trackers\">\n        <item quantity=\"other\">%1$d个跟踪器</item>\n    </plurals>\n    <string name=\"install\">安装</string>\n    <string name=\"update\">升级</string>\n    <string name=\"source_code\">源代码</string>\n    <string name=\"pref_import_existing\">导入现有规则</string>\n    <string name=\"pref_import_existing_msg\">将被其他应用禁用的组件添加到 App Manager.。使用此工具时要小心，因为可能有许多误报。 请只选择您确定的应用。</string>\n    <string name=\"clear_cache\">清除缓存</string>\n    <string name=\"block_unblock_trackers_description\">禁用或解禁所有已安装应用的广告和跟踪组件</string>\n    <string name=\"block_components_dots\">屏蔽组件…</string>\n    <string name=\"deny_app_ops_description\">设置由常数值标识的应用操作模式，如 <tt>63</tt> 或 <tt> RUN_IN_BACKGROUND</tt></string>\n    <string name=\"clear_data_from_uninstalled_apps\">清除已卸载应用的数据</string>\n    <string name=\"clear_data_from_uninstalled_apps_description\">清除使用 <tt> DONT_DELETE_DATA </tt>标志卸载的应用中的数据</string>\n    <string name=\"clear_app_cache\">清除缓存</string>\n    <string name=\"clear_app_cache_description\">清除所有应用程序的缓存</string>\n    <string name=\"no_tracker_found\">没有发现跟踪器</string>\n    <string name=\"failed_packages\">错误的软件包</string>\n    <string name=\"input_signatures\">输入签名</string>\n    <string name=\"input_signatures_description\">用空格隔开输入的签名，如<tt>com.facebook org.app2 com.app3</tt>等。</string>\n    <string name=\"filtered_packages\">已过滤的软件包</string>\n    <string name=\"input_app_ops\">输入 AppOps 权限</string>\n    <string name=\"input_app_ops_description\">用空格隔开输入的AppOps称和/或常数，如 <tt>WAKE_LOCK 63 72 CAMERA</tt> 等。</string>\n    <string name=\"only_works_in_root_or_adb_mode\">仅在 root 或 ADB 模式下工作</string>\n    <string name=\"failed_to_parse_some_numbers\">无法解析某些数字</string>\n    <plurals name=\"no_of_splits\">\n        <item quantity=\"other\">%1$d 个拆分</item>\n    </plurals>\n    <string name=\"termux\">Termux 终端模拟器</string>\n    <string name=\"package_name_is_installed_successfully\"><xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g> 已安装</string>\n    <string name=\"filter\">筛选器</string>\n    <string name=\"filter_user_apps\">用户应用</string>\n    <string name=\"filter_system_apps\">系统应用</string>\n    <string name=\"filter_apps_with_rules\">被阻止</string>\n    <string name=\"select_all\">全选</string>\n    <string name=\"installed_version\">已安装版本</string>\n    <string name=\"trackers\">跟踪器</string>\n    <string name=\"components\">组件</string>\n    <string name=\"features\">特性</string>\n    <string name=\"whats_new\">更新内容</string>\n    <string name=\"blocking_rules\">屏蔽规则</string>\n    <string name=\"external_data\">外部数据</string>\n    <string name=\"data\">数据 </string>\n    <string name=\"backup\">备份</string>\n    <string name=\"restore\">还原</string>\n    <string name=\"delete_backup\">删除备份</string>\n    <string name=\"backup_options\">备份选项</string>\n    <plurals name=\"failed_to_backup_some_apk_files\">\n        <item quantity=\"other\">无法备份 %1$d个应用</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_backup\">\n        <item quantity=\"other\">无法备份%1$d个应用</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_restore\">\n        <item quantity=\"other\">无法还原%1$d个应用</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_delete_backup\">\n        <item quantity=\"other\">无法删除%1$d个备份</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_unblock_trackers\">\n        <item quantity=\"other\">无法解除来自 %1$d 个应用的跟踪器</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_block_components\">\n        <item quantity=\"other\">无法拦截%1$d个应用的组件</item>\n    </plurals>\n    <string name=\"apply_to_system_apps\">应用到系统应用</string>\n    <string name=\"apply_to_system_apps_question\">也应用于系统应用？如果不确定，请选择“否”。</string>\n    <string name=\"no\">否</string>\n    <string name=\"yes\">是</string>\n    <string name=\"skip_signature_checks\">跳过签名检查</string>\n    <string name=\"clear_data_message\">您确定要清除此应用的数据吗？</string>\n    <string name=\"clear\">清除</string>\n    <string name=\"block\">屏蔽</string>\n    <string name=\"unblock\">取消屏蔽</string>\n    <string name=\"block_unblock_trackers\">阻止/解除阻止跟踪器</string>\n    <string name=\"no_matching_package_found\">找不到任何此类应用</string>\n    <string name=\"export_icon\">提取图标</string>\n    <string name=\"open_in_termux\">在 Termux 中打开</string>\n    <string name=\"run_in_termux\">在 Termux 中运行</string>\n    <string name=\"website\">网址</string>\n    <string name=\"pref_remove_all_rules\">删除所有规则</string>\n    <string name=\"pref_remove_all_rules_msg\">权限已被授予，App Ops 和组件将回到它们的默认值。</string>\n    <string name=\"are_you_sure\">您确定吗？</string>\n    <string name=\"filter_apps_with_activities\">可打开</string>\n    <string name=\"toggle_default_app_ops\">切换默认 AppOps</string>\n    <string name=\"installer_error_aborted\">安装失败，要么因为它被取消，要么因为会话被意外关闭</string>\n    <string name=\"installer_error_blocked_device\">设备</string>\n    <string name=\"installer_error_blocked\">安装被阻止, 由 <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g></string>\n    <string name=\"installer_error_conflict\">无法安装这个应用，因为一个已安装的应用程序的包名和它一样</string>\n    <string name=\"installer_error_incompatible\">该应用与此设备不兼容</string>\n    <string name=\"installer_error_bad_apks\">无效的 APK 文件</string>\n    <string name=\"installer_error_storage\">没有足够的存储空间安装该应用</string>\n    <string name=\"installer_error_generic\">安装错误</string>\n    <string name=\"installer_error_lidl_rom\">您的ROM与无root安装程序不兼容。</string>\n    <string name=\"failed_to_fetch_package_info\">无法获取软件包信息</string>\n    <string name=\"batch_ops\">批量操作</string>\n    <string name=\"operation_running\">运行中的操作……</string>\n    <string name=\"full_stop_tap_to_see_details\">. 点按查看详情.</string>\n    <string name=\"try_again\">再试一次</string>\n    <string name=\"install_app_message\">你想要安装该应用吗？</string>\n    <string name=\"reinstall\">重新安装</string>\n    <string name=\"unblock_trackers\">取消屏蔽跟踪器</string>\n    <string name=\"package_installer\">软件包安装程序</string>\n    <string name=\"install_in_progress\">正在安装…</string>\n    <string name=\"installer_error_security\">无法访问APK文件</string>\n    <string name=\"installer_error_session_create\">无法创建安装程序会话</string>\n    <string name=\"installer_error_session_write\">无法写入安装程序会话</string>\n    <string name=\"installer_error_session_commit\">不能提交APK文件</string>\n    <string name=\"installer_error_session_abandon\">无法中断安装包会话</string>\n    <string name=\"backup_apk_files\">APK 文件</string>\n    <string name=\"backup_obb_media\">OBB和媒体文件</string>\n    <string name=\"failed_to_extract_obb_files\">无法提取OBB文件</string>\n    <string name=\"obb_files_extracted_successfully\">已提取OBB文件</string>\n    <string name=\"backup_multiple\">备份多个应用</string>\n    <string name=\"backup_all_users\">所有用户</string>\n    <string name=\"pref_app_language\">语言</string>\n    <string name=\"auto\">自动</string>\n    <string name=\"choose_language\">更改语言</string>\n    <string name=\"navigation_dial_pad\">拨号键盘</string>\n    <string name=\"keyboard_12_keys\">12 键</string>\n    <string name=\"keyboard_qwerty\">QWERTY 布局</string>\n    <string name=\"_undefined\">未定义</string>\n    <string name=\"orientation_user\">用户</string>\n    <string name=\"orientation_reverse_landscape\">镜像反转横屏</string>\n    <string name=\"orientation_reverse_portrait\">镜像反转竖屏</string>\n    <string name=\"orientation_portrait\">竖屏</string>\n    <string name=\"orientation_landscape\">横屏</string>\n    <string name=\"orientation_unspecified\">未指定</string>\n    <string name=\"launch_mode_single_task\">单个任务</string>\n    <string name=\"launch_mode_single_instance\">单实例</string>\n    <string name=\"base_apk\">基础 APK</string>\n    <string name=\"split_feature_name\">特性: <xliff:g id=\"feature_name\" example=\"Visualizer\">%1$s</xliff:g></string>\n    <string name=\"unknown_split_for_feature\"><xliff:g id=\"split_name\" example=\"some_split\">%1$s</xliff:g> 用于特性 <xliff:g id=\"feature_name\" example=\"Visualizer\">%2$s</xliff:g></string>\n    <string name=\"density_split_for_feature\"><xliff:g id=\"split_name\" example=\"xxdpi\">%1$s</xliff:g> (<xliff:g id=\"dpi_no\" example=\"480\">%2$d</xliff:g> DPI) 资源, 用于特性 <xliff:g id=\"feature_name\" example=\"Visualizer\">%3$s</xliff:g></string>\n    <string name=\"density_split_for_base_apk\"><xliff:g id=\"split_name\" example=\"xxdpi\">%1$s</xliff:g> (<xliff:g id=\"dpi_no\" example=\"480\">%2$d</xliff:g> DPI) 资源, 用于基础APK</string>\n    <string name=\"unknown_split_for_base_apk\"><xliff:g id=\"split_name\" example=\"some_split\">%1$s</xliff:g>拆分，用于基础 APK</string>\n    <string name=\"touchscreen_finger\">手指</string>\n    <string name=\"required\">必需的</string>\n    <string name=\"orientation_sensor\">根据物理方向传感器确定方向</string>\n    <string name=\"orientation_no_sensor\">无传感器</string>\n    <string name=\"orientation_locked\">已锁定</string>\n    <string name=\"launch_mode_multiple\">多个</string>\n    <string name=\"locale_split_for_base_apk\"><xliff:g id=\"split_name\" example=\"English\"> %1$s</xliff:g>语言环境，用于基础APK</string>\n    <string name=\"locale_split_for_feature\"><xliff:g id=\"split_name\" example=\"English\">%1$s</xliff:g> 语言环境, 用于特性 <xliff:g id=\"feature_name\" example=\"Visualizer\">%2$s</xliff:g></string>\n    <string name=\"abi_split_for_base_apk\"><xliff:g id=\"split_name\" example=\"arm64_v8a\">%1$s</xliff:g>代码，属于基础APK</string>\n    <string name=\"abi_split_for_feature\"><xliff:g id=\"split_name\" example=\"arm64_v8a\">%1$s</xliff:g> 代码, 用于 <xliff:g id=\"feature_name\" example=\"Visualizer\">%2$s</xliff:g></string>\n    <string name=\"touchscreen_stylus\">触控笔</string>\n    <string name=\"open_pgp_provider\">OpenPGP 提供商</string>\n    <string name=\"systemless_app\">Systemless 应用</string>\n    <string name=\"cancel\">取消</string>\n    <string name=\"ok\">好</string>\n    <string name=\"input_backup_name_description\">备份文件名称不应以数字开头，也不应包含任何空格。如果您想使用当前日期时间格式的命名，请将其保留为空。</string>\n    <string name=\"input_backup_name\">备份名称</string>\n    <string name=\"downgrade\">降级</string>\n    <string name=\"process_state_with_extra\">状态: <xliff:g id=\"process_state\" example=\"Sleeping\">%1$s</xliff:g> (<xliff:g id=\"state_extra\" example=\"High priority\">%2$s</xliff:g>)</string>\n    <string name=\"process_state\">状态: <xliff:g id=\"process_state\" example=\"Sleeping\">%1$s</xliff:g></string>\n    <string name=\"state_multithreaded\">多线程</string>\n    <string name=\"state_foreground\">前台</string>\n    <string name=\"state_session_leader\">会话首领</string>\n    <string name=\"state_locked_memory\">上锁的内存</string>\n    <string name=\"state_low_priority\">低优先级</string>\n    <string name=\"state_high_priority\">高优先级</string>\n    <string name=\"state_unknown\">未知</string>\n    <string name=\"state_waking\">苏醒</string>\n    <string name=\"state_idle\">空闲</string>\n    <string name=\"state_zombie\">废止</string>\n    <string name=\"state_dead\">停用</string>\n    <string name=\"state_device_io\">设备 I/O</string>\n    <string name=\"state_sleeping\">沉睡中</string>\n    <string name=\"navigation_wheel\">滚轮</string>\n    <plurals name=\"backup_exists_are_you_sure\">\n        <item quantity=\"other\">已完成多个应用程序的备份。你确定吗？</item>\n    </plurals>\n    <string name=\"navigation_no_nav\">无导航</string>\n    <string name=\"state_wake_kill\">唤醒杀死</string>\n    <string name=\"profiles\">配置</string>\n    <string name=\"no_profiles\">无配置</string>\n    <string name=\"keystore\">密钥库</string>\n    <string name=\"routine_ops\">常规操作权限</string>\n    <string name=\"apply_now\">现在应用…</string>\n    <string name=\"sort_by_memory_usage\">内存使用</string>\n    <string name=\"sort_by_apps_first\">应用程序优先</string>\n    <string name=\"sort_by_process_name\">进程名</string>\n    <string name=\"sort_by_process_id\">进程 ID</string>\n    <string name=\"filter_apps\">Android 应用</string>\n    <string name=\"no_apps\">没有应用</string>\n    <string name=\"apps\">应用程序</string>\n    <string name=\"pref_backup_flags_msg\">为备份选项添加一个预设, 以消除了每次备份/恢复时选择标志位(Flags)的负担。</string>\n    <string name=\"pref_compression_method\">压缩方法</string>\n    <string name=\"rules\">规则</string>\n    <string name=\"other\">其他</string>\n    <string name=\"changes_not_saved\">未保存更改</string>\n    <string name=\"allow_open_pgp_operation\">点击以允许 App Manager 使用 OpenPGP</string>\n    <string name=\"confirm_installation\">确认安装</string>\n    <string name=\"touchscreen_no_touch\">无触控</string>\n    <string name=\"non_critical_exts\">非关键扩展</string>\n    <string name=\"critical_exts\">关键扩展</string>\n    <string name=\"dsa_affine_y\">仿射 y 坐标</string>\n    <string name=\"dsa_affine_x\">仿射 x 坐标</string>\n    <string name=\"rsa_modulus\">RSA模数</string>\n    <string name=\"rsa_exponent\">RSA指数</string>\n    <string name=\"format\">格式</string>\n    <string name=\"public_key\">公钥</string>\n    <string name=\"algorithm\">算法</string>\n    <string name=\"app_signing_signature\">签名</string>\n    <string name=\"checksums\">校验和</string>\n    <string name=\"serial_no\">序列号</string>\n    <string name=\"not_yet_valid\">尚未生效</string>\n    <string name=\"expired\">已过期</string>\n    <string name=\"valid\">有效</string>\n    <string name=\"validity\">有效性</string>\n    <string name=\"type\">类别</string>\n    <string name=\"expiry_date\">到期日</string>\n    <string name=\"issued_date\">发布日期</string>\n    <string name=\"issuer\">发行商</string>\n    <string name=\"subject\">名称</string>\n    <string name=\"filter_apps_with_backups\">有备份</string>\n    <string name=\"sort_by_backup\">已备份应用优先</string>\n    <string name=\"failed_to_uninstall_updates\">无法卸载更新,它属于 <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g>.</string>\n    <string name=\"update_uninstalled_successfully\">用于 <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g>更新已被卸载.</string>\n    <string name=\"uninstall_updates\">卸载更新</string>\n    <string name=\"launch_mode_single_top\">栈顶</string>\n    <string name=\"only_install\">仅安装</string>\n    <string name=\"app_signing_install_without_data_loss\">如果您已经关闭了签名验证，您可以使用<b>仅安装</b>选项在不丢失数据情况下安装这个应用程序。</string>\n    <string name=\"app_data_will_be_lost\">现有数据将丢失。</string>\n    <string name=\"app_signing_signature_mismatch_for_system_apps\">无法安装应用程序，因为一个具有不同签名的系统应用程序的包名和它一样。</string>\n    <string name=\"do_you_want_to_uninstall_and_install\">您想要卸载并重新安装该应用程序吗\\?</string>\n    <string name=\"usage_access_not_supported\">无法请求使用情况访问权限，因为相应的设置页不存在。</string>\n    <string name=\"navigation_trackball\">轨迹球</string>\n    <string name=\"sys_config\">系统配置</string>\n    <string name=\"tap_to_see_details\">点击查看详情</string>\n    <string name=\"lib_details\">库详情</string>\n    <string name=\"no_libs\">没有库</string>\n    <string name=\"scanner\">扫描器</string>\n    <plurals name=\"libraries\">\n        <item quantity=\"other\">%1$d 个库</item>\n    </plurals>\n    <plurals name=\"classes\">\n        <item quantity=\"other\">%1$d 个类</item>\n    </plurals>\n    <plurals name=\"other_trackers_and_classes\">\n        <item quantity=\"other\"><xliff:g id=\"tracker_no\" example=\"8\">%1$d</xliff:g> 个跟踪器，共<xliff:g id=\"class_no\" example=\"50\">%2$d</xliff:g> 个类</item>\n    </plurals>\n    <plurals name=\"tracker_and_classes\">\n        <item quantity=\"other\">1 个跟踪器 <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g> 个 class</item>\n    </plurals>\n    <plurals name=\"two_trackers_and_classes\">\n        <item quantity=\"other\">2 个跟踪器 <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g> 个 classes</item>\n    </plurals>\n    <string name=\"copy\">复制</string>\n    <string name=\"view_missing_signatures\">点击以查看或发送 App Manager 的库数据库中还没有的签名。</string>\n    <plurals name=\"missing_signatures\">\n        <item quantity=\"other\">%1$d 个签名缺失</item>\n    </plurals>\n    <string name=\"orientation_behind\">与 activity 堆栈中紧接其后的 activity 的方向相同</string>\n    <string name=\"filter_running_apps\">运行中</string>\n    <string name=\"select_apk\">选择 APK</string>\n    <string name=\"send_crash_report\">发送崩溃报告</string>\n    <string name=\"tap_to_submit_crash_report\">点击提交崩溃报告。</string>\n    <string name=\"am_crashed\">App Manager 刚崩溃了</string>\n    <string name=\"un_apkm\">将 apkm 文件转换为 apks 文件</string>\n    <string name=\"in_progress\">进行中</string>\n    <string name=\"conversion_failed\">转换失败。</string>\n    <string name=\"input_profile_name\">配置文件名称</string>\n    <string name=\"duplicate\">重复</string>\n    <string name=\"new_profile\">新配置文件</string>\n    <string name=\"input_profile_name_description\">配置文件名不能包含任何空格。</string>\n    <string name=\"ecc\">椭圆曲线加密法</string>\n    <string name=\"rsa\">RSA</string>\n    <string name=\"aes\">AES</string>\n    <string name=\"none\">无</string>\n    <string name=\"pref_encryption_msg\">加密备份。</string>\n    <string name=\"encryption\">加密</string>\n    <string name=\"select_user\">选择用户</string>\n    <string name=\"failed_to_duplicate_profile\">无法复制配置文件</string>\n    <string name=\"keyboard_no_keys\">无键盘</string>\n    <string name=\"send_selected\">发送选中的应用</string>\n    <string name=\"enabled\">已启用</string>\n    <string name=\"choose\">选择</string>\n    <string name=\"input_permissions_description\">输入的权限之间用空格隔开，例如 <tt>com.permission.GET_ACCOUNTS android.permission.ACCESS_MEDIA_LOCATION</tt>等。使用 <tt>*</tt>应用到所有权限。</string>\n    <string name=\"input_permissions\">输入权限</string>\n    <string name=\"options\">选项</string>\n    <string name=\"off\">关闭</string>\n    <string name=\"on\">开启</string>\n    <string name=\"profile_state_msg\">自定义该配置文件的开启/关闭状态</string>\n    <string name=\"profile_block_trackers_msg\">屏蔽应用程序中的跟踪器</string>\n    <string name=\"profile_clear_data_msg\">清理应用程序的数据</string>\n    <string name=\"profile_clear_cache_msg\">清理应用程序的缓存</string>\n    <string name=\"profile_force_stop_msg\">强行停止应用</string>\n    <string name=\"allow_routine_ops_msg\">允许在例行操作中使用该配置文件</string>\n    <string name=\"profile_state\">配置文件状态</string>\n    <string name=\"allow_routine_ops\">允许例行操作</string>\n    <string name=\"adb_over_tcp\">网络调试</string>\n    <string name=\"pref_mode_of_operations\">操作模式</string>\n    <string name=\"user_profile_with_id\">用户：%1$s (%2$d)</string>\n    <string name=\"advanced\">高级</string>\n    <string name=\"simple\">简单</string>\n    <string name=\"close\">关闭</string>\n    <string name=\"no_root\">无 root</string>\n    <string name=\"root\">Root</string>\n    <string name=\"installer\">安装器</string>\n    <string name=\"install_location_prefer_external\">外部存储优先</string>\n    <string name=\"install_location_internal_only\">仅内部存储</string>\n    <string name=\"install_location\">安装位置</string>\n    <string name=\"comment\">备注</string>\n    <string name=\"pref_sign_apk_msg\">安装 APK 前先对它们进行签名。</string>\n    <string name=\"pref_sign_apk\">对 APK 进行签名</string>\n    <string name=\"pref_signature_schemes_msg\">为了更好的兼容性，至少应选中 v1 和 v2 方案。v4 方案需要选中 v2 或 v3。</string>\n    <string name=\"v4_scheme\">v4 方案 （自 Android 11 起）</string>\n    <string name=\"v3_scheme\">v3 方案（自 Android 9 起）</string>\n    <string name=\"v2_scheme\">v2 方案 （自 Android 7.0 起）</string>\n    <string name=\"v1_scheme\">v1 方案（自 Android 1.0 起）</string>\n    <string name=\"pref_apk_signing_msg\">设置签名方案，自定义签名密钥等。</string>\n    <string name=\"apk_signing\">APK 签名</string>\n    <string name=\"app_signing_signature_schemes\">签名方案</string>\n    <string name=\"source_stamp_verified\">SourceStamp 已验证。</string>\n    <string name=\"verified\">已验证</string>\n    <string name=\"splits\">分割</string>\n    <string name=\"not_verified\">未验证</string>\n    <plurals name=\"verified_with_warning\">\n        <item quantity=\"other\">已验证，但有 %d 个警告</item>\n    </plurals>\n    <plurals name=\"app_signing_signature_schemes_pl\">\n        <item quantity=\"other\">签名方案</item>\n    </plurals>\n    <string name=\"input_keystore_alias_pass_description\">插入别名 <b>%1$s</b> 的密码。如果该密码与密钥存储库密码相同，可以留空。</string>\n    <string name=\"input_keystore_alias_pass\">别名 <b>%1$s</b> 的密码</string>\n    <string name=\"input_keystore_pass_msg\">点击此处输入密钥库密码</string>\n    <string name=\"input_keystore_pass_description\">输入 App Manager 密钥库密码。如果您是第一次看到这个，请使用密码生成器生成一个密码，并在插入之前将其保存在一个安全的地方。</string>\n    <string name=\"input_keystore_pass\">输入密钥库密码</string>\n    <string name=\"no_app_ops_permission\">没有显示应用操作的权限</string>\n    <string name=\"pref_backup_android_keystore_msg\">并不是所有的应用程序在恢复后都能正常工作。恢复密钥存储库在大多数设备上无法工作。</string>\n    <string name=\"pref_backup_android_keystore\">备份带 Android 密钥库的应用程序</string>\n    <string name=\"keep_data_and_app_signing_signatures\">保留数据和签名</string>\n    <string name=\"this_action_cannot_be_undone\">此操作无法被撤销。</string>\n    <string name=\"orientation_sensor_portrait\">传感器控制</string>\n    <string name=\"orientation_sensor_landscape\">横向显示</string>\n    <string name=\"orientation_full_sensor\">所有传感器</string>\n    <string name=\"orientation_full_user\">全部用户</string>\n    <string name=\"set_app_op_mode\">设置应用程序操作模式</string>\n    <string name=\"magisk_hide_enabled\">MagiskHide</string>\n    <string name=\"filter_apps_with_splits\">有分包</string>\n    <string name=\"value\">值</string>\n    <string name=\"interceptor\">意图拦截器</string>\n    <string name=\"resend_intent\">重新发送意图</string>\n    <string name=\"share\">分享</string>\n    <string name=\"extras\">附加</string>\n    <string name=\"category\">类别</string>\n    <string name=\"uri\">统一资源标识符</string>\n    <string name=\"mime_type\">MIME 类型</string>\n    <string name=\"action\">操作</string>\n    <string name=\"result_code\">结果代码</string>\n    <string name=\"activity_result\">活动结果</string>\n    <string name=\"send_edited_intent\">发送编辑过的意图</string>\n    <string name=\"matching_activities\">匹配活动</string>\n    <string name=\"set_custom_app_op\">设置自定义应用操作</string>\n    <string name=\"pref_about_device_msg\">基本设备信息，包括 Android 系统、CPU、GPU、RAM、电池等。</string>\n    <string name=\"battery\">电池</string>\n    <string name=\"graphics\">图形处理器</string>\n    <string name=\"cpu\">CPU</string>\n    <string name=\"users\">用户</string>\n    <string name=\"languages\">语言</string>\n    <string name=\"battery_capacity\">容量</string>\n    <string name=\"memory\">内存</string>\n    <string name=\"vendor\">厂商</string>\n    <string name=\"gles_version\">OpenGL ES 版本</string>\n    <string name=\"no_of_cores\">核心数量</string>\n    <string name=\"support_architectures\">支持的 ABI</string>\n    <string name=\"security_providers\">安全供应商</string>\n    <string name=\"kernel\">内核</string>\n    <string name=\"manufacturer\">制造商</string>\n    <string name=\"board_name\">主板</string>\n    <string name=\"model\">型号</string>\n    <string name=\"brand_name\">品牌</string>\n    <string name=\"about_device\">关于此设备</string>\n    <string name=\"set_mode_for_app_ops_dots\">为 App Ops 设置模式…</string>\n    <string name=\"security\">安全性</string>\n    <string name=\"orientation_user_portrait\">纵向视图</string>\n    <plurals name=\"alert_failed_to_set_app_ops\">\n        <item quantity=\"other\">无法为 %1$d 个应用设置权限</item>\n    </plurals>\n    <string name=\"patch_level\">安全补丁级别</string>\n    <string name=\"backup_skip_signature_checks_description\">还原校验和验证失败或具有与先前备份不同的 APK 签名的备份。</string>\n    <string name=\"backup_multiple_description\">使用一个单独<i>命名的</i>备份，而不是基本备份。</string>\n    <string name=\"backup_rules_description\">备份 App Manager 内配置的规则。<font fgcolor=\"#ff0000\">取决于权限，并非所有规则都可以在还原期间被重新应用。</font></string>\n    <string name=\"backup_extras_description\">备份应用权限、节电和数据使用选项、MagiskHide 状态、SSAID 等。<font fgcolor=\"#ff0000\">取决于权限，并非所有提取的应用都可以被还原。</font></string>\n    <string name=\"backup_extras\">附加</string>\n    <string name=\"backup_cache_description\">备份<b>缓存</b>、<b>no_cache</b> 和 <b>no_backup</b> 文件夹。</string>\n    <string name=\"backup_obb_media_description\">备份 OBB 和媒体文件夹。</string>\n    <string name=\"backup_external_data_description\">备份外部数据文件夹。</string>\n    <string name=\"backup_internal_data_description\">备份数据文件夹。如果选中，将默认备份内部数据文件夹。</string>\n    <string name=\"backup_apk_files_description\">仅备份来自源目录的 APK 文件，包括 splits。</string>\n    <string name=\"selinux\">SELinux</string>\n    <string name=\"window_size\">窗口尺寸</string>\n    <string name=\"refresh_rate\">刷新率</string>\n    <string name=\"scaling_factor\">缩放系数</string>\n    <string name=\"size\">尺寸</string>\n    <string name=\"density\">密度</string>\n    <string name=\"screen\">屏幕</string>\n    <string name=\"hardware\">硬件</string>\n    <string name=\"permissive\">宽容</string>\n    <string name=\"enforcing\">强制</string>\n    <string name=\"failed_to_enable_magisk_hide\">无法启用 MagiskHide</string>\n    <string name=\"failed_to_disable_magisk_hide\">无法禁用 MagiskHide</string>\n    <string name=\"disable_background_run_description\">将<i>忽略</i>模式设置到下列应用操作：<tt>RUN_IN_BACKGROUND</tt>（从 Android 7.0 起）和 <tt>RUN_ANY_IN_BACKGROUND</tt>（从 Android 9 起）。</string>\n    <plurals name=\"no_of_components\">\n        <item quantity=\"other\">%1$d 个组件</item>\n    </plurals>\n    <string name=\"state_parked\">已放置</string>\n    <string name=\"state_trace_stop\">追踪停止</string>\n    <string name=\"orientation_user_landscape\">水平视图</string>\n    <string name=\"backup_custom_users\">自定义用户</string>\n    <string name=\"no_volumes_found\">找不到任何具有写入权限的卷。</string>\n    <string name=\"pref_backup_volume_msg\">选择存储备份的卷或磁盘。</string>\n    <string name=\"backup_volume\">备份位置</string>\n    <string name=\"pref_backup_restore_msg\">定制备份/还原。</string>\n    <string name=\"backup_custom_users_description\">仅对指定用户执行备份</string>\n    <string name=\"unencrypted\">未加密</string>\n    <string name=\"bootloader\">Bootloader</string>\n    <string name=\"encrypted\">已加密</string>\n    <string name=\"drm_free_apkm_msg\">此 APKM 文件无 DRM，无需转换为 APKS。</string>\n    <string name=\"restore_msg\">还原有数据的应用程序</string>\n    <string name=\"backup_msg\">备份有数据的应用程序</string>\n    <string name=\"restore_latest_msg\">还原已安装的应用程序，它们的版本代码高于已安装的版本代码。</string>\n    <string name=\"restore_latest\">还原最新备份</string>\n    <string name=\"restore_not_installed_msg\">还原当前未安装的应用程序的基础备份。</string>\n    <string name=\"restore_all_msg\">从所有备份的应用程序中恢复基础备份。</string>\n    <string name=\"backup_apps_with_changes_msg\">重做上次备份以来有更改的应用程序的备份。所谓更改包括大小、版本和上次启动时间。</string>\n    <string name=\"backup_apps_with_changes\">备份有更改的应用程序</string>\n    <string name=\"redo_existing_backups_msg\">重做有先前备份的已安装应用程序的备份。</string>\n    <string name=\"redo_existing_backups\">重做现有备份</string>\n    <string name=\"verify_and_redo_backups_msg\">检查先前备份的完整性并重做未通过完整性检查的备份。</string>\n    <string name=\"verify_and_redo_backups\">验证和重做备份</string>\n    <string name=\"backup_apps_without_backups_msg\">备份没有任何先前备份的应用程序。</string>\n    <string name=\"backup_apps_without_backups\">备份没有备份的应用程序</string>\n    <string name=\"restore_not_installed\">还原未安装的应用</string>\n    <string name=\"restore_all\">恢复所有应用</string>\n    <string name=\"backup_all_apps_msg\">备份所有已安装的应用程序。</string>\n    <string name=\"backup_all_apps\">备份所有应用</string>\n    <string name=\"back_up\">备份</string>\n    <string name=\"list_options\">列表选项</string>\n    <string name=\"reverse\">反转</string>\n    <string name=\"os_version\">操作系统版本</string>\n    <string name=\"add\">添加</string>\n    <string name=\"add_to_profile\">添加到配置</string>\n    <string name=\"initializing\">初始化中…</string>\n    <string name=\"net_policy\">网络策略</string>\n    <string name=\"has_net_policy\">网络策略</string>\n    <string name=\"choose_what_to_do\">选择做什么。</string>\n    <string name=\"enable_battery_optimization\">启用电池优化？</string>\n    <string name=\"battery_optimization\">电池优化</string>\n    <string name=\"no_battery_optimization\">无电池优化</string>\n    <string name=\"screen_lock_msg\">用安卓屏幕锁锁定 App Manager</string>\n    <string name=\"screen_lock\">屏幕锁</string>\n    <string name=\"unlock_app_manager\">解锁 App Manager</string>\n    <string name=\"sd_card\">SD卡</string>\n    <string name=\"external_storage\">外部存储</string>\n    <string name=\"internal_storage\">内部存储</string>\n    <string name=\"restart_to_reflect_changes\">你必须立即重新启动设备才能使用新的更改。</string>\n    <string name=\"failed_to_change_ssaid\">无法更改 SSAID</string>\n    <string name=\"copied_to_clipboard\">已复制到剪贴板。</string>\n    <string name=\"ssaid_info\">SSAID (<tt>Settings.Secure.ANDROID_ID</tt>) 是分配给每个应用程序的设备标识符 (从 Android 8 Oreo 起)。它被应用程序广泛用于跟踪用户。</string>\n    <string name=\"ssaid\">SSAID</string>\n    <string name=\"type_uri\">URI</string>\n    <string name=\"type_string_array_list\">字符串列表</string>\n    <string name=\"type_string_array\">字符串数组</string>\n    <string name=\"type_float_array_list\">浮点数列表</string>\n    <string name=\"type_float_array\">浮点数数组</string>\n    <string name=\"type_long_array_list\">长整型列表</string>\n    <string name=\"type_long_array\">长整型数组</string>\n    <string name=\"type_int_array_list\">整型列表</string>\n    <string name=\"type_int_array\">整型数组</string>\n    <string name=\"type_component_name\">组件名(Component Name)</string>\n    <string name=\"type_null\">空(null)</string>\n    <string name=\"user_with_id\">用户：<xliff:g id=\"user_id\" example=\"0\">%1$d</xliff:g></string>\n    <string name=\"installed_apps\">已安装的应用</string>\n    <string name=\"last_actions\">上次操作</string>\n    <string name=\"pref_enable_disable_features_msg\">启用/禁用 App Manager 中的功能。</string>\n    <string name=\"enable_disable_features\">启用/禁用功能</string>\n    <string name=\"isolated\">已隔离</string>\n    <string name=\"screen_lock_not_enabled\">请在安卓系统设置中选择一个屏幕锁或清除应用数据。</string>\n    <string name=\"input_app_ops_description_profile\">app op 名称和/或常数间用英文空格隔开，比如 <tt>WAKE_LOCK 63 72 CAMERA</tt>等。用 <tt>* </tt>表示应用到所有配置的 app ops。</string>\n    <string name=\"working_on_adb_mode\">在 ADB 模式上正常工作</string>\n    <string name=\"verified_using_unreliable_hash\">使用不可靠哈希进行了验证</string>\n    <string name=\"installer_app_message\">选中<b>挑选</b>从已安装应用中进行选择或选中<b>自定义</b>指定自定义包名。</string>\n    <string name=\"specify_custom_name\">自定义</string>\n    <string name=\"filter_apps_without_backups\">无备份</string>\n    <string name=\"uninstalled_apps\">已卸载应用</string>\n    <string name=\"internal_data\">内部数据</string>\n    <string name=\"expiry_date_cannot_be_empty\">到期日不能为空。</string>\n    <string name=\"signing_key\">签名密钥</string>\n    <string name=\"failed_to_read_keystore\">无法读取密钥库。</string>\n    <string name=\"alias_pass\">别名密码</string>\n    <string name=\"choose_an_alias\">选择一个别名</string>\n    <string name=\"found_no_alias_in_keystore\">在密钥库中未找到别名！</string>\n    <string name=\"new_alias_password\">新建别名密码</string>\n    <string name=\"import_key\">导入密钥</string>\n    <string name=\"pem_file\">PEM 文件</string>\n    <string name=\"pk8_file\">PKCS #8 (PK8) 文件</string>\n    <string name=\"pem_and_pk8\">PEM 和 PKCS #8 (PK8)</string>\n    <string name=\"pkcs12_keystore\">PKCS #12 密钥库 (P12)</string>\n    <string name=\"bouncy_castle_keystore\">Bouncy Castle 密钥库 (BKS)</string>\n    <string name=\"java_keystore\">Java 密钥库 (JKS)</string>\n    <string name=\"keystore_pass\">密钥库密码</string>\n    <string name=\"keystore_file\">密钥库文件</string>\n    <string name=\"country_name\" tools:ignore=\"TypographyOther\">国名（C）</string>\n    <string name=\"state_name\">州名（ST）</string>\n    <string name=\"locality_name\">地区（城市）名称（L）</string>\n    <string name=\"organization_name\">机构名称（O）</string>\n    <string name=\"organization_unit\">组织单位（OU）</string>\n    <string name=\"common_name\">通用名（CN）</string>\n    <string name=\"input_key_password\">密钥密码</string>\n    <string name=\"failed_to_load_key\">无法加载密钥。</string>\n    <string name=\"key_not_set\">未设置。</string>\n    <string name=\"use_default\">使用默认</string>\n    <string name=\"invalid_rsa_key_size\">RSA加密的密钥大小无效。 密钥大小可以是1024位、2048位或4096位。</string>\n    <string name=\"crypto_key_size\">密钥大小</string>\n    <string name=\"invalid_aes_key_size\">AES加密的密钥大小无效。 密钥大小要么是128位，要么是256位。</string>\n    <string name=\"failed_to_initialize_key_store\">无法初始化 App Manager 密钥库。</string>\n    <string name=\"failed_to_save_key\">无法保存密钥。</string>\n    <string name=\"generate_key\">生成</string>\n    <string name=\"input_key\">输入密钥 (以十六进制表示）</string>\n    <string name=\"input_keystore_alias_pass_msg\">轻按此处提供 %1$s 的密码</string>\n    <string name=\"source_code_links\"><a href=\"https://github.com/MuntashirAkon/AppManager\">GitHub</a> • <a href=\"https://gitlab.com/muntashir/AppManager\">GitLab</a> • <a href=\"https://0xacab.org/muntashir/AppManager\">Riseup</a> • <a href=\"https://codeberg.org/muntashir/AppManager\">Codeberg</a></string>\n    <string name=\"pref_installer_msg\">配置应用安装程序的行为。</string>\n    <string name=\"filter_choice_tag\">标签</string>\n    <string name=\"filter_choice_pid\">PID</string>\n    <string name=\"filter_choice\">作为搜索依据</string>\n    <string name=\"enter_good_filename\">请输入一个有效的文件名。</string>\n    <string name=\"enter_filename\">输入文件名</string>\n    <string name=\"dialog_compiling_log\">正在编译日志…</string>\n    <string name=\"delete_saved_log\">删除已保存的日志</string>\n    <string name=\"copy_to_clipboard\">复制到剪贴板</string>\n    <string name=\"add_filter_ellipsis\">添加过滤器…</string>\n    <string name=\"add_filter\">添加过滤器</string>\n    <string name=\"log_level_fatal\">致命</string>\n    <string name=\"log_level_warn\">警告</string>\n    <string name=\"log_level_verbose\">详细</string>\n    <string name=\"log_level_info\">信息</string>\n    <string name=\"log_level_error\">错误</string>\n    <string name=\"log_level_debug\">调试</string>\n    <string name=\"filename\">文件名</string>\n    <string name=\"restart_log_viewer_to_see_changes\">重启日志查看器窗口来查看更改。</string>\n    <string name=\"pref_log_viewer_msg\">配置日志展示方式。</string>\n    <string name=\"log_viewer\">日志查看器</string>\n    <string name=\"log_level\">日志级别</string>\n    <string name=\"log_cleared\">日志已清除</string>\n    <string name=\"log_recording_started\">日志记录已启动。</string>\n    <string name=\"log_saved\">日志已保存。</string>\n    <string name=\"manage_saved_logs\">管理已保存的日志</string>\n    <string name=\"no_saved_logs\">无已保存的日志。</string>\n    <string name=\"notification_ticker\">日志记录已启动</string>\n    <string name=\"notification_subtext\">点击停止记录</string>\n    <string name=\"notification_title\">日志记录进行中</string>\n    <string name=\"open\">打开</string>\n    <string name=\"pref_cat_appearance\">外观</string>\n    <string name=\"pref_cat_advanced\">高级</string>\n    <string name=\"pref_buffer_title\">日志缓冲区(s)</string>\n    <string name=\"pref_cat_configuration\">配置</string>\n    <string name=\"pref_default_log_level_title\">默认日志级别</string>\n    <string name=\"pref_default_log_level_summary\">启动时、打开文件时和记录时的日志级别。</string>\n    <string name=\"pref_display_limit_title\">日志展示限制</string>\n    <string name=\"pref_display_limit_summary\">仅显示最后 %1$d 条日志以避免内存不足错误。</string>\n    <string name=\"pref_filter_pattern_title\">过滤掉标签</string>\n    <string name=\"pref_filter_pattern_summary\">从日志中过滤掉选择的标签。</string>\n    <string name=\"trackers_unblocked_successfully\">已放行跟踪器</string>\n    <string name=\"trackers_blocked_successfully\">跟踪器已被拦截</string>\n    <string name=\"failed_to_unblock_trackers\">无法取消拦截跟踪器</string>\n    <string name=\"failed_to_block_trackers\">无法拦截跟踪器</string>\n    <string name=\"profile_save_apk_msg\">保存 APK 文件于 <tt>AppManager/apks</tt>目录</string>\n    <string name=\"save_apk\">保存 APK</string>\n    <string name=\"running_services\">运行中的服务</string>\n    <string name=\"view_logs\">查看日志</string>\n    <string name=\"share_log\">分享</string>\n    <string name=\"text_include_dmesg\">包含内核日志</string>\n    <string name=\"omit_sensitive_info_summary\">忽略敏感信息，如网址、电话号码或电子邮件。</string>\n    <string name=\"omit_sensitive_info\">省略敏感信息</string>\n    <string name=\"undo\">撤销</string>\n    <string name=\"pause_unpause\">播放/暂停</string>\n    <string name=\"collapse_all\">收起所有</string>\n    <string name=\"expand_all\">展开所有</string>\n    <string name=\"file\">文件</string>\n    <string name=\"widget_start_recording\">记录\n\\n日志</string>\n    <string name=\"widget_recording_in_progress\">记录中…</string>\n    <string name=\"unable_to_save_log\">无法保存日志。你是否输入了有效的文件名\\?</string>\n    <plurals name=\"toast_log_truncated\">\n        <item quantity=\"other\">日志太大，仅显示最后 %d 行。</item>\n    </plurals>\n    <string name=\"toast_invalid_selection\">无效选择。请重试。</string>\n    <string name=\"toast_invalid_level\">无效的级别名称：%s</string>\n    <string name=\"pref_display_limit_hint\">请输入一个 %1$d 和 %2$d 之间的有效数字。</string>\n    <string name=\"text_include_device_info\">包含设备信息</string>\n    <string name=\"text_filter_text\">过滤器文本</string>\n    <string name=\"text_filter_ellipsis\">过滤器…</string>\n    <string name=\"subject_log_report\">日志报告</string>\n    <string name=\"start_recording_log\">记录</string>\n    <string name=\"settings\">设置</string>\n    <string name=\"send_log_title\">发送日志</string>\n    <string name=\"save_log\">保存日志</string>\n    <string name=\"save_as\">保存为 …</string>\n    <string name=\"record_log\">记录日志</string>\n    <string name=\"pref_show_timestamp_title\">显示进程 ID 和时间戳</string>\n    <string name=\"pref_show_timestamp_summary\">展开时显示进程 id 和时间戳。</string>\n    <string name=\"pref_log_write_period_title\">写入周期</string>\n    <string name=\"pref_log_write_period_summary\">每记录 %1$d 行写入磁盘。</string>\n    <string name=\"pref_log_line_period_error\">请输入1到1000之间的整数。</string>\n    <string name=\"pref_expanded_by_default_title\">默认展开</string>\n    <string name=\"pref_expanded_by_default_summary\">默认情况下显示完整的日志文本。</string>\n    <string name=\"latest_backup\">最新备份</string>\n    <string name=\"gz_bz2_compressed\">%1$s 已压缩</string>\n    <string name=\"pgp_aes_rsa_encrypted\">%1$s 已加密</string>\n    <string name=\"no_encryption\">无加密</string>\n    <string name=\"base_backup\">基础备份</string>\n    <string name=\"failed\">失败了</string>\n    <string name=\"confirm_import_keystore\">你确定要替换现有的密钥存储库吗\\?此操作无法撤消。</string>\n    <string name=\"import_keystore\">导入密钥库</string>\n    <string name=\"pref_import_export_keystore_msg\">导入/导出 App Manager 内部使用的 Bouncy Castle KeyStore (BKS)。</string>\n    <string name=\"pref_import_export_keystore\">导入/导出密钥库</string>\n    <string name=\"app_signing_signatures\">签名</string>\n    <string name=\"pref_rules_msg\">即时拦截，导入/导出/移除规则等。</string>\n    <string name=\"saf\">存储访问框架</string>\n    <string name=\"orientation_right_to_left\">从右至左</string>\n    <string name=\"orientation_left_to_right\">从左至右</string>\n    <string name=\"orientation_follow_locale\">遵照语言环境</string>\n    <plurals name=\"file_deletion_confirmation\">\n        <item quantity=\"other\">%d 个文件已被删除</item>\n    </plurals>\n    <string name=\"hidden\">隐藏</string>\n    <string name=\"suspended\">已挂起</string>\n    <string name=\"no_changes\">无更改</string>\n    <string name=\"pref_display_changes_msg\">以版本控制的方式显示版本、跟踪器、组件、权限、签名、SDK 等的更改。</string>\n    <string name=\"pref_display_changes\">展示更改</string>\n    <string name=\"netpolicy_disable_network_access\">禁用网络访问</string>\n    <string name=\"netpolicy_reject_wifi_data\">拒绝 Wi-Fi 数据</string>\n    <string name=\"netpolicy_reject_vpn_data\">拒绝 VPN 数据</string>\n    <string name=\"netpolicy_reject_cellular_data\">拒绝移动网络数据</string>\n    <string name=\"netpolicy_allow_background_data\">启用数据节省器时允许后台数据</string>\n    <string name=\"netpolicy_reject_background_data\">拒绝后台数据</string>\n    <string name=\"port_number_invalid\">无效的端口号。</string>\n    <string name=\"port_number_empty\">端口号为空。</string>\n    <string name=\"adb_connect_port_number_description\">端口位于 <b>IP 地址&amp;端口</b>部分下方，该部分就在 <b>设备名称</b>部分下面。</string>\n    <string name=\"port_number\">端口</string>\n    <string name=\"adb_connect\">连接</string>\n    <string name=\"wireless_debugging\">无线调试</string>\n    <string name=\"unknown_net_policy\">未知的 netpolicy (%1$s - %2$X)</string>\n    <string name=\"failed_to_prevent_background_run\">无法防止 %1$s 在后台运行</string>\n    <string name=\"community_links\"><a href=\"https://matrix.to/#/#appmanager:matrix.org\">Matrix</a> • <a href=\"https://t.me/AppManagerChannel\">Telegram</a> • <a href=\"https://x.com/AppManagerNews\">Twitter/X</a>• <a href=\"https://floss.social/@appmanager\">Mastodon</a></string>\n    <string name=\"community\">社区</string>\n    <plurals name=\"alert_failed_to_import_backups\">\n        <item quantity=\"other\">无法导入 %1$d 个备份</item>\n    </plurals>\n    <string name=\"import_from_tb\">从 Titanium Backup 导入</string>\n    <string name=\"import_from_oab\">从 OAndBackup 导入</string>\n    <string name=\"pref_import_backups_msg\">从 OAndBackup、Swift Backup (3.0–3.2) 或 Titanium Backup 导入备份。</string>\n    <string name=\"pref_import_backups\">导入备份</string>\n    <string name=\"added_to_queue\">已添至队列</string>\n    <string name=\"minimum_version\">最小版本: %d</string>\n    <string name=\"help_uses_permissions_tab\">点击一个项目来<b>授予</b>或<b>拒绝</b>它。只有<b>危险</b>和<b>开发</b>权限可被授予或撤销。</string>\n    <string name=\"help_permissions_tab\">这些权限由该应用程序定义且无法撤销。</string>\n    <string name=\"help_app_ops_tab\">点击项目以<b>允许</b>或<b>忽略</b>它。长按某个项目可查看其他支持的模式。</string>\n    <string name=\"saved_filters\">已保存的过滤器</string>\n    <string name=\"permission_flags\">权限标志位</string>\n    <string name=\"pref_selected_users_msg\">限制 App Manager 仅与选定的用户一起工作。</string>\n    <string name=\"pref_selected_users\">选中的用户</string>\n    <string name=\"error_with_details\">错误: %s</string>\n    <string name=\"files\">文件</string>\n    <string name=\"storage\">存储</string>\n    <string name=\"notice_saf\">与卷不同，所选目录将用于存储与App Manager相关的所有文件，包括保存的APK和备份。存储访问框架(Storage Access Framework, SAF)非常慢，因此，您应该只在其他选项无法使用时使用此选项。</string>\n    <string name=\"notice\">通知</string>\n    <string name=\"paired_successfully\">已配对。</string>\n    <string name=\"adb_pair\">配对</string>\n    <string name=\"invalid_password\">密码无效，请重试。</string>\n    <string name=\"keystore_pass_cannot_be_empty\">KeyStore 密码不能为空。</string>\n    <string name=\"keystore_password_info\">以下是 App Manager KeyStore 密码。如果您要备份/恢复 App Manager KeyStore，请将其存储在一个安全的地方。<b>此信息将不再显示。</b></string>\n    <string name=\"staging_apk_files\">分阶段进行中…</string>\n    <string name=\"running_services_logcat_hint\">单击一个项目打开日志查看器，并将相应的进程 ID 作为默认筛选器。</string>\n    <string name=\"pid\">进程 ID</string>\n    <plurals name=\"pref_thread_count_msg\">\n        <item quantity=\"other\">最多同时执行 %1$d 个操作</item>\n    </plurals>\n    <string name=\"pref_thread_count_hint\">值必需在 0 到 %1$d。0 表示<i>给定时间内的最大操作数</i>。</string>\n    <string name=\"pref_thread_count\">同时执行</string>\n    <string name=\"type_uri_array_list\">URI 列表</string>\n    <string name=\"type_uri_array\">URI 数组</string>\n    <string name=\"pref_always_on_background_msg\">总是在后台安装应用程序，完成后显示通知。</string>\n    <string name=\"pref_always_on_background\">后台安装</string>\n    <string name=\"pref_block_trackers_msg\">安装应用程序后使用 App Manager 拦截跟踪组件。</string>\n    <string name=\"next\">下一个</string>\n    <string name=\"installer_app_installed\">应用已安装</string>\n    <string name=\"background\">后台</string>\n    <string name=\"trim_caches_in_all_apps_description\">删除所有应用程序的缓存文件，包括 Android 系统</string>\n    <string name=\"trim_caches_in_all_apps\">减少所有应用程序的缓存</string>\n    <string name=\"user_root\">使用 root</string>\n    <string name=\"paste\">粘贴</string>\n    <string name=\"set_package_name_first\">先设置包名称！</string>\n    <string name=\"identifier\">标识符</string>\n    <string name=\"backup_volume_dialog_description\">带<tt>tree</tt>前缀的卷是使用存储访问框架 (SAF）选中的文件夹。除了这些文件夹外，App Manager 的默认目录是一个子文件夹，名为 <tt>AppMangaer</tt>。</string>\n    <string name=\"second_degree_tracker_note\">² 前缀表明跟踪器位于 <a href=\"https://etip.exodus-privacy.eu.org/\">ETIP 备用名单</a> 中。即它们是否真是跟踪器仍在调查中。</string>\n    <string name=\"failed_to_uninstall_app\">卸载失败</string>\n    <string name=\"pref_import_backups_hint\">选择备份文件所在路径 (Swift Backup/Titanium backup) 或路径 (OAndBackup)</string>\n    <string name=\"java\">Java</string>\n    <string name=\"smali\">Smali</string>\n    <string name=\"accessibility_service_description\">用于执行某些操作的通用无障碍服务，例如在非 root 模式下清除缓存。</string>\n    <string name=\"explore\">探索</string>\n    <string name=\"system_partition\">安卓 root</string>\n    <string name=\"exit_confirmation\">退出确认</string>\n    <string name=\"extract\">提取</string>\n    <string name=\"replace\">替换</string>\n    <string name=\"rename\">重命名</string>\n    <string name=\"import_from_sb\">从 Swift Backup 3.0 – 3.2 导入</string>\n    <string name=\"pref_default_blocking_method\">默认拦截方式</string>\n    <string name=\"intent_firewall_and_disable\">IFW + PM Disable</string>\n    <string name=\"intent_firewall\">IFW</string>\n    <string name=\"pref_default_blocking_method_description\">在没有拦截选项可选的情况下默认使用的方法。\n\\n<b>注意：</b> “IFW” 无法应用于 provider，使用的是“禁用”。</string>\n    <string name=\"pref_intent_firewall_and_disable_description\">使用 Intent Firewall 阻断组件并通过 PM 禁用它们。推荐 root 用户使用该方法。</string>\n    <string name=\"pref_intent_firewall_description\">仅使用 Intent Firewall 阻断组件。不推荐，因为有些系统程序可以绕过 IFW。</string>\n    <string name=\"pref_disable_description\">禁用组件。不推荐 root 用户使用，因为程序可以绕过这个。在 ADB 模式下，可以使用此方法禁用仅测试应用程序。</string>\n    <string name=\"authenticating\">正在验证…</string>\n    <string name=\"search_type_contains\">包含</string>\n    <string name=\"search_type_prefix\">前缀</string>\n    <string name=\"search_type_suffix\">后缀</string>\n    <string name=\"search_type_regular_expressions\">正则表达式</string>\n    <plurals name=\"usage_minutes\">\n        <item quantity=\"other\">%1$d 分钟</item>\n    </plurals>\n    <plurals name=\"usage_seconds\">\n        <item quantity=\"other\">%1$d 秒</item>\n    </plurals>\n    <string name=\"toggle_internet\">使用互联网</string>\n    <string name=\"vt_uploading\">VirusTotal: 上传中…</string>\n    <string name=\"vt_queued\">VirusTotal: 已排队</string>\n    <string name=\"vt_failed\">VirusTotal: 失败</string>\n    <string name=\"vt_success\">VirusTotal: %1$d/%2$d</string>\n    <string name=\"vt_scan_date\">扫描日期: %1$s</string>\n    <string name=\"vt_slowness_warning\">根据网速和服务器负载，这可能需要一段时间。</string>\n    <string name=\"pref_vt_apikey_summary\">启用 VirusTotal 扫描 APK 文件。</string>\n    <string name=\"uses_play_app_signing\">Play 应用签名</string>\n    <string name=\"scan_in_vt\">在 VirusTotal 中扫描</string>\n    <string name=\"process_id\">进程 ID</string>\n    <string name=\"parent_process_id\">父进程 ID</string>\n    <string name=\"virtual_memory\">虚拟内存</string>\n    <string name=\"cpu_percent\">CPU 占用</string>\n    <string name=\"cpu_time\">CPU 时间</string>\n    <string name=\"priority\">优先级</string>\n    <string name=\"threads\">线程数</string>\n    <string name=\"state\">进程状态</string>\n    <string name=\"commandline_args\">命令行参数</string>\n    <string name=\"swap\">Swap</string>\n    <string name=\"memory_chart_info\">● %1$s 个应用 ● %2$s 已缓存 ● %3$s 缓冲器 ● %4$s 可用</string>\n    <string name=\"warning_working_on_root_mode\">警告：工作于 root 而非 ADB 模式下。</string>\n    <string name=\"magisk_denylist\">Magisk 黑名单</string>\n    <string name=\"failed_to_enable_magisk_deny_list\">无法启用 Magisk 黑名单</string>\n    <string name=\"failed_to_disable_magisk_deny_list\">无法禁用 Magisk 黑名单</string>\n    <string name=\"vt_checking\">VirusTotal: 检查中…</string>\n    <string name=\"pref_vt_apikey\">VirusTotal API 密钥</string>\n    <string name=\"vt_permalink\">VirusTotal 永久链接</string>\n    <string name=\"pref_vt_apikey_description\">API 密钥使 App Manager 可以上传 APK 文件到 VirusTotal 以及获取报告。在 https://virustotal.com 注册，免费获得一个 API 密钥。</string>\n    <string name=\"vt_disclaimer\">VirusTotal 及其标识是 Chronicle LLC 的注册商标。App Manager- API 客户端及其作者都不对您可能发送给 VirusTotal 的任何数据负责。</string>\n    <string name=\"uses_play_app_signing_description\">此应用包含表明其<i>可能</i>使用<a href=\"https://support.google.com/googleplay/android-developer/answer/9842756\">Play 应用签名</a>的特定标记。在这个方案中，签名密钥存储在谷歌的服务器中，谷歌负责对应用程序进行签名。请注意，匹配签名信息是验证应用是否未被作者以外的任何人修改过的唯一方法（在这种情况下，也包括谷歌）。</string>\n    <string name=\"swap_chart_info\">● %1$s 已用 ● %2$s 可用</string>\n    <string name=\"failed_to_change_app_op_mode\">无法更改应用操作模式。</string>\n    <string name=\"failed_to_use_the_current_mode_of_operation\">无法使用当前操作模式。此会话退回到无 root 模式。</string>\n    <string name=\"mode_of_op_with_inferred_mode_of_op\">%1$s (推断模式: %2$s)</string>\n    <string name=\"hidden_api_enforcement_policy\">隐藏 API 强制策略</string>\n    <string name=\"hidden_api_enf_policy_none\">无（完整访问隐藏的 API）</string>\n    <string name=\"hidden_api_enf_policy_warn\">警告（完整地访问隐藏的 API，但发出警告）</string>\n    <string name=\"hidden_api_enf_policy_dark_grey_and_black\">强制（深灰和黑名单）</string>\n    <string name=\"hidden_api_enf_policy_black\">强制（仅黑名单）</string>\n    <string name=\"binary_32_bit\">32 位</string>\n    <string name=\"so_type_shared_library\">共享库</string>\n    <string name=\"file_modified_are_you_sure\">文件被修改。放弃所有更改并退出？</string>\n    <string name=\"save_and_exit\">保存并退出</string>\n    <string name=\"zygote_preload_name\">Zygote 预加载名</string>\n    <string name=\"binary_64_bit\">64 位</string>\n    <string name=\"primary_abi\">主 ABI</string>\n    <string name=\"hidden_api_enf_default_policy\">默认（基于应用类型）</string>\n    <string name=\"endianness_big_endian\">Big endian 编码</string>\n    <string name=\"endianness_little_endian\">Little endian 编码</string>\n    <string name=\"so_type_executable\">可执行</string>\n    <string name=\"auth_manager_description\">要从外部应用启动一个 intent，需要提供一个名为 <tt>auth</tt>的额外字段，其必须包含下列键：</string>\n    <string name=\"pref_saved_apk_name_format\">保存的 APK 名称格式</string>\n    <string name=\"pref_saved_apk_name_format_msg\">保存 APK 文件时用来命名它们的格式。</string>\n    <string name=\"auth_manager_title\">授权管理器</string>\n    <string name=\"regenerate_auth_key\">重新生成授权密钥</string>\n    <string name=\"regenerate_auth_key_warning\">你确定吗？必须用新的授权密钥来重新配置所有第三方应用。</string>\n    <string name=\"shortcut_icon\">快捷方式图标</string>\n    <string name=\"sort_by_installation_date\">安装日期</string>\n    <string name=\"backup_volume_unavailable_warning\">所选的备份卷当前不可用。如它位于外部存储，请插入它，或更改备份卷。</string>\n    <string name=\"change_backup_volume\">更改卷</string>\n    <string name=\"external\">外部</string>\n    <string name=\"internal\">内部</string>\n    <string name=\"tracker\">跟踪器</string>\n    <string name=\"input_ssaid_instruction\">SSAID 是一个 %1$d 字节的十六进制数，即一个包含 0 到 9 和 a 到 f 的长为 %2$d 的字符串。</string>\n    <string name=\"screen_time\">屏幕时间</string>\n    <string name=\"type_string_set\">字符集</string>\n    <string name=\"pref_vt_prompt_before_uploading\">上传文件前显示提示。</string>\n    <string name=\"vt_confirm_upload_and_scan\">是，上传并扫描</string>\n    <string name=\"open_in_new_window\">新窗口</string>\n    <string name=\"vt_confirm_uploading_file\">在 VirusTotal 数据库中找不到该文件。 你要上传吗？</string>\n    <string name=\"apk_checksums\">APK 校验和</string>\n    <string name=\"log_stop_recording\">停止录制</string>\n    <string name=\"item_select\">选择</string>\n    <string name=\"app_explorer\">应用浏览器</string>\n    <string name=\"netpolicy_cannot_be_modified_for_core_apps\">不允许修改 Android 核心应用的网络策略。</string>\n    <string name=\"open_developer_options_page\">在Android设置中打开开发者选项页面</string>\n    <string name=\"pref_pure_black_theme\">纯黑主题</string>\n    <string name=\"pref_pure_black_theme_msg\">启用夜间模式时，使用完全黑色的背景。</string>\n    <string name=\"usage_mobile_data\">移动流量</string>\n    <string name=\"usage_wifi_data\">Wi-Fi 流量</string>\n    <string name=\"usage_times_opened\">打开次数</string>\n    <string name=\"usage_last_used\">上次使用</string>\n    <string name=\"backup_apps_cannot_be_restored\">无法还原下列应用，因它们没有基备份：</string>\n    <string name=\"frozen\">已冻结</string>\n    <string name=\"unfreeze\">解冻</string>\n    <string name=\"freeze\">冻结</string>\n    <string name=\"backup_no_backups_present\">无备份。</string>\n    <string name=\"restore_dots\">还原…</string>\n    <string name=\"backup_apps_cannot_be_backed_up\">未安装下列应用，因而无法进行备份：</string>\n    <string name=\"restart_device\">重启设备</string>\n    <string name=\"import_backups_warning_delete_backups_after_import\">将备份导入 App Manager 后删除备份？ 每个备份在成功导入后会被单独删除。 如不确定，选择<b>否</b>。</string>\n    <string name=\"troubleshooting\">疑难解答</string>\n    <string name=\"pref_reload_apps\">重新加载应用</string>\n    <string name=\"pref_reload_apps_msg\">重新加载存储在 App Manager 数据库中的应用列表，以防意外行为。</string>\n    <string name=\"changelog_type_new\">新增</string>\n    <string name=\"changelog_type_fix\">修复</string>\n    <string name=\"changelog_type_improve\">改进</string>\n    <string name=\"unsupported_split_apk\">不支持</string>\n    <string name=\"view_changelog\">了解此版本中的新增功能</string>\n    <string name=\"sort_by_total_size\">总大小</string>\n    <string name=\"am_command\"><tt>am</tt>命令</string>\n    <string name=\"pref_sign_apk_no_signing_key\">无签名秘钥</string>\n    <string name=\"pref_sign_apk_error_signing_key_not_added\">签署 APK 文件需要有效的签名秘钥。</string>\n    <string name=\"pref_advanced_pref\">用户、APK 名称格式、并行执行等。</string>\n    <string name=\"hide_app_description\">这种方法只推荐日常使用。一个隐藏的应用看起来像被卸载了。但如果重新安装或更新，该应用会重新出现。</string>\n    <string name=\"failed_to_freeze\">无法冻结 <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g>。</string>\n    <string name=\"failed_to_unfreeze\">无法解冻 <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g>。</string>\n    <string name=\"freeze_unfreeze\">冻结/解冻</string>\n    <string name=\"profile_freeze_msg\">根据状态冻结或解冻应用</string>\n    <string name=\"pref_default_freezing_method\">默认冻结方式</string>\n    <string name=\"pref_default_freezing_method_description\">没有选择冻结方式选项时默认使用的方式。</string>\n    <string name=\"suspend_app\">暂停</string>\n    <string name=\"hide_app\">隐藏</string>\n    <plurals name=\"alert_failed_to_freeze\">\n        <item quantity=\"other\">无法冻结 %1$d 个应用</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_unfreeze\">\n        <item quantity=\"other\">无法解冻 %1$d 个应用</item>\n    </plurals>\n    <string name=\"suspend_app_description\">这是最弱的冻结方式。被暂停的应用仍可出现在启动器中，但图标会变灰且无法被启动。</string>\n    <string name=\"disable_app_description\">推荐的冻结方式。它会禁用应用及其所有部件，但所有快捷方式会丢失。</string>\n    <string name=\"sort_by_frozen_app\">已冻结应用优先</string>\n    <string name=\"filter_frozen_apps\">已冻结应用</string>\n    <string name=\"pref_appearance_description\">主题、方向、功能等。</string>\n    <string name=\"pref_privacy\">隐私</string>\n    <string name=\"pref_privacy_description\">屏幕锁、授权等。</string>\n    <string name=\"user_manual\">用户手册</string>\n    <string name=\"get_help\">获取帮助</string>\n    <string name=\"pref_version_changelog\">版本/变更日志</string>\n    <string name=\"file_open_with\">打开方式</string>\n    <string name=\"file_change_open_with\">更改打开方式</string>\n    <string name=\"file_accessed_date\">访问日期</string>\n    <string name=\"file_properties\">属性</string>\n    <string name=\"file_cut\">剪切</string>\n    <string name=\"fm_always_open_with\">始终打开</string>\n    <string name=\"fm_open_with_for_this_file_only\">仅对此文件</string>\n    <string name=\"file_open_as\">打开为…</string>\n    <string name=\"file_open_with_os_default_dialog\">使用操作系统默认对话框打开</string>\n    <string name=\"open_as_text\">文本</string>\n    <string name=\"open_as_video\">视频</string>\n    <string name=\"open_as_archive\">压缩文件</string>\n    <string name=\"open_as_folder\">文件夹</string>\n    <string name=\"confirm_file_deletion\">确定，删除</string>\n    <string name=\"on_unfreeze_open_application\">解冻后打开应用</string>\n    <string name=\"on_open_application_no_recents\">不要在“最近”中显示启动过的应用</string>\n    <string name=\"tap_to_freeze_app\">轻按冻结</string>\n    <string name=\"waiting_for_the_phone_to_be_locked\">等待手机锁定…</string>\n    <string name=\"file_shortcut_target_file\">目标文件</string>\n    <string name=\"open_as_other\">其他</string>\n    <string name=\"action_stop_service\">停止</string>\n    <string name=\"file_modification_date\">更改日期</string>\n    <string name=\"file_open_with_custom_activity\">自定义</string>\n    <string name=\"open_as_image\">图片</string>\n    <string name=\"freeze_on_phone_locked\">手机锁定时自动冻结应用</string>\n    <string name=\"delete_filename\">删除 %s</string>\n    <string name=\"file_creation_date\">创建日期</string>\n    <string name=\"sort_by_data_usage\">数据使用</string>\n    <string name=\"filter_apps_with_keystore\">使用密钥库</string>\n    <string name=\"filter_apps_with_saf\">使用 SAF</string>\n    <string name=\"filter_apps_with_ssaid\">使用 SSAID</string>\n    <string name=\"action_continue\">继续</string>\n    <string name=\"install_for_another_user\">选择安装用户…</string>\n    <string name=\"confirm_uninstallation\">确认卸载</string>\n    <string name=\"grant_required_permission\">授予所需权限</string>\n    <string name=\"grant_overlay_permission_message\">允许 App Manager 在所有其他窗口之上显示悬浮窗</string>\n    <string name=\"grant_accessibility_permission_for_tracking_window_contents\">允许 App Manager 使用辅助功能来跟踪前台窗口的内容。</string>\n    <string name=\"class_hierarchy\">层次结构</string>\n    <string name=\"title_ui_tracker\">UI 跟踪器</string>\n    <string name=\"title_terminal_emulator\">终端</string>\n    <string name=\"title_labs_activity\">实验室</string>\n    <string name=\"optimize_option_compile_layouts\">编译布局资源</string>\n    <string name=\"optimize_option_check_profiles\">在 DEX 优化期间考虑配置文件数据</string>\n    <string name=\"optimize_option_force_compilation\">即使不必要也强制编译</string>\n    <string name=\"optimize_option_force_dexopt\">立即执行DEX优化</string>\n    <string name=\"title_perform_runtime_optimization_to_apps\">进行运行时优化</string>\n    <string name=\"action_run\">运行</string>\n    <plurals name=\"alert_failed_to_optimize_apps\">\n        <item quantity=\"other\">无法优化%1$d 应用</item>\n    </plurals>\n    <string name=\"export_app_list_select_format\">选择导出应用列表的格式</string>\n    <string name=\"optimize_option_clear_profile_data\">清除之前的配置文件数据</string>\n    <string name=\"select_a_dex2oat_compiler_filter\"><tt>dex2oat</tt> 编译器筛选器</string>\n    <string name=\"summary_perform_runtime_optimization_to_apps\">优化DEX和（在Android 10和更高版本）布局，以提高应用的性能。</string>\n    <string name=\"action_optimize_app\">优化</string>\n    <string name=\"batch_ops_runtime_optimization\">运行时优化</string>\n    <string name=\"app_manager_build_expired\">需要更新</string>\n    <string name=\"app_manager_build_expired_message\">为了确保设备和数据的安全，你正在使用的App Manager的版本已经结束支持了。请更新至最新版本才可继续使用，若无更新，请立即卸载。</string>\n    <string name=\"app_manager_build_expiring_soon_warning\">该版本的App Manager即将过期，请立即更新到最新版本。</string>\n    <string name=\"renamed_successfully\">已重命名</string>\n    <string name=\"selinux_context\">SELinux 上下文</string>\n    <string name=\"unix_file_permissions\">模式</string>\n    <string name=\"file_group_id\">组（GID）</string>\n    <string name=\"file_owner_id\">所有者 (UID)</string>\n    <string name=\"calculating_file_size\">计算中…</string>\n    <string name=\"sort_by_filename\">名称</string>\n    <string name=\"sort_by_last_modified\">最后更改</string>\n    <string name=\"sort_by_file_size\">文件大小</string>\n    <string name=\"sort_by_file_type\">文件类型</string>\n    <string name=\"option_display_dot_files\">显示.开头文件</string>\n    <string name=\"option_display_folders_on_top\">文件夹置顶</string>\n    <string name=\"export_app_list\">导出应用列表</string>\n    <string name=\"export_option_xml\">XML</string>\n    <string name=\"export_option_markdown\">Markdown 格式</string>\n    <string name=\"adb_incomplete_usb_debugging_title\">不完整的 USB 调试</string>\n    <string name=\"funding_campaign_dialog_message\">我们正在限时为应用程序管理器开展 <b> 筹资活动 </b>。访问 <a href=\"https://opencollective.com/app-manager#category-ABOUT\">opencollective.com/app-manager</a> 以了解有关该活动的更多信息。此通知不会再次显示，但您可以在整个活动期间的“设置”页面中找到它。</string>\n    <string name=\"app_can_write_and_execute_in_same_place\">应用程序违反了<a href=\"https://en.wikipedia.org/wiki/W%5EX\">W^X策略</a>，并且能够在同一目录或内存的同一部分中写入和执行。这允许通过修改应用程序中嵌入的可执行文件或从Internet下载来执行任意可执行文件。除非这是应用程序的预期行为（如终端模拟器），建议找到针对SDK 29（Android 10）和更高版本的应用程序的更新版本，或找到替代方案。</string>\n    <string name=\"adb_incomplete_usb_debugging_message\">看起来USB调试配置不正确。请阅读 <a href=\"https://muntashirakon.github.io/AppManager/#subsec:enable-usb-debugging\"> 文档 </a> 了解其他步骤。如果您已经知道步骤，请单击“打开”以打开开发人员选项，或单击“关闭”以继续使用无root模式。</string>\n    <string name=\"funding_campaign_text\">我们正为 App Manager 举办一个限时的<b>筹款活动</b>。<a href=\"https://opencollective.com/app-manager#category-ABOUT\">了解更多……</a></string>\n    <string name=\"title_domains_supported_by_the_app\">支持的域名</string>\n    <string name=\"app_info_tag_open_links\">打开链接</string>\n    <string name=\"source_stamp_verified_and_identified_to_be_from_source\">已验证并查明 SourceStamp 来自 <xliff:g id=\"source\" example=\"Google Play\">%1$s</xliff:g>。</string>\n    <string name=\"pref_zip_align\">对齐APK文件</string>\n    <string name=\"read_only_file_warning\">更改不能被写入至此文件，可能由于其位于 App Manager 无写入权限的卷中，需要存到另一个地方吗\\?</string>\n    <string name=\"line_separator\">行分隔符</string>\n    <string name=\"pref_layout_direction\">布局方向</string>\n    <string name=\"block_unblock_components_dots\">禁用/解禁组件…</string>\n    <string name=\"unblock_components_dots\">解禁组件…</string>\n    <string name=\"block_unblock_components_description\">禁用或解禁具有特定签名的所有组件</string>\n    <string name=\"title_code_editor\">代码编辑器</string>\n    <plurals name=\"alert_failed_to_unblock_components\">\n        <item quantity=\"other\">无法解除对%1$d 应用的组件禁用</item>\n    </plurals>\n    <string name=\"redo\">重做</string>\n    <string name=\"read_only_file\">只读文件</string>\n    <string name=\"pref_zip_align_msg\">对齐APK文件可以减少其内存的使用，因为APK可被直接访问，而无需复制至内存(RAM)中。若<tt>extractNativeLibs</tt> 被设置为<tt>true</tt> 时，此步为必须的。</string>\n    <string name=\"search_option_whole_word\">匹配全字</string>\n    <plurals name=\"search_results\">\n        <item quantity=\"other\">%d 结果</item>\n    </plurals>\n    <string name=\"search_option_regex\">正则表达式</string>\n    <string name=\"replacement_text\">替换</string>\n    <string name=\"action_replace_all\">全部替换</string>\n    <string name=\"search_option_match_case\">匹配大小写</string>\n    <string name=\"uninstall_app_again_message\">在未清除数据和签名的情况下卸载了此应用，需要彻底卸载它吗？</string>\n    <string name=\"uninstall_app\">卸载%1$s</string>\n    <string name=\"debloat_list_type\">列表</string>\n    <string name=\"debloat_removal_type\">类型</string>\n    <string name=\"debloater_title\">预装卸载器</string>\n    <string name=\"system_app_put_back\">放回(Put back)</string>\n    <string name=\"debloat_list_oem\">OEM(厂商)</string>\n    <string name=\"debloat_list_carrier\">Carrier/ISP(运营商)</string>\n    <string name=\"debloat_list_google\">Google(谷歌)</string>\n    <string name=\"debloat_list_aosp\">AOSP(Android原生)</string>\n    <string name=\"debloat_list_misc\">杂项</string>\n    <string name=\"debloat_removal_safe\">安全</string>\n    <string name=\"debloat_removal_replace\">替换</string>\n    <string name=\"debloat_removal_caution\">留意</string>\n    <string name=\"static_shared_library\">静态共享库</string>\n    <string name=\"filter_force_stopped_apps\">已停止运行的应用</string>\n    <plurals name=\"folder_count\">\n        <item quantity=\"other\">%d 个文件夹</item>\n    </plurals>\n    <plurals name=\"file_count\">\n        <item quantity=\"other\">%d 个文件</item>\n    </plurals>\n    <string name=\"empty_folder\">空</string>\n    <string name=\"go_to_path\">转至…</string>\n    <string name=\"copy_this_path\">复制路径</string>\n    <string name=\"title_audio_player\">音频播放器</string>\n    <string name=\"restoring_app\">正在恢复 %1$s…</string>\n    <string name=\"symbolic_link\">符号链接</string>\n    <string name=\"create_new_folder\">新建文件夹</string>\n    <string name=\"create_new_file\">新建文件</string>\n    <string name=\"invalid_target_path\">无效路径</string>\n    <string name=\"conflict_detected_while_copying_message\">此位置中已存在名为“%1$s”的项目。你想换掉它吗？</string>\n    <string name=\"moved_successfully\">已移动</string>\n    <string name=\"title_change_selinux_context\">更改SELinux上下文</string>\n    <string name=\"warning_working_on_system_mode\">警告：在系统上运行，而不是在ADB模式下运行。</string>\n    <string name=\"backing_up_app\">正在备份 %1$s…</string>\n    <string name=\"installing_package\">正在安装 %1$s…</string>\n    <string name=\"enter_target_path\">目标路径</string>\n    <string name=\"title_confirm_deletion\">确认删除</string>\n    <string name=\"copy_these_paths\">复制路径</string>\n    <string name=\"failed_to_copy_specified_file\">无法复制“%1$s”。</string>\n    <string name=\"failed_to_delete_specified_file_after_copying\">复制“%1$s”后无法将其删除，可能是权限不足。</string>\n    <string name=\"pref_send_notifications_to_connected_devices\">向联网的设备发送通知</string>\n    <string name=\"symbolic_link_not_supported\">此文件夹不支持创建符号链接。</string>\n    <string name=\"copied_successfully\">已复制。</string>\n    <string name=\"pref_installer_force_dexopt_description\">安装应用程序后立即执行DEX优化，无需等待系统在系统空闲时执行此操作。</string>\n    <string name=\"create_new_symbolic_link\">新建符号链接</string>\n    <string name=\"pref_send_notification_to_connected_devices_msg\">设置是否向可穿戴设备等联网设备发送通知。</string>\n    <string name=\"change_mode\">更改模式</string>\n    <string name=\"enter_symbolic_link_name\">链接名称</string>\n    <string name=\"profile_modified_are_you_sure\">配置文件已更改。放弃所有更改并退出吗？</string>\n    <string name=\"title_alternatives_to_bloatware\">备选</string>\n    <string name=\"pref_enable_persistent_session_msg\">在后台运行 App Manager 可减少初始化延迟。如果您经常使用 App Manager ，这很有用。</string>\n    <string name=\"copy_keep_both_file\">保留两者</string>\n    <string name=\"path_not_a_folder\">“%1$s” 不是一个文件夹</string>\n    <string name=\"debloat_removal_caution_short_description\">谨慎删除</string>\n    <string name=\"path_does_not_exist\">“%1$s” 不存在</string>\n    <string name=\"conflict_detected_while_copying\">检测到冲突</string>\n    <string name=\"pref_files_remember_last_path_msg\">启用该选项后，打开新窗口会打开上次打开的文件夹而不是主文件夹。</string>\n    <string name=\"debloat_removal_safe_short_description\">可安全删除</string>\n    <string name=\"folder\">文件夹</string>\n    <string name=\"browse_files\">浏览</string>\n    <string name=\"action_lock_app\">锁定</string>\n    <string name=\"pref_files_msg\">配置文件管理器。</string>\n    <string name=\"app_manager_is_unlocked\">App Manager 已解锁</string>\n    <string name=\"pref_files_display_in_launcher\">在应用程序抽屉中显示“文件”</string>\n    <string name=\"apply_profile\">应用配置文件“%1$s”</string>\n    <string name=\"tap_to_open_notification_settings\">轻按隐藏</string>\n    <string name=\"change_owner_uid\">更改所有者 （UID）</string>\n    <string name=\"action_checking\">检查中…</string>\n    <string name=\"installer_options\">安装器选项</string>\n    <string name=\"pref_enable_persistent_session\">让 App Manager 在后台运行</string>\n    <string name=\"scan_report_from_pithus\">Pithus 报告</string>\n    <string name=\"pref_set_home\">设置主目录</string>\n    <string name=\"module_name\">模块名</string>\n    <string name=\"copy_profile_id\">复制配置 ID</string>\n    <string name=\"profile_id\">配置 ID</string>\n    <string name=\"xposed_module_info\">Xposed 模块信息</string>\n    <string name=\"pref_enable_auto_lock\">自动锁定</string>\n    <string name=\"report_not_available\">不可用</string>\n    <string name=\"pref_enable_auto_lock_msg\">当设备锁定时同时锁定 App Manager 。</string>\n    <string name=\"pref_files_remember_last_path\">记住上次打开的路径及其位置</string>\n    <string name=\"change_group_gid\">更改组（GID）</string>\n    <string name=\"app_manager_is_running\">App Manager 正在运行</string>\n    <string name=\"choose_a_profile_state\">选择配置文件状态</string>\n    <string name=\"apply_recursively\">应用于包含的文件</string>\n    <string name=\"title_description\">描述</string>\n    <string name=\"debloat_removal_replace_short_description\">使用备选代替</string>\n    <string name=\"pref_toggle_internet_msg\">在App Manager中激活互联网功能</string>\n    <string name=\"launch_activity_dialog_title\">启动活动：需要采取操作</string>\n    <string name=\"launch_activity_dialog_message\">App Manager正在尝试通过<b>搜索助手</b>（通常为Google Assistant）启动活动，但由于权限不足而无法执行该操作。要打开活动，请手动打开<b>搜索助手</b>（通常通过长按Home键来完成）。在你启动活动完成后，点击<b>关闭</b>按钮以恢复为原始助手。</string>\n    <string name=\"pref_use_vt\">使用VirusTotal</string>\n    <string name=\"virus_total\">VirusTotal</string>\n    <string name=\"netpolicy_reject_metered_background_data\">在按流量计费的网络上阻止后台数据</string>\n    <string name=\"netpolicy_reject_metered_data\">在按流量计费的网络上阻止数据</string>\n    <string name=\"netpolicy_allow_metered_background_data\">在省流器开启时仍在按流量计费的网络上允许后台数据</string>\n    <string name=\"select_filter\">选择筛选器</string>\n    <string name=\"size_in_bytes\">大小（字节）</string>\n    <string name=\"invalid_regex\">无效的正则表达式！</string>\n    <string name=\"value_cannot_be_empty\">值不能为空！</string>\n    <string name=\"date\">日期</string>\n    <string name=\"pref_use_vt_no_internet\">VirusTotal需要连接至互联网以运行，但互联网并未被启用。请先<a href=\"app-manager://settings/privacy_prefs/toggle_internet\">“启用互联网”</a>。</string>\n    <string name=\"pref_use_log_viewer\">使用日志查看器</string>\n    <string name=\"pref_installer\">使用安装器</string>\n    <string name=\"pref_cat_general\">通用</string>\n    <string name=\"status_remote_server_active\">远程服务器启用中</string>\n    <string name=\"status_remote_server_inactive\">远程服务器未启用</string>\n    <string name=\"status_remote_services_active\">远程服务启用中</string>\n    <string name=\"status_remote_services_inactive\">远程服务未启用</string>\n    <string name=\"status_connecting\">连接中…</string>\n    <string name=\"status_connecting_via_mode\">正在通过%s连接</string>\n    <string name=\"status_connected_via_mode\">已通过%s连接</string>\n    <string name=\"status_not_connected_via_mode\">无法通过%s连接</string>\n    <string name=\"adb_pairing_instruction\">请转到开发者选项以启用无线调试并生成配对码。如果已经打开了开发者选项，请单击 <b>手册</b>。</string>\n    <string name=\"adb_pairing_searching_for_port\">搜索中…</string>\n    <string name=\"adb_pairing_stop_searching\">停止</string>\n    <string name=\"adb_pairing_input_pairing_code\">配对码</string>\n    <string name=\"adb_pairing_pairing_code\">配对码</string>\n    <string name=\"adb_pairing_found_pairing_service_with_port\">在端口%d中寻找服务</string>\n    <string name=\"adb_pairing_pairing_in_progress\">配对中…</string>\n    <string name=\"adb_pairing_retry_pairing\">重试</string>\n    <string name=\"mode_of_op_custom_command_title\">自定义命令</string>\n    <string name=\"mode_of_op_custom_command\">如果您无法使用任何模式，您可以在任何受支持的 shell 中运行以下命令，以在特权模式下运行App Manager：</string>\n    <string name=\"finder_title\">访达</string>\n    <string name=\"mode_of_op_alternative_custom_command\">如果运行以上命令遇到“permission denied”错误，请运行下列命令：</string>\n    <string name=\"actual_installer\">实际安装者</string>\n    <string name=\"apk_source\">APK 源</string>\n    <string name=\"backup_cache\">缓存</string>\n    <string name=\"pref_use_system_font\">使用系统字体</string>\n    <string name=\"sensors\">传感器</string>\n    <string name=\"tag_sensors_disabled\">已禁用传感器</string>\n    <string name=\"pref_use_system_font_msg\">使用系统默认字体而非 material 字体。<font fgcolor=\"#ff0000\">这是实验性功能。</font></string>\n    <string name=\"activity_name\">Activity 名称</string>\n    <string name=\"available_memory\">可用内存：%s</string>\n    <string name=\"action_manual\">手动</string>\n    <string name=\"vulkan_version\">Vulkan 版本</string>\n    <string name=\"battery_technology\">技术</string>\n    <string name=\"battery_health\">健康度</string>\n    <string name=\"verified_boot\">已验证的启动</string>\n    <string name=\"android_verified_bootloader_version\">AVB 版本</string>\n    <string name=\"op_history\">历史记录</string>\n    <string name=\"no_history\">无记录</string>\n    <string name=\"title_confirm_execution\">确认执行</string>\n    <string name=\"clear_history\">清除记录</string>\n    <string name=\"favorites\">收藏</string>\n    <string name=\"add_to_favorites\">添加到收藏</string>\n    <string name=\"item_remove\">删除</string>\n    <string name=\"item_edit\">编辑</string>\n    <string name=\"remove_filename\">删除 %s</string>\n    <string name=\"advanced_suspend_app\">高级暂停</string>\n    <string name=\"advanced_suspend_app_description\">它强制停止并暂停应用确保应用不在后台运行。此方法的优先程度应高于常规的 <b>暂停</b>方法。</string>\n    <string name=\"freeze_prefer_per_app_option\">优先考虑不同应用不同选项</string>\n    <string name=\"remember_option_for_this_app\">记住此应用的选项</string>\n    <string name=\"overlay_category\">类别</string>\n    <string name=\"overlay_sdk_version_too_low\">遮盖层不被支持。</string>\n    <string name=\"no_overlays\">无遮盖层</string>\n    <string name=\"overlays\">遮盖层</string>\n    <string name=\"no_overlay_permission\">没有展示遮盖层的权限</string>\n    <string name=\"sort_by_overlay_names\">遮盖层名称</string>\n    <string name=\"sort_by_priority\">优先级</string>\n    <string name=\"overlay_target\">目标</string>\n    <string name=\"title_shortcut_for_frozen_app\">冻结的应用</string>\n    <string name=\"title_overlay\">遮罩</string>\n    <string name=\"message_shortcut_for_frozen_app\">对应于该快捷方式的应用似乎已被冻结。临时解冻并打开该快捷方式？</string>\n</resources>\n"
  },
  {
    "path": "app/src/main/res/values-zh-rTW/disclaimer.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- SPDX-License-Identifier: GPL-3.0-or-later --><resources>\n    <string name=\"disclaimer_header\">免責聲明</string>\n    <string name=\"disclaimer_footer\">© 2020–2024 Muntashir Al-Islam</string>\n    <string name=\"disclaimer_agree_forever\">不再顯示此訊息</string>\n    <string name=\"disclaimer_agree\">我同意</string>\n    <string name=\"disclaimer_exit\">退出</string>\n    <string name=\"disclaimer_body\">App Manager 提供 root 功能，如果使用不當，可能會損害您的裝置。對使用此應用程式造成的任何損害不承擔責任。如果您不完全瞭解 root 的工作原理，則應避免使用 root 選項，直到您完全了解風險。\n\\n\n\\n向其他應用程式和網站提供的任何連結都適合使用者。但不負責任何內容，你可能會發現連結至外部的連結。\n\\n\n\\n使用 App Manager 時，您需承擔自己的使用的全部責任，並且不會因濫用而承擔任何損害、索賠或貨幣價值。\n\\n\n\\n使用此應用程式，即表示您接受使用該應用程式的所有責任，並同意對於您做出的任何對您的裝置有不利影響的行為不負責。</string>\n</resources>"
  },
  {
    "path": "app/src/main/res/values-zh-rTW/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- SPDX-License-Identifier: GPL-3.0-or-later --><resources xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\" xmlns:tools=\"http://schemas.android.com/tools\">\n    <string name=\"_lang_tag\" translatable=\"false\">zh-TW</string>\n    <string name=\"uninstall\">解除安裝</string>\n    <string name=\"permissions\">使用權限</string>\n    <string name=\"sort_by_last_update\">最後更新</string>\n    <string name=\"error\">錯誤</string>\n    <string name=\"loading\">載入中…</string>\n    <!-- &#8230; = ... -->\n    <string name=\"system\">系統</string>\n    <string name=\"sort\">種類</string>\n    <string name=\"version_name_with_code\">版本 <xliff:g id=\"version_name\" example=\"2.5.17\">%1$s</xliff:g> (<xliff:g id=\"version_code\" example=\"365\">%2$d</xliff:g>)</string>\n    <string name=\"app_info\">應用程式資訊</string>\n    <string name=\"system_app\">系統應用程式</string>\n    <string name=\"user_app\">使用者應用程式</string>\n    <string name=\"date_installed\">安裝日期</string>\n    <string name=\"date_updated\">更新日期</string>\n    <string name=\"installer_app\">安裝程式</string>\n    <string name=\"share_apk\">分享 APK</string>\n    <string name=\"saved_successfully\">已儲存</string>\n    <string name=\"saving_failed\">儲存失敗，請重試。</string>\n    <string name=\"uninstalled_successfully\"><xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g> 已被解除安裝。</string>\n    <string name=\"failed_to_uninstall\">無法解除安裝 <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g>.</string>\n    <plurals name=\"main_list_date_days\">\n        <item quantity=\"other\"><xliff:g id=\"last_update_date\" example=\"20/10/2020\">%1$s</xliff:g> <xliff:g id=\"day_no\" example=\"5\">%2$d</xliff:g> 天</item>\n    </plurals>\n    <plurals name=\"other_trackers_and_classes\">\n        <item quantity=\"other\"><xliff:g id=\"tracker_no\" example=\"8\">%1$d</xliff:g> 帶有 <xliff:g id=\"class_no\" example=\"50\"> %2$d </xliff:g> 類的追蹤器</item>\n    </plurals>\n    <plurals name=\"two_trackers_and_classes\">\n        <item quantity=\"other\">2 個追蹤器，帶 <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g> 類</item>\n    </plurals>\n    <plurals name=\"tracker_and_classes\">\n        <item quantity=\"other\">1 個追蹤器，帶 <xliff:g id=\"class_no\" example=\"50\">%1$d</xliff:g> 類</item>\n    </plurals>\n    <string name=\"starting_activity\">開始活動：<xliff:g id=\"activity_name\" example=\".main.MainActivity\">%1$s</xliff:g></string>\n    <string name=\"pref_about_msg\">App Manager 版本，授權協議，致謝名單等。</string>\n    <string name=\"flags\">旗標</string>\n    <string name=\"launch_mode\">開啟方式</string>\n    <string name=\"ssaid_info\">SSAID（<tt> Settings.Secure.ANDROID_ID </tt>）是分配給每個應用程式的裝置標識字串（從 Android 8“ Oreo”開始）。應用程式廣泛使用它來追蹤使用者。</string>\n    <string name=\"type_component_name\">元件名稱</string>\n    <string name=\"window_size\">視窗尺寸</string>\n    <string name=\"input_keystore_alias_pass_description\">插入別名的密碼<b>%1$s</b> 。如果密碼與 KeyStore 密碼相同，則可以將其保留為空。</string>\n    <string name=\"input_keystore_alias_pass\">別名密碼<b>%1$s</b></string>\n    <string name=\"user_profile_with_id\">設定檔：%1$s（%2$d）</string>\n    <string name=\"failed_to_uninstall_updates\">無法解除安裝 <xliff:g id=\"app_name\" example=\"App Manager\"> %1$s </xliff:g> 的更新。</string>\n    <string name=\"update_uninstalled_successfully\"><xliff:g id=\"app_name\" example=\"App Manager\"> %1$s </xliff:g> 的更新已解除安裝。</string>\n    <string name=\"process_state_with_extra\">狀態： <xliff:g id=\"process_state\" example=\"Sleeping\">%1$s</xliff:g> (<xliff:g id=\"state_extra\" example=\"High priority\">%2$s</xliff:g>)</string>\n    <string name=\"process_state\">狀態： <xliff:g id=\"process_state\" example=\"Sleeping\">%1$s</xliff:g></string>\n    <string name=\"locale_split_for_base_apk\"><xliff:g id=\"split_name\" example=\"English\"> %1$s </xliff:g>基本語言環境 APK</string>\n    <string name=\"locale_split_for_feature\"><xliff:g id=\"split_name\" example=\"English\">%1$s</xliff:g> 功能的著域 <xliff:g id=\"feature_name\" example=\"Visualizer\"> %2$s </xliff:g></string>\n    <string name=\"abi_split_for_base_apk\"><xliff:g id=\"split_name\" example=\"arm64_v8a\">%1$s</xliff:g> 基本 APK 程式碼</string>\n    <string name=\"abi_split_for_feature\"><xliff:g id=\"split_name\" example=\"arm64_v8a\">%1$s</xliff:g> <xliff:g id=\"feature_name\" example=\"Visualizer\"> %2$s </xliff:g></string>\n    <string name=\"density_split_for_base_apk\"><xliff:g id=\"split_name\" example=\"xxdpi\">%1$s</xliff:g> （<xliff:g id=\"dpi_no\" example=\"480\">%2$d</xliff:g> DPI） 基礎 APK 資源</string>\n    <string name=\"density_split_for_feature\"><xliff:g id=\"split_name\" example=\"xxdpi\">%1$s</xliff:g> （<xliff:g id=\"dpi_no\" example=\"480\">%2$d</xliff:g> DPI） 功能資源 <xliff:g id=\"feature_name\" example=\"Visualizer\">%3$s</xliff:g></string>\n    <string name=\"unknown_split_for_base_apk\"><xliff:g id=\"split_name\" example=\"some_split\">%1$s</xliff:g> 用於基本 APK</string>\n    <string name=\"unknown_split_for_feature\"><xliff:g id=\"split_name\" example=\"some_split\">%1$s</xliff:g> 功能 <xliff:g id=\"feature_name\" example=\"Visualizer\">%2$s</xliff:g></string>\n    <string name=\"split_feature_name\">特寫： <xliff:g id=\"feature_name\" example=\"Visualizer\">%1$s</xliff:g></string>\n    <string name=\"installer_error_blocked\">安裝被 <xliff:g id=\"app_name\" example=\"App Manager\"> %1$s </xliff:g> 封鎖</string>\n    <string name=\"pref_remove_all_rules_msg\">將授予權限，應用程式操作和元件將還原為其預設值。</string>\n    <plurals name=\"verified_with_warning\">\n        <item quantity=\"other\">Verified with%d warning</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_set_app_ops\">\n        <item quantity=\"other\">無法為 %1$d 應用設置應用操作</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_block_components\">\n        <item quantity=\"other\">無法封鎖%1$d應用程式的元件</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_unblock_trackers\">\n        <item quantity=\"other\">無法從 %1$d 應用程式中解除封鎖追蹤器</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_delete_backup\">\n        <item quantity=\"other\">Could not delete%1$d backup</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_restore\">\n        <item quantity=\"other\">Could not restore%1$d app</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_backup\">\n        <item quantity=\"other\">Could not back up%1$d app</item>\n    </plurals>\n    <plurals name=\"failed_to_backup_some_apk_files\">\n        <item quantity=\"other\">Could not back up%1$d app</item>\n    </plurals>\n    <string name=\"backup\">備份</string>\n    <string name=\"package_name_is_installed_successfully\"><xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g> 已安裝</string>\n    <string name=\"block_components_dots\">封鎖元件…</string>\n    <string name=\"block_unblock_trackers_description\">封鎖或取消封鎖廣告並追蹤所有已安裝應用程式中的元件</string>\n    <string name=\"pref_import_existing_msg\">將其他應用程式停用的元件新增到 App Manager 。 使用此工具時要小心，因為可能會有很多誤報。僅選擇您確定的應用程式。</string>\n    <string name=\"pref_import_existing\">匯入現有規則</string>\n    <string name=\"source_code\">原始碼</string>\n    <string name=\"launch_app\">開啟</string>\n    <plurals name=\"alert_failed_to_disable_trackers\">\n        <item quantity=\"other\">無法停用%1$d應用程式的追蹤器</item>\n    </plurals>\n    <string name=\"sort_by_component_name\">元件名稱</string>\n    <string name=\"follow_system\">跟隨系統</string>\n    <string name=\"pref_import_blocker_msg\">從Blocker匯入封鎖規則，每個檔案都包含單個套件的規則。</string>\n    <string name=\"pref_import_watt_msg\">從 Watt 匯入封鎖規則，每個檔案包含單個套件名稱的規則，如下所示：<tt> packagename.xml</tt> 等等。</string>\n    <string name=\"pref_import_msg\">從 App Manager 匯入以前匯出的封鎖規則。</string>\n    <string name=\"pref_export_msg\">將在 App Manager 中配置的封鎖規則匯出到外部儲存空間。</string>\n    <string name=\"export_failed\">匯出失敗！</string>\n    <string name=\"import_failed\">匯入失敗！</string>\n    <string name=\"export_options\">匯出選項</string>\n    <string name=\"import_options\">匯入選項</string>\n    <plurals name=\"alert_failed_to_force_stop\">\n        <item quantity=\"other\">Could not force-stop%1$d app</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_disable_background\">\n        <item quantity=\"other\">Could not prevent%1$d app from running in the background</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_uninstall\">\n        <item quantity=\"other\">Could not uninstall%1$d app</item>\n    </plurals>\n    <plurals name=\"alert_failed_to_clear_data\">\n        <item quantity=\"other\">Could not clear data from%1$d app</item>\n    </plurals>\n    <string name=\"user_and_uid\">使用者： <xliff:g id=\"user_name\" example=\"root\">%1$s</xliff:g> （<xliff:g id=\"user_id\" example=\"0\">%2$d</xliff:g>）</string>\n    <string name=\"user_with_id\">使用者： <xliff:g id=\"user_id\" example=\"0\">%1$d</xliff:g></string>\n    <string name=\"memory_virtual_memory\">記憶體：%1$s，虛擬記憶體：%2$s</string>\n    <string name=\"pid_and_ppid\">處理程序 ID：%1$d，父級處理程序 ID：%2$d</string>\n    <plurals name=\"failed_to_import_files\">\n        <item quantity=\"other\">Could not import%1$d file.</item>\n    </plurals>\n    <string name=\"pref_import_blocker\">從攔截器匯入</string>\n    <string name=\"pref_import_export_blocking_rules_msg\">匯入/匯出規則，從 Watt 或 Blocker 匯入外部規則。</string>\n    <string name=\"pref_import_export_blocking_rules\">匯入/匯出封鎖規則</string>\n    <string name=\"external_multiple_data_dir\">外部資料目錄 <xliff:g id=\"dir_no\" example=\"1\">%1$d</xliff:g></string>\n    <string name=\"pref_global_blocking_enabled_msg\">使您可以封鎖任何應用程式的任何元件，而無需顯式開啟該應用程式的封鎖功能。</string>\n    <string name=\"pref_global_blocking_enabled\">即時元件封鎖</string>\n    <string name=\"failed_to_stop\">無法停止 <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g>.</string>\n    <string name=\"task_affinity\">任務親和性</string>\n    <string name=\"launch\">啟動</string>\n    <string name=\"filter_apps_without_backups\">沒有備份的</string>\n    <string name=\"uninstalled_apps\">解除安裝的應用程式</string>\n    <string name=\"installer_app_message\">按一下<b>選擇</b> 從已安裝的應用程式中選擇或按一下<b>自訂</b> 指定自訂套件名稱。</string>\n    <string name=\"specify_custom_name\">自訂</string>\n    <string name=\"verified_using_unreliable_hash\">使用不可靠的哈希值進行了驗證</string>\n    <string name=\"working_on_adb_mode\">在ADB模式下運作</string>\n    <string name=\"screen_lock_not_enabled\">在 Android 設定中啟用螢幕鎖定或清除應用程式資料。</string>\n    <string name=\"isolated\">隔離的</string>\n    <string name=\"last_actions\">最後動作</string>\n    <string name=\"pref_enable_disable_features_msg\">啟用或停用 App Manager 中的功能。</string>\n    <string name=\"enable_disable_features\">啟用/停用功能</string>\n    <string name=\"installed_apps\">已安裝的應用程式</string>\n    <string name=\"restart_to_reflect_changes\">您必須立即重新啟動裝置才能使用新的變更。</string>\n    <string name=\"failed_to_change_ssaid\">無法變更SSAID</string>\n    <string name=\"copied_to_clipboard\">複製到剪貼板。</string>\n    <string name=\"ssaid\">SSAID</string>\n    <string name=\"list_options\">清單選項</string>\n    <string name=\"reverse\">復原</string>\n    <string name=\"os_version\">作業系統版本</string>\n    <string name=\"add\">新增</string>\n    <string name=\"add_to_profile\">新增到設定檔</string>\n    <string name=\"initializing\">初始化中…</string>\n    <string name=\"net_policy\">淨政策</string>\n    <string name=\"has_net_policy\">淨政策</string>\n    <string name=\"choose_what_to_do\">選擇要做什麼。</string>\n    <string name=\"enable_battery_optimization\">啟用電池優化？</string>\n    <string name=\"battery_optimization\">電池優化</string>\n    <string name=\"no_battery_optimization\">沒有電池優化</string>\n    <string name=\"type_uri\">位址類型</string>\n    <string name=\"type_string_array_list\">字串清單</string>\n    <string name=\"type_string_array\">字串數組</string>\n    <string name=\"type_float_array_list\">十進制數字清單</string>\n    <string name=\"type_float_array\">十進制數字數組</string>\n    <string name=\"type_long_array_list\">長整數清單</string>\n    <string name=\"type_long_array\">長整數數組</string>\n    <string name=\"type_int_array_list\">整數清單</string>\n    <string name=\"type_int_array\">整數數組</string>\n    <string name=\"type_null\">沒有價值</string>\n    <string name=\"screen_lock_msg\">使用 Android 螢幕鎖定以鎖定 App Manager</string>\n    <string name=\"screen_lock\">螢幕鎖定</string>\n    <string name=\"unlock_app_manager\">解鎖 App Manager</string>\n    <string name=\"sd_card\">SD卡</string>\n    <string name=\"external_storage\">外部儲存空間</string>\n    <string name=\"internal_storage\">內部儲存空間</string>\n    <string name=\"back_up\">備份</string>\n    <string name=\"drm_free_apkm_msg\">APKM檔案不含DRM，無需將其轉換為APKS。</string>\n    <string name=\"restore_msg\">使用資料還原應用程式</string>\n    <string name=\"backup_msg\">使用資料備份應用程式</string>\n    <string name=\"restore_latest_msg\">還原已安裝的應用程式，其版本代碼高於已安裝的版本代碼。</string>\n    <string name=\"restore_latest\">還原最新備份</string>\n    <string name=\"restore_not_installed_msg\">還原目前未安裝的應用程式的基本備份。</string>\n    <string name=\"restore_not_installed\">還原未安裝的應用程式</string>\n    <string name=\"restore_all_msg\">從所有備份的應用程式還原基本備份。</string>\n    <string name=\"restore_all\">還原所有應用程式</string>\n    <string name=\"backup_apps_with_changes_msg\">重做自上次備份以來具有變更的應用程式的備份。它們包括大小，版本，上次啟動時間的變更。</string>\n    <string name=\"backup_apps_with_changes\">備份變更的應用程式</string>\n    <string name=\"redo_existing_backups_msg\">使用先前的備份重做已安裝應用程式的備份。</string>\n    <string name=\"redo_existing_backups\">重做現有備份</string>\n    <string name=\"verify_and_redo_backups_msg\">檢查完整性檢查失敗的先前備份和重做備份的完整性。</string>\n    <string name=\"verify_and_redo_backups\">驗證並重做備份</string>\n    <string name=\"backup_apps_without_backups_msg\">備份應用程式，而無需任何以前的備份。</string>\n    <string name=\"backup_apps_without_backups\">備份應用程式而無需備份</string>\n    <string name=\"backup_all_apps_msg\">備份所有已安裝的應用程式。</string>\n    <string name=\"backup_all_apps\">備份所有應用程式</string>\n    <string name=\"backup_custom_users_description\">僅對指定使用者執行備份</string>\n    <string name=\"backup_custom_users\">自訂使用者</string>\n    <string name=\"bootloader\">引導載入程式</string>\n    <string name=\"encrypted\">已加密</string>\n    <string name=\"unencrypted\">未加密</string>\n    <string name=\"no_volumes_found\">找不到具有寫入權限的任何卷宗。</string>\n    <string name=\"pref_backup_volume_msg\">選擇將儲存空間備份的卷宗或磁碟。</string>\n    <string name=\"backup_volume\">備份卷宗</string>\n    <string name=\"pref_backup_restore_msg\">自訂備份/還原。</string>\n    <string name=\"disable_background_run_description\">為以下應用操作設定 <i>忽略 </i> 模式： <tt>RUN_IN_BACKGROUND </tt> （來自 Android 7.0） 和 <tt>RUN_ANY_IN_BACKGROUND </tt> （來自 Android 9）。</string>\n    <string name=\"failed_to_enable_magisk_hide\">無法啟用MagiskHide</string>\n    <string name=\"failed_to_disable_magisk_hide\">無法停用MagiskHide</string>\n    <string name=\"refresh_rate\">螢幕更新率</string>\n    <string name=\"scaling_factor\">比例因子</string>\n    <string name=\"size\">尺寸</string>\n    <string name=\"density\">密度</string>\n    <string name=\"screen\">螢幕</string>\n    <string name=\"hardware\">硬體</string>\n    <string name=\"permissive\">寬容</string>\n    <string name=\"enforcing\">嚴格</string>\n    <string name=\"selinux\">SELinux</string>\n    <string name=\"pref_sign_apk_msg\">在安裝 APK 檔案之前，請先對其進行簽名。</string>\n    <string name=\"pref_sign_apk\">簽名 APK</string>\n    <string name=\"install_location_prefer_external\">偏好外部</string>\n    <string name=\"install_location_internal_only\">僅限內部</string>\n    <string name=\"install_location\">安裝位置</string>\n    <string name=\"installer\">安裝</string>\n    <string name=\"comment\">評論</string>\n    <string name=\"close\">關閉</string>\n    <string name=\"no_root\">無 Root</string>\n    <string name=\"root\">Root</string>\n    <string name=\"advanced\">先進的</string>\n    <string name=\"simple\">簡單的</string>\n    <string name=\"enabled\">已啟用</string>\n    <string name=\"choose\">選擇</string>\n    <string name=\"input_permissions_description\">輸入權限，帶空格，例如<tt> com.permission.GET_ACCOUNTS android.permission.ACCESS_MEDIA_LOCATION</tt> 等使用<tt> *</tt> 套用所有權限。</string>\n    <string name=\"input_permissions\">輸入權限</string>\n    <string name=\"options\">選項</string>\n    <string name=\"off\">離開</string>\n    <string name=\"on\">在</string>\n    <string name=\"profile_state_msg\">此配置檔案的自訂開/關狀態</string>\n    <string name=\"profile_block_trackers_msg\">追蹤器將從應用程式中被封鎖</string>\n    <string name=\"profile_clear_data_msg\">資料將從應用程式中清除</string>\n    <string name=\"profile_clear_cache_msg\">快取將從應用程式中清除</string>\n    <string name=\"profile_force_stop_msg\">應用程式將被強制停止</string>\n    <string name=\"allow_routine_ops_msg\">允許在常規操作中使用配置檔案</string>\n    <string name=\"profile_state\">設定檔狀態</string>\n    <string name=\"allow_routine_ops\">允許例行操作</string>\n    <string name=\"adb_over_tcp\">透過 TCP 的 ADB</string>\n    <string name=\"pref_mode_of_operations\">操作模式</string>\n    <string name=\"send_selected\">傳送選擇</string>\n    <string name=\"ecc\">橢圓曲線密碼學</string>\n    <string name=\"rsa\">RSA</string>\n    <string name=\"aes\">AES</string>\n    <string name=\"none\">沒有</string>\n    <string name=\"pref_encryption_msg\">為備份加密。</string>\n    <string name=\"encryption\">加密</string>\n    <string name=\"select_user\">選擇使用者</string>\n    <string name=\"failed_to_duplicate_profile\">無法複製設定檔</string>\n    <string name=\"duplicate\">複製</string>\n    <string name=\"new_profile\">新的配置檔案</string>\n    <string name=\"input_profile_name_description\">配置檔案名稱不能包含任何空格。</string>\n    <string name=\"input_profile_name\">配置檔案名稱</string>\n    <string name=\"un_apkm\">UnApkm</string>\n    <string name=\"in_progress\">進行中</string>\n    <string name=\"conversion_failed\">轉換失敗。</string>\n    <string name=\"select_apk\">選擇 APK</string>\n    <string name=\"send_crash_report\">傳送當機報告</string>\n    <string name=\"tap_to_submit_crash_report\">按一下以傳送當機報告。</string>\n    <string name=\"am_crashed\">App Manager 剛剛當機了</string>\n    <string name=\"filter_running_apps\">正在執行的應用程式</string>\n    <string name=\"copy\">複製</string>\n    <string name=\"view_missing_signatures\">按一下以檢視或傳送尚未出現在 App Manager 的資源庫資料庫中的簽名。</string>\n    <string name=\"tap_to_see_details\">點按即可檢視詳細資訊</string>\n    <string name=\"lib_details\">圖書館資料</string>\n    <string name=\"no_libs\">沒有圖書館</string>\n    <string name=\"scanner\">掃描器</string>\n    <string name=\"sys_config\">系統配置</string>\n    <string name=\"only_install\">僅安裝</string>\n    <string name=\"app_signing_install_without_data_loss\">如果您關閉了簽名驗證，則可以使用<b> 僅安裝</b> 選擇安裝應用程式而不會遺失資料。</string>\n    <string name=\"app_data_will_be_lost\">現有資料將遺失。</string>\n    <string name=\"app_signing_signature_mismatch_for_system_apps\">無法安裝應用程式，因為具有不同簽名的系統應用程式具有此套件名稱。</string>\n    <string name=\"do_you_want_to_uninstall_and_install\">您是否要再次解除安裝並安裝該應用程式？</string>\n    <string name=\"usage_access_not_supported\">由於相應的設定頁面不存在，因此無法要求使用權限。</string>\n    <string name=\"non_critical_exts\">非關鍵擴展</string>\n    <string name=\"critical_exts\">關鍵擴展</string>\n    <string name=\"dsa_affine_y\">仿射坐標</string>\n    <string name=\"dsa_affine_x\">仿射x坐標</string>\n    <string name=\"rsa_modulus\">模量</string>\n    <string name=\"rsa_exponent\">指數</string>\n    <string name=\"format\">格式</string>\n    <string name=\"public_key\">公鑰</string>\n    <string name=\"algorithm\">算法</string>\n    <string name=\"app_signing_signature\">簽名</string>\n    <string name=\"checksums\">校驗和</string>\n    <string name=\"serial_no\">序列號</string>\n    <string name=\"not_yet_valid\">尚未生效</string>\n    <string name=\"expired\">已到期</string>\n    <string name=\"valid\">有效的</string>\n    <string name=\"validity\">有效性</string>\n    <string name=\"type\">類型</string>\n    <string name=\"expiry_date\">到期日</string>\n    <string name=\"issued_date\">發行日期</string>\n    <string name=\"issuer\">發行人</string>\n    <string name=\"subject\">學科</string>\n    <string name=\"filter_apps_with_backups\">帶有備份的</string>\n    <string name=\"sort_by_backup\">預先備份</string>\n    <string name=\"uninstall_updates\">解除安裝更新</string>\n    <string name=\"allow_open_pgp_operation\">按一下以允許 App Manager 使用 OpenPGP</string>\n    <string name=\"confirm_installation\">確認安裝</string>\n    <string name=\"pref_backup_flags_msg\">為備份選項新增預設消除了每次備份/還原時選擇旗標的負擔。</string>\n    <string name=\"pref_compression_method\">壓縮方式</string>\n    <string name=\"rules\">規則</string>\n    <string name=\"other\">其他</string>\n    <string name=\"changes_not_saved\">變更未儲存</string>\n    <string name=\"sort_by_memory_usage\">記憶體使用情況</string>\n    <string name=\"sort_by_apps_first\">應用程式優先</string>\n    <string name=\"sort_by_process_name\">處理程序名稱</string>\n    <string name=\"sort_by_process_id\">處理程序ID</string>\n    <string name=\"filter_apps\">應用程式</string>\n    <string name=\"no_apps\">沒有應用程式</string>\n    <string name=\"apps\">應用程式</string>\n    <string name=\"routine_ops\">例行行動</string>\n    <string name=\"apply_now\">現在套用…</string>\n    <string name=\"keystore\">密鑰資源庫</string>\n    <string name=\"no_profiles\">沒有設定檔</string>\n    <string name=\"profiles\">設定檔</string>\n    <string name=\"open_pgp_provider\">OpenPGP提供者</string>\n    <string name=\"systemless_app\">無系統應用程式</string>\n    <string name=\"cancel\">取消</string>\n    <string name=\"ok\">好的</string>\n    <string name=\"input_backup_name_description\">備份名稱不能以數字開頭，也不能包含任何空格。如果要使用目前日期時間，請將其保留為空。</string>\n    <string name=\"input_backup_name\">備份名稱</string>\n    <string name=\"downgrade\">降級</string>\n    <string name=\"state_multithreaded\">多線程</string>\n    <string name=\"state_foreground\">前景</string>\n    <string name=\"state_session_leader\">會議負責人</string>\n    <string name=\"state_locked_memory\">鎖定的記憶體</string>\n    <string name=\"state_low_priority\">低優先級</string>\n    <string name=\"state_high_priority\">高優先級</string>\n    <string name=\"state_unknown\">未知</string>\n    <string name=\"state_waking\">醒來</string>\n    <string name=\"state_wake_kill\">喚醒殺戮</string>\n    <string name=\"state_idle\">閒置的</string>\n    <string name=\"state_parked\">停放</string>\n    <string name=\"state_zombie\">殭屍</string>\n    <string name=\"state_dead\">死的</string>\n    <string name=\"state_trace_stop\">追蹤停止</string>\n    <string name=\"state_device_io\">裝置I /O</string>\n    <string name=\"state_sleeping\">睡眠</string>\n    <string name=\"touchscreen_finger\">手指</string>\n    <string name=\"touchscreen_stylus\">觸控筆</string>\n    <string name=\"touchscreen_no_touch\">不要觸碰</string>\n    <string name=\"navigation_wheel\">車輪</string>\n    <string name=\"navigation_trackball\">軌跡球</string>\n    <string name=\"navigation_dial_pad\">撥號盤</string>\n    <string name=\"navigation_no_nav\">沒有導航</string>\n    <string name=\"keyboard_12_keys\">12鍵</string>\n    <string name=\"keyboard_qwerty\">QWERTY</string>\n    <string name=\"keyboard_no_keys\">沒有鑰匙</string>\n    <string name=\"_undefined\">不明確的</string>\n    <string name=\"required\">必需的</string>\n    <string name=\"orientation_user_portrait\">使用者頭像</string>\n    <string name=\"orientation_user_landscape\">使用者態勢</string>\n    <string name=\"orientation_sensor\">傳感器</string>\n    <string name=\"orientation_sensor_portrait\">傳感器肖像</string>\n    <string name=\"orientation_sensor_landscape\">傳感器格局</string>\n    <string name=\"orientation_user\">使用者</string>\n    <string name=\"orientation_reverse_landscape\">反向景觀</string>\n    <string name=\"orientation_reverse_portrait\">反向肖像</string>\n    <string name=\"orientation_portrait\">肖像</string>\n    <string name=\"orientation_landscape\">風景</string>\n    <string name=\"orientation_no_sensor\">沒有感應器</string>\n    <string name=\"orientation_locked\">已鎖定</string>\n    <string name=\"orientation_full_user\">完整使用者</string>\n    <string name=\"orientation_full_sensor\">全傳感器</string>\n    <string name=\"orientation_behind\">在後面</string>\n    <string name=\"orientation_unspecified\">未指定</string>\n    <string name=\"launch_mode_single_top\">單頂</string>\n    <string name=\"launch_mode_single_task\">單項任務</string>\n    <string name=\"launch_mode_single_instance\">單實例</string>\n    <string name=\"launch_mode_multiple\">多種的</string>\n    <string name=\"base_apk\">基地 APK</string>\n    <string name=\"choose_language\">變更語言</string>\n    <string name=\"auto\">自動</string>\n    <string name=\"pref_app_language\">語言</string>\n    <string name=\"backup_all_users\">全部使用者</string>\n    <string name=\"backup_multiple\">備份多個</string>\n    <string name=\"obb_files_extracted_successfully\">提取的OBB檔案</string>\n    <string name=\"failed_to_extract_obb_files\">無法提取OBB檔案</string>\n    <string name=\"backup_obb_media\">OBB和媒體</string>\n    <string name=\"backup_apk_files\">APK 檔案</string>\n    <string name=\"installer_error_session_abandon\">無法捨棄安裝程式會話</string>\n    <string name=\"installer_error_session_commit\">無法傳送 APK 檔案</string>\n    <string name=\"installer_error_session_write\">無法寫入安裝程式會話</string>\n    <string name=\"installer_error_session_create\">無法建立安裝程式會話</string>\n    <string name=\"installer_error_security\">無法存取 APK 檔案</string>\n    <string name=\"install_in_progress\">正在安裝…</string>\n    <string name=\"package_installer\">套件安裝程式</string>\n    <string name=\"unblock_trackers\">取消封鎖追蹤器</string>\n    <string name=\"reinstall\">重新安裝</string>\n    <string name=\"install_app_message\">您要安裝此應用程式嗎？</string>\n    <string name=\"try_again\">再試一次</string>\n    <string name=\"full_stop_tap_to_see_details\">。點按可檢視詳細資訊。</string>\n    <string name=\"operation_running\">正在執行…</string>\n    <string name=\"batch_ops\">批次處理操作</string>\n    <string name=\"failed_to_fetch_package_info\">無法取得套件資訊</string>\n    <string name=\"installer_error_lidl_rom\">您的 ROM 與無 Root 安裝程式不相容。</string>\n    <string name=\"installer_error_generic\">安裝失敗</string>\n    <string name=\"installer_error_storage\">沒有足夠的儲存空間空間來安裝應用程式</string>\n    <string name=\"installer_error_bad_apks\">選擇了無效的 APK 檔案</string>\n    <string name=\"installer_error_incompatible\">該應用程式與此裝置不相容</string>\n    <string name=\"installer_error_conflict\">由於與正在使用套件的名稱相衝突，因此無法安裝應用程式</string>\n    <string name=\"installer_error_blocked_device\">裝置</string>\n    <string name=\"installer_error_aborted\">由於安裝被取消或會話意外關閉，安裝失敗</string>\n    <string name=\"toggle_default_app_ops\">切換預設應用程式操作</string>\n    <string name=\"filter_apps_with_activities\">帶有活動的</string>\n    <string name=\"are_you_sure\">你確定嗎？</string>\n    <string name=\"pref_remove_all_rules\">刪除所有規則</string>\n    <string name=\"website\">網站</string>\n    <string name=\"run_in_termux\">在Termux中執行</string>\n    <string name=\"open_in_termux\">在Termux開啟</string>\n    <string name=\"export_icon\">提取圖示</string>\n    <string name=\"no_matching_package_found\">找不到任何此類別的應用程式</string>\n    <string name=\"block_unblock_trackers\">封鎖/取消封鎖追蹤器</string>\n    <string name=\"unblock\">解除封鎖</string>\n    <string name=\"block\">封鎖</string>\n    <string name=\"clear\">清除</string>\n    <string name=\"clear_data_message\">您確定要清除此應用程式中的資料嗎？</string>\n    <string name=\"skip_signature_checks\">跳過簽名檢查</string>\n    <string name=\"yes\">是</string>\n    <string name=\"no\">否</string>\n    <string name=\"apply_to_system_apps_question\">也套用於系統應用程式嗎？如果不確定，請選擇否。</string>\n    <string name=\"apply_to_system_apps\">套用於系統應用程式</string>\n    <plurals name=\"app_signing_signature_schemes_pl\">\n        <item quantity=\"other\">簽名方案</item>\n    </plurals>\n    <plurals name=\"missing_signatures\">\n        <item quantity=\"other\">%1$d 簽名缺失</item>\n    </plurals>\n    <plurals name=\"libraries\">\n        <item quantity=\"other\">%1$d 庫</item>\n    </plurals>\n    <plurals name=\"classes\">\n        <item quantity=\"other\">%1$d類</item>\n    </plurals>\n    <plurals name=\"backup_exists_are_you_sure\">\n        <item quantity=\"other\">超過一個應用程式已備份完成。是否確定？</item>\n    </plurals>\n    <string name=\"backup_options\">備份選項</string>\n    <string name=\"delete_backup\">刪除備份</string>\n    <string name=\"restore\">還原</string>\n    <string name=\"data\">資料</string>\n    <string name=\"external_data\">外部資料</string>\n    <string name=\"blocking_rules\">封鎖規則</string>\n    <string name=\"whats_new\">什麼是新的</string>\n    <string name=\"features\">特徵</string>\n    <string name=\"components\">成分</string>\n    <string name=\"trackers\">追蹤器</string>\n    <string name=\"installed_version\">安裝版本</string>\n    <string name=\"select_all\">全選</string>\n    <string name=\"filter_apps_with_rules\">有規則的應用程式</string>\n    <string name=\"filter_system_apps\">系統應用程式</string>\n    <string name=\"filter_user_apps\">使用者應用程式</string>\n    <string name=\"filter\">篩選</string>\n    <string name=\"termux\">Termux</string>\n    <plurals name=\"no_of_splits\">\n        <item quantity=\"other\">%1$d 拆分</item>\n    </plurals>\n    <string name=\"failed_to_parse_some_numbers\">無法解析一些數字</string>\n    <string name=\"only_works_in_root_or_adb_mode\">僅適用於root或ADB模式</string>\n    <string name=\"input_app_ops_description_profile\">輸入應用程式操作名稱和/或帶空格的常量，例如<tt> WAKE_LOCK 63 72相機</tt> 等使用<tt> *</tt> 套用所有已配置的應用程式操作。</string>\n    <string name=\"input_app_ops_description\">輸入應用程式操作名稱和/或帶空格的常量，例如<tt> WAKE_LOCK 63 72相機</tt> 等等。</string>\n    <string name=\"input_app_ops\">輸入應用程式操作</string>\n    <string name=\"filtered_packages\">過濾套件</string>\n    <string name=\"input_signatures_description\">輸入帶有空格的簽名，例如<tt> com.facebook org.app2 com.app3</tt> 等等。</string>\n    <string name=\"input_signatures\">輸入簽名</string>\n    <string name=\"failed_packages\">失敗的套件</string>\n    <string name=\"no_tracker_found\">找不到追蹤器</string>\n    <string name=\"clear_app_cache_description\">清除所有應用程式的快取</string>\n    <string name=\"clear_app_cache\">清除應用程式快取</string>\n    <string name=\"clear_data_from_uninstalled_apps_description\">清除透過以下方式解除安裝的應用程式中的資料<tt> DONT_DELETE_DATA</tt> 旗幟</string>\n    <string name=\"clear_data_from_uninstalled_apps\">清除已解除安裝應用程式中的資料</string>\n    <string name=\"deny_app_ops_description\">為透過常量值標識的應用程式操作設定一種模式，即<tt> 63</tt> 或者<tt> RUN_IN_BACKGROUND</tt></string>\n    <string name=\"clear_cache\">清除快取</string>\n    <string name=\"update\">更新</string>\n    <string name=\"install\">安裝</string>\n    <plurals name=\"no_of_components\">\n        <item quantity=\"other\">%1$d component</item>\n    </plurals>\n    <plurals name=\"no_of_trackers\">\n        <item quantity=\"other\">%1$d 追蹤器</item>\n    </plurals>\n    <string name=\"manifest_viewer\">清單檢視器</string>\n    <string name=\"external_apk_no_app_op\">外部 APK 沒有任何應用程式操作</string>\n    <string name=\"changelog\">變更日誌</string>\n    <string name=\"one_click_ops\">一鍵式操作</string>\n    <string name=\"never_ask\">永遠不要問</string>\n    <string name=\"failed_to_deny_dangerous_app_ops\">無法撤消所有危險的應用程式操作</string>\n    <string name=\"failed_to_deny_dangerous_perms\">無法撤消所有危險的權限</string>\n    <string name=\"failed_to_reset_app_ops\">無法重置應用程式操作</string>\n    <string name=\"failed_to_revoke_permission\">無法撤消權限</string>\n    <string name=\"failed_to_grant_permission\">無法授予權限</string>\n    <string name=\"unknown_op\">未知操作</string>\n    <string name=\"sort_by_tracker_components\">追蹤器優先</string>\n    <string name=\"deny_dangerous_permissions\">拒絕危險權限</string>\n    <string name=\"sort_by_denied_permissions\">首先被拒絕</string>\n    <string name=\"sort_by_dangerous_permissions\">危險第一</string>\n    <string name=\"sort_by_permission_names\">權限名稱</string>\n    <string name=\"sort_by_app_ops_values\">應用程式操作價值</string>\n    <string name=\"sort_by_denied_app_ops\">首先被拒絕</string>\n    <string name=\"sort_by_app_ops_names\">應用程式操作名稱</string>\n    <string name=\"deny_dangerous_app_ops\">拒絕危險的應用程式操作</string>\n    <string name=\"reset_to_default\">重置為預設</string>\n    <string name=\"block_trackers\">封鎖追蹤器</string>\n    <string name=\"sort_by_wifi_data\">Wi-Fi資料</string>\n    <string name=\"version\">版本</string>\n    <string name=\"apply\">套用</string>\n    <string name=\"select_theme\">主題</string>\n    <string name=\"night\">夜間</string>\n    <string name=\"day\">日間</string>\n    <string name=\"battery_mode\">電池模式</string>\n    <string name=\"pref_app_theme\">應用程式主題</string>\n    <string name=\"touchscreen\">觸控螢幕</string>\n    <string name=\"navigation\">導航</string>\n    <string name=\"keyboard_type\">鍵盤類型</string>\n    <string name=\"pref_export\">匯出</string>\n    <string name=\"pref_import\">匯入</string>\n    <string name=\"ago\">前</string>\n    <string name=\"reject_time\">拒絕時間</string>\n    <string name=\"accept_time\">接受時間</string>\n    <string name=\"duration\">期間</string>\n    <string name=\"running\">執行中</string>\n    <string name=\"mode\">模式</string>\n    <string name=\"permission_name\">權限名稱</string>\n    <string name=\"toggle_kill_for_system_apps\">切換殺死系統應用程式</string>\n    <string name=\"the_operation_was_successful\">完成</string>\n    <string name=\"export_blocking_rules\">匯出封鎖規則</string>\n    <string name=\"disable_background\">防止後台操作</string>\n    <string name=\"backup_restore\">備份/還原</string>\n    <string name=\"clear_data\">清除資料</string>\n    <string name=\"disable_background_run\">防止後台操作</string>\n    <string name=\"kill_process\">殺</string>\n    <string name=\"running_apps\">正在執行的應用程式</string>\n    <string name=\"apk_updater\">APK 更新器</string>\n    <string name=\"the_export_was_successful\">已匯出</string>\n    <string name=\"the_import_was_successful\">匯入完成</string>\n    <string name=\"pref_import_watt\">從 Watt 匯入</string>\n    <string name=\"sort_by_mobile_data\">移動資料</string>\n    <string name=\"sort_by_times_opened\">營業時間</string>\n    <string name=\"sort_by_screen_time\">檢測時間</string>\n    <string name=\"sort_by_last_used\">最後使用</string>\n    <plurals name=\"no_of_times_opened\">\n        <item quantity=\"other\">%1$d 次</item>\n    </plurals>\n    <string name=\"external_data_dir\">外部資料目錄</string>\n    <string name=\"sort_by_blocked_components\">先封鎖</string>\n    <string name=\"exodus_link\">εxodus鏈接</string>\n    <string name=\"usage_yesterday\">昨天</string>\n    <string name=\"patch_level\">Android 安全性更新</string>\n    <string name=\"backup_skip_signature_checks_description\">還原未透過校驗和驗證或具有與先前備份不同的 APK 簽名的備份。</string>\n    <string name=\"backup_multiple_description\">建立單獨的 <i> 命名 </i> 備份，而不是基礎備份。</string>\n    <string name=\"backup_rules_description\">備份在 App Manager 中配置的規則。</string>\n    <string name=\"backup_extras_description\">備份應用程式權限，節電和資料使用選項，MagiskHide 狀態，SSAID等。</string>\n    <string name=\"backup_extras\">附加功能</string>\n    <string name=\"backup_cache_description\">備份 <b> 快取 </b>、<b>no_cache </b> 和 <b>no_backup </b> 資料夾。</string>\n    <string name=\"backup_obb_media_description\">備份OBB和媒體資料夾。</string>\n    <string name=\"backup_external_data_description\">備份外部資料夾。</string>\n    <string name=\"backup_internal_data_description\">備份資料。如果選中，預設情況下將備份內部資料。</string>\n    <string name=\"backup_apk_files_description\">僅備份來源目錄中的 APK 檔案。<b> 來源</b> 必須選擇此項才能正常運作。</string>\n    <string name=\"set_mode_for_app_ops_dots\">設定應用程式操作的模式…</string>\n    <string name=\"security\">安全</string>\n    <string name=\"battery\">電池</string>\n    <string name=\"graphics\">圖形處理器</string>\n    <string name=\"cpu\">中央處理器</string>\n    <string name=\"users\">使用者數</string>\n    <string name=\"languages\">語言</string>\n    <string name=\"battery_capacity\">電池容量</string>\n    <string name=\"memory\">記憶體</string>\n    <string name=\"vendor\">分發</string>\n    <string name=\"gles_version\">OpenGL ES 版本</string>\n    <string name=\"no_of_cores\">核心數量</string>\n    <string name=\"support_architectures\">支援的架構</string>\n    <string name=\"security_providers\">安全提供者</string>\n    <string name=\"kernel\">核心</string>\n    <string name=\"manufacturer\">製造商</string>\n    <string name=\"board_name\">處理器代號</string>\n    <string name=\"model\">機型</string>\n    <string name=\"brand_name\">品牌</string>\n    <string name=\"pref_about_device_msg\">基本裝置資訊，包括 Android 系統，CPU，GPU，RAM，電池等。</string>\n    <string name=\"about_device\">關於裝置</string>\n    <string name=\"set_custom_app_op\">設定自訂應用程式</string>\n    <string name=\"interceptor\">攔截器</string>\n    <string name=\"resend_intent\">重新傳送意圖</string>\n    <string name=\"share\">分享</string>\n    <string name=\"extras\">附加功能</string>\n    <string name=\"category\">分類目錄</string>\n    <string name=\"uri\">位址</string>\n    <string name=\"mime_type\">MIME 類型</string>\n    <string name=\"action\">行動</string>\n    <string name=\"result_code\">結果碼</string>\n    <string name=\"activity_result\">活動結果</string>\n    <string name=\"send_edited_intent\">傳送變更後的Intent</string>\n    <string name=\"matching_activities\">配套活動</string>\n    <string name=\"value\">值</string>\n    <string name=\"filter_apps_with_splits\">拆分的</string>\n    <string name=\"set_app_op_mode\">在時尚上設定應用程式</string>\n    <string name=\"magisk_hide_enabled\">MagiskHide</string>\n    <string name=\"pref_backup_android_keystore_msg\">還原後，並非所有應用程式都能正常運作。還原 KeyStore 不適用於大多數裝置。</string>\n    <string name=\"pref_backup_android_keystore\">使用 Android KeyStore 備份應用程式</string>\n    <string name=\"keep_data_and_app_signing_signatures\">保留資料和簽名</string>\n    <string name=\"this_action_cannot_be_undone\">此操作無法撤消。</string>\n    <string name=\"no_app_ops_permission\">沒有顯示應用程式操作的權限</string>\n    <string name=\"input_keystore_pass_msg\">按一下此處輸入 KeyStore 密碼</string>\n    <string name=\"input_keystore_pass_description\">輸入App Manager KeyStore 密碼。如果您是第一次看到此密碼，請先使用密碼產生器產生密碼並將其儲存在安全的位置，然後再將其插入此處。</string>\n    <string name=\"input_keystore_pass\">輸入密鑰資源庫密碼</string>\n    <string name=\"splits\">分裂</string>\n    <string name=\"source_stamp_verified\">SourceStamp已驗證。</string>\n    <string name=\"not_verified\">未驗證</string>\n    <string name=\"verified\">已驗證</string>\n    <string name=\"pref_signature_schemes_msg\">至少應選擇v1和v2方案以取得更大的相容性。 v4方案需要v2或v3。</string>\n    <string name=\"v4_scheme\">v4方案（自 Android 11起）</string>\n    <string name=\"v3_scheme\">v3方案（自 Android 9起）</string>\n    <string name=\"v2_scheme\">v2方案（自 Android 7.0起）</string>\n    <string name=\"v1_scheme\">v1方案（自 Android 1.0起）</string>\n    <string name=\"pref_apk_signing_msg\">設定簽名方案，自訂簽名密鑰等。</string>\n    <string name=\"apk_signing\">APK 簽名</string>\n    <string name=\"app_signing_signature_schemes\">簽名方案</string>\n    <string name=\"app_settings\">設定</string>\n    <string name=\"usage_access\">使用權限</string>\n    <string name=\"str_logo\">標識</string>\n    <string name=\"rules_not_applied\">規則不適用</string>\n    <string name=\"failed_to_disable_op\">無法停用要求的應用程式操作</string>\n    <string name=\"failed_to_enable_op\">無法啟用要求的應用程式操作</string>\n    <string name=\"no_app_ops\">沒有應用程式操作</string>\n    <string name=\"app_ops\">應用程式操作</string>\n    <string name=\"app_size\">應用程式</string>\n    <string name=\"total_size\">全部</string>\n    <string name=\"storage_and_cache\">儲存空間和快取</string>\n    <string name=\"force_stop\">強制停止</string>\n    <string name=\"enable\">啟用</string>\n    <string name=\"disable\">停用</string>\n    <string name=\"stopped\">已停止</string>\n    <string name=\"uninstall_system_app_message\">這是一個系統應用程式。您確定要解除安裝此應用程式嗎？</string>\n    <string name=\"uninstall_app_message\">您要解除安裝此應用程式嗎？</string>\n    <string name=\"view_in_settings\">在設定中檢視</string>\n    <string name=\"no_content\">無內容</string>\n    <string name=\"no_usage_in_this_time_range\">在此時間範圍內無使用</string>\n    <string name=\"disabled_app\">已停用的應用程式</string>\n    <string name=\"key_name_cannot_be_null\">密鑰名稱不能為空</string>\n    <string name=\"error_evaluating_input\">無法評估輸入</string>\n    <string name=\"type_string\">人物</string>\n    <string name=\"type_long\">長整數</string>\n    <string name=\"type_int\">整數</string>\n    <string name=\"type_float\">小數</string>\n    <string name=\"type_boolean\">真假</string>\n    <string name=\"done\">完成</string>\n    <string name=\"add_item\">新增項目</string>\n    <string name=\"select_type\">選擇類型</string>\n    <string name=\"key_name\">鍵名</string>\n    <string name=\"boolean_value\">布爾值</string>\n    <string name=\"decimal_value\">十進制值</string>\n    <string name=\"integer_value\">整數值</string>\n    <string name=\"long_integer_value\">長整數值</string>\n    <string name=\"string_value\">字串值</string>\n    <string name=\"deletion_failed\">刪除失敗</string>\n    <string name=\"deleted_successfully\">已刪除</string>\n    <string name=\"delete\">刪除</string>\n    <string name=\"discard\">丟棄</string>\n    <string name=\"save\">儲存</string>\n    <string name=\"databases\">資料庫</string>\n    <string name=\"shared_prefs\">共用偏好</string>\n    <string name=\"test_only\">僅測試</string>\n    <string name=\"debuggable\">可偵錯的</string>\n    <string name=\"updated_app\">更新</string>\n    <string name=\"requested_large_heap\">大堆</string>\n    <string name=\"no_code\">沒有密碼</string>\n    <string name=\"process_name\">處理程序名稱</string>\n    <string name=\"native_library_dir\">原生 JNI 資源庫目錄</string>\n    <string name=\"dev_protected_data_dir\">裝置;保護的資料目錄</string>\n    <string name=\"search\">搜尋</string>\n    <string name=\"menu_apply_rules\">套用規則</string>\n    <string name=\"menu_remove_rules\">刪除規則</string>\n    <string name=\"failed_to_extract_apk_file\">無法提取 APK 檔案</string>\n    <string name=\"grant_usage_acess_message\">用於顯示應用使用資訊。</string>\n    <string name=\"grant_usage_access\">授予使用權限</string>\n    <string name=\"go\">前往</string>\n    <string name=\"go_back\">返回</string>\n    <string name=\"usage_less_than_a_minute\">不到一分鐘</string>\n    <plurals name=\"usage_hours\">\n        <item quantity=\"other\">%1$d hr</item>\n    </plurals>\n    <plurals name=\"usage_days\">\n        <item quantity=\"other\">%1$d day</item>\n    </plurals>\n    <plurals name=\"usage_months\">\n        <item quantity=\"other\">%1$d mo</item>\n    </plurals>\n    <string name=\"usage_7_days\">最近7天</string>\n    <string name=\"usage_today\">今天</string>\n    <string name=\"usage_weekly\">每週</string>\n    <string name=\"app_usage\">應用程式使用情況</string>\n    <string name=\"no_tracker_class\">沒有追蹤器類別</string>\n    <string name=\"no_shared_libs\">沒有共用資源庫</string>\n    <string name=\"all_classes\">所有類別</string>\n    <string name=\"tracker_classes\">追蹤器類</string>\n    <string name=\"tracker_details\">追蹤器詳細資訊</string>\n    <string name=\"found_trackers\">找到的追蹤器：</string>\n    <string name=\"toggle_class_listing\">切換類別清單</string>\n    <string name=\"class_viewer\">類檢視器</string>\n    <string name=\"word_wrap\">切換自動換行</string>\n    <string name=\"credits_message\">向以下開放原始碼專案的協作者致謝\n\\n- The Android Open Source Project\n\\n- <a href=\"https://github.com/butzist/ActivityLauncher\">Activity Launcher</a>\n\\n- <a href=\"https://bitbucket.org/oF2pks/fdroid-applications-info\">Apps_packages Info</a>\n\\n- <a href=\"https://github.com/zhaobao/AppsMonitor\">AppsMonitor</a>\n\\n- <a href=\"https://github.com/8enet/AppOpsX\">AppOpsX</a>\n\\n- <a href=\"https://github.com/billthefarmer/editor\">Editor</a>\n\\n- <a href=\"https://github.com/k3b/intent-intercept\">Intent Intercept</a>\n\\n- <a href=\"https://github.com/zhanghai/MaterialFiles\">Material Files</a>\n\\n- <a href=\"https://github.com/pluscubed/matlog\">MatLog</a>\n\\n- <a href=\"https://github.com/matrix-org/matrix-android-sdk\">Matrix Android SDK</a>\n\\n- <a href=\"https://github.com/jensstein/oandbackup\">OAndBackup</a>\n\\n- <a href=\"https://github.com/open-keychain/open-keychain\">Open Keychain</a>\n\\n- <a href=\"https://github.com/Aefyr/SAI\">SAI</a>\n\\n- <a href=\"https://github.com/RikkaApps/Shizuku\">Shizuku</a>\n\\n- <a href=\"https://github.com/tuyafeng/Watt\">Watt</a>\n\\n原創 logo 致謝: <a href=\"https://github.com/Atrate\">Atrate</a>. </string>\n    <string name=\"credits\">致謝</string>\n    <string name=\"third_party\">第三方資源庫和圖示</string>\n    <string name=\"license\">授權條款</string>\n    <string name=\"icon_picker\">圖示選擇器</string>\n    <string name=\"class_name\">類別名稱</string>\n    <string name=\"package_name\">套件名稱</string>\n    <string name=\"shortcut_name\">捷徑名稱</string>\n    <string name=\"create_shortcut\">建立捷徑</string>\n    <string name=\"error_verbose_pin_shortcut\">目前啟動器不支援PinShortcut。無法建立捷徑。</string>\n    <string name=\"error_creating_shortcut\">建立捷徑時發生錯誤</string>\n    <string name=\"empty_package_name\">空 套件名稱為空</string>\n    <string name=\"main_activity\">主要活動</string>\n    <string name=\"user_id\">使用者身份</string>\n    <string name=\"more_info\">更多資訊</string>\n    <string name=\"sdk_flags\">旗標</string>\n    <string name=\"sdk_max\">目標</string>\n    <string name=\"sdk_min\">最低</string>\n    <string name=\"data_dir\">資料目錄</string>\n    <string name=\"source_dir\">來源目錄</string>\n    <string name=\"paths_and_directories\">路徑</string>\n    <string name=\"user\">使用者</string>\n    <string name=\"app_not_installed\">應用程式未安裝</string>\n    <string name=\"media_size\">媒體</string>\n    <string name=\"obb_size\">Obb</string>\n    <string name=\"cache_size\">快取</string>\n    <string name=\"data_size\">資料大小</string>\n    <string name=\"about\">關於</string>\n    <string name=\"data_usage_msg\">資料使用情況</string>\n    <string name=\"data_transmitted\">已傳送的資料</string>\n    <string name=\"data_received\">已接收的資料</string>\n    <string name=\"sort_by_target_sdk\">目標 SDK</string>\n    <string name=\"sort_by_domain\">使用者應用程式優先</string>\n    <string name=\"sort_by_package_name\">套件名稱</string>\n    <string name=\"sort_by_app_label\">應用程式標籤</string>\n    <string name=\"manifest\">清單</string>\n    <string name=\"input_features\">輸入功能</string>\n    <string name=\"no_configurations\">沒有配置</string>\n    <string name=\"configurations\">構型</string>\n    <string name=\"app_signing_no_signatures\">沒有有效的簽名</string>\n    <string name=\"signatures\">簽名</string>\n    <string name=\"sort_by_sha\">簽名</string>\n    <string name=\"shared_user_id\">共用的使用者ID</string>\n    <string name=\"sort_by_shared_user_id\">共用的使用者ID</string>\n    <string name=\"no_feature\">沒有功能</string>\n    <string name=\"uses_feature\">使用功能</string>\n    <string name=\"group\">群組</string>\n    <string name=\"shared_libs\">共用資源庫</string>\n    <string name=\"declared_permission\">權限</string>\n    <string name=\"patterns_allowed\">允許的圖案</string>\n    <string name=\"write\">寫入</string>\n    <string name=\"read\">讀取</string>\n    <string name=\"path_permissions\">路徑權限</string>\n    <string name=\"grant_uri_permission\">授予URI權限</string>\n    <string name=\"soft_input\">軟輸入模式</string>\n    <string name=\"orientation\">螢幕旋轉</string>\n    <string name=\"no_service\">沒有服務</string>\n    <string name=\"service\">服務</string>\n    <string name=\"authority\">權威</string>\n    <string name=\"no_providers\">無提供者</string>\n    <string name=\"providers\">提供者</string>\n    <string name=\"no_receivers\">無接收器</string>\n    <string name=\"receivers\">接收器</string>\n    <string name=\"no_activities\">無活動</string>\n    <string name=\"refresh\">重新整理</string>\n    <string name=\"activities\">活動</string>\n    <string name=\"require_no_permission\">無權限需要</string>\n    <string name=\"pref_log_viewer_msg\">配置日誌顯示方式。</string>\n    <string name=\"log_viewer\">日誌檢視器</string>\n    <string name=\"pref_installer_msg\">配置應用安裝程式的行為。</string>\n    <string name=\"expiry_date_cannot_be_empty\">到期日期不能是空的。</string>\n    <string name=\"signing_key\">簽署金鑰</string>\n    <string name=\"failed_to_read_keystore\">無法讀取KeyStore。</string>\n    <string name=\"alias_pass\">別名密碼</string>\n    <string name=\"choose_an_alias\">選擇別名</string>\n    <string name=\"found_no_alias_in_keystore\">在KeyStore中找不到別名！</string>\n    <string name=\"new_alias_password\">新別名密碼</string>\n    <string name=\"import_key\">匯入金鑰</string>\n    <string name=\"pem_file\">PEM 檔</string>\n    <string name=\"pk8_file\">PKCS #8 （PK8） 檔</string>\n    <string name=\"keystore_pass\">鑰匙商店密碼</string>\n    <string name=\"keystore_file\">KeyStore檔案</string>\n    <string name=\"country_name\" tools:ignore=\"TypographyOther\">國家/地區名稱 （C）</string>\n    <string name=\"state_name\">州名（ST）</string>\n    <string name=\"locality_name\">地方（城市）名稱（L）</string>\n    <string name=\"organization_name\">組織名稱 （O）</string>\n    <string name=\"organization_unit\">組織單位（OU）</string>\n    <string name=\"common_name\">通用名稱（CN）</string>\n    <string name=\"input_key_password\">金鑰密碼</string>\n    <string name=\"failed_to_load_key\">無法載入金鑰。</string>\n    <string name=\"key_not_set\">未設定。</string>\n    <string name=\"use_default\">使用預設值</string>\n    <string name=\"invalid_rsa_key_size\">RSA 加密的密鑰大小無效。密鑰大小可以是1024、2048 或 4096 位元。</string>\n    <string name=\"crypto_key_size\">金鑰大小</string>\n    <string name=\"invalid_aes_key_size\">AES 加密的金鑰大小無效。金鑰大小可以是 128 位元或 256 位元。</string>\n    <string name=\"failed_to_initialize_key_store\">無法初始化App Manager密鑰庫。</string>\n    <string name=\"failed_to_save_key\">無法儲存金鑰。</string>\n    <string name=\"generate_key\">產生</string>\n    <string name=\"input_key\">輸入鍵（十六進制）</string>\n    <string name=\"input_keystore_alias_pass_msg\">按一下此處為%1$s 提供密碼</string>\n    <string name=\"internal_data\">內部資料</string>\n    <string name=\"app_signing_signatures\">簽名</string>\n    <string name=\"unable_to_save_log\">無法儲存日誌。您是否輸入了有效的檔案名稱？</string>\n    <string name=\"enter_good_filename\">請輸入有效的檔案名稱。</string>\n    <string name=\"restart_log_viewer_to_see_changes\">重新啟動日誌檢視器視窗以檢視變更。</string>\n    <string name=\"view_logs\">檢視日誌</string>\n    <string name=\"save_log\">儲存日誌</string>\n    <string name=\"pref_default_log_level_summary\">啟動時的日誌等級、開啟檔案時以及錄製時。</string>\n    <string name=\"log_level\">日誌等級</string>\n    <string name=\"failed_to_block_trackers\">無法封鎖追蹤器</string>\n    <string name=\"pref_rules_msg\">即時封鎖、匯入/匯出/刪除規則等。</string>\n    <string name=\"failed\">錯誤</string>\n    <string name=\"confirm_import_keystore\">您確定要取代現有的 KeyStore 嗎？此操作無法復原。</string>\n    <string name=\"import_keystore\">匯入 KeyStore</string>\n    <string name=\"pref_import_export_keystore_msg\">匯入/匯出 App Manager 內部使用的 Bouncy Castle KeyStore（BKS）。</string>\n    <string name=\"pref_import_export_keystore\">匯入/匯出 KeyStore</string>\n    <string name=\"latest_backup\">最新備份</string>\n    <string name=\"gz_bz2_compressed\">%1$s已壓縮</string>\n    <string name=\"pgp_aes_rsa_encrypted\">%1$s 加密</string>\n    <string name=\"no_encryption\">沒有加密</string>\n    <string name=\"base_backup\">基礎備份</string>\n    <string name=\"trackers_unblocked_successfully\">追蹤器現已解除封鎖</string>\n    <string name=\"trackers_blocked_successfully\">已封鎖追蹤器</string>\n    <string name=\"failed_to_unblock_trackers\">無法解除封鎖追蹤器</string>\n    <string name=\"profile_save_apk_msg\">將 APK 檔案儲存在<tt> AppManager/apks </tt>中</string>\n    <string name=\"save_apk\">儲存 APK</string>\n    <string name=\"running_services\">執行中的服務</string>\n    <string name=\"share_log\">分享</string>\n    <string name=\"text_include_dmesg\">包括核心日誌</string>\n    <string name=\"omit_sensitive_info_summary\">省略敏感資訊，如網址、電話號碼或電子郵件。</string>\n    <string name=\"omit_sensitive_info\">省略敏感資訊</string>\n    <string name=\"undo\">復原</string>\n    <string name=\"pause_unpause\">播放/暫停</string>\n    <string name=\"collapse_all\">全部摺疊</string>\n    <string name=\"expand_all\">全部展开</string>\n    <string name=\"file\">檔案</string>\n    <string name=\"widget_start_recording\">記錄\n\\n日誌</string>\n    <string name=\"widget_recording_in_progress\">記錄…</string>\n    <plurals name=\"toast_log_truncated\">\n        <item quantity=\"other\">日誌太大，顯示最後 %d 行。</item>\n    </plurals>\n    <string name=\"toast_invalid_selection\">選擇無效。請再試一次。</string>\n    <string name=\"toast_invalid_level\">無效等級名稱：%s</string>\n    <string name=\"pref_display_limit_hint\">請輸入一個介於%1$d和%2$d之間的有效數字。</string>\n    <string name=\"text_include_device_info\">包括裝置資訊</string>\n    <string name=\"text_filter_text\">過濾文字</string>\n    <string name=\"text_filter_ellipsis\">篩選…</string>\n    <string name=\"subject_log_report\">日誌報告</string>\n    <string name=\"start_recording_log\">記錄</string>\n    <string name=\"settings\">設定</string>\n    <string name=\"send_log_title\">傳送日誌</string>\n    <string name=\"save_as\">另存為…</string>\n    <string name=\"record_log\">記錄日誌</string>\n    <string name=\"pref_show_timestamp_title\">顯示 PID 與時間戳</string>\n    <string name=\"pref_show_timestamp_summary\">展開時顯示處理程序 ID 和時間戳。</string>\n    <string name=\"pref_log_write_period_title\">寫入期間</string>\n    <string name=\"pref_log_write_period_summary\">記錄時，每 %1$d 行寫入 SD 卡。</string>\n    <string name=\"pref_log_line_period_error\">請輸入1到1000之間的整數。</string>\n    <string name=\"pref_expanded_by_default_title\">預設為展開</string>\n    <string name=\"pref_expanded_by_default_summary\">預設情況下顯示完整的日誌。</string>\n    <string name=\"pref_filter_pattern_title\">過濾掉標籤</string>\n    <string name=\"pref_filter_pattern_summary\">從日誌中篩選出選定的標籤。</string>\n    <string name=\"pref_display_limit_title\">日誌顯示限制</string>\n    <string name=\"pref_display_limit_summary\">僅顯示最後 %1$d 日誌，以避免出現記憶體錯誤。</string>\n    <string name=\"pref_default_log_level_title\">預設日誌等級</string>\n    <string name=\"pref_cat_configuration\">配置</string>\n    <string name=\"pref_cat_appearance\">外觀</string>\n    <string name=\"pref_cat_advanced\">進階</string>\n    <string name=\"pref_buffer_title\">日誌緩衝區</string>\n    <string name=\"open\">開啟</string>\n    <string name=\"notification_title\">正在記錄日誌</string>\n    <string name=\"notification_ticker\">日誌錄製開始</string>\n    <string name=\"notification_subtext\">按一下即可停止錄製</string>\n    <string name=\"no_saved_logs\">找不到已儲存的記錄。</string>\n    <string name=\"manage_saved_logs\">管理已儲存的日誌</string>\n    <string name=\"log_saved\">已儲存日誌。</string>\n    <string name=\"log_recording_started\">日誌錄製已開始。</string>\n    <string name=\"log_cleared\">日誌已清除</string>\n    <string name=\"filter_choice_tag\">標籤</string>\n    <string name=\"filter_choice\">搜尋依據</string>\n    <string name=\"enter_filename\">輸入檔案名稱</string>\n    <string name=\"dialog_compiling_log\">正在編譯日誌…</string>\n    <string name=\"delete_saved_log\">刪除已儲存的日誌</string>\n    <string name=\"copy_to_clipboard\">複製到剪貼簿</string>\n    <string name=\"add_filter_ellipsis\">新增過濾器…</string>\n    <string name=\"add_filter\">新增過濾器</string>\n    <string name=\"log_level_fatal\">重大</string>\n    <string name=\"log_level_warn\">警告</string>\n    <string name=\"log_level_verbose\">詳細</string>\n    <string name=\"log_level_info\">資訊</string>\n    <string name=\"log_level_error\">錯誤</string>\n    <string name=\"log_level_debug\">偵錯</string>\n    <string name=\"filename\">檔案名稱</string>\n    <string name=\"orientation_right_to_left\">由右至左</string>\n    <string name=\"orientation_left_to_right\">由左至右</string>\n    <string name=\"orientation_follow_locale\">按照語言環境</string>\n    <plurals name=\"file_deletion_confirmation\">\n        <item quantity=\"other\">%d 檔案將被刪除</item>\n    </plurals>\n    <string name=\"no_changes\">沒有變更</string>\n    <string name=\"pref_display_changes_msg\">以版本控制的方式顯示版本，追蹤器，元件，權限，簽名，SDK 等的變更。</string>\n    <string name=\"pref_display_changes\">顯示變更</string>\n    <string name=\"hidden\">已隱藏</string>\n    <string name=\"suspended\">已待命</string>\n    <string name=\"netpolicy_reject_wifi_data\">拒絕 Wi-Fi 資料</string>\n    <string name=\"netpolicy_reject_vpn_data\">拒絕 VPN 資料</string>\n    <string name=\"netpolicy_allow_background_data\">開啟Data Saver時允許背景資料</string>\n    <string name=\"netpolicy_reject_background_data\">拒絕背景資料</string>\n    <string name=\"netpolicy_disable_network_access\">停用網路存取</string>\n    <string name=\"netpolicy_reject_cellular_data\">拒絕行動網路</string>\n    <string name=\"unknown_net_policy\">未知的網路政策 （%1$s - %2$X）</string>\n    <string name=\"port_number_invalid\">無效埠編號。</string>\n    <string name=\"port_number_empty\">埠編號為空。</string>\n    <string name=\"adb_connect_port_number_description\">埠編號位於 <b> IP 位址 &amp; 連接埠 </b> 部分下方 <b> 裝置名稱 </b> 部分正下方。</string>\n    <string name=\"port_number\">連接埠</string>\n    <string name=\"adb_connect\">連線</string>\n    <string name=\"wireless_debugging\">無線偵錯</string>\n    <string name=\"community\">社群</string>\n    <string name=\"failed_to_prevent_background_run\">無法防止 %1$s 在背景執行</string>\n    <plurals name=\"alert_failed_to_import_backups\">\n        <item quantity=\"other\">無法匯入 %1$d 備份</item>\n    </plurals>\n    <string name=\"import_from_tb\">從鈦備份匯入</string>\n    <string name=\"import_from_oab\">從 OAndBackup 匯入</string>\n    <string name=\"pref_import_backups_msg\">從 OAndBackup、Swift Backup (3.0–3.2) 或 Titanium Backup 匯入備份。</string>\n    <string name=\"pref_import_backups\">匯入備份</string>\n    <string name=\"help_app_ops_tab\">單擊項目以 <b> 允許 </b> 或 <b> 忽略 </b>。長按一個項目以檢視其他支援的模式。</string>\n    <string name=\"help_permissions_tab\">這些權限由該應用程式定義且無法撤銷。</string>\n    <string name=\"help_uses_permissions_tab\">點擊一個項目來<b>授予</b>或<b>撤銷</b>它。只有 <b>dangerous</b> 和 <b>development</b> 權限可以被授予或撤銷。</string>\n    <string name=\"minimum_version\">最低版本： %d</string>\n    <string name=\"added_to_queue\">新增到佇列中</string>\n    <string name=\"pref_selected_users\">選定的使用者</string>\n    <string name=\"pref_selected_users_msg\">限制 App Manager 僅與選定的使用者一同運作。</string>\n    <string name=\"permission_flags\">權限標誌</string>\n    <string name=\"saved_filters\">已儲存的過濾器</string>\n    <string name=\"error_with_details\">錯誤: %s</string>\n    <string name=\"notice\">通知</string>\n    <string name=\"notice_saf\">與卷不同，所選目錄將用於儲存與 App Manager相關的所有檔案，包括已儲存的 APK 和備份。儲存空間存取框架 （SAF） 非常緩慢，因此，您只能在無法使用其他選項時使用此選項。</string>\n    <string name=\"storage\">儲存空間</string>\n    <string name=\"files\">檔案</string>\n    <string name=\"keystore_password_info\">以下是 App Manager KeyStore 密碼。如果您要備份/還原 App Manager KeyStore，請將其存放在安全的地方。 <b>此訊息將不再顯示。</b></string>\n    <string name=\"keystore_pass_cannot_be_empty\">KeyStore 密碼不能為空。</string>\n    <string name=\"invalid_password\">密碼無效，請再試一次。</string>\n    <string name=\"adb_pair\">配對</string>\n    <string name=\"paired_successfully\">已配對。</string>\n    <string name=\"pem_and_pk8\">PEM 與 PKCS #8 (PK8)</string>\n    <string name=\"pref_block_trackers_msg\">使用App Manager安裝應用後封鎖跟蹤元件。</string>\n    <string name=\"running_services_logcat_hint\">按兩下項目以相應的流程ID作為預設篩選器開啟日誌檢視器。</string>\n    <string name=\"pid\">處理程序 ID</string>\n    <plurals name=\"pref_thread_count_msg\">\n        <item quantity=\"other\">最多同時執行 %1$d 操作</item>\n    </plurals>\n    <string name=\"pref_thread_count_hint\">值必須在 0 到 %1$d 之間，其中 0 表示給定時間 <i> 最大操作次數 </i>。</string>\n    <string name=\"pref_thread_count\">並列執行</string>\n    <string name=\"type_uri_array\">URI 數組</string>\n    <string name=\"pref_always_on_background_msg\">始終在後台安裝應用程式並在完成時顯示通知。</string>\n    <string name=\"pref_always_on_background\">在後台安裝</string>\n    <string name=\"next\">下頁</string>\n    <string name=\"installer_app_installed\">應用程式已安裝</string>\n    <string name=\"staging_apk_files\">儲存中…</string>\n    <string name=\"background\">背景</string>\n    <string name=\"trim_caches_in_all_apps_description\">從所有應用程式中刪除快取檔案，包括 android 系統</string>\n    <string name=\"trim_caches_in_all_apps\">修剪所有應用程式中的快取</string>\n    <string name=\"user_root\">使用 Root</string>\n    <string name=\"paste\">貼上</string>\n    <string name=\"set_package_name_first\">先設定套件名稱！</string>\n    <string name=\"identifier\">識別碼</string>\n    <string name=\"backup_volume_dialog_description\">帶有 <tt>/tree</tt> 前綴的卷宗是使用儲存存取框架 (SAF) 選擇的資料夾。除了這些資料夾，App Manager 的預設目錄是一個名為 <tt>AppManager</tt> 的子資料夾。</string>\n    <string name=\"second_degree_tracker_note\">² 前綴表示追蹤器在 <a href=\"https://etip.exodus-privacy.eu.org/\">ETIP 備用清單 </a> 中，即它們是否實際爲追蹤器仍在調查中。</string>\n    <string name=\"failed_to_uninstall_app\">解除安裝失敗</string>\n    <string name=\"saf\">SAF</string>\n    <string name=\"type_uri_array_list\">URI 列表</string>\n    <string name=\"filter_choice_pid\">PID</string>\n    <string name=\"pkcs12_keystore\">PKCS #12 密鑰庫 (P12)</string>\n    <string name=\"bouncy_castle_keystore\">Bouncy Castle 密鑰庫 (BKS)</string>\n    <string name=\"java_keystore\">Java 密鑰庫 (JKS)</string>\n    <string name=\"community_links\">Telegram: https://t.me/AppManagerChannel\n\\nTwitter: https://twitter.com/AppManagerNews</string>\n    <string name=\"source_code_links\">GitHub: https://github.com/MuntashirAkon/AppManager\n\\nGitLab: https://gitlab.com/muntashir/AppManager\n\\nRiseup: https://0xacab.org/muntashir/AppManager\n\\nCodeberg: https://codeberg.org/muntashir/AppManager</string>\n    <string name=\"accessibility_service_description\">通用無障礙服務，用於執行某些操作，例如在非 root 模式下清除緩存。</string>\n    <string name=\"exit_confirmation\">確認離開</string>\n    <string name=\"extract\">提取</string>\n    <string name=\"replace\">取代</string>\n    <string name=\"explore\">瀏覽</string>\n    <string name=\"import_from_sb\">從 Swift Backup 3.0 – 3.2 匯入</string>\n    <string name=\"pref_import_backups_hint\">選擇包含備份檔案的目錄 (Swift Backup/Titanium Backup) 或目錄 (OAndBackup)</string>\n    <string name=\"rename\">重新命名</string>\n    <string name=\"intent_firewall_and_disable\">IFW + 停用</string>\n    <string name=\"search_type_contains\">包含</string>\n    <string name=\"search_type_prefix\">前綴</string>\n    <string name=\"search_type_suffix\">後綴</string>\n    <string name=\"failed_to_enable_magisk_deny_list\">無法啟用 Magisk DenyList</string>\n    <string name=\"failed_to_use_the_current_mode_of_operation\">無法使用目前的操作模式。此工作階段回退到無 Root 模式。</string>\n    <string name=\"failed_to_change_app_op_mode\">無法變更應用程式操作模式。</string>\n    <string name=\"hidden_api_enf_policy_black\">嚴格（僅限黑名單）</string>\n    <plurals name=\"usage_minutes\">\n        <item quantity=\"other\">%1$d 分鐘</item>\n    </plurals>\n    <string name=\"toggle_internet\">使用網際網路</string>\n    <plurals name=\"usage_seconds\">\n        <item quantity=\"other\">%1$d 秒</item>\n    </plurals>\n    <string name=\"vt_uploading\">VirusTotal：正在上傳…</string>\n    <string name=\"vt_queued\">VirusTotal: 佇列</string>\n    <string name=\"process_id\">處理程序 ID</string>\n    <string name=\"pref_default_blocking_method\">預設封鎖模式</string>\n    <string name=\"pref_default_blocking_method_description\">在沒有選項選擇封鎖方法的地方預設使用的方法。</string>\n    <string name=\"pref_intent_firewall_and_disable_description\">使用 Intent Firewall 封鎖元件並停用它們。給 root 用戶的的建議方式。</string>\n    <string name=\"pref_intent_firewall_description\">僅使用 Intent Firewall 封鎖元件。不建議使用，因為某些系統應用程式可以繞過防火牆。</string>\n    <string name=\"authenticating\">正在認證…</string>\n    <string name=\"search_type_regular_expressions\">正則表達式</string>\n    <string name=\"vt_checking\">VirusTotal：正在檢查…</string>\n    <string name=\"vt_slowness_warning\">根據網際網路的速度和伺服器上的負載，這可能需要一段時間。</string>\n    <string name=\"commandline_args\">命令行參數</string>\n    <string name=\"vt_failed\">VirusTotal: 失敗</string>\n    <string name=\"vt_permalink\">VirusTotal 的永久連結</string>\n    <string name=\"pref_vt_apikey\">VirusTotal API 金鑰</string>\n    <string name=\"uses_play_app_signing\">Play 應用簽名</string>\n    <string name=\"pref_vt_apikey_description\">API 金鑰使 App Manager 能夠將 APK 檔案上傳到 VirusTotal 以及取得報告。在 https://virustotal.com 註冊，即可免費取得 API 金鑰。</string>\n    <string name=\"virtual_memory\">虛擬記憶體</string>\n    <string name=\"scan_in_vt\">在 VirusTotal 中掃描</string>\n    <string name=\"parent_process_id\">父進程 ID</string>\n    <string name=\"priority\">優先權</string>\n    <string name=\"threads\">線程數</string>\n    <string name=\"memory_chart_info\">● %1$s 應用程式 ● %2$s 快取 ● %3$s 緩衝區 ● %4$s 可用</string>\n    <string name=\"state\">進程狀態</string>\n    <string name=\"hidden_api_enforcement_policy\">隱藏的 API 執行策略</string>\n    <string name=\"hidden_api_enf_policy_none\">無（對隱藏 API 的完全存取權限 ）</string>\n    <string name=\"hidden_api_enf_policy_warn\">警告（完全存取隱藏的 API，但發出警告）</string>\n    <string name=\"hidden_api_enf_policy_dark_grey_and_black\">嚴格（深灰色和黑名單）</string>\n    <string name=\"swap_chart_info\">● %1$s 已使用 ● %2$s 可用</string>\n    <string name=\"warning_working_on_root_mode\">警告：在 root 而不是 ADB 模式下運作。</string>\n    <string name=\"zygote_preload_name\">Zygote 預先載入名稱</string>\n    <string name=\"hidden_api_enf_default_policy\">預設值（基於應用程式類型）</string>\n    <string name=\"binary_32_bit\">32 位元</string>\n    <string name=\"binary_64_bit\">64 位元</string>\n    <string name=\"so_type_shared_library\">共用資源庫</string>\n    <string name=\"failed_to_disable_magisk_deny_list\">無法停用 Magisk DenyList</string>\n    <string name=\"so_type_executable\">可執行檔案</string>\n    <string name=\"pref_disable_description\">僅停用元件。不建議root使用者使用，因為應用程式可以繞過此操作。在ADB模式下，可以使用此方法停用僅限測試的應用程式。</string>\n    <string name=\"file_modified_are_you_sure\">檔案已修改。捨棄所有變更並離開？</string>\n    <string name=\"pref_vt_apikey_summary\">啟用透過 VirusTotal 掃描 APK 檔案。</string>\n    <string name=\"uses_play_app_signing_description\">此應用程式包含某些標記，指示它 <i> 可能 </i> 正在使用 <a href=\"https://support.google.com/googleplay/android-developer/answer/9842756\"> Play 應用程式簽名 </a>。透過此方案，簽名金鑰儲存在Google的伺服器中，Google負責對應用程式進行簽名。請注意，相符的簽名資訊是驗證應用是否未被開發人員以外的任何人（在本例中為Google）修改的唯一方法。</string>\n    <string name=\"vt_disclaimer\">VirusTotal 及其標誌是 Chronicle LLC 的商標。 App Manager（API 客戶端）及其作者均不對您可能傳送給 VirusTotal 的任何資料負責。</string>\n    <string name=\"vt_scan_date\">掃描日期：%1$s</string>\n    <string name=\"primary_abi\">主要 ABI</string>\n    <string name=\"save_and_exit\">儲存並離開</string>\n    <string name=\"mode_of_op_with_inferred_mode_of_op\">%1$s（推斷模式：%2$s）</string>\n    <string name=\"intent_firewall\">IFW</string>\n    <string name=\"magisk_denylist\">Magisk黑名單</string>\n    <string name=\"java\">Java</string>\n    <string name=\"smali\">Smali</string>\n    <string name=\"vt_success\">病毒總共: %1$d/%2$d</string>\n    <string name=\"cpu_percent\">%% CPU</string>\n    <string name=\"swap\">SWAP</string>\n    <string name=\"cpu_time\">CPU時間</string>\n    <string name=\"pref_saved_apk_name_format\">儲存的 APK 名稱格式</string>\n    <string name=\"pref_saved_apk_name_format_msg\">儲存 APK 檔案時用於命名這些檔案的格式。</string>\n    <string name=\"auth_manager_description\">要從外部應用程式啟動 Intent，需要提供一個名為 <tt>auth</tt> 的額外字段，且必須包含以下鍵：</string>\n    <string name=\"auth_manager_title\">授權管理</string>\n    <string name=\"regenerate_auth_key\">重新產生授權密鑰</string>\n    <string name=\"regenerate_auth_key_warning\">您確定嗎？所有第三方應用必須使用新的授權密鑰。</string>\n    <string name=\"shortcut_icon\">快捷圖示</string>\n    <string name=\"system_partition\">Android root</string>\n    <string name=\"sort_by_installation_date\">安裝日期</string>\n    <string name=\"backup_volume_unavailable_warning\">選擇的備份卷目前無法使用。如果它位於外部儲存中，請插入它，或變更備份卷。</string>\n    <string name=\"change_backup_volume\">變更卷</string>\n    <string name=\"external\">外部</string>\n    <string name=\"internal\">内部</string>\n    <string name=\"tracker\">追蹤器</string>\n    <string name=\"input_ssaid_instruction\">SSAID 是一個 %1$d 位元組十六進位數值，即長度為 %2$d 的字串，其中包含 0 到 9 和 a 到 f。</string>\n    <string name=\"screen_time\">螢幕使用時間</string>\n    <string name=\"open_in_new_window\">新視窗</string>\n    <string name=\"type_string_set\">字串集</string>\n    <string name=\"pref_vt_prompt_before_uploading\">上傳檔案前顯示提示。</string>\n    <string name=\"vt_confirm_uploading_file\">在 VirusTotal 資料庫中找不到該檔案。是否要上傳？</string>\n    <string name=\"vt_confirm_upload_and_scan\">是，上傳並掃描</string>\n    <string name=\"endianness_little_endian\">位元組由小到大</string>\n    <string name=\"endianness_big_endian\">位元組由大到小</string>\n    <string name=\"frozen\">已凍結</string>\n    <string name=\"freeze\">凍結</string>\n    <string name=\"unfreeze\">解凍</string>\n    <string name=\"backup_no_backups_present\">沒有備份。</string>\n    <string name=\"backup_apps_cannot_be_restored\">無法還原以下應用，因為它們沒有基本備份：</string>\n    <string name=\"backup_apps_cannot_be_backed_up\">以下應用程式未安裝且無法備份：</string>\n    <string name=\"restart_device\">重新啟動裝置</string>\n    <string name=\"import_backups_warning_delete_backups_after_import\">將備份匯入應用程式管理員后將其刪除？每個備份在匯入成功後都會單獨刪除。如果不確定，請選擇<b>否</b>。</string>\n    <string name=\"usage_times_opened\">開啟次數</string>\n    <string name=\"usage_last_used\">上次使用時間</string>\n    <string name=\"usage_mobile_data\">行動數據</string>\n    <string name=\"usage_wifi_data\">Wi-Fi 數據</string>\n    <string name=\"troubleshooting\">疑難排解</string>\n    <string name=\"pref_reload_apps\">重新載入應用程式</string>\n    <string name=\"pref_reload_apps_msg\">重新載入儲存在 App Manager 資料庫中的應用程式清單，以防出現意外行為。</string>\n    <string name=\"changelog_type_new\">新增功能</string>\n    <string name=\"changelog_type_fix\">修正</string>\n    <string name=\"changelog_type_improve\">改進</string>\n    <string name=\"restore_dots\">還原…</string>\n    <string name=\"unsupported_split_apk\">不支援</string>\n    <string name=\"pref_pure_black_theme_msg\">啟用夜間模式時使用全黑背景。</string>\n    <string name=\"netpolicy_cannot_be_modified_for_core_apps\">無法針對 Android 核心應用程式變更網路策略。</string>\n    <string name=\"pref_pure_black_theme\">純黑色主題</string>\n    <string name=\"open_developer_options_page\">在 Android 設定中開啟開發人員選項頁面</string>\n    <string name=\"log_stop_recording\">停止錄製</string>\n    <string name=\"apk_checksums\">APK 校驗和</string>\n    <string name=\"item_select\">選擇</string>\n    <string name=\"view_changelog\">瞭解此版本的新增功能</string>\n    <string name=\"app_explorer\">應用程式瀏覽器</string>\n    <string name=\"sort_by_total_size\">大小總計</string>\n    <string name=\"am_command\"><tt>am</tt> 命令</string>\n    <string name=\"pref_sign_apk_error_signing_key_not_added\">簽署 APK 檔案需要一個有效的簽署金鑰。</string>\n    <string name=\"pref_sign_apk_no_signing_key\">沒有簽署金鑰</string>\n    <string name=\"freeze_unfreeze\">凍結/解凍</string>\n    <string name=\"profile_freeze_msg\">基於狀態凍結或解凍應用程式</string>\n    <string name=\"hide_app\">隱藏</string>\n    <string name=\"failed_to_freeze\">無法凍結 <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g>.</string>\n    <string name=\"failed_to_unfreeze\">無法解凍 <xliff:g id=\"app_name\" example=\"App Manager\">%1$s</xliff:g>.</string>\n    <string name=\"pref_default_freezing_method\">預設凍結方法</string>\n    <plurals name=\"alert_failed_to_unfreeze\">\n        <item quantity=\"other\">無法解凍 %1$d 個應用程式</item>\n    </plurals>\n    <string name=\"fm_open_with_for_this_file_only\">僅對此檔案</string>\n    <string name=\"file_creation_date\">建立日期</string>\n    <string name=\"file_modification_date\">修改日期</string>\n    <string name=\"file_accessed_date\">存取日期</string>\n    <string name=\"file_open_with\">開啟方式</string>\n    <string name=\"file_change_open_with\">變更開啟方式</string>\n    <string name=\"fm_always_open_with\">一律開啟</string>\n    <string name=\"file_open_as\">開啟為…</string>\n    <string name=\"file_open_with_custom_activity\">自訂</string>\n    <string name=\"file_properties\">內容</string>\n    <string name=\"file_cut\">剪下</string>\n    <string name=\"open_as_archive\">壓縮檔</string>\n    <string name=\"open_as_text\">文字</string>\n    <string name=\"open_as_folder\">資料夾</string>\n    <string name=\"file_open_with_os_default_dialog\">使用作業系統預設對話方塊開啟</string>\n    <string name=\"open_as_image\">圖片</string>\n    <string name=\"open_as_video\">影片</string>\n    <string name=\"open_as_other\">其他</string>\n    <string name=\"delete_filename\">刪除 %s</string>\n    <string name=\"on_unfreeze_open_application\">解凍後開啟應用程式</string>\n    <string name=\"action_stop_service\">停止</string>\n    <plurals name=\"alert_failed_to_freeze\">\n        <item quantity=\"other\">無法凍結 %1$d 個應用程式</item>\n    </plurals>\n    <string name=\"pref_privacy\">隱私權</string>\n    <string name=\"pref_privacy_description\">螢幕鎖定、授權等。</string>\n    <string name=\"user_manual\">使用者手冊</string>\n    <string name=\"get_help\">取得說明</string>\n    <string name=\"pref_version_changelog\">版本/變更記錄</string>\n    <string name=\"file_shortcut_target_file\">目標檔案</string>\n    <string name=\"confirm_file_deletion\">確定，刪除</string>\n    <string name=\"tap_to_freeze_app\">輕觸以凍結</string>\n    <string name=\"app_manager_build_expired\">需要更新</string>\n    <string name=\"renamed_successfully\">已重新命名</string>\n    <string name=\"selinux_context\"/>\n    <string name=\"unix_file_permissions\">模式</string>\n    <string name=\"sort_by_file_size\">檔案大小</string>\n    <string name=\"sort_by_file_type\">檔案類型</string>\n    <string name=\"sort_by_filename\">名稱</string>\n    <string name=\"action_continue\">繼續</string>\n    <string name=\"export_option_xml\">XML</string>\n    <string name=\"export_option_markdown\">Markdown</string>\n    <string name=\"debloat_removal_replace\">取代</string>\n    <string name=\"debloat_removal_caution\">警告</string>\n    <string name=\"file_group_id\">群組（GID）</string>\n    <string name=\"create_new_folder\">新增資料夾</string>\n    <string name=\"title_confirm_deletion\">確認刪除</string>\n    <string name=\"module_name\">模組名稱</string>\n    <string name=\"debloat_list_type\">列表</string>\n    <string name=\"pref_layout_direction\">佈局方向</string>\n    <string name=\"suspend_app\">暫停</string>\n    <string name=\"filter_frozen_apps\">已凍結的應用程式</string>\n    <string name=\"pref_appearance_description\">主題、方向、功能等。</string>\n    <string name=\"calculating_file_size\">正在計算…</string>\n    <string name=\"file_owner_id\">擁有者（UID）</string>\n    <string name=\"action_run\">執行</string>\n    <string name=\"optimize_option_compile_layouts\">編譯佈局資源</string>\n    <string name=\"optimize_option_clear_profile_data\">清除先前的設定檔資料</string>\n    <string name=\"action_optimize_app\">最佳化</string>\n    <string name=\"line_separator\">行分隔符</string>\n    <plurals name=\"search_results\">\n        <item quantity=\"other\">共有 %d 筆結果</item>\n    </plurals>\n    <string name=\"search_option_match_case\">匹配大小寫</string>\n    <string name=\"search_option_whole_word\">單字</string>\n    <string name=\"system_app_put_back\">放回</string>\n    <string name=\"debloat_removal_safe\">安全</string>\n    <string name=\"installing_package\">正在安裝 %1$s…</string>\n    <string name=\"symbolic_link\">符號連結</string>\n    <string name=\"enter_symbolic_link_name\">連結名稱</string>\n    <string name=\"create_new_symbolic_link\">新增符號連結</string>\n    <string name=\"enter_target_path\">目標路徑</string>\n    <string name=\"invalid_target_path\">無效路徑</string>\n    <string name=\"copied_successfully\">已複製。</string>\n    <string name=\"moved_successfully\">已移動</string>\n    <string name=\"change_mode\">變更模式</string>\n    <string name=\"change_group_gid\">變更群組（GID）</string>\n    <string name=\"failed_to_copy_specified_file\">無法複製「%1$s」。</string>\n    <string name=\"xposed_module_info\">Xposed 模組資訊</string>\n    <string name=\"scan_report_from_pithus\">Pithus 報告</string>\n    <string name=\"conflict_detected_while_copying\">偵測到衝突</string>\n    <string name=\"batch_ops_runtime_optimization\">執行階段最佳化</string>\n    <string name=\"pref_zip_align\">對齊 APK 檔案</string>\n    <string name=\"read_only_file\">唯讀檔案</string>\n    <string name=\"replacement_text\">替換</string>\n    <string name=\"debloat_list_aosp\">AOSP</string>\n    <string name=\"debloat_list_misc\">雜項</string>\n    <string name=\"static_shared_library\">靜態共用函式庫</string>\n    <string name=\"debloat_removal_safe_short_description\">可以安全移除</string>\n    <string name=\"filter_force_stopped_apps\">已停止的應用程式</string>\n    <string name=\"title_terminal_emulator\">終端機</string>\n    <string name=\"title_labs_activity\">實驗室</string>\n    <string name=\"title_ui_tracker\">UI 追蹤器</string>\n    <plurals name=\"folder_count\">\n        <item quantity=\"other\">%d 個資料夾</item>\n    </plurals>\n    <string name=\"profile_id\">設定檔 ID</string>\n    <string name=\"apply_profile\">套用設定檔「%1$s」</string>\n    <string name=\"copy_profile_id\">複製設定檔 ID</string>\n    <string name=\"sort_by_data_usage\">資料使用量</string>\n    <string name=\"tap_to_open_notification_settings\">點擊以隱藏</string>\n    <string name=\"block_unblock_components_dots\">封鎖／解除封鎖元件…</string>\n    <string name=\"title_description\">描述</string>\n    <string name=\"restoring_app\">正在恢復 %1$s…</string>\n    <string name=\"empty_folder\">空</string>\n    <plurals name=\"file_count\">\n        <item quantity=\"other\">%d 個檔案</item>\n    </plurals>\n    <string name=\"copy_this_path\">複製路徑</string>\n    <string name=\"title_audio_player\">音訊播放器</string>\n    <string name=\"unblock_components_dots\">解除封鎖元件…</string>\n    <string name=\"action_checking\">正在檢查…</string>\n    <string name=\"report_not_available\">無法使用</string>\n    <string name=\"sort_by_last_modified\">最後一次修改時間</string>\n    <string name=\"confirm_uninstallation\">確認解除安裝</string>\n    <string name=\"app_info_tag_open_links\">開啟連結</string>\n    <string name=\"title_domains_supported_by_the_app\">支援的網域</string>\n    <string name=\"option_display_folders_on_top\">資料夾顯示在最上方</string>\n    <string name=\"export_app_list\">匯出應用程式列表</string>\n    <string name=\"adb_incomplete_usb_debugging_title\">不完整的 USB 偵錯</string>\n    <string name=\"grant_required_permission\">授予所需的權限</string>\n    <string name=\"title_perform_runtime_optimization_to_apps\">執行執行階段最佳化</string>\n    <string name=\"optimize_option_force_dexopt\">立即執行 DEX 最佳化</string>\n    <string name=\"redo\">重做</string>\n    <string name=\"search_option_regex\">正則表達式</string>\n    <string name=\"debloat_removal_type\">類型</string>\n    <string name=\"title_code_editor\">程式碼編輯器</string>\n    <string name=\"action_replace_all\">取代全部</string>\n    <string name=\"uninstall_app\">解除安裝 %1$s</string>\n    <string name=\"debloat_list_oem\">OEM</string>\n    <string name=\"debloat_list_google\">Google</string>\n    <string name=\"folder\">資料夾</string>\n    <string name=\"browse_files\">瀏覽</string>\n    <string name=\"action_lock_app\">鎖定</string>\n    <string name=\"go_to_path\">前往…</string>\n    <string name=\"create_new_file\">新增檔案</string>\n    <string name=\"copy_these_paths\">複製路徑</string>\n    <string name=\"copy_keep_both_file\">保留兩者</string>\n    <string name=\"installer_options\">安裝程式選項</string>\n    <string name=\"debloat_removal_caution_short_description\">謹慎行事</string>\n    <string name=\"backing_up_app\">正在備份 %1$s…</string>\n    <string name=\"change_owner_uid\">變更擁有者（UID）</string>\n    <string name=\"pref_files_msg\">配置檔案管理員。</string>\n    <string name=\"pref_enable_auto_lock\">自動鎖定</string>\n</resources>"
  },
  {
    "path": "app/src/main/res/xml/accessibility_service_config.xml",
    "content": "<accessibility-service xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:description=\"@string/accessibility_service_description\"\n    android:accessibilityEventTypes=\"typeAllMask\"\n    android:accessibilityFeedbackType=\"feedbackGeneric\"\n    android:accessibilityFlags=\"flagDefault\"\n    android:canRetrieveWindowContent=\"true\"\n    android:notificationTimeout=\"100\" />"
  },
  {
    "path": "app/src/main/res/xml/app_widget_info_clear_cache.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<appwidget-provider xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:description=\"@string/clear_app_cache_description\"\n    android:initialLayout=\"@layout/app_widget_clear_cache\"\n    android:minWidth=\"40dp\"\n    android:minHeight=\"40dp\"\n    android:previewImage=\"@drawable/app_widget_preview_clear_cache\"\n    android:previewLayout=\"@layout/app_widget_clear_cache\"\n    android:targetCellWidth=\"1\"\n    android:targetCellHeight=\"1\"\n    android:updatePeriodMillis=\"0\"\n    android:widgetCategory=\"home_screen\" />"
  },
  {
    "path": "app/src/main/res/xml/app_widget_info_data_usage.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<appwidget-provider xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:description=\"@string/data_usage_msg\"\n    android:initialKeyguardLayout=\"@layout/app_widget_data_usage_small\"\n    android:initialLayout=\"@layout/app_widget_data_usage_small\"\n    android:minWidth=\"110dp\"\n    android:minHeight=\"80dp\"\n    android:minResizeWidth=\"100dp\"\n    android:minResizeHeight=\"50dp\"\n    android:previewImage=\"@drawable/app_widget_preview_data_usage\"\n    android:previewLayout=\"@layout/app_widget_data_usage_small\"\n    android:resizeMode=\"horizontal|vertical\"\n    android:maxResizeWidth=\"310dp\"\n    android:maxResizeHeight=\"80dp\"\n    android:targetCellWidth=\"2\"\n    android:targetCellHeight=\"1\"\n    android:updatePeriodMillis=\"60000\"\n    android:widgetCategory=\"home_screen\" />\n"
  },
  {
    "path": "app/src/main/res/xml/app_widget_info_screen_time.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<appwidget-provider xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:description=\"@string/screen_time\"\n    android:initialKeyguardLayout=\"@layout/app_widget_screen_time\"\n    android:initialLayout=\"@layout/app_widget_screen_time\"\n    android:minWidth=\"100dp\"\n    android:minHeight=\"90dp\"\n    android:minResizeWidth=\"100dp\"\n    android:minResizeHeight=\"50dp\"\n    android:previewImage=\"@drawable/app_widget_preview_screen_time\"\n    android:previewLayout=\"@layout/app_widget_screen_time\"\n    android:resizeMode=\"horizontal|vertical\"\n    android:maxResizeWidth=\"500dp\"\n    android:maxResizeHeight=\"350dp\"\n    android:targetCellWidth=\"2\"\n    android:targetCellHeight=\"2\"\n    android:updatePeriodMillis=\"60000\"\n    android:widgetCategory=\"home_screen\" />\n"
  },
  {
    "path": "app/src/main/res/xml/backup_rules.xml",
    "content": "<data-extraction-rules>\n    <cloud-backup>\n        <exclude domain=\"root\" path=\".\" />\n        <exclude domain=\"database\" path=\".\" />\n        <exclude domain=\"external\" path=\".\" />\n\n        <include domain=\"file\" path=\".\" />\n        <exclude domain=\"file\" path=\"conf\" />\n        <exclude domain=\"file\" path=\"profiles\" />\n\n        <include domain=\"sharedpref\" path=\".\" />\n        <exclude domain=\"sharedpref\" path=\"WebViewChromiumPrefs.xml\" />\n    </cloud-backup>\n    <device-transfer>\n        <exclude domain=\"root\" path=\".\" />\n        <exclude domain=\"database\" path=\".\" />\n        <exclude domain=\"external\" path=\".\" />\n\n        <include domain=\"file\" path=\".\" />\n        <exclude domain=\"file\" path=\"conf\" />\n        <exclude domain=\"file\" path=\"profiles\" />\n\n        <include domain=\"sharedpref\" path=\".\" />\n        <exclude domain=\"sharedpref\" path=\"WebViewChromiumPrefs.xml\" />\n    </device-transfer>\n</data-extraction-rules>"
  },
  {
    "path": "app/src/main/res/xml/full_backup_rules.xml",
    "content": "<full-backup-content>\n    <exclude domain=\"root\" path=\".\" />\n    <exclude domain=\"database\" path=\".\" />\n    <exclude domain=\"external\" path=\".\" />\n\n    <include domain=\"file\" path=\".\" />\n    <exclude domain=\"file\" path=\"conf\" />\n    <exclude domain=\"file\" path=\"profiles\" />\n\n    <include domain=\"sharedpref\" path=\".\" />\n    <exclude domain=\"sharedpref\" path=\"WebViewChromiumPrefs.xml\" />\n</full-backup-content>\n"
  },
  {
    "path": "app/src/main/res/xml/locales_config.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<locale-config xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <locale android:name=\"ar\"/>\n    <locale android:name=\"de\"/>\n    <locale android:name=\"en\"/>\n    <locale android:name=\"es-ES\"/>\n    <locale android:name=\"fa\"/>\n    <locale android:name=\"fr\"/>\n    <locale android:name=\"hi\"/>\n    <locale android:name=\"id\"/>\n    <locale android:name=\"it\"/>\n    <locale android:name=\"ja\"/>\n    <locale android:name=\"ko\"/>\n    <locale android:name=\"nb-NO\"/>\n    <locale android:name=\"pl\"/>\n    <locale android:name=\"pt\"/>\n    <locale android:name=\"pt-BR\"/>\n    <locale android:name=\"ro\"/>\n    <locale android:name=\"ru-RU\"/>\n    <locale android:name=\"tr-TR\"/>\n    <locale android:name=\"uk-UA\"/>\n    <locale android:name=\"vi\"/>\n    <locale android:name=\"zh-CN\"/>\n    <locale android:name=\"zh-TW\"/>\n</locale-config>\n"
  },
  {
    "path": "app/src/main/res/xml/network_security_config.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<network-security-config>\n    <base-config cleartextTrafficPermitted=\"false\" />\n    <domain-config>\n        <domain includeSubdomains=\"true\">www.virustotal.com</domain>\n        <pin-set expiration=\"2028-01-27\">\n            <!--\n            Resource: https://pki.goog/repository/\n            -->\n\n            <!-- GlobalSign Root CA -->\n            <pin digest=\"SHA-256\">K87oWBWM9UZfyddvDfoxL+8lpNyoUB2ptGtn0fv6G2Q=</pin>\n\n            <!-- GTS Root R1 -->\n            <pin digest=\"SHA-256\">hxqRlPTu1bMS/0DITB1SSu0vd4u/8l8TjPgfaAp63Gc=</pin>\n\n            <!-- GTS Root R2 -->\n            <pin digest=\"SHA-256\">Vfd95BwDeSQo+NUYxVEEIlvkOlWY2SalKK1lPhzOx78=</pin>\n\n            <!-- GTS Root R3 -->\n            <pin digest=\"SHA-256\">QXnt2YHvdHR3tJYmQIr0Paosp6t/nggsEGD4QJZ3Q0g=</pin>\n\n            <!-- GTS Root R4 -->\n            <pin digest=\"SHA-256\">mEflZT5enoR1FuXLgYYGqnVEoZvmf9c2bVBpiOjYQ0c=</pin>\n\n            <!-- GlobalSign ECC Root CA - R4 -->\n            <pin digest=\"SHA-256\">CLOmM1/OXvSPjw5UOYbAf9GKOxImEp9hhku9W90fHMk=</pin>\n        </pin-set>\n    </domain-config>\n    <domain-config>\n        <domain includeSubdomains=\"true\">beta.pithus.org</domain>\n        <pin-set expiration=\"2035-01-03\">\n            <!--\n            Resources:\n            https://letsencrypt.org/certificates/\n            https://community.letsencrypt.org/t/hpkp-best-practices-if-you-choose-to-implement/4625\n            -->\n\n            <!-- DST Root CA X3 -->\n            <pin digest=\"SHA-256\">Vjs8r4z+80wjNcr1YKepWQboSIRi63WsWXhIMN+eWys=</pin>\n\n            <!-- ISRG Root X1 -->\n            <pin digest=\"SHA-256\">C5+lpZ7tcVwmwQIMcRtPbsQtWLABXhQzejna0wHFr8M=</pin>\n\n            <!-- ISRG Root X2 -->\n            <pin digest=\"SHA-256\">diGVwiVYbubAI3RW4hB9xU8e/CH2GnkuvVFZE8zmgzI=</pin>\n        </pin-set>\n    </domain-config>\n    <domain-config cleartextTrafficPermitted=\"true\">\n        <domain includeSubdomains=\"false\">127.0.0.1</domain>\n        <domain includeSubdomains=\"false\">localhost</domain>\n    </domain-config>\n</network-security-config>"
  },
  {
    "path": "app/src/main/res/xml/preferences_about.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<PreferenceScreen xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\">\n\n    <io.github.muntashirakon.preference.HyperlinkPreference\n        app:title=\"@string/app_name\"\n        app:summary=\"@string/copyright_message\"\n        app:iconSpaceReserved=\"false\" />\n\n    <Preference\n        app:key=\"version\"\n        app:title=\"@string/pref_version_changelog\"\n        tools:summary=\"v3.0.0 (410)\"\n        app:iconSpaceReserved=\"false\" />\n\n    <io.github.muntashirakon.preference.HyperlinkPreference\n        app:key=\"license\"\n        app:title=\"@string/license\"\n        app:summary=\"@string/license_message\"\n        app:iconSpaceReserved=\"false\" />\n\n    <io.github.muntashirakon.preference.HyperlinkPreference\n        app:title=\"@string/source_code\"\n        app:summary=\"@string/source_code_links\"\n        app:iconSpaceReserved=\"false\" />\n\n    <io.github.muntashirakon.preference.HyperlinkPreference\n        app:title=\"@string/community\"\n        app:summary=\"@string/community_links\"\n        app:iconSpaceReserved=\"false\" />\n\n    <Preference\n        app:key=\"website\"\n        app:title=\"@string/website\"\n        app:iconSpaceReserved=\"false\" />\n\n    <Preference\n        app:key=\"user_manual\"\n        app:title=\"@string/user_manual\"\n        app:iconSpaceReserved=\"false\" />\n\n    <Preference\n        app:key=\"get_help\"\n        app:title=\"@string/get_help\"\n        app:iconSpaceReserved=\"false\" />\n\n    <Preference\n        app:key=\"third_party_libraries\"\n        app:title=\"@string/third_party\"\n        app:iconSpaceReserved=\"false\" />\n\n    <Preference\n        app:key=\"credits\"\n        app:title=\"@string/credits\"\n        app:iconSpaceReserved=\"false\" />\n\n</PreferenceScreen>\n"
  },
  {
    "path": "app/src/main/res/xml/preferences_advanced.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<PreferenceScreen xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\">\n    <Preference\n        app:key=\"selected_users\"\n        app:title=\"@string/pref_selected_users\"\n        app:summary=\"@string/pref_selected_users_msg\"\n        app:iconSpaceReserved=\"false\" />\n\n    <Preference\n        app:key=\"saved_apk_format\"\n        app:title=\"@string/pref_saved_apk_name_format\"\n        app:summary=\"@string/pref_saved_apk_name_format_msg\"\n        app:iconSpaceReserved=\"false\" />\n\n    <Preference\n        app:key=\"thread_count\"\n        app:title=\"@string/pref_thread_count\"\n        tools:summary=\"Execute at most 5 operations in parallel\"\n        app:iconSpaceReserved=\"false\" />\n\n    <Preference\n        app:key=\"adb_local_server_port\"\n        app:title=\"@string/adb_local_server_port\"\n        tools:summary=\"60001\"\n        app:iconSpaceReserved=\"false\" />\n\n    <Preference\n        app:key=\"import_export_keystore\"\n        app:title=\"@string/pref_import_export_keystore\"\n        app:summary=\"@string/pref_import_export_keystore_msg\"\n        app:iconSpaceReserved=\"false\" />\n\n    <SwitchPreferenceCompat\n        app:key=\"send_notifications_to_connected_devices\"\n        app:title=\"@string/pref_send_notifications_to_connected_devices\"\n        app:summary=\"@string/pref_send_notification_to_connected_devices_msg\"\n        app:iconSpaceReserved=\"false\" />\n\n</PreferenceScreen>"
  },
  {
    "path": "app/src/main/res/xml/preferences_appearance.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<PreferenceScreen xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\">\n    <Preference\n        app:key=\"app_theme\"\n        app:title=\"@string/pref_app_theme\"\n        tools:summary=\"Follow system\"\n        app:iconSpaceReserved=\"false\" />\n\n    <SwitchPreferenceCompat\n        app:key=\"app_theme_pure_black\"\n        app:title=\"@string/pref_pure_black_theme\"\n        app:summary=\"@string/pref_pure_black_theme_msg\"\n        app:iconSpaceReserved=\"false\" />\n\n    <SwitchPreferenceCompat\n        app:key=\"use_system_font\"\n        app:title=\"@string/pref_use_system_font\"\n        app:summary=\"@string/pref_use_system_font_msg\"\n        app:iconSpaceReserved=\"false\" />\n\n    <Preference\n        app:key=\"layout_orientation\"\n        app:title=\"@string/pref_layout_direction\"\n        tools:summary=\"Left to right\"\n        app:iconSpaceReserved=\"false\" />\n\n    <Preference\n        app:key=\"enabled_features\"\n        app:title=\"@string/enable_disable_features\"\n        app:summary=\"@string/pref_enable_disable_features_msg\"\n        app:iconSpaceReserved=\"false\" />\n</PreferenceScreen>"
  },
  {
    "path": "app/src/main/res/xml/preferences_backup_restore.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<PreferenceScreen xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    app:title=\"@string/backup_restore\">\n\n    <Preference\n        app:key=\"backup_compression_method\"\n        app:title=\"@string/pref_compression_method\"\n        tools:summary=\"Current method: GZip\"\n        app:iconSpaceReserved=\"false\" />\n\n    <Preference\n        app:key=\"backup_flags\"\n        app:title=\"@string/backup_options\"\n        app:summary=\"@string/pref_backup_flags_msg\"\n        app:iconSpaceReserved=\"false\" />\n\n    <SwitchPreferenceCompat\n        app:key=\"backup_android_keystore\"\n        app:title=\"@string/pref_backup_android_keystore\"\n        app:summary=\"@string/pref_backup_android_keystore_msg\"\n        app:iconSpaceReserved=\"false\" />\n\n    <Preference\n        app:key=\"encryption\"\n        app:title=\"@string/encryption\"\n        app:summary=\"@string/pref_encryption_msg\"\n        app:iconSpaceReserved=\"false\" />\n\n    <Preference\n        app:key=\"backup_volume\"\n        app:title=\"@string/backup_volume\"\n        app:summary=\"@string/pref_backup_volume_msg\"\n        app:iconSpaceReserved=\"false\" />\n\n    <Preference\n        app:key=\"import_backups\"\n        app:title=\"@string/pref_import_backups\"\n        app:summary=\"@string/pref_import_backups_msg\"\n        app:iconSpaceReserved=\"false\" />\n\n</PreferenceScreen>"
  },
  {
    "path": "app/src/main/res/xml/preferences_file_manager.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<PreferenceScreen xmlns:app=\"http://schemas.android.com/apk/res-auto\">\n\n    <SwitchPreferenceCompat\n        app:key=\"fm_display_in_launcher\"\n        app:title=\"@string/pref_files_display_in_launcher\"\n        app:iconSpaceReserved=\"false\" />\n\n    <SwitchPreferenceCompat\n        app:key=\"fm_remember_last_path\"\n        app:title=\"@string/pref_files_remember_last_path\"\n        app:summary=\"@string/pref_files_remember_last_path_msg\"\n        app:iconSpaceReserved=\"false\" />\n\n    <Preference\n        app:key=\"fm_home\"\n        app:title=\"@string/pref_set_home\"\n        app:iconSpaceReserved=\"false\" />\n\n</PreferenceScreen>\n"
  },
  {
    "path": "app/src/main/res/xml/preferences_installer.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<PreferenceScreen xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\">\n\n    <io.github.muntashirakon.preference.TopSwitchPreference\n        app:iconSpaceReserved=\"false\"\n        app:key=\"use_installer\"\n        app:persistent=\"false\"\n        app:title=\"@string/pref_installer\" />\n\n    <PreferenceCategory\n        app:iconSpaceReserved=\"false\"\n        app:key=\"cat_general\"\n        app:title=\"@string/pref_cat_general\">\n\n        <Preference\n            app:iconSpaceReserved=\"false\"\n            app:key=\"installer_install_location\"\n            app:title=\"@string/install_location\"\n            tools:summary=\"Auto\" />\n\n\n        <SwitchPreferenceCompat\n            app:iconSpaceReserved=\"false\"\n            app:key=\"installer_block_trackers\"\n            app:summary=\"@string/pref_block_trackers_msg\"\n            app:title=\"@string/block_trackers\" />\n\n        <SwitchPreferenceCompat\n            app:iconSpaceReserved=\"false\"\n            app:key=\"installer_display_changes\"\n            app:summary=\"@string/pref_display_changes_msg\"\n            app:title=\"@string/pref_display_changes\" />\n\n    </PreferenceCategory>\n\n    <PreferenceCategory\n        app:iconSpaceReserved=\"false\"\n        app:key=\"cat_advanced\"\n        app:title=\"@string/pref_cat_advanced\">\n\n        <Preference\n            app:iconSpaceReserved=\"false\"\n            app:key=\"installer_installer_app\"\n            app:title=\"@string/installer_app\"\n            tools:summary=\"App Manager\" />\n\n        <SwitchPreferenceCompat\n            app:iconSpaceReserved=\"false\"\n            app:key=\"installer_disable_verification\"\n            app:summary=\"@string/pref_disable_apk_verification_description\"\n            app:title=\"@string/pref_disable_apk_verification\" />\n\n        <SwitchPreferenceCompat\n            app:iconSpaceReserved=\"false\"\n            app:key=\"installer_update_ownership\"\n            app:summary=\"@string/pref_request_update_ownership_description\"\n            app:title=\"@string/pref_request_update_ownership\" />\n\n        <Preference\n            app:iconSpaceReserved=\"false\"\n            app:key=\"installer_default_pkg_source\"\n            app:title=\"@string/pref_default_package_source\"\n            tools:summary=\"Other\" />\n\n        <SwitchPreferenceCompat\n            app:iconSpaceReserved=\"false\"\n            app:key=\"installer_set_origin\"\n            app:summary=\"@string/pref_set_origin_description\"\n            app:title=\"@string/pref_set_origin\" />\n\n        <SwitchPreferenceCompat\n            app:iconSpaceReserved=\"false\"\n            app:key=\"installer_sign_apk\"\n            app:summary=\"@string/pref_sign_apk_msg\"\n            app:title=\"@string/pref_sign_apk\" />\n\n        <SwitchPreferenceCompat\n            app:iconSpaceReserved=\"false\"\n            app:key=\"installer_force_dex_opt\"\n            app:summary=\"@string/pref_installer_force_dexopt_description\"\n            app:title=\"@string/optimize_option_force_dexopt\" />\n\n        <SwitchPreferenceCompat\n            app:iconSpaceReserved=\"false\"\n            app:key=\"installer_always_on_background\"\n            app:summary=\"@string/pref_always_on_background_msg\"\n            app:title=\"@string/pref_always_on_background\" />\n\n    </PreferenceCategory>\n\n</PreferenceScreen>"
  },
  {
    "path": "app/src/main/res/xml/preferences_log_viewer.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<PreferenceScreen xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\">\n\n    <io.github.muntashirakon.preference.TopSwitchPreference\n        app:key=\"use_log_viewer\"\n        app:title=\"@string/pref_use_log_viewer\"\n        app:persistent=\"false\"\n        app:iconSpaceReserved=\"false\" />\n\n    <PreferenceCategory\n        app:key=\"cat_appearance\"\n        app:title=\"@string/pref_cat_appearance\"\n        app:iconSpaceReserved=\"false\">\n\n        <SwitchPreferenceCompat\n            app:key=\"log_viewer_expand_by_default\"\n            app:summary=\"@string/pref_expanded_by_default_summary\"\n            app:title=\"@string/pref_expanded_by_default_title\"\n            app:iconSpaceReserved=\"false\" />\n\n        <SwitchPreferenceCompat\n            app:key=\"log_viewer_show_pid_tid_timestamp\"\n            app:summary=\"@string/pref_show_timestamp_summary\"\n            app:title=\"@string/pref_show_timestamp_title\"\n            app:iconSpaceReserved=\"false\" />\n\n    </PreferenceCategory>\n\n    <PreferenceCategory\n        app:key=\"cat_conf\"\n        app:title=\"@string/pref_cat_configuration\"\n        app:iconSpaceReserved=\"false\" >\n\n        <Preference\n            app:key=\"log_viewer_buffer\"\n            app:title=\"@string/pref_buffer_title\"\n            tools:summary=\"main, system, crash\"\n            app:iconSpaceReserved=\"false\" />\n\n        <Preference\n            app:key=\"log_viewer_default_log_level\"\n            app:title=\"@string/pref_default_log_level_title\"\n            app:summary=\"@string/pref_default_log_level_summary\"\n            app:iconSpaceReserved=\"false\" />\n\n    </PreferenceCategory>\n\n    <PreferenceCategory\n        app:key=\"cat_advanced\"\n        app:title=\"@string/pref_cat_advanced\"\n        app:iconSpaceReserved=\"false\" >\n\n        <Preference\n            app:key=\"log_viewer_write_period\"\n            app:title=\"@string/pref_log_write_period_title\"\n            tools:summary=\"@string/pref_log_write_period_summary\"\n            app:iconSpaceReserved=\"false\" />\n\n        <Preference\n            app:key=\"log_viewer_display_limit\"\n            app:title=\"@string/pref_display_limit_title\"\n            tools:summary=\"@string/pref_display_limit_summary\"\n            app:iconSpaceReserved=\"false\" />\n\n        <Preference\n            app:key=\"log_viewer_filter_pattern\"\n            app:title=\"@string/pref_filter_pattern_title\"\n            app:summary=\"@string/pref_filter_pattern_summary\"\n            app:iconSpaceReserved=\"false\" />\n\n        <SwitchPreferenceCompat\n            app:key=\"log_viewer_omit_sensitive_info\"\n            app:title=\"@string/omit_sensitive_info\"\n            app:summary=\"@string/omit_sensitive_info_summary\"\n            app:iconSpaceReserved=\"false\" />\n\n    </PreferenceCategory>\n\n</PreferenceScreen>\n"
  },
  {
    "path": "app/src/main/res/xml/preferences_main.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<PreferenceScreen xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\">\n\n    <io.github.muntashirakon.preference.WarningAlertPreference\n        app:icon=\"@drawable/ic_caution\"\n        app:key=\"app_manager_expiring_notice\"\n        app:selectable=\"false\"\n        app:summary=\"@string/app_manager_build_expiring_soon_warning\" />\n\n    <io.github.muntashirakon.preference.InfoAlertPreference\n        app:icon=\"@drawable/ic_charity\"\n        app:key=\"funding_campaign_notice\"\n        app:selectable=\"false\"\n        app:summary=\"@string/funding_campaign_text\" />\n\n    <Preference\n        android:fragment=\"io.github.muntashirakon.AppManager.settings.ChangeLanguageFragment\"\n        app:icon=\"@drawable/ic_translate\"\n        app:key=\"custom_locale\"\n        app:title=\"@string/pref_app_language\"\n        tools:summary=\"Auto\" />\n\n    <Preference\n        android:fragment=\"io.github.muntashirakon.AppManager.settings.AppearancePreferences\"\n        app:icon=\"@drawable/ic_palette_swatch\"\n        app:key=\"appearance_prefs\"\n        app:summary=\"@string/pref_appearance_description\"\n        app:title=\"@string/pref_cat_appearance\" />\n\n    <Preference\n        android:fragment=\"io.github.muntashirakon.AppManager.settings.PrivacyPreferences\"\n        app:icon=\"@drawable/ic_security\"\n        app:key=\"privacy_prefs\"\n        app:summary=\"@string/pref_privacy_description\"\n        app:title=\"@string/pref_privacy\" />\n\n    <Preference\n        android:fragment=\"io.github.muntashirakon.AppManager.settings.ModeOfOpsPreference\"\n        app:icon=\"@drawable/ic_run_fast\"\n        app:key=\"mode_of_operations\"\n        app:title=\"@string/pref_mode_of_operations\"\n        tools:summary=\"Auto\" />\n\n    <Preference\n        android:fragment=\"io.github.muntashirakon.AppManager.settings.ApkSigningPreferences\"\n        app:icon=\"@drawable/ic_shield_key\"\n        app:key=\"apk_signing_prefs\"\n        app:summary=\"@string/pref_apk_signing_msg\"\n        app:title=\"@string/apk_signing\" />\n\n    <Preference\n        android:fragment=\"io.github.muntashirakon.AppManager.settings.InstallerPreferences\"\n        app:icon=\"@drawable/ic_get_app\"\n        app:key=\"installer\"\n        app:summary=\"@string/pref_installer_msg\"\n        app:title=\"@string/installer\" />\n\n    <Preference\n        android:fragment=\"io.github.muntashirakon.AppManager.settings.BackupRestorePreferences\"\n        app:icon=\"@drawable/ic_backup_restore\"\n        app:key=\"backup_restore_prefs\"\n        app:summary=\"@string/pref_backup_restore_msg\"\n        app:title=\"@string/backup_restore\" />\n\n    <Preference\n        android:fragment=\"io.github.muntashirakon.AppManager.settings.LogViewerPreferences\"\n        app:icon=\"@drawable/ic_view_list\"\n        app:key=\"log_viewer_prefs\"\n        app:summary=\"@string/pref_log_viewer_msg\"\n        app:title=\"@string/log_viewer\" />\n\n    <Preference\n        android:fragment=\"io.github.muntashirakon.AppManager.settings.FileManagerPreferences\"\n        app:icon=\"@drawable/ic_file_document_multiple\"\n        app:key=\"files_prefs\"\n        app:summary=\"@string/pref_files_msg\"\n        app:title=\"@string/files\" />\n\n    <Preference\n        android:fragment=\"io.github.muntashirakon.AppManager.settings.RulesPreferences\"\n        app:icon=\"@drawable/ic_list_status\"\n        app:key=\"rules_prefs\"\n        app:summary=\"@string/pref_rules_msg\"\n        app:title=\"@string/rules\" />\n\n    <Preference\n        android:fragment=\"io.github.muntashirakon.AppManager.settings.VirusTotalPreferences\"\n        app:icon=\"@drawable/ic_vt\"\n        app:key=\"vt\"\n        app:summary=\"@string/pref_vt_apikey_summary\"\n        app:title=\"@string/virus_total\" />\n\n    <Preference\n        android:fragment=\"io.github.muntashirakon.AppManager.settings.AdvancedPreferences\"\n        app:icon=\"@drawable/ic_tune\"\n        app:key=\"advanced_prefs\"\n        app:summary=\"@string/pref_advanced_pref\"\n        app:title=\"@string/pref_cat_advanced\" />\n\n    <Preference\n        android:fragment=\"io.github.muntashirakon.AppManager.settings.AboutDeviceFragment\"\n        app:icon=\"@drawable/ic_phone_android\"\n        app:key=\"about_device\"\n        app:summary=\"@string/pref_about_device_msg\"\n        app:title=\"@string/about_device\" />\n\n    <Preference\n        android:fragment=\"io.github.muntashirakon.AppManager.settings.AboutPreferences\"\n        app:icon=\"@drawable/ic_information\"\n        app:key=\"about\"\n        app:summary=\"@string/pref_about_msg\"\n        app:title=\"@string/about\" />\n\n    <Preference\n        android:fragment=\"io.github.muntashirakon.AppManager.settings.TroubleshootingPreferences\"\n        app:icon=\"@drawable/ic_hammer_wrench\"\n        app:key=\"troubleshooting_prefs\"\n        app:title=\"@string/troubleshooting\" />\n\n</PreferenceScreen>"
  },
  {
    "path": "app/src/main/res/xml/preferences_privacy.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<PreferenceScreen xmlns:app=\"http://schemas.android.com/apk/res-auto\">\n    <SwitchPreferenceCompat\n        app:key=\"enable_screen_lock\"\n        app:title=\"@string/screen_lock\"\n        app:summary=\"@string/screen_lock_msg\"\n        app:iconSpaceReserved=\"false\" />\n\n    <SwitchPreferenceCompat\n        app:key=\"enable_persistent_session\"\n        app:title=\"@string/pref_enable_persistent_session\"\n        app:summary=\"@string/pref_enable_persistent_session_msg\"\n        app:iconSpaceReserved=\"false\" />\n\n    <SwitchPreferenceCompat\n        app:key=\"enable_auto_lock\"\n        app:title=\"@string/pref_enable_auto_lock\"\n        app:summary=\"@string/pref_enable_auto_lock_msg\"\n        app:iconSpaceReserved=\"false\" />\n\n    <SwitchPreferenceCompat\n        app:key=\"toggle_internet\"\n        app:title=\"@string/toggle_internet\"\n        app:summary=\"@string/pref_toggle_internet_msg\"\n        app:persistent=\"false\"\n        app:iconSpaceReserved=\"false\" />\n\n    <Preference\n        app:key=\"auth_manager\"\n        app:title=\"@string/auth_manager_title\"\n        app:iconSpaceReserved=\"false\" />\n\n</PreferenceScreen>"
  },
  {
    "path": "app/src/main/res/xml/preferences_profile_config.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<PreferenceScreen xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\">\n\n    <Preference\n        app:key=\"profile_id\"\n        app:title=\"@string/profile_id\"\n        tools:summary=\"@tools:sample/lorem[1]\"\n        app:iconSpaceReserved=\"false\" />\n\n    <Preference\n        app:key=\"comment\"\n        app:title=\"@string/comment\"\n        tools:summary=\"@tools:sample/lorem[9]\"\n        app:iconSpaceReserved=\"false\" />\n\n    <Preference\n        app:key=\"state\"\n        app:summary=\"@string/profile_state_msg\"\n        tools:title=\"State: On\"\n        app:iconSpaceReserved=\"false\" />\n\n    <Preference\n        app:key=\"users\"\n        app:title=\"@string/users\"\n        tools:summary=\"Users: Main, Work\"\n        app:iconSpaceReserved=\"false\" />\n\n    <Preference\n        app:key=\"components\"\n        app:title=\"@string/components\"\n        tools:summary=\"Comma separated list of components\"\n        app:iconSpaceReserved=\"false\" />\n\n    <Preference\n        app:key=\"app_ops\"\n        app:title=\"@string/app_ops\"\n        tools:summary=\"Comma separated list of app ops\"\n        app:iconSpaceReserved=\"false\" />\n\n    <Preference\n        app:key=\"permissions\"\n        app:title=\"@string/declared_permission\"\n        tools:summary=\"Comma separated list of permissions\"\n        app:iconSpaceReserved=\"false\" />\n\n    <Preference\n        app:key=\"backup_data\"\n        app:title=\"@string/backup_restore\"\n        tools:summary=\"Backup Info\"\n        app:iconSpaceReserved=\"false\" />\n\n    <Preference\n        app:key=\"export_rules\"\n        app:title=\"@string/export_blocking_rules\"\n        tools:summary=\"Allowed flags\"\n        app:iconSpaceReserved=\"false\" />\n\n    <SwitchPreferenceCompat\n        app:key=\"freeze\"\n        app:title=\"@string/freeze\"\n        app:summary=\"@string/profile_freeze_msg\"\n        app:iconSpaceReserved=\"false\" />\n\n    <SwitchPreferenceCompat\n        app:key=\"force_stop\"\n        app:title=\"@string/force_stop\"\n        app:summary=\"@string/profile_force_stop_msg\"\n        app:iconSpaceReserved=\"false\" />\n\n    <SwitchPreferenceCompat\n        app:key=\"clear_cache\"\n        app:title=\"@string/clear_cache\"\n        app:summary=\"@string/profile_clear_cache_msg\"\n        app:iconSpaceReserved=\"false\" />\n\n    <SwitchPreferenceCompat\n        app:key=\"clear_data\"\n        app:title=\"@string/clear_data\"\n        app:summary=\"@string/profile_clear_data_msg\"\n        app:iconSpaceReserved=\"false\" />\n\n    <SwitchPreferenceCompat\n        app:key=\"block_trackers\"\n        app:title=\"@string/block_trackers\"\n        app:summary=\"@string/profile_block_trackers_msg\"\n        app:iconSpaceReserved=\"false\" />\n\n    <SwitchPreferenceCompat\n        app:key=\"save_apk\"\n        app:title=\"@string/save_apk\"\n        app:summary=\"@string/profile_save_apk_msg\"\n        app:iconSpaceReserved=\"false\" />\n\n    <SwitchPreferenceCompat\n        app:key=\"allow_routine\"\n        app:title=\"@string/allow_routine_ops\"\n        app:summary=\"@string/allow_routine_ops_msg\"\n        app:iconSpaceReserved=\"false\" />\n\n</PreferenceScreen>"
  },
  {
    "path": "app/src/main/res/xml/preferences_rules.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<PreferenceScreen xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\">\n\n    <Preference\n        app:key=\"freeze_type\"\n        app:title=\"@string/pref_default_freezing_method\"\n        app:iconSpaceReserved=\"false\" />\n\n    <Preference\n        app:key=\"default_blocking_method\"\n        app:title=\"@string/pref_default_blocking_method\"\n        app:iconSpaceReserved=\"false\" />\n\n    <SwitchPreferenceCompat\n        app:key=\"global_blocking_enabled\"\n        app:title=\"@string/pref_global_blocking_enabled\"\n        app:summary=\"@string/pref_global_blocking_enabled_msg\"\n        app:iconSpaceReserved=\"false\" />\n\n    <Preference\n        app:key=\"import_export_rules\"\n        app:title=\"@string/pref_import_export_blocking_rules\"\n        app:summary=\"@string/pref_import_export_blocking_rules_msg\"\n        android:fragment=\"io.github.muntashirakon.AppManager.settings.ImportExportRulesPreferences\"\n        app:iconSpaceReserved=\"false\" />\n\n    <io.github.muntashirakon.preference.PrimaryButtonPreference\n        app:key=\"remove_all_rules\"\n        app:title=\"@string/pref_remove_all_rules\"\n        app:icon=\"@drawable/ic_restore\"/>\n\n</PreferenceScreen>"
  },
  {
    "path": "app/src/main/res/xml/preferences_rules_import_export.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<PreferenceScreen xmlns:app=\"http://schemas.android.com/apk/res-auto\">\n\n    <Preference\n        app:key=\"export\"\n        app:title=\"@string/pref_export\"\n        app:summary=\"@string/pref_export_msg\"\n        app:iconSpaceReserved=\"false\" />\n\n    <Preference\n        app:key=\"import\"\n        app:title=\"@string/pref_import\"\n        app:summary=\"@string/pref_import_msg\"\n        app:iconSpaceReserved=\"false\" />\n\n    <Preference\n        app:key=\"import_existing\"\n        app:title=\"@string/pref_import_existing\"\n        app:summary=\"@string/pref_import_existing_msg\"\n        app:iconSpaceReserved=\"false\" />\n\n    <Preference\n        app:key=\"import_watt\"\n        app:title=\"@string/pref_import_watt\"\n        app:summary=\"@string/pref_import_watt_msg\"\n        app:iconSpaceReserved=\"false\" />\n\n    <Preference\n        app:key=\"import_blocker\"\n        app:title=\"@string/pref_import_blocker\"\n        app:summary=\"@string/pref_import_blocker_msg\"\n        app:iconSpaceReserved=\"false\" />\n\n</PreferenceScreen>"
  },
  {
    "path": "app/src/main/res/xml/preferences_signature.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<PreferenceScreen xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    app:title=\"@string/apk_signing\">\n\n    <Preference\n        app:key=\"signature_schemes\"\n        app:summary=\"@string/pref_signature_schemes_msg\"\n        app:title=\"@string/app_signing_signature_schemes\"\n        app:iconSpaceReserved=\"false\" />\n\n    <Preference\n        app:key=\"signing_keys\"\n        app:title=\"@string/signing_key\"\n        tools:summary=\"Using generic keys.\"\n        app:iconSpaceReserved=\"false\" />\n\n    <SwitchPreferenceCompat\n        app:key=\"zip_align\"\n        app:title=\"@string/pref_zip_align\"\n        app:summary=\"@string/pref_zip_align_msg\"\n        app:iconSpaceReserved=\"false\" />\n\n</PreferenceScreen>"
  },
  {
    "path": "app/src/main/res/xml/preferences_troubleshooting.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<PreferenceScreen xmlns:app=\"http://schemas.android.com/apk/res-auto\">\n    <Preference\n        app:key=\"reload_apps\"\n        app:title=\"@string/pref_reload_apps\"\n        app:summary=\"@string/pref_reload_apps_msg\"\n        app:iconSpaceReserved=\"false\" />\n</PreferenceScreen>"
  },
  {
    "path": "app/src/main/res/xml/preferences_virus_total.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<PreferenceScreen xmlns:app=\"http://schemas.android.com/apk/res-auto\">\n    <io.github.muntashirakon.preference.TopSwitchPreference\n        app:key=\"use_vt\"\n        app:title=\"@string/pref_use_vt\"\n        app:persistent=\"false\"\n        app:iconSpaceReserved=\"false\" />\n\n    <io.github.muntashirakon.preference.WarningAlertPreference\n        app:key=\"info_no_internet\"\n        app:icon=\"@drawable/ic_caution\"\n        app:iconSpaceReserved=\"false\"\n        app:selectable=\"false\"\n        app:summary=\"@string/pref_use_vt_no_internet\" />\n\n    <Preference\n        app:key=\"virus_total_api_key\"\n        app:title=\"@string/pref_vt_apikey\"\n        app:iconSpaceReserved=\"false\" />\n\n    <SwitchPreferenceCompat\n        app:key=\"virus_total_prompt_before_uploading\"\n        app:title=\"@string/pref_vt_prompt_before_uploading\"\n        app:iconSpaceReserved=\"false\" />\n\n    <io.github.muntashirakon.preference.DefaultAlertPreference\n        app:key=\"info\"\n        app:icon=\"@drawable/ic_information_circle\"\n        app:iconSpaceReserved=\"false\"\n        app:selectable=\"false\"\n        app:summary=\"@string/pref_vt_apikey_description\" />\n</PreferenceScreen>"
  },
  {
    "path": "app/src/main/res/xml/recording_widget_info.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<!-- Copyright 2012 Nolan Lawson -->\n<!-- 21600000 = 6 hours in milliseconds -->\n<appwidget-provider xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:description=\"@string/record_log\"\n    android:initialLayout=\"@layout/widget_recording\"\n    android:previewImage=\"@drawable/ic_shortcut_record\"\n    android:minHeight=\"40dp\"\n    android:minWidth=\"40dp\"\n    android:resizeMode=\"none\"\n    android:updatePeriodMillis=\"21600000\" />"
  },
  {
    "path": "app/src/test/java/android/os/UserHandleHidden.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage android.os;\n\npublic class UserHandleHidden {\n    public static final int PER_USER_RANGE = 100000;\n    public static final int USER_ALL = -1;\n    public static final int USER_NULL = -10000;\n    public static final int USER_SYSTEM = 0;\n    public static final boolean MU_ENABLED = true;\n\n    public static int getUserId(int uid) {\n        if (MU_ENABLED) {\n            return uid / PER_USER_RANGE;\n        } else {\n            return USER_SYSTEM;\n        }\n    }\n\n    public static int getUid(int userId, int appId) {\n        if (MU_ENABLED) {\n            return userId * PER_USER_RANGE + (appId % PER_USER_RANGE);\n        } else {\n            return appId;\n        }\n    }\n\n    public static int getAppId(int uid) {\n        return uid % PER_USER_RANGE;\n    }\n\n    public static int myUserId() {\n        return 0;\n    }\n}"
  },
  {
    "path": "app/src/test/java/android/system/OsHidden.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage android.system;\n\npublic class OsHidden {\n    public static StructPasswd getpwuid(int uid) throws ErrnoException {\n        throw new ErrnoException(\"pwuid\", OsConstants.EACCES);\n    }\n}\n"
  },
  {
    "path": "app/src/test/java/android/system/StructPasswd.java",
    "content": "package android.system;\n\n/**\n * Corresponds to C's {@code struct passwd} from {@code &lt;pwd.h&gt;}.\n */\npublic final class StructPasswd {\n    public final String pw_name;\n    public final int pw_uid;\n    public final int pw_gid;\n    public final String pw_dir;\n    public final String pw_shell;\n\n    public StructPasswd(String pw_name, int pw_uid, int pw_gid, String pw_dir, String pw_shell) {\n        this.pw_name = pw_name;\n        this.pw_uid = pw_uid;\n        this.pw_gid = pw_gid;\n        this.pw_dir = pw_dir;\n        this.pw_shell = pw_shell;\n    }\n}"
  },
  {
    "path": "app/src/test/java/androidx/documentfile/provider/DexDocumentFileTest.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage androidx.documentfile.provider;\n\nimport android.net.Uri;\n\nimport org.junit.Before;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.robolectric.RobolectricTestRunner;\n\nimport java.io.File;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Objects;\n\nimport io.github.muntashirakon.AppManager.backup.convert.OABConverter;\nimport io.github.muntashirakon.AppManager.fm.ContentType2;\nimport io.github.muntashirakon.io.Paths;\nimport io.github.muntashirakon.io.fs.VirtualFileSystem;\n\nimport static androidx.documentfile.provider.ZipDocumentFileTest.getChildNames;\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertFalse;\nimport static org.junit.Assert.assertNotEquals;\nimport static org.junit.Assert.assertNotNull;\nimport static org.junit.Assert.assertNull;\nimport static org.junit.Assert.assertTrue;\n\n@RunWith(RobolectricTestRunner.class)\npublic class DexDocumentFileTest {\n    private final ClassLoader classLoader = getClass().getClassLoader();\n    private File dexFile;\n\n    @Before\n    public void setUp() throws Exception {\n        assert classLoader != null;\n        dexFile = new File(new File(classLoader.getResource(OABConverter.PATH_SUFFIX).getFile(), \"ademar.textlauncher\"), \"classes.dex\");\n    }\n\n    @Test\n    public void testDexFile() throws Throwable {\n        List<String> level1 = Arrays.asList(\"a\", \"ademar\");\n        int fsId = VirtualFileSystem.mount(Uri.fromFile(new File(\"/tmp/dex1\")), Paths.get(dexFile), ContentType2.DEX.getMimeType());\n        VirtualDocumentFile doc = new VirtualDocumentFile(null, Objects.requireNonNull(VirtualFileSystem.getFileSystem(fsId)));\n        assertTrue(doc.isDirectory());\n        assertFalse(doc.isFile());\n        assertTrue(doc.exists());\n        assertEquals(doc.length(), 0);\n        assertEquals(File.separator, doc.getName());\n        // Children checks\n        List<String> tmpList = getChildNames(doc);\n        Collections.sort(tmpList);\n        assertEquals(level1, tmpList);\n        // Arbitrary Directory level check\n        VirtualDocumentFile ademarDir = doc.findFile(\"ademar\");\n        assertNotNull(ademarDir);\n        VirtualDocumentFile textLauncherDir = ademarDir.findFile(\"textlauncher\");\n        assertNotNull(textLauncherDir);\n        VirtualDocumentFile activitySmali = textLauncherDir.findFile(\"Activity.smali\");\n        assertNotNull(activitySmali);\n        assertTrue(activitySmali.exists());\n        assertTrue(activitySmali.canRead());\n        assertTrue(activitySmali.isFile());\n        assertFalse(activitySmali.isDirectory());\n        assertNotEquals(activitySmali.length(), 0);\n        assertEquals(\"/ademar/textlauncher/Activity.smali\", activitySmali.getFullPath());\n        // Parent check\n        DocumentFile parent = activitySmali.getParentFile();\n        assertNotNull(parent);\n        assertTrue(parent.exists());\n        assertTrue(parent.canRead());\n        assertFalse(parent.isFile());\n        assertTrue(parent.isDirectory());\n        assertEquals(parent.length(), 0);\n        assertEquals(\"/ademar/textlauncher\", ((VirtualDocumentFile) parent).getFullPath());\n        assertEquals(textLauncherDir.getUri(), parent.getUri());\n        VirtualDocumentFile invalidFile = textLauncherDir.findFile(\"Invalid.smali\");\n        assertNull(invalidFile);\n    }\n}"
  },
  {
    "path": "app/src/test/java/androidx/documentfile/provider/ZipDocumentFileTest.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage androidx.documentfile.provider;\n\nimport android.net.Uri;\n\nimport com.j256.simplemagic.ContentType;\n\nimport org.junit.Before;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.robolectric.RobolectricTestRunner;\n\nimport java.io.File;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\nimport java.util.Objects;\n\nimport io.github.muntashirakon.AppManager.backup.convert.OABConverter;\nimport io.github.muntashirakon.io.Paths;\nimport io.github.muntashirakon.io.fs.VirtualFileSystem;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertFalse;\nimport static org.junit.Assert.assertNotEquals;\nimport static org.junit.Assert.assertNotNull;\nimport static org.junit.Assert.assertTrue;\n\n@RunWith(RobolectricTestRunner.class)\npublic class ZipDocumentFileTest {\n    private final ClassLoader classLoader = getClass().getClassLoader();\n    private File apkFile;\n\n    @Before\n    public void setUp() throws Exception {\n        assert classLoader != null;\n        apkFile = new File(new File(classLoader.getResource(OABConverter.PATH_SUFFIX).getFile(), \"ademar.textlauncher\"), \"base.apk\");\n    }\n\n    @Test\n    public void testZipDocument() throws Throwable {\n        List<String> level1 = Arrays.asList(\"AndroidManifest.xml\", \"META-INF\", \"classes.dex\", \"res\", \"resources.arsc\");\n        int fsId = VirtualFileSystem.mount(Uri.fromFile(new File(\"/tmp/zip1\")), Paths.get(apkFile), ContentType.ZIP.getMimeType());\n        VirtualDocumentFile doc = new VirtualDocumentFile(null, Objects.requireNonNull(VirtualFileSystem.getFileSystem(fsId)));\n        assertTrue(doc.isDirectory());\n        assertFalse(doc.isFile());\n        assertTrue(doc.exists());\n        assertEquals(doc.length(), 0);\n        assertEquals(doc.getName(), File.separator);\n        // Children checks\n        List<String> tmpList = getChildNames(doc);\n        Collections.sort(tmpList);\n        assertEquals(level1, tmpList);\n        // Arbitrary Directory level check\n        VirtualDocumentFile resDir = doc.findFile(\"res\");\n        assertNotNull(resDir);\n        VirtualDocumentFile layoutDir = resDir.findFile(\"layout\");\n        assertNotNull(layoutDir);\n        VirtualDocumentFile activityXml = layoutDir.findFile(\"activity.xml\");\n        assertNotNull(activityXml);\n        assertTrue(activityXml.exists());\n        assertTrue(activityXml.canRead());\n        assertTrue(activityXml.isFile());\n        assertFalse(activityXml.isDirectory());\n        assertNotEquals(activityXml.length(), 0);\n        assertEquals(\"/res/layout/activity.xml\", activityXml.getFullPath());\n    }\n\n    public static List<String> getChildNames(DocumentFile doc) {\n        List<String> list = new ArrayList<>();\n        DocumentFile[] files = doc.listFiles();\n        for (DocumentFile file : files) {\n            list.add(file.getName());\n        }\n        return list;\n    }\n}"
  },
  {
    "path": "app/src/test/java/io/github/muntashirakon/AppManager/apk/dexopt/DexOptOptionsTest.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.apk.dexopt;\n\nimport static org.junit.Assert.*;\n\nimport android.os.Parcel;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.robolectric.RobolectricTestRunner;\n\n@RunWith(RobolectricTestRunner.class)\npublic class DexOptOptionsTest {\n    @Test\n    public void testParcelable() {\n        DexOptOptions dexOptOptions = DexOptOptions.getDefault();\n        dexOptOptions.packages = new String[]{\"android.package\"};\n        Parcel parcel = Parcel.obtain();\n        dexOptOptions.writeToParcel(parcel, 0);\n        parcel.setDataPosition(0);\n        DexOptOptions dexOptOptions2 = DexOptOptions.CREATOR.createFromParcel(parcel);\n        assertArrayEquals(dexOptOptions.packages, dexOptOptions2.packages);\n        assertEquals(dexOptOptions.compilerFiler, dexOptOptions2.compilerFiler);\n        assertEquals(dexOptOptions.compileLayouts, dexOptOptions2.compileLayouts);\n        assertEquals(dexOptOptions.clearProfileData, dexOptOptions2.clearProfileData);\n        assertEquals(dexOptOptions.checkProfiles, dexOptOptions2.checkProfiles);\n        assertEquals(dexOptOptions.bootComplete, dexOptOptions2.bootComplete);\n        assertEquals(dexOptOptions.forceCompilation, dexOptOptions2.forceCompilation);\n        assertEquals(dexOptOptions.forceDexOpt, dexOptOptions2.forceDexOpt);\n    }\n}\n"
  },
  {
    "path": "app/src/test/java/io/github/muntashirakon/AppManager/apk/parser/AndroidBinXmlDecoderTest.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.apk.parser;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertFalse;\nimport static org.junit.Assert.assertTrue;\n\nimport org.junit.After;\nimport org.junit.Before;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.robolectric.RobolectricTestRunner;\n\nimport java.io.IOException;\nimport java.nio.ByteBuffer;\nimport java.util.Objects;\n\nimport io.github.muntashirakon.io.Path;\nimport io.github.muntashirakon.io.Paths;\n\n@RunWith(RobolectricTestRunner.class)\npublic class AndroidBinXmlDecoderTest {\n    private final ClassLoader classLoader = Objects.requireNonNull(getClass().getClassLoader());\n    private Path testPath;\n\n    @Before\n    public void setUp() {\n        testPath = Paths.get(\"/tmp/test\");\n        testPath.mkdirs();\n    }\n\n    @After\n    public void tearDown() {\n        testPath.delete();\n    }\n\n    @Test\n    public void testBinary() {\n        Path xmlBinary = Paths.get(classLoader.getResource(\"xml/HMS_Core_Android_Manifest.bin.xml\").getFile());\n        Path xmlPlainManifest = Paths.get(classLoader.getResource(\"xml/HMS_Core_Android_Manifest.man.xml\").getFile());\n        assertTrue(AndroidBinXmlDecoder.isBinaryXml(ByteBuffer.wrap(xmlBinary.getContentAsBinary())));\n        assertFalse(AndroidBinXmlDecoder.isBinaryXml(ByteBuffer.wrap(xmlPlainManifest.getContentAsBinary())));\n    }\n\n    @Test\n    public void testDecodeManifest() throws IOException {\n        Path xmlBinary = Paths.get(classLoader.getResource(\"xml/HMS_Core_Android_Manifest.bin.xml\").getFile());\n        Path xmlPlainManifest = Paths.get(classLoader.getResource(\"xml/HMS_Core_Android_Manifest.man.xml\").getFile());\n        String xml = AndroidBinXmlDecoder.decode(xmlBinary.getContentAsBinary());\n        assertEquals(xmlPlainManifest.getContentAsString(), xml);\n    }\n\n    @Test\n    public void testDecodeLayout() throws IOException {\n        Path xmlBinary = Paths.get(classLoader.getResource(\"xml/test_layout.bin.xml\").getFile());\n        Path xmlPlainManifest = Paths.get(classLoader.getResource(\"xml/test_layout.plain.xml\").getFile());\n        String xml = AndroidBinXmlDecoder.decode(xmlBinary.getContentAsBinary());\n        assertEquals(xmlPlainManifest.getContentAsString(), xml);\n    }\n}"
  },
  {
    "path": "app/src/test/java/io/github/muntashirakon/AppManager/apk/parser/AndroidBinXmlEncoderTest.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.apk.parser;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertTrue;\n\nimport org.junit.After;\nimport org.junit.Before;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.robolectric.RobolectricTestRunner;\n\nimport java.io.IOException;\nimport java.nio.ByteBuffer;\nimport java.util.Objects;\n\nimport io.github.muntashirakon.io.Path;\nimport io.github.muntashirakon.io.Paths;\n\n@RunWith(RobolectricTestRunner.class)\npublic class AndroidBinXmlEncoderTest {\n    private final ClassLoader classLoader = Objects.requireNonNull(getClass().getClassLoader());\n    private Path testPath;\n\n    @Before\n    public void setUp() throws Exception {\n        testPath = Paths.get(\"/tmp/test\");\n        testPath.mkdirs();\n    }\n\n    @After\n    public void tearDown() {\n        testPath.delete();\n    }\n\n    @Test\n    public void testEncodeManifest() throws IOException {\n        Path xmlBinary = Paths.get(classLoader.getResource(\"xml/HMS_Core_Android_Manifest.bin.xml\").getFile());\n        Path xmlPlain = Paths.get(classLoader.getResource(\"xml/HMS_Core_Android_Manifest.man.xml\").getFile());\n        // Encode\n        String xml = xmlPlain.getContentAsString();\n        byte[] bytes = AndroidBinXmlEncoder.encodeString(xml);\n        ByteBuffer byteBuffer = ByteBuffer.wrap(bytes);\n        assertTrue(AndroidBinXmlDecoder.isBinaryXml(byteBuffer));\n        // Decode\n        String actualXml = AndroidBinXmlDecoder.decode(byteBuffer);\n//        byte[] manifestContent = xmlBinary.getContentAsBinary();\n//        assertArrayEquals(manifestContent, bytes);\n        assertEquals(xml, actualXml);\n    }\n\n    @Test\n    public void testEncodeLayout() throws IOException {\n        Path xmlBinary = Paths.get(classLoader.getResource(\"xml/test_layout.bin.xml\").getFile());\n        Path xmlPlain = Paths.get(classLoader.getResource(\"xml/test_layout.plain.xml\").getFile());\n        // Encode\n        String xml = xmlPlain.getContentAsString();\n        byte[] bytes = AndroidBinXmlEncoder.encodeString(xml);\n        ByteBuffer byteBuffer = ByteBuffer.wrap(bytes);\n        assertTrue(AndroidBinXmlDecoder.isBinaryXml(byteBuffer));\n        // Decode\n        String actualXml = AndroidBinXmlDecoder.decode(byteBuffer);\n//        byte[] manifestContent = xmlBinary.getContentAsBinary();\n//        assertArrayEquals(manifestContent, bytes);\n        assertEquals(xml, actualXml);\n    }\n}"
  },
  {
    "path": "app/src/test/java/io/github/muntashirakon/AppManager/apk/parser/ManifestParserTest.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.apk.parser;\n\nimport static org.junit.Assert.assertEquals;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.robolectric.RobolectricTestRunner;\n\nimport java.io.IOException;\nimport java.util.List;\nimport java.util.Objects;\n\nimport io.github.muntashirakon.io.Path;\nimport io.github.muntashirakon.io.Paths;\n\n@RunWith(RobolectricTestRunner.class)\npublic class ManifestParserTest {\n    private final ClassLoader classLoader = Objects.requireNonNull(getClass().getClassLoader());\n\n    @Test\n    public void testManifestIntentFilterParsing() throws IOException {\n        Path xmlBinary = Paths.get(classLoader.getResource(\"xml/HMS_Core_Android_Manifest.bin.xml\").getFile());\n        ManifestParser parser = new ManifestParser(xmlBinary.getContentAsBinary());\n        List<ManifestComponent> manifestComponents = parser.parseComponents();\n        assertEquals(1598, manifestComponents.size());\n        int intentFilterCount = 0;\n        for (ManifestComponent component : manifestComponents) {\n            intentFilterCount += component.intentFilters.size();\n        }\n        assertEquals(156, intentFilterCount);\n    }\n}\n"
  },
  {
    "path": "app/src/test/java/io/github/muntashirakon/AppManager/backup/BackupDataDirectoryInfoTest.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.backup;\n\nimport static org.junit.Assert.*;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.robolectric.RobolectricTestRunner;\n\n@RunWith(RobolectricTestRunner.class)\npublic class BackupDataDirectoryInfoTest {\n    @Test\n    public void getInfoInternal() {\n        BackupDataDirectoryInfo ceInfo1 = BackupDataDirectoryInfo.getInfo(\"/data/data/package.name\", 0);\n        assertEquals(BackupDataDirectoryInfo.TYPE_INTERNAL, ceInfo1.type);\n        assertEquals(BackupDataDirectoryInfo.TYPE_CREDENTIAL_PROTECTED, ceInfo1.subtype);\n        assertTrue(ceInfo1.isMounted);\n        BackupDataDirectoryInfo ceInfo2 = BackupDataDirectoryInfo.getInfo(\"/data/user/0/package.name\", 0);\n        assertEquals(BackupDataDirectoryInfo.TYPE_INTERNAL, ceInfo2.type);\n        assertEquals(BackupDataDirectoryInfo.TYPE_CREDENTIAL_PROTECTED, ceInfo2.subtype);\n        assertTrue(ceInfo2.isMounted);\n        BackupDataDirectoryInfo ceInfo3 = BackupDataDirectoryInfo.getInfo(\"/data/user/10/package.name\", 0);\n        assertEquals(BackupDataDirectoryInfo.TYPE_UNKNOWN, ceInfo3.type);\n        assertEquals(BackupDataDirectoryInfo.TYPE_CUSTOM, ceInfo3.subtype);\n        assertTrue(ceInfo3.isMounted);\n        BackupDataDirectoryInfo deInfo1 = BackupDataDirectoryInfo.getInfo(\"/data/user_de/0/package.name\", 0);\n        assertEquals(BackupDataDirectoryInfo.TYPE_INTERNAL, deInfo1.type);\n        assertEquals(BackupDataDirectoryInfo.TYPE_DEVICE_PROTECTED, deInfo1.subtype);\n        assertTrue(deInfo1.isMounted);\n        BackupDataDirectoryInfo deInfo2 = BackupDataDirectoryInfo.getInfo(\"/data/user_de/10/package.name\", 0);\n        assertEquals(BackupDataDirectoryInfo.TYPE_UNKNOWN, deInfo2.type);\n        assertEquals(BackupDataDirectoryInfo.TYPE_CUSTOM, deInfo2.subtype);\n        assertTrue(deInfo2.isMounted);\n    }\n\n    @Test\n    public void getInfoExternal() {\n        BackupDataDirectoryInfo sdcardAndroidData = BackupDataDirectoryInfo.getInfo(\"/sdcard/Android/data/package.name\", 0);\n        assertEquals(BackupDataDirectoryInfo.TYPE_EXTERNAL, sdcardAndroidData.type);\n        assertEquals(BackupDataDirectoryInfo.TYPE_ANDROID_DATA, sdcardAndroidData.subtype);\n        assertFalse(sdcardAndroidData.isMounted);\n        BackupDataDirectoryInfo sdcardAndroidObb = BackupDataDirectoryInfo.getInfo(\"/sdcard/Android/obb/package.name\", 0);\n        assertEquals(BackupDataDirectoryInfo.TYPE_EXTERNAL, sdcardAndroidObb.type);\n        assertEquals(BackupDataDirectoryInfo.TYPE_ANDROID_OBB, sdcardAndroidObb.subtype);\n        assertFalse(sdcardAndroidObb.isMounted);\n        BackupDataDirectoryInfo sdcardAndroidMedia = BackupDataDirectoryInfo.getInfo(\"/sdcard/Android/media/package.name\", 0);\n        assertEquals(BackupDataDirectoryInfo.TYPE_EXTERNAL, sdcardAndroidMedia.type);\n        assertEquals(BackupDataDirectoryInfo.TYPE_ANDROID_MEDIA, sdcardAndroidMedia.subtype);\n        assertFalse(sdcardAndroidMedia.isMounted);\n        BackupDataDirectoryInfo sdcardCustom = BackupDataDirectoryInfo.getInfo(\"/sdcard/AppManager\", 0);\n        assertEquals(BackupDataDirectoryInfo.TYPE_EXTERNAL, sdcardCustom.type);\n        assertEquals(BackupDataDirectoryInfo.TYPE_CUSTOM, sdcardCustom.subtype);\n        assertFalse(sdcardCustom.isMounted);\n    }\n}"
  },
  {
    "path": "app/src/test/java/io/github/muntashirakon/AppManager/backup/BackupManagerTest.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.backup;\n\nimport static org.junit.Assert.*;\n\nimport org.junit.After;\nimport org.junit.Before;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.robolectric.RobolectricTestRunner;\nimport org.robolectric.annotation.LooperMode;\n\nimport java.io.IOException;\n\nimport io.github.muntashirakon.AppManager.BuildConfig;\nimport io.github.muntashirakon.AppManager.backup.struct.BackupMetadataV5;\nimport io.github.muntashirakon.AppManager.backup.struct.BackupOpOptions;\nimport io.github.muntashirakon.AppManager.backup.struct.DeleteOpOptions;\nimport io.github.muntashirakon.AppManager.backup.struct.RestoreOpOptions;\nimport io.github.muntashirakon.AppManager.batchops.struct.BatchBackupOptions;\nimport io.github.muntashirakon.AppManager.db.utils.AppDb;\nimport io.github.muntashirakon.AppManager.settings.Prefs;\nimport io.github.muntashirakon.AppManager.utils.ContextUtils;\nimport io.github.muntashirakon.AppManager.utils.RoboUtils;\nimport io.github.muntashirakon.io.Path;\nimport io.github.muntashirakon.io.Paths;\n\n@RunWith(RobolectricTestRunner.class)\n@LooperMode(LooperMode.Mode.INSTRUMENTATION_TEST)\npublic class BackupManagerTest {\n    private final ClassLoader classLoader = getClass().getClassLoader();\n    private Path rscBackupPath;\n    private Path tmpBackupPath;\n    private int mDefaultMetaVersion;\n\n    @Before\n    public void setUp() {\n        assert classLoader != null;\n        mDefaultMetaVersion = MetadataManager.getCurrentBackupMetaVersion();\n        rscBackupPath = Paths.get(classLoader.getResource(\"backups/v4\").getFile());\n        tmpBackupPath = Paths.get(RoboUtils.getTestBaseDir());\n    }\n\n    @After\n    public void tearDown() {\n        MetadataManager.setCurrentBackupMetaVersion(mDefaultMetaVersion);\n        for (Path path : tmpBackupPath.listFiles()) {\n            path.delete();\n        }\n    }\n\n    @Test\n    public void testBackupV5Default() throws BackupException, IOException {\n        MetadataManager.setCurrentBackupMetaVersion(5);\n        // First run restore\n        testRestoreV4Default();\n        // Do backup\n        Prefs.Storage.setVolumePath(tmpBackupPath.getUri().toString());\n        BackupManager bm = new BackupManager();\n        BackupOpOptions options = new BackupOpOptions(\"dnsfilter.android\", 0, 1110, null, true);\n        bm.backup(options, null);\n        Path[] backupPaths = Prefs.Storage.getAppManagerDirectory().findFile(BackupItems.BACKUP_DIRECTORY).listFiles();\n        assertEquals(1, backupPaths.length);\n        Path backupPath = backupPaths[0];\n        String backupUuid = backupPath.getName();\n        assertTrue(BackupUtils.isUuid(backupUuid));\n        BackupItems.BackupItem backupItem = BackupItems.findBackupItem(BackupUtils.getV5RelativeDir(backupUuid));\n        assertEquals(1, backupItem.getSourceFiles().length);\n        assertEquals(1, backupItem.getDataFiles(0).length);\n        assertEquals(1, backupItem.getDataFiles(1).length);\n        assertTrue(backupItem.getIconFile().exists());\n        assertTrue(backupItem.isV5AndUp());\n        assertTrue(backupItem.getMetadataV5File(false).exists());\n        assertTrue(backupItem.getInfoFile().exists());\n        BackupMetadataV5 metadata = backupItem.getMetadata();\n        assertNull(metadata.metadata.backupName);\n        assertEquals(0, metadata.info.userId);\n        assertEquals(MetadataManager.getCurrentBackupMetaVersion(), metadata.info.version);\n        assertTrue(metadata.isBaseBackup());\n        assertEquals(\"dnsfilter.android\", metadata.metadata.packageName);\n        assertEquals(2, metadata.metadata.dataDirs.length);\n        assertEquals(BuildConfig.APPLICATION_ID, metadata.metadata.installer);\n        assertFalse(metadata.metadata.isSplitApk);\n        bm.verify(BackupUtils.getV5RelativeDir(backupUuid));\n    }\n\n    @Test\n    public void testBackupV5Custom() throws BackupException, IOException {\n        MetadataManager.setCurrentBackupMetaVersion(5);\n        // First run restore\n        testRestoreV4Default();\n        // Do backup\n        Prefs.Storage.setVolumePath(tmpBackupPath.getUri().toString());\n        BackupManager bm = new BackupManager();\n        BackupOpOptions options = new BackupOpOptions(\"dnsfilter.android\", 0, 1110 | BackupFlags.BACKUP_MULTIPLE, \"test_backup\", false);\n        bm.backup(options, null);\n        Path[] backupPaths = Prefs.Storage.getAppManagerDirectory().findFile(BackupItems.BACKUP_DIRECTORY).listFiles();\n        assertEquals(1, backupPaths.length);\n        Path backupPath = backupPaths[0];\n        String backupUuid = backupPath.getName();\n        assertTrue(BackupUtils.isUuid(backupUuid));\n        BackupItems.BackupItem backupItem = BackupItems.findBackupItem(BackupUtils.getV5RelativeDir(backupUuid));\n        assertEquals(1, backupItem.getSourceFiles().length);\n        assertEquals(1, backupItem.getDataFiles(0).length);\n        assertEquals(1, backupItem.getDataFiles(1).length);\n        assertTrue(backupItem.getIconFile().exists());\n        assertTrue(backupItem.isV5AndUp());\n        assertTrue(backupItem.getMetadataV5File(false).exists());\n        assertTrue(backupItem.getInfoFile().exists());\n        BackupMetadataV5 metadata = backupItem.getMetadata();\n        assertEquals(\"test_backup\", metadata.metadata.backupName);\n        assertEquals(0, metadata.info.userId);\n        assertEquals(MetadataManager.getCurrentBackupMetaVersion(), metadata.info.version);\n        assertFalse(metadata.isBaseBackup());\n        assertEquals(\"dnsfilter.android\", metadata.metadata.packageName);\n        assertEquals(2, metadata.metadata.dataDirs.length);\n        assertEquals(BuildConfig.APPLICATION_ID, metadata.metadata.installer);\n        assertFalse(metadata.metadata.isSplitApk);\n        bm.verify(BackupUtils.getV5RelativeDir(backupUuid));\n    }\n\n    @Test\n    public void testBackupV4Default() throws BackupException, IOException {\n        MetadataManager.setCurrentBackupMetaVersion(4);\n        // First run restore\n        testRestoreV4Default();\n        // Do backup\n        Prefs.Storage.setVolumePath(tmpBackupPath.getUri().toString());\n        BackupManager bm = new BackupManager();\n        BackupOpOptions options = new BackupOpOptions(\"dnsfilter.android\", 0, 1110, null, true);\n        bm.backup(options, null);\n        BackupItems.BackupItem backupItem = BackupItems.findBackupItem(\"dnsfilter.android/0\");\n        assertEquals(1, backupItem.getSourceFiles().length);\n        assertEquals(1, backupItem.getDataFiles(0).length);\n        assertEquals(1, backupItem.getDataFiles(1).length);\n        assertTrue(backupItem.getIconFile().exists());\n        assertFalse(backupItem.isV5AndUp());\n        assertTrue(backupItem.getMetadataV2File().exists());\n        BackupMetadataV5 metadata = backupItem.getMetadata();\n        assertNull(metadata.metadata.backupName);\n        assertEquals(0, metadata.info.userId);\n        assertEquals(MetadataManager.getCurrentBackupMetaVersion(), metadata.info.version);\n        assertTrue(metadata.isBaseBackup());\n        assertEquals(\"dnsfilter.android\", metadata.metadata.packageName);\n        assertEquals(2, metadata.metadata.dataDirs.length);\n        assertEquals(BuildConfig.APPLICATION_ID, metadata.metadata.installer);\n        assertFalse(metadata.metadata.isSplitApk);\n        bm.verify(\"dnsfilter.android/0\");\n    }\n\n\n    @Test\n    public void testBackupV4Custom() throws BackupException, IOException {\n        MetadataManager.setCurrentBackupMetaVersion(4);\n        // First run restore\n        testRestoreV4Default();\n        // Do backup\n        Prefs.Storage.setVolumePath(tmpBackupPath.getUri().toString());\n        BackupManager bm = new BackupManager();\n        BackupOpOptions options = new BackupOpOptions(\"dnsfilter.android\", 0, 1110 | BackupFlags.BACKUP_MULTIPLE, \"test_backup\", false);\n        bm.backup(options, null);\n        BackupItems.BackupItem backupItem = BackupItems.findBackupItem(\"dnsfilter.android/0_test_backup\");\n        assertEquals(1, backupItem.getSourceFiles().length);\n        assertEquals(1, backupItem.getDataFiles(0).length);\n        assertEquals(1, backupItem.getDataFiles(1).length);\n        assertTrue(backupItem.getIconFile().exists());\n        assertFalse(backupItem.isV5AndUp());\n        assertTrue(backupItem.getMetadataV2File().exists());\n        BackupMetadataV5 metadata = backupItem.getMetadata();\n        assertEquals(\"test_backup\", metadata.metadata.backupName);\n        assertEquals(0, metadata.info.userId);\n        assertEquals(MetadataManager.getCurrentBackupMetaVersion(), metadata.info.version);\n        assertFalse(metadata.isBaseBackup());\n        assertEquals(\"dnsfilter.android\", metadata.metadata.packageName);\n        assertEquals(2, metadata.metadata.dataDirs.length);\n        assertEquals(BuildConfig.APPLICATION_ID, metadata.metadata.installer);\n        assertFalse(metadata.metadata.isSplitApk);\n        bm.verify(\"dnsfilter.android/0_test_backup\");\n    }\n\n    @Test\n    public void testRestoreV4Default() throws BackupException {\n        Prefs.Storage.setVolumePath(rscBackupPath.getUri().toString());\n        new AppDb().loadInstalledOrBackedUpApplications(ContextUtils.getContext());\n        BackupManager bm = new BackupManager();\n        RestoreOpOptions options = new RestoreOpOptions(\"dnsfilter.android\", 0, null, 1110);\n        bm.restore(options, null);\n    }\n\n    @Test\n    public void testRestoreV4DefaultBatchOps() throws BackupException {\n        Prefs.Storage.setVolumePath(rscBackupPath.getUri().toString());\n        new AppDb().loadInstalledOrBackedUpApplications(ContextUtils.getContext());\n        BackupManager bm = new BackupManager();\n        BatchBackupOptions options = new BatchBackupOptions(1110, null, null);\n        bm.restore(options.getRestoreOpOptions(\"dnsfilter.android\", 0), null);\n    }\n\n    @Test\n    public void testRestoreV4DefaultAsCustom() throws BackupException {\n        Prefs.Storage.setVolumePath(rscBackupPath.getUri().toString());\n        BackupManager bm = new BackupManager();\n        RestoreOpOptions options = new RestoreOpOptions(\"dnsfilter.android\", 0, \"dnsfilter.android/0\", 1110);\n        bm.restore(options, null);\n    }\n\n    @Test\n    public void testRestoreV4DefaultAsRelativeDirBatchOps() throws BackupException {\n        Prefs.Storage.setVolumePath(rscBackupPath.getUri().toString());\n        new AppDb().loadInstalledOrBackedUpApplications(ContextUtils.getContext());\n        BackupManager bm = new BackupManager();\n        BatchBackupOptions options = new BatchBackupOptions(1110, null, new String[]{\"dnsfilter.android/0\"});\n        bm.restore(options.getRestoreOpOptions(\"dnsfilter.android\", 0), null);\n    }\n\n    @Test\n    public void testRestoreV4Custom() throws BackupException {\n        Prefs.Storage.setVolumePath(rscBackupPath.getUri().toString());\n        BackupManager bm = new BackupManager();\n        RestoreOpOptions options = new RestoreOpOptions(\"dnsfilter.android\", 0, \"dnsfilter.android/0_test\", 1110);\n        bm.restore(options, null);\n    }\n\n    @Test\n    public void testRestoreV4CustomAsBackupNameBatchOps() throws BackupException {\n        Prefs.Storage.setVolumePath(rscBackupPath.getUri().toString());\n        new AppDb().loadInstalledOrBackedUpApplications(ContextUtils.getContext());\n        BackupManager bm = new BackupManager();\n        BatchBackupOptions options = new BatchBackupOptions(1110, new String[]{\"test\"}, null);\n        bm.restore(options.getRestoreOpOptions(\"dnsfilter.android\", 0), null);\n    }\n\n    @Test\n    public void testRestoreV4CustomAsRelativeDirBatchOps() throws BackupException {\n        Prefs.Storage.setVolumePath(rscBackupPath.getUri().toString());\n        new AppDb().loadInstalledOrBackedUpApplications(ContextUtils.getContext());\n        BackupManager bm = new BackupManager();\n        BatchBackupOptions options = new BatchBackupOptions(1110, null, new String[]{\"dnsfilter.android/0_test\"});\n        bm.restore(options.getRestoreOpOptions(\"dnsfilter.android\", 0), null);\n    }\n\n    @Test\n    public void testDeleteV4Default() throws IOException, BackupException {\n        Prefs.Storage.setVolumePath(tmpBackupPath.getUri().toString());\n        assertNotNull(rscBackupPath.findFile(\"AppManager\")\n                .copyTo(tmpBackupPath, true));\n        Path amDir = tmpBackupPath.findFile(\"AppManager\");\n        assertTrue(amDir.exists());\n        new AppDb().loadInstalledOrBackedUpApplications(ContextUtils.getContext());\n        BackupManager bm = new BackupManager();\n        DeleteOpOptions options = new DeleteOpOptions(\"dnsfilter.android\", 0, null);\n        bm.deleteBackup(options);\n        assertTrue(amDir.exists());\n        Path appBackupPath = amDir.findFile(\"dnsfilter.android\");\n        appBackupPath.findFile(\"0_test\");\n    }\n\n    @Test\n    public void testDeleteV4DefaultBatchOps() throws IOException, BackupException {\n        Prefs.Storage.setVolumePath(tmpBackupPath.getUri().toString());\n        assertNotNull(rscBackupPath.findFile(\"AppManager\")\n                .copyTo(tmpBackupPath, true));\n        Path amDir = tmpBackupPath.findFile(\"AppManager\");\n        assertTrue(amDir.exists());\n        new AppDb().loadInstalledOrBackedUpApplications(ContextUtils.getContext());\n        BackupManager bm = new BackupManager();\n        BatchBackupOptions options = new BatchBackupOptions(1110, null, null);\n        bm.deleteBackup(options.getDeleteOpOptions(\"dnsfilter.android\", 0));\n        assertTrue(amDir.exists());\n        Path appBackupPath = amDir.findFile(\"dnsfilter.android\");\n        appBackupPath.findFile(\"0_test\");\n    }\n\n    @Test\n    public void testDeleteV4DefaultAsCustom() throws IOException, BackupException {\n        Prefs.Storage.setVolumePath(tmpBackupPath.getUri().toString());\n        assertNotNull(rscBackupPath.findFile(\"AppManager\")\n                .copyTo(tmpBackupPath, true));\n        Path amDir = tmpBackupPath.findFile(\"AppManager\");\n        assertTrue(amDir.exists());\n        BackupManager bm = new BackupManager();\n        DeleteOpOptions options = new DeleteOpOptions(\"dnsfilter.android\", 0, new String[]{\"dnsfilter.android/0\"});\n        bm.deleteBackup(options);\n        assertTrue(amDir.exists());\n        Path appBackupPath = amDir.findFile(\"dnsfilter.android\");\n        appBackupPath.findFile(\"0_test\");\n    }\n\n    @Test\n    public void testDeleteV4DefaultRelativeDirBatchOps() throws IOException, BackupException {\n        Prefs.Storage.setVolumePath(tmpBackupPath.getUri().toString());\n        assertNotNull(rscBackupPath.findFile(\"AppManager\")\n                .copyTo(tmpBackupPath, true));\n        Path amDir = tmpBackupPath.findFile(\"AppManager\");\n        assertTrue(amDir.exists());\n        new AppDb().loadInstalledOrBackedUpApplications(ContextUtils.getContext());\n        BackupManager bm = new BackupManager();\n        BatchBackupOptions options = new BatchBackupOptions(1110, null, new String[]{\"dnsfilter.android/0\"});\n        bm.deleteBackup(options.getDeleteOpOptions(\"dnsfilter.android\", 0));\n        assertTrue(amDir.exists());\n        Path appBackupPath = amDir.findFile(\"dnsfilter.android\");\n        appBackupPath.findFile(\"0_test\");\n    }\n\n    @Test\n    public void testDeleteV4Custom() throws IOException, BackupException {\n        Prefs.Storage.setVolumePath(tmpBackupPath.getUri().toString());\n        assertNotNull(rscBackupPath.findFile(\"AppManager\")\n                .copyTo(tmpBackupPath, true));\n        Path amDir = tmpBackupPath.findFile(\"AppManager\");\n        assertTrue(amDir.exists());\n        BackupManager bm = new BackupManager();\n        DeleteOpOptions options = new DeleteOpOptions(\"dnsfilter.android\", 0, new String[]{\"dnsfilter.android/0_test\"});\n        bm.deleteBackup(options);\n        assertTrue(amDir.exists());\n        Path appBackupPath = amDir.findFile(\"dnsfilter.android\");\n        appBackupPath.findFile(\"0\");\n    }\n\n    @Test\n    public void testDeleteV4CustomRelativeDirBatchOps() throws IOException, BackupException {\n        Prefs.Storage.setVolumePath(tmpBackupPath.getUri().toString());\n        assertNotNull(rscBackupPath.findFile(\"AppManager\")\n                .copyTo(tmpBackupPath, true));\n        Path amDir = tmpBackupPath.findFile(\"AppManager\");\n        assertTrue(amDir.exists());\n        new AppDb().loadInstalledOrBackedUpApplications(ContextUtils.getContext());\n        BackupManager bm = new BackupManager();\n        BatchBackupOptions options = new BatchBackupOptions(1110, null, new String[]{\"dnsfilter.android/0_test\"});\n        bm.deleteBackup(options.getDeleteOpOptions(\"dnsfilter.android\", 0));\n        assertTrue(amDir.exists());\n        Path appBackupPath = amDir.findFile(\"dnsfilter.android\");\n        appBackupPath.findFile(\"0\");\n    }\n\n    @Test\n    public void testDeleteV4CustomBackupNameBatchOps() throws IOException, BackupException {\n        Prefs.Storage.setVolumePath(tmpBackupPath.getUri().toString());\n        assertNotNull(rscBackupPath.findFile(\"AppManager\")\n                .copyTo(tmpBackupPath, true));\n        Path amDir = tmpBackupPath.findFile(\"AppManager\");\n        assertTrue(amDir.exists());\n        new AppDb().loadInstalledOrBackedUpApplications(ContextUtils.getContext());\n        BackupManager bm = new BackupManager();\n        BatchBackupOptions options = new BatchBackupOptions(1110, new String[]{\"test\"}, null);\n        bm.deleteBackup(options.getDeleteOpOptions(\"dnsfilter.android\", 0));\n        assertTrue(amDir.exists());\n        Path appBackupPath = amDir.findFile(\"dnsfilter.android\");\n        appBackupPath.findFile(\"0\");\n    }\n\n    @Test\n    public void testDeleteV4DefaultAndCustom() throws IOException, BackupException {\n        Prefs.Storage.setVolumePath(tmpBackupPath.getUri().toString());\n        assertNotNull(rscBackupPath.findFile(\"AppManager\")\n                .copyTo(tmpBackupPath, true));\n        Path amDir = tmpBackupPath.findFile(\"AppManager\");\n        assertTrue(amDir.exists());\n        BackupManager bm = new BackupManager();\n        DeleteOpOptions options = new DeleteOpOptions(\"dnsfilter.android\", 0, new String[]{\"dnsfilter.android/0\", \"dnsfilter.android/0_test\"});\n        bm.deleteBackup(options);\n        assertTrue(amDir.exists());\n        assertFalse(amDir.hasFile(\"dnsfilter.android\"));\n    }\n\n    @Test\n    public void testDeleteV4DefaultAndCustomRelativeDirsBatchOps() throws IOException, BackupException {\n        Prefs.Storage.setVolumePath(tmpBackupPath.getUri().toString());\n        assertNotNull(rscBackupPath.findFile(\"AppManager\")\n                .copyTo(tmpBackupPath, true));\n        Path amDir = tmpBackupPath.findFile(\"AppManager\");\n        assertTrue(amDir.exists());\n        new AppDb().loadInstalledOrBackedUpApplications(ContextUtils.getContext());\n        BackupManager bm = new BackupManager();\n        BatchBackupOptions options = new BatchBackupOptions(1110, null, new String[]{\"dnsfilter.android/0\", \"dnsfilter.android/0_test\"});\n        bm.deleteBackup(options.getDeleteOpOptions(\"dnsfilter.android\", 0));\n        assertTrue(amDir.exists());\n        assertFalse(amDir.hasFile(\"dnsfilter.android\"));\n    }\n\n    @Test\n    public void testDeleteV4DefaultAndCustomBackupNamesBatchOps() throws IOException, BackupException {\n        Prefs.Storage.setVolumePath(tmpBackupPath.getUri().toString());\n        assertNotNull(rscBackupPath.findFile(\"AppManager\")\n                .copyTo(tmpBackupPath, true));\n        Path amDir = tmpBackupPath.findFile(\"AppManager\");\n        assertTrue(amDir.exists());\n        new AppDb().loadInstalledOrBackedUpApplications(ContextUtils.getContext());\n        BackupManager bm = new BackupManager();\n        BatchBackupOptions options = new BatchBackupOptions(1110, new String[]{null, \"test\"}, null);\n        bm.deleteBackup(options.getDeleteOpOptions(\"dnsfilter.android\", 0));\n        assertTrue(amDir.exists());\n        assertFalse(amDir.hasFile(\"dnsfilter.android\"));\n    }\n\n    @Test\n    public void testVerifyV4Default() throws BackupException {\n        Prefs.Storage.setVolumePath(rscBackupPath.getUri().toString());\n        BackupManager bm = new BackupManager();\n        bm.verify(\"dnsfilter.android/0\");\n    }\n\n    @Test\n    public void testVerifyV4DefaultAsCustom() throws BackupException {\n        Prefs.Storage.setVolumePath(rscBackupPath.getUri().toString());\n        BackupManager bm = new BackupManager();\n        bm.verify(\"dnsfilter.android/0\");\n    }\n\n    @Test\n    public void testVerifyV4Custom() throws BackupException {\n        Prefs.Storage.setVolumePath(rscBackupPath.getUri().toString());\n        BackupManager bm = new BackupManager();\n        bm.verify(\"dnsfilter.android/0_test\");\n    }\n}"
  },
  {
    "path": "app/src/test/java/io/github/muntashirakon/AppManager/backup/BackupUtilsTest.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.backup;\n\nimport static org.junit.Assert.*;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.robolectric.RobolectricTestRunner;\n\n@RunWith(RobolectricTestRunner.class)\npublic class BackupUtilsTest {\n\n    @Test\n    public void getWritableDataDirectory() {\n        assertEquals(\"/data/user/10/com.example.package\", BackupUtils.getWritableDataDirectory(\"/data/data/com.example.package\", 0, 10));\n        assertEquals(\"/data/user/10/com.example.package\", BackupUtils.getWritableDataDirectory(\"/data/user/0/com.example.package\", 0, 10));\n        assertEquals(\"/data/user/10/com.example.package\", BackupUtils.getWritableDataDirectory(\"/data/user/10/com.example.package\", 0, 10));\n        assertEquals(\"/data/user_de/10/com.example.package\", BackupUtils.getWritableDataDirectory(\"/data/user_de/0/com.example.package\", 0, 10));\n        assertEquals(\"/data/user_de/10/com.example.package\", BackupUtils.getWritableDataDirectory(\"/data/user_de/10/com.example.package\", 0, 10));\n        // Single user\n        assertEquals(\"/sdcard/Android/data/com.example.package\", BackupUtils.getWritableDataDirectory(\"/sdcard/Android/data/com.example.package\", 0, 10));\n        assertEquals(\"/sdcard/Android/data/com.example.package\", BackupUtils.getWritableDataDirectory(\"/storage/sdcard/Android/data/com.example.package\", 0, 10));\n        assertEquals(\"/sdcard/Android/data/com.example.package\", BackupUtils.getWritableDataDirectory(\"/storage/sdcard0/Android/data/com.example.package\", 0, 10));\n        assertEquals(\"/sdcard/Android/data/com.example.package\", BackupUtils.getWritableDataDirectory(\"/storage/emulated/0/Android/data/com.example.package\", 0, 10));\n        assertEquals(\"/sdcard/Android/data/com.example.package\", BackupUtils.getWritableDataDirectory(\"/data/media/0/Android/data/com.example.package\", 0, 10));\n        // Multiple user todo\n//        assertEquals(\"/data/media/10/Android/data/com.example.package\", BackupUtils.getWritableDataDirectory(\"/sdcard/Android/data/com.example.package\", 0, 10));\n//        assertEquals(\"/data/media/10/Android/data/com.example.package\", BackupUtils.getWritableDataDirectory(\"/storage/sdcard/Android/data/com.example.package\", 0, 10));\n//        assertEquals(\"/data/media/10/Android/data/com.example.package\", BackupUtils.getWritableDataDirectory(\"/storage/sdcard0/Android/data/com.example.package\", 0, 10));\n//        assertEquals(\"/data/media/10/Android/data/com.example.package\", BackupUtils.getWritableDataDirectory(\"/storage/emulated/0/Android/data/com.example.package\", 0, 10));\n//        assertEquals(\"/data/media/10/Android/data/com.example.package\", BackupUtils.getWritableDataDirectory(\"/data/media/0/Android/data/com.example.package\", 0, 10));\n    }\n}\n"
  },
  {
    "path": "app/src/test/java/io/github/muntashirakon/AppManager/backup/adb/AndroidBackupCreatorTest.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.backup.adb;\n\nimport static org.junit.Assert.*;\n\nimport android.content.pm.PackageInfo;\nimport android.content.pm.PackageManager;\nimport android.content.pm.Signature;\n\nimport org.junit.After;\nimport org.junit.Before;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.robolectric.RobolectricTestRunner;\nimport org.robolectric.RuntimeEnvironment;\n\nimport java.io.IOException;\nimport java.util.Collections;\nimport java.util.HashMap;\nimport java.util.List;\nimport java.util.Map;\nimport java.util.Objects;\n\nimport io.github.muntashirakon.AppManager.utils.DigestUtils;\nimport io.github.muntashirakon.AppManager.utils.RoboUtils;\nimport io.github.muntashirakon.AppManager.utils.TarUtils;\nimport io.github.muntashirakon.AppManager.utils.TarUtilsTest;\nimport io.github.muntashirakon.io.Path;\nimport io.github.muntashirakon.io.Paths;\n\n@RunWith(RobolectricTestRunner.class)\npublic class AndroidBackupCreatorTest {\n    private final ClassLoader classLoader = getClass().getClassLoader();\n    private Path testDir;\n    private Path tarPath;\n\n    @Before\n    public void setUp() throws Exception {\n        assert classLoader != null;\n        testDir = Paths.get(RoboUtils.getTestBaseDir()).createNewDirectory(\"test-dir\");\n        tarPath = Paths.get(classLoader.getResource(\"backups/adb/all_data.tar\").getFile());\n    }\n\n    @After\n    public void tearDown() throws Exception {\n        testDir.delete();\n    }\n\n    @Test\n    public void testTarToAb() throws IOException {\n        Path tmpAbPath = testDir.createNewFile(\"output.ab\", null);\n        Path tmpTarPath = testDir.createNewFile(\"output.tar\", null);\n        AndroidBackupCreator.fromTar(tarPath, tmpAbPath, null, 36, true);\n        AndroidBackupExtractor.toTar(tmpAbPath, tmpTarPath, null);\n        // We cannot compare AB files directly because fromTar method directly processes the tar\n        //  file which cause a slight mismatch in the footer section of the file.\n        assertEquals(DigestUtils.getHexDigest(DigestUtils.SHA_256, tarPath),\n                DigestUtils.getHexDigest(DigestUtils.SHA_256, tmpTarPath));\n    }\n\n    @Test\n    public void testAmToAdbBackup() throws IOException {\n        assert classLoader != null;\n        Path sourceFile = Paths.get(classLoader.getResource(\"backups/adb/source.tar.gz.0\").getFile());\n        Map<Integer, List<Path>> categoryFilesMap = new HashMap<Integer, List<Path>>() {{\n            put(BackupCategories.CAT_SRC, Collections.singletonList(sourceFile));\n            put(BackupCategories.CAT_INT_CE, Collections.singletonList(Paths.get(classLoader.getResource(\"backups/adb/data0.tar.gz.0\").getFile())));\n            put(BackupCategories.CAT_INT_DE, Collections.singletonList(Paths.get(classLoader.getResource(\"backups/adb/data1.tar.gz.0\").getFile())));\n            put(BackupCategories.CAT_EXT, Collections.singletonList(Paths.get(classLoader.getResource(\"backups/adb/data2.tar.gz.0\").getFile())));\n        }};\n        TarUtils.extract(TarUtils.TAR_GZIP, new Path[]{sourceFile}, testDir, null, null, null);\n        Path baseApk = testDir.findFile(\"base.apk\");\n        PackageManager packageManager = RuntimeEnvironment.getApplication().getPackageManager();\n        PackageInfo packageInfo = packageManager.getPackageArchiveInfo(Objects.requireNonNull(baseApk.getFilePath()), 0);\n        assert packageInfo != null;\n        // Robolectric does not yet support generating signatures\n        packageInfo.signatures = new Signature[]{new Signature(\"308202e4308201cc020101300d06092a864886f70d01010b050030373116301406035504030c0d416e64726f69642044656275673110300e060355040a0c07416e64726f6964310b30090603550406130255533020170d3235303931383032353031335a180f32303535303931313032353031335a30373116301406035504030c0d416e64726f69642044656275673110300e060355040a0c07416e64726f6964310b300906035504061302555330820122300d06092a864886f70d01010105000382010f003082010a0282010100c189f17de4aa0e706c5710e49a990cc5ef6231988372500ded8e67ee817e928301adee36cbf815467ac75f3918a1dd8ecf33f3cede61cb7bc00852407fc0b8c90a5372226923cc930d19146e9f76129d3add81b63c986e73f05a1f5522017e655b3291fb7a1f7e0f28e7d019d57301629c34ac0d3f801fdea639766900fec630e5be6c703ec8d59e6273daf3c88b7f1f506eb334a51578587978791a5e7899f7b3c5825a706b85f6c64eebdb9dc5c556f2759db5f4efe0bdc95f6eb6ae05f783919eba91e9aaa8978288b775414f4e4dbc0cd4b1db6bc459978938f34f5b31866e36cc2ac9c14441f83f61c27b2af23f2814b99bf14d3efa6388c18262e398790203010001300d06092a864886f70d01010b050003820101008fc815e3fd2df80b52678fda6baa994f7160f677bbede6d51e3d5f7ce0babc7db2941d4b3be9af4a2b2d39cfce90776cb74d79cbc00a8fa6ca443e746074351ec2a64e7b14a59f6560dfa3de4276c1e28ab16a567f9b970ee0a1810cffa5bb4dd5b6c9475edd0eb4449433af476e75604cc7c3114536288f036e6d0265e5f59edd6d20ee4da55b6706b006d2e822cee940b21caa7d90142d171a217b02ad15b57714ffbbdb61022def6b96d0cf9f04a85d47954ee804b7e1cb8e59922c456fed040fe620aa86b9e542d3cdfa073539582818080b17133e895ad2947c4f9290c7826a91bea226be5660ef33b41e27682994bb7e5111524cd9747637f9cea238f1\")};\n        try(AndroidBackupCreator creator = new AndroidBackupCreator(categoryFilesMap, testDir, packageInfo, null, TarUtils.TAR_GZIP)) {\n            Path newAbFile = creator.getBackupFile(0);\n            Path tmpTarPath = testDir.createNewFile(\"output.tar\", null);\n            AndroidBackupExtractor.toTar(newAbFile, tmpTarPath, null);\n            // We cannot do a direct tar hash matching because the alignment of files is incorrect\n            List<String> expected = TarUtilsTest.getFileNamesNoCompress(Collections.singletonList(tarPath));\n            List<String> actual = TarUtilsTest.getFileNamesNoCompress(Collections.singletonList(tmpTarPath));\n            Collections.sort(expected);\n            Collections.sort(actual);\n            assertEquals(expected, actual);\n            assertEquals(tarPath.length(), tmpTarPath.length());\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/test/java/io/github/muntashirakon/AppManager/backup/adb/AndroidBackupExtractorTest.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.backup.adb;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertNotNull;\nimport static org.junit.Assert.assertNull;\nimport static org.junit.Assert.assertThrows;\n\nimport org.junit.After;\nimport org.junit.Before;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.robolectric.RobolectricTestRunner;\n\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\n\nimport io.github.muntashirakon.AppManager.utils.DigestUtils;\nimport io.github.muntashirakon.AppManager.utils.RoboUtils;\nimport io.github.muntashirakon.AppManager.utils.TarUtils;\nimport io.github.muntashirakon.AppManager.utils.TarUtilsTest;\nimport io.github.muntashirakon.io.Path;\nimport io.github.muntashirakon.io.Paths;\n\n@RunWith(RobolectricTestRunner.class)\npublic class AndroidBackupExtractorTest {\n    private final ClassLoader classLoader = getClass().getClassLoader();\n    private Path testDir;\n    private Path abPath;\n    private Path tarPath;\n\n    @Before\n    public void setUp() throws Exception {\n        assert classLoader != null;\n        testDir = Paths.get(RoboUtils.getTestBaseDir()).createNewDirectory(\"test-dir\");\n        abPath = Paths.get(classLoader.getResource(\"backups/adb/all_data.ab\").getFile());\n        tarPath = Paths.get(classLoader.getResource(\"backups/adb/all_data.tar\").getFile());\n    }\n\n    @After\n    public void tearDown() throws Exception {\n        testDir.delete();\n    }\n\n    @Test\n    public void testAbToTar() throws IOException {\n        Path tmpTarPath = testDir.createNewFile(\"output.tar\", null);\n        AndroidBackupExtractor.toTar(abPath, tmpTarPath, null);\n        assertEquals(DigestUtils.getHexDigest(DigestUtils.SHA_256, tarPath),\n                DigestUtils.getHexDigest(DigestUtils.SHA_256, tmpTarPath));\n    }\n\n    @Test\n    public void testAbToAmBackup() throws IOException {\n        List<String> internalFiles = new ArrayList<String>() {{\n            add(\"root_data.txt\");\n            add(\"files/internal_data.txt\");\n            add(\"databases/mixed_test_db-journal\");\n            add(\"databases/mixed_test_db\");\n            add(\"shared_prefs/mixed_prefs.xml\");\n        }};\n        List<String> externalFiles = new ArrayList<String>() {{\n            add(\"Images/\");\n            add(\"Images/test_image.txt\");\n            add(\"Documents/\");\n            add(\"Documents/document.txt\");\n            add(\"external_data.txt\");\n        }};\n        try (AndroidBackupExtractor extractor = new AndroidBackupExtractor(abPath, testDir,\n                \"io.github.muntashirakon.androidbackuptestapps.all_data\")) {\n            // CAT_SRC\n            Path[] sourceFiles = extractor.getSourceFiles(\".tar.gz\", TarUtils.TAR_GZIP);\n            assertNotNull(sourceFiles);\n            assertEquals(Collections.singletonList(\"base.apk\"), TarUtilsTest.getFileNamesGZip(Arrays.asList(sourceFiles)));\n            sourceFiles[0].copyTo(Paths.get(\"/tmp\"));\n            // CAT_INT_CE\n            Path[] intCeFiles = extractor.getInternalCeDataFiles(0, \".tar.gz\", TarUtils.TAR_GZIP);\n            assertNotNull(intCeFiles);\n            assertEquals(internalFiles, TarUtilsTest.getFileNamesGZip(Arrays.asList(intCeFiles)));\n            intCeFiles[0].copyTo(Paths.get(\"/tmp\"));\n            // CAT_INT_DE\n            Path[] intDeFiles = extractor.getInternalDeDataFiles(1, \".tar.gz\", TarUtils.TAR_GZIP);\n            assertNotNull(intDeFiles);\n            assertEquals(internalFiles, TarUtilsTest.getFileNamesGZip(Arrays.asList(intDeFiles)));\n            intDeFiles[0].copyTo(Paths.get(\"/tmp\"));\n            // CAT_EXT\n            Path[] extFiles = extractor.getExternalDataFiles(2, \".tar.gz\", TarUtils.TAR_GZIP);\n            assertNotNull(extFiles);\n            assertEquals(externalFiles, TarUtilsTest.getFileNamesGZip(Arrays.asList(extFiles)));\n            extFiles[0].copyTo(Paths.get(\"/tmp\"));\n            // CAT_OBB\n            assertNull(extractor.getObbFiles(3, \".tar.gz\", TarUtils.TAR_GZIP));\n        }\n    }\n\n    @Test\n    public void testKeyValue() {\n        assertThrows(\"Unknown/unsupported entries detected.\", IOException.class, () -> {\n            assert classLoader != null;\n            Path abPath = Paths.get(classLoader.getResource(\"backups/adb/key_value.ab\").getFile());\n            try (AndroidBackupExtractor ignored = new AndroidBackupExtractor(abPath, testDir,\n                    \"io.github.muntashirakon.androidbackuptestapps.key_value\")) {\n            }\n        });\n    }\n}\n"
  },
  {
    "path": "app/src/test/java/io/github/muntashirakon/AppManager/backup/convert/OABConverterTest.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.backup.convert;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertFalse;\n\nimport org.junit.After;\nimport org.junit.Before;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.robolectric.RobolectricTestRunner;\n\nimport java.io.IOException;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\n\nimport io.github.muntashirakon.AppManager.backup.BackupException;\nimport io.github.muntashirakon.AppManager.backup.BackupItems;\nimport io.github.muntashirakon.AppManager.backup.BackupUtils;\nimport io.github.muntashirakon.AppManager.backup.MetadataManager;\nimport io.github.muntashirakon.AppManager.backup.struct.BackupMetadataV5;\nimport io.github.muntashirakon.AppManager.settings.Prefs;\nimport io.github.muntashirakon.AppManager.utils.RoboUtils;\nimport io.github.muntashirakon.AppManager.utils.TarUtilsTest;\nimport io.github.muntashirakon.io.Path;\nimport io.github.muntashirakon.io.Paths;\n\n@RunWith(RobolectricTestRunner.class)\npublic class OABConverterTest {\n    private static final String PACKAGE_NAME_FULL = \"dnsfilter.android\";\n    private static final String PACKAGE_NAME_APK_INT = \"org.billthefarmer.editor\";\n    private static final String PACKAGE_NAME_INT = \"ca.cmetcalfe.locationshare\";\n    private static final String PACKAGE_NAME_APK = \"ademar.textlauncher\";\n    private final ClassLoader classLoader = getClass().getClassLoader();\n    private Path tmpBackupPath;\n\n    @Before\n    public void setUp() throws IOException {\n        tmpBackupPath = Paths.get(RoboUtils.getTestBaseDir()).createNewDirectory(\"backup-dir\");\n        Prefs.Storage.setVolumePath(tmpBackupPath.toString());\n    }\n\n    @After\n    public void tearDown() {\n        tmpBackupPath.delete();\n    }\n\n    @Test\n    public void convertFullTest() throws BackupException, IOException {\n        final List<String> internalStorage = Collections.emptyList();\n        final List<String> externalStorage = Arrays.asList(\"files/PersonalDNSFilter/dnsfilter.conf\",\n                \"files/PersonalDNSFilter/additionalHosts.txt\",\n                \"files/PersonalDNSFilter/VERSION.TXT\",\n                \"files/PersonalDNSFilter/log/trafficlog/trafficlog_0.log\",\n                \"files/PersonalDNSFilter/dnsperf.info\",\n                \"files/PersonalDNSFilter/FILTERHOSTS.TXT.idx/IDX_VERSION\",\n                \"files/PersonalDNSFilter/FILTERHOSTS.TXT.idx/idx0\",\n                \"files/PersonalDNSFilter/FILTERHOSTS.TXT.idx/idx1\",\n                \"files/PersonalDNSFilter/FILTERHOSTS.TXT.idx/idx2\",\n                \"files/PersonalDNSFilter/FILTERHOSTS.TXT.idx/idx3\",\n                \"files/PersonalDNSFilter/FILTERHOSTS.TXT.idx/idx4\",\n                \"files/PersonalDNSFilter/FILTERHOSTS.TXT.idx/idx5\",\n                \"files/PersonalDNSFilter/FILTERHOSTS.TXT.idx/idx6\",\n                \"files/PersonalDNSFilter/FILTERHOSTS.TXT.idx/idx7\",\n                \"files/PersonalDNSFilter/FILTERHOSTS.TXT.idx/idx8\",\n                \"files/PersonalDNSFilter/FILTERHOSTS.TXT.idx/idx9\",\n                \"files/PersonalDNSFilter/FILTERHOSTS.TXT.idx/idx10\",\n                \"files/PersonalDNSFilter/FILTERHOSTS.TXT.idx/idx11\",\n                \"files/PersonalDNSFilter/FILTERHOSTS.TXT.idx/idx12\",\n                \"files/PersonalDNSFilter/FILTERHOSTS.TXT.idx/idx13\",\n                \"files/PersonalDNSFilter/FILTERHOSTS.TXT.idx/idx14\",\n                \"files/PersonalDNSFilter/FILTERHOSTS.TXT\",\n                \"files/PersonalDNSFilter/FILTERHOSTS.TXT.DLD_CNT\");\n        Collections.sort(internalStorage);\n        Collections.sort(externalStorage);\n        assert classLoader != null;\n        Path backupLocation = Paths.get(classLoader.getResource(OABConverter.PATH_SUFFIX).getFile())\n                .findFile(PACKAGE_NAME_FULL);\n        OABConverter oabConvert = new OABConverter(backupLocation);\n        oabConvert.convert();\n        Path newBackupLocation = Prefs.Storage.getAppManagerDirectory()\n                .findFile(BackupItems.BACKUP_DIRECTORY)\n                .listFiles()[0];\n        BackupItems.BackupItem backupItem = BackupItems.findBackupItem(BackupUtils.getV5RelativeDir(newBackupLocation.getName()));\n        // Verify source\n        BackupMetadataV5 metadataV5 = backupItem.getMetadata();\n        assertEquals(MetadataManager.getCurrentBackupMetaVersion(), metadataV5.info.version);\n        assertEquals(\"OAndBackup\", metadataV5.metadata.backupName);\n        assertEquals(Collections.singletonList(\"base.apk\"), TarUtilsTest.getFileNamesGZip(\n                Arrays.asList(backupItem.getSourceFiles())));\n        List<String> files = TarUtilsTest.getFileNamesGZip(Arrays.asList(backupItem.getDataFiles(0)));\n        Collections.sort(files);\n        assertEquals(internalStorage, files);\n        files = TarUtilsTest.getFileNamesGZip(Arrays.asList(backupItem.getDataFiles(1)));\n        Collections.sort(files);\n        assertEquals(externalStorage, files);\n    }\n\n    @Test\n    public void convertApkInternalStorageTest() throws BackupException, IOException {\n        final List<String> internalStorage = Collections.singletonList(\"shared_prefs/org.billthefarmer.editor_preferences.xml\");\n        assert classLoader != null;\n        Path backupLocation = Paths.get(classLoader.getResource(OABConverter.PATH_SUFFIX).getFile())\n                .findFile(PACKAGE_NAME_APK_INT);\n        OABConverter oabConvert = new OABConverter(backupLocation);\n        oabConvert.convert();\n        Path newBackupLocation = Prefs.Storage.getAppManagerDirectory()\n                .findFile(BackupItems.BACKUP_DIRECTORY)\n                .listFiles()[0];\n        BackupItems.BackupItem backupItem = BackupItems.findBackupItem(BackupUtils.getV5RelativeDir(newBackupLocation.getName()));\n        // Verify source\n        BackupMetadataV5 metadataV5 = backupItem.getMetadata();\n        assertEquals(MetadataManager.getCurrentBackupMetaVersion(), metadataV5.info.version);\n        assertEquals(\"OAndBackup\", metadataV5.metadata.backupName);\n        assertEquals(Collections.singletonList(\"base.apk\"), TarUtilsTest.getFileNamesGZip(\n                Arrays.asList(backupItem.getSourceFiles())));\n        List<String> files = TarUtilsTest.getFileNamesGZip(Arrays.asList(backupItem.getDataFiles(0)));\n        assertEquals(internalStorage, files);\n        assertFalse(newBackupLocation.hasFile(\"data1.tar.gz.0\"));\n    }\n\n    @Test\n    public void convertInternalStorageOnlyTest() throws BackupException, IOException {\n        final List<String> internalStorage = Arrays.asList(\"shared_prefs/ca.cmetcalfe.locationshare_preferences.xml\",\n                \"shared_prefs/_has_set_default_values.xml\");\n        assert classLoader != null;\n        Path backupLocation = Paths.get(classLoader.getResource(OABConverter.PATH_SUFFIX).getFile())\n                .findFile(PACKAGE_NAME_INT);\n        OABConverter oabConvert = new OABConverter(backupLocation);\n        oabConvert.convert();\n        Path newBackupLocation = Prefs.Storage.getAppManagerDirectory()\n                .findFile(BackupItems.BACKUP_DIRECTORY)\n                .listFiles()[0];\n        BackupItems.BackupItem backupItem = BackupItems.findBackupItem(BackupUtils.getV5RelativeDir(newBackupLocation.getName()));\n        // Verify source\n        BackupMetadataV5 metadataV5 = backupItem.getMetadata();\n        assertEquals(MetadataManager.getCurrentBackupMetaVersion(), metadataV5.info.version);\n        assertEquals(\"OAndBackup\", metadataV5.metadata.backupName);\n        List<String> files = TarUtilsTest.getFileNamesGZip(Arrays.asList(backupItem.getDataFiles(0)));\n        assertEquals(internalStorage, files);\n        assertFalse(newBackupLocation.hasFile(\"source.tar.gz.0\"));\n        assertFalse(newBackupLocation.hasFile(\"data1.tar.gz.0\"));\n    }\n\n    @Test\n    public void convertApkOnlyTest() throws BackupException, IOException {\n        assert classLoader != null;\n        Path backupLocation = Paths.get(classLoader.getResource(OABConverter.PATH_SUFFIX).getFile())\n                .findFile(PACKAGE_NAME_APK);\n        OABConverter oabConvert = new OABConverter(backupLocation);\n        oabConvert.convert();\n        Path newBackupLocation = Prefs.Storage.getAppManagerDirectory()\n                .findFile(BackupItems.BACKUP_DIRECTORY)\n                .listFiles()[0];\n        BackupItems.BackupItem backupItem = BackupItems.findBackupItem(BackupUtils.getV5RelativeDir(newBackupLocation.getName()));\n        // Verify source\n        BackupMetadataV5 metadataV5 = backupItem.getMetadata();\n        assertEquals(MetadataManager.getCurrentBackupMetaVersion(), metadataV5.info.version);\n        assertEquals(\"OAndBackup\", metadataV5.metadata.backupName);\n        assertEquals(Collections.singletonList(\"base.apk\"), TarUtilsTest.getFileNamesGZip(\n                Arrays.asList(backupItem.getSourceFiles())));\n        assertFalse(newBackupLocation.hasFile(\"data0.tar.gz.0\"));\n        assertFalse(newBackupLocation.hasFile(\"data1.tar.gz.0\"));\n    }\n}\n"
  },
  {
    "path": "app/src/test/java/io/github/muntashirakon/AppManager/backup/convert/SBConverterTest.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.backup.convert;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertFalse;\n\nimport org.junit.After;\nimport org.junit.Before;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.robolectric.RobolectricTestRunner;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\n\nimport io.github.muntashirakon.AppManager.backup.BackupException;\nimport io.github.muntashirakon.AppManager.backup.BackupItems;\nimport io.github.muntashirakon.AppManager.backup.BackupUtils;\nimport io.github.muntashirakon.AppManager.backup.MetadataManager;\nimport io.github.muntashirakon.AppManager.backup.struct.BackupMetadataV5;\nimport io.github.muntashirakon.AppManager.settings.Prefs;\nimport io.github.muntashirakon.AppManager.utils.RoboUtils;\nimport io.github.muntashirakon.AppManager.utils.TarUtilsTest;\nimport io.github.muntashirakon.io.Path;\nimport io.github.muntashirakon.io.Paths;\n\n@RunWith(RobolectricTestRunner.class)\npublic class SBConverterTest {\n    private static final String PACKAGE_NAME_FULL = \"dnsfilter.android\";\n    private static final String PACKAGE_NAME_APK_INT = \"org.billthefarmer.editor\";\n    private static final String PACKAGE_NAME_APK = \"ademar.textlauncher\";\n    private static final String PACKAGE_NAME_APK_SPLITS = \"com.google.android.samples.dynamicfeatures.ondemand\";\n    private static final String PACKAGE_NAME_APK_OBB = \"com.test.app\";\n\n    private final ClassLoader classLoader = getClass().getClassLoader();\n    private File backupLocation;\n    private Path tmpBackupPath;\n\n    @Before\n    public void setUp() throws IOException {\n        assert classLoader != null;\n        backupLocation = new File(classLoader.getResource(\"SwiftBackup\").getFile());\n        tmpBackupPath = Paths.get(RoboUtils.getTestBaseDir()).createNewDirectory(\"backup-dir\");\n        Prefs.Storage.setVolumePath(tmpBackupPath.toString());\n    }\n\n    @After\n    public void tearDown() {\n        tmpBackupPath.delete();\n    }\n\n    @Test\n    public void convertFullTest() throws BackupException, IOException {\n        final List<String> internalStorage = Collections.singletonList(\"code_cache/\");\n        final List<String> externalStorage = Arrays.asList(\"files/\",\n                \"files/PersonalDNSFilter/\",\n                \"files/PersonalDNSFilter/dnsfilter.conf\",\n                \"files/PersonalDNSFilter/additionalHosts.txt\",\n                \"files/PersonalDNSFilter/VERSION.TXT\");\n        Collections.sort(internalStorage);\n        Collections.sort(externalStorage);\n\n        Path xmlFile = Paths.get(new File(backupLocation, PACKAGE_NAME_FULL + \".xml\"));\n        SBConverter sbConvert = new SBConverter(xmlFile);\n        sbConvert.convert();\n        Path newBackupLocation = Prefs.Storage.getAppManagerDirectory()\n                .findFile(BackupItems.BACKUP_DIRECTORY)\n                .listFiles()[0];\n        BackupItems.BackupItem backupItem = BackupItems.findBackupItem(BackupUtils.getV5RelativeDir(newBackupLocation.getName()));\n        // Verify source\n        BackupMetadataV5 metadataV5 = backupItem.getMetadata();\n        assertEquals(MetadataManager.getCurrentBackupMetaVersion(), metadataV5.info.version);\n        assertEquals(\"SB\", metadataV5.metadata.backupName);\n        assertEquals(Collections.singletonList(\"base.apk\"), TarUtilsTest.getFileNamesGZip(\n                Arrays.asList(backupItem.getSourceFiles())));\n        List<String> files = TarUtilsTest.getFileNamesGZip(Arrays.asList(backupItem.getDataFiles(0)));\n        Collections.sort(files);\n        assertEquals(internalStorage, files);\n        files = TarUtilsTest.getFileNamesGZip(Arrays.asList(backupItem.getDataFiles(1)));\n        Collections.sort(files);\n        assertEquals(externalStorage, files);\n    }\n\n    @Test\n    public void convertApkInternalStorageTest() throws BackupException, IOException {\n        final List<String> internalStorage = Arrays.asList(\"code_cache/\",\n                \"shared_prefs/\",\n                \"shared_prefs/org.billthefarmer.editor_preferences.xml\");\n        Collections.sort(internalStorage);\n        Path xmlFile = Paths.get(new File(backupLocation, PACKAGE_NAME_APK_INT + \".xml\"));\n        SBConverter sbConvert = new SBConverter(xmlFile);\n        sbConvert.convert();\n        Path newBackupLocation = Prefs.Storage.getAppManagerDirectory()\n                .findFile(BackupItems.BACKUP_DIRECTORY)\n                .listFiles()[0];\n        BackupItems.BackupItem backupItem = BackupItems.findBackupItem(BackupUtils.getV5RelativeDir(newBackupLocation.getName()));\n        // Verify source\n        BackupMetadataV5 metadataV5 = backupItem.getMetadata();\n        assertEquals(MetadataManager.getCurrentBackupMetaVersion(), metadataV5.info.version);\n        assertEquals(\"SB\", metadataV5.metadata.backupName);\n        assertEquals(Collections.singletonList(\"base.apk\"), TarUtilsTest.getFileNamesGZip(\n                Arrays.asList(backupItem.getSourceFiles())));\n        List<String> files = TarUtilsTest.getFileNamesGZip(Arrays.asList(backupItem.getDataFiles(0)));\n        Collections.sort(files);\n        assertEquals(internalStorage, files);\n        assertFalse(newBackupLocation.hasFile(\"data1.tar.gz.0\"));\n    }\n\n    @Test\n    public void convertApkOnlyTest() throws BackupException, IOException {\n        Path xmlFile = Paths.get(new File(backupLocation, PACKAGE_NAME_APK + \".xml\"));\n        SBConverter sbConvert = new SBConverter(xmlFile);\n        sbConvert.convert();\n        Path newBackupLocation = Prefs.Storage.getAppManagerDirectory()\n                .findFile(BackupItems.BACKUP_DIRECTORY)\n                .listFiles()[0];\n        BackupItems.BackupItem backupItem = BackupItems.findBackupItem(BackupUtils.getV5RelativeDir(newBackupLocation.getName()));\n        // Verify source\n        BackupMetadataV5 metadataV5 = backupItem.getMetadata();\n        assertEquals(MetadataManager.getCurrentBackupMetaVersion(), metadataV5.info.version);\n        assertEquals(\"SB\", metadataV5.metadata.backupName);\n        assertEquals(Collections.singletonList(\"base.apk\"), TarUtilsTest.getFileNamesGZip(\n                Arrays.asList(backupItem.getSourceFiles())));\n        assertFalse(newBackupLocation.hasFile(\"data0.tar.gz.0\"));\n        assertFalse(newBackupLocation.hasFile(\"data1.tar.gz.0\"));\n    }\n\n    @Test\n    public void convertApkSplitsTest() throws BackupException, IOException {\n        final List<String> expectedApkFiles = Arrays.asList(\"base.apk\",\n                \"split_config.en.apk\",\n                \"split_config.hdpi.apk\");\n        Collections.sort(expectedApkFiles);\n        Path xmlFile = Paths.get(new File(backupLocation, PACKAGE_NAME_APK_SPLITS + \".xml\"));\n        SBConverter sbConvert = new SBConverter(xmlFile);\n        sbConvert.convert();\n        Path newBackupLocation = Prefs.Storage.getAppManagerDirectory()\n                .findFile(BackupItems.BACKUP_DIRECTORY)\n                .listFiles()[0];\n        BackupItems.BackupItem backupItem = BackupItems.findBackupItem(BackupUtils.getV5RelativeDir(newBackupLocation.getName()));\n        // Verify source\n        BackupMetadataV5 metadataV5 = backupItem.getMetadata();\n        assertEquals(MetadataManager.getCurrentBackupMetaVersion(), metadataV5.info.version);\n        assertEquals(\"SB\", metadataV5.metadata.backupName);\n        List<String> actualApkFiles = TarUtilsTest.getFileNamesGZip(\n                Arrays.asList(backupItem.getSourceFiles()));\n        Collections.sort(actualApkFiles);\n        assertEquals(expectedApkFiles, actualApkFiles);\n        assertFalse(newBackupLocation.hasFile(\"data0.tar.gz.0\"));\n        assertFalse(newBackupLocation.hasFile(\"data1.tar.gz.0\"));\n    }\n\n\n    // FIXME: 14/9/21 The test below is disabled due to Rebolectric unable to parse APK files\n//    @Test\n//    public void convertApkObbTest() throws BackupException, IOException {\n//        Path xmlFile = Paths.get(new File(backupLocation, PACKAGE_NAME_APK_OBB + \".xml\"));\n//        SBConverter sbConvert = new SBConverter(xmlFile);\n//        sbConvert.convert();\n//        Path newBackupLocation = Prefs.Storage.getAppManagerDirectory()\n//                .findFile(BackupItems.BACKUP_DIRECTORY)\n//                .listFiles()[0];\n//        BackupItems.BackupItem backupItem = BackupItems.findBackupItem(BackupUtils.getV5RelativeDir(newBackupLocation.getName()));\n//        // Verify source\n//        BackupMetadataV5 metadataV5 = backupItem.getMetadata();\n//        assertEquals(MetadataManager.getCurrentBackupMetaVersion(), metadataV5.info.version);\n//        assertEquals(\"SB\", metadataV5.metadata.backupName);\n//        assertEquals(Collections.singletonList(\"base.apk\"), TarUtilsTest.getFileNamesGZip(\n//                Arrays.asList(backupItem.getSourceFiles())));\n//        assertEquals(Collections.singletonList(\"test-assets.obb\"), TarUtilsTest.getFileNamesGZip(Arrays.asList(backupItem.getDataFiles(0))));\n//        assertFalse(newBackupLocation.hasFile(\"data1.tar.gz.0\"));\n//    }\n}\n"
  },
  {
    "path": "app/src/test/java/io/github/muntashirakon/AppManager/backup/convert/TBConverterTest.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.backup.convert;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertFalse;\n\nimport org.junit.After;\nimport org.junit.Before;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.robolectric.RobolectricTestRunner;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\n\nimport io.github.muntashirakon.AppManager.backup.BackupException;\nimport io.github.muntashirakon.AppManager.backup.BackupItems;\nimport io.github.muntashirakon.AppManager.backup.BackupUtils;\nimport io.github.muntashirakon.AppManager.backup.MetadataManager;\nimport io.github.muntashirakon.AppManager.backup.struct.BackupMetadataV5;\nimport io.github.muntashirakon.AppManager.settings.Prefs;\nimport io.github.muntashirakon.AppManager.utils.TarUtilsTest;\nimport io.github.muntashirakon.io.Path;\nimport io.github.muntashirakon.io.Paths;\n\n@RunWith(RobolectricTestRunner.class)\npublic class TBConverterTest {\n    private static final String PACKAGE_NAME_FULL = \"dnsfilter.android\";\n    private static final String PACKAGE_NAME_APK_INT = \"org.billthefarmer.editor\";\n    private static final String PACKAGE_NAME_INT = \"ca.cmetcalfe.locationshare\";\n    private static final String PACKAGE_NAME_APK = \"ademar.textlauncher\";\n\n    private final ClassLoader classLoader = getClass().getClassLoader();\n    private File backupLocation;\n\n    @Before\n    public void setUp() {\n        Prefs.Storage.setVolumePath(\"file:///tmp\");\n        Paths.get(\"/tmp/AppManager\").delete();\n        assert classLoader != null;\n        backupLocation = new File(classLoader.getResource(TBConverter.PATH_SUFFIX).getFile());\n    }\n\n    @After\n    public void tearDown() {\n        Paths.get(\"/tmp/AppManager\").delete();\n    }\n\n    @Test\n    public void convertFullTest() throws BackupException, IOException {\n        final List<String> internalStorage = Arrays.asList(\"code_cache/\",\n                \"code_cache/com.android.opengl.shaders_cache\");\n        final List<String> externalStorage = Arrays.asList(\"files/\",\n                \"files/PersonalDNSFilter/\",\n                \"files/PersonalDNSFilter/dnsfilter.conf\",\n                \"files/PersonalDNSFilter/additionalHosts.txt\",\n                \"files/PersonalDNSFilter/VERSION.TXT\",\n                \"files/PersonalDNSFilter/log/\",\n                \"files/PersonalDNSFilter/log/trafficlog/\",\n                \"files/PersonalDNSFilter/log/trafficlog/trafficlog_0.log\",\n                \"files/PersonalDNSFilter/FILTERHOSTS.TXT.idx/\",\n                \"files/PersonalDNSFilter/FILTERHOSTS.TXT.idx/IDX_VERSION\",\n                \"files/PersonalDNSFilter/FILTERHOSTS.TXT.idx/idx0\",\n                \"files/PersonalDNSFilter/FILTERHOSTS.TXT.idx/idx1\",\n                \"files/PersonalDNSFilter/FILTERHOSTS.TXT.idx/idx2\",\n                \"files/PersonalDNSFilter/FILTERHOSTS.TXT.idx/idx3\",\n                \"files/PersonalDNSFilter/FILTERHOSTS.TXT.idx/idx4\",\n                \"files/PersonalDNSFilter/FILTERHOSTS.TXT.idx/idx5\",\n                \"files/PersonalDNSFilter/FILTERHOSTS.TXT.idx/idx6\",\n                \"files/PersonalDNSFilter/FILTERHOSTS.TXT.idx/idx7\",\n                \"files/PersonalDNSFilter/FILTERHOSTS.TXT.idx/idx8\",\n                \"files/PersonalDNSFilter/FILTERHOSTS.TXT.idx/idx9\",\n                \"files/PersonalDNSFilter/FILTERHOSTS.TXT.idx/idx10\",\n                \"files/PersonalDNSFilter/FILTERHOSTS.TXT.idx/idx11\",\n                \"files/PersonalDNSFilter/FILTERHOSTS.TXT.idx/idx12\",\n                \"files/PersonalDNSFilter/FILTERHOSTS.TXT.idx/idx13\",\n                \"files/PersonalDNSFilter/FILTERHOSTS.TXT.idx/idx14\",\n                \"files/PersonalDNSFilter/FILTERHOSTS.TXT\",\n                \"files/PersonalDNSFilter/FILTERHOSTS.TXT.DLD_CNT\");\n        Collections.sort(internalStorage);\n        Collections.sort(externalStorage);\n        Path propFile = Paths.get(new File(backupLocation, PACKAGE_NAME_FULL + \"-20210529-164214.properties\"));\n        TBConverter tbConvert = new TBConverter(propFile);\n        tbConvert.convert();\n        Path newBackupLocation = Prefs.Storage.getAppManagerDirectory()\n                .findFile(BackupItems.BACKUP_DIRECTORY)\n                .listFiles()[0];\n        BackupItems.BackupItem backupItem = BackupItems.findBackupItem(BackupUtils.getV5RelativeDir(newBackupLocation.getName()));\n        // Verify source\n        BackupMetadataV5 metadataV5 = backupItem.getMetadata();\n        assertEquals(MetadataManager.getCurrentBackupMetaVersion(), metadataV5.info.version);\n        assertEquals(\"TB\", metadataV5.metadata.backupName);\n        assertEquals(Collections.singletonList(\"base.apk\"), TarUtilsTest.getFileNamesGZip(\n                Arrays.asList(backupItem.getSourceFiles())));\n        List<String> files = TarUtilsTest.getFileNamesGZip(\n                Arrays.asList(backupItem.getDataFiles(0)));\n        Collections.sort(files);\n        assertEquals(internalStorage, files);\n        files = TarUtilsTest.getFileNamesGZip(\n                Arrays.asList(backupItem.getDataFiles(1)));\n        Collections.sort(files);\n        assertEquals(externalStorage, files);\n    }\n\n    @Test\n    public void convertApkInternalStorageTest() throws BackupException, IOException {\n        final List<String> internalStorage = Arrays.asList(\"code_cache/\",\n                \"code_cache/com.android.opengl.shaders_cache\",\n                \"shared_prefs/\",\n                \"shared_prefs/org.billthefarmer.editor_preferences.xml\");\n        Collections.sort(internalStorage);\n        Path propFile = Paths.get(new File(backupLocation, PACKAGE_NAME_APK_INT + \"-20210529-164210.properties\"));\n        TBConverter tbConvert = new TBConverter(propFile);\n        tbConvert.convert();\n        Path newBackupLocation = Prefs.Storage.getAppManagerDirectory()\n                .findFile(BackupItems.BACKUP_DIRECTORY)\n                .listFiles()[0];\n        BackupItems.BackupItem backupItem = BackupItems.findBackupItem(BackupUtils.getV5RelativeDir(newBackupLocation.getName()));\n        // Verify source\n        BackupMetadataV5 metadataV5 = backupItem.getMetadata();\n        assertEquals(MetadataManager.getCurrentBackupMetaVersion(), metadataV5.info.version);\n        assertEquals(\"TB\", metadataV5.metadata.backupName);\n        assertEquals(Collections.singletonList(\"base.apk\"), TarUtilsTest.getFileNamesGZip(\n                Arrays.asList(backupItem.getSourceFiles())));\n        List<String> files = TarUtilsTest.getFileNamesGZip(\n                Arrays.asList(backupItem.getDataFiles(0)));\n        Collections.sort(files);\n        assertEquals(internalStorage, files);\n        assertFalse(newBackupLocation.hasFile(\"data1.tar.gz.0\"));\n    }\n\n    @Test\n    public void convertInternalStorageOnlyTest() throws BackupException, IOException {\n        final List<String> internalStorage = Arrays.asList(\"code_cache/\",\n                \"code_cache/com.android.opengl.shaders_cache\",\n                \"shared_prefs/\",\n                \"shared_prefs/ca.cmetcalfe.locationshare_preferences.xml\",\n                \"shared_prefs/_has_set_default_values.xml\");\n        Collections.sort(internalStorage);\n        Path propFile = Paths.get(new File(backupLocation, PACKAGE_NAME_INT + \"-20210529-164219.properties\"));\n        TBConverter tbConvert = new TBConverter(propFile);\n        tbConvert.convert();\n        Path newBackupLocation = Prefs.Storage.getAppManagerDirectory()\n                .findFile(BackupItems.BACKUP_DIRECTORY)\n                .listFiles()[0];\n        BackupItems.BackupItem backupItem = BackupItems.findBackupItem(BackupUtils.getV5RelativeDir(newBackupLocation.getName()));\n        // Verify source\n        BackupMetadataV5 metadataV5 = backupItem.getMetadata();\n        assertEquals(MetadataManager.getCurrentBackupMetaVersion(), metadataV5.info.version);\n        assertEquals(\"TB\", metadataV5.metadata.backupName);\n        List<String> files = TarUtilsTest.getFileNamesGZip(\n                Arrays.asList(backupItem.getDataFiles(0)));\n        Collections.sort(files);\n        assertEquals(internalStorage, files);\n        assertFalse(newBackupLocation.hasFile(\"source.tar.gz.0\"));\n        assertFalse(newBackupLocation.hasFile(\"data1.tar.gz.0\"));\n    }\n\n    @Test\n    public void convertApkOnlyTest() throws BackupException, IOException {\n        Path propFile = Paths.get(new File(backupLocation, PACKAGE_NAME_APK + \"-20210530-111646.properties\"));\n        TBConverter tbConvert = new TBConverter(propFile);\n        tbConvert.convert();\n        Path newBackupLocation = Prefs.Storage.getAppManagerDirectory()\n                .findFile(BackupItems.BACKUP_DIRECTORY)\n                .listFiles()[0];\n        BackupItems.BackupItem backupItem = BackupItems.findBackupItem(BackupUtils.getV5RelativeDir(newBackupLocation.getName()));\n        // Verify source\n        BackupMetadataV5 metadataV5 = backupItem.getMetadata();\n        assertEquals(MetadataManager.getCurrentBackupMetaVersion(), metadataV5.info.version);\n        assertEquals(\"TB\", metadataV5.metadata.backupName);\n        assertEquals(Collections.singletonList(\"base.apk\"), TarUtilsTest.getFileNamesGZip(\n                Arrays.asList(backupItem.getSourceFiles())));\n        assertFalse(newBackupLocation.hasFile(\"data0.tar.gz.0\"));\n        assertFalse(newBackupLocation.hasFile(\"data1.tar.gz.0\"));\n    }\n}"
  },
  {
    "path": "app/src/test/java/io/github/muntashirakon/AppManager/batchops/BatchQueueItemTest.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.batchops;\n\nimport static org.junit.Assert.*;\n\nimport android.net.Uri;\nimport android.os.Parcel;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.robolectric.RobolectricTestRunner;\n\nimport java.util.Objects;\n\nimport io.github.muntashirakon.AppManager.backup.convert.ImportType;\nimport io.github.muntashirakon.AppManager.batchops.struct.BatchBackupImportOptions;\n\n@RunWith(RobolectricTestRunner.class)\npublic class BatchQueueItemTest {\n    @Test\n    public void testBackupImportParcelable() {\n        Uri uri = Uri.parse(\"file:///sdcard/OAndBackup\");\n        BatchBackupImportOptions options = new BatchBackupImportOptions(ImportType.OAndBackup, uri, false);\n        BatchQueueItem queueItem = BatchQueueItem.getBatchOpQueue(BatchOpsManager.OP_IMPORT_BACKUPS, null, null, options);\n        Parcel parcel = Parcel.obtain();\n        queueItem.writeToParcel(parcel, 0);\n        parcel.setDataPosition(0);\n        BatchQueueItem queueItem2 = BatchQueueItem.CREATOR.createFromParcel(parcel);\n        assertEquals(BatchOpsManager.OP_IMPORT_BACKUPS, queueItem2.getOp());\n        BatchBackupImportOptions options2 = (BatchBackupImportOptions) Objects.requireNonNull(queueItem2.getOptions());\n        assertEquals(ImportType.OAndBackup, options2.getImportType());\n        assertEquals(uri, options2.getDirectory());\n        assertFalse(options2.isRemoveImportedDirectory());\n    }\n}"
  },
  {
    "path": "app/src/test/java/io/github/muntashirakon/AppManager/batchops/struct/BatchAppOpsOptionsTest.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.batchops.struct;\n\nimport static org.junit.Assert.*;\n\nimport android.os.Parcel;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.robolectric.RobolectricTestRunner;\n\n@RunWith(RobolectricTestRunner.class)\npublic class BatchAppOpsOptionsTest {\n    @Test\n    public void testParcelable() {\n        int[] array = new int[]{12, 13, 14};\n        BatchAppOpsOptions options = new BatchAppOpsOptions(array, 0);\n        Parcel parcel = Parcel.obtain();\n        options.writeToParcel(parcel, 0);\n        parcel.setDataPosition(0);\n        BatchAppOpsOptions options2 = BatchAppOpsOptions.CREATOR.createFromParcel(parcel);\n        assertArrayEquals(array, options2.getAppOps());\n        assertEquals(0, options2.getMode());\n    }\n}"
  },
  {
    "path": "app/src/test/java/io/github/muntashirakon/AppManager/batchops/struct/BatchBackupImportOptionsTest.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.batchops.struct;\n\nimport static org.junit.Assert.*;\n\nimport android.net.Uri;\nimport android.os.Parcel;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.robolectric.RobolectricTestRunner;\n\nimport io.github.muntashirakon.AppManager.backup.convert.ImportType;\n\n@RunWith(RobolectricTestRunner.class)\npublic class BatchBackupImportOptionsTest {\n    @Test\n    public void testParcelable() {\n        Uri uri = Uri.parse(\"file:///sdcard/OAndBackup\");\n        BatchBackupImportOptions options = new BatchBackupImportOptions(ImportType.OAndBackup, uri, false);\n        Parcel parcel = Parcel.obtain();\n        options.writeToParcel(parcel, 0);\n        parcel.setDataPosition(0);\n        BatchBackupImportOptions options2 = BatchBackupImportOptions.CREATOR.createFromParcel(parcel);\n        assertEquals(ImportType.OAndBackup, options2.getImportType());\n        assertEquals(uri, options2.getDirectory());\n        assertFalse(options2.isRemoveImportedDirectory());\n    }\n}"
  },
  {
    "path": "app/src/test/java/io/github/muntashirakon/AppManager/batchops/struct/BatchDexOptOptionsTest.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.batchops.struct;\n\nimport static org.junit.Assert.*;\n\nimport android.os.Parcel;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.robolectric.RobolectricTestRunner;\n\nimport io.github.muntashirakon.AppManager.apk.dexopt.DexOptOptions;\n\n@RunWith(RobolectricTestRunner.class)\npublic class BatchDexOptOptionsTest {\n    @Test\n    public void testParcelable() {\n        DexOptOptions dexOptOptions = DexOptOptions.getDefault();\n        dexOptOptions.packages = new String[]{\"android.package\"};\n        BatchDexOptOptions options = new BatchDexOptOptions(dexOptOptions);\n        Parcel parcel = Parcel.obtain();\n        options.writeToParcel(parcel, 0);\n        parcel.setDataPosition(0);\n        BatchDexOptOptions options2 = BatchDexOptOptions.CREATOR.createFromParcel(parcel);\n        DexOptOptions dexOptOptions2 = options2.getDexOptOptions();\n        assertArrayEquals(dexOptOptions.packages, dexOptOptions2.packages);\n        assertEquals(dexOptOptions.compilerFiler, dexOptOptions2.compilerFiler);\n        assertEquals(dexOptOptions.compileLayouts, dexOptOptions2.compileLayouts);\n        assertEquals(dexOptOptions.clearProfileData, dexOptOptions2.clearProfileData);\n        assertEquals(dexOptOptions.checkProfiles, dexOptOptions2.checkProfiles);\n        assertEquals(dexOptOptions.bootComplete, dexOptOptions2.bootComplete);\n        assertEquals(dexOptOptions.forceCompilation, dexOptOptions2.forceCompilation);\n        assertEquals(dexOptOptions.forceDexOpt, dexOptOptions2.forceDexOpt);\n    }\n}"
  },
  {
    "path": "app/src/test/java/io/github/muntashirakon/AppManager/compat/ActivityManagerCompatTest.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.compat;\n\nimport android.app.ActivityManager;\nimport android.content.ComponentName;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.robolectric.RobolectricTestRunner;\n\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\n\nimport io.github.muntashirakon.io.IoUtils;\n\nimport static org.junit.Assert.assertArrayEquals;\nimport static org.junit.Assert.assertEquals;\n\n@RunWith(RobolectricTestRunner.class)\npublic class ActivityManagerCompatTest {\n    private final ClassLoader classLoader = getClass().getClassLoader();\n\n    @Test\n    public void parseRunningAppProcesses() throws IOException {\n        assert classLoader != null;\n        File dumpSysFile = new File(classLoader.getResource(\"dumpsys_app_processes.txt\").getFile());\n        List<ActivityManager.RunningAppProcessInfo> expectedRunningAppProcesses = new ArrayList<>(3);\n        expectedRunningAppProcesses.add(new ActivityManager.RunningAppProcessInfo() {\n            {\n                processName = \"com.qualcomm.qti.services.systemhelper:systemhelper_service\";\n                pid = 22828;\n                uid = 10213;\n                pkgList = new String[]{\"com.qualcomm.qti.services.systemhelper\"};\n            }\n        });\n        expectedRunningAppProcesses.add(new ActivityManager.RunningAppProcessInfo() {\n            {\n                processName = \"org.mozilla.fenix:tab6\";\n                pid = 13763;\n                uid = 10262;\n                pkgList = new String[]{\"org.mozilla.fenix\"};\n            }\n        });\n        expectedRunningAppProcesses.add(new ActivityManager.RunningAppProcessInfo() {\n            {\n                processName = \"system\";\n                pid = 1879;\n                uid = 1000;\n                pkgList = new String[]{\"com.android.networkstack.inprocess\", \"android\", \"com.android.service.settingsobserver\", \"com.android.providers.settings\", \"com.android.server.telecom\", \"com.android.networkstack.tethering.inprocess\"};\n            }\n        });\n        Collections.sort(expectedRunningAppProcesses, (o1, o2) -> Integer.compare(o1.pid, o2.pid));\n        try (InputStream is = new FileInputStream(dumpSysFile)) {\n            byte[] allBytes = IoUtils.readFully(is, -1, true);\n            String s = new String(allBytes);\n            List<String> sysDump = Arrays.asList(s.split(\"\\n\"));\n            List<ActivityManager.RunningAppProcessInfo> actualRunningAppProcess = ActivityManagerCompat.parseRunningAppProcesses(sysDump);\n            Collections.sort(actualRunningAppProcess, (o1, o2) -> Integer.compare(o1.pid, o2.pid));\n            assertEquals(expectedRunningAppProcesses.size(), actualRunningAppProcess.size());\n            for (int i = 0; i < expectedRunningAppProcesses.size(); ++i) {\n                ActivityManager.RunningAppProcessInfo expected = expectedRunningAppProcesses.get(i);\n                ActivityManager.RunningAppProcessInfo actual = actualRunningAppProcess.get(i);\n                assertEquals(expected.processName, actual.processName);\n                assertEquals(expected.uid, actual.uid);\n                assertEquals(expected.pid, actual.pid);\n                assertArrayEquals(expected.pkgList, actual.pkgList);\n            }\n        }\n    }\n\n    @Test\n    public void parseRunningServices() throws IOException {\n        assert classLoader != null;\n        File dumpSysFile = new File(classLoader.getResource(\"dumpsys_services.txt\").getFile());\n        List<ActivityManager.RunningServiceInfo> expectedRunningServices = new ArrayList<>(3);\n        expectedRunningServices.add(new ActivityManager.RunningServiceInfo() {\n            {\n                service = ComponentName.unflattenFromString(\"org.bromite.bromite/org.chromium.content.app.SandboxedProcessService0\");\n                process = \"org.bromite.bromite:sandboxed_process0:org.chromium.content.app.SandboxedProcessService0:1\";\n                uid = 10143;\n                pid = 6072;\n                clientCount = 1;\n                activeSince = 86235304L;\n                lastActivityTime = 51116115L;\n            }\n        });\n        expectedRunningServices.add(new ActivityManager.RunningServiceInfo() {\n            {\n                service = ComponentName.unflattenFromString(\"org.bromite.bromite/org.chromium.content.app.SandboxedProcessService0\");\n                process = \"org.bromite.bromite:sandboxed_process0:org.chromium.content.app.SandboxedProcessService0:2\";\n                uid = 10143;\n                pid = 6082;\n                clientCount = 2;\n                activeSince = 86235636L;\n                lastActivityTime = 52902756L;\n            }\n        });\n        expectedRunningServices.add(new ActivityManager.RunningServiceInfo() {\n            {\n                service = ComponentName.unflattenFromString(\"org.bromite.bromite/org.chromium.content.app.PrivilegedProcessService0\");\n                process = \"org.bromite.bromite:privileged_process0\";\n                uid = 10143;\n                pid = 4604;\n                clientCount = 2;\n                activeSince = 84180869L;\n                lastActivityTime = 50297542L;\n            }\n        });\n        Collections.sort(expectedRunningServices, (o1, o2) -> Integer.compare(o1.pid, o2.pid));\n        try (InputStream is = new FileInputStream(dumpSysFile)) {\n            byte[] allBytes = IoUtils.readFully(is, -1, true);\n            String s = new String(allBytes);\n            List<String> sysDump = Arrays.asList(s.split(\"\\n\"));\n            List<ActivityManager.RunningServiceInfo> actualRunningServices = ActivityManagerCompat.parseRunningServices(sysDump);\n            Collections.sort(actualRunningServices, (o1, o2) -> Integer.compare(o1.pid, o2.pid));\n            assertEquals(expectedRunningServices.size(), actualRunningServices.size());\n            for (int i = 0; i < expectedRunningServices.size(); ++i) {\n                // Currently, on service, process, UID, PID should be matched\n                ActivityManager.RunningServiceInfo expected = expectedRunningServices.get(i);\n                ActivityManager.RunningServiceInfo actual = actualRunningServices.get(i);\n                assertEquals(expected.service, actual.service);\n                assertEquals(expected.process, actual.process);\n                assertEquals(expected.uid, actual.uid);\n                assertEquals(expected.pid, actual.pid);\n            }\n        }\n    }\n}"
  },
  {
    "path": "app/src/test/java/io/github/muntashirakon/AppManager/filters/FilterItemTest.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.filters;\n\nimport static org.junit.Assert.*;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.robolectric.RobolectricTestRunner;\n\nimport io.github.muntashirakon.AppManager.filters.options.FilterOptions;\n\n@RunWith(RobolectricTestRunner.class)\npublic class FilterItemTest {\n    @Test\n    public void testAddFilterOption() {\n        FilterItem filterItem = new FilterItem();\n        filterItem.addFilterOption(FilterOptions.create(\"apk_size\"));\n        assertEquals(\"apk_size_1\", filterItem.getExpr());\n        filterItem.addFilterOption(FilterOptions.create(\"app_label\"));\n        assertEquals(\"apk_size_1 & app_label_2\", filterItem.getExpr());\n        filterItem.addFilterOption(FilterOptions.create(\"app_type\"));\n        assertEquals(\"apk_size_1 & app_label_2 & app_type_3\", filterItem.getExpr());\n        filterItem.addFilterOption(FilterOptions.create(\"backup\"));\n        assertEquals(\"apk_size_1 & app_label_2 & app_type_3 & backup_4\", filterItem.getExpr());\n    }\n\n    @Test\n    public void testUpdateFilterOption() {\n        FilterItem filterItem = new FilterItem();\n        filterItem.addFilterOption(FilterOptions.create(\"apk_size\"));\n        filterItem.addFilterOption(FilterOptions.create(\"app_label\"));\n        filterItem.addFilterOption(FilterOptions.create(\"app_type\"));\n        filterItem.addFilterOption(FilterOptions.create(\"backup\"));\n        assertEquals(\"apk_size_1 & app_label_2 & app_type_3 & backup_4\", filterItem.getExpr());\n        filterItem.updateFilterOptionAt(0, FilterOptions.create(\"compile_sdk\"));\n        assertEquals(\"compile_sdk_1 & app_label_2 & app_type_3 & backup_4\", filterItem.getExpr());\n        filterItem.updateFilterOptionAt(0, FilterOptions.create(\"components\"));\n        assertEquals(\"components_1 & app_label_2 & app_type_3 & backup_4\", filterItem.getExpr());\n        filterItem.updateFilterOptionAt(1, FilterOptions.create(\"pkg_name\"));\n        assertEquals(\"components_1 & pkg_name_2 & app_type_3 & backup_4\", filterItem.getExpr());\n        filterItem.updateFilterOptionAt(2, FilterOptions.create(\"version_name\"));\n        assertEquals(\"components_1 & pkg_name_2 & version_name_3 & backup_4\", filterItem.getExpr());\n        filterItem.updateFilterOptionAt(3, FilterOptions.create(\"times_opened\"));\n        assertEquals(\"components_1 & pkg_name_2 & version_name_3 & times_opened_4\", filterItem.getExpr());\n        assertThrows(IllegalArgumentException.class, () -> filterItem.updateFilterOptionAt(4, FilterOptions.create(\"apk_size\")));\n        filterItem.removeFilterOptionAt(0);\n        filterItem.removeFilterOptionAt(0);\n        filterItem.removeFilterOptionAt(0);\n        assertEquals(\"times_opened_4\", filterItem.getExpr());\n        filterItem.updateFilterOptionAt(0, FilterOptions.create(\"running_apps\"));\n        assertEquals(\"running_apps_4\", filterItem.getExpr());\n        filterItem.removeFilterOptionAt(0);\n        assertEquals(\"\", filterItem.getExpr());\n    }\n\n    @Test\n    public void testRemoveFilterOption() {\n        FilterItem filterItem = new FilterItem();\n        filterItem.addFilterOption(FilterOptions.create(\"apk_size\"));\n        assertEquals(\"apk_size_1\", filterItem.getExpr());\n        filterItem.addFilterOption(FilterOptions.create(\"app_label\"));\n        assertEquals(\"apk_size_1 & app_label_2\", filterItem.getExpr());\n        filterItem.addFilterOption(FilterOptions.create(\"app_type\"));\n        assertEquals(\"apk_size_1 & app_label_2 & app_type_3\", filterItem.getExpr());\n        filterItem.addFilterOption(FilterOptions.create(\"backup\"));\n        assertEquals(\"apk_size_1 & app_label_2 & app_type_3 & backup_4\", filterItem.getExpr());\n        filterItem.removeFilterOptionAt(3);\n        assertEquals(\"apk_size_1 & app_label_2 & app_type_3\", filterItem.getExpr());\n        filterItem.removeFilterOptionAt(0);\n        assertEquals(\"app_label_2 & app_type_3\", filterItem.getExpr());\n        filterItem.addFilterOption(FilterOptions.create(\"times_opened\"));\n        assertEquals(\"app_label_2 & app_type_3 & times_opened_1\", filterItem.getExpr());\n        filterItem.addFilterOption(FilterOptions.create(\"times_opened\"));\n        assertEquals(\"app_label_2 & app_type_3 & times_opened_1 & times_opened_4\", filterItem.getExpr());\n        filterItem.addFilterOption(FilterOptions.create(\"pkg_name\"));\n        assertEquals(\"app_label_2 & app_type_3 & times_opened_1 & times_opened_4 & pkg_name_5\", filterItem.getExpr());\n        filterItem.removeFilterOptionAt(0);\n        filterItem.removeFilterOptionAt(0);\n        filterItem.removeFilterOptionAt(0);\n        filterItem.removeFilterOptionAt(0);\n        assertEquals(\"pkg_name_5\", filterItem.getExpr());\n        filterItem.removeFilterOptionAt(0);\n        assertEquals(\"\", filterItem.getExpr());\n    }\n}"
  },
  {
    "path": "app/src/test/java/io/github/muntashirakon/AppManager/fm/FmProviderTest.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.fm;\n\nimport android.net.Uri;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.robolectric.RobolectricTestRunner;\n\nimport static org.junit.Assert.assertEquals;\n\n@RunWith(RobolectricTestRunner.class)\npublic class FmProviderTest {\n    private final String cpFile = \"content://\" + FmProvider.AUTHORITY + \"/storage/emulated/0/AppManager\";\n    private final String noFile = \"file:///storage/emulated/0/AppManager\";\n\n    private final String cpContent = \"content://\" + FmProvider.AUTHORITY + \"/!com.authority/primary%3Adocument/AppManager\";\n    private final String noContent = \"content://com.authority/primary%3Adocument/AppManager\";\n\n    @Test\n    public void getContentUriForFile() {\n        Uri uri = FmProvider.getContentUri(Uri.parse(noFile));\n        assertEquals(cpFile, uri.toString());\n    }\n\n    @Test\n    public void getContentUriForContent() {\n        Uri uri = FmProvider.getContentUri(Uri.parse(noContent));\n        assertEquals(cpContent, uri.toString());\n    }\n\n    @Test\n    public void getFileProviderPathForFile() {\n        Uri uri = FmProvider.getFileProviderPathInternal(Uri.parse(cpFile));\n        assertEquals(noFile, uri.toString());\n    }\n\n    @Test\n    public void getFileProviderPathForContent() {\n        Uri uri = FmProvider.getFileProviderPathInternal(Uri.parse(cpContent));\n        assertEquals(noContent, uri.toString());\n    }\n}"
  },
  {
    "path": "app/src/test/java/io/github/muntashirakon/AppManager/rules/PseudoRulesTest.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.rules;\n\nimport org.junit.After;\nimport org.junit.Before;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.robolectric.RobolectricTestRunner;\n\nimport java.util.List;\n\nimport io.github.muntashirakon.AppManager.magisk.MagiskProcess;\nimport io.github.muntashirakon.AppManager.rules.struct.AppOpRule;\nimport io.github.muntashirakon.AppManager.rules.struct.BatteryOptimizationRule;\nimport io.github.muntashirakon.AppManager.rules.struct.ComponentRule;\nimport io.github.muntashirakon.AppManager.rules.struct.FreezeRule;\nimport io.github.muntashirakon.AppManager.rules.struct.MagiskDenyListRule;\nimport io.github.muntashirakon.AppManager.rules.struct.MagiskHideRule;\nimport io.github.muntashirakon.AppManager.rules.struct.NetPolicyRule;\nimport io.github.muntashirakon.AppManager.rules.struct.NotificationListenerRule;\nimport io.github.muntashirakon.AppManager.rules.struct.PermissionRule;\nimport io.github.muntashirakon.AppManager.rules.struct.RuleEntry;\nimport io.github.muntashirakon.AppManager.rules.struct.SsaidRule;\nimport io.github.muntashirakon.AppManager.utils.FreezeUtils;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertNotEquals;\n\n@RunWith(RobolectricTestRunner.class)\npublic class PseudoRulesTest {\n    private static final String PACKAGE_NAME = \"sample.package\";\n\n    private PseudoRules rules;\n\n    @Before\n    public void setUp() {\n        rules = new PseudoRules(PACKAGE_NAME, 0);\n    }\n\n    @Test\n    public void uniquenessOfActivitiesTest() {\n        rules.setComponent(\".activity\", RuleType.ACTIVITY, ComponentRule.COMPONENT_BLOCKED_IFW_DISABLE);\n        rules.setComponent(\".activity\", RuleType.ACTIVITY, ComponentRule.COMPONENT_TO_BE_DEFAULTED);\n        assertEquals(1, rules.getAll().size());\n        assertNotEquals(new ComponentRule(PACKAGE_NAME, \".activity\", RuleType.ACTIVITY,\n                ComponentRule.COMPONENT_BLOCKED_IFW_DISABLE), rules.getAll().get(0));\n        assertEquals(new ComponentRule(PACKAGE_NAME, \".activity\", RuleType.ACTIVITY,\n                ComponentRule.COMPONENT_TO_BE_DEFAULTED), rules.getAll().get(0));\n    }\n\n    @Test\n    public void uniquenessOfProvidersTest() {\n        rules.setComponent(\".activity\", RuleType.PROVIDER, ComponentRule.COMPONENT_BLOCKED_IFW_DISABLE);\n        rules.setComponent(\".activity\", RuleType.PROVIDER, ComponentRule.COMPONENT_TO_BE_DEFAULTED);\n        assertEquals(1, rules.getAll().size());\n        assertNotEquals(new ComponentRule(PACKAGE_NAME, \".activity\", RuleType.PROVIDER,\n                ComponentRule.COMPONENT_BLOCKED_IFW_DISABLE), rules.getAll().get(0));\n        assertEquals(new ComponentRule(PACKAGE_NAME, \".activity\", RuleType.PROVIDER,\n                ComponentRule.COMPONENT_TO_BE_DEFAULTED), rules.getAll().get(0));\n    }\n\n    @Test\n    public void uniquenessOfServicesTest() {\n        rules.setComponent(\".activity\", RuleType.SERVICE, ComponentRule.COMPONENT_BLOCKED_IFW_DISABLE);\n        rules.setComponent(\".activity\", RuleType.SERVICE, ComponentRule.COMPONENT_TO_BE_DEFAULTED);\n        assertEquals(1, rules.getAll().size());\n        assertNotEquals(new ComponentRule(PACKAGE_NAME, \".activity\", RuleType.SERVICE,\n                ComponentRule.COMPONENT_BLOCKED_IFW_DISABLE), rules.getAll().get(0));\n        assertEquals(new ComponentRule(PACKAGE_NAME, \".activity\", RuleType.SERVICE,\n                ComponentRule.COMPONENT_TO_BE_DEFAULTED), rules.getAll().get(0));\n    }\n\n    @Test\n    public void uniquenessOfReceiversTest() {\n        rules.setComponent(\".activity\", RuleType.RECEIVER, ComponentRule.COMPONENT_BLOCKED_IFW_DISABLE);\n        rules.setComponent(\".activity\", RuleType.RECEIVER, ComponentRule.COMPONENT_TO_BE_DEFAULTED);\n        assertEquals(1, rules.getAll().size());\n        assertNotEquals(new ComponentRule(PACKAGE_NAME, \".activity\", RuleType.RECEIVER,\n                ComponentRule.COMPONENT_BLOCKED_IFW_DISABLE), rules.getAll().get(0));\n        assertEquals(new ComponentRule(PACKAGE_NAME, \".activity\", RuleType.RECEIVER,\n                ComponentRule.COMPONENT_TO_BE_DEFAULTED), rules.getAll().get(0));\n    }\n\n    @Test\n    public void uniquenessOfAppOpsTest() {\n        rules.setAppOp(55, 3);\n        rules.setAppOp(55, 0);\n        assertEquals(1, rules.getAll().size());\n        assertNotEquals(new AppOpRule(PACKAGE_NAME, 55, 3), rules.getAll().get(0));\n        assertEquals(new AppOpRule(PACKAGE_NAME, 55, 0), rules.getAll().get(0));\n    }\n\n    @Test\n    public void uniquenessOfPermissionsTest() {\n        rules.setPermission(\".perm\", true, 32);\n        rules.setPermission(\".perm\", false, 4);\n        assertEquals(1, rules.getAll().size());\n        assertNotEquals(new PermissionRule(PACKAGE_NAME, \".perm\", true, 32), rules.getAll().get(0));\n        assertEquals(new PermissionRule(PACKAGE_NAME, \".perm\", false, 4), rules.getAll().get(0));\n    }\n\n    @Test\n    public void uniquenessOfMagiskHideTest() {\n        MagiskProcess mp1 = new MagiskProcess(PACKAGE_NAME, \"pkg:process\");\n        MagiskProcess mp2 = new MagiskProcess(mp1);\n        mp1.setEnabled(false);\n        mp2.setEnabled(true);\n        rules.setMagiskHide(mp1);\n        rules.setMagiskHide(mp2);\n        assertEquals(1, rules.getAll().size());\n        assertNotEquals(new MagiskHideRule(mp1), rules.getAll().get(0));\n        assertEquals(new MagiskHideRule(mp2), rules.getAll().get(0));\n    }\n\n    @Test\n    public void uniquenessOfMagiskDenyListTest() {\n        MagiskProcess mp1 = new MagiskProcess(PACKAGE_NAME, \"pkg:process\");\n        MagiskProcess mp2 = new MagiskProcess(mp1);\n        mp1.setEnabled(false);\n        mp2.setEnabled(true);\n        rules.setMagiskDenyList(mp1);\n        rules.setMagiskDenyList(mp2);\n        assertEquals(1, rules.getAll().size());\n        assertNotEquals(new MagiskDenyListRule(mp1), rules.getAll().get(0));\n        assertEquals(new MagiskDenyListRule(mp2), rules.getAll().get(0));\n    }\n\n    @Test\n    public void uniquenessOfBatteryOptimizationTest() {\n        rules.setBatteryOptimization(false);\n        rules.setBatteryOptimization(true);\n        assertEquals(1, rules.getAll().size());\n        assertNotEquals(new BatteryOptimizationRule(PACKAGE_NAME, false), rules.getAll().get(0));\n        assertEquals(new BatteryOptimizationRule(PACKAGE_NAME, true), rules.getAll().get(0));\n    }\n\n    @Test\n    public void uniquenessOfNetPolicyTest() {\n        rules.setNetPolicy(4);\n        rules.setNetPolicy(1 << 16);\n        assertEquals(1, rules.getAll().size());\n        assertNotEquals(new NetPolicyRule(PACKAGE_NAME, 4), rules.getAll().get(0));\n        assertEquals(new NetPolicyRule(PACKAGE_NAME, 1 << 16), rules.getAll().get(0));\n    }\n\n    @Test\n    public void uniquenessOfNotificationTest() {\n        rules.setNotificationListener(\".notif\", true);\n        rules.setNotificationListener(\".notif\", false);\n        assertEquals(1, rules.getAll().size());\n        assertNotEquals(new NotificationListenerRule(PACKAGE_NAME, \".notif\", true), rules.getAll().get(0));\n        assertEquals(new NotificationListenerRule(PACKAGE_NAME, \".notif\", false), rules.getAll().get(0));\n    }\n\n    @Test\n    public void uniquenessOfSsaidTest() {\n        rules.setSsaid(\"bc9948c6\");\n        rules.setSsaid(\"f6740c90\");\n        assertEquals(1, rules.getAll().size());\n        assertNotEquals(new SsaidRule(PACKAGE_NAME, \"bc9948c6\"), rules.getAll().get(0));\n        assertEquals(new SsaidRule(PACKAGE_NAME, \"f6740c90\"), rules.getAll().get(0));\n    }\n\n\n    @Test\n    public void uniquenessOfFreezeTest() {\n        rules.setFreezeType(FreezeUtils.FREEZE_ADV_SUSPEND);\n        rules.setFreezeType(FreezeUtils.FREEZE_DISABLE);\n        assertEquals(1, rules.getAll().size());\n        assertNotEquals(new FreezeRule(PACKAGE_NAME, FreezeUtils.FREEZE_ADV_SUSPEND), rules.getAll().get(0));\n        assertEquals(new FreezeRule(PACKAGE_NAME, FreezeUtils.FREEZE_DISABLE), rules.getAll().get(0));\n    }\n\n    @Test\n    public void interUniquenessTest() {\n        rules.setComponent(\".component\", RuleType.ACTIVITY, ComponentRule.COMPONENT_BLOCKED_IFW_DISABLE);\n        rules.setComponent(\".component\", RuleType.PROVIDER, ComponentRule.COMPONENT_BLOCKED_IFW_DISABLE);\n        rules.setComponent(\".component\", RuleType.SERVICE, ComponentRule.COMPONENT_BLOCKED_IFW_DISABLE);\n        rules.setComponent(\".component\", RuleType.RECEIVER, ComponentRule.COMPONENT_BLOCKED_IFW_DISABLE);\n        rules.setPermission(\".component\", true, 4);\n        rules.setNotificationListener(\".component\", true);\n        List<RuleEntry> ruleEntries = rules.getAll();\n        assertEquals(6, ruleEntries.size());\n        assertEquals(new ComponentRule(PACKAGE_NAME, \".component\", RuleType.ACTIVITY,\n                ComponentRule.COMPONENT_BLOCKED_IFW_DISABLE), ruleEntries.get(0));\n        assertEquals(new ComponentRule(PACKAGE_NAME, \".component\", RuleType.PROVIDER,\n                ComponentRule.COMPONENT_BLOCKED_IFW_DISABLE), ruleEntries.get(1));\n        assertEquals(new ComponentRule(PACKAGE_NAME, \".component\", RuleType.SERVICE,\n                ComponentRule.COMPONENT_BLOCKED_IFW_DISABLE), ruleEntries.get(2));\n        assertEquals(new ComponentRule(PACKAGE_NAME, \".component\", RuleType.RECEIVER,\n                ComponentRule.COMPONENT_BLOCKED_IFW_DISABLE), ruleEntries.get(3));\n        assertEquals(new PermissionRule(PACKAGE_NAME, \".component\", true, 4), ruleEntries.get(4));\n        assertEquals(new NotificationListenerRule(PACKAGE_NAME, \".component\", true), ruleEntries.get(5));\n    }\n\n    @Test\n    public void interUniquenessStubTest() {\n        rules.setComponent(RuleEntry.STUB, RuleType.ACTIVITY, ComponentRule.COMPONENT_BLOCKED_IFW_DISABLE);\n        rules.setComponent(RuleEntry.STUB, RuleType.PROVIDER, ComponentRule.COMPONENT_BLOCKED_IFW_DISABLE);\n        rules.setComponent(RuleEntry.STUB, RuleType.SERVICE, ComponentRule.COMPONENT_BLOCKED_IFW_DISABLE);\n        rules.setComponent(RuleEntry.STUB, RuleType.RECEIVER, ComponentRule.COMPONENT_BLOCKED_IFW_DISABLE);\n        rules.setPermission(RuleEntry.STUB, true, 4);\n        rules.setNotificationListener(RuleEntry.STUB, true);\n        rules.setNetPolicy(4);\n        rules.setBatteryOptimization(true);\n        // \"STUB\" is the name of the process (although impossible but tested anyway)\n        MagiskProcess mp = new MagiskProcess(PACKAGE_NAME, RuleEntry.STUB);\n        mp.setEnabled(true);\n        rules.setMagiskHide(mp);\n        rules.setMagiskDenyList(mp);\n        rules.setSsaid(\"bc9948c6\");\n        rules.setFreezeType(FreezeUtils.FREEZE_DISABLE);\n        List<RuleEntry> ruleEntries = rules.getAll();\n        assertEquals(12, ruleEntries.size());\n        assertEquals(new ComponentRule(PACKAGE_NAME, RuleEntry.STUB, RuleType.ACTIVITY,\n                ComponentRule.COMPONENT_BLOCKED_IFW_DISABLE), ruleEntries.get(0));\n        assertEquals(new ComponentRule(PACKAGE_NAME, RuleEntry.STUB, RuleType.PROVIDER,\n                ComponentRule.COMPONENT_BLOCKED_IFW_DISABLE), ruleEntries.get(1));\n        assertEquals(new ComponentRule(PACKAGE_NAME, RuleEntry.STUB, RuleType.SERVICE,\n                ComponentRule.COMPONENT_BLOCKED_IFW_DISABLE), ruleEntries.get(2));\n        assertEquals(new ComponentRule(PACKAGE_NAME, RuleEntry.STUB, RuleType.RECEIVER,\n                ComponentRule.COMPONENT_BLOCKED_IFW_DISABLE), ruleEntries.get(3));\n        assertEquals(new PermissionRule(PACKAGE_NAME, RuleEntry.STUB, true, 4), ruleEntries.get(4));\n        assertEquals(new NotificationListenerRule(PACKAGE_NAME, RuleEntry.STUB, true), ruleEntries.get(5));\n        assertEquals(new NetPolicyRule(PACKAGE_NAME, 4), ruleEntries.get(6));\n        assertEquals(new BatteryOptimizationRule(PACKAGE_NAME, true), ruleEntries.get(7));\n        assertEquals(new MagiskHideRule(mp), ruleEntries.get(8));\n        assertEquals(new MagiskDenyListRule(mp), ruleEntries.get(9));\n        assertEquals(new SsaidRule(PACKAGE_NAME, \"bc9948c6\"), ruleEntries.get(10));\n        assertEquals(new FreezeRule(PACKAGE_NAME, FreezeUtils.FREEZE_DISABLE), ruleEntries.get(11));\n    }\n\n    @After\n    public void tearDown() {\n        rules.setReadOnly();\n        rules.close();\n    }\n}"
  },
  {
    "path": "app/src/test/java/io/github/muntashirakon/AppManager/rules/compontents/ComponentUtilsTest.java",
    "content": "/*\n * SPDX-License-Identifier: GPL-3.0-or-later\n */\n\npackage io.github.muntashirakon.AppManager.rules.compontents;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.robolectric.RobolectricTestRunner;\n\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.util.HashMap;\n\nimport io.github.muntashirakon.AppManager.rules.RuleType;\nimport io.github.muntashirakon.io.Path;\nimport io.github.muntashirakon.io.Paths;\n\nimport static org.junit.Assert.assertEquals;\n\n@RunWith(RobolectricTestRunner.class)\npublic class ComponentUtilsTest {\n    private final ClassLoader classLoader = getClass().getClassLoader();\n\n    @Test\n    public void getIFWRulesForPackage() {\n        assert classLoader != null;\n        Path ifwDir = Paths.get(classLoader.getResource(\"ifw\").getFile());\n        HashMap<String, RuleType> expectedHashMap = getExpectedHashMap();\n        HashMap<String, RuleType> actualHashMap = ComponentUtils.getIFWRulesForPackage(\"sample.package\", ifwDir);\n        assertEquals(expectedHashMap.size(), actualHashMap.size());\n        for (String component : expectedHashMap.keySet()) {\n            assertEquals(expectedHashMap.get(component), actualHashMap.get(component));\n        }\n    }\n\n    @Test\n    public void readIFWRules() throws IOException {\n        assert classLoader != null;\n        File ifwFile = new File(classLoader.getResource(\"ifw\").getFile(), \"sample.package.xml\");\n        HashMap<String, RuleType> expectedHashMap = getExpectedHashMap();\n        HashMap<String, RuleType> actualHashMap;\n        try (InputStream is = new FileInputStream(ifwFile)) {\n            actualHashMap = ComponentUtils.readIFWRules(is, \"sample.package\");\n        }\n        assertEquals(expectedHashMap.size(), actualHashMap.size());\n        for (String component : expectedHashMap.keySet()) {\n            assertEquals(expectedHashMap.get(component), actualHashMap.get(component));\n        }\n    }\n\n    private HashMap<String, RuleType> getExpectedHashMap() {\n        return new HashMap<String, RuleType>(7) {\n            {\n                // Although we have short class names, the reader should return full class names\n                put(\"sample.package.NastyActivity\", RuleType.ACTIVITY);\n                put(\"sample.package.ad.AdActivity\", RuleType.ACTIVITY);\n                put(\"sample.package.log.CrashLogActivity\", RuleType.ACTIVITY);\n                put(\"sample.package.SystemBroadcastReceiver\", RuleType.RECEIVER);\n                put(\"sample.package.ThirdPartyReceiver\", RuleType.RECEIVER);\n                put(\"sample.package.MalwareService\", RuleType.SERVICE);\n                put(\"sample.package.AlwaysRunningLoggingService\", RuleType.SERVICE);\n            }\n        };\n    }\n}"
  },
  {
    "path": "app/src/test/java/io/github/muntashirakon/AppManager/rules/struct/RuleEntryTest.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.rules.struct;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.robolectric.RobolectricTestRunner;\n\nimport io.github.muntashirakon.AppManager.magisk.MagiskProcess;\nimport io.github.muntashirakon.AppManager.rules.RuleType;\nimport io.github.muntashirakon.AppManager.utils.FreezeUtils;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertTrue;\n\nimport android.app.AppOpsManager;\n\n@RunWith(RobolectricTestRunner.class)\npublic class RuleEntryTest {\n    private static final String PACKAGE_NAME = \"sample.package\";\n\n    @Test\n    public void flattenActivityToString() {\n        RuleEntry rule = new ComponentRule(PACKAGE_NAME, \".activity\", RuleType.ACTIVITY,\n                ComponentRule.COMPONENT_BLOCKED_IFW_DISABLE);\n        assertEquals(PACKAGE_NAME + \"\\t.activity\\tACTIVITY\\ttrue\", rule.flattenToString(true));\n        assertEquals(\".activity\\tACTIVITY\\ttrue\", rule.flattenToString(false));\n    }\n\n    @Test\n    public void flattenProviderToString() {\n        RuleEntry rule = new ComponentRule(PACKAGE_NAME, \".provider\", RuleType.PROVIDER,\n                ComponentRule.COMPONENT_TO_BE_BLOCKED_IFW_DISABLE);\n        assertEquals(PACKAGE_NAME + \"\\t.provider\\tPROVIDER\\tdis_false\", rule.flattenToString(true));\n        assertEquals(\".provider\\tPROVIDER\\tdis_false\", rule.flattenToString(false));\n    }\n\n    @Test\n    public void flattenReceiverToString() {\n        RuleEntry rule = new ComponentRule(PACKAGE_NAME, \".receiver\", RuleType.RECEIVER,\n                ComponentRule.COMPONENT_TO_BE_DEFAULTED);\n        assertEquals(PACKAGE_NAME + \"\\t.receiver\\tRECEIVER\\tunblocked\", rule.flattenToString(true));\n        assertEquals(\".receiver\\tRECEIVER\\tunblocked\", rule.flattenToString(false));\n    }\n\n    @Test\n    public void flattenServiceToString() {\n        RuleEntry rule = new ComponentRule(PACKAGE_NAME, \".service\", RuleType.SERVICE,\n                ComponentRule.COMPONENT_TO_BE_DEFAULTED);\n        assertEquals(PACKAGE_NAME + \"\\t.service\\tSERVICE\\tunblocked\", rule.flattenToString(true));\n        assertEquals(\".service\\tSERVICE\\tunblocked\", rule.flattenToString(false));\n    }\n\n    @Test\n    public void flattenAppOpToString() {\n        RuleEntry rule = new AppOpRule(PACKAGE_NAME, 55, AppOpsManager.MODE_DEFAULT);\n        assertEquals(PACKAGE_NAME + \"\\t55\\tAPP_OP\\t3\", rule.flattenToString(true));\n        assertEquals(\"55\\tAPP_OP\\t3\", rule.flattenToString(false));\n    }\n\n    @Test\n    public void flattenPermissionToString() {\n        RuleEntry rule = new PermissionRule(PACKAGE_NAME, \".permission\", true, 32);\n        assertEquals(PACKAGE_NAME + \"\\t.permission\\tPERMISSION\\ttrue\\t32\", rule.flattenToString(true));\n        assertEquals(\".permission\\tPERMISSION\\ttrue\\t32\", rule.flattenToString(false));\n    }\n\n    @Test\n    public void flattenMagiskHideToString() {\n        MagiskProcess mp = new MagiskProcess(PACKAGE_NAME, \"pkg:process\");\n        mp.setEnabled(true);\n        RuleEntry rule = new MagiskHideRule(mp);\n        assertEquals(PACKAGE_NAME + \"\\tpkg:process\\tMAGISK_HIDE\\ttrue\\tfalse\", rule.flattenToString(true));\n        assertEquals(\"pkg:process\\tMAGISK_HIDE\\ttrue\\tfalse\", rule.flattenToString(false));\n    }\n\n    @Test\n    public void flattenMagiskHideIsolatedToString() {\n        MagiskProcess mp = new MagiskProcess(PACKAGE_NAME, \"pkg:process\");\n        mp.setEnabled(true);\n        mp.setIsolatedProcess(true);\n        RuleEntry rule = new MagiskHideRule(mp);\n        assertEquals(PACKAGE_NAME + \"\\tpkg:process\\tMAGISK_HIDE\\ttrue\\ttrue\", rule.flattenToString(true));\n        assertEquals(\"pkg:process\\tMAGISK_HIDE\\ttrue\\ttrue\", rule.flattenToString(false));\n    }\n\n    @Test\n    public void flattenMagiskDenyListToString() {\n        MagiskProcess mp = new MagiskProcess(PACKAGE_NAME, \"pkg:process\");\n        mp.setEnabled(true);\n        RuleEntry rule = new MagiskDenyListRule(mp);\n        assertEquals(PACKAGE_NAME + \"\\tpkg:process\\tMAGISK_DENY_LIST\\ttrue\\tfalse\", rule.flattenToString(true));\n        assertEquals(\"pkg:process\\tMAGISK_DENY_LIST\\ttrue\\tfalse\", rule.flattenToString(false));\n    }\n\n    @Test\n    public void flattenMagiskDenyListIsolatedToString() {\n        MagiskProcess mp = new MagiskProcess(PACKAGE_NAME, \"pkg:process\");\n        mp.setEnabled(true);\n        mp.setIsolatedProcess(true);\n        RuleEntry rule = new MagiskDenyListRule(mp);\n        assertEquals(PACKAGE_NAME + \"\\tpkg:process\\tMAGISK_DENY_LIST\\ttrue\\ttrue\", rule.flattenToString(true));\n        assertEquals(\"pkg:process\\tMAGISK_DENY_LIST\\ttrue\\ttrue\", rule.flattenToString(false));\n    }\n\n    @Test\n    public void flattenBatteryOptToString() {\n        RuleEntry rule = new BatteryOptimizationRule(PACKAGE_NAME, true);\n        assertEquals(PACKAGE_NAME + \"\\tSTUB\\tBATTERY_OPT\\ttrue\", rule.flattenToString(true));\n        assertEquals(\"STUB\\tBATTERY_OPT\\ttrue\", rule.flattenToString(false));\n    }\n\n    @Test\n    public void flattenNetPolicyToString() {\n        RuleEntry rule = new NetPolicyRule(PACKAGE_NAME, 4);\n        assertEquals(PACKAGE_NAME + \"\\tSTUB\\tNET_POLICY\\t4\", rule.flattenToString(true));\n        assertEquals(\"STUB\\tNET_POLICY\\t4\", rule.flattenToString(false));\n    }\n\n    @Test\n    public void flattenNotificationListenerToString() {\n        RuleEntry rule = new NotificationListenerRule(PACKAGE_NAME, \".notif\", true);\n        assertEquals(PACKAGE_NAME + \"\\t.notif\\tNOTIFICATION\\ttrue\", rule.flattenToString(true));\n        assertEquals(\".notif\\tNOTIFICATION\\ttrue\", rule.flattenToString(false));\n    }\n\n    @Test\n    public void flattenSsaidToString() {\n        RuleEntry rule = new SsaidRule(PACKAGE_NAME, \"bc9948c6\");\n        assertEquals(PACKAGE_NAME + \"\\tSTUB\\tSSAID\\tbc9948c6\", rule.flattenToString(true));\n        assertEquals(\"STUB\\tSSAID\\tbc9948c6\", rule.flattenToString(false));\n    }\n\n    @Test\n    public void flattenFreezeToString() {\n        RuleEntry rule = new FreezeRule(PACKAGE_NAME, FreezeUtils.FREEZE_DISABLE);\n        assertEquals(PACKAGE_NAME + \"\\tSTUB\\tFREEZE\\t\" + FreezeUtils.FREEZE_DISABLE, rule.flattenToString(true));\n        assertEquals(\"STUB\\tFREEZE\\t\" + FreezeUtils.FREEZE_DISABLE, rule.flattenToString(false));\n    }\n\n    @Test\n    public void addPackageWithTab() {\n        ComponentRule rule = new ComponentRule(PACKAGE_NAME, \".activity\", RuleType.ACTIVITY,\n                ComponentRule.COMPONENT_BLOCKED_IFW_DISABLE);\n        assertEquals(PACKAGE_NAME + \"\\t\", rule.addPackageWithTab(true));\n        assertEquals(\"\", rule.addPackageWithTab(false));\n    }\n\n    @Test\n    public void unflattenActivityFromString() {\n        RuleEntry rule = new ComponentRule(PACKAGE_NAME, \".activity\", RuleType.ACTIVITY,\n                ComponentRule.COMPONENT_BLOCKED_IFW_DISABLE);\n        assertEquals(RuleEntry.unflattenFromString(null, PACKAGE_NAME + \"\\t.activity\\tACTIVITY\\ttrue\", true), rule);\n        assertEquals(RuleEntry.unflattenFromString(PACKAGE_NAME, PACKAGE_NAME + \"\\t.activity\\tACTIVITY\\ttrue\", true), rule);\n        assertEquals(RuleEntry.unflattenFromString(PACKAGE_NAME, \".activity\\tACTIVITY\\ttrue\", false), rule);\n    }\n\n    @Test\n    public void unflattenProviderFromString() {\n        RuleEntry rule = new ComponentRule(PACKAGE_NAME, \".provider\", RuleType.PROVIDER,\n                ComponentRule.COMPONENT_TO_BE_DISABLED);\n        assertEquals(RuleEntry.unflattenFromString(null, PACKAGE_NAME + \"\\t.provider\\tPROVIDER\\tfalse\", true), rule);\n        assertEquals(RuleEntry.unflattenFromString(PACKAGE_NAME, PACKAGE_NAME + \"\\t.provider\\tPROVIDER\\tfalse\", true), rule);\n        assertEquals(RuleEntry.unflattenFromString(PACKAGE_NAME, \".provider\\tPROVIDER\\tfalse\", false), rule);\n    }\n\n    @Test\n    public void unflattenReceiverFromString() {\n        RuleEntry rule = new ComponentRule(PACKAGE_NAME, \".receiver\", RuleType.RECEIVER,\n                ComponentRule.COMPONENT_TO_BE_DEFAULTED);\n        assertEquals(RuleEntry.unflattenFromString(null, PACKAGE_NAME + \"\\t.receiver\\tRECEIVER\\tunblocked\", true), rule);\n        assertEquals(RuleEntry.unflattenFromString(PACKAGE_NAME, PACKAGE_NAME + \"\\t.receiver\\tRECEIVER\\tunblocked\", true), rule);\n        assertEquals(RuleEntry.unflattenFromString(PACKAGE_NAME, \".receiver\\tRECEIVER\\tunblocked\", false), rule);\n    }\n\n    @Test\n    public void unflattenServiceFromString() {\n        RuleEntry rule = new ComponentRule(PACKAGE_NAME, \".service\", RuleType.SERVICE,\n                ComponentRule.COMPONENT_TO_BE_DEFAULTED);\n        assertEquals(RuleEntry.unflattenFromString(null, PACKAGE_NAME + \"\\t.service\\tSERVICE\\tunblocked\", true), rule);\n        assertEquals(RuleEntry.unflattenFromString(PACKAGE_NAME, PACKAGE_NAME + \"\\t.service\\tSERVICE\\tunblocked\", true), rule);\n        assertEquals(RuleEntry.unflattenFromString(PACKAGE_NAME, \".service\\tSERVICE\\tunblocked\", false), rule);\n    }\n\n    @Test\n    public void unflattenAppOpFromString() {\n        RuleEntry rule = new AppOpRule(PACKAGE_NAME, 55, AppOpsManager.MODE_DEFAULT);\n        assertEquals(RuleEntry.unflattenFromString(null, PACKAGE_NAME + \"\\t55\\tAPP_OP\\t3\", true), rule);\n        assertEquals(RuleEntry.unflattenFromString(PACKAGE_NAME, PACKAGE_NAME + \"\\t55\\tAPP_OP\\t3\", true), rule);\n        assertEquals(RuleEntry.unflattenFromString(PACKAGE_NAME, \"55\\tAPP_OP\\t3\", false), rule);\n    }\n\n    @Test\n    public void unflattenPermissionFromString() {\n        RuleEntry rule = new PermissionRule(PACKAGE_NAME, \".permission\", true, 32);\n        assertEquals(RuleEntry.unflattenFromString(null, PACKAGE_NAME + \"\\t.permission\\tPERMISSION\\ttrue\\t32\", true), rule);\n        assertEquals(RuleEntry.unflattenFromString(PACKAGE_NAME, PACKAGE_NAME + \"\\t.permission\\tPERMISSION\\ttrue\\t32\", true), rule);\n        assertEquals(RuleEntry.unflattenFromString(PACKAGE_NAME, \".permission\\tPERMISSION\\ttrue\\t32\", false), rule);\n    }\n\n    @Test\n    public void unflattenPermissionWithoutFlagsFromString() {\n        RuleEntry rule = new PermissionRule(PACKAGE_NAME, \".permission\", true, 0);\n        assertEquals(RuleEntry.unflattenFromString(null, PACKAGE_NAME + \"\\t.permission\\tPERMISSION\\ttrue\", true), rule);\n        assertEquals(RuleEntry.unflattenFromString(PACKAGE_NAME, PACKAGE_NAME + \"\\t.permission\\tPERMISSION\\ttrue\", true), rule);\n        assertEquals(RuleEntry.unflattenFromString(PACKAGE_NAME, \".permission\\tPERMISSION\\ttrue\", false), rule);\n    }\n\n    @Test\n    public void unflattenMagiskHideFromStringOld() {\n        MagiskProcess mp = new MagiskProcess(PACKAGE_NAME, PACKAGE_NAME);\n        mp.setEnabled(true);\n        RuleEntry rule = new MagiskHideRule(mp);\n        assertEquals(RuleEntry.unflattenFromString(null, PACKAGE_NAME + \"\\tSTUB\\tMAGISK_HIDE\\ttrue\", true), rule);\n        assertEquals(RuleEntry.unflattenFromString(PACKAGE_NAME, PACKAGE_NAME + \"\\tSTUB\\tMAGISK_HIDE\\ttrue\", true), rule);\n        assertEquals(RuleEntry.unflattenFromString(PACKAGE_NAME, \"STUB\\tMAGISK_HIDE\\ttrue\", false), rule);\n    }\n\n    @Test\n    public void unflattenMagiskHideFromStringNew() {\n        MagiskProcess mp = new MagiskProcess(PACKAGE_NAME, \"pkg:process\");\n        mp.setEnabled(true);\n        RuleEntry rule = new MagiskHideRule(mp);\n        assertEquals(RuleEntry.unflattenFromString(null, PACKAGE_NAME + \"\\tpkg:process\\tMAGISK_HIDE\\ttrue\", true), rule);\n        assertEquals(RuleEntry.unflattenFromString(PACKAGE_NAME, PACKAGE_NAME + \"\\tpkg:process\\tMAGISK_HIDE\\ttrue\", true), rule);\n        assertEquals(RuleEntry.unflattenFromString(PACKAGE_NAME, \"pkg:process\\tMAGISK_HIDE\\ttrue\", false), rule);\n    }\n\n    @Test\n    public void unflattenMagiskHideIsolatedFromString() {\n        MagiskProcess mp = new MagiskProcess(PACKAGE_NAME, \"pkg:process\");\n        mp.setEnabled(true);\n        mp.setIsolatedProcess(true);\n        RuleEntry rule = new MagiskHideRule(mp);\n        assertEquals(RuleEntry.unflattenFromString(null, PACKAGE_NAME + \"\\tpkg:process\\tMAGISK_HIDE\\ttrue\\ttrue\", true), rule);\n        assertEquals(RuleEntry.unflattenFromString(PACKAGE_NAME, PACKAGE_NAME + \"\\tpkg:process\\tMAGISK_HIDE\\ttrue\\ttrue\", true), rule);\n        assertEquals(RuleEntry.unflattenFromString(PACKAGE_NAME, \"pkg:process\\tMAGISK_HIDE\\ttrue\\ttrue\", false), rule);\n    }\n\n    @Test\n    public void unflattenMagiskDenyListFromString() {\n        MagiskProcess mp = new MagiskProcess(PACKAGE_NAME, \"pkg:process\");\n        mp.setEnabled(true);\n        RuleEntry rule = new MagiskDenyListRule(mp);\n        assertEquals(RuleEntry.unflattenFromString(null, PACKAGE_NAME + \"\\tpkg:process\\tMAGISK_DENY_LIST\\ttrue\", true), rule);\n        assertEquals(RuleEntry.unflattenFromString(PACKAGE_NAME, PACKAGE_NAME + \"\\tpkg:process\\tMAGISK_DENY_LIST\\ttrue\", true), rule);\n        assertEquals(RuleEntry.unflattenFromString(PACKAGE_NAME, \"pkg:process\\tMAGISK_DENY_LIST\\ttrue\", false), rule);\n    }\n\n    @Test\n    public void unflattenMagiskDenyListIsolatedFromString() {\n        MagiskProcess mp = new MagiskProcess(PACKAGE_NAME, \"pkg:process\");\n        mp.setEnabled(true);\n        mp.setIsolatedProcess(true);\n        RuleEntry rule = new MagiskDenyListRule(mp);\n        assertEquals(RuleEntry.unflattenFromString(null, PACKAGE_NAME + \"\\tpkg:process\\tMAGISK_DENY_LIST\\ttrue\\ttrue\", true), rule);\n        assertEquals(RuleEntry.unflattenFromString(PACKAGE_NAME, PACKAGE_NAME + \"\\tpkg:process\\tMAGISK_DENY_LIST\\ttrue\\ttrue\", true), rule);\n        assertEquals(RuleEntry.unflattenFromString(PACKAGE_NAME, \"pkg:process\\tMAGISK_DENY_LIST\\ttrue\\ttrue\", false), rule);\n    }\n\n    @Test\n    public void unflattenMagiskDenyListZygoteFromString() {\n        String processName = PACKAGE_NAME + \"_zygote\";\n        MagiskProcess mp = new MagiskProcess(PACKAGE_NAME, processName);\n        mp.setEnabled(true);\n        mp.setIsolatedProcess(true);\n        mp.setAppZygote(true);\n        RuleEntry rule = new MagiskDenyListRule(mp);\n        MagiskDenyListRule parsedRule = (MagiskDenyListRule) RuleEntry.unflattenFromString(null, PACKAGE_NAME + \"\\t\" + processName + \"\\tMAGISK_DENY_LIST\\ttrue\\ttrue\", true);\n        // Check if it automatically detects zygote process\n        assertTrue(parsedRule.getMagiskProcess().isAppZygote());\n        assertEquals(parsedRule, rule);\n        assertEquals(RuleEntry.unflattenFromString(PACKAGE_NAME, PACKAGE_NAME + \"\\t\" + processName + \"\\tMAGISK_DENY_LIST\\ttrue\\ttrue\", true), rule);\n        assertEquals(RuleEntry.unflattenFromString(PACKAGE_NAME, processName + \"\\tMAGISK_DENY_LIST\\ttrue\\ttrue\", false), rule);\n    }\n\n    @Test\n    public void unflattenBatteryOptFromString() {\n        RuleEntry rule = new BatteryOptimizationRule(PACKAGE_NAME, true);\n        assertEquals(RuleEntry.unflattenFromString(null, PACKAGE_NAME + \"\\tSTUB\\tBATTERY_OPT\\ttrue\", true), rule);\n        assertEquals(RuleEntry.unflattenFromString(PACKAGE_NAME, PACKAGE_NAME + \"\\tSTUB\\tBATTERY_OPT\\ttrue\", true), rule);\n        assertEquals(RuleEntry.unflattenFromString(PACKAGE_NAME, \"STUB\\tBATTERY_OPT\\ttrue\", false), rule);\n    }\n\n    @Test\n    public void unflattenNetPolicyFromString() {\n        RuleEntry rule = new NetPolicyRule(PACKAGE_NAME, 4);\n        assertEquals(RuleEntry.unflattenFromString(null, PACKAGE_NAME + \"\\tSTUB\\tNET_POLICY\\t4\", true), rule);\n        assertEquals(RuleEntry.unflattenFromString(PACKAGE_NAME, PACKAGE_NAME + \"\\tSTUB\\tNET_POLICY\\t4\", true), rule);\n        assertEquals(RuleEntry.unflattenFromString(PACKAGE_NAME, \"STUB\\tNET_POLICY\\t4\", false), rule);\n    }\n\n    @Test\n    public void unflattenNotificationListenerFromString() {\n        RuleEntry rule = new NotificationListenerRule(PACKAGE_NAME, \".notif\", true);\n        assertEquals(RuleEntry.unflattenFromString(null, PACKAGE_NAME + \"\\t.notif\\tNOTIFICATION\\ttrue\", true), rule);\n        assertEquals(RuleEntry.unflattenFromString(PACKAGE_NAME, PACKAGE_NAME + \"\\t.notif\\tNOTIFICATION\\ttrue\", true), rule);\n        assertEquals(RuleEntry.unflattenFromString(PACKAGE_NAME, \".notif\\tNOTIFICATION\\ttrue\", false), rule);\n    }\n\n    @Test\n    public void unflattenSsaidFromString() {\n        RuleEntry rule = new SsaidRule(PACKAGE_NAME, \"bc9948c6\");\n        assertEquals(RuleEntry.unflattenFromString(null, PACKAGE_NAME + \"\\tSTUB\\tSSAID\\tbc9948c6\", true), rule);\n        assertEquals(RuleEntry.unflattenFromString(PACKAGE_NAME, PACKAGE_NAME + \"\\tSTUB\\tSSAID\\tbc9948c6\", true), rule);\n        assertEquals(RuleEntry.unflattenFromString(PACKAGE_NAME, \"STUB\\tSSAID\\tbc9948c6\", false), rule);\n    }\n\n    @Test\n    public void unflattenFreezeFromString() {\n        RuleEntry rule = new FreezeRule(PACKAGE_NAME, FreezeUtils.FREEZE_DISABLE);\n        assertEquals(RuleEntry.unflattenFromString(null, PACKAGE_NAME + \"\\tSTUB\\tFREEZE\\t\" + FreezeUtils.FREEZE_DISABLE, true), rule);\n        assertEquals(RuleEntry.unflattenFromString(PACKAGE_NAME, PACKAGE_NAME + \"\\tSTUB\\tFREEZE\\t\" + FreezeUtils.FREEZE_DISABLE, true), rule);\n        assertEquals(RuleEntry.unflattenFromString(PACKAGE_NAME, \"STUB\\tFREEZE\\t\" + FreezeUtils.FREEZE_DISABLE, false), rule);\n    }\n}"
  },
  {
    "path": "app/src/test/java/io/github/muntashirakon/AppManager/runningapps/ProcessParserTest.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.runningapps;\n\nimport static org.junit.Assert.assertEquals;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.robolectric.RobolectricTestRunner;\n\nimport java.util.HashMap;\nimport java.util.Objects;\n\nimport io.github.muntashirakon.io.Path;\nimport io.github.muntashirakon.io.Paths;\n\n@RunWith(RobolectricTestRunner.class)\npublic class ProcessParserTest {\n    private final ClassLoader classLoader = getClass().getClassLoader();\n\n    @Test\n    public void parse() {\n        assert classLoader != null;\n        Path procDir = Paths.get(classLoader.getResource(\"proc\").getFile());\n        ProcessParser pp = new ProcessParser();\n        HashMap<Integer, String> processStrings = new HashMap<Integer, String>(5) {\n            {\n                put(1129, \"ProcessItem{pid=1129, ppid=1, rss=380, user='1000', uid=1000, state='S', state_extra='',\" +\n                        \" name='ATFWD-daemon', context='u:r:atfwd:s0'}\");\n                put(11, \"ProcessItem{pid=11, ppid=2, rss=0, user='0', uid=0, state='S', state_extra='',\" +\n                        \" name='rcuos/0', context='u:r:kernel:s0'}\");\n                put(11547, \"ProcessItem{pid=11547, ppid=2, rss=0, user='0', uid=0, state='S', state_extra='',\" +\n                        \" name='kworker/u16:4', context='u:r:kernel:s0'}\");\n                put(123, \"ProcessItem{pid=123, ppid=2, rss=0, user='0', uid=0, state='S', state_extra='',\" +\n                        \" name='irq/33-bcl_vbat', context='u:r:kernel:s0'}\");\n                put(1101, \"ProcessItem{pid=1101, ppid=1, rss=981, user='1046', uid=1046, state='S', state_extra='',\" +\n                        \" name='media.swcodec', context='u:r:mediaswcodec:s0'}\");\n            }\n        };\n        HashMap<Integer, ProcessItem> processItemHashMap = pp.parse(procDir);\n        for (int pid : processItemHashMap.keySet()) {\n            assertEquals(processStrings.get(pid), Objects.requireNonNull(processItemHashMap.get(pid)).toString());\n        }\n    }\n}"
  },
  {
    "path": "app/src/test/java/io/github/muntashirakon/AppManager/scanner/vt/VirusTotalTest.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.scanner.vt;\n\nimport org.junit.Before;\nimport org.junit.Test;\n\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.IOException;\n\nimport io.github.muntashirakon.AppManager.backup.convert.OABConverter;\n\npublic class VirusTotalTest {\n    private static final String API_KEY = null;\n    private final ClassLoader classLoader = getClass().getClassLoader();\n    private VirusTotal vt;\n\n    @Before\n    public void setUp() throws Exception {\n        if (API_KEY == null) return;\n        vt = new VirusTotal(API_KEY);\n    }\n\n    @Test\n    public void uploadFileThrowsNothing() throws IOException {\n        if (vt == null) return;\n        assert classLoader != null;\n        File baseApk = new File(classLoader.getResource(OABConverter.PATH_SUFFIX).getFile(), \"dnsfilter.android/base.apk\");\n        try (FileInputStream fis = new FileInputStream(baseApk)) {\n            VirusTotal.ResponseV3<String> vtFileScanMeta = vt.uploadFile(\"dnsfilter.android\", fis);\n            System.out.println(vtFileScanMeta);\n        }\n    }\n\n    @Test\n    public void fetchFileReportThrowsNothing() throws IOException {\n        if (vt == null) return;\n        VtFileReport report1 = vt.fetchFileReport(\"029e2ed8dea7db94a293bdb7c0d197059f85d4dc51b6ff56548b29b65afe13c5\").response;\n        VtFileReport report2 = vt.fetchFileReport(\"a5146a143c7bbd6a0b8384a1aa233243b72cca94cbec62aa3d70a82f5b262550\").response;\n        // Throws nothing\n        System.out.println(report1);\n        System.out.println(report2);\n    }\n}\n"
  },
  {
    "path": "app/src/test/java/io/github/muntashirakon/AppManager/ssaid/SsaidSettingsTest.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.ssaid;\n\nimport static org.junit.Assert.*;\n\nimport org.junit.Before;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.robolectric.RobolectricTestRunner;\n\nimport java.io.IOException;\n\nimport io.github.muntashirakon.io.IoUtils;\nimport io.github.muntashirakon.io.Path;\nimport io.github.muntashirakon.io.Paths;\n\n@RunWith(RobolectricTestRunner.class)\npublic class SsaidSettingsTest {\n    private final ClassLoader classLoader = getClass().getClassLoader();\n    private Path ssaidLocation;\n\n    @Before\n    public void setUp() {\n        ssaidLocation = Paths.get(classLoader.getResource(\"xml/settings_ssaid.xml\").getFile());\n    }\n\n    @Test\n    public void testGetSsaid() throws IOException {\n        SsaidSettings settings = new SsaidSettings(ssaidLocation, 0);\n        assertEquals(\"A1F3C47E89D45B60C29E70A3F58D92E11B6AD02C78FE4D50937CA1B446E98F12\", settings.getSsaid(\"android\", 1000));\n        assertEquals(\"3E9B72CDA48150F4\", settings.getSsaid(\"com.google.android.gms\", 10123));\n        assertEquals(\"3E9B72CDA48150F4\", settings.getSsaid(\"com.android.vending\", 10124));\n        assertEquals(\"3E9B72CDA48150F4\", settings.getSsaid(\"com.android.chrome\", 10125));\n        assertEquals(\"9F4C3A7E21D86B52\", settings.getSsaid(\"com.whatsapp\", 10126));\n    }\n\n    @Test\n    public void testSetSsaid() throws IOException {\n        Path tmpSsaidLocation = Paths.get(\"/tmp/settings_ssaid.xml\");\n        try {\n            IoUtils.copy(ssaidLocation, tmpSsaidLocation);\n            SsaidSettings settings = new SsaidSettings(tmpSsaidLocation, 0);\n            assertEquals(\"9F4C3A7E21D86B52\", settings.getSsaid(\"com.whatsapp\", 10126));\n            settings.setSsaid(\"com.whatsapp\", 10126, \"4CAF91D267B8E3A5\");\n            assertEquals(\"4CAF91D267B8E3A5\", settings.getSsaid(\"com.whatsapp\", 10126));\n            // Check if the changes have persisted\n            SsaidSettings settings2 = new SsaidSettings(tmpSsaidLocation, 0);\n            assertEquals(\"4CAF91D267B8E3A5\", settings2.getSsaid(\"com.whatsapp\", 10126));\n        } finally {\n            tmpSsaidLocation.delete();\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/test/java/io/github/muntashirakon/AppManager/utils/BitmapRandomizerTest.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.utils;\n\nimport static org.junit.Assert.*;\nimport android.graphics.Bitmap;\nimport android.graphics.BitmapFactory;\nimport android.graphics.Color;\nimport org.junit.Before;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.robolectric.RobolectricTestRunner;\n\nimport java.io.InputStream;\n\nimport io.github.muntashirakon.io.Paths;\n\n@RunWith(RobolectricTestRunner.class)\npublic class BitmapRandomizerTest {\n    private final ClassLoader classLoader = getClass().getClassLoader();\n    private Bitmap bitmap;\n\n    @Before\n    public void setUp() throws Exception {\n        assert classLoader != null;\n        // Load test_icon.png as mutable Bitmap\n        try (InputStream is = Paths.get(classLoader.getResource(\"images/test_icon.png\").getFile()).openInputStream()) {\n            Bitmap original = BitmapFactory.decodeStream(is);\n            bitmap = original.copy(Bitmap.Config.ARGB_8888, true);\n        }\n\n        assertNotNull(bitmap);\n        assertTrue(bitmap.isMutable());\n    }\n\n    @Test\n    public void testRandomizePixelChangesPixelColor() {\n        int width = bitmap.getWidth();\n        int height = bitmap.getHeight();\n\n        // Store original bitmap copy for pixel color comparison\n        Bitmap originalCopy = bitmap.copy(Bitmap.Config.ARGB_8888, false);\n\n        boolean pixelChanged = false;\n        boolean msbFlipped = false;\n\n        // Run multiple times to test different random pixels\n        for (int i = 0; i < 10; i++) {\n            BitmapRandomizer.randomizePixel(bitmap);\n\n            // Find pixel locations changed by comparing with originalCopy\n            for (int x = 0; x < width && !pixelChanged; x++) {\n                for (int y = 0; y < height && !pixelChanged; y++) {\n                    int origColor = originalCopy.getPixel(x, y);\n                    int modColor = bitmap.getPixel(x, y);\n                    if (origColor != modColor) {\n                        pixelChanged = true;\n\n                        // Extract RGB channels\n                        int origRed = Color.red(origColor);\n                        int origGreen = Color.green(origColor);\n                        int origBlue = Color.blue(origColor);\n\n                        int modRed = Color.red(modColor);\n                        int modGreen = Color.green(modColor);\n                        int modBlue = Color.blue(modColor);\n\n                        // Check for flipped bits in upper half (bits 4 to 7) for any channel\n                        if (checkUpperHalfBitsFlipped(origRed, modRed) ||\n                            checkUpperHalfBitsFlipped(origGreen, modGreen) ||\n                            checkUpperHalfBitsFlipped(origBlue, modBlue)) {\n                            msbFlipped = true;\n                        }\n                    }\n                }\n            }\n        }\n\n        assertTrue(\"At least one pixel color should be changed\", pixelChanged);\n        assertTrue(\"At least one upper half bit (bits 4-7) should be flipped\", msbFlipped);\n    }\n\n    private boolean checkUpperHalfBitsFlipped(int original, int modified) {\n        // Focus on bits 4-7 mask: 0b11110000 = 0xF0\n        int originalMasked = original & 0xF0;\n        int modifiedMasked = modified & 0xF0;\n        return (originalMasked ^ modifiedMasked) != 0;\n    }\n}\n"
  },
  {
    "path": "app/src/test/java/io/github/muntashirakon/AppManager/utils/RoboUtils.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.utils;\n\nimport androidx.annotation.NonNull;\n\nimport java.io.File;\nimport java.util.Objects;\n\npublic class RoboUtils {\n    @NonNull\n    public static File getTestBaseDir() {\n        return Objects.requireNonNull(ContextUtils.getContext().getDataDir().getParentFile());\n    }\n}\n"
  },
  {
    "path": "app/src/test/java/io/github/muntashirakon/AppManager/utils/TarUtilsTest.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.utils;\n\nimport static org.junit.Assert.assertArrayEquals;\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertNotEquals;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.VisibleForTesting;\n\nimport org.apache.commons.compress.archivers.ArchiveEntry;\nimport org.apache.commons.compress.archivers.tar.TarArchiveInputStream;\nimport org.apache.commons.compress.compressors.gzip.GzipCompressorInputStream;\nimport org.junit.After;\nimport org.junit.Before;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.robolectric.RobolectricTestRunner;\n\nimport java.io.BufferedInputStream;\nimport java.io.File;\nimport java.io.FileNotFoundException;\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\n\nimport io.github.muntashirakon.io.IoUtils;\nimport io.github.muntashirakon.io.Path;\nimport io.github.muntashirakon.io.Paths;\nimport io.github.muntashirakon.io.SplitInputStream;\n\n@RunWith(RobolectricTestRunner.class)\npublic class TarUtilsTest {\n    private final ClassLoader classLoader = getClass().getClassLoader();\n    private Path testRoot;\n    private Path tmpRoot;\n    private Path[] tarGzFilesForExtractTest;\n\n    @Before\n    public void setUp() throws Throwable {\n        assert classLoader != null;\n        List<Path> resFiles = new ArrayList<>();\n        resFiles.add(Paths.get(classLoader.getResource(\"plain.txt\").getFile()));\n        resFiles.add(Paths.get(classLoader.getResource(\"raw/exclude.txt\").getFile()));\n        resFiles.add(Paths.get(classLoader.getResource(\"raw/include.txt\").getFile()));\n        resFiles.add(Paths.get(classLoader.getResource(\"prefixed/prefixed_exclude.txt\").getFile()));\n        resFiles.add(Paths.get(classLoader.getResource(\"prefixed/prefixed_include.txt\").getFile()));\n        tmpRoot = Paths.get(\"/tmp\");\n        List<Path> tmpFiles = new ArrayList<>();\n        testRoot = tmpRoot.findOrCreateDirectory(\"test\");\n        testRoot.findOrCreateDirectory(\"raw\");\n        testRoot.findOrCreateDirectory(\"prefixed\");\n        tmpFiles.add(testRoot.findOrCreateFile(\"plain.txt\", null));\n        tmpFiles.add(testRoot.findOrCreateDirectory(\"raw\").findOrCreateFile(\"exclude.txt\", null));\n        tmpFiles.add(testRoot.findOrCreateDirectory(\"raw\").findOrCreateFile(\"include.txt\", null));\n        tmpFiles.add(testRoot.findOrCreateDirectory(\"prefixed\").findOrCreateFile(\"prefixed_exclude.txt\", null));\n        tmpFiles.add(testRoot.findOrCreateDirectory(\"prefixed\").findOrCreateFile(\"prefixed_include.txt\", null));\n        // Copy files to tmpRoot\n        for (int i = 0; i < resFiles.size(); ++i) {\n            IoUtils.copy(resFiles.get(i), tmpFiles.get(i));\n        }\n        tarGzFilesForExtractTest = TarUtils.create(TarUtils.TAR_GZIP, testRoot, tmpRoot, \"am_ex.tar.gz\",\n                null, null, null, false).toArray(new Path[0]);\n    }\n\n    @After\n    public void tearDown() throws FileNotFoundException {\n        testRoot.delete();\n        tarGzFilesForExtractTest[0].delete();\n        if (tmpRoot.hasFile(\"am.tar.gz.0\")) {\n            tmpRoot.findFile(\"am.tar.gz.0\").delete();\n        }\n    }\n\n    @Test\n    public void testCreateTarGZipWithFilter() throws Throwable {\n        createTest(tmpRoot, testRoot, /* language=regexp */ new String[]{\".*include\\\\.txt\"}, null,\n                Arrays.asList(\"prefixed/\", \"prefixed/prefixed_include.txt\", \"raw/\", \"raw/include.txt\"));\n    }\n\n    @Test\n    public void testExtractTarGZipWithFilter() throws Throwable {\n        extractTest(tarGzFilesForExtractTest, testRoot, /* language=regexp */ new String[]{\".*include\\\\.txt\"},\n                null, Arrays.asList(\"\", \"prefixed/\", \"prefixed/prefixed_include.txt\", \"raw/\", \"raw/include.txt\"));\n    }\n\n    @Test\n    public void testCreateTarGZipWithDirectoryFilter() throws Throwable {\n        createTest(tmpRoot, testRoot, /* language=regexp */ new String[]{\"prefixed/.*\"}, null,\n                Arrays.asList(\"prefixed/\", \"prefixed/prefixed_include.txt\", \"prefixed/prefixed_exclude.txt\"));\n    }\n\n    @Test\n    public void testExtractTarGZipWithDirectoryFilter() throws Throwable {\n        extractTest(tarGzFilesForExtractTest, testRoot, /* language=regexp */ new String[]{\"prefixed/.*\"}, null,\n                Arrays.asList(\"\", \"prefixed/\", \"prefixed/prefixed_include.txt\", \"prefixed/prefixed_exclude.txt\", \"raw/\"));\n    }\n\n    @Test\n    public void testCreateTarGZipWithMultipleFilters() throws Throwable {\n        createTest(tmpRoot, testRoot, /* language=regexp */ new String[]{\".*include\\\\.txt\", \"plain.*\"}, null,\n                Arrays.asList(\"prefixed/\", \"prefixed/prefixed_include.txt\", \"plain.txt\", \"raw/\", \"raw/include.txt\"));\n    }\n\n    @Test\n    public void testExtractTarGZipWithMultipleFilters() throws Throwable {\n        extractTest(tarGzFilesForExtractTest, testRoot, /* language=regexp */new String[]{\".*include\\\\.txt\", \"plain.*\"},\n                null, Arrays.asList(\"\", \"prefixed/\", \"prefixed/prefixed_include.txt\", \"plain.txt\", \"raw/\",\n                        \"raw/include.txt\"));\n    }\n\n    @Test\n    public void testCreateTarGZipWithDirectoryAndMultipleFilters() throws Throwable {\n        createTest(tmpRoot, testRoot, /* language=regexp */ new String[]{\".*include\\\\.txt\", \"plain.*\", \"prefixed/.*\"},\n                null, Arrays.asList(\"prefixed/\", \"prefixed/prefixed_include.txt\",\n                        \"prefixed/prefixed_exclude.txt\", \"plain.txt\", \"raw/\", \"raw/include.txt\"));\n    }\n\n    @Test\n    public void testExtractTarGZipWithDirectoryAndMultipleFilters() throws Throwable {\n        extractTest(tarGzFilesForExtractTest, testRoot, /* language=regexp */ new String[]{\".*include\\\\.txt\", \"plain.*\",\n                \"prefixed/.*\"}, null, Arrays.asList(\"\", \"prefixed/\", \"prefixed/prefixed_include.txt\",\n                \"prefixed/prefixed_exclude.txt\", \"plain.txt\", \"raw/\", \"raw/include.txt\"));\n    }\n\n    @Test\n    public void testCreateTarGZipWithExclude() throws Throwable {\n        createTest(tmpRoot, testRoot, null, /* language=regexp */ new String[]{\".*exclude\\\\.txt\"},\n                Arrays.asList(\"prefixed/\", \"prefixed/prefixed_include.txt\", \"plain.txt\", \"raw/\", \"raw/include.txt\"));\n    }\n\n    @Test\n    public void testExtractTarGZipWithExclude() throws Throwable {\n        extractTest(tarGzFilesForExtractTest, testRoot, null, /* language=regexp */\n                new String[]{\".*exclude\\\\.txt\"}, Arrays.asList(\"\", \"prefixed/\", \"prefixed/prefixed_include.txt\",\n                        \"plain.txt\", \"raw/\", \"raw/include.txt\"));\n    }\n\n    @Test\n    public void testCreateTarGZipWithExcludeDirectory() throws Throwable {\n        createTest(tmpRoot, testRoot, null, /* language=regexp */ new String[]{\"raw/.*\"}, Arrays.asList(\n                \"prefixed/\", \"prefixed/prefixed_include.txt\", \"prefixed/prefixed_exclude.txt\", \"plain.txt\"));\n    }\n\n    @Test\n    public void testExtractTarGZipWithExcludeDirectory() throws Throwable {\n        extractTest(tarGzFilesForExtractTest, testRoot, null, /* language=regexp */ new String[]{\"raw/.*\"},\n                Arrays.asList(\"\", \"prefixed/\", \"prefixed/prefixed_include.txt\", \"prefixed/prefixed_exclude.txt\",\n                        \"plain.txt\", \"raw/\"));\n    }\n\n    @Test\n    public void testCreateTarGZipWithMultipleExcludes() throws Throwable {\n        createTest(tmpRoot, testRoot, null, /* language=regexp */ new String[]{\".*exclude\\\\.txt\", \"plain.*\"},\n                Arrays.asList(\"prefixed/\", \"prefixed/prefixed_include.txt\", \"raw/\", \"raw/include.txt\"));\n    }\n\n    @Test\n    public void testExtractTarGZipWithMultipleExcludes() throws Throwable {\n        extractTest(tarGzFilesForExtractTest, testRoot, null, /* language=regexp */\n                new String[]{\".*exclude\\\\.txt\", \"plain.*\"}, Arrays.asList(\"\", \"prefixed/\",\n                        \"prefixed/prefixed_include.txt\", \"raw/\", \"raw/include.txt\"));\n    }\n\n    @Test\n    public void testCreateTarGZipWithDirectoryAndMultipleExcludes() throws Throwable {\n        createTest(tmpRoot, testRoot, null, /* language=regexp */ new String[]{\".*exclude\\\\.txt\", \"plain.*\",\n                \"raw/.*\"}, Arrays.asList(\"prefixed/\", \"prefixed/prefixed_include.txt\"));\n    }\n\n    @Test\n    public void testExtractTarGZipWithDirectoryAndMultipleExcludes() throws Throwable {\n        extractTest(tarGzFilesForExtractTest, testRoot, null, /* language=regexp */\n                new String[]{\".*exclude\\\\.txt\", \"plain.*\", \"raw/.*\"}, Arrays.asList(\"\", \"prefixed/\",\n                        \"prefixed/prefixed_include.txt\", \"raw/\"));\n    }\n\n    @Test\n    public void testCreateTarGZipWithFilterAndExclude() throws Throwable {\n        createTest(tmpRoot, testRoot, /* language=regexp */ new String[]{\".*\\\\.txt\"}, /* language=regexp */\n                new String[]{\".*exclude\\\\.txt\"}, Arrays.asList(\"prefixed/\", \"prefixed/prefixed_include.txt\",\n                        \"plain.txt\", \"raw/\", \"raw/include.txt\"));\n    }\n\n    @Test\n    public void testExtractTarGZipWithFilterAndExclude() throws Throwable {\n        extractTest(tarGzFilesForExtractTest, testRoot, /* language=regexp */ new String[]{\".*\\\\.txt\"},\n                /* language=regexp */new String[]{\".*exclude\\\\.txt\"}, Arrays.asList(\"\", \"prefixed/\",\n                        \"prefixed/prefixed_include.txt\", \"plain.txt\", \"raw/\", \"raw/include.txt\"));\n    }\n\n    @Test\n    public void testCreateTarGZipWithFilterAndExcludeContainingDirectory() throws Throwable {\n        createTest(tmpRoot, testRoot, /* language=regexp */ new String[]{\".*\\\\.txt\", \"include/.*\"},\n                /* language=regexp */ new String[]{\".*exclude\\\\.txt\", \"raw/.*\"}, Arrays.asList(\"prefixed/\",\n                        \"prefixed/prefixed_include.txt\", \"plain.txt\"));\n    }\n\n    @Test\n    public void testExtractTarGZipWithFilterAndExcludeContainingDirectory() throws Throwable {\n        extractTest(tarGzFilesForExtractTest, testRoot, /* language=regexp */ new String[]{\".*\\\\.txt\", \"include/.*\"},\n                /* language=regexp */ new String[]{\".*exclude\\\\.txt\", \"raw/.*\"}, Arrays.asList(\"\", \"prefixed/\",\n                        \"prefixed/prefixed_include.txt\", \"plain.txt\", \"raw/\"));\n    }\n\n    @Test\n    public void testCreateTarGZipWithNoFiltersOrExcludes() throws Throwable {\n        createTest(tmpRoot, testRoot, null, null, Arrays.asList(\"prefixed/\",\n                \"prefixed/prefixed_include.txt\", \"prefixed/prefixed_exclude.txt\", \"plain.txt\", \"raw/\",\n                \"raw/include.txt\", \"raw/exclude.txt\"));\n    }\n\n    @Test\n    public void testExtractTarGZipWithNoFiltersOrExcludes() throws Throwable {\n        extractTest(tarGzFilesForExtractTest, testRoot, null, null, Arrays.asList(\"\", \"prefixed/\",\n                \"prefixed/prefixed_include.txt\", \"prefixed/prefixed_exclude.txt\", \"plain.txt\", \"raw/\",\n                \"raw/include.txt\", \"raw/exclude.txt\"));\n    }\n\n    @Test\n    public void testGetRelativePath() {\n        File basePath = new File(\"/data/data/package.name\");\n        File[] absolutes = new File[]{\n                new File(basePath, \"app_lib\"),\n                new File(basePath, \"app_webview\"),\n                new File(basePath, \"app_webview/variations_seed_new\"),\n                new File(basePath, \"app_webview/pref_store\"),\n                new File(basePath, \"app_webview/webview_data.lock\"),\n                new File(basePath, \"app_webview/variations_stamp\"),\n                new File(basePath, \"app_webview/variations_seed\"),\n                new File(basePath, \"app_webview/Default\"),\n                new File(basePath, \"app_webview/Default/Session Storage\"),\n                new File(basePath, \"app_webview/Default/Session Storage\"),\n                new File(basePath, \"app_webview/Default/Session Storage/CURRENT\"),\n                new File(basePath, \"app_webview/Default/Session Storage/LOG\"),\n                new File(basePath, \"app_webview/Default/Session Storage/MANIFEST-000001\"),\n                new File(basePath, \"app_webview/Default/Session Storage/000003.log\"),\n                new File(basePath, \"app_webview/Default/Session Storage/LOCK\"),\n                new File(basePath, \"app_webview/Default/Web Data-journal\"),\n                new File(basePath, \"app_webview/Default/blob_storage\"),\n        };\n        String[] expectedPaths = new String[]{\n                \"app_lib\",\n                \"app_webview\",\n                \"app_webview/variations_seed_new\",\n                \"app_webview/pref_store\",\n                \"app_webview/webview_data.lock\",\n                \"app_webview/variations_stamp\",\n                \"app_webview/variations_seed\",\n                \"app_webview/Default\",\n                \"app_webview/Default/Session Storage\",\n                \"app_webview/Default/Session Storage\",\n                \"app_webview/Default/Session Storage/CURRENT\",\n                \"app_webview/Default/Session Storage/LOG\",\n                \"app_webview/Default/Session Storage/MANIFEST-000001\",\n                \"app_webview/Default/Session Storage/000003.log\",\n                \"app_webview/Default/Session Storage/LOCK\",\n                \"app_webview/Default/Web Data-journal\",\n                \"app_webview/Default/blob_storage\",\n        };\n        String[] actualPaths = new String[expectedPaths.length];\n        for (int i = 0; i < actualPaths.length; ++i) {\n            actualPaths[i] = getRelativePath(absolutes[i], basePath, \"/\");\n        }\n        assertArrayEquals(expectedPaths, actualPaths);\n    }\n\n    @Test\n    public void testGetRelativePathsUnix() {\n        assertEquals(\"stuff/xyz.dat\", getRelativePath(new File(\"/var/data/stuff/xyz.dat\"),\n                new File(\"/var/data/\"), \"/\"));\n        assertEquals(\"../../b/c\", getRelativePath(new File(\"/a/b/c\"),\n                new File(\"/a/x/y/\"), \"/\"));\n        assertEquals(\"../../b/c\", getRelativePath(new File(\"/m/n/o/a/b/c\"),\n                new File(\"/m/n/o/a/x/y/\"), \"/\"));\n    }\n\n    @Test\n    public void testGetRelativePathFileToFileDoesNotWork() {\n        File target = new File(\"C:\\\\Windows\\\\Boot\\\\Fonts\\\\chs_boot.ttf\");\n        File base = new File(\"C:\\\\Windows\\\\Speech\\\\Common\\\\sapisvr.exe\");\n        File workingBase = new File(\"C:\\\\Windows\\\\Speech\\\\Common\\\\\");\n\n        assertNotEquals(\"..\\\\..\\\\Boot\\\\Fonts\\\\chs_boot.ttf\", getRelativePath(target, base, \"\\\\\"));\n        assertEquals(\"..\\\\..\\\\Boot\\\\Fonts\\\\chs_boot.ttf\", getRelativePath(target, workingBase, \"\\\\\"));\n    }\n\n    @Test\n    public void testGetRelativePathDirectoryToFile() {\n        File target = new File(\"C:\\\\Windows\\\\Boot\\\\Fonts\\\\chs_boot.ttf\");\n        File base = new File(\"C:\\\\Windows\\\\Speech\\\\Common\\\\\");\n\n        assertEquals(\"..\\\\..\\\\Boot\\\\Fonts\\\\chs_boot.ttf\", getRelativePath(target, base, \"\\\\\"));\n    }\n\n    @Test\n    public void testGetRelativePathFileToDirectoryDoesNotWork() {\n        File target = new File(\"C:\\\\Windows\\\\Boot\\\\Fonts\");\n        File base = new File(\"C:\\\\Windows\\\\Speech\\\\Common\\\\foo.txt\");\n        File workingBase = new File(\"C:\\\\Windows\\\\Speech\\\\Common\\\\\");\n\n        assertNotEquals(\"..\\\\..\\\\Boot\\\\Fonts\", getRelativePath(target, base, \"\\\\\"));\n        assertEquals(\"..\\\\..\\\\Boot\\\\Fonts\", getRelativePath(target, workingBase, \"\\\\\"));\n    }\n\n    @Test\n    public void testGetRelativePathFileToDirectory2DoesNotWork() {\n        File target = new File(\"C:\\\\Windows\\\\Boot\\\\Fonts\");\n        File base = new File(\"C:\\\\foo.txt\");\n        File workingBase = new File(\"C:\\\\\");\n\n        assertNotEquals(\"Windows\\\\Boot\\\\Fonts\", getRelativePath(target, base, \"\\\\\"));\n        assertEquals(\"Windows\\\\Boot\\\\Fonts\", getRelativePath(target, workingBase, \"\\\\\"));\n    }\n\n    @Test\n    public void testGetRelativePathDirectoryToDirectory() {\n        File target = new File(\"C:\\\\Windows\\\\Boot\\\\\");\n        File base = new File(\"C:\\\\Windows\\\\Speech\\\\Common\\\\\");\n        String expected = \"..\\\\..\\\\Boot\\\\\";\n\n        String relPath = getRelativePath(target, base, \"\\\\\");\n        assertEquals(expected, relPath);\n    }\n\n    @Test\n    public void testGetRelativePathDifferentDriveLetters() {\n        File target = new File(\"D:\\\\sources\\\\recovery\\\\RecEnv.exe\");\n        File base = new File(\"C:\\\\Java\\\\workspace\\\\AcceptanceTests\\\\Standard test data\\\\geo\\\\\");\n        assertEquals(target.getAbsolutePath(), getRelativePath(target, base, \"\\\\\"));\n    }\n\n    @Test\n    public void testGetAbsolutePathToDataApp() {\n        String[] brokenPaths = new String[]{\n                \"/data/app\",\n                \"/data/app/\",\n                \"/data/app/example.app\",\n                \"/data/app/example.app/\",\n                \"/data/app/example.app/lib\",\n                \"/data/app/example.app/lib/\",\n                \"/data/app/example.app/oat\",\n                \"/data/app/example.app/base.apk\",\n                \"/data/app/~~random-things==/example.app-more_random_things==\",\n                \"/data/app/~~random-things==/example.app-more_random_things==/\",\n                \"/data/app/~~random-things==/example.app-more_random_things==/lib\",\n                \"/data/app/~~random-things==/example.app-more_random_things==/lib/\",\n                \"/data/app/~~random-things==/example.app-more_random_things==/base.apk\",\n        };\n        String realPath = \"/data/app/~~new-random-things==/example.app-more_new_random_things==\";\n        String[] expectedPaths = new String[]{\n                \"/data/app\",\n                \"/data/app\",\n                realPath,\n                realPath,\n                realPath + \"/lib\",\n                realPath + \"/lib\",\n                realPath + \"/oat\",\n                realPath + \"/base.apk\",\n                realPath,\n                realPath,\n                realPath + \"/lib\",\n                realPath + \"/lib\",\n                realPath + \"/base.apk\",\n        };\n        for (int i = 0; i < brokenPaths.length; ++i) {\n            assertEquals(\"Failed in index \" + i, expectedPaths[i], TarUtils.getAbsolutePathToDataApp(brokenPaths[i], realPath));\n        }\n    }\n\n    @NonNull\n    public static List<String> getFileNamesGZip(@NonNull List<Path> tarFiles) throws IOException {\n        List<String> fileNames = new ArrayList<>();\n        try (SplitInputStream sis = new SplitInputStream(tarFiles);\n             BufferedInputStream bis = new BufferedInputStream(sis);\n             GzipCompressorInputStream gis = new GzipCompressorInputStream(bis, true);\n             TarArchiveInputStream tis = new TarArchiveInputStream(gis)) {\n            ArchiveEntry entry;\n            while ((entry = tis.getNextEntry()) != null) {\n                fileNames.add(entry.getName());\n            }\n        }\n        return fileNames;\n    }\n\n    @NonNull\n    public static List<String> getFileNamesNoCompress(@NonNull List<Path> tarFiles) throws IOException {\n        List<String> fileNames = new ArrayList<>();\n        try (SplitInputStream sis = new SplitInputStream(tarFiles);\n             BufferedInputStream bis = new BufferedInputStream(sis);\n             TarArchiveInputStream tis = new TarArchiveInputStream(bis)) {\n            ArchiveEntry entry;\n            while ((entry = tis.getNextEntry()) != null) {\n                fileNames.add(entry.getName());\n            }\n        }\n        return fileNames;\n    }\n\n    private static void createTest(@NonNull Path source, @NonNull Path testRoot, @Nullable String[] include,\n                                   @Nullable String[] exclude, @NonNull List<String> expectedPaths) throws Throwable {\n        List<Path> files = TarUtils.create(TarUtils.TAR_GZIP, testRoot, source, \"am.tar.gz\", include,\n                null, exclude, false);\n        List<String> actualPaths = getFileNamesGZip(files);\n        Collections.sort(expectedPaths);\n        Collections.sort(actualPaths);\n        assertEquals(expectedPaths, actualPaths);\n    }\n\n    private static void extractTest(@NonNull Path[] sourceFiles, @NonNull Path testRoot, @Nullable String[] include,\n                                    @Nullable String[] exclude, @NonNull List<String> expectedPaths) throws Throwable {\n        List<String> actualPaths = new ArrayList<>();\n        recreateDir(testRoot);\n        TarUtils.extract(TarUtils.TAR_GZIP, sourceFiles, testRoot, include, exclude, null);\n        gatherFiles(actualPaths, testRoot, testRoot);\n        Collections.sort(expectedPaths);\n        Collections.sort(actualPaths);\n        assertEquals(expectedPaths, actualPaths);\n    }\n\n    private static void recreateDir(@NonNull Path dir) {\n        dir.delete();\n        dir.mkdirs();\n    }\n\n    private static void gatherFiles(@NonNull List<String> files, @NonNull Path basePath, @NonNull Path source) {\n        files.add(Paths.relativePath(source, basePath));\n        if (source.isDirectory()) {\n            Path[] children = source.listFiles();\n            if (children.length == 0) return;\n            for (Path child : children) {\n                gatherFiles(files, basePath, child);\n            }\n        }\n    }\n\n    @VisibleForTesting\n    @NonNull\n    static String getRelativePath(@NonNull File file, @NonNull File basePath, @NonNull String separator) {\n        String baseDir = basePath.toURI().getPath();\n        String targetPath = file.toURI().getPath();\n        return Paths.relativePath(targetPath, baseDir, separator);\n    }\n}\n"
  },
  {
    "path": "app/src/test/java/io/github/muntashirakon/csv/CsvWriterTest.java",
    "content": "// SPDX-License-Identifier: MIT AND GPL-3.0-or-later\n\npackage io.github.muntashirakon.csv;\n\nimport static org.junit.Assert.*;\n\nimport org.junit.Before;\nimport org.junit.Test;\n\nimport java.io.IOException;\nimport java.io.StringWriter;\nimport java.util.ArrayList;\nimport java.util.List;\n\n// Copyright 2020 Yong Mook Kim\n// Copyright 2024 Muntashir Al-Islam\npublic class CsvWriterTest {\n\n    @Before\n    public void setUp() throws Exception {\n    }\n\n    @Test\n    public void testCsvLineDefault() throws IOException {\n        try (StringWriter writer = new StringWriter()) {\n            String[] record = {\"1\", \"apple\", \"10\", \"9.99\"};\n            String expected = \"1,apple,10,9.99\";\n            new CsvWriter(writer).addLine(record);\n            String result = writer.toString();\n            assertEquals(expected, result);\n        }\n    }\n\n    @Test\n    public void testCsvLineQuoted() throws IOException {\n        try (StringWriter writer = new StringWriter()) {\n            String[] record = {\"1\", \"apple\", \"10\", \"9.99\"};\n            String expected = \"\\\"1\\\",\\\"apple\\\",\\\"10\\\",\\\"9.99\\\"\";\n            new CsvWriter(writer).addLine(record, true);\n            String result = writer.toString();\n            assertEquals(expected, result);\n        }\n    }\n\n    @Test\n    public void testCsvLineContainsEmptyValue() throws IOException {\n        try (StringWriter writer = new StringWriter()) {\n            String[] record = {\"1\", \"\", \"10\", \"\"};\n            String expected = \"1,,10,\";\n            new CsvWriter(writer).addLine(record);\n            String result = writer.toString();\n            assertEquals(expected, result);\n        }\n    }\n\n    @Test\n    public void testCsvEmptyLine() throws IOException {\n        try (StringWriter writer = new StringWriter()) {\n            String expected = \"\";\n            new CsvWriter(writer).addLine();\n            String result = writer.toString();\n            assertEquals(expected, result);\n        }\n    }\n\n    @Test\n    public void testCsvLineWithCustomSeparator() throws IOException {\n        try (StringWriter writer = new StringWriter()) {\n            String[] record = {\"1\", \"apple;orange\", \"10\", \"9.99\"};\n            String expected = \"1;\\\"apple;orange\\\";10;9.99\";\n            new CsvWriter(writer, \";\").addLine(record);\n            String result = writer.toString();\n            assertEquals(expected, result);\n        }\n    }\n\n    @Test\n    public void testCsvLineContainsComma() throws IOException {\n        try (StringWriter writer = new StringWriter()) {\n            String[] record = {\"1\", \"apple,orange\", \"10\", \"9.99\"};\n            String expected = \"1,\\\"apple,orange\\\",10,9.99\";\n            new CsvWriter(writer).addLine(record);\n            String result = writer.toString();\n            assertEquals(expected, result);\n        }\n    }\n\n    @Test\n    public void testCsvLineContainsDoubleQuotes() throws IOException {\n        try (StringWriter writer = new StringWriter()) {\n            String[] record = {\"1\", \"12\\\"apple\", \"10\", \"9.99\"};\n            String expected = \"1,\\\"12\\\"\\\"apple\\\",10,9.99\";\n            new CsvWriter(writer).addLine(record);\n            String result = writer.toString();\n            assertEquals(expected, result);\n        }\n    }\n\n    @Test\n    public void testCsvLineContainsNewline() throws IOException {\n        try (StringWriter writer = new StringWriter()) {\n            String[] record = {\"1\", \"promotion!\\napple\", \"10\", \"9.99\"};\n            String expected = \"1,\\\"promotion!\\napple\\\",10,9.99\";\n            new CsvWriter(writer).addLine(record);\n            String result = writer.toString();\n            assertEquals(expected, result);\n        }\n    }\n\n    @Test\n    public void testCsvLineDefaultTwoLines() throws IOException {\n        try (StringWriter writer = new StringWriter()) {\n            List<String[]> records = new ArrayList<String[]>() {{\n                add(new String[]{\"1\", \"apple\", \"10\", \"9.99\"});\n                add(new String[]{\"2\", \"orange\", \"5\", \"4.99\"});\n            }};\n            String expected = \"1,apple,10,9.99\\n2,orange,5,4.99\";\n            new CsvWriter(writer).addLines(records);\n            String result = writer.toString();\n            assertEquals(expected, result);\n        }\n    }\n\n    @Test\n    public void testCsvLineTwoLinesDifferentSizeThrowsException() throws IOException {\n        try (StringWriter writer = new StringWriter()) {\n            List<String[]> records = new ArrayList<String[]>() {{\n                add(new String[]{\"1\", \"apple\", \"10\", \"9.99\"});\n                add(new String[]{\"2\", \"orange\", \"5\"});\n            }};\n            assertThrows(IndexOutOfBoundsException.class, () -> new CsvWriter(writer).addLines(records));\n            records.remove(1);\n            records.add(new String[]{\"2\", \"orange\", \"5\", \"4.99\", \"rotten\"});\n            assertThrows(IndexOutOfBoundsException.class, () -> new CsvWriter(writer).addLines(records));\n        }\n    }\n\n    @Test\n    public void testCsvLineDefaultViaField() throws IOException {\n        try (StringWriter writer = new StringWriter()) {\n            String expected = \"1,apple,10,9.99\";\n            CsvWriter csvWriter = new CsvWriter(writer);\n            csvWriter.addField(\"1\");\n            csvWriter.addField(\"apple\");\n            csvWriter.addField(\"10\");\n            csvWriter.addField(\"9.99\");\n            csvWriter.addLine();\n            String result = writer.toString();\n            assertEquals(expected, result);\n        }\n    }\n\n    @Test\n    public void testCsvLineDefaultTwoLinesViaField() throws IOException {\n        try (StringWriter writer = new StringWriter()) {\n            String expected = \"1,apple,10,9.99\\n2,orange,5,4.99\";\n            CsvWriter csvWriter = new CsvWriter(writer);\n            csvWriter.addField(\"1\");\n            csvWriter.addField(\"apple\");\n            csvWriter.addField(\"10\");\n            csvWriter.addField(\"9.99\");\n            csvWriter.addLine();\n            csvWriter.addField(\"2\");\n            csvWriter.addField(\"orange\");\n            csvWriter.addField(\"5\");\n            csvWriter.addField(\"4.99\");\n            csvWriter.addLine();\n            String result = writer.toString();\n            assertEquals(expected, result);\n        }\n    }\n\n    @Test\n    public void testCsvLineDefaultTwoLinesDifferentSizeThrowsExceptionViaField() throws IOException {\n        try (StringWriter writer = new StringWriter()) {\n            CsvWriter csvWriter = new CsvWriter(writer);\n            csvWriter.addField(\"1\");\n            csvWriter.addField(\"apple\");\n            csvWriter.addField(\"10\");\n            csvWriter.addField(\"9.99\");\n            csvWriter.addLine();\n            csvWriter.addField(\"2\");\n            csvWriter.addField(\"orange\");\n            csvWriter.addField(\"5\");\n            assertThrows(IndexOutOfBoundsException.class, csvWriter::addLine);\n            csvWriter.addField(\"4.99\");\n            assertThrows(IndexOutOfBoundsException.class, () -> csvWriter.addField(\"rotten\"));\n        }\n    }\n}"
  },
  {
    "path": "app/src/test/java/io/github/muntashirakon/io/PathTest.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.io;\n\nimport org.junit.After;\nimport org.junit.Before;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.robolectric.RobolectricTestRunner;\n\nimport java.io.File;\nimport java.io.FileNotFoundException;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.nio.charset.StandardCharsets;\nimport java.util.Locale;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertFalse;\nimport static org.junit.Assert.assertNotEquals;\nimport static org.junit.Assert.assertNotNull;\nimport static org.junit.Assert.assertNull;\nimport static org.junit.Assert.assertThrows;\nimport static org.junit.Assert.assertTrue;\n\n@RunWith(RobolectricTestRunner.class)\npublic class PathTest {\n    private Path tmpPath;\n    private Path tmpFile;\n\n    @Before\n    public void setUp() throws Exception {\n        tmpPath = Paths.get(\"/tmp\");\n        tmpFile = tmpPath.createNewFile(\"am_tmp\", null);\n    }\n\n    @After\n    public void tearDown() {\n        tmpFile.delete();\n    }\n\n    @Test\n    public void getName() {\n        assertEquals(\"tmp\", tmpPath.getName());\n        assertEquals(\"am_tmp\", tmpFile.getName());\n    }\n\n    @Test\n    public void getUri() {\n        assertEquals(\"file:///tmp\", tmpPath.getUri().toString());\n        assertEquals(\"file:///tmp/am_tmp\", tmpFile.getUri().toString());\n    }\n\n    @Test\n    public void getFile() {\n        assertEquals(new File(\"/tmp\"), tmpPath.getFile());\n        assertEquals(new File(\"/tmp/am_tmp\"), tmpFile.getFile());\n    }\n\n    @Test\n    public void getFilePath() {\n        assertEquals(\"/tmp\", tmpPath.getFilePath());\n        assertEquals(\"/tmp/am_tmp\", tmpFile.getFilePath());\n    }\n\n    @Test\n    public void getRealFilePath() throws IOException {\n        String os = System.getProperty(\"os.name\");\n        if (os != null && (os.toLowerCase(Locale.ROOT).contains(\"darwin\") || os.toLowerCase(Locale.ROOT).contains(\"mac\"))) {\n            assertEquals(\"/private/tmp\", tmpPath.getRealFilePath());\n            assertEquals(\"/private/tmp/am_tmp\", tmpFile.getRealFilePath());\n        } else {\n            assertEquals(\"/tmp\", tmpPath.getRealFilePath());\n            assertEquals(\"/tmp/am_tmp\", tmpFile.getRealFilePath());\n        }\n    }\n\n    @Test\n    public void length() {\n        assertNotEquals(0, tmpPath.length());\n        assertEquals(0, tmpFile.length());\n    }\n\n    @Test\n    public void createNewFile() throws IOException {\n        Path newFile = tmpPath.createNewFile(\"am_new_file\", null);\n        assertTrue(tmpPath.hasFile(\"am_new_file\"));\n        assertTrue(newFile.exists());\n        assertEquals(0, newFile.length());\n        assertTrue(newFile.delete());\n    }\n\n    @Test\n    public void createNewFileInCurrentDir() throws IOException {\n        Path newFile = tmpPath.createNewFile(\"./am_new_file\", null);\n        assertTrue(tmpPath.hasFile(\"am_new_file\"));\n        assertEquals(0, newFile.length());\n        assertTrue(newFile.delete());\n    }\n\n    @Test\n    public void createNewFileTrailingSlash() throws IOException {\n        Path newFile = tmpPath.createNewFile(\"am_new_file/\", null);\n        assertTrue(tmpPath.hasFile(\"am_new_file\"));\n        assertEquals(0, newFile.length());\n        assertTrue(newFile.delete());\n    }\n\n    @Test\n    public void createNewFileInNonExistingDir() {\n        assertThrows(IllegalArgumentException.class, () ->\n                tmpPath.createNewFile(\"non_existing_dir/am_new_file\", null));\n    }\n\n    @Test\n    public void createNewFileInExistingDir() throws IOException {\n        Path dir = tmpPath.createNewDirectory(\"am_new_dir\");\n        assertThrows(IllegalArgumentException.class, () ->\n                tmpPath.createNewFile(\"am_new_dir/am_new_file\", null));\n        assertTrue(dir.delete());\n    }\n\n    @Test\n    public void createNewFileTwoTimes() throws IOException {\n        Path newFile = tmpPath.createNewFile(\"am_new_file\", null);\n        try (OutputStream os = newFile.openOutputStream()) {\n            os.write(\"This is a test.\".getBytes(StandardCharsets.UTF_8));\n        }\n        assertTrue(newFile.exists());\n        assertNotEquals(0, newFile.length());\n        Path newNewFile = tmpPath.createNewFile(\"am_new_file\", null);\n        assertTrue(newNewFile.exists());\n        assertEquals(0, newFile.length());\n        assertTrue(newNewFile.delete());\n    }\n\n    @Test\n    public void createNewFileOverridingDirectory() throws IOException {\n        Path newFile = tmpPath.createNewDirectory(\"am_new_dir\");\n        assertTrue(newFile.exists());\n        assertTrue(newFile.isDirectory());\n        assertThrows(IOException.class, () -> tmpPath.createNewFile(\"am_new_dir\", null));\n        assertTrue(newFile.delete());\n    }\n\n    @Test\n    public void createNewFileRecursive() throws IOException {\n        Path newFile = tmpPath.createNewArbitraryFile(\"non_existing_dir/am_new_dir/am_new_file\", null);\n        assertTrue(newFile.exists());\n        assertTrue(newFile.isFile());\n        assertTrue(tmpPath.findFile(\"non_existing_dir\").delete());\n    }\n\n    @Test\n    public void createNewFileRecursiveNoRecursive() throws IOException {\n        Path newFile = tmpPath.createNewArbitraryFile(\"/am_new_file/\", null);\n        assertTrue(tmpPath.hasFile(\"am_new_file\"));\n        assertTrue(newFile.exists());\n        assertTrue(newFile.isFile());\n        assertTrue(newFile.delete());\n    }\n\n    @Test\n    public void createNewFileRecursiveParent() throws IOException {\n        Path dir = tmpPath.createNewDirectory(\"am_new_dir\");\n        assertThrows(IOException.class, () ->\n                dir.createNewArbitraryFile(\"../am_new_file\", null));\n        assertFalse(dir.hasFile(\"am_new_file\"));\n        assertFalse(tmpFile.hasFile(\"am_new_file\"));\n        assertTrue(dir.delete());\n    }\n\n    @Test\n    public void createNewDirectory() throws IOException {\n        Path newFile = tmpPath.createNewDirectory(\"am_new_dir\");\n        assertTrue(newFile.exists());\n        assertTrue(newFile.isDirectory());\n        assertTrue(newFile.delete());\n    }\n\n    @Test\n    public void createNewDirectoryInCurrentDir() throws IOException {\n        Path newFile = tmpPath.createNewDirectory(\"./am_new_dir/\");\n        assertTrue(tmpPath.hasFile(\"am_new_dir\"));\n        assertTrue(newFile.exists());\n        assertTrue(newFile.isDirectory());\n        assertTrue(newFile.delete());\n    }\n\n    @Test\n    public void createNewDirectoryWithFileSeparator() {\n        assertThrows(IllegalArgumentException.class, () -> tmpPath.createNewDirectory(\"non_existing_dir/am_new_dir\"));\n    }\n\n    @Test\n    public void createDirectories() throws IOException {\n        Path newFile = tmpPath.createDirectories(\"non_existing_dir/am_new_dir\");\n        assertTrue(tmpPath.hasFile(\"non_existing_dir\"));\n        Path dir = tmpPath.findFile(\"non_existing_dir\");\n        assertTrue(dir.hasFile(\"am_new_dir\"));\n        assertTrue(newFile.exists());\n        assertTrue(newFile.isDirectory());\n        assertTrue(dir.delete());\n    }\n\n    @Test\n    public void createDirectoriesExistingDir() throws IOException {\n        Path dir = tmpPath.createNewDirectory(\"existing_dir\");\n        Path newFile = tmpPath.createDirectories(\"existing_dir/am_new_dir\");\n        assertTrue(tmpPath.hasFile(\"existing_dir\"));\n        assertTrue(dir.hasFile(\"am_new_dir\"));\n        assertTrue(newFile.exists());\n        assertTrue(newFile.isDirectory());\n        assertTrue(dir.delete());\n        assertFalse(newFile.exists());\n    }\n\n    @Test\n    public void createDirectoriesAllExisting() throws IOException {\n        Path dir = tmpPath.createNewDirectory(\"existing_dir\");\n        Path childDir = dir.createNewDirectory(\"am_new_dir\");\n        assertThrows(IOException.class, () -> tmpPath.createDirectories(\"existing_dir/am_new_dir\"));\n        assertTrue(dir.hasFile(\"am_new_dir\"));\n        assertEquals(dir.findFile(\"am_new_dir\"), childDir);\n        assertTrue(dir.delete());\n    }\n\n    @Test\n    public void createDirectoriesInParent() throws IOException {\n        Path parent = tmpPath.createNewDirectory(\"existing_dir\");\n        assertThrows(IOException.class, () -> parent.createDirectories(\"../am_new_dir\"));\n        assertFalse(tmpPath.hasFile(\"am_new_dir\"));\n        assertFalse(parent.hasFile(\"am_new_dir\"));\n        assertTrue(parent.delete());\n    }\n\n    @Test\n    public void createDirectoriesWithExistingFilenameAsComponent() throws IOException {\n        Path newFile = tmpPath.createNewFile(\"am_new_file\", null);\n        assertTrue(newFile.exists());\n        assertEquals(0, newFile.length());\n        assertThrows(IOException.class, () -> tmpPath.createDirectories(\"am_new_file/am_new_dir\"));\n        assertTrue(newFile.delete());\n    }\n\n    @Test\n    public void createNewDirectoryOverridingFile() throws IOException {\n        Path newFile = tmpPath.createNewFile(\"am_new_file\", null);\n        assertTrue(newFile.exists());\n        assertFalse(newFile.isDirectory());\n        assertThrows(IOException.class, () -> tmpPath.createNewDirectory(\"am_new_file\"));\n        assertTrue(newFile.delete());\n    }\n\n    @Test\n    public void createNewDirectoriesOverridingFile() throws IOException {\n        Path newFile = tmpPath.createNewFile(\"am_new_file\", null);\n        assertTrue(newFile.exists());\n        assertFalse(newFile.isDirectory());\n        assertThrows(IOException.class, () -> tmpPath.createDirectories(\"am_new_file/another_dir\"));\n        assertTrue(newFile.delete());\n    }\n\n    @Test\n    public void deleteSingleFile() throws IOException {\n        Path newFile = tmpPath.createNewFile(\"am_new_file\", null);\n        assertTrue(newFile.exists());\n        assertTrue(newFile.isFile());\n        assertTrue(newFile.delete());\n        assertFalse(newFile.exists());\n    }\n\n    @Test\n    public void deleteCreateDeleteSingleFile() throws IOException {\n        Path newFile = tmpPath.createNewFile(\"am_new_file\", null);\n        assertTrue(newFile.exists());\n        assertTrue(newFile.isFile());\n        assertTrue(newFile.delete());\n        assertFalse(newFile.exists());\n        assertTrue(newFile.recreate());\n        assertTrue(newFile.exists());\n        assertTrue(newFile.isFile());\n        assertTrue(newFile.delete());\n        assertFalse(newFile.exists());\n    }\n\n    @Test\n    public void deleteDirectory() throws IOException {\n        Path newFile = tmpPath.createNewDirectory(\"am_new_dir\");\n        assertTrue(newFile.exists());\n        assertTrue(newFile.isDirectory());\n        assertTrue(newFile.delete());\n        assertFalse(newFile.exists());\n    }\n\n    @Test\n    public void deleteDirectoryWithContents() throws IOException {\n        Path newFile = tmpPath.createNewDirectory(\"am_new_dir\");\n        newFile.createNewFile(\"file_1\", null);\n        newFile.createNewFile(\"file_2\", null);\n        newFile.createNewFile(\"file_3\", null);\n        Path subDir = newFile.createNewDirectory(\"dir_1\");\n        subDir.createNewFile(\"file_1\", null);\n        subDir.createNewFile(\"file_2\", null);\n        subDir.createNewFile(\"file_3\", null);\n        newFile.createNewDirectory(\"dir_2\");\n        assertTrue(newFile.exists());\n        assertTrue(newFile.isDirectory());\n        assertTrue(newFile.delete());\n        assertFalse(newFile.exists());\n    }\n\n    @Test\n    public void hasFile() {\n        assertFalse(tmpPath.hasFile(\"jfjfasdjfflasdjajsdkasdjjfasdkfjskdaffsadqrurewiasjdsd\"));\n        assertTrue(tmpPath.hasFile(\"am_tmp\"));\n    }\n\n    @Test\n    public void findFileExistingFile() throws FileNotFoundException {\n        Path path = tmpPath.findFile(\"am_tmp\");\n        assertEquals(tmpFile, path);\n        assertTrue(path.isFile());\n    }\n\n    @Test\n    public void findFileNonExistingFile() {\n        assertThrows(FileNotFoundException.class, () -> tmpPath.findFile(\"jfjfasdjfflasdjajsdkasdjjfasdkfjskdaffsadqrurewiasjdsd\"));\n    }\n\n    @Test\n    public void findFileExistingDirectory() throws FileNotFoundException {\n        Path path = Paths.get(File.separator).findFile(\"tmp\");\n        assertEquals(tmpPath, path);\n        assertTrue(path.isDirectory());\n    }\n\n    @Test\n    public void findOrCreateFile() throws IOException {\n        Path path = tmpPath.findOrCreateFile(\"am_new_file\", null);\n        assertTrue(path.isFile());\n        assertTrue(path.delete());\n    }\n\n    @Test\n    public void findOrCreateFileExistingFile() throws IOException {\n        Path newFile = tmpPath.createNewFile(\"am_new_file\", null);\n        Path path = tmpPath.findOrCreateFile(\"am_new_file\", null);\n        assertEquals(newFile, path);\n        assertTrue(path.isFile());\n        assertTrue(path.delete());\n    }\n\n    @Test\n    public void findOrCreateFileInAnotherDirectory() throws IOException {\n        Path dir = tmpPath.createNewDirectory(\"am_new_dir\");\n        assertTrue(dir.isDirectory());\n        assertThrows(IllegalArgumentException.class, () -> tmpPath.findOrCreateFile(\"am_new_dir/am_new_file\", null));\n        assertFalse(dir.hasFile(\"am_new_file\"));\n        assertTrue(dir.delete());\n    }\n\n    @Test\n    public void findOrCreateFileExistingDirectory() throws IOException {\n        Path dir = tmpPath.createNewDirectory(\"am_new_dir\");\n        assertTrue(dir.isDirectory());\n        assertThrows(IOException.class, () -> tmpPath.findOrCreateFile(\"am_new_dir\", null));\n        assertTrue(dir.delete());\n    }\n\n    @Test\n    public void findOrCreateDirectory() throws IOException {\n        Path path = tmpPath.findOrCreateDirectory(\"am_new_dir\");\n        assertTrue(path.isDirectory());\n        assertTrue(path.delete());\n    }\n\n    @Test\n    public void findOrCreateDirectoryExistingDirectory() throws IOException {\n        Path dir = tmpPath.createNewDirectory(\"am_new_dir\");\n        Path path = tmpPath.findOrCreateDirectory(\"am_new_dir\");\n        assertEquals(dir, path);\n        assertTrue(path.isDirectory());\n        assertTrue(path.delete());\n    }\n\n    @Test\n    public void findOrCreateDirectoryInAnotherDirectory() throws IOException {\n        Path path = tmpPath.createNewDirectory(\"am_new_dir\");\n        assertTrue(path.isDirectory());\n        assertThrows(IllegalArgumentException.class, () -> tmpPath.findOrCreateDirectory(\"am_new_dir/am_another_dir\"));\n        assertFalse(path.hasFile(\"am_another_dir\"));\n        assertTrue(path.delete());\n    }\n\n    @Test\n    public void findOrCreateDirectoryExistingFile() throws IOException {\n        Path path = tmpPath.createNewFile(\"am_new_file\", null);\n        assertTrue(path.isFile());\n        assertThrows(IOException.class, () -> tmpPath.findOrCreateDirectory(\"am_new_file\"));\n        assertTrue(path.delete());\n    }\n\n    @Test\n    public void isDirectory() {\n        assertTrue(tmpPath.isDirectory());\n        assertFalse(tmpFile.isDirectory());\n    }\n\n    @Test\n    public void isFile() {\n        assertFalse(tmpPath.isFile());\n        assertTrue(tmpFile.isFile());\n    }\n\n    @Test\n    public void renameFileInSameDirectory() throws IOException {\n        Path src = tmpPath.findOrCreateFile(\"am_new_file\", null);\n        assertTrue(src.renameTo(\"am_new_file_2\"));\n        assertTrue(tmpPath.hasFile(\"am_new_file_2\"));\n        assertFalse(tmpPath.hasFile(\"am_new_file\"));\n        assertEquals(tmpPath.findFile(\"am_new_file_2\"), src);\n        assertTrue(src.delete());\n    }\n\n    @Test\n    public void renameDirInSameDirectory() throws IOException {\n        Path src = tmpPath.findOrCreateDirectory(\"am_new_dir_src\");\n        Path childFile = src.findOrCreateFile(\"test_file\", null);\n        Path childDir = src.findOrCreateDirectory(\"test_dir\");\n        assertTrue(src.renameTo(\"am_new_dir_dst\"));\n        assertTrue(tmpPath.hasFile(\"am_new_dir_dst\"));\n        assertFalse(tmpPath.hasFile(\"am_new_dir_src\"));\n        Path dst = tmpPath.findFile(\"am_new_dir_dst\");\n        assertEquals(dst, src);\n        assertFalse(childFile.exists());\n        assertFalse(childDir.exists());\n        assertTrue(dst.hasFile(\"test_file\"));\n        assertTrue(dst.hasFile(\"test_dir\"));\n        assertTrue(dst.delete());\n        assertFalse(src.delete());\n    }\n\n    @Test\n    public void renameFileInSameDirectoryTargetExists() throws IOException {\n        Path src = tmpPath.findOrCreateFile(\"am_new_file\", null);\n        Path dst = tmpPath.findOrCreateFile(\"am_new_file_2\", null);\n        assertFalse(src.renameTo(\"am_new_file_2\"));\n        assertTrue(tmpPath.hasFile(\"am_new_file\"));\n        assertTrue(tmpPath.hasFile(\"am_new_file_2\"));\n        assertEquals(tmpPath.findFile(\"am_new_file\"), src);\n        assertEquals(tmpPath.findFile(\"am_new_file_2\"), dst);\n        assertTrue(src.delete());\n        assertTrue(dst.delete());\n    }\n\n    @Test\n    public void renameFileInChildDirectoryFails() throws IOException {\n        Path src = tmpPath.findOrCreateFile(\"am_new_file\", null);\n        Path dst = tmpPath.createNewDirectory(\"am_new_dir\");\n        assertFalse(src.renameTo(\"am_new_dir/am_new_file_2\"));\n        assertFalse(dst.hasFile(\"am_new_file_2\"));\n        assertTrue(tmpPath.hasFile(\"am_new_file\"));\n        assertEquals(tmpPath.findFile(\"am_new_file\"), src);\n        assertTrue(dst.delete());\n        assertTrue(src.delete());\n    }\n\n    @Test\n    public void renameFileInParentDirectoryFails() throws IOException {\n        Path parent = tmpPath.createNewDirectory(\"am_new_dir\");\n        Path childDir = parent.createNewDirectory(\"am_child_dir\");\n        Path childChildFile = childDir.createNewFile(\"am_new_file\", null);\n        assertFalse(childChildFile.renameTo(\"../am_new_file_2\"));\n        assertFalse(childDir.hasFile(\"am_new_file_2\"));\n        assertTrue(childDir.hasFile(\"am_new_file\"));\n        assertFalse(parent.hasFile(\"am_new_file_2\"));\n        assertTrue(parent.delete());\n    }\n\n    @Test\n    public void moveFileToFile() throws IOException {\n        Path src = tmpPath.createNewFile(\"am_new_file\", null);\n        Path dst = tmpPath.createNewFile(\"moved_file\", null);\n        assertTrue(src.moveTo(dst));\n        assertTrue(tmpPath.hasFile(\"moved_file\"));\n        assertFalse(tmpPath.hasFile(\"am_new_file\"));\n        assertEquals(dst, src);\n        assertTrue(src.delete());\n        assertFalse(dst.delete());\n    }\n\n    @Test\n    public void moveToSameFile() throws IOException {\n        Path src = tmpPath.createNewFile(\"am_new_file\", null);\n        assertFalse(src.moveTo(src));\n        assertTrue(src.delete());\n    }\n\n    @Test\n    public void moveFileToFileNoOverride() throws IOException {\n        Path src = tmpPath.createNewFile(\"am_new_file\", null);\n        Path dst = tmpPath.createNewFile(\"moved_file\", null);\n        assertFalse(src.moveTo(dst, false));\n        assertTrue(tmpPath.hasFile(\"moved_file\"));\n        assertTrue(tmpPath.hasFile(\"am_new_file\"));\n        assertNotEquals(dst, src);\n        assertTrue(src.delete());\n        assertTrue(dst.delete());\n    }\n\n    @Test\n    public void moveFileToDir() throws IOException {\n        Path src = tmpPath.createNewFile(\"am_new_file\", null);\n        Path dst = tmpPath.createNewDirectory(\"am_new_dir\");\n        assertTrue(src.moveTo(dst));\n        assertTrue(dst.hasFile(\"am_new_file\"));\n        assertFalse(tmpPath.hasFile(\"am_new_file\"));\n        assertEquals(dst.findFile(\"am_new_file\"), src);\n        assertTrue(dst.delete());\n        assertFalse(src.delete());\n    }\n\n    @Test\n    public void moveFileToDirAndFile() throws IOException {\n        Path src = tmpPath.createNewFile(\"am_new_file\", null);\n        Path child = tmpPath.createNewDirectory(\"am_new_dir\");\n        Path dst = child.createNewFile(\"moved_file\", null);\n        assertTrue(src.moveTo(dst));\n        assertTrue(child.hasFile(\"moved_file\"));\n        assertFalse(tmpPath.hasFile(\"am_new_file\"));\n        assertEquals(dst, src);\n        assertTrue(child.delete());\n        assertFalse(src.delete());\n    }\n\n    @Test\n    public void moveDirToDir() throws IOException {\n        Path src = tmpPath.createNewDirectory(\"am_new_dir_src\");\n        Path dst = tmpPath.createNewDirectory(\"am_new_dir_dst\");\n        src.createNewFile(\"some_file\", null);\n        assertTrue(dst.delete());\n        assertTrue(src.moveTo(dst));\n        assertFalse(tmpPath.hasFile(\"am_new_dir_src\"));\n        assertTrue(tmpPath.hasFile(\"am_new_dir_dst\"));\n        assertTrue(dst.hasFile(\"some_file\"));\n        assertEquals(dst, src);\n        assertTrue(dst.delete());\n        assertFalse(src.delete());\n    }\n\n    @Test\n    public void moveToSameDir() throws IOException {\n        Path src = tmpPath.createNewDirectory(\"am_new_dir\");\n        assertFalse(src.moveTo(src));\n        assertTrue(src.delete());\n    }\n\n    @Test\n    public void moveToSameChildDir() throws IOException {\n        Path src = tmpPath.createNewDirectory(\"am_new_dir\");\n        Path child = src.createNewDirectory(\"am_child_dir\");\n        assertFalse(src.moveTo(child));\n        assertTrue(src.delete());\n    }\n\n    @Test\n    public void moveDirToExistingDir() throws IOException {\n        Path src = tmpPath.createNewDirectory(\"am_new_dir_src\");\n        Path dst = tmpPath.createNewDirectory(\"am_new_dir_dst\");\n        src.createNewFile(\"some_file\", null);\n        assertTrue(src.moveTo(dst));\n        assertFalse(tmpPath.hasFile(\"am_new_dir_src\"));\n        assertTrue(tmpPath.hasFile(\"am_new_dir_dst\"));\n        assertTrue(dst.hasFile(\"am_new_dir_src\"));\n        assertTrue(dst.findFile(\"am_new_dir_src\").hasFile(\"some_file\"));\n        assertEquals(dst.findFile(\"am_new_dir_src\"), src);\n        assertTrue(dst.delete());\n        assertFalse(src.delete());\n    }\n\n    @Test\n    public void moveDirToFileFails() throws IOException {\n        Path dst = tmpPath.createNewFile(\"am_new_file\", null);\n        Path child = tmpPath.createNewDirectory(\"am_new_dir\");\n        child.createNewFile(\"some_file\", null);\n        assertFalse(child.moveTo(dst));\n        assertTrue(tmpPath.hasFile(\"am_new_file\"));\n        assertTrue(tmpPath.hasFile(\"am_new_dir\"));\n        assertTrue(child.delete());\n        assertTrue(dst.delete());\n    }\n\n    @Test\n    public void copyFileToFile() throws IOException {\n        Path src = tmpPath.createNewFile(\"am_new_file\", null);\n        Path dst = tmpPath.createNewFile(\"copied_file\", null);\n        assertNotNull(src.copyTo(dst));\n        assertTrue(tmpPath.hasFile(\"am_new_file\"));\n        assertTrue(tmpPath.hasFile(\"copied_file\"));\n        assertNotEquals(dst, src);\n        assertTrue(src.delete());\n        assertTrue(dst.delete());\n    }\n\n    @Test\n    public void copyToSameFile() throws IOException {\n        Path src = tmpPath.createNewFile(\"am_new_file\", null);\n        assertNull(src.copyTo(src));\n        assertTrue(src.delete());\n    }\n\n    @Test\n    public void copyFileToFileNoOverride() throws IOException {\n        Path src = tmpPath.createNewFile(\"am_new_file\", null);\n        Path dst = tmpPath.createNewFile(\"copied_file\", null);\n        assertNull(src.copyTo(dst, false));\n        assertTrue(tmpPath.hasFile(\"am_new_file\"));\n        assertTrue(tmpPath.hasFile(\"copied_file\"));\n        assertNotEquals(dst, src);\n        assertTrue(src.delete());\n        assertTrue(dst.delete());\n    }\n\n    @Test\n    public void copyFileToDir() throws IOException {\n        Path src = tmpPath.createNewFile(\"am_new_file\", null);\n        Path dst = tmpPath.createNewDirectory(\"am_new_dir\");\n        assertNotNull(src.copyTo(dst));\n        assertTrue(dst.hasFile(\"am_new_file\"));\n        assertTrue(tmpPath.hasFile(\"am_new_file\"));\n        assertNotEquals(dst.findFile(\"am_new_file\"), src);\n        assertTrue(dst.delete());\n        assertTrue(src.delete());\n    }\n\n    @Test\n    public void copyFileToDirAndFile() throws IOException {\n        Path src = tmpPath.createNewFile(\"am_new_file\", null);\n        Path child = tmpPath.createNewDirectory(\"am_new_dir\");\n        Path dst = child.createNewFile(\"copied_file\", null);\n        assertNotNull(src.copyTo(dst));\n        assertTrue(child.hasFile(\"copied_file\"));\n        assertTrue(tmpPath.hasFile(\"am_new_file\"));\n        assertNotEquals(dst, src);\n        assertTrue(child.delete());\n        assertTrue(src.delete());\n    }\n\n    @Test\n    public void copyDirToDir() throws IOException {\n        Path src = tmpPath.createNewDirectory(\"am_new_dir_src\");\n        Path dst = tmpPath.createNewDirectory(\"am_new_dir_dst\");\n        src.createNewFile(\"some_file\", null);\n        assertTrue(dst.delete());\n        assertNotNull(src.copyTo(dst));\n        assertTrue(tmpPath.hasFile(\"am_new_dir_src\"));\n        assertTrue(tmpPath.hasFile(\"am_new_dir_dst\"));\n        assertTrue(src.hasFile(\"some_file\"));\n        assertTrue(dst.hasFile(\"some_file\"));\n        assertNotEquals(dst, src);\n        assertTrue(dst.delete());\n        assertTrue(src.delete());\n    }\n\n    @Test\n    public void copyToSameDir() throws IOException {\n        Path src = tmpPath.createNewDirectory(\"am_new_dir\");\n        assertNull(src.copyTo(src));\n        assertTrue(src.delete());\n    }\n\n    @Test\n    public void copyToSameChildDir() throws IOException {\n        Path src = tmpPath.createNewDirectory(\"am_new_dir\");\n        Path child = src.createNewDirectory(\"am_child_dir\");\n        assertNull(src.copyTo(child));\n        assertTrue(src.delete());\n    }\n\n    @Test\n    public void copyDirToExistingDir() throws IOException {\n        Path src = tmpPath.createNewDirectory(\"am_new_dir_src\");\n        Path dst = tmpPath.createNewDirectory(\"am_new_dir_dst\");\n        src.createNewFile(\"some_file\", null);\n        assertNotNull(src.copyTo(dst));\n        assertTrue(tmpPath.hasFile(\"am_new_dir_src\"));\n        assertTrue(tmpPath.hasFile(\"am_new_dir_dst\"));\n        assertTrue(dst.hasFile(\"am_new_dir_src\"));\n        assertTrue(dst.findFile(\"am_new_dir_src\").hasFile(\"some_file\"));\n        assertNotEquals(dst.findFile(\"am_new_dir_src\"), src);\n        assertTrue(dst.delete());\n        assertTrue(src.delete());\n    }\n\n    @Test\n    public void copyDirToFileFails() throws IOException {\n        Path dst = tmpPath.createNewFile(\"am_new_file\", null);\n        Path child = tmpPath.createNewDirectory(\"am_new_dir\");\n        child.createNewFile(\"some_file\", null);\n        assertNull(child.copyTo(dst));\n        assertTrue(tmpPath.hasFile(\"am_new_file\"));\n        assertTrue(tmpPath.hasFile(\"am_new_dir\"));\n        assertTrue(child.delete());\n        assertTrue(dst.delete());\n    }\n\n    @Test\n    public void openOutputStreamForFile() throws IOException {\n        byte[] bytes = \"This is a test.\".getBytes(StandardCharsets.UTF_8);\n        Path newFile = tmpPath.createNewFile(\"am_new_file\", null);\n        try (OutputStream os = newFile.openOutputStream()) {\n            os.write(bytes);\n        }\n        assertTrue(newFile.exists());\n        assertEquals(bytes.length, newFile.length());\n        assertTrue(newFile.delete());\n    }\n\n    @Test\n    public void openOutputStreamForFileAppend() throws IOException {\n        byte[] bytes = \"This is a test.\".getBytes(StandardCharsets.UTF_8);\n        Path newFile = tmpPath.createNewFile(\"am_new_file\", null);\n        try (OutputStream os = newFile.openOutputStream()) {\n            os.write(bytes);\n        }\n        assertTrue(newFile.exists());\n        assertEquals(bytes.length, newFile.length());\n        try (OutputStream os = newFile.openOutputStream(true)) {\n            os.write(bytes);\n        }\n        assertTrue(newFile.exists());\n        assertEquals(bytes.length * 2, newFile.length());\n        assertTrue(newFile.delete());\n    }\n\n    @Test\n    public void openOutputStreamForDirectory() throws IOException {\n        Path newFile = tmpPath.createNewDirectory(\"am_new_dir\");\n        assertThrows(IOException.class, newFile::openOutputStream);\n        assertTrue(newFile.delete());\n    }\n\n    @Test\n    public void openInputStreamForFile() throws IOException {\n        Path newFile = tmpPath.createNewFile(\"am_new_file\", null);\n        //noinspection EmptyTryBlock\n        try (InputStream ignore = newFile.openInputStream()) {\n        }\n        assertTrue(newFile.exists());\n        assertEquals(0, newFile.length());\n        assertTrue(newFile.delete());\n    }\n\n    @Test\n    public void openInputStreamForDirectory() throws IOException {\n        Path newFile = tmpPath.createNewDirectory(\"am_new_dir\");\n        assertThrows(IOException.class, newFile::openInputStream);\n        assertTrue(newFile.delete());\n    }\n}\n"
  },
  {
    "path": "app/src/test/java/io/github/muntashirakon/io/PathsTest.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.io;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertNull;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.robolectric.RobolectricTestRunner;\n\n@RunWith(RobolectricTestRunner.class)\npublic class PathsTest {\n\n    @Test\n    public void sanitizePath() {\n        assertNull(Paths.sanitize(\"\", false));\n        assertEquals(\"/\", Paths.sanitize(\"/\", false));\n        assertEquals(\"/\", Paths.sanitize(\"//\", false));\n        assertEquals(\"/\", Paths.sanitize(\"/\\n/\", false));\n        assertEquals(\"/\", Paths.sanitize(\"/\\n\\r/\", false));\n        assertEquals(\"/rn\", Paths.sanitize(\"/r\\n\\rn/\", false));\n        assertEquals(\"/\", Paths.sanitize(\"///\", false));\n        assertEquals(\"/a\", Paths.sanitize(\"/a/\", false));\n        assertEquals(\"/a\", Paths.sanitize(\"//a//\", false));\n        assertEquals(\"/a\", Paths.sanitize(\"///a///\", false));\n        assertEquals(\"/a/b/c\", Paths.sanitize(\"/a/b/c\", false));\n        assertEquals(\"/a/b/c\", Paths.sanitize(\"/a/b//c\", false));\n        assertEquals(\"/a/b/c\", Paths.sanitize(\"/a/b///c\", false));\n        assertEquals(\"/a/b/c\", Paths.sanitize(\"/a/b/c/\", false));\n        assertEquals(\"/a/b/c\", Paths.sanitize(\"/a/b/c//\", false));\n        assertEquals(\"/a/b/c\", Paths.sanitize(\"/a/b/c///\", false));\n        assertEquals(\"a/b/c\", Paths.sanitize(\"././a/./b/c/./\", false));\n        assertEquals(\"/a/b/c\", Paths.sanitize(\"/a/b/c/.\", false));\n        assertEquals(\"/a/b/c/..\", Paths.sanitize(\"/a/b/c/..\", false));\n        assertEquals(\"/a/b/c/..\", Paths.sanitize(\"/a/b/c/../\", false));\n        assertEquals(\"/ab/bc/ca/..\", Paths.sanitize(\"/ab/bc/ca/..//\", false));\n    }\n\n    @Test\n    public void sanitizePathOmitRoot() {\n        assertNull(Paths.sanitize(\"\", true));\n        assertEquals(\"/\", Paths.sanitize(\"/\", true));\n        assertEquals(\"/\", Paths.sanitize(\"//\", true));\n        assertEquals(\"/\", Paths.sanitize(\"/\\n/\", true));\n        assertEquals(\"/\", Paths.sanitize(\"/\\n\\r/\", true));\n        assertEquals(\"/\", Paths.sanitize(\"///\", true));\n        assertEquals(\"nr\", Paths.sanitize(\"/n\\n\\rr/\", true));\n        assertEquals(\"a\", Paths.sanitize(\"a/\", true));\n        assertEquals(\"a\", Paths.sanitize(\"a//\", true));\n        assertEquals(\"a\", Paths.sanitize(\"a///\", true));\n        assertEquals(\"a/b/c\", Paths.sanitize(\"a/b/c\", true));\n        assertEquals(\"a/b/c\", Paths.sanitize(\"a/b//c\", true));\n        assertEquals(\"a/b/c\", Paths.sanitize(\"a/b///c\", true));\n        assertEquals(\"a/b/c\", Paths.sanitize(\"a/b/c/\", true));\n        assertEquals(\"a/b/c\", Paths.sanitize(\"a/b/c//\", true));\n        assertEquals(\"a/b/c\", Paths.sanitize(\"a/b/c///\", true));\n        assertEquals(\"a/b/c\", Paths.sanitize(\"./a/./b/c/./\", true));\n        assertEquals(\"a/b/c\", Paths.sanitize(\"a/b/c/.\", true));\n        assertEquals(\"a/b/c/..\", Paths.sanitize(\"a/b/c/..\", true));\n        assertEquals(\"a/b/c/..\", Paths.sanitize(\"a/b/c/../\", true));\n        assertEquals(\"a/b/c/..\", Paths.sanitize(\"a/b/c/..//\", true));\n    }\n\n\n    @Test\n    public void normalizePath() {\n        assertNull(Paths.normalize(\"\"));\n        assertEquals(\"/\", Paths.normalize(\"/\"));\n        assertEquals(\"/\", Paths.normalize(\"//\"));\n        assertEquals(\"/\", Paths.normalize(\"/\\n/\"));\n        assertEquals(\"/\", Paths.normalize(\"/\\n\\r/\"));\n        assertEquals(\"/\", Paths.normalize(\"///\"));\n        assertEquals(\"/rn\", Paths.normalize(\"/r\\n\\rn/\"));\n        assertEquals(\"/a\", Paths.normalize(\"/a/\"));\n        assertEquals(\"/a\", Paths.normalize(\"//a//\"));\n        assertEquals(\"/a\", Paths.normalize(\"///a///\"));\n        assertEquals(\"/a\", Paths.normalize(\"/../a\"));\n        assertEquals(\"/b\", Paths.normalize(\"/a/../../../b\"));\n        assertEquals(\"../a\", Paths.normalize(\"../a\"));\n        assertEquals(\"../../b\", Paths.normalize(\"a/../../../b\"));\n        assertEquals(\"/a/b/c\", Paths.normalize(\"/a/b/c\"));\n        assertEquals(\"/a/b/c\", Paths.normalize(\"/a/b//c\"));\n        assertEquals(\"/a/b/c\", Paths.normalize(\"/a/b///c\"));\n        assertEquals(\"/a/b/c\", Paths.normalize(\"/a/b/c/\"));\n        assertEquals(\"/a/b/c\", Paths.normalize(\"/a/b/c//\"));\n        assertEquals(\"/a/b/c\", Paths.normalize(\"/a/b/c///\"));\n        assertEquals(\"a/b/c\", Paths.normalize(\"././a/./b/c/./\"));\n        assertEquals(\"/a/b/c\", Paths.normalize(\"/a/b/c/.\"));\n        assertEquals(\"/a/b\", Paths.normalize(\"/a/b/c/..\"));\n        assertEquals(\"/a/b\", Paths.normalize(\"/a/b/c/../\"));\n        assertEquals(\"/ab/bc\", Paths.normalize(\"/ab/bc/ca/..//\"));\n    }\n\n    @Test\n    public void getLastPathSegment() {\n        assertEquals(\"\", Paths.getLastPathSegment(\"\"));\n        assertEquals(\"\", Paths.getLastPathSegment(\"/\"));\n        assertEquals(\"\", Paths.getLastPathSegment(\"//\"));\n        assertEquals(\"\", Paths.getLastPathSegment(\"/\\n/\"));\n        assertEquals(\"\", Paths.getLastPathSegment(\"/\\n\\r/\"));\n        assertEquals(\"\", Paths.getLastPathSegment(\"///\"));\n        assertEquals(\"rn\", Paths.getLastPathSegment(\"/r\\n\\rn/\"));\n        assertEquals(\"a\", Paths.getLastPathSegment(\"a/\"));\n        assertEquals(\"a\", Paths.getLastPathSegment(\"a//\"));\n        assertEquals(\"a\", Paths.getLastPathSegment(\"a///\"));\n        assertEquals(\"c\", Paths.getLastPathSegment(\"a/b/c\"));\n        assertEquals(\"c\", Paths.getLastPathSegment(\"a/b//c\"));\n        assertEquals(\"c\", Paths.getLastPathSegment(\"a/b///c\"));\n        assertEquals(\"c\", Paths.getLastPathSegment(\"a/b/c/\"));\n        assertEquals(\"c\", Paths.getLastPathSegment(\"a/b/c//\"));\n        assertEquals(\"c\", Paths.getLastPathSegment(\"a/b/c///\"));\n        assertEquals(\"c\", Paths.getLastPathSegment(\"a/b/c/.\"));\n        assertEquals(\"\", Paths.getLastPathSegment(\"a/b/c/..\"));\n        assertEquals(\"\", Paths.getLastPathSegment(\"a/b/c/../\"));\n        assertEquals(\"d\", Paths.getLastPathSegment(\"a/b/c/../d\"));\n        assertEquals(\"c\", Paths.getLastPathSegment(\"../a/b/c\"));\n        assertEquals(\"c\", Paths.getLastPathSegment(\"/../a/b/c\"));\n        assertEquals(\"ewrjpoewiwfjfpwrejtp\", Paths.getLastPathSegment(\"asdkjrejvncnmiet/eru43jffn/ewrjpoewiwfjfpwrejtp\"));\n        assertEquals(\"ewrjpoewiwfjfpwrejtp\", Paths.getLastPathSegment(\"asdkjrejvncnmiet/eru43jffn/ewrjpoewiwfjfpwrejtp/\"));\n    }\n\n    @Test\n    public void removeLastPathSegment() {\n        assertEquals(\"\", Paths.removeLastPathSegment(\"\"));\n        assertEquals(\"/\", Paths.removeLastPathSegment(\"/\"));\n        assertEquals(\"/\", Paths.removeLastPathSegment(\"/\\n/\"));\n        assertEquals(\"/\", Paths.removeLastPathSegment(\"/\\n\\r/\"));\n        assertEquals(\"/\", Paths.removeLastPathSegment(\"///\"));\n        assertEquals(\"/\", Paths.removeLastPathSegment(\"/n\\n\\rr/\"));\n        assertEquals(\"/\", Paths.removeLastPathSegment(\"/.\"));\n        assertEquals(\"\", Paths.removeLastPathSegment(\".ext\"));\n        assertEquals(\"/\", Paths.removeLastPathSegment(\"/.ext\"));\n        assertEquals(\"\", Paths.removeLastPathSegment(\"a/\"));\n        assertEquals(\"a\", Paths.removeLastPathSegment(\"a/b/.\"));\n        assertEquals(\"a\", Paths.removeLastPathSegment(\"a/b//.\"));\n        assertEquals(\"a/b/..\", Paths.removeLastPathSegment(\"a/b/..\"));\n        assertEquals(\"a/b/../..\", Paths.removeLastPathSegment(\"a/b/../..\"));\n        assertEquals(\"..\", Paths.removeLastPathSegment(\"../\"));\n        assertEquals(\"../a\", Paths.removeLastPathSegment(\"../a/b\"));\n        assertEquals(\"/../a\", Paths.removeLastPathSegment(\"/../a/b\"));\n        assertEquals(\"a\", Paths.removeLastPathSegment(\"a/b/\"));\n        assertEquals(\"a\", Paths.removeLastPathSegment(\"a/b.c\"));\n        assertEquals(\"a\", Paths.removeLastPathSegment(\"a/b.c/\"));\n        assertEquals(\"a/b.c\", Paths.removeLastPathSegment(\"a/b.c/d\"));\n        assertEquals(\"a\", Paths.removeLastPathSegment(\"a/b.c.d\"));\n        assertEquals(\"a\", Paths.removeLastPathSegment(\"a/b.c.d.e\"));\n        assertEquals(\"asdkjrejvncnmiet/eru43jffn\", Paths.removeLastPathSegment(\"asdkjrejvncnmiet/eru43jffn/ewrjpoewiwfjfpwrejtp.ext\"));\n    }\n\n    @Test\n    public void appendPathSegment() {\n        assertEquals(\"\", Paths.appendPathSegment(\"\", \"\"));\n        assertEquals(\"\", Paths.appendPathSegment(\"\", \"/\"));\n        assertEquals(\"\", Paths.appendPathSegment(\"\", \"/\\n\"));\n        assertEquals(\"\", Paths.appendPathSegment(\"\", \"/\\n\\r\"));\n        assertEquals(\"\", Paths.appendPathSegment(\"\", \"/\\n\\r/\"));\n        assertEquals(\"/\", Paths.appendPathSegment(\"/\", \"\"));\n        assertEquals(\"/\", Paths.appendPathSegment(\"/\", \"/\"));\n        assertEquals(\"/a\", Paths.appendPathSegment(\"/\", \"a\"));\n        assertEquals(\"/a\", Paths.appendPathSegment(\"/\", \"/a\"));\n        assertEquals(\"/a\", Paths.appendPathSegment(\"/\", \"a/\"));\n        assertEquals(\"/a\", Paths.appendPathSegment(\"/\", \"/a/\"));\n        assertEquals(\"/a/b/c/d\", Paths.appendPathSegment(\"/a/b/c\", \"d\"));\n        assertEquals(\"/a/b/c/d\", Paths.appendPathSegment(\"/a/b/c/\", \"d\"));\n        assertEquals(\"/a/b/c/d\", Paths.appendPathSegment(\"/a/b/c/\", \"/d\"));\n        assertEquals(\"/a/b/c/d\", Paths.appendPathSegment(\"/a/b/c/\", \"/d/\"));\n    }\n\n    @Test\n    public void trimPathExtension() {\n        assertEquals(\"\", Paths.trimPathExtension(\"\"));\n        assertEquals(\"/\", Paths.trimPathExtension(\"/\"));\n        assertEquals(\"/\", Paths.trimPathExtension(\"/.\"));\n        assertEquals(\".ext\", Paths.trimPathExtension(\".ext\"));\n        assertEquals(\"/.ext\", Paths.trimPathExtension(\"/.ext\"));\n        assertEquals(\"a\", Paths.trimPathExtension(\"a/\"));\n        assertEquals(\"a/b\", Paths.trimPathExtension(\"a/b/.\"));\n        assertEquals(\"a/b/..\", Paths.trimPathExtension(\"a/b/..\"));\n        assertEquals(\"a/b\", Paths.trimPathExtension(\"a/b/\"));\n        assertEquals(\"a/b\", Paths.trimPathExtension(\"a/b/\"));\n        assertEquals(\"a/b\", Paths.trimPathExtension(\"a/b.c\"));\n        assertEquals(\"a/b\", Paths.trimPathExtension(\"a/b.c/\"));\n        assertEquals(\"a/b.c/d\", Paths.trimPathExtension(\"a/b.c/d\"));\n        assertEquals(\"a/b.c\", Paths.trimPathExtension(\"a/b.c.d\"));\n        assertEquals(\"a/b.c.d\", Paths.trimPathExtension(\"a/b.c.d.e\"));\n        assertEquals(\"asdkjrejvncnmiet/eru43jffn/ewrjpoewiwfjfpwrejtp\",\n                Paths.trimPathExtension(\"asdkjrejvncnmiet/eru43jffn/ewrjpoewiwfjfpwrejtp.ext\"));\n    }\n\n    @Test\n    public void getPathExtension() {\n        assertNull(Paths.getPathExtension(\"\"));\n        assertNull(Paths.getPathExtension(\"/\"));\n        assertNull(Paths.getPathExtension(\"/.\"));\n        assertEquals(\"ext\", Paths.getPathExtension(\".ext\"));\n        assertEquals(\"ext\", Paths.getPathExtension(\"/.ext\"));\n        assertNull(Paths.getPathExtension(\"a/\"));\n        assertNull(Paths.getPathExtension(\"a/b/.\"));\n        assertNull(Paths.getPathExtension(\"a/b/..\"));\n        assertNull(Paths.getPathExtension(\"a/b/\"));\n        assertNull(Paths.getPathExtension(\"a/b/\"));\n        assertEquals(\"c\", Paths.getPathExtension(\"a/b.c\"));\n        assertEquals(\"c\", Paths.getPathExtension(\"a/b.c/\"));\n        assertNull(Paths.getPathExtension(\"a/b.c/d\"));\n        assertEquals(\"d\", Paths.getPathExtension(\"a/b.c.d\"));\n        assertEquals(\"e\", Paths.getPathExtension(\"a/b.c.d.e\"));\n        assertNull(Paths.getPathExtension(\"a/b.c.d.e.\"));\n        assertEquals(\"ext\", Paths.getPathExtension(\"asdkjrejvncnmiet/eru43jffn/ewrjpoewiwfjfpwrejtp.ext\"));\n    }\n\n    @Test\n    public void relativePath() {\n\n    }\n}"
  },
  {
    "path": "app/src/test/java/io/github/muntashirakon/io/ShadowLocalFileOverlay.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.io;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport org.robolectric.annotation.Implementation;\nimport org.robolectric.annotation.Implements;\n\n@Implements(LocalFileOverlay.class)\npublic class ShadowLocalFileOverlay {\n    @Implementation\n    @Nullable\n    public static ExtendedFile getOverlayFileOrNull(@NonNull ExtendedFile file) {\n        return null;\n    }\n}\n"
  },
  {
    "path": "app/src/test/java/io/github/muntashirakon/io/SplitInputStreamTest.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.io;\n\nimport static org.junit.Assert.assertEquals;\n\nimport org.junit.After;\nimport org.junit.Before;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.robolectric.RobolectricTestRunner;\n\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.OutputStream;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport io.github.muntashirakon.AppManager.utils.DigestUtils;\n\n@RunWith(RobolectricTestRunner.class)\npublic class SplitInputStreamTest {\n    private final List<Path> fileList = new ArrayList<>();\n    private final List<File> junkFiles = new ArrayList<>();\n    private final ClassLoader classLoader = getClass().getClassLoader();\n\n    @Before\n    public void setUp() {\n        assert classLoader != null;\n        fileList.add(Paths.get(classLoader.getResource(\"AppManager_v2.5.22.apks.0\").getFile()));\n        fileList.add(Paths.get(classLoader.getResource(\"AppManager_v2.5.22.apks.1\").getFile()));\n        fileList.add(Paths.get(classLoader.getResource(\"AppManager_v2.5.22.apks.2\").getFile()));\n        fileList.add(Paths.get(classLoader.getResource(\"AppManager_v2.5.22.apks.3\").getFile()));\n        fileList.add(Paths.get(classLoader.getResource(\"AppManager_v2.5.22.apks.4\").getFile()));\n        fileList.add(Paths.get(classLoader.getResource(\"AppManager_v2.5.22.apks.5\").getFile()));\n        fileList.add(Paths.get(classLoader.getResource(\"AppManager_v2.5.22.apks.6\").getFile()));\n        fileList.add(Paths.get(classLoader.getResource(\"AppManager_v2.5.22.apks.7\").getFile()));\n    }\n\n    @After\n    public void tearDown() {\n        for (File file : junkFiles) {\n            file.delete();\n        }\n    }\n\n    @Test\n    public void read() throws IOException {\n        File file = new File(\"/tmp/AppManager_v2.5.22.apks\");\n        junkFiles.add(file);\n        try (SplitInputStream splitInputStream = new SplitInputStream(fileList);\n             OutputStream outputStream = new FileOutputStream(file)) {\n            IoUtils.copy(splitInputStream, outputStream);\n        }\n        assert classLoader != null;\n        String expectedHash = DigestUtils.getHexDigest(DigestUtils.SHA_256, new File(classLoader.getResource(\"AppManager_v2.5.22.apks\").getFile()));\n        String actualHash = DigestUtils.getHexDigest(DigestUtils.SHA_256, file);\n        assertEquals(expectedHash, actualHash);\n    }\n\n    @Test\n    public void skip() throws IOException {\n        try (SplitInputStream splitInputStream = new SplitInputStream(fileList)) {\n            // For 1 KB\n            long expectedSkipBytes = 10024;\n            long actualSkipBytes = splitInputStream.skip(expectedSkipBytes);\n            assertEquals(expectedSkipBytes, actualSkipBytes);\n            // For 1 MB\n            expectedSkipBytes = 1024 * 1024;\n            actualSkipBytes = splitInputStream.skip(expectedSkipBytes);\n            assertEquals(expectedSkipBytes, actualSkipBytes);\n            // For 2 MB\n            expectedSkipBytes = 1024 * 1024 * 2;\n            actualSkipBytes = splitInputStream.skip(expectedSkipBytes);\n            assertEquals(expectedSkipBytes, actualSkipBytes);\n        }\n    }\n}"
  },
  {
    "path": "app/src/test/java/io/github/muntashirakon/io/SplitOutputStreamTest.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.io;\n\nimport static org.junit.Assert.assertEquals;\n\nimport androidx.annotation.NonNull;\n\nimport org.junit.After;\nimport org.junit.Before;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.robolectric.RobolectricTestRunner;\n\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileNotFoundException;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport io.github.muntashirakon.AppManager.utils.DigestUtils;\n\n@RunWith(RobolectricTestRunner.class)\npublic class SplitOutputStreamTest {\n    private SplitOutputStream splitOutputStream;\n    private InputStream inputStream;\n    private final List<File> junkFiles = new ArrayList<>();\n    private final ClassLoader classLoader = getClass().getClassLoader();\n\n    @Before\n    public void setUp() throws Exception {\n        Path tmpPath = Paths.get(\"/tmp\");\n        splitOutputStream = new SplitOutputStream(tmpPath, \"AppManager_v2.5.22.apks\", 1024000);\n        assert classLoader != null;\n        File sampleFile = new File(classLoader.getResource(\"AppManager_v2.5.22.apks\").getFile());\n        inputStream = new FileInputStream(sampleFile);\n    }\n\n    @After\n    public void tearDown() throws Exception {\n        splitOutputStream.close();\n        inputStream.close();\n        for (File file : junkFiles) {\n            file.delete();\n        }\n    }\n\n    @Test\n    public void write() throws IOException {\n        IoUtils.copy(inputStream, splitOutputStream);\n        List<String> expectedHashes = getExpectedHashes();\n        List<String> actualHashes = getActualHashes();\n        assertEquals(expectedHashes, actualHashes);\n    }\n\n    @NonNull\n    private List<String> getExpectedHashes() {\n        List<String> expectedHashes = new ArrayList<>();\n        List<File> fileList = new ArrayList<>();\n        assert classLoader != null;\n        fileList.add(new File(classLoader.getResource(\"AppManager_v2.5.22.apks.0\").getFile()));\n        fileList.add(new File(classLoader.getResource(\"AppManager_v2.5.22.apks.1\").getFile()));\n        fileList.add(new File(classLoader.getResource(\"AppManager_v2.5.22.apks.2\").getFile()));\n        fileList.add(new File(classLoader.getResource(\"AppManager_v2.5.22.apks.3\").getFile()));\n        fileList.add(new File(classLoader.getResource(\"AppManager_v2.5.22.apks.4\").getFile()));\n        fileList.add(new File(classLoader.getResource(\"AppManager_v2.5.22.apks.5\").getFile()));\n        fileList.add(new File(classLoader.getResource(\"AppManager_v2.5.22.apks.6\").getFile()));\n        fileList.add(new File(classLoader.getResource(\"AppManager_v2.5.22.apks.7\").getFile()));\n        for (File file : fileList) {\n            expectedHashes.add(DigestUtils.getHexDigest(DigestUtils.SHA_256, file));\n        }\n        return expectedHashes;\n    }\n\n    @NonNull\n    private List<String> getActualHashes() throws FileNotFoundException {\n        List<String> actualHashes = new ArrayList<>();\n        List<File> fileList = new ArrayList<>();\n        fileList.add(new File(\"/tmp/AppManager_v2.5.22.apks.0\"));\n        fileList.add(new File(\"/tmp/AppManager_v2.5.22.apks.1\"));\n        fileList.add(new File(\"/tmp/AppManager_v2.5.22.apks.2\"));\n        fileList.add(new File(\"/tmp/AppManager_v2.5.22.apks.3\"));\n        fileList.add(new File(\"/tmp/AppManager_v2.5.22.apks.4\"));\n        fileList.add(new File(\"/tmp/AppManager_v2.5.22.apks.5\"));\n        fileList.add(new File(\"/tmp/AppManager_v2.5.22.apks.6\"));\n        fileList.add(new File(\"/tmp/AppManager_v2.5.22.apks.7\"));\n        for (File file : fileList) {\n            if (!file.exists()) {\n                throw new FileNotFoundException(file + \" does not exist.\");\n            }\n            actualHashes.add(DigestUtils.getHexDigest(DigestUtils.SHA_256, file));\n            junkFiles.add(file);\n        }\n        return actualHashes;\n    }\n}"
  },
  {
    "path": "app/src/test/java/io/github/muntashirakon/io/fs/ZipFileSystemTest.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.io.fs;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertFalse;\nimport static org.junit.Assert.assertNotEquals;\nimport static org.junit.Assert.assertNotNull;\nimport static org.junit.Assert.assertNull;\nimport static org.junit.Assert.assertThrows;\nimport static org.junit.Assert.assertTrue;\n\nimport org.junit.After;\nimport org.junit.Before;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.robolectric.RobolectricTestRunner;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.io.OutputStream;\nimport java.nio.charset.StandardCharsets;\nimport java.util.Objects;\nimport java.util.concurrent.atomic.AtomicReference;\n\nimport io.github.muntashirakon.io.Path;\nimport io.github.muntashirakon.io.Paths;\n\n// Note: We don't have to test weird paths such as ./, ../, etc. because they're taken care of by the Path API.\n@RunWith(RobolectricTestRunner.class)\npublic class ZipFileSystemTest {\n    private final ClassLoader classLoader = Objects.requireNonNull(getClass().getClassLoader());\n    private Path tmpPath;\n\n    @Before\n    public void setUp() throws Exception {\n        tmpPath = Paths.get(\"/tmp\");\n    }\n\n    @After\n    public void tearDown() throws Exception {\n    }\n\n    @Test\n    public void isFileOrDirectory() throws IOException {\n        Path base = Paths.get(classLoader.getResource(\"oandbackups/dnsfilter.android\").getFile());\n        Path apkFile = base.findFile(\"base.apk\");\n        Path mountPoint = Paths.get(\"/tmp/am_mount_point_1\");\n        int fsId = VirtualFileSystem.mount(mountPoint.getUri(), apkFile, \"application/zip\");\n        assertTrue(mountPoint.findFile(\"AndroidManifest.xml\").isFile());\n        assertTrue(mountPoint.findFile(\"assets\").isDirectory());\n        assertTrue(mountPoint.findFile(\"classes.dex\").isFile());\n        assertTrue(mountPoint.findFile(\"META-INF\").isDirectory());\n        assertTrue(mountPoint.findFile(\"res\").isDirectory());\n        assertTrue(mountPoint.findFile(\"resources.arsc\").isFile());\n        VirtualFileSystem.unmount(fsId);\n    }\n\n    @Test\n    public void isHidden() {\n        // TODO: 25/11/22\n    }\n\n    @Test\n    public void lastAccess() {\n        // TODO: 25/11/22\n    }\n\n    @Test\n    public void creationTime() {\n        // TODO: 25/11/22\n    }\n\n    @Test\n    public void createNewFileReadOnly() throws IOException {\n        Path base = Paths.get(classLoader.getResource(\"oandbackups/dnsfilter.android\").getFile());\n        Path apkFile = base.findFile(\"base.apk\");\n        Path mountPoint = Paths.get(\"/tmp/am_mount_point_2\");\n        int fsId = VirtualFileSystem.mount(mountPoint.getUri(), apkFile, \"application/zip\");\n        assertThrows(IOException.class, () -> mountPoint.createNewFile(\"test.txt\", null));\n        assertTrue(mountPoint.findFile(\"AndroidManifest.xml\").isFile());\n        assertTrue(mountPoint.findFile(\"assets\").isDirectory());\n        assertTrue(mountPoint.findFile(\"classes.dex\").isFile());\n        assertTrue(mountPoint.findFile(\"META-INF\").isDirectory());\n        assertTrue(mountPoint.findFile(\"res\").isDirectory());\n        assertTrue(mountPoint.findFile(\"resources.arsc\").isFile());\n        VirtualFileSystem.unmount(fsId);\n    }\n\n    @Test\n    public void createNewFileRWNoChange() throws IOException {\n        Path base = Paths.get(classLoader.getResource(\"oandbackups/dnsfilter.android\").getFile());\n        Path apkFile = base.findFile(\"base.apk\");\n        Path mountPoint = Paths.get(\"/tmp/am_mount_point_3\");\n        AtomicReference<File> modifiedApk = new AtomicReference<>();\n        VirtualFileSystem.MountOptions options = getRWOptions((fs, cachedFile) -> {\n            modifiedApk.set(cachedFile);\n            return true;\n        });\n        int fsId = VirtualFileSystem.mount(mountPoint.getUri(), apkFile, \"application/zip\", options);\n        assertTrue(mountPoint.findFile(\"AndroidManifest.xml\").isFile());\n        assertTrue(mountPoint.findFile(\"assets\").isDirectory());\n        assertTrue(mountPoint.findFile(\"classes.dex\").isFile());\n        assertTrue(mountPoint.findFile(\"META-INF\").isDirectory());\n        assertTrue(mountPoint.findFile(\"res\").isDirectory());\n        assertTrue(mountPoint.findFile(\"resources.arsc\").isFile());\n        VirtualFileSystem.unmount(fsId);\n        assertNull(modifiedApk.get());\n    }\n\n    @Test\n    public void createNewFileRW() throws IOException {\n        Path base = Paths.get(classLoader.getResource(\"oandbackups/dnsfilter.android\").getFile());\n        Path apkFile = base.findFile(\"base.apk\");\n        Path mountPoint = Paths.get(\"/tmp/am_mount_point_4\");\n        AtomicReference<File> modifiedApk = new AtomicReference<>();\n        VirtualFileSystem.MountOptions options = getRWOptions((fs, cachedFile) -> {\n            modifiedApk.set(cachedFile);\n            return true;\n        });\n        int fsId = VirtualFileSystem.mount(mountPoint.getUri(), apkFile, \"application/zip\", options);\n        Path testText = mountPoint.createNewFile(\"test.txt\", null);\n        try (OutputStream os = testText.openOutputStream()) {\n            os.write(\"This is a test file\".getBytes(StandardCharsets.UTF_8));\n        }\n        assertTrue(mountPoint.findFile(\"AndroidManifest.xml\").isFile());\n        assertTrue(mountPoint.findFile(\"assets\").isDirectory());\n        assertTrue(mountPoint.findFile(\"classes.dex\").isFile());\n        assertTrue(mountPoint.findFile(\"META-INF\").isDirectory());\n        assertTrue(mountPoint.findFile(\"res\").isDirectory());\n        assertTrue(mountPoint.findFile(\"resources.arsc\").isFile());\n        VirtualFileSystem.unmount(fsId);\n        assertNotNull(modifiedApk.get());\n        // Remount to verify contents\n        fsId = VirtualFileSystem.mount(mountPoint.getUri(), Paths.get(modifiedApk.get()), \"application/zip\");\n        assertTrue(mountPoint.findFile(\"AndroidManifest.xml\").isFile());\n        assertTrue(mountPoint.findFile(\"assets\").isDirectory());\n        assertTrue(mountPoint.findFile(\"classes.dex\").isFile());\n        assertTrue(mountPoint.findFile(\"META-INF\").isDirectory());\n        assertTrue(mountPoint.findFile(\"res\").isDirectory());\n        assertTrue(mountPoint.findFile(\"resources.arsc\").isFile());\n        assertTrue(mountPoint.findFile(\"test.txt\").isFile());\n        assertEquals(\"This is a test file\", mountPoint.findFile(\"test.txt\").getContentAsString());\n        VirtualFileSystem.unmount(fsId);\n        assertTrue(modifiedApk.get().delete());\n    }\n\n    @Test\n    public void createNewFileRWInplace() throws IOException {\n        Path base = Paths.get(classLoader.getResource(\"oandbackups/dnsfilter.android\").getFile());\n        Path apkFile = base.findFile(\"base.apk\");\n        Path tmpApkFile = apkFile.copyTo(tmpPath);\n        assertNotNull(tmpApkFile);\n        Path mountPoint = Paths.get(\"/tmp/am_mount_point_5\");\n        VirtualFileSystem.MountOptions options = getRWOptions((fs, cachedFile) -> false);\n        int fsId = VirtualFileSystem.mount(mountPoint.getUri(), tmpApkFile, \"application/zip\", options);\n        Path testText = mountPoint.createNewFile(\"test.txt\", null);\n        try (OutputStream os = testText.openOutputStream()) {\n            os.write(\"This is a test file\".getBytes(StandardCharsets.UTF_8));\n        }\n        assertTrue(mountPoint.findFile(\"AndroidManifest.xml\").isFile());\n        assertTrue(mountPoint.findFile(\"assets\").isDirectory());\n        assertTrue(mountPoint.findFile(\"classes.dex\").isFile());\n        assertTrue(mountPoint.findFile(\"META-INF\").isDirectory());\n        assertTrue(mountPoint.findFile(\"res\").isDirectory());\n        assertTrue(mountPoint.findFile(\"resources.arsc\").isFile());\n        VirtualFileSystem.unmount(fsId);\n        // Remount to verify contents\n        fsId = VirtualFileSystem.mount(mountPoint.getUri(), tmpApkFile, \"application/zip\");\n        assertTrue(mountPoint.findFile(\"AndroidManifest.xml\").isFile());\n        assertTrue(mountPoint.findFile(\"assets\").isDirectory());\n        assertTrue(mountPoint.findFile(\"classes.dex\").isFile());\n        assertTrue(mountPoint.findFile(\"META-INF\").isDirectory());\n        assertTrue(mountPoint.findFile(\"res\").isDirectory());\n        assertTrue(mountPoint.findFile(\"resources.arsc\").isFile());\n        assertTrue(mountPoint.findFile(\"test.txt\").isFile());\n        assertEquals(\"This is a test file\", mountPoint.findFile(\"test.txt\").getContentAsString());\n        VirtualFileSystem.unmount(fsId);\n        assertTrue(tmpApkFile.delete());\n    }\n\n    @Test\n    public void deleteReadOnly() throws IOException {\n        Path base = Paths.get(classLoader.getResource(\"oandbackups/dnsfilter.android\").getFile());\n        Path apkFile = base.findFile(\"base.apk\");\n        Path mountPoint = Paths.get(\"/tmp/am_mount_point_6\");\n        int fsId = VirtualFileSystem.mount(mountPoint.getUri(), apkFile, \"application/zip\");\n        assertFalse(mountPoint.findFile(\"resources.arsc\").delete());\n        assertTrue(mountPoint.findFile(\"AndroidManifest.xml\").isFile());\n        assertTrue(mountPoint.findFile(\"assets\").isDirectory());\n        assertTrue(mountPoint.findFile(\"classes.dex\").isFile());\n        assertTrue(mountPoint.findFile(\"META-INF\").isDirectory());\n        assertTrue(mountPoint.findFile(\"res\").isDirectory());\n        VirtualFileSystem.unmount(fsId);\n    }\n\n    @Test\n    public void deleteRW() throws IOException {\n        Path base = Paths.get(classLoader.getResource(\"oandbackups/dnsfilter.android\").getFile());\n        Path apkFile = base.findFile(\"base.apk\");\n        Path mountPoint = Paths.get(\"/tmp/am_mount_point_7\");\n        AtomicReference<File> modifiedApk = new AtomicReference<>();\n        VirtualFileSystem.MountOptions options = getRWOptions((fs, cachedFile) -> {\n            modifiedApk.set(cachedFile);\n            return true;\n        });\n        int fsId = VirtualFileSystem.mount(mountPoint.getUri(), apkFile, \"application/zip\", options);\n        assertTrue(mountPoint.findFile(\"resources.arsc\").delete());\n        assertTrue(mountPoint.findFile(\"AndroidManifest.xml\").isFile());\n        assertTrue(mountPoint.findFile(\"assets\").isDirectory());\n        assertTrue(mountPoint.findFile(\"classes.dex\").isFile());\n        assertTrue(mountPoint.findFile(\"META-INF\").isDirectory());\n        assertTrue(mountPoint.findFile(\"res\").isDirectory());\n        VirtualFileSystem.unmount(fsId);\n        assertNotNull(modifiedApk.get());\n        // Remount to verify contents\n        fsId = VirtualFileSystem.mount(mountPoint.getUri(), Paths.get(modifiedApk.get()), \"application/zip\");\n        assertTrue(mountPoint.findFile(\"AndroidManifest.xml\").isFile());\n        assertTrue(mountPoint.findFile(\"assets\").isDirectory());\n        assertTrue(mountPoint.findFile(\"classes.dex\").isFile());\n        assertTrue(mountPoint.findFile(\"META-INF\").isDirectory());\n        assertTrue(mountPoint.findFile(\"res\").isDirectory());\n        assertFalse(mountPoint.hasFile(\"resources.arsc\"));\n        VirtualFileSystem.unmount(fsId);\n        assertTrue(modifiedApk.get().delete());\n    }\n\n    @Test\n    public void deleteCreateFromExistingFileRW() throws IOException {\n        Path base = Paths.get(classLoader.getResource(\"oandbackups/dnsfilter.android\").getFile());\n        Path apkFile = base.findFile(\"base.apk\");\n        Path mountPoint = Paths.get(\"/tmp/am_mount_point_8\");\n        AtomicReference<File> modifiedApk = new AtomicReference<>();\n        VirtualFileSystem.MountOptions options = getRWOptions((fs, cachedFile) -> {\n            modifiedApk.set(cachedFile);\n            return true;\n        });\n        int fsId = VirtualFileSystem.mount(mountPoint.getUri(), apkFile, \"application/zip\", options);\n        assertNotEquals(0, mountPoint.findFile(\"resources.arsc\").length());\n        assertTrue(mountPoint.findFile(\"resources.arsc\").delete());\n        Path arsc = mountPoint.createNewFile(\"resources.arsc\", null);\n        assertEquals(0, arsc.length());\n        assertTrue(mountPoint.findFile(\"AndroidManifest.xml\").isFile());\n        assertTrue(mountPoint.findFile(\"assets\").isDirectory());\n        assertTrue(mountPoint.findFile(\"classes.dex\").isFile());\n        assertTrue(mountPoint.findFile(\"META-INF\").isDirectory());\n        assertTrue(mountPoint.findFile(\"res\").isDirectory());\n        VirtualFileSystem.unmount(fsId);\n        assertNotNull(modifiedApk.get());\n        // Remount to verify contents\n        fsId = VirtualFileSystem.mount(mountPoint.getUri(), Paths.get(modifiedApk.get()), \"application/zip\");\n        assertTrue(mountPoint.findFile(\"AndroidManifest.xml\").isFile());\n        assertTrue(mountPoint.findFile(\"assets\").isDirectory());\n        assertTrue(mountPoint.findFile(\"classes.dex\").isFile());\n        assertTrue(mountPoint.findFile(\"META-INF\").isDirectory());\n        assertTrue(mountPoint.findFile(\"res\").isDirectory());\n        assertTrue(mountPoint.findFile(\"resources.arsc\").isFile());\n        assertEquals(0, mountPoint.findFile(\"resources.arsc\").length());\n        VirtualFileSystem.unmount(fsId);\n        assertTrue(modifiedApk.get().delete());\n    }\n\n    @Test\n    public void deleteCreateDirFromExistingFileRW() throws IOException {\n        Path base = Paths.get(classLoader.getResource(\"oandbackups/dnsfilter.android\").getFile());\n        Path apkFile = base.findFile(\"base.apk\");\n        Path mountPoint = Paths.get(\"/tmp/am_mount_point_9\");\n        AtomicReference<File> modifiedApk = new AtomicReference<>();\n        VirtualFileSystem.MountOptions options = getRWOptions((fs, cachedFile) -> {\n            modifiedApk.set(cachedFile);\n            return true;\n        });\n        int fsId = VirtualFileSystem.mount(mountPoint.getUri(), apkFile, \"application/zip\", options);\n        assertNotEquals(0, mountPoint.findFile(\"resources.arsc\").length());\n        assertTrue(mountPoint.findFile(\"resources.arsc\").delete());\n        Path arsc = mountPoint.createNewDirectory(\"resources.arsc\");\n        assertEquals(0, arsc.length());\n        assertTrue(mountPoint.findFile(\"AndroidManifest.xml\").isFile());\n        assertTrue(mountPoint.findFile(\"assets\").isDirectory());\n        assertTrue(mountPoint.findFile(\"classes.dex\").isFile());\n        assertTrue(mountPoint.findFile(\"META-INF\").isDirectory());\n        assertTrue(mountPoint.findFile(\"res\").isDirectory());\n        VirtualFileSystem.unmount(fsId);\n        assertNotNull(modifiedApk.get());\n        // Remount to verify contents\n        fsId = VirtualFileSystem.mount(mountPoint.getUri(), Paths.get(modifiedApk.get()), \"application/zip\");\n        assertTrue(mountPoint.findFile(\"AndroidManifest.xml\").isFile());\n        assertTrue(mountPoint.findFile(\"assets\").isDirectory());\n        assertTrue(mountPoint.findFile(\"classes.dex\").isFile());\n        assertTrue(mountPoint.findFile(\"META-INF\").isDirectory());\n        assertTrue(mountPoint.findFile(\"res\").isDirectory());\n        assertTrue(mountPoint.findFile(\"resources.arsc\").isDirectory());\n        assertEquals(0, mountPoint.findFile(\"resources.arsc\").length());\n        VirtualFileSystem.unmount(fsId);\n        assertTrue(modifiedApk.get().delete());\n    }\n\n    @Test\n    public void deleteCreateDeleteFromExistingFileRW() throws IOException {\n        Path base = Paths.get(classLoader.getResource(\"oandbackups/dnsfilter.android\").getFile());\n        Path apkFile = base.findFile(\"base.apk\");\n        Path mountPoint = Paths.get(\"/tmp/am_mount_point_10\");\n        AtomicReference<File> modifiedApk = new AtomicReference<>();\n        VirtualFileSystem.MountOptions options = getRWOptions((fs, cachedFile) -> {\n            modifiedApk.set(cachedFile);\n            return true;\n        });\n        int fsId = VirtualFileSystem.mount(mountPoint.getUri(), apkFile, \"application/zip\", options);\n        assertNotEquals(0, mountPoint.findFile(\"resources.arsc\").length());\n        assertTrue(mountPoint.findFile(\"resources.arsc\").delete());\n        Path arsc = mountPoint.createNewFile(\"resources.arsc\", null);\n        assertEquals(0, arsc.length());\n        assertTrue(arsc.delete());\n        assertTrue(mountPoint.findFile(\"AndroidManifest.xml\").isFile());\n        assertTrue(mountPoint.findFile(\"assets\").isDirectory());\n        assertTrue(mountPoint.findFile(\"classes.dex\").isFile());\n        assertTrue(mountPoint.findFile(\"META-INF\").isDirectory());\n        assertTrue(mountPoint.findFile(\"res\").isDirectory());\n        VirtualFileSystem.unmount(fsId);\n        assertNotNull(modifiedApk.get());\n        // Remount to verify contents\n        fsId = VirtualFileSystem.mount(mountPoint.getUri(), Paths.get(modifiedApk.get()), \"application/zip\");\n        assertTrue(mountPoint.findFile(\"AndroidManifest.xml\").isFile());\n        assertTrue(mountPoint.findFile(\"assets\").isDirectory());\n        assertTrue(mountPoint.findFile(\"classes.dex\").isFile());\n        assertTrue(mountPoint.findFile(\"META-INF\").isDirectory());\n        assertTrue(mountPoint.findFile(\"res\").isDirectory());\n        assertFalse(mountPoint.hasFile(\"resources.arsc\"));\n        VirtualFileSystem.unmount(fsId);\n        assertTrue(modifiedApk.get().delete());\n    }\n\n    @Test\n    public void createDeleteFileRW() throws IOException {\n        Path base = Paths.get(classLoader.getResource(\"oandbackups/dnsfilter.android\").getFile());\n        Path apkFile = base.findFile(\"base.apk\");\n        Path mountPoint = Paths.get(\"/tmp/am_mount_point_11\");\n        AtomicReference<File> modifiedApk = new AtomicReference<>();\n        VirtualFileSystem.MountOptions options = getRWOptions((fs, cachedFile) -> {\n            modifiedApk.set(cachedFile);\n            return true;\n        });\n        int fsId = VirtualFileSystem.mount(mountPoint.getUri(), apkFile, \"application/zip\", options);\n        Path testText = mountPoint.createNewFile(\"test.txt\", null);\n        assertTrue(testText.delete());\n        assertTrue(mountPoint.findFile(\"AndroidManifest.xml\").isFile());\n        assertTrue(mountPoint.findFile(\"assets\").isDirectory());\n        assertTrue(mountPoint.findFile(\"classes.dex\").isFile());\n        assertTrue(mountPoint.findFile(\"META-INF\").isDirectory());\n        assertTrue(mountPoint.findFile(\"res\").isDirectory());\n        assertTrue(mountPoint.findFile(\"resources.arsc\").isFile());\n        VirtualFileSystem.unmount(fsId);\n        assertNotNull(modifiedApk.get());\n        // Remount to verify contents\n        fsId = VirtualFileSystem.mount(mountPoint.getUri(), Paths.get(modifiedApk.get()), \"application/zip\");\n        assertTrue(mountPoint.findFile(\"AndroidManifest.xml\").isFile());\n        assertTrue(mountPoint.findFile(\"assets\").isDirectory());\n        assertTrue(mountPoint.findFile(\"classes.dex\").isFile());\n        assertTrue(mountPoint.findFile(\"META-INF\").isDirectory());\n        assertTrue(mountPoint.findFile(\"res\").isDirectory());\n        assertTrue(mountPoint.findFile(\"resources.arsc\").isFile());\n        assertFalse(mountPoint.hasFile(\"test.txt\"));\n        VirtualFileSystem.unmount(fsId);\n        assertTrue(modifiedApk.get().delete());\n    }\n\n    @Test\n    public void createDeleteDirRW() throws IOException {\n        Path base = Paths.get(classLoader.getResource(\"oandbackups/dnsfilter.android\").getFile());\n        Path apkFile = base.findFile(\"base.apk\");\n        Path mountPoint = Paths.get(\"/tmp/am_mount_point_12\");\n        AtomicReference<File> modifiedApk = new AtomicReference<>();\n        VirtualFileSystem.MountOptions options = getRWOptions((fs, cachedFile) -> {\n            modifiedApk.set(cachedFile);\n            return true;\n        });\n        int fsId = VirtualFileSystem.mount(mountPoint.getUri(), apkFile, \"application/zip\", options);\n        Path testDir = mountPoint.createNewDirectory(\"test_dir\");\n        assertTrue(testDir.delete());\n        assertTrue(mountPoint.findFile(\"AndroidManifest.xml\").isFile());\n        assertTrue(mountPoint.findFile(\"assets\").isDirectory());\n        assertTrue(mountPoint.findFile(\"classes.dex\").isFile());\n        assertTrue(mountPoint.findFile(\"META-INF\").isDirectory());\n        assertTrue(mountPoint.findFile(\"res\").isDirectory());\n        assertTrue(mountPoint.findFile(\"resources.arsc\").isFile());\n        VirtualFileSystem.unmount(fsId);\n        assertNotNull(modifiedApk.get());\n        // Remount to verify contents\n        fsId = VirtualFileSystem.mount(mountPoint.getUri(), Paths.get(modifiedApk.get()), \"application/zip\");\n        assertTrue(mountPoint.findFile(\"AndroidManifest.xml\").isFile());\n        assertTrue(mountPoint.findFile(\"assets\").isDirectory());\n        assertTrue(mountPoint.findFile(\"classes.dex\").isFile());\n        assertTrue(mountPoint.findFile(\"META-INF\").isDirectory());\n        assertTrue(mountPoint.findFile(\"res\").isDirectory());\n        assertTrue(mountPoint.findFile(\"resources.arsc\").isFile());\n        assertFalse(mountPoint.hasFile(\"test_dir\"));\n        VirtualFileSystem.unmount(fsId);\n        assertTrue(modifiedApk.get().delete());\n    }\n\n    @Test\n    public void list() {\n        // TODO: 25/11/22\n    }\n\n    @Test\n    public void mkdir() throws IOException {\n        Path base = Paths.get(classLoader.getResource(\"oandbackups/dnsfilter.android\").getFile());\n        Path apkFile = base.findFile(\"base.apk\");\n        Path mountPoint = Paths.get(\"/tmp/am_mount_point_13\");\n        AtomicReference<File> modifiedApk = new AtomicReference<>();\n        VirtualFileSystem.MountOptions options = getRWOptions((fs, cachedFile) -> {\n            modifiedApk.set(cachedFile);\n            return true;\n        });\n        int fsId = VirtualFileSystem.mount(mountPoint.getUri(), apkFile, \"application/zip\", options);\n        VirtualFileSystem fs = Objects.requireNonNull(VirtualFileSystem.getFileSystem(fsId));\n        assertTrue(fs.mkdir(\"/test_dir\"));\n        assertTrue(mountPoint.findFile(\"AndroidManifest.xml\").isFile());\n        assertTrue(mountPoint.findFile(\"assets\").isDirectory());\n        assertTrue(mountPoint.findFile(\"classes.dex\").isFile());\n        assertTrue(mountPoint.findFile(\"META-INF\").isDirectory());\n        assertTrue(mountPoint.findFile(\"res\").isDirectory());\n        assertTrue(mountPoint.findFile(\"resources.arsc\").isFile());\n        assertTrue(mountPoint.findFile(\"test_dir\").isDirectory());\n        VirtualFileSystem.unmount(fsId);\n        assertNotNull(modifiedApk.get());\n        // Remount to verify contents\n        fsId = VirtualFileSystem.mount(mountPoint.getUri(), Paths.get(modifiedApk.get()), \"application/zip\");\n        assertTrue(mountPoint.findFile(\"AndroidManifest.xml\").isFile());\n        assertTrue(mountPoint.findFile(\"assets\").isDirectory());\n        assertTrue(mountPoint.findFile(\"classes.dex\").isFile());\n        assertTrue(mountPoint.findFile(\"META-INF\").isDirectory());\n        assertTrue(mountPoint.findFile(\"res\").isDirectory());\n        assertTrue(mountPoint.findFile(\"resources.arsc\").isFile());\n        assertTrue(mountPoint.findFile(\"test_dir\").isDirectory());\n        VirtualFileSystem.unmount(fsId);\n        assertTrue(modifiedApk.get().delete());\n    }\n\n    @Test\n    public void mkdirMultipleDirs() throws IOException {\n        Path base = Paths.get(classLoader.getResource(\"oandbackups/dnsfilter.android\").getFile());\n        Path apkFile = base.findFile(\"base.apk\");\n        Path mountPoint = Paths.get(\"/tmp/am_mount_point_14\");\n        AtomicReference<File> modifiedApk = new AtomicReference<>();\n        VirtualFileSystem.MountOptions options = getRWOptions((fs, cachedFile) -> {\n            modifiedApk.set(cachedFile);\n            return true;\n        });\n        int fsId = VirtualFileSystem.mount(mountPoint.getUri(), apkFile, \"application/zip\", options);\n        VirtualFileSystem fs = Objects.requireNonNull(VirtualFileSystem.getFileSystem(fsId));\n        assertFalse(fs.mkdir(\"/test_dir/test_dir_2\"));\n        assertTrue(mountPoint.findFile(\"AndroidManifest.xml\").isFile());\n        assertTrue(mountPoint.findFile(\"assets\").isDirectory());\n        assertTrue(mountPoint.findFile(\"classes.dex\").isFile());\n        assertTrue(mountPoint.findFile(\"META-INF\").isDirectory());\n        assertTrue(mountPoint.findFile(\"res\").isDirectory());\n        assertTrue(mountPoint.findFile(\"resources.arsc\").isFile());\n        assertFalse(mountPoint.hasFile(\"test_dir\"));\n        VirtualFileSystem.unmount(fsId);\n        assertNull(modifiedApk.get());\n    }\n\n    @Test\n    public void mkdirExistingFileOrDir() throws IOException {\n        Path base = Paths.get(classLoader.getResource(\"oandbackups/dnsfilter.android\").getFile());\n        Path apkFile = base.findFile(\"base.apk\");\n        Path mountPoint = Paths.get(\"/tmp/am_mount_point_15\");\n        AtomicReference<File> modifiedApk = new AtomicReference<>();\n        VirtualFileSystem.MountOptions options = getRWOptions((fs, cachedFile) -> {\n            modifiedApk.set(cachedFile);\n            return true;\n        });\n        int fsId = VirtualFileSystem.mount(mountPoint.getUri(), apkFile, \"application/zip\", options);\n        VirtualFileSystem fs = Objects.requireNonNull(VirtualFileSystem.getFileSystem(fsId));\n        assertFalse(fs.mkdir(\"/assets\"));\n        assertFalse(fs.mkdir(\"/classes.dex\"));\n        assertTrue(mountPoint.findFile(\"AndroidManifest.xml\").isFile());\n        assertTrue(mountPoint.findFile(\"assets\").isDirectory());\n        assertTrue(mountPoint.findFile(\"classes.dex\").isFile());\n        assertTrue(mountPoint.findFile(\"META-INF\").isDirectory());\n        assertTrue(mountPoint.findFile(\"res\").isDirectory());\n        assertTrue(mountPoint.findFile(\"resources.arsc\").isFile());\n        assertFalse(mountPoint.hasFile(\"test_dir\"));\n        VirtualFileSystem.unmount(fsId);\n        assertNull(modifiedApk.get());\n    }\n\n    @Test\n    public void mkdirs() throws IOException {\n        Path base = Paths.get(classLoader.getResource(\"oandbackups/dnsfilter.android\").getFile());\n        Path apkFile = base.findFile(\"base.apk\");\n        Path mountPoint = Paths.get(\"/tmp/am_mount_point_16\");\n        AtomicReference<File> modifiedApk = new AtomicReference<>();\n        VirtualFileSystem.MountOptions options = getRWOptions((fs, cachedFile) -> {\n            modifiedApk.set(cachedFile);\n            return true;\n        });\n        int fsId = VirtualFileSystem.mount(mountPoint.getUri(), apkFile, \"application/zip\", options);\n        VirtualFileSystem fs = Objects.requireNonNull(VirtualFileSystem.getFileSystem(fsId));\n        assertTrue(fs.mkdirs(\"/test_dir/test_dir_2\"));\n        assertTrue(mountPoint.findFile(\"AndroidManifest.xml\").isFile());\n        assertTrue(mountPoint.findFile(\"assets\").isDirectory());\n        assertTrue(mountPoint.findFile(\"classes.dex\").isFile());\n        assertTrue(mountPoint.findFile(\"META-INF\").isDirectory());\n        assertTrue(mountPoint.findFile(\"res\").isDirectory());\n        assertTrue(mountPoint.findFile(\"resources.arsc\").isFile());\n        assertTrue(mountPoint.findFile(\"test_dir\").isDirectory());\n        assertTrue(mountPoint.findFile(\"test_dir\").findFile(\"test_dir_2\").isDirectory());\n        VirtualFileSystem.unmount(fsId);\n        assertNotNull(modifiedApk.get());\n        // Remount to verify contents\n        fsId = VirtualFileSystem.mount(mountPoint.getUri(), Paths.get(modifiedApk.get()), \"application/zip\");\n        assertTrue(mountPoint.findFile(\"AndroidManifest.xml\").isFile());\n        assertTrue(mountPoint.findFile(\"assets\").isDirectory());\n        assertTrue(mountPoint.findFile(\"classes.dex\").isFile());\n        assertTrue(mountPoint.findFile(\"META-INF\").isDirectory());\n        assertTrue(mountPoint.findFile(\"res\").isDirectory());\n        assertTrue(mountPoint.findFile(\"resources.arsc\").isFile());\n        assertTrue(mountPoint.findFile(\"test_dir\").isDirectory());\n        assertTrue(mountPoint.findFile(\"test_dir\").findFile(\"test_dir_2\").isDirectory());\n        VirtualFileSystem.unmount(fsId);\n        assertTrue(modifiedApk.get().delete());\n    }\n\n    @Test\n    public void mkdirsInsideExistingDir() throws IOException {\n        Path base = Paths.get(classLoader.getResource(\"oandbackups/dnsfilter.android\").getFile());\n        Path apkFile = base.findFile(\"base.apk\");\n        Path mountPoint = Paths.get(\"/tmp/am_mount_point_17\");\n        AtomicReference<File> modifiedApk = new AtomicReference<>();\n        VirtualFileSystem.MountOptions options = getRWOptions((fs, cachedFile) -> {\n            modifiedApk.set(cachedFile);\n            return true;\n        });\n        int fsId = VirtualFileSystem.mount(mountPoint.getUri(), apkFile, \"application/zip\", options);\n        VirtualFileSystem fs = Objects.requireNonNull(VirtualFileSystem.getFileSystem(fsId));\n        assertTrue(fs.mkdirs(\"/assets/test_dir_2\"));\n        assertTrue(mountPoint.findFile(\"AndroidManifest.xml\").isFile());\n        assertTrue(mountPoint.findFile(\"assets\").isDirectory());\n        assertTrue(mountPoint.findFile(\"classes.dex\").isFile());\n        assertTrue(mountPoint.findFile(\"META-INF\").isDirectory());\n        assertTrue(mountPoint.findFile(\"res\").isDirectory());\n        assertTrue(mountPoint.findFile(\"resources.arsc\").isFile());\n        assertTrue(mountPoint.findFile(\"assets\").findFile(\"test_dir_2\").isDirectory());\n        VirtualFileSystem.unmount(fsId);\n        assertNotNull(modifiedApk.get());\n        // Remount to verify contents\n        fsId = VirtualFileSystem.mount(mountPoint.getUri(), Paths.get(modifiedApk.get()), \"application/zip\");\n        assertTrue(mountPoint.findFile(\"AndroidManifest.xml\").isFile());\n        assertTrue(mountPoint.findFile(\"assets\").isDirectory());\n        assertTrue(mountPoint.findFile(\"classes.dex\").isFile());\n        assertTrue(mountPoint.findFile(\"META-INF\").isDirectory());\n        assertTrue(mountPoint.findFile(\"res\").isDirectory());\n        assertTrue(mountPoint.findFile(\"resources.arsc\").isFile());\n        assertTrue(mountPoint.findFile(\"assets\").findFile(\"test_dir_2\").isDirectory());\n        VirtualFileSystem.unmount(fsId);\n        assertTrue(modifiedApk.get().delete());\n    }\n\n    @Test\n    public void mkdirsAllExistingDirsOrFiles() throws IOException {\n        Path base = Paths.get(classLoader.getResource(\"oandbackups/dnsfilter.android\").getFile());\n        Path apkFile = base.findFile(\"base.apk\");\n        Path mountPoint = Paths.get(\"/tmp/am_mount_point_18\");\n        AtomicReference<File> modifiedApk = new AtomicReference<>();\n        VirtualFileSystem.MountOptions options = getRWOptions((fs, cachedFile) -> {\n            modifiedApk.set(cachedFile);\n            return true;\n        });\n        int fsId = VirtualFileSystem.mount(mountPoint.getUri(), apkFile, \"application/zip\", options);\n        VirtualFileSystem fs = Objects.requireNonNull(VirtualFileSystem.getFileSystem(fsId));\n        assertFalse(fs.mkdirs(\"/assets/dnsfilter.conf\"));\n        assertFalse(fs.mkdirs(\"/res/layout\"));\n        assertTrue(mountPoint.findFile(\"AndroidManifest.xml\").isFile());\n        assertTrue(mountPoint.findFile(\"assets\").isDirectory());\n        assertTrue(mountPoint.findFile(\"classes.dex\").isFile());\n        assertTrue(mountPoint.findFile(\"META-INF\").isDirectory());\n        assertTrue(mountPoint.findFile(\"res\").isDirectory());\n        assertTrue(mountPoint.findFile(\"resources.arsc\").isFile());\n        VirtualFileSystem.unmount(fsId);\n        assertNull(modifiedApk.get());\n    }\n\n    @Test\n    public void renameToExistingFileSameDirectory() throws IOException {\n        Path base = Paths.get(classLoader.getResource(\"oandbackups/dnsfilter.android\").getFile());\n        Path apkFile = base.findFile(\"base.apk\");\n        Path mountPoint = Paths.get(\"/tmp/am_mount_point_19\");\n        AtomicReference<File> modifiedApk = new AtomicReference<>();\n        VirtualFileSystem.MountOptions options = getRWOptions((fs, cachedFile) -> {\n            modifiedApk.set(cachedFile);\n            return true;\n        });\n        int fsId = VirtualFileSystem.mount(mountPoint.getUri(), apkFile, \"application/zip\", options);\n        VirtualFileSystem fs = Objects.requireNonNull(VirtualFileSystem.getFileSystem(fsId));\n        assertTrue(fs.renameTo(\"/AndroidManifest.xml\", \"/Manifest.xml\"));\n        assertFalse(mountPoint.hasFile(\"AndroidManifest.xml\"));\n        assertTrue(mountPoint.findFile(\"Manifest.xml\").isFile());\n        assertTrue(mountPoint.findFile(\"assets\").isDirectory());\n        assertTrue(mountPoint.findFile(\"classes.dex\").isFile());\n        assertTrue(mountPoint.findFile(\"META-INF\").isDirectory());\n        assertTrue(mountPoint.findFile(\"res\").isDirectory());\n        assertTrue(mountPoint.findFile(\"resources.arsc\").isFile());\n        VirtualFileSystem.unmount(fsId);\n        assertNotNull(modifiedApk.get());\n        // Remount to verify contents\n        fsId = VirtualFileSystem.mount(mountPoint.getUri(), Paths.get(modifiedApk.get()), \"application/zip\");\n        assertFalse(mountPoint.hasFile(\"AndroidManifest.xml\"));\n        assertTrue(mountPoint.findFile(\"Manifest.xml\").isFile());\n        assertTrue(mountPoint.findFile(\"assets\").isDirectory());\n        assertTrue(mountPoint.findFile(\"classes.dex\").isFile());\n        assertTrue(mountPoint.findFile(\"META-INF\").isDirectory());\n        assertTrue(mountPoint.findFile(\"res\").isDirectory());\n        assertTrue(mountPoint.findFile(\"resources.arsc\").isFile());\n        VirtualFileSystem.unmount(fsId);\n        assertTrue(modifiedApk.get().delete());\n    }\n\n    @Test\n    public void renameToExistingFileDifferentExistingDirectory() throws IOException {\n        Path base = Paths.get(classLoader.getResource(\"oandbackups/dnsfilter.android\").getFile());\n        Path apkFile = base.findFile(\"base.apk\");\n        Path mountPoint = Paths.get(\"/tmp/am_mount_point_20\");\n        AtomicReference<File> modifiedApk = new AtomicReference<>();\n        VirtualFileSystem.MountOptions options = getRWOptions((fs, cachedFile) -> {\n            modifiedApk.set(cachedFile);\n            return true;\n        });\n        int fsId = VirtualFileSystem.mount(mountPoint.getUri(), apkFile, \"application/zip\", options);\n        VirtualFileSystem fs = Objects.requireNonNull(VirtualFileSystem.getFileSystem(fsId));\n        assertTrue(fs.renameTo(\"/AndroidManifest.xml\", \"/assets/Manifest.xml\"));\n        assertFalse(mountPoint.hasFile(\"AndroidManifest.xml\"));\n        assertTrue(mountPoint.findFile(\"assets\").isDirectory());\n        assertTrue(mountPoint.findFile(\"assets\").findFile(\"Manifest.xml\").isFile());\n        assertTrue(mountPoint.findFile(\"assets\").findFile(\"dnsfilter.conf\").isFile());\n        assertTrue(mountPoint.findFile(\"assets\").findFile(\"additionalHosts.txt\").isFile());\n        assertTrue(mountPoint.findFile(\"classes.dex\").isFile());\n        assertTrue(mountPoint.findFile(\"META-INF\").isDirectory());\n        assertTrue(mountPoint.findFile(\"res\").isDirectory());\n        assertTrue(mountPoint.findFile(\"resources.arsc\").isFile());\n        VirtualFileSystem.unmount(fsId);\n        assertNotNull(modifiedApk.get());\n        // Remount to verify contents\n        fsId = VirtualFileSystem.mount(mountPoint.getUri(), Paths.get(modifiedApk.get()), \"application/zip\");\n        assertFalse(mountPoint.hasFile(\"AndroidManifest.xml\"));\n        assertTrue(mountPoint.findFile(\"assets\").isDirectory());\n        assertTrue(mountPoint.findFile(\"assets\").findFile(\"Manifest.xml\").isFile());\n        assertTrue(mountPoint.findFile(\"assets\").findFile(\"dnsfilter.conf\").isFile());\n        assertTrue(mountPoint.findFile(\"assets\").findFile(\"additionalHosts.txt\").isFile());\n        assertTrue(mountPoint.findFile(\"classes.dex\").isFile());\n        assertTrue(mountPoint.findFile(\"META-INF\").isDirectory());\n        assertTrue(mountPoint.findFile(\"res\").isDirectory());\n        assertTrue(mountPoint.findFile(\"resources.arsc\").isFile());\n        VirtualFileSystem.unmount(fsId);\n        assertTrue(modifiedApk.get().delete());\n    }\n\n    @Test\n    public void renameToExistingFileDifferentNonExistingDirectory() throws IOException {\n        Path base = Paths.get(classLoader.getResource(\"oandbackups/dnsfilter.android\").getFile());\n        Path apkFile = base.findFile(\"base.apk\");\n        Path mountPoint = Paths.get(\"/tmp/am_mount_point_21\");\n        AtomicReference<File> modifiedApk = new AtomicReference<>();\n        VirtualFileSystem.MountOptions options = getRWOptions((fs, cachedFile) -> {\n            modifiedApk.set(cachedFile);\n            return true;\n        });\n        int fsId = VirtualFileSystem.mount(mountPoint.getUri(), apkFile, \"application/zip\", options);\n        VirtualFileSystem fs = Objects.requireNonNull(VirtualFileSystem.getFileSystem(fsId));\n        assertTrue(fs.renameTo(\"/AndroidManifest.xml\", \"/test_dir/Manifest.xml\"));\n        assertFalse(mountPoint.hasFile(\"AndroidManifest.xml\"));\n        assertTrue(mountPoint.findFile(\"assets\").isDirectory());\n        assertTrue(mountPoint.findFile(\"classes.dex\").isFile());\n        assertTrue(mountPoint.findFile(\"META-INF\").isDirectory());\n        assertTrue(mountPoint.findFile(\"res\").isDirectory());\n        assertTrue(mountPoint.findFile(\"resources.arsc\").isFile());\n        assertTrue(mountPoint.findFile(\"test_dir\").isDirectory());\n        assertTrue(mountPoint.findFile(\"test_dir\").findFile(\"Manifest.xml\").isFile());\n        VirtualFileSystem.unmount(fsId);\n        assertNotNull(modifiedApk.get());\n        // Remount to verify contents\n        fsId = VirtualFileSystem.mount(mountPoint.getUri(), Paths.get(modifiedApk.get()), \"application/zip\");\n        assertFalse(mountPoint.hasFile(\"AndroidManifest.xml\"));\n        assertTrue(mountPoint.findFile(\"assets\").isDirectory());\n        assertTrue(mountPoint.findFile(\"classes.dex\").isFile());\n        assertTrue(mountPoint.findFile(\"META-INF\").isDirectory());\n        assertTrue(mountPoint.findFile(\"res\").isDirectory());\n        assertTrue(mountPoint.findFile(\"resources.arsc\").isFile());\n        assertTrue(mountPoint.findFile(\"test_dir\").isDirectory());\n        assertTrue(mountPoint.findFile(\"test_dir\").findFile(\"Manifest.xml\").isFile());\n        VirtualFileSystem.unmount(fsId);\n        assertTrue(modifiedApk.get().delete());\n    }\n\n    @Test\n    public void renameToExistingFileExistingFile() throws IOException {\n        Path base = Paths.get(classLoader.getResource(\"oandbackups/dnsfilter.android\").getFile());\n        Path apkFile = base.findFile(\"base.apk\");\n        Path mountPoint = Paths.get(\"/tmp/am_mount_point_22\");\n        AtomicReference<File> modifiedApk = new AtomicReference<>();\n        VirtualFileSystem.MountOptions options = getRWOptions((fs, cachedFile) -> {\n            modifiedApk.set(cachedFile);\n            return true;\n        });\n        int fsId = VirtualFileSystem.mount(mountPoint.getUri(), apkFile, \"application/zip\", options);\n        VirtualFileSystem fs = Objects.requireNonNull(VirtualFileSystem.getFileSystem(fsId));\n        String manifestContents = mountPoint.findFile(\"AndroidManifest.xml\").getContentAsString();\n        assertTrue(fs.renameTo(\"/AndroidManifest.xml\", \"/assets/dnsfilter.conf\"));\n        assertFalse(mountPoint.hasFile(\"AndroidManifest.xml\"));\n        assertTrue(mountPoint.findFile(\"assets\").isDirectory());\n        assertTrue(mountPoint.findFile(\"assets\").findFile(\"dnsfilter.conf\").isFile());\n        assertTrue(mountPoint.findFile(\"classes.dex\").isFile());\n        assertTrue(mountPoint.findFile(\"META-INF\").isDirectory());\n        assertTrue(mountPoint.findFile(\"res\").isDirectory());\n        assertTrue(mountPoint.findFile(\"resources.arsc\").isFile());\n        VirtualFileSystem.unmount(fsId);\n        assertNotNull(modifiedApk.get());\n        fsId = VirtualFileSystem.mount(mountPoint.getUri(), Paths.get(modifiedApk.get()), \"application/zip\");\n        assertFalse(mountPoint.hasFile(\"AndroidManifest.xml\"));\n        assertTrue(mountPoint.findFile(\"assets\").isDirectory());\n        assertTrue(mountPoint.findFile(\"assets\").findFile(\"dnsfilter.conf\").isFile());\n        assertTrue(mountPoint.findFile(\"classes.dex\").isFile());\n        assertTrue(mountPoint.findFile(\"META-INF\").isDirectory());\n        assertTrue(mountPoint.findFile(\"res\").isDirectory());\n        assertTrue(mountPoint.findFile(\"resources.arsc\").isFile());\n        assertEquals(manifestContents, mountPoint.findFile(\"assets\").findFile(\"dnsfilter.conf\").getContentAsString());\n        VirtualFileSystem.unmount(fsId);\n    }\n\n    @Test\n    public void renameToNewFileExistingDirectory() throws IOException {\n        Path base = Paths.get(classLoader.getResource(\"oandbackups/dnsfilter.android\").getFile());\n        Path apkFile = base.findFile(\"base.apk\");\n        Path mountPoint = Paths.get(\"/tmp/am_mount_point_23\");\n        AtomicReference<File> modifiedApk = new AtomicReference<>();\n        VirtualFileSystem.MountOptions options = getRWOptions((fs, cachedFile) -> {\n            modifiedApk.set(cachedFile);\n            return true;\n        });\n        int fsId = VirtualFileSystem.mount(mountPoint.getUri(), apkFile, \"application/zip\", options);\n        VirtualFileSystem fs = Objects.requireNonNull(VirtualFileSystem.getFileSystem(fsId));\n        Path testText = mountPoint.createNewFile(\"test.txt\", null);\n        try (OutputStream os = testText.openOutputStream()) {\n            os.write(\"This is a test file\".getBytes(StandardCharsets.UTF_8));\n        }\n        assertFalse(fs.renameTo(\"/test.txt\", \"/assets\"));\n        assertTrue(mountPoint.findFile(\"AndroidManifest.xml\").isFile());\n        assertTrue(mountPoint.findFile(\"assets\").isDirectory());\n        assertFalse(mountPoint.findFile(\"assets\").hasFile(\"test.txt\"));\n        assertTrue(mountPoint.findFile(\"assets\").findFile(\"dnsfilter.conf\").isFile());\n        assertTrue(mountPoint.findFile(\"assets\").findFile(\"additionalHosts.txt\").isFile());\n        assertTrue(mountPoint.findFile(\"classes.dex\").isFile());\n        assertTrue(mountPoint.findFile(\"META-INF\").isDirectory());\n        assertTrue(mountPoint.findFile(\"res\").isDirectory());\n        assertTrue(mountPoint.findFile(\"resources.arsc\").isFile());\n        assertTrue(mountPoint.findFile(\"test.txt\").isFile());\n        VirtualFileSystem.unmount(fsId);\n        assertNotNull(modifiedApk.get());\n        // Remount to verify contents\n        fsId = VirtualFileSystem.mount(mountPoint.getUri(), Paths.get(modifiedApk.get()), \"application/zip\");\n        assertTrue(mountPoint.findFile(\"AndroidManifest.xml\").isFile());\n        assertTrue(mountPoint.findFile(\"assets\").isDirectory());\n        assertFalse(mountPoint.findFile(\"assets\").hasFile(\"test.txt\"));\n        assertTrue(mountPoint.findFile(\"assets\").findFile(\"dnsfilter.conf\").isFile());\n        assertTrue(mountPoint.findFile(\"assets\").findFile(\"additionalHosts.txt\").isFile());\n        assertTrue(mountPoint.findFile(\"classes.dex\").isFile());\n        assertTrue(mountPoint.findFile(\"META-INF\").isDirectory());\n        assertTrue(mountPoint.findFile(\"res\").isDirectory());\n        assertTrue(mountPoint.findFile(\"resources.arsc\").isFile());\n        assertTrue(mountPoint.findFile(\"test.txt\").isFile());\n        assertEquals(\"This is a test file\", mountPoint.findFile(\"test.txt\").getContentAsString());\n        VirtualFileSystem.unmount(fsId);\n        assertTrue(modifiedApk.get().delete());\n    }\n\n    @Test\n    public void renameToExistingDirectoryWithContentsSameDirectory() throws IOException {\n        Path base = Paths.get(classLoader.getResource(\"oandbackups/dnsfilter.android\").getFile());\n        Path apkFile = base.findFile(\"base.apk\");\n        Path mountPoint = Paths.get(\"/tmp/am_mount_point_24\");\n        AtomicReference<File> modifiedApk = new AtomicReference<>();\n        VirtualFileSystem.MountOptions options = getRWOptions((fs, cachedFile) -> {\n            modifiedApk.set(cachedFile);\n            return true;\n        });\n        int fsId = VirtualFileSystem.mount(mountPoint.getUri(), apkFile, \"application/zip\", options);\n        VirtualFileSystem fs = Objects.requireNonNull(VirtualFileSystem.getFileSystem(fsId));\n        assertTrue(fs.renameTo(\"/assets\", \"/abs\"));\n        assertTrue(mountPoint.findFile(\"AndroidManifest.xml\").isFile());\n        assertFalse(mountPoint.hasFile(\"assets\"));\n        assertTrue(mountPoint.findFile(\"abs\").isDirectory());\n        assertTrue(mountPoint.findFile(\"abs\").findFile(\"dnsfilter.conf\").isFile());\n        assertTrue(mountPoint.findFile(\"abs\").findFile(\"additionalHosts.txt\").isFile());\n        assertTrue(mountPoint.findFile(\"classes.dex\").isFile());\n        assertTrue(mountPoint.findFile(\"META-INF\").isDirectory());\n        assertTrue(mountPoint.findFile(\"res\").isDirectory());\n        assertTrue(mountPoint.findFile(\"resources.arsc\").isFile());\n        VirtualFileSystem.unmount(fsId);\n        assertNotNull(modifiedApk.get());\n        // Remount to verify contents\n        fsId = VirtualFileSystem.mount(mountPoint.getUri(), Paths.get(modifiedApk.get()), \"application/zip\");\n        assertTrue(mountPoint.findFile(\"AndroidManifest.xml\").isFile());\n        assertFalse(mountPoint.hasFile(\"assets\"));\n        assertTrue(mountPoint.findFile(\"abs\").isDirectory());\n        assertTrue(mountPoint.findFile(\"abs\").findFile(\"dnsfilter.conf\").isFile());\n        assertTrue(mountPoint.findFile(\"abs\").findFile(\"additionalHosts.txt\").isFile());\n        assertTrue(mountPoint.findFile(\"classes.dex\").isFile());\n        assertTrue(mountPoint.findFile(\"META-INF\").isDirectory());\n        assertTrue(mountPoint.findFile(\"res\").isDirectory());\n        assertTrue(mountPoint.findFile(\"resources.arsc\").isFile());\n        VirtualFileSystem.unmount(fsId);\n        assertTrue(modifiedApk.get().delete());\n    }\n\n    @Test\n    public void renameToExistingDirectoryWithContentsDifferentExistingDirectory() throws IOException {\n        Path base = Paths.get(classLoader.getResource(\"oandbackups/dnsfilter.android\").getFile());\n        Path apkFile = base.findFile(\"base.apk\");\n        Path mountPoint = Paths.get(\"/tmp/am_mount_point_25\");\n        AtomicReference<File> modifiedApk = new AtomicReference<>();\n        VirtualFileSystem.MountOptions options = getRWOptions((fs, cachedFile) -> {\n            modifiedApk.set(cachedFile);\n            return true;\n        });\n        int fsId = VirtualFileSystem.mount(mountPoint.getUri(), apkFile, \"application/zip\", options);\n        VirtualFileSystem fs = Objects.requireNonNull(VirtualFileSystem.getFileSystem(fsId));\n        assertFalse(fs.renameTo(\"/assets\", \"/res\"));\n        assertTrue(mountPoint.findFile(\"AndroidManifest.xml\").isFile());\n        assertTrue(mountPoint.findFile(\"assets\").isDirectory());\n        assertTrue(mountPoint.findFile(\"assets\").findFile(\"dnsfilter.conf\").isFile());\n        assertTrue(mountPoint.findFile(\"assets\").findFile(\"additionalHosts.txt\").isFile());\n        assertTrue(mountPoint.findFile(\"classes.dex\").isFile());\n        assertTrue(mountPoint.findFile(\"META-INF\").isDirectory());\n        assertTrue(mountPoint.findFile(\"res\").isDirectory());\n        assertTrue(mountPoint.findFile(\"resources.arsc\").isFile());\n        VirtualFileSystem.unmount(fsId);\n        assertNull(modifiedApk.get());\n    }\n\n    @Test\n    public void renameToExistingDirectoryWithContentsDifferentNonExistingDirectory() throws IOException {\n        Path base = Paths.get(classLoader.getResource(\"oandbackups/dnsfilter.android\").getFile());\n        Path apkFile = base.findFile(\"base.apk\");\n        Path mountPoint = Paths.get(\"/tmp/am_mount_point_26\");\n        AtomicReference<File> modifiedApk = new AtomicReference<>();\n        VirtualFileSystem.MountOptions options = getRWOptions((fs, cachedFile) -> {\n            modifiedApk.set(cachedFile);\n            return true;\n        });\n        int fsId = VirtualFileSystem.mount(mountPoint.getUri(), apkFile, \"application/zip\", options);\n        VirtualFileSystem fs = Objects.requireNonNull(VirtualFileSystem.getFileSystem(fsId));\n        assertTrue(fs.renameTo(\"/assets\", \"/res/new\"));\n        assertTrue(mountPoint.findFile(\"AndroidManifest.xml\").isFile());\n        assertFalse(mountPoint.hasFile(\"assets\"));\n        assertTrue(mountPoint.findFile(\"classes.dex\").isFile());\n        assertTrue(mountPoint.findFile(\"META-INF\").isDirectory());\n        Path res = mountPoint.findFile(\"res\");\n        assertTrue(res.isDirectory());\n        assertTrue(res.findFile(\"new\").isDirectory());\n        assertTrue(res.findFile(\"new\").findFile(\"dnsfilter.conf\").isFile());\n        assertTrue(res.findFile(\"new\").findFile(\"additionalHosts.txt\").isFile());\n        assertTrue(mountPoint.findFile(\"resources.arsc\").isFile());\n        VirtualFileSystem.unmount(fsId);\n        assertNotNull(modifiedApk.get());\n        // Remount to verify contents\n        fsId = VirtualFileSystem.mount(mountPoint.getUri(), Paths.get(modifiedApk.get()), \"application/zip\");\n        assertTrue(mountPoint.findFile(\"AndroidManifest.xml\").isFile());\n        assertFalse(mountPoint.hasFile(\"assets\"));\n        assertTrue(mountPoint.findFile(\"classes.dex\").isFile());\n        assertTrue(mountPoint.findFile(\"META-INF\").isDirectory());\n        res = mountPoint.findFile(\"res\");\n        assertTrue(res.isDirectory());\n        assertTrue(res.findFile(\"new\").isDirectory());\n        assertTrue(res.findFile(\"new\").findFile(\"dnsfilter.conf\").isFile());\n        assertTrue(res.findFile(\"new\").findFile(\"additionalHosts.txt\").isFile());\n        assertTrue(mountPoint.findFile(\"resources.arsc\").isFile());\n        VirtualFileSystem.unmount(fsId);\n        assertTrue(modifiedApk.get().delete());\n    }\n\n    @Test\n    public void setLastModified() {\n        // TODO: 25/11/22\n    }\n\n    @Test\n    public void newOutputStreamAppend() {\n        // TODO: 25/11/22\n    }\n\n    @Test\n    public void lastModified() {\n        // TODO: 25/11/22\n    }\n\n    @Test\n    public void length() {\n        // TODO: 25/11/22\n    }\n\n    @Test\n    public void checkAccess() {\n        // TODO: 25/11/22\n    }\n\n    @Test\n    public void getMode() {\n        // TODO: 25/11/22\n    }\n\n    private VirtualFileSystem.MountOptions getRWOptions(VirtualFileSystem.OnFileSystemUnmounted event) {\n        return new VirtualFileSystem.MountOptions.Builder()\n                .setReadWrite(true)\n                .setOnFileSystemUnmounted(event)\n                .build();\n    }\n}"
  },
  {
    "path": "app/src/test/java/io/github/muntashirakon/test/shadows/OsConstantsValues.java",
    "content": "// SPDX-License-Identifier: MIT\n\npackage io.github.muntashirakon.test.shadows;\n\nimport com.google.common.collect.ImmutableMap;\n\nimport java.io.File;\n\n/**\n * Provides a utility class for OsConstants See\n * https://unix.superglobalmegacorp.com/Net2/newsrc/sys/stat.h.html.\n */\nfinal class OsConstantsValues {\n\n  private OsConstantsValues() {}\n\n  // Type of file.\n  public static final String S_IFMT = \"S_IFMT\";\n\n  // Directory.\n  public static final String S_IFDIR = \"S_IFDIR\";\n\n  // Regular file.\n  public static final String S_IFREG = \"S_IFREG\";\n\n  // Symbolic link.\n  public static final String S_IFLNK = \"S_IFLNK\";\n\n  // Type of file value.\n  public static final int S_IFMT_VALUE = 0x0170000;\n\n  // Directory value.\n  public static final int S_IFDIR_VALUE = 0x0040000;\n\n  // Regular file value.\n  public static final int S_IFREG_VALUE = 0x0100000;\n\n  // Link value.\n  public static final int S_IFLNK_VALUE = 0x0120000;\n\n  // File open mode values from\n  // https://github.com/torvalds/linux/blob/master/include/uapi/asm-generic/fcntl.h\n  static final ImmutableMap<String, Integer> OPEN_MODE_VALUES =\n      new ImmutableMap.Builder<String, Integer>()\n          .put(\"O_RDONLY\", 0x0000)\n          .put(\"O_WRONLY\", 0x0001)\n          .put(\"O_RDWR\", 0x0002)\n          .put(\"O_ACCMODE\", 0x0003)\n          .put(\"O_CREAT\", 0x0100)\n          .put(\"O_EXCL\", 0x0200)\n          .put(\"O_TRUNC\", 0x1000)\n          .put(\"O_APPEND\", 0x2000)\n          // access values\n          .put(\"R_OK\", 4)\n          .put(\"W_OK\", 2)\n          .put(\"X_OK\", 8)\n          .put(\"F_OK\", 0)\n          .build();\n\n  /** Returns the st_mode for the path. */\n  public static int getMode(String path) {\n    if (path == null) {\n      return 0;\n    }\n\n    File file = new File(path);\n    if (file.isDirectory()) {\n      return S_IFDIR_VALUE;\n    }\n    if (file.isFile()) {\n      return S_IFREG_VALUE;\n    }\n    if (!canonicalize(path).equals(path)) {\n      return S_IFLNK_VALUE;\n    }\n    return 0;\n  }\n\n  private static String canonicalize(String path) {\n    try {\n      return new File(path).getCanonicalPath();\n    } catch (Throwable t) {\n      throw new RuntimeException(t);\n    }\n  }\n}"
  },
  {
    "path": "app/src/test/java/io/github/muntashirakon/test/shadows/ShadowBackupDataDirectoryInfo.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.test.shadows;\n\nimport org.robolectric.annotation.Implementation;\nimport org.robolectric.annotation.Implements;\nimport org.robolectric.annotation.RealObject;\n\nimport java.io.File;\n\nimport io.github.muntashirakon.AppManager.backup.BackupDataDirectoryInfo;\nimport io.github.muntashirakon.AppManager.utils.RoboUtils;\nimport io.github.muntashirakon.io.Path;\nimport io.github.muntashirakon.io.Paths;\n\n@Implements(BackupDataDirectoryInfo.class)\npublic class ShadowBackupDataDirectoryInfo {\n    @RealObject\n    private BackupDataDirectoryInfo mRealObject;\n\n    @Implementation\n    public Path getDirectory() {\n        boolean hasSep = mRealObject.rawPath.startsWith(File.separator);\n        return Paths.get(RoboUtils.getTestBaseDir().getAbsolutePath()\n                + (hasSep ? (File.separator + mRealObject.rawPath) : mRealObject.rawPath));\n    }\n}\n"
  },
  {
    "path": "app/src/test/java/io/github/muntashirakon/test/shadows/ShadowDeviceIdleManagerCompat.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.test.shadows;\n\nimport androidx.annotation.NonNull;\n\nimport org.robolectric.annotation.Implementation;\nimport org.robolectric.annotation.Implements;\n\nimport io.github.muntashirakon.AppManager.compat.DeviceIdleManagerCompat;\n\n@Implements(DeviceIdleManagerCompat.class)\npublic class ShadowDeviceIdleManagerCompat {\n    @Implementation\n    public static boolean isBatteryOptimizedApp(@NonNull String packageName) {\n        return true;\n    }\n}\n"
  },
  {
    "path": "app/src/test/java/io/github/muntashirakon/test/shadows/ShadowOsConstants.java",
    "content": "// SPDX-License-Identifier: MIT\n\npackage io.github.muntashirakon.test.shadows;\n\nimport android.system.OsConstants;\n\nimport org.robolectric.annotation.Implementation;\nimport org.robolectric.annotation.Implements;\n\nimport java.lang.reflect.Field;\nimport java.util.regex.Pattern;\n\n@Implements(value = OsConstants.class, minSdk = 21)\npublic final class ShadowOsConstants {\n  private static final Pattern ERRNO_PATTERN = Pattern.compile(\"E[A-Z0-9]+\");\n\n  @Implementation\n  public static void initConstants() {\n    int errnos = 1;\n    try {\n      for (Field field : OsConstants.class.getDeclaredFields()) {\n        final String fieldName = field.getName();\n\n        if (ERRNO_PATTERN.matcher(fieldName).matches() && field.getType() == int.class) {\n          field.setInt(null, errnos++);\n        }\n        // Type of file.\n        if (fieldName.equals(OsConstantsValues.S_IFMT)) {\n          field.setInt(null, OsConstantsValues.S_IFMT_VALUE);\n          continue;\n        }\n        // Directory.\n        if (fieldName.equals(OsConstantsValues.S_IFDIR)) {\n          field.setInt(null, OsConstantsValues.S_IFDIR_VALUE);\n          continue;\n        }\n        // Regular file.\n        if (fieldName.equals(OsConstantsValues.S_IFREG)) {\n          field.setInt(null, OsConstantsValues.S_IFREG_VALUE);\n          continue;\n        }\n        // Symbolic link.\n        if (fieldName.equals(OsConstantsValues.S_IFLNK)) {\n          field.setInt(null, OsConstantsValues.S_IFLNK_VALUE);\n        }\n\n        // File open modes.\n        if (OsConstantsValues.OPEN_MODE_VALUES.containsKey(fieldName)) {\n          field.setInt(null, OsConstantsValues.OPEN_MODE_VALUES.get(fieldName));\n        }\n      }\n    } catch (ReflectiveOperationException e) {\n      throw new RuntimeException(e);\n    }\n  }\n}"
  },
  {
    "path": "app/src/test/java/io/github/muntashirakon/test/shadows/ShadowOwners.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.test.shadows;\n\nimport androidx.annotation.NonNull;\n\nimport org.robolectric.annotation.Implementation;\nimport org.robolectric.annotation.Implements;\n\nimport io.github.muntashirakon.AppManager.users.Owners;\n\n@Implements(value = Owners.class, minSdk = 21)\npublic class ShadowOwners {\n\n    @Implementation\n    @NonNull\n    public static String getOwnerName(int uid) {\n        return String.valueOf(uid);\n    }\n}\n"
  },
  {
    "path": "app/src/test/java/io/github/muntashirakon/test/shadows/ShadowPackageInstallerCompat.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.test.shadows;\n\nimport android.content.pm.ApplicationInfo;\nimport android.content.pm.PackageInfo;\nimport android.content.pm.PackageManager;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport org.robolectric.RuntimeEnvironment;\nimport org.robolectric.Shadows;\nimport org.robolectric.annotation.Implementation;\nimport org.robolectric.annotation.Implements;\nimport org.robolectric.shadows.ShadowPackageManager;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.util.Objects;\n\nimport io.github.muntashirakon.AppManager.apk.installer.InstallerOptions;\nimport io.github.muntashirakon.AppManager.apk.installer.PackageInstallerCompat;\nimport io.github.muntashirakon.AppManager.progress.ProgressHandler;\nimport io.github.muntashirakon.AppManager.utils.FileUtils;\nimport io.github.muntashirakon.AppManager.utils.RoboUtils;\nimport io.github.muntashirakon.io.Path;\nimport io.github.muntashirakon.io.Paths;\n\n@Implements(PackageInstallerCompat.class)\npublic class ShadowPackageInstallerCompat {\n    @Implementation\n    public boolean install(@NonNull Path[] apkFiles, @NonNull String packageName, @NonNull InstallerOptions options,\n                           @Nullable ProgressHandler progressHandler) {\n        PackageManager packageManager = RuntimeEnvironment.getApplication().getPackageManager();\n        ShadowPackageManager shadowPackageManager = Shadows.shadowOf(packageManager);\n        String apkPath = apkFiles[0].getFilePath();\n        if (apkPath != null) {\n            PackageInfo packageInfo = packageManager.getPackageArchiveInfo(apkFiles[0].getFilePath(), 0);\n            if (packageInfo != null) {\n                packageInfo.packageName = packageName;\n                ApplicationInfo applicationInfo = Objects.requireNonNull(packageInfo.applicationInfo);\n                File roboDir = RoboUtils.getTestBaseDir();\n                File apkDir = new File(roboDir.getAbsoluteFile() + \"/data/app/\" + packageName);\n                if (!apkDir.exists() && !apkDir.mkdirs()) {\n                    return false;\n                }\n                String[] filenames = new String[apkFiles.length];\n                int i = 0;\n                for (Path apkFile : apkFiles) {\n                    String filename = apkFile.getName();\n                    filenames[i] = filename;\n                    File dupApkFile = new File(apkDir, filename);\n                    try {\n                        FileUtils.copy(apkFile, Paths.get(dupApkFile), null);\n                    } catch (IOException e) {\n                        e.printStackTrace();\n                        return false;\n                    }\n                    ++i;\n                }\n                if (filenames.length > 1) {\n                    // Split APK\n                    applicationInfo.splitPublicSourceDirs = new String[filenames.length - 1];\n                    for (i = 1; i < filenames.length; ++i) {\n                        applicationInfo.splitPublicSourceDirs[i - 1] = new File(apkDir, filenames[i]).getAbsolutePath();\n                    }\n                    applicationInfo.splitSourceDirs = applicationInfo.splitPublicSourceDirs;\n                }\n                applicationInfo.publicSourceDir = new File(apkDir, filenames[0]).getAbsolutePath();\n                applicationInfo.sourceDir = applicationInfo.publicSourceDir;\n                applicationInfo.deviceProtectedDataDir = \"/data/user_de/0/\" + packageName;\n                applicationInfo.dataDir = \"/data/data/\" + packageName;\n                shadowPackageManager.installPackage(packageInfo);\n                return true;\n            }\n        }\n        return false;\n    }\n}\n"
  },
  {
    "path": "app/src/test/java/io/github/muntashirakon/test/shadows/ShadowPackageManagerCompat.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.test.shadows;\n\nimport android.content.pm.PackageInfo;\nimport android.content.pm.PackageManager;\nimport android.os.RemoteException;\n\nimport androidx.annotation.NonNull;\n\nimport org.robolectric.annotation.Implementation;\nimport org.robolectric.annotation.Implements;\n\nimport io.github.muntashirakon.AppManager.BuildConfig;\nimport io.github.muntashirakon.AppManager.compat.PackageManagerCompat;\nimport io.github.muntashirakon.AppManager.utils.ContextUtils;\n\n@Implements(PackageManagerCompat.class)\npublic class ShadowPackageManagerCompat {\n    @Implementation\n    @NonNull\n    public static PackageInfo getPackageInfo(@NonNull String packageName, int flags, int userId)\n            throws RemoteException, PackageManager.NameNotFoundException {\n        return ContextUtils.getContext().getPackageManager().getPackageInfo(packageName, flags);\n    }\n\n    public static boolean clearApplicationUserData(@NonNull String packageName, int userId) {\n        // App data may have been cleaned already depending on how it was handled in unit tests\n        return true;\n    }\n\n    public static String getInstallerPackageName(@NonNull String packageName, int userId) {\n        return BuildConfig.APPLICATION_ID;\n    }\n}\n"
  },
  {
    "path": "app/src/test/java/org/apache/commons/compress/archivers/tar/TarArchiveInputStreamTest.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage org.apache.commons.compress.archivers.tar;\n\nimport static org.junit.Assert.assertEquals;\n\nimport org.apache.commons.compress.archivers.ArchiveEntry;\nimport org.junit.After;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.robolectric.RobolectricTestRunner;\n\nimport java.io.BufferedInputStream;\nimport java.io.File;\nimport java.io.FileNotFoundException;\nimport java.io.IOException;\nimport java.io.OutputStream;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport io.github.muntashirakon.AppManager.utils.DigestUtils;\nimport io.github.muntashirakon.io.IoUtils;\nimport io.github.muntashirakon.io.Path;\nimport io.github.muntashirakon.io.Paths;\nimport io.github.muntashirakon.io.SplitInputStream;\n\n@RunWith(RobolectricTestRunner.class)\npublic class TarArchiveInputStreamTest {\n    private final ClassLoader classLoader = getClass().getClassLoader();\n    private final List<File> junkFiles = new ArrayList<>();\n\n    @After\n    public void tearDown() {\n        for (File file : junkFiles) {\n            file.delete();\n        }\n    }\n\n    @Test\n    public void TestUnTar() throws IOException {\n        List<Path> pathList = new ArrayList<>();\n        assert classLoader != null;\n        pathList.add(Paths.get(classLoader.getResource(\"AppManager_v2.5.22.apks.tar.0\").getFile()));\n        pathList.add(Paths.get(classLoader.getResource(\"AppManager_v2.5.22.apks.tar.1\").getFile()));\n\n        // Always run tests using SplitInputStream\n        try (SplitInputStream sis = new SplitInputStream(pathList);\n             BufferedInputStream bis = new BufferedInputStream(sis);\n             TarArchiveInputStream tis = new TarArchiveInputStream(bis)) {\n            ArchiveEntry entry;\n            while ((entry = tis.getNextEntry()) != null) {\n                // create a new path, remember check zip slip attack\n                File file = new File(\"/tmp\", entry.getName());\n                // copy TarArchiveInputStream to newPath\n                try (OutputStream os = Paths.get(file).openOutputStream()) {\n                    IoUtils.copy(tis, os);\n                }\n            }\n        }\n\n        // Check integrity\n        List<String> expectedHashes = new ArrayList<>();\n        List<File> fileList = new ArrayList<>();\n        fileList.add(new File(classLoader.getResource(\"AppManager_v2.5.22.apks.0\").getFile()));\n        fileList.add(new File(classLoader.getResource(\"AppManager_v2.5.22.apks.1\").getFile()));\n        for (File file : fileList) {\n            expectedHashes.add(DigestUtils.getHexDigest(DigestUtils.SHA_256, file));\n        }\n        List<String> actualHashes = new ArrayList<>();\n        fileList.clear();\n        fileList.add(new File(\"/tmp/AppManager_v2.5.22.apks.0\"));\n        fileList.add(new File(\"/tmp/AppManager_v2.5.22.apks.1\"));\n        for (File file : fileList) {\n            if (!file.exists()) {\n                throw new FileNotFoundException(file + \" does not exist.\");\n            }\n            actualHashes.add(DigestUtils.getHexDigest(DigestUtils.SHA_256, file));\n            junkFiles.add(file);\n        }\n        assertEquals(expectedHashes, actualHashes);\n    }\n}"
  },
  {
    "path": "app/src/test/java/org/apache/commons/compress/archivers/tar/TarArchiveOutputStreamTest.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage org.apache.commons.compress.archivers.tar;\n\nimport static org.junit.Assert.assertEquals;\n\nimport org.apache.commons.compress.archivers.ArchiveEntry;\nimport org.junit.After;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.robolectric.RobolectricTestRunner;\n\nimport java.io.BufferedInputStream;\nimport java.io.BufferedOutputStream;\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\n\nimport io.github.muntashirakon.io.IoUtils;\nimport io.github.muntashirakon.io.Path;\nimport io.github.muntashirakon.io.Paths;\nimport io.github.muntashirakon.io.SplitInputStream;\nimport io.github.muntashirakon.io.SplitOutputStream;\n\n@RunWith(RobolectricTestRunner.class)\npublic class TarArchiveOutputStreamTest {\n    private final ClassLoader classLoader = getClass().getClassLoader();\n    private final List<File> junkFiles = new ArrayList<>();\n\n    @After\n    public void tearDown() {\n        for (File file : junkFiles) {\n            file.delete();\n        }\n    }\n\n    @Test\n    public void testTarSplit() throws IOException {\n        List<String> fileNames = Arrays.asList(\"AppManager_v2.5.22.apks.0\", \"AppManager_v2.5.22.apks.1\");\n        List<Path> fileList = new ArrayList<>();\n        assert classLoader != null;\n        for (String fileName : fileNames) {\n            fileList.add(Paths.get(classLoader.getResource(fileName).getFile()));\n        }\n\n        Path tmpPath = Paths.get(\"/tmp\");\n        // Always run tests using SplitOutputStream\n        try (SplitOutputStream sot = new SplitOutputStream(tmpPath, \"AppManager_v2.5.22.apks.tar\", 1024 * 1024);\n             BufferedOutputStream bot = new BufferedOutputStream(sot);\n             TarArchiveOutputStream tot = new TarArchiveOutputStream(bot)) {\n            for (Path file : fileList) {\n                TarArchiveEntry tarEntry = new TarArchiveEntry(file, file.getName());\n                tot.putArchiveEntry(tarEntry);\n                try (InputStream is = file.openInputStream()) {\n                    IoUtils.copy(is, tot);\n                }\n                tot.closeArchiveEntry();\n            }\n            tot.finish();\n        }\n\n        // Check integrity\n        List<String> actualFileNames = new ArrayList<>();\n        List<Path> pathList = new ArrayList<>();\n        pathList.add(tmpPath.findFile(\"AppManager_v2.5.22.apks.tar.0\"));\n        pathList.add(tmpPath.findFile(\"AppManager_v2.5.22.apks.tar.1\"));\n        try (SplitInputStream sis = new SplitInputStream(pathList);\n             BufferedInputStream bis = new BufferedInputStream(sis);\n             TarArchiveInputStream tis = new TarArchiveInputStream(bis)) {\n            ArchiveEntry entry;\n            while ((entry = tis.getNextEntry()) != null) {\n                // create a new path, remember check zip slip attack\n                actualFileNames.add(entry.getName());\n            }\n        }\n        Collections.sort(fileNames);\n        Collections.sort(actualFileNames);\n        assertEquals(fileNames, actualFileNames);\n        for (Path path : pathList) {\n            junkFiles.add(path.getFile());\n        }\n    }\n\n    @Test\n    public void testTar() throws IOException {\n        File base = new File(\"/tmp/AppManager_v2.5.22.apks.tar\");\n        List<String> fileNames = Arrays.asList(\"AppManager_v2.5.22.apks.0\", \"AppManager_v2.5.22.apks.1\");\n        List<Path> fileList = new ArrayList<>();\n        assert classLoader != null;\n        for (String fileName : fileNames) {\n            fileList.add(Paths.get(classLoader.getResource(fileName).getFile()));\n        }\n\n        // Always run tests using SplitOutputStream\n        try (FileOutputStream sot = new FileOutputStream(base);\n             BufferedOutputStream bot = new BufferedOutputStream(sot);\n             TarArchiveOutputStream tot = new TarArchiveOutputStream(bot)) {\n            for (Path file : fileList) {\n                TarArchiveEntry tarEntry = new TarArchiveEntry(file, file.getName());\n                tot.putArchiveEntry(tarEntry);\n                try (InputStream is = file.openInputStream()) {\n                    IoUtils.copy(is, tot);\n                }\n                tot.closeArchiveEntry();\n            }\n            tot.finish();\n        }\n\n        // Check integrity\n        List<String> actualFileNames = new ArrayList<>();\n        try (FileInputStream sis = new FileInputStream(base);\n             BufferedInputStream bis = new BufferedInputStream(sis);\n             TarArchiveInputStream tis = new TarArchiveInputStream(bis)) {\n            ArchiveEntry entry;\n            while ((entry = tis.getNextEntry()) != null) {\n                // create a new path, remember check zip slip attack\n                actualFileNames.add(entry.getName());\n            }\n        }\n        Collections.sort(fileNames);\n        Collections.sort(actualFileNames);\n        assertEquals(fileNames, actualFileNames);\n        junkFiles.add(base);\n    }\n}"
  },
  {
    "path": "app/src/test/java/org/apache/commons/compress/compressors/bzip2/BZip2CompressorInputStreamTest.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage org.apache.commons.compress.compressors.bzip2;\n\nimport static org.junit.Assert.assertEquals;\n\nimport org.apache.commons.compress.archivers.ArchiveEntry;\nimport org.apache.commons.compress.archivers.tar.TarArchiveInputStream;\nimport org.junit.After;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.robolectric.RobolectricTestRunner;\n\nimport java.io.BufferedInputStream;\nimport java.io.File;\nimport java.io.FileNotFoundException;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Objects;\n\nimport io.github.muntashirakon.AppManager.utils.DigestUtils;\nimport io.github.muntashirakon.io.IoUtils;\nimport io.github.muntashirakon.io.Path;\nimport io.github.muntashirakon.io.Paths;\nimport io.github.muntashirakon.io.SplitInputStream;\n\n@RunWith(RobolectricTestRunner.class)\npublic class BZip2CompressorInputStreamTest {\n    private final ClassLoader classLoader = Objects.requireNonNull(getClass().getClassLoader());\n    private final List<File> junkFiles = new ArrayList<>();\n\n    @After\n    public void tearDown() {\n        for (File file : junkFiles) {\n            file.delete();\n        }\n    }\n\n    @Test\n    public void testUnTarBZip2() throws IOException {\n        try (InputStream is = Paths.get(classLoader.getResource(\"AppManager_v2.5.22.apks.tar.bz2\").getFile()).openInputStream();\n             BufferedInputStream bis = new BufferedInputStream(is);\n             BZip2CompressorInputStream bZis = new BZip2CompressorInputStream(bis);\n             TarArchiveInputStream tis = new TarArchiveInputStream(bZis)) {\n            ArchiveEntry entry;\n            while ((entry = tis.getNextEntry()) != null) {\n                // create a new path, remember check zip slip attack\n                File file = new File(\"/tmp\", entry.getName());\n                // copy TarArchiveInputStream to newPath\n                try (OutputStream os = Paths.get(file).openOutputStream()) {\n                    IoUtils.copy(tis, os);\n                }\n            }\n        }\n\n        // Check integrity\n        List<File> fileList = new ArrayList<>();\n        List<String> expectedHashes = new ArrayList<>();\n        fileList.add(new File(classLoader.getResource(\"AppManager_v2.5.22.apks.0\").getFile()));\n        fileList.add(new File(classLoader.getResource(\"AppManager_v2.5.22.apks.1\").getFile()));\n        for (File file : fileList) {\n            expectedHashes.add(DigestUtils.getHexDigest(DigestUtils.SHA_256, file));\n        }\n        List<String> actualHashes = new ArrayList<>();\n        fileList.clear();\n        fileList.add(new File(\"/tmp/AppManager_v2.5.22.apks.0\"));\n        fileList.add(new File(\"/tmp/AppManager_v2.5.22.apks.1\"));\n        for (File file : fileList) {\n            if (!file.exists()) {\n                throw new FileNotFoundException(file + \" does not exist.\");\n            }\n            actualHashes.add(DigestUtils.getHexDigest(DigestUtils.SHA_256, file));\n            junkFiles.add(file);\n        }\n        assertEquals(expectedHashes, actualHashes);\n    }\n\n    @Test\n    public void testSplitUnTarBZip2() throws IOException {\n        List<Path> pathList = new ArrayList<>();\n        pathList.add(Paths.get(classLoader.getResource(\"AppManager_v2.5.22.apks.tar.bz2.0\").getFile()));\n        pathList.add(Paths.get(classLoader.getResource(\"AppManager_v2.5.22.apks.tar.bz2.1\").getFile()));\n\n        try (SplitInputStream sis = new SplitInputStream(pathList);\n             BufferedInputStream bis = new BufferedInputStream(sis);\n             BZip2CompressorInputStream bZis = new BZip2CompressorInputStream(bis);\n             TarArchiveInputStream tis = new TarArchiveInputStream(bZis)) {\n            ArchiveEntry entry;\n            while ((entry = tis.getNextEntry()) != null) {\n                // create a new path, remember check zip slip attack\n                File file = new File(\"/tmp\", entry.getName());\n                // copy TarArchiveInputStream to newPath\n                try (OutputStream os = Paths.get(file).openOutputStream()) {\n                    IoUtils.copy(tis, os);\n                }\n            }\n        }\n\n        // Check integrity\n        List<String> expectedHashes = new ArrayList<>();\n        List<File> fileList = new ArrayList<>();\n        fileList.add(new File(classLoader.getResource(\"AppManager_v2.5.22.apks.0\").getFile()));\n        fileList.add(new File(classLoader.getResource(\"AppManager_v2.5.22.apks.1\").getFile()));\n        for (File file : fileList) {\n            expectedHashes.add(DigestUtils.getHexDigest(DigestUtils.SHA_256, file));\n        }\n        List<String> actualHashes = new ArrayList<>();\n        fileList.clear();\n        fileList.add(new File(\"/tmp/AppManager_v2.5.22.apks.0\"));\n        fileList.add(new File(\"/tmp/AppManager_v2.5.22.apks.1\"));\n        for (File file : fileList) {\n            if (!file.exists()) {\n                throw new FileNotFoundException(file + \" does not exist.\");\n            }\n            actualHashes.add(DigestUtils.getHexDigest(DigestUtils.SHA_256, file));\n            junkFiles.add(file);\n        }\n        assertEquals(expectedHashes, actualHashes);\n    }\n}"
  },
  {
    "path": "app/src/test/java/org/apache/commons/compress/compressors/bzip2/BZip2CompressorOutputStreamTest.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage org.apache.commons.compress.compressors.bzip2;\n\nimport static org.junit.Assert.assertEquals;\n\nimport org.apache.commons.compress.archivers.ArchiveEntry;\nimport org.apache.commons.compress.archivers.tar.TarArchiveEntry;\nimport org.apache.commons.compress.archivers.tar.TarArchiveInputStream;\nimport org.apache.commons.compress.archivers.tar.TarArchiveOutputStream;\nimport org.junit.After;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.robolectric.RobolectricTestRunner;\n\nimport java.io.BufferedInputStream;\nimport java.io.BufferedOutputStream;\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\n\nimport io.github.muntashirakon.io.IoUtils;\nimport io.github.muntashirakon.io.Path;\nimport io.github.muntashirakon.io.Paths;\nimport io.github.muntashirakon.io.SplitInputStream;\nimport io.github.muntashirakon.io.SplitOutputStream;\n\n@RunWith(RobolectricTestRunner.class)\npublic class BZip2CompressorOutputStreamTest {\n    private final ClassLoader classLoader = getClass().getClassLoader();\n    private final List<File> junkFiles = new ArrayList<>();\n\n    @After\n    public void tearDown() {\n        for (File file : junkFiles) {\n            file.delete();\n        }\n    }\n\n    @Test\n    public void testTarGzip() throws IOException {\n        File base = new File(\"/tmp/AppManager_v2.5.22.apks.tar.bz2\");\n        List<String> fileNames = Arrays.asList(\"AppManager_v2.5.22.apks.0\", \"AppManager_v2.5.22.apks.1\");\n        List<Path> fileList = new ArrayList<>();\n        assert classLoader != null;\n        for (String fileName : fileNames) {\n            fileList.add(Paths.get(classLoader.getResource(fileName).getFile()));\n        }\n\n        try (FileOutputStream fos = new FileOutputStream(base);\n             BufferedOutputStream bos = new BufferedOutputStream(fos);\n             BZip2CompressorOutputStream bZos = new BZip2CompressorOutputStream(bos);\n             TarArchiveOutputStream tos = new TarArchiveOutputStream(bZos)) {\n            for (Path file : fileList) {\n                TarArchiveEntry tarEntry = new TarArchiveEntry(file, file.getName());\n                tos.putArchiveEntry(tarEntry);\n                try (InputStream is = file.openInputStream()) {\n                    IoUtils.copy(is, tos);\n                }\n                tos.closeArchiveEntry();\n            }\n            tos.finish();\n        }\n\n        // Check integrity\n        List<String> actualFileNames = new ArrayList<>();\n        try (FileInputStream sis = new FileInputStream(base);\n             BufferedInputStream bis = new BufferedInputStream(sis);\n             BZip2CompressorInputStream bcis = new BZip2CompressorInputStream(bis);\n             TarArchiveInputStream tis = new TarArchiveInputStream(bcis)) {\n            ArchiveEntry entry;\n            while ((entry = tis.getNextEntry()) != null) {\n                // create a new path, remember check zip slip attack\n                actualFileNames.add(entry.getName());\n            }\n        }\n\n        Collections.sort(fileNames);\n        Collections.sort(actualFileNames);\n        assertEquals(fileNames, actualFileNames);\n        junkFiles.add(base);\n    }\n\n    @Test\n    public void testSplitTarBZip2() throws IOException {\n        List<String> fileNames = Arrays.asList(\"AppManager_v2.5.22.apks.0\", \"AppManager_v2.5.22.apks.1\");\n        List<Path> fileList = new ArrayList<>();\n        assert classLoader != null;\n        for (String fileName : fileNames) {\n            fileList.add(Paths.get(classLoader.getResource(fileName).getFile()));\n        }\n\n        Path tmpPath = Paths.get(\"/tmp\");\n        try (SplitOutputStream sos = new SplitOutputStream(tmpPath, \"AppManager_v2.5.22.apks.tar.bz2\", 1024 * 1024);\n             BufferedOutputStream bos = new BufferedOutputStream(sos);\n             BZip2CompressorOutputStream bZos = new BZip2CompressorOutputStream(bos);\n             TarArchiveOutputStream tos = new TarArchiveOutputStream(bZos)) {\n            for (Path file : fileList) {\n                TarArchiveEntry tarEntry = new TarArchiveEntry(file, file.getName());\n                tos.putArchiveEntry(tarEntry);\n                try (InputStream is = file.openInputStream()) {\n                    IoUtils.copy(is, tos);\n                }\n                tos.closeArchiveEntry();\n            }\n            tos.finish();\n        }\n\n        // Check integrity\n        List<String> actualFileNames = new ArrayList<>();\n        List<Path> pathList = new ArrayList<>();\n        pathList.add(tmpPath.findFile(\"AppManager_v2.5.22.apks.tar.bz2.0\"));\n        pathList.add(tmpPath.findFile(\"AppManager_v2.5.22.apks.tar.bz2.1\"));\n        try (SplitInputStream sis = new SplitInputStream(pathList);\n             BufferedInputStream bis = new BufferedInputStream(sis);\n             BZip2CompressorInputStream bcis = new BZip2CompressorInputStream(bis);\n             TarArchiveInputStream tis = new TarArchiveInputStream(bcis)) {\n            ArchiveEntry entry;\n            while ((entry = tis.getNextEntry()) != null) {\n                // create a new path, remember check zip slip attack\n                actualFileNames.add(entry.getName());\n            }\n        }\n        Collections.sort(fileNames);\n        Collections.sort(actualFileNames);\n        assertEquals(fileNames, actualFileNames);\n        for (Path path : pathList) {\n            junkFiles.add(path.getFile());\n        }\n    }\n}"
  },
  {
    "path": "app/src/test/java/org/apache/commons/compress/compressors/gzip/GzipCompressorInputStreamTest.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage org.apache.commons.compress.compressors.gzip;\n\nimport static org.junit.Assert.assertEquals;\n\nimport org.apache.commons.compress.archivers.ArchiveEntry;\nimport org.apache.commons.compress.archivers.tar.TarArchiveInputStream;\nimport org.junit.After;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.robolectric.RobolectricTestRunner;\n\nimport java.io.BufferedInputStream;\nimport java.io.File;\nimport java.io.FileNotFoundException;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport io.github.muntashirakon.AppManager.utils.DigestUtils;\nimport io.github.muntashirakon.io.IoUtils;\nimport io.github.muntashirakon.io.Path;\nimport io.github.muntashirakon.io.Paths;\nimport io.github.muntashirakon.io.SplitInputStream;\n\n@RunWith(RobolectricTestRunner.class)\npublic class GzipCompressorInputStreamTest {\n    private final ClassLoader classLoader = getClass().getClassLoader();\n    private final List<File> junkFiles = new ArrayList<>();\n\n    @After\n    public void tearDown() {\n        for (File file : junkFiles) {\n            file.delete();\n        }\n    }\n\n    @Test\n    public void testUnTarGzip() throws IOException {\n        assert classLoader != null;\n        try (InputStream is = Paths.get(classLoader.getResource(\"AppManager_v2.5.22.apks.tar.gz\").getFile()).openInputStream();\n             BufferedInputStream bis = new BufferedInputStream(is);\n             GzipCompressorInputStream gis = new GzipCompressorInputStream(bis, true);\n             TarArchiveInputStream tis = new TarArchiveInputStream(gis)) {\n            ArchiveEntry entry;\n            while ((entry = tis.getNextEntry()) != null) {\n                // create a new path, remember check zip slip attack\n                File file = new File(\"/tmp\", entry.getName());\n                // copy TarArchiveInputStream to newPath\n                try (OutputStream os = Paths.get(file).openOutputStream()) {\n                    IoUtils.copy(tis, os);\n                }\n            }\n        }\n\n        // Check integrity\n        List<File> fileList = new ArrayList<>();\n        List<String> expectedHashes = new ArrayList<>();\n        fileList.add(new File(classLoader.getResource(\"AppManager_v2.5.22.apks.0\").getFile()));\n        fileList.add(new File(classLoader.getResource(\"AppManager_v2.5.22.apks.1\").getFile()));\n        for (File file : fileList) {\n            expectedHashes.add(DigestUtils.getHexDigest(DigestUtils.SHA_256, file));\n        }\n        List<String> actualHashes = new ArrayList<>();\n        fileList.clear();\n        fileList.add(new File(\"/tmp/AppManager_v2.5.22.apks.0\"));\n        fileList.add(new File(\"/tmp/AppManager_v2.5.22.apks.1\"));\n        for (File file : fileList) {\n            if (!file.exists()) {\n                throw new FileNotFoundException(file + \" does not exist.\");\n            }\n            actualHashes.add(DigestUtils.getHexDigest(DigestUtils.SHA_256, file));\n            junkFiles.add(file);\n        }\n        assertEquals(expectedHashes, actualHashes);\n    }\n\n    @Test\n    public void testSplitUnTarGzip() throws IOException {\n        List<Path> pathList = new ArrayList<>();\n        assert classLoader != null;\n        pathList.add(Paths.get(classLoader.getResource(\"AppManager_v2.5.22.apks.tar.gz.0\").getFile()));\n        pathList.add(Paths.get(classLoader.getResource(\"AppManager_v2.5.22.apks.tar.gz.1\").getFile()));\n\n        try (SplitInputStream sis = new SplitInputStream(pathList);\n             BufferedInputStream bis = new BufferedInputStream(sis);\n             GzipCompressorInputStream gis = new GzipCompressorInputStream(bis, true);\n             TarArchiveInputStream tis = new TarArchiveInputStream(gis)) {\n            ArchiveEntry entry;\n            while ((entry = tis.getNextEntry()) != null) {\n                // create a new path, remember check zip slip attack\n                File file = new File(\"/tmp\", entry.getName());\n                // copy TarArchiveInputStream to newPath\n                try (OutputStream os = Paths.get(file).openOutputStream()) {\n                    IoUtils.copy(tis, os);\n                }\n            }\n        }\n\n        // Check integrity\n        List<String> expectedHashes = new ArrayList<>();\n        List<File> fileList = new ArrayList<>();\n        fileList.add(new File(classLoader.getResource(\"AppManager_v2.5.22.apks.0\").getFile()));\n        fileList.add(new File(classLoader.getResource(\"AppManager_v2.5.22.apks.1\").getFile()));\n        for (File file : fileList) {\n            expectedHashes.add(DigestUtils.getHexDigest(DigestUtils.SHA_256, file));\n        }\n        List<String> actualHashes = new ArrayList<>();\n        fileList.clear();\n        fileList.add(new File(\"/tmp/AppManager_v2.5.22.apks.0\"));\n        fileList.add(new File(\"/tmp/AppManager_v2.5.22.apks.1\"));\n        for (File file : fileList) {\n            if (!file.exists()) {\n                throw new FileNotFoundException(file + \" does not exist.\");\n            }\n            actualHashes.add(DigestUtils.getHexDigest(DigestUtils.SHA_256, file));\n            junkFiles.add(file);\n        }\n        assertEquals(expectedHashes, actualHashes);\n    }\n}"
  },
  {
    "path": "app/src/test/java/org/apache/commons/compress/compressors/gzip/GzipCompressorOutputStreamTest.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage org.apache.commons.compress.compressors.gzip;\n\nimport static org.junit.Assert.assertEquals;\n\nimport org.apache.commons.compress.archivers.ArchiveEntry;\nimport org.apache.commons.compress.archivers.tar.TarArchiveEntry;\nimport org.apache.commons.compress.archivers.tar.TarArchiveInputStream;\nimport org.apache.commons.compress.archivers.tar.TarArchiveOutputStream;\nimport org.junit.After;\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.robolectric.RobolectricTestRunner;\n\nimport java.io.BufferedInputStream;\nimport java.io.BufferedOutputStream;\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.Collections;\nimport java.util.List;\n\nimport io.github.muntashirakon.io.IoUtils;\nimport io.github.muntashirakon.io.Path;\nimport io.github.muntashirakon.io.Paths;\nimport io.github.muntashirakon.io.SplitInputStream;\nimport io.github.muntashirakon.io.SplitOutputStream;\n\n@RunWith(RobolectricTestRunner.class)\npublic class GzipCompressorOutputStreamTest {\n    private final ClassLoader classLoader = getClass().getClassLoader();\n    private final List<File> junkFiles = new ArrayList<>();\n\n    @After\n    public void tearDown() {\n        for (File file : junkFiles) {\n            file.delete();\n        }\n    }\n\n    @Test\n    public void testTarGzip() throws IOException {\n        File base = new File(\"/tmp/AppManager_v2.5.22.apks.tar.gz\");\n        List<String> fileNames = Arrays.asList(\"AppManager_v2.5.22.apks.0\", \"AppManager_v2.5.22.apks.1\");\n        List<Path> fileList = new ArrayList<>();\n        assert classLoader != null;\n        for (String fileName : fileNames) {\n            fileList.add(Paths.get(classLoader.getResource(fileName).getFile()));\n        }\n\n        try (FileOutputStream fos = new FileOutputStream(base);\n             BufferedOutputStream bos = new BufferedOutputStream(fos);\n             GzipCompressorOutputStream gos = new GzipCompressorOutputStream(bos);\n             TarArchiveOutputStream tos = new TarArchiveOutputStream(gos)) {\n            for (Path file : fileList) {\n                TarArchiveEntry tarEntry = new TarArchiveEntry(file, file.getName());\n                tos.putArchiveEntry(tarEntry);\n                try (InputStream is = file.openInputStream()) {\n                    IoUtils.copy(is, tos);\n                }\n                tos.closeArchiveEntry();\n            }\n            tos.finish();\n        }\n\n        // Check integrity\n        List<String> actualFileNames = new ArrayList<>();\n        try (FileInputStream sis = new FileInputStream(base);\n             BufferedInputStream bis = new BufferedInputStream(sis);\n             GzipCompressorInputStream gcis = new GzipCompressorInputStream(bis);\n             TarArchiveInputStream tis = new TarArchiveInputStream(gcis)) {\n            ArchiveEntry entry;\n            while ((entry = tis.getNextEntry()) != null) {\n                // create a new path, remember check zip slip attack\n                actualFileNames.add(entry.getName());\n            }\n        }\n\n        Collections.sort(fileNames);\n        Collections.sort(actualFileNames);\n        assertEquals(fileNames, actualFileNames);\n        junkFiles.add(base);\n    }\n\n    @Test\n    public void testSplitTarGzip() throws IOException {\n        List<String> fileNames = Arrays.asList(\"AppManager_v2.5.22.apks.0\", \"AppManager_v2.5.22.apks.1\");\n        List<Path> fileList = new ArrayList<>();\n        assert classLoader != null;\n        for (String fileName : fileNames) {\n            fileList.add(Paths.get(classLoader.getResource(fileName).getFile()));\n        }\n\n        Path tmpPath = Paths.get(\"/tmp\");\n        try (SplitOutputStream sos = new SplitOutputStream(tmpPath, \"AppManager_v2.5.22.apks.tar.gz\", 1041921);\n             BufferedOutputStream bos = new BufferedOutputStream(sos);\n             GzipCompressorOutputStream gos = new GzipCompressorOutputStream(bos);\n             TarArchiveOutputStream tos = new TarArchiveOutputStream(gos)) {\n            for (Path file : fileList) {\n                TarArchiveEntry tarEntry = new TarArchiveEntry(file, file.getName());\n                tos.putArchiveEntry(tarEntry);\n                try (InputStream is = file.openInputStream()) {\n                    IoUtils.copy(is, tos);\n                }\n                tos.closeArchiveEntry();\n            }\n            tos.finish();\n        }\n\n        // Check integrity\n        List<String> actualFileNames = new ArrayList<>();\n        List<Path> pathList = new ArrayList<>();\n        pathList.add(tmpPath.findFile(\"AppManager_v2.5.22.apks.tar.gz.0\"));\n        pathList.add(tmpPath.findFile(\"AppManager_v2.5.22.apks.tar.gz.1\"));\n        try (SplitInputStream sis = new SplitInputStream(pathList);\n             BufferedInputStream bis = new BufferedInputStream(sis);\n             GzipCompressorInputStream gcis = new GzipCompressorInputStream(bis);\n             TarArchiveInputStream tis = new TarArchiveInputStream(gcis)) {\n            ArchiveEntry entry;\n            while ((entry = tis.getNextEntry()) != null) {\n                // create a new path, remember check zip slip attack\n                actualFileNames.add(entry.getName());\n            }\n        }\n        Collections.sort(fileNames);\n        Collections.sort(actualFileNames);\n        assertEquals(fileNames, actualFileNames);\n        for (Path path : pathList) {\n            junkFiles.add(path.getFile());\n        }\n    }\n}\n"
  },
  {
    "path": "app/src/test/resources/SwiftBackup/ademar.textlauncher.xml",
    "content": "}#31737)B+oxm[|~yx7BNR;`GRIY _b_¥¥­¦¯´¢²m²¢¯¨¨¦u·¸ªy¬À®²~rtÅ½»ºÊÎÉÎ~ÛÇÝÍ¸ÙÒØªÞÔØÝá¡¬ÙïßÊÚÛÉçÝëðäôùç¥°µÀ©íăóÞíāïÓüòĀąùĉĎüºÅÊÕ¾ĂĘĈóĂĖĄĈÇÒØáÞÞÜæÏēĩęĄĝģĕ×ıñÚĨĠĩąĢĸĨĳãîåĶĪĮĪĶľīķŀŅĳŃþŃĳŀĹĹķùĒûĿňĽīŃņŁŌŅńŔćĒĉŚŎŒŎŚŢŏĻĐťŪŘňėİęŝŦśũĞĩįĹĢůűŬŷŷūŝƁŮŵĭĸŲƃƁƄŋĴŸƀŷŷſŻƇƏżŨƐƇŁŌƆƗƕƘşňƋƍƕƖƌƠƠƜŸƣƚŔşƙƨƢƘƞųŜƟơƩƢƭƵƃƵƬŦűŨƹƭƱƭƹǁƮƺǃǈƶǆƁǆƶǃƼƼƺżƕžǂǅǀǋǄǃƳǖǊǒǓǉǝǝǙǕƏƚǔǥǣǦƭƖǙǛǣǚǚǨǠƞƩƠǱǥǩǥǱǹǦǲǻȀǮǾƹǾǮǻǴǴǲǁǃǃǺǺǶȊǾȍȐǋǾȒȀȄǐǄǝǆȗȏǫȉȝȋǯȑȑǐǛǣǤǫǦǪǥǧǮǯǰǬǱǭǷǠȣȥȭȮȤȸȸȴȐȭȽȫȯǮǹǰɁȵȹȵɁɉȶɂɋɐȾɎȉɎȾɋɄɄɂȑȓȓɗɋɚɝȘɋɟɍɑȝȑȪȓɤɜȸɖɪɘɜțȦȬȶȟɲɠɭɳɱɉɴɺɱɪɩɫȬʆȾɗɆɰɨɹʊɘɽɈʀɩɋʅʋɽʂɭʘʄɭɸʍʖɽɽʈɬ"
  },
  {
    "path": "app/src/test/resources/SwiftBackup/com.google.android.samples.dynamicfeatures.ondemand.xml",
    "content": "}#215'@)mvkYz|wv5@FP9}}^EPHX]¡£«¡¥ª®knk£®¢¯¨¨³µu»®¼ÀÀ®³µ³º¿´ÂÎºË¾ÆËÉ¾ÑÄÊÑÕÈÓÇÍÕÑÚÛÔÜßÔ¡ãäÖ¥ØìÚÞª© êðâ°ñé³íðî÷ùîëā÷ûĀĄÁÄÁùĄøąþþĉċËđĄĒĖĖĄĉċĉĐĕĊĘĤĐÛġĔĜġğĔħãĚĠħīĞĩĝëģīħİıĪòĲĵĪ÷ĹĺĬûĮłİĴĀôĮĎ÷ŉŉŁĝĿľŎŒōĲŔŊŎœŗćĒĉœřŋęőŠŏőğĢğŗŢŖţŜŜŧũĩůŢŰŴŴŢŧũŧŮųŨŶƂŮĹſŲźſŽŲƅŁŸžƅƉżƇŻŉƁƉƅƎƏƈŐƐƓƈŕƗƘƊřƌƠƎƒŞŒūŔƥƝŹƛƚƪƮƩƮŞũƻűŷŲŸźžŧƫǁƱƜƽƶƼƎǂƸƼǁǅŵƀƅƐŹƽǓǃƮƾƿƭǋǁǏǔǈǘǝǋƉƔƙƤƍǑǧǗǂǑǥǓƷǠǖǤǩǝǭǲǠƞƩƮƹƢǦǼǬǗǦǺǨǬƫƶƻǂƽǆƿǀǂǌƵǹȏǿǪȃȉǻƽȗǗǀȎȆȏǫȈȞȎșǉǔǋȎșȍȚȓȓȞȠǠȦșȧȫȫșȞȠȞȥȪȟȭȹȥǰȶȩȱȶȴȩȼǸȯȵȼɀȳȾȲȀȸɀȼɅɆȿȇɇɊȿǿȘȁɅɎɃȱɉɌɇɒɋɊɚȍȘȏɓɛɠɞɓɆȔəɤɘɥɞȾțɪɌȠȹȢɦɯɤɲȧȲȸɂȫɸɺɵʀʀɴɦʊɷɾȶɁɻʌʊʍɔȽʁʉʀʀʈʄʐʘʅɱʙʐɊɕʏʠʞʡɨɑʔʖʞʟʕʩʩʥʁʬʣɝɨʢʱʫʡʧɼɥʨʪʲʫʶʾʌʾʵɯɺɱ˂ʶʹʴ˂ʶʣˇˈʚʈˉˋˈʿˑˉˉ˕˄˘˓˛˔ʖˋ˟˓ˠ˖˕ʝ˟˚ʔʭʖ˚˝˘ˣ˜˛ˋˮˢ˪˫ˡ˵˵˱˭ʧʲˬ˽˻˾˅ʮ˱˳˻˲˲̀˸ʶˁʸ˻̆˺̇̀̀̋̍ˍ̘̘̗̦̓̆̔̆̋̍̋̒̌̒̚˝̡̣̖̞̣̖̩˥̢̜̩̭̠̫̟˭̥̭̩̲̳̬˴̴̷̬˹˻˻̶̶̸̲̲̮͈̼͂̃͊̈ͅ˼̕˾͏̧̧̨͇̣͕͉͉̙̠̤̝̠̦̤̩̥̯̘́̓̈̓͛ͥͦ̚̚͜͝ͰͰ͈ͬͥ͵̨̦̱ͣͧͫͶͪͷͰͰͻͽ̽΃Ͷ΄ΈΈͶͻͽͻ΂·ͼΊΖ΂͍ΓΆΎΓΑΆΙ͕ΌΒΙΝΐΛΏ͝ΕΝΙ΢ΣΜͤΤΧΜͩͫͫίΣβεͰΣηΥΩ͵ͩ΂ͫμδΐήςΰδͳ;΄ΎͷϊθυϋωΡόϒωςρσ΄ϞΖίΞψπϑϢΰϕΠϘρΣϝϣϕϚυϰϜυϐϥϮϕϕϠτ"
  },
  {
    "path": "app/src/test/resources/SwiftBackup/com.test.app.xml",
    "content": "}#616'@)mvkYz|wv5@IHQ:~~_FQHX^a^¢£cªª­h¨« m¯°¢q¤¸¦ªvjl½µ³²ÂÆÁÆvÓ{¿ÕÅ°ÑÊÐ¢ÖÌÐÕÙ¢ ¨ÕëÛÆÖ×ÅãÙçìàðõã¡¬±¼¥éÿïÚéýëÏøîüāõąĊø¶ÁÆÑºþĔĄïþĒĀĄÃÎÛ×ÞÙÚâËďĥĕĀęğđÓĭíÖĤĜĥāĞĴĤįßêáõóî÷öñøøêăìŁĿĐŁĳęĿŁļŇňĿńŊľŊýĈÿŎŏŁďŖŖŉřĔŔŗŌČĥĎŒśŐľŖřŔşŘŗŧĚĥĜĴĲŜĶİŮŶŌĶĵŹŹŬżĩńŻżŎĮƃƃŶŦĵŎķŻƄŹƇļŇōŗŀƍƏƊƕƕƉŻƟƌƓŋŖƐơƟƢũŒƖƞƕƕƝƙƥƭƚƆƮƥşŪƤƵƳƶŽŦƩƫƳƴƪƾƾƺƖǁƸŲŽƷǆǀƶƼƑźƽƿǇǀǋǓơǓǊƄƏƆǕǖǈƖǝǝǐǠƛǛǞǓƓƬƕǙǜǗǢǛǚǊǭǡǩǪǠǴǴǰǬƦƱǫǼǺǽǄƭǰǲǺǱǱǿǷƵǀƷȆȇǹǇȎȎȁȑǌȌȏȄǑǓǓȊȊȆȚȎȝȠǛȎȢȐȔǠǔǭǖȧȟǻșȭțǿȡȡǠǫǲǹǷǹǹǶǷǾǿȀǼȁǽȇǰȳȵȽȾȴɈɈɄȠȽɍȻȿǾȉȀɏɐɂȐɗɗɊɚȕɕɘɍȚȜȜɠɔɣɦȡɔɨɖɚȦȚȳȜɭɥɁɟɳɡɥȤȯȵȿȨɻɩɶɼɺɒɽʃɺɳɲɴȵʏɇɠɏɹɱʂʓɡʆɑʉɲɔʎʔʆʋɶʡʍɶʁʖʟʆʆʑɵ"
  },
  {
    "path": "app/src/test/resources/SwiftBackup/dnsfilter.android.xml",
    "content": "}#31=947=7;-F/s|q_}|;FLLVROUR\\Ej¤Q\\S£cªili¡§®²¥°¤r·«»´²°¾º±}¿À²´È¶ºz|ÍÅ¡ÃÂÒÖÑÖã¢ÏåÕÀáÚà²æÜàåé¤©´á÷çÒâãÑïåóøìüāï­¸ÄÇÂÂÂÌµùďÿêùčûßĈþČđąĕĚĈÆÑÞßÚÛÛåÎĒĨĘăĒĦĔĘ×âîññïïð÷àĤĺĪĕĮĴĦèłĂëĹıĺĖĳŉĹńôÿöĹĿņŊĽňļĊŏŃœŌŊňŖŒŉĈġĊŎŗŌĺŒŕŐśŔœţĖġĘũŝŭŦŤŢŐŌŃŬŢŰŲŷŷūŷĪŃĬŰŹŮżıļłŌĵƂƄſƊƊžŰƔƁƈŀŋƅƖƔƗŞŇƋƓƊƊƒƎƚƢƏŻƣƚŔşƙƪƨƫŲśƞƠƨƩƟƳƳƯƋƶƭŧŲƬƻƵƫƱƆůƲƴƼƵǀǈƖǈƿŹƄŻƾǄǋǏǂǍǁƏǔǈǘǑǏǍǛǗǎƍƦƏǓǖǑǜǕǔǄǧǛǣǤǚǮǮǪǦƠƫǥǶǴǷƾƧǪǬǴǫǫǹǱƯƺƱǴǺȁȅǸȃǷǅȊǾȎȇȅȃȑȍȄǐǒǒȉȉȅșȍȜȟǚȍȡȏȓǟǓǬǕȦȞǺȘȬȚǾȠȠǟǪǳǴǳǶǹǴǶǽǾǿǻȀǼȆǯȲȴȼȽȳɇɇɃȟȼɌȺȾǽȈǿɂɈɏɓɆɑɅȓɘɌɜɕɓɑɟɛɒȞȠȠɤɘɧɪȥɘɬɚɞȪȞȷȠɱɩɅɣɷɥɩȨȳȹɃȬɿɭɺʀɾɖʁʇɾɷɶɸȹʓɋɤɓɽɵʆʗɥʊɕʍɶɘʒʘʊʏɺʥʑɺʅʚʣʊʊʕɹ"
  },
  {
    "path": "app/src/test/resources/SwiftBackup/org.billthefarmer.editor.xml",
    "content": "}#2926(A*nwlZ{}xw6AFMIS\n<aHSJZ¡`c`¦¤ª h­¡ª° ¦¦ª·°±¯©v°¼º{½¾°²Æ´¸xzËÃÁÀÐÔÏÔá ÍãÓ¾ßØÞ°äÚÞãç¢§²ßõåÐàáÏíãñöêúÿí«¶»Æ¯óĉùäóćõÙĂøĆċÿďĔĂÀËÐÙÖÓÖßÈČĢĒýČĠĎĒÑÜåæçèæèñÚĞĴĤďĨĮĠâļüåĳīĴĐĭŃĳľîùðŁĿŅĻķĹăňļŅŋĻŁŁŅŒŋŌŊńđŋŗŕĉĢċŏŘōĻœŖőŜŕŔŤėĢęŪŨŮŤŠłĠĹĢŦůŤŲħĲĸłīŸźŵƀƀŴŦƊŷžĶŁŻƌƊƍŔĽƁƉƀƀƈƄƐƘƅűƙƐŊŕƏƠƞơŨőƔƖƞƟƕƩƩƥƁƬƣŝŨƢƱƫơƧżťƨƪƲƫƶƾƌƾƵůźűǂǀǆƼƸƺƄǉƽǆǌƼǂǂǆǓǌǍǋǅƒǌǘǖƊƣƌǐǓǎǙǒǑǁǤǘǠǡǗǫǫǧǣƝƨǢǳǱǴƻƤǧǩǱǨǨǶǮƬƷƮǿǽȃǹǵǷǁȆǺȃȉǹǿǿȃȐȉȊȈȂǏȉȕȓǔǖǖȍȍȉȝȑȠȣǞȑȥȓȗǣǗǰǙȪȢǾȜȰȞȂȤȤǣǮǵǸǼǹǽǸǺȁȂȃǿȄȀȊǳȶȸɀɁȷɋɋɇȣɀɐȾɂȁȌȃɔɒɘɎɊɌȖɛɏɘɞɎɔɔɘɥɞɟɝɗȤɞɪɨȩȫȫɯɣɲɵȰɣɷɥɩȵȩɂȫɼɴɐɮʂɰɴȳȾɄɎȷʊɸʅʋʉɡʌʒʉʂʁʃɄʞɖɯɞʈʀʑʢɰʕɠʘʁɣʝʣʕʚʅʰʜʅʐʥʮʕʕʠʄ"
  },
  {
    "path": "app/src/test/resources/TitaniumBackup/ademar.textlauncher-20210530-111646.properties",
    "content": "#Titanium Backup\n#Sun May 30 14:20:21 GMT+03:00 2021\napp_apk_md5=7016ac07c52a556afd2eed992b976255\nhas_dbdata=0\nsys_ro.build.version.release=6.0.1\nhas_prefsdata=0\napp_is_system=0\napp_version_code=7\nhas_prefsdata_jpu=0\nsys_ro.build.description=Some description\ngeneration=1\napp_gui_label=Text Launcher 1.3.1\napp_label=Text Launcher\nsys_ro.build.date.utc=1469090187\nsys_ro.serialno=abcdef12\napp_apk_location=internal\napp_apk_codec=BZIP2\nsys_ro.product.model=Some Model\napp_version_name=1.3.1\napp_is_forward_locked=0\n"
  },
  {
    "path": "app/src/test/resources/TitaniumBackup/ca.cmetcalfe.locationshare-20210529-164219.properties",
    "content": "#Titanium Backup\n#Sat May 29 19:42:21 GMT+03:00 2021\napp_apk_md5=932896b6374dabc812ccd5fa00374cf3\nhas_dbdata=0\nsys_ro.build.version.release=6.0.1\nhas_prefsdata=0\napp_is_system=0\napp_version_code=8\nhas_prefsdata_jpu=0\nsys_ro.build.description=Some description\ngeneration=1\napp_gui_label=Location Share 1.4.1\napp_label=Location Share\napp_gui_icon=iVBORw0KGgoAAAANSUhEUgAAAJwAAACcCAYAAACKuMJNAAAABHNCSVQICAgIfAhkiAAAIABJREFUeJztvXlwHGeWH/h7edeB+yZBAARPkRQlkqJutSjJklp9ST3Tsj2jnY221zHjsB129Dgc6w27Z6jomJ1w7zrC4Y6eWccoxjN2e1otqik1ORJFiWoekiiSEkmRAkgCJA7iBgqoQgGoIyuPt39kJlgACmAVCKAKlH4RGQASX2V+Vfmr9973rg/4Gl/ja3yNr/E1vsYSgPI9gUIHM3uf0e0+K/Z+ISJeaOBXGV95ws1DKJ5NmrRxGTHP+BnXzDTuq4avHOHSiDBNqtlkSjsvAlAAyAAk96cIQHCH2gAsACYAwzuIyLzNdefM4asCKd8TWAkwM833YJnZB6AIQCmAYgBFzBwE4HcP73cNDvkkzCScCSAFQAcQBxBj5pj7+xSASQATAMaZeRJAYr45Ane/BLwrJVz6w5slZWQAJQAqAFTCIVktgLUAatxz5QDKmbkYgJ+INGbWiMgjGjGz4F7fhqMqPeLpzJwkohgcokUAjAEYBTACoB/AYNr5MQDjcCQjZs/5biTfXUU4T5KlqSyCI6Eq3GMNgM0ANgHYAKAeQDUzlxARkGb4MzMxM9zzucwBgEMW77XefIgoCmCEmfuJqAPAdfcYgEPKUThEZbjqdiHpvBpx1xDOfagCHGlTBKAMQB2AewDsArADDtmqmTmTKcHsseUWaJ7fM05hnt8Bh2xzXu/aeqMAOgFcBnABQCuAIQBhOKr4rrL1VjXhZkkyEY6KrACwF8Aj7rERjg0GZvYkkKcK018PLN/nwWk/vcMjoac+Ace+6wRwBsBpAGfhEC8CR2VPS75lmueyY1USLn2VB8eIDwBYD+D7AL4HR6rJ7ljAJViaFCyU9+2Rz4ZDQCFNENoA2gAcAvA2HNU7CYd4AFanjVcoH3xWmG1MM3M5gKcB/AGAZ+AQzyOZ5f4sJILdDh752F2kAACIKA7gJID/BeADIhoBZtiGdj4muxisigfhrQpxy5BeC0eS/T4c+0wBIDGzlSbF0rEq3ifm2n4e+QQisuC4X1oAvA7g74noRrqDeTUQr+AfhOt8tV2iNQJ4EcBLAO4DEGRmGY40E2e9tODf220wh3zkwAQQg6Nu3wLwa3fFC2YWXWIWLAr2oaR/eK7qfAHA7wK4H0A1AJ+7qhTSFpcF+37uEDNWwEQEItLh+Pa+BHAQwCEiGgMcjVCo0q7gHtDssA8zPwdnMfAYgGY4RMslqH63YUZMloiSALrhrGwPEtE7hRw6K6iHlea4FeGsOv8hgOcB3Asn5CR8hYk2G+nEswHEiagVwPsA3gBwnYiMQnMcF8RDS19tMXMRnJXn7wF4HI6jVkwbBxTIvAsA0/49151iE1EYwEcAfgXgQyIKu4uugpB2BfHgXCLJcCID34Qj2Z5m5nT/2ex0n69xC+kOYc+h/BGANwEcAdALIFUIhMt7tohLpiCA7XBstX8IoMFdELD77fyaaAuD4CQVpDuRHwfQBMfuPRiJRC4z80S+SZe3B5lmr5XDUZ1/AODbAFR24PnSviZb7mB3lUpElGLmD2zb/h/JZPLjYDA4lE+7Li8PM80Wq4GjQv8IwENwA+gZfGpfY3Gw0uK1F0zT/IVpmm/6fL5+ID+hsRVXqWkqshbAP4Ej2TY5/2J8TbYlhejZwUS0WxTFKmaujkQi/19ZWVm/m/u0ov66FZVwblqQDSfJ8d8B+N/hrEK/ttWWF0xENhHBtu2IZVm/ikQiP6murg4BELyU+JXAij1gL3LAzDUA/m84UYPg11JtRWG5dnPCNM0jExMTP6qqqhpgZmmlSLcihEsjWzOA/wfAPwDgd7NqC0+y2TbsgX5Y11rAV1tg996EPR4G60mQZQNEYFGCoCiAooH8fqCoBEJ1DWhdA4St2yE2rgfEgvseee4TC4BuGMYnExMT/6aqqqptpeKwy/6gvW8PM68H8BqAB5jZj1u1AQVBNntsFPZnn8K6+Dns3m7w5AQ4mQSSScAyAcsC0hOCPVucCBAIIMEhmCwDJaXghvWg+kaoa9ZCeOQJCGVleXtvszBNOmZOpVKplqGhoR82NTW1w3kW9nIuJpb1Yae5NioB/AWAZ+HEQoW8k40ZbJmwL34O89OPYd/sBI+GwBNRIJmYS7BcLi2KgKoBmg+CPwA0rgdv2wG1sQni/Q+AVG2J30zuU8St3LtUIpE4FQ6H/1VHR8fNffv22cu5kFi2B56Wl1YG4M/hOHTzTzbbBkfCMM+dhn35AuyebtgD/UAsBvDSf85MBCgKUFIGoaQE2LUXcoNDPKGqGhBmp+6tGKZJx8xGLBb79djY2H+8efNm/759+6zlknLL4haZ5Wf71wB+gAKw2Xg8AuuL87DOfAzrRht4sB8wjEVLsmxAzICuAyND4NAwOBSCUVoKs/0a+MFHIG/dDrmkdNnuv9DU3J+CIAiyz+f7bkVFRViW5Z+9+uqrnW7F2pJ/MMv24GOxWJ3f7/+nAP4VgCp3NZofstk27K4OmKc+hPX5GdhdHQ7R8gguLgE3bYDw0KNQ9j4MuSFviwx2kyaQSqXGdF1/LRKJ/NX69eu7l+NmS/7wXelWZlnW90RR/PcANuXTz8bRCKy2q7BOn4J15mPwWCgf08gMQYRdvw7inocgPvIEaMMmKMUl+ZqNxcyk63pXIpH4LxMTEwfWr18/AixtRGLJPvk0NRqwLOspl2yPMLOdLz+bPTQA67PTMI8dhX2jDUil8jGN24KDRbDv2QHhG09DfeBhyJVVeZkHEVmWZQnJZPJiLBb7f2Ox2LvNzc0T7v+WhHRLabF6KUbbRFF8BQ7Z0leqKwq7vxfm++/AOPB3sK98WbBkAwCamoR48TPg4K+gn/gAZmg4L/NgZkEURSiKsktRlFdUVd194sQJFUsomJZk0eBlHyQSiTpFUb4vCMJ34cZGsbSkzgr28CCM3/wa5on3gcgYCkaFLgTTBHV3gn/zJhK6Dt8L34NUXrHSsyBmtmVZhs/ne9o0zZv19fUjRHRlqTJM7pgM3kTGxsaKFEX5JhH9YwCaV+Byp9fPeT7jERhv/hLm8feBSBirgmwe2AYND4L+/i3E3/t7WJOT071KVhACAJZlWdU07cVgMPjyRx99VJqhMdCiL36noOPHj0slJSX7iOhlImrIR4oRM4MNA8aRQ7COHQHGwyt5+6UDM2hsFMJbv8LkJyfAur7ipGNmURAEVlW1TlXV79XW1n77+PHjEpbg23tHhHPL0fiRRx5pIKLfI6Jn0nxtKwvThHXqQxh/99/BU5MrfvslBdug8Qjkv/o5Js+fA+fB/mRmQZZl8vl8u4LB4CuBQGALEfH+/fvv6Nkuhb4hwzD+T0mS/gU7FfEr7gJhw4DddxPJf/svgMmJlbrtCoBgb9oC+1/+WwQ2boK0siExJiLbtm3E4/HRSCTy3xsbG/8DnHDYorHoRYObXWAbhvG0JEnPM3Mt8lGDwAweGULqZ/8572SjmloIG7dAWNcIqBp4PAL7+jXY7VcBczHZPwzqvAE6cgix7/0u/Os3QJblJZ/3PCBPg6mqWh4IBJ69fPny2Z07d/7GPb+ozJJFEc41Hu1IJFIiCML34dSNiq6tsbJJnZEwzBPHHD9bvuDzQ3zwUUjfeBpC43rA53dipKYBjkRgt7XCfPcQ7JudgJ2bgCDLhHDuE1jNG5EIFgFV1StKOiJiSZJEn8+3sby8/HePHj16GkBosavWxUo4IiLWdf15QRAeY2bPPb6yS0LLgj3QB/PYESARX9FbT0NRID31LKTnvg2heSNI87mpSw64qgbCmrWgNfVI/fVfgrs7nUyUHECRMIRPT8FqaEIiEAT7fFAUZanfSUa4woVlWQ74fL6H1q5d+yIRveadz/V6ORuA3o3C4fA6URR/wMwb4fT3WPG6UXt0BNanp8ADfSt52xkQNm+D+I2nIWzcAvL5Z5ANAEgUgeISiLsegPzC94BAcFH3ofZrEK62wI6Eoes6Uiu3kCAAJIqi4Pf760tLS18+duyYV4OS8/NezIqDiAh+v/+7giDshttdcqXBpgn7ZhfMT07lrKaWDCRA3PMghKZmkKrOP4wIJCsQH3sSwtp1gJy7dKJ4DMLFz0ADvbAMY6VJByKCJElqIBDYUVNT8wMiwquvvrq8hPOk2+jo6BpFUV4iouq08ytru42Nwmq55KQY5Qs+n6NGi4qzGi5UVIHWrAMWIOdCoM4boBvtwOQELMuCruswVibrhZiZBEGAz+crLSkpeeno0aNN27Zty/m55yrhiIgQCAReIKJdcHPccr3pUoD7bsI+dzp/0g0AlZSAyspB2UosIlCwCCQt0nSOTYGutoCGBgAAlmUhmUyuGOngqFY1EAjsqKys/EEsFpP379+/PITz9HVra2uZLMuvwKm4ykv1NicTsPv7YPf25uP2AAhUUwdx525HumXbWp8ZSOngO/iSUHcnqL93OhnBsiwkEgmYi3K75A5BEDgQCCilpaWvNDc31z355JM5ucFykXB04MABad26dU8IgrCXmZW8ZYIM9sO61groyZW9sSgCJaUQNm2B/NLLkP+3/wNUuybrl3MsBntowMkAXiRobBR0sxMIj06fs217JUknyLIsFBUV3adp2jOhUEjLRcplLdsPHDhAe/fu9fv9/t8nIpmZLTit6vOgTntht11ZuTsLAuDzQ6hbC2HXA5D2PQthwyZnBZoFmBmwLVhffA77ZtcdEQ5sA329oIE+sEt2t8AZsVgMwWAQgiDkvKFJlvCaHFrBYFAqLS39nWQyeRROu/+s3CRZEY6Z6cqVK2JJSUm9KIrPwmngfEczXyyYGTweAY+sUM6YIIBKyyHs3gv5O9+HuO3eOSrUIZRTr0qzimKYGbAs8OgIjDf/DpgYxyLcVzNAoSHQyDCYec79pqamUFRU5IxbHtKBmQVN07ioqOjRcDi8IRKJjGGePcRm47Yq0au+8vl8ZYFA4HsAylzbLT+LhXgcHB13SvmWG7IM4Z4dUP75v4H2o38PcfvOzPba5ATsrg5weGzu/wwDdlcHUv/pVdhXWxYZ4poJCo+BRoZARma3yOQypjV5i0Qisv1+f7GmaS82NTXVvPHGG0I2frnbSjivs+LAwECZKIovuje944kvFtzT6YSI7hSaBlq7DkJNHcAAjw7DHugD4nFAkiBucRy64kOPgapqgAwrS56cgHX2E5gfHIHV3QGhphbClu0Q6hsARQFPRGFfb4fdchEcCS/dilrXgbFRIDwG1K3NOGRychKBQADSYlfEtwEzIxAIoLi4+JlkMvn6888/fzOb1y04G2amV199lV555ZVgcXHxLlEU78tHvHTGnEaG70yd+gMQd+6C9K0XIWzaApKcuCSbJvhmF6yLn4NqaiHu3OUQTVVn2mrMADPMj4/DOHIY3NUBnhgHTBP2RBR2dycgSo4ktG2nOsxILXkpIsWmQNFx8DyEA4BEIgGfz7ekpPPUNDOTJEkIBoNbotHoQ3/913/d2dPTM7Z//35gAZvhtjPZtm0bBQKBMkVRHoKzAYeFPGTyTiM2BcQWme9WVAzpoccgvfgyhIbGGaEoYgYHgqB1DSBFBYLBaTJ64FQKPNAH87fvwzx9Ejw85KyUPTKZ5pKozKygJx1pvACYGclkEpqmLYekIwC2z+eT/X7/Axs3bjwWDAbDbguweV+0IHG8FwYCgWoiejTDDVccHE+AE4uw30RHTUrffgnCxs0gf2CmPUYE8vkgVNeCSstmkI1N0ynKOfxr6H/5X2AcPQzu6XbsyHyZF0YKSM5POO/Z2ba9HM5hr8UrNE2Dpmm7FEVZe+zYMeF2C5UFCbd//35qbm4OiqK4VRTFrcCMfiF5ARsG2MhdilBFBYSdu1w1muW33bJgDw/B/O1RpP72r2Ac+jXsL847tlMe7VgAjiTNQCJ305AZ52zbXpYwGDMLkiTB5/OtV1V1+8MPP+y1EJiXdfOSh5mptbWVqqqqKiRJup+Igux0U8xvN3HbBuzcc/+oogpC4/qsG8lwPAbr8kUYb/wCxq9/CeuTk05WyiLuvSywec4iZCHpskykIwDs8/n8mqbdV1NTU/vyyy8LCy0q5yWcN3lFUSqIaLt7Ou9t17HISjXy+bIOsgMAT0RhffE5zN8eBXfeAFJ34KxdDjjOiVt/ZuFzs20bqVRqSSMSRGTLsgxFUTYXFRVVHzhwYMHxC6rHJ554QtI0rU6SpC08c7uh/EGUFtWDw23Cn8MrCFBUUCBQiI0FAUGcnle2Dl4vIqHr+pKRzrZtQZZlqKrapKpq/R/+4R+qOS8amJn2799Pjz/+eLEsy81EVLvQ+JUEqeri+qvFpsA5lA5SeQXEhx+H9K2XIGy/D8hfz4/MkGXHl5gD2TwsMelIEASoqlqhadqmhx9+uAJuOlOmwfMRiLZt20Y1NTXlkiRtJCIV7oYTSzHDO4I/4Kwwc4Q9GnKiAVmmopOiQNywCfLv/CMo/+SPIO17FtTQCGi+nO+9LNA0wJ9d9nAmUnqr1zslnZcjqaqqoijKhurq6uqXX36Z5kvOnI9wfODAAUiSVElEza46zb/9BkAoKweVlef+wsiY0xuu5RJ4IXvMdex6IM0HcftOKD/8Iyg//OcQ9z4MqqjMv5r1+UFuzHQhLCQBmRmJRAKWZS06euRenxVFYUVR1vn9/ppQKER/+qd/mvGCGQlHRDhw4AAJglBGROsWNZNlAlVWg6qqnc6SuYAZ9vU2mIcOgjtvgFM62LLAtu0cluU4dmMxcDIBtsxbD4EIVFQE6bEnof7x/wX5934Iqq4FFDX7XLilBBEQCIKLFlbz2ahbIkIikYArVBY1HWaGJElQFKVGVdXyEydOzOuPm+OQcsu/6Ec/+pEsSVKlKIo17r/ybr8BgFC/DrR5C3D6JBCN5vZiPQnrs9PQ+29C3PcsxF17IdQ6sVQ7NAKr5QtYn5+FULcG0tPPQ9iyDfClqVBBAAWLIb/4A4gPPATzyCFYHx2HPTS4su6SomKgtg4onb9zZrZk8xCPx+H3+xebYUKCIJCiKBWSJFW/9NJL/rfffnsiUxfNjB7Q/fv349lnny2SJGmtIAil+Y6fzoAkgytqwFV1oFwJBzjO3L5e2K//TyddSJQAOClE3mG7xBN374X0ze9CvGfHHBVKdWsh/8E/g/TUczCPvQvz7GkIldUQdj0AoXkDSPOBR0dhtV6CeeZjIDSyNO8fAFdWgytrAFpaGRCPx+Hz+SDmaC64QgqSJBX5fL765557rvztt9+ecO242xKOWltb6Qc/+EGxu1VO3nccnAEiiJIIUZYW7xRkdkJDC/hAeXQE5kmnwFp88hlIz7wAobpm+v8kCE4xTON6yL//Q0jf/J7jRikuAWQ3eG/ZDmmf+SZSf/tXsC9fyLkmNSOqa5wjgzRazKo1HclkEqqq5hR79a4lSZIoSVJVSUlJ5csvv3wTGfy2Gb8ioVCINE0rIaJKYLrRW2FIOADCmnqIW7dlTBlaMjADySTsnm6Y7/wGqf/2X2GeOAaempoxjCQJFCwGrV0Hqq4BBQIgRQXJCkjTgNIyCBs3Q/nhH4I2bHYl6h1AFIHaNeDq2jn/ulOyAY49lqtz2FupiqIISZLKg8FgubtwmDM2I+EmJydJVdUiABWuDi6IFaoHqqoGbdsJrqlb/psZBnh4CNZnp5F6/W8d4n1yykkgSF9USFLGlHMix4EsbN4K+dsvAYHcXTrp4OpacON6YFbn86UgmwfbtmEYRq4uE5YkiUVRLNU0rXRycpIOHDgw52Zzvm6vvvoqkskkCYJQJIpiXvq53w6kqBCqaiDUrgH3r0TlFgOJBLjzBszBAdid12Ffa4X46BNOEfSs9g5z5ksESDLEhx6D8M5bsONxwFxcTJObmsFr6h3Hb/r1s0CuEQkv7no79epdVxAESJJUrChKSTKZpCtXrswRVHOutH//fgYAURQDAEoKxP02B2JtLaT79yDVdgW0Uv3gmIF4DHb7VdjDQ7C7OyC/8k+ddKcs1LtQVg6qrAb6ehZHOL8f2LwVSFOny0E2D7mQjpkhCAJEUQyqqlrU2tpKra2tc8ZlUqkEZ5mrCYLgL4j4aQZQaTlox33g9RvyM4FoBNZnZ5zK/2zJIwi3soEXAa5vBDduAIK5Fcncybhc1CsRQRRFTRAEP5yKvjnISLjnnntOEgTBB8ALWhYe6UQRQt0aiA88DNbytHeVZYIjY1mX/XEyCY5GgEXk80FRwPftBtauc/yBS0i2TDl06fBIZy28wvaKaxQi8jc1NSneufRBMwjnSbNHH31UJiK/++LbTjhfEEvKoNy/G9zQnLc52NfbnAKZLEwPu/M6eGjQccnkCF5TD2y7FygrX3KyZXV/d/W6EOlcX5wkiqJ/7969GaVARglXXl4uM7NGRCvW+W5RkCRQTR1o78OL6ki0FLAuX4R9rRU8OTkv6ZgZHB2H+f67zm6FudrFkgTcvxeoq886W3kpyZZWOHNb0gGQZVnWqqqqZGTQjBndIqqqSkSk4NaiomDFnFBUAm3Pg+Cm/Eg5HhmC8d5hWBfOgaMRsLdZHLMTo00kwMNDMD98D+aJY4urp11TD+x6AMgiaeF26jF9XDaYPY6Zoes6bNueEXv1tKMoigIRyX6/P+M3I+NJXddFIpIwj+FXSCBFATWuh/XstyB2dQCmseLfDrv1MoxkEhwahrjnIScKIIhO052Odlgfn4B57L3FZQ2LEvjp58HrGma4QjJhJRYRHrxqsNnjiEgQRVFy+TMHs0/Snj17KBgMEhzpV7CSLR1iUTGKn/sWps6fBX1+ZmnCRznC7mhHqvM68Mu/gVBVA2g+pyXF8OCdzefe+4EnngJKFt5ReiXJ5sEj3ayxBECQJIkACC+//DIfOHBg+gPIyELDMFYF0dLBqgbz+/8Y8o22/FVVMQOTk7BjsVt/38k8AkHw9/8ROJh9LcZKQ9d1KIoCwe1xcrs0pxk23Kuvvorz589D13Xbtm0bd9iTf8VABBJFFN97H6wXXgQvIiN4SWHbznEHZGNZBn/nd8AbNjuLhttFMrLAcrlSUqkU7FsVZGzbtm2aJsNJ5J3xIWRcNExMTLDbjsu7SmGGG9JARBAVBYFnvwVs3Q4ulFTwxUBRgc33AE8956SSFyDZZsMwDHYzh23LsqxkMplRWGUkXDQatWzbNph5hfoWLB2k2jrYTz0Lnid9p+BBBC6vAJ79NriqelWQDXBUqWmaME3TsizLmJyczGi4zrDhvDhqX1+fadt2kpmNQnb8ZoQgQNv7CFKdN8ATE6BVtskbB4uA3Q+C79+zYmRbqmu5EQkzmUzqw8PDnrC6vUr99NNPTdM0E8ycKtTg/UJQyiugPPkMaPu9YF9euvovDpoGbNkG3vfsgmWJhUg2D6ZpGslkMn7x4sWMPqCMhOvu7rZ0Z+XgvWjVsU7esAl49BvghkZwviussoEogteuAx7fByzgxC5UsgmCwADYNE3DNM3E0NBQxoyGTG4RBsCWZSWZOUbOxqxZTayQQKoG8YGHnQKX8XFgeDDfU1oQXF4BPPAIeM9D82Yy50Ni5WJSuXZc0jTNOObxcMyWcLxnzx6qqqpCIpGIWZY1sepsuDRo5RVQnngK2PUAOIe+IisOfwDYcT/40W/MuzVSoZMNcFr4G4YRi8fjMThcmjNmjkr1Bum6HrNtezynOxYg1KZmSE8+A95xH3jlduHLHrIM3rzViSasa8w4pJDJliFhcyqRSExWVlaiubk5q6otCILA4+Pjk4ZhRAo1ATNrEAFbd4DHRkGD/UD3EvQHXkJw3VrgocfA2++b879CIFEOY8gwDEqlUtGJiYkoEXFZWVl2VVsAMDAwMGkYhudTmMPU1QQtGIS6437w7gcLS8rJMrBzN/je3XMC86uJbG6hFblbMY1HIpGIu4iYgzmEa29vZ1mW7ba2tslkMhkCkFrNdpwHdW09tCeeyihJ8oat28F7HwHWzGwMvZrIBtzqam8YhqnreqizszM8PDzM7e3tt5dwJ06csPv6+uyDBw9OTU1NDVmW5ZW3r4646gIQm5qhPvetBTt/rxhq18B++nlg05Z8z+SOQUQ2M8MwjMnJycmB06dPhwHYJ06cmMOZTCqVAaC9vd2MxWLhVCo14jJ41apUD+QPgO7bA/u57yx6C8klgaqCn34e2HE/MKvXXb4D8Yu9lm3bHI/Hx+Px+Gh7e3sCWbpFAAAbN25EWVkZj4+PjxuGMXA3qFQAIEGAWF4Obe/DsHc/mL+J3LcbvHOXU8w8M3kxq5cXkvPXbVgDwzCQTCZDsVgsXFpaar/wwgsZ7f75UsxZFEW7t7c3HI/Hb7o3K4juSXcKQZIhrWuA+sw3wbUrULk/GzW14CeeBuobZzh4VyPZ0v5PqVSKYrFY/9DQ0KggCHZPT0/W/eG4qqrKFkXRbmlpCUej0S7btpNwVqqr3o4DAEHzQbxnB+x9z61sY0FRBD/xDHjTPTPagBWaesxlnCAINgBKJpN6NBrtbmtrC4XDYbu1tdVGthLuxIkT7PP5rEOHDk2NjY31GIYx5N541dtxAJy6zrIyqE8/B3v7TrCwQqS7Zwf4kSeAsrJpVVqIEivHe7K7dWZ4fHy868KFCxE4uxVl3wETbmOS0dFRY3BwMJRIJLqymuEqgiArUOobID3zTVDpTFtqWRAsAu97ztmMzS1pXO1k86DrOqampgbC4fBQW1tbsqmpad4GSPMSTlVVFgTB7urqGo1Go1fcC3iG4N0h6UQR6iOPgx94eFkzhFlWnHvseXB6dVyI6jGXcWkaj5LJJI+Pj98YGBgYLisrsyRJyp1wVVVVtiRJ1unTp8ODg4NXLMuaJOcudwfZ4KxahbIKiN/5PtCwHqwsQzG1JANr14G/832nVWoBkyjbcXTLHGAANDk5GR8ZGbny+eefj0QiEfvGjRvz2vrzrjxPnDhhh0Ih6+233566cuVKRywWa3f/ddcQzoPvnh2S63T7AAATzElEQVQQv/EUqKJqaVUrEbi0DHjqWaB5U9Y9QQqdbF5lFhFxKpVCJBLp7enpaTt+/Lhnv2VcMAC3cXU0NTVxfX293d3dPTY6Onph1kXuKuKpDz8OYeOWJVWtrKjAhk3AN54pePW4CMnGRISpqSkeHR1tHRkZGSoqKrKamprmJRuwMOE4EAjY8XjcPHv2bLi7u/uiaZo6EYlEi9zwqoAhNDQ5K8i0Pr53jPIK4JEngNKFi5g9rCZfnMsBYWJiIjU0NHTp4sWLIUmSzO7u7sUTrrW11QqHw+b7778/de7cuWvj4+MtwHTP37sO2gMPQdyyzUmIvOOL+YCNW4AHH8tq+GoiG+CksKVSKQwPD3d2dXVdOnXqVDgSiZi4ja/2dtEDbmpqsteuXWu3t7eHOzo6PnA759wdsa5ZoJJS4MFHwGvuPLjP1TXAQ486hTF3EdJlTTgcRn9//8c9PT0jRUVFVn19vVc8vygJBwDc3d1tJRIJ44MPPogcOXLkt8lk0ttw/u5xj7ggQYCydTvEpg1zguo5QVGBhvVOcH6F7bblthU9+42ZhVAoFLl8+fKHp06dGpmcnDT6+vrmdfh6uC3hALAsy5ZhGMZHH300NDw8/Ilt2yYR3RVhrtkQyitBO3fdWQpTdQ2wc9d0a9SFUCgqMptxadKNo9EoDQ0NXbxx48bNeDyeAOCp0zsiHADYw8PDpqZpqWvXrk2dPXv2sK7ribStyO8uKSfLkLbvhLhpy+KknKKA1290CHebOO1qIpt7zjPfaXR01Lh27drRK1euhHVdT+GWO2RBZEM4BmD39PQYhmGkXnvttYtjY2OXLMsycJeRzYNYWwfhnh2Lk3IVVcCWbc7PBVAI6jGXcZ50Y2aOx+M8MDBw7ezZs2cmJyfjExMTBhaIn6Yja8IBsFRVTR0/fjzy5ZdfHk4mk1PpIjard7JKQIoKcf0GiI3rnc7j2UIQwOsaHcIt0Bq1UEiUyzjPFcbMCIVC+tWrVw+dOXNm0C2Wz0qdAtnnuNkAzEQiYfj9fvP1118/HYlE2gzDSGZzk9UIcU09xE1bgdIc9mYtLgWaNsypUUjHaiRbumCJx+PG4OBg57Fjx34bj8eTiUTCk25Z2fS5JFXa4XDYKC4uNn7xi18MtLa2vhOPx4ds2/Zmc1cRj8orIGzcBMrFRdLQ5NQoZPDjFZJ6zDRmoXGedDNNk0OhUOTq1avvHj58uEuW5VQkEjGQQ55ktoTzXCCmruspn89nvPbaa78NhUIthmHEcZeRzYNQUQWxockJwN8OkgSs3+CQbhYKTWIt5loAeGpqKtXT09N2+PDhIwCM4eHhnNQpkJuEYwB2JBIxamtrzYMHDw5fuHDh6Pj4+E3DMLwb3lXEE9aug7BrL7ii8vaDy8qdTuqzFgurnWxExETEuq7bw8PDgy0tLe+99957N6uqqkw4G4BmTTYgd8IxADMSiegAUj/+8Y9P9ff3f5ZMJifulsquGZBloLLKSZq8DXhtA1BVM8MVUojqcRH3ZNu2EY1G493d3Rd//vOfHwVghEKhJG6TGZIJuRbGMABrfHw8VV1dbXZ0dEx99NFHx8bGxq4bhsF3VRq6C0FRIAay6DG3pt4J1rsoVImV4zi2bZvi8Tj39/f3njt37oObN29GXOnm+d5yet6LIRwDMEZGRhIA9D/+4z8+d+PGjeMTExOD7s5zd1UEQqhdA+m+PQvvdCPJoLXrgDKHcHcD2VzYpmnaoVAo0t7e/tGf//mf/xaAHgqFso4szMZiSv88v5yxZs0aA0DqF7/4xXv9/f3nEomE6UYg7h7SFRWD1m9cWK3W1jk7NN9FgXo3dClEo1Hu6ur64tChQ78BkCoqKjKwSOkGLJ5wDMAcGBhI+v1+48iRI4OfffbZ0f7+/nPJZJJz/BYVNIgIJIkgaYEwVX3D9LZEBW6PZTXOw/j4OPf09Fy7ePHikVOnTnVXVlYak5OT3sp0UYvExW7A7kk5Mx6PJ5lZfP31189XVlbWBIPBtZIkNcqybOMuKZ6mQBGEdY2wOm9kHlC7BlRcnHV6eqH649LG2slkEsPDw4PXr18/cfTo0Y/j8XgskUgksYiVaTqWpCBT0zShvb3dFEUx2tjYqJSUlNyjaZriFVksxT3yCiJgcgLWpQvOhh/pkGXgyX/gOHyz2NFwNZDNtm0MDg7GW1tb3z18+PBb7777bo9pmgkACRQC4VKpFPn9fqGjo0OvqamJ19XVlQWDwc2qUxK3+kknyWDDgPXFeSA2NfN/lVXAk88AaxsWjLuuhkgDEdlEhLGxMVy/fv2TkydP/vpXv/rVFVEUEy7hdCzSdvOwWJXqgd0JpOLxuOTz+aS33nqro66u7h2/379GFMXdwWCQ01LSVyXxSJJA/kDmiENlDRAsXjAVaTU4f5mZBUFANBqlmzdvXvniiy/ePXbs2BXTNOOuKl30QiEdS0E4252InkgkxI6Ojujhw4cvl5eXH9Y0rVIUxQZN01a/lBMEkKLM/bQrKhdcnRY62TxZQEQci8Wot7d3sKWl5ciHH374WXt7eySZTCbhSLZFuUFmY8mbapimSX19falkMjlWX18Pv9/f7PP5AtKtdJ3VSbzYFOz2q+C+npnn9+wF7rk3Y/fxQo80eLWlRMTJZBLd3d3hlpaWQ4cPHz7k2m1xOHbbHatSD0tNOC+rQGhra9Oj0Wj/unXrpOLi4k0+n08RXbXDzLTaXCecSoEH+2Ff+fLWSSLgsX3Ahs0F01gw22t5ZIOzmQf39vbGLl68ePjNN9/81eHDh7sBxN0jhVtukDvGshAOjhQTrl+/rp87d+7q3r17q4qKiho1TZMFQSD3Da8u0hEByQSsz88AhrvJis8PPP280+5eXD293jyyMTNblmUPDg4a58+f//BnP/vZX544caIfjlTzJNuSqFIPy9GnatohqGmaGAqFrKNHj57ft2/f+kAgsEZVVdEjHVaReiVJAiQR5uWLwNioc7JxvdPGobIK3lspdMdvOtkMw7BDoVDq/Pnz537605/+p5aWlhFZlr2dZDyf25KoUg/L1RjNU61UUlIiRSIR6+LFi5cefPDBe3w+X5WmaZIoit6ntDpIR+S4RoYGgY7rgCA6daf33qrOKuTY6Gw1almWHQqFUpcvX776k5/85MeXLl0aDgaDqVgs5tltS042YPkknPfT1nXdrq6ulru6uvQLFy6c27lz51q/31+vaZrsLiRWB+EAQJQgVlTCYoA2bgZ9+yWgqhoQxIInW9rvbBgGDw4OGp9//vm5n/zkJz++fPnyUElJiR6NRifhkM2z25Y8Jr6cEm5atcZiMbukpEQaGhpKtbS0XNy6dWtA07R6TdN8bi8xYDUQTxRBpeUwtu4A7tvjNIV2bbdCJxw7RjMnEgn09PTELly4cOynP/3pTy9fvjxSXFycmpiYmMItsmVdo5ArlrPXqEckGwB0XedAICANDAykrl+/frWxsZE0TatXVbVI0zR27YqCXkgQEUAESdNgMk/HTgs9EE9EtiAIiMVi1N3dPXb+/PnDP//5z/9ba2trKBAI6Glk89wfy5bts1IdlRlwWnNKkiT09PSkDMPor6ysNGVZrlQUpVzTNKwW0hERRFGEZVl5V5FZjLWJCOPj49Td3T1w+fLlQwcPHnzz5MmTA5Ik6W7VfLr7Y8lWpJmwkoSz4RirDABtbW3xVCo1EAwGw4qilMiyXKuqKomiuCqiEoIgQBAE2LOD+bOQb7JZloXR0VG+ceNG66VLl946fPjwO++8804PAN2yLI9sOu4wKJ8tVnKr5GnSuQe6u7uTo6OjI4qiDMuyTKIo1qiqqiqKwnSr8LZgJd7tSJfHsJYtCAInEgn09/fHrl279smZM2d+/e677350/PjxPsuykpjp2PVWpMuOlSYckEY6y7IwPDysd3V1jaZSqV5FUWKSJFWJoliqqiq56oBQwBJPcNuoem1IPeTJ+cvk7HslhMNh6u3tHfjyyy/f/eCDD95+5513Ll67di2USCQ8p+6yrkbnQ742g58W3ZZl0dTUlHX+/PnI+Ph4X3l5eUoQBJ8kSRWSJAmSJFGhSzvBTUtK632b1euWahwRsbtdJOm6zmNjY2ZnZ+fVlpaWowcPHjz8m9/8pn1sbGzKtu10p+6K2GyzkS/CeWrVs+sgSRLa2tqmOjs7O2VZHpZlWSCiIkmS/IIgkJDWkLkQiZdOumxwpyvbNCcuiIgty8LU1BT6+/vHrly5cuaTTz45+Mtf/vL9kydPDgiCoOu6nphFtpxL/JYC+SacRzrbsixb0zQaHR01z54923/16tUvq6qqTCLyEZFPFEVZFMWCJp43t6VYSNyOaC4ZmZkRj8ftsbGxqY6Ojo7z588f/Zu/+Zv/eejQoUv9/f2Tsizruq579pqOmXltK17SmS/CARlIZ5qmbVkWa5pGnZ2d8SNHjlwOBAJ9oiiazOwTRdEviqLkPlgnGFtgiQC3I91iyTZLooGZOZVKcTQa1Xt6evouXbr0ydGjR9/4sz/7s7c6OjrCsiynEolEulSbTba8IJ+E8zCDdACsVCplA4AkSfTZZ58NvfvuuxfKy8tDgiDItm37BEFQZFkWBEGYrhDziOddNJ8EzES6XB2/sxYg6UXmbFkWT01NGX19faOtra2XTp48+eaf/Mmf/K9z5851EJFhWZaeSqVicBYGngpdEbfH7VAIhPOQTjrPtrP9fr84OTlpnjx5svvatWsXFUWJMHPQtu0ySZIkdzXL7jEt9YD8qlyPdNk6h4E5SZHT59yVJwOgWCzGfX19yba2tuuffPLJwb/4i7/4H2+88cYXuq4nfT6flUgkPPWZLtUWXda31CgMPXQLBKe0UAKguIcGQA0Gg1oqlRJTqZTw4IMPVnznO995dPfu3d9taGjYWVVVpVVUVLAsy2Bm25V0VAiq1rZtpFKp245Ll2xeRodHPMuyhHA4TKFQSO/r62u9dOnSO0ePHj398ccfDwKwg8GgNTU15RHMOzz1mVcVOhuFRjjAmRPBkb7pxFPhEE9lZtnn88n33HNPyeOPP7599+7dz9bX1z9QW1tbU1FRgUAg4O3jCWYm78gH+TzVqOv6bYemSWoAEOLxOMLhMIaGhkZ6e3svfvHFFx9++umnl1tbWyPJZNIgImNqaiqdZOkSLW8Lg4VQiITz4Ek7EYDsHipcAiqKosqyLBcVFSnNzc1Fa9euLX/mmWe+0dzc/Eh1dfXm8vLyQElJiRAIBCCK4nTlmEc+ACtGwNmk86aS5j8DXImcSCQQjUY5EonEh4eHb3R1dZ35+OOPT3V3d490dXVNTk5O6oZhGClHbKZwi2TpEYO822rzoZAJB8yUdpkknqwoiizLspxKpaQnn3yyvKGhoXzz5s0bm5qattfV1W2rrKxsKCkpKfb7/aLf74csy576mrbo0yXgUiw8Zhv8aa3M2DAM7/8CEcE0TSQSCcTjcSsajU6Njo72Dg4OXu3t7W3p6Oho7+zsjJw5c2aMiAyXaF7nIo9sBm4RrSClWjoKnXAePGnnSbx04nmHGAgElFQqJTQ0NAS2b99e1tjYWNHc3NxYX1+/uaKioqmsrKy+uLi4yu/3+zVNg6qqUBRl2mkLpzxz2v2QdtKbwxzHbhop5/RUSVPjDsNtG7quIx6PI5lMYmpqKjE1NTU6Pj4+ODo62tnX19fe1dXV3dPTM3b16tVwT0/PlKIodiwW8+yxFGZKMxO3ogUFK9XSsVoI52E28WTcIp+kaZqaTCYlAJKiKCIzCw0NDYFt27aVNzU1ldfV1VVWV1evraqqaiguLq4LBoOVRUVFZZqmBTVN0yRJIlmWWZIkSJI0HZz3XBrp0m/GpFwp5h2WZU0fhmGQYRhIpVKJeDw+FY/HI9FodCwcDg+FQqGe4eHh/lAoNNrZ2Rm+du3aWBrJLACmpmlmMpn0CJZ+eKpzVRDNw2ojnIfZxPOknmfryaqqyrquiwBERVEkZhZkWZYaGxsD27ZtK1+zZk15VVVVcUlJSUl5eXllSUlJtaZpJYFAoEhV1YCqqn5ZljVJklRRFCXRgUBEAlz7j13Ytm1ZlmWZpmlalpVKpVLJVCoV13U9FovFJnVdj0aj0ZHR0dHRiYmJ6Ojo6ERvb2/4+vXr4Y6OjinDMEwislOplAXAVFXV0nXda2nqtcfyFgKrkmgeVivhPHjEm23npR+yqqoyAFHXdQGAoCiK4PaxI8MwxK1btwY3bdpUWl1dXVxZWVlcXFwcDAaDPk3TfKqqapIkKbIsK4qiyKIoii7p4HDNtjwj3jCMlGEYeiwWSyQSiXg0Go2Njo5OjI6OTty4cWO8paVlSpZlE476tV0Ht62qqg3A0nXdU5OeBPP+TrfPViXRPKx2wnmgtMOTep4/zzumyaiqqghAZGYhlUoRAPJIqCgKAUAqlYJhGARAkGVZLCoqkgKBgKiqquhVnFmWxbqu27FYzJycnDQNw7AAsCzLrCgKu9dhcpr7cSqVst1cPxtOgZFng1m4ZY+lEyx9xVnQi4FscbcQLh3pxEuXfOnq1yPf9DlVVQUAoizLAgDynLXuT4+U3u/pYHfMdLWaoihwx7Lb4d3WdX02iawFjjnJqncL7kbCpWM2+YQMhzjPecpwCGnXBTIklc460m2tdKLZGY67lmTpuNsJlw5K+5mJiOnnMhEOs373kE6QhQiXTqhMavKuJVk6vkqEmw2a9XsmQtKssfN9Xjzr99kHMFdyfSUINhtfZcJlwuzPI9Pnk0nCzcbsc19JcmXC/w8/JISRV2sMdQAAAABJRU5ErkJggg\\=\\=\nsys_ro.build.date.utc=1469090187\nsys_ro.serialno=abcdef12\napp_apk_location=internal\napp_apk_codec=BZIP2\nsys_ro.product.model=Some Model\napp_version_name=1.4.1\napp_is_forward_locked=0\n"
  },
  {
    "path": "app/src/test/resources/TitaniumBackup/dnsfilter.android-20210529-164214.properties",
    "content": "#Titanium Backup\n#Sat May 29 19:42:17 GMT+03:00 2021\napp_apk_md5=6df217d8c3415e7664cb4942b2145ec1\nhas_dbdata=0\nsys_ro.build.version.release=6.0.1\nhas_external_data=1\nhas_prefsdata=0\napp_is_system=0\napp_version_code=1504801\nhas_prefsdata_jpu=0\nsys_ro.build.description=Some description\ngeneration=1\napp_gui_label=personalDNSfilter 1.50.48.1\napp_label=personalDNSfilter\napp_gui_icon=iVBORw0KGgoAAAANSUhEUgAAAJwAAACcCAYAAACKuMJNAAAABHNCSVQICAgIfAhkiAAAIABJREFUeJztnXmMXdd93z/n3P2+92ZfyOEqkbIkUrtsa7G1K3a9JbESC26QFK4RBAhStAngFEHRAgrQNmmAoM1fbYImbdMiaSwkUSLHltfKkmlHkWKLWkiJWijuw9nfvO2u5/SPe9/jbBTJmSHFN3M/wNWMhm/uvW/u9/3O7/c7v/M7UFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUFBQUPCBIq7IVTQCnrgy1ypYJU9oAAT6A76RVaC14KtfMDKhFXQVGoF+QqL1ZXl263tSjdBohBDZp0Rr8VUOWdTDXkRiNJqN8/5qCShRogE0OP/rLsTIOpyjRCn/bnVnKS34bq33UQIm1uW9nP/dlPwSaDMtlyvzn2ZvRP78dC66zvNcB9ZNcHrxJ2IYuFeh7gC5VZEOA5a6wG3L/Ktaw30U51jVeYSEWGoxJaU8DRwEfgic6bxgnUS3LoJbILY+4F7gZ4DbgW1AGXA5974LrjLy56eAAKgLIdqiexo4AEzC+ohuzYJbILbtwKeBXwRuBXytNYDQl8kfKFhfhBBa645L1AJeT9P0rxuNxld7e3vfa79mLddYm9XJg4L5+fl+4NNa618GPkYutvZR0B20n1X+1QM+qrX+kpTy82+//fZQ/m9rMh5rEpxG89u//duiVCrdq7X+JSHEnVprlQvNAIz8GqI4uuKQ+WG0h1kp5YeklL/oOM7Djz/+ePtZrprVC05rIYTQX/nKV4aFED8jhLiF3C/NxVbQ3UidP2PDMD5kWdbP/cqv/Mo2IYR64oknVq2b1QvuycclIC3L+pgQ4nbODaOF2DYOUgghDMNwTdO8ZXh4+FFA8sDqdbN6wX3hScWDD0okdwghxgp/bWOitcYwDCzLGjZN88P79+83n/j+6jM1qxecgF/6zIcdtBjTWlc45wcUbCyEEEJYluWZpjl29913l3niCb3amYjVCS6LTsWe/df3JzodAdzcySwEtzERQgjbsqyhffv2DQEyd6kumdUJ7skvZNGKSEzAWvV5CrqCPDcnhBCWEMIB4NDkFbRwGaI6MycLt23zoLUWURRJQNy59UNXUHCZumWz1jC0VsUwuknQWhMEQTtftyrWNBSqJBVKFdNWmwWttUjTVAAEZ2av+JBasAlpC261rMmHW8uFC7qaVT/7wsIVXFEKwRVcUcy1/LK9XndxFaO1RpNVJSitSTTEWpPq7NNqCrCkwEAgRF4aIwpv43ysSXAO9oYxkXkRPxpINARK0VKKZqpppIp6qqglKfOpopooQqUxBZQNSa9p0GNIyqakZGSHLyWeIbCEyByeXISbXYprEly4XnfxAaC1RgGh0rm4NEEurNkk5VSQcDyMOBbEnAoSTocxE1HCfKpopKqzls4RgoopGbZMxhyTrbbFTs9it2ux07UYsk1KUuIbEk8KXENiC4EpNqclXJPgIqI1L/C4EiwcFtN8OIy1ppoo3m2FvNHIjreaEUeaIWfChNZFTqGEWhPGKVNxyuHm4o+gJWDUMrnWt7nBd9hXcrih5HCNZzNomdhSYAgwyL4KNr4I1yS4biHWMJOkvN2MeKUW8HKtxcFai3dbETWlSdFcaEXZaq97Mko4GSU8N9dEAIaAkpTsci1uLrvcXvHYX3a4vuSwxTZxCsF1H81UcTyIeb0e8HIusKNBzHSc0FSaSGnSfEi9klPBbf+wmipea4QcboY8NVnDNQS9psEux+LWisvtFZcbSy7X+Q5lQyDafuAGoOsFp3Tm1J8IYg43I16ab3KwFnA6TJhOUhppSpBqknUW2LBpss01qSWKmSShniriSzh5FvVCrBVNBbNxyskg5qVai5Ih6DVNRi2DfSWXD/d63FhyuNaz6bcMrC62gl0nOA3ESjMdJ7zbyobIg/WA91oRp6OE6TilliginYnsclmwfWWHX985iCkEs3HKZJxwKog5GcacDBIm4oS5JGU+v5cLvScNRFoTpZp6ClNxyvFAcKgZ8r25OsOWyU7X4saSw61lj+t8m62OSdmQyC4SYFcJLlKKg/WAH841eaUe8E4r4nSYMBOnNNPswV6pIbLPNLij4jFoGcRaE6pz6ZNqopiOEyailPEo5lQQ814rE+N0nEW6gTr/vbaH3kRrWiplOk45KmJeqQc8P9dgxDbZ7lhc7zvc1evxQH+JAas7HmV33CVZpFmPU743XePPzs5zPIhpKEX6AdXjCcASAldKvNzADJOJRWlNrDSB0jSVYj5RzMQpU3HCmTBLsRwLYo62Ik6FMbNJSuN9hmRNFlXHqaaWKk6FCYcaIS/Mt3gviNjjWvSbRldEuF0luFYccbIZciyPLq9GskhUYBgC14A+DLZmNbIkuQDriWI6TjkbZeI7Fca8F8S804x4rxUxGSeE+azGSmggUJogSnivGTIXhKiSg2Fc/QvmukZwSimSOCFNUq7cwLk+tO2OJQW90qDXNNjmWmgNoVLMJYrxKOZ4Lrp3WxEnwpj3WhGnwoT5NCXVKwc8WmuSJEEpVQhuvVFpitLqyuYyLiNCgGtIthiSLY7JbRWPRGmm45RjQcQbzZBD9ZC3WllS+mgrornEsmutUUp1zRLNrhFce7aALvnDrhZTCkYdk1HH5KO9PoFSHGvFPD01zx+dmuWdVvRB3+Ka2Chz7xsWV0quLzl8tMdnwLr6h8wLUQiuS5BiY1SaFILrEiQbY3qrEFyXIDeC2lij4CobqADzamfNjdmuEtakl24uwFwL7QevOrOgl5+sdP2KXOqysikKMFeLAGyRlQ6N2AZjtsWwnSVuB03J18bnKBsGfZbBiG0y7Fj0WQaeIbHWeQzMSpS6X3Fdk4e7kthCsNUx2V9yuaOS1aWNORZ9ZlYmbkvJy9UG//PYFI0kxZbZOoZ+22TMsbiu7HBzj8e1JZeyuT7VHBvFhysEtwADuKHkcH9fibt7ffZ6NtvyiXHPEBgLhPNOvcV4EDEVpZ2fWULgG5JB22SbZ3FDxeXu/jIf6StRznNoq9XNRumFVgiO7EFudyweGijx6ECZOyseO1wLX8pL8puydRIp1STlvWbIa/MtDs61+Ie+Bg8P93BLj4cjxaqqOjbCcAqF4DAF3Fp2+dxQD58aqrCv5OAbWSyl8gU3GjpVtu0QIdF0Sr9XChsUWRXvS3MN3qgHHG9G/JPRHu4ZKNNvm5iXKDqxQRK/m1ZwAvCl5K5ejy+N9fOpwQp9ub+Vas1MnHIiiIm1Zo9vM9QucNRZTdqJKGG7a9NIFM1Udc5ZNiVlw6CRZtW+CphPUp6ZqHK0ETIZJjw4VGGHb2PLi08SiM5/uptNKThBVrF7T6/Pb+wc5N4+H0dkQ109UbzdCjkwl62N2OVabHf6wcoKCCKt+eFck4P1gE+O9tJKFW/VA9qe3IhjcUevjwZenW9xvBnRUlkC5Y1GwH8/NsVMnPDTW/q4puRctOgKH66L6TEk9/X6/MauIT7W53eSkTNxwo/mWvz52Tm+P9tgu2vx4ECJETv7M6Vkaw3+8NQMjhA8tKOH442Qs0FWtauBVqrY5ll8dksfr1ZbfG18jp9Um8zG2b+PhzFfPTWLBh7b2s9u38G8iBB0I4gNNuHUlicFd/R4/OqOAe7t8zFEtiPtVJzy9GSN/3h0gr+amGc2SbnBd/hIj4clBVprmqnipfkW356pk2jotQweHu5hl+/QruOYihLeqAWkGj69pZevXLeVn93az7Btdv7YU1HCU6fn+NbEPBNhjLqIkiu5QSS3qQQngF2uzeMjvTzQX8IgL11Xmr+aqPL7x6d4sdYi1JottsX+ksuYYwFZYDARJfzlxDytBQtgbuvzua7s4OWBRqQ0x1oRh+dbWELwobLDv9gzwhe3D9BvmR3ZnAljvjY+x4uzDYL0wjXMGyVo2FSCGzANHukv8dhIL07uOyng7ybn+U/HpnijGXZ8set8m/0LhBQozZFmyHema4vO2W+Z3NFXYotrdX52Jog5ON8kUhopBH2mwa9eO8IvbB+g3zI6wjnSCHhmYp6D883L/M6vHjaN4CRwa8Xl8S19DFjZ206Bl2sB/+G9SU6HcWcFmAT2+g57fLuT9piJU56bazIRp4vOK4Bbej12+04nddJIUo42I04sqM51hODLu4f49Ggfg22fUMMLs3WenawxGyWX9f1fLWyaoGGLY/LxvhK3ll2EEGgNsYI3GyEfrvjcVHI7r7Wl4OH+ElvtbAhMtGY8SvjxfICfO/imyFp6NdOUIdtkh2dTMiVzcUqs4XQr4pX5FmMLLJ8lBI9v7+dsGHNgpk4zVVTzXN0dsz6fHO097/1vlALMTSO4D/kOH+/zKRnnkrW2hIcHyny4x1v0WiFg0DI6CWAJ7HYtfmv3EPNJPwBng5jfP3KGUGUtJI42wk4+DuBkEPPHx6b45tnqonNHWvN2PSDOF8Mo4N1GyI/nmtw3WMY3Vy4j3whig00iuIohuaXkcmvZ7Uyki7xN1hbHZIvz/n8GAfRbBvf2+Z01PM9O1fjTapPpfChMl6wjbaaKN+st3mkEy8639LXzScrheosjjZDbev01vdernTW2XO2OAsxdrsX+skP/KhehCCEwYNHkvSGy1hPh+yzITnUmrguhgJOtiFeqTW7p8bqqV8ilsiks3F7f5jrf7jzIRqp4uxkyvSQAgExUe32bLbaJIQQqT5vMxinpguRFPdWMOFY2U5D/uJEqGmnasV62EPRZxorzpima+Thr6wowGSa8mQ+1jlEI7jxc/QWYEtjhWGx3rMx305qzUcJfnK1yqL68ZrlsSr481s+IZWZWTGvebIQ8M12ntsBHKwn41GjfIgv/2nyLf5xrMBElCGDANvjESC+jjrXsOs1UcWC6xqFaQJQnlceDmGqSMmKsPG5shIqRNVb8Xv0YQjDqWAwvmJ4aDxO+MVXn1RX8q222yeeGejr/H6Sag/WA/3ZyhtnkXOri04MVfu+6LQwv6Fr0jbNVTgURE7lf12+bfGKkh9t7S8uuU0tSWqniWCsiilMUUI1TxoOYkRUEujHqfTfBkOrJLPHajjgTramlWc3aSt5VKW/+3B4FY62ZS1JmkoTWAn8t0dkiZc84VzPXbxv0LIgyU5W18fLN5RbLEDBom3iGZDYf2ltKMRWunI/TXddRZWW6wedfE74h8aXozEUqDa00a7u6Eo6UmPKcNUm1JlQXbioI4EmJmwu73WKrka7sdJh5dbC9wL+LlGb+PB+ERGnUeSTXTZav6wR3qf1uLSEwxTmLla2zOr+1WGnOMtVcVNNpKWBhHKzJrNz5rmOKxdW/Ku+uvhIttXL7rm4rW+oqwRlku99cSrVsR1z5g5RkMwnnO0eSN5zuPFuR93u7iGspDQvjXvk+96rJItWlXY/O987qqeoki5e+vpseYtfcqxACUwpcKbAv4SMdKk2kzg1GphBUDIPSeSLBhlKEC0Rgkl/zIlIVgVIEC4ZQU0pK55k5SJSmlapFFs3M23etdKWZJCHQi4dnkf+O3UV5u64RHGSOti/BvYS/73yqqKWKJH+wpshmDba7FrZg2REqRStVnYStJQUVQ+KJC/+p6knW3RIyMThS0GuvLLhQaabDZNF0mGPI83ZIOhumtJb0l83+HgK3i55i10SpQmTrQXulpCTOt3RlOYnK8m5TccqYI0EI9ng2f3D91k50uBBDwG7X7lR+eFJyV6/Pv71mhHp67vVSw58en1pkjQ7XgkUVIhNhwpMnZ/jexPyy6zRTxQuz9Y5AIdu3a6u7fMu8WGlOh/EicQJYQI8UlFa5EuyDoGsEB2AISb8p6DGA+OJ+RwEngqyT+Fie/HVlJjrlrSxac8Eqd1PAHs9meNRcNNPwDzMN/uvRs1Tjcz9tpecW1GhgJkr49kQVY4UScqWhnqSdIdUWgkHHZHiFed1GqhiPks6sRBtXQL8UnZq9bqBrBCeEwJCCIVMyeAlTPxp4uxXxViviznyeUoq2H3jh80gh8IzlD9U3BDNRsmgh9FJirVecPluJPtvgWt9ZUTxzScqpMF6UBwTwhGDYzDqpFxZunRFCIKVk1DQYMc+/HnQl3m1FvF4PqA1V6M2d+HbkumKqQWTObXvuVZP30l3Q2FnrzBK2h16FXlML/zHX4uYeb8W1C8eDbCfDpbnDiiEYswxsoxDcZUFKSZ8lGTUlJQH1i3zAs3HKq/WAw42Qj/b4SJEJqJYqnpmqMR6li1oH91uZ33adb3cm8E+HCc/O1JmOs2EtVYrPbe1H54ulD1abHK4FnWGvxzS4xrfpXRIEhErzdiNkNko689CeFOzxXfb3eMtW+iutebUeMJNPfy2kXwp22Qam0R17NEAXCs43DUZMgyEJ9YsbrUiBN5oRP5xrclPeYAYyP+pYEPPn41XqC/ZAHbENpIDtjkk5t4jVOOVbM3V+VG0BcF+vz6/vHKTflMwlKXNxypF6Njcrge2exWNj/ezynM59ZGtVm0xFCXNx0jGXW12bW3o9hu3lc6gtpXilFiwqHIDswQ2agjHbQHbRkLomb/NKbkHeHlId02TMNthmXtof+GQQ8/3ZBocaAanWiHxj3UcGSmxxTMajmKNBxNEg4uVawMFawNkoCwgkgh7TYIttcTx/zXyq2OJY7PAcEqWZiZNObZwtBbt9h58a6eWB4UrnuKnXo5YoGonqzFyUDMmtvT4f7S+vuD71bJhyqBFSXyK4ioTtVpZG6Yb9GdqsOby5kvGREAIrF9xu69JWaoZa85N6i7+ZrDGZO/oGcGvF49e2D3B7xaOcO+yh1hxqhBxphiitEQIG8orf4SV7WsVa83K1yXuNsBNxVkyD3Z7DYJ6D01rTSFK+fbbKMxNVJqMYnV//Q2WXjw+WubbkLDpvu9Xha42AY2G0rNBzyBDssQ1Klrl5LNyVtXH5bIORWZo9dubHXQpnwoRvTNf43kydVqqy8wnBJwcr/Nr2Qe7u8ankojvSDHmtHtDKLYtnCG4sOdzbt7gEfDyI+fFck4m8ykMAWxyLfT0utpQoramnih9M1/mT41OcDqJOcDHqWnxipId7+kvYS61bvl/XszMNqsniaXsBjJmC610T17KQl9Cj5INmTXd6pTtgCiEwDIOKbbLbNth5iR6oAt5shvzx6Vn+Yb5JmDv4lhT8/GgPv7lriIf6SwxZBhNRymuNkDNRklmjvEnhF0Z78PNqklRrXpipc6QeEOTncqXk2pLDvopHrDQTYcLzUzV+58gZ3mmEHbH1WgaPDPfw8HAPW73lH1wNnI5iflg9d59tXAG7Lckex8Q0za6xbtBlU1ttwdmmyQ7H5Ebr0v/QgdK8ON/k949N8WYjzCbqtcYQgkcHy/zO3lF+YbSXIcvg3VbIwVrQacVQNiQP9GervAwB1STle1PznGxFHQs0aBvsq7iMuiang4i/PD3Lvzl8imMLXmNLwccHyjy2tZ89S4ZSyPfP0vBitcXbrXDZLoNjhmCvbdDnWBhdFKFClwkOcj/OstjpWtzuSJbHdRemoTTPzjb4l2+e4bV6uMhK31By+fd7tvBH+7bxYH+ZU2FCNZ9+kkLQbxr81u4RyobB02fmOFQLOglZSwhurHhcU3L42zNz/OZrJ/gv74xTXZD8NQU8OtzDL+8aZn+Pt2hhzkJaSvHk2eqyYAHgegtu8kw82+46wXVVWgSy1IhpmvQ4Nnscg+vNlNdWsWi9qTQvzLf48usn+XfXjvBTg2X8vFLDNwQP9JX4SI+H0nTSKACWgPv7fE40Q/7s+BRngnNzbELAoVqL33sr6wNXz3cBbFM2JF/cNsBj2zLLdr5Au6U0r9QCDlSbyxLTnoCbHIMbPAury/w36ELBARiGgWPb7PJs7nVjDtc1F5mSW0SkNa81A/71W+N8sdbLz4/0cn3Jzqp+BfQIiebcBFh7dsOVWYa/HqeLyosipRkPYhAsEpoB7C07fGnnEPcPVhhyTCyx8oS7BmaTlL+erDKZ+48LudES3OiZ9Dp21/lv0IWCa+fjLMtixLG53Wkx1Ew5u8roJdFwLIj4X2dmeaUe8NNDPdzf77PdtXCkXOZztB+wKcWKdcMpdBK6thRsd2zuGSzxiZFe9vV49JkGhuC8QglTxZFGyHenG8s+RBZwmy24zrVwne7YkHcpXSc4yNMjpknFddjjWtxlK74W6FVHzAlwMkyYjeu83Yz47ozL3b0et1U89vg2A5aBvYL4lt0X+Sa8psFOz+a2Xp87+0vcUHbZ6lo4UsD7lMhrYDJO+cZ0fcVtKncYcJtrsM1zOsNpYeGuEO1hdZvncL8X8aNIM7nGHE1Dad5ohpwMY/6x1mKna7HHs7nWt9nl2ozZJv2WQcUwaKSKAcvCEtnKrX7LYNS1GHMtdvkOu32bHZ7NsGNlK7su4vqtVPFaPeCZqRqtJaXnNnCXK7jRt6m4meC6TWzQpYITuf9jWRZ9nsPNXou7g5i/a63eyrXRQC1V1FrZVuAvzbfotwwGLIMB06BiGrhSsN02+Wc7B/ENiSMlZVPSZxn5YeKb8tLWXuhs+u3vpmq8vYJ122bCXa7BLt/Btu2utG7QpYKDc8Oq5ziMeQ6PtBJ+FGqm13GH8hSopopqqngvWFzx+bNDPfyrXUOM2ua69AKppykv1wK+M1NftKYCMuv2EVuwz7PodZ2ujE7bdOdds2Ay33Ho91w+4pvcY4srOtkm12k9fKo1R5oRT0/Nr+i7XWPCg77BrpLbCRa60bpBFwsOzlk533UZ8Rw+XxJsN7moJX1XC1prJqKE78zU+eZ0fZlL4At41JPc4tv0e25nOO1WuvfOWWzlKr7Ph32Lh1xBRXbH4mBNtt70B3NN/mZynulkcSJEAjdbgk+WDLaVPFzX7WrrBl0uODg31eV5Hj2ey8/6khutLCN/tZOorFHO307O8+Pa4sY6AhiQ8HMlwbW+Q2UDWDfYIIKTUmLbNr7vs8e1+Iwn2Wpc3W9O532D/3pinu/M1Je1eLCB+x3BxzyDgZKP0+W+W5sN0wHTNE183ycMQx5NEt5JNNWmZuoqbWBXSxVfPVvl6anass7oNrDXEvzzimRrycf3PGzb7nqxwRqNwPLCmg+O9tBaKpUY8lw+XzK43RZX5dAaKsXfTs7z1bNVji2JSiVZzu1L5WztbLlcwnGcrh9K26zpXdSukg6Y7U++YRi4rkulXGaPZ/H5kmSfdXVFrYnWfGe6wf84M8frjYClhS7DEj7nSR7wDHrLJTzX7UzSbwQL17WJ36V0JtVNMwsg4pg7kpTjiWJOad65CvbdSLXmudkGf3JmlpcX1NG16RVwryP4lC8ZKnmUSqXOULoRxAYbSHBt2gFEyfcZTRIeTRVTaUqrpTm9mhqmdUDnC6j/vtrkD45P88Nqk+qSFIgn4HZb8IWy5NpSZqWdLq0IeT82nOA6U16eR5qm7EpTPpO2iLXi6aZm5gr3LdVkw+iBuSb/+fgUz801qKWLF8XYwK2W4PGS4Bbfpq9Sxvd9TNPsvKeNwoYTHCyYgfB90jTlBqX4rA4JtOKZlqZ6hUSntaaaKP7fbJ0/OjXL83ONZcOoDdxiC36uJLinbNNfLuH7flfPl74fG1JwQKdIsy26G5XiMzqiruG5QFO7zKJLtGY8zKas/s/4HM/NNZb1HrGBm2zBZzzBx32TQf+c37YRxQYbWHBAZ9pLKYXWmls1KGKUVhwINfOXQXQ6byR9pBnxzek6//fsHK83wmUVLI6A/Zbg877gQd9ka8mjXC5viOmr92NDC669rNB1s50CtdbcphsYxBgCDoSa2XXK62idtVydjBJ+XAt4erLGN6ZrnI2Xh8eegJsswWMlwQO+yVbfpVKp4HnehhYbbHDBwTl/ri06gFtp4IiYsoDvBlkN3Wp1p9EEqWYmTnmzGfL8bIOvT9d5rREQrNAEuiIyn+0LvuAe32Q0t2ye52Ga5oYdSttseMHByqLbR4MBmdAjNd8IFOPJRTfVBDIfbTZJaaSKd1oRz801+O50ncPNkPkV1pIKoE/Ax1zBY77gNs9kwPc6lm2jBglL2RSCg5VFZ9TrfFmkDBmSv2goTiawfPetlZlOEp6aqPJ6I+Sl+RYngnjZOoQ2EuiR8ClP8E9Lgp22Qe8mFBtsIsHB4hxd27+TtRqPi4i9puR/1zUvRvqiGh3+fbXV6RX3fphkjWd+uSL5hKPptS3KpdKiYXQj+2xL2VSCa2MYBp7nIaXMjlqNO0TITlPwdAu+1lQcS/Syec6FXEiT7Xq2+1zJL5bgGgPKrkNPpYLv+51odLOx6QSX7XevOymTdusIq17HarX4oki5zZJ8vaU5ECrG00sPKMp5YPAzvuQuW9NvSipelmMrlUpYltUR22aybrAJBQeLRddOsrYTxVajyc0iYtjQ3O1KfhDAC6HmTHrh3fx6RNaK4QFXcKct2GHCgGPj52JbGoluNrHBOhRgdivth92uo+sIzrKwm03KQcBInLDX0NznCl6NBD+JNO/GixPGtoBthuBmW3C7DXtN2GkKhiwD33XxPA/P8xZV7G5GobVZs4XbCLHVwgSxYRhYloXjODhBQE8UsT1O2Gdp7nHgVCp4N4HTiaZHCnaasMuAXaZgzBT0mBLXtnFzsTmOg2mam3YIXcqmHFJXom157Lznmp2LJggC3DCkEkVsSxKCVDGdamZUVk08ZGR7cbmmgd0WquPg5oWThVVbzBq3IL86Kn7Xk066pB1M5CKKoogwDPHimJ40ZZfWCOhYRNu2cZysDUM7KCiEtpzCwq1AWygLW4M5joPneSRJQhzHKKU6eT3btjvWrBDa+1MI7n1YKLz2MKuU6hxtQbaP9u8UnJ9CcBfBwoi2Laz2Ts6FwC6NQnCrpBDa6tgIWY2CLmJNgjOlsT79qgq6gtyXXdPzXp3gXn9WA7TqoRKamNXXLxZ0CUopHUVREgRBCvD66XdXVaC/OsHtz6YVD//gx/M6SWeUUpEQor0fWcEGQwih0zSNG43G3IvGYYgIAAADRUlEQVQvvjgHwJHKFRTcE8BeeOH7L0VhGE5orRv6PMWHBd2NEEIrpQjDMKzVapMvvfRSg927Bc8+u6pRbbU+nGZ4u6Ra1ceOHXsjCIKJQnAbD53vQxZFEXNzc3OnT58+XK/XkztvHly177/6oGHSVYB+6qmn/nFycvKNKIqCXHSFP7cB0NkmxkprTb1ej8fHx986cODADwA9/eq0YpXu0+pLTmdmZH9/v/X888/H9913n1+pVK61LGskL5nWWmtR5Kq6k7bYABqNhjh58uSxn/zkJ0/97u/+7nPlcjkcHx8PWaVhWUuNsyyXy2aapqYQojk2NlZ2HGeLZVl9+eS3zgOJgi6iHfxprWk0GuL06dMThw8f/vbXv/71rx05cmTCsqyo1WrFXHELBzSbTeG6rvnqq69GruvO+L6fWpY1aBhGWQhhLJhjLExdF7AgQGBubi4+fvz4iUOHDn3nm9/85lNPPvnkEcMwgmq1GpBtYbEqC7cWIQiyqTHX9/1Kmqal+++/f+yzn/3sx2+66aaHR0dH9w4MDPS5ruuYpmlKuXSP7YKrBa21AFSapkmr1YpmZ2fnTp48efT111///rPPPnvgmWeeOWoYRr3ZbNaBgGwJ76os3FpFYJBtcud5nldRSnmmaboPPfTQtkceeeTeHTt23FCpVIYqlUqPbdvWam+y4LIjkiRJ5jOmTpw48dZzzz33o29961vH4jgOpJStIAhqQAuIYFW7hWYXWuuNkonOIROdb5qmV6vVTMuyTMuyzJGRkfINN9zQ6ziOkSRJYeWuQgzDIEmS9NChQ9WJiYlGnJHYtp1IKYMgCBpAk0xsCWswHOshAMk50TmA5ziOZ5Usu16PJFEEliWBVW0XXnBliAHiWGHblMu2ihtxHIZhi8yqBZwT25rSXutlcdqis8janjn5VwvHsbC0BKRt2YWFu0qJ4iglFilhmJDpL1pwxKyD2GB9o0eZHybnxNf+Xi65ViG8qwO95HtF5p+lnBNZ+//XJaG/3g9e5IdccrR/fjmuWbA29IKv7aMtMLXgZ+vC5Xr4gpVFVojt6mWhsDTrLLQ2V0oAhdC6gyJtVVBQUFBQUFBQUFBQUFBQUFBQUFBQcGn8f+ceLfTMtoldAAAAAElFTkSuQmCC\nsys_ro.build.date.utc=1469090187\nsys_ro.serialno=abcdef12\napp_apk_location=internal\napp_apk_codec=BZIP2\nsys_ro.product.model=Some device\napp_version_name=1.50.48.1\napp_is_forward_locked=0\n"
  },
  {
    "path": "app/src/test/resources/TitaniumBackup/org.billthefarmer.editor-20210529-164210.properties",
    "content": "#Titanium Backup\n#Sat May 29 19:42:11 GMT+03:00 2021\napp_apk_md5=71ecafd32cda1d2975f8aa3cbacdc540\nhas_dbdata=0\nsys_ro.build.version.release=6.0.1\nhas_prefsdata=0\napp_is_system=0\napp_version_code=155\nhas_prefsdata_jpu=0\nsys_ro.build.description=Some description\ngeneration=1\napp_gui_label=\\u0420\\u0435\\u0434\\u0430\\u043a\\u0442\\u043e\\u0440 1.55\napp_label=\\u0420\\u0435\\u0434\\u0430\\u043a\\u0442\\u043e\\u0440\napp_gui_icon=iVBORw0KGgoAAAANSUhEUgAAAJwAAACcCAYAAACKuMJNAAAABHNCSVQICAgIfAhkiAAAIABJREFUeJztvXuwHNd93/n5nX7MzH3fC4AA8SAIkCBIgA+Roh6U9ZYsO4oiO2v5EW8ltlzraOO4vN711taut1LF/cOuzW5Sm9iV2NqXta6kSk7FSTaJLEVeWSYtUSRFkYRIkCABkiAIgAQuHvc1d2a6+5zf/tE9Mz2Pe3Fn5g5wQc23qm9Pnz59+vW9v/N7ndMwwggjjDDCCCOMMMIII4wwwggjjDDCCCOMMMK7CnIjTqqqcqPO/SMEFRG90RfRjqG/dFUNgElgHCgBQRzHhSAIzLDP/SMOF0VREoZhDagC5Wyp3kgiDo1wGdHGgVuBTzrnHhGR+4DdQHGY5x4BAAUs8Dbwsqo+bYz5HvAisAzEN4J4Q3npqjoNfFJVfw34qIiEwzjPCD2jpqrHVfUrxpivisj89b6ATSVcJtU+YFV/U+AzIlIE/M0+zwh9QwGrqlWF457IPwb+VETc9bqATSOCqk4Bf1PhvwIOk+prI6JtTSgQA2fVuf9ojPkfRGT1epx4UwihqjPOuS+KmL+DcDdKcTPaHWHoSICLqu7fLi8v/4Pp6emFYet1AxNOVcPYuS96Yv4ecAQIBr+sEa4XBBxwRdX9c2PM/yYiC8M832a4Jj5lRH4euJsR2W46KBiF7Yj8srX2M6o6M8zzDUQ4Vd1trftZQR4ECpt0TSPcEMg+MF8C7lRVb1hnGYhw1vIxMeZ9wPQmXc8INw4iRh5xzn0EmBvWSfx+D7ysOoXlc8B+HVmj7xaUEPl8HMdPAEPx0fUt4abgqIoeUZjYzAsa4QZDecgEwUFVHYqnoW8JZ+BjiMw5HUm3dxMEJtVxtFKrfAd4a7Pb74twqiqqvN8O2aIZ4fpDQUS41/f9XQyBcP12qYF1upeRZfquhDrdIyJTw2i7b8JhmGSALnmErQsVnRGR0jDa7pcwxjkNRGRg/W2kAA4Hg8SnDOKDDiVfsW8JNQhRqonjhfkyL86vslBNsE5Rmg9Jsx/a8ltby7OKjQerzfraLMrKtbnd1m5zLy1tNVet593SUBCB/dNFPn9ojl3jAYHXO28cKsYbju/3uneJtcTxtVNX+O7ZJeZXE2KnDTI1CdN8yU5bX3yeVKo5orYfT46sWYV63Xw7DcKtQdR2Qm9lqIJF8WWJx95c5L9+/24e2jVBwd86ydV9E04B6eMlvHCxzPffXuGtpQibk1AN8rSTqRuR6tt16VWvw/plrRKz3kZG53bpmRV2k7xbFUr6D7psLfOrMX/6ymV2jAXcMTsUdawvDCTh+nn+xy+tMr8aIwK+SPZCFVS6EIyOrrKblOqUWl2IhbRIUtrabOlGG+VSv7qbQsJBek+eMVRixw/eWeHiaszBmRKDa9ubg4G71F5egpDqbwqYjGxkZMvebbZWpEHG/Jmk9admSku2XW+isbv9SrPz1A9FFEGaBGw7LqWopJJctr6Bo6SPw3cQeELsFOua+zaKYd7nde3cFdg3VWAiTE8ruWUzsV57Gz3XVidXNzSepwgG4eB0kamCt6VuZiAdLr/eKO6/ZZwzSxHVeIWlyLZJsbXP0+u1rXXctdrr9762ApqSGfZPF/jJg7Psngz7updkE68rj8Gt1B7v5taJAh/fP81YYDizVKNmXWqJtivtWYFrlLcaAvUqDUuyXfdrq0e7/tY4prslmu/Kt7qx0AKBCd/jkb2TfPy2aWaLfs/vaJjqw2BGQ5+K9J2zJW6fLrJQTSjHFuvyr/fa52zZXuN394O76HXXOE47fmxt+EbYNREwEXpIRpteL32YPfDAXWrfJzbC9rGA7aOs9B8pbB2P4Ag/EhgRboQODFN76F+Hc6lyeZOoNiP0gGGOwx9MhxuxbYQeMXBoa8S5EXrBgH64/ulWTRwLtYRy5LBdHV3a2rq2rFrK28v6cXPczP84+d7GM7BzPGCm6ONtlQBqDgN0qZoFxHvHq1dWeercSs7xm3PqNpy7bUHznJO2Pfje4hDukuFRby9/Dhrrpi9ufQfwFialtmbCjIceP7Z3kh+/fYYdYwG9Ru63pB9ujQj5NfH2SsS331zk6fMrLNaSjghDMx+uM6ctn2LUWK+R1kS+bK1ybcrR7lGI9Efr9tZE/R6dQmyVV66sYoDPHJxlrrh1fJ19E85BXy/h+KUyJy5XqCSOgmeaL7WFBNIluVJRlRyBOkkIXQjIOsTqkXC51ZZEPf0qMsqZxRrffGOB+3aMM9sH4ewQrg9uQMbvm4s1KrHDN/WwS0okJHvpkpFGcvlx+X3pQek+ybr1bB+QkVK7EC47rlGveTzQQUSkTjXJbW9xqGRxUMWp8tpClYVa79Spd17DwHW1UgUo+gbfdN5Qezvr3bDWK6xx8rWO7aYF5NPwrnXM1lPB21APups0dDgRePimPz17WBg40tDo2ja43L2txC3jId6Wf3s3L1Sh4Bke3DXBtrGgUbaRBc3UpSHhunapChzdPs75lYjYKleqCYlzrd1km/LfNCq6d5MNYyB3fL0zzNclXzd/fDcdrUWf07501RsJX4Q9kwV+6tAceybCntKrhi3JB4o09NqlAvie4TMHZtk3VeTEpVUWaknDD9fystuU+HYiNQmy9gitXLWuYx2aLdBKuFy91rpbH56kWdU/eXCW2WKA6bFLHXbHc0NGznvGcO+Oce7bMX4TKEY3IQaQyMoW7FIvkU4qMuh/fl6yjPCjgf671BadaYR3E6QfXWmDGOXDjdCBYcqQ6240jLC1MWyVeiThRmjBsAXIJuhw/V2iNP6MMAz0q1sP+70MnA/Xz31VE8u55YgL5agx9UOH30tb227xq7X7zPIbtDqC24+n41ytd6AdP24OtaH+zESEqYLH0e1jbC8F+F2m61JVYuuoJkqiAIIvynhg8IxghphHd939cJF1HLtY5nvnlnj9ao2V2HbPh1PXGVXI/U7ra4e1nM8yaZfCneVpaYuDud52jpU3gzWev8+5ks9H903zuTvnODBTbJkjLrbKcmRZjJRyDDUVnEIoymzBsa1omAhlaKHH62o0CPDWUpVvnV7g5JVKy6j6jmTKDpLl0o60tRw6y7qSM99+W932yEZewnaLPmxFuCwf7q2liK+8cBEj8PNHdrBrIp2K2TpYjJRzZVhMfJx42IxwTpWLtZg9FvYBk0NKoRt45H2vjHv+QplLlTiXnkSankQbCTqI18yRa5KymXXcQdj8sfkuuJu0bP8NpHlM3UJpWxf1VC3fKKux5dtnlvjwvml2TRSwDpYTuBT7rKrgGZo3kyluzoScq4IaDUox419+RoMvPSzxZl7jYAmY9Mg3heUondqhrido+0vNcoHy03U1yNUxhVfuIjpn/Grkz3W03/jdnK4rn7bUnv9Wn64Ltrado9B4DgXPUIktkU2n7FqO4XJkKCfrd5dO4dyqbFN1HwymzbEvP6MnN5N0g33crY9ltuhT6GPe2RGujZbpuoywrRRQ8AyrCSzEhooVPNIAvydg6mua2yZNdi0o5lc8db9cmOa2Rx/dvAmm+26on67FAQ/fOsnO8XBLS4p3A0Tgxw/MsGO8wFJiiFwq2YxpEq5BOtNJOoEJI/Lrgvvt/b/EbZt1XQNLuF6xczzkpw5t46FdExR902oc5NpcU0p2MyrarmetY9v3beSYDV3TVlk07RLnij6//tBuPn1gG2EQYhV8aS4dpCO3pkk6I1I0yBe8xP2DPz6vm0K6vgTNvOokFfucUw447Z20VpVaYqkmSuzWGpfaivWqaNvGRv4RtP1I7bb/5oNvhIJncHGMXxjDikeigtXUSrUKSba4bLu+uPyaxgzyTmFBlf+gCf/T37lb3hjo+jbpPnuCJ8JY4DPm61BzrwbBzUo4Azz+3Sf4xrcf47Of+zyH7roHzw+bO13z3pJsuysyw8kpRpUZ4CfwqfzfL+jv/sp90vc3uG5s8F5ky+pyW/W61oQqcZLwV089zR/+0Vd4/cxZ5heX+MVf+Fscueconp99Fq2NZBshHWCccouiP+2Nifujl/V//eI9crqfyxzNLfIuQblS5QfHfsgf/tFXOP7Kq1gRfvDCCxCE/PzfVO49eu/ApEPlFlX9GXwt/fFr+ujfPshbItITBQYbeT9i3A2HAqux5fkLS/z7U5c4/uY5rAgYj0oU8/1jxxA/wAH3HTmKH2Tf3c1IVpfkG5Z0yA6j/Iwq8f9ziv/lX6me/jmRDQ9+3YRZzEeMu5FYjS0vXSrzF+dWeLOwndn3f4qrx75LUimjIlSimKeeP0ZQKOKA93SRdL3odChGRSYd/KKoW1o9Zf7wy8/omY06hwfsUkdku5FYjS3HL63w56evcnwpxpvdwfZP/BTW91n44few5RUcUK7WeOzp71OJYkQMDxw52mFI1LEhQwJElAlEfs3gksK0+RdffkZf3QjpBp9UeoNuiHZUE0s5dsT1cant7XcpXO88quvXutY1duzf4v9Lqsr55RqPnV3gxYUaFAq4oIB6PlMf/2lqCPblZ7FLCzh1lKs1nnj+GLEqxvO4//DdA5EuhYyp8usehOF49JVHj+srjx6VaL3r7tsPZ1fscxY94BTT67u5XIk5eaXCmaUqy5Ft+05DZ1YH0DGIec2yuoetsd36u3PdrN/5T9Ta1laBCBhRFmoJZ6sWLRRxYUji+cRiiBVqlVUWvvsNyi8+SbJ0FZclOoSFIu+7715+9ed+hqOH7sJ4QdMX14efLn13WlH0y4j5vyoLvLKepLvuc4uUY8u3Tl/le2eXWIpSXbMlh83VSdI+Sr7b1wVzx+ZI0hmN6JI3l/1p/0Jhc19belKfknyzIUDowXjRUCqF0EE2IVYlDksEH/gJPKfEx59GVxZwqqlO9+JxYuf4zb/9ixw+cBDPZDToRdLl4JASyq8iuNJ2/s8vP6On1iLdpnynYaMvQoAX5sucuLRKZB0l33SQBq87kdZOrJSWMFeDRLmyRt5cR701JGqevC3bNx6BUYqhwS8EaTcahljPJxFDohCrEjkldkoSFDEP/zjGOuzxJ9FKGRDiJOHYKyf5vX/5Vf7Hv/sr7N21O5u0UDZuSLR0reCQcXX6JbXqvGL8ZeA1ujy2wSez6bH+a1cqlGNL4KXpzJ4hW6eLMZIFlKVl8dt++21l7XWutRgjaUwxd5zf9rvb+kYuBQ9KoSEo1CVbAev5RGKIVIgUIgeRUyKbEs+GRXj4x5GjjyCliey+DVGS8OyJV/itf/RPuLJwBYM246smjbl6a8Ve1wr4i4wL/D0VfuPv/5un5rq9/8EIp70tqs2Lq0Ny6/zSXkbb72uhvT1ZY99ax7LO/huBQJRCIHiFEC02JVtdZ6tLtsg5IptKuNi5TNIVkPd8jODhT+FPTIEYQEgSxxvnL/D3/+d/zNl33kbUdpCu14C/Z8xY4JuP33vnPX+j230MlJ7Uz3LHbImpQtqTr/diB3nZ6x3bvq/9Grpd01r/FNdryZONYmqNJg3JRmokuDrhmmRLnJI4xRNDaWKKsXs/SPC+T2PGJhEREME6x2tvneO3f/8Pef3sGdTGLaSrS7k1JV19TV3KIZ6YA2HgP/jxR7/dobJd9++lHt42zt3bxpkseB1k3MzzrNXetc6jbesbDV+UQmgwhTBzfYQknkeSGQhpN6rENrdkZLOaZlYXfEPge5ixcYI77id4z0eQsYnGOaxznDxzhn/6L/+E46dO4ZKog3Trdq9tpPOMCX3xJh6cKnSMjLjusdR0hu1pdk+EnFuuUY6zWcxpc2V0cW809jXKmoZAXunvNqdbh2HQ2G7W0o5jNL/Rch3DhlN4fWGVpThBCiEUQlzQNBAa1uh6ks0IJc/gG8k+nG0wkzMEhx8C45E8/ziuUgZVoijmmRdfBqd88af/BvfedVfffjrFqagmJ/yFjloDjWmoj6DqFdtKAeOBx4GZEpFzdHmvHQXdTrNWpEMbf9bYtwbW3HcdxZ2SOsVPXC5zarGMKYZooYALAqxJdbYoI1udaHmdrU423whF3xAaaYzbSGepyUh313tAHcmx7+BWl0GhWqvx/eMv4Rn4z//6Z3ngnrv7CvgLumCT+O2vX3m6wzVyQ/LhFCj4hoI/GtvQjtXY8uJ8leNXylSMl5EtJDFpN5pao5lks90lm2+EscAjzI2MS3M6pEm6iWmCww8hxiN69tvo6gqg1GpVnjz2ApB2tQ8eOYIftJJuvYC/ojXUPZsk1b/k0Uc3T8KBIx2it1W0nZsfldhy4vIqf3l2kVeXYygWU8nmeSR0dqP133mdzTPCuO9R8FKTI5X2ms5u3oV0/j0P46qrJC8+iVZWUFVWqzW+9/wPCX0fVHno6FG84NoBfxFiZ90PBPevz7298Gy3exwsPWkreURvYihQybrRv3hrgZeXIigUsUGI9TxiPGKFSFv1taiLgTAZeBSznqOhWoisTbriOOF7PwE2IX75GWx5Eecc5dUKf/nk96lVq3gGHjhy77o6nToihWdD3/uy872vPfrZQ0vd7nVTutQR5wZDJbacuJKS7fhiBIVCRjafGCEi52fr0o06VXwRxgOP8cDLGVaaG6y7FukEUyjhP/xparHFnXwOlq6AOlarqzz53HOIs3jGcN/dR7qTTkhAnxeV3/cj/uyzB2RhrXsdLMW83eoboWdUYssrV8p8+60FXsrI5oJCKtkyP1tDonWxRutkmwxTstW/EJQSLWPbNUjnVKn5Bex7P52WvfJ9WLqCqFKtVnny2eewSczf/Vu/wD133Y3nZd4OA6LEOH3ZGPkn1ZA/+8QeWVzvfvsj3CXQwuBkawnQd+wcoOGbBDXrOH6pzOPnFnl5KU6zPjI/W51scb4L7UY2Y5gKPSYCL43kAE50Q6Qjm4ukkihVq1AoIe/9JCIKLz+NLF1GnCOqVXn2hz/kf7cJv/ZLv8Rddx7CMwGgVpSXMPI76vGfPjInXbvRPPpy6M/P62QljJ9LlAPW9ZaeJJJOnJI4JbKO2Kb6x0YJ1+FbWwfa8WP9c3RW0w2dpx8I8OZyhb98a5FTKxnZwoDE5FKM8kTLutIkC1fZTLLNFHwmQq8jHcvRnjXTmQxhnbJqHeXYNa7JCHhxFZ76OvrCE8jqEqIOo0oh8HjPPffw27/5m7p7z22aON4Wkf/Ct3zn6C2ystH77hl1wsWOA7bHcalG4PRilW+8fpkfXihTSVzHw6g7giHNyYK632+NDJKc7dIxGU57WdtLoOW47Hf2Z63cvM3AmA/bJwJK48WGny1p+Nkyyabp9Gbd/GyhJ8wWfCZCv+X+6td/LdJZp6zEjnLSHI7gSTqu1RfBi1ZxT30D+/zjUE5JJ+ooGMP+vXvcP/qd313cfsv2L/jbit85KusnXeYxEOGiHgknwMXViD89Mc/JK6tZUuAa5OkgV/2ld3mIbQ+6++xLaY1uqUxAIw8Pcuv8/vyOARH6MFHwCUpFKIY4P2jks+W70bWcukXPMFPwmQy9rvecv3bXhXCJU1Ziy0rcNDV9aWbOBEYIBPxameTYd6h852vo8lVELTiXeE7fPnL4ni8+/NEHvvP7v/EbtV7u/boSzgh88/UrPHlusZl8CQ1yoZkky5Wt3y2kB7VKs7Y6Wbt5spIv1+5SrIOQ5HYOAN+DYsEjKBZykq1VZ2t0pV3IVvINc8WA8cAg0JVQjXvsQrrYOVZix0psUZrdqJ8nW31B8cpL1I79FSuP/3vs0tVErT0O7r8v165+m1OneiIbbMqord6wWEtIVLMUJWlMw1WfEstAo6yOVN/N5oLL6qVrpf7pyzzq+nHj4UudbNL6+UoUOs7T3E/985jpz8ax/cI3UCyYNMUoDFvIFitthkGnU7dOtonAq89ylCr4deY05hTTbF9aVq+TqFLOutH6IV5dsgkEddJJKuEChGBsnMLhh/Arq8niE994MVle+J0VWf1OP2SDQbJFNHspPSwKTIQeoTGkEb70oWTca0E+PadjR7d1o760pvd0aTe/Ibmlvg3NbXLXJwMsgZeSzS8W0hSjMGyRbLVcF1pf2rvRbcWAqeyTlPV7M0jjGTbOl5WRq1PvRstJOoakYSA0JFsa5A9FCAwEQKAW3znC0kQ8efihZ8fuuO8frkR8k+PHN2QgdMPA03X1wjnn4PDcODvGgpYkzHc7fAOFgsEvFdLkySBs0dnykYNusdGxwLCjFDAV5sm2BunoJF3kHMuxpRxbbI5sdQMhMELgCaFpki1Ui28TTFSLjXXP+ONTv3frx37h65x66pquj3WfxSAH99qdKrB7MuT9e6Yp+h7nV2pUk1x6Enn9LCvLbbcQuN4lavtxaUv5smbb3Ud55XW41n1ZjZbtHu5XweHwg1SyaZjT2ZBrOnVTsnnsLNW7UUkj2PULkXq/CkYFFW3Mm1zvYiPnWI4sK+uRLWcoBEDgLJ5LMFEUSxI/g7N/QMLXfvClh9d16m4E112H843h8NwY44HHhZWIqnXkZxlvrNvLtMs580p9F1J0LevYr2uUt6I3o0GpJI4zS1XeWKliwgDayFbX2fJ+tjjzs9V1tqJnuKUUMF3wUwMBkIxY3UiX6mvNG4gbZHOdZMt0Nd/L62xKoC6VbHEcSZI8o4n+8epq8vVXv/TwmuGqXjBA8L6uxPdGOSVVTg/OFDk4U2Trzp/UPyqJ5eTVVa7ECSYOISxgg6ARG40zyRa5VqduPoJQ9Ay7xgrMFT3qWR9GFZcRay3SpSFOIbKOxciyFCUk3ciWNxBMSrZQHZ5N8OPEEkXPOrV/UHO1r7/6pQ9c3qxnM+As5r3Kt+w48lKkvza2KiqJ5eRChb86t8TLy3EWiE+TJ6OsG13Pz6aqlHyPXWMB20tBw1eZmpVybdIBiXMs1JLMI9BdsgUtZCOVbElCYGN2h7LihcFXT19J/uOJL35gUyRbHQPPYg7vNsr0D+csl1eWeeHiIq+UJfWz+X6Lzha7zqyPpI1st46HbC+mMx4ZkVTHzcVC1yKdkjp1r1QTrtaSFmu0w88mTZ0tVIuXxPhxzP6i4a/dNr1wx2zpjU/eNrWpZINNSE8aka2JWqUMi68xFy8yXbqTSxISY1rI1hIfbZFsMOZ77J4I2V4KmoF43RjpyOLTlyoxl6vJ+k7djGwhiq+uQba9IXz+wCwP7pxgsnP8y6ZgcCtVR6RLodRWLlNcOc3D3mU08Pl6coSyq2fpsq5Tt062W8bChtMZTQlzbdKlc4FcqSXMVxOgizUqzXVdsvlq8a3Fi2JmjeXnDu3knrkxxoaY+j/Q1wRHZGvCOSW+egp7+QSTY/BwGKOe5U/0PdQsTUOhS7hqzPfYN1Fg51iYRT9IowaZxXkt0kVOmV+NeafSHLOypoGQt0aTBBNHTGnCl47u4dBciYIxadsbnmKwN/RFuMv9HphDtyjAzYzVlat4tYsEuozGIWOyxMNyEht4fCW+Nxc9aCXbdOixd6LAjlLY0l69S6yTq55g2/7Iala5sBpzIUe2ZtYHqWQzmVOXlGy+WrwkwY8jZsTypfv2cGi2hJ996WeYuCGTSlt1vHalwqmrFZYy5bYjFSjndGueq5tvTlskbVe/na61r3n1HT67nI+v5dg17mn/ygs8YF/nliAB52PUMS1VPuS/RTjl80+vHiJ2tJKt4HH7ZJG5YtCM42YJk0Zy25lVYBRcZo2KQCVxXKxEXKzG19DZaCGbnyQEScS+gvCzd+7i0FwJrxHf29CESX3jug8TtOr47luLPH9hmavVpKEw5x249dw3oDl9V31pSWmCeiQgX5Zvq4XEuTLNKqxH0HpL19JVxcbcom9SKC0ggWDE4Bkf3/OZCxwf8i9TNWP8/oVdVF36nYrp0Gf/ZIG5YoAn0vjHacnSJbedkU40DWtVEst8ZiCsZY029bcuZAuFzx+Y4665MQLT1Nn6FSIbxcBfE+zFFWdIZ0966VKZi+W46WMiR6SGhFsnPSl37vZpuNYry0vOZhtNcjbKczeY317rXrdVzrOrMM+El+BJEc8E+H4xW0IKgeMni1epSsj/8fYMzgTcNlFgWylodGOuTqoW0mVXlCOdIZ1j78JqzMVKTOS0a7jKzyRbWCebs/g2Johjbi8ZfmLfDPdum6DoeS33JQ39cOPvtRdcV7eICLyxUGWhmtQ/rdPsKrX1M5Qd0qmla+2s1xpL7UKsbAxtuyTLSzBoO2cjMapZ1vkAlDv0HLvMIqExeF6AHxTxgyJBUMDzQ4wfsM13/PS2JcT4PBftIPECfDENSZsaBm2kA1rHJAirSUq2+W5kq4erjKREEyHA4TuHn8QESczBkuHT+2a4f8ckxWyEV9vtDBUD63C9HhNlOeOmoaAqTYuMhmWW/3xl82hp/VlP+sq26000drefPTtPI9yY+3wlXY5LKdrM1ev2Tx/UFjkcXGCHX8WYEr4XEvgFAj/E80I84yPGQ4xhp2f5z3assK9W4Htln0tJmJ1UupMOWrrYcmJ5ezVivhJT60a2vM7WIFvajYZJxMExn0/umeb+HROMBd6672lY2BSHi/aw3DIeUgrS00pu2Uys195Gz7XRetvjt9njLTIeKJ7n4/khnh/gmQBPPIykuX8mixrv8GM+UFrgfWOLbPPjXC6bNAhUTy3K57lVE9eQbN3Ilve3tUq2VGc7OObz4V2T3LdjgrHAX/cdDRODW6k9XKED7pwZ48JKRJSUKcfumjfZzwNYr81rtadt63VhY+7mDHOyjGcMvufhez6+8fGMwdRz1hRElXSOBMd2r8aPjV8BEZ4uT3M5CbpLOtKDK7Hl7XLEO6sRNbt2N9r0s7k0xShJCOKIg2Men9idSraJwF//5obsqupfh2sMPtg4KVRhrhTw0K4pir7hnZWI2LlGDlddV3L1yuRM9A7rtP57jTEJbXWg8x8kb0w0ynJt1UvyOl4e8dUr3BeeZ8av4MkEnmdSomUzFomCOEWMIurSDFRxoJKSbuwKAM+Up5jv1r0CldhxdiXi7XK0ZjfayNQVTSMIzuJn4arbS4b4hdPJAAANNklEQVRP7Z3JulH/2v9wW1WHg/oL7u0KrcLuiZBd47OsxJZK3CRca8ud71jbflxTMrYdsJkKsqJcPvY0ty2VCUUxXnPeYJOZKOnQOkWcS+ekF4dgqSsS270qHx67QkEcf7Uy2yLpVJUocby1XOOt5VqazybrZH2gBAqBJllsNGJvaPjMvtmsG/Wu8cTyGJ6YuyFzi1gAESZCn4nwWrW3JqLqKsWV5yi6ZbxsUIsRRXDporax4CSd4tQ2X2T91zavygfHrgLw7eU5Fq2P03SQ+OnlGm8u19IIQzvZTBvZSF0fdbLtCYXPHZjj6PYJSl2s0RuFwd0iA0mJmxfz595ghgVCYzHGTyWbKAaLkJDO7+KBMynZHLRLjvrWjKnxwbGrOIVvLm/nagRnlmu8vlRt1OvoRiVPtqwbtQkmipg1li8cupVDc2MUPa+nB60y3PdyXcc0vJvwb7/6VfbGZ/jY0Um2F9O5b0UUEQcuARcj4oEYmkPAko52UqeMx4xU+dDYJaLE8nuXp3l1sdqo05H1kTcQGt1ohBfHlGzEF+/b1xFB6AlDfLGjbJEeoarUKqsce+YpHrv4Niuru/jcIwVuLWXSTZNsiTMJV3fgraUXZQ9SDFM4PjQ2z6VtFX53eYaqzQXiWwyEesaH4ttMZ0siZsXxxffs49DsWBYu6+f+hms4jCRcj0iSmMe/+WcsXJonsfDnzy0SFkp89pESe4sO0QRIQGNwmXRz3byNmcmlWZdnHCLCLDGfnYoo7q/x6JmdWBV8Q0eWboDDt3VrNGJ3IPzs4bQb9SXTGbcg+nb8btVv1Q8VqsS1Gk8+9i2stXi+R2yF750o8/iLS1xcjIB6l5qSTlwELgIX55YEnEWtBWtRm6RLkmBcxCyrfGxsnt/aeY65QAmM6TKyyuLFKdn2FQyfv2M7d82m3eggZKsLkSGlw92YT5AbsjkuIkslcbg2v8j6TttmP961XpdufiPXuO4x2YaNa1w8fZJXX3geEcH3A3w/YLkKT7y0QqFQ5CMPBOzbGYAmbRKufnGam7Eg679UUJcF8XGITZixMX+tuIybrvGvywdYsQEemkYPXEo2E9WY8eDwzDgl3+PccoQR2F4KmCg0R3v1gs6Q4OZicLdIj1dnBM4uVXnxUpl3VmpEVlum56qnJ9U9fPlgfD4frlnemdHR7rztlmvX3O700XXkz2V/XHmR1R/8BZXyCkGYhbCClHSLq/DkiTJqQj7h+ey9xaQmXyNrMruKRsBX0cwZrCbtctOJZxKcTXBxjcmkyqe9ZbRo+VZtP5eTAp5N8OIIiSJsLeYKwrPvrPDypUrjvkq+4cGdEzyyd5rpHscmNJJUOu2bTcFARkM+82IjEOBKNebZC8u8OL/CSmQ70oIa3n/tTrg8YerpRa1lnTlua5bnCddCUHKEzWpYh5s/S/T04/ien2aF+D6+7+Nly9Wy8oOTZXzf5+MPeNy6XdB09DIN6WY0izZYVH0UD0RwgFOHdTFJEmHjKklcZVITPiFVwjDmMbuP+diHWhWJE7BQcXBmsda4R6cQWeWNxQrGCI/smWYyvHaEofGOUjE7tG8UXdcEzDQ9qcKbixUiqxQ803ypLSSQVsnVIKHkCNRJQuhCQNYhVg+E06RGfPUc9so5vIxoQRCksVPPS8NanmGx7Hj21CqF0OPD98KOmSL1GGo6q1EacVAsiEUljUs4VayzWBuRJDWSuIpNaji1TJuIDwXgQnhidTvzicE5MMZQyE3SUk+/8o3yzkrEE2cXOTRbYjK8IZ/j6Irrmg9ngHey+UT87EHViYQ01Bnq03U1yJLfl51UIZ2ui+YUXkBGym5ZwNlxjXrN44EOIiJ1qqXkt5VF3OljGJFUsgV+U8J5Pp7nYYyHMYYrywlPHF/CWcdH75ti23QhNRLEgvggMYqPio+qwaFY57A2IU4i4qRGktRwNk7TojyfCb3MfRJwBo8F5ojF6xwUkk1HJqRqyltLNZbz8/Bt8H1uSR2unwtTIMy+/RRZ7diXx3p2ltYrrHEB63m82g+7VoKrQkqWhYu40y82SOZ7Qda1+piMbJJ9FlKdcmkx4rEfLuBskpJuKsThgXgoBlUPh4fTTLpZS2ITkiQisTHWJaDKqjMsSpF5pjhviywngoHulmjd5WdS3914kH6Tttf3tLXHNPSgxzmB/dMlzi3XqCa1LkH7rQmtrOAunkaiStqdenXJ5uH5XibdTJbokVrd1lmuLMV867mIalTj0++ZZnrMz8gmOBWsCs5JWt9arLMk1hI5Zdn6lKXE6do0rya7OCm3sezNoMa/5nA31fQf+57tE8wUgxaV45rImt6SbhHoTcpZB7fPlLhciUmcspzNhtnNglz3W/aN8txUWpqXup1182W0tUHu/NB8OUqqyEdL81RPPYcnkkk1D8+vS7Y07y09zmWKu8M5h7OWq8uWP3uqSlyr8akHJpksZjqbTRV86xTn0iyaWD0qUmQ+meCVaAcv617OFw6ghRAQiht8zp4IO8YDPrF/hh1jQU+Rg14NwV5xXbtUSCfPe9+tU+wcDzi9UM3mLdPmC28QpVOZb9/uNt8bNA0J2giWX7efp6NuthHVqpx/Y5HlS2/hZwTzfD8lmkkzeuvdqJJKtzrZnLM454iShH/33XnE1vj4vROUQrJ66T+hik8iBRb9W3ijcC+vBXdQLW1nm8C2Hp+vJ8LO8ZAP75thPEh9cVsJ1918Sd+jcNvUGLdPj23ZEEwdZ0+/xteW3uANl2D8MJVudclmTGZcODSbZkvVYa1tkM5ai00SnLP8yePz1KIaHzsywVRJSBxUzBzx3P14e3+Mue0HuLU0zocGvGZVxQ5TTA2Avgg3Y3Hznibag2rQjrS7YoAWhg91jvPnznLy+AsY8dIu1POyMQcm7T6tayRMqmpDqtkkScnWWBKSJOHffHeemCIPv/depg5/jOCWIxRLU4gXgBjiG6zYKuAZIvGGo8b1RbidO4kvXTZLqLOkX55+V2Lx6mVOv/oy8++cb+hqRjKykepqQhpNyOtuNifZbNa1qir7D93F0Yfez4Mf/jDbd+/BD8cQL4StFGwXUGRRnVavXbl39NulxmL0nBg5LNaFW1dG9Q8F5t85z5unXsVZi+/7qdsjGymszrXOkdcwFJqEU1WmZma548h93HXfA+w/dJipmTkmp2cIwrCNZFvjKaZRNj3vw0CTR6+FvggnIvrSpdozovpeYGoL94p9o1atcua1k5x+5eV0qJ8058+1Lh1tJto0M5zLSOgcQaHAvr23cfj+h9h74A527N7L7LZtlMYnMpI1nc1bDQZRgeOJsReG0X7fRoNnzGOecV+wqnudbjFTaBNw+cLbnH3jNVaWFhFjMqcuuPrIK9LBMXVL1w9CZnbsZO/BOzlw+Ai79t7Gjlv3MDk9gx8MZ3K/zUaayi7LRjk+NVucH8Y5+ibc9ln/h+cvRSeMyJ2CTryr8uNUOX3yBG+ePJEO+ZN66C2zRK1Nw3EIU7Oz7Ny7n/2HDrP7ttu5Zfc+dty6m0JprNncjbuTnuALeKLHxJjX9glbSodjm8jSS/PRtzzRB63hLufePVKuslrm3OnXuJwZC2Sj5tM5UBTfN+zYvZftu3az7+Cd7Dt4iD0H7mRqdg7PuzltKAF8I1Ux8p/GisGbNKer3lQM5IcLxoNv2JXoI9bILuvc9M3yn3wtnH/zdS6cPUMSx42u1PM8xianuGX3Xnbu2ceBu4+y745D7Lh1D4ViaetYmX3CN6hn+L4gf75/jItDO88gBx8ak7MnriZ/6uLkdid8MFFueovVJgmvv/QiF8+fTTN6w5DJmVl23Lqb3bcd4PADD3H74SPvCpLV4QkEnpwPffmD2AQnRWRYodTBIw12xvuGzEe3BcZsQ7krdhrczKRbvHqFSxfexvcD9t5xqCHNDj/wXma2bcfzm4/sZr5PSLtRz4gLPVks+uaPY+N/4/4ZuTrscw6MN67qzEpS+9XEyS9HVu9MVMOtaPJvBKeOH+PEc88QFArcefR+9t1xF2Fho2HzmwfZSH4benK5YPgPVW/1tx6emxv4W1rXPO9mNXTy8uWpiMkvRE7/2zjROxOn/s3oLllZXMALAgrFUmYwvPtgBPWM2MBwseiZ/7e0LfhvDogMxSptx6YSQlW9V5eTR+LI/Xc1634ytgQ285fcpALvXQWhoa/FgZEXC6H3Dw/P+H9yva9hU6Gq3htltldq9qOJc/+lU/djidWCzU8Oncs3G2E4qL/Y+sSGnkAgUjNGXhJP/0WJwr9anOPCwyLxug0N6bo2Faoq3ztLsVhcnSVmdzEIPxGpe684d4eKbEOkiKpRHfSj3iOsBcE4PGKByyKcFuWYUX3Kee7FRVde+P/+2fbyo4/KdffXD/2Fq2rw0jzbkrg27QemFFtCLxTf2GENRBsBQBW1qhaPqFgIVokqy4lbWTy6Y0cZGY5TdyO4YRJmJN2GC7mBpBphhBFGGGGEEUYYYYQRRhhhhBFGGGGEEUYY4UcI/z8GXvxAGAXu9gAAAABJRU5ErkJggg\\=\\=\nsys_ro.build.date.utc=1469090187\nsys_ro.serialno=abcdef12\napp_apk_location=internal\napp_apk_codec=BZIP2\nsys_ro.product.model=Some device\napp_version_name=1.55\napp_is_forward_locked=0\n"
  },
  {
    "path": "app/src/test/resources/backups/v4/AppManager/dnsfilter.android/0/checksums.txt",
    "content": "d7d98dc22da624e1bb36815b3c426d3555c23c53acd3e6585ab383de874c9f35\tcert_0\nfb24bc8ccf6a4bd76459bf59d1e91d8161b46d3c15654ec15552cea9408f0b5e\tsource.tar.gz.0\n619cd045ceafe404f8627b825b4f3de99e299be9052740266f46a4bce080e56f\tdata0.tar.gz.0\n619cd045ceafe404f8627b825b4f3de99e299be9052740266f46a4bce080e56f\tdata1.tar.gz.0\n7ee2b41276c954e60d44bfbe5184cc8db94b3984690709d792e71c809a82f0d5\tmisc.am.tsv\n37a8b643ab7e7630040bdf7ead8f32554a12bda7b2a3fee31183e7bd976d261c\tmeta_v2.am.json\n"
  },
  {
    "path": "app/src/test/resources/backups/v4/AppManager/dnsfilter.android/0/meta_v2.am.json",
    "content": "{\n    \"label\": \"personalDNSfilter\",\n    \"package_name\": \"dnsfilter.android\",\n    \"version_name\": \"1.50.58.1\",\n    \"version_code\": 1505801,\n    \"data_dirs\": [\n        \"\\/data\\/data\\/dnsfilter.android\",\n        \"\\/storage\\/emulated\\/0\\/Android\\/data\\/dnsfilter.android\"\n    ],\n    \"is_system\": false,\n    \"is_split_apk\": false,\n    \"split_configs\": [],\n    \"has_rules\": false,\n    \"backup_time\": 1757779627086,\n    \"checksum_algo\": \"SHA-256\",\n    \"crypto\": \"none\",\n    \"version\": 4,\n    \"apk_name\": \"base.apk\",\n    \"instruction_set\": \"arm64\",\n    \"flags\": 1110,\n    \"user_handle\": 0,\n    \"tar_type\": \"z\",\n    \"key_store\": false,\n    \"installer\": \"io.github.muntashirakon.AppManager\"\n}"
  },
  {
    "path": "app/src/test/resources/backups/v4/AppManager/dnsfilter.android/0/misc.am.tsv",
    "content": "dnsfilter.android\tandroid.permission.READ_EXTERNAL_STORAGE\tPERMISSION\tfalse\t2816\ndnsfilter.android\tandroid.permission.WRITE_EXTERNAL_STORAGE\tPERMISSION\tfalse\t2816\ndnsfilter.android\tandroid.permission.POST_NOTIFICATIONS\tPERMISSION\ttrue\t769\ndnsfilter.android\t0\tAPP_OP\t1\ndnsfilter.android\t1\tAPP_OP\t1\ndnsfilter.android\t4\tAPP_OP\t1\ndnsfilter.android\t5\tAPP_OP\t1\ndnsfilter.android\t6\tAPP_OP\t1\ndnsfilter.android\t7\tAPP_OP\t1\ndnsfilter.android\t8\tAPP_OP\t1\ndnsfilter.android\t9\tAPP_OP\t1\ndnsfilter.android\t13\tAPP_OP\t1\ndnsfilter.android\t14\tAPP_OP\t1\ndnsfilter.android\t16\tAPP_OP\t1\ndnsfilter.android\t18\tAPP_OP\t1\ndnsfilter.android\t19\tAPP_OP\t1\ndnsfilter.android\t20\tAPP_OP\t1\ndnsfilter.android\t26\tAPP_OP\t1\ndnsfilter.android\t27\tAPP_OP\t1\ndnsfilter.android\t51\tAPP_OP\t1\ndnsfilter.android\t52\tAPP_OP\t1\ndnsfilter.android\t53\tAPP_OP\t1\ndnsfilter.android\t54\tAPP_OP\t1\ndnsfilter.android\t56\tAPP_OP\t1\ndnsfilter.android\t57\tAPP_OP\t1\ndnsfilter.android\t59\tAPP_OP\t1\ndnsfilter.android\t60\tAPP_OP\t1\ndnsfilter.android\t62\tAPP_OP\t1\ndnsfilter.android\t65\tAPP_OP\t1\ndnsfilter.android\t69\tAPP_OP\t1\ndnsfilter.android\t74\tAPP_OP\t1\ndnsfilter.android\t77\tAPP_OP\t1\ndnsfilter.android\t79\tAPP_OP\t1\ndnsfilter.android\t81\tAPP_OP\t1\ndnsfilter.android\t83\tAPP_OP\t1\ndnsfilter.android\t85\tAPP_OP\t1\ndnsfilter.android\t87\tAPP_OP\t1\ndnsfilter.android\t90\tAPP_OP\t1\ndnsfilter.android\t111\tAPP_OP\t1\ndnsfilter.android\t112\tAPP_OP\t1\ndnsfilter.android\t114\tAPP_OP\t1\ndnsfilter.android\t116\tAPP_OP\t1\ndnsfilter.android\t123\tAPP_OP\t1\ndnsfilter.android\t149\tAPP_OP\t1\ndnsfilter.android\t150\tAPP_OP\t1\ndnsfilter.android\t151\tAPP_OP\t1\ndnsfilter.android\t152\tAPP_OP\t1\ndnsfilter.android\t119\tAPP_OP\t3\n"
  },
  {
    "path": "app/src/test/resources/backups/v4/AppManager/dnsfilter.android/0_test/checksums.txt",
    "content": "d7d98dc22da624e1bb36815b3c426d3555c23c53acd3e6585ab383de874c9f35\tcert_0\nfb24bc8ccf6a4bd76459bf59d1e91d8161b46d3c15654ec15552cea9408f0b5e\tsource.tar.gz.0\n619cd045ceafe404f8627b825b4f3de99e299be9052740266f46a4bce080e56f\tdata0.tar.gz.0\n619cd045ceafe404f8627b825b4f3de99e299be9052740266f46a4bce080e56f\tdata1.tar.gz.0\n7ee2b41276c954e60d44bfbe5184cc8db94b3984690709d792e71c809a82f0d5\tmisc.am.tsv\n18349c3bd613cee8710081bb71bfd2b19f7bb76e5ef3bb73fd5d73a4ee84d913\tmeta_v2.am.json\n"
  },
  {
    "path": "app/src/test/resources/backups/v4/AppManager/dnsfilter.android/0_test/meta_v2.am.json",
    "content": "{\n    \"label\": \"personalDNSfilter\",\n    \"package_name\": \"dnsfilter.android\",\n    \"version_name\": \"1.50.58.1\",\n    \"version_code\": 1505801,\n    \"data_dirs\": [\n        \"\\/data\\/data\\/dnsfilter.android\",\n        \"\\/storage\\/emulated\\/0\\/Android\\/data\\/dnsfilter.android\"\n    ],\n    \"is_system\": false,\n    \"is_split_apk\": false,\n    \"split_configs\": [],\n    \"has_rules\": false,\n    \"backup_time\": 1757782908072,\n    \"checksum_algo\": \"SHA-256\",\n    \"crypto\": \"none\",\n    \"version\": 4,\n    \"apk_name\": \"base.apk\",\n    \"instruction_set\": \"arm64\",\n    \"flags\": 1110,\n    \"user_handle\": 0,\n    \"tar_type\": \"z\",\n    \"key_store\": false,\n    \"installer\": \"io.github.muntashirakon.AppManager\"\n}"
  },
  {
    "path": "app/src/test/resources/backups/v4/AppManager/dnsfilter.android/0_test/misc.am.tsv",
    "content": "dnsfilter.android\tandroid.permission.READ_EXTERNAL_STORAGE\tPERMISSION\tfalse\t2816\ndnsfilter.android\tandroid.permission.WRITE_EXTERNAL_STORAGE\tPERMISSION\tfalse\t2816\ndnsfilter.android\tandroid.permission.POST_NOTIFICATIONS\tPERMISSION\ttrue\t769\ndnsfilter.android\t0\tAPP_OP\t1\ndnsfilter.android\t1\tAPP_OP\t1\ndnsfilter.android\t4\tAPP_OP\t1\ndnsfilter.android\t5\tAPP_OP\t1\ndnsfilter.android\t6\tAPP_OP\t1\ndnsfilter.android\t7\tAPP_OP\t1\ndnsfilter.android\t8\tAPP_OP\t1\ndnsfilter.android\t9\tAPP_OP\t1\ndnsfilter.android\t13\tAPP_OP\t1\ndnsfilter.android\t14\tAPP_OP\t1\ndnsfilter.android\t16\tAPP_OP\t1\ndnsfilter.android\t18\tAPP_OP\t1\ndnsfilter.android\t19\tAPP_OP\t1\ndnsfilter.android\t20\tAPP_OP\t1\ndnsfilter.android\t26\tAPP_OP\t1\ndnsfilter.android\t27\tAPP_OP\t1\ndnsfilter.android\t51\tAPP_OP\t1\ndnsfilter.android\t52\tAPP_OP\t1\ndnsfilter.android\t53\tAPP_OP\t1\ndnsfilter.android\t54\tAPP_OP\t1\ndnsfilter.android\t56\tAPP_OP\t1\ndnsfilter.android\t57\tAPP_OP\t1\ndnsfilter.android\t59\tAPP_OP\t1\ndnsfilter.android\t60\tAPP_OP\t1\ndnsfilter.android\t62\tAPP_OP\t1\ndnsfilter.android\t65\tAPP_OP\t1\ndnsfilter.android\t69\tAPP_OP\t1\ndnsfilter.android\t74\tAPP_OP\t1\ndnsfilter.android\t77\tAPP_OP\t1\ndnsfilter.android\t79\tAPP_OP\t1\ndnsfilter.android\t81\tAPP_OP\t1\ndnsfilter.android\t83\tAPP_OP\t1\ndnsfilter.android\t85\tAPP_OP\t1\ndnsfilter.android\t87\tAPP_OP\t1\ndnsfilter.android\t90\tAPP_OP\t1\ndnsfilter.android\t111\tAPP_OP\t1\ndnsfilter.android\t112\tAPP_OP\t1\ndnsfilter.android\t114\tAPP_OP\t1\ndnsfilter.android\t116\tAPP_OP\t1\ndnsfilter.android\t123\tAPP_OP\t1\ndnsfilter.android\t149\tAPP_OP\t1\ndnsfilter.android\t150\tAPP_OP\t1\ndnsfilter.android\t151\tAPP_OP\t1\ndnsfilter.android\t152\tAPP_OP\t1\ndnsfilter.android\t119\tAPP_OP\t3\n"
  },
  {
    "path": "app/src/test/resources/dumpsys_app_processes.txt",
    "content": "ACTIVITY MANAGER RUNNING PROCESSES (dumpsys activity processes)\n  All known processes:\n  *PERS* UID 10213 ProcessRecord{33f9d74 22828:com.qualcomm.qti.services.systemhelper:systemhelper_service/u0a213}\n    user #0 uid=10213 gids={50213, 20213, 9997, 99909997}\n    mRequiredAbi=arm64-v8a instructionSet=arm64\n    dir=/system_ext/app/com.qualcomm.qti.services.systemhelper/com.qualcomm.qti.services.systemhelper.apk publicDir=/system_ext/app/com.qualcomm.qti.services.systemhelper/com.qualcomm.qti.services.systemhelper.apk data=/data/user/0/com.qualcomm.qti.services.systemhelper\n    packageList={com.qualcomm.qti.services.systemhelper}\n    compat={440dpi}\n    thread=android.app.IApplicationThread$Stub$Proxy@e1cef6d\n    pid=22828 starting=false\n    lastActivityTime=-1d7h27m37s717ms lastPssTime=-33s713ms pssStatType=2 nextPssTime=+59m26s35ms\n    lastPss=6.8MB lastSwapPss=4.9MB lastCachedPss=0.00 lastCachedSwapPss=0.00 lastRss=74MB\n    procStateMemTracker: best=0 (0=0 3.18038239E12x)\n    adjSeq=132374 lruSeq=194\n    oom adj: max=-800 procState: max=20 curRaw=-800 setRaw=-800 cur=-800 set=-800\n    lastCompactTime=132620905 lastCompactAction=3\n    mCurSchedGroup=2 setSchedGroup=2 systemNoUi=true trimMemoryLevel=0\n    curProcState=0 mRepProcState=0 pssProcState=0 setProcState=0 lastStateTime=-1d13h8m2s482ms\n    curCapability=LCM setCapability=LCM\n    cached=false empty=false\n    notCachedSinceIdle=true initialIdlePss=5460\n    reportedInteraction=true time=-1h38m33s429ms\n    persistent=true removed=false\n    startSeq=312\n    mountMode=DEFAULT\n    lastRequestedGc=-17h12m28s726ms lastLowMemory=-17h15m9s60ms reportLowMemory=false\n    callerPackage=android\n     Configuration={1.0 452mcc4mnc [en_US] ldltr sw392dp w392dp h827dp 440dpi nrml long hdr widecg port night finger -keyb/v/h -nav/h winConfig={ mBounds=Rect(0, 0 - 1080, 2400) mAppBounds=Rect(0, 0 - 1080, 2356) mWindowingMode=fullscreen mDisplayWindowingMode=fullscreen mActivityType=undefined mAlwaysOnTop=undefined mRotation=ROTATION_0 mEnableMaglevButton=false mMaglevButtonType=0 mMaglevButtonWidth=0 mMaglevButtonOffset=0 mGameWindow=false mFreeformInBackground=false} s.15889 themeChanged=0 themeChangedFlags=0 extraData = Bundle[{}]}\n     OverrideConfiguration={0.0 ?mcc?mnc ?localeList ?layoutDir ?swdp ?wdp ?hdp ?density ?lsize ?long ?ldr ?wideColorGamut ?orien ?uimode ?night ?touch ?keyb/?/? ?nav/? winConfig={ mBounds=Rect(0, 0 - 0, 0) mAppBounds=null mWindowingMode=undefined mDisplayWindowingMode=undefined mActivityType=undefined mAlwaysOnTop=undefined mRotation=undefined mEnableMaglevButton=false mMaglevButtonType=0 mMaglevButtonWidth=0 mMaglevButtonOffset=0 mGameWindow=false mFreeformInBackground=false} themeChanged=0 themeChangedFlags=0 extraData = Bundle[{}]}\n     mLastReportedConfiguration={1.0 452mcc4mnc [en_US] ldltr sw392dp w392dp h827dp 440dpi nrml long hdr widecg port night finger -keyb/v/h -nav/h winConfig={ mBounds=Rect(0, 0 - 1080, 2400) mAppBounds=Rect(0, 0 - 1080, 2356) mWindowingMode=fullscreen mDisplayWindowingMode=fullscreen mActivityType=undefined mAlwaysOnTop=undefined mRotation=ROTATION_0 mEnableMaglevButton=false mMaglevButtonType=0 mMaglevButtonWidth=0 mMaglevButtonOffset=0 mGameWindow=false mFreeformInBackground=false} s.15889 themeChanged=0 themeChangedFlags=0 extraData = Bundle[{}]}\n    Services:\n      - ServiceRecord{8ba7e5f u0 com.qualcomm.qti.services.systemhelper/.SysHelperService}\n    Receivers:\n      - ReceiverList{5b2a32 22828 com.qualcomm.qti.services.systemhelper:systemhelper_service/10213/u0 remote:a4d323d}\n      - ReceiverList{39aafe7 22828 com.qualcomm.qti.services.systemhelper:systemhelper_service/10213/u0 remote:7e719a6}\n      - ReceiverList{4dfb539 22828 com.qualcomm.qti.services.systemhelper:systemhelper_service/10213/u0 remote:8467900}\n  *APP* UID 10262 ProcessRecord{cb3c4f8 13763:org.mozilla.fenix:tab6/u0a262}\n    user #0 uid=10262 gids={3003, 50262, 20262, 9997, 99909997}\n    mRequiredAbi=arm64-v8a instructionSet=arm64\n    class=org.mozilla.fenix.FenixApplication\n    dir=/data/app/~~TA9UsdKk_SIyGkRtDG8ndQ==/org.mozilla.fenix-Qy07q25EhcPxIHC6H-jW0Q==/base.apk publicDir=/data/app/~~TA9UsdKk_SIyGkRtDG8ndQ==/org.mozilla.fenix-Qy07q25EhcPxIHC6H-jW0Q==/base.apk data=/data/user/0/org.mozilla.fenix\n    packageList={org.mozilla.fenix}\n    compat={440dpi}\n    thread=android.app.IApplicationThread$Stub$Proxy@c474e28\n    pid=13763 starting=false\n    lastActivityTime=-34s880ms lastPssTime=-41s202ms pssStatType=0 nextPssTime=-14s884ms\n    lastPss=0.00 lastSwapPss=0.00 lastCachedPss=0.00 lastCachedSwapPss=0.00 lastRss=0.00\n    procStateMemTracker: best=4 () / pending state=4 highest=4 1.0x\n    adjSeq=132374 lruSeq=20094\n    oom adj: max=1001 procState: max=20 curRaw=900 setRaw=900 cur=900 set=900\n    lastCompactTime=133676185 lastCompactAction=2\n    mCurSchedGroup=0 setSchedGroup=0 systemNoUi=false trimMemoryLevel=0\n    curProcState=17 mRepProcState=17 pssProcState=20 setProcState=17 lastStateTime=-34s884ms\n    curCapability=--- setCapability=---\n    cached=true empty=true\n    hasClientActivities=true foregroundActivities=false (rep=false)\n    startSeq=1289\n    mountMode=DEFAULT\n    lastCpuTime=0 whenUnimportant=-34s884ms\n    lastRequestedGc=-41s177ms lastLowMemory=-41s177ms reportLowMemory=false\n    callerPackage=org.mozilla.fenix\n     Configuration={1.0 452mcc4mnc [en_US] ldltr sw392dp w392dp h827dp 440dpi nrml long hdr widecg port night finger -keyb/v/h -nav/h winConfig={ mBounds=Rect(0, 0 - 1080, 2400) mAppBounds=Rect(0, 0 - 1080, 2356) mWindowingMode=fullscreen mDisplayWindowingMode=fullscreen mActivityType=undefined mAlwaysOnTop=undefined mRotation=ROTATION_0 mEnableMaglevButton=false mMaglevButtonType=0 mMaglevButtonWidth=0 mMaglevButtonOffset=0 mGameWindow=false mFreeformInBackground=false} s.15880 themeChanged=0 themeChangedFlags=0 extraData = Bundle[{}]}\n     OverrideConfiguration={0.0 ?mcc?mnc ?localeList ?layoutDir ?swdp ?wdp ?hdp ?density ?lsize ?long ?ldr ?wideColorGamut ?orien ?uimode ?night ?touch ?keyb/?/? ?nav/? winConfig={ mBounds=Rect(0, 0 - 0, 0) mAppBounds=null mWindowingMode=undefined mDisplayWindowingMode=undefined mActivityType=undefined mAlwaysOnTop=undefined mRotation=undefined mEnableMaglevButton=false mMaglevButtonType=0 mMaglevButtonWidth=0 mMaglevButtonOffset=0 mGameWindow=false mFreeformInBackground=false} themeChanged=0 themeChangedFlags=0 extraData = Bundle[{}]}\n     mLastReportedConfiguration={1.0 452mcc4mnc [en_US] ldltr sw392dp w392dp h827dp 440dpi nrml long hdr widecg port night finger -keyb/v/h -nav/h winConfig={ mBounds=Rect(0, 0 - 1080, 2400) mAppBounds=Rect(0, 0 - 1080, 2356) mWindowingMode=fullscreen mDisplayWindowingMode=fullscreen mActivityType=undefined mAlwaysOnTop=undefined mRotation=ROTATION_0 mEnableMaglevButton=false mMaglevButtonType=0 mMaglevButtonWidth=0 mMaglevButtonOffset=0 mGameWindow=false mFreeformInBackground=false} s.15880 themeChanged=0 themeChangedFlags=0 extraData = Bundle[{}]}\n    Services:\n      - ServiceRecord{664a3d3 u0 org.mozilla.fenix/org.mozilla.gecko.process.GeckoChildProcessServices$tab6}\n  *PERS* UID 1000 ProcessRecord{8c8ff5d 1879:system/1000}\n    user #0 uid=1000 gids={}\n    mRequiredAbi=null instructionSet=null\n    dir=/system/framework/framework-res.apk publicDir=/system/framework/framework-res.apk data=/data/system\n    packageList={com.android.networkstack.inprocess, android, com.android.service.settingsobserver, com.android.providers.settings, com.android.server.telecom, com.android.networkstack.tethering.inprocess}\n    compat=null\n    thread=android.app.ActivityThread$ApplicationThread@4d208a1\n    pid=1879 starting=false\n    lastActivityTime=-41s277ms lastPssTime=-33s664ms pssStatType=2 nextPssTime=+59m26s31ms\n    lastPss=287MB lastSwapPss=4.5MB lastCachedPss=0.00 lastCachedSwapPss=0.00 lastRss=489MB\n    procStateMemTracker: best=0 (0=0 3.18038239E12x)\n    adjSeq=132374 lruSeq=1\n    oom adj: max=-900 procState: max=20 curRaw=-900 setRaw=-900 cur=-900 set=-900\n    lastCompactTime=0 lastCompactAction=0\n    mCurSchedGroup=3 setSchedGroup=3 systemNoUi=true trimMemoryLevel=0\n    curProcState=0 mRepProcState=0 pssProcState=0 setProcState=0 lastStateTime=-1d13h8m18s462ms\n    curCapability=LCM setCapability=LCM\n    cached=false empty=false\n    notCachedSinceIdle=true initialIdlePss=256020\n    reportedInteraction=true time=-52m30s486ms\n    persistent=true removed=false\n    startSeq=0\n    mountMode=NONE\n    lastRequestedGc=-17h15m1s105ms lastLowMemory=-17h15m9s64ms reportLowMemory=false\n     Configuration={1.0 452mcc4mnc [en_US] ldltr sw392dp w392dp h827dp 440dpi nrml long hdr widecg port night finger -keyb/v/h -nav/h winConfig={ mBounds=Rect(0, 0 - 1080, 2400) mAppBounds=Rect(0, 0 - 1080, 2356) mWindowingMode=fullscreen mDisplayWindowingMode=fullscreen mActivityType=undefined mAlwaysOnTop=undefined mRotation=ROTATION_0 mEnableMaglevButton=false mMaglevButtonType=0 mMaglevButtonWidth=0 mMaglevButtonOffset=0 mGameWindow=false mFreeformInBackground=false} s.15938 themeChanged=0 themeChangedFlags=0 extraData = Bundle[{}]}\n     OverrideConfiguration={0.0 ?mcc?mnc ?localeList ?layoutDir ?swdp ?wdp ?hdp ?density ?lsize ?long ?ldr ?wideColorGamut ?orien ?uimode ?night ?touch ?keyb/?/? ?nav/? winConfig={ mBounds=Rect(0, 0 - 0, 0) mAppBounds=null mWindowingMode=undefined mDisplayWindowingMode=undefined mActivityType=undefined mAlwaysOnTop=undefined mRotation=undefined mEnableMaglevButton=false mMaglevButtonType=0 mMaglevButtonWidth=0 mMaglevButtonOffset=0 mGameWindow=false mFreeformInBackground=false} themeChanged=0 themeChangedFlags=0 extraData = Bundle[{}]}\n     mLastReportedConfiguration={1.0 452mcc4mnc [en_US] ldltr sw392dp w392dp h827dp 440dpi nrml long hdr widecg port night finger -keyb/v/h -nav/h winConfig={ mBounds=Rect(0, 0 - 1080, 2400) mAppBounds=Rect(0, 0 - 1080, 2356) mWindowingMode=fullscreen mDisplayWindowingMode=fullscreen mActivityType=undefined mAlwaysOnTop=undefined mRotation=ROTATION_0 mEnableMaglevButton=false mMaglevButtonType=0 mMaglevButtonWidth=0 mMaglevButtonOffset=0 mGameWindow=false mFreeformInBackground=false} s.15938 themeChanged=0 themeChangedFlags=0 extraData = Bundle[{}]}\n    Services:\n      - ServiceRecord{2bfefdd u0 com.android.networkstack.inprocess/com.android.server.NetworkStackService}\n      - ServiceRecord{4fe5d5c u0 com.android.server.telecom/.components.BluetoothPhoneService}\n      - ServiceRecord{8ebd1e1 u0 com.android.service.settingsobserver/.SettingsXmlObserverService}\n      - ServiceRecord{a64d3a4 u0 com.android.server.telecom/.components.TelecomService}\n      - ServiceRecord{e6a1e11 u0 com.android.networkstack.tethering.inprocess/com.android.networkstack.tethering.TetheringService}\n    Connections:\n      - ConnectionRecord{1627b4 u0 CR IMP com.android.networkstack.inprocess/com.android.server.NetworkStackService:@4bb8c87}\n      - ConnectionRecord{10d1ffd u0 CR FGS android.ext.services/.autofill.InlineSuggestionRenderServiceImpl:@6d78454}\n      - ConnectionRecord{16633ed u0 CR !FG IMPB !VIS rkr.simplekeyboard.inputmethod/.latin.LatinIME:@7b9b204}\n      - ConnectionRecord{2a17472 u0 CR FGSA CAPS DEAD com.camel.corp.universalcopy/.UniversalCopyService:@e713d7d}\n      - ConnectionRecord{41360d8 u0 CR FGS LACT SLTA UI CAPS rkr.simplekeyboard.inputmethod/.latin.LatinIME:@e1b23bb}\n      - ConnectionRecord{4692740 u0 CR FGS android.ext.services/com.android.textclassifier.DefaultTextClassifierService:@e3be2c3}\n      - ConnectionRecord{59f8060 u0 CR FGS com.android.systemui/.screenshot.TakeScreenshotService:@49d6c63}\n      - ConnectionRecord{6ea0d07 u0 CR IMP com.android.providers.media.module/com.android.providers.media.fuse.ExternalStorageServiceImpl:@cd33746}\n      - ConnectionRecord{6eb77cf u0 CR com.android.systemui/.keyguard.KeyguardService:@4eff02e}\n      - ConnectionRecord{73ed051 u0 CR FGSA CAPS com.asdoi.quicktiles/com.asdoi.quicksettings.utils.CustomAccessibilityService:@a033178}\n      - ConnectionRecord{8de06aa u0 CR FGS com.miui.notification/.NotificationListener:@9085595}\n      - ConnectionRecord{9647c96 u0 CR FGS android.ext.services/.autofill.InlineSuggestionRenderServiceImpl:@be07fb1}\n      - ConnectionRecord{9d398cc u0 CR com.miui.daemon/.performance.MiuiPerfService:@da232ff}\n      - ConnectionRecord{a3c8543 u0 CR FGS !PRCP com.blackshark.barrage/.service.NotificationMonitorService:@c17baf2}\n      - ConnectionRecord{aaa3867 u0 CR FGS android.ext.services/.autofill.InlineSuggestionRenderServiceImpl:@7d57426}\n      - ConnectionRecord{b651596 u0 CR com.miui.daemon/.performance.SysoptService:@38fdcb1}\n      - ConnectionRecord{bd2043b u0 CR FGSA UI CAPS com.miui.miwallpaper/.wallpaperservice.ImageWallpaper:@8d87aca}\n      - ConnectionRecord{c2780c9 u0 CR FGS android.ext.services/.autofill.InlineSuggestionRenderServiceImpl:@a86f8d0}\n      - ConnectionRecord{c97d697 u0 CR !FG !VIS com.xiaomi.location.fused/.FusedLocationService:@b7aed16}\n      - ConnectionRecord{ddc8696 u0 CR FGSA CAPS com.android.settings/.accessibility.accessibilitymenu.AccessibilityMenuService:@a6a71b1}\n      - ConnectionRecord{e0ab237 u0 CR IMP FGS com.android.server.telecom/.components.TelecomService:@4077336}\n      - ConnectionRecord{e381e38 u0 CR IMP com.android.networkstack.tethering.inprocess/com.android.networkstack.tethering.TetheringService:@2d0fa9b}\n      - ConnectionRecord{e67fc44 u0 CR com.miui.wmsvc/.WMService:@5349957}\n      - ConnectionRecord{f63cc22 u0 CR FGS android.ext.services/.autofill.InlineSuggestionRenderServiceImpl:@bcc65ed}\n      - ConnectionRecord{fd375c8 u0 CR FGSA UI CAPS com.miui.miwallpaper/.wallpaperservice.ImageWallpaper:@58bb66b}\n    Published Providers:\n      - com.android.providers.settings.SettingsProvider\n        -> ContentProviderRecord{fdc0c3a u0 com.android.providers.settings/.SettingsProvider}\n      - com.android.server.textclassifier.IconsContentProvider\n        -> ContentProviderRecord{714fa53 u0 android/com.android.server.textclassifier.IconsContentProvider}\n    Connected Providers:\n      - 53c80ac/com.miui.securitycenter/.provider.SecurityCenterProvider->1879:system/1000 s1/1 u0/0 +3d3h10m26s961ms\n      - 49a4e4a/com.miui.securitycenter/com.miui.idprovider.IdProvider->1879:system/1000 s0/0 u1/1 +3d2h42m23s426ms\n      - 12837bc/com.android.systemui/.keyguard.KeyguardSliceProvider->1879:system/1000 s0/0 u1/1 +3d0h7m14s589ms\n      - 7247cc0/com.miui.securitycenter/com.miui.antispam.db.AntiSpamProvider->1879:system/1000 s0/0 u1/1 +2d23h27m34s346ms\n    Receivers:\n      - ReceiverList{3df68 1879 system/1000/u0 local:e3b428b}\n      - ReceiverList{5f838 1879 system/1000/u-1 local:a25fc9b}\n      - ReceiverList{da249 1879 system/1000/u-1 local:a92b050}\n      - ReceiverList{2645e8 1879 system/1000/u0 local:265330b}\n      - ReceiverList{2eadde 1879 system/1000/u0 local:1eb0919}\n      - ReceiverList{36410a 1879 system/1000/u-1 local:bcd7d75}\n      - ReceiverList{421d39 1879 system/1000/u0 local:3918100}\n      - ReceiverList{56cd11 1879 system/1000/u0 local:c3e2938}\n      - ReceiverList{5d9817 1879 system/1000/u0 local:6a0c496}\n      - ReceiverList{68ac27 1879 system/1000/u0 local:5fa5ee6}\n      - ReceiverList{763d25 1879 system/1000/u0 local:afbbd1c}\n      - ReceiverList{9ea1bc 1879 system/1000/u-1 local:26109af}\n      - ReceiverList{acaaf2 1879 system/1000/u0 local:6653dfd}\n      - ReceiverList{babd4d 1879 system/1000/u0 local:48f04e4}\n      - ReceiverList{c21837 1879 system/1000/u0 local:704b136}\n      - ReceiverList{cb73ca 1879 system/1000/u-1 local:900c335}\n      - ReceiverList{dc556c 1879 system/1000/u999 local:8db7e1f}\n      - ReceiverList{ea11c2 1879 system/1000/u0 local:84fbe0d}\n      - ReceiverList{f7a195 1879 system/1000/u0 local:a2b2d4c}\n      - ReceiverList{10727bf 1879 system/1000/u-1 local:cda9de}\n      - ReceiverList{118b357 1879 system/1000/u0 local:3b644d6}\n      - ReceiverList{125df8c 1879 system/1000/u0 local:8ca5cbf}\n      - ReceiverList{133719f 1879 system/1000/u0 local:cf76f3e}\n      - ReceiverList{13579be 1879 system/1000/u-1 local:ba01879}\n      - ReceiverList{150b9a2 1879 system/1000/u0 local:dca996d}\n      - ReceiverList{1544e2a 1879 system/1000/u0 local:ed50b15}\n      - ReceiverList{1672d77 1879 system/1000/u-1 local:de7d376}\n      - ReceiverList{1739650 1879 system/1000/u0 local:9dd6413}\n      - ReceiverList{17afea4 1879 system/1000/u-1 local:642a937}\n      - ReceiverList{1b1ac38 1879 system/1000/u0 local:520009b}\n      - ReceiverList{1baf58f 1879 system/1000/u0 local:fbccee}\n      - ReceiverList{1bb95cd 1879 system/1000/u0 local:521ef64}\n      - ReceiverList{1c6fb0f 1879 system/1000/u0 local:846786e}\n      - ReceiverList{1f1a292 1879 system/1000/u-1 local:88ad01d}\n      - ReceiverList{1fab7e3 1879 system/1000/u0 local:83a9412}\n      - ReceiverList{1fc0b3b 1879 system/1000/u0 local:ada3dca}\n      - ReceiverList{1fe6482 1879 system/1000/u0 local:a0aa3cd}\n      - ReceiverList{200e738 1879 system/1000/u999 local:28b479b}\n      - ReceiverList{2013380 1879 system/1000/u-1 local:8b77803}\n      - ReceiverList{2449c28 1879 system/1000/u0 local:5c9fa4b}\n      - ReceiverList{24f19ae 1879 system/1000/u0 local:4fd8229}\n      - ReceiverList{26215d8 1879 system/1000/u0 local:4f8cbb}\n      - ReceiverList{27c1243 1879 system/1000/u0 local:8995bf2}\n      - ReceiverList{28293bd 1879 system/1000/u0 local:12f6f14}\n      - ReceiverList{28355de 1879 system/1000/u-1 local:b895119}\n      - ReceiverList{284c840 1879 system/1000/u-1 local:4ed67c3}\n      - ReceiverList{293d06e 1879 system/1000/u-1 local:49bdbe9}\n      - ReceiverList{2a245da 1879 system/1000/u-1 local:3265385}\n      - ReceiverList{2a7c31b 1879 system/1000/u0 local:144692a}\n      - ReceiverList{2bd7147 1879 system/1000/u0 local:6808486}\n      - ReceiverList{2cd0d72 1879 system/1000/u0 local:6179a7d}\n      - ReceiverList{2ed4ba0 1879 system/1000/u0 local:f225ca3}\n      - ReceiverList{31a11ba 1879 system/1000/u0 local:f7062e5}\n      - ReceiverList{32cbc48 1879 system/1000/u0 local:dfc06eb}\n      - ReceiverList{32e512c 1879 system/1000/u-1 local:30d10df}\n      - ReceiverList{33246ce 1879 system/1000/u0 local:52aafc9}\n      - ReceiverList{349c5ae 1879 system/1000/u0 local:fc75e29}\n      - ReceiverList{3518000 1879 system/1000/u0 local:c1f2683}\n      - ReceiverList{352a6b3 1879 system/1000/u0 local:c74bc22}\n      - ReceiverList{362e0af 1879 system/1000/u0 local:731f08e}\n      - ReceiverList{3649f03 1879 system/1000/u0 local:44d23b2}\n      - ReceiverList{375412a 1879 system/1000/u0 local:fe5ea15}\n      - ReceiverList{3770b03 1879 system/1000/u0 local:b5bfb2}\n      - ReceiverList{38a2b7f 1879 system/1000/u0 local:8af649e}\n      - ReceiverList{3b9bf19 1879 system/1000/u0 local:e3cfe60}\n      - ReceiverList{3bb6110 1879 system/1000/u-1 local:c0ea1d3}\n      - ReceiverList{3bf6c54 1879 system/1000/u0 local:227fa7}\n      - ReceiverList{3c4819b 1879 system/1000/u-1 local:efb11aa}\n      - ReceiverList{3c78282 1879 system/1000/u-1 local:aed79cd}\n      - ReceiverList{3db86bb 1879 system/1000/u0 local:de4774a}\n      - ReceiverList{3e2a9f3 1879 system/1000/u0 local:181c462}\n      - ReceiverList{42a30f0 1879 system/1000/u0 local:9794533}\n      - ReceiverList{4432ad7 1879 system/1000/u-1 local:aa9ea56}\n      - ReceiverList{44c314e 1879 system/1000/u0 local:527b449}\n      - ReceiverList{44f0354 1879 system/1000/u0 local:76612a7}\n      - ReceiverList{46534a5 1879 system/1000/u0 local:f5e29c}\n      - ReceiverList{46ce5e4 1879 system/1000/u0 local:c3aa577}\n      - ReceiverList{473b289 1879 system/1000/u-1 local:601d990}\n      - ReceiverList{489e66b 1879 system/1000/u0 local:ab6c7ba}\n      - ReceiverList{48aefac 1879 system/1000/u0 local:c97195f}\n      - ReceiverList{4a6c11b 1879 system/1000/u-1 local:c089f2a}\n      - ReceiverList{4aae80b 1879 system/1000/u-1 local:da4bda}\n      - ReceiverList{4bb0a01 1879 system/1000/u0 local:52a83e8}\n      - ReceiverList{4bb4ef3 1879 system/1000/u0 local:371dd62}\n      - ReceiverList{4c0546f 1879 system/1000/u0 local:11db4e}\n      - ReceiverList{4d71d45 1879 system/1000/u0 local:a1189bc}\n      - ReceiverList{4d91a3d 1879 system/1000/u0 local:d49ff94}\n      - ReceiverList{4eda4a8 1879 system/1000/u0 local:1c7d4cb}\n      - ReceiverList{51080db 1879 system/1000/u0 local:a8685ea}\n      - ReceiverList{514b6d2 1879 system/1000/u0 local:b388d5d}\n      - ReceiverList{5443d9a 1879 system/1000/u0 local:53a5245}\n      - ReceiverList{544863a 1879 system/1000/u-1 local:3a1d965}\n      - ReceiverList{54db6bf 1879 system/1000/u0 local:ce914de}\n      - ReceiverList{552544f 1879 system/1000/u0 local:86e6eae}\n      - ReceiverList{57a25f3 1879 system/1000/u0 local:d19b062}\n      - ReceiverList{5840382 1879 system/1000/u0 local:db75ecd}\n      - ReceiverList{58bc8f5 1879 system/1000/u0 local:d23d62c}\n      - ReceiverList{5921da8 1879 system/1000/u0 local:ebe91cb}\n      - ReceiverList{59c3b51 1879 system/1000/u-1 local:9176878}\n      - ReceiverList{5a02c02 1879 system/1000/u0 local:680d94d}\n      - ReceiverList{5a9e3c3 1879 system/1000/u0 local:e7d8372}\n      - ReceiverList{5c273a2 1879 system/1000/u-1 local:e66fb6d}\n      - ReceiverList{5d1bdd9 1879 system/1000/u-1 local:14ec020}\n      - ReceiverList{5d5b844 1879 system/1000/u0 local:b13c557}\n      - ReceiverList{5e36c7f 1879 system/1000/u0 local:d91099e}\n      - ReceiverList{60293b5 1879 system/1000/u0 local:ce013ec}\n      - ReceiverList{6048a52 1879 system/1000/u0 local:87d7edd}\n      - ReceiverList{60607ac 1879 system/1000/u0 local:92f915f}\n      - ReceiverList{61e4f0a 1879 system/1000/u0 local:3350375}\n      - ReceiverList{636fbb2 1879 system/1000/u0 local:8d759bd}\n      - ReceiverList{6635a01 1879 system/1000/u0 local:e0213e8}\n      - ReceiverList{66806d6 1879 system/1000/u-1 local:66ecaf1}\n      - ReceiverList{66e08b1 1879 system/1000/u0 local:dc48f58}\n      - ReceiverList{68ada55 1879 system/1000/u-1 local:518d10c}\n      - ReceiverList{697e30a 1879 system/1000/u0 local:2086775}\n      - ReceiverList{6986f31 1879 system/1000/u0 local:d167fd8}\n      - ReceiverList{6b1e74f 1879 system/1000/u0 local:a146dae}\n      - ReceiverList{6c3cf73 1879 system/1000/u0 local:b420fe2}\n      - ReceiverList{6ccbcf9 1879 system/1000/u0 local:aa7c7c0}\n      - ReceiverList{6e20fb2 1879 system/1000/u0 local:bb23dbd}\n      - ReceiverList{6e33845 1879 system/1000/u0 local:8a130bc}\n      - ReceiverList{6fb5bab 1879 system/1000/u0 local:35bc9fa}\n      - ReceiverList{710637a 1879 system/1000/u-1 local:69e3a5}\n      - ReceiverList{71dfce8 1879 system/1000/u0 local:61d660b}\n      - ReceiverList{71e4799 1879 system/1000/u-1 local:2b458e0}\n      - ReceiverList{729b7f5 1879 system/1000/u0 local:1d8212c}\n      - ReceiverList{73cf99e 1879 system/1000/u-1 local:7d82bd9}\n      - ReceiverList{757213c 1879 system/1000/u0 local:9b5d72f}\n      - ReceiverList{76e6f72 1879 system/1000/u-1 local:b9447d}\n      - ReceiverList{77554f4 1879 system/1000/u0 local:f1226c7}\n      - ReceiverList{78c4aa7 1879 system/1000/u0 local:4076766}\n      - ReceiverList{78e673c 1879 system/1000/u-1 local:2c6752f}\n      - ReceiverList{7932fb5 1879 system/1000/u0 local:6219fec}\n      - ReceiverList{79407e1 1879 system/1000/u0 local:cb34d48}\n      - ReceiverList{7975e95 1879 system/1000/u-1 local:eafbe4c}\n      - ReceiverList{798f6aa 1879 system/1000/u0 local:3190595}\n      - ReceiverList{7b0fd99 1879 system/1000/u0 local:fa826e0}\n      - ReceiverList{7ba5c89 1879 system/1000/u0 local:8f0eb90}\n      - ReceiverList{7cfa96b 1879 system/1000/u0 local:a3db6ba}\n      - ReceiverList{7e2c5ff 1879 system/1000/u0 local:bf7d91e}\n      - ReceiverList{7e53e58 1879 system/1000/u0 local:7bc073b}\n      - ReceiverList{7e6a06d 1879 system/1000/u0 local:47e0084}\n      - ReceiverList{7ec68bd 1879 system/1000/u0 local:7777814}\n      - ReceiverList{80dad2c 1879 system/1000/u0 local:4a05cdf}\n      - ReceiverList{82ade71 1879 system/1000/u0 local:d3c2418}\n      - ReceiverList{82ade8d 1879 system/1000/u-1 local:991e324}\n      - ReceiverList{8360eca 1879 system/1000/u0 local:558ea35}\n      - ReceiverList{84f76d5 1879 system/1000/u0 local:bd40f8c}\n      - ReceiverList{8536054 1879 system/1000/u0 local:37dc3a7}\n      - ReceiverList{856c55d 1879 system/1000/u-1 local:414e334}\n      - ReceiverList{85e1041 1879 system/1000/u0 local:f78bb28}\n      - ReceiverList{860256e 1879 system/1000/u0 local:d4064e9}\n      - ReceiverList{8636e1e 1879 system/1000/u0 local:975a259}\n      - ReceiverList{86be266 1879 system/1000/u-1 local:7919ac1}\n      - ReceiverList{871ddef 1879 system/1000/u0 local:bd59ace}\n      - ReceiverList{875f21a 1879 system/1000/u0 local:90808c5}\n      - ReceiverList{886b023 1879 system/1000/u0 local:964552}\n      - ReceiverList{89072a3 1879 system/1000/u0 local:87b81d2}\n      - ReceiverList{8993224 1879 system/1000/u0 local:5f37ab7}\n      - ReceiverList{89ba089 1879 system/1000/u0 local:f3cbf90}\n      - ReceiverList{8a02c92 1879 system/1000/u0 local:e15421d}\n      - ReceiverList{8a3d0d9 1879 system/1000/u0 local:a13f20}\n      - ReceiverList{8b07025 1879 system/1000/u0 local:1c2dc1c}\n      - ReceiverList{8b34075 1879 system/1000/u0 local:1e87bac}\n      - ReceiverList{8cdf839 1879 system/1000/u0 local:7c7e800}\n      - ReceiverList{8d0ed62 1879 system/1000/u0 local:8a0442d}\n      - ReceiverList{8d5ad35 1879 system/1000/u-1 local:11a36c}\n      - ReceiverList{8fcdd16 1879 system/1000/u0 local:141231}\n      - ReceiverList{9103e25 1879 system/1000/u0 local:7a9221c}\n      - ReceiverList{913dafa 1879 system/1000/u0 local:5fa8925}\n      - ReceiverList{91520fe 1879 system/1000/u0 local:2a4d4b9}\n      - ReceiverList{9183b8d 1879 system/1000/u-1 local:969424}\n      - ReceiverList{919c3ae 1879 system/1000/u-1 local:7009429}\n      - ReceiverList{91e0a5c 1879 system/1000/u-1 local:d5030cf}\n      - ReceiverList{91f26da 1879 system/1000/u0 local:df61885}\n      - ReceiverList{9243d50 1879 system/1000/u0 local:adc4713}\n      - ReceiverList{92a926d 1879 system/1000/u-1 local:5727a84}\n      - ReceiverList{92fe500 1879 system/1000/u-1 local:93ff83}\n      - ReceiverList{931f2fe 1879 system/1000/u-1 local:4c9aeb9}\n      - ReceiverList{9378cf6 1879 system/1000/u-1 local:f8e1591}\n      - ReceiverList{9387003 1879 system/1000/u0 local:ab998b2}\n      - ReceiverList{9397962 1879 system/1000/u0 local:663802d}\n      - ReceiverList{93a99b8 1879 system/1000/u0 local:1aa341b}\n      - ReceiverList{947685c 1879 system/1000/u-1 local:4ec46cf}\n      - ReceiverList{95db2c4 1879 system/1000/u-1 local:92d19d7}\n      - ReceiverList{95f4a97 1879 system/1000/u999 local:1a7b116}\n      - ReceiverList{96034f2 1879 system/1000/u0 local:ee8affd}\n      - ReceiverList{9756ef8 1879 system/1000/u0 local:5e2165b}\n      - ReceiverList{97722ba 1879 system/1000/u0 local:9c317e5}\n      - ReceiverList{9ae383c 1879 system/1000/u-1 local:72eea2f}\n      - ReceiverList{9b38e89 1879 system/1000/u0 local:327a590}\n      - ReceiverList{9bc2d5c 1879 system/1000/u-1 local:d4ffcf}\n      - ReceiverList{9d6b829 1879 system/1000/u-1 local:cdcf1b0}\n      - ReceiverList{9d9e69e 1879 system/1000/u0 local:250acd9}\n      - ReceiverList{9eb7ec3 1879 system/1000/u-1 local:8a8aa72}\n      - ReceiverList{9f575f7 1879 system/1000/u0 local:f17edf6}\n      - ReceiverList{9fa7f02 1879 system/1000/u0 local:354984d}\n      - ReceiverList{9fb9126 1879 system/1000/u0 local:36bcc81}\n      - ReceiverList{a063bfc 1879 system/1000/u0 local:b19a4ef}\n      - ReceiverList{a072e4f 1879 system/1000/u0 local:1e670ae}\n      - ReceiverList{a0f7e07 1879 system/1000/u0 local:253cc46}\n      - ReceiverList{a3df0ad 1879 system/1000/u0 local:5db69c4}\n      - ReceiverList{a42aaa6 1879 system/1000/u0 local:1615c01}\n      - ReceiverList{a54981d 1879 system/1000/u0 local:a6f48f4}\n      - ReceiverList{a5d9922 1879 system/1000/u0 local:48946ed}\n      - ReceiverList{a61b5ac 1879 system/1000/u-1 local:815375f}\n      - ReceiverList{a62a1d9 1879 system/1000/u999 local:3c4b420}\n      - ReceiverList{a73db66 1879 system/1000/u0 local:749d7c1}\n      - ReceiverList{a8110d0 1879 system/1000/u-1 local:2223893}\n      - ReceiverList{a879b80 1879 system/1000/u0 local:f368003}\n      - ReceiverList{a8d71b7 1879 system/1000/u0 local:ce780b6}\n      - ReceiverList{aa5ea26 1879 system/1000/u0 local:753e981}\n      - ReceiverList{acd453d 1879 system/1000/u0 local:d17f694}\n      - ReceiverList{ace99d9 1879 system/1000/u-1 local:3058c20}\n      - ReceiverList{ad49cbd 1879 system/1000/u0 local:8cffc14}\n      - ReceiverList{af78b5e 1879 system/1000/u-1 local:7feec99}\n      - ReceiverList{b10ae48 1879 system/1000/u-1 local:c1080eb}\n      - ReceiverList{b19c962 1879 system/1000/u0 local:d53102d}\n      - ReceiverList{b19f3af 1879 system/1000/u-1 local:bdd6f8e}\n      - ReceiverList{b1cf51a 1879 system/1000/u0 local:fad37c5}\n      - ReceiverList{b252691 1879 system/1000/u0 local:f4daf1b}\n      - ReceiverList{b45081f 1879 system/1000/u0 local:d8f4fbe}\n      - ReceiverList{b4b880e 1879 system/1000/u-1 local:d472e09}\n      - ReceiverList{b4d7b9b 1879 system/1000/u0 local:f83b3aa}\n      - ReceiverList{b4de3ff 1879 system/1000/u-1 local:7c4af1e}\n      - ReceiverList{b4f4553 1879 system/1000/u0 local:a5c3142}\n      - ReceiverList{b56aa83 1879 system/1000/u0 local:6da2d32}\n      - ReceiverList{b5d74fe 1879 system/1000/u0 local:249f8b9}\n      - ReceiverList{b5ecb32 1879 system/1000/u0 local:86b73d}\n      - ReceiverList{b63bf5b 1879 system/1000/u0 local:e3dae6a}\n      - ReceiverList{b8548e6 1879 system/1000/u0 local:42e8b41}\n      - ReceiverList{ba2003b 1879 system/1000/u-1 local:e3ae6ca}\n      - ReceiverList{badd362 1879 system/1000/u0 local:6e9022d}\n      - ReceiverList{bb387bb 1879 system/1000/u0 local:807dc4a}\n      - ReceiverList{bc9f189 1879 system/1000/u0 local:dddb490}\n      - ReceiverList{be56b99 1879 system/1000/u0 local:7518ce0}\n      - ReceiverList{bf8c1c9 1879 system/1000/u0 local:7c09dd0}\n      - ReceiverList{c131528 1879 system/1000/u-1 local:e52b74b}\n      - ReceiverList{c17de7c 1879 system/1000/u0 local:aba416f}\n      - ReceiverList{c25452e 1879 system/1000/u-1 local:feb2ba9}\n      - ReceiverList{c288c5d 1879 system/1000/u-1 local:6856634}\n      - ReceiverList{c2e9f29 1879 system/1000/u0 local:99814b0}\n      - ReceiverList{c391c26 1879 system/1000/u0 local:74ca381}\n      - ReceiverList{c58182a 1879 system/1000/u0 local:bc1bd15}\n      - ReceiverList{c5b7214 1879 system/1000/u0 local:6b80467}\n      - ReceiverList{c67b48f 1879 system/1000/u0 local:17827ee}\n      - ReceiverList{c719be7 1879 system/1000/u0 local:b5635a6}\n      - ReceiverList{c829f04 1879 system/1000/u-1 local:5dd0f17}\n      - ReceiverList{c82e149 1879 system/1000/u-1 local:ca98b50}\n      - ReceiverList{c83c77c 1879 system/1000/u0 local:5302e6f}\n      - ReceiverList{c894fa9 1879 system/1000/u-1 local:9e53730}\n      - ReceiverList{c92ae6d 1879 system/1000/u0 local:b398684}\n      - ReceiverList{c98fbd5 1879 system/1000/u0 local:6ec888c}\n      - ReceiverList{ca17f06 1879 system/1000/u-1 local:71f45e1}\n      - ReceiverList{caa9ba2 1879 system/1000/u-1 local:cb6c36d}\n      - ReceiverList{d0a2394 1879 system/1000/u-1 local:e148be7}\n      - ReceiverList{d0b095e 1879 system/1000/u0 local:c59a299}\n      - ReceiverList{d43f933 1879 system/1000/u0 local:de5c8a2}\n      - ReceiverList{d494c90 1879 system/1000/u0 local:7bb0b53}\n      - ReceiverList{d557223 1879 system/1000/u0 local:43ecf52}\n      - ReceiverList{d5e7e47 1879 system/1000/u0 local:3f9a586}\n      - ReceiverList{d68d3dd 1879 system/1000/u0 local:2041bb4}\n      - ReceiverList{d708eba 1879 system/1000/u0 local:d4eb3e5}\n      - ReceiverList{d7419b5 1879 system/1000/u0 local:8abf1ec}\n      - ReceiverList{d84b7c6 1879 system/1000/u-1 local:89ce9a1}\n      - ReceiverList{d920456 1879 system/1000/u0 local:7344e71}\n      - ReceiverList{d959216 1879 system/1000/u0 local:b7a7b31}\n      - ReceiverList{daa687e 1879 system/1000/u0 local:5ac8a39}\n      - ReceiverList{db65434 1879 system/1000/u-1 local:6469b07}\n      - ReceiverList{dc84ace 1879 system/1000/u-1 local:c0643c9}\n      - ReceiverList{dcf07f9 1879 system/1000/u0 local:c685ec0}\n      - ReceiverList{dda51d6 1879 system/1000/u0 local:45f61f1}\n      - ReceiverList{e12d2e3 1879 system/1000/u0 local:1863b12}\n      - ReceiverList{e1b334e 1879 system/1000/u-1 local:ca97e49}\n      - ReceiverList{e20d326 1879 system/1000/u0 local:bb4d681}\n      - ReceiverList{e24fa8d 1879 system/1000/u0 local:8f2ef24}\n      - ReceiverList{e2c0763 1879 system/1000/u0 local:f297192}\n      - ReceiverList{e3e5fe4 1879 system/1000/u0 local:ddc777}\n      - ReceiverList{e518bb9 1879 system/1000/u0 local:4979980}\n      - ReceiverList{e54e5d5 1879 system/1000/u0 local:fddda8c}\n      - ReceiverList{e56a0bd 1879 system/1000/u0 local:8c79014}\n      - ReceiverList{e5925d6 1879 system/1000/u0 local:70505f1}\n      - ReceiverList{e61735f 1879 system/1000/u0 local:f795ffe}\n      - ReceiverList{e7b5a20 1879 system/1000/u-1 local:ffd9523}\n      - ReceiverList{e8f4905 1879 system/1000/u0 local:da40c7c}\n      - ReceiverList{ea4cdee 1879 system/1000/u0 local:1845f69}\n      - ReceiverList{eaf7048 1879 system/1000/u-1 local:7c90aeb}\n      - ReceiverList{ed9d669 1879 system/1000/u0 local:1ca0f0}\n      - ReceiverList{eeb8a14 1879 system/1000/u0 local:7997c67}\n      - ReceiverList{efa261d 1879 system/1000/u0 local:71a4ef4}\n      - ReceiverList{f00f6c1 1879 system/1000/u0 local:9d52ba8}\n      - ReceiverList{f10cf49 1879 system/1000/u-1 local:6227150}\n      - ReceiverList{f162017 1879 system/1000/u0 local:2466c96}\n      - ReceiverList{f39ceee 1879 system/1000/u-1 local:d38c469}\n      - ReceiverList{f3e7018 1879 system/1000/u0 local:257e7fb}\n      - ReceiverList{f407081 1879 system/1000/u0 local:3637468}\n      - ReceiverList{f5b52d4 1879 system/1000/u0 local:3bbf027}\n      - ReceiverList{f60290d 1879 system/1000/u-1 local:37bc7a4}\n      - ReceiverList{f7aa8a4 1879 system/1000/u0 local:72ebb37}\n      - ReceiverList{f7dc211 1879 system/1000/u0 local:683d238}\n      - ReceiverList{f7e45f6 1879 system/1000/u0 local:6481291}\n      - ReceiverList{f808e8a 1879 system/1000/u0 local:ac290f5}\n      - ReceiverList{f81b562 1879 system/1000/u0 local:bf72c2d}\n      - ReceiverList{f920787 1879 system/1000/u0 local:8c8bc6}\n      - ReceiverList{fadc9c8 1879 system/1000/u0 local:5cada6b}\n      - ReceiverList{fb2034d 1879 system/1000/u-1 local:f5fa2e4}\n      - ReceiverList{fb47d60 1879 system/1000/u0 local:8243d63}\n      - ReceiverList{fc22ea5 1879 system/1000/u0 local:22849c}\n      - ReceiverList{fc4e930 1879 system/1000/u-1 local:ae6b673}\n      - ReceiverList{fd3bada 1879 system/1000/u0 local:b107c85}\n      - ReceiverList{fdeb606 1879 system/1000/u0 local:ec2f8e1}\n      - ReceiverList{fe4cc06 1879 system/1000/u0 local:d5ba6e1}\n      - ReceiverList{fe9064e 1879 system/1000/u0 local:e8ebd49}\n      - ReceiverList{ff23367 1879 system/1000/u0 local:3a47b26}"
  },
  {
    "path": "app/src/test/resources/dumpsys_services.txt",
    "content": "ACTIVITY MANAGER SERVICES (dumpsys activity services)\n  User 0 active services:\n  * ServiceRecord{1938575 u0 org.bromite.bromite/org.chromium.content.app.SandboxedProcessService0:1}\n    intent={cmp=org.bromite.bromite/org.chromium.content.app.SandboxedProcessService0}\n    packageName=org.bromite.bromite\n    processName=org.bromite.bromite:sandboxed_process0:org.chromium.content.app.SandboxedProcessService0:1\n    permission=org.bromite.bromite.permission.CHILD_SERVICE\n    baseDir=/data/app/~~PLFMxs20ci87ThmrNHElNw==/org.bromite.bromite-inrEzXw9ApNPhQ1AEFw9DQ==/base.apk\n    dataDir=/data/user/0/org.bromite.bromite\n    app=ProcessRecord{8345513 6072:org.bromite.bromite:sandboxed_process0:org.chromium.content.app.SandboxedProcessService0:1/u0a143i-9000}\n    isolatedProc=ProcessRecord{8345513 6072:org.bromite.bromite:sandboxed_process0:org.chromium.content.app.SandboxedProcessService0:1/u0a143i-9000}\n    allowWhileInUsePermissionInFgs=true\n    recentCallingPackage=org.bromite.bromite\n    createTime=-29m50s704ms startingBgTimeout=--\n    lastActivity=-29m50s153ms restartTime=-29m50s249ms createdFromFg=true\n    Bindings:\n    * IntentBindRecord{8194875 CREATE}:\n      intent={cmp=org.bromite.bromite/org.chromium.content.app.SandboxedProcessService0}\n      binder=android.os.BinderProxy@655b00a\n      requested=true received=true hasBound=true doRebind=false\n      * Client AppBindRecord{fdb307b ProcessRecord{3b8ec3d 4531:org.bromite.bromite/u0a143}}\n        Per-process Connections:\n          ConnectionRecord{42aa0dc u0 CR WPRI org.bromite.bromite/org.chromium.content.app.SandboxedProcessService0:1:@8866949}\n          ConnectionRecord{cc5424e u0 CR WPRI org.bromite.bromite/org.chromium.content.app.SandboxedProcessService0:1:@8866949}\n    All Connections:\n      ConnectionRecord{cc5424e u0 CR WPRI org.bromite.bromite/org.chromium.content.app.SandboxedProcessService0:1:@8866949}\n      ConnectionRecord{42aa0dc u0 CR WPRI org.bromite.bromite/org.chromium.content.app.SandboxedProcessService0:1:@8866949}\n\n  * ServiceRecord{bf7a90a u0 org.bromite.bromite/org.chromium.content.app.SandboxedProcessService0:2}\n    intent={cmp=org.bromite.bromite/org.chromium.content.app.SandboxedProcessService0}\n    packageName=org.bromite.bromite\n    processName=org.bromite.bromite:sandboxed_process0:org.chromium.content.app.SandboxedProcessService0:2\n    permission=org.bromite.bromite.permission.CHILD_SERVICE\n    baseDir=/data/app/~~PLFMxs20ci87ThmrNHElNw==/org.bromite.bromite-inrEzXw9ApNPhQ1AEFw9DQ==/base.apk\n    dataDir=/data/user/0/org.bromite.bromite\n    app=ProcessRecord{4d51080 6082:org.bromite.bromite:sandboxed_process0:org.chromium.content.app.SandboxedProcessService0:2/u0a143i-8999}\n    isolatedProc=ProcessRecord{4d51080 6082:org.bromite.bromite:sandboxed_process0:org.chromium.content.app.SandboxedProcessService0:2/u0a143i-8999}\n    allowWhileInUsePermissionInFgs=true\n    recentCallingPackage=org.bromite.bromite\n    createTime=-29m50s372ms startingBgTimeout=--\n    lastActivity=-3s512ms restartTime=-29m50s234ms createdFromFg=true\n    Bindings:\n    * IntentBindRecord{33b4e98 CREATE}:\n      intent={cmp=org.bromite.bromite/org.chromium.content.app.SandboxedProcessService0}\n      binder=android.os.BinderProxy@3c2f6f1\n      requested=true received=true hasBound=true doRebind=false\n      * Client AppBindRecord{a6c2d6 ProcessRecord{3b8ec3d 4531:org.bromite.bromite/u0a143}}\n        Per-process Connections:\n          ConnectionRecord{991d1d7 u0 CR org.bromite.bromite/org.chromium.content.app.SandboxedProcessService0:2:@4fecd56}\n          ConnectionRecord{b3e250f u0 CR WPRI org.bromite.bromite/org.chromium.content.app.SandboxedProcessService0:2:@cbf36b9}\n          ConnectionRecord{c2cdafe u0 CR WPRI org.bromite.bromite/org.chromium.content.app.SandboxedProcessService0:2:@cbf36b9}\n    All Connections:\n      ConnectionRecord{991d1d7 u0 CR org.bromite.bromite/org.chromium.content.app.SandboxedProcessService0:2:@4fecd56}\n      ConnectionRecord{c2cdafe u0 CR WPRI org.bromite.bromite/org.chromium.content.app.SandboxedProcessService0:2:@cbf36b9}\n      ConnectionRecord{b3e250f u0 CR WPRI org.bromite.bromite/org.chromium.content.app.SandboxedProcessService0:2:@cbf36b9}\n\n  * ServiceRecord{c74e913 u0 org.bromite.bromite/org.chromium.content.app.PrivilegedProcessService0}\n    intent={cmp=org.bromite.bromite/org.chromium.content.app.PrivilegedProcessService0}\n    packageName=org.bromite.bromite\n    processName=org.bromite.bromite:privileged_process0\n    permission=org.bromite.bromite.permission.CHILD_SERVICE\n    baseDir=/data/app/~~PLFMxs20ci87ThmrNHElNw==/org.bromite.bromite-inrEzXw9ApNPhQ1AEFw9DQ==/base.apk\n    dataDir=/data/user/0/org.bromite.bromite\n    app=ProcessRecord{5b57123 4604:org.bromite.bromite:privileged_process0/u0a143}\n    allowWhileInUsePermissionInFgs=false\n    recentCallingPackage=org.bromite.bromite\n    createTime=-1h4m5s139ms startingBgTimeout=--\n    lastActivity=-43m28s726ms restartTime=-43m28s726ms createdFromFg=false\n    Bindings:\n    * IntentBindRecord{de25957 CREATE}:\n      intent={cmp=org.bromite.bromite/org.chromium.content.app.PrivilegedProcessService0}\n      binder=android.os.BinderProxy@e2bc44\n      requested=true received=true hasBound=true doRebind=false\n      * Client AppBindRecord{67f112d ProcessRecord{3b8ec3d 4531:org.bromite.bromite/u0a143}}\n        Per-process Connections:\n          ConnectionRecord{8336a52 u0 CR IMP org.bromite.bromite/org.chromium.content.app.PrivilegedProcessService0:@c9bdedd}\n          ConnectionRecord{f7c8bd9 u0 CR WPRI org.bromite.bromite/org.chromium.content.app.PrivilegedProcessService0:@acc0620}\n    All Connections:\n      ConnectionRecord{f7c8bd9 u0 CR WPRI org.bromite.bromite/org.chromium.content.app.PrivilegedProcessService0:@acc0620}\n      ConnectionRecord{8336a52 u0 CR IMP org.bromite.bromite/org.chromium.content.app.PrivilegedProcessService0:@c9bdedd}\n\n  Connection bindings to services:\n  * ConnectionRecord{991d1d7 u0 CR org.bromite.bromite/org.chromium.content.app.SandboxedProcessService0:2:@4fecd56}\n    binding=AppBindRecord{a6c2d6 org.bromite.bromite/org.chromium.content.app.SandboxedProcessService0:2:org.bromite.bromite}\n    conn=android.os.BinderProxy@4fecd56 flags=0x1\n  * ConnectionRecord{cc5424e u0 CR WPRI org.bromite.bromite/org.chromium.content.app.SandboxedProcessService0:1:@8866949}\n    binding=AppBindRecord{fdb307b org.bromite.bromite/org.chromium.content.app.SandboxedProcessService0:1:org.bromite.bromite}\n    conn=android.os.BinderProxy@8866949 flags=0x21\n  * ConnectionRecord{42aa0dc u0 CR WPRI org.bromite.bromite/org.chromium.content.app.SandboxedProcessService0:1:@8866949}\n    binding=AppBindRecord{fdb307b org.bromite.bromite/org.chromium.content.app.SandboxedProcessService0:1:org.bromite.bromite}\n    conn=android.os.BinderProxy@8866949 flags=0x21\n  * ConnectionRecord{f7c8bd9 u0 CR WPRI org.bromite.bromite/org.chromium.content.app.PrivilegedProcessService0:@acc0620}\n    binding=AppBindRecord{67f112d org.bromite.bromite/org.chromium.content.app.PrivilegedProcessService0:org.bromite.bromite}\n    conn=android.os.BinderProxy@acc0620 flags=0x21\n  * ConnectionRecord{8336a52 u0 CR IMP org.bromite.bromite/org.chromium.content.app.PrivilegedProcessService0:@c9bdedd}\n    binding=AppBindRecord{67f112d org.bromite.bromite/org.chromium.content.app.PrivilegedProcessService0:org.bromite.bromite}\n    conn=android.os.BinderProxy@c9bdedd flags=0x41\n  * ConnectionRecord{c2cdafe u0 CR WPRI org.bromite.bromite/org.chromium.content.app.SandboxedProcessService0:2:@cbf36b9}\n    binding=AppBindRecord{a6c2d6 org.bromite.bromite/org.chromium.content.app.SandboxedProcessService0:2:org.bromite.bromite}\n    conn=android.os.BinderProxy@cbf36b9 flags=0x21\n  * ConnectionRecord{b3e250f u0 CR WPRI org.bromite.bromite/org.chromium.content.app.SandboxedProcessService0:2:@cbf36b9}\n    binding=AppBindRecord{a6c2d6 org.bromite.bromite/org.chromium.content.app.SandboxedProcessService0:2:org.bromite.bromite}\n    conn=android.os.BinderProxy@cbf36b9 flags=0x21\n"
  },
  {
    "path": "app/src/test/resources/ifw/sample.package.xml",
    "content": "<rules>\n    <activity block=\"true\" log=\"false\">\n        <component-filter name=\"sample.package/.NastyActivity\" />\n        <component-filter name=\"sample.package/.ad.AdActivity\" />\n        <component-filter name=\"sample.package/.log.CrashLogActivity\" />\n    </activity>\n    <broadcast block=\"true\" log=\"false\">\n        <component-filter name=\"sample.package/.SystemBroadcastReceiver\" />\n        <component-filter name=\"sample.package/.ThirdPartyReceiver\" />\n    </broadcast>\n    <service block=\"true\" log=\"false\">\n        <component-filter name=\"sample.package/.MalwareService\" />\n        <component-filter name=\"sample.package/.AlwaysRunningLoggingService\" />\n    </service>\n</rules>"
  },
  {
    "path": "app/src/test/resources/oandbackups/ademar.textlauncher/ademar.textlauncher.log",
    "content": "{\n    \"label\": \"Text Launcher\",\n    \"versionName\": \"1.3.1\",\n    \"versionCode\": 7,\n    \"packageName\": \"ademar.textlauncher\",\n    \"sourceDir\": \"\\/data\\/app\\/ademar.textlauncher-TaN6bjb-6xC8V87dgtDF3F1==\\/base.apk\",\n    \"dataDir\": \"\\/data\\/user\\/0\\/ademar.textlauncher\",\n    \"lastBackupMillis\": 1622312833917,\n    \"isEncrypted\": false,\n    \"isSystem\": false,\n    \"backupMode\": 1\n}\n"
  },
  {
    "path": "app/src/test/resources/oandbackups/ca.cmetcalfe.locationshare/ca.cmetcalfe.locationshare.log",
    "content": "{\n    \"label\": \"Location Share\",\n    \"versionName\": \"1.4.1\",\n    \"versionCode\": 8,\n    \"packageName\": \"ca.cmetcalfe.locationshare\",\n    \"sourceDir\": \"\\/data\\/app\\/ca.cmetcalfe.locationshare-VJ9qJEV-rAxJAdWynUa3VQ==\\/base.apk\",\n    \"dataDir\": \"\\/data\\/user\\/0\\/ca.cmetcalfe.locationshare\",\n    \"lastBackupMillis\": 1622312833717,\n    \"isEncrypted\": false,\n    \"isSystem\": false,\n    \"backupMode\": 2\n}\n"
  },
  {
    "path": "app/src/test/resources/oandbackups/dnsfilter.android/dnsfilter.android.log",
    "content": "{\n    \"label\": \"personalDNSfilter\",\n    \"versionName\": \"1.50.48.1\",\n    \"versionCode\": 1504801,\n    \"packageName\": \"dnsfilter.android\",\n    \"sourceDir\": \"\\/data\\/app\\/dnsfilter.android-LIG5n-OC2yy5cwNzftJVNA==\\/base.apk\",\n    \"dataDir\": \"\\/data\\/user\\/0\\/dnsfilter.android\",\n    \"lastBackupMillis\": 1622312871474,\n    \"isEncrypted\": false,\n    \"isSystem\": false,\n    \"backupMode\": 3\n}\n"
  },
  {
    "path": "app/src/test/resources/oandbackups/org.billthefarmer.editor/org.billthefarmer.editor.log",
    "content": "{\n    \"label\": \"Editor\",\n    \"versionName\": \"1.55\",\n    \"versionCode\": 155,\n    \"packageName\": \"org.billthefarmer.editor\",\n    \"sourceDir\": \"\\/data\\/app\\/org.billthefarmer.editor-xidn2qiAFDxKdpdfTaYvJw==\\/base.apk\",\n    \"dataDir\": \"\\/data\\/user\\/0\\/org.billthefarmer.editor\",\n    \"lastBackupMillis\": 1622312824655,\n    \"isEncrypted\": false,\n    \"isSystem\": false,\n    \"backupMode\": 3\n}\n"
  },
  {
    "path": "app/src/test/resources/plain.txt",
    "content": "Sed ac accumsan justo, vel sagittis nulla. Aenean pretium ante nec luctus vulputate. Fusce et blandit nisl. Cras id bibendum magna. Duis neque lacus, convallis rutrum auctor at, molestie eget ipsum. Etiam ut risus nec diam vulputate pretium a id sem. Duis ut consectetur sapien. Sed dui nunc, semper eu purus eu, interdum vehicula nisi. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Aliquam eros lacus, tristique aliquam luctus a, tincidunt sed dui. Phasellus pretium mauris vitae augue feugiat, vitae gravida ligula maximus. Maecenas at ex vitae nisi pulvinar aliquam non eu sapien. Aliquam erat volutpat. Nunc eleifend leo elit, vitae tempus lectus dignissim sollicitudin. Maecenas ut tortor nec lectus elementum porta. Phasellus laoreet sodales sodales.\n\nPraesent facilisis sed nulla ac condimentum. Praesent pretium tempor nibh, at ornare risus feugiat in. Cras scelerisque pretium erat. Nullam non odio mattis, commodo odio sed, condimentum arcu. In sit amet imperdiet tellus. Morbi ultrices viverra dignissim. Fusce dui nisi, lobortis condimentum viverra ac, sagittis a tellus. Proin vitae interdum sem, at lobortis augue. Nullam volutpat blandit magna vitae bibendum. In a nisl rhoncus, interdum tortor in, porta eros. Suspendisse sem justo, pellentesque a aliquet nec, rutrum vitae dui. Suspendisse ac quam maximus nulla porta viverra scelerisque et ex. Phasellus egestas nunc vitae libero suscipit fringilla. Aenean sit amet feugiat lorem, sed porttitor quam.\n\nPhasellus massa magna, rhoncus vitae mauris non, maximus interdum dolor. Mauris et placerat nunc. Ut commodo ipsum id varius rutrum. Aliquam diam libero, lobortis non risus sollicitudin, mollis venenatis velit. Nulla facilisi. Sed at felis iaculis, posuere dolor et, vestibulum lorem. Nam et ante condimentum, aliquet metus a, vulputate sem. Duis augue ipsum, rutrum consequat pulvinar a, iaculis nec elit. Mauris eu dolor efficitur, vestibulum augue id, scelerisque ligula. Cras a egestas erat. Proin ultricies laoreet sagittis. Morbi maximus nibh urna, sed consequat arcu blandit eu. Pellentesque eget enim felis. Nunc gravida ligula ac magna ultricies consectetur. Donec elit nulla, pretium non nunc nec, ornare ullamcorper ipsum.\n\nAliquam eget posuere velit. Curabitur sit amet ipsum neque. Fusce molestie feugiat nisl, eu ornare elit luctus a. Fusce pulvinar molestie sapien, quis suscipit lectus viverra sed. Phasellus odio lorem, vehicula a justo id, vulputate accumsan nisi. Nulla porta est vel sem faucibus sagittis molestie pretium diam. Integer sem dolor, placerat eget aliquam et, gravida accumsan lorem. Integer porta velit sit amet dignissim lobortis. Ut a pharetra diam. Fusce gravida ex nec enim dapibus, sed lacinia metus pharetra. Pellentesque vehicula urna eu mi finibus placerat. Vivamus venenatis ante accumsan tellus auctor, quis ullamcorper sapien tempor. Suspendisse eget ligula maximus, fringilla lorem at, tristique leo. Suspendisse varius lectus id erat dapibus, ac laoreet arcu ultricies.\n\nCras pellentesque sem a dignissim ullamcorper. Aliquam gravida consequat nunc quis tristique. Donec vulputate lectus in enim porta, eu molestie dolor finibus. Aenean elementum vulputate interdum. Nullam mollis ex diam, nec auctor ante vulputate ac. Sed vulputate libero tortor, nec dictum diam ultrices vel. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Etiam pellentesque risus sed urna tempor, eget imperdiet erat porttitor. Donec sodales tellus at lacus maximus porttitor. Nunc vel lobortis nunc. Cras finibus erat id rhoncus feugiat."
  },
  {
    "path": "app/src/test/resources/prefixed/prefixed_exclude.txt",
    "content": "Sed ac accumsan justo, vel sagittis nulla. Aenean pretium ante nec luctus vulputate. Fusce et blandit nisl. Cras id bibendum magna. Duis neque lacus, convallis rutrum auctor at, molestie eget ipsum. Etiam ut risus nec diam vulputate pretium a id sem. Duis ut consectetur sapien. Sed dui nunc, semper eu purus eu, interdum vehicula nisi. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Aliquam eros lacus, tristique aliquam luctus a, tincidunt sed dui. Phasellus pretium mauris vitae augue feugiat, vitae gravida ligula maximus. Maecenas at ex vitae nisi pulvinar aliquam non eu sapien. Aliquam erat volutpat. Nunc eleifend leo elit, vitae tempus lectus dignissim sollicitudin. Maecenas ut tortor nec lectus elementum porta. Phasellus laoreet sodales sodales.\n\nPraesent facilisis sed nulla ac condimentum. Praesent pretium tempor nibh, at ornare risus feugiat in. Cras scelerisque pretium erat. Nullam non odio mattis, commodo odio sed, condimentum arcu. In sit amet imperdiet tellus. Morbi ultrices viverra dignissim. Fusce dui nisi, lobortis condimentum viverra ac, sagittis a tellus. Proin vitae interdum sem, at lobortis augue. Nullam volutpat blandit magna vitae bibendum. In a nisl rhoncus, interdum tortor in, porta eros. Suspendisse sem justo, pellentesque a aliquet nec, rutrum vitae dui. Suspendisse ac quam maximus nulla porta viverra scelerisque et ex. Phasellus egestas nunc vitae libero suscipit fringilla. Aenean sit amet feugiat lorem, sed porttitor quam.\n\nPhasellus massa magna, rhoncus vitae mauris non, maximus interdum dolor. Mauris et placerat nunc. Ut commodo ipsum id varius rutrum. Aliquam diam libero, lobortis non risus sollicitudin, mollis venenatis velit. Nulla facilisi. Sed at felis iaculis, posuere dolor et, vestibulum lorem. Nam et ante condimentum, aliquet metus a, vulputate sem. Duis augue ipsum, rutrum consequat pulvinar a, iaculis nec elit. Mauris eu dolor efficitur, vestibulum augue id, scelerisque ligula. Cras a egestas erat. Proin ultricies laoreet sagittis. Morbi maximus nibh urna, sed consequat arcu blandit eu. Pellentesque eget enim felis. Nunc gravida ligula ac magna ultricies consectetur. Donec elit nulla, pretium non nunc nec, ornare ullamcorper ipsum.\n\nAliquam eget posuere velit. Curabitur sit amet ipsum neque. Fusce molestie feugiat nisl, eu ornare elit luctus a. Fusce pulvinar molestie sapien, quis suscipit lectus viverra sed. Phasellus odio lorem, vehicula a justo id, vulputate accumsan nisi. Nulla porta est vel sem faucibus sagittis molestie pretium diam. Integer sem dolor, placerat eget aliquam et, gravida accumsan lorem. Integer porta velit sit amet dignissim lobortis. Ut a pharetra diam. Fusce gravida ex nec enim dapibus, sed lacinia metus pharetra. Pellentesque vehicula urna eu mi finibus placerat. Vivamus venenatis ante accumsan tellus auctor, quis ullamcorper sapien tempor. Suspendisse eget ligula maximus, fringilla lorem at, tristique leo. Suspendisse varius lectus id erat dapibus, ac laoreet arcu ultricies.\n\nCras pellentesque sem a dignissim ullamcorper. Aliquam gravida consequat nunc quis tristique. Donec vulputate lectus in enim porta, eu molestie dolor finibus. Aenean elementum vulputate interdum. Nullam mollis ex diam, nec auctor ante vulputate ac. Sed vulputate libero tortor, nec dictum diam ultrices vel. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Etiam pellentesque risus sed urna tempor, eget imperdiet erat porttitor. Donec sodales tellus at lacus maximus porttitor. Nunc vel lobortis nunc. Cras finibus erat id rhoncus feugiat."
  },
  {
    "path": "app/src/test/resources/prefixed/prefixed_include.txt",
    "content": "Sed ac accumsan justo, vel sagittis nulla. Aenean pretium ante nec luctus vulputate. Fusce et blandit nisl. Cras id bibendum magna. Duis neque lacus, convallis rutrum auctor at, molestie eget ipsum. Etiam ut risus nec diam vulputate pretium a id sem. Duis ut consectetur sapien. Sed dui nunc, semper eu purus eu, interdum vehicula nisi. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Aliquam eros lacus, tristique aliquam luctus a, tincidunt sed dui. Phasellus pretium mauris vitae augue feugiat, vitae gravida ligula maximus. Maecenas at ex vitae nisi pulvinar aliquam non eu sapien. Aliquam erat volutpat. Nunc eleifend leo elit, vitae tempus lectus dignissim sollicitudin. Maecenas ut tortor nec lectus elementum porta. Phasellus laoreet sodales sodales.\n\nPraesent facilisis sed nulla ac condimentum. Praesent pretium tempor nibh, at ornare risus feugiat in. Cras scelerisque pretium erat. Nullam non odio mattis, commodo odio sed, condimentum arcu. In sit amet imperdiet tellus. Morbi ultrices viverra dignissim. Fusce dui nisi, lobortis condimentum viverra ac, sagittis a tellus. Proin vitae interdum sem, at lobortis augue. Nullam volutpat blandit magna vitae bibendum. In a nisl rhoncus, interdum tortor in, porta eros. Suspendisse sem justo, pellentesque a aliquet nec, rutrum vitae dui. Suspendisse ac quam maximus nulla porta viverra scelerisque et ex. Phasellus egestas nunc vitae libero suscipit fringilla. Aenean sit amet feugiat lorem, sed porttitor quam.\n\nPhasellus massa magna, rhoncus vitae mauris non, maximus interdum dolor. Mauris et placerat nunc. Ut commodo ipsum id varius rutrum. Aliquam diam libero, lobortis non risus sollicitudin, mollis venenatis velit. Nulla facilisi. Sed at felis iaculis, posuere dolor et, vestibulum lorem. Nam et ante condimentum, aliquet metus a, vulputate sem. Duis augue ipsum, rutrum consequat pulvinar a, iaculis nec elit. Mauris eu dolor efficitur, vestibulum augue id, scelerisque ligula. Cras a egestas erat. Proin ultricies laoreet sagittis. Morbi maximus nibh urna, sed consequat arcu blandit eu. Pellentesque eget enim felis. Nunc gravida ligula ac magna ultricies consectetur. Donec elit nulla, pretium non nunc nec, ornare ullamcorper ipsum.\n\nAliquam eget posuere velit. Curabitur sit amet ipsum neque. Fusce molestie feugiat nisl, eu ornare elit luctus a. Fusce pulvinar molestie sapien, quis suscipit lectus viverra sed. Phasellus odio lorem, vehicula a justo id, vulputate accumsan nisi. Nulla porta est vel sem faucibus sagittis molestie pretium diam. Integer sem dolor, placerat eget aliquam et, gravida accumsan lorem. Integer porta velit sit amet dignissim lobortis. Ut a pharetra diam. Fusce gravida ex nec enim dapibus, sed lacinia metus pharetra. Pellentesque vehicula urna eu mi finibus placerat. Vivamus venenatis ante accumsan tellus auctor, quis ullamcorper sapien tempor. Suspendisse eget ligula maximus, fringilla lorem at, tristique leo. Suspendisse varius lectus id erat dapibus, ac laoreet arcu ultricies.\n\nCras pellentesque sem a dignissim ullamcorper. Aliquam gravida consequat nunc quis tristique. Donec vulputate lectus in enim porta, eu molestie dolor finibus. Aenean elementum vulputate interdum. Nullam mollis ex diam, nec auctor ante vulputate ac. Sed vulputate libero tortor, nec dictum diam ultrices vel. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Etiam pellentesque risus sed urna tempor, eget imperdiet erat porttitor. Donec sodales tellus at lacus maximus porttitor. Nunc vel lobortis nunc. Cras finibus erat id rhoncus feugiat."
  },
  {
    "path": "app/src/test/resources/proc/11/attr/exec",
    "content": ""
  },
  {
    "path": "app/src/test/resources/proc/11/attr/fscreate",
    "content": ""
  },
  {
    "path": "app/src/test/resources/proc/11/attr/keycreate",
    "content": ""
  },
  {
    "path": "app/src/test/resources/proc/11/attr/sockcreate",
    "content": ""
  },
  {
    "path": "app/src/test/resources/proc/11/cgroup",
    "content": "4:schedtune:/\n3:cpuset:/\n2:cpuacct:/\n1:cpu:/\n0::/\n"
  },
  {
    "path": "app/src/test/resources/proc/11/cmdline",
    "content": ""
  },
  {
    "path": "app/src/test/resources/proc/11/comm",
    "content": "rcuos/0\n"
  },
  {
    "path": "app/src/test/resources/proc/11/coredump_filter",
    "content": ""
  },
  {
    "path": "app/src/test/resources/proc/11/cpuset",
    "content": "/\n"
  },
  {
    "path": "app/src/test/resources/proc/11/limits",
    "content": "Limit                     Soft Limit           Hard Limit           Units     \nMax cpu time              unlimited            unlimited            seconds   \nMax file size             unlimited            unlimited            bytes     \nMax data size             unlimited            unlimited            bytes     \nMax stack size            8388608              unlimited            bytes     \nMax core file size        0                    unlimited            bytes     \nMax resident set          unlimited            unlimited            bytes     \nMax processes             10069                10069                processes \nMax open files            1024                 4096                 files     \nMax locked memory         65536                65536                bytes     \nMax address space         unlimited            unlimited            bytes     \nMax file locks            unlimited            unlimited            locks     \nMax pending signals       10069                10069                signals   \nMax msgqueue size         819200               819200               bytes     \nMax nice priority         0                    0                    \nMax realtime priority     0                    0                    \nMax realtime timeout      unlimited            unlimited            us        \n"
  },
  {
    "path": "app/src/test/resources/proc/11/oom_adj",
    "content": "0\n"
  },
  {
    "path": "app/src/test/resources/proc/11/oom_score",
    "content": "0\n"
  },
  {
    "path": "app/src/test/resources/proc/11/oom_score_adj",
    "content": "0\n"
  },
  {
    "path": "app/src/test/resources/proc/11/sched",
    "content": "rcuos/0 (11, #threads: 1)\n-------------------------------------------------------------------\nse.exec_start                                :      46182981.337838\nse.vruntime                                  :       7820385.658509\nse.sum_exec_runtime                          :          1103.644132\nse.statistics.sum_sleep_runtime              :      47044164.053054\nse.statistics.wait_start                     :             0.000000\nse.statistics.sleep_start                    :      47047666.809248\nse.statistics.block_start                    :             0.000000\nse.statistics.sleep_max                      :        193826.955279\nse.statistics.block_max                      :             0.000000\nse.statistics.exec_max                       :             1.191666\nse.statistics.slice_max                      :             0.416146\nse.statistics.wait_max                       :            14.207032\nse.statistics.wait_sum                       :          2328.396632\nse.statistics.wait_count                     :                32838\nse.statistics.iowait_sum                     :             0.000000\nse.statistics.iowait_count                   :                    0\nse.nr_migrations                             :                 7821\nse.statistics.nr_migrations_cold             :                    0\nse.statistics.nr_failed_migrations_affine    :                    0\nse.statistics.nr_failed_migrations_running   :                  331\nse.statistics.nr_failed_migrations_hot       :                    1\nse.statistics.nr_forced_migrations           :                   10\nse.statistics.nr_wakeups                     :                32548\nse.statistics.nr_wakeups_sync                :                    0\nse.statistics.nr_wakeups_migrate             :                 7130\nse.statistics.nr_wakeups_local               :                23858\nse.statistics.nr_wakeups_remote              :                 8690\nse.statistics.nr_wakeups_affine              :                    0\nse.statistics.nr_wakeups_affine_attempts     :                    0\nse.statistics.nr_wakeups_passive             :                    0\nse.statistics.nr_wakeups_idle                :                    0\nse.statistics.nr_wakeups_sis_attempts        :                    0\nse.statistics.nr_wakeups_sis_idle            :                    0\nse.statistics.nr_wakeups_sis_cache_affine    :                    0\nse.statistics.nr_wakeups_sis_suff_cap        :                    0\nse.statistics.nr_wakeups_sis_idle_cpu        :                    0\nse.statistics.nr_wakeups_sis_count           :                    0\nse.statistics.nr_wakeups_secb_attempts       :                    0\nse.statistics.nr_wakeups_secb_sync           :                    0\nse.statistics.nr_wakeups_secb_idle_bt        :                    0\nse.statistics.nr_wakeups_secb_insuff_cap     :                    0\nse.statistics.nr_wakeups_secb_no_nrg_sav     :                    0\nse.statistics.nr_wakeups_secb_nrg_sav        :                    0\nse.statistics.nr_wakeups_secb_count          :                    0\nse.statistics.nr_wakeups_fbt_attempts        :                    0\nse.statistics.nr_wakeups_fbt_no_cpu          :                    0\nse.statistics.nr_wakeups_fbt_no_sd           :                    0\nse.statistics.nr_wakeups_fbt_pref_idle       :                    0\nse.statistics.nr_wakeups_fbt_count           :                    0\nse.statistics.nr_wakeups_cas_attempts        :                    0\nse.statistics.nr_wakeups_cas_count           :                    0\nload_avg                                     :                    0\nravg.demand                                  :                47215\navg_atom                                     :             0.033608\navg_per_cpu                                  :             0.141112\nnr_switches                                  :                32838\nnr_voluntary_switches                        :                32548\nnr_involuntary_switches                      :                  290\nse.load.weight                               :                 1024\nse.avg.load_sum                              :                53692\nse.avg.util_sum                              :                37752\nse.avg.load_avg                              :                    0\nse.avg.util_avg                              :                    0\nse.avg.last_update_time                      :       46182981337838\npolicy                                       :                    0\nprio                                         :                  120\nclock-delta                                  :                   52\n"
  },
  {
    "path": "app/src/test/resources/proc/11/sched_group_id",
    "content": "0\n"
  },
  {
    "path": "app/src/test/resources/proc/11/sched_init_task_load",
    "content": "0\n"
  },
  {
    "path": "app/src/test/resources/proc/11/sched_wake_up_idle",
    "content": "0\n"
  },
  {
    "path": "app/src/test/resources/proc/11/schedstat",
    "content": "1103644132 2326480173 32838\n"
  },
  {
    "path": "app/src/test/resources/proc/11/stat",
    "content": "11 (rcuos/0) S 2 0 0 0 -1 2129984 0 0 0 0 0 109 0 0 20 0 1 0 0 0 0 18446744073709551615 0 0 0 0 0 0 0 2147483647 0 0 0 0 17 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n"
  },
  {
    "path": "app/src/test/resources/proc/11/statm",
    "content": "0 0 0 0 0 0 0\n"
  },
  {
    "path": "app/src/test/resources/proc/11/status",
    "content": "Name:\trcuos/0\nState:\tS (sleeping)\nTgid:\t11\nPid:\t11\nPPid:\t2\nTracerPid:\t0\nUid:\t0\t0\t0\t0\nGid:\t0\t0\t0\t0\nNgid:\t0\nFDSize:\t64\nGroups:\t\nThreads:\t1\nSigQ:\t3/10069\nSigPnd:\t0000000000000000\nShdPnd:\t0000000000000000\nSigBlk:\t0000000000000000\nSigIgn:\tffffffffffffffff\nSigCgt:\t0000000000000000\nCapInh:\t0000000000000000\nCapPrm:\t0000003fffffffff\nCapEff:\t0000003fffffffff\nCapBnd:\t0000003fffffffff\nCapAmb:\t0000000000000000\nSeccomp:\t0\nSpeculation_Store_Bypass:\tunknown\nCpus_allowed:\tff\nCpus_allowed_list:\t0-7\nMems_allowed:\t1\nMems_allowed_list:\t0\nvoluntary_ctxt_switches:\t32548\nnonvoluntary_ctxt_switches:\t290\n"
  },
  {
    "path": "app/src/test/resources/proc/11/timerslack_ns",
    "content": ""
  },
  {
    "path": "app/src/test/resources/proc/11/wchan",
    "content": "0"
  },
  {
    "path": "app/src/test/resources/proc/1101/attr/exec",
    "content": ""
  },
  {
    "path": "app/src/test/resources/proc/1101/attr/fscreate",
    "content": ""
  },
  {
    "path": "app/src/test/resources/proc/1101/attr/keycreate",
    "content": ""
  },
  {
    "path": "app/src/test/resources/proc/1101/attr/sockcreate",
    "content": ""
  },
  {
    "path": "app/src/test/resources/proc/1101/cgroup",
    "content": "4:schedtune:/foreground\n3:cpuset:/foreground\n2:cpuacct:/uid_1046/pid_1101\n1:cpu:/\n0::/\n"
  },
  {
    "path": "app/src/test/resources/proc/1101/comm",
    "content": "mediaswcodec\n"
  },
  {
    "path": "app/src/test/resources/proc/1101/coredump_filter",
    "content": "00000023\n"
  },
  {
    "path": "app/src/test/resources/proc/1101/cpuset",
    "content": "/foreground\n"
  },
  {
    "path": "app/src/test/resources/proc/1101/limits",
    "content": "Limit                     Soft Limit           Hard Limit           Units     \nMax cpu time              unlimited            unlimited            seconds   \nMax file size             unlimited            unlimited            bytes     \nMax data size             unlimited            unlimited            bytes     \nMax stack size            8388608              unlimited            bytes     \nMax core file size        0                    unlimited            bytes     \nMax resident set          unlimited            unlimited            bytes     \nMax processes             10069                10069                processes \nMax open files            32768                32768                files     \nMax locked memory         67108864             67108864             bytes     \nMax address space         unlimited            unlimited            bytes     \nMax file locks            unlimited            unlimited            locks     \nMax pending signals       10069                10069                signals   \nMax msgqueue size         819200               819200               bytes     \nMax nice priority         40                   40                   \nMax realtime priority     0                    0                    \nMax realtime timeout      unlimited            unlimited            us        \n"
  },
  {
    "path": "app/src/test/resources/proc/1101/oom_adj",
    "content": "-17\n"
  },
  {
    "path": "app/src/test/resources/proc/1101/oom_score",
    "content": "0\n"
  },
  {
    "path": "app/src/test/resources/proc/1101/oom_score_adj",
    "content": "-1000\n"
  },
  {
    "path": "app/src/test/resources/proc/1101/sched",
    "content": "mediaswcodec (1101, #threads: 7)\n-------------------------------------------------------------------\nse.exec_start                                :         18089.672016\nse.vruntime                                  :          9421.108550\nse.sum_exec_runtime                          :           145.847140\nse.statistics.sum_sleep_runtime              :          8603.615542\nse.statistics.wait_start                     :             0.000000\nse.statistics.sleep_start                    :         18334.541826\nse.statistics.block_start                    :             0.000000\nse.statistics.sleep_max                      :          8396.450755\nse.statistics.block_max                      :             4.679479\nse.statistics.exec_max                       :             3.296823\nse.statistics.slice_max                      :             7.950521\nse.statistics.wait_max                       :            15.044115\nse.statistics.wait_sum                       :           163.094535\nse.statistics.wait_count                     :                  322\nse.statistics.iowait_sum                     :           113.461660\nse.statistics.iowait_count                   :                  122\nse.nr_migrations                             :                   26\nse.statistics.nr_migrations_cold             :                    0\nse.statistics.nr_failed_migrations_affine    :                    0\nse.statistics.nr_failed_migrations_running   :                    4\nse.statistics.nr_failed_migrations_hot       :                    0\nse.statistics.nr_forced_migrations           :                    1\nse.statistics.nr_wakeups                     :                  214\nse.statistics.nr_wakeups_sync                :                   55\nse.statistics.nr_wakeups_migrate             :                   24\nse.statistics.nr_wakeups_local               :                  103\nse.statistics.nr_wakeups_remote              :                  111\nse.statistics.nr_wakeups_affine              :                    0\nse.statistics.nr_wakeups_affine_attempts     :                    0\nse.statistics.nr_wakeups_passive             :                    0\nse.statistics.nr_wakeups_idle                :                    0\nse.statistics.nr_wakeups_sis_attempts        :                    0\nse.statistics.nr_wakeups_sis_idle            :                    0\nse.statistics.nr_wakeups_sis_cache_affine    :                    0\nse.statistics.nr_wakeups_sis_suff_cap        :                    0\nse.statistics.nr_wakeups_sis_idle_cpu        :                    0\nse.statistics.nr_wakeups_sis_count           :                    0\nse.statistics.nr_wakeups_secb_attempts       :                    0\nse.statistics.nr_wakeups_secb_sync           :                    0\nse.statistics.nr_wakeups_secb_idle_bt        :                    0\nse.statistics.nr_wakeups_secb_insuff_cap     :                    0\nse.statistics.nr_wakeups_secb_no_nrg_sav     :                    0\nse.statistics.nr_wakeups_secb_nrg_sav        :                    0\nse.statistics.nr_wakeups_secb_count          :                    0\nse.statistics.nr_wakeups_fbt_attempts        :                    0\nse.statistics.nr_wakeups_fbt_no_cpu          :                    0\nse.statistics.nr_wakeups_fbt_no_sd           :                    0\nse.statistics.nr_wakeups_fbt_pref_idle       :                    0\nse.statistics.nr_wakeups_fbt_count           :                    0\nse.statistics.nr_wakeups_cas_attempts        :                    0\nse.statistics.nr_wakeups_cas_count           :                    0\nload_avg                                     :                    0\nravg.demand                                  :                    0\navg_atom                                     :             0.452941\navg_per_cpu                                  :             5.609505\nnr_switches                                  :                  322\nnr_voluntary_switches                        :                  215\nnr_involuntary_switches                      :                  107\nse.load.weight                               :                 1024\nse.avg.load_sum                              :             14470718\nse.avg.util_sum                              :             10958438\nse.avg.load_avg                              :                  303\nse.avg.util_avg                              :                  229\nse.avg.last_update_time                      :          18089672016\npolicy                                       :                    0\nprio                                         :                  120\nclock-delta                                  :                   52\n"
  },
  {
    "path": "app/src/test/resources/proc/1101/sched_group_id",
    "content": "0\n"
  },
  {
    "path": "app/src/test/resources/proc/1101/sched_init_task_load",
    "content": "0\n"
  },
  {
    "path": "app/src/test/resources/proc/1101/sched_wake_up_idle",
    "content": "0\n"
  },
  {
    "path": "app/src/test/resources/proc/1101/schedstat",
    "content": "145847140 163013389 322\n"
  },
  {
    "path": "app/src/test/resources/proc/1101/stat",
    "content": "1101 (mediaswcodec) S 1 1101 0 0 -1 1077952768 7230 0 256 0 29 17 0 0 20 0 7 0 941 277195735040 981 18446744073709551615 1 1 0 0 0 0 0 4096 1073775864 0 0 0 17 5 0 0 0 0 0 0 0 0 0 0 0 0 0\n"
  },
  {
    "path": "app/src/test/resources/proc/1101/statm",
    "content": "67674740 981 620 3 0 67667003 0\n"
  },
  {
    "path": "app/src/test/resources/proc/1101/status",
    "content": "Name:\tmediaswcodec\nState:\tS (sleeping)\nTgid:\t1101\nPid:\t1101\nPPid:\t1\nTracerPid:\t0\nUid:\t1046\t1046\t1046\t1046\nGid:\t1006\t1006\t1006\t1006\nNgid:\t0\nFDSize:\t128\nGroups:\t1026 1031 \nVmPeak:\t270699360 kB\nVmSize:\t270698960 kB\nVmLck:\t       0 kB\nVmPin:\t       0 kB\nVmHWM:\t   14068 kB\nVmRSS:\t    3924 kB\nVmData:\t270667880 kB\nVmStk:\t     132 kB\nVmExe:\t      12 kB\nVmLib:\t   17852 kB\nVmPTE:\t     456 kB\nVmPMD:\t     292 kB\nVmSwap:\t    3416 kB\nThreads:\t7\nSigQ:\t0/10069\nSigPnd:\t0000000000000000\nShdPnd:\t0000000000000000\nSigBlk:\t0000000080000000\nSigIgn:\t0000000000001000\nSigCgt:\t0000000c400084f8\nCapInh:\t0000000000000000\nCapPrm:\t0000000000000000\nCapEff:\t0000000000000000\nCapBnd:\t0000003fffffffff\nCapAmb:\t0000000000000000\nSeccomp:\t2\nSpeculation_Store_Bypass:\tunknown\nCpus_allowed:\tff\nCpus_allowed_list:\t0-7\nMems_allowed:\t1\nMems_allowed_list:\t0\nvoluntary_ctxt_switches:\t215\nnonvoluntary_ctxt_switches:\t107\n"
  },
  {
    "path": "app/src/test/resources/proc/1101/timerslack_ns",
    "content": ""
  },
  {
    "path": "app/src/test/resources/proc/1101/wchan",
    "content": "0"
  },
  {
    "path": "app/src/test/resources/proc/1129/attr/exec",
    "content": ""
  },
  {
    "path": "app/src/test/resources/proc/1129/attr/fscreate",
    "content": ""
  },
  {
    "path": "app/src/test/resources/proc/1129/attr/keycreate",
    "content": ""
  },
  {
    "path": "app/src/test/resources/proc/1129/attr/sockcreate",
    "content": ""
  },
  {
    "path": "app/src/test/resources/proc/1129/cgroup",
    "content": "4:schedtune:/\n3:cpuset:/\n2:cpuacct:/uid_1000/pid_1129\n1:cpu:/\n0::/\n"
  },
  {
    "path": "app/src/test/resources/proc/1129/comm",
    "content": "ATFWD-daemon\n"
  },
  {
    "path": "app/src/test/resources/proc/1129/coredump_filter",
    "content": "00000023\n"
  },
  {
    "path": "app/src/test/resources/proc/1129/cpuset",
    "content": "/\n"
  },
  {
    "path": "app/src/test/resources/proc/1129/limits",
    "content": "Limit                     Soft Limit           Hard Limit           Units     \nMax cpu time              unlimited            unlimited            seconds   \nMax file size             unlimited            unlimited            bytes     \nMax data size             unlimited            unlimited            bytes     \nMax stack size            8388608              unlimited            bytes     \nMax core file size        0                    unlimited            bytes     \nMax resident set          unlimited            unlimited            bytes     \nMax processes             10069                10069                processes \nMax open files            32768                32768                files     \nMax locked memory         67108864             67108864             bytes     \nMax address space         unlimited            unlimited            bytes     \nMax file locks            unlimited            unlimited            locks     \nMax pending signals       10069                10069                signals   \nMax msgqueue size         819200               819200               bytes     \nMax nice priority         40                   40                   \nMax realtime priority     0                    0                    \nMax realtime timeout      unlimited            unlimited            us        \n"
  },
  {
    "path": "app/src/test/resources/proc/1129/oom_adj",
    "content": "-17\n"
  },
  {
    "path": "app/src/test/resources/proc/1129/oom_score",
    "content": "0\n"
  },
  {
    "path": "app/src/test/resources/proc/1129/oom_score_adj",
    "content": "-1000\n"
  },
  {
    "path": "app/src/test/resources/proc/1129/sched",
    "content": "ATFWD-daemon (1129, #threads: 3)\n-------------------------------------------------------------------\nse.exec_start                                :         16433.632340\nse.vruntime                                  :          8781.006829\nse.sum_exec_runtime                          :            36.209485\nse.statistics.sum_sleep_runtime              :          7043.858305\nse.statistics.wait_start                     :             0.000000\nse.statistics.sleep_start                    :         16664.327810\nse.statistics.block_start                    :             0.000000\nse.statistics.sleep_max                      :          5000.071109\nse.statistics.block_max                      :            22.777500\nse.statistics.exec_max                       :             3.235104\nse.statistics.slice_max                      :             6.224168\nse.statistics.wait_max                       :            15.811094\nse.statistics.wait_sum                       :            53.612555\nse.statistics.wait_count                     :                   40\nse.statistics.iowait_sum                     :             4.179220\nse.statistics.iowait_count                   :                    4\nse.nr_migrations                             :                    7\nse.statistics.nr_migrations_cold             :                    0\nse.statistics.nr_failed_migrations_affine    :                    0\nse.statistics.nr_failed_migrations_running   :                    0\nse.statistics.nr_failed_migrations_hot       :                    0\nse.statistics.nr_forced_migrations           :                    1\nse.statistics.nr_wakeups                     :                   23\nse.statistics.nr_wakeups_sync                :                    0\nse.statistics.nr_wakeups_migrate             :                    5\nse.statistics.nr_wakeups_local               :                    3\nse.statistics.nr_wakeups_remote              :                   20\nse.statistics.nr_wakeups_affine              :                    0\nse.statistics.nr_wakeups_affine_attempts     :                    0\nse.statistics.nr_wakeups_passive             :                    0\nse.statistics.nr_wakeups_idle                :                    0\nse.statistics.nr_wakeups_sis_attempts        :                    0\nse.statistics.nr_wakeups_sis_idle            :                    0\nse.statistics.nr_wakeups_sis_cache_affine    :                    0\nse.statistics.nr_wakeups_sis_suff_cap        :                    0\nse.statistics.nr_wakeups_sis_idle_cpu        :                    0\nse.statistics.nr_wakeups_sis_count           :                    0\nse.statistics.nr_wakeups_secb_attempts       :                    0\nse.statistics.nr_wakeups_secb_sync           :                    0\nse.statistics.nr_wakeups_secb_idle_bt        :                    0\nse.statistics.nr_wakeups_secb_insuff_cap     :                    0\nse.statistics.nr_wakeups_secb_no_nrg_sav     :                    0\nse.statistics.nr_wakeups_secb_nrg_sav        :                    0\nse.statistics.nr_wakeups_secb_count          :                    0\nse.statistics.nr_wakeups_fbt_attempts        :                    0\nse.statistics.nr_wakeups_fbt_no_cpu          :                    0\nse.statistics.nr_wakeups_fbt_no_sd           :                    0\nse.statistics.nr_wakeups_fbt_pref_idle       :                    0\nse.statistics.nr_wakeups_fbt_count           :                    0\nse.statistics.nr_wakeups_cas_attempts        :                    0\nse.statistics.nr_wakeups_cas_count           :                    0\nload_avg                                     :                    0\nravg.demand                                  :                    0\navg_atom                                     :             0.905237\navg_per_cpu                                  :             5.172783\nnr_switches                                  :                   40\nnr_voluntary_switches                        :                   24\nnr_involuntary_switches                      :                   16\nse.load.weight                               :                 1024\nse.avg.load_sum                              :              1678402\nse.avg.util_sum                              :              1622211\nse.avg.load_avg                              :                   29\nse.avg.util_avg                              :                   28\nse.avg.last_update_time                      :          16433632340\npolicy                                       :                    0\nprio                                         :                  120\nclock-delta                                  :                   52\n"
  },
  {
    "path": "app/src/test/resources/proc/1129/sched_group_id",
    "content": "0\n"
  },
  {
    "path": "app/src/test/resources/proc/1129/sched_init_task_load",
    "content": "0\n"
  },
  {
    "path": "app/src/test/resources/proc/1129/sched_wake_up_idle",
    "content": "0\n"
  },
  {
    "path": "app/src/test/resources/proc/1129/schedstat",
    "content": "36209485 53612555 40\n"
  },
  {
    "path": "app/src/test/resources/proc/1129/stat",
    "content": "1129 (ATFWD-daemon) S 1 1129 0 0 -1 1077952768 1470 0 2 0 1 2 0 0 20 0 3 0 952 81948672 380 18446744073709551615 1 1 0 0 0 0 0 0 1073792255 0 0 0 17 6 0 0 0 0 0 0 0 0 0 0 0 0 0\n"
  },
  {
    "path": "app/src/test/resources/proc/1129/statm",
    "content": "20007 380 380 7 0 18017 0\n"
  },
  {
    "path": "app/src/test/resources/proc/1129/status",
    "content": "Name:\tATFWD-daemon\nState:\tS (sleeping)\nTgid:\t1129\nPid:\t1129\nPPid:\t1\nTracerPid:\t0\nUid:\t1000\t1000\t1000\t1000\nGid:\t1000\t1000\t1000\t1000\nNgid:\t0\nFDSize:\t64\nGroups:\t1001 \nVmPeak:\t   80028 kB\nVmSize:\t   80028 kB\nVmLck:\t       0 kB\nVmPin:\t       0 kB\nVmHWM:\t    3224 kB\nVmRSS:\t    1520 kB\nVmData:\t   71936 kB\nVmStk:\t     132 kB\nVmExe:\t      28 kB\nVmLib:\t    3784 kB\nVmPTE:\t      84 kB\nVmPMD:\t      12 kB\nVmSwap:\t     984 kB\nThreads:\t3\nSigQ:\t3/10069\nSigPnd:\t0000000000000000\nShdPnd:\t0000000000000000\nSigBlk:\t0000000080000000\nSigIgn:\t0000000000000000\nSigCgt:\t0000000c4000c4ff\nCapInh:\t0000000000000000\nCapPrm:\t0000000000000000\nCapEff:\t0000000000000000\nCapBnd:\t0000003fffffffff\nCapAmb:\t0000000000000000\nSeccomp:\t0\nSpeculation_Store_Bypass:\tunknown\nCpus_allowed:\tff\nCpus_allowed_list:\t0-7\nMems_allowed:\t1\nMems_allowed_list:\t0\nvoluntary_ctxt_switches:\t24\nnonvoluntary_ctxt_switches:\t16\n"
  },
  {
    "path": "app/src/test/resources/proc/1129/timerslack_ns",
    "content": ""
  },
  {
    "path": "app/src/test/resources/proc/1129/wchan",
    "content": "0"
  },
  {
    "path": "app/src/test/resources/proc/11547/attr/exec",
    "content": ""
  },
  {
    "path": "app/src/test/resources/proc/11547/attr/fscreate",
    "content": ""
  },
  {
    "path": "app/src/test/resources/proc/11547/attr/keycreate",
    "content": ""
  },
  {
    "path": "app/src/test/resources/proc/11547/attr/sockcreate",
    "content": ""
  },
  {
    "path": "app/src/test/resources/proc/11547/cgroup",
    "content": "4:schedtune:/\n3:cpuset:/\n2:cpuacct:/\n1:cpu:/\n0::/\n"
  },
  {
    "path": "app/src/test/resources/proc/11547/cmdline",
    "content": ""
  },
  {
    "path": "app/src/test/resources/proc/11547/comm",
    "content": "kworker/u16:4\n"
  },
  {
    "path": "app/src/test/resources/proc/11547/coredump_filter",
    "content": ""
  },
  {
    "path": "app/src/test/resources/proc/11547/cpuset",
    "content": "/\n"
  },
  {
    "path": "app/src/test/resources/proc/11547/limits",
    "content": "Limit                     Soft Limit           Hard Limit           Units     \nMax cpu time              unlimited            unlimited            seconds   \nMax file size             unlimited            unlimited            bytes     \nMax data size             unlimited            unlimited            bytes     \nMax stack size            8388608              unlimited            bytes     \nMax core file size        0                    unlimited            bytes     \nMax resident set          unlimited            unlimited            bytes     \nMax processes             10069                10069                processes \nMax open files            1024                 4096                 files     \nMax locked memory         65536                65536                bytes     \nMax address space         unlimited            unlimited            bytes     \nMax file locks            unlimited            unlimited            locks     \nMax pending signals       10069                10069                signals   \nMax msgqueue size         819200               819200               bytes     \nMax nice priority         0                    0                    \nMax realtime priority     0                    0                    \nMax realtime timeout      unlimited            unlimited            us        \n"
  },
  {
    "path": "app/src/test/resources/proc/11547/oom_adj",
    "content": "0\n"
  },
  {
    "path": "app/src/test/resources/proc/11547/oom_score",
    "content": "0\n"
  },
  {
    "path": "app/src/test/resources/proc/11547/oom_score_adj",
    "content": "0\n"
  },
  {
    "path": "app/src/test/resources/proc/11547/sched",
    "content": "kworker/u16:4 (11547, #threads: 1)\n-------------------------------------------------------------------\nse.exec_start                                :      46201287.008358\nse.vruntime                                  :       7821017.331670\nse.sum_exec_runtime                          :         23903.898189\nse.statistics.sum_sleep_runtime              :       3009413.444577\nse.statistics.wait_start                     :             0.000000\nse.statistics.sleep_start                    :      47066277.777430\nse.statistics.block_start                    :             0.000000\nse.statistics.sleep_max                      :        116912.412909\nse.statistics.block_max                      :            71.767812\nse.statistics.exec_max                       :             3.246146\nse.statistics.slice_max                      :             3.558489\nse.statistics.wait_max                       :            28.439010\nse.statistics.wait_sum                       :         30895.667946\nse.statistics.wait_count                     :                96912\nse.statistics.iowait_sum                     :           113.733431\nse.statistics.iowait_count                   :                  112\nse.nr_migrations                             :                25933\nse.statistics.nr_migrations_cold             :                    0\nse.statistics.nr_failed_migrations_affine    :                    0\nse.statistics.nr_failed_migrations_running   :                 2029\nse.statistics.nr_failed_migrations_hot       :                   29\nse.statistics.nr_forced_migrations           :                  426\nse.statistics.nr_wakeups                     :                87168\nse.statistics.nr_wakeups_sync                :                    0\nse.statistics.nr_wakeups_migrate             :                23443\nse.statistics.nr_wakeups_local               :                71609\nse.statistics.nr_wakeups_remote              :                15559\nse.statistics.nr_wakeups_affine              :                    0\nse.statistics.nr_wakeups_affine_attempts     :                    0\nse.statistics.nr_wakeups_passive             :                    0\nse.statistics.nr_wakeups_idle                :                    0\nse.statistics.nr_wakeups_sis_attempts        :                    0\nse.statistics.nr_wakeups_sis_idle            :                    0\nse.statistics.nr_wakeups_sis_cache_affine    :                    0\nse.statistics.nr_wakeups_sis_suff_cap        :                    0\nse.statistics.nr_wakeups_sis_idle_cpu        :                    0\nse.statistics.nr_wakeups_sis_count           :                    0\nse.statistics.nr_wakeups_secb_attempts       :                    0\nse.statistics.nr_wakeups_secb_sync           :                    0\nse.statistics.nr_wakeups_secb_idle_bt        :                    0\nse.statistics.nr_wakeups_secb_insuff_cap     :                    0\nse.statistics.nr_wakeups_secb_no_nrg_sav     :                    0\nse.statistics.nr_wakeups_secb_nrg_sav        :                    0\nse.statistics.nr_wakeups_secb_count          :                    0\nse.statistics.nr_wakeups_fbt_attempts        :                    0\nse.statistics.nr_wakeups_fbt_no_cpu          :                    0\nse.statistics.nr_wakeups_fbt_no_sd           :                    0\nse.statistics.nr_wakeups_fbt_pref_idle       :                    0\nse.statistics.nr_wakeups_fbt_count           :                    0\nse.statistics.nr_wakeups_cas_attempts        :                    0\nse.statistics.nr_wakeups_cas_count           :                    0\nload_avg                                     :                    2\nravg.demand                                  :               414094\navg_atom                                     :             0.246518\navg_per_cpu                                  :             0.921755\nnr_switches                                  :                96966\nnr_voluntary_switches                        :                87147\nnr_involuntary_switches                      :                 9819\nse.load.weight                               :                 1024\nse.avg.load_sum                              :              1697176\nse.avg.util_sum                              :              1191478\nse.avg.load_avg                              :                   34\nse.avg.util_avg                              :                   24\nse.avg.last_update_time                      :       46201287008358\npolicy                                       :                    0\nprio                                         :                  120\nclock-delta                                  :                   52\n"
  },
  {
    "path": "app/src/test/resources/proc/11547/sched_group_id",
    "content": "0\n"
  },
  {
    "path": "app/src/test/resources/proc/11547/sched_init_task_load",
    "content": "0\n"
  },
  {
    "path": "app/src/test/resources/proc/11547/sched_wake_up_idle",
    "content": "0\n"
  },
  {
    "path": "app/src/test/resources/proc/11547/schedstat",
    "content": "23903973344 30890593207 96967\n"
  },
  {
    "path": "app/src/test/resources/proc/11547/stat",
    "content": "11547 (kworker/u16:4) S 2 0 0 0 -1 69238880 0 0 0 0 2 2387 0 0 20 0 1 0 4401080 0 0 18446744073709551615 0 0 0 0 0 0 0 2147483647 0 0 0 0 17 0 0 0 0 0 0 0 0 0 0 0 0 0 0\n"
  },
  {
    "path": "app/src/test/resources/proc/11547/statm",
    "content": "0 0 0 0 0 0 0\n"
  },
  {
    "path": "app/src/test/resources/proc/11547/status",
    "content": "Name:\tkworker/u16:4\nState:\tS (sleeping)\nTgid:\t11547\nPid:\t11547\nPPid:\t2\nTracerPid:\t0\nUid:\t0\t0\t0\t0\nGid:\t0\t0\t0\t0\nNgid:\t0\nFDSize:\t64\nGroups:\t\nThreads:\t1\nSigQ:\t3/10069\nSigPnd:\t0000000000000000\nShdPnd:\t0000000000000000\nSigBlk:\t0000000000000000\nSigIgn:\tffffffffffffffff\nSigCgt:\t0000000000000000\nCapInh:\t0000000000000000\nCapPrm:\t0000003fffffffff\nCapEff:\t0000003fffffffff\nCapBnd:\t0000003fffffffff\nCapAmb:\t0000000000000000\nSeccomp:\t0\nSpeculation_Store_Bypass:\tunknown\nCpus_allowed:\tff\nCpus_allowed_list:\t0-7\nMems_allowed:\t1\nMems_allowed_list:\t0\nvoluntary_ctxt_switches:\t87147\nnonvoluntary_ctxt_switches:\t9819\n"
  },
  {
    "path": "app/src/test/resources/proc/11547/timerslack_ns",
    "content": ""
  },
  {
    "path": "app/src/test/resources/proc/11547/wchan",
    "content": "0"
  },
  {
    "path": "app/src/test/resources/proc/123/attr/exec",
    "content": ""
  },
  {
    "path": "app/src/test/resources/proc/123/attr/fscreate",
    "content": ""
  },
  {
    "path": "app/src/test/resources/proc/123/attr/keycreate",
    "content": ""
  },
  {
    "path": "app/src/test/resources/proc/123/attr/sockcreate",
    "content": ""
  },
  {
    "path": "app/src/test/resources/proc/123/cgroup",
    "content": "4:schedtune:/\n3:cpuset:/\n2:cpuacct:/\n1:cpu:/\n0::/\n"
  },
  {
    "path": "app/src/test/resources/proc/123/cmdline",
    "content": ""
  },
  {
    "path": "app/src/test/resources/proc/123/comm",
    "content": "irq/33-bcl_vbat\n"
  },
  {
    "path": "app/src/test/resources/proc/123/coredump_filter",
    "content": ""
  },
  {
    "path": "app/src/test/resources/proc/123/cpuset",
    "content": "/\n"
  },
  {
    "path": "app/src/test/resources/proc/123/limits",
    "content": "Limit                     Soft Limit           Hard Limit           Units     \nMax cpu time              unlimited            unlimited            seconds   \nMax file size             unlimited            unlimited            bytes     \nMax data size             unlimited            unlimited            bytes     \nMax stack size            8388608              unlimited            bytes     \nMax core file size        0                    unlimited            bytes     \nMax resident set          unlimited            unlimited            bytes     \nMax processes             10069                10069                processes \nMax open files            1024                 4096                 files     \nMax locked memory         65536                65536                bytes     \nMax address space         unlimited            unlimited            bytes     \nMax file locks            unlimited            unlimited            locks     \nMax pending signals       10069                10069                signals   \nMax msgqueue size         819200               819200               bytes     \nMax nice priority         0                    0                    \nMax realtime priority     0                    0                    \nMax realtime timeout      unlimited            unlimited            us        \n"
  },
  {
    "path": "app/src/test/resources/proc/123/oom_adj",
    "content": "0\n"
  },
  {
    "path": "app/src/test/resources/proc/123/oom_score",
    "content": "0\n"
  },
  {
    "path": "app/src/test/resources/proc/123/oom_score_adj",
    "content": "0\n"
  },
  {
    "path": "app/src/test/resources/proc/123/sched",
    "content": "irq/33-bcl_vbat (123, #threads: 1)\n-------------------------------------------------------------------\nse.exec_start                                :           359.655417\nse.vruntime                                  :             0.000000\nse.sum_exec_runtime                          :             0.040625\nse.statistics.sum_sleep_runtime              :             0.000000\nse.statistics.wait_start                     :             0.000000\nse.statistics.sleep_start                    :             0.000000\nse.statistics.block_start                    :           359.638594\nse.statistics.sleep_max                      :             0.000000\nse.statistics.block_max                      :             0.000000\nse.statistics.exec_max                       :             0.021615\nse.statistics.slice_max                      :             0.000000\nse.statistics.wait_max                       :             0.002708\nse.statistics.wait_sum                       :             0.002708\nse.statistics.wait_count                     :                    1\nse.statistics.iowait_sum                     :             0.000000\nse.statistics.iowait_count                   :                    0\nse.nr_migrations                             :                    0\nse.statistics.nr_migrations_cold             :                    0\nse.statistics.nr_failed_migrations_affine    :                    0\nse.statistics.nr_failed_migrations_running   :                    0\nse.statistics.nr_failed_migrations_hot       :                    0\nse.statistics.nr_forced_migrations           :                    0\nse.statistics.nr_wakeups                     :                    1\nse.statistics.nr_wakeups_sync                :                    0\nse.statistics.nr_wakeups_migrate             :                    0\nse.statistics.nr_wakeups_local               :                    0\nse.statistics.nr_wakeups_remote              :                    1\nse.statistics.nr_wakeups_affine              :                    0\nse.statistics.nr_wakeups_affine_attempts     :                    0\nse.statistics.nr_wakeups_passive             :                    0\nse.statistics.nr_wakeups_idle                :                    0\nse.statistics.nr_wakeups_sis_attempts        :                    0\nse.statistics.nr_wakeups_sis_idle            :                    0\nse.statistics.nr_wakeups_sis_cache_affine    :                    0\nse.statistics.nr_wakeups_sis_suff_cap        :                    0\nse.statistics.nr_wakeups_sis_idle_cpu        :                    0\nse.statistics.nr_wakeups_sis_count           :                    0\nse.statistics.nr_wakeups_secb_attempts       :                    0\nse.statistics.nr_wakeups_secb_sync           :                    0\nse.statistics.nr_wakeups_secb_idle_bt        :                    0\nse.statistics.nr_wakeups_secb_insuff_cap     :                    0\nse.statistics.nr_wakeups_secb_no_nrg_sav     :                    0\nse.statistics.nr_wakeups_secb_nrg_sav        :                    0\nse.statistics.nr_wakeups_secb_count          :                    0\nse.statistics.nr_wakeups_fbt_attempts        :                    0\nse.statistics.nr_wakeups_fbt_no_cpu          :                    0\nse.statistics.nr_wakeups_fbt_no_sd           :                    0\nse.statistics.nr_wakeups_fbt_pref_idle       :                    0\nse.statistics.nr_wakeups_fbt_count           :                    0\nse.statistics.nr_wakeups_cas_attempts        :                    0\nse.statistics.nr_wakeups_cas_count           :                    0\nload_avg                                     :                    0\nravg.demand                                  :                    0\navg_atom                                     :             0.020312\navg_per_cpu                                  :             0.000001\nnr_switches                                  :                    2\nnr_voluntary_switches                        :                    2\nnr_involuntary_switches                      :                    0\nse.load.weight                               :                 1024\nse.avg.load_sum                              :             47864797\nse.avg.util_sum                              :              4693402\nse.avg.load_avg                              :                 1002\nse.avg.util_avg                              :                   97\nse.avg.last_update_time                      :            359550782\npolicy                                       :                    1\nprio                                         :                   49\nclock-delta                                  :                   52\n"
  },
  {
    "path": "app/src/test/resources/proc/123/sched_group_id",
    "content": "0\n"
  },
  {
    "path": "app/src/test/resources/proc/123/sched_init_task_load",
    "content": "0\n"
  },
  {
    "path": "app/src/test/resources/proc/123/sched_wake_up_idle",
    "content": "0\n"
  },
  {
    "path": "app/src/test/resources/proc/123/schedstat",
    "content": "40625 2708 2\n"
  },
  {
    "path": "app/src/test/resources/proc/123/stat",
    "content": "123 (irq/33-bcl_vbat) S 2 0 0 0 -1 2129984 0 0 0 0 0 0 0 0 -51 0 1 0 35 0 0 18446744073709551615 0 0 0 0 0 0 0 2147483647 0 0 0 0 17 1 50 1 0 0 0 0 0 0 0 0 0 0 0\n"
  },
  {
    "path": "app/src/test/resources/proc/123/statm",
    "content": "0 0 0 0 0 0 0\n"
  },
  {
    "path": "app/src/test/resources/proc/123/status",
    "content": "Name:\tirq/33-bcl_vbat\nState:\tS (sleeping)\nTgid:\t123\nPid:\t123\nPPid:\t2\nTracerPid:\t0\nUid:\t0\t0\t0\t0\nGid:\t0\t0\t0\t0\nNgid:\t0\nFDSize:\t64\nGroups:\t\nThreads:\t1\nSigQ:\t3/10069\nSigPnd:\t0000000000000000\nShdPnd:\t0000000000000000\nSigBlk:\t0000000000000000\nSigIgn:\tffffffffffffffff\nSigCgt:\t0000000000000000\nCapInh:\t0000000000000000\nCapPrm:\t0000003fffffffff\nCapEff:\t0000003fffffffff\nCapBnd:\t0000003fffffffff\nCapAmb:\t0000000000000000\nSeccomp:\t0\nSpeculation_Store_Bypass:\tunknown\nCpus_allowed:\tff\nCpus_allowed_list:\t0-7\nMems_allowed:\t1\nMems_allowed_list:\t0\nvoluntary_ctxt_switches:\t2\nnonvoluntary_ctxt_switches:\t0\n"
  },
  {
    "path": "app/src/test/resources/proc/123/timerslack_ns",
    "content": ""
  },
  {
    "path": "app/src/test/resources/proc/123/wchan",
    "content": "0"
  },
  {
    "path": "app/src/test/resources/proc/uptime",
    "content": "3334.46 23480.90\n"
  },
  {
    "path": "app/src/test/resources/raw/exclude.txt",
    "content": "Sed ac accumsan justo, vel sagittis nulla. Aenean pretium ante nec luctus vulputate. Fusce et blandit nisl. Cras id bibendum magna. Duis neque lacus, convallis rutrum auctor at, molestie eget ipsum. Etiam ut risus nec diam vulputate pretium a id sem. Duis ut consectetur sapien. Sed dui nunc, semper eu purus eu, interdum vehicula nisi. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Aliquam eros lacus, tristique aliquam luctus a, tincidunt sed dui. Phasellus pretium mauris vitae augue feugiat, vitae gravida ligula maximus. Maecenas at ex vitae nisi pulvinar aliquam non eu sapien. Aliquam erat volutpat. Nunc eleifend leo elit, vitae tempus lectus dignissim sollicitudin. Maecenas ut tortor nec lectus elementum porta. Phasellus laoreet sodales sodales.\n\nPraesent facilisis sed nulla ac condimentum. Praesent pretium tempor nibh, at ornare risus feugiat in. Cras scelerisque pretium erat. Nullam non odio mattis, commodo odio sed, condimentum arcu. In sit amet imperdiet tellus. Morbi ultrices viverra dignissim. Fusce dui nisi, lobortis condimentum viverra ac, sagittis a tellus. Proin vitae interdum sem, at lobortis augue. Nullam volutpat blandit magna vitae bibendum. In a nisl rhoncus, interdum tortor in, porta eros. Suspendisse sem justo, pellentesque a aliquet nec, rutrum vitae dui. Suspendisse ac quam maximus nulla porta viverra scelerisque et ex. Phasellus egestas nunc vitae libero suscipit fringilla. Aenean sit amet feugiat lorem, sed porttitor quam.\n\nPhasellus massa magna, rhoncus vitae mauris non, maximus interdum dolor. Mauris et placerat nunc. Ut commodo ipsum id varius rutrum. Aliquam diam libero, lobortis non risus sollicitudin, mollis venenatis velit. Nulla facilisi. Sed at felis iaculis, posuere dolor et, vestibulum lorem. Nam et ante condimentum, aliquet metus a, vulputate sem. Duis augue ipsum, rutrum consequat pulvinar a, iaculis nec elit. Mauris eu dolor efficitur, vestibulum augue id, scelerisque ligula. Cras a egestas erat. Proin ultricies laoreet sagittis. Morbi maximus nibh urna, sed consequat arcu blandit eu. Pellentesque eget enim felis. Nunc gravida ligula ac magna ultricies consectetur. Donec elit nulla, pretium non nunc nec, ornare ullamcorper ipsum.\n\nAliquam eget posuere velit. Curabitur sit amet ipsum neque. Fusce molestie feugiat nisl, eu ornare elit luctus a. Fusce pulvinar molestie sapien, quis suscipit lectus viverra sed. Phasellus odio lorem, vehicula a justo id, vulputate accumsan nisi. Nulla porta est vel sem faucibus sagittis molestie pretium diam. Integer sem dolor, placerat eget aliquam et, gravida accumsan lorem. Integer porta velit sit amet dignissim lobortis. Ut a pharetra diam. Fusce gravida ex nec enim dapibus, sed lacinia metus pharetra. Pellentesque vehicula urna eu mi finibus placerat. Vivamus venenatis ante accumsan tellus auctor, quis ullamcorper sapien tempor. Suspendisse eget ligula maximus, fringilla lorem at, tristique leo. Suspendisse varius lectus id erat dapibus, ac laoreet arcu ultricies.\n\nCras pellentesque sem a dignissim ullamcorper. Aliquam gravida consequat nunc quis tristique. Donec vulputate lectus in enim porta, eu molestie dolor finibus. Aenean elementum vulputate interdum. Nullam mollis ex diam, nec auctor ante vulputate ac. Sed vulputate libero tortor, nec dictum diam ultrices vel. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Etiam pellentesque risus sed urna tempor, eget imperdiet erat porttitor. Donec sodales tellus at lacus maximus porttitor. Nunc vel lobortis nunc. Cras finibus erat id rhoncus feugiat."
  },
  {
    "path": "app/src/test/resources/raw/include.txt",
    "content": "Sed ac accumsan justo, vel sagittis nulla. Aenean pretium ante nec luctus vulputate. Fusce et blandit nisl. Cras id bibendum magna. Duis neque lacus, convallis rutrum auctor at, molestie eget ipsum. Etiam ut risus nec diam vulputate pretium a id sem. Duis ut consectetur sapien. Sed dui nunc, semper eu purus eu, interdum vehicula nisi. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Aliquam eros lacus, tristique aliquam luctus a, tincidunt sed dui. Phasellus pretium mauris vitae augue feugiat, vitae gravida ligula maximus. Maecenas at ex vitae nisi pulvinar aliquam non eu sapien. Aliquam erat volutpat. Nunc eleifend leo elit, vitae tempus lectus dignissim sollicitudin. Maecenas ut tortor nec lectus elementum porta. Phasellus laoreet sodales sodales.\n\nPraesent facilisis sed nulla ac condimentum. Praesent pretium tempor nibh, at ornare risus feugiat in. Cras scelerisque pretium erat. Nullam non odio mattis, commodo odio sed, condimentum arcu. In sit amet imperdiet tellus. Morbi ultrices viverra dignissim. Fusce dui nisi, lobortis condimentum viverra ac, sagittis a tellus. Proin vitae interdum sem, at lobortis augue. Nullam volutpat blandit magna vitae bibendum. In a nisl rhoncus, interdum tortor in, porta eros. Suspendisse sem justo, pellentesque a aliquet nec, rutrum vitae dui. Suspendisse ac quam maximus nulla porta viverra scelerisque et ex. Phasellus egestas nunc vitae libero suscipit fringilla. Aenean sit amet feugiat lorem, sed porttitor quam.\n\nPhasellus massa magna, rhoncus vitae mauris non, maximus interdum dolor. Mauris et placerat nunc. Ut commodo ipsum id varius rutrum. Aliquam diam libero, lobortis non risus sollicitudin, mollis venenatis velit. Nulla facilisi. Sed at felis iaculis, posuere dolor et, vestibulum lorem. Nam et ante condimentum, aliquet metus a, vulputate sem. Duis augue ipsum, rutrum consequat pulvinar a, iaculis nec elit. Mauris eu dolor efficitur, vestibulum augue id, scelerisque ligula. Cras a egestas erat. Proin ultricies laoreet sagittis. Morbi maximus nibh urna, sed consequat arcu blandit eu. Pellentesque eget enim felis. Nunc gravida ligula ac magna ultricies consectetur. Donec elit nulla, pretium non nunc nec, ornare ullamcorper ipsum.\n\nAliquam eget posuere velit. Curabitur sit amet ipsum neque. Fusce molestie feugiat nisl, eu ornare elit luctus a. Fusce pulvinar molestie sapien, quis suscipit lectus viverra sed. Phasellus odio lorem, vehicula a justo id, vulputate accumsan nisi. Nulla porta est vel sem faucibus sagittis molestie pretium diam. Integer sem dolor, placerat eget aliquam et, gravida accumsan lorem. Integer porta velit sit amet dignissim lobortis. Ut a pharetra diam. Fusce gravida ex nec enim dapibus, sed lacinia metus pharetra. Pellentesque vehicula urna eu mi finibus placerat. Vivamus venenatis ante accumsan tellus auctor, quis ullamcorper sapien tempor. Suspendisse eget ligula maximus, fringilla lorem at, tristique leo. Suspendisse varius lectus id erat dapibus, ac laoreet arcu ultricies.\n\nCras pellentesque sem a dignissim ullamcorper. Aliquam gravida consequat nunc quis tristique. Donec vulputate lectus in enim porta, eu molestie dolor finibus. Aenean elementum vulputate interdum. Nullam mollis ex diam, nec auctor ante vulputate ac. Sed vulputate libero tortor, nec dictum diam ultrices vel. Class aptent taciti sociosqu ad litora torquent per conubia nostra, per inceptos himenaeos. Etiam pellentesque risus sed urna tempor, eget imperdiet erat porttitor. Donec sodales tellus at lacus maximus porttitor. Nunc vel lobortis nunc. Cras finibus erat id rhoncus feugiat."
  },
  {
    "path": "app/src/test/resources/robolectric.properties",
    "content": "sdk=35\nshadows=io.github.muntashirakon.test.shadows.ShadowOsConstants,io.github.muntashirakon.test.shadows.ShadowOwners,io.github.muntashirakon.test.shadows.ShadowPackageInstallerCompat,io.github.muntashirakon.test.shadows.ShadowPackageManagerCompat,io.github.muntashirakon.test.shadows.ShadowDeviceIdleManagerCompat,io.github.muntashirakon.test.shadows.ShadowBackupDataDirectoryInfo,io.github.muntashirakon.io.ShadowLocalFileOverlay"
  },
  {
    "path": "app/src/test/resources/xml/HMS_Core_Android_Manifest.man.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest\n  xmlns:android=\"http://schemas.android.com/apk/res/android\"\n  android:versionCode=\"50001204\"\n  android:versionName=\"5.0.1.204\"\n  android:compileSdkVersion=\"28\"\n  android:compileSdkVersionCodename=\"9\"\n  package=\"com.huawei.hwid\"\n  platformBuildVersionCode=\"50001204\"\n  platformBuildVersionName=\"5.0.1.204\">\n  <uses-sdk\n    android:minSdkVersion=\"19\"\n    android:targetSdkVersion=\"28\">\n  </uses-sdk>\n  <permission\n    android:name=\"com.huawei.hms.kit.awareness.PERMISSION\"\n    android:protectionLevel=\"signature\">\n  </permission>\n  <uses-permission\n    android:name=\"com.huawei.hms.kit.awareness.PERMISSION\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"android.permission.ACCESS_NETWORK_STATE\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"android.permission.ACCESS_WIFI_STATE\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"android.permission.BLUETOOTH\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"android.permission.BLUETOOTH_ADMIN\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"android.permission.ACCESS_COARSE_LOCATION\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"android.permission.ACCESS_FINE_LOCATION\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"android.permission.CHANGE_WIFI_STATE\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"android.permission.WRITE_EXTERNAL_STORAGE\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"android.permission.READ_EXTERNAL_STORAGE\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"android.permission.INTERNET\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"android.permission.LOCAL_MAC_ADDRESS\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"android.permission.REQUEST_INSTALL_PACKAGES\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"com.huawei.appmarket.service.commondata.permission.GET_COMMON_DATA\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"com.huawei.permission.sec.ACCESS_UDID\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"android.permission.BODY_SENSORS\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"android.permission.CAMERA\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"android.permission.USE_FACERECOGNITION\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"android.permission.USE_BIOMETRIC\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"android.permission.NFC\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"android.permission.BLUETOOTH_PRIVILEGED\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"huawei.android.permission.HW_SIGNATURE_OR_SYSTEM\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"android.permission.USE_FINGERPRINT\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"android.permission.MANAGE_FINGERPRINT\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"com.huawei.android.permission.ACCESS_BIND_MSDP_MOVEMENT_SERVICE\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"android.permission.WAKE_LOCK\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"android.permission.ACCESS_BACKGROUND_LOCATION\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"android.permission.READ_PHONE_STATE\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"com.huawei.permission.sec.MDM.v2\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"android.permission.READ_PRIVILEGED_PHONE_STATE\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"com.huawei.permission.ACCESS_HW_KEYSTORE\">\n  </uses-permission>\n  <permission\n    android:name=\"com.huawei.android.permission.INNER_RECEIVER\"\n    android:protectionLevel=\"signatureOrSystem\">\n  </permission>\n  <uses-permission\n    android:name=\"com.huawei.android.permission.INNER_RECEIVER\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"com.huawei.permission.push.ACCESS_BIND_SERVICE\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"com.huawei.push.permission.HMS_OPERATION\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"android.permission.HIDE_NON_SYSTEM_OVERLAY_WINDOWS\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"com.huawei.lbs.permission.BIND_HMS_SERVICE\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"android.permission.UPDATE_APP_OPS_STATS\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"android.permission.UPDATE_DEVICE_STATS\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"android.permission.WRITE_SECURE_SETTINGS\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"android.permission.WRITE_SETTINGS\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"com.huawei.android.powerkit.permission.BIND\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"com.huawei.android.powerkit.permission.STATECHG\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"com.huawei.lbs.permission.ACCESS_BIND_LBSSERVICE\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"com.huawei.android.permission.ACCESS_BIND_ARSERVICE\">\n  </uses-permission>\n  <permission\n    android:name=\"com.huawei.lbs.permission.LBS_SERVICE_GEOFENCE_ACTION\"\n    android:protectionLevel=\"signatureOrSystem\">\n  </permission>\n  <uses-permission\n    android:name=\"com.huawei.lbs.permission.LBS_SERVICE_GEOFENCE_ACTION\">\n  </uses-permission>\n  <permission\n    android:name=\"com.huawei.hms.location.permission.PENDINGINTENT\"\n    android:protectionLevel=\"signatureOrSystem\">\n  </permission>\n  <uses-permission\n    android:name=\"com.huawei.hms.location.permission.PENDINGINTENT\">\n  </uses-permission>\n  <permission\n    android:label=\"@0x7f0b0199\"\n    android:name=\"com.huawei.hms.permission.ACTIVITY_RECOGNITION\"\n    android:protectionLevel=\"dangerous\"\n    android:description=\"@0x7f0b0198\">\n  </permission>\n  <uses-permission\n    android:name=\"com.huawei.hms.permission.ACTIVITY_RECOGNITION\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"android.permission.PACKAGE_USAGE_STATS\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"android.permission.INTERACT_ACROSS_USERS\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"android.permission.MANAGE_USERS\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"android.permission.SET_ACTIVITY_WATCHER\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"com.huawei.permission.ACTIVITY_NOTIFIER_PERMISSION\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"com.huawei.iaware.DATABASE_READ_PERMISSION\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"com.huawei.iaware.DATABASE_WRITE_PERMISSION\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"com.huawei.health.permission.HW_HEALTH_CLIENT\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"com.huawei.dataprivacycenter.permission.LAUNCH_DATA_PRIVACY_CENTER\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"android.permission.AUTHENTICATE_ACCOUNTS\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"android.permission.GET_ACCOUNTS\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"android.permission.MANAGE_ACCOUNTS\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"android.permission.USE_CREDENTIALS\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"android.permission.VIBRATE\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"android.permission.MODIFY_PHONE_STATE\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"com.huawei.appmarket.provider.readPermission\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"android.permission.READ_SMS\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"android.permission.STATUS_BAR\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"com.huawei.hicloud.permission.LAUNCHER_ACTIVITY\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"com.huawei.authentication.HW_ACCESS_AUTH_SERVICE\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"com.huawei.hicloud.permission.STARTUPGUIDE\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"com.huawei.android.permission.photoshareconfig\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"com.huawei.hicloud.permission.hicloudLogin\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"com.huawei.deviceattestation.HW_DEVICE_ATTESTATION_ACCESS\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"android.permission.INSTALL_PACKAGES\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"com.huawei.permission.GET_LOCK_PASSWORD_CHANGED\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"com.huawei.hwid.permission.FAMILY_SHARE\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"com.huawei.android.permission.ANTITHEFT\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"android.permission.READ_CONTACTS\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"com.huawei.parentcontrol.permission.provider\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"com.huawei.fingerprint.permission.USER_INTERACTIVE\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"com.huawei.wallet.permission.COMMON_SYS_OR_SIG\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"com.huawei.android.thememanager.permission.THEME_PROVIDER_ACCESS\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"com.huawei.android.thememanager.permission.THEMEMANAGER_INTERFACE\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"huawei.permission.CLICK_STATUSBAR_BROADCAST\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"android.permission.FLASHLIGHT\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"com.huawei.permission.SECURITY_DIAGNOSE\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"com.huawei.systemmanager.permission.ACCESS_INTERFACE\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"com.huawei.permission.BEHAVIOR_COLLECT\">\n  </uses-permission>\n  <permission\n    android:label=\"Allow read content provider\"\n    android:name=\"com.huawei.hwid.permission.gameservice.inshowbuoylist.provider\"\n    android:protectionLevel=\"signatureOrSystem\">\n  </permission>\n  <permission\n    android:label=\"Allow read content provider\"\n    android:name=\"com.huawei.hwid.permission.gameservice.buoy.provider\"\n    android:protectionLevel=\"signatureOrSystem\">\n  </permission>\n  <permission\n    android:label=\"Allow read content provider\"\n    android:name=\"com.huawei.hwid.permission.gameservice.archive.access.provider\"\n    android:protectionLevel=\"normal\"\n    android:description=\"@0x7f0b0efd\">\n  </permission>\n  <uses-permission\n    android:name=\"com.huawei.gameassistant.permission.gameservice.ingameassistant.provider\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"com.huawei.appmarket.permission.gameservice.subaccount.provider\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"com.huawei.gamebox.permission.gameservice.subaccount.provider\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"com.huawei.android.hms.innerservice.permission\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"com.huawei.appmarket.permission.THIRD_AGREEMENT_CHECK_PROVIDER_SERVICE\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"com.huawei.hwid.permission.ACCESS\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"com.huawei.hwid.permission.CONTENT_PROVIDER\">\n  </uses-permission>\n  <permission\n    android:label=\"@0x7f0b1111\"\n    android:name=\"com.huawei.android.sns.sdk.permission\"\n    android:protectionLevel=\"normal\"\n    android:description=\"@0x7f0b1111\">\n  </permission>\n  <permission\n    android:name=\"com.huawei.android.sns.permission.BACKUP\"\n    android:protectionLevel=\"signatureOrSystem\">\n  </permission>\n  <permission\n    android:name=\"com.huawei.android.sns.alarm.permission\"\n    android:protectionLevel=\"signatureOrSystem\">\n  </permission>\n  <uses-permission\n    android:name=\"com.huawei.android.sns.sdk.permission\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"com.huawei.android.sns.alarm.permission\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"com.huawei.android.permission.gallerysupportphotoshare\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"com.huawei.locationsharing.permission.START\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"android.permission.REORDER_TASKS\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"com.android.launcher.permission.INSTALL_SHORTCUT\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"com.android.launcher.permission.READ_SETTINGS\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"com.huawei.android.launcher.permission.READ_SETTINGS\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"com.huawei.launcher2.permission.READ_SETTINGS\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"com.huawei.launcher3.permission.READ_SETTINGS\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"com.android.launcher2.permission.READ_SETTINGS\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"com.huawei.launcher.permission.READ_SETTINGS\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"com.android.launcher.permission.UNINSTALL_SHORTCUT\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"android.permission.READ_MEDIA_AUDIO\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"android.permission.READ_MEDIA_IMAGES\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"android.permission.READ_MEDIA_VIDEO\">\n  </uses-permission>\n  <permission\n    android:name=\"com.huawei.permission.app.DOWNLOAD\"\n    android:protectionLevel=\"signatureOrSystem\">\n  </permission>\n  <uses-permission\n    android:name=\"android.permission.GET_TASKS\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"android.permission.REAL_GET_TASKS\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"com.huawei.permission.app.DOWNLOAD\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"androidx.ads.identifier.provider.HIGH_PRIORITY\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"android.permission.SYSTEM_OVERLAY_WINDOW\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"android.permission.INTERNAL_SYSTEM_WINDOW\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"android.permission.STATUS_BAR_SERVICE\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"android.permission.EXPAND_STATUS_BAR\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"android.permission.READ_SEARCH_INDEXABLES\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"com.huawei.permission.external_app_settings.USE_COMPONENT\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"com.huawei.deskclock.broadcast.permission\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"android.permission.FOREGROUND_SERVICE\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"android.permission.RECEIVE_BOOT_COMPLETED\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"android.permission.READ_LOGS\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"com.huawei.permission.KIT_UPDATE_OVER\">\n  </uses-permission>\n  <permission\n    android:name=\"com.huawei.permission.userSwitch\"\n    android:protectionLevel=\"signature\">\n  </permission>\n  <uses-permission\n    android:name=\"com.huawei.permission.userSwitch\">\n  </uses-permission>\n  <permission\n    android:name=\"com.huawei.permission.KIT_UPDATE_OVER\"\n    android:protectionLevel=\"signature\">\n  </permission>\n  <permission\n    android:name=\"com.huawei.permission.innerbroadcast\"\n    android:protectionLevel=\"signature\">\n  </permission>\n  <uses-permission\n    android:name=\"com.huawei.permission.innerbroadcast\">\n  </uses-permission>\n  <permission\n    android:name=\"com.huawei.hms.permission.signature\"\n    android:protectionLevel=\"signature\">\n  </permission>\n  <uses-permission\n    android:name=\"com.huawei.hms.permission.signature\">\n  </uses-permission>\n  <permission\n    android:name=\"com.huawei.hms.permission.signatureOrSystem\"\n    android:protectionLevel=\"signatureOrSystem\">\n  </permission>\n  <uses-permission\n    android:name=\"com.huawei.hms.permission.signatureOrSystem\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"com.huawei.android.permission.ACCESS_HWBOOSTER_SERVICE\">\n  </uses-permission>\n  <permission\n    android:name=\"netDiag\"\n    android:protectionLevel=\"signatureOrSystem\">\n  </permission>\n  <uses-feature\n    android:name=\"android.hardware.camera\">\n  </uses-feature>\n  <uses-feature\n    android:name=\"android.hardware.camera.autofocus\">\n  </uses-feature>\n  <uses-permission\n    android:name=\"android.permission.FORCE_STOP_PACKAGES\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"android.permission.KILL_BACKGROUND_PROCESSES\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"com.huawei.android.hsf.permission.COPY_PACKAGE\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"com.huawei.push.permission.RESET_PUSH\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"android.permission.SYSTEM_ALERT_WINDOW\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"android.permission.CHANGE_NETWORK_STATE\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"android.permission.CREATE_USERS\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"android.permission.MANAGE_FACERECOGNITION\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"com.huawei.dataprivacycenter.permission.LAUNCH_APP_PRIVACY_STATEMENT\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"com.huawei.android.permission.VR\">\n  </uses-permission>\n  <uses-permission\n    android:name=\"com.huawei.vrservice.permission.VR\">\n  </uses-permission>\n  <supports-screens\n    android:anyDensity=\"true\"\n    android:smallScreens=\"true\"\n    android:normalScreens=\"true\"\n    android:largeScreens=\"true\"\n    android:resizeable=\"true\">\n  </supports-screens>\n  <application\n    android:theme=\"@0x7f130007\"\n    android:label=\"@0x7f0b0503\"\n    android:icon=\"@0x7f0802a8\"\n    android:name=\"com.huawei.hms.app.CoreApplication\"\n    android:manageSpaceActivity=\"com.huawei.hms.dynamic.module.manager.update.activity.ManageSpaceActivity\"\n    android:allowBackup=\"false\"\n    android:supportsRtl=\"true\"\n    android:directBootAware=\"true\"\n    android:networkSecurityConfig=\"@0x7f150013\"\n    android:appComponentFactory=\"android.support.v4.app.CoreComponentFactory\">\n    <meta-data\n      android:name=\"permission.reason.android.permission-group.CALENDAR\"\n      android:resource=\"@0x7f0b01b3\">\n    </meta-data>\n    <meta-data\n      android:name=\"permission.reason.android.permission-group.CAMERA\"\n      android:resource=\"@0x7f0b01b4\">\n    </meta-data>\n    <meta-data\n      android:name=\"permission.reason.android.permission-group.CONTACTS\"\n      android:resource=\"@0x7f0b01b5\">\n    </meta-data>\n    <meta-data\n      android:name=\"permission.reason.android.permission-group.LOCATION\"\n      android:resource=\"@0x7f0b01b6\">\n    </meta-data>\n    <meta-data\n      android:name=\"permission.reason.android.permission.READ_PHONE_STATE\"\n      android:resource=\"@0x7f0b01b7\">\n    </meta-data>\n    <meta-data\n      android:name=\"permission.reason.android.permission-group.SMS\"\n      android:resource=\"@0x7f0b01b8\">\n    </meta-data>\n    <meta-data\n      android:name=\"permission.reason.android.permission-group.STORAGE\"\n      android:resource=\"@0x7f0b01b9\">\n    </meta-data>\n    <meta-data\n      android:name=\"permission.reason.com.huawei.hms.permission.ACTIVITY_RECOGNITION\"\n      android:resource=\"@0x7f0b01ba\">\n    </meta-data>\n    <meta-data\n      android:name=\"permission.reason.android.permission-group.SENSORS\"\n      android:resource=\"@0x7f0b01bb\">\n    </meta-data>\n    <activity\n      android:theme=\"@style/Theme.Translucent.NoTitleBar\"\n      android:name=\"net.openid.appauth.AuthorizationManagementActivity\"\n      android:exported=\"false\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"layoutDirection|locale|orientation|screenLayout|screenSize|smallestScreenSize\">\n    </activity>\n    <meta-data\n      android:name=\"pushcore_version\"\n      android:value=\"HMS100101302\">\n    </meta-data>\n    <meta-data\n      android:name=\"hw.theme_type\"\n      android:value=\"273\">\n    </meta-data>\n    <meta-data\n      android:name=\"com.huawei.membership.grs_app_name\"\n      android:value=\"hms\">\n    </meta-data>\n    <meta-data\n      android:name=\"com.facebook.sdk.CodelessDebugLogEnabled\"\n      android:value=\"false\">\n    </meta-data>\n    <meta-data\n      android:name=\"com.facebook.sdk.AutoLogAppEventsEnabled\"\n      android:value=\"false\">\n    </meta-data>\n    <meta-data\n      android:name=\"com.facebook.sdk.AdvertiserIDCollectionEnabled\"\n      android:value=\"false\">\n    </meta-data>\n    <meta-data\n      android:name=\"FOSAFER_APPID\"\n      android:value=\"31283661\">\n    </meta-data>\n    <meta-data\n      android:name=\"FOSAFER_APPKEY\"\n      android:value=\"0b57172f-3785-4dc7-8c65-c63f202643b2\">\n    </meta-data>\n    <meta-data\n      android:name=\"com.huawei.hms.kit.api_level:hwid\"\n      android:value=\"5\">\n    </meta-data>\n    <meta-data\n      android:name=\"hwc-theme\"\n      android:value=\"androidhwext:style/Theme.Emui\">\n    </meta-data>\n    <meta-data\n      android:name=\"oplog_encrypt\"\n      android:value=\"1\">\n    </meta-data>\n    <activity\n      android:theme=\"@0x7f1301bb\"\n      android:name=\".manager.AccountManagerActivity\"\n      android:exported=\"false\"\n      android:excludeFromRecents=\"true\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"layoutDirection|locale|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui.Translucent\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light.NoActionBar\"\n      android:label=\"@0x7f0b001e\"\n      android:name=\".ui.common.login.RegisterResetVerifyEmailActivity\"\n      android:exported=\"false\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:windowSoftInputMode=\"stateAlwaysHidden\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui.NoActionBar\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"@0x7f0b0948\"\n      android:name=\".europe.common.SetRegisterBirthdayActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:windowSoftInputMode=\"stateAlwaysHidden\">\n      <intent-filter>\n        <action\n          android:name=\"com.huawei.hwid.SET_REGISTER_BIRTHDAY\">\n        </action>\n        <category\n          android:name=\"android.intent.category.DEFAULT\">\n        </category>\n      </intent-filter>\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bb\"\n      android:name=\".manager.accountmgr.auth.GetTokenActivity\"\n      android:exported=\"true\"\n      android:excludeFromRecents=\"true\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:windowSoftInputMode=\"stateHidden\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui.Translucent\">\n      </meta-data>\n      <intent-filter>\n        <action\n          android:name=\"com.huawei.hwid.GET_AUTH_TOKEN\">\n        </action>\n        <category\n          android:name=\"android.intent.category.DEFAULT\">\n        </category>\n      </intent-filter>\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bb\"\n      android:name=\".manager.accountmgr.AuthenticatorActivity\"\n      android:exported=\"false\"\n      android:excludeFromRecents=\"true\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui.Translucent\">\n      </meta-data>\n    </activity>\n    <activity\n      android:name=\".ui.common.login.MoreServiceActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\">\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"\"\n      android:icon=\"@0x7f0803de\"\n      android:name=\".ui.extend.setting.StartUpGuideLoginActivity\"\n      android:exported=\"true\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"layoutDirection|locale|mcc|mnc|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:windowSoftInputMode=\"adjustResize|stateHidden\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n      <intent-filter>\n        <action\n          android:name=\"com.huawei.hwid.START_BY_OOBE\">\n        </action>\n        <category\n          android:name=\"android.intent.category.DEFAULT\">\n        </category>\n      </intent-filter>\n      <intent-filter>\n        <action\n          android:name=\"com.huawei.hwid.STARTUP_GUIDE\">\n        </action>\n        <category\n          android:name=\"android.intent.category.DEFAULT\">\n        </category>\n      </intent-filter>\n      <intent-filter>\n        <action\n          android:name=\"com.huawei.hwid.ACTION_LOGINBIND_FINGERPRINT\">\n        </action>\n        <category\n          android:name=\"android.intent.category.DEFAULT\">\n        </category>\n      </intent-filter>\n      <intent-filter>\n        <action\n          android:name=\"com.huawei.hwid.ACTION_START_FOR_GOTO_ACCOUNTCENTER\">\n        </action>\n        <category\n          android:name=\"android.intent.category.DEFAULT\">\n        </category>\n      </intent-filter>\n      <intent-filter>\n        <action\n          android:name=\"com.huawei.hwid.ACTION_BIND_SECURE_PHONE_SUPPORT\">\n        </action>\n        <category\n          android:name=\"android.intent.category.DEFAULT\">\n        </category>\n      </intent-filter>\n      <intent-filter>\n        <action\n          android:name=\"com.android.settings.action.EXTRA_SETTINGS\">\n        </action>\n      </intent-filter>\n      <intent-filter>\n        <action\n          android:name=\"com.huawei.hwid.action.START_BY_OOBE_APP\">\n        </action>\n        <category\n          android:name=\"android.intent.category.DEFAULT\">\n        </category>\n      </intent-filter>\n      <intent-filter>\n        <action\n          android:name=\"android.intent.action.VIEW\">\n        </action>\n        <category\n          android:name=\"android.intent.category.DEFAULT\">\n        </category>\n        <category\n          android:name=\"android.intent.category.BROWSABLE\">\n        </category>\n        <data\n          android:scheme=\"hwid\">\n        </data>\n        <data\n          android:host=\"startup\">\n        </data>\n      </intent-filter>\n      <meta-data\n        android:name=\"com.android.settings.category\"\n        android:value=\"com.android.settings.category.accounts\">\n      </meta-data>\n      <meta-data\n        android:name=\"com.android.settings.title\"\n        android:resource=\"@0x7f0b001e\">\n      </meta-data>\n      <meta-data\n        android:name=\"com.android.settings.icon\"\n        android:resource=\"@0x7f0805be\">\n      </meta-data>\n    </activity>\n    <service\n      android:name=\".manager.accountmgr.HwAccMgrService\"\n      android:exported=\"false\"\n      android:process=\":remote\">\n      <intent-filter>\n        <action\n          android:name=\"android.accounts.AccountAuthenticator\">\n        </action>\n      </intent-filter>\n      <meta-data\n        android:name=\"android.accounts.AccountAuthenticator\"\n        android:resource=\"@0x7f150004\">\n      </meta-data>\n      <meta-data\n        android:name=\"android.accounts.AccountAuthenticator.customTokens\"\n        android:value=\"true\">\n      </meta-data>\n    </service>\n    <activity\n      android:theme=\"@0x7f1301bb\"\n      android:name=\".ui.extend.setting.LogoutAccountActivity\"\n      android:exported=\"true\"\n      android:excludeFromRecents=\"true\"\n      android:configChanges=\"layoutDirection|locale|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:windowSoftInputMode=\"stateHidden\">\n      <intent-filter>\n        <action\n          android:name=\"com.huawei.hwid.ACTION_LOGOUT\">\n        </action>\n        <category\n          android:name=\"android.intent.category.DEFAULT\">\n        </category>\n      </intent-filter>\n      <intent-filter>\n        <action\n          android:name=\"com.huawei.hwid.ACTION_LOGOUT_FOR_APP\">\n        </action>\n        <category\n          android:name=\"android.intent.category.DEFAULT\">\n        </category>\n      </intent-filter>\n      <intent-filter>\n        <action\n          android:name=\"com.huawei.hwid.ACTION_LOGOUT_FOR_APP_BY_USERID\">\n        </action>\n        <category\n          android:name=\"android.intent.category.DEFAULT\">\n        </category>\n      </intent-filter>\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui.Translucent\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:name=\".ui.UpgradeSuccessActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n      <intent-filter>\n        <action\n          android:name=\"com.huawei.third.ACTION_UPGRADE_SUCCESS\">\n        </action>\n        <category\n          android:name=\"android.intent.category.DEFAULT\">\n        </category>\n      </intent-filter>\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bb\"\n      android:name=\".ui.BindAccountActivity\"\n      android:exported=\"false\"\n      android:excludeFromRecents=\"true\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui.Translucent\">\n      </meta-data>\n      <intent-filter>\n        <action\n          android:name=\"com.huawei.third.ACTION_BIND_ACCOUNT\">\n        </action>\n        <category\n          android:name=\"android.intent.category.DEFAULT\">\n        </category>\n      </intent-filter>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"@0x7f0b09a7\"\n      android:name=\"com.huawei.familygrp.invitefamilygrp.InviteByUserAccountActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:windowSoftInputMode=\"adjustResize|stateHidden\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bb\"\n      android:name=\"com.huawei.familygrp.invitefamilygrp.InviteModleSelectActivity\"\n      android:exported=\"false\"\n      android:excludeFromRecents=\"true\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"layoutDirection|locale|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui.Translucent\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"@0x7f0b0693\"\n      android:name=\"com.huawei.familygrp.invitefamilygrp.InviteFamilyMemberActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"@0x7f0b05b9\"\n      android:name=\"com.huawei.familygrp.invitefamilygrp.InviteUserInfoActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <intent-filter>\n        <action\n          android:name=\"com.huawei.hwid.action.INVITE_USER_INFO\">\n        </action>\n        <category\n          android:name=\"android.intent.category.DEFAULT\">\n        </category>\n      </intent-filter>\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"@0x7f0b065d\"\n      android:name=\"com.huawei.familygrp.createchildaccount.FamilyPayShareActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"@0x7f0b022d\"\n      android:name=\".ui.OpenWexinFastLoginActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"layoutDirection|locale|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n      <intent-filter>\n        <category\n          android:name=\"android.intent.category.DEFAULT\">\n        </category>\n      </intent-filter>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"@0x7f0b01ed\"\n      android:name=\"com.huawei.hwid20.third.BindThirdAccountSuccessActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"layoutDirection|locale|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n      <intent-filter>\n        <category\n          android:name=\"android.intent.category.DEFAULT\">\n        </category>\n      </intent-filter>\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bb\"\n      android:name=\".wxapi.WXEntryActivity\"\n      android:exported=\"true\"\n      android:configChanges=\"layoutDirection|locale|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui.Translucent\">\n      </meta-data>\n      <intent-filter>\n        <action\n          android:name=\"android.intent.action.MAIN\">\n        </action>\n      </intent-filter>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"@0x7f0b02e7\"\n      android:name=\"com.huawei.hwid20.accountdetail.AccountDetailActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <intent-filter>\n        <action\n          android:name=\"com.huawei.hwid.ACTION_ACCOUNT_DETAIL\">\n        </action>\n        <category\n          android:name=\"android.intent.category.DEFAULT\">\n        </category>\n      </intent-filter>\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bb\"\n      android:name=\"com.huawei.hwid20.accountdetail.SetNickNameActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"layoutDirection|mcc|mnc|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <intent-filter>\n        <action\n          android:name=\"com.huawei.hwid.ACTION_SET_NICKNAME\">\n        </action>\n        <category\n          android:name=\"android.intent.category.DEFAULT\">\n        </category>\n      </intent-filter>\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui.Translucent\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"@0x7f0b0265\"\n      android:name=\"com.huawei.hwid20.AccountCenter.CenterActivity\"\n      android:exported=\"true\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:windowSoftInputMode=\"adjustPan|stateHidden\">\n      <intent-filter>\n        <action\n          android:name=\"com.huawei.hwid.ACTION_INNER_CENTER_ACTIVITY\">\n        </action>\n        <category\n          android:name=\"android.intent.category.DEFAULT\">\n        </category>\n      </intent-filter>\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"@0x7f0b018f\"\n      android:name=\"com.huawei.hwid20.accountdetail.DetailMoreActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"@0x7f0b02a1\"\n      android:name=\"com.huawei.hwid20.centermore.CenterMoreActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"@0x7f0b051b\"\n      android:name=\"com.huawei.hwid20.accountsecurity.AccountSecurityActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"@0x7f0b058d\"\n      android:name=\"com.huawei.hwid20.accountsecurity.BioRecognitionSwitchActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"@0x7f0b06b7\"\n      android:name=\"com.huawei.hwid20.accountsecurity.ThirdBindListActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"@0x7f0b052c\"\n      android:name=\"com.huawei.hwid20.accountsecurity.RebindThird2AcctActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"@0x7f0b026c\"\n      android:name=\".cloudsettings.ui.ThirdAccountUnbindActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:name=\".cloudsettings.ui.AccountChangeActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:label=\"@0x7f0b0291\"\n      android:name=\".cloudsettings.ui.HandlePhotoActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"keyboardHidden|layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <intent-filter>\n        <action\n          android:name=\"com.huawei.hwid.ACTION_TAKE_PICTURE\">\n        </action>\n        <category\n          android:name=\"android.intent.category.DEFAULT\">\n        </category>\n      </intent-filter>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Black\"\n      android:label=\"@0x7f0b0268\"\n      android:name=\".cloudsettings.ui.SetDefaultHeadImage\"\n      android:exported=\"false\"\n      android:configChanges=\"keyboardHidden|layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bb\"\n      android:name=\".fingerprint.ui.FingerAuthActivity\"\n      android:exported=\"true\"\n      android:excludeFromRecents=\"true\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:windowSoftInputMode=\"stateHidden\">\n      <intent-filter>\n        <action\n          android:name=\"com.huawei.hwid.FINGER_AUTH\">\n        </action>\n        <category\n          android:name=\"android.intent.category.DEFAULT\">\n        </category>\n      </intent-filter>\n      <intent-filter>\n        <action\n          android:name=\"com.huawei.hwid.ACTION_UNIFY_PASSWORD_VERIFY\">\n        </action>\n        <category\n          android:name=\"android.intent.category.DEFAULT\">\n        </category>\n      </intent-filter>\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui.Translucent\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bb\"\n      android:name=\".cloudsettings.ui.HuaweiIDForSettingsActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"layoutDirection|locale|mcc|mnc|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui.Translucent\">\n      </meta-data>\n      <intent-filter>\n        <action\n          android:name=\"com.android.settings.action.IA_SETTINGS\">\n        </action>\n        <category\n          android:name=\"android.intent.category.DEFAULT\">\n        </category>\n      </intent-filter>\n      <meta-data\n        android:name=\"hw_meta_tile_type\"\n        android:value=\"hwid_tile\">\n      </meta-data>\n      <meta-data\n        android:name=\"com.android.settings.category\"\n        android:value=\"com.android.settings.category.ia.homepage\">\n      </meta-data>\n      <meta-data\n        android:name=\"com.android.settings.icon\"\n        android:resource=\"@0x7f080084\">\n      </meta-data>\n      <meta-data\n        android:name=\"com.android.settings.title\"\n        android:resource=\"@0x7f0b0013\">\n      </meta-data>\n      <meta-data\n        android:name=\"com.android.settings.summary\"\n        android:resource=\"@0x7f0b0072\">\n      </meta-data>\n      <meta-data\n        android:name=\"com.android.settings.icon_uri\"\n        android:value=\"content://com.huawei.hwid.settings.provider/icon\">\n      </meta-data>\n      <meta-data\n        android:name=\"com.android.settings.title_uri\"\n        android:value=\"content://com.huawei.hwid.settings.provider/title\">\n      </meta-data>\n      <meta-data\n        android:name=\"com.android.settings.summary_uri\"\n        android:value=\"content://com.huawei.hwid.settings.provider/summary\">\n      </meta-data>\n      <meta-data\n        android:name=\"com.android.settings.badge_uri\"\n        android:value=\"content://com.huawei.hwid.settings.provider/badge\">\n      </meta-data>\n    </activity>\n    <provider\n      android:name=\"com.huawei.hwid20.provider.SettingsProvider\"\n      android:exported=\"false\"\n      android:authorities=\"com.huawei.hwid.settings.provider\">\n    </provider>\n    <provider\n      android:name=\"com.huawei.hwid20.provider.HwIDInnerProvider\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\"\n      android:authorities=\"com.huawei.hwid.inner.provider\">\n    </provider>\n    <provider\n      android:name=\".fingerprint.provider.HwIDProvider\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.core\"\n      android:authorities=\"com.huawei.hwid.api.provider\">\n    </provider>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"@0x7f0b0260\"\n      android:name=\".cloudsettings.ui.about.AboutAccountActivity\"\n      android:exported=\"false\"\n      android:excludeFromRecents=\"true\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:windowSoftInputMode=\"stateAlwaysHidden\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n      <intent-filter>\n        <action\n          android:name=\"com.huawei.hwid.ACTION_ABOUT_ACCOUNT\">\n        </action>\n        <category\n          android:name=\"android.intent.category.DEFAULT\">\n        </category>\n      </intent-filter>\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bb\"\n      android:name=\".ui.common.checkid.CheckIdentityActivity\"\n      android:exported=\"false\"\n      android:excludeFromRecents=\"true\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:windowSoftInputMode=\"stateHidden\">\n      <intent-filter>\n        <action\n          android:name=\"com.huawei.hwid.ACTION_CHECK_IDENTITY\">\n        </action>\n        <category\n          android:name=\"android.intent.category.DEFAULT\">\n        </category>\n      </intent-filter>\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui.Translucent\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bb\"\n      android:name=\"com.huawei.hwid20.loginseccode.verify.VerifyLoginSecCodeActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:windowSoftInputMode=\"stateHidden\">\n      <intent-filter>\n        <action\n          android:name=\"com.huawei.hwid.CHECK_LOGIN_IDENTITY\">\n        </action>\n        <category\n          android:name=\"android.intent.category.DEFAULT\">\n        </category>\n      </intent-filter>\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui.Translucent\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"@0x7f0b06d1\"\n      android:name=\"com.huawei.hwid20.loginseccode.seccode.LoginSecCodeActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:windowSoftInputMode=\"stateHidden\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bb\"\n      android:name=\".cloudsettings.ui.CheckUpdateApkActivity\"\n      android:exported=\"false\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <intent-filter>\n        <action\n          android:name=\"com.huawei.hwid.updateAPK\">\n        </action>\n        <category\n          android:name=\"android.intent.category.DEFAULT\">\n        </category>\n      </intent-filter>\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui.Translucent\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"@0x7f0b026e\"\n      android:name=\"com.huawei.hwid20.accountprotect.AccountProtectActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"@0x7f0b07eb\"\n      android:name=\"com.huawei.hwid20.accountprotect.SafeAccountActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"@0x7f0b026e\"\n      android:name=\"com.huawei.hwid20.accountprotect.OpenAccountProtectGuideActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"@0x7f0b026e\"\n      android:name=\".cloudsettings.ui.accoutprotect.AccountOprChoose\"\n      android:exported=\"false\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"@0x7f0b026e\"\n      android:name=\".cloudsettings.ui.accoutprotect.AccountOprEffectiveBindActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:name=\".europe.apk.child.ChildMngActivity\"\n      android:exported=\"false\"\n      android:excludeFromRecents=\"true\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:windowSoftInputMode=\"stateHidden\">\n      <intent-filter>\n        <action\n          android:name=\"com.huawei.hwid.ACTION_CHILD_MNG\">\n        </action>\n        <category\n          android:name=\"android.intent.category.DEFAULT\">\n        </category>\n      </intent-filter>\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bb\"\n      android:label=\"@0x7f0b061a\"\n      android:name=\".europe.common.CheckGuarderPwdActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <intent-filter>\n        <action\n          android:name=\"com.huawei.hwid.EUROPE_GUARDER_UID_AUTH\">\n        </action>\n        <category\n          android:name=\"android.intent.category.DEFAULT\">\n        </category>\n      </intent-filter>\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui.Translucent\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"@0x7f0b0010\"\n      android:name=\".europe.common.CountrySupportListActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"@0x7f0b097f\"\n      android:name=\".europe.apk.ui.ChildRegisterCheckGuarderPwdActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <intent-filter>\n        <action\n          android:name=\"com.huawei.hwid.EUROPE_CHILD_REGISTER_GUARDER_UID_AUTH\">\n        </action>\n        <category\n          android:name=\"android.intent.category.DEFAULT\">\n        </category>\n      </intent-filter>\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"@0x7f0b097f\"\n      android:name=\".europe.apk.ui.InviteChildCheckGuardianPwdActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"@0x7f0b0687\"\n      android:name=\"com.huawei.hwid20.accountsteps.CheckAccountPwdActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:windowSoftInputMode=\"adjustResize|stateVisible\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"@0x7f0b003c\"\n      android:name=\"com.huawei.hwid20.accountsteps.CheckMultiAuthCodeActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:windowSoftInputMode=\"adjustResize|stateVisible\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"@0x7f0b05e2\"\n      android:name=\"com.huawei.hwid20.accountsteps.CheckAccountActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"@0x7f0b003b\"\n      android:name=\"com.huawei.hwid20.accountsteps.SetPhoneNumberActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:windowSoftInputMode=\"adjustResize|stateVisible\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"@0x7f0b003a\"\n      android:name=\"com.huawei.hwid20.accountsteps.SetEmailAddrActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:windowSoftInputMode=\"adjustResize|stateVisible\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"@0x7f0b0913\"\n      android:name=\"com.huawei.hwid20.password.modifypassword.ModifyPassWordPreActvity\"\n      android:exported=\"false\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"@0x7f0b06b6\"\n      android:name=\"com.huawei.hwid20.password.modifypassword.ModifyPasswordActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:windowSoftInputMode=\"adjustResize|stateHidden\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:name=\".europe.apk.ui.WebViewSelfServiceActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <intent-filter>\n        <action\n          android:name=\"com.huawei.hwid.ACTION_SELFSERVICE\">\n        </action>\n        <category\n          android:name=\"android.intent.category.DEFAULT\">\n        </category>\n      </intent-filter>\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:label=\"@0x7f0b0617\"\n      android:name=\".europe.apk.datacopy.GetAccoutDataActivity\"\n      android:exported=\"false\"\n      android:excludeFromRecents=\"true\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:windowSoftInputMode=\"stateHidden\">\n      <intent-filter>\n        <action\n          android:name=\"com.huawei.hwid.ACTION_RECEIVE_INFO\">\n        </action>\n        <category\n          android:name=\"android.intent.category.DEFAULT\">\n        </category>\n      </intent-filter>\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"@0x7f0b02d1\"\n      android:name=\".social.apk.ui.ChooseAreaActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <intent-filter>\n        <action\n          android:name=\"com.huawei.hwid.ACTION_CHOOSE_AREA\">\n        </action>\n        <category\n          android:name=\"android.intent.category.DEFAULT\">\n        </category>\n      </intent-filter>\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"@0x7f0b02e9\"\n      android:name=\".social.apk.ui.LocationAgreementActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"@0x7f0b02d1\"\n      android:name=\".social.apk.ui.CityActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"@0x7f0b018b\"\n      android:name=\"com.huawei.hwid20.setting.AccountCenterSettingActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <intent-filter>\n        <action\n          android:name=\"com.huawei.hwid.ACTION_ACCOUNT_CENTER_SETTING\">\n        </action>\n        <category\n          android:name=\"android.intent.category.DEFAULT\">\n        </category>\n      </intent-filter>\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"@0x7f0b02da\"\n      android:name=\"com.huawei.hwid20.setting.SocialMessageSettingActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Translucent.NoTitleBar\"\n      android:label=\"@0x7f0b001e\"\n      android:name=\"com.google.android.gms.auth.api.signin.internal.SignInHubActivity\"\n      android:exported=\"false\"\n      android:excludeFromRecents=\"true\"\n      android:configChanges=\"keyboard|keyboardHidden|layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bb\"\n      android:name=\"net.openid.appauth.RedirectUriReceiverActivity\"\n      android:exported=\"true\"\n      android:configChanges=\"layoutDirection|locale|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <intent-filter>\n        <action\n          android:name=\"android.intent.action.VIEW\">\n        </action>\n        <category\n          android:name=\"android.intent.category.DEFAULT\">\n        </category>\n        <category\n          android:name=\"android.intent.category.BROWSABLE\">\n        </category>\n        <data\n          android:scheme=\"com.googleusercontent.apps.388076668644-2tv6uncn7tkc36nh75lfmksocrhvvi85\">\n        </data>\n      </intent-filter>\n    </activity>\n    <meta-data\n      android:name=\"com.facebook.sdk.ApplicationId\"\n      android:value=\"@0x7f0b03bc\">\n    </meta-data>\n    <activity\n      android:theme=\"@0x7f1301bb\"\n      android:name=\".cloudsettings.ui.LoginByPasswordActivity\"\n      android:exported=\"false\"\n      android:excludeFromRecents=\"true\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"layoutDirection|locale|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <intent-filter>\n        <action\n          android:name=\"com.huawei.hwid.ACTION_LOGIN_BY_PWD\">\n        </action>\n        <category\n          android:name=\"android.intent.category.DEFAULT\">\n        </category>\n      </intent-filter>\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui.Translucent\">\n      </meta-data>\n    </activity>\n    <activity\n      android:label=\"@0x7f0b027f\"\n      android:name=\".cloudsettings.ui.ChoosePicAlbumActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"keyboardHidden|layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\">\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"@0x7f0b0213\"\n      android:name=\".ui.extend.setting.QrCodeSTLoginActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <intent-filter>\n        <action\n          android:name=\"com.huawei.hwid.action.AUTH_LOGIN\">\n        </action>\n        <category\n          android:name=\"android.intent.category.DEFAULT\">\n        </category>\n      </intent-filter>\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bb\"\n      android:name=\"com.huawei.hwid20.unifyexport.UnifyExportActivity\"\n      android:exported=\"true\"\n      android:excludeFromRecents=\"true\"\n      android:configChanges=\"layoutDirection|locale|mcc|mnc|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui.Translucent\">\n      </meta-data>\n      <intent-filter>\n        <action\n          android:name=\"android.intent.action.VIEW\">\n        </action>\n        <category\n          android:name=\"android.intent.category.DEFAULT\">\n        </category>\n        <category\n          android:name=\"android.intent.category.BROWSABLE\">\n        </category>\n        <data\n          android:scheme=\"hwid\">\n        </data>\n        <data\n          android:host=\"com.huawei.hwid\">\n        </data>\n      </intent-filter>\n      <intent-filter>\n        <action\n          android:name=\"com.huawei.hwid.AgreeUpdate\">\n        </action>\n        <category\n          android:name=\"android.intent.category.DEFAULT\">\n        </category>\n      </intent-filter>\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bb\"\n      android:name=\".ui.extend.setting.LoginBySDKActivity\"\n      android:exported=\"true\"\n      android:excludeFromRecents=\"true\"\n      android:configChanges=\"layoutDirection|locale|mcc|mnc|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui.Translucent\">\n      </meta-data>\n      <intent-filter>\n        <action\n          android:name=\"com.huawei.hwid.LOGIN_BY_SDK\">\n        </action>\n        <category\n          android:name=\"android.intent.category.DEFAULT\">\n        </category>\n      </intent-filter>\n    </activity>\n    <service\n      android:name=\".ui.extend.setting.GetCloudListService\"\n      android:exported=\"false\">\n    </service>\n    <service\n      android:name=\".simchange.service.SimChangeService\"\n      android:exported=\"false\">\n    </service>\n    <service\n      android:name=\".cloudsettings.services.CloudAccountService\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.core\">\n      <intent-filter>\n        <action\n          android:name=\"com.huawei.hwid.ICloudService\">\n        </action>\n      </intent-filter>\n    </service>\n    <meta-data\n      android:name=\"MEMBERSDK_CHANNEL\"\n      android:value=\"100003\">\n    </meta-data>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"@0x7f0b05a2\"\n      android:name=\".cloudsettings.ui.servicecountry.ServiceCountryChangeActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bb\"\n      android:name=\".cloudsettings.ui.servicecountry.RemoteAccessAuthorizeActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui.Translucent\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"@0x7f0b089f\"\n      android:name=\"com.huawei.hwid20.devicemanager.AccountDeviceManagerActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:name=\"com.huawei.hwid20.devicemanager.AccountDeviceDetailActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:windowSoftInputMode=\"adjustPan|stateHidden\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"@0x7f0b06c6\"\n      android:name=\"com.huawei.hwid20.mydevicemanager.homepage.MyDeviceManagerActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:name=\"com.huawei.hwid20.mydevicemanager.MyDeviceManagerDetailActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:windowSoftInputMode=\"adjustPan|stateHidden\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:name=\"com.tencent.tauth.AuthActivity\"\n      android:exported=\"false\"\n      android:launchMode=\"singleTask\"\n      android:noHistory=\"true\">\n      <intent-filter>\n        <action\n          android:name=\"android.intent.action.VIEW\">\n        </action>\n        <category\n          android:name=\"android.intent.category.DEFAULT\">\n        </category>\n        <category\n          android:name=\"android.intent.category.BROWSABLE\">\n        </category>\n        <data\n          android:scheme=\"209207\">\n        </data>\n      </intent-filter>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Translucent.NoTitleBar\"\n      android:name=\"com.tencent.connect.common.AssistActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"keyboardHidden|layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bb\"\n      android:name=\"com.huawei.hwid20.push.PushDialogActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui.Translucent\">\n      </meta-data>\n      <intent-filter>\n        <action\n          android:name=\"com.huawei.hwid20.push.PUSH_DIALOG\">\n        </action>\n        <category\n          android:name=\"android.intent.category.DEFAULT\">\n        </category>\n      </intent-filter>\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bb\"\n      android:name=\"com.huawei.hwid20.figureverifycode.FigureVerifyCodeActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui.Translucent\">\n      </meta-data>\n      <intent-filter>\n        <action\n          android:name=\"com.huawei.hwid20.figureverifycode.FigureVerifyCode\">\n        </action>\n        <category\n          android:name=\"android.intent.category.DEFAULT\">\n        </category>\n      </intent-filter>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"@0x7f0b083a\"\n      android:name=\"com.huawei.hwid20.RealNameVerify.RealNameActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"@0x7f0b083a\"\n      android:name=\"com.huawei.hwid20.RealNameVerify.RealNameConfirmActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"@0x7f0b077f\"\n      android:name=\"com.huawei.hwid20.RealNameVerify.RealNameInfoActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:name=\"com.huawei.hwid20.inputrealname.RealNameCleanListActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"@0x7f0b083a\"\n      android:name=\"com.huawei.hwid20.RealNameVerify.RealNameIDVerifyActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"@0x7f0b083a\"\n      android:name=\"com.huawei.hwid20.RealNameVerify.RealNameIDVerifySuccessActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"@0x7f0b074f\"\n      android:name=\"com.huawei.hwid20.RealNameVerify.RealNameUnbindOtherAccountActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"@0x7f0b071e\"\n      android:name=\"com.huawei.hwid20.RealNameVerify.RealNameCleanOrUnbindResultActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:name=\"com.huawei.hwid20.RealNameVerify.RealNameSendPoliceActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"@0x7f0b083a\"\n      android:name=\"com.huawei.hwid20.RealNameVerify.RealNameIDVerifyFailedActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bb\"\n      android:name=\"com.huawei.hwid20.accountprotect.AccountProtectSettingsSuggestionActivity\"\n      android:enabled=\"false\"\n      android:exported=\"false\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <intent-filter\n        android:priority=\"1\">\n        <action\n          android:name=\"android.intent.action.MAIN\">\n        </action>\n        <category\n          android:name=\"com.android.settings.suggested.category.SETTINGS_ONLY\">\n        </category>\n      </intent-filter>\n      <meta-data\n        android:name=\"com.android.settings.icon\"\n        android:resource=\"@0x7f0803df\">\n      </meta-data>\n      <meta-data\n        android:name=\"com.android.settings.title\"\n        android:resource=\"@0x7f0b0004\">\n      </meta-data>\n      <meta-data\n        android:name=\"com.android.settings.summary\"\n        android:resource=\"@0x7f0b0005\">\n      </meta-data>\n      <meta-data\n        android:name=\"com.android.settings.dismiss\"\n        android:value=\"0,7,14\">\n      </meta-data>\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui.Translucent\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"@0x7f0b08c6\"\n      android:name=\"com.huawei.hwid20.homecountry.HomeCountryGuideActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"@0x7f0b077f\"\n      android:name=\"com.huawei.hwid20.RealNameVerify.RealNameManualInfoActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"@0x7f0b08c6\"\n      android:name=\"com.huawei.hwid20.homecountry.HomeCountryChangeAllowedActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"@0x7f0b08c6\"\n      android:name=\"com.huawei.hwid20.homecountry.HomeCountryChangeFailActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bb\"\n      android:name=\"com.huawei.hwid20.accountfrozen.AccountFrozenActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui.Translucent\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bb\"\n      android:name=\"com.huawei.hwid20.accountsteps.AccountIdentityActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:windowSoftInputMode=\"stateHidden\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui.Translucent\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bb\"\n      android:name=\".ui.common.login.SetLoginBirthdayActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:windowSoftInputMode=\"stateHidden\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui.Translucent\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"@0x7f0b0681\"\n      android:name=\"com.huawei.hwid20.accountsteps.AccountIdentitySelectActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"@0x7f0b09be\"\n      android:name=\"com.huawei.hwid20.engine.loginbysms.LoginVerifyPasswordActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"@0x7f0b01f0\"\n      android:name=\"com.huawei.hwid20.password.setpassword.SetPasswordActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"@0x7f0b05a2\"\n      android:name=\"com.huawei.hwid20.login.countrylist.ChooseCountryActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:windowSoftInputMode=\"adjustPan|stateHidden\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"@0x7f0b09c5\"\n      android:name=\"com.huawei.hwid20.verify.VerifyMobilePhonePromptActivity\"\n      android:exported=\"false\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"@0x7f0b0131\"\n      android:name=\"com.huawei.familygrp.creategrp.CreateGrpActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"layoutDirection|locale|mcc|mnc|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"@0x7f0b0075\"\n      android:name=\"com.huawei.familygrp.purchasesharing.PurchaseSharingActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"layoutDirection|locale|mcc|mnc|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <intent-filter>\n        <action\n          android:name=\"com.huawei.hwid.action.PURCHASE_SHARING\">\n        </action>\n        <category\n          android:name=\"android.intent.category.DEFAULT\">\n        </category>\n      </intent-filter>\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n      <meta-data\n        android:name=\"com.huawei.hwid.familyshare.menu\"\n        android:resource=\"@0x7f0b0075\">\n      </meta-data>\n      <meta-data\n        android:name=\"com.huawei.hwid.familyshare.menu.icon\"\n        android:resource=\"@0x7f080351\">\n      </meta-data>\n      <meta-data\n        android:name=\"com.huawei.hwid.familyshare.menu.summary\"\n        android:resource=\"@0x7f0b0076\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"@0x7f0b0075\"\n      android:name=\"com.huawei.familygrp.purchasesharing.PurchaseSharingDetailActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"@0x7f0b012f\"\n      android:name=\"com.huawei.familygrp.creategrp.GrpListActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"@0x7f0b0657\"\n      android:name=\"com.huawei.hwid20.AccountCenter.UpdateUserInfoActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"@0x7f0b09a7\"\n      android:name=\"com.huawei.familygrp.homepage.FamilyGrpHomePageActivity\"\n      android:exported=\"false\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"@0x7f0b09a7\"\n      android:name=\"com.huawei.familygrp.checkfamilymember.CheckFamilyMemberActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:windowSoftInputMode=\"adjustResize|stateHidden\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"@0x7f0b09a9\"\n      android:name=\"com.huawei.familygrp.invitedtofamilygrp.InvitedToFamilyGrpActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"@0x7f0b0658\"\n      android:name=\"com.huawei.familygrp.NotifyList.NotifyListActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <provider\n      android:name=\".fingerprint.provider.HwIDFileProvider\"\n      android:exported=\"false\"\n      android:authorities=\"com.huawei.hwid.fileProvider\"\n      android:grantUriPermissions=\"true\">\n      <meta-data\n        android:name=\"android.support.FILE_PROVIDER_PATHS\"\n        android:resource=\"@0x7f15000b\">\n      </meta-data>\n    </provider>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"@0x7f0b0593\"\n      android:name=\"com.huawei.hwid20.childmanager.CreateChildAccountActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bb\"\n      android:name=\"com.huawei.hwid20.AccountCenter.JumpCenterFromSdkActivity\"\n      android:exported=\"true\"\n      android:excludeFromRecents=\"true\"\n      android:configChanges=\"layoutDirection|locale|mcc|mnc|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui.Translucent\">\n      </meta-data>\n      <intent-filter>\n        <action\n          android:name=\"com.huawei.hwid.ACTION_MAIN_SETTINGS\">\n        </action>\n        <category\n          android:name=\"android.intent.category.DEFAULT\">\n        </category>\n      </intent-filter>\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bb\"\n      android:name=\".update.BridgeActivity\"\n      android:exported=\"false\"\n      android:excludeFromRecents=\"true\"\n      android:configChanges=\"fontScale|layoutDirection|locale|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:hardwareAccelerated=\"true\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui.Translucent\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"@0x7f0b05c5\"\n      android:name=\"com.huawei.hwid20.emergencycontact.EmergencyContactActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:windowSoftInputMode=\"adjustPan|stateHidden\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:name=\"com.huawei.hwid20.emergencycontact.EmergencyContactSelectActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:windowSoftInputMode=\"adjustPan|stateHidden\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bb\"\n      android:name=\"com.huawei.hwid20.wlanwarning.WlanJumpWarningActivity\"\n      android:exported=\"true\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:windowSoftInputMode=\"stateHidden\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui.Translucent\">\n      </meta-data>\n      <intent-filter>\n        <action\n          android:name=\"com.huawei.hwid.WLAN_JUMP_WARNING\">\n        </action>\n        <category\n          android:name=\"android.intent.category.DEFAULT\">\n        </category>\n      </intent-filter>\n    </activity>\n    <activity\n      android:name=\"com.huawei.hwid20.scancode.ScanCodeSkipActivity\"\n      android:exported=\"false\"\n      android:screenOrientation=\"portrait\"\n      android:configChanges=\"keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:windowSoftInputMode=\"stateHidden\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui.NoActionBar\">\n      </meta-data>\n      <intent-filter>\n        <action\n          android:name=\"com.huawei.hwid.ACTION_SCAN_CODE\">\n        </action>\n        <category\n          android:name=\"android.intent.category.DEFAULT\">\n        </category>\n      </intent-filter>\n    </activity>\n    <activity\n      android:name=\"com.huawei.hwid20.scancode.ScanCodeActivity\"\n      android:exported=\"false\"\n      android:screenOrientation=\"portrait\"\n      android:configChanges=\"keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:windowSoftInputMode=\"stateHidden\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui.NoActionBar\">\n      </meta-data>\n    </activity>\n    <activity\n      android:name=\"com.huawei.hwid20.third.BindThirdAccountErrorActivity\"\n      android:configChanges=\"screenLayout|screenSize|smallestScreenSize\">\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light.NoActionBar\"\n      android:name=\".cloudsettings.ui.SecurityDetectActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui.NoActionBar\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:name=\"com.huawei.familygrp.openchildmode.CreateChildModeActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bb\"\n      android:name=\".ui.common.login.LoginGuideOpenBioAuthActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui.Translucent\">\n      </meta-data>\n      <intent-filter>\n        <action\n          android:name=\"com.huawei.hwid.ACTION_OPEN_BIO\">\n        </action>\n        <category\n          android:name=\"android.intent.category.DEFAULT\">\n        </category>\n      </intent-filter>\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bb\"\n      android:name=\"com.huawei.hwid20.inputrealname.InputRealNameActivity\"\n      android:exported=\"false\"\n      android:excludeFromRecents=\"true\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui.Translucent\">\n      </meta-data>\n    </activity>\n    <meta-data\n      android:name=\"huawei_module_scankit_local\"\n      android:value=\"1030100\">\n    </meta-data>\n    <meta-data\n      android:name=\"huawei_module_scankit_sdk_version\"\n      android:value=\"scan:1.2.0.300\">\n    </meta-data>\n    <meta-data\n      android:name=\"com.huawei.hms.client.service.name:scan\"\n      android:value=\"scan:1.2.0.300\">\n    </meta-data>\n    <meta-data\n      android:name=\"com.huawei.hms.min_api_level:scan:huawei_module_scankit\"\n      android:value=\"1\">\n    </meta-data>\n    <meta-data\n      android:name=\"com.huawei.hms.min_api_level:scan:hmscore\"\n      android:value=\"1\">\n    </meta-data>\n    <activity\n      android:name=\"com.huawei.hms.hmsscankit.ScanKitActivity\"\n      android:screenOrientation=\"portrait\">\n    </activity>\n    <meta-data\n      android:name=\"com.huawei.hms.kit.api_level:iap\"\n      android:value=\"2\">\n    </meta-data>\n    <activity\n      android:theme=\"@0x7f13026a\"\n      android:name=\"com.huawei.hms.iap.ui.IapEntryActivity\"\n      android:exported=\"false\"\n      android:taskAffinity=\"com.huawei.android.hwpay.paytask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:windowSoftInputMode=\"adjustResize|stateHidden\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui.Translucent.NoTitleBar\">\n      </meta-data>\n      <meta-data\n        android:name=\"android.notch_support\"\n        android:value=\"true\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@0x7f13026c\"\n      android:name=\"com.huawei.hms.pay.thirdinvoke.InternalThirdInvokeActivity\"\n      android:exported=\"false\"\n      android:excludeFromRecents=\"true\"\n      android:screenOrientation=\"behind\"\n      android:configChanges=\"keyboard|keyboardHidden|layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <intent-filter>\n        <action\n          android:name=\"com.huawei.pay.intent.action.Internal_Third_Invoke\">\n        </action>\n        <action\n          android:name=\"com.huawei.pay.intent.action.BankCard_Third_Invoke\">\n        </action>\n        <action\n          android:name=\"com.huawei.pay.intent.action.Hcoin_Container\">\n        </action>\n        <action\n          android:name=\"com.huawei.pay.intent.action.Family_Grant\">\n        </action>\n        <action\n          android:name=\"com.huawei.pay.intent.action.PAYMENT_INFO\">\n        </action>\n        <category\n          android:name=\"android.intent.category.DEFAULT\">\n        </category>\n      </intent-filter>\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui.Translucent.NoTitleBar\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@0x7f13026c\"\n      android:name=\"com.huawei.hms.pay.thirdinvoke.ExternalThirdInvokeActivity\"\n      android:exported=\"true\"\n      android:screenOrientation=\"behind\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <intent-filter>\n        <action\n          android:name=\"com.huawei.pay.intent.action.Hcoin_Third_Invoke\">\n        </action>\n        <action\n          android:name=\"com.huawei.pay.intent.action.Hcoin_Third_Invoke_Receive\">\n        </action>\n        <action\n          android:name=\"android.intent.action.VIEW\">\n        </action>\n        <category\n          android:name=\"android.intent.category.DEFAULT\">\n        </category>\n        <category\n          android:name=\"android.intent.category.BROWSABLE\">\n        </category>\n        <data\n          android:scheme=\"pay\"\n          android:host=\"com.huawei.hwid.external\">\n        </data>\n        <data\n          android:scheme=\"pay\"\n          android:host=\"com.huawei.hwid\">\n        </data>\n      </intent-filter>\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui.Translucent.NoTitleBar\">\n      </meta-data>\n    </activity>\n    <receiver\n      android:name=\"com.huawei.push.IAPPushBroadcastReceiver\"\n      android:permission=\"com.huawei.android.permission.INNER_RECEIVER\"\n      android:exported=\"false\">\n      <intent-filter>\n        <action\n          android:name=\"com.huawei.hms.push.action.inner.receive_token\">\n        </action>\n        <action\n          android:name=\"com.huawei.hms.push.action.inner.datamsg_iap\">\n        </action>\n      </intent-filter>\n    </receiver>\n    <activity\n      android:theme=\"@0x7f13026c\"\n      android:name=\"com.huawei.pay.agreement.AgreementActivity\"\n      android:exported=\"false\"\n      android:screenOrientation=\"behind\"\n      android:configChanges=\"keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:exported=\"false\"\n        android:value=\"androidhwext:style/Theme.Emui.Translucent.NoTitleBar\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@0x7f13026a\"\n      android:name=\"com.huawei.webview.IAPWebViewActivity\"\n      android:exported=\"false\"\n      android:screenOrientation=\"behind\"\n      android:configChanges=\"layoutDirection|screenLayout|screenSize|smallestScreenSize\"\n      android:uiOptions=\"splitActionBarWhenNarrow\">\n      <intent-filter>\n        <action\n          android:name=\"com.huawei.pay.intent.action.web_activity\">\n        </action>\n        <category\n          android:name=\"android.intent.category.DEFAULT\">\n        </category>\n      </intent-filter>\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <provider\n      android:name=\"com.huawei.pay.sp.provider.IPCCallProvider\"\n      android:exported=\"false\"\n      android:process=\"null.core\"\n      android:authorities=\"com.huawei.pay.sp.provider.IPCCallProvider\">\n    </provider>\n    <activity\n      android:theme=\"@0x7f13026c\"\n      android:name=\"com.huawei.wallet.logic.permissions.PermissionsActivity\"\n      android:exported=\"false\"\n      android:screenOrientation=\"behind\"\n      android:configChanges=\"keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:windowSoftInputMode=\"adjustResize|stateHidden\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui.Translucent.NoTitleBar\">\n      </meta-data>\n    </activity>\n    <service\n      android:name=\"com.huawei.hms.tss.innerservice.TssInnerService\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid\">\n    </service>\n    <meta-data\n      android:name=\"hms_module:tss\"\n      android:value=\"com.huawei.hms.tss.MainEntry:1\">\n    </meta-data>\n    <provider\n      android:name=\"com.huawei.hms.tss.provider.SharedFileContentProvider\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.core\"\n      android:authorities=\"com.huawei.hwid\">\n    </provider>\n    <meta-data\n      android:name=\"com.huawei.hms.kit.api_level:tss\"\n      android:value=\"1\">\n    </meta-data>\n    <meta-data\n      android:name=\"com.huawei.hms.kit.api_level:account\"\n      android:value=\"1\">\n    </meta-data>\n    <meta-data\n      android:name=\"com.huawei.hms.kit.type:account\"\n      android:value=\"app\">\n    </meta-data>\n    <service\n      android:name=\".cloudsettings.innerservices.CloudAccountInnerService\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\">\n      <intent-filter>\n        <action\n          android:name=\"com.huawei.hwid.ICloudInnerService\">\n        </action>\n      </intent-filter>\n    </service>\n    <service\n      android:name=\".common.innercall.server.HwidInnerService\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\">\n      <intent-filter>\n        <action\n          android:name=\"com.huawei.hwid.hwid.innerservice\">\n        </action>\n      </intent-filter>\n    </service>\n    <receiver\n      android:name=\".common.usecase.push.AccountApkPushReceiver\"\n      android:permission=\"com.huawei.android.permission.INNER_RECEIVER\"\n      android:exported=\"false\">\n      <intent-filter>\n        <action\n          android:name=\"com.huawei.hms.push.action.inner.receive_token\">\n        </action>\n        <action\n          android:name=\"com.huawei.hms.push.action.inner.datamsg_account\">\n        </action>\n      </intent-filter>\n    </receiver>\n    <activity\n      android:name=\"com.huawei.hwid20.accountregister.RegisterChildEmailActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\">\n    </activity>\n    <activity\n      android:name=\"com.huawei.hwid20.accountregister.RegisterChildNicknameActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\">\n    </activity>\n    <activity\n      android:name=\"com.huawei.hwid20.accountregister.RegisterChildSecurityPhoneActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\">\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"@0x7f0b01e2\"\n      android:name=\"com.huawei.hwid20.accountregister.RegisterEmailActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:windowSoftInputMode=\"stateHidden\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"@0x7f0b0202\"\n      android:name=\"com.huawei.hwid20.accountregister.RegisterSetPasswordActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:windowSoftInputMode=\"stateVisible\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light.NoActionBar\"\n      android:name=\"com.huawei.hwid20.accountregister.RegisterSetPhoneActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:windowSoftInputMode=\"adjustResize|stateHidden\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui.NoActionBar\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light.NoActionBar\"\n      android:name=\"com.huawei.hwid20.accountregister.RegisterSetSecurityPhoneActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:windowSoftInputMode=\"adjustResize|stateHidden\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui.NoActionBar\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"@0x7f0b01ec\"\n      android:name=\"com.huawei.hwid20.accountregister.RegisterPhoneActivity\"\n      android:exported=\"false\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:windowSoftInputMode=\"stateHidden\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light.NoActionBar\"\n      android:name=\"com.huawei.hwid20.accountregister.RegisterPhoneVerifyCodeActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:windowSoftInputMode=\"stateHidden\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui.NoActionBar\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light.NoActionBar\"\n      android:name=\"com.huawei.hwid20.accountregister.RegisterEmailVerifyCodeActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:windowSoftInputMode=\"stateHidden\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui.NoActionBar\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"@0x7f0b0036\"\n      android:name=\"com.huawei.hwid20.accountregister.ThirdBindPhoneActivity\"\n      android:exported=\"false\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:windowSoftInputMode=\"stateVisible\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:name=\"com.huawei.hwid20.accountregister.RegisterAdvertActivity\"\n      android:exported=\"false\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"@0x7f0b0263\"\n      android:name=\"com.huawei.hwid20.accountregister.ThirdBindEmailActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:windowSoftInputMode=\"stateVisible\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light.NoActionBar\"\n      android:name=\"com.huawei.hwid20.accountregister.RegisterSetBirthdayActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:windowSoftInputMode=\"stateAlwaysHidden\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui.NoActionBar\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:name=\"com.huawei.hwid20.accountregister.ForgetOrRegisterActivity\"\n      android:exported=\"false\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"@0x7f0b0657\"\n      android:name=\"com.huawei.hwid20.accountregister.UpdateUserNameAndLoginIdActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:windowSoftInputMode=\"adjustResize|stateHidden\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light.NoActionBar\"\n      android:name=\"com.huawei.hwid20.accountregister.ChooseRegisterTypeActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:windowSoftInputMode=\"adjustResize|stateHidden\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui.NoActionBar\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light.NoActionBar\"\n      android:name=\"com.huawei.hwid20.accountregister.RegisterSetUserNameActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:windowSoftInputMode=\"adjustResize|stateHidden\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui.NoActionBar\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light.NoActionBar\"\n      android:name=\"com.huawei.hwid20.accountregister.RegisterSetEmailActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:windowSoftInputMode=\"adjustResize|stateHidden\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui.NoActionBar\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light.NoActionBar\"\n      android:name=\"com.huawei.hwid20.accountregister.RegisterSetPwdActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:windowSoftInputMode=\"adjustResize|stateHidden\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui.NoActionBar\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light.NoActionBar\"\n      android:name=\"com.huawei.hwid20.accountregister.CreateChildAccountActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:windowSoftInputMode=\"stateAlwaysHidden\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui.NoActionBar\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"@0x7f0b0011\"\n      android:name=\"com.huawei.hwid20.agreement.ParentAgreementForAspiegelActvity\"\n      android:exported=\"false\"\n      android:configChanges=\"layoutDirection|locale|mcc|mnc|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <meta-data\n      android:name=\"com.huawei.hms.kit.api_level:safetydetect\"\n      android:value=\"1\">\n    </meta-data>\n    <meta-data\n      android:name=\"hms_module:urlchecker\"\n      android:value=\"com.huawei.hms.safetydetect.urlchecker.MainEntry:1\">\n    </meta-data>\n    <service\n      android:name=\"com.huawei.hms.safetydetect.sysintegrity.innerservice.SafetyDetectInnerService\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\">\n    </service>\n    <meta-data\n      android:name=\"hms_module:safetydetect\"\n      android:value=\"com.huawei.hms.safetydetect.sysintegrity.MainEntry:1\">\n    </meta-data>\n    <meta-data\n      android:name=\"hms_module:wifidetect\"\n      android:value=\"com.huawei.hms.safetydetect.wifidetect.MainEntry:1\">\n    </meta-data>\n    <meta-data\n      android:name=\"hms_module:appscheck\"\n      android:value=\"com.huawei.hms.safetydetect.appscheck.MainEntry:1\">\n    </meta-data>\n    <activity\n      android:name=\"com.huawei.hms.safetydetect.userdetect.service.GeeTestActivity\"\n      android:excludeFromRecents=\"true\"\n      android:configChanges=\"keyboardHidden|orientation|screenSize\"\n      android:windowSoftInputMode=\"adjustResize|stateAlwaysHidden\"\n      android:noHistory=\"true\">\n    </activity>\n    <service\n      android:name=\"com.huawei.hms.safetydetect.userdetect.service.SafetyDetectInnerService\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.safetydetect.userdetect.innerservice.UserDetectInnerService\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\">\n    </service>\n    <meta-data\n      android:name=\"hms_module:userdetect\"\n      android:value=\"com.huawei.hms.safetydetect.userdetect.MainEntry:1\">\n    </meta-data>\n    <provider\n      android:name=\"com.huawei.jos.game.buoy.provider.InShowBuoyListProvider\"\n      android:readPermission=\"com.huawei.hwid.permission.gameservice.inshowbuoylist.provider\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.core\"\n      android:authorities=\"com.huawei.hwid.gameservice.inshowbuoylist\">\n    </provider>\n    <provider\n      android:name=\"com.huawei.jos.game.buoy.provider.ShowBuoyProvider\"\n      android:readPermission=\"com.huawei.hwid.permission.gameservice.buoy.provider\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.core\"\n      android:authorities=\"com.huawei.hwid.peripheralprovider\">\n    </provider>\n    <provider\n      android:name=\"com.huawei.jos.common.storage.memory.MemoryCacheProvider\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\"\n      android:authorities=\"com.huawei.hwid.MemoryCacheProvider\">\n    </provider>\n    <provider\n      android:name=\"com.huawei.jos.common.storage.sp.SharedPreferenceProvider\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\"\n      android:authorities=\"com.huawei.hwid.SharedPreferencesProvider\">\n    </provider>\n    <provider\n      android:name=\"com.huawei.updatesdk.fileprovider.UpdateSdkFileProvider\"\n      android:exported=\"false\"\n      android:authorities=\"com.huawei.hwid.updateSdk.fileProvider\"\n      android:grantUriPermissions=\"true\">\n    </provider>\n    <provider\n      android:name=\"com.huawei.jos.game.archive.ArchiveRemoteAccessProvider\"\n      android:readPermission=\"com.huawei.hwid.permission.gameservice.archive.access.provider\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.core\"\n      android:authorities=\"com.huawei.hms.jos.archive\">\n    </provider>\n    <provider\n      android:name=\"com.huawei.jos.user.RealNameProvider\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\"\n      android:authorities=\"com.huawei.jos.realname.provider\">\n    </provider>\n    <service\n      android:name=\"com.huawei.jos.game.buoy.service.NotifyAppStateService\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\">\n      <intent-filter>\n        <action\n          android:name=\"com.huawei.hwid.NOTIFY_APP_STATE_SERVICE\">\n        </action>\n      </intent-filter>\n    </service>\n    <service\n      android:name=\"com.huawei.jos.game.buoy.service.FingerService\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\">\n      <intent-filter>\n        <action\n          android:name=\"com.huawei.hwid.gameservice.fingerservice\">\n        </action>\n      </intent-filter>\n    </service>\n    <service\n      android:name=\"com.huawei.jos.common.service.JosUIService\"\n      android:enabled=\"true\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.jos.ui\">\n    </service>\n    <service\n      android:name=\"com.huawei.jos.common.service.MainUIService\"\n      android:enabled=\"true\"\n      android:exported=\"false\">\n    </service>\n    <activity\n      android:theme=\"@style/Theme.Translucent.NoTitleBar\"\n      android:label=\"\"\n      android:name=\"com.huawei.jos.joint.notice.JosNoticeDialogActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"keyboard|keyboardHidden|layoutDirection|locale|orientation|screenLayout|screenSize|smallestScreenSize\">\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Translucent.NoTitleBar\"\n      android:label=\"\"\n      android:name=\"com.huawei.jos.hmsagent.pay.PayGuideActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"keyboard|keyboardHidden|layoutDirection|locale|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui.Translucent.NoTitleBar\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Translucent.NoTitleBar\"\n      android:name=\"com.huawei.jos.game.login.GameLoginActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"keyboard|keyboardHidden|layoutDirection|locale|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui.Translucent\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Translucent.NoTitleBar\"\n      android:name=\"com.huawei.jos.game.login.GameSignInActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"keyboard|keyboardHidden|layoutDirection|locale|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui.Translucent\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Translucent.NoTitleBar\"\n      android:name=\"com.huawei.hms.jos.api.account.JosSignInActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"keyboard|keyboardHidden|layoutDirection|locale|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui.Translucent\">\n      </meta-data>\n      <meta-data\n        android:name=\"hms_verify_fingerprint\"\n        android:value=\"true\">\n      </meta-data>\n      <intent-filter>\n        <action\n          android:name=\"com.huawei.hms.jos.signIn\">\n        </action>\n        <category\n          android:name=\"android.intent.category.DEFAULT\">\n        </category>\n      </intent-filter>\n    </activity>\n    <activity\n      android:name=\"com.huawei.jos.game.gameservicelite.GameServiceIntroduceActivity\"\n      android:exported=\"false\">\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Translucent.NoTitleBar\"\n      android:label=\"\"\n      android:name=\"com.huawei.jos.joint.recovery.JosRecoveryDialogActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"keyboard|keyboardHidden|layoutDirection|locale|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui.Translucent.NoTitleBar\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Translucent.NoTitleBar\"\n      android:label=\"\"\n      android:name=\"com.huawei.jos.joint.protocol.JosPayCouponDialogActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"keyboard|keyboardHidden|layoutDirection|locale|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui.Translucent.NoTitleBar\">\n      </meta-data>\n    </activity>\n    <meta-data\n      android:name=\"com.huawei.hms.kit.api_level:game\"\n      android:value=\"1\">\n    </meta-data>\n    <meta-data\n      android:name=\"com.huawei.hms.kit.api_level:jos\"\n      android:value=\"1\">\n    </meta-data>\n    <meta-data\n      android:name=\"com.huawei.hms.kit.api_level:core\"\n      android:value=\"1\">\n    </meta-data>\n    <meta-data\n      android:name=\"com.huawei.hms.kit.api_level:sns\"\n      android:value=\"1\">\n    </meta-data>\n    <meta-data\n      android:name=\"com.huawei.hms.kit.type:sns\"\n      android:value=\"app\">\n    </meta-data>\n    <provider\n      android:name=\"com.huawei.sns.storage.db.SNSContentProvider\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\"\n      android:authorities=\"com.huawei.android.sns.provider\">\n    </provider>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:name=\"com.huawei.sns.ui.HomeActivity\"\n      android:exported=\"true\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:windowSoftInputMode=\"adjustPan|stateAlwaysHidden\"\n      android:hardwareAccelerated=\"true\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n      <intent-filter>\n        <action\n          android:name=\"com.huawei.sns.action.FRIEND_HOME\">\n        </action>\n        <action\n          android:name=\"com.huawei.sns.action.MSG_VIEW\">\n        </action>\n        <category\n          android:name=\"android.intent.category.DEFAULT\">\n        </category>\n      </intent-filter>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"@0x7f0b1151\"\n      android:name=\"com.huawei.sns.ui.user.AddFriendActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:windowSoftInputMode=\"adjustPan|stateAlwaysHidden\"\n      android:hardwareAccelerated=\"true\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"@0x7f0b116d\"\n      android:name=\"com.huawei.sns.ui.user.UserDetailActivity\"\n      android:exported=\"false\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:hardwareAccelerated=\"true\"\n      android:uiOptions=\"splitActionBarWhenNarrow\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"@0x7f0b10b2\"\n      android:name=\"com.huawei.sns.ui.user.UserNotifyActivity\"\n      android:exported=\"false\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:windowSoftInputMode=\"adjustResize|stateAlwaysHidden\"\n      android:hardwareAccelerated=\"true\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"@0x7f0b1038\"\n      android:name=\"com.huawei.sns.ui.group.GroupListActivity\"\n      android:exported=\"false\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:hardwareAccelerated=\"true\"\n      android:uiOptions=\"splitActionBarWhenNarrow\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"@0x7f0b1033\"\n      android:name=\"com.huawei.sns.ui.group.GroupActivity\"\n      android:exported=\"false\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:hardwareAccelerated=\"true\"\n      android:uiOptions=\"splitActionBarWhenNarrow\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"@0x7f0b1053\"\n      android:name=\"com.huawei.sns.ui.group.GroupHeadImageActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:uiOptions=\"splitActionBarWhenNarrow\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"\"\n      android:name=\"com.huawei.sns.ui.group.CreateGroupActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:hardwareAccelerated=\"true\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"\"\n      android:name=\"com.huawei.sns.ui.group.GroupInviteActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:hardwareAccelerated=\"true\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"@0x7f0b111b\"\n      android:name=\"com.huawei.sns.ui.selector.GroupSelectorActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:hardwareAccelerated=\"true\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:name=\"com.huawei.sns.ui.selector.UserSelectorActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:windowSoftInputMode=\"adjustPan|stateAlwaysHidden\"\n      android:hardwareAccelerated=\"true\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Translucent.NoTitleBar\"\n      android:name=\"com.huawei.sns.ui.login.HwAccountLoginActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui.Translucent.NoTitleBar\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:name=\"com.huawei.sns.ui.user.UserDetailHeadImageActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <service\n      android:name=\"com.huawei.sns.sdk.sdkimpl.SNSSDKServiceImpl\"\n      android:exported=\"true\">\n      <intent-filter>\n        <action\n          android:name=\"com.huawei.sns.sdk.api.SNS_SDK_OPENAPI\">\n        </action>\n      </intent-filter>\n    </service>\n    <provider\n      android:name=\"com.huawei.sns.sdk.sdkimpl.SNSSDKContentProvider\"\n      android:exported=\"true\"\n      android:authorities=\"com.huawei.android.sns.sdk\">\n    </provider>\n    <provider\n      android:name=\"com.huawei.sns.backup.BackupContentProvider\"\n      android:permission=\"com.huawei.android.sns.permission.BACKUP\"\n      android:exported=\"true\"\n      android:authorities=\"com.huawei.android.sns.backup\">\n    </provider>\n    <activity\n      android:theme=\"@0x7f130291\"\n      android:name=\"com.huawei.sns.ui.twodimcode.TwoDimCodeActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:hardwareAccelerated=\"true\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui.Translucent\">\n      </meta-data>\n      <intent-filter>\n        <action\n          android:name=\"com.huawei.sns.action.SELF_TWO_DIMCODE\">\n        </action>\n        <category\n          android:name=\"android.intent.category.DEFAULT\">\n        </category>\n      </intent-filter>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"@0x7f0b1152\"\n      android:name=\"com.huawei.sns.ui.user.PrivacySettingActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n      <intent-filter>\n        <action\n          android:name=\"com.huawei.sns.action.PRIVACY_SETTINGS\">\n        </action>\n        <category\n          android:name=\"android.intent.category.DEFAULT\">\n        </category>\n      </intent-filter>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"@0x7f0b10df\"\n      android:name=\"com.huawei.sns.ui.user.MessageSettingActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n      <intent-filter>\n        <action\n          android:name=\"com.huawei.sns.action.MESSAGE_SETTINGS\">\n        </action>\n        <category\n          android:name=\"android.intent.category.DEFAULT\">\n        </category>\n      </intent-filter>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:name=\"com.huawei.sns.ui.chat.SingleChatActivity\"\n      android:exported=\"false\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:windowSoftInputMode=\"adjustResize|stateAlwaysHidden\"\n      android:hardwareAccelerated=\"true\"\n      android:uiOptions=\"splitActionBarWhenNarrow\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"@0x7f0b1141\"\n      android:name=\"com.huawei.sns.ui.chat.singledetail.SingleChatDetailActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:hardwareAccelerated=\"true\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:name=\"com.huawei.sns.ui.chat.photo.photoview.PhotoViewPagerActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:hardwareAccelerated=\"true\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"@0x7f0b10ca\"\n      android:name=\"com.huawei.sns.ui.chat.SearchChatRecordActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:hardwareAccelerated=\"true\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"@0x7f0b0fdc\"\n      android:name=\"com.huawei.sns.ui.chat.ChatRecordActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:hardwareAccelerated=\"true\"\n      android:uiOptions=\"splitActionBarWhenNarrow\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"@0x7f0b0fea\"\n      android:name=\"com.huawei.sns.ui.chat.ChatHistoryActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:hardwareAccelerated=\"true\"\n      android:uiOptions=\"splitActionBarWhenNarrow\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:name=\"com.huawei.sns.ui.chat.GroupChatActivity\"\n      android:exported=\"false\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:windowSoftInputMode=\"adjustResize|stateAlwaysHidden\"\n      android:hardwareAccelerated=\"true\"\n      android:uiOptions=\"splitActionBarWhenNarrow\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"@0x7f0b0fda\"\n      android:name=\"com.huawei.sns.ui.group.NormalGroupActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:hardwareAccelerated=\"true\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"@0x7f0b10a2\"\n      android:name=\"com.huawei.sns.ui.chat.photo.send.AlbumPicBrowserActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:hardwareAccelerated=\"true\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:name=\"com.huawei.sns.ui.chat.photo.send.PhotoPagerActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:hardwareAccelerated=\"true\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"@0x7f0b0fea\"\n      android:name=\"com.huawei.sns.ui.complain.ComplainDeletePicActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:hardwareAccelerated=\"true\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:name=\"com.huawei.sns.ui.photo.PhotoListActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:hardwareAccelerated=\"true\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:icon=\"@0x7f080780\"\n      android:name=\"com.huawei.sns.ui.selector.TransmitActivity\"\n      android:exported=\"true\"\n      android:taskAffinity=\"com.huawei.hwid.task.sharemsg\"\n      android:excludeFromRecents=\"true\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:hardwareAccelerated=\"true\"\n      android:uiOptions=\"splitActionBarWhenNarrow\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity-alias\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:name=\"com.huawei.sns.ui.selector.TransmitActivityAlias\"\n      android:enabled=\"true\"\n      android:targetActivity=\"com.huawei.sns.ui.selector.TransmitActivity\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n      <intent-filter\n        android:label=\"@0x7f0b0077\">\n        <action\n          android:name=\"android.intent.action.SEND\">\n        </action>\n        <category\n          android:name=\"android.intent.category.DEFAULT\">\n        </category>\n        <data\n          android:mimeType=\"text/plain\">\n        </data>\n      </intent-filter>\n      <intent-filter\n        android:label=\"@0x7f0b0077\">\n        <action\n          android:name=\"android.intent.action.SEND\">\n        </action>\n        <category\n          android:name=\"android.intent.category.DEFAULT\">\n        </category>\n        <data\n          android:mimeType=\"image/*\">\n        </data>\n      </intent-filter>\n      <intent-filter\n        android:label=\"@0x7f0b0077\">\n        <action\n          android:name=\"android.intent.action.SEND_MULTIPLE\">\n        </action>\n        <category\n          android:name=\"android.intent.category.DEFAULT\">\n        </category>\n        <data\n          android:mimeType=\"image/*\">\n        </data>\n      </intent-filter>\n    </activity-alias>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"\"\n      android:name=\"com.huawei.sns.sdk.sdkimpl.ui.SDKWelcomeActivity\"\n      android:exported=\"true\"\n      android:configChanges=\"keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n      <intent-filter>\n        <action\n          android:name=\"com.huawei.sns.sdk.proxy_action_view\">\n        </action>\n        <action\n          android:name=\"com.huawei.sns.sdk.FRIEND_VIEW\">\n        </action>\n        <action\n          android:name=\"com.huawei.sns.sdk.MSG_VIEW\">\n        </action>\n        <action\n          android:name=\"com.huawei.sns.sdk.ASSISTANT_CHAT_VIEW\">\n        </action>\n        <action\n          android:name=\"com.huawei.android.sns.action.UPDATE_APK_VIEW\">\n        </action>\n        <action\n          android:name=\"com.huawei.sns.sdk.CHAT_GROUP_DETAIL_VIEW\">\n        </action>\n        <action\n          android:name=\"com.huawei.sns.sdk.CHAT_FRIEND_DETAIL_VIEW\">\n        </action>\n        <action\n          android:name=\"com.huawei.sns.sdk.COMMON_GROUP_DETAIL_VIEW\">\n        </action>\n        <action\n          android:name=\"com.huawei.sns.sdk.SHOW_FRIEND_LIST_VIEW\">\n        </action>\n        <action\n          android:name=\"com.huawei.sns.sdk.SHOW_GROUP_SELECTOR_VIEW\">\n        </action>\n        <action\n          android:name=\"com.huawei.sns.sdk.CREATE_GROUP_VIEW\">\n        </action>\n        <action\n          android:name=\"com.huawei.sns.sdk.FAMILY_GROUP_DETAIL_VIEW\">\n        </action>\n        <action\n          android:name=\"com.huawei.sns.sdk.FAMILY_GROUP_VIEW\">\n        </action>\n        <action\n          android:name=\"com.huawei.sns.sdk.COMMON_GROUP_VIEW\">\n        </action>\n        <action\n          android:name=\"com.huawei.sns.sdk.FRIEND_DETAIL_VIEW\">\n        </action>\n        <category\n          android:name=\"android.intent.category.DEFAULT\">\n        </category>\n      </intent-filter>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:name=\"com.huawei.sns.ui.conversation.MessageSearchActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:hardwareAccelerated=\"true\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:name=\"com.huawei.sns.ui.padsearch.SearchActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:hardwareAccelerated=\"true\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:name=\"com.huawei.sns.ui.chat.DeleteGroupMemberActivity\"\n      android:exported=\"false\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:hardwareAccelerated=\"true\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"@0x7f0b0fde\"\n      android:name=\"com.huawei.sns.ui.user.ChatSettingActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n      <intent-filter>\n        <action\n          android:name=\"com.huawei.sns.action.CHAT_SETTINGS\">\n        </action>\n        <category\n          android:name=\"android.intent.category.DEFAULT\">\n        </category>\n      </intent-filter>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:name=\"com.huawei.sns.ui.chat.AssistantChatActivity\"\n      android:exported=\"false\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:hardwareAccelerated=\"true\"\n      android:uiOptions=\"splitActionBarWhenNarrow\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"@0x7f0b1148\"\n      android:name=\"com.huawei.sns.ui.chat.AssistantListActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:hardwareAccelerated=\"true\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"@0x7f0b1149\"\n      android:name=\"com.huawei.sns.ui.chat.AssistantDetailActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:hardwareAccelerated=\"true\"\n      android:uiOptions=\"splitActionBarWhenNarrow\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"\"\n      android:name=\"com.huawei.sns.ui.browser.WebViewActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:hardwareAccelerated=\"true\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <receiver\n      android:name=\"com.huawei.sns.logic.push.PushDealReceiver\"\n      android:exported=\"false\">\n    </receiver>\n    <receiver\n      android:name=\"com.huawei.sns.logic.notification.ShowNotificationReceiver\"\n      android:exported=\"false\">\n    </receiver>\n    <receiver\n      android:name=\"com.huawei.sns.logic.push.PushSnsAarReceiver\"\n      android:exported=\"false\"\n      permission=\"com.huawei.android.permission.INNER_RECEIVER\">\n      <intent-filter>\n        <action\n          android:name=\"com.huawei.hms.push.action.inner.receive_token\">\n        </action>\n        <action\n          android:name=\"com.huawei.hms.push.action.inner.datamsg_sns\">\n        </action>\n      </intent-filter>\n    </receiver>\n    <activity\n      android:theme=\"@style/Theme.Translucent\"\n      android:name=\"com.huawei.sns.ui.qrcode.CheckQRCodeActivity\"\n      android:exported=\"true\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui.Translucent\">\n      </meta-data>\n      <intent-filter>\n        <action\n          android:name=\"com.huawei.intent.action.QRCODE\">\n        </action>\n        <category\n          android:name=\"android.intent.category.DEFAULT\">\n        </category>\n      </intent-filter>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"@0x7f0b10ff\"\n      android:name=\"com.huawei.sns.ui.qrcode.QRTextUrlActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:uiOptions=\"splitActionBarWhenNarrow\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"@0x7f0b1083\"\n      android:name=\"com.huawei.sns.ui.group.ApplyJoinGroupActivity\"\n      android:exported=\"false\"\n      android:launchMode=\"singleTop\"\n      android:screenOrientation=\"portrait\"\n      android:configChanges=\"keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:hardwareAccelerated=\"true\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"@0x7f0b0fbd\"\n      android:name=\"com.huawei.sns.ui.chat.ShowGroupMemberForAtActivity\"\n      android:exported=\"false\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:hardwareAccelerated=\"true\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Translucent\"\n      android:label=\"\"\n      android:name=\"com.huawei.hms.sns.HwSNSEntryActivity\"\n      android:exported=\"true\"\n      android:configChanges=\"keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui.Translucent\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"@0x7f0b0fea\"\n      android:name=\"com.huawei.sns.ui.complain.ComplainUploadActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:hardwareAccelerated=\"true\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"@0x7f0b0fea\"\n      android:name=\"com.huawei.sns.ui.complain.ComplainCategoryActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"@0x7f0b0fea\"\n      android:name=\"com.huawei.sns.ui.complain.ComplainUrlActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"@0x7f0b0fea\"\n      android:name=\"com.huawei.sns.ui.complain.ComplainSuccessActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"@0x7f0b0fee\"\n      android:name=\"com.huawei.sns.ui.browser.WebViewSimpleActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"@0x7f0b1148\"\n      android:name=\"com.huawei.sns.ui.user.AssistantSearchActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:hardwareAccelerated=\"true\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"@0x7f0b1058\"\n      android:name=\"com.huawei.sns.ui.group.NormalGroupInviteActivity\"\n      android:exported=\"true\"\n      android:configChanges=\"keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:hardwareAccelerated=\"true\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <provider\n      android:name=\"com.huawei.sns.storage.fileprovider.SNSFileProvider\"\n      android:exported=\"false\"\n      android:authorities=\"com.huawei.android.sns.fileprovider\"\n      android:grantUriPermissions=\"true\">\n      <meta-data\n        android:name=\"android.support.FILE_PROVIDER_PATHS\"\n        android:resource=\"@0x7f150019\">\n      </meta-data>\n    </provider>\n    <provider\n      android:name=\"com.huawei.opendevice.open.OaidDataProvider\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.persistent\"\n      android:authorities=\"com.huawei.hwid.pps.oaid\">\n    </provider>\n    <provider\n      android:name=\"com.huawei.openalliance.ad.ppskit.provider.ApiProvider\"\n      android:writePermission=\"com.huawei.permission.app.DOWNLOAD\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.persistent\"\n      android:authorities=\"com.huawei.hwid.pps.apiprovider\">\n    </provider>\n    <service\n      android:name=\"com.huawei.android.hms.ppskit.PpsChannelInfoService\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.persistent\">\n      <intent-filter>\n        <action\n          android:name=\"com.huawei.android.hms.CHANNEL_SERVICE\">\n        </action>\n      </intent-filter>\n    </service>\n    <service\n      android:name=\"com.huawei.android.hms.ppskit.PpsInstallationService\"\n      android:exported=\"true\">\n      <intent-filter>\n        <action\n          android:name=\"com.huawei.openalliance.ad.INSTALL_SERVICE\">\n        </action>\n      </intent-filter>\n    </service>\n    <service\n      android:name=\"com.huawei.android.hms.ppskit.PpsCoreService\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.persistent\">\n      <intent-filter>\n        <action\n          android:name=\"com.huawei.android.hms.ppskit.PPS_API_SERVICE\">\n        </action>\n      </intent-filter>\n    </service>\n    <service\n      android:name=\"com.huawei.opendevice.open.identifier.internal.OaidService\"\n      android:enabled=\"true\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.persistent\"\n      android:visibleToInstantApps=\"true\">\n      <intent-filter>\n        <action\n          android:name=\"androidx.ads.identifier.provider.GET_AD_ID\">\n        </action>\n        <category\n          android:name=\"android.intent.category.DEFAULT\">\n        </category>\n      </intent-filter>\n      <meta-data\n        android:name=\"instantapps.clients.allowed\"\n        android:value=\"true\">\n      </meta-data>\n    </service>\n    <service\n      android:name=\"com.huawei.hms.opendeviceidentifier.OpenDeviceIdentifierBindService\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.persistent\">\n      <intent-filter>\n        <action\n          android:name=\"com.uodis.opendevice.OPENIDS_SERVICE\">\n        </action>\n      </intent-filter>\n    </service>\n    <activity\n      android:theme=\"@style/Theme.DeviceDefault\"\n      android:name=\"com.huawei.opendevice.open.OAIDSettingActivity\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hms.oobe\"\n      android:configChanges=\"keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <intent-filter>\n        <action\n          android:name=\"com.huawei.hms.action.OAID_SETTING\">\n        </action>\n        <category\n          android:name=\"android.intent.category.DEFAULT\">\n        </category>\n      </intent-filter>\n      <intent-filter>\n        <action\n          android:name=\"android.intent.action.VIEW\">\n        </action>\n        <category\n          android:name=\"android.intent.category.DEFAULT\">\n        </category>\n        <category\n          android:name=\"android.intent.category.BROWSABLE\">\n        </category>\n        <data\n          android:scheme=\"hwpps\"\n          android:host=\"oaid_setting\">\n        </data>\n      </intent-filter>\n      <intent-filter>\n        <action\n          android:name=\"androidx.ads.identifier.provider.OPEN_SETTINGS\">\n        </action>\n      </intent-filter>\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui.WithActionBar\">\n      </meta-data>\n    </activity>\n    <activity-alias\n      android:label=\"@0x7f0b0008\"\n      android:name=\"com.huawei.opendevice.open.OAIDSetting\"\n      android:permission=\"com.huawei.permission.external_app_settings.USE_COMPONENT\"\n      android:enabled=\"true\"\n      android:exported=\"true\"\n      android:targetActivity=\"com.huawei.opendevice.open.OAIDSettingActivity\">\n      <intent-filter>\n        <action\n          android:name=\"com.huawei.settings.action.UPLOADED_TO_APP_MARKET_EXTRA_APP_SETTINGS\">\n        </action>\n      </intent-filter>\n      <meta-data\n        android:name=\"com.android.settings.menutitle\"\n        android:resource=\"@0x7f0b0008\">\n      </meta-data>\n      <meta-data\n        android:name=\"com.android.settings.menuicon\"\n        android:resource=\"@0x7f0807ae\">\n      </meta-data>\n      <meta-data\n        android:name=\"com.android.settings.search_config_file\"\n        android:resource=\"@0x7f150018\">\n      </meta-data>\n      <meta-data\n        android:name=\"com.android.settings.menu.category\"\n        android:value=\"com.huawei.opendevice.open.OAIDSetting\">\n      </meta-data>\n    </activity-alias>\n    <activity\n      android:label=\" \"\n      android:name=\"com.huawei.openalliance.ad.ppskit.activity.PPSActivity\"\n      android:exported=\"true\"\n      android:configChanges=\"keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <intent-filter>\n        <action\n          android:name=\"com.huawei.hms.pps.action.PPS_DETAIL\">\n        </action>\n        <category\n          android:name=\"android.intent.category.DEFAULT\">\n        </category>\n      </intent-filter>\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:name=\"com.huawei.opendevice.open.OAIDStatisticPrivacyActivity\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hms.oobe\"\n      android:configChanges=\"keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <intent-filter>\n        <action\n          android:name=\"com.huawei.hms.ppskit.ACTION.OAID_STATISTIC\">\n        </action>\n        <category\n          android:name=\"android.intent.category.DEFAULT\">\n        </category>\n        <category\n          android:name=\"android.intent.category.BROWSABLE\">\n        </category>\n      </intent-filter>\n      <intent-filter>\n        <action\n          android:name=\"android.intent.action.VIEW\">\n        </action>\n        <category\n          android:name=\"android.intent.category.DEFAULT\">\n        </category>\n        <category\n          android:name=\"android.intent.category.BROWSABLE\">\n        </category>\n        <data\n          android:scheme=\"hwpps\"\n          android:host=\"statistics\">\n        </data>\n      </intent-filter>\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui.WithActionBar\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.NoTitleBar.Fullscreen\"\n      android:name=\"com.huawei.openalliance.ad.ppskit.activity.PPSRewardActivity\"\n      android:exported=\"true\"\n      android:screenOrientation=\"behind\"\n      android:configChanges=\"keyboard|keyboardHidden|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <intent-filter>\n        <action\n          android:name=\"com.huawei.hms.pps.action.PPS_REWARD\">\n        </action>\n        <category\n          android:name=\"android.intent.category.DEFAULT\">\n        </category>\n      </intent-filter>\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui.NoActionBar.Fullscreen\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.NoTitleBar.Fullscreen\"\n      android:name=\"com.huawei.openalliance.ad.ppskit.activity.InterstitialAdActivity\"\n      android:exported=\"true\"\n      android:screenOrientation=\"sensor\"\n      android:configChanges=\"keyboard|keyboardHidden|mcc|mnc|navigation|screenLayout|screenSize|smallestScreenSize\">\n      <intent-filter>\n        <action\n          android:name=\"com.huawei.hms.pps.action.PPS_INTERSTITIAL\">\n        </action>\n        <category\n          android:name=\"android.intent.category.DEFAULT\">\n        </category>\n      </intent-filter>\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui.NoActionBar.Fullscreen\">\n      </meta-data>\n    </activity>\n    <activity\n      android:label=\"\"\n      android:name=\"com.huawei.opendevice.open.PrivacyActivity\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hms.oobe\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <intent-filter>\n        <action\n          android:name=\"com.android.settings.action.EXTRA_APP_SETTINGS\">\n        </action>\n        <category\n          android:name=\"android.intent.category.DEFAULT\">\n        </category>\n      </intent-filter>\n      <meta-data\n        android:name=\"com.android.settings.menutitle\"\n        android:resource=\"@0x7f0b0150\">\n      </meta-data>\n      <meta-data\n        android:name=\"com.android.settings.menu.category\"\n        android:value=\"com.huawei.opendevice.open.LOCATION_AUTHORITY\">\n      </meta-data>\n      <meta-data\n        android:name=\"com.android.settings.menu.provider\"\n        android:value=\"content://com.huawei.hwid.pps.locationauth.innerprovider\">\n      </meta-data>\n      <meta-data\n        android:name=\"com.android.settings.menu.type\"\n        android:value=\"10\">\n      </meta-data>\n      <meta-data\n        android:name=\"com.android.settings.menu_is_dynamic_show\"\n        android:value=\"true\">\n      </meta-data>\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui.WithActionBar\">\n      </meta-data>\n    </activity>\n    <provider\n      android:name=\"com.huawei.openalliance.ad.ppskit.provider.LocationAuthInnerProvider\"\n      android:permission=\"android.permission.READ_SEARCH_INDEXABLES\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.persistent\"\n      android:authorities=\"com.huawei.hwid.pps.locationauth.innerprovider\">\n      <intent-filter>\n        <action\n          android:name=\"android.content.action.SEARCH_SUPPORTED_PROVIDER\">\n        </action>\n      </intent-filter>\n    </provider>\n    <activity\n      android:label=\"@0x7f0b0064\"\n      android:name=\"com.huawei.opendevice.open.PpsAdActivity\"\n      android:exported=\"true\"\n      android:configChanges=\"keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <intent-filter>\n        <action\n          android:name=\"android.intent.action.VIEW\">\n        </action>\n        <category\n          android:name=\"android.intent.category.DEFAULT\">\n        </category>\n        <category\n          android:name=\"android.intent.category.BROWSABLE\">\n        </category>\n        <data\n          android:scheme=\"hwpps\"\n          android:host=\"ad\">\n        </data>\n      </intent-filter>\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui.WithActionBar\">\n      </meta-data>\n    </activity>\n    <activity\n      android:label=\"\"\n      android:name=\"com.huawei.opendevice.open.SimplePrivacyActivity\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hms.oobe\"\n      android:taskAffinity=\"com.huawei.hwid.pps.oobe\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <intent-filter>\n        <action\n          android:name=\"com.huawei.hms.ppskit.ACTION.SIMPLE_PRIVACY\">\n        </action>\n        <category\n          android:name=\"android.intent.category.DEFAULT\">\n        </category>\n        <category\n          android:name=\"android.intent.category.BROWSABLE\">\n        </category>\n      </intent-filter>\n      <intent-filter>\n        <action\n          android:name=\"android.intent.action.VIEW\">\n        </action>\n        <category\n          android:name=\"android.intent.category.DEFAULT\">\n        </category>\n        <category\n          android:name=\"android.intent.category.BROWSABLE\">\n        </category>\n        <data\n          android:scheme=\"hwpps\"\n          android:host=\"privacy\">\n        </data>\n      </intent-filter>\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui.WithActionBar\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.DeviceDefault\"\n      android:label=\"@0x7f0b006f\"\n      android:name=\"com.huawei.opendevice.open.OAIDMoreSettingActivity\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hms.oobe\"\n      android:configChanges=\"keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <intent-filter>\n        <action\n          android:name=\"com.huawei.hms.action.OAID_SETTING_MORE\">\n        </action>\n        <category\n          android:name=\"android.intent.category.DEFAULT\">\n        </category>\n      </intent-filter>\n      <intent-filter>\n        <action\n          android:name=\"android.intent.action.VIEW\">\n        </action>\n        <category\n          android:name=\"android.intent.category.DEFAULT\">\n        </category>\n        <category\n          android:name=\"android.intent.category.BROWSABLE\">\n        </category>\n        <data\n          android:scheme=\"hwpps\"\n          android:host=\"oaid_setting_more\">\n        </data>\n      </intent-filter>\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui.WithActionBar\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light.DarkActionBar\"\n      android:label=\"@0x7f0b006d\"\n      android:name=\"com.huawei.opendevice.open.AboutOaidActivity\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hms.oobe\"\n      android:configChanges=\"keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <intent-filter>\n        <action\n          android:name=\"android.intent.action.VIEW\">\n        </action>\n        <category\n          android:name=\"android.intent.category.DEFAULT\">\n        </category>\n        <category\n          android:name=\"android.intent.category.BROWSABLE\">\n        </category>\n        <data\n          android:scheme=\"hwads\"\n          android:host=\"about_oaid\">\n        </data>\n      </intent-filter>\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui.WithActionBar\">\n      </meta-data>\n    </activity>\n    <activity\n      android:name=\"com.huawei.opendevice.open.BaseSettingActivity\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hms.oobe\"\n      android:configChanges=\"keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize|uiMode\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui.WithActionBar\">\n      </meta-data>\n    </activity>\n    <service\n      android:name=\"com.huawei.openalliance.ad.ppskit.exsplash.PPSExSplashService\"\n      android:permission=\"android.permission.WRITE_SECURE_SETTINGS\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.persistent\">\n      <intent-filter>\n        <action\n          android:name=\"com.huawei.android.hms.ppskit.PPS_EXSPLASH_SERVICE\">\n        </action>\n      </intent-filter>\n    </service>\n    <service\n      android:name=\"com.huawei.hms.ads.ExSplashOutterService\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.persistent\">\n      <intent-filter>\n        <action\n          android:name=\"com.huawei.hms.ads.EXSPLASH_SERVICE\">\n        </action>\n      </intent-filter>\n    </service>\n    <activity\n      android:theme=\"@0x7f130253\"\n      android:name=\"com.huawei.appgallery.agd.internal.framework.download.MarketDownloadActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"orientation|screenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui.Translucent.NoTitleBar\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@0x7f130253\"\n      android:name=\"com.huawei.appgallery.agd.internal.service.installhiapp.GuideInstallAppGallery\"\n      android:exported=\"true\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui.Translucent.NoTitleBar\">\n      </meta-data>\n      <intent-filter>\n        <action\n          android:name=\"com.huawei.hwid.agd.service.intent.INSTALL_APP_GALLERY\">\n        </action>\n        <category\n          android:name=\"android.intent.category.DEFAULT\">\n        </category>\n      </intent-filter>\n    </activity>\n    <provider\n      android:name=\"android.support.v4.content.FileProvider\"\n      android:exported=\"false\"\n      android:authorities=\"com.huawei.hwid.agdsdk.fileprovider\"\n      android:grantUriPermissions=\"true\">\n      <meta-data\n        android:name=\"android.support.FILE_PROVIDER_PATHS\"\n        android:resource=\"@0x7f150000\">\n      </meta-data>\n    </provider>\n    <meta-data\n      android:name=\"com.huawei.hms.min_api_level:framework-manager:kams\"\n      android:value=\"1\">\n    </meta-data>\n    <meta-data\n      android:name=\"com.huawei.hms.min_api_level:framework-manager:kpms\"\n      android:value=\"1\">\n    </meta-data>\n    <meta-data\n      android:name=\"hms_module:KMSFinder.API\"\n      android:value=\"com.huawei.hms.fwksdk.MainEntry:1\">\n    </meta-data>\n    <meta-data\n      android:name=\"hms_context_module:KMSFinder.API\"\n      android:value=\"com.huawei.hms.fwksdk.KmsAttachBaseContext:1\">\n    </meta-data>\n    <provider\n      android:name=\"com.huawei.hms.fwkit.kams.provideragent.StubContentProvider\"\n      android:enabled=\"true\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.core\"\n      android:authorities=\"com.huawei.hms.contentprovider\">\n    </provider>\n    <provider\n      android:name=\"com.huawei.hms.commonkit.config.CommonKitProvider\"\n      android:enabled=\"true\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\"\n      android:authorities=\"com.huawei.hms.bindcommonprovider\"\n      android:initOrder=\"100\">\n    </provider>\n    <provider\n      android:name=\"com.huawei.hms.fwkit.provider.HMSFrameworkProvider\"\n      android:enabled=\"true\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\"\n      android:authorities=\"com.huawei.hms.servicemanager\">\n    </provider>\n    <provider\n      android:name=\"com.huawei.hms.fwkit.provider.UpdateSettingProvider\"\n      android:enabled=\"true\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\"\n      android:authorities=\"com.huawei.hms.fwkit.provider.UpdateSettingProvider\">\n    </provider>\n    <provider\n      android:name=\"com.huawei.hms.runtimekit.kitcontainerservice.KitProcessAgent1Provider\"\n      android:enabled=\"true\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:authorities=\"com.huawei.hms.runtimekit.kitcontainerservice.KitProcessAgent1Provider\">\n    </provider>\n    <provider\n      android:name=\"com.huawei.hms.runtimekit.kitcontainerservice.KitProcessAgent2Provider\"\n      android:enabled=\"true\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:authorities=\"com.huawei.hms.runtimekit.kitcontainerservice.KitProcessAgent2Provider\">\n    </provider>\n    <provider\n      android:name=\"com.huawei.hms.runtimekit.kitcontainerservice.KitProcessAgent3Provider\"\n      android:enabled=\"true\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:authorities=\"com.huawei.hms.runtimekit.kitcontainerservice.KitProcessAgent3Provider\">\n    </provider>\n    <provider\n      android:name=\"com.huawei.hms.runtimekit.kitcontainerservice.KitProcessAgentCoreProvider\"\n      android:enabled=\"true\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\"\n      android:authorities=\"com.huawei.hms.runtimekit.kitcontainerservice.KitProcessAgentCoreProvider\">\n    </provider>\n    <provider\n      android:name=\"com.huawei.hms.runtimekit.kitcontainerservice.KitProcessAgentPersistProvider\"\n      android:enabled=\"true\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.persistent\"\n      android:authorities=\"com.huawei.hms.runtimekit.kitcontainerservice.KitProcessAgentPersistProvider\">\n    </provider>\n    <provider\n      android:name=\"com.huawei.hms.commonkit.apptouch.datastore.AppTouchContentProvider\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\"\n      android:authorities=\"com.huawei.hms.fwkit.datastore\">\n    </provider>\n    <service\n      android:name=\"com.huawei.hms.fwksdk.service.DummyCoreService\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.fwksdk.service.DummyPersistService\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.persistent\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.fwkit.kpms.core.jobservice.HMSStubKitUpdateJobService\"\n      android:permission=\"android.permission.BIND_JOB_SERVICE\"\n      android:process=\"com.huawei.hwid.core\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.fwkit.kpms.core.jobservice.HMSStubKitRebootJobService\"\n      android:permission=\"android.permission.BIND_JOB_SERVICE\"\n      android:process=\"com.huawei.hwid.core\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.fwkit.kpms.core.jobservice.HMSStubKitUpdateAlarmService\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.fwkit.kpms.core.jobservice.HMSStubKitRebootService\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stubexplicit.HMSStableCaseService\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stubexplicit.HMSStableCaseJobService\"\n      android:permission=\"android.permission.BIND_JOB_SERVICE\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\">\n    </service>\n    <receiver\n      android:name=\"com.huawei.hms.fwksdk.broadcast.PersistCoreReceiver\"\n      android:enabled=\"true\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\">\n      <intent-filter>\n        <action\n          android:name=\"kitUpdateFromNotification_Persist\">\n        </action>\n      </intent-filter>\n    </receiver>\n    <receiver\n      android:name=\"com.huawei.hms.fwksdk.broadcast.HMSAppInstallBroadcastReceiver\"\n      android:enabled=\"true\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\">\n      <intent-filter>\n        <action\n          android:name=\"android.intent.action.MY_PACKAGE_REPLACED\">\n        </action>\n      </intent-filter>\n    </receiver>\n    <receiver\n      android:name=\"com.huawei.hms.fwksdk.broadcast.OOBEFirstBootReceiver\"\n      android:enabled=\"true\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.oobe\">\n      <intent-filter>\n        <action\n          android:name=\"android.intent.action.PRE_BOOT_COMPLETED\">\n        </action>\n      </intent-filter>\n    </receiver>\n    <receiver\n      android:name=\"com.huawei.hms.fwksdk.broadcast.PackageRemovedReceiver\"\n      android:enabled=\"true\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\">\n      <intent-filter>\n        <action\n          android:name=\"android.intent.action.PACKAGE_REMOVED\">\n        </action>\n        <data\n          android:scheme=\"package\">\n        </data>\n      </intent-filter>\n    </receiver>\n    <receiver\n      android:name=\"com.huawei.hms.fwksdk.broadcast.MultiUserSwitchReceiver\"\n      android:permission=\"com.huawei.permission.userSwitch\"\n      android:enabled=\"true\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.core\">\n      <intent-filter>\n        <action\n          android:name=\"com.huawei.hms.MultiUserSwitchReceiver\">\n        </action>\n      </intent-filter>\n    </receiver>\n    <activity\n      android:theme=\"@style/Theme.Translucent.NoTitleBar\"\n      android:name=\"com.huawei.hms.fwksdk.stub.UpdateStubActivity\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.nobreakcontainer\"\n      android:excludeFromRecents=\"true\"\n      android:launchMode=\"standard\"\n      android:configChanges=\"density|keyboardHidden|orientation|screenLayout|screenSize|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Translucent.NoTitleBar\"\n      android:name=\"com.huawei.hms.fwksdk.stub.UpdateNotificationStubActivity\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.nobreakcontainer\"\n      android:excludeFromRecents=\"true\"\n      android:launchMode=\"standard\"\n      android:configChanges=\"density|keyboardHidden|orientation|screenLayout|screenSize|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130108\"\n      android:name=\"com.huawei.hms.fwksdk.stub.HmsSettingActivity\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:excludeFromRecents=\"true\"\n      android:launchMode=\"standard\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n      <intent-filter>\n        <action\n          android:name=\"android.intent.action.APPLICATION_PREFERENCES\">\n        </action>\n        <category\n          android:name=\"android.intent.category.DEFAULT\">\n        </category>\n      </intent-filter>\n      <intent-filter>\n        <action\n          android:name=\"com.huawei.homevision.settings.action.EXTRA_APP_SETTINGS\">\n        </action>\n        <category\n          android:name=\"android.intent.category.DEFAULT\">\n        </category>\n      </intent-filter>\n      <meta-data\n        android:name=\"com.huawei.homevision.settings.menu.category\"\n        android:value=\"com.huawei.hms.main\">\n      </meta-data>\n      <meta-data\n        android:name=\"com.huawei.homevision.settings.menu.title\"\n        android:resource=\"@0x7f0b0503\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Translucent.NoTitleBar\"\n      android:name=\"com.huawei.hms.fwksdk.stub.AGCLinkActivity\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:excludeFromRecents=\"true\"\n      android:launchMode=\"standard\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n      <intent-filter>\n        <action\n          android:name=\"com.huawei.hms.agclink.VIEW_AGC_LINK\">\n        </action>\n        <category\n          android:name=\"android.intent.category.BROWSABLE\">\n        </category>\n        <category\n          android:name=\"android.intent.category.DEFAULT\">\n        </category>\n        <data\n          android:scheme=\"https\">\n        </data>\n        <data\n          android:scheme=\"http\">\n        </data>\n      </intent-filter>\n    </activity>\n    <activity\n      android:theme=\"@0x7f130108\"\n      android:name=\"com.huawei.hms.runtimekit.stubexplicit.TileLongClickJumperActivity\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:excludeFromRecents=\"true\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n      <intent-filter>\n        <action\n          android:name=\"android.service.quicksettings.action.QS_TILE_PREFERENCES\">\n        </action>\n      </intent-filter>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.NoTitleBar\"\n      android:name=\"com.huawei.hms.StatementActivity\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.oobe\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|layoutDirection|locale|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <intent-filter>\n        <action\n          android:name=\"com.huawei.hms.action.oobe.HW_HMS_STATEMENT\">\n        </action>\n      </intent-filter>\n      <intent-filter>\n        <action\n          android:name=\"android.intent.action.MAIN\">\n        </action>\n      </intent-filter>\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui.NoTitleBar\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.NoTitleBar\"\n      android:name=\"com.huawei.hms.AppAnalyticsStatementActivity\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.oobe\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|layoutDirection|locale|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <intent-filter>\n        <action\n          android:name=\"com.huawei.hms.action.oobe.HW_HMS_APP_ANALYTICS_STATEMENT\">\n        </action>\n      </intent-filter>\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui.NoTitleBar\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.NoTitleBar\"\n      android:name=\"com.huawei.hms.core.oobe.StatisticsAndAnalyticsPrivacyActivity\"\n      android:permission=\"com.huawei.permission.external_app_settings.USE_COMPONENT\"\n      android:enabled=\"true\"\n      android:process=\"com.huawei.hwid.oobe\"\n      android:configChanges=\"fontScale|layoutDirection|locale|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui.NoTitleBar\">\n      </meta-data>\n      <meta-data\n        android:name=\"com.android.settings.menu.category\"\n        android:value=\"com.huawei.hms.category.StatisticsAndAnalyticsPrivacy\">\n      </meta-data>\n      <meta-data\n        android:name=\"com.android.settings.menu.provider\"\n        android:value=\"content://com.huawei.hms.privacy.StatisticsAndAnalyticsProvider\">\n      </meta-data>\n      <meta-data\n        android:name=\"com.android.settings.menutitle\"\n        android:resource=\"@0x7f0b014d\">\n      </meta-data>\n      <meta-data\n        android:name=\"com.android.settings.menu.summary_one\"\n        android:resource=\"@0x7f0b014e\">\n      </meta-data>\n      <meta-data\n        android:name=\"com.android.settings.menu.summary_two\"\n        android:resource=\"@0x7f0b014f\">\n      </meta-data>\n      <meta-data\n        android:name=\"com.android.settings.menu_is_dynamic_show\"\n        android:value=\"true\">\n      </meta-data>\n      <meta-data\n        android:name=\"com.android.settings.menu.type\"\n        android:value=\"10\">\n      </meta-data>\n      <meta-data\n        android:name=\"com.android.settings.enhanced_search_config_file\"\n        android:resource=\"@0x7f150016\">\n      </meta-data>\n      <meta-data\n        android:name=\"com.android.settings.search_config_file\"\n        android:resource=\"@0x7f150017\">\n      </meta-data>\n      <meta-data\n        android:name=\"com.android.settings.new_search_config_file\"\n        android:resource=\"@0x7f150016\">\n      </meta-data>\n      <intent-filter>\n        <action\n          android:name=\"com.android.settings.action.EXTRA_APP_SETTINGS\">\n        </action>\n      </intent-filter>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.NoTitleBar\"\n      android:name=\"com.huawei.hms.core.oobe.UpdateSettingActivity\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.oobe\"\n      android:configChanges=\"fontScale|layoutDirection|locale|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <intent-filter>\n        <action\n          android:name=\"com.huawei.hms.action.oobe.HW_HMS_UPDATE_SETTING\">\n        </action>\n        <category\n          android:name=\"android.intent.category.DEFAULT\">\n        </category>\n      </intent-filter>\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui.NoTitleBar\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.NoTitleBar\"\n      android:name=\"com.huawei.hms.core.oobe.PrivacyStatementActivity\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.oobe\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|layoutDirection|locale|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <intent-filter>\n        <action\n          android:name=\"com.huawei.hms.action.PRIVACY_STATEMENT\">\n        </action>\n        <category\n          android:name=\"android.intent.category.DEFAULT\">\n        </category>\n      </intent-filter>\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui.NoTitleBar\">\n      </meta-data>\n    </activity>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitPersistentStubService1\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.persistent\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitPersistentStubService2\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.persistent\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitPersistentStubService3\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.persistent\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitPersistentStubService4\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.persistent\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitPersistentStubService5\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.persistent\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitPersistentStubService6\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.persistent\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitPersistentStubService7\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.persistent\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitPersistentStubService8\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.persistent\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitPersistentStubService9\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.persistent\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitPersistentStubService10\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.persistent\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitPersistentStubService11\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.persistent\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitPersistentStubService12\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.persistent\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitPersistentStubService13\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.persistent\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitPersistentStubService14\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.persistent\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitPersistentStubService15\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.persistent\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitPersistentStubService16\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.persistent\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitPersistentStubService17\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.persistent\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitPersistentStubService18\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.persistent\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitPersistentStubService19\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.persistent\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitPersistentStubService20\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.persistent\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitPersistentStubService21\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.persistent\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitPersistentStubService22\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.persistent\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitPersistentStubService23\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.persistent\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitPersistentStubService24\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.persistent\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitPersistentStubService25\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.persistent\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitPersistentStubService26\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.persistent\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitPersistentStubService27\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.persistent\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitPersistentStubService28\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.persistent\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitPersistentStubService29\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.persistent\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitPersistentStubService30\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.persistent\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitPersistentStubService31\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.persistent\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitPersistentStubService32\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.persistent\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitPersistentStubService33\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.persistent\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitPersistentStubService34\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.persistent\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitPersistentStubService35\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.persistent\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitPersistentStubService36\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.persistent\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitPersistentStubService37\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.persistent\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitPersistentStubService38\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.persistent\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitPersistentStubService39\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.persistent\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitPersistentStubService40\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.persistent\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitPersistentStubService41\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.persistent\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitPersistentStubService42\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.persistent\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitPersistentStubService43\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.persistent\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitPersistentStubService44\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.persistent\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitPersistentStubService45\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.persistent\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitPersistentStubService46\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.persistent\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitPersistentStubService47\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.persistent\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitPersistentStubService48\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.persistent\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitPersistentStubService49\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.persistent\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitPersistentStubService50\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.persistent\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitPersistentNEStubService1\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.persistent\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitPersistentNEStubService2\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.persistent\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitPersistentNEStubService3\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.persistent\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitPersistentNEStubService4\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.persistent\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitPersistentNEStubService5\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.persistent\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitPersistentNEStubService6\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.persistent\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitPersistentNEStubService7\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.persistent\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitPersistentNEStubService8\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.persistent\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitPersistentNEStubService9\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.persistent\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitPersistentNEStubService10\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.persistent\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitPersistentNEStubService11\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.persistent\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitPersistentNEStubService12\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.persistent\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitPersistentNEStubService13\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.persistent\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitPersistentNEStubService14\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.persistent\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitPersistentNEStubService15\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.persistent\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitPersistentNEStubService16\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.persistent\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitPersistentNEStubService17\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.persistent\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitPersistentNEStubService18\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.persistent\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitPersistentNEStubService19\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.persistent\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitPersistentNEStubService20\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.persistent\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitPersistentNEStubService21\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.persistent\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitPersistentNEStubService22\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.persistent\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitPersistentNEStubService23\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.persistent\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitPersistentNEStubService24\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.persistent\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitPersistentNEStubService25\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.persistent\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitPersistentNEStubService26\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.persistent\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitPersistentNEStubService27\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.persistent\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitPersistentNEStubService28\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.persistent\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitPersistentNEStubService29\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.persistent\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitPersistentNEStubService30\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.persistent\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitPersistentNEStubService31\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.persistent\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitPersistentNEStubService32\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.persistent\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitPersistentNEStubService33\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.persistent\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitPersistentNEStubService34\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.persistent\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitPersistentNEStubService35\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.persistent\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitPersistentNEStubService36\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.persistent\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitPersistentNEStubService37\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.persistent\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitPersistentNEStubService38\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.persistent\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitPersistentNEStubService39\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.persistent\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitPersistentNEStubService40\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.persistent\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitPersistentNEStubService41\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.persistent\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitPersistentNEStubService42\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.persistent\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitPersistentNEStubService43\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.persistent\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitPersistentNEStubService44\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.persistent\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitPersistentNEStubService45\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.persistent\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitPersistentNEStubService46\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.persistent\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitPersistentNEStubService47\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.persistent\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitPersistentNEStubService48\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.persistent\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitPersistentNEStubService49\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.persistent\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitPersistentNEStubService50\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.persistent\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitCoreStubService1\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.core\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitCoreStubService2\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.core\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitCoreStubService3\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.core\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitCoreStubService4\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.core\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitCoreStubService5\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.core\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitCoreStubService6\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.core\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitCoreStubService7\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.core\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitCoreStubService8\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.core\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitCoreStubService9\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.core\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitCoreStubService10\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.core\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitCoreStubService11\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.core\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitCoreStubService12\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.core\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitCoreStubService13\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.core\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitCoreStubService14\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.core\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitCoreStubService15\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.core\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitCoreStubService16\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.core\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitCoreStubService17\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.core\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitCoreStubService18\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.core\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitCoreStubService19\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.core\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitCoreStubService20\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.core\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitCoreStubService21\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.core\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitCoreStubService22\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.core\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitCoreStubService23\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.core\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitCoreStubService24\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.core\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitCoreStubService25\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.core\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitCoreStubService26\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.core\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitCoreStubService27\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.core\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitCoreStubService28\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.core\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitCoreStubService29\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.core\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitCoreStubService30\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.core\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitCoreStubService31\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.core\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitCoreStubService32\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.core\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitCoreStubService33\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.core\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitCoreStubService34\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.core\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitCoreStubService35\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.core\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitCoreStubService36\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.core\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitCoreStubService37\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.core\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitCoreStubService38\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.core\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitCoreStubService39\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.core\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitCoreStubService40\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.core\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitCoreStubService41\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.core\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitCoreStubService42\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.core\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitCoreStubService43\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.core\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitCoreStubService44\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.core\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitCoreStubService45\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.core\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitCoreStubService46\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.core\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitCoreStubService47\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.core\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitCoreStubService48\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.core\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitCoreStubService49\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.core\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitCoreStubService50\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.core\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitCoreNEStubService1\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitCoreNEStubService2\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitCoreNEStubService3\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitCoreNEStubService4\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitCoreNEStubService5\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitCoreNEStubService6\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitCoreNEStubService7\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitCoreNEStubService8\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitCoreNEStubService9\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitCoreNEStubService10\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitCoreNEStubService11\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitCoreNEStubService12\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitCoreNEStubService13\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitCoreNEStubService14\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitCoreNEStubService15\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitCoreNEStubService16\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitCoreNEStubService17\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitCoreNEStubService18\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitCoreNEStubService19\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitCoreNEStubService20\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitCoreNEStubService21\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitCoreNEStubService22\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitCoreNEStubService23\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitCoreNEStubService24\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitCoreNEStubService25\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitCoreNEStubService26\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitCoreNEStubService27\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitCoreNEStubService28\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitCoreNEStubService29\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitCoreNEStubService30\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitCoreNEStubService31\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitCoreNEStubService32\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitCoreNEStubService33\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitCoreNEStubService34\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitCoreNEStubService35\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitCoreNEStubService36\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitCoreNEStubService37\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitCoreNEStubService38\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitCoreNEStubService39\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitCoreNEStubService40\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitCoreNEStubService41\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitCoreNEStubService42\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitCoreNEStubService43\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitCoreNEStubService44\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitCoreNEStubService45\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitCoreNEStubService46\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitCoreNEStubService47\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitCoreNEStubService48\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitCoreNEStubService49\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitCoreNEStubService50\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\">\n    </service>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitStandardCoreStubActivity1\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.core\"\n      android:launchMode=\"standard\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopCoreStubActivity1\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.core\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopCoreStubActivity2\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.core\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopCoreStubActivity3\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.core\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopCoreStubActivity4\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.core\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopCoreStubActivity5\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.core\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopCoreStubActivity6\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.core\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopCoreStubActivity7\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.core\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopCoreStubActivity8\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.core\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopCoreStubActivity9\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.core\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopCoreStubActivity10\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.core\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceCoreStubActivity1\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.core\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceCoreStubActivity2\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.core\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceCoreStubActivity3\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.core\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceCoreStubActivity4\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.core\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceCoreStubActivity5\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.core\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceCoreStubActivity6\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.core\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceCoreStubActivity7\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.core\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceCoreStubActivity8\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.core\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceCoreStubActivity9\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.core\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceCoreStubActivity10\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.core\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskCoreStubActivity1\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.core\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskCoreStubActivity2\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.core\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskCoreStubActivity3\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.core\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskCoreStubActivity4\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.core\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskCoreStubActivity5\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.core\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskCoreStubActivity6\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.core\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskCoreStubActivity7\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.core\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskCoreStubActivity8\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.core\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskCoreStubActivity9\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.core\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskCoreStubActivity10\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.core\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitStandardCoreNEStubActivity1\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\"\n      android:launchMode=\"standard\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopCoreNEStubActivity1\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopCoreNEStubActivity2\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopCoreNEStubActivity3\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopCoreNEStubActivity4\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopCoreNEStubActivity5\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopCoreNEStubActivity6\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopCoreNEStubActivity7\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopCoreNEStubActivity8\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopCoreNEStubActivity9\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopCoreNEStubActivity10\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceCoreNEStubActivity1\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceCoreNEStubActivity2\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceCoreNEStubActivity3\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceCoreNEStubActivity4\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceCoreNEStubActivity5\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceCoreNEStubActivity6\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceCoreNEStubActivity7\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceCoreNEStubActivity8\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceCoreNEStubActivity9\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceCoreNEStubActivity10\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskCoreNEStubActivity1\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskCoreNEStubActivity2\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskCoreNEStubActivity3\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskCoreNEStubActivity4\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskCoreNEStubActivity5\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskCoreNEStubActivity6\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskCoreNEStubActivity7\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskCoreNEStubActivity8\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskCoreNEStubActivity9\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskCoreNEStubActivity10\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitStandardCoreTransparentActivity1\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.core\"\n      android:launchMode=\"standard\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopCoreTransparentActivity1\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.core\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopCoreTransparentActivity2\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.core\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopCoreTransparentActivity3\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.core\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopCoreTransparentActivity4\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.core\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopCoreTransparentActivity5\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.core\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceCoreTransparentActivity1\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.core\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceCoreTransparentActivity2\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.core\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceCoreTransparentActivity3\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.core\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceCoreTransparentActivity4\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.core\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceCoreTransparentActivity5\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.core\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskCoreTransparentActivity1\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.core\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskCoreTransparentActivity2\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.core\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskCoreTransparentActivity3\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.core\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskCoreTransparentActivity4\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.core\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskCoreTransparentActivity5\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.core\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitStandardCoreNETransparentActivity1\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\"\n      android:launchMode=\"standard\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopCoreNETransparentActivity1\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopCoreNETransparentActivity2\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopCoreNETransparentActivity3\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopCoreNETransparentActivity4\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopCoreNETransparentActivity5\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceCoreNETransparentActivity1\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceCoreNETransparentActivity2\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceCoreNETransparentActivity3\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceCoreNETransparentActivity4\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceCoreNETransparentActivity5\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskCoreNETransparentActivity1\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskCoreNETransparentActivity2\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskCoreNETransparentActivity3\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskCoreNETransparentActivity4\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskCoreNETransparentActivity5\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC1StubService1\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC1StubService2\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC1StubService3\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC1StubService4\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC1StubService5\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC1StubService6\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC1StubService7\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC1StubService8\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC1StubService9\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC1StubService10\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC1StubService11\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC1StubService12\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC1StubService13\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC1StubService14\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC1StubService15\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC1StubService16\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC1StubService17\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC1StubService18\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC1StubService19\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC1StubService20\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC1StubService21\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC1StubService22\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC1StubService23\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC1StubService24\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC1StubService25\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC1StubService26\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC1StubService27\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC1StubService28\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC1StubService29\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC1StubService30\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC1StubService31\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC1StubService32\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC1StubService33\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC1StubService34\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC1StubService35\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC1StubService36\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC1StubService37\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC1StubService38\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC1StubService39\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC1StubService40\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC1StubService41\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC1StubService42\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC1StubService43\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC1StubService44\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC1StubService45\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC1StubService46\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC1StubService47\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC1StubService48\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC1StubService49\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC1StubService50\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC1NEStubService1\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC1NEStubService2\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC1NEStubService3\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC1NEStubService4\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC1NEStubService5\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC1NEStubService6\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC1NEStubService7\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC1NEStubService8\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC1NEStubService9\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC1NEStubService10\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC1NEStubService11\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC1NEStubService12\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC1NEStubService13\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC1NEStubService14\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC1NEStubService15\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC1NEStubService16\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC1NEStubService17\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC1NEStubService18\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC1NEStubService19\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC1NEStubService20\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC1NEStubService21\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC1NEStubService22\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC1NEStubService23\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC1NEStubService24\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC1NEStubService25\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC1NEStubService26\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC1NEStubService27\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC1NEStubService28\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC1NEStubService29\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC1NEStubService30\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC1NEStubService31\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC1NEStubService32\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC1NEStubService33\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC1NEStubService34\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC1NEStubService35\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC1NEStubService36\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC1NEStubService37\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC1NEStubService38\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC1NEStubService39\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC1NEStubService40\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC1NEStubService41\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC1NEStubService42\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC1NEStubService43\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC1NEStubService44\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC1NEStubService45\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC1NEStubService46\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC1NEStubService47\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC1NEStubService48\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC1NEStubService49\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC1NEStubService50\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\">\n    </service>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitStandardC1StubActivity1\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"standard\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC1StubActivity1\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC1StubActivity2\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC1StubActivity3\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC1StubActivity4\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC1StubActivity5\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC1StubActivity6\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC1StubActivity7\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC1StubActivity8\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC1StubActivity9\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC1StubActivity10\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC1StubActivity11\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC1StubActivity12\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC1StubActivity13\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC1StubActivity14\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC1StubActivity15\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC1StubActivity16\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC1StubActivity17\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC1StubActivity18\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC1StubActivity19\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC1StubActivity20\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC1StubActivity1\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC1StubActivity2\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC1StubActivity3\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC1StubActivity4\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC1StubActivity5\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC1StubActivity6\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC1StubActivity7\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC1StubActivity8\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC1StubActivity9\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC1StubActivity10\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC1StubActivity11\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC1StubActivity12\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC1StubActivity13\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC1StubActivity14\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC1StubActivity15\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC1StubActivity16\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC1StubActivity17\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC1StubActivity18\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC1StubActivity19\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC1StubActivity20\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC1StubActivity1\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC1StubActivity2\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC1StubActivity3\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC1StubActivity4\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC1StubActivity5\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC1StubActivity6\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC1StubActivity7\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC1StubActivity8\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC1StubActivity9\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC1StubActivity10\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC1StubActivity11\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC1StubActivity12\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC1StubActivity13\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC1StubActivity14\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC1StubActivity15\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC1StubActivity16\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC1StubActivity17\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC1StubActivity18\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC1StubActivity19\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC1StubActivity20\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitStandardC1NEStubActivity1\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"standard\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC1NEStubActivity1\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC1NEStubActivity2\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC1NEStubActivity3\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC1NEStubActivity4\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC1NEStubActivity5\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC1NEStubActivity6\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC1NEStubActivity7\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC1NEStubActivity8\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC1NEStubActivity9\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC1NEStubActivity10\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC1NEStubActivity11\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC1NEStubActivity12\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC1NEStubActivity13\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC1NEStubActivity14\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC1NEStubActivity15\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC1NEStubActivity16\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC1NEStubActivity17\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC1NEStubActivity18\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC1NEStubActivity19\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC1NEStubActivity20\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC1NEStubActivity1\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC1NEStubActivity2\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC1NEStubActivity3\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC1NEStubActivity4\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC1NEStubActivity5\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC1NEStubActivity6\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC1NEStubActivity7\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC1NEStubActivity8\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC1NEStubActivity9\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC1NEStubActivity10\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC1NEStubActivity11\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC1NEStubActivity12\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC1NEStubActivity13\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC1NEStubActivity14\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC1NEStubActivity15\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC1NEStubActivity16\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC1NEStubActivity17\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC1NEStubActivity18\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC1NEStubActivity19\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC1NEStubActivity20\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC1NEStubActivity1\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC1NEStubActivity2\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC1NEStubActivity3\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC1NEStubActivity4\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC1NEStubActivity5\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC1NEStubActivity6\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC1NEStubActivity7\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC1NEStubActivity8\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC1NEStubActivity9\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC1NEStubActivity10\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC1NEStubActivity11\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC1NEStubActivity12\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC1NEStubActivity13\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC1NEStubActivity14\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC1NEStubActivity15\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC1NEStubActivity16\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC1NEStubActivity17\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC1NEStubActivity18\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC1NEStubActivity19\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC1NEStubActivity20\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitStandardC1TransparentActivity1\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"standard\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC1TransparentActivity1\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC1TransparentActivity2\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC1TransparentActivity3\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC1TransparentActivity4\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC1TransparentActivity5\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC1TransparentActivity1\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC1TransparentActivity2\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC1TransparentActivity3\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC1TransparentActivity4\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC1TransparentActivity5\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC1TransparentActivity1\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC1TransparentActivity2\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC1TransparentActivity3\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC1TransparentActivity4\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC1TransparentActivity5\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitStandardC1NETransparentActivity1\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"standard\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC1NETransparentActivity1\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC1NETransparentActivity2\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC1NETransparentActivity3\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC1NETransparentActivity4\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC1NETransparentActivity5\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC1NETransparentActivity1\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC1NETransparentActivity2\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC1NETransparentActivity3\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC1NETransparentActivity4\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC1NETransparentActivity5\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC1NETransparentActivity1\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC1NETransparentActivity2\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC1NETransparentActivity3\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC1NETransparentActivity4\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC1NETransparentActivity5\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC2StubService1\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC2StubService2\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC2StubService3\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC2StubService4\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC2StubService5\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC2StubService6\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC2StubService7\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC2StubService8\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC2StubService9\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC2StubService10\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC2StubService11\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC2StubService12\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC2StubService13\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC2StubService14\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC2StubService15\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC2StubService16\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC2StubService17\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC2StubService18\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC2StubService19\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC2StubService20\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC2StubService21\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC2StubService22\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC2StubService23\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC2StubService24\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC2StubService25\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC2StubService26\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC2StubService27\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC2StubService28\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC2StubService29\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC2StubService30\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC2StubService31\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC2StubService32\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC2StubService33\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC2StubService34\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC2StubService35\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC2StubService36\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC2StubService37\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC2StubService38\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC2StubService39\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC2StubService40\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC2StubService41\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC2StubService42\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC2StubService43\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC2StubService44\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC2StubService45\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC2StubService46\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC2StubService47\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC2StubService48\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC2StubService49\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC2StubService50\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC2NEStubService1\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC2NEStubService2\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC2NEStubService3\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC2NEStubService4\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC2NEStubService5\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC2NEStubService6\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC2NEStubService7\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC2NEStubService8\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC2NEStubService9\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC2NEStubService10\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC2NEStubService11\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC2NEStubService12\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC2NEStubService13\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC2NEStubService14\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC2NEStubService15\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC2NEStubService16\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC2NEStubService17\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC2NEStubService18\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC2NEStubService19\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC2NEStubService20\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC2NEStubService21\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC2NEStubService22\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC2NEStubService23\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC2NEStubService24\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC2NEStubService25\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC2NEStubService26\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC2NEStubService27\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC2NEStubService28\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC2NEStubService29\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC2NEStubService30\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC2NEStubService31\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC2NEStubService32\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC2NEStubService33\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC2NEStubService34\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC2NEStubService35\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC2NEStubService36\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC2NEStubService37\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC2NEStubService38\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC2NEStubService39\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC2NEStubService40\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC2NEStubService41\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC2NEStubService42\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC2NEStubService43\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC2NEStubService44\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC2NEStubService45\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC2NEStubService46\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC2NEStubService47\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC2NEStubService48\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC2NEStubService49\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC2NEStubService50\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\">\n    </service>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitStandardC2StubActivity1\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"standard\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC2StubActivity1\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC2StubActivity2\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC2StubActivity3\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC2StubActivity4\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC2StubActivity5\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC2StubActivity6\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC2StubActivity7\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC2StubActivity8\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC2StubActivity9\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC2StubActivity10\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC2StubActivity11\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC2StubActivity12\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC2StubActivity13\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC2StubActivity14\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC2StubActivity15\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC2StubActivity16\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC2StubActivity17\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC2StubActivity18\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC2StubActivity19\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC2StubActivity20\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC2StubActivity1\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC2StubActivity2\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC2StubActivity3\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC2StubActivity4\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC2StubActivity5\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC2StubActivity6\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC2StubActivity7\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC2StubActivity8\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC2StubActivity9\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC2StubActivity10\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC2StubActivity11\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC2StubActivity12\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC2StubActivity13\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC2StubActivity14\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC2StubActivity15\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC2StubActivity16\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC2StubActivity17\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC2StubActivity18\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC2StubActivity19\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC2StubActivity20\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC2StubActivity1\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC2StubActivity2\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC2StubActivity3\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC2StubActivity4\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC2StubActivity5\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC2StubActivity6\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC2StubActivity7\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC2StubActivity8\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC2StubActivity9\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC2StubActivity10\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC2StubActivity11\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC2StubActivity12\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC2StubActivity13\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC2StubActivity14\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC2StubActivity15\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC2StubActivity16\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC2StubActivity17\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC2StubActivity18\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC2StubActivity19\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC2StubActivity20\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitStandardC2NEStubActivity1\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"standard\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC2NEStubActivity1\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC2NEStubActivity2\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC2NEStubActivity3\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC2NEStubActivity4\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC2NEStubActivity5\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC2NEStubActivity6\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC2NEStubActivity7\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC2NEStubActivity8\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC2NEStubActivity9\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC2NEStubActivity10\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC2NEStubActivity11\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC2NEStubActivity12\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC2NEStubActivity13\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC2NEStubActivity14\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC2NEStubActivity15\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC2NEStubActivity16\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC2NEStubActivity17\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC2NEStubActivity18\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC2NEStubActivity19\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC2NEStubActivity20\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC2NEStubActivity1\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC2NEStubActivity2\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC2NEStubActivity3\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC2NEStubActivity4\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC2NEStubActivity5\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC2NEStubActivity6\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC2NEStubActivity7\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC2NEStubActivity8\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC2NEStubActivity9\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC2NEStubActivity10\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC2NEStubActivity11\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC2NEStubActivity12\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC2NEStubActivity13\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC2NEStubActivity14\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC2NEStubActivity15\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC2NEStubActivity16\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC2NEStubActivity17\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC2NEStubActivity18\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC2NEStubActivity19\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC2NEStubActivity20\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC2NEStubActivity1\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC2NEStubActivity2\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC2NEStubActivity3\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC2NEStubActivity4\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC2NEStubActivity5\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC2NEStubActivity6\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC2NEStubActivity7\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC2NEStubActivity8\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC2NEStubActivity9\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC2NEStubActivity10\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC2NEStubActivity11\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC2NEStubActivity12\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC2NEStubActivity13\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC2NEStubActivity14\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC2NEStubActivity15\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC2NEStubActivity16\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC2NEStubActivity17\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC2NEStubActivity18\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC2NEStubActivity19\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC2NEStubActivity20\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitStandardC2TransparentActivity1\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"standard\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC2TransparentActivity1\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC2TransparentActivity2\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC2TransparentActivity3\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC2TransparentActivity4\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC2TransparentActivity5\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC2TransparentActivity1\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC2TransparentActivity2\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC2TransparentActivity3\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC2TransparentActivity4\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC2TransparentActivity5\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC2TransparentActivity1\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC2TransparentActivity2\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC2TransparentActivity3\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC2TransparentActivity4\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC2TransparentActivity5\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitStandardC2NETransparentActivity1\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"standard\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC2NETransparentActivity1\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC2NETransparentActivity2\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC2NETransparentActivity3\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC2NETransparentActivity4\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC2NETransparentActivity5\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC2NETransparentActivity1\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC2NETransparentActivity2\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC2NETransparentActivity3\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC2NETransparentActivity4\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC2NETransparentActivity5\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC2NETransparentActivity1\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC2NETransparentActivity2\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC2NETransparentActivity3\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC2NETransparentActivity4\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC2NETransparentActivity5\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC3StubService1\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC3StubService2\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC3StubService3\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC3StubService4\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC3StubService5\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC3StubService6\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC3StubService7\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC3StubService8\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC3StubService9\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC3StubService10\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC3StubService11\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC3StubService12\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC3StubService13\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC3StubService14\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC3StubService15\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC3StubService16\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC3StubService17\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC3StubService18\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC3StubService19\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC3StubService20\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC3StubService21\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC3StubService22\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC3StubService23\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC3StubService24\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC3StubService25\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC3StubService26\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC3StubService27\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC3StubService28\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC3StubService29\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC3StubService30\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC3StubService31\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC3StubService32\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC3StubService33\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC3StubService34\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC3StubService35\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC3StubService36\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC3StubService37\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC3StubService38\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC3StubService39\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC3StubService40\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC3StubService41\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC3StubService42\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC3StubService43\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC3StubService44\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC3StubService45\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC3StubService46\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC3StubService47\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC3StubService48\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC3StubService49\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC3StubService50\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC3NEStubService1\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC3NEStubService2\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC3NEStubService3\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC3NEStubService4\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC3NEStubService5\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC3NEStubService6\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC3NEStubService7\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC3NEStubService8\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC3NEStubService9\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC3NEStubService10\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC3NEStubService11\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC3NEStubService12\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC3NEStubService13\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC3NEStubService14\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC3NEStubService15\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC3NEStubService16\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC3NEStubService17\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC3NEStubService18\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC3NEStubService19\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC3NEStubService20\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC3NEStubService21\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC3NEStubService22\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC3NEStubService23\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC3NEStubService24\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC3NEStubService25\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC3NEStubService26\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC3NEStubService27\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC3NEStubService28\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC3NEStubService29\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC3NEStubService30\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC3NEStubService31\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC3NEStubService32\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC3NEStubService33\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC3NEStubService34\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC3NEStubService35\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC3NEStubService36\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC3NEStubService37\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC3NEStubService38\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC3NEStubService39\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC3NEStubService40\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC3NEStubService41\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC3NEStubService42\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC3NEStubService43\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC3NEStubService44\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC3NEStubService45\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC3NEStubService46\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC3NEStubService47\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC3NEStubService48\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC3NEStubService49\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\">\n    </service>\n    <service\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitC3NEStubService50\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\">\n    </service>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitStandardC3StubActivity1\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"standard\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC3StubActivity1\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC3StubActivity2\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC3StubActivity3\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC3StubActivity4\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC3StubActivity5\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC3StubActivity6\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC3StubActivity7\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC3StubActivity8\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC3StubActivity9\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC3StubActivity10\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC3StubActivity11\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC3StubActivity12\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC3StubActivity13\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC3StubActivity14\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC3StubActivity15\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC3StubActivity16\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC3StubActivity17\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC3StubActivity18\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC3StubActivity19\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC3StubActivity20\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC3StubActivity1\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC3StubActivity2\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC3StubActivity3\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC3StubActivity4\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC3StubActivity5\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC3StubActivity6\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC3StubActivity7\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC3StubActivity8\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC3StubActivity9\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC3StubActivity10\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC3StubActivity11\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC3StubActivity12\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC3StubActivity13\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC3StubActivity14\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC3StubActivity15\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC3StubActivity16\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC3StubActivity17\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC3StubActivity18\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC3StubActivity19\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC3StubActivity20\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC3StubActivity1\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC3StubActivity2\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC3StubActivity3\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC3StubActivity4\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC3StubActivity5\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC3StubActivity6\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC3StubActivity7\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC3StubActivity8\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC3StubActivity9\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC3StubActivity10\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC3StubActivity11\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC3StubActivity12\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC3StubActivity13\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC3StubActivity14\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC3StubActivity15\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC3StubActivity16\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC3StubActivity17\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC3StubActivity18\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC3StubActivity19\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC3StubActivity20\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitStandardC3NEStubActivity1\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"standard\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC3NEStubActivity1\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC3NEStubActivity2\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC3NEStubActivity3\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC3NEStubActivity4\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC3NEStubActivity5\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC3NEStubActivity6\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC3NEStubActivity7\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC3NEStubActivity8\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC3NEStubActivity9\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC3NEStubActivity10\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC3NEStubActivity11\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC3NEStubActivity12\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC3NEStubActivity13\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC3NEStubActivity14\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC3NEStubActivity15\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC3NEStubActivity16\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC3NEStubActivity17\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC3NEStubActivity18\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC3NEStubActivity19\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC3NEStubActivity20\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC3NEStubActivity1\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC3NEStubActivity2\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC3NEStubActivity3\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC3NEStubActivity4\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC3NEStubActivity5\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC3NEStubActivity6\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC3NEStubActivity7\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC3NEStubActivity8\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC3NEStubActivity9\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC3NEStubActivity10\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC3NEStubActivity11\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC3NEStubActivity12\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC3NEStubActivity13\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC3NEStubActivity14\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC3NEStubActivity15\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC3NEStubActivity16\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC3NEStubActivity17\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC3NEStubActivity18\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC3NEStubActivity19\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC3NEStubActivity20\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC3NEStubActivity1\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC3NEStubActivity2\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC3NEStubActivity3\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC3NEStubActivity4\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC3NEStubActivity5\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC3NEStubActivity6\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC3NEStubActivity7\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC3NEStubActivity8\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC3NEStubActivity9\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC3NEStubActivity10\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC3NEStubActivity11\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC3NEStubActivity12\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC3NEStubActivity13\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC3NEStubActivity14\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC3NEStubActivity15\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC3NEStubActivity16\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC3NEStubActivity17\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC3NEStubActivity18\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC3NEStubActivity19\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC3NEStubActivity20\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitStandardC3TransparentActivity1\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"standard\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC3TransparentActivity1\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC3TransparentActivity2\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC3TransparentActivity3\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC3TransparentActivity4\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC3TransparentActivity5\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC3TransparentActivity1\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC3TransparentActivity2\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC3TransparentActivity3\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC3TransparentActivity4\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC3TransparentActivity5\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC3TransparentActivity1\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC3TransparentActivity2\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC3TransparentActivity3\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC3TransparentActivity4\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC3TransparentActivity5\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitStandardC3NETransparentActivity1\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"standard\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC3NETransparentActivity1\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC3NETransparentActivity2\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC3NETransparentActivity3\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC3NETransparentActivity4\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC3NETransparentActivity5\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC3NETransparentActivity1\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC3NETransparentActivity2\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC3NETransparentActivity3\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC3NETransparentActivity4\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC3NETransparentActivity5\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC3NETransparentActivity1\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC3NETransparentActivity2\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC3NETransparentActivity3\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC3NETransparentActivity4\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bc\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC3NETransparentActivity5\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitStandardC1NRStubActivity1\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"standard\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\"\n      android:resizeableActivity=\"false\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC1NRStubActivity1\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\"\n      android:resizeableActivity=\"false\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC1NRStubActivity1\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\"\n      android:resizeableActivity=\"false\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC1NRStubActivity1\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\"\n      android:resizeableActivity=\"false\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitStandardC1NENRStubActivity1\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"standard\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\"\n      android:resizeableActivity=\"false\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC1NENRStubActivity1\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\"\n      android:resizeableActivity=\"false\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC1NENRStubActivity1\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\"\n      android:resizeableActivity=\"false\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC1NENRStubActivity1\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container1\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\"\n      android:resizeableActivity=\"false\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitStandardC2NRStubActivity1\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"standard\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\"\n      android:resizeableActivity=\"false\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC2NRStubActivity1\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\"\n      android:resizeableActivity=\"false\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC2NRStubActivity1\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\"\n      android:resizeableActivity=\"false\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC2NRStubActivity1\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\"\n      android:resizeableActivity=\"false\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitStandardC2NENRStubActivity1\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"standard\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\"\n      android:resizeableActivity=\"false\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC2NENRStubActivity1\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\"\n      android:resizeableActivity=\"false\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC2NENRStubActivity1\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\"\n      android:resizeableActivity=\"false\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC2NENRStubActivity1\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container2\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\"\n      android:resizeableActivity=\"false\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitStandardC3NRStubActivity1\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"standard\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\"\n      android:resizeableActivity=\"false\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC3NRStubActivity1\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\"\n      android:resizeableActivity=\"false\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC3NRStubActivity1\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\"\n      android:resizeableActivity=\"false\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC3NRStubActivity1\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\"\n      android:resizeableActivity=\"false\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitStandardC3NENRStubActivity1\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"standard\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\"\n      android:resizeableActivity=\"false\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopC3NENRStubActivity1\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\"\n      android:resizeableActivity=\"false\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceC3NENRStubActivity1\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\"\n      android:resizeableActivity=\"false\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskC3NENRStubActivity1\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.container3\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\"\n      android:resizeableActivity=\"false\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitStandardCoreNRStubActivity1\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.core\"\n      android:launchMode=\"standard\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\"\n      android:resizeableActivity=\"false\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopCoreNRStubActivity1\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.core\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\"\n      android:resizeableActivity=\"false\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceCoreNRStubActivity1\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.core\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\"\n      android:resizeableActivity=\"false\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskCoreNRStubActivity1\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.core\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\"\n      android:resizeableActivity=\"false\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitStandardCoreNENRStubActivity1\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\"\n      android:launchMode=\"standard\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\"\n      android:resizeableActivity=\"false\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTopCoreNENRStubActivity1\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\"\n      android:resizeableActivity=\"false\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleInstanceCoreNENRStubActivity1\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\"\n      android:resizeableActivity=\"false\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f130008\"\n      android:name=\"com.huawei.hms.runtimekit.stub.HMSKitSingleTaskCoreNENRStubActivity1\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\"\n      android:resizeableActivity=\"false\">\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Translucent.NoTitleBar\"\n      android:name=\"com.huawei.hms.approuter.AppRouterActivity\"\n      android:enabled=\"true\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.nobreakcontainer\"\n      android:excludeFromRecents=\"true\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize|touchscreen|uiMode\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui.Translucent.NoTitleBar\">\n      </meta-data>\n      <intent-filter\n        android:priority=\"900\">\n        <action\n          android:name=\"android.intent.action.VIEW\">\n        </action>\n        <action\n          android:name=\"android.nfc.action.NDEF_DISCOVERED\">\n        </action>\n        <category\n          android:name=\"android.intent.category.BROWSABLE\">\n        </category>\n        <category\n          android:name=\"android.intent.category.DEFAULT\">\n        </category>\n        <data\n          android:scheme=\"https\">\n        </data>\n        <data\n          android:scheme=\"http\">\n        </data>\n        <data\n          android:host=\"*.link.cloud.huawei.com\">\n        </data>\n        <data\n          android:host=\"link.cloud.huawei.com\">\n        </data>\n        <data\n          android:pathPrefix=\"/\">\n        </data>\n      </intent-filter>\n    </activity>\n    <service\n      android:label=\"FIDO Security Key\"\n      android:icon=\"@0x7f08056a\"\n      android:name=\"com.huawei.hms.runtimekit.stubexplicit.FidoStubTileService\"\n      android:permission=\"android.permission.BIND_QUICK_SETTINGS_TILE\"\n      android:process=\"com.huawei.hwid.container1\">\n      <intent-filter>\n        <action\n          android:name=\"android.service.quicksettings.action.QS_TILE\">\n        </action>\n      </intent-filter>\n    </service>\n    <provider\n      android:name=\"com.huawei.hms.fwkit.kpms.core.provider.KpmsInstallPathProvider\"\n      android:exported=\"false\"\n      android:authorities=\"com.huawei.hms.fwkit.KitUpgradePath\"\n      android:grantUriPermissions=\"true\">\n      <meta-data\n        android:name=\"android.support.FILE_PROVIDER_PATHS\"\n        android:resource=\"@0x7f15000e\">\n      </meta-data>\n    </provider>\n    <service\n      android:name=\"com.huawei.hms.location.geocoder.HwGeoCoderService\"\n      android:permission=\"huawei.android.permission.HW_SIGNATURE_OR_SYSTEM\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.core\">\n      <intent-filter>\n        <action\n          android:name=\"com.android.location.service.GeocodeProvider\">\n        </action>\n      </intent-filter>\n      <meta-data\n        android:name=\"serviceVersion\"\n        android:value=\"0\">\n      </meta-data>\n      <meta-data\n        android:name=\"serviceIsMultiuser\"\n        android:value=\"true\">\n      </meta-data>\n    </service>\n    <service\n      android:name=\"com.huawei.hms.location.service.HwLocationService\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\">\n      <intent-filter>\n        <action\n          android:name=\"com.huawei.hms.location.service.locationservice\">\n        </action>\n      </intent-filter>\n    </service>\n    <service\n      android:name=\"com.huawei.locatorservice.ability.nlpservice.HwNLPService\"\n      android:permission=\"android.permission.WRITE_SECURE_SETTINGS\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.core\"\n      android:directBootAware=\"true\">\n      <intent-filter>\n        <action\n          android:name=\"com.android.location.service.v3.NetworkLocationProvider\">\n        </action>\n      </intent-filter>\n      <meta-data\n        android:name=\"serviceVersion\"\n        android:value=\"1\">\n      </meta-data>\n      <meta-data\n        android:name=\"serviceIsMultiuser\"\n        android:value=\"false\">\n      </meta-data>\n    </service>\n    <uses-library\n      android:name=\"org.apache.http.legacy\"\n      android:required=\"false\">\n    </uses-library>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"@0x7f0b001e\"\n      android:name=\".ui.common.login.LoginActivity\"\n      android:exported=\"false\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:windowSoftInputMode=\"stateVisible\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"@0x7f0b069b\"\n      android:name=\"com.huawei.hwid20.login.loginbysms.LoginBySMSActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light.NoActionBar\"\n      android:name=\"com.huawei.hwid20.login.loginbysms.LoginOrRegisterBySmsActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:windowSoftInputMode=\"adjustResize|stateHidden\">\n      <intent-filter>\n        <action\n          android:name=\"com.huawei.hwid.LOGIN_OR_REGISTER_BY_SMS\">\n        </action>\n        <category\n          android:name=\"android.intent.category.DEFAULT\">\n        </category>\n      </intent-filter>\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui.NoActionBar\">\n      </meta-data>\n      <intent-filter>\n        <action\n          android:name=\"com.huawei.hwid.LOGIN_OR_REGISTER_BY_SMS\">\n        </action>\n        <category\n          android:name=\"android.intent.category.DEFAULT\">\n        </category>\n      </intent-filter>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light.NoActionBar\"\n      android:name=\"com.huawei.hwid20.login.loginbysms.OneKeyLoginOrRegisterActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:windowSoftInputMode=\"adjustResize|stateHidden\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui.NoActionBar\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light.NoActionBar\"\n      android:name=\"com.huawei.hwid20.login.onekeylogin.LoginLoadingActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:windowSoftInputMode=\"adjustResize|stateHidden\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui.NoActionBar\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light.NoActionBar\"\n      android:name=\"com.huawei.hwid20.login.fidologin.FidoLoginActivity\"\n      android:exported=\"false\"\n      android:launchMode=\"singleTop\"\n      android:screenOrientation=\"portrait\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:windowSoftInputMode=\"adjustResize|stateHidden\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui.NoActionBar\">\n      </meta-data>\n    </activity>\n    <meta-data\n      android:name=\"com.huawei.hwid.identity.name\"\n      android:resource=\"@0x7f0b0e9f\">\n    </meta-data>\n    <meta-data\n      android:name=\"com.huawei.hms.kit.api_level:innerIdentity\"\n      android:value=\"1\">\n    </meta-data>\n    <activity\n      android:theme=\"@0x7f13026a\"\n      android:name=\"com.huawei.hms.identity.address.detail.view.UserAddressDetailActivity\"\n      android:exported=\"false\"\n      android:screenOrientation=\"behind\"\n      android:configChanges=\"keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:windowSoftInputMode=\"adjustResize|stateHidden\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:name=\"com.huawei.hms.identity.address.invoke.InnerThirdInvokeActivity\"\n      android:exported=\"false\"\n      android:screenOrientation=\"behind\">\n      <intent-filter>\n        <action\n          android:name=\"com.huawei.identity.intent.action.addressmanagement\">\n        </action>\n        <category\n          android:name=\"android.intent.category.DEFAULT\">\n        </category>\n        <data\n          android:scheme=\"identity\"\n          android:host=\"com.huawei.hwid.external\">\n        </data>\n        <data\n          android:scheme=\"identity\"\n          android:host=\"com.huawei.hwid\">\n        </data>\n      </intent-filter>\n    </activity>\n    <activity\n      android:theme=\"@0x7f13026a\"\n      android:name=\"com.huawei.hms.identity.address.management.view.UserAddressManagementActivity\"\n      android:exported=\"true\"\n      android:screenOrientation=\"behind\"\n      android:configChanges=\"keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@0x7f13026a\"\n      android:name=\"com.huawei.hms.identity.address.choosecountry.view.ChooseCountryActivity\"\n      android:exported=\"false\"\n      android:screenOrientation=\"behind\"\n      android:configChanges=\"keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:windowSoftInputMode=\"adjustResize|stateHidden\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@0x7f13026a\"\n      android:name=\"com.huawei.hms.identity.address.choosearea.view.ChooseAreaActivity\"\n      android:exported=\"false\"\n      android:screenOrientation=\"behind\"\n      android:configChanges=\"keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:windowSoftInputMode=\"adjustResize|stateHidden\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <service\n      android:name=\"com.huawei.hms.identity.service.IdentityRequestService\"\n      android:exported=\"false\">\n    </service>\n    <meta-data\n      android:name=\"hms_module:litedrm\"\n      android:value=\"com.huawei.hms.litedrm.MainEntry:1\">\n    </meta-data>\n    <meta-data\n      android:name=\"com.huawei.hms.kit.api_level:litedrm\"\n      android:value=\"1\">\n    </meta-data>\n    <activity\n      android:theme=\"@0x7f1301b0\"\n      android:name=\"com.huawei.hms.mlplugin.card.bcr.CaptureActivity\"\n      android:resizeableActivity=\"false\">\n    </activity>\n    <meta-data\n      android:name=\"com.huawei.hms.client.service.name:ml-computer-card-bcr-plugin\"\n      android:value=\"ml-computer-card-bcr-plugin:2.0.1.304\">\n    </meta-data>\n    <meta-data\n      android:name=\"com.huawei.hms.min_api_level:ml-computer-vision:huawei_module_mlkit_bcr\"\n      android:value=\"3\">\n    </meta-data>\n    <meta-data\n      android:name=\"com.huawei.hms.client.service.name:ml-computer-dynamic\"\n      android:value=\"ml-computer-dynamic:2.0.1.300\">\n    </meta-data>\n    <meta-data\n      android:name=\"availableLoaded\"\n      android:value=\"yes\">\n    </meta-data>\n    <provider\n      android:name=\"com.huawei.hms.update.provider.UpdateProvider\"\n      android:exported=\"false\"\n      android:authorities=\"com.huawei.hwid.hms.update.provider\"\n      android:grantUriPermissions=\"true\">\n    </provider>\n    <meta-data\n      android:name=\"com.huawei.hms.client.service.name:ml-computer-camera-inner\"\n      android:value=\"ml-computer-camera-inner:2.0.1.300\">\n    </meta-data>\n    <meta-data\n      android:name=\"com.huawei.hms.client.service.name:ml-computer-ha-inner\"\n      android:value=\"ml-computer-ha-inner:2.0.1.300\">\n    </meta-data>\n    <activity\n      android:theme=\"@0x7f1301bb\"\n      android:name=\"com.huawei.hms.hwid.api.impl.PermissionRequestActivity\"\n      android:exported=\"true\"\n      android:excludeFromRecents=\"true\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:hardwareAccelerated=\"true\">\n      <intent-filter>\n        <action\n          android:name=\"com.huawei.hwid.ACTION_SMS_PERMISSION\">\n        </action>\n        <category\n          android:name=\"android.intent.category.DEFAULT\">\n        </category>\n      </intent-filter>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"@0x7f0b050c\"\n      android:name=\"com.huawei.hms.hwid.api.impl.WebAuthorizationActivity\"\n      android:exported=\"true\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <intent-filter>\n        <action\n          android:name=\"com.huawei.hwid.ACTION.WEBAUTH\">\n        </action>\n        <category\n          android:name=\"android.intent.category.DEFAULT\">\n        </category>\n      </intent-filter>\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bb\"\n      android:name=\"com.huawei.hms.hwid.api.impl.ForegroundSignInActivity\"\n      android:exported=\"true\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <intent-filter>\n        <action\n          android:name=\"com.huawei.hwid.ACTION.ForegroundSignIn\">\n        </action>\n        <category\n          android:name=\"android.intent.category.DEFAULT\">\n        </category>\n      </intent-filter>\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui.Translucent\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bb\"\n      android:name=\".ui.SignInGoogleActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"layoutDirection|locale|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:windowSoftInputMode=\"stateHidden\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bb\"\n      android:name=\".ui.BrowserSignInGoogleActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"layoutDirection|locale|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:windowSoftInputMode=\"stateHidden\">\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"@0x7f0b01fc\"\n      android:name=\"com.huawei.hwid20.login.loginbyqr.LoginByQRActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"@0x7f0b09c7\"\n      android:name=\"com.huawei.hwid20.riskrecheck.RiskReckeckUserPersonalIdActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"keyboardHidden|layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:windowSoftInputMode=\"stateVisible\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"@0x7f0b09ca\"\n      android:name=\"com.huawei.hwid20.riskrecheck.RiskReckeckEnsurePhoneNumberActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"keyboardHidden|layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:windowSoftInputMode=\"stateVisible\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:name=\"com.huawei.hwid20.riskrecheck.RiskReckeckEnsureEmailAddressActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"keyboardHidden|layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:windowSoftInputMode=\"stateVisible\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"@0x7f0b0683\"\n      android:name=\"com.huawei.hwid20.riskrecheck.RiskReckeckOtherWaysActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"keyboardHidden|layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"@0x7f0b07cf\"\n      android:name=\"com.huawei.hwid20.riskrecheck.RiskReckeckEmergencyContactActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"keyboardHidden|layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:windowSoftInputMode=\"stateVisible\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:name=\"com.huawei.hwid20.agreement.AgreementForAdvertActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui.NoActionBar\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"@0x7f0b0011\"\n      android:name=\".europe.common.EuropeManageAgreementActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <intent-filter>\n        <action\n          android:name=\"com.huawei.hwid.EUROPE_AGREEMNET_MANAGER\">\n        </action>\n        <category\n          android:name=\"android.intent.category.DEFAULT\">\n        </category>\n      </intent-filter>\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bb\"\n      android:name=\"com.huawei.hwid20.agreement.AgreementForAspiegelNoticeActivity\"\n      android:exported=\"false\"\n      android:excludeFromRecents=\"true\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <intent-filter>\n        <action\n          android:name=\"com.huawei.hwid.EUROPE_AGREEMNET_REGISTER\">\n        </action>\n        <category\n          android:name=\"android.intent.category.DEFAULT\">\n        </category>\n      </intent-filter>\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui.Translucent\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bb\"\n      android:name=\"com.huawei.hwid20.agreement.AgreementForAspiegelStepNoticeActivity\"\n      android:exported=\"false\"\n      android:excludeFromRecents=\"true\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <intent-filter>\n        <action\n          android:name=\"com.huawei.hwid.EUROPE_AGREEMNET_REGISTER_NOTICE_STEP_TWO\">\n        </action>\n        <category\n          android:name=\"android.intent.category.DEFAULT\">\n        </category>\n      </intent-filter>\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui.Translucent\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"@0x7f0b0011\"\n      android:name=\"com.huawei.hwid20.agreement.AgreementForAspiegelActvity\"\n      android:exported=\"false\"\n      android:configChanges=\"layoutDirection|locale|mcc|mnc|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light.NoActionBar\"\n      android:label=\"@0x7f0b0011\"\n      android:name=\"com.huawei.hwid20.agreement.AgreementForAspiegelStep2Activity\"\n      android:exported=\"false\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <intent-filter>\n        <action\n          android:name=\"com.huawei.hwid.EUROPE_AGREEMNET_REGISTER_STEP_TWO\">\n        </action>\n        <category\n          android:name=\"android.intent.category.DEFAULT\">\n        </category>\n      </intent-filter>\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui.NoActionBar\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"@0x7f0b0011\"\n      android:name=\"com.huawei.hwid20.agreement.ShowAgreementActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <intent-filter>\n        <category\n          android:name=\"android.intent.category.DEFAULT\">\n        </category>\n      </intent-filter>\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"@0x7f0b09aa\"\n      android:name=\"com.huawei.hwid20.agreement.ShowInternalAgreementActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <intent-filter>\n        <category\n          android:name=\"android.intent.category.DEFAULT\">\n        </category>\n      </intent-filter>\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Holo.Light\"\n      android:label=\"\"\n      android:name=\".ui.common.login.PrivacyPolicyActivity\"\n      android:permission=\"com.huawei.dataprivacycenter.permission.LAUNCH_APP_PRIVACY_STATEMENT\"\n      android:exported=\"true\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:windowSoftInputMode=\"stateAlwaysHidden\"\n      android:logo=\"@0x7f0803de\">\n      <intent-filter>\n        <action\n          android:name=\"com.huawei.hwid.ACTION.HWID_PRIVACY_STATEMENT\">\n        </action>\n        <category\n          android:name=\"android.intent.category.DEFAULT\">\n        </category>\n      </intent-filter>\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301bb\"\n      android:name=\"com.huawei.hwid20.agreement.PermissionDescriptionActivity\"\n      android:exported=\"false\"\n      android:excludeFromRecents=\"true\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui.Translucent\">\n      </meta-data>\n    </activity>\n    <meta-data\n      android:name=\"com.huawei.hms.kit.api_level:walletkit\"\n      android:value=\"1\">\n    </meta-data>\n    <meta-data\n      android:name=\"com.huawei.hms.kit.type:walletkit\"\n      android:value=\"app\">\n    </meta-data>\n    <activity\n      android:name=\"com.huawei.hms.walletkit.ui.LicenseActivity\"\n      android:exported=\"false\"\n      android:screenOrientation=\"behind\"\n      android:configChanges=\"keyboard|keyboardHidden|orientation|screenSize\">\n    </activity>\n    <activity\n      android:name=\"com.huawei.hms.walletkit.ui.WalletKitAdapterAddcardActivity\"\n      android:screenOrientation=\"portrait\"\n      android:configChanges=\"keyboardHidden|layoutDirection|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hms_verify_fingerprint\"\n        android:value=\"false\">\n      </meta-data>\n      <intent-filter>\n        <action\n          android:name=\"com.huawei.hms.walletkit.action.ADD_ONLINE_PASS\">\n        </action>\n        <category\n          android:name=\"android.intent.category.DEFAULT\">\n        </category>\n      </intent-filter>\n      <intent-filter>\n        <action\n          android:name=\"android.intent.action.VIEW\">\n        </action>\n        <category\n          android:name=\"android.intent.category.DEFAULT\">\n        </category>\n        <category\n          android:name=\"android.intent.category.BROWSABLE\">\n        </category>\n        <data\n          android:scheme=\"hms\"\n          android:host=\"www.huawei.com\"\n          android:path=\"/payapp\">\n        </data>\n        <data\n          android:scheme=\"hms\"\n          android:host=\"www.huawei.com\"\n          android:pathPrefix=\"/payapp/\">\n        </data>\n      </intent-filter>\n    </activity>\n    <activity\n      android:name=\"com.huawei.hms.walletkit.ui.PrivacyPolicyActivity\"\n      android:exported=\"false\"\n      android:launchMode=\"singleInstance\"\n      android:screenOrientation=\"portrait\"\n      android:configChanges=\"layoutDirection|screenLayout|screenSize|smallestScreenSize\"\n      android:windowSoftInputMode=\"stateAlwaysHidden\">\n    </activity>\n    <service\n      android:name=\"com.huawei.hms.walletkit.service.WalletAdapterService\"\n      android:exported=\"false\">\n    </service>\n    <meta-data\n      android:name=\"com.huawei.hms.kit.api_level:opendevice\"\n      android:value=\"1\">\n    </meta-data>\n    <service\n      android:name=\"com.huawei.hms.kit.service.KitService\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.core\">\n      <intent-filter>\n        <action\n          android:name=\"com.huawei.hms.kit.kitservice\">\n        </action>\n      </intent-filter>\n    </service>\n    <meta-data\n      android:name=\"com.huawei.settings.notdisableable\"\n      android:value=\"1\">\n    </meta-data>\n    <meta-data\n      android:name=\"android.max_aspect\"\n      android:value=\"2.34\">\n    </meta-data>\n    <meta-data\n      android:name=\"CHANNEL\"\n      android:value=\"pre-install\">\n    </meta-data>\n    <meta-data\n      android:name=\"hsf-signature\"\n      android:value=\"CqbS/W+Y8Y/PQ0AMflWjTry1wSpt4AxDL+CmWai7c65YkzbuJFntmvD1irXqgm+jt/1nJ+vNE01fK64xJS0a3zn4TXBBvbjGM6y2Qq6ZvYRCnHMvsq9OeY7Bb6XKhFRDUlBnPlEeqdWPmVZqDZMeGYHygUd28x3mIZiVxvcNwqHdOGmqyp1gK3Popju0NFChaAK3IiLy3vR+QSLJw7yFzgUoSNR/vAUo1qFhRnMlxKzts7gQwXrYLnzpIC6/GkeG6sbUMAJxVo1y1KFgk007b2k5Y79eEDwv8tvEDtXQjweP0+JhZ5qyUYP3Xco+a0x+JACsZmbFw74I3Gc2dFWYWQ==\">\n    </meta-data>\n    <meta-data\n      android:name=\"statement_hms_cn_version\"\n      android:value=\"1.0\">\n    </meta-data>\n    <meta-data\n      android:name=\"statement_hms_cn\"\n      android:resource=\"@0x7f15001a\">\n    </meta-data>\n    <meta-data\n      android:name=\"statement_hms_cn_doublelink\"\n      android:resource=\"@0x7f15001b\">\n    </meta-data>\n    <meta-data\n      android:name=\"watch_statement_hms\"\n      android:value=\"@0x7f0b0002\">\n    </meta-data>\n    <meta-data\n      android:name=\"watch_statement_hms_version\"\n      android:value=\"1.0\">\n    </meta-data>\n    <meta-data\n      android:name=\"tv_oobe_privacy_base_registration\"\n      android:resource=\"@0x7f15001c\">\n    </meta-data>\n    <meta-data\n      android:name=\"data_privacy_center_service\"\n      android:resource=\"@0x7f150008\">\n    </meta-data>\n    <meta-data\n      android:name=\"data_privacy_support_range\"\n      android:value=\"cn\">\n    </meta-data>\n    <meta-data\n      android:name=\"com.huawei.hms.kit.api_level:hmscore\"\n      android:value=\"5\">\n    </meta-data>\n    <activity\n      android:theme=\"@style/Theme.Translucent.NoTitleBar\"\n      android:name=\"com.huawei.hms.core.activity.JumpActivity\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.core\"\n      android:excludeFromRecents=\"true\"\n      android:configChanges=\"fontScale|layoutDirection|locale|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:hardwareAccelerated=\"true\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui.Translucent.NoTitleBar\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Translucent.NoTitleBar\"\n      android:name=\"com.huawei.hms.core.activity.UiJumpActivity\"\n      android:exported=\"true\"\n      android:excludeFromRecents=\"true\"\n      android:screenOrientation=\"behind\"\n      android:configChanges=\"fontScale|layoutDirection|locale|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:hardwareAccelerated=\"true\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui.Translucent.NoTitleBar\">\n      </meta-data>\n    </activity>\n    <service\n      android:name=\"com.huawei.hms.core.service.HMSCoreService\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.core\"\n      android:directBootAware=\"true\">\n      <meta-data\n        android:name=\"hms_app_signer\"\n        android:value=\"pMZMvNV2rS2BOdT8BJuoiCB4X63E2gVjyB/5WUigtbgPqECNqfLzQR5P95Wb7PQtOOStkR0fzhqjotKX9TFCXAY3glIRVC7JArUsmFIhT4EO87cRZc29RAKAzSDWYbRzDgJCP7cMx4rS+FUWWxN1CnibzQ2FGwOgdJkZHONTf8XAyFbhTsZsNmdDpT42iA9e9C4k9oYata8tBGf/urD6EfLdFdWfM3h5P7VyCkDj9Ej2FTerYgbUfkHOqgtbPrHo6lCVtUTQR8GCoIPCOabiUx2a66wUhHqXbt3XVW7bbxQvh5gQ0LVMuOmeEjaZr4pMsEkn/0NTLYSCwZZ/MEaRfg==\">\n      </meta-data>\n      <meta-data\n        android:name=\"hms_app_cert_chain\"\n        android:value=\"['MIIF/TCCA+WgAwIBAgIIIQV1CU5bvEMwDQYJKoZIhvcNAQELBQAwUDELMAkGA1UEBhMCQ04xDzANBgNVBAoMBkh1YXdlaTETMBEGA1UECwwKSHVhd2VpIENCRzEbMBkGA1UEAwwSSHVhd2VpIENCRyBSb290IENBMB4XDTE4MDEzMDA3NDI1OVoXDTM4MDEyNTA3NDI1OVowYzELMAkGA1UEBhMCQ04xDzANBgNVBAoMBkh1YXdlaTETMBEGA1UECwwKSHVhd2VpIENCRzEuMCwGA1UEAwwlSHVhd2VpIENCRyBBcHBsaWNhdGlvbiBJbnRlZ3JhdGlvbiBDQTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMCCUUvjL5oXThUxFklLXbLNkfHtjs8rlOT3hRE3VmicI7LFJXGMCByB7ORucGDStwIMH1ac1pnBsV2dabuQj0WiXbYtRD44IxCN879RJBFry9AV7PypYrxucFqgeqt19PpSpSMa4ROBxAyVRq9F6m6HWlBTtlLXvH9yAbPOp+rvaEd5LD7MNsVFOXeMVBoRuhoxohrAIB3pzwAjX8fWSoe8Vrz6F3LAIVHE1CzEn0sFUtKIuWVm1l1cGNlsMeUwSMwj8PBtTNb9IQaNTsA2qguQgkdPaDda0ENg/FIZ2zHzV9l4k7SrpFvqSde0sEDR9mSfIeJ3x5pATJp25X5K1+ZoFZRa7sQHMWA6HOYwfqBXxQmK0pETzjB5zVfXQLnDP0TqK1xcS8X6jJuvkm5F691nu7ypfmZx0RNPTnFZiNOz+Qdzklm1BJHlmNIVbFke6qHUHOBX57EAsu2HumkWWyqQ0MaXcpuuLMdU3OZ6vtoSsYevNhN4Ypm2v0Zr3FCSjgnWAwU02MNROMCBCRazt4txJ1tEYnmu0Bd5qLJXFWc1zweP52XS6BqeFRYb50M5O/AQI5sXsO10fWN05jezS7jDzqjar7PYNGHuuY6cO5QVo8/t9t/sZ8vHN++Et2BzMKm5n11YM6tPJZKKpL0F+ZBa3qgEMFoNxwckvnmT79D5AgMBAAGjgccwgcQwHwYDVR0jBBgwFoAUqsTTeUfobiNr7/CpbCJzPXoZaaEwHQYDVR0OBBYEFOHI/wFzBqHgXhMOWqee63/XnhuIMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/BAQDAgEGMGEGA1UdHwRaMFgwVqBUoFKGUGh0dHA6Ly9jcGtpLWNhd2ViLmh1YXdlaS5jb20vY3BraS9zZXJ2bGV0L2NybEZpbGVEb3duLmNybD9jZXJ0eXBlPTEmL3Jvb3RjcmwuY3JsMA0GCSqGSIb3DQEBCwUAA4ICAQDPxMXcr1lLbdPHfoncb/QzQpRCQx/EYd7c/7VUKaTXV8k4JQ2Z0hHNPPHyjU8MkPg764d+UCcOMkI+PB+zXYKeumQsWks2YRHQQa93bLAONPo0Z8b/r9fjrklCExJT3kA2qThRA4BEfl4WydFS4J2kpdTFxtSbMI77DEllyF8L1Nn5mqKCXgZGA3g6vgkxBM/gLaApV9/Mg2QEhTV9WA78+fCbgGVLCYELrvuc+MKljbBnOIoj49tz8VUbjoFJD6AcCBe00qbecDjvx31ERskziWMs+PZ4oNp2zMdsa3BrE/vANlEbtTigmTHMora36tEL1JX1cKu+So7I6fykmsPZA3keDHp8treLb4KcbDpLcqAu4V8vMqJ8tFU6ilh65HOATWz+g/jEpMPZuiN+qjSYnDFxzts9mWERsSG003S6yg9ZnehcA3iRVNPZZ8hSZZH0YKNqxpda/TR6P5qXiHRA6A+MdoBOE4HmuUy3QFV7zYl5snR6SmrDfVmtsyz8aMqifx4gsVV2M5/owv8H3bUdOd5RbkKhzOS2Pmep0bbwWRFUrWuQ+5ci2LLkZyIt9ffNR8W9gbmZOZZTrwSFRIT1Q433NOzCQNDjKwnekGAx8o746tqqZxGCXgy2MaIIqvajhNw9Dr3NBQ8ziWyqaQBk2RrCWh6Q++Sd0b5L3RwHrQ==','MIIFAzCCAuugAwIBAgISIBkIAhAENHCLeunQ91WA4AERMA0GCSqGSIb3DQEBCwUAMGMxCzAJBgNVBAYTAkNOMQ8wDQYDVQQKDAZIdWF3ZWkxEzARBgNVBAsMCkh1YXdlaSBDQkcxLjAsBgNVBAMMJUh1YXdlaSBDQkcgQXBwbGljYXRpb24gSW50ZWdyYXRpb24gQ0EwHhcNMTkwODAyMDIwNDM0WhcNMjkwNzMwMDIwNDM0WjBiMQswCQYDVQQGEwJDTjEPMA0GA1UECgwGSHVhd2VpMSkwJwYDVQQLDCBIdWF3ZWkgQ0JHIENsb3VkIFNlY3VyaXR5IFNpZ25lcjEXMBUGA1UEAwwOSHVhd2VpIENCRyBITVMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDDwEsRSSiAxEq8Vq0ufN1cqh12WTFs4jEavRayu5Q4rh8LVXaPgqnyfh21KHmUDq7B18mLxCYql/4+5PK/6DOE+fFBGS9XfJVGN7d+P3fgMcY9uzk97/49Nyc6MrBqPZEamdEL9JhF/NuXSE3vWW9RmuQiIooDzbuEyq74AnnkJSWTpzjbMNYewAezW9GOiACat/rc3JGbdzzCCpJRBaxe8TlL/bTRiS6vAIXZ4sSv2OQakK+HIep+0BvjUDtbejQjoTvtFgIcsImc5HbFVlD2LBFiy6uNSIpb/mVdtzseA+KyWng595j2WDYRFx6AtN/cwcOp/VJ0LVLtWb4WBoVNAgMBAAGjgbEwga4wHwYDVR0jBBgwFoAU4cj/AXMGoeBeEw5ap57rf9eeG4gwHQYDVR0OBBYEFF85R/XM54pV9banUoj0cogDVjmxMAsGA1UdDwQEAwIDqDBABgNVHR8EOTA3MDWgM6Axhi9odHRwOi8vY3JsLmNsb3VkLmh1YXdlaS5jb20vSHVhd2VpQ0JHSEFJY3JsLmNybDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDQYJKoZIhvcNAQELBQADggIBAE+xtDWQOKmIMRU1YmDqkeuWeXAuNdq64g5m2SFy/rG1kyksyIf89TOnWOBLiKu14x+OIyNdWPmYpjoe/hX4tREsqlbupZm0S/CDa6FJXJ7IyGSSZMKsnZAoCzFItN8UR2+gUuQ72cKoomMn2cNJz9ehHaEW7jTuKFg5J4ibV32r23lpDbomkAx7jMG5kknmnyAVOx5JzB0jQipzqssZvd6gj2dxhkiQmS6VpAwt8YCLNmekCg6r7iq3qS8T/v1FDOVtAu1Iv6xSS91q65r4sG5xmUo6qMr0FZedRS5mL+Rbo+CyRZEeX3BKimrSUgAkrwsQXcZlntPEpyZR+7Ihx3vqv9iijea+3JYN5nFY1pb8zkNMRqiCAZ3wmYWHFg63G77DGEoXoNfKq7QeRtGM4C9DBfzWqJjMIYCUMgvCjjHCufaQnO3hr8/fZ5uVEBsjNsu/UVlZfFvbU6+5vsHtFtJryDCeVsm1cgBZLon6COS45urZEw008+gFarD1+xJ01E4HouSoDYdN9SKCIsco5IwrNuuQOfi6VG2q7rYWFq/a/zi9SUtRFoiHymuymUnE4Z1mjYtG6wjZjfxtpqnYCaRbC4MibjkKKVGRGMk/7m4gIs6Nm1zQg/iGcW1TC7VO6CNb5GME9TEIGwxj3jWUqJ0aRwUx5rIBgqzJ4JAhu+0J']\">\n      </meta-data>\n      <intent-filter>\n        <action\n          android:name=\"com.huawei.hms.core.aidlservice\">\n        </action>\n        <action\n          android:name=\"com.huawei.hms.core.locationaidlservice\">\n        </action>\n      </intent-filter>\n    </service>\n    <service\n      android:name=\"com.huawei.hms.core.service.HMSInnerService\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\"\n      android:directBootAware=\"true\">\n      <intent-filter>\n        <action\n          android:name=\"com.huawei.hms.core.innerservice\">\n        </action>\n      </intent-filter>\n    </service>\n    <receiver\n      android:name=\"com.huawei.hms.core.HMSOnBootBroadcastReceiver\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.persistent\">\n      <intent-filter>\n        <action\n          android:name=\"android.intent.action.BOOT_COMPLETED\">\n        </action>\n        <category\n          android:name=\"android.intent.category.DEFAULT\">\n        </category>\n      </intent-filter>\n    </receiver>\n    <provider\n      android:name=\"com.huawei.hms.log.LogFileProvider\"\n      android:exported=\"false\"\n      android:authorities=\"com.huawei.hms.log.LogFileProvider\"\n      android:grantUriPermissions=\"true\">\n      <meta-data\n        android:name=\"android.support.FILE_PROVIDER_PATHS\"\n        android:resource=\"@0x7f15000f\">\n      </meta-data>\n    </provider>\n    <provider\n      android:name=\"com.huawei.hms.privacy.PrivacyProvider\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.oobe\"\n      android:authorities=\"com.huawei.hms.statement\"\n      android:directBootAware=\"true\">\n    </provider>\n    <provider\n      android:name=\"com.huawei.hms.privacy.StatisticsAndAnalyticsProvider\"\n      android:permission=\"android.permission.READ_SEARCH_INDEXABLES\"\n      android:exported=\"true\"\n      android:authorities=\"com.huawei.hms.privacy.StatisticsAndAnalyticsProvider\">\n      <intent-filter>\n        <action\n          android:name=\"android.content.action.SEARCH_SUPPORTED_PROVIDER\">\n        </action>\n      </intent-filter>\n    </provider>\n    <provider\n      android:name=\"com.huawei.hms.dynamic.module.manager.install.ApkInstallProvider\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\"\n      android:authorities=\"com.huawei.hms.install.apkInstallProvider\"\n      android:grantUriPermissions=\"true\"\n      android:directBootAware=\"true\">\n      <meta-data\n        android:name=\"android.support.FILE_PROVIDER_PATHS\"\n        android:resource=\"@0x7f150002\">\n      </meta-data>\n    </provider>\n    <provider\n      android:name=\"com.huawei.hms.dynamic.module.manager.install.ModuleFileProvider\"\n      android:exported=\"false\"\n      android:process=\"com.huawei.hwid.core\"\n      android:authorities=\"com.huawei.hms.dynamic.moduleFileProvider\"\n      android:grantUriPermissions=\"true\"\n      android:directBootAware=\"true\">\n      <meta-data\n        android:name=\"android.support.FILE_PROVIDER_PATHS\"\n        android:resource=\"@0x7f150011\">\n      </meta-data>\n    </provider>\n    <provider\n      android:name=\"com.huawei.hms.dynamic.module.manager.query.ModuleQueryProvider\"\n      android:exported=\"true\"\n      android:process=\"com.huawei.hwid.core\"\n      android:authorities=\"com.huawei.hms\"\n      android:directBootAware=\"true\">\n    </provider>\n    <activity\n      android:theme=\"@style/Theme.WithActionBar\"\n      android:name=\"com.huawei.hms.dynamic.module.manager.update.activity.ManageSpaceActivity\"\n      android:exported=\"false\"\n      android:excludeFromRecents=\"true\"\n      android:configChanges=\"fontScale|layoutDirection|locale|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:hardwareAccelerated=\"true\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <meta-data\n      android:name=\"com.huawei.hms.client.service.name:ml-computer-card-bcr-model\"\n      android:value=\"ml-computer-card-bcr-model:2.0.1.304\">\n    </meta-data>\n    <meta-data\n      android:name=\"com.huawei.hms.client.service.name:dynamic-api\"\n      android:value=\"dynamic-api:1.0.13.303\">\n    </meta-data>\n    <meta-data\n      android:name=\"com.huawei.hms.min_api_level:dynamic-api:huawei_module_dynamicloader\"\n      android:value=\"2\">\n    </meta-data>\n    <provider\n      android:name=\"com.huawei.hms.mlsdk.common.provider.MLInitializerProvider\"\n      android:exported=\"false\"\n      android:authorities=\"com.huawei.hwid.MLInitializerProvider\">\n    </provider>\n    <provider\n      android:name=\"com.huawei.agconnect.core.provider.AGConnectInitializeProvider\"\n      android:exported=\"false\"\n      android:authorities=\"com.huawei.hwid.AGCInitializeProvider\">\n    </provider>\n    <service\n      android:name=\"com.huawei.agconnect.core.ServiceDiscovery\"\n      android:exported=\"false\">\n    </service>\n    <activity\n      android:theme=\"@0x7f130260\"\n      android:name=\"com.facebook.FacebookActivity\"\n      android:configChanges=\"keyboard|keyboardHidden|orientation|screenLayout|screenSize\">\n    </activity>\n    <activity\n      android:name=\"com.facebook.CustomTabMainActivity\">\n    </activity>\n    <activity\n      android:name=\"com.facebook.CustomTabActivity\">\n    </activity>\n    <meta-data\n      android:name=\"com.google.android.gms.version\"\n      android:value=\"@0x7f0c0023\">\n    </meta-data>\n    <activity\n      android:name=\"com.huawei.phoneservice.faq.FaqDispatchActivity\"\n      android:excludeFromRecents=\"true\"\n      android:configChanges=\"fontScale|layoutDirection|locale|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui.Translucent\">\n      </meta-data>\n    </activity>\n    <activity\n      android:name=\"com.huawei.phoneservice.faq.ui.FaqSecondaryListActivity\"\n      android:configChanges=\"keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\">\n    </activity>\n    <activity\n      android:name=\"com.huawei.phoneservice.faq.ui.FaqQuestionDetailActivity\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\">\n    </activity>\n    <activity\n      android:name=\"com.huawei.phoneservice.faq.ui.FaqCategoryActivity\"\n      android:configChanges=\"keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:windowSoftInputMode=\"adjustPan\">\n    </activity>\n    <activity\n      android:name=\"com.huawei.phoneservice.faq.ui.FaqOnlineActivity\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:windowSoftInputMode=\"adjustResize|stateAlwaysHidden\"\n      android:hardwareAccelerated=\"true\">\n    </activity>\n    <activity\n      android:name=\"com.huawei.phoneservice.faq.ui.IpccDetailActivity\"\n      android:configChanges=\"fontScale|layoutDirection|locale|orientation|screenLayout|screenSize|smallestScreenSize\">\n    </activity>\n    <activity\n      android:name=\"com.huawei.phoneservice.faq.ui.FaqTirdListActivity\"\n      android:configChanges=\"fontScale|layoutDirection|locale|orientation|screenLayout|screenSize|smallestScreenSize\">\n    </activity>\n    <activity\n      android:name=\"com.huawei.phoneservice.faq.ui.FaqSearchActivity\"\n      android:configChanges=\"fontScale|layoutDirection|locale|orientation|screenLayout|screenSize|smallestScreenSize\">\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Translucent.NoTitleBar.Fullscreen\"\n      android:name=\"com.huawei.phoneservice.faq.ui.FaqShareActivity\"\n      android:configChanges=\"screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui.Translucent\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301b0\"\n      android:name=\"com.huawei.phoneservice.feedback.photolibrary.ui.MatisseActivity\"\n      android:configChanges=\"keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301a4\"\n      android:name=\"com.huawei.phoneservice.feedback.photolibrary.internal.ui.AlbumPreviewActivity\"\n      android:configChanges=\"keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f1301a4\"\n      android:name=\"com.huawei.phoneservice.feedback.photolibrary.internal.ui.SelectedPreviewActivity\"\n      android:configChanges=\"keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\">\n    </activity>\n    <activity\n      android:name=\"com.huawei.phoneservice.feedback.ui.ProblemSuggestActivity\"\n      android:configChanges=\"keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:windowSoftInputMode=\"adjustResize|stateAlwaysHidden\">\n    </activity>\n    <activity\n      android:name=\"com.huawei.phoneservice.feedback.ui.ProductSuggestionActivity\"\n      android:configChanges=\"keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:windowSoftInputMode=\"adjustResize|stateAlwaysHidden\">\n    </activity>\n    <activity\n      android:name=\"com.huawei.phoneservice.feedback.ui.FeedListActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\">\n    </activity>\n    <activity\n      android:name=\"com.huawei.phoneservice.feedback.ui.FeedDetailsActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\">\n    </activity>\n    <activity\n      android:name=\"com.huawei.phoneservice.feedback.ui.FeedbackDisabledActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\">\n    </activity>\n    <activity\n      android:name=\"com.huawei.phoneservice.feedback.ui.FeedbackDispatchActivity\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"fontScale|layoutDirection|locale|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:windowSoftInputMode=\"adjustResize|stateAlwaysHidden\">\n    </activity>\n    <activity\n      android:name=\"com.huawei.phoneservice.feedback.ui.FeedUploadActivity\"\n      android:configChanges=\"keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:windowSoftInputMode=\"adjustResize|stateAlwaysHidden\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f13026a\"\n      android:name=\"com.huawei.pay.ui.setting.PaymentInfoActivity\"\n      android:exported=\"false\"\n      android:screenOrientation=\"behind\"\n      android:configChanges=\"keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@0x7f13026a\"\n      android:name=\"com.huawei.pay.ui.setting.PaymentSettingActivity\"\n      android:exported=\"false\"\n      android:screenOrientation=\"behind\"\n      android:configChanges=\"keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@0x7f13026a\"\n      android:name=\"com.huawei.pay.ui.setting.SelectDefaultPaymentActivity\"\n      android:exported=\"false\"\n      android:screenOrientation=\"behind\"\n      android:configChanges=\"keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@0x7f13026a\"\n      android:name=\"com.huawei.pay.ui.setting.security.SettingPayPasswordActivity\"\n      android:exported=\"false\"\n      android:screenOrientation=\"behind\"\n      android:configChanges=\"keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <intent-filter>\n        <action\n          android:name=\"com.huawei.pay.intent.action.Set_Pay_Password\">\n        </action>\n        <category\n          android:name=\"android.intent.category.DEFAULT\">\n        </category>\n      </intent-filter>\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@0x7f13026a\"\n      android:name=\"com.huawei.pay.ui.setting.PhoneBillSettingActivity\"\n      android:exported=\"false\"\n      android:screenOrientation=\"behind\"\n      android:configChanges=\"keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@0x7f13026a\"\n      android:name=\"com.huawei.pay.ui.setting.PayPalSettingActivity\"\n      android:exported=\"false\"\n      android:screenOrientation=\"behind\"\n      android:configChanges=\"keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@0x7f13026a\"\n      android:name=\"com.huawei.pay.ui.setting.WithholdListActivity\"\n      android:exported=\"false\"\n      android:screenOrientation=\"behind\"\n      android:configChanges=\"keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <intent-filter>\n        <action\n          android:name=\"com.huawei.pay.intent.action.With_Hold_List\">\n        </action>\n        <category\n          android:name=\"android.intent.category.DEFAULT\">\n        </category>\n      </intent-filter>\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@0x7f13026a\"\n      android:name=\"com.huawei.pay.ui.setting.WithholdDetailActivity\"\n      android:exported=\"false\"\n      android:screenOrientation=\"behind\"\n      android:configChanges=\"keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@0x7f13026a\"\n      android:name=\"com.huawei.pay.subscription.SubscribeListActivity\"\n      android:exported=\"false\"\n      android:screenOrientation=\"behind\"\n      android:configChanges=\"keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@0x7f13026a\"\n      android:name=\"com.huawei.pay.ui.setting.security.OldPassConfirmActivity\"\n      android:exported=\"false\"\n      android:screenOrientation=\"behind\"\n      android:configChanges=\"keyboard|keyboardHidden|layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@0x7f13026a\"\n      android:name=\"com.huawei.pay.ui.bill.MyBillActivity\"\n      android:exported=\"false\"\n      android:screenOrientation=\"behind\"\n      android:configChanges=\"keyboard|keyboardHidden|layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <intent-filter>\n        <action\n          android:name=\"com.huawei.pay.intent.action.Hcoin_Bill\">\n        </action>\n        <category\n          android:name=\"android.intent.category.DEFAULT\">\n        </category>\n      </intent-filter>\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@0x7f13026a\"\n      android:name=\"com.huawei.pay.ui.bill.WalletBillDetailActivity\"\n      android:exported=\"false\"\n      android:screenOrientation=\"behind\"\n      android:configChanges=\"keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@0x7f13026a\"\n      android:name=\"com.huawei.payinfo.ui.bankcard.cardlist.CardListActivity\"\n      android:exported=\"false\"\n      android:screenOrientation=\"behind\"\n      android:configChanges=\"keyboard|keyboardHidden|layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:windowSoftInputMode=\"adjustResize|stateHidden\"\n      android:uiOptions=\"splitActionBarWhenNarrow\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@0x7f13026a\"\n      android:name=\"com.huawei.payinfo.ui.bankcard.CardBindDetailActivity\"\n      android:exported=\"false\"\n      android:screenOrientation=\"behind\"\n      android:configChanges=\"keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:windowSoftInputMode=\"adjustResize|stateHidden\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@0x7f13026a\"\n      android:name=\"com.huawei.pay.ui.setting.ServiceLicenseActivity\"\n      android:exported=\"false\"\n      android:screenOrientation=\"behind\"\n      android:configChanges=\"keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@0x7f13026a\"\n      android:name=\"com.huawei.pay.ui.billaddr.billinvoice.BillInvoiceSettingActivity\"\n      android:exported=\"false\"\n      android:screenOrientation=\"behind\"\n      android:configChanges=\"keyboard|keyboardHidden|locale|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:windowSoftInputMode=\"adjustResize|stateHidden\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@0x7f13026a\"\n      android:name=\"com.huawei.pay.ui.billaddr.billinvoice.BillInvoiceSucceedActivity\"\n      android:exported=\"false\"\n      android:screenOrientation=\"behind\"\n      android:configChanges=\"keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@0x7f13026a\"\n      android:name=\"com.huawei.pay.ui.billaddr.billinvoice.BillAddrInfoActivity\"\n      android:exported=\"false\"\n      android:screenOrientation=\"behind\"\n      android:configChanges=\"keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:uiOptions=\"splitActionBarWhenNarrow\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@0x7f13026a\"\n      android:name=\"com.huawei.pay.ui.setting.SettingPayNoPassActivity\"\n      android:exported=\"false\"\n      android:screenOrientation=\"behind\"\n      android:configChanges=\"keyboard|keyboardHidden|layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <intent-filter>\n        <action\n          android:name=\"com.huawei.pay.intent.action.Pay_NoPass\">\n        </action>\n        <category\n          android:name=\"android.intent.category.DEFAULT\">\n        </category>\n      </intent-filter>\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@0x7f13026a\"\n      android:name=\"com.huawei.pay.ui.setting.security.GrantManagementActivity\"\n      android:exported=\"false\"\n      android:screenOrientation=\"behind\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@0x7f13026c\"\n      android:name=\"com.huawei.pay.ui.setting.security.GrantManagementVerifyPwdActivity\"\n      android:exported=\"false\"\n      android:screenOrientation=\"behind\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui.Translucent.NoTitleBar\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@0x7f13026a\"\n      android:name=\"com.huawei.pay.ui.family.FamilySharePaymentActivity\"\n      android:exported=\"false\"\n      android:screenOrientation=\"behind\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <intent-filter>\n        <action\n          android:name=\"com.huawei.pay.intent.action.FAMILY_SHARE\">\n        </action>\n        <category\n          android:name=\"android.intent.category.DEFAULT\">\n        </category>\n      </intent-filter>\n      <meta-data\n        android:name=\"android.notch_support\"\n        android:value=\"true\">\n      </meta-data>\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n      <meta-data\n        android:name=\"com.huawei.hwid.familyshare.menu\"\n        android:resource=\"@0x7f0b0084\">\n      </meta-data>\n      <meta-data\n        android:name=\"com.huawei.hwid.familyshare.menu.icon\"\n        android:resource=\"@0x7f08050e\">\n      </meta-data>\n      <meta-data\n        android:name=\"com.huawei.hwid.familyshare.menu.summary\"\n        android:resource=\"@0x7f0b0085\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@0x7f13026a\"\n      android:name=\"com.huawei.pay.ui.setting.PriorityPayMethodSettingActivity\"\n      android:exported=\"false\"\n      android:screenOrientation=\"behind\"\n      android:configChanges=\"keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <provider\n      android:name=\"com.huawei.pay.hcoin.IAPContentProvider\"\n      android:exported=\"false\"\n      android:authorities=\"com.huawei.pay.provider\">\n    </provider>\n    <activity\n      android:theme=\"@0x7f13026a\"\n      android:name=\"com.huawei.subscription.client.survey.SubscribeCancelSurveyActivity\"\n      android:exported=\"false\"\n      android:screenOrientation=\"behind\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@0x7f13026a\"\n      android:name=\"com.huawei.subscription.client.detail.pause.SelectPausePeriodActivity\"\n      android:exported=\"false\"\n      android:screenOrientation=\"behind\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@0x7f13026a\"\n      android:name=\"com.huawei.subscription.client.result.SubscribeResultActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"keyboard|keyboardHidden|layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@0x7f13026a\"\n      android:name=\"com.huawei.subscription.client.detail.SubscribeDetailActivity\"\n      android:exported=\"false\"\n      android:screenOrientation=\"behind\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@0x7f13026a\"\n      android:name=\"com.huawei.pay.ui.billaddr.view.ChooseProvinceActivity\"\n      android:exported=\"false\"\n      android:screenOrientation=\"behind\"\n      android:configChanges=\"keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:windowSoftInputMode=\"adjustResize|stateHidden\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@0x7f13026a\"\n      android:name=\"com.huawei.pay.ui.card.CardInfoActivity\"\n      android:exported=\"false\"\n      android:screenOrientation=\"behind\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:windowSoftInputMode=\"adjustResize|stateHidden\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@0x7f13026a\"\n      android:name=\"com.huawei.pay.ui.card.CardInfoGlobalActivity\"\n      android:exported=\"false\"\n      android:screenOrientation=\"behind\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:windowSoftInputMode=\"adjustResize|stateHidden\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@0x7f13026a\"\n      android:name=\"com.huawei.pay.ui.card.CardInputNumActivity\"\n      android:exported=\"false\"\n      android:screenOrientation=\"behind\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:windowSoftInputMode=\"adjustPan|stateHidden\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@0x7f13026b\"\n      android:name=\"com.huawei.pay.ui.card.BindCardEntryActivity\"\n      android:exported=\"false\"\n      android:screenOrientation=\"behind\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:windowSoftInputMode=\"adjustPan|stateHidden\">\n      <intent-filter>\n        <action\n          android:name=\"com.huawei.pay.intent.action.BIND_BANKCARD\">\n        </action>\n        <category\n          android:name=\"android.intent.category.DEFAULT\">\n        </category>\n      </intent-filter>\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/cp3_Theme_Emui.NoTitle_Dialog\">\n      </meta-data>\n    </activity>\n    <activity\n      android:name=\"com.huawei.pay.ui.card.BindCardResultActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:windowSoftInputMode=\"adjustResize|stateHidden\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@0x7f13026a\"\n      android:name=\"com.huawei.pay.ui.card.pay.PayCardInfoActivity\"\n      android:exported=\"false\"\n      android:screenOrientation=\"behind\"\n      android:configChanges=\"keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:windowSoftInputMode=\"adjustResize|stateHidden\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@0x7f13026a\"\n      android:name=\"com.huawei.pay.ui.card.pay.PayCardInputNumActivity\"\n      android:exported=\"false\"\n      android:screenOrientation=\"behind\"\n      android:configChanges=\"keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@0x7f13026a\"\n      android:name=\"com.huawei.password.view.SettingPayPassQuizActivity\"\n      android:exported=\"false\"\n      android:screenOrientation=\"behind\"\n      android:configChanges=\"keyboard|keyboardHidden|layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <intent-filter>\n        <action\n          android:name=\"com.huawei.pay.intent.action.SETTING_PAY_PASSQUIZ\">\n        </action>\n        <category\n          android:name=\"android.intent.category.DEFAULT\">\n        </category>\n      </intent-filter>\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@0x7f13026a\"\n      android:name=\"com.huawei.password.view.PayPassConfirmActivity\"\n      android:exported=\"false\"\n      android:screenOrientation=\"behind\"\n      android:configChanges=\"keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@0x7f13026a\"\n      android:name=\"com.huawei.password.view.ForgotPayPassActivity\"\n      android:exported=\"false\"\n      android:screenOrientation=\"behind\"\n      android:configChanges=\"keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@0x7f13026a\"\n      android:name=\"com.huawei.password.view.RetrievePassByQuizActivity\"\n      android:exported=\"false\"\n      android:screenOrientation=\"behind\"\n      android:configChanges=\"keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@0x7f13026a\"\n      android:name=\"com.huawei.password.view.VerifySmsActivity\"\n      android:exported=\"false\"\n      android:screenOrientation=\"behind\"\n      android:configChanges=\"keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@0x7f13026a\"\n      android:name=\"com.huawei.password.view.GuideSetPayPasswordActivity\"\n      android:exported=\"false\"\n      android:excludeFromRecents=\"true\"\n      android:screenOrientation=\"behind\"\n      android:configChanges=\"keyboard|locale|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n      <meta-data\n        android:name=\"android.notch_support\"\n        android:value=\"true\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@0x7f13026a\"\n      android:name=\"com.huawei.password.view.PayPasswordActivity\"\n      android:exported=\"false\"\n      android:screenOrientation=\"behind\"\n      android:configChanges=\"keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:name=\"com.huawei.pay.ui.card.camera.BankCardCaptureActivity\"\n      android:exported=\"false\"\n      android:screenOrientation=\"portrait\"\n      android:configChanges=\"keyboardHidden|orientation|screenSize\"\n      android:hardwareAccelerated=\"true\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui.NoActionBar\">\n      </meta-data>\n    </activity>\n    <service\n      android:name=\"com.huawei.subscription.api.request.SubscribeRequestService\"\n      android:exported=\"false\">\n    </service>\n    <activity\n      android:name=\"com.twitter.sdk.android.tweetcomposer.ComposerActivity\"\n      android:exported=\"false\"\n      android:windowSoftInputMode=\"adjustResize|stateVisible\">\n    </activity>\n    <service\n      android:name=\"com.twitter.sdk.android.tweetcomposer.TweetUploadService\"\n      android:enabled=\"true\"\n      android:exported=\"false\">\n    </service>\n    <activity\n      android:name=\"com.twitter.sdk.android.core.identity.OAuthActivity\"\n      android:exported=\"false\"\n      android:excludeFromRecents=\"true\"\n      android:configChanges=\"orientation|screenSize\">\n    </activity>\n    <activity\n      android:name=\"com.sina.weibo.sdk.web.WeiboSdkWebActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"keyboardHidden|orientation\"\n      android:windowSoftInputMode=\"adjustResize\">\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Translucent.NoTitleBar\"\n      android:name=\"com.sina.weibo.sdk.share.WbShareResultActivity\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"keyboardHidden|orientation|screenSize\">\n      <intent-filter>\n        <action\n          android:name=\"com.sina.weibo.sdk.action.ACTION_SDK_REQ_ACTIVITY\">\n        </action>\n        <category\n          android:name=\"android.intent.category.DEFAULT\">\n        </category>\n      </intent-filter>\n      <intent-filter>\n        <action\n          android:name=\"com.sina.weibo.sdk.action.ACTION_SDK_REQ_STORY\">\n        </action>\n        <category\n          android:name=\"android.intent.category.DEFAULT\">\n        </category>\n      </intent-filter>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Translucent.NoTitleBar\"\n      android:name=\"com.sina.weibo.sdk.share.WbShareTransActivity\"\n      android:launchMode=\"singleTop\"\n      android:configChanges=\"keyboardHidden|orientation|screenSize\">\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Translucent.NoTitleBar\"\n      android:name=\"com.sina.weibo.sdk.share.WbShareToStoryActivity\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"keyboardHidden|orientation|screenSize\">\n    </activity>\n    <meta-data\n      android:name=\"com.huawei.android.vr.application.mode\"\n      android:value=\"vr_only\">\n    </meta-data>\n    <activity\n      android:theme=\"@0x7f13026c\"\n      android:name=\"com.huawei.pay.ui.SchemeStartActivity\"\n      android:exported=\"true\"\n      android:taskAffinity=\"com.huawei.wallet.paytask\"\n      android:excludeFromRecents=\"true\"\n      android:screenOrientation=\"behind\"\n      android:configChanges=\"keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui.Translucent.NoTitleBar\">\n      </meta-data>\n      <intent-filter>\n        <action\n          android:name=\"android.intent.action.VIEW\">\n        </action>\n        <category\n          android:name=\"android.intent.category.BROWSABLE\">\n        </category>\n        <category\n          android:name=\"android.intent.category.DEFAULT\">\n        </category>\n        <data\n          android:scheme=\"hwid\"\n          android:host=\"platformapi\">\n        </data>\n      </intent-filter>\n    </activity>\n    <activity\n      android:theme=\"@0x7f13026a\"\n      android:name=\"com.huawei.pay.ui.recharge.BaseResultActivity\"\n      android:exported=\"false\"\n      android:screenOrientation=\"behind\"\n      android:configChanges=\"keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@0x7f13026a\"\n      android:name=\"com.huawei.pay.ui.PayActivity\"\n      android:exported=\"false\"\n      android:taskAffinity=\"com.huawei.android.hwpay.paytask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:windowSoftInputMode=\"adjustResize|stateHidden\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n      <meta-data\n        android:name=\"android.notch_support\"\n        android:value=\"true\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@0x7f13026a\"\n      android:name=\"com.huawei.pay.ui.onlinepayselectbank.BankSelectActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:windowSoftInputMode=\"adjustResize|stateHidden\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n      <meta-data\n        android:name=\"android.notch_support\"\n        android:value=\"true\">\n      </meta-data>\n    </activity>\n    <service\n      android:name=\"com.huawei.pay.service.PayRequestService\"\n      android:exported=\"false\">\n    </service>\n    <activity\n      android:theme=\"@0x7f13026a\"\n      android:name=\"com.huawei.pay.ui.WithholdActivity\"\n      android:exported=\"false\"\n      android:taskAffinity=\"com.huawei.android.hwpay.paytask\"\n      android:screenOrientation=\"behind\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:windowSoftInputMode=\"adjustResize|stateHidden\">\n      <meta-data\n        android:name=\"android.notch_support\"\n        android:value=\"true\">\n      </meta-data>\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@0x7f13026a\"\n      android:name=\"com.huawei.pay.ui.familyshare.FamilyShareSignActivity\"\n      android:exported=\"false\"\n      android:screenOrientation=\"behind\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:windowSoftInputMode=\"adjustResize|stateHidden\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n      <meta-data\n        android:name=\"android.notch_support\"\n        android:value=\"true\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@0x7f13026a\"\n      android:name=\"com.huawei.pay.ui.setting.ThirdInvokePrivacyStatementActivity\"\n      android:permission=\"com.huawei.dataprivacycenter.permission.LAUNCH_APP_PRIVACY_STATEMENT\"\n      android:exported=\"true\"\n      android:launchMode=\"singleInstance\"\n      android:screenOrientation=\"behind\"\n      android:configChanges=\"keyboard|keyboardHidden|layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n      <intent-filter>\n        <action\n          android:name=\"com.huawei.pay.ACTION.IAP_PRIVACY_STATEMENT\">\n        </action>\n        <category\n          android:name=\"android.intent.category.DEFAULT\">\n        </category>\n      </intent-filter>\n    </activity>\n    <activity\n      android:theme=\"@0x7f13026c\"\n      android:name=\"com.huawei.pay.ui.thirdpay.ThirdPayActivity\"\n      android:exported=\"false\"\n      android:taskAffinity=\"com.huawei.android.hwpay.paytask\"\n      android:excludeFromRecents=\"true\"\n      android:screenOrientation=\"behind\"\n      android:configChanges=\"keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui.Translucent.NoTitleBar\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@0x7f13026c\"\n      android:name=\"com.huawei.pay.ui.thirdpay.PaypalThirdPayActivity\"\n      android:exported=\"false\"\n      android:excludeFromRecents=\"true\"\n      android:launchMode=\"singleInstance\"\n      android:screenOrientation=\"behind\"\n      android:configChanges=\"keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui.Translucent.NoTitleBar\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@0x7f13026a\"\n      android:name=\"com.huawei.pay.ui.thirdpay.OverSeaThridPayActivity\"\n      android:exported=\"false\"\n      android:excludeFromRecents=\"true\"\n      android:screenOrientation=\"behind\"\n      android:configChanges=\"keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@0x7f13026c\"\n      android:name=\"com.huawei.pay.ui.alipay.AlipaySignResultActivity\"\n      android:exported=\"false\"\n      android:taskAffinity=\"com.huawei.android.hwpay.paytask\"\n      android:excludeFromRecents=\"true\"\n      android:screenOrientation=\"behind\"\n      android:configChanges=\"keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui.Translucent.NoTitleBar\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@0x7f13026c\"\n      android:name=\".wxapi.WXPayEntryActivity\"\n      android:exported=\"true\"\n      android:taskAffinity=\"com.huawei.android.hwpay.paytask\"\n      android:excludeFromRecents=\"true\"\n      android:screenOrientation=\"behind\"\n      android:configChanges=\"keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui.Translucent.NoTitleBar\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@0x7f13026a\"\n      android:name=\"com.huawei.pay.ui.recharge.PayResultActivity\"\n      android:exported=\"false\"\n      android:taskAffinity=\"com.huawei.android.hwpay.paytask\"\n      android:screenOrientation=\"behind\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:windowSoftInputMode=\"adjustPan|stateHidden\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n      <meta-data\n        android:name=\"android.notch_support\"\n        android:value=\"true\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@0x7f13026a\"\n      android:name=\"com.huawei.pay.ui.recharge.WithholdResultActivity\"\n      android:exported=\"false\"\n      android:taskAffinity=\"com.huawei.android.hwpay.paytask\"\n      android:screenOrientation=\"behind\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:windowSoftInputMode=\"adjustPan|stateHidden\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n      <meta-data\n        android:name=\"android.notch_support\"\n        android:value=\"true\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@0x7f13026a\"\n      android:name=\"com.huawei.pay.ui.thirdpay.ThirdPayWebViewActivity\"\n      android:exported=\"false\"\n      android:screenOrientation=\"behind\"\n      android:configChanges=\"keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:windowSoftInputMode=\"adjustResize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:name=\"com.huawei.pay.ui.familyshare.FamilyGrantPayActivity\"\n      android:exported=\"false\"\n      android:excludeFromRecents=\"true\"\n      android:configChanges=\"keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:windowSoftInputMode=\"adjustResize|stateHidden\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui.NoTitleBar\">\n      </meta-data>\n    </activity>\n    <activity\n      android:name=\"com.huawei.pay.ui.familyshare.FamilyGrantPayConfirmActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:windowSoftInputMode=\"adjustResize|stateHidden\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui.NoTitleBar\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@0x7f13026c\"\n      android:name=\"com.huawei.pay.subscription.VerifyPassTransitActivity\"\n      android:exported=\"false\"\n      android:screenOrientation=\"behind\"\n      android:configChanges=\"keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui.Translucent.NoTitleBar\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@0x7f13026c\"\n      android:name=\"com.huawei.pay.ui.web.threeds.ThreedsTransparentWebViewActivity\"\n      android:exported=\"false\"\n      android:screenOrientation=\"behind\"\n      android:configChanges=\"keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:windowSoftInputMode=\"adjustResize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui.Translucent.NoTitleBar\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@0x7f13026a\"\n      android:name=\"com.huawei.pay.ui.web.threeds.ThreedsNormalWebViewActivity\"\n      android:exported=\"false\"\n      android:screenOrientation=\"behind\"\n      android:configChanges=\"keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:windowSoftInputMode=\"adjustResize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@0x7f13026a\"\n      android:name=\"com.huawei.pay.subscription.ui.SubscribeActivity\"\n      android:exported=\"false\"\n      android:taskAffinity=\"com.huawei.android.hwpay.paytask\"\n      android:screenOrientation=\"behind\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:windowSoftInputMode=\"adjustResize|stateHidden\">\n      <meta-data\n        android:name=\"android.notch_support\"\n        android:value=\"true\">\n      </meta-data>\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@0x7f13026a\"\n      android:name=\"com.huawei.pay.payability.ui.AddPayMethodActivity\"\n      android:exported=\"false\"\n      android:screenOrientation=\"behind\"\n      android:configChanges=\"keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Translucent.NoTitleBar.Fullscreen\"\n      android:name=\"com.huawei.pay.ui.VRPayActivity\"\n      android:exported=\"false\"\n      android:screenOrientation=\"behind\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui.Translucent.NoTitleBar\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@0x7f13026a\"\n      android:name=\"com.huawei.pay.ui.web.agreement.AgreementWebViewActivity\"\n      android:exported=\"false\"\n      android:screenOrientation=\"behind\"\n      android:configChanges=\"keyboard|keyboardHidden|layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@0x7f13026a\"\n      android:name=\"com.huawei.pay.ui.web.normal.CommonWebViewActivity\"\n      android:exported=\"false\"\n      android:screenOrientation=\"behind\"\n      android:configChanges=\"keyboard|keyboardHidden|layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@0x7f13026a\"\n      android:name=\"com.huawei.pay.ui.web.bill.BillWebViewActivity\"\n      android:exported=\"false\"\n      android:screenOrientation=\"behind\"\n      android:configChanges=\"keyboard|keyboardHidden|layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:name=\"com.braintreepayments.api.BraintreeBrowserSwitchActivity\"\n      android:exported=\"true\"\n      android:launchMode=\"singleTask\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <intent-filter>\n        <action\n          android:name=\"android.intent.action.VIEW\">\n        </action>\n        <category\n          android:name=\"android.intent.category.DEFAULT\">\n        </category>\n        <category\n          android:name=\"android.intent.category.BROWSABLE\">\n        </category>\n        <data\n          android:scheme=\"com.huawei.hwid.braintree\">\n        </data>\n      </intent-filter>\n    </activity>\n    <uses-library\n      android:name=\"hwkeystore\"\n      android:required=\"false\">\n    </uses-library>\n    <uses-library\n      android:name=\"hccm\"\n      android:required=\"false\">\n    </uses-library>\n    <uses-library\n      android:name=\"hwpay_hccm_lib\"\n      android:required=\"false\">\n    </uses-library>\n    <activity\n      android:theme=\"@0x7f1302a3\"\n      android:name=\"com.huawei.updatesdk.service.otaupdate.AppUpdateActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"orientation|screenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui.Translucent.NoTitleBar\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@0x7f1302a3\"\n      android:name=\"com.huawei.updatesdk.support.pm.PackageInstallerActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"keyboardHidden|orientation|screenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui.Translucent\">\n      </meta-data>\n    </activity>\n    <meta-data\n      android:name=\"com.huawei.hms.client.service.name:fido-fido2\"\n      android:value=\"fido-fido2:5.0.1.200\">\n    </meta-data>\n    <meta-data\n      android:name=\"com.huawei.hms.min_api_level:fido-fido2:fido\"\n      android:value=\"400\">\n    </meta-data>\n    <provider\n      android:name=\"com.huawei.openalliance.ad.ppskit.provider.PPSInstallFileProvider\"\n      android:exported=\"false\"\n      android:authorities=\"com.huawei.hwid.hiad.fileprovider\"\n      android:grantUriPermissions=\"true\">\n    </provider>\n    <provider\n      android:name=\"com.huawei.openalliance.ad.ppskit.provider.InnerApiProvider\"\n      android:exported=\"false\"\n      android:authorities=\"com.huawei.hwid.pps.innerapiprovider\">\n    </provider>\n    <activity\n      android:theme=\"@style/Theme.Light.NoTitleBar\"\n      android:name=\"com.huawei.openalliance.ad.ppskit.activity.InstallActivity\"\n      android:exported=\"false\"\n      android:excludeFromRecents=\"true\"\n      android:configChanges=\"keyboard|keyboardHidden|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui.Light.NoTitleBar\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Light.NoTitleBar\"\n      android:name=\"com.huawei.openalliance.ad.ppskit.activity.HMSSDKInstallActivity\"\n      android:exported=\"false\"\n      android:excludeFromRecents=\"true\"\n      android:configChanges=\"keyboard|keyboardHidden|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui.Light.NoTitleBar\">\n      </meta-data>\n    </activity>\n    <activity\n      android:label=\" \"\n      android:name=\"com.huawei.openalliance.ad.ppskit.activity.InnerPPSActivity\"\n      android:exported=\"false\"\n      android:screenOrientation=\"portrait\"\n      android:configChanges=\"keyboard|keyboardHidden|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.NoTitleBar.Fullscreen\"\n      android:name=\"com.huawei.openalliance.ad.ppskit.activity.InnerPPSRewardActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"keyboard|keyboardHidden|mcc|mnc|navigation|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui.NoActionBar.Fullscreen\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.NoTitleBar.Fullscreen\"\n      android:name=\"com.huawei.openalliance.ad.ppskit.activity.InnerPPSInterstitialAdActivity\"\n      android:exported=\"false\"\n      android:screenOrientation=\"sensor\"\n      android:configChanges=\"keyboard|keyboardHidden|mcc|mnc|navigation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui.NoActionBar.Fullscreen\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Translucent.NoTitleBar\"\n      android:name=\"com.huawei.openalliance.ad.ppskit.activity.AgProtocolActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"orientation|screenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui.Translucent.NoTitleBar\">\n      </meta-data>\n    </activity>\n    <meta-data\n      android:name=\"com.huawei.android.hms:fastview-lite\"\n      android:value=\"fastview-lite:2.2.0.302\">\n    </meta-data>\n    <activity\n      android:theme=\"@0x7f130273\"\n      android:name=\"com.huawei.fastengine.fastview.download.download.DownloadActivity\"\n      android:configChanges=\"orientation|screenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui.Translucent.NoTitleBar\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@0x7f130273\"\n      android:name=\"com.huawei.fastengine.fastview.download.download.HiappDownloadActivity\"\n      android:configChanges=\"orientation|screenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui.Translucent.NoTitleBar\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Translucent\"\n      android:name=\"com.huawei.fastengine.fastview.download.install.PackageInstallerActivity\"\n      android:exported=\"false\"\n      android:excludeFromRecents=\"true\"\n      android:configChanges=\"keyboardHidden|orientation|screenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui.Translucent\">\n      </meta-data>\n    </activity>\n    <provider\n      android:name=\"com.huawei.fastengine.fastview.download.install.FastAppEngineFileProvider\"\n      android:exported=\"false\"\n      android:authorities=\"com.huawei.hwid.fastapp.engine.fileProvider\"\n      android:grantUriPermissions=\"true\">\n      <meta-data\n        android:name=\"android.support.FILE_PROVIDER_PATHS\"\n        android:resource=\"@0x7f15000a\">\n      </meta-data>\n    </provider>\n    <activity\n      android:theme=\"@style/Theme.Translucent.NoTitleBar\"\n      android:name=\"com.huawei.fastengine.fastview.startfastappengine.JumpActivity\"\n      android:exported=\"false\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui.Translucent.NoTitleBar\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@0x7f13026a\"\n      android:name=\"com.huawei.cardcoupon.counter.CouponActivity\"\n      android:exported=\"false\"\n      android:screenOrientation=\"behind\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|layoutDirection|locale|screenLayout|screenSize|smallestScreenSize\"\n      android:windowSoftInputMode=\"adjustResize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@0x7f13026a\"\n      android:name=\"com.huawei.cardcoupon.traffic.MyCardCouponActivity\"\n      android:exported=\"false\"\n      android:screenOrientation=\"behind\"\n      android:configChanges=\"keyboard|keyboardHidden|layoutDirection|locale|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@0x7f13026a\"\n      android:name=\"com.huawei.cardcoupon.traffic.SelectCardActivity\"\n      android:exported=\"false\"\n      android:screenOrientation=\"behind\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@0x7f13026a\"\n      android:name=\"com.huawei.cardcoupon.center.VoucherCenterActivity\"\n      android:exported=\"false\"\n      android:screenOrientation=\"behind\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@0x7f13026a\"\n      android:name=\"com.huawei.cardcoupon.voucher.MyVoucherActivity\"\n      android:exported=\"false\"\n      android:screenOrientation=\"behind\"\n      android:configChanges=\"fontScale|keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@0x7f13026c\"\n      android:name=\"com.huawei.hms.pay.invoke.InvokeTransparentActivity\"\n      android:exported=\"false\"\n      android:screenOrientation=\"behind\"\n      android:configChanges=\"keyboard|keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui.Translucent.NoTitleBar\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@0x7f13026a\"\n      android:name=\"com.huawei.hwpoints.recharge.HcoinRechargeActivity\"\n      android:exported=\"false\"\n      android:screenOrientation=\"behind\"\n      android:configChanges=\"keyboard|keyboardHidden|layoutDirection|locale|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:windowSoftInputMode=\"adjustPan|stateHidden\">\n      <intent-filter>\n        <action\n          android:name=\"com.huawei.pay.intent.action.Hcoin_Recharge\">\n        </action>\n        <category\n          android:name=\"android.intent.category.DEFAULT\">\n        </category>\n      </intent-filter>\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@0x7f13026a\"\n      android:name=\"com.huawei.hwpoints.center.HcoinContainerActivity\"\n      android:exported=\"false\"\n      android:screenOrientation=\"behind\"\n      android:configChanges=\"locale|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@0x7f13026a\"\n      android:name=\"com.huawei.hwpoints.balance.HcoinBalanceActivity\"\n      android:exported=\"false\"\n      android:screenOrientation=\"behind\"\n      android:configChanges=\"keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <intent-filter>\n        <action\n          android:name=\"com.huawei.pay.intent.action.Hcoin_Balance\">\n        </action>\n        <category\n          android:name=\"android.intent.category.DEFAULT\">\n        </category>\n      </intent-filter>\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@0x7f13026a\"\n      android:name=\"com.huawei.hwpoints.balance.TradeResultActivity\"\n      android:exported=\"false\"\n      android:screenOrientation=\"behind\"\n      android:configChanges=\"keyboard|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <activity\n      android:name=\"com.huawei.hwpoints.exchange.HCoinExchangeActivity\"\n      android:exported=\"false\"\n      android:screenOrientation=\"portrait\"\n      android:configChanges=\"keyboardHidden|orientation|screenSize\"\n      android:hardwareAccelerated=\"true\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui.NoActionBar\">\n      </meta-data>\n    </activity>\n    <activity\n      android:theme=\"@0x7f13026a\"\n      android:name=\"com.huawei.hwpoints.ui.web.hcoin.HcoinWebViewActivity\"\n      android:exported=\"false\"\n      android:screenOrientation=\"behind\"\n      android:configChanges=\"keyboard|keyboardHidden|layoutDirection|orientation|screenLayout|screenSize|smallestScreenSize\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui\">\n      </meta-data>\n    </activity>\n    <meta-data\n      android:name=\"com.huawei.hms.min_api_level:framework-inner-stub-sdk:runtime\"\n      android:value=\"4\">\n    </meta-data>\n    <meta-data\n      android:name=\"com.huawei.hms.min_api_level:framework-inner-stub-sdk:fwcom-grs\"\n      android:value=\"1\">\n    </meta-data>\n    <meta-data\n      android:name=\"com.huawei.hms.min_api_level:framework-inner-stub-sdk:fwcom-util\"\n      android:value=\"1\">\n    </meta-data>\n    <activity\n      android:theme=\"@0x7f13025e\"\n      android:name=\"com.braintreepayments.api.AndroidPayActivity\">\n    </activity>\n    <activity\n      android:theme=\"@0x7f13025e\"\n      android:name=\"com.braintreepayments.api.GooglePaymentActivity\">\n    </activity>\n    <activity\n      android:name=\"com.braintreepayments.api.threedsecure.ThreeDSecureWebViewActivity\">\n    </activity>\n    <service\n      android:name=\"com.braintreepayments.api.internal.AnalyticsIntentService\">\n    </service>\n    <activity\n      android:name=\"com.alipay.sdk.app.H5PayActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"keyboardHidden|navigation|orientation|screenSize\">\n    </activity>\n    <activity\n      android:name=\"com.alipay.sdk.app.H5AuthActivity\"\n      android:exported=\"false\"\n      android:configChanges=\"keyboardHidden|navigation|orientation|screenSize\">\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Translucent.NoTitleBar\"\n      android:name=\"com.alipay.sdk.app.PayResultActivity\"\n      android:exported=\"true\"\n      android:launchMode=\"singleInstance\"\n      android:configChanges=\"keyboardHidden|navigation|orientation|screenSize\">\n      <intent-filter>\n        <category\n          android:name=\"android.intent.category.DEFAULT\">\n        </category>\n      </intent-filter>\n    </activity>\n    <activity\n      android:theme=\"@style/Theme.Translucent.NoTitleBar\"\n      android:name=\"com.alipay.sdk.app.AlipayResultActivity\"\n      android:exported=\"true\"\n      android:launchMode=\"singleTask\">\n    </activity>\n    <activity\n      android:name=\"com.alipay.sdk.app.H5OpenAuthActivity\"\n      android:exported=\"false\"\n      android:screenOrientation=\"behind\"\n      android:configChanges=\"keyboardHidden|navigation|orientation|screenSize\"\n      android:windowSoftInputMode=\"adjustResize|stateHidden\">\n    </activity>\n    <meta-data\n      android:name=\"com.huawei.hms.min_api_level:hms-min-inner-sdk:hmscore\"\n      android:value=\"3\">\n    </meta-data>\n    <activity\n      android:theme=\"@style/Theme.Translucent\"\n      android:name=\"com.huawei.hms.activity.BridgeActivity\"\n      android:exported=\"false\"\n      android:excludeFromRecents=\"true\"\n      android:configChanges=\"fontScale|layoutDirection|locale|orientation|screenLayout|screenSize|smallestScreenSize\"\n      android:hardwareAccelerated=\"true\">\n      <meta-data\n        android:name=\"hwc-theme\"\n        android:value=\"androidhwext:style/Theme.Emui.Translucent\">\n      </meta-data>\n    </activity>\n    <activity\n      android:name=\"com.huawei.hms.activity.EnableServiceActivity\"\n      android:configChanges=\"keyboardHidden|orientation|screenLayout|screenSize|smallestScreenSize\">\n    </activity>\n    <meta-data\n      android:name=\"hwouc\"\n      android:value=\"hwmarket\">\n    </meta-data>\n    <meta-data\n      android:name=\"brotlipress\"\n      android:value=\"noPress\">\n    </meta-data>\n    <meta-data\n      android:name=\"com.android.vending.splits\"\n      android:resource=\"@0x7f15001e\">\n    </meta-data>\n  </application>\n</manifest>\n"
  },
  {
    "path": "app/src/test/resources/xml/settings_ssaid.xml",
    "content": "<?xml version='1.0' encoding='UTF-8' standalone='yes' ?>\n<settings version=\"-1\">\n  <setting id=\"0\" name=\"userkey\" value=\"A1F3C47E89D45B60C29E70A3F58D92E11B6AD02C78FE4D50937CA1B446E98F12\" package=\"android\" defaultValue=\"A1F3C47E89D45B60C29E70A3F58D92E11B6AD02C78FE4D50937CA1B446E98F12\" defaultSysSet=\"true\" tag=\"null\" />\n  <setting id=\"1\" name=\"10123\" value=\"3E9B72CDA48150F4\" package=\"com.google.android.gms\" defaultValue=\"3E9B72CDA48150F4\" defaultSysSet=\"false\" tag=\"null\" />\n  <setting id=\"2\" name=\"10124\" value=\"3E9B72CDA48150F4\" package=\"com.android.vending\" defaultValue=\"3E9B72CDA48150F4\" defaultSysSet=\"false\" tag=\"null\" />\n  <setting id=\"3\" name=\"10125\" value=\"3E9B72CDA48150F4\" package=\"com.android.chrome\" defaultValue=\"3E9B72CDA48150F4\" defaultSysSet=\"false\" tag=\"null\" />\n  <setting id=\"4\" name=\"10126\" value=\"9F4C3A7E21D86B52\" package=\"com.whatsapp\" defaultValue=\"9F4C3A7E21D86B52\" defaultSysSet=\"false\" tag=\"null\" />\n</settings>\n"
  },
  {
    "path": "app/src/test/resources/xml/test_layout.plain.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<FrameLayout\n  xmlns:android=\"http://schemas.android.com/apk/res/android\"\n  android:fitsSystemWindows=\"false\"\n  android:layout_width=\"fill_parent\"\n  android:layout_height=\"fill_parent\"\n  android:animateLayoutChanges=\"false\">\n  <ImageView\n    android:layout_gravity=\"center\"\n    android:id=\"@0x7f0902c2\"\n    android:layout_width=\"?0x7f0403c0\"\n    android:layout_height=\"?0x7f0403c0\">\n  </ImageView>\n</FrameLayout>\n"
  },
  {
    "path": "build.gradle",
    "content": "// SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-or-later\n\nbuildscript {\n    apply from: 'versions.gradle'\n\n    repositories {\n        google()\n        mavenCentral()\n    }\n    dependencies {\n        classpath \"com.android.tools.build:gradle:${agp_version}\"\n    }\n}\n\nwrapper {\n    distributionType = Wrapper.DistributionType.BIN\n}\n\nallprojects {\n    repositories {\n        google()\n        mavenCentral()\n        maven { url \"https://jitpack.io\" }\n    }\n    gradle.projectsEvaluated {\n        tasks.withType(JavaCompile).tap {\n            configureEach {\n                options.compilerArgs << \"-Xlint:unchecked\" << \"-Xlint:deprecation\"\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "docs/.gitignore",
    "content": "/build\n/src/main/res\n/dist\n"
  },
  {
    "path": "docs/build.gradle",
    "content": "import javax.inject.Inject\n\n// SPDX-License-Identifier: GPL-3.0-or-later\n\nplugins {\n    id('com.android.library')\n}\n\nandroid {\n    namespace 'io.github.muntashirakon.AppManager.docs'\n    compileSdk compile_sdk\n    buildToolsVersion = build_tools\n\n    defaultConfig {\n        minSdk min_sdk\n        targetSdk target_sdk\n    }\n\n    compileOptions {\n        encoding \"UTF-8\"\n    }\n}\n\n// https://docs.gradle.org/current/userguide/service_injection.html#execoperations\ninterface InjectedExecOps {\n    @Inject\n    ExecOperations getExecOps()\n}\n\ntasks.register('buildDocs') {\n    def injected = project.objects.newInstance(InjectedExecOps)\n    doLast {\n        println(\"=== docs: start ===\")\n        String buildExec = \"${rootProject.projectDir.absolutePath}/scripts/make_docs.sh\"\n        injected.execOps.exec {\n            workingDir = project.rootDir\n            executable = buildExec\n        }\n        println(\"=== docs: finish ===\")\n    }\n}\n\ntasks.register('cleanupDocs') {\n    doLast {\n        File file = new File(\"${rootProject.projectDir.absolutePath}/docs/src/main/res\")\n        if (file.exists()) {\n            deleteDir(file)\n        }\n    }\n}\n\ndef deleteDir(File dir) {\n    if (dir != null && dir.isDirectory()) {\n        String[] children = dir.list()\n        if (children == null) return false\n        for (String child : children) {\n            boolean success = deleteDir(new File(dir, child))\n            if (!success) return false\n        }\n        return dir.delete()\n    } else if (dir != null && dir.isFile()) {\n        return dir.delete()\n    } else return false\n}\n\npreBuild.dependsOn buildDocs\nclean.dependsOn cleanupDocs"
  },
  {
    "path": "docs/mdbook/.gitignore",
    "content": "book\nsrc"
  },
  {
    "path": "docs/mdbook/book.toml",
    "content": "[book]\nauthors = [\"Muntashir Al-Islam\"]\nlanguage = \"en\"\nmultilingual = false\nsrc = \"src\"\ntitle = \"App Manager\"\n"
  },
  {
    "path": "docs/mdbook/build.py",
    "content": "#  SPDX-License-Identifier: GPL-3.0-or-later\n\nimport re\nimport os\nimport argparse\n\ndef sanitize_filename(title):\n    \"\"\"Convert a title to a valid filename.\"\"\"\n    # Remove characters that aren't suitable for filenames\n    sanitized = re.sub(r'[^\\w\\s-]', '', title.lower())\n    # Replace spaces with hyphens\n    sanitized = re.sub(r'\\s+', '-', sanitized)\n    return sanitized\n\ndef extract_heading_level(line):\n    \"\"\"Extract heading level (1-4) from markdown heading.\"\"\"\n    match = re.match(r'^(#{1,3})\\s+(.+)$', line)\n    if match:\n        return len(match.group(1)), match.group(2).strip()\n    return 0, None\n\ndef process_markdown_file(input_file, output_dir):\n    \"\"\"Split markdown file into sections based on headings and generate summary.\"\"\"\n    os.makedirs(output_dir, exist_ok=True)\n\n    with open(input_file, 'r', encoding='utf-8') as f:\n        content = f.read()\n\n    # Split content by lines\n    lines = content.split('\\n')\n\n    current_files = {}  # Level -> current filename for that level\n    file_contents = {}  # Filename -> content\n    structure = []  # For building the summary structure\n\n    # Track used filenames to avoid duplicates\n    used_filenames = {}  # Base filename -> count\n\n    current_content = []\n    current_level = 0\n    current_title = \"index\"\n\n    # Hierarchical numbering to ensure unique files\n    section_numbers = {1: 0, 2: 0, 3: 0, 4: 0}\n\n    for line in lines:\n        level, title = extract_heading_level(line)\n\n        if level > 0:  # This is a heading\n            # Save current content before starting a new section\n            if current_content:\n                # Generate a unique filename\n                base_filename = sanitize_filename(current_title)\n\n                # Update section numbers for hierarchy\n                section_numbers[current_level] += 1\n                # Reset all lower levels\n                for l in range(current_level + 1, 5):\n                    section_numbers[l] = 0\n\n                # Create a unique section identifier\n                section_id = \"\"\n                for l in range(1, current_level + 1):\n                    section_id += f\"{section_numbers[l]}.\"\n\n                # Create unique filename with section numbers\n                filename = f\"{section_id.rstrip('.')}-{base_filename}.md\"\n\n                current_files[current_level] = filename\n\n                # Add to structure\n                indent = \"  \" * (current_level - 1)\n                structure.append(f\"{indent}- [{current_title}]({filename})\")\n\n                file_contents[filename] = '\\n'.join(current_content)\n\n            # Reset content for new section\n            current_content = [line]\n            current_level = level\n            current_title = title\n\n            # Clear lower level files\n            for l in list(current_files.keys()):\n                if l > level:\n                    del current_files[l]\n        else:\n            # Add to current content\n            current_content.append(line)\n\n    # Save the last section\n    if current_content:\n        # Generate a unique filename\n        base_filename = sanitize_filename(current_title)\n\n        # Update section numbers\n        section_numbers[current_level] += 1\n\n        # Create a unique section identifier\n        section_id = \"\"\n        for l in range(1, current_level + 1):\n            section_id += f\"{section_numbers[l]}.\"\n\n        # Create unique filename with section numbers\n        filename = f\"{section_id.rstrip('.')}-{base_filename}.md\"\n\n        current_files[current_level] = filename\n\n        # Add to structure\n        indent = \"  \" * (current_level - 1)\n        structure.append(f\"{indent}- [{current_title}]({filename})\")\n\n        file_contents[filename] = '\\n'.join(current_content)\n\n    # Write files\n    for filename, content in file_contents.items():\n        with open(os.path.join(output_dir, filename), 'w', encoding='utf-8') as f:\n            f.write(content)\n\n    # Create SUMMARY.md\n    summary_content = \"# Summary\\n\\n\" + \"\\n\".join(structure)\n    with open(os.path.join(output_dir, \"SUMMARY.md\"), 'w', encoding='utf-8') as f:\n        f.write(summary_content)\n\n    return structure\n\ndef convert_latex_to_markdown(input_file, output_file):\n    \"\"\"Convert LaTeX to Markdown using Pandoc.\"\"\"\n    import subprocess\n\n    cmd = [\"pandoc\", \"-f\", \"latex\", \"-t\", \"markdown_strict+tex_math_dollars\",\n           input_file, \"-o\", output_file]\n\n    subprocess.run(cmd, check=True)\n    return output_file\n\ndef main():\n    parser = argparse.ArgumentParser(description=\"Convert LaTeX to mdBook format\")\n    parser.add_argument(\"input_file\", help=\"Input LaTeX file\")\n    parser.add_argument(\"--output-dir\", default=\"src\",\n                        help=\"Output directory for mdBook source files\")\n    parser.add_argument(\"--skip-pandoc\", action=\"store_true\",\n                        help=\"Skip Pandoc conversion (input is already Markdown)\")\n\n    args = parser.parse_args()\n\n    # Step 1: Convert LaTeX to Markdown if needed\n    if not args.skip_pandoc:\n        print(f\"Converting {args.input_file} to Markdown...\")\n        temp_md = \"temp_converted.md\"\n        convert_latex_to_markdown(args.input_file, temp_md)\n        input_md = temp_md\n    else:\n        input_md = args.input_file\n\n    # Step 2: Process Markdown and split into sections\n    print(f\"Processing Markdown and creating mdBook structure in {args.output_dir}...\")\n    structure = process_markdown_file(input_md, args.output_dir)\n\n    # Cleanup temporary file\n    if not args.skip_pandoc and os.path.exists(temp_md):\n        os.remove(temp_md)\n\n    print(f\"Done! mdBook structure created in {args.output_dir}\")\n    print(f\"Created {len(structure)} section files\")\n    print(\"You can now run 'mdbook build' in the parent directory of your src folder\")\n\nif __name__ == \"__main__\":\n    main()"
  },
  {
    "path": "docs/raw/.gitignore",
    "content": "*.*\n!.gitignore\n!*.tex\n!*.css\n!*.html\n!*.drawio\n!*.png\n!*.pdf\n!*.svg\n!*.xml\n!*.lua\n!*.md\n!*.sh\nen/svg-inkscape\nen/main_vanilla.pdf\nen/transient.tex\n"
  },
  {
    "path": "docs/raw/changelog_old.md",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later OR CC-BY-SA-4.0 -->\n---\nsidebar: auto\n---\n# Old Changelog\n\n## v2.5.12 (341)\n- <span><TagFeature/></span>  Added support for splitting data backups into 1GB files to circumvent the limitation of FAT32 file system\n- <span><TagFeature/></span>  Added the ability to unblock trackers\n- <span><TagFeature/></span>  Added an option to skip signature checks while restoring backups\n- <span><TagFeature/></span>  [Termux][termux] support: <code>run-as</code> debuggable app or run new session as app in the [App Info tab][app_info]\n- <span><TagFeature/></span>  Display backup app info in the [Main page][main_page]\n- <span><TagFeature/></span>  Restoring source files (except apk files) disabled on unsupported architecture\n- <span><TagFeature/></span>  Display confirmation dialog before clearing app data\n- <span><TagFeature/></span>  Ability to import components disabled using IFW on MAT\n- <span><TagFeature/></span>  Include external media and obb directory for backups\n- <span><TagFeature/></span>  Allow importing existing rules by other apps or tools\n- <span><TagFeature/></span>  Added an option to extract app icon in [App Info tab][app_info]\n- <span><TagFix/></span> Display restore and delete backups only for apps with backup\n- <span><TagFix/></span> Display progress indicator while taking backups\n- <span><TagFix/></span> Display progress indicator while loading app ops\n- <span><TagFix/></span> Fixed app not opening in the latest and the only supported Aurora Droid (v1.0.6)\n- <span><TagFix/></span> Fixed crash on night mode change while browsing [App Details page][1]\n- <span><TagFix/></span> Fixed crash when trying to open external apk file\n- <span><TagFix/></span> Fixed NullPointerException when an external data directory is null\n- <span><TagFix/></span> Fixed toolbar in full screen dialog\n- <span><TagFix/></span> Fixed case insensitive searching\n- <span><TagFix/></span> Optimized app theme\n- <span><TagFix/></span> Replaced AndroidShell with LibSuperuser\n- <span><TagFix/></span> Request external storage permission when saving apk files\n- <span><TagFix/></span> Workaround for AppBarLayout bug in Material Design\n- <span><TagFix/></span> Update external apk info on install/uninstall events\n\nTo use Termux features, make sure you are using Termux v0.96 or later and `allow-external-apps=true` is added in <tt>~/.termux/termux.properties</tt>.\n\nData backup feature is still considered experimental and please do not rely on it to manage your backups yet.\n\n## v2.5.11 (333)\n- <span><TagFeature/></span>  Added experimental support for app data backup. Please test only on apps you don't need. (root only)\n- <span><TagFeature/></span>  Added sharing split apk files as apks (can be installed via [SAI][8]).\n- <span><TagFeature/></span>  Implemented saving apk files in batch selection mode.\n- <span><TagFeature/></span>  Added what's new for apk file that needs an update (when opening external apk files).\n- <span><TagFeature/></span>  Added an option to apply 1-click ops to system apps (disabled by default).\n- <span><TagFeature/></span>  Added installed app version info in the App Info tab. Clicking the _i_ icon opens the installed [App Info][app_info] tab.\n- <span><TagFeature/></span>  New on-demand permissions <tt>READ_EXTERNAL_STORAGE</tt> & <tt>WRITE_EXTERNAL_STORAGE</tt> for app backup support\n- <span><TagFeature/></span>  Display apps that are uninstalled but have backups in the main page\n- <span><TagFeature/></span>  Added a disclaimer\n- <span><TagFix/></span> Fixed selections being not cleared after the task is completed in the main page\n- <span><TagFix/></span> Convert various info in the configurations and features tab to text to improve readability\n- <span><TagFix/></span> Fix crash in the [Main page][main_page] while filtering apps by search query\n- <span><TagFix/></span> Fix crash in the [App Info][app_info] tab when existence of external data directory has false-positive result\n\n**Note:** Backup data are stored at <tt>/sdcard/AppManager</tt> and apk backups are stored at <tt>/sdcard/AppManager/apks</tt>. Data backups are currently not working on Android Lollipop.\n\n## v2.5.10 (324)\n- <span><TagFeature/></span>  Added 1-click operations (as [1-Click Ops](./guide/one-click-ops-page.md) in the menu section in the [Main page][main_page]): block (ads and) trackers, component blocking by signatures, app op blocking\n- <span><TagFeature/></span>  Added support for external apk: You can now open apk files from your file manager. You can view app details, manifest or scan for trackers directly from there\n- <span><TagFeature/></span>  Added persistent apps filtering option in the [Main page][main_page]\n- <span><TagFeature/></span>  Alternative manifest viewer for installed apks\n- <span><TagFeature/></span>  Display number of trackers as a tag in the [App Info][app_info] tab\n- <span><TagFeature/></span>  Added a select all option in the bottom bar in the [Main page][main_page] in selection mode\n- <span><TagFeature/></span>  Added links to source code and community\n- <span><TagFeature/></span>  Added support for installing/updating apk files in the [App Info][app_info] tab (incomplete)\n- <span><TagFeature/></span>  Added an option to import existing disabled components in the Import/Export settings (incomplete)\n- <span><TagFeature/></span>  Added split apk information in [App Info][app_info] tab\n- <span><TagFeature/></span>  Added an option to open [Termux](./guide/main-page.md#termux) in the [Main page][main_page] (incomplete)\n- <span><TagFeature/></span>  Initial support for app banner\n- <span><TagFix/></span> Fixed inconsistency of enable and disable in the App Info tab\n- <span><TagFix/></span> Fixed issue with persistent app cache\n- <span><TagFix/></span> Fixed scrolling issue on settings page\n- <span><TagFix/></span> Fixed crashes when switching to the components tabs for non-root users\n- <span><TagFix/></span> Fixed crash when trying to view summary while scanning is still in progress in the exodus page\n- <span><TagFix/></span> Fixed crashes on devices that does not support data usage\n- <span><TagFix/></span> Fixed crash when trying to view manifest of an split apk\n- <span><TagFix/></span> Fixed wrong package installer name in the [App Info][app_info] tab\n- <span><TagFix/></span> Fixed changelog formatting for old devices\n\n## v2.5.9 (315)\n- <span><TagFeature/></span>  Merged [App Info][app_info] as a single tab in [App Details][1]\n- <span><TagFeature/></span>  Added option to reset all app ops\n- <span><TagFeature/></span>  Added option to revoke all dangerous app ops/permissions\n- <span><TagFeature/></span>  Highlight trackers in the component tabs\n- <span><TagFeature/></span>  Added option to save manifest and class dump\n- <span><TagFeature/></span>  Added the ability to grant/revoke development permissions\n- <span><TagFeature/></span>  Added sorting options for components, app ops and uses permissions tabs\n- <span><TagFeature/></span>  Added sort by wifi usage in the [App Usage][6] page\n- <span><TagFeature/></span>  Added launch button in the [App Info][app_info] tab\n- <span><TagFeature/></span>  Added never ask option to usage status prompt\n- <span><TagFeature/></span>  Added long click to select apps in the [Main page][main_page]\n- <span><TagFeature/></span>  Added changelog within the app\n- <span><TagFix/></span> Click to select apps during selection mode\n- <span><TagFix/></span> Improved component blocker\n- <span><TagFix/></span> Improved manifest loading for large apps\n- <span><TagFix/></span> Improved tab loading performance\n- <span><TagFix/></span> Fixed app ops checking and custom app ops for some devices\n- <span><TagFix/></span> Disabled activity opening for disabled activities\n- <span><TagFix/></span> Get real activity name for activities that use activity-alias\n- <span><TagFix/></span> Fixed background colors\n- <span><TagFix/></span> Fixed crashing when loading the services tab for non-root users\n- <span><TagFix/></span> Fixed back button for class viewer which was not working\n- <span><TagFix/></span> Changed block icon's colour to accent colour\n- <span><TagFix/></span> Removed translation until the app is complete\n- <span><TagFix/></span> Made links in the credit section clickable\n- <span><TagFix/></span> Fixed various memory leaks\n\n## v2.5.8 (289)\n- <span><TagFeature/></span>  Added [import/export capabilities for blocking rules](./guide/settings-page.md#import-export-blocking-rules)\n- <span><TagFeature/></span>  Added ability to [select themes](./guide/settings-page.html#app-theme) (night/day)\n- <span><TagFeature/></span>  Added mode, duration, accept time, reject time for app ops\n- <span><TagFeature/></span>  Highlight running services\n- <span><TagFeature/></span>  Highlight disabled components not disabled within App Manager\n- <span><TagFeature/></span>  Added swipe to refresh in the [App Usage][6] page\n- <span><TagFeature/></span>  Added screen time percentage with indicator\n- <span><TagFeature/></span>  Separate instructions and about pages with fullscreen dialog for both\n- <span><TagFeature/></span>  Rounded overflow menu (still incomplete)\n- <span><TagFix/></span> Fixed various device/SDK specific app ops issues\n- <span><TagFix/></span> Stability improvements of the entire apps\n- <span><TagFix/></span> Added <tt>ACCESS_NETWORK_STATE</tt> permission to support older operating systems\n- <span><TagFix/></span> Fixed deleting all IFW rules when selecting [Global Component Blocking][5]\n- <span><TagFix/></span> Fixed various search issues\n\n## v2.5.7 (265)\n- <span><TagFeature/></span>  Initial support for [ADB over TCP](./guide/adb-over-tcp.md) (port 5555) for non-root users\n- <span><TagFix/></span> Fixed importing rules from [Watt][2] and [Blocker][3]\n- <span><TagFix/></span> Display Aurora Droid in [App Info][app_info] page as a first priority over F-Droid\n- <span><TagFix/></span> Improved performance for component blocking\n- <span><TagFix/></span> Fixed app op mode detection issue\n\n**For root users:** If you've skipped [v2.5.6](#v2-5-6-233), you may need to apply all rules globally by applying [Global Component Blocking][5] in Settings in order for them to work.\n\n## v2.5.6 (233)\n- <span><TagFeature/></span>  [Batch operations](./guide/main-page.md#batch-operations) in the main page: clear app data, disable run in background, disable/kill/uninstall apps (click on the app icon to select)\n- <span><TagFeature/></span>  Full support of [Blocker][3]'s exported files which was broken due to a bug in Blocker\n- <span><TagFeature/></span>  Reimplementation of blocking activities, receivers, services and providers\n- <span><TagFix/></span> Removed ConstraintLayout dependency therefore a potential decrease in app size\n- <span><TagFix/></span> Fixed duplicate app usage warning in the [App Info][app_info] page\n- <span><TagFix/></span> Fixed crash when an app icon is not found in [App Details][1] page\n\n**Note for root users:** In order to ensure that the previous blocking rules are preserved with the new blocking implementation, this update reads from the previous rules consequently increasing the loading time in the [Main page][main_page]. This feature will be removed in the next release but can still be simulated by applying [global component blocking][5] in Settings.\n\n## v2.5.5 (215)\n- <span><TagFeature/></span>  Added [Running Apps/Process Viewer](./guide/main-page.md#running-apps) (requires root)\n- <span><TagFeature/></span>  Added [Usage Details Viewer][6]\n- <span><TagFeature/></span>  Added [Apk Updater](./guide/main-page.md#apk-updater) and [Aurora Store](./guide/app-details-page.md#actions-in-app-info-tab) support\n- <span><TagFeature/></span>  Save modified values of app ops and permissions to the disk (on progress)\n- <span><TagFix/></span> Uninstall support for non-root users\n- <span><TagFix/></span> Restructure app usage\n- <span><TagFix/></span> Added more clarity as well as improve performance in the [App Details][1] page\n\n[1]: ./guide/app-details-page.md\n[2]: https://github.com/tuyafeng/Watt\n[3]: https://github.com/lihenggui/blocker\n[app_info]: ./guide/app-details-page.md#app-info-tab\n[5]: ./guide/settings-page.md#global-component-blocking\n[6]: ./guide/main-page.md#app-usage\n[main_page]: ./guide/main-page.md\n[8]: https://github.com/Aefyr/SAI\n[termux]: https://github.com/termux/termux-app\n"
  },
  {
    "path": "docs/raw/css/custom.css",
    "content": "#title-block-header{display:none}#TOC{height:100%;width:16em;position:fixed;z-index:1;top:0;left:0;overflow-x:hidden;padding:0 1.25em;color:#21005d;background:#eaddff}#TOC ul{list-style-type:none;padding:1em 0;margin:0;font-weight:700;font-size:1.2em}#TOC ul ul{list-style-type:none;padding:0 0 0 20px;margin:0;font-weight:400;font-size:.8em}#TOC ul ul ul{list-style-type:none;padding:0 0 0 20px;margin:0;font-style:oblique;font-size:.9em}.center{text-align:center}.level1,.footnotes,.titlingpage{padding:1em;margin:auto}.level5 h5 .header-section-number{display:none}.level5 h5{margin:auto;display:inline-block;padding-right:.5em}.level5 h5+p,.level5 h5+div+p{display:inline}.level5 h5+div{display:inline}.titlingpage p:nth-child(2){font-size:3em}.footnotes{margin-right:auto!important;border-bottom:unset!important;font-size:inherit!important}@media screen and (min-width:48em){.level1,.footnotes,.titlingpage{margin-left:18.5em}}@media screen and (max-width:48em){#TOC{position:unset;height:unset;width:unset;background:unset}.level1,.footnotes,.titlingpage{max-width:42em}}.amalert{border-width:0 0 0 3pt!important;border-style:solid;padding:.4em .4em .4em .8em;color:unset!important;background:unset!important;margin-bottom:1em}.amalert>p:first-child{padding-right:5px}.amalert.tip{border-color:#625b71!important;color:#1d192b!important;background-color:#e8def8!important}.amalert.warning{border-color:#7d5260!important;color:#31111d!important;background-color:#ffd8e4!important}.amalert.danger{border-color:#b3261e!important;color:#410e0b!important;background-color:#f9dedc!important}.amalert p:nth-child(1),.amalert p:nth-child(2){display:inline}.seealso *,.seealso-inline{font-style:oblique;margin:0}.seealso *{display:inline-block}.seealso ul{padding:0}.seealso ul li:before{content:'\\00a0\\2022\\00a0'}.colorbox{padding:3px 7px;border-radius:5px}figcaption.caption span.id:after{content:' '}figure{text-align:center}html{font-size:100%;overflow-y:scroll;-webkit-text-size-adjust:100%;-ms-text-size-adjust:100%}body{font-family:Palatino,palatino linotype,Georgia,Times,times new roman,serif;font-size:12px;line-height:1.5em;word-break:break-word;color:#1c1b1f;background:#fffbfe}a{color:#6750a4;text-decoration:none}a:active,a:visited{color:#6750a4}a:hover{color:#6750a4;text-decoration:underline}a:focus{outline:thin dotted}a:hover,a:active{outline:0}.anchor{opacity:.2}.anchor:after{content:\"¶︎\"}.anchor:hover{opacity:1;text-decoration:none}::-moz-selection{background:#e7e0ec;color:#49454f}::selection{background:#e7e0ec;color:#49454f}a::-moz-selection{background:#fff;color:#6750a4}a::selection{background:#fff;color:#6750a4}p{margin:1em 0}img,object[type='image/svg+xml']{max-width:100%}h1,h2,h3,h4,h5,h6{font-weight:400;color:#1c1b1f;line-height:1em}h4,h5,h6{font-weight:700}h1{font-size:2.5em}h2{font-size:2em}h3{font-size:1.5em}h4{font-size:1.2em}h5{font-size:1em}h6{font-size:.9em}blockquote{color:#666;margin:0}hr{display:block;border:0;border-top:1px solid rgba(0,0,0,.12);border-bottom:1px solid rgba(0,0,0,.12);margin:1em 0;padding:0}pre,code,kbd,samp{font-family:monospace,monospace;_font-family:'courier new',monospace;font-size:.98em}div.sourceCode{background-color:#f4f4f4}pre{padding:1em;word-wrap:break-word;background-color:#f4f4f4}b,strong{font-weight:700}dfn{font-style:italic}ins{background:#e7e0ec;color:#49454f;text-decoration:none}mark{background:#e7e0ec;color:#49454f;font-style:italic;font-weight:700}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:baseline}sup{top:-.5em}sub{bottom:-.25em}ul,ol{margin:1em 0;padding:0 0 0 2em}li p:last-child{margin:0}dd{margin:0 0 0 2em}img,object[type='image/svg+xml']{border:0;-ms-interpolation-mode:bicubic;vertical-align:middle}table{border-collapse:collapse;border-spacing:0}td{vertical-align:top}@media only screen and (min-width:480px){body{font-size:14px}}@media only screen and (min-width:768px){body{font-size:16px}}@media(prefers-color-scheme:dark){#TOC{color:#eaddff;background:#4f378b!important}body{color:#e6e1e5!important;background-color:#1c1b1f!important}a,a:visited{color:#d0bcff!important}h1,h2,h3,h4,h5,h6{color:#e6e1e5!important}hr{border-top:1px solid rgba(255,255,255,.2);border-bottom:1px solid rgba(255,255,255,.2)}pre,div.sourceCode{background-color:#242424}.amalert.tip{border-color:#ccc2dc!important;color:#e8def8!important;background-color:#4a4458!important}.amalert.warning{border-color:#efb8c8!important;color:#ffd8e4!important;background-color:#633b48!important}.amalert.danger{border-color:#f2b8b5!important;color:#f2b8b5!important;background-color:#8c1d18!important}}@media print{*{background:0 0!important;color:#000!important;filter:none!important;-ms-filter:none!important}#TOC{display:none}.amalert.tip{color:unset!important;background-color:unset!important}.amalert.warning{color:unset!important;background-color:unset!important}.amalert.danger{color:unset!important;background-color:unset!important}body{font-size:12pt;max-width:100%}a,a:visited{text-decoration:underline}hr{height:1px;border:0;border-bottom:1px solid #000}a[href]:after{content:\" <\" attr(href)\">\"}abbr[title]:after{content:\" (\" attr(title)\")\"}.ir a:after,a.uri:after,a[href^=\"javascript:\"]:after,a[href^=\"mailto:\"]:after,a[href^=\"app-manager:\"]:after,a[href^=\"#\"]:after{content:\"\"}a[href^=\"#toc:\"]{text-decoration:none}a.footnote-ref{text-decoration:none}a.footnote-back{display:none}pre,blockquote{border:1px solid #999;padding:.5em;page-break-inside:avoid}tr,img,object[type='image/svg+xml']{page-break-inside:avoid}img,object[type='image/svg+xml']{max-width:100%!important}@page:left{margin:15mm 20mm 15mm 10mm}@page:right{margin:15mm 10mm 15mm 20mm}p,h2,h3{orphans:3;widows:3}h2,h3{page-break-after:avoid}}"
  },
  {
    "path": "docs/raw/de/index.html",
    "content": "<!doctype html><html xmlns=http://www.w3.org/1999/xhtml lang=de xml:lang=de><meta charset=utf-8><meta name=generator content=\"pandoc\"><meta name=viewport content=\"width=device-width,initial-scale=1,user-scalable=yes\"><meta name=author content=\"Muntashir Al-Islam\"><title>App Manager</title><style>code{white-space:pre-wrap}span.smallcaps{font-variant:small-caps}div.columns{display:flex;gap:min(4vw,1.5em)}div.column{flex:auto;overflow-x:auto}div.hanging-indent{margin-left:1.5em;text-indent:-1.5em}ul.task-list[class]{list-style:none}ul.task-list li input[type=checkbox]{font-size:inherit;width:.8em;margin:0 .8em .2em -1.6em;vertical-align:middle}.display.math{display:block;text-align:center;margin:.5rem auto}html{-webkit-text-size-adjust:100%}pre>code.sourceCode{white-space:pre;position:relative}pre>code.sourceCode>span{display:inline-block;line-height:1.25}pre>code.sourceCode>span:empty{height:1.2em}.sourceCode{overflow:visible}code.sourceCode>span{color:inherit;text-decoration:inherit}div.sourceCode{margin:1em 0}pre.sourceCode{margin:0}@media screen{div.sourceCode{overflow:auto}}@media print{pre>code.sourceCode{white-space:pre-wrap}pre>code.sourceCode>span{text-indent:-5em;padding-left:5em}}pre.numberSource code{counter-reset:source-line 0}pre.numberSource code>span{position:relative;left:-4em;counter-increment:source-line}pre.numberSource code>span>a:first-child::before{content:counter(source-line);position:relative;left:-1em;text-align:right;vertical-align:baseline;border:none;display:inline-block;-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;padding:0 4px;width:4em}pre.numberSource{margin-left:3em;padding-left:4px}div.sourceCode{}@media screen{pre>code.sourceCode>span>a:first-child::before{text-decoration:underline}}code span.al{font-weight:700}code span.an{font-style:italic}code span.cf{font-weight:700}code span.co{font-style:italic}code span.cv{font-style:italic}code span.do{font-style:italic}code span.dt{text-decoration:underline}code span.er{font-weight:700}code span.in{font-style:italic}code span.kw{font-weight:700}code span.pp{font-weight:700}code span.wa{font-style:italic}</style><link rel=stylesheet href=../css/custom.css><header id=title-block-header><h1 class=title>App Manager</h1><p class=author>Muntashir Al-Islam</header><nav id=TOC role=doc-toc><ul class=incremental><li><span><span class=toc-section-number>1</span> <a href=#ch:introduction id=toc:ch:introduction>Einleitung</a></span><ul class=incremental><li><span><span class=toc-section-number>1.1</span> <a href=#sec:terminologies id=toc:sec:terminologies>Fachbegriffe</a></span><li><span><span class=toc-section-number>1.2</span> <a href=#sec:supported-versions id=toc:sec:supported-versions>Unterstützte Versionen</a></span><li><span><span class=toc-section-number>1.3</span> <a href=#sec:official-sources id=toc:sec:official-sources>Offizielle\nQuellen</a></span><ul class=incremental><li><span><span class=toc-section-number>1.3.1</span> <a href=#subsec:binary-distribution-sources id=toc:subsec:binary-distribution-sources>Quellen der binären\nVerteilung</a></span><li><span><span class=toc-section-number>1.3.2</span> <a href=#subsec:links-to-source-code id=toc:subsec:links-to-source-code>Links zum Quellcode</a></span><li><span><span class=toc-section-number>1.3.3</span> <a href=#subsec:translations id=toc:subsec:translations>Übersetzungen</a></span></ul><li><span><span class=toc-section-number>1.4</span> <a href=#sec:contributing id=toc:sec:contributing>Mitwirkende</a></span><ul class=incremental><li><span><span class=toc-section-number>1.4.1</span> <a href=#subsec:build-instructions id=toc:subsec:build-instructions>Hinweise zur\nErstellung</a></span><li><span><span class=toc-section-number>1.4.2</span> <a href=#subsec:submitting-patches id=toc:subsec:submitting-patches>Einreichen von\nPatches</a></span></ul><li><span><span class=toc-section-number>1.5</span> <a href=#sec:donation-&-funding id=toc:sec:donation-&-funding>Spende &\nFörderung</a></span><li><span><span class=toc-section-number>1.6</span> <a href=#sec:contact id=toc:sec:contact>Ansprechpartner</a></span></ul><li><span><span class=toc-section-number>2</span> <a href=#ch:pages id=toc:ch:pages>Seiten</a></span><ul class=incremental><li><span><span class=toc-section-number>2.1</span> <a href=#sec:main-page id=toc:sec:main-page>Hauptseite</a></span><ul class=incremental><li><span><span class=toc-section-number>2.1.1</span> <a href=#subsec:batch-operations id=toc:subsec:batch-operations>Stapelverarbeitung</a></span><li><span><span class=toc-section-number>2.1.2</span> <a href=#subsec:main-colour-codes id=toc:subsec:main-colour-codes>Farbcode</a></span><li><span><span class=toc-section-number>2.1.3</span> <a href=#subsec:main-page-application-types id=toc:subsec:main-page-application-types>Anwendungstypen</a></span><li><span><span class=toc-section-number>2.1.4</span> <a href=#subsec:main-page-version-info id=toc:subsec:main-page-version-info>Infos zur Version</a></span><li><span><span class=toc-section-number>2.1.5</span> <a href=#subsec:main-page-options-menu id=toc:subsec:main-page-options-menu>Menü Optionen</a></span></ul><li><span><span class=toc-section-number>2.2</span> <a href=#sec:app-details-page id=toc:sec:app-details-page>App-Detailseite</a></span><ul class=incremental><li><span><span class=toc-section-number>2.2.1</span> <a href=#subsec:app-details-colour-codes id=toc:subsec:app-details-colour-codes>Farbcodes</a></span><li><span><span class=toc-section-number>2.2.2</span> <a href=#subsec:app-info-tab id=toc:subsec:app-info-tab>Registerkarte\nApp-Info</a></span><li><span><span class=toc-section-number>2.2.3</span> <a href=#subsec:component-tabs id=toc:subsec:component-tabs>Registerkarten der\nKomponenten</a></span><li><span><span class=toc-section-number>2.2.4</span> <a href=#subsec:permission-tabs id=toc:subsec:permission-tabs>Registerkarten\nBerechtigungen</a></span><li><span><span class=toc-section-number>2.2.5</span> <a href=#subsec:signatures-tab id=toc:subsec:signatures-tab>Registerkarte Signaturen</a></span><li><span><span class=toc-section-number>2.2.6</span> <a href=#subsec:uses-features-tab id=toc:subsec:uses-features-tab>Uses\nFeatures tab</a></span><li><span><span class=toc-section-number>2.2.7</span> <a href=#subsec:configurations-tab id=toc:subsec:configurations-tab>Configurations tab</a></span><li><span><span class=toc-section-number>2.2.8</span> <a href=#subsec:shared-libs-tab id=toc:subsec:shared-libs-tab>Registerkarte Gemeinsame\nBibliotheken</a></span></ul><li><span><span class=toc-section-number>2.3</span> <a href=#sec:1-click-ops-page id=toc:sec:1-click-ops-page>1-Klick-Ops\nSeite</a></span><ul class=incremental><li><span><span class=toc-section-number>2.3.1</span> <a href=#subsec:block-unblock-trackers id=toc:subsec:block-unblock-trackers>Blockieren/Entsperren von\nTrackern</a></span><li><span><span class=toc-section-number>2.3.2</span> <a href=#subsec:block-components-dots id=toc:subsec:block-components-dots>Block\nKomponenten Punkte</a></span><li><span><span class=toc-section-number>2.3.3</span> <a href=#subsec:set-mode-for-app-ops-dots id=toc:subsec:set-mode-for-app-ops-dots>Modus für App Ops\neinstellen Punkte</a></span><li><span><span class=toc-section-number>2.3.4</span> <a href=#subsec:1-click-back-up id=toc:subsec:1-click-back-up>Sichern</a></span><li><span><span class=toc-section-number>2.3.5</span> <a href=#subsec:1-click-restore id=toc:subsec:1-click-restore>Wiederherstellen</a></span><li><span><span class=toc-section-number>2.3.6</span> <a href=#subsec:trim-caches-in-all-apps id=toc:subsec:trim-caches-in-all-apps>Trim Caches in All\nApps</a></span></ul><li><span><span class=toc-section-number>2.4</span> <a href=#sec:profiles-page id=toc:sec:profiles-page>Seite\nProfile</a></span><ul class=incremental><li><span><span class=toc-section-number>2.4.1</span> <a href=#subsec:profiles-options-menu id=toc:subsec:profiles-options-menu>Menü Optionen</a></span></ul><li><span><span class=toc-section-number>2.5</span> <a href=#sec:profile-page id=toc:sec:profile-page>Seite\nProfil</a></span><ul class=incremental><li><span><span class=toc-section-number>2.5.1</span> <a href=#subsec:profile-options-menu id=toc:subsec:profile-options-menu>Menü Optionen</a></span><li><span><span class=toc-section-number>2.5.2</span> <a href=#subsec:profile-apps-tab id=toc:subsec:profile-apps-tab>Registerkarte\nAnwendungen</a></span><li><span><span class=toc-section-number>2.5.3</span> <a href=#subsec:profile-configurations-tab id=toc:subsec:profile-configurations-tab>Registerkarte\nKonfigurationen</a></span></ul><li><span><span class=toc-section-number>2.6</span> <a href=#sec:settings-page id=toc:sec:settings-page>Seite\nEinstellungen</a></span><ul class=incremental><li><span><span class=toc-section-number>2.6.1</span> <a href=#subsec:language id=toc:subsec:language>Sprache</a></span><li><span><span class=toc-section-number>2.6.2</span> <a href=#subsec:appearance id=toc:subsec:appearance>Appearance</a></span><li><span><span class=toc-section-number>2.6.3</span> <a href=#subsec:privacy id=toc:subsec:privacy>Privacy</a></span><li><span><span class=toc-section-number>2.6.4</span> <a href=#subsec:mode-of-operation id=toc:subsec:mode-of-operation>Betriebsmodus</a></span><li><span><span class=toc-section-number>2.6.5</span> <a href=#subsec:apk-signing id=toc:subsec:apk-signing>APK-Signierung</a></span><li><span><span class=toc-section-number>2.6.6</span> <a href=#subsec:installer id=toc:subsec:installer>Installationsprogramm</a></span><li><span><span class=toc-section-number>2.6.7</span> <a href=#subsec:backup/restore id=toc:subsec:backup/restore>Sichern/Wiederherstellen</a></span><li><span><span class=toc-section-number>2.6.8</span> <a href=#subsec:rules id=toc:subsec:rules>Regeln</a></span><li><span><span class=toc-section-number>2.6.9</span> <a href=#subsec:advanced id=toc:subsec:advanced>Advanced</a></span><li><span><span class=toc-section-number>2.6.10</span> <a href=#subsec:device-info id=toc:subsec:device-info>Über das Gerät\nselbst</a></span></ul><li><span><span class=toc-section-number>2.7</span> <a href=#sec:scanner-page id=toc:sec:scanner-page>Scanner-Seite</a></span><li><span><span class=toc-section-number>2.8</span> <a href=#sec:interceptor-page id=toc:sec:interceptor-page>Interceptor-Seite</a></span><ul class=incremental><li><span><span class=toc-section-number>2.8.1</span> <a href=#subsec:intent-filters id=toc:subsec:intent-filters>Intent-Filter</a></span><li><span><span class=toc-section-number>2.8.2</span> <a href=#subsec:matching-activities id=toc:subsec:matching-activities>Übereinstimmende\nAktivitäten</a></span><li><span><span class=toc-section-number>2.8.3</span> <a href=#subsec:interceptor-reset-to-default id=toc:subsec:interceptor-reset-to-default>Zurücksetzen auf\nStandard</a></span><li><span><span class=toc-section-number>2.8.4</span> <a href=#subsec:interceptor-send-edited-intent id=toc:subsec:interceptor-send-edited-intent>Geänderte Absicht\nsenden</a></span></ul><li><span><span class=toc-section-number>2.9</span> <a href=#sec:shared-preferences-editor-page id=toc:sec:shared-preferences-editor-page>Editorseite für gemeinsame\nEinstellungen</a></span></ul><li><span><span class=toc-section-number>3</span> <a href=#ch:guides id=toc:ch:guides>Leitlinien</a></span><ul class=incremental><li><span><span class=toc-section-number>3.1</span> <a href=#sec:adb-over-tcp id=toc:sec:adb-over-tcp>ADB über\nTCP</a></span><ul class=incremental><li><span><span class=toc-section-number>3.1.1</span> <a href=#subsec:enable-developer-options id=toc:subsec:enable-developer-options>Entwickleroptionen\naktivieren</a></span><li><span><span class=toc-section-number>3.1.2</span> <a href=#subsec:enable-usb-debugging id=toc:subsec:enable-usb-debugging>USB-Debugging\naktivieren</a></span><li><span><span class=toc-section-number>3.1.3</span> <a href=#subsec:setup-adb-on-pc-or-mac id=toc:subsec:setup-adb-on-pc-or-mac>ADB auf einem PC oder Mac\neinrichten</a></span><li><span><span class=toc-section-number>3.1.4</span> <a href=#subsec:configure-adb-over-tcp id=toc:subsec:configure-adb-over-tcp>ADB über TCP\neinrichten</a></span></ul><li><span><span class=toc-section-number>3.2</span> <a href=#sec:wireless-debugging id=toc:sec:wireless-debugging>Wireless\nDebugging</a></span><ul class=incremental><li><span><span class=toc-section-number>3.2.1</span> <a href=#subsec:enable-developer-options-and-usb-debugging id=toc:subsec:enable-developer-options-and-usb-debugging>Enable\ndeveloper options and USB Debugging</a></span><li><span><span class=toc-section-number>3.2.2</span> <a href=#subsec:enable-wireless-debugging id=toc:subsec:enable-wireless-debugging>Enable Wireless\nDebugging</a></span><li><span><span class=toc-section-number>3.2.3</span> <a href=#subsec:pair-adb-with-app-manager id=toc:subsec:pair-adb-with-app-manager>Pair ADB with App\nManager</a></span><li><span><span class=toc-section-number>3.2.4</span> <a href=#subsec:connect-app-manager-to-adb id=toc:subsec:connect-app-manager-to-adb>Connect App Manager to\nADB</a></span></ul><li><span><span class=toc-section-number>3.3</span> <a href=#sec:backup-restore id=toc:sec:backup-restore>Back\nup/Restore</a></span><ul class=incremental><li><span><span class=toc-section-number>3.3.1</span> <a href=#subsec:backup-location id=toc:subsec:backup-location>Location</a></span><li><span><span class=toc-section-number>3.3.2</span> <a href=#subsec:backup-restore-backup-options id=toc:subsec:backup-restore-backup-options>Backup\nOptions</a></span><li><span><span class=toc-section-number>3.3.3</span> <a href=#subsec:backup-restore-backup id=toc:subsec:backup-restore-backup>Sicherung</a></span><li><span><span class=toc-section-number>3.3.4</span> <a href=#subsec:backup-restore-restore id=toc:subsec:backup-restore-restore>Wiederherstellung</a></span><li><span><span class=toc-section-number>3.3.5</span> <a href=#subsec:backup-restore-delete-backup id=toc:subsec:backup-restore-delete-backup>Sicherung\nlöschen</a></span></ul><li><span><span class=toc-section-number>3.4</span> <a href=#sec:automating-tasks id=toc:sec:automating-tasks>Automating\nTasks</a></span><ul class=incremental><li><span><span class=toc-section-number>3.4.1</span> <a href=#subsec:generating-authorization-key id=toc:subsec:generating-authorization-key>Generating authorization\nkey</a></span><li><span><span class=toc-section-number>3.4.2</span> <a href=#subsec:at:general-configuration id=toc:subsec:at:general-configuration>Configuring\ntasks</a></span><li><span><span class=toc-section-number>3.4.3</span> <a href=#subsec:at:features id=toc:subsec:at:features>Features</a></span><li><span><span class=toc-section-number>3.4.4</span> <a href=#subsec:triggering-a-profile id=toc:subsec:triggering-a-profile>Triggering a\nprofile</a></span></ul><li><span><span class=toc-section-number>3.5</span> <a href=#sec:net-policy id=toc:sec:net-policy>Net\nPolicy</a></span></ul><li><span><span class=toc-section-number>4</span> <a href=#ch:faq id=toc:ch:faq>Frequently Asked Questions</a></span><ul class=incremental><li><span><span class=toc-section-number>4.1</span> <a href=#sec:faq:app-components id=toc:sec:faq:app-components>App\nComponents</a></span><ul class=incremental><li><span><span class=toc-section-number>4.1.1</span> <a href=#subsec:faq:what-are-app-components id=toc:subsec:faq:what-are-app-components>What are the application\ncomponents?</a></span><li><span><span class=toc-section-number>4.1.2</span> <a href=#subsec:faq:how-components-blocked id=toc:subsec:faq:how-components-blocked>How are the tracker and other\ncomponents blocked in App Manager? What are its\nlimitations?</a></span><li><span><span class=toc-section-number>4.1.3</span> <a href=#subsec:faq:components-blocked-by-others id=toc:subsec:faq:components-blocked-by-others>Does app components\nblocked by other tools retained in App Manager?</a></span><li><span><span class=toc-section-number>4.1.4</span> <a href=#subsec:faq:components-reblocked-in-am id=toc:subsec:faq:components-reblocked-in-am>What happens to the\ncomponents blocked by App Manager which were previously blocked by other\ntools?</a></span><li><span><span class=toc-section-number>4.1.5</span> <a href=#subsec:faq:what-is-instant-component-blocking id=toc:subsec:faq:what-is-instant-component-blocking>What is instant\ncomponent blocking?</a></span><li><span><span class=toc-section-number>4.1.6</span> <a href=#subsec:tracker-classes-versus-tracker-components id=toc:subsec:tracker-classes-versus-tracker-components>Tracker\nclasses versus tracker components</a></span></ul><li><span><span class=toc-section-number>4.2</span> <a href=#sec:faq:adb-over-tcp id=toc:sec:faq:adb-over-tcp>ADB over\nTCP</a></span><ul class=incremental><li><span><span class=toc-section-number>4.2.1</span> <a href=#subsec:faq:enable-adb-on-every-restart id=toc:subsec:faq:enable-adb-on-every-restart>Do I have to enable ADB\nover TCP everytime I restart?</a></span><li><span><span class=toc-section-number>4.2.2</span> <a href=#subsec:faq:usb-debugging id=toc:subsec:faq:usb-debugging>Cannot enable USB debugging. What to\ndo?</a></span><li><span><span class=toc-section-number>4.2.3</span> <a href=#subsec:faq:block-components-using-adb id=toc:subsec:faq:block-components-using-adb>Can I block tracker or\nany other application components using ADB over TCP?</a></span><li><span><span class=toc-section-number>4.2.4</span> <a href=#subsec:faq:adb-features id=toc:subsec:faq:adb-features>Which\nfeatures can be used in ADB mode?</a></span></ul><li><span><span class=toc-section-number>4.3</span> <a href=#sec:faq:miscellanea id=toc:sec:faq:miscellanea>Sonstiges</a></span><ul class=incremental><li><span><span class=toc-section-number>4.3.1</span> <a href=#subsec:faq:no-root-no-harms id=toc:subsec:faq:no-root-no-harms>Ich verwende kein root/ADB. Bin ich\nvöllig vor irgendwelchen Schäden sicher?</a></span><li><span><span class=toc-section-number>4.3.2</span> <a href=#subsec:faq:how-trackers-libs-updated id=toc:subsec:faq:how-trackers-libs-updated>Wie werden die Tracker und\nBibliotheken aktualisiert?</a></span><li><span><span class=toc-section-number>4.3.3</span> <a href=#subsec:faq:apks-deleted-after-installed id=toc:subsec:faq:apks-deleted-after-installed>Are APKs deleted after\ninstalled?</a></span><li><span><span class=toc-section-number>4.3.4</span> <a href=#subsec:faq:shizuku-support id=toc:subsec:faq:shizuku-support>Gibt es Pläne für\nShizuku?</a></span><li><span><span class=toc-section-number>4.3.5</span> <a href=#subsec:faq:what-are-bloatware id=toc:subsec:faq:what-are-bloatware>Was ist Bloatware und wie kann\nman sie entfernen?</a></span></ul></ul><li><span><span class=toc-section-number>5</span> <a href=#ch:specifications id=toc:ch:specifications>Spezifikationen</a></span><ul class=incremental><li><span><span class=toc-section-number>5.1</span> <a href=#sec:rules-specification id=toc:sec:rules-specification>Regeln\nSpezifikationen</a></span><ul class=incremental><li><span><span class=toc-section-number>5.1.1</span> <a href=#hintergrund id=toc:hintergrund>Hintergrund</a></span><li><span><span class=toc-section-number>5.1.2</span> <a href=#regeln-dateiformat id=toc:regeln-dateiformat>Regeln\nDateiformat</a></span></ul></ul><li><span><span class=toc-section-number>6</span> <a href=#ch:changelogs id=toc:ch:changelogs>Änderungsprotokolle</a></span><ul class=incremental><li><span><span class=toc-section-number>6.1</span> <a href=#sec:v4.0.5-(445) id=toc:sec:v4.0.5-(445)>v4.0.5\n(445)</a></span><li><span><span class=toc-section-number>6.2</span> <a href=#sec:v4.0.4-(444) id=toc:sec:v4.0.4-(444)>v4.0.4\n(444)</a></span><li><span><span class=toc-section-number>6.3</span> <a href=#sec:v4.0.3-(443) id=toc:sec:v4.0.3-(443)>v4.0.3\n(443)</a></span><li><span><span class=toc-section-number>6.4</span> <a href=#sec:v4.0.2-(442) id=toc:sec:v4.0.2-(442)>v4.0.2\n(442)</a></span><li><span><span class=toc-section-number>6.5</span> <a href=#sec:v4.0.1-(441) id=toc:sec:v4.0.1-(441)>v4.0.1\n(441)</a></span><ul class=incremental><li><span><span class=toc-section-number>6.5.1</span> <a href=#overlay-management id=toc:overlay-management>Overlay\nmanagement</a></span><li><span><span class=toc-section-number>6.5.2</span> <a href=#unfreeze-option-in-activity-shortcuts id=toc:unfreeze-option-in-activity-shortcuts>Unfreeze option in\nactivity shortcuts</a></span><li><span><span class=toc-section-number>6.5.3</span> <a href=#market-like-url-support id=toc:market-like-url-support><code>market</code>-like URL\nsupport</a></span><li><span><span class=toc-section-number>6.5.4</span> <a href=#updated-color-codes id=toc:updated-color-codes>Updated color\ncodes</a></span><li><span><span class=toc-section-number>6.5.5</span> <a href=#others id=toc:others>Others</a></span></ul><li><span><span class=toc-section-number>6.6</span> <a href=#sec:v4.0.0-(440) id=toc:sec:v4.0.0-(440)>v4.0.0\n(440)</a></span><ul class=incremental><li><span><span class=toc-section-number>6.6.1</span> <a href=#new-logo id=toc:new-logo>New logo!</a></span><li><span><span class=toc-section-number>6.6.2</span> <a href=#android-14-and-15-support id=toc:android-14-and-15-support>Android 14 and 15\nsupport</a></span><li><span><span class=toc-section-number>6.6.3</span> <a href=#revamped-debloater id=toc:revamped-debloater>Revamped\ndebloater</a></span><li><span><span class=toc-section-number>6.6.4</span> <a href=#introducing-file-manager id=toc:introducing-file-manager>Introducing file\nmanager</a></span><li><span><span class=toc-section-number>6.6.5</span> <a href=#integrated-code-editor id=toc:integrated-code-editor>Integrated code editor</a></span><li><span><span class=toc-section-number>6.6.6</span> <a href=#history-of-operations id=toc:history-of-operations>History of\noperations</a></span><li><span><span class=toc-section-number>6.6.7</span> <a href=#per-app-freezing-and-more id=toc:per-app-freezing-and-more>Per-app freezing, and\nmore</a></span><li><span><span class=toc-section-number>6.6.8</span> <a href=#log-viewer-enhancements id=toc:log-viewer-enhancements>Log\nviewer enhancements</a></span><li><span><span class=toc-section-number>6.6.9</span> <a href=#launching-non-exported-activities id=toc:launching-non-exported-activities>Launching non-exported\nactivities</a></span><li><span><span class=toc-section-number>6.6.10</span> <a href=#new-tags-in-app-info-tab id=toc:new-tags-in-app-info-tab>New\ntags in App Info tab</a></span><li><span><span class=toc-section-number>6.6.11</span> <a href=#per-session-installer-options id=toc:per-session-installer-options>Per-session installer\noptions</a></span><li><span><span class=toc-section-number>6.6.12</span> <a href=#advanced-mode-of-operations-adb-enhancements id=toc:advanced-mode-of-operations-adb-enhancements>Advanced mode of\noperations, ADB enhancements, …</a></span><li><span><span class=toc-section-number>6.6.13</span> <a href=#data-usage-widget-and-more id=toc:data-usage-widget-and-more>Data usage widget, and\nmore</a></span><li><span><span class=toc-section-number>6.6.14</span> <a href=#others-1 id=toc:others-1>Others</a></span></ul><li><span><span class=toc-section-number>6.7</span> <a href=#sec:v3.1.0-(423) id=toc:sec:v3.1.0-(423)>v3.1.0\n(423)</a></span><ul class=incremental><li><span><span class=toc-section-number>6.7.1</span> <a href=#android-13-support id=toc:android-13-support>Android 13\nsupport</a></span><li><span><span class=toc-section-number>6.7.2</span> <a href=#introducing-freezeunfreeze id=toc:introducing-freezeunfreeze>Introducing\nfreeze/unfreeze</a></span><li><span><span class=toc-section-number>6.7.3</span> <a href=#export-app-list id=toc:export-app-list>Export app\nlist</a></span><li><span><span class=toc-section-number>6.7.4</span> <a href=#elliptic-curve-crypography-ecc id=toc:elliptic-curve-crypography-ecc>Elliptic Curve Crypography\n(ECC)</a></span><li><span><span class=toc-section-number>6.7.5</span> <a href=#new-languages id=toc:new-languages>New\nlanguages</a></span><li><span><span class=toc-section-number>6.7.6</span> <a href=#more-list-options id=toc:more-list-options>More list\noptions</a></span><li><span><span class=toc-section-number>6.7.7</span> <a href=#improved-handling-of-mode-of-operation id=toc:improved-handling-of-mode-of-operation>Improved handling of\nmode of operation</a></span><li><span><span class=toc-section-number>6.7.8</span> <a href=#handling-multiple-users id=toc:handling-multiple-users>Handling multiple users</a></span><li><span><span class=toc-section-number>6.7.9</span> <a href=#explorer-enhancements id=toc:explorer-enhancements>Explorer\nenhancements</a></span><li><span><span class=toc-section-number>6.7.10</span> <a href=#new-tag-wx id=toc:new-tag-wx>New tag: WX</a></span><li><span><span class=toc-section-number>6.7.11</span> <a href=#app-ops-management id=toc:app-ops-management>App ops\nmanagement</a></span><li><span><span class=toc-section-number>6.7.12</span> <a href=#batch-uninstallation id=toc:batch-uninstallation>Batch\nuninstallation</a></span><li><span><span class=toc-section-number>6.7.13</span> <a href=#running-apps id=toc:running-apps>Running apps</a></span><li><span><span class=toc-section-number>6.7.14</span> <a href=#interceptor id=toc:interceptor>Interceptor</a></span><li><span><span class=toc-section-number>6.7.15</span> <a href=#device-specific-changes id=toc:device-specific-changes>Device-specific changes</a></span><li><span><span class=toc-section-number>6.7.16</span> <a href=#others-2 id=toc:others-2>Others</a></span></ul><li><span><span class=toc-section-number>6.8</span> <a href=#sec:v3.0.0-(410) id=toc:sec:v3.0.0-(410)>v3.0.0\n(410)</a></span><ul class=incremental><li><span><span class=toc-section-number>6.8.1</span> <a href=#material-3-and-more id=toc:material-3-and-more>Material 3 and\nMore</a></span><li><span><span class=toc-section-number>6.8.2</span> <a href=#wireless-debugging id=toc:wireless-debugging>Wireless\nDebugging</a></span><li><span><span class=toc-section-number>6.8.3</span> <a href=#languages id=toc:languages>Languages</a></span><li><span><span class=toc-section-number>6.8.4</span> <a href=#introducing-app-explorer id=toc:introducing-app-explorer>Introducing App\nExplorer</a></span><li><span><span class=toc-section-number>6.8.5</span> <a href=#import-backups-from-other-applications id=toc:import-backups-from-other-applications>Import Backups from\nOther Applications</a></span><li><span><span class=toc-section-number>6.8.6</span> <a href=#virustotal id=toc:virustotal>VirusTotal</a></span><li><span><span class=toc-section-number>6.8.7</span> <a href=#trigger-profiles-from-the-automation-software id=toc:trigger-profiles-from-the-automation-software>Trigger Profiles\nfrom the Automation Software</a></span><li><span><span class=toc-section-number>6.8.8</span> <a href=#improved-application-installer id=toc:improved-application-installer>Improved Application\nInstaller</a></span><li><span><span class=toc-section-number>6.8.9</span> <a href=#component-blocking id=toc:component-blocking>Component\nBlocking</a></span><li><span><span class=toc-section-number>6.8.10</span> <a href=#advanced-searching id=toc:advanced-searching>Advanced\nSearching</a></span><li><span><span class=toc-section-number>6.8.11</span> <a href=#shared-libraries id=toc:shared-libraries>Shared\nLibraries</a></span><li><span><span class=toc-section-number>6.8.12</span> <a href=#make-the-best-use-of-interceptor id=toc:make-the-best-use-of-interceptor>Make the Best Use of\nInterceptor</a></span><li><span><span class=toc-section-number>6.8.13</span> <a href=#widget-screen-time id=toc:widget-screen-time>Widget: Screen\nTime</a></span><li><span><span class=toc-section-number>6.8.14</span> <a href=#widget-clear-cache id=toc:widget-clear-cache>Widget: Clear\nCache</a></span></ul><li><span><span class=toc-section-number>6.9</span> <a href=#sec:v2.6.0-(385) id=toc:sec:v2.6.0-(385)>v2.6.0\n(385)</a></span><ul class=incremental><li><span><span class=toc-section-number>6.9.1</span> <a href=#introducing-backups id=toc:introducing-backups>Introducing\nBackups</a></span><li><span><span class=toc-section-number>6.9.2</span> <a href=#introducing-log-viewer id=toc:introducing-log-viewer>Introducing Log Viewer</a></span><li><span><span class=toc-section-number>6.9.3</span> <a href=#lock-app-manager id=toc:lock-app-manager>Lock App\nManager</a></span><li><span><span class=toc-section-number>6.9.4</span> <a href=#extended-modes-for-app-ops id=toc:extended-modes-for-app-ops>Extended Modes for App\nOps</a></span><li><span><span class=toc-section-number>6.9.5</span> <a href=#new-batch-ops-add-to-profile id=toc:new-batch-ops-add-to-profile>New Batch Ops: Add to\nProfile</a></span><li><span><span class=toc-section-number>6.9.6</span> <a href=#app-info-improved id=toc:app-info-improved>App Info:\nImproved</a></span><li><span><span class=toc-section-number>6.9.7</span> <a href=#advanced-sort-and-filtering-options-in-the-main-page id=toc:advanced-sort-and-filtering-options-in-the-main-page>Advanced\nSort and Filtering Options in the Main Page</a></span><li><span><span class=toc-section-number>6.9.8</span> <a href=#about-this-device id=toc:about-this-device>About This\nDevice</a></span><li><span><span class=toc-section-number>6.9.9</span> <a href=#enabledisable-features id=toc:enabledisable-features>Enable/disable Features</a></span><li><span><span class=toc-section-number>6.9.10</span> <a href=#new-languages-1 id=toc:new-languages-1>New\nLanguages</a></span><li><span><span class=toc-section-number>6.9.11</span> <a href=#signing-the-apk-files id=toc:signing-the-apk-files>Signing the\nAPK Files</a></span><li><span><span class=toc-section-number>6.9.12</span> <a href=#new-extension-unapkm id=toc:new-extension-unapkm>New\nExtension: UnAPKM</a></span></ul><li><span><span class=toc-section-number>6.10</span> <a href=#sec:v2.5.20-(375) id=toc:sec:v2.5.20-(375)>v2.5.20\n(375)</a></span><ul class=incremental><li><span><span class=toc-section-number>6.10.1</span> <a href=#subsec:introducing-profiles id=toc:subsec:introducing-profiles>Introducing\nProfiles</a></span><li><span><span class=toc-section-number>6.10.2</span> <a href=#subsec:the-interceptor id=toc:subsec:the-interceptor>The\nInterceptor</a></span><li><span><span class=toc-section-number>6.10.3</span> <a href=#subsec:unapkm:-dedrm-the-apkm-files id=toc:subsec:unapkm:-dedrm-the-apkm-files>UnAPKM: DeDRM the APKM\nfiles</a></span><li><span><span class=toc-section-number>6.10.4</span> <a href=#subsec:multiple-user id=toc:subsec:multiple-user>Multiple\nuser</a></span><li><span><span class=toc-section-number>6.10.5</span> <a href=#vive-la-france id=toc:vive-la-france>Vive la\nFrance!</a></span><li><span><span class=toc-section-number>6.10.6</span> <a href=#report-crashes id=toc:report-crashes>Report\ncrashes</a></span><li><span><span class=toc-section-number>6.10.7</span> <a href=#android-11 id=toc:android-11>Android 11</a></span><li><span><span class=toc-section-number>6.10.8</span> <a href=#app-installer-improvements id=toc:app-installer-improvements>App Installer\nImprovements</a></span></ul><li><span><span class=toc-section-number>6.11</span> <a href=#v2.5.17-368 id=toc:v2.5.17-368>v2.5.17 (368)</a></span><ul class=incremental><li><span><span class=toc-section-number>6.11.1</span> <a href=#app-installer id=toc:app-installer>App\nInstaller</a></span><li><span><span class=toc-section-number>6.11.2</span> <a href=#scanner-replacement-for-exodus-page id=toc:scanner-replacement-for-exodus-page>Scanner: Replacement for\nExodus Page</a></span><li><span><span class=toc-section-number>6.11.3</span> <a href=#introducing-system-config id=toc:introducing-system-config>Introducing System\nConfig</a></span><li><span><span class=toc-section-number>6.11.4</span> <a href=#more-languages id=toc:more-languages>More\nLanguages</a></span><li><span><span class=toc-section-number>6.11.5</span> <a href=#app-info-tab id=toc:app-info-tab>App Info Tab</a></span><li><span><span class=toc-section-number>6.11.6</span> <a href=#navigation-improvements id=toc:navigation-improvements>Navigation Improvements</a></span><li><span><span class=toc-section-number>6.11.7</span> <a href=#running-apps-page id=toc:running-apps-page>Running Apps\nPage</a></span><li><span><span class=toc-section-number>6.11.8</span> <a href=#built-in-toybox id=toc:built-in-toybox>Built-in\nToybox</a></span><li><span><span class=toc-section-number>6.11.9</span> <a href=#component-blocker-improvements id=toc:component-blocker-improvements>Component Blocker\nImprovements</a></span><li><span><span class=toc-section-number>6.11.10</span> <a href=#improvements-in-the-app-details-page id=toc:improvements-in-the-app-details-page>Improvements in the App\nDetails Page</a></span><li><span><span class=toc-section-number>6.11.11</span> <a href=#app-manifest id=toc:app-manifest>App Manifest</a></span></ul><li><span><span class=toc-section-number>6.12</span> <a href=#v2.5.13-348 id=toc:v2.5.13-348>v2.5.13 (348)</a></span><ul class=incremental><li><span><span class=toc-section-number>6.12.1</span> <a href=#bundled-app-split-apk id=toc:bundled-app-split-apk>Bundled App\n(Split APK)</a></span><li><span><span class=toc-section-number>6.12.2</span> <a href=#direct-install-support id=toc:direct-install-support>Direct\nInstall Support</a></span><li><span><span class=toc-section-number>6.12.3</span> <a href=#remove-all-blocking-rules id=toc:remove-all-blocking-rules>Remove All Blocking\nRules</a></span><li><span><span class=toc-section-number>6.12.4</span> <a href=#app-ops id=toc:app-ops>App Ops</a></span><li><span><span class=toc-section-number>6.12.5</span> <a href=#enhanced-adb-support id=toc:enhanced-adb-support>Enhanced ADB\nSupport</a></span><li><span><span class=toc-section-number>6.12.6</span> <a href=#filtering-in-main-page id=toc:filtering-in-main-page>Filtering\nin Main Page</a></span><li><span><span class=toc-section-number>6.12.7</span> <a href=#apk-backupsharing id=toc:apk-backupsharing>Apk\nBackup/Sharing</a></span><li><span><span class=toc-section-number>6.12.8</span> <a href=#batch-ops id=toc:batch-ops>Batch Ops</a></span><li><span><span class=toc-section-number>6.12.9</span> <a href=#translations id=toc:translations>Translations</a></span><li><span><span class=toc-section-number>6.12.10</span> <a href=#app-data-backup id=toc:app-data-backup>App Data\nBackup</a></span></ul></ul><li><span><span class=toc-section-number>7</span> <a href=#ch:app-ops id=toc:ch:app-ops>App Ops</a></span><ul class=incremental><li><span><span class=toc-section-number>7.1</span> <a href=#sec:app-ops-background id=toc:sec:app-ops-background>Background</a></span><li><span><span class=toc-section-number>7.2</span> <a href=#sec:introduction-to-app-ops id=toc:sec:introduction-to-app-ops>Introduction to App\nOps</a></span><li><span><span class=toc-section-number>7.3</span> <a href=#sec:appopsmanager id=toc:sec:appopsmanager>AppOpsManager</a></span><ul class=incremental><li><span><span class=toc-section-number>7.3.1</span> <a href=#subsec:op-constants id=toc:subsec:op-constants><code>OP_*</code> Constants</a></span><li><span><span class=toc-section-number>7.3.2</span> <a href=#subsec:mode-constants id=toc:subsec:mode-constants><code>MODE_*</code>\nConstants</a></span><li><span><span class=toc-section-number>7.3.3</span> <a href=#subsec:package-ops id=toc:subsec:package-ops>PackageOps</a></span><li><span><span class=toc-section-number>7.3.4</span> <a href=#subsec:opentry id=toc:subsec:opentry>OpEntry</a></span><li><span><span class=toc-section-number>7.3.5</span> <a href=#subsec:usage id=toc:subsec:usage>Usage</a></span></ul><li><span><span class=toc-section-number>7.4</span> <a href=#sec:appopsservice id=toc:sec:appopsservice>AppOpsService</a></span><li><span><span class=toc-section-number>7.5</span> <a href=#sec:appops-xml id=toc:sec:appops-xml>appops.xml</a></span><li><span><span class=toc-section-number>7.6</span> <a href=#sec:appops-cli id=toc:sec:appops-cli>Command Line\nInterface</a></span></ul></ul></nav><div class=titlingpage><div class=center><p><img src=../images/icon.png style=width:1in alt=image><p><strong><span class=smallcaps>App Manager</span></strong><p><strong>Nutzerhandbuch</strong><p><em>v4.0.5</em><p>27 Juli 2025<p>Copyright © 2020–2025 Muntashir Al-Islam<blockquote><p>“Weise und langsam. Wer schnell läuft, der stolpert.” <span>— Bruder\nLorenz, <em>Romeo und Julia</em></span></blockquote></div></div><section id=ch:introduction class=level1 data-number=1><h1 data-number=1><span class=header-section-number>1</span> <a href=#toc:ch:introduction>Einleitung</a><a href=#ch:introduction class=anchor aria-hidden=true></a></h1><p>App Manager ist ein fortschrittlicher Paketmanager für Android. Er\nbietet zahllose Funktionen und benötigt daher ein Benutzer- handbuch, um\nseine Benutzer zu unterstützen. Dieses Dokument fungiert als\nBenutzerhandbuch für App Manager in dem Sinne, dass es darauf abzielt,\njede Funktion zu beschreiben, die App Manager zu bieten hat. Dieses\nDokument kann auch als “offizieller” Leitfaden für App Manager\nbetrachtet werden und stellt das erwartete Verhalten von App Manager\ndar. Übersetzungen können dieses Dokument (das in Englisch verfasst ist)\nfalsch interpretieren. Daher sollte jeder befähigte Benutzer die\nenglische Version des Dokuments lesen, um das Beste aus dem App Manager\nherauszuholen. Es kann auch andere inoffizielle oder\nDrittanbieter-Ressourcen wie Blog-Artikel, Videos, Chat- Gruppen usw.\ngeben. Diese Ressourcen können zwar für viele Menschen nützlich sein,\nsind aber möglicherweise nicht auf dem neuesten Stand der aktuellen\nVersion von App Manager. Wenn in App Manager Abweichungen von diesem\nDokument festgestellt werden, sollten diese im <a href=https://github.com/MuntashirAkon/AppManager/issues>App Manager\nProblembehandlung</a> gemeldet werden.<section id=sec:terminologies class=level2 data-number=1.1><h2 data-number=1.1><span class=header-section-number>1.1</span> <a href=#toc:sec:terminologies>Fachbegriffe</a><a href=#sec:terminologies class=anchor aria-hidden=true></a></h2><ul class=incremental><li><p><strong>AM</strong> — Kurzbezeichnung für App Manager.<li><p><strong>Blockieren/Entsperren</strong> — Dient zum Sperren oder\nEntsperren von Komponenten. Wie Komponenten blockiert werden, hängt von\nden Benutzereinstellungen ab.<li><p><strong>IFW</strong> — Kurzform für Intent Firewall.<li><p><strong>Ops</strong> — Kurzbezeichnung für Maßnahmen, e.g. app\nops, batch ops, 1-click ops<li><p><strong>SSAID</strong> — Kurzbezeichnung von\n<code>Settings.Secure.Android_ID</code>. Es ist eine Gerätekennung, die\njeder App zugewiesen wird (ab Android Oreo). Sie wird aus der\nKombination des Signierzertifikats der App und der SSAID, die für das\nPaket <code>Android</code> festgelegt wurde. Daher ist sie für eine App\ngarantiert gleich, so lange der Benutzer das Gerät nicht formatiert. Sie\nwird häufig für die Nachverfolgung verwendet.<li><p><strong>Tracker</strong> — Bezeichnet Tracker-Komponenten im\ngesamten Dokument und im App Manager, außer in der <a href=#sec:scanner-page>Scanner-Seite</a>. Tracker umfassen\nBibliotheken wie Crash Reporter, Analytik, Profilerstellung,\nIdentifizierung, Anzeige, Standort usw. Daher sind sie in ihren\nFunktionen nicht gleich. Es gibt keine Unterscheidung oder\nVoreingenommenheit zwischen Open-Source- und Closed-Source-Bibliotheken,\ndie Tracking fördern.</ul></section><section id=sec:supported-versions class=level2 data-number=1.2><h2 data-number=1.2><span class=header-section-number>1.2</span> <a href=#toc:sec:supported-versions>Unterstützte Versionen</a><a href=#sec:supported-versions class=anchor aria-hidden=true></a></h2><p>Derzeit werden die Versionen v3.0.0 – v3.0.3 (stable) und v3.1.0\n(alpha und Debug Versionen) unterstützt. Frühere Versionen von App\nManager können Sicherheitslücken enthalten und sollten nicht verwendet\nwerden.</section><section id=sec:official-sources class=level2 data-number=1.3><h2 data-number=1.3><span class=header-section-number>1.3</span> <a href=#toc:sec:official-sources>Offizielle Quellen</a><a href=#sec:official-sources class=anchor aria-hidden=true></a></h2><section id=subsec:binary-distribution-sources class=level3 data-number=1.3.1><h3 data-number=1.3.1><span class=header-section-number>1.3.1</span>\n<a href=#toc:subsec:binary-distribution-sources>Quellen der binären\nVerteilung</a><a href=#subsec:binary-distribution-sources class=anchor aria-hidden=true></a></h3><p>App Manager wird über die folgenden Quellen verbreitet. Inoffizielle\nQuellen können modifizierte Versionen von App Manager vertreiben, und\nniemand außer Ihnen ist für die Folgen der Verwendung solcher\nDistributionen verantwortlich.<ol class=incremental><li><p>Offizielles F-Droid-Repository.<a href=#fn1 class=footnote-ref id=fnref1 role=doc-noteref><sup>1</sup></a><br><em>Link:</em> <a href=https://f-droid.org/packages/io.github.muntashirakon.AppManager class=uri>https://f-droid.org/packages/io.github.muntashirakon.AppManager</a><li><p>GitHub Repository.<br><em>Normale Veröffentlichungen:</em> <a href=https://github.com/MuntashirAkon/AppManager/releases class=uri>https://github.com/MuntashirAkon/AppManager/releases</a><br><em>Debug-Versionen:</em> <a href=https://github.com/MuntashirAkon/AppManager/actions class=uri>https://github.com/MuntashirAkon/AppManager/actions</a><li><p>Telegram.<br><em>Normale Veröffentlichungen:</em> <a href=https://t.me/AppManagerChannel class=uri>https://t.me/AppManagerChannel</a><br><em>Debug-Versionen:</em> <a href=https://t.me/AppManagerDebug class=uri>https://t.me/AppManagerDebug</a></ol></section><section id=subsec:links-to-source-code class=level3 data-number=1.3.2><h3 data-number=1.3.2><span class=header-section-number>1.3.2</span>\n<a href=#toc:subsec:links-to-source-code>Links zum Quellcode</a><a href=#subsec:links-to-source-code class=anchor aria-hidden=true></a></h3><p>Alle außer GitHub sind die Spiegel-Links. Die Tags sollten immer auf\ndem neuesten Stand sein, aber beim Master-Zweig ist nicht garantiert,\ndass er aktuell zu sein. Wenn das Ziel ist, den Master-Zweig zu klonen,\nverwenden Sie den GitHub-Link statt der anderen.<ol class=incremental><li><p>GitHub: <a href=https://github.com/MuntashirAkon/AppManager class=uri>https://github.com/MuntashirAkon/AppManager</a><li><p>Codeberg: <a href=https://codeberg.org/muntashir/AppManager class=uri>https://codeberg.org/muntashir/AppManager</a><li><p>GitLab: <a href=https://gitlab.com/muntashir/AppManager class=uri>https://gitlab.com/muntashir/AppManager</a><li><p>Riseup: <a href=https://0xacab.org/muntashir/AppManager class=uri>https://0xacab.org/muntashir/AppManager</a><li><p>sourcehut: <a href=https://git.sr.ht/~muntashir/AppManager class=uri>https://git.sr.ht/~muntashir/AppManager</a></ol></section><section id=subsec:translations class=level3 data-number=1.3.3><h3 data-number=1.3.3><span class=header-section-number>1.3.3</span>\n<a href=#toc:subsec:translations>Übersetzungen</a><a href=#subsec:translations class=anchor aria-hidden=true></a></h3><p>App Manager akzeptiert keine Übersetzungen direkt über\nPull-/Merge-Anfragen. Übersetzungen werden automatisiert über Weblate\nrealisiert. Um dem Übersetzungsteam beizutreten, besuchen Sie <a href=https://hosted.weblate.org/engage/app-manager/ class=uri>https://hosted.weblate.org/engage/app-manager/</a>.</section></section><section id=sec:contributing class=level2 data-number=1.4><h2 data-number=1.4><span class=header-section-number>1.4</span> <a href=#toc:sec:contributing>Mitwirkende</a><a href=#sec:contributing class=anchor aria-hidden=true></a></h2><p>Es gibt mehrere Möglichkeiten, wie ein Benutzer einen Beitrag leisten\nkann, z. B. durch das Erstellen hilfreicher Fragen, die Teilnahme an\nDiskussionen, die Verbesserung von Dokumentationen und Übersetzungen,\ndas Hinzufügen unbekannter Bibliotheken oder Tracker, die Überprüfung\ndes Quellcodes sowie die Meldung von Sicherheitslücken.<section id=subsec:build-instructions class=level3 data-number=1.4.1><h3 data-number=1.4.1><span class=header-section-number>1.4.1</span>\n<a href=#toc:subsec:build-instructions>Hinweise zur Erstellung</a><a href=#subsec:build-instructions class=anchor aria-hidden=true></a></h3><p>Bauanleitungen finden Sie in der Datei BUILDING, die sich im\nStammverzeichnis des Quellcodes befindet.</section><section id=subsec:submitting-patches class=level3 data-number=1.4.2><h3 data-number=1.4.2><span class=header-section-number>1.4.2</span>\n<a href=#toc:subsec:submitting-patches>Einreichen von Patches</a><a href=#subsec:submitting-patches class=anchor aria-hidden=true></a></h3><p>Repositories, die sich an anderen Orten als GitHub befinden, werden\nderzeit als Spiegel betrachtet. Pull-/Merge-Anfragen, die an diesen\nOrten eingereicht wurden, werden nicht akzeptiert.<a href=#fn2 class=footnote-ref id=fnref2 role=doc-noteref><sup>2</sup></a>\nStattdessen können Patches (als <code>.patch-</code> Dateien) über\nE-Mail-Anhänge eingereicht werden. <em>Die Signierung ist eine\nVoraussetzung.</em> Weitere Informationen finden Sie in der Datei\nCONTRIBUTING, die sich im Stammverzeichnis des Quellcodes befindet.<div class=\"amalert warning\"><p><strong><em>Hinweis:</em></strong><p>Wenn Sie Patches per E-Mail einreichen, kann die gesamte Konversation\nin Zukunft öffentlich zugänglich sein. Daher sollten Sie keine\npersönlich identifizierbaren Informationen (PII) außer Ihrem Namen oder\nIhrer E-Mail-Adresse aufführen.</div></section></section><section id=sec:donation-&-funding class=level2 data-number=1.5><h2 data-number=1.5><span class=header-section-number>1.5</span> <a href=#toc:sec:donation-&-funding>Spende & Förderung</a><a href=#sec:donation-&-funding class=anchor aria-hidden=true></a></h2><p><em>Eine Spende oder ein Kauf ist keine Voraussetzung für die Nutzung\nvon App Manager.</em> App Manager unterstützt zwar keine Käufe, es\nkönnen aber Spenden über Open Source Collective an den Entwickler von\nApp Manager gesendet werden.<p>Open Source Collective ist ein Finanzdienstleister auf der Open\nCollective-Plattform, der Open-Source-Projekten bei der Verwaltung ihre\nFinanzen. Derzeit werden Zahlungen per Bankkonten, PayPal, Kredit- oder\nDebitkarten und Kryptowährungen unterstützt.<p><em>Link:</em> <a href=https://opencollective.com/muntashir class=uri>https://opencollective.com/muntashir</a>.<p>Mit der Überweisung von Spenden stimmen die Absender zu, dass sie die\nSpenden nicht als Druckmittel verwenden, um die von ihnen gewünschten\nFunktionen zu priorisieren. Für Feature-Anfragen sind keine Belohnungen\noder Spenden erforderlich, und sie werden nach den Präferenzen des\nEntwicklers priorisiert.<p><em>App-Manager nimmt alle Angebote für Finanzierungen oder Zuschüsse\nan.</em> Vertreter der interessierten Organisation können direkt den\nEntwickler über die in §<a href=#sec:Ansprechpartner data-reference-type=ref data-reference=sec:Ansprechpartner>[sec:Ansprechpartner]</a>\nangegebenen Optionen kontaktieren.<p>In addition, the maintainers and contributors of this project DO NOT\nconsent to the creation, sale, or promotion of tokens, cryptocurrencies,\nNFTs, or any other financial instruments that claim to represent this\nproject, its code, or its community. Any such attempts are unauthorized\nand not affiliated with this project in any way.</section><section id=sec:contact class=level2 data-number=1.6><h2 data-number=1.6><span class=header-section-number>1.6</span> <a href=#toc:sec:contact>Ansprechpartner</a><a href=#sec:contact class=anchor aria-hidden=true></a></h2><p>Muntashir Al-Islam<a href=#fn3 class=footnote-ref id=fnref3 role=doc-noteref><sup>3</sup></a><br>Email: <a href=mailto:muntashirakon@riseup.net>muntashirakon [at]\nriseup [dot] net</a><br>Key Fingerprint:\n<code>7bad37c2981e41f8f6abea7f58f0b4f26c346fce</code><br>GitHub: <a href=https://github.com/MuntashirAkon class=uri>https://github.com/MuntashirAkon</a><br>Twitter: <a href=https://twitter.com/Muntashir class=uri>https://twitter.com/Muntashir</a></section></section><section id=ch:pages class=level1 data-number=2><h1 data-number=2><span class=header-section-number>2</span> <a href=#toc:ch:pages>Seiten</a><a href=#ch:pages class=anchor aria-hidden=true></a></h1><section id=sec:main-page class=level2 data-number=2.1><h2 data-number=2.1><span class=header-section-number>2.1</span> <a href=#toc:sec:main-page>Hauptseite</a><a href=#sec:main-page class=anchor aria-hidden=true></a></h2><p>Die Hauptseite listet alle installierten, deinstallierten und\ngesicherten Anwendungen auf. Ein einfacher Klick auf ein installiertes\nAnwendungselement öffnet die entsprechende Seite <a href=#sec:app-details-page>App-Detailseite</a>. Für die\ndeinstallierten Systemanwendungen wird ein Dialogfeld angezeigt, das zur\nNeuinstallation der Anwendung verwendet werden kann. Mit der Option <a href=#par:main-page-sort>Sortierung</a> aus den Listenoptionen können\ndie App-Elemente auf verschiedene Weise sortiert und beim Beenden\nbeibehalten werden. Es ist auch möglich, Elemente zu filtern mit Hilfe\nder <a href=#par:main-page-filter>Filter</a> Option in den\nListenoptionen. Die Filterung ist auch über die Suchleiste mit\nzusätzlicher Unterstützung für reguläre Ausdrücke möglich..<figure id=fig:main_page_entry_info_labeled><figure><object data=../images/main_page_entry_info_labeled.svg type=image/svg+xml></object></figure><figcaption>Figure 1: Ein Menüpunkt der Anwendungsliste auf der\nHauptseite</figcaption></figure><section id=subsec:batch-operations class=level3 data-number=2.1.1><h3 data-number=2.1.1><span class=header-section-number>2.1.1</span>\n<a href=#toc:subsec:batch-operations>Stapelverarbeitung</a><a href=#subsec:batch-operations class=anchor aria-hidden=true></a></h3><p>Auf dieser Seite sind auch Stapeloperationen oder Operationen mit\nmehreren Anwendungen möglich. Der Mehrfachauswahlmodus kann aktiviert\nwerden, indem man auf ein beliebiges Anwendungssymbol klickt oder indem\nman auf ein beliebiges Element in der Liste lange klickt. Einmal\naktiviert, wählt ein einfacher Klick auf ein Listenelement ausgewählt,\nanstatt die Seite mit den Anwendungsdetails zu öffnen. In diesem Modus\nbefinden sich die Stapeloperationen im Mehrfachauswahlmenü unten auf der\nSeite. Zu den Operationen gehören:<ul class=incremental><li><p>Hinzufügen der ausgewählten Anwendungen zu einem <a href=#sec:profiles-page>Profil</a><li><p><a href=#sec:backup-restore>Sicherung, Wiederherstellung oder\nLöschung</a> der Anwendungen<li><p>Blockieren der Tracker für die Anwendungen<li><p>Löschen von Daten oder Cache aus den Anwendungen<li><p>Aktivieren/Deaktivieren/Zwangsstoppen/Deinstallieren der\nAnwendungen<li><p>Exportieren der im App Manager gespeicherten\nBlockierungsregeln<li><p>Verhindern von Hintergrundoperationen der Anwendungen (Android 7\nund höher)<li><p>peichern der APK-Dateien in\n<code>App Manager/apks</code><li><p>Einstellen von <a href=#sec:net-policy>Netzrichtlinien</a></ul><div class=\"amalert tip\"><p><strong><em>Barrierefreiheit:</em></strong><p>Nachdem der Mehrfachauswahlmodus aktiviert wurde, ist es möglich, mit\nder rechten oder linken Taste der Tastatur in das Menü mit der rechten\noder linken Taste der Tastatur oder der Fernbedienung zu navigieren.</div></section><section id=subsec:main-colour-codes class=level3 data-number=2.1.2><h3 data-number=2.1.2><span class=header-section-number>2.1.2</span>\n<a href=#toc:subsec:main-colour-codes>Farbcode</a><a href=#subsec:main-colour-codes class=anchor aria-hidden=true></a></h3><ul class=incremental><li><p><span class=colorbox style=background-color:#fceed1><span style=color:#000>helles gräuliches Orange (Tag)</span></span> /\n<span class=colorbox style=background-color:#091f36><span style=color:#fff>Dunkelblau (Nacht)</span></span> – Die Anwendung\nist für den Batchbetrieb ausgewählt<li><p><span class=colorbox style=background-color:#ff8a80><span style=color:#000>Hellrot (Tag)</span></span> / <span class=colorbox style=background-color:#4f1c14><span style=color:#fff>Dunkelrot (Nacht)</span></span> – Deaktivierte\nAnwendung<li><p><span class=colorbox style=background-color:#ff0><span style=color:#000>Yellow Star</span></span> – Debuggingfähige\nAnwendung<li><p><span style=color:#e05915>Orange <em>Datum</em></span> – Die\nAnwendung hat Zugriff auf die Systemprotokolle<li><p><span style=color:#e05915>Orange <em>UID</em></span> – Die\nBenutzer-ID wird von mehreren Anwendungen gemeinsam genutzt<li><p><span style=color:#e05915>Orange <em>SDK</em></span> – Die\nAnwendung verwendet möglicherweise Klartextverkehr (z. B. HTTP)<li><p><span style=color:red>Rot <em>Paketname</em></span> – Die\nAnwendung erlaubt keine Löschung ihrer Daten<li><p><span style=color:red>Red <em>backup</em></span> – Die\ndeinstallierte Anwendung mit einem oder mehreren Backups, die im App\nManager<li><p><span style=color:#e05915>Orange <em>backup</em></span> –\nVeraltetes Backup, d.h. das Basis-Backup enthält eine ältere Version der\ninstallierten Anwendung<li><p><span style=color:#09868b>Dunkles Cyan\n<em>backup</em></span> – aktuelles Backup, d.h. Basis-Backup enthält die\ngleiche oder höhere Version der installierten Anwendung<li><p><span style=color:#09868b>Dark cyan <em>package\nname</em></span> – Erzwungener Anwendungsstopp<li><p><span style=color:#09868b>Dark cyan <em>version</em></span>\n– Inaktive Anwendung<li><p><span style=color:#f0f>Magenta</span> – Persistente\nAnwendung, d.h. sie bleibt die ganze Zeit über aktiv.</ul></section><section id=subsec:main-page-application-types class=level3 data-number=2.1.3><h3 data-number=2.1.3><span class=header-section-number>2.1.3</span>\n<a href=#toc:subsec:main-page-application-types>Anwendungstypen</a><a href=#subsec:main-page-application-types class=anchor aria-hidden=true></a></h3><p>Eine Anwendung kann entweder eine <strong>Benutzer</strong>- oder\neine <strong>System</strong>-Anwendung mit den folgenden Suffixen\nsein:<ul class=incremental><li><p><code>X</code> – Unterstützt mehrere Architekturen<li><p><code>0</code> – Keine Dex-Dateien in der Anwendung\nvorhanden<li><p>– Unterbrochene Anwendung<li><p><code>#</code> – Die Anwendung hat das System aufgefordert, einen\ngroßen Heap, d. h. großen Laufzeitspeicher, zuzuweisen<li><p><code>?</code> – Die Anwendung forderte die virtuelle Maschine\nauf, in den sicheren Modus zu wechseln.</ul></section><section id=subsec:main-page-version-info class=level3 data-number=2.1.4><h3 data-number=2.1.4><span class=header-section-number>2.1.4</span>\n<a href=#toc:subsec:main-page-version-info>Infos zur Version</a><a href=#subsec:main-page-version-info class=anchor aria-hidden=true></a></h3><p>Auf den Versionsnamen folgen die nachstehenden Präfixe:<ul class=incremental><li><p><code>_</code> – Keine Hardware-Beschleunigung (was die\nIn-App-Animationen oder Transparenzen beeinträchtigt)<li><p><code>~</code> – Reine Testanwendung<li><p><code>debug</code> – Debuggingfähige Anwendung</ul></section><section id=subsec:main-page-options-menu class=level3 data-number=2.1.5><h3 data-number=2.1.5><span class=header-section-number>2.1.5</span>\n<a href=#toc:subsec:main-page-options-menu>Menü Optionen</a><a href=#subsec:main-page-options-menu class=anchor aria-hidden=true></a></h3><p>Das Menü Optionen bietet verschiedene Optionen zum Sortieren und\nFiltern der aufgelisteten Anwendungen sowie zum Navigieren zu\nverschiedenen Seiten innerhalb oder außerhalb des App Managers.<section id=subsubsec:main-list-options class=level4 data-number=2.1.5.1><h4 data-number=2.1.5.1><span class=header-section-number>2.1.5.1</span> Liste der Optionen<a href=#subsubsec:main-list-options class=anchor aria-hidden=true></a></h4><p><strong>Listenoptionen</strong> enthalten die Optionen zum Sortieren\nund Filtern der Liste auf der Hauptseite.<section id=sortierung class=level5 data-number=2.1.5.1.1><h5 data-number=2.1.5.1.1><span class=header-section-number>2.1.5.1.1</span> Sortierung<a href=#sortierung class=anchor aria-hidden=true></a></h5><div id=par:main-page-sort></div><p>Die auf der Hauptseite aufgeführten Anwendungen können auf folgende\nWeise sortiert werden:<ul class=incremental><li><p><strong>Benutzeranwendungen zuerst.</strong> Die\nBenutzeranwendungen werden oben aufgelistet<li><p><strong>App Label.</strong> Sortieren Sie die Liste in\naufsteigender Reihenfolge nach ihren Anwendungsbezeichnungen (auch\nbekannt als <em>Anwendungsnamen</em>). Dies ist die\nStandardsortierpräferenz<li><p><strong>Paketname.</strong> Sortiert die Liste in aufsteigender\nReihenfolge nach den Paketnamen<li><p><strong>Letzte Aktualisierung.</strong> Sortieren der Liste in\nabsteigender Reihenfolge nach dem Datum der letzten\nAktualisierung<li><p><strong>Gemeinsame Benutzer-ID.</strong> Sortiert die Liste in\nabsteigender Reihenfolge nach der Kernel-Benutzer-ID<li><p><strong>Ziel-SDK.</strong> Sortieren der Liste in aufsteigender\nReihenfolge nach dem Ziel-SDK<li><p><strong>Signatur.</strong> Sortieren der Liste in aufsteigender\nReihenfolge auf der Grundlage der Signierinformationen<li><p><strong>Disabled first.</strong> Die deaktivierten Anwendungen\nwerden zuoberst aufgeführt<li><p><strong>Blocked first.</strong> Sortieren Sie die Liste in\nabsteigender Reihenfolge nach der Anzahl der blockierten Komponenten\njeder Anwendung hat<li><p><strong>Backed up first.</strong> Die Anwendungen mit\nSicherungskopien ganz oben anzeigen<li><p><strong>Tracker.</strong> Sortieren Sie die Liste in absteigender\nReihenfolge nach der Anzahl der Tracker-Komponenten jeder Anwendung\nhat<li><p><strong>Last actions.</strong> Sortieren Sie die Liste in\nabsteigender Reihenfolge nach der letzten Zeit und dem Datum der\nAktionen, die an den Anwendungen im App Manager vorgenommen\nwurden.</ul><p>Darüber hinaus gibt es die Option <em>umgekehrt</em>, die verwendet\nwerden kann, um die Liste in umgekehrter Reihenfolge zu sortieren.\nUnabhängig von der Sortiereinstellungen werden die Anwendungen zunächst\nalphabetisch sortiert, um zufällige Sortierergebnisse zu vermeiden.</section><section id=filter class=level5 data-number=2.1.5.1.2><h5 data-number=2.1.5.1.2><span class=header-section-number>2.1.5.1.2</span> Filter<a href=#filter class=anchor aria-hidden=true></a></h5><div id=par:main-page-filter></div><p>Die auf der Hauptseite aufgeführten Anwendungen können auf folgende\nWeise gefiltert werden:<ul class=incremental><li><p><strong>Benutzeranwendungen.</strong> Nur die Benutzeranwendungen\nauflisten<li><p><strong>Systemanwendungen.</strong> Nur die Systemanwendungen\nauflisten<li><p><strong>Deaktivierte Anwendungen.</strong> Nur die deaktivierten\nAnwendungen auflisten<li><p><strong>Anwendungen mit Regeln.</strong> Auflisten der\nAnwendungen mit einer oder mehreren Sperrregeln<li><p><strong>Anwendungen mit Aktivitäten.</strong> Auflistung der\nAnwendungen mit einer oder mehreren Aktivitäten<li><p><strong>Anwendungen mit Backups.</strong> Liste der Anwendungen\nmit einem oder mehreren Backups<li><p><strong>Laufende Anwendungen.</strong> Auflisten der Anwendungen,\ndie derzeit ausgeführt werden<li><p><strong>Anwendungen mit Splits.</strong> Auflisten der\nAnwendungen mit einer oder mehreren geteilten APK-Dateien<li><p><strong>Installierte Anwendungen.</strong> Nur die installierten\nAnwendungen auflisten<li><p><strong>Deinstallierte Anwendungen.</strong> Nur die\ndeinstallierten Anwendungen auflisten<li><p><strong>Anwendungen ohne Backups.</strong> Listet die Anwendungen\nauf, von denen keine Backups vorhanden sind.</ul><p>Anders als bei der Sortierung ist es möglich, mehr als eine\nFilteroption gleichzeitig anzuwenden. Zum Beispiel können die\ndeaktivierten Benutzer- anwendungen aufgelistet werden, indem sowohl\n<em>Benutzeranwendungen</em> als auch <em>Inaktivierte Anwendungen</em>\nausgewählt werden. Dies kann besonders nützlich sein für <a href=#subsec:batch-operations>Batch-Operationen</a>, bei denen das\nFiltern der Benutzeranwendungen notwendig sein kann, um bestimmte\nOperationen sicher auszuführen.</section><section id=profilname class=level5 data-number=2.1.5.1.3><h5 data-number=2.1.5.1.3><span class=header-section-number>2.1.5.1.3</span> Profilname<a href=#profilname class=anchor aria-hidden=true></a></h5><p>Es ist auch möglich, die Anwendungen aufzulisten, die nur in einem <a href=#sec:profiles-page>Profil</a> vorhanden sind. Dies kann nützlich\nsein, um bestimmte Vorgänge in einem Profil auszuführen (z. B. die\nDeinstallation aller Anwendungen in einem Profil), die nicht über die\nSeite <a href=#sec:profiles-page>Profile</a> durchgeführt werden\nkönnen.</section></section><section id=anleitungen class=level4 data-number=2.1.5.2><h4 data-number=2.1.5.2><span class=header-section-number>2.1.5.2</span> Anleitungen<a href=#anleitungen class=anchor aria-hidden=true></a></h4><p>Durch Klicken auf den <strong>Anleitung</strong> wird die\nOffline-Version des App Manager Benutzerhandbuchs geöffnet. Es kann auch\ndie Online-Version öffnen, wenn die entsprechende Funktionsaufteilung,\nd. h. <code>feat_docs</code>, nicht installiert ist oder wenn kein\nWebView im System vorhanden ist, um das Handbuch zu laden.</section><section id=subsubsec:main:1-click-ops class=level4 data-number=2.1.5.3><h4 data-number=2.1.5.3><span class=header-section-number>2.1.5.3</span> 1-Klick-Operationen<a href=#subsubsec:main:1-click-ops class=anchor aria-hidden=true></a></h4><p><strong>1-Click Ops</strong> steht für die Ein-Klick-Operationen. Es\nöffnet die <a href=#sec:1-click-ops-page>entsprechende Seite</a> in\neiner neuen Aktivität.</section><section id=app-nutzung class=level4 data-number=2.1.5.4><h4 data-number=2.1.5.4><span class=header-section-number>2.1.5.4</span> App Nutzung<a href=#app-nutzung class=anchor aria-hidden=true></a></h4><p>App-Nutzungsstatistiken wie z. B. Bildschirmzeit, Datennutzung\n(sowohl mobil als auch Wi-Fi), <em>die Haufigkeit, die eine App geöffnet\nwurde</em>, können durch Klicken auf die Option\n<strong>App-Nutzung</strong> im Menü aufgerufen werden. Es erfordert\njedoch die Berechtigung <em>Nutzungszugriff</em>. Dieser Menüpunkt wird\nnicht aufgeführt, wenn die Nutzungszugriffsfunktion in <a href=#subsec:enable/disable-features>Einstellungen</a> ausgeschaltet\nist.</section><section id=subsubsec:main:running-apps class=level4 data-number=2.1.5.5><h4 data-number=2.1.5.5><span class=header-section-number>2.1.5.5</span> Laufende Apps<a href=#subsubsec:main:running-apps class=anchor aria-hidden=true></a></h4><p>Dieser Menüpunkt öffnet eine neue Seite, auf der eine Liste der\nlaufenden Anwendungen oder Prozesse angezeigt wird. Er zeigt auch die\naktuelle Speicher- und Cache-Nutzung (falls verfügbar) an. Wenn Root\noder ADB für den App Manager nicht verfügbar ist, zeigt er sich nur in\nden neueren Versionen von Android. Die laufenden Anwendungen oder\nProzesse können auf der Ergebnisseite auch zwangsgestoppt oder beendet\nwerden. Ergebnisseite beendet werden. Die Protokolle für die einzelnen\nProzess-IDs (PIDs) können auch im <a href=#subsubsec:log-viewer>Log-Betrachter</a> eingesehen werden.\nDarüber hinaus ist es möglich, Stapelverarbeitungsvorgänge auszuführen,\nindem Sie auf das Symbol klicken oder einen Langklick auf ein Element.\nEin normaler Klick auf ein Element öffnet einen Dialog, in dem\ndetailliertere Informationen angezeigt werden.</section><section id=profile class=level4 data-number=2.1.5.6><h4 data-number=2.1.5.6><span class=header-section-number>2.1.5.6</span> Profile<a href=#profile class=anchor aria-hidden=true></a></h4><p>Dieser Menüpunkt öffnet die Seite <a href=#sec:profiles-page>Profile-Seite</a>. Profile sind eine\nMöglichkeit zur Konfiguration regelmäßig verwendeter Aufgaben. Sie\nkönnen auch über Tastenkombinationen aufgerufen werden.</section><section id=apk-updater class=level4 data-number=2.1.5.7><h4 data-number=2.1.5.7><span class=header-section-number>2.1.5.7</span> APK-Updater<a href=#apk-updater class=anchor aria-hidden=true></a></h4><p>Wenn die App <a href=https://github.com/rumboalla/apkupdater>APK\nUpdater</a> im System installiert ist, kann sie direkt über diesen\nMenüpunkt geöffnet werden. Die Option bleibt ausgeblendet, wenn die App\nnicht im System vorhanden ist.</section><section id=termux class=level4 data-number=2.1.5.8><h4 data-number=2.1.5.8><span class=header-section-number>2.1.5.8</span> Termux<a href=#termux class=anchor aria-hidden=true></a></h4><p>Wenn die App <a href=https://github.com/termux/termux-app>Termux</a> im System\ninstalliert ist, kann die laufende Sitzung (oder eine neue Sitzung)\ndirekt über diesen Menüpunkt geöffnet werden. Die Option bleibt\nausgeblendet, wenn die App nicht im System vorhanden ist.</section><section id=debloater class=level4 data-number=2.1.5.9><h4 data-number=2.1.5.9><span class=header-section-number>2.1.5.9</span> Debloater<a href=#debloater class=anchor aria-hidden=true></a></h4><p>This menu item opens the debloater page that lists all the bloatware\navailable in the device and in App Manager. It also suggests alternative\napplications based on the criteria set by the <a href=https://github.com/MuntashirAkon/android-debloat-list>Android\nDebloat List</a> project.</section><section id=subsubsec:main:labs class=level4 data-number=2.1.5.10><h4 data-number=2.1.5.10><span class=header-section-number>2.1.5.10</span> Labs<a href=#subsubsec:main:labs class=anchor aria-hidden=true></a></h4><p>This menu item opens the labs page that lists all the additional\nfeatures. They include Log Viewer, System Config, Terminal, File Manager\n(as Files), UI Tracker, Interceptor, and Code Editor pages.</section><section id=einstellungen class=level4 data-number=2.1.5.11><h4 data-number=2.1.5.11><span class=header-section-number>2.1.5.11</span> Einstellungen<a href=#einstellungen class=anchor aria-hidden=true></a></h4><p>Dieser Menüpunkt öffnet die\nIn-App-Hyperref[sec:settings-page]<span>Einstellungsseite</span>.</section></section></section><section id=sec:app-details-page class=level2 data-number=2.2><h2 data-number=2.2><span class=header-section-number>2.2</span> <a href=#toc:sec:app-details-page>App-Detailseite</a><a href=#sec:app-details-page class=anchor aria-hidden=true></a></h2><p><strong>Anwendungsdetails</strong> Seite besteht aus 11 (elf)\nRegisterkarten. Sie beschreibt fast alle Informationen, die eine\nAnwendung haben kann, einschließlich aller Attribute aus ihrem Manifest,\n<a href=#ch:app-ops>Anwendungsoperationen</a>, Signier Informationen,\nBibliotheken, und so weiter.<section id=subsec:app-details-colour-codes class=level3 data-number=2.2.1><h3 data-number=2.2.1><span class=header-section-number>2.2.1</span>\n<a href=#toc:subsec:app-details-colour-codes>Farbcodes</a><a href=#subsec:app-details-colour-codes class=anchor aria-hidden=true></a></h3><p>Liste der Farben, die auf dieser Seite verwendet werden, und ihre\nBedeutung:<ul class=incremental><li><p><span class=colorbox style=background-color:red><span style=color:#000>Rot (Tag)</span></span> / <span class=colorbox style=background-color:#790d0d><span style=color:#fff>Dunkelrot\n(Nacht)</span></span> – Kennzeichnet alle App-OPs oder Berechtigungen\nmit dem Flag \"Gefährlich\" oder alle im App Manager blockierten\nKomponenten<li><p><span class=colorbox style=background-color:#ff8a80><span style=color:#000>Hellrot (Tag)</span></span> / <span class=colorbox style=background-color:#4f1c14><span style=color:#fff>sehr\nDunkelrot (Nacht)</span></span> – Bezeichnet die außerhalb des App\nManagers deaktivierten Komponenten<div class=\"amalert tip\"><p><strong><em>Hinweis:</em></strong><p>Eine Komponente, die als deaktiviert gekennzeichnet ist, bedeutet\nnicht immer, dass sie vom Benutzer deaktiviert wurde: Sie kann auch vom\nSystem deaktiviert werden oder in ihrem Manifest als deaktiviert\ngekennzeichnet sein. Die Komponenten einer deaktivierten Anwendung\nwerden auch vom System (und App Manager) als deaktiviert betrachtet.</div><li><p><span class=colorbox style=background-color:#ff8017><span style=color:#000>Kräftiges Orange (Tag)</span></span> / <span class=colorbox style=background-color:#ff801780><span style=color:#fff>sehr dunkles Orange (Nacht)</span></span> –\nBezeichnet die Tracker-Komponenten<li><p><span class=colorbox style=background-color:#ea80fc><span style=color:#000>Zartes Magenta (Tag)</span></span> / <span class=colorbox style=background-color:#431c5d><span style=color:#fff>sehr dunkles Violett (Nacht)</span></span> –\nBezeichnet die laufenden Dienste.</ul></section><section id=subsec:app-info-tab class=level3 data-number=2.2.2><h3 data-number=2.2.2><span class=header-section-number>2.2.2</span>\n<a href=#toc:subsec:app-info-tab>Registerkarte App-Info</a><a href=#subsec:app-info-tab class=anchor aria-hidden=true></a></h3><p><strong>App Info</strong> enthält allgemeine Informationen über eine\nAnwendung. Außerdem werden hier viele Aktionen aufgelistet, die auf\ndieser Registerkarte durchgeführt werden können.<section id=subsubsec:app-info-general-information class=level4 data-number=2.2.2.1><h4 data-number=2.2.2.1><span class=header-section-number>2.2.2.1</span> Allgemeine Informationen<a href=#subsubsec:app-info-general-information class=anchor aria-hidden=true></a></h4><p>Die folgende Liste ist in der gleichen Reihenfolge wie auf der\nRegisterkarte \"App-Info\" aufgeführt.<ul class=incremental><li><p><strong>Anwendungssymbol</strong> Das Anwendungssymbol. Wenn die\nAnwendung kein Symbol hat, wird das Standardsymbol des Systems\nangezeigt. Es ist auch möglich, die APK-Signatur über SHA- oder\nMD5-Summen zu überprüfen, die in der Zwischenablage gespeichert sind,\nindem Sie einfach darauf klicken.<li><p><strong>Anwendungskennzeichnung.</strong> Das Anwendungslabel\noder der Name der Anwendung.<li><p><strong>Paketname.</strong> Der Name des Anwendungspakets. Wenn\nSie auf den Namen klicken, wird er in der Zwischenablage\ngespeichert.<li><p><strong>Version.</strong> Die Anwendungsversion ist in zwei Teile\nunterteilt. Der erste Teil heißt <em>Versions- name</em>. Das Format\ndieses Teils variiert, besteht aber häufig aus mehreren durch Punkte\ngetrennten Ganzzahlen. Der zweite Teil wird <em>Versionscode</em>\ngenannt. Er wird von den ersten Klammern umschlossen. Der Versionscode\nist eine ganze Zahl, die genutzt wird um zwischen Anwendungsversionen zu\nunterscheiden (da ein Versionsname für eine Maschine unlesbar sein\nkann). Generell gilt, hat eine neue Version einer Anwendung einen\nhöheren Versionscode als die alten Versionen. Zum Beispiel, wenn\n<code>123</code> und <code>125</code> zwei Versionscodes einer Anwendung\nsind, kann man sagen, dass die letztere aktueller ist als die erstere\nweil der Versionscode der letzteren höher ist. Anwendungen, die\nverschiedene APK-Dateien für dieselbe Version auf verschiedenen\nPlattformen (Mobilgeräte, Tabs, Desktops usw.) oder Architekturen (32/64\nBit, ARM oder Intel) anbieten, können die Versionsnummern Nummern\nirreführend sein, da sie oft Präfixe für jede Plattform\nhinzufügen.<li><p><strong>Tags.</strong> (Auch bekannt als Tag-Clouds) Tags\nenthalten die grundlegendsten, prägnantesten und nützlichsten\nInformationen über eine Anwendung, wie z. B..<ul class=incremental><li><p><em>Tracker info.</em> Anzahl der Tracker-Komponenten in der\nAnwendung (z. B. <em>5 Tracker</em>) Die Farbe des Tags erscheint\norange, wenn die Tracker nicht blockiert sind, und dunkelcyan, wenn sie\nim App Manager blockiert sind. Ein Klick auf das Tag öffnet ein\nDialogfeld mit der Liste der Tracker-Komponenten, die gesperrt oder\nfreigegeben werden können wenn der App Manager über ausreichende\nBerechtigungen verfügt. Benutzeranwendung oder Systemanwendung. Wenn es\nsich um eine Systemanwendung handelt, ob die Anwendung eine\naktualisierte Version der Systemanwendung ist oder ob die Anwendung\nsystemlos installiert wurde über Magisk installiert wurde.<li><p><em>Split APK info.</em> Anzahl der Splits in der APK mit\nAusnahme der Basis-APK (z. B. <em>5 splits</em>). Wenn Sie auf das Tag\nklicken, wird ein Dialogfeld mit den Informationen über die aufgeteilte\nAPK, wie Typ und Größe, geöffnet.<li><p><em>Debuggable.</em> Die Anwendung kann über ADBdebuggt werden.\nDebuggingfähige Anwendungen können bestimmte Funktionen nutzen, die\neiner normalen Anwendung nicht zur Verfügung stehen. Auf die Daten der\nAnwendung kann über ADB zugegriffen werden (z.B. unter Verwendung von\n<code>run-as</code> command) ohne zusätzliche Berechtigungen.<li><p><em>Test only.</em> Die Anwendung ist eine reine Testanwendung.\nReine Testanwendungen können bestimmte Funktionen nutzen Funktionen\nnutzen, die einer normalen Anwendung nicht zur Verfügung stehen. Auf die\nDaten der Anwendung kann über ADB zugegriffen werden (z. B. unter\nVerwendung von <code>run-as</code> command) ohne zusätzliche\nBerechtigungen.<li><p><em>Large heap.</em> Die Anwendung hat eine große Heap-Größe\nangefordert, d.h. es wird mehr Platz im Speicher (RAM) für die\ndynamische Zuweisung angefordert. Es obliegt dem Betriebssystem zu\nentscheiden, ob es der Anwendung einen großen Speicherplatz für die\nAnwendung zugewiesen wird. Der App Manager zum Beispiel fordert eine\ngroße Heap-Größe an, weil er eine ganze APK in den Speicher laden muss.\nAPK in den Speicher laden muss, während er eine APK vor Android 8\nscannt. Code. Der Anwendung ist kein Code zugeordnet, d. h. es sind\nkeine DEX-Dateien vorhanden. Bei einigen Systemanwendungen kann sich der\neigentliche Code an einem anderen Ort befinden.<li><p><em>Running.</em> Ein oder mehrere Dienste der Anwendung werden\nderzeit im Hintergrund ausgeführt. Ein Klick auf auf das Tag öffnet\neinen Dialog mit der Liste der laufenden Dienste. Durch Anklicken eines\nbeliebigen Dienstes wird dieser in der Protokollanzeige geöffnet Viewer,\nsofern die Funktion des Log Viewers aktiviert ist. Die Anwendung wird\nzwangsweise gestoppt. Dies kann jedoch nicht verhindern, dass sie später\nautomatisch später.<li><p><em>Disabled.</em> Zeigt an, dass die Anwendung deaktiviert (vor\ndem Startprogramm verborgen) ist.<li><p><em>Suspended.</em> Zeigt an, dass die Anwendung ausgesetzt ist\n(im Launcher ausgegraut).<li><p><em>Hidden.</em> Zeigt an, dass die Anwendung versteckt ist (im\nLauncher ausgeblendet).<li><p><em>MagiskHide.</em> MagiskHide ist aktiviert. Ein Klick auf das\nTag öffnet einen Dialog mit der Liste der Prozessen innerhalb der\nAnwendung, die der MagiskHide-Liste hinzugefügt oder aus ihr entfernt\nwerden können.<li><p><em>MagiskDenyList.</em> Die Anwendung ist in MagiskDenyList\nvorhanden. Ein Klick auf das Tag öffnet einen Dialog mit der Liste der\nProzesse innerhalb der Anwendung, die zu MagiskDenyList hinzugefügt oder\ndaraus entfernt werden können. \"KeyStore\". Die Anwendung hat Elemente im\nAndroid KeyStore. Ein Klick auf das Tag öffnet einen Dialog mit allen\nKeyStore-Dateien, die zur Anwendung gehören.<p>Die Anwendung wurde mindestens einmal unter Verwendung von App\nManager gesichert. Ein Klick auf das Tag wird ein Dialog geöffnet, der\nalle verfügbaren Sicherungen zusammen mit den Metadaten\nenthält.<li><p><em>Keine Batterieoptimierung.</em> Die Batterieoptimierung ist\nfür die Anwendung deaktiviert. Es ist möglich ist es möglich, die\nAkku-Optimierung wieder zu aktivieren, indem Sie auf das Tag\nklicken.<li><p><a href=#sec:net-policy><em>Netzpolitik.</em></a> Die\nNetzpolitik (z. B. die Datennutzung im Hintergrund) ist für die\nAnwendung. Wenn Sie auf das Tag klicken, wird ein Dialogfeld mit den\nunterstützten Richtlinien für die Plattform zusammen mit den Optionen zu\nderen Konfiguration.<li><p><a href=#sec:terminologies><em>SSAID.</em></a> Ein Klick auf\ndas Tag öffnet ein Dialogfeld mit der aktuellen SSAID, die der Anwendung\nzugewiesen ist. Es ist auch möglich, die SSAID bei Bedarf\nzurückzusetzen/neu zu generieren.<li><p><em>SAF.</em> Gibt an, dass der Anwendung der Zugriff auf einen\noder mehrere Speicherorte oder Dateien gewährt wurde. Dateien, d. h.\nURIs, über das Storage Access Framework (SAF). Ein Klick auf das Tag\nöffnet einen Dialog mit der Liste der gewährten URIs. . Zeigt an, dass\ndie Anwendung möglicherweise von Google signiert ist.</ul><li><p><strong>Horizontales Aktionsfeld.</strong> Ein Aktionspanel mit\nverschiedenen Aktionen, die für die Anwendung durchgeführt werden\nkönnen. die Anwendung. Siehe §<a href=#subsubsec:horizontal-action-panel data-reference-type=ref data-reference=subsubsec:horizontal-action-panel>2.2.2.3</a> für eine\nvollständige Liste der hier verfügbaren Aktionen. Zusätzliche Aktionen\nsind im Menü <a href=#subsubsec:app-info-options-menu>options menu</a>\nverfügbar.<li><p><strong>Pfade & Verzeichnisse.</strong> Enthält verschiedene\nInformationen zu Anwendungspfaden, einschließlich <em>app\nVerzeichnis</em> (wo sich die APK-Dateien befinden),\n<em>Datenverzeichnisse</em> (intern, gerätegeschützt und extern),\n<em>geteilte APK-Verzeichnisse</em> (zusammen mit den Split-Namen), und\n<em>native JNI-Bibliothek</em> (falls vorhanden). JNI Bibliotheken\nwerden verwendet, um native Codes aufzurufen, die normalerweise in C/C++\ngeschrieben sind. Die Verwendung einer nativen Bibliothek kann die\nAnwendung schneller laufen lassen oder einer Anwendung helfen,\nBibliotheken von Drittanbietern zu verwenden, die in anderen Sprachen\nals Java geschrieben wurden, wie in den meisten Spiele. Die\nVerzeichnisse können über Dateimanager von Drittanbietern geöffnet\nwerden, sofern sie dies unterstützen und über die erforderlichen Die\nVerzeichnisse können über Dateimanager von Drittanbietern geöffnet\nwerden, sofern sie diese unterstützen und über die erforderlichen\nBerechtigungen verfügen, indem Sie auf das Startsymbol auf der rechten\nSeite jedes Verzeichnisses klicken.<li><p><strong>Datennutzung.</strong> Die von der Anwendung verwendete\nDatenmenge, wie vom Betriebssystem gemeldet. Je nach Android-Version\nkann dies eine breite Palette von Berechtigungen erfordern,\neinschließlich <em>Nutzungszugriff</em> und <em>Telefonie</em>\nBerechtigungen.<li><p><strong>Storage & Cache.</strong> Zeigt Informationen über\ndie Größe der Anwendung (APK-Dateien, optimierte Dateien), Daten und\nCache. Bei älteren Geräten wird auch die Größe von externen Daten,\nCache, Medien und OBB-Ordnern angezeigt. Dieser Teil bleibt\nausgeblendet, wenn auf neueren Geräten die Berechtigung\n<em>Nutzungszugriff</em> nicht erteilt wird.<li><p><strong>Weitere Informationen</strong> Zeigt weitere\nInformationen an, wie z. B..<ul class=incremental><li><p><strong>SDK.</strong> Zeigt Informationen im Zusammenhang mit dem\nAndroid SDK an. Es gibt zwei (bei alten Geräten einen) Werte:\n<em>Max</em> bezeichnet das Ziel-SDK und <em>Min</em> bezeichnet das\nMindest-SDK (letzteres ist in alten Geräten nicht verfügbar Geräten\nnicht verfügbar). Es ist empfehlenswert, Anwendungen mit dem maximalen\nSDK zu verwenden, das die Plattform derzeit unterstützt, um um\nsicherzustellen, dass die Anwendung nicht im Kompatibilitätsmodus\nausgeführt wird, um datenschutzwidrige Funktionen zu verwenden. SDK wird\nauch als textbf<span>API Level</span> bezeichnet.<div class=seealso-inline><p><em>Siehe auch: <span><a href=https://en.wikipedia.org/wiki/Android_version_history#Overview>Android\nVersionsgeschichte</a></span></em></div><li><p><strong>Flags.</strong> Die Anwendungsflags, die zum Zeitpunkt\nder Erstellung der Anwendung verwendet wurden. Für eine vollständige\nListe der Flags und deren Funktion finden Sie auf der Seite <a href=https://developer.android.com/reference/android/content/pm/ApplicationInfo#flags>offizielle\nDokumentation</a>.<li><p><strong>Date Installed.</strong> Das Datum, an dem die Anwendung\nzum ersten Mal installiert wurde.<li><p><strong>Date Updated.</strong> Das Datum, an dem die Anwendung\nzuletzt aktualisiert wurde. Dies ist dasselbe wie <em>Date\nInstalled</em> wenn die Anwendung nicht aktualisiert wurde.<li><p><strong>Installer App.</strong> Die Anwendung, die diese\nAnwendung installiert hat. Nicht alle Anwendungen liefern die\nInformationen, die der Paketmanager verwendet werden, um die\nInstaller-Anwendung zu registrieren. Daher sollte dieser Wert nicht als\nselbstverständlich angesehen werden.<li><p><strong>Benutzer-ID.</strong> Die eindeutige Benutzer-ID, die der\nAnwendung vom Android-System zugewiesen wurde. Bei gemeinsam genutzten\nAnwendungen wird dieselbe Benutzer-ID mehreren Anwendungen zugewiesen,\ndie die gleiche <em>Gemeinsame User ID</em> haben.<li><p><strong>Gemeinsame Benutzer-ID.</strong> Gilt für Anwendungen,\ndie gemeinsam genutzt werden. Die gemeinsam genutzte Anwendung muss die\ngleichen <a href=#subsec:signatures-tab>Signaturen</a> haben.<li><p><strong>Primäres ABI.</strong> Von dieser Plattform unterstützte\nArchitektur für diese Anwendung.<li><p><strong>Zygote Preload Name.</strong> Verantwortlich für das\nVorladen von Anwendungscode und Daten, die von allen isolierte Dienste,\ndie die Anwendung Zygote verwenden.<li><p><strong>Versteckte API-Durchsetzungsrichtlinie</strong>. Seit\nAndroid 9 sind viele Methoden und Klassen im Android-Framework durch\neine versteckte API-Durchsetzungsrichtlinie für Drittanbieteranwendungen\nunzugänglich gemacht. Sie hat die folgenden Optionen:<ul class=incremental><li><p><em>Default.</em> Basierend auf der Art der Anwendung. Für\nSystemanwendungen sollte es deaktiviert sein, und für andere sollte es\nerzwungen werden.<li><p><em>None/disabled.</em> Die Anwendung hat vollen Zugriff auf die\nversteckte API, wie sie vorher verwendet wurde Android 9.<li><p><em>Warn.</em> Wie oben, mit dem Unterschied, dass Warnungen\njedes Mal protokolliert werden, wenn die Anwendung auf die versteckte\nAPI zugreift. Diese Funktion wird meist nicht verwendet.<li><p><em>Enforce.</em> Die Anwendung kann nicht auf die versteckte API\nzugreifen, entweder auf die dunkelgraue Liste oder die schwarze Liste,\noder beides. Dies ist die Standardoption für Anwendungen von\nDrittanbietern in Android 9 und höher, es sei denn, die Anwendung vom\nOEM oder dem Hersteller auf die Whitelist gesetzt wurde.<div class=\"amalert warning\"><p><strong><em>Warnung:</em></strong><p>Die Richtlinie zur Durchsetzung versteckter APIs ist in Android nicht\nrichtig implementiert und kann von der Anwendung umgangen werden. Aus\ndiesem Grund sollte diesem Wert nicht vertraut werden.</div></ul><li><p><strong>SELinux.</strong> Obligatorische\nZugriffskontrollrichtlinie (MAC), die vom Betriebssystem über SELinux\nfestgelegt wurde.<li><p><strong>Main Activity.</strong> Der Haupteinstiegspunkt in die\nAnwendung. Dies ist nur sichtbar, wenn die Anwendung über <a href=#subsubsec:activities>activities</a> und jede dieser Aktivitäten\nkann vom Launcher aus geöffnet werden. Außerdem gibt es eine\nStart-Schaltfläche auf der rechten Seite, die verwendet werden kann, um\ndiese Aktivität zu starten.</ul></ul></section><section id=subsubsec:tags class=level4 data-number=2.2.2.2><h4 data-number=2.2.2.2><span class=header-section-number>2.2.2.2</span> Schlagwörter<a href=#subsubsec:tags class=anchor aria-hidden=true></a></h4><ul class=incremental><li><p><strong>Tracker info.</strong> Number of tracker components in\nthe application (e.g., <em>5 trackers</em>) The colour of the tag\nappears orange if the trackers are unblocked and dark cyan if they are\nblocked in App Manager. Clicking on the tag opens a dialog containing\nthe list of tracker components which can also be blocked or unblocked\nprovided App Manager has sufficient privileges.<li><p><strong>Application type.</strong> User application or system\napplication. For a system application, it displays whether the\napplication is an updated version of the system application or the\napplication is installed systemless-ly via Magisk.<li><p><strong>Split APK info.</strong> Number of splits in the APK\nexcluding the base APK (e.g., <em>5 splits</em>). Clicking on the tag\nopens a dialog containing a few additional information, such as name,\ntype, and size.<li><p><strong>Debuggable.</strong> The application can be debugged over\nADB. Debuggable applications can enjoy certain functions unavailable to\na regular application. The data of the application might be accessible\nvia ADB (e.g. using <code>run-as</code> command) without any additional\npermissions.<li><p><strong>Test only.</strong> The application is a test-only\napplication. Test-only applications can enjoy certain functions\nunavailable to a regular application. The data of the application might\nbe accessible via ADB (e.g. using <code>run-as</code> command) without\nany additional permissions.<li><p><strong>No code.</strong> The application does not have any code\nassociated with it i.e., DEX files aren’t present. In some system\napplications, the actual code might be located in another\nplace.<li><p><strong>Large heap.</strong> The application has requested large\nheap size i.e., more space in memory (RAM) is requested for dynamic\nallocation. It is still up to the operating system to decide whether to\nallocate large space for the application. App Manager, for example,\nrequests large heap size because it needs to load an entire APK into\nmemory while scanning an APK.<li><p><strong>Open links.</strong> The application may open certain\nlinks from any applications. If the application can open any links by\ndefault, the color of the tag would be red, dark cyan if otherwise.\nClicking on the tag opens a dialog with the supported hosts or domains\nlisted. In Android 12 onwards, it displays an option to enable or\ndisable opening links by default provided App Manager has sufficient\npermissions. Otherwise, it displays an option to open the system\nsettings page for the application.<li><p><strong>Running.</strong> One or more services of the application\nis currently running in the background. Clicking on the tag opens a\ndialog containing the list of running services. Clicking on any services\nopens the log viewer with default filter set to the UID associated with\nthe service (which can be different from the UID of the application if\nit is running in a separate or isolated process) provided the log viewer\nfeature is enabled. There’s also an option to force-stop the\napplication.<li><p><strong>Stopped.</strong> The application is force stopped. This\nmay not prevent it from running automatically later.<li><p><strong>Disabled.</strong> Denotes that the application is\ndisabled (hidden from the launcher).<li><p><strong>Suspended.</strong> Denotes that the application is\nsuspended (grayed out in the launcher).<li><p><strong>Hidden.</strong> Denotes that the application is hidden\n(hidden from the launcher).<li><p><strong>MagiskHide.</strong> MagiskHide is enabled for the\napplication. Clicking on the tag opens a dialog containing the list of\nprocess names within the application that can be added to or removed\nfrom the MagiskHide list.<li><p><strong>MagiskDenyList.</strong> The application is present in\nMagisk DenyList. Clicking on the tag opens a dialog containing the list\nof process names within the application that can be added to or removed\nfrom Magisk DenyList.<li><p><strong>WX.</strong> The application violates the “W^X policy”\nand is capable of writing and executing in the same directory or in the\nsame portion of memory. This allows the execution of arbitrary\nexecutables either by the modification of executables embedded within\nthe application or by downloading them from the Internet.<br><div class=seealso-inline><p><em>Siehe auch: <span><a href=https://en.wikipedia.org/wiki/W%5EX>W^X in\nWikipedia</a></span></em></div><li><p><strong>Bloatware.</strong> The application may be a known\nbloatware. Clicking on the tag opens a dialog containing detailed\ninformation in addition to suggestions (if available).<li><p><strong>KeyStore.</strong> The application has items in the\nAndroid KeyStore. Clicking on the tag opens a dialog containing all the\nKeyStore files that belong to the application.<li><p><strong>Backup.</strong> The application was backed up using App\nManager at least once. Clicking on the tag opens a dialog containing all\nthe available backups along with metadata.<li><p><strong>No battery optimisation.</strong> Battery optimisation is\ndisabled for the application. It is possible to re-enable battery\noptimisation by clicking on the tag.<li><p><strong>Sensors disabled.</strong> Sensors are disabled for the\napplication. Sensors are disabled for most applications by\ndefault.<li><p><a href=#sec:net-policy><strong>Net policy.</strong></a>\nNetwork policy (e.g., background data usage) is configured for the\napplication. Clicking on the tag displays a dialog containing the\nsupported policies for the platform along with the options to configure\nthem.<li><p><a href=#sec:terminologies><strong>SSAID.</strong></a> Clicking\non the tag opens a dialog containing the current SSAID assigned to the\napplication. It is also possible to reset/regenerate the SSAID if\nneeded.<li><p><strong>SAF.</strong> Denotes that the application has been\ngranted to access one or more storage locations or files i.e. URIs via\nStorage Access Framework (SAF). Clicking on the tag opens a dialog\ncontaining the list of granted URIs.<li><p><strong>Play App Signing.</strong> Indicates that the application\nmight be signed by Google.<li><p><strong>Xposed.</strong> Indicates that the application may be an\nXposed module. Clicking on the tag displays a dialog with additional\ninformation.<li><p><strong>Static Shared Library.</strong> Denotes that the\napplication serves as a static shared library for one or more\napplications. Clicking on the tag opens a dialog containing a list of\ninstalled versions of the library along with an option to uninstall\nthem.<div class=\"amalert tip\"><p><strong><em>Notice:</em></strong><p>The trichrome library (supplied by Google Chrome, Vanadium or similar\nprojects) is currently the only known static shared library on\nAndroid.</div></ul></section><section id=subsubsec:horizontal-action-panel class=level4 data-number=2.2.2.3><h4 data-number=2.2.2.3><span class=header-section-number>2.2.2.3</span> Waagerechte Aktionsfläche<a href=#subsubsec:horizontal-action-panel class=anchor aria-hidden=true></a></h4><p>Die horizontale Aktionsleiste, wie im vorherigen Abschnitt\nbeschrieben, besteht aus verschiedenen anwendungsbezogenen Aktionen, wie\nz. B..<ul class=incremental><li><p><strong>Starten.</strong> Starten Sie die Anwendung, sofern sie\neine Starter <a href=#subsubsec:activities>Aktivität</a> hat.<li><p><strong>Deaktivieren.</strong> Deaktivieren Sie die Anwendung.\nDiese Schaltfläche wird nicht angezeigt, wenn sie bereits deaktiviert\nist oder der Benutzer nicht über ausreichende Berechtigungen verfügt.\nNachdem die Anwendung deaktiviert wurde, wird sie aus der\nAnwendungsschublade ausgeblendet. Verknüpfungen für die Anwendung können\nebenfalls entfernt werden. Die Anwendung kann nur über den App-Manager\noder ein anderes Tool, das dies unterstützt, wieder aktiviert werden. In\nden Android-Einstellungen gibt es keine Option, um eine deaktivierte\nBenutzeranwendung zu aktivieren.<li><p><strong>Deinstallieren.</strong> Deinstallieren Sie die\nAnwendung.<li><p><strong>Aktivieren.</strong> Aktivieren Sie die Anwendung. Diese\nSchaltfläche wird nicht angezeigt, wenn sie bereits aktiviert ist oder\nder Benutzer nicht über ausreichende Berechtigungen verfügt.<li><p><strong>Stopp erzwingen.</strong> Erzwingt das Anhalten der\nAnwendung.<li><p><strong>Daten löschen.</strong> Löscht Daten aus der Anwendung.\nDies schließt alle Informationen ein, die in den internen und neuerdings\nauch in den externen Verzeichnissen gespeicherten Informationen,\neinschließlich Konten (falls von der Anwendung festgelegt), Cache usw.\nDas Löschen von Daten aus dem App-Manager werden beispielsweise alle in\nder Anwendung gespeicherten Regeln entfernt (die Sperrung wird jedoch\nnicht aufgehoben). Aus diesem Grund sollten Sie immer Sicherungskopien\nIhrer Regeln erstellen. Diese Schaltfläche wird nicht angezeigt, wenn\nder Benutzer über ausreichende Rechte verfügt.<li><p><strong>Cache löschen.</strong> Anwendungscache löschen. Es gibt\nkeine Android-Möglichkeit, den Cache einer bestimmten Anwendung zu\nlöschen. Daher sind Root-Rechte erforderlich, um den Cache des internen\nSpeichers der Anwendung zu löschen.<li><p><strong>Installieren.</strong> Aktion zur Installation einer\nAnwendung, die über eine Drittanbieteranwendung geöffnet wurde. Diese\nSchaltfläche wird nur angezeigt, wenn die Anwendung noch nicht\ninstalliert wurde.<li><p><strong>Was gibt’s Neues.</strong> Diese Schaltfläche wird für\neine externe Anwendung angezeigt, wenn sie bereits installiert ist. Wenn\nSie auf diese Schaltfläche wird ein Dialogfeld angezeigt, in dem die\nUnterschiede zwischen der geöffneten und der installierten Version im\nSinne einer Versionskontrolle an. Die angezeigten Informationen umfassen\n<em>Version</em>, <em>Tracker</em>, <em>Zulassungen</em>,\n<em>Komponenten</em>, <em>Signaturen</em> (Prüfsummenänderungen),\n<em>Merkmale</em>, <em>Gemeinsame Bibliotheken</em> und\n<em>SDK</em>.<li><p><strong>Update.</strong> Wird angezeigt, wenn die Anwendung einen\nhöheren Versionscode hat als die installierte Anwendung.<li><p><strong>Neuinstallation.</strong> Wird angezeigt, wenn die\nAnwendung denselben Versionscode hat wie die installierte\nAnwendung.<li><p><strong>Downgrade.</strong> Wird angezeigt, wenn die Anwendung\neinen niedrigeren Versionscode hat als die installierte\nAnwendung.<li><p><strong>Manifest.</strong> Wenn Sie auf diese Schaltfläche\nklicken, wird die Manifest-Datei der Anwendung auf einer separaten Seite\nangezeigt. Die Manifest-Datei kann über die entsprechende Schaltfläche\n(oben rechts) ein- oder ausgepackt oder über die Schaltfläche oder über\ndie Schaltfläche \"Speichern\" im Speicher abgelegt werden.<li><p><strong>Scanner.</strong> Scannt die Anwendung, um potenzielle\nTracker und Bibliotheken aufzulisten. Es scannt auch die Datei unter\nVerwendung von VirusTotal, falls konfiguriert.<br><div class=seealso-inline><p><em>Siehe auch: <span><a href=#sec:scanner-page>Scanner-Seite</a></span></em></div><li><p><strong>Gemeinsame Voreinstellungen</strong> Wenn Sie auf diese\nSchaltfläche klicken, wird eine Liste der von der Anwendung verwendeten\ngemeinsamen Einstellungen angezeigt. Wenn Sie auf ein\nEinstellungselement in der Liste klicken, wird die Seite <a href=#sec:shared-preferences-editor-page>Gemeinsame Voreinstellungen\nEditor-Seite</a>. Diese Option ist nur sichtbar, wenn der Benutzer über\ndie erforderlichen Berechtigungen verfügt.<li><p><strong>Datenbanken.</strong> Wenn Sie auf diese Schaltfläche\nklicken, wird eine Liste der Datenbanken angezeigt, die von der\nAnwendung verwendet werden. Diese Option ist nur sichtbar, wenn der\nBenutzer über die erforderlichen Berechtigungen verfügt.<li><p><strong>F-Droid.</strong> Öffnet die Anwendung in Ihrem\nbevorzugten <em>F-Droid</em>-Client.<li><p><strong>Store.</strong> Öffnet die Anwendung in <em>Aurora\nStore</em>. Die Option ist nur sichtbar, wenn <em>Aurora Store</em>\ninstalliert ist.</ul></section><section id=subsubsec:app-info-options-menu class=level4 data-number=2.2.2.4><h4 data-number=2.2.2.4><span class=header-section-number>2.2.2.4</span> Menü Optionen<a href=#subsubsec:app-info-options-menu class=anchor aria-hidden=true></a></h4><p>Das Menü \"Optionen\" befindet sich in der oberen rechten Ecke der\nSeite. Eine vollständige Beschreibung der dort vorhandenen Optionen\nfinden Sie unten angegeben:<ul class=incremental><li><p><strong>Teilen.</strong> Die Schaltfläche Teilen kann verwendet\nwerden, um die APK zu teilen oder (wenn die Anwendung mehrere Teile hat)\n<em>APKS</em> Datei, die aus der Anwendung extrahiert wurde.<li><p><strong>Auffrischen.</strong> Aktualisiert die Registerkarte\nApp-Info.<li><p><strong>Ansicht in Einstellungen.</strong> Öffnen Sie die\nAnwendung in den Android-Einstellungen.<p><strong>Sichern/Wiederherstellen.</strong> Öffnen Sie den Dialog zum\nSichern/Wiederherstellen.<li><p><strong>Blockierungsregeln exportieren.</strong> Exportieren von\nRegeln, die für die Anwendung im App Manager konfiguriert\nwurden.<li><p><strong>Öffnen in Termux.</strong> Öffnen Sie die Anwendung in\nTermux. Dabei wird <code>su - user_id</code> ausgeführt, wobei\n<code>user_id</code> die Kernel-Benutzerkennung der Anwendung bezeichnet\n(beschrieben in §<a href=#subsubsec:app-info-general-information data-reference-type=ref data-reference=subsubsec:app-info-general-information>2.2.2.1</a>).\nDiese Option ist nur für den Root-Benutzer sichtbar. Siehe §<a href=#subsubsec:config-termux data-reference-type=ref data-reference=subsubsec:config-termux>2.2.2.5</a>, um zu erfahren,\nwie man Termux für die Ausführung von Befehlen aus Anwendungen von\nDrittanbietern konfiguriert.<li><p><strong>Ausführen in Termux.</strong> Öffnen Sie die Anwendung\nüber <code>run-as package_name</code> in Termux. Dies ist nur Dies gilt\nnur für die debuggbaren Anwendungen und funktioniert sowohl für Root-\nals auch für ADB-Benutzer. Siehe §<a href=#subsubsec:config-termux data-reference-type=ref data-reference=subsubsec:config-termux>2.2.2.5</a> erfahren Sie, wie\nSie Termux so konfigurieren, dass Befehle von Drittanbieteranwendungen\nausgeführt werden.<li><p><strong>MagiskHide.</strong> Öffnet ein Dialogfeld mit der Liste\nder Prozesse innerhalb der Anwendung, die zum MagiskHide hinzugefügt\noder aus der MagiskHide-Liste entfernt werden können.<li><p><strong>MagiskDenyList.</strong> Öffnet ein Dialogfeld mit einer\nListe von Prozessen innerhalb der Anwendung, die aus der MagiskDenyList\nhinzugefügt oder entfernt werden können.<li><p><strong>Batterieoptimierung.</strong> Aktivieren/Deaktivieren der\nBatterieoptimierung.<li><p><a href=#sec:net-policy><strong>Netzpolitik.</strong></a>\nKonfigurieren Sie die Netzpolitik (z. B. die Datennutzung im\nHintergrund) für die Anwendung.<li><p><strong>Symbol extrahieren.</strong> Extrahieren und Speichern\ndes Symbols der Anwendung im gemeinsamen Speicher.<li><p><strong>Hinzufügenzum Profile.</strong> Fügen Sie die Anwendung\nzu einem der konfigurierten <a href=#sec:profile-page>Profile</a>\nhinzu.</ul></section><section id=subsubsec:config-termux class=level4 data-number=2.2.2.5><h4 data-number=2.2.2.5><span class=header-section-number>2.2.2.5</span> Termux konfigurieren<a href=#subsubsec:config-termux class=anchor aria-hidden=true></a></h4><p>Standardmäßig lässt Termux die Ausführung von Befehlen aus\nDrittanbieteranwendungen nicht zu. Um diese Option zu verwenden, muss\nTermux v0.96 oder höher erforderlich und\n<code>allow-external-apps=true</code> muss in\n<code>~/.termux/termux.properties</code> hinzugefügt werden.<div class=\"amalert tip\"><p><strong><em>Info:</em></strong><p>Das Aktivieren dieser Option schwächt die Sicherheit von Termux\nnicht. Die Anwendungen von Drittanbietern müssen den Benutzer immer noch\nfragen, ob die Ausführung beliebiger Befehle in Termux zu erlauben.</div></section></section><section id=subsec:component-tabs class=level3 data-number=2.2.3><h3 data-number=2.2.3><span class=header-section-number>2.2.3</span>\n<a href=#toc:subsec:component-tabs>Registerkarten der\nKomponenten</a><a href=#subsec:component-tabs class=anchor aria-hidden=true></a></h3><p><strong>Aktivitäten</strong>, <strong>Dienste</strong>,\n<strong>Empfänger</strong> (d. h. Rundfunkempfänger) und\n<strong>Provider</strong> (d. h. Inhaltsanbieter) werden gemeinsam als\nAnwendungskomponenten bezeichnet. Der Grund dafür ist, dass sie sich in\nvielerlei Hinsicht ähnliche Merkmale aufweisen. Zum Beispiel haben sie\nalle einen <em>Name</em>, ein <em>Label</em>, ein <em>Icon</em> und\nwerden über <em>Absicht</em> ausgeführt. Anwendungskomponenten sind die\nBausteine einer Anwendung und müssen im dem Anwendungsmanifest\ndeklariert werden. Das Anwendungsmanifest ist eine Datei, in der\nanwendungsspezifische Metadaten gespeichert werden. Das Android\nBetriebssystem lernt durch das Lesen der Metadaten, was es mit der\nAnwendung tun soll.<p>Die in diesen Registerkarten verwendeten Farben werden in §<a href=#subsec:app-details-colour-codes data-reference-type=ref data-reference=subsec:app-details-colour-codes>2.2.1</a> erklärt. Es\nist auch möglich, die Liste der Komponenten so zu sortieren, dass\nblockierte oder Tracker-Komponenten ganz oben in der Liste angezeigt\nwerden, und zwar über die Option <strong>Sortieren</strong> im Menü\nÜberlauf-Menü.<section id=subsubsec:activities class=level4 data-number=2.2.3.1><h4 data-number=2.2.3.1><span class=header-section-number>2.2.3.1</span> Aktivitäten<a href=#subsubsec:activities class=anchor aria-hidden=true></a></h4><p><strong>Aktivitäten</strong> sind die Fenster oder Seiten, die vom\nAndroid-Betriebssystem eindeutig identifiziert werden können (z. B.,\n<em>Hauptseite</em> und <em>App-Detailseite</em> sind zwei Aktivitäten).\nJede Aktivität kann mehrere UI-Komponenten haben bekannt als\n<em>Widgets</em> oder <em>Fragmente</em>, und jede Komponente kann\nverschachtelt oder übereinander gelegt werden. Der Entwickler kann sich\nauch dafür entscheiden, externe Dateien, Links usw. innerhalb einer\nAktivität zu öffnen, indem er eine Methode namens\n<em>Inhaltsfilter</em>. Wenn Sie zum Beispiel eine Datei mit Ihrem\nDateimanager öffnen, durchsucht entweder Ihr Dateimanager oder\nBetriebssystem die Inhaltsfilter über PackageManager, um die Aktivitäten\nzu finden, die die Datei öffnen können, und bietet Ihnen an, die Datei\nmit diesen Aktivitäten zu öffnen.<p>Aktivitäten, die exportierbar sind, können in der Regel von\nbeliebigen Drittanbieteranwendungen geöffnet werden. Einige Aktivitäten\nerfordern Berechtigungen, und wenn das der Fall ist, kann nur eine\nAnwendung mit diesen Berechtigungen sie öffnen. In der\n<em>Aktivitäten</em> können Aktivitäten über die Schaltfläche\n<strong>Launch</strong> gestartet werden. Wenn es erforderlich ist,\nzusätzliche zusätzliche Informationen, wie z. B. Intent-Extras, Daten\noder Aktionen, einzugeben, öffnet ein langer Klick auf die Schaltfläche\n<strong>Starten</strong> das Fenster <a href=#sec:interceptor-page>Activity Interceptor</a> Seite, die solche\nFunktionen bietet.<div class=\"amalert tip\"><p><strong><em>Hinweis:</em></strong><p>Wenn Sie eine Aktivität nicht öffnen können, ist es wahrscheinlich,\ndass bestimmte Abhängigkeiten nicht erfüllt sind, z.B.  Sie Sie können\nz. B. die Seite <em>App-Details</em> nicht öffnen, weil Sie dafür\nzumindest einen Paketnamen angeben müssen. Da diese Abhängigkeiten nicht\nprogrammatisch hergeleitet werden können, können diese Aktivitäten\nstandardmäßig nicht über den App Manager geöffnet werden.</div><p>Es ist auch möglich, über die Schaltfläche <strong>Verknüpfung\nerstellen</strong> Verknüpfungen zu den Aktivitäten zu erstellen.<div class=\"amalert danger\"><p><strong><em>Vorsicht:</em></strong><p>Wenn Sie App Manager deinstallieren, gehen alle von App Manager\nerstellten Verknüpfungen verloren.</div></section><section id=subsubsec:details:servcies class=level4 data-number=2.2.3.2><h4 data-number=2.2.3.2><span class=header-section-number>2.2.3.2</span> Dienste<a href=#subsubsec:details:servcies class=anchor aria-hidden=true></a></h4><p>Im Gegensatz zu <a href=#subsubsec:activities>Aktivitäten</a>, die\nBenutzer sehen können, erledigen <strong>Dienste</strong>\nHintergrundaufgaben. Zum Beispiel, wenn Sie mit dem Internetbrowser\nIhres Telefons ein Video aus dem Internet herunterladen, verwendet der\nInternetbrowser einen <em>Hintergrunddienst</em>, um den Inhalt\nherunterzuladen.<p>Wenn eine Aktivität geschlossen oder aus dem Abschnitt\n<em>Ereignisse</em> entfernt wird, kann sie sofort zerstört werden,\nabhängig von vielen Faktoren, z. B. davon, wie viel freier Speicherplatz\nauf dem Telefon vorhanden ist. Dienste können jedoch auf Wunsch\nunbegrenzt ausgeführt werden. Wenn mehr Dienste im Hintergrund\nausgeführt werden, kann das Telefon aufgrund des Mangels an Speicher\nund/oder Verarbeitungsleistung langsamer werden, und der Akku des\nTelefons wird schneller entladen. Bei neueren Android-Versionen ist die\nFunktion zur Akkuoptimierung standardmäßig für alle Anwendungen\naktiviert. Wenn diese Funktion aktiviert ist, kann das System jeden\nDienst willkürlich beenden. Allerdings, Vordergrunddienste (d. h.\nDienste, die mit einer festen Benachrichtigung laufen, wie z. B. der\nMusikplayer) werden in der Regel nicht beendet, es sei denn, die\nRessourcen des Systems sind knapp (Speicher, Batterie usw.).\nHerstellerspezifische Standard-ROMs können eine aggressivere Optimierung\nbieten. MIUI verfügt beispielsweise über eine sehr aggressive\nOptimierungsfunktion, die als <em>MIUI Optimierung</em> bekannt ist.<p>Beide Aktivitäten und Dienste werden im selben <a href=https://stackoverflow.com/questions/7597742>looper</a>\nausgeführt, dem Hauptlooper, was bedeutet, dass die Dienste nicht\nwirklich im Hintergrund ausgeführt werden. Es ist die Aufgabe des\nEntwicklers, dies sicherzustellen. Wie kommuniziert die Anwendung mit\ndem Dienst? Sie verwendet <a href=#subsubsec:app-details-receivers>Broadcast Empfänger</a> oder\nBinder.</section><section id=subsubsec:app-details-receivers class=level4 data-number=2.2.3.3><h4 data-number=2.2.3.3><span class=header-section-number>2.2.3.3</span> Empfänger<a href=#subsubsec:app-details-receivers class=anchor aria-hidden=true></a></h4><p><strong>Empfänger</strong> (auch <em>Broadcast Empfänger</em>\ngenannt) können für die Ausführung bestimmter Aufgaben für bestimmten\nEreignissen verwendet werden. Diese Komponenten werden als\nBroadcast-Empfänger bezeichnet, da sie ausgeführt werden, sobald eine\nBroadcast-Nachricht empfangen wird. Diese Broadcast-Nachrichten werden\nmit einer Methode namens Intent gesendet. Intent ist eine spezielle\nFunktion für Android die verwendet werden kann, um Anwendungen,\nAktivitäten und Dienste zu öffnen und Broadcast-Nachrichten zu senden.\nDaher verwenden, wie bei den <a href=#subsubsec:activities>Aktivitäten</a>, Broadcast-Empfänger\nIntent-Filter, um nur die gewünschten Broadcast-Nachricht(en) zu\nempfangen. Broadcast-Nachrichten können entweder vom System oder von der\nApp selbst gesendet werden. Wenn eine Broadcast-Nachricht gesendet wird,\nwerden die entsprechenden Empfänger vom System geweckt, damit sie\nAufgaben ausführen können. Zum Beispiel, wenn Sie wenig Speicherplatz\nhaben, kann es sein, dass Ihr Telefon nach dem Aktivieren der mobilen\nDaten oder dem Herstellen einer Wifi-Verbindung für einen Moment\neinfriert oder verzögert wird. Haben Sie sich schon einmal gefragt,\nwarum? Das liegt daran, dass Broadcast-Empfänger, die\n‘android.net.conn.CONNECTIVITY_CHANGE‘ empfangen können vom System\ngeweckt werden, sobald Sie die Datenverbindung aktivieren. Da viele Apps\ndiesen Absichtsfilter verwenden, werden alle diese Apps fast sofort vom\nSystem geweckt, was das Einfrieren oder die Verzögerungen\nverursacht.<p>Abgesehen davon können Empfänger für die Interprozesskommunikation\n(IPC) verwendet werden, d. h. sie helfen Ihnen bei der Kommunikation\nzwischen verschiedenen Anwendungen (vorausgesetzt, Sie haben die\nerforderlichen Berechtigungen) oder sogar zwischen verschiedenen\nKomponenten einer einzigen Anwendung.</section><section id=subsubsec:providers class=level4 data-number=2.2.3.4><h4 data-number=2.2.3.4><span class=header-section-number>2.2.3.4</span> Anbieter<a href=#subsubsec:providers class=anchor aria-hidden=true></a></h4><p><strong>Provider</strong> (auch <em>Content Provider</em> genannt)\nwerden für die Datenverwaltung verwendet. Wenn Sie zum Beispiel eine\nAPK-Datei speichern oder Regeln in App Manager exportieren, wird ein\nInhaltsanbieter namens <code>.fm.FmProvider</code> verwendet, um die APK\nzu speichern oder die Regeln zu exportieren. Es gibt viele\nInhaltsanbieter, darunter auch die vom System bereitgestellten, um\nverschiedene inhaltsbezogenen Aufgaben wie Datenbankverwaltung,\nNachverfolgung, Suche usw. Jeder Inhaltsanbieter hat ein Feld namens\n<em>Authority</em>, das für die Anwendung im gesamten Android-Ökosystem\nebenso eindeutig ist wie der Paketname.</section><section id=zusätzliche-funktionen-für-gerootete-handys class=level4 data-number=2.2.3.5><h4 data-number=2.2.3.5><span class=header-section-number>2.2.3.5</span> Zusätzliche Funktionen für\ngerootete Handys<a href=#zusätzliche-funktionen-für-gerootete-handys class=anchor aria-hidden=true></a></h4><p>Im Gegensatz zu Nicht-Root-Benutzern, die in diesen Registerkarten\nmeist nur Zuschauer sind, können Root-Benutzer verschiedene Operationen\ndurchführen.<section id=komponenten-blockieren. class=level5 data-number=2.2.3.5.1><h5 data-number=2.2.3.5.1><span class=header-section-number>2.2.3.5.1</span> Komponenten blockieren.<a href=#komponenten-blockieren. class=anchor aria-hidden=true></a></h5><p>Auf der rechten Seite jeder Komponente befindet sich ein Symbol für\n“Blockieren” (das zu einem Symbol für “Entblocken/Wiederherstellen”\nwird, wenn die Komponente blockiert ist). Diese Ikone (eigentlich eine\nSchaltfläche) kann benutzt werden, um den Blockierungsstatus dieser\nbestimmten Komponente zu ändern. Wenn <a href=#subsubsec:instant-component-blocking>Instant Component\nBlocking</a> nicht aktiviert ist oder die Blockierung noch nie auf die\nAnwendung angewendet wurde, müssen die Änderungen über die Option\n<strong>Regeln anwenden</strong> im Drei-Punkte-Menü. Es ist auch\nmöglich, die bereits angewendeten Regeln mit der gleichen Option zu\nentfernen (dieses Mal als <strong>Regeln entfernen</strong>).<p>Es ist auch möglich, die Komponente mit einer der verschiedenen\nMethoden zu blockieren, indem Sie lange auf das Symbol klicken.<div class=seealso-inline><p><em>Siehe auch: <span><a href=#sec:faq:app-components>FAQ:\nApp-Komponenten</a></span></em></div></section><section id=par:appdetails:blocking-trackers class=level5 data-number=2.2.3.5.2><h5 data-number=2.2.3.5.2><span class=header-section-number>2.2.3.5.2</span> Tracker blockieren.<a href=#par:appdetails:blocking-trackers class=anchor aria-hidden=true></a></h5><p>Es ist möglich, Tracker-Komponenten mit der Option <strong>Tracker\nblockieren</strong> im Drei-Punkte-Menü zu deaktivieren. Alle Tracker\nKomponenten werden unabhängig von der Registerkarte, in der Sie sich\ngerade befinden, blockiert.<div class=\"amalert tip\"><p><strong><em>Info:</em></strong><p>Tracker-Komponenten sind eine Untermenge der Anwendungskomponenten.\nDaher werden sie mit der gleichen Methode blockiert, die auch für das\nBlockieren anderer Komponenten verwendet.</div><div class=seealso><p><em>Siehe auch:</em><ul class=incremental><li><p><a href=#subsec:tracker-classes-versus-tracker-components>FAQ:\nTracker-Klassen versus Tracker-Komponenten</a><li><p><a href=#sec:scanner-page>Scanner-Seite</a><li><p><a href=#subsec:block-unblock-trackers>1-Click Ops Page:\nTracker blockieren/entblocken</a></ul></div></section></section></section><section id=subsec:permission-tabs class=level3 data-number=2.2.4><h3 data-number=2.2.4><span class=header-section-number>2.2.4</span>\n<a href=#toc:subsec:permission-tabs>Registerkarten\nBerechtigungen</a><a href=#subsec:permission-tabs class=anchor aria-hidden=true></a></h3><p>Registerkarten <strong>App Ops</strong>, <strong>Verwendete\nBerechtigungen</strong> und <strong>Berechtigungen</strong> beziehen\nsich auf Berechtigungen. In Android erfordert die Kommunikation zwischen\nApps oder Prozessen, die nicht dieselbe Identität haben (bekannt als\n<em>Shared ID</em>), oft Berechtigung(en). Diese Berechtigungen werden\nvon der Berechtigungssteuerung verwaltet. Einige Berechtigungen werden\nals <em>normale</em> Berechtigungen, die automatisch gewährt werden,\nwenn sie im Anwendungsmanifest erscheinen, aber <em>gefährlich</em> und\n<em>Entwicklung</em> Berechtigungen erfordern eine Bestätigung durch den\nBenutzer. Die in diesen Registerkarten verwendeten Farben werden in §<a href=#subsec:app-details-colour-codes data-reference-type=ref data-reference=subsec:app-details-colour-codes>2.2.1</a>\nerläutert.<section id=subsubsec:app-ops class=level4 data-number=2.2.4.1><h4 data-number=2.2.4.1><span class=header-section-number>2.2.4.1</span> Anwendungsoperationen<a href=#subsubsec:app-ops class=anchor aria-hidden=true></a></h4><p><strong>App Ops</strong> steht für <strong>Application\nOperationen</strong>. Seit Android 4.3 werden <em>App Ops</em> von\nAndroid verwendet, um viele Systemberechtigungen zu kontrollieren. Jeder\nApp Ops ist eine eindeutige Nummer zugeordnet, die zusammen mit dem\nprivaten Namen der Operation auf der Registerkarte App Ops angezeigt\nwird. Einige App Ops haben auch einen öffentlichen Namen. Eine große\nAnzahl von App Ops sind auch mit Textit<span>Zulassungen</span>\nverbunden. Auf dieser Registerkarte wird eine App-Operation als\ngefährlich eingestuft, wenn die zugehörige Berechtigung als gefährlich\nmarkiert ist. Andere Informationen wie <em>Flags</em>,\n<em>Berechtigungsname</em>, <em>Berechtigungsbeschreibung</em>,\n<em>Paketname</em>, <em>Gruppe</em> werden ebenfalls aus der zugehörigen\n<a href=#subsubsec:permissions>Erlaubnis</a> übernommen. Andere können\ndie folgenden enthalten:<ul class=incremental><li><p><strong>Mode.</strong> Er beschreibt den aktuellen\nBerechtigungsstatus, der <em>Erlauben</em>, <em>Verbieten</em> (eine\neher falsche Bezeichnung, es bedeutet einfach Fehler),\n<em>Ignorieren</em> (bedeutet eigentlich verweigern),\n<em>standardmäßig</em> (abgeleitet aus einer Liste von Voreinstellungen,\ndie intern vom Hersteller oder dem AOSP festgelegt wurden),\n<em>Vordergrund</em> (in neueren Android-Versionen bedeutet es, dass die\nApp Ops nur verwendet werden kann, wenn die Anwendung im Vordergrund\nläuft), und einige benutzerdefinierte Modi, die von den Anbietern\nfestgelegt wurden (MIUI verwendet beispielsweise\n<em>Fragen</em>).<li><p><strong>Geltungsdauer.</strong> Die Zeitspanne, in der diese\nAnwendung verwendet wurde (es kann negative Zeitspannen geben, deren\nAnwendungsfälle mir derzeit nicht bekannt sind).<li><p><strong>Accept Time.</strong> Das letzte Mal, dass der\nAnwendungsvorgang akzeptiert wurde.<li><p><strong>Reject Time.</strong> Letztes Mal, als die App-Operation\nabgelehnt wurde.</ul><div class=\"amalert tip\"><p><strong><em>Info:</em></strong><p>Der Inhalt dieser Registerkarte ist für No-Root-Benutzer sichtbar,\nwenn <code>android.permission.GET_APP_OPS_STATS</code> über ADBgewährt\nwird.</div><p>Neben jedem App-OP-Element befindet sich eine Umschalttaste, mit der\nes zugelassen oder verweigert (ignoriert) werden kann. Andere\nunterstützte Modi können auch durch einen langen Klick auf die\nUmschalttaste eingestellt werden. Wenn die gewünschte Anwendung nicht in\nder Registerkarte aufgeführt ist, kann stattdessen die Option <em>Set\ncustom app op</em> im Menü verwendet werden. Es ist auch möglich, die\nÄnderungen mit der Option <em>Zurücksetzen auf Standard</em>\nzurückzusetzen oder alle gefährlichen App-Ops mit der entsprechenden\nOption im Menü zu verweigern. Aufgrund der Funktionsweise von App Ops\nkann es einige Zeit dauern, bis das System sie anwendet.<div class=\"amalert tip\"><p><strong><em>Tip:</em></strong><p>Das Verweigern bestimmter App Ops kann zu Fehlverhalten der Anwendung\nführen. Wenn alle Versuche fehlschlagen, kann die Option <em>Auf\nStandardwerte zurücksetzen</em> als letzter Ausweg verwendet werden.</div><p>Es ist möglich, die Liste in aufsteigender Reihenfolge nach\nApp-Op-Namen und den zugehörigen eindeutigen Nummern (oder Werten) zu\nsortieren, oder die verweigerten App-Ops zuerst aufzulisten und die\nentsprechenden Sortieroptionen zu verwenden.<div class=seealso-inline><p><em>Siehe auch: <span><a href=#ch:app-ops>Anhang: App\nOps</a></span></em></div></section><section id=verwendete-berechtigungen class=level4 data-number=2.2.4.2><h4 data-number=2.2.4.2><span class=header-section-number>2.2.4.2</span> Verwendete Berechtigungen<a href=#verwendete-berechtigungen class=anchor aria-hidden=true></a></h4><p><strong>Verwendete Berechtigungen</strong> sind die von der Anwendung\nverwendeten Berechtigungen. Diese werden so genannt, weil sie im\nManifest unter Verwendung von <code>Verwendete Berechtigung</code>-Tags\nangegeben werden. Informationen wie <em>Flags</em>,\n<em>Berechtigungsname</em>, <em>Berechtigungsbeschreibung</em>,\n<em>Paketname</em>, <em>Gruppe</em> werden aus dem zugehörigen <a href=#subsubsec:permissions>Berechtigung</a>.<p>Privilegierte Benutzer können die Berechtigungen <em>Gefährlich</em>\nund <em>Entwicklung</em> über die Umschalttaste auf der rechten Seite\njedes Berechtigungselements. Es ist auch möglich, gefährliche\nBerechtigungen auf einmal zu entziehen, indem man die entsprechende\nOption im Menü. Nur diese beiden Arten von Berechtigungen können\nentzogen werden, da Android nicht erlaubt <em>normal</em> Berechtigungen\n(was die meisten von ihnen sind) nicht ändern kann. Es könnte immer noch\nmöglich sein, sie zu widerrufen, indem man\n<code>runtime-permissions.xml</code> selbst bearbeitet, aber ob dies\neine Möglichkeit ist, wird noch untersucht.<div class=\"amalert tip\"><p><strong><em>Info:</em></strong><p>Da gefährliche Berechtigungen standardmäßig vom System entzogen\nwerden, ist der Entzug aller gefährlichen Berechtigungen gleichbedeutend\nmit dem Zurücksetzen aller Berechtigungen.</div><p>Es ist möglich, die Berechtigungen nach ihrem Namen (in aufsteigender\nReihenfolge) zu sortieren oder zu wählen, ob zuerst die verweigerten\noder gefährlichen Berechtigungen zuerst anzuzeigen, indem Sie die\nentsprechenden Optionen im Menü verwenden.</section><section id=subsubsec:permissions class=level4 data-number=2.2.4.3><h4 data-number=2.2.4.3><span class=header-section-number>2.2.4.3</span> Berechtigungen<a href=#subsubsec:permissions class=anchor aria-hidden=true></a></h4><p><strong>Berechtigungen</strong> sind normalerweise benutzerdefinierte\nBerechtigungen, die von der Anwendung selbst festgelegt werden. Diese\nArt von Berechtigungen werden als <em>interne</em> Berechtigungen\ngekennzeichnet. Sie enthält auch in anderen Anwendungen deklarierte\nBerechtigungen, die als <em>Externe</em> Berechtigungen bezeichnet\nwerden. Externe Berechtigungen werden in den Anwendungskomponenten als\nAbhängigkeiten angegeben, d. h. eine Anwendung darf die Komponente nur\naufrufen, wenn sie die angegebene Berechtigung besitzt. Hier ist eine\nvollständige Beschreibung der einzelnen Element, das dort angezeigt\nwird:<ul class=incremental><li><p><strong>Name.</strong> Jede Berechtigung hat einen eindeutigen\nNamen wie <code>android.permission.INTERNET</code>, aber mehrere\nAnwendungen können die gleiche Berechtigung anfordern.<li><p><strong>Icon.</strong> Jede Berechtigung kann ein eigenes Symbol\nhaben. Die anderen Berechtigungsregisterkarten haben kein Symbol, weil\nsie im Anwendungsmanifest kein Symbol enthalten.<li><p><strong>Beschreibung.</strong> Dieses optionale Feld beschreibt\ndie Berechtigung. Wenn der Berechtigung keine Beschreibung zugeordnet\nist, wird das Feld nicht angezeigt.<li><p><strong>Flags.</strong> (Verwendet das Flaggensymbol oder den\nNamen <strong>Schutzstufe</strong>) Hier werden verschiedene\nBerechtigungen Flaggen wie <em>Normal</em>, <em>Entwicklung</em>,\n<em>Gefährlich</em>, <em>instant</em>, <em>Gewährt</em>,\n<em>Widerrufen</em>, <em>Signatur</em>, <em>Privilegiert</em>,\nusw.<li><p><strong>Paketname.</strong> Bezeichnet den mit der Berechtigung\nverbundenen Paketnamen, d. h. das Paket, das die Berechtigung\ndefiniert.<p><strong>Gruppe.</strong> Der Gruppenname, der mit der Berechtigung\nverbunden ist (falls vorhanden). Mehrere zusammengehörige Berechtigungen\nkönnen oft zusammen gruppiert werden.</ul></section></section><section id=subsec:signatures-tab class=level3 data-number=2.2.5><h3 data-number=2.2.5><span class=header-section-number>2.2.5</span>\n<a href=#toc:subsec:signatures-tab>Registerkarte Signaturen</a><a href=#subsec:signatures-tab class=anchor aria-hidden=true></a></h3><p><strong>Signaturen</strong> werden eigentlich Signierinformationen\ngenannt. Eine Anwendung wird mit einem oder mehreren Signierzertifikaten\nsigniert, bevor sie veröffentlicht wird. Die Integrität einer Anwendung,\nd.h. ob die Anwendung vom tatsächlichen Entwickler stammt und nicht von\nanderen Personen verändert wurde, kann anhand der Signierinformationen\nüberprüft werden. Wenn eine Anwendung von einem Unbefugten geändert\nwird, kann sie nicht mehr mit den ursprünglichen Zertifikaten signiert\nwerden, da die Signierinformationen vom eigentlichen Entwickler geheim\ngehalten werden. Signierinformationen können durch Prüfsummen überprüft\nwerden. Die Prüfsummen werden aus den Zertifikaten selbst generiert.\nWenn der Entwickler die Prüfsummen für die Signierzertifikate liefert,\nkönnen diese mit den Prüfsummen verglichen werden, die in der\nRegisterkarte <strong>Signaturen</strong> generierten Prüfsummen\nabgeglichen werden, um die Anwendung zu verifizieren. Wenn Sie zum\nBeispiel App Manager von GitHub oder dem Telegram Channel\nheruntergeladen haben, können Sie überprüfen, ob die Anwendung\ntatsächlich von mir freigegeben wurde, indem Sie einfach die folgende\n<em>SHA256</em>-Prüfsumme mit der auf dieser Registerkarte\nangezeigten:<pre><code>320c0c0fe8cef873f2b554cb88c837f1512589dcced50c5b25c43c04596760ab</code></pre><p>In dieser Registerkarte werden mehrere Hash-Algorithmen zur Erzeugung\nvon Prüfsummen verwendet. Dazu gehören <em>MD5</em>, <em>SHA1</em>,\n<em>SHA256</em> und <em>SHA512</em>.<div class=\"amalert danger\"><p><strong><em>Vorsicht:</em></strong><p>Signierinformationen sollten mit einem zuverlässigen\nHashing-Algorithmus wie <em>SHA256</em> überprüft werden. Verlassen Sie\nsich NICHT auf <em>MD5</em> oder <em>SHA1</em>-Prüfsummen, da diese\ndafür bekannt sind, dieselben Prüfsummen für mehrere Zertifikate zu\nerzeugen.</div></section><section id=subsec:uses-features-tab class=level3 data-number=2.2.6><h3 data-number=2.2.6><span class=header-section-number>2.2.6</span>\n<a href=#toc:subsec:uses-features-tab>Uses Features tab</a><a href=#subsec:uses-features-tab class=anchor aria-hidden=true></a></h3><p><strong>Uses Features</strong> tab lists the features declared by the\napplication, such as OpenGL ES, telephony, and leanback. Some features\ncan be required by the application, and some features can be optional.\nRequired features must be present in the system along with the required\nversion. Otherwise, any attempt to install the application will be\ndenied by the system. Colours used in this tab are explained in §<a href=#subsec:app-details-colour-codes data-reference-type=ref data-reference=subsec:app-details-colour-codes>2.2.1</a>.</section><section id=subsec:configurations-tab class=level3 data-number=2.2.7><h3 data-number=2.2.7><span class=header-section-number>2.2.7</span>\n<a href=#toc:subsec:configurations-tab>Configurations tab</a><a href=#subsec:configurations-tab class=anchor aria-hidden=true></a></h3><p><strong>Configurations</strong> tab lists the configurations required\nby the application, such as input method type (qwerty, 12 key), touch\nscreen type (finger, stylus, etc.), and navigation type (dial pad,\ntrackball, wheel). This tab is going to be empty for most\napplications.</section><section id=subsec:shared-libs-tab class=level3 data-number=2.2.8><h3 data-number=2.2.8><span class=header-section-number>2.2.8</span>\n<a href=#toc:subsec:shared-libs-tab>Registerkarte Gemeinsame\nBibliotheken</a><a href=#subsec:shared-libs-tab class=anchor aria-hidden=true></a></h3><p><strong>Gemeinsame Bibliotheken</strong> listet alle\nJAR-Legacy-Abhängigkeiten sowie die JNI-Bibliotheken (Java Native\nInterface) auf. Für JNI-Bibliotheken wird die Plattform\n(x86/x86_64/ARM/AArch64), die Architektur (32/64 Bit), der Objekttyp\n(Shared Object oder ausführbar), usw.</section></section><section id=sec:1-click-ops-page class=level2 data-number=2.3><h2 data-number=2.3><span class=header-section-number>2.3</span> <a href=#toc:sec:1-click-ops-page>1-Klick-Ops Seite</a><a href=#sec:1-click-ops-page class=anchor aria-hidden=true></a></h2><p>Diese Seite wird angezeigt, wenn Sie die Option <a href=#subsubsec:main:1-click-ops>1-Click Ops</a> im <a href=#subsec:main-page-options-menu>Hauptmenü</a> auswählen.<section id=subsec:block-unblock-trackers class=level3 data-number=2.3.1><h3 data-number=2.3.1><span class=header-section-number>2.3.1</span>\n<a href=#toc:subsec:block-unblock-trackers>Blockieren/Entsperren von\nTrackern</a><a href=#subsec:block-unblock-trackers class=anchor aria-hidden=true></a></h3><p>Mit dieser Option können Sie die Werbe-/Tracker-Komponenten der\ninstallierten Anwendungen blockieren oder freigeben. Wenn Sie diese\nOption auswählen, fragt der App Manager, ob er Tracker von allen\nAnwendungen oder nur von den Benutzeranwendungen auflisten soll.\nNeulinge sollten es vermeiden, Tracker aus den Systemanwendungen zu\nblockieren, um unangenehme Folgen zu vermeiden. Danach erscheint ein\nDialogfeld mit mehreren Auswahlmöglichkeiten, in dem Sie eine oder\nmehrere Anwendungen von diesem Vorgang ausschließen können. Die\nÄnderungen werden sofort übernommen, wenn Sie die Schaltfläche\n<em>block</em> oder <em>unblock</em> drücken.<div class=\"amalert warning\"><p><strong><em>Hinweis:</em></strong><p>Bestimmte Anwendungen funktionieren nach dem Blockieren ihrer Tracker\nmöglicherweise nicht mehr wie erwartet. Wenn dies der Fall ist,\nentfernen Sie die Blockierungsregeln auf einmal oder nacheinander in den\nKomponenten-Registerkarten der <a href=#sec:app-details-page>App-Detailseite</a> für die entsprechende\nAnwendung.</div><div class=seealso><p><em>Siehe auch:</em><ul class=incremental><li><p><a href=#subsec:faq:how-to-unblock-tracker-components>Wie hebt\nman die Blockierung von Tracker-Komponenten auf, die mit 1-Click Ops\noder Batch Ops blockiert wurden?</a><li><p><a href=#par:appdetails:blocking-trackers>App-Detailseite:\nBlocking Trackers</a></ul></div></section><section id=subsec:block-components-dots class=level3 data-number=2.3.2><h3 data-number=2.3.2><span class=header-section-number>2.3.2</span>\n<a href=#toc:subsec:block-components-dots>Block\nKomponenten Punkte</a><a href=#subsec:block-components-dots class=anchor aria-hidden=true></a></h3><p>Diese Option kann verwendet werden, um bestimmte\nAnwendungskomponenten zu blockieren, die durch ihre Signaturen\nfestgelegt sind. Die Signatur einer Komponente ist der vollständige Name\noder ein Teil des Namens der Komponente. Aus Sicherheitsgründen wird\nempfohlen, am Ende jeder Teilsignatur einen <code>.</code> (Punkt) am\nEnde jeder Teilsignatur hinzuzufügen, da der zugrunde liegende\nAlgorithmus die Komponenten in einer gierigen Weise sucht und abgleicht.\nEs ist auch möglich, mehr als eine Signatur einzufügen; in diesem Fall\nmüssen alle Signaturen durch Leerzeichen getrennt werden. Ähnlich wie\nbei der obigen Option gibt es auch die Möglichkeit, die\nSystemanwendungen zu sperren.<div class=\"amalert danger\"><p><strong><em>Vorsicht:</em></strong><p>Wenn Sie sich nicht über die Folgen des Blockierens von\nAnwendungskomponenten anhand ihrer Signaturen im Klaren sind, sollten\nSie diese Option nicht verwenden, da sie zu einem Bootloop oder\nSoftbrick führen kann und Sie infolgedessen möglicherweise einen\nWerksreset durchführen müssen.</div></section><section id=subsec:set-mode-for-app-ops-dots class=level3 data-number=2.3.3><h3 data-number=2.3.3><span class=header-section-number>2.3.3</span>\n<a href=#toc:subsec:set-mode-for-app-ops-dots>Modus für App Ops\neinstellen Punkte</a><a href=#subsec:set-mode-for-app-ops-dots class=anchor aria-hidden=true></a></h3><p>Diese Option kann verwendet werden, um bestimmte <a href=#ch:app-ops>Anwendungsoperationen</a> aller oder ausgewählter\nAnwendungen zu konfigurieren. Es gibt zwei Felder. In das erste Feld\nkönnen mehrere app-ops-Konstanten (entweder Namen oder Werte) durch\nLeerzeichen getrennt eingegeben werden. Es ist nicht immer möglich, im\nVoraus alle App-Op-Konstanten zu kennen, da sie von Gerät zu Gerät und\nvon Betriebssystem zu Betriebssystem variieren. Die gewünschte\nApp-Op-Konstante ist in der Registerkarte <em>App Ops</em> auf der Seite\n<a href=#sec:app-details-page>App-Detailseite</a> zu finden. Das\nzweite Feld kann verwendet werden, um eine der <a href=#subsec:mode-constants>Modi</a> einzufügen oder auszuwählen, die\nfür die angegebenen App Ops gesetzt werden.<div class=\"amalert danger\"><p><strong><em>Vorsicht:</em></strong><p>Wenn Sie nicht gut über App Ops und die Folgen ihrer Blockierung\ninformiert sind, sollten Sie diese Option nicht verwenden.</div></section><section id=subsec:1-click-back-up class=level3 data-number=2.3.4><h3 data-number=2.3.4><span class=header-section-number>2.3.4</span>\n<a href=#toc:subsec:1-click-back-up>Sichern</a><a href=#subsec:1-click-back-up class=anchor aria-hidden=true></a></h3><p>1-Klick-Optionen für Backups. Als Vorsichtsmaßnahme werden die\nbetroffenen Sicherungen aufgelistet, bevor ein Vorgang durchgeführt\nwird.<section id=alle-anwendungen-sichern class=level5 data-number=2.3.4.0.1><h5 data-number=2.3.4.0.1><span class=header-section-number>2.3.4.0.1</span> Alle Anwendungen\nsichern<a href=#alle-anwendungen-sichern class=anchor aria-hidden=true></a></h5><p>. Sichern Sie alle installierten Anwendungen.</section><section id=vorhandene-sicherungen-rückgängig-machen. class=level5 data-number=2.3.4.0.2><h5 data-number=2.3.4.0.2><span class=header-section-number>2.3.4.0.2</span> Vorhandene Sicherungen\nrückgängig machen.<a href=#vorhandene-sicherungen-rückgängig-machen. class=anchor aria-hidden=true></a></h5><p>Sichern Sie alle installierten Anwendungen, für die bereits ein\nBackup vorhanden ist.</section><section id=anwendungen-ohne-backups-sichern. class=level5 data-number=2.3.4.0.3><h5 data-number=2.3.4.0.3><span class=header-section-number>2.3.4.0.3</span> Anwendungen ohne Backups\nsichern.<a href=#anwendungen-ohne-backups-sichern. class=anchor aria-hidden=true></a></h5><p>Sichern Sie alle installierten Anwendungen ohne vorheriges\nBackup.</section><section id=backups-überprüfen-und-wiederherstellen. class=level5 data-number=2.3.4.0.4><h5 data-number=2.3.4.0.4><span class=header-section-number>2.3.4.0.4</span> Backups überprüfen und\nwiederherstellen.<a href=#backups-überprüfen-und-wiederherstellen. class=anchor aria-hidden=true></a></h5><p>Überprüfen Sie die kürzlich erstellten Sicherungen der installierten\nAnwendungen und wiederholen Sie die Sicherung, falls erforderlich.</section><section id=sichern-sie-anwendungen-mit-änderungen. class=level5 data-number=2.3.4.0.5><h5 data-number=2.3.4.0.5><span class=header-section-number>2.3.4.0.5</span> Sichern Sie Anwendungen\nmit Änderungen.<a href=#sichern-sie-anwendungen-mit-änderungen. class=anchor aria-hidden=true></a></h5><p>Wenn sich eine Anwendung seit der letzten Sicherung geändert hat,\nwiederholen Sie ihre Sicherung. Dabei wird eine Reihe von Indizes\nüberprüft, darunter die Anwendungsversion, das Datum der letzten\nAktualisierung, das Datum des letzten Starts, die Integrität und die\nDatei-Hashes. Die Hashes der Verzeichnisse werden während des\nSicherungsvorgangs erfasst und in einer Datenbank gespeichert. Bei der\nAusführung dieses Vorgangs werden neue Hashes erstellt und mit den in\nder Datenbank gespeicherten verglichen.</section></section><section id=subsec:1-click-restore class=level3 data-number=2.3.5><h3 data-number=2.3.5><span class=header-section-number>2.3.5</span>\n<a href=#toc:subsec:1-click-restore>Wiederherstellen</a><a href=#subsec:1-click-restore class=anchor aria-hidden=true></a></h3><p>1-Klick-Optionen für die Wiederherstellung. Als Vorsichtsmaßnahme\nwerden die betroffenen Sicherungen aufgelistet, bevor eine Operation\ndurchgeführt wird.<section id=wiederherstellen-aller-anwendungen class=level5 data-number=2.3.5.0.1><h5 data-number=2.3.5.0.1><span class=header-section-number>2.3.5.0.1</span> Wiederherstellen aller\nAnwendungen<a href=#wiederherstellen-aller-anwendungen class=anchor aria-hidden=true></a></h5><p>Wiederherstellen des <em>Basis-Backups</em> aller gesicherten\nAnwendungen.</section><section id=wiederherstellen-von-nicht-installierten-anwendungen class=level5 data-number=2.3.5.0.2><h5 data-number=2.3.5.0.2><span class=header-section-number>2.3.5.0.2</span> Wiederherstellen von\nnicht installierten Anwendungen<a href=#wiederherstellen-von-nicht-installierten-anwendungen class=anchor aria-hidden=true></a></h5><p>. Wiederherstellen des <em>Basis-Backup</em> aller gesicherten\nAnwendungen, die derzeit nicht installiert sind.</section><section id=wiederherstellen-der-letzten-backups class=level5 data-number=2.3.5.0.3><h5 data-number=2.3.5.0.3><span class=header-section-number>2.3.5.0.3</span> Wiederherstellen der\nletzten Backups<a href=#wiederherstellen-der-letzten-backups class=anchor aria-hidden=true></a></h5><p>. Wiederherstellen des <em>Basis-Backup</em> von bereits\ninstallierten Anwendungen, deren Versionscodes höher sind als die der\ninstallierten Versionen.</section></section><section id=subsec:trim-caches-in-all-apps class=level3 data-number=2.3.6><h3 data-number=2.3.6><span class=header-section-number>2.3.6</span>\n<a href=#toc:subsec:trim-caches-in-all-apps>Trim Caches in All\nApps</a><a href=#subsec:trim-caches-in-all-apps class=anchor aria-hidden=true></a></h3><p>Delete caches from all applications, including Android system. During\nthis operation, caches of all the running applications may not be\ncleared as expected.</section></section><section id=sec:profiles-page class=level2 data-number=2.4><h2 data-number=2.4><span class=header-section-number>2.4</span> <a href=#toc:sec:profiles-page>Seite Profile</a><a href=#sec:profiles-page class=anchor aria-hidden=true></a></h2><p>Die Seite Profile kann über das Menü <a href=#subsec:main-page-options-menu>Optionsmenu</a> auf der Hauptseite\naufgerufen werden. Sie zeigt in erster Linie eine Liste der\nkonfigurierten Profile zusammen mit den typischen Optionen zur\nDurchführung von Operationen mit ihnen an. Neue Profile können auch über\ndie Schaltfläche <em>plus</em> in der rechten unteren Ecke hinzugefügt\noder importiert werden, dupliziert oder aus einer der Voreinstellungen\nerstellt werden. Wenn Sie auf ein Profilelement klicken, wird die\nzugehörige Seite <a href=#sec:profile-page>Profilseite</a>\ngeöffnet.<section id=subsec:profiles-options-menu class=level3 data-number=2.4.1><h3 data-number=2.4.1><span class=header-section-number>2.4.1</span>\n<a href=#toc:subsec:profiles-options-menu>Menü Optionen</a><a href=#subsec:profiles-options-menu class=anchor aria-hidden=true></a></h3><p>Auf dieser Seite gibt es zwei Optionsmenüs. Das Menü mit den drei\nPunkten in der oberen rechten Ecke bietet zwei Optionen:\n<em>Voreinstellungen</em> und <em>Importieren</em>.<ul class=incremental><li><p><span>textbf</span><span>Voreinstellungen</span> Diese Option\nlistet eine Reihe von integrierten Profilen auf, die als Ausgangspunkt\nverwendet werden können. Die Profile werden aus dem Projekt <a href=https://gitlab.com/W1nst0n/universal-android-debloater>Universal\nAndroid Debloater</a>.<br><div class=seealso-inline><p><em>Siehe auch: <span><a href=#subsec:faq:what-are-bloatware>FAQ:\nWas ist Bloatware und wie entfernt man sie?</a></span></em></div><li><p><strong>Importieren.</strong> Mit dieser Option können Sie ein\nvorhandenes Profil importieren, das zuvor aus dem App Manager exportiert\nwurde.</ul><p>Wenn Sie lange auf ein Profilelement klicken, wird ein weiteres\nOptionsmenü angezeigt. Es bietet die folgenden Optionen:<ul class=incremental><li><p><strong>Jetzt anwenden</strong>. Diese Option kann verwendet\nwerden, um das Profil direkt anzuwenden. Wenn Sie darauf klicken, wird\nein Dialog angezeigt, in dem ein <a href=#subsubsec:profile-state>Profilzustand</a> ausgewählt werden\nkann. Wenn Sie eine der Optionen auswählen, wird das Profil sofort\nangewendet.<p>Wenn Sie auf Löschen klicken, wird das Profil sofort und ohne Warnung\nentfernt.<li><p><strong>Duplizieren.</strong> Diese Option kann verwendet werden,\num das Profil zu duplizieren. Wenn Sie darauf klicken, wird ein Dialog\nangezeigt, in dem ein Name für das neue Profil festgelegt werden kann.\nWenn Sie auf “OK” klicken, wird <a href=#sec:profile-page>Profilseite</a> geladen, wobei alle\nKonfigurationen, die dieses Profil hat, dupliziert werden. Das Profil\nwird jedoch nicht gespeichert, bis es manuell gespeichert wird.<li><p><strong>Export.</strong> Exportiert das Profil auf einen externen\nSpeicher. Auf diese Weise exportierte Profile können über die Option\n<em>import</em> wie oben erwähnt importiert werden.<p><em><span>Textbf</span><span>Verknüpfung erstellen</span> Mit dieser\nOption können Sie eine Verknüpfung für das Profil erstellen. Wenn Sie\ndarauf klicken, werden zwei Optionen angezeigt: <em>Einfach</em> und\n<em>Erweitert</em>. Bei der Konfiguration mit der letzteren Option wird\nder Benutzer aufgefordert, einen Profilstatus auszuwählen, wenn die\nVerknüpfung aufgerufen wird. Bei der ersten Option wird dagegen immer\nder Standardstatus, der beim letzten Speichern des Profils konfiguriert\nwurde.</em></ul></section></section><section id=sec:profile-page class=level2 data-number=2.5><h2 data-number=2.5><span class=header-section-number>2.5</span> <a href=#toc:sec:profile-page>Seite Profil</a><a href=#sec:profile-page class=anchor aria-hidden=true></a></h2><p>Die Seite Profil zeigt die Konfigurationen für ein Profil an. Sie\nbietet auch die Möglichkeit, sie zu bearbeiten.<section id=subsec:profile-options-menu class=level3 data-number=2.5.1><h3 data-number=2.5.1><span class=header-section-number>2.5.1</span>\n<a href=#toc:subsec:profile-options-menu>Menü Optionen</a><a href=#subsec:profile-options-menu class=anchor aria-hidden=true></a></h3><p>Das Menü mit den drei Punkten in der oberen rechten Ecke öffnet das\nOptionen-Menü. Es enthält verschiedene Optionen wie.<ul class=incremental><li><p><strong>Anwenden</strong>. Diese Option kann verwendet werden, um\ndas Profil anzuwenden. Wenn Sie darauf klicken, wird ein Dialogfeld\nangezeigt, in dem Sie einen <a href=#subsubsec:profile-state>Profilzustand</a> auswählen können. Wenn\nSie eine der Optionen auswählen, wird das Profil sofort angewendet.<div class=\"amalert tip\"><p><strong><em>Hinweis:</em></strong><p>Wenn Sie ein Profil anwenden, werden einige Pakete, die den Kriterien\nnicht entsprechen, einfach ignoriert.</div><li><p><strong>Speichern.</strong> Speichern Sie die Änderungen am\nProfil.<div class=\"amalert warning\"><p><strong><em>Hinweis:</em></strong><p>Änderungen werden nie automatisch gespeichert. Sie müssen sie von\nhier aus manuell speichern.</div><li><p><strong>Verwerfen.</strong> Verwirft alle Änderungen, die seit\ndem letzten Speichervorgang vorgenommen wurden.<li><p><strong>Löschen.</strong> Wenn Sie auf Löschen klicken, wird das\nProfil sofort und ohne Warnung gelöscht.<li><p><strong>Duplizieren.</strong> Mit dieser Option können Sie das\nProfil duplizieren. Wenn Sie darauf klicken, wird ein Dialogfeld\nangezeigt in dem man einen Namen für das neue Profil festlegen kann.\nWenn Sie auf “OK” klicken, wird diese Seite neu geladen, indem alle\nKonfigurationen, die dieses Profil hat, dupliziert. Das Profil wird\njedoch nicht gespeichert, bis es manuell gespeichert wird.<li><p><strong>Erstellen einer Verknüpfung</strong> Mit dieser Option\nkönnen Sie eine Verknüpfung für das Profil erstellen. Wenn Sie darauf\nklicken, gibt es werden zwei Optionen angezeigt: <em>Einfach</em> und\n<em>Erweitert</em>. Bei der Konfiguration mit der letzteren Option wird\nder Benutzer aufgefordert Benutzer aufgefordert, einen Profilstatus\nauszuwählen, wenn die Verknüpfung aufgerufen wird. Bei der ersten Option\nwird dagegen immer der Standardstatus, der beim letzten Speichern des\nProfils konfiguriert wurde.</ul></section><section id=subsec:profile-apps-tab class=level3 data-number=2.5.2><h3 data-number=2.5.2><span class=header-section-number>2.5.2</span>\n<a href=#toc:subsec:profile-apps-tab>Registerkarte Anwendungen</a><a href=#subsec:profile-apps-tab class=anchor aria-hidden=true></a></h3><p>Auf der Registerkarte Apps werden die in diesem Profil konfigurierten\nPakete aufgelistet. Pakete können hinzugefügt oder entfernt werden,\nindem Sie die Schaltfläche <em>Plus</em> unten nutzen. Pakete können\nauch entfernt werden, indem Sie lange auf sie klicken (in diesem Fall\nwird ein Popup mit der einzigen Option <em>Löschen</em> angezeigt).</section><section id=subsec:profile-configurations-tab class=level3 data-number=2.5.3><h3 data-number=2.5.3><span class=header-section-number>2.5.3</span>\n<a href=#toc:subsec:profile-configurations-tab>Registerkarte\nKonfigurationen</a><a href=#subsec:profile-configurations-tab class=anchor aria-hidden=true></a></h3><p>Auf der Registerkarte Konfigurationen können Sie die ausgewählten\nPakete konfigurieren.<section id=profile-id class=level4 data-number=2.5.3.1><h4 data-number=2.5.3.1><span class=header-section-number>2.5.3.1</span> Profile ID<a href=#profile-id class=anchor aria-hidden=true></a></h4><p>The unique ID for this profile, currently set based on the profile\nname. The profile ID can be used to <a href=#subsec:triggering-a-profile>trigger the profile</a> from a\nthird-party application.</section><section id=anmerkung class=level4 data-number=2.5.3.2><h4 data-number=2.5.3.2><span class=header-section-number>2.5.3.2</span> Anmerkung<a href=#anmerkung class=anchor aria-hidden=true></a></h4><p>Dies ist der Text, der auf der Seite <a href=#sec:profiles-page>Profile</a> angezeigt wird. Wenn er nicht\ngesetzt ist, werden stattdessen die aktuellen Konfigurationen\nstattdessen angezeigt.</section><section id=subsubsec:profile-state class=level4 data-number=2.5.3.3><h4 data-number=2.5.3.3><span class=header-section-number>2.5.3.3</span> Zustand<a href=#subsubsec:profile-state class=anchor aria-hidden=true></a></h4><p>Gibt an, wie sich bestimmte konfigurierte Optionen standardmäßig\nverhalten werden. Wenn zum Beispiel die Option <em>deaktivieren</em>\naktiviert ist, werden die Anwendungen deaktiviert, wenn der Zustand\n<em>Ein</em> ist, und aktiviert, wenn der Zustand <em>Aus</em> ist.\nDerzeit werden nur die Werte <em>Ein</em> und <em>On</em>\nunterstützt.</section><section id=nutzer class=level4 data-number=2.5.3.4><h4 data-number=2.5.3.4><span class=header-section-number>2.5.3.4</span> Nutzer<a href=#nutzer class=anchor aria-hidden=true></a></h4><p>Wählen Sie die Benutzer aus, auf die das Profil angewendet werden\nsoll. Standardmäßig sind alle Benutzer ausgewählt.</section><section id=komponenten class=level4 data-number=2.5.3.5><h4 data-number=2.5.3.5><span class=header-section-number>2.5.3.5</span> Komponenten<a href=#komponenten class=anchor aria-hidden=true></a></h4><p>Dies verhält sich genauso wie die Option <a href=#subsec:block-components-dots>Block-Komponenten-Punkte</a> auf\nder 1-Klick-Ops-Seite. Allerdings wird die Blockierung hier nur auf die\nausgewählten Pakete angewendet. Wenn der Status von <a href=#subsubsec:profile-state>Status</a> <em>ein</em> ist, werden die\nKomponenten blockiert, und wenn der Status <em>aus</em> ist, werden die\nKomponenten entsperrt. Die Option kann (unabhängig von den eingegebenen\nWerten) durch Klicken auf die Schaltfläche <em>deaktiviert</em> im\nEingabedialog deaktiviert werden.<div class=seealso-inline><p><em>Siehe auch: <span><a href=#subsec:faq:what-are-app-components>Was sind die\nApp-Komponenten?</a></span></em></div></section><section id=anwendungsoperationen class=level4 data-number=2.5.3.6><h4 data-number=2.5.3.6><span class=header-section-number>2.5.3.6</span> Anwendungsoperationen<a href=#anwendungsoperationen class=anchor aria-hidden=true></a></h4><p>Dies verhält sich genauso wie die Option <a href=#subsec:set-mode-for-app-ops-dots>Modus für App Ops\neinstellen…</a> auf der der Seite 1-Klick-Ops. Allerdings wird der\nVorgang hier nur auf die ausgewählten Pakete angewendet. Wenn der Status\nvon <a href=#subsubsec:profile-state>Status</a> <em>Ein</em> ist,\nwerden die App-Ops verweigert (d. h. ignoriert), und wenn der Status\n<em>Aus</em> ist, werden die App-Ops zugelassen. Die Option kann\ndeaktiviert werden (unabhängig von den eingegebenen Werte) durch Klicken\nauf die Schaltfläche <em>deaktivieren</em> im Eingabedialog deaktiviert\nwerden.</section><section id=berechtigungen class=level4 data-number=2.5.3.7><h4 data-number=2.5.3.7><span class=header-section-number>2.5.3.7</span> Berechtigungen<a href=#berechtigungen class=anchor aria-hidden=true></a></h4><p>Mit dieser Option können Sie bestimmte Rechte für die ausgewählten\nPakete gewähren oder entziehen. Wie andere oben, müssen die\nBerechtigungen durch Leerzeichen getrennt werden. Wenn der <a href=#subsubsec:profile-state>Staus</a> <em>Ein</em> ist, werden die\nwerden die Berechtigungen entzogen, und wenn der Status <em>Aus</em>\nist, werden die Berechtigungen erlaubt. Die Option kann deaktiviert\nwerden (unabhängig von den eingegebenen Werten), indem Sie im\nEingabedialog auf die Schaltfläche <em>deaktivieren</em> klicken.</section><section id=sichernwiederherstellen class=level4 data-number=2.5.3.8><h4 data-number=2.5.3.8><span class=header-section-number>2.5.3.8</span> Sichern/Wiederherstellen<a href=#sichernwiederherstellen class=anchor aria-hidden=true></a></h4><p>Mit dieser Option können Sie ein Backup der ausgewählten Anwendungen\nund ihrer Daten erstellen oder diese wiederherstellen. Hier sind zwei\nOptionen verfügbar: <em>Sicherungsoptionen</em> und\n<em>Sicherungsname</em>.<ul class=incremental><li><p><strong>Backup-Name</strong> Legen Sie einen benutzerdefinierten\nNamen für die Sicherung fest. Wenn der Name der Sicherung festgelegt\nist, erhält sie bei jeder Erstellung einer Sicherung einen eindeutigen\nNamen mit dem Suffix backup-name erhalten. Dieses Verhalten wird in\neiner zukünftigen Version korrigiert werden. Lassen Sie dieses Feld für\nreguläre “Basis”-Sicherungen leer (stellen Sie außerdem sicher, dass Sie\n<em>Mehrfachsicherung</em> in den Sicherungsoptionen\naktivieren).</ul><p>Wenn der Status von <a href=#subsubsec:profile-state>Staus</a>\n<em>Ein</em> ist, werden die Pakete gesichert, und wenn der Status\n<em>off</em>, werden die Pakete wiederhergestellt. Die Option kann\ndeaktiviert werden, indem Sie auf die Schaltfläche <em>deaktivieren</em>\nim dem Eingabedialog.</section><section id=regeln-für-die-exportsperre class=level4 data-number=2.5.3.9><h4 data-number=2.5.3.9><span class=header-section-number>2.5.3.9</span> Regeln für die\nExportsperre<a href=#regeln-für-die-exportsperre class=anchor aria-hidden=true></a></h4><div class=\"amalert danger\"><p><strong><em>Achtung:</em></strong><p>Diese Option ist noch nicht implementiert.</div></section><section id=freeze class=level4 data-number=2.5.3.10><h4 data-number=2.5.3.10><span class=header-section-number>2.5.3.10</span> Freeze<a href=#freeze class=anchor aria-hidden=true></a></h4><p>Allow freezing or unfreezing the selected packages depending on the\nvalue of the <a href=#subsubsec:profile-state>state</a>. If the state\nis <em>on</em>, the packages will be frozen, and if the state is\n<em>off</em>, they will be unfrozen.</section><section id=zwangsstopp class=level4 data-number=2.5.3.11><h4 data-number=2.5.3.11><span class=header-section-number>2.5.3.11</span> Zwangsstopp<a href=#zwangsstopp class=anchor aria-hidden=true></a></h4><p>Ermöglicht, dass die ausgewählten Pakete zwangsgestoppt werden.</section><section id=zwischenspeicher-löschen class=level4 data-number=2.5.3.12><h4 data-number=2.5.3.12><span class=header-section-number>2.5.3.12</span> Zwischenspeicher löschen<a href=#zwischenspeicher-löschen class=anchor aria-hidden=true></a></h4><p>Aktiviert das Löschen des Cache für die ausgewählten Pakete.</section><section id=daten-löschen class=level4 data-number=2.5.3.13><h4 data-number=2.5.3.13><span class=header-section-number>2.5.3.13</span> Daten löschen<a href=#daten-löschen class=anchor aria-hidden=true></a></h4><p>Aktiviert das Löschen von Daten für die ausgewählten Pakete.</section><section id=tracker-blockieren class=level4 data-number=2.5.3.14><h4 data-number=2.5.3.14><span class=header-section-number>2.5.3.14</span> Tracker blockieren<a href=#tracker-blockieren class=anchor aria-hidden=true></a></h4><p>Aktiviert die Sperrung oder Entsperrung der Tracker-Komponenten der\nausgewählten Pakete je nach dem Wert von <a href=#subsubsec:profile-state>Status</a>. Wenn der Zustand\n<em>EIN</em> ist, werden die Tracker blockiert, und wenn der Zustand\n<em>AUS</em> ist, werden die Tracker entsperrt.</section><section id=apk-speichern class=level4 data-number=2.5.3.15><h4 data-number=2.5.3.15><span class=header-section-number>2.5.3.15</span> APK speichern<a href=#apk-speichern class=anchor aria-hidden=true></a></h4><p>Aktiviert die Speicherung von APK-Dateien unter\n<code>AppManager/apks</code> (oder in dem auf der Einstellungsseite\nausgewählten Verzeichnis) der ausgewählten Pakete.</section></section></section><section id=sec:settings-page class=level2 data-number=2.6><h2 data-number=2.6><span class=header-section-number>2.6</span> <a href=#toc:sec:settings-page>Seite Einstellungen</a><a href=#sec:settings-page class=anchor aria-hidden=true></a></h2><p>Die Seite Einstellungen kann verwendet werden, um das Verhalten des\nApp Manager anzupassen.<section id=subsec:language class=level3 data-number=2.6.1><h3 data-number=2.6.1><span class=header-section-number>2.6.1</span>\n<a href=#toc:subsec:language>Sprache</a><a href=#subsec:language class=anchor aria-hidden=true></a></h3><p>Konfigurieren Sie die In-App-Sprache. App Manager unterstützt derzeit\n21 (einundzwanzig) Sprachen.</section><section id=subsec:appearance class=level3 data-number=2.6.2><h3 data-number=2.6.2><span class=header-section-number>2.6.2</span>\n<a href=#toc:subsec:appearance>Appearance</a><a href=#subsec:appearance class=anchor aria-hidden=true></a></h3><section id=subsubsec:app-theme class=level4 data-number=2.6.2.1><h4 data-number=2.6.2.1><span class=header-section-number>2.6.2.1</span> App-Design<a href=#subsubsec:app-theme class=anchor aria-hidden=true></a></h4><p>In-App-Thema konfigurieren.</section><section id=subsubsec:pure-black-theme class=level4 data-number=2.6.2.2><h4 data-number=2.6.2.2><span class=header-section-number>2.6.2.2</span> Pure Black Theme<a href=#subsubsec:pure-black-theme class=anchor aria-hidden=true></a></h4><p>Whether to use a black background instead of the material themed\nbackground.</section><section id=subsubsec:layout-direction class=level4 data-number=2.6.2.3><h4 data-number=2.6.2.3><span class=header-section-number>2.6.2.3</span> Layout Direction<a href=#subsubsec:layout-direction class=anchor aria-hidden=true></a></h4><p>Change layout direction, either left to right or right to left. This\nis usually set using the selected language but not everybody prefers the\nsame direction.</section><section id=subsubsec:enable/disable-features class=level4 data-number=2.6.2.4><h4 data-number=2.6.2.4><span class=header-section-number>2.6.2.4</span> Aktivieren/Deaktivieren von\nFunktionen<a href=#subsubsec:enable/disable-features class=anchor aria-hidden=true></a></h4><p>Aktivieren oder deaktivieren Sie bestimmte Funktionen im App Manager,\nz. B.<ul class=incremental><li><p><strong>Interceptor</strong><li><p><strong>Manifest Betrachter</strong><li><p><strong>Scanner</strong><li><p><strong>Paketinstallationsprogramm</strong><li><p><strong>Benutzungszugriff</strong> Wenn diese Funktion\ndeaktiviert ist, fragt der App Manager nie nach der Berechtigung\n<em>Benutzungszugriff</em>. <strong>Protokollanzeige</strong><li><p><strong>App Explorer.</strong> Die Option “Explore” wird nicht\nverfügbar sein, wenn versucht wird, eine APK-Datei zu öffnen.<li><p><strong>Nutze das Internet.</strong> Alle Internetfunktionen sind\ndeaktiviert, wenn diese Funktion ausgeschaltet ist. Derzeit ist die\neinzige Internetfunktion das Abrufen von Scanberichten über\nVirusTotal.</ul></section></section><section id=subsec:privacy class=level3 data-number=2.6.3><h3 data-number=2.6.3><span class=header-section-number>2.6.3</span>\n<a href=#toc:subsec:privacy>Privacy</a><a href=#subsec:privacy class=anchor aria-hidden=true></a></h3><section id=subsubsec:screen-lock class=level4 data-number=2.6.3.1><h4 data-number=2.6.3.1><span class=header-section-number>2.6.3.1</span> Bildschirm sperren<a href=#subsubsec:screen-lock class=anchor aria-hidden=true></a></h4><p>Sperren Sie den App Manager mit der Android-Bildschirmsperre, sofern\neine Bildschirmsperre konfiguriert ist.<div class=\"amalert warning\"><p><strong><em>Warnung:</em></strong><p>Wenn die Bildschirmsperre in Android nach dem Aktivieren dieser\nEinstellung deaktiviert ist, wird App Manager nicht geöffnet, bis sie\nwieder aktiviert wird.</div></section><section id=subsubsec:run-am-in-background class=level4 data-number=2.6.3.2><h4 data-number=2.6.3.2><span class=header-section-number>2.6.3.2</span> Run App Manager in the\nBackground<a href=#subsubsec:run-am-in-background class=anchor aria-hidden=true></a></h4><p>Whether to run App Manager in the background to reduce the\ninitialisation delay. On certain devices, this can also help if you’re\nfrequently disconnected from ADB.</section><section id=subsubsec:use-the-internet class=level4 data-number=2.6.3.3><h4 data-number=2.6.3.3><span class=header-section-number>2.6.3.3</span> Use the Internet<a href=#subsubsec:use-the-internet class=anchor aria-hidden=true></a></h4><p>Whether to activate the Internet features in App Manager. This\ncurrently include VirusTotal and Pithus scanning in the <a href=#sec:scanner-page>Scanner page</a>.</section><section id=subsubsec:auth-manager class=level4 data-number=2.6.3.4><h4 data-number=2.6.3.4><span class=header-section-number>2.6.3.4</span> Authorization Manager<a href=#subsubsec:auth-manager class=anchor aria-hidden=true></a></h4><p>This setting allows a third-party application to get access to\ncertain features, such as profiles.</section></section><section id=subsec:mode-of-operation class=level3 data-number=2.6.4><h3 data-number=2.6.4><span class=header-section-number>2.6.4</span>\n<a href=#toc:subsec:mode-of-operation>Betriebsmodus</a><a href=#subsec:mode-of-operation class=anchor aria-hidden=true></a></h3><p>Der Betriebsmodus legt fest, wie der App Manager insgesamt\nfunktioniert. Er hat die folgenden Optionen:<ul class=incremental><li><p><strong>Auto.</strong> Überlassen Sie App Manager die Wahl der\ngeeigneten Option. Obwohl dies die Standardoption ist, sollten nicht\ngerootete Benutzer den Modus <em>no-root</em> verwenden.<p><strong>Root.</strong> Betreibt App Manager im Root-Modus. App\nManager fällt in den Modus <em>no-root</em> zurück, wenn root nicht\nerkannt wird, oder in seltenen Fällen, wenn die Binder-Kommunikation\nüber root deaktiviert ist (z.B. in <a href=https://github.com/MuntashirAkon/AppManager/issues/606>Phh\nSuperUser</a>).<li><p><strong>ADB über TCP.</strong> Betreiben Sie App Manager im\nADB-Modus über <a href=#sec:adb-over-tcp>ADB über TCP</a>. App Manager\nfällt in den <em>no-root</em>-Modus zurück, wenn ADB over TCP nicht\naktiviert ist.<p><strong>Wireless debugging</strong>. Aktivieren Sie ADB über Wireless\nDebugging. Es wird versucht, zunächst automatisch eine Verbindung mit\ndem konfigurierten Port automatisch zu verbinden. Wenn dies fehlschlägt,\nwird der Benutzer aufgefordert, entweder ein Pairing durchzuführen oder\nsich manuell mit dem ADB-Daemon zu verbinden. App Manager fällt in den\nModus <em>no-root</em> zurück, wenn die Verbindung mit dem ADB-Daemon\nauf diese Weise nicht zustande kommt.<div class=\"amalert tip\"><p><strong><em>Info:</em></strong><p>Diese Option wird nur bei Geräten mit Android 11 oder höher\nangezeigt, da Wireless Debugging mit Android 11 eingeführt wurde.</div><li><p><strong>No-root.</strong> Betreiben Sie App Manager im no-root\nModus. Während App Manager in diesem Modus besser funktioniert, werden\nalle Root- oder ADB-spezifischen Funktionen deaktiviert.</ul><p>Hier wird auch der aktuell abgeleitete Betriebsmodus angezeigt. Die\ntatsächlichen Betriebsmodi sind <em>root</em>, <em>ABD</em> und\n<em>no-root</em>.</section><section id=subsec:apk-signing class=level3 data-number=2.6.5><h3 data-number=2.6.5><span class=header-section-number>2.6.5</span>\n<a href=#toc:subsec:apk-signing>APK-Signierung</a><a href=#subsec:apk-signing class=anchor aria-hidden=true></a></h3><section id=signaturregelungen class=level4 data-number=2.6.5.1><h4 data-number=2.6.5.1><span class=header-section-number>2.6.5.1</span> Signaturregelungen<a href=#signaturregelungen class=anchor aria-hidden=true></a></h4><p>Konfigurieren Sie die <a href=https://source.android.com/security/apksigning>Signaturschemata</a>,\ndie verwendet werden sollen, wenn die APK-Signierung aktiviert ist. Die\nSignaturschemata v1 und v2 sind standardmäßig aktiviert, aber v3 sollte\nebenfalls aktiviert werden, um eine angemessene Sicherheit in Android 9\noder höher zu gewährleisten.</section><section id=signierschlüssel class=level4 data-number=2.6.5.2><h4 data-number=2.6.5.2><span class=header-section-number>2.6.5.2</span> Signierschlüssel<a href=#signierschlüssel class=anchor aria-hidden=true></a></h4><p>Konfigurieren Sie einen benutzerdefinierten Signierschlüssel zum\nSignieren von APK-Dateien. Schlüssel aus einem bestehenden KeyStore\nkönnen in den App Manager importiert werden, oder es kann ein neuer\nSchlüssel generiert werden.<div class=\"amalert danger\"><p><strong><em>Gefahr:</em></strong><p>Verwenden Sie nicht den Schlüssel, der mit App Manager geliefert\nwird, da er für jeden öffentlich zugänglich ist. In Zukunft wird der\nStandardschlüssel entfernt werden.</div><div class=\"amalert tip\"><p><strong><em>Tipp:</em></strong><p>Wenn Sie den Schlüssel in Zukunft verwenden müssen, empfiehlt es\nsich, selbst einen KeyStore zu erstellen und den Schlüssel zu\nimportieren. Bei Schlüsseln, die im App Manager generiert wurden,\nbesteht die Gefahr, dass sie ohne eine ordnungsgemäße Sicherung gelöscht\nwerden.</div></section><section id=align-apk-files class=level4 data-number=2.6.5.3><h4 data-number=2.6.5.3><span class=header-section-number>2.6.5.3</span> Align APK Files<a href=#align-apk-files class=anchor aria-hidden=true></a></h4><p>Performs zip alignment when App Manager signs an APK file. Zip\nalignment stores the files in the APK file (which is actually a zip\nfile) in a way that a zip file reader can access the files quite easily\nusing random access instead of loading the entire APK file in the\nmemory, which results in the reduction of Android’s memory usage. Note\nthat this step is required if an application’s manifest has\n<code>extractNativeLibs</code> set to <code>true</code>.</section></section><section id=subsec:installer class=level3 data-number=2.6.6><h3 data-number=2.6.6><span class=header-section-number>2.6.6</span>\n<a href=#toc:subsec:installer>Installationsprogramm</a><a href=#subsec:installer class=anchor aria-hidden=true></a></h3><p>Configure the default behaviour of the installer. You can also find\nmost of the settings by clicking on the <em>cog</em> icon when you\ninstall an application.<section id=installationsort class=level4 data-number=2.6.6.1><h4 data-number=2.6.6.1><span class=header-section-number>2.6.6.1</span> Installationsort<a href=#installationsort class=anchor aria-hidden=true></a></h4><p>Definieren Sie den APK-Installationsort. Dies kann eine der Optionen\n<em>auto</em>, <em>nur intern</em> und <em>vorzugsweise extern</em>\nsein. Bei neueren Android-Versionen garantiert die Auswahl der letzten\nOption nicht, dass die Anwendung auf dem externen Speicher installiert\nwird.</section><section id=tracker-blockieren-1 class=level4 data-number=2.6.6.2><h4 data-number=2.6.6.2><span class=header-section-number>2.6.6.2</span> Tracker blockieren<a href=#tracker-blockieren-1 class=anchor aria-hidden=true></a></h4><p>Ob die Tracking-Komponenten sofort nach der Installation der\nAnwendung blockiert werden sollen.</section><section id=änderungen-anzeigen class=level4 data-number=2.6.6.3><h4 data-number=2.6.6.3><span class=header-section-number>2.6.6.3</span> Änderungen anzeigen<a href=#änderungen-anzeigen class=anchor aria-hidden=true></a></h4><p>Ob Änderungen an Version, Tracker, Komponenten, Berechtigungen,\nSignaturen, SDK usw. versionskontrolliert angezeigt werden sollen, wenn\ndie Anwendung bereits installiert wurde.</section><section id=installationsapps class=level4 data-number=2.6.6.4><h4 data-number=2.6.6.4><span class=header-section-number>2.6.6.4</span> InstallationsApps<a href=#installationsapps class=anchor aria-hidden=true></a></h4><p>Wählen Sie die Installationsanwendung aus. Dies ist nützlich für\nAnwendungen, die explizit das Installationsprogramm prüfen, um\nfestzustellen, ob die Anwendung rechtmäßig installiert wurde. Dies\nfunktioniert nur für Root- oder ADB-Benutzer.<div class=\"amalert tip\"><p><strong><em>Hinweis:</em></strong><p>Während die Suche nach dem Installationsprogramm ein legitimes\nAnliegen für eine Anwendung zu sein scheint, kümmert sich das\nAndroid-Framework bereits während der Installation um dieses Problem.\nDie Suche nach dem Installationsprogramm ist einfach der falsche Weg, um\ndie Legitimität der Quelle einer Anwendung zu beweisen.</div></section><section id=apk-signieren class=level4 data-number=2.6.6.5><h4 data-number=2.6.6.5><span class=header-section-number>2.6.6.5</span> APK signieren<a href=#apk-signieren class=anchor aria-hidden=true></a></h4><p>Ob die APK-Dateien vor der Installation der Anwendung signiert werden\nsollen. Die Seite <a href=#subsec:apk-signing>APK Signierung</a> kann\nverwendet werden, um die Signierung zu konfigurieren.</section><section id=immediately-perform-dex-optimization class=level4 data-number=2.6.6.6><h4 data-number=2.6.6.6><span class=header-section-number>2.6.6.6</span> Immediately Perform DEX\nOptimization<a href=#immediately-perform-dex-optimization class=anchor aria-hidden=true></a></h4><p>Whether to perform DEX optimization immediately after installing the\napplication. This can be useful for heavy applications, such as the\ngaming applications.</section><section id=im-hintergrund-installieren class=level4 data-number=2.6.6.7><h4 data-number=2.6.6.7><span class=header-section-number>2.6.6.7</span> Im Hintergrund\ninstallieren<a href=#im-hintergrund-installieren class=anchor aria-hidden=true></a></h4><p>Ob Anwendungen immer im Hintergrund installiert werden sollen. Sobald\ndie Installation abgeschlossen ist, wird eine Benachrichtigung\nausgegeben.</section></section><section id=subsec:backup/restore class=level3 data-number=2.6.7><h3 data-number=2.6.7><span class=header-section-number>2.6.7</span>\n<a href=#toc:subsec:backup/restore>Sichern/Wiederherstellen</a><a href=#subsec:backup/restore class=anchor aria-hidden=true></a></h3><p>Einstellungen in Bezug auf <a href=#sec:backup-restore>Sicherung/Wiederherstellung</a>.<section id=komprimierungsverfahren class=level4 data-number=2.6.7.1><h4 data-number=2.6.7.1><span class=header-section-number>2.6.7.1</span> Komprimierungsverfahren<a href=#komprimierungsverfahren class=anchor aria-hidden=true></a></h4><p>Legen Sie die Kompressionsmethode fest, die bei Backups verwendet\nwerden soll. App Manager unterstützt die Komprimierungsmethoden GZip und\nBZip2, GZip ist die Standardkomprimierungsmethode. Es hat keinen\nEinfluss auf die Wiederherstellung einer bestehenden Sicherung.</section><section id=subsubsec:settings-backup-options class=level4 data-number=2.6.7.2><h4 data-number=2.6.7.2><span class=header-section-number>2.6.7.2</span> Sicherungsoptionen<a href=#subsubsec:settings-backup-options class=anchor aria-hidden=true></a></h4><p>Passen Sie das Dialogfeld <em>Sicherung/Wiederherstellung</em> an,\ndas bei der Erstellung einer Sicherung angezeigt wird.<div class=seealso-inline><p><em>Siehe auch: <span><a href=#subsec:backup-restore-backup-options>Sicherungsoptionen</a></span></em></div></section><section id=anwendungen-mit-android-keystore-sichern class=level4 data-number=2.6.7.3><h4 data-number=2.6.7.3><span class=header-section-number>2.6.7.3</span> Anwendungen mit Android\nKeyStore sichern<a href=#anwendungen-mit-android-keystore-sichern class=anchor aria-hidden=true></a></h4><p>Sicherung von Anwendungen mit Einträgen im Android KeyStore zulassen.\nDiese Option ist standardmäßig deaktiviert, da einige Anwendungen (z. B.\nSignal) bei der Wiederherstellung abstürzen können.</section><section id=subsubsec:settings-encryption class=level4 data-number=2.6.7.4><h4 data-number=2.6.7.4><span class=header-section-number>2.6.7.4</span> Verschlüsselung<a href=#subsubsec:settings-encryption class=anchor aria-hidden=true></a></h4><p>Legen Sie eine Verschlüsselungsmethode für die Backups fest. App\nManager unterstützt derzeit OpenPGP (über <a href=https://f-droid.org/packages/org.sufficientlysecure.keychain/>OpenKeyChain</a>),\nAES und RSA (Hybridverschlüsselung mit AES). Wie bei der <a href=#subsec:apk-signing>APK Signierung</a> werden die AES- und\nRSA-Schlüssel im KeyStore gespeichert und können aus anderen KeyStores\nimportiert werden.<div class=\"amalert danger\"><p><strong><em>Gefahr:</em></strong><p>Zu Ihrer eigenen Sicherheit ist es nicht empfehlenswert,\nRSA-Schlüssel innerhalb des App Managers zu erzeugen. Stattdessen\nsollten sie aus einem KeyStore importiert werden, der an einem sicheren\nOrt aufbewahrt wird.<br>Im Falle von AES sollte der generierte Schlüssel an einem sicheren Ort\ngespeichert werden, z. B. in einem Passwortmanager.</div></section><section id=subsubsec:backup-volume class=level4 data-number=2.6.7.5><h4 data-number=2.6.7.5><span class=header-section-number>2.6.7.5</span> Sicherungsvolumen<a href=#subsubsec:backup-volume class=anchor aria-hidden=true></a></h4><p>Wählen Sie den Speicher, in dem die Backups gespeichert werden. Hier\nwerden auch Protokolle und exportierte APK-Dateien gespeichert.<div class=\"amalert tip\"><p><strong><em>Hinweis:</em></strong><p>Das Backup-Volume gibt nur den Speicherort, nicht den Pfad an.\nBackups werden traditionell im Ordner <code>AppManager</code> innerhalb\ndes Speicherpfads gespeichert. Wenn der Pfad jedoch mit Storage Access\nFramework (SAF) ausgewählt wurde, wird der ausgewählte Pfad oder das\nVerzeichnis direkt verwendet.</div></section><section id=backups-importieren class=level4 data-number=2.6.7.6><h4 data-number=2.6.7.6><span class=header-section-number>2.6.7.6</span> Backups importieren<a href=#backups-importieren class=anchor aria-hidden=true></a></h4><p>Importieren Sie Sicherungen aus alten und eingestellten Projekten wie\nTitanium Backup, OAndBackup und Swift Backup (Version 3.0 bis 3.2). Die\nSicherungen werden nach dem Importieren nicht gelöscht, um Datenverluste\nzu vermeiden, falls die importierten Sicherungen nicht ordnungsgemäß\nwiederhergestellt werden können.</section></section><section id=subsec:rules class=level3 data-number=2.6.8><h3 data-number=2.6.8><span class=header-section-number>2.6.8</span>\n<a href=#toc:subsec:rules>Regeln</a><a href=#subsec:rules class=anchor aria-hidden=true></a></h3><section id=subsubsec:instant-component-blocking class=level4 data-number=2.6.8.1><h4 data-number=2.6.8.1><span class=header-section-number>2.6.8.1</span> Sofortige\nKomponentensperre<a href=#subsubsec:instant-component-blocking class=anchor aria-hidden=true></a></h4><p>Standardmäßig werden Sperrregeln nicht angewendet, es sei denn, sie\nwerden explizit in <a href=#sec:app-details-page>der Seite mit den\nAnwendungsdetails</a> für eine beliebige Anwendung angewendet. Nach\nAktivierung dieser Option werden alle (alten und neuen) Regeln sofort\nfür alle Anwendungen angewendet, ohne dass die Sperrung für eine\nAnwendung explizit aktiviert wird.<div class=seealso-inline><p><em>Siehe auch: <span><a href=#subsec:faq:what-is-instant-component-blocking>FAQ: Was ist\nInstant-Component-Blocking?</a></span></em></div></section><section id=importexport-sperrregeln class=level4 data-number=2.6.8.2><h4 data-number=2.6.8.2><span class=header-section-number>2.6.8.2</span> Import/Export-Sperrregeln<a href=#importexport-sperrregeln class=anchor aria-hidden=true></a></h4><p>Es ist möglich, Sperrregeln im App Manager für alle Anwendungen zu\nimportieren oder zu exportieren. Die Arten von Regeln (Komponenten, App\nOps oder Berechtigungen), die importiert oder exportiert werden sollen,\nkönnen ebenfalls ausgewählt werden. Es ist auch möglich, Sperrregeln aus\n<a href=https://github.com/lihenggui/blocker>Blocker</a> und <a href=https://github.com/tuyafeng/Watt>Watt</a> zu importieren. Wenn es\nnotwendig ist, Sperrregeln für eine einzelne Anwendung zu exportieren,\nkann die entsprechende <a href=#sec:app-details-page>App-Detailseite</a> verwendet werden, um\nRegeln zu exportieren, oder für mehrere Anwendungen können <a href=#subsec:batch-operations>Batchoperationen</a> verwendet\nwerden.<div class=seealso-inline><p><em>Siehe auch: <span><a href=#sec:rules-specification>Regelspezifikation</a></span></em></div><section id=export class=level5 data-number=2.6.8.2.1><h5 data-number=2.6.8.2.1><span class=header-section-number>2.6.8.2.1</span> Export<a href=#export class=anchor aria-hidden=true></a></h5><p>Exportiert Sperrregeln für alle im App Manager konfigurierten\nAnwendungen. Dies kann <a href=#subsec:faq:what-are-app-components>Anwendungskomponenten</a>,\nApp-OPs und Berechtigungen umfassen, basierend auf den in den\nMulti-Choice-Optionen ausgewählten Optionen.</section><section id=importieren class=level5 data-number=2.6.8.2.2><h5 data-number=2.6.8.2.2><span class=header-section-number>2.6.8.2.2</span> Importieren<a href=#importieren class=anchor aria-hidden=true></a></h5><p>Importieren Sie zuvor exportierte Blockierungsregeln aus dem App\nManager. Ähnlich wie beim Export kann dies <a href=#subsec:faq:what-are-app-components>App Komponenten</a>, App\nOperationen und Berechtigungen basierend auf den in den\nMulti-Choice-Optionen ausgewählten Optionen enthalten.</section><section id=par:import-existing-rules class=level5 data-number=2.6.8.2.3><h5 data-number=2.6.8.2.3><span class=header-section-number>2.6.8.2.3</span> Importieren bestehender\nRegeln<a href=#par:import-existing-rules class=anchor aria-hidden=true></a></h5><p>Hinzufügen von Komponenten zum App Manager, die von anderen\nAnwendungen deaktiviert wurden. App Manager verfolgt nur die\nKomponenten, die innerhalb von App Manager deaktiviert wurden. Wenn\nAnwendungskomponenten von anderen Tools oder Anwendungen blockiert oder\ndeaktiviert werden, können Sie diese mit dieser Option importieren. Wenn\nSie auf diese Option klicken, findet App Manager die Komponenten, die\nmöglicherweise von anderen Anwendungen oder Tools deaktiviert wurden,\nund listet nur den Namen der Anwendungen zusammen mit der Anzahl der\nübereinstimmenden Komponenten auf. Zur Sicherheit sind alle Anwendungen\nstandardmäßig nicht ausgewählt. Sie müssen manuell ausgewählt werden,\nund die Blockierung muss über den App Manager erneut angewendet\nwerden.<div class=\"amalert danger\"><p><strong><em>Achtung:</em></strong><p>Seien Sie bei der Verwendung dieses Tools vorsichtig, da es viele\nfalsch positive Ergebnisse geben kann. Wählen Sie nur die Anwendungen\naus, bei denen Sie sich sicher sind.</div></section><section id=importieren-von-watt class=level5 data-number=2.6.8.2.4><h5 data-number=2.6.8.2.4><span class=header-section-number>2.6.8.2.4</span> Importieren von Watt<a href=#importieren-von-watt class=anchor aria-hidden=true></a></h5><p>Importieren Sie Konfigurationsdateien aus <a href=https://github.com/tuyafeng/Watt>Watt</a>, wobei jede Datei\nRegeln für ein einzelnes Paket enthält und der Dateiname der Name des\nPakets mit der Erweiterung <code>.xml</code> ist.<div class=\"amalert tip\"><p><strong><em>Tip:</em></strong><p>Speicherort der Konfigurationsdateien in Watt:\n<code>/sdcard/Android/data/com.tuyafeng.watt/files/ifw</code></div></section><section id=importieren-von-blocker class=level5 data-number=2.6.8.2.5><h5 data-number=2.6.8.2.5><span class=header-section-number>2.6.8.2.5</span> Importieren von Blocker<a href=#importieren-von-blocker class=anchor aria-hidden=true></a></h5><p>Importieren Sie Blockierungsregeln aus <a href=https://github.com/lihenggui/blocker>Blocker</a>, wobei jede\nDatei Regeln für ein einzelnes Paket enthält. Diese Dateien haben die\nErweiterung <code>.json</code>.</section></section><section id=alle-regeln-löschen class=level4 data-number=2.6.8.3><h4 data-number=2.6.8.3><span class=header-section-number>2.6.8.3</span> Alle Regeln löschen<a href=#alle-regeln-löschen class=anchor aria-hidden=true></a></h4><p>Ein-Klick-Option zum Entfernen aller im App Manager konfigurierten\nRegeln. Dadurch werden alle blockierten Komponenten aktiviert, die\nApp-OPs werden auf ihre Standardwerte gesetzt und die Berechtigungen\nwerden gewährt.</section></section><section id=subsec:advanced class=level3 data-number=2.6.9><h3 data-number=2.6.9><span class=header-section-number>2.6.9</span>\n<a href=#toc:subsec:advanced>Advanced</a><a href=#subsec:advanced class=anchor aria-hidden=true></a></h3><section id=subsubsec:selected-users class=level4 data-number=2.6.9.1><h4 data-number=2.6.9.1><span class=header-section-number>2.6.9.1</span> Ausgewählte Benutzer<a href=#subsubsec:selected-users class=anchor aria-hidden=true></a></h4><p>Mit dieser Option können Sie festlegen, für welche Benutzer App\nManager arbeiten soll. App Manager arbeitet standardmäßig für alle\nBenutzer im Root- oder ADB-Modus.</section><section id=subsubsec:saved-apk-name-format class=level4 data-number=2.6.9.2><h4 data-number=2.6.9.2><span class=header-section-number>2.6.9.2</span> Gespeichertes\nAPK-Namensformat<a href=#subsubsec:saved-apk-name-format class=anchor aria-hidden=true></a></h4><p>Legt das Format des APK-Namens fest, das beim Speichern über\nBatch-Operationen oder über Profile verwendet werden soll. App Manager\nbietet einige spezielle Schlüsselwörter, die in <code>%</code>\n(Prozentzeichen) eingeschlossen und unterhalb des Eingabefeldes zu\nfinden sind. Diese Schlüsselwörter sind:<ul class=incremental><li><p><strong><code>Bezeichnung</code>.</strong> Bezeichnet den Namen\noder die Bezeichnung der Anwendung. Dieser kann je nach Anwendung in der\nkonfigurierten Sprache lokalisiert werden.<li><p><strong><code>Paketname</code>.</strong> Bezeichnet den Namen des\nPakets oder die Anwendungs-ID, den eindeutigen Bezeichner, den jede\nAnwendung hat.<li><p><strong><code>Version</code>.</strong> Gibt die aktuelle Version\nder Anwendung an, die dem Manifest entnommen wurde.<li><p><strong><code>Versionscode</code>.</strong> Bezeichnet den\naktuellen Versionscode der Anwendung, der verwendet werden kann, um zwei\nVersionen derselben Anwendung zu unterscheiden.<li><p><strong><code>mindest notwendiges SDK </code>.</strong>\nBezeichnet das minimale SDK (d. h. die Version des Android-Frameworks),\nmit dem die Anwendung arbeiten kann. Diese Daten sind erst seit Android\n7 (Nougat) verfügbar.<li><p><strong><code>empfohlenes SDK</code>.</strong> Bezeichnet das\nSDK, auf das diese Anwendung abzielt. Die Anwendung kann auf höheren\nSDKs arbeiten, aber nur im Kompatibilitätsmodus.<li><p><strong><code>Datumsangabe</code>.</strong> Bezeichnet die\nUhrzeit und das Datum, an dem die APK exportiert wird.</ul></section><section id=subsubsec:import/export-keystore class=level4 data-number=2.6.9.3><h4 data-number=2.6.9.3><span class=header-section-number>2.6.9.3</span> Schlüsselspeicher\nimportieren/exportieren<a href=#subsubsec:import/export-keystore class=anchor aria-hidden=true></a></h4><p>Importieren oder exportieren Sie den von App Manager verwendeten\nKeyStore. Dies ist ein Bouncy Castle KeyStore mit der Erweiterung\n<code>bks</code>. Daher werden andere KeyStore wie Java KeyStore (JKS)\noder PKCS #12 nicht unterstützt. Wenn ein Schlüssel aus einem solchen\nKeyStore importiert werden muss, sollten die entsprechenden Optionen wie\noben angegeben gewählt werden.</section></section><section id=subsec:device-info class=level3 data-number=2.6.10><h3 data-number=2.6.10><span class=header-section-number>2.6.10</span> <a href=#toc:subsec:device-info>Über das Gerät selbst</a><a href=#subsec:device-info class=anchor aria-hidden=true></a></h3><p>Anzeige von Android-Version, Sicherheit, CPU, GPU, Akku, Speicher,\nBildschirm, Sprachen, Benutzerinformationen usw.</section></section><section id=sec:scanner-page class=level2 data-number=2.7><h2 data-number=2.7><span class=header-section-number>2.7</span> <a href=#toc:sec:scanner-page>Scanner-Seite</a><a href=#sec:scanner-page class=anchor aria-hidden=true></a></h2><p><strong>Scanner-Seite</strong> wird angezeigt, nachdem Sie auf die\nSchaltfläche <em>Scanner</em> in der Registerkarte <a href=#subsec:app-info-tab>App-Info</a> geklickt haben. Externe\nAPK-Dateien können auch über Dateimanager, Webbrowser usw. zum Scannen\ngeöffnet werden.<p>Es wird nach Trackern und Bibliotheken gescannt und die Anzahl der\nTracker und Bibliotheken als Zusammenfassung angezeigt. Es zeigt auch\nPrüfsummen der APK-Datei sowie die Signierzertifikate. Wenn VirusTotal\nin den Einstellungen konfiguriert ist, versucht es auch, Berichte von\nVirusTotal abzurufen, oder lädt die APK-Datei hoch, wenn sie sich nicht\nin der Datenbank befindet.<div class=\"amalert danger\"><p><strong><em>Disclaimer:</em></strong><p>App Manager scannt eine Anwendung nur statisch und ohne Vorurteile.\nDie Anwendung kann Optionen für die Ablehnung anbieten, oder in einigen\nFällen werden bestimmte Funktionen des Trackers von der Anwendung\nüberhaupt nicht genutzt (z. B. F-Droid), oder manche Anwendungen\nverwenden sie einfach als Platzhalter, um den Ausfall bestimmter\nFunktionen zu verhindern (z. B.  Fennec F-Droid). <strong>Die Absicht\ndes Scanners ist es, Ihnen eine Vorstellung davon zu geben, was die APK\nenthalten könnte. Er sollte als erster Schritt für weitere\nUntersuchungen angesehen werden.</strong></div><p>Ein Klick auf den ersten Punkt (d.h. die Anzahl der Klassen) öffnet\neine neue Seite mit einer Liste der Tracker-Klassen für die Anwendung.\nAlle Klassen können auch durch Anklicken des Menüs <em>Toggle Class\nListing</em> angezeigt werden. Eine Vorschau auf jede Klasse kann durch\neinfaches Klicken auf ein beliebiges Klassenelement angezeigt werden. In\nAndroid 8 (Oreo) und später, enthält dies die gesamte SMALI-Version der\nKlasse und kann mit der entsprechenden Option in Java konvertiert\nwerden.<div class=\"amalert tip\"><p><strong><em>Hinweis:</em></strong><p>Aufgrund verschiedener Einschränkungen ist es nicht möglich, alle\nKomponenten einer APK-Datei zu scannen. Dies gilt insbesondere, wenn\neine APK stark verschleiert ist. Der Scanner prüft auch keine\nZeichenketten (oder Website-Signaturen).</div><p>Der zweite Punkt listet die Anzahl der Tracker zusammen mit deren\nNamen auf. Wenn Sie auf diesen Punkt klicken, wird ein Dialog angezeigt,\nder den Namen der Tracker, die übereinstimmenden Signaturen und die\nAnzahl der Klassen für jede Signatur. Einige Tracker-Namen können ein\n<span class=\"math inline\"><sup>2</sup></span> vorangestellt, was\nanzeigt, dass die Tracker in der <a href=https://etip.exodus-privacy.eu.org>ETIP</a> Stand-by-Liste stehen\nd.h. ob es sich um tatsächliche Tracker handelt, wird noch\nuntersucht.<p>Der dritte Punkt listet die Anzahl der Bibliotheken zusammen mit\nihren Namen auf. Die Informationen stammen größtenteils aus dem <a href=https://gitlab.com/IzzyOnDroid/repo>IzzyOnDroid\nRepository</a>.<div class=seealso-inline><p><em>Siehe auch: <span><a href=#subsec:tracker-classes-versus-tracker-components>FAQ:\nTracker-Klassen vs. Tracker-Komponenten</a></span></em></div><p>Unten auf der Seite befindet sich ein spezieller Punkt, der die\nAnzahl der fehlenden Signaturen (d. h. der fehlenden Klassen) angibt.\nDie fehlenden Signaturen sind diejenigen, die AM nicht mit bekannten\nBibliotheken abgleichen konnte. Die Zahl selbst hat keine Bedeutung, da\nviele Bibliotheken Hunderte von Klassen enthalten, aber ein Klick auf\ndas Element öffnet ein Dialogfeld der die Signaturen enthält, was bei\nder Überprüfung der fehlenden Signaturen hilfreich ist. <strong>Diese\nFunktion ist nur für Personen gedacht, die wissen, was eine fehlende\nSignatur ist und was damit zu tun ist. Andere Benutzer sollten sie\nignorieren.</strong></section><section id=sec:interceptor-page class=level2 data-number=2.8><h2 data-number=2.8><span class=header-section-number>2.8</span> <a href=#toc:sec:interceptor-page>Interceptor-Seite</a><a href=#sec:interceptor-page class=anchor aria-hidden=true></a></h2><p>Interceptor kann verwendet werden, um die Kommunikation zwischen\nAnwendungen mit Hilfe von <code>Intent</code> abzufangen. Er arbeitet\nals Man-in-the-Middle zwischen der Quell- und der Zielanwendung. Er\nbietet eine funktionsreiche Benutzeroberfläche zur Bearbeitung von\n<code>Intent</code>s.<div class=\"amalert warning\"><p><strong><em>Warning:</em></strong><p>Interceptor funktioniert nur für <em>implicit</em>-Intents, bei denen\ndie <a href=#subsec:faq:what-are-app-components>App-Komponente</a>\nnicht angegeben ist.</div><div class=seealso><p><em>Siehe auch:</em><ul class=incremental><li><p><a href=https://developer.android.com/guide/components/intents-common>Gemeinsame\nIntents</a><li><p><a href=https://developer.android.com/guide/components/intents-filters>Intents\nund Intent-Filter</a></ul></div><section id=subsec:intent-filters class=level3 data-number=2.8.1><h3 data-number=2.8.1><span class=header-section-number>2.8.1</span>\n<a href=#toc:subsec:intent-filters>Intent-Filter</a><a href=#subsec:intent-filters class=anchor aria-hidden=true></a></h3><p>Intent-Filter werden von den Anwendungen verwendet, um die Aufgaben\nzu spezifizieren, die sie ausführen können oder die sie mit anderen\nAnwendungen ausführen werden. Wenn Sie zum Beispiel eine PDF-Datei mit\neinem Dateimanager öffnen, versucht der Dateimanager, die Anwendungen zu\nfinden, mit denen die PDF-Datei geöffnet werden soll. Um die richtigen\nAnwendungen zu finden, erstellt der Dateimanager einen Intent mit\nFiltern wie dem MIME-Typ und bittet das System, die Anwendungen\nabzurufen, die diesen Filter öffnen können. Das System durchsucht das\nManifest der installierten Anwendungen nach dem Filter und listet die\nAnwendungskomponenten auf, die in der Lage sind, diesen Filter (in\nunserem Fall das PDF) zu öffnen. Daraufhin öffnet entweder der\nDateimanager die gewünschte Anwendungskomponente von selbst oder es wird\neine vom System bereitgestellte Option verwendet, um sie zu öffnen. Wenn\nmehrere Anwendungskomponenten in der Lage sind, das Dokument zu öffnen,\nund keine Standardeinstellung festgelegt ist, erhalten Sie\nmöglicherweise eine Aufforderung, die richtige Anwendungskomponente\nauszuwählen.<section id=subsubsec:action class=level4 data-number=2.8.1.1><h4 data-number=2.8.1.1><span class=header-section-number>2.8.1.1</span> Aktion<a href=#subsubsec:action class=anchor aria-hidden=true></a></h4><p>Aktion gibt die auszuführende allgemeine Aktion an, z. B.\n<code>android.intent.action.VIEW</code>. Anwendungen deklarieren oft die\nrelevanten Aktionen in der Manifestdatei an, um die gewünschten Intents\nabzufangen. Die Aktion ist besonders nützlich für Broadcast Intent, wo\nsie eine wichtige Rolle spielt. In anderen Fällen dient sie als erste\nMöglichkeit, die relevanten Anwendungskomponenten herauszufiltern.\nGenerische Aktionen wie <code>android.intent.action.VIEW</code> und\n<code>android.intent.action.SEND</code> werden von vielen Anwendungen\nverwendet. Daher kann diese Einstellung allein viele\nAnwendungskomponenten abdecken.</section><section id=subsubsec:data class=level4 data-number=2.8.1.2><h4 data-number=2.8.1.2><span class=header-section-number>2.8.1.2</span> Daten<a href=#subsubsec:data class=anchor aria-hidden=true></a></h4><p>Daten sind ursprünglich als URI (Uniform Resource Identifier)\nbekannt, die in <a href=http://www.faqs.org/rfcs/rfc2396.html>RFC\n2396</a> definiert sind. Es kann sich um Weblinks, Dateispeicherorte\noder eine spezielle Funktion namens <em>Inhalt</em> handeln. Inhalte\nsind eine Android-Funktion, die von den <a href=#appdetails:providers>Inhaltsanbietern</a> verwaltet wird. Daten\nsind oft mit einem <a href=#subsubsec:mime-type>MIME-Typ</a>\nverbunden.<p>Beispiele:<pre><code>http://search.disroot.org/?q=URI%20in%20Android%20scheme&amp;categories=general&amp;language=en-US\nhttps://developer.android.com/reference/android/net/Uri\nfile:///sdcard/AppManager.apk\nmailto:email@example.com\ncontent://io.github.muntashirakon.AppManager.provider/23485af89b08d87e898a90c7e/AppManager.apk</code></pre></section><section id=subsubsec:mime-type class=level4 data-number=2.8.1.3><h4 data-number=2.8.1.3><span class=header-section-number>2.8.1.3</span> MIME-Typ<a href=#subsubsec:mime-type class=anchor aria-hidden=true></a></h4><p>MIME-Typ des Feldes <a href=#subsubsec:data>Daten</a>. Wenn das\nDatenfeld zum Beispiel auf <code>file:///sdcard/AppManager.apk</code>\neingestellt ist, kann der zugehörige MIME-Typ\n<code>application/vnd.android.package-archive</code> sein.</section><section id=kategorien class=level4 data-number=2.8.1.4><h4 data-number=2.8.1.4><span class=header-section-number>2.8.1.4</span> Kategorien<a href=#kategorien class=anchor aria-hidden=true></a></h4><p>Dies ist ähnlich wie <a href=#subsubsec:action>Aktion</a> in dem\nSinne, dass es auch vom System zum Filtern von Anwendungskomponenten\nverwendet wird. Dies hat keine weiteren Vorteile. Im Gegensatz zu\n<em>Aktion</em> kann es mehr als eine Kategorie geben. Wenn Sie auf die\nSchaltfläche <em>plus</em> neben dem Titel klicken, können Sie weitere\nKategorien hinzufügen.</section><section id=flaggen class=level4 data-number=2.8.1.5><h4 data-number=2.8.1.5><span class=header-section-number>2.8.1.5</span> Flaggen<a href=#flaggen class=anchor aria-hidden=true></a></h4><p>Markierungen sind nützlich, um zu bestimmen, wie sich das System\nwährend des Starts oder nach dem Start einer Aktivität verhalten soll.\nDies sollte nicht berührt werden, da es ein gewisses technisches\nHintergrundwissen erfordert. Die Schaltfläche <em>plus</em> neben dem\nTitel kann verwendet werden, um eine oder mehrere Markierungen\nhinzuzufügen.</section><section id=extras class=level4 data-number=2.8.1.6><h4 data-number=2.8.1.6><span class=header-section-number>2.8.1.6</span> Extras<a href=#extras class=anchor aria-hidden=true></a></h4><p>Extras sind die Schlüssel-Wert-Paare, die für die Bereitstellung\nzusätzlicher Informationen für die Zielkomponente verwendet werden.\nWeitere Extras können über die Schaltfläche <em>plus</em> neben dem\nTitel hinzugefügt werden.</section><section id=uri class=level4 data-number=2.8.1.7><h4 data-number=2.8.1.7><span class=header-section-number>2.8.1.7</span> URI<a href=#uri class=anchor aria-hidden=true></a></h4><p>Stellt den gesamten Inhalt als URI dar (z. B.\n<code>intent://…</code>). Einige Daten können nicht in eine Zeichenkette\numgewandelt werden, und werden daher hier möglicherweise nicht\nangezeigt.</section></section><section id=subsec:matching-activities class=level3 data-number=2.8.2><h3 data-number=2.8.2><span class=header-section-number>2.8.2</span>\n<a href=#toc:subsec:matching-activities>Übereinstimmende\nAktivitäten</a><a href=#subsec:matching-activities class=anchor aria-hidden=true></a></h3><p>Listet alle Aktivitätskomponenten auf, die dem Zweck entsprechen.\nDies wird intern vom System bestimmt (und nicht vom App Manager). Die\nSchaltfläche \"Starten\" neben jeder Komponente kann verwendet werden, um\nsie direkt vom App Manager aus zu starten.</section><section id=subsec:interceptor-reset-to-default class=level3 data-number=2.8.3><h3 data-number=2.8.3><span class=header-section-number>2.8.3</span>\n<a href=#toc:subsec:interceptor-reset-to-default>Zurücksetzen auf\nStandard</a><a href=#subsec:interceptor-reset-to-default class=anchor aria-hidden=true></a></h3><p>Setzt das Objekt in seinen Ausgangszustand zurück.</section><section id=subsec:interceptor-send-edited-intent class=level3 data-number=2.8.4><h3 data-number=2.8.4><span class=header-section-number>2.8.4</span>\n<a href=#toc:subsec:interceptor-send-edited-intent>Geänderte Absicht\nsenden</a><a href=#subsec:interceptor-send-edited-intent class=anchor aria-hidden=true></a></h3><p>Sendet den bearbeiteten Inhalt erneut an die Zielanwendung. Dies kann\neine Liste von Anwendungen öffnen, in der die gewünschte Anwendung\nausgewählt werden muss. Das von der Zielanwendung erhaltene Ergebnis\nwird an die Quellanwendung gesendet. Daher weiß die Quellanwendung\nnicht, ob es einen Man-in-the-Middle gab.</section></section><section id=sec:shared-preferences-editor-page class=level2 data-number=2.9><h2 data-number=2.9><span class=header-section-number>2.9</span> <a href=#toc:sec:shared-preferences-editor-page>Editorseite für\ngemeinsame Einstellungen</a><a href=#sec:shared-preferences-editor-page class=anchor aria-hidden=true></a></h2><p>Gemeinsame Einstellungen können auf dieser Seite bearbeitet werden.\nWenn Sie auf ein Element in der Liste klicken, wird der\nBearbeitungsdialog geöffnet, in dem das Element bearbeitet werden kann.\nÜber die schwebende Aktionsschaltfläche in der unteren rechten Ecke kann\nein neues Element hinzugefügt werden. Zum Speichern oder Löschen der\nDatei, oder um aktuelle Änderungen zu verwerfen, können die\nentsprechenden Optionen im Menü verwendet werden.</section></section><section id=ch:guides class=level1 data-number=3><h1 data-number=3><span class=header-section-number>3</span> <a href=#toc:ch:guides>Leitlinien</a><a href=#ch:guides class=anchor aria-hidden=true></a></h1><section id=sec:adb-over-tcp class=level2 data-number=3.1><h2 data-number=3.1><span class=header-section-number>3.1</span> <a href=#toc:sec:adb-over-tcp>ADB über TCP</a><a href=#sec:adb-over-tcp class=anchor aria-hidden=true></a></h2><p>Viele reine Root-Funktionen können weiterhin genutzt werden, indem\nADB über TCP aktiviert wird. Hierfür ist ein PC oder Mac mit\ninstallierten Android Plattform-Tools und ein Android-Telefon mit\naktivierten Entwickleroptionen und USB-Debugging.<div class=\"amalert tip\"><p><strong><em>Root-Benutzer:</em></strong><p>Wenn dem App Manager die Superuser-Berechtigung erteilt wurde, kann\ner bereits ohne Probleme privilegierten Code ausführen. <strong>Daher\nbrauchen Root-Benutzer ADB über TCP nicht zu aktivieren.</strong> Wenn\nSie ADB over TCP trotzdem verwenden wollen, müssen Sie die\nSuperuser-Berechtigung für App Manager widerrufen und Ihr Gerät neu\nstarten. Es kann sein, dass Sie die Meldung <em>working on ADB mode</em>\nohne Neustart sehen, aber das ist nicht ganz richtig. Der Server (der\nals Schnittstelle zwischen System und App Manager dient) wird immer noch\nim Root-Modus ausgeführt. Dies ist ein bekanntes Problem und wird in\neiner zukünftigen Version von App Manager behoben.</div><div class=seealso-inline><p><em>Siehe auch: <span><a href=#sec:faq:adb-over-tcp>FAQ:\nADB-over-TCP</a></span></em></div><section id=subsec:enable-developer-options class=level3 data-number=3.1.1><h3 data-number=3.1.1><span class=header-section-number>3.1.1</span>\n<a href=#toc:subsec:enable-developer-options>Entwickleroptionen\naktivieren</a><a href=#subsec:enable-developer-options class=anchor aria-hidden=true></a></h3><section id=subsubsec:location-of-developer-options class=level4 data-number=3.1.1.1><h4 data-number=3.1.1.1><span class=header-section-number>3.1.1.1</span> Ort der\nEntwickleroptionen<a href=#subsubsec:location-of-developer-options class=anchor aria-hidden=true></a></h4><p><strong>Developer options</strong> is located in Android\n<strong>Settings</strong>, either directly near the bottom of the page\n(in most ROMs) or under some other settings, such as\n<strong>System</strong> (Google Pixel, Lineage OS, Asus Zenfone 8.0+),\n<strong>Additional Settings</strong> (Xiaomi MIUI, Oppo ColorOS),\n<strong>More Settings</strong> (Vivo FuntouchOS), <strong>More</strong>\n(ZTE Nubia). Unlike other options, it is not visible until explicitly\nenabled by the user. If it is already enabled, you can use the search\nbox in Android <strong>Settings</strong> to locate it as well.</section><section id=aktivieren-von-entwickleroptionen class=level4 data-number=3.1.1.2><h4 data-number=3.1.1.2><span class=header-section-number>3.1.1.2</span> Aktivieren von\nEntwickleroptionen<a href=#aktivieren-von-entwickleroptionen class=anchor aria-hidden=true></a></h4><p>This option is available within Android <strong>Settings</strong> as\nwell but like the location of the developer options, it also differs\nfrom device to device. But in general, you have to find <strong>Build\nnumber</strong> (or <strong>MIUI version</strong> for MIUI ROMs and\n<strong>Software version</strong> for Vivo FuntouchOS,\n<strong>Version</strong> for Oppo ColorOS) and tap it at least 7 (seven)\ntimes until you finally get a message saying <em>You are now a\ndeveloper</em> (you may be prompted to insert pin/password/pattern or\nsolve captchas at this point). In most devices, it is located at the\nbottom of the settings page, inside <strong>About Phone</strong>. But\nthe best way to find it is to use the search box.</section></section><section id=subsec:enable-usb-debugging class=level3 data-number=3.1.2><h3 data-number=3.1.2><span class=header-section-number>3.1.2</span>\n<a href=#toc:subsec:enable-usb-debugging>USB-Debugging\naktivieren</a><a href=#subsec:enable-usb-debugging class=anchor aria-hidden=true></a></h3><p>After <a href=#subsubsec:location-of-developer-options>locating the\ndeveloper options</a>, enable <strong>Developer option</strong> (if not\nalready). After that, scroll down a bit until you will find the option\n<strong>USB debugging</strong>. Use the toggle button on the right-hand\nside to enable it. At this point, you may get an alert prompt where you\nmay have to click <em>OK</em> to actually enable it. You may also have\nto enable some other options depending on device vendor and ROM. Here\nare some examples:<section id=xiaomi-miui class=level4 data-number=3.1.2.1><h4 data-number=3.1.2.1><span class=header-section-number>3.1.2.1</span> Xiaomi (MIUI)<a href=#xiaomi-miui class=anchor aria-hidden=true></a></h4><p>Enable <strong>USB debugging (Security settings)</strong> as\nwell.</section><section id=huawei-emui class=level4 data-number=3.1.2.2><h4 data-number=3.1.2.2><span class=header-section-number>3.1.2.2</span> Huawei (EMUI)<a href=#huawei-emui class=anchor aria-hidden=true></a></h4><p>Enable <strong>Allow ADB debugging in charge only mode</strong> as\nwell. When connecting to your PC or Mac, you may get a prompt saying\n<strong>Allow access to device data?</strong> in which case click\n<strong>YES, ALLOW ACCESS</strong>.<div class=\"amalert tip\"><p><strong><em>Notice:</em></strong><p>Often the <strong>USB debugging</strong> mode could be disabled\nautomatically by the system. If that’s the case, repeat the above\nprocedure.</div></section><section id=realme class=level4 data-number=3.1.2.3><h4 data-number=3.1.2.3><span class=header-section-number>3.1.2.3</span> Realme<a href=#realme class=anchor aria-hidden=true></a></h4><p>Depending on the device and the version of operating system, you have\nto enable <strong>Disable Permission Monitoring</strong>, or <strong>USB\ndebugging (Security settings)</strong> along with <strong>Install via\nUSB</strong>.</section><section id=oneplus-oxygen-os class=level4 data-number=3.1.2.4><h4 data-number=3.1.2.4><span class=header-section-number>3.1.2.4</span> OnePlus (Oxygen OS)<a href=#oneplus-oxygen-os class=anchor aria-hidden=true></a></h4><p>Depending on the device and the version of operating system, you have\nto enable <strong>Disable Permission Monitoring</strong>.</section><section id=lg class=level4 data-number=3.1.2.5><h4 data-number=3.1.2.5><span class=header-section-number>3.1.2.5</span> LG<a href=#lg class=anchor aria-hidden=true></a></h4><p>Make sure you have <strong>USB tethering</strong> enabled.</section><section id=fehlersuche class=level4 data-number=3.1.2.6><h4 data-number=3.1.2.6><span class=header-section-number>3.1.2.6</span> Fehlersuche<a href=#fehlersuche class=anchor aria-hidden=true></a></h4><p>In case <strong>USB Debugging</strong> is greyed out, you can do the\nfollowing:<ol class=incremental><li><p>Make sure you enabled USB debugging before connecting your phone\nto the PC or Mac via USB cable<li><p>Enable USB tethering after connecting to PC or Mac via USB\ncable<li><p>(For Samsung) If your device is running KNOX, you may have to\nfollow some additional steps. See official documentations or consult\nsupport for further assistant</ol></section></section><section id=subsec:setup-adb-on-pc-or-mac class=level3 data-number=3.1.3><h3 data-number=3.1.3><span class=header-section-number>3.1.3</span>\n<a href=#toc:subsec:setup-adb-on-pc-or-mac>ADB auf einem PC oder Mac\neinrichten</a><a href=#subsec:setup-adb-on-pc-or-mac class=anchor aria-hidden=true></a></h3><p>In order to enable ADB over TCP, you have to set up ADB in your PC or\nMac. <strong><em>Lineage OS users can skip to §<a href=#subsubsec:lineage-os data-reference-type=ref data-reference=subsubsec:lineage-os>3.1.4.1</a>.</em></strong><section id=windows class=level4 data-number=3.1.3.1><h4 data-number=3.1.3.1><span class=header-section-number>3.1.3.1</span> Windows<a href=#windows class=anchor aria-hidden=true></a></h4><ol class=incremental><li><p>Download the latest version of <a href=https://dl.google.com/android/repository/platform-tools-latest-windows.zip>Android\nSDK Platform-Tools</a> for Windows<li><p>Extract the contents of the zip file into any directory (such as\n<code>C:\\</code><span><code>adb</code></span>) and navigate to that\ndirectory using <em>Explorer</em><li><p>Open <strong>Command Prompt</strong>,\n<strong>PowerShell</strong>, or <strong>Terminal</strong> from this\ndirectory. You can do it manually from the start menu or by holding\n<code>Shift</code> and right clicking within the directory in <em>File\nExplorer</em> and then clicking either on <em>Open command window\nhere</em>, or <em>Open PowerShell window here</em> (depending on what\nyou have installed). You can now access ADB by typing <code>adb</code>\n(Command Prompt) or <code>./adb</code> (PowerShell). Do not close this\nwindow yet.</ol><div class=\"amalert tip\"><p><strong><em>Tip:</em></strong><p>If you have <a href=https://learn.microsoft.com/en-us/windows/package-manager/winget/>WinGet</a>\ninstalled, you can install ADB using the following command:<div class=sourceCode id=cb3 data-frame=lines><pre class=\"sourceCode bash\"><code class=\"sourceCode bash\"><span id=cb3-1><a href=#cb3-1 aria-hidden=true tabindex=-1></a><span class=ex>winget</span> install <span class=at>--id</span> Google.PlatformTools</span></code></pre></div><p>After that, you can simply type <code>adb</code> to access ADB.</div></section><section id=macos class=level4 data-number=3.1.3.2><h4 data-number=3.1.3.2><span class=header-section-number>3.1.3.2</span> macOS<a href=#macos class=anchor aria-hidden=true></a></h4><ol class=incremental><li><p>Download the latest version of <a href=https://dl.google.com/android/repository/platform-tools-latest-darwin.zip>Android\nSDK Platform-Tools</a> for macOS<li><p>Extract the contents of the zip file into a directory by clicking\non it. After that, navigate to that directory using <em>Finder</em> and\nlocate <code>adb</code><li><p>Open <strong>Terminal</strong> using <em>Launchpad</em> or\n<em>Spotlight</em> and drag-and-drop <code>adb</code> from the\n<em>Finder</em> window into the <em>Terminal</em> window. Do not close\nthe <em>Terminal</em> window yet</ol><div class=\"amalert tip\"><p><strong><em>Tip:</em></strong><p>If you have <a href=https://brew.sh>Homebrew</a> installed, you can\ninstall ADB using the following command:<div class=sourceCode id=cb4 data-frame=lines><pre class=\"sourceCode bash\"><code class=\"sourceCode bash\"><span id=cb4-1><a href=#cb4-1 aria-hidden=true tabindex=-1></a><span class=ex>brew</span> install <span class=at>--cask</span> android-platform-tools</span></code></pre></div><p>After that, you can simply type <code>adb</code> in any\n<em>Terminal</em> window to access ADB.</div></section><section id=linux class=level4 data-number=3.1.3.3><h4 data-number=3.1.3.3><span class=header-section-number>3.1.3.3</span> Linux<a href=#linux class=anchor aria-hidden=true></a></h4><ol class=incremental><li><p>In your favourite terminal emulator, run the following\ncommand:<div class=sourceCode id=cb5 data-frame=lines data-autogobble><pre class=\"sourceCode bash\"><code class=\"sourceCode bash\"><span id=cb5-1><a href=#cb5-1 aria-hidden=true tabindex=-1></a><span class=bu>cd</span> ~/Downloads <span class=kw>&amp;&amp;</span> <span class=ex>curl</span> <span class=at>-o</span> platform-tools.zip <span class=at>-L</span> <span class=dt>\\</span></span>\n<span id=cb5-2><a href=#cb5-2 aria-hidden=true tabindex=-1></a>https://dl.google.com/android/repository/platform-tools-latest-linux.zip <span class=kw>&amp;&amp;</span> <span class=dt>\\</span></span>\n<span id=cb5-3><a href=#cb5-3 aria-hidden=true tabindex=-1></a><span class=fu>unzip</span> platform-tools.zip <span class=kw>&amp;&amp;</span> <span class=fu>rm</span> platform-tools.zip <span class=kw>&amp;&amp;</span> <span class=bu>cd</span> platform-tools</span></code></pre></div><li><p>If it is successful, you can simply type <code>./adb</code> in\nthe in <em>same</em> terminal emulator window or type\n<code>~/Downloads/platform-tools/adb</code> in any terminal emulator to\naccess ADB.</ol></section></section><section id=subsec:configure-adb-over-tcp class=level3 data-number=3.1.4><h3 data-number=3.1.4><span class=header-section-number>3.1.4</span>\n<a href=#toc:subsec:configure-adb-over-tcp>ADB über TCP\neinrichten</a><a href=#subsec:configure-adb-over-tcp class=anchor aria-hidden=true></a></h3><section id=subsubsec:lineage-os class=level4 data-number=3.1.4.1><h4 data-number=3.1.4.1><span class=header-section-number>3.1.4.1</span> Lineage OS 17.1 und\nvorherige<a href=#subsubsec:lineage-os class=anchor aria-hidden=true></a></h4><p>Lineage OS (or its derivatives) users can directly enable ADB over\nTCP using the developer options. To enable that, go to the\n<strong>Developer options</strong>, scroll down until you find\n<strong>ADB over Network</strong>. Now, use the toggle button on the\nright-hand side to enable it and skip to §<a href=#subsubsec:adb-mode-in-app-manager data-reference-type=ref data-reference=subsubsec:adb-mode-in-app-manager>3.1.4.3</a>.<div class=\"amalert warning\"><p><strong><em>Warning:</em></strong><p>You can turn off <strong>ADB over Network</strong> in developer\noptions, but turning off this option will also stop App Manager’s remote\nserver. So, turn it off only when you’re not going to use App Manager in\nADB over TCP mode.</div></section><section id=subsubsec:enable-adb-over-tcp-via-pc-or-mac class=level4 data-number=3.1.4.2><h4 data-number=3.1.4.2><span class=header-section-number>3.1.4.2</span> ADB über TCP mittels einem\nPC oder Mac<a href=#subsubsec:enable-adb-over-tcp-via-pc-or-mac class=anchor aria-hidden=true></a></h4><p>For other ROMs, you can do this using the command\nprompt/PowerShell/terminal emulator that you’ve opened in the step 3 of\nthe previous section. In this section, I will use <code>adb</code> to\ndenote <code>./adb</code>, <code>adb</code> or any other command that\nyou needed to use based on your platform and software in the previous\nsection.<ol class=incremental><li><p>Connect your device to your PC or Mac using a USB cable. For some\ndevices, it is necessary to turn on <em>File transfer mode (MTP)</em> as\nwell<li><p>To confirm that everything is working as expected, type\n<code>adb devices</code> in your terminal. If your device is connected\nsuccessfully, you will see something like this:<pre><code>List of devices attached\nxxxxxxxx  device</code></pre><div class=\"amalert tip\"><p><strong><em>Notice:</em></strong><p>In some Android phones, an alert prompt will be appeared with a\nmessage <strong>Allow USB Debugging</strong> in which case, check\n<em>Always allow from this computer</em> and click\n<strong>Allow</strong>.</div><li><p>Finally, run the following command to enable ADB over TCP:<div class=sourceCode id=cb7 data-frame=lines data-autogobble><pre class=\"sourceCode bash\"><code class=\"sourceCode bash\"><span id=cb7-1><a href=#cb7-1 aria-hidden=true tabindex=-1></a><span class=ex>adb</span> tcpip 5555</span></code></pre></div></ol><div class=\"amalert danger\"><p><strong><em>Danger:</em></strong><p>You cannot disable developer options or USB debugging after enabling\nADB over TCP.</div></section><section id=subsubsec:adb-mode-in-app-manager class=level4 data-number=3.1.4.3><h4 data-number=3.1.4.3><span class=header-section-number>3.1.4.3</span> ADB-Modus im App Manager\naktivieren<a href=#subsubsec:adb-mode-in-app-manager class=anchor aria-hidden=true></a></h4><p>After enabling ADB over TCP, relaunch App Manager. App Manager should\ndetect ADB mode automatically. If it cannot, you can change the mode of\noperation to ADB over TCP in the <a href=#subsec:mode-of-operation>settings page</a>. There, you can also\nverify whether App Manager has correctly detected ADB as indicated by\nthe <em>inferred mode</em>.<div class=\"amalert tip\"><p><strong><em>Notice:</em></strong><p>In some Android devices, the USB cable is needed to be disconnected\nfrom the PC before connecting to App Manager.</div><div class=\"amalert warning\"><p><strong><em>Warning:</em></strong><p>ADB over TCP will be disabled after a reboot. In that case, you have\nto follow §<a href=#subsubsec:enable-adb-over-tcp-via-pc-or-mac data-reference-type=ref data-reference=subsubsec:enable-adb-over-tcp-via-pc-or-mac>3.1.4.2</a>\nagain.</div></section></section></section><section id=sec:wireless-debugging class=level2 data-number=3.2><h2 data-number=3.2><span class=header-section-number>3.2</span> <a href=#toc:sec:wireless-debugging>Wireless Debugging</a><a href=#sec:wireless-debugging class=anchor aria-hidden=true></a></h2><p>If you are running Android 11 or later and capable of connecting to a\nWi-Fi network for, at least, a few moments, Wireless Debugging is the\nrecommended approach as it offers more protection than <a href=#sec:adb-over-tcp>ADB over TCP</a>. It requires two steps:<ol class=incremental><li><p><strong>ADB pairing.</strong> The initial and a bit complex step\nfor a novice user. Fortunately, this step is not required all the\ntime.<li><p><strong>Connecting to ADB.</strong> Needs to be done every time\nyou reboot your phone. App Manager can also automate this step in most\ndevices.</ol><section id=subsec:enable-developer-options-and-usb-debugging class=level3 data-number=3.2.1><h3 data-number=3.2.1><span class=header-section-number>3.2.1</span>\n<a href=#toc:subsec:enable-developer-options-and-usb-debugging>Enable\ndeveloper options and USB Debugging</a><a href=#subsec:enable-developer-options-and-usb-debugging class=anchor aria-hidden=true></a></h3><p>See §<a href=#subsec:enable-developer-options data-reference-type=ref data-reference=subsec:enable-developer-options>3.1.1</a> and §<a href=#subsec:enable-usb-debugging data-reference-type=ref data-reference=subsec:enable-usb-debugging>3.1.2</a>.</section><section id=subsec:enable-wireless-debugging class=level3 data-number=3.2.2><h3 data-number=3.2.2><span class=header-section-number>3.2.2</span>\n<a href=#toc:subsec:enable-wireless-debugging>Enable Wireless\nDebugging</a><a href=#subsec:enable-wireless-debugging class=anchor aria-hidden=true></a></h3><p>In the <strong>Developer options</strong> page, find <strong>Wireless\ndebugging</strong> and click to open it. In the new page, turn on\n<em>Use wireless debugging</em>. Depending on the operating system, you\nmight see a dialog prompt asking you to verify your decision. If that is\nthe case, click <em>Allow</em>.<div class=\"amalert tip\"><p><strong><em>Tip:</em></strong><p>For easy access, you might want to add <strong>Wireless\ndebugging</strong> in the notification tiles section. To do this, find\n<strong>Quick settings developer tiles</strong> in the <strong>Developer\noptions</strong> page and click to open it. In the new window, enable\n<em>Wireless debugging</em>. In case you do not see this setting, you\nmay find a <strong>Wireless debugging</strong> tile in the tile\ncustomization panel.</div></section><section id=subsec:pair-adb-with-app-manager class=level3 data-number=3.2.3><h3 data-number=3.2.3><span class=header-section-number>3.2.3</span>\n<a href=#toc:subsec:pair-adb-with-app-manager>Pair ADB with App\nManager</a><a href=#subsec:pair-adb-with-app-manager class=anchor aria-hidden=true></a></h3><p>In App Manager, navigate to <strong>Settings</strong> > <a href=#subsec:mode-of-operation>Mode of operation</a> and then enable\n<em>Wireless debugging</em>. At this, App Manager will try to establish\na wireless debugging connection automatically which will fail if it has\nnot been paired before. Once it fails, it will ask you to either connect\nor pair ADB. Select <em>pair</em> and a new dialog will appear. It will\nask you to navigate to the <strong>Wireless debugging</strong> page.<div class=\"amalert tip\"><p><strong><em>Note:</em></strong><p>As of v4.0.0, pairing is done using a notification prompt. So, if you\nhave disabled notification for App Manager, you must enable it\nfirst.</div><p>In the <strong>Wireless debugging</strong> page, select <strong>Pair\ndevice with pairing code</strong>. At this, a dialog containing a\npairing code will be displayed. A notification asking for the pairing\ncode will also be visible almost instantly. Insert the pairing code in\nthe input box in the notification and click <em>pair</em>. If the\npairing is successful, App Manager will display notification with the\nmessage “paired”, and the dialog in the <strong>Wireless\ndebugging</strong> page will be dismissed automatically. You will also\nbe able to see App Manager listed as an ADB client in the same page.<div class=\"amalert tip\"><p><strong><em>Notice:</em></strong><p>If you do not use App Manager in ADB mode for a while, App Manager\nmight be removed from the list of clients. In that case, you have to\nrepeat the above procedure.</div></section><section id=subsec:connect-app-manager-to-adb class=level3 data-number=3.2.4><h3 data-number=3.2.4><span class=header-section-number>3.2.4</span>\n<a href=#toc:subsec:connect-app-manager-to-adb>Connect App Manager to\nADB</a><a href=#subsec:connect-app-manager-to-adb class=anchor aria-hidden=true></a></h3><p>App Manager should be able to connect to ADB automatically if the\nmode of operation is set to <em>auto</em>, <em>ADB over TCP</em> or\n<em>Wireless debugging</em>. If this is not the case, select\n<em>Wireless debugging</em> in <strong>Settings</strong> > <a href=#subsec:mode-of-operation>Mode of operation</a>. If App Manager\nfails to detect or connect to ADB, it will ask you to connect or pair\nADB. Select <em>connect</em>.<p>Now, navigate to the <strong>Wireless debugging</strong> page in\nAndroid settings, and note down the port number displayed in the page.\nIn App Manager’s dialog prompt, replace the port number with the one you\nhave noted earlier, and click <em>connect</em>.<p>Once a connection has been established, you can disable\n<strong>Wireless debugging</strong> in Android settings.<div class=\"amalert danger\"><p><strong><em>Caution:</em></strong><p>Never disable <strong>USB Debugging</strong> or any other additional\noptions described in §<a href=#subsec:enable-developer-options-and-usb-debugging data-reference-type=ref data-reference=subsec:enable-developer-options-and-usb-debugging>3.2.1</a>.\nIf you do this, the remote server used by App Manager will be stopped,\nand you may have to start all over again.</div></section></section><section id=sec:backup-restore class=level2 data-number=3.3><h2 data-number=3.3><span class=header-section-number>3.3</span> <a href=#toc:sec:backup-restore>Back up/Restore</a><a href=#sec:backup-restore class=anchor aria-hidden=true></a></h2><p>App Manager verfügt über ein modernes, fortschrittliches und einfach\nzu bedienendes Sicherungs-/Wiederherstellungssystem, das von Grund auf\nneu implementiert wurde. Dies ist wahrscheinlich die einzige App, die\nnicht nur die App oder ihre Daten wiederherstellen kann, sondern auch\ndie Berechtigungen und Regeln, die Sie im App Manager konfiguriert\nhaben. Sie können auch wählen, ob Sie eine App mehrfach (mit\nbenutzerdefinierten Namen) oder für alle Benutzer sichern möchten.<div class=seealso><p><em>Siehe auch:</em><ul class=incremental><li><p><a href=#subsec:1-click-back-up>1-Click Ops:\nSicherung</a><li><p><a href=#subsec:1-click-restore>1-Click Ops:\nWiederherstellung</a></ul></div><section id=subsec:backup-location class=level3 data-number=3.3.1><h3 data-number=3.3.1><span class=header-section-number>3.3.1</span>\n<a href=#toc:subsec:backup-location>Location</a><a href=#subsec:backup-location class=anchor aria-hidden=true></a></h3><p>Sichern/Wiederherstellen ist ein Teil von<a href=#subsec:batch-operations>Batch-Operationen</a>. Es befindet sich\nauch im <a href=#subsubsec:app-info-options-menu>Optionsmenü</a> in\nder <a href=#subsec:app-info-tab>Registerkarte Anwendungsinfo</a>.\nClicking on <strong>Backup/Restore</strong> opens the <strong>Backup\nOptions</strong>. Backups are located at\n<code>/storage/emulated/0/AppManager</code> by default. You can\nconfigure custom backup location in the <a href=#subsubsec:backup-volume>settings page</a> in which case the\nbackups will be located at the <code>AppManager</code> folder in the\nselected volume.<div class=\"amalert tip\"><p><strong><em>Hinweis:</em></strong><p>Wenn eine oder mehrere ausgewählte Anwendungen keine Sicherung haben,\nwerden die Optionen <strong>Wiederherstellen</strong> and\n<strong>Sicherung löschen</strong> nicht angezeigt.</div></section><section id=subsec:backup-restore-backup-options class=level3 data-number=3.3.2><h3 data-number=3.3.2><span class=header-section-number>3.3.2</span>\n<a href=#toc:subsec:backup-restore-backup-options>Backup Options</a><a href=#subsec:backup-restore-backup-options class=anchor aria-hidden=true></a></h3><p>Mit den Backup-Optionen (intern als Backup-Flags bezeichnet) können\nSie die Backups im Handumdrehen anpassen. Die Anpassungen werden jedoch\nnicht für zukünftige Sicherungen gespeichert. Wenn Sie diesen Dialog\nanpassen möchten, verwenden Sie <a href=#subsubsec:settings-backup-options>Backup-Optionen</a> in der <a href=#sec:settings-page>Einstellungen-Seite</a>.<p>Eine vollständige Beschreibung der Sicherungsoptionen finden Sie\nweiter unten:<ul class=incremental><li><p><strong>APK-Dateien.</strong> Whether to back up the APK files.\nThis includes the <em>base APK</em> file along with the\n<code>split APK</code> files if they exist.<li><p><strong>Internal data.</strong> Ob die APK-Dateien gesichert\nwerden sollen. Dies umfasst die Datei <em>Basis-APK</em> sowie die\nDateien <code>Split-APK</code>, falls vorhanden.<li><p><strong>External data.</strong> Whether to back up data\ndirectories located in the internal memory as well as SD Card (if\nexists). External data directories often contain non-essential app data\nor media files (instead of using the dedicated media folder) and may\nincrease the backup size. However, it might be essential for some apps.\nAlthough it isn’t checked by default (as it might dramatically increase\nthe size of the backups), you may have to check it in order to ensure a\nsmooth restore of your backups.<div class=\"amalert warning\"><p><strong><em>Caution:</em></strong><p>Internal data folders should always be backed up if you are going to\nback up the external data folders. However, it could be useful to back\nup only the external folders if the app in question downloads a lot of\nassets from the Internet.</div><li><p><strong>OBB and media.</strong> Whether to back up or restore the\nOBB and the media directories located in the external storage or the SD\nCard. This is useful for games and the graphical software which actually\nuse these folders.<li><p><strong>Cache.</strong> Android apps have multiple cache\ndirectories located at every data directories (both internal and\nexternal). There are two types of cache: <strong>cache</strong> and\n<strong>code cache</strong>. Enabling this option excludes both cache\ndirectories from all the data directories. It is generally advised to\nexclude cache directories since most apps do not clear the cache\nregularly (for some reason, the only way an app can clear its cache is\nby deleting the entire cache directory) and usually handled by the OS\nitself. Apps such as Telegram may use a very large cache (depending on\nthe storage space) which may dramatically increase the backup size. When\nit is disabled, AM also ignores the <strong>no_backup</strong>\ndirectories.<li><p><strong>Extras.</strong> Backup/restore app permissions, net\npolicy, battery optimization, SSAID, etc., enabled by default. Note\nthat, blocking rules are applied <em>after</em> applying the extras. So,\nif an item is present in both places, it will be overwritten (i.e., the\none from the blocking rules will be used).<li><p><strong>Rules.</strong> This option lets you back up blocking\nrules configured within App Manager. This might come in handy if you\nhave customised permissions or block some components using App Manager\nas they will also be backed up or restored when you enable this\noption.<li><p><strong>Backup Multiple.</strong> Whether this is a multiple\nbackup. By default, backups are saved using their user ID. Enabling this\noption allows you to create additional backups. These backups use the\ncurrent date-time as the default backup name, but you can also specify\ncustom backup name using the input field displayed when you click on the\n<strong>Backup</strong> button.<li><p><strong>Ausgewählte Anwender.</strong> Sicherung oder\nWiederherstellung für die ausgewählten Benutzer statt nur für den\naktuellen Benutzer. Diese Option wird nur angezeigt, wenn das System\nmehr als einen Benutzer hat.<li><p><strong>Signaturprüfungen überspringen.</strong> Beim Erstellen\neines Backups werden die Prüfsummen jeder Datei (sowie die Signier-\nZertifikat(e) der APK-Basisdatei) generiert und in der Datei\n<code>checksums.txt</code> gespeichert. Wenn Sie die Sicherung\nwiederherstellen, werden die Prüfsummen erneut generiert und mit den in\nder genannten Datei gespeicherten Prüfsummen abgeglichen. Wenn Sie diese\nOption aktivieren, werden die Signaturprüfungen ausgeschaltet. Diese\nOption wird nur bei der Wiederherstellung eines Backups angewendet.\nWährend der Sicherung werden die Prüfsummen unabhängig von dieser Option\ngeneriert.<div class=\"amalert warning\"><p><strong><em>Caution:</em></strong><p>Sie sollten diese Option immer deaktivieren, um sicherzustellen, dass\nIhre Sicherungen nicht von Anwendungen Dritter verändert werden. Dies\nwürde jedoch nur funktionieren, wenn Sie die Verschlüsselung aktiviert\nhaben.</div></ul><div class=seealso-inline><p><em>Siehe auch: <span><a href=#subsubsec:settings-encryption>Einstellungen:\nVerschlüsselung</a></span></em></div></section><section id=subsec:backup-restore-backup class=level3 data-number=3.3.3><h3 data-number=3.3.3><span class=header-section-number>3.3.3</span>\n<a href=#toc:subsec:backup-restore-backup>Sicherung</a><a href=#subsec:backup-restore-backup class=anchor aria-hidden=true></a></h3><p>Backup respects all the backup options except <strong>Skip signature\nchecks</strong>. If base backups (i.e., backups that don’t have the\n<strong>Backup Multiple</strong> option) already exist, you will get a\nwarning as the backups will be overwritten. If <strong>Backup\nMultiple</strong> is set, you have an option to input the backup name,\nor you can leave it blank to use the current date-time.</section><section id=subsec:backup-restore-restore class=level3 data-number=3.3.4><h3 data-number=3.3.4><span class=header-section-number>3.3.4</span>\n<a href=#toc:subsec:backup-restore-restore>Wiederherstellung</a><a href=#subsec:backup-restore-restore class=anchor aria-hidden=true></a></h3><p>Restore respects all the backup options and will fail if <strong>APK\nfiles</strong> option is set, but the backup doesn’t contain such\nbackups or in other cases, if the app isn’t installed. When restoring\nbackups for multiple packages, you can only restore the base backups\n(see <a href=#subsec:backup-restore-backup>backup</a> section for an\nexplanation). However, when restoring backups for a single package, you\nhave the option to select which backup to restore. If <strong>All\nusers</strong> option is set, AM will restore the selected backup for\nall users in the latter case but in the former case, it will restore\nbase backups for the respective users.<div class=\"amalert tip\"><p><strong><em>Notice:</em></strong><p>Apps that use storage access framework (SAF), SSAID or Android\nKeyStore works properly only after an immediate restart.</div></section><section id=subsec:backup-restore-delete-backup class=level3 data-number=3.3.5><h3 data-number=3.3.5><span class=header-section-number>3.3.5</span>\n<a href=#toc:subsec:backup-restore-delete-backup>Sicherung\nlöschen</a><a href=#subsec:backup-restore-delete-backup class=anchor aria-hidden=true></a></h3><p>Delete backup only respects <strong>All users</strong> option and\nwhen it is selected, only the base backups for all users will be deleted\nwith a prompt. When deleting backups for a single package, another\ndialog will be displayed where you can select the backups to delete.</section></section><section id=sec:automating-tasks class=level2 data-number=3.4><h2 data-number=3.4><span class=header-section-number>3.4</span> <a href=#toc:sec:automating-tasks>Automating Tasks</a><a href=#sec:automating-tasks class=anchor aria-hidden=true></a></h2><p>It is possible to trigger profiles configured inside App Manager via\nthird-party applications such as <strong>Automation</strong> or\n<strong>Tasker</strong>. Traditionally, <code>Intent</code>s are used to\ntrigger such operations.<section id=subsec:generating-authorization-key class=level3 data-number=3.4.1><h3 data-number=3.4.1><span class=header-section-number>3.4.1</span>\n<a href=#toc:subsec:generating-authorization-key>Generating\nauthorization key</a><a href=#subsec:generating-authorization-key class=anchor aria-hidden=true></a></h3><p>In order to ensure proper security, an authorization key is required.\nTo generate a authorization key, go to <strong>Settings</strong> page\nand then <strong>Privacy</strong> > <strong>Authorization\nManager</strong>. If an authorization key has not been generated, it\nwill be generated automatically. The key can be regenerated as\nrequired.<div class=\"amalert danger\"><p><strong><em>Caution:</em></strong><p>Regenerating the authorization key can have some side effects such as\ninvalidation of all the previously configured Intents.</div></section><section id=subsec:at:general-configuration class=level3 data-number=3.4.2><h3 data-number=3.4.2><span class=header-section-number>3.4.2</span>\n<a href=#toc:subsec:at:general-configuration>Configuring tasks</a><a href=#subsec:at:general-configuration class=anchor aria-hidden=true></a></h3><p>The activity\n<code>io.github.muntashirakon.AppManager.crypto.auth.AuthFeatureDemultiplexer</code>\nis responsible for handling all the automations. Sending an intent to\nthe activity lets App Manager perform the designated operation by\nredirecting the <code>Intent</code> to the designated activity or\nservice.<section id=required-extras class=level4 data-number=3.4.2.1><h4 data-number=3.4.2.1><span class=header-section-number>3.4.2.1</span> Required extras<a href=#required-extras class=anchor aria-hidden=true></a></h4><p>It has two primary extras required in all conditions. The key names,\ndata types are all follows:<ol class=incremental><li><p><strong><code>auth</code>.</strong> (String value) The\nauthorization key as described in the earlier section.<li><p><strong><code>feature</code>.</strong> (String value) Name of the\nfeature. Supported features are described in the next section.</ol></section></section><section id=subsec:at:features class=level3 data-number=3.4.3><h3 data-number=3.4.3><span class=header-section-number>3.4.3</span>\n<a href=#toc:subsec:at:features>Features</a><a href=#subsec:at:features class=anchor aria-hidden=true></a></h3><p>App Manager current support a single feature, namely\n<code>profile</code>.</section><section id=subsec:triggering-a-profile class=level3 data-number=3.4.4><h3 data-number=3.4.4><span class=header-section-number>3.4.4</span>\n<a href=#toc:subsec:triggering-a-profile>Triggering a profile</a><a href=#subsec:triggering-a-profile class=anchor aria-hidden=true></a></h3><p>In order to trigger a profile, <code>feature</code> must have the\nvalue <code>profile</code>. In addition, the following extras can be\nincluded:<ol class=incremental><li><p><strong><code>prof</code>.</strong> (String value – required) The\nname of the profile as displayed in the <a href=#sec:profiles-page>Profiles page</a>.<li><p><strong><code>state</code>.</strong> (String value – optional)\nState of the profile – currently <code>on</code> or <code>off</code> –\nas specified in the documentation. If this extra is not set, App Manager\nwill display a prompt where a state must be selected. Therefore, for\ncomplete automation, this option should be set.</ol></section></section><section id=sec:net-policy class=level2 data-number=3.5><h2 data-number=3.5><span class=header-section-number>3.5</span> <a href=#toc:sec:net-policy>Net Policy</a><a href=#sec:net-policy class=anchor aria-hidden=true></a></h2><p>Short for <strong>Network policy</strong> or network policies. It is\nusually located in the Android settings under <strong>Mobile data &\nWifi</strong> section in the app info page of an app. Not all policies\nare guaranteed to be included in this page (e.g. Samsung), and not all\nsettings are well-understood due to lack of documentation. App Manager\ncan display all the net policies declared in the <a href=https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/net/NetworkPolicyManager.java>NetworkPolicyManager</a>.\nPolicies unknown to App Manager will have a <em>Unknown</em> prefix\nalong with the policy constant name and number in the hexadecimal\nformat. Unknown policies should be reported to App Manager for\ninclusion.<p>Net policy allows a user to configure certain networking behaviour of\nan app without modifying the ip tables directly and/or running a\nfirewall app. However, the features it offers largely depend on Android\nversion and ROM. A list of known net policies are listed below:<ol class=incremental><li><p><strong>None</strong> or\n<strong><code>POLICY_NONE</code></strong>: (AOSP) No specific network\npolicy is set. System can still assign rules depending on the nature of\nthe app.<li><p><strong>Reject background data on metered networks</strong> or\n<strong><code>POLICY_REJECT_METERED_BACKGROUND</code></strong>: (AOSP)\nReject network usage on metered networks when the application is in\nbackground.<li><p><strong>Allow background data on metered networks even when Data\nSaver is on</strong> or\n<strong><code>POLICY_ALLOW_METERED_BACKGROUND</code></strong>: (AOSP)\nAllow metered network use in the background even when data saving mode\nis enabled.<li><p><strong>Reject cellular data</strong> or\n<strong><code>POLICY_REJECT_CELLULAR</code></strong> (Android 11+) or\n<strong><code>POLICY_REJECT_ON_DATA</code></strong> (up to Android 10):\n(Lineage OS) Reject mobile/cellular data. Signals network unavailable to\nthe configured app as if the mobile data is inactive.<li><p><strong>Reject VPN data</strong> or\n<strong><code>POLICY_REJECT_VPN</code></strong> (Android 11+) or\n<strong><code>POLICY_REJECT_ON_VPN</code></strong> (up to Android 10):\n(Lineage OS) Reject VPN data. Signals network unavailable to the\nconfigured app as if the VPN is inactive.<li><p><strong>Reject Wi-Fi data</strong> or\n<strong><code>POLICY_REJECT_WIFI</code></strong> (Android 11+) or\n<strong><code>POLICY_REJECT_ON_WLAN</code></strong> (up to Android 10):\n(Lineage OS) Reject Wi-Fi data. Signals network unavailable to the\nconfigured app as if the device is not connected to a Wi-Fi\nnetwork.<li><p><strong>Disable network access</strong> or\n<strong><code>POLICY_REJECT_ALL</code></strong> (Android 11+) or\n<strong><code>POLICY_NETWORK_ISOLATED</code></strong> (up to Android\n10): (Lineage OS) Reject network access in all circumstances. This is\nnot the same as enforcing the other three policies above, and is the\nrecommended policy for dodgy apps. If this policy is enforced, there is\nno need to enforce the other policies.<li><p><strong><code>POLICY_ALLOW_METERED_IN_ROAMING</code></strong>:\n(Samsung) Possibly allow metered network use during roaming. Exact\nmeaning is currently unknown.<li><p><strong><code>POLICY_ALLOW_WHITELIST_IN_ROAMING</code></strong>:\n(Samsung) Possibly allow network use during roaming. Exact meaning is\ncurrently unknown.<li><p><strong>Reject data on metered networks</strong> or\n<strong><code>POLICY_REJECT_METERED</code></strong>: (Motorola) Reject\nnetwork usage if it is a metered network.<li><p><strong>Reject background data</strong> or\n<strong><code>POLICY_REJECT_BACKGROUND</code></strong>: (Motorola)\nReject network usage in the background.<li><p><strong>Disable network access</strong> or\n<strong><code>POLICY_REJECT_ALL</code></strong>: (Motorola) Reject\nnetwork access altogether. Like Lineage OS, it blocks internet\nconnections via iptables. But whether it signals the unavailability of\nnetwork to the configured app is not known.</ol><div class=\"amalert tip\"><p><strong><em>Note:</em></strong><p>Corresponding Lineage OS patches are as follows:<ol class=incremental><li><p><a href=https://github.com/LineageOS/android_frameworks_base/commit/a04932bafbbf7d99efd18276152cc2c9c9b2073e>fw/b:\nSquash of app fw restriction commits</a><li><p><a href=https://github.com/LineageOS/android_frameworks_base/commit/02c8c82854348f52afe2199f310f44b5f578b5b8>fw/b:\nAdd support for per app network isolation</a></ol></div></section></section><section id=ch:faq class=level1 data-number=4><h1 data-number=4><span class=header-section-number>4</span> <a href=#toc:ch:faq>Frequently Asked Questions</a><a href=#ch:faq class=anchor aria-hidden=true></a></h1><section id=sec:faq:app-components class=level2 data-number=4.1><h2 data-number=4.1><span class=header-section-number>4.1</span> <a href=#toc:sec:faq:app-components>App Components</a><a href=#sec:faq:app-components class=anchor aria-hidden=true></a></h2><section id=subsec:faq:what-are-app-components class=level3 data-number=4.1.1><h3 data-number=4.1.1><span class=header-section-number>4.1.1</span>\n<a href=#toc:subsec:faq:what-are-app-components>What are the\napplication components?</a><a href=#subsec:faq:what-are-app-components class=anchor aria-hidden=true></a></h3><p>Activities, services, broadcast receivers (or only receivers) and\ncontent providers (or only providers) are jointly called application\ncomponents. More technically, they all inherit the <a href=https://developer.android.com/reference/android/content/pm/ComponentInfo>ComponentInfo</a>\nclass and can be launched via Intent.</section><section id=subsec:faq:how-components-blocked class=level3 data-number=4.1.2><h3 data-number=4.1.2><span class=header-section-number>4.1.2</span>\n<a href=#toc:subsec:faq:how-components-blocked>How are the tracker and\nother components blocked in App Manager? What are its limitations?</a><a href=#subsec:faq:how-components-blocked class=anchor aria-hidden=true></a></h3><p>App Manager typically blocks application components (or tracker\ncomponents) using a method called <a href=https://carteryagemann.com/pages/android-intent-firewall.html>Intent\nFirewall (IFW)</a>, it is superior to other methods such as <em>pm</em>\n(PackageManager), <a href=https://github.com/RikkaApps/Shizuku>Shizuku</a> or any other\nmethod that uses the package manager to enable or disable the\ncomponents. If a component is disabled by the latter methods, the\napplication itself can detect that the component is being blocked and\ncan re-enable it as it has full access to its own components. (Many\ndeceptive applications actually do this in order to keep the tracker\ncomponents unblocked.) On the other hand, IFW is a true firewall and the\napplication cannot detect if its components are being blocked. App\nManager uses the term <em>block</em> rather than <em>disable</em> for\nthis reason.<p>Even IFW has some limitations which are primarily applicable for the\nsystem applications:<ul class=incremental><li><p>The application in question is whitelisted by the system i.e. the\nsystem cannot function properly without these applications and may cause\nrandom crashes. These applications include but not limited to Android\nSystem, System UI, Phone Services. They will continue to work even if\nthey are disabled or blocked.<li><p>Another system application or system process has activated a\nspecific component of the application in question via interprocess\ncommunication (IPC). In this case, the component will be activated\nregardless of blocking status or even if the entire application is\ndisabled. If there is such a system application that is not needed, the\nonly way to prevent it from running is by getting rid of it.</ul></section><section id=subsec:faq:components-blocked-by-others class=level3 data-number=4.1.3><h3 data-number=4.1.3><span class=header-section-number>4.1.3</span>\n<a href=#toc:subsec:faq:components-blocked-by-others>Does app\ncomponents blocked by other tools retained in App Manager?</a><a href=#subsec:faq:components-blocked-by-others class=anchor aria-hidden=true></a></h3><p><strong>No.</strong> But the application components blocked by the\nsystem or any other tools are displayed in the <a href=#subsec:component-tabs>component tabs</a>. These rules can be\nimported from <a href=#par:import-existing-rules>Settings</a>.\nHowever, it is not possible for App Manager to distinguish the\ncomponents blocked by the third-party tools and components blocked by\nthe system. Therefore, the applications listed in the import page should\nbe selected with care.</section><section id=subsec:faq:components-reblocked-in-am class=level3 data-number=4.1.4><h3 data-number=4.1.4><span class=header-section-number>4.1.4</span>\n<a href=#toc:subsec:faq:components-reblocked-in-am>What happens to the\ncomponents blocked by App Manager which were previously blocked by other\ntools?</a><a href=#subsec:faq:components-reblocked-in-am class=anchor aria-hidden=true></a></h3><p><em>App Manager blocks the components again</em> if requested. In\ncase of unblocking, they will be reverted to the default state as\nspecified in the manifest of the application. But if the components were\nblocked by <a href=https://www.myandroidtools.com>MyAndroidTools\n(MAT)</a> with IFW method, they will not be unblocked by App Manager as\nit uses a different format. To fix this issue, the rules have to be\nimported from <a href=#par:import-existing-rules>Settings</a> at\nfirst, in which case MAT’s configurations will be permanently\nremoved.</section><section id=subsec:faq:what-is-instant-component-blocking class=level3 data-number=4.1.5><h3 data-number=4.1.5><span class=header-section-number>4.1.5</span>\n<a href=#toc:subsec:faq:what-is-instant-component-blocking>What is\ninstant component blocking?</a><a href=#subsec:faq:what-is-instant-component-blocking class=anchor aria-hidden=true></a></h3><p>When you block a component in the <a href=#sec:app-details-page>App\nDetails page</a>, the blocking is not applied by default. It is only\napplied when you apply blocking using the <em>Apply rules</em> option in\nthe top-right menu. If you enable <a href=#subsubsec:instant-component-blocking>instant component\nblocking</a>, blocking will be applied as soon as you block a component.\nIf you choose to block tracker components, however, blocking is applied\nautomatically regardless of this setting. You can also remove blocking\nfor an application by simply clicking on <em>Remove rules</em> in the\nsame menu in the <strong>App Details page</strong>. Since the default\nbehaviour gives you more control over applications, it is better to keep\n<em>instant component blocking</em> option disabled.</section><section id=subsec:tracker-classes-versus-tracker-components class=level3 data-number=4.1.6><h3 data-number=4.1.6><span class=header-section-number>4.1.6</span>\n<a href=#toc:subsec:tracker-classes-versus-tracker-components>Tracker\nclasses versus tracker components</a><a href=#subsec:tracker-classes-versus-tracker-components class=anchor aria-hidden=true></a></h3><p>All application components are classes but not all classes are\ncomponents. In fact, only a few of the classes are components. That\nbeing said, <a href=#sec:scanner-page>scanner page</a> displays a list\nof trackers along with the number of classes, not just the components.\nIn all other pages, trackers and tracker components are used\nsynonymously to denote tracker components, i.e. blocking tracker means\nblocking tracker components, not tracker classes.<div class=\"amalert tip\"><p><strong><em>Info:</em></strong><p>Tracker classes that are not components cannot be blocked. They can\nonly be removed by editing the application itself.</div></section></section><section id=sec:faq:adb-over-tcp class=level2 data-number=4.2><h2 data-number=4.2><span class=header-section-number>4.2</span> <a href=#toc:sec:faq:adb-over-tcp>ADB over TCP</a><a href=#sec:faq:adb-over-tcp class=anchor aria-hidden=true></a></h2><section id=subsec:faq:enable-adb-on-every-restart class=level3 data-number=4.2.1><h3 data-number=4.2.1><span class=header-section-number>4.2.1</span>\n<a href=#toc:subsec:faq:enable-adb-on-every-restart>Do I have to\nenable ADB over TCP everytime I restart?</a><a href=#subsec:faq:enable-adb-on-every-restart class=anchor aria-hidden=true></a></h3><p>Unfortunately, yes. This is because the ADB daemon, the process\nresponsible for ADB connection, is also restarted after a reboot, and it\ndoes not re-enable ADB over TCP.</section><section id=subsec:faq:usb-debugging class=level3 data-number=4.2.2><h3 data-number=4.2.2><span class=header-section-number>4.2.2</span>\n<a href=#toc:subsec:faq:usb-debugging>Cannot enable USB debugging.\nWhat to do?</a><a href=#subsec:faq:usb-debugging class=anchor aria-hidden=true></a></h3><p>See §<a href=#subsec:enable-usb-debugging data-reference-type=ref data-reference=subsec:enable-usb-debugging>3.1.2</a> in Kapitel <a href=#ch:guides data-reference-type=ref data-reference=ch:guides>3</a>.</section><section id=subsec:faq:block-components-using-adb class=level3 data-number=4.2.3><h3 data-number=4.2.3><span class=header-section-number>4.2.3</span>\n<a href=#toc:subsec:faq:block-components-using-adb>Can I block tracker\nor any other application components using ADB over TCP?</a><a href=#subsec:faq:block-components-using-adb class=anchor aria-hidden=true></a></h3><p>ADB has limited number of <a href=https://github.com/aosp-mirror/platform_frameworks_base/blob/master/packages/Shell/AndroidManifest.xml>permissions</a>\nand controlling application components is not one of them. However, the\ncomponents of a <em>test-only</em> app can be controlled via ADB. If App\nManager detects such an application, it enables the blocking options\nautomatically.</section><section id=subsec:faq:adb-features class=level3 data-number=4.2.4><h3 data-number=4.2.4><span class=header-section-number>4.2.4</span>\n<a href=#toc:subsec:faq:adb-features>Which features can be used in ADB\nmode?</a><a href=#subsec:faq:adb-features class=anchor aria-hidden=true></a></h3><p>Die unterstützten Funktionen werden im ADB-Modus automatisch\naktiviert. Zu den unterstützten Funktionen gehören Deaktivieren,\nerzwungenes Anhalten, Löschen von Anwendungsdaten, Gewähren oder\nEntziehen von App-Ops und Berechtigungen usw. Es ist auch möglich,\nAnwendungen zu installieren oder Anwendungen ohne Aufforderung durch das\nSystem zu installieren oder zu deinstallieren.</section></section><section id=sec:faq:miscellanea class=level2 data-number=4.3><h2 data-number=4.3><span class=header-section-number>4.3</span> <a href=#toc:sec:faq:miscellanea>Sonstiges</a><a href=#sec:faq:miscellanea class=anchor aria-hidden=true></a></h2><section id=subsec:faq:no-root-no-harms class=level3 data-number=4.3.1><h3 data-number=4.3.1><span class=header-section-number>4.3.1</span>\n<a href=#toc:subsec:faq:no-root-no-harms>Ich verwende kein root/ADB.\nBin ich völlig vor irgendwelchen Schäden sicher?</a><a href=#subsec:faq:no-root-no-harms class=anchor aria-hidden=true></a></h3><p>Ja. AM kann keine Systemeinstellungen ohne Root oder ADB over\nTCPändern.</section><section id=subsec:faq:how-trackers-libs-updated class=level3 data-number=4.3.2><h3 data-number=4.3.2><span class=header-section-number>4.3.2</span>\n<a href=#toc:subsec:faq:how-trackers-libs-updated>Wie werden die\nTracker und Bibliotheken aktualisiert?</a><a href=#subsec:faq:how-trackers-libs-updated class=anchor aria-hidden=true></a></h3><p>Tracker und Bibliotheken werden manuell aktualisiert, bevor eine neue\nVersion veröffentlicht wird.</section><section id=subsec:faq:apks-deleted-after-installed class=level3 data-number=4.3.3><h3 data-number=4.3.3><span class=header-section-number>4.3.3</span>\n<a href=#toc:subsec:faq:apks-deleted-after-installed>Are APKs deleted\nafter installed?</a><a href=#subsec:faq:apks-deleted-after-installed class=anchor aria-hidden=true></a></h3><p>No, APKs aren’t deleted by App Manager after they are installed.</section><section id=subsec:faq:shizuku-support class=level3 data-number=4.3.4><h3 data-number=4.3.4><span class=header-section-number>4.3.4</span>\n<a href=#toc:subsec:faq:shizuku-support>Gibt es Pläne für\nShizuku?</a><a href=#subsec:faq:shizuku-support class=anchor aria-hidden=true></a></h3><p>Die Verwendung von versteckten APIs und die Ausführung von\nprivilegiertem Code durch App Manager ist jetzt viel komplexer und kann\nnicht mit anderen Anwendungen von Drittanbietern wie z. B. <a href=https://shizuku.rikka.app>Shizuku</a>. Hier sind einige Gründe\nfür die Nichtberücksichtigung von Shizuku (das jetzt die Apache 2.0\nLizenz hat) durch den App Manager:<ol class=incremental><li><p>Shizuku war ursprünglich unfrei, was mich dazu veranlasste, einen\nähnlichen Ansatz für App Manager zu verwenden, um sowohl root und ADB zu\nnutzen<li><p>App Manager unterstützt bereits sowohl ADB als auch Root, was in\neinigen Fällen leistungsfähiger ist als Shizuku<li><p>Sich für die wichtigsten Funktionen auf eine Drittanbieter-App zu\nverlassen, ist keine gute Designentscheidung<li><p>Die Integration von Shizuku wird die Komplexität des App Managers\nerhöhen.</ol></section><section id=subsec:faq:what-are-bloatware class=level3 data-number=4.3.5><h3 data-number=4.3.5><span class=header-section-number>4.3.5</span>\n<a href=#toc:subsec:faq:what-are-bloatware>Was ist Bloatware und wie\nkann man sie entfernen?</a><a href=#subsec:faq:what-are-bloatware class=anchor aria-hidden=true></a></h3><p>Bei Bloatware handelt es sich um überflüssige Anwendungen, die vom\nHersteller oder OEM geliefert werden und in der Regel Systemanwendungen\nsind. Diese Anwendungen werden oft verwendet, um Benutzer zu verfolgen\nund Benutzerdaten zu sammeln, die sie möglicherweise gewinnbringend\nverkaufen. System-Apps müssen keine Erlaubnis einholen, um auf\nGeräteinformationen, Kontakte und Nachrichtendaten sowie auf andere\nNutzungsdaten wie Ihre Gewohnheiten und alles, was Sie auf Ihrem\ngemeinsamen Speicher speichern, zugreifen zu können.<p>Die Bloatware umfassen auch Google-Apps (wie Google Play Services,\nGoogle Play Store, Gmail, Google, Messages, Dialer, Kontakte),\nFacebook-Apps (die Facebook-App besteht aus vier oder fünf Apps),\nFacebook Messenger, Instagram, Twitter und viele andere Apps, die\nebenfalls Nutzer verfolgen und/oder Nutzerdaten ohne Zustimmung sammeln\nkönnen, da sie alle System-Apps sind. Sie können einige Berechtigungen\nin den Android-Einstellungen deaktivieren, aber seien Sie sich bewusst,\ndass die Android-Einstellungen fast jede Berechtigung versteckt, die ein\nSicherheitsexperte als potenziell gefährlich bezeichnen würde.<p>Wenn es sich bei der Bloatware um Benutzeranwendungen handelt, können\nSie sie entweder über die Android-Einstellungen oder über AM\ndeinstallieren. Die Deinstallation von System- Apps ist ohne\nRoot-Berechtigung nicht möglich. Sie können System-Apps auch mit ADB\ndeinstallieren, aber das funktioniert möglicherweise nicht bei allen\nApps. AM kann System-Apps mit Root oder ADB deinstallieren (letzteres\nnatürlich mit gewissen Einschränkungen), aber diese Methoden können die\nSystemanwendungen nicht vollständig entfernen, da sie sich in der\nPartition <em>system</em> befinden, die eine schreibgeschützte Partition\nist. Wenn Sie über Root verfügen, können Sie diese Partition wieder\neinhängen, um diese Anwendungen manuell zu entfernen, aber dies wird\nOver the Air (OTA)-Updates unterbrechen, da die Daten in der\nSystempartition geändert wurden. Es gibt zwei Arten von Updates, Delta-\n(eine kleine Version, die nur die Änderungen zwischen zwei Versionen\nenthält) und vollständige Updates. Sie können weiterhin vollständige\nUpdates anwenden, aber die Bloatware wird erneut installiert, und Sie\nmüssen sie daher erneut löschen. Außerdem bieten nicht alle Hersteller\nvollständige Aktualisierungen an.<p>Eine andere Lösung besteht darin, diese Apps entweder über die\nAndroid-Einstellungen (No-Root) oder AM zu deaktivieren, aber bestimmte\nDienste können weiterhin im Hintergrund laufen, da sie von anderen\nSystemanwendungen unter Verwendung von Interprozesskommunikation (IPC)\ngestartet werden können. Eine mögliche Lösung ist es, alle Bloatware zu\ndeaktivieren, bis der Dienst endgültig beendet ist (nach einem\nNeustart). Aufgrund der starken Änderungen an den Android-Frameworks\ndurch die Hersteller kann das Entfernen oder Deaktivieren bestimmter\nBloatware jedoch zum Absturz der System-UI oder sogar einen Bootloop\nverursachen, was zu einem (Soft-)Bricking Ihres Geräts führt. Sie können\nim Internet suchen oder andere Benutzer befragen um mehr darüber\nherauszufinden, wie Sie Ihr Gerät debloaten können.<p>Ab v2.5.19 verfügt AM über eine neue Funktion namens <a href=#sec:profile-page>Profile</a>. Die <a href=#sec:profiles-page>Seite Profile</a> bietet die Möglichkeit, neue\nProfile aus einer der Voreinstellungen zu erstellen. Die\nVoreinstellungen bestehen aus Debloating-Profilen, die als Ausgangspunkt\nfür die Überwachung, Deaktivierung und Entfernung von Bloatware von\neinem proprietären Android-Betriebssystem.<div class=\"amalert warning\"><p><strong><em>Hinweis:</em></strong><p>In den meisten Fällen können Sie Ihr Gerät nicht vollständig\ndebloaten. Daher empfiehlt es sich, ein benutzerdefiniertes ROM zu\nverwenden, wie Graphene OS, Lineage OS oder deren Derivate, die frei von\nBloatware sind.</div></section></section></section><section id=ch:specifications class=level1 data-number=5><h1 data-number=5><span class=header-section-number>5</span> <a href=#toc:ch:specifications>Spezifikationen</a><a href=#ch:specifications class=anchor aria-hidden=true></a></h1><section id=sec:rules-specification class=level2 data-number=5.1><h2 data-number=5.1><span class=header-section-number>5.1</span> <a href=#toc:sec:rules-specification>Regeln Spezifikationen</a><a href=#sec:rules-specification class=anchor aria-hidden=true></a></h2><section id=hintergrund class=level3 data-number=5.1.1><h3 data-number=5.1.1><span class=header-section-number>5.1.1</span>\n<a href=#toc:hintergrund>Hintergrund</a><a href=#hintergrund class=anchor aria-hidden=true></a></h3><p>AM unterstützt derzeit das Sperren von Aktivitäten,\nBroadcast-Empfängern, Inhaltsanbietern, Diensten, App-Ops und\nBerechtigungen, und in Zukunft werde ich möglicherweise weitere\nBlockierungsoptionen hinzufügen. Um die Portabilität zu erhöhen, ist es\nnotwendig, alle diese Daten zu importieren/exportieren. dieser\nDaten.<p>Die Pflege einer Datenbank sollte die beste Wahl sein, wenn es um die\nSpeicherung von Daten geht. Im Moment werden mehrere\n<code>tsv</code>-Dateien wobei jede Datei den Namen des Pakets und eine\n<code>.tsv</code>-Erweiterung hat. Die Datei/Datenbank wird\nabgefragt/verarbeitet durch die Klasse\n<code>RegelSpeicherManager</code>. Aufgrund dieser Abstraktion sollte es\nin Zukunft einfacher sein, auf Datenbank- oder verschlüsselte\nDatenbanksysteme zu wechseln, ohne das Design des gesamten Projekts zu\nändern. Derzeit werden alle Konfigurations Dateien unter\n<code>/data/data/io.github.muntashirakon.AppManager/Files/conf</code>\ngespeichert.</section><section id=regeln-dateiformat class=level3 data-number=5.1.2><h3 data-number=5.1.2><span class=header-section-number>5.1.2</span>\n<a href=#toc:regeln-dateiformat>Regeln Dateiformat</a><a href=#regeln-dateiformat class=anchor aria-hidden=true></a></h3><section id=intern class=level4 data-number=5.1.2.1><h4 data-number=5.1.2.1><span class=header-section-number>5.1.2.1</span> Intern<a href=#intern class=anchor aria-hidden=true></a></h4><p>Das folgende Format wird intern in App Manager verwendet und ist\nnicht mit dem externen Format kompatibel.<pre><code> &lt;Name&gt; &lt;Typ&gt; &lt;Modus&gt;|&lt;Komponente_Status&gt;|&lt;ist_gewährt&gt;</code></pre><p>Hier:<ul class=incremental><li><p><code>&lt;Name></code> – Name der Komponente/Zulassung/App-Op\n(im Falle einer App-Op kann es sich um einen String oder eine ganze Zahl\nhandeln)<li><p><code>&lt;Typ></code> – Eines der Elemente\n<code>ACTIVITY</code>, <code>RECEIVER</code>, <code>PROVIDER</code>,\n<code>SERVICE</code>, <code>App_OP</code>,\n<code>PERMISSION</code><li><p><code>&lt;Modus></code> – (Für app ops) Die zugehörige <a href=#subsec:mode-constants>mode constant</a><li><p><code>&lt;Komponente_Status></code> – (Für Komponenten)\nKomponentenstatus<ul class=incremental><li><p><code>wahr</code> – Die Komponente wurde angewendet (der Wert\n<code>wahr</code> wird aus Kompatibilitätsgründen beibehalten)<li><p><code>falsch</code> – Die Komponente wurde noch nicht angewendet,\nwird aber in Zukunft angewendet (der Wert <code>falsch</code> wird aus\nKompatibilitätsgründen beibehalten)<li><p><code>freigeschaltet</code> – Die Komponente soll freigegeben\nwerden</ul><li><p><code>&lt;ist_gewährt></code> – (Für Berechtigungen) Ob die\nBerechtigung erteilt oder entzogen ist</ul></section><section id=extern class=level4 data-number=5.1.2.2><h4 data-number=5.1.2.2><span class=header-section-number>5.1.2.2</span> Extern<a href=#extern class=anchor aria-hidden=true></a></h4><p>Externes Format wird zum Importieren oder Exportieren von Regeln in\nApp Manager verwendet.<pre><code> &lt;Paketname&gt; &lt;Komponentenname&gt; &lt;Typ&gt; &lt;Modus&gt;|&lt;Komponentenstatus&gt;|&lt;ist_gewährt&gt;</code></pre><p>Das Format ist im Wesentlichen dasselbe wie oben, mit Ausnahme des\nersten Elements, das der Name des Pakets ist.<div class=\"amalert danger\"><p><strong><em>Vorsicht:</em></strong><p>Die exportierten Regeln haben ein anderes Format als die internen\nRegeln und sollten nicht direkt in die Datei\n<strong>conf</strong>-Ordner kopiert werden.</div></section></section></section></section><section id=ch:changelogs class=level1 data-number=6><h1 data-number=6><span class=header-section-number>6</span> <a href=#toc:ch:changelogs>Änderungsprotokolle</a><a href=#ch:changelogs class=anchor aria-hidden=true></a></h1><section id=sec:v4.0.5-(445) class=level2 data-number=6.1><h2 data-number=6.1><span class=header-section-number>6.1</span> <a href=#toc:sec:v4.0.5-(445)>v4.0.5 (445)</a><a href=#sec:v4.0.5-(445) class=anchor aria-hidden=true></a></h2><ul class=incremental><li><p>Added option to allow installing the existing applications in the\ninstaller page<li><p>Display unsafe bloatware info<li><p>Display vector icon on the splash screen in Android 7.1 and\nearlier<li><p>Enabled “Clear data from uninstalled apps” to no-root users in\n1-click ops page<li><p>Enabled predictive back in Android 14 onwards<li><p>Improved accessibility by updating the content description of the\naction items<li><p>In app info tab, open “Open by default” setting in the “Open\nlinks” dialog<li><p>In debloater page, sort by app label (or app name) rather than\npackage name<li><p>Fixed freezing an app with “Remember for this app” turned\non<li><p>Fixed selecting texts in the list items due to framework\nbugs<li><p>Fixed setting app ops in custom ROMs with MIUI properties\ninjected<li><p>Fixed updating profile modification status when an application is\ndeleted from the list<li><p>Handled common colors and cursor movements in terminal\noutput.</ul></section><section id=sec:v4.0.4-(444) class=level2 data-number=6.2><h2 data-number=6.2><span class=header-section-number>6.2</span> <a href=#toc:sec:v4.0.4-(444)>v4.0.4 (444)</a><a href=#sec:v4.0.4-(444) class=anchor aria-hidden=true></a></h2><ul class=incremental><li><p>Optimized searching and filtering in the main page<li><p>Adopted sentence-case for the titles<li><p>Use the configured state to execute a profile for the simple\nshortcuts<li><p>Prevented crashing while searching throughout the\napplication<li><p>Fixed integer overflow issue in the tar compression.</ul></section><section id=sec:v4.0.3-(443) class=level2 data-number=6.3><h2 data-number=6.3><span class=header-section-number>6.3</span> <a href=#toc:sec:v4.0.3-(443)>v4.0.3 (443)</a><a href=#sec:v4.0.3-(443) class=anchor aria-hidden=true></a></h2><ul class=incremental><li><p>Updated translations<li><p>Improved handling the list items throughout App Manager<li><p>Fixed a regression error in file manager<li><p>Fixed spinners in the App Usage and the System Config\npages.</ul></section><section id=sec:v4.0.2-(442) class=level2 data-number=6.4><h2 data-number=6.4><span class=header-section-number>6.4</span> <a href=#toc:sec:v4.0.2-(442)>v4.0.2 (442)</a><a href=#sec:v4.0.2-(442) class=anchor aria-hidden=true></a></h2><ul class=incremental><li><p>Updated bloatware<li><p>Fixed fetching applications in multi-user environment in no-root\nmode<li><p>Fixed opening <code>app-manager</code> URLs from the web\nbrowsers<li><p>Fixed updating SSAID<li><p>Prevented a crash in Android &lt; 9.0 that occurs due to invalid\napp ops.</ul></section><section id=sec:v4.0.1-(441) class=level2 data-number=6.5><h2 data-number=6.5><span class=header-section-number>6.5</span> <a href=#toc:sec:v4.0.1-(441)>v4.0.1 (441)</a><a href=#sec:v4.0.1-(441) class=anchor aria-hidden=true></a></h2><section id=overlay-management class=level3 data-number=6.5.1><h3 data-number=6.5.1><span class=header-section-number>6.5.1</span>\n<a href=#toc:overlay-management>Overlay management</a><a href=#overlay-management class=anchor aria-hidden=true></a></h3><p>In the App Details page, a new tab “Overlays” is added where per-app\noverlays are displayed. They can also be enabled or disabled using the\ntoggle button. In addition, if the App Details page of an overlay\npackage is opened, a “Overlay” tag will be displayed in the App Info\ntab. Clicking on the tag opens a dialog containing additional info along\nwith a button that allows navigating to the App Details page of the\noverlay target package if it is installed.<section id=known-limitation class=level5 data-number=6.5.1.0.1><h5 data-number=6.5.1.0.1><span class=header-section-number>6.5.1.0.1</span> Known limitation<a href=#known-limitation class=anchor aria-hidden=true></a></h5><p>At present, it only works for root/ADB users in Android 8 (Oreo) and\nlater.</section></section><section id=unfreeze-option-in-activity-shortcuts class=level3 data-number=6.5.2><h3 data-number=6.5.2><span class=header-section-number>6.5.2</span>\n<a href=#toc:unfreeze-option-in-activity-shortcuts>Unfreeze option in\nactivity shortcuts</a><a href=#unfreeze-option-in-activity-shortcuts class=anchor aria-hidden=true></a></h3><p>If the application corresponding to the shortcut being launched is\nfrozen, App Manager will now offer you to unfreeze the app temporarily\nso that the shortcut can be launched. The app will be frozen again once\nthe screen is locked.<section id=known-limitation-1 class=level5 data-number=6.5.2.0.1><h5 data-number=6.5.2.0.1><span class=header-section-number>6.5.2.0.1</span> Known limitation<a href=#known-limitation-1 class=anchor aria-hidden=true></a></h5><p>This may not work on devices without a screen lock or if the screen\nis locked some time after the display goes off.</section></section><section id=market-like-url-support class=level3 data-number=6.5.3><h3 data-number=6.5.3><span class=header-section-number>6.5.3</span>\n<a href=#toc:market-like-url-support><code>market</code>-like URL\nsupport</a><a href=#market-like-url-support class=anchor aria-hidden=true></a></h3><p>Third-party applications can now open the App Details page of any\ninstalled package by invoking an Intent with an URL with the following\nformat:<pre><code>app-manager://details?id=&lt;pkg&gt;&amp;user=&lt;user_id&gt;</code></pre><p>where <code>&lt;pkg></code> stands for package name, and\n<code>&lt;user_id></code> stands for the user ID which is\noptional.</section><section id=updated-color-codes class=level3 data-number=6.5.4><h3 data-number=6.5.4><span class=header-section-number>6.5.4</span>\n<a href=#toc:updated-color-codes>Updated color codes</a><a href=#updated-color-codes class=anchor aria-hidden=true></a></h3><p>In order to improve accessibility, certain color codes have been\nimproved. Visit <a href=app-manager://settings/about/version>Settings\n> About > Version/Changelog</a> for details.</section><section id=others class=level3 data-number=6.5.5><h3 data-number=6.5.5><span class=header-section-number>6.5.5</span>\n<a href=#toc:others>Others</a><a href=#others class=anchor aria-hidden=true></a></h3><ul class=incremental><li><p>Avoided waiting for the remote server to respond when no-root\nmode is set<li><p>Fixed downgrading apps in Android 10 onwards<li><p>Fixed installer issues in the Huawei stock operating\nsystems<li><p>Improved text formatting in the “What’s New” dialog<li><p>In the UI tracker window, fixed clicking on the icon after it is\niconified<li><p>Updated bloatware and suggestions</ul></section></section><section id=sec:v4.0.0-(440) class=level2 data-number=6.6><h2 data-number=6.6><span class=header-section-number>6.6</span> <a href=#toc:sec:v4.0.0-(440)>v4.0.0 (440)</a><a href=#sec:v4.0.0-(440) class=anchor aria-hidden=true></a></h2><p>App Manager v4.0.0 comes with a lot of new features and improvements.\nVisit <a href=app-manager://settings/about/version>Settings > About\n> Version/Changelog</a> for details.<section id=new-logo class=level3 data-number=6.6.1><h3 data-number=6.6.1><span class=header-section-number>6.6.1</span>\n<a href=#toc:new-logo>New logo!</a><a href=#new-logo class=anchor aria-hidden=true></a></h3><p>The new logo is just a cursive “A”. The design is based on the <a href=https://freetengwar.sourceforge.net/>Tengwar Telcontar</a> font\nwhich was created to bring the Tengwar script, originally created by J.\nR. R. Tolkien, to the digital world. The letter has the classic App\nManager color (i.e., #dcaf74) and uses a pure black background instead\nof a shade of grey.</section><section id=android-14-and-15-support class=level3 data-number=6.6.2><h3 data-number=6.6.2><span class=header-section-number>6.6.2</span>\n<a href=#toc:android-14-and-15-support>Android 14 and 15 support</a><a href=#android-14-and-15-support class=anchor aria-hidden=true></a></h3><p>App Manager now targets Android 14 and fully supports Android 15.<section id=known-issue class=level5 data-number=6.6.2.0.1><h5 data-number=6.6.2.0.1><span class=header-section-number>6.6.2.0.1</span> Known issue<a href=#known-issue class=anchor aria-hidden=true></a></h5><p>KeyStore backup/restore is not working in Android 12 and later.</section></section><section id=revamped-debloater class=level3 data-number=6.6.3><h3 data-number=6.6.3><span class=header-section-number>6.6.3</span>\n<a href=#toc:revamped-debloater>Revamped debloater</a><a href=#revamped-debloater class=anchor aria-hidden=true></a></h3><p>Debloating profiles were available as “Presets” in the Profiles page\nwhich has now been replaced with the Debloater page and can be accessed\nfrom the three-dots menu in the Main page. <a href=https://github.com/MuntashirAkon/android-debloat-list>ADL</a> is\na new project that focuses on maintaining a list of bloatware as well as\npotential open source alternatives. Contributions are welcome!</section><section id=introducing-file-manager class=level3 data-number=6.6.4><h3 data-number=6.6.4><span class=header-section-number>6.6.4</span>\n<a href=#toc:introducing-file-manager>Introducing file manager</a><a href=#introducing-file-manager class=anchor aria-hidden=true></a></h3><p>App Manager offers an (almost) fully-featured file manager with basic\nfile operations, such as copy, cut, rename, and delete along with the\nbatch operations. It also offers an extensive “Open with…” dialog to\nopen a file with another app, and a comprehensive file properties\nviewer. Folders can also be added to the list of favorites for quick\naccess. And many more.</section><section id=integrated-code-editor class=level3 data-number=6.6.5><h3 data-number=6.6.5><span class=header-section-number>6.6.5</span>\n<a href=#toc:integrated-code-editor>Integrated code editor</a><a href=#integrated-code-editor class=anchor aria-hidden=true></a></h3><p>Manifest and code viewers have been replaced with this new editor.\nAmong other regular features, it includes proper syntax highlighting and\nadvanced searching options. In addition, files from third-party apps can\nalso be opened for editing.</section><section id=history-of-operations class=level3 data-number=6.6.6><h3 data-number=6.6.6><span class=header-section-number>6.6.6</span>\n<a href=#toc:history-of-operations>History of operations</a><a href=#history-of-operations class=anchor aria-hidden=true></a></h3><p>All 1-click operations, batch operations, and profile invocations are\nnow stored as history. The history items can also be executed from the\nHistory page. To ensure consistency, the profile state, configurations,\npackage list are also stored, and this stored version is executed\ninstead of the actual profile. As a result, this works even if the\nprofile is deleted.</section><section id=per-app-freezing-and-more class=level3 data-number=6.6.7><h3 data-number=6.6.7><span class=header-section-number>6.6.7</span>\n<a href=#toc:per-app-freezing-and-more>Per-app freezing, and\nmore</a><a href=#per-app-freezing-and-more class=anchor aria-hidden=true></a></h3><p>Freeze/unfreeze feature now supports setting per-app freezing method\nwhich is beneficial in certain scenarios, such as when a user want to\nsuspend some apps while using the disable method as the default. In\naddition, an “Advanced suspend” option is added which force-stops an\napplication before suspending it, thus, prevent it’s services from\nrunning in the background.</section><section id=log-viewer-enhancements class=level3 data-number=6.6.8><h3 data-number=6.6.8><span class=header-section-number>6.6.8</span>\n<a href=#toc:log-viewer-enhancements>Log viewer enhancements</a><a href=#log-viewer-enhancements class=anchor aria-hidden=true></a></h3><p>Log viewer now supports enhanced searching and filtering options,\nsuch as keyword- and regular expression-based searching and filtering.\nPlease read the in-app changelog for details. Support for batch\noperations has also been added.</section><section id=launching-non-exported-activities class=level3 data-number=6.6.9><h3 data-number=6.6.9><span class=header-section-number>6.6.9</span>\n<a href=#toc:launching-non-exported-activities>Launching non-exported\nactivities</a><a href=#launching-non-exported-activities class=anchor aria-hidden=true></a></h3><p>App Manager now supports launching non-exported activities in no-root\nand ADB mode. However, in no-root mode,\n<code>android.permission.WRITE_SECURE_SETTINGS</code> permission is\nrequired.</section><section id=new-tags-in-app-info-tab class=level3 data-number=6.6.10><h3 data-number=6.6.10><span class=header-section-number>6.6.10</span> <a href=#toc:new-tags-in-app-info-tab>New tags in App Info tab</a><a href=#new-tags-in-app-info-tab class=anchor aria-hidden=true></a></h3><p>Five new tags are added in the App Info tab. They are: bloatware,\nXposed, sensors disabled, open links, and static shared libs. Clicking\non “bloatware” will display more information regarding the bloatware and\nsuggest alternatives, “Xposed” tag will display dependency information,\n“open links” will display a list of links supported by the application,\nand “static shared libs” will display all version of the application\ninstalled in the system along with an option to uninstall them. The\nlatter is useful for applications, such as Trichrome.<section id=known-issue-1 class=level5 data-number=6.6.10.0.1><h5 data-number=6.6.10.0.1><span class=header-section-number>6.6.10.0.1</span> Known issue<a href=#known-issue-1 class=anchor aria-hidden=true></a></h5><p>“Sensors disabled” only works real-time. That means if the\napplication is not currently active, this tag will always display even\nthough the applications may use sensors while it is running. This is a\nframework limitation and nothing can be done to avoid it\neffectively.</section></section><section id=per-session-installer-options class=level3 data-number=6.6.11><h3 data-number=6.6.11><span class=header-section-number>6.6.11</span> <a href=#toc:per-session-installer-options>Per-session installer\noptions</a><a href=#per-session-installer-options class=anchor aria-hidden=true></a></h3><p>It is not possible to modify installer options during the\ninstallation by clicking on the “settings” button in the installation\ndialog. The installer options will be applied to all the applications\ninstalled in the same session (i.e., the installer queue).</section><section id=advanced-mode-of-operations-adb-enhancements class=level3 data-number=6.6.12><h3 data-number=6.6.12><span class=header-section-number>6.6.12</span> <a href=#toc:advanced-mode-of-operations-adb-enhancements>Advanced mode\nof operations, ADB enhancements, …</a><a href=#advanced-mode-of-operations-adb-enhancements class=anchor aria-hidden=true></a></h3><p>App Manager now supports running its remote server (which is used as\na proxy for running privileged operations) as any supported user (UID).\nThis includes root (0), system (1000), and shell/ADB (2000) through the\ncustom commands. This is also useful for Fire TVs which have disabled\nconnecting to ADB from localhost through socket connection. In addition,\nADB pairing is now done using notifications rather than split screen.\nADB connection speed can also be improved by choosing to run App Manager\nin the background which can be configured in the settings.</section><section id=data-usage-widget-and-more class=level3 data-number=6.6.13><h3 data-number=6.6.13><span class=header-section-number>6.6.13</span> <a href=#toc:data-usage-widget-and-more>Data usage widget, and more</a><a href=#data-usage-widget-and-more class=anchor aria-hidden=true></a></h3><p>Data usage widget display the total data usage for the day, similar\nto the screen time widget which displays the total screen time for the\nday. In addition, existing widgets have been improved.</section><section id=others-1 class=level3 data-number=6.6.14><h3 data-number=6.6.14><span class=header-section-number>6.6.14</span> <a href=#toc:others-1>Others</a><a href=#others-1 class=anchor aria-hidden=true></a></h3><ul class=incremental><li><p>Replaced log viewer, sys config, Terminal, etc. with Labs\npage<li><p>Added an option to disable sensors for each app in the App Info\ntab<li><p>Added an option to perform runtime optimization of applications\nin the 1-click Ops page and in the App Info tab<li><p>Added support for Zstandard compression for\nbackup/restore<li><p>Enabling APK signing now automatically enables zip align\nfeature<li><p>Support exporting application list as CSV or JSON in the batch\noperations<li><p>Added pure black theme support<li><p>Display current activity name (when possible) in the UI Tracker\nwindow<li><p>Added an option to filter apps by user in the Main page<li><p>Display a link to Pithus report in the scanner page if\navailable.</ul></section></section><section id=sec:v3.1.0-(423) class=level2 data-number=6.7><h2 data-number=6.7><span class=header-section-number>6.7</span> <a href=#toc:sec:v3.1.0-(423)>v3.1.0 (423)</a><a href=#sec:v3.1.0-(423) class=anchor aria-hidden=true></a></h2><p>App Manager v3.1.0 comes with a few new features and a lot of\nimprovements. Visit <a href=app-manager://settings/about/version>Settings > About >\nVersion/Changelog</a> for details.<section id=android-13-support class=level3 data-number=6.7.1><h3 data-number=6.7.1><span class=header-section-number>6.7.1</span>\n<a href=#toc:android-13-support>Android 13 support</a><a href=#android-13-support class=anchor aria-hidden=true></a></h3><p>App Manager now targets Android 13 which means most issues in Android\n12 and 13 has been addressed, including SSAID and SAF issues as well as\nmonochrome icons and other theming issues.<section id=known-issue-2 class=level5 data-number=6.7.1.0.1><h5 data-number=6.7.1.0.1><span class=header-section-number>6.7.1.0.1</span> Known issue<a href=#known-issue-2 class=anchor aria-hidden=true></a></h5><p>KeyStore backup/restore not working in Android 12 and later.</section></section><section id=introducing-freezeunfreeze class=level3 data-number=6.7.2><h3 data-number=6.7.2><span class=header-section-number>6.7.2</span>\n<a href=#toc:introducing-freezeunfreeze>Introducing\nfreeze/unfreeze</a><a href=#introducing-freezeunfreeze class=anchor aria-hidden=true></a></h3><p>Enable/disable is replaced with freeze/unfreeze to allow greater\ncontrol on the behaviours of an app. It supports suspend, disable and\nhide functionalities which can be controlled at <a href=app-manager://settings/rules_prefs/freeze_type>Settings >\nRules > Default freezing method</a>. In order to make it easy to\nfreeze or unfreeze an app, shortcuts can also be created from the App\nInfo tab by long clicking on the freeze or unfreeze button.</section><section id=export-app-list class=level3 data-number=6.7.3><h3 data-number=6.7.3><span class=header-section-number>6.7.3</span>\n<a href=#toc:export-app-list>Export app list</a><a href=#export-app-list class=anchor aria-hidden=true></a></h3><p>In the Main page, it is now possible to export the list of apps in\neither XML or Markdown format using batch operations. In the future, the\nXML file may also be imported to App Manager.</section><section id=elliptic-curve-crypography-ecc class=level3 data-number=6.7.4><h3 data-number=6.7.4><span class=header-section-number>6.7.4</span>\n<a href=#toc:elliptic-curve-crypography-ecc>Elliptic Curve Crypography\n(ECC)</a><a href=#elliptic-curve-crypography-ecc class=anchor aria-hidden=true></a></h3><p>App Manager now fully supports encrypting backups using ECC in\naddition to offering AES, RSA and OpenPGP.</section><section id=new-languages class=level3 data-number=6.7.5><h3 data-number=6.7.5><span class=header-section-number>6.7.5</span>\n<a href=#toc:new-languages>New languages</a><a href=#new-languages class=anchor aria-hidden=true></a></h3><p>Two new languages are added: Korean and Romanian.</section><section id=more-list-options class=level3 data-number=6.7.6><h3 data-number=6.7.6><span class=header-section-number>6.7.6</span>\n<a href=#toc:more-list-options>More list options</a><a href=#more-list-options class=anchor aria-hidden=true></a></h3><p>In the main page, more sorting and filtering options are added.\nSorting options include sorting the apps by total size, total data\nusage, launch count, screen time and last usage time. Filtering options\ninclude filtering the apps having at least one item in the Android\nKeyStore, filtering apps with URIs granted via SAF, and filtering apps\nwith SSAID.</section><section id=improved-handling-of-mode-of-operation class=level3 data-number=6.7.7><h3 data-number=6.7.7><span class=header-section-number>6.7.7</span>\n<a href=#toc:improved-handling-of-mode-of-operation>Improved handling\nof mode of operation</a><a href=#improved-handling-of-mode-of-operation class=anchor aria-hidden=true></a></h3><p>Fixed various issues with ADB pairing, handled incomplete USB\ndebugging. Some rooting methods cannot allow interprocess communication\nvia Binder. In those cases, ADB mode is used as a fallback method by\nenabling it automatically if possible.</section><section id=handling-multiple-users class=level3 data-number=6.7.8><h3 data-number=6.7.8><span class=header-section-number>6.7.8</span>\n<a href=#toc:handling-multiple-users>Handling multiple users</a><a href=#handling-multiple-users class=anchor aria-hidden=true></a></h3><p>When possible, App Manager will be able to display apps from work\nprofile in no-root mode in addition to allowing basic operations such as\nlaunching the app or navigating to the system settings. For backups, it\nis now possible to restore backups for other users, but for work\nprofile, some apps may only work properly after re-enabling the work\nprofile. In the installer page, selecting <em>All users</em> will now\ninstall the app for all users instead of only the current user. Finally,\nin the app info tab, current app can be installed in another profile\nusing the <em>Install for…</em> option available in the three-dots menu.\nThis is analogous to the <code>pm install-existing</code> command,\nthereby, making the installation process a lot faster.</section><section id=explorer-enhancements class=level3 data-number=6.7.9><h3 data-number=6.7.9><span class=header-section-number>6.7.9</span>\n<a href=#toc:explorer-enhancements>Explorer enhancements</a><a href=#explorer-enhancements class=anchor aria-hidden=true></a></h3><p>Explorer can now open DEX and JAR files in addition to APK files.\nSeveral sorting options as well as folder options are also added as the\nlist options.</section><section id=new-tag-wx class=level3 data-number=6.7.10><h3 data-number=6.7.10><span class=header-section-number>6.7.10</span> <a href=#toc:new-tag-wx>New tag: WX</a><a href=#new-tag-wx class=anchor aria-hidden=true></a></h3><p>In app info tab, a new tag called WX is added. It is displayed in\nAndroid 10 and later if the application targets Android 9 or earlier. It\nindicates <a href=https://en.wikipedia.org/wiki/W%5EX>W^X</a>\nviolation which allows the app to execute arbitrary executable files\neither by the modification of executables embedded within the app or by\ndownloading them from the Internet.</section><section id=app-ops-management class=level3 data-number=6.7.11><h3 data-number=6.7.11><span class=header-section-number>6.7.11</span> <a href=#toc:app-ops-management>App ops management</a><a href=#app-ops-management class=anchor aria-hidden=true></a></h3><p>App ops are now managed automatically to avoid various app ops\nrelated crashes in various platforms. This will also lessen the amount\nof crashes in an unsupported operating system.</section><section id=batch-uninstallation class=level3 data-number=6.7.12><h3 data-number=6.7.12><span class=header-section-number>6.7.12</span> <a href=#toc:batch-uninstallation>Batch uninstallation</a><a href=#batch-uninstallation class=anchor aria-hidden=true></a></h3><p>In the Main page, enabled batch uninstallation in no-root mode.</section><section id=running-apps class=level3 data-number=6.7.13><h3 data-number=6.7.13><span class=header-section-number>6.7.13</span> <a href=#toc:running-apps>Running apps</a><a href=#running-apps class=anchor aria-hidden=true></a></h3><p>Enabled advanced searching. Searching now matches not only app labels\nbut also package names.</section><section id=interceptor class=level3 data-number=6.7.14><h3 data-number=6.7.14><span class=header-section-number>6.7.14</span> <a href=#toc:interceptor>Interceptor</a><a href=#interceptor class=anchor aria-hidden=true></a></h3><p>Copy the intercepted Intent as am command which can be run from\neither an ADB shell or a terminal using root with the same\neffectiveness.</section><section id=device-specific-changes class=level3 data-number=6.7.15><h3 data-number=6.7.15><span class=header-section-number>6.7.15</span> <a href=#toc:device-specific-changes>Device-specific changes</a><a href=#device-specific-changes class=anchor aria-hidden=true></a></h3><section id=graphene-os class=level5 data-number=6.7.15.0.1><h5 data-number=6.7.15.0.1><span class=header-section-number>6.7.15.0.1</span> Graphene OS<a href=#graphene-os class=anchor aria-hidden=true></a></h5><p>Explicitly handle the Internet permission which is a runtime\npermission in the OS.</section><section id=miui class=level5 data-number=6.7.15.0.2><h5 data-number=6.7.15.0.2><span class=header-section-number>6.7.15.0.2</span> MIUI<a href=#miui class=anchor aria-hidden=true></a></h5><p>Fixed permission denied issues in the installer due to a framework\nissue introduced in MIUI 12.5.</section><section id=motorola class=level5 data-number=6.7.15.0.3><h5 data-number=6.7.15.0.3><span class=header-section-number>6.7.15.0.3</span> Motorola<a href=#motorola class=anchor aria-hidden=true></a></h5><p>Fixed crashes in the Interceptor page due to a framework issue\nintroduced in Android 11.</section></section><section id=others-2 class=level3 data-number=6.7.16><h3 data-number=6.7.16><span class=header-section-number>6.7.16</span> <a href=#toc:others-2>Others</a><a href=#others-2 class=anchor aria-hidden=true></a></h3><ul class=incremental><li><p>Improved Java-Smali conversion by including all the subclasses\nduring conversion<li><p>Improved scanning performance in the Scanner page<li><p>Improved updating the list of apps in the Main page<li><p>Scan all the available paths to detect systemless-ly installed\nsystem apps<li><p><code>vacuum</code> SQLite database before opening it for viewing\nor editing.</ul></section></section><section id=sec:v3.0.0-(410) class=level2 data-number=6.8><h2 data-number=6.8><span class=header-section-number>6.8</span> <a href=#toc:sec:v3.0.0-(410)>v3.0.0 (410)</a><a href=#sec:v3.0.0-(410) class=anchor aria-hidden=true></a></h2><p>App Manager v3.0.0 comes with a lot of features and improvements. See\n<a href=app-manager://settings/about/version>Settings > About >\nVersion/Changelog</a> to see a more detailed changelog.<section id=material-3-and-more class=level3 data-number=6.8.1><h3 data-number=6.8.1><span class=header-section-number>6.8.1</span>\n<a href=#toc:material-3-and-more>Material 3 and More</a><a href=#material-3-and-more class=anchor aria-hidden=true></a></h3><p>Material 3, somewhat similar to <em>Material You</em>, is a\nsignificant improvement over Material Design 2 with support for dynamic\ncolours in Android 12 and later. In addition, many design changes have\nbeen made in App Manager without any significant changes in the overall\nuser experience.<section id=known-issue-3 class=level5 data-number=6.8.1.0.1><h5 data-number=6.8.1.0.1><span class=header-section-number>6.8.1.0.1</span> Known issue<a href=#known-issue-3 class=anchor aria-hidden=true></a></h5><p>Switches are still based on Material Design 2 which will be fixed in\na future release.</section></section><section id=wireless-debugging class=level3 data-number=6.8.2><h3 data-number=6.8.2><span class=header-section-number>6.8.2</span>\n<a href=#toc:wireless-debugging>Wireless Debugging</a><a href=#wireless-debugging class=anchor aria-hidden=true></a></h3><p>Wireless debugging support has been fully implemented. Head over to\n§<a href=#sec:wireless-debugging data-reference-type=ref data-reference=sec:wireless-debugging>3.2</a> for instructions on how\nto configure wireless debugging.<div class=\"amalert tip\"><p><strong><em>No-root users:</em></strong><p>Due to auto-detection feature, startup time might be large for\nno-root users when the mode of operation is set to <em>auto</em>.\nInstead, no-root users should select <em>no-root</em> instead of\n<em>auto</em>.</div></section><section id=languages class=level3 data-number=6.8.3><h3 data-number=6.8.3><span class=header-section-number>6.8.3</span>\n<a href=#toc:languages>Languages</a><a href=#languages class=anchor aria-hidden=true></a></h3><p>App Manager is fully translated into Indonesian and Italian languages\nand can be enabled in settings. Bengali is removed due to lack of\ntranslators.</section><section id=introducing-app-explorer class=level3 data-number=6.8.4><h3 data-number=6.8.4><span class=header-section-number>6.8.4</span>\n<a href=#toc:introducing-app-explorer>Introducing App Explorer</a><a href=#introducing-app-explorer class=anchor aria-hidden=true></a></h3><p>App Explorer can be used to browse the contents of an application.\nThis includes binary XML files, DEX contents or any other media files.\nDEX contents can only be explored in Android Oreo (Android 8) and later.\nIt’s also possible to convert an <code>.smali</code> file into\n<code>.java</code> for a better understanding of the reversed code. This\nfeature, if not needed, can be disabled in Settings > Enable/disable\nfeatures.</section><section id=import-backups-from-other-applications class=level3 data-number=6.8.5><h3 data-number=6.8.5><span class=header-section-number>6.8.5</span>\n<a href=#toc:import-backups-from-other-applications>Import Backups\nfrom Other Applications</a><a href=#import-backups-from-other-applications class=anchor aria-hidden=true></a></h3><p>It is possible to import backups from discontinued or obsolete\napplications such as Titanium Backup, OAndBackup and Swift Backup\n(version 3.0 to 3.2). Go to Setting > Backup/restore to find this\noption.</section><section id=virustotal class=level3 data-number=6.8.6><h3 data-number=6.8.6><span class=header-section-number>6.8.6</span>\n<a href=#toc:virustotal>VirusTotal</a><a href=#virustotal class=anchor aria-hidden=true></a></h3><p>VirusTotal is a widely used tool to scan files and URLs for viruses.\nIn the scanner page and in the running apps page, an option to scan\nfiles with VirusTotal has been added. But the option is hidden by\ndefault. To enable the option, it is necessary to obtain an API key from\nVirusTotal. Go to Settings > VirusTotal API Key for more\ninformation.<div class=\"amalert warning\"><p><strong><em>Internet feature:</em></strong><p>This is currently the only feature which require an Internet\nconnection. If you wish to use any Internet feature that might also be\nadded in the future, enable <em>Use the Internet</em> in Settings >\nEnable/disable features.</div></section><section id=trigger-profiles-from-the-automation-software class=level3 data-number=6.8.7><h3 data-number=6.8.7><span class=header-section-number>6.8.7</span>\n<a href=#toc:trigger-profiles-from-the-automation-software>Trigger\nProfiles from the Automation Software</a><a href=#trigger-profiles-from-the-automation-software class=anchor aria-hidden=true></a></h3><p>As the implementation of routine operations is being delayed, an\noption to trigger profiles from the external automation software is\nadded. See §<a href=#sec:automating-tasks data-reference-type=ref data-reference=sec:automating-tasks>3.4</a> for instructions on how to\nconfigure profile automation.</section><section id=improved-application-installer class=level3 data-number=6.8.8><h3 data-number=6.8.8><span class=header-section-number>6.8.8</span>\n<a href=#toc:improved-application-installer>Improved Application\nInstaller</a><a href=#improved-application-installer class=anchor aria-hidden=true></a></h3><p>Application installer includes several improvements including the\nability to downgrade applications in no-root mode, installing multiple\napplications at once and blocking trackers after installation. In\nAndroid 12 and later, no-root users can update applications without any\nuser interactions.</section><section id=component-blocking class=level3 data-number=6.8.9><h3 data-number=6.8.9><span class=header-section-number>6.8.9</span>\n<a href=#toc:component-blocking>Component Blocking</a><a href=#component-blocking class=anchor aria-hidden=true></a></h3><p>It is now possible to configure how App Manager should block a\ncomponent. Visit Settings > Rules > Default blocking method for\nmore information. In the components tab, long clicking the block/unblock\nbutton opens a context menu which allows per-component blocking in a\nsimilar manner. ADB users can also block the components of a <em>Test\nonly</em> app.</section><section id=advanced-searching class=level3 data-number=6.8.10><h3 data-number=6.8.10><span class=header-section-number>6.8.10</span> <a href=#toc:advanced-searching>Advanced Searching</a><a href=#advanced-searching class=anchor aria-hidden=true></a></h3><p>In some pages, the search bar supports additional searching which\nincludes searching via prefix, suffix or even regular expressions. In\nthe main page, it is also possible to search for applications using the\nfirst letters of each word, e.g. <em>App Manager</em> can be listed by\nsearching for <em>am</em>.</section><section id=shared-libraries class=level3 data-number=6.8.11><h3 data-number=6.8.11><span class=header-section-number>6.8.11</span> <a href=#toc:shared-libraries>Shared Libraries</a><a href=#shared-libraries class=anchor aria-hidden=true></a></h3><p>Shared libraries tab has received a significant improvements. It can\ndisplay three types of libraries, such as native, jar and APK files.</section><section id=make-the-best-use-of-interceptor class=level3 data-number=6.8.12><h3 data-number=6.8.12><span class=header-section-number>6.8.12</span> <a href=#toc:make-the-best-use-of-interceptor>Make the Best Use of\nInterceptor</a><a href=#make-the-best-use-of-interceptor class=anchor aria-hidden=true></a></h3><p>Activity interceptor can be opened directly from the activities tab\nby long clicking on the launch button, and similarly, activities can be\nlaunched from the activity interceptor page with or without root, for\nany users.<div class=\"amalert tip\"><p><strong><em>Notice:</em></strong><p>Currently, activities opened via root cannot send the results back to\nthe original applications.</div></section><section id=widget-screen-time class=level3 data-number=6.8.13><h3 data-number=6.8.13><span class=header-section-number>6.8.13</span> <a href=#toc:widget-screen-time>Widget: Screen Time</a><a href=#widget-screen-time class=anchor aria-hidden=true></a></h3><p>Screen time widget is quite similar to Digital Wellbeing’s widget by\nthe same name. It displays the total screen time for the day along with\nthe top three apps from all users.</section><section id=widget-clear-cache class=level3 data-number=6.8.14><h3 data-number=6.8.14><span class=header-section-number>6.8.14</span> <a href=#toc:widget-clear-cache>Widget: Clear Cache</a><a href=#widget-clear-cache class=anchor aria-hidden=true></a></h3><p>Clear cache widget can be to clear cache from all the applications\ndirectly from the home screen.</section></section><section id=sec:v2.6.0-(385) class=level2 data-number=6.9><h2 data-number=6.9><span class=header-section-number>6.9</span> <a href=#toc:sec:v2.6.0-(385)>v2.6.0 (385)</a><a href=#sec:v2.6.0-(385) class=anchor aria-hidden=true></a></h2><section id=introducing-backups class=level3 data-number=6.9.1><h3 data-number=6.9.1><span class=header-section-number>6.9.1</span>\n<a href=#toc:introducing-backups>Introducing Backups</a><a href=#introducing-backups class=anchor aria-hidden=true></a></h3><p>Back up/restore feature is now finally out of beta! Read <a href=#sec:backup-restore>the corresponding guide</a> to understand how\nit works.</section><section id=introducing-log-viewer class=level3 data-number=6.9.2><h3 data-number=6.9.2><span class=header-section-number>6.9.2</span>\n<a href=#toc:introducing-log-viewer>Introducing Log Viewer</a><a href=#introducing-log-viewer class=anchor aria-hidden=true></a></h3><p><a href=#subsubsec:log-viewer>Log viewer</a> is essentially a\nfront-end for <code>logcat</code>. It can be used to filter logs by\n<em>tag</em> or <em>pid</em> (process ID), or even by custom filters.\nLog levels AKA verbosity can also be configured. You can also save,\nshare and manage logs.</section><section id=lock-app-manager class=level3 data-number=6.9.3><h3 data-number=6.9.3><span class=header-section-number>6.9.3</span>\n<a href=#toc:lock-app-manager>Lock App Manager</a><a href=#lock-app-manager class=anchor aria-hidden=true></a></h3><p><a href=#subsubsec:screen-lock>Lock App Manager</a> with the screen\nlock configured for your device.</section><section id=extended-modes-for-app-ops class=level3 data-number=6.9.4><h3 data-number=6.9.4><span class=header-section-number>6.9.4</span>\n<a href=#toc:extended-modes-for-app-ops>Extended Modes for App\nOps</a><a href=#extended-modes-for-app-ops class=anchor aria-hidden=true></a></h3><p>You can set any mode for any app ops that your device supports,\neither from the <a href=#subsec:set-mode-for-app-ops-dots>1-click ops\npage</a> or from the <a href=#subsubsec:app-ops>app ops tab</a>.</section><section id=new-batch-ops-add-to-profile class=level3 data-number=6.9.5><h3 data-number=6.9.5><span class=header-section-number>6.9.5</span>\n<a href=#toc:new-batch-ops-add-to-profile>New Batch Ops: Add to\nProfile</a><a href=#new-batch-ops-add-to-profile class=anchor aria-hidden=true></a></h3><p>You can now easily add selected apps to an existing profile using the\nbatch operations.</section><section id=app-info-improved class=level3 data-number=6.9.6><h3 data-number=6.9.6><span class=header-section-number>6.9.6</span>\n<a href=#toc:app-info-improved>App Info: Improved</a><a href=#app-info-improved class=anchor aria-hidden=true></a></h3><p>App info tab now has many options, including the ability to change <a href=#sec:terminologies>SSAID</a>, network policy (i.e. background\nnetwork usage), battery optimization, etc. Most of the tags used in this\ntab are also clickable, and if you click on them, you will be able to\nlook at the current state or configure them right away.</section><section id=advanced-sort-and-filtering-options-in-the-main-page class=level3 data-number=6.9.7><h3 data-number=6.9.7><span class=header-section-number>6.9.7</span>\n<a href=#toc:advanced-sort-and-filtering-options-in-the-main-page>Advanced\nSort and Filtering Options in the Main Page</a><a href=#advanced-sort-and-filtering-options-in-the-main-page class=anchor aria-hidden=true></a></h3><p>Sort and filter options are now replaced by <a href=#subsubsec:main-list-options>List Options</a> which is highly\nconfigurable, including the ability to filter using profiles.</section><section id=about-this-device class=level3 data-number=6.9.8><h3 data-number=6.9.8><span class=header-section-number>6.9.8</span>\n<a href=#toc:about-this-device>About This Device</a><a href=#about-this-device class=anchor aria-hidden=true></a></h3><p>Interested in knowing about your device in just one page? Go to the\nbottom of the <a href=#subsec:device-info>settings page</a>.</section><section id=enabledisable-features class=level3 data-number=6.9.9><h3 data-number=6.9.9><span class=header-section-number>6.9.9</span>\n<a href=#toc:enabledisable-features>Enable/disable Features</a><a href=#enabledisable-features class=anchor aria-hidden=true></a></h3><p>Not interested in all the features that AM offers? You can disable\nsome features in <a href=#subsubsec:enable/disable-features>settings</a>.</section><section id=new-languages-1 class=level3 data-number=6.9.10><h3 data-number=6.9.10><span class=header-section-number>6.9.10</span> <a href=#toc:new-languages-1>New Languages</a><a href=#new-languages-1 class=anchor aria-hidden=true></a></h3><p>AM now has more than 19 languages! New languages include Farsi,\nJapanese and Traditional Chinese.</section><section id=signing-the-apk-files class=level3 data-number=6.9.11><h3 data-number=6.9.11><span class=header-section-number>6.9.11</span> <a href=#toc:signing-the-apk-files>Signing the APK Files</a><a href=#signing-the-apk-files class=anchor aria-hidden=true></a></h3><p>You can now import external signing keys in AM! For security, App\nManager has its own encrypted KeyStore which can also be <a href=#subsubsec:import/export-keystore>imported or exported</a>.</section><section id=new-extension-unapkm class=level3 data-number=6.9.12><h3 data-number=6.9.12><span class=header-section-number>6.9.12</span> <a href=#toc:new-extension-unapkm>New Extension: UnAPKM</a><a href=#new-extension-unapkm class=anchor aria-hidden=true></a></h3><p>Since APKMirror has removed encryption from their APKM files, it’s no\nlonger necessary to decrypt them. As a result, the option to decrypt\nAPKM files has been removed. Instead, this option is now provided by the\nUnAPKM extension which you can grab from <a href=https://f-droid.org/packages/io.github.muntashirakon.unapkm/>F-Droid</a>.\nSo, if you have an encrypted APKM file and have this extension\ninstalled, you can open the file directly in AM.</section></section><section id=sec:v2.5.20-(375) class=level2 data-number=6.10><h2 data-number=6.10><span class=header-section-number>6.10</span>\n<a href=#toc:sec:v2.5.20-(375)>v2.5.20 (375)</a><a href=#sec:v2.5.20-(375) class=anchor aria-hidden=true></a></h2><section id=subsec:introducing-profiles class=level3 data-number=6.10.1><h3 data-number=6.10.1><span class=header-section-number>6.10.1</span> <a href=#toc:subsec:introducing-profiles>Introducing Profiles</a><a href=#subsec:introducing-profiles class=anchor aria-hidden=true></a></h3><p><a href=#sec:profile-page>Profiles</a> finally closes the <a href=https://github.com/MuntashirAkon/AppManager/issues/72>related\nissue</a>. Profiles can be used to execute certain tasks repeatedly\nwithout doing everything manually. A profile can be applied (or invoked)\neither from the <a href=#sec:profiles-page>Profiles page</a> or from\nthe home screen by creating shortcuts. There are also some presets which\nconsist of debloating profiles taken from <a href=https://gitlab.com/W1nst0n/universal-android-debloater>Universal\nAndroid Debloater</a>.<section id=known-limitations class=level5 data-number=6.10.1.0.1><h5 data-number=6.10.1.0.1><span class=header-section-number>6.10.1.0.1</span> Known limitations<a href=#known-limitations class=anchor aria-hidden=true></a></h5><ul class=incremental><li><p>Exporting rules and applying permissions are not currently\nworking.<li><p>Profiles are applied for all users.</ul></section></section><section id=subsec:the-interceptor class=level3 data-number=6.10.2><h3 data-number=6.10.2><span class=header-section-number>6.10.2</span> <a href=#toc:subsec:the-interceptor>The Interceptor</a><a href=#subsec:the-interceptor class=anchor aria-hidden=true></a></h3><p><a href=https://github.com/MuntashirAkon/intent-intercept>Intent\nIntercept</a> works as a man-in-the-middle between source and\ndestination, that is, when you open a file or URL with another app, you\ncan see what is being shared by opening it with Interceptor first. You\ncan also add or modify the intents before sending them to the\ndestination. Additionally, you can double-click on any exportable\nactivities in the Activities tab in the App Details page to open them in\nthe Interceptor to add more configurations.<section id=known-limitation-2 class=level5 data-number=6.10.2.0.1><h5 data-number=6.10.2.0.1><span class=header-section-number>6.10.2.0.1</span> Known limitation<a href=#known-limitation-2 class=anchor aria-hidden=true></a></h5><p>Editing extras is not currently possible.</section></section><section id=subsec:unapkm:-dedrm-the-apkm-files class=level3 data-number=6.10.3><h3 data-number=6.10.3><span class=header-section-number>6.10.3</span> <a href=#toc:subsec:unapkm:-dedrm-the-apkm-files>UnAPKM: DeDRM the APKM\nfiles</a><a href=#subsec:unapkm:-dedrm-the-apkm-files class=anchor aria-hidden=true></a></h3><p>When I released a small tool called <a href=https://f-droid.org/en/packages/io.github.muntashirakon.unapkm>UnAPKM</a>,\nI promised that similar feature will be available in App Manager. I am\nproud to announce that you can open APKM files directly in the App Info\npage or convert them to APKS or install them directly.</section><section id=subsec:multiple-user class=level3 data-number=6.10.4><h3 data-number=6.10.4><span class=header-section-number>6.10.4</span> <a href=#toc:subsec:multiple-user>Multiple user</a><a href=#subsec:multiple-user class=anchor aria-hidden=true></a></h3><p>App manager now supports multiple users! For now, this requires root\nor ADB. But no-root support is also being considered. If you have\nmultiple users enabled and click on an app installed in multiple\nprofiles, an alert prompt will be displayed where you can select the\nuser.</section><section id=vive-la-france class=level3 data-number=6.10.5><h3 data-number=6.10.5><span class=header-section-number>6.10.5</span> <a href=#toc:vive-la-france>Vive la France!</a><a href=#vive-la-france class=anchor aria-hidden=true></a></h3><p>Thanks to the contributors, we have one more addition to the language\nclub: French. You can add more languages or improve existing\ntranslations at <a href=https://hosted.weblate.org/engage/app-manager>Weblate</a>.</section><section id=report-crashes class=level3 data-number=6.10.6><h3 data-number=6.10.6><span class=header-section-number>6.10.6</span> <a href=#toc:report-crashes>Report crashes</a><a href=#report-crashes class=anchor aria-hidden=true></a></h3><p>If App Manager crashes, you can now easily report the crash from the\nnotifications which opens the share options. Crashes are not reported by\nApp Manager, it only redirects you to your favourite Email client.</section><section id=android-11 class=level3 data-number=6.10.7><h3 data-number=6.10.7><span class=header-section-number>6.10.7</span> <a href=#toc:android-11>Android 11</a><a href=#android-11 class=anchor aria-hidden=true></a></h3><p>Added support for Android 11. Not everything may work as expected\nthough.</section><section id=app-installer-improvements class=level3 data-number=6.10.8><h3 data-number=6.10.8><span class=header-section-number>6.10.8</span> <a href=#toc:app-installer-improvements>App Installer Improvements</a><a href=#app-installer-improvements class=anchor aria-hidden=true></a></h3><section id=set-installation-locations class=level4 data-number=6.10.8.1><h4 data-number=6.10.8.1><span class=header-section-number>6.10.8.1</span> Set installation\nlocations<a href=#set-installation-locations class=anchor aria-hidden=true></a></h4><p>In settings page, you can set install locations such as auto\n(default), internal only and prefer external.</section><section id=set-apk-installer class=level4 data-number=6.10.8.2><h4 data-number=6.10.8.2><span class=header-section-number>6.10.8.2</span> Set APK installer<a href=#set-apk-installer class=anchor aria-hidden=true></a></h4><p>In settings page, you can also set default APK installer (root/ADB\nonly) instead of App Manager.</section><section id=multiple-users class=level4 data-number=6.10.8.3><h4 data-number=6.10.8.3><span class=header-section-number>6.10.8.3</span> Multiple users<a href=#multiple-users class=anchor aria-hidden=true></a></h4><p>In settings page, you can allow App Manager to display multiple users\nduring APK installation.</section><section id=signing-apk-files class=level4 data-number=6.10.8.4><h4 data-number=6.10.8.4><span class=header-section-number>6.10.8.4</span> Signing APK files<a href=#signing-apk-files class=anchor aria-hidden=true></a></h4><p>In settings page, you can choose to sign APK files before installing\nthem. You can also select which signature scheme to use in the <em>APK\nsigning</em> option in settings.<section id=known-limitation-3 class=level5 data-number=6.10.8.4.1><h5 data-number=6.10.8.4.1><span class=header-section-number>6.10.8.4.1</span> Known limitation<a href=#known-limitation-3 class=anchor aria-hidden=true></a></h5><p>Currently, only a generic key is used to sign APK files</section></section></section></section><section id=v2.5.17-368 class=level2 data-number=6.11><h2 data-number=6.11><span class=header-section-number>6.11</span>\n<a href=#toc:v2.5.17-368>v2.5.17 (368)</a><a href=#v2.5.17-368 class=anchor aria-hidden=true></a></h2><section id=app-installer class=level3 data-number=6.11.1><h3 data-number=6.11.1><span class=header-section-number>6.11.1</span> <a href=#toc:app-installer>App Installer</a><a href=#app-installer class=anchor aria-hidden=true></a></h3><p>As promised, it is now possible to select splits. AM also provides\nrecommendations based on device configurations. If the app is already\ninstalled, recommendations are provided based on the installed app. It\nis also possible to downgrade to a lower version without data loss if\nthe device has root or ADB. But it should be noted that not all app can\nbe downgraded. Installer is also improved to speed up the installation\nprocess, especially, for root users. If the app has already been\ninstalled and the new (x)apk(s) is newer or older or the same version\nwith a different signature, AM will display a list of changes similar to\n<strong>What’s New</strong> before prompting the user to install the\napp. This is useful if the app has introduced tracker components, new\npermissions, etc.<section id=known-limitations-1 class=level5 data-number=6.11.1.0.1><h5 data-number=6.11.1.0.1><span class=header-section-number>6.11.1.0.1</span> Known Limitations<a href=#known-limitations-1 class=anchor aria-hidden=true></a></h5><ul class=incremental><li><p>Large app can take a long time to fetch app info, and therefore,\nit may take a long time display the installation prompt.<li><p>If the apk is not located in the internal storage, the app has to\nbe cached first which might also take a long time depending on the size\nof the apk.</ul></section></section><section id=scanner-replacement-for-exodus-page class=level3 data-number=6.11.2><h3 data-number=6.11.2><span class=header-section-number>6.11.2</span> <a href=#toc:scanner-replacement-for-exodus-page>Scanner: Replacement for\nExodus Page</a><a href=#scanner-replacement-for-exodus-page class=anchor aria-hidden=true></a></h3><p>Exodus page is now replaced with scanner page. <a href=#sec:scanner-page>Scanner page</a> contains not only a list of\ntrackers but also a list of used libraries. This is just a start. In the\nfuture, this page will contain more in depth analysis of the app.</section><section id=introducing-system-config class=level3 data-number=6.11.3><h3 data-number=6.11.3><span class=header-section-number>6.11.3</span> <a href=#toc:introducing-system-config>Introducing System Config</a><a href=#introducing-system-config class=anchor aria-hidden=true></a></h3><p>System Config lists various system configurations and\nwhitelists/blacklists included in Android by either OEM/vendor, AOSP or\neven some Magisk modules. Root users can access this option from the\noverflow menu in the main page. There isn’t any official documentation\nfor these options therefore it’s difficult to write a complete\ndocumentation for this page. I will gradually add documentations using\nmy own knowledge. However, some functions should be understandable by\ntheir name.</section><section id=more-languages class=level3 data-number=6.11.4><h3 data-number=6.11.4><span class=header-section-number>6.11.4</span> <a href=#toc:more-languages>More Languages</a><a href=#more-languages class=anchor aria-hidden=true></a></h3><p>Thanks to the contributors, AM now has more than 12 languages. New\nlanguages include Bengali, Hindi, Norwegian, Polish, Russian, Simplified\nChinese, Turkish and Ukrainian.</section><section id=app-info-tab class=level3 data-number=6.11.5><h3 data-number=6.11.5><span class=header-section-number>6.11.5</span> <a href=#toc:app-info-tab>App Info Tab</a><a href=#app-info-tab class=anchor aria-hidden=true></a></h3><p>More tags are added in the <a href=#subsec:app-info-tab>app info\ntab</a> such as <strong>KeyStore</strong> (apps with KeyStore items),\n<strong>Systemless app</strong> (apps installed via Magisk),\n<strong>Running</strong> (apps that are running). For external apk, two\nmore options are added namely <strong>Reinstall</strong> and\n<strong>Downgrade</strong>. Now it is possible to share an apk via\nBluetooth. For system apps, it is possible to uninstall updates for\nroot/ADB users. But like the similar option in the system settings, this\noperation will clear all app data. As stated above, exodus has been\nreplaced with scanner.</section><section id=navigation-improvements class=level3 data-number=6.11.6><h3 data-number=6.11.6><span class=header-section-number>6.11.6</span> <a href=#toc:navigation-improvements>Navigation Improvements</a><a href=#navigation-improvements class=anchor aria-hidden=true></a></h3><p>It’s now relatively easy to navigate to various UI components using\nkeyboard. You can use up/down button to navigate between list items and\ntab button to navigate to UI components inside an item.</section><section id=running-apps-page class=level3 data-number=6.11.7><h3 data-number=6.11.7><span class=header-section-number>6.11.7</span> <a href=#toc:running-apps-page>Running Apps Page</a><a href=#running-apps-page class=anchor aria-hidden=true></a></h3><p>It is now possible to sort and filter processes in this tab. Also,\nthe three big buttons are replaced with an easy-to-use three dot menu.\nPreviously the memory usage was wrong which is fixed in this\nversion.</section><section id=built-in-toybox class=level3 data-number=6.11.8><h3 data-number=6.11.8><span class=header-section-number>6.11.8</span> <a href=#toc:built-in-toybox>Built-in Toybox</a><a href=#built-in-toybox class=anchor aria-hidden=true></a></h3><p>Toybox (an alternative to busybox) is bundled with AM. Although\nAndroid has this utility built-in from API 23, toybox is bundled in\norder to prevent buggy implementations and to support API &lt; 23.</section><section id=component-blocker-improvements class=level3 data-number=6.11.9><h3 data-number=6.11.9><span class=header-section-number>6.11.9</span> <a href=#toc:component-blocker-improvements>Component Blocker\nImprovements</a><a href=#component-blocker-improvements class=anchor aria-hidden=true></a></h3><p>Component blocker seemed to be problematic in the previous version,\nespecially when global component blocking is enabled. The issues are\nmostly fixed now.<div class=\"amalert warning\"><p><strong><em>Caution:</em></strong><p>The component blocking mechanism is no longer compatible with v2.5.6\ndue to various security issues. If you have this version, upgrade to\nv2.5.13 or earlier versions first. After that, enable <a href=#subsubsec:instant-component-blocking>global component\nblocking</a> and disable it again.</div></section><section id=improvements-in-the-app-details-page class=level3 data-number=6.11.10><h3 data-number=6.11.10><span class=header-section-number>6.11.10</span> <a href=#toc:improvements-in-the-app-details-page>Improvements in the App\nDetails Page</a><a href=#improvements-in-the-app-details-page class=anchor aria-hidden=true></a></h3><p>Value of various app ops depend on their parent app ops. Therefore,\nwhen you allow/deny an app op, the parent of the app op gets modified.\nThis fixes the issues some users have been complaining regarding some\napp ops that couldn’t be changed.<p>If an app has the target API 23 or less, its permissions cannot be\nmodified using the <code>pm grant …</code> command. Therefore, for such\napps, option to toggle permission has been disabled.<p>The signature tab is improved to support localization. It also\ndisplays multiple checksums for a signature.</section><section id=app-manifest class=level3 data-number=6.11.11><h3 data-number=6.11.11><span class=header-section-number>6.11.11</span> <a href=#toc:app-manifest>App Manifest</a><a href=#app-manifest class=anchor aria-hidden=true></a></h3><p>Manifest no longer crashes if the size of the manifest is too long.\nGenerated manifest are now more accurate than before.</section></section><section id=v2.5.13-348 class=level2 data-number=6.12><h2 data-number=6.12><span class=header-section-number>6.12</span>\n<a href=#toc:v2.5.13-348>v2.5.13 (348)</a><a href=#v2.5.13-348 class=anchor aria-hidden=true></a></h2><section id=bundled-app-split-apk class=level3 data-number=6.12.1><h3 data-number=6.12.1><span class=header-section-number>6.12.1</span> <a href=#toc:bundled-app-split-apk>Bundled App (Split APK)</a><a href=#bundled-app-split-apk class=anchor aria-hidden=true></a></h3><p>Bundled app formats such as <strong>apks</strong> and\n<strong>xapk</strong> are now supported. You can install these apps\nusing the regular installation buttons. For root and adb users, apps are\ninstalled using shell, and for non-root users, the platform default\nmethod is used.<section id=known-limitations-2 class=level5 data-number=6.12.1.0.1><h5 data-number=6.12.1.0.1><span class=header-section-number>6.12.1.0.1</span> Known Limitations<a href=#known-limitations-2 class=anchor aria-hidden=true></a></h5><ul class=incremental><li><p>Currently <em>all</em> splits apks are installed. But this\nbehaviour is going to change in the next release. If you only need a few\nsplits instead of all, extract the <strong>APKS</strong> or\n<strong>XAPK</strong> file, and then, create a new zip file with your\ndesired split apks and replace the <strong>ZIP</strong> extension with\n<strong>APKS</strong>. Now, open it with AM.<li><p>There is no progress dialog to display the installation\nprogress.</ul></section></section><section id=direct-install-support class=level3 data-number=6.12.2><h3 data-number=6.12.2><span class=header-section-number>6.12.2</span> <a href=#toc:direct-install-support>Direct Install Support</a><a href=#direct-install-support class=anchor aria-hidden=true></a></h3><p>You can now install <strong>APK</strong>, <strong>APKS</strong> or\n<strong>XAPK</strong> directly from your favourite browser or file\nmanager. For apps that need updates, a <strong>What’s New</strong>\ndialog is displayed showing the changes in the new version.<section id=known-limitations-3 class=level5 data-number=6.12.2.0.1><h5 data-number=6.12.2.0.1><span class=header-section-number>6.12.2.0.1</span> Known Limitations<a href=#known-limitations-3 class=anchor aria-hidden=true></a></h5><ul class=incremental><li><p>Downgrade is not yet possible.<li><p>There is no progress dialog to display the installation progress.\nIf you cannot interact with the current page, wait until the\ninstallation is finished.</ul></section></section><section id=remove-all-blocking-rules class=level3 data-number=6.12.3><h3 data-number=6.12.3><span class=header-section-number>6.12.3</span> <a href=#toc:remove-all-blocking-rules>Remove All Blocking Rules</a><a href=#remove-all-blocking-rules class=anchor aria-hidden=true></a></h3><p>In the Settings page, a new option is added which can be used to\nremove all blocking rules configured within App Manager.</section><section id=app-ops class=level3 data-number=6.12.4><h3 data-number=6.12.4><span class=header-section-number>6.12.4</span> <a href=#toc:app-ops>App\nOps</a><a href=#app-ops class=anchor aria-hidden=true></a></h3><ul class=incremental><li><p>App Ops are now generated using a technique similar to AppOpsX.\nThis should decrease the loading time significantly in the App Ops\ntab.<li><p>In the App Ops tab, a menu item is added which can be used to\nlist only active app ops without including the default app ops. The\npreference is saved in the shared preferences.</ul><section id=known-limitation-4 class=level5 data-number=6.12.4.0.1><h5 data-number=6.12.4.0.1><span class=header-section-number>6.12.4.0.1</span> Known Limitation<a href=#known-limitation-4 class=anchor aria-hidden=true></a></h5><p>Often the App Ops tab may not be responsive. If that’s the case,\nrestart App Manager.</section></section><section id=enhanced-adb-support class=level3 data-number=6.12.5><h3 data-number=6.12.5><span class=header-section-number>6.12.5</span> <a href=#toc:enhanced-adb-support>Enhanced ADB Support</a><a href=#enhanced-adb-support class=anchor aria-hidden=true></a></h3><p>ADB shell commands are now executed using a technique similar to\nAppOpsX (This is the <em>free</em> alternative of AppOps by Rikka.).\nThis should dramatically increase the execution time.<section id=known-limitation-5 class=level5 data-number=6.12.5.0.1><h5 data-number=6.12.5.0.1><span class=header-section-number>6.12.5.0.1</span> Known Limitation<a href=#known-limitation-5 class=anchor aria-hidden=true></a></h5><p>AM can often crash or become not responsive. If that’s the case,\nrestart App Manager.</section></section><section id=filtering-in-main-page class=level3 data-number=6.12.6><h3 data-number=6.12.6><span class=header-section-number>6.12.6</span> <a href=#toc:filtering-in-main-page>Filtering in Main Page</a><a href=#filtering-in-main-page class=anchor aria-hidden=true></a></h3><p>Add an option to filter apps that has at least one activity.</section><section id=apk-backupsharing class=level3 data-number=6.12.7><h3 data-number=6.12.7><span class=header-section-number>6.12.7</span> <a href=#toc:apk-backupsharing>Apk Backup/Sharing</a><a href=#apk-backupsharing class=anchor aria-hidden=true></a></h3><p>Apk files are now saved as <code>app name_version.extension</code>\ninstead of <code>package.name.extension</code>.</section><section id=batch-ops class=level3 data-number=6.12.8><h3 data-number=6.12.8><span class=header-section-number>6.12.8</span> <a href=#toc:batch-ops>Batch Ops</a><a href=#batch-ops class=anchor aria-hidden=true></a></h3><ul class=incremental><li><p>Added a foreground service to run batch operations. The result of\nthe operation is displayed in a notification. If an operation has failed\nfor some packages, clicking on the notification will open a dialog box\nlisting the failed packages. There is also a <strong>Try Again</strong>\nbutton on the bottom which can be used to perform the operation again\nfor the failed packages.<li><p>Replaced Linux <em>kill</em> with\n<strong>force-stop</strong>.</ul></section><section id=translations class=level3 data-number=6.12.9><h3 data-number=6.12.9><span class=header-section-number>6.12.9</span> <a href=#toc:translations>Translations</a><a href=#translations class=anchor aria-hidden=true></a></h3><p>Added German and Portuguese (Brazilian) translations.<section id=known-limitation-6 class=level5 data-number=6.12.9.0.1><h5 data-number=6.12.9.0.1><span class=header-section-number>6.12.9.0.1</span> Known Limitation<a href=#known-limitation-6 class=anchor aria-hidden=true></a></h5><p>Not all translations are verified yet.</section></section><section id=app-data-backup class=level3 data-number=6.12.10><h3 data-number=6.12.10><span class=header-section-number>6.12.10</span> <a href=#toc:app-data-backup>App Data Backup</a><a href=#app-data-backup class=anchor aria-hidden=true></a></h3><p>Install app only for the current user at the time of restoring\nbackups. Support for split apks is also added.<p><em>Data backup feature is now considered unstable. If you encounter\nany problem, please report to me without hesitation.</em></section></section></section><section id=ch:app-ops class=level1 data-number=7><h1 data-number=7><span class=header-section-number>7</span> <a href=#toc:ch:app-ops>App Ops</a><a href=#ch:app-ops class=anchor aria-hidden=true></a></h1><section id=sec:app-ops-background class=level2 data-number=7.1><h2 data-number=7.1><span class=header-section-number>7.1</span> <a href=#toc:sec:app-ops-background>Background</a><a href=#sec:app-ops-background class=anchor aria-hidden=true></a></h2><p><strong>App Ops</strong> (short hand for <strong>Application\nOperations</strong>) are used by Android system (since Android 4.3) to\ncontrol application permissions. The user <em>can</em> control some\npermissions, but only the permissions that are considered dangerous (and\nGoogle thinks knowing your phone number isn’t a dangerous thing). So,\napp ops seems to be the one we need if we want to install apps like\nFacebook and it’s Messenger (the latter literary records everything if\nyou live outside the EU) and still want <em>some</em> privacy and/or\nsecurity. Although certain features of app ops were available in\nSettings and later in hidden settings in older version of Android, it’s\ncompletely hidden in newer versions of Android and is continued to be\nkept hidden. Now, any app with\n<strong>android.Manifest.permission.GET_APP_OPS_STATS</strong>\npermission can get the app ops information for other applications but\nthis permission is hidden from users and can only be enabled using ADB\nor root. Still, the app with this permission cannot grant or revoke\npermissions (actually mode of operation) for apps other than itself\n(with limited capacity, of course). To modify the ops of other app, the\napp needs\n<strong>android.Manifest.permission.UPDATE_APP_OPS_STATS</strong>\npermissions which isn’t accessible via <code>pm</code> command. So, you\ncannot grant it via root or ADB, the permission is only granted to the\nsystem apps. There are very few apps who support disabling permissions\nvia app ops. The best one to my knowledge is <a href=https://github.com/8enet/AppOpsX>AppOpsX</a>. The main (visible)\ndifference between my app (AppManager) and this app is that the latter\nalso provides you the ability to revoke internet permissions (by writing\nip tables). One crucial problem that I faced during the development of\nthe app ops API is the lack of documentation in English language.</section><section id=sec:introduction-to-app-ops class=level2 data-number=7.2><h2 data-number=7.2><span class=header-section-number>7.2</span> <a href=#toc:sec:introduction-to-app-ops>Introduction to App Ops</a><a href=#sec:introduction-to-app-ops class=anchor aria-hidden=true></a></h2><figure id=fig:appops><figure><object data=../images/appops.svg type=image/svg+xml></object></figure><figcaption>Figure 2: How app ops work</figcaption></figure><p>Figure <a href=#fig:appops>1</a> describes the process of changing\nand processing permission. <a href=#sec:appopsmanager>AppOpsManager</a> can be used to manage\npermissions in Settings app. <strong>AppOpsManager</strong> is also\nuseful in determining if a certain permission (or operation) is granted\nto the application. Most of the methods of\n<strong>AppOpsManager</strong> are accessible to the user app but unlike\na system app, it can only be used to check permissions for any app or\nfor the app itself and start or terminating certain operations.\nMoreover, not all operations are actually accessible from this Java\nclass. <strong>AppOpsManager</strong> holds all the necessary constants\nsuch as <a href=#subsec:op-constants><code>OP_*</code></a>,\n<code>OPSTR_*</code>, <a href=#subsec:mode-constants><code>MODE_*</code></a> which describes\noperation code, operation string and mode of operations respectively. It\nalso holds necessary data structures such as <a href=#subsec:package-ops>PackageOps</a> and <strong>OpEntry</strong>.\n<strong>PackageOps</strong> holds <strong>OpEntry</strong> for a\npackage, and <strong>OpEntry</strong>, as the name suggests, describes\neach operation.<p><code>AppOpService</code> is completely hidden from a user\napplication but accessible to the system applications. As it can be seen\nin Figure <a href=#fig:appops>1</a>, this is the class that does the\nactual management stuff. It contains data structures such as\n<strong>Ops</strong> to store basic package info and <strong>Op</strong>\nwhich is similar to <strong>OpEntry</strong> of\n<strong>AppOpsManager</strong>. It also has <strong>Shell</strong> which\nis actually the source code of the <a href=#sec:appops-cli><em>appops</em> command line tool</a>. It writes\nconfigurations to or read configurations from <a href=#sec:appops-xml><code>/data/system/appops.xml</code></a>. System\nservices calls <strong>AppOpsService</strong> to find out what an\napplication is allowed and what is not allowed to perform, and\n<strong>AppOpsService</strong> determines these permissions by parsing\n<code>/data/system/appops.xml</code>. If no custom values are present in\n<em>appops.xml</em>, it returns the default mode available in\n<strong>AppOpsManager</strong>.</section><section id=sec:appopsmanager class=level2 data-number=7.3><h2 data-number=7.3><span class=header-section-number>7.3</span> <a href=#toc:sec:appopsmanager>AppOpsManager</a><a href=#sec:appopsmanager class=anchor aria-hidden=true></a></h2><p><a href=https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/app/AppOpsManager.java>AppOpsManager</a>\nstands for application operations manager. It consists of various\nconstants and classes to modify app operations.<div class=seealso-inline><p><em>Siehe auch: <span><a href=https://developer.android.com/reference/android/app/AppOpsManager>AppOpsManager\ndocumentation</a></span></em></div><section id=subsec:op-constants class=level3 data-number=7.3.1><h3 data-number=7.3.1><span class=header-section-number>7.3.1</span>\n<a href=#toc:subsec:op-constants><code>OP_*</code> Constants</a><a href=#subsec:op-constants class=anchor aria-hidden=true></a></h3><p><code>OP_*</code> are the integer constants starting from\n<code>0</code>. <code>OP_NONE</code> implies that no operations are\nspecified whereas <code>_NUM_OP</code> denotes the number of operations\ndefined in <code>OP_*</code> prefix. While they denote each operation,\nthe operations are not necessarily unique. In fact, there are many\noperations that are actually a single operation denoted by multiple\n<code>OP_*</code> constant (possibly for future use). Vendors may define\ntheir own op based on their requirements. MIUI is one of the vendors who\nare known to do that.<div class=listing><div class=sourceCode id=cb11 data-frame=lines><pre class=\"sourceCode java\"><code class=\"sourceCode java\"><span id=cb11-1><a href=#cb11-1 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=dt>final</span> <span class=dt>int</span> OP_NONE <span class=op>=</span> <span class=op>-</span><span class=dv>1</span><span class=op>;</span></span>\n<span id=cb11-2><a href=#cb11-2 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=dt>final</span> <span class=dt>int</span> OP_COARSE_LOCATION <span class=op>=</span> <span class=dv>0</span><span class=op>;</span></span>\n<span id=cb11-3><a href=#cb11-3 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=dt>final</span> <span class=dt>int</span> OP_FINE_LOCATION <span class=op>=</span> <span class=dv>1</span><span class=op>;</span></span>\n<span id=cb11-4><a href=#cb11-4 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=dt>final</span> <span class=dt>int</span> OP_GPS <span class=op>=</span> <span class=dv>2</span><span class=op>;</span></span>\n<span id=cb11-5><a href=#cb11-5 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=dt>final</span> <span class=dt>int</span> OP_VIBRATE <span class=op>=</span> <span class=dv>3</span><span class=op>;</span></span>\n<span id=cb11-6><a href=#cb11-6 aria-hidden=true tabindex=-1></a><span class=kw>...</span></span>\n<span id=cb11-7><a href=#cb11-7 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=dt>final</span> <span class=dt>int</span> OP_READ_DEVICE_IDENTIFIERS <span class=op>=</span> <span class=dv>89</span><span class=op>;</span></span>\n<span id=cb11-8><a href=#cb11-8 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=dt>final</span> <span class=dt>int</span> OP_ACCESS_MEDIA_LOCATION <span class=op>=</span> <span class=dv>90</span><span class=op>;</span></span>\n<span id=cb11-9><a href=#cb11-9 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=dt>final</span> <span class=dt>int</span> OP_ACTIVATE_PLATFORM_VPN <span class=op>=</span> <span class=dv>91</span><span class=op>;</span></span>\n<span id=cb11-10><a href=#cb11-10 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=dt>final</span> <span class=dt>int</span> _NUM_OP <span class=op>=</span> <span class=dv>92</span><span class=op>;</span></span></code></pre></div></div><p>Whether an operation is unique is defined by\n<code>sOpToSwitch</code>. It maps each operation to another operation or\nto itself (if it’s a unique operation). For instance,\n<code>OP_FINE_LOCATION</code> and <code>OP_GPS</code> are mapped to\n<code>OP_COARSE_LOCATION</code>.<p>Each operation has a private name which are described by\n<code>sOpNames</code>. These names are usually the same names as the\nconstants without the <code>OP_</code> prefix. Some operations have\npublic names as well which are described by <code>sOpToString</code>.\nFor instance, <code>OP_COARSE_LOCATION</code> has the public name\n<strong>android:coarse_location</strong>.<p>As a gradual process of moving permissions to app ops, there are\nalready many permissions that are defined under some operations. These\npermissions are mapped in <code>sOpPerms</code>. For example, the\npermission\n<strong>android.Manifest.permission.ACCESS_COARSE_LOCATION</strong> is\nmapped to <code>OP_COARSE_LOCATION</code>. Some operations may not have\nany associated permissions which have <code>null</code> values.<p>As described in the previous section, operations that are configured\nfor an app are stored at <a href=#sec:appops-xml><code>/data/system/appops.xml</code></a>. If an\noperation is not configured, then whether system will allow that\noperation is determined from <code>sOpDefaultMode</code>. It lists the\n<em>default mode</em> for each operation.</section><section id=subsec:mode-constants class=level3 data-number=7.3.2><h3 data-number=7.3.2><span class=header-section-number>7.3.2</span>\n<a href=#toc:subsec:mode-constants><code>MODE_*</code> Constants</a><a href=#subsec:mode-constants class=anchor aria-hidden=true></a></h3><p><code>MODE_*</code> constants also integer constants starting from\n<code>0</code>. These constants are assigned to each operation\ndescribing whether an app is authorised to perform that operation. These\nmodes usually have associated names such as <strong>allow</strong> for\n<code>MODE_ALLOWED</code>, <strong>ignore</strong> for\n<code>MODE_IGNORED</code>, <strong>deny</strong> for\n<code>MODE_ERRORED</code> (a rather misnomer), <strong>default</strong>\nfor <code>MODE_DEFAULT</code> and <strong>foreground</strong> for\n<code>MODE_FOREGROUND</code>.<ol class=incremental><li><p><strong><code>MODE_ALLOWED</code>.</strong> The app is allowed to\nperform the given operation<li><p><strong><code>MODE_IGNORED</code>.</strong> The app is not\nallowed to perform the given operation, and any attempt to perform the\noperation should <em>silently fail</em>, i.e. it should not cause the\napp to crash<li><p><strong><code>MODE_ERRORED</code>.</strong> The app is not\nallowed to perform the given operation, and this attempt should cause it\nto have a fatal error, typically a\n<code>SecurityException</code><li><p><strong><code>MODE_DEFAULT</code>.</strong> The app should use\nits default security check, specified in\n<code>AppOpsManager</code><li><p><strong><code>MODE_FOREGROUND</code>.</strong> Special mode that\nmeans “allow only when app is in foreground.” This mode was added in\nAndroid 10<li><p><strong><code>MODE_ASK</code>.</strong> This is a custom mode\nused by MIUI whose uses are unknown.</ol></section><section id=subsec:package-ops class=level3 data-number=7.3.3><h3 data-number=7.3.3><span class=header-section-number>7.3.3</span>\n<a href=#toc:subsec:package-ops>PackageOps</a><a href=#subsec:package-ops class=anchor aria-hidden=true></a></h3><p><strong>AppOpsManager.PackageOps</strong> is a data structure to\nstore all the <strong>OpEntry</strong> for a package. In simple terms,\nit stores all the customised operations for a package.<div class=listing><div class=sourceCode id=cb12 data-frame=lines><pre class=\"sourceCode java\"><code class=\"sourceCode java\"><span id=cb12-1><a href=#cb12-1 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=kw>class</span> PackageOps <span class=kw>implements</span> Parcelable <span class=op>{</span></span>\n<span id=cb12-2><a href=#cb12-2 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=bu>String</span> mPackageName<span class=op>;</span></span>\n<span id=cb12-3><a href=#cb12-3 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=dt>int</span> mUid<span class=op>;</span></span>\n<span id=cb12-4><a href=#cb12-4 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=bu>List</span><span class=op>&lt;</span>OpEntry<span class=op>&gt;</span> mEntries<span class=op>;</span></span>\n<span id=cb12-5><a href=#cb12-5 aria-hidden=true tabindex=-1></a>    <span class=kw>...</span></span>\n<span id=cb12-6><a href=#cb12-6 aria-hidden=true tabindex=-1></a><span class=op>}</span></span></code></pre></div></div><p>As can be seen in Listing <a href=#lst:package-ops-class>2</a>, it\nstores all <strong>OpEntry</strong> for a package as well as the\ncorresponding package name and its kernel user ID.</section><section id=subsec:opentry class=level3 data-number=7.3.4><h3 data-number=7.3.4><span class=header-section-number>7.3.4</span>\n<a href=#toc:subsec:opentry>OpEntry</a><a href=#subsec:opentry class=anchor aria-hidden=true></a></h3><p><strong>AppOpsManager.OpEntry</strong> is a data structure that\nstores a single operation for any package.<div class=listing><div class=sourceCode id=cb13 data-frame=lines><pre class=\"sourceCode java\"><code class=\"sourceCode java\"><span id=cb13-1><a href=#cb13-1 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=dt>final</span> <span class=kw>class</span> OpEntry <span class=kw>implements</span> Parcelable <span class=op>{</span></span>\n<span id=cb13-2><a href=#cb13-2 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=dt>int</span> mOp<span class=op>;</span></span>\n<span id=cb13-3><a href=#cb13-3 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=dt>boolean</span> mRunning<span class=op>;</span></span>\n<span id=cb13-4><a href=#cb13-4 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=at>@Mode</span> <span class=dt>int</span> mMode<span class=op>;</span></span>\n<span id=cb13-5><a href=#cb13-5 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=at>@Nullable</span> LongSparseLongArray mAccessTimes<span class=op>;</span></span>\n<span id=cb13-6><a href=#cb13-6 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=at>@Nullable</span> LongSparseLongArray mRejectTimes<span class=op>;</span></span>\n<span id=cb13-7><a href=#cb13-7 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=at>@Nullable</span> LongSparseLongArray mDurations<span class=op>;</span></span>\n<span id=cb13-8><a href=#cb13-8 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=at>@Nullable</span> LongSparseLongArray mProxyUids<span class=op>;</span></span>\n<span id=cb13-9><a href=#cb13-9 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=at>@Nullable</span> LongSparseArray<span class=op>&lt;</span><span class=bu>String</span><span class=op>&gt;</span> mProxyPackageNames<span class=op>;</span></span>\n<span id=cb13-10><a href=#cb13-10 aria-hidden=true tabindex=-1></a>    <span class=kw>...</span></span>\n<span id=cb13-11><a href=#cb13-11 aria-hidden=true tabindex=-1></a><span class=op>}</span></span></code></pre></div></div><p>Here:<ul class=incremental><li><p><code>mOp</code>: Denotes one of the <a href=#subsec:op-constants><code>OP_*</code> constants</a><li><p><code>mRunning</code>: Whether the operation is in progress\n(i.e. the operation has started but not finished yet). Not all\noperations can be started or finished this way<li><p><code>mMOde</code>: One of the <a href=#subsec:mode-constants><code>MODE_*</code> constants</a><li><p><code>mAccessTimes</code>: Stores all the available access\ntimes<li><p><code>mRejectTimes</code>: Stores all the available reject\ntimes<li><p><code>mDurations</code>: All available access durations, checking\nthis with <code>mRunning</code> will tell you for how long the app is\nperforming a certain app operation<li><p><code>mProxyUids</code>: No documentation found<li><p><code>mProxyPackageNames:</code> No documentation found</ul></section><section id=subsec:usage class=level3 data-number=7.3.5><h3 data-number=7.3.5><span class=header-section-number>7.3.5</span>\n<a href=#toc:subsec:usage>Usage</a><a href=#subsec:usage class=anchor aria-hidden=true></a></h3><p>TODO</section></section><section id=sec:appopsservice class=level2 data-number=7.4><h2 data-number=7.4><span class=header-section-number>7.4</span> <a href=#toc:sec:appopsservice>AppOpsService</a><a href=#sec:appopsservice class=anchor aria-hidden=true></a></h2><p>TODO</section><section id=sec:appops-xml class=level2 data-number=7.5><h2 data-number=7.5><span class=header-section-number>7.5</span> <a href=#toc:sec:appops-xml>appops.xml</a><a href=#sec:appops-xml class=anchor aria-hidden=true></a></h2><p>Latest <code>appops.xml</code> has the following format: (This DTD is\nmade by me and by no means perfect, has compatibility issues.)<pre><code>&lt;!DOCTYPE app-ops [\n\n&lt;!ELEMENT app-ops (uid|pkg)*&gt;\n&lt;!ATTLIST app-ops v CDATA #IMPLIED&gt;\n\n&lt;!ELEMENT uid (op)*&gt;\n&lt;!ATTLIST uid n CDATA #REQUIRED&gt;\n\n&lt;!ELEMENT pkg (uid)*&gt;\n&lt;!ATTLIST pkg n CDATA #REQUIRED&gt;\n\n&lt;!ELEMENT uid (op)*&gt;\n&lt;!ATTLIST uid\nn CDATA #REQUIRED\np CDATA #IMPLIED&gt;\n\n&lt;!ELEMENT op (st)*&gt;\n&lt;!ATTLIST op\nn CDATA #REQUIRED\nm CDATA #REQUIRED&gt;\n\n&lt;!ELEMENT st EMPTY&gt;\n&lt;!ATTLIST st\nn CDATA #REQUIRED\nt CDATA #IMPLIED\nr CDATA #IMPLIED\nd CDATA #IMPLIED\npp CDATA #IMPLIED\npu CDATA #IMPLIED&gt;\n\n]&gt;</code></pre><p>The instruction below follows the exact order given above:<ul class=incremental><li><p><code>app-ops</code>: The root element. It can contain any number\nof <code>pkg</code> or package <code>uid</code><ul class=incremental><li><p><code>v</code>: (optional, integer) The version number (default:\n<code>NO_VERSION</code> or <code>-1</code>)</ul><li><p><code>pkg</code>: Stores package info. It can contain any number\nof <code>uid</code><ul class=incremental><li><p><code>n</code>: (required, string) Name of the package</ul><li><p>Package <code>uid</code>: Stores package or packages info<ul class=incremental><li><p><code>n</code>: (required, integer) The user ID</ul><li><p><code>uid</code>: The package user ID. It can contain any number\nof <code>op</code><ul class=incremental><li><p><code>n</code>: (required, integer) The user ID<li><p><code>p</code>: (optional, boolean) Is the app is a\nprivate/system app</ul><li><p><code>op</code>: The operation, can contain <code>st</code> or\nnothing at all<ul class=incremental><li><p><code>n</code>: (required, integer) The op name in integer,\ni.e. AppOpsManager.OP_*<li><p><code>m</code>: (required, integer) The op mode,\ni.e. AppOpsManager.MODE_*</ul><li><p><code>st</code>: State of operation: whether the operation is\naccessed, rejected or running (not available on old versions)<ul class=incremental><li><p><code>n</code>: (required, long) Key containing flags and\nuid<li><p><code>t</code>: (optional, long) Access time (default:\n<code>0</code>)<li><p><code>r</code>: (optional, long) Reject time (default:\n<code>0</code>)<li><p><code>d</code>: (optional, long) Access duration (default:\n<code>0</code>)<li><p><code>pp</code>: (optional, string) Proxy package name<li><p><code>pu</code>: (optional, integer) Proxy package uid</ul></ul><p>This definition can be found at <a href=https://android.googlesource.com/platform/frameworks/base/+/master/services/core/java/com/android/server/appop/AppOpsService.java>AppOpsService</a>.</section><section id=sec:appops-cli class=level2 data-number=7.6><h2 data-number=7.6><span class=header-section-number>7.6</span> <a href=#toc:sec:appops-cli>Command Line Interface</a><a href=#sec:appops-cli class=anchor aria-hidden=true></a></h2><p><code>appops</code> or <code>cmd appops</code> (on latest versions)\ncan be accessible via ADB or root. This is an easier method to get or\nupdate any operation for a package (provided the package name is known).\nThe help page of this command is self-explanatory:<pre><code>AppOps service (appops) commands:\nhelp\nPrint this help text.\nstart [--user &lt;USER_ID&gt;] &lt;PACKAGE | UID&gt; &lt;OP&gt;\nStarts a given operation for a particular application.\nstop [--user &lt;USER_ID&gt;] &lt;PACKAGE | UID&gt; &lt;OP&gt;\nStops a given operation for a particular application.\nset [--user &lt;USER_ID&gt;] &lt;[--uid] PACKAGE | UID&gt; &lt;OP&gt; &lt;MODE&gt;\nSet the mode for a particular application and operation.\nget [--user &lt;USER_ID&gt;] &lt;PACKAGE | UID&gt; [&lt;OP&gt;]\nReturn the mode for a particular application and optional operation.\nquery-op [--user &lt;USER_ID&gt;] &lt;OP&gt; [&lt;MODE&gt;]\nPrint all packages that currently have the given op in the given mode.\nreset [--user &lt;USER_ID&gt;] [&lt;PACKAGE&gt;]\nReset the given application or all applications to default modes.\nwrite-settings\nImmediately write pending changes to storage.\nread-settings\nRead the last written settings, replacing current state in RAM.\noptions:\n&lt;PACKAGE&gt; an Android package name or its UID if prefixed by --uid\n&lt;OP&gt;      an AppOps operation.\n&lt;MODE&gt;    one of allow, ignore, deny, or default\n&lt;USER_ID&gt; the user id under which the package is installed. If --user is not\nspecified, the current user is assumed.</code></pre></section></section><section id=footnotes class=\"footnotes footnotes-end-of-document\" role=doc-endnotes><hr><ol><li id=fn1><p>Nur für die Verteilung normaler Versionen<a href=#fnref1 class=footnote-back role=doc-backlink>↩︎</a><li id=fn2><p>GitHub Pull Anträge werden manuell mit den\nentsprechenden Patches zusammengeführt. Daher kann es sein, dass GitHub\nsie fälschlicherweise als geschlossen markiert, anstatt sie\nzusammenzuführen.<a href=#fnref2 class=footnote-back role=doc-backlink>↩︎</a><li id=fn3><p>Sie können mich auch als “Muntashir Akon” ansprechen<a href=#fnref3 class=footnote-back role=doc-backlink>↩︎</a></ol></section>"
  },
  {
    "path": "docs/raw/de/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"intro$main$$supported-versions-title\">Unterstützte Versionen</string>\n    <string name=\"titlepage$user_manual\">{\\\\huge\\\\bfseries Nutzerhandbuch\\\\par}</string>\n    <string name=\"intro$main$$terminologies-title\">Fachbegriffe</string>\n    <string name=\"intro$main$terminologies\">\\\\begin{itemize}\n\\n \\\\item \\\\textbf{AM} --- Kurzbezeichnung für App Manager.\n\\n \\\\item \\\\textbf{Blockieren/Entsperren} --- Dient zum Sperren oder Entsperren von Komponenten. Wie Komponenten blockiert werden, hängt von \n\\n den Benutzereinstellungen ab.\n\\n \\\\item \\\\textbf{IFW} --- Kurzform für Intent Firewall.\n\\n \\\\item \\\\textbf{Ops} --- Kurzbezeichnung für Maßnahmen, e.g.\\\\ app ops, batch ops, 1-click ops\n\\n \\\\item \\\\textbf{SSAID} --- Kurzbezeichnung von \\\\texttt{Settings.Secure.Android\\\\_ID}. Es ist eine Gerätekennung, die\n\\n jeder App zugewiesen wird (ab Android Oreo). Sie wird aus der Kombination des Signierzertifikats der App und der \n\\n SSAID, die für das Paket \\\\texttt{Android} festgelegt wurde. Daher ist sie für eine App garantiert gleich, so lange\n\\n der Benutzer das Gerät nicht formatiert. Sie wird häufig für die Nachverfolgung verwendet.\n\\n \\\\item \\\\textbf{Tracker} --- Bezeichnet Tracker-Komponenten im gesamten Dokument und im App Manager, außer in der\n\\n \\\\hyperref[sec:scanner-page]{Scanner-Seite}. Tracker umfassen Bibliotheken wie Crash Reporter, Analytik,\n\\n Profilerstellung, Identifizierung, Anzeige, Standort usw. Daher sind sie in ihren Funktionen nicht gleich. Es gibt keine Unterscheidung oder Voreingenommenheit\n\\n zwischen Open-Source- und Closed-Source-Bibliotheken, die Tracking fördern.\n\\n\\\\end{itemize}</string>\n    <string name=\"intro$main$bin-sources\">App Manager wird über die folgenden Quellen verbreitet. Inoffizielle Quellen können modifizierte Versionen von App\n\\nManager vertreiben, und niemand außer Ihnen ist für die Folgen der Verwendung solcher Distributionen verantwortlich.\n\\n\\\\begin{enumerate}\n\\n \\\\item Offizielles F-Droid-Repository.\\\\footnote{Nur für die Verteilung normaler Versionen}\\\\\\\\\n\\n \\\\textit{Link:} \\\\url{https://f-droid.org/packages/io.github.muntashirakon.AppManager}\n\\n \\\\item GitHub Repository.\\\\\\\\\n\\n \\\\textit{Normale Veröffentlichungen:} \\\\url{https://github.com/MuntashirAkon/AppManager/releases}\\\\\\\\\n\\n \\\\textit{Debug-Versionen:} \\\\url{https://github.com/MuntashirAkon/AppManager/actions}\n\\n \\\\item Telegram.\\\\\\\\\n\\n \\\\textit{Normale Veröffentlichungen:} \\\\url{https://t.me/AppManagerChannel}\\\\\\\\\n\\n \\\\textit{Debug-Versionen:} \\\\url{https://t.me/AppManagerDebug}\n\\n\\\\end{enumerate}</string>\n    <string name=\"intro$main$donation\">\\\\emph{Eine Spende oder ein Kauf ist keine Voraussetzung für die Nutzung von App Manager.} App Manager unterstützt zwar keine\n\\nKäufe, es können aber Spenden über Open Source Collective an den Entwickler von App Manager gesendet werden.\n\\n\n\\nOpen Source Collective ist ein Finanzdienstleister auf der Open Collective-Plattform, der Open-Source-Projekten bei der Verwaltung\n\\nihre Finanzen. Derzeit werden Zahlungen per Bankkonten, PayPal, Kredit- oder Debitkarten und\n\\nKryptowährungen unterstützt.\n\\n\n\\n\\\\textit{Link:} \\\\url{https://opencollective.com/muntashir}.\n\\n\n\\nMit der Überweisung von Spenden stimmen die Absender zu, dass sie die Spenden nicht als Druckmittel verwenden, um die von ihnen gewünschten\n\\nFunktionen zu priorisieren. Für Feature-Anfragen sind keine Belohnungen oder Spenden erforderlich, und sie werden nach den\n\\nPräferenzen des Entwicklers priorisiert.\n\\n\n\\n\\\\emph{App-Manager nimmt alle Angebote für Finanzierungen oder Zuschüsse an.} Vertreter der interessierten Organisation können\n\\ndirekt den Entwickler über die in \\\\Sref{sec:Ansprechpartner} angegebenen Optionen kontaktieren.</string>\n    <string name=\"intro$main$intro\">App Manager ist ein fortschrittlicher Paketmanager für Android. Er bietet zahllose Funktionen und benötigt daher ein Benutzer-\n\\nhandbuch, um seine Benutzer zu unterstützen. Dieses Dokument fungiert als Benutzerhandbuch für App Manager in dem Sinne,\n\\ndass es darauf abzielt, jede Funktion zu beschreiben, die App Manager zu bieten hat. Dieses Dokument kann auch als ``offizieller\\'\\' Leitfaden für App Manager betrachtet\n\\nwerden und stellt das erwartete Verhalten von App Manager dar. Übersetzungen können dieses Dokument (das in \n\\nEnglisch verfasst ist) falsch interpretieren. Daher sollte jeder befähigte Benutzer die englische Version des Dokuments lesen, um das Beste\n\\naus dem App Manager herauszuholen. Es kann auch andere inoffizielle oder Drittanbieter-Ressourcen wie Blog-Artikel, Videos, Chat-\n\\nGruppen usw. geben. Diese Ressourcen können zwar für viele Menschen nützlich sein, sind aber möglicherweise nicht auf dem neuesten \n\\nStand der aktuellen Version von App Manager. Wenn in App Manager Abweichungen von diesem Dokument festgestellt werden, sollten diese im \n\\n\\\\href{https://github.com/MuntashirAkon/AppManager/issues}{App Manager Problembehandlung} gemeldet werden.</string>\n    <string name=\"intro$main$submit-patches\">Repositories, die sich an anderen Orten als GitHub befinden, werden derzeit als Spiegel betrachtet. Pull-/Merge-Anfragen, die\n\\nan diesen Orten eingereicht wurden, werden nicht akzeptiert.\\\\footnote{GitHub Pull Anträge werden manuell mit den entsprechenden Patches zusammengeführt.\n\\nDaher kann es sein, dass GitHub sie fälschlicherweise als geschlossen markiert, anstatt sie zusammenzuführen.} Stattdessen können Patches (als \\\\texttt{.patch-} Dateien)\n\\nüber E-Mail-Anhänge eingereicht werden. \\\\textit{Die Signierung ist eine Voraussetzung.} Weitere Informationen finden Sie in der Datei CONTRIBUTING, die sich im Stammverzeichnis\n\\ndes Quellcodes befindet.\n\\n\n\\n\\\\begin{warning}{Hinweis}\n\\n Wenn Sie Patches per E-Mail einreichen, kann die gesamte Konversation in Zukunft öffentlich zugänglich sein. Daher sollten Sie keine\n\\n persönlich identifizierbaren Informationen (PII) außer Ihrem Namen oder Ihrer E-Mail-Adresse aufführen.\n\\n\\\\end{warning}</string>\n    <string name=\"pages$main-page$intro\">Die Hauptseite listet alle installierten, deinstallierten und gesicherten Anwendungen auf. Ein einfacher Klick auf ein installiertes Anwendungselement\n\\nöffnet die entsprechende Seite \\\\hyperref[sec:app-details-page]{App-Detailseite}. Für die deinstallierten Systemanwendungen wird ein\n\\nDialogfeld angezeigt, das zur Neuinstallation der Anwendung verwendet werden kann. Mit der Option \\\\hyperlink{par:main-page-sort}{Sortierung} aus den\n\\nListenoptionen können die App-Elemente auf verschiedene Weise sortiert und beim Beenden beibehalten werden. Es ist auch möglich, Elemente zu filtern\n\\nmit Hilfe der \\\\hyperlink{par:main-page-filter}{Filter} Option in den Listenoptionen. Die Filterung ist auch über die \n\\nSuchleiste mit zusätzlicher Unterstützung für reguläre Ausdrücke möglich..</string>\n    <string name=\"intro$main$$introduction-chapter-title\">Einleitung</string>\n    <string name=\"intro$main$$official-sources-title\">Offizielle Quellen</string>\n    <string name=\"intro$main$$source-code-links-title\">Links zum Quellcode</string>\n    <string name=\"intro$main$$translations-title\">Übersetzungen</string>\n    <string name=\"intro$main$$contributing-title\">Mitwirkende</string>\n    <string name=\"intro$main$$buiding-title\">Hinweise zur Erstellung</string>\n    <string name=\"intro$main$$submit-patches-title\">Einreichen von Patches</string>\n    <string name=\"titlepage$quotation\">\\\\begin{quotation}\n\\n ``Weise und langsam. Wer schnell läuft, der stolpert.\\'\\'\n\\n %\\\\sourceatright\n\\n {--- Bruder Lorenz, \\\\textit{Romeo und Julia}}\n\\n \\\\end{quotation}</string>\n    <string name=\"intro$main$$bin-sources-title\">Quellen der binären Verteilung</string>\n    <string name=\"intro$main$$donation-title\">Spende \\\\&amp; Förderung</string>\n    <string name=\"intro$main$$contact-title\">Ansprechpartner</string>\n    <string name=\"intro$main$supported-versions\">Derzeit werden die Versionen v3.0.0 -- v3.0.3 (stable) und v3.1.0 (alpha und Debug Versionen) unterstützt. Frühere Versionen von App\n\\nManager können Sicherheitslücken enthalten und sollten nicht verwendet werden.</string>\n    <string name=\"intro$main$source-code-links\">Alle außer GitHub sind die Spiegel-Links. Die Tags sollten immer auf dem neuesten Stand sein, aber beim Master-Zweig ist nicht garantiert, dass er\n\\naktuell zu sein. Wenn das Ziel ist, den Master-Zweig zu klonen, verwenden Sie den GitHub-Link statt der anderen.</string>\n    <string name=\"intro$main$translations\">App Manager akzeptiert keine Übersetzungen direkt über Pull-/Merge-Anfragen. Übersetzungen werden automatisiert über\n\\nWeblate realisiert. Um dem Übersetzungsteam beizutreten, besuchen Sie \\\\url{https://hosted.weblate.org/engage/app-manager/}.</string>\n    <string name=\"intro$main$contributing\">Es gibt mehrere Möglichkeiten, wie ein Benutzer einen Beitrag leisten kann, z. B. durch das Erstellen hilfreicher Fragen, die Teilnahme an Diskussionen, die Verbesserung von\n\\nDokumentationen und Übersetzungen, das Hinzufügen unbekannter Bibliotheken oder Tracker, die Überprüfung des Quellcodes sowie die\n\\nMeldung von Sicherheitslücken.</string>\n    <string name=\"intro$main$buiding\">Bauanleitungen finden Sie in der Datei BUILDING, die sich im Stammverzeichnis des Quellcodes befindet.</string>\n    <string name=\"pages$main$$pages-chapter-title\">Seiten</string>\n    <string name=\"pages$main-page$$section-title\">Hauptseite</string>\n    <string name=\"pages$main-page$$how-app-ops-work-title\">Ein Menüpunkt der Anwendungsliste auf der Hauptseite</string>\n    <string name=\"pages$main-page$$batch-operations-title\">Stapelverarbeitung</string>\n    <string name=\"pages$main-page$$colour-codes-title\">Farbcode</string>\n    <string name=\"intro$main$contact\">Muntashir Al-Islam\\\\footnote{Sie können mich auch als ``Muntashir Akon\\'\\' ansprechen}\\\\\\\\\n\\nEmail: \\\\href{mailto:muntashirakon@riseup.net}{muntashirakon [at] riseup [dot] net}\\\\\\\\\n\\nKey Fingerprint: \\\\texttt{7bad37c2981e41f8f6abea7f58f0b4f26c346fce}\\\\\\\\\n\\nGitHub: \\\\url{https://github.com/MuntashirAkon}\\\\\\\\\n\\nTwitter: \\\\url{https://twitter.com/Muntashir}</string>\n    <string name=\"pages$main-page$$application-types-title\">Anwendungstypen</string>\n    <string name=\"pages$main-page$$version-info-title\">Infos zur Version</string>\n    <string name=\"pages$main-page$$options-menu-title\">Menü Optionen</string>\n    <string name=\"pages$main-page$$instructions-title\">Anleitungen</string>\n    <string name=\"pages$main-page$$list-options-title\">Liste der Optionen</string>\n    <string name=\"pages$main-page$$sort-title\">Sortierung</string>\n    <string name=\"pages$main-page$$filter-title\">Filter</string>\n    <string name=\"pages$main-page$$profile_name-title\">Profilname</string>\n    <string name=\"pages$main-page$$1-click-ops-title\">1-Klick-Operationen</string>\n    <string name=\"pages$main-page$$app-usage-title\">App Nutzung</string>\n    <string name=\"pages$main-page$$running-apps-title\">Laufende Apps</string>\n    <string name=\"pages$main-page$$profiles-title\">Profile</string>\n    <string name=\"pages$main-page$$apk-updater-title\">APK-Updater</string>\n    <string name=\"pages$main-page$$termux-title\">Termux</string>\n    <string name=\"pages$main-page$$settings-title\">Einstellungen</string>\n    <string name=\"guide$backup-restore$options\">Mit den Backup-Optionen (intern als Backup-Flags bezeichnet) können Sie die Backups im Handumdrehen anpassen.\n\\nDie Anpassungen werden jedoch nicht für zukünftige Sicherungen gespeichert.\n\\nWenn Sie diesen Dialog anpassen möchten, verwenden Sie \\\\hyperref[subsubsec:settings-backup-options]{Backup-Optionen} in der \\\\hyperref[sec:settings-page]{Einstellungen-Seite}.\n\\n\n\\nEine vollständige Beschreibung der Sicherungsoptionen finden Sie weiter unten:\n\\n\\\\begin{itemize}\n\\n \\\\item \\\\textbf{APK-Dateien.} Whether to back up the APK files.\n\\n This includes the \\\\textit{base APK} file along with the \\\\texttt{split APK} files if they exist.\n\\n\n\\n \\\\item \\\\textbf{Internal data.} Ob die APK-Dateien gesichert werden sollen.\n\\n Dies umfasst die Datei \\\\textit{Basis-APK} sowie die Dateien \\\\texttt{Split-APK}, falls vorhanden.\n\\n\n\\n \\\\item \\\\textbf{External data.} Whether to back up data directories located in the internal memory as well as SD Card (if exists).\n\\n External data directories often contain non-essential app data or media files (instead of using the dedicated media folder) and may increase the backup size.\n\\n However, it might be essential for some apps.\n\\n Although it isn\\'t checked by default (as it might dramatically increase the size of the backups), you may have to check it in order to ensure a smooth restore of your backups.\n\\n \\\\begin{warning}{Caution}\n\\n Internal data folders should always be backed up if you are going to back up the external data folders.\n\\n However, it could be useful to back up only the external folders if the app in question downloads a lot of assets from the Internet.\n\\n \\\\end{warning}\n\\n\n\\n \\\\item \\\\textbf{OBB and media.} Whether to back up or restore the OBB and the media directories located in the\n\\n external storage or the SD Card.\n\\n This is useful for games and the graphical software which actually use these folders.\n\\n\n\\n \\\\item \\\\textbf{Cache.} Android apps have multiple cache directories located at every data directories (both internal and external).\n\\n There are two types of cache: \\\\textbf{cache} and \\\\textbf{code cache}.\n\\n Enabling this option excludes both cache directories from all the data directories.\n\\n It is generally advised to exclude cache directories since most apps do not clear the cache regularly (for some\n\\n reason, the only way an app can clear its cache is by deleting the entire cache directory) and usually handled by the OS itself.\n\\n Apps such as Telegram may use a very large cache (depending on the storage space) which may dramatically increase the backup size.\n\\n When it is disabled, AM also ignores the \\\\textbf{no\\\\_backup} directories.\n\\n\n\\n \\\\item \\\\textbf{Extras.} Backup/restore app permissions, net policy, battery optimization, SSAID, etc., enabled by default.\n\\n Note that, blocking rules are applied \\\\textit{after} applying the extras.\n\\n So, if an item is present in both places, it will be overwritten (i.e., the one from the blocking rules will be used).\n\\n\n\\n \\\\item \\\\textbf{Rules.} This option lets you back up blocking rules configured within App Manager.\n\\n This might come in handy if you have customised permissions or block some components using App Manager as they will\n\\n also be backed up or restored when you enable this option.\n\\n\n\\n \\\\item \\\\textbf{Backup Multiple.} Whether this is a multiple backup.\n\\n By default, backups are saved using their user ID\\\\@.\n\\n Enabling this option allows you to create additional backups.\n\\n These backups use the current date-time as the default backup name, but you can also specify custom backup name\n\\n using the input field displayed when you click on the \\\\textbf{Backup} button.\n\\n\n\\n \\\\item \\\\textbf{Ausgewählte Anwender.} Sicherung oder Wiederherstellung für die ausgewählten Benutzer statt nur für den aktuellen Benutzer.\n\\n Diese Option wird nur angezeigt, wenn das System mehr als einen Benutzer hat.\n\\n\n\\n \\\\item \\\\textbf{Signaturprüfungen überspringen.} Beim Erstellen eines Backups werden die Prüfsummen jeder Datei (sowie die Signier-\n\\n Zertifikat(e) der APK-Basisdatei) generiert und in der Datei \\\\texttt{checksums.txt} gespeichert.\n\\n Wenn Sie die Sicherung wiederherstellen, werden die Prüfsummen erneut generiert und mit den in der genannten Datei gespeicherten Prüfsummen abgeglichen.\n\\n Wenn Sie diese Option aktivieren, werden die Signaturprüfungen ausgeschaltet.\n\\n Diese Option wird nur bei der Wiederherstellung eines Backups angewendet.\n\\n Während der Sicherung werden die Prüfsummen unabhängig von dieser Option generiert.\n\\n \\\\begin{warning}{Caution}\n\\n Sie sollten diese Option immer deaktivieren, um sicherzustellen, dass Ihre Sicherungen nicht von Anwendungen Dritter verändert werden.\n\\n Dies würde jedoch nur funktionieren, wenn Sie die Verschlüsselung aktiviert haben.\n\\n \\\\end{warning}\n\\n\\\\end{itemize}\n\\n\n\\n\\\\seealsoinline{\\\\hyperref[subsubsec:settings-encryption]{Einstellungen: Verschlüsselung}}</string>\n    <string name=\"appendices$changelogs$$chapter-title\">Änderungsprotokolle</string>\n    <string name=\"guide$backup-restore$$delete-title\">Sicherung löschen</string>\n    <string name=\"guide$backup-restore$intro\">App Manager verfügt über ein modernes, fortschrittliches und einfach zu bedienendes Sicherungs-/Wiederherstellungssystem, das von Grund auf neu implementiert wurde.\n\\nDies ist wahrscheinlich die einzige App, die nicht nur die App oder ihre Daten wiederherstellen kann, sondern auch die Berechtigungen und\n\\nRegeln, die Sie im App Manager konfiguriert haben.\n\\nSie können auch wählen, ob Sie eine App mehrfach (mit benutzerdefinierten Namen) oder für alle Benutzer sichern möchten.\n\\n\n\\n\\\\begin{amseealso}\n\\n \\\\item \\\\hyperref[subsec:1-click-back-up]{1-Click Ops: Sicherung}\n\\n \\\\item \\\\hyperref[subsec:1-click-restore]{1-Click Ops: Wiederherstellung}\n\\n\\\\end{amseealso}</string>\n    <string name=\"guide$backup-restore$location\">Sichern/Wiederherstellen ist ein Teil von\\\\hyperref[subsec:batch-operations]{Batch-Operationen}.\n\\nEs befindet sich auch im \\\\hyperref[subsubsec:app-info-options-menu]{Optionsmenü} in der\n\\n\\\\hyperref[subsec:app-info-tab]{Registerkarte Anwendungsinfo}.\n\\nClicking on \\\\textbf{Backup/Restore} opens the \\\\textbf{Backup Options}.\n\\nBackups are located at \\\\texttt{/storage/emulated/0/AppManager} by default.\n\\nYou can configure custom backup location in the \\\\hyperref[subsubsec:backup-volume]{settings page} in which case the backups\n\\nwill be located at the \\\\texttt{AppManager} folder in the selected volume.\n\\n\n\\n\\\\begin{tip}{Hinweis}\n\\n Wenn eine oder mehrere ausgewählte Anwendungen keine Sicherung haben, werden die Optionen \\\\textbf{Wiederherstellen} and \\\\textbf{Sicherung löschen} \n\\n nicht angezeigt.\n\\n\\\\end{tip}</string>\n    <string name=\"guide$backup-restore$$backup-title\">Sicherung</string>\n    <string name=\"guide$backup-restore$$restore-title\">Wiederherstellung</string>\n    <string name=\"pages$app-details-page$$colour-codes-title\">Farbcodes</string>\n    <string name=\"pages$main-page$running-apps\">Dieser Menüpunkt öffnet eine neue Seite, auf der eine Liste der laufenden Anwendungen oder Prozesse angezeigt wird. Er zeigt auch die\n\\naktuelle Speicher- und Cache-Nutzung (falls verfügbar) an. Wenn Root oder ADB für den App Manager nicht verfügbar ist, zeigt er sich nur\n\\nin den neueren Versionen von Android. Die laufenden Anwendungen oder Prozesse können auf der Ergebnisseite auch zwangsgestoppt oder beendet werden.\n\\nErgebnisseite beendet werden. Die Protokolle für die einzelnen Prozess-IDs (PIDs) können auch im \\\\hyperref[subsubsec:log-viewer]{Log-Betrachter} eingesehen werden.\n\\nDarüber hinaus ist es möglich, Stapelverarbeitungsvorgänge auszuführen, indem Sie auf das Symbol klicken oder einen Langklick auf ein\n\\nElement. Ein normaler Klick auf ein Element öffnet einen Dialog, in dem detailliertere Informationen angezeigt werden.</string>\n    <string name=\"pages$main-page$profiles\">Dieser Menüpunkt öffnet die Seite \\\\hyperref[sec:profiles-page]{Profile-Seite}. Profile sind eine Möglichkeit zur Konfiguration regelmäßig verwendeter\n\\nAufgaben. Sie können auch über Tastenkombinationen aufgerufen werden.</string>\n    <string name=\"pages$app-details-page$$section-title\">App-Detailseite</string>\n    <string name=\"pages$main-page$apk-updater\">Wenn die App \\\\href{https://github.com/rumboalla/apkupdater}{APK Updater} im System installiert ist, kann sie\n\\ndirekt über diesen Menüpunkt geöffnet werden. Die Option bleibt ausgeblendet, wenn die App nicht im System vorhanden ist.</string>\n    <string name=\"pages$main-page$termux\">Wenn die App \\\\href{https://github.com/termux/termux-app}{Termux} im System installiert ist, kann die laufende Sitzung (oder eine\n\\nneue Sitzung) direkt über diesen Menüpunkt geöffnet werden. Die Option bleibt ausgeblendet, wenn die App nicht im System\n\\n vorhanden ist.</string>\n    <string name=\"pages$main-page$settings\">Dieser Menüpunkt öffnet die In-App-Hyperref[sec:settings-page]{Einstellungsseite}.</string>\n    <string name=\"pages$app-details-page$$app-info-tab-title\">Registerkarte App-Info</string>\n    <string name=\"pages$app-details-page$$app-info-general-information-title\">Allgemeine Informationen</string>\n    <string name=\"pages$app-details-page$$horizontal-action-panel-title\">Waagerechte Aktionsfläche</string>\n    <string name=\"pages$app-details-page$$component-tabs-title\">Registerkarten der Komponenten</string>\n    <string name=\"pages$app-details-page$$app-info-options-menu-title\">Menü Optionen</string>\n    <string name=\"pages$app-details-page$$activities-title\">Aktivitäten</string>\n    <string name=\"pages$app-details-page$$receivers-title\">Empfänger</string>\n    <string name=\"pages$app-details-page$$servcies-title\">Dienste</string>\n    <string name=\"pages$app-details-page$$providers-title\">Anbieter</string>\n    <string name=\"pages$app-details-page$$additional-features-for-rooted-phones-title\">Zusätzliche Funktionen für gerootete Handys</string>\n    <string name=\"pages$app-details-page$$blocking-trackers-title\">Tracker blockieren.</string>\n    <string name=\"pages$app-details-page$$permission-tabs-title\">Registerkarten Berechtigungen</string>\n    <string name=\"pages$app-details-page$$uses-permissions-title\">Verwendete Berechtigungen</string>\n    <string name=\"pages$app-details-page$$permissions-title\">Berechtigungen</string>\n    <string name=\"pages$app-details-page$$signatures-tab-title\">Registerkarte Signaturen</string>\n    <string name=\"pages$app-details-page$intro\">\\\\textbf{Anwendungsdetails} Seite besteht aus 11 (elf) Registerkarten. Sie beschreibt fast alle Informationen, die\n\\neine Anwendung haben kann, einschließlich aller Attribute aus ihrem Manifest, \\\\hyperref[ch:app-ops]{Anwendungsoperationen}, Signier\n\\nInformationen, Bibliotheken, und so weiter.</string>\n    <string name=\"pages$app-details-page$$app-ops-title\">Anwendungsoperationen</string>\n    <string name=\"pages$app-details-page$app-info-tab\">\\\\textbf{App Info} enthält allgemeine Informationen über eine Anwendung. Außerdem werden hier viele Aktionen aufgelistet, die\n\\nauf dieser Registerkarte durchgeführt werden können.</string>\n    <string name=\"pages$app-details-page$colour-codes\">Liste der Farben, die auf dieser Seite verwendet werden, und ihre Bedeutung:\n\\n\\\\begin{itemize}\n\\n \\\\item \\\\colorbox{AMRed}{\\\\textcolor{black}{Rot (Tag)}} / \\\\colorbox{AMDarkRed}{\\\\textcolor{white}{Dunkelrot (Nacht)}}\n\\n -- Kennzeichnet alle App-OPs oder Berechtigungen mit dem Flag \\\"Gefährlich\\\" oder alle im App Manager blockierten Komponenten\n\\n\n\\n \\\\item \\\\colorbox{AMLightRed}{\\\\textcolor{black}{Hellrot (Tag)}} / \\\\colorbox{AMVeryDarkRed}{\\\\textcolor{white}{sehr\n\\n Dunkelrot (Nacht)}} -- Bezeichnet die außerhalb des App Managers deaktivierten Komponenten\n\\n\n\\n \\\\begin{tip}{Hinweis}\n\\n Eine Komponente, die als deaktiviert gekennzeichnet ist, bedeutet nicht immer, dass sie vom Benutzer deaktiviert wurde: Sie kann auch vom System deaktiviert werden\n\\n oder in ihrem Manifest als deaktiviert gekennzeichnet sein. Die Komponenten einer deaktivierten Anwendung werden auch\n\\n vom System (und App Manager) als deaktiviert betrachtet.\n\\n \\\\end{tip}\n\\n\n\\n \\\\item \\\\colorbox{AMVividOrange}{\\\\textcolor{black}{Kräftiges Orange (Tag)}} / \\\\colorbox{AMVeryDarkOrange}{\n\\n \\\\textcolor{white}{sehr dunkles Orange (Nacht)}} -- Bezeichnet die Tracker-Komponenten\n\\n\n\\n \\\\item \\\\colorbox{AMSoftMagenta}{\\\\textcolor{black}{Zartes Magenta (Tag)}} / \\\\colorbox{AMVeryDarkViolet}{\n\\n \\\\textcolor{white}{sehr dunkles Violett (Nacht)}} -- Bezeichnet die laufenden Dienste.\n\\n\\\\end{itemize}</string>\n    <string name=\"pages$app-details-page$app-info-general-information\">Die folgende Liste ist in der gleichen Reihenfolge wie auf der Registerkarte \\\"App-Info\\\" aufgeführt.\n\\n\\\\begin{itemize}\n\\n \\\\item \\\\textbf{Anwendungssymbol} Das Anwendungssymbol. Wenn die Anwendung kein Symbol hat, wird das Standardsymbol des Systems\n\\n angezeigt. Es ist auch möglich, die APK-Signatur über SHA- oder MD5-Summen zu überprüfen, die in der Zwischenablage\n\\n gespeichert sind, indem Sie einfach darauf klicken.\n\\n\n\\n \\\\item \\\\textbf {Anwendungskennzeichnung.} Das Anwendungslabel oder der Name der Anwendung.\n\\n\n\\n \\\\item \\\\textbf{Paketname.} Der Name des Anwendungspakets. Wenn Sie auf den Namen klicken, wird er in der Zwischenablage gespeichert.\n\\n\n\\n \\\\item \\\\textbf{Version.} Die Anwendungsversion ist in zwei Teile unterteilt. Der erste Teil heißt \\\\textit{Versions-\n\\n name}. Das Format dieses Teils variiert, besteht aber häufig aus mehreren durch Punkte getrennten Ganzzahlen. Der zweite Teil\n\\n wird \\\\textit{Versionscode} genannt. Er wird von den ersten Klammern umschlossen. Der Versionscode ist eine ganze Zahl, die genutzt wird\n\\n um zwischen Anwendungsversionen zu unterscheiden (da ein Versionsname für eine Maschine unlesbar sein kann). Generell gilt,\n\\n hat eine neue Version einer Anwendung einen höheren Versionscode als die alten Versionen. Zum Beispiel, wenn \\\\texttt{123} und\n\\n \\\\texttt{125} zwei Versionscodes einer Anwendung sind, kann man sagen, dass die letztere aktueller ist als die erstere\n\\n weil der Versionscode der letzteren höher ist. Anwendungen, die verschiedene APK-Dateien für dieselbe Version\n\\n auf verschiedenen Plattformen (Mobilgeräte, Tabs, Desktops usw.) oder Architekturen (32/64 Bit, ARM oder Intel) anbieten, können die Versionsnummern\n\\n Nummern irreführend sein, da sie oft Präfixe für jede Plattform hinzufügen.\n\\n\n\\n \\\\item \\\\textbf{Tags.} (Auch bekannt als Tag-Clouds) Tags enthalten die grundlegendsten, prägnantesten und nützlichsten Informationen über eine\n\\n Anwendung, wie z. B..\n\\n \\\\begin{itemize}\n\\n \\\\item \\\\textit{Tracker info.} Anzahl der Tracker-Komponenten in der Anwendung (z. B. \\\\textit{5 Tracker}) Die\n\\n Farbe des Tags erscheint orange, wenn die Tracker nicht blockiert sind, und dunkelcyan, wenn sie im App Manager blockiert sind.\n\\n Ein Klick auf das Tag öffnet ein Dialogfeld mit der Liste der Tracker-Komponenten, die gesperrt oder freigegeben werden können\n\\n wenn der App Manager über ausreichende Berechtigungen verfügt.\n\\n \\\\Textit{Anwendungstyp.} Benutzeranwendung oder Systemanwendung. Wenn es sich um eine Systemanwendung handelt, ob\n\\n die Anwendung eine aktualisierte Version der Systemanwendung ist oder ob die Anwendung systemlos installiert wurde\n\\n über Magisk installiert wurde.\n\\n \\\\item \\\\textit{Split APK info.} Anzahl der Splits in der APK mit Ausnahme der Basis-APK (z. B. \\\\textit{5 splits}).\n\\n Wenn Sie auf das Tag klicken, wird ein Dialogfeld mit den Informationen über die aufgeteilte APK, wie Typ und Größe, geöffnet.\n\\n \\\\item \\\\textit{Debuggable.} Die Anwendung kann über ADB\\\\@ debuggt werden. Debuggingfähige Anwendungen können bestimmte\n\\n Funktionen nutzen, die einer normalen Anwendung nicht zur Verfügung stehen. Auf die Daten der Anwendung kann über ADB zugegriffen werden (z.B.\\\\ unter Verwendung von\n\\n \\\\texttt{run-as} command) ohne zusätzliche Berechtigungen.\n\\n \\\\item \\\\textit{Test only.} Die Anwendung ist eine reine Testanwendung. Reine Testanwendungen können bestimmte Funktionen nutzen\n\\n Funktionen nutzen, die einer normalen Anwendung nicht zur Verfügung stehen. Auf die Daten der Anwendung kann über ADB zugegriffen werden (z. B. unter Verwendung von\n\\n \\\\texttt{run-as} command) ohne zusätzliche Berechtigungen.\n\\n \\\\item \\\\textit{Large heap.} Die Anwendung hat eine große Heap-Größe angefordert, d.h. es wird mehr Platz im Speicher (RAM)\n\\n für die dynamische Zuweisung angefordert. Es obliegt dem Betriebssystem zu entscheiden, ob es der Anwendung einen großen\n\\n Speicherplatz für die Anwendung zugewiesen wird. Der App Manager zum Beispiel fordert eine große Heap-Größe an, weil er eine ganze APK in den Speicher laden muss.\n\\n APK in den Speicher laden muss, während er eine APK vor Android 8 scannt.\n\\n \\\\Kein Code. Der Anwendung ist kein Code zugeordnet, d. h. es sind keine DEX-Dateien vorhanden.\n\\n Bei einigen Systemanwendungen kann sich der eigentliche Code an einem anderen Ort befinden.\n\\n \\\\item \\\\textit{Running.} Ein oder mehrere Dienste der Anwendung werden derzeit im Hintergrund ausgeführt. Ein Klick auf\n\\n auf das Tag öffnet einen Dialog mit der Liste der laufenden Dienste. Durch Anklicken eines beliebigen Dienstes wird dieser in der Protokollanzeige geöffnet\n\\n Viewer, sofern die Funktion des Log Viewers aktiviert ist.\n\\n \\\\Textit{Stopped} Die Anwendung wird zwangsweise gestoppt. Dies kann jedoch nicht verhindern, dass sie später automatisch\n\\n später.\n\\n \\\\item \\\\textit{Disabled.} Zeigt an, dass die Anwendung deaktiviert (vor dem Startprogramm verborgen) ist.\n\\n \\\\item \\\\textit{Suspended.} Zeigt an, dass die Anwendung ausgesetzt ist (im Launcher ausgegraut).\n\\n \\\\item \\\\textit{Hidden.} Zeigt an, dass die Anwendung versteckt ist (im Launcher ausgeblendet).\n\\n \\\\item \\\\textit{MagiskHide.} MagiskHide ist aktiviert. Ein Klick auf das Tag öffnet einen Dialog mit der Liste der\n\\n Prozessen innerhalb der Anwendung, die der MagiskHide-Liste hinzugefügt oder aus ihr entfernt werden können.\n\\n \\\\item \\\\textit{MagiskDenyList.} Die Anwendung ist in MagiskDenyList vorhanden. Ein Klick auf das Tag öffnet einen Dialog\n\\n mit der Liste der Prozesse innerhalb der Anwendung, die zu MagiskDenyList hinzugefügt oder daraus entfernt werden können.\n\\n \\\\Element \\\"KeyStore\\\". Die Anwendung hat Elemente im Android KeyStore. Ein Klick auf das Tag öffnet einen Dialog\n\\n mit allen KeyStore-Dateien, die zur Anwendung gehören.\n\\n\n\\n \\\\Textit{Backup.} Die Anwendung wurde mindestens einmal unter Verwendung von App Manager gesichert. Ein Klick auf das Tag\n\\n wird ein Dialog geöffnet, der alle verfügbaren Sicherungen zusammen mit den Metadaten enthält.\n\\n \\\\item \\\\textit{Keine Batterieoptimierung.} Die Batterieoptimierung ist für die Anwendung deaktiviert. Es ist möglich\n\\n ist es möglich, die Akku-Optimierung wieder zu aktivieren, indem Sie auf das Tag klicken.\n\\n \\\\item \\\\hyperref[sec:net-policy]{\\\\textit{Netzpolitik.}} Die Netzpolitik (z. B. die Datennutzung im Hintergrund) ist\n\\n für die Anwendung. Wenn Sie auf das Tag klicken, wird ein Dialogfeld mit den unterstützten Richtlinien für die Plattform\n\\n zusammen mit den Optionen zu deren Konfiguration.\n\\n \\\\item \\\\hyperref[sec:terminologies]{\\\\textit{SSAID.}} Ein Klick auf das Tag öffnet ein Dialogfeld mit der aktuellen\n\\n SSAID, die der Anwendung zugewiesen ist. Es ist auch möglich, die SSAID bei Bedarf zurückzusetzen/neu zu generieren.\n\\n \\\\item \\\\textit{SAF.} Gibt an, dass der Anwendung der Zugriff auf einen oder mehrere Speicherorte oder Dateien gewährt wurde.\n\\n Dateien, d. h. URIs, über das Storage Access Framework (SAF). Ein Klick auf das Tag öffnet einen Dialog mit der Liste der\n\\n gewährten URIs.\n\\n \\\\Textit{Play App Signing}. Zeigt an, dass die Anwendung möglicherweise von Google signiert ist.\n\\n \\\\end{itemize}\n\\n\n\\n \\\\item \\\\textbf{Horizontales Aktionsfeld.} Ein Aktionspanel mit verschiedenen Aktionen, die für die Anwendung durchgeführt werden können.\n\\n die Anwendung. Siehe \\\\Sref{subsubsec:horizontal-action-panel} für eine vollständige Liste der hier verfügbaren Aktionen.\n\\n Zusätzliche Aktionen sind im Menü \\\\hyperref[subsubsec:app-info-options-menu]{options menu} verfügbar.\n\\n\n\\n \\\\item \\\\textbf{Pfade \\\\&amp; Verzeichnisse.} Enthält verschiedene Informationen zu Anwendungspfaden, einschließlich \\\\textit{app\n\\n Verzeichnis} (wo sich die APK-Dateien befinden), \\\\textit{Datenverzeichnisse} (intern, gerätegeschützt und extern),\n\\n \\\\textit{geteilte APK-Verzeichnisse} (zusammen mit den Split-Namen), und \\\\textit{native JNI-Bibliothek} (falls vorhanden). JNI\n\\n Bibliotheken werden verwendet, um native Codes aufzurufen, die normalerweise in C/C++ geschrieben sind. Die Verwendung einer nativen Bibliothek kann die Anwendung\n\\n schneller laufen lassen oder einer Anwendung helfen, Bibliotheken von Drittanbietern zu verwenden, die in anderen Sprachen als Java geschrieben wurden, wie in den meisten\n\\n Spiele. Die Verzeichnisse können über Dateimanager von Drittanbietern geöffnet werden, sofern sie dies unterstützen und über die erforderlichen\n\\n Die Verzeichnisse können über Dateimanager von Drittanbietern geöffnet werden, sofern sie diese unterstützen und über die erforderlichen Berechtigungen verfügen, indem Sie auf das Startsymbol auf der rechten Seite jedes Verzeichnisses klicken.\n\\n\n\\n \\\\item \\\\textbf {Datennutzung.} Die von der Anwendung verwendete Datenmenge, wie vom Betriebssystem gemeldet. Je nach\n\\n Android-Version kann dies eine breite Palette von Berechtigungen erfordern, einschließlich \\\\textit{Nutzungszugriff} und \\\\textit{Telefonie}\n\\n Berechtigungen.\n\\n\n\\n \\\\item \\\\textbf{Storage \\\\&amp; Cache.} Zeigt Informationen über die Größe der Anwendung (APK-Dateien, optimierte\n\\n Dateien), Daten und Cache. Bei älteren Geräten wird auch die Größe von externen Daten, Cache, Medien und OBB-Ordnern angezeigt.\n\\n Dieser Teil bleibt ausgeblendet, wenn auf neueren Geräten die Berechtigung \\\\textit{Nutzungszugriff} nicht erteilt wird.\n\\n\n\\n \\\\item \\\\textbf{Weitere Informationen} Zeigt weitere Informationen an, wie z. B..\n\\n \\\\begin{itemize}\n\\n \\\\item \\\\textbf{SDK.} Zeigt Informationen im Zusammenhang mit dem Android SDK an. Es gibt zwei (bei alten Geräten einen) Werte:\n\\n \\\\textit{Max} bezeichnet das Ziel-SDK und \\\\textit{Min} bezeichnet das Mindest-SDK (letzteres ist in alten Geräten nicht verfügbar\n\\n Geräten nicht verfügbar). Es ist empfehlenswert, Anwendungen mit dem maximalen SDK zu verwenden, das die Plattform derzeit unterstützt, um\n\\n um sicherzustellen, dass die Anwendung nicht im Kompatibilitätsmodus ausgeführt wird, um datenschutzwidrige Funktionen zu verwenden.\n\\n SDK wird auch als textbf{API Level} bezeichnet.\n\\n \\\\seealsoinline{\\\\href{https://en.wikipedia.org/wiki/Android_version_history\\\\#Overview}{Android Versionsgeschichte}}\n\\n\n\\n \\\\item \\\\textbf{Flags.} Die Anwendungsflags, die zum Zeitpunkt der Erstellung der Anwendung verwendet wurden. Für eine vollständige Liste der\n\\n Flags und deren Funktion finden Sie auf der Seite\n\\n \\\\href{https://developer.android.com/reference/android/content/pm/ApplicationInfo\\\\#flags}{offizielle Dokumentation}.\n\\n\n\\n \\\\item \\\\textbf{Date Installed.} Das Datum, an dem die Anwendung zum ersten Mal installiert wurde.\n\\n\n\\n \\\\item \\\\textbf{Date Updated.} Das Datum, an dem die Anwendung zuletzt aktualisiert wurde. Dies ist dasselbe wie \\\\textit{Date Installed}\n\\n wenn die Anwendung nicht aktualisiert wurde.\n\\n\n\\n \\\\item \\\\textbf{Installer App.} Die Anwendung, die diese Anwendung installiert hat. Nicht alle Anwendungen liefern die Informationen, die der\n\\n Paketmanager verwendet werden, um die Installer-Anwendung zu registrieren. Daher sollte dieser Wert nicht als selbstverständlich angesehen werden.\n\\n\n\\n \\\\item \\\\textbf{Benutzer-ID.} Die eindeutige Benutzer-ID, die der Anwendung vom Android-System zugewiesen wurde. Bei gemeinsam genutzten Anwendungen wird dieselbe\n\\n Benutzer-ID mehreren Anwendungen zugewiesen, die die gleiche \\\\textit{Gemeinsame User ID} haben.\n\\n\n\\n \\\\item \\\\textbf{Gemeinsame Benutzer-ID.} Gilt für Anwendungen, die gemeinsam genutzt werden. Die gemeinsam genutzte Anwendung muss\n\\n die gleichen \\\\hyperref[subsec:signatures-tab]{Signaturen} haben.\n\\n\n\\n \\\\item \\\\textbf{Primäres ABI.} Von dieser Plattform unterstützte Architektur für diese Anwendung.\n\\n\n\\n \\\\item \\\\textbf{Zygote Preload Name.} Verantwortlich für das Vorladen von Anwendungscode und Daten, die von allen\n\\n isolierte Dienste, die die Anwendung Zygote verwenden.\n\\n\n\\n \\\\item \\\\textbf{Versteckte API-Durchsetzungsrichtlinie}. Seit Android 9 sind viele Methoden und Klassen im Android-Framework\n\\n durch eine versteckte API-Durchsetzungsrichtlinie für Drittanbieteranwendungen unzugänglich gemacht. Sie hat die\n\\n folgenden Optionen:\n\\n \\\\begin{itemize}\n\\n \\\\item \\\\textit{Default.} Basierend auf der Art der Anwendung. Für Systemanwendungen sollte es deaktiviert sein,\n\\n und für andere sollte es erzwungen werden.\n\\n \\\\item \\\\textit{None/disabled.} Die Anwendung hat vollen Zugriff auf die versteckte API, wie sie vorher verwendet wurde\n\\n Android 9.\n\\n \\\\item \\\\textit{Warn.} Wie oben, mit dem Unterschied, dass Warnungen jedes Mal protokolliert werden, wenn die Anwendung auf\n\\n die versteckte API zugreift. Diese Funktion wird meist nicht verwendet.\n\\n \\\\item \\\\textit{Enforce.} Die Anwendung kann nicht auf die versteckte API zugreifen, entweder auf die dunkelgraue Liste oder die schwarze Liste, oder\n\\n beides. Dies ist die Standardoption für Anwendungen von Drittanbietern in Android 9 und höher, es sei denn, die\n\\n Anwendung vom OEM oder dem Hersteller auf die Whitelist gesetzt wurde.\n\\n \\\\begin{warning}{Warnung}\n\\n Die Richtlinie zur Durchsetzung versteckter APIs ist in Android nicht richtig implementiert und kann von der\n\\n Anwendung umgangen werden. Aus diesem Grund sollte diesem Wert nicht vertraut werden.\n\\n \\\\end{warning}\n\\n \\\\end{itemize}\n\\n\n\\n \\\\item \\\\textbf{SELinux.} Obligatorische Zugriffskontrollrichtlinie (MAC), die vom Betriebssystem über SELinux festgelegt wurde.\n\\n\n\\n \\\\item \\\\textbf{Main Activity.} Der Haupteinstiegspunkt in die Anwendung. Dies ist nur sichtbar, wenn die Anwendung über\n\\n \\\\hyperref[subsubsec:activities]{activities} und jede dieser Aktivitäten kann vom Launcher aus geöffnet werden. Außerdem gibt es eine\n\\n Start-Schaltfläche auf der rechten Seite, die verwendet werden kann, um diese Aktivität zu starten.\n\\n \\\\end{itemize}\n\\n\\\\end{itemize}</string>\n    <string name=\"pages$app-details-page$horizontal-action-panel\">Die horizontale Aktionsleiste, wie im vorherigen Abschnitt beschrieben, besteht aus verschiedenen anwendungsbezogenen Aktionen, wie z. B..\n\\n\\\\begin{itemize}\n\\n \\\\item \\\\textbf{Starten.} Starten Sie die Anwendung, sofern sie eine Starter \\\\hyperref[subsubsec:activities]{Aktivität} hat.\n\\n\n\\n \\\\item \\\\textbf{Deaktivieren.} Deaktivieren Sie die Anwendung. Diese Schaltfläche wird nicht angezeigt, wenn sie bereits deaktiviert ist oder der Benutzer\n\\n nicht über ausreichende Berechtigungen verfügt. Nachdem die Anwendung deaktiviert wurde, wird sie aus der Anwendungsschublade ausgeblendet. Verknüpfungen\n\\n für die Anwendung können ebenfalls entfernt werden. Die Anwendung kann nur über den App-Manager oder ein anderes Tool, das dies unterstützt, wieder aktiviert werden.\n\\n In den Android-Einstellungen gibt es keine Option, um eine deaktivierte Benutzeranwendung zu aktivieren.\n\\n\n\\n \\\\item \\\\textbf {Deinstallieren.} Deinstallieren Sie die Anwendung.\n\\n\n\\n \\\\item \\\\textbf{Aktivieren.} Aktivieren Sie die Anwendung. Diese Schaltfläche wird nicht angezeigt, wenn sie bereits aktiviert ist oder der Benutzer\n\\n nicht über ausreichende Berechtigungen verfügt.\n\\n\n\\n \\\\item \\\\textbf{Stopp erzwingen.} Erzwingt das Anhalten der Anwendung.\n\\n\n\\n \\\\item \\\\textbf{Daten löschen.} Löscht Daten aus der Anwendung. Dies schließt alle Informationen ein, die in den internen\n\\n und neuerdings auch in den externen Verzeichnissen gespeicherten Informationen, einschließlich Konten (falls von der Anwendung festgelegt), Cache usw. Das Löschen von Daten\n\\n aus dem App-Manager werden beispielsweise alle in der Anwendung gespeicherten Regeln entfernt (die Sperrung wird jedoch nicht aufgehoben).\n\\n Aus diesem Grund sollten Sie immer Sicherungskopien Ihrer Regeln erstellen. Diese Schaltfläche wird nicht angezeigt, wenn der Benutzer\n\\n über ausreichende Rechte verfügt.\n\\n\n\\n \\\\item \\\\textbf{Cache löschen.} Anwendungscache löschen. Es gibt keine Android-Möglichkeit, den Cache einer bestimmten\n\\n Anwendung zu löschen. Daher sind Root-Rechte erforderlich, um den Cache des internen Speichers der Anwendung zu löschen.\n\\n\n\\n \\\\item \\\\textbf{Installieren.} Aktion zur Installation einer Anwendung, die über eine Drittanbieteranwendung geöffnet wurde. Diese Schaltfläche wird nur\n\\n angezeigt, wenn die Anwendung noch nicht installiert wurde.\n\\n\n\\n \\\\item \\\\textbf{Was gibt\\'s Neues.} Diese Schaltfläche wird für eine externe Anwendung angezeigt, wenn sie bereits installiert ist. Wenn Sie auf\n\\n diese Schaltfläche wird ein Dialogfeld angezeigt, in dem die Unterschiede zwischen der geöffneten und der installierten Version im Sinne einer\n\\n Versionskontrolle an. Die angezeigten Informationen umfassen \\\\textit{Version}, \\\\textit{Tracker},\n\\n \\\\textit{Zulassungen}, \\\\textit{Komponenten}, \\\\textit{Signaturen} (Prüfsummenänderungen), \\\\textit{Merkmale},\n\\n \\\\textit{Gemeinsame Bibliotheken} und \\\\textit{SDK}.\n\\n\n\\n \\\\item \\\\textbf{Update.} Wird angezeigt, wenn die Anwendung einen höheren Versionscode hat als die installierte Anwendung.\n\\n\n\\n \\\\item \\\\textbf{Neuinstallation.} Wird angezeigt, wenn die Anwendung denselben Versionscode hat wie die installierte Anwendung.\n\\n\n\\n \\\\item \\\\textbf{Downgrade.} Wird angezeigt, wenn die Anwendung einen niedrigeren Versionscode hat als die installierte Anwendung.\n\\n\n\\n \\\\item \\\\textbf{Manifest.} Wenn Sie auf diese Schaltfläche klicken, wird die Manifest-Datei der Anwendung auf einer separaten Seite angezeigt. Die\n\\n Manifest-Datei kann über die entsprechende Schaltfläche (oben rechts) ein- oder ausgepackt oder über die Schaltfläche\n\\n oder über die Schaltfläche \\\"Speichern\\\" im Speicher abgelegt werden.\n\\n\n\\n \\\\item \\\\textbf{Scanner.} Scannt die Anwendung, um potenzielle Tracker und Bibliotheken aufzulisten. Es scannt auch die\n\\n Datei unter Verwendung von VirusTotal, falls konfiguriert.\\\\\\\\\n\\n \\\\seealsoinline{\\\\hyperref[sec:scanner-page]{Scanner-Seite}}\n\\n\n\\n \\\\item \\\\textbf{Gemeinsame Voreinstellungen} Wenn Sie auf diese Schaltfläche klicken, wird eine Liste der von der Anwendung verwendeten gemeinsamen Einstellungen angezeigt.\n\\n Wenn Sie auf ein Einstellungselement in der Liste klicken, wird die Seite \\\\hyperref[sec:shared-preferences-editor-page]{Gemeinsame Voreinstellungen\n\\n Editor-Seite}. Diese Option ist nur sichtbar, wenn der Benutzer über die erforderlichen Berechtigungen verfügt.\n\\n\n\\n \\\\item \\\\textbf {Datenbanken.} Wenn Sie auf diese Schaltfläche klicken, wird eine Liste der Datenbanken angezeigt, die von der Anwendung verwendet werden. Diese Option\n\\n ist nur sichtbar, wenn der Benutzer über die erforderlichen Berechtigungen verfügt.\n\\n\n\\n \\\\item \\\\textbf{F-Droid.} Öffnet die Anwendung in Ihrem bevorzugten \\\\textit{F-Droid}-Client.\n\\n\n\\n \\\\item \\\\textbf{Store.} Öffnet die Anwendung in \\\\textit{Aurora Store}. Die Option ist nur sichtbar, wenn \\\\textit{Aurora\n\\n Store} installiert ist.\n\\n\\\\end{itemize}</string>\n    <string name=\"pages$app-details-page$additional-features-for-rooted-phones\">Im Gegensatz zu Nicht-Root-Benutzern, die in diesen Registerkarten meist nur Zuschauer sind, können Root-Benutzer verschiedene Operationen durchführen.</string>\n    <string name=\"pages$app-details-page$app-info-options-menu\">Das Menü \\\"Optionen\\\" befindet sich in der oberen rechten Ecke der Seite. Eine vollständige Beschreibung der dort vorhandenen Optionen finden Sie\n\\nunten angegeben:\n\\n\\\\begin{itemize}\n\\n \\\\item \\\\textbf{Teilen.} Die Schaltfläche Teilen kann verwendet werden, um die APK zu teilen oder (wenn die Anwendung mehrere Teile hat)\n\\n \\\\textit{APKS} Datei, die aus der Anwendung extrahiert wurde.\n\\n\n\\n \\\\item \\\\textbf{Auffrischen.} Aktualisiert die Registerkarte App-Info.\n\\n\n\\n \\\\item \\\\textbf{Ansicht in Einstellungen.} Öffnen Sie die Anwendung in den Android-Einstellungen.\n\\n\n\\n \\\\Eintrag \\\\textbf{Sichern/Wiederherstellen.} Öffnen Sie den Dialog zum Sichern/Wiederherstellen.\n\\n\n\\n \\\\item \\\\textbf{Blockierungsregeln exportieren.} Exportieren von Regeln, die für die Anwendung im App Manager konfiguriert wurden.\n\\n\n\\n \\\\item \\\\textbf{Öffnen in Termux.} Öffnen Sie die Anwendung in Termux. Dabei wird \\\\texttt{su - user\\\\_id} ausgeführt, wobei\n\\n \\\\texttt{user\\\\_id} die Kernel-Benutzerkennung der Anwendung bezeichnet (beschrieben in \\\\Sref{subsubsec:app-info-general-information}).\n\\n Diese Option ist nur für den Root-Benutzer sichtbar. Siehe \\\\Sref{subsubsec:config-termux}, um zu erfahren, wie man Termux\n\\n für die Ausführung von Befehlen aus Anwendungen von Drittanbietern konfiguriert.\n\\n\n\\n \\\\item \\\\textbf{Ausführen in Termux.} Öffnen Sie die Anwendung über \\\\texttt{run-as package\\\\_name} in Termux. Dies ist nur\n\\n Dies gilt nur für die debuggbaren Anwendungen und funktioniert sowohl für Root- als auch für ADB-Benutzer. Siehe \\\\Sref{subsubsec:config-termux}\n\\n erfahren Sie, wie Sie Termux so konfigurieren, dass Befehle von Drittanbieteranwendungen ausgeführt werden.\n\\n\n\\n \\\\item \\\\textbf{MagiskHide.} Öffnet ein Dialogfeld mit der Liste der Prozesse innerhalb der Anwendung, die zum MagiskHide hinzugefügt\n\\n oder aus der MagiskHide-Liste entfernt werden können.\n\\n\n\\n \\\\item \\\\textbf{MagiskDenyList.} Öffnet ein Dialogfeld mit einer Liste von Prozessen innerhalb der Anwendung, die\n\\n aus der MagiskDenyList hinzugefügt oder entfernt werden können.\n\\n\n\\n \\\\item \\\\textbf{Batterieoptimierung.} Aktivieren/Deaktivieren der Batterieoptimierung.\n\\n\n\\n \\\\item \\\\hyperref[sec:net-policy]{\\\\textbf{Netzpolitik.}} Konfigurieren Sie die Netzpolitik (z. B. die Datennutzung im Hintergrund) für die\n\\n Anwendung.\n\\n\n\\n \\\\item \\\\textbf{Symbol extrahieren.} Extrahieren und Speichern des Symbols der Anwendung im gemeinsamen Speicher.\n\\n\n\\n \\\\item \\\\textbf{Hinzufügenzum Profile.} Fügen Sie die Anwendung zu einem der konfigurierten \\\\hyperref[sec:profile-page]{Profile} hinzu.\n\\n\\\\end{itemize}</string>\n    <string name=\"pages$app-details-page$config-termux\">Standardmäßig lässt Termux die Ausführung von Befehlen aus Drittanbieteranwendungen nicht zu. Um diese Option zu verwenden, muss Termux v0.96\n\\noder höher erforderlich und \\\\texttt{allow-external-apps=true} muss in \\\\texttt{\\\\textasciitilde/.termux/termux.properties} hinzugefügt werden.\n\\n\n\\n\\\\begin{tip}{Info}\n\\n Das Aktivieren dieser Option schwächt die Sicherheit von Termux nicht. Die Anwendungen von Drittanbietern müssen den Benutzer immer noch fragen, ob\n\\n die Ausführung beliebiger Befehle in Termux zu erlauben.\n\\n\\\\end{tip}</string>\n    <string name=\"pages$app-details-page$component-tabs\">\\\\textbf{Aktivitäten}, \\\\textbf{Dienste}, \\\\textbf{Empfänger} (d. h. Rundfunkempfänger) und \\\\textbf{Provider}\n\\n(d. h. Inhaltsanbieter) werden gemeinsam als Anwendungskomponenten bezeichnet. Der Grund dafür ist, dass sie sich\n\\nin vielerlei Hinsicht ähnliche Merkmale aufweisen. Zum Beispiel haben sie alle einen \\\\textit{Name}, ein \\\\textit{Label}, ein \\\\textit{Icon} und werden\n\\nüber \\\\textit{Absicht} ausgeführt. Anwendungskomponenten sind die Bausteine einer Anwendung und müssen im\n\\ndem Anwendungsmanifest deklariert werden. Das Anwendungsmanifest ist eine Datei, in der anwendungsspezifische Metadaten gespeichert werden. Das Android\n\\nBetriebssystem lernt durch das Lesen der Metadaten, was es mit der Anwendung tun soll.\n\\n\n\\nDie in diesen Registerkarten verwendeten Farben werden in \\\\Sref{subsec:app-details-colour-codes} erklärt. Es ist auch möglich, die Liste der Komponenten so zu sortieren,\n\\ndass blockierte oder Tracker-Komponenten ganz oben in der Liste angezeigt werden, und zwar über die Option \\\\textbf{Sortieren} im Menü\n\\nÜberlauf-Menü.</string>\n    <string name=\"pages$app-details-page$activities\">\\\\textbf{Aktivitäten} sind die Fenster oder Seiten, die vom Android-Betriebssystem eindeutig identifiziert werden können (z. B.,\n\\n\\\\textit{Hauptseite} und \\\\textit{App-Detailseite} sind zwei Aktivitäten). Jede Aktivität kann mehrere UI-Komponenten haben\n\\nbekannt als \\\\textit{Widgets} oder \\\\textit{Fragmente}, und jede Komponente kann verschachtelt oder übereinander gelegt werden. Der\n\\nEntwickler kann sich auch dafür entscheiden, externe Dateien, Links usw. innerhalb einer Aktivität zu öffnen, indem er eine Methode namens\n\\n\\\\textit{Inhaltsfilter}. Wenn Sie zum Beispiel eine Datei mit Ihrem Dateimanager öffnen, durchsucht entweder Ihr Dateimanager oder\n\\nBetriebssystem die Inhaltsfilter über PackageManager, um die Aktivitäten zu finden, die die Datei öffnen können, und\n\\nbietet Ihnen an, die Datei mit diesen Aktivitäten zu öffnen.\n\\n\n\\nAktivitäten, die exportierbar sind, können in der Regel von beliebigen Drittanbieteranwendungen geöffnet werden. Einige Aktivitäten erfordern\n\\nBerechtigungen, und wenn das der Fall ist, kann nur eine Anwendung mit diesen Berechtigungen sie öffnen. In der\n\\n\\\\textit{Aktivitäten} können Aktivitäten über die Schaltfläche \\\\textbf{Launch} gestartet werden. Wenn es erforderlich ist, zusätzliche\n\\nzusätzliche Informationen, wie z. B. Intent-Extras, Daten oder Aktionen, einzugeben, öffnet ein langer Klick auf die Schaltfläche \\\\textbf{Starten} das Fenster\n\\n\\\\hyperref[sec:interceptor-page]{Activity Interceptor} Seite, die solche Funktionen bietet.\n\\n\n\\n\\\\begin{tip}{Hinweis}\n\\n Wenn Sie eine Aktivität nicht öffnen können, ist es wahrscheinlich, dass bestimmte Abhängigkeiten nicht erfüllt sind, z.B. \\\\ Sie\n\\n Sie können z. B. die Seite \\\\textit{App-Details} nicht öffnen, weil Sie dafür zumindest einen Paketnamen angeben müssen. Da diese\n\\n Abhängigkeiten nicht programmatisch hergeleitet werden können, können diese Aktivitäten standardmäßig nicht über den App Manager geöffnet werden.\n\\n\\\\end{tip}\n\\n\n\\nEs ist auch möglich, über die Schaltfläche \\\\textbf{Verknüpfung erstellen} Verknüpfungen zu den Aktivitäten zu erstellen.\n\\n\n\\n\\\\begin{danger}{Vorsicht}\n\\n Wenn Sie App Manager deinstallieren, gehen alle von App Manager erstellten Verknüpfungen verloren.\n\\n\\\\end{danger}</string>\n    <string name=\"pages$app-details-page$servcies\">Im Gegensatz zu \\\\hyperref[subsubsec:activities]{Aktivitäten}, die Benutzer sehen können, erledigen \\\\textbf{Dienste} Hintergrundaufgaben. Zum Beispiel,\n\\nwenn Sie mit dem Internetbrowser Ihres Telefons ein Video aus dem Internet herunterladen, verwendet der Internetbrowser einen\n\\n\\\\textit{Hintergrunddienst}, um den Inhalt herunterzuladen.\n\\n\n\\nWenn eine Aktivität geschlossen oder aus dem Abschnitt \\\\textit{Ereignisse} entfernt wird, kann sie sofort zerstört werden, abhängig von\n\\nvielen Faktoren, z. B. davon, wie viel freier Speicherplatz auf dem Telefon vorhanden ist. Dienste können jedoch auf Wunsch unbegrenzt ausgeführt werden. Wenn mehr\n\\nDienste im Hintergrund ausgeführt werden, kann das Telefon aufgrund des Mangels an Speicher und/oder Verarbeitungsleistung langsamer werden, und\n\\nder Akku des Telefons wird schneller entladen. Bei neueren Android-Versionen ist die Funktion zur Akkuoptimierung\n\\nstandardmäßig für alle Anwendungen aktiviert. Wenn diese Funktion aktiviert ist, kann das System jeden Dienst willkürlich beenden. Allerdings,\n\\nVordergrunddienste (d. h. Dienste, die mit einer festen Benachrichtigung laufen, wie z. B. der Musikplayer) werden in der Regel nicht\n\\nbeendet, es sei denn, die Ressourcen des Systems sind knapp (Speicher, Batterie usw.). Herstellerspezifische Standard-ROMs können eine\n\\naggressivere Optimierung bieten. MIUI verfügt beispielsweise über eine sehr aggressive Optimierungsfunktion, die als \\\\textit{MIUI Optimierung} bekannt ist.\n\\n\n\\nBeide Aktivitäten und Dienste werden im selben \\\\href{https://stackoverflow.com/questions/7597742}{looper} ausgeführt, dem\n\\nHauptlooper, was bedeutet, dass die Dienste nicht wirklich im Hintergrund ausgeführt werden. Es ist die Aufgabe des Entwicklers, dies\n\\nsicherzustellen. Wie kommuniziert die Anwendung mit dem Dienst\\? Sie verwendet\n\\n\\\\hyperref[subsubsec:app-details-receivers]{Broadcast Empfänger} oder Binder.</string>\n    <string name=\"pages$app-details-page$receivers\">\\\\textbf{Empfänger} (auch \\\\textit{Broadcast Empfänger} genannt) können für die Ausführung bestimmter Aufgaben für\n\\nbestimmten Ereignissen verwendet werden. Diese Komponenten werden als Broadcast-Empfänger bezeichnet, da sie ausgeführt werden, sobald eine Broadcast-Nachricht\n\\nempfangen wird. Diese Broadcast-Nachrichten werden mit einer Methode namens Intent gesendet. Intent ist eine spezielle Funktion für Android\n\\ndie verwendet werden kann, um Anwendungen, Aktivitäten und Dienste zu öffnen und Broadcast-Nachrichten zu senden. Daher verwenden, wie bei den\n\\n\\\\hyperref[subsubsec:activities]{Aktivitäten}, Broadcast-Empfänger Intent-Filter, um nur die gewünschten\n\\nBroadcast-Nachricht(en) zu empfangen. Broadcast-Nachrichten können entweder vom System oder von der App selbst gesendet werden. Wenn eine Broadcast-Nachricht\n\\ngesendet wird, werden die entsprechenden Empfänger vom System geweckt, damit sie Aufgaben ausführen können. Zum Beispiel, wenn Sie\n\\nwenig Speicherplatz haben, kann es sein, dass Ihr Telefon nach dem Aktivieren der mobilen Daten oder dem Herstellen einer Wifi-Verbindung für einen Moment einfriert oder verzögert wird.\n\\nHaben Sie sich schon einmal gefragt, warum\\? Das liegt daran, dass Broadcast-Empfänger, die `android.net.conn.CONNECTIVITY\\\\_CHANGE` empfangen können\n\\nvom System geweckt werden, sobald Sie die Datenverbindung aktivieren. Da viele Apps diesen Absichtsfilter verwenden, werden alle diese Apps\n\\nfast sofort vom System geweckt, was das Einfrieren oder die Verzögerungen verursacht. \n\\n\n\\nAbgesehen davon können Empfänger für die Interprozesskommunikation (IPC) verwendet werden, d. h. sie helfen Ihnen bei der Kommunikation zwischen verschiedenen Anwendungen (vorausgesetzt, Sie haben die\n\\nerforderlichen Berechtigungen) oder sogar zwischen verschiedenen Komponenten einer einzigen Anwendung.</string>\n    <string name=\"pages$app-details-page$providers\">\\\\textbf{Provider} (auch \\\\textit{Content Provider} genannt) werden für die Datenverwaltung verwendet. Wenn Sie zum Beispiel eine\n\\nAPK-Datei speichern oder Regeln in App Manager exportieren, wird ein Inhaltsanbieter namens \\\\texttt{.fm.FmProvider} verwendet, um die APK zu speichern oder\n\\ndie Regeln zu exportieren. Es gibt viele Inhaltsanbieter, darunter auch die vom System bereitgestellten, um verschiedene\n\\ninhaltsbezogenen Aufgaben wie Datenbankverwaltung, Nachverfolgung, Suche usw. Jeder Inhaltsanbieter hat ein Feld namens\n\\n\\\\textit{Authority}, das für die Anwendung im gesamten Android-Ökosystem ebenso eindeutig ist wie der Paketname.</string>\n    <string name=\"pages$app-details-page$blocking-components\">Auf der rechten Seite jeder Komponente befindet sich ein Symbol für ``Blockieren\\'\\' (das zu einem Symbol für ``Entblocken/Wiederherstellen\\'\\' wird, wenn\n\\ndie Komponente blockiert ist). Diese Ikone (eigentlich eine Schaltfläche) kann benutzt werden, um den Blockierungsstatus dieser\n\\nbestimmten Komponente zu ändern. Wenn \\\\hyperref[subsubsec:instant-component-blocking]{Instant Component Blocking} nicht aktiviert ist oder\n\\ndie Blockierung noch nie auf die Anwendung angewendet wurde, müssen die Änderungen über die Option \\\\textbf{Regeln anwenden}\n\\nim Drei-Punkte-Menü. Es ist auch möglich, die bereits angewendeten Regeln mit der gleichen Option zu entfernen (dieses\n\\nMal als \\\\textbf{Regeln entfernen}).\n\\n\n\\nEs ist auch möglich, die Komponente mit einer der verschiedenen Methoden zu blockieren, indem Sie lange auf das Symbol klicken.\n\\n\n\\n\\\\seealsoinline{\\\\hyperref[sec:faq:app-components]{FAQ: App-Komponenten}}</string>\n    <string name=\"pages$app-details-page$blocking-trackers\">Es ist möglich, Tracker-Komponenten mit der Option \\\\textbf{Tracker blockieren} im Drei-Punkte-Menü zu deaktivieren. Alle Tracker\n\\nKomponenten werden unabhängig von der Registerkarte, in der Sie sich gerade befinden, blockiert.\n\\n\n\\n\\\\begin{tip}{Info}\n\\n Tracker-Komponenten sind eine Untermenge der Anwendungskomponenten. Daher werden sie mit der gleichen Methode blockiert, die auch für\n\\n das Blockieren anderer Komponenten verwendet.\n\\n\\\\end{tip}\n\\n\n\\n\\\\begin{amseealso}\n\\n \\\\item \\\\hyperref[subsec:tracker-classes-versus-tracker-components]{FAQ: Tracker-Klassen versus Tracker-Komponenten}\n\\n \\\\item \\\\hyperref[sec:scanner-page]{Scanner-Seite}\n\\n \\\\item \\\\hyperref[subsec:block-unblock-trackers]{1-Click Ops Page: Tracker blockieren/entblocken}\n\\n\\\\end{amseealso}</string>\n    <string name=\"pages$app-details-page$permission-tabs\">\\\\Die Registerkarten \\\\textbf{App Ops}, \\\\textbf{Verwendete Berechtigungen} und \\\\textbf{Berechtigungen} beziehen sich auf Berechtigungen. In Android\n\\nerfordert die Kommunikation zwischen Apps oder Prozessen, die nicht dieselbe Identität haben (bekannt als \\\\textit{Shared ID}), oft\n\\nBerechtigung(en). Diese Berechtigungen werden von der Berechtigungssteuerung verwaltet. Einige Berechtigungen werden als\n\\n\\\\textit{normale} Berechtigungen, die automatisch gewährt werden, wenn sie im Anwendungsmanifest erscheinen, aber\n\\n\\\\textit{gefährlich} und \\\\textit{Entwicklung} Berechtigungen erfordern eine Bestätigung durch den Benutzer. Die in diesen Registerkarten verwendeten Farben\n\\nwerden in \\\\Sref{subsec:app-details-colour-codes} erläutert.</string>\n    <string name=\"pages$app-details-page$$config-termux-title\">Termux konfigurieren</string>\n    <string name=\"pages$app-details-page$$blocking-components-title\">Komponenten blockieren.</string>\n    <string name=\"pages$main-page$batch-operations\">Auf dieser Seite sind auch Stapeloperationen oder Operationen mit mehreren Anwendungen möglich. Der Mehrfachauswahlmodus kann\n\\naktiviert werden, indem man auf ein beliebiges Anwendungssymbol klickt oder indem man auf ein beliebiges Element in der Liste lange klickt. Einmal aktiviert, wählt ein einfacher Klick auf\n\\nein Listenelement ausgewählt, anstatt die Seite mit den Anwendungsdetails zu öffnen. In diesem Modus befinden sich die Stapeloperationen im\n\\nMehrfachauswahlmenü unten auf der Seite. Zu den Operationen gehören:\n\\n\\\\begin{itemize}\n\\n \\\\item Hinzufügen der ausgewählten Anwendungen zu einem \\\\hyperref[sec:profiles-page]{Profil}\n\\n \\\\item \\\\hyperref[sec:backup-restore]{Sicherung, Wiederherstellung oder Löschung} der Anwendungen\n\\n \\\\item Blockieren der Tracker für die Anwendungen\n\\n \\\\item Löschen von Daten oder Cache aus den Anwendungen\n\\n \\\\item Aktivieren/Deaktivieren/Zwangsstoppen/Deinstallieren der Anwendungen\n\\n \\\\item Exportieren der im App Manager gespeicherten Blockierungsregeln\n\\n \\\\item Verhindern von Hintergrundoperationen der Anwendungen (Android 7 und höher)\n\\n \\\\item peichern der APK-Dateien in \\\\texttt{App Manager/apks}\n\\n \\\\item Einstellen von \\\\hyperref[sec:net-policy]{Netzrichtlinien}\n\\n\\\\end{itemize}\n\\n\n\\n\\\\begin{tip}{Barrierefreiheit}\n\\nNachdem der Mehrfachauswahlmodus aktiviert wurde, ist es möglich, mit der rechten oder linken Taste der Tastatur in das\n\\n Menü mit der rechten oder linken Taste der Tastatur oder der Fernbedienung zu navigieren.\n\\n\\\\end{tip}</string>\n    <string name=\"pages$main-page$colour-codes\">\\\\begin{itemize}\n\\n \\\\item \\\\colorbox{AMLightGreyishOrange}{\\\\textcolor{black}{helles gräuliches Orange (Tag)}} / \\\\colorbox{AMDarkBlue}{\n\\n \\\\textcolor{white}{Dunkelblau (Nacht)}} -- Die Anwendung ist für den Batchbetrieb ausgewählt\n\\n \\\\item \\\\colorbox{AMLightRed}{\\\\textcolor{black}{Hellrot (Tag)}} / \\\\colorbox{AMVeryDarkRed}{\\\\textcolor{white}\n\\n {Dunkelrot (Nacht)}} -- Deaktivierte Anwendung\n\\n \\\\item \\\\colorbox{AMYellow}{\\\\textcolor{black}{Yellow Star}} -- Debuggingfähige Anwendung\n\\n \\\\item \\\\textcolor{AMOrange}{Orange \\\\textit{Datum}} -- Die Anwendung hat Zugriff auf die Systemprotokolle\n\\n \\\\item \\\\textcolor{AMOrange}{Orange \\\\textit{UID}} -- Die Benutzer-ID wird von mehreren Anwendungen gemeinsam genutzt\n\\n \\\\item \\\\textcolor{AMOrange}{Orange \\\\textit{SDK}} -- Die Anwendung verwendet möglicherweise Klartextverkehr (z. B. HTTP)\n\\n \\\\item \\\\textcolor{red}{Rot \\\\textit{Paketname}} -- Die Anwendung erlaubt keine Löschung ihrer Daten\n\\n \\\\item \\\\textcolor{red}{Red \\\\textit{backup}} -- Die deinstallierte Anwendung mit einem oder mehreren Backups, die im App\n\\n Manager\n\\n \\\\item \\\\textcolor{AMOrange}{Orange \\\\textit{backup}} -- Veraltetes Backup, d.h. das Basis-Backup enthält eine ältere\n\\n Version der installierten Anwendung\n\\n \\\\item \\\\textcolor{AMDarkCyan}{Dunkles Cyan \\\\textit{backup}} -- aktuelles Backup, d.h. \\\\das Basis-Backup enthält die\n\\n gleiche oder höhere Version der installierten Anwendung\n\\n \\\\item \\\\textcolor{AMDarkCyan}{Dark cyan \\\\textit{package name}} -- Erzwungener Anwendungsstopp\n\\n \\\\item \\\\textcolor{AMDarkCyan}{Dark cyan \\\\textit{version}} -- Inaktive Anwendung\n\\n \\\\item \\\\textcolor{magenta}{Magenta} -- Persistente Anwendung, d.h. sie bleibt die ganze Zeit über aktiv.\n\\n\\\\end{itemize}</string>\n    <string name=\"pages$main-page$application-types\">Eine Anwendung kann entweder eine \\\\textbf{Benutzer}- oder eine \\\\textbf{System}-Anwendung mit den folgenden Suffixen sein:\n\\n\\\\begin{itemize}\n\\n \\\\item \\\\texttt{X} -- Unterstützt mehrere Architekturen\n\\n \\\\item \\\\texttt{0} -- Keine Dex-Dateien in der Anwendung vorhanden\n\\n \\\\item \\\\texttt{\\\\°} -- Unterbrochene Anwendung\n\\n \\\\item \\\\texttt{\\\\#} -- Die Anwendung hat das System aufgefordert, einen großen Heap, d. h. großen Laufzeitspeicher, zuzuweisen\n\\n \\\\item \\\\texttt{\\?} -- Die Anwendung forderte die virtuelle Maschine auf, in den sicheren Modus zu wechseln.\n\\n\\\\end{itemize}</string>\n    <string name=\"pages$main-page$version-info\">Auf den Versionsnamen folgen die nachstehenden Präfixe:\n\\n\\\\begin{itemize}\n\\n \\\\item \\\\texttt{\\\\_} -- Keine Hardware-Beschleunigung (was die In-App-Animationen oder Transparenzen beeinträchtigt)\n\\n \\\\item \\\\texttt{\\\\textasciitilde} -- Reine Testanwendung\n\\n \\\\item \\\\texttt{debug} -- Debuggingfähige Anwendung\n\\n\\\\end{itemize}</string>\n    <string name=\"pages$main-page$options-menu\">Das Menü Optionen bietet verschiedene Optionen zum Sortieren und Filtern der aufgelisteten Anwendungen sowie zum Navigieren\n\\nzu verschiedenen Seiten innerhalb oder außerhalb des App Managers.</string>\n    <string name=\"pages$main-page$instructions\">Durch Klicken auf den \\\\textbf{Anleitung} wird die Offline-Version des App Manager Benutzerhandbuchs geöffnet. Es kann auch die\n\\nOnline-Version öffnen, wenn die entsprechende Funktionsaufteilung, d. h. \\\\texttt{feat\\\\_docs}, nicht installiert ist oder wenn kein WebView\n\\nim System vorhanden ist, um das Handbuch zu laden.</string>\n    <string name=\"pages$main-page$list-options\">\\\\textbf{Listenoptionen} enthalten die Optionen zum Sortieren und Filtern der Liste auf der Hauptseite.</string>\n    <string name=\"pages$main-page$profile_name\">Es ist auch möglich, die Anwendungen aufzulisten, die nur in einem \\\\hyperref[sec:profiles-page]{Profil} vorhanden sind. Dies kann\n\\nnützlich sein, um bestimmte Vorgänge in einem Profil auszuführen (z. B. die Deinstallation aller Anwendungen in einem Profil), die\n\\nnicht über die Seite \\\\hyperref[sec:profiles-page]{Profile} durchgeführt werden können.</string>\n    <string name=\"pages$main-page$1-click-ops\">\\\\textbf{1-Click Ops} steht für die Ein-Klick-Operationen. Es öffnet die \\\\hyperref[sec:1-click-ops-page]{entsprechende\n\\nSeite} in einer neuen Aktivität.</string>\n    <string name=\"pages$main-page$sort\">Die auf der Hauptseite aufgeführten Anwendungen können auf folgende Weise sortiert werden:\n\\n\\\\begin{itemize}\n\\n \\\\item \\\\textbf{Benutzeranwendungen zuerst.} Die Benutzeranwendungen werden oben aufgelistet\n\\n \\\\item \\\\textbf{App Label.} Sortieren Sie die Liste in aufsteigender Reihenfolge nach ihren Anwendungsbezeichnungen (auch bekannt als\n\\n \\\\textit{Anwendungsnamen}). Dies ist die Standardsortierpräferenz\n\\n \\\\item \\\\textbf{Paketname.} Sortiert die Liste in aufsteigender Reihenfolge nach den Paketnamen\n\\n \\\\item \\\\textbf{Letzte Aktualisierung.} Sortieren der Liste in absteigender Reihenfolge nach dem Datum der letzten Aktualisierung\n\\n \\\\item \\\\textbf{Gemeinsame Benutzer-ID.} Sortiert die Liste in absteigender Reihenfolge nach der Kernel-Benutzer-ID\n\\n \\\\item \\\\textbf{Ziel-SDK.} Sortieren der Liste in aufsteigender Reihenfolge nach dem Ziel-SDK\n\\n \\\\item \\\\textbf{Signatur.} Sortieren der Liste in aufsteigender Reihenfolge auf der Grundlage der Signierinformationen\n\\n \\\\item \\\\textbf{Disabled first.} Die deaktivierten Anwendungen werden zuoberst aufgeführt\n\\n \\\\item \\\\textbf{Blocked first.} Sortieren Sie die Liste in absteigender Reihenfolge nach der Anzahl der blockierten Komponenten jeder\n\\n Anwendung hat\n\\n \\\\item \\\\textbf{Backed up first.} Die Anwendungen mit Sicherungskopien ganz oben anzeigen\n\\n \\\\item \\\\textbf{Tracker.} Sortieren Sie die Liste in absteigender Reihenfolge nach der Anzahl der Tracker-Komponenten jeder\n\\n Anwendung hat\n\\n \\\\item \\\\textbf{Last actions.} Sortieren Sie die Liste in absteigender Reihenfolge nach der letzten Zeit und dem Datum der Aktionen, die\n\\n an den Anwendungen im App Manager vorgenommen wurden.\n\\n\\\\end{itemize}\n\\n\n\\nDarüber hinaus gibt es die Option \\\\textit{umgekehrt}, die verwendet werden kann, um die Liste in umgekehrter Reihenfolge zu sortieren. Unabhängig von\n\\nder Sortiereinstellungen werden die Anwendungen zunächst alphabetisch sortiert, um zufällige Sortierergebnisse\n\\nzu vermeiden.</string>\n    <string name=\"pages$main-page$filter\">Die auf der Hauptseite aufgeführten Anwendungen können auf folgende Weise gefiltert werden:\n\\n\\\\begin{itemize}\n\\n \\\\item \\\\textbf{Benutzeranwendungen.} Nur die Benutzeranwendungen auflisten\n\\n \\\\item \\\\textbf{Systemanwendungen.} Nur die Systemanwendungen auflisten\n\\n \\\\item \\\\textbf{Deaktivierte Anwendungen.} Nur die deaktivierten Anwendungen auflisten\n\\n \\\\item \\\\textbf{Anwendungen mit Regeln.} Auflisten der Anwendungen mit einer oder mehreren Sperrregeln\n\\n \\\\item \\\\textbf{Anwendungen mit Aktivitäten.} Auflistung der Anwendungen mit einer oder mehreren Aktivitäten\n\\n \\\\item \\\\textbf{Anwendungen mit Backups.} Liste der Anwendungen mit einem oder mehreren Backups\n\\n \\\\item \\\\textbf{Laufende Anwendungen.} Auflisten der Anwendungen, die derzeit ausgeführt werden\n\\n \\\\item \\\\textbf{Anwendungen mit Splits.} Auflisten der Anwendungen mit einer oder mehreren geteilten APK-Dateien\n\\n \\\\item \\\\textbf{Installierte Anwendungen.} Nur die installierten Anwendungen auflisten\n\\n \\\\item \\\\textbf{Deinstallierte Anwendungen.} Nur die deinstallierten Anwendungen auflisten\n\\n \\\\item \\\\textbf{Anwendungen ohne Backups.} Listet die Anwendungen auf, von denen keine Backups vorhanden sind.\n\\n\\\\end{itemize}\n\\n\n\\nAnders als bei der Sortierung ist es möglich, mehr als eine Filteroption gleichzeitig anzuwenden. Zum Beispiel können die deaktivierten Benutzer-\n\\nanwendungen aufgelistet werden, indem sowohl \\\\textit{Benutzeranwendungen} als auch \\\\textit{Inaktivierte Anwendungen} ausgewählt werden. Dies kann besonders nützlich sein\n\\n für \\\\hyperref[subsec:batch-operations]{Batch-Operationen}, bei denen das Filtern der Benutzeranwendungen notwendig sein kann,\n\\n um bestimmte Operationen sicher auszuführen.</string>\n    <string name=\"pages$main-page$app-usage\">App-Nutzungsstatistiken wie z. B. Bildschirmzeit, Datennutzung (sowohl mobil als auch Wi-Fi), \\\\textit{die Haufigkeit, die\n\\n eine App geöffnet wurde}, können durch Klicken auf die Option \\\\textbf{App-Nutzung} im Menü aufgerufen werden. Es erfordert jedoch\n\\ndie Berechtigung \\\\textit{Nutzungszugriff}. Dieser Menüpunkt wird nicht aufgeführt, wenn die Nutzungszugriffsfunktion in\n\\n\\\\hyperref[subsec:enable/disable-features]{Einstellungen} ausgeschaltet ist.</string>\n    <string name=\"pages$app-details-page$uses-permissions\">\\\\textbf{Verwendete Berechtigungen} sind die von der Anwendung verwendeten Berechtigungen. Diese werden so genannt, weil sie im Manifest\n\\nunter Verwendung von \\\\texttt{Verwendete Berechtigung}-Tags angegeben werden. Informationen wie \\\\textit{Flags}, \\\\textit{Berechtigungsname},\n\\n\\\\textit{Berechtigungsbeschreibung}, \\\\textit{Paketname}, \\\\textit{Gruppe} werden aus dem zugehörigen\n\\n\\\\hyperref[subsubsec:permissions]{Berechtigung}.\n\\n\n\\nPrivilegierte Benutzer können die Berechtigungen \\\\textit{Gefährlich} und \\\\textit{Entwicklung} über die Umschalttaste\n\\nauf der rechten Seite jedes Berechtigungselements. Es ist auch möglich, gefährliche Berechtigungen auf einmal zu entziehen, indem man die\n\\nentsprechende Option im Menü. Nur diese beiden Arten von Berechtigungen können entzogen werden, da Android nicht erlaubt\n\\n\\\\textit{normal} Berechtigungen (was die meisten von ihnen sind) nicht ändern kann. Es könnte immer noch möglich sein, sie zu widerrufen,\n\\nindem man \\\\texttt{runtime-permissions.xml} selbst bearbeitet, aber ob dies eine Möglichkeit ist, wird noch untersucht.\n\\n\n\\n\\\\begin{tip}{Info}\n\\n Da gefährliche Berechtigungen standardmäßig vom System entzogen werden, ist der Entzug aller gefährlichen Berechtigungen gleichbedeutend mit\n\\n dem Zurücksetzen aller Berechtigungen.\n\\n\\\\end{tip}\n\\n\n\\nEs ist möglich, die Berechtigungen nach ihrem Namen (in aufsteigender Reihenfolge) zu sortieren oder zu wählen, ob zuerst die verweigerten oder gefährlichen\n\\nBerechtigungen zuerst anzuzeigen, indem Sie die entsprechenden Optionen im Menü verwenden.</string>\n    <string name=\"pages$app-details-page$signatures-tab_1\">\\\\textbf{Signaturen} werden eigentlich Signierinformationen genannt. Eine Anwendung wird mit einem oder mehreren Signierzertifikaten\n\\nsigniert, bevor sie veröffentlicht wird. Die Integrität einer Anwendung, d.h. ob die\n\\nAnwendung vom tatsächlichen Entwickler stammt und nicht von anderen Personen verändert wurde, kann anhand der Signierinformationen überprüft werden.\n\\nWenn eine Anwendung von einem Unbefugten geändert wird, kann sie nicht mehr mit den ursprünglichen Zertifikaten signiert werden,\n\\nda die Signierinformationen vom eigentlichen Entwickler geheim gehalten werden. Signierinformationen können durch\n\\nPrüfsummen überprüft werden. Die Prüfsummen werden aus den Zertifikaten selbst generiert. Wenn der Entwickler die\n\\nPrüfsummen für die Signierzertifikate liefert, können diese mit den Prüfsummen verglichen werden, die in der Registerkarte \\\\textbf{Signaturen}\n\\ngenerierten Prüfsummen abgeglichen werden, um die Anwendung zu verifizieren. Wenn Sie zum Beispiel App Manager von GitHub oder dem Telegram Channel heruntergeladen haben, können Sie\n\\nüberprüfen, ob die Anwendung tatsächlich von mir freigegeben wurde, indem Sie einfach die folgende \\\\textit{SHA256}-Prüfsumme mit\n\\nder auf dieser Registerkarte angezeigten:</string>\n    <string name=\"pages$one-click-ops-page$$section-title\">1-Klick-Ops Seite</string>\n    <string name=\"pages$one-click-ops-page$$block-unblock-trackers-title\">Blockieren/Entsperren von Trackern</string>\n    <string name=\"pages$one-click-ops-page$$block-components-dots-title\">Block Komponenten\\\\ Punkte</string>\n    <string name=\"pages$one-click-ops-page$$set-mode-for-app-ops-dots-title\">Modus für App Ops einstellen\\\\ Punkte</string>\n    <string name=\"pages$one-click-ops-page$$1-click-back-up-title\">Sichern</string>\n    <string name=\"pages$one-click-ops-page$set-mode-for-app-ops-dots\">Diese Option kann verwendet werden, um bestimmte \\\\hyperref[ch:app-ops]{Anwendungsoperationen} aller oder ausgewählter Anwendungen zu konfigurieren.\n\\nEs gibt zwei Felder. In das erste Feld können mehrere app-ops-Konstanten (entweder Namen oder Werte) durch Leerzeichen getrennt eingegeben werden.\n\\nEs ist nicht immer möglich, im Voraus alle App-Op-Konstanten zu kennen, da sie von Gerät zu Gerät und von Betriebssystem zu Betriebssystem variieren.\n\\nDie gewünschte App-Op-Konstante ist in der Registerkarte \\\\textit{App Ops} auf der Seite \\\\hyperref[sec:app-details-page]{App-Detailseite} zu finden.\n\\nDas zweite Feld kann verwendet werden, um eine der \\\\hyperref[subsec:mode-constants]{Modi} einzufügen oder auszuwählen, die für die angegebenen App Ops gesetzt werden.\n\\n\n\\n\\\\begin{danger}{Vorsicht}\n\\n Wenn Sie nicht gut über App Ops und die Folgen ihrer Blockierung informiert sind, sollten Sie diese Option nicht verwenden.\n\\n\\\\end{danger}</string>\n    <string name=\"pages$app-details-page$app-ops\">\\\\textbf{App Ops} steht für \\\\textbf{Application Operationen}. Seit Android 4.3 werden \\\\textit{App Ops} von Android verwendet, um\n\\nviele Systemberechtigungen zu kontrollieren. Jeder App Ops ist eine eindeutige Nummer zugeordnet, die zusammen mit dem\n\\nprivaten Namen der Operation auf der Registerkarte App Ops angezeigt wird. Einige App Ops haben auch einen öffentlichen Namen. Eine große Anzahl von App Ops sind\n\\nauch mit Textit{Zulassungen} verbunden. Auf dieser Registerkarte wird eine App-Operation als gefährlich eingestuft, wenn die zugehörige Berechtigung\n\\nals gefährlich markiert ist. Andere Informationen wie \\\\textit{Flags}, \\\\textit{Berechtigungsname}, \\\\textit{Berechtigungsbeschreibung},\n\\n\\\\textit{Paketname}, \\\\textit{Gruppe} werden ebenfalls aus der zugehörigen \\\\hyperref[subsubsec:permissions]{Erlaubnis} übernommen.\n\\nAndere können die folgenden enthalten:\n\\n\\\\begin{itemize}\n\\n \\\\item \\\\textbf{Mode.} Er beschreibt den aktuellen Berechtigungsstatus, der \\\\textit{Erlauben}, \\\\textit{Verbieten} (eine\n\\n eher falsche Bezeichnung, es bedeutet einfach Fehler), \\\\textit{Ignorieren} (bedeutet eigentlich verweigern), \\\\textit{standardmäßig} (abgeleitet aus\n\\n einer Liste von Voreinstellungen, die intern vom Hersteller oder dem AOSP festgelegt wurden), \\\\textit{Vordergrund} (in neueren Android-Versionen bedeutet es,\n\\n dass die App Ops nur verwendet werden kann, wenn die Anwendung im Vordergrund läuft), und einige benutzerdefinierte Modi, die von den\n\\n Anbietern festgelegt wurden (MIUI verwendet beispielsweise \\\\textit{Fragen}).\n\\n\n\\n \\\\item \\\\textbf{Geltungsdauer.} Die Zeitspanne, in der diese Anwendung verwendet wurde (es kann negative Zeitspannen geben, deren\n\\n Anwendungsfälle mir derzeit nicht bekannt sind).\n\\n\n\\n \\\\item \\\\textbf{Accept Time.} Das letzte Mal, dass der Anwendungsvorgang akzeptiert wurde.\n\\n\n\\n \\\\item \\\\textbf{Reject Time.} Letztes Mal, als die App-Operation abgelehnt wurde.\n\\n\\\\end{itemize}\n\\n\n\\n\\\\begin{tip}{Info}\n\\n Der Inhalt dieser Registerkarte ist für No-Root-Benutzer sichtbar, wenn \\\\texttt{android.permission.GET\\\\_APP\\\\_OPS\\\\_STATS} über ADB\\\\@ gewährt wird.\n\\n\\\\end{tip}\n\\n\n\\nNeben jedem App-OP-Element befindet sich eine Umschalttaste, mit der es zugelassen oder verweigert (ignoriert) werden kann. Andere unterstützte Modi\n\\nkönnen auch durch einen langen Klick auf die Umschalttaste eingestellt werden. Wenn die gewünschte Anwendung nicht in der Registerkarte aufgeführt ist,\n\\nkann stattdessen die Option \\\\textit{Set custom app op} im Menü verwendet werden. Es ist auch möglich, die Änderungen\n\\nmit der Option \\\\textit{Zurücksetzen auf Standard} zurückzusetzen oder alle gefährlichen App-Ops mit der entsprechenden Option im Menü zu verweigern.\n\\nAufgrund der Funktionsweise von App Ops kann es einige Zeit dauern, bis das System sie anwendet.\n\\n\n\\n\\\\begin{tip}{Tip}\n\\n Das Verweigern bestimmter App Ops kann zu Fehlverhalten der Anwendung führen. Wenn alle Versuche fehlschlagen, kann die Option \\\\textit{Auf Standardwerte zurücksetzen}\n\\n als letzter Ausweg verwendet werden.\n\\n\\\\end{tip}\n\\n\n\\nEs ist möglich, die Liste in aufsteigender Reihenfolge nach App-Op-Namen und den zugehörigen eindeutigen Nummern (oder Werten) zu sortieren, oder\n\\ndie verweigerten App-Ops zuerst aufzulisten und die entsprechenden Sortieroptionen zu verwenden.\n\\n\n\\n\\\\seealsoinline{\\\\hyperref[ch:app-ops]{Anhang: App Ops}}</string>\n    <string name=\"pages$app-details-page$permissions\">\\\\textbf{Berechtigungen} sind normalerweise benutzerdefinierte Berechtigungen, die von der Anwendung selbst festgelegt werden. Diese Art von Berechtigungen werden\n\\nals \\\\textit{interne} Berechtigungen gekennzeichnet. Sie enthält auch in anderen Anwendungen deklarierte Berechtigungen, die als\n\\n\\\\textit{Externe} Berechtigungen bezeichnet werden. Externe Berechtigungen werden in den Anwendungskomponenten als Abhängigkeiten angegeben, d. h.\n\\neine Anwendung darf die Komponente nur aufrufen, wenn sie die angegebene Berechtigung besitzt. Hier ist eine vollständige Beschreibung der einzelnen\n\\nElement, das dort angezeigt wird:\n\\n\\\\begin{itemize}\n\\n \\\\item \\\\textbf{Name.} Jede Berechtigung hat einen eindeutigen Namen wie \\\\texttt{android.permission.INTERNET}, aber mehrere\n\\n Anwendungen können die gleiche Berechtigung anfordern.\n\\n\n\\n \\\\item \\\\textbf{Icon.} Jede Berechtigung kann ein eigenes Symbol haben. Die anderen Berechtigungsregisterkarten haben kein Symbol, weil\n\\n sie im Anwendungsmanifest kein Symbol enthalten.\n\\n\n\\n \\\\item \\\\textbf{Beschreibung.} Dieses optionale Feld beschreibt die Berechtigung. Wenn der Berechtigung keine Beschreibung zugeordnet ist,\n\\n wird das Feld nicht angezeigt.\n\\n\n\\n \\\\item \\\\textbf{Flags.} (Verwendet das Flaggensymbol oder den Namen \\\\textbf{Schutzstufe}) Hier werden verschiedene Berechtigungen\n\\n Flaggen wie \\\\textit{Normal}, \\\\textit{Entwicklung}, \\\\textit{Gefährlich}, \\\\textit{instant}, \\\\textit{Gewährt},\n\\n \\\\textit{Widerrufen}, \\\\textit{Signatur}, \\\\textit{Privilegiert}, usw.\n\\n\n\\n \\\\item \\\\textbf{Paketname.} Bezeichnet den mit der Berechtigung verbundenen Paketnamen, d. h. das Paket, das die\n\\n Berechtigung definiert.\n\\n\n\\n \\\\Eintrag \\\\textbf{Gruppe.} Der Gruppenname, der mit der Berechtigung verbunden ist (falls vorhanden). Mehrere zusammengehörige Berechtigungen können oft\n\\n zusammen gruppiert werden.\n\\n\\\\end{itemize}</string>\n    <string name=\"pages$app-details-page$signatures-tab_2\">In dieser Registerkarte werden mehrere Hash-Algorithmen zur Erzeugung von Prüfsummen verwendet. Dazu gehören \\\\textit{MD5}, \\\\textit{SHA1},\n\\n\\\\textit{SHA256} und \\\\textit{SHA512}.\n\\n\n\\n\\\\begin{danger}{Vorsicht}\n\\n Signierinformationen sollten mit einem zuverlässigen Hashing-Algorithmus wie \\\\textit{SHA256} überprüft werden. Verlassen Sie sich NICHT auf\n\\n \\\\textit{MD5} oder \\\\textit{SHA1}-Prüfsummen, da diese dafür bekannt sind, dieselben Prüfsummen für mehrere Zertifikate zu erzeugen.\n\\n\\\\end{danger}</string>\n    <string name=\"pages$one-click-ops-page$block-unblock-trackers\">Mit dieser Option können Sie die Werbe-/Tracker-Komponenten der installierten Anwendungen blockieren oder freigeben.\n\\nWenn Sie diese Option auswählen, fragt der App Manager, ob er Tracker von allen Anwendungen oder nur von den Benutzeranwendungen auflisten soll.\n\\nNeulinge sollten es vermeiden, Tracker aus den Systemanwendungen zu blockieren, um unangenehme Folgen zu vermeiden.\n\\nDanach erscheint ein Dialogfeld mit mehreren Auswahlmöglichkeiten, in dem Sie eine oder mehrere Anwendungen von diesem Vorgang ausschließen können.\n\\nDie Änderungen werden sofort übernommen, wenn Sie die Schaltfläche \\\\textit{block} oder \\\\textit{unblock} drücken.\n\\n\n\\n\\\\begin{warning}{Hinweis}\n\\n Bestimmte Anwendungen funktionieren nach dem Blockieren ihrer Tracker möglicherweise nicht mehr wie erwartet.\n\\n Wenn dies der Fall ist, entfernen Sie die Blockierungsregeln auf einmal oder nacheinander in den Komponenten-Registerkarten der \\\\hyperref[sec:app-details-page]{App-Detailseite} für die entsprechende Anwendung.\n\\n\\\\end{warning}\n\\n\n\\n\\\\begin{amseealso}\n\\n \\\\item \\\\hyperref[subsec:faq:how-to-unblock-tracker-components]{Wie hebt man die Blockierung von Tracker-Komponenten auf, die mit 1-Click Ops oder Batch Ops blockiert wurden\\?}\n\\n \\\\item \\\\hyperref[par:appdetails:blocking-trackers]{App-Detailseite: Blocking Trackers}\n\\n\\\\end{amseealso}</string>\n    <string name=\"pages$one-click-ops-page$block-components-dots\">Diese Option kann verwendet werden, um bestimmte Anwendungskomponenten zu blockieren, die durch ihre Signaturen festgelegt sind.\n\\nDie Signatur einer Komponente ist der vollständige Name oder ein Teil des Namens der Komponente.\n\\nAus Sicherheitsgründen wird empfohlen, am Ende jeder Teilsignatur einen \\\\texttt{.} (Punkt) am Ende jeder Teilsignatur hinzuzufügen, da der zugrunde liegende\n\\nAlgorithmus die Komponenten in einer gierigen Weise sucht und abgleicht.\n\\nEs ist auch möglich, mehr als eine Signatur einzufügen; in diesem Fall müssen alle Signaturen durch Leerzeichen getrennt werden.\n\\nÄhnlich wie bei der obigen Option gibt es auch die Möglichkeit, die Systemanwendungen zu sperren.\n\\n\n\\n\\\\begin{danger}{Vorsicht}\n\\n Wenn Sie sich nicht über die Folgen des Blockierens von Anwendungskomponenten anhand ihrer Signaturen im Klaren sind, sollten Sie diese Option nicht\n\\n verwenden, da sie zu einem Bootloop oder Softbrick führen kann und Sie infolgedessen möglicherweise einen Werksreset durchführen müssen.\n\\n\\\\end{danger}</string>\n    <string name=\"pages$one-click-ops-page$back-up\">1-Klick-Optionen für Backups. Als Vorsichtsmaßnahme werden die betroffenen Sicherungen aufgelistet, bevor ein Vorgang durchgeführt wird.\n\\n\n\\n\\\\paragraph{Alle Anwendungen sichern}. Sichern Sie alle installierten Anwendungen.\n\\n\n\\n\\\\paragraph{Vorhandene Sicherungen rückgängig machen.} Sichern Sie alle installierten Anwendungen, für die bereits ein Backup vorhanden ist.\n\\n\n\\n\\\\paragraph{Anwendungen ohne Backups sichern.} Sichern Sie alle installierten Anwendungen ohne vorheriges Backup.\n\\n\n\\n\\\\paragraph{Backups überprüfen und wiederherstellen.} Überprüfen Sie die kürzlich erstellten Sicherungen der installierten Anwendungen und wiederholen Sie die Sicherung, falls erforderlich.\n\\n\n\\n\\\\paragraph{Sichern Sie Anwendungen mit Änderungen.} Wenn sich eine Anwendung seit der letzten Sicherung geändert hat, wiederholen Sie ihre Sicherung.\n\\nDabei wird eine Reihe von Indizes überprüft, darunter die Anwendungsversion, das Datum der letzten Aktualisierung, das Datum des letzten Starts, die Integrität und die Datei-Hashes.\n\\nDie Hashes der Verzeichnisse werden während des Sicherungsvorgangs erfasst und in einer Datenbank gespeichert.\n\\nBei der Ausführung dieses Vorgangs werden neue Hashes erstellt und mit den in der Datenbank gespeicherten verglichen.</string>\n    <string name=\"pages$one-click-ops-page$$1-click-restore-title\">Wiederherstellen</string>\n    <string name=\"pages$profiles-page$options-menu\">Auf dieser Seite gibt es zwei Optionsmenüs. Das Menü mit den drei Punkten in der oberen rechten Ecke bietet zwei Optionen:\n\\n\\\\textit{Voreinstellungen} und \\\\textit{Importieren}.\n\\n\\\\begin{itemize}\n\\n \\\\item{textbf}{Voreinstellungen} Diese Option listet eine Reihe von integrierten Profilen auf, die als Ausgangspunkt verwendet werden können.\n\\n Die Profile werden aus dem Projekt \\\\href{https://gitlab.com/W1nst0n/universal-android-debloater}{Universal\n\\n Android Debloater}.\\\\\\\\\n\\n \\\\seealsoinline{\\\\hyperref[subsec:faq:what-are-bloatware]{FAQ: Was ist Bloatware und wie entfernt man sie\\?}}\n\\n\n\\n \\\\item \\\\textbf{Importieren.} Mit dieser Option können Sie ein vorhandenes Profil importieren, das zuvor aus dem App Manager exportiert wurde.\n\\n\\\\end{itemize}\n\\n\n\\nWenn Sie lange auf ein Profilelement klicken, wird ein weiteres Optionsmenü angezeigt. Es bietet die folgenden Optionen:\n\\n\\\\begin{itemize}\n\\n \\\\item \\\\textbf{Jetzt anwenden}. Diese Option kann verwendet werden, um das Profil direkt anzuwenden. Wenn Sie darauf klicken, wird ein Dialog\n\\n angezeigt, in dem ein \\\\hyperref[subsubsec:profile-state]{Profilzustand} ausgewählt werden kann.\n\\n Wenn Sie eine der Optionen auswählen, wird das Profil sofort angewendet.\n\\n\n\\n \\\\Textbf{Löschen} Wenn Sie auf Löschen klicken, wird das Profil sofort und ohne Warnung entfernt.\n\\n\n\\n \\\\item \\\\textbf{Duplizieren.} Diese Option kann verwendet werden, um das Profil zu duplizieren. Wenn Sie darauf klicken, wird ein Dialog\n\\n angezeigt, in dem ein Name für das neue Profil festgelegt werden kann. Wenn Sie auf ``OK\\'\\' klicken, wird \\\\hyperref[sec:profile-page]{Profilseite}\n\\n geladen, wobei alle Konfigurationen, die dieses Profil hat, dupliziert werden. Das Profil wird jedoch nicht gespeichert,\n\\n bis es manuell gespeichert wird.\n\\n\n\\n \\\\item \\\\textbf{Export.} Exportiert das Profil auf einen externen Speicher. Auf diese Weise exportierte Profile können über\n\\n die Option \\\\textit{import} wie oben erwähnt importiert werden.\n\\n\n\\n \\\\it{Textbf}{Verknüpfung erstellen} Mit dieser Option können Sie eine Verknüpfung für das Profil erstellen. Wenn Sie darauf klicken,\n\\n werden zwei Optionen angezeigt: \\\\textit{Einfach} und \\\\textit{Erweitert}. Bei der Konfiguration mit der letzteren Option wird der Benutzer aufgefordert,\n\\n einen Profilstatus auszuwählen, wenn die Verknüpfung aufgerufen wird. Bei der ersten Option wird dagegen immer der\n\\n Standardstatus, der beim letzten Speichern des Profils konfiguriert wurde.\n\\n\\\\end{itemize}</string>\n    <string name=\"pages$profile-page$$section-title\">Seite Profil</string>\n    <string name=\"pages$profile-page$$options-menu-title\">Menü Optionen</string>\n    <string name=\"pages$profile-page$$apps-tab-title\">Registerkarte Anwendungen</string>\n    <string name=\"pages$profile-page$$configurations-tab-title\">Registerkarte Konfigurationen</string>\n    <string name=\"pages$profile-page$$comment-title\">Anmerkung</string>\n    <string name=\"pages$profile-page$$state-title\">Zustand</string>\n    <string name=\"pages$profile-page$$users-title\">Nutzer</string>\n    <string name=\"pages$profile-page$$components-title\">Komponenten</string>\n    <string name=\"pages$profile-page$$app-ops-title\">Anwendungsoperationen</string>\n    <string name=\"pages$profile-page$$permissions-title\">Berechtigungen</string>\n    <string name=\"pages$profile-page$$backup-restore-title\">Sichern/Wiederherstellen</string>\n    <string name=\"pages$profile-page$$export-blocking-rules-title\">Regeln für die Exportsperre</string>\n    <string name=\"pages$profile-page$$force-stop-title\">Zwangsstopp</string>\n    <string name=\"pages$profile-page$$clear-cache-title\">Zwischenspeicher löschen</string>\n    <string name=\"pages$profile-page$$clear-data-title\">Daten löschen</string>\n    <string name=\"pages$profile-page$$block-trackers-title\">Tracker blockieren</string>\n    <string name=\"pages$profile-page$$save-apk-title\">APK speichern</string>\n    <string name=\"pages$profile-page$configurations-tab\">Auf der Registerkarte Konfigurationen können Sie die ausgewählten Pakete konfigurieren.</string>\n    <string name=\"pages$profile-page$comment\">Dies ist der Text, der auf der Seite \\\\hyperref[sec:profiles-page]{Profile} angezeigt wird. Wenn er nicht gesetzt ist, werden stattdessen die aktuellen\n\\nKonfigurationen stattdessen angezeigt.</string>\n    <string name=\"pages$profiles-page$$options-menu-title\">Menü Optionen</string>\n    <string name=\"pages$one-click-ops-page$intro\">Diese Seite wird angezeigt, wenn Sie die Option \\\\hyperref[subsubsec:main:1-click-ops]{1-Click Ops} im \\\\hyperref[subsec:main-page-options-menu]{Hauptmenü} auswählen.</string>\n    <string name=\"pages$profiles-page$$section-title\">Seite Profile</string>\n    <string name=\"pages$one-click-ops-page$restore\">1-Klick-Optionen für die Wiederherstellung. Als Vorsichtsmaßnahme werden die betroffenen Sicherungen aufgelistet, bevor eine Operation durchgeführt wird.\n\\n\n\\n\\\\paragraph{Wiederherstellen aller Anwendungen} Wiederherstellen des \\\\textit{Basis-Backups} aller gesicherten Anwendungen.\n\\n\n\\n\\\\paragraph{Wiederherstellen von nicht installierten Anwendungen}. Wiederherstellen des \\\\textit{Basis-Backup} aller gesicherten Anwendungen, die derzeit nicht installiert sind.\n\\n\n\\n\\\\paragraph{Wiederherstellen der letzten Backups}. Wiederherstellen des \\\\textit{Basis-Backup} von bereits installierten Anwendungen, deren Versionscodes höher sind als die der installierten Versionen.</string>\n    <string name=\"pages$profiles-page$intro\">Die Seite Profile kann über das Menü \\\\hyperref[subsec:main-page-options-menu]{Optionsmenu} auf der Hauptseite aufgerufen werden.\n\\nSie zeigt in erster Linie eine Liste der konfigurierten Profile zusammen mit den typischen Optionen zur Durchführung von Operationen mit ihnen an.\n\\nNeue Profile können auch über die Schaltfläche \\\\textit{plus} in der rechten unteren Ecke hinzugefügt oder importiert werden,\n\\ndupliziert oder aus einer der Voreinstellungen erstellt werden. Wenn Sie auf ein Profilelement klicken, wird die zugehörige Seite \\\\hyperref[sec:profile-page]{Profilseite} geöffnet.</string>\n    <string name=\"pages$profile-page$state\">Gibt an, wie sich bestimmte konfigurierte Optionen standardmäßig verhalten werden. Wenn zum Beispiel die Option \\\\textit{deaktivieren} aktiviert ist,\n\\nwerden die Anwendungen deaktiviert, wenn der Zustand \\\\textit{Ein} ist, und aktiviert, wenn der Zustand \\\\textit{Aus} ist.\n\\nDerzeit werden nur die Werte \\\\textit{Ein} und \\\\textit{On} unterstützt.</string>\n    <string name=\"pages$profile-page$intro\">Die Seite Profil zeigt die Konfigurationen für ein Profil an. Sie bietet auch die Möglichkeit, sie zu bearbeiten.</string>\n    <string name=\"pages$profile-page$apps-tab\">Auf der Registerkarte Apps werden die in diesem Profil konfigurierten Pakete aufgelistet. Pakete können hinzugefügt oder entfernt werden, indem Sie die Schaltfläche \\\\textit{Plus}\n\\nunten nutzen. Pakete können auch entfernt werden, indem Sie lange auf sie klicken (in diesem Fall wird ein\n\\nPopup mit der einzigen Option \\\\textit{Löschen} angezeigt).</string>\n    <string name=\"pages$profile-page$options-menu\">Das Menü mit den drei Punkten in der oberen rechten Ecke öffnet das Optionen-Menü. Es enthält verschiedene Optionen wie.\n\\n\\\\begin{itemize}\n\\n\\\\item \\\\textbf{Anwenden}. Diese Option kann verwendet werden, um das Profil anzuwenden. Wenn Sie darauf klicken, wird ein Dialogfeld angezeigt, in dem\n\\n Sie einen \\\\hyperref[subsubsec:profile-state]{Profilzustand} auswählen können. Wenn Sie eine der Optionen auswählen, wird das Profil\n\\n sofort angewendet.\n\\n \\\\begin{tip}{Hinweis}\n\\n Wenn Sie ein Profil anwenden, werden einige Pakete, die den Kriterien nicht entsprechen, einfach ignoriert.\n\\n \\\\end{tip}\n\\n\n\\n \\\\item \\\\textbf{Speichern.} Speichern Sie die Änderungen am Profil.\n\\n \\\\begin{warning}{Hinweis}\n\\n Änderungen werden nie automatisch gespeichert. Sie müssen sie von hier aus manuell speichern.\n\\n \\\\end{warning}\n\\n\n\\n \\\\item \\\\textbf{Verwerfen.} Verwirft alle Änderungen, die seit dem letzten Speichervorgang vorgenommen wurden.\n\\n\n\\n\\\\item \\\\textbf{Löschen.} Wenn Sie auf Löschen klicken, wird das Profil sofort und ohne Warnung gelöscht.\n\\n\n\\n \\\\item \\\\textbf{Duplizieren.} Mit dieser Option können Sie das Profil duplizieren. Wenn Sie darauf klicken, wird ein Dialogfeld angezeigt\n\\n in dem man einen Namen für das neue Profil festlegen kann. Wenn Sie auf ``OK\\'\\' klicken, wird diese Seite neu geladen, indem\n\\n alle Konfigurationen, die dieses Profil hat, dupliziert. Das Profil wird jedoch nicht gespeichert, bis es manuell gespeichert wird.\n\\n\n\\n\\\\item \\\\textbf{Erstellen einer Verknüpfung} Mit dieser Option können Sie eine Verknüpfung für das Profil erstellen. Wenn Sie darauf klicken, gibt es\n\\n werden zwei Optionen angezeigt: \\\\textit{Einfach} und \\\\textit{Erweitert}. Bei der Konfiguration mit der letzteren Option wird der Benutzer aufgefordert\n\\n Benutzer aufgefordert, einen Profilstatus auszuwählen, wenn die Verknüpfung aufgerufen wird. Bei der ersten Option wird dagegen immer der\n\\n Standardstatus, der beim letzten Speichern des Profils konfiguriert wurde.\n\\n\\\\end{itemize}</string>\n    <string name=\"pages$profile-page$users\">Wählen Sie die Benutzer aus, auf die das Profil angewendet werden soll. Standardmäßig sind alle Benutzer ausgewählt.</string>\n    <string name=\"pages$settings-page$$app-theme-title\">App-Design</string>\n    <string name=\"pages$settings-page$$screen-lock-title\">Bildschirm sperren</string>\n    <string name=\"pages$settings-page$$mode-of-operation-title\">Betriebsmodus</string>\n    <string name=\"pages$settings-page$$enable-disable-features-title\">Aktivieren/Deaktivieren von Funktionen</string>\n    <string name=\"pages$settings-page$$apk-signing-title\">APK-Signierung</string>\n    <string name=\"pages$settings-page$$signature-schemes-title\">Signaturregelungen</string>\n    <string name=\"pages$settings-page$$signing-key-title\">Signierschlüssel</string>\n    <string name=\"faq$misc$$section-title\">Sonstiges</string>\n    <string name=\"faq$misc$$i-dont-use-root-adb-title\">Ich verwende kein root/ADB. Bin ich völlig vor irgendwelchen Schäden sicher\\?</string>\n    <string name=\"faq$misc$$how-tracker-updated-title\">Wie werden die Tracker und Bibliotheken aktualisiert\\?</string>\n    <string name=\"faq$misc$$bloatware-title\">Was ist Bloatware und wie kann man sie entfernen\\?</string>\n    <string name=\"appendices$specifications$$background-title\">Hintergrund</string>\n    <string name=\"faq$misc$bloatware\">Bei Bloatware handelt es sich um überflüssige Anwendungen, die vom Hersteller oder OEM geliefert werden und in der Regel Systemanwendungen sind. Diese Anwendungen werden oft verwendet,\n\\num Benutzer zu verfolgen und Benutzerdaten zu sammeln, die sie möglicherweise gewinnbringend verkaufen. System-Apps müssen keine Erlaubnis einholen,\n\\num auf Geräteinformationen, Kontakte und Nachrichtendaten sowie auf andere Nutzungsdaten wie Ihre\n\\nGewohnheiten und alles, was Sie auf Ihrem gemeinsamen Speicher speichern, zugreifen zu können.\n\\n\n\\nDie Bloatware umfassen auch Google-Apps (wie Google Play Services, Google Play Store, Gmail, Google, Messages,\n\\nDialer, Kontakte), Facebook-Apps (die Facebook-App besteht aus vier oder fünf Apps), Facebook Messenger, Instagram,\n\\nTwitter und viele andere Apps, die ebenfalls Nutzer verfolgen und/oder Nutzerdaten ohne Zustimmung sammeln können, da sie alle\n\\nSystem-Apps sind. Sie können einige Berechtigungen in den Android-Einstellungen deaktivieren, aber seien Sie sich bewusst, dass die Android-Einstellungen fast\n\\njede Berechtigung versteckt, die ein Sicherheitsexperte als potenziell gefährlich bezeichnen würde.\n\\n\n\\nWenn es sich bei der Bloatware um Benutzeranwendungen handelt, können Sie sie entweder über die Android-Einstellungen oder über AM deinstallieren. Die Deinstallation von System-\n\\nApps ist ohne Root-Berechtigung nicht möglich. Sie können System-Apps auch mit ADB deinstallieren, aber das funktioniert möglicherweise nicht bei allen\n\\nApps. AM kann System-Apps mit Root oder ADB deinstallieren (letzteres natürlich mit gewissen Einschränkungen), aber diese Methoden\n\\nkönnen die Systemanwendungen nicht vollständig entfernen, da sie sich in der Partition \\\\emph{system} befinden, die eine schreibgeschützte\n\\nPartition ist. Wenn Sie über Root verfügen, können Sie diese Partition wieder einhängen, um diese Anwendungen manuell zu entfernen, aber dies wird Over\n\\nthe Air (OTA)-Updates unterbrechen, da die Daten in der Systempartition geändert wurden. Es gibt zwei Arten von Updates, Delta-\n\\n(eine kleine Version, die nur die Änderungen zwischen zwei Versionen enthält) und vollständige Updates. Sie können weiterhin vollständige Updates anwenden,\n\\naber die Bloatware wird erneut installiert, und Sie müssen sie daher erneut löschen. Außerdem bieten nicht alle\n\\nHersteller vollständige Aktualisierungen an.\n\\n\n\\nEine andere Lösung besteht darin, diese Apps entweder über die Android-Einstellungen (No-Root) oder AM zu deaktivieren, aber bestimmte Dienste können weiterhin\n\\nim Hintergrund laufen, da sie von anderen Systemanwendungen unter Verwendung von Interprozesskommunikation (IPC) gestartet werden können. Eine mögliche\n\\nLösung ist es, alle Bloatware zu deaktivieren, bis der Dienst endgültig beendet ist (nach einem Neustart). Aufgrund der starken\n\\nÄnderungen an den Android-Frameworks durch die Hersteller kann das Entfernen oder Deaktivieren bestimmter Bloatware jedoch zum Absturz der System-UI\n\\noder sogar einen Bootloop verursachen, was zu einem (Soft-)Bricking Ihres Geräts führt. Sie können im Internet suchen oder andere Benutzer befragen\n\\num mehr darüber herauszufinden, wie Sie Ihr Gerät debloaten können.\n\\n\n\\nAb v2.5.19 verfügt AM über eine neue Funktion namens \\\\hyperref[sec:profile-page]{Profile}. Die\n\\n\\\\hyperref[sec:profiles-page]{Seite Profile} bietet die Möglichkeit, neue Profile aus einer der Voreinstellungen zu erstellen. Die Voreinstellungen\n\\nbestehen aus Debloating-Profilen, die als Ausgangspunkt für die Überwachung, Deaktivierung und Entfernung von Bloatware von\n\\neinem proprietären Android-Betriebssystem.\n\\n\n\\n\\\\begin{warning}{Hinweis}\n\\n In den meisten Fällen können Sie Ihr Gerät nicht vollständig debloaten. Daher empfiehlt es sich, ein benutzerdefiniertes ROM zu verwenden,\n\\n wie Graphene OS, Lineage OS oder deren Derivate, die frei von Bloatware sind.\n\\n\\\\end{warning}</string>\n    <string name=\"appendices$specifications$$chapter-title\">Spezifikationen</string>\n    <string name=\"appendices$specifications$$rules-specification-title\">Regeln Spezifikationen</string>\n    <string name=\"appendices$specifications$$external-title\">Extern</string>\n    <string name=\"pages$profile-page$components\">Dies verhält sich genauso wie die Option \\\\hyperref[subsec:block-components-dots]{Block-Komponenten-Punkte} auf der\n\\n1-Klick-Ops-Seite. Allerdings wird die Blockierung hier nur auf die ausgewählten Pakete angewendet.\n\\nWenn der Status von \\\\hyperref[subsubsec:profile-state]{Status} \\\\textit{ein} ist, werden die Komponenten blockiert,\n\\nund wenn der Status \\\\textit{aus} ist, werden die Komponenten entsperrt.\n\\nDie Option kann (unabhängig von den eingegebenen Werten) durch Klicken auf die Schaltfläche \\\\textit{deaktiviert} im Eingabedialog deaktiviert werden.\n\\n\n\\n\\\\seealsoinline{\\\\hyperref[subsec:faq:what-are-app-components]{Was sind die App-Komponenten\\?}}</string>\n    <string name=\"appendices$specifications$external\">Externes Format wird zum Importieren oder Exportieren von Regeln in App Manager verwendet.\n\\n\\\\begin{Verbatim}\n\\n &lt;Paketname&gt; &lt;Komponentenname&gt; &lt;Typ&gt; &lt;Modus&gt;|&lt;Komponentenstatus&gt;|&lt;ist_gewährt&gt;\n\\n\\\\end{Verbatim}\n\\nDas Format ist im Wesentlichen dasselbe wie oben, mit Ausnahme des ersten Elements, das der Name des Pakets ist.\n\\n\n\\n\\\\begin{danger}{Vorsicht}\n\\n Die exportierten Regeln haben ein anderes Format als die internen Regeln und sollten nicht direkt in die Datei\n\\n \\\\textbf{conf}-Ordner kopiert werden.\n\\n\\\\end{danger}</string>\n    <string name=\"appendices$specifications$internal\">Das folgende Format wird intern in App Manager verwendet und ist nicht mit dem externen Format kompatibel.\n\\n\\\\begin{Verbatim}\n\\n &lt;Name&gt; &lt;Typ&gt; &lt;Modus&gt;|&lt;Komponente_Status&gt;|&lt;ist_gewährt&gt;\n\\n\\\\end{Verbatim}\n\\nHier:\n\\n\\\\begin{itemize}\n\\n \\\\item \\\\texttt{&lt;Name&gt;} -- Name der Komponente/Zulassung/App-Op (im Falle einer App-Op kann es sich um einen String oder eine ganze Zahl handeln)\n\\n \\\\item \\\\texttt{&lt;Typ&gt;} -- Eines der Elemente \\\\texttt{ACTIVITY}, \\\\texttt{RECEIVER}, \\\\texttt{PROVIDER}, \\\\texttt{SERVICE},\n\\n \\\\texttt{App\\\\_OP}, \\\\texttt{PERMISSION}\n\\n \\\\item \\\\texttt{&lt;Modus&gt;} -- (Für app ops) Die zugehörige \\\\hyperref[subsec:mode-constants]{mode constant}\n\\n \\\\item \\\\texttt{&lt;Komponente\\\\_Status&gt;} -- (Für Komponenten) Komponentenstatus\n\\n \\\\begin{itemize}\n\\n \\\\item \\\\texttt{wahr} -- Die Komponente wurde angewendet (der Wert \\\\texttt{wahr} wird aus Kompatibilitätsgründen beibehalten)\n\\n \\\\item \\\\texttt{falsch} -- Die Komponente wurde noch nicht angewendet, wird aber in Zukunft angewendet (der Wert \\\\texttt{falsch}\n\\n wird aus Kompatibilitätsgründen beibehalten)\n\\n \\\\item \\\\texttt{freigeschaltet} -- Die Komponente soll freigegeben werden\n\\n \\\\end{itemize}\n\\n \\\\item \\\\texttt{&lt;ist\\\\_gewährt&gt;} -- (Für Berechtigungen) Ob die Berechtigung erteilt oder entzogen ist\n\\n\\\\end{itemize}</string>\n    <string name=\"appendices$specifications$background\">AM unterstützt derzeit das Sperren von Aktivitäten, Broadcast-Empfängern, Inhaltsanbietern, Diensten, App-Ops und Berechtigungen,\n\\nund in Zukunft werde ich möglicherweise weitere Blockierungsoptionen hinzufügen. Um die Portabilität zu erhöhen, ist es notwendig, alle diese Daten zu importieren/exportieren.\n\\ndieser Daten.\n\\n\n\\nDie Pflege einer Datenbank sollte die beste Wahl sein, wenn es um die Speicherung von Daten geht. Im Moment werden mehrere \\\\texttt{tsv}-Dateien\n\\nwobei jede Datei den Namen des Pakets und eine \\\\texttt{.tsv}-Erweiterung hat. Die Datei/Datenbank wird abgefragt/verarbeitet\n\\ndurch die Klasse \\\\texttt{RegelSpeicherManager}. Aufgrund dieser Abstraktion sollte es in Zukunft einfacher sein, auf Datenbank- oder\n\\nverschlüsselte Datenbanksysteme zu wechseln, ohne das Design des gesamten Projekts zu ändern. Derzeit werden alle Konfigurations\n\\nDateien unter \\\\texttt{/data/data/io.github.muntashirakon.AppManager/Files/conf} gespeichert.</string>\n    <string name=\"appendices$specifications$$internal-title\">Intern</string>\n    <string name=\"appendices$specifications$$rules-file-format-title\">Regeln Dateiformat</string>\n    <string name=\"faq$aot$feature-adb\">Die unterstützten Funktionen werden im ADB-Modus automatisch aktiviert. Zu den unterstützten Funktionen gehören Deaktivieren, erzwungenes Anhalten,\n\\nLöschen von Anwendungsdaten, Gewähren oder Entziehen von App-Ops und Berechtigungen usw. Es ist auch möglich, Anwendungen zu installieren oder\n\\nAnwendungen ohne Aufforderung durch das System zu installieren oder zu deinstallieren.</string>\n    <string name=\"faq$misc$$shizuku-title\">Gibt es Pläne für Shizuku\\?</string>\n    <string name=\"faq$misc$i-dont-use-root-adb\">Ja. AM kann keine Systemeinstellungen ohne Root oder ADB over TCP\\\\@ ändern.</string>\n    <string name=\"faq$misc$how-tracker-updated\">Tracker und Bibliotheken werden manuell aktualisiert, bevor eine neue Version veröffentlicht wird.</string>\n    <string name=\"faq$misc$shizuku\">Die Verwendung von versteckten APIs und die Ausführung von privilegiertem Code durch App Manager ist jetzt viel komplexer und kann nicht mit\n\\nanderen Anwendungen von Drittanbietern wie z. B. \\\\href{https://shizuku.rikka.app}{Shizuku}. Hier sind einige Gründe für die Nichtberücksichtigung von\n\\nShizuku (das jetzt die Apache 2.0 Lizenz hat) durch den App Manager:\n\\n\\\\begin{enumerate}\n\\n \\\\item Shizuku war ursprünglich unfrei, was mich dazu veranlasste, einen ähnlichen Ansatz für App Manager zu verwenden, um sowohl root\n\\n und ADB zu nutzen\n\\n \\\\item App Manager unterstützt bereits sowohl ADB als auch Root, was in einigen Fällen leistungsfähiger ist als Shizuku\n\\n \\\\item Sich für die wichtigsten Funktionen auf eine Drittanbieter-App zu verlassen, ist keine gute Designentscheidung\n\\n \\\\item Die Integration von Shizuku wird die Komplexität des App Managers erhöhen.\n\\n\\\\end{enumerate}</string>\n    <string name=\"pages$settings-page$$section-title\">Seite Einstellungen</string>\n    <string name=\"pages$settings-page$$language-title\">Sprache</string>\n    <string name=\"pages$settings-page$$installer-app-title\">InstallationsApps</string>\n    <string name=\"pages$settings-page$$installer-title\">Installationsprogramm</string>\n    <string name=\"pages$settings-page$$sign-apk-title\">APK signieren</string>\n    <string name=\"pages$settings-page$$install-location-title\">Installationsort</string>\n    <string name=\"pages$settings-page$$backup-restore-title\">Sichern/Wiederherstellen</string>\n    <string name=\"pages$profile-page$save-apk\">Aktiviert die Speicherung von APK-Dateien unter \\\\texttt{AppManager/apks} (oder in dem auf der Einstellungsseite ausgewählten Verzeichnis) der ausgewählten Pakete.</string>\n    <string name=\"pages$settings-page$$compression-method-title\">Komprimierungsverfahren</string>\n    <string name=\"pages$settings-page$$backup-options-title\">Sicherungsoptionen</string>\n    <string name=\"pages$settings-page$$instant-component-blocking-title\">Sofortige Komponentensperre</string>\n    <string name=\"pages$profile-page$app-ops\">Dies verhält sich genauso wie die Option \\\\hyperref[subsec:set-mode-for-app-ops-dots]{Modus für App Ops einstellen\\\\dots} auf der\n\\nder Seite 1-Klick-Ops. Allerdings wird der Vorgang hier nur auf die ausgewählten Pakete angewendet.\n\\nWenn der Status von \\\\hyperref[subsubsec:profile-state]{Status} \\\\textit{Ein} ist, werden die App-Ops verweigert (d. h. ignoriert),\n\\nund wenn der Status \\\\textit{Aus} ist, werden die App-Ops zugelassen. Die Option kann deaktiviert werden (unabhängig von den eingegebenen\n\\nWerte) durch Klicken auf die Schaltfläche \\\\textit{deaktivieren} im Eingabedialog deaktiviert werden.</string>\n    <string name=\"pages$profile-page$permissions\">Mit dieser Option können Sie bestimmte Rechte für die ausgewählten Pakete gewähren oder entziehen. Wie andere oben,\n\\nmüssen die Berechtigungen durch Leerzeichen getrennt werden. Wenn der \\\\hyperref[subsubsec:profile-state]{Staus} \\\\textit{Ein} ist, werden die\n\\nwerden die Berechtigungen entzogen, und wenn der Status \\\\textit{Aus} ist, werden die Berechtigungen erlaubt. Die Option kann\n\\ndeaktiviert werden (unabhängig von den eingegebenen Werten), indem Sie im Eingabedialog auf die Schaltfläche \\\\textit{deaktivieren} klicken.</string>\n    <string name=\"pages$profile-page$block-trackers\">Aktiviert die Sperrung oder Entsperrung der Tracker-Komponenten der ausgewählten Pakete je nach dem Wert von \\\\hyperref[subsubsec:profile-state]{Status}.\n\\nWenn der Zustand \\\\textit{EIN} ist, werden die Tracker blockiert, und wenn der Zustand \\\\textit{AUS} ist, werden die Tracker entsperrt.</string>\n    <string name=\"pages$settings-page$$backup-apps-with-keystore-title\">Anwendungen mit Android KeyStore sichern</string>\n    <string name=\"pages$profile-page$export-blocking-rules\">\\\\begin{danger}{Achtung}\n\\n Diese Option ist noch nicht implementiert.\n\\n\\\\end{danger}</string>\n    <string name=\"pages$profile-page$force-stop\">Ermöglicht, dass die ausgewählten Pakete zwangsgestoppt werden.</string>\n    <string name=\"pages$profile-page$clear-data\">Aktiviert das Löschen von Daten für die ausgewählten Pakete.</string>\n    <string name=\"pages$profile-page$clear-cache\">Aktiviert das Löschen des Cache für die ausgewählten Pakete.</string>\n    <string name=\"pages$settings-page$$encryption-title\">Verschlüsselung</string>\n    <string name=\"pages$settings-page$$rules-title\">Regeln</string>\n    <string name=\"pages$settings-page$$backup-volume-title\">Sicherungsvolumen</string>\n    <string name=\"pages$settings-page$$remove-all-rules-title\">Alle Regeln löschen</string>\n    <string name=\"pages$settings-page$$import-export-keystore-title\">Schlüsselspeicher importieren/exportieren</string>\n    <string name=\"pages$settings-page$$import-export-blocking-rules-title\">Import/Export-Sperrregeln</string>\n    <string name=\"pages$settings-page$$device-info-title\">Über das Gerät selbst</string>\n    <string name=\"pages$settings-page$intro\">Die Seite Einstellungen kann verwendet werden, um das Verhalten des App Manager anzupassen.</string>\n    <string name=\"pages$settings-page$language\">Konfigurieren Sie die In-App-Sprache. App Manager unterstützt derzeit 21 (einundzwanzig) Sprachen.</string>\n    <string name=\"pages$settings-page$app-theme\">In-App-Thema konfigurieren.</string>\n    <string name=\"pages$settings-page$screen-lock\">Sperren Sie den App Manager mit der Android-Bildschirmsperre, sofern eine Bildschirmsperre konfiguriert ist.\n\\n\n\\n\\\\begin{warning}{Warnung}\n\\n Wenn die Bildschirmsperre in Android nach dem Aktivieren dieser Einstellung deaktiviert ist, wird App Manager nicht geöffnet, bis sie wieder aktiviert wird.\n\\n\\\\end{warning}</string>\n    <string name=\"pages$settings-page$mode-of-operation\">Der Betriebsmodus legt fest, wie der App Manager insgesamt funktioniert. Er hat die folgenden Optionen:\n\\n\\\\begin{itemize}\n\\n \\\\item \\\\textbf{Auto.} Überlassen Sie App Manager die Wahl der geeigneten Option.\n\\n Obwohl dies die Standardoption ist, sollten nicht gerootete Benutzer den Modus \\\\textit{no-root} verwenden.\n\\n\n\\n \\\\textbf{Root.} Betreibt App Manager im Root-Modus. App Manager fällt in den Modus \\\\textit{no-root} zurück, wenn root\n\\n nicht erkannt wird, oder in seltenen Fällen, wenn die Binder-Kommunikation über root deaktiviert ist (z.B. in \\\\href{https://github.com/MuntashirAkon/AppManager/issues/606}{Phh SuperUser}).\n\\n\n\\n \\\\item \\\\textbf{ADB über TCP.} Betreiben Sie App Manager im ADB-Modus über \\\\hyperref[sec:adb-over-tcp]{ADB über TCP}.\n\\n App Manager fällt in den \\\\textit{no-root}-Modus zurück, wenn ADB over TCP nicht aktiviert ist.\n\\n\n\\n \\\\textbf{Wireless debugging}. Aktivieren Sie ADB über Wireless Debugging. Es wird versucht, zunächst automatisch eine Verbindung mit dem konfigurierten Port\n\\n automatisch zu verbinden. Wenn dies fehlschlägt, wird der Benutzer aufgefordert, entweder ein Pairing durchzuführen oder sich manuell mit dem ADB-Daemon zu verbinden.\n\\n App Manager fällt in den Modus \\\\textit{no-root} zurück, wenn die Verbindung mit dem ADB-Daemon auf diese Weise nicht zustande kommt.\n\\n \\\\begin{tip}{Info}\n\\n Diese Option wird nur bei Geräten mit Android 11 oder höher angezeigt, da Wireless Debugging mit Android 11 eingeführt wurde.\n\\n \\\\end{tip}\n\\n\n\\n \\\\item \\\\textbf{No-root.} Betreiben Sie App Manager im no-root Modus. Während App Manager in diesem Modus besser funktioniert,\n\\n werden alle Root- oder ADB-spezifischen Funktionen deaktiviert.\n\\n\\\\end{itemize}\n\\n\n\\nHier wird auch der aktuell abgeleitete Betriebsmodus angezeigt. Die tatsächlichen Betriebsmodi sind \\\\textit{root}, \\\\textit{ABD} und \\\\textit{no-root}.</string>\n    <string name=\"pages$settings-page$enable-disable-features\">Aktivieren oder deaktivieren Sie bestimmte Funktionen im App Manager, z. B.\n\\n\\\\begin{itemize}\n\\n \\\\item \\\\textbf{Interceptor}\n\\n \\\\item \\\\textbf{Manifest Betrachter}\n\\n \\\\item \\\\textbf{Scanner}\n\\n \\\\item \\\\textbf{Paketinstallationsprogramm}\n\\n \\\\item \\\\textbf{Benutzungszugriff} Wenn diese Funktion deaktiviert ist, fragt der App Manager nie nach der Berechtigung \\\\textit{Benutzungszugriff}.\n\\n \\\\Eintrag \\\\textbf{Protokollanzeige}\n\\n \\\\item \\\\textbf{App Explorer.} Die Option ``Explore\\'\\' wird nicht verfügbar sein, wenn versucht wird, eine APK-Datei zu öffnen.\n\\n \\\\item \\\\textbf{Nutze das Internet.} Alle Internetfunktionen sind deaktiviert, wenn diese Funktion ausgeschaltet ist.\n\\n Derzeit ist die einzige Internetfunktion das Abrufen von Scanberichten über VirusTotal.\n\\n\\\\end{itemize}</string>\n    <string name=\"pages$settings-page$signature-schemes\">Konfigurieren Sie die \\\\href{https://source.android.com/security/apksigning}{Signaturschemata}, die verwendet werden sollen, wenn die APK-Signierung aktiviert ist.\n\\nDie Signaturschemata v1 und v2 sind standardmäßig aktiviert, aber v3 sollte ebenfalls aktiviert werden, um eine angemessene Sicherheit in Android 9 oder höher zu gewährleisten.</string>\n    <string name=\"pages$settings-page$signing-key\">Konfigurieren Sie einen benutzerdefinierten Signierschlüssel zum Signieren von APK-Dateien. Schlüssel aus einem bestehenden KeyStore können in den App Manager importiert werden,\n\\noder es kann ein neuer Schlüssel generiert werden.\n\\n\n\\n\\\\begin{danger}{Gefahr}\n\\n Verwenden Sie nicht den Schlüssel, der mit App Manager geliefert wird, da er für jeden öffentlich zugänglich ist. In Zukunft wird\n\\n der Standardschlüssel entfernt werden.\n\\n\\\\end{danger}\n\\n\n\\n\\\\begin{tip}{Tipp}\n\\n Wenn Sie den Schlüssel in Zukunft verwenden müssen, empfiehlt es sich, selbst einen KeyStore zu erstellen und den Schlüssel\n\\n zu importieren. Bei Schlüsseln, die im App Manager generiert wurden, besteht die Gefahr, dass sie ohne eine ordnungsgemäße Sicherung gelöscht werden.\n\\n\\\\end{tip}</string>\n    <string name=\"pages$profile-page$backup-restore\">Mit dieser Option können Sie ein Backup der ausgewählten Anwendungen und ihrer Daten erstellen oder diese wiederherstellen.\n\\nHier sind zwei Optionen verfügbar: \\\\textit{Sicherungsoptionen} und \\\\textit{Sicherungsname}.\n\\n\\\\begin{itemize}\n\\n \\\\textbf{Backup-Optionen} Dasselbe wie die \\\\hyperref[subsec:backup-restore-backup-options]{Sicherungsoptionen} der\n\\n Sicherungs-/Wiederherstellungsfunktion. Wenn nicht festgelegt, werden die Standardoptionen verwendet.\n\\n \\\\item \\\\textbf{Backup-Name} Legen Sie einen benutzerdefinierten Namen für die Sicherung fest. Wenn der Name der Sicherung festgelegt ist, erhält sie bei jeder Erstellung einer Sicherung\n\\n einen eindeutigen Namen mit dem Suffix backup-name erhalten. Dieses Verhalten wird in einer zukünftigen Version korrigiert werden.\n\\n Lassen Sie dieses Feld für reguläre ``Basis\\'\\'-Sicherungen leer (stellen Sie außerdem sicher, dass Sie \\\\textit{Mehrfachsicherung} in den\n\\n Sicherungsoptionen aktivieren).\n\\n\\\\end{itemize}\n\\n\n\\nWenn der Status von \\\\hyperref[subsubsec:profile-state]{Staus} \\\\textit{Ein} ist, werden die Pakete gesichert, und wenn der Status\n\\n\\\\textit{off}, werden die Pakete wiederhergestellt. Die Option kann deaktiviert werden, indem Sie auf die Schaltfläche \\\\textit{deaktivieren} im\n\\ndem Eingabedialog.</string>\n    <string name=\"pages$app-details-page$$shared-libs-tab-title\">Registerkarte Gemeinsame Bibliotheken</string>\n    <string name=\"keywords$see_also\">\\\\newcommand{\\\\KeywordSeeAlso}{Siehe auch:}</string>\n    <string name=\"pages$settings-page$sign-apk\">Ob die APK-Dateien vor der Installation der Anwendung signiert werden sollen. Die Seite \\\\hyperref[subsec:apk-signing]{APK Signierung} kann\n\\nverwendet werden, um die Signierung zu konfigurieren.</string>\n    <string name=\"pages$settings-page$backup-restore\">Einstellungen in Bezug auf \\\\hyperref[sec:backup-restore]{Sicherung/Wiederherstellung}.</string>\n    <string name=\"pages$settings-page$install-location\">Definieren Sie den APK-Installationsort. Dies kann eine der Optionen \\\\textit{auto}, \\\\textit{nur intern} und \\\\textit{vorzugsweise extern} sein.\n\\nBei neueren Android-Versionen garantiert die Auswahl der letzten Option nicht, dass die Anwendung auf dem externen Speicher installiert wird.</string>\n    <string name=\"keywords$end_of_keyword_in_alert\">\\\\newcommand{\\\\KeywordEndOfKeyWordInAlert}{:}</string>\n    <string name=\"pages$settings-page$$install-in-the-background-title\">Im Hintergrund installieren</string>\n    <string name=\"pages$settings-page$$import-backups-title\">Backups importieren</string>\n    <string name=\"pages$settings-page$$selected-users-title\">Ausgewählte Benutzer</string>\n    <string name=\"pages$settings-page$$saved-apk-name-format-title\">Gespeichertes APK-Namensformat</string>\n    <string name=\"pages$settings-page$$block-trackers-title\">Tracker blockieren</string>\n    <string name=\"pages$settings-page$$display-changes-title\">Änderungen anzeigen</string>\n    <string name=\"pages$settings-page$selected-users\">Mit dieser Option können Sie festlegen, für welche Benutzer App Manager arbeiten soll. App Manager arbeitet standardmäßig für alle Benutzer im Root- oder ADB-Modus.</string>\n    <string name=\"pages$settings-page$block-trackers\">Ob die Tracking-Komponenten sofort nach der Installation der Anwendung blockiert werden sollen.</string>\n    <string name=\"pages$settings-page$display-changes\">Ob Änderungen an Version, Tracker, Komponenten, Berechtigungen, Signaturen, SDK usw. versionskontrolliert angezeigt werden sollen, wenn die Anwendung bereits installiert wurde.</string>\n    <string name=\"pages$settings-page$install-in-the-background\">Ob Anwendungen immer im Hintergrund installiert werden sollen. Sobald die Installation abgeschlossen ist, wird eine Benachrichtigung ausgegeben.</string>\n    <string name=\"pages$settings-page$compression-method\">Legen Sie die Kompressionsmethode fest, die bei Backups verwendet werden soll. App Manager unterstützt die Komprimierungsmethoden GZip und BZip2,\n\\nGZip ist die Standardkomprimierungsmethode. Es hat keinen Einfluss auf die Wiederherstellung einer bestehenden Sicherung.</string>\n    <string name=\"pages$settings-page$backup-options\">Passen Sie das Dialogfeld \\\\textit{Sicherung/Wiederherstellung} an, das bei der Erstellung einer Sicherung angezeigt wird.\n\\n\n\\n\\\\seealsoinline{\\\\hyperref[subsec:backup-restore-backup-options]{Sicherungsoptionen}}</string>\n    <string name=\"pages$settings-page$import-backups\">Importieren Sie Sicherungen aus alten und eingestellten Projekten wie Titanium Backup, OAndBackup und Swift Backup (Version 3.0 bis 3.2).\n\\nDie Sicherungen werden nach dem Importieren nicht gelöscht, um Datenverluste zu vermeiden, falls die importierten Sicherungen nicht ordnungsgemäß wiederhergestellt werden können.</string>\n    <string name=\"pages$settings-page$import-export-keystore\">Importieren oder exportieren Sie den von App Manager verwendeten KeyStore. Dies ist ein Bouncy Castle KeyStore mit der Erweiterung \\\\texttt{bks}.\n\\nDaher werden andere KeyStore wie Java KeyStore (JKS) oder PKCS \\\\#12 nicht unterstützt.\n\\nWenn ein Schlüssel aus einem solchen KeyStore importiert werden muss, sollten die entsprechenden Optionen wie oben angegeben gewählt werden.</string>\n    <string name=\"pages$settings-page$installer-app\">Wählen Sie die Installationsanwendung aus. Dies ist nützlich für Anwendungen, die explizit das Installationsprogramm prüfen, um festzustellen, ob die Anwendung rechtmäßig installiert wurde.\n\\nDies funktioniert nur für Root- oder ADB-Benutzer.\n\\n\n\\n\\\\begin{tip}{Hinweis}\n\\n Während die Suche nach dem Installationsprogramm ein legitimes Anliegen für eine Anwendung zu sein scheint, kümmert sich das Android-Framework bereits während der Installation um dieses Problem.\n\\n Die Suche nach dem Installationsprogramm ist einfach der falsche Weg, um die Legitimität der Quelle einer Anwendung zu beweisen.\n\\n\\\\end{tip}</string>\n    <string name=\"pages$settings-page$encryption\">Legen Sie eine Verschlüsselungsmethode für die Backups fest. App Manager unterstützt derzeit OpenPGP (über\n\\n\\\\href{https://f-droid.org/packages/org.sufficientlysecure.keychain/}{OpenKeyChain}), AES und RSA (Hybridverschlüsselung mit AES).\n\\nWie bei der \\\\hyperref[subsec:apk-signing]{APK Signierung} werden die AES- und RSA-Schlüssel im KeyStore gespeichert und können aus anderen KeyStores importiert werden.\n\\n\n\\n\\\\begin{danger}{Gefahr}\n\\n Zu Ihrer eigenen Sicherheit ist es nicht empfehlenswert, RSA-Schlüssel innerhalb des App Managers zu erzeugen. Stattdessen sollten sie aus einem KeyStore importiert werden, der an einem sicheren Ort aufbewahrt wird.\\\\\\\\\n\\n Im Falle von AES sollte der generierte Schlüssel an einem sicheren Ort gespeichert werden, z. B. in einem Passwortmanager.\n\\n\\\\end{danger}</string>\n    <string name=\"pages$settings-page$backup-apps-with-keystore\">Sicherung von Anwendungen mit Einträgen im Android KeyStore zulassen. Diese Option ist standardmäßig deaktiviert, da einige Anwendungen (z. B. Signal) bei der Wiederherstellung abstürzen können.</string>\n    <string name=\"pages$settings-page$backup-volume\">Wählen Sie den Speicher, in dem die Backups gespeichert werden. Hier werden auch Protokolle und exportierte APK-Dateien gespeichert.\n\\n\n\\n\\\\begin{tip}{Hinweis}\n\\n Das Backup-Volume gibt nur den Speicherort, nicht den Pfad an. Backups werden traditionell im Ordner \\\\texttt{AppManager} innerhalb des Speicherpfads gespeichert.\n\\n Wenn der Pfad jedoch mit Storage Access Framework (SAF) ausgewählt wurde, wird der ausgewählte Pfad oder das Verzeichnis direkt verwendet.\n\\n\\\\end{tip}</string>\n    <string name=\"pages$settings-page$instant-component-blocking\">Standardmäßig werden Sperrregeln nicht angewendet, es sei denn, sie werden explizit in \\\\hyperref[sec:app-details-page]{der Seite mit den Anwendungsdetails} für eine beliebige Anwendung angewendet.\n\\nNach Aktivierung dieser Option werden alle (alten und neuen) Regeln sofort für alle Anwendungen angewendet, ohne dass die Sperrung für eine Anwendung explizit aktiviert wird.\n\\n\n\\n\\\\seealsoinline{\\\\hyperref[subsec:faq:what-is-instant-component-blocking]{FAQ: Was ist Instant-Component-Blocking\\?}}</string>\n    <string name=\"pages$settings-page$import-export-blocking-rules\">Es ist möglich, Sperrregeln im App Manager für alle Anwendungen zu importieren oder zu exportieren. Die Arten von Regeln (Komponenten, App Ops oder Berechtigungen), die importiert oder exportiert werden sollen, können ebenfalls ausgewählt werden.\n\\nEs ist auch möglich, Sperrregeln aus \\\\href{https://github.com/lihenggui/blocker}{Blocker} und \\\\href{https://github.com/tuyafeng/Watt}{Watt} zu importieren.\n\\nWenn es notwendig ist, Sperrregeln für eine einzelne Anwendung zu exportieren, kann die entsprechende \\\\hyperref[sec:app-details-page]{App-Detailseite} verwendet werden, um Regeln zu exportieren, oder für mehrere Anwendungen können \\\\hyperref[subsec:batch-operations]{Batchoperationen} verwendet werden.\n\\n\n\\n\\\\seealsoinline{\\\\hyperref[sec:rules-specification]{Regelspezifikation}}\n\\n\n\\n\\\\paragraph{Export} Exportiert Sperrregeln für alle im App Manager konfigurierten Anwendungen.\n\\nDies kann \\\\hyperref[subsec:faq:what-are-app-components]{Anwendungskomponenten}, App-OPs und Berechtigungen umfassen, basierend auf den in den Multi-Choice-Optionen ausgewählten Optionen.\n\\n\n\\n\\\\paragraph{Importieren} Importieren Sie zuvor exportierte Blockierungsregeln aus dem App Manager.\n\\nÄhnlich wie beim Export kann dies \\\\hyperref[subsec:faq:what-are-app-components]{App Komponenten}, App Operationen und Berechtigungen basierend auf den in den Multi-Choice-Optionen ausgewählten Optionen enthalten.\n\\n\n\\n\\\\paragraph{Importieren bestehender Regeln}\\\\label{par:import-existing-rules}\n\\n\\\\antomsection\n\\nHinzufügen von Komponenten zum App Manager, die von anderen Anwendungen deaktiviert wurden. App Manager verfolgt nur die Komponenten, die innerhalb von App Manager deaktiviert wurden.\n\\nWenn Anwendungskomponenten von anderen Tools oder Anwendungen blockiert oder deaktiviert werden, können Sie diese mit dieser Option importieren.\n\\nWenn Sie auf diese Option klicken, findet App Manager die Komponenten, die möglicherweise von anderen Anwendungen oder Tools deaktiviert wurden, und listet nur den Namen der Anwendungen zusammen mit der Anzahl der übereinstimmenden Komponenten auf.\n\\nZur Sicherheit sind alle Anwendungen standardmäßig nicht ausgewählt. Sie müssen manuell ausgewählt werden, und die Blockierung muss über den App Manager erneut angewendet werden.\n\\n\n\\n\\\\begin{danger}{Achtung}\n\\n Seien Sie bei der Verwendung dieses Tools vorsichtig, da es viele falsch positive Ergebnisse geben kann.\n\\n Wählen Sie nur die Anwendungen aus, bei denen Sie sich sicher sind.\n\\n\\\\end{danger}\n\\n\n\\n\\\\paragraph{Importieren von Watt} Importieren Sie Konfigurationsdateien aus \\\\href{https://github.com/tuyafeng/Watt}{Watt}, wobei jede Datei\n\\nRegeln für ein einzelnes Paket enthält und der Dateiname der Name des Pakets mit der Erweiterung \\\\texttt{.xml} ist.\n\\n\n\\n\\\\begin{tip}{Tip}\n\\n Speicherort der Konfigurationsdateien in Watt: \\\\texttt{/sdcard/Android/data/com.tuyafeng.watt/files/ifw}\n\\n\\\\end{tip}\n\\n\n\\n\\\\paragraph{Importieren von Blocker} Importieren Sie Blockierungsregeln aus \\\\href{https://github.com/lihenggui/blocker}{Blocker}, wobei jede Datei Regeln für ein einzelnes Paket enthält.\n\\nDiese Dateien haben die Erweiterung \\\\texttt{.json}.</string>\n    <string name=\"pages$settings-page$remove-all-rules\">Ein-Klick-Option zum Entfernen aller im App Manager konfigurierten Regeln.\n\\nDadurch werden alle blockierten Komponenten aktiviert, die App-OPs werden auf ihre Standardwerte gesetzt und die Berechtigungen werden gewährt.</string>\n    <string name=\"pages$settings-page$saved-apk-name-format\">Legt das Format des APK-Namens fest, das beim Speichern über Batch-Operationen oder über Profile verwendet werden soll.\n\\nApp Manager bietet einige spezielle Schlüsselwörter, die in \\\\texttt{\\\\%} (Prozentzeichen) eingeschlossen und unterhalb des Eingabefeldes zu finden sind.\n\\nDiese Schlüsselwörter sind:\n\\n\\\\begin{itemize}\n\\n \\\\item \\\\textbf{\\\\texttt{Bezeichnung}.} Bezeichnet den Namen oder die Bezeichnung der Anwendung. Dieser kann je nach Anwendung in der konfigurierten Sprache lokalisiert werden.\n\\n \\\\item \\\\textbf{\\\\texttt{Paketname}.} Bezeichnet den Namen des Pakets oder die Anwendungs-ID, den eindeutigen Bezeichner, den jede Anwendung hat.\n\\n \\\\item \\\\textbf{\\\\texttt{Version}.} Gibt die aktuelle Version der Anwendung an, die dem Manifest entnommen wurde.\n\\n \\\\item \\\\textbf{\\\\texttt{Versionscode}.} Bezeichnet den aktuellen Versionscode der Anwendung, der verwendet werden kann, um zwei Versionen derselben Anwendung zu unterscheiden.\n\\n \\\\item \\\\textbf{\\\\texttt{mindest notwendiges SDK }.} Bezeichnet das minimale SDK (d. h. die Version des Android-Frameworks), mit dem die Anwendung arbeiten kann. Diese Daten sind erst seit Android 7 (Nougat) verfügbar.\n\\n \\\\item \\\\textbf{\\\\texttt{empfohlenes SDK}.} Bezeichnet das SDK, auf das diese Anwendung abzielt. Die Anwendung kann auf höheren SDKs arbeiten, aber nur im Kompatibilitätsmodus.\n\\n \\\\item \\\\textbf{\\\\texttt{Datumsangabe}.} Bezeichnet die Uhrzeit und das Datum, an dem die APK exportiert wird.\n\\n\\\\end{itemize}</string>\n    <string name=\"keywords$chapter\">\\\\newcommand{\\\\KeywordChapter}{Kapitel}</string>\n    <string name=\"pages$app-details-page$shared-libs-tab\">\\\\textbf{Gemeinsame Bibliotheken} listet alle JAR-Legacy-Abhängigkeiten sowie die JNI-Bibliotheken (Java Native Interface) auf.\n\\nFür JNI-Bibliotheken wird die Plattform (x86/x86\\\\_64/ARM/AArch64), die Architektur (32/64 Bit), der Objekttyp (Shared Object\n\\noder ausführbar), usw.</string>\n    <string name=\"pages$scanner-page$$missing-signatures-title\">Fehlende Signaturen</string>\n    <string name=\"pages$scanner-page$missing-signatures\">Unten auf der Seite befindet sich ein spezieller Punkt, der die Anzahl der fehlenden Signaturen (d. h. der fehlenden Klassen) angibt.\n\\nDie fehlenden Signaturen sind diejenigen, die AM nicht mit bekannten Bibliotheken abgleichen konnte. Die Zahl selbst hat keine\n\\nBedeutung, da viele Bibliotheken Hunderte von Klassen enthalten, aber ein Klick auf das Element öffnet ein Dialogfeld\n\\nder die Signaturen enthält, was bei der Überprüfung der fehlenden Signaturen hilfreich ist. \\\\textbf{Diese Funktion ist nur für Personen\n\\ngedacht, die wissen, was eine fehlende Signatur ist und was damit zu tun ist. Andere Benutzer sollten sie ignorieren.}</string>\n    <string name=\"pages$settings-page$device-info\">Anzeige von Android-Version, Sicherheit, CPU, GPU, Akku, Speicher, Bildschirm, Sprachen, Benutzerinformationen usw.</string>\n    <string name=\"pages$scanner-page$$section-title\">Scanner-Seite</string>\n    <string name=\"pages$scanner-page$intro\">\\\\textbf{Scanner-Seite} wird angezeigt, nachdem Sie auf die Schaltfläche \\\\emph{Scanner} in der Registerkarte \\\\hyperref[subsec:app-info-tab]{App-Info} geklickt haben.\n\\nExterne APK-Dateien können auch über Dateimanager, Webbrowser usw. zum Scannen geöffnet werden.\n\\n\n\\nEs wird nach Trackern und Bibliotheken gescannt und die Anzahl der Tracker und Bibliotheken als Zusammenfassung angezeigt. Es zeigt auch\n\\nPrüfsummen der APK-Datei sowie die Signierzertifikate. Wenn VirusTotal in den Einstellungen konfiguriert ist,\n\\nversucht es auch, Berichte von VirusTotal abzurufen, oder lädt die APK-Datei hoch, wenn sie sich nicht in der Datenbank befindet.\n\\n\n\\n\\\\begin{danger}{Disclaimer}\n\\n App Manager scannt eine Anwendung nur statisch und ohne Vorurteile. Die Anwendung kann Optionen für die Ablehnung anbieten,\n\\n oder in einigen Fällen werden bestimmte Funktionen des Trackers von der Anwendung überhaupt nicht genutzt (z. B. F-Droid),\n\\n oder manche Anwendungen verwenden sie einfach als Platzhalter, um den Ausfall bestimmter Funktionen zu verhindern (z. B. \\\\ Fennec F-Droid).\n\\n \\\\textbf{Die Absicht des Scanners ist es, Ihnen eine Vorstellung davon zu geben, was die APK enthalten könnte. Er sollte als erster Schritt für weitere Untersuchungen angesehen werden.}\n\\n\\\\end{danger}\n\\n\n\\nEin Klick auf den ersten Punkt (d.h. die Anzahl der Klassen) öffnet eine neue Seite mit einer Liste der Tracker-Klassen für die Anwendung.\n\\nAlle Klassen können auch durch Anklicken des Menüs \\\\textit{Toggle Class Listing} angezeigt werden.\n\\nEine Vorschau auf jede Klasse kann durch einfaches Klicken auf ein beliebiges Klassenelement angezeigt werden. In Android 8 (Oreo) und später,\n\\nenthält dies die gesamte SMALI-Version der Klasse und kann mit der entsprechenden Option in Java konvertiert werden.\n\\n\n\\n\\\\begin{tip}{Hinweis}\n\\n Aufgrund verschiedener Einschränkungen ist es nicht möglich, alle Komponenten einer APK-Datei zu scannen. Dies gilt insbesondere, wenn\n\\n eine APK stark verschleiert ist. Der Scanner prüft auch keine Zeichenketten (oder Website-Signaturen).\n\\n\\\\end{tip}\n\\n\n\\nDer zweite Punkt listet die Anzahl der Tracker zusammen mit deren Namen auf. Wenn Sie auf diesen Punkt klicken, wird ein Dialog angezeigt, der\n\\nden Namen der Tracker, die übereinstimmenden Signaturen und die Anzahl der Klassen für jede Signatur. Einige Tracker-Namen können ein\n\\n$^2$ vorangestellt, was anzeigt, dass die Tracker in der \\\\href{https://etip.exodus-privacy.eu.org}{ETIP} Stand-by-Liste stehen\n\\nd.h. ob es sich um tatsächliche Tracker handelt, wird noch untersucht.\n\\n\n\\nDer dritte Punkt listet die Anzahl der Bibliotheken zusammen mit ihren Namen auf. Die Informationen stammen größtenteils aus dem\n\\n\\\\href{https://gitlab.com/IzzyOnDroid/repo}{IzzyOnDroid Repository}.\n\\n\n\\n\\\\seealsoinline{\\\\hyperref[subsec:tracker-classes-versus-tracker-components]{FAQ: Tracker-Klassen vs. Tracker-Komponenten}}</string>\n    <string name=\"pages$interceptor-page$$section-title\">Interceptor-Seite</string>\n    <string name=\"pages$interceptor-page$$intent-filters-title\">Intent-Filter</string>\n    <string name=\"pages$interceptor-page$$action-title\">Aktion</string>\n    <string name=\"pages$interceptor-page$$data-title\">Daten</string>\n    <string name=\"pages$interceptor-page$$mime-type-title\">MIME-Typ</string>\n    <string name=\"pages$interceptor-page$$categories-title\">Kategorien</string>\n    <string name=\"pages$interceptor-page$$flags-title\">Flaggen</string>\n    <string name=\"pages$interceptor-page$$extras-title\">Extras</string>\n    <string name=\"pages$interceptor-page$$uri-title\">URI</string>\n    <string name=\"pages$interceptor-page$$matching-activities-title\">Übereinstimmende Aktivitäten</string>\n    <string name=\"pages$interceptor-page$intro\">Interceptor kann verwendet werden, um die Kommunikation zwischen Anwendungen mit Hilfe von \\\\texttt{Intent} abzufangen.\n\\nEr arbeitet als Man-in-the-Middle zwischen der Quell- und der Zielanwendung.\n\\nEr bietet eine funktionsreiche Benutzeroberfläche zur Bearbeitung von \\\\texttt{Intent}s.\n\\n\n\\n\\\\begin{warning}{Warning}\n\\n Interceptor funktioniert nur für \\\\textit{implicit}-Intents, bei denen die \\\\hyperref[subsec:faq:what-are-app-components]{App-Komponente} nicht angegeben ist.\n\\n\\\\end{warning}\n\\n\n\\n\\\\begin{amseealso}\n\\n \\\\item \\\\href{https://developer.android.com/guide/components/intents-common}{Gemeinsame Intents}\n\\n \\\\item \\\\href{https://developer.android.com/guide/components/intents-filters}{Intents und Intent-Filter}\n\\n\\\\end{amseealso}</string>\n    <string name=\"pages$interceptor-page$$reset-to-default-title\">Zurücksetzen auf Standard</string>\n    <string name=\"pages$interceptor-page$$send-edited-intent-title\">Geänderte Absicht senden</string>\n    <string name=\"pages$interceptor-page$intent-filters\">Intent-Filter werden von den Anwendungen verwendet, um die Aufgaben zu spezifizieren, die sie ausführen können oder die sie mit anderen Anwendungen ausführen werden.\n\\nWenn Sie zum Beispiel eine PDF-Datei mit einem Dateimanager öffnen, versucht der Dateimanager, die Anwendungen zu finden, mit denen die PDF-Datei geöffnet werden soll.\n\\nUm die richtigen Anwendungen zu finden, erstellt der Dateimanager einen Intent mit Filtern wie dem MIME-Typ und bittet das System, die Anwendungen abzurufen, die diesen Filter öffnen können.\n\\nDas System durchsucht das Manifest der installierten Anwendungen nach dem Filter und listet die Anwendungskomponenten auf, die in der Lage sind, diesen Filter (in unserem Fall das PDF) zu öffnen.\n\\nDaraufhin öffnet entweder der Dateimanager die gewünschte Anwendungskomponente von selbst oder es wird eine vom System bereitgestellte Option verwendet, um sie zu öffnen.\n\\nWenn mehrere Anwendungskomponenten in der Lage sind, das Dokument zu öffnen, und keine Standardeinstellung festgelegt ist, erhalten Sie möglicherweise eine Aufforderung, die richtige Anwendungskomponente auszuwählen.</string>\n    <string name=\"pages$interceptor-page$categories\">Dies ist ähnlich wie \\\\hyperref[subsubsec:action]{Aktion} in dem Sinne, dass es auch vom System zum Filtern von Anwendungskomponenten verwendet wird.\n\\nDies hat keine weiteren Vorteile. Im Gegensatz zu \\\\textit{Aktion} kann es mehr als eine Kategorie geben. Wenn Sie auf die Schaltfläche \\\\textit{plus} neben dem Titel klicken, können Sie weitere Kategorien hinzufügen.</string>\n    <string name=\"pages$interceptor-page$data\">Daten sind ursprünglich als URI (Uniform Resource Identifier) bekannt, die in \\\\href{http://www.faqs.org/rfcs/rfc2396.html}{RFC 2396} definiert sind.\n\\nEs kann sich um Weblinks, Dateispeicherorte oder eine spezielle Funktion namens \\\\textit{Inhalt} handeln. Inhalte sind eine Android-Funktion, die von den \\\\hyperref[appdetails:providers]{Inhaltsanbietern} verwaltet wird.\n\\nDaten sind oft mit einem \\\\hyperref[subsubsec:mime-type]{MIME-Typ} verbunden.\n\\n\n\\nBeispiele:</string>\n    <string name=\"pages$interceptor-page$mime-type\">MIME-Typ des Feldes \\\\hyperref[subsubsec:data]{Daten}. Wenn das Datenfeld zum Beispiel auf \\\\texttt{file:///sdcard/AppManager.apk} eingestellt ist,\n\\nkann der zugehörige MIME-Typ \\\\texttt{application/vnd.android.package-archive} sein.</string>\n    <string name=\"pages$interceptor-page$action\">Aktion gibt die auszuführende allgemeine Aktion an, z. B. \\\\texttt{android.intent.action.VIEW}. Anwendungen deklarieren oft\n\\ndie relevanten Aktionen in der Manifestdatei an, um die gewünschten Intents abzufangen. Die Aktion ist besonders nützlich für Broadcast\n\\nIntent, wo sie eine wichtige Rolle spielt. In anderen Fällen dient sie als erste Möglichkeit, die relevanten Anwendungskomponenten herauszufiltern.\n\\nGenerische Aktionen wie \\\\texttt{android.intent.action.VIEW} und \\\\texttt{android.intent.action.SEND} werden von vielen Anwendungen verwendet.\n\\nDaher kann diese Einstellung allein viele Anwendungskomponenten abdecken.</string>\n    <string name=\"guide$aot$$aot-lineage-os-title\">Lineage OS 17.1 und vorherige</string>\n    <string name=\"guide$aot$$enable-aot-via-pc-title\">ADB über TCP mittels einem PC oder Mac</string>\n    <string name=\"guide$aot$$adb-mode-am-title\">ADB-Modus im App Manager aktivieren</string>\n    <string name=\"guide$aot$$lg-usb-debug-title\">LG</string>\n    <string name=\"guide$aot$$troubleshooting-usb-debug-title\">Fehlersuche</string>\n    <string name=\"guide$aot$$setup-adb-on-pc-title\">ADB auf einem PC oder Mac einrichten</string>\n    <string name=\"guide$aot$$setup-adb-win-title\">Windows</string>\n    <string name=\"guide$aot$$setup-adb-mac-title\">macOS</string>\n    <string name=\"guide$aot$$setup-adb-linux-title\">Linux</string>\n    <string name=\"guide$aot$$configure-aot-title\">ADB über TCP einrichten</string>\n    <string name=\"guide$aot$$enable-dev-options-title\">Entwickleroptionen aktivieren</string>\n    <string name=\"guide$aot$$section-title\">ADB über TCP</string>\n    <string name=\"pages$interceptor-page$flags\">Markierungen sind nützlich, um zu bestimmen, wie sich das System während des Starts oder nach dem Start einer Aktivität verhalten soll.\n\\nDies sollte nicht berührt werden, da es ein gewisses technisches Hintergrundwissen erfordert. Die Schaltfläche \\\\textit{plus} neben dem Titel kann verwendet werden, um eine oder mehrere Markierungen hinzuzufügen.</string>\n    <string name=\"pages$interceptor-page$reset-to-default\">Setzt das Objekt in seinen Ausgangszustand zurück.</string>\n    <string name=\"pages$shared-prefs-editor-page$$section_title\">Editorseite für gemeinsame Einstellungen</string>\n    <string name=\"pages$shared-prefs-editor-page$intro\">Gemeinsame Einstellungen können auf dieser Seite bearbeitet werden. Wenn Sie auf ein Element in der Liste klicken, wird der Bearbeitungsdialog geöffnet, in dem das Element bearbeitet werden kann.\n\\nÜber die schwebende Aktionsschaltfläche in der unteren rechten Ecke kann ein neues Element hinzugefügt werden. Zum Speichern oder Löschen der Datei,\n\\noder um aktuelle Änderungen zu verwerfen, können die entsprechenden Optionen im Menü verwendet werden.</string>\n    <string name=\"guide$main$$guides-chapter-title\">Leitlinien</string>\n    <string name=\"guide$aot$$location-dev-options-title\">Ort der Entwickleroptionen</string>\n    <string name=\"guide$aot$$how-to-enable-dev-options-title\">Aktivieren von Entwickleroptionen</string>\n    <string name=\"guide$aot$$enable-usb-debugging-title\">USB-Debugging aktivieren</string>\n    <string name=\"guide$aot$$miui-usb-debug-title\">Xiaomi (MIUI)</string>\n    <string name=\"guide$aot$$emui-usb-debug-title\">Huawei (EMUI)</string>\n    <string name=\"guide$aot$$realme-usb-debug-title\">Realme</string>\n    <string name=\"pages$interceptor-page$extras\">Extras sind die Schlüssel-Wert-Paare, die für die Bereitstellung zusätzlicher Informationen für die Zielkomponente verwendet werden. Weitere Extras können über die Schaltfläche \\\\textit{plus} neben dem Titel hinzugefügt werden.</string>\n    <string name=\"pages$interceptor-page$uri\">Stellt den gesamten Inhalt als URI dar (z. B. \\\\texttt{intent://\\\\dots}). Einige Daten können nicht in eine Zeichenkette umgewandelt werden,\n\\nund werden daher hier möglicherweise nicht angezeigt.</string>\n    <string name=\"pages$interceptor-page$matching-activities\">Listet alle Aktivitätskomponenten auf, die dem Zweck entsprechen. Dies wird intern vom System bestimmt (und nicht vom App Manager).\n\\nDie Schaltfläche \\\"Starten\\\" neben jeder Komponente kann verwendet werden, um sie direkt vom App Manager aus zu starten.</string>\n    <string name=\"pages$interceptor-page$send-edited-intent\">Sendet den bearbeiteten Inhalt erneut an die Zielanwendung. Dies kann eine Liste von Anwendungen öffnen, in der die gewünschte Anwendung ausgewählt werden muss.\n\\nDas von der Zielanwendung erhaltene Ergebnis wird an die Quellanwendung gesendet. Daher weiß die Quellanwendung nicht, ob es einen Man-in-the-Middle gab.</string>\n    <string name=\"guide$aot$intro\">Viele reine Root-Funktionen können weiterhin genutzt werden, indem ADB über TCP aktiviert wird. Hierfür ist ein PC oder Mac mit installierten Android\n\\nPlattform-Tools und ein Android-Telefon mit aktivierten Entwickleroptionen und USB-Debugging.\n\\n\n\\n\\\\begin{tip}{Root-Benutzer}\n\\n Wenn dem App Manager die Superuser-Berechtigung erteilt wurde, kann er bereits ohne Probleme privilegierten Code ausführen.\n\\n \\\\textbf{Daher brauchen Root-Benutzer ADB über TCP nicht zu aktivieren.} Wenn Sie ADB over TCP trotzdem verwenden wollen, müssen Sie\n\\n die Superuser-Berechtigung für App Manager widerrufen und Ihr Gerät neu starten. Es kann sein, dass Sie die Meldung \\\\textit{working on ADB mode}\n\\n ohne Neustart sehen, aber das ist nicht ganz richtig. Der Server (der als Schnittstelle zwischen System und App Manager dient)\n\\n wird immer noch im Root-Modus ausgeführt. Dies ist ein bekanntes Problem und wird in einer zukünftigen Version von App Manager behoben.\n\\n\\\\end{tip}\n\\n\n\\n\\\\seealsoinline{\\\\hyperref[sec:faq:adb-over-tcp]{FAQ: ADB-over-TCP}}</string>\n    <string name=\"pages$app-details-page$$tags-title\">Schlagwörter</string>\n</resources>"
  },
  {
    "path": "docs/raw/en/README.md",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later OR CC-BY-SA-4.0 -->\n## Usage\n\n```\n./doctool.sh VERB [ARGS]\nWhere:\ncheck       Run dependency checker.\ncheckabuse <target-dir>         Detect spams or mistranslations.\n```\n\n## Requirements\n\n* [pandoc](https://github.com/jgm/pandoc) (v2.13 or later) (for macOS, run `brew install pandoc`)\n* [pandoc-crossref](https://github.com/lierdakil/pandoc-crossref) (for macOS, run `brew install pandoc-crossref`)\n* Bash\n* GNU grep (for macOS, run `brew install ggrep`)\n* GNU Sed (for macOS, run `brew install gsed`)\n* minify (for macOS, run `brew install minify`)\n* urlextract (`pip install urlextract`)\n* find\n\n### Adding a new article\n\n1. Create a new article following the typical Latex syntax.\n2. Add custom translation keys for the title tags e.g. `section{}`,\n   `subsection{}`, `subsubsection{}`, `chapter{}`, `caption{}` and\n   `paragraph{}` at the end of the title line.\n\n   **Key format:** `%%##$key>>` where `key` is an arbitrary key for the title\n   unique to the file and must match this regex: `[a-zA-Z0-9-_\\.]+`.\n\n   **Example:** Consider the following line in Latex in a file located at \n   `appendices/app-ops.tex`:\n   ```latex\n   \\chapter{App Ops}\\label{ch:app-ops}\n   ```\n\n   This has to be altered as follows:\n   ```latex\n   \\chapter{App Ops}\\label{ch:app-ops} %%##$chapter-title>>\n   ```\n   \n   On issuing an `rebase`, the line will be extracted as follows in strings.xml:\n   ```xml\n   <string name=\"appendices$app-ops$$chapter-title\">App Ops</string>\n   ```\n   \n   Finally, the full title must be within a single line.\n\n3. Add custom translation keys for the contents.\n\n   **Format:** Start of the content is denoted by `%%!!key<<` where key is an\n   arbitrary key for the content unique to the file and must match this regex:\n   `[a-zA-Z0-9-_\\.]+`. End of the content is denoted by `%%!!>>`.\n\n   **Example:** Consider the following paragraph in Latex:\n   ```latex\n   After \\hyperref[subsubsec:location-of-developer-options]{locating the developer options}, enable \\textbf{Developer option} (if not already).\n   After that, scroll down a bit until you will find the option \\textbf{USB debugging}.\n   Use the toggle button on the right-hand side to enable it.\n   At this point, you may get an alert prompt where you may have to click \\textit{OK} to actually enable it.\n   You may also have to enable some other options depending on device vendor and ROM.\n   ```\n\n   This has to be altered as follows:\n   ```latex\n   %%!!enable-usb-debug<<\n   After \\hyperref[subsubsec:location-of-developer-options]{locating the developer options}, enable \\textbf{Developer option} (if not already). After that, scroll down a bit until you will find the option \\textbf{USB debugging}.\n   Use the toggle button on the right-hand side to enable it.\n   At this point, you may get an alert prompt where you may have to click \\textit{OK} to actually enable it.\n   You may also have to enable some other options depending on device vendor and ROM\\@.\n   %%!!>>\n   ```\n\n   On issuing an `rebase`, strings within `%%!!enable-usb-debug<<` and `%%!!>>`\n   will be extracted under the key `guide$aot$enable-usb-debug`.\n\n   Note that the start and end markers must be located in a separate line with\n   no additional spaces, similar to EOF markers.\n"
  },
  {
    "path": "docs/raw/en/appendices/app-ops.tex",
    "content": "% SPDX-License-Identifier: GPL-3.0-or-later OR CC-BY-SA-4.0\n\\chapter{App Ops}\\label{ch:app-ops}\n\n\\section{Background}\\label{sec:app-ops-background}\n\\textbf{App Ops} (short hand for \\textbf{Application Operations}) are used by Android system (since Android 4.3) to\ncontrol application permissions. The user \\emph{can} control some permissions, but only the permissions that are considered\ndangerous (and Google thinks knowing your phone number isn't a dangerous thing). So, app ops seems to be the one we need\nif we want to install apps like Facebook and it's Messenger (the latter literary records everything if you live outside\nthe EU) and still want \\emph{some} privacy and/or security. Although certain features of app ops were available in\nSettings and later in hidden settings in older version of Android, it's completely hidden in newer versions of Android\nand is continued to be kept hidden. Now, any app with \\textbf{android.Manifest.permission.GET\\_APP\\_OPS\\_STATS}\npermission can get the app ops information for other applications but this permission is hidden from users and can only\nbe enabled using ADB or root. Still, the app with this permission cannot grant or revoke permissions (actually mode of\noperation) for apps other than itself (with limited capacity, of course). To modify the ops of other app, the app needs\n\\textbf{android.Manifest.permission.UPDATE\\_APP\\_OPS\\_STATS} permissions which isn't accessible via \\texttt{pm} command.\nSo, you cannot grant it via root or ADB, the permission is only granted to the system apps. There are very few apps who\nsupport disabling permissions via app ops. The best one to my knowledge is\n\\href{https://github.com/8enet/AppOpsX}{AppOpsX}. The main (visible) difference between my app (AppManager) and this\napp is that the latter also provides you the ability to revoke internet permissions (by writing ip tables). One crucial\nproblem that I faced during the development of the app ops API is the lack of documentation in English language.\n\n\n\\section{Introduction to App Ops}\\label{sec:introduction-to-app-ops}\n\n\\begin{figure}[ht]\n    \\centering\n    \\includesvg[inkscapelatex=false, scale=0.6, keepaspectratio]{../images/appops.svg}\n    \\caption{How app ops work}\n    \\label{fig:appops}\n\\end{figure}\n\nFigure \\hyperref[fig:appops]{1} describes the process of changing and processing permission.\n\\hyperref[sec:appopsmanager]{AppOpsManager} can be used to manage permissions in Settings app. \\textbf{AppOpsManager} is\nalso useful in determining if a certain permission (or operation) is granted to the application. Most of the methods of\n\\textbf{AppOpsManager} are accessible to the user app but unlike a system app, it can only be used to check permissions\nfor any app or for the app itself and start or terminating certain operations. Moreover, not all operations are actually\naccessible from this Java class. \\textbf{AppOpsManager} holds all the necessary constants such as\n\\hyperref[subsec:op-constants]{\\texttt{OP\\_*}}, \\texttt{OPSTR\\_*}, \\hyperref[subsec:mode-constants]{\\texttt{MODE\\_*}}\nwhich describes operation code, operation string and mode of operations respectively. It also holds necessary data\nstructures such as \\hyperref[subsec:package-ops]{PackageOps} and \\textbf{OpEntry}. \\textbf{PackageOps} holds\n\\textbf{OpEntry} for a package, and \\textbf{OpEntry}, as the name suggests, describes each operation.\n\n\\texttt{AppOpService} is completely hidden from a user application but accessible to the system applications.\nAs it can be seen in Figure \\hyperref[fig:appops]{1}, this is the class that does the actual management stuff.\nIt contains data structures such as \\textbf{Ops} to store basic package info and \\textbf{Op} which is similar to\n\\textbf{OpEntry} of \\textbf{AppOpsManager}.\nIt also has \\textbf{Shell} which is actually the source code of the \\hyperref[sec:appops-cli]{\\textit{appops} command line tool}.\nIt writes configurations to or read configurations from \\hyperref[sec:appops-xml]{\\texttt{/data/system/appops.xml}}.\nSystem services calls \\textbf{AppOpsService} to find out what an application is allowed and what is not allowed to perform,\nand \\textbf{AppOpsService} determines these permissions by parsing \\texttt{/data/system/appops.xml}. If no custom values\nare present in \\textit{appops.xml}, it returns the default mode available in \\textbf{AppOpsManager}.\n\n\n\\section{AppOpsManager}\\label{sec:appopsmanager}\n\\href{https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/app/AppOpsManager.java}{AppOpsManager}\nstands for application operations manager. It consists of various constants and classes to modify app operations.\n\n\\seealsoinline{\\href{https://developer.android.com/reference/android/app/AppOpsManager}{AppOpsManager documentation}}\n\n\\subsection{\\texttt{OP\\_*} Constants}\\label{subsec:op-constants}\n\\texttt{OP\\_*} are the integer constants starting from \\texttt{0}. \\texttt{OP\\_NONE} implies that no operations are\nspecified whereas \\texttt{\\_NUM\\_OP} denotes the number of operations defined in \\texttt{OP\\_*} prefix. While they\ndenote each operation, the operations are not necessarily unique. In fact, there are many operations that are actually\na single operation denoted by multiple \\texttt{OP\\_*} constant (possibly for future use). Vendors may define their own\nop based on their requirements. MIUI is one of the vendors who are known to do that.\n\n\\begin{listing}[ht]\n    \\begin{minted}[frame=lines]{java}\npublic static final int OP_NONE = -1;\npublic static final int OP_COARSE_LOCATION = 0;\npublic static final int OP_FINE_LOCATION = 1;\npublic static final int OP_GPS = 2;\npublic static final int OP_VIBRATE = 3;\n...\npublic static final int OP_READ_DEVICE_IDENTIFIERS = 89;\npublic static final int OP_ACCESS_MEDIA_LOCATION = 90;\npublic static final int OP_ACTIVATE_PLATFORM_VPN = 91;\npublic static final int _NUM_OP = 92;\n    \\end{minted}\n    \\caption{Sneak-peek of \\texttt{OP\\_*}}\n    \\label{lst:op-constants}\n\\end{listing}\n\nWhether an operation is unique is defined by \\texttt{sOpToSwitch}.\nIt maps each operation to another operation or to itself (if it's a unique operation).\nFor instance, \\texttt{OP\\_FINE\\_LOCATION} and \\texttt{OP\\_GPS} are mapped to \\texttt{OP\\_COARSE\\_LOCATION}.\n\nEach operation has a private name which are described by \\texttt{sOpNames}.\nThese names are usually the same names as the constants without the \\texttt{OP\\_} prefix.\nSome operations have public names as well which are described by \\texttt{sOpToString}.\nFor instance, \\texttt{OP\\_COARSE\\_LOCATION} has the public name \\textbf{android:coarse\\_location}.\n\nAs a gradual process of moving permissions to app ops, there are already many permissions that are defined under some operations.\nThese permissions are mapped in \\texttt{sOpPerms}.\nFor example, the permission \\textbf{android.Manifest.permission.ACCESS\\_COARSE\\_LOCATION} is mapped to\n\\texttt{OP\\_COARSE\\_LOCATION}. Some operations may not have any associated permissions which have \\texttt{null} values.\n\nAs described in the previous section, operations that are configured for an app are stored at\n\\hyperref[sec:appops-xml]{\\texttt{/data/system/appops.xml}}.\nIf an operation is not configured, then whether system will allow that operation is determined from \\texttt{sOpDefaultMode}.\nIt lists the \\textit{default mode} for each operation.\n\n\\subsection{\\texttt{MODE\\_*} Constants}\\label{subsec:mode-constants}\n\\texttt{MODE\\_*} constants also integer constants starting from \\texttt{0}. These constants are assigned to each\noperation describing whether an app is authorised to perform that operation. These modes usually have associated names\nsuch as \\textbf{allow} for \\texttt{MODE\\_ALLOWED}, \\textbf{ignore} for \\texttt{MODE\\_IGNORED}, \\textbf{deny} for\n\\texttt{MODE\\_ERRORED} (a rather misnomer), \\textbf{default} for \\texttt{MODE\\_DEFAULT} and \\textbf{foreground}\nfor \\texttt{MODE\\_FOREGROUND}.\n\n\\begin{enumerate}\n    \\addtocounter{enumi}{-1}\n    \\item \\textbf{\\texttt{MODE\\_ALLOWED}.} The app is allowed to perform the given operation\n    \\item \\textbf{\\texttt{MODE\\_IGNORED}.} The app is not allowed to perform the given operation, and any attempt to\n    perform the operation should \\emph{silently fail}, i.e.\\ it should not cause the app to crash\n    \\item \\textbf{\\texttt{MODE\\_ERRORED}.} The app is not allowed to perform the given operation, and this attempt\n    should cause it to have a fatal error, typically a \\texttt{SecurityException}\n    \\item \\textbf{\\texttt{MODE\\_DEFAULT}.} The app should use its default security check, specified in \\texttt{AppOpsManager}\n    \\item \\textbf{\\texttt{MODE\\_FOREGROUND}.} Special mode that means ``allow only when app is in foreground.''\n    This mode was added in Android 10\n    \\item \\textbf{\\texttt{MODE\\_ASK}.} This is a custom mode used by MIUI whose uses are unknown.\n\\end{enumerate}\n\n\\subsection{PackageOps}\\label{subsec:package-ops}\n\\textbf{AppOpsManager.PackageOps} is a data structure to store all the \\textbf{OpEntry} for a package. In simple terms,\nit stores all the customised operations for a package.\n\n\\begin{listing}[H]\n    \\begin{minted}[frame=lines]{java}\npublic static class PackageOps implements Parcelable {\n    private final String mPackageName;\n    private final int mUid;\n    private final List<OpEntry> mEntries;\n    ...\n}\n    \\end{minted}\n    \\caption{Class \\texttt{PackageOps}}\n    \\label{lst:package-ops-class}\n\\end{listing}\n\nAs can be seen in Listing \\hyperref[lst:package-ops-class]{2}, it stores all \\textbf{OpEntry} for a package as well as the\ncorresponding package name and its kernel user ID\\@.\n\n\\subsection{OpEntry}\\label{subsec:opentry}\n\\textbf{AppOpsManager.OpEntry} is a data structure that stores a single operation for any package.\n\n\\begin{listing}[H]\n    \\begin{minted}[frame=lines]{java}\npublic static final class OpEntry implements Parcelable {\n    private final int mOp;\n    private final boolean mRunning;\n    private final @Mode int mMode;\n    private final @Nullable LongSparseLongArray mAccessTimes;\n    private final @Nullable LongSparseLongArray mRejectTimes;\n    private final @Nullable LongSparseLongArray mDurations;\n    private final @Nullable LongSparseLongArray mProxyUids;\n    private final @Nullable LongSparseArray<String> mProxyPackageNames;\n    ...\n}\n    \\end{minted}\n    \\caption{Class \\texttt{OpEntry}}\n    \\label{lst:class-op-entry}\n\\end{listing}\nHere:\n\\begin{itemize}\n    \\item \\texttt{mOp}: Denotes one of the \\hyperref[subsec:op-constants]{\\texttt{OP\\_*} constants}\n    \\item \\texttt{mRunning}: Whether the operation is in progress (i.e.\\ the operation has started but not finished\n    yet). Not all operations can be started or finished this way\n    \\item \\texttt{mMOde}: One of the \\hyperref[subsec:mode-constants]{\\texttt{MODE\\_*} constants}\n    \\item \\texttt{mAccessTimes}: Stores all the available access times\n    \\item \\texttt{mRejectTimes}: Stores all the available reject times\n    \\item \\texttt{mDurations}: All available access durations, checking this with \\texttt{mRunning} will tell you for\n    how long the app is performing a certain app operation\n    \\item \\texttt{mProxyUids}: No documentation found\n    \\item \\texttt{mProxyPackageNames:} No documentation found\n\\end{itemize}\n\n\\subsection{Usage}\\label{subsec:usage}\nTODO\n\n\n\\section{AppOpsService}\\label{sec:appopsservice}\nTODO\n\n\n\\section{appops.xml}\\label{sec:appops-xml}\nLatest \\texttt{appops.xml} has the following format: (This DTD is made by me and by no means perfect, has compatibility issues.)\n\n\\begin{Verbatim}\n<!DOCTYPE app-ops [\n\n<!ELEMENT app-ops (uid|pkg)*>\n<!ATTLIST app-ops v CDATA #IMPLIED>\n\n<!ELEMENT uid (op)*>\n<!ATTLIST uid n CDATA #REQUIRED>\n\n<!ELEMENT pkg (uid)*>\n<!ATTLIST pkg n CDATA #REQUIRED>\n\n<!ELEMENT uid (op)*>\n<!ATTLIST uid\nn CDATA #REQUIRED\np CDATA #IMPLIED>\n\n<!ELEMENT op (st)*>\n<!ATTLIST op\nn CDATA #REQUIRED\nm CDATA #REQUIRED>\n\n<!ELEMENT st EMPTY>\n<!ATTLIST st\nn CDATA #REQUIRED\nt CDATA #IMPLIED\nr CDATA #IMPLIED\nd CDATA #IMPLIED\npp CDATA #IMPLIED\npu CDATA #IMPLIED>\n\n]>\n\\end{Verbatim}\nThe instruction below follows the exact order given above:\n\\begin{itemize}\n    \\item \\texttt{app-ops}: The root element. It can contain any number of \\texttt{pkg} or package \\texttt{uid}\n    \\begin{itemize}\n        \\item \\texttt{v}: (optional, integer) The version number (default: \\texttt{NO\\_VERSION} or \\texttt{-1})\n    \\end{itemize}\n\n    \\item \\texttt{pkg}: Stores package info. It can contain any number of \\texttt{uid}\n    \\begin{itemize}\n        \\item \\texttt{n}: (required, string) Name of the package\n    \\end{itemize}\n\n    \\item Package \\texttt{uid}: Stores package or packages info\n    \\begin{itemize}\n        \\item \\texttt{n}: (required, integer) The user ID\n    \\end{itemize}\n\n    \\item \\texttt{uid}: The package user ID. It can contain any number of \\texttt{op}\n    \\begin{itemize}\n        \\item \\texttt{n}: (required, integer) The user ID\n        \\item \\texttt{p}: (optional, boolean) Is the app is a private/system app\n    \\end{itemize}\n\n    \\item \\texttt{op}: The operation, can contain \\texttt{st} or nothing at all\n    \\begin{itemize}\n        \\item \\texttt{n}: (required, integer) The op name in integer, i.e.\\ AppOpsManager.OP\\_*\n        \\item \\texttt{m}: (required, integer) The op mode, i.e.\\ AppOpsManager.MODE\\_*\n    \\end{itemize}\n\n    \\item \\texttt{st}: State of operation: whether the operation is accessed, rejected or running (not available on old versions)\n    \\begin{itemize}\n        \\item \\texttt{n}: (required, long) Key containing flags and uid\n        \\item \\texttt{t}: (optional, long) Access time (default: \\texttt{0})\n        \\item \\texttt{r}: (optional, long) Reject time (default: \\texttt{0})\n        \\item \\texttt{d}: (optional, long) Access duration (default: \\texttt{0})\n        \\item \\texttt{pp}: (optional, string) Proxy package name\n        \\item \\texttt{pu}: (optional, integer) Proxy package uid\n    \\end{itemize}\n\\end{itemize}\n\nThis definition can be found at\n\\href{https://android.googlesource.com/platform/frameworks/base/+/master/services/core/java/com/android/server/appop/AppOpsService.java}{AppOpsService}.\n\n\n\\section{Command Line Interface}\\label{sec:appops-cli}\n\\texttt{appops} or \\texttt{cmd appops} (on latest versions) can be accessible via ADB or root. This is an easier method\nto get or update any operation for a package (provided the package name is known). The help page of this command is\nself-explanatory:\n\\begin{Verbatim}\nAppOps service (appops) commands:\nhelp\nPrint this help text.\nstart [--user <USER_ID>] <PACKAGE | UID> <OP>\nStarts a given operation for a particular application.\nstop [--user <USER_ID>] <PACKAGE | UID> <OP>\nStops a given operation for a particular application.\nset [--user <USER_ID>] <[--uid] PACKAGE | UID> <OP> <MODE>\nSet the mode for a particular application and operation.\nget [--user <USER_ID>] <PACKAGE | UID> [<OP>]\nReturn the mode for a particular application and optional operation.\nquery-op [--user <USER_ID>] <OP> [<MODE>]\nPrint all packages that currently have the given op in the given mode.\nreset [--user <USER_ID>] [<PACKAGE>]\nReset the given application or all applications to default modes.\nwrite-settings\nImmediately write pending changes to storage.\nread-settings\nRead the last written settings, replacing current state in RAM.\noptions:\n<PACKAGE> an Android package name or its UID if prefixed by --uid\n<OP>      an AppOps operation.\n<MODE>    one of allow, ignore, deny, or default\n<USER_ID> the user id under which the package is installed. If --user is not\nspecified, the current user is assumed.\n\\end{Verbatim}\n"
  },
  {
    "path": "docs/raw/en/appendices/changelogs.tex",
    "content": "% SPDX-License-Identifier: GPL-3.0-or-later OR CC-BY-SA-4.0\n\\chapter{Changelogs}\\label{ch:changelogs} %%##$chapter-title>>\n\n\\section{v4.0.5 (445)}\\label{sec:v4.0.5-(445)}\n\\begin{itemize}\n    \\item Added option to allow installing the existing applications in the installer page\n    \\item Display unsafe bloatware info\n    \\item Display vector icon on the splash screen in Android 7.1 and earlier\n    \\item Enabled ``Clear data from uninstalled apps'' to no-root users in 1-click ops page\n    \\item Enabled predictive back in Android 14 onwards\n    \\item Improved accessibility by updating the content description of the action items\n    \\item In app info tab, open ``Open by default'' setting in the ``Open links'' dialog\n    \\item In debloater page, sort by app label (or app name) rather than package name\n    \\item Fixed freezing an app with ``Remember for this app'' turned on\n    \\item Fixed selecting texts in the list items due to framework bugs\n    \\item Fixed setting app ops in custom ROMs with MIUI properties injected\n    \\item Fixed updating profile modification status when an application is deleted from the list\n    \\item Handled common colors and cursor movements in terminal output.\n\\end{itemize}\n\n\\section{v4.0.4 (444)}\\label{sec:v4.0.4-(444)}\n\\begin{itemize}\n    \\item Optimized searching and filtering in the main page\n    \\item Adopted sentence-case for the titles\n    \\item Use the configured state to execute a profile for the simple shortcuts\n    \\item Prevented crashing while searching throughout the application\n    \\item Fixed integer overflow issue in the tar compression.\n\\end{itemize}\n\n\\section{v4.0.3 (443)}\\label{sec:v4.0.3-(443)}\n\\begin{itemize}\n    \\item Updated translations\n    \\item Improved handling the list items throughout App Manager\n    \\item Fixed a regression error in file manager\n    \\item Fixed spinners in the App Usage and the System Config pages.\n\\end{itemize}\n\n\\section{v4.0.2 (442)}\\label{sec:v4.0.2-(442)}\n\\begin{itemize}\n    \\item Updated bloatware\n    \\item Fixed fetching applications in multi-user environment in no-root mode\n    \\item Fixed opening \\texttt{app-manager} URLs from the web browsers\n    \\item Fixed updating SSAID\n    \\item Prevented a crash in Android < 9.0 that occurs due to invalid app ops.\n\\end{itemize}\n\n\\section{v4.0.1 (441)}\\label{sec:v4.0.1-(441)}\n\\subsection{Overlay management}\nIn the App Details page, a new tab ``Overlays'' is added where per-app overlays are displayed. They\ncan also be enabled or disabled using the toggle button. In addition, if the App Details page of an\noverlay package is opened, a ``Overlay'' tag will be displayed in the App Info tab. Clicking on the\ntag opens a dialog containing additional info along with a button that allows navigating to the\nApp Details page of the overlay target package if it is installed.\n\n\\paragraph{Known limitation} At present, it only works for root/ADB users in Android 8 (Oreo) and\nlater.\n\n\\subsection{Unfreeze option in activity shortcuts}\nIf the application corresponding to the shortcut being launched is frozen, App Manager will now\noffer you to unfreeze the app temporarily so that the shortcut can be launched. The app will be\nfrozen again once the screen is locked.\n\n\\paragraph{Known limitation} This may not work on devices without a screen lock or if the screen is\nlocked some time after the display goes off.\n\n\\subsection{\\texttt{market}-like URL support}\nThird-party applications can now open the App Details page of any installed package by invoking an\nIntent with an URL with the following format:\n\n\\begin{verbatim}\napp-manager://details?id=<pkg>&user=<user_id>\n\\end{verbatim}\n\nwhere \\texttt{<pkg>} stands for package name, and \\texttt{<user\\_id>} stands for the user ID which\nis optional.\n\n\\subsection{Updated color codes}\nIn order to improve accessibility, certain color codes have been improved. Visit\n\\href{app-manager://settings/about/version}{Settings > About > Version/Changelog} for details.\n\n\\subsection{Others}\n\\begin{itemize}\n    \\item Avoided waiting for the remote server to respond when no-root mode is set\n    \\item Fixed downgrading apps in Android 10 onwards\n    \\item Fixed installer issues in the Huawei stock operating systems\n    \\item Improved text formatting in the ``What's New'' dialog\n    \\item In the UI tracker window, fixed clicking on the icon after it is iconified\n    \\item Updated bloatware and suggestions\n\\end{itemize}\n\n\\section{v4.0.0 (440)}\\label{sec:v4.0.0-(440)}\n\nApp Manager v4.0.0 comes with a lot of new features and improvements. Visit\n\\href{app-manager://settings/about/version}{Settings > About > Version/Changelog} for details.\n\n\\subsection{New logo!}\nThe new logo is just a cursive ``A''. The design is based on the\n\\href{https://freetengwar.sourceforge.net/}{Tengwar Telcontar} font which was created to bring the\nTengwar script, originally created by J. R. R. Tolkien, to the digital world. The letter has the\nclassic App Manager color (i.e., \\#dcaf74) and uses a pure black background instead of a shade of\ngrey.\n\n\\subsection{Android 14 and 15 support}\nApp Manager now targets Android 14 and fully supports Android 15.\n\n\\paragraph{Known issue} KeyStore backup/restore is not working in Android 12 and later.\n\n\\subsection{Revamped debloater}\nDebloating profiles were available as ``Presets'' in the Profiles page which has now been replaced\nwith the Debloater page and can be accessed from the three-dots menu in the Main page.\n\\href{https://github.com/MuntashirAkon/android-debloat-list}{ADL} is a new project that focuses on\nmaintaining a list of bloatware as well as potential open source alternatives. Contributions are\nwelcome!\n\n\\subsection{Introducing file manager}\nApp Manager offers an (almost) fully-featured file manager with basic file operations, such as copy,\ncut, rename, and delete along with the batch operations. It also offers an extensive ``Open with\\dots''\ndialog to open a file with another app, and a comprehensive file properties viewer. Folders can also\nbe added to the list of favorites for quick access. And many more.\n\n\\subsection{Integrated code editor}\nManifest and code viewers have been replaced with this new editor. Among other regular features, it\nincludes proper syntax highlighting and advanced searching options. In addition, files from\nthird-party apps can also be opened for editing.\n\n\\subsection{History of operations}\nAll 1-click operations, batch operations, and profile invocations are now stored as history. The\nhistory items can also be executed from the History page. To ensure consistency, the profile state,\nconfigurations, package list are also stored, and this stored version is executed instead of the\nactual profile. As a result, this works even if the profile is deleted.\n\n\\subsection{Per-app freezing, and more}\nFreeze/unfreeze feature now supports setting per-app freezing method which is beneficial in certain\nscenarios, such as when a user want to suspend some apps while using the disable method as the\ndefault. In addition, an ``Advanced suspend'' option is added which force-stops an application\nbefore suspending it, thus, prevent it's services from running in the background.\n\n\\subsection{Log viewer enhancements}\nLog viewer now supports enhanced searching and filtering options, such as keyword- and regular\nexpression-based searching and filtering. Please read the in-app changelog for details. Support for\nbatch operations has also been added.\n\n\\subsection{Launching non-exported activities}\nApp Manager now supports launching non-exported activities in no-root and ADB mode. However, in\nno-root mode, \\texttt{android.permission.WRITE\\_SECURE\\_SETTINGS} permission is required.\n\n\\subsection{New tags in App Info tab}\nFive new tags are added in the App Info tab. They are: bloatware, Xposed, sensors disabled, open\nlinks, and static shared libs. Clicking on ``bloatware'' will display more information regarding\nthe bloatware and suggest alternatives, ``Xposed'' tag will display dependency information, ``open\nlinks'' will display a list of links supported by the application, and ``static shared libs'' will\ndisplay all version of the application installed in the system along with an option to uninstall\nthem. The latter is useful for applications, such as Trichrome.\n\n\\paragraph{Known issue} ``Sensors disabled'' only works real-time. That means if the application is\nnot currently active, this tag will always display even though the applications may use sensors\nwhile it is running. This is a framework limitation and nothing can be done to avoid it effectively.\n\n\\subsection{Per-session installer options}\nIt is not possible to modify installer options during the installation by clicking on the ``settings''\nbutton in the installation dialog. The installer options will be applied to all the applications\ninstalled in the same session (i.e., the installer queue).\n\n\\subsection{Advanced mode of operations, ADB enhancements, \\dots}\nApp Manager now supports running its remote server (which is used as a proxy for running privileged\noperations) as any supported user (UID). This includes root (0), system (1000), and shell/ADB (2000)\nthrough the custom commands. This is also useful for Fire TVs which have disabled connecting to ADB\nfrom localhost through socket connection. In addition, ADB pairing is now done using notifications\nrather than split screen. ADB connection speed can also be improved by choosing to run App Manager\nin the background which can be configured in the settings.\n\n\\subsection{Data usage widget, and more}\nData usage widget display the total data usage for the day, similar to the screen time widget which\ndisplays the total screen time for the day. In addition, existing widgets have been improved.\n\n\\subsection{Others}\n\\begin{itemize}\n    \\item Replaced log viewer, sys config, Terminal, etc. with Labs page\n    \\item Added an option to disable sensors for each app in the App Info tab\n    \\item Added an option to perform runtime optimization of applications in the 1-click Ops page\n    and in the App Info tab\n    \\item Added support for Zstandard compression for backup/restore\n    \\item Enabling APK signing now automatically enables zip align feature\n    \\item Support exporting application list as CSV or JSON in the batch operations\n    \\item Added pure black theme support\n    \\item Display current activity name (when possible) in the UI Tracker window\n    \\item Added an option to filter apps by user in the Main page\n    \\item Display a link to Pithus report in the scanner page if available.\n\\end{itemize}\n\n\n\\section{v3.1.0 (423)}\\label{sec:v3.1.0-(423)}\n\nApp Manager v3.1.0 comes with a few new features and a lot of improvements.\nVisit \\href{app-manager://settings/about/version}{Settings > About > Version/Changelog} for details.\n\n\\subsection{Android 13 support}\nApp Manager now targets Android 13 which means most issues in Android 12 and 13 has been addressed, including SSAID and SAF issues as well as monochrome icons and other theming issues.\n\n\\paragraph{Known issue} KeyStore backup/restore not working in Android 12 and later.\n\n\\subsection{Introducing freeze/unfreeze}\nEnable/disable is replaced with freeze/unfreeze to allow greater control on the behaviours of an app.\nIt supports suspend, disable and hide functionalities which can be controlled at\n\\href{app-manager://settings/rules_prefs/freeze_type}{Settings > Rules > Default freezing method}.\nIn order to make it easy to freeze or unfreeze an app, shortcuts can also be created from the App Info tab by long clicking on the freeze or unfreeze button.\n\n\\subsection{Export app list}\nIn the Main page, it is now possible to export the list of apps in either XML or Markdown format using batch operations.\nIn the future, the XML file may also be imported to App Manager.\n\n\\subsection{Elliptic Curve Crypography (ECC)}\nApp Manager now fully supports encrypting backups using ECC in addition to offering AES, RSA and OpenPGP\\@.\n\n\\subsection{New languages}\nTwo new languages are added: Korean and Romanian.\n\n\\subsection{More list options}\nIn the main page, more sorting and filtering options are added. Sorting options include sorting the apps by total size,\ntotal data usage, launch count, screen time and last usage time. Filtering options include filtering the apps having\nat least one item in the Android KeyStore, filtering apps with URIs granted via SAF, and filtering apps with SSAID\\@.\n\n\\subsection{Improved handling of mode of operation}\nFixed various issues with ADB pairing, handled incomplete USB debugging. Some rooting methods cannot allow interprocess\ncommunication via Binder. In those cases, ADB mode is used as a fallback method by enabling it automatically if possible.\n\n\\subsection{Handling multiple users}\nWhen possible, App Manager will be able to display apps from work profile in no-root mode in addition to allowing basic operations such as launching the app or navigating to the system settings.\nFor backups, it is now possible to restore backups for other users, but for work profile, some apps may only work properly after re-enabling the work profile.\nIn the installer page, selecting \\textit{All users} will now install the app for all users instead of only the current user.\nFinally, in the app info tab, current app can be installed in another profile using the \\textit{Install for\\dots} option available in the three-dots menu.\nThis is analogous to the \\texttt{pm install-existing} command, thereby, making the installation process a lot faster.\n\n\\subsection{Explorer enhancements}\nExplorer can now open DEX and JAR files in addition to APK files. Several sorting options as well as folder options are also added as the list options.\n\n\\subsection{New tag: WX}\nIn app info tab, a new tag called WX is added. It is displayed in Android 10 and later if the application targets\nAndroid 9 or earlier. It indicates \\href{https://en.wikipedia.org/wiki/W\\%5EX}{W\\^{}X} violation which allows the app to execute arbitrary executable files either by the modification of executables embedded within the app or by downloading them from the Internet.\n\n\\subsection{App ops management}\nApp ops are now managed automatically to avoid various app ops related crashes in various platforms.\nThis will also lessen the amount of crashes in an unsupported operating system.\n\n\\subsection{Batch uninstallation}\nIn the Main page, enabled batch uninstallation in no-root mode.\n\n\\subsection{Running apps}\nEnabled advanced searching. Searching now matches not only app labels but also package names.\n\n\\subsection{Interceptor}\nCopy the intercepted Intent as am command which can be run from either an ADB shell or a terminal using root with the same effectiveness.\n\n\\subsection{Device-specific changes}\n\\paragraph{Graphene OS} Explicitly handle the Internet permission which is a runtime permission in the OS.\n\\paragraph{MIUI} Fixed permission denied issues in the installer due to a framework issue introduced in MIUI 12.5.\n\\paragraph{Motorola} Fixed crashes in the Interceptor page due to a framework issue introduced in Android 11.\n\n\\subsection{Others}\n\\begin{itemize}\n    \\item Improved Java-Smali conversion by including all the subclasses during conversion\n    \\item Improved scanning performance in the Scanner page\n    \\item Improved updating the list of apps in the Main page\n    \\item Scan all the available paths to detect systemless-ly installed system apps\n    \\item \\texttt{vacuum} SQLite database before opening it for viewing or editing.\n\\end{itemize}\n\n\\section{v3.0.0 (410)}\\label{sec:v3.0.0-(410)}\n\nApp Manager v3.0.0 comes with a lot of features and improvements.\nSee \\href{app-manager://settings/about/version}{Settings > About > Version/Changelog} to see a more detailed changelog.\n\n\\subsection{Material 3 and More}\nMaterial 3, somewhat similar to \\textit{Material You}, is a significant improvement over Material Design 2 with support for dynamic colours in Android 12 and later.\nIn addition, many design changes have been made in App Manager without any significant changes in the overall user experience.\n\n\\paragraph{Known issue} Switches are still based on Material Design 2 which will be fixed in a future release.\n\n\\subsection{Wireless Debugging}\nWireless debugging support has been fully implemented. Head over to \\Sref{sec:wireless-debugging} for instructions on how to configure wireless debugging.\n\n\\begin{tip}{No-root users}\n    Due to auto-detection feature, startup time might be large for no-root users when the mode of operation is set to \\textit{auto}.\n    Instead, no-root users should select \\textit{no-root} instead of \\textit{auto}.\n\\end{tip}\n\n\\subsection{Languages}\nApp Manager is fully translated into Indonesian and Italian languages and can be enabled in settings. Bengali is removed due to lack of translators.\n\n\\subsection{Introducing App Explorer}\nApp Explorer can be used to browse the contents of an application. This includes binary XML files, DEX contents or any other media files.\nDEX contents can only be explored in Android Oreo (Android 8) and later. It's also possible to convert an \\texttt{.smali} file into \\texttt{.java} for a better understanding of the reversed code.\nThis feature, if not needed, can be disabled in Settings > Enable/disable features.\n\n\\subsection{Import Backups from Other Applications}\nIt is possible to import backups from discontinued or obsolete applications such as Titanium Backup, OAndBackup and Swift Backup (version 3.0 to 3.2).\nGo to Setting > Backup/restore to find this option.\n\n\\subsection{VirusTotal}\nVirusTotal is a widely used tool to scan files and URLs for viruses. In the scanner page and in the running apps page, an option to scan files with VirusTotal has been added.\nBut the option is hidden by default. To enable the option, it is necessary to obtain an API key from VirusTotal. Go to Settings > VirusTotal API Key for more information.\n\n\\begin{warning}{Internet feature}\n    This is currently the only feature which require an Internet connection. If you wish to use any Internet feature that might also be added in the future,\n    enable \\textit{Use the Internet} in Settings > Enable/disable features.\n\\end{warning}\n\n\\subsection{Trigger Profiles from the Automation Software}\nAs the implementation of routine operations is being delayed, an option to trigger profiles from the external automation software is added.\nSee \\Sref{sec:automating-tasks} for instructions on how to configure profile automation.\n\n\\subsection{Improved Application Installer}\nApplication installer includes several improvements including the ability to downgrade applications in no-root mode, installing multiple applications at once and blocking trackers after installation.\nIn Android 12 and later, no-root users can update applications without any user interactions.\n\n\\subsection{Component Blocking}\nIt is now possible to configure how App Manager should block a component. Visit Settings > Rules > Default blocking method for more information.\nIn the components tab, long clicking the block/unblock button opens a context menu which allows per-component blocking in a similar manner.\nADB users can also block the components of a \\textit{Test only} app.\n\n\\subsection{Advanced Searching}\nIn some pages, the search bar supports additional searching which includes searching via prefix, suffix or even regular expressions.\nIn the main page, it is also possible to search for applications using the first letters of each word, e.g.\\ \\textit{App Manager} can be listed by searching for \\textit{am}.\n\n\\subsection{Shared Libraries}\nShared libraries tab has received a significant improvements. It can display three types of libraries, such as native, jar and APK files.\n\n\\subsection{Make the Best Use of Interceptor}\nActivity interceptor can be opened directly from the activities tab by long clicking on the launch button, and similarly, activities can be launched from the activity interceptor page with or without root, for any users.\n\n\\begin{tip}{Notice}\n    Currently, activities opened via root cannot send the results back to the original applications.\n\\end{tip}\n\n\\subsection{Widget: Screen Time}\nScreen time widget is quite similar to Digital Wellbeing's widget by the same name.\nIt displays the total screen time for the day along with the top three apps from all users.\n\n\\subsection{Widget: Clear Cache}\nClear cache widget can be to clear cache from all the applications directly from the home screen.\n\n\n\\section{v2.6.0 (385)}\\label{sec:v2.6.0-(385)}\n\n\\subsection{Introducing Backups}\nBack up/restore feature is now finally out of beta!\nRead \\hyperref[sec:backup-restore]{the corresponding guide} to understand how it works.\n\n\\subsection{Introducing Log Viewer}\n\\hyperref[subsubsec:log-viewer]{Log viewer} is essentially a front-end for \\texttt{logcat}.\nIt can be used to filter logs by \\textit{tag} or \\textit{pid} (process ID), or even by custom filters.\nLog levels AKA verbosity can also be configured.\nYou can also save, share and manage logs.\n\n\\subsection{Lock App Manager}\n\\hyperref[subsubsec:screen-lock]{Lock App Manager} with the screen lock configured for your device.\n\n\\subsection{Extended Modes for App Ops}\nYou can set any mode for any app ops that your device supports, either from the\n\\hyperref[subsec:set-mode-for-app-ops-dots]{1-click ops page} or from the \\hyperref[subsubsec:app-ops]{app ops tab}.\n\n\\subsection{New Batch Ops: Add to Profile}\nYou can now easily add selected apps to an existing profile using the batch operations.\n\n\\subsection{App Info: Improved}\nApp info tab now has many options, including the ability to change \\hyperref[sec:terminologies]{SSAID}, network policy\n(i.e.\\ background network usage), battery optimization, etc.\nMost of the tags used in this tab are also clickable, and if you click on them, you will be able to look at the current\nstate or configure them right away.\n\n\\subsection{Advanced Sort and Filtering Options in the Main Page}\nSort and filter options are now replaced by \\hyperref[subsubsec:main-list-options]{List Options} which is highly configurable,\nincluding the ability to filter using profiles.\n\n\\subsection{About This Device}\nInterested in knowing about your device in just one page?\nGo to the bottom of the \\hyperref[subsec:device-info]{settings page}.\n\n\\subsection{Enable/disable Features}\nNot interested in all the features that AM offers?\nYou can disable some features in \\hyperref[subsubsec:enable/disable-features]{settings}.\n\n\\subsection{New Languages}\nAM now has more than 19 languages!\nNew languages include Farsi, Japanese and Traditional Chinese.\n\n\\subsection{Signing the APK Files}\nYou can now import external signing keys in AM! For security, App Manager has its own encrypted KeyStore which can also be \\hyperref[subsubsec:import/export-keystore]{imported or exported}.\n\n\\subsection{New Extension: UnAPKM}\nSince APKMirror has removed encryption from their APKM files, it's no longer necessary to decrypt them.\nAs a result, the option to decrypt APKM files has been removed.\nInstead, this option is now provided by the UnAPKM extension which you can grab from \\href{https://f-droid.org/packages/io.github.muntashirakon.unapkm/}{F-Droid}.\nSo, if you have an encrypted APKM file and have this extension installed, you can open the file directly in AM\\@.\n\n\n\\section{v2.5.20 (375)}\\label{sec:v2.5.20-(375)}\n\n\\subsection{Introducing Profiles}\\label{subsec:introducing-profiles}\n\\hyperref[sec:profile-page]{Profiles} finally closes the\n\\href{https://github.com/MuntashirAkon/AppManager/issues/72}{related issue}. Profiles can be used to execute certain\ntasks repeatedly without doing everything manually. A profile can be applied (or invoked) either from the\n\\hyperref[sec:profiles-page]{Profiles page} or from the home screen by creating shortcuts. There are also some presets\nwhich consist of debloating profiles taken from\n\\href{https://gitlab.com/W1nst0n/universal-android-debloater}{Universal Android Debloater}.\n\n\\paragraph{Known limitations}\n\\begin{itemize}\n    \\item Exporting rules and applying permissions are not currently working.\n    \\item Profiles are applied for all users.\n\\end{itemize}\n\n\\subsection{The Interceptor}\\label{subsec:the-interceptor}\n\\href{https://github.com/MuntashirAkon/intent-intercept}{Intent Intercept} works as a man-in-the-middle between source\nand destination, that is, when you open a file or URL with another app, you can see what is being shared by opening it\nwith Interceptor first. You can also add or modify the intents before sending them to the destination. Additionally,\nyou can double-click on any exportable activities in the Activities tab in the App Details page to open them in the\nInterceptor to add more configurations.\n\n\\paragraph{Known limitation} Editing extras is not currently possible.\n\n\\subsection{UnAPKM: DeDRM the APKM files}\\label{subsec:unapkm:-dedrm-the-apkm-files}\nWhen I released a small tool called \\href{https://f-droid.org/en/packages/io.github.muntashirakon.unapkm}{UnAPKM},\nI promised that similar feature will be available in App Manager. I am proud to announce that you can open APKM files\ndirectly in the App Info page or convert them to APKS or install them directly.\n\n\\subsection{Multiple user}\\label{subsec:multiple-user}\nApp manager now supports multiple users! For now, this requires root or ADB. But no-root support is also being\nconsidered. If you have multiple users enabled and click on an app installed in multiple profiles, an alert prompt will\nbe displayed where you can select the user.\n\n\\subsection{Vive la France!}\nThanks to the contributors, we have one more addition to the language club: French. You can add more languages or\nimprove existing translations at \\href{https://hosted.weblate.org/engage/app-manager}{Weblate}.\n\n\\subsection{Report crashes}\nIf App Manager crashes, you can now easily report the crash from the notifications which opens the share options.\nCrashes are not reported by App Manager, it only redirects you to your favourite Email client.\n\n\\subsection{Android 11}\nAdded support for Android 11. Not everything may work as expected though.\n\n\\subsection{App Installer Improvements}\n\n\\subsubsection{Set installation locations}\nIn settings page, you can set install locations such as auto (default), internal only and prefer external.\n\n\\subsubsection{Set APK installer}\nIn settings page, you can also set default APK installer (root/ADB only) instead of App Manager.\n\n\\subsubsection{Multiple users}\nIn settings page, you can allow App Manager to display multiple users during APK installation.\n\n\\subsubsection{Signing APK files}\nIn settings page, you can choose to sign APK files before installing them. You can also select which signature scheme\nto use in the \\textit{APK signing} option in settings.\n\n\\paragraph{Known limitation} Currently, only a generic key is used to sign APK files\n\n\n\\section{v2.5.17 (368)}\n\n\\subsection{App Installer}\nAs promised, it is now possible to select splits. AM also provides recommendations based on device configurations.\nIf the app is already installed, recommendations are provided based on the installed app. It is also possible to\ndowngrade to a lower version without data loss if the device has root or ADB. But it should be noted that not all app\ncan be downgraded. Installer is also improved to speed up the installation process, especially, for root users.\nIf the app has already been installed and the new (x)apk(s) is newer or older or the same version with a different\nsignature, AM will display a list of changes similar to \\textbf{What's New} before prompting the user to install\nthe app. This is useful if the app has introduced tracker components, new permissions, etc.\n\n\\paragraph{Known Limitations}\n\\begin{itemize}\n    \\item Large app can take a long time to fetch app info, and therefore, it may take a long time display the installation prompt.\n    \\item If the apk is not located in the internal storage, the app has to be cached first which might also take\n    a long time depending on the size of the apk.\n\\end{itemize}\n\n\\subsection{Scanner: Replacement for Exodus Page}\nExodus page is now replaced with scanner page. \\hyperref[sec:scanner-page]{Scanner page} contains not only a list of\ntrackers but also a list of used libraries. This is just a start. In the future, this page will contain more in depth\nanalysis of the app.\n\n\\subsection{Introducing System Config}\nSystem Config lists various system configurations and whitelists/blacklists included in Android by either OEM/vendor,\nAOSP or even some Magisk modules. Root users can access this option from the overflow menu in the main page.\nThere isn't any official documentation for these options therefore it's difficult to write a complete documentation\nfor this page. I will gradually add documentations using my own knowledge. However, some functions should be\nunderstandable by their name.\n\n\\subsection{More Languages}\nThanks to the contributors, AM now has more than 12 languages. New languages include Bengali, Hindi, Norwegian, Polish,\nRussian, Simplified Chinese, Turkish and Ukrainian.\n\n\\subsection{App Info Tab}\nMore tags are added in the \\hyperref[subsec:app-info-tab]{app info tab} such as \\textbf{KeyStore} (apps with KeyStore\nitems), \\textbf{Systemless app} (apps installed via Magisk), \\textbf{Running} (apps that are running). For external apk,\ntwo more options are added namely \\textbf{Reinstall} and \\textbf{Downgrade}. Now it is possible to share an apk via\nBluetooth. For system apps, it is possible to uninstall updates for root/ADB users. But like the similar option in the\nsystem settings, this operation will clear all app data. As stated above, exodus has been replaced with scanner.\n\n\\subsection{Navigation Improvements}\nIt's now relatively easy to navigate to various UI components using keyboard. You can use up/down button to navigate\nbetween list items and tab button to navigate to UI components inside an item.\n\n\\subsection{Running Apps Page}\nIt is now possible to sort and filter processes in this tab. Also, the three big buttons are replaced with an\neasy-to-use three dot menu. Previously the memory usage was wrong which is fixed in this version.\n\n\\subsection{Built-in Toybox}\nToybox (an alternative to busybox) is bundled with AM. Although Android has this utility built-in from API 23, toybox\nis bundled in order to prevent buggy implementations and to support API < 23.\n\n\\subsection{Component Blocker Improvements}\nComponent blocker seemed to be problematic in the previous version, especially when global component blocking is enabled.\nThe issues are mostly fixed now.\n\n\\begin{warning}{Caution}\n    The component blocking mechanism is no longer compatible with v2.5.6 due to various security issues. If you have\n    this version, upgrade to v2.5.13 or earlier versions first. After that, enable\n    \\hyperref[subsubsec:instant-component-blocking]{global component blocking} and disable it again.\n\\end{warning}\n\n\\subsection{Improvements in the App Details Page}\nValue of various app ops depend on their parent app ops. Therefore, when you allow/deny an app op, the parent of the app\nop gets modified. This fixes the issues some users have been complaining regarding some app ops that couldn't be changed.\n\nIf an app has the target API 23 or less, its permissions cannot be modified using the \\texttt{pm grant \\ldots} command.\nTherefore, for such apps, option to toggle permission has been disabled.\n\nThe signature tab is improved to support localization. It also displays multiple checksums for a signature.\n\n\\subsection{App Manifest}\nManifest no longer crashes if the size of the manifest is too long. Generated manifest are now more accurate than before.\n\n\n\\section{v2.5.13 (348)}\n\n\\subsection{Bundled App (Split APK)}\nBundled app formats such as \\textbf{apks} and \\textbf{xapk} are now supported. You can install these apps using\nthe regular installation buttons. For root and adb users, apps are installed using shell, and for non-root users,\nthe platform default method is used.\n\n\\paragraph{Known Limitations}\n\\begin{itemize}\n    \\item Currently \\textit{all} splits apks are installed. But this behaviour is going to change in the next release.\n    If you only need a few splits instead of all, extract the \\textbf{APKS} or \\textbf{XAPK} file, and then, create a new zip\n    file with your desired split apks and replace the \\textbf{ZIP} extension with \\textbf{APKS}. Now, open it with AM\\@.\n    \\item There is no progress dialog to display the installation progress.\n\\end{itemize}\n\n\\subsection{Direct Install Support}\nYou can now install \\textbf{APK}, \\textbf{APKS} or \\textbf{XAPK} directly from your favourite browser or file manager.\nFor apps that need updates, a \\textbf{What's New} dialog is displayed showing the changes in the new version.\n\n\\paragraph{Known Limitations}\n\\begin{itemize}\n    \\item Downgrade is not yet possible.\n    \\item There is no progress dialog to display the installation progress. If you cannot interact with the current page,\n    wait until the installation is finished.\n\\end{itemize}\n\n\\subsection{Remove All Blocking Rules}\nIn the Settings page, a new option is added which can be used to remove all blocking rules configured within App Manager.\n\n\\subsection{App Ops}\n\\begin{itemize}\n    \\item App Ops are now generated using a technique similar to AppOpsX. This should decrease the loading time\n    significantly in the App Ops tab.\n    \\item In the App Ops tab, a menu item is added which can be used to list only active app ops without including the\n    default app ops. The preference is saved in the shared preferences.\n\\end{itemize}\n\n\\paragraph{Known Limitation} Often the App Ops tab may not be responsive. If that's the case, restart App Manager.\n\n\\subsection{Enhanced ADB Support}\nADB shell commands are now executed using a technique similar to AppOpsX (This is the \\textit{free} alternative of AppOps by Rikka.).\nThis should dramatically increase the execution time.\n\n\\paragraph{Known Limitation} AM can often crash or become not responsive. If that's the case, restart App Manager.\n\n\\subsection{Filtering in Main Page}\nAdd an option to filter apps that has at least one activity.\n\n\\subsection{Apk Backup/Sharing}\nApk files are now saved as \\texttt{app name\\_version.extension} instead of \\texttt{package.name.extension}.\n\n\\subsection{Batch Ops}\n\\begin{itemize}\n    \\item Added a foreground service to run batch operations. The result of the operation is displayed in a notification.\n    If an operation has failed for some packages, clicking on the notification will open a dialog box listing the failed\n    packages. There is also a \\textbf{Try Again} button on the bottom which can be used to perform the operation again for the failed packages.\n    \\item Replaced Linux \\textit{kill} with \\textbf{force-stop}.\n\\end{itemize}\n\n\\subsection{Translations}\nAdded German and Portuguese (Brazilian) translations.\n\n\\paragraph{Known Limitation} Not all translations are verified yet.\n\n\\subsection{App Data Backup}\nInstall app only for the current user at the time of restoring backups. Support for split apks is also added.\n\n\\textit{Data backup feature is now considered unstable. If you encounter any problem, please report to me without hesitation.}\n"
  },
  {
    "path": "docs/raw/en/appendices/main.tex",
    "content": "% SPDX-License-Identifier: GPL-3.0-or-later OR CC-BY-SA-4.0\n\\appendix\n\\input{appendices/specifications.tex}\n\\input{appendices/changelogs.tex}\n\\input{appendices/app-ops.tex}\n"
  },
  {
    "path": "docs/raw/en/appendices/specifications.tex",
    "content": "% SPDX-License-Identifier: GPL-3.0-or-later OR CC-BY-SA-4.0\n\\chapter{Specifications}\\label{ch:specifications} %%##$chapter-title>>\n\n\\section{Rules Specification}\\label{sec:rules-specification} %%##$rules-specification-title>>\n\n\\subsection{Background} %%##$background-title>>\n%%!!background<<\nAM currently supports blocking activities, broadcast receivers, content providers, services, app ops and permissions,\nand in future I may add more blocking options. In order to add more portability, it is necessary to import/export all\nthese data.\n\nMaintaining a database should be the best choice when it comes to storing data. For now, several \\texttt{tsv} files\nwith each file having the name of the package and a \\texttt{.tsv} extension. The file/database will be queried/processed\nby the \\texttt{RulesStorageManager} class. Due to this abstraction, it should be easier to switch to database or\nencrypted database systems in future without changing the design of the entire project. Currently, All configuration\nfiles are stored at \\texttt{/data/data/io.github.muntashirakon.AppManager/Files/conf}.\n%%!!>>\n\n\\subsection{Rules File Format} %%##$rules-file-format-title>>\n\n\\subsubsection{Internal} %%##$internal-title>>\n%%!!internal<<\nThe format below is used internally within App Manager and is \\textit{not compatible with the external format.}\n\\begin{Verbatim}\n    <name> <type> <mode>|<component_status>|<is_granted>\n\\end{Verbatim}\nHere:\n\\begin{itemize}\n    \\item \\texttt{<name>} -- Component/permission/app op name (in case of app op, it could be string or integer)\n    \\item \\texttt{<type>} -- One of the \\texttt{ACTIVITY}, \\texttt{RECEIVER}, \\texttt{PROVIDER}, \\texttt{SERVICE},\n    \\texttt{APP\\_OP},  \\texttt{PERMISSION}\n    \\item \\texttt{<mode>} -- (For app ops) The associated \\hyperref[subsec:mode-constants]{mode constant}\n    \\item \\texttt{<component\\_status>} -- (For components) Component status\n    \\begin{itemize}\n        \\item \\texttt{true} -- Component has been applied (\\texttt{true} value is kept for compatibility)\n        \\item \\texttt{false} -- Component hasn't been applied yet, but will be applied in future (\\texttt{false} value\n        is kept for compatibility)\n        \\item \\texttt{unblocked} -- Component is scheduled to be unblocked\n    \\end{itemize}\n    \\item \\texttt{<is\\_granted>} -- (For permissions) Whether the permission is granted or revoked\n\\end{itemize}\n%%!!>>\n\n\\subsubsection{External} %%##$external-title>>\n%%!!external<<\nExternal format is used for importing or exporting rules in App Manager.\n\\begin{Verbatim}\n    <package_name> <component_name> <type> <mode>|<component_status>|<is_granted>\n\\end{Verbatim}\nThis the format is essentially the same as above except for the first item which is the name of the package.\n\n\\begin{danger}{Caution}\n    The exported rules have a different format than the internal one and should not be copied directly to the\n    \\textbf{conf} folder.\n\\end{danger}\n%%!!>>\n"
  },
  {
    "path": "docs/raw/en/custom.css",
    "content": "/* SPDX-License-Identifier: GPL-3.0-or-later OR CC-BY-SA-4.0 */\n#title-block-header {\n    display: none;\n}\n\n#TOC {\n    height: 100%;\n    width: 16em;\n    position: fixed;\n    z-index: 1;\n    top: 0;\n    left: 0;\n    overflow-x: hidden;\n    padding: 0 1.25em;\n    color: #21005D; /* ?attr/colorOnPrimaryContainer */\n    background: #EADDFF; /* ?attr/colorPrimaryContainer */\n}\n\n#TOC ul {\n    list-style-type: none;\n    padding: 1em 0;\n    margin: 0;\n    font-weight: bold;\n    font-size: 1.2em;\n}\n\n#TOC ul ul {\n    list-style-type: none;\n    padding: 0 0 0 20px;\n    margin: 0;\n    font-weight: normal;\n    font-size: 0.8em;\n}\n\n#TOC ul ul ul {\n    list-style-type: none;\n    padding: 0 0 0 20px;\n    margin: 0;\n    font-style: oblique;\n    font-size: 0.9em;\n}\n\n.center {\n    text-align: center;\n}\n\n.level1, .footnotes, .titlingpage {\n    padding: 1em;\n    margin: auto;\n}\n\n.level5 h5 .header-section-number {\n    display: none;\n}\n\n.level5 h5 {\n    margin: auto;\n    display: inline-block;\n    padding-right: 0.5em;\n}\n\n.level5 h5 + p, .level5 h5 + div + p {\n    display: inline;\n}\n\n.level5 h5 + div {\n    display: inline;\n}\n\n.titlingpage p:nth-child(2) {\n    font-size: 3em;\n}\n\n.footnotes {\n    margin-right: auto !important;\n    border-bottom: unset !important;\n    font-size: inherit !important;\n}\n\n@media screen and (min-width: 48em) {\n    .level1, .footnotes, .titlingpage {\n        margin-left: 18.5em;\n    }\n}\n\n@media screen and (max-width: 48em) {\n    #TOC {\n        position: unset;\n        height: unset;\n        width: unset;\n        background: unset;\n    }\n\n    .level1, .footnotes, .titlingpage {\n        max-width: 42em;\n    }\n}\n\n.amalert {\n    border-width: 0 0 0 3pt !important;\n    border-style: solid;\n    padding: 0.4em 0.4em 0.4em 0.8em;\n    color: unset !important;\n    background: unset !important;\n    margin-bottom: 1em;\n}\n\n.amalert > p:first-child {\n    padding-right: 5px;\n}\n\n.amalert.tip {\n    border-color: #625B71 !important; /* ?attr/colorSecondary */\n    color: #1D192B !important; /* ?attr/colorOnSecondaryContainer */\n    background-color: #E8DEF8 !important; /* ?attr/colorSecondaryContainer */\n}\n\n.amalert.warning {\n    border-color: #7D5260 !important; /* ?attr/colorTertiary */\n    color: #31111D !important; /* ?attr/colorOnTertiaryContainer */\n    background-color: #FFD8E4 !important; /* ?attr/colorTertiaryContainer */\n}\n\n.amalert.danger {\n    border-color: #B3261E !important; /* ?attr/colorError */\n    color: #410E0B !important; /* ?attr/colorOnErrorContainer */\n    background-color: #F9DEDC !important; /* ?attr/colorErrorContainer */\n}\n\n.amalert p:nth-child(1), .amalert p:nth-child(2) {\n    display: inline;\n}\n\n.seealso *, .seealso-inline {\n    font-style: oblique;\n    margin: 0;\n}\n\n.seealso * {\n    display: inline-block;\n}\n\n.seealso ul {\n    padding: 0;\n}\n\n.seealso ul li:before {\n    content: '\\00a0\\2022\\00a0';\n}\n\n.colorbox {\n    padding: 3px 7px;\n    border-radius: 5px;\n}\n\nfigcaption.caption span.id:after {\n    content: ' ';\n}\n\nfigure {\n    text-align: center;\n}\n\nhtml {\n    font-size: 100%;\n    overflow-y: scroll;\n    -webkit-text-size-adjust: 100%;\n    -ms-text-size-adjust: 100%;\n}\n\nbody {\n    font-family: Palatino, 'Palatino Linotype', Georgia, Times, 'Times New Roman', serif;\n    font-size: 12px;\n    line-height: 1.5em;\n    word-break: break-word;\n    color: #1C1B1F; /* ?attr/colorOnSurface */\n    background: #FFFBFE; /* ?attr/colorSurface */\n}\n\na {\n    color: #6750A4; /* ?attr/colorPrimary */\n    text-decoration: none;\n}\n\na:active, a:visited {\n    color: #6750A4; /* ?attr/colorPrimary */\n}\n\na:hover {\n    color: #6750A4; /* ?attr/colorPrimary */\n    text-decoration: underline;\n}\n\na:focus {\n    outline: thin dotted;\n}\n\na:hover, a:active {\n    outline: 0;\n}\n\n.anchor {\n    opacity: 0.2;\n}\n\n.anchor:after {\n    content: \"¶︎\";\n}\n\n.anchor:hover {\n    opacity: 1.0;\n    text-decoration: none;\n}\n\n::-moz-selection {\n    background: #E7E0EC; /* ?attr/colorSurfaceVariant */\n    color: #49454F; /* ?attr/colorOnSurfaceVariant */\n}\n\n::selection {\n    background: #E7E0EC; /* ?attr/colorSurfaceVariant */\n    color: #49454F; /* ?attr/colorOnSurfaceVariant */\n}\n\na::-moz-selection {\n    background: #FFFFFF; /* ?attr/colorOnPrimary */\n    color: #6750A4; /* ?attr/colorPrimary */\n}\n\na::selection {\n    background: #FFFFFF; /* ?attr/colorOnPrimary */\n    color: #6750A4; /* ?attr/colorPrimary */\n}\n\np {\n    margin: 1em 0;\n}\n\nimg, object[type='image/svg+xml'] {\n    max-width: 100%;\n}\n\nh1, h2, h3, h4, h5, h6 {\n    font-weight: normal;\n    color: #1C1B1F; /* ?attr/colorOnSurface */\n    line-height: 1em;\n}\n\nh4, h5, h6 {\n    font-weight: bold;\n}\n\nh1 {\n    font-size: 2.5em;\n}\n\nh2 {\n    font-size: 2em;\n}\n\nh3 {\n    font-size: 1.5em;\n}\n\nh4 {\n    font-size: 1.2em;\n}\n\nh5 {\n    font-size: 1em;\n}\n\nh6 {\n    font-size: 0.9em;\n}\n\nblockquote {\n    color: #666666;\n    margin: 0;\n}\n\nhr {\n    display: block;\n    border: 0;\n    border-top: 1px solid rgba(0, 0, 0, 0.12); /* ?android:attr/colorControlHighlight */\n    border-bottom: 1px solid rgba(0, 0, 0, 0.12); /* ?android:attr/colorControlHighlight */\n    margin: 1em 0;\n    padding: 0;\n}\n\npre, code, kbd, samp {\n    font-family: monospace, monospace;\n    _font-family: 'courier new', monospace;\n    font-size: 0.98em;\n}\n\ndiv.sourceCode {\n    background-color: #f4f4f4;\n}\n\npre {\n    padding: 1em;\n    word-wrap: break-word;\n    background-color: #f4f4f4;\n}\n\nb, strong {\n    font-weight: bold;\n}\n\ndfn {\n    font-style: italic;\n}\n\nins {\n    background: #E7E0EC; /* ?attr/colorSurfaceVariant */\n    color: #49454F; /* ?attr/colorOnSurfaceVariant */\n    text-decoration: none;\n}\n\nmark {\n    background: #E7E0EC; /* ?attr/colorSurfaceVariant */\n    color: #49454F; /* ?attr/colorOnSurfaceVariant */\n    font-style: italic;\n    font-weight: bold;\n}\n\nsub, sup {\n    font-size: 75%;\n    line-height: 0;\n    position: relative;\n    vertical-align: baseline;\n}\n\nsup {\n    top: -0.5em;\n}\n\nsub {\n    bottom: -0.25em;\n}\n\nul, ol {\n    margin: 1em 0;\n    padding: 0 0 0 2em;\n}\n\nli p:last-child {\n    margin: 0;\n}\n\ndd {\n    margin: 0 0 0 2em;\n}\n\nimg, object[type='image/svg+xml'] {\n    border: 0;\n    -ms-interpolation-mode: bicubic;\n    vertical-align: middle;\n}\n\ntable {\n    border-collapse: collapse;\n    border-spacing: 0;\n}\n\ntd {\n    vertical-align: top;\n}\n\n@media only screen and (min-width: 480px) {\n    body {\n        font-size: 14px;\n    }\n}\n\n@media only screen and (min-width: 768px) {\n    body {\n        font-size: 16px;\n    }\n}\n\n@media (prefers-color-scheme: dark) {\n    #TOC {\n        color: #EADDFF; /* ?attr/colorOnPrimaryContainer */\n        background: #4F378B !important; /* ?attr/colorPrimaryContainer */\n    }\n\n    body {\n        color: #E6E1E5 !important; /* ?attr/colorOnSurface */\n        background-color: #1C1B1F !important; /* ?attr/colorSurface */\n    }\n\n    a, a:visited {\n        color: #D0BCFF !important; /* ?attr/colorPrimary */\n    }\n\n    h1, h2, h3, h4, h5, h6 {\n        color: #E6E1E5 !important; /* ?attr/colorOnSurface */\n    }\n\n    hr {\n        border-top: 1px solid rgba(255, 255, 255, 0.2); /* ?android:attr/colorControlHighlight */\n        border-bottom: 1px solid rgba(255, 255, 255, 0.2); /* ?android:attr/colorControlHighlight */\n    }\n\n    pre, div.sourceCode {\n        background-color: #242424;\n    }\n\n    .amalert.tip {\n        border-color: #CCC2DC !important; /* ?attr/colorSecondary */\n        color: #E8DEF8 !important; /* ?attr/colorOnSecondaryContainer */\n        background-color: #4A4458 !important; /* ?attr/colorSecondaryContainer */\n    }\n\n    .amalert.warning {\n        border-color: #EFB8C8 !important; /* ?attr/colorTertiary */\n        color: #FFD8E4 !important; /* ?attr/colorOnTertiaryContainer */\n        background-color: #633B48 !important; /* ?attr/colorTertiaryContainer */\n    }\n\n    .amalert.danger {\n        border-color: #F2B8B5 !important; /* ?attr/colorError */\n        color: #F2B8B5 !important; /* ?attr/colorOnErrorContainer */\n        background-color: #8C1D18 !important; /* ?attr/colorErrorContainer */\n    }\n}\n\n@media print {\n    * {\n        background: transparent !important;\n        color: black !important;\n        filter: none !important;\n        -ms-filter: none !important;\n    }\n\n    #TOC {\n        display: none;\n    }\n\n    .amalert.tip {\n        color: unset !important;\n        background-color: unset !important;\n    }\n\n    .amalert.warning {\n        color: unset !important;\n        background-color: unset !important;\n    }\n\n    .amalert.danger {\n        color: unset !important;\n        background-color: unset !important;\n    }\n\n    body {\n        font-size: 12pt;\n        max-width: 100%;\n    }\n\n    a, a:visited {\n        text-decoration: underline;\n    }\n\n    hr {\n        height: 1px;\n        border: 0;\n        border-bottom: 1px solid black;\n    }\n\n    a[href]:after {\n        content: \" <\" attr(href) \">\";\n    }\n\n    abbr[title]:after {\n        content: \" (\" attr(title) \")\";\n    }\n\n    .ir a:after, a.uri:after, a[href^=\"javascript:\"]:after, a[href^=\"mailto:\"]:after, a[href^=\"app-manager:\"]:after, a[href^=\"#\"]:after {\n        content: \"\";\n    }\n\n    a[href^=\"#toc:\"] {\n        text-decoration: none;\n    }\n\n    a.footnote-ref {\n        text-decoration: none;\n    }\n\n    a.footnote-back {\n        display: none;\n    }\n\n    pre, blockquote {\n        border: 1px solid #999;\n        padding: .5em;\n        page-break-inside: avoid;\n    }\n\n    tr, img, object[type='image/svg+xml'] {\n        page-break-inside: avoid;\n    }\n\n    img, object[type='image/svg+xml'] {\n        max-width: 100% !important;\n    }\n\n    @page :left {\n        margin: 15mm 20mm 15mm 10mm;\n    }\n\n    @page :right {\n        margin: 15mm 10mm 15mm 20mm;\n    }\n\n    p, h2, h3 {\n        orphans: 3;\n        widows: 3;\n    }\n\n    h2, h3 {\n        page-break-after: avoid;\n    }\n}\n"
  },
  {
    "path": "docs/raw/en/doctool.sh",
    "content": "#!/usr/bin/env bash\n# SPDX-License-Identifier: GPL-3.0-or-later\n\n{ [[ $(uname) == Darwin ]] || [[ $(uname) =~ .*BSD.* ]]; } && {\n  alias sed=\"gsed\"\n  alias grep=\"ggrep\"\n}\n\nfunction check_deps() {\n  echo -n \"Pandoc: \" && ( command -v pandoc || echo \"Not found.\" )\n  echo -n \"pandoc-crossref: \" && ( { command -v pandoc-crossref || ls ./pandoc-crossref; } || echo \"Not found.\" )\n  echo -n \"minify: \" && ( command -v minify || echo \"Not found.\" )\n  { [[ $(uname) == Darwin ]] || [[ $(uname) =~ .*BSD.* ]]; } && {\n    echo -n \"GNU grep: \" && ( command -v ggrep || echo \"Not found.\" )\n    echo -n \"GNU sed: \" && ( command -v gsed || echo \"Not found.\" )\n  }\n  echo -n \"urlextract: \" && ( command -v urlextract || echo \"Not found.\" )\n}\n\nfunction detect_abuse() {\n  baseDir=.\n  compareDir=\"$2\"\n\n  [ -z \"$2\" ] && { echo \"Compare directory not specified.\"; exit 0; }\n\n  # Compare number of latex tags\n\n  # Check URL changes\n  baseFiles=$(find \"$baseDir\" | grep -e '\\.tex$' | sed -e \"s%$baseDir%%g\" -e \"s/^\\///g\")\n  compareFiles=$(find \"$compareDir\" | grep -e '\\.tex$' | sed -e \"s%$compareDir%%g\" -e \"s/^\\///g\")\n\n  while read -r test; do\n    { echo \"$compareFiles\" | grep \"$test\" >/dev/null; } && {\n      base=$(urlextract \"$baseDir/$test\")\n      compare=$(urlextract \"$compareDir/$test\")\n\n      echo \"$compare\" | grep -vh \"$base\"\n      echo -n \"--\\n\\n\"\n      echo \"WARNING: $baseDir/$test(BASE) does not have these URLs, but $compareDir/$test(COMPARE) has. These links has possibility of spam!\"\n      echo -n \"--\\n\\n\"\n    }\n  done < <(echo \"$baseFiles\")\n}\n\ncase $1 in\n\"check\") check_deps ;;\n\"checkabuse\") detect_abuse \"$@\" ;;\nesac\n"
  },
  {
    "path": "docs/raw/en/faq/aot.tex",
    "content": "% SPDX-License-Identifier: GPL-3.0-or-later OR CC-BY-SA-4.0\n\\section{ADB over TCP}\\label{sec:faq:adb-over-tcp} %%##$section-title>>\n\n\\subsection{Do I have to enable ADB over TCP everytime I restart?}\\label{subsec:faq:enable-adb-on-every-restart} %%##$restart-title>>\n%%!!restart<<\nUnfortunately, yes. This is because the ADB daemon, the process responsible for ADB connection, is also restarted after\na reboot, and it does not re-enable ADB over TCP\\@.\n%%!!>>\n\n\\subsection{Cannot enable USB debugging. What to do?}\\label{subsec:faq:usb-debugging} %%##$usb-debugging-title>>\n%%!!usb-debugging<<\nSee \\Sref{subsec:enable-usb-debugging} in \\Cref{ch:guides}.\n%%!!>>\n\n\\subsection{Can I block tracker or any other application components using ADB over TCP?}\\label{subsec:faq:block-components-using-adb} %%##$block-tracker-title>>\n%%!!block-tracker<<\nADB has limited number of \\href{https://github.com/aosp-mirror/platform_frameworks_base/blob/master/packages/Shell/AndroidManifest.xml}{permissions}\nand controlling application components is not one of them. However, the components of a \\textit{test-only} app can be\ncontrolled via ADB\\@. If App Manager detects such an application, it enables the blocking options automatically.\n%%!!>>\n\n\\subsection{Which features can be used in ADB mode?}\\label{subsec:faq:adb-features} %%##$feature-adb-title>>\n%%!!feature-adb<<\nSupported features are enabled automatically in the ADB mode. Supported features include disabling, force-stopping,\nclearing application data, granting or revoking app ops and permissions, and so on. It is also possible to install or\nuninstall applications without any prompt from the system.\n%%!!>>\n"
  },
  {
    "path": "docs/raw/en/faq/app-components.tex",
    "content": "% SPDX-License-Identifier: GPL-3.0-or-later OR CC-BY-SA-4.0\n\\section{App Components}\\label{sec:faq:app-components} %%##$section-title>>\n\n\\subsection{What are the application components?}\\label{subsec:faq:what-are-app-components} %%##$what-are-app-components-title>>\n%%!!what-are-app-components<<\nActivities, services, broadcast receivers (or only receivers) and content providers (or only providers) are jointly\ncalled application components. More technically, they all inherit the\n\\href{https://developer.android.com/reference/android/content/pm/ComponentInfo}{ComponentInfo} class and can be launched\nvia Intent.\n%%!!>>\n\n\\subsection{How are the tracker and other components blocked in App Manager? What are its limitations?}\\label{subsec:faq:how-components-blocked} %%##$limitations-title>>\n%%!!limitations<<\nApp Manager typically blocks application components (or tracker components) using a method called\n\\href{https://carteryagemann.com/pages/android-intent-firewall.html}{Intent Firewall (IFW)}, it is superior to\nother methods such as \\textit{pm} (PackageManager), \\href{https://github.com/RikkaApps/Shizuku}{Shizuku} or any other\nmethod that uses the package manager to enable or disable the components. If a component is disabled by the latter\nmethods, the application itself can detect that the component is being blocked and can re-enable it as it has full\naccess to its own components. (Many deceptive applications actually do this in order to keep the tracker components\nunblocked.) On the other hand, IFW is a true firewall and the application cannot detect if its components are being\nblocked. App Manager uses the term \\textit{block} rather than \\textit{disable} for this reason.\n\nEven IFW has some limitations which are primarily applicable for the system applications:\n\\begin{itemize}\n    \\item The application in question is whitelisted by the system i.e.\\ the system cannot function properly without\n    these applications and may cause random crashes. These applications include but not limited to Android System,\n    System UI, Phone Services. They will continue to work even if they are disabled or blocked.\n\n    \\item Another system application or system process has activated a specific component of the application in question\n    via interprocess communication (IPC). In this case, the component will be activated regardless of blocking status or\n    even if the entire application is disabled. If there is such a system application that is not needed, the only way\n    to prevent it from running is by getting rid of it.\n\\end{itemize}\n%%!!>>\n\n\\subsection{Does app components blocked by other tools retained in App Manager?}\\label{subsec:faq:components-blocked-by-others} %%##$other-tools-retained-in-am-title>>\n%%!!other-tools-retained-in-am<<\n\\textbf{No.} But the application components blocked by the system or any other tools are displayed in the\n\\hyperref[subsec:component-tabs]{component tabs}. These rules can be imported from \\hyperref[par:import-existing-rules]{Settings}.\nHowever, it is not possible for App Manager to distinguish the components blocked by the third-party tools and\ncomponents blocked by the system. Therefore, the applications listed in the import page should be selected with care.\n%%!!>>\n\n\\subsection{What happens to the components blocked by App Manager which were previously blocked by other tools?}\\label{subsec:faq:components-reblocked-in-am} %%##$also-blocked-by-other-tools-title>>\n%%!!also-blocked-by-other-tools<<\n\\textit{App Manager blocks the components again} if requested. In case of unblocking, they will be reverted to the\ndefault state as specified in the manifest of the application. But if the components were blocked by\n\\href{https://www.myandroidtools.com}{MyAndroidTools (MAT)} with IFW method, they will not be unblocked by App Manager\nas it uses a different format. To fix this issue, the rules have to be imported from \\hyperref[par:import-existing-rules]{Settings}\nat first, in which case MAT's configurations will be permanently removed.\n%%!!>>\n\n\\subsection{What is instant component blocking?}\\label{subsec:faq:what-is-instant-component-blocking} %%##$what-is-component-blocking-title>>\n%%!!what-is-component-blocking<<\nWhen you block a component in the \\hyperref[sec:app-details-page]{App Details page}, the blocking is not applied by\ndefault. It is only applied when you apply blocking using the \\textit{Apply rules} option in the top-right menu. If you\nenable \\hyperref[subsubsec:instant-component-blocking]{instant component blocking}, blocking will be applied as soon as you block a component.\nIf you choose to block tracker components, however, blocking is applied automatically regardless of this setting.\nYou can also remove blocking for an application by simply clicking on \\textit{Remove rules} in the same menu in the \\textbf{App Details page}.\nSince the default behaviour gives you more control over applications, it is better to keep \\textit{instant component blocking} option disabled.\n%%!!>>\n\n\\subsection{Tracker classes versus tracker components}\\label{subsec:tracker-classes-versus-tracker-components} %%##$tracker-classes-versus-tracker-components-title>>\n%%!!tracker-classes-versus-tracker-components<<\nAll application components are classes but not all classes are components. In fact, only a few of the classes are components.\nThat being said, \\hyperref[sec:scanner-page]{scanner page} displays a list of trackers along with the number of classes,\nnot just the components. In all other pages, trackers and tracker components are used synonymously to denote tracker\ncomponents, i.e.\\ blocking tracker means blocking tracker components, not tracker classes.\n\n\\begin{tip}{Info}\n    Tracker classes that are not components cannot be blocked. They can only be removed by editing the application itself.\n\\end{tip}\n%%!!>>\n"
  },
  {
    "path": "docs/raw/en/faq/main.tex",
    "content": "% SPDX-License-Identifier: GPL-3.0-or-later OR CC-BY-SA-4.0\n\\chapter{Frequently Asked Questions}\\label{ch:faq} %%##$faq-chapter-title>>\n\n\\input{faq/app-components.tex}\n\\input{faq/aot.tex}\n\\input{faq/misc.tex}"
  },
  {
    "path": "docs/raw/en/faq/misc.tex",
    "content": "% SPDX-License-Identifier: GPL-3.0-or-later OR CC-BY-SA-4.0\n\\section{Miscellanea}\\label{sec:faq:miscellanea} %%##$section-title>>\n\n\\subsection{I don't use root/ADB. Am I completely safe from any harms?}\\label{subsec:faq:no-root-no-harms} %%##$i-dont-use-root-adb-title>>\n%%!!i-dont-use-root-adb<<\nYes. AM cannot modify any system settings without root or ADB\\@.\n%%!!>>\n\n\\subsection{How are the trackers and libraries are updated?}\\label{subsec:faq:how-trackers-libs-updated} %%##$how-tracker-updated-title>>\n%%!!how-tracker-updated<<\nTrackers and libraries are updated manually before making a new release.\n%%!!>>\n\n\\subsection{Are APKs deleted after installed?}\\label{subsec:faq:apks-deleted-after-installed} %%##$apks-deleted-after-installed>>\n%%!!apks-deleted-after-installed<<\nNo, APKs aren't deleted by App Manager after they are installed.\n%%!!>>\n\n\\subsection{Any plans for Shizuku?}\\label{subsec:faq:shizuku-support} %%##$shizuku-title>>\n%%!!shizuku<<\nApp Manager's use of hidden API and privileged code execution is now much more complex and cannot be integrated with\nother third party apps such as \\href{https://shizuku.rikka.app}{Shizuku}. Here are some reasons for not considering\nShizuku (which now has Apache 2.0 license) for App Manager:\n\\begin{enumerate}\n    \\item Shizuku was initially non-free which led me to use a similar approach for App Manager to support both root\n    and ADB\n    \\item App Manager already supports both ADB and root which in some cases is more capable than Shizuku\n    \\item Relying on a third-party app for the major functionalities is not a good design choice\n    \\item Integration of Shizuku will increase the complexity of App Manager.\n\\end{enumerate}\n%%!!>>\n\n\\subsection{What are bloatware and how to remove them?}\\label{subsec:faq:what-are-bloatware} %%##$bloatware-title>>\n%%!!bloatware<<\nBloatware are the unnecessary pre-installed apps, usually system apps. Some of the apps are often\nused to track users and collect user data which they might sell for profits. Many system apps do not\nneed to request any permission to access device info, contacts and messaging data, and other usage\ninfo, such as your phone usage habits and everything you store on your shared storage(s).\n\nThe bloatware may also include Google apps, Meta apps, and Twitter/X which can also track users\nand/or collect user data without consent. You can disable a few permissions from Android settings\nbut be aware that Android settings hides many permissions a security researcher would call\npotentially \\emph{dangerous} (e.g., internet, sensor).\n\nWere the bloatware user apps, they could be easily uninstalled either from Android settings or AM\\@.\nUninstalling system apps is not possible without privileged permission, but even then, it cannot\n\\emph{remove} the system apps completely as they are located in the \\emph{system} partition which is\na read-only partition. If you have root, you can remount this partition to manually \\emph{purge}\nthese apps but this will break Over the Air (OTA) updates since data in the system partition has\nbeen modified. There are two kind of updates, delta (small-size, consisting of only the changes\nbetween two versions) and full updates. You may still be able to apply full updates, but the\nbloatware will be installed again, and consequently, you have to delete them all over again.\n\nAnother solution is to disable these apps either from Android settings or AM, but certain services\ncan still run in the background as they can be started by other system apps using Inter-process\nCommunication (IPC). One possible solution is to disable all bloatware until the service has finally\nstopped (after a restart). However, due to heavy modifications of the Android frameworks by the\nvendors, removing or disabling certain bloatware may cause the System UI to crash or even cause\nbootloop. From v4.0.0, AM has a new feature called \\textbf{Debloater} which can be used as a\nstarting point to monitor, disable, and remove the bloatware from a proprietary Android operating\nsystem.\n\n\\begin{warning}{Note}\n    In most cases, you cannot completely debloat your device. Therefore, it is recommended that you\n    use a custom ROM free from bloatware, such as Graphene OS, Lineage OS or their derivatives.\n\\end{warning}\n%%!!>>\n"
  },
  {
    "path": "docs/raw/en/guide/aot.tex",
    "content": "% SPDX-License-Identifier: GPL-3.0-or-later OR CC-BY-SA-4.0\n\\section{ADB over TCP}\\label{sec:adb-over-tcp} %%##$section-title>>\n%%!!intro<<\nMany root-only features can still be used by enabling ADB over TCP. To do that, a PC or Mac is required with Android\nplatform-tools installed, and an Android phone with developer options \\& USB debugging enabled.\n\n\\begin{tip}{Root users}\n    If superuser permission has been granted to App Manager, it can already execute privileged code\n    without any problem. \\textbf{Therefore, root users do not need to enable ADB over TCP.} But if\n    you insist on using ADB over TCP, you must revoke superuser permission for App Manager.\n\\end{tip}\n\n\\seealsoinline{\\hyperref[sec:faq:adb-over-tcp]{FAQ: ADB over TCP}}\n%%!!>>\n\n\\subsection{Enable developer options}\\label{subsec:enable-developer-options} %%##$enable-dev-options-title>>\n\n\\subsubsection{Location of developer options}\\label{subsubsec:location-of-developer-options} %%##$location-dev-options-title>>\n%%!!location-dev-options<<\n\\textbf{Developer options} is located in Android \\textbf{Settings}, either directly near the bottom\nof the page (in most ROMs) or under some other settings, such as \\textbf{System} (Google Pixel,\nLineage OS, Asus Zenfone 8.0+), \\textbf{Additional Settings} (Xiaomi MIUI, Oppo ColorOS),\n\\textbf{More Settings} (Vivo FuntouchOS), \\textbf{More} (ZTE Nubia). Unlike other options, it is not\nvisible until explicitly enabled by the user. If it is already enabled, you can use the search box\nin Android \\textbf{Settings} to locate it as well.\n%%!!>>\n\n\\subsubsection{How to enable developer options} %%##$how-to-enable-dev-options-title>>\n%%!!how-to-enable-dev-options<<\nThis option is available within Android \\textbf{Settings} as well but like the location of the developer options, it\nalso differs from device to device. But in general, you have to find \\textbf{Build number} (or \\textbf{MIUI version} for\nMIUI ROMs and \\textbf{Software version} for Vivo FuntouchOS, \\textbf{Version} for Oppo ColorOS) and tap it at least 7\n(seven) times until you finally get a message saying \\textit{You are now a developer} (you may be prompted to insert\npin/password/pattern or solve captchas at this point). In most devices, it is located at the bottom of the settings\npage, inside \\textbf{About Phone}. But the best way to find it is to use the search box.\n%%!!>>\n\n\\subsection{Enable USB debugging}\\label{subsec:enable-usb-debugging} %%##$enable-usb-debugging-title>>\n%%!!enable-usb-debug<<\nAfter \\hyperref[subsubsec:location-of-developer-options]{locating the developer options}, enable \\textbf{Developer\noption} (if not already). After that, scroll down a bit until you will find the option \\textbf{USB debugging}. Use the\ntoggle button on the right-hand side to enable it. At this point, you may get an alert prompt where you may have to\nclick \\textit{OK} to actually enable it. You may also have to enable some other options depending on device vendor and\nROM. Here are some examples:\n%%!!>>\n\n\\subsubsection{Xiaomi (MIUI)} %%##$miui-usb-debug-title>>\n%%!!miui-usb-debug<<\nEnable \\textbf{USB debugging (Security settings)} as well.\n%%!!>>\n\n\\subsubsection{Huawei (EMUI)} %%##$emui-usb-debug-title>>\n%%!!emui-usb-debug<<\nEnable \\textbf{Allow ADB debugging in charge only mode} as well. When connecting to your PC or Mac, you may get a prompt\nsaying \\textbf{Allow access to device data?} in which case click \\textbf{YES, ALLOW ACCESS}.\n\n\\begin{tip}{Notice}\n    Often the \\textbf{USB debugging} mode could be disabled automatically by the system. If that's the case, repeat the\n    above procedure.\n\\end{tip}\n%%!!>>\n\n\\subsubsection{Realme} %%##$realme-usb-debug-title>>\n%%!!realme-usb-debug<<\nDepending on the device and the version of operating system, you have to enable \\textbf{Disable Permission Monitoring},\nor \\textbf{USB debugging (Security settings)} along with \\textbf{Install via USB}.\n%%!!>>\n\n\\subsubsection{OnePlus (Oxygen OS)} %%##$oneplus-usb-debug-title>>\n%%!!oneplus-usb-debug<<\nDepending on the device and the version of operating system, you have to enable \\textbf{Disable Permission Monitoring}.\n%%!!>>\n\n\\subsubsection{LG} %%##$lg-usb-debug-title>>\n%%!!lg-usb-debug<<\nMake sure you have \\textbf{USB tethering} enabled.\n%%!!>>\n\n\\subsubsection{Troubleshooting} %%##$troubleshooting-usb-debug-title>>\n%%!!troubleshooting-usb-debug<<\nIn case \\textbf{USB Debugging} is greyed out, you can do the following:\n\\begin{enumerate}\n    \\item Make sure you enabled USB debugging before connecting your phone to the PC or Mac via USB cable\n    \\item Enable USB tethering after connecting to PC or Mac via USB cable\n    \\item (For Samsung) If your device is running KNOX, you may have to follow some additional steps. See official\n    documentations or consult support for further assistant\n\\end{enumerate}\n%%!!>>\n\n\\subsection{Setup ADB on PC or Mac}\\label{subsec:setup-adb-on-pc-or-mac} %%##$setup-adb-on-pc-title>>\n%%!!setup-adb-on-pc<<\nIn order to enable ADB over TCP, you have to set up ADB in your PC or Mac. \\textbf{\\textit{Lineage OS users can skip to\n\\Sref{subsubsec:lineage-os}.}}\n%%!!>>\n\n\\subsubsection{Windows} %%##$setup-adb-win-title>>\n%%!!setup-adb-win<<\n\\begin{enumerate}\n    \\item Download the latest version of\n    \\href{https://dl.google.com/android/repository/platform-tools-latest-windows.zip}{Android SDK Platform-Tools} for\n    Windows\n    \\item Extract the contents of the zip file into any directory (such as \\texttt{C:\\textbackslash{adb}}) and navigate\n    to that directory using \\textit{Explorer}\n    \\item Open \\textbf{Command Prompt}, \\textbf{PowerShell}, or \\textbf{Terminal} from this directory.\n    You can do it manually from the start menu or by holding \\texttt{Shift} and right clicking within\n    the directory in \\textit{File Explorer} and then clicking either on \\textit{Open command window here},\n    or \\textit{Open PowerShell window here} (depending on what you have installed). You can now\n    access ADB by typing \\texttt{adb} (Command Prompt) or \\texttt{./adb} (PowerShell).\n    Do not close this window yet.\n\\end{enumerate}\n\n\\begin{tip}{Tip}\n    If you have \\href{https://learn.microsoft.com/en-us/windows/package-manager/winget/}{WinGet}\n    installed, you can install ADB using the following command:\n    \\begin{minted}[frame=lines]{bash}\nwinget install --id Google.PlatformTools\n    \\end{minted}\n    After that, you can simply type \\texttt{adb} to access ADB\\@.\n\\end{tip}\n%%!!>>\n\n\\subsubsection{macOS} %%##$setup-adb-mac-title>>\n%%!!setup-adb-mac<<\n\\begin{enumerate}\n    \\item Download the latest version of\n    \\href{https://dl.google.com/android/repository/platform-tools-latest-darwin.zip}{Android SDK Platform-Tools} for\n    macOS\n    \\item Extract the contents of the zip file into a directory by clicking on it. After that, navigate to that\n    directory using \\textit{Finder} and locate \\texttt{adb}\n    \\item Open \\textbf{Terminal} using \\textit{Launchpad} or \\textit{Spotlight} and drag-and-drop \\texttt{adb} from the\n    \\textit{Finder} window into the \\textit{Terminal} window. Do not close the \\textit{Terminal} window yet\n\\end{enumerate}\n\n\\begin{tip}{Tip}\n    If you have \\href{https://brew.sh}{Homebrew} installed, you can install ADB using the following\n    command:\n    \\begin{minted}[frame=lines]{bash}\nbrew install --cask android-platform-tools\n    \\end{minted}\n    After that, you can simply type \\texttt{adb} in any \\textit{Terminal} window to access ADB\\@.\n\\end{tip}\n%%!!>>\n\n\\subsubsection{Linux} %%##$setup-adb-linux-title>>\n%%!!setup-adb-linux<<\n\\begin{enumerate}\n    \\item In your favourite terminal emulator, run the following command:\n    \\begin{minted}[frame=lines,autogobble]{bash}\ncd ~/Downloads && curl -o platform-tools.zip -L \\\nhttps://dl.google.com/android/repository/platform-tools-latest-linux.zip && \\\nunzip platform-tools.zip && rm platform-tools.zip && cd platform-tools\n    \\end{minted}\n    \\item If it is successful, you can simply type \\texttt{./adb} in the in \\textit{same} terminal emulator window or\n    type \\texttt{\\textasciitilde/Downloads/platform-tools/adb} in any terminal emulator to access ADB\\@.\n\\end{enumerate}\n%%!!>>\n\n\\subsection{Configure ADB over TCP}\\label{subsec:configure-adb-over-tcp} %%##$configure-aot-title>>\n\n\\subsubsection{Lineage OS 17.1 and Earlier}\\label{subsubsec:lineage-os} %%##$aot-lineage-os-title>>\n%%!!aot-lineage-os<<\nLineage OS (or its derivatives) users can directly enable ADB over TCP using the developer options. To enable that,\ngo to the \\textbf{Developer options}, scroll down until you find \\textbf{ADB over Network}. Now, use the toggle button\non the right-hand side to enable it and skip to \\Sref{subsubsec:adb-mode-in-app-manager}.\n\n\\begin{warning}{Warning}\n    You can turn off \\textbf{ADB over Network} in developer options, but turning off this option will also stop App\n    Manager's remote server. So, turn it off only when you're not going to use App Manager in ADB over TCP mode.\n\\end{warning}\n%%!!>>\n\n\\subsubsection{Enable ADB over TCP via PC or Mac}\\label{subsubsec:enable-adb-over-tcp-via-pc-or-mac} %%##$enable-aot-via-pc-title>>\n%%!!enable-aot-via-pc<<\nFor other ROMs, you can do this using the command prompt/PowerShell/terminal emulator that you've opened in the step 3\nof the previous section. In this section, I will use \\texttt{adb} to denote \\texttt{./adb}, \\texttt{adb} or any other\ncommand that you needed to use based on your platform and software in the previous section.\n\\begin{enumerate}\n    \\item Connect your device to your PC or Mac using a USB cable. For some devices, it is necessary to turn on\n    \\textit{File transfer mode (MTP)} as well\n    \\item To confirm that everything is working as expected, type \\texttt{adb devices} in your terminal. If your device\n    is connected successfully, you will see something like this:\n    \\begin{Verbatim}\nList of devices attached\nxxxxxxxx  device\n    \\end{Verbatim}\n    \\begin{tip}{Notice}\n        In some Android phones, an alert prompt will be appeared with a message \\textbf{Allow USB Debugging}\n        in which case, check \\textit{Always allow from this computer} and click \\textbf{Allow}.\n    \\end{tip}\n    \\item Finally, run the following command to enable ADB over TCP:\n    \\begin{minted}[frame=lines,autogobble]{bash}\nadb tcpip 5555\n    \\end{minted}\n\\end{enumerate}\n\n\\begin{danger}{Danger}\n    You cannot disable developer options or USB debugging after enabling ADB over TCP\\@.\n\\end{danger}\n%%!!>>\n\n\\subsubsection{Enable ADB mode in App Manager}\\label{subsubsec:adb-mode-in-app-manager} %%##$adb-mode-am-title>>\n%%!!adb-mode-am<<\nAfter enabling ADB over TCP, relaunch App Manager. App Manager should detect ADB mode automatically. If it cannot,\nyou can change the mode of operation to ADB over TCP in the \\hyperref[subsec:mode-of-operation]{settings page}.\nThere, you can also verify whether App Manager has correctly detected ADB as indicated by the \\textit{inferred mode}.\n\n\\begin{tip}{Notice}\n    In some Android devices, the USB cable is needed to be disconnected from the PC before connecting to App Manager.\n\\end{tip}\n\n\\begin{warning}{Warning}\n    ADB over TCP will be disabled after a reboot. In that case, you have to follow \\Sref{subsubsec:enable-adb-over-tcp-via-pc-or-mac} again.\n\\end{warning}\n%%!!>>\n"
  },
  {
    "path": "docs/raw/en/guide/automation.tex",
    "content": "% SPDX-License-Identifier: GPL-3.0-or-later OR CC-BY-SA-4.0\n\\section{Automating Tasks}\\label{sec:automating-tasks} %%##$section-title>>\n%%!!intro<<\nIt is possible to trigger profiles configured inside App Manager via third-party applications such as \\textbf{Automation} or \\textbf{Tasker}.\nTraditionally, \\texttt{Intent}s are used to trigger such operations.\n%%!!>>\n\n\\subsection{Generating authorization key}\\label{subsec:generating-authorization-key} %%##$generating-authorization-key-title>>\n%%!!generating-authorization-key<<\nIn order to ensure proper security, an authorization key is required. To generate a authorization key, go to \\textbf{Settings} page and then \\textbf{Privacy} > \\textbf{Authorization Manager}.\nIf an authorization key has not been generated, it will be generated automatically. The key can be regenerated as required.\n\n\\begin{danger}{Caution}\n    Regenerating the authorization key can have some side effects such as invalidation of all the previously configured Intents.\n\\end{danger}\n%%!!>>\n\n\\subsection{Configuring tasks}\\label{subsec:at:general-configuration} %%##$general-configuration-title>>\n%%!!general-configuration<<\nThe activity \\texttt{io.github.muntashirakon.AppManager.crypto.auth.AuthFeatureDemultiplexer} is responsible for handling all the automations.\nSending an intent to the activity lets App Manager perform the designated operation by redirecting the \\texttt{Intent} to the designated activity or service.\n%%!!>>\n\n\\subsubsection{Required extras} %%##$required-extras-title>>\n%%!!required-extras<<\nIt has two primary extras required in all conditions. The key names, data types are all follows:\n\\begin{enumerate}\n    \\item \\textbf{\\texttt{auth}.} (String value) The authorization key as described in the earlier section.\n    \\item \\textbf{\\texttt{feature}.} (String value) Name of the feature. Supported features are described in the next section.\n\\end{enumerate}\n%%!!>>\n\n\\subsection{Features}\\label{subsec:at:features} %%##$features-title>>\n%%!!features<<\nApp Manager current support a single feature, namely \\texttt{profile}.\n%%!!>>\n\n\\subsection{Triggering a profile}\\label{subsec:triggering-a-profile} %%##$triggering-a-profile-title>>\n%%!!triggering-a-profile<<\nIn order to trigger a profile, \\texttt{feature} must have the value \\texttt{profile}. In addition, the following extras can be included:\n\\begin{enumerate}\n    \\item \\textbf{\\texttt{prof}.} (String value -- required) The name of the profile as displayed in the \\hyperref[sec:profiles-page]{Profiles page}.\n    \\item \\textbf{\\texttt{state}.} (String value -- optional) State of the profile -- currently \\texttt{on} or \\texttt{off} -- as specified in the documentation.\n    If this extra is not set, App Manager will display a prompt where a state must be selected. Therefore, for complete automation,\n    this option should be set.\n\\end{enumerate}\n%%!!>>\n"
  },
  {
    "path": "docs/raw/en/guide/backup-restore.tex",
    "content": "% SPDX-License-Identifier: GPL-3.0-or-later OR CC-BY-SA-4.0\n\\section{Back up/Restore}\\label{sec:backup-restore} %%##$section-title>>\n%%!!intro<<\nApp Manager has a modern, advanced and easy-to-use backup/restore system implemented from the scratch.\nThis is probably the only app that has the ability to restore not only the app or its data but also permissions and\nrules that you've configured within App Manager.\nYou can also choose to back up an app multiple times (with custom names) or for all users.\n\n\\begin{amseealso}\n    \\item \\hyperref[subsec:1-click-back-up]{1-Click Ops: Back up}\n    \\item \\hyperref[subsec:1-click-restore]{1-Click Ops: Restore}\n\\end{amseealso}\n%%!!>>\n\n\\subsection{Location}\\label{subsec:backup-location} %%##$location-title>>\n%%!!location<<\nBack up/restore is a part of \\hyperref[subsec:batch-operations]{batch operations}.\nIt is also located inside the \\hyperref[subsubsec:app-info-options-menu]{options menu} in the\n\\hyperref[subsec:app-info-tab]{App Info tab}.\nClicking on \\textbf{Backup/Restore} opens the \\textbf{Backup Options}.\nBackups are located at \\texttt{/storage/emulated/0/AppManager} by default.\nYou can configure custom backup location in the \\hyperref[subsubsec:backup-volume]{settings page} in which case the backups\nwill be located at the \\texttt{AppManager} folder in the selected volume.\n\n\\begin{tip}{Note}\n    If one or more selected apps do not have any backup, the \\textbf{Restore} and \\textbf{Delete Backup} options will\n    not be displayed.\n\\end{tip}\n%%!!>>\n\n\\subsection{Backup Options}\\label{subsec:backup-restore-backup-options} %%##$options-title>>\n%%!!options<<\nBackup options (internally known as backup flags) let you customise the backups on the fly.\nHowever, the customisations will not be remembered for the future backups.\nIf you want to customise this dialog, use \\hyperref[subsubsec:settings-backup-options]{Backup Options} in the \\hyperref[sec:settings-page]{Settings page}.\n\nA complete description of the backup options is given below:\n\\begin{itemize}\n    \\item \\textbf{APK files.} Whether to back up the APK files.\n    This includes the \\textit{base APK} file along with the \\texttt{split APK} files if they exist.\n\n    \\item \\textbf{Internal data.} Whether to back up the internal data directories.\n    These directories are located at \\texttt{/data/user/<user\\_id>} and (for Android N or later) \\texttt{/data/user\\_de/<user\\_id>}.\n\n    \\item \\textbf{External data.} Whether to back up data directories located in the internal memory as well as SD Card (if exists).\n    External data directories often contain non-essential app data or media files (instead of using the dedicated media folder) and may increase the backup size.\n    However, it might be essential for some apps.\n    Although it isn't checked by default (as it might dramatically increase the size of the backups), you may have to check it in order to ensure a smooth restore of your backups.\n    \\begin{warning}{Caution}\n        Internal data folders should always be backed up if you are going to back up the external data folders.\n        However, it could be useful to back up only the external folders if the app in question downloads a lot of assets from the Internet.\n    \\end{warning}\n\n    \\item \\textbf{OBB and media.} Whether to back up or restore the OBB and the media directories located in the\n    external storage or the SD Card.\n    This is useful for games and the graphical software which actually use these folders.\n\n    \\item \\textbf{Cache.} Android apps have multiple cache directories located at every data directories (both internal and external).\n    There are two types of cache: \\textbf{cache} and \\textbf{code cache}.\n    Disabling this option excludes both cache directories from all the data directories.\n    It is generally advised to exclude cache directories since most apps do not clear the cache regularly and usually handled by the OS itself.\n    Apps such as Telegram may use a very large cache (depending on the storage space) which may dramatically increase the backup size.\n    When it is disabled, AM also ignores the \\textbf{no\\_backup} directories.\n\n    \\item \\textbf{Extras.} Backup/restore app permissions, net policy, battery optimization, SSAID, etc., enabled by default.\n    Note that, blocking rules are applied \\textit{after} applying the extras.\n    So, if an item is present in both places, it will be overwritten (i.e., the one from the blocking rules will be used).\n\n    \\item \\textbf{Rules.} This option lets you back up blocking rules configured within App Manager.\n    This might come in handy if you have customised permissions or block some components using App Manager as they will\n    also be backed up or restored when you enable this option.\n\n    \\item \\textbf{Backup Multiple.} Whether this is a multiple backup.\n    By default, backups are saved using their user ID\\@.\n    Enabling this option allows you to create additional backups.\n    These backups use the current date-time as the default backup name, but you can also specify custom backup name\n    using the input field displayed when you click on the \\textbf{Backup} button.\n\n    \\item \\textbf{Custom users.} Backup or restore for the selected users instead of only the current user.\n    This option is only displayed if the system has more than one user.\n\n    \\item \\textbf{Skip signature checks.} When taking a backup, checksum of every file (as well as the signing\n    certificate(s) of the base APK file) is generated and stored in the \\texttt{checksums.txt} file.\n    When you restore the backup, the checksums are generated again and are matched with the checksums stored in the said file.\n    Enabling this option will disable the signature checks.\n    This option is applied only when you restore a backup.\n    During backup, the checksums are generated regardless of this option.\n    \\begin{warning}{Caution}\n        You should always disable this option to ensure that your backups are not modified by any third-party applications.\n        However, this would only work if you enabled encryption.\n    \\end{warning}\n\\end{itemize}\n\n\\seealsoinline{\\hyperref[subsubsec:settings-encryption]{Settings: Encryption}}\n%%!!>>\n\n\\subsection{Backup}\\label{subsec:backup-restore-backup} %%##$backup-title>>\n%%!!backup<<\nBackup respects all the backup options except \\textbf{Skip signature checks}.\nIf base backups (i.e., backups that don't have the \\textbf{Backup Multiple} option) already exist, you will get a warning as the backups will be overwritten.\nIf \\textbf{Backup Multiple} is set, you have an option to input the backup name, or you can leave it blank to use the current date-time.\n%%!!>>\n\n\\subsection{Restore}\\label{subsec:backup-restore-restore} %%##$restore-title>>\n%%!!restore<<\nRestore respects all the backup options and will fail if \\textbf{APK files} option is set, but the backup doesn't\ncontain such backups or in other cases, if the app isn't installed.\nWhen restoring backups for multiple packages, you can only restore the base backups (see \\hyperref[subsec:backup-restore-backup]{backup} section for an explanation).\nHowever, when restoring backups for a single package, you have the option to select which backup to restore.\nIf \\textbf{All users} option is set, AM will restore the selected backup for all users in the latter case but in the former case, it will restore base backups for the respective users.\n\n\\begin{tip}{Notice}\n    Apps that use storage access framework (SAF), SSAID or Android KeyStore works properly only after an immediate restart.\n\\end{tip}\n%%!!>>\n\n\\subsection{Delete Backup}\\label{subsec:backup-restore-delete-backup} %%##$delete-title>>\n%%!!delete<<\nDelete backup only respects \\textbf{All users} option and when it is selected, only the base backups for all users will be deleted with a prompt.\nWhen deleting backups for a single package, another dialog will be displayed where you can select the backups to delete.\n%%!!>>\n"
  },
  {
    "path": "docs/raw/en/guide/main.tex",
    "content": "% SPDX-License-Identifier: GPL-3.0-or-later OR CC-BY-SA-4.0\n\\chapter{Guides}\\label{ch:guides} %%##$guides-chapter-title>>\n\n\\input{guide/aot.tex}\n\\input{guide/wireless_debugging.tex}\n\\input{guide/backup-restore.tex}\n\\input{guide/automation.tex}\n\\input{guide/net-policy.tex}\n"
  },
  {
    "path": "docs/raw/en/guide/net-policy.tex",
    "content": "% SPDX-License-Identifier: GPL-3.0-or-later OR CC-BY-SA-4.0\n\\section{Net Policy}\\label{sec:net-policy} %%##$section-title>>\n%%!!intro<<\nShort for \\textbf{Network policy} or network policies.\nIt is usually located in the Android settings under \\textbf{Mobile data \\& Wifi} section in the app info page of an app.\nNot all policies are guaranteed to be included in this page (e.g.\\ Samsung), and not all settings are well-understood due to lack of documentation.\nApp Manager can display all the net policies declared in the \\href{https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/net/NetworkPolicyManager.java}{NetworkPolicyManager}.\nPolicies unknown to App Manager will have a \\textit{Unknown} prefix along with the policy constant name and number in the hexadecimal format.\nUnknown policies should be reported to App Manager for inclusion.\n\nNet policy allows a user to configure certain networking behaviour of an app without modifying the ip tables directly and/or running a firewall app.\nHowever, the features it offers largely depend on Android version and ROM. A list of known net policies are listed below:\n\n\\begin{enumerate}\n    \\item \\textbf{None} or \\textbf{\\texttt{POLICY\\_NONE}}: (AOSP) No specific network policy is set.\n    System can still assign rules depending on the nature of the app.\n\n    \\item \\textbf{Reject background data on metered networks} or \\textbf{\\texttt{POLICY\\_REJECT\\_METERED\\_BACKGROUND}}: (AOSP) Reject network usage on metered networks when the application is in background.\n\n    \\item \\textbf{Allow background data on metered networks even when Data Saver is on} or \\textbf{\\texttt{POLICY\\_ALLOW\\_METERED\\_BACKGROUND}}: (AOSP) Allow metered network use in the background even when data saving mode is enabled.\n\n    \\item \\textbf{Reject cellular data} or \\textbf{\\texttt{POLICY\\_REJECT\\_CELLULAR}} (Android 11+) or \\textbf{\\texttt{POLICY\\_REJECT\\_ON\\_DATA}} (up to Android 10): (Lineage OS) Reject mobile/cellular data.\n    Signals network unavailable to the configured app as if the mobile data is inactive.\n\n    \\item \\textbf{Reject VPN data} or \\textbf{\\texttt{POLICY\\_REJECT\\_VPN}} (Android 11+) or \\textbf{\\texttt{POLICY\\_REJECT\\_ON\\_VPN}} (up to Android 10): (Lineage OS) Reject VPN data.\n    Signals network unavailable to the configured app as if the VPN is inactive.\n\n    \\item \\textbf{Reject Wi-Fi data} or \\textbf{\\texttt{POLICY\\_REJECT\\_WIFI}} (Android 11+) or \\textbf{\\texttt{POLICY\\_REJECT\\_ON\\_WLAN}} (up to Android 10): (Lineage OS) Reject Wi-Fi data.\n    Signals network unavailable to the configured app as if the device is not connected to a Wi-Fi network.\n\n    \\item \\textbf{Disable network access} or \\textbf{\\texttt{POLICY\\_REJECT\\_ALL}} (Android 11+) or \\textbf{\\texttt{POLICY\\_NETWORK\\_ISOLATED}} (up to Android 10): (Lineage OS) Reject network access in all circumstances.\n    This is not the same as enforcing the other three policies above, and is the recommended policy for dodgy apps.\n    If this policy is enforced, there is no need to enforce the other policies.\n\n    \\item \\textbf{\\texttt{POLICY\\_ALLOW\\_METERED\\_IN\\_ROAMING}}: (Samsung) Possibly allow metered network use during roaming.\n    Exact meaning is currently unknown.\n\n    \\item \\textbf{\\texttt{POLICY\\_ALLOW\\_WHITELIST\\_IN\\_ROAMING}}: (Samsung) Possibly allow network use during roaming.\n    Exact meaning is currently unknown.\n\n    \\item \\textbf{Reject data on metered networks} or \\textbf{\\texttt{POLICY\\_REJECT\\_METERED}}: (Motorola) Reject network usage if it is a metered network.\n\n    \\item \\textbf{Reject background data} or \\textbf{\\texttt{POLICY\\_REJECT\\_BACKGROUND}}: (Motorola) Reject network usage in the background.\n\n    \\item \\textbf{Disable network access} or \\textbf{\\texttt{POLICY\\_REJECT\\_ALL}}: (Motorola) Reject network access altogether.\n    Like Lineage OS, it blocks internet connections via iptables. But whether it signals the unavailability of network to the configured app is not known.\n\\end{enumerate}\n\n\\begin{tip}{Note}\n    Corresponding Lineage OS patches are as follows:\n    \\begin{enumerate}\n        \\item \\href{https://github.com/LineageOS/android\\_frameworks\\_base/commit/a04932bafbbf7d99efd18276152cc2c9c9b2073e}{fw/b: Squash of app fw restriction commits}\n        \\item \\href{https://github.com/LineageOS/android\\_frameworks\\_base/commit/02c8c82854348f52afe2199f310f44b5f578b5b8}{fw/b: Add support for per app network isolation}\n    \\end{enumerate}\n\\end{tip}\n%%!!>>\n"
  },
  {
    "path": "docs/raw/en/guide/wireless_debugging.tex",
    "content": "% SPDX-License-Identifier: GPL-3.0-or-later OR CC-BY-SA-4.0\n\\section{Wireless Debugging}\\label{sec:wireless-debugging} %%##$section-title>>\n%%!!intro<<\nIf you are running Android 11 or later and capable of connecting to a Wi-Fi network for, at least, a few moments,\nWireless Debugging is the recommended approach as it offers more protection than \\hyperref[sec:adb-over-tcp]{ADB over TCP}.\nIt requires two steps:\n\\begin{enumerate}\n    \\item \\textbf{ADB pairing.} The initial and a bit complex step for a novice user. Fortunately,\n    this step is not required all the time.\n    \\item \\textbf{Connecting to ADB.} Needs to be done every time you reboot your phone. App Manager\n    can also automate this step in most devices.\n\\end{enumerate}\n%%!!>>\n\n\\subsection{Enable developer options and USB Debugging}\\label{subsec:enable-developer-options-and-usb-debugging} %%##$enable-developer-options-and-usb-debugging-title>>\n%%!!enable-developer-options-and-usb-debugging<<\nSee \\Sref{subsec:enable-developer-options} and \\Sref{subsec:enable-usb-debugging}.\n%%!!>>\n\n\\subsection{Enable Wireless Debugging}\\label{subsec:enable-wireless-debugging} %%##$enable-wireless-debugging-title>>\n%%!!enable-wireless-debugging<<\nIn the \\textbf{Developer options} page, find \\textbf{Wireless debugging} and click to open it. In\nthe new page, turn on \\textit{Use wireless debugging}. Depending on the operating system, you might\nsee a dialog prompt asking you to verify your decision. If that is the case, click \\textit{Allow}.\n\n\\begin{tip}{Tip}\n    For easy access, you might want to add \\textbf{Wireless debugging} in the notification tiles\n    section. To do this, find \\textbf{Quick settings developer tiles} in the \\textbf{Developer\n    options} page and click to open it. In the new window, enable \\textit{Wireless debugging}.\n    In case you do not see this setting, you may find a \\textbf{Wireless debugging} tile in the tile\n    customization panel.\n\\end{tip}\n%%!!>>\n\n\\subsection{Pair ADB with App Manager}\\label{subsec:pair-adb-with-app-manager} %%##$pair-adb-with-appmanager-title>>\n%%!!pair-adb-with-app-manager<<\nIn App Manager, navigate to \\textbf{Settings} > \\hyperref[subsec:mode-of-operation]{Mode of operation}\nand then enable \\textit{Wireless debugging}. At this, App Manager will try to establish a wireless\ndebugging connection automatically which will fail if it has not been paired before. Once it fails,\nit will ask you to either connect or pair ADB\\@. Select \\textit{pair} and a new dialog will appear.\nIt will ask you to navigate to the \\textbf{Wireless debugging} page.\n\n\\begin{tip}{Note}\n    As of v4.0.0, pairing is done using a notification prompt. So, if you have disabled notification\n    for App Manager, you must enable it first.\n\\end{tip}\n\nIn the \\textbf{Wireless debugging} page, select \\textbf{Pair device with pairing code}. At this, a\ndialog containing a pairing code will be displayed. A notification asking for the pairing code will\nalso be visible almost instantly. Insert the pairing code in the input box in the notification\nand click \\textit{pair}. If the pairing is successful, App Manager will display notification with\nthe message ``paired'', and the dialog in the \\textbf{Wireless debugging} page will be dismissed\nautomatically. You will also be able to see App Manager listed as an ADB client in the same page.\n\n\\begin{tip}{Notice}\n    If you do not use App Manager in ADB mode for a while, App Manager might be removed from the\n    list of clients. In that case, you have to repeat the above procedure.\n\\end{tip}\n%%!!>>\n\n\\subsection{Connect App Manager to ADB}\\label{subsec:connect-app-manager-to-adb} %%##$connect-am-to-adb-title>>\n%%!!connect-am-to-adb<<\nApp Manager should be able to connect to ADB automatically if the mode of operation is set to\n\\textit{auto}, \\textit{ADB over TCP} or \\textit{Wireless debugging}. If this is not the case, select\n\\textit{Wireless debugging} in \\textbf{Settings} > \\hyperref[subsec:mode-of-operation]{Mode of operation}.\nIf App Manager fails to detect or connect to ADB, it will ask you to connect or pair ADB. Select\n\\textit{connect}.\n\nNow, navigate to the \\textbf{Wireless debugging} page in Android settings, and note down the port\nnumber displayed in the page. In App Manager's dialog prompt, replace the port number with the one\nyou have noted earlier, and click \\textit{connect}.\n\nOnce a connection has been established, you can disable \\textbf{Wireless debugging} in Android settings.\n\n\\begin{danger}{Caution}\n    Never disable \\textbf{USB Debugging} or any other additional options described in \\Sref{subsec:enable-developer-options-and-usb-debugging}.\n    If you do this, the remote server used by App Manager will be stopped, and you may have to start all over again.\n\\end{danger}\n%%!!>>"
  },
  {
    "path": "docs/raw/en/images/appops.drawio",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later OR CC-BY-SA-4.0 -->\n<mxfile host=\"Electron\" modified=\"2022-02-10T06:33:32.464Z\" agent=\"5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/15.4.0 Chrome/91.0.4472.164 Electron/13.5.0 Safari/537.36\" version=\"15.4.0\" etag=\"Ukx45r_3ZvZvyicD9gHN\" type=\"device\"><diagram id=\"_3i6XxWqvhupi8UbKG9B\" name=\"Page-1\">7VnbcuI4EP0aHpMyvhEegQzZ2kpmqGGrNjNvwha2NrbllUUC+fpt2ZLvDoYxZLdq80CkltS6nKPTLRgZi3D/wFDsP1EXByNdc/cj436k63cTHT6F4ZAZLFPLDB4jbmYaF4Y1ecfSqLrtiIuTSkdOacBJXDU6NIqwwys2xBh9q3bb0qA6a4w8OaNWGNYOCnCj25/E5b7clj4p7L9h4vlq5rE9zVpCpDpLx4mPXPpWMhlfRsaCUcqzUrhf4ECcnTqXbNyyozVfGMMR7zPg+W7zsDdmSTT9aX39431FV9/5jfTyioKd3PAschmFMbodgNv5homl84M8D/vvnVjvfEsjfpOkaM2gw9iKAfB50Q4lT/xfY85J5CXyCHI/OqO7yMViaRp0e/MJx+sYOaL1DYgENp+HAdTGcjZJjbEFdY8hl8C27wkDzAmNxCic8FLTggaUpVMZU/hbLoUbEgTKHtEIS89LFJJA0HOFAgSrpen664erTgozjvclkzzsB0xDzNkBuqjWiQReMl+3Zf2t4NHYkDa/xCHVD0nqernrAl0oSIBPAFtvgK1QFsfQG+cGyLM4/hYnTyiCy8CUS1hh5jXrc3kCYNRFgOVybtj21QlgTKsEmLbgb14Tf3MY/NvueUaBNWavBCDsSQFQxFgUY0YdnCTHabBBzouXEufbjgckwh306AK1hRvbLbI0rYNSCd0JpNp4MwQ/7noIhH1NglgXEojf0SuCxpwesH4bhQLc7BMsXwGjV1zuVMQfRZ8OVnV1JMrwSB2UIqovxARP66zgoBAzlJXRziU0K2Lu3JbmIsMp2EeU7KdkeSjzAiQuTDpznliklRdYvy8rl+Gtbdd4a/bk7Vi7FHHtBnFRHNM4ud0DAF2y4xxAQlzMjB7Ck0H9uDmmRElJhdw2JWlRqrVcmn6acmFkb9KoVsH/MpCbWhVyoy2W6deUqkmLVNVwxpE7Ey8AqG0C6rxUIcV7wp/Fod1asvaj1HK/l+eZVg6qErlLItapagpKU8DAEVPYClig6mG+wozAjjET5IJMWI79axfGCvdzMxHgFHPw8XwPu+qJ0wFyCUSrBUNlYzjIRLryxmoBVs6woiQNGh3pkD6pcSPbjxxVfsjUHJl1/dFrjuTJ1x2lPMu3fT71xsZJ3HOEVBOnO6HtZqN2hI2wj+dy5UfhQVSLYWlNjXN27DUNWx/FpfNZp17pKQgDsPNXaVdnizEU7eqOOmgHPECHUrdYdEi6F6zX5hlblXc9FDKPw3K6+22QxChSOdDCR5EnsrQYs5AArUVS1ZJ/ZWldtEnSHC9JqEMQB84JrQGpgcOIY/iECF3vXMq8yhM3LxjQ5hFtMOxyzjCEXbRJm7TqPUMB8UT8dYDG8DY15iLmEQcFM9kQEtcVA+eBcDbPw/rZz8QPJUN+SyXXOsqVq0ck/sVrUCOVqVcd0O02wZdRy7ZHxVBqWdbKXDk71BIqeTBuKGghmnkW8IGCpqG+ueLULBOEy2ir3VNbzU/S1nok/s+E9OYDoi5MjxS5QpQ4ZXUB1Ei0pU0hO0GxhpKpJEsyH/GWK6pmlu8yndNyF5TB06c2vHTlfMrIO/AXKUOS568fvVOEXTl18RbtAn6CSlqfrZIT81qyqLcF3G5ZbALU0MQzs0GlpUpX+2hpT/2rPpeGV0Ozpxpa/6vhadxs/R6wom4LH8ODupYHnq9//76MTd3PT9AiifrNuIb6BcWoLfwNI0bVxEo7IkYna8RgmdB1vgM5erN7S4RZc3Q3lERAtfhNOute/LBvfPkH</diagram></mxfile>"
  },
  {
    "path": "docs/raw/en/images/main_page_entry_info_labeled.drawio",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later OR CC-BY-SA-4.0 -->\n<mxfile host=\"Electron\" modified=\"2022-02-10T07:10:38.030Z\" agent=\"5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/15.4.0 Chrome/91.0.4472.164 Electron/13.5.0 Safari/537.36\" etag=\"V01vGRo2H8n8E0BvjPjq\" version=\"15.4.0\" type=\"device\"><diagram id=\"1__146syWW9rmBwxSfKT\" name=\"Page-1\">7L3XluNG0jX6NLqcWfDmEt4ShCHszVkgYQkPwj/9QVZ1y3SXvtGMWi39M+rVVUXCMZERsWPvyETyB5RrNmmM++LSJWn9AwIl2w8o/wOCUCRy/gYb9vcNOAa9b8jHMnnfBP+0wSmP9NPGz4fNZZK+fnHg1HX1VPa/3Pjo2jZ9TL/YFo9jt/7ysKyrf/mpfZynX21wHnH99Va/TKbi01aYoH/aIadlXnz+aALH3vc08eejP93Kq4iTbv3ZJlT4AeXGrpveXzUbl9ag8z53zPt54q/s/bFlY9pOv+WEtEAEravdmTBfbneQ5mOd//HpKktcz5/u+FNjp/1zF4zd3CYpuAj0A8quRTmlTh8/wN71tPm5rZia+nwHny9f09hVP3YV2NKnY9mkUzqCk8o2/3Sd9wO5ru7Gc0uSZvFcn7fBZmVdf976A4JCb/9gBuzp2umTgyDY+f7r+/98M+k4pdvPNn3qDyntzoaM+3nIp70I+ck2n7wT+eyd60+2pohP24qfm5n+tDH+5F/5j9f+yQLni09G+DcMgn9lEDZ+VHP/lVnOW5w+6vufdR7BUQIrMtDX3cozAiVyb3viuszbc+vj7Mb03M2C7ivPCGA+7WjKJAEf+qHpf+kcPzcR8o1MRJH/xH9hJJT42kgk/rWN0D/KRMRXJiq7f+blVMz3fzZzO8Wvohzjqmv/yfT9JW5PiBj/E/NRCIsSxIfmwwWKx35hvjrNpm9gvE8NRL4wJvVtjIlS8C/jjSK/MiUO0d/RluRXtjxtdm74HWb7t6Lu25oN/k5mw/E/2WzUB2mLeMsfrz5uf2EyYpi76VO//OP11jHMeQCC9dtPO89XOfh73oMInz4hgh55v+D55v2a70f8Jx7BkzQLQR95hCgKBPdHesSXqPyNEueXHoHC9NeY/D0dgv7dDgFTp0O8ecIXPsEZ52mXz7h+HsnU/1Beddz8gHD6uYsv4io+X3Pna5b/hm7zJ+L/F24D/0FAguLwnwwkn3XGH+E4ejylr+k84v7O4N6ORoEYivfX6TDnKy8dX2XXfoKkfxL/xL6h//yJieh7+Q+Ffj//CWzTbWXyei9LiWzMZ0NDw4f66T9IRB+5z3+vO3yrLETD/5qXwPgH8u0Pcwfk97vDr6GJ+wJ0FP2vzC/fiqh+5RAf6Ivv6xDoH+cQDq+BfAL9dxLVP8gjPiKq39cjsD+OcDgyg+DEWk6F7TD/lUDxrYjEV27xARH9vm7xdd3vm7lF3Fc/IGwST/F/JZv4w3ziA3L5fX0C/gZ0AvoVp4AhmMD/rNQxvnfeVw4xdf3vThzQt/EGCv3l0MBHieOjkYE/zhm+Ljt/Nt/9s+Hea5d1fAeDcD+a9v6TXcU2btL/KNwfVHrPflOwf+uBhM/vxbgpa2ANM67jqWy7c/vbrYIBkvzt/M8Na7s2/TZugOHQF8MP8AfDD/D39QT6Kwv+sve6cSq6vGvjWu9ARL2Z9JlO0/6pT+N56n5p8LOHxj34dP7bmxC8+SeJf37Pbz/fy++/YqlfSRRv5yUMGJH9yT7nFrEE987/n0H76ubxkf5fHfKpHDzFY55OvyGG0uQXo75fW39MgYst6S/a8e0N+VEZ+wvLvoq4fwuTeO+7sn3D/iqdHsXn/j878DMUvroafB77Dv88cb58OycdheXs1NcnW79te7sXnP0B578I6k+2GdPzKvH9R4gdu+kkED+9/3FY98eIN3/awr7auL915nuDvxqW+L/95Osh5G8Qxyj9xUgv/nUUYx8EMfaHVQrQr0wNvPKzKT9b4dvF9T8R/OehDf+bcf2vovdXRMPviusfZ3z8q7j+HDd/kbhGPqoK/q/G9Y9+8IfENU5+mZ+RD2j7943sX2ftPzIx86QsYOYRAr0Tso+42n+i0+/vXf2vVfp/FUkjvuDqH1K071sHJr43upPfF93f5d7vQ3fst6I7/tdC948qeP+r6P6jH/wh6E5hX4pw7E/G9l8v0/2I3K7CfytAT0j6Dv22ksp/F6CTX4zjQB9M+fuueP71PLFvVokDffFpSsBfaiDnL1SMw77wh+853ehjf/j1CWg/Brwev03+mPsknn6F4kHvu/4Ght/sCMQXMv4DYPi+xbjPF/6v1fHfgunRv5XpUX8tpvfRrMK/md5XTO/jzPEtwh36i/E/9OvKzhcw/wnSoR8E5AcK+oFGf9pUtq8prusTBv5G/N9OBeEvCzzYBw/p/EgIvg/m/8m1259Q/o/G/HQrp/cW4CcYvr9/HxjCEPjT+58aAd7sP3vzM8T5nSM8KPIbM8jnAP2LZJDP7f47g/xZGYT+Ej7+/Bzy6zPAfpQGztkN4FlJkDSy7u/68Ld2Aoz6QDdQPx71fbLId68Rf+cs8g1GAFH8t+I+9tfC/Y/qhP+ruP/HjgB+PUMHxYg/GeG/rhb++CzQV1D/6eGgX0f6sTkdtmv/E8D/X521hWL/WjIg33fW93+7ZPhx+s7vAPvfOo3rc3z9VcD+72lc320aF/QF1H/wxNd3hXrsa1P/EXH97cLzR4SAfwEP//xX8zx/R1j/1urvXy2s/67+fq+wppEvwpqk/uSwhr8y9R+crv+fy9af+/7/tbD+3O6/w/q7T7r+88Ma/95hTf4/V3LBfuu0vL9YyQX7e1re9yq50MgXcf3HFVzAqgfX+xMs7fj5wbaPK+bvj75Ne/9rU23AY9FvVZazU9PX9F5dz+o4f703qi7b6vO10dd8f6WPH1Cmicv2H2CRx3/EfV+Xj7dSzD/Ax3w67f/2SeJn/fjJif8u2f8mF/tiZUb4o4L9RxN98H/fx863P3OzfwdyqD+VJf6/8AgPRv7GbIL9tR7Nwz6a8Pl3NvlDsskXk7wRCvmLZJPl0+pcHyYUIm4Afrb319s02d+ZXT591D/eBwH+dWKhf29i+V8dGiC/0CTwB0MD8Edzy79nYsH/3PLDH55YvkH5Af+t5QeM/kslFvzv8sP3qyr+xZ75xpEPbP9F5rm9+zMCvS3v9aGS+TEtIf826v+vziKlMfw3zCKFKey7zgD6/FUB/61V5m/w6ACO/kaY/xxbfxWY/2jhv/9VmP8zJn7Sn0fl/yrTPuF/wyPK5u1rSdi3v8yrf/9mE+hn/aUDxDS7V/k2NQjl7900dc2vduj/baKfvn3jawP93H9+Ou5TA/m3ReVQ5v0tIvZA9nClx17tFdKkvGPOf4bjFoKbn6885fwlOhwTnn+5HPay5XyhXpqat2C2ivyoSPwNClC1DUu8D5ELwwilWkde66pGJFLZQh1HX7iMY3WJZeHCoIacK4hdBw1zZ13LxBW8V6nnnIYNiiH4lm0JQaC6ZQy5LofNHFNEUL6v3D72m+iJrB/wmRShqHz7AWFPjxHxmjzeLI2wj/Pnnj7etj4YIS8Vo14fExnWGrEai/osqlC8rAK6l5cWv3NUZkMMWEHemzeBGR82OZ+JXDTPy8SYIkTiqSnFq4/N+na6E+s0XHL2AikF/iH0pp9Kzx1azefbh4tcBCfhSzzyy0SHWHqKSzFNN/0YqVNRsr3+JCg4yQpXY9j1vC5bvK7nIdjJE0TQ7vO/5vElRxtlt0t7c0NV9wS+UFG1aJoUVe4znWatyqbcxpbxGwVa6Z0ns0htI3E7Qvb8eHWNddrjxo9HtmLw5clArEi31OM+OhhV2Au42QNJxIBEqzTnw8fKnA7AkjiBRS6TXDHOMkfbg+hpjs/tbsYwBLkwB6u24H6G0uMtSMkZvbOYsGNqP+cChxVuDF+/GP/KMAHGiJRl8yFj5jlbWhzzyLnZZ+TztsWQpTBO6xndz5lbzHgtEycYv2PMQPCnCVlmlpjYzG32kvcJwxoEy1ol92KZqKuEvWK1ip9rxi6Y+6sLHwqfKdI6cNYgdhrTarmsFa3H2B7Te1bgWcLZYktPGIJgJkRgB0mG+Bxizq2QkYWW3TC3W2h5IUPHMnJj5KTzaCzzVkNdNZzicUokQMvkG6UkFBtgxnO9nEjCSgHFrpzA6ZylWnYQOsaDFUyVLVUrvyneYFmamw2VF1fSeXTNk+XpG+wdzy9aHnN54xRJXQYq2BnL2CDeXK+2tiHvYWbyWaIKEgtDnrb2NGNejeUB4aeKPyBF7mLZ8uecTZ4NLkzEdenCzAYrRRaoxOxS7ovFwfPXhmMvshSeYVccknGV5nCNNmHL8ZENR2bzWWQW6Qcnhcl1Y5NCI4X2paarlRQ6KVeZoKXS5aEQWCiujp7TwbNZpOBhGVgcrRxabAs/psx8fiz7pNhl7bP8vBWRT84t/II52cpZoc4odW5nTL0VLCJwlTJidl88TU5yOGcQLogavOwQa6OSzQSXsqKtNUvW5ry+IstKEBUpdgA8Xa/VTjhyz0f1BS75e9WZKpE6NM7ddy9Tb1T72pq+TCWBelnNfvd1Lyzo0kK4l9YO6hXzGMSVlQ6PrKPmZ9cPJGpWQsw7tkumTdiU5TjlydvVauJCk4QCckpbF4UXZRulXw310LNJzEquee03oggG+wIVWqRhtI5NKgKxUwcjpZVYSGanmXWGvUxHZ8M7JnBstb45Pq1ml3rY/YVj+ohjLrwVm9WD6cJoa548A2ClrJVHbJV9FimT2xnOA9Z3qL07VaKJ0IA6Fq1nuF3sz6eyXZbXmbjYxk0dTa8m36cj3aieUJlCMOJ12BztrVzvs3vdUdRhCR/G72g9Ua8MAhAWoPjV8mTWcUSx8/RieGkvpTJt7yleX+6xdbN2ESpU9cvaH9yjryZF70vntkJb7j1ZsnHUOvW9Fj+78zq7LG6dztsNmdPjWkN1Ny9UBv/wtMndYRv2q364NeNJC+BBRxwWWY46Nl2A3BU6ANQbKdnhDD4cE6m/PBAnWsTwGq8+3OeNnxjSBfaPYDmBkhWrWB9tf0m85zg+49c9VpKz76fMfcjwU/bOTIKP/AlgI6plYuAMS+91ZFcFIT73DaGTJx21KNrQT7rALu474noLKBuyLxN/ey/eSPpYw4bNKwnYiY8bSe8ivJgQKdumHvi5ZAwdOo97vCT1Tt+DICCmTLq+Ynur0ouMP62bsRlJv0CNvO7G7eI1ehwffdk3oR/DUWm85vp1Q8Pt/EgsxJHpuGbqgqfZxRSH0CfsuNUzYod1/zIhO9KKJO8XV7xvZKNQfc2LCq+NAqtpqiRuUddvyuedNRoX5MDjEO+e8dIQKIi1jvJVDD+qRVeOF2uGU7IYjx3BfLIMSFsk1fOECQDaKshDd80sPOBd6OFtyFMWq9SusPYWDZl+NCesnodl9DFcKNYmMpiybnNU4ndZ7hPHB503Fv58ww8IDW+z7JMruLmZzLPHRsfDCMExwPeKNeU8ZY89TXWFco+TEJ5IpGJp0HvpgaLGcrvSKXl0Wf2ipRZJ02TE4aU8T6ULEziwyI9UmmEguZYnPWOt84WMMJnLdjlvWCbKqtgVyhGNjztty+8ksOpD4nf0aORkDfyb4oQF6whPAm7HF51lKMeRii/zRYi4T1+4H5hTWqvBNdAlWI+DI15ms7ZtYaRCafYJ+GCT2tdnXOqS0kDlsBuyMuzlMBhSRyDlSFimfXkK8CV9bC+dTxFtieBWNh73ZKMWIaOok6EVCidMlf0Im2c5O/bgtptzJ9Xy0d73UOmvTiVpF8MtaZ8bnCszxMLOn5KqTeLgVh9nIwDjyA/jKUIRhrd+k/gRSZrUi8IrB7HaKEsWaCKgiDbcZ2Neb/hkN4AF31NU8x5oVj3B2+KutffzVg2UHo5b4AEyMt5V0iXvIEjXnFSeGeXNqeXhPTrNCXObSWoL9gmsT2ySsh7DnpJ7JdNJBjzN9+W0lGW+btSFFBu6R3UTpzRlrSeRrYLaDhfQ7qt6N7fxvIJvys+zld1iXeq+9GS6kRE1he6If+4Edwk5vS3VV+JhsfR6SaLHvq+jhrLHI13Eeg5EnCxlpsNwbl0HpBxgbXqc8CjWYe1d4ICDg/OensFhtP2Ir5skFxgZyk0zeXE+DQuMGea9y4+hnTuceGanysaLZ/NIUwN0L0qbKCARQ9O793gbzJMKxLfnWpipig73Qx3iZvbvDjzmdbf7TXQp1HccATzUpA+POGkUDN07Au1EvvQe6SjqBECRp7ohZgIfRYs0dHwQSNQjfjsVLO1sg2u6UnLpSWYcpOfRPgaiRUgNfMmRl9IBBkLRO/Asc+XdetXi+gqoEpqDR0kagUvgpvyWIl69cFBxusEPfqTJhU67ZL5GBPmIYAA9UwD6uKBrBA/RGwgoAIx6M3vLy8cR9ObTKK2eTgRitKHqhcyvNbNtyHGFYfRIaYQ/OePCF9UFvdXtgtDEeWSC0whljhuUyqZwT29MfCl7SjBFwDIbmVvp1LwU1GQa4DaKAhszTgf02NwB1zZMAiUB1ty3a8yBuL+AxZtE1AQ7cbotOfBK3p8kiHyxzI4Wv2Y1RPW3m2dIEJK1qPSYs6lEw0Wt92oRkVAHTOKGARoee/gwHxl9slkWdihNFAAuieOWAgxbsOdjv4MZwqyBghreGcMYnUUZdm8AXaN09HL+OanDm5UJM4+oVhwV/2XNXns4oFtvNJIFByLqJTQpgIGWu7X0N4NnXkBbSWE1yTZzakeRMSlARgmO7vEL2Kc+hCI6GTmjl+d7DnsyQVmbKNBeTJYIXpiIxhK1NhoGas0IiXXjWDmW6CORjeejqdeEY3D96R7601habW3P83JGqAXLs7H2iiYBtCUwCbUUuJlHce2EsHFNb38KGzIE0ZFTLFPJylI7Vy8vjxNyneXK7I95ItfrfjJNcalwTq427/GcnatoGlt8gVUHhCvBg9+t1qipzQ4OzlXhfnNIeBeZ5xwJ2KBt/WM/msugthrmlVhGRAUJoebMHxnwsQj8vqMKIVVcGr+EFxGg8DhOgE+x5EC/qyxnVkqtwA+iShmjZjlZ4FamAv1oMY/3yKMASMNvUXJzZ+a6AKq6MsD8wOcTZmV6PNqdU9/Bkma7xi4JzE5175RAEKO0kfdQZYIM2A8efNeBAV8APpMzp5L21NBS1kVdH9pdlfVtmOZPGjDS3NdQII5mPdmyYhnFskDrRWN1gdbLUH8Af1vXf+m3XEVu7kCCNsmbxlhRzy31jdYNzG9Oc1wuEHobUj1vLw+3ylu7rLRUNGFAm/xMZCh4Fr1RNte893TGaRlF91wn8aJr47f4BWUHOG79GI1LSByEG0XZb3d34lyJJdwB5+IlJ8RBtuIes8t0a7TO72w2LvNiY9zVlCC7uPZwkkth6Z5XAIEHQUwAkBFEj5r0A+8RXuodkDUUgP3DDOhB2q4v6F4l5Sn8chggqXKwivEIhgrqXmu0IC9o9ETFcC+gM9RubQBdGOyW9YJBNc8Qeig5HIIIz+4UQxKW7d48MVWnW0XvDyi/8h4HUDRxKsXl7xf3uHJogKdcnFs5bLEmxLSr6ZnlC3sszODlccfkh83yIqsxjOGBvrY6600hslzNiJrjc7naFaz0BO0VkIoLmEtthGqSNbi2nZRBKoBcf6ZVLGlcVUDNenc6hDe000nYEIVgEMysa6im4BHhbejSUoLCnhV6xC1jl4f8rhh9xjuAYGtqSNIsmzIS1lwFtHrlL+C8DFenc6vcRAXcO5OhqGCYCizg5cgBOQ68zDc95nYJ83ukWFhhrBIIS8RX1KDNtGZwwtVhFwENyl2WM7ShmHy0L2i1F+LMtl53TTyeYoSsCAhzlSnL9MKS1XPGLAvsyKMNlfzASOhR7pm5MUQ/NwOrbGs4l04k7PvEOhxuzJ839MaocoZoyNWqX4Jud08tnOiePfcLCyFBz2AVHolQ27eiSBuI6OSuUCfDbKkhA+nnsReGV63CSjyL69Z6CTmPpK+KJXCJZ2skwVPh9YvQsSgiXzRZFGjG8AXByBiB8wb7CcoFAKOfUx43PjI0tHDVBOwoslxHClsSK8z0H2YbJfS+eDks1LUrg+hb7zTzPBrHdrwXRj6Xa4gdddLfr6yJ2l0PQ1c17AMtSQx3jGSix62wq24bYSUr+g4RnBPCrqeBeMoAJrTUiX434bZplEL6/aCJZTvmJw+CgIYF2FQzpejgmgaMOMrV7TEa+IsaHsFECZbq6TWL1B06ngLIhCz8gVFVMLTyI8GPIEikxOXLcPYsr3O6M7UWQg5i8RbLQ+CxfquoF+jqOqDISU9LHPtjEG0sbiulEZ4CabhFzG4rzSWs/dAvpIoXhVKBq1v/CmXNvbq7VPiF1trWo7PUu8ZRvjjc1bdzXmHrhNIEkA8/Sc8b50yDsBAinQwYvjwpXhWLhP2aynSvR/EMHhYKxberyr1UDNVmpWOGtVYGPhVIFP+eTJIquGL8KNxU35nC6bLbcz5lkUaQvdzl9I2vi3ZLz92uOSWX1NV6upIHcyejUqIawQ3mKW9MPZGIJ2wpF0teBEcUahE/cypt4xt+uzuTA3BfShW3F/iOOd+IOuTofoMjD0dKd4Wwr7OUpQg3SY4MHCnwwl0ox8w6ncIMkwRZPGC76sIiLT1ljFE+Sm2mbnKQ7VPSv4RKpZiG5ehbqTjSEt9veO/igqa4d1bg/BLp9NpE4M6NwDYsjx4gxmdSuQYt2dtJwCvMBeSqqY6OhuIYU89m45miJ3XVWX92TvYyFJjQCUDooF0mqviDQODFBvRuYjw6YsklH4nL0ODLQ1T9jUxWUPu8w/tLDAfs3V0ZG87H+JDJ56PCtWsME8Jl4GEjOplpdOEo4mEq94J5yLkqucjUxutL1BlS04Vtiq/ELAud9cxvTlvPr/4EUNgBmToxBtK/vvjx7h8CAivQob5ROj25lumzAG3G70eDl3FAwxk38kqr3nY5cnmXjatsBEWSO8Krc1Pc+zxYlh7lKYXNc1X36+V6n3n5gPQIsELCcanG8HQC2x2J4iUxANm9FmLygpb5qRovAq9qonkMZAGrwMlu7OTf3aqrwYFYz3nqXS+NfiftPNMseT31He1xSjNq2xReRuOdtUduj8zrutw2EF+mKuMCLNHwZcEemZf56w1E2Lq3FJnOydAlHKw7QYCMLKXwDNq/lXONZAdB761rqzDWJQCX7k7nTS/YtEpUu9xGe6hGAqTLG5jZwj5fJGyA1iiTFBAQT0LW9m64zJeIQRKSpN9ajX7AEAyJQBXZium3NJs62QXpWEfWzrP3W0pg+ft5dFpYuobRLr/7L+jEOECeNxh9JOris6Xlj3ytY6f6EbInYB+Z4o6AvM3EaCNId2OvGVY+/F4hn4Fisj2eEq8c52tRKU4w3RR3M68YdmBkPysL1Qp5DW4Z0sBvXBdiygdewN1owNlAgQGWnw7SlPYpZQGXy687BTg+Oh5vfjDOU3pLNTnMyVvVNdETsK2ndv4yU/uKkOJsSeW8+OeHicsnjpdRxvTOueA77Koj3MwXrHGcBpCc+tEdDzaHqOVpwXAH6gZBF3ShLfThw2CrFcjXrPRO3p4OWX/LEKvXr3QdX0BXOZ2cx/alQSKx3VYyR09j5iP9Amzl4aXV1oUdI64x6V1oljuxu52P/mSXombPwNymUJ/X7YAb1g0ZEYs7vLUgzDqTh8VKV8soCJejpNIdSe3lYkIXdgCaI3jioL4wLpCtk0i3tWAkY1pkn5uxocscncuuKs5LXiRe1yvT5laMIrZpu1v0OJ5mIaKNXR4boK02tHcgHll/YXhrc/Bx2J5vBD3I8Sdy9wgF818xmpIukhDamhAvohFDBS2lisHeUObcPqRFIQGxcBjNRFTmyZRnloQ7qCp5T7kPtSTFstPgdbKFQF0VRCM8VmHG1qM+qKKcb+V7xotCYWXKLOs7WDRIbKdHoz2GLocSa7OYU69rs6wf7dwXkvaaIETngSCzOVhAicrye5RIgK7XDF438wJ6aNMVbT2LKLrrne53DF2d+rnLXQPJzqiV063D24VpCsrCbzGSjDYoHZ2UhiDD5jU4T9zf3Vs22KwG6JMiXe/kehLupgwpc4PQ0Egjsn2ORJ5atVVqAITKoSqNEQrZB3MplTK6NCuapd5d65ZEjUSvJzgO7u1OXI04LNXCqqJutXs4MuRZ75ny0pUa3BVDTai5dVLCS2UrJwdxY6160mKujEMtMwPwzN3pq/1+i+qWdUjIgKXwzGbeYEC50HhtVT97rxTJcpquVTFdL54A3S59qxfHbfc4MfQKrdZHa3IqweA87rYgjEtOw8PuGnUumrwHcbq6UW9al4okZLVDvLDIhmgoGo1W9ItZSio2mE4qVlCd94ILBQUicfU1j/oKCW72a9ke4ybjsvtSYt5j8o3rjGUhMqwRn8XjcVX5phnEeIhOS2ASjnVyGUpDeLa8LpN7HHrDIJx5Po2A/qqriqRzOWUqrzb4nb6TVoknXef5dpn4WdlwNcKLqrNRtnUZJa2fcni51m6C8wSA7RnfXctr7h1/PLn6UvTx2uyVMgexJnpV+HTji9y+RHWWjB4duFq93w7VToT9xLtnYbOB2wYt7A3Oyx6aAXH9Ps0Lo4ERl+TS+jGP1yU486XakTYEofNebEnQRR6RBq8765zM/sEYxLOG4ERefapf1gzwUsI74ykPkZcMpN91bETEDSTSWteqsGUKVCDEghtdOidPL5vaDKUMuQ02IrRe1OyMdp117uecSqfsmuAvbDYdOmvhp9eHWsoPtHJSOJAKVVqtBYScyNlccsGOfA7gEXUZOwjpsoKJ5NDXypdrsfp0I/pTaXJKPJwt8qKkgPcUfZgvbNpN2JHZ9XZt+RXkg904ou1R93MUjPHwiIpHTT5xrJCz7GhEzLpY8SCIq1e/nPk20M8LiXhPArdi2AZCUAS5Zbi1cYtwwlVB3EJrqk8Zqj+pHfm4+3xLYkBR0oEFyHXzIiEvJ9HIEa6wodsTN7E78jwzI4tZ4Ke6Qe4jhi2wQK84plNSAT5lLtOqqXrwpHXhhuIFLavXnCZct44nZ5j8Xj18gpCiIbiu6DOEF2yYR+Vy9i5dvPjs7nG5wATjeHticHPo9xldSPAQpFgwobR1KdEs7dnYYwp9roJAGpja0eMF2FyHrYvfKnrEIapNDHZOsYvO0iDpoLD1QK0G6sfiZJ5cFTwauQ0f2jO+Kt7iaQZgFDMTHDQkP3e158gJVs/kL5JubnheYBDBPimzd+Y+w7pfY7+4TuXdBgWymUGSq/xcVjWHEMtQ0k7zEUAmkxUgcVjcJ/S8PQR9IGCQWHhA814BkU5FHkl6E0oVeUaELUTAenLLc7BrmAxyayqpn+MAQ2AogIs+5RcPaDKZLgaEsxSYcAlxyFrP5kN7iLVj4DV6pItTKAFSiqMUbIfKUHBFbuFztMadXyduTNWNofVO87SR4bYdOls76Iv208ury2GPW11oOhXx5PRO34RTldM+RQ/p1ImCb963eFClYlR2N+ZodcgwvvRSolNEqffRbCe1yMohccgbVm60MsZ0hlFjslSd8OJ2SIWleW07ZufHwckMUCnCdPcG74h5CsAQmWXSJV3hgqe1VpLK7DbVqt4oYnqdaVFi1TR3NSXs9WFIIih2HReNCnIX0ZNx9TZZ11f85PNEfFEwOzYa1k4rV9PS/ZHzVtqj5HK197UZEkk43Ds8H/xRqY2/x3VcjUJ42+SwLfNuOVHdpcPODVjaEAHRuLmw41P49CqgN2IJqkgHvW6OHTzdJ6FLw9O2WVI72zOBnYJhuullwSHH42l19wG9dnmcaHuyWGcn30BA6rujAW+wMrlgC1Ms7Dks4yoE8aFivGnFGvaK3VmwstNZvD5fnpggdNpA61idYMLmsIYA2MXheipG8jmQwHgdSYP9ysIxQq3UBJqJZd3uZibYeDrjAEGNX4sc7HeQ7ad+NAAKO8nCwVCKaJm5p1UnA/Zom3WwFWDBeHLMG8Vj4Bsx2bMPlscU07xH39l9f2O3Vy7D7/TmJ0EwOOgtH6XT2wP+ZQC2fx9xi7xfOv+Nvx0IZr9RaXMKAp0aoCjq16i5bTR3cm02G3NjaqJ4aEna1yQFX7CG5DdiO+L0Mg77SdEBBQsyk3QMQc17e+yZ+tQRt5xa6lujAnmiZu6kNQaP3grAeYhXh0y67NVyYNdyuBqJb5y6jEblYytJwl7uWn7H9gs9dKktVZrygnXt6sVV2Z3Hxpd3baAdARi2xK78Wl74wJNf3T2om/ZNa4AfUlMvZCjJU7XqW5UQM0NkJvM4SeGD2VDgEn0bvtL22R4p1cwVnwGeV6WUPrLBw9MPMGqHKsksH8C3lFC+zXxdE1qWzPH1rdZl5iCJqCh6ivEUkIbHXUb7gwZqueiI80ZBUzWAOlfFf6vWQccrSR/zu8OSnnlc4EZOTi2NK1i2wLFRTb4XX8w29elo4RXQO+a+3B9x+wpBBoCHbGkpQrwv/rpeuJYEjPjay4sGe2cz1wx+6KdnUHN70DVu3dk+Afx0M7LphPS3TLBfB0YChK9f48A2S6ATovxweNx+bxcL9ZcTR6d0NGTU6gdxQEGORolHWr/ulNfKKx6Z2GvbbXl96rB/naY7lZ6inYAxCqVPTQBNWVk/pBm9hcVmE5cJ9s1Ah3OlZZi4r6du1+8nMDcZNEkw1TMARltvpYt2xUeAlEJuqhNN7nSZce5yZrm616ZCuXAQky9h01o3et5jyRU7RBVQSTG8x0tqShf1glvCm4N2PW/XQFGK6E92zeefdFF2r66wey24zrL4Npt4m3VdspM8rd0qm5gGkuj4XKlCf+8knKav0u2SitdXu/m99YiluRX7CZRF4Qs3DneJgsPevBRcs5d9uJ38nod5nmcg/R7fsR4MFx4FE8vwuCT5nY6VAHpCMCuv3BM9Qep5hek2HRqUqQnjcNV257AWaX3vpIbcPGpmMve1qlgdE0FY6h6I8Gpv1B2a4cuZAPtkvutBRomJx8dCce+rQCfucI9C2X4R8n7So0uJCp4Ws4vnjk0YsU6s3ZHrtcPuNW5E+8k5YxFKX9foWqDeqWjNqNEsqRpaxfBx5k75aBLHu7ueHzcaOM/sabpX/Br2gicqvKiUXc+cb2wB1GTLsODCnomdITGq0ePczLWaMX6gsEWzusLktG1d86AH4UFitgn2avRMJAQnWSpbNmLU9B4YDxgw50adn9lPJ4twiY5llsC6uAVijp46nVyXJ+zoce0iR78NV//x2FwfOo83e5+RYjE/Qz2nWAXMADMGtFNgxXoyRuTxmBJfyFfngfJxIVmvkY0vyB3UQM6fVLPPlngTCUAb+CCYsRMMdd9WbN8ktQg0KBSTiZMuJwOGkeQZQ1lEcgxz5jwspt1ZXTimtqgzodR7EtQh/VSGU/2lcMthmfEEGDCcsuwOphbOWGyay3ErU6hJlZW/kHF0LVM0Mb3z3CkkbMY48+w8FDDnkZPXhRpsbfwnfX+svpcPQwFpsHhrYJje4i4szwsCgV7yoJKGiYFxbSjqbBw+yJ2SJMtJZK8eGNhOL1J7iR2nCa56ECAXVWPst3LE4G32wS2ovrf43YbilvR2pl/iFvMEkJjwIrnrgt/KihG4z6iR33RpLy7twDlQ075e2OIQl36+gm5V38NOtBekT8g4iwSLPYY8YW/ISSFnARTK0BpIWTKQ/CnUbB/hHCLdCl2iZyx9m1V3gBKJShk7tbIrMw82JJp6+kCneKnW/Oknj0ROe4uGqQYh9zY/vPuOkk8MM9a7/aSWfQ+XXF8Qvy/jgPTL+Nm/klp4q6Qj+nsGa7PyHiwJ8roxZ7+e6mGzQZEpW3vz5F+jozCyKjr6UKVONNShnyCA36Lvd9cFm5kY/LUOnP1y+kTSHR2h6+7VVNFYXOUVhkcOznvxHqRYt8VAe1iYyQF0fyQIqB6Pr+55a0KBcfOCfE6uahO2qpUFpECly0S0b6gB/GrbyBe2bZPtZdjGacF3lcRA7aQ1UPGJD+I2+qrNRZGl9+Cu+sSv0b1eFeEZ1WDo3SITiEbVAm/MsUdO99KGe+MdcthAHsj17a3Ax6t4CwAXzzJG4fZZhEUnhy2n7W4YRq+hlJLXocAv/gEdk+bfWSkdIK9Ca11b3ZfOOqsR9BHI7dGKp9bK7A2R36VTHMgTym/T/Uo+SUwVPZBDRZtL7o8NSpALf3fHoMPg3nBepWr4/dC2i3da4gZSXNgqwNviywyFcsEMLKEdWXRQ1LPIIH5zsglqe7XGWjFcD/YNi5CGSkxLfwG3veA91kUysklOqs9ZeiAX0oSgQkHwV3op34PKrU/E5IBRU6xNV+WJUvxepSBneIPvlkDXjUL5BBQxUq4uEVu6ZKO9y2PCCyD53nRQNk/OPqq3dI16BlCkenI08U5FEaIwaIPLhO04E643BetzmxMs9SrfDrfGKNYhrsKdGutr0/FXuo783rZ0b7iqgJSydr3MgQhoagoLhi1ty4BPSLX7ojh0V+TGLGl2m9u0KCouwyg17t/qW3jLDjW3rlfOc2pReXUjFzcNmIMX3/jc6g18dzZn4LqJ85J7yTbx1tYVr5shEYXRkF8BfdD7k0aytVkOdVqZFbkI1Lmr77xA2YzdqU4VlZytOA3zkIZaPT/iaW9RdrXFuAIVRyXO7Q4xaZMJHqau4fPlAJVFGfFDtdtuhtQJPOp2LiCoFihulrSHsWPvOcsrFufpOfdulrnLrLQuuWGHTXrvVcvV793nvXXOXK3VFuxkcKqBGmM4PqQGAvLRtRzZeNzgtAk7MRocDVSQukdn1gfZNYN06nkTIk6qxbsqDA19C3yAmOwkCc2WoJbN4T1BorD+lIttTQCvxKwBuIASew8RUl5MWpqZULgQeUbkwZEawK4tu8erNXmfVChbQ6OoSw+Ucibg93UY0LSwJg4xyfQBqiDvYeyr1BNM+2Ln/ekGPQc+pxGkwZK5Yg+RE8mBo6Ix8cqPS/uEfTqNu5EgmJFAuNXAXvfLSj95q7i9TZ1UhuVRAj58v74XFvIzjZX3lyk30iRc4VS/PYraenm9cWHUQblzh1emAiu4hSthtzZsELRThe107dfJKAERxu8HA6d1DSK6YAe59Dsx1tpceBRPi0ZDxBjZteqKqmZrH992CA/iNle9HLa12XEEn0lWZVIL10M5TwuMonngIMIy814IUhhE/gA8BoOEmG9Zj18VGLQ59D2rfmPdYmlodXIsROHb1rBqtTcAxfDC5n18Jnl9FXFfZCc+i5rLDWTccqpFKW2DU7CHDIe0oIYC9IXEvnFgbyhK/eyRyU2G52aOWND7QLYwCh8w70x0nHYKWOKebXaT4oGDACfSnRh06elB1nvnLpseE+NtTbCX+Xyi9ryT2EsmABIXCkAhTIITSH5SgFwAFtR29xJ1WyPkV9mET6JbbCDarHxuaVyelvj+8qfoyDbltDycj6IhR2g3suhw7GA2UeZzlTuurY1ZXJmZoJb8EnXu9LJbwmIUw0in900mwYTVDQzZVCIYOQK6qlBOlJpn2BzaVDEhQYsLLbFw57y1l8j1/r7fu/05YuTlUsCPy3rrBo4G3MN1cdGPqXzxgquRG2r/4pORVkWxLZxSm4cYzg34RBwwpKKM5nJK/aNfqb7tlFt6XkwbwDwS1G4X2+0Zw36oBAtBrZuMW3zTkEYL7lI6JQKT4zZ3IV16o+3N3ZV4H2fiZJCZhnAh9DQurQ0K0Oe1yjQvqxEtOfiSGOo+6tt1vG68eFPmuKoZdOJurtubJICFZIO6Jg0loWuefeVAAc8iUiFyLUvcTiy66mgbFVfvxAy+Fq3tnqap4nYebECkP4yFcvUbAfeeyPMWTabohGUMWI5rGp5mMQaOdsLJuOhp3/pDidHG0gzWBwX0Iby1b0NyLF64eNQgoibcq7ehSIPg+riwu6VUxKuOtBa0EQ+8grwCBlTYhO9nZwv900p6UdfiO+OV1RAaOoQCZl6KnBhGpSYyhc0V1z5sBNhOpZeBavPSb9aJsiBh6I7p7PazSVRn4xhDf893b9zYtQb6xjaI0sGVIFmyi965awyZwF+dVukdpVehoyy5pOA8L7a7zNj2eqp2XbgvxYnedgIyJoZtpmdhT432w5hiKF2OLcRIizstTr5kXwe3IqcVfo2+KJCiLdtmRbmiU+eO5w3IfTCFMn5VqDrIGFYr1ikwFIgTLL/XvTMN3qh8Hw8K6gAbZryBlledqzBlmKQ8zQf3xdxrQ6R7+2QX8Nryfo1ZUkmzJ2PalKR1HoLt31zNZss3a5yOtU9n3jKakL768UOQcZq0LtUqp+QlBCHY+6Z1PNEAXZ1Tp6z1ELgt9sDthFIe3aIOPqV3TsjITLkDVXDvrwGlDrNfMREJJlI99cRnETfu0n0k5vFyhSErP+WG/UJUx1iunG4IBV2t3JkoWBgMBst0dy0iN2oqPTE54kVz4usIrZ4utTLTDE8BWESkyVPHolNhaWWVB6CibYwrqr/um+1cTBfglh0TLoA9nbHsB8HRlPdo2Dkd2uotsYL7n2eCwI5yAZkLkIRFPskvyiWDeXIWcmxpUxUFB9TcH9cAyAXqngImTrzSsiiW65W4l+vEoqLXK3xxy/pTp7wQXetutq8ibgTCMuuLF73cyfRlO5WlMQTZixsqPBgte6YdhN1TMMa5Pl7LFL+BoYIOnc30012Ccwrgx+zTu+F1wuOCg7HZbXG5x+mSVFDCb5Nz7QV9tHeo3S6w7owQ9UI87botvfjkPTXrFWRxkhEoHhPocFqjb5xSq00cHD6N+/XVKVoSb5OX+1ZkPtuXXTHyuHZ8gKHEdAURwCJUFgKxpgRGa9yIYfXKsdgpnBzC0IaPNkie9yJTlUYTTZaYsD1RQInbGOkRJIVKdA0wWzJAl9xqI9vRy2CzRjHoGT6fZ/y5oZLGyIS1XRcRi5IMwAlLjhspJjBFD23X2WckoSdxtnEgz8rkPXSBYkqHYtOlub/tJK4SL9fhRIZ9wDC8y9cH9OQJ+V2eALWB0ghLD5cIdi9F+UJA96JkUFSo/yDIUR3vduuVFtPxz6tIvc3hERgFNzoSAp+6zXsZ6WBqp+/Xb3Mo2ABItx5MIdGDh/tE3Bd3f14FOrvFKkssqc+8+EgVKTQGI9hUmptZmok43ZeOEer9wrjFnJN5pq40SAhudXIcBtPH2SMik7LkReyPDHzGKzSd7NTZaolNtNS98hd+JECbxWBvtAxxfOUetamPvUi7jqWF5ss1R9Z7nHqEWtskMx+97KucDcZpqBR4DnrJkLHwTNaFKaegLWEAs7lFmUpWrdTAc5Wic8rP2/E2y1XOYuACjI+DJX3Y9Vq6T/36QB9p0JiPA1gEP33XtWvH7fHb5OsauoCxndONtgmzkqRccDtqgCEos23Bc22sQYz21nS95hujjZ5CJSzM5ZWBkdQnPWHVrFBhfxVeGRDHBq2CWY192giMICgYcyV5ygycs+923c5Pwnb+qMdebbFP4S9ENtMXfr1Uz070u8NWGJdRIItabhrqvs+NCQiMz0k4Ksqujt+iqUxPBCsin3uG4J6DJMYj4MIdv72dT1kNwyXBsxSnkw3OYMbDvsE069H30UJRvLffhvU2MlcIqU/9WVQWct32BGjp6WRFpr9mazSt6JX2+HJnRIaThbtXAm9ybaEMqmO4m9Dk2HDsVrSe6xbWT5xtDOQgzApTdCKg3WwqobAuskKNjcOQTaI2XUf74cEomNpj37su77xqsh6MA4kDwokGgDzV6XgL6EjYFpxNs1TMPrn+CEIJEhoIaVbsZrUru+4UqsSqsthmALq85aEmNiZlO7BreBOCaiaKocwvEbu/oFZZlH7G9iqY+itpgXLTHj8WxmSaKNah2SHqRSsIQfe6ia4hSc720lP1fUOJx2iZbgMIqHqKTF68lpOYy5QaXjeQeMfw9GRmmYr4hcApZLuuLTMoVPUCOmGB95RYrmJmDSPXg6lf9WhpSO9uGG5bVrfelOoVNY7CnKQYqTOuaKGSQJ73B7hbfWqRKvF53uwFepIIbKSCsCxuYQbfVHAAA7VUUYmot8zAGUWCY0RJi4TiCeLfZgQ9L+y8YZVo7zrrVPuq27GF01hhDCnuRZ4PwgJEkb1YJKNsyYuLtNxRXhwsM103QDXLl1LH6MMrOa/2CJE9iUtUAOws83LoIOxkWA33wZ834IZ9ZcWvWy8w4cyLRm5CVJZzTl560T03wWBI2jCT0jQiXLG8Qlws8HjuzXFt1mPecg6YgOhla2vFlnuD0q5wohxN9WoTAyz0CtyPbtf71rd7YdvT9pI3b0R6eqCSpEXzm4lvpni/qYZiDdXAKaCVCkpOlAi7hNaJ1pkZxdmMeeQVnIriOMNmO/EUDOBsW8vsVOJdSq6hErQdu+d1YAeVIxQGwcbnIt+csnQuB/v26M+egm9NZ5vJNt6m7h8GIc15hjT2BQlrUX2bJtJZw+AjSo5iT3RO2Zbh1us8bJBRlZzGULD+NhEjIhS+V7KI4d4TxXz695GqxKgLHXuoE93JZPD2kBlkUkRGAC0jeoNgnzIg26M7U5oPJyMW6hHMwOYwhKjmRTrw2gyQ2jK9wfY4TpQwHxaom+X2SQUt/CSMQG4PiLNKsQVzJWuuKxgPwi3EDgrwcW7rMbSQAJISwrOG32l2wWTqeidGs60NJZ9lpqotFHn6qojkrH+ey42Cdl85dsoLvmS686K6d3u9XtCim/twQwqYOz/vTBk79Dbqa5+wbsdlpSgyVCFnl5W9pFkF58jXNZ9cukecMib5AdJwZaM4A5/O5AGjaEqR7H199tN+UQrzFDxzkhjwyTvSgUUuhDdYNvVMn+qLla0IADg8i5M6SptZKReoeIKn7EVIfchpRouSYGBIhvMAP9P8cCSzAUXlDQwYsWXTi2eYguKy8VxL1mCMuXZYQYoFJeyZdkMIn6O9i6SdspyvCYbqB7LgWUWgIqa3881ivaLiRs7SXOXiMl6IMwOeZ4Om570dok9pyJvznmMKMCxxsTjk5om1ZS+3xIo7sygradFJVzEs1dIoe+lyy6jkoThT8ONOVbASYIo7ACuhfcKijGGAajL9CHPDckZYtAvar8JT44GHYi5IDybWYvIAO+TL7CBRMd3QJJ4dlLEDIF5qP0uwfrogoJ9WkNOnuBL954Vfp3XnYEEwvOspyNdHe1JKh4dlMC3gAIXjqAL9lXbVKAnLseLqAEjo2zz/tzp3/gAUIBzkEDedob1ej0zvQY9e7hTfsbRp4W47zAPKlxRUr8wL1LtFMB9dPiHNgnL5PUCazhpNNJfKJfeiSVdt+giuaeXmmzO86ox/PotstVgwOXmKiU2j4ue1uxoP/BYnsaTd3JM53IDOuvHXDIwDJvdY6GG3wRi3mblaOHzNcsvjhHctj0s4SQ/Yfnvq/ckbqCNwWzKu++BQ7P3tMXq35XSQS1cpTG5WdRN2KQDPuDCsaru4MFZqnudgfQXwn40/r6aQlRtYVOV9KQO2G5P0Z0tk/LgEBljeBizm9r76wvuxP65T802XqEEo5IslahDi6y83+LwM5s+XrPi87dsvYvIbvu38faW8+qQR3+pbyu4UjuEfrVFEccJ/8xpFX363xYffbQx9YP8/bn2i//L1TdnPnvY71if6reubfo6lv8r6RH+vb/qBH/xB31nzFbBT6Hdbi0hE/SQLG6z4/1K/QHLGal38H19/i/G/XIroXy489Cv4eHZv9vbvV9cm+jgj/2LVo/9suSF+Be+J9+WG+Fd/65c3WiAbnONZCsfkSsYUVflGFurVEevjfCGo52ks92ARl0rytxNqyPYKyEXoJpGT4tG4TIImqN7Uc4wazzBga72h9whfZpMFbQijN0kllSz+9sRJyW6t9Pa4znGA8VX2raIRLNFMUwdcEB73mJYh2Ht2YKJ7hxTjxPiTnkQ5Qjm5oandQXR5WTmrPwT4Cpdq06keQ6BeXaox1ymseAflEk8TkQfyUurd9FAJm1NAo5EreTmeKF2RuPIEvTY9oxmfDRQvpDR6e3Q5I02DptG+RdsgkdQyUaN5RJjQSXJBupx6lWFEYS2V/nEXJ1jkz+4R1LsEC5dHJ6FNiMyttDxjdkDiPjoqB1C/ejsCYpnJdZZtNqVVzXYdFL57QO2Jb+NFPm3XAXqXw5J02Ca/3qwlEXFMkG8Sh9HPBDwHLHorGN4rYAGqpR5tMKAR/PByjaG7bWiVTRLK6546+7ybh5TsoDyLm4IZ8lZ2g7DqMbxW+vlcJUteKkcZ6tPiJzEH1abUTe15VZBHGK6WEwlp6j9r1CiePa+TSivNAWDW4CGHZLyFi82vglJtRWnv8yGeSnqJq9m8cZzDXxCc6GIPTQlauyhzEajd1ud5VVr0pRWjmZQWtW8jCR/R13OCkumgm0PaBdQiDOl1cSQcZyQjg0h7UQTNayBcRVIEzmAwskftZG5zT39QGYGhq2Wk64mUJvU+Voto+jHwKn718bgh+jt6P/mze1ntyuh3mXqj4ENgWGZUVMItQDVt0C1YY4OKv14odkJvBvrUdqAbfEpy5k1+LFHRe+BpE/WYpOuD8Ce7ZO3xgqFAQ2zto5X+//aupOdtG4j+ogLal6O129qtzdZNuyxZ1maRkn59TQdpk+ZrgAJpemjOJCBiyDeaebOx3A3cszY7znI53mlCS14QGxQvihFHvTbHR06OUZ/kRKtsjGBa18K67iA6KHGyGLlXrmWBynFU5lws+H1csuJAGbbw5lMiOxIz7N1B4H6IvaNeJxRzVi2Ybw02W0pdpaC3gT2s/claM14LEaASHrhNKa1lHBesSeZ+94CPu3Yb2kCXt7Jc9MiuX5fz8rGeK+/JyO1Qb5SECnTancd1xCTjQc8zNKIBUit4R6DcAkRg5EdWtfQp8EeUoCr5OkX6/ADlqzBnxWkNt6TrNChyK+I2e4KZovfTmQ3j3FSsDk7NOp0v0Mh3yB0rfHbabOBOD5+Lqwb5QUyAotmuxhE3YPXY9SwpYpFbzKMqoaoe9qbkgxRgOaJTHfuc3Ws1QL6YtS0PkmKf00RnNxSwhCSOshOBlCKm+dJA1k0vnGe5mGjsfqjHS+q10XVsoDmP/hbPmKhQh8VjTMT7pMwLdUNOJbazF7xKlmudxsQckeDyzj03en+1OCY9zgGZd8iXzJidja4kzmMMc0EnMrZkp2PLHSb7nNqsbpSuBdITsCstmzgzt8sC2i1FSFccJwzNoh8+D4q0EN4k3ptjYSbspafmayce0viJ4f1y+cThX6GlEM+HEhBWnZphsoCQbD2RqMsmBU4lbYm4TOEzPANuv+1K0fsG8WBDgmppdTvGAC6X9ek+1ReCLuVkHhPDEAJnvtEt2Y00yRxQyBozMt5mx2B/whHJcPHuzg4rVTVxVsBVPlVKm1Dt4z3E6JDBzw+flFmz5TwmBH2mZfpjAcWw67hImn7On0CZOOEFJwT+Jc2J7rac7B1v0mlKDPGMVahi34sl6OctB1egzcIRZUtitGFcSpjT7/z/q8OaqFZWy6kqWqRbnxHYOKn02T45CcKJUEGmkCXC7tLIG3jUgk7IJTnrrbGrfVounFmax7TArSdmQle6y1TLjzUMTUIYZsE1BqzSwziPUgojfF86+KJGZ8FbS+dVqlwsX3DtQORaVtEwPZOuN3JMEII4tksQ5vWtwQ+l59zS9KX47M16RplLuA7FrMR0en2SNuNpxTzqQSJO2uexvarUt7ZmHaWM982HuUUOumkKPQmIAR6dac35966izDXxzl+ld0RPOUDYPTJHLAdIGpDX16p6p+ihXx0i4AcdrkzUCFlh9h6tCll5Qt3FsKUPhsDY5FzEHQh6WcMaVRcyT9o62W7xc8idhFsVyn0h7FSKszsQjspxtOXiEFjcwqNESUm9V8CUMSe6QA0bVVmcsRHYLWzI3HZCjnc84o5qSfiVBw01ELyLKxpeUFVcyrpLJgCmdCaWXRnutfBkavLRTWVdHtl9XlGFCKdbpDTedVdNOHaHOh3lAC8pN14WWSn5NeEaRuLG+JIroVPH2cYde0fNAFNlmu2/Ya/LcIXTrZaQiSRwor1RT4WsYrxor0dJd4jL1duRgj8bbU4nru6jnDiBrlG+tEaw8PTQhLKL3sbUQb4rfustbieKP8Ya5j4P7fijKfO3s2PID2xhgv+XbOFve/D+XxzaD8VBfOvPfriP/K/c2e+d+pc3+yV/9hO77XIM/jWqqZ83l/V7z/MD5hLJ76uXwYxL/3nht083/lLh2Esi65+LX9Odt5dx+O0k77xIl+pverZ3ff7lYKpPh/jFkf7Td8bSf/l7fMSR8j+GI0U2ad8/v1hTX7KpzddNoh2/Aw==</diagram></mxfile>"
  },
  {
    "path": "docs/raw/en/images/main_page_entry_info_numbered.drawio",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later OR CC-BY-SA-4.0 -->\n<mxfile host=\"Electron\" modified=\"2021-11-18T07:22:21.739Z\" agent=\"5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/15.4.0 Chrome/91.0.4472.164 Electron/13.5.0 Safari/537.36\" etag=\"qzGz4e-YDD1zfOxqenwh\" version=\"15.4.0\" type=\"device\"><diagram id=\"1__146syWW9rmBwxSfKT\" name=\"Page-1\">7L3XstzIsTX8NLqUAt5cwttGw7ubP9AN2/Bo+Kf/UXuTGs2QOppPmuEcnRgGudmwXajMXLlWVqH2X1Cu3aUpGcpbn2bNXxAo3f+C8n9BEIpErp9gx/G5A8egzx3FVKWfu+CfdjjVmX3Z+fW0pUqz989OnPu+mavh5zuffddlz/ln+5Jp6refn5b3zc+/dUiK7JsdzjNpvt0bVOlcftkLE/RPB+SsKsqvX03g2OeRNvl69pdHeZdJ2m//sAsV/oJyU9/Pn5/ancsa0HlfO+bzOvGfHP17y6asm3/NBaaHIUlqPyeS/uuj8LmENJC/Il9auybN8uWRv7R2Pr72wXWbq7uvDXYrqzlzhuQJjmyXwa995dw21xZ8fUzew6cN8mrPrm9l876bv9j0atznNtc3/fRxY5SlcAwH+9/z1NfZPxwhROj6A66omubr/q7vQCO+NDib5mz/p10B/72DL8/M+jabp+M65csFCIX8Df+86ItfIsSX7e0nK1NfDFf+g32/7ku++FXx93v/1PPXhy+d/31DZCUiaH3jLYT59vqTNJ/b8lf4X9th6pcuBf3KQ//aFp9d+tVnwZ4hm6qrrdkELqq64st9fl3fX/uhjz8w8wu7Yn83yTf9/x0r/XOTkNDPDfIVKP7RIMR3LALTv5dJ8G9MwibPehm+Mcz1iPP3ev9XOnTSVEV3bT6v3suu/SzoterCIObLgbZK0+afxd/PveIfLYP8RpahyF8EC0p8axsS/9Y06O9lGeIby1T934pqLpfH39qlm5N3WU1J3Xd/Y4bhlnQXSE+/l9WaLJ9/A5t9aRfyCxtSv40NUQr+eXRR5DcWxCH6B5qQ/MaEl6muHf9V1oJ/kLXwb5PTj7UW9Z3sRDSgJ99D0v3MUsS4AEbz0S9/fX90DHOdgGDD/tPB61MB/r+eQYQvVxBBj3ze8Nr4vOfnGf8djvBL6P2NkuIvHQGF6W+B90f6Af0f+wFMXX7w4QC/cAXOuC67fQXv60ym+avybpL2LwinX4f4MqmT6zN3fWb5/0veAv9OsIHi8B8MG19V3O/hL3oyZ+/5OuPxSco+zkaB1EyO9+Un1yc/m95V330BoL8Rf8P+dJtf4TYU+uPcJrRNr5PJ+6OqJLI1Xy0Njd/VQv9Gtvme1/yf84LfKtXQ8L/mHDD+Hf31u3kB8p97wT/DDu8NGCb6f8oPfiM0+MYPvqMUfqwfoL+fHzi8BpIG9Kcj/GtH+B73/LGO8L1S5W9EJhyZQXBiq+bSdpj/S97wW5GEb7zhO9zyx3rDt9W538wbkqH+C8KmyZz86Qq/whW+wxd/rCvAvwFVgP6JL8AQDIYGfqgbTJ999o0fzP3wH2cH6LdxAgr9ebn+e9nhe9X6388H6G+s8fNO6ae57Iu+Sxq9B/34YZ5XNs/Hl65Jlrn/ufGu7pmOEFz/N/zrZvSPx/j9y80/t45/0t//3AmyLmXAKOVPPnDtESvw6Pz/aKl3v0zP7H/qjy8luzmZiuzLtd8dAfxC77L0ZwOh3xp+yppkrtbsZ834nhm/XGr2VTf/5DAY/nOHgX8agvt6k8+mfrnuF+7w94b8Bx7yvSLmL1zmXSbDR1glx/DRjst4dTY/y6+WvUzzNbLefQO+j/0EEZ64Pn5ck03Cepnr/cVRPvZ9PCHO/gXnvx/5U3bdJXn8PWKnfr6yz0/bfx+7+8vXYSLzpz3su0sGt//suG+L0v+zB347TvgboANK/2IwD/92wAj7DjpgvwE6fH+Y+1t0AA7/1ZRfrfC/BTD+2Tj5v4KLf27m7wb5v4csf5+H8a+QBYa+7yS/Gkn+s/LBrxhR/zPcf5Nwx0nol9MpvsMJf6+A/771iR8b8PB/Eu7/aVj/W1GM/doohn8MQSAR9JdO9Euy+DsThF8zF+pPxPht5AP2S/mA/cF48e18hN9MQoK++DIq9b+hmvC/SEVi5B83vv39WjP0jTF+X574X5c26F+ZNqgfkzVw6BdK40fnjO/NiPgzZ3yTM74PQr8FhED/yzIJiv6BEAL9MAjJ9mr+onSvGPjc/mjB3zAE/rL9UyPAxvEPG//gaP9hnQtFfi2PpX8MIhE09Dfk50QW+6Wz/c6g9LVP/gSlPwqU6F8K4j8eln6wIP6DYOk/ABL8VwLJ1/d5fndqg+J/I36JJL98/+T3RpLvjbL+iSS/hyTG8G8wAyP+WMzAfjSV+XnV/L8CNX7tMBuC/hjUwCDybzj00x/kj2Uif465/bAxN+gX6PGdCZw/Fj2+NfXvgR6/oaT5N3HoP0CPX1tNgX9UOYX+Bd/Af+wYPfpnOeVH4QX9C2qJktQfjBfwN6b+340X/37cYz9IQmAI9Ytw/rHp/+tz/hnOP3zKzR8fzvif4uFfwcCvHoP/QZP0CAT/G0X+sSUH7M9R+B9HAX6BGX94wYH6QzHjv2EAFiN/LWbgPwYzYAj/Y4dgse9N3fgTMH4XwPjFtB2EQv5YwMD/2zTDvzdh8N+Hi6+x+a/hAvsxcPHLnPP35dF+EFrgf0qSP4pe/Mi3AL5ve+y/FS3+n0ZT/wO0QH8tWhA/ilz8IuP86AoG/r23z/+Eix83lYJGf17C+sMnUsD/Dx5RtR/Li7If/zNfV8eE/qG/9OSRNWb/ruaPhWr4Rz/PfftPO/R/NlGa5cnyOWf5GwP9o//8dN6XBvIf7zqjzOcmIg5d8ReEq3z2bm+QJhU9c/0xHK8UvOL65CvXD9HhmOj6nytgP1+vD+qtbXgLZus4iMs02KEQVbuowocIuTGMUKlN7HeeasQila/UeQ6lxzhWn1oWLoxqxHmC2PfQuPTWvUo9wX9XesFp2KgYQmDZlhCGqlclkOdx2MIxZQwVx8Yd07CLvsgGIZ9LMYrK7l8Q9vIYEW/I88PSCPu8/j2y58feJyMUlWI023Mmo0YjNmNVX2UdibdNQI/q1uEPjsptiAErk/nLLjDT0yaXC1tE87pNgilCLA7X1j3AFn2/3Il1Wi69eoGUwuAUBjPIpNcBbebr48tFLobT6C2exW2mIywrr11ZtuvnRL2vawf9RVBwmpeexrDbdV+2fN+vU7DH9QO0+/qr+XzF0UbVH9LRuqjqXZAaKaoWz7OiykOu06xV25TX2jLuUqCV/nUxizQ2knQTZC/Pd99alz1cfjrzDYNvLwZiRbqjno/JwajSXsHDnkgqhiRaZwUfPTfmcgCWxAks9pj0jnGWOdk+RM9Lcu33coYhyJU5WbUDzzNWPm9BSsHovcVEPdMEBRc6rOAyfPNmgjvDhBgjUpbNR4xZFGxlccyz4JaAka/HFiOWwjhtYPSgYNyE8TsmSTH+wJiR4C8TsswiMYlZ2OytGFKGNQiWtSruzTJxXwtHzWo1vzSMXTKPdx89FT5XpG3krFHsNabTClkrO5+xfWbwrdC3hKvFlp4yBMHMiMCOkgzxBcRceyEjjyy7ZVw3svyIoRMZcRk57X0ay/3NUDcNp3icEgnQMtmllJRiQ8x4bbcLSVgppNiNEzids1TLDiPHeLKCqbKVahWu4o+WpXn5WPtJLV1nNzxZXb7BPvDiphUJV7ROmTZVqIKDiYyNouv5jbWPxQAzc8ASdZhaGPKytZeZ8Goijwg/1/wJKXKfyFawFGz6anFhJu5rH+U2WMCgRCXmkIpALE+ev7cce5Ol6Aq78pSMu7REW7wLe4FPbDQxe8Aii0g/OSlK7zublhopdG8126y01Em5zgUtk25PhcAicXP0gg5f7SqFT8vAknjj0HJf+Sljlutr2RfFrtuQF9ejiHx67eFXzMk3zop0RmkKO2eavWQRgauVCbOH8mVyksM5o3BD1PBtR1gXV2wueJQV751ZsTbnDzVZ1YKoSIkD4Ol+rw/CkQc+bm5wxT/q3lSJzKFx7nH4uepS3XtvhyqTBOpttccj0P2opCsL4d5aN6p3zGcQT1Z6PLbOhl+8IJSoRYkw/9xvuTZjc17glC/vd6tNSk0SSsipbF0U3pRtVEE9NuPApgkreeZ92IkyHO0bVGqxhtE6NqsIxM49jFRWaiG5neXWFfYyHV8N75nQsdXGdQJazW/NeAQrxwwxx9x4KzHrJ9NH8d6+eAbAStUoz8SqhjxWZq83nCesH1D3cOpUE6ERdSxaz3G7PF4vZb+t7ytxsa2XOZpez0FAx7pRv6Aqg2DE77ElPjq5ORbvfqCowxIBjD/QZqbeOQQgLETxu+XLrOOIYu/r5fjW3kpt2v5LvL+9c+8X7SbUqBpUTTB651DPij5UjrtBe+G/WLJ11CYL/A6/uvO+eCxuXc7bj7kz4FpL9a4fKWNw+trsHbANB/Uwuu100QJ41BGHRdazSUwPIHeNjgD1Jkp2OIOPplQabk/EiVcxuidbAA9FG6SGdIODM1wvoGTFOtEnO1hT/zVNr+T9SJT06vs5954y/JL9K5PgE38B2IRquRg64zr4PdnXYYQvQ0vo5MUeLYo29IsusKv3ibj+CpYiZd8m/rEtuiR9blHLFrUE7MQnraT3MV7OiJTv8wD8XDLGHl2mI1nT5qAfYRgScy7d34m919lNxl+Wa+xGOqxQK2+H4d78Vk+Sc6iGNgoSOK6M99K8XTTar6/EIhyZz3uurniW30xxjALCTjo9Jw5YD24zciCdSPJBeceHVjZKNdD8uPS7OLTatk6TDvWCtno9WKP1QA48T/HhG28NgcJE66lAxfCzXnXlfLNmNKer8TwQLCCrkLRFUr0umAGgbYI89vfcwkPeg57+jrxksc7sGuvceMz1s71g9Totp8/xRrE2kcOU5S5xhT9keUidAHTeVAaLi58QGrmLHJAbeLiFLPLnTifjBMEJwPeaNeUiY88jy3SF8s6LEF5IpGJZOPjZiaLG6t7pjDz7vHnTUodkWTrh8Fpdl9KlCRxY5CcqyzGQXKuLnrHW9UFGmNxj+4I3LBNlVewOFYjGJ722Fw8SWPUp8Qd6tnK6hYGrOFHJOsKLgLvpTec5ynGkEsh8GSHeKxAeJ+ZU1mZwLXQLt/PkiLfZbl1XGplQmUMKvtikju2VVLqktFA1HoasjEc1jobUE0g1EZZp314CfMue+1vnM0RbY7iTjecj3alVyCnqYmilwglzbT+j9lUtjj163e48SLV6do8jUoa7U0vazfAqOuBG586MiXDwl1jr0iR0m/NqBGAcxWm8RCjG8C5o0yAmSZN6U3jtIFYX5+kKzQQU04b3as27i892C1jwI0M1/4nm9Qtslg+te1yPaqD0eLqhD8jI9FBJj3yAIN0KUnnllL9klo8P6LykjLuQ1B4eM1g2xyRlPYF9pfArppcMeF4e62Upy3y71I0UW3pAdROnNGVrZpGtw8aOVtDuu/ow9+m6Q2DKr6uV/WrdmqHyZbqVETWDHkhwHQRPCTmDLTV34mmx9HZL4+dxbJOGsuczW8VmCUWcrGSmx3Bu20akGmFtfl7wKDZR49/gkIPD65le4Wl0w4RvuySXGBnJbTv7STGPK4wZ5qMvzrFbepx45ZfqxstX+8wyA3QvSpsoIBFjO3iPZB/Niwok7msrzUxFx8epjkm7BA8HnoqmP4I2vpXqJ44AHmrSp09cNAqGHj2B9iJf+c9sEnUCoMhL3REzhc+yQ1o6OQkkHpCgm0uWdvbRMz0pvQ0kM43S6+yeI9EhpAYWz/UzOsRAKPonnueefFjvRtzeIVVBS/isSCP0CNyUP1LEexBOKsl2+MlPNLnSWZ8u95ggnzEMoGcOQR+XdIPgEeqCgALAqLeLv74DHEHdgEZp9XIiEKMt1axkcW+YfUfOOwyjZ0Yj/MUZV76sb6jbdCtCE9eZKU4jlDntUCabwiNzmeRWDZRgioBltjK30Zl5K6nZNMBjlCU25ZwO6LF5AK5tmARKAqx57PeEA3F/A+/qiqgJDuJ0V3Hgk3y8SBD5YpWfHX7PG4gaXNc3JAjJO1R6LvlcodGqNke9ikikAybhYoCGJz4+LmdOX2yWhR1KEwWAS+K0ZwDDVuz1PB5gOhtrXOgiPq4Yxug8zrFHC+gapaO367+LOnxYmTCLmOrESQne1uJ3pwO61aWRPDwRUa+gWQEMtDqsdXANnnkDbSVF9SzbzKUdRcakABklOHrAb+CY+hTK+GLkjF5d2xz2YsKqMVGgvZg8FfwoFY017mw0CtWGEVLL5Vg5kegzlY3Xs222lGNw/eWd+stYO23rrusKRmgEy7ex7o6mIbSnMAl1FHiYZ3nvhaj1TP94CTsyhvFZUCxTy8raOHe/qM4Lcp31zhzPZSa3+3ExTXGtcU6ud//5Wpy7aBp7coNVB4QrwYOfndaqmc2ODs7V0eE6JHyIzGuJBWzU9uF5nO1tVDsN8yssJ+KShFBz4c8c+FgMfj5QhZBqLkvewpsIUXiaZsCnWHKkP1WWsyiVVuInUWeM0bCcLHAbU4N+tJjnZ+RRAKThjyhxvYW5r4CqbgwwP/D5lNmYAY8P59J3sKTZnnFIAnNQ/SclEMQ4a+UjUpkwB/aDx8BzYMAXgM8UzKWkfTWylG1Vt6f2UGV9H+fliwaMNe89loijWS+2qllGsSzQetHYPKD1cjQYwf+dF7x1t1AR1xtJ0CZ51xgrHri1cWndwIL2MsftBqHumOlFd3t6ddHZVa1logkD2hTkIkPBi+hPsrkVg68zTscouu85qR/f26DDbyg7wkkXJGhSQeIouBRlfzzdhXMVlnInXIi3ghBH2UoGzK6yvdX6oLfZpCrKnfE2U4Ls8j7AaSFFlXfdAQQeBDEhQEYQPWo6jLxP+Jl/QtZYAvYPM6AHabu5oUedVpfwK2CApMrJKsYzHGuof2/xiryhyRcVw7uBzlD7rQV0YbQ71g9H1bxC6KkUcAQiPH9QDElYtuf6YqbObk0fT6i48z4HUDR1asXjHzfvvHNoiGdcUlgFbLEmxHSb6ZvVG3uuzOgXSc8Up83yIqsxjOGDvrZ660MhslzDiJoTcIXal6z0Au0VkJoLmVtjRGqat7i2X5RBKoFcf2V1ImlcXULt9nB6hDe0y0nYCIVgEMysZ6im4BORO/ZZJUHRwAoD4lWJx0NBX04B459AsLUNJGmWTRkpa24CWr+LN3BehmuypVNcUQHPzuQoKhimAgt4NXFAjgMvC0yfcW9R8YgVCyuNTQJhiQSKGna51o5OtDnsKqBhdchyjrYUU0z2Da2PUlzYzu/vqc9TjJCXIWFuMmWZflSxesGYVYmdRbyjUhAaKT3JA7O0hhgUZmhVXQMX0oWEw5Bap8NNxctFXUaVc0RD7lbzFnS7f2nRTA/sdVxYCQl6hZvwTIXGdssyayGil/tSnQ2zo8YcpJ/nURp+vQkb8Srve+en5DKRgSpWwCVenZGGL4XXb0LPooh802RRoBkjEAQjZwTOH+0XKBcAjH7NRdIGyNjSwl0TsLPMCx0pbUmsMTN4ml2c0sfqF7DQNJ4Mom970MzrbB3b8d8Y+VrvEXY26fC4syZq9wMM3dVoCLU0NbwplokBt6K+dnfCSjf0EyI4J4I9XwPxlANM6KgL/VzB3TVKIYNh1MSqm4qLB0FAwwJsaphKdHBNA0ac5Np9Tgb+psZnOFOCpfp6wyJNj06XADIhC39iVB2OnfxM8TMMUyn1+CpafMvvnf5KraVQgFh0E3kMfTboFPUG3T0HFDnpeU2SYArjncVtpTKiSyCNbswcttLeoiaIglKqeVGoFLh2h3cka97dO6QyKLXOtp69pT40jgrE8aF+XPOOOieSZoB8+EV6PjhnFkalEOtkyPDVRfHqRCTs91xlRzOJV/CwUCR+3FUepHKsdyubcqyzcvCtQKIEj3SWVMETk2fpZfrBlE6fu6/lkkUaQQ5yX9Au35Tdnl2HPXNOb5mnDXQtj+ZBxpVEtYIXLnPRmnoqES/YUm6WvAqOKDQifuVU2sZ33H04swNwX8oUbxD4nrk2RB1y9KDFkacjZYdC2PdFyjOEmyVHBo4U+tEhVFNuXU5hRmmKrD6wXX1jkY6ec8aonpW2UK4c5secDm+hVimmZTnarRRHWpOHiw8eLmiK92AFLqiQXm9MBO69GOzDivgJYnwhlXvYkYOdhrzC3ECumpv4bCmOMfV8MV4ZelFXnQ0W52IvY4kJvQCEDtrnooo/CQRebUDvZsanY5Zci4m4jS2+PkU12Ml0A7XPB3y8xWjEPt2VseFiSk6ZfD1rXLsnMCHcRh424ouZxjeOIp6m8iiZp1yokofMXbK9RZ0hNV3Y5+ROLLLQW6/CdbpmeQ8XgMIOyNSpMZLB/c1Pj+AUEFiBTvWD0unpvcpeJWgz/jhbvEpCGs65iVc61T3k2OM9NqnzCRRJHgivLm35GIpwXQeUpxS2KFQ9aNb7Y+HlE9JjwAoJx6Naw9cJ7HAkipfEEGT3RkjIG1oVl2q8CbyqieY5kiWsAidz2Tl4eHXfgBOxgfPVh14Zw0HaRa5Z8nbpO9rnlHbS9jm6TcYna4+9AVm2bXV3EF+mKuMCLNHwbcWeuZ8HmwsibDs6isyWdOxTDtadMEQmllJ4Bh0+yrlGeoCg97etUxjrFoJb95fzZjds3iSqW93JHuuJAOnSBTM52debhA3QGmWWQgLiScjaPw2XBxIxSkKaDnun0U8YgiERqCJbMYOOZjMnvyE968jadfXhZgRWfF5HZ6Wlaxjt8Ufwhi6MA+R5h9Fnqq4BW1nBxDc6dqkfIX8B9pEr3gTI20JMNoL0LnvPseoZDAr5ChWTHfCMeBc434hKeYHprni7ecewEyOHRVmpTiga8MiQBn7iupBQAfACzqUBZwMFBlh+OUhb2ZeUBVyuuB8U4PjodH74wbTMmZtpclSQbt238QuwrZd2/TAz+46Q4mJJ1bIG15eJ6xeOl1PG/Mm54AfsqRPcLjesdZwWkJzm2Z9PtoCo9WXBcA/qBmEf9pEtDNHTYOsNyNe88i/eno354OaINeh3ukluoKucXi4S+9YisdjtG1mglzGLiX4DtvL0s3rvo54Rt4T0bzTLXdjdLedwsUtRsxdgblNorvv2wA2bloyJ1Rs/WhDlvcnDYq2rVRxG61lR2YFk9nozoRs7As0RvnBQX5hWyNZJpN87MJIxr3LALdjY547O5XcV5yU/Fu/bnekKK0ER27S9PX6eL7MU0dauzh3QVhs6ehCPbLAyvLU7+DTurw+CHhb4C3n4hIIF7wTNSA9JCW1LiTfRipGCVlLNYB8oc+0fs7KUgFg4jXYmavNiygtLwj1UV7yvPMZGkhLZafEm3SOgrkqiFZ6bsGDb2ZxUWS1u9Znx4kjYmCrPhx4WDRI76MnozrEvoNTaLebS69oi62e3DKWkvWcI0XkgyGwOFlCitoIBJVKg6zWD182ihJ7afEc73yLK/v6ghwNDN6d5HXLfQrIzadXs9ni3Mm1JWbibIOlkg9LRRWkIMmrfo/PCg8Nz89FmNUCfFOn+ILeLcLdVRJk7hEZGFpPdayKKzGqsSgMgVI11ZUxQxD6ZW6VU8a3d0DzzH1q/pmos+gPBcfBg9+JmJFGlllYd95s9wLEhL/rAVLe+0uC+HBtCLayLEt5qW7k4iJdo9YsWC2UaG5kZgWcezlAfDzduOtYhIQOWoiub+aMBFULrd3XzGvxKJKt5vtflfL/5AuTehk4vT/fwOTHyS63RJ2t2asHgfM5dEcYj5/Fp9626lG0xgDjdvHgwrVtNErLaI35U5mM8lq1GK/rNrCQVG00nE2uoKQbBg8ISkbjmXsRDjYSu/V7357TLuOy9lYT3mWLnemNdiRxrxVf5fN5Vvm1HMRnjyxKYhGO9XEXSGF0tb6r0kUT+OApXns9ioL+auibpQs6Y2m8M/qAfpFXhad/7gV2lQV61XIPwourslG3dJkkb5gJe742X4jwBYHvBD8/y20fPny+uuZVDsrVHrSxhool+Hb285CZ3b1FdJGNAR65RH+6p2qlwXHj3Km029Lqwg/3RedtjOyJeMGRFabQw4pFc1jyX6b6GV75Ue9KGIHQ5yj0N+9gnsvD9YJ2L2T8Zg3g1EJzKW0AN65YDXkr4VzwVEfKWgfS7T62IeKFEWttWl7ZMgQqEWHKTRxfk5WVzl6OUIXfhTkTWm1qcyW7y3vuaU+mM3VL8jS2mQ+cd/PKHSMv4kVYuCgdSoUqrjYCQM7mYayHYccABPKJuUw8hfV4ysRwFWvX2LFafXWK4lCanJOPVIj9OS/jI0Kf5xubDhB2Z3dx7x28gHxzGGe/PZljicErGZ1w+G/KFY6Wc52crYtbNSkZB3Pzm7SzuSL9uJOK/CNxKYBsIQRHkltHtkg7hhLuCeKXW1l8y1HBRO/L5CPiOxICipEMLkOv2TUJ+QaKxI9xhQ7dnbmYP5HVlRhazwL/ahbxnAltgHS5xyua0BnzKXOdNU/XwReuCi+IlLav3giY8r0lmZ5yDQT0DgpDiMbxv6CuCV2xcJuV29S5dvvn84XOFwITT5L4wuD31x4KuJArqbSUTSXufEe3aXY095yjgagikgbmbfF6AzW3c++Sjokecotom4OCceOgijZIOCltP1GqhYSov5snV4bOVu+ipvZK74q++ZgBGsTDhSUPy61AHjpxh9Ur+IukVhu+HBhEes7L4V+4zrMc9Ccr7XD1sUCBbGCS9y691UwsIsQwl67UAAWQy3QASR+VjRq/HQ9AnAgaJhSe0HDUQ6VTsk6Q/o1RZ5ETUQQSsp25RgEPjbJB7W0vDkoQYAkMhXA4Zv/pAk8l0OSKcpcCER4hj3vk2H9ljop0jr9ETXV5CCZBSHKVgO1LGkisLC1/iLemDJvUSqmkNbXDal42M7n7qbOOgbzrIbu++gH1u86D5UsSzMzhDG811QQcUPWZzLwqB+diTUZXKSTm8hKPVMcf4ys+IXhGlIUDzg9Riq4DEsWhZudWqBNMZRk3ISnWim9cjNZYVje2YfZCEFzNApRjTPRc+EPMSgBGyyKRHesINzxqtIpXFa+tNdSlifl9pUWLVrPA0JRr0cUxjKPEcD41L8hDRi3ENNtk0d/zi80RyUzA7MVrWzmpP07LjWfBWNqDkerePrR1TSTi9B7yc/FmrbXAkTVJPQuTuctRVRb9eqO7RUe+FLG2IgGi4HuwEFD6/S+iDWIIq0klvu2OHL+9F6NL4sm2W1K72zOCgYJhedltxyPF5Wj0CQK89Hie6gSy3xSl2EJD64WjAG6xcLtnSFEt7iaqkjkB8qBhvWomGvRNvEaz8chZ/KNYXJgi9NtI61qSYsDusIQB2cXq+ipF8ASQw3sTSaL/zaIpRKzOBZmJZr3fNFJsuZxwhqA0akYODHrKDLIhHQGFnWTgZShEts/C1+mLAPm2zDrYBLJgujulSPAZ+PwN79cH6nBOa9+kHexwf7PbO5fiD3oM0DEcHdYtJurw95N8GYPuPCbfIx60PPvjbiWD2B5U25zDUqRGK42GLW3enuYtrs/lUGHMbJ2NH0oEmKfiKtSS/E/uZZLdpPC6KDihYmJukYwhqMdjTwDSXjnALam3cVgXyRM29WWsNHnVLwHmId4/Muuw3cmg3crQZaWBcuoxG5XOvSMJeH1rxwI4bPfaZLdWa8oZ17e4nddVf5ya3T22gnSEYtsTu/Fbd+NCX3/0jbNruQ2uAf6Sm3shIkud60/c6JRaGyE3meZHCJ7OjwCWGLnpn3as7M6pdaj4HPK/OKH1iw6evn2DUDlXSRT6BbymR7C580xBani7J/aPWZRYgiagoeonxDJCG50NGh5MGarnsietBQVM1gDp3Jfio1kHnO82ey6fDkr553uBWTi8tjStYvsKJUc+Bn9zMLgvoeOUV0DvmsT6eSfeOQAaAx3ztKEJ8rMG23bgOvKMk3gd51WD/auaWw0/98gxq6U66wa0HO6SAn+5GPl+Q/pEJjvvISIDwDVsS2mYFdEJcnA6P25/tYqHhduHonE2GjFrDKI4oyNEo8cya94PyO3nDYxN774ctby8dDu7z/KCyS7QTMEah9KUJoDmvmqe0oG5U7jZxm+HADHW4UDqGSYZm7g/9cQFzm0OzBFMDA2C08ze67DZ8AkgpFKY60+RBVznnrVeWawZtLpUbBzHFGrWd5dLLkUie2COqgEqK4T/fUlt5qB+6KW+O2v16XANFKWK42DVffNFF+aO+w9695HrL4rt85m3W88he8rVur21iHkmi5wuljoKjl3CavkvuLRPv724PBuuZSEsnDjMoi8I3bhofEgVHg3krufaohmi/+D0P8zzPQPojeWADGC48SyaR4WlNiwedKCH0gmBW3rgXeoHU6w7TXTa2KNMQxump3cFhHdIF/kUNuWXSzHQZGlWxeiaGsMw7EeHdudQDWuDblQCHdHnoYU6Jqc8nQvkY6lAnHvCAQvlxE4ph1uNbhQq+lrCr701tFLNOoj2Q+73HHg1uxMfFORMRyt73+F6i/qVozbjVLKkeO8UIcOZBBWiaJIe3XV83GTjPHFl21PwWDYIvKryoVP3AXBu2AGqyVVRy0cAkzpga9eRzXu5Z7ZQ8UdiiWV1hCtq27kU4gPAgMdsERzV6IVKCkyyVrVoxbgcfjAeMmONS13cO88UiPKJnmTW0bl6JmJOvzhfX5Qk7ft772NHd8R48n7sXQNf55hAwUiIWV6gXFKuAGWDGiPYKrFgvxoh9HlOSG/nufVA+LiXrPbHJDXmAGsj1L9PsqyX+TALQBj4IZuyEYzN0NTu0aSMCDQolZOpk68WAYSR9JVAekxzDXDkPS2hvUVeOaSzqSijNkYZNRL+U8VJ/GdxxWG68AAaMlyx7gKmFC5aY5nq6VQa1mbLxNzKJ71WGpqZ/XTtHhM0YV55dxhLmfHL2+0iDrZ3/ou/PLfCLcSwhDRbdFobpPemj6rohEOgVDyppmBga95airsbho9wrabpeRPbug4Ht7CZ1t8Rx2vCuhyFyUzXG/ihHjP5un9yK6keHP2wo6Uj/YIY16TBfAIkJL9OHLgSdrBih94pb+UOXDuLajZwDtd37ja0OcRuWO+hW9TPsRHtFhpRM8liw2HMsUtZFLgq5CKBQhjZAypKhFMyRZgcI5xDZXuoSvWDZx6y6E5RIVMo4qI3dmGW0IdHUsyc6J2u9Fa8gfaZyNlg0TLUIeXTF6T8OlHxhmLE97Be1Hke0FvqKBEOVhGRQJa/hnTbCRyUd0T8zWJdXj3BNkbfLXP16qYfdBkWmfBvMi39NjsLIqujoY5058dhEQYoAfot+Pl0f7mZq8PcmdI7b5RNpf/aErnt3U0UTcZM3GJ44uBjER5hh/Z4A7WFhJgfQ/ZkioHo8vfuX20YC4xUl+Zo91SZsVatKSIEqj4npwFBD+N11cSDs+y7b67hP84ofKomB2klnoOILH8V9ClSbi2NLH8BTDWnQoEezKcIrbsDQu0WmEI2qJd6a04Bc7qWNj9Y/5aiFfJDrO7fEp7vohoCL5zmjcMciwqJTwJbT9S6G0VskZeR9LPFbcELnrAUPVspGyK/RRtc2762zzmaEQwxye7zhmbUxR0sUD+kSB/KM8vv8uJMvElNFH+RQ0ebSx3OHUuTGP7wp7DF4MJx3pRrBMHbd6l+WcEGKizoFeFtyW6BILpmRJbQzj0+KepU5xO9OPkPdoDZYJ0bbyX5gEdJSqWnpb+C2N3zA+lhGdsnJ9CXPTuRGmhBUKgj+zm7VZ1B5zYWYHDBqhnXZprxQij/qDOQMfwy8Cui6SahegCLGyt0jEkuXbHTweEx4AyQ/2h7Kl9k5JtXNtnhgAEVqZkcTH1QcIwqDtrhM2I4z43pbsgG3O+HabLJ7eg1GsQ5xFx7U1Nzbnr/TTRwMtqX7410FpJS1m3UJRUBTM1gwbGlfR3xG6iMQxbG/Iy6zZrm7dFlZ1lyOUWoyfNS38I4dG27b7pzvNKLy7icuaVswBy9x+cIaDPxwdmfk+pnz00fFtsneNTWvmxERR/FY3AF90IeLRrKNWY1NVps1uQrUdWjo/VDZjcOpLxWVXq24DPOUxka9vuJl73F+t8WkBhVHJSnsHjFpkwmfpq7hy+0ElUUZCSK1311D6gUe9XoPEFQLFDcr2sfYafCd9Z2Iy/xaBi/PvXVROo/csdMm/c+q5RYM3uvROVeu1hoLdnI400CNMZqeUgsB+ehZjmw8XThro16MR0cDFaT+2ZvNSfbtKF163oSIi2rxngpD49ABHyBmO00jsyOodXd4X5AobLjkYtcQwCsxawQuoCT+U4SUN5NVZi6UHkReEXlypAawa88fyWbN/hcVyjbQJOrSE6WcGfh9E4U0LWypQ8wyfYIqyGcYByr1AtO+2OV4eeHAge9pBWm0ZK48IuRCcuCoaEK8i/PWveCAzpJ+IghmIhBuM7D347bRL94q3Y+pk8q4PivAhx/3z8JCcaWx6vE25VaahTuc6e6zbKy3Pxg3Rh2VB3f6VSawgld6EuZ2UYugvSrsl2u/L0YJiDD+OBk4axoQ0SU7ylXQi4nWFcKzfFk0GiHGxG51X9YN2wT4fkB4mHSF6hewrS2OIwRMuimzWno+yvlaaJTtEwcRlpuPUpCiMA5G4DEYJCR8x/r8psCgzVHgW80H6xYrQ2vScyXKwLbGTWv8ESiGN7Yc0ystmruIByI783nc3lyQcau5EaWsCy/BHjEc0oEaCtAXEvvBgf2xrPSrR2YvHV+7OWHhEADZwih8yHwy0Wk+KGCJR77bbYaHDgKcSHcS0KWXB1mfnbvuekJM7pZib/P1Qu3lILG3TAAkLhWAQpgEp5D8ogC5ACyo6x8V6nVGxG+yCV9Et9xBtFnF0tG4PK/J4x3M8ZnvymV5uJhEQ47RfmLR8TzAbKI84Gpv2jobs7gqN0Et+S3q3OVlbspiFMNIl/fNJsFEtQuGbGoRjBwBXVUqF0otC2yOXaaYkKAlpZZauHM92lvkhuA4Hv3xmjDydivh521z+5GjAffwPFwMEqpY/fBuFIY6vPl0olVR7Eqn0pYxgQsDvhAHDKkok7leUv8cNmroesXNrptpI5hHgtrdansDY9hPlWAhqPPSaU9cDWm18CFlcyowBW5zN9Kjd9revUNJjmkhLgaZawgXQS/j1tmgAH3dq8qKqp7QioNvqaEek77fp/vOi66yJHXDoDPnet5gkgAW0h3q2yyShL59DbUDhTyLSKXIdSzhXlh019EuLu/+hRl8I1r7I8syxet92IDIYJxK5R60Au6/kJcbz6boRFUCWI5nGr5mMQaO9sLFuOj52IdTSdDW0gw2AAX0MXK7jyE5Fi89PG4RURMe9cdQpEFwQ1La/Vop4l1HOgvaiSdeQ34JAypswo+rs4XhZaWDqGvJg/GreowMHUIBM69EToziShOZ0ubK+xC1Amxn0ttAtWUddutCWZAwdMd0DvvVpqqzc4yhf+a7D27sWSPtsi2i9HAtSJbsoQ/unkAm8FenUwZHGVTorCouLTnfT+w+N/ajmetDFx5reaG3nYKMiWG76VvYS6ODKKEYSpcTCzGy8kGLcyDZ99GryXmD31MgCqRoy7ZZU57oNIXj+yPyGE2hSt41qo4yhjWKdQkMBeIEKxh0/0qDLlUc00lBPWDDjD/S8qZzNaaMs1Rkxei9mUdjiPRgX+wC3jo+aDBLqmj2Yky7knbOU7AD19NstvqwxuVYx3zlLaON6HuQPAUZp0nrVm9yRt4iEIJDYFrnCw3Rzbl0ytaModdhT9xOKeXZr+oYUHrvRIzMVAdQBY/hHlLquAQ1E5NgItVLTwMW8ZI+OyZimW53GLKKS27Yb0R1jPXO6YZQ0vXGXYmChcFgsEz39zL24rbWU5Mj3jQnvs/IGuhKq3LN8BWARUSWvnQsvhSWVtVFCCraxrSh+vux287N9ABu2QnhAdjTGct+EhxN+c+WXbKxqz8SK3j+ZSEI7KxWkLkASVjli/yiXDqaF2chp442VVFwQM39eQ+BXKAeGWDixDurynK934lHtc0sKvqDwpduPlw65Y3oWu/agYp4MQjLfCjf9Pogs7ft1JbGEOQg7qjwZLT8lfUQ9sjAGOf2fK9z8gGGCjr2NjPMDwkuKIAfS0Afht8LzxsOxmb31eOel0tSYQV/TM61V/TZPaBuv8G6M0HUG/G1+74O4ov31XxQkNVJJ6B4TKDDaY12OaVR2yQ8AxoPmrtTdiTepW/vo8h8tS+/Y+R57/kQQ4n5DiKARag8AmJNCY3OcIlx86upPCicHKPIhs8uTF+PMleVVhNNlpixI1VAiduY6AkkhVr0DDBbMkTXwupi29GrcLcmMRwYvlgW/LWjksbIhLXfVxGL0xzACUtOOymmMEWPXd/bVyShF3G2cSDPqvQzdIFiysZy16VlcA8SV4m353Aiwz5hGD7k+xN68YT8KU+A2kBphKXHWwx7t7J6I6B7UTIsazR4EuSkTg+78yuL6fnXXaQ+5vAIjIIbPQl+3bm4L0cV62BqZxA0H3Mo2BBItwFMIdHDp/dCvDf3eN0FOncTlSXWLGDefKyKFJqAEWwqK8w8y0WcHirHiPRhZbxyKcgiVzcaJASvvjgOg+nT4hOxSVnyKg5nDr7jHZlOfulstcJmWurfxRs/U6DNEnA0XsckuXPPxtSnQaQ9x9Ii8+2ZE+s/Lz1CbV2am89BDlTOBuM0VAY8B73lyFT6JuvBlFPSljCC2dyiTKWbVmngvUrRueSne37McpXzBLgAE+BgVRh2u1feS78/0WcWtubzBBbBL9/17MbxBtydA11DVzC2c7nRPmNWmlYrbsctMARldh14r401iMne237QAmOy0UuoRKW5vnMwkvqiZ6xeFCoa7sI7B+LYoFUwq3HIWoERBAVj7iRPmaFz9d2h28VF2K5/6nnUexJQ+BuRzeyN32/1qxeD/rQVxmMUyKJWV0O9z7kxIYHxBQnHZdU3yUc0VdmFYGUccK8IPHOYJngMXLjn94/rKatluDR8VeJ8scEFzHg4dphmffoxWSiKD/bHsN5OFgohDVmwiMpKbvuRAi09X6zIDLZ8i+cNvdM+Xx2MyHCy8PAr4E2eLVRhfY4PE5odG068mtYL3cKGmbONkRyFRWHKXgS0m80kFNZFVmiwaRzzWdTm+2Q/fRgFU3vsR98XvV/P1pNxIHFEONEAkKc6PW8BHQnbgrNrlorZF9efQChBQgsh7Ya5Vrex20GhSqIqq22GoMs7HmoTY1b2E7tHrhDWC1GOVXGL2eMNdcqqDAt21OE83EkLlJuO5LkyJtPGiQ4tDtGsWkkIut/PdANJcn5UvqofO0o8J8v0WkBA1Utk8uK9msVCptTovoPEO0WXJzPrXCZvBM4g2/NsmUGhehDQGQv9l8RyNbNoGLmdTPNuJktDBm/HcNuy+s1V6nfcOgpzkWKkybmygyoCeT2e4Gn1uUPqNOB5cxDoWSKwiQqjqnSjHHZVcAIDdVRZi6i/LsAZRYJjREmLhfIF4t9mBL0o7aJllfjoe+tS+6rXs6XTWlECKd5NXk7CAkSRvVkko+zpm4u1wlHeHCwzfT9CDctXUs/o4zu97vaMkCNNKlQA7Cz3C+gk7HTcDO/JXw/gRUNtJW93EJho4UWjMCEqLzinqPz4UZhgMCRrmVlpWxGuWV4hbhZ4Pdd1PJv1mY+cAyYg+vnWWYnluVDWl05coJle72KIRX6JB7F7f+xDd5S2Pe9vefcnZKBHKk07tHBNfDfFh6saijXWI6eAViooOVMi7BFaL1pXZhQXM+GRd3gpivMKm/3CUzCAs+8dc1Cpf6u4lkrRbupf95EdVY5QGASbXqvsOlXl3E7249WfI2tBpLezbXxM3T8NQlqKHGntGxI1ovoxTaS3xjFAlALFXuiSsR3Dbfdl3CGjrjiNoWD9YyJGTCj8oOQxw30miuXy7zNTiUkXevZUZ7qXyfDjJTPIpIicAFpG9EfBvmRAfsQPpjKfTk6s1DNcgM1hCFHNm3TijRkijWX6o+1znChhASxQruUNaQ2t/CxMQG6PiLNJiQVzFWtuGxgPwi3EDkvwdV7nM7SQApISwYuGP2h2xWTq/iAms2sMpVhkpm4sFHkFqogUbHBdy02C9tg4di5KvmL666a6777fb2jVzWN0kRLmru+7UsYBfYz62hes20lVK4oM1cjVZdUgaVbJOfJ9K2aPHhCnSkh+hDRc2SnOwOcrecAomlEk+9hew3zclNK8BM+SpgZ88Y5sZJEb4Y+WTb2yl/pmZSsGAA4v4qxO0m7Wyg0qX+AtexFSn3KW06IkGBiS4zzAz6w4HclsQVF5BwNGbNUO4hWmoLhsvLaKNRhjaRxWkBJBiQam2xEi4Gj/JmmXLOcbgqGGkSx5VhGomBnsYrdYv6y5ibM0T7l5jB/hzIgX+ajpxWBH6Esai/Z65oQCDEtcLQ5xfbGx7NVNraQ3y6qWVp30FMNSLY2y176wjFoeyysFPx9UDSshpngjsBI6pCzKGAaoJtPPqDAsZ4JFu6SDOro0Hngp5oYMYGItJo+wQ77NHhIV04tM4tVDOTsC4qUOiwTrlwsC+mmFBX2JKzF43fht3g4OFgTDv1+CfHt2F6V0eFgG0wJOUDiOa9BfWV9PkrCeG66OgIR+zPP/qHMXT0ABolGOcNMZu/v9zPUB9OjtQfE9S5sW7nXjMqJ8RUHNxrxBvVsE89HlC9IsqJA/A6TtrclEC6laCz+eddWmz/Ce1V6xO+O7yfnXq8w3iwWTk+eE2DUqed37u/HE3SRNJM31LubgAp3l8vccjAOmj0QYYK/FGK9duEY4A83yqvOCd61IKjjNTtj+eOv9xRuoI3B7Om3H6FDs4+M1eq/jdJBLNylKXat2hUMKwTsuDKvaHi5MtVoUBVhfAfxlk6+rKeTVDhZr+VzKgO2nNPuHJTL+vgQG+E1nVVd8WX3h89zkWRcfi738dP5vsGAF8tMvNv667g3x7UrcXxdV/MclK3650OJvt+7Nn8vq/cuVb37tsno/aFW9v6/e/gctqof/uajej1u4/xvA+IG/PVdEgzSPWqz8/7KgRArG6jz8r/8Pvzr56xI3/3JBmwYc+Alz/6F7848//3TNm+8j/c9W0/n3lrHhN7BNfC5jw78Hd1g/0o1scI5vKRxTKDlT1tVHEmo2R2zO64OgXpex3JNFPCotPi5oINsvIQ+h21ROy2frMSmaonrbLAlqvKKQbfSWPmJ8XUwWtCGKP6i6VLH4x5sMFbt30sdrIOcJxu3YD6UcrvFCUydcEj73nNcxPAZ2ZOJHj5TTzASznsYFQjmFoan9SfRFVTtbMIb4Bldq26s+Q6B+U6kJ1yus+AAy3NdE5Im8leYwfVTClgzQM+RO3s4XStckrrxAr82veMEXA8VLKYs/XonNSdOgaXTo0C5MJbVK1XiZECZy0kKQbpcOYhhR2CpleD7EGRb5q3sE9SHBwu3ZS2gbIUsnra+EHZFkiM/aAZSi2c+QWBdyW2SbzWhVsz0HhR8+UBHixzhEQNtNiD7kqCIdti3urrWmIo4JsitxGP1Kwfulor+BYaMSFqBGGtAWA9wziG73BHrYhlbbJKG8H5lzLId5SukByn64KZgRb+UuhNXP8b3Rr9cmWfJaO8rYXBa/CB+oYmReZi+bgjyjaLOcWMiy4NWgRvkaeJ1UOmkJAWMDk+fTyY1Wm98Epd7Lyj6WU7wU2prUi+lynMPfEJzoEx/NCFq7KUsZqv0+FEVdWfStE+OFlFZ16GIJn9D3a4bS+aTbUzoE1CIM6X1zJBxnJCOHSHtVBM1vIVxFMgTOYTBiRB1kYXOvYFQZgaHrdaKbmZRm9THVq2gGCfAqfgvwpCWGB/q4eJl32+zaGA6Z+qB2Y2hYZlzWghuimjbqFqyxYc3fbxQ7o66BvrQD8NGAkpxll59rXA4+eItBPWfp/iSC2a5Ye7phKOCme/fsJJKq1uZZP5W3kI8NjsjJFWKD6AQxqH3uL6VL0THokxSpxYNgb0aUGdG5BowYJ4ueOvmeZ+A1D4mwswVuxuWZMZh+Zz90enAPuCf08WZ6w8SOopUJRtiSsaXHC3obYlk81v6+3oe9V439Scs+CKiEXq1Xzu95HGfkDU3dttu6Rq6G2tOEI88XLbiXl3Eu7j7vtCMAOitVGA9e/KhPGtZAhRL2eprAgbx8GN7HyIaVrcE60iMpGdrkuSOY+Mi7Goa69P/f3pktK4oEYfiNJqhiv5Rd2RVRuWN3B0Eo5enHsqM7+gh9Zib6dLdxnEsNQ7G+qiT/zCSzRPJKqON0cvGv4eGgIZG74JhZAZlqcd86tWFMtzmrt5PtpZoukZF0iBvnoHZ2cclNjh4X5FvsXzNznCV1NQ5uWqsgVlNJEdPEYo55hlR11G0zfh61RILDdI49jfdrdY59fOvaHEmKPVcVHW9wIgyRAFe9tVKEI5jLLWLdaMnNLJcQjc7z9aCJZrvF6rRFZn3yrkFNiAo1amaMieMJEXM7dWVChbbTpbxKZpd1FMB6QbbLe02zUXgXi2OicT0nkwPWKDHTsYsVCXiCYZb4ioxr2NGB5ZaVPY1sVjcy12qjSWvnWlxxZmJnKbJ3FJRWAEBDs+ijx7dplAr34NBduzMVcbNT9eogjqLgTICiWX6JDa+QpcDzUZlDax2Zfti0PrmbiXCdbaPWyaVrKDaVf/anLddtOiUtPAMeWR9SO1q9joMWNcvL2T2rtxO0zCpzHBqGMHfqDb0jDyeaZEY4FUoYMW+zp3l3Rie8hs1s73QoV1UTsAJQ+UjJbKja471P0D4DpkePlFlzx80Yvy1iLdaPTZuWnQ5E0vQSftJmoeMvART422pW9OGakIUzq3SaEn0QswqVdl3azIv6mrSrVqtvchhfBW0Yywwl9L2ufOWwJn4GU0uofNFImyKGxKlS6ak9cUJ8ToQcMaksQfsQLWYlj1ubCYkkx4V1Oqw9Wk6dWqpPUQqsM2EiV9rL1I4/rZFvQqGsBdcoiVz3g2QRUQT0PGnkiRodz+9WOskjZWl5gmvPRW7HKhqhx9JqQ55CfII49hDiM69ft2CUzZxNFN0Mn321zovYha5DMRdYTW4/SZtBdSFm1JHEsU6PJ7o8V+/WmnWULOiuHkosstRNUyjIFpZo7FSXhL9/Ks0STdzzK+meKVJGCB2OsSNmJSINxOuXPL+XfuFbHQ7sljq6MIutEKdmMaNVIc4muGsV0RTzcm5c5UQEDmoLWSO2qi7EM+l6kO0dmPrcRNjkvlykQkdFgO1aYayMT7acjuYW1/C4AE9S93lryoSzWCKNOKmyWBOn1t6hLZnYjs/xzgzu8TMK/IVvt1QJeRcoGkipPMhk3SXDFkV0LGaHzO/WwplZk8dDla2zMdvVF/zkAadbpHTa664acmyHdHqRtCCj3KBpZCXjLyG3ZSTuFCwTxXfWQXzlxoWjxi2Tx5rt3Y+9LqMLqjZrCbtIAifaV+qskHkA0t1qLOkOXK5mHTbwU2OX0KGre7jWSqDXuA5XgyyaHDUhOyzuztRI3ivebta4B1H8GG+YYx6bxvZ70pMDvvDXQcwf7gv3e8Z+nFD+T02gf7NMHlwM+G/7w/6maXcc9dtk8nvr8b9K/kPdYTkGvOVP/b6hd++Fh77bEP0dcfuaTVljRmi9Oac4NHnfIFVYvrUTPeX7yAC/HhLSP2bz/Ua5vR9CgoD0Nxa9hR/A8+M4xkOrZsD3WcAhy/2rWPRDWAPzTD8nCwo+GYv+HNCBXuyfkwVNPA72/eM0QH8IwsC0rk+Kg3s+HP1468C09s+Jg+GfzFIN9HdnXwUGB54NRn8Y3EAu85PC4MCTweg7t/yrwMBdlp6MBtOj8fUSXwEH9xYHRbF/DQChB4DQvwpIX298vbG/AhDwfED6ogO8jBrnyceqgmcg0h/vDl5Gkz96uk/AA/Z1IHgdXU7Rz3dCIOwTeRlpToHn49FXg+BltDkJnvAeAgf83lcBAvlHIH9chgzo8Q8foPnAQOBoPAby/cGZ7+dGv1zzQ3byH1OiwwvADiP72QJggnwD+pu4+/jM5jt/6//U5tt99aMC4J871Qx4LAAmf1kBMK6kKorz95vlZhTXZpGk+BN/Aw==</diagram></mxfile>"
  },
  {
    "path": "docs/raw/en/index.html",
    "content": "<!doctype html><html xmlns=http://www.w3.org/1999/xhtml lang=en xml:lang=en><meta charset=utf-8><meta name=generator content=\"pandoc\"><meta name=viewport content=\"width=device-width,initial-scale=1,user-scalable=yes\"><meta name=author content=\"Muntashir Al-Islam\"><title>App Manager</title><style>code{white-space:pre-wrap}span.smallcaps{font-variant:small-caps}div.columns{display:flex;gap:min(4vw,1.5em)}div.column{flex:auto;overflow-x:auto}div.hanging-indent{margin-left:1.5em;text-indent:-1.5em}ul.task-list[class]{list-style:none}ul.task-list li input[type=checkbox]{font-size:inherit;width:.8em;margin:0 .8em .2em -1.6em;vertical-align:middle}.display.math{display:block;text-align:center;margin:.5rem auto}html{-webkit-text-size-adjust:100%}pre>code.sourceCode{white-space:pre;position:relative}pre>code.sourceCode>span{display:inline-block;line-height:1.25}pre>code.sourceCode>span:empty{height:1.2em}.sourceCode{overflow:visible}code.sourceCode>span{color:inherit;text-decoration:inherit}div.sourceCode{margin:1em 0}pre.sourceCode{margin:0}@media screen{div.sourceCode{overflow:auto}}@media print{pre>code.sourceCode{white-space:pre-wrap}pre>code.sourceCode>span{text-indent:-5em;padding-left:5em}}pre.numberSource code{counter-reset:source-line 0}pre.numberSource code>span{position:relative;left:-4em;counter-increment:source-line}pre.numberSource code>span>a:first-child::before{content:counter(source-line);position:relative;left:-1em;text-align:right;vertical-align:baseline;border:none;display:inline-block;-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;padding:0 4px;width:4em}pre.numberSource{margin-left:3em;padding-left:4px}div.sourceCode{}@media screen{pre>code.sourceCode>span>a:first-child::before{text-decoration:underline}}code span.al{font-weight:700}code span.an{font-style:italic}code span.cf{font-weight:700}code span.co{font-style:italic}code span.cv{font-style:italic}code span.do{font-style:italic}code span.dt{text-decoration:underline}code span.er{font-weight:700}code span.in{font-style:italic}code span.kw{font-weight:700}code span.pp{font-weight:700}code span.wa{font-style:italic}</style><link rel=stylesheet href=../css/custom.css><header id=title-block-header><h1 class=title>App Manager</h1><p class=author>Muntashir Al-Islam</header><nav id=TOC role=doc-toc><ul class=incremental><li><span><span class=toc-section-number>1</span> <a href=#ch:introduction id=toc:ch:introduction>Introduction</a></span><ul class=incremental><li><span><span class=toc-section-number>1.1</span> <a href=#sec:terminologies id=toc:sec:terminologies>Terminologies</a></span><li><span><span class=toc-section-number>1.2</span> <a href=#sec:supported-versions id=toc:sec:supported-versions>Supported\nVersions</a></span><li><span><span class=toc-section-number>1.3</span> <a href=#sec:official-sources id=toc:sec:official-sources>Official\nSources</a></span><ul class=incremental><li><span><span class=toc-section-number>1.3.1</span> <a href=#subsec:binary-distribution-sources id=toc:subsec:binary-distribution-sources>Binary Distribution\nSources</a></span><li><span><span class=toc-section-number>1.3.2</span> <a href=#subsec:links-to-source-code id=toc:subsec:links-to-source-code>Links to the Source\nCode</a></span><li><span><span class=toc-section-number>1.3.3</span> <a href=#subsec:translations id=toc:subsec:translations>Translations</a></span></ul><li><span><span class=toc-section-number>1.4</span> <a href=#sec:contributing id=toc:sec:contributing>Contributing</a></span><ul class=incremental><li><span><span class=toc-section-number>1.4.1</span> <a href=#subsec:build-instructions id=toc:subsec:build-instructions>Build Instructions</a></span><li><span><span class=toc-section-number>1.4.2</span> <a href=#subsec:submitting-patches id=toc:subsec:submitting-patches>Submitting patches</a></span></ul><li><span><span class=toc-section-number>1.5</span> <a href=#sec:donation-&-funding id=toc:sec:donation-&-funding>Donation &\nFunding</a></span><li><span><span class=toc-section-number>1.6</span> <a href=#sec:contact id=toc:sec:contact>Contact</a></span></ul><li><span><span class=toc-section-number>2</span> <a href=#ch:pages id=toc:ch:pages>Pages</a></span><ul class=incremental><li><span><span class=toc-section-number>2.1</span> <a href=#sec:main-page id=toc:sec:main-page>Main Page</a></span><ul class=incremental><li><span><span class=toc-section-number>2.1.1</span> <a href=#subsec:batch-operations id=toc:subsec:batch-operations>Batch\nOperations</a></span><li><span><span class=toc-section-number>2.1.2</span> <a href=#subsec:main-colour-codes id=toc:subsec:main-colour-codes>Colour Codes</a></span><li><span><span class=toc-section-number>2.1.3</span> <a href=#subsec:main-page-application-types id=toc:subsec:main-page-application-types>Application\nTypes</a></span><li><span><span class=toc-section-number>2.1.4</span> <a href=#subsec:main-page-version-info id=toc:subsec:main-page-version-info>Version Info</a></span><li><span><span class=toc-section-number>2.1.5</span> <a href=#subsec:main-page-options-menu id=toc:subsec:main-page-options-menu>Options Menu</a></span></ul><li><span><span class=toc-section-number>2.2</span> <a href=#sec:app-details-page id=toc:sec:app-details-page>App Details\nPage</a></span><ul class=incremental><li><span><span class=toc-section-number>2.2.1</span> <a href=#subsec:app-details-colour-codes id=toc:subsec:app-details-colour-codes>Colour Codes</a></span><li><span><span class=toc-section-number>2.2.2</span> <a href=#subsec:app-info-tab id=toc:subsec:app-info-tab>App Info\nTab</a></span><li><span><span class=toc-section-number>2.2.3</span> <a href=#subsec:component-tabs id=toc:subsec:component-tabs>Component\nTabs</a></span><li><span><span class=toc-section-number>2.2.4</span> <a href=#subsec:permission-tabs id=toc:subsec:permission-tabs>Permission Tabs</a></span><li><span><span class=toc-section-number>2.2.5</span> <a href=#subsec:signatures-tab id=toc:subsec:signatures-tab>Signatures\nTab</a></span><li><span><span class=toc-section-number>2.2.6</span> <a href=#subsec:uses-features-tab id=toc:subsec:uses-features-tab>Uses\nFeatures tab</a></span><li><span><span class=toc-section-number>2.2.7</span> <a href=#subsec:configurations-tab id=toc:subsec:configurations-tab>Configurations tab</a></span><li><span><span class=toc-section-number>2.2.8</span> <a href=#subsec:shared-libs-tab id=toc:subsec:shared-libs-tab>Shared\nLibraries Tab</a></span></ul><li><span><span class=toc-section-number>2.3</span> <a href=#sec:1-click-ops-page id=toc:sec:1-click-ops-page>1-Click Ops\nPage</a></span><ul class=incremental><li><span><span class=toc-section-number>2.3.1</span> <a href=#subsec:block-unblock-trackers id=toc:subsec:block-unblock-trackers>Block/Unblock\nTrackers</a></span><li><span><span class=toc-section-number>2.3.2</span> <a href=#subsec:block-components-dots id=toc:subsec:block-components-dots>Block Components…</a></span><li><span><span class=toc-section-number>2.3.3</span> <a href=#subsec:set-mode-for-app-ops-dots id=toc:subsec:set-mode-for-app-ops-dots>Set Mode for App\nOps…</a></span><li><span><span class=toc-section-number>2.3.4</span> <a href=#subsec:1-click-back-up id=toc:subsec:1-click-back-up>Back\nup</a></span><li><span><span class=toc-section-number>2.3.5</span> <a href=#subsec:1-click-restore id=toc:subsec:1-click-restore>Restore</a></span><li><span><span class=toc-section-number>2.3.6</span> <a href=#subsec:trim-caches-in-all-apps id=toc:subsec:trim-caches-in-all-apps>Trim Caches in All\nApps</a></span></ul><li><span><span class=toc-section-number>2.4</span> <a href=#sec:profiles-page id=toc:sec:profiles-page>Profiles\nPage</a></span><ul class=incremental><li><span><span class=toc-section-number>2.4.1</span> <a href=#subsec:profiles-options-menu id=toc:subsec:profiles-options-menu>Options Menu</a></span></ul><li><span><span class=toc-section-number>2.5</span> <a href=#sec:profile-page id=toc:sec:profile-page>Profile\nPage</a></span><ul class=incremental><li><span><span class=toc-section-number>2.5.1</span> <a href=#subsec:profile-options-menu id=toc:subsec:profile-options-menu>Options Menu</a></span><li><span><span class=toc-section-number>2.5.2</span> <a href=#subsec:profile-apps-tab id=toc:subsec:profile-apps-tab>Apps\nTab</a></span><li><span><span class=toc-section-number>2.5.3</span> <a href=#subsec:profile-configurations-tab id=toc:subsec:profile-configurations-tab>Configurations\nTab</a></span></ul><li><span><span class=toc-section-number>2.6</span> <a href=#sec:settings-page id=toc:sec:settings-page>Settings\nPage</a></span><ul class=incremental><li><span><span class=toc-section-number>2.6.1</span> <a href=#subsec:language id=toc:subsec:language>Language</a></span><li><span><span class=toc-section-number>2.6.2</span> <a href=#subsec:appearance id=toc:subsec:appearance>Appearance</a></span><li><span><span class=toc-section-number>2.6.3</span> <a href=#subsec:privacy id=toc:subsec:privacy>Privacy</a></span><li><span><span class=toc-section-number>2.6.4</span> <a href=#subsec:mode-of-operation id=toc:subsec:mode-of-operation>Mode\nof Operation</a></span><li><span><span class=toc-section-number>2.6.5</span> <a href=#subsec:apk-signing id=toc:subsec:apk-signing>APK\nSigning</a></span><li><span><span class=toc-section-number>2.6.6</span> <a href=#subsec:installer id=toc:subsec:installer>Installer</a></span><li><span><span class=toc-section-number>2.6.7</span> <a href=#subsec:backup/restore id=toc:subsec:backup/restore>Back\nup/Restore</a></span><li><span><span class=toc-section-number>2.6.8</span> <a href=#subsec:rules id=toc:subsec:rules>Rules</a></span><li><span><span class=toc-section-number>2.6.9</span> <a href=#subsec:advanced id=toc:subsec:advanced>Advanced</a></span><li><span><span class=toc-section-number>2.6.10</span> <a href=#subsec:device-info id=toc:subsec:device-info>About the\ndevice</a></span></ul><li><span><span class=toc-section-number>2.7</span> <a href=#sec:scanner-page id=toc:sec:scanner-page>Scanner\nPage</a></span><li><span><span class=toc-section-number>2.8</span> <a href=#sec:interceptor-page id=toc:sec:interceptor-page>Interceptor\nPage</a></span><ul class=incremental><li><span><span class=toc-section-number>2.8.1</span> <a href=#subsec:intent-filters id=toc:subsec:intent-filters>Intent\nFilters</a></span><li><span><span class=toc-section-number>2.8.2</span> <a href=#subsec:matching-activities id=toc:subsec:matching-activities>Matching Activities</a></span><li><span><span class=toc-section-number>2.8.3</span> <a href=#subsec:interceptor-reset-to-default id=toc:subsec:interceptor-reset-to-default>Reset to\nDefault</a></span><li><span><span class=toc-section-number>2.8.4</span> <a href=#subsec:interceptor-send-edited-intent id=toc:subsec:interceptor-send-edited-intent>Send Edited\nIntent</a></span></ul><li><span><span class=toc-section-number>2.9</span> <a href=#sec:shared-preferences-editor-page id=toc:sec:shared-preferences-editor-page>Shared Preferences Editor\nPage</a></span></ul><li><span><span class=toc-section-number>3</span> <a href=#ch:guides id=toc:ch:guides>Guides</a></span><ul class=incremental><li><span><span class=toc-section-number>3.1</span> <a href=#sec:adb-over-tcp id=toc:sec:adb-over-tcp>ADB over\nTCP</a></span><ul class=incremental><li><span><span class=toc-section-number>3.1.1</span> <a href=#subsec:enable-developer-options id=toc:subsec:enable-developer-options>Enable developer\noptions</a></span><li><span><span class=toc-section-number>3.1.2</span> <a href=#subsec:enable-usb-debugging id=toc:subsec:enable-usb-debugging>Enable USB\ndebugging</a></span><li><span><span class=toc-section-number>3.1.3</span> <a href=#subsec:setup-adb-on-pc-or-mac id=toc:subsec:setup-adb-on-pc-or-mac>Setup ADB on PC or\nMac</a></span><li><span><span class=toc-section-number>3.1.4</span> <a href=#subsec:configure-adb-over-tcp id=toc:subsec:configure-adb-over-tcp>Configure ADB over\nTCP</a></span></ul><li><span><span class=toc-section-number>3.2</span> <a href=#sec:wireless-debugging id=toc:sec:wireless-debugging>Wireless\nDebugging</a></span><ul class=incremental><li><span><span class=toc-section-number>3.2.1</span> <a href=#subsec:enable-developer-options-and-usb-debugging id=toc:subsec:enable-developer-options-and-usb-debugging>Enable\ndeveloper options and USB Debugging</a></span><li><span><span class=toc-section-number>3.2.2</span> <a href=#subsec:enable-wireless-debugging id=toc:subsec:enable-wireless-debugging>Enable Wireless\nDebugging</a></span><li><span><span class=toc-section-number>3.2.3</span> <a href=#subsec:pair-adb-with-app-manager id=toc:subsec:pair-adb-with-app-manager>Pair ADB with App\nManager</a></span><li><span><span class=toc-section-number>3.2.4</span> <a href=#subsec:connect-app-manager-to-adb id=toc:subsec:connect-app-manager-to-adb>Connect App Manager to\nADB</a></span></ul><li><span><span class=toc-section-number>3.3</span> <a href=#sec:backup-restore id=toc:sec:backup-restore>Back\nup/Restore</a></span><ul class=incremental><li><span><span class=toc-section-number>3.3.1</span> <a href=#subsec:backup-location id=toc:subsec:backup-location>Location</a></span><li><span><span class=toc-section-number>3.3.2</span> <a href=#subsec:backup-restore-backup-options id=toc:subsec:backup-restore-backup-options>Backup\nOptions</a></span><li><span><span class=toc-section-number>3.3.3</span> <a href=#subsec:backup-restore-backup id=toc:subsec:backup-restore-backup>Backup</a></span><li><span><span class=toc-section-number>3.3.4</span> <a href=#subsec:backup-restore-restore id=toc:subsec:backup-restore-restore>Restore</a></span><li><span><span class=toc-section-number>3.3.5</span> <a href=#subsec:backup-restore-delete-backup id=toc:subsec:backup-restore-delete-backup>Delete\nBackup</a></span></ul><li><span><span class=toc-section-number>3.4</span> <a href=#sec:automating-tasks id=toc:sec:automating-tasks>Automating\nTasks</a></span><ul class=incremental><li><span><span class=toc-section-number>3.4.1</span> <a href=#subsec:generating-authorization-key id=toc:subsec:generating-authorization-key>Generating authorization\nkey</a></span><li><span><span class=toc-section-number>3.4.2</span> <a href=#subsec:at:general-configuration id=toc:subsec:at:general-configuration>Configuring\ntasks</a></span><li><span><span class=toc-section-number>3.4.3</span> <a href=#subsec:at:features id=toc:subsec:at:features>Features</a></span><li><span><span class=toc-section-number>3.4.4</span> <a href=#subsec:triggering-a-profile id=toc:subsec:triggering-a-profile>Triggering a\nprofile</a></span></ul><li><span><span class=toc-section-number>3.5</span> <a href=#sec:net-policy id=toc:sec:net-policy>Net\nPolicy</a></span></ul><li><span><span class=toc-section-number>4</span> <a href=#ch:faq id=toc:ch:faq>Frequently Asked Questions</a></span><ul class=incremental><li><span><span class=toc-section-number>4.1</span> <a href=#sec:faq:app-components id=toc:sec:faq:app-components>App\nComponents</a></span><ul class=incremental><li><span><span class=toc-section-number>4.1.1</span> <a href=#subsec:faq:what-are-app-components id=toc:subsec:faq:what-are-app-components>What are the application\ncomponents?</a></span><li><span><span class=toc-section-number>4.1.2</span> <a href=#subsec:faq:how-components-blocked id=toc:subsec:faq:how-components-blocked>How are the tracker and other\ncomponents blocked in App Manager? What are its\nlimitations?</a></span><li><span><span class=toc-section-number>4.1.3</span> <a href=#subsec:faq:components-blocked-by-others id=toc:subsec:faq:components-blocked-by-others>Does app components\nblocked by other tools retained in App Manager?</a></span><li><span><span class=toc-section-number>4.1.4</span> <a href=#subsec:faq:components-reblocked-in-am id=toc:subsec:faq:components-reblocked-in-am>What happens to the\ncomponents blocked by App Manager which were previously blocked by other\ntools?</a></span><li><span><span class=toc-section-number>4.1.5</span> <a href=#subsec:faq:what-is-instant-component-blocking id=toc:subsec:faq:what-is-instant-component-blocking>What is instant\ncomponent blocking?</a></span><li><span><span class=toc-section-number>4.1.6</span> <a href=#subsec:tracker-classes-versus-tracker-components id=toc:subsec:tracker-classes-versus-tracker-components>Tracker\nclasses versus tracker components</a></span></ul><li><span><span class=toc-section-number>4.2</span> <a href=#sec:faq:adb-over-tcp id=toc:sec:faq:adb-over-tcp>ADB over\nTCP</a></span><ul class=incremental><li><span><span class=toc-section-number>4.2.1</span> <a href=#subsec:faq:enable-adb-on-every-restart id=toc:subsec:faq:enable-adb-on-every-restart>Do I have to enable ADB\nover TCP everytime I restart?</a></span><li><span><span class=toc-section-number>4.2.2</span> <a href=#subsec:faq:usb-debugging id=toc:subsec:faq:usb-debugging>Cannot enable USB debugging. What to\ndo?</a></span><li><span><span class=toc-section-number>4.2.3</span> <a href=#subsec:faq:block-components-using-adb id=toc:subsec:faq:block-components-using-adb>Can I block tracker or\nany other application components using ADB over TCP?</a></span><li><span><span class=toc-section-number>4.2.4</span> <a href=#subsec:faq:adb-features id=toc:subsec:faq:adb-features>Which\nfeatures can be used in ADB mode?</a></span></ul><li><span><span class=toc-section-number>4.3</span> <a href=#sec:faq:miscellanea id=toc:sec:faq:miscellanea>Miscellanea</a></span><ul class=incremental><li><span><span class=toc-section-number>4.3.1</span> <a href=#subsec:faq:no-root-no-harms id=toc:subsec:faq:no-root-no-harms>I don’t use root/ADB. Am I\ncompletely safe from any harms?</a></span><li><span><span class=toc-section-number>4.3.2</span> <a href=#subsec:faq:how-trackers-libs-updated id=toc:subsec:faq:how-trackers-libs-updated>How are the trackers and\nlibraries are updated?</a></span><li><span><span class=toc-section-number>4.3.3</span> <a href=#subsec:faq:apks-deleted-after-installed id=toc:subsec:faq:apks-deleted-after-installed>Are APKs deleted after\ninstalled?</a></span><li><span><span class=toc-section-number>4.3.4</span> <a href=#subsec:faq:shizuku-support id=toc:subsec:faq:shizuku-support>Any plans for\nShizuku?</a></span><li><span><span class=toc-section-number>4.3.5</span> <a href=#subsec:faq:what-are-bloatware id=toc:subsec:faq:what-are-bloatware>What are bloatware and how to\nremove them?</a></span></ul></ul><li><span><span class=toc-section-number>5</span> <a href=#ch:specifications id=toc:ch:specifications>Specifications</a></span><ul class=incremental><li><span><span class=toc-section-number>5.1</span> <a href=#sec:rules-specification id=toc:sec:rules-specification>Rules\nSpecification</a></span><ul class=incremental><li><span><span class=toc-section-number>5.1.1</span> <a href=#background id=toc:background>Background</a></span><li><span><span class=toc-section-number>5.1.2</span> <a href=#rules-file-format id=toc:rules-file-format>Rules File\nFormat</a></span></ul></ul><li><span><span class=toc-section-number>6</span> <a href=#ch:changelogs id=toc:ch:changelogs>Changelogs</a></span><ul class=incremental><li><span><span class=toc-section-number>6.1</span> <a href=#sec:v4.0.5-(445) id=toc:sec:v4.0.5-(445)>v4.0.5\n(445)</a></span><li><span><span class=toc-section-number>6.2</span> <a href=#sec:v4.0.4-(444) id=toc:sec:v4.0.4-(444)>v4.0.4\n(444)</a></span><li><span><span class=toc-section-number>6.3</span> <a href=#sec:v4.0.3-(443) id=toc:sec:v4.0.3-(443)>v4.0.3\n(443)</a></span><li><span><span class=toc-section-number>6.4</span> <a href=#sec:v4.0.2-(442) id=toc:sec:v4.0.2-(442)>v4.0.2\n(442)</a></span><li><span><span class=toc-section-number>6.5</span> <a href=#sec:v4.0.1-(441) id=toc:sec:v4.0.1-(441)>v4.0.1\n(441)</a></span><ul class=incremental><li><span><span class=toc-section-number>6.5.1</span> <a href=#overlay-management id=toc:overlay-management>Overlay\nmanagement</a></span><li><span><span class=toc-section-number>6.5.2</span> <a href=#unfreeze-option-in-activity-shortcuts id=toc:unfreeze-option-in-activity-shortcuts>Unfreeze option in\nactivity shortcuts</a></span><li><span><span class=toc-section-number>6.5.3</span> <a href=#market-like-url-support id=toc:market-like-url-support><code>market</code>-like URL\nsupport</a></span><li><span><span class=toc-section-number>6.5.4</span> <a href=#updated-color-codes id=toc:updated-color-codes>Updated color\ncodes</a></span><li><span><span class=toc-section-number>6.5.5</span> <a href=#others id=toc:others>Others</a></span></ul><li><span><span class=toc-section-number>6.6</span> <a href=#sec:v4.0.0-(440) id=toc:sec:v4.0.0-(440)>v4.0.0\n(440)</a></span><ul class=incremental><li><span><span class=toc-section-number>6.6.1</span> <a href=#new-logo id=toc:new-logo>New logo!</a></span><li><span><span class=toc-section-number>6.6.2</span> <a href=#android-14-and-15-support id=toc:android-14-and-15-support>Android 14 and 15\nsupport</a></span><li><span><span class=toc-section-number>6.6.3</span> <a href=#revamped-debloater id=toc:revamped-debloater>Revamped\ndebloater</a></span><li><span><span class=toc-section-number>6.6.4</span> <a href=#introducing-file-manager id=toc:introducing-file-manager>Introducing file\nmanager</a></span><li><span><span class=toc-section-number>6.6.5</span> <a href=#integrated-code-editor id=toc:integrated-code-editor>Integrated code editor</a></span><li><span><span class=toc-section-number>6.6.6</span> <a href=#history-of-operations id=toc:history-of-operations>History of\noperations</a></span><li><span><span class=toc-section-number>6.6.7</span> <a href=#per-app-freezing-and-more id=toc:per-app-freezing-and-more>Per-app freezing, and\nmore</a></span><li><span><span class=toc-section-number>6.6.8</span> <a href=#log-viewer-enhancements id=toc:log-viewer-enhancements>Log\nviewer enhancements</a></span><li><span><span class=toc-section-number>6.6.9</span> <a href=#launching-non-exported-activities id=toc:launching-non-exported-activities>Launching non-exported\nactivities</a></span><li><span><span class=toc-section-number>6.6.10</span> <a href=#new-tags-in-app-info-tab id=toc:new-tags-in-app-info-tab>New\ntags in App Info tab</a></span><li><span><span class=toc-section-number>6.6.11</span> <a href=#per-session-installer-options id=toc:per-session-installer-options>Per-session installer\noptions</a></span><li><span><span class=toc-section-number>6.6.12</span> <a href=#advanced-mode-of-operations-adb-enhancements id=toc:advanced-mode-of-operations-adb-enhancements>Advanced mode of\noperations, ADB enhancements, …</a></span><li><span><span class=toc-section-number>6.6.13</span> <a href=#data-usage-widget-and-more id=toc:data-usage-widget-and-more>Data usage widget, and\nmore</a></span><li><span><span class=toc-section-number>6.6.14</span> <a href=#others-1 id=toc:others-1>Others</a></span></ul><li><span><span class=toc-section-number>6.7</span> <a href=#sec:v3.1.0-(423) id=toc:sec:v3.1.0-(423)>v3.1.0\n(423)</a></span><ul class=incremental><li><span><span class=toc-section-number>6.7.1</span> <a href=#android-13-support id=toc:android-13-support>Android 13\nsupport</a></span><li><span><span class=toc-section-number>6.7.2</span> <a href=#introducing-freezeunfreeze id=toc:introducing-freezeunfreeze>Introducing\nfreeze/unfreeze</a></span><li><span><span class=toc-section-number>6.7.3</span> <a href=#export-app-list id=toc:export-app-list>Export app\nlist</a></span><li><span><span class=toc-section-number>6.7.4</span> <a href=#elliptic-curve-crypography-ecc id=toc:elliptic-curve-crypography-ecc>Elliptic Curve Crypography\n(ECC)</a></span><li><span><span class=toc-section-number>6.7.5</span> <a href=#new-languages id=toc:new-languages>New\nlanguages</a></span><li><span><span class=toc-section-number>6.7.6</span> <a href=#more-list-options id=toc:more-list-options>More list\noptions</a></span><li><span><span class=toc-section-number>6.7.7</span> <a href=#improved-handling-of-mode-of-operation id=toc:improved-handling-of-mode-of-operation>Improved handling of\nmode of operation</a></span><li><span><span class=toc-section-number>6.7.8</span> <a href=#handling-multiple-users id=toc:handling-multiple-users>Handling multiple users</a></span><li><span><span class=toc-section-number>6.7.9</span> <a href=#explorer-enhancements id=toc:explorer-enhancements>Explorer\nenhancements</a></span><li><span><span class=toc-section-number>6.7.10</span> <a href=#new-tag-wx id=toc:new-tag-wx>New tag: WX</a></span><li><span><span class=toc-section-number>6.7.11</span> <a href=#app-ops-management id=toc:app-ops-management>App ops\nmanagement</a></span><li><span><span class=toc-section-number>6.7.12</span> <a href=#batch-uninstallation id=toc:batch-uninstallation>Batch\nuninstallation</a></span><li><span><span class=toc-section-number>6.7.13</span> <a href=#running-apps id=toc:running-apps>Running apps</a></span><li><span><span class=toc-section-number>6.7.14</span> <a href=#interceptor id=toc:interceptor>Interceptor</a></span><li><span><span class=toc-section-number>6.7.15</span> <a href=#device-specific-changes id=toc:device-specific-changes>Device-specific changes</a></span><li><span><span class=toc-section-number>6.7.16</span> <a href=#others-2 id=toc:others-2>Others</a></span></ul><li><span><span class=toc-section-number>6.8</span> <a href=#sec:v3.0.0-(410) id=toc:sec:v3.0.0-(410)>v3.0.0\n(410)</a></span><ul class=incremental><li><span><span class=toc-section-number>6.8.1</span> <a href=#material-3-and-more id=toc:material-3-and-more>Material 3 and\nMore</a></span><li><span><span class=toc-section-number>6.8.2</span> <a href=#wireless-debugging id=toc:wireless-debugging>Wireless\nDebugging</a></span><li><span><span class=toc-section-number>6.8.3</span> <a href=#languages id=toc:languages>Languages</a></span><li><span><span class=toc-section-number>6.8.4</span> <a href=#introducing-app-explorer id=toc:introducing-app-explorer>Introducing App\nExplorer</a></span><li><span><span class=toc-section-number>6.8.5</span> <a href=#import-backups-from-other-applications id=toc:import-backups-from-other-applications>Import Backups from\nOther Applications</a></span><li><span><span class=toc-section-number>6.8.6</span> <a href=#virustotal id=toc:virustotal>VirusTotal</a></span><li><span><span class=toc-section-number>6.8.7</span> <a href=#trigger-profiles-from-the-automation-software id=toc:trigger-profiles-from-the-automation-software>Trigger Profiles\nfrom the Automation Software</a></span><li><span><span class=toc-section-number>6.8.8</span> <a href=#improved-application-installer id=toc:improved-application-installer>Improved Application\nInstaller</a></span><li><span><span class=toc-section-number>6.8.9</span> <a href=#component-blocking id=toc:component-blocking>Component\nBlocking</a></span><li><span><span class=toc-section-number>6.8.10</span> <a href=#advanced-searching id=toc:advanced-searching>Advanced\nSearching</a></span><li><span><span class=toc-section-number>6.8.11</span> <a href=#shared-libraries id=toc:shared-libraries>Shared\nLibraries</a></span><li><span><span class=toc-section-number>6.8.12</span> <a href=#make-the-best-use-of-interceptor id=toc:make-the-best-use-of-interceptor>Make the Best Use of\nInterceptor</a></span><li><span><span class=toc-section-number>6.8.13</span> <a href=#widget-screen-time id=toc:widget-screen-time>Widget: Screen\nTime</a></span><li><span><span class=toc-section-number>6.8.14</span> <a href=#widget-clear-cache id=toc:widget-clear-cache>Widget: Clear\nCache</a></span></ul><li><span><span class=toc-section-number>6.9</span> <a href=#sec:v2.6.0-(385) id=toc:sec:v2.6.0-(385)>v2.6.0\n(385)</a></span><ul class=incremental><li><span><span class=toc-section-number>6.9.1</span> <a href=#introducing-backups id=toc:introducing-backups>Introducing\nBackups</a></span><li><span><span class=toc-section-number>6.9.2</span> <a href=#introducing-log-viewer id=toc:introducing-log-viewer>Introducing Log Viewer</a></span><li><span><span class=toc-section-number>6.9.3</span> <a href=#lock-app-manager id=toc:lock-app-manager>Lock App\nManager</a></span><li><span><span class=toc-section-number>6.9.4</span> <a href=#extended-modes-for-app-ops id=toc:extended-modes-for-app-ops>Extended Modes for App\nOps</a></span><li><span><span class=toc-section-number>6.9.5</span> <a href=#new-batch-ops-add-to-profile id=toc:new-batch-ops-add-to-profile>New Batch Ops: Add to\nProfile</a></span><li><span><span class=toc-section-number>6.9.6</span> <a href=#app-info-improved id=toc:app-info-improved>App Info:\nImproved</a></span><li><span><span class=toc-section-number>6.9.7</span> <a href=#advanced-sort-and-filtering-options-in-the-main-page id=toc:advanced-sort-and-filtering-options-in-the-main-page>Advanced\nSort and Filtering Options in the Main Page</a></span><li><span><span class=toc-section-number>6.9.8</span> <a href=#about-this-device id=toc:about-this-device>About This\nDevice</a></span><li><span><span class=toc-section-number>6.9.9</span> <a href=#enabledisable-features id=toc:enabledisable-features>Enable/disable Features</a></span><li><span><span class=toc-section-number>6.9.10</span> <a href=#new-languages-1 id=toc:new-languages-1>New\nLanguages</a></span><li><span><span class=toc-section-number>6.9.11</span> <a href=#signing-the-apk-files id=toc:signing-the-apk-files>Signing the\nAPK Files</a></span><li><span><span class=toc-section-number>6.9.12</span> <a href=#new-extension-unapkm id=toc:new-extension-unapkm>New\nExtension: UnAPKM</a></span></ul><li><span><span class=toc-section-number>6.10</span> <a href=#sec:v2.5.20-(375) id=toc:sec:v2.5.20-(375)>v2.5.20\n(375)</a></span><ul class=incremental><li><span><span class=toc-section-number>6.10.1</span> <a href=#subsec:introducing-profiles id=toc:subsec:introducing-profiles>Introducing\nProfiles</a></span><li><span><span class=toc-section-number>6.10.2</span> <a href=#subsec:the-interceptor id=toc:subsec:the-interceptor>The\nInterceptor</a></span><li><span><span class=toc-section-number>6.10.3</span> <a href=#subsec:unapkm:-dedrm-the-apkm-files id=toc:subsec:unapkm:-dedrm-the-apkm-files>UnAPKM: DeDRM the APKM\nfiles</a></span><li><span><span class=toc-section-number>6.10.4</span> <a href=#subsec:multiple-user id=toc:subsec:multiple-user>Multiple\nuser</a></span><li><span><span class=toc-section-number>6.10.5</span> <a href=#vive-la-france id=toc:vive-la-france>Vive la\nFrance!</a></span><li><span><span class=toc-section-number>6.10.6</span> <a href=#report-crashes id=toc:report-crashes>Report\ncrashes</a></span><li><span><span class=toc-section-number>6.10.7</span> <a href=#android-11 id=toc:android-11>Android 11</a></span><li><span><span class=toc-section-number>6.10.8</span> <a href=#app-installer-improvements id=toc:app-installer-improvements>App Installer\nImprovements</a></span></ul><li><span><span class=toc-section-number>6.11</span> <a href=#v2.5.17-368 id=toc:v2.5.17-368>v2.5.17 (368)</a></span><ul class=incremental><li><span><span class=toc-section-number>6.11.1</span> <a href=#app-installer id=toc:app-installer>App\nInstaller</a></span><li><span><span class=toc-section-number>6.11.2</span> <a href=#scanner-replacement-for-exodus-page id=toc:scanner-replacement-for-exodus-page>Scanner: Replacement for\nExodus Page</a></span><li><span><span class=toc-section-number>6.11.3</span> <a href=#introducing-system-config id=toc:introducing-system-config>Introducing System\nConfig</a></span><li><span><span class=toc-section-number>6.11.4</span> <a href=#more-languages id=toc:more-languages>More\nLanguages</a></span><li><span><span class=toc-section-number>6.11.5</span> <a href=#app-info-tab id=toc:app-info-tab>App Info Tab</a></span><li><span><span class=toc-section-number>6.11.6</span> <a href=#navigation-improvements id=toc:navigation-improvements>Navigation Improvements</a></span><li><span><span class=toc-section-number>6.11.7</span> <a href=#running-apps-page id=toc:running-apps-page>Running Apps\nPage</a></span><li><span><span class=toc-section-number>6.11.8</span> <a href=#built-in-toybox id=toc:built-in-toybox>Built-in\nToybox</a></span><li><span><span class=toc-section-number>6.11.9</span> <a href=#component-blocker-improvements id=toc:component-blocker-improvements>Component Blocker\nImprovements</a></span><li><span><span class=toc-section-number>6.11.10</span> <a href=#improvements-in-the-app-details-page id=toc:improvements-in-the-app-details-page>Improvements in the App\nDetails Page</a></span><li><span><span class=toc-section-number>6.11.11</span> <a href=#app-manifest id=toc:app-manifest>App Manifest</a></span></ul><li><span><span class=toc-section-number>6.12</span> <a href=#v2.5.13-348 id=toc:v2.5.13-348>v2.5.13 (348)</a></span><ul class=incremental><li><span><span class=toc-section-number>6.12.1</span> <a href=#bundled-app-split-apk id=toc:bundled-app-split-apk>Bundled App\n(Split APK)</a></span><li><span><span class=toc-section-number>6.12.2</span> <a href=#direct-install-support id=toc:direct-install-support>Direct\nInstall Support</a></span><li><span><span class=toc-section-number>6.12.3</span> <a href=#remove-all-blocking-rules id=toc:remove-all-blocking-rules>Remove All Blocking\nRules</a></span><li><span><span class=toc-section-number>6.12.4</span> <a href=#app-ops-1 id=toc:app-ops-1>App Ops</a></span><li><span><span class=toc-section-number>6.12.5</span> <a href=#enhanced-adb-support id=toc:enhanced-adb-support>Enhanced ADB\nSupport</a></span><li><span><span class=toc-section-number>6.12.6</span> <a href=#filtering-in-main-page id=toc:filtering-in-main-page>Filtering\nin Main Page</a></span><li><span><span class=toc-section-number>6.12.7</span> <a href=#apk-backupsharing id=toc:apk-backupsharing>Apk\nBackup/Sharing</a></span><li><span><span class=toc-section-number>6.12.8</span> <a href=#batch-ops id=toc:batch-ops>Batch Ops</a></span><li><span><span class=toc-section-number>6.12.9</span> <a href=#translations id=toc:translations>Translations</a></span><li><span><span class=toc-section-number>6.12.10</span> <a href=#app-data-backup id=toc:app-data-backup>App Data\nBackup</a></span></ul></ul><li><span><span class=toc-section-number>7</span> <a href=#ch:app-ops id=toc:ch:app-ops>App Ops</a></span><ul class=incremental><li><span><span class=toc-section-number>7.1</span> <a href=#sec:app-ops-background id=toc:sec:app-ops-background>Background</a></span><li><span><span class=toc-section-number>7.2</span> <a href=#sec:introduction-to-app-ops id=toc:sec:introduction-to-app-ops>Introduction to App\nOps</a></span><li><span><span class=toc-section-number>7.3</span> <a href=#sec:appopsmanager id=toc:sec:appopsmanager>AppOpsManager</a></span><ul class=incremental><li><span><span class=toc-section-number>7.3.1</span> <a href=#subsec:op-constants id=toc:subsec:op-constants><code>OP_*</code> Constants</a></span><li><span><span class=toc-section-number>7.3.2</span> <a href=#subsec:mode-constants id=toc:subsec:mode-constants><code>MODE_*</code>\nConstants</a></span><li><span><span class=toc-section-number>7.3.3</span> <a href=#subsec:package-ops id=toc:subsec:package-ops>PackageOps</a></span><li><span><span class=toc-section-number>7.3.4</span> <a href=#subsec:opentry id=toc:subsec:opentry>OpEntry</a></span><li><span><span class=toc-section-number>7.3.5</span> <a href=#subsec:usage id=toc:subsec:usage>Usage</a></span></ul><li><span><span class=toc-section-number>7.4</span> <a href=#sec:appopsservice id=toc:sec:appopsservice>AppOpsService</a></span><li><span><span class=toc-section-number>7.5</span> <a href=#sec:appops-xml id=toc:sec:appops-xml>appops.xml</a></span><li><span><span class=toc-section-number>7.6</span> <a href=#sec:appops-cli id=toc:sec:appops-cli>Command Line\nInterface</a></span></ul></ul></nav><div class=titlingpage><div class=center><p><img src=../images/icon.png style=width:1in alt=image><p><strong><span class=smallcaps>App Manager</span></strong><p><strong>User Manual</strong><p><em>v4.0.5</em><p>22 February 2026<p>Copyright © 2020–2025 Muntashir Al-Islam<blockquote><p>“Wisely and slow. They stumble that run fast.” <span>— Friar\nLaurence, <em>Romeo and Juliet</em></span></blockquote></div></div><section id=ch:introduction class=level1 data-number=1><h1 data-number=1><span class=header-section-number>1</span> <a href=#toc:ch:introduction>Introduction</a><a href=#ch:introduction class=anchor aria-hidden=true></a></h1><p>App Manager is an advanced package manager for Android. It offers\nnumerous features and thus, requires a user manual to assist its users.\nThis document acts as a user manual for App Manager in the sense that it\naims to describe every feature that App Manager has to offer. This\ndocument also serves as the “official” guidelines for App Manager and\nrepresents the expected behavior of App Manager. Translations can\nmisinterpret this document (which is in English). Therefore, a capable\nuser should read the English version of the document to get the most out\nof it. There may as well be other unofficial or third-party resources,\nsuch as blog articles, videos, forums, and chat groups. While these\nresources may be useful to many people, they may not be up-to-date with\nthe latest version of App Manager. In case of any deviations detected in\nApp Manager from this document, they should be reported in the <a href=https://github.com/MuntashirAkon/AppManager/issues>App Manager\nissue tracker</a>.<section id=sec:terminologies class=level2 data-number=1.1><h2 data-number=1.1><span class=header-section-number>1.1</span> <a href=#toc:sec:terminologies>Terminologies</a><a href=#sec:terminologies class=anchor aria-hidden=true></a></h2><ul class=incremental><li><p><strong>AM</strong> — Short name for App Manager.<li><p><strong>Block/Unblock</strong> — Used for component blocking or\nunblocking. How components are blocked depends on the user\npreferences.<li><p><strong>IFW</strong> — Short form of Intent Firewall.<li><p><strong>Ops</strong> — Short name for operations, e.g. app ops,\nbatch ops, 1-click ops<li><p><strong>SAF</strong> — Short for Storage Access Framework, an\nabstraction used by Android to allow apps to use or serve files without\nworrying about the underlying file system.<li><p><strong>SSAID</strong> — Short form of\n<code>Settings.Secure.ANDROID_ID</code>. It is a device identifier\nassigned to each app (Android Oreo onwards). It is generated from the\ncombination of the signing certificate of the app and the SSAID set for\nthe package <code>android</code>. As a result, it is guaranteed to be\nthe same for an app unless the user chooses to format the device. It is\nwidely used for tracking.<li><p><strong>Tracker</strong> — Denotes tracker components throughout\nthe document and in App Manager except in the <a href=#sec:scanner-page>scanner page</a>. Trackers include libraries\nsuch as crash reporters, analytics, profiling, identification, ad,\nlocation, etc. Thus, they are not equal in functions. There is no\ndistinction or bias among the open-source and closed-source libraries\nthat promote tracking.</ul></section><section id=sec:supported-versions class=level2 data-number=1.2><h2 data-number=1.2><span class=header-section-number>1.2</span> <a href=#toc:sec:supported-versions>Supported Versions</a><a href=#sec:supported-versions class=anchor aria-hidden=true></a></h2><p>At present, the supported version is v4.0.1. Previous versions of App\nManager may contain security vulnerabilities and should not be used.</section><section id=sec:official-sources class=level2 data-number=1.3><h2 data-number=1.3><span class=header-section-number>1.3</span> <a href=#toc:sec:official-sources>Official Sources</a><a href=#sec:official-sources class=anchor aria-hidden=true></a></h2><section id=subsec:binary-distribution-sources class=level3 data-number=1.3.1><h3 data-number=1.3.1><span class=header-section-number>1.3.1</span>\n<a href=#toc:subsec:binary-distribution-sources>Binary Distribution\nSources</a><a href=#subsec:binary-distribution-sources class=anchor aria-hidden=true></a></h3><p>App Manager is distributed using the following sources. Unofficial\nsources may distribute modified versions of App Manager, and you alone\nshall be responsible for the consequences of using such a\ndistribution.<ol class=incremental><li><p>Official F-Droid repository.<br><em>Link:</em> <a href=https://f-droid.org/packages/io.github.muntashirakon.AppManager class=uri>https://f-droid.org/packages/io.github.muntashirakon.AppManager</a><li><p>IzzyOnDroid repository.<br><em>Link:</em> <a href=https://apt.izzysoft.de/fdroid/index/apk/io.github.muntashirakon.AppManager class=uri>https://apt.izzysoft.de/fdroid/index/apk/io.github.muntashirakon.AppManager</a><li><p>GitHub repository.<br><em>Link:</em> <a href=https://github.com/MuntashirAkon/AppManager/releases class=uri>https://github.com/MuntashirAkon/AppManager/releases</a><li><p>Telegram.<br><em>Link:</em> <a href=https://t.me/AppManagerChannel class=uri>https://t.me/AppManagerChannel</a></ol></section><section id=subsec:links-to-source-code class=level3 data-number=1.3.2><h3 data-number=1.3.2><span class=header-section-number>1.3.2</span>\n<a href=#toc:subsec:links-to-source-code>Links to the Source\nCode</a><a href=#subsec:links-to-source-code class=anchor aria-hidden=true></a></h3><p>All but GitHub are mirrors. The tags should always be up-to-date, but\nthe master branch may not. If you want to clone the master branch, use\nthe GitHub link instead of the others.<ol class=incremental><li><p>GitHub: <a href=https://github.com/MuntashirAkon/AppManager class=uri>https://github.com/MuntashirAkon/AppManager</a><li><p>Codeberg: <a href=https://codeberg.org/muntashir/AppManager class=uri>https://codeberg.org/muntashir/AppManager</a><li><p>GitLab: <a href=https://gitlab.com/muntashir/AppManager class=uri>https://gitlab.com/muntashir/AppManager</a><li><p>Riseup: <a href=https://0xacab.org/muntashir/AppManager class=uri>https://0xacab.org/muntashir/AppManager</a><li><p>sourcehut: <a href=https://git.sr.ht/~muntashir/AppManager class=uri>https://git.sr.ht/~muntashir/AppManager</a></ol></section><section id=subsec:translations class=level3 data-number=1.3.3><h3 data-number=1.3.3><span class=header-section-number>1.3.3</span>\n<a href=#toc:subsec:translations>Translations</a><a href=#subsec:translations class=anchor aria-hidden=true></a></h3><p>App Manager does not accept translations via pull/merge requests.\nTranslations are managed through Hosted Weblate. To translate App\nManager, visit <a href=https://hosted.weblate.org/engage/app-manager/ class=uri>https://hosted.weblate.org/engage/app-manager/</a>. Please\nread the <strong>Info</strong> section before getting started.</section></section><section id=sec:contributing class=level2 data-number=1.4><h2 data-number=1.4><span class=header-section-number>1.4</span> <a href=#toc:sec:contributing>Contributing</a><a href=#sec:contributing class=anchor aria-hidden=true></a></h2><p>There are many ways a user can contribute, such as creating helpful\nissues, attending discussions, improving documentation and translations,\nreporting unknown libraries or trackers, reviewing the source code, and\nreporting security vulnerabilities.<section id=subsec:build-instructions class=level3 data-number=1.4.1><h3 data-number=1.4.1><span class=header-section-number>1.4.1</span>\n<a href=#toc:subsec:build-instructions>Build Instructions</a><a href=#subsec:build-instructions class=anchor aria-hidden=true></a></h3><p>Build instructions are available in the BUILDING file located in the\nsource root.</section><section id=subsec:submitting-patches class=level3 data-number=1.4.2><h3 data-number=1.4.2><span class=header-section-number>1.4.2</span>\n<a href=#toc:subsec:submitting-patches>Submitting patches</a><a href=#subsec:submitting-patches class=anchor aria-hidden=true></a></h3><p>Repositories located on sites other than GitHub are currently\nconsidered mirrors, and pull/merge requests submitted on those sites\nwill not be accepted.<a href=#fn1 class=footnote-ref id=fnref1 role=doc-noteref><sup>1</sup></a> Instead, patches (as\n<code>.patch</code> files) can be submitted via email attachments.\n<em>Signing-off is a requirement.</em> See the CONTRIBUTING file located\nat the source root for more information.<div class=\"amalert warning\"><p><strong><em>Notice.</em></strong><p>In the case of submitting patches via email, the whole conversation\nmay be publicly accessible in the future. So, please do not include\npersonally identifiable information (PII) other than your name or email\naddress.</div></section></section><section id=sec:donation-&-funding class=level2 data-number=1.5><h2 data-number=1.5><span class=header-section-number>1.5</span> <a href=#toc:sec:donation-&-funding>Donation & Funding</a><a href=#sec:donation-&-funding class=anchor aria-hidden=true></a></h2><p>As of September 2024, App Manager is not accepting financial support\nuntil further notice. But you may still be able to send gifts (e.g.,\ngift cards, subscriptions, food and drink, flowers, or even cash).\nPlease reach out to the maintainer using the options given in §<a href=#sec:contact data-reference-type=ref data-reference=sec:contact>1.6</a> for further assistance.<p>In addition, the maintainers and contributors of this project DO NOT\nconsent to the creation, sale, or promotion of tokens, cryptocurrencies,\nNFTs, or any other financial instruments that claim to represent this\nproject, its code, or its community. Any such attempts are unauthorized\nand not affiliated with this project in any way.</section><section id=sec:contact class=level2 data-number=1.6><h2 data-number=1.6><span class=header-section-number>1.6</span> <a href=#toc:sec:contact>Contact</a><a href=#sec:contact class=anchor aria-hidden=true></a></h2><p>App Manager Community<br>Email: <a href=mailto:am4android@riseup.net>am4android [at] riseup\n[dot] net</a><br>GitHub: <a href=https://github.com/AMCommunity class=uri>https://github.com/AMCommunity</a><br>Twitter/X: <a href=https://x.com/AppManagerNews class=uri>https://x.com/AppManagerNews</a><br>Mastodon: <a href=https://floss.social/@appmanager>@appmanager@floss.social</a><br><br>Muntashir Al-Islam<a href=#fn2 class=footnote-ref id=fnref2 role=doc-noteref><sup>2</sup></a><br>Email: <a href=mailto:muntashirakon@riseup.net>muntashirakon [at]\nriseup [dot] net</a><br>GitHub: <a href=https://github.com/MuntashirAkon class=uri>https://github.com/MuntashirAkon</a><br>Twitter/X: <a href=https://x.com/Muntashir class=uri>https://x.com/Muntashir</a><br>Mastodon: <a href=https://infosec.exchange/@muntashir>@muntashir@infosec.exchange</a></section></section><section id=ch:pages class=level1 data-number=2><h1 data-number=2><span class=header-section-number>2</span> <a href=#toc:ch:pages>Pages</a><a href=#ch:pages class=anchor aria-hidden=true></a></h1><section id=sec:main-page class=level2 data-number=2.1><h2 data-number=2.1><span class=header-section-number>2.1</span> <a href=#toc:sec:main-page>Main Page</a><a href=#sec:main-page class=anchor aria-hidden=true></a></h2><p>Main page lists all the installed, uninstalled and backed up\napplications. A single click on any installed application item opens the\nrespective <a href=#sec:app-details-page>App Details page</a>. For the\nuninstalled system applications, a dialog prompt is displayed with an\noption reinstall them. The applications uninstalled without removing\ntheir data and signatures are also displayed in this page with an option\nto perform a full uninstallation. For the uninstalled applications\nhaving one or more backups, the restore dialog is displayed. Using the\n<a href=#par:main-page-sort>sort</a> option from the list options, the\nitems can be sorted in various ways. It is also possible to filter items\nusing the <a href=#par:main-page-filter>filter</a> option in the list\noptions. Filtering is also possible from the search bar with additional\nsupport for the regular expressions.<figure id=fig:main_page_entry_info_labeled data-latex-placement=ht><figure><object data=../images/main_page_entry_info_labeled.svg type=image/svg+xml></object></figure><figcaption>Figure 1: An application list item in the main\npage</figcaption></figure><section id=subsec:batch-operations class=level3 data-number=2.1.1><h3 data-number=2.1.1><span class=header-section-number>2.1.1</span>\n<a href=#toc:subsec:batch-operations>Batch Operations</a><a href=#subsec:batch-operations class=anchor aria-hidden=true></a></h3><p>Batch operations or operations on multiple applications are also\navailable within this page. Multiple selection mode can be activated by\nclicking on the app icon of an item or by long-clicking on any items in\nthe list. Once activated, a click on an item selects it instead of\nopening the App Details page. In this mode, the batch operations are\nlocated in the multiple selection menu at the bottom of the page. The\noperations include:<ul class=incremental><li><p>Adding the selected applications to a <a href=#sec:profiles-page>profile</a><li><p><a href=#sec:backup-restore>Backing up applications</a>, or\nrestoring and deleting the existing backups<li><p>Blocking the trackers from the applications<li><p>Clearing data or cache from the applications<li><p>Exporting the blocking rules configured inside App\nManager<li><p>Exporting the list of applications in Markdown, CSV, JSON or XML\nformat<li><p>Freezing/unfreezing/force-stopping/uninstalling the\napplications<li><p>Performing run-time optimization of the applications (Android 7\nonwards)<li><p>Preventing the background operations of the applications (Android\n7 onwards)<li><p>Saving the APK files to <code>AppManager/apks</code><li><p>Setting <a href=#sec:net-policy>net policies</a></ul><div class=\"amalert tip\"><p><strong><em>Accessibility.</em></strong><p>After the multiple selection mode has been activated, it is possible\nto navigate in or out of the multiple selection menu using the right or\nleft keys of the keyboard or remote.</div></section><section id=subsec:main-colour-codes class=level3 data-number=2.1.2><h3 data-number=2.1.2><span class=header-section-number>2.1.2</span>\n<a href=#toc:subsec:main-colour-codes>Colour Codes</a><a href=#subsec:main-colour-codes class=anchor aria-hidden=true></a></h3><ul class=incremental><li><p><span class=colorbox style=background-color:#ff0000b3><span style=color:#000>Red (day)</span></span> / <span class=colorbox style=background-color:#790d0d><span style=color:#fff>dark red (night)</span></span> – Uninstalled\napplication<li><p><span class=colorbox style=background-color:#ff8a80><span style=color:#000>Light red (day)</span></span> / <span class=colorbox style=background-color:#4f1c14bf><span style=color:#fff>very\ndark red (night)</span></span> – Frozen application<li><p><span class=colorbox style=background-color:#09868b><span style=color:#fff>Dark cyan</span></span> – Force-stopped\napplication<li><p><span class=colorbox style=background-color:#ff0><span style=color:#000>Yellow Star</span></span> – Debuggable\napplication<li><p><span style=color:#e05915>Orange <em>Date</em></span> – The\napplication can read system logs<li><p><span style=color:#e05915>Orange <em>UID</em></span> – The\nuser ID is being shared among multiple applications<li><p><span style=color:#e05915>Orange <em>SDK</em></span> – The\napplication possibly uses cleartext (i.e. HTTP) traffic<li><p><span style=color:#ff8017>Light orange <em>package\nname</em></span> – The application has one or more trackers<li><p><span style=color:red>Red <em>app label</em></span> – The\napplication does not allow clearing its data<li><p><span style=color:#09868b>Dark cyan <em>version</em></span>\n– Inactive application<li><p><span style=color:#f0f>Magenta type</span> – Persistent\napplication i.e. it remains running all the time<li><p><span style=color:red>Red <em>backup</em></span> – The\nuninstalled application with one or more backups present in App\nManager<li><p><span style=color:#e05915>Orange <em>backup</em></span> –\nOutdated backup, i.e. the base backup contains an older version of the\ninstalled application<li><p><span style=color:#09868b>Dark cyan <em>backup</em></span>\n– Up to date backup, i.e. the base backup contains the same or higher\nversion of the installed application.</ul></section><section id=subsec:main-page-application-types class=level3 data-number=2.1.3><h3 data-number=2.1.3><span class=header-section-number>2.1.3</span>\n<a href=#toc:subsec:main-page-application-types>Application\nTypes</a><a href=#subsec:main-page-application-types class=anchor aria-hidden=true></a></h3><p>An application can be either a <strong>User</strong> or a\n<strong>System</strong> application along with the following\nsuffixes:<ul class=incremental><li><p><code>X</code> – Supports multiple architectures<li><p><code>0</code> – No dex files present in the application<li><p><code>°</code> – Suspended application<li><p><code>#</code> – The application requested the system to allocate\na large heap i.e. large runtime memory<li><p><code>?</code> – The application requested the virtual machine to\nbe in the safe mode.</ul></section><section id=subsec:main-page-version-info class=level3 data-number=2.1.4><h3 data-number=2.1.4><span class=header-section-number>2.1.4</span>\n<a href=#toc:subsec:main-page-version-info>Version Info</a><a href=#subsec:main-page-version-info class=anchor aria-hidden=true></a></h3><p>Version name is followed by the prefixes below:<ul class=incremental><li><p><code>_</code> – No hardware acceleration (breaking the in-app\nanimations or transparencies)<li><p><code>~</code> – Test-only application<li><p><code>debug</code> – Debuggable application</ul></section><section id=subsec:main-page-options-menu class=level3 data-number=2.1.5><h3 data-number=2.1.5><span class=header-section-number>2.1.5</span>\n<a href=#toc:subsec:main-page-options-menu>Options Menu</a><a href=#subsec:main-page-options-menu class=anchor aria-hidden=true></a></h3><p>Options menu offers several options that can be used to sort and\nfilter the listed applications as well as to navigate to different pages\nwithin or outside App Manager.<section id=subsubsec:main-list-options class=level4 data-number=2.1.5.1><h4 data-number=2.1.5.1><span class=header-section-number>2.1.5.1</span> List Options<a href=#subsubsec:main-list-options class=anchor aria-hidden=true></a></h4><p><strong>List options</strong> contain the options to sort and filter\nthe list in the main page.<section id=sort class=level5 data-number=2.1.5.1.1><h5 data-number=2.1.5.1.1><span class=header-section-number>2.1.5.1.1</span> Sort<a href=#sort class=anchor aria-hidden=true></a></h5><div id=par:main-page-sort></div><p>The applications listed in the main page can be sorted in the\nfollowing ways:<ul class=incremental><li><p><strong>User apps first.</strong> The user applications are\nlisted on top<li><p><strong>App label.</strong> Sort the list in ascending order\nbased on their application labels (also known as <em>application\nnames</em>). This is the default sorting preference<li><p><strong>Package name.</strong> Sort the list in ascending order\nbased on their package names<li><p><strong>Last update.</strong> Sort the list in descending order\nbased on the date they were last updated<li><p><strong>Shared user ID.</strong> Sort the list in descending\norder based on their kernel user ID<li><p><strong>Target SDK.</strong> Sort the list in ascending order\nbased on their target SDK<li><p><strong>Signature.</strong> Sort the list in ascending order\nbased on their signing information<li><p><strong>Frozen first.</strong> The frozen applications are listed\non the top<li><p><strong>Blocked first.</strong> Sort the list in descending order\nbased on the number of blocked components each application has<li><p><strong>Backed up first.</strong> Display the applications with\nbackups on the top<li><p><strong>Trackers.</strong> Sort the list in descending order\nbased on the number of tracker components each application has<li><p><strong>Last actions.</strong> Sort the list in descending order\nbased on the latest time and date of any actions made to the\napplications within App Manager.<li><p><strong>Installation date.</strong> Sort the list by the date of\ninstallation in descending order.<li><p><strong>Total size.</strong> Sort the list by the total size of\nthe applications and their data in descending order. Requires\n<code>Usage Access</code> permission.<li><p><strong>Data usage.</strong> Sort the list by the total data\nusage in descending order. Requires <code>Usage Access</code>\npermission.<li><p><strong>Times opened.</strong> List frequently used applications\non top. Requires <code>Usage Access</code> permission.<li><p><strong>Screen time.</strong> List the applications with the\nhighest engagements on top. Requires <code>Usage Access</code>\npermission.<li><p><strong>Last used.</strong> List last used apps on top. Requires\n<code>Usage Access</code> permission.</ul><p>In addition, there is the <em>reverse</em> option that can be used to\nsort the list in the reverse order. Regardless of the sorting\npreferences, the applications are sorted alphabetically at first in\norder to prevent producing any random sorting results.</section><section id=filter class=level5 data-number=2.1.5.1.2><h5 data-number=2.1.5.1.2><span class=header-section-number>2.1.5.1.2</span> Filter<a href=#filter class=anchor aria-hidden=true></a></h5><div id=par:main-page-filter></div><p>The applications listed in the main page can be filtered in the\nfollowing ways:<ul class=incremental><li><p><strong>User apps.</strong> List only the user\napplications<li><p><strong>System apps.</strong> List only the system\napplications<li><p><strong>Frozen apps.</strong> List only the frozen\napplications<li><p><strong>Stopped apps.</strong> List only the applications that\nwere forced-stopped<li><p><strong>Installed apps.</strong> List only the installed\napplications<li><p><strong>Uninstalled apps.</strong> List only the uninstalled\napplications<li><p><strong>With rules.</strong> List the applications with one or\nmore blocking rules<li><p><strong>With activities.</strong> List the applications with one\nor more activities<li><p><strong>With backups.</strong> List the applications with one or\nmore backups<li><p><strong>Without backups.</strong> List the applications with no\nbackups present.<li><p><strong>Running apps.</strong> List the applications that are\ncurrently running<li><p><strong>With splits.</strong> List the applications with one or\nmore split APK files<li><p><strong>With KeyStore.</strong> List only the applications with\nAndroid KeyStore.<li><p><strong>With SAF.</strong> List only the applications with SAF\naccess.<li><p><strong>With SSAID.</strong> List only the applications with a\nvalid SSAID.</ul><p>Unlike sorting, it is possible to apply more than one filtering\noptions at the same time. For example, the frozen user applications can\nbe listed by selecting both <em>User apps</em> and <em>Frozen apps</em>.\nThis can be particularly useful for <a href=#subsec:batch-operations>batch operations</a> where filtering the\nuser applications may be necessary to carry out certain operations\nsafely.<div class=\"amalert warning\"><p><strong><em>Inconsistencies.</em></strong><p>App Manager extensively caches everything in this page. Therefore,\ncertain states (e.g., freeze and stopped states) may not always be\nup-to-date.</div></section><section id=profile-name class=level5 data-number=2.1.5.1.3><h5 data-number=2.1.5.1.3><span class=header-section-number>2.1.5.1.3</span> Profile Name<a href=#profile-name class=anchor aria-hidden=true></a></h5><p>It is also possible to list the applications that are only present in\na <a href=#sec:profiles-page>profile</a>. This can be useful for\ncarrying out certain operations on a profile (e.g., uninstalling all the\napplications in a profile) that cannot be done via the <a href=#sec:profiles-page>Profiles page</a>.</section></section><section id=user-manual class=level4 data-number=2.1.5.2><h4 data-number=2.1.5.2><span class=header-section-number>2.1.5.2</span> User Manual<a href=#user-manual class=anchor aria-hidden=true></a></h4><p>Clicking on the <strong>User manual</strong> opens the offline\nversion of the App Manager user manual. It may also open the online\nversion if the corresponding feature split i.e. <code>feat_docs</code>\nis not installed, or if an WebView is not present in the system to load\nthe manual.</section><section id=subsubsec:main:1-click-ops class=level4 data-number=2.1.5.3><h4 data-number=2.1.5.3><span class=header-section-number>2.1.5.3</span> 1-Click Ops<a href=#subsubsec:main:1-click-ops class=anchor aria-hidden=true></a></h4><p><strong>1-Click Ops</strong> stands for the single-click operations.\nIt opens the <a href=#sec:1-click-ops-page>corresponding page</a> in a\nnew activity.</section><section id=app-usage class=level4 data-number=2.1.5.4><h4 data-number=2.1.5.4><span class=header-section-number>2.1.5.4</span> App Usage<a href=#app-usage class=anchor aria-hidden=true></a></h4><p>Application usage statistics, such as <em>screen time</em>, <em>data\nusage</em> (both mobile and Wi-Fi), <em>number of times an app was\nopened</em>, can be accessed by clicking on the <strong>App\nUsage</strong> option in the menu. However, it requires the <em>Usage\nAccess</em> permission. This menu item will not be listed if the usage\naccess feature is disabled in <a href=#subsubsec:enable/disable-features>settings</a>.</section><section id=subsubsec:main:running-apps class=level4 data-number=2.1.5.5><h4 data-number=2.1.5.5><span class=header-section-number>2.1.5.5</span> Running Apps<a href=#subsubsec:main:running-apps class=anchor aria-hidden=true></a></h4><p>This menu item opens a new page where a list of running applications\nor processes are displayed. It also displays the current memory and\ncache (if available) usage. If root or ADB is not available to App\nManager, it only displays itself in the recent versions of Android. The\nrunning applications or processes can also be force-stopped or killed\nwithin the resultant page. Logs for each process ID (PID) can also be\nviewed in the <a href=#subsubsec:main:labs>log viewer</a>. In\naddition, it is also possible to carry out batch operations either by\nclicking on the icon or by long-clicking on an item. Normal click on any\nitems opens a dialog where a more detailed information is displayed.</section><section id=profiles class=level4 data-number=2.1.5.6><h4 data-number=2.1.5.6><span class=header-section-number>2.1.5.6</span> Profiles<a href=#profiles class=anchor aria-hidden=true></a></h4><p>This menu item opens the <a href=#sec:profiles-page>profiles\npage</a>. Profiles are a way to configure regularly used tasks. They can\nalso be invoked via shortcuts.</section><section id=apk-updater class=level4 data-number=2.1.5.7><h4 data-number=2.1.5.7><span class=header-section-number>2.1.5.7</span> APK Updater<a href=#apk-updater class=anchor aria-hidden=true></a></h4><p>If the app <a href=https://github.com/rumboalla/apkupdater>APK\nUpdater</a> is installed in the system, it can be opened directly via\nthis menu item. The option remains hidden if the app is not present in\nthe system.</section><section id=termux class=level4 data-number=2.1.5.8><h4 data-number=2.1.5.8><span class=header-section-number>2.1.5.8</span> Termux<a href=#termux class=anchor aria-hidden=true></a></h4><p>If the app <a href=https://github.com/termux/termux-app>Termux</a>\nis installed in the system, the running session (or a new session) can\nbe opened directly via this menu item. The option remains hidden if the\napp is not present in the system.</section><section id=debloater class=level4 data-number=2.1.5.9><h4 data-number=2.1.5.9><span class=header-section-number>2.1.5.9</span> Debloater<a href=#debloater class=anchor aria-hidden=true></a></h4><p>This menu item opens the debloater page that lists all the bloatware\navailable in the device and in App Manager. It also suggests alternative\napplications based on the criteria set by the <a href=https://github.com/MuntashirAkon/android-debloat-list>Android\nDebloat List</a> project.</section><section id=subsubsec:main:labs class=level4 data-number=2.1.5.10><h4 data-number=2.1.5.10><span class=header-section-number>2.1.5.10</span> Labs<a href=#subsubsec:main:labs class=anchor aria-hidden=true></a></h4><p>This menu item opens the labs page that lists all the additional\nfeatures. They include Log Viewer, System Config, Terminal, File Manager\n(as Files), UI Tracker, Interceptor, and Code Editor pages.</section><section id=settings class=level4 data-number=2.1.5.11><h4 data-number=2.1.5.11><span class=header-section-number>2.1.5.11</span> Settings<a href=#settings class=anchor aria-hidden=true></a></h4><p>This menu item opens the in-app <a href=#sec:settings-page>Settings\npage</a>.</section></section></section><section id=sec:app-details-page class=level2 data-number=2.2><h2 data-number=2.2><span class=header-section-number>2.2</span> <a href=#toc:sec:app-details-page>App Details Page</a><a href=#sec:app-details-page class=anchor aria-hidden=true></a></h2><p><strong>App Details</strong> page consists of 11 (eleven) tabs. It\ndescribes almost every bit of information an application usually has,\nincluding all attributes from its manifest, <a href=#ch:app-ops>application operations</a> (app ops), signing\ninformation, libraries, and so on.<section id=subsec:app-details-colour-codes class=level3 data-number=2.2.1><h3 data-number=2.2.1><span class=header-section-number>2.2.1</span>\n<a href=#toc:subsec:app-details-colour-codes>Colour Codes</a><a href=#subsec:app-details-colour-codes class=anchor aria-hidden=true></a></h3><p>List of colours used in this page, and their meaning:<ul class=incremental><li><p><span class=colorbox style=background-color:#ff0000b3><span style=color:#000>Red (day)</span></span> / <span class=colorbox style=background-color:#790d0d><span style=color:#fff>dark red (night)</span></span> – Denotes any app\nops or permissions having the dangerous flag, or any components blocked\nwithin App Manager, or any unsupported but required features.<li><p><span class=colorbox style=background-color:#ff8a80><span style=color:#000>Light red (day)</span></span> / <span class=colorbox style=background-color:#4f1c14bf><span style=color:#fff>very\ndark red (night)</span></span> – Denotes the components disabled outside\nof App Manager, or any unsupported but optional features.<div class=\"amalert tip\"><p><strong><em>Note.</em></strong><p>A component marked as disabled does not always mean that it is\ndisabled by the user: It could also be disabled by the system or marked\nas disabled in its manifest. The components of a disabled application\nare also considered disabled by the system (and App Manager).</div><li><p><span class=colorbox style=background-color:#ff8017><span style=color:#000>Vivid orange (day)</span></span> / <span class=colorbox style=background-color:#ff801780><span style=color:#fff>very\ndark orange (night)</span></span> – Denotes the tracker\ncomponents<li><p><span class=colorbox style=background-color:#ea80fc><span style=color:#000>Soft magenta (day)</span></span> / <span class=colorbox style=background-color:#431c5d><span style=color:#fff>very dark violet (night)</span></span> – Denotes\nthe running services.<li><p><span class=colorbox style=background-color:#1b8654><span style=color:#fff>Green</span></span> – Used in the tracker-indicator\ntag to denote that all the trackers in the application are\nblocked.</ul></section><section id=subsec:app-info-tab class=level3 data-number=2.2.2><h3 data-number=2.2.2><span class=header-section-number>2.2.2</span>\n<a href=#toc:subsec:app-info-tab>App Info Tab</a><a href=#subsec:app-info-tab class=anchor aria-hidden=true></a></h3><p><strong>App Info</strong> tab contains general information about an\napplication. It also lists many actions that can be performed within\nthis tab.<section id=subsubsec:app-info-general-information class=level4 data-number=2.2.2.1><h4 data-number=2.2.2.1><span class=header-section-number>2.2.2.1</span> General Information<a href=#subsubsec:app-info-general-information class=anchor aria-hidden=true></a></h4><p>The list below is in the same order as listed in the App Info\ntab.<ul class=incremental><li><p><strong>Application Icon.</strong> The application icon. If the\napplication does not have an icon, the system default icon will be\ndisplayed. It is also possible to verify the APK signature via SHA or\nMD5 sums stored in the clipboard by simply clicking on it.<li><p><strong>Application Label.</strong> The application label or the\nname of the application.<li><p><strong>Package Name.</strong> The name of the application\npackage. Clicking on the name stores it in the clipboard.<li><p><strong>Version.</strong> The application version is divided into\ntwo parts. The first part is called <em>version name</em>. The format of\nthis part varies but often consists of multiple integers separated by\ndots. The second part is called <em>version code</em>. It is enclosed by\nthe first brackets. The version code is an integer used to differentiate\nbetween application versions (since a version name can be unreadable to\na machine). In general, a new version of an application has higher\nversion code than the old ones. For example, if <code>123</code> and\n<code>125</code> are two version codes of an application, we can say\nthat the latter is more updated than the former because the version code\nof the latter is higher. An application that serves different APK files\nfor the same version on different platforms (mobile, tabs, desktops,\netc.) or architectures (32/64 bit, ARM or Intel), the version numbers\ncan be misleading as they often add prefixes for each platform.<li><p><strong>Tags.</strong> (Also known as tag clouds) Tags include\nthe most basic, concise and useful information of an application. See\n§<a href=#subsubsec:tags data-reference-type=ref data-reference=subsubsec:tags>2.2.2.2</a> for a complete list of tags\nshown here.<li><p><strong>Horizontal Action Panel.</strong> An action panel\nconsisting of various actions that can be carried out for the\napplication. See §<a href=#subsubsec:horizontal-action-panel data-reference-type=ref data-reference=subsubsec:horizontal-action-panel>2.2.2.3</a> for a\ncomplete list of actions available here. Additional actions are\navailable in the <a href=#subsubsec:app-info-options-menu>options\nmenu</a>.<li><p><strong>Paths & Directories.</strong> Contains various\ninformation regarding application paths including <em>app directory</em>\n(where the APK files reside), <em>data directories</em> (internal,\ndevice protected and externals), and <em>JNI library directory</em> (if\npresent). JNI libraries are used to invoke native codes usually written\nin C/C++. Use of native library can make the application run faster or\nhelp an application use third-party libraries written using languages\nother than Java like in most games. The directories can be opened via\nfile managers provided they support it and have the necessary\npermissions, by clicking on the launch button on the right-hand side of\na directory item.<li><p><strong>Data Usage.</strong> Amount of data used by the\napplication as reported by the operating system. Depending on Android\nversion, this may require a wide range of permissions including\n<em>Usage Access</em> and <em>Telephony</em> permissions.<li><p><strong>Storage & Cache.</strong> Displays information\nregarding the size of the application (APK files, optimised files), data\nand cache. In older devices, size of external data, cache, media and OBB\nfolders are also displayed. This part remains hidden if <em>Usage\nAccess</em> permission is not granted in the newer devices.<li><p><strong>More Info.</strong> Displays other information such\nas–<ul class=incremental><li><p><strong>SDK.</strong> Displays information related to the Android\nSDK: <em>Max</em> denotes the target SDK and <em>Min</em> denotes the\nminimum SDK (the latter is not available in Android Lollipop). If the\ntarget SDK value is less than the platform SDK (i.e., the highest SDK\nthe current operating system supports), the application will run in the\ncompatibility mode. This means the application may have access to\ncertain features that are unavailable or restricted in a newer version\nof Android, which can be a security and/or privacy issue. SDK is also\nknown as <strong>API Level</strong>.<br><div class=seealso-inline><p><em>See also: <span><a href=https://en.wikipedia.org/wiki/Android_version_history#Overview>Android\nVersion History</a></span></em></div><li><p><strong>Flags.</strong> The application flags used at the time of\nbuilding the application. For a complete list of flags and what they do,\nread the <a href=https://developer.android.com/reference/android/content/pm/ApplicationInfo#flags>official\ndocumentation</a>.<li><p><strong>Date Installed.</strong> The date when the application\nwas first installed.<li><p><strong>Date Updated.</strong> The date when the application was\nlast updated. This is the same as <em>Date Installed</em> if the\napplication hasn’t been updated.<li><p><strong>Process Name.</strong> The name of the process if it is\ndifferent from the package name. Process name is set when an application\nis being started by the system, and is usually the same as the package\nname.<li><p><strong>Installer App.</strong> The application that installed\nthis application. The installer application may not always be the same\nas the application that installed this application, because Android\nallows setting an arbitrary value for this field. In Android 11 onwards,\nthe actual installer application is also stored by the system which can\nbe accessed by clicking the “Info” button on the right-hand side of the\nitem. The field will not be visible if the installer application is not\nreported by the system (e.g., due to the installer application being\nuninstalled or hidden). Installer application may be granted additional\nprivileges by the system so that it can control certain behaviour of the\napplication it installs.<li><p><strong>User ID.</strong> The unique user ID set by the system to\nthe application. For shared applications, the same user ID is assigned\nto multiple applications having the same <em>Shared User\nID</em>.<li><p><strong>Shared User ID.</strong> Applicable for applications that\nare shared together. The shared application must have the same <a href=#subsec:signatures-tab>signatures</a>.<li><p><strong>Primary ABI.</strong> Architecture supported by this\nplatform for this application.<li><p><strong>Zygote preload name.</strong> Responsible for preloading\napplication code and data shared across all the isolated services that\nuses app zygote.<li><p><strong>Hidden API enforcement policy.</strong> Since Android 9,\nmany methods and classes in Android framework have been made\ninaccessible to the third-party applications through hidden API\nenforcement policy. It has the following options:<ul class=incremental><li><p><em>Default.</em> Based on the type of application. For system\napplications, it should be disabled, and for others, it should be\nenforced.<li><p><em>None/disabled.</em> The application has full access to the\nhidden API as it used to be before Android 9.<li><p><em>Warn.</em> Same as above, except that warnings will be logged\neach time the application accesses the hidden API. This is mostly\nunused.<li><p><em>Enforce.</em> The application cannot access hidden API,\neither dark-grey list or blacklist, or both of them. This is the default\noption for the third-party applications in Android 9 onwards unless the\napplication is whitelisted by the OEM or the vendor.<div class=\"amalert warning\"><p><strong><em>Warning.</em></strong><p>Hidden API enforcement policy is not properly implemented in Android\nand can be bypassed by the application. As a result, this value should\nnot be trusted.</div></ul><li><p><strong>SELinux.</strong> Mandatory access control (MAC) policy\nset by the operating system via SELinux.<li><p><strong>Main Activity.</strong> The main entry point to the\napplication. This is only visible if the application has <a href=#subsubsec:activities>activities</a> and any of those are\nopenable from the Launcher. There’s also a launch button on the\nright-hand side which can be used to launch this activity.</ul></ul></section><section id=subsubsec:tags class=level4 data-number=2.2.2.2><h4 data-number=2.2.2.2><span class=header-section-number>2.2.2.2</span> Tags<a href=#subsubsec:tags class=anchor aria-hidden=true></a></h4><ul class=incremental><li><p><strong>Tracker info.</strong> Number of tracker components in\nthe application (e.g., <em>5 trackers</em>) The colour of the tag\nappears orange if the trackers are unblocked and dark cyan if they are\nblocked in App Manager. Clicking on the tag opens a dialog containing\nthe list of tracker components which can also be blocked or unblocked\nprovided App Manager has sufficient privileges.<li><p><strong>Application type.</strong> User application or system\napplication. For a system application, it displays whether the\napplication is an updated version of the system application or the\napplication is installed systemless-ly via Magisk.<li><p><strong>Split APK info.</strong> Number of splits in the APK\nexcluding the base APK (e.g., <em>5 splits</em>). Clicking on the tag\nopens a dialog containing a few additional information, such as name,\ntype, and size.<li><p><strong>Debuggable.</strong> The application can be debugged over\nADB. Debuggable applications can enjoy certain functions unavailable to\na regular application. The data of the application might be accessible\nvia ADB (e.g. using <code>run-as</code> command) without any additional\npermissions.<li><p><strong>Test only.</strong> The application is a test-only\napplication. Test-only applications can enjoy certain functions\nunavailable to a regular application. The data of the application might\nbe accessible via ADB (e.g. using <code>run-as</code> command) without\nany additional permissions.<li><p><strong>No code.</strong> The application does not have any code\nassociated with it i.e., DEX files aren’t present. In some system\napplications, the actual code might be located in another\nplace.<li><p><strong>Large heap.</strong> The application has requested large\nheap size i.e., more space in memory (RAM) is requested for dynamic\nallocation. It is still up to the operating system to decide whether to\nallocate large space for the application. App Manager, for example,\nrequests large heap size because it needs to load an entire APK into\nmemory while scanning an APK.<li><p><strong>Open links.</strong> The application may open certain\nlinks from any applications. If the application can open any links by\ndefault, the color of the tag would be red, dark cyan if otherwise.\nClicking on the tag opens a dialog with the supported hosts or domains\nlisted. In Android 12 onwards, it displays an option to enable or\ndisable opening links by default provided App Manager has sufficient\npermissions. Otherwise, it displays an option to open the system\nsettings page for the application.<li><p><strong>Running.</strong> One or more services of the application\nis currently running in the background. Clicking on the tag opens a\ndialog containing the list of running services. Clicking on any services\nopens the log viewer with default filter set to the UID associated with\nthe service (which can be different from the UID of the application if\nit is running in a separate or isolated process) provided the log viewer\nfeature is enabled. There’s also an option to force-stop the\napplication.<li><p><strong>Stopped.</strong> The application is force stopped. This\nmay not prevent it from running automatically later.<li><p><strong>Disabled.</strong> Denotes that the application is\ndisabled (hidden from the launcher).<li><p><strong>Suspended.</strong> Denotes that the application is\nsuspended (grayed out in the launcher).<li><p><strong>Hidden.</strong> Denotes that the application is hidden\n(hidden from the launcher).<li><p><strong>MagiskHide.</strong> MagiskHide is enabled for the\napplication. Clicking on the tag opens a dialog containing the list of\nprocess names within the application that can be added to or removed\nfrom the MagiskHide list.<li><p><strong>MagiskDenyList.</strong> The application is present in\nMagisk DenyList. Clicking on the tag opens a dialog containing the list\nof process names within the application that can be added to or removed\nfrom Magisk DenyList.<li><p><strong>WX.</strong> The application violates the “W^X policy”\nand is capable of writing and executing in the same directory or in the\nsame portion of memory. This allows the execution of arbitrary\nexecutables either by the modification of executables embedded within\nthe application or by downloading them from the Internet.<br><div class=seealso-inline><p><em>See also: <span><a href=https://en.wikipedia.org/wiki/W%5EX>W^X\nin Wikipedia</a></span></em></div><li><p><strong>Bloatware.</strong> The application may be a known\nbloatware. Clicking on the tag opens a dialog containing detailed\ninformation in addition to suggestions (if available).<li><p><strong>KeyStore.</strong> The application has items in the\nAndroid KeyStore. Clicking on the tag opens a dialog containing all the\nKeyStore files that belong to the application.<li><p><strong>Backup.</strong> The application was backed up using App\nManager at least once. Clicking on the tag opens a dialog containing all\nthe available backups along with metadata.<li><p><strong>No battery optimisation.</strong> Battery optimisation is\ndisabled for the application. It is possible to re-enable battery\noptimisation by clicking on the tag.<li><p><strong>Sensors disabled.</strong> Sensors are disabled for the\napplication. Sensors are disabled for most applications by\ndefault.<li><p><a href=#sec:net-policy><strong>Net policy.</strong></a>\nNetwork policy (e.g., background data usage) is configured for the\napplication. Clicking on the tag displays a dialog containing the\nsupported policies for the platform along with the options to configure\nthem.<li><p><a href=#sec:terminologies><strong>SSAID.</strong></a> Clicking\non the tag opens a dialog containing the current SSAID assigned to the\napplication. It is also possible to reset/regenerate the SSAID if\nneeded.<li><p><strong>SAF.</strong> Denotes that the application has been\ngranted to access one or more storage locations or files i.e. URIs via\nStorage Access Framework (SAF). Clicking on the tag opens a dialog\ncontaining the list of granted URIs.<li><p><strong>Play App Signing.</strong> Indicates that the application\nmight be signed by Google.<li><p><strong>Xposed.</strong> Indicates that the application may be an\nXposed module. Clicking on the tag displays a dialog with additional\ninformation.<li><p><strong>Static Shared Library.</strong> Denotes that the\napplication serves as a static shared library for one or more\napplications. Clicking on the tag opens a dialog containing a list of\ninstalled versions of the library along with an option to uninstall\nthem.<div class=\"amalert tip\"><p><strong><em>Notice.</em></strong><p>The trichrome library (supplied by Google Chrome, Vanadium or similar\nprojects) is currently the only known static shared library on\nAndroid.</div></ul></section><section id=subsubsec:horizontal-action-panel class=level4 data-number=2.2.2.3><h4 data-number=2.2.2.3><span class=header-section-number>2.2.2.3</span> Horizontal Action Panel<a href=#subsubsec:horizontal-action-panel class=anchor aria-hidden=true></a></h4><p>Horizontal Action Panel, as described in the previous section,\nconsists of various application-related actions, such as–<ul class=incremental><li><p><strong>Launch.</strong> Launch the application provided it has a\nlauncher <a href=#subsubsec:activities>activity</a>.<li><p><strong>Freeze.</strong> Freeze the application. This button is\nnot displayed if it is already frozen or the user does not have enough\nprivileges. After the application is frozen, it may be hidden from the\napp drawer depending on how it was configured. Shortcuts configured by\nthe application may also be removed. The application may only be\nunfrozen via App Manager, <code>pm</code> command or any other tools\nthat offer such a feature. Long clicking on the button opens a dialog\nwhere a shortcut can be configured to quickly freeze or unfreeze the\napplication.<li><p><strong>Uninstall.</strong> Uninstall the application with a\nprompt. In the dialog prompt, it is possible to uninstall updates of a\nsystem application, or if App Manager has enough privileges or the\noperating system supports it, it is possible to uninstall the\napplication without clearing its data and signature. For the latter\ncase, the installed application must match the signature with the\npreviously installed application if it is installed again.<div class=\"amalert tip\"><p><strong><em>Tips.</em></strong><p>A better way to reinstall an application with a different signature\nwould be to back up its data using App Manager and restore it again\nafter installing the application instead of opting to preserving data\nand signature of the application during uninstallation as this option\nmay cause undefined behaviour in the future.</div><li><p><strong>Unfreeze.</strong> Unfreeze the application. This button\nis not displayed if it is already enabled or the user does not have\nenough privileges. Similar to the <em>Freeze</em> button, long clicking\non the button opens a dialog where a shortcut can be configured to\nquickly freeze or unfreeze the application.<li><p><strong>Force Stop.</strong> Force-stop the application.<li><p><strong>Clear Data.</strong> Clear data from the application.\nThis includes any information stored in the internal and, recently, the\nexternal directories, including accounts (if set by the application),\ncache, etc. Clearing data from App Manager, for example, removes all the\nrules (the blocking is not removed though) saved within the application\n(Which is why you should always take backups of your rules). This button\nis not displayed if the user does not have enough privileges.<li><p><strong>Clear Cache.</strong> Clear the application cache. If the\napplication is running during the operation, the cache may not be\ncleared as expected.<li><p><strong>Install.</strong> Install the application, only displayed\nif the application hasn’t already been installed.<li><p><strong>What’s New.</strong> Displayed for an external\napplication if an older version of it is already installed. Clicking on\nthis button opens a dialog containing the differences between this and\nthe installed version in a version control manner. Changes include\n<em>version</em>, <em>trackers</em>, <em>permissions</em>,\n<em>components</em>, <em>signatures</em> (only checksum changes),\n<em>features</em>, <em>shared libraries</em> and <em>SDK</em>.<li><p><strong>Update.</strong> Displayed if the application has a\nhigher version code than the installed application.<li><p><strong>Reinstall.</strong> Displayed if the application has the\nsame version code as the installed application.<li><p><strong>Downgrade.</strong> Displayed if the application has a\nlower version code than the installed application.<li><p><strong>Manifest.</strong> Opens the application’s manifest file\nin a separate page. If the application has more than one split, it will\ndisplay the list of split APK files, and clicking on an item will open\nthe corresponding manifest file instead.<li><p><strong>Scanner.</strong> Scan the application in order to list\npotential trackers and libraries. It also scans the file using\nVirusTotal and fetch results from Pithus if configured.<br><div class=seealso-inline><p><em>See also: <span><a href=#sec:scanner-page>Scanner\npage</a></span></em></div><li><p><strong>Shared Prefs.</strong> Displays a list of shared\npreferences used by the application. Clicking on a preference item in\nthe list opens the <a href=#sec:shared-preferences-editor-page>Shared\nPreferences Editor page</a>. This option is only visible if the user has\nthe required privileges.<li><p><strong>Databases.</strong> Displays a list of databases used by\nthe application. Clicking on an item opens a list of activities that can\nopen the database. This option is only visible if the user has the\nrequired privileges.<li><p><strong>F-Droid.</strong> Open the application in the selected\n<em>F-Droid</em> client.<li><p><strong>Store.</strong> Open the application in <em>Aurora\nStore</em>. The option is only visible if <em>Aurora Store</em> is\ninstalled.</ul></section><section id=subsubsec:app-info-options-menu class=level4 data-number=2.2.2.4><h4 data-number=2.2.2.4><span class=header-section-number>2.2.2.4</span> Options Menu<a href=#subsubsec:app-info-options-menu class=anchor aria-hidden=true></a></h4><p>Options-menu is located in the top-right corner of the page. A\ncomplete description of the options present there are given below:<ul class=incremental><li><p><strong>Share.</strong> Share button can be used to share the APK\nor (if the application is has multiple splits, OBB files or any\ndependencies) <em>APKS</em> file extracted from the\napplication.<li><p><strong>Refresh.</strong> Refresh the App Info tab.<li><p><strong>View in Settings.</strong> Open the application in\nAndroid Settings.<li><p><strong>Backup/restore.</strong> Open the backup/restore\ndialog.<li><p><strong>Export blocking rules.</strong> Export rules configured\nfor the application within App Manager.<li><p><strong>Open in Termux.</strong> Open the application in Termux.\nThis actually runs <code>su - user_id</code> where <code>user_id</code>\ndenotes the application’s kernel user ID (described in §<a href=#subsubsec:app-info-general-information data-reference-type=ref data-reference=subsubsec:app-info-general-information>2.2.2.1</a>).\nThis option is only visible to the root users. See §<a href=#subsubsec:config-termux data-reference-type=ref data-reference=subsubsec:config-termux>2.2.2.5</a> to learn how to\nconfigure Termux to run commands from third-party applications.<li><p><strong>Run in Termux.</strong> Open the application via\n<code>run-as package_name</code> in Termux. This is only applicable to\nthe debuggable applications and works for both root and ADB users. See\n§<a href=#subsubsec:config-termux data-reference-type=ref data-reference=subsubsec:config-termux>2.2.2.5</a> to learn how to\nconfigure Termux to run commands from third-party applications.<li><p><strong>MagiskHide.</strong> Open a dialog containing the list of\nprocess names within the application that can be added or removed from\nthe MagiskHide list.<li><p><strong>Magisk DenyList.</strong> Open a dialog containing the\nlist of process namees within the application that can be added or\nremoved from Magisk DenyList.<li><p><strong>Battery optimisation.</strong> Enable/disable battery\noptimisation for this application.<li><p><strong>Sensors.</strong> Enable/disable sensors for this\napplication.<li><p><a href=#sec:net-policy><strong>Net policy.</strong></a>\nConfigure network policy (e.g., background data usage) for the\napplication.<li><p><strong>Extract Icon.</strong> Extract and save the application’s\nicon in the shared storage.<li><p><strong>Optimize.</strong> Perform optimisation for this\napplication. This option is for advanced users only.<li><p><strong>Add to profile.</strong> Add the application to one of\nthe configured <a href=#sec:profile-page>profiles</a>.<li><p><strong>Install for….</strong> Install the application for\nanother user and/or in the work profile if configured.</ul></section><section id=subsubsec:config-termux class=level4 data-number=2.2.2.5><h4 data-number=2.2.2.5><span class=header-section-number>2.2.2.5</span> Configuring Termux<a href=#subsubsec:config-termux class=anchor aria-hidden=true></a></h4><p>By default, Termux does not allow running commands from a third-party\napplication. To use this option, Termux v0.96 or later is required and\n<code>allow-external-apps=true</code> must be added in\n<code>~/.termux/termux.properties</code>.<div class=\"amalert tip\"><p><strong><em>Info.</em></strong><p>Enabling this option does not weaken Termux’ security. The\nthird-party applications still need to ask the user to allow running\narbitrary commands in Termux.</div></section></section><section id=subsec:component-tabs class=level3 data-number=2.2.3><h3 data-number=2.2.3><span class=header-section-number>2.2.3</span>\n<a href=#toc:subsec:component-tabs>Component Tabs</a><a href=#subsec:component-tabs class=anchor aria-hidden=true></a></h3><p><strong>Activities</strong>, <strong>Services</strong>,\n<strong>Receivers</strong> (i.e., broadcast receivers) and\n<strong>Providers</strong> (e.g., content providers) are collectively\nknown as the application components, because they offer similar features\nand share similar properties. For example, they all have a\n<em>name</em>, a <em>label</em>, an <em>icon</em>, can be enabled or\ndisabled, and can be executed via <em>Intent</em>. Application\ncomponents are the building blocks of an application and must be\ndeclared in the application manifest (with a few exceptions).\nApplication manifest is a file where application specific metadata are\nstored. The Android operating system learns what to do with the\napplication by reading the metadata.<p>Colours used in these tabs are explained in §<a href=#subsec:app-details-colour-codes data-reference-type=ref data-reference=subsec:app-details-colour-codes>2.2.1</a>. It is also\npossible to sort the list of components to display blocked or tracker\ncomponents on top of the list via the <strong>Sort</strong> option\nlocated in the three-dots menu.<section id=subsubsec:activities class=level4 data-number=2.2.3.1><h4 data-number=2.2.3.1><span class=header-section-number>2.2.3.1</span> Activities<a href=#subsubsec:activities class=anchor aria-hidden=true></a></h4><p><strong>Activities</strong> are the windows or pages that can be\nuniquely identified by the Android operating system (e.g., <em>Main\npage</em> and <em>App Details page</em> are two activities). Each\nactivity can have multiple UI components known as <em>widgets</em> or\n<em>fragments</em>, and each component can be nested or placed on top of\neach other. The developer can also choose to open external files, links,\netc. within an activity using a method called <em>intent filters</em>.\nFor example, when you open a file in your file manager, either your file\nmanager or the operating system scans the intent filters via\nPackageManager, find the activities capable of opening the file, and\nlist those activities so that you can choose your preferred\nactivity.<p>Activities that are <em>exportable</em> can be opened by any\nthird-party applications. However, Some activities may require\npermissions, and only an application having those permissions can open\nthem. In the <em>Activities</em> tab, certain activities can be launched\nvia the <strong>Launch</strong> button. If it is necessary to supply\nadditional information, such as Intent extras, data or action, long\nclicking on the <strong>Launch</strong> button opens the <a href=#sec:interceptor-page>Activity Interceptor</a> page which\nprovides such features.<div class=\"amalert tip\"><p><strong><em>Tip.</em></strong><p>No-root users can grant\n<code>android.permission.WRITE_SECURE_SETTINGS</code> via ADB to launch\n<em>non-exportable</em> activities.</div><div class=\"amalert tip\"><p><strong><em>Notice.</em></strong><p>If launching an activity throws an error, it may have certain\ndependencies which are not met (e.g., <em>App Details</em> page in App\nManager cannot be launched using the launch button, because it requires\na package name). Since the dependencies cannot be inferred\nprogrammatically, the activity may not be opened from App Manager by\ndefault.</div><p>It is also possible to create shortcuts of an activity-launch using\nthe <strong>Create shortcut</strong> button. If you need to supply\nadditional information, you can create a shortcut from the Activity\nInterceptor page instead.<div class=\"amalert danger\"><p><strong><em>Caution.</em></strong><p>If you uninstall App Manager, all shortcuts created by App Manager\nwill be lost.</div></section><section id=subsubsec:details:servcies class=level4 data-number=2.2.3.2><h4 data-number=2.2.3.2><span class=header-section-number>2.2.3.2</span> Services<a href=#subsubsec:details:servcies class=anchor aria-hidden=true></a></h4><p>Unlike <a href=#subsubsec:activities>activities</a> that users can\nsee, <strong>Services</strong> handle background tasks. For example, if\nyou’re downloading a video from the internet using your phone’s Internet\nbrowser, the Internet browser is using a <em>foreground service</em> to\ndownload the content.<p>When an activity is closed or removed from the <em>Recents</em> page,\nit may be destroyed immediately depending on the amount free memory the\nphone has, battery statistics, or how the activity is configured. But\nservices can be run indefinitely if desired. If more services run in the\nbackground, the phone may become slower due to the shortage of memory\nand/or processing power, and the phone’s battery will be drained more\nquickly. Newer versions of Android come with a battery optimisation\nfeature enabled by default for all applications. With this feature\nenabled, the system can randomly terminate any service depending on the\namount of resources the system has or the service requires. However,\nforeground services (i.e., services that run with a fixed notification,\nsuch as music player or downloader) are not typically terminated unless\nthe system is very low on resources (memory, battery, etc.). Certain\nstock ROMs can offer more aggressive optimisation. MIUI, for example,\nhas a very aggressive optimisation feature known as the <em>MIUI\noptimisation</em>.<p>Both activities and services are run in the same <a href=https://stackoverflow.com/questions/7597742>looper</a> called the\nmain looper, which means the services do not really run in the\nbackground. It is the task of the developer to ensure this. How do the\napplication communicate with the services? It uses <a href=#subsubsec:app-details-receivers>broadcast receiver</a> or\nBinder.</section><section id=subsubsec:app-details-receivers class=level4 data-number=2.2.3.3><h4 data-number=2.2.3.3><span class=header-section-number>2.2.3.3</span> Receivers<a href=#subsubsec:app-details-receivers class=anchor aria-hidden=true></a></h4><p><strong>Receivers</strong> (also called <em>broadcast receivers</em>)\ncan be used to trigger execution of certain tasks when certain events\noccur. These components are called broadcast receivers, because they are\nexecuted as soon as a broadcast message is received. These broadcast\nmessages are sent using a method called <em>Intent</em>. Intent is a\nspecial feature in Android that can be used to open applications (i.e.,\nactivities), run services and send broadcast messages. Therefore, like\n<a href=#subsubsec:activities>activities</a>, broadcast receivers use\n<em>intent filters</em> to receive the desired broadcast messages.\nBroadcast messages can be sent by the system or the application itself.\nWhen a broadcast message is sent, the corresponding receivers are\nactivated by the system so that they can execute tasks. For example, if\nyour phone is low on resources, it may freeze or experience lags for a\nmoment after you enable mobile data or connect it to the Wi-Fi. This is\nbecause broadcast receivers that can receive\n<code>android.net.conn.CONNECTIVITY_CHANGE</code> are activated by the\nsystem as soon as the data connection is enabled. Since many\napplications typically use this intent filter, they are all activated\nalmost immediately by the system which causes the freezing or lags.<p>Receivers can also be used for inter-process communication (IPC),\ni.e., it can be used to communicate across multiple applications or even\ndifferent components of a single application.</section><section id=subsubsec:providers class=level4 data-number=2.2.3.4><h4 data-number=2.2.3.4><span class=header-section-number>2.2.3.4</span> Providers<a href=#subsubsec:providers class=anchor aria-hidden=true></a></h4><p><strong>Providers</strong> are primarily used for data management.\nFor example, when you save an APK file or export rules in App Manager,\nit uses a content provider called <code>.fm.FmProvider</code> to save\nthe APK or export the rules. There are many providers, including the\nones provided by the system, that can be used to manage various\ncontent-related tasks, such as database management, tracking, searching,\netc. Each provider has a field called <em>Authority</em> which is unique\nto the application in the entire Android ecosystem just as the package\nname.</section><section id=additional-features-for-rooted-phones class=level4 data-number=2.2.3.5><h4 data-number=2.2.3.5><span class=header-section-number>2.2.3.5</span> Additional Features for\nRooted Phones<a href=#additional-features-for-rooted-phones class=anchor aria-hidden=true></a></h4><p>Unlike the no-root users who are mostly spectators in these tabs,\nroot users can perform various operations.<section id=blocking-components. class=level5 data-number=2.2.3.5.1><h5 data-number=2.2.3.5.1><span class=header-section-number>2.2.3.5.1</span> Blocking Components.<a href=#blocking-components. class=anchor aria-hidden=true></a></h5><p>On the right-most side of each component item, there is a switch\nwhich can be used to toggle the blocking status of that particular\ncomponent. If <a href=#subsubsec:instant-component-blocking>Instant\nComponent Blocking</a> is not enabled or blocking is never applied to\nthe application before, it is required to apply the changes using the\n<strong>Apply rules</strong> option in three-dots menu. It is also\npossible to remove the already-applied rules using the same option\n(which would be read as <strong>Remove rules</strong> this time).<p>It is also possible to block the component using one of the several\nmethods by long clicking on the button.<div class=seealso-inline><p><em>See also: <span><a href=#sec:faq:app-components>FAQ: App\nComponents</a></span></em></div></section><section id=par:appdetails:blocking-trackers class=level5 data-number=2.2.3.5.2><h5 data-number=2.2.3.5.2><span class=header-section-number>2.2.3.5.2</span> Blocking Trackers.<a href=#par:appdetails:blocking-trackers class=anchor aria-hidden=true></a></h5><p>It is possible to disable tracker components using the <strong>Block\ntracker</strong> option in the three-dots menu. All tracker components\nwill be blocked regardless of the tab you’re currently in.<div class=\"amalert tip\"><p><strong><em>Info.</em></strong><p>Tracker components are a subset of application components. Therefore,\nthey are blocked using the same method used for blocking any other\ncomponents.</div><div class=seealso><p><em>See also:</em><ul class=incremental><li><p><a href=#subsec:tracker-classes-versus-tracker-components>FAQ:\nTracker classes versus tracker components</a><li><p><a href=#sec:scanner-page>Scanner Page</a><li><p><a href=#subsec:block-unblock-trackers>1-Click Ops Page:\nBlock/Unblock Trackers</a></ul></div></section></section></section><section id=subsec:permission-tabs class=level3 data-number=2.2.4><h3 data-number=2.2.4><span class=header-section-number>2.2.4</span>\n<a href=#toc:subsec:permission-tabs>Permission Tabs</a><a href=#subsec:permission-tabs class=anchor aria-hidden=true></a></h3><p><strong>App Ops</strong>, <strong>Uses Permissions</strong> and\n<strong>Permissions</strong> tabs are related to permissions. In Android\ncommunication across applications or processes not having the same\nidentity (known as <em>shared ID</em>) often require permissions. These\npermissions are managed by the permission controller. Some permissions\nare considered <em>normal</em> permissions which are granted\nautomatically if they appear in the application manifest, but\n<em>dangerous</em> and <em>development</em> permissions require\nconfirmation from the user. Colours used in these tabs are explained in\n§<a href=#subsec:app-details-colour-codes data-reference-type=ref data-reference=subsec:app-details-colour-codes>2.2.1</a>.<section id=subsubsec:app-ops class=level4 data-number=2.2.4.1><h4 data-number=2.2.4.1><span class=header-section-number>2.2.4.1</span> App Ops<a href=#subsubsec:app-ops class=anchor aria-hidden=true></a></h4><p><strong>App Ops</strong> stands for <strong>Application\nOperations</strong>. Since Android 4.3, <em>App Ops</em> are used by\nAndroid to control many system permissions. Each app op has a unique\nnumber associated with it which is displayed along with the private name\nof the operation in the App Ops tab. Some app ops also have a public\nname. A large number of app ops are also associated with\n<em>permissions</em>. In this tab, an app op is considered dangerous if\nits associated permission is marked as dangerous. Other information such\nas <em>flags</em>, <em>permission name</em>, <em>permission\ndescription</em>, <em>package name</em>, <em>group</em> are also taken\nfrom the associated <a href=#subsubsec:permissions>permission</a>.\nOthers may include the following:<ul class=incremental><li><p><strong>Mode.</strong> It describes the current authorisation\nstatus which can be <em>allow</em>, <em>deny</em> (a rather misnomer, it\nsimply means error), <em>ignore</em> (it actually means deny),\n<em>default</em> (inferred from a list of defaults set internally by the\nvendor or the AOSP), <em>foreground</em> (in newer Android versions, it\nmeans the app op can only be used when the application is running in\nforeground), and some custom modes set by the vendors (MIUI uses\n<em>ask</em>, for example).<li><p><strong>Duration.</strong> The amount of time this app op has\nbeen used (there can be negative durations whose use cases are currently\nunknown to me).<li><p><strong>Accept Time.</strong> Last time the app op was\naccepted.<li><p><strong>Reject Time.</strong> Last time the app op was\nrejected.</ul><div class=\"amalert tip\"><p><strong><em>Info.</em></strong><p>Contents of this tab are visible to no-root users if\n<code>android.permission.GET_APP_OPS_STATS</code> is granted via\nADB.</div><p>There is a toggle button next to each app op item which can be used\nto allow or deny (ignore) it. Other supported modes can also be set by\nlong clicking on the toggle button. If the desired app op is not listed\nin the tab, <em>Set custom app op</em> option in the menu can be used\ninstead. It is also possible to reset the changes using the <em>Reset to\ndefault</em> option, or deny all the dangerous app ops using the\ncorresponding option in the menu. Due to the nature how app ops work,\nthe system may take some time to apply them.<div class=\"amalert tip\"><p><strong><em>Tip.</em></strong><p>Denying certain app ops may cause the application to misbehave. If\nall attempts fail, <em>reset to default</em> option can be used as the\nlast resort.</div><p>It is possible to sort the list in ascending order by app op names\nand the associated unique numbers (or values), or list the denied app\nops first using the corresponding sorting options.<div class=seealso-inline><p><em>See also: <span><a href=#ch:app-ops>Appendix: App\nOps</a></span></em></div></section><section id=uses-permissions class=level4 data-number=2.2.4.2><h4 data-number=2.2.4.2><span class=header-section-number>2.2.4.2</span> Uses Permissions<a href=#uses-permissions class=anchor aria-hidden=true></a></h4><p><strong>Uses Permissions</strong> are the permissions used by the\napplication. This is named so because they are specified in the manifest\nusing <code>uses-permission</code> tags. Information such as\n<em>flags</em>, <em>permission name</em>, <em>permission\ndescription</em>, <em>package name</em>, <em>group</em> are taken from\nthe associated <a href=#subsubsec:permissions>permission</a>.<p>Privileged users can grant or revoke the <em>dangerous</em> and\n<em>development</em> permissions via the toggle button on the right side\nof each permission item. It is also possible revoke dangerous\npermissions all at once using the corresponding option in the menu. Only\nthese two types of permissions can be revoked because Android does not\nallow the modification of <em>normal</em> permissions (which most of\nthem are). It might still be possible to revoke them by editing\n<code>runtime-permissions.xml</code> itself, but whether this is a\npossibility is still being investigated.<div class=\"amalert tip\"><p><strong><em>Info.</em></strong><p>Since dangerous permissions are revoked by default by the system,\nrevoking all dangerous permissions is the same as resetting all the\npermissions.</div><p>It is possible to sort the permissions by their name (in ascending\norder) or choose to display denied or dangerous permissions at first\nusing the corresponding options in the menu.</section><section id=subsubsec:permissions class=level4 data-number=2.2.4.3><h4 data-number=2.2.4.3><span class=header-section-number>2.2.4.3</span> Permissions<a href=#subsubsec:permissions class=anchor aria-hidden=true></a></h4><p><strong>Permissions</strong> are usually custom permissions defined\nby the application itself. These type of permissions are marked as\n<em>Internal</em> permissions. It also contains permissions declared by\nother applications which are marked as <em>External</em> permissions. An\nexternal permission can be specified in an <em>exported</em> application\ncomponent so that another application may invoke the component only if\nit holds the permission. Below is a complete description of each item\ndisplayed in this tab:<ul class=incremental><li><p><strong>Name.</strong> A permission has a unique name (e.g.,\n<code>android.permission.INTERNET</code>) that multiple applications can\nrequest. The application that declared the permission is automatically\ngranted and cannot be revoked.<li><p><strong>Icon.</strong> Each permission can have a custom icon.\nThe other permission tabs do not have any icon because they do not\ncontain any icon in the application manifest.<li><p><strong>Description.</strong> This optional field describes the\npermission. If there isn’t any description associated with the\npermission, the field is not displayed.<li><p><strong>Flags.</strong> (Uses the flag symbol or\n<strong>Protection Level</strong> name) This describes various\npermission flags such as <em>normal</em>, <em>development</em>,\n<em>dangerous</em>, <em>instant</em>, <em>granted</em>,\n<em>revoked</em>, <em>signature</em>, <em>privileged</em>, etc.<li><p><strong>Package Name.</strong> Denotes the package name\nassociated with the permission, i.e. the package that defined the\npermission.<li><p><strong>Group.</strong> The group name associated with the\npermission (if any). Several related permissions can often be grouped\ntogether.</ul></section></section><section id=subsec:signatures-tab class=level3 data-number=2.2.5><h3 data-number=2.2.5><span class=header-section-number>2.2.5</span>\n<a href=#toc:subsec:signatures-tab>Signatures Tab</a><a href=#subsec:signatures-tab class=anchor aria-hidden=true></a></h3><p><strong>Signatures</strong> are actually called signing information.\nAn application is signed with one or more signing keys by its developer\nbefore publishing it. The integrity of an application, i.e., whether the\napplication is from the actual developer and has not been modified by\nanother person, can be checked using the signing certificate included in\nthe APK files. This is because when an application is modified by an\nunauthorised entity, the application can longer be signed with the\noriginal signing keys since the signing keys are unknown to the entity.\nOne way to verify the integrity of an application is via the checksums\ngenerated from the certificates. If the developer supplies the checksums\nfor the signing certificates, they can be compared against the checksums\ngenerated in the <strong>Signatures</strong> tab to verify the\napplication. For example, if you have downloaded App Manager from GitHub\nor Telegram Channel, you can verify whether the application was actually\nreleased by me by simply matching the following <em>SHA256</em> checksum\nwith the one displayed in this tab:<pre><code>320c0c0fe8cef873f2b554cb88c837f1512589dcced50c5b25c43c04596760ab</code></pre><p>Several hashing algorithms are used to generate checksums in this\ntab. They include <em>MD5</em>, <em>SHA1</em>, <em>SHA256</em> and\n<em>SHA512</em>.<div class=\"amalert danger\"><p><strong><em>Caution.</em></strong><p>Signing information should be verified using a reliable hashing\nalgorithm, such as <em>SHA256</em>. DO NOT rely on <em>MD5</em> or\n<em>SHA1</em> checksums as they are known to generate the same checksums\nfor multiple certificates.</div></section><section id=subsec:uses-features-tab class=level3 data-number=2.2.6><h3 data-number=2.2.6><span class=header-section-number>2.2.6</span>\n<a href=#toc:subsec:uses-features-tab>Uses Features tab</a><a href=#subsec:uses-features-tab class=anchor aria-hidden=true></a></h3><p><strong>Uses Features</strong> tab lists the features declared by the\napplication, such as OpenGL ES, telephony, and leanback. Some features\ncan be required by the application, and some features can be optional.\nRequired features must be present in the system along with the required\nversion. Otherwise, any attempt to install the application will be\ndenied by the system. Colours used in this tab are explained in §<a href=#subsec:app-details-colour-codes data-reference-type=ref data-reference=subsec:app-details-colour-codes>2.2.1</a>.</section><section id=subsec:configurations-tab class=level3 data-number=2.2.7><h3 data-number=2.2.7><span class=header-section-number>2.2.7</span>\n<a href=#toc:subsec:configurations-tab>Configurations tab</a><a href=#subsec:configurations-tab class=anchor aria-hidden=true></a></h3><p><strong>Configurations</strong> tab lists the configurations required\nby the application, such as input method type (qwerty, 12 key), touch\nscreen type (finger, stylus, etc.), and navigation type (dial pad,\ntrackball, wheel). This tab is going to be empty for most\napplications.</section><section id=subsec:shared-libs-tab class=level3 data-number=2.2.8><h3 data-number=2.2.8><span class=header-section-number>2.2.8</span>\n<a href=#toc:subsec:shared-libs-tab>Shared Libraries Tab</a><a href=#subsec:shared-libs-tab class=anchor aria-hidden=true></a></h3><p><strong>Shared libraries</strong> tab lists the legacy JAR\ndependencies, any static shared library dependencies (currently, the\nonly known cases are the Chromium-based browsers and WebViews) as well\nas the JNI (Java native interface) libraries. For JNI libraries, it\nspecifies platform (x86/x86_64/ARM/AArch64), architecture (32/64 bit),\nobject type (shared object or executable), etc.</section></section><section id=sec:1-click-ops-page class=level2 data-number=2.3><h2 data-number=2.3><span class=header-section-number>2.3</span> <a href=#toc:sec:1-click-ops-page>1-Click Ops Page</a><a href=#sec:1-click-ops-page class=anchor aria-hidden=true></a></h2><p>This page is displayed on selecting the <a href=#subsubsec:main:1-click-ops>1-Click Ops option</a> in the <a href=#subsec:main-page-options-menu>main menu</a>.<section id=subsec:block-unblock-trackers class=level3 data-number=2.3.1><h3 data-number=2.3.1><span class=header-section-number>2.3.1</span>\n<a href=#toc:subsec:block-unblock-trackers>Block/Unblock\nTrackers</a><a href=#subsec:block-unblock-trackers class=anchor aria-hidden=true></a></h3><p>This option can be used to block or unblock the ad/tracker components\nfrom the installed applications. On selecting this option, App Manager\nwill ask if it should list trackers from all the applications or only\nfrom the user applications. Novice users should avoid blocking trackers\nfrom the system applications in order to avoid bad consequences. After\nthat, a multi-choice dialog box will appear where it is possible to\nexclude one or more applications from this operation. The changes are\napplied immediately on pressing the <em>block</em> or <em>unblock</em>\nbutton.<div class=\"amalert warning\"><p><strong><em>Notice.</em></strong><p>Certain applications may not function as expected after blocking\ntheir trackers. If that is the case, remove the blocking rules all at\nonce or one by one in the component tabs of the <a href=#sec:app-details-page>App Details page</a> for the corresponding\napplication.</div><div class=seealso-inline><p><em>See also: <span><a href=#par:appdetails:blocking-trackers>App\nDetails Page: Blocking Trackers</a></span></em></div></section><section id=subsec:block-components-dots class=level3 data-number=2.3.2><h3 data-number=2.3.2><span class=header-section-number>2.3.2</span>\n<a href=#toc:subsec:block-components-dots>Block Components…</a><a href=#subsec:block-components-dots class=anchor aria-hidden=true></a></h3><p>This option can be used to block certain application components as\nspecified by their signatures. A signature of a component is the full\nname or partial name of the component. For safety, it is recommended to\nadd a <code>.</code> (dot) at the end of each partial signature, because\nthe underlying algorithm searches and matches the components in a greedy\nmanner. It is also possible to insert more than one signature in which\ncase all the signatures have to be separated by white spaces. Similar to\nthe option above, there is also an option to apply blocking to the\nsystem applications.<div class=\"amalert danger\"><p><strong><em>Caution.</em></strong><p>If you are not aware of the consequences of blocking applcations\ncomponents by their signatures, you should avoid using this option as it\nmay result in bootloop or soft brick, and you may have to apply factory\nreset as a result.</div></section><section id=subsec:set-mode-for-app-ops-dots class=level3 data-number=2.3.3><h3 data-number=2.3.3><span class=header-section-number>2.3.3</span>\n<a href=#toc:subsec:set-mode-for-app-ops-dots>Set Mode for App\nOps…</a><a href=#subsec:set-mode-for-app-ops-dots class=anchor aria-hidden=true></a></h3><p>This option can be used to configure certain <a href=#ch:app-ops>applcation operations</a> of all or selected\napplications. There are two fields. The first field can be used to\ninsert more than one app op constants (either names or values) separated\nby white spaces. It is not always possible to know in advance about all\nthe app op constants as they vary from device to device and from OS to\nOS. Desired app op constant can be found in the <em>App Ops</em> tab\nlocated in the <a href=#sec:app-details-page>App Details page</a>. The\nsecond field can be used to insert or select one of the <a href=#subsec:mode-constants>modes</a> that will be set against the\nspecified app ops.<div class=\"amalert danger\"><p><strong><em>Caution.</em></strong><p>Unless you are well-informed about app ops and the consequences of\nblocking them, you should avoid using this option.</div></section><section id=subsec:1-click-back-up class=level3 data-number=2.3.4><h3 data-number=2.3.4><span class=header-section-number>2.3.4</span>\n<a href=#toc:subsec:1-click-back-up>Back up</a><a href=#subsec:1-click-back-up class=anchor aria-hidden=true></a></h3><p>1-Click options for back up. As a precaution, it lists the affected\nbackups before performing any operation.<section id=back-up-all-apps. class=level5 data-number=2.3.4.0.1><h5 data-number=2.3.4.0.1><span class=header-section-number>2.3.4.0.1</span> Back up all apps.<a href=#back-up-all-apps. class=anchor aria-hidden=true></a></h5><p>Back up all the installed applications.</section><section id=redo-existing-backups. class=level5 data-number=2.3.4.0.2><h5 data-number=2.3.4.0.2><span class=header-section-number>2.3.4.0.2</span> Redo existing backups.<a href=#redo-existing-backups. class=anchor aria-hidden=true></a></h5><p>Back up all the installed applications that have a previous\nbackup.</section><section id=back-up-apps-without-backups. class=level5 data-number=2.3.4.0.3><h5 data-number=2.3.4.0.3><span class=header-section-number>2.3.4.0.3</span> Back up apps without\nbackups.<a href=#back-up-apps-without-backups. class=anchor aria-hidden=true></a></h5><p>Back up all the installed applications without a previous backup.</section><section id=verify-and-redo-backups. class=level5 data-number=2.3.4.0.4><h5 data-number=2.3.4.0.4><span class=header-section-number>2.3.4.0.4</span> Verify and redo\nbackups.<a href=#verify-and-redo-backups. class=anchor aria-hidden=true></a></h5><p>Verify the recently made backups of the installed applications and\nredo backup if necessary.</section><section id=back-up-apps-with-changes. class=level5 data-number=2.3.4.0.5><h5 data-number=2.3.4.0.5><span class=header-section-number>2.3.4.0.5</span> Back up apps with\nchanges.<a href=#back-up-apps-with-changes. class=anchor aria-hidden=true></a></h5><p>If an app has changed since the last backup, redo its backup. It\nchecks a number of indices including application version, last update\ndate, last launch date, integrity and file hashes. Directory hashes are\ntaken during the backup process and are stored in a database. On running\nthis operation, new hashes are taken and compared with the ones kept in\nthe database.</section></section><section id=subsec:1-click-restore class=level3 data-number=2.3.5><h3 data-number=2.3.5><span class=header-section-number>2.3.5</span>\n<a href=#toc:subsec:1-click-restore>Restore</a><a href=#subsec:1-click-restore class=anchor aria-hidden=true></a></h3><p>1-Click options for restore. As a precaution, it lists the affected\nbackups before performing any operation.<section id=restore-all-apps. class=level5 data-number=2.3.5.0.1><h5 data-number=2.3.5.0.1><span class=header-section-number>2.3.5.0.1</span> Restore all apps.<a href=#restore-all-apps. class=anchor aria-hidden=true></a></h5><p>Restore <em>base backup</em> of all the backed up applications.</section><section id=restore-not-installed-apps. class=level5 data-number=2.3.5.0.2><h5 data-number=2.3.5.0.2><span class=header-section-number>2.3.5.0.2</span> Restore not installed\napps.<a href=#restore-not-installed-apps. class=anchor aria-hidden=true></a></h5><p>Restore <em>base backup</em> of all the backed up applications that\nare not currently installed.</section><section id=restore-latest-backups. class=level5 data-number=2.3.5.0.3><h5 data-number=2.3.5.0.3><span class=header-section-number>2.3.5.0.3</span> Restore latest backups.<a href=#restore-latest-backups. class=anchor aria-hidden=true></a></h5><p>Restore <em>base backup</em> of already installed applications whose\nversion codes are higher than the installed version code.</section></section><section id=subsec:trim-caches-in-all-apps class=level3 data-number=2.3.6><h3 data-number=2.3.6><span class=header-section-number>2.3.6</span>\n<a href=#toc:subsec:trim-caches-in-all-apps>Trim Caches in All\nApps</a><a href=#subsec:trim-caches-in-all-apps class=anchor aria-hidden=true></a></h3><p>Delete caches from all applications, including Android system. During\nthis operation, caches of all the running applications may not be\ncleared as expected.</section></section><section id=sec:profiles-page class=level2 data-number=2.4><h2 data-number=2.4><span class=header-section-number>2.4</span> <a href=#toc:sec:profiles-page>Profiles Page</a><a href=#sec:profiles-page class=anchor aria-hidden=true></a></h2><p>Profiles page can be accessed from the <a href=#subsec:main-page-options-menu>options-menu</a> in the main page.\nIt primarily displays a list of configured profiles along with the\ntypical options to perform operations on them. New profiles can also be\nadded using the <em>plus</em> button at the bottom-right corner.\nProfiles can be imported, duplicated or deleted. Clicking on a profile\nitem opens its <a href=#sec:profile-page>profile page</a>.<section id=subsec:profiles-options-menu class=level3 data-number=2.4.1><h3 data-number=2.4.1><span class=header-section-number>2.4.1</span>\n<a href=#toc:subsec:profiles-options-menu>Options Menu</a><a href=#subsec:profiles-options-menu class=anchor aria-hidden=true></a></h3><p>The three-dots menu in the top-right corner opens the global option\nmenu. It has an option to import an existing profile that was previously\nexported from App Manager.<p>Long clicking on any profile item brings up another options-menu. It\noffers the following options:<ul class=incremental><li><p><strong>Apply now….</strong> This option can be used to apply the\nprofile directly. When clicked, a dialog is displayed where it is\npossible to select a <a href=#subsubsec:profile-state>profile\nstate</a>. On selecting one of the states, the profile will be applied\nimmediately.<li><p><strong>Delete.</strong> Clicking on this option will remove the\nprofile immediately without a warning.<li><p><strong>Duplicate.</strong> This option can be used to duplicate\nthe profile. When clicked, a dialog is displayed where it is possible to\nset a name for the new profile. On clicking “OK”, the <a href=#sec:profile-page>profile page</a> will be loaded by duplicating\nall the configurations that this profile have. However, the profile will\nnot be saved until it is saved manually.<li><p><strong>Copy profile ID.</strong> This option is used to copy the\nunique profile ID of the profile. The profile ID can be used to <a href=#subsec:triggering-a-profile>trigger the profile</a> from a\nthird-party application.<li><p><strong>Export.</strong> Export the profile to an external\nstorage. Profiles exported this way can be imported via the\n<em>import</em> option as mentioned above.<li><p><strong>Create shortcut.</strong> This option can be used to\ncreate a shortcut for the profile. There are two options:\n<em>Simple</em> and <em>Advanced</em>. When configured with the latter\noption, it prompts the user to select a profile state when the shortcut\nis invoked. The former option, on the other hand, always uses the\ndefault state that was configured when the profile was last\nsaved.</ul></section></section><section id=sec:profile-page class=level2 data-number=2.5><h2 data-number=2.5><span class=header-section-number>2.5</span> <a href=#toc:sec:profile-page>Profile Page</a><a href=#sec:profile-page class=anchor aria-hidden=true></a></h2><p>Profile page displays the configurations for a profile. It also\noffers the options to edit them.<section id=subsec:profile-options-menu class=level3 data-number=2.5.1><h3 data-number=2.5.1><span class=header-section-number>2.5.1</span>\n<a href=#toc:subsec:profile-options-menu>Options Menu</a><a href=#subsec:profile-options-menu class=anchor aria-hidden=true></a></h3><p>The three dots menu in the top-right corner opens the options-menu.\nIt contains several options such as–<ul class=incremental><li><p><strong>Apply.</strong> This option can be used to apply the\nprofile directly. When clicked, a dialog is displayed where it is\npossible to select a <a href=#subsubsec:profile-state>profile\nstate</a>. On selecting one of the states, the profile will be applied\nimmediately.<div class=\"amalert tip\"><p><strong><em>Notice.</em></strong><p>When you apply a profile, if some packages do not match the criteria,\nthey will simply be ignored.</div><li><p><strong>Save.</strong> Save changes to the profile.<li><p><strong>Discard.</strong> Discard any modifications made since\nthe last time it was saved.<li><p><strong>Delete.</strong> Clicking on this option will remove the\nprofile immediately without a warning.<li><p><strong>Duplicate.</strong> This option can be used to duplicate\nthe profile. When clicked, a dialog is displayed where it is possible to\nset a name for the new profile. On clicking “OK”, this page will be\nreloaded by duplicating all the configurations that this profile have.\nHowever, the new profile will not be saved until it is saved\nmanually.<li><p><strong>Create shortcut.</strong> This option can be used to\ncreate a shortcut for the profile. There are two options:\n<em>Simple</em> and <em>Advanced</em>. When configured with the latter\noption, it prompts the user to select a profile state when the shortcut\nis invoked. The former option, on the other hand, always uses the\ndefault state that was configured when the profile was last\nsaved.</ul></section><section id=subsec:profile-apps-tab class=level3 data-number=2.5.2><h3 data-number=2.5.2><span class=header-section-number>2.5.2</span>\n<a href=#toc:subsec:profile-apps-tab>Apps Tab</a><a href=#subsec:profile-apps-tab class=anchor aria-hidden=true></a></h3><p>Apps tab lists the packages configured for this profile. Packages can\nbe added or removed using the <em>plus</em> button located near the\nbottom of the screen. A package can also be removed by long clicking on\nit (in which case, a popup will be displayed with the only option,\n<em>delete</em>).</section><section id=subsec:profile-configurations-tab class=level3 data-number=2.5.3><h3 data-number=2.5.3><span class=header-section-number>2.5.3</span>\n<a href=#toc:subsec:profile-configurations-tab>Configurations\nTab</a><a href=#subsec:profile-configurations-tab class=anchor aria-hidden=true></a></h3><p>Configurations tab can be used to configure the selected\npackages.<div class=\"amalert tip\"><p><strong><em>Uninstalling a List of Applications..</em></strong><p>Since uninstalling is a one time event, it is not part of the\nconfigurations. However, it is still possible to uninstall the\napplications belonging to a profile. To do this, you can filter the\napplications in the Main page using a profile, select all the filtered\napplications, and uninstall them.</div><section id=profile-id class=level4 data-number=2.5.3.1><h4 data-number=2.5.3.1><span class=header-section-number>2.5.3.1</span> Profile ID<a href=#profile-id class=anchor aria-hidden=true></a></h4><p>The unique ID for this profile, currently set based on the profile\nname. The profile ID can be used to <a href=#subsec:triggering-a-profile>trigger the profile</a> from a\nthird-party application.</section><section id=comment class=level4 data-number=2.5.3.2><h4 data-number=2.5.3.2><span class=header-section-number>2.5.3.2</span> Comment<a href=#comment class=anchor aria-hidden=true></a></h4><p>This is the text that will be displayed in the <a href=#sec:profiles-page>profiles page</a>. If not set, the current\nconfigurations will be displayed instead.</section><section id=subsubsec:profile-state class=level4 data-number=2.5.3.3><h4 data-number=2.5.3.3><span class=header-section-number>2.5.3.3</span> State<a href=#subsubsec:profile-state class=anchor aria-hidden=true></a></h4><p>Denotes how certain configured options will behave by default. For\ninstance, if <em>disable</em> option is turned on, the applications will\nbe disabled if the state is <em>on</em> and will be enabled if the state\nis <em>off</em>. Currently, it only supports <em>on</em> and\n<em>off</em> values.</section><section id=users class=level4 data-number=2.5.3.4><h4 data-number=2.5.3.4><span class=header-section-number>2.5.3.4</span> Users<a href=#users class=anchor aria-hidden=true></a></h4><p>Select users for which is the profile will be applied. All users are\nselected by default.</section><section id=components class=level4 data-number=2.5.3.5><h4 data-number=2.5.3.5><span class=header-section-number>2.5.3.5</span> Components<a href=#components class=anchor aria-hidden=true></a></h4><p>This behaves the same way as the <a href=#subsec:block-components-dots>Block Components…</a> option does\nin the 1-Click Ops page. However, the blocking here is only applied to\nthe selected packages. If the <a href=#subsubsec:profile-state>state</a> is <em>on</em>, the components\nwill be blocked, and if the state is <em>off</em>, the components will\nbe unblocked. The option can be disabled (regardless of the inserted\nvalues) by clicking on the <em>disabled</em> button on the input\ndialog.<div class=seealso-inline><p><em>See also: <span><a href=#subsec:faq:what-are-app-components>What are the app\ncomponents?</a></span></em></div></section><section id=app-ops class=level4 data-number=2.5.3.6><h4 data-number=2.5.3.6><span class=header-section-number>2.5.3.6</span> App Ops<a href=#app-ops class=anchor aria-hidden=true></a></h4><p>This behaves the same way as the <a href=#subsec:set-mode-for-app-ops-dots>Set Mode for App Ops…</a>\noption does in the 1-Click Ops page. However, the operation here is only\napplied to the selected packages. If the <a href=#subsubsec:profile-state>state</a> is <em>on</em>, the app ops\nwill be denied (i.e. ignored), and if the state is <em>off</em>, the app\nops will be allowed. The option can be disabled (regardless of the\ninserted values) by clicking on the <em>disable</em> button in the input\ndialog.</section><section id=permissions class=level4 data-number=2.5.3.7><h4 data-number=2.5.3.7><span class=header-section-number>2.5.3.7</span> Permissions<a href=#permissions class=anchor aria-hidden=true></a></h4><p>This option can be used to grant or revoke certain permissions from\nthe selected packages. Like others above, permissions must be separated\nby white spaces. If the <a href=#subsubsec:profile-state>state</a> is\n<em>on</em>, the permissions will be revoked, and if the state is\n<em>off</em>, the permissions will be allowed. The option can be\ndisabled (regardless of the inserted values) by clicking on the\n<em>disable</em> button in the input dialog.</section><section id=backuprestore class=level4 data-number=2.5.3.8><h4 data-number=2.5.3.8><span class=header-section-number>2.5.3.8</span> Backup/Restore<a href=#backuprestore class=anchor aria-hidden=true></a></h4><p>This option can be used to take a backup of the selected applications\nand its data or restore them. Two options are available here: <em>Backup\noptions</em> and <em>backup name</em>.<ul class=incremental><li><p><strong>Backup options.</strong> Same as the <a href=#subsec:backup-restore-backup-options>backup options</a> of the\nbackup/restore feature. If not set, the default options will be\nused.<li><p><strong>Backup name.</strong> Set a custom name for the backup.\nIf the backup name is set, each time a backup is made, it will be given\na unique name with backup-name as the suffix. This behaviour will be\nfixed in a future release. Leave this field empty for regular “base”\nbackups (also, make sure not to enable <em>backup multiple</em> in the\nbackup options).</ul><p>If the <a href=#subsubsec:profile-state>state</a> is <em>on</em>,\nthe packages will be backed up, and if the state is <em>off</em>, the\npackages will be restored. The option can be disabled by clicking on the\n<em>disable</em> button in the input dialog.</section><section id=export-blocking-rules class=level4 data-number=2.5.3.9><h4 data-number=2.5.3.9><span class=header-section-number>2.5.3.9</span> Export Blocking Rules<a href=#export-blocking-rules class=anchor aria-hidden=true></a></h4><div class=\"amalert danger\"><p><strong><em>Danger.</em></strong><p>This option is not yet implemented.</div></section><section id=freeze class=level4 data-number=2.5.3.10><h4 data-number=2.5.3.10><span class=header-section-number>2.5.3.10</span> Freeze<a href=#freeze class=anchor aria-hidden=true></a></h4><p>Allow freezing or unfreezing the selected packages depending on the\nvalue of the <a href=#subsubsec:profile-state>state</a>. If the state\nis <em>on</em>, the packages will be frozen, and if the state is\n<em>off</em>, they will be unfrozen.</section><section id=force-stop class=level4 data-number=2.5.3.11><h4 data-number=2.5.3.11><span class=header-section-number>2.5.3.11</span> Force-stop<a href=#force-stop class=anchor aria-hidden=true></a></h4><p>Allow the selected packages to be force-stopped.</section><section id=clear-cache class=level4 data-number=2.5.3.12><h4 data-number=2.5.3.12><span class=header-section-number>2.5.3.12</span> Clear Cache<a href=#clear-cache class=anchor aria-hidden=true></a></h4><p>Enable clearing cache for the selected packages.</section><section id=clear-data class=level4 data-number=2.5.3.13><h4 data-number=2.5.3.13><span class=header-section-number>2.5.3.13</span> Clear Data<a href=#clear-data class=anchor aria-hidden=true></a></h4><p>Enable clearing data for the selected packages.</section><section id=block-trackers class=level4 data-number=2.5.3.14><h4 data-number=2.5.3.14><span class=header-section-number>2.5.3.14</span> Block Trackers<a href=#block-trackers class=anchor aria-hidden=true></a></h4><p>Enable blocking or unblocking of the tracker components from the\nselected packages depending on the value of the <a href=#subsubsec:profile-state>state</a>. If the state is <em>on</em>,\nthe trackers will be blocked, and if the state is <em>off</em>, the\ntrackers will be unblocked.</section><section id=save-apk class=level4 data-number=2.5.3.15><h4 data-number=2.5.3.15><span class=header-section-number>2.5.3.15</span> Save APK<a href=#save-apk class=anchor aria-hidden=true></a></h4><p>Enable saving APK files at <code>AppManager/apks</code> (or in the\ndirectory selected in the settings page) of the selected packages.</section></section></section><section id=sec:settings-page class=level2 data-number=2.6><h2 data-number=2.6><span class=header-section-number>2.6</span> <a href=#toc:sec:settings-page>Settings Page</a><a href=#sec:settings-page class=anchor aria-hidden=true></a></h2><p>Settings page can be used to customise the behaviour of App\nManager.<section id=subsec:language class=level3 data-number=2.6.1><h3 data-number=2.6.1><span class=header-section-number>2.6.1</span>\n<a href=#toc:subsec:language>Language</a><a href=#subsec:language class=anchor aria-hidden=true></a></h3><p>Configure in-app language. App Manager currently supports 22\n(twenty-two) languages.</section><section id=subsec:appearance class=level3 data-number=2.6.2><h3 data-number=2.6.2><span class=header-section-number>2.6.2</span>\n<a href=#toc:subsec:appearance>Appearance</a><a href=#subsec:appearance class=anchor aria-hidden=true></a></h3><section id=subsubsec:app-theme class=level4 data-number=2.6.2.1><h4 data-number=2.6.2.1><span class=header-section-number>2.6.2.1</span> App Theme<a href=#subsubsec:app-theme class=anchor aria-hidden=true></a></h4><p>Configure in-app theme.</section><section id=subsubsec:pure-black-theme class=level4 data-number=2.6.2.2><h4 data-number=2.6.2.2><span class=header-section-number>2.6.2.2</span> Pure Black Theme<a href=#subsubsec:pure-black-theme class=anchor aria-hidden=true></a></h4><p>Whether to use a black background instead of the material themed\nbackground.</section><section id=subsubsec:layout-direction class=level4 data-number=2.6.2.3><h4 data-number=2.6.2.3><span class=header-section-number>2.6.2.3</span> Layout Direction<a href=#subsubsec:layout-direction class=anchor aria-hidden=true></a></h4><p>Change layout direction, either left to right or right to left. This\nis usually set using the selected language but not everybody prefers the\nsame direction.</section><section id=subsubsec:enable/disable-features class=level4 data-number=2.6.2.4><h4 data-number=2.6.2.4><span class=header-section-number>2.6.2.4</span> Enable/Disable Features<a href=#subsubsec:enable/disable-features class=anchor aria-hidden=true></a></h4><p>Enable or disable certain features in App Manager, such as<ul class=incremental><li><p><strong>Interceptor</strong><li><p><strong>Manifest viewer</strong><li><p><strong>Scanner</strong><li><p><strong>Package installer</strong><li><p><strong>Usage access.</strong> With this feature turned off, App\nManager will never ask for the <em>Usage Access</em>\npermission.<li><p><strong>Log viewer</strong><li><p><strong>App explorer.</strong> The “Explore” option will not be\navailable while trying to open an APK file.<li><p><strong>App info.</strong> The “App info” option displayed while\ntrying to open an APK file.<li><p><strong>Code Editor</strong><li><p><strong>VirusTotal</strong></ul></section></section><section id=subsec:privacy class=level3 data-number=2.6.3><h3 data-number=2.6.3><span class=header-section-number>2.6.3</span>\n<a href=#toc:subsec:privacy>Privacy</a><a href=#subsec:privacy class=anchor aria-hidden=true></a></h3><section id=subsubsec:screen-lock class=level4 data-number=2.6.3.1><h4 data-number=2.6.3.1><span class=header-section-number>2.6.3.1</span> Screen Lock<a href=#subsubsec:screen-lock class=anchor aria-hidden=true></a></h4><p>Lock App Manager using Android screen lock provided a screen lock is\nconfigured.<div class=\"amalert warning\"><p><strong><em>Warning.</em></strong><p>If screen lock is disabled in Android after enabling this setting,\nApp Manager will not open until it is enabled again.</div></section><section id=subsubsec:run-am-in-background class=level4 data-number=2.6.3.2><h4 data-number=2.6.3.2><span class=header-section-number>2.6.3.2</span> Run App Manager in the\nBackground<a href=#subsubsec:run-am-in-background class=anchor aria-hidden=true></a></h4><p>Whether to run App Manager in the background to reduce the\ninitialisation delay. On certain devices, this can also help if you’re\nfrequently disconnected from ADB.</section><section id=subsubsec:use-the-internet class=level4 data-number=2.6.3.3><h4 data-number=2.6.3.3><span class=header-section-number>2.6.3.3</span> Use the Internet<a href=#subsubsec:use-the-internet class=anchor aria-hidden=true></a></h4><p>Whether to activate the Internet features in App Manager. This\ncurrently include VirusTotal and Pithus scanning in the <a href=#sec:scanner-page>Scanner page</a>.</section><section id=subsubsec:auth-manager class=level4 data-number=2.6.3.4><h4 data-number=2.6.3.4><span class=header-section-number>2.6.3.4</span> Authorization Manager<a href=#subsubsec:auth-manager class=anchor aria-hidden=true></a></h4><p>This setting allows a third-party application to get access to\ncertain features, such as profiles.</section></section><section id=subsec:mode-of-operation class=level3 data-number=2.6.4><h3 data-number=2.6.4><span class=header-section-number>2.6.4</span>\n<a href=#toc:subsec:mode-of-operation>Mode of Operation</a><a href=#subsec:mode-of-operation class=anchor aria-hidden=true></a></h3><p>Mode of operation defines how App Manager works as a whole. It has\nthe following options:<ul class=incremental><li><p><strong>Auto.</strong> Let App Manager decide the suitable\noption. Although this is the default option, non-rooted users should use\nthe <em>no-root</em> mode.<li><p><strong>Root.</strong> Operate App Manager in root mode. App\nManager will fall back to <em>no-root</em> mode if root is not detected,\nor in rare cases when Binder communication through root is disabled\n(e.g. in <a href=https://github.com/MuntashirAkon/AppManager/issues/606>Phh\nSuperUser</a>).<li><p><strong>ADB over TCP.</strong> Operate App Manager in ADB mode\nvia <a href=#sec:adb-over-tcp>ADB over TCP</a>. App Manager will fall\nback to <em>no-root</em> mode if ADB over TCP is not enabled.<li><p><strong>Wireless debugging.</strong> Enable ADB via Wireless\nDebugging. It will try to connect to the configured port automatically\nat first. On failure, it will ask the user to either pair or connect to\nthe ADB daemon manually. App Manager will fall back to <em>no-root</em>\nmode if it fails to connect to the ADB daemon this way.<div class=\"amalert tip\"><p><strong><em>Info.</em></strong><p>This option is only displayed in devices running Android 11 or later\nas Wireless Debugging was introduced in Android 11.</div><li><p><strong>No-root.</strong> Operate App Manager in no-root mode.\nWhile App Manager performs better in this mode, all the root- or\nADB-specific features will be disabled.</ul><p>It also displays the actual mode of operation at the top. The actual\nmode of operations are <em>root</em>, <em>ABD</em> and\n<em>no-root</em>.<div class=\"amalert tip\"><p><strong><em>Notice.</em></strong><p>“Remote service” is only required for ADB users or when you use the\ncustom commands.</div></section><section id=subsec:apk-signing class=level3 data-number=2.6.5><h3 data-number=2.6.5><span class=header-section-number>2.6.5</span>\n<a href=#toc:subsec:apk-signing>APK Signing</a><a href=#subsec:apk-signing class=anchor aria-hidden=true></a></h3><section id=signature-schemes class=level4 data-number=2.6.5.1><h4 data-number=2.6.5.1><span class=header-section-number>2.6.5.1</span> Signature Schemes<a href=#signature-schemes class=anchor aria-hidden=true></a></h4><p>Configure the <a href=https://source.android.com/security/apksigning>signature\nschemes</a> to be used when APK signing is enabled. v1 and v2 signature\nschemes are enabled by default, but v3 should also be enabled to ensure\nproper security in Android 9 or later.</section><section id=signing-key class=level4 data-number=2.6.5.2><h4 data-number=2.6.5.2><span class=header-section-number>2.6.5.2</span> Signing Key<a href=#signing-key class=anchor aria-hidden=true></a></h4><p>Configure the signing key for signing APK files. Keys from an\nexisting KeyStore can be imported to App Manager, or a new key can be\ngenerated.<div class=\"amalert tip\"><p><strong><em>Tip.</em></strong><p>If you need to use the key in the future, it is recommended that you\ncreate a KeyStore yourself and import the key here. Without a proper\nbackup, keys generated within App Manager are at the risk of being\ndeleted.</div></section><section id=align-apk-files class=level4 data-number=2.6.5.3><h4 data-number=2.6.5.3><span class=header-section-number>2.6.5.3</span> Align APK Files<a href=#align-apk-files class=anchor aria-hidden=true></a></h4><p>Performs zip alignment when App Manager signs an APK file. Zip\nalignment stores the files in the APK file (which is actually a zip\nfile) in a way that a zip file reader can access the files quite easily\nusing random access instead of loading the entire APK file in the\nmemory, which results in the reduction of Android’s memory usage. Note\nthat this step is required if an application’s manifest has\n<code>extractNativeLibs</code> set to <code>true</code>.</section></section><section id=subsec:installer class=level3 data-number=2.6.6><h3 data-number=2.6.6><span class=header-section-number>2.6.6</span>\n<a href=#toc:subsec:installer>Installer</a><a href=#subsec:installer class=anchor aria-hidden=true></a></h3><p>Configure the default behaviour of the installer. You can also find\nmost of the settings by clicking on the <em>cog</em> icon when you\ninstall an application.<section id=install-location class=level4 data-number=2.6.6.1><h4 data-number=2.6.6.1><span class=header-section-number>2.6.6.1</span> Install Location<a href=#install-location class=anchor aria-hidden=true></a></h4><p>Define APK installation location. This can be one of <em>auto</em>,\n<em>internal only</em> and <em>prefer external</em>. In newer Android\nversions, selecting the last option does not guarantee that the\napplication will be installed in the external storage.</section><section id=block-trackers-1 class=level4 data-number=2.6.6.2><h4 data-number=2.6.6.2><span class=header-section-number>2.6.6.2</span> Block Trackers<a href=#block-trackers-1 class=anchor aria-hidden=true></a></h4><p>Whether to block the tracking components immediately after installing\nthe application.</section><section id=display-changes class=level4 data-number=2.6.6.3><h4 data-number=2.6.6.3><span class=header-section-number>2.6.6.3</span> Display Changes<a href=#display-changes class=anchor aria-hidden=true></a></h4><p>Whether to display changes in version, trackers, components,\npermissions, signatures, SDK, etc. in a version controlled style before\ninstalling the application if the application has already been\ninstalled.</section><section id=installer-app class=level4 data-number=2.6.6.4><h4 data-number=2.6.6.4><span class=header-section-number>2.6.6.4</span> Installer App<a href=#installer-app class=anchor aria-hidden=true></a></h4><p>Select the installer application. This is useful for applications\nthat explicitly checks the installer as a way to verify if the\napplication is installed legitimately. This only works for root or ADB\nusers.<div class=\"amalert tip\"><p><strong><em>Notice.</em></strong><p>While checking for the installer might seem a legitimate concern for\nan application, the Android framework already deals with this during the\ninstallation. Checking for the installer is simply the wrong way to\nprove the legitimacy of the source of an application.</div></section><section id=sign-apk class=level4 data-number=2.6.6.5><h4 data-number=2.6.6.5><span class=header-section-number>2.6.6.5</span> Sign APK<a href=#sign-apk class=anchor aria-hidden=true></a></h4><p>Whether to sign the APK files before installing the application. A\nsigning key has to be added or generated before this option can be\nenabled. This can be done in the <a href=#subsec:apk-signing>APK\nsigning</a> page.</section><section id=immediately-perform-dex-optimization class=level4 data-number=2.6.6.6><h4 data-number=2.6.6.6><span class=header-section-number>2.6.6.6</span> Immediately Perform DEX\nOptimization<a href=#immediately-perform-dex-optimization class=anchor aria-hidden=true></a></h4><p>Whether to perform DEX optimization immediately after installing the\napplication. This can be useful for heavy applications, such as the\ngaming applications.</section><section id=install-in-the-background class=level4 data-number=2.6.6.7><h4 data-number=2.6.6.7><span class=header-section-number>2.6.6.7</span> Install in the Background<a href=#install-in-the-background class=anchor aria-hidden=true></a></h4><p>Whether to always install applications in the background. A\nnotification will be issued once the installation is finished.</section></section><section id=subsec:backup/restore class=level3 data-number=2.6.7><h3 data-number=2.6.7><span class=header-section-number>2.6.7</span>\n<a href=#toc:subsec:backup/restore>Back up/Restore</a><a href=#subsec:backup/restore class=anchor aria-hidden=true></a></h3><p>Settings related to <a href=#sec:backup-restore>back\nup/restore</a>.<section id=compression-method class=level4 data-number=2.6.7.1><h4 data-number=2.6.7.1><span class=header-section-number>2.6.7.1</span> Compression method<a href=#compression-method class=anchor aria-hidden=true></a></h4><p>Set the compression method to be used during backups. App Manager\nsupports GZip, BZip2 and Zstandard compression methods, GZip being the\ndefault compression method. It doesn’t affect the restore of an existing\nbackup.</section><section id=subsubsec:settings-backup-options class=level4 data-number=2.6.7.2><h4 data-number=2.6.7.2><span class=header-section-number>2.6.7.2</span> Backup Options<a href=#subsubsec:settings-backup-options class=anchor aria-hidden=true></a></h4><p>Customise the <em>back up/restore dialog</em> displayed while taking\na backup.<div class=seealso-inline><p><em>See also: <span><a href=#subsec:backup-restore-backup-options>Backup\noptions</a></span></em></div></section><section id=backup-apps-with-android-keystore class=level4 data-number=2.6.7.3><h4 data-number=2.6.7.3><span class=header-section-number>2.6.7.3</span> Backup apps with Android\nKeyStore<a href=#backup-apps-with-android-keystore class=anchor aria-hidden=true></a></h4><p>Allow backup of applications that has entries in the Android\nKeyStore. This option is disabled by default because a few apps (such as\nSignal or Element) may crash if restored.</section><section id=subsubsec:settings-encryption class=level4 data-number=2.6.7.4><h4 data-number=2.6.7.4><span class=header-section-number>2.6.7.4</span> Encryption<a href=#subsubsec:settings-encryption class=anchor aria-hidden=true></a></h4><p>Set an encryption method for the backups. App Manager currently\nsupports OpenPGP (via <a href=https://f-droid.org/packages/org.sufficientlysecure.keychain/>OpenKeyChain</a>),\nAES, RSA and ECC. Like <a href=#subsec:apk-signing>APK signing</a>,\nThe AES, RSA and ECC keys are stored in the KeyStore and can be imported\nfrom other KeyStores.<div class=\"amalert danger\"><p><strong><em>Danger.</em></strong><p>For your own safety, it is not recommended generating RSA and ECC\nkeys inside App Manager. Instead, they should be imported from a\nKeyStore stored in a secure place.<br>In case of AES, the generated key should be stored in a secure place,\nsuch as in a password manager.</div></section><section id=subsubsec:backup-volume class=level4 data-number=2.6.7.5><h4 data-number=2.6.7.5><span class=header-section-number>2.6.7.5</span> Backup Volume<a href=#subsubsec:backup-volume class=anchor aria-hidden=true></a></h4><p>Select the storage where the backups will be stored. This is also\nwhere logs and exported APK files are saved.<div class=\"amalert tip\"><p><strong><em>Notice.</em></strong><p>The backup volume only specifies the storage, not the path. Backups\nare traditionally stored in the <code>AppManager</code> folder inside\nthe storage path. But when the path is selected using Storage Access\nFramework (SAF), the selected path or directory is used directly.</div></section><section id=import-backups class=level4 data-number=2.6.7.6><h4 data-number=2.6.7.6><span class=header-section-number>2.6.7.6</span> Import Backups<a href=#import-backups class=anchor aria-hidden=true></a></h4><p>Import backups from old and discontinued projects such as Titanium\nBackup, OAndBackup, and Swift Backup (version 3.0 to 3.2). The backups\nare not deleted after importing to prevent data loss in case the\nimported backups cannot be restored properly.</section></section><section id=subsec:rules class=level3 data-number=2.6.8><h3 data-number=2.6.8><span class=header-section-number>2.6.8</span>\n<a href=#toc:subsec:rules>Rules</a><a href=#subsec:rules class=anchor aria-hidden=true></a></h3><section id=subsubsec:instant-component-blocking class=level4 data-number=2.6.8.1><h4 data-number=2.6.8.1><span class=header-section-number>2.6.8.1</span> Instant Component\nBlocking<a href=#subsubsec:instant-component-blocking class=anchor aria-hidden=true></a></h4><p>By default, blocking rules are not applied unless they are applied\nexplicitly in <a href=#sec:app-details-page>the App Details page</a>\nfor any application. After enabling this option, all (old and new) rules\nare applied immediately for all applications without explicitly enabling\nblocking for an application.<div class=seealso-inline><p><em>See also: <span><a href=#subsec:faq:what-is-instant-component-blocking>FAQ: What is\ninstant component blocking?</a></span></em></div></section><section id=importexport-blocking-rules class=level4 data-number=2.6.8.2><h4 data-number=2.6.8.2><span class=header-section-number>2.6.8.2</span> Import/Export Blocking\nRules<a href=#importexport-blocking-rules class=anchor aria-hidden=true></a></h4><p>It is possible to import or export blocking rules within App Manager\nfor all applications. The types of rules (components, app ops or\npermissions) that should be imported or exported can also be selected.\nIt is also possible to import blocking rules from <a href=https://github.com/lihenggui/blocker>Blocker</a> and <a href=https://github.com/tuyafeng/Watt>Watt</a>. If it is necessary to\nexport blocking rules for a single application, the corresponding <a href=#sec:app-details-page>App Details page</a> can be used to export\nrules, or for multiple apps, <a href=#subsec:batch-operations>batch\noperations</a> can be used.<div class=seealso-inline><p><em>See also: <span><a href=#sec:rules-specification>Rules\nSpecification</a></span></em></div><section id=export class=level5 data-number=2.6.8.2.1><h5 data-number=2.6.8.2.1><span class=header-section-number>2.6.8.2.1</span> Export<a href=#export class=anchor aria-hidden=true></a></h5><p>Export blocking rules for all applications configured within App\nManager. This may include <a href=#subsec:faq:what-are-app-components>app components</a>, app ops\nand permissions based on the options selected in the multi-choice\noptions.</section><section id=import class=level5 data-number=2.6.8.2.2><h5 data-number=2.6.8.2.2><span class=header-section-number>2.6.8.2.2</span> Import<a href=#import class=anchor aria-hidden=true></a></h5><p>Import previously exported blocking rules from App Manager. Similar\nto export, this may include <a href=#subsec:faq:what-are-app-components>app components</a>, app ops\nand permissions based on the options selected in the multi-choice\noptions.</section><section id=par:import-existing-rules class=level5 data-number=2.6.8.2.3><h5 data-number=2.6.8.2.3><span class=header-section-number>2.6.8.2.3</span> Import Existing Rules<a href=#par:import-existing-rules class=anchor aria-hidden=true></a></h5><p>Add components disabled by other applications to App Manager. App\nManager only keeps track of the components disabled within App Manager.\nIf application components are blocked or disabled by other tools or\napplications, this option can be utilised to import them. On clicking\nthis option, App Manager will find the components potentially disabled\nby other applications or tools and list only the name of the\napplications along with the number of matched components. For safety,\nall the applications are unselected by default. They have to be selected\nmanually, and the blocking has to be re-applied via App Manager.<div class=\"amalert danger\"><p><strong><em>Caution.</em></strong><p>Be careful when using this tool as there can be many false positives.\nChoose only the applications that you are certain about.</div></section><section id=import-from-watt class=level5 data-number=2.6.8.2.4><h5 data-number=2.6.8.2.4><span class=header-section-number>2.6.8.2.4</span> Import from Watt<a href=#import-from-watt class=anchor aria-hidden=true></a></h5><p>Import configuration files from <a href=https://github.com/tuyafeng/Watt>Watt</a>, each file containing\nrules for a single package and file name being the name of the package\nwith <code>.xml</code> extension.<div class=\"amalert tip\"><p><strong><em>Tip.</em></strong><p>Location of configuration files in Watt:\n<code>/sdcard/Android/data/com.tuyafeng.watt/files/ifw</code></div></section><section id=import-from-blocker class=level5 data-number=2.6.8.2.5><h5 data-number=2.6.8.2.5><span class=header-section-number>2.6.8.2.5</span> Import from Blocker<a href=#import-from-blocker class=anchor aria-hidden=true></a></h5><p>Import blocking rules from <a href=https://github.com/lihenggui/blocker>Blocker</a>, each file\ncontaining rules for a single package. These files have a\n<code>.json</code> extension.</section></section><section id=remove-all-rules class=level4 data-number=2.6.8.3><h4 data-number=2.6.8.3><span class=header-section-number>2.6.8.3</span> Remove all rules<a href=#remove-all-rules class=anchor aria-hidden=true></a></h4><p>One-click option to remove all rules configured within App Manager.\nThis will enable all blocked components, app ops will be set to their\ndefault values and permissions will be granted.</section></section><section id=subsec:advanced class=level3 data-number=2.6.9><h3 data-number=2.6.9><span class=header-section-number>2.6.9</span>\n<a href=#toc:subsec:advanced>Advanced</a><a href=#subsec:advanced class=anchor aria-hidden=true></a></h3><section id=subsubsec:selected-users class=level4 data-number=2.6.9.1><h4 data-number=2.6.9.1><span class=header-section-number>2.6.9.1</span> Selected Users<a href=#subsubsec:selected-users class=anchor aria-hidden=true></a></h4><p>This option lets you control the users App Manager should operate on.\nApp Manager operates on all users in root or ADB mode by default.</section><section id=subsubsec:saved-apk-name-format class=level4 data-number=2.6.9.2><h4 data-number=2.6.9.2><span class=header-section-number>2.6.9.2</span> Saved APK Name Format<a href=#subsubsec:saved-apk-name-format class=anchor aria-hidden=true></a></h4><p>Defines the format of the APK name to be used while saving it via\nbatch operations or through profiles. App Manager offers some special\nkeywords enclosed inside <code>%</code> (percentage) signs and available\nbelow the input box. These keywords are:<ul class=incremental><li><p><strong><code>label</code>.</strong> Denotes the name or label of\nthe application. This can be localised to the configured language\ndepending on the app.<li><p><strong><code>package_name</code>.</strong> Denotes the name of\nthe package or application ID, the unique identifier that each\napplication has.<li><p><strong><code>version</code>.</strong> Denotes the current\nversion of the application extracted from its manifest.<li><p><strong><code>version_code</code>.</strong> Denotes the current\nversion code of the application that can be used to separate two\nversions of the same application.<li><p><strong><code>min_sdk</code>.</strong> Denotes the minimum SDK\n(i.e. Android framework version) that the application can operate on.\nThis data is only available since Android 7 (Nougat).<li><p><strong><code>target_sdk</code>.</strong> Denotes the SDK that\nthis application targets. The application can operate on higher SDK but\nonly in the compatibility mode.<li><p><strong><code>datetime</code>.</strong> Denotes the time and date\nwhen the APK is exported.</ul></section><section id=subsubsec:import/export-keystore class=level4 data-number=2.6.9.3><h4 data-number=2.6.9.3><span class=header-section-number>2.6.9.3</span> Import/Export Keystore<a href=#subsubsec:import/export-keystore class=anchor aria-hidden=true></a></h4><p>Import or export the KeyStore used by App Manager. This is a Bouncy\nCastle KeyStore with <code>bks</code> extension. Therefore, other\nKeyStore such as Java KeyStore (JKS) or PKCS #12 are not supported. If a\nkey is needed to be imported from such a KeyStore, the relevant options\nshould be should as specified above.</section></section><section id=subsec:device-info class=level3 data-number=2.6.10><h3 data-number=2.6.10><span class=header-section-number>2.6.10</span> <a href=#toc:subsec:device-info>About the device</a><a href=#subsec:device-info class=anchor aria-hidden=true></a></h3><p>Display Android version, security, CPU, GPU, battery, memory, screen,\nlanguages, user info, etc.</section></section><section id=sec:scanner-page class=level2 data-number=2.7><h2 data-number=2.7><span class=header-section-number>2.7</span> <a href=#toc:sec:scanner-page>Scanner Page</a><a href=#sec:scanner-page class=anchor aria-hidden=true></a></h2><p><strong>Scanner page</strong> appears after clicking on the\n<em>scanner</em> button in the <a href=#subsec:app-info-tab>App Info\ntab</a>. External APK files can also be opened for scanning from file\nmanagers, web browsers, etc.<p>It scans for trackers and libraries, and displays the number of\ntrackers and libraries as a summary. It also displays checksums of the\nAPK file as well as the signing certificates. If VirusTotal is\nconfigured in the settings, it also attempts to retrieve reports from\nVirusTotal, or uploads the APK file if it is not in the database. It\nalso display a link to the <a href=https://beta.pithus.org>Pithus</a>\nreport provided the Internet features are enabled.<div class=\"amalert danger\"><p><strong><em>Disclaimer.</em></strong><p>App Manager only scans an application statically without prejudice.\nThe application may provide the options for opting out, or in some\ncases, certain features of the tracker may not be used at all by the\napplication (e.g. F-Droid), or some applications may simply use them as\nplaceholders to prevent the breaking of certain features (e.g. Fennec\nF-Droid). <strong>The intention of the scanner is to give you an idea\nabout what the APK might contain. It should be taken as an initial step\nfor further investigations.</strong></div><p>Clicking on the first item (i.e. number of classes) opens a new page\ncontaining a list of tracker classes for the application. All classes\ncan also be viewed by clicking on the <em>Toggle Class Listing</em>\nmenu. The SMALI or Java version of the class can be viewed by simply\nclicking on an item.<div class=\"amalert tip\"><p><strong><em>Notice.</em></strong><p>Due to various limitations, it is not possible to scan all the\ncomponents of an APK file. This is especially true if an APK is highly\nobfuscated or packed. The scanner also does not check strings (or\nwebsite signatures).</div><p>The second item lists the number of trackers along with their names.\nClicking on the item displays a dialog containing the name of trackers,\nmatched signatures, and the number of classes against each signature.\nSome tracker names may have <span class=\"math inline\"><sup>2</sup></span> prefix which indicates that the\ntrackers are in the <a href=https://etip.exodus-privacy.eu.org>ETIP</a> stand-by list, i.e.,\nwhether they are actual trackers is still being investigated.<p>The third item lists the number of libraries along with their names.\nThe information are mostly taken from <a href=https://gitlab.com/IzzyOnDroid/repo>IzzyOnDroid repo</a>.<div class=seealso-inline><p><em>See also: <span><a href=#subsec:tracker-classes-versus-tracker-components>FAQ: Tracker\nclasses vs tracker components</a></span></em></div></section><section id=sec:interceptor-page class=level2 data-number=2.8><h2 data-number=2.8><span class=header-section-number>2.8</span> <a href=#toc:sec:interceptor-page>Interceptor Page</a><a href=#sec:interceptor-page class=anchor aria-hidden=true></a></h2><p>Interceptor can be used to intercept communication between\napplications using <code>Intent</code>. It works as a man-in-the-middle\nbetween the source and the destination applications. It offers a\nfeature-complete user interface for editing <code>Intent</code>s.<div class=\"amalert warning\"><p><strong><em>Warning.</em></strong><p>Interceptor only works for <em>implicit</em> intents where the <a href=#subsec:faq:what-are-app-components>app component</a> isn’t\nspecified.</div><div class=seealso><p><em>See also:</em><ul class=incremental><li><p><a href=https://developer.android.com/guide/components/intents-common>Common\nIntents</a><li><p><a href=https://developer.android.com/guide/components/intents-filters>Intents\nand Intent Filters</a></ul></div><section id=subsec:intent-filters class=level3 data-number=2.8.1><h3 data-number=2.8.1><span class=header-section-number>2.8.1</span>\n<a href=#toc:subsec:intent-filters>Intent Filters</a><a href=#subsec:intent-filters class=anchor aria-hidden=true></a></h3><p>Intent filters are used by the applications to specify the tasks they\nare able to perform or the tasks they are going to perform using other\napplications. For example, when you’re opening a PDF file using a file\nmanager, the file manager will try to find the applications to open the\nPDF with. To find the right applications, the file manager will create\nan Intent with filters such as the MIME type and ask the system to\nretrieve the applications capable of opening this filter. The system\nwill search through the Manifest of the installed applications to match\nthe filter and list the application components that are able to open\nthis filter (in our case the PDF). At this, either the file manager will\nopen the desired application component all by itself or use a system\nprovided option to open it. If multiple application components are able\nto open it and no default is set, you may get a prompt where you have to\nchoose the right application component.<section id=subsubsec:action class=level4 data-number=2.8.1.1><h4 data-number=2.8.1.1><span class=header-section-number>2.8.1.1</span> Action<a href=#subsubsec:action class=anchor aria-hidden=true></a></h4><p>Action specifies the generic action to perform such as\n<code>android.intent.action.VIEW</code>. Applications often declare the\nrelevant actions in the Manifest file to catch the desired Intents. The\naction is particularly useful for broadcast Intent where it plays a\nvital rule. In other cases, it works as an initial way to filter out the\nrelevant application components. Generic actions such as\n<code>android.intent.action.VIEW</code> and\n<code>android.intent.action.SEND</code> are widely used by applications.\nHence, setting this alone may match many application components.</section><section id=subsubsec:data class=level4 data-number=2.8.1.2><h4 data-number=2.8.1.2><span class=header-section-number>2.8.1.2</span> Data<a href=#subsubsec:data class=anchor aria-hidden=true></a></h4><p>Data is originally known as URI (Uniform Resource Identifier) defined\nin <a href=http://www.faqs.org/rfcs/rfc2396.html>RFC 2396</a>. It can\nbe web links, file location, or a special feature called\n<em>content</em>. Contents are an Android feature managed by the <a href=#subsubsec:providers>content providers</a>. Data are often\nassociated with a <a href=#subsubsec:mime-type>MIME type</a>.<p>Examples:<pre><code>http://search.disroot.org/?q=URI%20in%20Android%20scheme&amp;categories=general&amp;language=en-US\nhttps://developer.android.com/reference/android/net/Uri\nfile:///sdcard/AppManager.apk\nmailto:email@example.com\ncontent://io.github.muntashirakon.AppManager.provider/23485af89b08d87e898a90c7e/AppManager.apk</code></pre></section><section id=subsubsec:mime-type class=level4 data-number=2.8.1.3><h4 data-number=2.8.1.3><span class=header-section-number>2.8.1.3</span> MIME Type<a href=#subsubsec:mime-type class=anchor aria-hidden=true></a></h4><p>MIME type of the <a href=#subsubsec:data>data</a>. For example, if\nthe data field is set to <code>file:///sdcard/AppManager.apk</code>, the\nassociated MIME type can be\n<code>application/vnd.android.package-archive</code>.</section><section id=categories class=level4 data-number=2.8.1.4><h4 data-number=2.8.1.4><span class=header-section-number>2.8.1.4</span> Categories<a href=#categories class=anchor aria-hidden=true></a></h4><p>This is similar to <a href=#subsubsec:action>action</a> in the\nsense that it is also used by the system to filter application\ncomponents. This has no further benefits. Unlike <em>action</em>, there\ncan be more than one category. Clicking on the <em>plus</em> button next\nto the title allows adding more categories.</section><section id=flags class=level4 data-number=2.8.1.5><h4 data-number=2.8.1.5><span class=header-section-number>2.8.1.5</span> Flags<a href=#flags class=anchor aria-hidden=true></a></h4><p>Flags are useful in determining how system should behave during the\nlaunch or after the launch of an activity. This should not be touched as\nit requires some technical background. The <em>plus</em> button next to\nthe title can be used to add one or more flags.</section><section id=extras class=level4 data-number=2.8.1.6><h4 data-number=2.8.1.6><span class=header-section-number>2.8.1.6</span> Extras<a href=#extras class=anchor aria-hidden=true></a></h4><p>Extras are the key-value pairs used for supplying additional\ninformation to the destination component. More extras can be added using\nthe <em>plus</em> button next to the title.</section><section id=uri class=level4 data-number=2.8.1.7><h4 data-number=2.8.1.7><span class=header-section-number>2.8.1.7</span> URI<a href=#uri class=anchor aria-hidden=true></a></h4><p>Represents the entire Intent as a URI (e.g. <code>intent://…</code>).\nSome data cannot be converted to string, and as a result, they might not\nappear here.</section></section><section id=subsec:matching-activities class=level3 data-number=2.8.2><h3 data-number=2.8.2><span class=header-section-number>2.8.2</span>\n<a href=#toc:subsec:matching-activities>Matching Activities</a><a href=#subsec:matching-activities class=anchor aria-hidden=true></a></h3><p>List all the activity components that matches the Intent. This is\ninternally determined by the system (rather than App Manager). The\nlaunch button next to each component can be used to launch them directly\nfrom App Manager.</section><section id=subsec:interceptor-reset-to-default class=level3 data-number=2.8.3><h3 data-number=2.8.3><span class=header-section-number>2.8.3</span>\n<a href=#toc:subsec:interceptor-reset-to-default>Reset to\nDefault</a><a href=#subsec:interceptor-reset-to-default class=anchor aria-hidden=true></a></h3><p>Reset the Intent to its initial state.</section><section id=subsec:interceptor-send-edited-intent class=level3 data-number=2.8.4><h3 data-number=2.8.4><span class=header-section-number>2.8.4</span>\n<a href=#toc:subsec:interceptor-send-edited-intent>Send Edited\nIntent</a><a href=#subsec:interceptor-send-edited-intent class=anchor aria-hidden=true></a></h3><p>Resend the edited Intent to the destination application. This may\nopen a list of applications where the desired application is needed to\nbe selected. The result received from the target application will be\nsent to the source application. As a result, the source application will\nnot know if there was a man-in-the-middle.</section></section><section id=sec:shared-preferences-editor-page class=level2 data-number=2.9><h2 data-number=2.9><span class=header-section-number>2.9</span> <a href=#toc:sec:shared-preferences-editor-page>Shared Preferences Editor\nPage</a><a href=#sec:shared-preferences-editor-page class=anchor aria-hidden=true></a></h2><p>Shared preferences can be edited in this page. Clicking any item on\nthe list opens the edit dialog where the item can be edited. The\nfloating action button in the bottom-right corner can be used to add a\nnew item. To save or delete the file, or to discard current changes, the\nrespective options in the menu can be used.</section></section><section id=ch:guides class=level1 data-number=3><h1 data-number=3><span class=header-section-number>3</span> <a href=#toc:ch:guides>Guides</a><a href=#ch:guides class=anchor aria-hidden=true></a></h1><section id=sec:adb-over-tcp class=level2 data-number=3.1><h2 data-number=3.1><span class=header-section-number>3.1</span> <a href=#toc:sec:adb-over-tcp>ADB over TCP</a><a href=#sec:adb-over-tcp class=anchor aria-hidden=true></a></h2><p>Many root-only features can still be used by enabling ADB over TCP.\nTo do that, a PC or Mac is required with Android platform-tools\ninstalled, and an Android phone with developer options & USB\ndebugging enabled.<div class=\"amalert tip\"><p><strong><em>Root users.</em></strong><p>If superuser permission has been granted to App Manager, it can\nalready execute privileged code without any problem. <strong>Therefore,\nroot users do not need to enable ADB over TCP.</strong> But if you\ninsist on using ADB over TCP, you must revoke superuser permission for\nApp Manager.</div><div class=seealso-inline><p><em>See also: <span><a href=#sec:faq:adb-over-tcp>FAQ: ADB over\nTCP</a></span></em></div><section id=subsec:enable-developer-options class=level3 data-number=3.1.1><h3 data-number=3.1.1><span class=header-section-number>3.1.1</span>\n<a href=#toc:subsec:enable-developer-options>Enable developer\noptions</a><a href=#subsec:enable-developer-options class=anchor aria-hidden=true></a></h3><section id=subsubsec:location-of-developer-options class=level4 data-number=3.1.1.1><h4 data-number=3.1.1.1><span class=header-section-number>3.1.1.1</span> Location of developer\noptions<a href=#subsubsec:location-of-developer-options class=anchor aria-hidden=true></a></h4><p><strong>Developer options</strong> is located in Android\n<strong>Settings</strong>, either directly near the bottom of the page\n(in most ROMs) or under some other settings, such as\n<strong>System</strong> (Google Pixel, Lineage OS, Asus Zenfone 8.0+),\n<strong>Additional Settings</strong> (Xiaomi MIUI, Oppo ColorOS),\n<strong>More Settings</strong> (Vivo FuntouchOS), <strong>More</strong>\n(ZTE Nubia). Unlike other options, it is not visible until explicitly\nenabled by the user. If it is already enabled, you can use the search\nbox in Android <strong>Settings</strong> to locate it as well.</section><section id=how-to-enable-developer-options class=level4 data-number=3.1.1.2><h4 data-number=3.1.1.2><span class=header-section-number>3.1.1.2</span> How to enable developer\noptions<a href=#how-to-enable-developer-options class=anchor aria-hidden=true></a></h4><p>This option is available within Android <strong>Settings</strong> as\nwell but like the location of the developer options, it also differs\nfrom device to device. But in general, you have to find <strong>Build\nnumber</strong> (or <strong>MIUI version</strong> for MIUI ROMs and\n<strong>Software version</strong> for Vivo FuntouchOS,\n<strong>Version</strong> for Oppo ColorOS) and tap it at least 7 (seven)\ntimes until you finally get a message saying <em>You are now a\ndeveloper</em> (you may be prompted to insert pin/password/pattern or\nsolve captchas at this point). In most devices, it is located at the\nbottom of the settings page, inside <strong>About Phone</strong>. But\nthe best way to find it is to use the search box.</section></section><section id=subsec:enable-usb-debugging class=level3 data-number=3.1.2><h3 data-number=3.1.2><span class=header-section-number>3.1.2</span>\n<a href=#toc:subsec:enable-usb-debugging>Enable USB debugging</a><a href=#subsec:enable-usb-debugging class=anchor aria-hidden=true></a></h3><p>After <a href=#subsubsec:location-of-developer-options>locating the\ndeveloper options</a>, enable <strong>Developer option</strong> (if not\nalready). After that, scroll down a bit until you will find the option\n<strong>USB debugging</strong>. Use the toggle button on the right-hand\nside to enable it. At this point, you may get an alert prompt where you\nmay have to click <em>OK</em> to actually enable it. You may also have\nto enable some other options depending on device vendor and ROM. Here\nare some examples:<section id=xiaomi-miui class=level4 data-number=3.1.2.1><h4 data-number=3.1.2.1><span class=header-section-number>3.1.2.1</span> Xiaomi (MIUI)<a href=#xiaomi-miui class=anchor aria-hidden=true></a></h4><p>Enable <strong>USB debugging (Security settings)</strong> as\nwell.</section><section id=huawei-emui class=level4 data-number=3.1.2.2><h4 data-number=3.1.2.2><span class=header-section-number>3.1.2.2</span> Huawei (EMUI)<a href=#huawei-emui class=anchor aria-hidden=true></a></h4><p>Enable <strong>Allow ADB debugging in charge only mode</strong> as\nwell. When connecting to your PC or Mac, you may get a prompt saying\n<strong>Allow access to device data?</strong> in which case click\n<strong>YES, ALLOW ACCESS</strong>.<div class=\"amalert tip\"><p><strong><em>Notice.</em></strong><p>Often the <strong>USB debugging</strong> mode could be disabled\nautomatically by the system. If that’s the case, repeat the above\nprocedure.</div></section><section id=realme class=level4 data-number=3.1.2.3><h4 data-number=3.1.2.3><span class=header-section-number>3.1.2.3</span> Realme<a href=#realme class=anchor aria-hidden=true></a></h4><p>Depending on the device and the version of operating system, you have\nto enable <strong>Disable Permission Monitoring</strong>, or <strong>USB\ndebugging (Security settings)</strong> along with <strong>Install via\nUSB</strong>.</section><section id=oneplus-oxygen-os class=level4 data-number=3.1.2.4><h4 data-number=3.1.2.4><span class=header-section-number>3.1.2.4</span> OnePlus (Oxygen OS)<a href=#oneplus-oxygen-os class=anchor aria-hidden=true></a></h4><p>Depending on the device and the version of operating system, you have\nto enable <strong>Disable Permission Monitoring</strong>.</section><section id=lg class=level4 data-number=3.1.2.5><h4 data-number=3.1.2.5><span class=header-section-number>3.1.2.5</span> LG<a href=#lg class=anchor aria-hidden=true></a></h4><p>Make sure you have <strong>USB tethering</strong> enabled.</section><section id=troubleshooting class=level4 data-number=3.1.2.6><h4 data-number=3.1.2.6><span class=header-section-number>3.1.2.6</span> Troubleshooting<a href=#troubleshooting class=anchor aria-hidden=true></a></h4><p>In case <strong>USB Debugging</strong> is greyed out, you can do the\nfollowing:<ol class=incremental><li><p>Make sure you enabled USB debugging before connecting your phone\nto the PC or Mac via USB cable<li><p>Enable USB tethering after connecting to PC or Mac via USB\ncable<li><p>(For Samsung) If your device is running KNOX, you may have to\nfollow some additional steps. See official documentations or consult\nsupport for further assistant</ol></section></section><section id=subsec:setup-adb-on-pc-or-mac class=level3 data-number=3.1.3><h3 data-number=3.1.3><span class=header-section-number>3.1.3</span>\n<a href=#toc:subsec:setup-adb-on-pc-or-mac>Setup ADB on PC or\nMac</a><a href=#subsec:setup-adb-on-pc-or-mac class=anchor aria-hidden=true></a></h3><p>In order to enable ADB over TCP, you have to set up ADB in your PC or\nMac. <strong><em>Lineage OS users can skip to §<a href=#subsubsec:lineage-os data-reference-type=ref data-reference=subsubsec:lineage-os>3.1.4.1</a>.</em></strong><section id=windows class=level4 data-number=3.1.3.1><h4 data-number=3.1.3.1><span class=header-section-number>3.1.3.1</span> Windows<a href=#windows class=anchor aria-hidden=true></a></h4><ol class=incremental><li><p>Download the latest version of <a href=https://dl.google.com/android/repository/platform-tools-latest-windows.zip>Android\nSDK Platform-Tools</a> for Windows<li><p>Extract the contents of the zip file into any directory (such as\n<code>C:\\</code><span><code>adb</code></span>) and navigate to that\ndirectory using <em>Explorer</em><li><p>Open <strong>Command Prompt</strong>,\n<strong>PowerShell</strong>, or <strong>Terminal</strong> from this\ndirectory. You can do it manually from the start menu or by holding\n<code>Shift</code> and right clicking within the directory in <em>File\nExplorer</em> and then clicking either on <em>Open command window\nhere</em>, or <em>Open PowerShell window here</em> (depending on what\nyou have installed). You can now access ADB by typing <code>adb</code>\n(Command Prompt) or <code>./adb</code> (PowerShell). Do not close this\nwindow yet.</ol><div class=\"amalert tip\"><p><strong><em>Tip.</em></strong><p>If you have <a href=https://learn.microsoft.com/en-us/windows/package-manager/winget/>WinGet</a>\ninstalled, you can install ADB using the following command:<div class=sourceCode id=cb3 data-frame=lines><pre class=\"sourceCode bash\"><code class=\"sourceCode bash\"><span id=cb3-1><a href=#cb3-1 aria-hidden=true tabindex=-1></a><span class=ex>winget</span> install <span class=at>--id</span> Google.PlatformTools</span></code></pre></div><p>After that, you can simply type <code>adb</code> to access ADB.</div></section><section id=macos class=level4 data-number=3.1.3.2><h4 data-number=3.1.3.2><span class=header-section-number>3.1.3.2</span> macOS<a href=#macos class=anchor aria-hidden=true></a></h4><ol class=incremental><li><p>Download the latest version of <a href=https://dl.google.com/android/repository/platform-tools-latest-darwin.zip>Android\nSDK Platform-Tools</a> for macOS<li><p>Extract the contents of the zip file into a directory by clicking\non it. After that, navigate to that directory using <em>Finder</em> and\nlocate <code>adb</code><li><p>Open <strong>Terminal</strong> using <em>Launchpad</em> or\n<em>Spotlight</em> and drag-and-drop <code>adb</code> from the\n<em>Finder</em> window into the <em>Terminal</em> window. Do not close\nthe <em>Terminal</em> window yet</ol><div class=\"amalert tip\"><p><strong><em>Tip.</em></strong><p>If you have <a href=https://brew.sh>Homebrew</a> installed, you can\ninstall ADB using the following command:<div class=sourceCode id=cb4 data-frame=lines><pre class=\"sourceCode bash\"><code class=\"sourceCode bash\"><span id=cb4-1><a href=#cb4-1 aria-hidden=true tabindex=-1></a><span class=ex>brew</span> install <span class=at>--cask</span> android-platform-tools</span></code></pre></div><p>After that, you can simply type <code>adb</code> in any\n<em>Terminal</em> window to access ADB.</div></section><section id=linux class=level4 data-number=3.1.3.3><h4 data-number=3.1.3.3><span class=header-section-number>3.1.3.3</span> Linux<a href=#linux class=anchor aria-hidden=true></a></h4><ol class=incremental><li><p>In your favourite terminal emulator, run the following\ncommand:<div class=sourceCode id=cb5 data-frame=lines data-autogobble><pre class=\"sourceCode bash\"><code class=\"sourceCode bash\"><span id=cb5-1><a href=#cb5-1 aria-hidden=true tabindex=-1></a><span class=bu>cd</span> ~/Downloads <span class=kw>&amp;&amp;</span> <span class=ex>curl</span> <span class=at>-o</span> platform-tools.zip <span class=at>-L</span> <span class=dt>\\</span></span>\n<span id=cb5-2><a href=#cb5-2 aria-hidden=true tabindex=-1></a>https://dl.google.com/android/repository/platform-tools-latest-linux.zip <span class=kw>&amp;&amp;</span> <span class=dt>\\</span></span>\n<span id=cb5-3><a href=#cb5-3 aria-hidden=true tabindex=-1></a><span class=fu>unzip</span> platform-tools.zip <span class=kw>&amp;&amp;</span> <span class=fu>rm</span> platform-tools.zip <span class=kw>&amp;&amp;</span> <span class=bu>cd</span> platform-tools</span></code></pre></div><li><p>If it is successful, you can simply type <code>./adb</code> in\nthe in <em>same</em> terminal emulator window or type\n<code>~/Downloads/platform-tools/adb</code> in any terminal emulator to\naccess ADB.</ol></section></section><section id=subsec:configure-adb-over-tcp class=level3 data-number=3.1.4><h3 data-number=3.1.4><span class=header-section-number>3.1.4</span>\n<a href=#toc:subsec:configure-adb-over-tcp>Configure ADB over\nTCP</a><a href=#subsec:configure-adb-over-tcp class=anchor aria-hidden=true></a></h3><section id=subsubsec:lineage-os class=level4 data-number=3.1.4.1><h4 data-number=3.1.4.1><span class=header-section-number>3.1.4.1</span> Lineage OS 17.1 and\nEarlier<a href=#subsubsec:lineage-os class=anchor aria-hidden=true></a></h4><p>Lineage OS (or its derivatives) users can directly enable ADB over\nTCP using the developer options. To enable that, go to the\n<strong>Developer options</strong>, scroll down until you find\n<strong>ADB over Network</strong>. Now, use the toggle button on the\nright-hand side to enable it and skip to §<a href=#subsubsec:adb-mode-in-app-manager data-reference-type=ref data-reference=subsubsec:adb-mode-in-app-manager>3.1.4.3</a>.<div class=\"amalert warning\"><p><strong><em>Warning.</em></strong><p>You can turn off <strong>ADB over Network</strong> in developer\noptions, but turning off this option will also stop App Manager’s remote\nserver. So, turn it off only when you’re not going to use App Manager in\nADB over TCP mode.</div></section><section id=subsubsec:enable-adb-over-tcp-via-pc-or-mac class=level4 data-number=3.1.4.2><h4 data-number=3.1.4.2><span class=header-section-number>3.1.4.2</span> Enable ADB over TCP via PC\nor Mac<a href=#subsubsec:enable-adb-over-tcp-via-pc-or-mac class=anchor aria-hidden=true></a></h4><p>For other ROMs, you can do this using the command\nprompt/PowerShell/terminal emulator that you’ve opened in the step 3 of\nthe previous section. In this section, I will use <code>adb</code> to\ndenote <code>./adb</code>, <code>adb</code> or any other command that\nyou needed to use based on your platform and software in the previous\nsection.<ol class=incremental><li><p>Connect your device to your PC or Mac using a USB cable. For some\ndevices, it is necessary to turn on <em>File transfer mode (MTP)</em> as\nwell<li><p>To confirm that everything is working as expected, type\n<code>adb devices</code> in your terminal. If your device is connected\nsuccessfully, you will see something like this:<pre><code>List of devices attached\nxxxxxxxx  device</code></pre><div class=\"amalert tip\"><p><strong><em>Notice.</em></strong><p>In some Android phones, an alert prompt will be appeared with a\nmessage <strong>Allow USB Debugging</strong> in which case, check\n<em>Always allow from this computer</em> and click\n<strong>Allow</strong>.</div><li><p>Finally, run the following command to enable ADB over TCP:<div class=sourceCode id=cb7 data-frame=lines data-autogobble><pre class=\"sourceCode bash\"><code class=\"sourceCode bash\"><span id=cb7-1><a href=#cb7-1 aria-hidden=true tabindex=-1></a><span class=ex>adb</span> tcpip 5555</span></code></pre></div></ol><div class=\"amalert danger\"><p><strong><em>Danger.</em></strong><p>You cannot disable developer options or USB debugging after enabling\nADB over TCP.</div></section><section id=subsubsec:adb-mode-in-app-manager class=level4 data-number=3.1.4.3><h4 data-number=3.1.4.3><span class=header-section-number>3.1.4.3</span> Enable ADB mode in App\nManager<a href=#subsubsec:adb-mode-in-app-manager class=anchor aria-hidden=true></a></h4><p>After enabling ADB over TCP, relaunch App Manager. App Manager should\ndetect ADB mode automatically. If it cannot, you can change the mode of\noperation to ADB over TCP in the <a href=#subsec:mode-of-operation>settings page</a>. There, you can also\nverify whether App Manager has correctly detected ADB as indicated by\nthe <em>inferred mode</em>.<div class=\"amalert tip\"><p><strong><em>Notice.</em></strong><p>In some Android devices, the USB cable is needed to be disconnected\nfrom the PC before connecting to App Manager.</div><div class=\"amalert warning\"><p><strong><em>Warning.</em></strong><p>ADB over TCP will be disabled after a reboot. In that case, you have\nto follow §<a href=#subsubsec:enable-adb-over-tcp-via-pc-or-mac data-reference-type=ref data-reference=subsubsec:enable-adb-over-tcp-via-pc-or-mac>3.1.4.2</a>\nagain.</div></section></section></section><section id=sec:wireless-debugging class=level2 data-number=3.2><h2 data-number=3.2><span class=header-section-number>3.2</span> <a href=#toc:sec:wireless-debugging>Wireless Debugging</a><a href=#sec:wireless-debugging class=anchor aria-hidden=true></a></h2><p>If you are running Android 11 or later and capable of connecting to a\nWi-Fi network for, at least, a few moments, Wireless Debugging is the\nrecommended approach as it offers more protection than <a href=#sec:adb-over-tcp>ADB over TCP</a>. It requires two steps:<ol class=incremental><li><p><strong>ADB pairing.</strong> The initial and a bit complex step\nfor a novice user. Fortunately, this step is not required all the\ntime.<li><p><strong>Connecting to ADB.</strong> Needs to be done every time\nyou reboot your phone. App Manager can also automate this step in most\ndevices.</ol><section id=subsec:enable-developer-options-and-usb-debugging class=level3 data-number=3.2.1><h3 data-number=3.2.1><span class=header-section-number>3.2.1</span>\n<a href=#toc:subsec:enable-developer-options-and-usb-debugging>Enable\ndeveloper options and USB Debugging</a><a href=#subsec:enable-developer-options-and-usb-debugging class=anchor aria-hidden=true></a></h3><p>See §<a href=#subsec:enable-developer-options data-reference-type=ref data-reference=subsec:enable-developer-options>3.1.1</a> and §<a href=#subsec:enable-usb-debugging data-reference-type=ref data-reference=subsec:enable-usb-debugging>3.1.2</a>.</section><section id=subsec:enable-wireless-debugging class=level3 data-number=3.2.2><h3 data-number=3.2.2><span class=header-section-number>3.2.2</span>\n<a href=#toc:subsec:enable-wireless-debugging>Enable Wireless\nDebugging</a><a href=#subsec:enable-wireless-debugging class=anchor aria-hidden=true></a></h3><p>In the <strong>Developer options</strong> page, find <strong>Wireless\ndebugging</strong> and click to open it. In the new page, turn on\n<em>Use wireless debugging</em>. Depending on the operating system, you\nmight see a dialog prompt asking you to verify your decision. If that is\nthe case, click <em>Allow</em>.<div class=\"amalert tip\"><p><strong><em>Tip.</em></strong><p>For easy access, you might want to add <strong>Wireless\ndebugging</strong> in the notification tiles section. To do this, find\n<strong>Quick settings developer tiles</strong> in the <strong>Developer\noptions</strong> page and click to open it. In the new window, enable\n<em>Wireless debugging</em>. In case you do not see this setting, you\nmay find a <strong>Wireless debugging</strong> tile in the tile\ncustomization panel.</div></section><section id=subsec:pair-adb-with-app-manager class=level3 data-number=3.2.3><h3 data-number=3.2.3><span class=header-section-number>3.2.3</span>\n<a href=#toc:subsec:pair-adb-with-app-manager>Pair ADB with App\nManager</a><a href=#subsec:pair-adb-with-app-manager class=anchor aria-hidden=true></a></h3><p>In App Manager, navigate to <strong>Settings</strong> > <a href=#subsec:mode-of-operation>Mode of operation</a> and then enable\n<em>Wireless debugging</em>. At this, App Manager will try to establish\na wireless debugging connection automatically which will fail if it has\nnot been paired before. Once it fails, it will ask you to either connect\nor pair ADB. Select <em>pair</em> and a new dialog will appear. It will\nask you to navigate to the <strong>Wireless debugging</strong> page.<div class=\"amalert tip\"><p><strong><em>Note.</em></strong><p>As of v4.0.0, pairing is done using a notification prompt. So, if you\nhave disabled notification for App Manager, you must enable it\nfirst.</div><p>In the <strong>Wireless debugging</strong> page, select <strong>Pair\ndevice with pairing code</strong>. At this, a dialog containing a\npairing code will be displayed. A notification asking for the pairing\ncode will also be visible almost instantly. Insert the pairing code in\nthe input box in the notification and click <em>pair</em>. If the\npairing is successful, App Manager will display notification with the\nmessage “paired”, and the dialog in the <strong>Wireless\ndebugging</strong> page will be dismissed automatically. You will also\nbe able to see App Manager listed as an ADB client in the same page.<div class=\"amalert tip\"><p><strong><em>Notice.</em></strong><p>If you do not use App Manager in ADB mode for a while, App Manager\nmight be removed from the list of clients. In that case, you have to\nrepeat the above procedure.</div></section><section id=subsec:connect-app-manager-to-adb class=level3 data-number=3.2.4><h3 data-number=3.2.4><span class=header-section-number>3.2.4</span>\n<a href=#toc:subsec:connect-app-manager-to-adb>Connect App Manager to\nADB</a><a href=#subsec:connect-app-manager-to-adb class=anchor aria-hidden=true></a></h3><p>App Manager should be able to connect to ADB automatically if the\nmode of operation is set to <em>auto</em>, <em>ADB over TCP</em> or\n<em>Wireless debugging</em>. If this is not the case, select\n<em>Wireless debugging</em> in <strong>Settings</strong> > <a href=#subsec:mode-of-operation>Mode of operation</a>. If App Manager\nfails to detect or connect to ADB, it will ask you to connect or pair\nADB. Select <em>connect</em>.<p>Now, navigate to the <strong>Wireless debugging</strong> page in\nAndroid settings, and note down the port number displayed in the page.\nIn App Manager’s dialog prompt, replace the port number with the one you\nhave noted earlier, and click <em>connect</em>.<p>Once a connection has been established, you can disable\n<strong>Wireless debugging</strong> in Android settings.<div class=\"amalert danger\"><p><strong><em>Caution.</em></strong><p>Never disable <strong>USB Debugging</strong> or any other additional\noptions described in §<a href=#subsec:enable-developer-options-and-usb-debugging data-reference-type=ref data-reference=subsec:enable-developer-options-and-usb-debugging>3.2.1</a>.\nIf you do this, the remote server used by App Manager will be stopped,\nand you may have to start all over again.</div></section></section><section id=sec:backup-restore class=level2 data-number=3.3><h2 data-number=3.3><span class=header-section-number>3.3</span> <a href=#toc:sec:backup-restore>Back up/Restore</a><a href=#sec:backup-restore class=anchor aria-hidden=true></a></h2><p>App Manager has a modern, advanced and easy-to-use backup/restore\nsystem implemented from the scratch. This is probably the only app that\nhas the ability to restore not only the app or its data but also\npermissions and rules that you’ve configured within App Manager. You can\nalso choose to back up an app multiple times (with custom names) or for\nall users.<div class=seealso><p><em>See also:</em><ul class=incremental><li><p><a href=#subsec:1-click-back-up>1-Click Ops: Back\nup</a><li><p><a href=#subsec:1-click-restore>1-Click Ops:\nRestore</a></ul></div><section id=subsec:backup-location class=level3 data-number=3.3.1><h3 data-number=3.3.1><span class=header-section-number>3.3.1</span>\n<a href=#toc:subsec:backup-location>Location</a><a href=#subsec:backup-location class=anchor aria-hidden=true></a></h3><p>Back up/restore is a part of <a href=#subsec:batch-operations>batch\noperations</a>. It is also located inside the <a href=#subsubsec:app-info-options-menu>options menu</a> in the <a href=#subsec:app-info-tab>App Info tab</a>. Clicking on\n<strong>Backup/Restore</strong> opens the <strong>Backup\nOptions</strong>. Backups are located at\n<code>/storage/emulated/0/AppManager</code> by default. You can\nconfigure custom backup location in the <a href=#subsubsec:backup-volume>settings page</a> in which case the\nbackups will be located at the <code>AppManager</code> folder in the\nselected volume.<div class=\"amalert tip\"><p><strong><em>Note.</em></strong><p>If one or more selected apps do not have any backup, the\n<strong>Restore</strong> and <strong>Delete Backup</strong> options will\nnot be displayed.</div></section><section id=subsec:backup-restore-backup-options class=level3 data-number=3.3.2><h3 data-number=3.3.2><span class=header-section-number>3.3.2</span>\n<a href=#toc:subsec:backup-restore-backup-options>Backup Options</a><a href=#subsec:backup-restore-backup-options class=anchor aria-hidden=true></a></h3><p>Backup options (internally known as backup flags) let you customise\nthe backups on the fly. However, the customisations will not be\nremembered for the future backups. If you want to customise this dialog,\nuse <a href=#subsubsec:settings-backup-options>Backup Options</a> in\nthe <a href=#sec:settings-page>Settings page</a>.<p>A complete description of the backup options is given below:<ul class=incremental><li><p><strong>APK files.</strong> Whether to back up the APK files.\nThis includes the <em>base APK</em> file along with the\n<code>split APK</code> files if they exist.<li><p><strong>Internal data.</strong> Whether to back up the internal\ndata directories. These directories are located at\n<code>/data/user/&lt;user_id></code> and (for Android N or later)\n<code>/data/user_de/&lt;user_id></code>.<li><p><strong>External data.</strong> Whether to back up data\ndirectories located in the internal memory as well as SD Card (if\nexists). External data directories often contain non-essential app data\nor media files (instead of using the dedicated media folder) and may\nincrease the backup size. However, it might be essential for some apps.\nAlthough it isn’t checked by default (as it might dramatically increase\nthe size of the backups), you may have to check it in order to ensure a\nsmooth restore of your backups.<div class=\"amalert warning\"><p><strong><em>Caution.</em></strong><p>Internal data folders should always be backed up if you are going to\nback up the external data folders. However, it could be useful to back\nup only the external folders if the app in question downloads a lot of\nassets from the Internet.</div><li><p><strong>OBB and media.</strong> Whether to back up or restore the\nOBB and the media directories located in the external storage or the SD\nCard. This is useful for games and the graphical software which actually\nuse these folders.<li><p><strong>Cache.</strong> Android apps have multiple cache\ndirectories located at every data directories (both internal and\nexternal). There are two types of cache: <strong>cache</strong> and\n<strong>code cache</strong>. Disabling this option excludes both cache\ndirectories from all the data directories. It is generally advised to\nexclude cache directories since most apps do not clear the cache\nregularly and usually handled by the OS itself. Apps such as Telegram\nmay use a very large cache (depending on the storage space) which may\ndramatically increase the backup size. When it is disabled, AM also\nignores the <strong>no_backup</strong> directories.<li><p><strong>Extras.</strong> Backup/restore app permissions, net\npolicy, battery optimization, SSAID, etc., enabled by default. Note\nthat, blocking rules are applied <em>after</em> applying the extras. So,\nif an item is present in both places, it will be overwritten (i.e., the\none from the blocking rules will be used).<li><p><strong>Rules.</strong> This option lets you back up blocking\nrules configured within App Manager. This might come in handy if you\nhave customised permissions or block some components using App Manager\nas they will also be backed up or restored when you enable this\noption.<li><p><strong>Backup Multiple.</strong> Whether this is a multiple\nbackup. By default, backups are saved using their user ID. Enabling this\noption allows you to create additional backups. These backups use the\ncurrent date-time as the default backup name, but you can also specify\ncustom backup name using the input field displayed when you click on the\n<strong>Backup</strong> button.<li><p><strong>Custom users.</strong> Backup or restore for the selected\nusers instead of only the current user. This option is only displayed if\nthe system has more than one user.<li><p><strong>Skip signature checks.</strong> When taking a backup,\nchecksum of every file (as well as the signing certificate(s) of the\nbase APK file) is generated and stored in the <code>checksums.txt</code>\nfile. When you restore the backup, the checksums are generated again and\nare matched with the checksums stored in the said file. Enabling this\noption will disable the signature checks. This option is applied only\nwhen you restore a backup. During backup, the checksums are generated\nregardless of this option.<div class=\"amalert warning\"><p><strong><em>Caution.</em></strong><p>You should always disable this option to ensure that your backups are\nnot modified by any third-party applications. However, this would only\nwork if you enabled encryption.</div></ul><div class=seealso-inline><p><em>See also: <span><a href=#subsubsec:settings-encryption>Settings:\nEncryption</a></span></em></div></section><section id=subsec:backup-restore-backup class=level3 data-number=3.3.3><h3 data-number=3.3.3><span class=header-section-number>3.3.3</span>\n<a href=#toc:subsec:backup-restore-backup>Backup</a><a href=#subsec:backup-restore-backup class=anchor aria-hidden=true></a></h3><p>Backup respects all the backup options except <strong>Skip signature\nchecks</strong>. If base backups (i.e., backups that don’t have the\n<strong>Backup Multiple</strong> option) already exist, you will get a\nwarning as the backups will be overwritten. If <strong>Backup\nMultiple</strong> is set, you have an option to input the backup name,\nor you can leave it blank to use the current date-time.</section><section id=subsec:backup-restore-restore class=level3 data-number=3.3.4><h3 data-number=3.3.4><span class=header-section-number>3.3.4</span>\n<a href=#toc:subsec:backup-restore-restore>Restore</a><a href=#subsec:backup-restore-restore class=anchor aria-hidden=true></a></h3><p>Restore respects all the backup options and will fail if <strong>APK\nfiles</strong> option is set, but the backup doesn’t contain such\nbackups or in other cases, if the app isn’t installed. When restoring\nbackups for multiple packages, you can only restore the base backups\n(see <a href=#subsec:backup-restore-backup>backup</a> section for an\nexplanation). However, when restoring backups for a single package, you\nhave the option to select which backup to restore. If <strong>All\nusers</strong> option is set, AM will restore the selected backup for\nall users in the latter case but in the former case, it will restore\nbase backups for the respective users.<div class=\"amalert tip\"><p><strong><em>Notice.</em></strong><p>Apps that use storage access framework (SAF), SSAID or Android\nKeyStore works properly only after an immediate restart.</div></section><section id=subsec:backup-restore-delete-backup class=level3 data-number=3.3.5><h3 data-number=3.3.5><span class=header-section-number>3.3.5</span>\n<a href=#toc:subsec:backup-restore-delete-backup>Delete Backup</a><a href=#subsec:backup-restore-delete-backup class=anchor aria-hidden=true></a></h3><p>Delete backup only respects <strong>All users</strong> option and\nwhen it is selected, only the base backups for all users will be deleted\nwith a prompt. When deleting backups for a single package, another\ndialog will be displayed where you can select the backups to delete.</section></section><section id=sec:automating-tasks class=level2 data-number=3.4><h2 data-number=3.4><span class=header-section-number>3.4</span> <a href=#toc:sec:automating-tasks>Automating Tasks</a><a href=#sec:automating-tasks class=anchor aria-hidden=true></a></h2><p>It is possible to trigger profiles configured inside App Manager via\nthird-party applications such as <strong>Automation</strong> or\n<strong>Tasker</strong>. Traditionally, <code>Intent</code>s are used to\ntrigger such operations.<section id=subsec:generating-authorization-key class=level3 data-number=3.4.1><h3 data-number=3.4.1><span class=header-section-number>3.4.1</span>\n<a href=#toc:subsec:generating-authorization-key>Generating\nauthorization key</a><a href=#subsec:generating-authorization-key class=anchor aria-hidden=true></a></h3><p>In order to ensure proper security, an authorization key is required.\nTo generate a authorization key, go to <strong>Settings</strong> page\nand then <strong>Privacy</strong> > <strong>Authorization\nManager</strong>. If an authorization key has not been generated, it\nwill be generated automatically. The key can be regenerated as\nrequired.<div class=\"amalert danger\"><p><strong><em>Caution.</em></strong><p>Regenerating the authorization key can have some side effects such as\ninvalidation of all the previously configured Intents.</div></section><section id=subsec:at:general-configuration class=level3 data-number=3.4.2><h3 data-number=3.4.2><span class=header-section-number>3.4.2</span>\n<a href=#toc:subsec:at:general-configuration>Configuring tasks</a><a href=#subsec:at:general-configuration class=anchor aria-hidden=true></a></h3><p>The activity\n<code>io.github.muntashirakon.AppManager.crypto.auth.AuthFeatureDemultiplexer</code>\nis responsible for handling all the automations. Sending an intent to\nthe activity lets App Manager perform the designated operation by\nredirecting the <code>Intent</code> to the designated activity or\nservice.<section id=required-extras class=level4 data-number=3.4.2.1><h4 data-number=3.4.2.1><span class=header-section-number>3.4.2.1</span> Required extras<a href=#required-extras class=anchor aria-hidden=true></a></h4><p>It has two primary extras required in all conditions. The key names,\ndata types are all follows:<ol class=incremental><li><p><strong><code>auth</code>.</strong> (String value) The\nauthorization key as described in the earlier section.<li><p><strong><code>feature</code>.</strong> (String value) Name of the\nfeature. Supported features are described in the next section.</ol></section></section><section id=subsec:at:features class=level3 data-number=3.4.3><h3 data-number=3.4.3><span class=header-section-number>3.4.3</span>\n<a href=#toc:subsec:at:features>Features</a><a href=#subsec:at:features class=anchor aria-hidden=true></a></h3><p>App Manager current support a single feature, namely\n<code>profile</code>.</section><section id=subsec:triggering-a-profile class=level3 data-number=3.4.4><h3 data-number=3.4.4><span class=header-section-number>3.4.4</span>\n<a href=#toc:subsec:triggering-a-profile>Triggering a profile</a><a href=#subsec:triggering-a-profile class=anchor aria-hidden=true></a></h3><p>In order to trigger a profile, <code>feature</code> must have the\nvalue <code>profile</code>. In addition, the following extras can be\nincluded:<ol class=incremental><li><p><strong><code>prof</code>.</strong> (String value – required) The\nname of the profile as displayed in the <a href=#sec:profiles-page>Profiles page</a>.<li><p><strong><code>state</code>.</strong> (String value – optional)\nState of the profile – currently <code>on</code> or <code>off</code> –\nas specified in the documentation. If this extra is not set, App Manager\nwill display a prompt where a state must be selected. Therefore, for\ncomplete automation, this option should be set.</ol></section></section><section id=sec:net-policy class=level2 data-number=3.5><h2 data-number=3.5><span class=header-section-number>3.5</span> <a href=#toc:sec:net-policy>Net Policy</a><a href=#sec:net-policy class=anchor aria-hidden=true></a></h2><p>Short for <strong>Network policy</strong> or network policies. It is\nusually located in the Android settings under <strong>Mobile data &\nWifi</strong> section in the app info page of an app. Not all policies\nare guaranteed to be included in this page (e.g. Samsung), and not all\nsettings are well-understood due to lack of documentation. App Manager\ncan display all the net policies declared in the <a href=https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/net/NetworkPolicyManager.java>NetworkPolicyManager</a>.\nPolicies unknown to App Manager will have a <em>Unknown</em> prefix\nalong with the policy constant name and number in the hexadecimal\nformat. Unknown policies should be reported to App Manager for\ninclusion.<p>Net policy allows a user to configure certain networking behaviour of\nan app without modifying the ip tables directly and/or running a\nfirewall app. However, the features it offers largely depend on Android\nversion and ROM. A list of known net policies are listed below:<ol class=incremental><li><p><strong>None</strong> or\n<strong><code>POLICY_NONE</code></strong>: (AOSP) No specific network\npolicy is set. System can still assign rules depending on the nature of\nthe app.<li><p><strong>Reject background data on metered networks</strong> or\n<strong><code>POLICY_REJECT_METERED_BACKGROUND</code></strong>: (AOSP)\nReject network usage on metered networks when the application is in\nbackground.<li><p><strong>Allow background data on metered networks even when Data\nSaver is on</strong> or\n<strong><code>POLICY_ALLOW_METERED_BACKGROUND</code></strong>: (AOSP)\nAllow metered network use in the background even when data saving mode\nis enabled.<li><p><strong>Reject cellular data</strong> or\n<strong><code>POLICY_REJECT_CELLULAR</code></strong> (Android 11+) or\n<strong><code>POLICY_REJECT_ON_DATA</code></strong> (up to Android 10):\n(Lineage OS) Reject mobile/cellular data. Signals network unavailable to\nthe configured app as if the mobile data is inactive.<li><p><strong>Reject VPN data</strong> or\n<strong><code>POLICY_REJECT_VPN</code></strong> (Android 11+) or\n<strong><code>POLICY_REJECT_ON_VPN</code></strong> (up to Android 10):\n(Lineage OS) Reject VPN data. Signals network unavailable to the\nconfigured app as if the VPN is inactive.<li><p><strong>Reject Wi-Fi data</strong> or\n<strong><code>POLICY_REJECT_WIFI</code></strong> (Android 11+) or\n<strong><code>POLICY_REJECT_ON_WLAN</code></strong> (up to Android 10):\n(Lineage OS) Reject Wi-Fi data. Signals network unavailable to the\nconfigured app as if the device is not connected to a Wi-Fi\nnetwork.<li><p><strong>Disable network access</strong> or\n<strong><code>POLICY_REJECT_ALL</code></strong> (Android 11+) or\n<strong><code>POLICY_NETWORK_ISOLATED</code></strong> (up to Android\n10): (Lineage OS) Reject network access in all circumstances. This is\nnot the same as enforcing the other three policies above, and is the\nrecommended policy for dodgy apps. If this policy is enforced, there is\nno need to enforce the other policies.<li><p><strong><code>POLICY_ALLOW_METERED_IN_ROAMING</code></strong>:\n(Samsung) Possibly allow metered network use during roaming. Exact\nmeaning is currently unknown.<li><p><strong><code>POLICY_ALLOW_WHITELIST_IN_ROAMING</code></strong>:\n(Samsung) Possibly allow network use during roaming. Exact meaning is\ncurrently unknown.<li><p><strong>Reject data on metered networks</strong> or\n<strong><code>POLICY_REJECT_METERED</code></strong>: (Motorola) Reject\nnetwork usage if it is a metered network.<li><p><strong>Reject background data</strong> or\n<strong><code>POLICY_REJECT_BACKGROUND</code></strong>: (Motorola)\nReject network usage in the background.<li><p><strong>Disable network access</strong> or\n<strong><code>POLICY_REJECT_ALL</code></strong>: (Motorola) Reject\nnetwork access altogether. Like Lineage OS, it blocks internet\nconnections via iptables. But whether it signals the unavailability of\nnetwork to the configured app is not known.</ol><div class=\"amalert tip\"><p><strong><em>Note.</em></strong><p>Corresponding Lineage OS patches are as follows:<ol class=incremental><li><p><a href=https://github.com/LineageOS/android_frameworks_base/commit/a04932bafbbf7d99efd18276152cc2c9c9b2073e>fw/b:\nSquash of app fw restriction commits</a><li><p><a href=https://github.com/LineageOS/android_frameworks_base/commit/02c8c82854348f52afe2199f310f44b5f578b5b8>fw/b:\nAdd support for per app network isolation</a></ol></div></section></section><section id=ch:faq class=level1 data-number=4><h1 data-number=4><span class=header-section-number>4</span> <a href=#toc:ch:faq>Frequently Asked Questions</a><a href=#ch:faq class=anchor aria-hidden=true></a></h1><section id=sec:faq:app-components class=level2 data-number=4.1><h2 data-number=4.1><span class=header-section-number>4.1</span> <a href=#toc:sec:faq:app-components>App Components</a><a href=#sec:faq:app-components class=anchor aria-hidden=true></a></h2><section id=subsec:faq:what-are-app-components class=level3 data-number=4.1.1><h3 data-number=4.1.1><span class=header-section-number>4.1.1</span>\n<a href=#toc:subsec:faq:what-are-app-components>What are the\napplication components?</a><a href=#subsec:faq:what-are-app-components class=anchor aria-hidden=true></a></h3><p>Activities, services, broadcast receivers (or only receivers) and\ncontent providers (or only providers) are jointly called application\ncomponents. More technically, they all inherit the <a href=https://developer.android.com/reference/android/content/pm/ComponentInfo>ComponentInfo</a>\nclass and can be launched via Intent.</section><section id=subsec:faq:how-components-blocked class=level3 data-number=4.1.2><h3 data-number=4.1.2><span class=header-section-number>4.1.2</span>\n<a href=#toc:subsec:faq:how-components-blocked>How are the tracker and\nother components blocked in App Manager? What are its limitations?</a><a href=#subsec:faq:how-components-blocked class=anchor aria-hidden=true></a></h3><p>App Manager typically blocks application components (or tracker\ncomponents) using a method called <a href=https://carteryagemann.com/pages/android-intent-firewall.html>Intent\nFirewall (IFW)</a>, it is superior to other methods such as <em>pm</em>\n(PackageManager), <a href=https://github.com/RikkaApps/Shizuku>Shizuku</a> or any other\nmethod that uses the package manager to enable or disable the\ncomponents. If a component is disabled by the latter methods, the\napplication itself can detect that the component is being blocked and\ncan re-enable it as it has full access to its own components. (Many\ndeceptive applications actually do this in order to keep the tracker\ncomponents unblocked.) On the other hand, IFW is a true firewall and the\napplication cannot detect if its components are being blocked. App\nManager uses the term <em>block</em> rather than <em>disable</em> for\nthis reason.<p>Even IFW has some limitations which are primarily applicable for the\nsystem applications:<ul class=incremental><li><p>The application in question is whitelisted by the system i.e. the\nsystem cannot function properly without these applications and may cause\nrandom crashes. These applications include but not limited to Android\nSystem, System UI, Phone Services. They will continue to work even if\nthey are disabled or blocked.<li><p>Another system application or system process has activated a\nspecific component of the application in question via interprocess\ncommunication (IPC). In this case, the component will be activated\nregardless of blocking status or even if the entire application is\ndisabled. If there is such a system application that is not needed, the\nonly way to prevent it from running is by getting rid of it.</ul></section><section id=subsec:faq:components-blocked-by-others class=level3 data-number=4.1.3><h3 data-number=4.1.3><span class=header-section-number>4.1.3</span>\n<a href=#toc:subsec:faq:components-blocked-by-others>Does app\ncomponents blocked by other tools retained in App Manager?</a><a href=#subsec:faq:components-blocked-by-others class=anchor aria-hidden=true></a></h3><p><strong>No.</strong> But the application components blocked by the\nsystem or any other tools are displayed in the <a href=#subsec:component-tabs>component tabs</a>. These rules can be\nimported from <a href=#par:import-existing-rules>Settings</a>.\nHowever, it is not possible for App Manager to distinguish the\ncomponents blocked by the third-party tools and components blocked by\nthe system. Therefore, the applications listed in the import page should\nbe selected with care.</section><section id=subsec:faq:components-reblocked-in-am class=level3 data-number=4.1.4><h3 data-number=4.1.4><span class=header-section-number>4.1.4</span>\n<a href=#toc:subsec:faq:components-reblocked-in-am>What happens to the\ncomponents blocked by App Manager which were previously blocked by other\ntools?</a><a href=#subsec:faq:components-reblocked-in-am class=anchor aria-hidden=true></a></h3><p><em>App Manager blocks the components again</em> if requested. In\ncase of unblocking, they will be reverted to the default state as\nspecified in the manifest of the application. But if the components were\nblocked by <a href=https://www.myandroidtools.com>MyAndroidTools\n(MAT)</a> with IFW method, they will not be unblocked by App Manager as\nit uses a different format. To fix this issue, the rules have to be\nimported from <a href=#par:import-existing-rules>Settings</a> at\nfirst, in which case MAT’s configurations will be permanently\nremoved.</section><section id=subsec:faq:what-is-instant-component-blocking class=level3 data-number=4.1.5><h3 data-number=4.1.5><span class=header-section-number>4.1.5</span>\n<a href=#toc:subsec:faq:what-is-instant-component-blocking>What is\ninstant component blocking?</a><a href=#subsec:faq:what-is-instant-component-blocking class=anchor aria-hidden=true></a></h3><p>When you block a component in the <a href=#sec:app-details-page>App\nDetails page</a>, the blocking is not applied by default. It is only\napplied when you apply blocking using the <em>Apply rules</em> option in\nthe top-right menu. If you enable <a href=#subsubsec:instant-component-blocking>instant component\nblocking</a>, blocking will be applied as soon as you block a component.\nIf you choose to block tracker components, however, blocking is applied\nautomatically regardless of this setting. You can also remove blocking\nfor an application by simply clicking on <em>Remove rules</em> in the\nsame menu in the <strong>App Details page</strong>. Since the default\nbehaviour gives you more control over applications, it is better to keep\n<em>instant component blocking</em> option disabled.</section><section id=subsec:tracker-classes-versus-tracker-components class=level3 data-number=4.1.6><h3 data-number=4.1.6><span class=header-section-number>4.1.6</span>\n<a href=#toc:subsec:tracker-classes-versus-tracker-components>Tracker\nclasses versus tracker components</a><a href=#subsec:tracker-classes-versus-tracker-components class=anchor aria-hidden=true></a></h3><p>All application components are classes but not all classes are\ncomponents. In fact, only a few of the classes are components. That\nbeing said, <a href=#sec:scanner-page>scanner page</a> displays a list\nof trackers along with the number of classes, not just the components.\nIn all other pages, trackers and tracker components are used\nsynonymously to denote tracker components, i.e. blocking tracker means\nblocking tracker components, not tracker classes.<div class=\"amalert tip\"><p><strong><em>Info.</em></strong><p>Tracker classes that are not components cannot be blocked. They can\nonly be removed by editing the application itself.</div></section></section><section id=sec:faq:adb-over-tcp class=level2 data-number=4.2><h2 data-number=4.2><span class=header-section-number>4.2</span> <a href=#toc:sec:faq:adb-over-tcp>ADB over TCP</a><a href=#sec:faq:adb-over-tcp class=anchor aria-hidden=true></a></h2><section id=subsec:faq:enable-adb-on-every-restart class=level3 data-number=4.2.1><h3 data-number=4.2.1><span class=header-section-number>4.2.1</span>\n<a href=#toc:subsec:faq:enable-adb-on-every-restart>Do I have to\nenable ADB over TCP everytime I restart?</a><a href=#subsec:faq:enable-adb-on-every-restart class=anchor aria-hidden=true></a></h3><p>Unfortunately, yes. This is because the ADB daemon, the process\nresponsible for ADB connection, is also restarted after a reboot, and it\ndoes not re-enable ADB over TCP.</section><section id=subsec:faq:usb-debugging class=level3 data-number=4.2.2><h3 data-number=4.2.2><span class=header-section-number>4.2.2</span>\n<a href=#toc:subsec:faq:usb-debugging>Cannot enable USB debugging.\nWhat to do?</a><a href=#subsec:faq:usb-debugging class=anchor aria-hidden=true></a></h3><p>See §<a href=#subsec:enable-usb-debugging data-reference-type=ref data-reference=subsec:enable-usb-debugging>3.1.2</a> in Chapter <a href=#ch:guides data-reference-type=ref data-reference=ch:guides>3</a>.</section><section id=subsec:faq:block-components-using-adb class=level3 data-number=4.2.3><h3 data-number=4.2.3><span class=header-section-number>4.2.3</span>\n<a href=#toc:subsec:faq:block-components-using-adb>Can I block tracker\nor any other application components using ADB over TCP?</a><a href=#subsec:faq:block-components-using-adb class=anchor aria-hidden=true></a></h3><p>ADB has limited number of <a href=https://github.com/aosp-mirror/platform_frameworks_base/blob/master/packages/Shell/AndroidManifest.xml>permissions</a>\nand controlling application components is not one of them. However, the\ncomponents of a <em>test-only</em> app can be controlled via ADB. If App\nManager detects such an application, it enables the blocking options\nautomatically.</section><section id=subsec:faq:adb-features class=level3 data-number=4.2.4><h3 data-number=4.2.4><span class=header-section-number>4.2.4</span>\n<a href=#toc:subsec:faq:adb-features>Which features can be used in ADB\nmode?</a><a href=#subsec:faq:adb-features class=anchor aria-hidden=true></a></h3><p>Supported features are enabled automatically in the ADB mode.\nSupported features include disabling, force-stopping, clearing\napplication data, granting or revoking app ops and permissions, and so\non. It is also possible to install or uninstall applications without any\nprompt from the system.</section></section><section id=sec:faq:miscellanea class=level2 data-number=4.3><h2 data-number=4.3><span class=header-section-number>4.3</span> <a href=#toc:sec:faq:miscellanea>Miscellanea</a><a href=#sec:faq:miscellanea class=anchor aria-hidden=true></a></h2><section id=subsec:faq:no-root-no-harms class=level3 data-number=4.3.1><h3 data-number=4.3.1><span class=header-section-number>4.3.1</span>\n<a href=#toc:subsec:faq:no-root-no-harms>I don’t use root/ADB. Am I\ncompletely safe from any harms?</a><a href=#subsec:faq:no-root-no-harms class=anchor aria-hidden=true></a></h3><p>Yes. AM cannot modify any system settings without root or ADB.</section><section id=subsec:faq:how-trackers-libs-updated class=level3 data-number=4.3.2><h3 data-number=4.3.2><span class=header-section-number>4.3.2</span>\n<a href=#toc:subsec:faq:how-trackers-libs-updated>How are the trackers\nand libraries are updated?</a><a href=#subsec:faq:how-trackers-libs-updated class=anchor aria-hidden=true></a></h3><p>Trackers and libraries are updated manually before making a new\nrelease.</section><section id=subsec:faq:apks-deleted-after-installed class=level3 data-number=4.3.3><h3 data-number=4.3.3><span class=header-section-number>4.3.3</span>\n<a href=#toc:subsec:faq:apks-deleted-after-installed>Are APKs deleted\nafter installed?</a><a href=#subsec:faq:apks-deleted-after-installed class=anchor aria-hidden=true></a></h3><p>No, APKs aren’t deleted by App Manager after they are installed.</section><section id=subsec:faq:shizuku-support class=level3 data-number=4.3.4><h3 data-number=4.3.4><span class=header-section-number>4.3.4</span>\n<a href=#toc:subsec:faq:shizuku-support>Any plans for Shizuku?</a><a href=#subsec:faq:shizuku-support class=anchor aria-hidden=true></a></h3><p>App Manager’s use of hidden API and privileged code execution is now\nmuch more complex and cannot be integrated with other third party apps\nsuch as <a href=https://shizuku.rikka.app>Shizuku</a>. Here are some\nreasons for not considering Shizuku (which now has Apache 2.0 license)\nfor App Manager:<ol class=incremental><li><p>Shizuku was initially non-free which led me to use a similar\napproach for App Manager to support both root and ADB<li><p>App Manager already supports both ADB and root which in some\ncases is more capable than Shizuku<li><p>Relying on a third-party app for the major functionalities is not\na good design choice<li><p>Integration of Shizuku will increase the complexity of App\nManager.</ol></section><section id=subsec:faq:what-are-bloatware class=level3 data-number=4.3.5><h3 data-number=4.3.5><span class=header-section-number>4.3.5</span>\n<a href=#toc:subsec:faq:what-are-bloatware>What are bloatware and how\nto remove them?</a><a href=#subsec:faq:what-are-bloatware class=anchor aria-hidden=true></a></h3><p>Bloatware are the unnecessary pre-installed apps, usually system\napps. Some of the apps are often used to track users and collect user\ndata which they might sell for profits. Many system apps do not need to\nrequest any permission to access device info, contacts and messaging\ndata, and other usage info, such as your phone usage habits and\neverything you store on your shared storage(s).<p>The bloatware may also include Google apps, Meta apps, and Twitter/X\nwhich can also track users and/or collect user data without consent. You\ncan disable a few permissions from Android settings but be aware that\nAndroid settings hides many permissions a security researcher would call\npotentially <em>dangerous</em> (e.g., internet, sensor).<p>Were the bloatware user apps, they could be easily uninstalled either\nfrom Android settings or AM. Uninstalling system apps is not possible\nwithout privileged permission, but even then, it cannot <em>remove</em>\nthe system apps completely as they are located in the <em>system</em>\npartition which is a read-only partition. If you have root, you can\nremount this partition to manually <em>purge</em> these apps but this\nwill break Over the Air (OTA) updates since data in the system partition\nhas been modified. There are two kind of updates, delta (small-size,\nconsisting of only the changes between two versions) and full updates.\nYou may still be able to apply full updates, but the bloatware will be\ninstalled again, and consequently, you have to delete them all over\nagain.<p>Another solution is to disable these apps either from Android\nsettings or AM, but certain services can still run in the background as\nthey can be started by other system apps using Inter-process\nCommunication (IPC). One possible solution is to disable all bloatware\nuntil the service has finally stopped (after a restart). However, due to\nheavy modifications of the Android frameworks by the vendors, removing\nor disabling certain bloatware may cause the System UI to crash or even\ncause bootloop. From v4.0.0, AM has a new feature called\n<strong>Debloater</strong> which can be used as a starting point to\nmonitor, disable, and remove the bloatware from a proprietary Android\noperating system.<div class=\"amalert warning\"><p><strong><em>Note.</em></strong><p>In most cases, you cannot completely debloat your device. Therefore,\nit is recommended that you use a custom ROM free from bloatware, such as\nGraphene OS, Lineage OS or their derivatives.</div></section></section></section><section id=ch:specifications class=level1 data-number=5><h1 data-number=5><span class=header-section-number>5</span> <a href=#toc:ch:specifications>Specifications</a><a href=#ch:specifications class=anchor aria-hidden=true></a></h1><section id=sec:rules-specification class=level2 data-number=5.1><h2 data-number=5.1><span class=header-section-number>5.1</span> <a href=#toc:sec:rules-specification>Rules Specification</a><a href=#sec:rules-specification class=anchor aria-hidden=true></a></h2><section id=background class=level3 data-number=5.1.1><h3 data-number=5.1.1><span class=header-section-number>5.1.1</span>\n<a href=#toc:background>Background</a><a href=#background class=anchor aria-hidden=true></a></h3><p>AM currently supports blocking activities, broadcast receivers,\ncontent providers, services, app ops and permissions, and in future I\nmay add more blocking options. In order to add more portability, it is\nnecessary to import/export all these data.<p>Maintaining a database should be the best choice when it comes to\nstoring data. For now, several <code>tsv</code> files with each file\nhaving the name of the package and a <code>.tsv</code> extension. The\nfile/database will be queried/processed by the\n<code>RulesStorageManager</code> class. Due to this abstraction, it\nshould be easier to switch to database or encrypted database systems in\nfuture without changing the design of the entire project. Currently, All\nconfiguration files are stored at\n<code>/data/data/io.github.muntashirakon.AppManager/Files/conf</code>.</section><section id=rules-file-format class=level3 data-number=5.1.2><h3 data-number=5.1.2><span class=header-section-number>5.1.2</span>\n<a href=#toc:rules-file-format>Rules File Format</a><a href=#rules-file-format class=anchor aria-hidden=true></a></h3><section id=internal class=level4 data-number=5.1.2.1><h4 data-number=5.1.2.1><span class=header-section-number>5.1.2.1</span> Internal<a href=#internal class=anchor aria-hidden=true></a></h4><p>The format below is used internally within App Manager and is <em>not\ncompatible with the external format.</em><pre><code>    &lt;name&gt; &lt;type&gt; &lt;mode&gt;|&lt;component_status&gt;|&lt;is_granted&gt;</code></pre><p>Here:<ul class=incremental><li><p><code>&lt;name></code> – Component/permission/app op name (in\ncase of app op, it could be string or integer)<li><p><code>&lt;type></code> – One of the <code>ACTIVITY</code>,\n<code>RECEIVER</code>, <code>PROVIDER</code>, <code>SERVICE</code>,\n<code>APP_OP</code>, <code>PERMISSION</code><li><p><code>&lt;mode></code> – (For app ops) The associated <a href=#subsec:mode-constants>mode constant</a><li><p><code>&lt;component_status></code> – (For components)\nComponent status<ul class=incremental><li><p><code>true</code> – Component has been applied (<code>true</code>\nvalue is kept for compatibility)<li><p><code>false</code> – Component hasn’t been applied yet, but will\nbe applied in future (<code>false</code> value is kept for\ncompatibility)<li><p><code>unblocked</code> – Component is scheduled to be\nunblocked</ul><li><p><code>&lt;is_granted></code> – (For permissions) Whether the\npermission is granted or revoked</ul></section><section id=external class=level4 data-number=5.1.2.2><h4 data-number=5.1.2.2><span class=header-section-number>5.1.2.2</span> External<a href=#external class=anchor aria-hidden=true></a></h4><p>External format is used for importing or exporting rules in App\nManager.<pre><code>    &lt;package_name&gt; &lt;component_name&gt; &lt;type&gt; &lt;mode&gt;|&lt;component_status&gt;|&lt;is_granted&gt;</code></pre><p>This the format is essentially the same as above except for the first\nitem which is the name of the package.<div class=\"amalert danger\"><p><strong><em>Caution.</em></strong><p>The exported rules have a different format than the internal one and\nshould not be copied directly to the <strong>conf</strong> folder.</div></section></section></section></section><section id=ch:changelogs class=level1 data-number=6><h1 data-number=6><span class=header-section-number>6</span> <a href=#toc:ch:changelogs>Changelogs</a><a href=#ch:changelogs class=anchor aria-hidden=true></a></h1><section id=sec:v4.0.5-(445) class=level2 data-number=6.1><h2 data-number=6.1><span class=header-section-number>6.1</span> <a href=#toc:sec:v4.0.5-(445)>v4.0.5 (445)</a><a href=#sec:v4.0.5-(445) class=anchor aria-hidden=true></a></h2><ul class=incremental><li><p>Added option to allow installing the existing applications in the\ninstaller page<li><p>Display unsafe bloatware info<li><p>Display vector icon on the splash screen in Android 7.1 and\nearlier<li><p>Enabled “Clear data from uninstalled apps” to no-root users in\n1-click ops page<li><p>Enabled predictive back in Android 14 onwards<li><p>Improved accessibility by updating the content description of the\naction items<li><p>In app info tab, open “Open by default” setting in the “Open\nlinks” dialog<li><p>In debloater page, sort by app label (or app name) rather than\npackage name<li><p>Fixed freezing an app with “Remember for this app” turned\non<li><p>Fixed selecting texts in the list items due to framework\nbugs<li><p>Fixed setting app ops in custom ROMs with MIUI properties\ninjected<li><p>Fixed updating profile modification status when an application is\ndeleted from the list<li><p>Handled common colors and cursor movements in terminal\noutput.</ul></section><section id=sec:v4.0.4-(444) class=level2 data-number=6.2><h2 data-number=6.2><span class=header-section-number>6.2</span> <a href=#toc:sec:v4.0.4-(444)>v4.0.4 (444)</a><a href=#sec:v4.0.4-(444) class=anchor aria-hidden=true></a></h2><ul class=incremental><li><p>Optimized searching and filtering in the main page<li><p>Adopted sentence-case for the titles<li><p>Use the configured state to execute a profile for the simple\nshortcuts<li><p>Prevented crashing while searching throughout the\napplication<li><p>Fixed integer overflow issue in the tar compression.</ul></section><section id=sec:v4.0.3-(443) class=level2 data-number=6.3><h2 data-number=6.3><span class=header-section-number>6.3</span> <a href=#toc:sec:v4.0.3-(443)>v4.0.3 (443)</a><a href=#sec:v4.0.3-(443) class=anchor aria-hidden=true></a></h2><ul class=incremental><li><p>Updated translations<li><p>Improved handling the list items throughout App Manager<li><p>Fixed a regression error in file manager<li><p>Fixed spinners in the App Usage and the System Config\npages.</ul></section><section id=sec:v4.0.2-(442) class=level2 data-number=6.4><h2 data-number=6.4><span class=header-section-number>6.4</span> <a href=#toc:sec:v4.0.2-(442)>v4.0.2 (442)</a><a href=#sec:v4.0.2-(442) class=anchor aria-hidden=true></a></h2><ul class=incremental><li><p>Updated bloatware<li><p>Fixed fetching applications in multi-user environment in no-root\nmode<li><p>Fixed opening <code>app-manager</code> URLs from the web\nbrowsers<li><p>Fixed updating SSAID<li><p>Prevented a crash in Android &lt; 9.0 that occurs due to invalid\napp ops.</ul></section><section id=sec:v4.0.1-(441) class=level2 data-number=6.5><h2 data-number=6.5><span class=header-section-number>6.5</span> <a href=#toc:sec:v4.0.1-(441)>v4.0.1 (441)</a><a href=#sec:v4.0.1-(441) class=anchor aria-hidden=true></a></h2><section id=overlay-management class=level3 data-number=6.5.1><h3 data-number=6.5.1><span class=header-section-number>6.5.1</span>\n<a href=#toc:overlay-management>Overlay management</a><a href=#overlay-management class=anchor aria-hidden=true></a></h3><p>In the App Details page, a new tab “Overlays” is added where per-app\noverlays are displayed. They can also be enabled or disabled using the\ntoggle button. In addition, if the App Details page of an overlay\npackage is opened, a “Overlay” tag will be displayed in the App Info\ntab. Clicking on the tag opens a dialog containing additional info along\nwith a button that allows navigating to the App Details page of the\noverlay target package if it is installed.<section id=known-limitation class=level5 data-number=6.5.1.0.1><h5 data-number=6.5.1.0.1><span class=header-section-number>6.5.1.0.1</span> Known limitation<a href=#known-limitation class=anchor aria-hidden=true></a></h5><p>At present, it only works for root/ADB users in Android 8 (Oreo) and\nlater.</section></section><section id=unfreeze-option-in-activity-shortcuts class=level3 data-number=6.5.2><h3 data-number=6.5.2><span class=header-section-number>6.5.2</span>\n<a href=#toc:unfreeze-option-in-activity-shortcuts>Unfreeze option in\nactivity shortcuts</a><a href=#unfreeze-option-in-activity-shortcuts class=anchor aria-hidden=true></a></h3><p>If the application corresponding to the shortcut being launched is\nfrozen, App Manager will now offer you to unfreeze the app temporarily\nso that the shortcut can be launched. The app will be frozen again once\nthe screen is locked.<section id=known-limitation-1 class=level5 data-number=6.5.2.0.1><h5 data-number=6.5.2.0.1><span class=header-section-number>6.5.2.0.1</span> Known limitation<a href=#known-limitation-1 class=anchor aria-hidden=true></a></h5><p>This may not work on devices without a screen lock or if the screen\nis locked some time after the display goes off.</section></section><section id=market-like-url-support class=level3 data-number=6.5.3><h3 data-number=6.5.3><span class=header-section-number>6.5.3</span>\n<a href=#toc:market-like-url-support><code>market</code>-like URL\nsupport</a><a href=#market-like-url-support class=anchor aria-hidden=true></a></h3><p>Third-party applications can now open the App Details page of any\ninstalled package by invoking an Intent with an URL with the following\nformat:<pre><code>app-manager://details?id=&lt;pkg&gt;&amp;user=&lt;user_id&gt;</code></pre><p>where <code>&lt;pkg></code> stands for package name, and\n<code>&lt;user_id></code> stands for the user ID which is\noptional.</section><section id=updated-color-codes class=level3 data-number=6.5.4><h3 data-number=6.5.4><span class=header-section-number>6.5.4</span>\n<a href=#toc:updated-color-codes>Updated color codes</a><a href=#updated-color-codes class=anchor aria-hidden=true></a></h3><p>In order to improve accessibility, certain color codes have been\nimproved. Visit <a href=app-manager://settings/about/version>Settings\n> About > Version/Changelog</a> for details.</section><section id=others class=level3 data-number=6.5.5><h3 data-number=6.5.5><span class=header-section-number>6.5.5</span>\n<a href=#toc:others>Others</a><a href=#others class=anchor aria-hidden=true></a></h3><ul class=incremental><li><p>Avoided waiting for the remote server to respond when no-root\nmode is set<li><p>Fixed downgrading apps in Android 10 onwards<li><p>Fixed installer issues in the Huawei stock operating\nsystems<li><p>Improved text formatting in the “What’s New” dialog<li><p>In the UI tracker window, fixed clicking on the icon after it is\niconified<li><p>Updated bloatware and suggestions</ul></section></section><section id=sec:v4.0.0-(440) class=level2 data-number=6.6><h2 data-number=6.6><span class=header-section-number>6.6</span> <a href=#toc:sec:v4.0.0-(440)>v4.0.0 (440)</a><a href=#sec:v4.0.0-(440) class=anchor aria-hidden=true></a></h2><p>App Manager v4.0.0 comes with a lot of new features and improvements.\nVisit <a href=app-manager://settings/about/version>Settings > About\n> Version/Changelog</a> for details.<section id=new-logo class=level3 data-number=6.6.1><h3 data-number=6.6.1><span class=header-section-number>6.6.1</span>\n<a href=#toc:new-logo>New logo!</a><a href=#new-logo class=anchor aria-hidden=true></a></h3><p>The new logo is just a cursive “A”. The design is based on the <a href=https://freetengwar.sourceforge.net/>Tengwar Telcontar</a> font\nwhich was created to bring the Tengwar script, originally created by J.\nR. R. Tolkien, to the digital world. The letter has the classic App\nManager color (i.e., #dcaf74) and uses a pure black background instead\nof a shade of grey.</section><section id=android-14-and-15-support class=level3 data-number=6.6.2><h3 data-number=6.6.2><span class=header-section-number>6.6.2</span>\n<a href=#toc:android-14-and-15-support>Android 14 and 15 support</a><a href=#android-14-and-15-support class=anchor aria-hidden=true></a></h3><p>App Manager now targets Android 14 and fully supports Android 15.<section id=known-issue class=level5 data-number=6.6.2.0.1><h5 data-number=6.6.2.0.1><span class=header-section-number>6.6.2.0.1</span> Known issue<a href=#known-issue class=anchor aria-hidden=true></a></h5><p>KeyStore backup/restore is not working in Android 12 and later.</section></section><section id=revamped-debloater class=level3 data-number=6.6.3><h3 data-number=6.6.3><span class=header-section-number>6.6.3</span>\n<a href=#toc:revamped-debloater>Revamped debloater</a><a href=#revamped-debloater class=anchor aria-hidden=true></a></h3><p>Debloating profiles were available as “Presets” in the Profiles page\nwhich has now been replaced with the Debloater page and can be accessed\nfrom the three-dots menu in the Main page. <a href=https://github.com/MuntashirAkon/android-debloat-list>ADL</a> is\na new project that focuses on maintaining a list of bloatware as well as\npotential open source alternatives. Contributions are welcome!</section><section id=introducing-file-manager class=level3 data-number=6.6.4><h3 data-number=6.6.4><span class=header-section-number>6.6.4</span>\n<a href=#toc:introducing-file-manager>Introducing file manager</a><a href=#introducing-file-manager class=anchor aria-hidden=true></a></h3><p>App Manager offers an (almost) fully-featured file manager with basic\nfile operations, such as copy, cut, rename, and delete along with the\nbatch operations. It also offers an extensive “Open with…” dialog to\nopen a file with another app, and a comprehensive file properties\nviewer. Folders can also be added to the list of favorites for quick\naccess. And many more.</section><section id=integrated-code-editor class=level3 data-number=6.6.5><h3 data-number=6.6.5><span class=header-section-number>6.6.5</span>\n<a href=#toc:integrated-code-editor>Integrated code editor</a><a href=#integrated-code-editor class=anchor aria-hidden=true></a></h3><p>Manifest and code viewers have been replaced with this new editor.\nAmong other regular features, it includes proper syntax highlighting and\nadvanced searching options. In addition, files from third-party apps can\nalso be opened for editing.</section><section id=history-of-operations class=level3 data-number=6.6.6><h3 data-number=6.6.6><span class=header-section-number>6.6.6</span>\n<a href=#toc:history-of-operations>History of operations</a><a href=#history-of-operations class=anchor aria-hidden=true></a></h3><p>All 1-click operations, batch operations, and profile invocations are\nnow stored as history. The history items can also be executed from the\nHistory page. To ensure consistency, the profile state, configurations,\npackage list are also stored, and this stored version is executed\ninstead of the actual profile. As a result, this works even if the\nprofile is deleted.</section><section id=per-app-freezing-and-more class=level3 data-number=6.6.7><h3 data-number=6.6.7><span class=header-section-number>6.6.7</span>\n<a href=#toc:per-app-freezing-and-more>Per-app freezing, and\nmore</a><a href=#per-app-freezing-and-more class=anchor aria-hidden=true></a></h3><p>Freeze/unfreeze feature now supports setting per-app freezing method\nwhich is beneficial in certain scenarios, such as when a user want to\nsuspend some apps while using the disable method as the default. In\naddition, an “Advanced suspend” option is added which force-stops an\napplication before suspending it, thus, prevent it’s services from\nrunning in the background.</section><section id=log-viewer-enhancements class=level3 data-number=6.6.8><h3 data-number=6.6.8><span class=header-section-number>6.6.8</span>\n<a href=#toc:log-viewer-enhancements>Log viewer enhancements</a><a href=#log-viewer-enhancements class=anchor aria-hidden=true></a></h3><p>Log viewer now supports enhanced searching and filtering options,\nsuch as keyword- and regular expression-based searching and filtering.\nPlease read the in-app changelog for details. Support for batch\noperations has also been added.</section><section id=launching-non-exported-activities class=level3 data-number=6.6.9><h3 data-number=6.6.9><span class=header-section-number>6.6.9</span>\n<a href=#toc:launching-non-exported-activities>Launching non-exported\nactivities</a><a href=#launching-non-exported-activities class=anchor aria-hidden=true></a></h3><p>App Manager now supports launching non-exported activities in no-root\nand ADB mode. However, in no-root mode,\n<code>android.permission.WRITE_SECURE_SETTINGS</code> permission is\nrequired.</section><section id=new-tags-in-app-info-tab class=level3 data-number=6.6.10><h3 data-number=6.6.10><span class=header-section-number>6.6.10</span> <a href=#toc:new-tags-in-app-info-tab>New tags in App Info tab</a><a href=#new-tags-in-app-info-tab class=anchor aria-hidden=true></a></h3><p>Five new tags are added in the App Info tab. They are: bloatware,\nXposed, sensors disabled, open links, and static shared libs. Clicking\non “bloatware” will display more information regarding the bloatware and\nsuggest alternatives, “Xposed” tag will display dependency information,\n“open links” will display a list of links supported by the application,\nand “static shared libs” will display all version of the application\ninstalled in the system along with an option to uninstall them. The\nlatter is useful for applications, such as Trichrome.<section id=known-issue-1 class=level5 data-number=6.6.10.0.1><h5 data-number=6.6.10.0.1><span class=header-section-number>6.6.10.0.1</span> Known issue<a href=#known-issue-1 class=anchor aria-hidden=true></a></h5><p>“Sensors disabled” only works real-time. That means if the\napplication is not currently active, this tag will always display even\nthough the applications may use sensors while it is running. This is a\nframework limitation and nothing can be done to avoid it\neffectively.</section></section><section id=per-session-installer-options class=level3 data-number=6.6.11><h3 data-number=6.6.11><span class=header-section-number>6.6.11</span> <a href=#toc:per-session-installer-options>Per-session installer\noptions</a><a href=#per-session-installer-options class=anchor aria-hidden=true></a></h3><p>It is not possible to modify installer options during the\ninstallation by clicking on the “settings” button in the installation\ndialog. The installer options will be applied to all the applications\ninstalled in the same session (i.e., the installer queue).</section><section id=advanced-mode-of-operations-adb-enhancements class=level3 data-number=6.6.12><h3 data-number=6.6.12><span class=header-section-number>6.6.12</span> <a href=#toc:advanced-mode-of-operations-adb-enhancements>Advanced mode\nof operations, ADB enhancements, …</a><a href=#advanced-mode-of-operations-adb-enhancements class=anchor aria-hidden=true></a></h3><p>App Manager now supports running its remote server (which is used as\na proxy for running privileged operations) as any supported user (UID).\nThis includes root (0), system (1000), and shell/ADB (2000) through the\ncustom commands. This is also useful for Fire TVs which have disabled\nconnecting to ADB from localhost through socket connection. In addition,\nADB pairing is now done using notifications rather than split screen.\nADB connection speed can also be improved by choosing to run App Manager\nin the background which can be configured in the settings.</section><section id=data-usage-widget-and-more class=level3 data-number=6.6.13><h3 data-number=6.6.13><span class=header-section-number>6.6.13</span> <a href=#toc:data-usage-widget-and-more>Data usage widget, and more</a><a href=#data-usage-widget-and-more class=anchor aria-hidden=true></a></h3><p>Data usage widget display the total data usage for the day, similar\nto the screen time widget which displays the total screen time for the\nday. In addition, existing widgets have been improved.</section><section id=others-1 class=level3 data-number=6.6.14><h3 data-number=6.6.14><span class=header-section-number>6.6.14</span> <a href=#toc:others-1>Others</a><a href=#others-1 class=anchor aria-hidden=true></a></h3><ul class=incremental><li><p>Replaced log viewer, sys config, Terminal, etc. with Labs\npage<li><p>Added an option to disable sensors for each app in the App Info\ntab<li><p>Added an option to perform runtime optimization of applications\nin the 1-click Ops page and in the App Info tab<li><p>Added support for Zstandard compression for\nbackup/restore<li><p>Enabling APK signing now automatically enables zip align\nfeature<li><p>Support exporting application list as CSV or JSON in the batch\noperations<li><p>Added pure black theme support<li><p>Display current activity name (when possible) in the UI Tracker\nwindow<li><p>Added an option to filter apps by user in the Main page<li><p>Display a link to Pithus report in the scanner page if\navailable.</ul></section></section><section id=sec:v3.1.0-(423) class=level2 data-number=6.7><h2 data-number=6.7><span class=header-section-number>6.7</span> <a href=#toc:sec:v3.1.0-(423)>v3.1.0 (423)</a><a href=#sec:v3.1.0-(423) class=anchor aria-hidden=true></a></h2><p>App Manager v3.1.0 comes with a few new features and a lot of\nimprovements. Visit <a href=app-manager://settings/about/version>Settings > About >\nVersion/Changelog</a> for details.<section id=android-13-support class=level3 data-number=6.7.1><h3 data-number=6.7.1><span class=header-section-number>6.7.1</span>\n<a href=#toc:android-13-support>Android 13 support</a><a href=#android-13-support class=anchor aria-hidden=true></a></h3><p>App Manager now targets Android 13 which means most issues in Android\n12 and 13 has been addressed, including SSAID and SAF issues as well as\nmonochrome icons and other theming issues.<section id=known-issue-2 class=level5 data-number=6.7.1.0.1><h5 data-number=6.7.1.0.1><span class=header-section-number>6.7.1.0.1</span> Known issue<a href=#known-issue-2 class=anchor aria-hidden=true></a></h5><p>KeyStore backup/restore not working in Android 12 and later.</section></section><section id=introducing-freezeunfreeze class=level3 data-number=6.7.2><h3 data-number=6.7.2><span class=header-section-number>6.7.2</span>\n<a href=#toc:introducing-freezeunfreeze>Introducing\nfreeze/unfreeze</a><a href=#introducing-freezeunfreeze class=anchor aria-hidden=true></a></h3><p>Enable/disable is replaced with freeze/unfreeze to allow greater\ncontrol on the behaviours of an app. It supports suspend, disable and\nhide functionalities which can be controlled at <a href=app-manager://settings/rules_prefs/freeze_type>Settings >\nRules > Default freezing method</a>. In order to make it easy to\nfreeze or unfreeze an app, shortcuts can also be created from the App\nInfo tab by long clicking on the freeze or unfreeze button.</section><section id=export-app-list class=level3 data-number=6.7.3><h3 data-number=6.7.3><span class=header-section-number>6.7.3</span>\n<a href=#toc:export-app-list>Export app list</a><a href=#export-app-list class=anchor aria-hidden=true></a></h3><p>In the Main page, it is now possible to export the list of apps in\neither XML or Markdown format using batch operations. In the future, the\nXML file may also be imported to App Manager.</section><section id=elliptic-curve-crypography-ecc class=level3 data-number=6.7.4><h3 data-number=6.7.4><span class=header-section-number>6.7.4</span>\n<a href=#toc:elliptic-curve-crypography-ecc>Elliptic Curve Crypography\n(ECC)</a><a href=#elliptic-curve-crypography-ecc class=anchor aria-hidden=true></a></h3><p>App Manager now fully supports encrypting backups using ECC in\naddition to offering AES, RSA and OpenPGP.</section><section id=new-languages class=level3 data-number=6.7.5><h3 data-number=6.7.5><span class=header-section-number>6.7.5</span>\n<a href=#toc:new-languages>New languages</a><a href=#new-languages class=anchor aria-hidden=true></a></h3><p>Two new languages are added: Korean and Romanian.</section><section id=more-list-options class=level3 data-number=6.7.6><h3 data-number=6.7.6><span class=header-section-number>6.7.6</span>\n<a href=#toc:more-list-options>More list options</a><a href=#more-list-options class=anchor aria-hidden=true></a></h3><p>In the main page, more sorting and filtering options are added.\nSorting options include sorting the apps by total size, total data\nusage, launch count, screen time and last usage time. Filtering options\ninclude filtering the apps having at least one item in the Android\nKeyStore, filtering apps with URIs granted via SAF, and filtering apps\nwith SSAID.</section><section id=improved-handling-of-mode-of-operation class=level3 data-number=6.7.7><h3 data-number=6.7.7><span class=header-section-number>6.7.7</span>\n<a href=#toc:improved-handling-of-mode-of-operation>Improved handling\nof mode of operation</a><a href=#improved-handling-of-mode-of-operation class=anchor aria-hidden=true></a></h3><p>Fixed various issues with ADB pairing, handled incomplete USB\ndebugging. Some rooting methods cannot allow interprocess communication\nvia Binder. In those cases, ADB mode is used as a fallback method by\nenabling it automatically if possible.</section><section id=handling-multiple-users class=level3 data-number=6.7.8><h3 data-number=6.7.8><span class=header-section-number>6.7.8</span>\n<a href=#toc:handling-multiple-users>Handling multiple users</a><a href=#handling-multiple-users class=anchor aria-hidden=true></a></h3><p>When possible, App Manager will be able to display apps from work\nprofile in no-root mode in addition to allowing basic operations such as\nlaunching the app or navigating to the system settings. For backups, it\nis now possible to restore backups for other users, but for work\nprofile, some apps may only work properly after re-enabling the work\nprofile. In the installer page, selecting <em>All users</em> will now\ninstall the app for all users instead of only the current user. Finally,\nin the app info tab, current app can be installed in another profile\nusing the <em>Install for…</em> option available in the three-dots menu.\nThis is analogous to the <code>pm install-existing</code> command,\nthereby, making the installation process a lot faster.</section><section id=explorer-enhancements class=level3 data-number=6.7.9><h3 data-number=6.7.9><span class=header-section-number>6.7.9</span>\n<a href=#toc:explorer-enhancements>Explorer enhancements</a><a href=#explorer-enhancements class=anchor aria-hidden=true></a></h3><p>Explorer can now open DEX and JAR files in addition to APK files.\nSeveral sorting options as well as folder options are also added as the\nlist options.</section><section id=new-tag-wx class=level3 data-number=6.7.10><h3 data-number=6.7.10><span class=header-section-number>6.7.10</span> <a href=#toc:new-tag-wx>New tag: WX</a><a href=#new-tag-wx class=anchor aria-hidden=true></a></h3><p>In app info tab, a new tag called WX is added. It is displayed in\nAndroid 10 and later if the application targets Android 9 or earlier. It\nindicates <a href=https://en.wikipedia.org/wiki/W%5EX>W^X</a>\nviolation which allows the app to execute arbitrary executable files\neither by the modification of executables embedded within the app or by\ndownloading them from the Internet.</section><section id=app-ops-management class=level3 data-number=6.7.11><h3 data-number=6.7.11><span class=header-section-number>6.7.11</span> <a href=#toc:app-ops-management>App ops management</a><a href=#app-ops-management class=anchor aria-hidden=true></a></h3><p>App ops are now managed automatically to avoid various app ops\nrelated crashes in various platforms. This will also lessen the amount\nof crashes in an unsupported operating system.</section><section id=batch-uninstallation class=level3 data-number=6.7.12><h3 data-number=6.7.12><span class=header-section-number>6.7.12</span> <a href=#toc:batch-uninstallation>Batch uninstallation</a><a href=#batch-uninstallation class=anchor aria-hidden=true></a></h3><p>In the Main page, enabled batch uninstallation in no-root mode.</section><section id=running-apps class=level3 data-number=6.7.13><h3 data-number=6.7.13><span class=header-section-number>6.7.13</span> <a href=#toc:running-apps>Running apps</a><a href=#running-apps class=anchor aria-hidden=true></a></h3><p>Enabled advanced searching. Searching now matches not only app labels\nbut also package names.</section><section id=interceptor class=level3 data-number=6.7.14><h3 data-number=6.7.14><span class=header-section-number>6.7.14</span> <a href=#toc:interceptor>Interceptor</a><a href=#interceptor class=anchor aria-hidden=true></a></h3><p>Copy the intercepted Intent as am command which can be run from\neither an ADB shell or a terminal using root with the same\neffectiveness.</section><section id=device-specific-changes class=level3 data-number=6.7.15><h3 data-number=6.7.15><span class=header-section-number>6.7.15</span> <a href=#toc:device-specific-changes>Device-specific changes</a><a href=#device-specific-changes class=anchor aria-hidden=true></a></h3><section id=graphene-os class=level5 data-number=6.7.15.0.1><h5 data-number=6.7.15.0.1><span class=header-section-number>6.7.15.0.1</span> Graphene OS<a href=#graphene-os class=anchor aria-hidden=true></a></h5><p>Explicitly handle the Internet permission which is a runtime\npermission in the OS.</section><section id=miui class=level5 data-number=6.7.15.0.2><h5 data-number=6.7.15.0.2><span class=header-section-number>6.7.15.0.2</span> MIUI<a href=#miui class=anchor aria-hidden=true></a></h5><p>Fixed permission denied issues in the installer due to a framework\nissue introduced in MIUI 12.5.</section><section id=motorola class=level5 data-number=6.7.15.0.3><h5 data-number=6.7.15.0.3><span class=header-section-number>6.7.15.0.3</span> Motorola<a href=#motorola class=anchor aria-hidden=true></a></h5><p>Fixed crashes in the Interceptor page due to a framework issue\nintroduced in Android 11.</section></section><section id=others-2 class=level3 data-number=6.7.16><h3 data-number=6.7.16><span class=header-section-number>6.7.16</span> <a href=#toc:others-2>Others</a><a href=#others-2 class=anchor aria-hidden=true></a></h3><ul class=incremental><li><p>Improved Java-Smali conversion by including all the subclasses\nduring conversion<li><p>Improved scanning performance in the Scanner page<li><p>Improved updating the list of apps in the Main page<li><p>Scan all the available paths to detect systemless-ly installed\nsystem apps<li><p><code>vacuum</code> SQLite database before opening it for viewing\nor editing.</ul></section></section><section id=sec:v3.0.0-(410) class=level2 data-number=6.8><h2 data-number=6.8><span class=header-section-number>6.8</span> <a href=#toc:sec:v3.0.0-(410)>v3.0.0 (410)</a><a href=#sec:v3.0.0-(410) class=anchor aria-hidden=true></a></h2><p>App Manager v3.0.0 comes with a lot of features and improvements. See\n<a href=app-manager://settings/about/version>Settings > About >\nVersion/Changelog</a> to see a more detailed changelog.<section id=material-3-and-more class=level3 data-number=6.8.1><h3 data-number=6.8.1><span class=header-section-number>6.8.1</span>\n<a href=#toc:material-3-and-more>Material 3 and More</a><a href=#material-3-and-more class=anchor aria-hidden=true></a></h3><p>Material 3, somewhat similar to <em>Material You</em>, is a\nsignificant improvement over Material Design 2 with support for dynamic\ncolours in Android 12 and later. In addition, many design changes have\nbeen made in App Manager without any significant changes in the overall\nuser experience.<section id=known-issue-3 class=level5 data-number=6.8.1.0.1><h5 data-number=6.8.1.0.1><span class=header-section-number>6.8.1.0.1</span> Known issue<a href=#known-issue-3 class=anchor aria-hidden=true></a></h5><p>Switches are still based on Material Design 2 which will be fixed in\na future release.</section></section><section id=wireless-debugging class=level3 data-number=6.8.2><h3 data-number=6.8.2><span class=header-section-number>6.8.2</span>\n<a href=#toc:wireless-debugging>Wireless Debugging</a><a href=#wireless-debugging class=anchor aria-hidden=true></a></h3><p>Wireless debugging support has been fully implemented. Head over to\n§<a href=#sec:wireless-debugging data-reference-type=ref data-reference=sec:wireless-debugging>3.2</a> for instructions on how\nto configure wireless debugging.<div class=\"amalert tip\"><p><strong><em>No-root users.</em></strong><p>Due to auto-detection feature, startup time might be large for\nno-root users when the mode of operation is set to <em>auto</em>.\nInstead, no-root users should select <em>no-root</em> instead of\n<em>auto</em>.</div></section><section id=languages class=level3 data-number=6.8.3><h3 data-number=6.8.3><span class=header-section-number>6.8.3</span>\n<a href=#toc:languages>Languages</a><a href=#languages class=anchor aria-hidden=true></a></h3><p>App Manager is fully translated into Indonesian and Italian languages\nand can be enabled in settings. Bengali is removed due to lack of\ntranslators.</section><section id=introducing-app-explorer class=level3 data-number=6.8.4><h3 data-number=6.8.4><span class=header-section-number>6.8.4</span>\n<a href=#toc:introducing-app-explorer>Introducing App Explorer</a><a href=#introducing-app-explorer class=anchor aria-hidden=true></a></h3><p>App Explorer can be used to browse the contents of an application.\nThis includes binary XML files, DEX contents or any other media files.\nDEX contents can only be explored in Android Oreo (Android 8) and later.\nIt’s also possible to convert an <code>.smali</code> file into\n<code>.java</code> for a better understanding of the reversed code. This\nfeature, if not needed, can be disabled in Settings > Enable/disable\nfeatures.</section><section id=import-backups-from-other-applications class=level3 data-number=6.8.5><h3 data-number=6.8.5><span class=header-section-number>6.8.5</span>\n<a href=#toc:import-backups-from-other-applications>Import Backups\nfrom Other Applications</a><a href=#import-backups-from-other-applications class=anchor aria-hidden=true></a></h3><p>It is possible to import backups from discontinued or obsolete\napplications such as Titanium Backup, OAndBackup and Swift Backup\n(version 3.0 to 3.2). Go to Setting > Backup/restore to find this\noption.</section><section id=virustotal class=level3 data-number=6.8.6><h3 data-number=6.8.6><span class=header-section-number>6.8.6</span>\n<a href=#toc:virustotal>VirusTotal</a><a href=#virustotal class=anchor aria-hidden=true></a></h3><p>VirusTotal is a widely used tool to scan files and URLs for viruses.\nIn the scanner page and in the running apps page, an option to scan\nfiles with VirusTotal has been added. But the option is hidden by\ndefault. To enable the option, it is necessary to obtain an API key from\nVirusTotal. Go to Settings > VirusTotal API Key for more\ninformation.<div class=\"amalert warning\"><p><strong><em>Internet feature.</em></strong><p>This is currently the only feature which require an Internet\nconnection. If you wish to use any Internet feature that might also be\nadded in the future, enable <em>Use the Internet</em> in Settings >\nEnable/disable features.</div></section><section id=trigger-profiles-from-the-automation-software class=level3 data-number=6.8.7><h3 data-number=6.8.7><span class=header-section-number>6.8.7</span>\n<a href=#toc:trigger-profiles-from-the-automation-software>Trigger\nProfiles from the Automation Software</a><a href=#trigger-profiles-from-the-automation-software class=anchor aria-hidden=true></a></h3><p>As the implementation of routine operations is being delayed, an\noption to trigger profiles from the external automation software is\nadded. See §<a href=#sec:automating-tasks data-reference-type=ref data-reference=sec:automating-tasks>3.4</a> for instructions on how to\nconfigure profile automation.</section><section id=improved-application-installer class=level3 data-number=6.8.8><h3 data-number=6.8.8><span class=header-section-number>6.8.8</span>\n<a href=#toc:improved-application-installer>Improved Application\nInstaller</a><a href=#improved-application-installer class=anchor aria-hidden=true></a></h3><p>Application installer includes several improvements including the\nability to downgrade applications in no-root mode, installing multiple\napplications at once and blocking trackers after installation. In\nAndroid 12 and later, no-root users can update applications without any\nuser interactions.</section><section id=component-blocking class=level3 data-number=6.8.9><h3 data-number=6.8.9><span class=header-section-number>6.8.9</span>\n<a href=#toc:component-blocking>Component Blocking</a><a href=#component-blocking class=anchor aria-hidden=true></a></h3><p>It is now possible to configure how App Manager should block a\ncomponent. Visit Settings > Rules > Default blocking method for\nmore information. In the components tab, long clicking the block/unblock\nbutton opens a context menu which allows per-component blocking in a\nsimilar manner. ADB users can also block the components of a <em>Test\nonly</em> app.</section><section id=advanced-searching class=level3 data-number=6.8.10><h3 data-number=6.8.10><span class=header-section-number>6.8.10</span> <a href=#toc:advanced-searching>Advanced Searching</a><a href=#advanced-searching class=anchor aria-hidden=true></a></h3><p>In some pages, the search bar supports additional searching which\nincludes searching via prefix, suffix or even regular expressions. In\nthe main page, it is also possible to search for applications using the\nfirst letters of each word, e.g. <em>App Manager</em> can be listed by\nsearching for <em>am</em>.</section><section id=shared-libraries class=level3 data-number=6.8.11><h3 data-number=6.8.11><span class=header-section-number>6.8.11</span> <a href=#toc:shared-libraries>Shared Libraries</a><a href=#shared-libraries class=anchor aria-hidden=true></a></h3><p>Shared libraries tab has received a significant improvements. It can\ndisplay three types of libraries, such as native, jar and APK files.</section><section id=make-the-best-use-of-interceptor class=level3 data-number=6.8.12><h3 data-number=6.8.12><span class=header-section-number>6.8.12</span> <a href=#toc:make-the-best-use-of-interceptor>Make the Best Use of\nInterceptor</a><a href=#make-the-best-use-of-interceptor class=anchor aria-hidden=true></a></h3><p>Activity interceptor can be opened directly from the activities tab\nby long clicking on the launch button, and similarly, activities can be\nlaunched from the activity interceptor page with or without root, for\nany users.<div class=\"amalert tip\"><p><strong><em>Notice.</em></strong><p>Currently, activities opened via root cannot send the results back to\nthe original applications.</div></section><section id=widget-screen-time class=level3 data-number=6.8.13><h3 data-number=6.8.13><span class=header-section-number>6.8.13</span> <a href=#toc:widget-screen-time>Widget: Screen Time</a><a href=#widget-screen-time class=anchor aria-hidden=true></a></h3><p>Screen time widget is quite similar to Digital Wellbeing’s widget by\nthe same name. It displays the total screen time for the day along with\nthe top three apps from all users.</section><section id=widget-clear-cache class=level3 data-number=6.8.14><h3 data-number=6.8.14><span class=header-section-number>6.8.14</span> <a href=#toc:widget-clear-cache>Widget: Clear Cache</a><a href=#widget-clear-cache class=anchor aria-hidden=true></a></h3><p>Clear cache widget can be to clear cache from all the applications\ndirectly from the home screen.</section></section><section id=sec:v2.6.0-(385) class=level2 data-number=6.9><h2 data-number=6.9><span class=header-section-number>6.9</span> <a href=#toc:sec:v2.6.0-(385)>v2.6.0 (385)</a><a href=#sec:v2.6.0-(385) class=anchor aria-hidden=true></a></h2><section id=introducing-backups class=level3 data-number=6.9.1><h3 data-number=6.9.1><span class=header-section-number>6.9.1</span>\n<a href=#toc:introducing-backups>Introducing Backups</a><a href=#introducing-backups class=anchor aria-hidden=true></a></h3><p>Back up/restore feature is now finally out of beta! Read <a href=#sec:backup-restore>the corresponding guide</a> to understand how\nit works.</section><section id=introducing-log-viewer class=level3 data-number=6.9.2><h3 data-number=6.9.2><span class=header-section-number>6.9.2</span>\n<a href=#toc:introducing-log-viewer>Introducing Log Viewer</a><a href=#introducing-log-viewer class=anchor aria-hidden=true></a></h3><p><a href=#subsubsec:log-viewer>Log viewer</a> is essentially a\nfront-end for <code>logcat</code>. It can be used to filter logs by\n<em>tag</em> or <em>pid</em> (process ID), or even by custom filters.\nLog levels AKA verbosity can also be configured. You can also save,\nshare and manage logs.</section><section id=lock-app-manager class=level3 data-number=6.9.3><h3 data-number=6.9.3><span class=header-section-number>6.9.3</span>\n<a href=#toc:lock-app-manager>Lock App Manager</a><a href=#lock-app-manager class=anchor aria-hidden=true></a></h3><p><a href=#subsubsec:screen-lock>Lock App Manager</a> with the screen\nlock configured for your device.</section><section id=extended-modes-for-app-ops class=level3 data-number=6.9.4><h3 data-number=6.9.4><span class=header-section-number>6.9.4</span>\n<a href=#toc:extended-modes-for-app-ops>Extended Modes for App\nOps</a><a href=#extended-modes-for-app-ops class=anchor aria-hidden=true></a></h3><p>You can set any mode for any app ops that your device supports,\neither from the <a href=#subsec:set-mode-for-app-ops-dots>1-click ops\npage</a> or from the <a href=#subsubsec:app-ops>app ops tab</a>.</section><section id=new-batch-ops-add-to-profile class=level3 data-number=6.9.5><h3 data-number=6.9.5><span class=header-section-number>6.9.5</span>\n<a href=#toc:new-batch-ops-add-to-profile>New Batch Ops: Add to\nProfile</a><a href=#new-batch-ops-add-to-profile class=anchor aria-hidden=true></a></h3><p>You can now easily add selected apps to an existing profile using the\nbatch operations.</section><section id=app-info-improved class=level3 data-number=6.9.6><h3 data-number=6.9.6><span class=header-section-number>6.9.6</span>\n<a href=#toc:app-info-improved>App Info: Improved</a><a href=#app-info-improved class=anchor aria-hidden=true></a></h3><p>App info tab now has many options, including the ability to change <a href=#sec:terminologies>SSAID</a>, network policy (i.e. background\nnetwork usage), battery optimization, etc. Most of the tags used in this\ntab are also clickable, and if you click on them, you will be able to\nlook at the current state or configure them right away.</section><section id=advanced-sort-and-filtering-options-in-the-main-page class=level3 data-number=6.9.7><h3 data-number=6.9.7><span class=header-section-number>6.9.7</span>\n<a href=#toc:advanced-sort-and-filtering-options-in-the-main-page>Advanced\nSort and Filtering Options in the Main Page</a><a href=#advanced-sort-and-filtering-options-in-the-main-page class=anchor aria-hidden=true></a></h3><p>Sort and filter options are now replaced by <a href=#subsubsec:main-list-options>List Options</a> which is highly\nconfigurable, including the ability to filter using profiles.</section><section id=about-this-device class=level3 data-number=6.9.8><h3 data-number=6.9.8><span class=header-section-number>6.9.8</span>\n<a href=#toc:about-this-device>About This Device</a><a href=#about-this-device class=anchor aria-hidden=true></a></h3><p>Interested in knowing about your device in just one page? Go to the\nbottom of the <a href=#subsec:device-info>settings page</a>.</section><section id=enabledisable-features class=level3 data-number=6.9.9><h3 data-number=6.9.9><span class=header-section-number>6.9.9</span>\n<a href=#toc:enabledisable-features>Enable/disable Features</a><a href=#enabledisable-features class=anchor aria-hidden=true></a></h3><p>Not interested in all the features that AM offers? You can disable\nsome features in <a href=#subsubsec:enable/disable-features>settings</a>.</section><section id=new-languages-1 class=level3 data-number=6.9.10><h3 data-number=6.9.10><span class=header-section-number>6.9.10</span> <a href=#toc:new-languages-1>New Languages</a><a href=#new-languages-1 class=anchor aria-hidden=true></a></h3><p>AM now has more than 19 languages! New languages include Farsi,\nJapanese and Traditional Chinese.</section><section id=signing-the-apk-files class=level3 data-number=6.9.11><h3 data-number=6.9.11><span class=header-section-number>6.9.11</span> <a href=#toc:signing-the-apk-files>Signing the APK Files</a><a href=#signing-the-apk-files class=anchor aria-hidden=true></a></h3><p>You can now import external signing keys in AM! For security, App\nManager has its own encrypted KeyStore which can also be <a href=#subsubsec:import/export-keystore>imported or exported</a>.</section><section id=new-extension-unapkm class=level3 data-number=6.9.12><h3 data-number=6.9.12><span class=header-section-number>6.9.12</span> <a href=#toc:new-extension-unapkm>New Extension: UnAPKM</a><a href=#new-extension-unapkm class=anchor aria-hidden=true></a></h3><p>Since APKMirror has removed encryption from their APKM files, it’s no\nlonger necessary to decrypt them. As a result, the option to decrypt\nAPKM files has been removed. Instead, this option is now provided by the\nUnAPKM extension which you can grab from <a href=https://f-droid.org/packages/io.github.muntashirakon.unapkm/>F-Droid</a>.\nSo, if you have an encrypted APKM file and have this extension\ninstalled, you can open the file directly in AM.</section></section><section id=sec:v2.5.20-(375) class=level2 data-number=6.10><h2 data-number=6.10><span class=header-section-number>6.10</span>\n<a href=#toc:sec:v2.5.20-(375)>v2.5.20 (375)</a><a href=#sec:v2.5.20-(375) class=anchor aria-hidden=true></a></h2><section id=subsec:introducing-profiles class=level3 data-number=6.10.1><h3 data-number=6.10.1><span class=header-section-number>6.10.1</span> <a href=#toc:subsec:introducing-profiles>Introducing Profiles</a><a href=#subsec:introducing-profiles class=anchor aria-hidden=true></a></h3><p><a href=#sec:profile-page>Profiles</a> finally closes the <a href=https://github.com/MuntashirAkon/AppManager/issues/72>related\nissue</a>. Profiles can be used to execute certain tasks repeatedly\nwithout doing everything manually. A profile can be applied (or invoked)\neither from the <a href=#sec:profiles-page>Profiles page</a> or from\nthe home screen by creating shortcuts. There are also some presets which\nconsist of debloating profiles taken from <a href=https://gitlab.com/W1nst0n/universal-android-debloater>Universal\nAndroid Debloater</a>.<section id=known-limitations class=level5 data-number=6.10.1.0.1><h5 data-number=6.10.1.0.1><span class=header-section-number>6.10.1.0.1</span> Known limitations<a href=#known-limitations class=anchor aria-hidden=true></a></h5><ul class=incremental><li><p>Exporting rules and applying permissions are not currently\nworking.<li><p>Profiles are applied for all users.</ul></section></section><section id=subsec:the-interceptor class=level3 data-number=6.10.2><h3 data-number=6.10.2><span class=header-section-number>6.10.2</span> <a href=#toc:subsec:the-interceptor>The Interceptor</a><a href=#subsec:the-interceptor class=anchor aria-hidden=true></a></h3><p><a href=https://github.com/MuntashirAkon/intent-intercept>Intent\nIntercept</a> works as a man-in-the-middle between source and\ndestination, that is, when you open a file or URL with another app, you\ncan see what is being shared by opening it with Interceptor first. You\ncan also add or modify the intents before sending them to the\ndestination. Additionally, you can double-click on any exportable\nactivities in the Activities tab in the App Details page to open them in\nthe Interceptor to add more configurations.<section id=known-limitation-2 class=level5 data-number=6.10.2.0.1><h5 data-number=6.10.2.0.1><span class=header-section-number>6.10.2.0.1</span> Known limitation<a href=#known-limitation-2 class=anchor aria-hidden=true></a></h5><p>Editing extras is not currently possible.</section></section><section id=subsec:unapkm:-dedrm-the-apkm-files class=level3 data-number=6.10.3><h3 data-number=6.10.3><span class=header-section-number>6.10.3</span> <a href=#toc:subsec:unapkm:-dedrm-the-apkm-files>UnAPKM: DeDRM the APKM\nfiles</a><a href=#subsec:unapkm:-dedrm-the-apkm-files class=anchor aria-hidden=true></a></h3><p>When I released a small tool called <a href=https://f-droid.org/en/packages/io.github.muntashirakon.unapkm>UnAPKM</a>,\nI promised that similar feature will be available in App Manager. I am\nproud to announce that you can open APKM files directly in the App Info\npage or convert them to APKS or install them directly.</section><section id=subsec:multiple-user class=level3 data-number=6.10.4><h3 data-number=6.10.4><span class=header-section-number>6.10.4</span> <a href=#toc:subsec:multiple-user>Multiple user</a><a href=#subsec:multiple-user class=anchor aria-hidden=true></a></h3><p>App manager now supports multiple users! For now, this requires root\nor ADB. But no-root support is also being considered. If you have\nmultiple users enabled and click on an app installed in multiple\nprofiles, an alert prompt will be displayed where you can select the\nuser.</section><section id=vive-la-france class=level3 data-number=6.10.5><h3 data-number=6.10.5><span class=header-section-number>6.10.5</span> <a href=#toc:vive-la-france>Vive la France!</a><a href=#vive-la-france class=anchor aria-hidden=true></a></h3><p>Thanks to the contributors, we have one more addition to the language\nclub: French. You can add more languages or improve existing\ntranslations at <a href=https://hosted.weblate.org/engage/app-manager>Weblate</a>.</section><section id=report-crashes class=level3 data-number=6.10.6><h3 data-number=6.10.6><span class=header-section-number>6.10.6</span> <a href=#toc:report-crashes>Report crashes</a><a href=#report-crashes class=anchor aria-hidden=true></a></h3><p>If App Manager crashes, you can now easily report the crash from the\nnotifications which opens the share options. Crashes are not reported by\nApp Manager, it only redirects you to your favourite Email client.</section><section id=android-11 class=level3 data-number=6.10.7><h3 data-number=6.10.7><span class=header-section-number>6.10.7</span> <a href=#toc:android-11>Android 11</a><a href=#android-11 class=anchor aria-hidden=true></a></h3><p>Added support for Android 11. Not everything may work as expected\nthough.</section><section id=app-installer-improvements class=level3 data-number=6.10.8><h3 data-number=6.10.8><span class=header-section-number>6.10.8</span> <a href=#toc:app-installer-improvements>App Installer Improvements</a><a href=#app-installer-improvements class=anchor aria-hidden=true></a></h3><section id=set-installation-locations class=level4 data-number=6.10.8.1><h4 data-number=6.10.8.1><span class=header-section-number>6.10.8.1</span> Set installation\nlocations<a href=#set-installation-locations class=anchor aria-hidden=true></a></h4><p>In settings page, you can set install locations such as auto\n(default), internal only and prefer external.</section><section id=set-apk-installer class=level4 data-number=6.10.8.2><h4 data-number=6.10.8.2><span class=header-section-number>6.10.8.2</span> Set APK installer<a href=#set-apk-installer class=anchor aria-hidden=true></a></h4><p>In settings page, you can also set default APK installer (root/ADB\nonly) instead of App Manager.</section><section id=multiple-users class=level4 data-number=6.10.8.3><h4 data-number=6.10.8.3><span class=header-section-number>6.10.8.3</span> Multiple users<a href=#multiple-users class=anchor aria-hidden=true></a></h4><p>In settings page, you can allow App Manager to display multiple users\nduring APK installation.</section><section id=signing-apk-files class=level4 data-number=6.10.8.4><h4 data-number=6.10.8.4><span class=header-section-number>6.10.8.4</span> Signing APK files<a href=#signing-apk-files class=anchor aria-hidden=true></a></h4><p>In settings page, you can choose to sign APK files before installing\nthem. You can also select which signature scheme to use in the <em>APK\nsigning</em> option in settings.<section id=known-limitation-3 class=level5 data-number=6.10.8.4.1><h5 data-number=6.10.8.4.1><span class=header-section-number>6.10.8.4.1</span> Known limitation<a href=#known-limitation-3 class=anchor aria-hidden=true></a></h5><p>Currently, only a generic key is used to sign APK files</section></section></section></section><section id=v2.5.17-368 class=level2 data-number=6.11><h2 data-number=6.11><span class=header-section-number>6.11</span>\n<a href=#toc:v2.5.17-368>v2.5.17 (368)</a><a href=#v2.5.17-368 class=anchor aria-hidden=true></a></h2><section id=app-installer class=level3 data-number=6.11.1><h3 data-number=6.11.1><span class=header-section-number>6.11.1</span> <a href=#toc:app-installer>App Installer</a><a href=#app-installer class=anchor aria-hidden=true></a></h3><p>As promised, it is now possible to select splits. AM also provides\nrecommendations based on device configurations. If the app is already\ninstalled, recommendations are provided based on the installed app. It\nis also possible to downgrade to a lower version without data loss if\nthe device has root or ADB. But it should be noted that not all app can\nbe downgraded. Installer is also improved to speed up the installation\nprocess, especially, for root users. If the app has already been\ninstalled and the new (x)apk(s) is newer or older or the same version\nwith a different signature, AM will display a list of changes similar to\n<strong>What’s New</strong> before prompting the user to install the\napp. This is useful if the app has introduced tracker components, new\npermissions, etc.<section id=known-limitations-1 class=level5 data-number=6.11.1.0.1><h5 data-number=6.11.1.0.1><span class=header-section-number>6.11.1.0.1</span> Known Limitations<a href=#known-limitations-1 class=anchor aria-hidden=true></a></h5><ul class=incremental><li><p>Large app can take a long time to fetch app info, and therefore,\nit may take a long time display the installation prompt.<li><p>If the apk is not located in the internal storage, the app has to\nbe cached first which might also take a long time depending on the size\nof the apk.</ul></section></section><section id=scanner-replacement-for-exodus-page class=level3 data-number=6.11.2><h3 data-number=6.11.2><span class=header-section-number>6.11.2</span> <a href=#toc:scanner-replacement-for-exodus-page>Scanner: Replacement for\nExodus Page</a><a href=#scanner-replacement-for-exodus-page class=anchor aria-hidden=true></a></h3><p>Exodus page is now replaced with scanner page. <a href=#sec:scanner-page>Scanner page</a> contains not only a list of\ntrackers but also a list of used libraries. This is just a start. In the\nfuture, this page will contain more in depth analysis of the app.</section><section id=introducing-system-config class=level3 data-number=6.11.3><h3 data-number=6.11.3><span class=header-section-number>6.11.3</span> <a href=#toc:introducing-system-config>Introducing System Config</a><a href=#introducing-system-config class=anchor aria-hidden=true></a></h3><p>System Config lists various system configurations and\nwhitelists/blacklists included in Android by either OEM/vendor, AOSP or\neven some Magisk modules. Root users can access this option from the\noverflow menu in the main page. There isn’t any official documentation\nfor these options therefore it’s difficult to write a complete\ndocumentation for this page. I will gradually add documentations using\nmy own knowledge. However, some functions should be understandable by\ntheir name.</section><section id=more-languages class=level3 data-number=6.11.4><h3 data-number=6.11.4><span class=header-section-number>6.11.4</span> <a href=#toc:more-languages>More Languages</a><a href=#more-languages class=anchor aria-hidden=true></a></h3><p>Thanks to the contributors, AM now has more than 12 languages. New\nlanguages include Bengali, Hindi, Norwegian, Polish, Russian, Simplified\nChinese, Turkish and Ukrainian.</section><section id=app-info-tab class=level3 data-number=6.11.5><h3 data-number=6.11.5><span class=header-section-number>6.11.5</span> <a href=#toc:app-info-tab>App Info Tab</a><a href=#app-info-tab class=anchor aria-hidden=true></a></h3><p>More tags are added in the <a href=#subsec:app-info-tab>app info\ntab</a> such as <strong>KeyStore</strong> (apps with KeyStore items),\n<strong>Systemless app</strong> (apps installed via Magisk),\n<strong>Running</strong> (apps that are running). For external apk, two\nmore options are added namely <strong>Reinstall</strong> and\n<strong>Downgrade</strong>. Now it is possible to share an apk via\nBluetooth. For system apps, it is possible to uninstall updates for\nroot/ADB users. But like the similar option in the system settings, this\noperation will clear all app data. As stated above, exodus has been\nreplaced with scanner.</section><section id=navigation-improvements class=level3 data-number=6.11.6><h3 data-number=6.11.6><span class=header-section-number>6.11.6</span> <a href=#toc:navigation-improvements>Navigation Improvements</a><a href=#navigation-improvements class=anchor aria-hidden=true></a></h3><p>It’s now relatively easy to navigate to various UI components using\nkeyboard. You can use up/down button to navigate between list items and\ntab button to navigate to UI components inside an item.</section><section id=running-apps-page class=level3 data-number=6.11.7><h3 data-number=6.11.7><span class=header-section-number>6.11.7</span> <a href=#toc:running-apps-page>Running Apps Page</a><a href=#running-apps-page class=anchor aria-hidden=true></a></h3><p>It is now possible to sort and filter processes in this tab. Also,\nthe three big buttons are replaced with an easy-to-use three dot menu.\nPreviously the memory usage was wrong which is fixed in this\nversion.</section><section id=built-in-toybox class=level3 data-number=6.11.8><h3 data-number=6.11.8><span class=header-section-number>6.11.8</span> <a href=#toc:built-in-toybox>Built-in Toybox</a><a href=#built-in-toybox class=anchor aria-hidden=true></a></h3><p>Toybox (an alternative to busybox) is bundled with AM. Although\nAndroid has this utility built-in from API 23, toybox is bundled in\norder to prevent buggy implementations and to support API &lt; 23.</section><section id=component-blocker-improvements class=level3 data-number=6.11.9><h3 data-number=6.11.9><span class=header-section-number>6.11.9</span> <a href=#toc:component-blocker-improvements>Component Blocker\nImprovements</a><a href=#component-blocker-improvements class=anchor aria-hidden=true></a></h3><p>Component blocker seemed to be problematic in the previous version,\nespecially when global component blocking is enabled. The issues are\nmostly fixed now.<div class=\"amalert warning\"><p><strong><em>Caution.</em></strong><p>The component blocking mechanism is no longer compatible with v2.5.6\ndue to various security issues. If you have this version, upgrade to\nv2.5.13 or earlier versions first. After that, enable <a href=#subsubsec:instant-component-blocking>global component\nblocking</a> and disable it again.</div></section><section id=improvements-in-the-app-details-page class=level3 data-number=6.11.10><h3 data-number=6.11.10><span class=header-section-number>6.11.10</span> <a href=#toc:improvements-in-the-app-details-page>Improvements in the App\nDetails Page</a><a href=#improvements-in-the-app-details-page class=anchor aria-hidden=true></a></h3><p>Value of various app ops depend on their parent app ops. Therefore,\nwhen you allow/deny an app op, the parent of the app op gets modified.\nThis fixes the issues some users have been complaining regarding some\napp ops that couldn’t be changed.<p>If an app has the target API 23 or less, its permissions cannot be\nmodified using the <code>pm grant …</code> command. Therefore, for such\napps, option to toggle permission has been disabled.<p>The signature tab is improved to support localization. It also\ndisplays multiple checksums for a signature.</section><section id=app-manifest class=level3 data-number=6.11.11><h3 data-number=6.11.11><span class=header-section-number>6.11.11</span> <a href=#toc:app-manifest>App Manifest</a><a href=#app-manifest class=anchor aria-hidden=true></a></h3><p>Manifest no longer crashes if the size of the manifest is too long.\nGenerated manifest are now more accurate than before.</section></section><section id=v2.5.13-348 class=level2 data-number=6.12><h2 data-number=6.12><span class=header-section-number>6.12</span>\n<a href=#toc:v2.5.13-348>v2.5.13 (348)</a><a href=#v2.5.13-348 class=anchor aria-hidden=true></a></h2><section id=bundled-app-split-apk class=level3 data-number=6.12.1><h3 data-number=6.12.1><span class=header-section-number>6.12.1</span> <a href=#toc:bundled-app-split-apk>Bundled App (Split APK)</a><a href=#bundled-app-split-apk class=anchor aria-hidden=true></a></h3><p>Bundled app formats such as <strong>apks</strong> and\n<strong>xapk</strong> are now supported. You can install these apps\nusing the regular installation buttons. For root and adb users, apps are\ninstalled using shell, and for non-root users, the platform default\nmethod is used.<section id=known-limitations-2 class=level5 data-number=6.12.1.0.1><h5 data-number=6.12.1.0.1><span class=header-section-number>6.12.1.0.1</span> Known Limitations<a href=#known-limitations-2 class=anchor aria-hidden=true></a></h5><ul class=incremental><li><p>Currently <em>all</em> splits apks are installed. But this\nbehaviour is going to change in the next release. If you only need a few\nsplits instead of all, extract the <strong>APKS</strong> or\n<strong>XAPK</strong> file, and then, create a new zip file with your\ndesired split apks and replace the <strong>ZIP</strong> extension with\n<strong>APKS</strong>. Now, open it with AM.<li><p>There is no progress dialog to display the installation\nprogress.</ul></section></section><section id=direct-install-support class=level3 data-number=6.12.2><h3 data-number=6.12.2><span class=header-section-number>6.12.2</span> <a href=#toc:direct-install-support>Direct Install Support</a><a href=#direct-install-support class=anchor aria-hidden=true></a></h3><p>You can now install <strong>APK</strong>, <strong>APKS</strong> or\n<strong>XAPK</strong> directly from your favourite browser or file\nmanager. For apps that need updates, a <strong>What’s New</strong>\ndialog is displayed showing the changes in the new version.<section id=known-limitations-3 class=level5 data-number=6.12.2.0.1><h5 data-number=6.12.2.0.1><span class=header-section-number>6.12.2.0.1</span> Known Limitations<a href=#known-limitations-3 class=anchor aria-hidden=true></a></h5><ul class=incremental><li><p>Downgrade is not yet possible.<li><p>There is no progress dialog to display the installation progress.\nIf you cannot interact with the current page, wait until the\ninstallation is finished.</ul></section></section><section id=remove-all-blocking-rules class=level3 data-number=6.12.3><h3 data-number=6.12.3><span class=header-section-number>6.12.3</span> <a href=#toc:remove-all-blocking-rules>Remove All Blocking Rules</a><a href=#remove-all-blocking-rules class=anchor aria-hidden=true></a></h3><p>In the Settings page, a new option is added which can be used to\nremove all blocking rules configured within App Manager.</section><section id=app-ops-1 class=level3 data-number=6.12.4><h3 data-number=6.12.4><span class=header-section-number>6.12.4</span> <a href=#toc:app-ops-1>App\nOps</a><a href=#app-ops-1 class=anchor aria-hidden=true></a></h3><ul class=incremental><li><p>App Ops are now generated using a technique similar to AppOpsX.\nThis should decrease the loading time significantly in the App Ops\ntab.<li><p>In the App Ops tab, a menu item is added which can be used to\nlist only active app ops without including the default app ops. The\npreference is saved in the shared preferences.</ul><section id=known-limitation-4 class=level5 data-number=6.12.4.0.1><h5 data-number=6.12.4.0.1><span class=header-section-number>6.12.4.0.1</span> Known Limitation<a href=#known-limitation-4 class=anchor aria-hidden=true></a></h5><p>Often the App Ops tab may not be responsive. If that’s the case,\nrestart App Manager.</section></section><section id=enhanced-adb-support class=level3 data-number=6.12.5><h3 data-number=6.12.5><span class=header-section-number>6.12.5</span> <a href=#toc:enhanced-adb-support>Enhanced ADB Support</a><a href=#enhanced-adb-support class=anchor aria-hidden=true></a></h3><p>ADB shell commands are now executed using a technique similar to\nAppOpsX (This is the <em>free</em> alternative of AppOps by Rikka.).\nThis should dramatically increase the execution time.<section id=known-limitation-5 class=level5 data-number=6.12.5.0.1><h5 data-number=6.12.5.0.1><span class=header-section-number>6.12.5.0.1</span> Known Limitation<a href=#known-limitation-5 class=anchor aria-hidden=true></a></h5><p>AM can often crash or become not responsive. If that’s the case,\nrestart App Manager.</section></section><section id=filtering-in-main-page class=level3 data-number=6.12.6><h3 data-number=6.12.6><span class=header-section-number>6.12.6</span> <a href=#toc:filtering-in-main-page>Filtering in Main Page</a><a href=#filtering-in-main-page class=anchor aria-hidden=true></a></h3><p>Add an option to filter apps that has at least one activity.</section><section id=apk-backupsharing class=level3 data-number=6.12.7><h3 data-number=6.12.7><span class=header-section-number>6.12.7</span> <a href=#toc:apk-backupsharing>Apk Backup/Sharing</a><a href=#apk-backupsharing class=anchor aria-hidden=true></a></h3><p>Apk files are now saved as <code>app name_version.extension</code>\ninstead of <code>package.name.extension</code>.</section><section id=batch-ops class=level3 data-number=6.12.8><h3 data-number=6.12.8><span class=header-section-number>6.12.8</span> <a href=#toc:batch-ops>Batch Ops</a><a href=#batch-ops class=anchor aria-hidden=true></a></h3><ul class=incremental><li><p>Added a foreground service to run batch operations. The result of\nthe operation is displayed in a notification. If an operation has failed\nfor some packages, clicking on the notification will open a dialog box\nlisting the failed packages. There is also a <strong>Try Again</strong>\nbutton on the bottom which can be used to perform the operation again\nfor the failed packages.<li><p>Replaced Linux <em>kill</em> with\n<strong>force-stop</strong>.</ul></section><section id=translations class=level3 data-number=6.12.9><h3 data-number=6.12.9><span class=header-section-number>6.12.9</span> <a href=#toc:translations>Translations</a><a href=#translations class=anchor aria-hidden=true></a></h3><p>Added German and Portuguese (Brazilian) translations.<section id=known-limitation-6 class=level5 data-number=6.12.9.0.1><h5 data-number=6.12.9.0.1><span class=header-section-number>6.12.9.0.1</span> Known Limitation<a href=#known-limitation-6 class=anchor aria-hidden=true></a></h5><p>Not all translations are verified yet.</section></section><section id=app-data-backup class=level3 data-number=6.12.10><h3 data-number=6.12.10><span class=header-section-number>6.12.10</span> <a href=#toc:app-data-backup>App Data Backup</a><a href=#app-data-backup class=anchor aria-hidden=true></a></h3><p>Install app only for the current user at the time of restoring\nbackups. Support for split apks is also added.<p><em>Data backup feature is now considered unstable. If you encounter\nany problem, please report to me without hesitation.</em></section></section></section><section id=ch:app-ops class=level1 data-number=7><h1 data-number=7><span class=header-section-number>7</span> <a href=#toc:ch:app-ops>App Ops</a><a href=#ch:app-ops class=anchor aria-hidden=true></a></h1><section id=sec:app-ops-background class=level2 data-number=7.1><h2 data-number=7.1><span class=header-section-number>7.1</span> <a href=#toc:sec:app-ops-background>Background</a><a href=#sec:app-ops-background class=anchor aria-hidden=true></a></h2><p><strong>App Ops</strong> (short hand for <strong>Application\nOperations</strong>) are used by Android system (since Android 4.3) to\ncontrol application permissions. The user <em>can</em> control some\npermissions, but only the permissions that are considered dangerous (and\nGoogle thinks knowing your phone number isn’t a dangerous thing). So,\napp ops seems to be the one we need if we want to install apps like\nFacebook and it’s Messenger (the latter literary records everything if\nyou live outside the EU) and still want <em>some</em> privacy and/or\nsecurity. Although certain features of app ops were available in\nSettings and later in hidden settings in older version of Android, it’s\ncompletely hidden in newer versions of Android and is continued to be\nkept hidden. Now, any app with\n<strong>android.Manifest.permission.GET_APP_OPS_STATS</strong>\npermission can get the app ops information for other applications but\nthis permission is hidden from users and can only be enabled using ADB\nor root. Still, the app with this permission cannot grant or revoke\npermissions (actually mode of operation) for apps other than itself\n(with limited capacity, of course). To modify the ops of other app, the\napp needs\n<strong>android.Manifest.permission.UPDATE_APP_OPS_STATS</strong>\npermissions which isn’t accessible via <code>pm</code> command. So, you\ncannot grant it via root or ADB, the permission is only granted to the\nsystem apps. There are very few apps who support disabling permissions\nvia app ops. The best one to my knowledge is <a href=https://github.com/8enet/AppOpsX>AppOpsX</a>. The main (visible)\ndifference between my app (AppManager) and this app is that the latter\nalso provides you the ability to revoke internet permissions (by writing\nip tables). One crucial problem that I faced during the development of\nthe app ops API is the lack of documentation in English language.</section><section id=sec:introduction-to-app-ops class=level2 data-number=7.2><h2 data-number=7.2><span class=header-section-number>7.2</span> <a href=#toc:sec:introduction-to-app-ops>Introduction to App Ops</a><a href=#sec:introduction-to-app-ops class=anchor aria-hidden=true></a></h2><figure id=fig:appops data-latex-placement=ht><figure><object data=../images/appops.svg type=image/svg+xml></object></figure><figcaption>Figure 2: How app ops work</figcaption></figure><p>Figure <a href=#fig:appops>1</a> describes the process of changing\nand processing permission. <a href=#sec:appopsmanager>AppOpsManager</a> can be used to manage\npermissions in Settings app. <strong>AppOpsManager</strong> is also\nuseful in determining if a certain permission (or operation) is granted\nto the application. Most of the methods of\n<strong>AppOpsManager</strong> are accessible to the user app but unlike\na system app, it can only be used to check permissions for any app or\nfor the app itself and start or terminating certain operations.\nMoreover, not all operations are actually accessible from this Java\nclass. <strong>AppOpsManager</strong> holds all the necessary constants\nsuch as <a href=#subsec:op-constants><code>OP_*</code></a>,\n<code>OPSTR_*</code>, <a href=#subsec:mode-constants><code>MODE_*</code></a> which describes\noperation code, operation string and mode of operations respectively. It\nalso holds necessary data structures such as <a href=#subsec:package-ops>PackageOps</a> and <strong>OpEntry</strong>.\n<strong>PackageOps</strong> holds <strong>OpEntry</strong> for a\npackage, and <strong>OpEntry</strong>, as the name suggests, describes\neach operation.<p><code>AppOpService</code> is completely hidden from a user\napplication but accessible to the system applications. As it can be seen\nin Figure <a href=#fig:appops>1</a>, this is the class that does the\nactual management stuff. It contains data structures such as\n<strong>Ops</strong> to store basic package info and <strong>Op</strong>\nwhich is similar to <strong>OpEntry</strong> of\n<strong>AppOpsManager</strong>. It also has <strong>Shell</strong> which\nis actually the source code of the <a href=#sec:appops-cli><em>appops</em> command line tool</a>. It writes\nconfigurations to or read configurations from <a href=#sec:appops-xml><code>/data/system/appops.xml</code></a>. System\nservices calls <strong>AppOpsService</strong> to find out what an\napplication is allowed and what is not allowed to perform, and\n<strong>AppOpsService</strong> determines these permissions by parsing\n<code>/data/system/appops.xml</code>. If no custom values are present in\n<em>appops.xml</em>, it returns the default mode available in\n<strong>AppOpsManager</strong>.</section><section id=sec:appopsmanager class=level2 data-number=7.3><h2 data-number=7.3><span class=header-section-number>7.3</span> <a href=#toc:sec:appopsmanager>AppOpsManager</a><a href=#sec:appopsmanager class=anchor aria-hidden=true></a></h2><p><a href=https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/app/AppOpsManager.java>AppOpsManager</a>\nstands for application operations manager. It consists of various\nconstants and classes to modify app operations.<div class=seealso-inline><p><em>See also: <span><a href=https://developer.android.com/reference/android/app/AppOpsManager>AppOpsManager\ndocumentation</a></span></em></div><section id=subsec:op-constants class=level3 data-number=7.3.1><h3 data-number=7.3.1><span class=header-section-number>7.3.1</span>\n<a href=#toc:subsec:op-constants><code>OP_*</code> Constants</a><a href=#subsec:op-constants class=anchor aria-hidden=true></a></h3><p><code>OP_*</code> are the integer constants starting from\n<code>0</code>. <code>OP_NONE</code> implies that no operations are\nspecified whereas <code>_NUM_OP</code> denotes the number of operations\ndefined in <code>OP_*</code> prefix. While they denote each operation,\nthe operations are not necessarily unique. In fact, there are many\noperations that are actually a single operation denoted by multiple\n<code>OP_*</code> constant (possibly for future use). Vendors may define\ntheir own op based on their requirements. MIUI is one of the vendors who\nare known to do that.<div class=listing><div class=sourceCode id=cb11 data-frame=lines><pre class=\"sourceCode java\"><code class=\"sourceCode java\"><span id=cb11-1><a href=#cb11-1 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=dt>final</span> <span class=dt>int</span> OP_NONE <span class=op>=</span> <span class=op>-</span><span class=dv>1</span><span class=op>;</span></span>\n<span id=cb11-2><a href=#cb11-2 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=dt>final</span> <span class=dt>int</span> OP_COARSE_LOCATION <span class=op>=</span> <span class=dv>0</span><span class=op>;</span></span>\n<span id=cb11-3><a href=#cb11-3 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=dt>final</span> <span class=dt>int</span> OP_FINE_LOCATION <span class=op>=</span> <span class=dv>1</span><span class=op>;</span></span>\n<span id=cb11-4><a href=#cb11-4 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=dt>final</span> <span class=dt>int</span> OP_GPS <span class=op>=</span> <span class=dv>2</span><span class=op>;</span></span>\n<span id=cb11-5><a href=#cb11-5 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=dt>final</span> <span class=dt>int</span> OP_VIBRATE <span class=op>=</span> <span class=dv>3</span><span class=op>;</span></span>\n<span id=cb11-6><a href=#cb11-6 aria-hidden=true tabindex=-1></a><span class=kw>...</span></span>\n<span id=cb11-7><a href=#cb11-7 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=dt>final</span> <span class=dt>int</span> OP_READ_DEVICE_IDENTIFIERS <span class=op>=</span> <span class=dv>89</span><span class=op>;</span></span>\n<span id=cb11-8><a href=#cb11-8 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=dt>final</span> <span class=dt>int</span> OP_ACCESS_MEDIA_LOCATION <span class=op>=</span> <span class=dv>90</span><span class=op>;</span></span>\n<span id=cb11-9><a href=#cb11-9 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=dt>final</span> <span class=dt>int</span> OP_ACTIVATE_PLATFORM_VPN <span class=op>=</span> <span class=dv>91</span><span class=op>;</span></span>\n<span id=cb11-10><a href=#cb11-10 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=dt>final</span> <span class=dt>int</span> _NUM_OP <span class=op>=</span> <span class=dv>92</span><span class=op>;</span></span></code></pre></div></div><p>Whether an operation is unique is defined by\n<code>sOpToSwitch</code>. It maps each operation to another operation or\nto itself (if it’s a unique operation). For instance,\n<code>OP_FINE_LOCATION</code> and <code>OP_GPS</code> are mapped to\n<code>OP_COARSE_LOCATION</code>.<p>Each operation has a private name which are described by\n<code>sOpNames</code>. These names are usually the same names as the\nconstants without the <code>OP_</code> prefix. Some operations have\npublic names as well which are described by <code>sOpToString</code>.\nFor instance, <code>OP_COARSE_LOCATION</code> has the public name\n<strong>android:coarse_location</strong>.<p>As a gradual process of moving permissions to app ops, there are\nalready many permissions that are defined under some operations. These\npermissions are mapped in <code>sOpPerms</code>. For example, the\npermission\n<strong>android.Manifest.permission.ACCESS_COARSE_LOCATION</strong> is\nmapped to <code>OP_COARSE_LOCATION</code>. Some operations may not have\nany associated permissions which have <code>null</code> values.<p>As described in the previous section, operations that are configured\nfor an app are stored at <a href=#sec:appops-xml><code>/data/system/appops.xml</code></a>. If an\noperation is not configured, then whether system will allow that\noperation is determined from <code>sOpDefaultMode</code>. It lists the\n<em>default mode</em> for each operation.</section><section id=subsec:mode-constants class=level3 data-number=7.3.2><h3 data-number=7.3.2><span class=header-section-number>7.3.2</span>\n<a href=#toc:subsec:mode-constants><code>MODE_*</code> Constants</a><a href=#subsec:mode-constants class=anchor aria-hidden=true></a></h3><p><code>MODE_*</code> constants also integer constants starting from\n<code>0</code>. These constants are assigned to each operation\ndescribing whether an app is authorised to perform that operation. These\nmodes usually have associated names such as <strong>allow</strong> for\n<code>MODE_ALLOWED</code>, <strong>ignore</strong> for\n<code>MODE_IGNORED</code>, <strong>deny</strong> for\n<code>MODE_ERRORED</code> (a rather misnomer), <strong>default</strong>\nfor <code>MODE_DEFAULT</code> and <strong>foreground</strong> for\n<code>MODE_FOREGROUND</code>.<ol class=incremental><li><p><strong><code>MODE_ALLOWED</code>.</strong> The app is allowed to\nperform the given operation<li><p><strong><code>MODE_IGNORED</code>.</strong> The app is not\nallowed to perform the given operation, and any attempt to perform the\noperation should <em>silently fail</em>, i.e. it should not cause the\napp to crash<li><p><strong><code>MODE_ERRORED</code>.</strong> The app is not\nallowed to perform the given operation, and this attempt should cause it\nto have a fatal error, typically a\n<code>SecurityException</code><li><p><strong><code>MODE_DEFAULT</code>.</strong> The app should use\nits default security check, specified in\n<code>AppOpsManager</code><li><p><strong><code>MODE_FOREGROUND</code>.</strong> Special mode that\nmeans “allow only when app is in foreground.” This mode was added in\nAndroid 10<li><p><strong><code>MODE_ASK</code>.</strong> This is a custom mode\nused by MIUI whose uses are unknown.</ol></section><section id=subsec:package-ops class=level3 data-number=7.3.3><h3 data-number=7.3.3><span class=header-section-number>7.3.3</span>\n<a href=#toc:subsec:package-ops>PackageOps</a><a href=#subsec:package-ops class=anchor aria-hidden=true></a></h3><p><strong>AppOpsManager.PackageOps</strong> is a data structure to\nstore all the <strong>OpEntry</strong> for a package. In simple terms,\nit stores all the customised operations for a package.<div class=listing><div class=sourceCode id=cb12 data-frame=lines><pre class=\"sourceCode java\"><code class=\"sourceCode java\"><span id=cb12-1><a href=#cb12-1 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=kw>class</span> PackageOps <span class=kw>implements</span> Parcelable <span class=op>{</span></span>\n<span id=cb12-2><a href=#cb12-2 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=bu>String</span> mPackageName<span class=op>;</span></span>\n<span id=cb12-3><a href=#cb12-3 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=dt>int</span> mUid<span class=op>;</span></span>\n<span id=cb12-4><a href=#cb12-4 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=bu>List</span><span class=op>&lt;</span>OpEntry<span class=op>&gt;</span> mEntries<span class=op>;</span></span>\n<span id=cb12-5><a href=#cb12-5 aria-hidden=true tabindex=-1></a>    <span class=kw>...</span></span>\n<span id=cb12-6><a href=#cb12-6 aria-hidden=true tabindex=-1></a><span class=op>}</span></span></code></pre></div></div><p>As can be seen in Listing <a href=#lst:package-ops-class>2</a>, it\nstores all <strong>OpEntry</strong> for a package as well as the\ncorresponding package name and its kernel user ID.</section><section id=subsec:opentry class=level3 data-number=7.3.4><h3 data-number=7.3.4><span class=header-section-number>7.3.4</span>\n<a href=#toc:subsec:opentry>OpEntry</a><a href=#subsec:opentry class=anchor aria-hidden=true></a></h3><p><strong>AppOpsManager.OpEntry</strong> is a data structure that\nstores a single operation for any package.<div class=listing><div class=sourceCode id=cb13 data-frame=lines><pre class=\"sourceCode java\"><code class=\"sourceCode java\"><span id=cb13-1><a href=#cb13-1 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=dt>final</span> <span class=kw>class</span> OpEntry <span class=kw>implements</span> Parcelable <span class=op>{</span></span>\n<span id=cb13-2><a href=#cb13-2 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=dt>int</span> mOp<span class=op>;</span></span>\n<span id=cb13-3><a href=#cb13-3 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=dt>boolean</span> mRunning<span class=op>;</span></span>\n<span id=cb13-4><a href=#cb13-4 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=at>@Mode</span> <span class=dt>int</span> mMode<span class=op>;</span></span>\n<span id=cb13-5><a href=#cb13-5 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=at>@Nullable</span> LongSparseLongArray mAccessTimes<span class=op>;</span></span>\n<span id=cb13-6><a href=#cb13-6 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=at>@Nullable</span> LongSparseLongArray mRejectTimes<span class=op>;</span></span>\n<span id=cb13-7><a href=#cb13-7 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=at>@Nullable</span> LongSparseLongArray mDurations<span class=op>;</span></span>\n<span id=cb13-8><a href=#cb13-8 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=at>@Nullable</span> LongSparseLongArray mProxyUids<span class=op>;</span></span>\n<span id=cb13-9><a href=#cb13-9 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=at>@Nullable</span> LongSparseArray<span class=op>&lt;</span><span class=bu>String</span><span class=op>&gt;</span> mProxyPackageNames<span class=op>;</span></span>\n<span id=cb13-10><a href=#cb13-10 aria-hidden=true tabindex=-1></a>    <span class=kw>...</span></span>\n<span id=cb13-11><a href=#cb13-11 aria-hidden=true tabindex=-1></a><span class=op>}</span></span></code></pre></div></div><p>Here:<ul class=incremental><li><p><code>mOp</code>: Denotes one of the <a href=#subsec:op-constants><code>OP_*</code> constants</a><li><p><code>mRunning</code>: Whether the operation is in progress\n(i.e. the operation has started but not finished yet). Not all\noperations can be started or finished this way<li><p><code>mMOde</code>: One of the <a href=#subsec:mode-constants><code>MODE_*</code> constants</a><li><p><code>mAccessTimes</code>: Stores all the available access\ntimes<li><p><code>mRejectTimes</code>: Stores all the available reject\ntimes<li><p><code>mDurations</code>: All available access durations, checking\nthis with <code>mRunning</code> will tell you for how long the app is\nperforming a certain app operation<li><p><code>mProxyUids</code>: No documentation found<li><p><code>mProxyPackageNames:</code> No documentation found</ul></section><section id=subsec:usage class=level3 data-number=7.3.5><h3 data-number=7.3.5><span class=header-section-number>7.3.5</span>\n<a href=#toc:subsec:usage>Usage</a><a href=#subsec:usage class=anchor aria-hidden=true></a></h3><p>TODO</section></section><section id=sec:appopsservice class=level2 data-number=7.4><h2 data-number=7.4><span class=header-section-number>7.4</span> <a href=#toc:sec:appopsservice>AppOpsService</a><a href=#sec:appopsservice class=anchor aria-hidden=true></a></h2><p>TODO</section><section id=sec:appops-xml class=level2 data-number=7.5><h2 data-number=7.5><span class=header-section-number>7.5</span> <a href=#toc:sec:appops-xml>appops.xml</a><a href=#sec:appops-xml class=anchor aria-hidden=true></a></h2><p>Latest <code>appops.xml</code> has the following format: (This DTD is\nmade by me and by no means perfect, has compatibility issues.)<pre><code>&lt;!DOCTYPE app-ops [\n\n&lt;!ELEMENT app-ops (uid|pkg)*&gt;\n&lt;!ATTLIST app-ops v CDATA #IMPLIED&gt;\n\n&lt;!ELEMENT uid (op)*&gt;\n&lt;!ATTLIST uid n CDATA #REQUIRED&gt;\n\n&lt;!ELEMENT pkg (uid)*&gt;\n&lt;!ATTLIST pkg n CDATA #REQUIRED&gt;\n\n&lt;!ELEMENT uid (op)*&gt;\n&lt;!ATTLIST uid\nn CDATA #REQUIRED\np CDATA #IMPLIED&gt;\n\n&lt;!ELEMENT op (st)*&gt;\n&lt;!ATTLIST op\nn CDATA #REQUIRED\nm CDATA #REQUIRED&gt;\n\n&lt;!ELEMENT st EMPTY&gt;\n&lt;!ATTLIST st\nn CDATA #REQUIRED\nt CDATA #IMPLIED\nr CDATA #IMPLIED\nd CDATA #IMPLIED\npp CDATA #IMPLIED\npu CDATA #IMPLIED&gt;\n\n]&gt;</code></pre><p>The instruction below follows the exact order given above:<ul class=incremental><li><p><code>app-ops</code>: The root element. It can contain any number\nof <code>pkg</code> or package <code>uid</code><ul class=incremental><li><p><code>v</code>: (optional, integer) The version number (default:\n<code>NO_VERSION</code> or <code>-1</code>)</ul><li><p><code>pkg</code>: Stores package info. It can contain any number\nof <code>uid</code><ul class=incremental><li><p><code>n</code>: (required, string) Name of the package</ul><li><p>Package <code>uid</code>: Stores package or packages info<ul class=incremental><li><p><code>n</code>: (required, integer) The user ID</ul><li><p><code>uid</code>: The package user ID. It can contain any number\nof <code>op</code><ul class=incremental><li><p><code>n</code>: (required, integer) The user ID<li><p><code>p</code>: (optional, boolean) Is the app is a\nprivate/system app</ul><li><p><code>op</code>: The operation, can contain <code>st</code> or\nnothing at all<ul class=incremental><li><p><code>n</code>: (required, integer) The op name in integer,\ni.e. AppOpsManager.OP_*<li><p><code>m</code>: (required, integer) The op mode,\ni.e. AppOpsManager.MODE_*</ul><li><p><code>st</code>: State of operation: whether the operation is\naccessed, rejected or running (not available on old versions)<ul class=incremental><li><p><code>n</code>: (required, long) Key containing flags and\nuid<li><p><code>t</code>: (optional, long) Access time (default:\n<code>0</code>)<li><p><code>r</code>: (optional, long) Reject time (default:\n<code>0</code>)<li><p><code>d</code>: (optional, long) Access duration (default:\n<code>0</code>)<li><p><code>pp</code>: (optional, string) Proxy package name<li><p><code>pu</code>: (optional, integer) Proxy package uid</ul></ul><p>This definition can be found at <a href=https://android.googlesource.com/platform/frameworks/base/+/master/services/core/java/com/android/server/appop/AppOpsService.java>AppOpsService</a>.</section><section id=sec:appops-cli class=level2 data-number=7.6><h2 data-number=7.6><span class=header-section-number>7.6</span> <a href=#toc:sec:appops-cli>Command Line Interface</a><a href=#sec:appops-cli class=anchor aria-hidden=true></a></h2><p><code>appops</code> or <code>cmd appops</code> (on latest versions)\ncan be accessible via ADB or root. This is an easier method to get or\nupdate any operation for a package (provided the package name is known).\nThe help page of this command is self-explanatory:<pre><code>AppOps service (appops) commands:\nhelp\nPrint this help text.\nstart [--user &lt;USER_ID&gt;] &lt;PACKAGE | UID&gt; &lt;OP&gt;\nStarts a given operation for a particular application.\nstop [--user &lt;USER_ID&gt;] &lt;PACKAGE | UID&gt; &lt;OP&gt;\nStops a given operation for a particular application.\nset [--user &lt;USER_ID&gt;] &lt;[--uid] PACKAGE | UID&gt; &lt;OP&gt; &lt;MODE&gt;\nSet the mode for a particular application and operation.\nget [--user &lt;USER_ID&gt;] &lt;PACKAGE | UID&gt; [&lt;OP&gt;]\nReturn the mode for a particular application and optional operation.\nquery-op [--user &lt;USER_ID&gt;] &lt;OP&gt; [&lt;MODE&gt;]\nPrint all packages that currently have the given op in the given mode.\nreset [--user &lt;USER_ID&gt;] [&lt;PACKAGE&gt;]\nReset the given application or all applications to default modes.\nwrite-settings\nImmediately write pending changes to storage.\nread-settings\nRead the last written settings, replacing current state in RAM.\noptions:\n&lt;PACKAGE&gt; an Android package name or its UID if prefixed by --uid\n&lt;OP&gt;      an AppOps operation.\n&lt;MODE&gt;    one of allow, ignore, deny, or default\n&lt;USER_ID&gt; the user id under which the package is installed. If --user is not\nspecified, the current user is assumed.</code></pre></section></section><section id=footnotes class=\"footnotes footnotes-end-of-document\" role=doc-endnotes><hr><ol><li id=fn1><p>GitHub pull requests will be merged manually using the\ncorresponding patches. As a result, GitHub may wrongfully mark them\nclosed instead of merged.<a href=#fnref1 class=footnote-back role=doc-backlink>↩︎</a><li id=fn2><p>You can also address me as “Muntashir Akon”<a href=#fnref2 class=footnote-back role=doc-backlink>↩︎</a></ol></section>"
  },
  {
    "path": "docs/raw/en/intro/main.tex",
    "content": "% SPDX-License-Identifier: GPL-3.0-or-later OR CC-BY-SA-4.0\n\\chapter{Introduction}\\label{ch:introduction} %%##$introduction-chapter-title>>\n%%!!intro<<\nApp Manager is an advanced package manager for Android. It offers numerous features and thus, requires a user\nmanual to assist its users. This document acts as a user manual for App Manager in the sense that it aims to describe\nevery feature that App Manager has to offer. This document also serves as the ``official'' guidelines for\nApp Manager and represents the expected behavior of App Manager. Translations can misinterpret this document (which is\nin English). Therefore, a capable user should read the English version of the document to get the most out\nof it. There may as well be other unofficial or third-party resources, such as blog articles, videos, forums, and chat\ngroups. While these resources may be useful to many people, they may not be up-to-date with the latest\nversion of App Manager. In case of any deviations detected in App Manager from this document, they should be reported in the\n\\href{https://github.com/MuntashirAkon/AppManager/issues}{App Manager issue tracker}.\n%%!!>>\n\n\n\\section{Terminologies}\\label{sec:terminologies} %%##$terminologies-title>>\n%%!!terminologies<<\n\\begin{itemize}\n    \\item \\textbf{AM} --- Short name for App Manager.\n    \\item \\textbf{Block/Unblock} --- Used for component blocking or unblocking. How components are blocked depends on\n    the user preferences.\n    \\item \\textbf{IFW} --- Short form of Intent Firewall.\n    \\item \\textbf{Ops} --- Short name for operations, e.g.\\ app ops, batch ops, 1-click ops\n    \\item \\textbf{SAF} --- Short for Storage Access Framework, an abstraction used by Android to allow apps to use or\n    serve files without worrying about the underlying file system.\n    \\item \\textbf{SSAID} --- Short form of \\texttt{Settings.Secure.ANDROID\\_ID}. It is a device identifier assigned to\n    each app (Android Oreo onwards). It is generated from the combination of the signing certificate of the app\n    and the SSAID set for the package \\texttt{android}. As a result, it is guaranteed to be the same for an app unless\n    the user chooses to format the device. It is widely used for tracking.\n    \\item \\textbf{Tracker} --- Denotes tracker components throughout the document and in App Manager except in the\n    \\hyperref[sec:scanner-page]{scanner page}. Trackers include libraries such as crash reporters, analytics,\n    profiling, identification, ad, location, etc. Thus, they are not equal in functions. There is no distinction or bias\n    among the open-source and closed-source libraries that promote tracking.\n\\end{itemize}\n%%!!>>\n\n\n\\section{Supported Versions}\\label{sec:supported-versions} %%##$supported-versions-title>>\n%%!!supported-versions<<\nAt present, the supported version is v4.0.1.\nPrevious versions of App Manager may contain security vulnerabilities and should not be used.\n%%!!>>\n\n\n\\section{Official Sources}\\label{sec:official-sources} %%##$official-sources-title>>\n\n\\subsection{Binary Distribution Sources}\\label{subsec:binary-distribution-sources} %%##$bin-sources-title>>\n%%!!bin-sources<<\nApp Manager is distributed using the following sources. Unofficial sources may distribute modified versions of App\nManager, and you alone shall be responsible for the consequences of using such a distribution.\n\\begin{enumerate}\n    \\item Official F-Droid repository.\\\\\n    \\textit{Link:} \\url{https://f-droid.org/packages/io.github.muntashirakon.AppManager}\n    \\item IzzyOnDroid repository.\\\\\n    \\textit{Link:} \\url{https://apt.izzysoft.de/fdroid/index/apk/io.github.muntashirakon.AppManager}\n    \\item GitHub repository.\\\\\n    \\textit{Link:} \\url{https://github.com/MuntashirAkon/AppManager/releases}\n    \\item Telegram.\\\\\n    \\textit{Link:} \\url{https://t.me/AppManagerChannel}\n\\end{enumerate}\n%%!!>>\n\n\\subsection{Links to the Source Code}\\label{subsec:links-to-source-code} %%##$source-code-links-title>>\n%%!!source-code-links<<\nAll but GitHub are mirrors. The tags should always be up-to-date, but the master branch may not.\nIf you want to clone the master branch, use the GitHub link instead of the others.\n%%!!>>\n\\begin{enumerate}\n    \\item GitHub: \\url{https://github.com/MuntashirAkon/AppManager}\n    \\item Codeberg: \\url{https://codeberg.org/muntashir/AppManager}\n    \\item GitLab: \\url{https://gitlab.com/muntashir/AppManager}\n    \\item Riseup: \\url{https://0xacab.org/muntashir/AppManager}\n    \\item sourcehut: \\url{https://git.sr.ht/~muntashir/AppManager}\n\\end{enumerate}\n\n\\subsection{Translations}\\label{subsec:translations} %%##$translations-title>>\n%%!!translations<<\nApp Manager does not accept translations via pull/merge requests. Translations are managed through\nHosted Weblate. To translate App Manager, visit \\url{https://hosted.weblate.org/engage/app-manager/}.\nPlease read the \\textbf{Info} section before getting started.\n%%!!>>\n\n\n\\section{Contributing}\\label{sec:contributing} %%##$contributing-title>>\n%%!!contributing<<\nThere are many ways a user can contribute, such as creating helpful issues, attending discussions,\nimproving documentation and translations, reporting unknown libraries or trackers, reviewing the source code,\nand reporting security vulnerabilities.\n%%!!>>\n\n\\subsection{Build Instructions}\\label{subsec:build-instructions} %%##$buiding-title>>\n%%!!buiding<<\nBuild instructions are available in the BUILDING file located in the source root.\n%%!!>>\n\n\\subsection{Submitting patches}\\label{subsec:submitting-patches} %%##$submit-patches-title>>\n%%!!submit-patches<<\nRepositories located on sites other than GitHub are currently considered mirrors, and pull/merge requests submitted on\nthose sites will not be accepted.\\footnote{GitHub pull requests will be merged manually using the corresponding patches.\nAs a result, GitHub may wrongfully mark them closed instead of merged.} Instead, patches (as \\texttt{.patch} files) can\nbe submitted via email attachments. \\textit{Signing-off is a requirement.} See the CONTRIBUTING file\nlocated at the source root for more information.\n\n\\begin{warning}{Notice}\n    In the case of submitting patches via email, the whole conversation may be publicly accessible in the future.\n    So, please do not include personally identifiable information (PII) other than your name or email address.\n\\end{warning}\n%%!!>>\n\n\n\\section{Donation \\& Funding}\\label{sec:donation-&-funding} %%##$donation-title>>\n%%!!donation<<\n% \\emph{Donation or purchasing is not a requirement in order to use App Manager.} While App Manager does not support any\n% purchases, donations can be sent to the owner of App Manager through Open Source Collective.\n%\n% Open Source Collective is a fiscal host in the Open Collective platform which helps the open source projects manage\n% their finances. At present, it supports payments through bank accounts, PayPal, credit or debit cards and\n% cryptocurrencies.\n%\n% \\textit{Link:} \\url{https://opencollective.com/muntashir}.\n%\n% By sending donations, the senders agree that they shall not use the donations as a leverage to prioritise their\n% requested features. Feature requests do not require any bounties or donations, and they are prioritised in accordance\n% with the preferences of the owner.\n%\n% \\emph{App Manager accepts any offers of funding or grants.} Representatives of the interested organization can contact\n% the owner directly using the options given in \\Sref{sec:contact}.\n\nAs of September 2024, App Manager is not accepting financial support until further notice. But\nyou may still be able to send gifts (e.g., gift cards, subscriptions, food and drink, flowers, or\neven cash). Please reach out to the maintainer using the options given in \\Sref{sec:contact} for further\nassistance.\n%%!!>>\n\n%%!!funding-disclaimer<<\nIn addition, the maintainers and contributors of this project DO NOT consent to the creation, sale,\nor promotion of tokens, cryptocurrencies, NFTs, or any other financial instruments that claim to\nrepresent this project, its code, or its community. Any such attempts are unauthorized and not\naffiliated with this project in any way.\n%%!!>>\n\n\\section{Contact}\\label{sec:contact} %%##$contact-title>>\n%%!!contact<<\nApp Manager Community\\\\\nEmail: \\href{mailto:am4android@riseup.net}{am4android [at] riseup [dot] net}\\\\\nGitHub: \\url{https://github.com/AMCommunity}\\\\\nTwitter/X: \\url{https://x.com/AppManagerNews}\\\\\nMastodon: \\href{https://floss.social/@appmanager}{@appmanager@floss.social}\\\\\n\\\\\n\nMuntashir Al-Islam\\footnote{You can also address me as ``Muntashir Akon''}\\\\\nEmail: \\href{mailto:muntashirakon@riseup.net}{muntashirakon [at] riseup [dot] net}\\\\\nGitHub: \\url{https://github.com/MuntashirAkon}\\\\\nTwitter/X: \\url{https://x.com/Muntashir}\\\\\nMastodon: \\href{https://infosec.exchange/@muntashir}{@muntashir@infosec.exchange}\n%%!!>>\n\n"
  },
  {
    "path": "docs/raw/en/keywords.tex",
    "content": "% SPDX-License-Identifier: GPL-3.0-or-later OR CC-BY-SA-4.0\n\n%%!!chapter<<\n\\newcommand{\\KeywordChapter}{Chapter}\n%%!!>>\n%%!!see_also<<\n\\newcommand{\\KeywordSeeAlso}{See also:}\n%%!!>>\n%%!!end_of_keyword_in_alert<<\n\\newcommand{\\KeywordEndOfKeyWordInAlert}{.}\n%%!!>>\n"
  },
  {
    "path": "docs/raw/en/lua/alert_fix.lua",
    "content": "function AlertFix(el)\n    if el.classes:includes 'amalert--tip' then\n        el.classes = {'amalert', 'tip'}\n        return el\n    end\n    if el.classes:includes 'amalert--warning' then\n        el.classes = {'amalert', 'warning'}\n        return el\n    end\n    if el.classes:includes 'amalert--danger' then\n        el.classes = {'amalert', 'danger'}\n        return el\n    end\n    return nil\nend\n\nif FORMAT:match 'html' then\n    return {\n        {Div = AlertFix}\n    }\nend\n"
  },
  {
    "path": "docs/raw/en/lua/header_with_hyperlinks.lua",
    "content": "pandoc.utils = require 'pandoc.utils'\n\n-- Adds links to headings with IDs.\nfunction Header (h)\n    if h.level < 4 then\n        local anchor_link = pandoc.Link(\n            h.content,\n            '#toc:' .. h.identifier\n        )\n        h.content = pandoc.Inlines {anchor_link}\n    end\n    if h.identifier ~= '' then\n        -- An empty link to this header\n        local anchor_link = pandoc.Link(\n            {},                  -- content\n            '#' .. h.identifier, -- href\n            '',                  -- title\n            {class = 'anchor', ['aria-hidden'] = 'true'} -- attributes\n        )\n        h.content:insert(anchor_link)\n    end\n    return h\nend\n\nif FORMAT:match 'html' then\n    return {\n        {Header = Header}\n    }\nend\n"
  },
  {
    "path": "docs/raw/en/lua/img_to_object.lua",
    "content": "function SvgImage (el)\n    if el.src:match '.svg$' then\n        data = 'data=\"' .. el.src .. '\" type=\"image/svg+xml\"'\n        id = el.identifier and ' id=\"' .. el.identifier .. '\"' or nil\n        classes = el.classes and ' class=\"' .. table.concat(el.classes, ' ') .. '\"' or nil\n        -- TODO\n        -- figcaption = el.caption and '<figcaption aria-hidden=\"true\">' .. table.concat(el.caption, ' ') .. '</figcaption>' or nil\n        attr = \"\"\n        for name, val in pairs(el.attributes) do\n            attr = attr .. ' ' .. name .. '=\"' .. val .. '\"'\n        end\n        return pandoc.RawInline('html', '<figure><object ' .. data .. id .. classes .. attr .. '></object></figure>')\n    end\n    return nil\nend\n\nif FORMAT:match 'html' then\n    return {\n        {Image = SvgImage}\n    }\nend\n"
  },
  {
    "path": "docs/raw/en/lua/toc_generator.lua",
    "content": "_ENV = pandoc\n\nlocal not_empty = function (x) return #x > 0 end\nlocal section_to_toc_item\n\n--[[\n    Produces ToC items recursively in the following format:\n    <ul ...>\n        <li><span><span class=\"toc-section-number\">1.1</span> <a id=\"1.1\" href=\"#sec:terminologies\">Terminologies</a></span></li>\n        ...\n    </ul>\n]]--\nlocal to_toc_item = function (number, text, id, subcontents)\n    local toc_entry\n    if number then\n        -- <span class=\"toc-section-number\">1.1</span>\n        local section_number = Span(Str(number), {class='toc-section-number'})\n        -- <a id=\"1.1\" href=\"#sec:terminologies\">Terminologies</a>\n        local link = id == '' and text or Link(text, '#' .. id, '', {id='toc:' .. id})\n        toc_entry = Span{section_number, Space(), link}\n    else\n        toc_entry = id == '' and text or Link(text, '#' .. id, {id='toc:' .. id})\n    end\n    local subitems = subcontents:map(section_to_toc_item):filter(not_empty)\n    return List{Plain{toc_entry}} ..\n    (#subitems == 0 and {} or {BulletList(subitems)})\nend\n\nsection_to_toc_item = function (div)\n    -- bail if this is not a section wrapper\n    if div.t ~= 'Div' or not div.content[1] or div.content[1].t ~= 'Header' then\n        return {}\n    end\n    local heading = div.content:remove(1)\n    -- bail if the header level is greater than 3\n    if heading.level > 3 then\n        return {}\n    end\n    local number = heading.attributes.number\n    -- bail if this is not supposed to be included in the toc\n    if not number and heading.classes:includes 'unlisted' then\n        return {}\n    end\n\n    return to_toc_item(number, heading.content, div.identifier, div.content)\nend\n\n-- return filter\nreturn {\n    {\n    Pandoc = function (doc)\n        -- avoid problems with headings nested below divs:\n        local blocks_no_divs = doc.blocks:walk{\n            Div = function (x) return x.content end\n        }\n        local sections = utils.make_sections(true, nil, blocks_no_divs)\n        local toc_items = sections:map(section_to_toc_item):filter(not_empty)\n        doc.meta['table-of-contents'] = {BulletList(toc_items)}\n        doc.meta.toc = doc.meta['table-of-contents']\n        return doc\n    end\n    },\n}"
  },
  {
    "path": "docs/raw/en/main.tex",
    "content": "% SPDX-License-Identifier: GPL-3.0-or-later OR CC-BY-SA-4.0\n\\ifdefined\\Vanilla\\else\n\\documentclass{memoir}\n\\fi\n\n% ------------------------------\n% Unknown commands/env for po4a\n% ------------------------------\n% po4a: environment Verbatim\n% po4a: verbatim environment Verbatim\n% po4a: environment minted []\n% po4a: environment listing []\n% po4a: command -hyperref []{_}\n% po4a: command +hypertarget {}{_}\n% po4a: command -href {}{_}\n% po4a: command -url {}\n% po4a: command -pagecolor {}\n% po4a: command *colorbox {}{_}\n\n\\usepackage[margin=1in]{geometry}\n\\usepackage[T1]{fontenc}\n\\usepackage{mathpazo} % Palatino\n\\usepackage[utf8]{inputenc}\n\\usepackage[english]{babel}\n\\usepackage{graphicx}\n\\usepackage[dvipsnames]{xcolor}\n\\usepackage{tikz}\n\\usepackage{mdframed}\n\\usepackage[outputdir=.]{minted}\n\\usepackage{hyperref}\n\\usepackage[all]{hypcap}\n\\usepackage[inkscapearea=page]{svg}\n\n% po4a: command hypersetup {}\n\\hypersetup{\n    unicode=true,\n    colorlinks=true\n}\n\n% Add numbering for subsubsection\n\\setcounter{tocdepth}{3}\n\\setcounter{secnumdepth}{3}\n\n% Import localised keywords\n\\input{keywords}\n\n% -------------------\n% Alert environments\n% -------------------\n\n% po4a: environment amalert--tip []{}\n% po4a: environment amalert--warning []{}\n% po4a: environment amalert--danger []{}\n% po4a: environment mdframed []{_}\n\\newenvironment{amalert--tip}\n{\\mdframed[linecolor={black},backgroundcolor=white,linewidth=3pt,topline=false,rightline=false,bottomline=false]}\n{\\endmdframed}\n\n\\newenvironment{amalert--warning}\n{\\mdframed[linecolor={Dandelion},backgroundcolor=white,linewidth=3pt,topline=false,rightline=false,bottomline=false]}\n{\\endmdframed}\n\n\\newenvironment{amalert--danger}\n{\\mdframed[linecolor={BrickRed},backgroundcolor=white,linewidth=3pt,topline=false,rightline=false,bottomline=false]}\n{\\endmdframed}\n\n% po4a: environment tip [_]\n\\newenvironment{tip}[1]\n{%\n    \\begin{amalert--tip}\n    \\noindent\n    \\textbf{\\textit{#1\\KeywordEndOfKeyWordInAlert}}\n    }%\n    {\n    \\end{amalert--tip}\n}\n\n% po4a: environment warning [_]\n\\newenvironment{warning}[1]\n{\n    \\begin{amalert--warning}\n    \\noindent\n    \\textbf{\\textit{#1\\KeywordEndOfKeyWordInAlert}}\n    }%\n    {\n    \\end{amalert--warning}\n}\n\n% po4a: environment danger [_]\n\\newenvironment{danger}[1]\n{\n    \\begin{amalert--danger}\n    \\noindent\n    \\textbf{\\textit{#1\\KeywordEndOfKeyWordInAlert}}\n    }%\n    {\n    \\end{amalert--danger}\n}\n\n% --------------------\n% Reference overrides (useful for localization)\n% --------------------\n\\newcommand{\\listingrefname}{Listing}\n% po4a: command Lref {_}\n\\newcommand{\\Lref}[1]{\\listingrefname~\\ref{#1}}\n\n% ----------------------\n% See also environments\n% ----------------------\n% po4a: command seealso-inline {_}\n\\newenvironment{seealso-inline}{}{}\n\\newcommand{\\seealsoinline}[1]{\n\\begin{seealso-inline}\n\\noindent\\textit{\\KeywordSeeAlso~{#1}}\n\\end{seealso-inline}\n}\n% po4a: environment amseealso\n\\newenvironment{amseealso}{\n    \\begin{seealso}\n        \\itshape\\KeywordSeeAlso\n        \\begin{itemize}\n        }\n        {\n        \\end{itemize}\n    \\end{seealso}\n}\n\n% Special case for \\includesvg for Pandoc\n\\ifdefined\\Vanilla\\else\n    \\renewcommand{\\includesvg}{\\includegraphics}\n\\fi\n\n% \\Cref, \\Sref fix for Pandoc\n\\ifdefined\\Vanilla\\else\n\\renewcommand{\\Cref}{\\KeywordChapter~\\ref}\n\\fi\n\\ifdefined\\Vanilla\\else\n\\renewcommand{\\Sref}{§\\ref}\n\\fi\n\n% -------------------\n% Colours used in AM\n% -------------------\n% The format used here is parsed by Regex and should not be altered.\n\\definecolor{AMRed}{HTML}{FF0000}\n\\definecolor{AMDarkRed}{HTML}{790D0D}\n\\definecolor{AMLightRed}{HTML}{FF8A80}\n\\definecolor{AMVeryDarkRed}{HTML}{4F1C14}\n\\definecolor{AMVividOrange}{HTML}{FF8017}\n\\ifdefined\\Vanilla\\else\n    \\definecolor{uninstalled-day}{HTML}{FF0000B3}\n    \\definecolor{uninstalled-night}{HTML}{790D0D}\n    \\definecolor{disabled-day}{HTML}{FF8A80}\n    \\definecolor{disabled-night}{HTML}{4F1C14BF}\n    \\definecolor{force-stopped}{HTML}{09868B}\n    \\definecolor{tracker-day}{HTML}{FF8017}\n    \\definecolor{tracker-night}{HTML}{FF801780}\n    % For compatibility only\n    \\definecolor{AMVeryDarkOrange}{HTML}{FF801780}\n\\fi\n\\ifdefined\\Vanilla\n    % We have to define Vanilla colour later because Pandoc only looks at the first colour\n    \\definecolor{uninstalled-day}{HTML}{FF0000}\n    \\definecolor{uninstalled-night}{HTML}{790D0D}\n    \\definecolor{disabled-day}{HTML}{FF8A80}\n    \\definecolor{disabled-night}{HTML}{4F1C14}\n    \\definecolor{force-stopped}{HTML}{09868B}\n    \\definecolor{tracker-day}{HTML}{FF8017}\n    \\definecolor{tracker-night}{HTML}{FF8017}\n    % For compatibility only\n    \\definecolor{AMVeryDarkOrange}{HTML}{FF8017}\n\\fi\n\\definecolor{AMSoftMagenta}{HTML}{EA80FC}\n\\definecolor{AMVeryDarkViolet}{HTML}{431C5D}\n\\definecolor{AMLightGreyishOrange}{HTML}{FCEED1}\n\\definecolor{AMDarkBlue}{HTML}{091F36}\n\\definecolor{AMOrange}{HTML}{E05915}\n\\definecolor{AMDarkCyan}{HTML}{09868B}\n\\definecolor{AMGreen}{HTML}{1b8654}\n\\definecolor{AMYellow}{HTML}{FFFF00}\n\\definecolor{SunTan}{HTML}{F6D5A8}\n\n% ------------------\n% colorbox override\n% ------------------\n\\newcommand{\\backgroundcolor}[2]{\n\n}\n\n% META\n\\title{App Manager}\n\\author{Muntashir Al-Islam}\n\n% Load variables\n\\input{transient}\n\n\\begin{document}\n    \\input{titlepage}\n    \\ifdefined\\HCode\n    % Don't display table of contents for tex4ht\n    \\else\n        \\tableofcontents\n    \\fi\n    \\input{intro/main}\n    \\input{pages/main}\n    \\input{guide/main}\n    \\input{faq/main}\n    \\input{appendices/main}\n\\end{document}\n"
  },
  {
    "path": "docs/raw/en/main_vanilla.tex",
    "content": "% SPDX-License-Identifier: GPL-3.0-or-later OR CC-BY-SA-4.0\n%! suppress = DocumentclassNotInRoot\n\\documentclass{memoir}\n\\setstocksize{9in}{6in}\n\\settrimmedsize{9in}{6in}{*}\n\\setlrmarginsandblock{0.75in}{0.75in}{*}\n\\setulmarginsandblock{1in}{1in}{*}\n\\checkandfixthelayout\n\n\\newcommand{\\Vanilla}{\\LaTeX}\n\n% -----------------------------------\n% Define Latex-specific environments\n% -----------------------------------\n\n% po4a: command announcement [_]\n\\newenvironment{announcement}{}{}\n% Override seealso to remove 'see also' prefix\n\\renewenvironment{seealso}{}{}\n\n% Include main\n\\input{main}\n"
  },
  {
    "path": "docs/raw/en/pages/app-details-page.tex",
    "content": "% SPDX-License-Identifier: GPL-3.0-or-later OR CC-BY-SA-4.0\n\\section{App Details Page}\\label{sec:app-details-page} %%##$section-title>>\n%%!!intro<<\n\\textbf{App Details} page consists of 11 (eleven) tabs. It describes almost every bit of information\nan application usually has, including all attributes from its manifest,\n\\hyperref[ch:app-ops]{application operations} (app ops), signing information, libraries, and so on.\n%%!!>>\n\n\\subsection{Colour Codes}\\label{subsec:app-details-colour-codes} %%##$colour-codes-title>>\n%%!!colour-codes<<\nList of colours used in this page, and their meaning:\n\\begin{itemize}\n    \\item \\colorbox{uninstalled-day}{\\textcolor{black}{Red (day)}} / \\colorbox{uninstalled-night}{\\textcolor{white}{dark red (night)}}\n    -- Denotes any app ops or permissions having the dangerous flag, or any components blocked\n    within App Manager, or any unsupported but required features.\n\n    \\item \\colorbox{disabled-day}{\\textcolor{black}{Light red (day)}} / \\colorbox{disabled-night}{\\textcolor{white}{very\n    dark red (night)}} -- Denotes the components disabled outside of App Manager, or any unsupported\n    but optional features.\n\n    \\begin{tip}{Note}\n        A component marked as disabled does not always mean that it is disabled by the user: It could also be disabled\n        by the system or marked as disabled in its manifest. The components of a disabled application are also\n        considered disabled by the system (and App Manager).\n    \\end{tip}\n\n    \\item \\colorbox{tracker-day}{\\textcolor{black}{Vivid orange (day)}} / \\colorbox{tracker-night}{\n        \\textcolor{white}{very dark orange (night)}} -- Denotes the tracker components\n\n    \\item \\colorbox{AMSoftMagenta}{\\textcolor{black}{Soft magenta (day)}} / \\colorbox{AMVeryDarkViolet}{\n        \\textcolor{white}{very dark violet (night)}} -- Denotes the running services.\n\n    \\item \\colorbox{AMGreen}{\\textcolor{white}{Green}}  -- Used in the tracker-indicator tag\n    to denote that all the trackers in the application are blocked.\n\\end{itemize}\n%%!!>>\n\n\\subsection{App Info Tab}\\label{subsec:app-info-tab} %%##$app-info-tab-title>>\n%%!!app-info-tab<<\n\\textbf{App Info} tab contains general information about an application. It also lists many actions that can be\nperformed within this tab.\n%%!!>>\n\n\\subsubsection{General Information}\\label{subsubsec:app-info-general-information} %%##$app-info-general-information-title>>\n%%!!app-info-general-information<<\nThe list below is in the same order as listed in the App Info tab.\n\\begin{itemize}\n    \\item \\textbf{Application Icon.} The application icon. If the application does not have an icon, the system default\n    icon will be displayed. It is also possible to verify the APK signature via SHA or MD5 sums stored in the clipboard\n    by simply clicking on it.\n\n    \\item \\textbf{Application Label.} The application label or the name of the application.\n\n    \\item \\textbf{Package Name.} The name of the application package. Clicking on the name stores it in the clipboard.\n\n    \\item \\textbf{Version.} The application version is divided into two parts. The first part is called \\textit{version\n    name}. The format of this part varies but often consists of multiple integers separated by dots. The second part\n    is called \\textit{version code}. It is enclosed by the first brackets. The version code is an integer used to\n    differentiate between application versions (since a version name can be unreadable to a machine). In general,\n    a new version of an application has higher version code than the old ones. For example, if \\texttt{123} and\n    \\texttt{125} are two version codes of an application, we can say that the latter is more updated than the former\n    because the version code of the latter is higher. An application that serves different APK files for the same version\n    on different platforms (mobile, tabs, desktops, etc.) or architectures (32/64 bit, ARM or Intel), the version\n    numbers can be misleading as they often add prefixes for each platform.\n\n    \\item \\textbf{Tags.} (Also known as tag clouds) Tags include the most basic, concise and useful information of an\n    application. See \\Sref{subsubsec:tags} for a complete list of tags shown here.\n\n    \\item \\textbf{Horizontal Action Panel.} An action panel consisting of various actions that can be carried out for\n    the application. See \\Sref{subsubsec:horizontal-action-panel} for a complete list of actions available here.\n    Additional actions are available in the \\hyperref[subsubsec:app-info-options-menu]{options menu}.\n\n    \\item \\textbf{Paths \\& Directories.} Contains various information regarding application paths\n    including \\textit{app directory} (where the APK files reside), \\textit{data directories}\n    (internal, device protected and externals), and \\textit{JNI library directory} (if present).\n    JNI libraries are used to invoke native codes usually written in C/C++. Use of native library\n    can make the application run faster or help an application use third-party libraries written\n    using languages other than Java like in most games. The directories can be opened via file\n    managers provided they support it and have the necessary permissions, by clicking on the launch\n    button on the right-hand side of a directory item.\n\n    \\item \\textbf{Data Usage.} Amount of data used by the application as reported by the operating system. Depending on\n    Android version, this may require a wide range of permissions including \\textit{Usage Access} and \\textit{Telephony}\n    permissions.\n\n    \\item \\textbf{Storage \\& Cache.} Displays information regarding the size of the application (APK files, optimised\n    files), data and cache. In older devices, size of external data, cache, media and OBB folders are also displayed.\n    This part remains hidden if \\textit{Usage Access} permission is not granted in the newer devices.\n\n    \\item \\textbf{More Info.} Displays other information such as--\n    \\begin{itemize}\n        \\item \\textbf{SDK.} Displays information related to the Android SDK: \\textit{Max} denotes\n        the target SDK and \\textit{Min} denotes the minimum SDK (the latter is not available in\n        Android Lollipop). If the target SDK value is less than the platform SDK (i.e., the highest\n        SDK the current operating system supports), the application will run in the compatibility\n        mode. This means the application may have access to certain features that are unavailable or\n        restricted in a newer version of Android, which can be a security and/or privacy issue. SDK\n        is also known as \\textbf{API Level}.\\\\\n        \\seealsoinline{\\href{https://en.wikipedia.org/wiki/Android_version_history\\#Overview}{Android Version History}}\n\n        \\item \\textbf{Flags.} The application flags used at the time of building the application. For a complete list of\n        flags and what they do, read the\n        \\href{https://developer.android.com/reference/android/content/pm/ApplicationInfo\\#flags}{official documentation}.\n\n        \\item \\textbf{Date Installed.} The date when the application was first installed.\n\n        \\item \\textbf{Date Updated.} The date when the application was last updated. This is the same as \\textit{Date Installed}\n        if the application hasn't been updated.\n\n        \\item \\textbf{Process Name.} The name of the process if it is different from the package\n        name. Process name is set when an application is being started by the system, and is usually\n        the same as the package name.\n\n        \\item \\textbf{Installer App.} The application that installed this application. The installer\n        application may not always be the same as the application that installed this application,\n        because Android allows setting an arbitrary value for this field. In Android 11 onwards, the\n        actual installer application is also stored by the system which can be accessed by clicking\n        the ``Info'' button on the right-hand side of the item. The field will not be visible if the\n        installer application is not reported by the system (e.g., due to the installer application\n        being uninstalled or hidden). Installer application may be granted additional privileges by\n        the system so that it can control certain behaviour of the application it installs.\n\n        \\item \\textbf{User ID.} The unique user ID set by the system to the application. For shared\n        applications, the same user ID is assigned to multiple applications having the same\n        \\textit{Shared User ID}.\n\n        \\item \\textbf{Shared User ID.} Applicable for applications that are shared together. The shared application must\n        have the same \\hyperref[subsec:signatures-tab]{signatures}.\n\n        \\item \\textbf{Primary ABI.} Architecture supported by this platform for this application.\n\n        \\item \\textbf{Zygote preload name.} Responsible for preloading application code and data shared across all the\n        isolated services that uses app zygote.\n\n        \\item \\textbf{Hidden API enforcement policy.} Since Android 9, many methods and classes in Android framework\n        have been made inaccessible to the third-party applications through hidden API enforcement policy. It has the\n        following options:\n        \\begin{itemize}\n            \\item \\textit{Default.} Based on the type of application. For system applications, it should be disabled,\n            and for others, it should be enforced.\n            \\item \\textit{None/disabled.} The application has full access to the hidden API as it used to be before\n            Android 9.\n            \\item \\textit{Warn.} Same as above, except that warnings will be logged each time the application accesses\n            the hidden API. This is mostly unused.\n            \\item \\textit{Enforce.} The application cannot access hidden API, either dark-grey list or blacklist, or\n            both of them. This is the default option for the third-party applications in Android 9 onwards unless the\n            application is whitelisted by the OEM or the vendor.\n            \\begin{warning}{Warning}\n                Hidden API enforcement policy is not properly implemented in Android and can be bypassed by the\n                application. As a result, this value should not be trusted.\n            \\end{warning}\n        \\end{itemize}\n\n        \\item \\textbf{SELinux.} Mandatory access control (MAC) policy set by the operating system via SELinux.\n\n        \\item \\textbf{Main Activity.} The main entry point to the application. This is only visible if the application has\n        \\hyperref[subsubsec:activities]{activities} and any of those are openable from the Launcher. There's also a\n        launch button on the right-hand side which can be used to launch this activity.\n    \\end{itemize}\n\\end{itemize}\n%%!!>>\n\n\\subsubsection{Tags}\\label{subsubsec:tags} %%##$tags-title>>\n%%!!tags-list<<\n\\begin{itemize}\n    \\item \\textbf{Tracker info.} Number of tracker components in the application (e.g., \\textit{5 trackers}) The colour\n    of the tag appears orange if the trackers are unblocked and dark cyan if they are blocked in App Manager.\n    Clicking on the tag opens a dialog containing the list of tracker components which can also be blocked or unblocked\n    provided App Manager has sufficient privileges.\n\n    \\item \\textbf{Application type.} User application or system application. For a system\n    application, it displays whether the application is an updated version of the system application\n    or the application is installed systemless-ly via Magisk.\n\n    \\item \\textbf{Split APK info.} Number of splits in the APK excluding the base APK (e.g., \\textit{5 splits}).\n    Clicking on the tag opens a dialog containing a few additional information, such as name, type, and size.\n\n    \\item \\textbf{Debuggable.} The application can be debugged over ADB\\@. Debuggable applications can enjoy certain\n    functions unavailable to a regular application. The data of the application might be accessible via ADB (e.g.\\ using\n    \\texttt{run-as} command) without any additional permissions.\n\n    \\item \\textbf{Test only.} The application is a test-only application. Test-only applications can enjoy certain\n    functions unavailable to a regular application. The data of the application might be accessible via ADB (e.g.\\ using\n    \\texttt{run-as} command) without any additional permissions.\n\n    \\item \\textbf{No code.} The application does not have any code associated with it i.e., DEX files aren't present.\n    In some system applications, the actual code might be located in another place.\n\n    \\item \\textbf{Large heap.} The application has requested large heap size i.e., more space in memory (RAM) is\n    requested for dynamic allocation. It is still up to the operating system to decide whether to allocate large space\n    for the application. App Manager, for example, requests large heap size because it needs to load an entire APK\n    into memory while scanning an APK\\@.\n\n    \\item \\textbf{Open links.} The application may open certain links from any applications. If the\n    application can open any links by default, the color of the tag would be red, dark cyan if\n    otherwise. Clicking on the tag opens a dialog with the supported hosts or domains listed. In\n    Android 12 onwards, it displays an option to enable or disable opening links by default provided\n    App Manager has sufficient permissions. Otherwise, it displays an option to open the system\n    settings page for the application.\n\n    \\item \\textbf{Running.} One or more services of the application is currently running in the\n    background. Clicking on the tag opens a dialog containing the list of running services. Clicking\n    on any services opens the log viewer with default filter set to the UID associated with the\n    service (which can be different from the UID of the application if it is running in a separate\n    or isolated process) provided the log viewer feature is enabled. There's also an option to\n    force-stop the application.\n\n    \\item \\textbf{Stopped.} The application is force stopped. This may not prevent it from running automatically later.\n\n    \\item \\textbf{Disabled.} Denotes that the application is disabled (hidden from the launcher).\n\n    \\item \\textbf{Suspended.} Denotes that the application is suspended (grayed out in the launcher).\n\n    \\item \\textbf{Hidden.} Denotes that the application is hidden (hidden from the launcher).\n\n    \\item \\textbf{MagiskHide.} MagiskHide is enabled for the application. Clicking on the tag opens\n    a dialog containing the list of process names within the application that can be added to or\n    removed from the MagiskHide list.\n\n    \\item \\textbf{MagiskDenyList.} The application is present in Magisk DenyList. Clicking on the\n    tag opens a dialog containing the list of process names within the application that can be added\n    to or removed from Magisk DenyList.\n\n    \\item \\textbf{WX.} The application violates the ``W\\textasciicircum{}X policy'' and is capable\n    of writing and executing in the same directory or in the same portion of memory. This allows the\n    execution of arbitrary executables either by the modification of executables embedded within the\n    application or by downloading them from the Internet.\\\\\n    \\seealsoinline{\\href{https://en.wikipedia.org/wiki/W\\%5EX}{W\\textasciicircum{}X in Wikipedia}}\n\n    \\item \\textbf{Bloatware.} The application may be a known bloatware. Clicking on the tag opens a\n    dialog containing detailed information in addition to suggestions (if available).\n\n    \\item \\textbf{KeyStore.} The application has items in the Android KeyStore. Clicking on the tag opens a dialog\n    containing all the KeyStore files that belong to the application.\n\n    \\item \\textbf{Backup.} The application was backed up using App Manager at least once. Clicking on the tag\n    opens a dialog containing all the available backups along with metadata.\n\n    \\item \\textbf{No battery optimisation.} Battery optimisation is disabled for the application. It is possible to\n    re-enable battery optimisation by clicking on the tag.\n\n    \\item \\textbf{Sensors disabled.} Sensors are disabled for the application. Sensors are disabled\n    for most applications by default.\n\n    \\item \\hyperref[sec:net-policy]{\\textbf{Net policy.}} Network policy (e.g., background data usage) is configured\n    for the application. Clicking on the tag displays a dialog containing the supported policies for the platform\n    along with the options to configure them.\n\n    \\item \\hyperref[sec:terminologies]{\\textbf{SSAID.}} Clicking on the tag opens a dialog containing the current\n    SSAID assigned to the application. It is also possible to reset/regenerate the SSAID if needed.\n\n    \\item \\textbf{SAF.} Denotes that the application has been granted to access one or more storage locations or\n    files i.e.\\ URIs via Storage Access Framework (SAF). Clicking on the tag opens a dialog containing the list of\n    granted URIs.\n\n    \\item \\textbf{Play App Signing.} Indicates that the application might be signed by Google.\n\n    \\item \\textbf{Xposed.} Indicates that the application may be an Xposed module. Clicking on the\n    tag displays a dialog with additional information.\n\n    \\item \\textbf{Static Shared Library.} Denotes that the application serves as a static shared\n    library for one or more applications. Clicking on the tag opens a dialog containing a list of\n    installed versions of the library along with an option to uninstall them.\n    \\begin{tip}{Notice}\n        The trichrome library (supplied by Google Chrome, Vanadium or similar projects) is currently\n        the only known static shared library on Android.\n    \\end{tip}\n\\end{itemize}\n%%!!>>\n\n\\subsubsection{Horizontal Action Panel}\\label{subsubsec:horizontal-action-panel} %%##$horizontal-action-panel-title>>\n%%!!horizontal-action-panel<<\nHorizontal Action Panel, as described in the previous section, consists of various application-related actions, such as--\n\\begin{itemize}\n    \\item \\textbf{Launch.} Launch the application provided it has a launcher \\hyperref[subsubsec:activities]{activity}.\n\n    \\item \\textbf{Freeze.} Freeze the application. This button is not displayed if it is already frozen or the user\n    does not have enough privileges. After the application is frozen, it may be hidden from the app drawer depending on\n    how it was configured. Shortcuts configured by the application may also be removed. The application may only be\n    unfrozen via App Manager, \\texttt{pm} command or any other tools that offer such a feature. Long clicking on the\n    button opens a dialog where a shortcut can be configured to quickly freeze or unfreeze the application.\n\n    \\item \\textbf{Uninstall.} Uninstall the application with a prompt. In the dialog prompt, it is possible to uninstall\n    updates of a system application, or if App Manager has enough privileges or the operating system supports it, it is\n    possible to uninstall the application without clearing its data and signature. For the latter case, the installed\n    application must match the signature with the previously installed application if it is installed again.\n    \\begin{tip}{Tips}\n        A better way to reinstall an application with a different signature would be to back up its data using App\n        Manager and restore it again after installing the application instead of opting to preserving data and signature\n        of the application during uninstallation as this option may cause undefined behaviour in the future.\n    \\end{tip}\n\n    \\item \\textbf{Unfreeze.} Unfreeze the application. This button is not displayed if it is already enabled or the user\n    does not have enough privileges. Similar to the \\textit{Freeze} button, long clicking on the button opens a dialog\n    where a shortcut can be configured to quickly freeze or unfreeze the application.\n\n    \\item \\textbf{Force Stop.} Force-stop the application.\n\n    \\item \\textbf{Clear Data.} Clear data from the application. This includes any information stored in the internal\n    and, recently, the external directories, including accounts (if set by the application), cache, etc. Clearing data\n    from App Manager, for example, removes all the rules (the blocking is not removed though) saved within the\n    application (Which is why you should always take backups of your rules). This button is not displayed if the user\n    does not have enough privileges.\n\n    \\item \\textbf{Clear Cache.} Clear the application cache. If the application is running during the operation, the\n    cache may not be cleared as expected.\n\n    \\item \\textbf{Install.} Install the application, only displayed if the application hasn't\n    already been installed.\n\n    \\item \\textbf{What's New.} Displayed for an external application if an older version of it is\n    already installed. Clicking on this button opens a dialog containing the differences between\n    this and the installed version in a version control manner. Changes include \\textit{version},\n    \\textit{trackers}, \\textit{permissions}, \\textit{components}, \\textit{signatures} (only checksum\n    changes), \\textit{features}, \\textit{shared libraries} and \\textit{SDK}.\n\n    \\item \\textbf{Update.} Displayed if the application has a higher version code than the installed application.\n\n    \\item \\textbf{Reinstall.} Displayed if the application has the same version code as the installed application.\n\n    \\item \\textbf{Downgrade.} Displayed if the application has a lower version code than the installed application.\n\n    \\item \\textbf{Manifest.} Opens the application's manifest file in a separate page. If the\n    application has more than one split, it will display the list of split APK files, and clicking\n    on an item will open the corresponding manifest file instead.\n\n    \\item \\textbf{Scanner.} Scan the application in order to list potential trackers and libraries.\n    It also scans the file using VirusTotal and fetch results from Pithus if configured.\\\\\n    \\seealsoinline{\\hyperref[sec:scanner-page]{Scanner page}}\n\n    \\item \\textbf{Shared Prefs.} Displays a list of shared preferences used by the application.\n    Clicking on a preference item in the list opens the \\hyperref[sec:shared-preferences-editor-page]{Shared Preferences\n    Editor page}. This option is only visible if the user has the required privileges.\n\n    \\item \\textbf{Databases.} Displays a list of databases used by the application. Clicking on an\n    item opens a list of activities that can open the database. This option is only visible if the\n    user has the required privileges.\n\n    \\item \\textbf{F-Droid.} Open the application in the selected \\textit{F-Droid} client.\n\n    \\item \\textbf{Store.} Open the application in \\textit{Aurora Store}. The option is only visible if \\textit{Aurora\n    Store} is installed.\n\\end{itemize}\n%%!!>>\n\n\\subsubsection{Options Menu}\\label{subsubsec:app-info-options-menu} %%##$app-info-options-menu-title>>\n%%!!app-info-options-menu<<\nOptions-menu is located in the top-right corner of the page. A complete description of the options present there are\ngiven below:\n\\begin{itemize}\n    \\item \\textbf{Share.} Share button can be used to share the APK or (if the application is has multiple splits, OBB\n    files or any dependencies) \\textit{APKS} file extracted from the application.\n\n    \\item \\textbf{Refresh.} Refresh the App Info tab.\n\n    \\item \\textbf{View in Settings.} Open the application in Android Settings.\n\n    \\item \\textbf{Backup/restore.} Open the backup/restore dialog.\n\n    \\item \\textbf{Export blocking rules.} Export rules configured for the application within App Manager.\n\n    \\item \\textbf{Open in Termux.} Open the application in Termux. This actually runs \\texttt{su - user\\_id} where\n    \\texttt{user\\_id} denotes the application's kernel user ID (described in \\Sref{subsubsec:app-info-general-information}).\n    This option is only visible to the root users. See \\Sref{subsubsec:config-termux} to learn how to configure Termux\n    to run commands from third-party applications.\n\n    \\item \\textbf{Run in Termux.} Open the application via \\texttt{run-as package\\_name} in Termux. This is only\n    applicable to the debuggable applications and works for both root and ADB users. See \\Sref{subsubsec:config-termux}\n    to learn how to configure Termux to run commands from third-party applications.\n\n    \\item \\textbf{MagiskHide.} Open a dialog containing the list of process names within the application that can be added\n    or removed from the MagiskHide list.\n\n    \\item \\textbf{Magisk DenyList.} Open a dialog containing the list of process namees within the application that can be\n    added or removed from Magisk DenyList.\n\n    \\item \\textbf{Battery optimisation.} Enable/disable battery optimisation for this application.\n\n    \\item \\textbf{Sensors.} Enable/disable sensors for this application.\n\n    \\item \\hyperref[sec:net-policy]{\\textbf{Net policy.}} Configure network policy (e.g., background data usage) for the\n    application.\n\n    \\item \\textbf{Extract Icon.} Extract and save the application's icon in the shared storage.\n\n    \\item \\textbf{Optimize.} Perform optimisation for this application. This option is for advanced\n    users only.\n\n    \\item \\textbf{Add to profile.} Add the application to one of the configured \\hyperref[sec:profile-page]{profiles}.\n\n    \\item \\textbf{Install for….} Install the application for another user and/or in the work profile if configured.\n\\end{itemize}\n%%!!>>\n\n\\subsubsection{Configuring Termux}\\label{subsubsec:config-termux} %%##$config-termux-title>>\n%%!!config-termux<<\nBy default, Termux does not allow running commands from a third-party application. To use this option, Termux v0.96 or\nlater is required and \\texttt{allow-external-apps=true} must be added in \\texttt{\\textasciitilde/.termux/termux.properties}.\n\n\\begin{tip}{Info}\n    Enabling this option does not weaken Termux' security. The third-party applications still need to ask the user to\n    allow running arbitrary commands in Termux.\n\\end{tip}\n%%!!>>\n\n\\subsection{Component Tabs}\\label{subsec:component-tabs} %%##$component-tabs-title>>\n%%!!component-tabs<<\n\\textbf{Activities}, \\textbf{Services}, \\textbf{Receivers} (i.e., broadcast receivers) and\n\\textbf{Providers} (e.g., content providers) are collectively known as the application components,\nbecause they offer similar features and share similar properties. For example, they all have a\n\\textit{name}, a \\textit{label}, an \\textit{icon}, can be enabled or disabled, and can be executed\nvia \\textit{Intent}. Application components are the building blocks of an application and must be\ndeclared in the application manifest (with a few exceptions). Application manifest is a file where\napplication specific metadata are stored. The Android operating system learns what to do with the\napplication by reading the metadata.\n\nColours used in these tabs are explained in \\Sref{subsec:app-details-colour-codes}. It is also\npossible to sort the list of components to display blocked or tracker components on top of the list\nvia the \\textbf{Sort} option located in the three-dots menu.\n%%!!>>\n\n\\subsubsection{Activities}\\label{subsubsec:activities} %%##$activities-title>>\n%%!!activities<<\n\\textbf{Activities} are the windows or pages that can be uniquely identified by the Android operating system (e.g.,\n\\textit{Main page} and \\textit{App Details page} are two activities). Each activity can have multiple UI components\nknown as \\textit{widgets} or \\textit{fragments}, and each component can be nested or placed on top of each other. The\ndeveloper can also choose to open external files, links, etc. within an activity using a method called\n\\textit{intent filters}. For example, when you open a file in your file manager, either your file manager or the\noperating system scans the intent filters via PackageManager, find the activities capable of opening the file, and\nlist those activities so that you can choose your preferred activity.\n\nActivities that are \\textit{exportable} can be opened by any third-party applications. However, Some\nactivities may require permissions, and only an application having those permissions can open them.\nIn the \\textit{Activities} tab, certain activities can be launched via the \\textbf{Launch} button.\nIf it is necessary to supply additional information, such as Intent extras, data or action, long\nclicking on the \\textbf{Launch} button opens the \\hyperref[sec:interceptor-page]{Activity Interceptor}\npage which provides such features.\n\n\\begin{tip}{Tip}\n    No-root users can grant \\texttt{android.permission.WRITE\\_SECURE\\_SETTINGS} via ADB to launch\n    \\textit{non-exportable} activities.\n\\end{tip}\n\n\\begin{tip}{Notice}\n    If launching an activity throws an error, it may have certain dependencies which are not met\n    (e.g., \\textit{App Details} page in App Manager cannot be launched using the launch button,\n    because it requires a package name). Since the dependencies cannot be inferred programmatically,\n    the activity may not be opened from App Manager by default.\n\\end{tip}\n\nIt is also possible to create shortcuts of an activity-launch using the \\textbf{Create shortcut}\nbutton. If you need to supply additional information, you can create a shortcut from the Activity\nInterceptor page instead.\n\n\\begin{danger}{Caution}\n    If you uninstall App Manager, all shortcuts created by App Manager will be lost.\n\\end{danger}\n%%!!>>\n\n\\subsubsection{Services}\\label{subsubsec:details:servcies} %%##$servcies-title>>\n%%!!servcies<<\nUnlike \\hyperref[subsubsec:activities]{activities} that users can see, \\textbf{Services} handle background tasks. For example,\nif you're downloading a video from the internet using your phone's Internet browser, the Internet browser is using a\n\\textit{foreground service} to download the content.\n\nWhen an activity is closed or removed from the \\textit{Recents} page, it may be destroyed\nimmediately depending on the amount free memory the phone has, battery statistics, or how the\nactivity is configured. But services can be run indefinitely if desired. If more services run in the\nbackground, the phone may become slower due to the shortage of memory and/or processing power, and\nthe phone's battery will be drained more quickly. Newer versions of Android come with a battery\noptimisation feature enabled by default for all applications. With this feature enabled, the system\ncan randomly terminate any service depending on the amount of resources the system has or the\nservice requires. However, foreground services (i.e., services that run with a fixed notification,\nsuch as music player or downloader) are not typically terminated unless the system is very low on\nresources (memory, battery, etc.). Certain stock ROMs can offer more aggressive optimisation. MIUI,\nfor example, has a very aggressive optimisation feature known as the \\textit{MIUI optimisation}.\n\nBoth activities and services are run in the same \\href{https://stackoverflow.com/questions/7597742}{looper} called\nthe main looper, which means the services do not really run in the background. It is the task of the developer to\nensure this. How do the application communicate with the services? It uses\n\\hyperref[subsubsec:app-details-receivers]{broadcast receiver} or Binder.\n%%!!>>\n\n\\subsubsection{Receivers}\\label{subsubsec:app-details-receivers} %%##$receivers-title>>\n%%!!receivers<<\n\\textbf{Receivers} (also called \\textit{broadcast receivers}) can be used to trigger execution of certain tasks when\ncertain events occur. These components are called broadcast receivers, because they are executed as soon as a broadcast\nmessage is received. These broadcast messages are sent using a method called \\textit{Intent}. Intent is a special\nfeature in Android that can be used to open applications (i.e., activities), run services and send broadcast messages.\nTherefore, like \\hyperref[subsubsec:activities]{activities}, broadcast receivers use \\textit{intent filters} to receive\nthe desired broadcast messages. Broadcast messages can be sent by the system or the application itself. When a broadcast\nmessage is sent, the corresponding receivers are activated by the system so that they can execute tasks. For example, if\nyour phone is low on resources, it may freeze or experience lags for a moment after you enable mobile data or connect it\nto the Wi-Fi. This is because broadcast receivers that can receive \\texttt{android.net.conn.CONNECTIVITY\\_CHANGE} are\nactivated by the system as soon as the data connection is enabled. Since many applications typically use this intent\nfilter, they are all activated almost immediately by the system which causes the freezing or lags.\n\nReceivers can also be used for inter-process communication (IPC), i.e., it can be used to communicate across multiple\napplications or even different components of a single application.\n%%!!>>\n\n\\subsubsection{Providers}\\label{subsubsec:providers} %%##$providers-title>>\n%%!!providers<<\n\\textbf{Providers} are primarily used for data management. For example, when you save an APK file or\nexport rules in App Manager, it uses a content provider called \\texttt{.fm.FmProvider} to save the\nAPK or export the rules. There are many providers, including the ones provided by the system, that\ncan be used to manage various content-related tasks, such as database management, tracking,\nsearching, etc. Each provider has a field called \\textit{Authority} which is unique to the\napplication in the entire Android ecosystem just as the package name.\n%%!!>>\n\n\\subsubsection{Additional Features for Rooted Phones} %%##$additional-features-for-rooted-phones-title>>\n%%!!additional-features-for-rooted-phones<<\nUnlike the no-root users who are mostly spectators in these tabs, root users can perform various operations.\n%%!!>>\n\n\\paragraph{Blocking Components.} %%##$blocking-components-title>>\n%%!!blocking-components<<\nOn the right-most side of each component item, there is a switch which can be used to toggle the blocking status of that\nparticular component. If \\hyperref[subsubsec:instant-component-blocking]{Instant Component Blocking} is not enabled or\nblocking is never applied to the application before, it is required to apply the changes using the \\textbf{Apply rules}\noption in three-dots menu. It is also possible to remove the already-applied rules using the same option (which would be\nread as \\textbf{Remove rules} this time).\n\nIt is also possible to block the component using one of the several methods by long clicking on the button.\n\n\\seealsoinline{\\hyperref[sec:faq:app-components]{FAQ: App Components}}\n%%!!>>\n\n\\paragraph{Blocking Trackers.}\\label{par:appdetails:blocking-trackers} %%##$blocking-trackers-title>>\n\\phantomsection\n%%!!blocking-trackers<<\nIt is possible to disable tracker components using the \\textbf{Block tracker} option in the three-dots menu. All tracker\ncomponents will be blocked regardless of the tab you're currently in.\n\n\\begin{tip}{Info}\n    Tracker components are a subset of application components. Therefore, they are blocked using the same method used\n    for blocking any other components.\n\\end{tip}\n\n\\begin{amseealso}\n    \\item \\hyperref[subsec:tracker-classes-versus-tracker-components]{FAQ: Tracker classes versus tracker components}\n    \\item \\hyperref[sec:scanner-page]{Scanner Page}\n    \\item \\hyperref[subsec:block-unblock-trackers]{1-Click Ops Page: Block/Unblock Trackers}\n\\end{amseealso}\n%%!!>>\n\n\\subsection{Permission Tabs}\\label{subsec:permission-tabs} %%##$permission-tabs-title>>\n%%!!permission-tabs<<\n\\textbf{App Ops}, \\textbf{Uses Permissions} and \\textbf{Permissions} tabs are related to permissions. In Android\ncommunication across applications or processes not having the same identity (known as \\textit{shared ID}) often\nrequire permissions. These permissions are managed by the permission controller. Some permissions are considered\n\\textit{normal} permissions which are granted automatically if they appear in the application manifest, but\n\\textit{dangerous} and \\textit{development} permissions require confirmation from the user. Colours used in these tabs\nare explained in \\Sref{subsec:app-details-colour-codes}.\n%%!!>>\n\n\\subsubsection{App Ops}\\label{subsubsec:app-ops} %%##$app-ops-title>>\n%%!!app-ops<<\n\\textbf{App Ops} stands for \\textbf{Application Operations}. Since Android 4.3, \\textit{App Ops} are used by Android to\ncontrol many system permissions. Each app op has a unique number associated with it which is displayed along with the\nprivate name of the operation in the App Ops tab. Some app ops also have a public name. A large number of app ops are\nalso associated with \\textit{permissions}. In this tab, an app op is considered dangerous if its associated permission\nis marked as dangerous. Other information such as \\textit{flags}, \\textit{permission name}, \\textit{permission description},\n\\textit{package name}, \\textit{group} are also taken from the associated \\hyperref[subsubsec:permissions]{permission}.\nOthers may include the following:\n\\begin{itemize}\n    \\item \\textbf{Mode.} It describes the current authorisation status which can be \\textit{allow}, \\textit{deny} (a\n    rather misnomer, it simply means error), \\textit{ignore} (it actually means deny), \\textit{default} (inferred from\n    a list of defaults set internally by the vendor or the AOSP), \\textit{foreground} (in newer Android versions, it\n    means the app op can only be used when the application is running in foreground), and some custom modes set by the\n    vendors (MIUI uses \\textit{ask}, for example).\n\n    \\item \\textbf{Duration.} The amount of time this app op has been used (there can be negative durations whose\n    use cases are currently unknown to me).\n\n    \\item \\textbf{Accept Time.} Last time the app op was accepted.\n\n    \\item \\textbf{Reject Time.} Last time the app op was rejected.\n\\end{itemize}\n\n\\begin{tip}{Info}\n    Contents of this tab are visible to no-root users if \\texttt{android.permission.GET\\_APP\\_OPS\\_STATS} is granted via ADB\\@.\n\\end{tip}\n\nThere is a toggle button next to each app op item which can be used to allow or deny (ignore) it. Other supported modes\ncan also be set by long clicking on the toggle button. If the desired app op is not listed in the tab,\n\\textit{Set custom app op} option in the menu can be used instead. It is also possible to reset the changes\nusing the \\textit{Reset to default} option, or deny all the dangerous app ops using the corresponding option in the menu.\nDue to the nature how app ops work, the system may take some time to apply them.\n\n\\begin{tip}{Tip}\n    Denying certain app ops may cause the application to misbehave. If all attempts fail, \\textit{reset to default}\n    option can be used as the last resort.\n\\end{tip}\n\nIt is possible to sort the list in ascending order by app op names and the associated unique numbers (or values), or\nlist the denied app ops first using the corresponding sorting options.\n\n\\seealsoinline{\\hyperref[ch:app-ops]{Appendix: App Ops}}\n%%!!>>\n\n\\subsubsection{Uses Permissions} %%##$uses-permissions-title>>\n%%!!uses-permissions<<\n\\textbf{Uses Permissions} are the permissions used by the application. This is named so because they are specified in\nthe manifest using \\texttt{uses-permission} tags. Information such as \\textit{flags}, \\textit{permission name},\n\\textit{permission description}, \\textit{package name}, \\textit{group} are taken from the associated\n\\hyperref[subsubsec:permissions]{permission}.\n\nPrivileged users can grant or revoke the \\textit{dangerous} and \\textit{development} permissions via the toggle button\non the right side of each permission item. It is also possible revoke dangerous permissions all at once using the\ncorresponding option in the menu. Only these two types of permissions can be revoked because Android does not allow\nthe modification of \\textit{normal} permissions (which most of them are). It might still be possible to revoke them\nby editing \\texttt{runtime-permissions.xml} itself, but whether this is a possibility is still being investigated.\n\n\\begin{tip}{Info}\n    Since dangerous permissions are revoked by default by the system, revoking all dangerous permissions is the same as\n    resetting all the permissions.\n\\end{tip}\n\nIt is possible to sort the permissions by their name (in ascending order) or choose to display denied or dangerous\npermissions at first using the corresponding options in the menu.\n%%!!>>\n\n\\subsubsection{Permissions}\\label{subsubsec:permissions} %%##$permissions-title>>\n%%!!permissions<<\n\\textbf{Permissions} are usually custom permissions defined by the application itself. These type of\npermissions are marked as \\textit{Internal} permissions. It also contains permissions declared by\nother applications which are marked as \\textit{External} permissions. An external permission can be\nspecified in an \\textit{exported} application component so that another application may invoke the\ncomponent only if it holds the permission. Below is a complete description of each item displayed in\nthis tab:\n\\begin{itemize}\n    \\item \\textbf{Name.} A permission has a unique name (e.g., \\texttt{android.permission.INTERNET})\n    that multiple applications can request. The application that declared the permission is\n    automatically granted and cannot be revoked.\n\n    \\item \\textbf{Icon.} Each permission can have a custom icon. The other permission tabs do not have any icon because\n    they do not contain any icon in the application manifest.\n\n    \\item \\textbf{Description.} This optional field describes the permission. If there isn't any description associated\n    with the permission, the field is not displayed.\n\n    \\item \\textbf{Flags.} (Uses the flag symbol or \\textbf{Protection Level} name) This describes various permission\n    flags such as \\textit{normal}, \\textit{development}, \\textit{dangerous}, \\textit{instant}, \\textit{granted},\n    \\textit{revoked}, \\textit{signature}, \\textit{privileged}, etc.\n\n    \\item \\textbf{Package Name.} Denotes the package name associated with the permission, i.e.\\ the package that defined\n    the permission.\n\n    \\item \\textbf{Group.} The group name associated with the permission (if any). Several related permissions can often\n    be grouped together.\n\\end{itemize}\n%%!!>>\n\n\\subsection{Signatures Tab}\\label{subsec:signatures-tab} %%##$signatures-tab-title>>\n%%!!signatures-tab_1<<\n\\textbf{Signatures} are actually called signing information. An application is signed with one or\nmore signing keys by its developer before publishing it. The integrity of an application, i.e.,\nwhether the application is from the actual developer and has not been modified by another person,\ncan be checked using the signing certificate included in the APK files. This is because when an\napplication is modified by an unauthorised entity, the application can longer be signed with the\noriginal signing keys since the signing keys are unknown to the entity. One way to verify the\nintegrity of an application is via the checksums generated from the certificates. If the developer\nsupplies the checksums for the signing certificates, they can be compared against the checksums\ngenerated in the \\textbf{Signatures} tab to verify the application. For example, if you have\ndownloaded App Manager from GitHub or Telegram Channel, you can verify whether the application was\nactually released by me by simply matching the following \\textit{SHA256} checksum with the one\ndisplayed in this tab:\n%%!!>>\n\\begin{Verbatim}\n320c0c0fe8cef873f2b554cb88c837f1512589dcced50c5b25c43c04596760ab\n\\end{Verbatim}\n\n%%!!signatures-tab_2<<\nSeveral hashing algorithms are used to generate checksums in this tab. They include \\textit{MD5}, \\textit{SHA1},\n\\textit{SHA256} and \\textit{SHA512}.\n\n\\begin{danger}{Caution}\n    Signing information should be verified using a reliable hashing algorithm, such as \\textit{SHA256}.\n    DO NOT rely on \\textit{MD5} or \\textit{SHA1} checksums as they are known to generate the same\n    checksums for multiple certificates.\n\\end{danger}\n%%!!>>\n\n\\subsection{Uses Features tab}\\label{subsec:uses-features-tab} %%##$uses-features-tab-title>>\n%%!!uses-features-tab<<\n\\textbf{Uses Features} tab lists the features declared by the application, such as OpenGL ES,\ntelephony, and leanback. Some features can be required by the application, and some features can be\noptional. Required features must be present in the system along with the required version.\nOtherwise, any attempt to install the application will be denied by the system. Colours used in this\ntab are explained in \\Sref{subsec:app-details-colour-codes}.\n%%!!>>\n\n\\subsection{Configurations tab}\\label{subsec:configurations-tab} %%##$configurations-tab-title>>\n%%!!configurations-tab<<\n\\textbf{Configurations} tab lists the configurations required by the application, such as input\nmethod type (qwerty, 12 key), touch screen type (finger, stylus, etc.), and navigation type (dial\npad, trackball, wheel). This tab is going to be empty for most applications.\n%%!!>>\n\n\\subsection{Shared Libraries Tab}\\label{subsec:shared-libs-tab} %%##$shared-libs-tab-title>>\n%%!!shared-libs-tab<<\n\\textbf{Shared libraries} tab lists the legacy JAR dependencies, any static shared library\ndependencies (currently, the only known cases are the Chromium-based browsers and WebViews) as well\nas the JNI (Java native interface) libraries. For JNI libraries, it specifies platform\n(x86/x86\\_64/ARM/AArch64), architecture (32/64 bit), object type (shared object or executable), etc.\n%%!!>>\n"
  },
  {
    "path": "docs/raw/en/pages/interceptor-page.tex",
    "content": "% SPDX-License-Identifier: GPL-3.0-or-later OR CC-BY-SA-4.0\n\\section{Interceptor Page}\\label{sec:interceptor-page} %%##$section-title>>\n%%!!intro<<\nInterceptor can be used to intercept communication between applications using \\texttt{Intent}.\nIt works as a man-in-the-middle between the source and the destination applications.\nIt offers a feature-complete user interface for editing \\texttt{Intent}s.\n\n\\begin{warning}{Warning}\n    Interceptor only works for \\textit{implicit} intents where the \\hyperref[subsec:faq:what-are-app-components]{app component} isn't specified.\n\\end{warning}\n\n\\begin{amseealso}\n    \\item \\href{https://developer.android.com/guide/components/intents-common}{Common Intents}\n    \\item \\href{https://developer.android.com/guide/components/intents-filters}{Intents and Intent Filters}\n\\end{amseealso}\n%%!!>>\n\n\\subsection{Intent Filters}\\label{subsec:intent-filters} %%##$intent-filters-title>>\n%%!!intent-filters<<\nIntent filters are used by the applications to specify the tasks they are able to perform or the tasks they are going to perform using other applications.\nFor example, when you're opening a PDF file using a file manager, the file manager will try to find the applications to open the PDF with.\nTo find the right applications, the file manager will create an Intent with filters such as the MIME type and ask the system to retrieve the applications capable of opening this filter.\nThe system will search through the Manifest of the installed applications to match the filter and list the application components that are able to open this filter (in our case the PDF).\nAt this, either the file manager will open the desired application component all by itself or use a system provided option to open it.\nIf multiple application components are able to open it and no default is set, you may get a prompt where you have to choose the right application component.\n%%!!>>\n\n\\subsubsection{Action}\\label{subsubsec:action} %%##$action-title>>\n%%!!action<<\nAction specifies the generic action to perform such as \\texttt{android.intent.action.VIEW}. Applications often declare\nthe relevant actions in the Manifest file to catch the desired Intents. The action is particularly useful for broadcast\nIntent where it plays a vital rule. In other cases, it works as an initial way to filter out the relevant application components.\nGeneric actions such as \\texttt{android.intent.action.VIEW} and \\texttt{android.intent.action.SEND} are widely used by applications.\nHence, setting this alone may match many application components.\n%%!!>>\n\n\\subsubsection{Data}\\label{subsubsec:data} %%##$data-title>>\n%%!!data<<\nData is originally known as URI (Uniform Resource Identifier) defined in \\href{http://www.faqs.org/rfcs/rfc2396.html}{RFC 2396}.\nIt can be web links, file location, or a special feature called \\textit{content}. Contents are an Android feature managed by the \\hyperref[subsubsec:providers]{content providers}.\nData are often associated with a \\hyperref[subsubsec:mime-type]{MIME type}.\n\nExamples:\n%%!!>>\n\\begin{Verbatim}\nhttp://search.disroot.org/?q=URI%20in%20Android%20scheme&categories=general&language=en-US\nhttps://developer.android.com/reference/android/net/Uri\nfile:///sdcard/AppManager.apk\nmailto:email@example.com\ncontent://io.github.muntashirakon.AppManager.provider/23485af89b08d87e898a90c7e/AppManager.apk\n\\end{Verbatim}\n\n\\subsubsection{MIME Type}\\label{subsubsec:mime-type} %%##$mime-type-title>>\n%%!!mime-type<<\nMIME type of the \\hyperref[subsubsec:data]{data}. For example, if the data field is set to \\texttt{file:///sdcard/AppManager.apk},\nthe associated MIME type can be \\texttt{application/vnd.android.package-archive}.\n%%!!>>\n\n\\subsubsection{Categories} %%##$categories-title>>\n%%!!categories<<\nThis is similar to \\hyperref[subsubsec:action]{action} in the sense that it is also used by the system to filter application components.\nThis has no further benefits. Unlike \\textit{action}, there can be more than one category. Clicking on the \\textit{plus} button next to the title allows adding more categories.\n%%!!>>\n\n\\subsubsection{Flags} %%##$flags-title>>\n%%!!flags<<\nFlags are useful in determining how system should behave during the launch or after the launch of an activity.\nThis should not be touched as it requires some technical background. The \\textit{plus} button next to the title can be used to add one or more flags.\n%%!!>>\n\n\\subsubsection{Extras} %%##$extras-title>>\n%%!!extras<<\nExtras are the key-value pairs used for supplying additional information to the destination component. More extras can be added using the \\textit{plus} button next to the title.\n%%!!>>\n\n\\subsubsection{URI} %%##$uri-title>>\n%%!!uri<<\nRepresents the entire Intent as a URI (e.g. \\texttt{intent://\\dots}). Some data cannot be converted to string,\nand as a result, they might not appear here.\n%%!!>>\n\n\\subsection{Matching Activities}\\label{subsec:matching-activities} %%##$matching-activities-title>>\n%%!!matching-activities<<\nList all the activity components that matches the Intent. This is internally determined by the system (rather than App Manager).\nThe launch button next to each component can be used to launch them directly from App Manager.\n%%!!>>\n\n\\subsection{Reset to Default}\\label{subsec:interceptor-reset-to-default} %%##$reset-to-default-title>>\n%%!!reset-to-default<<\nReset the Intent to its initial state.\n%%!!>>\n\n\\subsection{Send Edited Intent}\\label{subsec:interceptor-send-edited-intent} %%##$send-edited-intent-title>>\n%%!!send-edited-intent<<\nResend the edited Intent to the destination application. This may open a list of applications where the desired application is needed to be selected.\nThe result received from the target application will be sent to the source application. As a result, the source application will not know if there was a man-in-the-middle.\n%%!!>>\n"
  },
  {
    "path": "docs/raw/en/pages/main-page.tex",
    "content": "% SPDX-License-Identifier: GPL-3.0-or-later OR CC-BY-SA-4.0\n\\section{Main Page}\\label{sec:main-page} %%##$section-title>>\n%%!!intro<<\nMain page lists all the installed, uninstalled and backed up applications. A single click on any\ninstalled application item opens the respective \\hyperref[sec:app-details-page]{App Details page}.\nFor the uninstalled system applications, a dialog prompt is displayed with an option reinstall them.\nThe applications uninstalled without removing their data and signatures are also displayed in this\npage with an option to perform a full uninstallation. For the uninstalled applications having one or\nmore backups, the restore dialog is displayed. Using the \\hyperlink{par:main-page-sort}{sort} option\nfrom the list options, the items can be sorted in various ways. It is also possible to filter items\nusing the \\hyperlink{par:main-page-filter}{filter} option in the list options. Filtering is also\npossible from the search bar with additional support for the regular expressions.\n%%!!>>\n\n\\begin{figure}[ht]\n    \\centering\n    \\includesvg[inkscapelatex=false, scale=0.6, keepaspectratio]{../images/main_page_entry_info_labeled.svg}\n    \\caption{An application list item in the main page} %%##$how-app-ops-work-title>>\n    \\label{fig:main_page_entry_info_labeled}\n\\end{figure}\n\n\\subsection{Batch Operations}\\label{subsec:batch-operations} %%##$batch-operations-title>>\n%%!!batch-operations<<\nBatch operations or operations on multiple applications are also available within this page.\nMultiple selection mode can be activated by clicking on the app icon of an item or by long-clicking\non any items in the list. Once activated, a click on an item selects it instead of opening the App\nDetails page. In this mode, the batch operations are located in the multiple selection menu at the\nbottom of the page. The operations include:\n\\begin{itemize}\n    \\item Adding the selected applications to a \\hyperref[sec:profiles-page]{profile}\n    \\item \\hyperref[sec:backup-restore]{Backing up applications}, or restoring and deleting the\n    existing backups\n    \\item Blocking the trackers from the applications\n    \\item Clearing data or cache from the applications\n    \\item Exporting the blocking rules configured inside App Manager\n    \\item Exporting the list of applications in Markdown, CSV, JSON or XML format\n    \\item Freezing/unfreezing/force-stopping/uninstalling the applications\n    \\item Performing run-time optimization of the applications (Android 7 onwards)\n    \\item Preventing the background operations of the applications (Android 7 onwards)\n    \\item Saving the APK files to \\texttt{AppManager/apks}\n    \\item Setting \\hyperref[sec:net-policy]{net policies}\n\\end{itemize}\n\n\\begin{tip}{Accessibility}\n    After the multiple selection mode has been activated, it is possible to navigate in or out of\n    the multiple selection menu using the right or left keys of the keyboard or remote.\n\\end{tip}\n%%!!>>\n\n\\subsection{Colour Codes}\\label{subsec:main-colour-codes} %%##$colour-codes-title>>\n%%!!colour-codes<<\n\\begin{itemize}\n    \\item \\colorbox{uninstalled-day}{\\textcolor{black}{Red (day)}} / \\colorbox{uninstalled-night}{\\textcolor{white}\n    {dark red (night)}} -- Uninstalled application\n    \\item \\colorbox{disabled-day}{\\textcolor{black}{Light red (day)}} / \\colorbox{disabled-night}{\\textcolor{white}\n    {very dark red (night)}} -- Frozen application\n    \\item \\colorbox{force-stopped}{\\textcolor{white}{Dark cyan}} -- Force-stopped application\n    \\item \\colorbox{AMYellow}{\\textcolor{black}{Yellow Star}} -- Debuggable application\n\n    \\item \\textcolor{AMOrange}{Orange \\textit{Date}} -- The application can read system logs\n    \\item \\textcolor{AMOrange}{Orange \\textit{UID}} -- The user ID is being shared among multiple applications\n    \\item \\textcolor{AMOrange}{Orange \\textit{SDK}} -- The application possibly uses cleartext (i.e.\\ HTTP) traffic\n    \\item \\textcolor{tracker-day}{Light orange \\textit{package name}} -- The application has one or more trackers\n    \\item \\textcolor{red}{Red \\textit{app label}} -- The application does not allow clearing its data\n    \\item \\textcolor{AMDarkCyan}{Dark cyan \\textit{version}} -- Inactive application\n    \\item \\textcolor{magenta}{Magenta type} -- Persistent application i.e.\\ it remains running all the time\n\n    \\item \\textcolor{red}{Red \\textit{backup}} -- The uninstalled application with one or more\n    backups present in App Manager\n    \\item \\textcolor{AMOrange}{Orange \\textit{backup}} -- Outdated backup, i.e.\\ the base backup\n    contains an older version of the installed application\n    \\item \\textcolor{AMDarkCyan}{Dark cyan \\textit{backup}} -- Up to date backup, i.e.\\ the base\n    backup contains the same or higher version of the installed application.\n\\end{itemize}\n%%!!>>\n\n\\subsection{Application Types}\\label{subsec:main-page-application-types} %%##$application-types-title>>\n%%!!application-types<<\nAn application can be either a \\textbf{User} or a \\textbf{System} application along with the following suffixes:\n\\begin{itemize}\n    \\item \\texttt{X} -- Supports multiple architectures\n    \\item \\texttt{0} -- No dex files present in the application\n    \\item \\texttt{°} -- Suspended application\n    \\item \\texttt{\\#} -- The application requested the system to allocate a large heap i.e.\\ large runtime memory\n    \\item \\texttt{?} -- The application requested the virtual machine to be in the safe mode.\n\\end{itemize}\n%%!!>>\n\n\\subsection{Version Info}\\label{subsec:main-page-version-info} %%##$version-info-title>>\n%%!!version-info<<\nVersion name is followed by the prefixes below:\n\\begin{itemize}\n    \\item \\texttt{\\_} -- No hardware acceleration (breaking the in-app animations or transparencies)\n    \\item \\texttt{\\textasciitilde} -- Test-only application\n    \\item \\texttt{debug} -- Debuggable application\n\\end{itemize}\n%%!!>>\n\n\\subsection{Options Menu}\\label{subsec:main-page-options-menu} %%##$options-menu-title>>\n%%!!options-menu<<\nOptions menu offers several options that can be used to sort and filter the listed applications as well as to navigate\nto different pages within or outside App Manager.\n%%!!>>\n\n\\subsubsection{List Options}\\label{subsubsec:main-list-options} %%##$list-options-title>>\n%%!!list-options<<\n\\textbf{List options} contain the options to sort and filter the list in the main page.\n%%!!>>\n\n\\paragraph{Sort}\\hypertarget{par:main-page-sort}{} %%##$sort-title>>\n%%!!sort<<\nThe applications listed in the main page can be sorted in the following ways:\n\\begin{itemize}\n    \\item \\textbf{User apps first.} The user applications are listed on top\n    \\item \\textbf{App label.} Sort the list in ascending order based on their application labels (also known as\n    \\textit{application names}). This is the default sorting preference\n    \\item \\textbf{Package name.} Sort the list in ascending order based on their package names\n    \\item \\textbf{Last update.} Sort the list in descending order based on the date they were last updated\n    \\item \\textbf{Shared user ID.} Sort the list in descending order based on their kernel user ID\n    \\item \\textbf{Target SDK.} Sort the list in ascending order based on their target SDK\n    \\item \\textbf{Signature.} Sort the list in ascending order based on their signing information\n    \\item \\textbf{Frozen first.} The frozen applications are listed on the top\n    \\item \\textbf{Blocked first.} Sort the list in descending order based on the number of blocked components each\n    application has\n    \\item \\textbf{Backed up first.} Display the applications with backups on the top\n    \\item \\textbf{Trackers.} Sort the list in descending order based on the number of tracker components each\n    application has\n    \\item \\textbf{Last actions.} Sort the list in descending order based on the latest time and date of any actions made\n    to the applications within App Manager.\n    \\item \\textbf{Installation date.} Sort the list by the date of installation in descending order.\n    \\item \\textbf{Total size.} Sort the list by the total size of the applications and their data in descending order. Requires \\texttt{Usage Access} permission.\n    \\item \\textbf{Data usage.} Sort the list by the total data usage in descending order. Requires \\texttt{Usage Access} permission.\n    \\item \\textbf{Times opened.} List frequently used applications on top. Requires \\texttt{Usage Access} permission.\n    \\item \\textbf{Screen time.} List the applications with the highest engagements on top. Requires \\texttt{Usage Access} permission.\n    \\item \\textbf{Last used.} List last used apps on top. Requires \\texttt{Usage Access} permission.\n\\end{itemize}\n\nIn addition, there is the \\textit{reverse} option that can be used to sort the list in the reverse order. Regardless of\nthe sorting preferences, the applications are sorted alphabetically at first in order to prevent producing any random\nsorting results.\n%%!!>>\n\n\\paragraph{Filter}\\hypertarget{par:main-page-filter}{} %%##$filter-title>>\n%%!!filter<<\nThe applications listed in the main page can be filtered in the following ways:\n\\begin{itemize}\n    \\item \\textbf{User apps.} List only the user applications\n    \\item \\textbf{System apps.} List only the system applications\n    \\item \\textbf{Frozen apps.} List only the frozen applications\n    \\item \\textbf{Stopped apps.} List only the applications that were forced-stopped\n    \\item \\textbf{Installed apps.} List only the installed applications\n    \\item \\textbf{Uninstalled apps.} List only the uninstalled applications\n    \\item \\textbf{With rules.} List the applications with one or more blocking rules\n    \\item \\textbf{With activities.} List the applications with one or more activities\n    \\item \\textbf{With backups.} List the applications with one or more backups\n    \\item \\textbf{Without backups.} List the applications with no backups present.\n    \\item \\textbf{Running apps.} List the applications that are currently running\n    \\item \\textbf{With splits.} List the applications with one or more split APK files\n    \\item \\textbf{With KeyStore.} List only the applications with Android KeyStore.\n    \\item \\textbf{With SAF.} List only the applications with SAF access.\n    \\item \\textbf{With SSAID.} List only the applications with a valid SSAID\\@.\n\\end{itemize}\n\nUnlike sorting, it is possible to apply more than one filtering options at the same time. For example, the frozen user\napplications can be listed by selecting both \\textit{User apps} and \\textit{Frozen apps}. This can be particularly\nuseful for \\hyperref[subsec:batch-operations]{batch operations} where filtering the user applications may be necessary\nto carry out certain operations safely.\n\n\\begin{warning}{Inconsistencies}\n    App Manager extensively caches everything in this page. Therefore, certain states (e.g., freeze\n    and stopped states) may not always be up-to-date.\n\\end{warning}\n%%!!>>\n\n\\paragraph{Profile Name}%%##$profile_name-title>>\n%%!!profile_name<<\nIt is also possible to list the applications that are only present in a \\hyperref[sec:profiles-page]{profile}. This can\nbe useful for carrying out certain operations on a profile (e.g., uninstalling all the applications in a profile) that\ncannot be done via the \\hyperref[sec:profiles-page]{Profiles page}.\n%%!!>>\n\n\\subsubsection{User Manual} %%##$instructions-title>>\n%%!!instructions<<\nClicking on the \\textbf{User manual} opens the offline version of the App Manager user manual. It may also open the\nonline version if the corresponding feature split i.e.\\ \\texttt{feat\\_docs} is not installed, or if an WebView is not\npresent in the system to load the manual.\n%%!!>>\n\n\\subsubsection{1-Click Ops}\\label{subsubsec:main:1-click-ops} %%##$1-click-ops-title>>\n%%!!1-click-ops<<\n\\textbf{1-Click Ops} stands for the single-click operations. It opens the \\hyperref[sec:1-click-ops-page]{corresponding\npage} in a new activity.\n%%!!>>\n\n\\subsubsection{App Usage} %%##$app-usage-title>>\n%%!!app-usage<<\nApplication usage statistics, such as \\textit{screen time}, \\textit{data usage} (both mobile and\nWi-Fi), \\textit{number of times an app was opened}, can be accessed by clicking on the \\textbf{App\nUsage} option in the menu. However, it requires the \\textit{Usage Access} permission. This menu item\nwill not be listed if the usage access feature is disabled in \\hyperref[subsubsec:enable/disable-features]{settings}.\n%%!!>>\n\n\\subsubsection{Running Apps}\\label{subsubsec:main:running-apps} %%##$running-apps-title>>\n% TODO: Create a new page for the running apps\n%%!!running-apps<<\nThis menu item opens a new page where a list of running applications or processes are displayed. It also displays the\ncurrent memory and cache (if available) usage. If root or ADB is not available to App Manager, it only displays itself\nin the recent versions of Android. The running applications or processes can also be force-stopped or killed within the\nresultant page. Logs for each process ID (PID) can also be viewed in the \\hyperref[subsubsec:main:labs]{log viewer}.\nIn addition, it is also possible to carry out batch operations either by clicking on the icon or by long-clicking on an\nitem. Normal click on any items opens a dialog where a more detailed information is displayed.\n%%!!>>\n\n\\subsubsection{Profiles} %%##$profiles-title>>\n%%!!profiles<<\nThis menu item opens the \\hyperref[sec:profiles-page]{profiles page}. Profiles are a way to configure regularly used\ntasks. They can also be invoked via shortcuts.\n%%!!>>\n\n\\subsubsection{APK Updater} %%##$apk-updater-title>>\n%%!!apk-updater<<\nIf the app \\href{https://github.com/rumboalla/apkupdater}{APK Updater} is installed in the system, it can be opened\ndirectly via this menu item. The option remains hidden if the app is not present in the system.\n%%!!>>\n\n\\subsubsection{Termux} %%##$termux-title>>\n%%!!termux<<\nIf the app \\href{https://github.com/termux/termux-app}{Termux} is installed in the system, the running session (or a\nnew session) can be opened directly via this menu item. The option remains hidden if the app is not present in the\nsystem.\n%%!!>>\n\n\\subsubsection{Debloater} %%##$debloater-title>>\n%%!!debloater<<\nThis menu item opens the debloater page that lists all the bloatware available in the device and in\nApp Manager. It also suggests alternative applications based on the criteria set by the \\href{https://github.com/MuntashirAkon/android-debloat-list}{Android Debloat List}\nproject.\n%%!!>>\n\n\\subsubsection{Labs}\\label{subsubsec:main:labs} %%##$labs-title>>\n%%!!labs<<\nThis menu item opens the labs page that lists all the additional features. They include Log Viewer,\nSystem Config, Terminal, File Manager (as Files), UI Tracker, Interceptor, and Code Editor pages.\n%%!!>>\n\n\\subsubsection{Settings} %%##$settings-title>>\n%%!!settings<<\nThis menu item opens the in-app \\hyperref[sec:settings-page]{Settings page}.\n%%!!>>\n"
  },
  {
    "path": "docs/raw/en/pages/main.tex",
    "content": "% SPDX-License-Identifier: GPL-3.0-or-later OR CC-BY-SA-4.0\n\\chapter{Pages}\\label{ch:pages} %%##$pages-chapter-title>>\n\n\\input{pages/main-page.tex}\n\\input{pages/app-details-page.tex}\n\\input{pages/one-click-ops-page.tex}\n\\input{pages/profiles-page.tex}\n\\input{pages/profile-page.tex}\n\\input{pages/settings-page.tex}\n\\input{pages/scanner-page.tex}\n\\input{pages/interceptor-page.tex}\n\\input{pages/shared-prefs-editor-page.tex}\n"
  },
  {
    "path": "docs/raw/en/pages/one-click-ops-page.tex",
    "content": "% SPDX-License-Identifier: GPL-3.0-or-later OR CC-BY-SA-4.0\n\\section{1-Click Ops Page}\\label{sec:1-click-ops-page} %%##$section-title>>\n%%!!intro<<\nThis page is displayed on selecting the \\hyperref[subsubsec:main:1-click-ops]{1-Click Ops option} in the \\hyperref[subsec:main-page-options-menu]{main menu}.\n%%!!>>\n\n\\subsection{Block/Unblock Trackers}\\label{subsec:block-unblock-trackers} %%##$block-unblock-trackers-title>>\n%%!!block-unblock-trackers<<\nThis option can be used to block or unblock the ad/tracker components from the installed applications.\nOn selecting this option, App Manager will ask if it should list trackers from all the applications or only from the user applications.\nNovice users should avoid blocking trackers from the system applications in order to avoid bad consequences.\nAfter that, a multi-choice dialog box will appear where it is possible to exclude one or more applications from this operation.\nThe changes are applied immediately on pressing the \\textit{block} or \\textit{unblock} button.\n\n\\begin{warning}{Notice}\n    Certain applications may not function as expected after blocking their trackers.\n    If that is the case, remove the blocking rules all at once or one by one in the component tabs of the \\hyperref[sec:app-details-page]{App Details page} for the corresponding application.\n\\end{warning}\n\n\\seealsoinline{\\hyperref[par:appdetails:blocking-trackers]{App Details Page: Blocking Trackers}}\n%%!!>>\n\n\\subsection{Block Components\\dots}\\label{subsec:block-components-dots} %%##$block-components-dots-title>>\n%%!!block-components-dots<<\nThis option can be used to block certain application components as specified by their signatures.\nA signature of a component is the full name or partial name of the component.\nFor safety, it is recommended to add a \\texttt{.} (dot) at the end of each partial signature, because the underlying\nalgorithm searches and matches the components in a greedy manner.\nIt is also possible to insert more than one signature in which case all the signatures have to be separated by white spaces.\nSimilar to the option above, there is also an option to apply blocking to the system applications.\n\n\\begin{danger}{Caution}\n    If you are not aware of the consequences of blocking applcations components by their signatures, you should avoid\n    using this option as it may result in bootloop or soft brick, and you may have to apply factory reset as a result.\n\\end{danger}\n%%!!>>\n\n\\subsection{Set Mode for App Ops\\dots}\\label{subsec:set-mode-for-app-ops-dots} %%##$set-mode-for-app-ops-dots-title>>\n%%!!set-mode-for-app-ops-dots<<\nThis option can be used to configure certain \\hyperref[ch:app-ops]{applcation operations} of all or selected applications.\nThere are two fields. The first field can be used to insert more than one app op constants (either names or values) separated by white spaces.\nIt is not always possible to know in advance about all the app op constants as they vary from device to device and from OS to OS\\@.\nDesired app op constant can be found in the \\textit{App Ops} tab located in the \\hyperref[sec:app-details-page]{App Details page}.\nThe second field can be used to insert or select one of the \\hyperref[subsec:mode-constants]{modes} that will be set against the specified app ops.\n\n\\begin{danger}{Caution}\n    Unless you are well-informed about app ops and the consequences of blocking them, you should avoid using this option.\n\\end{danger}\n%%!!>>\n\n\\subsection{Back up}\\label{subsec:1-click-back-up} %%##$1-click-back-up-title>>\n%%!!back-up<<\n1-Click options for back up. As a precaution, it lists the affected backups before performing any operation.\n\n\\paragraph{Back up all apps.} Back up all the installed applications.\n\n\\paragraph{Redo existing backups.} Back up all the installed applications that have a previous backup.\n\n\\paragraph{Back up apps without backups.} Back up all the installed applications without a previous backup.\n\n\\paragraph{Verify and redo backups.} Verify the recently made backups of the installed applications and redo backup if necessary.\n\n\\paragraph{Back up apps with changes.} If an app has changed since the last backup, redo its backup.\nIt checks a number of indices including application version, last update date, last launch date, integrity and file hashes.\nDirectory hashes are taken during the backup process and are stored in a database.\nOn running this operation, new hashes are taken and compared with the ones kept in the database.\n%%!!>>\n\n\\subsection{Restore}\\label{subsec:1-click-restore} %%##$1-click-restore-title>>\n%%!!restore<<\n1-Click options for restore. As a precaution, it lists the affected backups before performing any operation.\n\n\\paragraph{Restore all apps.} Restore \\textit{base backup} of all the backed up applications.\n\n\\paragraph{Restore not installed apps.} Restore \\textit{base backup} of all the backed up applications that are not currently installed.\n\n\\paragraph{Restore latest backups.} Restore \\textit{base backup} of already installed applications whose version codes are higher than the installed version code.\n%%!!>>\n\n\\subsection{Trim Caches in All Apps}\\label{subsec:trim-caches-in-all-apps} %%##$trim-caches-in-all-apps-title>>\n%%!!trim-caches-in-all-apps<<\nDelete caches from all applications, including Android system. During this operation, caches of all the running\napplications may not be cleared as expected.\n%%!!>>\n"
  },
  {
    "path": "docs/raw/en/pages/profile-page.tex",
    "content": "% SPDX-License-Identifier: GPL-3.0-or-later OR CC-BY-SA-4.0\n\\section{Profile Page}\\label{sec:profile-page} %%##$section-title>>\n%%!!intro<<\nProfile page displays the configurations for a profile. It also offers the options to edit them.\n%%!!>>\n\n\\subsection{Options Menu}\\label{subsec:profile-options-menu} %%##$options-menu-title>>\n%%!!options-menu<<\nThe three dots menu in the top-right corner opens the options-menu. It contains several options such as--\n\\begin{itemize}\n    \\item \\textbf{Apply.} This option can be used to apply the profile directly. When\n    clicked, a dialog is displayed where it is possible to select a \\hyperref[subsubsec:profile-state]{profile state}.\n    On selecting one of the states, the profile will be applied immediately.\n    \\begin{tip}{Notice}\n        When you apply a profile, if some packages do not match the criteria, they will simply be ignored.\n    \\end{tip}\n\n    \\item \\textbf{Save.} Save changes to the profile.\n\n    \\item \\textbf{Discard.} Discard any modifications made since the last time it was saved.\n\n    \\item \\textbf{Delete.} Clicking on this option will remove the profile immediately without a warning.\n\n    \\item \\textbf{Duplicate.} This option can be used to duplicate the profile. When clicked, a\n    dialog is displayed where it is possible to set a name for the new profile. On clicking ``OK'',\n    this page will be reloaded by duplicating all the configurations that this profile have.\n    However, the new profile will not be saved until it is saved manually.\n\n    \\item \\textbf{Create shortcut.} This option can be used to create a shortcut for the profile.\n    There are two options: \\textit{Simple} and \\textit{Advanced}. When configured with the latter\n    option, it prompts the user to select a profile state when the shortcut is invoked. The former\n    option, on the other hand, always uses the default state that was configured when the profile\n    was last saved.\n\\end{itemize}\n%%!!>>\n\n\\subsection{Apps Tab}\\label{subsec:profile-apps-tab} %%##$apps-tab-title>>\n%%!!apps-tab<<\nApps tab lists the packages configured for this profile. Packages can be added or removed using the\n\\textit{plus} button located near the bottom of the screen. A package can also be removed by long\nclicking on it (in which case, a popup will be displayed with the only option, \\textit{delete}).\n%%!!>>\n\n\\subsection{Configurations Tab}\\label{subsec:profile-configurations-tab} %%##$configurations-tab-title>>\n%%!!configurations-tab<<\nConfigurations tab can be used to configure the selected packages.\n\n\\begin{tip}{Uninstalling a List of Applications.}\n    Since uninstalling is a one time event, it is not part of the configurations. However, it is\n    still possible to uninstall the applications belonging to a profile. To do this, you can filter\n    the applications in the Main page using a profile, select all the filtered applications, and\n    uninstall them.\n\\end{tip}\n%%!!>>\n\n\\subsubsection{Profile ID} %%##$profile-id-title>>\n%%!!profile-id<<\nThe unique ID for this profile, currently set based on the profile name. The profile ID can be used\nto \\hyperref[subsec:triggering-a-profile]{trigger the profile} from a third-party application.\n%%!!>>\n\n\\subsubsection{Comment} %%##$comment-title>>\n%%!!comment<<\nThis is the text that will be displayed in the \\hyperref[sec:profiles-page]{profiles page}. If not set, the current\nconfigurations will be displayed instead.\n%%!!>>\n\n\\subsubsection{State}\\label{subsubsec:profile-state} %%##$state-title>>\n%%!!state<<\nDenotes how certain configured options will behave by default. For instance, if \\textit{disable} option is turned on,\nthe applications will be disabled if the state is \\textit{on} and will be enabled if the state is \\textit{off}.\nCurrently, it only supports \\textit{on} and \\textit{off} values.\n%%!!>>\n\n\\subsubsection{Users} %%##$users-title>>\n%%!!users<<\nSelect users for which is the profile will be applied. All users are selected by default.\n%%!!>>\n\n\\subsubsection{Components} %%##$components-title>>\n%%!!components<<\nThis behaves the same way as the \\hyperref[subsec:block-components-dots]{Block Components\\dots} option does in the\n1-Click Ops page. However, the blocking here is only applied to the selected packages.\nIf the \\hyperref[subsubsec:profile-state]{state} is \\textit{on}, the components will be blocked,\nand if the state is \\textit{off}, the components will be unblocked.\nThe option can be disabled (regardless of the inserted values) by clicking on the \\textit{disabled} button on the input dialog.\n\n\\seealsoinline{\\hyperref[subsec:faq:what-are-app-components]{What are the app components?}}\n%%!!>>\n\n\\subsubsection{App Ops} %%##$app-ops-title>>\n%%!!app-ops<<\nThis behaves the same way as the \\hyperref[subsec:set-mode-for-app-ops-dots]{Set Mode for App Ops\\dots} option does in\nthe 1-Click Ops page. However, the operation here is only applied to the selected packages.\nIf the \\hyperref[subsubsec:profile-state]{state} is \\textit{on}, the app ops will be denied (i.e.\\ ignored),\nand if the state is \\textit{off}, the app ops will be allowed. The option can be disabled (regardless of the inserted\nvalues) by clicking on the \\textit{disable} button in the input dialog.\n%%!!>>\n\n\\subsubsection{Permissions} %%##$permissions-title>>\n%%!!permissions<<\nThis option can be used to grant or revoke certain permissions from the selected packages. Like others above,\npermissions must be separated by white spaces. If the \\hyperref[subsubsec:profile-state]{state} is \\textit{on}, the\npermissions will be revoked, and if the state is \\textit{off}, the permissions will be allowed. The option can be\ndisabled (regardless of the inserted values) by clicking on the \\textit{disable} button in the input dialog.\n%%!!>>\n\n\\subsubsection{Backup/Restore} %%##$backup-restore-title>>\n%%!!backup-restore<<\nThis option can be used to take a backup of the selected applications and its data or restore them.\nTwo options are available here: \\textit{Backup options} and \\textit{backup name}.\n\\begin{itemize}\n    \\item \\textbf{Backup options.} Same as the \\hyperref[subsec:backup-restore-backup-options]{backup options} of the\n    backup/restore feature. If not set, the default options will be used.\n    \\item \\textbf{Backup name.} Set a custom name for the backup. If the backup name is set, each time a backup is made,\n    it will be given a unique name with backup-name as the suffix. This behaviour will be fixed in a future release.\n    Leave this field empty for regular ``base'' backups (also, make sure not to enable \\textit{backup multiple} in the\n    backup options).\n\\end{itemize}\n\nIf the \\hyperref[subsubsec:profile-state]{state} is \\textit{on}, the packages will be backed up, and if the state is\n\\textit{off}, the packages will be restored. The option can be disabled by clicking on the \\textit{disable} button in\nthe input dialog.\n%%!!>>\n\n\\subsubsection{Export Blocking Rules} %%##$export-blocking-rules-title>>\n%%!!export-blocking-rules<<\n\\begin{danger}{Danger}\n    This option is not yet implemented.\n\\end{danger}\n%%!!>>\n\n\\subsubsection{Freeze} %%##$freeze-title>>\n%%!!freeze<<\nAllow freezing or unfreezing the selected packages depending on the value of the \\hyperref[subsubsec:profile-state]{state}.\nIf the state is \\textit{on}, the packages will be frozen, and if the state is \\textit{off}, they will be unfrozen.\n%%!!>>\n\n\\subsubsection{Force-stop} %%##$force-stop-title>>\n%%!!force-stop<<\nAllow the selected packages to be force-stopped.\n%%!!>>\n\n\\subsubsection{Clear Cache} %%##$clear-cache-title>>\n%%!!clear-cache<<\nEnable clearing cache for the selected packages.\n%%!!>>\n\n\\subsubsection{Clear Data} %%##$clear-data-title>>\n%%!!clear-data<<\nEnable clearing data for the selected packages.\n%%!!>>\n\n\\subsubsection{Block Trackers} %%##$block-trackers-title>>\n%%!!block-trackers<<\nEnable blocking or unblocking of the tracker components from the selected packages depending on the value of the \\hyperref[subsubsec:profile-state]{state}.\nIf the state is \\textit{on}, the trackers will be blocked, and if the state is \\textit{off}, the trackers will be unblocked.\n%%!!>>\n\n\\subsubsection{Save APK} %%##$save-apk-title>>\n%%!!save-apk<<\nEnable saving APK files at \\texttt{AppManager/apks} (or in the directory selected in the settings page) of the selected packages.\n%%!!>>\n"
  },
  {
    "path": "docs/raw/en/pages/profiles-page.tex",
    "content": "% SPDX-License-Identifier: GPL-3.0-or-later OR CC-BY-SA-4.0\n\\section{Profiles Page}\\label{sec:profiles-page} %%##$section-title>>\n%%!!intro<<\nProfiles page can be accessed from the \\hyperref[subsec:main-page-options-menu]{options-menu} in the\nmain page. It primarily displays a list of configured profiles along with the typical options to\nperform operations on them. New profiles can also be added using the \\textit{plus} button at the\nbottom-right corner. Profiles can be imported, duplicated or deleted. Clicking on a profile item\nopens its \\hyperref[sec:profile-page]{profile page}.\n%%!!>>\n\n\\subsection{Options Menu}\\label{subsec:profiles-options-menu} %%##$options-menu-title>>\n%%!!options-menu<<\nThe three-dots menu in the top-right corner opens the global option menu. It has an option to import\nan existing profile that was previously exported from App Manager.\n\nLong clicking on any profile item brings up another options-menu. It offers the following options:\n\\begin{itemize}\n    \\item \\textbf{Apply now\\dots.} This option can be used to apply the profile directly. When\n    clicked, a dialog is displayed where it is possible to select a \\hyperref[subsubsec:profile-state]{profile state}.\n    On selecting one of the states, the profile will be applied immediately.\n\n    \\item \\textbf{Delete.} Clicking on this option will remove the profile immediately without a warning.\n\n    \\item \\textbf{Duplicate.} This option can be used to duplicate the profile. When clicked, a\n    dialog is displayed where it is possible to set a name for the new profile. On clicking ``OK'',\n    the \\hyperref[sec:profile-page]{profile page} will be loaded by duplicating all the\n    configurations that this profile have. However, the profile will not be saved until it is saved\n    manually.\n\n    \\item \\textbf{Copy profile ID.} This option is used to copy the unique profile ID of the profile.\n    The profile ID can be used to \\hyperref[subsec:triggering-a-profile]{trigger the profile} from a\n    third-party application.\n\n    \\item \\textbf{Export.} Export the profile to an external storage. Profiles exported this way can\n    be imported via the \\textit{import} option as mentioned above.\n\n    \\item \\textbf{Create shortcut.} This option can be used to create a shortcut for the profile.\n    There are two options: \\textit{Simple} and \\textit{Advanced}. When configured with the latter\n    option, it prompts the user to select a profile state when the shortcut is invoked. The former\n    option, on the other hand, always uses the default state that was configured when the profile\n    was last saved.\n\\end{itemize}\n%%!!>>\n"
  },
  {
    "path": "docs/raw/en/pages/scanner-page.tex",
    "content": "% SPDX-License-Identifier: GPL-3.0-or-later OR CC-BY-SA-4.0\n\\section{Scanner Page}\\label{sec:scanner-page} %%##$section-title>>\n%%!!intro<<\n\\textbf{Scanner page} appears after clicking on the \\emph{scanner} button in the \\hyperref[subsec:app-info-tab]{App Info tab}.\nExternal APK files can also be opened for scanning from file managers, web browsers, etc.\n\nIt scans for trackers and libraries, and displays the number of trackers and libraries as a summary.\nIt also displays checksums of the APK file as well as the signing certificates. If VirusTotal is\nconfigured in the settings, it also attempts to retrieve reports from VirusTotal, or uploads the APK\nfile if it is not in the database. It also display a link to the \\href{https://beta.pithus.org}{Pithus}\nreport provided the Internet features are enabled.\n\n\\begin{danger}{Disclaimer}\n    App Manager only scans an application statically without prejudice. The application may provide\n    the options for opting out, or in some cases, certain features of the tracker may not be used at\n    all by the application (e.g.\\ F-Droid), or some applications may simply use them as placeholders\n    to prevent the breaking of certain features (e.g.\\ Fennec F-Droid). \\textbf{The intention of the\n    scanner is to give you an idea about what the APK might contain. It should be taken as an\n    initial step for further investigations.}\n\\end{danger}\n\nClicking on the first item (i.e.\\ number of classes) opens a new page containing a list of tracker\nclasses for the application. All classes can also be viewed by clicking on the \\textit{Toggle Class\nListing} menu. The SMALI or Java version of the class can be viewed by simply clicking on an item.\n\n\\begin{tip}{Notice}\n    Due to various limitations, it is not possible to scan all the components of an APK file. This\n    is especially true if an APK is highly obfuscated or packed. The scanner also does not check\n    strings (or website signatures).\n\\end{tip}\n\nThe second item lists the number of trackers along with their names. Clicking on the item displays a\ndialog containing the name of trackers, matched signatures, and the number of classes against each\nsignature. Some tracker names may have $^2$ prefix which indicates that the trackers are in the\n\\href{https://etip.exodus-privacy.eu.org}{ETIP} stand-by list, i.e., whether they are actual\ntrackers is still being investigated.\n\nThe third item lists the number of libraries along with their names. The information are mostly\ntaken from \\href{https://gitlab.com/IzzyOnDroid/repo}{IzzyOnDroid repo}.\n\n\\seealsoinline{\\hyperref[subsec:tracker-classes-versus-tracker-components]{FAQ: Tracker classes vs tracker components}}\n%%!!>>\n\n%\\subsection{Missing Signatures}\\label{subsec:missing-signatures} %%##$missing-signatures-title>>\n%%!!missing-signatures<<\n%At the bottom of the page, there is a special item denoting the number of missing signatures (i.e.,\n%missing classes). The missing signatures are the ones that App Manager has failed to match against\n%any known libraries. The number itself has no particular meaning as many libraries contain hundreds\n%of classes, but clicking on the item will bring up a dialog containing the signatures which is\n%helpful in inspecting the missing signatures. \\textbf{This feature is only intended for people who\n%know what a missing signature is and what to do with it, other users should ignore it.}\n%%!!>>\n"
  },
  {
    "path": "docs/raw/en/pages/settings-page.tex",
    "content": "% SPDX-License-Identifier: GPL-3.0-or-later OR CC-BY-SA-4.0\n\\section{Settings Page}\\label{sec:settings-page} %%##$section-title>>\n%%!!intro<<\nSettings page can be used to customise the behaviour of App Manager.\n%%!!>>\n\n\\subsection{Language}\\label{subsec:language} %%##$language-title>>\n%%!!language<<\nConfigure in-app language. App Manager currently supports 22 (twenty-two) languages.\n%%!!>>\n\n\\subsection{Appearance}\\label{subsec:appearance} %%##$appearance-title>>\n\n\\subsubsection{App Theme}\\label{subsubsec:app-theme} %%##$app-theme-title>>\n%%!!app-theme<<\nConfigure in-app theme.\n%%!!>>\n\n\\subsubsection{Pure Black Theme}\\label{subsubsec:pure-black-theme} %%##$pure-black-theme-title>>\n%%!!pure-black-theme<<\nWhether to use a black background instead of the material themed background.\n%%!!>>\n\n\\subsubsection{Layout Direction}\\label{subsubsec:layout-direction} %%##$layout-direction-title>>\n%%!!layout-direction<<\nChange layout direction, either left to right or right to left. This is usually set using the selected language but not\neverybody prefers the same direction.\n%%!!>>\n\n\\subsubsection{Enable/Disable Features}\\label{subsubsec:enable/disable-features} %%##$enable-disable-features-title>>\n%%!!enable-disable-features<<\nEnable or disable certain features in App Manager, such as\n\\begin{itemize}\n    \\item \\textbf{Interceptor}\n    \\item \\textbf{Manifest viewer}\n    \\item \\textbf{Scanner}\n    \\item \\textbf{Package installer}\n    \\item \\textbf{Usage access.} With this feature turned off, App Manager will never ask for the \\textit{Usage Access} permission.\n    \\item \\textbf{Log viewer}\n    \\item \\textbf{App explorer.} The ``Explore'' option will not be available while trying to open an APK file.\n    \\item \\textbf{App info.} The ``App info'' option displayed while trying to open an APK file.\n    \\item \\textbf{Code Editor}\n    \\item \\textbf{VirusTotal}\n\\end{itemize}\n%%!!>>\n\n\\subsection{Privacy}\\label{subsec:privacy} %%##$privacy-settings-title>>\n\n\\subsubsection{Screen Lock}\\label{subsubsec:screen-lock} %%##$screen-lock-title>>\n%%!!screen-lock<<\nLock App Manager using Android screen lock provided a screen lock is configured.\n\n\\begin{warning}{Warning}\n    If screen lock is disabled in Android after enabling this setting, App Manager will not open until it is enabled again.\n\\end{warning}\n%%!!>>\n\n\\subsubsection{Run App Manager in the Background}\\label{subsubsec:run-am-in-background} %%##$run-am-in-background-title>>\n%%!!run-am-in-background<<\nWhether to run App Manager in the background to reduce the initialisation delay. On certain devices,\nthis can also help if you're frequently disconnected from ADB\\@.\n%%!!>>\n\n\\subsubsection{Use the Internet}\\label{subsubsec:use-the-internet} %%##$use-the-internet-title>>\n%%!!use-the-internet<<\nWhether to activate the Internet features in App Manager. This currently include VirusTotal and\nPithus scanning in the \\hyperref[sec:scanner-page]{Scanner page}.\n%%!!>>\n\n\\subsubsection{Authorization Manager}\\label{subsubsec:auth-manager} %%##$auth-manager-title>>\n%%!!auth-manager<<\nThis setting allows a third-party application to get access to certain features, such as profiles.\n%%!!>>\n\n\\subsection{Mode of Operation}\\label{subsec:mode-of-operation} %%##$mode-of-operation-title>>\n%%!!mode-of-operation<<\nMode of operation defines how App Manager works as a whole. It has the following options:\n\\begin{itemize}\n    \\item \\textbf{Auto.} Let App Manager decide the suitable option.\n    Although this is the default option, non-rooted users should use the \\textit{no-root} mode.\n\n    \\item \\textbf{Root.} Operate App Manager in root mode. App Manager will fall back to \\textit{no-root} mode if root\n    is not detected, or in rare cases when Binder communication through root is disabled (e.g.\\ in \\href{https://github.com/MuntashirAkon/AppManager/issues/606}{Phh SuperUser}).\n\n    \\item \\textbf{ADB over TCP.} Operate App Manager in ADB mode via \\hyperref[sec:adb-over-tcp]{ADB over TCP}.\n    App Manager will fall back to \\textit{no-root} mode if ADB over TCP is not enabled.\n\n    \\item \\textbf{Wireless debugging.} Enable ADB via Wireless Debugging. It will try to connect to the configured port\n    automatically at first. On failure, it will ask the user to either pair or connect to the ADB daemon manually.\n    App Manager will fall back to \\textit{no-root} mode if it fails to connect to the ADB daemon this way.\n    \\begin{tip}{Info}\n        This option is only displayed in devices running Android 11 or later as Wireless Debugging was introduced in Android 11.\n    \\end{tip}\n\n    \\item \\textbf{No-root.} Operate App Manager in no-root mode. While App Manager performs better in this mode,\n    all the root- or ADB-specific features will be disabled.\n\\end{itemize}\n\nIt also displays the actual mode of operation at the top. The actual mode of operations are\n\\textit{root}, \\textit{ABD} and \\textit{no-root}.\n\n\\begin{tip}{Notice}\n    ``Remote service'' is only required for ADB users or when you use the custom commands.\n\\end{tip}\n%%!!>>\n\n\n\\subsection{APK Signing}\\label{subsec:apk-signing} %%##$apk-signing-title>>\n\n\\subsubsection{Signature Schemes} %%##$signature-schemes-title>>\n%%!!signature-schemes<<\nConfigure the \\href{https://source.android.com/security/apksigning}{signature schemes} to be used when APK signing is enabled.\nv1 and v2 signature schemes are enabled by default, but v3 should also be enabled to ensure proper security in Android 9 or later.\n%%!!>>\n\n\\subsubsection{Signing Key} %%##$signing-key-title>>\n%%!!signing-key<<\nConfigure the signing key for signing APK files. Keys from an existing KeyStore can be imported to App Manager,\nor a new key can be generated.\n\n\\begin{tip}{Tip}\n    If you need to use the key in the future, it is recommended that you create a KeyStore yourself\n    and import the key here. Without a proper backup, keys generated within App Manager are at the risk of being deleted.\n\\end{tip}\n%%!!>>\n\n\\subsubsection{Align APK Files} %%##$align-apk-files-title>>\n%%!!align-apk-files<<\nPerforms zip alignment when App Manager signs an APK file. Zip alignment stores the files in the APK\nfile (which is actually a zip file) in a way that a zip file reader can access the files quite\neasily using random access instead of loading the entire APK file in the memory, which results in\nthe reduction of Android's memory usage. Note that this step is required if an application's\nmanifest has \\texttt{extractNativeLibs} set to \\texttt{true}.\n%%!!>>\n\n\\subsection{Installer}\\label{subsec:installer} %%##$installer-title>>\n%%!!installer-subtitle<<\nConfigure the default behaviour of the installer. You can also find most of the settings by clicking\non the \\textit{cog} icon when you install an application.\n%%!!>>\n\n\\subsubsection{Install Location} %%##$install-location-title>>\n%%!!install-location<<\nDefine APK installation location. This can be one of \\textit{auto}, \\textit{internal only} and \\textit{prefer external}.\nIn newer Android versions, selecting the last option does not guarantee that the application will be installed in the\nexternal storage.\n%%!!>>\n\n\\subsubsection{Block Trackers} %%##$block-trackers-title>>\n%%!!block-trackers<<\nWhether to block the tracking components immediately after installing the application.\n%%!!>>\n\n\\subsubsection{Display Changes} %%##$display-changes-title>>\n%%!!display-changes<<\nWhether to display changes in version, trackers, components, permissions, signatures, SDK, etc. in a version controlled\nstyle before installing the application if the application has already been installed.\n%%!!>>\n\n\\subsubsection{Installer App} %%##$installer-app-title>>\n%%!!installer-app<<\nSelect the installer application. This is useful for applications that explicitly checks the installer as a way to\nverify if the application is installed legitimately. This only works for root or ADB users.\n\n\\begin{tip}{Notice}\n    While checking for the installer might seem a legitimate concern for an application, the Android framework already\n    deals with this during the installation. Checking for the installer is simply the wrong way to prove the legitimacy\n    of the source of an application.\n\\end{tip}\n%%!!>>\n\n\\subsubsection{Sign APK} %%##$sign-apk-title>>\n%%!!sign-apk<<\nWhether to sign the APK files before installing the application. A signing key has to be added or generated before this\noption can be enabled. This can be done in the \\hyperref[subsec:apk-signing]{APK signing} page.\n%%!!>>\n\n\\subsubsection{Immediately Perform DEX Optimization} %%##$immediately-perform-dex-opt-title>>\n%%!!immediately-perform-dex-op<<\nWhether to perform DEX optimization immediately after installing the application. This can be useful\nfor heavy applications, such as the gaming applications.\n%%!!>>\n\n\\subsubsection{Install in the Background} %%##$install-in-the-background-title>>\n%%!!install-in-the-background<<\nWhether to always install applications in the background. A notification will be issued once the installation is finished.\n%%!!>>\n\n\n\\subsection{Back up/Restore}\\label{subsec:backup/restore} %%##$backup-restore-title>>\n%%!!backup-restore<<\nSettings related to \\hyperref[sec:backup-restore]{back up/restore}.\n%%!!>>\n\n\\subsubsection{Compression method} %%##$compression-method-title>>\n%%!!compression-method<<\nSet the compression method to be used during backups. App Manager supports GZip, BZip2 and Zstandard\ncompression methods, GZip being the default compression method. It doesn't affect the restore of\nan existing backup.\n%%!!>>\n\n\\subsubsection{Backup Options}\\label{subsubsec:settings-backup-options} %%##$backup-options-title>>\n%%!!backup-options<<\nCustomise the \\textit{back up/restore dialog} displayed while taking a backup.\n\n\\seealsoinline{\\hyperref[subsec:backup-restore-backup-options]{Backup options}}\n%%!!>>\n\n\\subsubsection{Backup apps with Android KeyStore} %%##$backup-apps-with-keystore-title>>\n%%!!backup-apps-with-keystore<<\nAllow backup of applications that has entries in the Android KeyStore. This option is disabled by\ndefault because a few apps (such as Signal or Element) may crash if restored.\n%%!!>>\n\n\\subsubsection{Encryption}\\label{subsubsec:settings-encryption} %%##$encryption-title>>\n%%!!encryption<<\nSet an encryption method for the backups. App Manager currently supports OpenPGP (via\n\\href{https://f-droid.org/packages/org.sufficientlysecure.keychain/}{OpenKeyChain}), AES, RSA and ECC\\@.\nLike \\hyperref[subsec:apk-signing]{APK signing}, The AES, RSA and ECC keys are stored in the\nKeyStore and can be imported from other KeyStores.\n\n\\begin{danger}{Danger}\n    For your own safety, it is not recommended generating RSA and ECC keys inside App Manager.\n    Instead, they should be imported from a KeyStore stored in a secure place.\\\\\n    In case of AES, the generated key should be stored in a secure place, such as in a password manager.\n\\end{danger}\n%%!!>>\n\n\\subsubsection{Backup Volume}\\label{subsubsec:backup-volume} %%##$backup-volume-title>>\n%%!!backup-volume<<\nSelect the storage where the backups will be stored. This is also where logs and exported APK files are saved.\n\n\\begin{tip}{Notice}\n    The backup volume only specifies the storage, not the path. Backups are traditionally stored in the \\texttt{AppManager} folder inside the storage path.\n    But when the path is selected using Storage Access Framework (SAF), the selected path or directory is used directly.\n\\end{tip}\n%%!!>>\n\n\\subsubsection{Import Backups} %%##$import-backups-title>>\n%%!!import-backups<<\nImport backups from old and discontinued projects such as Titanium Backup, OAndBackup, and Swift Backup (version 3.0 to 3.2).\nThe backups are not deleted after importing to prevent data loss in case the imported backups cannot be restored properly.\n%%!!>>\n\n\n\\subsection{Rules}\\label{subsec:rules} %%##$rules-title>>\n\n\\subsubsection{Instant Component Blocking}\\label{subsubsec:instant-component-blocking} %%##$instant-component-blocking-title>>\n%%!!instant-component-blocking<<\nBy default, blocking rules are not applied unless they are applied explicitly in \\hyperref[sec:app-details-page]{the App Details page} for any application.\nAfter enabling this option, all (old and new) rules are applied immediately for all applications without explicitly enabling blocking for an application.\n\n\\seealsoinline{\\hyperref[subsec:faq:what-is-instant-component-blocking]{FAQ: What is instant component blocking?}}\n%%!!>>\n\n\\subsubsection{Import/Export Blocking Rules} %%##$import-export-blocking-rules-title>>\n%%!!import-export-blocking-rules<<\nIt is possible to import or export blocking rules within App Manager for all applications. The types of rules (components, app ops or permissions) that should be imported or exported can also be selected.\nIt is also possible to import blocking rules from \\href{https://github.com/lihenggui/blocker}{Blocker} and \\href{https://github.com/tuyafeng/Watt}{Watt}.\nIf it is necessary to export blocking rules for a single application, the corresponding \\hyperref[sec:app-details-page]{App Details page} can be used to export rules, or for multiple apps, \\hyperref[subsec:batch-operations]{batch operations} can be used.\n\n\\seealsoinline{\\hyperref[sec:rules-specification]{Rules Specification}}\n\n\\paragraph{Export} Export blocking rules for all applications configured within App Manager.\nThis may include \\hyperref[subsec:faq:what-are-app-components]{app components}, app ops and permissions based on the options selected in the multi-choice options.\n\n\\paragraph{Import} Import previously exported blocking rules from App Manager.\nSimilar to export, this may include \\hyperref[subsec:faq:what-are-app-components]{app components}, app ops and permissions based on the options selected in the multi-choice options.\n\n\\paragraph{Import Existing Rules}\\label{par:import-existing-rules}\n\\phantomsection\nAdd components disabled by other applications to App Manager. App Manager only keeps track of the components disabled within App Manager.\nIf application components are blocked or disabled by other tools or applications, this option can be utilised to import them.\nOn clicking this option, App Manager will find the components potentially disabled by other applications or tools and list only the name of the applications along with the number of matched components.\nFor safety, all the applications are unselected by default. They have to be selected manually, and the blocking has to be re-applied via App Manager.\n\n\\begin{danger}{Caution}\n    Be careful when using this tool as there can be many false positives.\n    Choose only the applications that you are certain about.\n\\end{danger}\n\n\\paragraph{Import from Watt} Import configuration files from \\href{https://github.com/tuyafeng/Watt}{Watt}, each file\ncontaining rules for a single package and file name being the name of the package with \\texttt{.xml} extension.\n\n\\begin{tip}{Tip}\n    Location of configuration files in Watt: \\texttt{/sdcard/Android/data/com.tuyafeng.watt/files/ifw}\n\\end{tip}\n\n\\paragraph{Import from Blocker} Import blocking rules from \\href{https://github.com/lihenggui/blocker}{Blocker}, each file containing rules for a single package.\nThese files have a \\texttt{.json} extension.\n%%!!>>\n\n\\subsubsection{Remove all rules} %%##$remove-all-rules-title>>\n%%!!remove-all-rules<<\nOne-click option to remove all rules configured within App Manager.\nThis will enable all blocked components, app ops will be set to their default values and permissions will be granted.\n%%!!>>\n\n\n\\subsection{Advanced}\\label{subsec:advanced} %%##$advanced-settings-title>>\n\n\\subsubsection{Selected Users}\\label{subsubsec:selected-users} %%##$selected-users-title>>\n%%!!selected-users<<\nThis option lets you control the users App Manager should operate on. App Manager operates on all users in root or ADB mode by default.\n%%!!>>\n\n\\subsubsection{Saved APK Name Format}\\label{subsubsec:saved-apk-name-format} %%##$saved-apk-name-format-title>>\n%%!!saved-apk-name-format<<\nDefines the format of the APK name to be used while saving it via batch operations or through profiles.\nApp Manager offers some special keywords enclosed inside \\texttt{\\%} (percentage) signs and available below the input box.\nThese keywords are:\n\\begin{itemize}\n    \\item \\textbf{\\texttt{label}.} Denotes the name or label of the application. This can be localised to the configured language depending on the app.\n    \\item \\textbf{\\texttt{package\\_name}.} Denotes the name of the package or application ID, the unique identifier that each application has.\n    \\item \\textbf{\\texttt{version}.} Denotes the current version of the application extracted from its manifest.\n    \\item \\textbf{\\texttt{version\\_code}.} Denotes the current version code of the application that can be used to separate two versions of the same application.\n    \\item \\textbf{\\texttt{min\\_sdk}.} Denotes the minimum SDK (i.e.\\ Android framework version) that the application can operate on. This data is only available since Android 7 (Nougat).\n    \\item \\textbf{\\texttt{target\\_sdk}.} Denotes the SDK that this application targets. The application can operate on higher SDK but only in the compatibility mode.\n    \\item \\textbf{\\texttt{datetime}.} Denotes the time and date when the APK is exported.\n\\end{itemize}\n%%!!>>\n\n\\subsubsection{Import/Export Keystore}\\label{subsubsec:import/export-keystore} %%##$import-export-keystore-title>>\n%%!!import-export-keystore<<\nImport or export the KeyStore used by App Manager. This is a Bouncy Castle KeyStore with \\texttt{bks} extension.\nTherefore, other KeyStore such as Java KeyStore (JKS) or PKCS \\#12 are not supported.\nIf a key is needed to be imported from such a KeyStore, the relevant options should be should as specified above.\n%%!!>>\n\n\n\\subsection{About the device}\\label{subsec:device-info} %%##$device-info-title>>\n%%!!device-info<<\nDisplay Android version, security, CPU, GPU, battery, memory, screen, languages, user info, etc.\n%%!!>>\n"
  },
  {
    "path": "docs/raw/en/pages/shared-prefs-editor-page.tex",
    "content": "% SPDX-License-Identifier: GPL-3.0-or-later OR CC-BY-SA-4.0\n\\section{Shared Preferences Editor Page}\\label{sec:shared-preferences-editor-page} %%##$section_title>>\n%%!!intro<<\nShared preferences can be edited in this page. Clicking any item on the list opens the edit dialog where the item can be\nedited. The floating action button in the bottom-right corner can be used to add a new item. To save or delete the file,\nor to discard current changes, the respective options in the menu can be used.\n%%!!>>\n"
  },
  {
    "path": "docs/raw/en/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--This file is auto-generated by ./scripts/docs.php. DO NOT EDIT THIS FILE.-->\n<resources xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\">\n    <string name=\"keywords$chapter\">\\\\newcommand{\\\\KeywordChapter}{Chapter}</string>\n    <string name=\"keywords$see_also\">\\\\newcommand{\\\\KeywordSeeAlso}{See also:}</string>\n    <string name=\"keywords$end_of_keyword_in_alert\">\\\\newcommand{\\\\KeywordEndOfKeyWordInAlert}{.}</string>\n    <string name=\"titlepage$user_manual\">{\\\\huge\\\\bfseries User Manual\\\\par}</string>\n    <string name=\"titlepage$quotation\">\\\\begin{quotation}\\n            ``Wisely and slow. They stumble that run fast.\\'\\'\\n            %\\\\sourceatright\\n                {--- Friar Laurence, \\\\textit{Romeo and Juliet}}\\n        \\\\end{quotation}</string>\n    <string name=\"intro$main$$introduction-chapter-title\">Introduction</string>\n    <string name=\"intro$main$$terminologies-title\">Terminologies</string>\n    <string name=\"intro$main$$supported-versions-title\">Supported Versions</string>\n    <string name=\"intro$main$$official-sources-title\">Official Sources</string>\n    <string name=\"intro$main$$bin-sources-title\">Binary Distribution Sources</string>\n    <string name=\"intro$main$$source-code-links-title\">Links to the Source Code</string>\n    <string name=\"intro$main$$translations-title\">Translations</string>\n    <string name=\"intro$main$$contributing-title\">Contributing</string>\n    <string name=\"intro$main$$buiding-title\">Build Instructions</string>\n    <string name=\"intro$main$$submit-patches-title\">Submitting patches</string>\n    <string name=\"intro$main$$donation-title\">Donation \\\\&amp; Funding</string>\n    <string name=\"intro$main$$contact-title\">Contact</string>\n    <string name=\"intro$main$intro\">App Manager is an advanced package manager for Android. It offers numerous features and thus, requires a user\\nmanual to assist its users. This document acts as a user manual for App Manager in the sense that it aims to describe\\nevery feature that App Manager has to offer. This document also serves as the ``official\\'\\' guidelines for\\nApp Manager and represents the expected behavior of App Manager. Translations can misinterpret this document (which is\\nin English). Therefore, a capable user should read the English version of the document to get the most out\\nof it. There may as well be other unofficial or third-party resources, such as blog articles, videos, forums, and chat\\ngroups. While these resources may be useful to many people, they may not be up-to-date with the latest\\nversion of App Manager. In case of any deviations detected in App Manager from this document, they should be reported in the\\n\\\\href{https://github.com/MuntashirAkon/AppManager/issues}{App Manager issue tracker}.</string>\n    <string name=\"intro$main$terminologies\">\\\\begin{itemize}\\n    \\\\item \\\\textbf{AM} --- Short name for App Manager.\\n    \\\\item \\\\textbf{Block/Unblock} --- Used for component blocking or unblocking. How components are blocked depends on\\n    the user preferences.\\n    \\\\item \\\\textbf{IFW} --- Short form of Intent Firewall.\\n    \\\\item \\\\textbf{Ops} --- Short name for operations, e.g.\\\\ app ops, batch ops, 1-click ops\\n    \\\\item \\\\textbf{SAF} --- Short for Storage Access Framework, an abstraction used by Android to allow apps to use or\\n    serve files without worrying about the underlying file system.\\n    \\\\item \\\\textbf{SSAID} --- Short form of \\\\texttt{Settings.Secure.ANDROID\\\\_ID}. It is a device identifier assigned to\\n    each app (Android Oreo onwards). It is generated from the combination of the signing certificate of the app\\n    and the SSAID set for the package \\\\texttt{android}. As a result, it is guaranteed to be the same for an app unless\\n    the user chooses to format the device. It is widely used for tracking.\\n    \\\\item \\\\textbf{Tracker} --- Denotes tracker components throughout the document and in App Manager except in the\\n    \\\\hyperref[sec:scanner-page]{scanner page}. Trackers include libraries such as crash reporters, analytics,\\n    profiling, identification, ad, location, etc. Thus, they are not equal in functions. There is no distinction or bias\\n    among the open-source and closed-source libraries that promote tracking.\\n\\\\end{itemize}</string>\n    <string name=\"intro$main$supported-versions\">At present, the supported version is v4.0.1.\\nPrevious versions of App Manager may contain security vulnerabilities and should not be used.</string>\n    <string name=\"intro$main$bin-sources\">App Manager is distributed using the following sources. Unofficial sources may distribute modified versions of App\\nManager, and you alone shall be responsible for the consequences of using such a distribution.\\n\\\\begin{enumerate}\\n    \\\\item Official F-Droid repository.\\\\\\\\\\n    \\\\textit{Link:} \\\\url{https://f-droid.org/packages/io.github.muntashirakon.AppManager}\\n    \\\\item IzzyOnDroid repository.\\\\\\\\\\n    \\\\textit{Link:} \\\\url{https://apt.izzysoft.de/fdroid/index/apk/io.github.muntashirakon.AppManager}\\n    \\\\item GitHub repository.\\\\\\\\\\n    \\\\textit{Link:} \\\\url{https://github.com/MuntashirAkon/AppManager/releases}\\n    \\\\item Telegram.\\\\\\\\\\n    \\\\textit{Link:} \\\\url{https://t.me/AppManagerChannel}\\n\\\\end{enumerate}</string>\n    <string name=\"intro$main$source-code-links\">All but GitHub are mirrors. The tags should always be up-to-date, but the master branch may not.\\nIf you want to clone the master branch, use the GitHub link instead of the others.</string>\n    <string name=\"intro$main$translations\">App Manager does not accept translations via pull/merge requests. Translations are managed through\\nHosted Weblate. To translate App Manager, visit \\\\url{https://hosted.weblate.org/engage/app-manager/}.\\nPlease read the \\\\textbf{Info} section before getting started.</string>\n    <string name=\"intro$main$contributing\">There are many ways a user can contribute, such as creating helpful issues, attending discussions,\\nimproving documentation and translations, reporting unknown libraries or trackers, reviewing the source code,\\nand reporting security vulnerabilities.</string>\n    <string name=\"intro$main$buiding\">Build instructions are available in the BUILDING file located in the source root.</string>\n    <string name=\"intro$main$submit-patches\">Repositories located on sites other than GitHub are currently considered mirrors, and pull/merge requests submitted on\\nthose sites will not be accepted.\\\\footnote{GitHub pull requests will be merged manually using the corresponding patches.\\nAs a result, GitHub may wrongfully mark them closed instead of merged.} Instead, patches (as \\\\texttt{.patch} files) can\\nbe submitted via email attachments. \\\\textit{Signing-off is a requirement.} See the CONTRIBUTING file\\nlocated at the source root for more information.\\n\\n\\\\begin{warning}{Notice}\\n    In the case of submitting patches via email, the whole conversation may be publicly accessible in the future.\\n    So, please do not include personally identifiable information (PII) other than your name or email address.\\n\\\\end{warning}</string>\n    <string name=\"intro$main$donation\">% \\\\emph{Donation or purchasing is not a requirement in order to use App Manager.} While App Manager does not support any\\n% purchases, donations can be sent to the owner of App Manager through Open Source Collective.\\n%\\n% Open Source Collective is a fiscal host in the Open Collective platform which helps the open source projects manage\\n% their finances. At present, it supports payments through bank accounts, PayPal, credit or debit cards and\\n% cryptocurrencies.\\n%\\n% \\\\textit{Link:} \\\\url{https://opencollective.com/muntashir}.\\n%\\n% By sending donations, the senders agree that they shall not use the donations as a leverage to prioritise their\\n% requested features. Feature requests do not require any bounties or donations, and they are prioritised in accordance\\n% with the preferences of the owner.\\n%\\n% \\\\emph{App Manager accepts any offers of funding or grants.} Representatives of the interested organization can contact\\n% the owner directly using the options given in \\\\Sref{sec:contact}.\\n\\nAs of September 2024, App Manager is not accepting financial support until further notice. But\\nyou may still be able to send gifts (e.g., gift cards, subscriptions, food and drink, flowers, or\\neven cash). Please reach out to the maintainer using the options given in \\\\Sref{sec:contact} for further\\nassistance.</string>\n    <string name=\"intro$main$funding-disclaimer\">In addition, the maintainers and contributors of this project DO NOT consent to the creation, sale,\\nor promotion of tokens, cryptocurrencies, NFTs, or any other financial instruments that claim to\\nrepresent this project, its code, or its community. Any such attempts are unauthorized and not\\naffiliated with this project in any way.</string>\n    <string name=\"intro$main$contact\">App Manager Community\\\\\\\\\\nEmail: \\\\href{mailto:am4android\\@riseup.net}{am4android [at] riseup [dot] net}\\\\\\\\\\nGitHub: \\\\url{https://github.com/AMCommunity}\\\\\\\\\\nTwitter/X: \\\\url{https://x.com/AppManagerNews}\\\\\\\\\\nMastodon: \\\\href{https://floss.social/\\@appmanager}{\\@appmanager\\@floss.social}\\\\\\\\\\n\\\\\\\\\\n\\nMuntashir Al-Islam\\\\footnote{You can also address me as ``Muntashir Akon\\'\\'}\\\\\\\\\\nEmail: \\\\href{mailto:muntashirakon\\@riseup.net}{muntashirakon [at] riseup [dot] net}\\\\\\\\\\nGitHub: \\\\url{https://github.com/MuntashirAkon}\\\\\\\\\\nTwitter/X: \\\\url{https://x.com/Muntashir}\\\\\\\\\\nMastodon: \\\\href{https://infosec.exchange/\\@muntashir}{\\@muntashir\\@infosec.exchange}</string>\n    <string name=\"pages$main$$pages-chapter-title\">Pages</string>\n    <string name=\"pages$main-page$$section-title\">Main Page</string>\n    <string name=\"pages$main-page$$how-app-ops-work-title\">An application list item in the main page</string>\n    <string name=\"pages$main-page$$batch-operations-title\">Batch Operations</string>\n    <string name=\"pages$main-page$$colour-codes-title\">Colour Codes</string>\n    <string name=\"pages$main-page$$application-types-title\">Application Types</string>\n    <string name=\"pages$main-page$$version-info-title\">Version Info</string>\n    <string name=\"pages$main-page$$options-menu-title\">Options Menu</string>\n    <string name=\"pages$main-page$$list-options-title\">List Options</string>\n    <string name=\"pages$main-page$$sort-title\">Sort</string>\n    <string name=\"pages$main-page$$filter-title\">Filter</string>\n    <string name=\"pages$main-page$$profile_name-title\">Profile Name</string>\n    <string name=\"pages$main-page$$instructions-title\">User Manual</string>\n    <string name=\"pages$main-page$$1-click-ops-title\">1-Click Ops</string>\n    <string name=\"pages$main-page$$app-usage-title\">App Usage</string>\n    <string name=\"pages$main-page$$running-apps-title\">Running Apps</string>\n    <string name=\"pages$main-page$$profiles-title\">Profiles</string>\n    <string name=\"pages$main-page$$apk-updater-title\">APK Updater</string>\n    <string name=\"pages$main-page$$termux-title\">Termux</string>\n    <string name=\"pages$main-page$$debloater-title\">Debloater</string>\n    <string name=\"pages$main-page$$labs-title\">Labs</string>\n    <string name=\"pages$main-page$$settings-title\">Settings</string>\n    <string name=\"pages$main-page$intro\">Main page lists all the installed, uninstalled and backed up applications. A single click on any\\ninstalled application item opens the respective \\\\hyperref[sec:app-details-page]{App Details page}.\\nFor the uninstalled system applications, a dialog prompt is displayed with an option reinstall them.\\nThe applications uninstalled without removing their data and signatures are also displayed in this\\npage with an option to perform a full uninstallation. For the uninstalled applications having one or\\nmore backups, the restore dialog is displayed. Using the \\\\hyperlink{par:main-page-sort}{sort} option\\nfrom the list options, the items can be sorted in various ways. It is also possible to filter items\\nusing the \\\\hyperlink{par:main-page-filter}{filter} option in the list options. Filtering is also\\npossible from the search bar with additional support for the regular expressions.</string>\n    <string name=\"pages$main-page$batch-operations\">Batch operations or operations on multiple applications are also available within this page.\\nMultiple selection mode can be activated by clicking on the app icon of an item or by long-clicking\\non any items in the list. Once activated, a click on an item selects it instead of opening the App\\nDetails page. In this mode, the batch operations are located in the multiple selection menu at the\\nbottom of the page. The operations include:\\n\\\\begin{itemize}\\n    \\\\item Adding the selected applications to a \\\\hyperref[sec:profiles-page]{profile}\\n    \\\\item \\\\hyperref[sec:backup-restore]{Backing up applications}, or restoring and deleting the\\n    existing backups\\n    \\\\item Blocking the trackers from the applications\\n    \\\\item Clearing data or cache from the applications\\n    \\\\item Exporting the blocking rules configured inside App Manager\\n    \\\\item Exporting the list of applications in Markdown, CSV, JSON or XML format\\n    \\\\item Freezing/unfreezing/force-stopping/uninstalling the applications\\n    \\\\item Performing run-time optimization of the applications (Android 7 onwards)\\n    \\\\item Preventing the background operations of the applications (Android 7 onwards)\\n    \\\\item Saving the APK files to \\\\texttt{AppManager/apks}\\n    \\\\item Setting \\\\hyperref[sec:net-policy]{net policies}\\n\\\\end{itemize}\\n\\n\\\\begin{tip}{Accessibility}\\n    After the multiple selection mode has been activated, it is possible to navigate in or out of\\n    the multiple selection menu using the right or left keys of the keyboard or remote.\\n\\\\end{tip}</string>\n    <string name=\"pages$main-page$colour-codes\">\\\\begin{itemize}\\n    \\\\item \\\\colorbox{uninstalled-day}{\\\\textcolor{black}{Red (day)}} / \\\\colorbox{uninstalled-night}{\\\\textcolor{white}\\n    {dark red (night)}} -- Uninstalled application\\n    \\\\item \\\\colorbox{disabled-day}{\\\\textcolor{black}{Light red (day)}} / \\\\colorbox{disabled-night}{\\\\textcolor{white}\\n    {very dark red (night)}} -- Frozen application\\n    \\\\item \\\\colorbox{force-stopped}{\\\\textcolor{white}{Dark cyan}} -- Force-stopped application\\n    \\\\item \\\\colorbox{AMYellow}{\\\\textcolor{black}{Yellow Star}} -- Debuggable application\\n\\n    \\\\item \\\\textcolor{AMOrange}{Orange \\\\textit{Date}} -- The application can read system logs\\n    \\\\item \\\\textcolor{AMOrange}{Orange \\\\textit{UID}} -- The user ID is being shared among multiple applications\\n    \\\\item \\\\textcolor{AMOrange}{Orange \\\\textit{SDK}} -- The application possibly uses cleartext (i.e.\\\\ HTTP) traffic\\n    \\\\item \\\\textcolor{tracker-day}{Light orange \\\\textit{package name}} -- The application has one or more trackers\\n    \\\\item \\\\textcolor{red}{Red \\\\textit{app label}} -- The application does not allow clearing its data\\n    \\\\item \\\\textcolor{AMDarkCyan}{Dark cyan \\\\textit{version}} -- Inactive application\\n    \\\\item \\\\textcolor{magenta}{Magenta type} -- Persistent application i.e.\\\\ it remains running all the time\\n\\n    \\\\item \\\\textcolor{red}{Red \\\\textit{backup}} -- The uninstalled application with one or more\\n    backups present in App Manager\\n    \\\\item \\\\textcolor{AMOrange}{Orange \\\\textit{backup}} -- Outdated backup, i.e.\\\\ the base backup\\n    contains an older version of the installed application\\n    \\\\item \\\\textcolor{AMDarkCyan}{Dark cyan \\\\textit{backup}} -- Up to date backup, i.e.\\\\ the base\\n    backup contains the same or higher version of the installed application.\\n\\\\end{itemize}</string>\n    <string name=\"pages$main-page$application-types\">An application can be either a \\\\textbf{User} or a \\\\textbf{System} application along with the following suffixes:\\n\\\\begin{itemize}\\n    \\\\item \\\\texttt{X} -- Supports multiple architectures\\n    \\\\item \\\\texttt{0} -- No dex files present in the application\\n    \\\\item \\\\texttt{°} -- Suspended application\\n    \\\\item \\\\texttt{\\\\#} -- The application requested the system to allocate a large heap i.e.\\\\ large runtime memory\\n    \\\\item \\\\texttt{\\?} -- The application requested the virtual machine to be in the safe mode.\\n\\\\end{itemize}</string>\n    <string name=\"pages$main-page$version-info\">Version name is followed by the prefixes below:\\n\\\\begin{itemize}\\n    \\\\item \\\\texttt{\\\\_} -- No hardware acceleration (breaking the in-app animations or transparencies)\\n    \\\\item \\\\texttt{\\\\textasciitilde} -- Test-only application\\n    \\\\item \\\\texttt{debug} -- Debuggable application\\n\\\\end{itemize}</string>\n    <string name=\"pages$main-page$options-menu\">Options menu offers several options that can be used to sort and filter the listed applications as well as to navigate\\nto different pages within or outside App Manager.</string>\n    <string name=\"pages$main-page$list-options\">\\\\textbf{List options} contain the options to sort and filter the list in the main page.</string>\n    <string name=\"pages$main-page$sort\">The applications listed in the main page can be sorted in the following ways:\\n\\\\begin{itemize}\\n    \\\\item \\\\textbf{User apps first.} The user applications are listed on top\\n    \\\\item \\\\textbf{App label.} Sort the list in ascending order based on their application labels (also known as\\n    \\\\textit{application names}). This is the default sorting preference\\n    \\\\item \\\\textbf{Package name.} Sort the list in ascending order based on their package names\\n    \\\\item \\\\textbf{Last update.} Sort the list in descending order based on the date they were last updated\\n    \\\\item \\\\textbf{Shared user ID.} Sort the list in descending order based on their kernel user ID\\n    \\\\item \\\\textbf{Target SDK.} Sort the list in ascending order based on their target SDK\\n    \\\\item \\\\textbf{Signature.} Sort the list in ascending order based on their signing information\\n    \\\\item \\\\textbf{Frozen first.} The frozen applications are listed on the top\\n    \\\\item \\\\textbf{Blocked first.} Sort the list in descending order based on the number of blocked components each\\n    application has\\n    \\\\item \\\\textbf{Backed up first.} Display the applications with backups on the top\\n    \\\\item \\\\textbf{Trackers.} Sort the list in descending order based on the number of tracker components each\\n    application has\\n    \\\\item \\\\textbf{Last actions.} Sort the list in descending order based on the latest time and date of any actions made\\n    to the applications within App Manager.\\n    \\\\item \\\\textbf{Installation date.} Sort the list by the date of installation in descending order.\\n    \\\\item \\\\textbf{Total size.} Sort the list by the total size of the applications and their data in descending order. Requires \\\\texttt{Usage Access} permission.\\n    \\\\item \\\\textbf{Data usage.} Sort the list by the total data usage in descending order. Requires \\\\texttt{Usage Access} permission.\\n    \\\\item \\\\textbf{Times opened.} List frequently used applications on top. Requires \\\\texttt{Usage Access} permission.\\n    \\\\item \\\\textbf{Screen time.} List the applications with the highest engagements on top. Requires \\\\texttt{Usage Access} permission.\\n    \\\\item \\\\textbf{Last used.} List last used apps on top. Requires \\\\texttt{Usage Access} permission.\\n\\\\end{itemize}\\n\\nIn addition, there is the \\\\textit{reverse} option that can be used to sort the list in the reverse order. Regardless of\\nthe sorting preferences, the applications are sorted alphabetically at first in order to prevent producing any random\\nsorting results.</string>\n    <string name=\"pages$main-page$filter\">The applications listed in the main page can be filtered in the following ways:\\n\\\\begin{itemize}\\n    \\\\item \\\\textbf{User apps.} List only the user applications\\n    \\\\item \\\\textbf{System apps.} List only the system applications\\n    \\\\item \\\\textbf{Frozen apps.} List only the frozen applications\\n    \\\\item \\\\textbf{Stopped apps.} List only the applications that were forced-stopped\\n    \\\\item \\\\textbf{Installed apps.} List only the installed applications\\n    \\\\item \\\\textbf{Uninstalled apps.} List only the uninstalled applications\\n    \\\\item \\\\textbf{With rules.} List the applications with one or more blocking rules\\n    \\\\item \\\\textbf{With activities.} List the applications with one or more activities\\n    \\\\item \\\\textbf{With backups.} List the applications with one or more backups\\n    \\\\item \\\\textbf{Without backups.} List the applications with no backups present.\\n    \\\\item \\\\textbf{Running apps.} List the applications that are currently running\\n    \\\\item \\\\textbf{With splits.} List the applications with one or more split APK files\\n    \\\\item \\\\textbf{With KeyStore.} List only the applications with Android KeyStore.\\n    \\\\item \\\\textbf{With SAF.} List only the applications with SAF access.\\n    \\\\item \\\\textbf{With SSAID.} List only the applications with a valid SSAID\\\\\\@.\\n\\\\end{itemize}\\n\\nUnlike sorting, it is possible to apply more than one filtering options at the same time. For example, the frozen user\\napplications can be listed by selecting both \\\\textit{User apps} and \\\\textit{Frozen apps}. This can be particularly\\nuseful for \\\\hyperref[subsec:batch-operations]{batch operations} where filtering the user applications may be necessary\\nto carry out certain operations safely.\\n\\n\\\\begin{warning}{Inconsistencies}\\n    App Manager extensively caches everything in this page. Therefore, certain states (e.g., freeze\\n    and stopped states) may not always be up-to-date.\\n\\\\end{warning}</string>\n    <string name=\"pages$main-page$profile_name\">It is also possible to list the applications that are only present in a \\\\hyperref[sec:profiles-page]{profile}. This can\\nbe useful for carrying out certain operations on a profile (e.g., uninstalling all the applications in a profile) that\\ncannot be done via the \\\\hyperref[sec:profiles-page]{Profiles page}.</string>\n    <string name=\"pages$main-page$instructions\">Clicking on the \\\\textbf{User manual} opens the offline version of the App Manager user manual. It may also open the\\nonline version if the corresponding feature split i.e.\\\\ \\\\texttt{feat\\\\_docs} is not installed, or if an WebView is not\\npresent in the system to load the manual.</string>\n    <string name=\"pages$main-page$1-click-ops\">\\\\textbf{1-Click Ops} stands for the single-click operations. It opens the \\\\hyperref[sec:1-click-ops-page]{corresponding\\npage} in a new activity.</string>\n    <string name=\"pages$main-page$app-usage\">Application usage statistics, such as \\\\textit{screen time}, \\\\textit{data usage} (both mobile and\\nWi-Fi), \\\\textit{number of times an app was opened}, can be accessed by clicking on the \\\\textbf{App\\nUsage} option in the menu. However, it requires the \\\\textit{Usage Access} permission. This menu item\\nwill not be listed if the usage access feature is disabled in \\\\hyperref[subsubsec:enable/disable-features]{settings}.</string>\n    <string name=\"pages$main-page$running-apps\">This menu item opens a new page where a list of running applications or processes are displayed. It also displays the\\ncurrent memory and cache (if available) usage. If root or ADB is not available to App Manager, it only displays itself\\nin the recent versions of Android. The running applications or processes can also be force-stopped or killed within the\\nresultant page. Logs for each process ID (PID) can also be viewed in the \\\\hyperref[subsubsec:main:labs]{log viewer}.\\nIn addition, it is also possible to carry out batch operations either by clicking on the icon or by long-clicking on an\\nitem. Normal click on any items opens a dialog where a more detailed information is displayed.</string>\n    <string name=\"pages$main-page$profiles\">This menu item opens the \\\\hyperref[sec:profiles-page]{profiles page}. Profiles are a way to configure regularly used\\ntasks. They can also be invoked via shortcuts.</string>\n    <string name=\"pages$main-page$apk-updater\">If the app \\\\href{https://github.com/rumboalla/apkupdater}{APK Updater} is installed in the system, it can be opened\\ndirectly via this menu item. The option remains hidden if the app is not present in the system.</string>\n    <string name=\"pages$main-page$termux\">If the app \\\\href{https://github.com/termux/termux-app}{Termux} is installed in the system, the running session (or a\\nnew session) can be opened directly via this menu item. The option remains hidden if the app is not present in the\\nsystem.</string>\n    <string name=\"pages$main-page$debloater\">This menu item opens the debloater page that lists all the bloatware available in the device and in\\nApp Manager. It also suggests alternative applications based on the criteria set by the \\\\href{https://github.com/MuntashirAkon/android-debloat-list}{Android Debloat List}\\nproject.</string>\n    <string name=\"pages$main-page$labs\">This menu item opens the labs page that lists all the additional features. They include Log Viewer,\\nSystem Config, Terminal, File Manager (as Files), UI Tracker, Interceptor, and Code Editor pages.</string>\n    <string name=\"pages$main-page$settings\">This menu item opens the in-app \\\\hyperref[sec:settings-page]{Settings page}.</string>\n    <string name=\"pages$app-details-page$$section-title\">App Details Page</string>\n    <string name=\"pages$app-details-page$$colour-codes-title\">Colour Codes</string>\n    <string name=\"pages$app-details-page$$app-info-tab-title\">App Info Tab</string>\n    <string name=\"pages$app-details-page$$app-info-general-information-title\">General Information</string>\n    <string name=\"pages$app-details-page$$tags-title\">Tags</string>\n    <string name=\"pages$app-details-page$$horizontal-action-panel-title\">Horizontal Action Panel</string>\n    <string name=\"pages$app-details-page$$app-info-options-menu-title\">Options Menu</string>\n    <string name=\"pages$app-details-page$$config-termux-title\">Configuring Termux</string>\n    <string name=\"pages$app-details-page$$component-tabs-title\">Component Tabs</string>\n    <string name=\"pages$app-details-page$$activities-title\">Activities</string>\n    <string name=\"pages$app-details-page$$servcies-title\">Services</string>\n    <string name=\"pages$app-details-page$$receivers-title\">Receivers</string>\n    <string name=\"pages$app-details-page$$providers-title\">Providers</string>\n    <string name=\"pages$app-details-page$$additional-features-for-rooted-phones-title\">Additional Features for Rooted Phones</string>\n    <string name=\"pages$app-details-page$$blocking-components-title\">Blocking Components.</string>\n    <string name=\"pages$app-details-page$$blocking-trackers-title\">Blocking Trackers.</string>\n    <string name=\"pages$app-details-page$$permission-tabs-title\">Permission Tabs</string>\n    <string name=\"pages$app-details-page$$app-ops-title\">App Ops</string>\n    <string name=\"pages$app-details-page$$uses-permissions-title\">Uses Permissions</string>\n    <string name=\"pages$app-details-page$$permissions-title\">Permissions</string>\n    <string name=\"pages$app-details-page$$signatures-tab-title\">Signatures Tab</string>\n    <string name=\"pages$app-details-page$$uses-features-tab-title\">Uses Features tab</string>\n    <string name=\"pages$app-details-page$$configurations-tab-title\">Configurations tab</string>\n    <string name=\"pages$app-details-page$$shared-libs-tab-title\">Shared Libraries Tab</string>\n    <string name=\"pages$app-details-page$intro\">\\\\textbf{App Details} page consists of 11 (eleven) tabs. It describes almost every bit of information\\nan application usually has, including all attributes from its manifest,\\n\\\\hyperref[ch:app-ops]{application operations} (app ops), signing information, libraries, and so on.</string>\n    <string name=\"pages$app-details-page$colour-codes\">List of colours used in this page, and their meaning:\\n\\\\begin{itemize}\\n    \\\\item \\\\colorbox{uninstalled-day}{\\\\textcolor{black}{Red (day)}} / \\\\colorbox{uninstalled-night}{\\\\textcolor{white}{dark red (night)}}\\n    -- Denotes any app ops or permissions having the dangerous flag, or any components blocked\\n    within App Manager, or any unsupported but required features.\\n\\n    \\\\item \\\\colorbox{disabled-day}{\\\\textcolor{black}{Light red (day)}} / \\\\colorbox{disabled-night}{\\\\textcolor{white}{very\\n    dark red (night)}} -- Denotes the components disabled outside of App Manager, or any unsupported\\n    but optional features.\\n\\n    \\\\begin{tip}{Note}\\n        A component marked as disabled does not always mean that it is disabled by the user: It could also be disabled\\n        by the system or marked as disabled in its manifest. The components of a disabled application are also\\n        considered disabled by the system (and App Manager).\\n    \\\\end{tip}\\n\\n    \\\\item \\\\colorbox{tracker-day}{\\\\textcolor{black}{Vivid orange (day)}} / \\\\colorbox{tracker-night}{\\n        \\\\textcolor{white}{very dark orange (night)}} -- Denotes the tracker components\\n\\n    \\\\item \\\\colorbox{AMSoftMagenta}{\\\\textcolor{black}{Soft magenta (day)}} / \\\\colorbox{AMVeryDarkViolet}{\\n        \\\\textcolor{white}{very dark violet (night)}} -- Denotes the running services.\\n\\n    \\\\item \\\\colorbox{AMGreen}{\\\\textcolor{white}{Green}}  -- Used in the tracker-indicator tag\\n    to denote that all the trackers in the application are blocked.\\n\\\\end{itemize}</string>\n    <string name=\"pages$app-details-page$app-info-tab\">\\\\textbf{App Info} tab contains general information about an application. It also lists many actions that can be\\nperformed within this tab.</string>\n    <string name=\"pages$app-details-page$app-info-general-information\">The list below is in the same order as listed in the App Info tab.\\n\\\\begin{itemize}\\n    \\\\item \\\\textbf{Application Icon.} The application icon. If the application does not have an icon, the system default\\n    icon will be displayed. It is also possible to verify the APK signature via SHA or MD5 sums stored in the clipboard\\n    by simply clicking on it.\\n\\n    \\\\item \\\\textbf{Application Label.} The application label or the name of the application.\\n\\n    \\\\item \\\\textbf{Package Name.} The name of the application package. Clicking on the name stores it in the clipboard.\\n\\n    \\\\item \\\\textbf{Version.} The application version is divided into two parts. The first part is called \\\\textit{version\\n    name}. The format of this part varies but often consists of multiple integers separated by dots. The second part\\n    is called \\\\textit{version code}. It is enclosed by the first brackets. The version code is an integer used to\\n    differentiate between application versions (since a version name can be unreadable to a machine). In general,\\n    a new version of an application has higher version code than the old ones. For example, if \\\\texttt{123} and\\n    \\\\texttt{125} are two version codes of an application, we can say that the latter is more updated than the former\\n    because the version code of the latter is higher. An application that serves different APK files for the same version\\n    on different platforms (mobile, tabs, desktops, etc.) or architectures (32/64 bit, ARM or Intel), the version\\n    numbers can be misleading as they often add prefixes for each platform.\\n\\n    \\\\item \\\\textbf{Tags.} (Also known as tag clouds) Tags include the most basic, concise and useful information of an\\n    application. See \\\\Sref{subsubsec:tags} for a complete list of tags shown here.\\n\\n    \\\\item \\\\textbf{Horizontal Action Panel.} An action panel consisting of various actions that can be carried out for\\n    the application. See \\\\Sref{subsubsec:horizontal-action-panel} for a complete list of actions available here.\\n    Additional actions are available in the \\\\hyperref[subsubsec:app-info-options-menu]{options menu}.\\n\\n    \\\\item \\\\textbf{Paths \\\\&amp; Directories.} Contains various information regarding application paths\\n    including \\\\textit{app directory} (where the APK files reside), \\\\textit{data directories}\\n    (internal, device protected and externals), and \\\\textit{JNI library directory} (if present).\\n    JNI libraries are used to invoke native codes usually written in C/C++. Use of native library\\n    can make the application run faster or help an application use third-party libraries written\\n    using languages other than Java like in most games. The directories can be opened via file\\n    managers provided they support it and have the necessary permissions, by clicking on the launch\\n    button on the right-hand side of a directory item.\\n\\n    \\\\item \\\\textbf{Data Usage.} Amount of data used by the application as reported by the operating system. Depending on\\n    Android version, this may require a wide range of permissions including \\\\textit{Usage Access} and \\\\textit{Telephony}\\n    permissions.\\n\\n    \\\\item \\\\textbf{Storage \\\\&amp; Cache.} Displays information regarding the size of the application (APK files, optimised\\n    files), data and cache. In older devices, size of external data, cache, media and OBB folders are also displayed.\\n    This part remains hidden if \\\\textit{Usage Access} permission is not granted in the newer devices.\\n\\n    \\\\item \\\\textbf{More Info.} Displays other information such as--\\n    \\\\begin{itemize}\\n        \\\\item \\\\textbf{SDK.} Displays information related to the Android SDK: \\\\textit{Max} denotes\\n        the target SDK and \\\\textit{Min} denotes the minimum SDK (the latter is not available in\\n        Android Lollipop). If the target SDK value is less than the platform SDK (i.e., the highest\\n        SDK the current operating system supports), the application will run in the compatibility\\n        mode. This means the application may have access to certain features that are unavailable or\\n        restricted in a newer version of Android, which can be a security and/or privacy issue. SDK\\n        is also known as \\\\textbf{API Level}.\\\\\\\\\\n        \\\\seealsoinline{\\\\href{https://en.wikipedia.org/wiki/Android_version_history\\\\#Overview}{Android Version History}}\\n\\n        \\\\item \\\\textbf{Flags.} The application flags used at the time of building the application. For a complete list of\\n        flags and what they do, read the\\n        \\\\href{https://developer.android.com/reference/android/content/pm/ApplicationInfo\\\\#flags}{official documentation}.\\n\\n        \\\\item \\\\textbf{Date Installed.} The date when the application was first installed.\\n\\n        \\\\item \\\\textbf{Date Updated.} The date when the application was last updated. This is the same as \\\\textit{Date Installed}\\n        if the application hasn\\'t been updated.\\n\\n        \\\\item \\\\textbf{Process Name.} The name of the process if it is different from the package\\n        name. Process name is set when an application is being started by the system, and is usually\\n        the same as the package name.\\n\\n        \\\\item \\\\textbf{Installer App.} The application that installed this application. The installer\\n        application may not always be the same as the application that installed this application,\\n        because Android allows setting an arbitrary value for this field. In Android 11 onwards, the\\n        actual installer application is also stored by the system which can be accessed by clicking\\n        the ``Info\\'\\' button on the right-hand side of the item. The field will not be visible if the\\n        installer application is not reported by the system (e.g., due to the installer application\\n        being uninstalled or hidden). Installer application may be granted additional privileges by\\n        the system so that it can control certain behaviour of the application it installs.\\n\\n        \\\\item \\\\textbf{User ID.} The unique user ID set by the system to the application. For shared\\n        applications, the same user ID is assigned to multiple applications having the same\\n        \\\\textit{Shared User ID}.\\n\\n        \\\\item \\\\textbf{Shared User ID.} Applicable for applications that are shared together. The shared application must\\n        have the same \\\\hyperref[subsec:signatures-tab]{signatures}.\\n\\n        \\\\item \\\\textbf{Primary ABI.} Architecture supported by this platform for this application.\\n\\n        \\\\item \\\\textbf{Zygote preload name.} Responsible for preloading application code and data shared across all the\\n        isolated services that uses app zygote.\\n\\n        \\\\item \\\\textbf{Hidden API enforcement policy.} Since Android 9, many methods and classes in Android framework\\n        have been made inaccessible to the third-party applications through hidden API enforcement policy. It has the\\n        following options:\\n        \\\\begin{itemize}\\n            \\\\item \\\\textit{Default.} Based on the type of application. For system applications, it should be disabled,\\n            and for others, it should be enforced.\\n            \\\\item \\\\textit{None/disabled.} The application has full access to the hidden API as it used to be before\\n            Android 9.\\n            \\\\item \\\\textit{Warn.} Same as above, except that warnings will be logged each time the application accesses\\n            the hidden API. This is mostly unused.\\n            \\\\item \\\\textit{Enforce.} The application cannot access hidden API, either dark-grey list or blacklist, or\\n            both of them. This is the default option for the third-party applications in Android 9 onwards unless the\\n            application is whitelisted by the OEM or the vendor.\\n            \\\\begin{warning}{Warning}\\n                Hidden API enforcement policy is not properly implemented in Android and can be bypassed by the\\n                application. As a result, this value should not be trusted.\\n            \\\\end{warning}\\n        \\\\end{itemize}\\n\\n        \\\\item \\\\textbf{SELinux.} Mandatory access control (MAC) policy set by the operating system via SELinux.\\n\\n        \\\\item \\\\textbf{Main Activity.} The main entry point to the application. This is only visible if the application has\\n        \\\\hyperref[subsubsec:activities]{activities} and any of those are openable from the Launcher. There\\'s also a\\n        launch button on the right-hand side which can be used to launch this activity.\\n    \\\\end{itemize}\\n\\\\end{itemize}</string>\n    <string name=\"pages$app-details-page$tags-list\">\\\\begin{itemize}\\n    \\\\item \\\\textbf{Tracker info.} Number of tracker components in the application (e.g., \\\\textit{5 trackers}) The colour\\n    of the tag appears orange if the trackers are unblocked and dark cyan if they are blocked in App Manager.\\n    Clicking on the tag opens a dialog containing the list of tracker components which can also be blocked or unblocked\\n    provided App Manager has sufficient privileges.\\n\\n    \\\\item \\\\textbf{Application type.} User application or system application. For a system\\n    application, it displays whether the application is an updated version of the system application\\n    or the application is installed systemless-ly via Magisk.\\n\\n    \\\\item \\\\textbf{Split APK info.} Number of splits in the APK excluding the base APK (e.g., \\\\textit{5 splits}).\\n    Clicking on the tag opens a dialog containing a few additional information, such as name, type, and size.\\n\\n    \\\\item \\\\textbf{Debuggable.} The application can be debugged over ADB\\\\\\@. Debuggable applications can enjoy certain\\n    functions unavailable to a regular application. The data of the application might be accessible via ADB (e.g.\\\\ using\\n    \\\\texttt{run-as} command) without any additional permissions.\\n\\n    \\\\item \\\\textbf{Test only.} The application is a test-only application. Test-only applications can enjoy certain\\n    functions unavailable to a regular application. The data of the application might be accessible via ADB (e.g.\\\\ using\\n    \\\\texttt{run-as} command) without any additional permissions.\\n\\n    \\\\item \\\\textbf{No code.} The application does not have any code associated with it i.e., DEX files aren\\'t present.\\n    In some system applications, the actual code might be located in another place.\\n\\n    \\\\item \\\\textbf{Large heap.} The application has requested large heap size i.e., more space in memory (RAM) is\\n    requested for dynamic allocation. It is still up to the operating system to decide whether to allocate large space\\n    for the application. App Manager, for example, requests large heap size because it needs to load an entire APK\\n    into memory while scanning an APK\\\\\\@.\\n\\n    \\\\item \\\\textbf{Open links.} The application may open certain links from any applications. If the\\n    application can open any links by default, the color of the tag would be red, dark cyan if\\n    otherwise. Clicking on the tag opens a dialog with the supported hosts or domains listed. In\\n    Android 12 onwards, it displays an option to enable or disable opening links by default provided\\n    App Manager has sufficient permissions. Otherwise, it displays an option to open the system\\n    settings page for the application.\\n\\n    \\\\item \\\\textbf{Running.} One or more services of the application is currently running in the\\n    background. Clicking on the tag opens a dialog containing the list of running services. Clicking\\n    on any services opens the log viewer with default filter set to the UID associated with the\\n    service (which can be different from the UID of the application if it is running in a separate\\n    or isolated process) provided the log viewer feature is enabled. There\\'s also an option to\\n    force-stop the application.\\n\\n    \\\\item \\\\textbf{Stopped.} The application is force stopped. This may not prevent it from running automatically later.\\n\\n    \\\\item \\\\textbf{Disabled.} Denotes that the application is disabled (hidden from the launcher).\\n\\n    \\\\item \\\\textbf{Suspended.} Denotes that the application is suspended (grayed out in the launcher).\\n\\n    \\\\item \\\\textbf{Hidden.} Denotes that the application is hidden (hidden from the launcher).\\n\\n    \\\\item \\\\textbf{MagiskHide.} MagiskHide is enabled for the application. Clicking on the tag opens\\n    a dialog containing the list of process names within the application that can be added to or\\n    removed from the MagiskHide list.\\n\\n    \\\\item \\\\textbf{MagiskDenyList.} The application is present in Magisk DenyList. Clicking on the\\n    tag opens a dialog containing the list of process names within the application that can be added\\n    to or removed from Magisk DenyList.\\n\\n    \\\\item \\\\textbf{WX.} The application violates the ``W\\\\textasciicircum{}X policy\\'\\' and is capable\\n    of writing and executing in the same directory or in the same portion of memory. This allows the\\n    execution of arbitrary executables either by the modification of executables embedded within the\\n    application or by downloading them from the Internet.\\\\\\\\\\n    \\\\seealsoinline{\\\\href{https://en.wikipedia.org/wiki/W\\\\%5EX}{W\\\\textasciicircum{}X in Wikipedia}}\\n\\n    \\\\item \\\\textbf{Bloatware.} The application may be a known bloatware. Clicking on the tag opens a\\n    dialog containing detailed information in addition to suggestions (if available).\\n\\n    \\\\item \\\\textbf{KeyStore.} The application has items in the Android KeyStore. Clicking on the tag opens a dialog\\n    containing all the KeyStore files that belong to the application.\\n\\n    \\\\item \\\\textbf{Backup.} The application was backed up using App Manager at least once. Clicking on the tag\\n    opens a dialog containing all the available backups along with metadata.\\n\\n    \\\\item \\\\textbf{No battery optimisation.} Battery optimisation is disabled for the application. It is possible to\\n    re-enable battery optimisation by clicking on the tag.\\n\\n    \\\\item \\\\textbf{Sensors disabled.} Sensors are disabled for the application. Sensors are disabled\\n    for most applications by default.\\n\\n    \\\\item \\\\hyperref[sec:net-policy]{\\\\textbf{Net policy.}} Network policy (e.g., background data usage) is configured\\n    for the application. Clicking on the tag displays a dialog containing the supported policies for the platform\\n    along with the options to configure them.\\n\\n    \\\\item \\\\hyperref[sec:terminologies]{\\\\textbf{SSAID.}} Clicking on the tag opens a dialog containing the current\\n    SSAID assigned to the application. It is also possible to reset/regenerate the SSAID if needed.\\n\\n    \\\\item \\\\textbf{SAF.} Denotes that the application has been granted to access one or more storage locations or\\n    files i.e.\\\\ URIs via Storage Access Framework (SAF). Clicking on the tag opens a dialog containing the list of\\n    granted URIs.\\n\\n    \\\\item \\\\textbf{Play App Signing.} Indicates that the application might be signed by Google.\\n\\n    \\\\item \\\\textbf{Xposed.} Indicates that the application may be an Xposed module. Clicking on the\\n    tag displays a dialog with additional information.\\n\\n    \\\\item \\\\textbf{Static Shared Library.} Denotes that the application serves as a static shared\\n    library for one or more applications. Clicking on the tag opens a dialog containing a list of\\n    installed versions of the library along with an option to uninstall them.\\n    \\\\begin{tip}{Notice}\\n        The trichrome library (supplied by Google Chrome, Vanadium or similar projects) is currently\\n        the only known static shared library on Android.\\n    \\\\end{tip}\\n\\\\end{itemize}</string>\n    <string name=\"pages$app-details-page$horizontal-action-panel\">Horizontal Action Panel, as described in the previous section, consists of various application-related actions, such as--\\n\\\\begin{itemize}\\n    \\\\item \\\\textbf{Launch.} Launch the application provided it has a launcher \\\\hyperref[subsubsec:activities]{activity}.\\n\\n    \\\\item \\\\textbf{Freeze.} Freeze the application. This button is not displayed if it is already frozen or the user\\n    does not have enough privileges. After the application is frozen, it may be hidden from the app drawer depending on\\n    how it was configured. Shortcuts configured by the application may also be removed. The application may only be\\n    unfrozen via App Manager, \\\\texttt{pm} command or any other tools that offer such a feature. Long clicking on the\\n    button opens a dialog where a shortcut can be configured to quickly freeze or unfreeze the application.\\n\\n    \\\\item \\\\textbf{Uninstall.} Uninstall the application with a prompt. In the dialog prompt, it is possible to uninstall\\n    updates of a system application, or if App Manager has enough privileges or the operating system supports it, it is\\n    possible to uninstall the application without clearing its data and signature. For the latter case, the installed\\n    application must match the signature with the previously installed application if it is installed again.\\n    \\\\begin{tip}{Tips}\\n        A better way to reinstall an application with a different signature would be to back up its data using App\\n        Manager and restore it again after installing the application instead of opting to preserving data and signature\\n        of the application during uninstallation as this option may cause undefined behaviour in the future.\\n    \\\\end{tip}\\n\\n    \\\\item \\\\textbf{Unfreeze.} Unfreeze the application. This button is not displayed if it is already enabled or the user\\n    does not have enough privileges. Similar to the \\\\textit{Freeze} button, long clicking on the button opens a dialog\\n    where a shortcut can be configured to quickly freeze or unfreeze the application.\\n\\n    \\\\item \\\\textbf{Force Stop.} Force-stop the application.\\n\\n    \\\\item \\\\textbf{Clear Data.} Clear data from the application. This includes any information stored in the internal\\n    and, recently, the external directories, including accounts (if set by the application), cache, etc. Clearing data\\n    from App Manager, for example, removes all the rules (the blocking is not removed though) saved within the\\n    application (Which is why you should always take backups of your rules). This button is not displayed if the user\\n    does not have enough privileges.\\n\\n    \\\\item \\\\textbf{Clear Cache.} Clear the application cache. If the application is running during the operation, the\\n    cache may not be cleared as expected.\\n\\n    \\\\item \\\\textbf{Install.} Install the application, only displayed if the application hasn\\'t\\n    already been installed.\\n\\n    \\\\item \\\\textbf{What\\'s New.} Displayed for an external application if an older version of it is\\n    already installed. Clicking on this button opens a dialog containing the differences between\\n    this and the installed version in a version control manner. Changes include \\\\textit{version},\\n    \\\\textit{trackers}, \\\\textit{permissions}, \\\\textit{components}, \\\\textit{signatures} (only checksum\\n    changes), \\\\textit{features}, \\\\textit{shared libraries} and \\\\textit{SDK}.\\n\\n    \\\\item \\\\textbf{Update.} Displayed if the application has a higher version code than the installed application.\\n\\n    \\\\item \\\\textbf{Reinstall.} Displayed if the application has the same version code as the installed application.\\n\\n    \\\\item \\\\textbf{Downgrade.} Displayed if the application has a lower version code than the installed application.\\n\\n    \\\\item \\\\textbf{Manifest.} Opens the application\\'s manifest file in a separate page. If the\\n    application has more than one split, it will display the list of split APK files, and clicking\\n    on an item will open the corresponding manifest file instead.\\n\\n    \\\\item \\\\textbf{Scanner.} Scan the application in order to list potential trackers and libraries.\\n    It also scans the file using VirusTotal and fetch results from Pithus if configured.\\\\\\\\\\n    \\\\seealsoinline{\\\\hyperref[sec:scanner-page]{Scanner page}}\\n\\n    \\\\item \\\\textbf{Shared Prefs.} Displays a list of shared preferences used by the application.\\n    Clicking on a preference item in the list opens the \\\\hyperref[sec:shared-preferences-editor-page]{Shared Preferences\\n    Editor page}. This option is only visible if the user has the required privileges.\\n\\n    \\\\item \\\\textbf{Databases.} Displays a list of databases used by the application. Clicking on an\\n    item opens a list of activities that can open the database. This option is only visible if the\\n    user has the required privileges.\\n\\n    \\\\item \\\\textbf{F-Droid.} Open the application in the selected \\\\textit{F-Droid} client.\\n\\n    \\\\item \\\\textbf{Store.} Open the application in \\\\textit{Aurora Store}. The option is only visible if \\\\textit{Aurora\\n    Store} is installed.\\n\\\\end{itemize}</string>\n    <string name=\"pages$app-details-page$app-info-options-menu\">Options-menu is located in the top-right corner of the page. A complete description of the options present there are\\ngiven below:\\n\\\\begin{itemize}\\n    \\\\item \\\\textbf{Share.} Share button can be used to share the APK or (if the application is has multiple splits, OBB\\n    files or any dependencies) \\\\textit{APKS} file extracted from the application.\\n\\n    \\\\item \\\\textbf{Refresh.} Refresh the App Info tab.\\n\\n    \\\\item \\\\textbf{View in Settings.} Open the application in Android Settings.\\n\\n    \\\\item \\\\textbf{Backup/restore.} Open the backup/restore dialog.\\n\\n    \\\\item \\\\textbf{Export blocking rules.} Export rules configured for the application within App Manager.\\n\\n    \\\\item \\\\textbf{Open in Termux.} Open the application in Termux. This actually runs \\\\texttt{su - user\\\\_id} where\\n    \\\\texttt{user\\\\_id} denotes the application\\'s kernel user ID (described in \\\\Sref{subsubsec:app-info-general-information}).\\n    This option is only visible to the root users. See \\\\Sref{subsubsec:config-termux} to learn how to configure Termux\\n    to run commands from third-party applications.\\n\\n    \\\\item \\\\textbf{Run in Termux.} Open the application via \\\\texttt{run-as package\\\\_name} in Termux. This is only\\n    applicable to the debuggable applications and works for both root and ADB users. See \\\\Sref{subsubsec:config-termux}\\n    to learn how to configure Termux to run commands from third-party applications.\\n\\n    \\\\item \\\\textbf{MagiskHide.} Open a dialog containing the list of process names within the application that can be added\\n    or removed from the MagiskHide list.\\n\\n    \\\\item \\\\textbf{Magisk DenyList.} Open a dialog containing the list of process namees within the application that can be\\n    added or removed from Magisk DenyList.\\n\\n    \\\\item \\\\textbf{Battery optimisation.} Enable/disable battery optimisation for this application.\\n\\n    \\\\item \\\\textbf{Sensors.} Enable/disable sensors for this application.\\n\\n    \\\\item \\\\hyperref[sec:net-policy]{\\\\textbf{Net policy.}} Configure network policy (e.g., background data usage) for the\\n    application.\\n\\n    \\\\item \\\\textbf{Extract Icon.} Extract and save the application\\'s icon in the shared storage.\\n\\n    \\\\item \\\\textbf{Optimize.} Perform optimisation for this application. This option is for advanced\\n    users only.\\n\\n    \\\\item \\\\textbf{Add to profile.} Add the application to one of the configured \\\\hyperref[sec:profile-page]{profiles}.\\n\\n    \\\\item \\\\textbf{Install for….} Install the application for another user and/or in the work profile if configured.\\n\\\\end{itemize}</string>\n    <string name=\"pages$app-details-page$config-termux\">By default, Termux does not allow running commands from a third-party application. To use this option, Termux v0.96 or\\nlater is required and \\\\texttt{allow-external-apps=true} must be added in \\\\texttt{\\\\textasciitilde/.termux/termux.properties}.\\n\\n\\\\begin{tip}{Info}\\n    Enabling this option does not weaken Termux\\' security. The third-party applications still need to ask the user to\\n    allow running arbitrary commands in Termux.\\n\\\\end{tip}</string>\n    <string name=\"pages$app-details-page$component-tabs\">\\\\textbf{Activities}, \\\\textbf{Services}, \\\\textbf{Receivers} (i.e., broadcast receivers) and\\n\\\\textbf{Providers} (e.g., content providers) are collectively known as the application components,\\nbecause they offer similar features and share similar properties. For example, they all have a\\n\\\\textit{name}, a \\\\textit{label}, an \\\\textit{icon}, can be enabled or disabled, and can be executed\\nvia \\\\textit{Intent}. Application components are the building blocks of an application and must be\\ndeclared in the application manifest (with a few exceptions). Application manifest is a file where\\napplication specific metadata are stored. The Android operating system learns what to do with the\\napplication by reading the metadata.\\n\\nColours used in these tabs are explained in \\\\Sref{subsec:app-details-colour-codes}. It is also\\npossible to sort the list of components to display blocked or tracker components on top of the list\\nvia the \\\\textbf{Sort} option located in the three-dots menu.</string>\n    <string name=\"pages$app-details-page$activities\">\\\\textbf{Activities} are the windows or pages that can be uniquely identified by the Android operating system (e.g.,\\n\\\\textit{Main page} and \\\\textit{App Details page} are two activities). Each activity can have multiple UI components\\nknown as \\\\textit{widgets} or \\\\textit{fragments}, and each component can be nested or placed on top of each other. The\\ndeveloper can also choose to open external files, links, etc. within an activity using a method called\\n\\\\textit{intent filters}. For example, when you open a file in your file manager, either your file manager or the\\noperating system scans the intent filters via PackageManager, find the activities capable of opening the file, and\\nlist those activities so that you can choose your preferred activity.\\n\\nActivities that are \\\\textit{exportable} can be opened by any third-party applications. However, Some\\nactivities may require permissions, and only an application having those permissions can open them.\\nIn the \\\\textit{Activities} tab, certain activities can be launched via the \\\\textbf{Launch} button.\\nIf it is necessary to supply additional information, such as Intent extras, data or action, long\\nclicking on the \\\\textbf{Launch} button opens the \\\\hyperref[sec:interceptor-page]{Activity Interceptor}\\npage which provides such features.\\n\\n\\\\begin{tip}{Tip}\\n    No-root users can grant \\\\texttt{android.permission.WRITE\\\\_SECURE\\\\_SETTINGS} via ADB to launch\\n    \\\\textit{non-exportable} activities.\\n\\\\end{tip}\\n\\n\\\\begin{tip}{Notice}\\n    If launching an activity throws an error, it may have certain dependencies which are not met\\n    (e.g., \\\\textit{App Details} page in App Manager cannot be launched using the launch button,\\n    because it requires a package name). Since the dependencies cannot be inferred programmatically,\\n    the activity may not be opened from App Manager by default.\\n\\\\end{tip}\\n\\nIt is also possible to create shortcuts of an activity-launch using the \\\\textbf{Create shortcut}\\nbutton. If you need to supply additional information, you can create a shortcut from the Activity\\nInterceptor page instead.\\n\\n\\\\begin{danger}{Caution}\\n    If you uninstall App Manager, all shortcuts created by App Manager will be lost.\\n\\\\end{danger}</string>\n    <string name=\"pages$app-details-page$servcies\">Unlike \\\\hyperref[subsubsec:activities]{activities} that users can see, \\\\textbf{Services} handle background tasks. For example,\\nif you\\'re downloading a video from the internet using your phone\\'s Internet browser, the Internet browser is using a\\n\\\\textit{foreground service} to download the content.\\n\\nWhen an activity is closed or removed from the \\\\textit{Recents} page, it may be destroyed\\nimmediately depending on the amount free memory the phone has, battery statistics, or how the\\nactivity is configured. But services can be run indefinitely if desired. If more services run in the\\nbackground, the phone may become slower due to the shortage of memory and/or processing power, and\\nthe phone\\'s battery will be drained more quickly. Newer versions of Android come with a battery\\noptimisation feature enabled by default for all applications. With this feature enabled, the system\\ncan randomly terminate any service depending on the amount of resources the system has or the\\nservice requires. However, foreground services (i.e., services that run with a fixed notification,\\nsuch as music player or downloader) are not typically terminated unless the system is very low on\\nresources (memory, battery, etc.). Certain stock ROMs can offer more aggressive optimisation. MIUI,\\nfor example, has a very aggressive optimisation feature known as the \\\\textit{MIUI optimisation}.\\n\\nBoth activities and services are run in the same \\\\href{https://stackoverflow.com/questions/7597742}{looper} called\\nthe main looper, which means the services do not really run in the background. It is the task of the developer to\\nensure this. How do the application communicate with the services\\? It uses\\n\\\\hyperref[subsubsec:app-details-receivers]{broadcast receiver} or Binder.</string>\n    <string name=\"pages$app-details-page$receivers\">\\\\textbf{Receivers} (also called \\\\textit{broadcast receivers}) can be used to trigger execution of certain tasks when\\ncertain events occur. These components are called broadcast receivers, because they are executed as soon as a broadcast\\nmessage is received. These broadcast messages are sent using a method called \\\\textit{Intent}. Intent is a special\\nfeature in Android that can be used to open applications (i.e., activities), run services and send broadcast messages.\\nTherefore, like \\\\hyperref[subsubsec:activities]{activities}, broadcast receivers use \\\\textit{intent filters} to receive\\nthe desired broadcast messages. Broadcast messages can be sent by the system or the application itself. When a broadcast\\nmessage is sent, the corresponding receivers are activated by the system so that they can execute tasks. For example, if\\nyour phone is low on resources, it may freeze or experience lags for a moment after you enable mobile data or connect it\\nto the Wi-Fi. This is because broadcast receivers that can receive \\\\texttt{android.net.conn.CONNECTIVITY\\\\_CHANGE} are\\nactivated by the system as soon as the data connection is enabled. Since many applications typically use this intent\\nfilter, they are all activated almost immediately by the system which causes the freezing or lags.\\n\\nReceivers can also be used for inter-process communication (IPC), i.e., it can be used to communicate across multiple\\napplications or even different components of a single application.</string>\n    <string name=\"pages$app-details-page$providers\">\\\\textbf{Providers} are primarily used for data management. For example, when you save an APK file or\\nexport rules in App Manager, it uses a content provider called \\\\texttt{.fm.FmProvider} to save the\\nAPK or export the rules. There are many providers, including the ones provided by the system, that\\ncan be used to manage various content-related tasks, such as database management, tracking,\\nsearching, etc. Each provider has a field called \\\\textit{Authority} which is unique to the\\napplication in the entire Android ecosystem just as the package name.</string>\n    <string name=\"pages$app-details-page$additional-features-for-rooted-phones\">Unlike the no-root users who are mostly spectators in these tabs, root users can perform various operations.</string>\n    <string name=\"pages$app-details-page$blocking-components\">On the right-most side of each component item, there is a switch which can be used to toggle the blocking status of that\\nparticular component. If \\\\hyperref[subsubsec:instant-component-blocking]{Instant Component Blocking} is not enabled or\\nblocking is never applied to the application before, it is required to apply the changes using the \\\\textbf{Apply rules}\\noption in three-dots menu. It is also possible to remove the already-applied rules using the same option (which would be\\nread as \\\\textbf{Remove rules} this time).\\n\\nIt is also possible to block the component using one of the several methods by long clicking on the button.\\n\\n\\\\seealsoinline{\\\\hyperref[sec:faq:app-components]{FAQ: App Components}}</string>\n    <string name=\"pages$app-details-page$blocking-trackers\">It is possible to disable tracker components using the \\\\textbf{Block tracker} option in the three-dots menu. All tracker\\ncomponents will be blocked regardless of the tab you\\'re currently in.\\n\\n\\\\begin{tip}{Info}\\n    Tracker components are a subset of application components. Therefore, they are blocked using the same method used\\n    for blocking any other components.\\n\\\\end{tip}\\n\\n\\\\begin{amseealso}\\n    \\\\item \\\\hyperref[subsec:tracker-classes-versus-tracker-components]{FAQ: Tracker classes versus tracker components}\\n    \\\\item \\\\hyperref[sec:scanner-page]{Scanner Page}\\n    \\\\item \\\\hyperref[subsec:block-unblock-trackers]{1-Click Ops Page: Block/Unblock Trackers}\\n\\\\end{amseealso}</string>\n    <string name=\"pages$app-details-page$permission-tabs\">\\\\textbf{App Ops}, \\\\textbf{Uses Permissions} and \\\\textbf{Permissions} tabs are related to permissions. In Android\\ncommunication across applications or processes not having the same identity (known as \\\\textit{shared ID}) often\\nrequire permissions. These permissions are managed by the permission controller. Some permissions are considered\\n\\\\textit{normal} permissions which are granted automatically if they appear in the application manifest, but\\n\\\\textit{dangerous} and \\\\textit{development} permissions require confirmation from the user. Colours used in these tabs\\nare explained in \\\\Sref{subsec:app-details-colour-codes}.</string>\n    <string name=\"pages$app-details-page$app-ops\">\\\\textbf{App Ops} stands for \\\\textbf{Application Operations}. Since Android 4.3, \\\\textit{App Ops} are used by Android to\\ncontrol many system permissions. Each app op has a unique number associated with it which is displayed along with the\\nprivate name of the operation in the App Ops tab. Some app ops also have a public name. A large number of app ops are\\nalso associated with \\\\textit{permissions}. In this tab, an app op is considered dangerous if its associated permission\\nis marked as dangerous. Other information such as \\\\textit{flags}, \\\\textit{permission name}, \\\\textit{permission description},\\n\\\\textit{package name}, \\\\textit{group} are also taken from the associated \\\\hyperref[subsubsec:permissions]{permission}.\\nOthers may include the following:\\n\\\\begin{itemize}\\n    \\\\item \\\\textbf{Mode.} It describes the current authorisation status which can be \\\\textit{allow}, \\\\textit{deny} (a\\n    rather misnomer, it simply means error), \\\\textit{ignore} (it actually means deny), \\\\textit{default} (inferred from\\n    a list of defaults set internally by the vendor or the AOSP), \\\\textit{foreground} (in newer Android versions, it\\n    means the app op can only be used when the application is running in foreground), and some custom modes set by the\\n    vendors (MIUI uses \\\\textit{ask}, for example).\\n\\n    \\\\item \\\\textbf{Duration.} The amount of time this app op has been used (there can be negative durations whose\\n    use cases are currently unknown to me).\\n\\n    \\\\item \\\\textbf{Accept Time.} Last time the app op was accepted.\\n\\n    \\\\item \\\\textbf{Reject Time.} Last time the app op was rejected.\\n\\\\end{itemize}\\n\\n\\\\begin{tip}{Info}\\n    Contents of this tab are visible to no-root users if \\\\texttt{android.permission.GET\\\\_APP\\\\_OPS\\\\_STATS} is granted via ADB\\\\\\@.\\n\\\\end{tip}\\n\\nThere is a toggle button next to each app op item which can be used to allow or deny (ignore) it. Other supported modes\\ncan also be set by long clicking on the toggle button. If the desired app op is not listed in the tab,\\n\\\\textit{Set custom app op} option in the menu can be used instead. It is also possible to reset the changes\\nusing the \\\\textit{Reset to default} option, or deny all the dangerous app ops using the corresponding option in the menu.\\nDue to the nature how app ops work, the system may take some time to apply them.\\n\\n\\\\begin{tip}{Tip}\\n    Denying certain app ops may cause the application to misbehave. If all attempts fail, \\\\textit{reset to default}\\n    option can be used as the last resort.\\n\\\\end{tip}\\n\\nIt is possible to sort the list in ascending order by app op names and the associated unique numbers (or values), or\\nlist the denied app ops first using the corresponding sorting options.\\n\\n\\\\seealsoinline{\\\\hyperref[ch:app-ops]{Appendix: App Ops}}</string>\n    <string name=\"pages$app-details-page$uses-permissions\">\\\\textbf{Uses Permissions} are the permissions used by the application. This is named so because they are specified in\\nthe manifest using \\\\texttt{uses-permission} tags. Information such as \\\\textit{flags}, \\\\textit{permission name},\\n\\\\textit{permission description}, \\\\textit{package name}, \\\\textit{group} are taken from the associated\\n\\\\hyperref[subsubsec:permissions]{permission}.\\n\\nPrivileged users can grant or revoke the \\\\textit{dangerous} and \\\\textit{development} permissions via the toggle button\\non the right side of each permission item. It is also possible revoke dangerous permissions all at once using the\\ncorresponding option in the menu. Only these two types of permissions can be revoked because Android does not allow\\nthe modification of \\\\textit{normal} permissions (which most of them are). It might still be possible to revoke them\\nby editing \\\\texttt{runtime-permissions.xml} itself, but whether this is a possibility is still being investigated.\\n\\n\\\\begin{tip}{Info}\\n    Since dangerous permissions are revoked by default by the system, revoking all dangerous permissions is the same as\\n    resetting all the permissions.\\n\\\\end{tip}\\n\\nIt is possible to sort the permissions by their name (in ascending order) or choose to display denied or dangerous\\npermissions at first using the corresponding options in the menu.</string>\n    <string name=\"pages$app-details-page$permissions\">\\\\textbf{Permissions} are usually custom permissions defined by the application itself. These type of\\npermissions are marked as \\\\textit{Internal} permissions. It also contains permissions declared by\\nother applications which are marked as \\\\textit{External} permissions. An external permission can be\\nspecified in an \\\\textit{exported} application component so that another application may invoke the\\ncomponent only if it holds the permission. Below is a complete description of each item displayed in\\nthis tab:\\n\\\\begin{itemize}\\n    \\\\item \\\\textbf{Name.} A permission has a unique name (e.g., \\\\texttt{android.permission.INTERNET})\\n    that multiple applications can request. The application that declared the permission is\\n    automatically granted and cannot be revoked.\\n\\n    \\\\item \\\\textbf{Icon.} Each permission can have a custom icon. The other permission tabs do not have any icon because\\n    they do not contain any icon in the application manifest.\\n\\n    \\\\item \\\\textbf{Description.} This optional field describes the permission. If there isn\\'t any description associated\\n    with the permission, the field is not displayed.\\n\\n    \\\\item \\\\textbf{Flags.} (Uses the flag symbol or \\\\textbf{Protection Level} name) This describes various permission\\n    flags such as \\\\textit{normal}, \\\\textit{development}, \\\\textit{dangerous}, \\\\textit{instant}, \\\\textit{granted},\\n    \\\\textit{revoked}, \\\\textit{signature}, \\\\textit{privileged}, etc.\\n\\n    \\\\item \\\\textbf{Package Name.} Denotes the package name associated with the permission, i.e.\\\\ the package that defined\\n    the permission.\\n\\n    \\\\item \\\\textbf{Group.} The group name associated with the permission (if any). Several related permissions can often\\n    be grouped together.\\n\\\\end{itemize}</string>\n    <string name=\"pages$app-details-page$signatures-tab_1\">\\\\textbf{Signatures} are actually called signing information. An application is signed with one or\\nmore signing keys by its developer before publishing it. The integrity of an application, i.e.,\\nwhether the application is from the actual developer and has not been modified by another person,\\ncan be checked using the signing certificate included in the APK files. This is because when an\\napplication is modified by an unauthorised entity, the application can longer be signed with the\\noriginal signing keys since the signing keys are unknown to the entity. One way to verify the\\nintegrity of an application is via the checksums generated from the certificates. If the developer\\nsupplies the checksums for the signing certificates, they can be compared against the checksums\\ngenerated in the \\\\textbf{Signatures} tab to verify the application. For example, if you have\\ndownloaded App Manager from GitHub or Telegram Channel, you can verify whether the application was\\nactually released by me by simply matching the following \\\\textit{SHA256} checksum with the one\\ndisplayed in this tab:</string>\n    <string name=\"pages$app-details-page$signatures-tab_2\">Several hashing algorithms are used to generate checksums in this tab. They include \\\\textit{MD5}, \\\\textit{SHA1},\\n\\\\textit{SHA256} and \\\\textit{SHA512}.\\n\\n\\\\begin{danger}{Caution}\\n    Signing information should be verified using a reliable hashing algorithm, such as \\\\textit{SHA256}.\\n    DO NOT rely on \\\\textit{MD5} or \\\\textit{SHA1} checksums as they are known to generate the same\\n    checksums for multiple certificates.\\n\\\\end{danger}</string>\n    <string name=\"pages$app-details-page$uses-features-tab\">\\\\textbf{Uses Features} tab lists the features declared by the application, such as OpenGL ES,\\ntelephony, and leanback. Some features can be required by the application, and some features can be\\noptional. Required features must be present in the system along with the required version.\\nOtherwise, any attempt to install the application will be denied by the system. Colours used in this\\ntab are explained in \\\\Sref{subsec:app-details-colour-codes}.</string>\n    <string name=\"pages$app-details-page$configurations-tab\">\\\\textbf{Configurations} tab lists the configurations required by the application, such as input\\nmethod type (qwerty, 12 key), touch screen type (finger, stylus, etc.), and navigation type (dial\\npad, trackball, wheel). This tab is going to be empty for most applications.</string>\n    <string name=\"pages$app-details-page$shared-libs-tab\">\\\\textbf{Shared libraries} tab lists the legacy JAR dependencies, any static shared library\\ndependencies (currently, the only known cases are the Chromium-based browsers and WebViews) as well\\nas the JNI (Java native interface) libraries. For JNI libraries, it specifies platform\\n(x86/x86\\\\_64/ARM/AArch64), architecture (32/64 bit), object type (shared object or executable), etc.</string>\n    <string name=\"pages$one-click-ops-page$$section-title\">1-Click Ops Page</string>\n    <string name=\"pages$one-click-ops-page$$block-unblock-trackers-title\">Block/Unblock Trackers</string>\n    <string name=\"pages$one-click-ops-page$$block-components-dots-title\">Block Components\\\\dots</string>\n    <string name=\"pages$one-click-ops-page$$set-mode-for-app-ops-dots-title\">Set Mode for App Ops\\\\dots</string>\n    <string name=\"pages$one-click-ops-page$$1-click-back-up-title\">Back up</string>\n    <string name=\"pages$one-click-ops-page$$1-click-restore-title\">Restore</string>\n    <string name=\"pages$one-click-ops-page$$trim-caches-in-all-apps-title\">Trim Caches in All Apps</string>\n    <string name=\"pages$one-click-ops-page$intro\">This page is displayed on selecting the \\\\hyperref[subsubsec:main:1-click-ops]{1-Click Ops option} in the \\\\hyperref[subsec:main-page-options-menu]{main menu}.</string>\n    <string name=\"pages$one-click-ops-page$block-unblock-trackers\">This option can be used to block or unblock the ad/tracker components from the installed applications.\\nOn selecting this option, App Manager will ask if it should list trackers from all the applications or only from the user applications.\\nNovice users should avoid blocking trackers from the system applications in order to avoid bad consequences.\\nAfter that, a multi-choice dialog box will appear where it is possible to exclude one or more applications from this operation.\\nThe changes are applied immediately on pressing the \\\\textit{block} or \\\\textit{unblock} button.\\n\\n\\\\begin{warning}{Notice}\\n    Certain applications may not function as expected after blocking their trackers.\\n    If that is the case, remove the blocking rules all at once or one by one in the component tabs of the \\\\hyperref[sec:app-details-page]{App Details page} for the corresponding application.\\n\\\\end{warning}\\n\\n\\\\seealsoinline{\\\\hyperref[par:appdetails:blocking-trackers]{App Details Page: Blocking Trackers}}</string>\n    <string name=\"pages$one-click-ops-page$block-components-dots\">This option can be used to block certain application components as specified by their signatures.\\nA signature of a component is the full name or partial name of the component.\\nFor safety, it is recommended to add a \\\\texttt{.} (dot) at the end of each partial signature, because the underlying\\nalgorithm searches and matches the components in a greedy manner.\\nIt is also possible to insert more than one signature in which case all the signatures have to be separated by white spaces.\\nSimilar to the option above, there is also an option to apply blocking to the system applications.\\n\\n\\\\begin{danger}{Caution}\\n    If you are not aware of the consequences of blocking applcations components by their signatures, you should avoid\\n    using this option as it may result in bootloop or soft brick, and you may have to apply factory reset as a result.\\n\\\\end{danger}</string>\n    <string name=\"pages$one-click-ops-page$set-mode-for-app-ops-dots\">This option can be used to configure certain \\\\hyperref[ch:app-ops]{applcation operations} of all or selected applications.\\nThere are two fields. The first field can be used to insert more than one app op constants (either names or values) separated by white spaces.\\nIt is not always possible to know in advance about all the app op constants as they vary from device to device and from OS to OS\\\\\\@.\\nDesired app op constant can be found in the \\\\textit{App Ops} tab located in the \\\\hyperref[sec:app-details-page]{App Details page}.\\nThe second field can be used to insert or select one of the \\\\hyperref[subsec:mode-constants]{modes} that will be set against the specified app ops.\\n\\n\\\\begin{danger}{Caution}\\n    Unless you are well-informed about app ops and the consequences of blocking them, you should avoid using this option.\\n\\\\end{danger}</string>\n    <string name=\"pages$one-click-ops-page$back-up\">1-Click options for back up. As a precaution, it lists the affected backups before performing any operation.\\n\\n\\\\paragraph{Back up all apps.} Back up all the installed applications.\\n\\n\\\\paragraph{Redo existing backups.} Back up all the installed applications that have a previous backup.\\n\\n\\\\paragraph{Back up apps without backups.} Back up all the installed applications without a previous backup.\\n\\n\\\\paragraph{Verify and redo backups.} Verify the recently made backups of the installed applications and redo backup if necessary.\\n\\n\\\\paragraph{Back up apps with changes.} If an app has changed since the last backup, redo its backup.\\nIt checks a number of indices including application version, last update date, last launch date, integrity and file hashes.\\nDirectory hashes are taken during the backup process and are stored in a database.\\nOn running this operation, new hashes are taken and compared with the ones kept in the database.</string>\n    <string name=\"pages$one-click-ops-page$restore\">1-Click options for restore. As a precaution, it lists the affected backups before performing any operation.\\n\\n\\\\paragraph{Restore all apps.} Restore \\\\textit{base backup} of all the backed up applications.\\n\\n\\\\paragraph{Restore not installed apps.} Restore \\\\textit{base backup} of all the backed up applications that are not currently installed.\\n\\n\\\\paragraph{Restore latest backups.} Restore \\\\textit{base backup} of already installed applications whose version codes are higher than the installed version code.</string>\n    <string name=\"pages$one-click-ops-page$trim-caches-in-all-apps\">Delete caches from all applications, including Android system. During this operation, caches of all the running\\napplications may not be cleared as expected.</string>\n    <string name=\"pages$profiles-page$$section-title\">Profiles Page</string>\n    <string name=\"pages$profiles-page$$options-menu-title\">Options Menu</string>\n    <string name=\"pages$profiles-page$intro\">Profiles page can be accessed from the \\\\hyperref[subsec:main-page-options-menu]{options-menu} in the\\nmain page. It primarily displays a list of configured profiles along with the typical options to\\nperform operations on them. New profiles can also be added using the \\\\textit{plus} button at the\\nbottom-right corner. Profiles can be imported, duplicated or deleted. Clicking on a profile item\\nopens its \\\\hyperref[sec:profile-page]{profile page}.</string>\n    <string name=\"pages$profiles-page$options-menu\">The three-dots menu in the top-right corner opens the global option menu. It has an option to import\\nan existing profile that was previously exported from App Manager.\\n\\nLong clicking on any profile item brings up another options-menu. It offers the following options:\\n\\\\begin{itemize}\\n    \\\\item \\\\textbf{Apply now\\\\dots.} This option can be used to apply the profile directly. When\\n    clicked, a dialog is displayed where it is possible to select a \\\\hyperref[subsubsec:profile-state]{profile state}.\\n    On selecting one of the states, the profile will be applied immediately.\\n\\n    \\\\item \\\\textbf{Delete.} Clicking on this option will remove the profile immediately without a warning.\\n\\n    \\\\item \\\\textbf{Duplicate.} This option can be used to duplicate the profile. When clicked, a\\n    dialog is displayed where it is possible to set a name for the new profile. On clicking ``OK\\'\\',\\n    the \\\\hyperref[sec:profile-page]{profile page} will be loaded by duplicating all the\\n    configurations that this profile have. However, the profile will not be saved until it is saved\\n    manually.\\n\\n    \\\\item \\\\textbf{Copy profile ID.} This option is used to copy the unique profile ID of the profile.\\n    The profile ID can be used to \\\\hyperref[subsec:triggering-a-profile]{trigger the profile} from a\\n    third-party application.\\n\\n    \\\\item \\\\textbf{Export.} Export the profile to an external storage. Profiles exported this way can\\n    be imported via the \\\\textit{import} option as mentioned above.\\n\\n    \\\\item \\\\textbf{Create shortcut.} This option can be used to create a shortcut for the profile.\\n    There are two options: \\\\textit{Simple} and \\\\textit{Advanced}. When configured with the latter\\n    option, it prompts the user to select a profile state when the shortcut is invoked. The former\\n    option, on the other hand, always uses the default state that was configured when the profile\\n    was last saved.\\n\\\\end{itemize}</string>\n    <string name=\"pages$profile-page$$section-title\">Profile Page</string>\n    <string name=\"pages$profile-page$$options-menu-title\">Options Menu</string>\n    <string name=\"pages$profile-page$$apps-tab-title\">Apps Tab</string>\n    <string name=\"pages$profile-page$$configurations-tab-title\">Configurations Tab</string>\n    <string name=\"pages$profile-page$$profile-id-title\">Profile ID</string>\n    <string name=\"pages$profile-page$$comment-title\">Comment</string>\n    <string name=\"pages$profile-page$$state-title\">State</string>\n    <string name=\"pages$profile-page$$users-title\">Users</string>\n    <string name=\"pages$profile-page$$components-title\">Components</string>\n    <string name=\"pages$profile-page$$app-ops-title\">App Ops</string>\n    <string name=\"pages$profile-page$$permissions-title\">Permissions</string>\n    <string name=\"pages$profile-page$$backup-restore-title\">Backup/Restore</string>\n    <string name=\"pages$profile-page$$export-blocking-rules-title\">Export Blocking Rules</string>\n    <string name=\"pages$profile-page$$freeze-title\">Freeze</string>\n    <string name=\"pages$profile-page$$force-stop-title\">Force-stop</string>\n    <string name=\"pages$profile-page$$clear-cache-title\">Clear Cache</string>\n    <string name=\"pages$profile-page$$clear-data-title\">Clear Data</string>\n    <string name=\"pages$profile-page$$block-trackers-title\">Block Trackers</string>\n    <string name=\"pages$profile-page$$save-apk-title\">Save APK</string>\n    <string name=\"pages$profile-page$intro\">Profile page displays the configurations for a profile. It also offers the options to edit them.</string>\n    <string name=\"pages$profile-page$options-menu\">The three dots menu in the top-right corner opens the options-menu. It contains several options such as--\\n\\\\begin{itemize}\\n    \\\\item \\\\textbf{Apply.} This option can be used to apply the profile directly. When\\n    clicked, a dialog is displayed where it is possible to select a \\\\hyperref[subsubsec:profile-state]{profile state}.\\n    On selecting one of the states, the profile will be applied immediately.\\n    \\\\begin{tip}{Notice}\\n        When you apply a profile, if some packages do not match the criteria, they will simply be ignored.\\n    \\\\end{tip}\\n\\n    \\\\item \\\\textbf{Save.} Save changes to the profile.\\n\\n    \\\\item \\\\textbf{Discard.} Discard any modifications made since the last time it was saved.\\n\\n    \\\\item \\\\textbf{Delete.} Clicking on this option will remove the profile immediately without a warning.\\n\\n    \\\\item \\\\textbf{Duplicate.} This option can be used to duplicate the profile. When clicked, a\\n    dialog is displayed where it is possible to set a name for the new profile. On clicking ``OK\\'\\',\\n    this page will be reloaded by duplicating all the configurations that this profile have.\\n    However, the new profile will not be saved until it is saved manually.\\n\\n    \\\\item \\\\textbf{Create shortcut.} This option can be used to create a shortcut for the profile.\\n    There are two options: \\\\textit{Simple} and \\\\textit{Advanced}. When configured with the latter\\n    option, it prompts the user to select a profile state when the shortcut is invoked. The former\\n    option, on the other hand, always uses the default state that was configured when the profile\\n    was last saved.\\n\\\\end{itemize}</string>\n    <string name=\"pages$profile-page$apps-tab\">Apps tab lists the packages configured for this profile. Packages can be added or removed using the\\n\\\\textit{plus} button located near the bottom of the screen. A package can also be removed by long\\nclicking on it (in which case, a popup will be displayed with the only option, \\\\textit{delete}).</string>\n    <string name=\"pages$profile-page$configurations-tab\">Configurations tab can be used to configure the selected packages.\\n\\n\\\\begin{tip}{Uninstalling a List of Applications.}\\n    Since uninstalling is a one time event, it is not part of the configurations. However, it is\\n    still possible to uninstall the applications belonging to a profile. To do this, you can filter\\n    the applications in the Main page using a profile, select all the filtered applications, and\\n    uninstall them.\\n\\\\end{tip}</string>\n    <string name=\"pages$profile-page$profile-id\">The unique ID for this profile, currently set based on the profile name. The profile ID can be used\\nto \\\\hyperref[subsec:triggering-a-profile]{trigger the profile} from a third-party application.</string>\n    <string name=\"pages$profile-page$comment\">This is the text that will be displayed in the \\\\hyperref[sec:profiles-page]{profiles page}. If not set, the current\\nconfigurations will be displayed instead.</string>\n    <string name=\"pages$profile-page$state\">Denotes how certain configured options will behave by default. For instance, if \\\\textit{disable} option is turned on,\\nthe applications will be disabled if the state is \\\\textit{on} and will be enabled if the state is \\\\textit{off}.\\nCurrently, it only supports \\\\textit{on} and \\\\textit{off} values.</string>\n    <string name=\"pages$profile-page$users\">Select users for which is the profile will be applied. All users are selected by default.</string>\n    <string name=\"pages$profile-page$components\">This behaves the same way as the \\\\hyperref[subsec:block-components-dots]{Block Components\\\\dots} option does in the\\n1-Click Ops page. However, the blocking here is only applied to the selected packages.\\nIf the \\\\hyperref[subsubsec:profile-state]{state} is \\\\textit{on}, the components will be blocked,\\nand if the state is \\\\textit{off}, the components will be unblocked.\\nThe option can be disabled (regardless of the inserted values) by clicking on the \\\\textit{disabled} button on the input dialog.\\n\\n\\\\seealsoinline{\\\\hyperref[subsec:faq:what-are-app-components]{What are the app components\\?}}</string>\n    <string name=\"pages$profile-page$app-ops\">This behaves the same way as the \\\\hyperref[subsec:set-mode-for-app-ops-dots]{Set Mode for App Ops\\\\dots} option does in\\nthe 1-Click Ops page. However, the operation here is only applied to the selected packages.\\nIf the \\\\hyperref[subsubsec:profile-state]{state} is \\\\textit{on}, the app ops will be denied (i.e.\\\\ ignored),\\nand if the state is \\\\textit{off}, the app ops will be allowed. The option can be disabled (regardless of the inserted\\nvalues) by clicking on the \\\\textit{disable} button in the input dialog.</string>\n    <string name=\"pages$profile-page$permissions\">This option can be used to grant or revoke certain permissions from the selected packages. Like others above,\\npermissions must be separated by white spaces. If the \\\\hyperref[subsubsec:profile-state]{state} is \\\\textit{on}, the\\npermissions will be revoked, and if the state is \\\\textit{off}, the permissions will be allowed. The option can be\\ndisabled (regardless of the inserted values) by clicking on the \\\\textit{disable} button in the input dialog.</string>\n    <string name=\"pages$profile-page$backup-restore\">This option can be used to take a backup of the selected applications and its data or restore them.\\nTwo options are available here: \\\\textit{Backup options} and \\\\textit{backup name}.\\n\\\\begin{itemize}\\n    \\\\item \\\\textbf{Backup options.} Same as the \\\\hyperref[subsec:backup-restore-backup-options]{backup options} of the\\n    backup/restore feature. If not set, the default options will be used.\\n    \\\\item \\\\textbf{Backup name.} Set a custom name for the backup. If the backup name is set, each time a backup is made,\\n    it will be given a unique name with backup-name as the suffix. This behaviour will be fixed in a future release.\\n    Leave this field empty for regular ``base\\'\\' backups (also, make sure not to enable \\\\textit{backup multiple} in the\\n    backup options).\\n\\\\end{itemize}\\n\\nIf the \\\\hyperref[subsubsec:profile-state]{state} is \\\\textit{on}, the packages will be backed up, and if the state is\\n\\\\textit{off}, the packages will be restored. The option can be disabled by clicking on the \\\\textit{disable} button in\\nthe input dialog.</string>\n    <string name=\"pages$profile-page$export-blocking-rules\">\\\\begin{danger}{Danger}\\n    This option is not yet implemented.\\n\\\\end{danger}</string>\n    <string name=\"pages$profile-page$freeze\">Allow freezing or unfreezing the selected packages depending on the value of the \\\\hyperref[subsubsec:profile-state]{state}.\\nIf the state is \\\\textit{on}, the packages will be frozen, and if the state is \\\\textit{off}, they will be unfrozen.</string>\n    <string name=\"pages$profile-page$force-stop\">Allow the selected packages to be force-stopped.</string>\n    <string name=\"pages$profile-page$clear-cache\">Enable clearing cache for the selected packages.</string>\n    <string name=\"pages$profile-page$clear-data\">Enable clearing data for the selected packages.</string>\n    <string name=\"pages$profile-page$block-trackers\">Enable blocking or unblocking of the tracker components from the selected packages depending on the value of the \\\\hyperref[subsubsec:profile-state]{state}.\\nIf the state is \\\\textit{on}, the trackers will be blocked, and if the state is \\\\textit{off}, the trackers will be unblocked.</string>\n    <string name=\"pages$profile-page$save-apk\">Enable saving APK files at \\\\texttt{AppManager/apks} (or in the directory selected in the settings page) of the selected packages.</string>\n    <string name=\"pages$settings-page$$section-title\">Settings Page</string>\n    <string name=\"pages$settings-page$$language-title\">Language</string>\n    <string name=\"pages$settings-page$$appearance-title\">Appearance</string>\n    <string name=\"pages$settings-page$$app-theme-title\">App Theme</string>\n    <string name=\"pages$settings-page$$pure-black-theme-title\">Pure Black Theme</string>\n    <string name=\"pages$settings-page$$layout-direction-title\">Layout Direction</string>\n    <string name=\"pages$settings-page$$enable-disable-features-title\">Enable/Disable Features</string>\n    <string name=\"pages$settings-page$$privacy-settings-title\">Privacy</string>\n    <string name=\"pages$settings-page$$screen-lock-title\">Screen Lock</string>\n    <string name=\"pages$settings-page$$run-am-in-background-title\">Run App Manager in the Background</string>\n    <string name=\"pages$settings-page$$use-the-internet-title\">Use the Internet</string>\n    <string name=\"pages$settings-page$$auth-manager-title\">Authorization Manager</string>\n    <string name=\"pages$settings-page$$mode-of-operation-title\">Mode of Operation</string>\n    <string name=\"pages$settings-page$$apk-signing-title\">APK Signing</string>\n    <string name=\"pages$settings-page$$signature-schemes-title\">Signature Schemes</string>\n    <string name=\"pages$settings-page$$signing-key-title\">Signing Key</string>\n    <string name=\"pages$settings-page$$align-apk-files-title\">Align APK Files</string>\n    <string name=\"pages$settings-page$$installer-title\">Installer</string>\n    <string name=\"pages$settings-page$$install-location-title\">Install Location</string>\n    <string name=\"pages$settings-page$$block-trackers-title\">Block Trackers</string>\n    <string name=\"pages$settings-page$$display-changes-title\">Display Changes</string>\n    <string name=\"pages$settings-page$$installer-app-title\">Installer App</string>\n    <string name=\"pages$settings-page$$sign-apk-title\">Sign APK</string>\n    <string name=\"pages$settings-page$$immediately-perform-dex-opt-title\">Immediately Perform DEX Optimization</string>\n    <string name=\"pages$settings-page$$install-in-the-background-title\">Install in the Background</string>\n    <string name=\"pages$settings-page$$backup-restore-title\">Back up/Restore</string>\n    <string name=\"pages$settings-page$$compression-method-title\">Compression method</string>\n    <string name=\"pages$settings-page$$backup-options-title\">Backup Options</string>\n    <string name=\"pages$settings-page$$backup-apps-with-keystore-title\">Backup apps with Android KeyStore</string>\n    <string name=\"pages$settings-page$$encryption-title\">Encryption</string>\n    <string name=\"pages$settings-page$$backup-volume-title\">Backup Volume</string>\n    <string name=\"pages$settings-page$$import-backups-title\">Import Backups</string>\n    <string name=\"pages$settings-page$$rules-title\">Rules</string>\n    <string name=\"pages$settings-page$$instant-component-blocking-title\">Instant Component Blocking</string>\n    <string name=\"pages$settings-page$$import-export-blocking-rules-title\">Import/Export Blocking Rules</string>\n    <string name=\"pages$settings-page$$remove-all-rules-title\">Remove all rules</string>\n    <string name=\"pages$settings-page$$advanced-settings-title\">Advanced</string>\n    <string name=\"pages$settings-page$$selected-users-title\">Selected Users</string>\n    <string name=\"pages$settings-page$$saved-apk-name-format-title\">Saved APK Name Format</string>\n    <string name=\"pages$settings-page$$import-export-keystore-title\">Import/Export Keystore</string>\n    <string name=\"pages$settings-page$$device-info-title\">About the device</string>\n    <string name=\"pages$settings-page$intro\">Settings page can be used to customise the behaviour of App Manager.</string>\n    <string name=\"pages$settings-page$language\">Configure in-app language. App Manager currently supports 22 (twenty-two) languages.</string>\n    <string name=\"pages$settings-page$app-theme\">Configure in-app theme.</string>\n    <string name=\"pages$settings-page$pure-black-theme\">Whether to use a black background instead of the material themed background.</string>\n    <string name=\"pages$settings-page$layout-direction\">Change layout direction, either left to right or right to left. This is usually set using the selected language but not\\neverybody prefers the same direction.</string>\n    <string name=\"pages$settings-page$enable-disable-features\">Enable or disable certain features in App Manager, such as\\n\\\\begin{itemize}\\n    \\\\item \\\\textbf{Interceptor}\\n    \\\\item \\\\textbf{Manifest viewer}\\n    \\\\item \\\\textbf{Scanner}\\n    \\\\item \\\\textbf{Package installer}\\n    \\\\item \\\\textbf{Usage access.} With this feature turned off, App Manager will never ask for the \\\\textit{Usage Access} permission.\\n    \\\\item \\\\textbf{Log viewer}\\n    \\\\item \\\\textbf{App explorer.} The ``Explore\\'\\' option will not be available while trying to open an APK file.\\n    \\\\item \\\\textbf{App info.} The ``App info\\'\\' option displayed while trying to open an APK file.\\n    \\\\item \\\\textbf{Code Editor}\\n    \\\\item \\\\textbf{VirusTotal}\\n\\\\end{itemize}</string>\n    <string name=\"pages$settings-page$screen-lock\">Lock App Manager using Android screen lock provided a screen lock is configured.\\n\\n\\\\begin{warning}{Warning}\\n    If screen lock is disabled in Android after enabling this setting, App Manager will not open until it is enabled again.\\n\\\\end{warning}</string>\n    <string name=\"pages$settings-page$run-am-in-background\">Whether to run App Manager in the background to reduce the initialisation delay. On certain devices,\\nthis can also help if you\\'re frequently disconnected from ADB\\\\\\@.</string>\n    <string name=\"pages$settings-page$use-the-internet\">Whether to activate the Internet features in App Manager. This currently include VirusTotal and\\nPithus scanning in the \\\\hyperref[sec:scanner-page]{Scanner page}.</string>\n    <string name=\"pages$settings-page$auth-manager\">This setting allows a third-party application to get access to certain features, such as profiles.</string>\n    <string name=\"pages$settings-page$mode-of-operation\">Mode of operation defines how App Manager works as a whole. It has the following options:\\n\\\\begin{itemize}\\n    \\\\item \\\\textbf{Auto.} Let App Manager decide the suitable option.\\n    Although this is the default option, non-rooted users should use the \\\\textit{no-root} mode.\\n\\n    \\\\item \\\\textbf{Root.} Operate App Manager in root mode. App Manager will fall back to \\\\textit{no-root} mode if root\\n    is not detected, or in rare cases when Binder communication through root is disabled (e.g.\\\\ in \\\\href{https://github.com/MuntashirAkon/AppManager/issues/606}{Phh SuperUser}).\\n\\n    \\\\item \\\\textbf{ADB over TCP.} Operate App Manager in ADB mode via \\\\hyperref[sec:adb-over-tcp]{ADB over TCP}.\\n    App Manager will fall back to \\\\textit{no-root} mode if ADB over TCP is not enabled.\\n\\n    \\\\item \\\\textbf{Wireless debugging.} Enable ADB via Wireless Debugging. It will try to connect to the configured port\\n    automatically at first. On failure, it will ask the user to either pair or connect to the ADB daemon manually.\\n    App Manager will fall back to \\\\textit{no-root} mode if it fails to connect to the ADB daemon this way.\\n    \\\\begin{tip}{Info}\\n        This option is only displayed in devices running Android 11 or later as Wireless Debugging was introduced in Android 11.\\n    \\\\end{tip}\\n\\n    \\\\item \\\\textbf{No-root.} Operate App Manager in no-root mode. While App Manager performs better in this mode,\\n    all the root- or ADB-specific features will be disabled.\\n\\\\end{itemize}\\n\\nIt also displays the actual mode of operation at the top. The actual mode of operations are\\n\\\\textit{root}, \\\\textit{ABD} and \\\\textit{no-root}.\\n\\n\\\\begin{tip}{Notice}\\n    ``Remote service\\'\\' is only required for ADB users or when you use the custom commands.\\n\\\\end{tip}</string>\n    <string name=\"pages$settings-page$signature-schemes\">Configure the \\\\href{https://source.android.com/security/apksigning}{signature schemes} to be used when APK signing is enabled.\\nv1 and v2 signature schemes are enabled by default, but v3 should also be enabled to ensure proper security in Android 9 or later.</string>\n    <string name=\"pages$settings-page$signing-key\">Configure the signing key for signing APK files. Keys from an existing KeyStore can be imported to App Manager,\\nor a new key can be generated.\\n\\n\\\\begin{tip}{Tip}\\n    If you need to use the key in the future, it is recommended that you create a KeyStore yourself\\n    and import the key here. Without a proper backup, keys generated within App Manager are at the risk of being deleted.\\n\\\\end{tip}</string>\n    <string name=\"pages$settings-page$align-apk-files\">Performs zip alignment when App Manager signs an APK file. Zip alignment stores the files in the APK\\nfile (which is actually a zip file) in a way that a zip file reader can access the files quite\\neasily using random access instead of loading the entire APK file in the memory, which results in\\nthe reduction of Android\\'s memory usage. Note that this step is required if an application\\'s\\nmanifest has \\\\texttt{extractNativeLibs} set to \\\\texttt{true}.</string>\n    <string name=\"pages$settings-page$installer-subtitle\">Configure the default behaviour of the installer. You can also find most of the settings by clicking\\non the \\\\textit{cog} icon when you install an application.</string>\n    <string name=\"pages$settings-page$install-location\">Define APK installation location. This can be one of \\\\textit{auto}, \\\\textit{internal only} and \\\\textit{prefer external}.\\nIn newer Android versions, selecting the last option does not guarantee that the application will be installed in the\\nexternal storage.</string>\n    <string name=\"pages$settings-page$block-trackers\">Whether to block the tracking components immediately after installing the application.</string>\n    <string name=\"pages$settings-page$display-changes\">Whether to display changes in version, trackers, components, permissions, signatures, SDK, etc. in a version controlled\\nstyle before installing the application if the application has already been installed.</string>\n    <string name=\"pages$settings-page$installer-app\">Select the installer application. This is useful for applications that explicitly checks the installer as a way to\\nverify if the application is installed legitimately. This only works for root or ADB users.\\n\\n\\\\begin{tip}{Notice}\\n    While checking for the installer might seem a legitimate concern for an application, the Android framework already\\n    deals with this during the installation. Checking for the installer is simply the wrong way to prove the legitimacy\\n    of the source of an application.\\n\\\\end{tip}</string>\n    <string name=\"pages$settings-page$sign-apk\">Whether to sign the APK files before installing the application. A signing key has to be added or generated before this\\noption can be enabled. This can be done in the \\\\hyperref[subsec:apk-signing]{APK signing} page.</string>\n    <string name=\"pages$settings-page$immediately-perform-dex-op\">Whether to perform DEX optimization immediately after installing the application. This can be useful\\nfor heavy applications, such as the gaming applications.</string>\n    <string name=\"pages$settings-page$install-in-the-background\">Whether to always install applications in the background. A notification will be issued once the installation is finished.</string>\n    <string name=\"pages$settings-page$backup-restore\">Settings related to \\\\hyperref[sec:backup-restore]{back up/restore}.</string>\n    <string name=\"pages$settings-page$compression-method\">Set the compression method to be used during backups. App Manager supports GZip, BZip2 and Zstandard\\ncompression methods, GZip being the default compression method. It doesn\\'t affect the restore of\\nan existing backup.</string>\n    <string name=\"pages$settings-page$backup-options\">Customise the \\\\textit{back up/restore dialog} displayed while taking a backup.\\n\\n\\\\seealsoinline{\\\\hyperref[subsec:backup-restore-backup-options]{Backup options}}</string>\n    <string name=\"pages$settings-page$backup-apps-with-keystore\">Allow backup of applications that has entries in the Android KeyStore. This option is disabled by\\ndefault because a few apps (such as Signal or Element) may crash if restored.</string>\n    <string name=\"pages$settings-page$encryption\">Set an encryption method for the backups. App Manager currently supports OpenPGP (via\\n\\\\href{https://f-droid.org/packages/org.sufficientlysecure.keychain/}{OpenKeyChain}), AES, RSA and ECC\\\\\\@.\\nLike \\\\hyperref[subsec:apk-signing]{APK signing}, The AES, RSA and ECC keys are stored in the\\nKeyStore and can be imported from other KeyStores.\\n\\n\\\\begin{danger}{Danger}\\n    For your own safety, it is not recommended generating RSA and ECC keys inside App Manager.\\n    Instead, they should be imported from a KeyStore stored in a secure place.\\\\\\\\\\n    In case of AES, the generated key should be stored in a secure place, such as in a password manager.\\n\\\\end{danger}</string>\n    <string name=\"pages$settings-page$backup-volume\">Select the storage where the backups will be stored. This is also where logs and exported APK files are saved.\\n\\n\\\\begin{tip}{Notice}\\n    The backup volume only specifies the storage, not the path. Backups are traditionally stored in the \\\\texttt{AppManager} folder inside the storage path.\\n    But when the path is selected using Storage Access Framework (SAF), the selected path or directory is used directly.\\n\\\\end{tip}</string>\n    <string name=\"pages$settings-page$import-backups\">Import backups from old and discontinued projects such as Titanium Backup, OAndBackup, and Swift Backup (version 3.0 to 3.2).\\nThe backups are not deleted after importing to prevent data loss in case the imported backups cannot be restored properly.</string>\n    <string name=\"pages$settings-page$instant-component-blocking\">By default, blocking rules are not applied unless they are applied explicitly in \\\\hyperref[sec:app-details-page]{the App Details page} for any application.\\nAfter enabling this option, all (old and new) rules are applied immediately for all applications without explicitly enabling blocking for an application.\\n\\n\\\\seealsoinline{\\\\hyperref[subsec:faq:what-is-instant-component-blocking]{FAQ: What is instant component blocking\\?}}</string>\n    <string name=\"pages$settings-page$import-export-blocking-rules\">It is possible to import or export blocking rules within App Manager for all applications. The types of rules (components, app ops or permissions) that should be imported or exported can also be selected.\\nIt is also possible to import blocking rules from \\\\href{https://github.com/lihenggui/blocker}{Blocker} and \\\\href{https://github.com/tuyafeng/Watt}{Watt}.\\nIf it is necessary to export blocking rules for a single application, the corresponding \\\\hyperref[sec:app-details-page]{App Details page} can be used to export rules, or for multiple apps, \\\\hyperref[subsec:batch-operations]{batch operations} can be used.\\n\\n\\\\seealsoinline{\\\\hyperref[sec:rules-specification]{Rules Specification}}\\n\\n\\\\paragraph{Export} Export blocking rules for all applications configured within App Manager.\\nThis may include \\\\hyperref[subsec:faq:what-are-app-components]{app components}, app ops and permissions based on the options selected in the multi-choice options.\\n\\n\\\\paragraph{Import} Import previously exported blocking rules from App Manager.\\nSimilar to export, this may include \\\\hyperref[subsec:faq:what-are-app-components]{app components}, app ops and permissions based on the options selected in the multi-choice options.\\n\\n\\\\paragraph{Import Existing Rules}\\\\label{par:import-existing-rules}\\n\\\\phantomsection\\nAdd components disabled by other applications to App Manager. App Manager only keeps track of the components disabled within App Manager.\\nIf application components are blocked or disabled by other tools or applications, this option can be utilised to import them.\\nOn clicking this option, App Manager will find the components potentially disabled by other applications or tools and list only the name of the applications along with the number of matched components.\\nFor safety, all the applications are unselected by default. They have to be selected manually, and the blocking has to be re-applied via App Manager.\\n\\n\\\\begin{danger}{Caution}\\n    Be careful when using this tool as there can be many false positives.\\n    Choose only the applications that you are certain about.\\n\\\\end{danger}\\n\\n\\\\paragraph{Import from Watt} Import configuration files from \\\\href{https://github.com/tuyafeng/Watt}{Watt}, each file\\ncontaining rules for a single package and file name being the name of the package with \\\\texttt{.xml} extension.\\n\\n\\\\begin{tip}{Tip}\\n    Location of configuration files in Watt: \\\\texttt{/sdcard/Android/data/com.tuyafeng.watt/files/ifw}\\n\\\\end{tip}\\n\\n\\\\paragraph{Import from Blocker} Import blocking rules from \\\\href{https://github.com/lihenggui/blocker}{Blocker}, each file containing rules for a single package.\\nThese files have a \\\\texttt{.json} extension.</string>\n    <string name=\"pages$settings-page$remove-all-rules\">One-click option to remove all rules configured within App Manager.\\nThis will enable all blocked components, app ops will be set to their default values and permissions will be granted.</string>\n    <string name=\"pages$settings-page$selected-users\">This option lets you control the users App Manager should operate on. App Manager operates on all users in root or ADB mode by default.</string>\n    <string name=\"pages$settings-page$saved-apk-name-format\">Defines the format of the APK name to be used while saving it via batch operations or through profiles.\\nApp Manager offers some special keywords enclosed inside \\\\texttt{\\\\%} (percentage) signs and available below the input box.\\nThese keywords are:\\n\\\\begin{itemize}\\n    \\\\item \\\\textbf{\\\\texttt{label}.} Denotes the name or label of the application. This can be localised to the configured language depending on the app.\\n    \\\\item \\\\textbf{\\\\texttt{package\\\\_name}.} Denotes the name of the package or application ID, the unique identifier that each application has.\\n    \\\\item \\\\textbf{\\\\texttt{version}.} Denotes the current version of the application extracted from its manifest.\\n    \\\\item \\\\textbf{\\\\texttt{version\\\\_code}.} Denotes the current version code of the application that can be used to separate two versions of the same application.\\n    \\\\item \\\\textbf{\\\\texttt{min\\\\_sdk}.} Denotes the minimum SDK (i.e.\\\\ Android framework version) that the application can operate on. This data is only available since Android 7 (Nougat).\\n    \\\\item \\\\textbf{\\\\texttt{target\\\\_sdk}.} Denotes the SDK that this application targets. The application can operate on higher SDK but only in the compatibility mode.\\n    \\\\item \\\\textbf{\\\\texttt{datetime}.} Denotes the time and date when the APK is exported.\\n\\\\end{itemize}</string>\n    <string name=\"pages$settings-page$import-export-keystore\">Import or export the KeyStore used by App Manager. This is a Bouncy Castle KeyStore with \\\\texttt{bks} extension.\\nTherefore, other KeyStore such as Java KeyStore (JKS) or PKCS \\\\#12 are not supported.\\nIf a key is needed to be imported from such a KeyStore, the relevant options should be should as specified above.</string>\n    <string name=\"pages$settings-page$device-info\">Display Android version, security, CPU, GPU, battery, memory, screen, languages, user info, etc.</string>\n    <string name=\"pages$scanner-page$$section-title\">Scanner Page</string>\n    <string name=\"pages$scanner-page$$missing-signatures-title\">Missing Signatures</string>\n    <string name=\"pages$scanner-page$intro\">\\\\textbf{Scanner page} appears after clicking on the \\\\emph{scanner} button in the \\\\hyperref[subsec:app-info-tab]{App Info tab}.\\nExternal APK files can also be opened for scanning from file managers, web browsers, etc.\\n\\nIt scans for trackers and libraries, and displays the number of trackers and libraries as a summary.\\nIt also displays checksums of the APK file as well as the signing certificates. If VirusTotal is\\nconfigured in the settings, it also attempts to retrieve reports from VirusTotal, or uploads the APK\\nfile if it is not in the database. It also display a link to the \\\\href{https://beta.pithus.org}{Pithus}\\nreport provided the Internet features are enabled.\\n\\n\\\\begin{danger}{Disclaimer}\\n    App Manager only scans an application statically without prejudice. The application may provide\\n    the options for opting out, or in some cases, certain features of the tracker may not be used at\\n    all by the application (e.g.\\\\ F-Droid), or some applications may simply use them as placeholders\\n    to prevent the breaking of certain features (e.g.\\\\ Fennec F-Droid). \\\\textbf{The intention of the\\n    scanner is to give you an idea about what the APK might contain. It should be taken as an\\n    initial step for further investigations.}\\n\\\\end{danger}\\n\\nClicking on the first item (i.e.\\\\ number of classes) opens a new page containing a list of tracker\\nclasses for the application. All classes can also be viewed by clicking on the \\\\textit{Toggle Class\\nListing} menu. The SMALI or Java version of the class can be viewed by simply clicking on an item.\\n\\n\\\\begin{tip}{Notice}\\n    Due to various limitations, it is not possible to scan all the components of an APK file. This\\n    is especially true if an APK is highly obfuscated or packed. The scanner also does not check\\n    strings (or website signatures).\\n\\\\end{tip}\\n\\nThe second item lists the number of trackers along with their names. Clicking on the item displays a\\ndialog containing the name of trackers, matched signatures, and the number of classes against each\\nsignature. Some tracker names may have $^2$ prefix which indicates that the trackers are in the\\n\\\\href{https://etip.exodus-privacy.eu.org}{ETIP} stand-by list, i.e., whether they are actual\\ntrackers is still being investigated.\\n\\nThe third item lists the number of libraries along with their names. The information are mostly\\ntaken from \\\\href{https://gitlab.com/IzzyOnDroid/repo}{IzzyOnDroid repo}.\\n\\n\\\\seealsoinline{\\\\hyperref[subsec:tracker-classes-versus-tracker-components]{FAQ: Tracker classes vs tracker components}}</string>\n    <string name=\"pages$scanner-page$missing-signatures\">%At the bottom of the page, there is a special item denoting the number of missing signatures (i.e.,\\n%missing classes). The missing signatures are the ones that App Manager has failed to match against\\n%any known libraries. The number itself has no particular meaning as many libraries contain hundreds\\n%of classes, but clicking on the item will bring up a dialog containing the signatures which is\\n%helpful in inspecting the missing signatures. \\\\textbf{This feature is only intended for people who\\n%know what a missing signature is and what to do with it, other users should ignore it.}</string>\n    <string name=\"pages$interceptor-page$$section-title\">Interceptor Page</string>\n    <string name=\"pages$interceptor-page$$intent-filters-title\">Intent Filters</string>\n    <string name=\"pages$interceptor-page$$action-title\">Action</string>\n    <string name=\"pages$interceptor-page$$data-title\">Data</string>\n    <string name=\"pages$interceptor-page$$mime-type-title\">MIME Type</string>\n    <string name=\"pages$interceptor-page$$categories-title\">Categories</string>\n    <string name=\"pages$interceptor-page$$flags-title\">Flags</string>\n    <string name=\"pages$interceptor-page$$extras-title\">Extras</string>\n    <string name=\"pages$interceptor-page$$uri-title\">URI</string>\n    <string name=\"pages$interceptor-page$$matching-activities-title\">Matching Activities</string>\n    <string name=\"pages$interceptor-page$$reset-to-default-title\">Reset to Default</string>\n    <string name=\"pages$interceptor-page$$send-edited-intent-title\">Send Edited Intent</string>\n    <string name=\"pages$interceptor-page$intro\">Interceptor can be used to intercept communication between applications using \\\\texttt{Intent}.\\nIt works as a man-in-the-middle between the source and the destination applications.\\nIt offers a feature-complete user interface for editing \\\\texttt{Intent}s.\\n\\n\\\\begin{warning}{Warning}\\n    Interceptor only works for \\\\textit{implicit} intents where the \\\\hyperref[subsec:faq:what-are-app-components]{app component} isn\\'t specified.\\n\\\\end{warning}\\n\\n\\\\begin{amseealso}\\n    \\\\item \\\\href{https://developer.android.com/guide/components/intents-common}{Common Intents}\\n    \\\\item \\\\href{https://developer.android.com/guide/components/intents-filters}{Intents and Intent Filters}\\n\\\\end{amseealso}</string>\n    <string name=\"pages$interceptor-page$intent-filters\">Intent filters are used by the applications to specify the tasks they are able to perform or the tasks they are going to perform using other applications.\\nFor example, when you\\'re opening a PDF file using a file manager, the file manager will try to find the applications to open the PDF with.\\nTo find the right applications, the file manager will create an Intent with filters such as the MIME type and ask the system to retrieve the applications capable of opening this filter.\\nThe system will search through the Manifest of the installed applications to match the filter and list the application components that are able to open this filter (in our case the PDF).\\nAt this, either the file manager will open the desired application component all by itself or use a system provided option to open it.\\nIf multiple application components are able to open it and no default is set, you may get a prompt where you have to choose the right application component.</string>\n    <string name=\"pages$interceptor-page$action\">Action specifies the generic action to perform such as \\\\texttt{android.intent.action.VIEW}. Applications often declare\\nthe relevant actions in the Manifest file to catch the desired Intents. The action is particularly useful for broadcast\\nIntent where it plays a vital rule. In other cases, it works as an initial way to filter out the relevant application components.\\nGeneric actions such as \\\\texttt{android.intent.action.VIEW} and \\\\texttt{android.intent.action.SEND} are widely used by applications.\\nHence, setting this alone may match many application components.</string>\n    <string name=\"pages$interceptor-page$data\">Data is originally known as URI (Uniform Resource Identifier) defined in \\\\href{http://www.faqs.org/rfcs/rfc2396.html}{RFC 2396}.\\nIt can be web links, file location, or a special feature called \\\\textit{content}. Contents are an Android feature managed by the \\\\hyperref[subsubsec:providers]{content providers}.\\nData are often associated with a \\\\hyperref[subsubsec:mime-type]{MIME type}.\\n\\nExamples:</string>\n    <string name=\"pages$interceptor-page$mime-type\">MIME type of the \\\\hyperref[subsubsec:data]{data}. For example, if the data field is set to \\\\texttt{file:///sdcard/AppManager.apk},\\nthe associated MIME type can be \\\\texttt{application/vnd.android.package-archive}.</string>\n    <string name=\"pages$interceptor-page$categories\">This is similar to \\\\hyperref[subsubsec:action]{action} in the sense that it is also used by the system to filter application components.\\nThis has no further benefits. Unlike \\\\textit{action}, there can be more than one category. Clicking on the \\\\textit{plus} button next to the title allows adding more categories.</string>\n    <string name=\"pages$interceptor-page$flags\">Flags are useful in determining how system should behave during the launch or after the launch of an activity.\\nThis should not be touched as it requires some technical background. The \\\\textit{plus} button next to the title can be used to add one or more flags.</string>\n    <string name=\"pages$interceptor-page$extras\">Extras are the key-value pairs used for supplying additional information to the destination component. More extras can be added using the \\\\textit{plus} button next to the title.</string>\n    <string name=\"pages$interceptor-page$uri\">Represents the entire Intent as a URI (e.g. \\\\texttt{intent://\\\\dots}). Some data cannot be converted to string,\\nand as a result, they might not appear here.</string>\n    <string name=\"pages$interceptor-page$matching-activities\">List all the activity components that matches the Intent. This is internally determined by the system (rather than App Manager).\\nThe launch button next to each component can be used to launch them directly from App Manager.</string>\n    <string name=\"pages$interceptor-page$reset-to-default\">Reset the Intent to its initial state.</string>\n    <string name=\"pages$interceptor-page$send-edited-intent\">Resend the edited Intent to the destination application. This may open a list of applications where the desired application is needed to be selected.\\nThe result received from the target application will be sent to the source application. As a result, the source application will not know if there was a man-in-the-middle.</string>\n    <string name=\"pages$shared-prefs-editor-page$$section_title\">Shared Preferences Editor Page</string>\n    <string name=\"pages$shared-prefs-editor-page$intro\">Shared preferences can be edited in this page. Clicking any item on the list opens the edit dialog where the item can be\\nedited. The floating action button in the bottom-right corner can be used to add a new item. To save or delete the file,\\nor to discard current changes, the respective options in the menu can be used.</string>\n    <string name=\"guide$main$$guides-chapter-title\">Guides</string>\n    <string name=\"guide$aot$$section-title\">ADB over TCP</string>\n    <string name=\"guide$aot$$enable-dev-options-title\">Enable developer options</string>\n    <string name=\"guide$aot$$location-dev-options-title\">Location of developer options</string>\n    <string name=\"guide$aot$$how-to-enable-dev-options-title\">How to enable developer options</string>\n    <string name=\"guide$aot$$enable-usb-debugging-title\">Enable USB debugging</string>\n    <string name=\"guide$aot$$miui-usb-debug-title\">Xiaomi (MIUI)</string>\n    <string name=\"guide$aot$$emui-usb-debug-title\">Huawei (EMUI)</string>\n    <string name=\"guide$aot$$realme-usb-debug-title\">Realme</string>\n    <string name=\"guide$aot$$oneplus-usb-debug-title\">OnePlus (Oxygen OS)</string>\n    <string name=\"guide$aot$$lg-usb-debug-title\">LG</string>\n    <string name=\"guide$aot$$troubleshooting-usb-debug-title\">Troubleshooting</string>\n    <string name=\"guide$aot$$setup-adb-on-pc-title\">Setup ADB on PC or Mac</string>\n    <string name=\"guide$aot$$setup-adb-win-title\">Windows</string>\n    <string name=\"guide$aot$$setup-adb-mac-title\">macOS</string>\n    <string name=\"guide$aot$$setup-adb-linux-title\">Linux</string>\n    <string name=\"guide$aot$$configure-aot-title\">Configure ADB over TCP</string>\n    <string name=\"guide$aot$$aot-lineage-os-title\">Lineage OS 17.1 and Earlier</string>\n    <string name=\"guide$aot$$enable-aot-via-pc-title\">Enable ADB over TCP via PC or Mac</string>\n    <string name=\"guide$aot$$adb-mode-am-title\">Enable ADB mode in App Manager</string>\n    <string name=\"guide$aot$intro\">Many root-only features can still be used by enabling ADB over TCP. To do that, a PC or Mac is required with Android\\nplatform-tools installed, and an Android phone with developer options \\\\&amp; USB debugging enabled.\\n\\n\\\\begin{tip}{Root users}\\n    If superuser permission has been granted to App Manager, it can already execute privileged code\\n    without any problem. \\\\textbf{Therefore, root users do not need to enable ADB over TCP.} But if\\n    you insist on using ADB over TCP, you must revoke superuser permission for App Manager.\\n\\\\end{tip}\\n\\n\\\\seealsoinline{\\\\hyperref[sec:faq:adb-over-tcp]{FAQ: ADB over TCP}}</string>\n    <string name=\"guide$aot$location-dev-options\">\\\\textbf{Developer options} is located in Android \\\\textbf{Settings}, either directly near the bottom\\nof the page (in most ROMs) or under some other settings, such as \\\\textbf{System} (Google Pixel,\\nLineage OS, Asus Zenfone 8.0+), \\\\textbf{Additional Settings} (Xiaomi MIUI, Oppo ColorOS),\\n\\\\textbf{More Settings} (Vivo FuntouchOS), \\\\textbf{More} (ZTE Nubia). Unlike other options, it is not\\nvisible until explicitly enabled by the user. If it is already enabled, you can use the search box\\nin Android \\\\textbf{Settings} to locate it as well.</string>\n    <string name=\"guide$aot$how-to-enable-dev-options\">This option is available within Android \\\\textbf{Settings} as well but like the location of the developer options, it\\nalso differs from device to device. But in general, you have to find \\\\textbf{Build number} (or \\\\textbf{MIUI version} for\\nMIUI ROMs and \\\\textbf{Software version} for Vivo FuntouchOS, \\\\textbf{Version} for Oppo ColorOS) and tap it at least 7\\n(seven) times until you finally get a message saying \\\\textit{You are now a developer} (you may be prompted to insert\\npin/password/pattern or solve captchas at this point). In most devices, it is located at the bottom of the settings\\npage, inside \\\\textbf{About Phone}. But the best way to find it is to use the search box.</string>\n    <string name=\"guide$aot$enable-usb-debug\">After \\\\hyperref[subsubsec:location-of-developer-options]{locating the developer options}, enable \\\\textbf{Developer\\noption} (if not already). After that, scroll down a bit until you will find the option \\\\textbf{USB debugging}. Use the\\ntoggle button on the right-hand side to enable it. At this point, you may get an alert prompt where you may have to\\nclick \\\\textit{OK} to actually enable it. You may also have to enable some other options depending on device vendor and\\nROM. Here are some examples:</string>\n    <string name=\"guide$aot$miui-usb-debug\">Enable \\\\textbf{USB debugging (Security settings)} as well.</string>\n    <string name=\"guide$aot$emui-usb-debug\">Enable \\\\textbf{Allow ADB debugging in charge only mode} as well. When connecting to your PC or Mac, you may get a prompt\\nsaying \\\\textbf{Allow access to device data\\?} in which case click \\\\textbf{YES, ALLOW ACCESS}.\\n\\n\\\\begin{tip}{Notice}\\n    Often the \\\\textbf{USB debugging} mode could be disabled automatically by the system. If that\\'s the case, repeat the\\n    above procedure.\\n\\\\end{tip}</string>\n    <string name=\"guide$aot$realme-usb-debug\">Depending on the device and the version of operating system, you have to enable \\\\textbf{Disable Permission Monitoring},\\nor \\\\textbf{USB debugging (Security settings)} along with \\\\textbf{Install via USB}.</string>\n    <string name=\"guide$aot$oneplus-usb-debug\">Depending on the device and the version of operating system, you have to enable \\\\textbf{Disable Permission Monitoring}.</string>\n    <string name=\"guide$aot$lg-usb-debug\">Make sure you have \\\\textbf{USB tethering} enabled.</string>\n    <string name=\"guide$aot$troubleshooting-usb-debug\">In case \\\\textbf{USB Debugging} is greyed out, you can do the following:\\n\\\\begin{enumerate}\\n    \\\\item Make sure you enabled USB debugging before connecting your phone to the PC or Mac via USB cable\\n    \\\\item Enable USB tethering after connecting to PC or Mac via USB cable\\n    \\\\item (For Samsung) If your device is running KNOX, you may have to follow some additional steps. See official\\n    documentations or consult support for further assistant\\n\\\\end{enumerate}</string>\n    <string name=\"guide$aot$setup-adb-on-pc\">In order to enable ADB over TCP, you have to set up ADB in your PC or Mac. \\\\textbf{\\\\textit{Lineage OS users can skip to\\n\\\\Sref{subsubsec:lineage-os}.}}</string>\n    <string name=\"guide$aot$setup-adb-win\">\\\\begin{enumerate}\\n    \\\\item Download the latest version of\\n    \\\\href{https://dl.google.com/android/repository/platform-tools-latest-windows.zip}{Android SDK Platform-Tools} for\\n    Windows\\n    \\\\item Extract the contents of the zip file into any directory (such as \\\\texttt{C:\\\\textbackslash{adb}}) and navigate\\n    to that directory using \\\\textit{Explorer}\\n    \\\\item Open \\\\textbf{Command Prompt}, \\\\textbf{PowerShell}, or \\\\textbf{Terminal} from this directory.\\n    You can do it manually from the start menu or by holding \\\\texttt{Shift} and right clicking within\\n    the directory in \\\\textit{File Explorer} and then clicking either on \\\\textit{Open command window here},\\n    or \\\\textit{Open PowerShell window here} (depending on what you have installed). You can now\\n    access ADB by typing \\\\texttt{adb} (Command Prompt) or \\\\texttt{./adb} (PowerShell).\\n    Do not close this window yet.\\n\\\\end{enumerate}\\n\\n\\\\begin{tip}{Tip}\\n    If you have \\\\href{https://learn.microsoft.com/en-us/windows/package-manager/winget/}{WinGet}\\n    installed, you can install ADB using the following command:\\n    \\\\begin{minted}[frame=lines]{bash}\\nwinget install --id Google.PlatformTools\\n    \\\\end{minted}\\n    After that, you can simply type \\\\texttt{adb} to access ADB\\\\\\@.\\n\\\\end{tip}</string>\n    <string name=\"guide$aot$setup-adb-mac\">\\\\begin{enumerate}\\n    \\\\item Download the latest version of\\n    \\\\href{https://dl.google.com/android/repository/platform-tools-latest-darwin.zip}{Android SDK Platform-Tools} for\\n    macOS\\n    \\\\item Extract the contents of the zip file into a directory by clicking on it. After that, navigate to that\\n    directory using \\\\textit{Finder} and locate \\\\texttt{adb}\\n    \\\\item Open \\\\textbf{Terminal} using \\\\textit{Launchpad} or \\\\textit{Spotlight} and drag-and-drop \\\\texttt{adb} from the\\n    \\\\textit{Finder} window into the \\\\textit{Terminal} window. Do not close the \\\\textit{Terminal} window yet\\n\\\\end{enumerate}\\n\\n\\\\begin{tip}{Tip}\\n    If you have \\\\href{https://brew.sh}{Homebrew} installed, you can install ADB using the following\\n    command:\\n    \\\\begin{minted}[frame=lines]{bash}\\nbrew install --cask android-platform-tools\\n    \\\\end{minted}\\n    After that, you can simply type \\\\texttt{adb} in any \\\\textit{Terminal} window to access ADB\\\\\\@.\\n\\\\end{tip}</string>\n    <string name=\"guide$aot$setup-adb-linux\">\\\\begin{enumerate}\\n    \\\\item In your favourite terminal emulator, run the following command:\\n    \\\\begin{minted}[frame=lines,autogobble]{bash}\\ncd ~/Downloads &amp;&amp; curl -o platform-tools.zip -L \\\\\\nhttps://dl.google.com/android/repository/platform-tools-latest-linux.zip &amp;&amp; \\\\\\nunzip platform-tools.zip &amp;&amp; rm platform-tools.zip &amp;&amp; cd platform-tools\\n    \\\\end{minted}\\n    \\\\item If it is successful, you can simply type \\\\texttt{./adb} in the in \\\\textit{same} terminal emulator window or\\n    type \\\\texttt{\\\\textasciitilde/Downloads/platform-tools/adb} in any terminal emulator to access ADB\\\\\\@.\\n\\\\end{enumerate}</string>\n    <string name=\"guide$aot$aot-lineage-os\">Lineage OS (or its derivatives) users can directly enable ADB over TCP using the developer options. To enable that,\\ngo to the \\\\textbf{Developer options}, scroll down until you find \\\\textbf{ADB over Network}. Now, use the toggle button\\non the right-hand side to enable it and skip to \\\\Sref{subsubsec:adb-mode-in-app-manager}.\\n\\n\\\\begin{warning}{Warning}\\n    You can turn off \\\\textbf{ADB over Network} in developer options, but turning off this option will also stop App\\n    Manager\\'s remote server. So, turn it off only when you\\'re not going to use App Manager in ADB over TCP mode.\\n\\\\end{warning}</string>\n    <string name=\"guide$aot$enable-aot-via-pc\">For other ROMs, you can do this using the command prompt/PowerShell/terminal emulator that you\\'ve opened in the step 3\\nof the previous section. In this section, I will use \\\\texttt{adb} to denote \\\\texttt{./adb}, \\\\texttt{adb} or any other\\ncommand that you needed to use based on your platform and software in the previous section.\\n\\\\begin{enumerate}\\n    \\\\item Connect your device to your PC or Mac using a USB cable. For some devices, it is necessary to turn on\\n    \\\\textit{File transfer mode (MTP)} as well\\n    \\\\item To confirm that everything is working as expected, type \\\\texttt{adb devices} in your terminal. If your device\\n    is connected successfully, you will see something like this:\\n    \\\\begin{Verbatim}\\nList of devices attached\\nxxxxxxxx  device\\n    \\\\end{Verbatim}\\n    \\\\begin{tip}{Notice}\\n        In some Android phones, an alert prompt will be appeared with a message \\\\textbf{Allow USB Debugging}\\n        in which case, check \\\\textit{Always allow from this computer} and click \\\\textbf{Allow}.\\n    \\\\end{tip}\\n    \\\\item Finally, run the following command to enable ADB over TCP:\\n    \\\\begin{minted}[frame=lines,autogobble]{bash}\\nadb tcpip 5555\\n    \\\\end{minted}\\n\\\\end{enumerate}\\n\\n\\\\begin{danger}{Danger}\\n    You cannot disable developer options or USB debugging after enabling ADB over TCP\\\\\\@.\\n\\\\end{danger}</string>\n    <string name=\"guide$aot$adb-mode-am\">After enabling ADB over TCP, relaunch App Manager. App Manager should detect ADB mode automatically. If it cannot,\\nyou can change the mode of operation to ADB over TCP in the \\\\hyperref[subsec:mode-of-operation]{settings page}.\\nThere, you can also verify whether App Manager has correctly detected ADB as indicated by the \\\\textit{inferred mode}.\\n\\n\\\\begin{tip}{Notice}\\n    In some Android devices, the USB cable is needed to be disconnected from the PC before connecting to App Manager.\\n\\\\end{tip}\\n\\n\\\\begin{warning}{Warning}\\n    ADB over TCP will be disabled after a reboot. In that case, you have to follow \\\\Sref{subsubsec:enable-adb-over-tcp-via-pc-or-mac} again.\\n\\\\end{warning}</string>\n    <string name=\"guide$wireless_debugging$$section-title\">Wireless Debugging</string>\n    <string name=\"guide$wireless_debugging$$enable-developer-options-and-usb-debugging-title\">Enable developer options and USB Debugging</string>\n    <string name=\"guide$wireless_debugging$$enable-wireless-debugging-title\">Enable Wireless Debugging</string>\n    <string name=\"guide$wireless_debugging$$pair-adb-with-appmanager-title\">Pair ADB with App Manager</string>\n    <string name=\"guide$wireless_debugging$$connect-am-to-adb-title\">Connect App Manager to ADB</string>\n    <string name=\"guide$wireless_debugging$intro\">If you are running Android 11 or later and capable of connecting to a Wi-Fi network for, at least, a few moments,\\nWireless Debugging is the recommended approach as it offers more protection than \\\\hyperref[sec:adb-over-tcp]{ADB over TCP}.\\nIt requires two steps:\\n\\\\begin{enumerate}\\n    \\\\item \\\\textbf{ADB pairing.} The initial and a bit complex step for a novice user. Fortunately,\\n    this step is not required all the time.\\n    \\\\item \\\\textbf{Connecting to ADB.} Needs to be done every time you reboot your phone. App Manager\\n    can also automate this step in most devices.\\n\\\\end{enumerate}</string>\n    <string name=\"guide$wireless_debugging$enable-developer-options-and-usb-debugging\">See \\\\Sref{subsec:enable-developer-options} and \\\\Sref{subsec:enable-usb-debugging}.</string>\n    <string name=\"guide$wireless_debugging$enable-wireless-debugging\">In the \\\\textbf{Developer options} page, find \\\\textbf{Wireless debugging} and click to open it. In\\nthe new page, turn on \\\\textit{Use wireless debugging}. Depending on the operating system, you might\\nsee a dialog prompt asking you to verify your decision. If that is the case, click \\\\textit{Allow}.\\n\\n\\\\begin{tip}{Tip}\\n    For easy access, you might want to add \\\\textbf{Wireless debugging} in the notification tiles\\n    section. To do this, find \\\\textbf{Quick settings developer tiles} in the \\\\textbf{Developer\\n    options} page and click to open it. In the new window, enable \\\\textit{Wireless debugging}.\\n    In case you do not see this setting, you may find a \\\\textbf{Wireless debugging} tile in the tile\\n    customization panel.\\n\\\\end{tip}</string>\n    <string name=\"guide$wireless_debugging$pair-adb-with-app-manager\">In App Manager, navigate to \\\\textbf{Settings} &gt; \\\\hyperref[subsec:mode-of-operation]{Mode of operation}\\nand then enable \\\\textit{Wireless debugging}. At this, App Manager will try to establish a wireless\\ndebugging connection automatically which will fail if it has not been paired before. Once it fails,\\nit will ask you to either connect or pair ADB\\\\\\@. Select \\\\textit{pair} and a new dialog will appear.\\nIt will ask you to navigate to the \\\\textbf{Wireless debugging} page.\\n\\n\\\\begin{tip}{Note}\\n    As of v4.0.0, pairing is done using a notification prompt. So, if you have disabled notification\\n    for App Manager, you must enable it first.\\n\\\\end{tip}\\n\\nIn the \\\\textbf{Wireless debugging} page, select \\\\textbf{Pair device with pairing code}. At this, a\\ndialog containing a pairing code will be displayed. A notification asking for the pairing code will\\nalso be visible almost instantly. Insert the pairing code in the input box in the notification\\nand click \\\\textit{pair}. If the pairing is successful, App Manager will display notification with\\nthe message ``paired\\'\\', and the dialog in the \\\\textbf{Wireless debugging} page will be dismissed\\nautomatically. You will also be able to see App Manager listed as an ADB client in the same page.\\n\\n\\\\begin{tip}{Notice}\\n    If you do not use App Manager in ADB mode for a while, App Manager might be removed from the\\n    list of clients. In that case, you have to repeat the above procedure.\\n\\\\end{tip}</string>\n    <string name=\"guide$wireless_debugging$connect-am-to-adb\">App Manager should be able to connect to ADB automatically if the mode of operation is set to\\n\\\\textit{auto}, \\\\textit{ADB over TCP} or \\\\textit{Wireless debugging}. If this is not the case, select\\n\\\\textit{Wireless debugging} in \\\\textbf{Settings} &gt; \\\\hyperref[subsec:mode-of-operation]{Mode of operation}.\\nIf App Manager fails to detect or connect to ADB, it will ask you to connect or pair ADB. Select\\n\\\\textit{connect}.\\n\\nNow, navigate to the \\\\textbf{Wireless debugging} page in Android settings, and note down the port\\nnumber displayed in the page. In App Manager\\'s dialog prompt, replace the port number with the one\\nyou have noted earlier, and click \\\\textit{connect}.\\n\\nOnce a connection has been established, you can disable \\\\textbf{Wireless debugging} in Android settings.\\n\\n\\\\begin{danger}{Caution}\\n    Never disable \\\\textbf{USB Debugging} or any other additional options described in \\\\Sref{subsec:enable-developer-options-and-usb-debugging}.\\n    If you do this, the remote server used by App Manager will be stopped, and you may have to start all over again.\\n\\\\end{danger}</string>\n    <string name=\"guide$backup-restore$$section-title\">Back up/Restore</string>\n    <string name=\"guide$backup-restore$$location-title\">Location</string>\n    <string name=\"guide$backup-restore$$options-title\">Backup Options</string>\n    <string name=\"guide$backup-restore$$backup-title\">Backup</string>\n    <string name=\"guide$backup-restore$$restore-title\">Restore</string>\n    <string name=\"guide$backup-restore$$delete-title\">Delete Backup</string>\n    <string name=\"guide$backup-restore$intro\">App Manager has a modern, advanced and easy-to-use backup/restore system implemented from the scratch.\\nThis is probably the only app that has the ability to restore not only the app or its data but also permissions and\\nrules that you\\'ve configured within App Manager.\\nYou can also choose to back up an app multiple times (with custom names) or for all users.\\n\\n\\\\begin{amseealso}\\n    \\\\item \\\\hyperref[subsec:1-click-back-up]{1-Click Ops: Back up}\\n    \\\\item \\\\hyperref[subsec:1-click-restore]{1-Click Ops: Restore}\\n\\\\end{amseealso}</string>\n    <string name=\"guide$backup-restore$location\">Back up/restore is a part of \\\\hyperref[subsec:batch-operations]{batch operations}.\\nIt is also located inside the \\\\hyperref[subsubsec:app-info-options-menu]{options menu} in the\\n\\\\hyperref[subsec:app-info-tab]{App Info tab}.\\nClicking on \\\\textbf{Backup/Restore} opens the \\\\textbf{Backup Options}.\\nBackups are located at \\\\texttt{/storage/emulated/0/AppManager} by default.\\nYou can configure custom backup location in the \\\\hyperref[subsubsec:backup-volume]{settings page} in which case the backups\\nwill be located at the \\\\texttt{AppManager} folder in the selected volume.\\n\\n\\\\begin{tip}{Note}\\n    If one or more selected apps do not have any backup, the \\\\textbf{Restore} and \\\\textbf{Delete Backup} options will\\n    not be displayed.\\n\\\\end{tip}</string>\n    <string name=\"guide$backup-restore$options\">Backup options (internally known as backup flags) let you customise the backups on the fly.\\nHowever, the customisations will not be remembered for the future backups.\\nIf you want to customise this dialog, use \\\\hyperref[subsubsec:settings-backup-options]{Backup Options} in the \\\\hyperref[sec:settings-page]{Settings page}.\\n\\nA complete description of the backup options is given below:\\n\\\\begin{itemize}\\n    \\\\item \\\\textbf{APK files.} Whether to back up the APK files.\\n    This includes the \\\\textit{base APK} file along with the \\\\texttt{split APK} files if they exist.\\n\\n    \\\\item \\\\textbf{Internal data.} Whether to back up the internal data directories.\\n    These directories are located at \\\\texttt{/data/user/&lt;user\\\\_id&gt;} and (for Android N or later) \\\\texttt{/data/user\\\\_de/&lt;user\\\\_id&gt;}.\\n\\n    \\\\item \\\\textbf{External data.} Whether to back up data directories located in the internal memory as well as SD Card (if exists).\\n    External data directories often contain non-essential app data or media files (instead of using the dedicated media folder) and may increase the backup size.\\n    However, it might be essential for some apps.\\n    Although it isn\\'t checked by default (as it might dramatically increase the size of the backups), you may have to check it in order to ensure a smooth restore of your backups.\\n    \\\\begin{warning}{Caution}\\n        Internal data folders should always be backed up if you are going to back up the external data folders.\\n        However, it could be useful to back up only the external folders if the app in question downloads a lot of assets from the Internet.\\n    \\\\end{warning}\\n\\n    \\\\item \\\\textbf{OBB and media.} Whether to back up or restore the OBB and the media directories located in the\\n    external storage or the SD Card.\\n    This is useful for games and the graphical software which actually use these folders.\\n\\n    \\\\item \\\\textbf{Cache.} Android apps have multiple cache directories located at every data directories (both internal and external).\\n    There are two types of cache: \\\\textbf{cache} and \\\\textbf{code cache}.\\n    Disabling this option excludes both cache directories from all the data directories.\\n    It is generally advised to exclude cache directories since most apps do not clear the cache regularly and usually handled by the OS itself.\\n    Apps such as Telegram may use a very large cache (depending on the storage space) which may dramatically increase the backup size.\\n    When it is disabled, AM also ignores the \\\\textbf{no\\\\_backup} directories.\\n\\n    \\\\item \\\\textbf{Extras.} Backup/restore app permissions, net policy, battery optimization, SSAID, etc., enabled by default.\\n    Note that, blocking rules are applied \\\\textit{after} applying the extras.\\n    So, if an item is present in both places, it will be overwritten (i.e., the one from the blocking rules will be used).\\n\\n    \\\\item \\\\textbf{Rules.} This option lets you back up blocking rules configured within App Manager.\\n    This might come in handy if you have customised permissions or block some components using App Manager as they will\\n    also be backed up or restored when you enable this option.\\n\\n    \\\\item \\\\textbf{Backup Multiple.} Whether this is a multiple backup.\\n    By default, backups are saved using their user ID\\\\\\@.\\n    Enabling this option allows you to create additional backups.\\n    These backups use the current date-time as the default backup name, but you can also specify custom backup name\\n    using the input field displayed when you click on the \\\\textbf{Backup} button.\\n\\n    \\\\item \\\\textbf{Custom users.} Backup or restore for the selected users instead of only the current user.\\n    This option is only displayed if the system has more than one user.\\n\\n    \\\\item \\\\textbf{Skip signature checks.} When taking a backup, checksum of every file (as well as the signing\\n    certificate(s) of the base APK file) is generated and stored in the \\\\texttt{checksums.txt} file.\\n    When you restore the backup, the checksums are generated again and are matched with the checksums stored in the said file.\\n    Enabling this option will disable the signature checks.\\n    This option is applied only when you restore a backup.\\n    During backup, the checksums are generated regardless of this option.\\n    \\\\begin{warning}{Caution}\\n        You should always disable this option to ensure that your backups are not modified by any third-party applications.\\n        However, this would only work if you enabled encryption.\\n    \\\\end{warning}\\n\\\\end{itemize}\\n\\n\\\\seealsoinline{\\\\hyperref[subsubsec:settings-encryption]{Settings: Encryption}}</string>\n    <string name=\"guide$backup-restore$backup\">Backup respects all the backup options except \\\\textbf{Skip signature checks}.\\nIf base backups (i.e., backups that don\\'t have the \\\\textbf{Backup Multiple} option) already exist, you will get a warning as the backups will be overwritten.\\nIf \\\\textbf{Backup Multiple} is set, you have an option to input the backup name, or you can leave it blank to use the current date-time.</string>\n    <string name=\"guide$backup-restore$restore\">Restore respects all the backup options and will fail if \\\\textbf{APK files} option is set, but the backup doesn\\'t\\ncontain such backups or in other cases, if the app isn\\'t installed.\\nWhen restoring backups for multiple packages, you can only restore the base backups (see \\\\hyperref[subsec:backup-restore-backup]{backup} section for an explanation).\\nHowever, when restoring backups for a single package, you have the option to select which backup to restore.\\nIf \\\\textbf{All users} option is set, AM will restore the selected backup for all users in the latter case but in the former case, it will restore base backups for the respective users.\\n\\n\\\\begin{tip}{Notice}\\n    Apps that use storage access framework (SAF), SSAID or Android KeyStore works properly only after an immediate restart.\\n\\\\end{tip}</string>\n    <string name=\"guide$backup-restore$delete\">Delete backup only respects \\\\textbf{All users} option and when it is selected, only the base backups for all users will be deleted with a prompt.\\nWhen deleting backups for a single package, another dialog will be displayed where you can select the backups to delete.</string>\n    <string name=\"guide$automation$$section-title\">Automating Tasks</string>\n    <string name=\"guide$automation$$generating-authorization-key-title\">Generating authorization key</string>\n    <string name=\"guide$automation$$general-configuration-title\">Configuring tasks</string>\n    <string name=\"guide$automation$$required-extras-title\">Required extras</string>\n    <string name=\"guide$automation$$features-title\">Features</string>\n    <string name=\"guide$automation$$triggering-a-profile-title\">Triggering a profile</string>\n    <string name=\"guide$automation$intro\">It is possible to trigger profiles configured inside App Manager via third-party applications such as \\\\textbf{Automation} or \\\\textbf{Tasker}.\\nTraditionally, \\\\texttt{Intent}s are used to trigger such operations.</string>\n    <string name=\"guide$automation$generating-authorization-key\">In order to ensure proper security, an authorization key is required. To generate a authorization key, go to \\\\textbf{Settings} page and then \\\\textbf{Privacy} &gt; \\\\textbf{Authorization Manager}.\\nIf an authorization key has not been generated, it will be generated automatically. The key can be regenerated as required.\\n\\n\\\\begin{danger}{Caution}\\n    Regenerating the authorization key can have some side effects such as invalidation of all the previously configured Intents.\\n\\\\end{danger}</string>\n    <string name=\"guide$automation$general-configuration\">The activity \\\\texttt{io.github.muntashirakon.AppManager.crypto.auth.AuthFeatureDemultiplexer} is responsible for handling all the automations.\\nSending an intent to the activity lets App Manager perform the designated operation by redirecting the \\\\texttt{Intent} to the designated activity or service.</string>\n    <string name=\"guide$automation$required-extras\">It has two primary extras required in all conditions. The key names, data types are all follows:\\n\\\\begin{enumerate}\\n    \\\\item \\\\textbf{\\\\texttt{auth}.} (String value) The authorization key as described in the earlier section.\\n    \\\\item \\\\textbf{\\\\texttt{feature}.} (String value) Name of the feature. Supported features are described in the next section.\\n\\\\end{enumerate}</string>\n    <string name=\"guide$automation$features\">App Manager current support a single feature, namely \\\\texttt{profile}.</string>\n    <string name=\"guide$automation$triggering-a-profile\">In order to trigger a profile, \\\\texttt{feature} must have the value \\\\texttt{profile}. In addition, the following extras can be included:\\n\\\\begin{enumerate}\\n    \\\\item \\\\textbf{\\\\texttt{prof}.} (String value -- required) The name of the profile as displayed in the \\\\hyperref[sec:profiles-page]{Profiles page}.\\n    \\\\item \\\\textbf{\\\\texttt{state}.} (String value -- optional) State of the profile -- currently \\\\texttt{on} or \\\\texttt{off} -- as specified in the documentation.\\n    If this extra is not set, App Manager will display a prompt where a state must be selected. Therefore, for complete automation,\\n    this option should be set.\\n\\\\end{enumerate}</string>\n    <string name=\"guide$net-policy$$section-title\">Net Policy</string>\n    <string name=\"guide$net-policy$intro\">Short for \\\\textbf{Network policy} or network policies.\\nIt is usually located in the Android settings under \\\\textbf{Mobile data \\\\&amp; Wifi} section in the app info page of an app.\\nNot all policies are guaranteed to be included in this page (e.g.\\\\ Samsung), and not all settings are well-understood due to lack of documentation.\\nApp Manager can display all the net policies declared in the \\\\href{https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/net/NetworkPolicyManager.java}{NetworkPolicyManager}.\\nPolicies unknown to App Manager will have a \\\\textit{Unknown} prefix along with the policy constant name and number in the hexadecimal format.\\nUnknown policies should be reported to App Manager for inclusion.\\n\\nNet policy allows a user to configure certain networking behaviour of an app without modifying the ip tables directly and/or running a firewall app.\\nHowever, the features it offers largely depend on Android version and ROM. A list of known net policies are listed below:\\n\\n\\\\begin{enumerate}\\n    \\\\item \\\\textbf{None} or \\\\textbf{\\\\texttt{POLICY\\\\_NONE}}: (AOSP) No specific network policy is set.\\n    System can still assign rules depending on the nature of the app.\\n\\n    \\\\item \\\\textbf{Reject background data on metered networks} or \\\\textbf{\\\\texttt{POLICY\\\\_REJECT\\\\_METERED\\\\_BACKGROUND}}: (AOSP) Reject network usage on metered networks when the application is in background.\\n\\n    \\\\item \\\\textbf{Allow background data on metered networks even when Data Saver is on} or \\\\textbf{\\\\texttt{POLICY\\\\_ALLOW\\\\_METERED\\\\_BACKGROUND}}: (AOSP) Allow metered network use in the background even when data saving mode is enabled.\\n\\n    \\\\item \\\\textbf{Reject cellular data} or \\\\textbf{\\\\texttt{POLICY\\\\_REJECT\\\\_CELLULAR}} (Android 11+) or \\\\textbf{\\\\texttt{POLICY\\\\_REJECT\\\\_ON\\\\_DATA}} (up to Android 10): (Lineage OS) Reject mobile/cellular data.\\n    Signals network unavailable to the configured app as if the mobile data is inactive.\\n\\n    \\\\item \\\\textbf{Reject VPN data} or \\\\textbf{\\\\texttt{POLICY\\\\_REJECT\\\\_VPN}} (Android 11+) or \\\\textbf{\\\\texttt{POLICY\\\\_REJECT\\\\_ON\\\\_VPN}} (up to Android 10): (Lineage OS) Reject VPN data.\\n    Signals network unavailable to the configured app as if the VPN is inactive.\\n\\n    \\\\item \\\\textbf{Reject Wi-Fi data} or \\\\textbf{\\\\texttt{POLICY\\\\_REJECT\\\\_WIFI}} (Android 11+) or \\\\textbf{\\\\texttt{POLICY\\\\_REJECT\\\\_ON\\\\_WLAN}} (up to Android 10): (Lineage OS) Reject Wi-Fi data.\\n    Signals network unavailable to the configured app as if the device is not connected to a Wi-Fi network.\\n\\n    \\\\item \\\\textbf{Disable network access} or \\\\textbf{\\\\texttt{POLICY\\\\_REJECT\\\\_ALL}} (Android 11+) or \\\\textbf{\\\\texttt{POLICY\\\\_NETWORK\\\\_ISOLATED}} (up to Android 10): (Lineage OS) Reject network access in all circumstances.\\n    This is not the same as enforcing the other three policies above, and is the recommended policy for dodgy apps.\\n    If this policy is enforced, there is no need to enforce the other policies.\\n\\n    \\\\item \\\\textbf{\\\\texttt{POLICY\\\\_ALLOW\\\\_METERED\\\\_IN\\\\_ROAMING}}: (Samsung) Possibly allow metered network use during roaming.\\n    Exact meaning is currently unknown.\\n\\n    \\\\item \\\\textbf{\\\\texttt{POLICY\\\\_ALLOW\\\\_WHITELIST\\\\_IN\\\\_ROAMING}}: (Samsung) Possibly allow network use during roaming.\\n    Exact meaning is currently unknown.\\n\\n    \\\\item \\\\textbf{Reject data on metered networks} or \\\\textbf{\\\\texttt{POLICY\\\\_REJECT\\\\_METERED}}: (Motorola) Reject network usage if it is a metered network.\\n\\n    \\\\item \\\\textbf{Reject background data} or \\\\textbf{\\\\texttt{POLICY\\\\_REJECT\\\\_BACKGROUND}}: (Motorola) Reject network usage in the background.\\n\\n    \\\\item \\\\textbf{Disable network access} or \\\\textbf{\\\\texttt{POLICY\\\\_REJECT\\\\_ALL}}: (Motorola) Reject network access altogether.\\n    Like Lineage OS, it blocks internet connections via iptables. But whether it signals the unavailability of network to the configured app is not known.\\n\\\\end{enumerate}\\n\\n\\\\begin{tip}{Note}\\n    Corresponding Lineage OS patches are as follows:\\n    \\\\begin{enumerate}\\n        \\\\item \\\\href{https://github.com/LineageOS/android\\\\_frameworks\\\\_base/commit/a04932bafbbf7d99efd18276152cc2c9c9b2073e}{fw/b: Squash of app fw restriction commits}\\n        \\\\item \\\\href{https://github.com/LineageOS/android\\\\_frameworks\\\\_base/commit/02c8c82854348f52afe2199f310f44b5f578b5b8}{fw/b: Add support for per app network isolation}\\n    \\\\end{enumerate}\\n\\\\end{tip}</string>\n    <string name=\"faq$main$$faq-chapter-title\">Frequently Asked Questions</string>\n    <string name=\"faq$app-components$$section-title\">App Components</string>\n    <string name=\"faq$app-components$$what-are-app-components-title\">What are the application components\\?</string>\n    <string name=\"faq$app-components$$limitations-title\">How are the tracker and other components blocked in App Manager\\? What are its limitations\\?</string>\n    <string name=\"faq$app-components$$other-tools-retained-in-am-title\">Does app components blocked by other tools retained in App Manager\\?</string>\n    <string name=\"faq$app-components$$also-blocked-by-other-tools-title\">What happens to the components blocked by App Manager which were previously blocked by other tools\\?</string>\n    <string name=\"faq$app-components$$what-is-component-blocking-title\">What is instant component blocking\\?</string>\n    <string name=\"faq$app-components$$tracker-classes-versus-tracker-components-title\">Tracker classes versus tracker components</string>\n    <string name=\"faq$app-components$what-are-app-components\">Activities, services, broadcast receivers (or only receivers) and content providers (or only providers) are jointly\\ncalled application components. More technically, they all inherit the\\n\\\\href{https://developer.android.com/reference/android/content/pm/ComponentInfo}{ComponentInfo} class and can be launched\\nvia Intent.</string>\n    <string name=\"faq$app-components$limitations\">App Manager typically blocks application components (or tracker components) using a method called\\n\\\\href{https://carteryagemann.com/pages/android-intent-firewall.html}{Intent Firewall (IFW)}, it is superior to\\nother methods such as \\\\textit{pm} (PackageManager), \\\\href{https://github.com/RikkaApps/Shizuku}{Shizuku} or any other\\nmethod that uses the package manager to enable or disable the components. If a component is disabled by the latter\\nmethods, the application itself can detect that the component is being blocked and can re-enable it as it has full\\naccess to its own components. (Many deceptive applications actually do this in order to keep the tracker components\\nunblocked.) On the other hand, IFW is a true firewall and the application cannot detect if its components are being\\nblocked. App Manager uses the term \\\\textit{block} rather than \\\\textit{disable} for this reason.\\n\\nEven IFW has some limitations which are primarily applicable for the system applications:\\n\\\\begin{itemize}\\n    \\\\item The application in question is whitelisted by the system i.e.\\\\ the system cannot function properly without\\n    these applications and may cause random crashes. These applications include but not limited to Android System,\\n    System UI, Phone Services. They will continue to work even if they are disabled or blocked.\\n\\n    \\\\item Another system application or system process has activated a specific component of the application in question\\n    via interprocess communication (IPC). In this case, the component will be activated regardless of blocking status or\\n    even if the entire application is disabled. If there is such a system application that is not needed, the only way\\n    to prevent it from running is by getting rid of it.\\n\\\\end{itemize}</string>\n    <string name=\"faq$app-components$other-tools-retained-in-am\">\\\\textbf{No.} But the application components blocked by the system or any other tools are displayed in the\\n\\\\hyperref[subsec:component-tabs]{component tabs}. These rules can be imported from \\\\hyperref[par:import-existing-rules]{Settings}.\\nHowever, it is not possible for App Manager to distinguish the components blocked by the third-party tools and\\ncomponents blocked by the system. Therefore, the applications listed in the import page should be selected with care.</string>\n    <string name=\"faq$app-components$also-blocked-by-other-tools\">\\\\textit{App Manager blocks the components again} if requested. In case of unblocking, they will be reverted to the\\ndefault state as specified in the manifest of the application. But if the components were blocked by\\n\\\\href{https://www.myandroidtools.com}{MyAndroidTools (MAT)} with IFW method, they will not be unblocked by App Manager\\nas it uses a different format. To fix this issue, the rules have to be imported from \\\\hyperref[par:import-existing-rules]{Settings}\\nat first, in which case MAT\\'s configurations will be permanently removed.</string>\n    <string name=\"faq$app-components$what-is-component-blocking\">When you block a component in the \\\\hyperref[sec:app-details-page]{App Details page}, the blocking is not applied by\\ndefault. It is only applied when you apply blocking using the \\\\textit{Apply rules} option in the top-right menu. If you\\nenable \\\\hyperref[subsubsec:instant-component-blocking]{instant component blocking}, blocking will be applied as soon as you block a component.\\nIf you choose to block tracker components, however, blocking is applied automatically regardless of this setting.\\nYou can also remove blocking for an application by simply clicking on \\\\textit{Remove rules} in the same menu in the \\\\textbf{App Details page}.\\nSince the default behaviour gives you more control over applications, it is better to keep \\\\textit{instant component blocking} option disabled.</string>\n    <string name=\"faq$app-components$tracker-classes-versus-tracker-components\">All application components are classes but not all classes are components. In fact, only a few of the classes are components.\\nThat being said, \\\\hyperref[sec:scanner-page]{scanner page} displays a list of trackers along with the number of classes,\\nnot just the components. In all other pages, trackers and tracker components are used synonymously to denote tracker\\ncomponents, i.e.\\\\ blocking tracker means blocking tracker components, not tracker classes.\\n\\n\\\\begin{tip}{Info}\\n    Tracker classes that are not components cannot be blocked. They can only be removed by editing the application itself.\\n\\\\end{tip}</string>\n    <string name=\"faq$aot$$section-title\">ADB over TCP</string>\n    <string name=\"faq$aot$$restart-title\">Do I have to enable ADB over TCP everytime I restart\\?</string>\n    <string name=\"faq$aot$$usb-debugging-title\">Cannot enable USB debugging. What to do\\?</string>\n    <string name=\"faq$aot$$block-tracker-title\">Can I block tracker or any other application components using ADB over TCP\\?</string>\n    <string name=\"faq$aot$$feature-adb-title\">Which features can be used in ADB mode\\?</string>\n    <string name=\"faq$aot$restart\">Unfortunately, yes. This is because the ADB daemon, the process responsible for ADB connection, is also restarted after\\na reboot, and it does not re-enable ADB over TCP\\\\\\@.</string>\n    <string name=\"faq$aot$usb-debugging\">See \\\\Sref{subsec:enable-usb-debugging} in \\\\Cref{ch:guides}.</string>\n    <string name=\"faq$aot$block-tracker\">ADB has limited number of \\\\href{https://github.com/aosp-mirror/platform_frameworks_base/blob/master/packages/Shell/AndroidManifest.xml}{permissions}\\nand controlling application components is not one of them. However, the components of a \\\\textit{test-only} app can be\\ncontrolled via ADB\\\\\\@. If App Manager detects such an application, it enables the blocking options automatically.</string>\n    <string name=\"faq$aot$feature-adb\">Supported features are enabled automatically in the ADB mode. Supported features include disabling, force-stopping,\\nclearing application data, granting or revoking app ops and permissions, and so on. It is also possible to install or\\nuninstall applications without any prompt from the system.</string>\n    <string name=\"faq$misc$$section-title\">Miscellanea</string>\n    <string name=\"faq$misc$$i-dont-use-root-adb-title\">I don\\'t use root/ADB. Am I completely safe from any harms\\?</string>\n    <string name=\"faq$misc$$how-tracker-updated-title\">How are the trackers and libraries are updated\\?</string>\n    <string name=\"faq$misc$$apks-deleted-after-installed\">Are APKs deleted after installed\\?</string>\n    <string name=\"faq$misc$$shizuku-title\">Any plans for Shizuku\\?</string>\n    <string name=\"faq$misc$$bloatware-title\">What are bloatware and how to remove them\\?</string>\n    <string name=\"faq$misc$i-dont-use-root-adb\">Yes. AM cannot modify any system settings without root or ADB\\\\\\@.</string>\n    <string name=\"faq$misc$how-tracker-updated\">Trackers and libraries are updated manually before making a new release.</string>\n    <string name=\"faq$misc$apks-deleted-after-installed\">No, APKs aren\\'t deleted by App Manager after they are installed.</string>\n    <string name=\"faq$misc$shizuku\">App Manager\\'s use of hidden API and privileged code execution is now much more complex and cannot be integrated with\\nother third party apps such as \\\\href{https://shizuku.rikka.app}{Shizuku}. Here are some reasons for not considering\\nShizuku (which now has Apache 2.0 license) for App Manager:\\n\\\\begin{enumerate}\\n    \\\\item Shizuku was initially non-free which led me to use a similar approach for App Manager to support both root\\n    and ADB\\n    \\\\item App Manager already supports both ADB and root which in some cases is more capable than Shizuku\\n    \\\\item Relying on a third-party app for the major functionalities is not a good design choice\\n    \\\\item Integration of Shizuku will increase the complexity of App Manager.\\n\\\\end{enumerate}</string>\n    <string name=\"faq$misc$bloatware\">Bloatware are the unnecessary pre-installed apps, usually system apps. Some of the apps are often\\nused to track users and collect user data which they might sell for profits. Many system apps do not\\nneed to request any permission to access device info, contacts and messaging data, and other usage\\ninfo, such as your phone usage habits and everything you store on your shared storage(s).\\n\\nThe bloatware may also include Google apps, Meta apps, and Twitter/X which can also track users\\nand/or collect user data without consent. You can disable a few permissions from Android settings\\nbut be aware that Android settings hides many permissions a security researcher would call\\npotentially \\\\emph{dangerous} (e.g., internet, sensor).\\n\\nWere the bloatware user apps, they could be easily uninstalled either from Android settings or AM\\\\\\@.\\nUninstalling system apps is not possible without privileged permission, but even then, it cannot\\n\\\\emph{remove} the system apps completely as they are located in the \\\\emph{system} partition which is\\na read-only partition. If you have root, you can remount this partition to manually \\\\emph{purge}\\nthese apps but this will break Over the Air (OTA) updates since data in the system partition has\\nbeen modified. There are two kind of updates, delta (small-size, consisting of only the changes\\nbetween two versions) and full updates. You may still be able to apply full updates, but the\\nbloatware will be installed again, and consequently, you have to delete them all over again.\\n\\nAnother solution is to disable these apps either from Android settings or AM, but certain services\\ncan still run in the background as they can be started by other system apps using Inter-process\\nCommunication (IPC). One possible solution is to disable all bloatware until the service has finally\\nstopped (after a restart). However, due to heavy modifications of the Android frameworks by the\\nvendors, removing or disabling certain bloatware may cause the System UI to crash or even cause\\nbootloop. From v4.0.0, AM has a new feature called \\\\textbf{Debloater} which can be used as a\\nstarting point to monitor, disable, and remove the bloatware from a proprietary Android operating\\nsystem.\\n\\n\\\\begin{warning}{Note}\\n    In most cases, you cannot completely debloat your device. Therefore, it is recommended that you\\n    use a custom ROM free from bloatware, such as Graphene OS, Lineage OS or their derivatives.\\n\\\\end{warning}</string>\n    <string name=\"appendices$specifications$$chapter-title\">Specifications</string>\n    <string name=\"appendices$specifications$$rules-specification-title\">Rules Specification</string>\n    <string name=\"appendices$specifications$$background-title\">Background</string>\n    <string name=\"appendices$specifications$$rules-file-format-title\">Rules File Format</string>\n    <string name=\"appendices$specifications$$internal-title\">Internal</string>\n    <string name=\"appendices$specifications$$external-title\">External</string>\n    <string name=\"appendices$specifications$background\">AM currently supports blocking activities, broadcast receivers, content providers, services, app ops and permissions,\\nand in future I may add more blocking options. In order to add more portability, it is necessary to import/export all\\nthese data.\\n\\nMaintaining a database should be the best choice when it comes to storing data. For now, several \\\\texttt{tsv} files\\nwith each file having the name of the package and a \\\\texttt{.tsv} extension. The file/database will be queried/processed\\nby the \\\\texttt{RulesStorageManager} class. Due to this abstraction, it should be easier to switch to database or\\nencrypted database systems in future without changing the design of the entire project. Currently, All configuration\\nfiles are stored at \\\\texttt{/data/data/io.github.muntashirakon.AppManager/Files/conf}.</string>\n    <string name=\"appendices$specifications$internal\">The format below is used internally within App Manager and is \\\\textit{not compatible with the external format.}\\n\\\\begin{Verbatim}\\n    &lt;name&gt; &lt;type&gt; &lt;mode&gt;|&lt;component_status&gt;|&lt;is_granted&gt;\\n\\\\end{Verbatim}\\nHere:\\n\\\\begin{itemize}\\n    \\\\item \\\\texttt{&lt;name&gt;} -- Component/permission/app op name (in case of app op, it could be string or integer)\\n    \\\\item \\\\texttt{&lt;type&gt;} -- One of the \\\\texttt{ACTIVITY}, \\\\texttt{RECEIVER}, \\\\texttt{PROVIDER}, \\\\texttt{SERVICE},\\n    \\\\texttt{APP\\\\_OP},  \\\\texttt{PERMISSION}\\n    \\\\item \\\\texttt{&lt;mode&gt;} -- (For app ops) The associated \\\\hyperref[subsec:mode-constants]{mode constant}\\n    \\\\item \\\\texttt{&lt;component\\\\_status&gt;} -- (For components) Component status\\n    \\\\begin{itemize}\\n        \\\\item \\\\texttt{true} -- Component has been applied (\\\\texttt{true} value is kept for compatibility)\\n        \\\\item \\\\texttt{false} -- Component hasn\\'t been applied yet, but will be applied in future (\\\\texttt{false} value\\n        is kept for compatibility)\\n        \\\\item \\\\texttt{unblocked} -- Component is scheduled to be unblocked\\n    \\\\end{itemize}\\n    \\\\item \\\\texttt{&lt;is\\\\_granted&gt;} -- (For permissions) Whether the permission is granted or revoked\\n\\\\end{itemize}</string>\n    <string name=\"appendices$specifications$external\">External format is used for importing or exporting rules in App Manager.\\n\\\\begin{Verbatim}\\n    &lt;package_name&gt; &lt;component_name&gt; &lt;type&gt; &lt;mode&gt;|&lt;component_status&gt;|&lt;is_granted&gt;\\n\\\\end{Verbatim}\\nThis the format is essentially the same as above except for the first item which is the name of the package.\\n\\n\\\\begin{danger}{Caution}\\n    The exported rules have a different format than the internal one and should not be copied directly to the\\n    \\\\textbf{conf} folder.\\n\\\\end{danger}</string>\n    <string name=\"appendices$changelogs$$chapter-title\">Changelogs</string>\n</resources>\n"
  },
  {
    "path": "docs/raw/en/titlepage.tex",
    "content": "% SPDX-License-Identifier: GPL-3.0-or-later OR CC-BY-SA-4.0\n% po4a: environment titlingpage\n\\begin{titlingpage}\n    \\pagecolor{SunTan}\n    \\begin{center}\n        \\includegraphics[width=1in]{../images/icon}\\par\\vspace{1cm}\n        {\\Huge\\textbf{\\textsc{App Manager}}\\par}\n        \\vspace{2.5cm}\n%%!!user_manual<<\n        {\\huge\\bfseries User Manual\\par}\n%%!!>>\n        \\vspace{.5cm}\n        {\\Large\\itshape\\version\\par}\n        \\vfill\n        {\\large\\today\\par}\n        \\vfill\n        {Copyright \\copyright\\ 2020--2025 Muntashir Al-Islam\\par}\n        \\pagebreak\n        \\pagecolor{white}\n%%!!quotation<<\n        \\begin{quotation}\n            ``Wisely and slow. They stumble that run fast.''\n            %\\sourceatright\n                {--- Friar Laurence, \\textit{Romeo and Juliet}}\n        \\end{quotation}\n%%!!>>\n    \\end{center}\n\\end{titlingpage}\n"
  },
  {
    "path": "docs/raw/es/index.html",
    "content": "<!doctype html><html xmlns=http://www.w3.org/1999/xhtml lang=es xml:lang=es><meta charset=utf-8><meta name=generator content=\"pandoc\"><meta name=viewport content=\"width=device-width,initial-scale=1,user-scalable=yes\"><meta name=author content=\"Muntashir Al-Islam\"><title>App Manager</title><style>code{white-space:pre-wrap}span.smallcaps{font-variant:small-caps}div.columns{display:flex;gap:min(4vw,1.5em)}div.column{flex:auto;overflow-x:auto}div.hanging-indent{margin-left:1.5em;text-indent:-1.5em}ul.task-list[class]{list-style:none}ul.task-list li input[type=checkbox]{font-size:inherit;width:.8em;margin:0 .8em .2em -1.6em;vertical-align:middle}.display.math{display:block;text-align:center;margin:.5rem auto}html{-webkit-text-size-adjust:100%}pre>code.sourceCode{white-space:pre;position:relative}pre>code.sourceCode>span{display:inline-block;line-height:1.25}pre>code.sourceCode>span:empty{height:1.2em}.sourceCode{overflow:visible}code.sourceCode>span{color:inherit;text-decoration:inherit}div.sourceCode{margin:1em 0}pre.sourceCode{margin:0}@media screen{div.sourceCode{overflow:auto}}@media print{pre>code.sourceCode{white-space:pre-wrap}pre>code.sourceCode>span{text-indent:-5em;padding-left:5em}}pre.numberSource code{counter-reset:source-line 0}pre.numberSource code>span{position:relative;left:-4em;counter-increment:source-line}pre.numberSource code>span>a:first-child::before{content:counter(source-line);position:relative;left:-1em;text-align:right;vertical-align:baseline;border:none;display:inline-block;-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;padding:0 4px;width:4em}pre.numberSource{margin-left:3em;padding-left:4px}div.sourceCode{}@media screen{pre>code.sourceCode>span>a:first-child::before{text-decoration:underline}}code span.al{font-weight:700}code span.an{font-style:italic}code span.cf{font-weight:700}code span.co{font-style:italic}code span.cv{font-style:italic}code span.do{font-style:italic}code span.dt{text-decoration:underline}code span.er{font-weight:700}code span.in{font-style:italic}code span.kw{font-weight:700}code span.pp{font-weight:700}code span.wa{font-style:italic}</style><link rel=stylesheet href=../css/custom.css><header id=title-block-header><h1 class=title>App Manager</h1><p class=author>Muntashir Al-Islam</header><nav id=TOC role=doc-toc><ul class=incremental><li><span><span class=toc-section-number>1</span> <a href=#ch:introduction id=toc:ch:introduction>Introducción</a></span><ul class=incremental><li><span><span class=toc-section-number>1.1</span> <a href=#sec:terminologies id=toc:sec:terminologies>Terminología</a></span><li><span><span class=toc-section-number>1.2</span> <a href=#sec:supported-versions id=toc:sec:supported-versions>Versiones\nsoportadas</a></span><li><span><span class=toc-section-number>1.3</span> <a href=#sec:official-sources id=toc:sec:official-sources>Fuentes\noficiales</a></span><ul class=incremental><li><span><span class=toc-section-number>1.3.1</span> <a href=#subsec:binary-distribution-sources id=toc:subsec:binary-distribution-sources>Fuentes de distribución\nbinaria</a></span><li><span><span class=toc-section-number>1.3.2</span> <a href=#subsec:links-to-source-code id=toc:subsec:links-to-source-code>Enlaces al código\nfuente</a></span><li><span><span class=toc-section-number>1.3.3</span> <a href=#subsec:translations id=toc:subsec:translations>Traducciones</a></span></ul><li><span><span class=toc-section-number>1.4</span> <a href=#sec:contributing id=toc:sec:contributing>Contribuyendo</a></span><ul class=incremental><li><span><span class=toc-section-number>1.4.1</span> <a href=#subsec:build-instructions id=toc:subsec:build-instructions>Instrucciones de\nconstrucción</a></span><li><span><span class=toc-section-number>1.4.2</span> <a href=#subsec:submitting-patches id=toc:subsec:submitting-patches>Envío de parches</a></span></ul><li><span><span class=toc-section-number>1.5</span> <a href=#sec:donation-&-funding id=toc:sec:donation-&-funding>Donación y\nFinanciamiento</a></span><li><span><span class=toc-section-number>1.6</span> <a href=#sec:contact id=toc:sec:contact>Contacto</a></span></ul><li><span><span class=toc-section-number>2</span> <a href=#ch:pages id=toc:ch:pages>Páginas</a></span><ul class=incremental><li><span><span class=toc-section-number>2.1</span> <a href=#sec:main-page id=toc:sec:main-page>Página principal</a></span><ul class=incremental><li><span><span class=toc-section-number>2.1.1</span> <a href=#subsec:batch-operations id=toc:subsec:batch-operations>Operaciones por lotes</a></span><li><span><span class=toc-section-number>2.1.2</span> <a href=#subsec:main-colour-codes id=toc:subsec:main-colour-codes>Códigos de color</a></span><li><span><span class=toc-section-number>2.1.3</span> <a href=#subsec:main-page-application-types id=toc:subsec:main-page-application-types>Tipos de\naplicación</a></span><li><span><span class=toc-section-number>2.1.4</span> <a href=#subsec:main-page-version-info id=toc:subsec:main-page-version-info>Información sobre la\nversión</a></span><li><span><span class=toc-section-number>2.1.5</span> <a href=#subsec:main-page-options-menu id=toc:subsec:main-page-options-menu>Opciones de menú</a></span></ul><li><span><span class=toc-section-number>2.2</span> <a href=#sec:app-details-page id=toc:sec:app-details-page>Página de\ndetalles de la aplicación</a></span><ul class=incremental><li><span><span class=toc-section-number>2.2.1</span> <a href=#subsec:app-details-colour-codes id=toc:subsec:app-details-colour-codes>Código de color</a></span><li><span><span class=toc-section-number>2.2.2</span> <a href=#subsec:app-info-tab id=toc:subsec:app-info-tab>Pestañas de\ninformación de la aplicación</a></span><li><span><span class=toc-section-number>2.2.3</span> <a href=#subsec:component-tabs id=toc:subsec:component-tabs>Pestañas de\ncomponentes</a></span><li><span><span class=toc-section-number>2.2.4</span> <a href=#subsec:permission-tabs id=toc:subsec:permission-tabs>Pestañas\nde permisos</a></span><li><span><span class=toc-section-number>2.2.5</span> <a href=#subsec:signatures-tab id=toc:subsec:signatures-tab>Pestañas de\nfirmas</a></span><li><span><span class=toc-section-number>2.2.6</span> <a href=#subsec:uses-features-tab id=toc:subsec:uses-features-tab>Uses\nFeatures tab</a></span><li><span><span class=toc-section-number>2.2.7</span> <a href=#subsec:configurations-tab id=toc:subsec:configurations-tab>Configurations tab</a></span><li><span><span class=toc-section-number>2.2.8</span> <a href=#subsec:shared-libs-tab id=toc:subsec:shared-libs-tab>Shared\nLibraries Tab</a></span></ul><li><span><span class=toc-section-number>2.3</span> <a href=#sec:1-click-ops-page id=toc:sec:1-click-ops-page>Página de\noperaciones con 1 clic</a></span><ul class=incremental><li><span><span class=toc-section-number>2.3.1</span> <a href=#subsec:block-unblock-trackers id=toc:subsec:block-unblock-trackers>Bloquear/desbloquear\nrastreadores</a></span><li><span><span class=toc-section-number>2.3.2</span> <a href=#subsec:block-components-dots id=toc:subsec:block-components-dots>Componentes de\nbloque</a></span><li><span><span class=toc-section-number>2.3.3</span> <a href=#subsec:set-mode-for-app-ops-dots id=toc:subsec:set-mode-for-app-ops-dots>Set Mode for App\nOps…</a></span><li><span><span class=toc-section-number>2.3.4</span> <a href=#subsec:1-click-back-up id=toc:subsec:1-click-back-up>Apoyar</a></span><li><span><span class=toc-section-number>2.3.5</span> <a href=#subsec:1-click-restore id=toc:subsec:1-click-restore>Restaurar</a></span><li><span><span class=toc-section-number>2.3.6</span> <a href=#subsec:trim-caches-in-all-apps id=toc:subsec:trim-caches-in-all-apps>Trim Caches in All\nApps</a></span></ul><li><span><span class=toc-section-number>2.4</span> <a href=#sec:profiles-page id=toc:sec:profiles-page>Página de\nperfiles</a></span><ul class=incremental><li><span><span class=toc-section-number>2.4.1</span> <a href=#subsec:profiles-options-menu id=toc:subsec:profiles-options-menu>Opciones de menú</a></span></ul><li><span><span class=toc-section-number>2.5</span> <a href=#sec:profile-page id=toc:sec:profile-page>Página de\nperfil</a></span><ul class=incremental><li><span><span class=toc-section-number>2.5.1</span> <a href=#subsec:profile-options-menu id=toc:subsec:profile-options-menu>Opciones de menú</a></span><li><span><span class=toc-section-number>2.5.2</span> <a href=#subsec:profile-apps-tab id=toc:subsec:profile-apps-tab>Pestaña\nde aplicaciones</a></span><li><span><span class=toc-section-number>2.5.3</span> <a href=#subsec:profile-configurations-tab id=toc:subsec:profile-configurations-tab>Pestaña de\nconfiguraciones</a></span></ul><li><span><span class=toc-section-number>2.6</span> <a href=#sec:settings-page id=toc:sec:settings-page>Página de\nconfiguraciones</a></span><ul class=incremental><li><span><span class=toc-section-number>2.6.1</span> <a href=#subsec:language id=toc:subsec:language>Idioma</a></span><li><span><span class=toc-section-number>2.6.2</span> <a href=#subsec:appearance id=toc:subsec:appearance>Appearance</a></span><li><span><span class=toc-section-number>2.6.3</span> <a href=#subsec:privacy id=toc:subsec:privacy>Privacy</a></span><li><span><span class=toc-section-number>2.6.4</span> <a href=#subsec:mode-of-operation id=toc:subsec:mode-of-operation>Modo\nde operación</a></span><li><span><span class=toc-section-number>2.6.5</span> <a href=#subsec:apk-signing id=toc:subsec:apk-signing>Firma de\nAPK</a></span><li><span><span class=toc-section-number>2.6.6</span> <a href=#subsec:installer id=toc:subsec:installer>Instalador</a></span><li><span><span class=toc-section-number>2.6.7</span> <a href=#subsec:backup/restore id=toc:subsec:backup/restore>Copia de\nseguridad/restaurar</a></span><li><span><span class=toc-section-number>2.6.8</span> <a href=#subsec:rules id=toc:subsec:rules>Reglas</a></span><li><span><span class=toc-section-number>2.6.9</span> <a href=#subsec:advanced id=toc:subsec:advanced>Advanced</a></span><li><span><span class=toc-section-number>2.6.10</span> <a href=#subsec:device-info id=toc:subsec:device-info>Sobre este\ndispositivo</a></span></ul><li><span><span class=toc-section-number>2.7</span> <a href=#sec:scanner-page id=toc:sec:scanner-page>Página del\nescáner</a></span><li><span><span class=toc-section-number>2.8</span> <a href=#sec:interceptor-page id=toc:sec:interceptor-page>Página del\ninterceptor</a></span><ul class=incremental><li><span><span class=toc-section-number>2.8.1</span> <a href=#subsec:intent-filters id=toc:subsec:intent-filters>Filtros de\nintención</a></span><li><span><span class=toc-section-number>2.8.2</span> <a href=#subsec:matching-activities id=toc:subsec:matching-activities>Actividades de\nemparejamiento</a></span><li><span><span class=toc-section-number>2.8.3</span> <a href=#subsec:interceptor-reset-to-default id=toc:subsec:interceptor-reset-to-default>Resetear a valores por\ndefecto</a></span><li><span><span class=toc-section-number>2.8.4</span> <a href=#subsec:interceptor-send-edited-intent id=toc:subsec:interceptor-send-edited-intent>Enviar intención\neditada</a></span></ul><li><span><span class=toc-section-number>2.9</span> <a href=#sec:shared-preferences-editor-page id=toc:sec:shared-preferences-editor-page>Página del editor de\npreferencias compartidas</a></span></ul><li><span><span class=toc-section-number>3</span> <a href=#ch:guides id=toc:ch:guides>Guías</a></span><ul class=incremental><li><span><span class=toc-section-number>3.1</span> <a href=#sec:adb-over-tcp id=toc:sec:adb-over-tcp>ABD sobre\nTCP</a></span><ul class=incremental><li><span><span class=toc-section-number>3.1.1</span> <a href=#subsec:enable-developer-options id=toc:subsec:enable-developer-options>Habilitar opciones de\ndesarrollador</a></span><li><span><span class=toc-section-number>3.1.2</span> <a href=#subsec:enable-usb-debugging id=toc:subsec:enable-usb-debugging>Habilitar depuración\nUSB</a></span><li><span><span class=toc-section-number>3.1.3</span> <a href=#subsec:setup-adb-on-pc-or-mac id=toc:subsec:setup-adb-on-pc-or-mac>Configurar ADB en PC o\nMac</a></span><li><span><span class=toc-section-number>3.1.4</span> <a href=#subsec:configure-adb-over-tcp id=toc:subsec:configure-adb-over-tcp>Configurar ADB sobre\nTCP</a></span></ul><li><span><span class=toc-section-number>3.2</span> <a href=#sec:wireless-debugging id=toc:sec:wireless-debugging>Wireless\nDebugging</a></span><ul class=incremental><li><span><span class=toc-section-number>3.2.1</span> <a href=#subsec:enable-developer-options-and-usb-debugging id=toc:subsec:enable-developer-options-and-usb-debugging>Enable\ndeveloper options and USB Debugging</a></span><li><span><span class=toc-section-number>3.2.2</span> <a href=#subsec:enable-wireless-debugging id=toc:subsec:enable-wireless-debugging>Enable Wireless\nDebugging</a></span><li><span><span class=toc-section-number>3.2.3</span> <a href=#subsec:pair-adb-with-app-manager id=toc:subsec:pair-adb-with-app-manager>Pair ADB with App\nManager</a></span><li><span><span class=toc-section-number>3.2.4</span> <a href=#subsec:connect-app-manager-to-adb id=toc:subsec:connect-app-manager-to-adb>Connect App Manager to\nADB</a></span></ul><li><span><span class=toc-section-number>3.3</span> <a href=#sec:backup-restore id=toc:sec:backup-restore>Back\nup/Restore</a></span><ul class=incremental><li><span><span class=toc-section-number>3.3.1</span> <a href=#subsec:backup-location id=toc:subsec:backup-location>Location</a></span><li><span><span class=toc-section-number>3.3.2</span> <a href=#subsec:backup-restore-backup-options id=toc:subsec:backup-restore-backup-options>Backup\nOptions</a></span><li><span><span class=toc-section-number>3.3.3</span> <a href=#subsec:backup-restore-backup id=toc:subsec:backup-restore-backup>Backup</a></span><li><span><span class=toc-section-number>3.3.4</span> <a href=#subsec:backup-restore-restore id=toc:subsec:backup-restore-restore>Restore</a></span><li><span><span class=toc-section-number>3.3.5</span> <a href=#subsec:backup-restore-delete-backup id=toc:subsec:backup-restore-delete-backup>Delete\nBackup</a></span></ul><li><span><span class=toc-section-number>3.4</span> <a href=#sec:automating-tasks id=toc:sec:automating-tasks>Automating\nTasks</a></span><ul class=incremental><li><span><span class=toc-section-number>3.4.1</span> <a href=#subsec:generating-authorization-key id=toc:subsec:generating-authorization-key>Generating authorization\nkey</a></span><li><span><span class=toc-section-number>3.4.2</span> <a href=#subsec:at:general-configuration id=toc:subsec:at:general-configuration>Configuring\ntasks</a></span><li><span><span class=toc-section-number>3.4.3</span> <a href=#subsec:at:features id=toc:subsec:at:features>Features</a></span><li><span><span class=toc-section-number>3.4.4</span> <a href=#subsec:triggering-a-profile id=toc:subsec:triggering-a-profile>Triggering a\nprofile</a></span></ul><li><span><span class=toc-section-number>3.5</span> <a href=#sec:net-policy id=toc:sec:net-policy>Net\nPolicy</a></span></ul><li><span><span class=toc-section-number>4</span> <a href=#ch:faq id=toc:ch:faq>Frequently Asked Questions</a></span><ul class=incremental><li><span><span class=toc-section-number>4.1</span> <a href=#sec:faq:app-components id=toc:sec:faq:app-components>App\nComponents</a></span><ul class=incremental><li><span><span class=toc-section-number>4.1.1</span> <a href=#subsec:faq:what-are-app-components id=toc:subsec:faq:what-are-app-components>What are the application\ncomponents?</a></span><li><span><span class=toc-section-number>4.1.2</span> <a href=#subsec:faq:how-components-blocked id=toc:subsec:faq:how-components-blocked>How are the tracker and other\ncomponents blocked in App Manager? What are its\nlimitations?</a></span><li><span><span class=toc-section-number>4.1.3</span> <a href=#subsec:faq:components-blocked-by-others id=toc:subsec:faq:components-blocked-by-others>Does app components\nblocked by other tools retained in App Manager?</a></span><li><span><span class=toc-section-number>4.1.4</span> <a href=#subsec:faq:components-reblocked-in-am id=toc:subsec:faq:components-reblocked-in-am>What happens to the\ncomponents blocked by App Manager which were previously blocked by other\ntools?</a></span><li><span><span class=toc-section-number>4.1.5</span> <a href=#subsec:faq:what-is-instant-component-blocking id=toc:subsec:faq:what-is-instant-component-blocking>What is instant\ncomponent blocking?</a></span><li><span><span class=toc-section-number>4.1.6</span> <a href=#subsec:tracker-classes-versus-tracker-components id=toc:subsec:tracker-classes-versus-tracker-components>Tracker\nclasses versus tracker components</a></span></ul><li><span><span class=toc-section-number>4.2</span> <a href=#sec:faq:adb-over-tcp id=toc:sec:faq:adb-over-tcp>ADB over\nTCP</a></span><ul class=incremental><li><span><span class=toc-section-number>4.2.1</span> <a href=#subsec:faq:enable-adb-on-every-restart id=toc:subsec:faq:enable-adb-on-every-restart>Do I have to enable ADB\nover TCP everytime I restart?</a></span><li><span><span class=toc-section-number>4.2.2</span> <a href=#subsec:faq:usb-debugging id=toc:subsec:faq:usb-debugging>Cannot enable USB debugging. What to\ndo?</a></span><li><span><span class=toc-section-number>4.2.3</span> <a href=#subsec:faq:block-components-using-adb id=toc:subsec:faq:block-components-using-adb>Can I block tracker or\nany other application components using ADB over TCP?</a></span><li><span><span class=toc-section-number>4.2.4</span> <a href=#subsec:faq:adb-features id=toc:subsec:faq:adb-features>Which\nfeatures can be used in ADB mode?</a></span></ul><li><span><span class=toc-section-number>4.3</span> <a href=#sec:faq:miscellanea id=toc:sec:faq:miscellanea>Miscellanea</a></span><ul class=incremental><li><span><span class=toc-section-number>4.3.1</span> <a href=#subsec:faq:no-root-no-harms id=toc:subsec:faq:no-root-no-harms>I don’t use root/ADB. Am I\ncompletely safe from any harms?</a></span><li><span><span class=toc-section-number>4.3.2</span> <a href=#subsec:faq:how-trackers-libs-updated id=toc:subsec:faq:how-trackers-libs-updated>How are the trackers and\nlibraries are updated?</a></span><li><span><span class=toc-section-number>4.3.3</span> <a href=#subsec:faq:apks-deleted-after-installed id=toc:subsec:faq:apks-deleted-after-installed>Are APKs deleted after\ninstalled?</a></span><li><span><span class=toc-section-number>4.3.4</span> <a href=#subsec:faq:shizuku-support id=toc:subsec:faq:shizuku-support>Any plans for\nShizuku?</a></span><li><span><span class=toc-section-number>4.3.5</span> <a href=#subsec:faq:what-are-bloatware id=toc:subsec:faq:what-are-bloatware>What are bloatware and how to\nremove them?</a></span></ul></ul><li><span><span class=toc-section-number>5</span> <a href=#ch:specifications id=toc:ch:specifications>Specifications</a></span><ul class=incremental><li><span><span class=toc-section-number>5.1</span> <a href=#sec:rules-specification id=toc:sec:rules-specification>Rules\nSpecification</a></span><ul class=incremental><li><span><span class=toc-section-number>5.1.1</span> <a href=#background id=toc:background>Background</a></span><li><span><span class=toc-section-number>5.1.2</span> <a href=#rules-file-format id=toc:rules-file-format>Rules File\nFormat</a></span></ul></ul><li><span><span class=toc-section-number>6</span> <a href=#ch:changelogs id=toc:ch:changelogs>Registros de\ncambios</a></span><ul class=incremental><li><span><span class=toc-section-number>6.1</span> <a href=#sec:v4.0.5-(445) id=toc:sec:v4.0.5-(445)>v4.0.5\n(445)</a></span><li><span><span class=toc-section-number>6.2</span> <a href=#sec:v4.0.4-(444) id=toc:sec:v4.0.4-(444)>v4.0.4\n(444)</a></span><li><span><span class=toc-section-number>6.3</span> <a href=#sec:v4.0.3-(443) id=toc:sec:v4.0.3-(443)>v4.0.3\n(443)</a></span><li><span><span class=toc-section-number>6.4</span> <a href=#sec:v4.0.2-(442) id=toc:sec:v4.0.2-(442)>v4.0.2\n(442)</a></span><li><span><span class=toc-section-number>6.5</span> <a href=#sec:v4.0.1-(441) id=toc:sec:v4.0.1-(441)>v4.0.1\n(441)</a></span><ul class=incremental><li><span><span class=toc-section-number>6.5.1</span> <a href=#overlay-management id=toc:overlay-management>Overlay\nmanagement</a></span><li><span><span class=toc-section-number>6.5.2</span> <a href=#unfreeze-option-in-activity-shortcuts id=toc:unfreeze-option-in-activity-shortcuts>Unfreeze option in\nactivity shortcuts</a></span><li><span><span class=toc-section-number>6.5.3</span> <a href=#market-like-url-support id=toc:market-like-url-support><code>market</code>-like URL\nsupport</a></span><li><span><span class=toc-section-number>6.5.4</span> <a href=#updated-color-codes id=toc:updated-color-codes>Updated color\ncodes</a></span><li><span><span class=toc-section-number>6.5.5</span> <a href=#others id=toc:others>Others</a></span></ul><li><span><span class=toc-section-number>6.6</span> <a href=#sec:v4.0.0-(440) id=toc:sec:v4.0.0-(440)>v4.0.0\n(440)</a></span><ul class=incremental><li><span><span class=toc-section-number>6.6.1</span> <a href=#new-logo id=toc:new-logo>New logo!</a></span><li><span><span class=toc-section-number>6.6.2</span> <a href=#android-14-and-15-support id=toc:android-14-and-15-support>Android 14 and 15\nsupport</a></span><li><span><span class=toc-section-number>6.6.3</span> <a href=#revamped-debloater id=toc:revamped-debloater>Revamped\ndebloater</a></span><li><span><span class=toc-section-number>6.6.4</span> <a href=#introducing-file-manager id=toc:introducing-file-manager>Introducing file\nmanager</a></span><li><span><span class=toc-section-number>6.6.5</span> <a href=#integrated-code-editor id=toc:integrated-code-editor>Integrated code editor</a></span><li><span><span class=toc-section-number>6.6.6</span> <a href=#history-of-operations id=toc:history-of-operations>History of\noperations</a></span><li><span><span class=toc-section-number>6.6.7</span> <a href=#per-app-freezing-and-more id=toc:per-app-freezing-and-more>Per-app freezing, and\nmore</a></span><li><span><span class=toc-section-number>6.6.8</span> <a href=#log-viewer-enhancements id=toc:log-viewer-enhancements>Log\nviewer enhancements</a></span><li><span><span class=toc-section-number>6.6.9</span> <a href=#launching-non-exported-activities id=toc:launching-non-exported-activities>Launching non-exported\nactivities</a></span><li><span><span class=toc-section-number>6.6.10</span> <a href=#new-tags-in-app-info-tab id=toc:new-tags-in-app-info-tab>New\ntags in App Info tab</a></span><li><span><span class=toc-section-number>6.6.11</span> <a href=#per-session-installer-options id=toc:per-session-installer-options>Per-session installer\noptions</a></span><li><span><span class=toc-section-number>6.6.12</span> <a href=#advanced-mode-of-operations-adb-enhancements id=toc:advanced-mode-of-operations-adb-enhancements>Advanced mode of\noperations, ADB enhancements, …</a></span><li><span><span class=toc-section-number>6.6.13</span> <a href=#data-usage-widget-and-more id=toc:data-usage-widget-and-more>Data usage widget, and\nmore</a></span><li><span><span class=toc-section-number>6.6.14</span> <a href=#others-1 id=toc:others-1>Others</a></span></ul><li><span><span class=toc-section-number>6.7</span> <a href=#sec:v3.1.0-(423) id=toc:sec:v3.1.0-(423)>v3.1.0\n(423)</a></span><ul class=incremental><li><span><span class=toc-section-number>6.7.1</span> <a href=#android-13-support id=toc:android-13-support>Android 13\nsupport</a></span><li><span><span class=toc-section-number>6.7.2</span> <a href=#introducing-freezeunfreeze id=toc:introducing-freezeunfreeze>Introducing\nfreeze/unfreeze</a></span><li><span><span class=toc-section-number>6.7.3</span> <a href=#export-app-list id=toc:export-app-list>Export app\nlist</a></span><li><span><span class=toc-section-number>6.7.4</span> <a href=#elliptic-curve-crypography-ecc id=toc:elliptic-curve-crypography-ecc>Elliptic Curve Crypography\n(ECC)</a></span><li><span><span class=toc-section-number>6.7.5</span> <a href=#new-languages id=toc:new-languages>New\nlanguages</a></span><li><span><span class=toc-section-number>6.7.6</span> <a href=#more-list-options id=toc:more-list-options>More list\noptions</a></span><li><span><span class=toc-section-number>6.7.7</span> <a href=#improved-handling-of-mode-of-operation id=toc:improved-handling-of-mode-of-operation>Improved handling of\nmode of operation</a></span><li><span><span class=toc-section-number>6.7.8</span> <a href=#handling-multiple-users id=toc:handling-multiple-users>Handling multiple users</a></span><li><span><span class=toc-section-number>6.7.9</span> <a href=#explorer-enhancements id=toc:explorer-enhancements>Explorer\nenhancements</a></span><li><span><span class=toc-section-number>6.7.10</span> <a href=#new-tag-wx id=toc:new-tag-wx>New tag: WX</a></span><li><span><span class=toc-section-number>6.7.11</span> <a href=#app-ops-management id=toc:app-ops-management>App ops\nmanagement</a></span><li><span><span class=toc-section-number>6.7.12</span> <a href=#batch-uninstallation id=toc:batch-uninstallation>Batch\nuninstallation</a></span><li><span><span class=toc-section-number>6.7.13</span> <a href=#running-apps id=toc:running-apps>Running apps</a></span><li><span><span class=toc-section-number>6.7.14</span> <a href=#interceptor id=toc:interceptor>Interceptor</a></span><li><span><span class=toc-section-number>6.7.15</span> <a href=#device-specific-changes id=toc:device-specific-changes>Device-specific changes</a></span><li><span><span class=toc-section-number>6.7.16</span> <a href=#others-2 id=toc:others-2>Others</a></span></ul><li><span><span class=toc-section-number>6.8</span> <a href=#sec:v3.0.0-(410) id=toc:sec:v3.0.0-(410)>v3.0.0\n(410)</a></span><ul class=incremental><li><span><span class=toc-section-number>6.8.1</span> <a href=#material-3-and-more id=toc:material-3-and-more>Material 3 and\nMore</a></span><li><span><span class=toc-section-number>6.8.2</span> <a href=#wireless-debugging id=toc:wireless-debugging>Wireless\nDebugging</a></span><li><span><span class=toc-section-number>6.8.3</span> <a href=#languages id=toc:languages>Languages</a></span><li><span><span class=toc-section-number>6.8.4</span> <a href=#introducing-app-explorer id=toc:introducing-app-explorer>Introducing App\nExplorer</a></span><li><span><span class=toc-section-number>6.8.5</span> <a href=#import-backups-from-other-applications id=toc:import-backups-from-other-applications>Import Backups from\nOther Applications</a></span><li><span><span class=toc-section-number>6.8.6</span> <a href=#virustotal id=toc:virustotal>VirusTotal</a></span><li><span><span class=toc-section-number>6.8.7</span> <a href=#trigger-profiles-from-the-automation-software id=toc:trigger-profiles-from-the-automation-software>Trigger Profiles\nfrom the Automation Software</a></span><li><span><span class=toc-section-number>6.8.8</span> <a href=#improved-application-installer id=toc:improved-application-installer>Improved Application\nInstaller</a></span><li><span><span class=toc-section-number>6.8.9</span> <a href=#component-blocking id=toc:component-blocking>Component\nBlocking</a></span><li><span><span class=toc-section-number>6.8.10</span> <a href=#advanced-searching id=toc:advanced-searching>Advanced\nSearching</a></span><li><span><span class=toc-section-number>6.8.11</span> <a href=#shared-libraries id=toc:shared-libraries>Shared\nLibraries</a></span><li><span><span class=toc-section-number>6.8.12</span> <a href=#make-the-best-use-of-interceptor id=toc:make-the-best-use-of-interceptor>Make the Best Use of\nInterceptor</a></span><li><span><span class=toc-section-number>6.8.13</span> <a href=#widget-screen-time id=toc:widget-screen-time>Widget: Screen\nTime</a></span><li><span><span class=toc-section-number>6.8.14</span> <a href=#widget-clear-cache id=toc:widget-clear-cache>Widget: Clear\nCache</a></span></ul><li><span><span class=toc-section-number>6.9</span> <a href=#sec:v2.6.0-(385) id=toc:sec:v2.6.0-(385)>v2.6.0\n(385)</a></span><ul class=incremental><li><span><span class=toc-section-number>6.9.1</span> <a href=#introducing-backups id=toc:introducing-backups>Introducing\nBackups</a></span><li><span><span class=toc-section-number>6.9.2</span> <a href=#introducing-log-viewer id=toc:introducing-log-viewer>Introducing Log Viewer</a></span><li><span><span class=toc-section-number>6.9.3</span> <a href=#lock-app-manager id=toc:lock-app-manager>Lock App\nManager</a></span><li><span><span class=toc-section-number>6.9.4</span> <a href=#extended-modes-for-app-ops id=toc:extended-modes-for-app-ops>Extended Modes for App\nOps</a></span><li><span><span class=toc-section-number>6.9.5</span> <a href=#new-batch-ops-add-to-profile id=toc:new-batch-ops-add-to-profile>New Batch Ops: Add to\nProfile</a></span><li><span><span class=toc-section-number>6.9.6</span> <a href=#app-info-improved id=toc:app-info-improved>App Info:\nImproved</a></span><li><span><span class=toc-section-number>6.9.7</span> <a href=#advanced-sort-and-filtering-options-in-the-main-page id=toc:advanced-sort-and-filtering-options-in-the-main-page>Advanced\nSort and Filtering Options in the Main Page</a></span><li><span><span class=toc-section-number>6.9.8</span> <a href=#about-this-device id=toc:about-this-device>About This\nDevice</a></span><li><span><span class=toc-section-number>6.9.9</span> <a href=#enabledisable-features id=toc:enabledisable-features>Enable/disable Features</a></span><li><span><span class=toc-section-number>6.9.10</span> <a href=#new-languages-1 id=toc:new-languages-1>New\nLanguages</a></span><li><span><span class=toc-section-number>6.9.11</span> <a href=#signing-the-apk-files id=toc:signing-the-apk-files>Signing the\nAPK Files</a></span><li><span><span class=toc-section-number>6.9.12</span> <a href=#new-extension-unapkm id=toc:new-extension-unapkm>New\nExtension: UnAPKM</a></span></ul><li><span><span class=toc-section-number>6.10</span> <a href=#sec:v2.5.20-(375) id=toc:sec:v2.5.20-(375)>v2.5.20\n(375)</a></span><ul class=incremental><li><span><span class=toc-section-number>6.10.1</span> <a href=#subsec:introducing-profiles id=toc:subsec:introducing-profiles>Introducing\nProfiles</a></span><li><span><span class=toc-section-number>6.10.2</span> <a href=#subsec:the-interceptor id=toc:subsec:the-interceptor>The\nInterceptor</a></span><li><span><span class=toc-section-number>6.10.3</span> <a href=#subsec:unapkm:-dedrm-the-apkm-files id=toc:subsec:unapkm:-dedrm-the-apkm-files>UnAPKM: DeDRM the APKM\nfiles</a></span><li><span><span class=toc-section-number>6.10.4</span> <a href=#subsec:multiple-user id=toc:subsec:multiple-user>Multiple\nuser</a></span><li><span><span class=toc-section-number>6.10.5</span> <a href=#vive-la-france id=toc:vive-la-france>Vive la\nFrance!</a></span><li><span><span class=toc-section-number>6.10.6</span> <a href=#report-crashes id=toc:report-crashes>Report\ncrashes</a></span><li><span><span class=toc-section-number>6.10.7</span> <a href=#android-11 id=toc:android-11>Android 11</a></span><li><span><span class=toc-section-number>6.10.8</span> <a href=#app-installer-improvements id=toc:app-installer-improvements>App Installer\nImprovements</a></span></ul><li><span><span class=toc-section-number>6.11</span> <a href=#v2.5.17-368 id=toc:v2.5.17-368>v2.5.17 (368)</a></span><ul class=incremental><li><span><span class=toc-section-number>6.11.1</span> <a href=#app-installer id=toc:app-installer>App\nInstaller</a></span><li><span><span class=toc-section-number>6.11.2</span> <a href=#scanner-replacement-for-exodus-page id=toc:scanner-replacement-for-exodus-page>Scanner: Replacement for\nExodus Page</a></span><li><span><span class=toc-section-number>6.11.3</span> <a href=#introducing-system-config id=toc:introducing-system-config>Introducing System\nConfig</a></span><li><span><span class=toc-section-number>6.11.4</span> <a href=#more-languages id=toc:more-languages>More\nLanguages</a></span><li><span><span class=toc-section-number>6.11.5</span> <a href=#app-info-tab id=toc:app-info-tab>App Info Tab</a></span><li><span><span class=toc-section-number>6.11.6</span> <a href=#navigation-improvements id=toc:navigation-improvements>Navigation Improvements</a></span><li><span><span class=toc-section-number>6.11.7</span> <a href=#running-apps-page id=toc:running-apps-page>Running Apps\nPage</a></span><li><span><span class=toc-section-number>6.11.8</span> <a href=#built-in-toybox id=toc:built-in-toybox>Built-in\nToybox</a></span><li><span><span class=toc-section-number>6.11.9</span> <a href=#component-blocker-improvements id=toc:component-blocker-improvements>Component Blocker\nImprovements</a></span><li><span><span class=toc-section-number>6.11.10</span> <a href=#improvements-in-the-app-details-page id=toc:improvements-in-the-app-details-page>Improvements in the App\nDetails Page</a></span><li><span><span class=toc-section-number>6.11.11</span> <a href=#app-manifest id=toc:app-manifest>App Manifest</a></span></ul><li><span><span class=toc-section-number>6.12</span> <a href=#v2.5.13-348 id=toc:v2.5.13-348>v2.5.13 (348)</a></span><ul class=incremental><li><span><span class=toc-section-number>6.12.1</span> <a href=#bundled-app-split-apk id=toc:bundled-app-split-apk>Bundled App\n(Split APK)</a></span><li><span><span class=toc-section-number>6.12.2</span> <a href=#direct-install-support id=toc:direct-install-support>Direct\nInstall Support</a></span><li><span><span class=toc-section-number>6.12.3</span> <a href=#remove-all-blocking-rules id=toc:remove-all-blocking-rules>Remove All Blocking\nRules</a></span><li><span><span class=toc-section-number>6.12.4</span> <a href=#app-ops id=toc:app-ops>App Ops</a></span><li><span><span class=toc-section-number>6.12.5</span> <a href=#enhanced-adb-support id=toc:enhanced-adb-support>Enhanced ADB\nSupport</a></span><li><span><span class=toc-section-number>6.12.6</span> <a href=#filtering-in-main-page id=toc:filtering-in-main-page>Filtering\nin Main Page</a></span><li><span><span class=toc-section-number>6.12.7</span> <a href=#apk-backupsharing id=toc:apk-backupsharing>Apk\nBackup/Sharing</a></span><li><span><span class=toc-section-number>6.12.8</span> <a href=#batch-ops id=toc:batch-ops>Batch Ops</a></span><li><span><span class=toc-section-number>6.12.9</span> <a href=#translations id=toc:translations>Translations</a></span><li><span><span class=toc-section-number>6.12.10</span> <a href=#app-data-backup id=toc:app-data-backup>App Data\nBackup</a></span></ul></ul><li><span><span class=toc-section-number>7</span> <a href=#ch:app-ops id=toc:ch:app-ops>App Ops</a></span><ul class=incremental><li><span><span class=toc-section-number>7.1</span> <a href=#sec:app-ops-background id=toc:sec:app-ops-background>Background</a></span><li><span><span class=toc-section-number>7.2</span> <a href=#sec:introduction-to-app-ops id=toc:sec:introduction-to-app-ops>Introduction to App\nOps</a></span><li><span><span class=toc-section-number>7.3</span> <a href=#sec:appopsmanager id=toc:sec:appopsmanager>AppOpsManager</a></span><ul class=incremental><li><span><span class=toc-section-number>7.3.1</span> <a href=#subsec:op-constants id=toc:subsec:op-constants><code>OP_*</code> Constants</a></span><li><span><span class=toc-section-number>7.3.2</span> <a href=#subsec:mode-constants id=toc:subsec:mode-constants><code>MODE_*</code>\nConstants</a></span><li><span><span class=toc-section-number>7.3.3</span> <a href=#subsec:package-ops id=toc:subsec:package-ops>PackageOps</a></span><li><span><span class=toc-section-number>7.3.4</span> <a href=#subsec:opentry id=toc:subsec:opentry>OpEntry</a></span><li><span><span class=toc-section-number>7.3.5</span> <a href=#subsec:usage id=toc:subsec:usage>Usage</a></span></ul><li><span><span class=toc-section-number>7.4</span> <a href=#sec:appopsservice id=toc:sec:appopsservice>AppOpsService</a></span><li><span><span class=toc-section-number>7.5</span> <a href=#sec:appops-xml id=toc:sec:appops-xml>appops.xml</a></span><li><span><span class=toc-section-number>7.6</span> <a href=#sec:appops-cli id=toc:sec:appops-cli>Command Line\nInterface</a></span></ul></ul></nav><div class=titlingpage><div class=center><p><img src=../images/icon.png style=width:1in alt=image><p><strong><span class=smallcaps>App Manager</span></strong><p><strong>Manual de Usuario</strong><p><em>v4.0.5</em><p>27 julio 2025<p>Copyright © 2020–2025 Muntashir Al-Islam<blockquote><p>“Sabio y lento. Tropiezan los que corren rápido”. <span>— Fray\nLaurence, <em>Romeo y Julieta</em></span></blockquote></div></div><section id=ch:introduction class=level1 data-number=1><h1 data-number=1><span class=header-section-number>1</span> <a href=#toc:ch:introduction>Introducción</a><a href=#ch:introduction class=anchor aria-hidden=true></a></h1><p>App Manager es un gestor de paquetes avanzado para Android. Ofrece\ninnumerables funciones y, en consecuencia, requiere un usuario manual\npara ayudar a sus usuarios. Este documento actúa como un manual de\nusuario para App Manager en el sentido de que pretende describir todas\nlas características que App Manager tiene para ofrecer. Este documento\ntambién puede ser considerado como el “oficial” directrices para App\nManager, y representa el comportamiento esperado de App Manager. Las\ntraducciones pueden malinterpretar este documento (que es escrito en\ninglés). Por lo tanto, cada usuario capaz debe leer la versión en inglés\ndel documento para obtener el mejor de App Manager. También podría haber\notros recursos no oficiales o de terceros como artículos de blog,\nvídeos, chat grupos, etc. Si bien estos recursos pueden ser útiles para\nmuchas personas, es posible que no estén actualizados con la versión\nactual de App Manager. versión de App Manager. Si se detectan\ndesviaciones en App Manager con respecto a este documento, deben\nnotificarse en el <a href=https://github.com/MuntashirAkon/AppManager/issues>Rastreador de\nproblemas de App Manager</a>.<section id=sec:terminologies class=level2 data-number=1.1><h2 data-number=1.1><span class=header-section-number>1.1</span> <a href=#toc:sec:terminologies>Terminología</a><a href=#sec:terminologies class=anchor aria-hidden=true></a></h2><ul class=incremental><li><p><strong>AM</strong> — Nombre corto para App Manager.<li><p><strong>Block/Unblock</strong> — Se utiliza para bloquear o\ndesbloquear componentes. La forma en que se bloquean los componentes\ndepende de las preferencias del usuario.<li><p><strong>IFW</strong> — Forma abreviada de Intent\nFirewall.<li><p><strong>Ops</strong> — Nombre abreviado de las operaciones, p.\nej., operaciones de aplicación, operaciones por lotes, operaciones de 1\nclic.<li><p><strong>SSAID</strong> — Forma abreviada de\n<code>Settings.Secure.ANDROID_ID</code>. Es un identificador de\ndispositivo asignado a cada aplicación (Android Oreo y en adelante). Se\ngenera a partir de la combinación del certificado de firma de la app y\nel SSAID establecido para el paquete <code>android</code>. Como\nresultado, se garantiza que sea el mismo para una app a menos que el\nusuario decida formatear el dispositivo. Se utiliza mucho para el\nseguimiento.<li><p><strong>Tracker</strong> — Denota los componentes del rastreador\nen todo el documento y en el App Manager, excepto en el <a href=#sec:scanner-page>página del rastreador</a>. Los rastreadores\nincluyen librerías como crash reporters, analytics perfilado,\nidentificación, anuncio, localización, etc. Por lo tanto, no son iguales\nen funciones. No hay distinción ni sesgo entre las bibliotecas de código\nabierto y las de código cerrado que promueven el rastreo.</ul></section><section id=sec:supported-versions class=level2 data-number=1.2><h2 data-number=1.2><span class=header-section-number>1.2</span> <a href=#toc:sec:supported-versions>Versiones soportadas</a><a href=#sec:supported-versions class=anchor aria-hidden=true></a></h2><p>En la actualidad, las versiones compatibles son v2.6.0 (estable),\nv3.0.0 (versiones alfa y de depuración). Las versiones anteriores de App\nManager pueden contener vulnerabilidades de seguridad y no deben\nutilizarse.</section><section id=sec:official-sources class=level2 data-number=1.3><h2 data-number=1.3><span class=header-section-number>1.3</span> <a href=#toc:sec:official-sources>Fuentes oficiales</a><a href=#sec:official-sources class=anchor aria-hidden=true></a></h2><section id=subsec:binary-distribution-sources class=level3 data-number=1.3.1><h3 data-number=1.3.1><span class=header-section-number>1.3.1</span>\n<a href=#toc:subsec:binary-distribution-sources>Fuentes de\ndistribución binaria</a><a href=#subsec:binary-distribution-sources class=anchor aria-hidden=true></a></h3><p>App Manager is distributed using the following sources. Unofficial\nsources may distribute modified versions of App Manager, and you alone\nshall be responsible for the consequences of using such a\ndistribution.<ol class=incremental><li><p>Official F-Droid repository.<a href=#fn1 class=footnote-ref id=fnref1 role=doc-noteref><sup>1</sup></a><br><em>Link:</em> <a href=https://f-droid.org/packages/io.github.muntashirakon.AppManager class=uri>https://f-droid.org/packages/io.github.muntashirakon.AppManager</a><li><p>GitHub repository.<br><em>Normal releases:</em> <a href=https://github.com/MuntashirAkon/AppManager/releases class=uri>https://github.com/MuntashirAkon/AppManager/releases</a><br><em>Debug releases:</em> <a href=https://github.com/MuntashirAkon/AMInsecureDebugBuilds class=uri>https://github.com/MuntashirAkon/AMInsecureDebugBuilds</a><li><p>Telegram.<br><em>Normal releases:</em> <a href=https://t.me/AppManagerChannel class=uri>https://t.me/AppManagerChannel</a><br><em>Debug releases:</em> <a href=https://t.me/AppManagerDebug class=uri>https://t.me/AppManagerDebug</a></ol></section><section id=subsec:links-to-source-code class=level3 data-number=1.3.2><h3 data-number=1.3.2><span class=header-section-number>1.3.2</span>\n<a href=#toc:subsec:links-to-source-code>Enlaces al código\nfuente</a><a href=#subsec:links-to-source-code class=anchor aria-hidden=true></a></h3><p>Todos, excepto GitHub, son los enlaces espejo. Las etiquetas deberían\nestar siempre actualizadas, pero no se garantiza que la rama maestra\nesté actualizada. Si el objetivo es clonar la rama maestra, utiliza el\nenlace de GitHub en lugar de los otros.<ol class=incremental><li><p>GitHub: <a href=https://github.com/MuntashirAkon/AppManager class=uri>https://github.com/MuntashirAkon/AppManager</a><li><p>Codeberg: <a href=https://codeberg.org/muntashir/AppManager class=uri>https://codeberg.org/muntashir/AppManager</a><li><p>GitLab: <a href=https://gitlab.com/muntashir/AppManager class=uri>https://gitlab.com/muntashir/AppManager</a><li><p>Riseup: <a href=https://0xacab.org/muntashir/AppManager class=uri>https://0xacab.org/muntashir/AppManager</a><li><p>sourcehut: <a href=https://git.sr.ht/~muntashir/AppManager class=uri>https://git.sr.ht/~muntashir/AppManager</a></ol></section><section id=subsec:translations class=level3 data-number=1.3.3><h3 data-number=1.3.3><span class=header-section-number>1.3.3</span>\n<a href=#toc:subsec:translations>Traducciones</a><a href=#subsec:translations class=anchor aria-hidden=true></a></h3><p>App Manager no acepta traducciones directamente a través de\nsolicitudes pull/merge. Las traducciones se gestionan automáticamente a\ntravés de Weblate. Para unirse al equipo de traducción, visite <a href=https://hosted.weblate.org/engage/app-manager/ class=uri>https://hosted.weblate.org/engage/app-manager/</a>.</section></section><section id=sec:contributing class=level2 data-number=1.4><h2 data-number=1.4><span class=header-section-number>1.4</span> <a href=#toc:sec:contributing>Contribuyendo</a><a href=#sec:contributing class=anchor aria-hidden=true></a></h2><p>Hay múltiples formas en las que un usuario puede contribuir, como\ncrear problemas útiles, asistir a debates, mejorar documentación y\ntraducciones, añadiendo bibliotecas o rastreadores no reconocidos,\nrevisando el código fuente, así como informar de las vulnerabilidades de\nseguridad.<section id=subsec:build-instructions class=level3 data-number=1.4.1><h3 data-number=1.4.1><span class=header-section-number>1.4.1</span>\n<a href=#toc:subsec:build-instructions>Instrucciones de\nconstrucción</a><a href=#subsec:build-instructions class=anchor aria-hidden=true></a></h3><p>Las instrucciones de compilación están disponibles en el archivo\nBUILDING ubicado en el directorio raíz de la fuente.</section><section id=subsec:submitting-patches class=level3 data-number=1.4.2><h3 data-number=1.4.2><span class=header-section-number>1.4.2</span>\n<a href=#toc:subsec:submitting-patches>Envío de parches</a><a href=#subsec:submitting-patches class=anchor aria-hidden=true></a></h3><p>Los repositorios ubicados en sitios distintos de GitHub se consideran\nactualmente réplicas, y las solicitudes de pull/merge enviadas en. <a href=#fn2 class=footnote-ref id=fnref2 role=doc-noteref><sup>2</sup></a> En su lugar, los parches (como\narchivos <code>.patch</code>) pueden ser enviados a través de archivos\nadjuntos de correo electrónico. <em>La firma es un requisito.</em>\nConsulte el archivo CONTRIBUIR ubicado en el directorio raíz de la\nfuente para obtener más información.<div class=\"amalert warning\"><p><strong><em>Notice.</em></strong><p>En caso de enviar parches por correo electrónico, toda la\nconversación puede ser accesible públicamente en el futuro. Por lo\ntanto, no incluya ninguna información personal identificable (PII) que\nno sea su nombre o dirección de correo electrónico.</div></section></section><section id=sec:donation-&-funding class=level2 data-number=1.5><h2 data-number=1.5><span class=header-section-number>1.5</span> <a href=#toc:sec:donation-&-funding>Donación y Financiamiento</a><a href=#sec:donation-&-funding class=anchor aria-hidden=true></a></h2><p><em>La donación o la compra no es un requisito para utilizar App\nManager.</em> Aunque App Manager no admite ninguna Aunque App Manager no\nadmite ninguna compra, se pueden enviar donaciones al propietario de App\nManager a través de Open Source Collective.<p>Open Source Collective es un host fiscal en la plataforma Open\nCollective que ayuda a los proyectos de código abierto a gestionar sus\nfinanzas. En la actualidad, admite pagos a través de cuentas bancarias,\nPayPal, tarjetas de crédito o débito y criptomonedas.<p><em>Link:</em> <a href=https://opencollective.com/muntashir class=uri>https://opencollective.com/muntashir</a>.<p>Al enviar las donaciones, los remitentes se comprometen a no\nutilizarlas como palanca para priorizar sus características solicitadas.\nLas solicitudes de características no requieren recompensas ni\ndonaciones, y se priorizan de acuerdo con las preferencias del\npropietario.<p><em>App Manager acepta cualquier oferta de financiación o\nsubvención.</em> Los representantes de la organización interesada pueden\nponerse en contacto directamente con el propietario utilizando las\nopciones que se indican en §<a href=#sec:contact data-reference-type=ref data-reference=sec:contact>1.6</a>.<p>In addition, the maintainers and contributors of this project DO NOT\nconsent to the creation, sale, or promotion of tokens, cryptocurrencies,\nNFTs, or any other financial instruments that claim to represent this\nproject, its code, or its community. Any such attempts are unauthorized\nand not affiliated with this project in any way.</section><section id=sec:contact class=level2 data-number=1.6><h2 data-number=1.6><span class=header-section-number>1.6</span> <a href=#toc:sec:contact>Contacto</a><a href=#sec:contact class=anchor aria-hidden=true></a></h2><p>Muntashir Al-Islam<a href=#fn3 class=footnote-ref id=fnref3 role=doc-noteref><sup>3</sup></a><br>Correo electrónico: <a href=mailto:muntashirakon@riseup.net>muntashirakon [arroba] riseup\n[punto] net</a><br>Huella digital de la llave:\n<code>7bad37c2981e41f8f6abea7f58f0b4f26c346fce</code><br>GitHub: <a href=https://github.com/MuntashirAkon class=uri>https://github.com/MuntashirAkon</a><br>Twitter: <a href=https://twitter.com/Muntashir class=uri>https://twitter.com/Muntashir</a></section></section><section id=ch:pages class=level1 data-number=2><h1 data-number=2><span class=header-section-number>2</span> <a href=#toc:ch:pages>Páginas</a><a href=#ch:pages class=anchor aria-hidden=true></a></h1><section id=sec:main-page class=level2 data-number=2.1><h2 data-number=2.1><span class=header-section-number>2.1</span> <a href=#toc:sec:main-page>Página principal</a><a href=#sec:main-page class=anchor aria-hidden=true></a></h2><p>La página principal muestra todas las aplicaciones instaladas,\ndesinstaladas y con copia de seguridad. Un solo clic en cualquier\nelemento de la aplicación instalada abre la respectiva <a href=#sec:app-details-page>página de detalles de la aplicación</a>.\nPara las aplicaciones del sistema desinstaladas, se muestra un diálogo\nque puede utilizarse para reinstalar la aplicación. Utilizando la opción\n<a href=#par:main-page-sort>ordenación</a> de las opciones de la\nlista, los elementos de la aplicación pueden ordenarse de varias maneras\ny conservarse al salir. También es posible filtrar los elementos\nutilizando la opción <a href=#par:main-page-filter>filtro</a> de las\nopciones de la lista. El filtrado también es posible a través de la\nbarra de búsqueda con soporte adicional para las expresiones\nregulares.<figure id=fig:main_page_entry_info_labeled><figure><object data=../images/main_page_entry_info_labeled.svg type=image/svg+xml></object></figure><figcaption>Figure 1: Un elemento de la lista de aplicaciones en la\npágina principal</figcaption></figure><section id=subsec:batch-operations class=level3 data-number=2.1.1><h3 data-number=2.1.1><span class=header-section-number>2.1.1</span>\n<a href=#toc:subsec:batch-operations>Operaciones por lotes</a><a href=#subsec:batch-operations class=anchor aria-hidden=true></a></h3><p>En esta página también se pueden realizar operaciones por lotes o en\nvarias aplicaciones. El modo de selección múltiple puede activarse\nhaciendo clic en el icono de cualquier aplicación o haciendo un clic\nprolongado en cualquier elemento de la lista. Una vez activado, un solo\nclic en un elemento de la lista lo selecciona en lugar de abrir la\npágina de detalles de la aplicación. En este modo, las operaciones por\nlotes se encuentran en el menú de selección múltiple en la parte\ninferior de la página. Las operaciones incluyen:<ul class=incremental><li><p>Añadir las aplicaciones seleccionadas a un perfil.<li><p><a href=#sec:backup-restore>Hacer una copia de seguridad,\nrestaurar o eliminar</a> las aplicaciones<li><p>Bloquear los rastreadores de las aplicaciones<li><p>Borrar los datos o la caché de las aplicaciones<li><p>Habilitar/deshabilitar/forzar la desinstalación de las\naplicaciones<li><p>Exportar las reglas de bloqueo guardadas en App Manager<li><p>Impedir las operaciones en segundo plano de las aplicaciones\n(Android 7 y posteriores)<li><p>Guardar los archivos APK en <code>AppManager/apks</code><li><p>Establecer <a href=#sec:net-policy>políticas de\nred</a></ul><div class=\"amalert tip\"><p><strong><em>Accesibilidad.</em></strong><p>Una vez activado el modo de selección múltiple, es posible navegar\ndentro o fuera del menú de selección múltiple de selección múltiple\nutilizando las teclas derecha o izquierda del teclado o del mando a\ndistancia.</div></section><section id=subsec:main-colour-codes class=level3 data-number=2.1.2><h3 data-number=2.1.2><span class=header-section-number>2.1.2</span>\n<a href=#toc:subsec:main-colour-codes>Códigos de color</a><a href=#subsec:main-colour-codes class=anchor aria-hidden=true></a></h3><ul class=incremental><li><p><span class=colorbox style=background-color:#ff0000b3><span style=color:#000>Red (day)</span></span> / <span class=colorbox style=background-color:#790d0d><span style=color:#fff>dark red (night)</span></span> – Uninstalled\napplication<li><p><span class=colorbox style=background-color:#ff8a80><span style=color:#000>Light red (day)</span></span> / <span class=colorbox style=background-color:#4f1c14bf><span style=color:#fff>very\ndark red (night)</span></span> – Frozen application<li><p><span class=colorbox style=background-color:#09868b><span style=color:#fff>Dark cyan</span></span> – Force-stopped\napplication<li><p><span class=colorbox style=background-color:#ff0><span style=color:#000>Yellow Star</span></span> – Debuggable\napplication<li><p><span style=color:#e05915>Orange <em>Date</em></span> – The\napplication can read system logs<li><p><span style=color:#e05915>Orange <em>UID</em></span> – The\nuser ID is being shared among multiple applications<li><p><span style=color:#e05915>Orange <em>SDK</em></span> – The\napplication possibly uses cleartext (i.e. HTTP) traffic<li><p><span style=color:#ff8017>Light orange <em>package\nname</em></span> – The application has one or more trackers<li><p><span style=color:red>Red <em>app label</em></span> – The\napplication does not allow clearing its data<li><p><span style=color:#09868b>Dark cyan <em>version</em></span>\n– Inactive application<li><p><span style=color:#f0f>Magenta type</span> – Persistent\napplication i.e. it remains running all the time<li><p><span style=color:red>Red <em>backup</em></span> – The\nuninstalled application with one or more backups present in App\nManager<li><p><span style=color:#e05915>Orange <em>backup</em></span> –\nOutdated backup, i.e. the base backup contains an older version of the\ninstalled application<li><p><span style=color:#09868b>Dark cyan <em>backup</em></span>\n– Up to date backup, i.e. the base backup contains the same or higher\nversion of the installed application.</ul></section><section id=subsec:main-page-application-types class=level3 data-number=2.1.3><h3 data-number=2.1.3><span class=header-section-number>2.1.3</span>\n<a href=#toc:subsec:main-page-application-types>Tipos de\naplicación</a><a href=#subsec:main-page-application-types class=anchor aria-hidden=true></a></h3><p>An application can be either a <strong>User</strong> or a\n<strong>System</strong> application along with the following\nsuffixes:<ul class=incremental><li><p><code>X</code> – Supports multiple architectures<li><p><code>0</code> – No dex files present in the application<li><p><code>°</code> – Suspended application<li><p><code>#</code> – The application requested the system to allocate\na large heap i.e. large runtime memory<li><p><code>?</code> – The application requested the virtual machine to\nbe in the safe mode.</ul></section><section id=subsec:main-page-version-info class=level3 data-number=2.1.4><h3 data-number=2.1.4><span class=header-section-number>2.1.4</span>\n<a href=#toc:subsec:main-page-version-info>Información sobre la\nversión</a><a href=#subsec:main-page-version-info class=anchor aria-hidden=true></a></h3><p>El nombre de la versión va seguido de los siguientes prefijos:<ul class=incremental><li><p><code>_</code> – Sin aceleración por hardware (rompiendo las\nanimaciones o transparencias in-app)<li><p><code>textasciitilde</code> – Aplicación de prueba<li><p><code>debug</code> – Aplicación depurable</ul></section><section id=subsec:main-page-options-menu class=level3 data-number=2.1.5><h3 data-number=2.1.5><span class=header-section-number>2.1.5</span>\n<a href=#toc:subsec:main-page-options-menu>Opciones de menú</a><a href=#subsec:main-page-options-menu class=anchor aria-hidden=true></a></h3><p>El menú de opciones ofrece varias opciones que se pueden usar para\nordenar y filtrar las aplicaciones enumeradas, así como para navegar a\ndiferentes páginas dentro o fuera de App Manager.<section id=subsubsec:main-list-options class=level4 data-number=2.1.5.1><h4 data-number=2.1.5.1><span class=header-section-number>2.1.5.1</span> Lista de opciones<a href=#subsubsec:main-list-options class=anchor aria-hidden=true></a></h4><p><strong>List options</strong> contiene las opciones para clasificar y\nfiltrar la lista en la página principal.<section id=clasificar class=level5 data-number=2.1.5.1.1><h5 data-number=2.1.5.1.1><span class=header-section-number>2.1.5.1.1</span> Clasificar<a href=#clasificar class=anchor aria-hidden=true></a></h5><div id=par:main-page-sort></div><p>The applications listed in the main page can be sorted in the\nfollowing ways:<ul class=incremental><li><p><strong>User apps first.</strong> The user applications are\nlisted on top<li><p><strong>App label.</strong> Sort the list in ascending order\nbased on their application labels (also known as <em>application\nnames</em>). This is the default sorting preference<li><p><strong>Package name.</strong> Sort the list in ascending order\nbased on their package names<li><p><strong>Last update.</strong> Sort the list in descending order\nbased on the date they were last updated<li><p><strong>Shared user ID.</strong> Sort the list in descending\norder based on their kernel user ID<li><p><strong>Target SDK.</strong> Sort the list in ascending order\nbased on their target SDK<li><p><strong>Signature.</strong> Sort the list in ascending order\nbased on their signing information<li><p><strong>Frozen first.</strong> The frozen applications are listed\non the top<li><p><strong>Blocked first.</strong> Sort the list in descending order\nbased on the number of blocked components each application has<li><p><strong>Backed up first.</strong> Display the applications with\nbackups on the top<li><p><strong>Trackers.</strong> Sort the list in descending order\nbased on the number of tracker components each application has<li><p><strong>Last actions.</strong> Sort the list in descending order\nbased on the latest time and date of any actions made to the\napplications within App Manager.<li><p><strong>Installation date.</strong> Sort the list by the date of\ninstallation in descending order.<li><p><strong>Total size.</strong> Sort the list by the total size of\nthe applications and their data in descending order. Requires\n<code>Usage Access</code> permission.<li><p><strong>Data usage.</strong> Sort the list by the total data\nusage in descending order. Requires <code>Usage Access</code>\npermission.<li><p><strong>Times opened.</strong> List frequently used applications\non top. Requires <code>Usage Access</code> permission.<li><p><strong>Screen time.</strong> List the applications with the\nhighest engagements on top. Requires <code>Usage Access</code>\npermission.<li><p><strong>Last used.</strong> List last used apps on top. Requires\n<code>Usage Access</code> permission.</ul><p>In addition, there is the <em>reverse</em> option that can be used to\nsort the list in the reverse order. Regardless of the sorting\npreferences, the applications are sorted alphabetically at first in\norder to prevent producing any random sorting results.</section><section id=filtro class=level5 data-number=2.1.5.1.2><h5 data-number=2.1.5.1.2><span class=header-section-number>2.1.5.1.2</span> Filtro<a href=#filtro class=anchor aria-hidden=true></a></h5><div id=par:main-page-filter></div><p>The applications listed in the main page can be filtered in the\nfollowing ways:<ul class=incremental><li><p><strong>User apps.</strong> List only the user\napplications<li><p><strong>System apps.</strong> List only the system\napplications<li><p><strong>Frozen apps.</strong> List only the frozen\napplications<li><p><strong>Stopped apps.</strong> List only the applications that\nwere forced-stopped<li><p><strong>Installed apps.</strong> List only the installed\napplications<li><p><strong>Uninstalled apps.</strong> List only the uninstalled\napplications<li><p><strong>With rules.</strong> List the applications with one or\nmore blocking rules<li><p><strong>With activities.</strong> List the applications with one\nor more activities<li><p><strong>With backups.</strong> List the applications with one or\nmore backups<li><p><strong>Without backups.</strong> List the applications with no\nbackups present.<li><p><strong>Running apps.</strong> List the applications that are\ncurrently running<li><p><strong>With splits.</strong> List the applications with one or\nmore split APK files<li><p><strong>With KeyStore.</strong> List only the applications with\nAndroid KeyStore.<li><p><strong>With SAF.</strong> List only the applications with SAF\naccess.<li><p><strong>With SSAID.</strong> List only the applications with a\nvalid SSAID.</ul><p>Unlike sorting, it is possible to apply more than one filtering\noptions at the same time. For example, the frozen user applications can\nbe listed by selecting both <em>User apps</em> and <em>Frozen apps</em>.\nThis can be particularly useful for <a href=#subsec:batch-operations>batch operations</a> where filtering the\nuser applications may be necessary to carry out certain operations\nsafely.<div class=\"amalert warning\"><p><strong><em>Inconsistencies.</em></strong><p>App Manager extensively caches everything in this page. Therefore,\ncertain states (e.g., freeze and stopped states) may not always be\nup-to-date.</div></section><section id=nombre-del-perfil class=level5 data-number=2.1.5.1.3><h5 data-number=2.1.5.1.3><span class=header-section-number>2.1.5.1.3</span> Nombre del perfil<a href=#nombre-del-perfil class=anchor aria-hidden=true></a></h5><p>It is also possible to list the applications that are only present in\na <a href=#sec:profiles-page>profile</a>. This can be useful for\ncarrying out certain operations on a profile (e.g., uninstalling all the\napplications in a profile) that cannot be done via the <a href=#sec:profiles-page>Profiles page</a>.</section></section><section id=instrucciones class=level4 data-number=2.1.5.2><h4 data-number=2.1.5.2><span class=header-section-number>2.1.5.2</span> Instrucciones<a href=#instrucciones class=anchor aria-hidden=true></a></h4><p>Al hacer clic en <strong>Instrucciones</strong> se abre la versión\nsin conexión del manual de usuario de App Manager. También puede abrir\nla versión en línea si la función correspondiente no está instalada, o\nsi no hay una WebView en el sistema para cargar el manual. presente en\nel sistema para cargar el manual.</section><section id=subsubsec:main:1-click-ops class=level4 data-number=2.1.5.3><h4 data-number=2.1.5.3><span class=header-section-number>2.1.5.3</span> Operaciones con 1 clic<a href=#subsubsec:main:1-click-ops class=anchor aria-hidden=true></a></h4><p><strong>1-Click Ops</strong> stands for the single-click operations.\nIt opens the <a href=#sec:1-click-ops-page>corresponding page</a> in a\nnew activity.</section><section id=uso-de-la-aplicación class=level4 data-number=2.1.5.4><h4 data-number=2.1.5.4><span class=header-section-number>2.1.5.4</span> Uso de la aplicación<a href=#uso-de-la-aplicación class=anchor aria-hidden=true></a></h4><p>Application usage statistics, such as <em>screen time</em>, <em>data\nusage</em> (both mobile and Wi-Fi), <em>number of times an app was\nopened</em>, can be accessed by clicking on the <strong>App\nUsage</strong> option in the menu. However, it requires the <em>Usage\nAccess</em> permission. This menu item will not be listed if the usage\naccess feature is disabled in <a href=#subsubsec:enable/disable-features>settings</a>.</section><section id=subsubsec:main:running-apps class=level4 data-number=2.1.5.5><h4 data-number=2.1.5.5><span class=header-section-number>2.1.5.5</span> Aplicaciones en ejecución<a href=#subsubsec:main:running-apps class=anchor aria-hidden=true></a></h4><p>This menu item opens a new page where a list of running applications\nor processes are displayed. It also displays the current memory and\ncache (if available) usage. If root or ADB is not available to App\nManager, it only displays itself in the recent versions of Android. The\nrunning applications or processes can also be force-stopped or killed\nwithin the resultant page. Logs for each process ID (PID) can also be\nviewed in the <a href=#subsubsec:main:labs>log viewer</a>. In\naddition, it is also possible to carry out batch operations either by\nclicking on the icon or by long-clicking on an item. Normal click on any\nitems opens a dialog where a more detailed information is displayed.</section><section id=perfiles class=level4 data-number=2.1.5.6><h4 data-number=2.1.5.6><span class=header-section-number>2.1.5.6</span> Perfiles<a href=#perfiles class=anchor aria-hidden=true></a></h4><p>This menu item opens the <a href=#sec:profiles-page>profiles\npage</a>. Profiles are a way to configure regularly used tasks. They can\nalso be invoked via shortcuts.</section><section id=actualizador-de-apk class=level4 data-number=2.1.5.7><h4 data-number=2.1.5.7><span class=header-section-number>2.1.5.7</span> Actualizador de APK<a href=#actualizador-de-apk class=anchor aria-hidden=true></a></h4><p>Si la aplicación <a href=https://github.com/rumboalla/apkupdater>APK Updater</a> está\ninstalada en el sistema, ésta puede ser abierta directamente desde este\nelemento del menú. La opción permanece oculta si la aplicación no está\npresente en el sistema.</section><section id=termux class=level4 data-number=2.1.5.8><h4 data-number=2.1.5.8><span class=header-section-number>2.1.5.8</span> Termux<a href=#termux class=anchor aria-hidden=true></a></h4><p>Si la aplicación <a href=https://github.com/termux/termux-app>Termux</a> está instalada en\nel sistema, la sesión en curso (o una nueva sesión) puede abrirse\ndirectamente a través de este elemento del menú. La opción permanece\noculta si la aplicación no está presente en el sistema.</section><section id=debloater class=level4 data-number=2.1.5.9><h4 data-number=2.1.5.9><span class=header-section-number>2.1.5.9</span> Debloater<a href=#debloater class=anchor aria-hidden=true></a></h4><p>This menu item opens the debloater page that lists all the bloatware\navailable in the device and in App Manager. It also suggests alternative\napplications based on the criteria set by the <a href=https://github.com/MuntashirAkon/android-debloat-list>Android\nDebloat List</a> project.</section><section id=subsubsec:main:labs class=level4 data-number=2.1.5.10><h4 data-number=2.1.5.10><span class=header-section-number>2.1.5.10</span> Labs<a href=#subsubsec:main:labs class=anchor aria-hidden=true></a></h4><p>This menu item opens the labs page that lists all the additional\nfeatures. They include Log Viewer, System Config, Terminal, File Manager\n(as Files), UI Tracker, Interceptor, and Code Editor pages.</section><section id=configuraciones class=level4 data-number=2.1.5.11><h4 data-number=2.1.5.11><span class=header-section-number>2.1.5.11</span> Configuraciones<a href=#configuraciones class=anchor aria-hidden=true></a></h4><p>Este elemento del menú abre la <a href=#sec:settings-page>Settings\npage</a> de la aplicación.</section></section></section><section id=sec:app-details-page class=level2 data-number=2.2><h2 data-number=2.2><span class=header-section-number>2.2</span> <a href=#toc:sec:app-details-page>Página de detalles de la\naplicación</a><a href=#sec:app-details-page class=anchor aria-hidden=true></a></h2><p><strong>App Details</strong> page consists of 11 (eleven) tabs. It\ndescribes almost every bit of information an application usually has,\nincluding all attributes from its manifest, <a href=#ch:app-ops>application operations</a> (app ops), signing\ninformation, libraries, and so on.<section id=subsec:app-details-colour-codes class=level3 data-number=2.2.1><h3 data-number=2.2.1><span class=header-section-number>2.2.1</span>\n<a href=#toc:subsec:app-details-colour-codes>Código de color</a><a href=#subsec:app-details-colour-codes class=anchor aria-hidden=true></a></h3><p>List of colours used in this page, and their meaning:<ul class=incremental><li><p><span class=colorbox style=background-color:#ff0000b3><span style=color:#000>Red (day)</span></span> / <span class=colorbox style=background-color:#790d0d><span style=color:#fff>dark red (night)</span></span> – Denotes any app\nops or permissions having the dangerous flag, or any components blocked\nwithin App Manager, or any unsupported but required features.<li><p><span class=colorbox style=background-color:#ff8a80><span style=color:#000>Light red (day)</span></span> / <span class=colorbox style=background-color:#4f1c14bf><span style=color:#fff>very\ndark red (night)</span></span> – Denotes the components disabled outside\nof App Manager, or any unsupported but optional features.<div class=\"amalert tip\"><p><strong><em>Note.</em></strong><p>A component marked as disabled does not always mean that it is\ndisabled by the user: It could also be disabled by the system or marked\nas disabled in its manifest. The components of a disabled application\nare also considered disabled by the system (and App Manager).</div><li><p><span class=colorbox style=background-color:#ff8017><span style=color:#000>Vivid orange (day)</span></span> / <span class=colorbox style=background-color:#ff801780><span style=color:#fff>very\ndark orange (night)</span></span> – Denotes the tracker\ncomponents<li><p><span class=colorbox style=background-color:#ea80fc><span style=color:#000>Soft magenta (day)</span></span> / <span class=colorbox style=background-color:#431c5d><span style=color:#fff>very dark violet (night)</span></span> – Denotes\nthe running services.<li><p><span class=colorbox style=background-color:#1b8654><span style=color:#fff>Green</span></span> – Used in the tracker-indicator\ntag to denote that all the trackers in the application are\nblocked.</ul></section><section id=subsec:app-info-tab class=level3 data-number=2.2.2><h3 data-number=2.2.2><span class=header-section-number>2.2.2</span>\n<a href=#toc:subsec:app-info-tab>Pestañas de información de la\naplicación</a><a href=#subsec:app-info-tab class=anchor aria-hidden=true></a></h3><p><strong>App Info</strong> tab contains general information about an\napplication. It also lists many actions that can be performed within\nthis tab.<section id=subsubsec:app-info-general-information class=level4 data-number=2.2.2.1><h4 data-number=2.2.2.1><span class=header-section-number>2.2.2.1</span> Información general<a href=#subsubsec:app-info-general-information class=anchor aria-hidden=true></a></h4><p>The list below is in the same order as listed in the App Info\ntab.<ul class=incremental><li><p><strong>Application Icon.</strong> The application icon. If the\napplication does not have an icon, the system default icon will be\ndisplayed. It is also possible to verify the APK signature via SHA or\nMD5 sums stored in the clipboard by simply clicking on it.<li><p><strong>Application Label.</strong> The application label or the\nname of the application.<li><p><strong>Package Name.</strong> The name of the application\npackage. Clicking on the name stores it in the clipboard.<li><p><strong>Version.</strong> The application version is divided into\ntwo parts. The first part is called <em>version name</em>. The format of\nthis part varies but often consists of multiple integers separated by\ndots. The second part is called <em>version code</em>. It is enclosed by\nthe first brackets. The version code is an integer used to differentiate\nbetween application versions (since a version name can be unreadable to\na machine). In general, a new version of an application has higher\nversion code than the old ones. For example, if <code>123</code> and\n<code>125</code> are two version codes of an application, we can say\nthat the latter is more updated than the former because the version code\nof the latter is higher. An application that serves different APK files\nfor the same version on different platforms (mobile, tabs, desktops,\netc.) or architectures (32/64 bit, ARM or Intel), the version numbers\ncan be misleading as they often add prefixes for each platform.<li><p><strong>Tags.</strong> (Also known as tag clouds) Tags include\nthe most basic, concise and useful information of an application. See\n§<a href=#subsubsec:tags data-reference-type=ref data-reference=subsubsec:tags>2.2.2.2</a> for a complete list of tags\nshown here.<li><p><strong>Horizontal Action Panel.</strong> An action panel\nconsisting of various actions that can be carried out for the\napplication. See §<a href=#subsubsec:horizontal-action-panel data-reference-type=ref data-reference=subsubsec:horizontal-action-panel>2.2.2.3</a> for a\ncomplete list of actions available here. Additional actions are\navailable in the <a href=#subsubsec:app-info-options-menu>options\nmenu</a>.<li><p><strong>Paths & Directories.</strong> Contains various\ninformation regarding application paths including <em>app directory</em>\n(where the APK files reside), <em>data directories</em> (internal,\ndevice protected and externals), and <em>JNI library directory</em> (if\npresent). JNI libraries are used to invoke native codes usually written\nin C/C++. Use of native library can make the application run faster or\nhelp an application use third-party libraries written using languages\nother than Java like in most games. The directories can be opened via\nfile managers provided they support it and have the necessary\npermissions, by clicking on the launch button on the right-hand side of\na directory item.<li><p><strong>Data Usage.</strong> Amount of data used by the\napplication as reported by the operating system. Depending on Android\nversion, this may require a wide range of permissions including\n<em>Usage Access</em> and <em>Telephony</em> permissions.<li><p><strong>Storage & Cache.</strong> Displays information\nregarding the size of the application (APK files, optimised files), data\nand cache. In older devices, size of external data, cache, media and OBB\nfolders are also displayed. This part remains hidden if <em>Usage\nAccess</em> permission is not granted in the newer devices.<li><p><strong>More Info.</strong> Displays other information such\nas–<ul class=incremental><li><p><strong>SDK.</strong> Displays information related to the Android\nSDK: <em>Max</em> denotes the target SDK and <em>Min</em> denotes the\nminimum SDK (the latter is not available in Android Lollipop). If the\ntarget SDK value is less than the platform SDK (i.e., the highest SDK\nthe current operating system supports), the application will run in the\ncompatibility mode. This means the application may have access to\ncertain features that are unavailable or restricted in a newer version\nof Android, which can be a security and/or privacy issue. SDK is also\nknown as <strong>API Level</strong>.<br><div class=seealso-inline><p><em>Ver también: <span><a href=https://en.wikipedia.org/wiki/Android_version_history#Overview>Android\nVersion History</a></span></em></div><li><p><strong>Flags.</strong> The application flags used at the time of\nbuilding the application. For a complete list of flags and what they do,\nread the <a href=https://developer.android.com/reference/android/content/pm/ApplicationInfo#flags>official\ndocumentation</a>.<li><p><strong>Date Installed.</strong> The date when the application\nwas first installed.<li><p><strong>Date Updated.</strong> The date when the application was\nlast updated. This is the same as <em>Date Installed</em> if the\napplication hasn’t been updated.<li><p><strong>Process Name.</strong> The name of the process if it is\ndifferent from the package name. Process name is set when an application\nis being started by the system, and is usually the same as the package\nname.<li><p><strong>Installer App.</strong> The application that installed\nthis application. The installer application may not always be the same\nas the application that installed this application, because Android\nallows setting an arbitrary value for this field. In Android 11 onwards,\nthe actual installer application is also stored by the system which can\nbe accessed by clicking the “Info” button on the right-hand side of the\nitem. The field will not be visible if the installer application is not\nreported by the system (e.g., due to the installer application being\nuninstalled or hidden). Installer application may be granted additional\nprivileges by the system so that it can control certain behaviour of the\napplication it installs.<li><p><strong>User ID.</strong> The unique user ID set by the system to\nthe application. For shared applications, the same user ID is assigned\nto multiple applications having the same <em>Shared User\nID</em>.<li><p><strong>Shared User ID.</strong> Applicable for applications that\nare shared together. The shared application must have the same <a href=#subsec:signatures-tab>signatures</a>.<li><p><strong>Primary ABI.</strong> Architecture supported by this\nplatform for this application.<li><p><strong>Zygote preload name.</strong> Responsible for preloading\napplication code and data shared across all the isolated services that\nuses app zygote.<li><p><strong>Hidden API enforcement policy.</strong> Since Android 9,\nmany methods and classes in Android framework have been made\ninaccessible to the third-party applications through hidden API\nenforcement policy. It has the following options:<ul class=incremental><li><p><em>Default.</em> Based on the type of application. For system\napplications, it should be disabled, and for others, it should be\nenforced.<li><p><em>None/disabled.</em> The application has full access to the\nhidden API as it used to be before Android 9.<li><p><em>Warn.</em> Same as above, except that warnings will be logged\neach time the application accesses the hidden API. This is mostly\nunused.<li><p><em>Enforce.</em> The application cannot access hidden API,\neither dark-grey list or blacklist, or both of them. This is the default\noption for the third-party applications in Android 9 onwards unless the\napplication is whitelisted by the OEM or the vendor.<div class=\"amalert warning\"><p><strong><em>Warning.</em></strong><p>Hidden API enforcement policy is not properly implemented in Android\nand can be bypassed by the application. As a result, this value should\nnot be trusted.</div></ul><li><p><strong>SELinux.</strong> Mandatory access control (MAC) policy\nset by the operating system via SELinux.<li><p><strong>Main Activity.</strong> The main entry point to the\napplication. This is only visible if the application has <a href=#subsubsec:activities>activities</a> and any of those are\nopenable from the Launcher. There’s also a launch button on the\nright-hand side which can be used to launch this activity.</ul></ul></section><section id=subsubsec:tags class=level4 data-number=2.2.2.2><h4 data-number=2.2.2.2><span class=header-section-number>2.2.2.2</span> Tags<a href=#subsubsec:tags class=anchor aria-hidden=true></a></h4><ul class=incremental><li><p><strong>Tracker info.</strong> Number of tracker components in\nthe application (e.g., <em>5 trackers</em>) The colour of the tag\nappears orange if the trackers are unblocked and dark cyan if they are\nblocked in App Manager. Clicking on the tag opens a dialog containing\nthe list of tracker components which can also be blocked or unblocked\nprovided App Manager has sufficient privileges.<li><p><strong>Application type.</strong> User application or system\napplication. For a system application, it displays whether the\napplication is an updated version of the system application or the\napplication is installed systemless-ly via Magisk.<li><p><strong>Split APK info.</strong> Number of splits in the APK\nexcluding the base APK (e.g., <em>5 splits</em>). Clicking on the tag\nopens a dialog containing a few additional information, such as name,\ntype, and size.<li><p><strong>Debuggable.</strong> The application can be debugged over\nADB. Debuggable applications can enjoy certain functions unavailable to\na regular application. The data of the application might be accessible\nvia ADB (e.g. using <code>run-as</code> command) without any additional\npermissions.<li><p><strong>Test only.</strong> The application is a test-only\napplication. Test-only applications can enjoy certain functions\nunavailable to a regular application. The data of the application might\nbe accessible via ADB (e.g. using <code>run-as</code> command) without\nany additional permissions.<li><p><strong>No code.</strong> The application does not have any code\nassociated with it i.e., DEX files aren’t present. In some system\napplications, the actual code might be located in another\nplace.<li><p><strong>Large heap.</strong> The application has requested large\nheap size i.e., more space in memory (RAM) is requested for dynamic\nallocation. It is still up to the operating system to decide whether to\nallocate large space for the application. App Manager, for example,\nrequests large heap size because it needs to load an entire APK into\nmemory while scanning an APK.<li><p><strong>Open links.</strong> The application may open certain\nlinks from any applications. If the application can open any links by\ndefault, the color of the tag would be red, dark cyan if otherwise.\nClicking on the tag opens a dialog with the supported hosts or domains\nlisted. In Android 12 onwards, it displays an option to enable or\ndisable opening links by default provided App Manager has sufficient\npermissions. Otherwise, it displays an option to open the system\nsettings page for the application.<li><p><strong>Running.</strong> One or more services of the application\nis currently running in the background. Clicking on the tag opens a\ndialog containing the list of running services. Clicking on any services\nopens the log viewer with default filter set to the UID associated with\nthe service (which can be different from the UID of the application if\nit is running in a separate or isolated process) provided the log viewer\nfeature is enabled. There’s also an option to force-stop the\napplication.<li><p><strong>Stopped.</strong> The application is force stopped. This\nmay not prevent it from running automatically later.<li><p><strong>Disabled.</strong> Denotes that the application is\ndisabled (hidden from the launcher).<li><p><strong>Suspended.</strong> Denotes that the application is\nsuspended (grayed out in the launcher).<li><p><strong>Hidden.</strong> Denotes that the application is hidden\n(hidden from the launcher).<li><p><strong>MagiskHide.</strong> MagiskHide is enabled for the\napplication. Clicking on the tag opens a dialog containing the list of\nprocess names within the application that can be added to or removed\nfrom the MagiskHide list.<li><p><strong>MagiskDenyList.</strong> The application is present in\nMagisk DenyList. Clicking on the tag opens a dialog containing the list\nof process names within the application that can be added to or removed\nfrom Magisk DenyList.<li><p><strong>WX.</strong> The application violates the “W^X policy”\nand is capable of writing and executing in the same directory or in the\nsame portion of memory. This allows the execution of arbitrary\nexecutables either by the modification of executables embedded within\nthe application or by downloading them from the Internet.<br><div class=seealso-inline><p><em>Ver también: <span><a href=https://en.wikipedia.org/wiki/W%5EX>W^X in\nWikipedia</a></span></em></div><li><p><strong>Bloatware.</strong> The application may be a known\nbloatware. Clicking on the tag opens a dialog containing detailed\ninformation in addition to suggestions (if available).<li><p><strong>KeyStore.</strong> The application has items in the\nAndroid KeyStore. Clicking on the tag opens a dialog containing all the\nKeyStore files that belong to the application.<li><p><strong>Backup.</strong> The application was backed up using App\nManager at least once. Clicking on the tag opens a dialog containing all\nthe available backups along with metadata.<li><p><strong>No battery optimisation.</strong> Battery optimisation is\ndisabled for the application. It is possible to re-enable battery\noptimisation by clicking on the tag.<li><p><strong>Sensors disabled.</strong> Sensors are disabled for the\napplication. Sensors are disabled for most applications by\ndefault.<li><p><a href=#sec:net-policy><strong>Net policy.</strong></a>\nNetwork policy (e.g., background data usage) is configured for the\napplication. Clicking on the tag displays a dialog containing the\nsupported policies for the platform along with the options to configure\nthem.<li><p><a href=#sec:terminologies><strong>SSAID.</strong></a> Clicking\non the tag opens a dialog containing the current SSAID assigned to the\napplication. It is also possible to reset/regenerate the SSAID if\nneeded.<li><p><strong>SAF.</strong> Denotes that the application has been\ngranted to access one or more storage locations or files i.e. URIs via\nStorage Access Framework (SAF). Clicking on the tag opens a dialog\ncontaining the list of granted URIs.<li><p><strong>Play App Signing.</strong> Indicates that the application\nmight be signed by Google.<li><p><strong>Xposed.</strong> Indicates that the application may be an\nXposed module. Clicking on the tag displays a dialog with additional\ninformation.<li><p><strong>Static Shared Library.</strong> Denotes that the\napplication serves as a static shared library for one or more\napplications. Clicking on the tag opens a dialog containing a list of\ninstalled versions of the library along with an option to uninstall\nthem.<div class=\"amalert tip\"><p><strong><em>Notice.</em></strong><p>The trichrome library (supplied by Google Chrome, Vanadium or similar\nprojects) is currently the only known static shared library on\nAndroid.</div></ul></section><section id=subsubsec:horizontal-action-panel class=level4 data-number=2.2.2.3><h4 data-number=2.2.2.3><span class=header-section-number>2.2.2.3</span> Panel de acción\nhorizontal<a href=#subsubsec:horizontal-action-panel class=anchor aria-hidden=true></a></h4><p>Horizontal Action Panel, as described in the previous section,\nconsists of various application-related actions, such as–<ul class=incremental><li><p><strong>Launch.</strong> Launch the application provided it has a\nlauncher <a href=#subsubsec:activities>activity</a>.<li><p><strong>Freeze.</strong> Freeze the application. This button is\nnot displayed if it is already frozen or the user does not have enough\nprivileges. After the application is frozen, it may be hidden from the\napp drawer depending on how it was configured. Shortcuts configured by\nthe application may also be removed. The application may only be\nunfrozen via App Manager, <code>pm</code> command or any other tools\nthat offer such a feature. Long clicking on the button opens a dialog\nwhere a shortcut can be configured to quickly freeze or unfreeze the\napplication.<li><p><strong>Uninstall.</strong> Uninstall the application with a\nprompt. In the dialog prompt, it is possible to uninstall updates of a\nsystem application, or if App Manager has enough privileges or the\noperating system supports it, it is possible to uninstall the\napplication without clearing its data and signature. For the latter\ncase, the installed application must match the signature with the\npreviously installed application if it is installed again.<div class=\"amalert tip\"><p><strong><em>Tips.</em></strong><p>A better way to reinstall an application with a different signature\nwould be to back up its data using App Manager and restore it again\nafter installing the application instead of opting to preserving data\nand signature of the application during uninstallation as this option\nmay cause undefined behaviour in the future.</div><li><p><strong>Unfreeze.</strong> Unfreeze the application. This button\nis not displayed if it is already enabled or the user does not have\nenough privileges. Similar to the <em>Freeze</em> button, long clicking\non the button opens a dialog where a shortcut can be configured to\nquickly freeze or unfreeze the application.<li><p><strong>Force Stop.</strong> Force-stop the application.<li><p><strong>Clear Data.</strong> Clear data from the application.\nThis includes any information stored in the internal and, recently, the\nexternal directories, including accounts (if set by the application),\ncache, etc. Clearing data from App Manager, for example, removes all the\nrules (the blocking is not removed though) saved within the application\n(Which is why you should always take backups of your rules). This button\nis not displayed if the user does not have enough privileges.<li><p><strong>Clear Cache.</strong> Clear the application cache. If the\napplication is running during the operation, the cache may not be\ncleared as expected.<li><p><strong>Install.</strong> Install the application, only displayed\nif the application hasn’t already been installed.<li><p><strong>What’s New.</strong> Displayed for an external\napplication if an older version of it is already installed. Clicking on\nthis button opens a dialog containing the differences between this and\nthe installed version in a version control manner. Changes include\n<em>version</em>, <em>trackers</em>, <em>permissions</em>,\n<em>components</em>, <em>signatures</em> (only checksum changes),\n<em>features</em>, <em>shared libraries</em> and <em>SDK</em>.<li><p><strong>Update.</strong> Displayed if the application has a\nhigher version code than the installed application.<li><p><strong>Reinstall.</strong> Displayed if the application has the\nsame version code as the installed application.<li><p><strong>Downgrade.</strong> Displayed if the application has a\nlower version code than the installed application.<li><p><strong>Manifest.</strong> Opens the application’s manifest file\nin a separate page. If the application has more than one split, it will\ndisplay the list of split APK files, and clicking on an item will open\nthe corresponding manifest file instead.<li><p><strong>Scanner.</strong> Scan the application in order to list\npotential trackers and libraries. It also scans the file using\nVirusTotal and fetch results from Pithus if configured.<br><div class=seealso-inline><p><em>Ver también: <span><a href=#sec:scanner-page>Scanner\npage</a></span></em></div><li><p><strong>Shared Prefs.</strong> Displays a list of shared\npreferences used by the application. Clicking on a preference item in\nthe list opens the <a href=#sec:shared-preferences-editor-page>Shared\nPreferences Editor page</a>. This option is only visible if the user has\nthe required privileges.<li><p><strong>Databases.</strong> Displays a list of databases used by\nthe application. Clicking on an item opens a list of activities that can\nopen the database. This option is only visible if the user has the\nrequired privileges.<li><p><strong>F-Droid.</strong> Open the application in the selected\n<em>F-Droid</em> client.<li><p><strong>Store.</strong> Open the application in <em>Aurora\nStore</em>. The option is only visible if <em>Aurora Store</em> is\ninstalled.</ul></section><section id=subsubsec:app-info-options-menu class=level4 data-number=2.2.2.4><h4 data-number=2.2.2.4><span class=header-section-number>2.2.2.4</span> Opciones de menú<a href=#subsubsec:app-info-options-menu class=anchor aria-hidden=true></a></h4><p>Options-menu is located in the top-right corner of the page. A\ncomplete description of the options present there are given below:<ul class=incremental><li><p><strong>Share.</strong> Share button can be used to share the APK\nor (if the application is has multiple splits, OBB files or any\ndependencies) <em>APKS</em> file extracted from the\napplication.<li><p><strong>Refresh.</strong> Refresh the App Info tab.<li><p><strong>View in Settings.</strong> Open the application in\nAndroid Settings.<li><p><strong>Backup/restore.</strong> Open the backup/restore\ndialog.<li><p><strong>Export blocking rules.</strong> Export rules configured\nfor the application within App Manager.<li><p><strong>Open in Termux.</strong> Open the application in Termux.\nThis actually runs <code>su - user_id</code> where <code>user_id</code>\ndenotes the application’s kernel user ID (described in §<a href=#subsubsec:app-info-general-information data-reference-type=ref data-reference=subsubsec:app-info-general-information>2.2.2.1</a>).\nThis option is only visible to the root users. See §<a href=#subsubsec:config-termux data-reference-type=ref data-reference=subsubsec:config-termux>2.2.2.5</a> to learn how to\nconfigure Termux to run commands from third-party applications.<li><p><strong>Run in Termux.</strong> Open the application via\n<code>run-as package_name</code> in Termux. This is only applicable to\nthe debuggable applications and works for both root and ADB users. See\n§<a href=#subsubsec:config-termux data-reference-type=ref data-reference=subsubsec:config-termux>2.2.2.5</a> to learn how to\nconfigure Termux to run commands from third-party applications.<li><p><strong>MagiskHide.</strong> Open a dialog containing the list of\nprocess names within the application that can be added or removed from\nthe MagiskHide list.<li><p><strong>Magisk DenyList.</strong> Open a dialog containing the\nlist of process namees within the application that can be added or\nremoved from Magisk DenyList.<li><p><strong>Battery optimisation.</strong> Enable/disable battery\noptimisation for this application.<li><p><strong>Sensors.</strong> Enable/disable sensors for this\napplication.<li><p><a href=#sec:net-policy><strong>Net policy.</strong></a>\nConfigure network policy (e.g., background data usage) for the\napplication.<li><p><strong>Extract Icon.</strong> Extract and save the application’s\nicon in the shared storage.<li><p><strong>Optimize.</strong> Perform optimisation for this\napplication. This option is for advanced users only.<li><p><strong>Add to profile.</strong> Add the application to one of\nthe configured <a href=#sec:profile-page>profiles</a>.<li><p><strong>Install for….</strong> Install the application for\nanother user and/or in the work profile if configured.</ul></section><section id=subsubsec:config-termux class=level4 data-number=2.2.2.5><h4 data-number=2.2.2.5><span class=header-section-number>2.2.2.5</span> Configurar Termux<a href=#subsubsec:config-termux class=anchor aria-hidden=true></a></h4><p>By default, Termux does not allow running commands from a third-party\napplication. To use this option, Termux v0.96 or later is required and\n<code>allow-external-apps=true</code> must be added in\n<code>~/.termux/termux.properties</code>.<div class=\"amalert tip\"><p><strong><em>Info.</em></strong><p>Enabling this option does not weaken Termux’ security. The\nthird-party applications still need to ask the user to allow running\narbitrary commands in Termux.</div></section></section><section id=subsec:component-tabs class=level3 data-number=2.2.3><h3 data-number=2.2.3><span class=header-section-number>2.2.3</span>\n<a href=#toc:subsec:component-tabs>Pestañas de componentes</a><a href=#subsec:component-tabs class=anchor aria-hidden=true></a></h3><p><strong>Activities</strong>, <strong>Services</strong>,\n<strong>Receivers</strong> (i.e., broadcast receivers) and\n<strong>Providers</strong> (e.g., content providers) are collectively\nknown as the application components, because they offer similar features\nand share similar properties. For example, they all have a\n<em>name</em>, a <em>label</em>, an <em>icon</em>, can be enabled or\ndisabled, and can be executed via <em>Intent</em>. Application\ncomponents are the building blocks of an application and must be\ndeclared in the application manifest (with a few exceptions).\nApplication manifest is a file where application specific metadata are\nstored. The Android operating system learns what to do with the\napplication by reading the metadata.<p>Colours used in these tabs are explained in §<a href=#subsec:app-details-colour-codes data-reference-type=ref data-reference=subsec:app-details-colour-codes>2.2.1</a>. It is also\npossible to sort the list of components to display blocked or tracker\ncomponents on top of the list via the <strong>Sort</strong> option\nlocated in the three-dots menu.<section id=subsubsec:activities class=level4 data-number=2.2.3.1><h4 data-number=2.2.3.1><span class=header-section-number>2.2.3.1</span> Actividades<a href=#subsubsec:activities class=anchor aria-hidden=true></a></h4><p><strong>Activities</strong> are the windows or pages that can be\nuniquely identified by the Android operating system (e.g., <em>Main\npage</em> and <em>App Details page</em> are two activities). Each\nactivity can have multiple UI components known as <em>widgets</em> or\n<em>fragments</em>, and each component can be nested or placed on top of\neach other. The developer can also choose to open external files, links,\netc. within an activity using a method called <em>intent filters</em>.\nFor example, when you open a file in your file manager, either your file\nmanager or the operating system scans the intent filters via\nPackageManager, find the activities capable of opening the file, and\nlist those activities so that you can choose your preferred\nactivity.<p>Activities that are <em>exportable</em> can be opened by any\nthird-party applications. However, Some activities may require\npermissions, and only an application having those permissions can open\nthem. In the <em>Activities</em> tab, certain activities can be launched\nvia the <strong>Launch</strong> button. If it is necessary to supply\nadditional information, such as Intent extras, data or action, long\nclicking on the <strong>Launch</strong> button opens the <a href=#sec:interceptor-page>Activity Interceptor</a> page which\nprovides such features.<div class=\"amalert tip\"><p><strong><em>Tip.</em></strong><p>No-root users can grant\n<code>android.permission.WRITE_SECURE_SETTINGS</code> via ADB to launch\n<em>non-exportable</em> activities.</div><div class=\"amalert tip\"><p><strong><em>Notice.</em></strong><p>If launching an activity throws an error, it may have certain\ndependencies which are not met (e.g., <em>App Details</em> page in App\nManager cannot be launched using the launch button, because it requires\na package name). Since the dependencies cannot be inferred\nprogrammatically, the activity may not be opened from App Manager by\ndefault.</div><p>It is also possible to create shortcuts of an activity-launch using\nthe <strong>Create shortcut</strong> button. If you need to supply\nadditional information, you can create a shortcut from the Activity\nInterceptor page instead.<div class=\"amalert danger\"><p><strong><em>Caution.</em></strong><p>If you uninstall App Manager, all shortcuts created by App Manager\nwill be lost.</div></section><section id=subsubsec:details:servcies class=level4 data-number=2.2.3.2><h4 data-number=2.2.3.2><span class=header-section-number>2.2.3.2</span> Servicios<a href=#subsubsec:details:servcies class=anchor aria-hidden=true></a></h4><p>Unlike <a href=#subsubsec:activities>activities</a> that users can\nsee, <strong>Services</strong> handle background tasks. For example, if\nyou’re downloading a video from the internet using your phone’s Internet\nbrowser, the Internet browser is using a <em>foreground service</em> to\ndownload the content.<p>When an activity is closed or removed from the <em>Recents</em> page,\nit may be destroyed immediately depending on the amount free memory the\nphone has, battery statistics, or how the activity is configured. But\nservices can be run indefinitely if desired. If more services run in the\nbackground, the phone may become slower due to the shortage of memory\nand/or processing power, and the phone’s battery will be drained more\nquickly. Newer versions of Android come with a battery optimisation\nfeature enabled by default for all applications. With this feature\nenabled, the system can randomly terminate any service depending on the\namount of resources the system has or the service requires. However,\nforeground services (i.e., services that run with a fixed notification,\nsuch as music player or downloader) are not typically terminated unless\nthe system is very low on resources (memory, battery, etc.). Certain\nstock ROMs can offer more aggressive optimisation. MIUI, for example,\nhas a very aggressive optimisation feature known as the <em>MIUI\noptimisation</em>.<p>Both activities and services are run in the same <a href=https://stackoverflow.com/questions/7597742>looper</a> called the\nmain looper, which means the services do not really run in the\nbackground. It is the task of the developer to ensure this. How do the\napplication communicate with the services? It uses <a href=#subsubsec:app-details-receivers>broadcast receiver</a> or\nBinder.</section><section id=subsubsec:app-details-receivers class=level4 data-number=2.2.3.3><h4 data-number=2.2.3.3><span class=header-section-number>2.2.3.3</span> Receptores<a href=#subsubsec:app-details-receivers class=anchor aria-hidden=true></a></h4><p><strong>Receivers</strong> (also called <em>broadcast receivers</em>)\ncan be used to trigger execution of certain tasks when certain events\noccur. These components are called broadcast receivers, because they are\nexecuted as soon as a broadcast message is received. These broadcast\nmessages are sent using a method called <em>Intent</em>. Intent is a\nspecial feature in Android that can be used to open applications (i.e.,\nactivities), run services and send broadcast messages. Therefore, like\n<a href=#subsubsec:activities>activities</a>, broadcast receivers use\n<em>intent filters</em> to receive the desired broadcast messages.\nBroadcast messages can be sent by the system or the application itself.\nWhen a broadcast message is sent, the corresponding receivers are\nactivated by the system so that they can execute tasks. For example, if\nyour phone is low on resources, it may freeze or experience lags for a\nmoment after you enable mobile data or connect it to the Wi-Fi. This is\nbecause broadcast receivers that can receive\n<code>android.net.conn.CONNECTIVITY_CHANGE</code> are activated by the\nsystem as soon as the data connection is enabled. Since many\napplications typically use this intent filter, they are all activated\nalmost immediately by the system which causes the freezing or lags.<p>Receivers can also be used for inter-process communication (IPC),\ni.e., it can be used to communicate across multiple applications or even\ndifferent components of a single application.</section><section id=subsubsec:providers class=level4 data-number=2.2.3.4><h4 data-number=2.2.3.4><span class=header-section-number>2.2.3.4</span> Proveedores<a href=#subsubsec:providers class=anchor aria-hidden=true></a></h4><p><strong>Providers</strong> are primarily used for data management.\nFor example, when you save an APK file or export rules in App Manager,\nit uses a content provider called <code>.fm.FmProvider</code> to save\nthe APK or export the rules. There are many providers, including the\nones provided by the system, that can be used to manage various\ncontent-related tasks, such as database management, tracking, searching,\netc. Each provider has a field called <em>Authority</em> which is unique\nto the application in the entire Android ecosystem just as the package\nname.</section><section id=características-adicionales-para-dispositivos-con-acceso-raíz class=level4 data-number=2.2.3.5><h4 data-number=2.2.3.5><span class=header-section-number>2.2.3.5</span> Características adicionales\npara dispositivos con acceso raíz<a href=#características-adicionales-para-dispositivos-con-acceso-raíz class=anchor aria-hidden=true></a></h4><p>A diferencia de los usuarios no-root, que son en su mayoría\nespectadores en estas pestañas, los usuarios root pueden realizar varias\noperaciones.<section id=bloqueo-de-componentes class=level5 data-number=2.2.3.5.1><h5 data-number=2.2.3.5.1><span class=header-section-number>2.2.3.5.1</span> Bloqueo de componentes<a href=#bloqueo-de-componentes class=anchor aria-hidden=true></a></h5><p>On the right-most side of each component item, there is a switch\nwhich can be used to toggle the blocking status of that particular\ncomponent. If <a href=#subsubsec:instant-component-blocking>Instant\nComponent Blocking</a> is not enabled or blocking is never applied to\nthe application before, it is required to apply the changes using the\n<strong>Apply rules</strong> option in three-dots menu. It is also\npossible to remove the already-applied rules using the same option\n(which would be read as <strong>Remove rules</strong> this time).<p>It is also possible to block the component using one of the several\nmethods by long clicking on the button.<div class=seealso-inline><p><em>Ver también: <span><a href=#sec:faq:app-components>FAQ: App\nComponents</a></span></em></div></section><section id=par:appdetails:blocking-trackers class=level5 data-number=2.2.3.5.2><h5 data-number=2.2.3.5.2><span class=header-section-number>2.2.3.5.2</span> Bloqueo de rastreadores<a href=#par:appdetails:blocking-trackers class=anchor aria-hidden=true></a></h5><p>It is possible to disable tracker components using the <strong>Block\ntracker</strong> option in the three-dots menu. All tracker components\nwill be blocked regardless of the tab you’re currently in.<div class=\"amalert tip\"><p><strong><em>Info.</em></strong><p>Tracker components are a subset of application components. Therefore,\nthey are blocked using the same method used for blocking any other\ncomponents.</div><div class=seealso><p><em>Ver también:</em><ul class=incremental><li><p><a href=#subsec:tracker-classes-versus-tracker-components>FAQ:\nTracker classes versus tracker components</a><li><p><a href=#sec:scanner-page>Scanner Page</a><li><p><a href=#subsec:block-unblock-trackers>1-Click Ops Page:\nBlock/Unblock Trackers</a></ul></div></section></section></section><section id=subsec:permission-tabs class=level3 data-number=2.2.4><h3 data-number=2.2.4><span class=header-section-number>2.2.4</span>\n<a href=#toc:subsec:permission-tabs>Pestañas de permisos</a><a href=#subsec:permission-tabs class=anchor aria-hidden=true></a></h3><p><strong>App Ops</strong>, <strong>Uses Permissions</strong> and\n<strong>Permissions</strong> tabs are related to permissions. In Android\ncommunication across applications or processes not having the same\nidentity (known as <em>shared ID</em>) often require permissions. These\npermissions are managed by the permission controller. Some permissions\nare considered <em>normal</em> permissions which are granted\nautomatically if they appear in the application manifest, but\n<em>dangerous</em> and <em>development</em> permissions require\nconfirmation from the user. Colours used in these tabs are explained in\n§<a href=#subsec:app-details-colour-codes data-reference-type=ref data-reference=subsec:app-details-colour-codes>2.2.1</a>.<section id=subsubsec:app-ops class=level4 data-number=2.2.4.1><h4 data-number=2.2.4.1><span class=header-section-number>2.2.4.1</span> Operaciones de\naplicaciones<a href=#subsubsec:app-ops class=anchor aria-hidden=true></a></h4><p><strong>App Ops</strong> stands for <strong>Application\nOperations</strong>. Since Android 4.3, <em>App Ops</em> are used by\nAndroid to control many system permissions. Each app op has a unique\nnumber associated with it which is displayed along with the private name\nof the operation in the App Ops tab. Some app ops also have a public\nname. A large number of app ops are also associated with\n<em>permissions</em>. In this tab, an app op is considered dangerous if\nits associated permission is marked as dangerous. Other information such\nas <em>flags</em>, <em>permission name</em>, <em>permission\ndescription</em>, <em>package name</em>, <em>group</em> are also taken\nfrom the associated <a href=#subsubsec:permissions>permission</a>.\nOthers may include the following:<ul class=incremental><li><p><strong>Mode.</strong> It describes the current authorisation\nstatus which can be <em>allow</em>, <em>deny</em> (a rather misnomer, it\nsimply means error), <em>ignore</em> (it actually means deny),\n<em>default</em> (inferred from a list of defaults set internally by the\nvendor or the AOSP), <em>foreground</em> (in newer Android versions, it\nmeans the app op can only be used when the application is running in\nforeground), and some custom modes set by the vendors (MIUI uses\n<em>ask</em>, for example).<li><p><strong>Duration.</strong> The amount of time this app op has\nbeen used (there can be negative durations whose use cases are currently\nunknown to me).<li><p><strong>Accept Time.</strong> Last time the app op was\naccepted.<li><p><strong>Reject Time.</strong> Last time the app op was\nrejected.</ul><div class=\"amalert tip\"><p><strong><em>Info.</em></strong><p>Contents of this tab are visible to no-root users if\n<code>android.permission.GET_APP_OPS_STATS</code> is granted via\nADB.</div><p>There is a toggle button next to each app op item which can be used\nto allow or deny (ignore) it. Other supported modes can also be set by\nlong clicking on the toggle button. If the desired app op is not listed\nin the tab, <em>Set custom app op</em> option in the menu can be used\ninstead. It is also possible to reset the changes using the <em>Reset to\ndefault</em> option, or deny all the dangerous app ops using the\ncorresponding option in the menu. Due to the nature how app ops work,\nthe system may take some time to apply them.<div class=\"amalert tip\"><p><strong><em>Tip.</em></strong><p>Denying certain app ops may cause the application to misbehave. If\nall attempts fail, <em>reset to default</em> option can be used as the\nlast resort.</div><p>It is possible to sort the list in ascending order by app op names\nand the associated unique numbers (or values), or list the denied app\nops first using the corresponding sorting options.<div class=seealso-inline><p><em>Ver también: <span><a href=#ch:app-ops>Appendix: App\nOps</a></span></em></div></section><section id=permisos-de-uso class=level4 data-number=2.2.4.2><h4 data-number=2.2.4.2><span class=header-section-number>2.2.4.2</span> Permisos de uso<a href=#permisos-de-uso class=anchor aria-hidden=true></a></h4><p><strong>Uses Permissions</strong> are the permissions used by the\napplication. This is named so because they are specified in the manifest\nusing <code>uses-permission</code> tags. Information such as\n<em>flags</em>, <em>permission name</em>, <em>permission\ndescription</em>, <em>package name</em>, <em>group</em> are taken from\nthe associated <a href=#subsubsec:permissions>permission</a>.<p>Privileged users can grant or revoke the <em>dangerous</em> and\n<em>development</em> permissions via the toggle button on the right side\nof each permission item. It is also possible revoke dangerous\npermissions all at once using the corresponding option in the menu. Only\nthese two types of permissions can be revoked because Android does not\nallow the modification of <em>normal</em> permissions (which most of\nthem are). It might still be possible to revoke them by editing\n<code>runtime-permissions.xml</code> itself, but whether this is a\npossibility is still being investigated.<div class=\"amalert tip\"><p><strong><em>Info.</em></strong><p>Since dangerous permissions are revoked by default by the system,\nrevoking all dangerous permissions is the same as resetting all the\npermissions.</div><p>It is possible to sort the permissions by their name (in ascending\norder) or choose to display denied or dangerous permissions at first\nusing the corresponding options in the menu.</section><section id=subsubsec:permissions class=level4 data-number=2.2.4.3><h4 data-number=2.2.4.3><span class=header-section-number>2.2.4.3</span> Permisos<a href=#subsubsec:permissions class=anchor aria-hidden=true></a></h4><p><strong>Permissions</strong> are usually custom permissions defined\nby the application itself. These type of permissions are marked as\n<em>Internal</em> permissions. It also contains permissions declared by\nother applications which are marked as <em>External</em> permissions. An\nexternal permission can be specified in an <em>exported</em> application\ncomponent so that another application may invoke the component only if\nit holds the permission. Below is a complete description of each item\ndisplayed in this tab:<ul class=incremental><li><p><strong>Name.</strong> A permission has a unique name (e.g.,\n<code>android.permission.INTERNET</code>) that multiple applications can\nrequest. The application that declared the permission is automatically\ngranted and cannot be revoked.<li><p><strong>Icon.</strong> Each permission can have a custom icon.\nThe other permission tabs do not have any icon because they do not\ncontain any icon in the application manifest.<li><p><strong>Description.</strong> This optional field describes the\npermission. If there isn’t any description associated with the\npermission, the field is not displayed.<li><p><strong>Flags.</strong> (Uses the flag symbol or\n<strong>Protection Level</strong> name) This describes various\npermission flags such as <em>normal</em>, <em>development</em>,\n<em>dangerous</em>, <em>instant</em>, <em>granted</em>,\n<em>revoked</em>, <em>signature</em>, <em>privileged</em>, etc.<li><p><strong>Package Name.</strong> Denotes the package name\nassociated with the permission, i.e. the package that defined the\npermission.<li><p><strong>Group.</strong> The group name associated with the\npermission (if any). Several related permissions can often be grouped\ntogether.</ul></section></section><section id=subsec:signatures-tab class=level3 data-number=2.2.5><h3 data-number=2.2.5><span class=header-section-number>2.2.5</span>\n<a href=#toc:subsec:signatures-tab>Pestañas de firmas</a><a href=#subsec:signatures-tab class=anchor aria-hidden=true></a></h3><p><strong>Signatures</strong> are actually called signing information.\nAn application is signed with one or more signing keys by its developer\nbefore publishing it. The integrity of an application, i.e., whether the\napplication is from the actual developer and has not been modified by\nanother person, can be checked using the signing certificate included in\nthe APK files. This is because when an application is modified by an\nunauthorised entity, the application can longer be signed with the\noriginal signing keys since the signing keys are unknown to the entity.\nOne way to verify the integrity of an application is via the checksums\ngenerated from the certificates. If the developer supplies the checksums\nfor the signing certificates, they can be compared against the checksums\ngenerated in the <strong>Signatures</strong> tab to verify the\napplication. For example, if you have downloaded App Manager from GitHub\nor Telegram Channel, you can verify whether the application was actually\nreleased by me by simply matching the following <em>SHA256</em> checksum\nwith the one displayed in this tab:<pre><code>320c0c0fe8cef873f2b554cb88c837f1512589dcced50c5b25c43c04596760ab</code></pre><p>Several hashing algorithms are used to generate checksums in this\ntab. They include <em>MD5</em>, <em>SHA1</em>, <em>SHA256</em> and\n<em>SHA512</em>.<div class=\"amalert danger\"><p><strong><em>Caution.</em></strong><p>Signing information should be verified using a reliable hashing\nalgorithm, such as <em>SHA256</em>. DO NOT rely on <em>MD5</em> or\n<em>SHA1</em> checksums as they are known to generate the same checksums\nfor multiple certificates.</div></section><section id=subsec:uses-features-tab class=level3 data-number=2.2.6><h3 data-number=2.2.6><span class=header-section-number>2.2.6</span>\n<a href=#toc:subsec:uses-features-tab>Uses Features tab</a><a href=#subsec:uses-features-tab class=anchor aria-hidden=true></a></h3><p><strong>Uses Features</strong> tab lists the features declared by the\napplication, such as OpenGL ES, telephony, and leanback. Some features\ncan be required by the application, and some features can be optional.\nRequired features must be present in the system along with the required\nversion. Otherwise, any attempt to install the application will be\ndenied by the system. Colours used in this tab are explained in §<a href=#subsec:app-details-colour-codes data-reference-type=ref data-reference=subsec:app-details-colour-codes>2.2.1</a>.</section><section id=subsec:configurations-tab class=level3 data-number=2.2.7><h3 data-number=2.2.7><span class=header-section-number>2.2.7</span>\n<a href=#toc:subsec:configurations-tab>Configurations tab</a><a href=#subsec:configurations-tab class=anchor aria-hidden=true></a></h3><p><strong>Configurations</strong> tab lists the configurations required\nby the application, such as input method type (qwerty, 12 key), touch\nscreen type (finger, stylus, etc.), and navigation type (dial pad,\ntrackball, wheel). This tab is going to be empty for most\napplications.</section><section id=subsec:shared-libs-tab class=level3 data-number=2.2.8><h3 data-number=2.2.8><span class=header-section-number>2.2.8</span>\n<a href=#toc:subsec:shared-libs-tab>Shared Libraries Tab</a><a href=#subsec:shared-libs-tab class=anchor aria-hidden=true></a></h3><p><strong>Shared libraries</strong> tab lists the legacy JAR\ndependencies, any static shared library dependencies (currently, the\nonly known cases are the Chromium-based browsers and WebViews) as well\nas the JNI (Java native interface) libraries. For JNI libraries, it\nspecifies platform (x86/x86_64/ARM/AArch64), architecture (32/64 bit),\nobject type (shared object or executable), etc.</section></section><section id=sec:1-click-ops-page class=level2 data-number=2.3><h2 data-number=2.3><span class=header-section-number>2.3</span> <a href=#toc:sec:1-click-ops-page>Página de operaciones con 1 clic</a><a href=#sec:1-click-ops-page class=anchor aria-hidden=true></a></h2><p>This page is displayed on selecting the <a href=#subsubsec:main:1-click-ops>1-Click Ops option</a> in the <a href=#subsec:main-page-options-menu>main menu</a>.<section id=subsec:block-unblock-trackers class=level3 data-number=2.3.1><h3 data-number=2.3.1><span class=header-section-number>2.3.1</span>\n<a href=#toc:subsec:block-unblock-trackers>Bloquear/desbloquear\nrastreadores</a><a href=#subsec:block-unblock-trackers class=anchor aria-hidden=true></a></h3><p>This option can be used to block or unblock the ad/tracker components\nfrom the installed applications. On selecting this option, App Manager\nwill ask if it should list trackers from all the applications or only\nfrom the user applications. Novice users should avoid blocking trackers\nfrom the system applications in order to avoid bad consequences. After\nthat, a multi-choice dialog box will appear where it is possible to\nexclude one or more applications from this operation. The changes are\napplied immediately on pressing the <em>block</em> or <em>unblock</em>\nbutton.<div class=\"amalert warning\"><p><strong><em>Notice.</em></strong><p>Certain applications may not function as expected after blocking\ntheir trackers. If that is the case, remove the blocking rules all at\nonce or one by one in the component tabs of the <a href=#sec:app-details-page>App Details page</a> for the corresponding\napplication.</div><div class=seealso-inline><p><em>Ver también: <span><a href=#par:appdetails:blocking-trackers>App Details Page: Blocking\nTrackers</a></span></em></div></section><section id=subsec:block-components-dots class=level3 data-number=2.3.2><h3 data-number=2.3.2><span class=header-section-number>2.3.2</span>\n<a href=#toc:subsec:block-components-dots>Componentes de bloque</a><a href=#subsec:block-components-dots class=anchor aria-hidden=true></a></h3><p>This option can be used to block certain application components as\nspecified by their signatures. A signature of a component is the full\nname or partial name of the component. For safety, it is recommended to\nadd a <code>.</code> (dot) at the end of each partial signature, because\nthe underlying algorithm searches and matches the components in a greedy\nmanner. It is also possible to insert more than one signature in which\ncase all the signatures have to be separated by white spaces. Similar to\nthe option above, there is also an option to apply blocking to the\nsystem applications.<div class=\"amalert danger\"><p><strong><em>Caution.</em></strong><p>If you are not aware of the consequences of blocking applcations\ncomponents by their signatures, you should avoid using this option as it\nmay result in bootloop or soft brick, and you may have to apply factory\nreset as a result.</div></section><section id=subsec:set-mode-for-app-ops-dots class=level3 data-number=2.3.3><h3 data-number=2.3.3><span class=header-section-number>2.3.3</span>\n<a href=#toc:subsec:set-mode-for-app-ops-dots>Set Mode for App\nOps…</a><a href=#subsec:set-mode-for-app-ops-dots class=anchor aria-hidden=true></a></h3><p>This option can be used to configure certain <a href=#ch:app-ops>applcation operations</a> of all or selected\napplications. There are two fields. The first field can be used to\ninsert more than one app op constants (either names or values) separated\nby white spaces. It is not always possible to know in advance about all\nthe app op constants as they vary from device to device and from OS to\nOS. Desired app op constant can be found in the <em>App Ops</em> tab\nlocated in the <a href=#sec:app-details-page>App Details page</a>. The\nsecond field can be used to insert or select one of the <a href=#subsec:mode-constants>modes</a> that will be set against the\nspecified app ops.<div class=\"amalert danger\"><p><strong><em>Caution.</em></strong><p>Unless you are well-informed about app ops and the consequences of\nblocking them, you should avoid using this option.</div></section><section id=subsec:1-click-back-up class=level3 data-number=2.3.4><h3 data-number=2.3.4><span class=header-section-number>2.3.4</span>\n<a href=#toc:subsec:1-click-back-up>Apoyar</a><a href=#subsec:1-click-back-up class=anchor aria-hidden=true></a></h3><p>1-Click options for back up. As a precaution, it lists the affected\nbackups before performing any operation.<section id=back-up-all-apps. class=level5 data-number=2.3.4.0.1><h5 data-number=2.3.4.0.1><span class=header-section-number>2.3.4.0.1</span> Back up all apps.<a href=#back-up-all-apps. class=anchor aria-hidden=true></a></h5><p>Back up all the installed applications.</section><section id=redo-existing-backups. class=level5 data-number=2.3.4.0.2><h5 data-number=2.3.4.0.2><span class=header-section-number>2.3.4.0.2</span> Redo existing backups.<a href=#redo-existing-backups. class=anchor aria-hidden=true></a></h5><p>Back up all the installed applications that have a previous\nbackup.</section><section id=back-up-apps-without-backups. class=level5 data-number=2.3.4.0.3><h5 data-number=2.3.4.0.3><span class=header-section-number>2.3.4.0.3</span> Back up apps without\nbackups.<a href=#back-up-apps-without-backups. class=anchor aria-hidden=true></a></h5><p>Back up all the installed applications without a previous backup.</section><section id=verify-and-redo-backups. class=level5 data-number=2.3.4.0.4><h5 data-number=2.3.4.0.4><span class=header-section-number>2.3.4.0.4</span> Verify and redo\nbackups.<a href=#verify-and-redo-backups. class=anchor aria-hidden=true></a></h5><p>Verify the recently made backups of the installed applications and\nredo backup if necessary.</section><section id=back-up-apps-with-changes. class=level5 data-number=2.3.4.0.5><h5 data-number=2.3.4.0.5><span class=header-section-number>2.3.4.0.5</span> Back up apps with\nchanges.<a href=#back-up-apps-with-changes. class=anchor aria-hidden=true></a></h5><p>If an app has changed since the last backup, redo its backup. It\nchecks a number of indices including application version, last update\ndate, last launch date, integrity and file hashes. Directory hashes are\ntaken during the backup process and are stored in a database. On running\nthis operation, new hashes are taken and compared with the ones kept in\nthe database.</section></section><section id=subsec:1-click-restore class=level3 data-number=2.3.5><h3 data-number=2.3.5><span class=header-section-number>2.3.5</span>\n<a href=#toc:subsec:1-click-restore>Restaurar</a><a href=#subsec:1-click-restore class=anchor aria-hidden=true></a></h3><p>1-Click options for restore. As a precaution, it lists the affected\nbackups before performing any operation.<section id=restore-all-apps. class=level5 data-number=2.3.5.0.1><h5 data-number=2.3.5.0.1><span class=header-section-number>2.3.5.0.1</span> Restore all apps.<a href=#restore-all-apps. class=anchor aria-hidden=true></a></h5><p>Restore <em>base backup</em> of all the backed up applications.</section><section id=restore-not-installed-apps. class=level5 data-number=2.3.5.0.2><h5 data-number=2.3.5.0.2><span class=header-section-number>2.3.5.0.2</span> Restore not installed\napps.<a href=#restore-not-installed-apps. class=anchor aria-hidden=true></a></h5><p>Restore <em>base backup</em> of all the backed up applications that\nare not currently installed.</section><section id=restore-latest-backups. class=level5 data-number=2.3.5.0.3><h5 data-number=2.3.5.0.3><span class=header-section-number>2.3.5.0.3</span> Restore latest backups.<a href=#restore-latest-backups. class=anchor aria-hidden=true></a></h5><p>Restore <em>base backup</em> of already installed applications whose\nversion codes are higher than the installed version code.</section></section><section id=subsec:trim-caches-in-all-apps class=level3 data-number=2.3.6><h3 data-number=2.3.6><span class=header-section-number>2.3.6</span>\n<a href=#toc:subsec:trim-caches-in-all-apps>Trim Caches in All\nApps</a><a href=#subsec:trim-caches-in-all-apps class=anchor aria-hidden=true></a></h3><p>Delete caches from all applications, including Android system. During\nthis operation, caches of all the running applications may not be\ncleared as expected.</section></section><section id=sec:profiles-page class=level2 data-number=2.4><h2 data-number=2.4><span class=header-section-number>2.4</span> <a href=#toc:sec:profiles-page>Página de perfiles</a><a href=#sec:profiles-page class=anchor aria-hidden=true></a></h2><p>Profiles page can be accessed from the <a href=#subsec:main-page-options-menu>options-menu</a> in the main page.\nIt primarily displays a list of configured profiles along with the\ntypical options to perform operations on them. New profiles can also be\nadded using the <em>plus</em> button at the bottom-right corner.\nProfiles can be imported, duplicated or deleted. Clicking on a profile\nitem opens its <a href=#sec:profile-page>profile page</a>.<section id=subsec:profiles-options-menu class=level3 data-number=2.4.1><h3 data-number=2.4.1><span class=header-section-number>2.4.1</span>\n<a href=#toc:subsec:profiles-options-menu>Opciones de menú</a><a href=#subsec:profiles-options-menu class=anchor aria-hidden=true></a></h3><p>The three-dots menu in the top-right corner opens the global option\nmenu. It has an option to import an existing profile that was previously\nexported from App Manager.<p>Long clicking on any profile item brings up another options-menu. It\noffers the following options:<ul class=incremental><li><p><strong>Apply now….</strong> This option can be used to apply the\nprofile directly. When clicked, a dialog is displayed where it is\npossible to select a <a href=#subsubsec:profile-state>profile\nstate</a>. On selecting one of the states, the profile will be applied\nimmediately.<li><p><strong>Delete.</strong> Clicking on this option will remove the\nprofile immediately without a warning.<li><p><strong>Duplicate.</strong> This option can be used to duplicate\nthe profile. When clicked, a dialog is displayed where it is possible to\nset a name for the new profile. On clicking “OK”, the <a href=#sec:profile-page>profile page</a> will be loaded by duplicating\nall the configurations that this profile have. However, the profile will\nnot be saved until it is saved manually.<li><p><strong>Copy profile ID.</strong> This option is used to copy the\nunique profile ID of the profile. The profile ID can be used to <a href=#subsec:triggering-a-profile>trigger the profile</a> from a\nthird-party application.<li><p><strong>Export.</strong> Export the profile to an external\nstorage. Profiles exported this way can be imported via the\n<em>import</em> option as mentioned above.<li><p><strong>Create shortcut.</strong> This option can be used to\ncreate a shortcut for the profile. There are two options:\n<em>Simple</em> and <em>Advanced</em>. When configured with the latter\noption, it prompts the user to select a profile state when the shortcut\nis invoked. The former option, on the other hand, always uses the\ndefault state that was configured when the profile was last\nsaved.</ul></section></section><section id=sec:profile-page class=level2 data-number=2.5><h2 data-number=2.5><span class=header-section-number>2.5</span> <a href=#toc:sec:profile-page>Página de perfil</a><a href=#sec:profile-page class=anchor aria-hidden=true></a></h2><p>Profile page displays the configurations for a profile. It also\noffers the options to edit them.<section id=subsec:profile-options-menu class=level3 data-number=2.5.1><h3 data-number=2.5.1><span class=header-section-number>2.5.1</span>\n<a href=#toc:subsec:profile-options-menu>Opciones de menú</a><a href=#subsec:profile-options-menu class=anchor aria-hidden=true></a></h3><p>The three dots menu in the top-right corner opens the options-menu.\nIt contains several options such as–<ul class=incremental><li><p><strong>Apply.</strong> This option can be used to apply the\nprofile directly. When clicked, a dialog is displayed where it is\npossible to select a <a href=#subsubsec:profile-state>profile\nstate</a>. On selecting one of the states, the profile will be applied\nimmediately.<div class=\"amalert tip\"><p><strong><em>Notice.</em></strong><p>When you apply a profile, if some packages do not match the criteria,\nthey will simply be ignored.</div><li><p><strong>Save.</strong> Save changes to the profile.<li><p><strong>Discard.</strong> Discard any modifications made since\nthe last time it was saved.<li><p><strong>Delete.</strong> Clicking on this option will remove the\nprofile immediately without a warning.<li><p><strong>Duplicate.</strong> This option can be used to duplicate\nthe profile. When clicked, a dialog is displayed where it is possible to\nset a name for the new profile. On clicking “OK”, this page will be\nreloaded by duplicating all the configurations that this profile have.\nHowever, the new profile will not be saved until it is saved\nmanually.<li><p><strong>Create shortcut.</strong> This option can be used to\ncreate a shortcut for the profile. There are two options:\n<em>Simple</em> and <em>Advanced</em>. When configured with the latter\noption, it prompts the user to select a profile state when the shortcut\nis invoked. The former option, on the other hand, always uses the\ndefault state that was configured when the profile was last\nsaved.</ul></section><section id=subsec:profile-apps-tab class=level3 data-number=2.5.2><h3 data-number=2.5.2><span class=header-section-number>2.5.2</span>\n<a href=#toc:subsec:profile-apps-tab>Pestaña de aplicaciones</a><a href=#subsec:profile-apps-tab class=anchor aria-hidden=true></a></h3><p>Apps tab lists the packages configured for this profile. Packages can\nbe added or removed using the <em>plus</em> button located near the\nbottom of the screen. A package can also be removed by long clicking on\nit (in which case, a popup will be displayed with the only option,\n<em>delete</em>).</section><section id=subsec:profile-configurations-tab class=level3 data-number=2.5.3><h3 data-number=2.5.3><span class=header-section-number>2.5.3</span>\n<a href=#toc:subsec:profile-configurations-tab>Pestaña de\nconfiguraciones</a><a href=#subsec:profile-configurations-tab class=anchor aria-hidden=true></a></h3><p>La pestaña Configuraciones se puede utilizar para configurar los\npaquetes seleccionados.<section id=profile-id class=level4 data-number=2.5.3.1><h4 data-number=2.5.3.1><span class=header-section-number>2.5.3.1</span> Profile ID<a href=#profile-id class=anchor aria-hidden=true></a></h4><p>The unique ID for this profile, currently set based on the profile\nname. The profile ID can be used to <a href=#subsec:triggering-a-profile>trigger the profile</a> from a\nthird-party application.</section><section id=comentario class=level4 data-number=2.5.3.2><h4 data-number=2.5.3.2><span class=header-section-number>2.5.3.2</span> Comentario<a href=#comentario class=anchor aria-hidden=true></a></h4><p>This is the text that will be displayed in the <a href=#sec:profiles-page>profiles page</a>. If not set, the current\nconfigurations will be displayed instead.</section><section id=subsubsec:profile-state class=level4 data-number=2.5.3.3><h4 data-number=2.5.3.3><span class=header-section-number>2.5.3.3</span> Estado<a href=#subsubsec:profile-state class=anchor aria-hidden=true></a></h4><p>Denotes how certain configured options will behave by default. For\ninstance, if <em>disable</em> option is turned on, the applications will\nbe disabled if the state is <em>on</em> and will be enabled if the state\nis <em>off</em>. Currently, it only supports <em>on</em> and\n<em>off</em> values.</section><section id=usuarios class=level4 data-number=2.5.3.4><h4 data-number=2.5.3.4><span class=header-section-number>2.5.3.4</span> Usuarios<a href=#usuarios class=anchor aria-hidden=true></a></h4><p>Seleccione los usuarios para los que se aplicará el perfil. Todos los\nusuarios se seleccionan de forma predeterminada.</section><section id=componentes class=level4 data-number=2.5.3.5><h4 data-number=2.5.3.5><span class=header-section-number>2.5.3.5</span> Componentes<a href=#componentes class=anchor aria-hidden=true></a></h4><p>This behaves the same way as the <a href=#subsec:block-components-dots>Block Components…</a> option does\nin the 1-Click Ops page. However, the blocking here is only applied to\nthe selected packages. If the <a href=#subsubsec:profile-state>state</a> is <em>on</em>, the components\nwill be blocked, and if the state is <em>off</em>, the components will\nbe unblocked. The option can be disabled (regardless of the inserted\nvalues) by clicking on the <em>disabled</em> button on the input\ndialog.<div class=seealso-inline><p><em>Ver también: <span><a href=#subsec:faq:what-are-app-components>What are the app\ncomponents?</a></span></em></div></section><section id=operaciones-de-aplicación class=level4 data-number=2.5.3.6><h4 data-number=2.5.3.6><span class=header-section-number>2.5.3.6</span> Operaciones de aplicación<a href=#operaciones-de-aplicación class=anchor aria-hidden=true></a></h4><p>This behaves the same way as the <a href=#subsec:set-mode-for-app-ops-dots>Set Mode for App Ops…</a>\noption does in the 1-Click Ops page. However, the operation here is only\napplied to the selected packages. If the <a href=#subsubsec:profile-state>state</a> is <em>on</em>, the app ops\nwill be denied (i.e. ignored), and if the state is <em>off</em>, the app\nops will be allowed. The option can be disabled (regardless of the\ninserted values) by clicking on the <em>disable</em> button in the input\ndialog.</section><section id=permisos class=level4 data-number=2.5.3.7><h4 data-number=2.5.3.7><span class=header-section-number>2.5.3.7</span> Permisos<a href=#permisos class=anchor aria-hidden=true></a></h4><p>This option can be used to grant or revoke certain permissions from\nthe selected packages. Like others above, permissions must be separated\nby white spaces. If the <a href=#subsubsec:profile-state>state</a> is\n<em>on</em>, the permissions will be revoked, and if the state is\n<em>off</em>, the permissions will be allowed. The option can be\ndisabled (regardless of the inserted values) by clicking on the\n<em>disable</em> button in the input dialog.</section><section id=copia-de-seguridadrestauracion class=level4 data-number=2.5.3.8><h4 data-number=2.5.3.8><span class=header-section-number>2.5.3.8</span> Copia de\nseguridad/restauracion<a href=#copia-de-seguridadrestauracion class=anchor aria-hidden=true></a></h4><p>This option can be used to take a backup of the selected applications\nand its data or restore them. Two options are available here: <em>Backup\noptions</em> and <em>backup name</em>.<ul class=incremental><li><p><strong>Backup options.</strong> Same as the <a href=#subsec:backup-restore-backup-options>backup options</a> of the\nbackup/restore feature. If not set, the default options will be\nused.<li><p><strong>Backup name.</strong> Set a custom name for the backup.\nIf the backup name is set, each time a backup is made, it will be given\na unique name with backup-name as the suffix. This behaviour will be\nfixed in a future release. Leave this field empty for regular “base”\nbackups (also, make sure not to enable <em>backup multiple</em> in the\nbackup options).</ul><p>If the <a href=#subsubsec:profile-state>state</a> is <em>on</em>,\nthe packages will be backed up, and if the state is <em>off</em>, the\npackages will be restored. The option can be disabled by clicking on the\n<em>disable</em> button in the input dialog.</section><section id=exportar-reglas-de-bloqueo class=level4 data-number=2.5.3.9><h4 data-number=2.5.3.9><span class=header-section-number>2.5.3.9</span> Exportar reglas de\nbloqueo<a href=#exportar-reglas-de-bloqueo class=anchor aria-hidden=true></a></h4><div class=\"amalert danger\"><p><strong><em>Danger.</em></strong><p>This option is not yet implemented.</div></section><section id=freeze class=level4 data-number=2.5.3.10><h4 data-number=2.5.3.10><span class=header-section-number>2.5.3.10</span> Freeze<a href=#freeze class=anchor aria-hidden=true></a></h4><p>Allow freezing or unfreezing the selected packages depending on the\nvalue of the <a href=#subsubsec:profile-state>state</a>. If the state\nis <em>on</em>, the packages will be frozen, and if the state is\n<em>off</em>, they will be unfrozen.</section><section id=parada-forzosa class=level4 data-number=2.5.3.11><h4 data-number=2.5.3.11><span class=header-section-number>2.5.3.11</span> Parada forzosa<a href=#parada-forzosa class=anchor aria-hidden=true></a></h4><p>Permita que los paquetes seleccionados se detengan a la fuerza.</section><section id=limpiar-caché class=level4 data-number=2.5.3.12><h4 data-number=2.5.3.12><span class=header-section-number>2.5.3.12</span> Limpiar caché<a href=#limpiar-caché class=anchor aria-hidden=true></a></h4><p>Habilite la limpieza de la caché para los paquetes seleccionados.</section><section id=limpiar-datos class=level4 data-number=2.5.3.13><h4 data-number=2.5.3.13><span class=header-section-number>2.5.3.13</span> Limpiar datos<a href=#limpiar-datos class=anchor aria-hidden=true></a></h4><p>Habilitar el borrado de los datos para los paquetes\nseleccionados.</section><section id=bloquear-rastreadores class=level4 data-number=2.5.3.14><h4 data-number=2.5.3.14><span class=header-section-number>2.5.3.14</span> Bloquear rastreadores<a href=#bloquear-rastreadores class=anchor aria-hidden=true></a></h4><p>Enable blocking or unblocking of the tracker components from the\nselected packages depending on the value of the <a href=#subsubsec:profile-state>state</a>. If the state is <em>on</em>,\nthe trackers will be blocked, and if the state is <em>off</em>, the\ntrackers will be unblocked.</section><section id=guardar-apk class=level4 data-number=2.5.3.15><h4 data-number=2.5.3.15><span class=header-section-number>2.5.3.15</span> Guardar APK<a href=#guardar-apk class=anchor aria-hidden=true></a></h4><p>Enable saving APK files at <code>AppManager/apks</code> (or in the\ndirectory selected in the settings page) of the selected packages.</section></section></section><section id=sec:settings-page class=level2 data-number=2.6><h2 data-number=2.6><span class=header-section-number>2.6</span> <a href=#toc:sec:settings-page>Página de configuraciones</a><a href=#sec:settings-page class=anchor aria-hidden=true></a></h2><p>La página de configuración se puede utilizar para personalizar el\ncomportamiento de App Manager.<section id=subsec:language class=level3 data-number=2.6.1><h3 data-number=2.6.1><span class=header-section-number>2.6.1</span>\n<a href=#toc:subsec:language>Idioma</a><a href=#subsec:language class=anchor aria-hidden=true></a></h3><p>Configurar el idioma de la aplicación. App Manager admite actualmente\n21 (veintiún) idiomas.</section><section id=subsec:appearance class=level3 data-number=2.6.2><h3 data-number=2.6.2><span class=header-section-number>2.6.2</span>\n<a href=#toc:subsec:appearance>Appearance</a><a href=#subsec:appearance class=anchor aria-hidden=true></a></h3><section id=subsubsec:app-theme class=level4 data-number=2.6.2.1><h4 data-number=2.6.2.1><span class=header-section-number>2.6.2.1</span> Tema de la aplicación<a href=#subsubsec:app-theme class=anchor aria-hidden=true></a></h4><p>Configurar el tema de la aplicación.</section><section id=subsubsec:pure-black-theme class=level4 data-number=2.6.2.2><h4 data-number=2.6.2.2><span class=header-section-number>2.6.2.2</span> Pure Black Theme<a href=#subsubsec:pure-black-theme class=anchor aria-hidden=true></a></h4><p>Whether to use a black background instead of the material themed\nbackground.</section><section id=subsubsec:layout-direction class=level4 data-number=2.6.2.3><h4 data-number=2.6.2.3><span class=header-section-number>2.6.2.3</span> Layout Direction<a href=#subsubsec:layout-direction class=anchor aria-hidden=true></a></h4><p>Change layout direction, either left to right or right to left. This\nis usually set using the selected language but not everybody prefers the\nsame direction.</section><section id=subsubsec:enable/disable-features class=level4 data-number=2.6.2.4><h4 data-number=2.6.2.4><span class=header-section-number>2.6.2.4</span> Habilitar/deshabilitar\ncaracterísticas<a href=#subsubsec:enable/disable-features class=anchor aria-hidden=true></a></h4><p>Enable or disable certain features in App Manager, such as<ul class=incremental><li><p><strong>Interceptor</strong><li><p><strong>Manifest viewer</strong><li><p><strong>Scanner</strong><li><p><strong>Package installer</strong><li><p><strong>Usage access.</strong> With this feature turned off, App\nManager will never ask for the <em>Usage Access</em>\npermission.<li><p><strong>Log viewer</strong><li><p><strong>App explorer.</strong> The “Explore” option will not be\navailable while trying to open an APK file.<li><p><strong>App info.</strong> The “App info” option displayed while\ntrying to open an APK file.<li><p><strong>Code Editor</strong><li><p><strong>VirusTotal</strong></ul></section></section><section id=subsec:privacy class=level3 data-number=2.6.3><h3 data-number=2.6.3><span class=header-section-number>2.6.3</span>\n<a href=#toc:subsec:privacy>Privacy</a><a href=#subsec:privacy class=anchor aria-hidden=true></a></h3><section id=subsubsec:screen-lock class=level4 data-number=2.6.3.1><h4 data-number=2.6.3.1><span class=header-section-number>2.6.3.1</span> Bloqueo de pantalla<a href=#subsubsec:screen-lock class=anchor aria-hidden=true></a></h4><p>Bloquear App Manager usando el bloqueo de pantalla de Android siempre\nque se configure un bloqueo de pantalla.<div class=\"amalert warning\"><p><strong><em>Advertencia.</em></strong><p>Si se desactiva el bloqueo de pantalla en Android después de activar\nesta configuración, App Manager no se abrirá hasta que se vuelva a\nactivar.</div></section><section id=subsubsec:run-am-in-background class=level4 data-number=2.6.3.2><h4 data-number=2.6.3.2><span class=header-section-number>2.6.3.2</span> Run App Manager in the\nBackground<a href=#subsubsec:run-am-in-background class=anchor aria-hidden=true></a></h4><p>Whether to run App Manager in the background to reduce the\ninitialisation delay. On certain devices, this can also help if you’re\nfrequently disconnected from ADB.</section><section id=subsubsec:use-the-internet class=level4 data-number=2.6.3.3><h4 data-number=2.6.3.3><span class=header-section-number>2.6.3.3</span> Use the Internet<a href=#subsubsec:use-the-internet class=anchor aria-hidden=true></a></h4><p>Whether to activate the Internet features in App Manager. This\ncurrently include VirusTotal and Pithus scanning in the <a href=#sec:scanner-page>Scanner page</a>.</section><section id=subsubsec:auth-manager class=level4 data-number=2.6.3.4><h4 data-number=2.6.3.4><span class=header-section-number>2.6.3.4</span> Authorization Manager<a href=#subsubsec:auth-manager class=anchor aria-hidden=true></a></h4><p>This setting allows a third-party application to get access to\ncertain features, such as profiles.</section></section><section id=subsec:mode-of-operation class=level3 data-number=2.6.4><h3 data-number=2.6.4><span class=header-section-number>2.6.4</span>\n<a href=#toc:subsec:mode-of-operation>Modo de operación</a><a href=#subsec:mode-of-operation class=anchor aria-hidden=true></a></h3><p>Mode of operation defines how App Manager works as a whole. It has\nthe following options:<ul class=incremental><li><p><strong>Auto.</strong> Let App Manager decide the suitable\noption. Although this is the default option, non-rooted users should use\nthe <em>no-root</em> mode.<li><p><strong>Root.</strong> Operate App Manager in root mode. App\nManager will fall back to <em>no-root</em> mode if root is not detected,\nor in rare cases when Binder communication through root is disabled\n(e.g. in <a href=https://github.com/MuntashirAkon/AppManager/issues/606>Phh\nSuperUser</a>).<li><p><strong>ADB over TCP.</strong> Operate App Manager in ADB mode\nvia <a href=#sec:adb-over-tcp>ADB over TCP</a>. App Manager will fall\nback to <em>no-root</em> mode if ADB over TCP is not enabled.<li><p><strong>Wireless debugging.</strong> Enable ADB via Wireless\nDebugging. It will try to connect to the configured port automatically\nat first. On failure, it will ask the user to either pair or connect to\nthe ADB daemon manually. App Manager will fall back to <em>no-root</em>\nmode if it fails to connect to the ADB daemon this way.<div class=\"amalert tip\"><p><strong><em>Info.</em></strong><p>This option is only displayed in devices running Android 11 or later\nas Wireless Debugging was introduced in Android 11.</div><li><p><strong>No-root.</strong> Operate App Manager in no-root mode.\nWhile App Manager performs better in this mode, all the root- or\nADB-specific features will be disabled.</ul><p>It also displays the actual mode of operation at the top. The actual\nmode of operations are <em>root</em>, <em>ABD</em> and\n<em>no-root</em>.<div class=\"amalert tip\"><p><strong><em>Notice.</em></strong><p>“Remote service” is only required for ADB users or when you use the\ncustom commands.</div></section><section id=subsec:apk-signing class=level3 data-number=2.6.5><h3 data-number=2.6.5><span class=header-section-number>2.6.5</span>\n<a href=#toc:subsec:apk-signing>Firma de APK</a><a href=#subsec:apk-signing class=anchor aria-hidden=true></a></h3><section id=esquemas-de-firma class=level4 data-number=2.6.5.1><h4 data-number=2.6.5.1><span class=header-section-number>2.6.5.1</span> Esquemas de firma<a href=#esquemas-de-firma class=anchor aria-hidden=true></a></h4><p>Configure the <a href=https://source.android.com/security/apksigning>signature\nschemes</a> to be used when APK signing is enabled. v1 and v2 signature\nschemes are enabled by default, but v3 should also be enabled to ensure\nproper security in Android 9 or later.</section><section id=clave-de-firma class=level4 data-number=2.6.5.2><h4 data-number=2.6.5.2><span class=header-section-number>2.6.5.2</span> Clave de firma<a href=#clave-de-firma class=anchor aria-hidden=true></a></h4><p>Configure the signing key for signing APK files. Keys from an\nexisting KeyStore can be imported to App Manager, or a new key can be\ngenerated.<div class=\"amalert tip\"><p><strong><em>Tip.</em></strong><p>If you need to use the key in the future, it is recommended that you\ncreate a KeyStore yourself and import the key here. Without a proper\nbackup, keys generated within App Manager are at the risk of being\ndeleted.</div></section><section id=align-apk-files class=level4 data-number=2.6.5.3><h4 data-number=2.6.5.3><span class=header-section-number>2.6.5.3</span> Align APK Files<a href=#align-apk-files class=anchor aria-hidden=true></a></h4><p>Performs zip alignment when App Manager signs an APK file. Zip\nalignment stores the files in the APK file (which is actually a zip\nfile) in a way that a zip file reader can access the files quite easily\nusing random access instead of loading the entire APK file in the\nmemory, which results in the reduction of Android’s memory usage. Note\nthat this step is required if an application’s manifest has\n<code>extractNativeLibs</code> set to <code>true</code>.</section></section><section id=subsec:installer class=level3 data-number=2.6.6><h3 data-number=2.6.6><span class=header-section-number>2.6.6</span>\n<a href=#toc:subsec:installer>Instalador</a><a href=#subsec:installer class=anchor aria-hidden=true></a></h3><p>Configure the default behaviour of the installer. You can also find\nmost of the settings by clicking on the <em>cog</em> icon when you\ninstall an application.<section id=ubicación-de-la-instalación class=level4 data-number=2.6.6.1><h4 data-number=2.6.6.1><span class=header-section-number>2.6.6.1</span> Ubicación de la\ninstalación<a href=#ubicación-de-la-instalación class=anchor aria-hidden=true></a></h4><p>Define APK installation location. This can be one of <em>auto</em>,\n<em>internal only</em> and <em>prefer external</em>. In newer Android\nversions, selecting the last option does not guarantee that the\napplication will be installed in the external storage.</section><section id=block-trackers class=level4 data-number=2.6.6.2><h4 data-number=2.6.6.2><span class=header-section-number>2.6.6.2</span> Block Trackers<a href=#block-trackers class=anchor aria-hidden=true></a></h4><p>Whether to block the tracking components immediately after installing\nthe application.</section><section id=display-changes class=level4 data-number=2.6.6.3><h4 data-number=2.6.6.3><span class=header-section-number>2.6.6.3</span> Display Changes<a href=#display-changes class=anchor aria-hidden=true></a></h4><p>Whether to display changes in version, trackers, components,\npermissions, signatures, SDK, etc. in a version controlled style before\ninstalling the application if the application has already been\ninstalled.</section><section id=aplicación-de-instalación class=level4 data-number=2.6.6.4><h4 data-number=2.6.6.4><span class=header-section-number>2.6.6.4</span> Aplicación de instalación<a href=#aplicación-de-instalación class=anchor aria-hidden=true></a></h4><p>Selecciona la aplicación instaladora, útil para aplicaciones que\ncomprueban explícitamente el instalador como forma de verificar si la\naplicación se instala legítimamente. Esto sólo funciona para los\nusuarios root o ADB.<div class=\"amalert tip\"><p><strong><em>Notice.</em></strong><p>Mientras que la comprobación del instalador puede parecer una\npreocupación legítima para una aplicación, el marco de Android ya se\nocupa de esto durante la instalación. La comprobación del instalador es\nsimplemente la manera incorrecta de probar la legitimidad de la fuente\nde una aplicación.</div></section><section id=firmar-apk class=level4 data-number=2.6.6.5><h4 data-number=2.6.6.5><span class=header-section-number>2.6.6.5</span> Firmar APK<a href=#firmar-apk class=anchor aria-hidden=true></a></h4><p>Whether to sign the APK files before installing the application. A\nsigning key has to be added or generated before this option can be\nenabled. This can be done in the <a href=#subsec:apk-signing>APK\nsigning</a> page.</section><section id=immediately-perform-dex-optimization class=level4 data-number=2.6.6.6><h4 data-number=2.6.6.6><span class=header-section-number>2.6.6.6</span> Immediately Perform DEX\nOptimization<a href=#immediately-perform-dex-optimization class=anchor aria-hidden=true></a></h4><p>Whether to perform DEX optimization immediately after installing the\napplication. This can be useful for heavy applications, such as the\ngaming applications.</section><section id=install-in-the-background class=level4 data-number=2.6.6.7><h4 data-number=2.6.6.7><span class=header-section-number>2.6.6.7</span> Install in the Background<a href=#install-in-the-background class=anchor aria-hidden=true></a></h4><p>Whether to always install applications in the background. A\nnotification will be issued once the installation is finished.</section></section><section id=subsec:backup/restore class=level3 data-number=2.6.7><h3 data-number=2.6.7><span class=header-section-number>2.6.7</span>\n<a href=#toc:subsec:backup/restore>Copia de seguridad/restaurar</a><a href=#subsec:backup/restore class=anchor aria-hidden=true></a></h3><p>Configuración relacionada con <a href=#sec:backup-restore>back\nup/restore</a>.<section id=método-de-compresión class=level4 data-number=2.6.7.1><h4 data-number=2.6.7.1><span class=header-section-number>2.6.7.1</span> Método de compresión<a href=#método-de-compresión class=anchor aria-hidden=true></a></h4><p>Establezca el método de compresión que se utilizará durante las\ncopias de seguridad. App Manager soporta los métodos de compresión GZip\ny BZip2, GZip es el método de compresión por defecto. No afecta a la\nrestauración de una copia de seguridad existente.</section><section id=subsubsec:settings-backup-options class=level4 data-number=2.6.7.2><h4 data-number=2.6.7.2><span class=header-section-number>2.6.7.2</span> Opciones de copia de\nseguridad<a href=#subsubsec:settings-backup-options class=anchor aria-hidden=true></a></h4><p>Personalice el <em>cuadro de diálogo de copia de\nseguridad/restauración</em> que se muestra al realizar una copia de\nseguridad.<div class=seealso-inline><p><em>Ver también: <span><a href=#subsec:backup-restore-backup-options>Backup\noptions</a></span></em></div></section><section id=aplicaciones-de-copia-de-seguridad-con-android-keystore class=level4 data-number=2.6.7.3><h4 data-number=2.6.7.3><span class=header-section-number>2.6.7.3</span> Aplicaciones de copia de\nseguridad con Android KeyStore<a href=#aplicaciones-de-copia-de-seguridad-con-android-keystore class=anchor aria-hidden=true></a></h4><p>Permitir la copia de seguridad de las aplicaciones que tienen\nentradas en el KeyStore de Android. Esta opción está desactivada por\ndefecto porque algunas aplicaciones (como Signal) pueden bloquearse si\nse restauran.</section><section id=subsubsec:settings-encryption class=level4 data-number=2.6.7.4><h4 data-number=2.6.7.4><span class=header-section-number>2.6.7.4</span> Encriptación<a href=#subsubsec:settings-encryption class=anchor aria-hidden=true></a></h4><p>Set an encryption method for the backups. App Manager currently\nsupports OpenPGP (via <a href=https://f-droid.org/packages/org.sufficientlysecure.keychain/>OpenKeyChain</a>),\nAES, RSA and ECC. Like <a href=#subsec:apk-signing>APK signing</a>,\nThe AES, RSA and ECC keys are stored in the KeyStore and can be imported\nfrom other KeyStores.<div class=\"amalert danger\"><p><strong><em>Danger.</em></strong><p>For your own safety, it is not recommended generating RSA and ECC\nkeys inside App Manager. Instead, they should be imported from a\nKeyStore stored in a secure place.<br>In case of AES, the generated key should be stored in a secure place,\nsuch as in a password manager.</div></section><section id=subsubsec:backup-volume class=level4 data-number=2.6.7.5><h4 data-number=2.6.7.5><span class=header-section-number>2.6.7.5</span> Volumen de copia de\nseguridad<a href=#subsubsec:backup-volume class=anchor aria-hidden=true></a></h4><p>Select the storage where the backups will be stored. This is also\nwhere logs and exported APK files are saved.<div class=\"amalert tip\"><p><strong><em>Notice.</em></strong><p>The backup volume only specifies the storage, not the path. Backups\nare traditionally stored in the <code>AppManager</code> folder inside\nthe storage path. But when the path is selected using Storage Access\nFramework (SAF), the selected path or directory is used directly.</div></section><section id=import-backups class=level4 data-number=2.6.7.6><h4 data-number=2.6.7.6><span class=header-section-number>2.6.7.6</span> Import Backups<a href=#import-backups class=anchor aria-hidden=true></a></h4><p>Import backups from old and discontinued projects such as Titanium\nBackup, OAndBackup, and Swift Backup (version 3.0 to 3.2). The backups\nare not deleted after importing to prevent data loss in case the\nimported backups cannot be restored properly.</section></section><section id=subsec:rules class=level3 data-number=2.6.8><h3 data-number=2.6.8><span class=header-section-number>2.6.8</span>\n<a href=#toc:subsec:rules>Reglas</a><a href=#subsec:rules class=anchor aria-hidden=true></a></h3><section id=subsubsec:instant-component-blocking class=level4 data-number=2.6.8.1><h4 data-number=2.6.8.1><span class=header-section-number>2.6.8.1</span> Bloqueo instantáneo de\ncomponentes<a href=#subsubsec:instant-component-blocking class=anchor aria-hidden=true></a></h4><p>By default, blocking rules are not applied unless they are applied\nexplicitly in <a href=#sec:app-details-page>the App Details page</a>\nfor any application. After enabling this option, all (old and new) rules\nare applied immediately for all applications without explicitly enabling\nblocking for an application.<div class=seealso-inline><p><em>Ver también: <span><a href=#subsec:faq:what-is-instant-component-blocking>FAQ: What is\ninstant component blocking?</a></span></em></div></section><section id=importarexportar-reglas-de-bloqueo class=level4 data-number=2.6.8.2><h4 data-number=2.6.8.2><span class=header-section-number>2.6.8.2</span> Importar/exportar reglas de\nbloqueo<a href=#importarexportar-reglas-de-bloqueo class=anchor aria-hidden=true></a></h4><p>It is possible to import or export blocking rules within App Manager\nfor all applications. The types of rules (components, app ops or\npermissions) that should be imported or exported can also be selected.\nIt is also possible to import blocking rules from <a href=https://github.com/lihenggui/blocker>Blocker</a> and <a href=https://github.com/tuyafeng/Watt>Watt</a>. If it is necessary to\nexport blocking rules for a single application, the corresponding <a href=#sec:app-details-page>App Details page</a> can be used to export\nrules, or for multiple apps, <a href=#subsec:batch-operations>batch\noperations</a> can be used.<div class=seealso-inline><p><em>Ver también: <span><a href=#sec:rules-specification>Rules\nSpecification</a></span></em></div><section id=export class=level5 data-number=2.6.8.2.1><h5 data-number=2.6.8.2.1><span class=header-section-number>2.6.8.2.1</span> Export<a href=#export class=anchor aria-hidden=true></a></h5><p>Export blocking rules for all applications configured within App\nManager. This may include <a href=#subsec:faq:what-are-app-components>app components</a>, app ops\nand permissions based on the options selected in the multi-choice\noptions.</section><section id=import class=level5 data-number=2.6.8.2.2><h5 data-number=2.6.8.2.2><span class=header-section-number>2.6.8.2.2</span> Import<a href=#import class=anchor aria-hidden=true></a></h5><p>Import previously exported blocking rules from App Manager. Similar\nto export, this may include <a href=#subsec:faq:what-are-app-components>app components</a>, app ops\nand permissions based on the options selected in the multi-choice\noptions.</section><section id=par:import-existing-rules class=level5 data-number=2.6.8.2.3><h5 data-number=2.6.8.2.3><span class=header-section-number>2.6.8.2.3</span> Import Existing Rules<a href=#par:import-existing-rules class=anchor aria-hidden=true></a></h5><p>Add components disabled by other applications to App Manager. App\nManager only keeps track of the components disabled within App Manager.\nIf application components are blocked or disabled by other tools or\napplications, this option can be utilised to import them. On clicking\nthis option, App Manager will find the components potentially disabled\nby other applications or tools and list only the name of the\napplications along with the number of matched components. For safety,\nall the applications are unselected by default. They have to be selected\nmanually, and the blocking has to be re-applied via App Manager.<div class=\"amalert danger\"><p><strong><em>Caution.</em></strong><p>Be careful when using this tool as there can be many false positives.\nChoose only the applications that you are certain about.</div></section><section id=import-from-watt class=level5 data-number=2.6.8.2.4><h5 data-number=2.6.8.2.4><span class=header-section-number>2.6.8.2.4</span> Import from Watt<a href=#import-from-watt class=anchor aria-hidden=true></a></h5><p>Import configuration files from <a href=https://github.com/tuyafeng/Watt>Watt</a>, each file containing\nrules for a single package and file name being the name of the package\nwith <code>.xml</code> extension.<div class=\"amalert tip\"><p><strong><em>Tip.</em></strong><p>Location of configuration files in Watt:\n<code>/sdcard/Android/data/com.tuyafeng.watt/files/ifw</code></div></section><section id=import-from-blocker class=level5 data-number=2.6.8.2.5><h5 data-number=2.6.8.2.5><span class=header-section-number>2.6.8.2.5</span> Import from Blocker<a href=#import-from-blocker class=anchor aria-hidden=true></a></h5><p>Import blocking rules from <a href=https://github.com/lihenggui/blocker>Blocker</a>, each file\ncontaining rules for a single package. These files have a\n<code>.json</code> extension.</section></section><section id=remover-todas-las-reglas class=level4 data-number=2.6.8.3><h4 data-number=2.6.8.3><span class=header-section-number>2.6.8.3</span> Remover todas las reglas<a href=#remover-todas-las-reglas class=anchor aria-hidden=true></a></h4><p>Opción de un clic para eliminar todas las reglas configuradas dentro\nde App Manager. Esto habilitará todos los componentes bloqueados, las\noperaciones de la aplicación se establecerán en sus valores\npredeterminados y se restablecerán los permisos.</section></section><section id=subsec:advanced class=level3 data-number=2.6.9><h3 data-number=2.6.9><span class=header-section-number>2.6.9</span>\n<a href=#toc:subsec:advanced>Advanced</a><a href=#subsec:advanced class=anchor aria-hidden=true></a></h3><section id=subsubsec:selected-users class=level4 data-number=2.6.9.1><h4 data-number=2.6.9.1><span class=header-section-number>2.6.9.1</span> Selected Users<a href=#subsubsec:selected-users class=anchor aria-hidden=true></a></h4><p>This option lets you control the users App Manager should operate on.\nApp Manager operates on all users in root or ADB mode by default.</section><section id=subsubsec:saved-apk-name-format class=level4 data-number=2.6.9.2><h4 data-number=2.6.9.2><span class=header-section-number>2.6.9.2</span> Saved APK Name Format<a href=#subsubsec:saved-apk-name-format class=anchor aria-hidden=true></a></h4><p>Defines the format of the APK name to be used while saving it via\nbatch operations or through profiles. App Manager offers some special\nkeywords enclosed inside <code>%</code> (percentage) signs and available\nbelow the input box. These keywords are:<ul class=incremental><li><p><strong><code>label</code>.</strong> Denotes the name or label of\nthe application. This can be localised to the configured language\ndepending on the app.<li><p><strong><code>package_name</code>.</strong> Denotes the name of\nthe package or application ID, the unique identifier that each\napplication has.<li><p><strong><code>version</code>.</strong> Denotes the current\nversion of the application extracted from its manifest.<li><p><strong><code>version_code</code>.</strong> Denotes the current\nversion code of the application that can be used to separate two\nversions of the same application.<li><p><strong><code>min_sdk</code>.</strong> Denotes the minimum SDK\n(i.e. Android framework version) that the application can operate on.\nThis data is only available since Android 7 (Nougat).<li><p><strong><code>target_sdk</code>.</strong> Denotes the SDK that\nthis application targets. The application can operate on higher SDK but\nonly in the compatibility mode.<li><p><strong><code>datetime</code>.</strong> Denotes the time and date\nwhen the APK is exported.</ul></section><section id=subsubsec:import/export-keystore class=level4 data-number=2.6.9.3><h4 data-number=2.6.9.3><span class=header-section-number>2.6.9.3</span> Importar/exportar\nKeystore<a href=#subsubsec:import/export-keystore class=anchor aria-hidden=true></a></h4><p>Import or export the KeyStore used by App Manager. This is a Bouncy\nCastle KeyStore with <code>bks</code> extension. Therefore, other\nKeyStore such as Java KeyStore (JKS) or PKCS #12 are not supported. If a\nkey is needed to be imported from such a KeyStore, the relevant options\nshould be should as specified above.</section></section><section id=subsec:device-info class=level3 data-number=2.6.10><h3 data-number=2.6.10><span class=header-section-number>2.6.10</span> <a href=#toc:subsec:device-info>Sobre este dispositivo</a><a href=#subsec:device-info class=anchor aria-hidden=true></a></h3><p>Muestra la versión de Android, la seguridad, la CPU, la GPU, la\nbatería, la memoria, la pantalla, los idiomas, la información del\nusuario, etc.</section></section><section id=sec:scanner-page class=level2 data-number=2.7><h2 data-number=2.7><span class=header-section-number>2.7</span> <a href=#toc:sec:scanner-page>Página del escáner</a><a href=#sec:scanner-page class=anchor aria-hidden=true></a></h2><p><strong>Scanner page</strong> appears after clicking on the\n<em>scanner</em> button in the <a href=#subsec:app-info-tab>App Info\ntab</a>. External APK files can also be opened for scanning from file\nmanagers, web browsers, etc.<p>It scans for trackers and libraries, and displays the number of\ntrackers and libraries as a summary. It also displays checksums of the\nAPK file as well as the signing certificates. If VirusTotal is\nconfigured in the settings, it also attempts to retrieve reports from\nVirusTotal, or uploads the APK file if it is not in the database. It\nalso display a link to the <a href=https://beta.pithus.org>Pithus</a>\nreport provided the Internet features are enabled.<div class=\"amalert danger\"><p><strong><em>Disclaimer.</em></strong><p>App Manager only scans an application statically without prejudice.\nThe application may provide the options for opting out, or in some\ncases, certain features of the tracker may not be used at all by the\napplication (e.g. F-Droid), or some applications may simply use them as\nplaceholders to prevent the breaking of certain features (e.g. Fennec\nF-Droid). <strong>The intention of the scanner is to give you an idea\nabout what the APK might contain. It should be taken as an initial step\nfor further investigations.</strong></div><p>Clicking on the first item (i.e. number of classes) opens a new page\ncontaining a list of tracker classes for the application. All classes\ncan also be viewed by clicking on the <em>Toggle Class Listing</em>\nmenu. The SMALI or Java version of the class can be viewed by simply\nclicking on an item.<div class=\"amalert tip\"><p><strong><em>Notice.</em></strong><p>Due to various limitations, it is not possible to scan all the\ncomponents of an APK file. This is especially true if an APK is highly\nobfuscated or packed. The scanner also does not check strings (or\nwebsite signatures).</div><p>The second item lists the number of trackers along with their names.\nClicking on the item displays a dialog containing the name of trackers,\nmatched signatures, and the number of classes against each signature.\nSome tracker names may have <span class=\"math inline\"><sup>2</sup></span> prefix which indicates that the\ntrackers are in the <a href=https://etip.exodus-privacy.eu.org>ETIP</a> stand-by list, i.e.,\nwhether they are actual trackers is still being investigated.<p>The third item lists the number of libraries along with their names.\nThe information are mostly taken from <a href=https://gitlab.com/IzzyOnDroid/repo>IzzyOnDroid repo</a>.<div class=seealso-inline><p><em>Ver también: <span><a href=#subsec:tracker-classes-versus-tracker-components>FAQ: Tracker\nclasses vs tracker components</a></span></em></div></section><section id=sec:interceptor-page class=level2 data-number=2.8><h2 data-number=2.8><span class=header-section-number>2.8</span> <a href=#toc:sec:interceptor-page>Página del interceptor</a><a href=#sec:interceptor-page class=anchor aria-hidden=true></a></h2><p>Interceptor can be used to intercept communication between\napplications using <code>Intent</code>. It works as a man-in-the-middle\nbetween the source and the destination applications. It offers a\nfeature-complete user interface for editing <code>Intent</code>s.<div class=\"amalert warning\"><p><strong><em>Warning.</em></strong><p>Interceptor only works for <em>implicit</em> intents where the <a href=#subsec:faq:what-are-app-components>app component</a> isn’t\nspecified.</div><div class=seealso><p><em>Ver también:</em><ul class=incremental><li><p><a href=https://developer.android.com/guide/components/intents-common>Common\nIntents</a><li><p><a href=https://developer.android.com/guide/components/intents-filters>Intents\nand Intent Filters</a></ul></div><section id=subsec:intent-filters class=level3 data-number=2.8.1><h3 data-number=2.8.1><span class=header-section-number>2.8.1</span>\n<a href=#toc:subsec:intent-filters>Filtros de intención</a><a href=#subsec:intent-filters class=anchor aria-hidden=true></a></h3><p>Intent filters are used by the applications to specify the tasks they\nare able to perform or the tasks they are going to perform using other\napplications. For example, when you’re opening a PDF file using a file\nmanager, the file manager will try to find the applications to open the\nPDF with. To find the right applications, the file manager will create\nan Intent with filters such as the MIME type and ask the system to\nretrieve the applications capable of opening this filter. The system\nwill search through the Manifest of the installed applications to match\nthe filter and list the application components that are able to open\nthis filter (in our case the PDF). At this, either the file manager will\nopen the desired application component all by itself or use a system\nprovided option to open it. If multiple application components are able\nto open it and no default is set, you may get a prompt where you have to\nchoose the right application component.<section id=subsubsec:action class=level4 data-number=2.8.1.1><h4 data-number=2.8.1.1><span class=header-section-number>2.8.1.1</span> Acción<a href=#subsubsec:action class=anchor aria-hidden=true></a></h4><p>Action specifies the generic action to perform such as\n<code>android.intent.action.VIEW</code>. Applications often declare the\nrelevant actions in the Manifest file to catch the desired Intents. The\naction is particularly useful for broadcast Intent where it plays a\nvital rule. In other cases, it works as an initial way to filter out the\nrelevant application components. Generic actions such as\n<code>android.intent.action.VIEW</code> and\n<code>android.intent.action.SEND</code> are widely used by applications.\nHence, setting this alone may match many application components.</section><section id=subsubsec:data class=level4 data-number=2.8.1.2><h4 data-number=2.8.1.2><span class=header-section-number>2.8.1.2</span> Datos<a href=#subsubsec:data class=anchor aria-hidden=true></a></h4><p>Data is originally known as URI (Uniform Resource Identifier) defined\nin <a href=http://www.faqs.org/rfcs/rfc2396.html>RFC 2396</a>. It can\nbe web links, file location, or a special feature called\n<em>content</em>. Contents are an Android feature managed by the <a href=#subsubsec:providers>content providers</a>. Data are often\nassociated with a <a href=#subsubsec:mime-type>MIME type</a>.<p>Examples:<pre><code>http://search.disroot.org/?q=URI%20in%20Android%20scheme&amp;categories=general&amp;language=en-US\nhttps://developer.android.com/reference/android/net/Uri\nfile:///sdcard/AppManager.apk\nmailto:email@example.com\ncontent://io.github.muntashirakon.AppManager.provider/23485af89b08d87e898a90c7e/AppManager.apk</code></pre></section><section id=subsubsec:mime-type class=level4 data-number=2.8.1.3><h4 data-number=2.8.1.3><span class=header-section-number>2.8.1.3</span> MIME Type<a href=#subsubsec:mime-type class=anchor aria-hidden=true></a></h4><p>MIME type of the <a href=#subsubsec:data>data</a>. For example, if\nthe data field is set to <code>file:///sdcard/AppManager.apk</code>, the\nassociated MIME type can be\n<code>application/vnd.android.package-archive</code>.</section><section id=categorías class=level4 data-number=2.8.1.4><h4 data-number=2.8.1.4><span class=header-section-number>2.8.1.4</span> Categorías<a href=#categorías class=anchor aria-hidden=true></a></h4><p>This is similar to <a href=#subsubsec:action>action</a> in the\nsense that it is also used by the system to filter application\ncomponents. This has no further benefits. Unlike <em>action</em>, there\ncan be more than one category. Clicking on the <em>plus</em> button next\nto the title allows adding more categories.</section><section id=banderas class=level4 data-number=2.8.1.5><h4 data-number=2.8.1.5><span class=header-section-number>2.8.1.5</span> Banderas<a href=#banderas class=anchor aria-hidden=true></a></h4><p>Los indicadores son útiles para determinar cómo debe comportarse el\nsistema durante el lanzamiento o después del lanzamiento de una\nactividad. Esto no debe ser tocado ya que requiere algunos conocimientos\ntécnicos. El botón <em>plus</em> junto al título puede utilizarse para\nañadir una o más banderas.</section><section id=extras class=level4 data-number=2.8.1.6><h4 data-number=2.8.1.6><span class=header-section-number>2.8.1.6</span> Extras<a href=#extras class=anchor aria-hidden=true></a></h4><p>Los extras son los pares clave-valor utilizados para proporcionar\ninformación adicional al componente de destino. Se pueden agregar más\nextras usando el botón <em>más</em> al lado del título.</section><section id=uri class=level4 data-number=2.8.1.7><h4 data-number=2.8.1.7><span class=header-section-number>2.8.1.7</span> URI<a href=#uri class=anchor aria-hidden=true></a></h4><p>Represents the entire Intent as a URI (e.g. <code>intent://…</code>).\nSome data cannot be converted to string, and as a result, they might not\nappear here.</section></section><section id=subsec:matching-activities class=level3 data-number=2.8.2><h3 data-number=2.8.2><span class=header-section-number>2.8.2</span>\n<a href=#toc:subsec:matching-activities>Actividades de\nemparejamiento</a><a href=#subsec:matching-activities class=anchor aria-hidden=true></a></h3><p>Enumera todos los componentes de la actividad que coinciden con la\nintención. Esto lo determina internamente el sistema (en lugar de App\nManager). El botón de lanzamiento junto a cada componente puede\nutilizarse para lanzarlos directamente desde App Manager.</section><section id=subsec:interceptor-reset-to-default class=level3 data-number=2.8.3><h3 data-number=2.8.3><span class=header-section-number>2.8.3</span>\n<a href=#toc:subsec:interceptor-reset-to-default>Resetear a valores\npor defecto</a><a href=#subsec:interceptor-reset-to-default class=anchor aria-hidden=true></a></h3><p>Restablece el Intent a su estado inicial.</section><section id=subsec:interceptor-send-edited-intent class=level3 data-number=2.8.4><h3 data-number=2.8.4><span class=header-section-number>2.8.4</span>\n<a href=#toc:subsec:interceptor-send-edited-intent>Enviar intención\neditada</a><a href=#subsec:interceptor-send-edited-intent class=anchor aria-hidden=true></a></h3><p>Vuelva a enviar la intención editada a la aplicación de destino. Esto\npuede abrir una lista de aplicaciones en la que es necesario seleccionar\nla aplicación deseada. El resultado recibido de la aplicación de destino\nse enviará a la aplicación de origen. Como resultado, la aplicación de\norigen no sabrá si hubo un man-in-the-middle.</section></section><section id=sec:shared-preferences-editor-page class=level2 data-number=2.9><h2 data-number=2.9><span class=header-section-number>2.9</span> <a href=#toc:sec:shared-preferences-editor-page>Página del editor de\npreferencias compartidas</a><a href=#sec:shared-preferences-editor-page class=anchor aria-hidden=true></a></h2><p>Las preferencias compartidas pueden editarse en esta página. Al hacer\nclic en cualquier elemento de la lista se abre el cuadro de diálogo de\nedición donde se puede editar. El botón de acción flotante en la esquina\ninferior derecha puede utilizarse para añadir un nuevo elemento. Para\nguardar o eliminar el archivo o para descartar los cambios actuales, se\npueden utilizar las opciones respectivas del menú.</section></section><section id=ch:guides class=level1 data-number=3><h1 data-number=3><span class=header-section-number>3</span> <a href=#toc:ch:guides>Guías</a><a href=#ch:guides class=anchor aria-hidden=true></a></h1><section id=sec:adb-over-tcp class=level2 data-number=3.1><h2 data-number=3.1><span class=header-section-number>3.1</span> <a href=#toc:sec:adb-over-tcp>ABD sobre TCP</a><a href=#sec:adb-over-tcp class=anchor aria-hidden=true></a></h2><p>Many root-only features can still be used by enabling ADB over TCP.\nTo do that, a PC or Mac is required with Android platform-tools\ninstalled, and an Android phone with developer options & USB\ndebugging enabled.<div class=\"amalert tip\"><p><strong><em>Root users.</em></strong><p>If superuser permission has been granted to App Manager, it can\nalready execute privileged code without any problem. <strong>Therefore,\nroot users do not need to enable ADB over TCP.</strong> But if you\ninsist on using ADB over TCP, you must revoke superuser permission for\nApp Manager.</div><div class=seealso-inline><p><em>Ver también: <span><a href=#sec:faq:adb-over-tcp>FAQ: ADB over\nTCP</a></span></em></div><section id=subsec:enable-developer-options class=level3 data-number=3.1.1><h3 data-number=3.1.1><span class=header-section-number>3.1.1</span>\n<a href=#toc:subsec:enable-developer-options>Habilitar opciones de\ndesarrollador</a><a href=#subsec:enable-developer-options class=anchor aria-hidden=true></a></h3><section id=subsubsec:location-of-developer-options class=level4 data-number=3.1.1.1><h4 data-number=3.1.1.1><span class=header-section-number>3.1.1.1</span> Ubicación de las opciones\nde desarrollador<a href=#subsubsec:location-of-developer-options class=anchor aria-hidden=true></a></h4><p><strong>Developer options</strong> is located in Android\n<strong>Settings</strong>, either directly near the bottom of the page\n(in most ROMs) or under some other settings, such as\n<strong>System</strong> (Google Pixel, Lineage OS, Asus Zenfone 8.0+),\n<strong>Additional Settings</strong> (Xiaomi MIUI, Oppo ColorOS),\n<strong>More Settings</strong> (Vivo FuntouchOS), <strong>More</strong>\n(ZTE Nubia). Unlike other options, it is not visible until explicitly\nenabled by the user. If it is already enabled, you can use the search\nbox in Android <strong>Settings</strong> to locate it as well.</section><section id=cómo-activar-las-opciones-del-desarrollador class=level4 data-number=3.1.1.2><h4 data-number=3.1.1.2><span class=header-section-number>3.1.1.2</span> Cómo activar las opciones\ndel desarrollador<a href=#cómo-activar-las-opciones-del-desarrollador class=anchor aria-hidden=true></a></h4><p>This option is available within Android <strong>Settings</strong> as\nwell but like the location of the developer options, it also differs\nfrom device to device. But in general, you have to find <strong>Build\nnumber</strong> (or <strong>MIUI version</strong> for MIUI ROMs and\n<strong>Software version</strong> for Vivo FuntouchOS,\n<strong>Version</strong> for Oppo ColorOS) and tap it at least 7 (seven)\ntimes until you finally get a message saying <em>You are now a\ndeveloper</em> (you may be prompted to insert pin/password/pattern or\nsolve captchas at this point). In most devices, it is located at the\nbottom of the settings page, inside <strong>About Phone</strong>. But\nthe best way to find it is to use the search box.</section></section><section id=subsec:enable-usb-debugging class=level3 data-number=3.1.2><h3 data-number=3.1.2><span class=header-section-number>3.1.2</span>\n<a href=#toc:subsec:enable-usb-debugging>Habilitar depuración\nUSB</a><a href=#subsec:enable-usb-debugging class=anchor aria-hidden=true></a></h3><p>After <a href=#subsubsec:location-of-developer-options>locating the\ndeveloper options</a>, enable <strong>Developer option</strong> (if not\nalready). After that, scroll down a bit until you will find the option\n<strong>USB debugging</strong>. Use the toggle button on the right-hand\nside to enable it. At this point, you may get an alert prompt where you\nmay have to click <em>OK</em> to actually enable it. You may also have\nto enable some other options depending on device vendor and ROM. Here\nare some examples:<section id=xiaomi-miui class=level4 data-number=3.1.2.1><h4 data-number=3.1.2.1><span class=header-section-number>3.1.2.1</span> Xiaomi (MIUI)<a href=#xiaomi-miui class=anchor aria-hidden=true></a></h4><p>Habilite <strong>Depuración USB (Configuración de seguridad)</strong>\ntambién.</section><section id=huawei-emui class=level4 data-number=3.1.2.2><h4 data-number=3.1.2.2><span class=header-section-number>3.1.2.2</span> HUAWEI (EMUI)<a href=#huawei-emui class=anchor aria-hidden=true></a></h4><p>Enable <strong>Allow ADB debugging in charge only mode</strong> as\nwell. When connecting to your PC or Mac, you may get a prompt saying\n<strong>Allow access to device data?</strong> in which case click\n<strong>YES, ALLOW ACCESS</strong>.<div class=\"amalert tip\"><p><strong><em>Notice.</em></strong><p>Often the <strong>USB debugging</strong> mode could be disabled\nautomatically by the system. If that’s the case, repeat the above\nprocedure.</div></section><section id=realme class=level4 data-number=3.1.2.3><h4 data-number=3.1.2.3><span class=header-section-number>3.1.2.3</span> Realme<a href=#realme class=anchor aria-hidden=true></a></h4><p>Depending on the device and the version of operating system, you have\nto enable <strong>Disable Permission Monitoring</strong>, or <strong>USB\ndebugging (Security settings)</strong> along with <strong>Install via\nUSB</strong>.</section><section id=oneplus-oxygen-os class=level4 data-number=3.1.2.4><h4 data-number=3.1.2.4><span class=header-section-number>3.1.2.4</span> OnePlus (Oxygen OS)<a href=#oneplus-oxygen-os class=anchor aria-hidden=true></a></h4><p>Depending on the device and the version of operating system, you have\nto enable <strong>Disable Permission Monitoring</strong>.</section><section id=lg class=level4 data-number=3.1.2.5><h4 data-number=3.1.2.5><span class=header-section-number>3.1.2.5</span> LG<a href=#lg class=anchor aria-hidden=true></a></h4><p>Aseguraré de tener <strong>USB tethering</strong> habilitado.</section><section id=solución-de-problemas class=level4 data-number=3.1.2.6><h4 data-number=3.1.2.6><span class=header-section-number>3.1.2.6</span> Solución de problemas<a href=#solución-de-problemas class=anchor aria-hidden=true></a></h4><p>In case <strong>USB Debugging</strong> is greyed out, you can do the\nfollowing:<ol class=incremental><li><p>Make sure you enabled USB debugging before connecting your phone\nto the PC or Mac via USB cable<li><p>Enable USB tethering after connecting to PC or Mac via USB\ncable<li><p>(For Samsung) If your device is running KNOX, you may have to\nfollow some additional steps. See official documentations or consult\nsupport for further assistant</ol></section></section><section id=subsec:setup-adb-on-pc-or-mac class=level3 data-number=3.1.3><h3 data-number=3.1.3><span class=header-section-number>3.1.3</span>\n<a href=#toc:subsec:setup-adb-on-pc-or-mac>Configurar ADB en PC o\nMac</a><a href=#subsec:setup-adb-on-pc-or-mac class=anchor aria-hidden=true></a></h3><p>In order to enable ADB over TCP, you have to set up ADB in your PC or\nMac. <strong><em>Lineage OS users can skip to §<a href=#subsubsec:lineage-os data-reference-type=ref data-reference=subsubsec:lineage-os>3.1.4.1</a>.</em></strong><section id=windows class=level4 data-number=3.1.3.1><h4 data-number=3.1.3.1><span class=header-section-number>3.1.3.1</span> Windows<a href=#windows class=anchor aria-hidden=true></a></h4><ol class=incremental><li><p>Download the latest version of <a href=https://dl.google.com/android/repository/platform-tools-latest-windows.zip>Android\nSDK Platform-Tools</a> for Windows<li><p>Extract the contents of the zip file into any directory (such as\n<code>C:\\</code><span><code>adb</code></span>) and navigate to that\ndirectory using <em>Explorer</em><li><p>Open <strong>Command Prompt</strong>,\n<strong>PowerShell</strong>, or <strong>Terminal</strong> from this\ndirectory. You can do it manually from the start menu or by holding\n<code>Shift</code> and right clicking within the directory in <em>File\nExplorer</em> and then clicking either on <em>Open command window\nhere</em>, or <em>Open PowerShell window here</em> (depending on what\nyou have installed). You can now access ADB by typing <code>adb</code>\n(Command Prompt) or <code>./adb</code> (PowerShell). Do not close this\nwindow yet.</ol><div class=\"amalert tip\"><p><strong><em>Tip.</em></strong><p>If you have <a href=https://learn.microsoft.com/en-us/windows/package-manager/winget/>WinGet</a>\ninstalled, you can install ADB using the following command:<div class=sourceCode id=cb3 data-frame=lines><pre class=\"sourceCode bash\"><code class=\"sourceCode bash\"><span id=cb3-1><a href=#cb3-1 aria-hidden=true tabindex=-1></a><span class=ex>winget</span> install <span class=at>--id</span> Google.PlatformTools</span></code></pre></div><p>After that, you can simply type <code>adb</code> to access ADB.</div></section><section id=macos class=level4 data-number=3.1.3.2><h4 data-number=3.1.3.2><span class=header-section-number>3.1.3.2</span> macOS<a href=#macos class=anchor aria-hidden=true></a></h4><ol class=incremental><li><p>Download the latest version of <a href=https://dl.google.com/android/repository/platform-tools-latest-darwin.zip>Android\nSDK Platform-Tools</a> for macOS<li><p>Extract the contents of the zip file into a directory by clicking\non it. After that, navigate to that directory using <em>Finder</em> and\nlocate <code>adb</code><li><p>Open <strong>Terminal</strong> using <em>Launchpad</em> or\n<em>Spotlight</em> and drag-and-drop <code>adb</code> from the\n<em>Finder</em> window into the <em>Terminal</em> window. Do not close\nthe <em>Terminal</em> window yet</ol><div class=\"amalert tip\"><p><strong><em>Tip.</em></strong><p>If you have <a href=https://brew.sh>Homebrew</a> installed, you can\ninstall ADB using the following command:<div class=sourceCode id=cb4 data-frame=lines><pre class=\"sourceCode bash\"><code class=\"sourceCode bash\"><span id=cb4-1><a href=#cb4-1 aria-hidden=true tabindex=-1></a><span class=ex>brew</span> install <span class=at>--cask</span> android-platform-tools</span></code></pre></div><p>After that, you can simply type <code>adb</code> in any\n<em>Terminal</em> window to access ADB.</div></section><section id=linux class=level4 data-number=3.1.3.3><h4 data-number=3.1.3.3><span class=header-section-number>3.1.3.3</span> Linux<a href=#linux class=anchor aria-hidden=true></a></h4><ol class=incremental><li><p>In your favourite terminal emulator, run the following\ncommand:<div class=sourceCode id=cb5 data-frame=lines data-autogobble><pre class=\"sourceCode bash\"><code class=\"sourceCode bash\"><span id=cb5-1><a href=#cb5-1 aria-hidden=true tabindex=-1></a><span class=bu>cd</span> ~/Downloads <span class=kw>&amp;&amp;</span> <span class=ex>curl</span> <span class=at>-o</span> platform-tools.zip <span class=at>-L</span> <span class=dt>\\</span></span>\n<span id=cb5-2><a href=#cb5-2 aria-hidden=true tabindex=-1></a>https://dl.google.com/android/repository/platform-tools-latest-linux.zip <span class=kw>&amp;&amp;</span> <span class=dt>\\</span></span>\n<span id=cb5-3><a href=#cb5-3 aria-hidden=true tabindex=-1></a><span class=fu>unzip</span> platform-tools.zip <span class=kw>&amp;&amp;</span> <span class=fu>rm</span> platform-tools.zip <span class=kw>&amp;&amp;</span> <span class=bu>cd</span> platform-tools</span></code></pre></div><li><p>If it is successful, you can simply type <code>./adb</code> in\nthe in <em>same</em> terminal emulator window or type\n<code>~/Downloads/platform-tools/adb</code> in any terminal emulator to\naccess ADB.</ol></section></section><section id=subsec:configure-adb-over-tcp class=level3 data-number=3.1.4><h3 data-number=3.1.4><span class=header-section-number>3.1.4</span>\n<a href=#toc:subsec:configure-adb-over-tcp>Configurar ADB sobre\nTCP</a><a href=#subsec:configure-adb-over-tcp class=anchor aria-hidden=true></a></h3><section id=subsubsec:lineage-os class=level4 data-number=3.1.4.1><h4 data-number=3.1.4.1><span class=header-section-number>3.1.4.1</span> Lineage OS 17.1 y\nanteriores<a href=#subsubsec:lineage-os class=anchor aria-hidden=true></a></h4><p>Los usuarios de Lineage OS (o sus derivados) pueden habilitar\ndirectamente ADB sobre TCP utilizando las opciones de desarrollador.\nPara habilitarlo vaya a las <strong>opciones de desarrollador</strong>,\ndesplácese hacia abajo hasta encontrar <strong>ADB sobre red</strong>.\nAhora, utilice el botón de conmutación en el lado derecho para\nhabilitarlo y pasar a §<a href=#subsec:adb-mode-in-app-manager data-reference-type=ref data-reference=subsec:adb-mode-in-app-manager>[subsec:adb-mode-in-app-manager]</a>.</section><section id=subsubsec:enable-adb-over-tcp-via-pc-or-mac class=level4 data-number=3.1.4.2><h4 data-number=3.1.4.2><span class=header-section-number>3.1.4.2</span> Habilitar ADB sobre TCP a\ntravés de PC o Mac<a href=#subsubsec:enable-adb-over-tcp-via-pc-or-mac class=anchor aria-hidden=true></a></h4><p>For other ROMs, you can do this using the command\nprompt/PowerShell/terminal emulator that you’ve opened in the step 3 of\nthe previous section. In this section, I will use <code>adb</code> to\ndenote <code>./adb</code>, <code>adb</code> or any other command that\nyou needed to use based on your platform and software in the previous\nsection.<ol class=incremental><li><p>Connect your device to your PC or Mac using a USB cable. For some\ndevices, it is necessary to turn on <em>File transfer mode (MTP)</em> as\nwell<li><p>To confirm that everything is working as expected, type\n<code>adb devices</code> in your terminal. If your device is connected\nsuccessfully, you will see something like this:<pre><code>List of devices attached\nxxxxxxxx  device</code></pre><div class=\"amalert tip\"><p><strong><em>Notice.</em></strong><p>In some Android phones, an alert prompt will be appeared with a\nmessage <strong>Allow USB Debugging</strong> in which case, check\n<em>Always allow from this computer</em> and click\n<strong>Allow</strong>.</div><li><p>Finally, run the following command to enable ADB over TCP:<div class=sourceCode id=cb7 data-frame=lines data-autogobble><pre class=\"sourceCode bash\"><code class=\"sourceCode bash\"><span id=cb7-1><a href=#cb7-1 aria-hidden=true tabindex=-1></a><span class=ex>adb</span> tcpip 5555</span></code></pre></div></ol><div class=\"amalert danger\"><p><strong><em>Danger.</em></strong><p>You cannot disable developer options or USB debugging after enabling\nADB over TCP.</div></section><section id=subsubsec:adb-mode-in-app-manager class=level4 data-number=3.1.4.3><h4 data-number=3.1.4.3><span class=header-section-number>3.1.4.3</span> Habilitar el modo ADB en\nApp Manager<a href=#subsubsec:adb-mode-in-app-manager class=anchor aria-hidden=true></a></h4><p>After enabling ADB over TCP, relaunch App Manager. App Manager should\ndetect ADB mode automatically. If it cannot, you can change the mode of\noperation to ADB over TCP in the <a href=#subsec:mode-of-operation>settings page</a>. There, you can also\nverify whether App Manager has correctly detected ADB as indicated by\nthe <em>inferred mode</em>.<div class=\"amalert tip\"><p><strong><em>Notice.</em></strong><p>In some Android devices, the USB cable is needed to be disconnected\nfrom the PC before connecting to App Manager.</div><div class=\"amalert warning\"><p><strong><em>Warning.</em></strong><p>ADB over TCP will be disabled after a reboot. In that case, you have\nto follow §<a href=#subsubsec:enable-adb-over-tcp-via-pc-or-mac data-reference-type=ref data-reference=subsubsec:enable-adb-over-tcp-via-pc-or-mac>3.1.4.2</a>\nagain.</div></section></section></section><section id=sec:wireless-debugging class=level2 data-number=3.2><h2 data-number=3.2><span class=header-section-number>3.2</span> <a href=#toc:sec:wireless-debugging>Wireless Debugging</a><a href=#sec:wireless-debugging class=anchor aria-hidden=true></a></h2><p>If you are running Android 11 or later and capable of connecting to a\nWi-Fi network for, at least, a few moments, Wireless Debugging is the\nrecommended approach as it offers more protection than <a href=#sec:adb-over-tcp>ADB over TCP</a>. It requires two steps:<ol class=incremental><li><p><strong>ADB pairing.</strong> The initial and a bit complex step\nfor a novice user. Fortunately, this step is not required all the\ntime.<li><p><strong>Connecting to ADB.</strong> Needs to be done every time\nyou reboot your phone. App Manager can also automate this step in most\ndevices.</ol><section id=subsec:enable-developer-options-and-usb-debugging class=level3 data-number=3.2.1><h3 data-number=3.2.1><span class=header-section-number>3.2.1</span>\n<a href=#toc:subsec:enable-developer-options-and-usb-debugging>Enable\ndeveloper options and USB Debugging</a><a href=#subsec:enable-developer-options-and-usb-debugging class=anchor aria-hidden=true></a></h3><p>See §<a href=#subsec:enable-developer-options data-reference-type=ref data-reference=subsec:enable-developer-options>3.1.1</a> and §<a href=#subsec:enable-usb-debugging data-reference-type=ref data-reference=subsec:enable-usb-debugging>3.1.2</a>.</section><section id=subsec:enable-wireless-debugging class=level3 data-number=3.2.2><h3 data-number=3.2.2><span class=header-section-number>3.2.2</span>\n<a href=#toc:subsec:enable-wireless-debugging>Enable Wireless\nDebugging</a><a href=#subsec:enable-wireless-debugging class=anchor aria-hidden=true></a></h3><p>In the <strong>Developer options</strong> page, find <strong>Wireless\ndebugging</strong> and click to open it. In the new page, turn on\n<em>Use wireless debugging</em>. Depending on the operating system, you\nmight see a dialog prompt asking you to verify your decision. If that is\nthe case, click <em>Allow</em>.<div class=\"amalert tip\"><p><strong><em>Tip.</em></strong><p>For easy access, you might want to add <strong>Wireless\ndebugging</strong> in the notification tiles section. To do this, find\n<strong>Quick settings developer tiles</strong> in the <strong>Developer\noptions</strong> page and click to open it. In the new window, enable\n<em>Wireless debugging</em>. In case you do not see this setting, you\nmay find a <strong>Wireless debugging</strong> tile in the tile\ncustomization panel.</div></section><section id=subsec:pair-adb-with-app-manager class=level3 data-number=3.2.3><h3 data-number=3.2.3><span class=header-section-number>3.2.3</span>\n<a href=#toc:subsec:pair-adb-with-app-manager>Pair ADB with App\nManager</a><a href=#subsec:pair-adb-with-app-manager class=anchor aria-hidden=true></a></h3><p>In App Manager, navigate to <strong>Settings</strong> > <a href=#subsec:mode-of-operation>Mode of operation</a> and then enable\n<em>Wireless debugging</em>. At this, App Manager will try to establish\na wireless debugging connection automatically which will fail if it has\nnot been paired before. Once it fails, it will ask you to either connect\nor pair ADB. Select <em>pair</em> and a new dialog will appear. It will\nask you to navigate to the <strong>Wireless debugging</strong> page.<div class=\"amalert tip\"><p><strong><em>Note.</em></strong><p>As of v4.0.0, pairing is done using a notification prompt. So, if you\nhave disabled notification for App Manager, you must enable it\nfirst.</div><p>In the <strong>Wireless debugging</strong> page, select <strong>Pair\ndevice with pairing code</strong>. At this, a dialog containing a\npairing code will be displayed. A notification asking for the pairing\ncode will also be visible almost instantly. Insert the pairing code in\nthe input box in the notification and click <em>pair</em>. If the\npairing is successful, App Manager will display notification with the\nmessage “paired”, and the dialog in the <strong>Wireless\ndebugging</strong> page will be dismissed automatically. You will also\nbe able to see App Manager listed as an ADB client in the same page.<div class=\"amalert tip\"><p><strong><em>Notice.</em></strong><p>If you do not use App Manager in ADB mode for a while, App Manager\nmight be removed from the list of clients. In that case, you have to\nrepeat the above procedure.</div></section><section id=subsec:connect-app-manager-to-adb class=level3 data-number=3.2.4><h3 data-number=3.2.4><span class=header-section-number>3.2.4</span>\n<a href=#toc:subsec:connect-app-manager-to-adb>Connect App Manager to\nADB</a><a href=#subsec:connect-app-manager-to-adb class=anchor aria-hidden=true></a></h3><p>App Manager should be able to connect to ADB automatically if the\nmode of operation is set to <em>auto</em>, <em>ADB over TCP</em> or\n<em>Wireless debugging</em>. If this is not the case, select\n<em>Wireless debugging</em> in <strong>Settings</strong> > <a href=#subsec:mode-of-operation>Mode of operation</a>. If App Manager\nfails to detect or connect to ADB, it will ask you to connect or pair\nADB. Select <em>connect</em>.<p>Now, navigate to the <strong>Wireless debugging</strong> page in\nAndroid settings, and note down the port number displayed in the page.\nIn App Manager’s dialog prompt, replace the port number with the one you\nhave noted earlier, and click <em>connect</em>.<p>Once a connection has been established, you can disable\n<strong>Wireless debugging</strong> in Android settings.<div class=\"amalert danger\"><p><strong><em>Caution.</em></strong><p>Never disable <strong>USB Debugging</strong> or any other additional\noptions described in §<a href=#subsec:enable-developer-options-and-usb-debugging data-reference-type=ref data-reference=subsec:enable-developer-options-and-usb-debugging>3.2.1</a>.\nIf you do this, the remote server used by App Manager will be stopped,\nand you may have to start all over again.</div></section></section><section id=sec:backup-restore class=level2 data-number=3.3><h2 data-number=3.3><span class=header-section-number>3.3</span> <a href=#toc:sec:backup-restore>Back up/Restore</a><a href=#sec:backup-restore class=anchor aria-hidden=true></a></h2><p>App Manager has a modern, advanced and easy-to-use backup/restore\nsystem implemented from the scratch. This is probably the only app that\nhas the ability to restore not only the app or its data but also\npermissions and rules that you’ve configured within App Manager. You can\nalso choose to back up an app multiple times (with custom names) or for\nall users.<div class=seealso><p><em>Ver también:</em><ul class=incremental><li><p><a href=#subsec:1-click-back-up>1-Click Ops: Back\nup</a><li><p><a href=#subsec:1-click-restore>1-Click Ops:\nRestore</a></ul></div><section id=subsec:backup-location class=level3 data-number=3.3.1><h3 data-number=3.3.1><span class=header-section-number>3.3.1</span>\n<a href=#toc:subsec:backup-location>Location</a><a href=#subsec:backup-location class=anchor aria-hidden=true></a></h3><p>Back up/restore is a part of <a href=#subsec:batch-operations>batch\noperations</a>. It is also located inside the <a href=#subsubsec:app-info-options-menu>options menu</a> in the <a href=#subsec:app-info-tab>App Info tab</a>. Clicking on\n<strong>Backup/Restore</strong> opens the <strong>Backup\nOptions</strong>. Backups are located at\n<code>/storage/emulated/0/AppManager</code> by default. You can\nconfigure custom backup location in the <a href=#subsubsec:backup-volume>settings page</a> in which case the\nbackups will be located at the <code>AppManager</code> folder in the\nselected volume.<div class=\"amalert tip\"><p><strong><em>Note.</em></strong><p>If one or more selected apps do not have any backup, the\n<strong>Restore</strong> and <strong>Delete Backup</strong> options will\nnot be displayed.</div></section><section id=subsec:backup-restore-backup-options class=level3 data-number=3.3.2><h3 data-number=3.3.2><span class=header-section-number>3.3.2</span>\n<a href=#toc:subsec:backup-restore-backup-options>Backup Options</a><a href=#subsec:backup-restore-backup-options class=anchor aria-hidden=true></a></h3><p>Backup options (internally known as backup flags) let you customise\nthe backups on the fly. However, the customisations will not be\nremembered for the future backups. If you want to customise this dialog,\nuse <a href=#subsubsec:settings-backup-options>Backup Options</a> in\nthe <a href=#sec:settings-page>Settings page</a>.<p>A complete description of the backup options is given below:<ul class=incremental><li><p><strong>APK files.</strong> Whether to back up the APK files.\nThis includes the <em>base APK</em> file along with the\n<code>split APK</code> files if they exist.<li><p><strong>Internal data.</strong> Whether to back up the internal\ndata directories. These directories are located at\n<code>/data/user/&lt;user_id></code> and (for Android N or later)\n<code>/data/user_de/&lt;user_id></code>.<li><p><strong>External data.</strong> Whether to back up data\ndirectories located in the internal memory as well as SD Card (if\nexists). External data directories often contain non-essential app data\nor media files (instead of using the dedicated media folder) and may\nincrease the backup size. However, it might be essential for some apps.\nAlthough it isn’t checked by default (as it might dramatically increase\nthe size of the backups), you may have to check it in order to ensure a\nsmooth restore of your backups.<div class=\"amalert warning\"><p><strong><em>Caution.</em></strong><p>Internal data folders should always be backed up if you are going to\nback up the external data folders. However, it could be useful to back\nup only the external folders if the app in question downloads a lot of\nassets from the Internet.</div><li><p><strong>OBB and media.</strong> Whether to back up or restore the\nOBB and the media directories located in the external storage or the SD\nCard. This is useful for games and the graphical software which actually\nuse these folders.<li><p><strong>Cache.</strong> Android apps have multiple cache\ndirectories located at every data directories (both internal and\nexternal). There are two types of cache: <strong>cache</strong> and\n<strong>code cache</strong>. Disabling this option excludes both cache\ndirectories from all the data directories. It is generally advised to\nexclude cache directories since most apps do not clear the cache\nregularly and usually handled by the OS itself. Apps such as Telegram\nmay use a very large cache (depending on the storage space) which may\ndramatically increase the backup size. When it is disabled, AM also\nignores the <strong>no_backup</strong> directories.<li><p><strong>Extras.</strong> Backup/restore app permissions, net\npolicy, battery optimization, SSAID, etc., enabled by default. Note\nthat, blocking rules are applied <em>after</em> applying the extras. So,\nif an item is present in both places, it will be overwritten (i.e., the\none from the blocking rules will be used).<li><p><strong>Rules.</strong> This option lets you back up blocking\nrules configured within App Manager. This might come in handy if you\nhave customised permissions or block some components using App Manager\nas they will also be backed up or restored when you enable this\noption.<li><p><strong>Backup Multiple.</strong> Whether this is a multiple\nbackup. By default, backups are saved using their user ID. Enabling this\noption allows you to create additional backups. These backups use the\ncurrent date-time as the default backup name, but you can also specify\ncustom backup name using the input field displayed when you click on the\n<strong>Backup</strong> button.<li><p><strong>Custom users.</strong> Backup or restore for the selected\nusers instead of only the current user. This option is only displayed if\nthe system has more than one user.<li><p><strong>Skip signature checks.</strong> When taking a backup,\nchecksum of every file (as well as the signing certificate(s) of the\nbase APK file) is generated and stored in the <code>checksums.txt</code>\nfile. When you restore the backup, the checksums are generated again and\nare matched with the checksums stored in the said file. Enabling this\noption will disable the signature checks. This option is applied only\nwhen you restore a backup. During backup, the checksums are generated\nregardless of this option.<div class=\"amalert warning\"><p><strong><em>Caution.</em></strong><p>You should always disable this option to ensure that your backups are\nnot modified by any third-party applications. However, this would only\nwork if you enabled encryption.</div></ul><div class=seealso-inline><p><em>Ver también: <span><a href=#subsubsec:settings-encryption>Settings:\nEncryption</a></span></em></div></section><section id=subsec:backup-restore-backup class=level3 data-number=3.3.3><h3 data-number=3.3.3><span class=header-section-number>3.3.3</span>\n<a href=#toc:subsec:backup-restore-backup>Backup</a><a href=#subsec:backup-restore-backup class=anchor aria-hidden=true></a></h3><p>Backup respects all the backup options except <strong>Skip signature\nchecks</strong>. If base backups (i.e., backups that don’t have the\n<strong>Backup Multiple</strong> option) already exist, you will get a\nwarning as the backups will be overwritten. If <strong>Backup\nMultiple</strong> is set, you have an option to input the backup name,\nor you can leave it blank to use the current date-time.</section><section id=subsec:backup-restore-restore class=level3 data-number=3.3.4><h3 data-number=3.3.4><span class=header-section-number>3.3.4</span>\n<a href=#toc:subsec:backup-restore-restore>Restore</a><a href=#subsec:backup-restore-restore class=anchor aria-hidden=true></a></h3><p>Restore respects all the backup options and will fail if <strong>APK\nfiles</strong> option is set, but the backup doesn’t contain such\nbackups or in other cases, if the app isn’t installed. When restoring\nbackups for multiple packages, you can only restore the base backups\n(see <a href=#subsec:backup-restore-backup>backup</a> section for an\nexplanation). However, when restoring backups for a single package, you\nhave the option to select which backup to restore. If <strong>All\nusers</strong> option is set, AM will restore the selected backup for\nall users in the latter case but in the former case, it will restore\nbase backups for the respective users.<div class=\"amalert tip\"><p><strong><em>Notice.</em></strong><p>Apps that use storage access framework (SAF), SSAID or Android\nKeyStore works properly only after an immediate restart.</div></section><section id=subsec:backup-restore-delete-backup class=level3 data-number=3.3.5><h3 data-number=3.3.5><span class=header-section-number>3.3.5</span>\n<a href=#toc:subsec:backup-restore-delete-backup>Delete Backup</a><a href=#subsec:backup-restore-delete-backup class=anchor aria-hidden=true></a></h3><p>Delete backup only respects <strong>All users</strong> option and\nwhen it is selected, only the base backups for all users will be deleted\nwith a prompt. When deleting backups for a single package, another\ndialog will be displayed where you can select the backups to delete.</section></section><section id=sec:automating-tasks class=level2 data-number=3.4><h2 data-number=3.4><span class=header-section-number>3.4</span> <a href=#toc:sec:automating-tasks>Automating Tasks</a><a href=#sec:automating-tasks class=anchor aria-hidden=true></a></h2><p>It is possible to trigger profiles configured inside App Manager via\nthird-party applications such as <strong>Automation</strong> or\n<strong>Tasker</strong>. Traditionally, <code>Intent</code>s are used to\ntrigger such operations.<section id=subsec:generating-authorization-key class=level3 data-number=3.4.1><h3 data-number=3.4.1><span class=header-section-number>3.4.1</span>\n<a href=#toc:subsec:generating-authorization-key>Generating\nauthorization key</a><a href=#subsec:generating-authorization-key class=anchor aria-hidden=true></a></h3><p>In order to ensure proper security, an authorization key is required.\nTo generate a authorization key, go to <strong>Settings</strong> page\nand then <strong>Privacy</strong> > <strong>Authorization\nManager</strong>. If an authorization key has not been generated, it\nwill be generated automatically. The key can be regenerated as\nrequired.<div class=\"amalert danger\"><p><strong><em>Caution.</em></strong><p>Regenerating the authorization key can have some side effects such as\ninvalidation of all the previously configured Intents.</div></section><section id=subsec:at:general-configuration class=level3 data-number=3.4.2><h3 data-number=3.4.2><span class=header-section-number>3.4.2</span>\n<a href=#toc:subsec:at:general-configuration>Configuring tasks</a><a href=#subsec:at:general-configuration class=anchor aria-hidden=true></a></h3><p>The activity\n<code>io.github.muntashirakon.AppManager.crypto.auth.AuthFeatureDemultiplexer</code>\nis responsible for handling all the automations. Sending an intent to\nthe activity lets App Manager perform the designated operation by\nredirecting the <code>Intent</code> to the designated activity or\nservice.<section id=required-extras class=level4 data-number=3.4.2.1><h4 data-number=3.4.2.1><span class=header-section-number>3.4.2.1</span> Required extras<a href=#required-extras class=anchor aria-hidden=true></a></h4><p>It has two primary extras required in all conditions. The key names,\ndata types are all follows:<ol class=incremental><li><p><strong><code>auth</code>.</strong> (String value) The\nauthorization key as described in the earlier section.<li><p><strong><code>feature</code>.</strong> (String value) Name of the\nfeature. Supported features are described in the next section.</ol></section></section><section id=subsec:at:features class=level3 data-number=3.4.3><h3 data-number=3.4.3><span class=header-section-number>3.4.3</span>\n<a href=#toc:subsec:at:features>Features</a><a href=#subsec:at:features class=anchor aria-hidden=true></a></h3><p>App Manager current support a single feature, namely\n<code>profile</code>.</section><section id=subsec:triggering-a-profile class=level3 data-number=3.4.4><h3 data-number=3.4.4><span class=header-section-number>3.4.4</span>\n<a href=#toc:subsec:triggering-a-profile>Triggering a profile</a><a href=#subsec:triggering-a-profile class=anchor aria-hidden=true></a></h3><p>In order to trigger a profile, <code>feature</code> must have the\nvalue <code>profile</code>. In addition, the following extras can be\nincluded:<ol class=incremental><li><p><strong><code>prof</code>.</strong> (String value – required) The\nname of the profile as displayed in the <a href=#sec:profiles-page>Profiles page</a>.<li><p><strong><code>state</code>.</strong> (String value – optional)\nState of the profile – currently <code>on</code> or <code>off</code> –\nas specified in the documentation. If this extra is not set, App Manager\nwill display a prompt where a state must be selected. Therefore, for\ncomplete automation, this option should be set.</ol></section></section><section id=sec:net-policy class=level2 data-number=3.5><h2 data-number=3.5><span class=header-section-number>3.5</span> <a href=#toc:sec:net-policy>Net Policy</a><a href=#sec:net-policy class=anchor aria-hidden=true></a></h2><p>Short for <strong>Network policy</strong> or network policies. It is\nusually located in the Android settings under <strong>Mobile data &\nWifi</strong> section in the app info page of an app. Not all policies\nare guaranteed to be included in this page (e.g. Samsung), and not all\nsettings are well-understood due to lack of documentation. App Manager\ncan display all the net policies declared in the <a href=https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/net/NetworkPolicyManager.java>NetworkPolicyManager</a>.\nPolicies unknown to App Manager will have a <em>Unknown</em> prefix\nalong with the policy constant name and number in the hexadecimal\nformat. Unknown policies should be reported to App Manager for\ninclusion.<p>Net policy allows a user to configure certain networking behaviour of\nan app without modifying the ip tables directly and/or running a\nfirewall app. However, the features it offers largely depend on Android\nversion and ROM. A list of known net policies are listed below:<ol class=incremental><li><p><strong>None</strong> or\n<strong><code>POLICY_NONE</code></strong>: (AOSP) No specific network\npolicy is set. System can still assign rules depending on the nature of\nthe app.<li><p><strong>Reject background data on metered networks</strong> or\n<strong><code>POLICY_REJECT_METERED_BACKGROUND</code></strong>: (AOSP)\nReject network usage on metered networks when the application is in\nbackground.<li><p><strong>Allow background data on metered networks even when Data\nSaver is on</strong> or\n<strong><code>POLICY_ALLOW_METERED_BACKGROUND</code></strong>: (AOSP)\nAllow metered network use in the background even when data saving mode\nis enabled.<li><p><strong>Reject cellular data</strong> or\n<strong><code>POLICY_REJECT_CELLULAR</code></strong> (Android 11+) or\n<strong><code>POLICY_REJECT_ON_DATA</code></strong> (up to Android 10):\n(Lineage OS) Reject mobile/cellular data. Signals network unavailable to\nthe configured app as if the mobile data is inactive.<li><p><strong>Reject VPN data</strong> or\n<strong><code>POLICY_REJECT_VPN</code></strong> (Android 11+) or\n<strong><code>POLICY_REJECT_ON_VPN</code></strong> (up to Android 10):\n(Lineage OS) Reject VPN data. Signals network unavailable to the\nconfigured app as if the VPN is inactive.<li><p><strong>Reject Wi-Fi data</strong> or\n<strong><code>POLICY_REJECT_WIFI</code></strong> (Android 11+) or\n<strong><code>POLICY_REJECT_ON_WLAN</code></strong> (up to Android 10):\n(Lineage OS) Reject Wi-Fi data. Signals network unavailable to the\nconfigured app as if the device is not connected to a Wi-Fi\nnetwork.<li><p><strong>Disable network access</strong> or\n<strong><code>POLICY_REJECT_ALL</code></strong> (Android 11+) or\n<strong><code>POLICY_NETWORK_ISOLATED</code></strong> (up to Android\n10): (Lineage OS) Reject network access in all circumstances. This is\nnot the same as enforcing the other three policies above, and is the\nrecommended policy for dodgy apps. If this policy is enforced, there is\nno need to enforce the other policies.<li><p><strong><code>POLICY_ALLOW_METERED_IN_ROAMING</code></strong>:\n(Samsung) Possibly allow metered network use during roaming. Exact\nmeaning is currently unknown.<li><p><strong><code>POLICY_ALLOW_WHITELIST_IN_ROAMING</code></strong>:\n(Samsung) Possibly allow network use during roaming. Exact meaning is\ncurrently unknown.<li><p><strong>Reject data on metered networks</strong> or\n<strong><code>POLICY_REJECT_METERED</code></strong>: (Motorola) Reject\nnetwork usage if it is a metered network.<li><p><strong>Reject background data</strong> or\n<strong><code>POLICY_REJECT_BACKGROUND</code></strong>: (Motorola)\nReject network usage in the background.<li><p><strong>Disable network access</strong> or\n<strong><code>POLICY_REJECT_ALL</code></strong>: (Motorola) Reject\nnetwork access altogether. Like Lineage OS, it blocks internet\nconnections via iptables. But whether it signals the unavailability of\nnetwork to the configured app is not known.</ol><div class=\"amalert tip\"><p><strong><em>Note.</em></strong><p>Corresponding Lineage OS patches are as follows:<ol class=incremental><li><p><a href=https://github.com/LineageOS/android_frameworks_base/commit/a04932bafbbf7d99efd18276152cc2c9c9b2073e>fw/b:\nSquash of app fw restriction commits</a><li><p><a href=https://github.com/LineageOS/android_frameworks_base/commit/02c8c82854348f52afe2199f310f44b5f578b5b8>fw/b:\nAdd support for per app network isolation</a></ol></div></section></section><section id=ch:faq class=level1 data-number=4><h1 data-number=4><span class=header-section-number>4</span> <a href=#toc:ch:faq>Frequently Asked Questions</a><a href=#ch:faq class=anchor aria-hidden=true></a></h1><section id=sec:faq:app-components class=level2 data-number=4.1><h2 data-number=4.1><span class=header-section-number>4.1</span> <a href=#toc:sec:faq:app-components>App Components</a><a href=#sec:faq:app-components class=anchor aria-hidden=true></a></h2><section id=subsec:faq:what-are-app-components class=level3 data-number=4.1.1><h3 data-number=4.1.1><span class=header-section-number>4.1.1</span>\n<a href=#toc:subsec:faq:what-are-app-components>What are the\napplication components?</a><a href=#subsec:faq:what-are-app-components class=anchor aria-hidden=true></a></h3><p>Activities, services, broadcast receivers (or only receivers) and\ncontent providers (or only providers) are jointly called application\ncomponents. More technically, they all inherit the <a href=https://developer.android.com/reference/android/content/pm/ComponentInfo>ComponentInfo</a>\nclass and can be launched via Intent.</section><section id=subsec:faq:how-components-blocked class=level3 data-number=4.1.2><h3 data-number=4.1.2><span class=header-section-number>4.1.2</span>\n<a href=#toc:subsec:faq:how-components-blocked>How are the tracker and\nother components blocked in App Manager? What are its limitations?</a><a href=#subsec:faq:how-components-blocked class=anchor aria-hidden=true></a></h3><p>App Manager typically blocks application components (or tracker\ncomponents) using a method called <a href=https://carteryagemann.com/pages/android-intent-firewall.html>Intent\nFirewall (IFW)</a>, it is superior to other methods such as <em>pm</em>\n(PackageManager), <a href=https://github.com/RikkaApps/Shizuku>Shizuku</a> or any other\nmethod that uses the package manager to enable or disable the\ncomponents. If a component is disabled by the latter methods, the\napplication itself can detect that the component is being blocked and\ncan re-enable it as it has full access to its own components. (Many\ndeceptive applications actually do this in order to keep the tracker\ncomponents unblocked.) On the other hand, IFW is a true firewall and the\napplication cannot detect if its components are being blocked. App\nManager uses the term <em>block</em> rather than <em>disable</em> for\nthis reason.<p>Even IFW has some limitations which are primarily applicable for the\nsystem applications:<ul class=incremental><li><p>The application in question is whitelisted by the system i.e. the\nsystem cannot function properly without these applications and may cause\nrandom crashes. These applications include but not limited to Android\nSystem, System UI, Phone Services. They will continue to work even if\nthey are disabled or blocked.<li><p>Another system application or system process has activated a\nspecific component of the application in question via interprocess\ncommunication (IPC). In this case, the component will be activated\nregardless of blocking status or even if the entire application is\ndisabled. If there is such a system application that is not needed, the\nonly way to prevent it from running is by getting rid of it.</ul></section><section id=subsec:faq:components-blocked-by-others class=level3 data-number=4.1.3><h3 data-number=4.1.3><span class=header-section-number>4.1.3</span>\n<a href=#toc:subsec:faq:components-blocked-by-others>Does app\ncomponents blocked by other tools retained in App Manager?</a><a href=#subsec:faq:components-blocked-by-others class=anchor aria-hidden=true></a></h3><p><strong>No.</strong> But the application components blocked by the\nsystem or any other tools are displayed in the <a href=#subsec:component-tabs>component tabs</a>. These rules can be\nimported from <a href=#par:import-existing-rules>Settings</a>.\nHowever, it is not possible for App Manager to distinguish the\ncomponents blocked by the third-party tools and components blocked by\nthe system. Therefore, the applications listed in the import page should\nbe selected with care.</section><section id=subsec:faq:components-reblocked-in-am class=level3 data-number=4.1.4><h3 data-number=4.1.4><span class=header-section-number>4.1.4</span>\n<a href=#toc:subsec:faq:components-reblocked-in-am>What happens to the\ncomponents blocked by App Manager which were previously blocked by other\ntools?</a><a href=#subsec:faq:components-reblocked-in-am class=anchor aria-hidden=true></a></h3><p><em>App Manager blocks the components again</em> if requested. In\ncase of unblocking, they will be reverted to the default state as\nspecified in the manifest of the application. But if the components were\nblocked by <a href=https://www.myandroidtools.com>MyAndroidTools\n(MAT)</a> with IFW method, they will not be unblocked by App Manager as\nit uses a different format. To fix this issue, the rules have to be\nimported from <a href=#par:import-existing-rules>Settings</a> at\nfirst, in which case MAT’s configurations will be permanently\nremoved.</section><section id=subsec:faq:what-is-instant-component-blocking class=level3 data-number=4.1.5><h3 data-number=4.1.5><span class=header-section-number>4.1.5</span>\n<a href=#toc:subsec:faq:what-is-instant-component-blocking>What is\ninstant component blocking?</a><a href=#subsec:faq:what-is-instant-component-blocking class=anchor aria-hidden=true></a></h3><p>When you block a component in the <a href=#sec:app-details-page>App\nDetails page</a>, the blocking is not applied by default. It is only\napplied when you apply blocking using the <em>Apply rules</em> option in\nthe top-right menu. If you enable <a href=#subsubsec:instant-component-blocking>instant component\nblocking</a>, blocking will be applied as soon as you block a component.\nIf you choose to block tracker components, however, blocking is applied\nautomatically regardless of this setting. You can also remove blocking\nfor an application by simply clicking on <em>Remove rules</em> in the\nsame menu in the <strong>App Details page</strong>. Since the default\nbehaviour gives you more control over applications, it is better to keep\n<em>instant component blocking</em> option disabled.</section><section id=subsec:tracker-classes-versus-tracker-components class=level3 data-number=4.1.6><h3 data-number=4.1.6><span class=header-section-number>4.1.6</span>\n<a href=#toc:subsec:tracker-classes-versus-tracker-components>Tracker\nclasses versus tracker components</a><a href=#subsec:tracker-classes-versus-tracker-components class=anchor aria-hidden=true></a></h3><p>All application components are classes but not all classes are\ncomponents. In fact, only a few of the classes are components. That\nbeing said, <a href=#sec:scanner-page>scanner page</a> displays a list\nof trackers along with the number of classes, not just the components.\nIn all other pages, trackers and tracker components are used\nsynonymously to denote tracker components, i.e. blocking tracker means\nblocking tracker components, not tracker classes.<div class=\"amalert tip\"><p><strong><em>Info.</em></strong><p>Tracker classes that are not components cannot be blocked. They can\nonly be removed by editing the application itself.</div></section></section><section id=sec:faq:adb-over-tcp class=level2 data-number=4.2><h2 data-number=4.2><span class=header-section-number>4.2</span> <a href=#toc:sec:faq:adb-over-tcp>ADB over TCP</a><a href=#sec:faq:adb-over-tcp class=anchor aria-hidden=true></a></h2><section id=subsec:faq:enable-adb-on-every-restart class=level3 data-number=4.2.1><h3 data-number=4.2.1><span class=header-section-number>4.2.1</span>\n<a href=#toc:subsec:faq:enable-adb-on-every-restart>Do I have to\nenable ADB over TCP everytime I restart?</a><a href=#subsec:faq:enable-adb-on-every-restart class=anchor aria-hidden=true></a></h3><p>Unfortunately, yes. This is because the ADB daemon, the process\nresponsible for ADB connection, is also restarted after a reboot, and it\ndoes not re-enable ADB over TCP.</section><section id=subsec:faq:usb-debugging class=level3 data-number=4.2.2><h3 data-number=4.2.2><span class=header-section-number>4.2.2</span>\n<a href=#toc:subsec:faq:usb-debugging>Cannot enable USB debugging.\nWhat to do?</a><a href=#subsec:faq:usb-debugging class=anchor aria-hidden=true></a></h3><p>See §<a href=#subsec:enable-usb-debugging data-reference-type=ref data-reference=subsec:enable-usb-debugging>3.1.2</a> in Capítulo <a href=#ch:guides data-reference-type=ref data-reference=ch:guides>3</a>.</section><section id=subsec:faq:block-components-using-adb class=level3 data-number=4.2.3><h3 data-number=4.2.3><span class=header-section-number>4.2.3</span>\n<a href=#toc:subsec:faq:block-components-using-adb>Can I block tracker\nor any other application components using ADB over TCP?</a><a href=#subsec:faq:block-components-using-adb class=anchor aria-hidden=true></a></h3><p>ADB has limited number of <a href=https://github.com/aosp-mirror/platform_frameworks_base/blob/master/packages/Shell/AndroidManifest.xml>permissions</a>\nand controlling application components is not one of them. However, the\ncomponents of a <em>test-only</em> app can be controlled via ADB. If App\nManager detects such an application, it enables the blocking options\nautomatically.</section><section id=subsec:faq:adb-features class=level3 data-number=4.2.4><h3 data-number=4.2.4><span class=header-section-number>4.2.4</span>\n<a href=#toc:subsec:faq:adb-features>Which features can be used in ADB\nmode?</a><a href=#subsec:faq:adb-features class=anchor aria-hidden=true></a></h3><p>Supported features are enabled automatically in the ADB mode.\nSupported features include disabling, force-stopping, clearing\napplication data, granting or revoking app ops and permissions, and so\non. It is also possible to install or uninstall applications without any\nprompt from the system.</section></section><section id=sec:faq:miscellanea class=level2 data-number=4.3><h2 data-number=4.3><span class=header-section-number>4.3</span> <a href=#toc:sec:faq:miscellanea>Miscellanea</a><a href=#sec:faq:miscellanea class=anchor aria-hidden=true></a></h2><section id=subsec:faq:no-root-no-harms class=level3 data-number=4.3.1><h3 data-number=4.3.1><span class=header-section-number>4.3.1</span>\n<a href=#toc:subsec:faq:no-root-no-harms>I don’t use root/ADB. Am I\ncompletely safe from any harms?</a><a href=#subsec:faq:no-root-no-harms class=anchor aria-hidden=true></a></h3><p>Yes. AM cannot modify any system settings without root or ADB.</section><section id=subsec:faq:how-trackers-libs-updated class=level3 data-number=4.3.2><h3 data-number=4.3.2><span class=header-section-number>4.3.2</span>\n<a href=#toc:subsec:faq:how-trackers-libs-updated>How are the trackers\nand libraries are updated?</a><a href=#subsec:faq:how-trackers-libs-updated class=anchor aria-hidden=true></a></h3><p>Trackers and libraries are updated manually before making a new\nrelease.</section><section id=subsec:faq:apks-deleted-after-installed class=level3 data-number=4.3.3><h3 data-number=4.3.3><span class=header-section-number>4.3.3</span>\n<a href=#toc:subsec:faq:apks-deleted-after-installed>Are APKs deleted\nafter installed?</a><a href=#subsec:faq:apks-deleted-after-installed class=anchor aria-hidden=true></a></h3><p>No, APKs aren’t deleted by App Manager after they are installed.</section><section id=subsec:faq:shizuku-support class=level3 data-number=4.3.4><h3 data-number=4.3.4><span class=header-section-number>4.3.4</span>\n<a href=#toc:subsec:faq:shizuku-support>Any plans for Shizuku?</a><a href=#subsec:faq:shizuku-support class=anchor aria-hidden=true></a></h3><p>App Manager’s use of hidden API and privileged code execution is now\nmuch more complex and cannot be integrated with other third party apps\nsuch as <a href=https://shizuku.rikka.app>Shizuku</a>. Here are some\nreasons for not considering Shizuku (which now has Apache 2.0 license)\nfor App Manager:<ol class=incremental><li><p>Shizuku was initially non-free which led me to use a similar\napproach for App Manager to support both root and ADB<li><p>App Manager already supports both ADB and root which in some\ncases is more capable than Shizuku<li><p>Relying on a third-party app for the major functionalities is not\na good design choice<li><p>Integration of Shizuku will increase the complexity of App\nManager.</ol></section><section id=subsec:faq:what-are-bloatware class=level3 data-number=4.3.5><h3 data-number=4.3.5><span class=header-section-number>4.3.5</span>\n<a href=#toc:subsec:faq:what-are-bloatware>What are bloatware and how\nto remove them?</a><a href=#subsec:faq:what-are-bloatware class=anchor aria-hidden=true></a></h3><p>Bloatware are the unnecessary pre-installed apps, usually system\napps. Some of the apps are often used to track users and collect user\ndata which they might sell for profits. Many system apps do not need to\nrequest any permission to access device info, contacts and messaging\ndata, and other usage info, such as your phone usage habits and\neverything you store on your shared storage(s).<p>The bloatware may also include Google apps, Meta apps, and Twitter/X\nwhich can also track users and/or collect user data without consent. You\ncan disable a few permissions from Android settings but be aware that\nAndroid settings hides many permissions a security researcher would call\npotentially <em>dangerous</em> (e.g., internet, sensor).<p>Were the bloatware user apps, they could be easily uninstalled either\nfrom Android settings or AM. Uninstalling system apps is not possible\nwithout privileged permission, but even then, it cannot <em>remove</em>\nthe system apps completely as they are located in the <em>system</em>\npartition which is a read-only partition. If you have root, you can\nremount this partition to manually <em>purge</em> these apps but this\nwill break Over the Air (OTA) updates since data in the system partition\nhas been modified. There are two kind of updates, delta (small-size,\nconsisting of only the changes between two versions) and full updates.\nYou may still be able to apply full updates, but the bloatware will be\ninstalled again, and consequently, you have to delete them all over\nagain.<p>Another solution is to disable these apps either from Android\nsettings or AM, but certain services can still run in the background as\nthey can be started by other system apps using Inter-process\nCommunication (IPC). One possible solution is to disable all bloatware\nuntil the service has finally stopped (after a restart). However, due to\nheavy modifications of the Android frameworks by the vendors, removing\nor disabling certain bloatware may cause the System UI to crash or even\ncause bootloop. From v4.0.0, AM has a new feature called\n<strong>Debloater</strong> which can be used as a starting point to\nmonitor, disable, and remove the bloatware from a proprietary Android\noperating system.<div class=\"amalert warning\"><p><strong><em>Note.</em></strong><p>In most cases, you cannot completely debloat your device. Therefore,\nit is recommended that you use a custom ROM free from bloatware, such as\nGraphene OS, Lineage OS or their derivatives.</div></section></section></section><section id=ch:specifications class=level1 data-number=5><h1 data-number=5><span class=header-section-number>5</span> <a href=#toc:ch:specifications>Specifications</a><a href=#ch:specifications class=anchor aria-hidden=true></a></h1><section id=sec:rules-specification class=level2 data-number=5.1><h2 data-number=5.1><span class=header-section-number>5.1</span> <a href=#toc:sec:rules-specification>Rules Specification</a><a href=#sec:rules-specification class=anchor aria-hidden=true></a></h2><section id=background class=level3 data-number=5.1.1><h3 data-number=5.1.1><span class=header-section-number>5.1.1</span>\n<a href=#toc:background>Background</a><a href=#background class=anchor aria-hidden=true></a></h3><p>AM currently supports blocking activities, broadcast receivers,\ncontent providers, services, app ops and permissions, and in future I\nmay add more blocking options. In order to add more portability, it is\nnecessary to import/export all these data.<p>Maintaining a database should be the best choice when it comes to\nstoring data. For now, several <code>tsv</code> files with each file\nhaving the name of the package and a <code>.tsv</code> extension. The\nfile/database will be queried/processed by the\n<code>RulesStorageManager</code> class. Due to this abstraction, it\nshould be easier to switch to database or encrypted database systems in\nfuture without changing the design of the entire project. Currently, All\nconfiguration files are stored at\n<code>/data/data/io.github.muntashirakon.AppManager/Files/conf</code>.</section><section id=rules-file-format class=level3 data-number=5.1.2><h3 data-number=5.1.2><span class=header-section-number>5.1.2</span>\n<a href=#toc:rules-file-format>Rules File Format</a><a href=#rules-file-format class=anchor aria-hidden=true></a></h3><section id=internal class=level4 data-number=5.1.2.1><h4 data-number=5.1.2.1><span class=header-section-number>5.1.2.1</span> Internal<a href=#internal class=anchor aria-hidden=true></a></h4><p>The format below is used internally within App Manager and is <em>not\ncompatible with the external format.</em><pre><code>    &lt;name&gt; &lt;type&gt; &lt;mode&gt;|&lt;component_status&gt;|&lt;is_granted&gt;</code></pre><p>Here:<ul class=incremental><li><p><code>&lt;name></code> – Component/permission/app op name (in\ncase of app op, it could be string or integer)<li><p><code>&lt;type></code> – One of the <code>ACTIVITY</code>,\n<code>RECEIVER</code>, <code>PROVIDER</code>, <code>SERVICE</code>,\n<code>APP_OP</code>, <code>PERMISSION</code><li><p><code>&lt;mode></code> – (For app ops) The associated <a href=#subsec:mode-constants>mode constant</a><li><p><code>&lt;component_status></code> – (For components)\nComponent status<ul class=incremental><li><p><code>true</code> – Component has been applied (<code>true</code>\nvalue is kept for compatibility)<li><p><code>false</code> – Component hasn’t been applied yet, but will\nbe applied in future (<code>false</code> value is kept for\ncompatibility)<li><p><code>unblocked</code> – Component is scheduled to be\nunblocked</ul><li><p><code>&lt;is_granted></code> – (For permissions) Whether the\npermission is granted or revoked</ul></section><section id=external class=level4 data-number=5.1.2.2><h4 data-number=5.1.2.2><span class=header-section-number>5.1.2.2</span> External<a href=#external class=anchor aria-hidden=true></a></h4><p>External format is used for importing or exporting rules in App\nManager.<pre><code>    &lt;package_name&gt; &lt;component_name&gt; &lt;type&gt; &lt;mode&gt;|&lt;component_status&gt;|&lt;is_granted&gt;</code></pre><p>This the format is essentially the same as above except for the first\nitem which is the name of the package.<div class=\"amalert danger\"><p><strong><em>Caution.</em></strong><p>The exported rules have a different format than the internal one and\nshould not be copied directly to the <strong>conf</strong> folder.</div></section></section></section></section><section id=ch:changelogs class=level1 data-number=6><h1 data-number=6><span class=header-section-number>6</span> <a href=#toc:ch:changelogs>Registros de cambios</a><a href=#ch:changelogs class=anchor aria-hidden=true></a></h1><section id=sec:v4.0.5-(445) class=level2 data-number=6.1><h2 data-number=6.1><span class=header-section-number>6.1</span> <a href=#toc:sec:v4.0.5-(445)>v4.0.5 (445)</a><a href=#sec:v4.0.5-(445) class=anchor aria-hidden=true></a></h2><ul class=incremental><li><p>Added option to allow installing the existing applications in the\ninstaller page<li><p>Display unsafe bloatware info<li><p>Display vector icon on the splash screen in Android 7.1 and\nearlier<li><p>Enabled “Clear data from uninstalled apps” to no-root users in\n1-click ops page<li><p>Enabled predictive back in Android 14 onwards<li><p>Improved accessibility by updating the content description of the\naction items<li><p>In app info tab, open “Open by default” setting in the “Open\nlinks” dialog<li><p>In debloater page, sort by app label (or app name) rather than\npackage name<li><p>Fixed freezing an app with “Remember for this app” turned\non<li><p>Fixed selecting texts in the list items due to framework\nbugs<li><p>Fixed setting app ops in custom ROMs with MIUI properties\ninjected<li><p>Fixed updating profile modification status when an application is\ndeleted from the list<li><p>Handled common colors and cursor movements in terminal\noutput.</ul></section><section id=sec:v4.0.4-(444) class=level2 data-number=6.2><h2 data-number=6.2><span class=header-section-number>6.2</span> <a href=#toc:sec:v4.0.4-(444)>v4.0.4 (444)</a><a href=#sec:v4.0.4-(444) class=anchor aria-hidden=true></a></h2><ul class=incremental><li><p>Optimized searching and filtering in the main page<li><p>Adopted sentence-case for the titles<li><p>Use the configured state to execute a profile for the simple\nshortcuts<li><p>Prevented crashing while searching throughout the\napplication<li><p>Fixed integer overflow issue in the tar compression.</ul></section><section id=sec:v4.0.3-(443) class=level2 data-number=6.3><h2 data-number=6.3><span class=header-section-number>6.3</span> <a href=#toc:sec:v4.0.3-(443)>v4.0.3 (443)</a><a href=#sec:v4.0.3-(443) class=anchor aria-hidden=true></a></h2><ul class=incremental><li><p>Updated translations<li><p>Improved handling the list items throughout App Manager<li><p>Fixed a regression error in file manager<li><p>Fixed spinners in the App Usage and the System Config\npages.</ul></section><section id=sec:v4.0.2-(442) class=level2 data-number=6.4><h2 data-number=6.4><span class=header-section-number>6.4</span> <a href=#toc:sec:v4.0.2-(442)>v4.0.2 (442)</a><a href=#sec:v4.0.2-(442) class=anchor aria-hidden=true></a></h2><ul class=incremental><li><p>Updated bloatware<li><p>Fixed fetching applications in multi-user environment in no-root\nmode<li><p>Fixed opening <code>app-manager</code> URLs from the web\nbrowsers<li><p>Fixed updating SSAID<li><p>Prevented a crash in Android &lt; 9.0 that occurs due to invalid\napp ops.</ul></section><section id=sec:v4.0.1-(441) class=level2 data-number=6.5><h2 data-number=6.5><span class=header-section-number>6.5</span> <a href=#toc:sec:v4.0.1-(441)>v4.0.1 (441)</a><a href=#sec:v4.0.1-(441) class=anchor aria-hidden=true></a></h2><section id=overlay-management class=level3 data-number=6.5.1><h3 data-number=6.5.1><span class=header-section-number>6.5.1</span>\n<a href=#toc:overlay-management>Overlay management</a><a href=#overlay-management class=anchor aria-hidden=true></a></h3><p>In the App Details page, a new tab “Overlays” is added where per-app\noverlays are displayed. They can also be enabled or disabled using the\ntoggle button. In addition, if the App Details page of an overlay\npackage is opened, a “Overlay” tag will be displayed in the App Info\ntab. Clicking on the tag opens a dialog containing additional info along\nwith a button that allows navigating to the App Details page of the\noverlay target package if it is installed.<section id=known-limitation class=level5 data-number=6.5.1.0.1><h5 data-number=6.5.1.0.1><span class=header-section-number>6.5.1.0.1</span> Known limitation<a href=#known-limitation class=anchor aria-hidden=true></a></h5><p>At present, it only works for root/ADB users in Android 8 (Oreo) and\nlater.</section></section><section id=unfreeze-option-in-activity-shortcuts class=level3 data-number=6.5.2><h3 data-number=6.5.2><span class=header-section-number>6.5.2</span>\n<a href=#toc:unfreeze-option-in-activity-shortcuts>Unfreeze option in\nactivity shortcuts</a><a href=#unfreeze-option-in-activity-shortcuts class=anchor aria-hidden=true></a></h3><p>If the application corresponding to the shortcut being launched is\nfrozen, App Manager will now offer you to unfreeze the app temporarily\nso that the shortcut can be launched. The app will be frozen again once\nthe screen is locked.<section id=known-limitation-1 class=level5 data-number=6.5.2.0.1><h5 data-number=6.5.2.0.1><span class=header-section-number>6.5.2.0.1</span> Known limitation<a href=#known-limitation-1 class=anchor aria-hidden=true></a></h5><p>This may not work on devices without a screen lock or if the screen\nis locked some time after the display goes off.</section></section><section id=market-like-url-support class=level3 data-number=6.5.3><h3 data-number=6.5.3><span class=header-section-number>6.5.3</span>\n<a href=#toc:market-like-url-support><code>market</code>-like URL\nsupport</a><a href=#market-like-url-support class=anchor aria-hidden=true></a></h3><p>Third-party applications can now open the App Details page of any\ninstalled package by invoking an Intent with an URL with the following\nformat:<pre><code>app-manager://details?id=&lt;pkg&gt;&amp;user=&lt;user_id&gt;</code></pre><p>where <code>&lt;pkg></code> stands for package name, and\n<code>&lt;user_id></code> stands for the user ID which is\noptional.</section><section id=updated-color-codes class=level3 data-number=6.5.4><h3 data-number=6.5.4><span class=header-section-number>6.5.4</span>\n<a href=#toc:updated-color-codes>Updated color codes</a><a href=#updated-color-codes class=anchor aria-hidden=true></a></h3><p>In order to improve accessibility, certain color codes have been\nimproved. Visit <a href=app-manager://settings/about/version>Settings\n> About > Version/Changelog</a> for details.</section><section id=others class=level3 data-number=6.5.5><h3 data-number=6.5.5><span class=header-section-number>6.5.5</span>\n<a href=#toc:others>Others</a><a href=#others class=anchor aria-hidden=true></a></h3><ul class=incremental><li><p>Avoided waiting for the remote server to respond when no-root\nmode is set<li><p>Fixed downgrading apps in Android 10 onwards<li><p>Fixed installer issues in the Huawei stock operating\nsystems<li><p>Improved text formatting in the “What’s New” dialog<li><p>In the UI tracker window, fixed clicking on the icon after it is\niconified<li><p>Updated bloatware and suggestions</ul></section></section><section id=sec:v4.0.0-(440) class=level2 data-number=6.6><h2 data-number=6.6><span class=header-section-number>6.6</span> <a href=#toc:sec:v4.0.0-(440)>v4.0.0 (440)</a><a href=#sec:v4.0.0-(440) class=anchor aria-hidden=true></a></h2><p>App Manager v4.0.0 comes with a lot of new features and improvements.\nVisit <a href=app-manager://settings/about/version>Settings > About\n> Version/Changelog</a> for details.<section id=new-logo class=level3 data-number=6.6.1><h3 data-number=6.6.1><span class=header-section-number>6.6.1</span>\n<a href=#toc:new-logo>New logo!</a><a href=#new-logo class=anchor aria-hidden=true></a></h3><p>The new logo is just a cursive “A”. The design is based on the <a href=https://freetengwar.sourceforge.net/>Tengwar Telcontar</a> font\nwhich was created to bring the Tengwar script, originally created by J.\nR. R. Tolkien, to the digital world. The letter has the classic App\nManager color (i.e., #dcaf74) and uses a pure black background instead\nof a shade of grey.</section><section id=android-14-and-15-support class=level3 data-number=6.6.2><h3 data-number=6.6.2><span class=header-section-number>6.6.2</span>\n<a href=#toc:android-14-and-15-support>Android 14 and 15 support</a><a href=#android-14-and-15-support class=anchor aria-hidden=true></a></h3><p>App Manager now targets Android 14 and fully supports Android 15.<section id=known-issue class=level5 data-number=6.6.2.0.1><h5 data-number=6.6.2.0.1><span class=header-section-number>6.6.2.0.1</span> Known issue<a href=#known-issue class=anchor aria-hidden=true></a></h5><p>KeyStore backup/restore is not working in Android 12 and later.</section></section><section id=revamped-debloater class=level3 data-number=6.6.3><h3 data-number=6.6.3><span class=header-section-number>6.6.3</span>\n<a href=#toc:revamped-debloater>Revamped debloater</a><a href=#revamped-debloater class=anchor aria-hidden=true></a></h3><p>Debloating profiles were available as “Presets” in the Profiles page\nwhich has now been replaced with the Debloater page and can be accessed\nfrom the three-dots menu in the Main page. <a href=https://github.com/MuntashirAkon/android-debloat-list>ADL</a> is\na new project that focuses on maintaining a list of bloatware as well as\npotential open source alternatives. Contributions are welcome!</section><section id=introducing-file-manager class=level3 data-number=6.6.4><h3 data-number=6.6.4><span class=header-section-number>6.6.4</span>\n<a href=#toc:introducing-file-manager>Introducing file manager</a><a href=#introducing-file-manager class=anchor aria-hidden=true></a></h3><p>App Manager offers an (almost) fully-featured file manager with basic\nfile operations, such as copy, cut, rename, and delete along with the\nbatch operations. It also offers an extensive “Open with…” dialog to\nopen a file with another app, and a comprehensive file properties\nviewer. Folders can also be added to the list of favorites for quick\naccess. And many more.</section><section id=integrated-code-editor class=level3 data-number=6.6.5><h3 data-number=6.6.5><span class=header-section-number>6.6.5</span>\n<a href=#toc:integrated-code-editor>Integrated code editor</a><a href=#integrated-code-editor class=anchor aria-hidden=true></a></h3><p>Manifest and code viewers have been replaced with this new editor.\nAmong other regular features, it includes proper syntax highlighting and\nadvanced searching options. In addition, files from third-party apps can\nalso be opened for editing.</section><section id=history-of-operations class=level3 data-number=6.6.6><h3 data-number=6.6.6><span class=header-section-number>6.6.6</span>\n<a href=#toc:history-of-operations>History of operations</a><a href=#history-of-operations class=anchor aria-hidden=true></a></h3><p>All 1-click operations, batch operations, and profile invocations are\nnow stored as history. The history items can also be executed from the\nHistory page. To ensure consistency, the profile state, configurations,\npackage list are also stored, and this stored version is executed\ninstead of the actual profile. As a result, this works even if the\nprofile is deleted.</section><section id=per-app-freezing-and-more class=level3 data-number=6.6.7><h3 data-number=6.6.7><span class=header-section-number>6.6.7</span>\n<a href=#toc:per-app-freezing-and-more>Per-app freezing, and\nmore</a><a href=#per-app-freezing-and-more class=anchor aria-hidden=true></a></h3><p>Freeze/unfreeze feature now supports setting per-app freezing method\nwhich is beneficial in certain scenarios, such as when a user want to\nsuspend some apps while using the disable method as the default. In\naddition, an “Advanced suspend” option is added which force-stops an\napplication before suspending it, thus, prevent it’s services from\nrunning in the background.</section><section id=log-viewer-enhancements class=level3 data-number=6.6.8><h3 data-number=6.6.8><span class=header-section-number>6.6.8</span>\n<a href=#toc:log-viewer-enhancements>Log viewer enhancements</a><a href=#log-viewer-enhancements class=anchor aria-hidden=true></a></h3><p>Log viewer now supports enhanced searching and filtering options,\nsuch as keyword- and regular expression-based searching and filtering.\nPlease read the in-app changelog for details. Support for batch\noperations has also been added.</section><section id=launching-non-exported-activities class=level3 data-number=6.6.9><h3 data-number=6.6.9><span class=header-section-number>6.6.9</span>\n<a href=#toc:launching-non-exported-activities>Launching non-exported\nactivities</a><a href=#launching-non-exported-activities class=anchor aria-hidden=true></a></h3><p>App Manager now supports launching non-exported activities in no-root\nand ADB mode. However, in no-root mode,\n<code>android.permission.WRITE_SECURE_SETTINGS</code> permission is\nrequired.</section><section id=new-tags-in-app-info-tab class=level3 data-number=6.6.10><h3 data-number=6.6.10><span class=header-section-number>6.6.10</span> <a href=#toc:new-tags-in-app-info-tab>New tags in App Info tab</a><a href=#new-tags-in-app-info-tab class=anchor aria-hidden=true></a></h3><p>Five new tags are added in the App Info tab. They are: bloatware,\nXposed, sensors disabled, open links, and static shared libs. Clicking\non “bloatware” will display more information regarding the bloatware and\nsuggest alternatives, “Xposed” tag will display dependency information,\n“open links” will display a list of links supported by the application,\nand “static shared libs” will display all version of the application\ninstalled in the system along with an option to uninstall them. The\nlatter is useful for applications, such as Trichrome.<section id=known-issue-1 class=level5 data-number=6.6.10.0.1><h5 data-number=6.6.10.0.1><span class=header-section-number>6.6.10.0.1</span> Known issue<a href=#known-issue-1 class=anchor aria-hidden=true></a></h5><p>“Sensors disabled” only works real-time. That means if the\napplication is not currently active, this tag will always display even\nthough the applications may use sensors while it is running. This is a\nframework limitation and nothing can be done to avoid it\neffectively.</section></section><section id=per-session-installer-options class=level3 data-number=6.6.11><h3 data-number=6.6.11><span class=header-section-number>6.6.11</span> <a href=#toc:per-session-installer-options>Per-session installer\noptions</a><a href=#per-session-installer-options class=anchor aria-hidden=true></a></h3><p>It is not possible to modify installer options during the\ninstallation by clicking on the “settings” button in the installation\ndialog. The installer options will be applied to all the applications\ninstalled in the same session (i.e., the installer queue).</section><section id=advanced-mode-of-operations-adb-enhancements class=level3 data-number=6.6.12><h3 data-number=6.6.12><span class=header-section-number>6.6.12</span> <a href=#toc:advanced-mode-of-operations-adb-enhancements>Advanced mode\nof operations, ADB enhancements, …</a><a href=#advanced-mode-of-operations-adb-enhancements class=anchor aria-hidden=true></a></h3><p>App Manager now supports running its remote server (which is used as\na proxy for running privileged operations) as any supported user (UID).\nThis includes root (0), system (1000), and shell/ADB (2000) through the\ncustom commands. This is also useful for Fire TVs which have disabled\nconnecting to ADB from localhost through socket connection. In addition,\nADB pairing is now done using notifications rather than split screen.\nADB connection speed can also be improved by choosing to run App Manager\nin the background which can be configured in the settings.</section><section id=data-usage-widget-and-more class=level3 data-number=6.6.13><h3 data-number=6.6.13><span class=header-section-number>6.6.13</span> <a href=#toc:data-usage-widget-and-more>Data usage widget, and more</a><a href=#data-usage-widget-and-more class=anchor aria-hidden=true></a></h3><p>Data usage widget display the total data usage for the day, similar\nto the screen time widget which displays the total screen time for the\nday. In addition, existing widgets have been improved.</section><section id=others-1 class=level3 data-number=6.6.14><h3 data-number=6.6.14><span class=header-section-number>6.6.14</span> <a href=#toc:others-1>Others</a><a href=#others-1 class=anchor aria-hidden=true></a></h3><ul class=incremental><li><p>Replaced log viewer, sys config, Terminal, etc. with Labs\npage<li><p>Added an option to disable sensors for each app in the App Info\ntab<li><p>Added an option to perform runtime optimization of applications\nin the 1-click Ops page and in the App Info tab<li><p>Added support for Zstandard compression for\nbackup/restore<li><p>Enabling APK signing now automatically enables zip align\nfeature<li><p>Support exporting application list as CSV or JSON in the batch\noperations<li><p>Added pure black theme support<li><p>Display current activity name (when possible) in the UI Tracker\nwindow<li><p>Added an option to filter apps by user in the Main page<li><p>Display a link to Pithus report in the scanner page if\navailable.</ul></section></section><section id=sec:v3.1.0-(423) class=level2 data-number=6.7><h2 data-number=6.7><span class=header-section-number>6.7</span> <a href=#toc:sec:v3.1.0-(423)>v3.1.0 (423)</a><a href=#sec:v3.1.0-(423) class=anchor aria-hidden=true></a></h2><p>App Manager v3.1.0 comes with a few new features and a lot of\nimprovements. Visit <a href=app-manager://settings/about/version>Settings > About >\nVersion/Changelog</a> for details.<section id=android-13-support class=level3 data-number=6.7.1><h3 data-number=6.7.1><span class=header-section-number>6.7.1</span>\n<a href=#toc:android-13-support>Android 13 support</a><a href=#android-13-support class=anchor aria-hidden=true></a></h3><p>App Manager now targets Android 13 which means most issues in Android\n12 and 13 has been addressed, including SSAID and SAF issues as well as\nmonochrome icons and other theming issues.<section id=known-issue-2 class=level5 data-number=6.7.1.0.1><h5 data-number=6.7.1.0.1><span class=header-section-number>6.7.1.0.1</span> Known issue<a href=#known-issue-2 class=anchor aria-hidden=true></a></h5><p>KeyStore backup/restore not working in Android 12 and later.</section></section><section id=introducing-freezeunfreeze class=level3 data-number=6.7.2><h3 data-number=6.7.2><span class=header-section-number>6.7.2</span>\n<a href=#toc:introducing-freezeunfreeze>Introducing\nfreeze/unfreeze</a><a href=#introducing-freezeunfreeze class=anchor aria-hidden=true></a></h3><p>Enable/disable is replaced with freeze/unfreeze to allow greater\ncontrol on the behaviours of an app. It supports suspend, disable and\nhide functionalities which can be controlled at <a href=app-manager://settings/rules_prefs/freeze_type>Settings >\nRules > Default freezing method</a>. In order to make it easy to\nfreeze or unfreeze an app, shortcuts can also be created from the App\nInfo tab by long clicking on the freeze or unfreeze button.</section><section id=export-app-list class=level3 data-number=6.7.3><h3 data-number=6.7.3><span class=header-section-number>6.7.3</span>\n<a href=#toc:export-app-list>Export app list</a><a href=#export-app-list class=anchor aria-hidden=true></a></h3><p>In the Main page, it is now possible to export the list of apps in\neither XML or Markdown format using batch operations. In the future, the\nXML file may also be imported to App Manager.</section><section id=elliptic-curve-crypography-ecc class=level3 data-number=6.7.4><h3 data-number=6.7.4><span class=header-section-number>6.7.4</span>\n<a href=#toc:elliptic-curve-crypography-ecc>Elliptic Curve Crypography\n(ECC)</a><a href=#elliptic-curve-crypography-ecc class=anchor aria-hidden=true></a></h3><p>App Manager now fully supports encrypting backups using ECC in\naddition to offering AES, RSA and OpenPGP.</section><section id=new-languages class=level3 data-number=6.7.5><h3 data-number=6.7.5><span class=header-section-number>6.7.5</span>\n<a href=#toc:new-languages>New languages</a><a href=#new-languages class=anchor aria-hidden=true></a></h3><p>Two new languages are added: Korean and Romanian.</section><section id=more-list-options class=level3 data-number=6.7.6><h3 data-number=6.7.6><span class=header-section-number>6.7.6</span>\n<a href=#toc:more-list-options>More list options</a><a href=#more-list-options class=anchor aria-hidden=true></a></h3><p>In the main page, more sorting and filtering options are added.\nSorting options include sorting the apps by total size, total data\nusage, launch count, screen time and last usage time. Filtering options\ninclude filtering the apps having at least one item in the Android\nKeyStore, filtering apps with URIs granted via SAF, and filtering apps\nwith SSAID.</section><section id=improved-handling-of-mode-of-operation class=level3 data-number=6.7.7><h3 data-number=6.7.7><span class=header-section-number>6.7.7</span>\n<a href=#toc:improved-handling-of-mode-of-operation>Improved handling\nof mode of operation</a><a href=#improved-handling-of-mode-of-operation class=anchor aria-hidden=true></a></h3><p>Fixed various issues with ADB pairing, handled incomplete USB\ndebugging. Some rooting methods cannot allow interprocess communication\nvia Binder. In those cases, ADB mode is used as a fallback method by\nenabling it automatically if possible.</section><section id=handling-multiple-users class=level3 data-number=6.7.8><h3 data-number=6.7.8><span class=header-section-number>6.7.8</span>\n<a href=#toc:handling-multiple-users>Handling multiple users</a><a href=#handling-multiple-users class=anchor aria-hidden=true></a></h3><p>When possible, App Manager will be able to display apps from work\nprofile in no-root mode in addition to allowing basic operations such as\nlaunching the app or navigating to the system settings. For backups, it\nis now possible to restore backups for other users, but for work\nprofile, some apps may only work properly after re-enabling the work\nprofile. In the installer page, selecting <em>All users</em> will now\ninstall the app for all users instead of only the current user. Finally,\nin the app info tab, current app can be installed in another profile\nusing the <em>Install for…</em> option available in the three-dots menu.\nThis is analogous to the <code>pm install-existing</code> command,\nthereby, making the installation process a lot faster.</section><section id=explorer-enhancements class=level3 data-number=6.7.9><h3 data-number=6.7.9><span class=header-section-number>6.7.9</span>\n<a href=#toc:explorer-enhancements>Explorer enhancements</a><a href=#explorer-enhancements class=anchor aria-hidden=true></a></h3><p>Explorer can now open DEX and JAR files in addition to APK files.\nSeveral sorting options as well as folder options are also added as the\nlist options.</section><section id=new-tag-wx class=level3 data-number=6.7.10><h3 data-number=6.7.10><span class=header-section-number>6.7.10</span> <a href=#toc:new-tag-wx>New tag: WX</a><a href=#new-tag-wx class=anchor aria-hidden=true></a></h3><p>In app info tab, a new tag called WX is added. It is displayed in\nAndroid 10 and later if the application targets Android 9 or earlier. It\nindicates <a href=https://en.wikipedia.org/wiki/W%5EX>W^X</a>\nviolation which allows the app to execute arbitrary executable files\neither by the modification of executables embedded within the app or by\ndownloading them from the Internet.</section><section id=app-ops-management class=level3 data-number=6.7.11><h3 data-number=6.7.11><span class=header-section-number>6.7.11</span> <a href=#toc:app-ops-management>App ops management</a><a href=#app-ops-management class=anchor aria-hidden=true></a></h3><p>App ops are now managed automatically to avoid various app ops\nrelated crashes in various platforms. This will also lessen the amount\nof crashes in an unsupported operating system.</section><section id=batch-uninstallation class=level3 data-number=6.7.12><h3 data-number=6.7.12><span class=header-section-number>6.7.12</span> <a href=#toc:batch-uninstallation>Batch uninstallation</a><a href=#batch-uninstallation class=anchor aria-hidden=true></a></h3><p>In the Main page, enabled batch uninstallation in no-root mode.</section><section id=running-apps class=level3 data-number=6.7.13><h3 data-number=6.7.13><span class=header-section-number>6.7.13</span> <a href=#toc:running-apps>Running apps</a><a href=#running-apps class=anchor aria-hidden=true></a></h3><p>Enabled advanced searching. Searching now matches not only app labels\nbut also package names.</section><section id=interceptor class=level3 data-number=6.7.14><h3 data-number=6.7.14><span class=header-section-number>6.7.14</span> <a href=#toc:interceptor>Interceptor</a><a href=#interceptor class=anchor aria-hidden=true></a></h3><p>Copy the intercepted Intent as am command which can be run from\neither an ADB shell or a terminal using root with the same\neffectiveness.</section><section id=device-specific-changes class=level3 data-number=6.7.15><h3 data-number=6.7.15><span class=header-section-number>6.7.15</span> <a href=#toc:device-specific-changes>Device-specific changes</a><a href=#device-specific-changes class=anchor aria-hidden=true></a></h3><section id=graphene-os class=level5 data-number=6.7.15.0.1><h5 data-number=6.7.15.0.1><span class=header-section-number>6.7.15.0.1</span> Graphene OS<a href=#graphene-os class=anchor aria-hidden=true></a></h5><p>Explicitly handle the Internet permission which is a runtime\npermission in the OS.</section><section id=miui class=level5 data-number=6.7.15.0.2><h5 data-number=6.7.15.0.2><span class=header-section-number>6.7.15.0.2</span> MIUI<a href=#miui class=anchor aria-hidden=true></a></h5><p>Fixed permission denied issues in the installer due to a framework\nissue introduced in MIUI 12.5.</section><section id=motorola class=level5 data-number=6.7.15.0.3><h5 data-number=6.7.15.0.3><span class=header-section-number>6.7.15.0.3</span> Motorola<a href=#motorola class=anchor aria-hidden=true></a></h5><p>Fixed crashes in the Interceptor page due to a framework issue\nintroduced in Android 11.</section></section><section id=others-2 class=level3 data-number=6.7.16><h3 data-number=6.7.16><span class=header-section-number>6.7.16</span> <a href=#toc:others-2>Others</a><a href=#others-2 class=anchor aria-hidden=true></a></h3><ul class=incremental><li><p>Improved Java-Smali conversion by including all the subclasses\nduring conversion<li><p>Improved scanning performance in the Scanner page<li><p>Improved updating the list of apps in the Main page<li><p>Scan all the available paths to detect systemless-ly installed\nsystem apps<li><p><code>vacuum</code> SQLite database before opening it for viewing\nor editing.</ul></section></section><section id=sec:v3.0.0-(410) class=level2 data-number=6.8><h2 data-number=6.8><span class=header-section-number>6.8</span> <a href=#toc:sec:v3.0.0-(410)>v3.0.0 (410)</a><a href=#sec:v3.0.0-(410) class=anchor aria-hidden=true></a></h2><p>App Manager v3.0.0 comes with a lot of features and improvements. See\n<a href=app-manager://settings/about/version>Settings > About >\nVersion/Changelog</a> to see a more detailed changelog.<section id=material-3-and-more class=level3 data-number=6.8.1><h3 data-number=6.8.1><span class=header-section-number>6.8.1</span>\n<a href=#toc:material-3-and-more>Material 3 and More</a><a href=#material-3-and-more class=anchor aria-hidden=true></a></h3><p>Material 3, somewhat similar to <em>Material You</em>, is a\nsignificant improvement over Material Design 2 with support for dynamic\ncolours in Android 12 and later. In addition, many design changes have\nbeen made in App Manager without any significant changes in the overall\nuser experience.<section id=known-issue-3 class=level5 data-number=6.8.1.0.1><h5 data-number=6.8.1.0.1><span class=header-section-number>6.8.1.0.1</span> Known issue<a href=#known-issue-3 class=anchor aria-hidden=true></a></h5><p>Switches are still based on Material Design 2 which will be fixed in\na future release.</section></section><section id=wireless-debugging class=level3 data-number=6.8.2><h3 data-number=6.8.2><span class=header-section-number>6.8.2</span>\n<a href=#toc:wireless-debugging>Wireless Debugging</a><a href=#wireless-debugging class=anchor aria-hidden=true></a></h3><p>Wireless debugging support has been fully implemented. Head over to\n§<a href=#sec:wireless-debugging data-reference-type=ref data-reference=sec:wireless-debugging>3.2</a> for instructions on how\nto configure wireless debugging.<div class=\"amalert tip\"><p><strong><em>No-root users.</em></strong><p>Due to auto-detection feature, startup time might be large for\nno-root users when the mode of operation is set to <em>auto</em>.\nInstead, no-root users should select <em>no-root</em> instead of\n<em>auto</em>.</div></section><section id=languages class=level3 data-number=6.8.3><h3 data-number=6.8.3><span class=header-section-number>6.8.3</span>\n<a href=#toc:languages>Languages</a><a href=#languages class=anchor aria-hidden=true></a></h3><p>App Manager is fully translated into Indonesian and Italian languages\nand can be enabled in settings. Bengali is removed due to lack of\ntranslators.</section><section id=introducing-app-explorer class=level3 data-number=6.8.4><h3 data-number=6.8.4><span class=header-section-number>6.8.4</span>\n<a href=#toc:introducing-app-explorer>Introducing App Explorer</a><a href=#introducing-app-explorer class=anchor aria-hidden=true></a></h3><p>App Explorer can be used to browse the contents of an application.\nThis includes binary XML files, DEX contents or any other media files.\nDEX contents can only be explored in Android Oreo (Android 8) and later.\nIt’s also possible to convert an <code>.smali</code> file into\n<code>.java</code> for a better understanding of the reversed code. This\nfeature, if not needed, can be disabled in Settings > Enable/disable\nfeatures.</section><section id=import-backups-from-other-applications class=level3 data-number=6.8.5><h3 data-number=6.8.5><span class=header-section-number>6.8.5</span>\n<a href=#toc:import-backups-from-other-applications>Import Backups\nfrom Other Applications</a><a href=#import-backups-from-other-applications class=anchor aria-hidden=true></a></h3><p>It is possible to import backups from discontinued or obsolete\napplications such as Titanium Backup, OAndBackup and Swift Backup\n(version 3.0 to 3.2). Go to Setting > Backup/restore to find this\noption.</section><section id=virustotal class=level3 data-number=6.8.6><h3 data-number=6.8.6><span class=header-section-number>6.8.6</span>\n<a href=#toc:virustotal>VirusTotal</a><a href=#virustotal class=anchor aria-hidden=true></a></h3><p>VirusTotal is a widely used tool to scan files and URLs for viruses.\nIn the scanner page and in the running apps page, an option to scan\nfiles with VirusTotal has been added. But the option is hidden by\ndefault. To enable the option, it is necessary to obtain an API key from\nVirusTotal. Go to Settings > VirusTotal API Key for more\ninformation.<div class=\"amalert warning\"><p><strong><em>Internet feature.</em></strong><p>This is currently the only feature which require an Internet\nconnection. If you wish to use any Internet feature that might also be\nadded in the future, enable <em>Use the Internet</em> in Settings >\nEnable/disable features.</div></section><section id=trigger-profiles-from-the-automation-software class=level3 data-number=6.8.7><h3 data-number=6.8.7><span class=header-section-number>6.8.7</span>\n<a href=#toc:trigger-profiles-from-the-automation-software>Trigger\nProfiles from the Automation Software</a><a href=#trigger-profiles-from-the-automation-software class=anchor aria-hidden=true></a></h3><p>As the implementation of routine operations is being delayed, an\noption to trigger profiles from the external automation software is\nadded. See §<a href=#sec:automating-tasks data-reference-type=ref data-reference=sec:automating-tasks>3.4</a> for instructions on how to\nconfigure profile automation.</section><section id=improved-application-installer class=level3 data-number=6.8.8><h3 data-number=6.8.8><span class=header-section-number>6.8.8</span>\n<a href=#toc:improved-application-installer>Improved Application\nInstaller</a><a href=#improved-application-installer class=anchor aria-hidden=true></a></h3><p>Application installer includes several improvements including the\nability to downgrade applications in no-root mode, installing multiple\napplications at once and blocking trackers after installation. In\nAndroid 12 and later, no-root users can update applications without any\nuser interactions.</section><section id=component-blocking class=level3 data-number=6.8.9><h3 data-number=6.8.9><span class=header-section-number>6.8.9</span>\n<a href=#toc:component-blocking>Component Blocking</a><a href=#component-blocking class=anchor aria-hidden=true></a></h3><p>It is now possible to configure how App Manager should block a\ncomponent. Visit Settings > Rules > Default blocking method for\nmore information. In the components tab, long clicking the block/unblock\nbutton opens a context menu which allows per-component blocking in a\nsimilar manner. ADB users can also block the components of a <em>Test\nonly</em> app.</section><section id=advanced-searching class=level3 data-number=6.8.10><h3 data-number=6.8.10><span class=header-section-number>6.8.10</span> <a href=#toc:advanced-searching>Advanced Searching</a><a href=#advanced-searching class=anchor aria-hidden=true></a></h3><p>In some pages, the search bar supports additional searching which\nincludes searching via prefix, suffix or even regular expressions. In\nthe main page, it is also possible to search for applications using the\nfirst letters of each word, e.g. <em>App Manager</em> can be listed by\nsearching for <em>am</em>.</section><section id=shared-libraries class=level3 data-number=6.8.11><h3 data-number=6.8.11><span class=header-section-number>6.8.11</span> <a href=#toc:shared-libraries>Shared Libraries</a><a href=#shared-libraries class=anchor aria-hidden=true></a></h3><p>Shared libraries tab has received a significant improvements. It can\ndisplay three types of libraries, such as native, jar and APK files.</section><section id=make-the-best-use-of-interceptor class=level3 data-number=6.8.12><h3 data-number=6.8.12><span class=header-section-number>6.8.12</span> <a href=#toc:make-the-best-use-of-interceptor>Make the Best Use of\nInterceptor</a><a href=#make-the-best-use-of-interceptor class=anchor aria-hidden=true></a></h3><p>Activity interceptor can be opened directly from the activities tab\nby long clicking on the launch button, and similarly, activities can be\nlaunched from the activity interceptor page with or without root, for\nany users.<div class=\"amalert tip\"><p><strong><em>Notice.</em></strong><p>Currently, activities opened via root cannot send the results back to\nthe original applications.</div></section><section id=widget-screen-time class=level3 data-number=6.8.13><h3 data-number=6.8.13><span class=header-section-number>6.8.13</span> <a href=#toc:widget-screen-time>Widget: Screen Time</a><a href=#widget-screen-time class=anchor aria-hidden=true></a></h3><p>Screen time widget is quite similar to Digital Wellbeing’s widget by\nthe same name. It displays the total screen time for the day along with\nthe top three apps from all users.</section><section id=widget-clear-cache class=level3 data-number=6.8.14><h3 data-number=6.8.14><span class=header-section-number>6.8.14</span> <a href=#toc:widget-clear-cache>Widget: Clear Cache</a><a href=#widget-clear-cache class=anchor aria-hidden=true></a></h3><p>Clear cache widget can be to clear cache from all the applications\ndirectly from the home screen.</section></section><section id=sec:v2.6.0-(385) class=level2 data-number=6.9><h2 data-number=6.9><span class=header-section-number>6.9</span> <a href=#toc:sec:v2.6.0-(385)>v2.6.0 (385)</a><a href=#sec:v2.6.0-(385) class=anchor aria-hidden=true></a></h2><section id=introducing-backups class=level3 data-number=6.9.1><h3 data-number=6.9.1><span class=header-section-number>6.9.1</span>\n<a href=#toc:introducing-backups>Introducing Backups</a><a href=#introducing-backups class=anchor aria-hidden=true></a></h3><p>Back up/restore feature is now finally out of beta! Read <a href=#sec:backup-restore>the corresponding guide</a> to understand how\nit works.</section><section id=introducing-log-viewer class=level3 data-number=6.9.2><h3 data-number=6.9.2><span class=header-section-number>6.9.2</span>\n<a href=#toc:introducing-log-viewer>Introducing Log Viewer</a><a href=#introducing-log-viewer class=anchor aria-hidden=true></a></h3><p><a href=#subsubsec:log-viewer>Log viewer</a> is essentially a\nfront-end for <code>logcat</code>. It can be used to filter logs by\n<em>tag</em> or <em>pid</em> (process ID), or even by custom filters.\nLog levels AKA verbosity can also be configured. You can also save,\nshare and manage logs.</section><section id=lock-app-manager class=level3 data-number=6.9.3><h3 data-number=6.9.3><span class=header-section-number>6.9.3</span>\n<a href=#toc:lock-app-manager>Lock App Manager</a><a href=#lock-app-manager class=anchor aria-hidden=true></a></h3><p><a href=#subsubsec:screen-lock>Lock App Manager</a> with the screen\nlock configured for your device.</section><section id=extended-modes-for-app-ops class=level3 data-number=6.9.4><h3 data-number=6.9.4><span class=header-section-number>6.9.4</span>\n<a href=#toc:extended-modes-for-app-ops>Extended Modes for App\nOps</a><a href=#extended-modes-for-app-ops class=anchor aria-hidden=true></a></h3><p>You can set any mode for any app ops that your device supports,\neither from the <a href=#subsec:set-mode-for-app-ops-dots>1-click ops\npage</a> or from the <a href=#subsubsec:app-ops>app ops tab</a>.</section><section id=new-batch-ops-add-to-profile class=level3 data-number=6.9.5><h3 data-number=6.9.5><span class=header-section-number>6.9.5</span>\n<a href=#toc:new-batch-ops-add-to-profile>New Batch Ops: Add to\nProfile</a><a href=#new-batch-ops-add-to-profile class=anchor aria-hidden=true></a></h3><p>You can now easily add selected apps to an existing profile using the\nbatch operations.</section><section id=app-info-improved class=level3 data-number=6.9.6><h3 data-number=6.9.6><span class=header-section-number>6.9.6</span>\n<a href=#toc:app-info-improved>App Info: Improved</a><a href=#app-info-improved class=anchor aria-hidden=true></a></h3><p>App info tab now has many options, including the ability to change <a href=#sec:terminologies>SSAID</a>, network policy (i.e. background\nnetwork usage), battery optimization, etc. Most of the tags used in this\ntab are also clickable, and if you click on them, you will be able to\nlook at the current state or configure them right away.</section><section id=advanced-sort-and-filtering-options-in-the-main-page class=level3 data-number=6.9.7><h3 data-number=6.9.7><span class=header-section-number>6.9.7</span>\n<a href=#toc:advanced-sort-and-filtering-options-in-the-main-page>Advanced\nSort and Filtering Options in the Main Page</a><a href=#advanced-sort-and-filtering-options-in-the-main-page class=anchor aria-hidden=true></a></h3><p>Sort and filter options are now replaced by <a href=#subsubsec:main-list-options>List Options</a> which is highly\nconfigurable, including the ability to filter using profiles.</section><section id=about-this-device class=level3 data-number=6.9.8><h3 data-number=6.9.8><span class=header-section-number>6.9.8</span>\n<a href=#toc:about-this-device>About This Device</a><a href=#about-this-device class=anchor aria-hidden=true></a></h3><p>Interested in knowing about your device in just one page? Go to the\nbottom of the <a href=#subsec:device-info>settings page</a>.</section><section id=enabledisable-features class=level3 data-number=6.9.9><h3 data-number=6.9.9><span class=header-section-number>6.9.9</span>\n<a href=#toc:enabledisable-features>Enable/disable Features</a><a href=#enabledisable-features class=anchor aria-hidden=true></a></h3><p>Not interested in all the features that AM offers? You can disable\nsome features in <a href=#subsubsec:enable/disable-features>settings</a>.</section><section id=new-languages-1 class=level3 data-number=6.9.10><h3 data-number=6.9.10><span class=header-section-number>6.9.10</span> <a href=#toc:new-languages-1>New Languages</a><a href=#new-languages-1 class=anchor aria-hidden=true></a></h3><p>AM now has more than 19 languages! New languages include Farsi,\nJapanese and Traditional Chinese.</section><section id=signing-the-apk-files class=level3 data-number=6.9.11><h3 data-number=6.9.11><span class=header-section-number>6.9.11</span> <a href=#toc:signing-the-apk-files>Signing the APK Files</a><a href=#signing-the-apk-files class=anchor aria-hidden=true></a></h3><p>You can now import external signing keys in AM! For security, App\nManager has its own encrypted KeyStore which can also be <a href=#subsubsec:import/export-keystore>imported or exported</a>.</section><section id=new-extension-unapkm class=level3 data-number=6.9.12><h3 data-number=6.9.12><span class=header-section-number>6.9.12</span> <a href=#toc:new-extension-unapkm>New Extension: UnAPKM</a><a href=#new-extension-unapkm class=anchor aria-hidden=true></a></h3><p>Since APKMirror has removed encryption from their APKM files, it’s no\nlonger necessary to decrypt them. As a result, the option to decrypt\nAPKM files has been removed. Instead, this option is now provided by the\nUnAPKM extension which you can grab from <a href=https://f-droid.org/packages/io.github.muntashirakon.unapkm/>F-Droid</a>.\nSo, if you have an encrypted APKM file and have this extension\ninstalled, you can open the file directly in AM.</section></section><section id=sec:v2.5.20-(375) class=level2 data-number=6.10><h2 data-number=6.10><span class=header-section-number>6.10</span>\n<a href=#toc:sec:v2.5.20-(375)>v2.5.20 (375)</a><a href=#sec:v2.5.20-(375) class=anchor aria-hidden=true></a></h2><section id=subsec:introducing-profiles class=level3 data-number=6.10.1><h3 data-number=6.10.1><span class=header-section-number>6.10.1</span> <a href=#toc:subsec:introducing-profiles>Introducing Profiles</a><a href=#subsec:introducing-profiles class=anchor aria-hidden=true></a></h3><p><a href=#sec:profile-page>Profiles</a> finally closes the <a href=https://github.com/MuntashirAkon/AppManager/issues/72>related\nissue</a>. Profiles can be used to execute certain tasks repeatedly\nwithout doing everything manually. A profile can be applied (or invoked)\neither from the <a href=#sec:profiles-page>Profiles page</a> or from\nthe home screen by creating shortcuts. There are also some presets which\nconsist of debloating profiles taken from <a href=https://gitlab.com/W1nst0n/universal-android-debloater>Universal\nAndroid Debloater</a>.<section id=known-limitations class=level5 data-number=6.10.1.0.1><h5 data-number=6.10.1.0.1><span class=header-section-number>6.10.1.0.1</span> Known limitations<a href=#known-limitations class=anchor aria-hidden=true></a></h5><ul class=incremental><li><p>Exporting rules and applying permissions are not currently\nworking.<li><p>Profiles are applied for all users.</ul></section></section><section id=subsec:the-interceptor class=level3 data-number=6.10.2><h3 data-number=6.10.2><span class=header-section-number>6.10.2</span> <a href=#toc:subsec:the-interceptor>The Interceptor</a><a href=#subsec:the-interceptor class=anchor aria-hidden=true></a></h3><p><a href=https://github.com/MuntashirAkon/intent-intercept>Intent\nIntercept</a> works as a man-in-the-middle between source and\ndestination, that is, when you open a file or URL with another app, you\ncan see what is being shared by opening it with Interceptor first. You\ncan also add or modify the intents before sending them to the\ndestination. Additionally, you can double-click on any exportable\nactivities in the Activities tab in the App Details page to open them in\nthe Interceptor to add more configurations.<section id=known-limitation-2 class=level5 data-number=6.10.2.0.1><h5 data-number=6.10.2.0.1><span class=header-section-number>6.10.2.0.1</span> Known limitation<a href=#known-limitation-2 class=anchor aria-hidden=true></a></h5><p>Editing extras is not currently possible.</section></section><section id=subsec:unapkm:-dedrm-the-apkm-files class=level3 data-number=6.10.3><h3 data-number=6.10.3><span class=header-section-number>6.10.3</span> <a href=#toc:subsec:unapkm:-dedrm-the-apkm-files>UnAPKM: DeDRM the APKM\nfiles</a><a href=#subsec:unapkm:-dedrm-the-apkm-files class=anchor aria-hidden=true></a></h3><p>When I released a small tool called <a href=https://f-droid.org/en/packages/io.github.muntashirakon.unapkm>UnAPKM</a>,\nI promised that similar feature will be available in App Manager. I am\nproud to announce that you can open APKM files directly in the App Info\npage or convert them to APKS or install them directly.</section><section id=subsec:multiple-user class=level3 data-number=6.10.4><h3 data-number=6.10.4><span class=header-section-number>6.10.4</span> <a href=#toc:subsec:multiple-user>Multiple user</a><a href=#subsec:multiple-user class=anchor aria-hidden=true></a></h3><p>App manager now supports multiple users! For now, this requires root\nor ADB. But no-root support is also being considered. If you have\nmultiple users enabled and click on an app installed in multiple\nprofiles, an alert prompt will be displayed where you can select the\nuser.</section><section id=vive-la-france class=level3 data-number=6.10.5><h3 data-number=6.10.5><span class=header-section-number>6.10.5</span> <a href=#toc:vive-la-france>Vive la France!</a><a href=#vive-la-france class=anchor aria-hidden=true></a></h3><p>Thanks to the contributors, we have one more addition to the language\nclub: French. You can add more languages or improve existing\ntranslations at <a href=https://hosted.weblate.org/engage/app-manager>Weblate</a>.</section><section id=report-crashes class=level3 data-number=6.10.6><h3 data-number=6.10.6><span class=header-section-number>6.10.6</span> <a href=#toc:report-crashes>Report crashes</a><a href=#report-crashes class=anchor aria-hidden=true></a></h3><p>If App Manager crashes, you can now easily report the crash from the\nnotifications which opens the share options. Crashes are not reported by\nApp Manager, it only redirects you to your favourite Email client.</section><section id=android-11 class=level3 data-number=6.10.7><h3 data-number=6.10.7><span class=header-section-number>6.10.7</span> <a href=#toc:android-11>Android 11</a><a href=#android-11 class=anchor aria-hidden=true></a></h3><p>Added support for Android 11. Not everything may work as expected\nthough.</section><section id=app-installer-improvements class=level3 data-number=6.10.8><h3 data-number=6.10.8><span class=header-section-number>6.10.8</span> <a href=#toc:app-installer-improvements>App Installer Improvements</a><a href=#app-installer-improvements class=anchor aria-hidden=true></a></h3><section id=set-installation-locations class=level4 data-number=6.10.8.1><h4 data-number=6.10.8.1><span class=header-section-number>6.10.8.1</span> Set installation\nlocations<a href=#set-installation-locations class=anchor aria-hidden=true></a></h4><p>In settings page, you can set install locations such as auto\n(default), internal only and prefer external.</section><section id=set-apk-installer class=level4 data-number=6.10.8.2><h4 data-number=6.10.8.2><span class=header-section-number>6.10.8.2</span> Set APK installer<a href=#set-apk-installer class=anchor aria-hidden=true></a></h4><p>In settings page, you can also set default APK installer (root/ADB\nonly) instead of App Manager.</section><section id=multiple-users class=level4 data-number=6.10.8.3><h4 data-number=6.10.8.3><span class=header-section-number>6.10.8.3</span> Multiple users<a href=#multiple-users class=anchor aria-hidden=true></a></h4><p>In settings page, you can allow App Manager to display multiple users\nduring APK installation.</section><section id=signing-apk-files class=level4 data-number=6.10.8.4><h4 data-number=6.10.8.4><span class=header-section-number>6.10.8.4</span> Signing APK files<a href=#signing-apk-files class=anchor aria-hidden=true></a></h4><p>In settings page, you can choose to sign APK files before installing\nthem. You can also select which signature scheme to use in the <em>APK\nsigning</em> option in settings.<section id=known-limitation-3 class=level5 data-number=6.10.8.4.1><h5 data-number=6.10.8.4.1><span class=header-section-number>6.10.8.4.1</span> Known limitation<a href=#known-limitation-3 class=anchor aria-hidden=true></a></h5><p>Currently, only a generic key is used to sign APK files</section></section></section></section><section id=v2.5.17-368 class=level2 data-number=6.11><h2 data-number=6.11><span class=header-section-number>6.11</span>\n<a href=#toc:v2.5.17-368>v2.5.17 (368)</a><a href=#v2.5.17-368 class=anchor aria-hidden=true></a></h2><section id=app-installer class=level3 data-number=6.11.1><h3 data-number=6.11.1><span class=header-section-number>6.11.1</span> <a href=#toc:app-installer>App Installer</a><a href=#app-installer class=anchor aria-hidden=true></a></h3><p>As promised, it is now possible to select splits. AM also provides\nrecommendations based on device configurations. If the app is already\ninstalled, recommendations are provided based on the installed app. It\nis also possible to downgrade to a lower version without data loss if\nthe device has root or ADB. But it should be noted that not all app can\nbe downgraded. Installer is also improved to speed up the installation\nprocess, especially, for root users. If the app has already been\ninstalled and the new (x)apk(s) is newer or older or the same version\nwith a different signature, AM will display a list of changes similar to\n<strong>What’s New</strong> before prompting the user to install the\napp. This is useful if the app has introduced tracker components, new\npermissions, etc.<section id=known-limitations-1 class=level5 data-number=6.11.1.0.1><h5 data-number=6.11.1.0.1><span class=header-section-number>6.11.1.0.1</span> Known Limitations<a href=#known-limitations-1 class=anchor aria-hidden=true></a></h5><ul class=incremental><li><p>Large app can take a long time to fetch app info, and therefore,\nit may take a long time display the installation prompt.<li><p>If the apk is not located in the internal storage, the app has to\nbe cached first which might also take a long time depending on the size\nof the apk.</ul></section></section><section id=scanner-replacement-for-exodus-page class=level3 data-number=6.11.2><h3 data-number=6.11.2><span class=header-section-number>6.11.2</span> <a href=#toc:scanner-replacement-for-exodus-page>Scanner: Replacement for\nExodus Page</a><a href=#scanner-replacement-for-exodus-page class=anchor aria-hidden=true></a></h3><p>Exodus page is now replaced with scanner page. <a href=#sec:scanner-page>Scanner page</a> contains not only a list of\ntrackers but also a list of used libraries. This is just a start. In the\nfuture, this page will contain more in depth analysis of the app.</section><section id=introducing-system-config class=level3 data-number=6.11.3><h3 data-number=6.11.3><span class=header-section-number>6.11.3</span> <a href=#toc:introducing-system-config>Introducing System Config</a><a href=#introducing-system-config class=anchor aria-hidden=true></a></h3><p>System Config lists various system configurations and\nwhitelists/blacklists included in Android by either OEM/vendor, AOSP or\neven some Magisk modules. Root users can access this option from the\noverflow menu in the main page. There isn’t any official documentation\nfor these options therefore it’s difficult to write a complete\ndocumentation for this page. I will gradually add documentations using\nmy own knowledge. However, some functions should be understandable by\ntheir name.</section><section id=more-languages class=level3 data-number=6.11.4><h3 data-number=6.11.4><span class=header-section-number>6.11.4</span> <a href=#toc:more-languages>More Languages</a><a href=#more-languages class=anchor aria-hidden=true></a></h3><p>Thanks to the contributors, AM now has more than 12 languages. New\nlanguages include Bengali, Hindi, Norwegian, Polish, Russian, Simplified\nChinese, Turkish and Ukrainian.</section><section id=app-info-tab class=level3 data-number=6.11.5><h3 data-number=6.11.5><span class=header-section-number>6.11.5</span> <a href=#toc:app-info-tab>App Info Tab</a><a href=#app-info-tab class=anchor aria-hidden=true></a></h3><p>More tags are added in the <a href=#subsec:app-info-tab>app info\ntab</a> such as <strong>KeyStore</strong> (apps with KeyStore items),\n<strong>Systemless app</strong> (apps installed via Magisk),\n<strong>Running</strong> (apps that are running). For external apk, two\nmore options are added namely <strong>Reinstall</strong> and\n<strong>Downgrade</strong>. Now it is possible to share an apk via\nBluetooth. For system apps, it is possible to uninstall updates for\nroot/ADB users. But like the similar option in the system settings, this\noperation will clear all app data. As stated above, exodus has been\nreplaced with scanner.</section><section id=navigation-improvements class=level3 data-number=6.11.6><h3 data-number=6.11.6><span class=header-section-number>6.11.6</span> <a href=#toc:navigation-improvements>Navigation Improvements</a><a href=#navigation-improvements class=anchor aria-hidden=true></a></h3><p>It’s now relatively easy to navigate to various UI components using\nkeyboard. You can use up/down button to navigate between list items and\ntab button to navigate to UI components inside an item.</section><section id=running-apps-page class=level3 data-number=6.11.7><h3 data-number=6.11.7><span class=header-section-number>6.11.7</span> <a href=#toc:running-apps-page>Running Apps Page</a><a href=#running-apps-page class=anchor aria-hidden=true></a></h3><p>It is now possible to sort and filter processes in this tab. Also,\nthe three big buttons are replaced with an easy-to-use three dot menu.\nPreviously the memory usage was wrong which is fixed in this\nversion.</section><section id=built-in-toybox class=level3 data-number=6.11.8><h3 data-number=6.11.8><span class=header-section-number>6.11.8</span> <a href=#toc:built-in-toybox>Built-in Toybox</a><a href=#built-in-toybox class=anchor aria-hidden=true></a></h3><p>Toybox (an alternative to busybox) is bundled with AM. Although\nAndroid has this utility built-in from API 23, toybox is bundled in\norder to prevent buggy implementations and to support API &lt; 23.</section><section id=component-blocker-improvements class=level3 data-number=6.11.9><h3 data-number=6.11.9><span class=header-section-number>6.11.9</span> <a href=#toc:component-blocker-improvements>Component Blocker\nImprovements</a><a href=#component-blocker-improvements class=anchor aria-hidden=true></a></h3><p>Component blocker seemed to be problematic in the previous version,\nespecially when global component blocking is enabled. The issues are\nmostly fixed now.<div class=\"amalert warning\"><p><strong><em>Caution.</em></strong><p>The component blocking mechanism is no longer compatible with v2.5.6\ndue to various security issues. If you have this version, upgrade to\nv2.5.13 or earlier versions first. After that, enable <a href=#subsubsec:instant-component-blocking>global component\nblocking</a> and disable it again.</div></section><section id=improvements-in-the-app-details-page class=level3 data-number=6.11.10><h3 data-number=6.11.10><span class=header-section-number>6.11.10</span> <a href=#toc:improvements-in-the-app-details-page>Improvements in the App\nDetails Page</a><a href=#improvements-in-the-app-details-page class=anchor aria-hidden=true></a></h3><p>Value of various app ops depend on their parent app ops. Therefore,\nwhen you allow/deny an app op, the parent of the app op gets modified.\nThis fixes the issues some users have been complaining regarding some\napp ops that couldn’t be changed.<p>If an app has the target API 23 or less, its permissions cannot be\nmodified using the <code>pm grant …</code> command. Therefore, for such\napps, option to toggle permission has been disabled.<p>The signature tab is improved to support localization. It also\ndisplays multiple checksums for a signature.</section><section id=app-manifest class=level3 data-number=6.11.11><h3 data-number=6.11.11><span class=header-section-number>6.11.11</span> <a href=#toc:app-manifest>App Manifest</a><a href=#app-manifest class=anchor aria-hidden=true></a></h3><p>Manifest no longer crashes if the size of the manifest is too long.\nGenerated manifest are now more accurate than before.</section></section><section id=v2.5.13-348 class=level2 data-number=6.12><h2 data-number=6.12><span class=header-section-number>6.12</span>\n<a href=#toc:v2.5.13-348>v2.5.13 (348)</a><a href=#v2.5.13-348 class=anchor aria-hidden=true></a></h2><section id=bundled-app-split-apk class=level3 data-number=6.12.1><h3 data-number=6.12.1><span class=header-section-number>6.12.1</span> <a href=#toc:bundled-app-split-apk>Bundled App (Split APK)</a><a href=#bundled-app-split-apk class=anchor aria-hidden=true></a></h3><p>Bundled app formats such as <strong>apks</strong> and\n<strong>xapk</strong> are now supported. You can install these apps\nusing the regular installation buttons. For root and adb users, apps are\ninstalled using shell, and for non-root users, the platform default\nmethod is used.<section id=known-limitations-2 class=level5 data-number=6.12.1.0.1><h5 data-number=6.12.1.0.1><span class=header-section-number>6.12.1.0.1</span> Known Limitations<a href=#known-limitations-2 class=anchor aria-hidden=true></a></h5><ul class=incremental><li><p>Currently <em>all</em> splits apks are installed. But this\nbehaviour is going to change in the next release. If you only need a few\nsplits instead of all, extract the <strong>APKS</strong> or\n<strong>XAPK</strong> file, and then, create a new zip file with your\ndesired split apks and replace the <strong>ZIP</strong> extension with\n<strong>APKS</strong>. Now, open it with AM.<li><p>There is no progress dialog to display the installation\nprogress.</ul></section></section><section id=direct-install-support class=level3 data-number=6.12.2><h3 data-number=6.12.2><span class=header-section-number>6.12.2</span> <a href=#toc:direct-install-support>Direct Install Support</a><a href=#direct-install-support class=anchor aria-hidden=true></a></h3><p>You can now install <strong>APK</strong>, <strong>APKS</strong> or\n<strong>XAPK</strong> directly from your favourite browser or file\nmanager. For apps that need updates, a <strong>What’s New</strong>\ndialog is displayed showing the changes in the new version.<section id=known-limitations-3 class=level5 data-number=6.12.2.0.1><h5 data-number=6.12.2.0.1><span class=header-section-number>6.12.2.0.1</span> Known Limitations<a href=#known-limitations-3 class=anchor aria-hidden=true></a></h5><ul class=incremental><li><p>Downgrade is not yet possible.<li><p>There is no progress dialog to display the installation progress.\nIf you cannot interact with the current page, wait until the\ninstallation is finished.</ul></section></section><section id=remove-all-blocking-rules class=level3 data-number=6.12.3><h3 data-number=6.12.3><span class=header-section-number>6.12.3</span> <a href=#toc:remove-all-blocking-rules>Remove All Blocking Rules</a><a href=#remove-all-blocking-rules class=anchor aria-hidden=true></a></h3><p>In the Settings page, a new option is added which can be used to\nremove all blocking rules configured within App Manager.</section><section id=app-ops class=level3 data-number=6.12.4><h3 data-number=6.12.4><span class=header-section-number>6.12.4</span> <a href=#toc:app-ops>App\nOps</a><a href=#app-ops class=anchor aria-hidden=true></a></h3><ul class=incremental><li><p>App Ops are now generated using a technique similar to AppOpsX.\nThis should decrease the loading time significantly in the App Ops\ntab.<li><p>In the App Ops tab, a menu item is added which can be used to\nlist only active app ops without including the default app ops. The\npreference is saved in the shared preferences.</ul><section id=known-limitation-4 class=level5 data-number=6.12.4.0.1><h5 data-number=6.12.4.0.1><span class=header-section-number>6.12.4.0.1</span> Known Limitation<a href=#known-limitation-4 class=anchor aria-hidden=true></a></h5><p>Often the App Ops tab may not be responsive. If that’s the case,\nrestart App Manager.</section></section><section id=enhanced-adb-support class=level3 data-number=6.12.5><h3 data-number=6.12.5><span class=header-section-number>6.12.5</span> <a href=#toc:enhanced-adb-support>Enhanced ADB Support</a><a href=#enhanced-adb-support class=anchor aria-hidden=true></a></h3><p>ADB shell commands are now executed using a technique similar to\nAppOpsX (This is the <em>free</em> alternative of AppOps by Rikka.).\nThis should dramatically increase the execution time.<section id=known-limitation-5 class=level5 data-number=6.12.5.0.1><h5 data-number=6.12.5.0.1><span class=header-section-number>6.12.5.0.1</span> Known Limitation<a href=#known-limitation-5 class=anchor aria-hidden=true></a></h5><p>AM can often crash or become not responsive. If that’s the case,\nrestart App Manager.</section></section><section id=filtering-in-main-page class=level3 data-number=6.12.6><h3 data-number=6.12.6><span class=header-section-number>6.12.6</span> <a href=#toc:filtering-in-main-page>Filtering in Main Page</a><a href=#filtering-in-main-page class=anchor aria-hidden=true></a></h3><p>Add an option to filter apps that has at least one activity.</section><section id=apk-backupsharing class=level3 data-number=6.12.7><h3 data-number=6.12.7><span class=header-section-number>6.12.7</span> <a href=#toc:apk-backupsharing>Apk Backup/Sharing</a><a href=#apk-backupsharing class=anchor aria-hidden=true></a></h3><p>Apk files are now saved as <code>app name_version.extension</code>\ninstead of <code>package.name.extension</code>.</section><section id=batch-ops class=level3 data-number=6.12.8><h3 data-number=6.12.8><span class=header-section-number>6.12.8</span> <a href=#toc:batch-ops>Batch Ops</a><a href=#batch-ops class=anchor aria-hidden=true></a></h3><ul class=incremental><li><p>Added a foreground service to run batch operations. The result of\nthe operation is displayed in a notification. If an operation has failed\nfor some packages, clicking on the notification will open a dialog box\nlisting the failed packages. There is also a <strong>Try Again</strong>\nbutton on the bottom which can be used to perform the operation again\nfor the failed packages.<li><p>Replaced Linux <em>kill</em> with\n<strong>force-stop</strong>.</ul></section><section id=translations class=level3 data-number=6.12.9><h3 data-number=6.12.9><span class=header-section-number>6.12.9</span> <a href=#toc:translations>Translations</a><a href=#translations class=anchor aria-hidden=true></a></h3><p>Added German and Portuguese (Brazilian) translations.<section id=known-limitation-6 class=level5 data-number=6.12.9.0.1><h5 data-number=6.12.9.0.1><span class=header-section-number>6.12.9.0.1</span> Known Limitation<a href=#known-limitation-6 class=anchor aria-hidden=true></a></h5><p>Not all translations are verified yet.</section></section><section id=app-data-backup class=level3 data-number=6.12.10><h3 data-number=6.12.10><span class=header-section-number>6.12.10</span> <a href=#toc:app-data-backup>App Data Backup</a><a href=#app-data-backup class=anchor aria-hidden=true></a></h3><p>Install app only for the current user at the time of restoring\nbackups. Support for split apks is also added.<p><em>Data backup feature is now considered unstable. If you encounter\nany problem, please report to me without hesitation.</em></section></section></section><section id=ch:app-ops class=level1 data-number=7><h1 data-number=7><span class=header-section-number>7</span> <a href=#toc:ch:app-ops>App Ops</a><a href=#ch:app-ops class=anchor aria-hidden=true></a></h1><section id=sec:app-ops-background class=level2 data-number=7.1><h2 data-number=7.1><span class=header-section-number>7.1</span> <a href=#toc:sec:app-ops-background>Background</a><a href=#sec:app-ops-background class=anchor aria-hidden=true></a></h2><p><strong>App Ops</strong> (short hand for <strong>Application\nOperations</strong>) are used by Android system (since Android 4.3) to\ncontrol application permissions. The user <em>can</em> control some\npermissions, but only the permissions that are considered dangerous (and\nGoogle thinks knowing your phone number isn’t a dangerous thing). So,\napp ops seems to be the one we need if we want to install apps like\nFacebook and it’s Messenger (the latter literary records everything if\nyou live outside the EU) and still want <em>some</em> privacy and/or\nsecurity. Although certain features of app ops were available in\nSettings and later in hidden settings in older version of Android, it’s\ncompletely hidden in newer versions of Android and is continued to be\nkept hidden. Now, any app with\n<strong>android.Manifest.permission.GET_APP_OPS_STATS</strong>\npermission can get the app ops information for other applications but\nthis permission is hidden from users and can only be enabled using ADB\nor root. Still, the app with this permission cannot grant or revoke\npermissions (actually mode of operation) for apps other than itself\n(with limited capacity, of course). To modify the ops of other app, the\napp needs\n<strong>android.Manifest.permission.UPDATE_APP_OPS_STATS</strong>\npermissions which isn’t accessible via <code>pm</code> command. So, you\ncannot grant it via root or ADB, the permission is only granted to the\nsystem apps. There are very few apps who support disabling permissions\nvia app ops. The best one to my knowledge is <a href=https://github.com/8enet/AppOpsX>AppOpsX</a>. The main (visible)\ndifference between my app (AppManager) and this app is that the latter\nalso provides you the ability to revoke internet permissions (by writing\nip tables). One crucial problem that I faced during the development of\nthe app ops API is the lack of documentation in English language.</section><section id=sec:introduction-to-app-ops class=level2 data-number=7.2><h2 data-number=7.2><span class=header-section-number>7.2</span> <a href=#toc:sec:introduction-to-app-ops>Introduction to App Ops</a><a href=#sec:introduction-to-app-ops class=anchor aria-hidden=true></a></h2><figure id=fig:appops><figure><object data=../images/appops.svg type=image/svg+xml></object></figure><figcaption>Figure 2: How app ops work</figcaption></figure><p>Figure <a href=#fig:appops>1</a> describes the process of changing\nand processing permission. <a href=#sec:appopsmanager>AppOpsManager</a> can be used to manage\npermissions in Settings app. <strong>AppOpsManager</strong> is also\nuseful in determining if a certain permission (or operation) is granted\nto the application. Most of the methods of\n<strong>AppOpsManager</strong> are accessible to the user app but unlike\na system app, it can only be used to check permissions for any app or\nfor the app itself and start or terminating certain operations.\nMoreover, not all operations are actually accessible from this Java\nclass. <strong>AppOpsManager</strong> holds all the necessary constants\nsuch as <a href=#subsec:op-constants><code>OP_*</code></a>,\n<code>OPSTR_*</code>, <a href=#subsec:mode-constants><code>MODE_*</code></a> which describes\noperation code, operation string and mode of operations respectively. It\nalso holds necessary data structures such as <a href=#subsec:package-ops>PackageOps</a> and <strong>OpEntry</strong>.\n<strong>PackageOps</strong> holds <strong>OpEntry</strong> for a\npackage, and <strong>OpEntry</strong>, as the name suggests, describes\neach operation.<p><code>AppOpService</code> is completely hidden from a user\napplication but accessible to the system applications. As it can be seen\nin Figure <a href=#fig:appops>1</a>, this is the class that does the\nactual management stuff. It contains data structures such as\n<strong>Ops</strong> to store basic package info and <strong>Op</strong>\nwhich is similar to <strong>OpEntry</strong> of\n<strong>AppOpsManager</strong>. It also has <strong>Shell</strong> which\nis actually the source code of the <a href=#sec:appops-cli><em>appops</em> command line tool</a>. It writes\nconfigurations to or read configurations from <a href=#sec:appops-xml><code>/data/system/appops.xml</code></a>. System\nservices calls <strong>AppOpsService</strong> to find out what an\napplication is allowed and what is not allowed to perform, and\n<strong>AppOpsService</strong> determines these permissions by parsing\n<code>/data/system/appops.xml</code>. If no custom values are present in\n<em>appops.xml</em>, it returns the default mode available in\n<strong>AppOpsManager</strong>.</section><section id=sec:appopsmanager class=level2 data-number=7.3><h2 data-number=7.3><span class=header-section-number>7.3</span> <a href=#toc:sec:appopsmanager>AppOpsManager</a><a href=#sec:appopsmanager class=anchor aria-hidden=true></a></h2><p><a href=https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/app/AppOpsManager.java>AppOpsManager</a>\nstands for application operations manager. It consists of various\nconstants and classes to modify app operations.<div class=seealso-inline><p><em>Ver también: <span><a href=https://developer.android.com/reference/android/app/AppOpsManager>AppOpsManager\ndocumentation</a></span></em></div><section id=subsec:op-constants class=level3 data-number=7.3.1><h3 data-number=7.3.1><span class=header-section-number>7.3.1</span>\n<a href=#toc:subsec:op-constants><code>OP_*</code> Constants</a><a href=#subsec:op-constants class=anchor aria-hidden=true></a></h3><p><code>OP_*</code> are the integer constants starting from\n<code>0</code>. <code>OP_NONE</code> implies that no operations are\nspecified whereas <code>_NUM_OP</code> denotes the number of operations\ndefined in <code>OP_*</code> prefix. While they denote each operation,\nthe operations are not necessarily unique. In fact, there are many\noperations that are actually a single operation denoted by multiple\n<code>OP_*</code> constant (possibly for future use). Vendors may define\ntheir own op based on their requirements. MIUI is one of the vendors who\nare known to do that.<div class=listing><div class=sourceCode id=cb11 data-frame=lines><pre class=\"sourceCode java\"><code class=\"sourceCode java\"><span id=cb11-1><a href=#cb11-1 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=dt>final</span> <span class=dt>int</span> OP_NONE <span class=op>=</span> <span class=op>-</span><span class=dv>1</span><span class=op>;</span></span>\n<span id=cb11-2><a href=#cb11-2 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=dt>final</span> <span class=dt>int</span> OP_COARSE_LOCATION <span class=op>=</span> <span class=dv>0</span><span class=op>;</span></span>\n<span id=cb11-3><a href=#cb11-3 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=dt>final</span> <span class=dt>int</span> OP_FINE_LOCATION <span class=op>=</span> <span class=dv>1</span><span class=op>;</span></span>\n<span id=cb11-4><a href=#cb11-4 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=dt>final</span> <span class=dt>int</span> OP_GPS <span class=op>=</span> <span class=dv>2</span><span class=op>;</span></span>\n<span id=cb11-5><a href=#cb11-5 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=dt>final</span> <span class=dt>int</span> OP_VIBRATE <span class=op>=</span> <span class=dv>3</span><span class=op>;</span></span>\n<span id=cb11-6><a href=#cb11-6 aria-hidden=true tabindex=-1></a><span class=kw>...</span></span>\n<span id=cb11-7><a href=#cb11-7 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=dt>final</span> <span class=dt>int</span> OP_READ_DEVICE_IDENTIFIERS <span class=op>=</span> <span class=dv>89</span><span class=op>;</span></span>\n<span id=cb11-8><a href=#cb11-8 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=dt>final</span> <span class=dt>int</span> OP_ACCESS_MEDIA_LOCATION <span class=op>=</span> <span class=dv>90</span><span class=op>;</span></span>\n<span id=cb11-9><a href=#cb11-9 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=dt>final</span> <span class=dt>int</span> OP_ACTIVATE_PLATFORM_VPN <span class=op>=</span> <span class=dv>91</span><span class=op>;</span></span>\n<span id=cb11-10><a href=#cb11-10 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=dt>final</span> <span class=dt>int</span> _NUM_OP <span class=op>=</span> <span class=dv>92</span><span class=op>;</span></span></code></pre></div></div><p>Whether an operation is unique is defined by\n<code>sOpToSwitch</code>. It maps each operation to another operation or\nto itself (if it’s a unique operation). For instance,\n<code>OP_FINE_LOCATION</code> and <code>OP_GPS</code> are mapped to\n<code>OP_COARSE_LOCATION</code>.<p>Each operation has a private name which are described by\n<code>sOpNames</code>. These names are usually the same names as the\nconstants without the <code>OP_</code> prefix. Some operations have\npublic names as well which are described by <code>sOpToString</code>.\nFor instance, <code>OP_COARSE_LOCATION</code> has the public name\n<strong>android:coarse_location</strong>.<p>As a gradual process of moving permissions to app ops, there are\nalready many permissions that are defined under some operations. These\npermissions are mapped in <code>sOpPerms</code>. For example, the\npermission\n<strong>android.Manifest.permission.ACCESS_COARSE_LOCATION</strong> is\nmapped to <code>OP_COARSE_LOCATION</code>. Some operations may not have\nany associated permissions which have <code>null</code> values.<p>As described in the previous section, operations that are configured\nfor an app are stored at <a href=#sec:appops-xml><code>/data/system/appops.xml</code></a>. If an\noperation is not configured, then whether system will allow that\noperation is determined from <code>sOpDefaultMode</code>. It lists the\n<em>default mode</em> for each operation.</section><section id=subsec:mode-constants class=level3 data-number=7.3.2><h3 data-number=7.3.2><span class=header-section-number>7.3.2</span>\n<a href=#toc:subsec:mode-constants><code>MODE_*</code> Constants</a><a href=#subsec:mode-constants class=anchor aria-hidden=true></a></h3><p><code>MODE_*</code> constants also integer constants starting from\n<code>0</code>. These constants are assigned to each operation\ndescribing whether an app is authorised to perform that operation. These\nmodes usually have associated names such as <strong>allow</strong> for\n<code>MODE_ALLOWED</code>, <strong>ignore</strong> for\n<code>MODE_IGNORED</code>, <strong>deny</strong> for\n<code>MODE_ERRORED</code> (a rather misnomer), <strong>default</strong>\nfor <code>MODE_DEFAULT</code> and <strong>foreground</strong> for\n<code>MODE_FOREGROUND</code>.<ol class=incremental><li><p><strong><code>MODE_ALLOWED</code>.</strong> The app is allowed to\nperform the given operation<li><p><strong><code>MODE_IGNORED</code>.</strong> The app is not\nallowed to perform the given operation, and any attempt to perform the\noperation should <em>silently fail</em>, i.e. it should not cause the\napp to crash<li><p><strong><code>MODE_ERRORED</code>.</strong> The app is not\nallowed to perform the given operation, and this attempt should cause it\nto have a fatal error, typically a\n<code>SecurityException</code><li><p><strong><code>MODE_DEFAULT</code>.</strong> The app should use\nits default security check, specified in\n<code>AppOpsManager</code><li><p><strong><code>MODE_FOREGROUND</code>.</strong> Special mode that\nmeans “allow only when app is in foreground.” This mode was added in\nAndroid 10<li><p><strong><code>MODE_ASK</code>.</strong> This is a custom mode\nused by MIUI whose uses are unknown.</ol></section><section id=subsec:package-ops class=level3 data-number=7.3.3><h3 data-number=7.3.3><span class=header-section-number>7.3.3</span>\n<a href=#toc:subsec:package-ops>PackageOps</a><a href=#subsec:package-ops class=anchor aria-hidden=true></a></h3><p><strong>AppOpsManager.PackageOps</strong> is a data structure to\nstore all the <strong>OpEntry</strong> for a package. In simple terms,\nit stores all the customised operations for a package.<div class=listing><div class=sourceCode id=cb12 data-frame=lines><pre class=\"sourceCode java\"><code class=\"sourceCode java\"><span id=cb12-1><a href=#cb12-1 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=kw>class</span> PackageOps <span class=kw>implements</span> Parcelable <span class=op>{</span></span>\n<span id=cb12-2><a href=#cb12-2 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=bu>String</span> mPackageName<span class=op>;</span></span>\n<span id=cb12-3><a href=#cb12-3 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=dt>int</span> mUid<span class=op>;</span></span>\n<span id=cb12-4><a href=#cb12-4 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=bu>List</span><span class=op>&lt;</span>OpEntry<span class=op>&gt;</span> mEntries<span class=op>;</span></span>\n<span id=cb12-5><a href=#cb12-5 aria-hidden=true tabindex=-1></a>    <span class=kw>...</span></span>\n<span id=cb12-6><a href=#cb12-6 aria-hidden=true tabindex=-1></a><span class=op>}</span></span></code></pre></div></div><p>As can be seen in Listing <a href=#lst:package-ops-class>2</a>, it\nstores all <strong>OpEntry</strong> for a package as well as the\ncorresponding package name and its kernel user ID.</section><section id=subsec:opentry class=level3 data-number=7.3.4><h3 data-number=7.3.4><span class=header-section-number>7.3.4</span>\n<a href=#toc:subsec:opentry>OpEntry</a><a href=#subsec:opentry class=anchor aria-hidden=true></a></h3><p><strong>AppOpsManager.OpEntry</strong> is a data structure that\nstores a single operation for any package.<div class=listing><div class=sourceCode id=cb13 data-frame=lines><pre class=\"sourceCode java\"><code class=\"sourceCode java\"><span id=cb13-1><a href=#cb13-1 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=dt>final</span> <span class=kw>class</span> OpEntry <span class=kw>implements</span> Parcelable <span class=op>{</span></span>\n<span id=cb13-2><a href=#cb13-2 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=dt>int</span> mOp<span class=op>;</span></span>\n<span id=cb13-3><a href=#cb13-3 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=dt>boolean</span> mRunning<span class=op>;</span></span>\n<span id=cb13-4><a href=#cb13-4 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=at>@Mode</span> <span class=dt>int</span> mMode<span class=op>;</span></span>\n<span id=cb13-5><a href=#cb13-5 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=at>@Nullable</span> LongSparseLongArray mAccessTimes<span class=op>;</span></span>\n<span id=cb13-6><a href=#cb13-6 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=at>@Nullable</span> LongSparseLongArray mRejectTimes<span class=op>;</span></span>\n<span id=cb13-7><a href=#cb13-7 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=at>@Nullable</span> LongSparseLongArray mDurations<span class=op>;</span></span>\n<span id=cb13-8><a href=#cb13-8 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=at>@Nullable</span> LongSparseLongArray mProxyUids<span class=op>;</span></span>\n<span id=cb13-9><a href=#cb13-9 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=at>@Nullable</span> LongSparseArray<span class=op>&lt;</span><span class=bu>String</span><span class=op>&gt;</span> mProxyPackageNames<span class=op>;</span></span>\n<span id=cb13-10><a href=#cb13-10 aria-hidden=true tabindex=-1></a>    <span class=kw>...</span></span>\n<span id=cb13-11><a href=#cb13-11 aria-hidden=true tabindex=-1></a><span class=op>}</span></span></code></pre></div></div><p>Here:<ul class=incremental><li><p><code>mOp</code>: Denotes one of the <a href=#subsec:op-constants><code>OP_*</code> constants</a><li><p><code>mRunning</code>: Whether the operation is in progress\n(i.e. the operation has started but not finished yet). Not all\noperations can be started or finished this way<li><p><code>mMOde</code>: One of the <a href=#subsec:mode-constants><code>MODE_*</code> constants</a><li><p><code>mAccessTimes</code>: Stores all the available access\ntimes<li><p><code>mRejectTimes</code>: Stores all the available reject\ntimes<li><p><code>mDurations</code>: All available access durations, checking\nthis with <code>mRunning</code> will tell you for how long the app is\nperforming a certain app operation<li><p><code>mProxyUids</code>: No documentation found<li><p><code>mProxyPackageNames:</code> No documentation found</ul></section><section id=subsec:usage class=level3 data-number=7.3.5><h3 data-number=7.3.5><span class=header-section-number>7.3.5</span>\n<a href=#toc:subsec:usage>Usage</a><a href=#subsec:usage class=anchor aria-hidden=true></a></h3><p>TODO</section></section><section id=sec:appopsservice class=level2 data-number=7.4><h2 data-number=7.4><span class=header-section-number>7.4</span> <a href=#toc:sec:appopsservice>AppOpsService</a><a href=#sec:appopsservice class=anchor aria-hidden=true></a></h2><p>TODO</section><section id=sec:appops-xml class=level2 data-number=7.5><h2 data-number=7.5><span class=header-section-number>7.5</span> <a href=#toc:sec:appops-xml>appops.xml</a><a href=#sec:appops-xml class=anchor aria-hidden=true></a></h2><p>Latest <code>appops.xml</code> has the following format: (This DTD is\nmade by me and by no means perfect, has compatibility issues.)<pre><code>&lt;!DOCTYPE app-ops [\n\n&lt;!ELEMENT app-ops (uid|pkg)*&gt;\n&lt;!ATTLIST app-ops v CDATA #IMPLIED&gt;\n\n&lt;!ELEMENT uid (op)*&gt;\n&lt;!ATTLIST uid n CDATA #REQUIRED&gt;\n\n&lt;!ELEMENT pkg (uid)*&gt;\n&lt;!ATTLIST pkg n CDATA #REQUIRED&gt;\n\n&lt;!ELEMENT uid (op)*&gt;\n&lt;!ATTLIST uid\nn CDATA #REQUIRED\np CDATA #IMPLIED&gt;\n\n&lt;!ELEMENT op (st)*&gt;\n&lt;!ATTLIST op\nn CDATA #REQUIRED\nm CDATA #REQUIRED&gt;\n\n&lt;!ELEMENT st EMPTY&gt;\n&lt;!ATTLIST st\nn CDATA #REQUIRED\nt CDATA #IMPLIED\nr CDATA #IMPLIED\nd CDATA #IMPLIED\npp CDATA #IMPLIED\npu CDATA #IMPLIED&gt;\n\n]&gt;</code></pre><p>The instruction below follows the exact order given above:<ul class=incremental><li><p><code>app-ops</code>: The root element. It can contain any number\nof <code>pkg</code> or package <code>uid</code><ul class=incremental><li><p><code>v</code>: (optional, integer) The version number (default:\n<code>NO_VERSION</code> or <code>-1</code>)</ul><li><p><code>pkg</code>: Stores package info. It can contain any number\nof <code>uid</code><ul class=incremental><li><p><code>n</code>: (required, string) Name of the package</ul><li><p>Package <code>uid</code>: Stores package or packages info<ul class=incremental><li><p><code>n</code>: (required, integer) The user ID</ul><li><p><code>uid</code>: The package user ID. It can contain any number\nof <code>op</code><ul class=incremental><li><p><code>n</code>: (required, integer) The user ID<li><p><code>p</code>: (optional, boolean) Is the app is a\nprivate/system app</ul><li><p><code>op</code>: The operation, can contain <code>st</code> or\nnothing at all<ul class=incremental><li><p><code>n</code>: (required, integer) The op name in integer,\ni.e. AppOpsManager.OP_*<li><p><code>m</code>: (required, integer) The op mode,\ni.e. AppOpsManager.MODE_*</ul><li><p><code>st</code>: State of operation: whether the operation is\naccessed, rejected or running (not available on old versions)<ul class=incremental><li><p><code>n</code>: (required, long) Key containing flags and\nuid<li><p><code>t</code>: (optional, long) Access time (default:\n<code>0</code>)<li><p><code>r</code>: (optional, long) Reject time (default:\n<code>0</code>)<li><p><code>d</code>: (optional, long) Access duration (default:\n<code>0</code>)<li><p><code>pp</code>: (optional, string) Proxy package name<li><p><code>pu</code>: (optional, integer) Proxy package uid</ul></ul><p>This definition can be found at <a href=https://android.googlesource.com/platform/frameworks/base/+/master/services/core/java/com/android/server/appop/AppOpsService.java>AppOpsService</a>.</section><section id=sec:appops-cli class=level2 data-number=7.6><h2 data-number=7.6><span class=header-section-number>7.6</span> <a href=#toc:sec:appops-cli>Command Line Interface</a><a href=#sec:appops-cli class=anchor aria-hidden=true></a></h2><p><code>appops</code> or <code>cmd appops</code> (on latest versions)\ncan be accessible via ADB or root. This is an easier method to get or\nupdate any operation for a package (provided the package name is known).\nThe help page of this command is self-explanatory:<pre><code>AppOps service (appops) commands:\nhelp\nPrint this help text.\nstart [--user &lt;USER_ID&gt;] &lt;PACKAGE | UID&gt; &lt;OP&gt;\nStarts a given operation for a particular application.\nstop [--user &lt;USER_ID&gt;] &lt;PACKAGE | UID&gt; &lt;OP&gt;\nStops a given operation for a particular application.\nset [--user &lt;USER_ID&gt;] &lt;[--uid] PACKAGE | UID&gt; &lt;OP&gt; &lt;MODE&gt;\nSet the mode for a particular application and operation.\nget [--user &lt;USER_ID&gt;] &lt;PACKAGE | UID&gt; [&lt;OP&gt;]\nReturn the mode for a particular application and optional operation.\nquery-op [--user &lt;USER_ID&gt;] &lt;OP&gt; [&lt;MODE&gt;]\nPrint all packages that currently have the given op in the given mode.\nreset [--user &lt;USER_ID&gt;] [&lt;PACKAGE&gt;]\nReset the given application or all applications to default modes.\nwrite-settings\nImmediately write pending changes to storage.\nread-settings\nRead the last written settings, replacing current state in RAM.\noptions:\n&lt;PACKAGE&gt; an Android package name or its UID if prefixed by --uid\n&lt;OP&gt;      an AppOps operation.\n&lt;MODE&gt;    one of allow, ignore, deny, or default\n&lt;USER_ID&gt; the user id under which the package is installed. If --user is not\nspecified, the current user is assumed.</code></pre></section></section><section id=footnotes class=\"footnotes footnotes-end-of-document\" role=doc-endnotes><hr><ol><li id=fn1><p>For distributing normal releases only<a href=#fnref1 class=footnote-back role=doc-backlink>↩︎</a><li id=fn2><p>Los pull requests de GitHub se fusionarán manualmente\nutilizando los parches correspondientes. Como resultado, GitHub puede\nmarcarlos erróneamente como cerrados en lugar de fusionados.<a href=#fnref2 class=footnote-back role=doc-backlink>↩︎</a><li id=fn3><p>también puede dirigirse a mí como “Muntashir Akon”<a href=#fnref3 class=footnote-back role=doc-backlink>↩︎</a></ol></section>"
  },
  {
    "path": "docs/raw/es/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"intro$main$$introduction-chapter-title\">Introducción</string>\n    <string name=\"intro$main$$terminologies-title\">Terminología</string>\n    <string name=\"intro$main$$supported-versions-title\">Versiones soportadas</string>\n    <string name=\"intro$main$$official-sources-title\">Fuentes oficiales</string>\n    <string name=\"intro$main$$bin-sources-title\">Fuentes de distribución binaria</string>\n    <string name=\"intro$main$$source-code-links-title\">Enlaces al código fuente</string>\n    <string name=\"intro$main$$translations-title\">Traducciones</string>\n    <string name=\"intro$main$$contributing-title\">Contribuyendo</string>\n    <string name=\"intro$main$$buiding-title\">Instrucciones de construcción</string>\n    <string name=\"intro$main$$submit-patches-title\">Envío de parches</string>\n    <string name=\"intro$main$$donation-title\">Donación y Financiamiento</string>\n    <string name=\"intro$main$$contact-title\">Contacto</string>\n    <string name=\"intro$main$supported-versions\">En la actualidad, las versiones compatibles son v2.6.0 (estable), v3.0.0 (versiones alfa y de depuración). Las versiones anteriores de App\n\\nManager pueden contener vulnerabilidades de seguridad y no deben utilizarse.</string>\n    <string name=\"intro$main$source-code-links\">Todos, excepto GitHub, son los enlaces espejo. Las etiquetas deberían estar siempre actualizadas, pero no se garantiza que la rama maestra esté\n\\nactualizada. Si el objetivo es clonar la rama maestra, utiliza el enlace de GitHub en lugar de los otros.</string>\n    <string name=\"intro$main$translations\">App Manager no acepta traducciones directamente a través de solicitudes pull/merge. Las traducciones se gestionan automáticamente a través de\n\\nWeblate. Para unirse al equipo de traducción, visite \\\\url{https://hosted.weblate.org/engage/app-manager/}.</string>\n    <string name=\"intro$main$buiding\">Las instrucciones de compilación están disponibles en el archivo BUILDING ubicado en el directorio raíz de la fuente.</string>\n    <string name=\"pages$main-page$$section-title\">Página principal</string>\n    <string name=\"pages$main-page$$batch-operations-title\">Operaciones por lotes</string>\n    <string name=\"pages$main-page$$colour-codes-title\">Códigos de color</string>\n    <string name=\"pages$main-page$$application-types-title\">Tipos de aplicación</string>\n    <string name=\"pages$main-page$$version-info-title\">Información sobre la versión</string>\n    <string name=\"pages$main-page$$instructions-title\">Instrucciones</string>\n    <string name=\"pages$main-page$$list-options-title\">Lista de opciones</string>\n    <string name=\"pages$main-page$$sort-title\">Clasificar</string>\n    <string name=\"pages$main-page$$filter-title\">Filtro</string>\n    <string name=\"pages$main-page$$profile_name-title\">Nombre del perfil</string>\n    <string name=\"pages$main-page$$1-click-ops-title\">Operaciones con 1 clic</string>\n    <string name=\"pages$main-page$$app-usage-title\">Uso de la aplicación</string>\n    <string name=\"pages$main-page$$running-apps-title\">Aplicaciones en ejecución</string>\n    <string name=\"pages$main-page$$profiles-title\">Perfiles</string>\n    <string name=\"pages$main-page$$apk-updater-title\">Actualizador de APK</string>\n    <string name=\"pages$main-page$$settings-title\">Configuraciones</string>\n    <string name=\"pages$main-page$options-menu\">El menú de opciones ofrece varias opciones que se pueden usar para ordenar y filtrar las aplicaciones enumeradas, así como para navegar\n\\n a diferentes páginas dentro o fuera de App Manager.</string>\n    <string name=\"pages$main-page$list-options\">\\\\textbf{List options} contiene las opciones para clasificar y filtrar la lista en la página principal.</string>\n    <string name=\"pages$main-page$settings\">Este elemento del menú abre la \\\\hyperref[sec:settings-page]{Settings page} de la aplicación.</string>\n    <string name=\"pages$app-details-page$$section-title\">Página de detalles de la aplicación</string>\n    <string name=\"pages$app-details-page$$colour-codes-title\">Código de color</string>\n    <string name=\"pages$app-details-page$$app-info-tab-title\">Pestañas de información de la aplicación</string>\n    <string name=\"pages$app-details-page$$app-info-general-information-title\">Información general</string>\n    <string name=\"pages$app-details-page$$horizontal-action-panel-title\">Panel de acción horizontal</string>\n    <string name=\"pages$app-details-page$$app-info-options-menu-title\">Opciones de menú</string>\n    <string name=\"pages$app-details-page$$config-termux-title\">Configurar Termux</string>\n    <string name=\"pages$app-details-page$$component-tabs-title\">Pestañas de componentes</string>\n    <string name=\"pages$app-details-page$$receivers-title\">Receptores</string>\n    <string name=\"pages$app-details-page$$providers-title\">Proveedores</string>\n    <string name=\"pages$app-details-page$$additional-features-for-rooted-phones-title\">Características adicionales para dispositivos con acceso raíz</string>\n    <string name=\"pages$app-details-page$$blocking-trackers-title\">Bloqueo de rastreadores</string>\n    <string name=\"pages$app-details-page$$blocking-components-title\">Bloqueo de componentes</string>\n    <string name=\"pages$app-details-page$$permission-tabs-title\">Pestañas de permisos</string>\n    <string name=\"pages$app-details-page$$uses-permissions-title\">Permisos de uso</string>\n    <string name=\"pages$app-details-page$$permissions-title\">Permisos</string>\n    <string name=\"pages$one-click-ops-page$$section-title\">Página de operaciones con 1 clic</string>\n    <string name=\"pages$profile-page$$apps-tab-title\">Pestaña de aplicaciones</string>\n    <string name=\"pages$profile-page$$configurations-tab-title\">Pestaña de configuraciones</string>\n    <string name=\"pages$profile-page$$comment-title\">Comentario</string>\n    <string name=\"pages$profile-page$$components-title\">Componentes</string>\n    <string name=\"pages$profile-page$$app-ops-title\">Operaciones de aplicación</string>\n    <string name=\"pages$profile-page$$permissions-title\">Permisos</string>\n    <string name=\"pages$profile-page$$backup-restore-title\">Copia de seguridad/restauracion</string>\n    <string name=\"pages$profile-page$$export-blocking-rules-title\">Exportar reglas de bloqueo</string>\n    <string name=\"pages$profile-page$$force-stop-title\">Parada forzosa</string>\n    <string name=\"pages$profile-page$$clear-cache-title\">Limpiar caché</string>\n    <string name=\"pages$profile-page$$clear-data-title\">Limpiar datos</string>\n    <string name=\"pages$profile-page$$block-trackers-title\">Bloquear rastreadores</string>\n    <string name=\"pages$profile-page$$save-apk-title\">Guardar APK</string>\n    <string name=\"pages$profile-page$users\">Seleccione los usuarios para los que se aplicará el perfil. Todos los usuarios se seleccionan de forma predeterminada.</string>\n    <string name=\"pages$profile-page$clear-cache\">Habilite la limpieza de la caché para los paquetes seleccionados.</string>\n    <string name=\"pages$settings-page$$section-title\">Página de configuraciones</string>\n    <string name=\"pages$settings-page$$language-title\">Idioma</string>\n    <string name=\"pages$settings-page$$app-theme-title\">Tema de la aplicación</string>\n    <string name=\"pages$settings-page$$screen-lock-title\">Bloqueo de pantalla</string>\n    <string name=\"pages$settings-page$$mode-of-operation-title\">Modo de operación</string>\n    <string name=\"pages$settings-page$$apk-signing-title\">Firma de APK</string>\n    <string name=\"pages$settings-page$$signing-key-title\">Clave de firma</string>\n    <string name=\"pages$settings-page$$installer-title\">Instalador</string>\n    <string name=\"pages$settings-page$$sign-apk-title\">Firmar APK</string>\n    <string name=\"pages$settings-page$$install-location-title\">Ubicación de la instalación</string>\n    <string name=\"pages$settings-page$$installer-app-title\">Aplicación de instalación</string>\n    <string name=\"pages$settings-page$$backup-restore-title\">Copia de seguridad/restaurar</string>\n    <string name=\"pages$settings-page$$encryption-title\">Encriptación</string>\n    <string name=\"pages$settings-page$$backup-volume-title\">Volumen de copia de seguridad</string>\n    <string name=\"pages$settings-page$$rules-title\">Reglas</string>\n    <string name=\"pages$settings-page$$import-export-blocking-rules-title\">Importar/exportar reglas de bloqueo</string>\n    <string name=\"pages$settings-page$$remove-all-rules-title\">Remover todas las reglas</string>\n    <string name=\"pages$settings-page$$import-export-keystore-title\">Importar/exportar Keystore</string>\n    <string name=\"pages$settings-page$$device-info-title\">Sobre este dispositivo</string>\n    <string name=\"pages$settings-page$language\">Configurar el idioma de la aplicación. App Manager admite actualmente 21 (veintiún) idiomas.</string>\n    <string name=\"pages$settings-page$app-theme\">Configurar el tema de la aplicación.</string>\n    <string name=\"pages$settings-page$backup-restore\">Configuración relacionada con \\\\hyperref[sec:backup-restore]{back up/restore}.</string>\n    <string name=\"pages$settings-page$backup-options\">Personalice el \\\\textit{cuadro de diálogo de copia de seguridad/restauración} que se muestra al realizar una copia de seguridad. \n\\n\n\\n\\\\seealsoinline{\\\\hyperref[subsec:backup-restore-backup-options]{Backup options}}</string>\n    <string name=\"pages$scanner-page$$section-title\">Página del escáner</string>\n    <string name=\"pages$scanner-page$$missing-signatures-title\">Firmas faltantes</string>\n    <string name=\"pages$interceptor-page$$categories-title\">Categorías</string>\n    <string name=\"pages$interceptor-page$$flags-title\">Banderas</string>\n    <string name=\"pages$interceptor-page$$uri-title\">URI</string>\n    <string name=\"pages$interceptor-page$$send-edited-intent-title\">Enviar intención editada</string>\n    <string name=\"pages$interceptor-page$matching-activities\">Enumera todos los componentes de la actividad que coinciden con la intención. Esto lo determina internamente el sistema (en lugar de App Manager).\n\\nEl botón de lanzamiento junto a cada componente puede utilizarse para lanzarlos directamente desde App Manager.</string>\n    <string name=\"pages$interceptor-page$reset-to-default\">Restablece el Intent a su estado inicial.</string>\n    <string name=\"guide$main$$guides-chapter-title\">Guías</string>\n    <string name=\"guide$aot$$section-title\">ABD sobre TCP</string>\n    <string name=\"guide$aot$$enable-dev-options-title\">Habilitar opciones de desarrollador</string>\n    <string name=\"guide$aot$$location-dev-options-title\">Ubicación de las opciones de desarrollador</string>\n    <string name=\"guide$aot$$how-to-enable-dev-options-title\">Cómo activar las opciones del desarrollador</string>\n    <string name=\"guide$aot$$enable-usb-debugging-title\">Habilitar depuración USB</string>\n    <string name=\"guide$aot$$miui-usb-debug-title\">Xiaomi (MIUI)</string>\n    <string name=\"guide$aot$$emui-usb-debug-title\">HUAWEI (EMUI)</string>\n    <string name=\"guide$aot$$troubleshooting-usb-debug-title\">Solución de problemas</string>\n    <string name=\"guide$aot$$setup-adb-on-pc-title\">Configurar ADB en PC o Mac</string>\n    <string name=\"guide$aot$$setup-adb-win-title\">Windows</string>\n    <string name=\"guide$aot$$setup-adb-mac-title\">macOS</string>\n    <string name=\"guide$aot$$configure-aot-title\">Configurar ADB sobre TCP</string>\n    <string name=\"guide$aot$$adb-mode-am-title\">Habilitar el modo ADB en App Manager</string>\n    <string name=\"guide$aot$miui-usb-debug\">Habilite \\\\textbf{Depuración USB (Configuración de seguridad)} también.</string>\n    <string name=\"guide$aot$lg-usb-debug\">Aseguraré de tener \\\\textbf{USB tethering} habilitado.</string>\n    <string name=\"pages$main$$pages-chapter-title\">Páginas</string>\n    <string name=\"intro$main$intro\">App Manager es un gestor de paquetes avanzado para Android. Ofrece innumerables funciones y, en consecuencia, requiere un usuario\n\\nmanual para ayudar a sus usuarios. Este documento actúa como un manual de usuario para App Manager en el sentido de que pretende describir\n\\ntodas las características que App Manager tiene para ofrecer. Este documento también puede ser considerado como el ``oficial\\'\\' directrices para\n\\nApp Manager, y representa el comportamiento esperado de App Manager. Las traducciones pueden malinterpretar este documento (que es\n\\nescrito en inglés). Por lo tanto, cada usuario capaz debe leer la versión en inglés del documento para obtener el mejor\n\\nde App Manager. También podría haber otros recursos no oficiales o de terceros como artículos de blog, vídeos, chat\n\\ngrupos, etc. Si bien estos recursos pueden ser útiles para muchas personas, es posible que no estén actualizados con la versión actual de App Manager.\n\\nversión de App Manager. Si se detectan desviaciones en App Manager con respecto a este documento, deben notificarse en el\n\\n\\\\href{https://github.com/MuntashirAkon/AppManager/issues}{Rastreador de problemas de App Manager}.</string>\n    <string name=\"intro$main$contributing\">Hay múltiples formas en las que un usuario puede contribuir, como crear problemas útiles, asistir a debates, mejorar\n\\ndocumentación y traducciones, añadiendo bibliotecas o rastreadores no reconocidos, revisando el código fuente, así como\n\\ninformar de las vulnerabilidades de seguridad.</string>\n    <string name=\"pages$main-page$$how-app-ops-work-title\">Un elemento de la lista de aplicaciones en la página principal</string>\n    <string name=\"pages$main-page$$termux-title\">Termux</string>\n    <string name=\"pages$main-page$$options-menu-title\">Opciones de menú</string>\n    <string name=\"pages$main-page$intro\">La página principal muestra todas las aplicaciones instaladas, desinstaladas y con copia de seguridad. Un solo clic en cualquier elemento de la aplicación instalada\n\\nabre la respectiva \\\\hyperref[sec:app-details-page]{página de detalles de la aplicación}. Para las aplicaciones del sistema desinstaladas, se muestra un\n\\ndiálogo que puede utilizarse para reinstalar la aplicación. Utilizando la opción \\\\hyperlink{par:main-page-sort}{ordenación} de las\n\\nopciones de la lista, los elementos de la aplicación pueden ordenarse de varias maneras y conservarse al salir. También es posible filtrar los elementos\n\\nutilizando la opción \\\\hyperlink{par:main-page-filter}{filtro} de las opciones de la lista. El filtrado también es posible a través de la barra de búsqueda\n\\ncon soporte adicional para las expresiones regulares.</string>\n    <string name=\"pages$main-page$version-info\">El nombre de la versión va seguido de los siguientes prefijos:\n\\n\\\\begin{itemize}\n\\n \\\\item \\\\texttt{\\\\_} -- Sin aceleración por hardware (rompiendo las animaciones o transparencias in-app)\n\\n \\\\item \\\\texttt{textasciitilde} -- Aplicación de prueba\n\\n \\\\item \\\\texttt{debug} -- Aplicación depurable\n\\n\\end{itemize}</string>\n    <string name=\"pages$main-page$instructions\">Al hacer clic en \\\\textbf{Instrucciones} se abre la versión sin conexión del manual de usuario de App Manager. También puede abrir la\n\\nversión en línea si la función correspondiente no está instalada, o si no hay una WebView en el sistema para cargar el manual.\n\\npresente en el sistema para cargar el manual.</string>\n    <string name=\"pages$app-details-page$additional-features-for-rooted-phones\">A diferencia de los usuarios no-root, que son en su mayoría espectadores en estas pestañas, los usuarios root pueden realizar varias operaciones.</string>\n    <string name=\"pages$app-details-page$$app-ops-title\">Operaciones de aplicaciones</string>\n    <string name=\"pages$app-details-page$$signatures-tab-title\">Pestañas de firmas</string>\n    <string name=\"pages$main-page$termux\">Si la aplicación \\\\href{https://github.com/termux/termux-app}{Termux} está instalada en el sistema, la sesión en curso (o una\n\\nnueva sesión) puede abrirse directamente a través de este elemento del menú. La opción permanece oculta si la aplicación no está presente en el\n\\nsistema.</string>\n    <string name=\"pages$main-page$apk-updater\">Si la aplicación \\\\href{https://github.com/rumboalla/apkupdater}{APK Updater} está instalada en el sistema, ésta puede ser abierta\n\\ndirectamente desde este elemento del menú. La opción permanece oculta si la aplicación no está presente en el sistema.</string>\n    <string name=\"pages$app-details-page$$activities-title\">Actividades</string>\n    <string name=\"pages$one-click-ops-page$$block-unblock-trackers-title\">Bloquear/desbloquear rastreadores</string>\n    <string name=\"pages$one-click-ops-page$$1-click-restore-title\">Restaurar</string>\n    <string name=\"pages$interceptor-page$$intent-filters-title\">Filtros de intención</string>\n    <string name=\"pages$app-details-page$$servcies-title\">Servicios</string>\n    <string name=\"pages$one-click-ops-page$$1-click-back-up-title\">Apoyar</string>\n    <string name=\"pages$profile-page$force-stop\">Permita que los paquetes seleccionados se detengan a la fuerza.</string>\n    <string name=\"pages$profile-page$clear-data\">Habilitar el borrado de los datos para los paquetes seleccionados.</string>\n    <string name=\"pages$settings-page$$enable-disable-features-title\">Habilitar/deshabilitar características</string>\n    <string name=\"pages$one-click-ops-page$$block-components-dots-title\">Componentes de bloque\\\\puntos</string>\n    <string name=\"pages$profiles-page$$section-title\">Página de perfiles</string>\n    <string name=\"pages$profiles-page$$options-menu-title\">Opciones de menú</string>\n    <string name=\"pages$profile-page$$options-menu-title\">Opciones de menú</string>\n    <string name=\"pages$profile-page$$users-title\">Usuarios</string>\n    <string name=\"pages$profile-page$configurations-tab\">La pestaña Configuraciones se puede utilizar para configurar los paquetes seleccionados.</string>\n    <string name=\"pages$profile-page$$section-title\">Página de perfil</string>\n    <string name=\"pages$profile-page$$state-title\">Estado</string>\n    <string name=\"pages$settings-page$$backup-apps-with-keystore-title\">Aplicaciones de copia de seguridad con Android KeyStore</string>\n    <string name=\"pages$settings-page$screen-lock\">Bloquear App Manager usando el bloqueo de pantalla de Android siempre que se configure un bloqueo de pantalla.\n\\n\n\\n\\\\begin{warning}{Advertencia}\n\\n Si se desactiva el bloqueo de pantalla en Android después de activar esta configuración, App Manager no se abrirá hasta que se vuelva a activar.\n\\n\\\\end{warning}</string>\n    <string name=\"pages$settings-page$$signature-schemes-title\">Esquemas de firma</string>\n    <string name=\"pages$settings-page$$compression-method-title\">Método de compresión</string>\n    <string name=\"pages$settings-page$$backup-options-title\">Opciones de copia de seguridad</string>\n    <string name=\"pages$settings-page$$instant-component-blocking-title\">Bloqueo instantáneo de componentes</string>\n    <string name=\"pages$settings-page$intro\">La página de configuración se puede utilizar para personalizar el comportamiento de App Manager.</string>\n    <string name=\"pages$settings-page$installer-app\">Selecciona la aplicación instaladora, útil para aplicaciones que comprueban explícitamente el instalador como forma de verificar si la aplicación se instala legítimamente.\n\\nEsto sólo funciona para los usuarios root o ADB.\n\\n\n\\n\\\\begin{tip}{Notice}\n\\n Mientras que la comprobación del instalador puede parecer una preocupación legítima para una aplicación, el marco de Android ya se ocupa de esto durante la instalación.\n\\n La comprobación del instalador es simplemente la manera incorrecta de probar la legitimidad de la fuente de una aplicación.\n\\n\\\\end{tip}</string>\n    <string name=\"pages$settings-page$compression-method\">Establezca el método de compresión que se utilizará durante las copias de seguridad. App Manager soporta los métodos de compresión GZip y BZip2,\n\\nGZip es el método de compresión por defecto. No afecta a la restauración de una copia de seguridad existente.</string>\n    <string name=\"pages$settings-page$backup-apps-with-keystore\">Permitir la copia de seguridad de las aplicaciones que tienen entradas en el KeyStore de Android. Esta opción está desactivada por defecto porque algunas aplicaciones (como Signal) pueden bloquearse si se restauran.</string>\n    <string name=\"pages$settings-page$device-info\">Muestra la versión de Android, la seguridad, la CPU, la GPU, la batería, la memoria, la pantalla, los idiomas, la información del usuario, etc.</string>\n    <string name=\"pages$interceptor-page$extras\">Los extras son los pares clave-valor utilizados para proporcionar información adicional al componente de destino. Se pueden agregar más extras usando el botón \\\\textit{más} al lado del título.</string>\n    <string name=\"pages$interceptor-page$$section-title\">Página del interceptor</string>\n    <string name=\"pages$interceptor-page$$action-title\">Acción</string>\n    <string name=\"pages$settings-page$remove-all-rules\">Opción de un clic para eliminar todas las reglas configuradas dentro de App Manager.\n\\n Esto habilitará todos los componentes bloqueados, las operaciones de la aplicación se establecerán en sus valores predeterminados y se restablecerán los permisos.</string>\n    <string name=\"pages$interceptor-page$$data-title\">Datos</string>\n    <string name=\"pages$interceptor-page$$extras-title\">Extras</string>\n    <string name=\"pages$interceptor-page$$reset-to-default-title\">Resetear a valores por defecto</string>\n    <string name=\"pages$interceptor-page$flags\">Los indicadores son útiles para determinar cómo debe comportarse el sistema durante el lanzamiento o después del lanzamiento de una actividad.\n\\nEsto no debe ser tocado ya que requiere algunos conocimientos técnicos. El botón \\\\textit{plus} junto al título puede utilizarse para añadir una o más banderas.</string>\n    <string name=\"pages$interceptor-page$send-edited-intent\">Vuelva a enviar la intención editada a la aplicación de destino. Esto puede abrir una lista de aplicaciones en la que es necesario seleccionar la aplicación deseada.\n\\nEl resultado recibido de la aplicación de destino se enviará a la aplicación de origen. Como resultado, la aplicación de origen no sabrá si hubo un man-in-the-middle.</string>\n    <string name=\"pages$shared-prefs-editor-page$$section_title\">Página del editor de preferencias compartidas</string>\n    <string name=\"guide$aot$$enable-aot-via-pc-title\">Habilitar ADB sobre TCP a través de PC o Mac</string>\n    <string name=\"pages$interceptor-page$$matching-activities-title\">Actividades de emparejamiento</string>\n    <string name=\"pages$shared-prefs-editor-page$intro\">Las preferencias compartidas pueden editarse en esta página. Al hacer clic en cualquier elemento de la lista se abre el cuadro de diálogo de edición donde se puede\n\\neditar. El botón de acción flotante en la esquina inferior derecha puede utilizarse para añadir un nuevo elemento. Para guardar o eliminar el archivo\n\\no para descartar los cambios actuales, se pueden utilizar las opciones respectivas del menú.</string>\n    <string name=\"guide$aot$$lg-usb-debug-title\">LG</string>\n    <string name=\"guide$aot$$aot-lineage-os-title\">Lineage OS 17.1 y anteriores</string>\n    <string name=\"guide$aot$$setup-adb-linux-title\">Linux</string>\n    <string name=\"guide$aot$aot-lineage-os\">Los usuarios de Lineage OS (o sus derivados) pueden habilitar directamente ADB sobre TCP utilizando las opciones de desarrollador. Para habilitarlo\n\\nvaya a las \\\\textbf{opciones de desarrollador}, desplácese hacia abajo hasta encontrar \\\\textbf{ADB sobre red}. Ahora, utilice el botón de conmutación\n\\nen el lado derecho para habilitarlo y pasar a \\\\Sref{subsec:adb-mode-in-app-manager}.</string>\n    <string name=\"appendices$changelogs$$chapter-title\">Registros de cambios</string>\n    <string name=\"keywords$chapter\">\\\\newcommand{\\\\KeywordChapter}{Capítulo}</string>\n    <string name=\"titlepage$user_manual\">{\\\\huge\\\\bfseries Manual de Usuario\\\\par}</string>\n    <string name=\"keywords$see_also\">\\\\newcommand{\\\\KeywordSeeAlso}{Ver también:}</string>\n    <string name=\"keywords$end_of_keyword_in_alert\">\\\\newcommand{\\\\KeywordEndOfKeyWordInAlert}{.}</string>\n    <string name=\"titlepage$quotation\">\\\\begin{quotation}\n\\n ``Sabio y lento. Tropiezan los que corren rápido\\'\\'.\n\\n %\\\\sourceatright\n\\n {--- Fray Laurence, \\\\textit{Romeo y Julieta}}\n\\n \\\\end{quotation}</string>\n    <string name=\"intro$main$submit-patches\">Los repositorios ubicados en sitios distintos de GitHub se consideran actualmente réplicas, y las solicitudes de pull/merge enviadas en.\n\\n\\\\footnote{Los pull requests de GitHub se fusionarán manualmente utilizando los parches correspondientes.\n\\nComo resultado, GitHub puede marcarlos erróneamente como cerrados en lugar de fusionados.} En su lugar, los parches (como archivos \\\\texttt{.patch}) pueden ser enviados a través de archivos adjuntos de correo electrónico. \\\\textit{La firma es un requisito.} Consulte el archivo CONTRIBUIR ubicado en el directorio raíz\n\\nde la fuente para obtener más información.\n\\n\n\\n\\\\begin{warning}{Notice}\n\\n En caso de enviar parches por correo electrónico, toda la conversación puede ser accesible públicamente en el futuro. Por lo tanto, no\n\\n incluya ninguna información personal identificable (PII) que no sea su nombre o dirección de correo electrónico.\n\\n\\\\end{warning}</string>\n    <string name=\"intro$main$contact\">Muntashir Al-Islam\\\\footnote{también puede dirigirse a mí como ``Muntashir Akon\\'\\'}\\\\\\\\\n\\nCorreo electrónico: \\\\href{mailto:muntashirakon\\@riseup.net}{muntashirakon [arroba] riseup [punto] net}\\\\\\\\\n\\nHuella digital de la llave: \\\\texttt{7bad37c2981e41f8f6abea7f58f0b4f26c346fce}\\\\\\\\\n\\nGitHub: \\\\url{https://github.com/MuntashirAkon}\\\\\\\\\n\\nTwitter: \\\\url{https://twitter.com/Muntashir}</string>\n    <string name=\"intro$main$terminologies\">\\\\begin{itemize}\n\\n \\\\item \\\\textbf{AM} --- Nombre corto para App Manager.\n\\n \\\\item \\\\textbf{Block/Unblock} --- Se utiliza para bloquear o desbloquear componentes. La forma en que se bloquean los componentes depende de\n\\n las preferencias del usuario.\n\\n \\\\item \\\\textbf{IFW} --- Forma abreviada de Intent Firewall.\n\\n \\\\item \\\\textbf{Ops} --- Nombre abreviado de las operaciones, p. ej., operaciones de aplicación, operaciones por lotes, operaciones de 1 clic.\n\\n \\\\item \\\\textbf{SSAID} --- Forma abreviada de \\\\texttt{Settings.Secure.ANDROID\\\\_ID}. Es un identificador de dispositivo asignado a\n\\n cada aplicación (Android Oreo y en adelante). Se genera a partir de la combinación del certificado de firma de la app\n\\n y el SSAID establecido para el paquete \\\\texttt{android}. Como resultado, se garantiza que sea el mismo para una app a menos que\n\\n el usuario decida formatear el dispositivo. Se utiliza mucho para el seguimiento.\n\\n \\\\item \\\\textbf{Tracker} --- Denota los componentes del rastreador en todo el documento y en el App Manager, excepto en el\n\\n \\\\hyperref[sec:scanner-page]{página del rastreador}. Los rastreadores incluyen librerías como crash reporters, analytics\n\\n perfilado, identificación, anuncio, localización, etc. Por lo tanto, no son iguales en funciones. No hay distinción ni sesgo\n\\n entre las bibliotecas de código abierto y las de código cerrado que promueven el rastreo.\n\\n\\\\end{itemize}</string>\n    <string name=\"intro$main$donation\">\\\\emph{La donación o la compra no es un requisito para utilizar App Manager.} Aunque App Manager no admite ninguna\n\\nAunque App Manager no admite ninguna compra, se pueden enviar donaciones al propietario de App Manager a través de Open Source Collective.\n\\n\n\\nOpen Source Collective es un host fiscal en la plataforma Open Collective que ayuda a los proyectos de código abierto a gestionar\n\\nsus finanzas. En la actualidad, admite pagos a través de cuentas bancarias, PayPal, tarjetas de crédito o débito y\n\\ncriptomonedas.\n\\n\n\\n\\\\textit{Link:} \\\\url{https://opencollective.com/muntashir}.\n\\n\n\\nAl enviar las donaciones, los remitentes se comprometen a no utilizarlas como palanca para priorizar sus\n\\ncaracterísticas solicitadas. Las solicitudes de características no requieren recompensas ni donaciones, y se priorizan de acuerdo con\n\\nlas preferencias del propietario.\n\\n\n\\n\\\\emph{App Manager acepta cualquier oferta de financiación o subvención.} Los representantes de la organización interesada pueden ponerse en contacto\n\\ndirectamente con el propietario utilizando las opciones que se indican en \\\\Sref{sec:contact}.</string>\n    <string name=\"pages$main-page$batch-operations\">En esta página también se pueden realizar operaciones por lotes o en varias aplicaciones. El modo de selección múltiple puede\n\\nactivarse haciendo clic en el icono de cualquier aplicación o haciendo un clic prolongado en cualquier elemento de la lista. Una vez activado, un solo clic en\n\\nun elemento de la lista lo selecciona en lugar de abrir la página de detalles de la aplicación. En este modo, las operaciones por lotes se encuentran en el\n\\nmenú de selección múltiple en la parte inferior de la página. Las operaciones incluyen:\n\\n\\\\begin{itemize}\n\\n \\\\item Añadir las aplicaciones seleccionadas a un perfil.\n\\n \\\\item \\\\hyperref[sec:backup-restore]{Hacer una copia de seguridad, restaurar o eliminar} las aplicaciones\n\\n \\\\item Bloquear los rastreadores de las aplicaciones\n\\n \\\\item Borrar los datos o la caché de las aplicaciones\n\\n \\\\item Habilitar/deshabilitar/forzar la desinstalación de las aplicaciones\n\\n \\\\item Exportar las reglas de bloqueo guardadas en App Manager\n\\n \\\\item Impedir las operaciones en segundo plano de las aplicaciones (Android 7 y posteriores)\n\\n \\\\item Guardar los archivos APK en \\\\texttt{AppManager/apks}\n\\n \\\\item Establecer \\\\hyperref[sec:net-policy]{políticas de red}\n\\n\\\\end{itemize}\n\\n\n\\n\\\\begin{tip}{Accesibilidad}\n\\n Una vez activado el modo de selección múltiple, es posible navegar dentro o fuera del menú de selección múltiple\n\\n de selección múltiple utilizando las teclas derecha o izquierda del teclado o del mando a distancia.\n\\n\\\\end{tip}</string>\n</resources>"
  },
  {
    "path": "docs/raw/fr/index.html",
    "content": "<!doctype html><html xmlns=http://www.w3.org/1999/xhtml lang=fr xml:lang=fr><meta charset=utf-8><meta name=generator content=\"pandoc\"><meta name=viewport content=\"width=device-width,initial-scale=1,user-scalable=yes\"><meta name=author content=\"Muntashir Al-Islam\"><title>App Manager</title><style>code{white-space:pre-wrap}span.smallcaps{font-variant:small-caps}div.columns{display:flex;gap:min(4vw,1.5em)}div.column{flex:auto;overflow-x:auto}div.hanging-indent{margin-left:1.5em;text-indent:-1.5em}ul.task-list[class]{list-style:none}ul.task-list li input[type=checkbox]{font-size:inherit;width:.8em;margin:0 .8em .2em -1.6em;vertical-align:middle}.display.math{display:block;text-align:center;margin:.5rem auto}html{-webkit-text-size-adjust:100%}pre>code.sourceCode{white-space:pre;position:relative}pre>code.sourceCode>span{display:inline-block;line-height:1.25}pre>code.sourceCode>span:empty{height:1.2em}.sourceCode{overflow:visible}code.sourceCode>span{color:inherit;text-decoration:inherit}div.sourceCode{margin:1em 0}pre.sourceCode{margin:0}@media screen{div.sourceCode{overflow:auto}}@media print{pre>code.sourceCode{white-space:pre-wrap}pre>code.sourceCode>span{text-indent:-5em;padding-left:5em}}pre.numberSource code{counter-reset:source-line 0}pre.numberSource code>span{position:relative;left:-4em;counter-increment:source-line}pre.numberSource code>span>a:first-child::before{content:counter(source-line);position:relative;left:-1em;text-align:right;vertical-align:baseline;border:none;display:inline-block;-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;padding:0 4px;width:4em}pre.numberSource{margin-left:3em;padding-left:4px}div.sourceCode{}@media screen{pre>code.sourceCode>span>a:first-child::before{text-decoration:underline}}code span.al{font-weight:700}code span.an{font-style:italic}code span.cf{font-weight:700}code span.co{font-style:italic}code span.cv{font-style:italic}code span.do{font-style:italic}code span.dt{text-decoration:underline}code span.er{font-weight:700}code span.in{font-style:italic}code span.kw{font-weight:700}code span.pp{font-weight:700}code span.wa{font-style:italic}</style><link rel=stylesheet href=../css/custom.css><header id=title-block-header><h1 class=title>App Manager</h1><p class=author>Muntashir Al-Islam</header><nav id=TOC role=doc-toc><ul class=incremental><li><span><span class=toc-section-number>1</span> <a href=#ch:introduction id=toc:ch:introduction>Introduction</a></span><ul class=incremental><li><span><span class=toc-section-number>1.1</span> <a href=#sec:terminologies id=toc:sec:terminologies>Terminologies</a></span><li><span><span class=toc-section-number>1.2</span> <a href=#sec:supported-versions id=toc:sec:supported-versions>Versions\nSupportées</a></span><li><span><span class=toc-section-number>1.3</span> <a href=#sec:official-sources id=toc:sec:official-sources>Sources\nOfficielles</a></span><ul class=incremental><li><span><span class=toc-section-number>1.3.1</span> <a href=#subsec:binary-distribution-sources id=toc:subsec:binary-distribution-sources>Sources de distribution de\nbinaires</a></span><li><span><span class=toc-section-number>1.3.2</span> <a href=#subsec:links-to-source-code id=toc:subsec:links-to-source-code>Liens vers code\nsource</a></span><li><span><span class=toc-section-number>1.3.3</span> <a href=#subsec:translations id=toc:subsec:translations>Traductions</a></span></ul><li><span><span class=toc-section-number>1.4</span> <a href=#sec:contributing id=toc:sec:contributing>Contribuer</a></span><ul class=incremental><li><span><span class=toc-section-number>1.4.1</span> <a href=#subsec:build-instructions id=toc:subsec:build-instructions>Instructions de build</a></span><li><span><span class=toc-section-number>1.4.2</span> <a href=#subsec:submitting-patches id=toc:subsec:submitting-patches>Soumettre des patchs</a></span></ul><li><span><span class=toc-section-number>1.5</span> <a href=#sec:donation-&-funding id=toc:sec:donation-&-funding>Dons et Financement</a></span><li><span><span class=toc-section-number>1.6</span> <a href=#sec:contact id=toc:sec:contact>Contact</a></span></ul><li><span><span class=toc-section-number>2</span> <a href=#ch:pages id=toc:ch:pages>Pages</a></span><ul class=incremental><li><span><span class=toc-section-number>2.1</span> <a href=#sec:main-page id=toc:sec:main-page>Main Page</a></span><ul class=incremental><li><span><span class=toc-section-number>2.1.1</span> <a href=#subsec:batch-operations id=toc:subsec:batch-operations>Batch\nOperations</a></span><li><span><span class=toc-section-number>2.1.2</span> <a href=#subsec:main-colour-codes id=toc:subsec:main-colour-codes>Colour Codes</a></span><li><span><span class=toc-section-number>2.1.3</span> <a href=#subsec:main-page-application-types id=toc:subsec:main-page-application-types>Application\nTypes</a></span><li><span><span class=toc-section-number>2.1.4</span> <a href=#subsec:main-page-version-info id=toc:subsec:main-page-version-info>Version Info</a></span><li><span><span class=toc-section-number>2.1.5</span> <a href=#subsec:main-page-options-menu id=toc:subsec:main-page-options-menu>Options Menu</a></span></ul><li><span><span class=toc-section-number>2.2</span> <a href=#sec:app-details-page id=toc:sec:app-details-page>App Details\nPage</a></span><ul class=incremental><li><span><span class=toc-section-number>2.2.1</span> <a href=#subsec:app-details-colour-codes id=toc:subsec:app-details-colour-codes>Colour Codes</a></span><li><span><span class=toc-section-number>2.2.2</span> <a href=#subsec:app-info-tab id=toc:subsec:app-info-tab>App Info\nTab</a></span><li><span><span class=toc-section-number>2.2.3</span> <a href=#subsec:component-tabs id=toc:subsec:component-tabs>Component\nTabs</a></span><li><span><span class=toc-section-number>2.2.4</span> <a href=#subsec:permission-tabs id=toc:subsec:permission-tabs>Permission Tabs</a></span><li><span><span class=toc-section-number>2.2.5</span> <a href=#subsec:signatures-tab id=toc:subsec:signatures-tab>Signatures\nTab</a></span><li><span><span class=toc-section-number>2.2.6</span> <a href=#subsec:uses-features-tab id=toc:subsec:uses-features-tab>Uses\nFeatures tab</a></span><li><span><span class=toc-section-number>2.2.7</span> <a href=#subsec:configurations-tab id=toc:subsec:configurations-tab>Configurations tab</a></span><li><span><span class=toc-section-number>2.2.8</span> <a href=#subsec:shared-libs-tab id=toc:subsec:shared-libs-tab>Shared\nLibraries Tab</a></span></ul><li><span><span class=toc-section-number>2.3</span> <a href=#sec:1-click-ops-page id=toc:sec:1-click-ops-page>1-Click Ops\nPage</a></span><ul class=incremental><li><span><span class=toc-section-number>2.3.1</span> <a href=#subsec:block-unblock-trackers id=toc:subsec:block-unblock-trackers>Block/Unblock\nTrackers</a></span><li><span><span class=toc-section-number>2.3.2</span> <a href=#subsec:block-components-dots id=toc:subsec:block-components-dots>Block Components…</a></span><li><span><span class=toc-section-number>2.3.3</span> <a href=#subsec:set-mode-for-app-ops-dots id=toc:subsec:set-mode-for-app-ops-dots>Set Mode for App\nOps…</a></span><li><span><span class=toc-section-number>2.3.4</span> <a href=#subsec:1-click-back-up id=toc:subsec:1-click-back-up>Back\nup</a></span><li><span><span class=toc-section-number>2.3.5</span> <a href=#subsec:1-click-restore id=toc:subsec:1-click-restore>Restore</a></span><li><span><span class=toc-section-number>2.3.6</span> <a href=#subsec:trim-caches-in-all-apps id=toc:subsec:trim-caches-in-all-apps>Trim Caches in All\nApps</a></span></ul><li><span><span class=toc-section-number>2.4</span> <a href=#sec:profiles-page id=toc:sec:profiles-page>Profiles\nPage</a></span><ul class=incremental><li><span><span class=toc-section-number>2.4.1</span> <a href=#subsec:profiles-options-menu id=toc:subsec:profiles-options-menu>Options Menu</a></span></ul><li><span><span class=toc-section-number>2.5</span> <a href=#sec:profile-page id=toc:sec:profile-page>Profile\nPage</a></span><ul class=incremental><li><span><span class=toc-section-number>2.5.1</span> <a href=#subsec:profile-options-menu id=toc:subsec:profile-options-menu>Options Menu</a></span><li><span><span class=toc-section-number>2.5.2</span> <a href=#subsec:profile-apps-tab id=toc:subsec:profile-apps-tab>Apps\nTab</a></span><li><span><span class=toc-section-number>2.5.3</span> <a href=#subsec:profile-configurations-tab id=toc:subsec:profile-configurations-tab>Configurations\nTab</a></span></ul><li><span><span class=toc-section-number>2.6</span> <a href=#sec:settings-page id=toc:sec:settings-page>Settings\nPage</a></span><ul class=incremental><li><span><span class=toc-section-number>2.6.1</span> <a href=#subsec:language id=toc:subsec:language>Language</a></span><li><span><span class=toc-section-number>2.6.2</span> <a href=#subsec:appearance id=toc:subsec:appearance>Appearance</a></span><li><span><span class=toc-section-number>2.6.3</span> <a href=#subsec:privacy id=toc:subsec:privacy>Privacy</a></span><li><span><span class=toc-section-number>2.6.4</span> <a href=#subsec:mode-of-operation id=toc:subsec:mode-of-operation>Mode\nof Operation</a></span><li><span><span class=toc-section-number>2.6.5</span> <a href=#subsec:apk-signing id=toc:subsec:apk-signing>APK\nSigning</a></span><li><span><span class=toc-section-number>2.6.6</span> <a href=#subsec:installer id=toc:subsec:installer>Installer</a></span><li><span><span class=toc-section-number>2.6.7</span> <a href=#subsec:backup/restore id=toc:subsec:backup/restore>Back\nup/Restore</a></span><li><span><span class=toc-section-number>2.6.8</span> <a href=#subsec:rules id=toc:subsec:rules>Rules</a></span><li><span><span class=toc-section-number>2.6.9</span> <a href=#subsec:advanced id=toc:subsec:advanced>Advanced</a></span><li><span><span class=toc-section-number>2.6.10</span> <a href=#subsec:device-info id=toc:subsec:device-info>About the\ndevice</a></span></ul><li><span><span class=toc-section-number>2.7</span> <a href=#sec:scanner-page id=toc:sec:scanner-page>Scanner\nPage</a></span><li><span><span class=toc-section-number>2.8</span> <a href=#sec:interceptor-page id=toc:sec:interceptor-page>Interceptor\nPage</a></span><ul class=incremental><li><span><span class=toc-section-number>2.8.1</span> <a href=#subsec:intent-filters id=toc:subsec:intent-filters>Intent\nFilters</a></span><li><span><span class=toc-section-number>2.8.2</span> <a href=#subsec:matching-activities id=toc:subsec:matching-activities>Matching Activities</a></span><li><span><span class=toc-section-number>2.8.3</span> <a href=#subsec:interceptor-reset-to-default id=toc:subsec:interceptor-reset-to-default>Reset to\nDefault</a></span><li><span><span class=toc-section-number>2.8.4</span> <a href=#subsec:interceptor-send-edited-intent id=toc:subsec:interceptor-send-edited-intent>Send Edited\nIntent</a></span></ul><li><span><span class=toc-section-number>2.9</span> <a href=#sec:shared-preferences-editor-page id=toc:sec:shared-preferences-editor-page>Shared Preferences Editor\nPage</a></span></ul><li><span><span class=toc-section-number>3</span> <a href=#ch:guides id=toc:ch:guides>Guides</a></span><ul class=incremental><li><span><span class=toc-section-number>3.1</span> <a href=#sec:adb-over-tcp id=toc:sec:adb-over-tcp>ADB over\nTCP</a></span><ul class=incremental><li><span><span class=toc-section-number>3.1.1</span> <a href=#subsec:enable-developer-options id=toc:subsec:enable-developer-options>Enable developer\noptions</a></span><li><span><span class=toc-section-number>3.1.2</span> <a href=#subsec:enable-usb-debugging id=toc:subsec:enable-usb-debugging>Enable USB\ndebugging</a></span><li><span><span class=toc-section-number>3.1.3</span> <a href=#subsec:setup-adb-on-pc-or-mac id=toc:subsec:setup-adb-on-pc-or-mac>Setup ADB on PC or\nMac</a></span><li><span><span class=toc-section-number>3.1.4</span> <a href=#subsec:configure-adb-over-tcp id=toc:subsec:configure-adb-over-tcp>Configure ADB over\nTCP</a></span></ul><li><span><span class=toc-section-number>3.2</span> <a href=#sec:wireless-debugging id=toc:sec:wireless-debugging>Wireless\nDebugging</a></span><ul class=incremental><li><span><span class=toc-section-number>3.2.1</span> <a href=#subsec:enable-developer-options-and-usb-debugging id=toc:subsec:enable-developer-options-and-usb-debugging>Enable\ndeveloper options and USB Debugging</a></span><li><span><span class=toc-section-number>3.2.2</span> <a href=#subsec:enable-wireless-debugging id=toc:subsec:enable-wireless-debugging>Enable Wireless\nDebugging</a></span><li><span><span class=toc-section-number>3.2.3</span> <a href=#subsec:pair-adb-with-app-manager id=toc:subsec:pair-adb-with-app-manager>Pair ADB with App\nManager</a></span><li><span><span class=toc-section-number>3.2.4</span> <a href=#subsec:connect-app-manager-to-adb id=toc:subsec:connect-app-manager-to-adb>Connect App Manager to\nADB</a></span></ul><li><span><span class=toc-section-number>3.3</span> <a href=#sec:backup-restore id=toc:sec:backup-restore>Back\nup/Restore</a></span><ul class=incremental><li><span><span class=toc-section-number>3.3.1</span> <a href=#subsec:backup-location id=toc:subsec:backup-location>Location</a></span><li><span><span class=toc-section-number>3.3.2</span> <a href=#subsec:backup-restore-backup-options id=toc:subsec:backup-restore-backup-options>Backup\nOptions</a></span><li><span><span class=toc-section-number>3.3.3</span> <a href=#subsec:backup-restore-backup id=toc:subsec:backup-restore-backup>Backup</a></span><li><span><span class=toc-section-number>3.3.4</span> <a href=#subsec:backup-restore-restore id=toc:subsec:backup-restore-restore>Restore</a></span><li><span><span class=toc-section-number>3.3.5</span> <a href=#subsec:backup-restore-delete-backup id=toc:subsec:backup-restore-delete-backup>Delete\nBackup</a></span></ul><li><span><span class=toc-section-number>3.4</span> <a href=#sec:automating-tasks id=toc:sec:automating-tasks>Automating\nTasks</a></span><ul class=incremental><li><span><span class=toc-section-number>3.4.1</span> <a href=#subsec:generating-authorization-key id=toc:subsec:generating-authorization-key>Generating authorization\nkey</a></span><li><span><span class=toc-section-number>3.4.2</span> <a href=#subsec:at:general-configuration id=toc:subsec:at:general-configuration>Configuring\ntasks</a></span><li><span><span class=toc-section-number>3.4.3</span> <a href=#subsec:at:features id=toc:subsec:at:features>Features</a></span><li><span><span class=toc-section-number>3.4.4</span> <a href=#subsec:triggering-a-profile id=toc:subsec:triggering-a-profile>Triggering a\nprofile</a></span></ul><li><span><span class=toc-section-number>3.5</span> <a href=#sec:net-policy id=toc:sec:net-policy>Net\nPolicy</a></span></ul><li><span><span class=toc-section-number>4</span> <a href=#ch:faq id=toc:ch:faq>Frequently Asked Questions</a></span><ul class=incremental><li><span><span class=toc-section-number>4.1</span> <a href=#sec:faq:app-components id=toc:sec:faq:app-components>App\nComponents</a></span><ul class=incremental><li><span><span class=toc-section-number>4.1.1</span> <a href=#subsec:faq:what-are-app-components id=toc:subsec:faq:what-are-app-components>What are the application\ncomponents?</a></span><li><span><span class=toc-section-number>4.1.2</span> <a href=#subsec:faq:how-components-blocked id=toc:subsec:faq:how-components-blocked>How are the tracker and other\ncomponents blocked in App Manager? What are its\nlimitations?</a></span><li><span><span class=toc-section-number>4.1.3</span> <a href=#subsec:faq:components-blocked-by-others id=toc:subsec:faq:components-blocked-by-others>Does app components\nblocked by other tools retained in App Manager?</a></span><li><span><span class=toc-section-number>4.1.4</span> <a href=#subsec:faq:components-reblocked-in-am id=toc:subsec:faq:components-reblocked-in-am>What happens to the\ncomponents blocked by App Manager which were previously blocked by other\ntools?</a></span><li><span><span class=toc-section-number>4.1.5</span> <a href=#subsec:faq:what-is-instant-component-blocking id=toc:subsec:faq:what-is-instant-component-blocking>What is instant\ncomponent blocking?</a></span><li><span><span class=toc-section-number>4.1.6</span> <a href=#subsec:tracker-classes-versus-tracker-components id=toc:subsec:tracker-classes-versus-tracker-components>Tracker\nclasses versus tracker components</a></span></ul><li><span><span class=toc-section-number>4.2</span> <a href=#sec:faq:adb-over-tcp id=toc:sec:faq:adb-over-tcp>ADB over\nTCP</a></span><ul class=incremental><li><span><span class=toc-section-number>4.2.1</span> <a href=#subsec:faq:enable-adb-on-every-restart id=toc:subsec:faq:enable-adb-on-every-restart>Do I have to enable ADB\nover TCP everytime I restart?</a></span><li><span><span class=toc-section-number>4.2.2</span> <a href=#subsec:faq:usb-debugging id=toc:subsec:faq:usb-debugging>Cannot enable USB debugging. What to\ndo?</a></span><li><span><span class=toc-section-number>4.2.3</span> <a href=#subsec:faq:block-components-using-adb id=toc:subsec:faq:block-components-using-adb>Can I block tracker or\nany other application components using ADB over TCP?</a></span><li><span><span class=toc-section-number>4.2.4</span> <a href=#subsec:faq:adb-features id=toc:subsec:faq:adb-features>Which\nfeatures can be used in ADB mode?</a></span></ul><li><span><span class=toc-section-number>4.3</span> <a href=#sec:faq:miscellanea id=toc:sec:faq:miscellanea>Miscellanea</a></span><ul class=incremental><li><span><span class=toc-section-number>4.3.1</span> <a href=#subsec:faq:no-root-no-harms id=toc:subsec:faq:no-root-no-harms>I don’t use root/ADB. Am I\ncompletely safe from any harms?</a></span><li><span><span class=toc-section-number>4.3.2</span> <a href=#subsec:faq:how-trackers-libs-updated id=toc:subsec:faq:how-trackers-libs-updated>How are the trackers and\nlibraries are updated?</a></span><li><span><span class=toc-section-number>4.3.3</span> <a href=#subsec:faq:apks-deleted-after-installed id=toc:subsec:faq:apks-deleted-after-installed>Are APKs deleted after\ninstalled?</a></span><li><span><span class=toc-section-number>4.3.4</span> <a href=#subsec:faq:shizuku-support id=toc:subsec:faq:shizuku-support>Any plans for\nShizuku?</a></span><li><span><span class=toc-section-number>4.3.5</span> <a href=#subsec:faq:what-are-bloatware id=toc:subsec:faq:what-are-bloatware>What are bloatware and how to\nremove them?</a></span></ul></ul><li><span><span class=toc-section-number>5</span> <a href=#ch:specifications id=toc:ch:specifications>Specifications</a></span><ul class=incremental><li><span><span class=toc-section-number>5.1</span> <a href=#sec:rules-specification id=toc:sec:rules-specification>Rules\nSpecification</a></span><ul class=incremental><li><span><span class=toc-section-number>5.1.1</span> <a href=#background id=toc:background>Background</a></span><li><span><span class=toc-section-number>5.1.2</span> <a href=#rules-file-format id=toc:rules-file-format>Rules File\nFormat</a></span></ul></ul><li><span><span class=toc-section-number>6</span> <a href=#ch:changelogs id=toc:ch:changelogs>Changelogs</a></span><ul class=incremental><li><span><span class=toc-section-number>6.1</span> <a href=#sec:v4.0.5-(445) id=toc:sec:v4.0.5-(445)>v4.0.5\n(445)</a></span><li><span><span class=toc-section-number>6.2</span> <a href=#sec:v4.0.4-(444) id=toc:sec:v4.0.4-(444)>v4.0.4\n(444)</a></span><li><span><span class=toc-section-number>6.3</span> <a href=#sec:v4.0.3-(443) id=toc:sec:v4.0.3-(443)>v4.0.3\n(443)</a></span><li><span><span class=toc-section-number>6.4</span> <a href=#sec:v4.0.2-(442) id=toc:sec:v4.0.2-(442)>v4.0.2\n(442)</a></span><li><span><span class=toc-section-number>6.5</span> <a href=#sec:v4.0.1-(441) id=toc:sec:v4.0.1-(441)>v4.0.1\n(441)</a></span><ul class=incremental><li><span><span class=toc-section-number>6.5.1</span> <a href=#overlay-management id=toc:overlay-management>Overlay\nmanagement</a></span><li><span><span class=toc-section-number>6.5.2</span> <a href=#unfreeze-option-in-activity-shortcuts id=toc:unfreeze-option-in-activity-shortcuts>Unfreeze option in\nactivity shortcuts</a></span><li><span><span class=toc-section-number>6.5.3</span> <a href=#market-like-url-support id=toc:market-like-url-support><code>market</code>-like URL\nsupport</a></span><li><span><span class=toc-section-number>6.5.4</span> <a href=#updated-color-codes id=toc:updated-color-codes>Updated color\ncodes</a></span><li><span><span class=toc-section-number>6.5.5</span> <a href=#others id=toc:others>Others</a></span></ul><li><span><span class=toc-section-number>6.6</span> <a href=#sec:v4.0.0-(440) id=toc:sec:v4.0.0-(440)>v4.0.0\n(440)</a></span><ul class=incremental><li><span><span class=toc-section-number>6.6.1</span> <a href=#new-logo id=toc:new-logo>New logo!</a></span><li><span><span class=toc-section-number>6.6.2</span> <a href=#android-14-and-15-support id=toc:android-14-and-15-support>Android 14 and 15\nsupport</a></span><li><span><span class=toc-section-number>6.6.3</span> <a href=#revamped-debloater id=toc:revamped-debloater>Revamped\ndebloater</a></span><li><span><span class=toc-section-number>6.6.4</span> <a href=#introducing-file-manager id=toc:introducing-file-manager>Introducing file\nmanager</a></span><li><span><span class=toc-section-number>6.6.5</span> <a href=#integrated-code-editor id=toc:integrated-code-editor>Integrated code editor</a></span><li><span><span class=toc-section-number>6.6.6</span> <a href=#history-of-operations id=toc:history-of-operations>History of\noperations</a></span><li><span><span class=toc-section-number>6.6.7</span> <a href=#per-app-freezing-and-more id=toc:per-app-freezing-and-more>Per-app freezing, and\nmore</a></span><li><span><span class=toc-section-number>6.6.8</span> <a href=#log-viewer-enhancements id=toc:log-viewer-enhancements>Log\nviewer enhancements</a></span><li><span><span class=toc-section-number>6.6.9</span> <a href=#launching-non-exported-activities id=toc:launching-non-exported-activities>Launching non-exported\nactivities</a></span><li><span><span class=toc-section-number>6.6.10</span> <a href=#new-tags-in-app-info-tab id=toc:new-tags-in-app-info-tab>New\ntags in App Info tab</a></span><li><span><span class=toc-section-number>6.6.11</span> <a href=#per-session-installer-options id=toc:per-session-installer-options>Per-session installer\noptions</a></span><li><span><span class=toc-section-number>6.6.12</span> <a href=#advanced-mode-of-operations-adb-enhancements id=toc:advanced-mode-of-operations-adb-enhancements>Advanced mode of\noperations, ADB enhancements, …</a></span><li><span><span class=toc-section-number>6.6.13</span> <a href=#data-usage-widget-and-more id=toc:data-usage-widget-and-more>Data usage widget, and\nmore</a></span><li><span><span class=toc-section-number>6.6.14</span> <a href=#others-1 id=toc:others-1>Others</a></span></ul><li><span><span class=toc-section-number>6.7</span> <a href=#sec:v3.1.0-(423) id=toc:sec:v3.1.0-(423)>v3.1.0\n(423)</a></span><ul class=incremental><li><span><span class=toc-section-number>6.7.1</span> <a href=#android-13-support id=toc:android-13-support>Android 13\nsupport</a></span><li><span><span class=toc-section-number>6.7.2</span> <a href=#introducing-freezeunfreeze id=toc:introducing-freezeunfreeze>Introducing\nfreeze/unfreeze</a></span><li><span><span class=toc-section-number>6.7.3</span> <a href=#export-app-list id=toc:export-app-list>Export app\nlist</a></span><li><span><span class=toc-section-number>6.7.4</span> <a href=#elliptic-curve-crypography-ecc id=toc:elliptic-curve-crypography-ecc>Elliptic Curve Crypography\n(ECC)</a></span><li><span><span class=toc-section-number>6.7.5</span> <a href=#new-languages id=toc:new-languages>New\nlanguages</a></span><li><span><span class=toc-section-number>6.7.6</span> <a href=#more-list-options id=toc:more-list-options>More list\noptions</a></span><li><span><span class=toc-section-number>6.7.7</span> <a href=#improved-handling-of-mode-of-operation id=toc:improved-handling-of-mode-of-operation>Improved handling of\nmode of operation</a></span><li><span><span class=toc-section-number>6.7.8</span> <a href=#handling-multiple-users id=toc:handling-multiple-users>Handling multiple users</a></span><li><span><span class=toc-section-number>6.7.9</span> <a href=#explorer-enhancements id=toc:explorer-enhancements>Explorer\nenhancements</a></span><li><span><span class=toc-section-number>6.7.10</span> <a href=#new-tag-wx id=toc:new-tag-wx>New tag: WX</a></span><li><span><span class=toc-section-number>6.7.11</span> <a href=#app-ops-management id=toc:app-ops-management>App ops\nmanagement</a></span><li><span><span class=toc-section-number>6.7.12</span> <a href=#batch-uninstallation id=toc:batch-uninstallation>Batch\nuninstallation</a></span><li><span><span class=toc-section-number>6.7.13</span> <a href=#running-apps id=toc:running-apps>Running apps</a></span><li><span><span class=toc-section-number>6.7.14</span> <a href=#interceptor id=toc:interceptor>Interceptor</a></span><li><span><span class=toc-section-number>6.7.15</span> <a href=#device-specific-changes id=toc:device-specific-changes>Device-specific changes</a></span><li><span><span class=toc-section-number>6.7.16</span> <a href=#others-2 id=toc:others-2>Others</a></span></ul><li><span><span class=toc-section-number>6.8</span> <a href=#sec:v3.0.0-(410) id=toc:sec:v3.0.0-(410)>v3.0.0\n(410)</a></span><ul class=incremental><li><span><span class=toc-section-number>6.8.1</span> <a href=#material-3-and-more id=toc:material-3-and-more>Material 3 and\nMore</a></span><li><span><span class=toc-section-number>6.8.2</span> <a href=#wireless-debugging id=toc:wireless-debugging>Wireless\nDebugging</a></span><li><span><span class=toc-section-number>6.8.3</span> <a href=#languages id=toc:languages>Languages</a></span><li><span><span class=toc-section-number>6.8.4</span> <a href=#introducing-app-explorer id=toc:introducing-app-explorer>Introducing App\nExplorer</a></span><li><span><span class=toc-section-number>6.8.5</span> <a href=#import-backups-from-other-applications id=toc:import-backups-from-other-applications>Import Backups from\nOther Applications</a></span><li><span><span class=toc-section-number>6.8.6</span> <a href=#virustotal id=toc:virustotal>VirusTotal</a></span><li><span><span class=toc-section-number>6.8.7</span> <a href=#trigger-profiles-from-the-automation-software id=toc:trigger-profiles-from-the-automation-software>Trigger Profiles\nfrom the Automation Software</a></span><li><span><span class=toc-section-number>6.8.8</span> <a href=#improved-application-installer id=toc:improved-application-installer>Improved Application\nInstaller</a></span><li><span><span class=toc-section-number>6.8.9</span> <a href=#component-blocking id=toc:component-blocking>Component\nBlocking</a></span><li><span><span class=toc-section-number>6.8.10</span> <a href=#advanced-searching id=toc:advanced-searching>Advanced\nSearching</a></span><li><span><span class=toc-section-number>6.8.11</span> <a href=#shared-libraries id=toc:shared-libraries>Shared\nLibraries</a></span><li><span><span class=toc-section-number>6.8.12</span> <a href=#make-the-best-use-of-interceptor id=toc:make-the-best-use-of-interceptor>Make the Best Use of\nInterceptor</a></span><li><span><span class=toc-section-number>6.8.13</span> <a href=#widget-screen-time id=toc:widget-screen-time>Widget: Screen\nTime</a></span><li><span><span class=toc-section-number>6.8.14</span> <a href=#widget-clear-cache id=toc:widget-clear-cache>Widget: Clear\nCache</a></span></ul><li><span><span class=toc-section-number>6.9</span> <a href=#sec:v2.6.0-(385) id=toc:sec:v2.6.0-(385)>v2.6.0\n(385)</a></span><ul class=incremental><li><span><span class=toc-section-number>6.9.1</span> <a href=#introducing-backups id=toc:introducing-backups>Introducing\nBackups</a></span><li><span><span class=toc-section-number>6.9.2</span> <a href=#introducing-log-viewer id=toc:introducing-log-viewer>Introducing Log Viewer</a></span><li><span><span class=toc-section-number>6.9.3</span> <a href=#lock-app-manager id=toc:lock-app-manager>Lock App\nManager</a></span><li><span><span class=toc-section-number>6.9.4</span> <a href=#extended-modes-for-app-ops id=toc:extended-modes-for-app-ops>Extended Modes for App\nOps</a></span><li><span><span class=toc-section-number>6.9.5</span> <a href=#new-batch-ops-add-to-profile id=toc:new-batch-ops-add-to-profile>New Batch Ops: Add to\nProfile</a></span><li><span><span class=toc-section-number>6.9.6</span> <a href=#app-info-improved id=toc:app-info-improved>App Info:\nImproved</a></span><li><span><span class=toc-section-number>6.9.7</span> <a href=#advanced-sort-and-filtering-options-in-the-main-page id=toc:advanced-sort-and-filtering-options-in-the-main-page>Advanced\nSort and Filtering Options in the Main Page</a></span><li><span><span class=toc-section-number>6.9.8</span> <a href=#about-this-device id=toc:about-this-device>About This\nDevice</a></span><li><span><span class=toc-section-number>6.9.9</span> <a href=#enabledisable-features id=toc:enabledisable-features>Enable/disable Features</a></span><li><span><span class=toc-section-number>6.9.10</span> <a href=#new-languages-1 id=toc:new-languages-1>New\nLanguages</a></span><li><span><span class=toc-section-number>6.9.11</span> <a href=#signing-the-apk-files id=toc:signing-the-apk-files>Signing the\nAPK Files</a></span><li><span><span class=toc-section-number>6.9.12</span> <a href=#new-extension-unapkm id=toc:new-extension-unapkm>New\nExtension: UnAPKM</a></span></ul><li><span><span class=toc-section-number>6.10</span> <a href=#sec:v2.5.20-(375) id=toc:sec:v2.5.20-(375)>v2.5.20\n(375)</a></span><ul class=incremental><li><span><span class=toc-section-number>6.10.1</span> <a href=#subsec:introducing-profiles id=toc:subsec:introducing-profiles>Introducing\nProfiles</a></span><li><span><span class=toc-section-number>6.10.2</span> <a href=#subsec:the-interceptor id=toc:subsec:the-interceptor>The\nInterceptor</a></span><li><span><span class=toc-section-number>6.10.3</span> <a href=#subsec:unapkm:-dedrm-the-apkm-files id=toc:subsec:unapkm:-dedrm-the-apkm-files>UnAPKM: DeDRM the APKM\nfiles</a></span><li><span><span class=toc-section-number>6.10.4</span> <a href=#subsec:multiple-user id=toc:subsec:multiple-user>Multiple\nuser</a></span><li><span><span class=toc-section-number>6.10.5</span> <a href=#vive-la-france id=toc:vive-la-france>Vive la\nFrance!</a></span><li><span><span class=toc-section-number>6.10.6</span> <a href=#report-crashes id=toc:report-crashes>Report\ncrashes</a></span><li><span><span class=toc-section-number>6.10.7</span> <a href=#android-11 id=toc:android-11>Android 11</a></span><li><span><span class=toc-section-number>6.10.8</span> <a href=#app-installer-improvements id=toc:app-installer-improvements>App Installer\nImprovements</a></span></ul><li><span><span class=toc-section-number>6.11</span> <a href=#v2.5.17-368 id=toc:v2.5.17-368>v2.5.17 (368)</a></span><ul class=incremental><li><span><span class=toc-section-number>6.11.1</span> <a href=#app-installer id=toc:app-installer>App\nInstaller</a></span><li><span><span class=toc-section-number>6.11.2</span> <a href=#scanner-replacement-for-exodus-page id=toc:scanner-replacement-for-exodus-page>Scanner: Replacement for\nExodus Page</a></span><li><span><span class=toc-section-number>6.11.3</span> <a href=#introducing-system-config id=toc:introducing-system-config>Introducing System\nConfig</a></span><li><span><span class=toc-section-number>6.11.4</span> <a href=#more-languages id=toc:more-languages>More\nLanguages</a></span><li><span><span class=toc-section-number>6.11.5</span> <a href=#app-info-tab id=toc:app-info-tab>App Info Tab</a></span><li><span><span class=toc-section-number>6.11.6</span> <a href=#navigation-improvements id=toc:navigation-improvements>Navigation Improvements</a></span><li><span><span class=toc-section-number>6.11.7</span> <a href=#running-apps-page id=toc:running-apps-page>Running Apps\nPage</a></span><li><span><span class=toc-section-number>6.11.8</span> <a href=#built-in-toybox id=toc:built-in-toybox>Built-in\nToybox</a></span><li><span><span class=toc-section-number>6.11.9</span> <a href=#component-blocker-improvements id=toc:component-blocker-improvements>Component Blocker\nImprovements</a></span><li><span><span class=toc-section-number>6.11.10</span> <a href=#improvements-in-the-app-details-page id=toc:improvements-in-the-app-details-page>Improvements in the App\nDetails Page</a></span><li><span><span class=toc-section-number>6.11.11</span> <a href=#app-manifest id=toc:app-manifest>App Manifest</a></span></ul><li><span><span class=toc-section-number>6.12</span> <a href=#v2.5.13-348 id=toc:v2.5.13-348>v2.5.13 (348)</a></span><ul class=incremental><li><span><span class=toc-section-number>6.12.1</span> <a href=#bundled-app-split-apk id=toc:bundled-app-split-apk>Bundled App\n(Split APK)</a></span><li><span><span class=toc-section-number>6.12.2</span> <a href=#direct-install-support id=toc:direct-install-support>Direct\nInstall Support</a></span><li><span><span class=toc-section-number>6.12.3</span> <a href=#remove-all-blocking-rules id=toc:remove-all-blocking-rules>Remove All Blocking\nRules</a></span><li><span><span class=toc-section-number>6.12.4</span> <a href=#app-ops-1 id=toc:app-ops-1>App Ops</a></span><li><span><span class=toc-section-number>6.12.5</span> <a href=#enhanced-adb-support id=toc:enhanced-adb-support>Enhanced ADB\nSupport</a></span><li><span><span class=toc-section-number>6.12.6</span> <a href=#filtering-in-main-page id=toc:filtering-in-main-page>Filtering\nin Main Page</a></span><li><span><span class=toc-section-number>6.12.7</span> <a href=#apk-backupsharing id=toc:apk-backupsharing>Apk\nBackup/Sharing</a></span><li><span><span class=toc-section-number>6.12.8</span> <a href=#batch-ops id=toc:batch-ops>Batch Ops</a></span><li><span><span class=toc-section-number>6.12.9</span> <a href=#translations id=toc:translations>Translations</a></span><li><span><span class=toc-section-number>6.12.10</span> <a href=#app-data-backup id=toc:app-data-backup>App Data\nBackup</a></span></ul></ul><li><span><span class=toc-section-number>7</span> <a href=#ch:app-ops id=toc:ch:app-ops>App Ops</a></span><ul class=incremental><li><span><span class=toc-section-number>7.1</span> <a href=#sec:app-ops-background id=toc:sec:app-ops-background>Background</a></span><li><span><span class=toc-section-number>7.2</span> <a href=#sec:introduction-to-app-ops id=toc:sec:introduction-to-app-ops>Introduction to App\nOps</a></span><li><span><span class=toc-section-number>7.3</span> <a href=#sec:appopsmanager id=toc:sec:appopsmanager>AppOpsManager</a></span><ul class=incremental><li><span><span class=toc-section-number>7.3.1</span> <a href=#subsec:op-constants id=toc:subsec:op-constants><code>OP_*</code> Constants</a></span><li><span><span class=toc-section-number>7.3.2</span> <a href=#subsec:mode-constants id=toc:subsec:mode-constants><code>MODE_*</code>\nConstants</a></span><li><span><span class=toc-section-number>7.3.3</span> <a href=#subsec:package-ops id=toc:subsec:package-ops>PackageOps</a></span><li><span><span class=toc-section-number>7.3.4</span> <a href=#subsec:opentry id=toc:subsec:opentry>OpEntry</a></span><li><span><span class=toc-section-number>7.3.5</span> <a href=#subsec:usage id=toc:subsec:usage>Usage</a></span></ul><li><span><span class=toc-section-number>7.4</span> <a href=#sec:appopsservice id=toc:sec:appopsservice>AppOpsService</a></span><li><span><span class=toc-section-number>7.5</span> <a href=#sec:appops-xml id=toc:sec:appops-xml>appops.xml</a></span><li><span><span class=toc-section-number>7.6</span> <a href=#sec:appops-cli id=toc:sec:appops-cli>Command Line\nInterface</a></span></ul></ul></nav><div class=titlingpage><div class=center><p><img src=../images/icon.png style=width:1in alt=image><p><strong><span class=smallcaps>App Manager</span></strong><p><strong>Manuel Utilisateur</strong><p><em>v4.0.5</em><p>27 juillet 2025<p>Copyright © 2020–2025 Muntashir Al-Islam<blockquote><p>“Wisely and slow. They stumble that run fast.” <span>— Friar\nLaurence, <em>Romeo and Juliet</em></span></blockquote></div></div><section id=ch:introduction class=level1 data-number=1><h1 data-number=1><span class=header-section-number>1</span> <a href=#toc:ch:introduction>Introduction</a><a href=#ch:introduction class=anchor aria-hidden=true></a></h1><p>App Manager est un gestionnaire avancé de packets pour Android. Il\noffre un multitude de fonctionnalités, et par conséquent, requiert un\nmanuel utilisateur pour aider ses utilisateurs. Ce document fait office\nde manuel utilisateur pour App Manage, au sens qu’il s’efforce de\ndécrire chaque fonctionnalité qu’App Manager a à offrir. Ce document\npeut aussi être considéré comme directives officielles pour App Manager,\net représente le comportement attendu de App Manager. Les traductions\npeuvent mésinterpréter ce document (qui est écrite en anglais). C’est\npourquoi tout utilisateur capable de le faire, devrait lire la version\nanglaise du document pour tirer le meilleur de App Manager. Il pourrait\ny avoir d’autres ressources tierces ou non-officielles telles que des\narticles de blogs, vidéos, groupes de discussion, etc. Bien que ces\nressources puissent être utiles pour certains, elles pourraient ne pas\nêtre à jour avec la version actuelle de App Manager. S’il y a des\ndifferences entre App Manager et ce document, elles devraient être\nsignalées sur <a href=https://github.com/MuntashirAkon/AppManager/issues>App Manager\nissue tracker</a>.<section id=sec:terminologies class=level2 data-number=1.1><h2 data-number=1.1><span class=header-section-number>1.1</span> <a href=#toc:sec:terminologies>Terminologies</a><a href=#sec:terminologies class=anchor aria-hidden=true></a></h2><ul class=incremental><li><p><strong>AM</strong> — Short name for App Manager.<li><p><strong>Block/Unblock</strong> — Used for component blocking or\nunblocking. How components are blocked depends on the user\npreferences.<li><p><strong>IFW</strong> — Short form of Intent Firewall.<li><p><strong>Ops</strong> — Short name for operations, e.g. app ops,\nbatch ops, 1-click ops<li><p><strong>SAF</strong> — Short for Storage Access Framework, an\nabstraction used by Android to allow apps to use or serve files without\nworrying about the underlying file system.<li><p><strong>SSAID</strong> — Short form of\n<code>Settings.Secure.ANDROID_ID</code>. It is a device identifier\nassigned to each app (Android Oreo onwards). It is generated from the\ncombination of the signing certificate of the app and the SSAID set for\nthe package <code>android</code>. As a result, it is guaranteed to be\nthe same for an app unless the user chooses to format the device. It is\nwidely used for tracking.<li><p><strong>Tracker</strong> — Denotes tracker components throughout\nthe document and in App Manager except in the <a href=#sec:scanner-page>scanner page</a>. Trackers include libraries\nsuch as crash reporters, analytics, profiling, identification, ad,\nlocation, etc. Thus, they are not equal in functions. There is no\ndistinction or bias among the open-source and closed-source libraries\nthat promote tracking.</ul></section><section id=sec:supported-versions class=level2 data-number=1.2><h2 data-number=1.2><span class=header-section-number>1.2</span> <a href=#toc:sec:supported-versions>Versions Supportées</a><a href=#sec:supported-versions class=anchor aria-hidden=true></a></h2><p>Actuellement, les versions maintenues sont v2.6.0 (stable), v3.0.0\n(versions alpha et debug). Les versions précédentes de App Manager\npourraient contenir des vulnérabilités et ne devraient pas être\nutilisées.</section><section id=sec:official-sources class=level2 data-number=1.3><h2 data-number=1.3><span class=header-section-number>1.3</span> <a href=#toc:sec:official-sources>Sources Officielles</a><a href=#sec:official-sources class=anchor aria-hidden=true></a></h2><section id=subsec:binary-distribution-sources class=level3 data-number=1.3.1><h3 data-number=1.3.1><span class=header-section-number>1.3.1</span>\n<a href=#toc:subsec:binary-distribution-sources>Sources de\ndistribution de binaires</a><a href=#subsec:binary-distribution-sources class=anchor aria-hidden=true></a></h3><p>App Manager is distributed using the following sources. Unofficial\nsources may distribute modified versions of App Manager, and you alone\nshall be responsible for the consequences of using such a\ndistribution.<ol class=incremental><li><p>Official F-Droid repository.<a href=#fn1 class=footnote-ref id=fnref1 role=doc-noteref><sup>1</sup></a><br><em>Link:</em> <a href=https://f-droid.org/packages/io.github.muntashirakon.AppManager class=uri>https://f-droid.org/packages/io.github.muntashirakon.AppManager</a><li><p>GitHub repository.<br><em>Normal releases:</em> <a href=https://github.com/MuntashirAkon/AppManager/releases class=uri>https://github.com/MuntashirAkon/AppManager/releases</a><br><em>Debug releases:</em> <a href=https://github.com/MuntashirAkon/AMInsecureDebugBuilds class=uri>https://github.com/MuntashirAkon/AMInsecureDebugBuilds</a><li><p>Telegram.<br><em>Normal releases:</em> <a href=https://t.me/AppManagerChannel class=uri>https://t.me/AppManagerChannel</a><br><em>Debug releases:</em> <a href=https://t.me/AppManagerDebug class=uri>https://t.me/AppManagerDebug</a></ol></section><section id=subsec:links-to-source-code class=level3 data-number=1.3.2><h3 data-number=1.3.2><span class=header-section-number>1.3.2</span>\n<a href=#toc:subsec:links-to-source-code>Liens vers code source</a><a href=#subsec:links-to-source-code class=anchor aria-hidden=true></a></h3><p>Tous sauf GitHub sont des liens miroirs. Les étiquettes devraient\ntoujours être à jour, mais la branche master n’est pas garantie d’être à\njour. Si le but est de cloner la branche master, utilisez le lien GitHub\nplutôt que les autres.<ol class=incremental><li><p>GitHub: <a href=https://github.com/MuntashirAkon/AppManager class=uri>https://github.com/MuntashirAkon/AppManager</a><li><p>Codeberg: <a href=https://codeberg.org/muntashir/AppManager class=uri>https://codeberg.org/muntashir/AppManager</a><li><p>GitLab: <a href=https://gitlab.com/muntashir/AppManager class=uri>https://gitlab.com/muntashir/AppManager</a><li><p>Riseup: <a href=https://0xacab.org/muntashir/AppManager class=uri>https://0xacab.org/muntashir/AppManager</a><li><p>sourcehut: <a href=https://git.sr.ht/~muntashir/AppManager class=uri>https://git.sr.ht/~muntashir/AppManager</a></ol></section><section id=subsec:translations class=level3 data-number=1.3.3><h3 data-number=1.3.3><span class=header-section-number>1.3.3</span>\n<a href=#toc:subsec:translations>Traductions</a><a href=#subsec:translations class=anchor aria-hidden=true></a></h3><p>App Manager n’accepte pas des traductions directement via des\nrequêtes pull/merge. Les traductions sont automatiquement merge via\nWeblate. Pour rejoindre l’équipe de traduction, allez sur <a href=https://hosted.weblate.org/engage/app-manager/ class=uri>https://hosted.weblate.org/engage/app-manager/</a>.</section></section><section id=sec:contributing class=level2 data-number=1.4><h2 data-number=1.4><span class=header-section-number>1.4</span> <a href=#toc:sec:contributing>Contribuer</a><a href=#sec:contributing class=anchor aria-hidden=true></a></h2><p>Il y a plusieurs possibilités pour un utilisateur de contribuer,\ncomme poser des questions utiles, participer aux discussions, améliorer\nla documentation et les traductions, ajouter des librairies ou des\ntrackers non reconnus, examiner le code source ainsi que signaler des\nvulnérabilités de sécurité.<section id=subsec:build-instructions class=level3 data-number=1.4.1><h3 data-number=1.4.1><span class=header-section-number>1.4.1</span>\n<a href=#toc:subsec:build-instructions>Instructions de build</a><a href=#subsec:build-instructions class=anchor aria-hidden=true></a></h3><p>Des instructions de build sont disponibles dans le fichier BUILDING\nsitué à la racine du code source.</section><section id=subsec:submitting-patches class=level3 data-number=1.4.2><h3 data-number=1.4.2><span class=header-section-number>1.4.2</span>\n<a href=#toc:subsec:submitting-patches>Soumettre des patchs</a><a href=#subsec:submitting-patches class=anchor aria-hidden=true></a></h3><p>Repositories located on sites other than GitHub are currently\nconsidered mirrors, and pull/merge requests submitted on those sites\nwill not be accepted.<a href=#fn2 class=footnote-ref id=fnref2 role=doc-noteref><sup>2</sup></a> Instead, patches (as\n<code>.patch</code> files) can be submitted via email attachments.\n<em>Signing-off is a requirement.</em> See the CONTRIBUTING file located\nat the source root for more information.<div class=\"amalert warning\"><p><strong><em>Notice :</em></strong><p>In the case of submitting patches via email, the whole conversation\nmay be publicly accessible in the future. So, please do not include\npersonally identifiable information (PII) other than your name or email\naddress.</div></section></section><section id=sec:donation-&-funding class=level2 data-number=1.5><h2 data-number=1.5><span class=header-section-number>1.5</span> <a href=#toc:sec:donation-&-funding>Dons et Financement</a><a href=#sec:donation-&-funding class=anchor aria-hidden=true></a></h2><p>As of September 2024, App Manager is not accepting financial support\nuntil further notice. But you may still be able to send gifts (e.g.,\ngift cards, subscriptions, food and drink, flowers, or even cash).\nPlease reach out to the maintainer using the options given in §<a href=#sec:contact data-reference-type=ref data-reference=sec:contact>1.6</a> for further assistance.<p>In addition, the maintainers and contributors of this project DO NOT\nconsent to the creation, sale, or promotion of tokens, cryptocurrencies,\nNFTs, or any other financial instruments that claim to represent this\nproject, its code, or its community. Any such attempts are unauthorized\nand not affiliated with this project in any way.</section><section id=sec:contact class=level2 data-number=1.6><h2 data-number=1.6><span class=header-section-number>1.6</span> <a href=#toc:sec:contact>Contact</a><a href=#sec:contact class=anchor aria-hidden=true></a></h2><p>App Manager Community<br>Email: <a href=mailto:am4android@riseup.net>am4android [at] riseup\n[dot] net</a><br>GitHub: <a href=https://github.com/AMCommunity class=uri>https://github.com/AMCommunity</a><br>Twitter/X: <a href=https://x.com/AppManagerNews class=uri>https://x.com/AppManagerNews</a><br>Mastodon: <a href=https://floss.social/@appmanager>@appmanager@floss.social</a><br><br>Muntashir Al-Islam<a href=#fn3 class=footnote-ref id=fnref3 role=doc-noteref><sup>3</sup></a><br>Email: <a href=mailto:muntashirakon@riseup.net>muntashirakon [at]\nriseup [dot] net</a><br>GitHub: <a href=https://github.com/MuntashirAkon class=uri>https://github.com/MuntashirAkon</a><br>Twitter/X: <a href=https://x.com/Muntashir class=uri>https://x.com/Muntashir</a><br>Mastodon: <a href=https://infosec.exchange/@muntashir>@muntashir@infosec.exchange</a></section></section><section id=ch:pages class=level1 data-number=2><h1 data-number=2><span class=header-section-number>2</span> <a href=#toc:ch:pages>Pages</a><a href=#ch:pages class=anchor aria-hidden=true></a></h1><section id=sec:main-page class=level2 data-number=2.1><h2 data-number=2.1><span class=header-section-number>2.1</span> <a href=#toc:sec:main-page>Main Page</a><a href=#sec:main-page class=anchor aria-hidden=true></a></h2><p>Main page lists all the installed, uninstalled and backed up\napplications. A single click on any installed application item opens the\nrespective <a href=#sec:app-details-page>App Details page</a>. For the\nuninstalled system applications, a dialog prompt is displayed with an\noption reinstall them. The applications uninstalled without removing\ntheir data and signatures are also displayed in this page with an option\nto perform a full uninstallation. For the uninstalled applications\nhaving one or more backups, the restore dialog is displayed. Using the\n<a href=#par:main-page-sort>sort</a> option from the list options, the\nitems can be sorted in various ways. It is also possible to filter items\nusing the <a href=#par:main-page-filter>filter</a> option in the list\noptions. Filtering is also possible from the search bar with additional\nsupport for the regular expressions.<figure id=fig:main_page_entry_info_labeled><figure><object data=../images/main_page_entry_info_labeled.svg type=image/svg+xml></object></figure><figcaption>Figure 1: An application list item in the main\npage</figcaption></figure><section id=subsec:batch-operations class=level3 data-number=2.1.1><h3 data-number=2.1.1><span class=header-section-number>2.1.1</span>\n<a href=#toc:subsec:batch-operations>Batch Operations</a><a href=#subsec:batch-operations class=anchor aria-hidden=true></a></h3><p>Batch operations or operations on multiple applications are also\navailable within this page. Multiple selection mode can be activated by\nclicking on the app icon of an item or by long-clicking on any items in\nthe list. Once activated, a click on an item selects it instead of\nopening the App Details page. In this mode, the batch operations are\nlocated in the multiple selection menu at the bottom of the page. The\noperations include:<ul class=incremental><li><p>Adding the selected applications to a <a href=#sec:profiles-page>profile</a><li><p><a href=#sec:backup-restore>Backing up applications</a>, or\nrestoring and deleting the existing backups<li><p>Blocking the trackers from the applications<li><p>Clearing data or cache from the applications<li><p>Exporting the blocking rules configured inside App\nManager<li><p>Exporting the list of applications in Markdown, CSV, JSON or XML\nformat<li><p>Freezing/unfreezing/force-stopping/uninstalling the\napplications<li><p>Performing run-time optimization of the applications (Android 7\nonwards)<li><p>Preventing the background operations of the applications (Android\n7 onwards)<li><p>Saving the APK files to <code>AppManager/apks</code><li><p>Setting <a href=#sec:net-policy>net policies</a></ul><div class=\"amalert tip\"><p><strong><em>Accessibility :</em></strong><p>After the multiple selection mode has been activated, it is possible\nto navigate in or out of the multiple selection menu using the right or\nleft keys of the keyboard or remote.</div></section><section id=subsec:main-colour-codes class=level3 data-number=2.1.2><h3 data-number=2.1.2><span class=header-section-number>2.1.2</span>\n<a href=#toc:subsec:main-colour-codes>Colour Codes</a><a href=#subsec:main-colour-codes class=anchor aria-hidden=true></a></h3><ul class=incremental><li><p><span class=colorbox style=background-color:#ff0000b3><span style=color:#000>Red (day)</span></span> / <span class=colorbox style=background-color:#790d0d><span style=color:#fff>dark red (night)</span></span> – Uninstalled\napplication<li><p><span class=colorbox style=background-color:#ff8a80><span style=color:#000>Light red (day)</span></span> / <span class=colorbox style=background-color:#4f1c14bf><span style=color:#fff>very\ndark red (night)</span></span> – Frozen application<li><p><span class=colorbox style=background-color:#09868b><span style=color:#fff>Dark cyan</span></span> – Force-stopped\napplication<li><p><span class=colorbox style=background-color:#ff0><span style=color:#000>Yellow Star</span></span> – Debuggable\napplication<li><p><span style=color:#e05915>Orange <em>Date</em></span> – The\napplication can read system logs<li><p><span style=color:#e05915>Orange <em>UID</em></span> – The\nuser ID is being shared among multiple applications<li><p><span style=color:#e05915>Orange <em>SDK</em></span> – The\napplication possibly uses cleartext (i.e. HTTP) traffic<li><p><span style=color:#ff8017>Light orange <em>package\nname</em></span> – The application has one or more trackers<li><p><span style=color:red>Red <em>app label</em></span> – The\napplication does not allow clearing its data<li><p><span style=color:#09868b>Dark cyan <em>version</em></span>\n– Inactive application<li><p><span style=color:#f0f>Magenta type</span> – Persistent\napplication i.e. it remains running all the time<li><p><span style=color:red>Red <em>backup</em></span> – The\nuninstalled application with one or more backups present in App\nManager<li><p><span style=color:#e05915>Orange <em>backup</em></span> –\nOutdated backup, i.e. the base backup contains an older version of the\ninstalled application<li><p><span style=color:#09868b>Dark cyan <em>backup</em></span>\n– Up to date backup, i.e. the base backup contains the same or higher\nversion of the installed application.</ul></section><section id=subsec:main-page-application-types class=level3 data-number=2.1.3><h3 data-number=2.1.3><span class=header-section-number>2.1.3</span>\n<a href=#toc:subsec:main-page-application-types>Application\nTypes</a><a href=#subsec:main-page-application-types class=anchor aria-hidden=true></a></h3><p>An application can be either a <strong>User</strong> or a\n<strong>System</strong> application along with the following\nsuffixes:<ul class=incremental><li><p><code>X</code> – Supports multiple architectures<li><p><code>0</code> – No dex files present in the application<li><p><code>°</code> – Suspended application<li><p><code>#</code> – The application requested the system to allocate\na large heap i.e. large runtime memory<li><p><code>?</code> – The application requested the virtual machine to\nbe in the safe mode.</ul></section><section id=subsec:main-page-version-info class=level3 data-number=2.1.4><h3 data-number=2.1.4><span class=header-section-number>2.1.4</span>\n<a href=#toc:subsec:main-page-version-info>Version Info</a><a href=#subsec:main-page-version-info class=anchor aria-hidden=true></a></h3><p>Version name is followed by the prefixes below:<ul class=incremental><li><p><code>_</code> – No hardware acceleration (breaking the in-app\nanimations or transparencies)<li><p><code>~</code> – Test-only application<li><p><code>debug</code> – Debuggable application</ul></section><section id=subsec:main-page-options-menu class=level3 data-number=2.1.5><h3 data-number=2.1.5><span class=header-section-number>2.1.5</span>\n<a href=#toc:subsec:main-page-options-menu>Options Menu</a><a href=#subsec:main-page-options-menu class=anchor aria-hidden=true></a></h3><p>Options menu offers several options that can be used to sort and\nfilter the listed applications as well as to navigate to different pages\nwithin or outside App Manager.<section id=subsubsec:main-list-options class=level4 data-number=2.1.5.1><h4 data-number=2.1.5.1><span class=header-section-number>2.1.5.1</span> List Options<a href=#subsubsec:main-list-options class=anchor aria-hidden=true></a></h4><p><strong>List options</strong> contain the options to sort and filter\nthe list in the main page.<section id=sort class=level5 data-number=2.1.5.1.1><h5 data-number=2.1.5.1.1><span class=header-section-number>2.1.5.1.1</span> Sort<a href=#sort class=anchor aria-hidden=true></a></h5><div id=par:main-page-sort></div><p>The applications listed in the main page can be sorted in the\nfollowing ways:<ul class=incremental><li><p><strong>User apps first.</strong> The user applications are\nlisted on top<li><p><strong>App label.</strong> Sort the list in ascending order\nbased on their application labels (also known as <em>application\nnames</em>). This is the default sorting preference<li><p><strong>Package name.</strong> Sort the list in ascending order\nbased on their package names<li><p><strong>Last update.</strong> Sort the list in descending order\nbased on the date they were last updated<li><p><strong>Shared user ID.</strong> Sort the list in descending\norder based on their kernel user ID<li><p><strong>Target SDK.</strong> Sort the list in ascending order\nbased on their target SDK<li><p><strong>Signature.</strong> Sort the list in ascending order\nbased on their signing information<li><p><strong>Frozen first.</strong> The frozen applications are listed\non the top<li><p><strong>Blocked first.</strong> Sort the list in descending order\nbased on the number of blocked components each application has<li><p><strong>Backed up first.</strong> Display the applications with\nbackups on the top<li><p><strong>Trackers.</strong> Sort the list in descending order\nbased on the number of tracker components each application has<li><p><strong>Last actions.</strong> Sort the list in descending order\nbased on the latest time and date of any actions made to the\napplications within App Manager.<li><p><strong>Installation date.</strong> Sort the list by the date of\ninstallation in descending order.<li><p><strong>Total size.</strong> Sort the list by the total size of\nthe applications and their data in descending order. Requires\n<code>Usage Access</code> permission.<li><p><strong>Data usage.</strong> Sort the list by the total data\nusage in descending order. Requires <code>Usage Access</code>\npermission.<li><p><strong>Times opened.</strong> List frequently used applications\non top. Requires <code>Usage Access</code> permission.<li><p><strong>Screen time.</strong> List the applications with the\nhighest engagements on top. Requires <code>Usage Access</code>\npermission.<li><p><strong>Last used.</strong> List last used apps on top. Requires\n<code>Usage Access</code> permission.</ul><p>In addition, there is the <em>reverse</em> option that can be used to\nsort the list in the reverse order. Regardless of the sorting\npreferences, the applications are sorted alphabetically at first in\norder to prevent producing any random sorting results.</section><section id=filter class=level5 data-number=2.1.5.1.2><h5 data-number=2.1.5.1.2><span class=header-section-number>2.1.5.1.2</span> Filter<a href=#filter class=anchor aria-hidden=true></a></h5><div id=par:main-page-filter></div><p>The applications listed in the main page can be filtered in the\nfollowing ways:<ul class=incremental><li><p><strong>User apps.</strong> List only the user\napplications<li><p><strong>System apps.</strong> List only the system\napplications<li><p><strong>Frozen apps.</strong> List only the frozen\napplications<li><p><strong>Stopped apps.</strong> List only the applications that\nwere forced-stopped<li><p><strong>Installed apps.</strong> List only the installed\napplications<li><p><strong>Uninstalled apps.</strong> List only the uninstalled\napplications<li><p><strong>With rules.</strong> List the applications with one or\nmore blocking rules<li><p><strong>With activities.</strong> List the applications with one\nor more activities<li><p><strong>With backups.</strong> List the applications with one or\nmore backups<li><p><strong>Without backups.</strong> List the applications with no\nbackups present.<li><p><strong>Running apps.</strong> List the applications that are\ncurrently running<li><p><strong>With splits.</strong> List the applications with one or\nmore split APK files<li><p><strong>With KeyStore.</strong> List only the applications with\nAndroid KeyStore.<li><p><strong>With SAF.</strong> List only the applications with SAF\naccess.<li><p><strong>With SSAID.</strong> List only the applications with a\nvalid SSAID.</ul><p>Unlike sorting, it is possible to apply more than one filtering\noptions at the same time. For example, the frozen user applications can\nbe listed by selecting both <em>User apps</em> and <em>Frozen apps</em>.\nThis can be particularly useful for <a href=#subsec:batch-operations>batch operations</a> where filtering the\nuser applications may be necessary to carry out certain operations\nsafely.<div class=\"amalert warning\"><p><strong><em>Inconsistencies :</em></strong><p>App Manager extensively caches everything in this page. Therefore,\ncertain states (e.g., freeze and stopped states) may not always be\nup-to-date.</div></section><section id=profile-name class=level5 data-number=2.1.5.1.3><h5 data-number=2.1.5.1.3><span class=header-section-number>2.1.5.1.3</span> Profile Name<a href=#profile-name class=anchor aria-hidden=true></a></h5><p>It is also possible to list the applications that are only present in\na <a href=#sec:profiles-page>profile</a>. This can be useful for\ncarrying out certain operations on a profile (e.g., uninstalling all the\napplications in a profile) that cannot be done via the <a href=#sec:profiles-page>Profiles page</a>.</section></section><section id=user-manual class=level4 data-number=2.1.5.2><h4 data-number=2.1.5.2><span class=header-section-number>2.1.5.2</span> User Manual<a href=#user-manual class=anchor aria-hidden=true></a></h4><p>Clicking on the <strong>User manual</strong> opens the offline\nversion of the App Manager user manual. It may also open the online\nversion if the corresponding feature split i.e. <code>feat_docs</code>\nis not installed, or if an WebView is not present in the system to load\nthe manual.</section><section id=subsubsec:main:1-click-ops class=level4 data-number=2.1.5.3><h4 data-number=2.1.5.3><span class=header-section-number>2.1.5.3</span> 1-Click Ops<a href=#subsubsec:main:1-click-ops class=anchor aria-hidden=true></a></h4><p><strong>1-Click Ops</strong> stands for the single-click operations.\nIt opens the <a href=#sec:1-click-ops-page>corresponding page</a> in a\nnew activity.</section><section id=app-usage class=level4 data-number=2.1.5.4><h4 data-number=2.1.5.4><span class=header-section-number>2.1.5.4</span> App Usage<a href=#app-usage class=anchor aria-hidden=true></a></h4><p>Application usage statistics, such as <em>screen time</em>, <em>data\nusage</em> (both mobile and Wi-Fi), <em>number of times an app was\nopened</em>, can be accessed by clicking on the <strong>App\nUsage</strong> option in the menu. However, it requires the <em>Usage\nAccess</em> permission. This menu item will not be listed if the usage\naccess feature is disabled in <a href=#subsubsec:enable/disable-features>settings</a>.</section><section id=subsubsec:main:running-apps class=level4 data-number=2.1.5.5><h4 data-number=2.1.5.5><span class=header-section-number>2.1.5.5</span> Running Apps<a href=#subsubsec:main:running-apps class=anchor aria-hidden=true></a></h4><p>This menu item opens a new page where a list of running applications\nor processes are displayed. It also displays the current memory and\ncache (if available) usage. If root or ADB is not available to App\nManager, it only displays itself in the recent versions of Android. The\nrunning applications or processes can also be force-stopped or killed\nwithin the resultant page. Logs for each process ID (PID) can also be\nviewed in the <a href=#subsubsec:main:labs>log viewer</a>. In\naddition, it is also possible to carry out batch operations either by\nclicking on the icon or by long-clicking on an item. Normal click on any\nitems opens a dialog where a more detailed information is displayed.</section><section id=profiles class=level4 data-number=2.1.5.6><h4 data-number=2.1.5.6><span class=header-section-number>2.1.5.6</span> Profiles<a href=#profiles class=anchor aria-hidden=true></a></h4><p>This menu item opens the <a href=#sec:profiles-page>profiles\npage</a>. Profiles are a way to configure regularly used tasks. They can\nalso be invoked via shortcuts.</section><section id=apk-updater class=level4 data-number=2.1.5.7><h4 data-number=2.1.5.7><span class=header-section-number>2.1.5.7</span> APK Updater<a href=#apk-updater class=anchor aria-hidden=true></a></h4><p>If the app <a href=https://github.com/rumboalla/apkupdater>APK\nUpdater</a> is installed in the system, it can be opened directly via\nthis menu item. The option remains hidden if the app is not present in\nthe system.</section><section id=termux class=level4 data-number=2.1.5.8><h4 data-number=2.1.5.8><span class=header-section-number>2.1.5.8</span> Termux<a href=#termux class=anchor aria-hidden=true></a></h4><p>If the app <a href=https://github.com/termux/termux-app>Termux</a>\nis installed in the system, the running session (or a new session) can\nbe opened directly via this menu item. The option remains hidden if the\napp is not present in the system.</section><section id=debloater class=level4 data-number=2.1.5.9><h4 data-number=2.1.5.9><span class=header-section-number>2.1.5.9</span> Debloater<a href=#debloater class=anchor aria-hidden=true></a></h4><p>This menu item opens the debloater page that lists all the bloatware\navailable in the device and in App Manager. It also suggests alternative\napplications based on the criteria set by the <a href=https://github.com/MuntashirAkon/android-debloat-list>Android\nDebloat List</a> project.</section><section id=subsubsec:main:labs class=level4 data-number=2.1.5.10><h4 data-number=2.1.5.10><span class=header-section-number>2.1.5.10</span> Labs<a href=#subsubsec:main:labs class=anchor aria-hidden=true></a></h4><p>This menu item opens the labs page that lists all the additional\nfeatures. They include Log Viewer, System Config, Terminal, File Manager\n(as Files), UI Tracker, Interceptor, and Code Editor pages.</section><section id=settings class=level4 data-number=2.1.5.11><h4 data-number=2.1.5.11><span class=header-section-number>2.1.5.11</span> Settings<a href=#settings class=anchor aria-hidden=true></a></h4><p>This menu item opens the in-app <a href=#sec:settings-page>Settings\npage</a>.</section></section></section><section id=sec:app-details-page class=level2 data-number=2.2><h2 data-number=2.2><span class=header-section-number>2.2</span> <a href=#toc:sec:app-details-page>App Details Page</a><a href=#sec:app-details-page class=anchor aria-hidden=true></a></h2><p><strong>App Details</strong> page consists of 11 (eleven) tabs. It\ndescribes almost every bit of information an application usually has,\nincluding all attributes from its manifest, <a href=#ch:app-ops>application operations</a> (app ops), signing\ninformation, libraries, and so on.<section id=subsec:app-details-colour-codes class=level3 data-number=2.2.1><h3 data-number=2.2.1><span class=header-section-number>2.2.1</span>\n<a href=#toc:subsec:app-details-colour-codes>Colour Codes</a><a href=#subsec:app-details-colour-codes class=anchor aria-hidden=true></a></h3><p>List of colours used in this page, and their meaning:<ul class=incremental><li><p><span class=colorbox style=background-color:#ff0000b3><span style=color:#000>Red (day)</span></span> / <span class=colorbox style=background-color:#790d0d><span style=color:#fff>dark red (night)</span></span> – Denotes any app\nops or permissions having the dangerous flag, or any components blocked\nwithin App Manager, or any unsupported but required features.<li><p><span class=colorbox style=background-color:#ff8a80><span style=color:#000>Light red (day)</span></span> / <span class=colorbox style=background-color:#4f1c14bf><span style=color:#fff>very\ndark red (night)</span></span> – Denotes the components disabled outside\nof App Manager, or any unsupported but optional features.<div class=\"amalert tip\"><p><strong><em>Note :</em></strong><p>A component marked as disabled does not always mean that it is\ndisabled by the user: It could also be disabled by the system or marked\nas disabled in its manifest. The components of a disabled application\nare also considered disabled by the system (and App Manager).</div><li><p><span class=colorbox style=background-color:#ff8017><span style=color:#000>Vivid orange (day)</span></span> / <span class=colorbox style=background-color:#ff801780><span style=color:#fff>very\ndark orange (night)</span></span> – Denotes the tracker\ncomponents<li><p><span class=colorbox style=background-color:#ea80fc><span style=color:#000>Soft magenta (day)</span></span> / <span class=colorbox style=background-color:#431c5d><span style=color:#fff>very dark violet (night)</span></span> – Denotes\nthe running services.<li><p><span class=colorbox style=background-color:#1b8654><span style=color:#fff>Green</span></span> – Used in the tracker-indicator\ntag to denote that all the trackers in the application are\nblocked.</ul></section><section id=subsec:app-info-tab class=level3 data-number=2.2.2><h3 data-number=2.2.2><span class=header-section-number>2.2.2</span>\n<a href=#toc:subsec:app-info-tab>App Info Tab</a><a href=#subsec:app-info-tab class=anchor aria-hidden=true></a></h3><p><strong>App Info</strong> tab contains general information about an\napplication. It also lists many actions that can be performed within\nthis tab.<section id=subsubsec:app-info-general-information class=level4 data-number=2.2.2.1><h4 data-number=2.2.2.1><span class=header-section-number>2.2.2.1</span> General Information<a href=#subsubsec:app-info-general-information class=anchor aria-hidden=true></a></h4><p>The list below is in the same order as listed in the App Info\ntab.<ul class=incremental><li><p><strong>Application Icon.</strong> The application icon. If the\napplication does not have an icon, the system default icon will be\ndisplayed. It is also possible to verify the APK signature via SHA or\nMD5 sums stored in the clipboard by simply clicking on it.<li><p><strong>Application Label.</strong> The application label or the\nname of the application.<li><p><strong>Package Name.</strong> The name of the application\npackage. Clicking on the name stores it in the clipboard.<li><p><strong>Version.</strong> The application version is divided into\ntwo parts. The first part is called <em>version name</em>. The format of\nthis part varies but often consists of multiple integers separated by\ndots. The second part is called <em>version code</em>. It is enclosed by\nthe first brackets. The version code is an integer used to differentiate\nbetween application versions (since a version name can be unreadable to\na machine). In general, a new version of an application has higher\nversion code than the old ones. For example, if <code>123</code> and\n<code>125</code> are two version codes of an application, we can say\nthat the latter is more updated than the former because the version code\nof the latter is higher. An application that serves different APK files\nfor the same version on different platforms (mobile, tabs, desktops,\netc.) or architectures (32/64 bit, ARM or Intel), the version numbers\ncan be misleading as they often add prefixes for each platform.<li><p><strong>Tags.</strong> (Also known as tag clouds) Tags include\nthe most basic, concise and useful information of an application. See\n§<a href=#subsubsec:tags data-reference-type=ref data-reference=subsubsec:tags>2.2.2.2</a> for a complete list of tags\nshown here.<li><p><strong>Horizontal Action Panel.</strong> An action panel\nconsisting of various actions that can be carried out for the\napplication. See §<a href=#subsubsec:horizontal-action-panel data-reference-type=ref data-reference=subsubsec:horizontal-action-panel>2.2.2.3</a> for a\ncomplete list of actions available here. Additional actions are\navailable in the <a href=#subsubsec:app-info-options-menu>options\nmenu</a>.<li><p><strong>Paths & Directories.</strong> Contains various\ninformation regarding application paths including <em>app directory</em>\n(where the APK files reside), <em>data directories</em> (internal,\ndevice protected and externals), and <em>JNI library directory</em> (if\npresent). JNI libraries are used to invoke native codes usually written\nin C/C++. Use of native library can make the application run faster or\nhelp an application use third-party libraries written using languages\nother than Java like in most games. The directories can be opened via\nfile managers provided they support it and have the necessary\npermissions, by clicking on the launch button on the right-hand side of\na directory item.<li><p><strong>Data Usage.</strong> Amount of data used by the\napplication as reported by the operating system. Depending on Android\nversion, this may require a wide range of permissions including\n<em>Usage Access</em> and <em>Telephony</em> permissions.<li><p><strong>Storage & Cache.</strong> Displays information\nregarding the size of the application (APK files, optimised files), data\nand cache. In older devices, size of external data, cache, media and OBB\nfolders are also displayed. This part remains hidden if <em>Usage\nAccess</em> permission is not granted in the newer devices.<li><p><strong>More Info.</strong> Displays other information such\nas–<ul class=incremental><li><p><strong>SDK.</strong> Displays information related to the Android\nSDK: <em>Max</em> denotes the target SDK and <em>Min</em> denotes the\nminimum SDK (the latter is not available in Android Lollipop). If the\ntarget SDK value is less than the platform SDK (i.e., the highest SDK\nthe current operating system supports), the application will run in the\ncompatibility mode. This means the application may have access to\ncertain features that are unavailable or restricted in a newer version\nof Android, which can be a security and/or privacy issue. SDK is also\nknown as <strong>API Level</strong>.<br><div class=seealso-inline><p><em>Voir aussi : <span><a href=https://en.wikipedia.org/wiki/Android_version_history#Overview>Android\nVersion History</a></span></em></div><li><p><strong>Flags.</strong> The application flags used at the time of\nbuilding the application. For a complete list of flags and what they do,\nread the <a href=https://developer.android.com/reference/android/content/pm/ApplicationInfo#flags>official\ndocumentation</a>.<li><p><strong>Date Installed.</strong> The date when the application\nwas first installed.<li><p><strong>Date Updated.</strong> The date when the application was\nlast updated. This is the same as <em>Date Installed</em> if the\napplication hasn’t been updated.<li><p><strong>Process Name.</strong> The name of the process if it is\ndifferent from the package name. Process name is set when an application\nis being started by the system, and is usually the same as the package\nname.<li><p><strong>Installer App.</strong> The application that installed\nthis application. The installer application may not always be the same\nas the application that installed this application, because Android\nallows setting an arbitrary value for this field. In Android 11 onwards,\nthe actual installer application is also stored by the system which can\nbe accessed by clicking the “Info” button on the right-hand side of the\nitem. The field will not be visible if the installer application is not\nreported by the system (e.g., due to the installer application being\nuninstalled or hidden). Installer application may be granted additional\nprivileges by the system so that it can control certain behaviour of the\napplication it installs.<li><p><strong>User ID.</strong> The unique user ID set by the system to\nthe application. For shared applications, the same user ID is assigned\nto multiple applications having the same <em>Shared User\nID</em>.<li><p><strong>Shared User ID.</strong> Applicable for applications that\nare shared together. The shared application must have the same <a href=#subsec:signatures-tab>signatures</a>.<li><p><strong>Primary ABI.</strong> Architecture supported by this\nplatform for this application.<li><p><strong>Zygote preload name.</strong> Responsible for preloading\napplication code and data shared across all the isolated services that\nuses app zygote.<li><p><strong>Hidden API enforcement policy.</strong> Since Android 9,\nmany methods and classes in Android framework have been made\ninaccessible to the third-party applications through hidden API\nenforcement policy. It has the following options:<ul class=incremental><li><p><em>Default.</em> Based on the type of application. For system\napplications, it should be disabled, and for others, it should be\nenforced.<li><p><em>None/disabled.</em> The application has full access to the\nhidden API as it used to be before Android 9.<li><p><em>Warn.</em> Same as above, except that warnings will be logged\neach time the application accesses the hidden API. This is mostly\nunused.<li><p><em>Enforce.</em> The application cannot access hidden API,\neither dark-grey list or blacklist, or both of them. This is the default\noption for the third-party applications in Android 9 onwards unless the\napplication is whitelisted by the OEM or the vendor.<div class=\"amalert warning\"><p><strong><em>Warning :</em></strong><p>Hidden API enforcement policy is not properly implemented in Android\nand can be bypassed by the application. As a result, this value should\nnot be trusted.</div></ul><li><p><strong>SELinux.</strong> Mandatory access control (MAC) policy\nset by the operating system via SELinux.<li><p><strong>Main Activity.</strong> The main entry point to the\napplication. This is only visible if the application has <a href=#subsubsec:activities>activities</a> and any of those are\nopenable from the Launcher. There’s also a launch button on the\nright-hand side which can be used to launch this activity.</ul></ul></section><section id=subsubsec:tags class=level4 data-number=2.2.2.2><h4 data-number=2.2.2.2><span class=header-section-number>2.2.2.2</span> Tags<a href=#subsubsec:tags class=anchor aria-hidden=true></a></h4><ul class=incremental><li><p><strong>Tracker info.</strong> Number of tracker components in\nthe application (e.g., <em>5 trackers</em>) The colour of the tag\nappears orange if the trackers are unblocked and dark cyan if they are\nblocked in App Manager. Clicking on the tag opens a dialog containing\nthe list of tracker components which can also be blocked or unblocked\nprovided App Manager has sufficient privileges.<li><p><strong>Application type.</strong> User application or system\napplication. For a system application, it displays whether the\napplication is an updated version of the system application or the\napplication is installed systemless-ly via Magisk.<li><p><strong>Split APK info.</strong> Number of splits in the APK\nexcluding the base APK (e.g., <em>5 splits</em>). Clicking on the tag\nopens a dialog containing a few additional information, such as name,\ntype, and size.<li><p><strong>Debuggable.</strong> The application can be debugged over\nADB. Debuggable applications can enjoy certain functions unavailable to\na regular application. The data of the application might be accessible\nvia ADB (e.g. using <code>run-as</code> command) without any additional\npermissions.<li><p><strong>Test only.</strong> The application is a test-only\napplication. Test-only applications can enjoy certain functions\nunavailable to a regular application. The data of the application might\nbe accessible via ADB (e.g. using <code>run-as</code> command) without\nany additional permissions.<li><p><strong>No code.</strong> The application does not have any code\nassociated with it i.e., DEX files aren’t present. In some system\napplications, the actual code might be located in another\nplace.<li><p><strong>Large heap.</strong> The application has requested large\nheap size i.e., more space in memory (RAM) is requested for dynamic\nallocation. It is still up to the operating system to decide whether to\nallocate large space for the application. App Manager, for example,\nrequests large heap size because it needs to load an entire APK into\nmemory while scanning an APK.<li><p><strong>Open links.</strong> The application may open certain\nlinks from any applications. If the application can open any links by\ndefault, the color of the tag would be red, dark cyan if otherwise.\nClicking on the tag opens a dialog with the supported hosts or domains\nlisted. In Android 12 onwards, it displays an option to enable or\ndisable opening links by default provided App Manager has sufficient\npermissions. Otherwise, it displays an option to open the system\nsettings page for the application.<li><p><strong>Running.</strong> One or more services of the application\nis currently running in the background. Clicking on the tag opens a\ndialog containing the list of running services. Clicking on any services\nopens the log viewer with default filter set to the UID associated with\nthe service (which can be different from the UID of the application if\nit is running in a separate or isolated process) provided the log viewer\nfeature is enabled. There’s also an option to force-stop the\napplication.<li><p><strong>Stopped.</strong> The application is force stopped. This\nmay not prevent it from running automatically later.<li><p><strong>Disabled.</strong> Denotes that the application is\ndisabled (hidden from the launcher).<li><p><strong>Suspended.</strong> Denotes that the application is\nsuspended (grayed out in the launcher).<li><p><strong>Hidden.</strong> Denotes that the application is hidden\n(hidden from the launcher).<li><p><strong>MagiskHide.</strong> MagiskHide is enabled for the\napplication. Clicking on the tag opens a dialog containing the list of\nprocess names within the application that can be added to or removed\nfrom the MagiskHide list.<li><p><strong>MagiskDenyList.</strong> The application is present in\nMagisk DenyList. Clicking on the tag opens a dialog containing the list\nof process names within the application that can be added to or removed\nfrom Magisk DenyList.<li><p><strong>WX.</strong> The application violates the “W^X policy”\nand is capable of writing and executing in the same directory or in the\nsame portion of memory. This allows the execution of arbitrary\nexecutables either by the modification of executables embedded within\nthe application or by downloading them from the Internet.<br><div class=seealso-inline><p><em>Voir aussi : <span><a href=https://en.wikipedia.org/wiki/W%5EX>W^X in\nWikipedia</a></span></em></div><li><p><strong>Bloatware.</strong> The application may be a known\nbloatware. Clicking on the tag opens a dialog containing detailed\ninformation in addition to suggestions (if available).<li><p><strong>KeyStore.</strong> The application has items in the\nAndroid KeyStore. Clicking on the tag opens a dialog containing all the\nKeyStore files that belong to the application.<li><p><strong>Backup.</strong> The application was backed up using App\nManager at least once. Clicking on the tag opens a dialog containing all\nthe available backups along with metadata.<li><p><strong>No battery optimisation.</strong> Battery optimisation is\ndisabled for the application. It is possible to re-enable battery\noptimisation by clicking on the tag.<li><p><strong>Sensors disabled.</strong> Sensors are disabled for the\napplication. Sensors are disabled for most applications by\ndefault.<li><p><a href=#sec:net-policy><strong>Net policy.</strong></a>\nNetwork policy (e.g., background data usage) is configured for the\napplication. Clicking on the tag displays a dialog containing the\nsupported policies for the platform along with the options to configure\nthem.<li><p><a href=#sec:terminologies><strong>SSAID.</strong></a> Clicking\non the tag opens a dialog containing the current SSAID assigned to the\napplication. It is also possible to reset/regenerate the SSAID if\nneeded.<li><p><strong>SAF.</strong> Denotes that the application has been\ngranted to access one or more storage locations or files i.e. URIs via\nStorage Access Framework (SAF). Clicking on the tag opens a dialog\ncontaining the list of granted URIs.<li><p><strong>Play App Signing.</strong> Indicates that the application\nmight be signed by Google.<li><p><strong>Xposed.</strong> Indicates that the application may be an\nXposed module. Clicking on the tag displays a dialog with additional\ninformation.<li><p><strong>Static Shared Library.</strong> Denotes that the\napplication serves as a static shared library for one or more\napplications. Clicking on the tag opens a dialog containing a list of\ninstalled versions of the library along with an option to uninstall\nthem.<div class=\"amalert tip\"><p><strong><em>Notice :</em></strong><p>The trichrome library (supplied by Google Chrome, Vanadium or similar\nprojects) is currently the only known static shared library on\nAndroid.</div></ul></section><section id=subsubsec:horizontal-action-panel class=level4 data-number=2.2.2.3><h4 data-number=2.2.2.3><span class=header-section-number>2.2.2.3</span> Horizontal Action Panel<a href=#subsubsec:horizontal-action-panel class=anchor aria-hidden=true></a></h4><p>Horizontal Action Panel, as described in the previous section,\nconsists of various application-related actions, such as–<ul class=incremental><li><p><strong>Launch.</strong> Launch the application provided it has a\nlauncher <a href=#subsubsec:activities>activity</a>.<li><p><strong>Freeze.</strong> Freeze the application. This button is\nnot displayed if it is already frozen or the user does not have enough\nprivileges. After the application is frozen, it may be hidden from the\napp drawer depending on how it was configured. Shortcuts configured by\nthe application may also be removed. The application may only be\nunfrozen via App Manager, <code>pm</code> command or any other tools\nthat offer such a feature. Long clicking on the button opens a dialog\nwhere a shortcut can be configured to quickly freeze or unfreeze the\napplication.<li><p><strong>Uninstall.</strong> Uninstall the application with a\nprompt. In the dialog prompt, it is possible to uninstall updates of a\nsystem application, or if App Manager has enough privileges or the\noperating system supports it, it is possible to uninstall the\napplication without clearing its data and signature. For the latter\ncase, the installed application must match the signature with the\npreviously installed application if it is installed again.<div class=\"amalert tip\"><p><strong><em>Tips :</em></strong><p>A better way to reinstall an application with a different signature\nwould be to back up its data using App Manager and restore it again\nafter installing the application instead of opting to preserving data\nand signature of the application during uninstallation as this option\nmay cause undefined behaviour in the future.</div><li><p><strong>Unfreeze.</strong> Unfreeze the application. This button\nis not displayed if it is already enabled or the user does not have\nenough privileges. Similar to the <em>Freeze</em> button, long clicking\non the button opens a dialog where a shortcut can be configured to\nquickly freeze or unfreeze the application.<li><p><strong>Force Stop.</strong> Force-stop the application.<li><p><strong>Clear Data.</strong> Clear data from the application.\nThis includes any information stored in the internal and, recently, the\nexternal directories, including accounts (if set by the application),\ncache, etc. Clearing data from App Manager, for example, removes all the\nrules (the blocking is not removed though) saved within the application\n(Which is why you should always take backups of your rules). This button\nis not displayed if the user does not have enough privileges.<li><p><strong>Clear Cache.</strong> Clear the application cache. If the\napplication is running during the operation, the cache may not be\ncleared as expected.<li><p><strong>Install.</strong> Install the application, only displayed\nif the application hasn’t already been installed.<li><p><strong>What’s New.</strong> Displayed for an external\napplication if an older version of it is already installed. Clicking on\nthis button opens a dialog containing the differences between this and\nthe installed version in a version control manner. Changes include\n<em>version</em>, <em>trackers</em>, <em>permissions</em>,\n<em>components</em>, <em>signatures</em> (only checksum changes),\n<em>features</em>, <em>shared libraries</em> and <em>SDK</em>.<li><p><strong>Update.</strong> Displayed if the application has a\nhigher version code than the installed application.<li><p><strong>Reinstall.</strong> Displayed if the application has the\nsame version code as the installed application.<li><p><strong>Downgrade.</strong> Displayed if the application has a\nlower version code than the installed application.<li><p><strong>Manifest.</strong> Opens the application’s manifest file\nin a separate page. If the application has more than one split, it will\ndisplay the list of split APK files, and clicking on an item will open\nthe corresponding manifest file instead.<li><p><strong>Scanner.</strong> Scan the application in order to list\npotential trackers and libraries. It also scans the file using\nVirusTotal and fetch results from Pithus if configured.<br><div class=seealso-inline><p><em>Voir aussi : <span><a href=#sec:scanner-page>Scanner\npage</a></span></em></div><li><p><strong>Shared Prefs.</strong> Displays a list of shared\npreferences used by the application. Clicking on a preference item in\nthe list opens the <a href=#sec:shared-preferences-editor-page>Shared\nPreferences Editor page</a>. This option is only visible if the user has\nthe required privileges.<li><p><strong>Databases.</strong> Displays a list of databases used by\nthe application. Clicking on an item opens a list of activities that can\nopen the database. This option is only visible if the user has the\nrequired privileges.<li><p><strong>F-Droid.</strong> Open the application in the selected\n<em>F-Droid</em> client.<li><p><strong>Store.</strong> Open the application in <em>Aurora\nStore</em>. The option is only visible if <em>Aurora Store</em> is\ninstalled.</ul></section><section id=subsubsec:app-info-options-menu class=level4 data-number=2.2.2.4><h4 data-number=2.2.2.4><span class=header-section-number>2.2.2.4</span> Options Menu<a href=#subsubsec:app-info-options-menu class=anchor aria-hidden=true></a></h4><p>Options-menu is located in the top-right corner of the page. A\ncomplete description of the options present there are given below:<ul class=incremental><li><p><strong>Share.</strong> Share button can be used to share the APK\nor (if the application is has multiple splits, OBB files or any\ndependencies) <em>APKS</em> file extracted from the\napplication.<li><p><strong>Refresh.</strong> Refresh the App Info tab.<li><p><strong>View in Settings.</strong> Open the application in\nAndroid Settings.<li><p><strong>Backup/restore.</strong> Open the backup/restore\ndialog.<li><p><strong>Export blocking rules.</strong> Export rules configured\nfor the application within App Manager.<li><p><strong>Open in Termux.</strong> Open the application in Termux.\nThis actually runs <code>su - user_id</code> where <code>user_id</code>\ndenotes the application’s kernel user ID (described in §<a href=#subsubsec:app-info-general-information data-reference-type=ref data-reference=subsubsec:app-info-general-information>2.2.2.1</a>).\nThis option is only visible to the root users. See §<a href=#subsubsec:config-termux data-reference-type=ref data-reference=subsubsec:config-termux>2.2.2.5</a> to learn how to\nconfigure Termux to run commands from third-party applications.<li><p><strong>Run in Termux.</strong> Open the application via\n<code>run-as package_name</code> in Termux. This is only applicable to\nthe debuggable applications and works for both root and ADB users. See\n§<a href=#subsubsec:config-termux data-reference-type=ref data-reference=subsubsec:config-termux>2.2.2.5</a> to learn how to\nconfigure Termux to run commands from third-party applications.<li><p><strong>MagiskHide.</strong> Open a dialog containing the list of\nprocess names within the application that can be added or removed from\nthe MagiskHide list.<li><p><strong>Magisk DenyList.</strong> Open a dialog containing the\nlist of process namees within the application that can be added or\nremoved from Magisk DenyList.<li><p><strong>Battery optimisation.</strong> Enable/disable battery\noptimisation for this application.<li><p><strong>Sensors.</strong> Enable/disable sensors for this\napplication.<li><p><a href=#sec:net-policy><strong>Net policy.</strong></a>\nConfigure network policy (e.g., background data usage) for the\napplication.<li><p><strong>Extract Icon.</strong> Extract and save the application’s\nicon in the shared storage.<li><p><strong>Optimize.</strong> Perform optimisation for this\napplication. This option is for advanced users only.<li><p><strong>Add to profile.</strong> Add the application to one of\nthe configured <a href=#sec:profile-page>profiles</a>.<li><p><strong>Install for….</strong> Install the application for\nanother user and/or in the work profile if configured.</ul></section><section id=subsubsec:config-termux class=level4 data-number=2.2.2.5><h4 data-number=2.2.2.5><span class=header-section-number>2.2.2.5</span> Configuring Termux<a href=#subsubsec:config-termux class=anchor aria-hidden=true></a></h4><p>By default, Termux does not allow running commands from a third-party\napplication. To use this option, Termux v0.96 or later is required and\n<code>allow-external-apps=true</code> must be added in\n<code>~/.termux/termux.properties</code>.<div class=\"amalert tip\"><p><strong><em>Info :</em></strong><p>Enabling this option does not weaken Termux’ security. The\nthird-party applications still need to ask the user to allow running\narbitrary commands in Termux.</div></section></section><section id=subsec:component-tabs class=level3 data-number=2.2.3><h3 data-number=2.2.3><span class=header-section-number>2.2.3</span>\n<a href=#toc:subsec:component-tabs>Component Tabs</a><a href=#subsec:component-tabs class=anchor aria-hidden=true></a></h3><p><strong>Activities</strong>, <strong>Services</strong>,\n<strong>Receivers</strong> (i.e., broadcast receivers) and\n<strong>Providers</strong> (e.g., content providers) are collectively\nknown as the application components, because they offer similar features\nand share similar properties. For example, they all have a\n<em>name</em>, a <em>label</em>, an <em>icon</em>, can be enabled or\ndisabled, and can be executed via <em>Intent</em>. Application\ncomponents are the building blocks of an application and must be\ndeclared in the application manifest (with a few exceptions).\nApplication manifest is a file where application specific metadata are\nstored. The Android operating system learns what to do with the\napplication by reading the metadata.<p>Colours used in these tabs are explained in §<a href=#subsec:app-details-colour-codes data-reference-type=ref data-reference=subsec:app-details-colour-codes>2.2.1</a>. It is also\npossible to sort the list of components to display blocked or tracker\ncomponents on top of the list via the <strong>Sort</strong> option\nlocated in the three-dots menu.<section id=subsubsec:activities class=level4 data-number=2.2.3.1><h4 data-number=2.2.3.1><span class=header-section-number>2.2.3.1</span> Activities<a href=#subsubsec:activities class=anchor aria-hidden=true></a></h4><p><strong>Activities</strong> are the windows or pages that can be\nuniquely identified by the Android operating system (e.g., <em>Main\npage</em> and <em>App Details page</em> are two activities). Each\nactivity can have multiple UI components known as <em>widgets</em> or\n<em>fragments</em>, and each component can be nested or placed on top of\neach other. The developer can also choose to open external files, links,\netc. within an activity using a method called <em>intent filters</em>.\nFor example, when you open a file in your file manager, either your file\nmanager or the operating system scans the intent filters via\nPackageManager, find the activities capable of opening the file, and\nlist those activities so that you can choose your preferred\nactivity.<p>Activities that are <em>exportable</em> can be opened by any\nthird-party applications. However, Some activities may require\npermissions, and only an application having those permissions can open\nthem. In the <em>Activities</em> tab, certain activities can be launched\nvia the <strong>Launch</strong> button. If it is necessary to supply\nadditional information, such as Intent extras, data or action, long\nclicking on the <strong>Launch</strong> button opens the <a href=#sec:interceptor-page>Activity Interceptor</a> page which\nprovides such features.<div class=\"amalert tip\"><p><strong><em>Tip :</em></strong><p>No-root users can grant\n<code>android.permission.WRITE_SECURE_SETTINGS</code> via ADB to launch\n<em>non-exportable</em> activities.</div><div class=\"amalert tip\"><p><strong><em>Notice :</em></strong><p>If launching an activity throws an error, it may have certain\ndependencies which are not met (e.g., <em>App Details</em> page in App\nManager cannot be launched using the launch button, because it requires\na package name). Since the dependencies cannot be inferred\nprogrammatically, the activity may not be opened from App Manager by\ndefault.</div><p>It is also possible to create shortcuts of an activity-launch using\nthe <strong>Create shortcut</strong> button. If you need to supply\nadditional information, you can create a shortcut from the Activity\nInterceptor page instead.<div class=\"amalert danger\"><p><strong><em>Caution :</em></strong><p>If you uninstall App Manager, all shortcuts created by App Manager\nwill be lost.</div></section><section id=subsubsec:details:servcies class=level4 data-number=2.2.3.2><h4 data-number=2.2.3.2><span class=header-section-number>2.2.3.2</span> Services<a href=#subsubsec:details:servcies class=anchor aria-hidden=true></a></h4><p>Unlike <a href=#subsubsec:activities>activities</a> that users can\nsee, <strong>Services</strong> handle background tasks. For example, if\nyou’re downloading a video from the internet using your phone’s Internet\nbrowser, the Internet browser is using a <em>foreground service</em> to\ndownload the content.<p>When an activity is closed or removed from the <em>Recents</em> page,\nit may be destroyed immediately depending on the amount free memory the\nphone has, battery statistics, or how the activity is configured. But\nservices can be run indefinitely if desired. If more services run in the\nbackground, the phone may become slower due to the shortage of memory\nand/or processing power, and the phone’s battery will be drained more\nquickly. Newer versions of Android come with a battery optimisation\nfeature enabled by default for all applications. With this feature\nenabled, the system can randomly terminate any service depending on the\namount of resources the system has or the service requires. However,\nforeground services (i.e., services that run with a fixed notification,\nsuch as music player or downloader) are not typically terminated unless\nthe system is very low on resources (memory, battery, etc.). Certain\nstock ROMs can offer more aggressive optimisation. MIUI, for example,\nhas a very aggressive optimisation feature known as the <em>MIUI\noptimisation</em>.<p>Both activities and services are run in the same <a href=https://stackoverflow.com/questions/7597742>looper</a> called the\nmain looper, which means the services do not really run in the\nbackground. It is the task of the developer to ensure this. How do the\napplication communicate with the services? It uses <a href=#subsubsec:app-details-receivers>broadcast receiver</a> or\nBinder.</section><section id=subsubsec:app-details-receivers class=level4 data-number=2.2.3.3><h4 data-number=2.2.3.3><span class=header-section-number>2.2.3.3</span> Receivers<a href=#subsubsec:app-details-receivers class=anchor aria-hidden=true></a></h4><p><strong>Receivers</strong> (also called <em>broadcast receivers</em>)\ncan be used to trigger execution of certain tasks when certain events\noccur. These components are called broadcast receivers, because they are\nexecuted as soon as a broadcast message is received. These broadcast\nmessages are sent using a method called <em>Intent</em>. Intent is a\nspecial feature in Android that can be used to open applications (i.e.,\nactivities), run services and send broadcast messages. Therefore, like\n<a href=#subsubsec:activities>activities</a>, broadcast receivers use\n<em>intent filters</em> to receive the desired broadcast messages.\nBroadcast messages can be sent by the system or the application itself.\nWhen a broadcast message is sent, the corresponding receivers are\nactivated by the system so that they can execute tasks. For example, if\nyour phone is low on resources, it may freeze or experience lags for a\nmoment after you enable mobile data or connect it to the Wi-Fi. This is\nbecause broadcast receivers that can receive\n<code>android.net.conn.CONNECTIVITY_CHANGE</code> are activated by the\nsystem as soon as the data connection is enabled. Since many\napplications typically use this intent filter, they are all activated\nalmost immediately by the system which causes the freezing or lags.<p>Receivers can also be used for inter-process communication (IPC),\ni.e., it can be used to communicate across multiple applications or even\ndifferent components of a single application.</section><section id=subsubsec:providers class=level4 data-number=2.2.3.4><h4 data-number=2.2.3.4><span class=header-section-number>2.2.3.4</span> Providers<a href=#subsubsec:providers class=anchor aria-hidden=true></a></h4><p><strong>Providers</strong> are primarily used for data management.\nFor example, when you save an APK file or export rules in App Manager,\nit uses a content provider called <code>.fm.FmProvider</code> to save\nthe APK or export the rules. There are many providers, including the\nones provided by the system, that can be used to manage various\ncontent-related tasks, such as database management, tracking, searching,\netc. Each provider has a field called <em>Authority</em> which is unique\nto the application in the entire Android ecosystem just as the package\nname.</section><section id=additional-features-for-rooted-phones class=level4 data-number=2.2.3.5><h4 data-number=2.2.3.5><span class=header-section-number>2.2.3.5</span> Additional Features for\nRooted Phones<a href=#additional-features-for-rooted-phones class=anchor aria-hidden=true></a></h4><p>Unlike the no-root users who are mostly spectators in these tabs,\nroot users can perform various operations.<section id=blocking-components. class=level5 data-number=2.2.3.5.1><h5 data-number=2.2.3.5.1><span class=header-section-number>2.2.3.5.1</span> Blocking Components.<a href=#blocking-components. class=anchor aria-hidden=true></a></h5><p>On the right-most side of each component item, there is a switch\nwhich can be used to toggle the blocking status of that particular\ncomponent. If <a href=#subsubsec:instant-component-blocking>Instant\nComponent Blocking</a> is not enabled or blocking is never applied to\nthe application before, it is required to apply the changes using the\n<strong>Apply rules</strong> option in three-dots menu. It is also\npossible to remove the already-applied rules using the same option\n(which would be read as <strong>Remove rules</strong> this time).<p>It is also possible to block the component using one of the several\nmethods by long clicking on the button.<div class=seealso-inline><p><em>Voir aussi : <span><a href=#sec:faq:app-components>FAQ: App\nComponents</a></span></em></div></section><section id=par:appdetails:blocking-trackers class=level5 data-number=2.2.3.5.2><h5 data-number=2.2.3.5.2><span class=header-section-number>2.2.3.5.2</span> Blocking Trackers.<a href=#par:appdetails:blocking-trackers class=anchor aria-hidden=true></a></h5><p>It is possible to disable tracker components using the <strong>Block\ntracker</strong> option in the three-dots menu. All tracker components\nwill be blocked regardless of the tab you’re currently in.<div class=\"amalert tip\"><p><strong><em>Info :</em></strong><p>Tracker components are a subset of application components. Therefore,\nthey are blocked using the same method used for blocking any other\ncomponents.</div><div class=seealso><p><em>Voir aussi :</em><ul class=incremental><li><p><a href=#subsec:tracker-classes-versus-tracker-components>FAQ:\nTracker classes versus tracker components</a><li><p><a href=#sec:scanner-page>Scanner Page</a><li><p><a href=#subsec:block-unblock-trackers>1-Click Ops Page:\nBlock/Unblock Trackers</a></ul></div></section></section></section><section id=subsec:permission-tabs class=level3 data-number=2.2.4><h3 data-number=2.2.4><span class=header-section-number>2.2.4</span>\n<a href=#toc:subsec:permission-tabs>Permission Tabs</a><a href=#subsec:permission-tabs class=anchor aria-hidden=true></a></h3><p><strong>App Ops</strong>, <strong>Uses Permissions</strong> and\n<strong>Permissions</strong> tabs are related to permissions. In Android\ncommunication across applications or processes not having the same\nidentity (known as <em>shared ID</em>) often require permissions. These\npermissions are managed by the permission controller. Some permissions\nare considered <em>normal</em> permissions which are granted\nautomatically if they appear in the application manifest, but\n<em>dangerous</em> and <em>development</em> permissions require\nconfirmation from the user. Colours used in these tabs are explained in\n§<a href=#subsec:app-details-colour-codes data-reference-type=ref data-reference=subsec:app-details-colour-codes>2.2.1</a>.<section id=subsubsec:app-ops class=level4 data-number=2.2.4.1><h4 data-number=2.2.4.1><span class=header-section-number>2.2.4.1</span> App Ops<a href=#subsubsec:app-ops class=anchor aria-hidden=true></a></h4><p><strong>App Ops</strong> stands for <strong>Application\nOperations</strong>. Since Android 4.3, <em>App Ops</em> are used by\nAndroid to control many system permissions. Each app op has a unique\nnumber associated with it which is displayed along with the private name\nof the operation in the App Ops tab. Some app ops also have a public\nname. A large number of app ops are also associated with\n<em>permissions</em>. In this tab, an app op is considered dangerous if\nits associated permission is marked as dangerous. Other information such\nas <em>flags</em>, <em>permission name</em>, <em>permission\ndescription</em>, <em>package name</em>, <em>group</em> are also taken\nfrom the associated <a href=#subsubsec:permissions>permission</a>.\nOthers may include the following:<ul class=incremental><li><p><strong>Mode.</strong> It describes the current authorisation\nstatus which can be <em>allow</em>, <em>deny</em> (a rather misnomer, it\nsimply means error), <em>ignore</em> (it actually means deny),\n<em>default</em> (inferred from a list of defaults set internally by the\nvendor or the AOSP), <em>foreground</em> (in newer Android versions, it\nmeans the app op can only be used when the application is running in\nforeground), and some custom modes set by the vendors (MIUI uses\n<em>ask</em>, for example).<li><p><strong>Duration.</strong> The amount of time this app op has\nbeen used (there can be negative durations whose use cases are currently\nunknown to me).<li><p><strong>Accept Time.</strong> Last time the app op was\naccepted.<li><p><strong>Reject Time.</strong> Last time the app op was\nrejected.</ul><div class=\"amalert tip\"><p><strong><em>Info :</em></strong><p>Contents of this tab are visible to no-root users if\n<code>android.permission.GET_APP_OPS_STATS</code> is granted via\nADB.</div><p>There is a toggle button next to each app op item which can be used\nto allow or deny (ignore) it. Other supported modes can also be set by\nlong clicking on the toggle button. If the desired app op is not listed\nin the tab, <em>Set custom app op</em> option in the menu can be used\ninstead. It is also possible to reset the changes using the <em>Reset to\ndefault</em> option, or deny all the dangerous app ops using the\ncorresponding option in the menu. Due to the nature how app ops work,\nthe system may take some time to apply them.<div class=\"amalert tip\"><p><strong><em>Tip :</em></strong><p>Denying certain app ops may cause the application to misbehave. If\nall attempts fail, <em>reset to default</em> option can be used as the\nlast resort.</div><p>It is possible to sort the list in ascending order by app op names\nand the associated unique numbers (or values), or list the denied app\nops first using the corresponding sorting options.<div class=seealso-inline><p><em>Voir aussi : <span><a href=#ch:app-ops>Appendix: App\nOps</a></span></em></div></section><section id=uses-permissions class=level4 data-number=2.2.4.2><h4 data-number=2.2.4.2><span class=header-section-number>2.2.4.2</span> Uses Permissions<a href=#uses-permissions class=anchor aria-hidden=true></a></h4><p><strong>Uses Permissions</strong> are the permissions used by the\napplication. This is named so because they are specified in the manifest\nusing <code>uses-permission</code> tags. Information such as\n<em>flags</em>, <em>permission name</em>, <em>permission\ndescription</em>, <em>package name</em>, <em>group</em> are taken from\nthe associated <a href=#subsubsec:permissions>permission</a>.<p>Privileged users can grant or revoke the <em>dangerous</em> and\n<em>development</em> permissions via the toggle button on the right side\nof each permission item. It is also possible revoke dangerous\npermissions all at once using the corresponding option in the menu. Only\nthese two types of permissions can be revoked because Android does not\nallow the modification of <em>normal</em> permissions (which most of\nthem are). It might still be possible to revoke them by editing\n<code>runtime-permissions.xml</code> itself, but whether this is a\npossibility is still being investigated.<div class=\"amalert tip\"><p><strong><em>Info :</em></strong><p>Since dangerous permissions are revoked by default by the system,\nrevoking all dangerous permissions is the same as resetting all the\npermissions.</div><p>It is possible to sort the permissions by their name (in ascending\norder) or choose to display denied or dangerous permissions at first\nusing the corresponding options in the menu.</section><section id=subsubsec:permissions class=level4 data-number=2.2.4.3><h4 data-number=2.2.4.3><span class=header-section-number>2.2.4.3</span> Permissions<a href=#subsubsec:permissions class=anchor aria-hidden=true></a></h4><p><strong>Permissions</strong> are usually custom permissions defined\nby the application itself. These type of permissions are marked as\n<em>Internal</em> permissions. It also contains permissions declared by\nother applications which are marked as <em>External</em> permissions. An\nexternal permission can be specified in an <em>exported</em> application\ncomponent so that another application may invoke the component only if\nit holds the permission. Below is a complete description of each item\ndisplayed in this tab:<ul class=incremental><li><p><strong>Name.</strong> A permission has a unique name (e.g.,\n<code>android.permission.INTERNET</code>) that multiple applications can\nrequest. The application that declared the permission is automatically\ngranted and cannot be revoked.<li><p><strong>Icon.</strong> Each permission can have a custom icon.\nThe other permission tabs do not have any icon because they do not\ncontain any icon in the application manifest.<li><p><strong>Description.</strong> This optional field describes the\npermission. If there isn’t any description associated with the\npermission, the field is not displayed.<li><p><strong>Flags.</strong> (Uses the flag symbol or\n<strong>Protection Level</strong> name) This describes various\npermission flags such as <em>normal</em>, <em>development</em>,\n<em>dangerous</em>, <em>instant</em>, <em>granted</em>,\n<em>revoked</em>, <em>signature</em>, <em>privileged</em>, etc.<li><p><strong>Package Name.</strong> Denotes the package name\nassociated with the permission, i.e. the package that defined the\npermission.<li><p><strong>Group.</strong> The group name associated with the\npermission (if any). Several related permissions can often be grouped\ntogether.</ul></section></section><section id=subsec:signatures-tab class=level3 data-number=2.2.5><h3 data-number=2.2.5><span class=header-section-number>2.2.5</span>\n<a href=#toc:subsec:signatures-tab>Signatures Tab</a><a href=#subsec:signatures-tab class=anchor aria-hidden=true></a></h3><p><strong>Signatures</strong> are actually called signing information.\nAn application is signed with one or more signing keys by its developer\nbefore publishing it. The integrity of an application, i.e., whether the\napplication is from the actual developer and has not been modified by\nanother person, can be checked using the signing certificate included in\nthe APK files. This is because when an application is modified by an\nunauthorised entity, the application can longer be signed with the\noriginal signing keys since the signing keys are unknown to the entity.\nOne way to verify the integrity of an application is via the checksums\ngenerated from the certificates. If the developer supplies the checksums\nfor the signing certificates, they can be compared against the checksums\ngenerated in the <strong>Signatures</strong> tab to verify the\napplication. For example, if you have downloaded App Manager from GitHub\nor Telegram Channel, you can verify whether the application was actually\nreleased by me by simply matching the following <em>SHA256</em> checksum\nwith the one displayed in this tab:<pre><code>320c0c0fe8cef873f2b554cb88c837f1512589dcced50c5b25c43c04596760ab</code></pre><p>Several hashing algorithms are used to generate checksums in this\ntab. They include <em>MD5</em>, <em>SHA1</em>, <em>SHA256</em> and\n<em>SHA512</em>.<div class=\"amalert danger\"><p><strong><em>Caution :</em></strong><p>Signing information should be verified using a reliable hashing\nalgorithm, such as <em>SHA256</em>. DO NOT rely on <em>MD5</em> or\n<em>SHA1</em> checksums as they are known to generate the same checksums\nfor multiple certificates.</div></section><section id=subsec:uses-features-tab class=level3 data-number=2.2.6><h3 data-number=2.2.6><span class=header-section-number>2.2.6</span>\n<a href=#toc:subsec:uses-features-tab>Uses Features tab</a><a href=#subsec:uses-features-tab class=anchor aria-hidden=true></a></h3><p><strong>Uses Features</strong> tab lists the features declared by the\napplication, such as OpenGL ES, telephony, and leanback. Some features\ncan be required by the application, and some features can be optional.\nRequired features must be present in the system along with the required\nversion. Otherwise, any attempt to install the application will be\ndenied by the system. Colours used in this tab are explained in §<a href=#subsec:app-details-colour-codes data-reference-type=ref data-reference=subsec:app-details-colour-codes>2.2.1</a>.</section><section id=subsec:configurations-tab class=level3 data-number=2.2.7><h3 data-number=2.2.7><span class=header-section-number>2.2.7</span>\n<a href=#toc:subsec:configurations-tab>Configurations tab</a><a href=#subsec:configurations-tab class=anchor aria-hidden=true></a></h3><p><strong>Configurations</strong> tab lists the configurations required\nby the application, such as input method type (qwerty, 12 key), touch\nscreen type (finger, stylus, etc.), and navigation type (dial pad,\ntrackball, wheel). This tab is going to be empty for most\napplications.</section><section id=subsec:shared-libs-tab class=level3 data-number=2.2.8><h3 data-number=2.2.8><span class=header-section-number>2.2.8</span>\n<a href=#toc:subsec:shared-libs-tab>Shared Libraries Tab</a><a href=#subsec:shared-libs-tab class=anchor aria-hidden=true></a></h3><p><strong>Shared libraries</strong> tab lists the legacy JAR\ndependencies, any static shared library dependencies (currently, the\nonly known cases are the Chromium-based browsers and WebViews) as well\nas the JNI (Java native interface) libraries. For JNI libraries, it\nspecifies platform (x86/x86_64/ARM/AArch64), architecture (32/64 bit),\nobject type (shared object or executable), etc.</section></section><section id=sec:1-click-ops-page class=level2 data-number=2.3><h2 data-number=2.3><span class=header-section-number>2.3</span> <a href=#toc:sec:1-click-ops-page>1-Click Ops Page</a><a href=#sec:1-click-ops-page class=anchor aria-hidden=true></a></h2><p>This page is displayed on selecting the <a href=#subsubsec:main:1-click-ops>1-Click Ops option</a> in the <a href=#subsec:main-page-options-menu>main menu</a>.<section id=subsec:block-unblock-trackers class=level3 data-number=2.3.1><h3 data-number=2.3.1><span class=header-section-number>2.3.1</span>\n<a href=#toc:subsec:block-unblock-trackers>Block/Unblock\nTrackers</a><a href=#subsec:block-unblock-trackers class=anchor aria-hidden=true></a></h3><p>This option can be used to block or unblock the ad/tracker components\nfrom the installed applications. On selecting this option, App Manager\nwill ask if it should list trackers from all the applications or only\nfrom the user applications. Novice users should avoid blocking trackers\nfrom the system applications in order to avoid bad consequences. After\nthat, a multi-choice dialog box will appear where it is possible to\nexclude one or more applications from this operation. The changes are\napplied immediately on pressing the <em>block</em> or <em>unblock</em>\nbutton.<div class=\"amalert warning\"><p><strong><em>Notice :</em></strong><p>Certain applications may not function as expected after blocking\ntheir trackers. If that is the case, remove the blocking rules all at\nonce or one by one in the component tabs of the <a href=#sec:app-details-page>App Details page</a> for the corresponding\napplication.</div><div class=seealso-inline><p><em>Voir aussi : <span><a href=#par:appdetails:blocking-trackers>App Details Page: Blocking\nTrackers</a></span></em></div></section><section id=subsec:block-components-dots class=level3 data-number=2.3.2><h3 data-number=2.3.2><span class=header-section-number>2.3.2</span>\n<a href=#toc:subsec:block-components-dots>Block Components…</a><a href=#subsec:block-components-dots class=anchor aria-hidden=true></a></h3><p>This option can be used to block certain application components as\nspecified by their signatures. A signature of a component is the full\nname or partial name of the component. For safety, it is recommended to\nadd a <code>.</code> (dot) at the end of each partial signature, because\nthe underlying algorithm searches and matches the components in a greedy\nmanner. It is also possible to insert more than one signature in which\ncase all the signatures have to be separated by white spaces. Similar to\nthe option above, there is also an option to apply blocking to the\nsystem applications.<div class=\"amalert danger\"><p><strong><em>Caution :</em></strong><p>If you are not aware of the consequences of blocking applcations\ncomponents by their signatures, you should avoid using this option as it\nmay result in bootloop or soft brick, and you may have to apply factory\nreset as a result.</div></section><section id=subsec:set-mode-for-app-ops-dots class=level3 data-number=2.3.3><h3 data-number=2.3.3><span class=header-section-number>2.3.3</span>\n<a href=#toc:subsec:set-mode-for-app-ops-dots>Set Mode for App\nOps…</a><a href=#subsec:set-mode-for-app-ops-dots class=anchor aria-hidden=true></a></h3><p>This option can be used to configure certain <a href=#ch:app-ops>applcation operations</a> of all or selected\napplications. There are two fields. The first field can be used to\ninsert more than one app op constants (either names or values) separated\nby white spaces. It is not always possible to know in advance about all\nthe app op constants as they vary from device to device and from OS to\nOS. Desired app op constant can be found in the <em>App Ops</em> tab\nlocated in the <a href=#sec:app-details-page>App Details page</a>. The\nsecond field can be used to insert or select one of the <a href=#subsec:mode-constants>modes</a> that will be set against the\nspecified app ops.<div class=\"amalert danger\"><p><strong><em>Caution :</em></strong><p>Unless you are well-informed about app ops and the consequences of\nblocking them, you should avoid using this option.</div></section><section id=subsec:1-click-back-up class=level3 data-number=2.3.4><h3 data-number=2.3.4><span class=header-section-number>2.3.4</span>\n<a href=#toc:subsec:1-click-back-up>Back up</a><a href=#subsec:1-click-back-up class=anchor aria-hidden=true></a></h3><p>1-Click options for back up. As a precaution, it lists the affected\nbackups before performing any operation.<section id=back-up-all-apps. class=level5 data-number=2.3.4.0.1><h5 data-number=2.3.4.0.1><span class=header-section-number>2.3.4.0.1</span> Back up all apps.<a href=#back-up-all-apps. class=anchor aria-hidden=true></a></h5><p>Back up all the installed applications.</section><section id=redo-existing-backups. class=level5 data-number=2.3.4.0.2><h5 data-number=2.3.4.0.2><span class=header-section-number>2.3.4.0.2</span> Redo existing backups.<a href=#redo-existing-backups. class=anchor aria-hidden=true></a></h5><p>Back up all the installed applications that have a previous\nbackup.</section><section id=back-up-apps-without-backups. class=level5 data-number=2.3.4.0.3><h5 data-number=2.3.4.0.3><span class=header-section-number>2.3.4.0.3</span> Back up apps without\nbackups.<a href=#back-up-apps-without-backups. class=anchor aria-hidden=true></a></h5><p>Back up all the installed applications without a previous backup.</section><section id=verify-and-redo-backups. class=level5 data-number=2.3.4.0.4><h5 data-number=2.3.4.0.4><span class=header-section-number>2.3.4.0.4</span> Verify and redo\nbackups.<a href=#verify-and-redo-backups. class=anchor aria-hidden=true></a></h5><p>Verify the recently made backups of the installed applications and\nredo backup if necessary.</section><section id=back-up-apps-with-changes. class=level5 data-number=2.3.4.0.5><h5 data-number=2.3.4.0.5><span class=header-section-number>2.3.4.0.5</span> Back up apps with\nchanges.<a href=#back-up-apps-with-changes. class=anchor aria-hidden=true></a></h5><p>If an app has changed since the last backup, redo its backup. It\nchecks a number of indices including application version, last update\ndate, last launch date, integrity and file hashes. Directory hashes are\ntaken during the backup process and are stored in a database. On running\nthis operation, new hashes are taken and compared with the ones kept in\nthe database.</section></section><section id=subsec:1-click-restore class=level3 data-number=2.3.5><h3 data-number=2.3.5><span class=header-section-number>2.3.5</span>\n<a href=#toc:subsec:1-click-restore>Restore</a><a href=#subsec:1-click-restore class=anchor aria-hidden=true></a></h3><p>1-Click options for restore. As a precaution, it lists the affected\nbackups before performing any operation.<section id=restore-all-apps. class=level5 data-number=2.3.5.0.1><h5 data-number=2.3.5.0.1><span class=header-section-number>2.3.5.0.1</span> Restore all apps.<a href=#restore-all-apps. class=anchor aria-hidden=true></a></h5><p>Restore <em>base backup</em> of all the backed up applications.</section><section id=restore-not-installed-apps. class=level5 data-number=2.3.5.0.2><h5 data-number=2.3.5.0.2><span class=header-section-number>2.3.5.0.2</span> Restore not installed\napps.<a href=#restore-not-installed-apps. class=anchor aria-hidden=true></a></h5><p>Restore <em>base backup</em> of all the backed up applications that\nare not currently installed.</section><section id=restore-latest-backups. class=level5 data-number=2.3.5.0.3><h5 data-number=2.3.5.0.3><span class=header-section-number>2.3.5.0.3</span> Restore latest backups.<a href=#restore-latest-backups. class=anchor aria-hidden=true></a></h5><p>Restore <em>base backup</em> of already installed applications whose\nversion codes are higher than the installed version code.</section></section><section id=subsec:trim-caches-in-all-apps class=level3 data-number=2.3.6><h3 data-number=2.3.6><span class=header-section-number>2.3.6</span>\n<a href=#toc:subsec:trim-caches-in-all-apps>Trim Caches in All\nApps</a><a href=#subsec:trim-caches-in-all-apps class=anchor aria-hidden=true></a></h3><p>Delete caches from all applications, including Android system. During\nthis operation, caches of all the running applications may not be\ncleared as expected.</section></section><section id=sec:profiles-page class=level2 data-number=2.4><h2 data-number=2.4><span class=header-section-number>2.4</span> <a href=#toc:sec:profiles-page>Profiles Page</a><a href=#sec:profiles-page class=anchor aria-hidden=true></a></h2><p>Profiles page can be accessed from the <a href=#subsec:main-page-options-menu>options-menu</a> in the main page.\nIt primarily displays a list of configured profiles along with the\ntypical options to perform operations on them. New profiles can also be\nadded using the <em>plus</em> button at the bottom-right corner.\nProfiles can be imported, duplicated or deleted. Clicking on a profile\nitem opens its <a href=#sec:profile-page>profile page</a>.<section id=subsec:profiles-options-menu class=level3 data-number=2.4.1><h3 data-number=2.4.1><span class=header-section-number>2.4.1</span>\n<a href=#toc:subsec:profiles-options-menu>Options Menu</a><a href=#subsec:profiles-options-menu class=anchor aria-hidden=true></a></h3><p>The three-dots menu in the top-right corner opens the global option\nmenu. It has an option to import an existing profile that was previously\nexported from App Manager.<p>Long clicking on any profile item brings up another options-menu. It\noffers the following options:<ul class=incremental><li><p><strong>Apply now….</strong> This option can be used to apply the\nprofile directly. When clicked, a dialog is displayed where it is\npossible to select a <a href=#subsubsec:profile-state>profile\nstate</a>. On selecting one of the states, the profile will be applied\nimmediately.<li><p><strong>Delete.</strong> Clicking on this option will remove the\nprofile immediately without a warning.<li><p><strong>Duplicate.</strong> This option can be used to duplicate\nthe profile. When clicked, a dialog is displayed where it is possible to\nset a name for the new profile. On clicking “OK”, the <a href=#sec:profile-page>profile page</a> will be loaded by duplicating\nall the configurations that this profile have. However, the profile will\nnot be saved until it is saved manually.<li><p><strong>Copy profile ID.</strong> This option is used to copy the\nunique profile ID of the profile. The profile ID can be used to <a href=#subsec:triggering-a-profile>trigger the profile</a> from a\nthird-party application.<li><p><strong>Export.</strong> Export the profile to an external\nstorage. Profiles exported this way can be imported via the\n<em>import</em> option as mentioned above.<li><p><strong>Create shortcut.</strong> This option can be used to\ncreate a shortcut for the profile. There are two options:\n<em>Simple</em> and <em>Advanced</em>. When configured with the latter\noption, it prompts the user to select a profile state when the shortcut\nis invoked. The former option, on the other hand, always uses the\ndefault state that was configured when the profile was last\nsaved.</ul></section></section><section id=sec:profile-page class=level2 data-number=2.5><h2 data-number=2.5><span class=header-section-number>2.5</span> <a href=#toc:sec:profile-page>Profile Page</a><a href=#sec:profile-page class=anchor aria-hidden=true></a></h2><p>Profile page displays the configurations for a profile. It also\noffers the options to edit them.<section id=subsec:profile-options-menu class=level3 data-number=2.5.1><h3 data-number=2.5.1><span class=header-section-number>2.5.1</span>\n<a href=#toc:subsec:profile-options-menu>Options Menu</a><a href=#subsec:profile-options-menu class=anchor aria-hidden=true></a></h3><p>The three dots menu in the top-right corner opens the options-menu.\nIt contains several options such as–<ul class=incremental><li><p><strong>Apply.</strong> This option can be used to apply the\nprofile directly. When clicked, a dialog is displayed where it is\npossible to select a <a href=#subsubsec:profile-state>profile\nstate</a>. On selecting one of the states, the profile will be applied\nimmediately.<div class=\"amalert tip\"><p><strong><em>Notice :</em></strong><p>When you apply a profile, if some packages do not match the criteria,\nthey will simply be ignored.</div><li><p><strong>Save.</strong> Save changes to the profile.<li><p><strong>Discard.</strong> Discard any modifications made since\nthe last time it was saved.<li><p><strong>Delete.</strong> Clicking on this option will remove the\nprofile immediately without a warning.<li><p><strong>Duplicate.</strong> This option can be used to duplicate\nthe profile. When clicked, a dialog is displayed where it is possible to\nset a name for the new profile. On clicking “OK”, this page will be\nreloaded by duplicating all the configurations that this profile have.\nHowever, the new profile will not be saved until it is saved\nmanually.<li><p><strong>Create shortcut.</strong> This option can be used to\ncreate a shortcut for the profile. There are two options:\n<em>Simple</em> and <em>Advanced</em>. When configured with the latter\noption, it prompts the user to select a profile state when the shortcut\nis invoked. The former option, on the other hand, always uses the\ndefault state that was configured when the profile was last\nsaved.</ul></section><section id=subsec:profile-apps-tab class=level3 data-number=2.5.2><h3 data-number=2.5.2><span class=header-section-number>2.5.2</span>\n<a href=#toc:subsec:profile-apps-tab>Apps Tab</a><a href=#subsec:profile-apps-tab class=anchor aria-hidden=true></a></h3><p>Apps tab lists the packages configured for this profile. Packages can\nbe added or removed using the <em>plus</em> button located near the\nbottom of the screen. A package can also be removed by long clicking on\nit (in which case, a popup will be displayed with the only option,\n<em>delete</em>).</section><section id=subsec:profile-configurations-tab class=level3 data-number=2.5.3><h3 data-number=2.5.3><span class=header-section-number>2.5.3</span>\n<a href=#toc:subsec:profile-configurations-tab>Configurations\nTab</a><a href=#subsec:profile-configurations-tab class=anchor aria-hidden=true></a></h3><p>Configurations tab can be used to configure the selected\npackages.<section id=profile-id class=level4 data-number=2.5.3.1><h4 data-number=2.5.3.1><span class=header-section-number>2.5.3.1</span> Profile ID<a href=#profile-id class=anchor aria-hidden=true></a></h4><p>The unique ID for this profile, currently set based on the profile\nname. The profile ID can be used to <a href=#subsec:triggering-a-profile>trigger the profile</a> from a\nthird-party application.</section><section id=comment class=level4 data-number=2.5.3.2><h4 data-number=2.5.3.2><span class=header-section-number>2.5.3.2</span> Comment<a href=#comment class=anchor aria-hidden=true></a></h4><p>This is the text that will be displayed in the <a href=#sec:profiles-page>profiles page</a>. If not set, the current\nconfigurations will be displayed instead.</section><section id=subsubsec:profile-state class=level4 data-number=2.5.3.3><h4 data-number=2.5.3.3><span class=header-section-number>2.5.3.3</span> State<a href=#subsubsec:profile-state class=anchor aria-hidden=true></a></h4><p>Denotes how certain configured options will behave by default. For\ninstance, if <em>disable</em> option is turned on, the applications will\nbe disabled if the state is <em>on</em> and will be enabled if the state\nis <em>off</em>. Currently, it only supports <em>on</em> and\n<em>off</em> values.</section><section id=users class=level4 data-number=2.5.3.4><h4 data-number=2.5.3.4><span class=header-section-number>2.5.3.4</span> Users<a href=#users class=anchor aria-hidden=true></a></h4><p>Select users for which is the profile will be applied. All users are\nselected by default.</section><section id=components class=level4 data-number=2.5.3.5><h4 data-number=2.5.3.5><span class=header-section-number>2.5.3.5</span> Components<a href=#components class=anchor aria-hidden=true></a></h4><p>This behaves the same way as the <a href=#subsec:block-components-dots>Block Components…</a> option does\nin the 1-Click Ops page. However, the blocking here is only applied to\nthe selected packages. If the <a href=#subsubsec:profile-state>state</a> is <em>on</em>, the components\nwill be blocked, and if the state is <em>off</em>, the components will\nbe unblocked. The option can be disabled (regardless of the inserted\nvalues) by clicking on the <em>disabled</em> button on the input\ndialog.<div class=seealso-inline><p><em>Voir aussi : <span><a href=#subsec:faq:what-are-app-components>What are the app\ncomponents?</a></span></em></div></section><section id=app-ops class=level4 data-number=2.5.3.6><h4 data-number=2.5.3.6><span class=header-section-number>2.5.3.6</span> App Ops<a href=#app-ops class=anchor aria-hidden=true></a></h4><p>This behaves the same way as the <a href=#subsec:set-mode-for-app-ops-dots>Set Mode for App Ops…</a>\noption does in the 1-Click Ops page. However, the operation here is only\napplied to the selected packages. If the <a href=#subsubsec:profile-state>state</a> is <em>on</em>, the app ops\nwill be denied (i.e. ignored), and if the state is <em>off</em>, the app\nops will be allowed. The option can be disabled (regardless of the\ninserted values) by clicking on the <em>disable</em> button in the input\ndialog.</section><section id=permissions class=level4 data-number=2.5.3.7><h4 data-number=2.5.3.7><span class=header-section-number>2.5.3.7</span> Permissions<a href=#permissions class=anchor aria-hidden=true></a></h4><p>This option can be used to grant or revoke certain permissions from\nthe selected packages. Like others above, permissions must be separated\nby white spaces. If the <a href=#subsubsec:profile-state>state</a> is\n<em>on</em>, the permissions will be revoked, and if the state is\n<em>off</em>, the permissions will be allowed. The option can be\ndisabled (regardless of the inserted values) by clicking on the\n<em>disable</em> button in the input dialog.</section><section id=backuprestore class=level4 data-number=2.5.3.8><h4 data-number=2.5.3.8><span class=header-section-number>2.5.3.8</span> Backup/Restore<a href=#backuprestore class=anchor aria-hidden=true></a></h4><p>This option can be used to take a backup of the selected applications\nand its data or restore them. Two options are available here: <em>Backup\noptions</em> and <em>backup name</em>.<ul class=incremental><li><p><strong>Backup options.</strong> Same as the <a href=#subsec:backup-restore-backup-options>backup options</a> of the\nbackup/restore feature. If not set, the default options will be\nused.<li><p><strong>Backup name.</strong> Set a custom name for the backup.\nIf the backup name is set, each time a backup is made, it will be given\na unique name with backup-name as the suffix. This behaviour will be\nfixed in a future release. Leave this field empty for regular “base”\nbackups (also, make sure not to enable <em>backup multiple</em> in the\nbackup options).</ul><p>If the <a href=#subsubsec:profile-state>state</a> is <em>on</em>,\nthe packages will be backed up, and if the state is <em>off</em>, the\npackages will be restored. The option can be disabled by clicking on the\n<em>disable</em> button in the input dialog.</section><section id=export-blocking-rules class=level4 data-number=2.5.3.9><h4 data-number=2.5.3.9><span class=header-section-number>2.5.3.9</span> Export Blocking Rules<a href=#export-blocking-rules class=anchor aria-hidden=true></a></h4><div class=\"amalert danger\"><p><strong><em>Danger :</em></strong><p>This option is not yet implemented.</div></section><section id=freeze class=level4 data-number=2.5.3.10><h4 data-number=2.5.3.10><span class=header-section-number>2.5.3.10</span> Freeze<a href=#freeze class=anchor aria-hidden=true></a></h4><p>Allow freezing or unfreezing the selected packages depending on the\nvalue of the <a href=#subsubsec:profile-state>state</a>. If the state\nis <em>on</em>, the packages will be frozen, and if the state is\n<em>off</em>, they will be unfrozen.</section><section id=force-stop class=level4 data-number=2.5.3.11><h4 data-number=2.5.3.11><span class=header-section-number>2.5.3.11</span> Force-stop<a href=#force-stop class=anchor aria-hidden=true></a></h4><p>Allow the selected packages to be force-stopped.</section><section id=clear-cache class=level4 data-number=2.5.3.12><h4 data-number=2.5.3.12><span class=header-section-number>2.5.3.12</span> Clear Cache<a href=#clear-cache class=anchor aria-hidden=true></a></h4><p>Enable clearing cache for the selected packages.</section><section id=clear-data class=level4 data-number=2.5.3.13><h4 data-number=2.5.3.13><span class=header-section-number>2.5.3.13</span> Clear Data<a href=#clear-data class=anchor aria-hidden=true></a></h4><p>Enable clearing data for the selected packages.</section><section id=block-trackers class=level4 data-number=2.5.3.14><h4 data-number=2.5.3.14><span class=header-section-number>2.5.3.14</span> Block Trackers<a href=#block-trackers class=anchor aria-hidden=true></a></h4><p>Enable blocking or unblocking of the tracker components from the\nselected packages depending on the value of the <a href=#subsubsec:profile-state>state</a>. If the state is <em>on</em>,\nthe trackers will be blocked, and if the state is <em>off</em>, the\ntrackers will be unblocked.</section><section id=save-apk class=level4 data-number=2.5.3.15><h4 data-number=2.5.3.15><span class=header-section-number>2.5.3.15</span> Save APK<a href=#save-apk class=anchor aria-hidden=true></a></h4><p>Enable saving APK files at <code>AppManager/apks</code> (or in the\ndirectory selected in the settings page) of the selected packages.</section></section></section><section id=sec:settings-page class=level2 data-number=2.6><h2 data-number=2.6><span class=header-section-number>2.6</span> <a href=#toc:sec:settings-page>Settings Page</a><a href=#sec:settings-page class=anchor aria-hidden=true></a></h2><p>Settings page can be used to customise the behaviour of App\nManager.<section id=subsec:language class=level3 data-number=2.6.1><h3 data-number=2.6.1><span class=header-section-number>2.6.1</span>\n<a href=#toc:subsec:language>Language</a><a href=#subsec:language class=anchor aria-hidden=true></a></h3><p>Configure in-app language. App Manager currently supports 22\n(twenty-two) languages.</section><section id=subsec:appearance class=level3 data-number=2.6.2><h3 data-number=2.6.2><span class=header-section-number>2.6.2</span>\n<a href=#toc:subsec:appearance>Appearance</a><a href=#subsec:appearance class=anchor aria-hidden=true></a></h3><section id=subsubsec:app-theme class=level4 data-number=2.6.2.1><h4 data-number=2.6.2.1><span class=header-section-number>2.6.2.1</span> App Theme<a href=#subsubsec:app-theme class=anchor aria-hidden=true></a></h4><p>Configure in-app theme.</section><section id=subsubsec:pure-black-theme class=level4 data-number=2.6.2.2><h4 data-number=2.6.2.2><span class=header-section-number>2.6.2.2</span> Pure Black Theme<a href=#subsubsec:pure-black-theme class=anchor aria-hidden=true></a></h4><p>Whether to use a black background instead of the material themed\nbackground.</section><section id=subsubsec:layout-direction class=level4 data-number=2.6.2.3><h4 data-number=2.6.2.3><span class=header-section-number>2.6.2.3</span> Layout Direction<a href=#subsubsec:layout-direction class=anchor aria-hidden=true></a></h4><p>Change layout direction, either left to right or right to left. This\nis usually set using the selected language but not everybody prefers the\nsame direction.</section><section id=subsubsec:enable/disable-features class=level4 data-number=2.6.2.4><h4 data-number=2.6.2.4><span class=header-section-number>2.6.2.4</span> Enable/Disable Features<a href=#subsubsec:enable/disable-features class=anchor aria-hidden=true></a></h4><p>Enable or disable certain features in App Manager, such as<ul class=incremental><li><p><strong>Interceptor</strong><li><p><strong>Manifest viewer</strong><li><p><strong>Scanner</strong><li><p><strong>Package installer</strong><li><p><strong>Usage access.</strong> With this feature turned off, App\nManager will never ask for the <em>Usage Access</em>\npermission.<li><p><strong>Log viewer</strong><li><p><strong>App explorer.</strong> The “Explore” option will not be\navailable while trying to open an APK file.<li><p><strong>App info.</strong> The “App info” option displayed while\ntrying to open an APK file.<li><p><strong>Code Editor</strong><li><p><strong>VirusTotal</strong></ul></section></section><section id=subsec:privacy class=level3 data-number=2.6.3><h3 data-number=2.6.3><span class=header-section-number>2.6.3</span>\n<a href=#toc:subsec:privacy>Privacy</a><a href=#subsec:privacy class=anchor aria-hidden=true></a></h3><section id=subsubsec:screen-lock class=level4 data-number=2.6.3.1><h4 data-number=2.6.3.1><span class=header-section-number>2.6.3.1</span> Screen Lock<a href=#subsubsec:screen-lock class=anchor aria-hidden=true></a></h4><p>Lock App Manager using Android screen lock provided a screen lock is\nconfigured.<div class=\"amalert warning\"><p><strong><em>Warning :</em></strong><p>If screen lock is disabled in Android after enabling this setting,\nApp Manager will not open until it is enabled again.</div></section><section id=subsubsec:run-am-in-background class=level4 data-number=2.6.3.2><h4 data-number=2.6.3.2><span class=header-section-number>2.6.3.2</span> Run App Manager in the\nBackground<a href=#subsubsec:run-am-in-background class=anchor aria-hidden=true></a></h4><p>Whether to run App Manager in the background to reduce the\ninitialisation delay. On certain devices, this can also help if you’re\nfrequently disconnected from ADB.</section><section id=subsubsec:use-the-internet class=level4 data-number=2.6.3.3><h4 data-number=2.6.3.3><span class=header-section-number>2.6.3.3</span> Use the Internet<a href=#subsubsec:use-the-internet class=anchor aria-hidden=true></a></h4><p>Whether to activate the Internet features in App Manager. This\ncurrently include VirusTotal and Pithus scanning in the <a href=#sec:scanner-page>Scanner page</a>.</section><section id=subsubsec:auth-manager class=level4 data-number=2.6.3.4><h4 data-number=2.6.3.4><span class=header-section-number>2.6.3.4</span> Authorization Manager<a href=#subsubsec:auth-manager class=anchor aria-hidden=true></a></h4><p>This setting allows a third-party application to get access to\ncertain features, such as profiles.</section></section><section id=subsec:mode-of-operation class=level3 data-number=2.6.4><h3 data-number=2.6.4><span class=header-section-number>2.6.4</span>\n<a href=#toc:subsec:mode-of-operation>Mode of Operation</a><a href=#subsec:mode-of-operation class=anchor aria-hidden=true></a></h3><p>Mode of operation defines how App Manager works as a whole. It has\nthe following options:<ul class=incremental><li><p><strong>Auto.</strong> Let App Manager decide the suitable\noption. Although this is the default option, non-rooted users should use\nthe <em>no-root</em> mode.<li><p><strong>Root.</strong> Operate App Manager in root mode. App\nManager will fall back to <em>no-root</em> mode if root is not detected,\nor in rare cases when Binder communication through root is disabled\n(e.g. in <a href=https://github.com/MuntashirAkon/AppManager/issues/606>Phh\nSuperUser</a>).<li><p><strong>ADB over TCP.</strong> Operate App Manager in ADB mode\nvia <a href=#sec:adb-over-tcp>ADB over TCP</a>. App Manager will fall\nback to <em>no-root</em> mode if ADB over TCP is not enabled.<li><p><strong>Wireless debugging.</strong> Enable ADB via Wireless\nDebugging. It will try to connect to the configured port automatically\nat first. On failure, it will ask the user to either pair or connect to\nthe ADB daemon manually. App Manager will fall back to <em>no-root</em>\nmode if it fails to connect to the ADB daemon this way.<div class=\"amalert tip\"><p><strong><em>Info :</em></strong><p>This option is only displayed in devices running Android 11 or later\nas Wireless Debugging was introduced in Android 11.</div><li><p><strong>No-root.</strong> Operate App Manager in no-root mode.\nWhile App Manager performs better in this mode, all the root- or\nADB-specific features will be disabled.</ul><p>It also displays the actual mode of operation at the top. The actual\nmode of operations are <em>root</em>, <em>ABD</em> and\n<em>no-root</em>.<div class=\"amalert tip\"><p><strong><em>Notice :</em></strong><p>“Remote service” is only required for ADB users or when you use the\ncustom commands.</div></section><section id=subsec:apk-signing class=level3 data-number=2.6.5><h3 data-number=2.6.5><span class=header-section-number>2.6.5</span>\n<a href=#toc:subsec:apk-signing>APK Signing</a><a href=#subsec:apk-signing class=anchor aria-hidden=true></a></h3><section id=signature-schemes class=level4 data-number=2.6.5.1><h4 data-number=2.6.5.1><span class=header-section-number>2.6.5.1</span> Signature Schemes<a href=#signature-schemes class=anchor aria-hidden=true></a></h4><p>Configure the <a href=https://source.android.com/security/apksigning>signature\nschemes</a> to be used when APK signing is enabled. v1 and v2 signature\nschemes are enabled by default, but v3 should also be enabled to ensure\nproper security in Android 9 or later.</section><section id=signing-key class=level4 data-number=2.6.5.2><h4 data-number=2.6.5.2><span class=header-section-number>2.6.5.2</span> Signing Key<a href=#signing-key class=anchor aria-hidden=true></a></h4><p>Configure the signing key for signing APK files. Keys from an\nexisting KeyStore can be imported to App Manager, or a new key can be\ngenerated.<div class=\"amalert tip\"><p><strong><em>Tip :</em></strong><p>If you need to use the key in the future, it is recommended that you\ncreate a KeyStore yourself and import the key here. Without a proper\nbackup, keys generated within App Manager are at the risk of being\ndeleted.</div></section><section id=align-apk-files class=level4 data-number=2.6.5.3><h4 data-number=2.6.5.3><span class=header-section-number>2.6.5.3</span> Align APK Files<a href=#align-apk-files class=anchor aria-hidden=true></a></h4><p>Performs zip alignment when App Manager signs an APK file. Zip\nalignment stores the files in the APK file (which is actually a zip\nfile) in a way that a zip file reader can access the files quite easily\nusing random access instead of loading the entire APK file in the\nmemory, which results in the reduction of Android’s memory usage. Note\nthat this step is required if an application’s manifest has\n<code>extractNativeLibs</code> set to <code>true</code>.</section></section><section id=subsec:installer class=level3 data-number=2.6.6><h3 data-number=2.6.6><span class=header-section-number>2.6.6</span>\n<a href=#toc:subsec:installer>Installer</a><a href=#subsec:installer class=anchor aria-hidden=true></a></h3><p>Configure the default behaviour of the installer. You can also find\nmost of the settings by clicking on the <em>cog</em> icon when you\ninstall an application.<section id=install-location class=level4 data-number=2.6.6.1><h4 data-number=2.6.6.1><span class=header-section-number>2.6.6.1</span> Install Location<a href=#install-location class=anchor aria-hidden=true></a></h4><p>Define APK installation location. This can be one of <em>auto</em>,\n<em>internal only</em> and <em>prefer external</em>. In newer Android\nversions, selecting the last option does not guarantee that the\napplication will be installed in the external storage.</section><section id=block-trackers-1 class=level4 data-number=2.6.6.2><h4 data-number=2.6.6.2><span class=header-section-number>2.6.6.2</span> Block Trackers<a href=#block-trackers-1 class=anchor aria-hidden=true></a></h4><p>Whether to block the tracking components immediately after installing\nthe application.</section><section id=display-changes class=level4 data-number=2.6.6.3><h4 data-number=2.6.6.3><span class=header-section-number>2.6.6.3</span> Display Changes<a href=#display-changes class=anchor aria-hidden=true></a></h4><p>Whether to display changes in version, trackers, components,\npermissions, signatures, SDK, etc. in a version controlled style before\ninstalling the application if the application has already been\ninstalled.</section><section id=installer-app class=level4 data-number=2.6.6.4><h4 data-number=2.6.6.4><span class=header-section-number>2.6.6.4</span> Installer App<a href=#installer-app class=anchor aria-hidden=true></a></h4><p>Select the installer application. This is useful for applications\nthat explicitly checks the installer as a way to verify if the\napplication is installed legitimately. This only works for root or ADB\nusers.<div class=\"amalert tip\"><p><strong><em>Notice :</em></strong><p>While checking for the installer might seem a legitimate concern for\nan application, the Android framework already deals with this during the\ninstallation. Checking for the installer is simply the wrong way to\nprove the legitimacy of the source of an application.</div></section><section id=sign-apk class=level4 data-number=2.6.6.5><h4 data-number=2.6.6.5><span class=header-section-number>2.6.6.5</span> Sign APK<a href=#sign-apk class=anchor aria-hidden=true></a></h4><p>Whether to sign the APK files before installing the application. A\nsigning key has to be added or generated before this option can be\nenabled. This can be done in the <a href=#subsec:apk-signing>APK\nsigning</a> page.</section><section id=immediately-perform-dex-optimization class=level4 data-number=2.6.6.6><h4 data-number=2.6.6.6><span class=header-section-number>2.6.6.6</span> Immediately Perform DEX\nOptimization<a href=#immediately-perform-dex-optimization class=anchor aria-hidden=true></a></h4><p>Whether to perform DEX optimization immediately after installing the\napplication. This can be useful for heavy applications, such as the\ngaming applications.</section><section id=install-in-the-background class=level4 data-number=2.6.6.7><h4 data-number=2.6.6.7><span class=header-section-number>2.6.6.7</span> Install in the Background<a href=#install-in-the-background class=anchor aria-hidden=true></a></h4><p>Whether to always install applications in the background. A\nnotification will be issued once the installation is finished.</section></section><section id=subsec:backup/restore class=level3 data-number=2.6.7><h3 data-number=2.6.7><span class=header-section-number>2.6.7</span>\n<a href=#toc:subsec:backup/restore>Back up/Restore</a><a href=#subsec:backup/restore class=anchor aria-hidden=true></a></h3><p>Settings related to <a href=#sec:backup-restore>back\nup/restore</a>.<section id=compression-method class=level4 data-number=2.6.7.1><h4 data-number=2.6.7.1><span class=header-section-number>2.6.7.1</span> Compression method<a href=#compression-method class=anchor aria-hidden=true></a></h4><p>Set the compression method to be used during backups. App Manager\nsupports GZip, BZip2 and Zstandard compression methods, GZip being the\ndefault compression method. It doesn’t affect the restore of an existing\nbackup.</section><section id=subsubsec:settings-backup-options class=level4 data-number=2.6.7.2><h4 data-number=2.6.7.2><span class=header-section-number>2.6.7.2</span> Backup Options<a href=#subsubsec:settings-backup-options class=anchor aria-hidden=true></a></h4><p>Customise the <em>back up/restore dialog</em> displayed while taking\na backup.<div class=seealso-inline><p><em>Voir aussi : <span><a href=#subsec:backup-restore-backup-options>Backup\noptions</a></span></em></div></section><section id=backup-apps-with-android-keystore class=level4 data-number=2.6.7.3><h4 data-number=2.6.7.3><span class=header-section-number>2.6.7.3</span> Backup apps with Android\nKeyStore<a href=#backup-apps-with-android-keystore class=anchor aria-hidden=true></a></h4><p>Allow backup of applications that has entries in the Android\nKeyStore. This option is disabled by default because a few apps (such as\nSignal or Element) may crash if restored.</section><section id=subsubsec:settings-encryption class=level4 data-number=2.6.7.4><h4 data-number=2.6.7.4><span class=header-section-number>2.6.7.4</span> Encryption<a href=#subsubsec:settings-encryption class=anchor aria-hidden=true></a></h4><p>Set an encryption method for the backups. App Manager currently\nsupports OpenPGP (via <a href=https://f-droid.org/packages/org.sufficientlysecure.keychain/>OpenKeyChain</a>),\nAES, RSA and ECC. Like <a href=#subsec:apk-signing>APK signing</a>,\nThe AES, RSA and ECC keys are stored in the KeyStore and can be imported\nfrom other KeyStores.<div class=\"amalert danger\"><p><strong><em>Danger :</em></strong><p>For your own safety, it is not recommended generating RSA and ECC\nkeys inside App Manager. Instead, they should be imported from a\nKeyStore stored in a secure place.<br>In case of AES, the generated key should be stored in a secure place,\nsuch as in a password manager.</div></section><section id=subsubsec:backup-volume class=level4 data-number=2.6.7.5><h4 data-number=2.6.7.5><span class=header-section-number>2.6.7.5</span> Backup Volume<a href=#subsubsec:backup-volume class=anchor aria-hidden=true></a></h4><p>Select the storage where the backups will be stored. This is also\nwhere logs and exported APK files are saved.<div class=\"amalert tip\"><p><strong><em>Notice :</em></strong><p>The backup volume only specifies the storage, not the path. Backups\nare traditionally stored in the <code>AppManager</code> folder inside\nthe storage path. But when the path is selected using Storage Access\nFramework (SAF), the selected path or directory is used directly.</div></section><section id=import-backups class=level4 data-number=2.6.7.6><h4 data-number=2.6.7.6><span class=header-section-number>2.6.7.6</span> Import Backups<a href=#import-backups class=anchor aria-hidden=true></a></h4><p>Import backups from old and discontinued projects such as Titanium\nBackup, OAndBackup, and Swift Backup (version 3.0 to 3.2). The backups\nare not deleted after importing to prevent data loss in case the\nimported backups cannot be restored properly.</section></section><section id=subsec:rules class=level3 data-number=2.6.8><h3 data-number=2.6.8><span class=header-section-number>2.6.8</span>\n<a href=#toc:subsec:rules>Rules</a><a href=#subsec:rules class=anchor aria-hidden=true></a></h3><section id=subsubsec:instant-component-blocking class=level4 data-number=2.6.8.1><h4 data-number=2.6.8.1><span class=header-section-number>2.6.8.1</span> Instant Component\nBlocking<a href=#subsubsec:instant-component-blocking class=anchor aria-hidden=true></a></h4><p>By default, blocking rules are not applied unless they are applied\nexplicitly in <a href=#sec:app-details-page>the App Details page</a>\nfor any application. After enabling this option, all (old and new) rules\nare applied immediately for all applications without explicitly enabling\nblocking for an application.<div class=seealso-inline><p><em>Voir aussi : <span><a href=#subsec:faq:what-is-instant-component-blocking>FAQ: What is\ninstant component blocking?</a></span></em></div></section><section id=importexport-blocking-rules class=level4 data-number=2.6.8.2><h4 data-number=2.6.8.2><span class=header-section-number>2.6.8.2</span> Import/Export Blocking\nRules<a href=#importexport-blocking-rules class=anchor aria-hidden=true></a></h4><p>It is possible to import or export blocking rules within App Manager\nfor all applications. The types of rules (components, app ops or\npermissions) that should be imported or exported can also be selected.\nIt is also possible to import blocking rules from <a href=https://github.com/lihenggui/blocker>Blocker</a> and <a href=https://github.com/tuyafeng/Watt>Watt</a>. If it is necessary to\nexport blocking rules for a single application, the corresponding <a href=#sec:app-details-page>App Details page</a> can be used to export\nrules, or for multiple apps, <a href=#subsec:batch-operations>batch\noperations</a> can be used.<div class=seealso-inline><p><em>Voir aussi : <span><a href=#sec:rules-specification>Rules\nSpecification</a></span></em></div><section id=export class=level5 data-number=2.6.8.2.1><h5 data-number=2.6.8.2.1><span class=header-section-number>2.6.8.2.1</span> Export<a href=#export class=anchor aria-hidden=true></a></h5><p>Export blocking rules for all applications configured within App\nManager. This may include <a href=#subsec:faq:what-are-app-components>app components</a>, app ops\nand permissions based on the options selected in the multi-choice\noptions.</section><section id=import class=level5 data-number=2.6.8.2.2><h5 data-number=2.6.8.2.2><span class=header-section-number>2.6.8.2.2</span> Import<a href=#import class=anchor aria-hidden=true></a></h5><p>Import previously exported blocking rules from App Manager. Similar\nto export, this may include <a href=#subsec:faq:what-are-app-components>app components</a>, app ops\nand permissions based on the options selected in the multi-choice\noptions.</section><section id=par:import-existing-rules class=level5 data-number=2.6.8.2.3><h5 data-number=2.6.8.2.3><span class=header-section-number>2.6.8.2.3</span> Import Existing Rules<a href=#par:import-existing-rules class=anchor aria-hidden=true></a></h5><p>Add components disabled by other applications to App Manager. App\nManager only keeps track of the components disabled within App Manager.\nIf application components are blocked or disabled by other tools or\napplications, this option can be utilised to import them. On clicking\nthis option, App Manager will find the components potentially disabled\nby other applications or tools and list only the name of the\napplications along with the number of matched components. For safety,\nall the applications are unselected by default. They have to be selected\nmanually, and the blocking has to be re-applied via App Manager.<div class=\"amalert danger\"><p><strong><em>Caution :</em></strong><p>Be careful when using this tool as there can be many false positives.\nChoose only the applications that you are certain about.</div></section><section id=import-from-watt class=level5 data-number=2.6.8.2.4><h5 data-number=2.6.8.2.4><span class=header-section-number>2.6.8.2.4</span> Import from Watt<a href=#import-from-watt class=anchor aria-hidden=true></a></h5><p>Import configuration files from <a href=https://github.com/tuyafeng/Watt>Watt</a>, each file containing\nrules for a single package and file name being the name of the package\nwith <code>.xml</code> extension.<div class=\"amalert tip\"><p><strong><em>Tip :</em></strong><p>Location of configuration files in Watt:\n<code>/sdcard/Android/data/com.tuyafeng.watt/files/ifw</code></div></section><section id=import-from-blocker class=level5 data-number=2.6.8.2.5><h5 data-number=2.6.8.2.5><span class=header-section-number>2.6.8.2.5</span> Import from Blocker<a href=#import-from-blocker class=anchor aria-hidden=true></a></h5><p>Import blocking rules from <a href=https://github.com/lihenggui/blocker>Blocker</a>, each file\ncontaining rules for a single package. These files have a\n<code>.json</code> extension.</section></section><section id=remove-all-rules class=level4 data-number=2.6.8.3><h4 data-number=2.6.8.3><span class=header-section-number>2.6.8.3</span> Remove all rules<a href=#remove-all-rules class=anchor aria-hidden=true></a></h4><p>One-click option to remove all rules configured within App Manager.\nThis will enable all blocked components, app ops will be set to their\ndefault values and permissions will be granted.</section></section><section id=subsec:advanced class=level3 data-number=2.6.9><h3 data-number=2.6.9><span class=header-section-number>2.6.9</span>\n<a href=#toc:subsec:advanced>Advanced</a><a href=#subsec:advanced class=anchor aria-hidden=true></a></h3><section id=subsubsec:selected-users class=level4 data-number=2.6.9.1><h4 data-number=2.6.9.1><span class=header-section-number>2.6.9.1</span> Selected Users<a href=#subsubsec:selected-users class=anchor aria-hidden=true></a></h4><p>This option lets you control the users App Manager should operate on.\nApp Manager operates on all users in root or ADB mode by default.</section><section id=subsubsec:saved-apk-name-format class=level4 data-number=2.6.9.2><h4 data-number=2.6.9.2><span class=header-section-number>2.6.9.2</span> Saved APK Name Format<a href=#subsubsec:saved-apk-name-format class=anchor aria-hidden=true></a></h4><p>Defines the format of the APK name to be used while saving it via\nbatch operations or through profiles. App Manager offers some special\nkeywords enclosed inside <code>%</code> (percentage) signs and available\nbelow the input box. These keywords are:<ul class=incremental><li><p><strong><code>label</code>.</strong> Denotes the name or label of\nthe application. This can be localised to the configured language\ndepending on the app.<li><p><strong><code>package_name</code>.</strong> Denotes the name of\nthe package or application ID, the unique identifier that each\napplication has.<li><p><strong><code>version</code>.</strong> Denotes the current\nversion of the application extracted from its manifest.<li><p><strong><code>version_code</code>.</strong> Denotes the current\nversion code of the application that can be used to separate two\nversions of the same application.<li><p><strong><code>min_sdk</code>.</strong> Denotes the minimum SDK\n(i.e. Android framework version) that the application can operate on.\nThis data is only available since Android 7 (Nougat).<li><p><strong><code>target_sdk</code>.</strong> Denotes the SDK that\nthis application targets. The application can operate on higher SDK but\nonly in the compatibility mode.<li><p><strong><code>datetime</code>.</strong> Denotes the time and date\nwhen the APK is exported.</ul></section><section id=subsubsec:import/export-keystore class=level4 data-number=2.6.9.3><h4 data-number=2.6.9.3><span class=header-section-number>2.6.9.3</span> Import/Export Keystore<a href=#subsubsec:import/export-keystore class=anchor aria-hidden=true></a></h4><p>Import or export the KeyStore used by App Manager. This is a Bouncy\nCastle KeyStore with <code>bks</code> extension. Therefore, other\nKeyStore such as Java KeyStore (JKS) or PKCS #12 are not supported. If a\nkey is needed to be imported from such a KeyStore, the relevant options\nshould be should as specified above.</section></section><section id=subsec:device-info class=level3 data-number=2.6.10><h3 data-number=2.6.10><span class=header-section-number>2.6.10</span> <a href=#toc:subsec:device-info>About the device</a><a href=#subsec:device-info class=anchor aria-hidden=true></a></h3><p>Display Android version, security, CPU, GPU, battery, memory, screen,\nlanguages, user info, etc.</section></section><section id=sec:scanner-page class=level2 data-number=2.7><h2 data-number=2.7><span class=header-section-number>2.7</span> <a href=#toc:sec:scanner-page>Scanner Page</a><a href=#sec:scanner-page class=anchor aria-hidden=true></a></h2><p><strong>Scanner page</strong> appears after clicking on the\n<em>scanner</em> button in the <a href=#subsec:app-info-tab>App Info\ntab</a>. External APK files can also be opened for scanning from file\nmanagers, web browsers, etc.<p>It scans for trackers and libraries, and displays the number of\ntrackers and libraries as a summary. It also displays checksums of the\nAPK file as well as the signing certificates. If VirusTotal is\nconfigured in the settings, it also attempts to retrieve reports from\nVirusTotal, or uploads the APK file if it is not in the database. It\nalso display a link to the <a href=https://beta.pithus.org>Pithus</a>\nreport provided the Internet features are enabled.<div class=\"amalert danger\"><p><strong><em>Disclaimer :</em></strong><p>App Manager only scans an application statically without prejudice.\nThe application may provide the options for opting out, or in some\ncases, certain features of the tracker may not be used at all by the\napplication (e.g. F-Droid), or some applications may simply use them as\nplaceholders to prevent the breaking of certain features (e.g. Fennec\nF-Droid). <strong>The intention of the scanner is to give you an idea\nabout what the APK might contain. It should be taken as an initial step\nfor further investigations.</strong></div><p>Clicking on the first item (i.e. number of classes) opens a new page\ncontaining a list of tracker classes for the application. All classes\ncan also be viewed by clicking on the <em>Toggle Class Listing</em>\nmenu. The SMALI or Java version of the class can be viewed by simply\nclicking on an item.<div class=\"amalert tip\"><p><strong><em>Notice :</em></strong><p>Due to various limitations, it is not possible to scan all the\ncomponents of an APK file. This is especially true if an APK is highly\nobfuscated or packed. The scanner also does not check strings (or\nwebsite signatures).</div><p>The second item lists the number of trackers along with their names.\nClicking on the item displays a dialog containing the name of trackers,\nmatched signatures, and the number of classes against each signature.\nSome tracker names may have <span class=\"math inline\"><sup>2</sup></span> prefix which indicates that the\ntrackers are in the <a href=https://etip.exodus-privacy.eu.org>ETIP</a> stand-by list, i.e.,\nwhether they are actual trackers is still being investigated.<p>The third item lists the number of libraries along with their names.\nThe information are mostly taken from <a href=https://gitlab.com/IzzyOnDroid/repo>IzzyOnDroid repo</a>.<div class=seealso-inline><p><em>Voir aussi : <span><a href=#subsec:tracker-classes-versus-tracker-components>FAQ: Tracker\nclasses vs tracker components</a></span></em></div></section><section id=sec:interceptor-page class=level2 data-number=2.8><h2 data-number=2.8><span class=header-section-number>2.8</span> <a href=#toc:sec:interceptor-page>Interceptor Page</a><a href=#sec:interceptor-page class=anchor aria-hidden=true></a></h2><p>Interceptor can be used to intercept communication between\napplications using <code>Intent</code>. It works as a man-in-the-middle\nbetween the source and the destination applications. It offers a\nfeature-complete user interface for editing <code>Intent</code>s.<div class=\"amalert warning\"><p><strong><em>Warning :</em></strong><p>Interceptor only works for <em>implicit</em> intents where the <a href=#subsec:faq:what-are-app-components>app component</a> isn’t\nspecified.</div><div class=seealso><p><em>Voir aussi :</em><ul class=incremental><li><p><a href=https://developer.android.com/guide/components/intents-common>Common\nIntents</a><li><p><a href=https://developer.android.com/guide/components/intents-filters>Intents\nand Intent Filters</a></ul></div><section id=subsec:intent-filters class=level3 data-number=2.8.1><h3 data-number=2.8.1><span class=header-section-number>2.8.1</span>\n<a href=#toc:subsec:intent-filters>Intent Filters</a><a href=#subsec:intent-filters class=anchor aria-hidden=true></a></h3><p>Intent filters are used by the applications to specify the tasks they\nare able to perform or the tasks they are going to perform using other\napplications. For example, when you’re opening a PDF file using a file\nmanager, the file manager will try to find the applications to open the\nPDF with. To find the right applications, the file manager will create\nan Intent with filters such as the MIME type and ask the system to\nretrieve the applications capable of opening this filter. The system\nwill search through the Manifest of the installed applications to match\nthe filter and list the application components that are able to open\nthis filter (in our case the PDF). At this, either the file manager will\nopen the desired application component all by itself or use a system\nprovided option to open it. If multiple application components are able\nto open it and no default is set, you may get a prompt where you have to\nchoose the right application component.<section id=subsubsec:action class=level4 data-number=2.8.1.1><h4 data-number=2.8.1.1><span class=header-section-number>2.8.1.1</span> Action<a href=#subsubsec:action class=anchor aria-hidden=true></a></h4><p>Action specifies the generic action to perform such as\n<code>android.intent.action.VIEW</code>. Applications often declare the\nrelevant actions in the Manifest file to catch the desired Intents. The\naction is particularly useful for broadcast Intent where it plays a\nvital rule. In other cases, it works as an initial way to filter out the\nrelevant application components. Generic actions such as\n<code>android.intent.action.VIEW</code> and\n<code>android.intent.action.SEND</code> are widely used by applications.\nHence, setting this alone may match many application components.</section><section id=subsubsec:data class=level4 data-number=2.8.1.2><h4 data-number=2.8.1.2><span class=header-section-number>2.8.1.2</span> Data<a href=#subsubsec:data class=anchor aria-hidden=true></a></h4><p>Data is originally known as URI (Uniform Resource Identifier) defined\nin <a href=http://www.faqs.org/rfcs/rfc2396.html>RFC 2396</a>. It can\nbe web links, file location, or a special feature called\n<em>content</em>. Contents are an Android feature managed by the <a href=#subsubsec:providers>content providers</a>. Data are often\nassociated with a <a href=#subsubsec:mime-type>MIME type</a>.<p>Examples:<pre><code>http://search.disroot.org/?q=URI%20in%20Android%20scheme&amp;categories=general&amp;language=en-US\nhttps://developer.android.com/reference/android/net/Uri\nfile:///sdcard/AppManager.apk\nmailto:email@example.com\ncontent://io.github.muntashirakon.AppManager.provider/23485af89b08d87e898a90c7e/AppManager.apk</code></pre></section><section id=subsubsec:mime-type class=level4 data-number=2.8.1.3><h4 data-number=2.8.1.3><span class=header-section-number>2.8.1.3</span> MIME Type<a href=#subsubsec:mime-type class=anchor aria-hidden=true></a></h4><p>MIME type of the <a href=#subsubsec:data>data</a>. For example, if\nthe data field is set to <code>file:///sdcard/AppManager.apk</code>, the\nassociated MIME type can be\n<code>application/vnd.android.package-archive</code>.</section><section id=categories class=level4 data-number=2.8.1.4><h4 data-number=2.8.1.4><span class=header-section-number>2.8.1.4</span> Categories<a href=#categories class=anchor aria-hidden=true></a></h4><p>This is similar to <a href=#subsubsec:action>action</a> in the\nsense that it is also used by the system to filter application\ncomponents. This has no further benefits. Unlike <em>action</em>, there\ncan be more than one category. Clicking on the <em>plus</em> button next\nto the title allows adding more categories.</section><section id=flags class=level4 data-number=2.8.1.5><h4 data-number=2.8.1.5><span class=header-section-number>2.8.1.5</span> Flags<a href=#flags class=anchor aria-hidden=true></a></h4><p>Flags are useful in determining how system should behave during the\nlaunch or after the launch of an activity. This should not be touched as\nit requires some technical background. The <em>plus</em> button next to\nthe title can be used to add one or more flags.</section><section id=extras class=level4 data-number=2.8.1.6><h4 data-number=2.8.1.6><span class=header-section-number>2.8.1.6</span> Extras<a href=#extras class=anchor aria-hidden=true></a></h4><p>Extras are the key-value pairs used for supplying additional\ninformation to the destination component. More extras can be added using\nthe <em>plus</em> button next to the title.</section><section id=uri class=level4 data-number=2.8.1.7><h4 data-number=2.8.1.7><span class=header-section-number>2.8.1.7</span> URI<a href=#uri class=anchor aria-hidden=true></a></h4><p>Represents the entire Intent as a URI (e.g. <code>intent://…</code>).\nSome data cannot be converted to string, and as a result, they might not\nappear here.</section></section><section id=subsec:matching-activities class=level3 data-number=2.8.2><h3 data-number=2.8.2><span class=header-section-number>2.8.2</span>\n<a href=#toc:subsec:matching-activities>Matching Activities</a><a href=#subsec:matching-activities class=anchor aria-hidden=true></a></h3><p>List all the activity components that matches the Intent. This is\ninternally determined by the system (rather than App Manager). The\nlaunch button next to each component can be used to launch them directly\nfrom App Manager.</section><section id=subsec:interceptor-reset-to-default class=level3 data-number=2.8.3><h3 data-number=2.8.3><span class=header-section-number>2.8.3</span>\n<a href=#toc:subsec:interceptor-reset-to-default>Reset to\nDefault</a><a href=#subsec:interceptor-reset-to-default class=anchor aria-hidden=true></a></h3><p>Reset the Intent to its initial state.</section><section id=subsec:interceptor-send-edited-intent class=level3 data-number=2.8.4><h3 data-number=2.8.4><span class=header-section-number>2.8.4</span>\n<a href=#toc:subsec:interceptor-send-edited-intent>Send Edited\nIntent</a><a href=#subsec:interceptor-send-edited-intent class=anchor aria-hidden=true></a></h3><p>Resend the edited Intent to the destination application. This may\nopen a list of applications where the desired application is needed to\nbe selected. The result received from the target application will be\nsent to the source application. As a result, the source application will\nnot know if there was a man-in-the-middle.</section></section><section id=sec:shared-preferences-editor-page class=level2 data-number=2.9><h2 data-number=2.9><span class=header-section-number>2.9</span> <a href=#toc:sec:shared-preferences-editor-page>Shared Preferences Editor\nPage</a><a href=#sec:shared-preferences-editor-page class=anchor aria-hidden=true></a></h2><p>Shared preferences can be edited in this page. Clicking any item on\nthe list opens the edit dialog where the item can be edited. The\nfloating action button in the bottom-right corner can be used to add a\nnew item. To save or delete the file, or to discard current changes, the\nrespective options in the menu can be used.</section></section><section id=ch:guides class=level1 data-number=3><h1 data-number=3><span class=header-section-number>3</span> <a href=#toc:ch:guides>Guides</a><a href=#ch:guides class=anchor aria-hidden=true></a></h1><section id=sec:adb-over-tcp class=level2 data-number=3.1><h2 data-number=3.1><span class=header-section-number>3.1</span> <a href=#toc:sec:adb-over-tcp>ADB over TCP</a><a href=#sec:adb-over-tcp class=anchor aria-hidden=true></a></h2><p>Many root-only features can still be used by enabling ADB over TCP.\nTo do that, a PC or Mac is required with Android platform-tools\ninstalled, and an Android phone with developer options & USB\ndebugging enabled.<div class=\"amalert tip\"><p><strong><em>Root users :</em></strong><p>If superuser permission has been granted to App Manager, it can\nalready execute privileged code without any problem. <strong>Therefore,\nroot users do not need to enable ADB over TCP.</strong> But if you\ninsist on using ADB over TCP, you must revoke superuser permission for\nApp Manager.</div><div class=seealso-inline><p><em>Voir aussi : <span><a href=#sec:faq:adb-over-tcp>FAQ: ADB over\nTCP</a></span></em></div><section id=subsec:enable-developer-options class=level3 data-number=3.1.1><h3 data-number=3.1.1><span class=header-section-number>3.1.1</span>\n<a href=#toc:subsec:enable-developer-options>Enable developer\noptions</a><a href=#subsec:enable-developer-options class=anchor aria-hidden=true></a></h3><section id=subsubsec:location-of-developer-options class=level4 data-number=3.1.1.1><h4 data-number=3.1.1.1><span class=header-section-number>3.1.1.1</span> Location of developer\noptions<a href=#subsubsec:location-of-developer-options class=anchor aria-hidden=true></a></h4><p><strong>Developer options</strong> is located in Android\n<strong>Settings</strong>, either directly near the bottom of the page\n(in most ROMs) or under some other settings, such as\n<strong>System</strong> (Google Pixel, Lineage OS, Asus Zenfone 8.0+),\n<strong>Additional Settings</strong> (Xiaomi MIUI, Oppo ColorOS),\n<strong>More Settings</strong> (Vivo FuntouchOS), <strong>More</strong>\n(ZTE Nubia). Unlike other options, it is not visible until explicitly\nenabled by the user. If it is already enabled, you can use the search\nbox in Android <strong>Settings</strong> to locate it as well.</section><section id=how-to-enable-developer-options class=level4 data-number=3.1.1.2><h4 data-number=3.1.1.2><span class=header-section-number>3.1.1.2</span> How to enable developer\noptions<a href=#how-to-enable-developer-options class=anchor aria-hidden=true></a></h4><p>This option is available within Android <strong>Settings</strong> as\nwell but like the location of the developer options, it also differs\nfrom device to device. But in general, you have to find <strong>Build\nnumber</strong> (or <strong>MIUI version</strong> for MIUI ROMs and\n<strong>Software version</strong> for Vivo FuntouchOS,\n<strong>Version</strong> for Oppo ColorOS) and tap it at least 7 (seven)\ntimes until you finally get a message saying <em>You are now a\ndeveloper</em> (you may be prompted to insert pin/password/pattern or\nsolve captchas at this point). In most devices, it is located at the\nbottom of the settings page, inside <strong>About Phone</strong>. But\nthe best way to find it is to use the search box.</section></section><section id=subsec:enable-usb-debugging class=level3 data-number=3.1.2><h3 data-number=3.1.2><span class=header-section-number>3.1.2</span>\n<a href=#toc:subsec:enable-usb-debugging>Enable USB debugging</a><a href=#subsec:enable-usb-debugging class=anchor aria-hidden=true></a></h3><p>After <a href=#subsubsec:location-of-developer-options>locating the\ndeveloper options</a>, enable <strong>Developer option</strong> (if not\nalready). After that, scroll down a bit until you will find the option\n<strong>USB debugging</strong>. Use the toggle button on the right-hand\nside to enable it. At this point, you may get an alert prompt where you\nmay have to click <em>OK</em> to actually enable it. You may also have\nto enable some other options depending on device vendor and ROM. Here\nare some examples:<section id=xiaomi-miui class=level4 data-number=3.1.2.1><h4 data-number=3.1.2.1><span class=header-section-number>3.1.2.1</span> Xiaomi (MIUI)<a href=#xiaomi-miui class=anchor aria-hidden=true></a></h4><p>Enable <strong>USB debugging (Security settings)</strong> as\nwell.</section><section id=huawei-emui class=level4 data-number=3.1.2.2><h4 data-number=3.1.2.2><span class=header-section-number>3.1.2.2</span> Huawei (EMUI)<a href=#huawei-emui class=anchor aria-hidden=true></a></h4><p>Enable <strong>Allow ADB debugging in charge only mode</strong> as\nwell. When connecting to your PC or Mac, you may get a prompt saying\n<strong>Allow access to device data?</strong> in which case click\n<strong>YES, ALLOW ACCESS</strong>.<div class=\"amalert tip\"><p><strong><em>Notice :</em></strong><p>Often the <strong>USB debugging</strong> mode could be disabled\nautomatically by the system. If that’s the case, repeat the above\nprocedure.</div></section><section id=realme class=level4 data-number=3.1.2.3><h4 data-number=3.1.2.3><span class=header-section-number>3.1.2.3</span> Realme<a href=#realme class=anchor aria-hidden=true></a></h4><p>Depending on the device and the version of operating system, you have\nto enable <strong>Disable Permission Monitoring</strong>, or <strong>USB\ndebugging (Security settings)</strong> along with <strong>Install via\nUSB</strong>.</section><section id=oneplus-oxygen-os class=level4 data-number=3.1.2.4><h4 data-number=3.1.2.4><span class=header-section-number>3.1.2.4</span> OnePlus (Oxygen OS)<a href=#oneplus-oxygen-os class=anchor aria-hidden=true></a></h4><p>Depending on the device and the version of operating system, you have\nto enable <strong>Disable Permission Monitoring</strong>.</section><section id=lg class=level4 data-number=3.1.2.5><h4 data-number=3.1.2.5><span class=header-section-number>3.1.2.5</span> LG<a href=#lg class=anchor aria-hidden=true></a></h4><p>Make sure you have <strong>USB tethering</strong> enabled.</section><section id=troubleshooting class=level4 data-number=3.1.2.6><h4 data-number=3.1.2.6><span class=header-section-number>3.1.2.6</span> Troubleshooting<a href=#troubleshooting class=anchor aria-hidden=true></a></h4><p>In case <strong>USB Debugging</strong> is greyed out, you can do the\nfollowing:<ol class=incremental><li><p>Make sure you enabled USB debugging before connecting your phone\nto the PC or Mac via USB cable<li><p>Enable USB tethering after connecting to PC or Mac via USB\ncable<li><p>(For Samsung) If your device is running KNOX, you may have to\nfollow some additional steps. See official documentations or consult\nsupport for further assistant</ol></section></section><section id=subsec:setup-adb-on-pc-or-mac class=level3 data-number=3.1.3><h3 data-number=3.1.3><span class=header-section-number>3.1.3</span>\n<a href=#toc:subsec:setup-adb-on-pc-or-mac>Setup ADB on PC or\nMac</a><a href=#subsec:setup-adb-on-pc-or-mac class=anchor aria-hidden=true></a></h3><p>In order to enable ADB over TCP, you have to set up ADB in your PC or\nMac. <strong><em>Lineage OS users can skip to §<a href=#subsubsec:lineage-os data-reference-type=ref data-reference=subsubsec:lineage-os>3.1.4.1</a>.</em></strong><section id=windows class=level4 data-number=3.1.3.1><h4 data-number=3.1.3.1><span class=header-section-number>3.1.3.1</span> Windows<a href=#windows class=anchor aria-hidden=true></a></h4><ol class=incremental><li><p>Download the latest version of <a href=https://dl.google.com/android/repository/platform-tools-latest-windows.zip>Android\nSDK Platform-Tools</a> for Windows<li><p>Extract the contents of the zip file into any directory (such as\n<code>C:\\</code><span><code>adb</code></span>) and navigate to that\ndirectory using <em>Explorer</em><li><p>Open <strong>Command Prompt</strong>,\n<strong>PowerShell</strong>, or <strong>Terminal</strong> from this\ndirectory. You can do it manually from the start menu or by holding\n<code>Shift</code> and right clicking within the directory in <em>File\nExplorer</em> and then clicking either on <em>Open command window\nhere</em>, or <em>Open PowerShell window here</em> (depending on what\nyou have installed). You can now access ADB by typing <code>adb</code>\n(Command Prompt) or <code>./adb</code> (PowerShell). Do not close this\nwindow yet.</ol><div class=\"amalert tip\"><p><strong><em>Tip :</em></strong><p>If you have <a href=https://learn.microsoft.com/en-us/windows/package-manager/winget/>WinGet</a>\ninstalled, you can install ADB using the following command:<div class=sourceCode id=cb3 data-frame=lines><pre class=\"sourceCode bash\"><code class=\"sourceCode bash\"><span id=cb3-1><a href=#cb3-1 aria-hidden=true tabindex=-1></a><span class=ex>winget</span> install <span class=at>--id</span> Google.PlatformTools</span></code></pre></div><p>After that, you can simply type <code>adb</code> to access ADB.</div></section><section id=macos class=level4 data-number=3.1.3.2><h4 data-number=3.1.3.2><span class=header-section-number>3.1.3.2</span> macOS<a href=#macos class=anchor aria-hidden=true></a></h4><ol class=incremental><li><p>Download the latest version of <a href=https://dl.google.com/android/repository/platform-tools-latest-darwin.zip>Android\nSDK Platform-Tools</a> for macOS<li><p>Extract the contents of the zip file into a directory by clicking\non it. After that, navigate to that directory using <em>Finder</em> and\nlocate <code>adb</code><li><p>Open <strong>Terminal</strong> using <em>Launchpad</em> or\n<em>Spotlight</em> and drag-and-drop <code>adb</code> from the\n<em>Finder</em> window into the <em>Terminal</em> window. Do not close\nthe <em>Terminal</em> window yet</ol><div class=\"amalert tip\"><p><strong><em>Tip :</em></strong><p>If you have <a href=https://brew.sh>Homebrew</a> installed, you can\ninstall ADB using the following command:<div class=sourceCode id=cb4 data-frame=lines><pre class=\"sourceCode bash\"><code class=\"sourceCode bash\"><span id=cb4-1><a href=#cb4-1 aria-hidden=true tabindex=-1></a><span class=ex>brew</span> install <span class=at>--cask</span> android-platform-tools</span></code></pre></div><p>After that, you can simply type <code>adb</code> in any\n<em>Terminal</em> window to access ADB.</div></section><section id=linux class=level4 data-number=3.1.3.3><h4 data-number=3.1.3.3><span class=header-section-number>3.1.3.3</span> Linux<a href=#linux class=anchor aria-hidden=true></a></h4><ol class=incremental><li><p>In your favourite terminal emulator, run the following\ncommand:<div class=sourceCode id=cb5 data-frame=lines data-autogobble><pre class=\"sourceCode bash\"><code class=\"sourceCode bash\"><span id=cb5-1><a href=#cb5-1 aria-hidden=true tabindex=-1></a><span class=bu>cd</span> ~/Downloads <span class=kw>&amp;&amp;</span> <span class=ex>curl</span> <span class=at>-o</span> platform-tools.zip <span class=at>-L</span> <span class=dt>\\</span></span>\n<span id=cb5-2><a href=#cb5-2 aria-hidden=true tabindex=-1></a>https://dl.google.com/android/repository/platform-tools-latest-linux.zip <span class=kw>&amp;&amp;</span> <span class=dt>\\</span></span>\n<span id=cb5-3><a href=#cb5-3 aria-hidden=true tabindex=-1></a><span class=fu>unzip</span> platform-tools.zip <span class=kw>&amp;&amp;</span> <span class=fu>rm</span> platform-tools.zip <span class=kw>&amp;&amp;</span> <span class=bu>cd</span> platform-tools</span></code></pre></div><li><p>If it is successful, you can simply type <code>./adb</code> in\nthe in <em>same</em> terminal emulator window or type\n<code>~/Downloads/platform-tools/adb</code> in any terminal emulator to\naccess ADB.</ol></section></section><section id=subsec:configure-adb-over-tcp class=level3 data-number=3.1.4><h3 data-number=3.1.4><span class=header-section-number>3.1.4</span>\n<a href=#toc:subsec:configure-adb-over-tcp>Configure ADB over\nTCP</a><a href=#subsec:configure-adb-over-tcp class=anchor aria-hidden=true></a></h3><section id=subsubsec:lineage-os class=level4 data-number=3.1.4.1><h4 data-number=3.1.4.1><span class=header-section-number>3.1.4.1</span> Lineage OS 17.1 and\nEarlier<a href=#subsubsec:lineage-os class=anchor aria-hidden=true></a></h4><p>Lineage OS (or its derivatives) users can directly enable ADB over\nTCP using the developer options. To enable that, go to the\n<strong>Developer options</strong>, scroll down until you find\n<strong>ADB over Network</strong>. Now, use the toggle button on the\nright-hand side to enable it and skip to §<a href=#subsubsec:adb-mode-in-app-manager data-reference-type=ref data-reference=subsubsec:adb-mode-in-app-manager>3.1.4.3</a>.<div class=\"amalert warning\"><p><strong><em>Warning :</em></strong><p>You can turn off <strong>ADB over Network</strong> in developer\noptions, but turning off this option will also stop App Manager’s remote\nserver. So, turn it off only when you’re not going to use App Manager in\nADB over TCP mode.</div></section><section id=subsubsec:enable-adb-over-tcp-via-pc-or-mac class=level4 data-number=3.1.4.2><h4 data-number=3.1.4.2><span class=header-section-number>3.1.4.2</span> Enable ADB over TCP via PC\nor Mac<a href=#subsubsec:enable-adb-over-tcp-via-pc-or-mac class=anchor aria-hidden=true></a></h4><p>For other ROMs, you can do this using the command\nprompt/PowerShell/terminal emulator that you’ve opened in the step 3 of\nthe previous section. In this section, I will use <code>adb</code> to\ndenote <code>./adb</code>, <code>adb</code> or any other command that\nyou needed to use based on your platform and software in the previous\nsection.<ol class=incremental><li><p>Connect your device to your PC or Mac using a USB cable. For some\ndevices, it is necessary to turn on <em>File transfer mode (MTP)</em> as\nwell<li><p>To confirm that everything is working as expected, type\n<code>adb devices</code> in your terminal. If your device is connected\nsuccessfully, you will see something like this:<pre><code>List of devices attached\nxxxxxxxx  device</code></pre><div class=\"amalert tip\"><p><strong><em>Notice :</em></strong><p>In some Android phones, an alert prompt will be appeared with a\nmessage <strong>Allow USB Debugging</strong> in which case, check\n<em>Always allow from this computer</em> and click\n<strong>Allow</strong>.</div><li><p>Finally, run the following command to enable ADB over TCP:<div class=sourceCode id=cb7 data-frame=lines data-autogobble><pre class=\"sourceCode bash\"><code class=\"sourceCode bash\"><span id=cb7-1><a href=#cb7-1 aria-hidden=true tabindex=-1></a><span class=ex>adb</span> tcpip 5555</span></code></pre></div></ol><div class=\"amalert danger\"><p><strong><em>Danger :</em></strong><p>You cannot disable developer options or USB debugging after enabling\nADB over TCP.</div></section><section id=subsubsec:adb-mode-in-app-manager class=level4 data-number=3.1.4.3><h4 data-number=3.1.4.3><span class=header-section-number>3.1.4.3</span> Enable ADB mode in App\nManager<a href=#subsubsec:adb-mode-in-app-manager class=anchor aria-hidden=true></a></h4><p>After enabling ADB over TCP, relaunch App Manager. App Manager should\ndetect ADB mode automatically. If it cannot, you can change the mode of\noperation to ADB over TCP in the <a href=#subsec:mode-of-operation>settings page</a>. There, you can also\nverify whether App Manager has correctly detected ADB as indicated by\nthe <em>inferred mode</em>.<div class=\"amalert tip\"><p><strong><em>Notice :</em></strong><p>In some Android devices, the USB cable is needed to be disconnected\nfrom the PC before connecting to App Manager.</div><div class=\"amalert warning\"><p><strong><em>Warning :</em></strong><p>ADB over TCP will be disabled after a reboot. In that case, you have\nto follow §<a href=#subsubsec:enable-adb-over-tcp-via-pc-or-mac data-reference-type=ref data-reference=subsubsec:enable-adb-over-tcp-via-pc-or-mac>3.1.4.2</a>\nagain.</div></section></section></section><section id=sec:wireless-debugging class=level2 data-number=3.2><h2 data-number=3.2><span class=header-section-number>3.2</span> <a href=#toc:sec:wireless-debugging>Wireless Debugging</a><a href=#sec:wireless-debugging class=anchor aria-hidden=true></a></h2><p>If you are running Android 11 or later and capable of connecting to a\nWi-Fi network for, at least, a few moments, Wireless Debugging is the\nrecommended approach as it offers more protection than <a href=#sec:adb-over-tcp>ADB over TCP</a>. It requires two steps:<ol class=incremental><li><p><strong>ADB pairing.</strong> The initial and a bit complex step\nfor a novice user. Fortunately, this step is not required all the\ntime.<li><p><strong>Connecting to ADB.</strong> Needs to be done every time\nyou reboot your phone. App Manager can also automate this step in most\ndevices.</ol><section id=subsec:enable-developer-options-and-usb-debugging class=level3 data-number=3.2.1><h3 data-number=3.2.1><span class=header-section-number>3.2.1</span>\n<a href=#toc:subsec:enable-developer-options-and-usb-debugging>Enable\ndeveloper options and USB Debugging</a><a href=#subsec:enable-developer-options-and-usb-debugging class=anchor aria-hidden=true></a></h3><p>See §<a href=#subsec:enable-developer-options data-reference-type=ref data-reference=subsec:enable-developer-options>3.1.1</a> and §<a href=#subsec:enable-usb-debugging data-reference-type=ref data-reference=subsec:enable-usb-debugging>3.1.2</a>.</section><section id=subsec:enable-wireless-debugging class=level3 data-number=3.2.2><h3 data-number=3.2.2><span class=header-section-number>3.2.2</span>\n<a href=#toc:subsec:enable-wireless-debugging>Enable Wireless\nDebugging</a><a href=#subsec:enable-wireless-debugging class=anchor aria-hidden=true></a></h3><p>In the <strong>Developer options</strong> page, find <strong>Wireless\ndebugging</strong> and click to open it. In the new page, turn on\n<em>Use wireless debugging</em>. Depending on the operating system, you\nmight see a dialog prompt asking you to verify your decision. If that is\nthe case, click <em>Allow</em>.<div class=\"amalert tip\"><p><strong><em>Tip :</em></strong><p>For easy access, you might want to add <strong>Wireless\ndebugging</strong> in the notification tiles section. To do this, find\n<strong>Quick settings developer tiles</strong> in the <strong>Developer\noptions</strong> page and click to open it. In the new window, enable\n<em>Wireless debugging</em>. In case you do not see this setting, you\nmay find a <strong>Wireless debugging</strong> tile in the tile\ncustomization panel.</div></section><section id=subsec:pair-adb-with-app-manager class=level3 data-number=3.2.3><h3 data-number=3.2.3><span class=header-section-number>3.2.3</span>\n<a href=#toc:subsec:pair-adb-with-app-manager>Pair ADB with App\nManager</a><a href=#subsec:pair-adb-with-app-manager class=anchor aria-hidden=true></a></h3><p>In App Manager, navigate to <strong>Settings</strong> > <a href=#subsec:mode-of-operation>Mode of operation</a> and then enable\n<em>Wireless debugging</em>. At this, App Manager will try to establish\na wireless debugging connection automatically which will fail if it has\nnot been paired before. Once it fails, it will ask you to either connect\nor pair ADB. Select <em>pair</em> and a new dialog will appear. It will\nask you to navigate to the <strong>Wireless debugging</strong> page.<div class=\"amalert tip\"><p><strong><em>Note :</em></strong><p>As of v4.0.0, pairing is done using a notification prompt. So, if you\nhave disabled notification for App Manager, you must enable it\nfirst.</div><p>In the <strong>Wireless debugging</strong> page, select <strong>Pair\ndevice with pairing code</strong>. At this, a dialog containing a\npairing code will be displayed. A notification asking for the pairing\ncode will also be visible almost instantly. Insert the pairing code in\nthe input box in the notification and click <em>pair</em>. If the\npairing is successful, App Manager will display notification with the\nmessage “paired”, and the dialog in the <strong>Wireless\ndebugging</strong> page will be dismissed automatically. You will also\nbe able to see App Manager listed as an ADB client in the same page.<div class=\"amalert tip\"><p><strong><em>Notice :</em></strong><p>If you do not use App Manager in ADB mode for a while, App Manager\nmight be removed from the list of clients. In that case, you have to\nrepeat the above procedure.</div></section><section id=subsec:connect-app-manager-to-adb class=level3 data-number=3.2.4><h3 data-number=3.2.4><span class=header-section-number>3.2.4</span>\n<a href=#toc:subsec:connect-app-manager-to-adb>Connect App Manager to\nADB</a><a href=#subsec:connect-app-manager-to-adb class=anchor aria-hidden=true></a></h3><p>App Manager should be able to connect to ADB automatically if the\nmode of operation is set to <em>auto</em>, <em>ADB over TCP</em> or\n<em>Wireless debugging</em>. If this is not the case, select\n<em>Wireless debugging</em> in <strong>Settings</strong> > <a href=#subsec:mode-of-operation>Mode of operation</a>. If App Manager\nfails to detect or connect to ADB, it will ask you to connect or pair\nADB. Select <em>connect</em>.<p>Now, navigate to the <strong>Wireless debugging</strong> page in\nAndroid settings, and note down the port number displayed in the page.\nIn App Manager’s dialog prompt, replace the port number with the one you\nhave noted earlier, and click <em>connect</em>.<p>Once a connection has been established, you can disable\n<strong>Wireless debugging</strong> in Android settings.<div class=\"amalert danger\"><p><strong><em>Caution :</em></strong><p>Never disable <strong>USB Debugging</strong> or any other additional\noptions described in §<a href=#subsec:enable-developer-options-and-usb-debugging data-reference-type=ref data-reference=subsec:enable-developer-options-and-usb-debugging>3.2.1</a>.\nIf you do this, the remote server used by App Manager will be stopped,\nand you may have to start all over again.</div></section></section><section id=sec:backup-restore class=level2 data-number=3.3><h2 data-number=3.3><span class=header-section-number>3.3</span> <a href=#toc:sec:backup-restore>Back up/Restore</a><a href=#sec:backup-restore class=anchor aria-hidden=true></a></h2><p>App Manager has a modern, advanced and easy-to-use backup/restore\nsystem implemented from the scratch. This is probably the only app that\nhas the ability to restore not only the app or its data but also\npermissions and rules that you’ve configured within App Manager. You can\nalso choose to back up an app multiple times (with custom names) or for\nall users.<div class=seealso><p><em>Voir aussi :</em><ul class=incremental><li><p><a href=#subsec:1-click-back-up>1-Click Ops: Back\nup</a><li><p><a href=#subsec:1-click-restore>1-Click Ops:\nRestore</a></ul></div><section id=subsec:backup-location class=level3 data-number=3.3.1><h3 data-number=3.3.1><span class=header-section-number>3.3.1</span>\n<a href=#toc:subsec:backup-location>Location</a><a href=#subsec:backup-location class=anchor aria-hidden=true></a></h3><p>Back up/restore is a part of <a href=#subsec:batch-operations>batch\noperations</a>. It is also located inside the <a href=#subsubsec:app-info-options-menu>options menu</a> in the <a href=#subsec:app-info-tab>App Info tab</a>. Clicking on\n<strong>Backup/Restore</strong> opens the <strong>Backup\nOptions</strong>. Backups are located at\n<code>/storage/emulated/0/AppManager</code> by default. You can\nconfigure custom backup location in the <a href=#subsubsec:backup-volume>settings page</a> in which case the\nbackups will be located at the <code>AppManager</code> folder in the\nselected volume.<div class=\"amalert tip\"><p><strong><em>Note :</em></strong><p>If one or more selected apps do not have any backup, the\n<strong>Restore</strong> and <strong>Delete Backup</strong> options will\nnot be displayed.</div></section><section id=subsec:backup-restore-backup-options class=level3 data-number=3.3.2><h3 data-number=3.3.2><span class=header-section-number>3.3.2</span>\n<a href=#toc:subsec:backup-restore-backup-options>Backup Options</a><a href=#subsec:backup-restore-backup-options class=anchor aria-hidden=true></a></h3><p>Backup options (internally known as backup flags) let you customise\nthe backups on the fly. However, the customisations will not be\nremembered for the future backups. If you want to customise this dialog,\nuse <a href=#subsubsec:settings-backup-options>Backup Options</a> in\nthe <a href=#sec:settings-page>Settings page</a>.<p>A complete description of the backup options is given below:<ul class=incremental><li><p><strong>APK files.</strong> Whether to back up the APK files.\nThis includes the <em>base APK</em> file along with the\n<code>split APK</code> files if they exist.<li><p><strong>Internal data.</strong> Whether to back up the internal\ndata directories. These directories are located at\n<code>/data/user/&lt;user_id></code> and (for Android N or later)\n<code>/data/user_de/&lt;user_id></code>.<li><p><strong>External data.</strong> Whether to back up data\ndirectories located in the internal memory as well as SD Card (if\nexists). External data directories often contain non-essential app data\nor media files (instead of using the dedicated media folder) and may\nincrease the backup size. However, it might be essential for some apps.\nAlthough it isn’t checked by default (as it might dramatically increase\nthe size of the backups), you may have to check it in order to ensure a\nsmooth restore of your backups.<div class=\"amalert warning\"><p><strong><em>Caution :</em></strong><p>Internal data folders should always be backed up if you are going to\nback up the external data folders. However, it could be useful to back\nup only the external folders if the app in question downloads a lot of\nassets from the Internet.</div><li><p><strong>OBB and media.</strong> Whether to back up or restore the\nOBB and the media directories located in the external storage or the SD\nCard. This is useful for games and the graphical software which actually\nuse these folders.<li><p><strong>Cache.</strong> Android apps have multiple cache\ndirectories located at every data directories (both internal and\nexternal). There are two types of cache: <strong>cache</strong> and\n<strong>code cache</strong>. Disabling this option excludes both cache\ndirectories from all the data directories. It is generally advised to\nexclude cache directories since most apps do not clear the cache\nregularly and usually handled by the OS itself. Apps such as Telegram\nmay use a very large cache (depending on the storage space) which may\ndramatically increase the backup size. When it is disabled, AM also\nignores the <strong>no_backup</strong> directories.<li><p><strong>Extras.</strong> Backup/restore app permissions, net\npolicy, battery optimization, SSAID, etc., enabled by default. Note\nthat, blocking rules are applied <em>after</em> applying the extras. So,\nif an item is present in both places, it will be overwritten (i.e., the\none from the blocking rules will be used).<li><p><strong>Rules.</strong> This option lets you back up blocking\nrules configured within App Manager. This might come in handy if you\nhave customised permissions or block some components using App Manager\nas they will also be backed up or restored when you enable this\noption.<li><p><strong>Backup Multiple.</strong> Whether this is a multiple\nbackup. By default, backups are saved using their user ID. Enabling this\noption allows you to create additional backups. These backups use the\ncurrent date-time as the default backup name, but you can also specify\ncustom backup name using the input field displayed when you click on the\n<strong>Backup</strong> button.<li><p><strong>Custom users.</strong> Backup or restore for the selected\nusers instead of only the current user. This option is only displayed if\nthe system has more than one user.<li><p><strong>Skip signature checks.</strong> When taking a backup,\nchecksum of every file (as well as the signing certificate(s) of the\nbase APK file) is generated and stored in the <code>checksums.txt</code>\nfile. When you restore the backup, the checksums are generated again and\nare matched with the checksums stored in the said file. Enabling this\noption will disable the signature checks. This option is applied only\nwhen you restore a backup. During backup, the checksums are generated\nregardless of this option.<div class=\"amalert warning\"><p><strong><em>Caution :</em></strong><p>You should always disable this option to ensure that your backups are\nnot modified by any third-party applications. However, this would only\nwork if you enabled encryption.</div></ul><div class=seealso-inline><p><em>Voir aussi : <span><a href=#subsubsec:settings-encryption>Settings:\nEncryption</a></span></em></div></section><section id=subsec:backup-restore-backup class=level3 data-number=3.3.3><h3 data-number=3.3.3><span class=header-section-number>3.3.3</span>\n<a href=#toc:subsec:backup-restore-backup>Backup</a><a href=#subsec:backup-restore-backup class=anchor aria-hidden=true></a></h3><p>Backup respects all the backup options except <strong>Skip signature\nchecks</strong>. If base backups (i.e., backups that don’t have the\n<strong>Backup Multiple</strong> option) already exist, you will get a\nwarning as the backups will be overwritten. If <strong>Backup\nMultiple</strong> is set, you have an option to input the backup name,\nor you can leave it blank to use the current date-time.</section><section id=subsec:backup-restore-restore class=level3 data-number=3.3.4><h3 data-number=3.3.4><span class=header-section-number>3.3.4</span>\n<a href=#toc:subsec:backup-restore-restore>Restore</a><a href=#subsec:backup-restore-restore class=anchor aria-hidden=true></a></h3><p>Restore respects all the backup options and will fail if <strong>APK\nfiles</strong> option is set, but the backup doesn’t contain such\nbackups or in other cases, if the app isn’t installed. When restoring\nbackups for multiple packages, you can only restore the base backups\n(see <a href=#subsec:backup-restore-backup>backup</a> section for an\nexplanation). However, when restoring backups for a single package, you\nhave the option to select which backup to restore. If <strong>All\nusers</strong> option is set, AM will restore the selected backup for\nall users in the latter case but in the former case, it will restore\nbase backups for the respective users.<div class=\"amalert tip\"><p><strong><em>Notice :</em></strong><p>Apps that use storage access framework (SAF), SSAID or Android\nKeyStore works properly only after an immediate restart.</div></section><section id=subsec:backup-restore-delete-backup class=level3 data-number=3.3.5><h3 data-number=3.3.5><span class=header-section-number>3.3.5</span>\n<a href=#toc:subsec:backup-restore-delete-backup>Delete Backup</a><a href=#subsec:backup-restore-delete-backup class=anchor aria-hidden=true></a></h3><p>Delete backup only respects <strong>All users</strong> option and\nwhen it is selected, only the base backups for all users will be deleted\nwith a prompt. When deleting backups for a single package, another\ndialog will be displayed where you can select the backups to delete.</section></section><section id=sec:automating-tasks class=level2 data-number=3.4><h2 data-number=3.4><span class=header-section-number>3.4</span> <a href=#toc:sec:automating-tasks>Automating Tasks</a><a href=#sec:automating-tasks class=anchor aria-hidden=true></a></h2><p>It is possible to trigger profiles configured inside App Manager via\nthird-party applications such as <strong>Automation</strong> or\n<strong>Tasker</strong>. Traditionally, <code>Intent</code>s are used to\ntrigger such operations.<section id=subsec:generating-authorization-key class=level3 data-number=3.4.1><h3 data-number=3.4.1><span class=header-section-number>3.4.1</span>\n<a href=#toc:subsec:generating-authorization-key>Generating\nauthorization key</a><a href=#subsec:generating-authorization-key class=anchor aria-hidden=true></a></h3><p>In order to ensure proper security, an authorization key is required.\nTo generate a authorization key, go to <strong>Settings</strong> page\nand then <strong>Privacy</strong> > <strong>Authorization\nManager</strong>. If an authorization key has not been generated, it\nwill be generated automatically. The key can be regenerated as\nrequired.<div class=\"amalert danger\"><p><strong><em>Caution :</em></strong><p>Regenerating the authorization key can have some side effects such as\ninvalidation of all the previously configured Intents.</div></section><section id=subsec:at:general-configuration class=level3 data-number=3.4.2><h3 data-number=3.4.2><span class=header-section-number>3.4.2</span>\n<a href=#toc:subsec:at:general-configuration>Configuring tasks</a><a href=#subsec:at:general-configuration class=anchor aria-hidden=true></a></h3><p>The activity\n<code>io.github.muntashirakon.AppManager.crypto.auth.AuthFeatureDemultiplexer</code>\nis responsible for handling all the automations. Sending an intent to\nthe activity lets App Manager perform the designated operation by\nredirecting the <code>Intent</code> to the designated activity or\nservice.<section id=required-extras class=level4 data-number=3.4.2.1><h4 data-number=3.4.2.1><span class=header-section-number>3.4.2.1</span> Required extras<a href=#required-extras class=anchor aria-hidden=true></a></h4><p>It has two primary extras required in all conditions. The key names,\ndata types are all follows:<ol class=incremental><li><p><strong><code>auth</code>.</strong> (String value) The\nauthorization key as described in the earlier section.<li><p><strong><code>feature</code>.</strong> (String value) Name of the\nfeature. Supported features are described in the next section.</ol></section></section><section id=subsec:at:features class=level3 data-number=3.4.3><h3 data-number=3.4.3><span class=header-section-number>3.4.3</span>\n<a href=#toc:subsec:at:features>Features</a><a href=#subsec:at:features class=anchor aria-hidden=true></a></h3><p>App Manager current support a single feature, namely\n<code>profile</code>.</section><section id=subsec:triggering-a-profile class=level3 data-number=3.4.4><h3 data-number=3.4.4><span class=header-section-number>3.4.4</span>\n<a href=#toc:subsec:triggering-a-profile>Triggering a profile</a><a href=#subsec:triggering-a-profile class=anchor aria-hidden=true></a></h3><p>In order to trigger a profile, <code>feature</code> must have the\nvalue <code>profile</code>. In addition, the following extras can be\nincluded:<ol class=incremental><li><p><strong><code>prof</code>.</strong> (String value – required) The\nname of the profile as displayed in the <a href=#sec:profiles-page>Profiles page</a>.<li><p><strong><code>state</code>.</strong> (String value – optional)\nState of the profile – currently <code>on</code> or <code>off</code> –\nas specified in the documentation. If this extra is not set, App Manager\nwill display a prompt where a state must be selected. Therefore, for\ncomplete automation, this option should be set.</ol></section></section><section id=sec:net-policy class=level2 data-number=3.5><h2 data-number=3.5><span class=header-section-number>3.5</span> <a href=#toc:sec:net-policy>Net Policy</a><a href=#sec:net-policy class=anchor aria-hidden=true></a></h2><p>Short for <strong>Network policy</strong> or network policies. It is\nusually located in the Android settings under <strong>Mobile data &\nWifi</strong> section in the app info page of an app. Not all policies\nare guaranteed to be included in this page (e.g. Samsung), and not all\nsettings are well-understood due to lack of documentation. App Manager\ncan display all the net policies declared in the <a href=https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/net/NetworkPolicyManager.java>NetworkPolicyManager</a>.\nPolicies unknown to App Manager will have a <em>Unknown</em> prefix\nalong with the policy constant name and number in the hexadecimal\nformat. Unknown policies should be reported to App Manager for\ninclusion.<p>Net policy allows a user to configure certain networking behaviour of\nan app without modifying the ip tables directly and/or running a\nfirewall app. However, the features it offers largely depend on Android\nversion and ROM. A list of known net policies are listed below:<ol class=incremental><li><p><strong>None</strong> or\n<strong><code>POLICY_NONE</code></strong>: (AOSP) No specific network\npolicy is set. System can still assign rules depending on the nature of\nthe app.<li><p><strong>Reject background data on metered networks</strong> or\n<strong><code>POLICY_REJECT_METERED_BACKGROUND</code></strong>: (AOSP)\nReject network usage on metered networks when the application is in\nbackground.<li><p><strong>Allow background data on metered networks even when Data\nSaver is on</strong> or\n<strong><code>POLICY_ALLOW_METERED_BACKGROUND</code></strong>: (AOSP)\nAllow metered network use in the background even when data saving mode\nis enabled.<li><p><strong>Reject cellular data</strong> or\n<strong><code>POLICY_REJECT_CELLULAR</code></strong> (Android 11+) or\n<strong><code>POLICY_REJECT_ON_DATA</code></strong> (up to Android 10):\n(Lineage OS) Reject mobile/cellular data. Signals network unavailable to\nthe configured app as if the mobile data is inactive.<li><p><strong>Reject VPN data</strong> or\n<strong><code>POLICY_REJECT_VPN</code></strong> (Android 11+) or\n<strong><code>POLICY_REJECT_ON_VPN</code></strong> (up to Android 10):\n(Lineage OS) Reject VPN data. Signals network unavailable to the\nconfigured app as if the VPN is inactive.<li><p><strong>Reject Wi-Fi data</strong> or\n<strong><code>POLICY_REJECT_WIFI</code></strong> (Android 11+) or\n<strong><code>POLICY_REJECT_ON_WLAN</code></strong> (up to Android 10):\n(Lineage OS) Reject Wi-Fi data. Signals network unavailable to the\nconfigured app as if the device is not connected to a Wi-Fi\nnetwork.<li><p><strong>Disable network access</strong> or\n<strong><code>POLICY_REJECT_ALL</code></strong> (Android 11+) or\n<strong><code>POLICY_NETWORK_ISOLATED</code></strong> (up to Android\n10): (Lineage OS) Reject network access in all circumstances. This is\nnot the same as enforcing the other three policies above, and is the\nrecommended policy for dodgy apps. If this policy is enforced, there is\nno need to enforce the other policies.<li><p><strong><code>POLICY_ALLOW_METERED_IN_ROAMING</code></strong>:\n(Samsung) Possibly allow metered network use during roaming. Exact\nmeaning is currently unknown.<li><p><strong><code>POLICY_ALLOW_WHITELIST_IN_ROAMING</code></strong>:\n(Samsung) Possibly allow network use during roaming. Exact meaning is\ncurrently unknown.<li><p><strong>Reject data on metered networks</strong> or\n<strong><code>POLICY_REJECT_METERED</code></strong>: (Motorola) Reject\nnetwork usage if it is a metered network.<li><p><strong>Reject background data</strong> or\n<strong><code>POLICY_REJECT_BACKGROUND</code></strong>: (Motorola)\nReject network usage in the background.<li><p><strong>Disable network access</strong> or\n<strong><code>POLICY_REJECT_ALL</code></strong>: (Motorola) Reject\nnetwork access altogether. Like Lineage OS, it blocks internet\nconnections via iptables. But whether it signals the unavailability of\nnetwork to the configured app is not known.</ol><div class=\"amalert tip\"><p><strong><em>Note :</em></strong><p>Corresponding Lineage OS patches are as follows:<ol class=incremental><li><p><a href=https://github.com/LineageOS/android_frameworks_base/commit/a04932bafbbf7d99efd18276152cc2c9c9b2073e>fw/b:\nSquash of app fw restriction commits</a><li><p><a href=https://github.com/LineageOS/android_frameworks_base/commit/02c8c82854348f52afe2199f310f44b5f578b5b8>fw/b:\nAdd support for per app network isolation</a></ol></div></section></section><section id=ch:faq class=level1 data-number=4><h1 data-number=4><span class=header-section-number>4</span> <a href=#toc:ch:faq>Frequently Asked Questions</a><a href=#ch:faq class=anchor aria-hidden=true></a></h1><section id=sec:faq:app-components class=level2 data-number=4.1><h2 data-number=4.1><span class=header-section-number>4.1</span> <a href=#toc:sec:faq:app-components>App Components</a><a href=#sec:faq:app-components class=anchor aria-hidden=true></a></h2><section id=subsec:faq:what-are-app-components class=level3 data-number=4.1.1><h3 data-number=4.1.1><span class=header-section-number>4.1.1</span>\n<a href=#toc:subsec:faq:what-are-app-components>What are the\napplication components?</a><a href=#subsec:faq:what-are-app-components class=anchor aria-hidden=true></a></h3><p>Activities, services, broadcast receivers (or only receivers) and\ncontent providers (or only providers) are jointly called application\ncomponents. More technically, they all inherit the <a href=https://developer.android.com/reference/android/content/pm/ComponentInfo>ComponentInfo</a>\nclass and can be launched via Intent.</section><section id=subsec:faq:how-components-blocked class=level3 data-number=4.1.2><h3 data-number=4.1.2><span class=header-section-number>4.1.2</span>\n<a href=#toc:subsec:faq:how-components-blocked>How are the tracker and\nother components blocked in App Manager? What are its limitations?</a><a href=#subsec:faq:how-components-blocked class=anchor aria-hidden=true></a></h3><p>App Manager typically blocks application components (or tracker\ncomponents) using a method called <a href=https://carteryagemann.com/pages/android-intent-firewall.html>Intent\nFirewall (IFW)</a>, it is superior to other methods such as <em>pm</em>\n(PackageManager), <a href=https://github.com/RikkaApps/Shizuku>Shizuku</a> or any other\nmethod that uses the package manager to enable or disable the\ncomponents. If a component is disabled by the latter methods, the\napplication itself can detect that the component is being blocked and\ncan re-enable it as it has full access to its own components. (Many\ndeceptive applications actually do this in order to keep the tracker\ncomponents unblocked.) On the other hand, IFW is a true firewall and the\napplication cannot detect if its components are being blocked. App\nManager uses the term <em>block</em> rather than <em>disable</em> for\nthis reason.<p>Even IFW has some limitations which are primarily applicable for the\nsystem applications:<ul class=incremental><li><p>The application in question is whitelisted by the system i.e. the\nsystem cannot function properly without these applications and may cause\nrandom crashes. These applications include but not limited to Android\nSystem, System UI, Phone Services. They will continue to work even if\nthey are disabled or blocked.<li><p>Another system application or system process has activated a\nspecific component of the application in question via interprocess\ncommunication (IPC). In this case, the component will be activated\nregardless of blocking status or even if the entire application is\ndisabled. If there is such a system application that is not needed, the\nonly way to prevent it from running is by getting rid of it.</ul></section><section id=subsec:faq:components-blocked-by-others class=level3 data-number=4.1.3><h3 data-number=4.1.3><span class=header-section-number>4.1.3</span>\n<a href=#toc:subsec:faq:components-blocked-by-others>Does app\ncomponents blocked by other tools retained in App Manager?</a><a href=#subsec:faq:components-blocked-by-others class=anchor aria-hidden=true></a></h3><p><strong>No.</strong> But the application components blocked by the\nsystem or any other tools are displayed in the <a href=#subsec:component-tabs>component tabs</a>. These rules can be\nimported from <a href=#par:import-existing-rules>Settings</a>.\nHowever, it is not possible for App Manager to distinguish the\ncomponents blocked by the third-party tools and components blocked by\nthe system. Therefore, the applications listed in the import page should\nbe selected with care.</section><section id=subsec:faq:components-reblocked-in-am class=level3 data-number=4.1.4><h3 data-number=4.1.4><span class=header-section-number>4.1.4</span>\n<a href=#toc:subsec:faq:components-reblocked-in-am>What happens to the\ncomponents blocked by App Manager which were previously blocked by other\ntools?</a><a href=#subsec:faq:components-reblocked-in-am class=anchor aria-hidden=true></a></h3><p><em>App Manager blocks the components again</em> if requested. In\ncase of unblocking, they will be reverted to the default state as\nspecified in the manifest of the application. But if the components were\nblocked by <a href=https://www.myandroidtools.com>MyAndroidTools\n(MAT)</a> with IFW method, they will not be unblocked by App Manager as\nit uses a different format. To fix this issue, the rules have to be\nimported from <a href=#par:import-existing-rules>Settings</a> at\nfirst, in which case MAT’s configurations will be permanently\nremoved.</section><section id=subsec:faq:what-is-instant-component-blocking class=level3 data-number=4.1.5><h3 data-number=4.1.5><span class=header-section-number>4.1.5</span>\n<a href=#toc:subsec:faq:what-is-instant-component-blocking>What is\ninstant component blocking?</a><a href=#subsec:faq:what-is-instant-component-blocking class=anchor aria-hidden=true></a></h3><p>When you block a component in the <a href=#sec:app-details-page>App\nDetails page</a>, the blocking is not applied by default. It is only\napplied when you apply blocking using the <em>Apply rules</em> option in\nthe top-right menu. If you enable <a href=#subsubsec:instant-component-blocking>instant component\nblocking</a>, blocking will be applied as soon as you block a component.\nIf you choose to block tracker components, however, blocking is applied\nautomatically regardless of this setting. You can also remove blocking\nfor an application by simply clicking on <em>Remove rules</em> in the\nsame menu in the <strong>App Details page</strong>. Since the default\nbehaviour gives you more control over applications, it is better to keep\n<em>instant component blocking</em> option disabled.</section><section id=subsec:tracker-classes-versus-tracker-components class=level3 data-number=4.1.6><h3 data-number=4.1.6><span class=header-section-number>4.1.6</span>\n<a href=#toc:subsec:tracker-classes-versus-tracker-components>Tracker\nclasses versus tracker components</a><a href=#subsec:tracker-classes-versus-tracker-components class=anchor aria-hidden=true></a></h3><p>All application components are classes but not all classes are\ncomponents. In fact, only a few of the classes are components. That\nbeing said, <a href=#sec:scanner-page>scanner page</a> displays a list\nof trackers along with the number of classes, not just the components.\nIn all other pages, trackers and tracker components are used\nsynonymously to denote tracker components, i.e. blocking tracker means\nblocking tracker components, not tracker classes.<div class=\"amalert tip\"><p><strong><em>Info :</em></strong><p>Tracker classes that are not components cannot be blocked. They can\nonly be removed by editing the application itself.</div></section></section><section id=sec:faq:adb-over-tcp class=level2 data-number=4.2><h2 data-number=4.2><span class=header-section-number>4.2</span> <a href=#toc:sec:faq:adb-over-tcp>ADB over TCP</a><a href=#sec:faq:adb-over-tcp class=anchor aria-hidden=true></a></h2><section id=subsec:faq:enable-adb-on-every-restart class=level3 data-number=4.2.1><h3 data-number=4.2.1><span class=header-section-number>4.2.1</span>\n<a href=#toc:subsec:faq:enable-adb-on-every-restart>Do I have to\nenable ADB over TCP everytime I restart?</a><a href=#subsec:faq:enable-adb-on-every-restart class=anchor aria-hidden=true></a></h3><p>Unfortunately, yes. This is because the ADB daemon, the process\nresponsible for ADB connection, is also restarted after a reboot, and it\ndoes not re-enable ADB over TCP.</section><section id=subsec:faq:usb-debugging class=level3 data-number=4.2.2><h3 data-number=4.2.2><span class=header-section-number>4.2.2</span>\n<a href=#toc:subsec:faq:usb-debugging>Cannot enable USB debugging.\nWhat to do?</a><a href=#subsec:faq:usb-debugging class=anchor aria-hidden=true></a></h3><p>See §<a href=#subsec:enable-usb-debugging data-reference-type=ref data-reference=subsec:enable-usb-debugging>3.1.2</a> in Chapitre <a href=#ch:guides data-reference-type=ref data-reference=ch:guides>3</a>.</section><section id=subsec:faq:block-components-using-adb class=level3 data-number=4.2.3><h3 data-number=4.2.3><span class=header-section-number>4.2.3</span>\n<a href=#toc:subsec:faq:block-components-using-adb>Can I block tracker\nor any other application components using ADB over TCP?</a><a href=#subsec:faq:block-components-using-adb class=anchor aria-hidden=true></a></h3><p>ADB has limited number of <a href=https://github.com/aosp-mirror/platform_frameworks_base/blob/master/packages/Shell/AndroidManifest.xml>permissions</a>\nand controlling application components is not one of them. However, the\ncomponents of a <em>test-only</em> app can be controlled via ADB. If App\nManager detects such an application, it enables the blocking options\nautomatically.</section><section id=subsec:faq:adb-features class=level3 data-number=4.2.4><h3 data-number=4.2.4><span class=header-section-number>4.2.4</span>\n<a href=#toc:subsec:faq:adb-features>Which features can be used in ADB\nmode?</a><a href=#subsec:faq:adb-features class=anchor aria-hidden=true></a></h3><p>Supported features are enabled automatically in the ADB mode.\nSupported features include disabling, force-stopping, clearing\napplication data, granting or revoking app ops and permissions, and so\non. It is also possible to install or uninstall applications without any\nprompt from the system.</section></section><section id=sec:faq:miscellanea class=level2 data-number=4.3><h2 data-number=4.3><span class=header-section-number>4.3</span> <a href=#toc:sec:faq:miscellanea>Miscellanea</a><a href=#sec:faq:miscellanea class=anchor aria-hidden=true></a></h2><section id=subsec:faq:no-root-no-harms class=level3 data-number=4.3.1><h3 data-number=4.3.1><span class=header-section-number>4.3.1</span>\n<a href=#toc:subsec:faq:no-root-no-harms>I don’t use root/ADB. Am I\ncompletely safe from any harms?</a><a href=#subsec:faq:no-root-no-harms class=anchor aria-hidden=true></a></h3><p>Yes. AM cannot modify any system settings without root or ADB.</section><section id=subsec:faq:how-trackers-libs-updated class=level3 data-number=4.3.2><h3 data-number=4.3.2><span class=header-section-number>4.3.2</span>\n<a href=#toc:subsec:faq:how-trackers-libs-updated>How are the trackers\nand libraries are updated?</a><a href=#subsec:faq:how-trackers-libs-updated class=anchor aria-hidden=true></a></h3><p>Trackers and libraries are updated manually before making a new\nrelease.</section><section id=subsec:faq:apks-deleted-after-installed class=level3 data-number=4.3.3><h3 data-number=4.3.3><span class=header-section-number>4.3.3</span>\n<a href=#toc:subsec:faq:apks-deleted-after-installed>Are APKs deleted\nafter installed?</a><a href=#subsec:faq:apks-deleted-after-installed class=anchor aria-hidden=true></a></h3><p>No, APKs aren’t deleted by App Manager after they are installed.</section><section id=subsec:faq:shizuku-support class=level3 data-number=4.3.4><h3 data-number=4.3.4><span class=header-section-number>4.3.4</span>\n<a href=#toc:subsec:faq:shizuku-support>Any plans for Shizuku?</a><a href=#subsec:faq:shizuku-support class=anchor aria-hidden=true></a></h3><p>App Manager’s use of hidden API and privileged code execution is now\nmuch more complex and cannot be integrated with other third party apps\nsuch as <a href=https://shizuku.rikka.app>Shizuku</a>. Here are some\nreasons for not considering Shizuku (which now has Apache 2.0 license)\nfor App Manager:<ol class=incremental><li><p>Shizuku was initially non-free which led me to use a similar\napproach for App Manager to support both root and ADB<li><p>App Manager already supports both ADB and root which in some\ncases is more capable than Shizuku<li><p>Relying on a third-party app for the major functionalities is not\na good design choice<li><p>Integration of Shizuku will increase the complexity of App\nManager.</ol></section><section id=subsec:faq:what-are-bloatware class=level3 data-number=4.3.5><h3 data-number=4.3.5><span class=header-section-number>4.3.5</span>\n<a href=#toc:subsec:faq:what-are-bloatware>What are bloatware and how\nto remove them?</a><a href=#subsec:faq:what-are-bloatware class=anchor aria-hidden=true></a></h3><p>Bloatware are the unnecessary pre-installed apps, usually system\napps. Some of the apps are often used to track users and collect user\ndata which they might sell for profits. Many system apps do not need to\nrequest any permission to access device info, contacts and messaging\ndata, and other usage info, such as your phone usage habits and\neverything you store on your shared storage(s).<p>The bloatware may also include Google apps, Meta apps, and Twitter/X\nwhich can also track users and/or collect user data without consent. You\ncan disable a few permissions from Android settings but be aware that\nAndroid settings hides many permissions a security researcher would call\npotentially <em>dangerous</em> (e.g., internet, sensor).<p>Were the bloatware user apps, they could be easily uninstalled either\nfrom Android settings or AM. Uninstalling system apps is not possible\nwithout privileged permission, but even then, it cannot <em>remove</em>\nthe system apps completely as they are located in the <em>system</em>\npartition which is a read-only partition. If you have root, you can\nremount this partition to manually <em>purge</em> these apps but this\nwill break Over the Air (OTA) updates since data in the system partition\nhas been modified. There are two kind of updates, delta (small-size,\nconsisting of only the changes between two versions) and full updates.\nYou may still be able to apply full updates, but the bloatware will be\ninstalled again, and consequently, you have to delete them all over\nagain.<p>Another solution is to disable these apps either from Android\nsettings or AM, but certain services can still run in the background as\nthey can be started by other system apps using Inter-process\nCommunication (IPC). One possible solution is to disable all bloatware\nuntil the service has finally stopped (after a restart). However, due to\nheavy modifications of the Android frameworks by the vendors, removing\nor disabling certain bloatware may cause the System UI to crash or even\ncause bootloop. From v4.0.0, AM has a new feature called\n<strong>Debloater</strong> which can be used as a starting point to\nmonitor, disable, and remove the bloatware from a proprietary Android\noperating system.<div class=\"amalert warning\"><p><strong><em>Note :</em></strong><p>In most cases, you cannot completely debloat your device. Therefore,\nit is recommended that you use a custom ROM free from bloatware, such as\nGraphene OS, Lineage OS or their derivatives.</div></section></section></section><section id=ch:specifications class=level1 data-number=5><h1 data-number=5><span class=header-section-number>5</span> <a href=#toc:ch:specifications>Specifications</a><a href=#ch:specifications class=anchor aria-hidden=true></a></h1><section id=sec:rules-specification class=level2 data-number=5.1><h2 data-number=5.1><span class=header-section-number>5.1</span> <a href=#toc:sec:rules-specification>Rules Specification</a><a href=#sec:rules-specification class=anchor aria-hidden=true></a></h2><section id=background class=level3 data-number=5.1.1><h3 data-number=5.1.1><span class=header-section-number>5.1.1</span>\n<a href=#toc:background>Background</a><a href=#background class=anchor aria-hidden=true></a></h3><p>AM currently supports blocking activities, broadcast receivers,\ncontent providers, services, app ops and permissions, and in future I\nmay add more blocking options. In order to add more portability, it is\nnecessary to import/export all these data.<p>Maintaining a database should be the best choice when it comes to\nstoring data. For now, several <code>tsv</code> files with each file\nhaving the name of the package and a <code>.tsv</code> extension. The\nfile/database will be queried/processed by the\n<code>RulesStorageManager</code> class. Due to this abstraction, it\nshould be easier to switch to database or encrypted database systems in\nfuture without changing the design of the entire project. Currently, All\nconfiguration files are stored at\n<code>/data/data/io.github.muntashirakon.AppManager/Files/conf</code>.</section><section id=rules-file-format class=level3 data-number=5.1.2><h3 data-number=5.1.2><span class=header-section-number>5.1.2</span>\n<a href=#toc:rules-file-format>Rules File Format</a><a href=#rules-file-format class=anchor aria-hidden=true></a></h3><section id=internal class=level4 data-number=5.1.2.1><h4 data-number=5.1.2.1><span class=header-section-number>5.1.2.1</span> Internal<a href=#internal class=anchor aria-hidden=true></a></h4><p>The format below is used internally within App Manager and is <em>not\ncompatible with the external format.</em><pre><code>    &lt;name&gt; &lt;type&gt; &lt;mode&gt;|&lt;component_status&gt;|&lt;is_granted&gt;</code></pre><p>Here:<ul class=incremental><li><p><code>&lt;name></code> – Component/permission/app op name (in\ncase of app op, it could be string or integer)<li><p><code>&lt;type></code> – One of the <code>ACTIVITY</code>,\n<code>RECEIVER</code>, <code>PROVIDER</code>, <code>SERVICE</code>,\n<code>APP_OP</code>, <code>PERMISSION</code><li><p><code>&lt;mode></code> – (For app ops) The associated <a href=#subsec:mode-constants>mode constant</a><li><p><code>&lt;component_status></code> – (For components)\nComponent status<ul class=incremental><li><p><code>true</code> – Component has been applied (<code>true</code>\nvalue is kept for compatibility)<li><p><code>false</code> – Component hasn’t been applied yet, but will\nbe applied in future (<code>false</code> value is kept for\ncompatibility)<li><p><code>unblocked</code> – Component is scheduled to be\nunblocked</ul><li><p><code>&lt;is_granted></code> – (For permissions) Whether the\npermission is granted or revoked</ul></section><section id=external class=level4 data-number=5.1.2.2><h4 data-number=5.1.2.2><span class=header-section-number>5.1.2.2</span> External<a href=#external class=anchor aria-hidden=true></a></h4><p>External format is used for importing or exporting rules in App\nManager.<pre><code>    &lt;package_name&gt; &lt;component_name&gt; &lt;type&gt; &lt;mode&gt;|&lt;component_status&gt;|&lt;is_granted&gt;</code></pre><p>This the format is essentially the same as above except for the first\nitem which is the name of the package.<div class=\"amalert danger\"><p><strong><em>Caution :</em></strong><p>The exported rules have a different format than the internal one and\nshould not be copied directly to the <strong>conf</strong> folder.</div></section></section></section></section><section id=ch:changelogs class=level1 data-number=6><h1 data-number=6><span class=header-section-number>6</span> <a href=#toc:ch:changelogs>Changelogs</a><a href=#ch:changelogs class=anchor aria-hidden=true></a></h1><section id=sec:v4.0.5-(445) class=level2 data-number=6.1><h2 data-number=6.1><span class=header-section-number>6.1</span> <a href=#toc:sec:v4.0.5-(445)>v4.0.5 (445)</a><a href=#sec:v4.0.5-(445) class=anchor aria-hidden=true></a></h2><ul class=incremental><li><p>Added option to allow installing the existing applications in the\ninstaller page<li><p>Display unsafe bloatware info<li><p>Display vector icon on the splash screen in Android 7.1 and\nearlier<li><p>Enabled “Clear data from uninstalled apps” to no-root users in\n1-click ops page<li><p>Enabled predictive back in Android 14 onwards<li><p>Improved accessibility by updating the content description of the\naction items<li><p>In app info tab, open “Open by default” setting in the “Open\nlinks” dialog<li><p>In debloater page, sort by app label (or app name) rather than\npackage name<li><p>Fixed freezing an app with “Remember for this app” turned\non<li><p>Fixed selecting texts in the list items due to framework\nbugs<li><p>Fixed setting app ops in custom ROMs with MIUI properties\ninjected<li><p>Fixed updating profile modification status when an application is\ndeleted from the list<li><p>Handled common colors and cursor movements in terminal\noutput.</ul></section><section id=sec:v4.0.4-(444) class=level2 data-number=6.2><h2 data-number=6.2><span class=header-section-number>6.2</span> <a href=#toc:sec:v4.0.4-(444)>v4.0.4 (444)</a><a href=#sec:v4.0.4-(444) class=anchor aria-hidden=true></a></h2><ul class=incremental><li><p>Optimized searching and filtering in the main page<li><p>Adopted sentence-case for the titles<li><p>Use the configured state to execute a profile for the simple\nshortcuts<li><p>Prevented crashing while searching throughout the\napplication<li><p>Fixed integer overflow issue in the tar compression.</ul></section><section id=sec:v4.0.3-(443) class=level2 data-number=6.3><h2 data-number=6.3><span class=header-section-number>6.3</span> <a href=#toc:sec:v4.0.3-(443)>v4.0.3 (443)</a><a href=#sec:v4.0.3-(443) class=anchor aria-hidden=true></a></h2><ul class=incremental><li><p>Updated translations<li><p>Improved handling the list items throughout App Manager<li><p>Fixed a regression error in file manager<li><p>Fixed spinners in the App Usage and the System Config\npages.</ul></section><section id=sec:v4.0.2-(442) class=level2 data-number=6.4><h2 data-number=6.4><span class=header-section-number>6.4</span> <a href=#toc:sec:v4.0.2-(442)>v4.0.2 (442)</a><a href=#sec:v4.0.2-(442) class=anchor aria-hidden=true></a></h2><ul class=incremental><li><p>Updated bloatware<li><p>Fixed fetching applications in multi-user environment in no-root\nmode<li><p>Fixed opening <code>app-manager</code> URLs from the web\nbrowsers<li><p>Fixed updating SSAID<li><p>Prevented a crash in Android &lt; 9.0 that occurs due to invalid\napp ops.</ul></section><section id=sec:v4.0.1-(441) class=level2 data-number=6.5><h2 data-number=6.5><span class=header-section-number>6.5</span> <a href=#toc:sec:v4.0.1-(441)>v4.0.1 (441)</a><a href=#sec:v4.0.1-(441) class=anchor aria-hidden=true></a></h2><section id=overlay-management class=level3 data-number=6.5.1><h3 data-number=6.5.1><span class=header-section-number>6.5.1</span>\n<a href=#toc:overlay-management>Overlay management</a><a href=#overlay-management class=anchor aria-hidden=true></a></h3><p>In the App Details page, a new tab “Overlays” is added where per-app\noverlays are displayed. They can also be enabled or disabled using the\ntoggle button. In addition, if the App Details page of an overlay\npackage is opened, a “Overlay” tag will be displayed in the App Info\ntab. Clicking on the tag opens a dialog containing additional info along\nwith a button that allows navigating to the App Details page of the\noverlay target package if it is installed.<section id=known-limitation class=level5 data-number=6.5.1.0.1><h5 data-number=6.5.1.0.1><span class=header-section-number>6.5.1.0.1</span> Known limitation<a href=#known-limitation class=anchor aria-hidden=true></a></h5><p>At present, it only works for root/ADB users in Android 8 (Oreo) and\nlater.</section></section><section id=unfreeze-option-in-activity-shortcuts class=level3 data-number=6.5.2><h3 data-number=6.5.2><span class=header-section-number>6.5.2</span>\n<a href=#toc:unfreeze-option-in-activity-shortcuts>Unfreeze option in\nactivity shortcuts</a><a href=#unfreeze-option-in-activity-shortcuts class=anchor aria-hidden=true></a></h3><p>If the application corresponding to the shortcut being launched is\nfrozen, App Manager will now offer you to unfreeze the app temporarily\nso that the shortcut can be launched. The app will be frozen again once\nthe screen is locked.<section id=known-limitation-1 class=level5 data-number=6.5.2.0.1><h5 data-number=6.5.2.0.1><span class=header-section-number>6.5.2.0.1</span> Known limitation<a href=#known-limitation-1 class=anchor aria-hidden=true></a></h5><p>This may not work on devices without a screen lock or if the screen\nis locked some time after the display goes off.</section></section><section id=market-like-url-support class=level3 data-number=6.5.3><h3 data-number=6.5.3><span class=header-section-number>6.5.3</span>\n<a href=#toc:market-like-url-support><code>market</code>-like URL\nsupport</a><a href=#market-like-url-support class=anchor aria-hidden=true></a></h3><p>Third-party applications can now open the App Details page of any\ninstalled package by invoking an Intent with an URL with the following\nformat:<pre><code>app-manager://details?id=&lt;pkg&gt;&amp;user=&lt;user_id&gt;</code></pre><p>where <code>&lt;pkg></code> stands for package name, and\n<code>&lt;user_id></code> stands for the user ID which is\noptional.</section><section id=updated-color-codes class=level3 data-number=6.5.4><h3 data-number=6.5.4><span class=header-section-number>6.5.4</span>\n<a href=#toc:updated-color-codes>Updated color codes</a><a href=#updated-color-codes class=anchor aria-hidden=true></a></h3><p>In order to improve accessibility, certain color codes have been\nimproved. Visit <a href=app-manager://settings/about/version>Settings\n> About > Version/Changelog</a> for details.</section><section id=others class=level3 data-number=6.5.5><h3 data-number=6.5.5><span class=header-section-number>6.5.5</span>\n<a href=#toc:others>Others</a><a href=#others class=anchor aria-hidden=true></a></h3><ul class=incremental><li><p>Avoided waiting for the remote server to respond when no-root\nmode is set<li><p>Fixed downgrading apps in Android 10 onwards<li><p>Fixed installer issues in the Huawei stock operating\nsystems<li><p>Improved text formatting in the “What’s New” dialog<li><p>In the UI tracker window, fixed clicking on the icon after it is\niconified<li><p>Updated bloatware and suggestions</ul></section></section><section id=sec:v4.0.0-(440) class=level2 data-number=6.6><h2 data-number=6.6><span class=header-section-number>6.6</span> <a href=#toc:sec:v4.0.0-(440)>v4.0.0 (440)</a><a href=#sec:v4.0.0-(440) class=anchor aria-hidden=true></a></h2><p>App Manager v4.0.0 comes with a lot of new features and improvements.\nVisit <a href=app-manager://settings/about/version>Settings > About\n> Version/Changelog</a> for details.<section id=new-logo class=level3 data-number=6.6.1><h3 data-number=6.6.1><span class=header-section-number>6.6.1</span>\n<a href=#toc:new-logo>New logo!</a><a href=#new-logo class=anchor aria-hidden=true></a></h3><p>The new logo is just a cursive “A”. The design is based on the <a href=https://freetengwar.sourceforge.net/>Tengwar Telcontar</a> font\nwhich was created to bring the Tengwar script, originally created by J.\nR. R. Tolkien, to the digital world. The letter has the classic App\nManager color (i.e., #dcaf74) and uses a pure black background instead\nof a shade of grey.</section><section id=android-14-and-15-support class=level3 data-number=6.6.2><h3 data-number=6.6.2><span class=header-section-number>6.6.2</span>\n<a href=#toc:android-14-and-15-support>Android 14 and 15 support</a><a href=#android-14-and-15-support class=anchor aria-hidden=true></a></h3><p>App Manager now targets Android 14 and fully supports Android 15.<section id=known-issue class=level5 data-number=6.6.2.0.1><h5 data-number=6.6.2.0.1><span class=header-section-number>6.6.2.0.1</span> Known issue<a href=#known-issue class=anchor aria-hidden=true></a></h5><p>KeyStore backup/restore is not working in Android 12 and later.</section></section><section id=revamped-debloater class=level3 data-number=6.6.3><h3 data-number=6.6.3><span class=header-section-number>6.6.3</span>\n<a href=#toc:revamped-debloater>Revamped debloater</a><a href=#revamped-debloater class=anchor aria-hidden=true></a></h3><p>Debloating profiles were available as “Presets” in the Profiles page\nwhich has now been replaced with the Debloater page and can be accessed\nfrom the three-dots menu in the Main page. <a href=https://github.com/MuntashirAkon/android-debloat-list>ADL</a> is\na new project that focuses on maintaining a list of bloatware as well as\npotential open source alternatives. Contributions are welcome!</section><section id=introducing-file-manager class=level3 data-number=6.6.4><h3 data-number=6.6.4><span class=header-section-number>6.6.4</span>\n<a href=#toc:introducing-file-manager>Introducing file manager</a><a href=#introducing-file-manager class=anchor aria-hidden=true></a></h3><p>App Manager offers an (almost) fully-featured file manager with basic\nfile operations, such as copy, cut, rename, and delete along with the\nbatch operations. It also offers an extensive “Open with…” dialog to\nopen a file with another app, and a comprehensive file properties\nviewer. Folders can also be added to the list of favorites for quick\naccess. And many more.</section><section id=integrated-code-editor class=level3 data-number=6.6.5><h3 data-number=6.6.5><span class=header-section-number>6.6.5</span>\n<a href=#toc:integrated-code-editor>Integrated code editor</a><a href=#integrated-code-editor class=anchor aria-hidden=true></a></h3><p>Manifest and code viewers have been replaced with this new editor.\nAmong other regular features, it includes proper syntax highlighting and\nadvanced searching options. In addition, files from third-party apps can\nalso be opened for editing.</section><section id=history-of-operations class=level3 data-number=6.6.6><h3 data-number=6.6.6><span class=header-section-number>6.6.6</span>\n<a href=#toc:history-of-operations>History of operations</a><a href=#history-of-operations class=anchor aria-hidden=true></a></h3><p>All 1-click operations, batch operations, and profile invocations are\nnow stored as history. The history items can also be executed from the\nHistory page. To ensure consistency, the profile state, configurations,\npackage list are also stored, and this stored version is executed\ninstead of the actual profile. As a result, this works even if the\nprofile is deleted.</section><section id=per-app-freezing-and-more class=level3 data-number=6.6.7><h3 data-number=6.6.7><span class=header-section-number>6.6.7</span>\n<a href=#toc:per-app-freezing-and-more>Per-app freezing, and\nmore</a><a href=#per-app-freezing-and-more class=anchor aria-hidden=true></a></h3><p>Freeze/unfreeze feature now supports setting per-app freezing method\nwhich is beneficial in certain scenarios, such as when a user want to\nsuspend some apps while using the disable method as the default. In\naddition, an “Advanced suspend” option is added which force-stops an\napplication before suspending it, thus, prevent it’s services from\nrunning in the background.</section><section id=log-viewer-enhancements class=level3 data-number=6.6.8><h3 data-number=6.6.8><span class=header-section-number>6.6.8</span>\n<a href=#toc:log-viewer-enhancements>Log viewer enhancements</a><a href=#log-viewer-enhancements class=anchor aria-hidden=true></a></h3><p>Log viewer now supports enhanced searching and filtering options,\nsuch as keyword- and regular expression-based searching and filtering.\nPlease read the in-app changelog for details. Support for batch\noperations has also been added.</section><section id=launching-non-exported-activities class=level3 data-number=6.6.9><h3 data-number=6.6.9><span class=header-section-number>6.6.9</span>\n<a href=#toc:launching-non-exported-activities>Launching non-exported\nactivities</a><a href=#launching-non-exported-activities class=anchor aria-hidden=true></a></h3><p>App Manager now supports launching non-exported activities in no-root\nand ADB mode. However, in no-root mode,\n<code>android.permission.WRITE_SECURE_SETTINGS</code> permission is\nrequired.</section><section id=new-tags-in-app-info-tab class=level3 data-number=6.6.10><h3 data-number=6.6.10><span class=header-section-number>6.6.10</span> <a href=#toc:new-tags-in-app-info-tab>New tags in App Info tab</a><a href=#new-tags-in-app-info-tab class=anchor aria-hidden=true></a></h3><p>Five new tags are added in the App Info tab. They are: bloatware,\nXposed, sensors disabled, open links, and static shared libs. Clicking\non “bloatware” will display more information regarding the bloatware and\nsuggest alternatives, “Xposed” tag will display dependency information,\n“open links” will display a list of links supported by the application,\nand “static shared libs” will display all version of the application\ninstalled in the system along with an option to uninstall them. The\nlatter is useful for applications, such as Trichrome.<section id=known-issue-1 class=level5 data-number=6.6.10.0.1><h5 data-number=6.6.10.0.1><span class=header-section-number>6.6.10.0.1</span> Known issue<a href=#known-issue-1 class=anchor aria-hidden=true></a></h5><p>“Sensors disabled” only works real-time. That means if the\napplication is not currently active, this tag will always display even\nthough the applications may use sensors while it is running. This is a\nframework limitation and nothing can be done to avoid it\neffectively.</section></section><section id=per-session-installer-options class=level3 data-number=6.6.11><h3 data-number=6.6.11><span class=header-section-number>6.6.11</span> <a href=#toc:per-session-installer-options>Per-session installer\noptions</a><a href=#per-session-installer-options class=anchor aria-hidden=true></a></h3><p>It is not possible to modify installer options during the\ninstallation by clicking on the “settings” button in the installation\ndialog. The installer options will be applied to all the applications\ninstalled in the same session (i.e., the installer queue).</section><section id=advanced-mode-of-operations-adb-enhancements class=level3 data-number=6.6.12><h3 data-number=6.6.12><span class=header-section-number>6.6.12</span> <a href=#toc:advanced-mode-of-operations-adb-enhancements>Advanced mode\nof operations, ADB enhancements, …</a><a href=#advanced-mode-of-operations-adb-enhancements class=anchor aria-hidden=true></a></h3><p>App Manager now supports running its remote server (which is used as\na proxy for running privileged operations) as any supported user (UID).\nThis includes root (0), system (1000), and shell/ADB (2000) through the\ncustom commands. This is also useful for Fire TVs which have disabled\nconnecting to ADB from localhost through socket connection. In addition,\nADB pairing is now done using notifications rather than split screen.\nADB connection speed can also be improved by choosing to run App Manager\nin the background which can be configured in the settings.</section><section id=data-usage-widget-and-more class=level3 data-number=6.6.13><h3 data-number=6.6.13><span class=header-section-number>6.6.13</span> <a href=#toc:data-usage-widget-and-more>Data usage widget, and more</a><a href=#data-usage-widget-and-more class=anchor aria-hidden=true></a></h3><p>Data usage widget display the total data usage for the day, similar\nto the screen time widget which displays the total screen time for the\nday. In addition, existing widgets have been improved.</section><section id=others-1 class=level3 data-number=6.6.14><h3 data-number=6.6.14><span class=header-section-number>6.6.14</span> <a href=#toc:others-1>Others</a><a href=#others-1 class=anchor aria-hidden=true></a></h3><ul class=incremental><li><p>Replaced log viewer, sys config, Terminal, etc. with Labs\npage<li><p>Added an option to disable sensors for each app in the App Info\ntab<li><p>Added an option to perform runtime optimization of applications\nin the 1-click Ops page and in the App Info tab<li><p>Added support for Zstandard compression for\nbackup/restore<li><p>Enabling APK signing now automatically enables zip align\nfeature<li><p>Support exporting application list as CSV or JSON in the batch\noperations<li><p>Added pure black theme support<li><p>Display current activity name (when possible) in the UI Tracker\nwindow<li><p>Added an option to filter apps by user in the Main page<li><p>Display a link to Pithus report in the scanner page if\navailable.</ul></section></section><section id=sec:v3.1.0-(423) class=level2 data-number=6.7><h2 data-number=6.7><span class=header-section-number>6.7</span> <a href=#toc:sec:v3.1.0-(423)>v3.1.0 (423)</a><a href=#sec:v3.1.0-(423) class=anchor aria-hidden=true></a></h2><p>App Manager v3.1.0 comes with a few new features and a lot of\nimprovements. Visit <a href=app-manager://settings/about/version>Settings > About >\nVersion/Changelog</a> for details.<section id=android-13-support class=level3 data-number=6.7.1><h3 data-number=6.7.1><span class=header-section-number>6.7.1</span>\n<a href=#toc:android-13-support>Android 13 support</a><a href=#android-13-support class=anchor aria-hidden=true></a></h3><p>App Manager now targets Android 13 which means most issues in Android\n12 and 13 has been addressed, including SSAID and SAF issues as well as\nmonochrome icons and other theming issues.<section id=known-issue-2 class=level5 data-number=6.7.1.0.1><h5 data-number=6.7.1.0.1><span class=header-section-number>6.7.1.0.1</span> Known issue<a href=#known-issue-2 class=anchor aria-hidden=true></a></h5><p>KeyStore backup/restore not working in Android 12 and later.</section></section><section id=introducing-freezeunfreeze class=level3 data-number=6.7.2><h3 data-number=6.7.2><span class=header-section-number>6.7.2</span>\n<a href=#toc:introducing-freezeunfreeze>Introducing\nfreeze/unfreeze</a><a href=#introducing-freezeunfreeze class=anchor aria-hidden=true></a></h3><p>Enable/disable is replaced with freeze/unfreeze to allow greater\ncontrol on the behaviours of an app. It supports suspend, disable and\nhide functionalities which can be controlled at <a href=app-manager://settings/rules_prefs/freeze_type>Settings >\nRules > Default freezing method</a>. In order to make it easy to\nfreeze or unfreeze an app, shortcuts can also be created from the App\nInfo tab by long clicking on the freeze or unfreeze button.</section><section id=export-app-list class=level3 data-number=6.7.3><h3 data-number=6.7.3><span class=header-section-number>6.7.3</span>\n<a href=#toc:export-app-list>Export app list</a><a href=#export-app-list class=anchor aria-hidden=true></a></h3><p>In the Main page, it is now possible to export the list of apps in\neither XML or Markdown format using batch operations. In the future, the\nXML file may also be imported to App Manager.</section><section id=elliptic-curve-crypography-ecc class=level3 data-number=6.7.4><h3 data-number=6.7.4><span class=header-section-number>6.7.4</span>\n<a href=#toc:elliptic-curve-crypography-ecc>Elliptic Curve Crypography\n(ECC)</a><a href=#elliptic-curve-crypography-ecc class=anchor aria-hidden=true></a></h3><p>App Manager now fully supports encrypting backups using ECC in\naddition to offering AES, RSA and OpenPGP.</section><section id=new-languages class=level3 data-number=6.7.5><h3 data-number=6.7.5><span class=header-section-number>6.7.5</span>\n<a href=#toc:new-languages>New languages</a><a href=#new-languages class=anchor aria-hidden=true></a></h3><p>Two new languages are added: Korean and Romanian.</section><section id=more-list-options class=level3 data-number=6.7.6><h3 data-number=6.7.6><span class=header-section-number>6.7.6</span>\n<a href=#toc:more-list-options>More list options</a><a href=#more-list-options class=anchor aria-hidden=true></a></h3><p>In the main page, more sorting and filtering options are added.\nSorting options include sorting the apps by total size, total data\nusage, launch count, screen time and last usage time. Filtering options\ninclude filtering the apps having at least one item in the Android\nKeyStore, filtering apps with URIs granted via SAF, and filtering apps\nwith SSAID.</section><section id=improved-handling-of-mode-of-operation class=level3 data-number=6.7.7><h3 data-number=6.7.7><span class=header-section-number>6.7.7</span>\n<a href=#toc:improved-handling-of-mode-of-operation>Improved handling\nof mode of operation</a><a href=#improved-handling-of-mode-of-operation class=anchor aria-hidden=true></a></h3><p>Fixed various issues with ADB pairing, handled incomplete USB\ndebugging. Some rooting methods cannot allow interprocess communication\nvia Binder. In those cases, ADB mode is used as a fallback method by\nenabling it automatically if possible.</section><section id=handling-multiple-users class=level3 data-number=6.7.8><h3 data-number=6.7.8><span class=header-section-number>6.7.8</span>\n<a href=#toc:handling-multiple-users>Handling multiple users</a><a href=#handling-multiple-users class=anchor aria-hidden=true></a></h3><p>When possible, App Manager will be able to display apps from work\nprofile in no-root mode in addition to allowing basic operations such as\nlaunching the app or navigating to the system settings. For backups, it\nis now possible to restore backups for other users, but for work\nprofile, some apps may only work properly after re-enabling the work\nprofile. In the installer page, selecting <em>All users</em> will now\ninstall the app for all users instead of only the current user. Finally,\nin the app info tab, current app can be installed in another profile\nusing the <em>Install for…</em> option available in the three-dots menu.\nThis is analogous to the <code>pm install-existing</code> command,\nthereby, making the installation process a lot faster.</section><section id=explorer-enhancements class=level3 data-number=6.7.9><h3 data-number=6.7.9><span class=header-section-number>6.7.9</span>\n<a href=#toc:explorer-enhancements>Explorer enhancements</a><a href=#explorer-enhancements class=anchor aria-hidden=true></a></h3><p>Explorer can now open DEX and JAR files in addition to APK files.\nSeveral sorting options as well as folder options are also added as the\nlist options.</section><section id=new-tag-wx class=level3 data-number=6.7.10><h3 data-number=6.7.10><span class=header-section-number>6.7.10</span> <a href=#toc:new-tag-wx>New tag: WX</a><a href=#new-tag-wx class=anchor aria-hidden=true></a></h3><p>In app info tab, a new tag called WX is added. It is displayed in\nAndroid 10 and later if the application targets Android 9 or earlier. It\nindicates <a href=https://en.wikipedia.org/wiki/W%5EX>W^X</a>\nviolation which allows the app to execute arbitrary executable files\neither by the modification of executables embedded within the app or by\ndownloading them from the Internet.</section><section id=app-ops-management class=level3 data-number=6.7.11><h3 data-number=6.7.11><span class=header-section-number>6.7.11</span> <a href=#toc:app-ops-management>App ops management</a><a href=#app-ops-management class=anchor aria-hidden=true></a></h3><p>App ops are now managed automatically to avoid various app ops\nrelated crashes in various platforms. This will also lessen the amount\nof crashes in an unsupported operating system.</section><section id=batch-uninstallation class=level3 data-number=6.7.12><h3 data-number=6.7.12><span class=header-section-number>6.7.12</span> <a href=#toc:batch-uninstallation>Batch uninstallation</a><a href=#batch-uninstallation class=anchor aria-hidden=true></a></h3><p>In the Main page, enabled batch uninstallation in no-root mode.</section><section id=running-apps class=level3 data-number=6.7.13><h3 data-number=6.7.13><span class=header-section-number>6.7.13</span> <a href=#toc:running-apps>Running apps</a><a href=#running-apps class=anchor aria-hidden=true></a></h3><p>Enabled advanced searching. Searching now matches not only app labels\nbut also package names.</section><section id=interceptor class=level3 data-number=6.7.14><h3 data-number=6.7.14><span class=header-section-number>6.7.14</span> <a href=#toc:interceptor>Interceptor</a><a href=#interceptor class=anchor aria-hidden=true></a></h3><p>Copy the intercepted Intent as am command which can be run from\neither an ADB shell or a terminal using root with the same\neffectiveness.</section><section id=device-specific-changes class=level3 data-number=6.7.15><h3 data-number=6.7.15><span class=header-section-number>6.7.15</span> <a href=#toc:device-specific-changes>Device-specific changes</a><a href=#device-specific-changes class=anchor aria-hidden=true></a></h3><section id=graphene-os class=level5 data-number=6.7.15.0.1><h5 data-number=6.7.15.0.1><span class=header-section-number>6.7.15.0.1</span> Graphene OS<a href=#graphene-os class=anchor aria-hidden=true></a></h5><p>Explicitly handle the Internet permission which is a runtime\npermission in the OS.</section><section id=miui class=level5 data-number=6.7.15.0.2><h5 data-number=6.7.15.0.2><span class=header-section-number>6.7.15.0.2</span> MIUI<a href=#miui class=anchor aria-hidden=true></a></h5><p>Fixed permission denied issues in the installer due to a framework\nissue introduced in MIUI 12.5.</section><section id=motorola class=level5 data-number=6.7.15.0.3><h5 data-number=6.7.15.0.3><span class=header-section-number>6.7.15.0.3</span> Motorola<a href=#motorola class=anchor aria-hidden=true></a></h5><p>Fixed crashes in the Interceptor page due to a framework issue\nintroduced in Android 11.</section></section><section id=others-2 class=level3 data-number=6.7.16><h3 data-number=6.7.16><span class=header-section-number>6.7.16</span> <a href=#toc:others-2>Others</a><a href=#others-2 class=anchor aria-hidden=true></a></h3><ul class=incremental><li><p>Improved Java-Smali conversion by including all the subclasses\nduring conversion<li><p>Improved scanning performance in the Scanner page<li><p>Improved updating the list of apps in the Main page<li><p>Scan all the available paths to detect systemless-ly installed\nsystem apps<li><p><code>vacuum</code> SQLite database before opening it for viewing\nor editing.</ul></section></section><section id=sec:v3.0.0-(410) class=level2 data-number=6.8><h2 data-number=6.8><span class=header-section-number>6.8</span> <a href=#toc:sec:v3.0.0-(410)>v3.0.0 (410)</a><a href=#sec:v3.0.0-(410) class=anchor aria-hidden=true></a></h2><p>App Manager v3.0.0 comes with a lot of features and improvements. See\n<a href=app-manager://settings/about/version>Settings > About >\nVersion/Changelog</a> to see a more detailed changelog.<section id=material-3-and-more class=level3 data-number=6.8.1><h3 data-number=6.8.1><span class=header-section-number>6.8.1</span>\n<a href=#toc:material-3-and-more>Material 3 and More</a><a href=#material-3-and-more class=anchor aria-hidden=true></a></h3><p>Material 3, somewhat similar to <em>Material You</em>, is a\nsignificant improvement over Material Design 2 with support for dynamic\ncolours in Android 12 and later. In addition, many design changes have\nbeen made in App Manager without any significant changes in the overall\nuser experience.<section id=known-issue-3 class=level5 data-number=6.8.1.0.1><h5 data-number=6.8.1.0.1><span class=header-section-number>6.8.1.0.1</span> Known issue<a href=#known-issue-3 class=anchor aria-hidden=true></a></h5><p>Switches are still based on Material Design 2 which will be fixed in\na future release.</section></section><section id=wireless-debugging class=level3 data-number=6.8.2><h3 data-number=6.8.2><span class=header-section-number>6.8.2</span>\n<a href=#toc:wireless-debugging>Wireless Debugging</a><a href=#wireless-debugging class=anchor aria-hidden=true></a></h3><p>Wireless debugging support has been fully implemented. Head over to\n§<a href=#sec:wireless-debugging data-reference-type=ref data-reference=sec:wireless-debugging>3.2</a> for instructions on how\nto configure wireless debugging.<div class=\"amalert tip\"><p><strong><em>No-root users :</em></strong><p>Due to auto-detection feature, startup time might be large for\nno-root users when the mode of operation is set to <em>auto</em>.\nInstead, no-root users should select <em>no-root</em> instead of\n<em>auto</em>.</div></section><section id=languages class=level3 data-number=6.8.3><h3 data-number=6.8.3><span class=header-section-number>6.8.3</span>\n<a href=#toc:languages>Languages</a><a href=#languages class=anchor aria-hidden=true></a></h3><p>App Manager is fully translated into Indonesian and Italian languages\nand can be enabled in settings. Bengali is removed due to lack of\ntranslators.</section><section id=introducing-app-explorer class=level3 data-number=6.8.4><h3 data-number=6.8.4><span class=header-section-number>6.8.4</span>\n<a href=#toc:introducing-app-explorer>Introducing App Explorer</a><a href=#introducing-app-explorer class=anchor aria-hidden=true></a></h3><p>App Explorer can be used to browse the contents of an application.\nThis includes binary XML files, DEX contents or any other media files.\nDEX contents can only be explored in Android Oreo (Android 8) and later.\nIt’s also possible to convert an <code>.smali</code> file into\n<code>.java</code> for a better understanding of the reversed code. This\nfeature, if not needed, can be disabled in Settings > Enable/disable\nfeatures.</section><section id=import-backups-from-other-applications class=level3 data-number=6.8.5><h3 data-number=6.8.5><span class=header-section-number>6.8.5</span>\n<a href=#toc:import-backups-from-other-applications>Import Backups\nfrom Other Applications</a><a href=#import-backups-from-other-applications class=anchor aria-hidden=true></a></h3><p>It is possible to import backups from discontinued or obsolete\napplications such as Titanium Backup, OAndBackup and Swift Backup\n(version 3.0 to 3.2). Go to Setting > Backup/restore to find this\noption.</section><section id=virustotal class=level3 data-number=6.8.6><h3 data-number=6.8.6><span class=header-section-number>6.8.6</span>\n<a href=#toc:virustotal>VirusTotal</a><a href=#virustotal class=anchor aria-hidden=true></a></h3><p>VirusTotal is a widely used tool to scan files and URLs for viruses.\nIn the scanner page and in the running apps page, an option to scan\nfiles with VirusTotal has been added. But the option is hidden by\ndefault. To enable the option, it is necessary to obtain an API key from\nVirusTotal. Go to Settings > VirusTotal API Key for more\ninformation.<div class=\"amalert warning\"><p><strong><em>Internet feature :</em></strong><p>This is currently the only feature which require an Internet\nconnection. If you wish to use any Internet feature that might also be\nadded in the future, enable <em>Use the Internet</em> in Settings >\nEnable/disable features.</div></section><section id=trigger-profiles-from-the-automation-software class=level3 data-number=6.8.7><h3 data-number=6.8.7><span class=header-section-number>6.8.7</span>\n<a href=#toc:trigger-profiles-from-the-automation-software>Trigger\nProfiles from the Automation Software</a><a href=#trigger-profiles-from-the-automation-software class=anchor aria-hidden=true></a></h3><p>As the implementation of routine operations is being delayed, an\noption to trigger profiles from the external automation software is\nadded. See §<a href=#sec:automating-tasks data-reference-type=ref data-reference=sec:automating-tasks>3.4</a> for instructions on how to\nconfigure profile automation.</section><section id=improved-application-installer class=level3 data-number=6.8.8><h3 data-number=6.8.8><span class=header-section-number>6.8.8</span>\n<a href=#toc:improved-application-installer>Improved Application\nInstaller</a><a href=#improved-application-installer class=anchor aria-hidden=true></a></h3><p>Application installer includes several improvements including the\nability to downgrade applications in no-root mode, installing multiple\napplications at once and blocking trackers after installation. In\nAndroid 12 and later, no-root users can update applications without any\nuser interactions.</section><section id=component-blocking class=level3 data-number=6.8.9><h3 data-number=6.8.9><span class=header-section-number>6.8.9</span>\n<a href=#toc:component-blocking>Component Blocking</a><a href=#component-blocking class=anchor aria-hidden=true></a></h3><p>It is now possible to configure how App Manager should block a\ncomponent. Visit Settings > Rules > Default blocking method for\nmore information. In the components tab, long clicking the block/unblock\nbutton opens a context menu which allows per-component blocking in a\nsimilar manner. ADB users can also block the components of a <em>Test\nonly</em> app.</section><section id=advanced-searching class=level3 data-number=6.8.10><h3 data-number=6.8.10><span class=header-section-number>6.8.10</span> <a href=#toc:advanced-searching>Advanced Searching</a><a href=#advanced-searching class=anchor aria-hidden=true></a></h3><p>In some pages, the search bar supports additional searching which\nincludes searching via prefix, suffix or even regular expressions. In\nthe main page, it is also possible to search for applications using the\nfirst letters of each word, e.g. <em>App Manager</em> can be listed by\nsearching for <em>am</em>.</section><section id=shared-libraries class=level3 data-number=6.8.11><h3 data-number=6.8.11><span class=header-section-number>6.8.11</span> <a href=#toc:shared-libraries>Shared Libraries</a><a href=#shared-libraries class=anchor aria-hidden=true></a></h3><p>Shared libraries tab has received a significant improvements. It can\ndisplay three types of libraries, such as native, jar and APK files.</section><section id=make-the-best-use-of-interceptor class=level3 data-number=6.8.12><h3 data-number=6.8.12><span class=header-section-number>6.8.12</span> <a href=#toc:make-the-best-use-of-interceptor>Make the Best Use of\nInterceptor</a><a href=#make-the-best-use-of-interceptor class=anchor aria-hidden=true></a></h3><p>Activity interceptor can be opened directly from the activities tab\nby long clicking on the launch button, and similarly, activities can be\nlaunched from the activity interceptor page with or without root, for\nany users.<div class=\"amalert tip\"><p><strong><em>Notice :</em></strong><p>Currently, activities opened via root cannot send the results back to\nthe original applications.</div></section><section id=widget-screen-time class=level3 data-number=6.8.13><h3 data-number=6.8.13><span class=header-section-number>6.8.13</span> <a href=#toc:widget-screen-time>Widget: Screen Time</a><a href=#widget-screen-time class=anchor aria-hidden=true></a></h3><p>Screen time widget is quite similar to Digital Wellbeing’s widget by\nthe same name. It displays the total screen time for the day along with\nthe top three apps from all users.</section><section id=widget-clear-cache class=level3 data-number=6.8.14><h3 data-number=6.8.14><span class=header-section-number>6.8.14</span> <a href=#toc:widget-clear-cache>Widget: Clear Cache</a><a href=#widget-clear-cache class=anchor aria-hidden=true></a></h3><p>Clear cache widget can be to clear cache from all the applications\ndirectly from the home screen.</section></section><section id=sec:v2.6.0-(385) class=level2 data-number=6.9><h2 data-number=6.9><span class=header-section-number>6.9</span> <a href=#toc:sec:v2.6.0-(385)>v2.6.0 (385)</a><a href=#sec:v2.6.0-(385) class=anchor aria-hidden=true></a></h2><section id=introducing-backups class=level3 data-number=6.9.1><h3 data-number=6.9.1><span class=header-section-number>6.9.1</span>\n<a href=#toc:introducing-backups>Introducing Backups</a><a href=#introducing-backups class=anchor aria-hidden=true></a></h3><p>Back up/restore feature is now finally out of beta! Read <a href=#sec:backup-restore>the corresponding guide</a> to understand how\nit works.</section><section id=introducing-log-viewer class=level3 data-number=6.9.2><h3 data-number=6.9.2><span class=header-section-number>6.9.2</span>\n<a href=#toc:introducing-log-viewer>Introducing Log Viewer</a><a href=#introducing-log-viewer class=anchor aria-hidden=true></a></h3><p><a href=#subsubsec:log-viewer>Log viewer</a> is essentially a\nfront-end for <code>logcat</code>. It can be used to filter logs by\n<em>tag</em> or <em>pid</em> (process ID), or even by custom filters.\nLog levels AKA verbosity can also be configured. You can also save,\nshare and manage logs.</section><section id=lock-app-manager class=level3 data-number=6.9.3><h3 data-number=6.9.3><span class=header-section-number>6.9.3</span>\n<a href=#toc:lock-app-manager>Lock App Manager</a><a href=#lock-app-manager class=anchor aria-hidden=true></a></h3><p><a href=#subsubsec:screen-lock>Lock App Manager</a> with the screen\nlock configured for your device.</section><section id=extended-modes-for-app-ops class=level3 data-number=6.9.4><h3 data-number=6.9.4><span class=header-section-number>6.9.4</span>\n<a href=#toc:extended-modes-for-app-ops>Extended Modes for App\nOps</a><a href=#extended-modes-for-app-ops class=anchor aria-hidden=true></a></h3><p>You can set any mode for any app ops that your device supports,\neither from the <a href=#subsec:set-mode-for-app-ops-dots>1-click ops\npage</a> or from the <a href=#subsubsec:app-ops>app ops tab</a>.</section><section id=new-batch-ops-add-to-profile class=level3 data-number=6.9.5><h3 data-number=6.9.5><span class=header-section-number>6.9.5</span>\n<a href=#toc:new-batch-ops-add-to-profile>New Batch Ops: Add to\nProfile</a><a href=#new-batch-ops-add-to-profile class=anchor aria-hidden=true></a></h3><p>You can now easily add selected apps to an existing profile using the\nbatch operations.</section><section id=app-info-improved class=level3 data-number=6.9.6><h3 data-number=6.9.6><span class=header-section-number>6.9.6</span>\n<a href=#toc:app-info-improved>App Info: Improved</a><a href=#app-info-improved class=anchor aria-hidden=true></a></h3><p>App info tab now has many options, including the ability to change <a href=#sec:terminologies>SSAID</a>, network policy (i.e. background\nnetwork usage), battery optimization, etc. Most of the tags used in this\ntab are also clickable, and if you click on them, you will be able to\nlook at the current state or configure them right away.</section><section id=advanced-sort-and-filtering-options-in-the-main-page class=level3 data-number=6.9.7><h3 data-number=6.9.7><span class=header-section-number>6.9.7</span>\n<a href=#toc:advanced-sort-and-filtering-options-in-the-main-page>Advanced\nSort and Filtering Options in the Main Page</a><a href=#advanced-sort-and-filtering-options-in-the-main-page class=anchor aria-hidden=true></a></h3><p>Sort and filter options are now replaced by <a href=#subsubsec:main-list-options>List Options</a> which is highly\nconfigurable, including the ability to filter using profiles.</section><section id=about-this-device class=level3 data-number=6.9.8><h3 data-number=6.9.8><span class=header-section-number>6.9.8</span>\n<a href=#toc:about-this-device>About This Device</a><a href=#about-this-device class=anchor aria-hidden=true></a></h3><p>Interested in knowing about your device in just one page? Go to the\nbottom of the <a href=#subsec:device-info>settings page</a>.</section><section id=enabledisable-features class=level3 data-number=6.9.9><h3 data-number=6.9.9><span class=header-section-number>6.9.9</span>\n<a href=#toc:enabledisable-features>Enable/disable Features</a><a href=#enabledisable-features class=anchor aria-hidden=true></a></h3><p>Not interested in all the features that AM offers? You can disable\nsome features in <a href=#subsubsec:enable/disable-features>settings</a>.</section><section id=new-languages-1 class=level3 data-number=6.9.10><h3 data-number=6.9.10><span class=header-section-number>6.9.10</span> <a href=#toc:new-languages-1>New Languages</a><a href=#new-languages-1 class=anchor aria-hidden=true></a></h3><p>AM now has more than 19 languages! New languages include Farsi,\nJapanese and Traditional Chinese.</section><section id=signing-the-apk-files class=level3 data-number=6.9.11><h3 data-number=6.9.11><span class=header-section-number>6.9.11</span> <a href=#toc:signing-the-apk-files>Signing the APK Files</a><a href=#signing-the-apk-files class=anchor aria-hidden=true></a></h3><p>You can now import external signing keys in AM! For security, App\nManager has its own encrypted KeyStore which can also be <a href=#subsubsec:import/export-keystore>imported or exported</a>.</section><section id=new-extension-unapkm class=level3 data-number=6.9.12><h3 data-number=6.9.12><span class=header-section-number>6.9.12</span> <a href=#toc:new-extension-unapkm>New Extension: UnAPKM</a><a href=#new-extension-unapkm class=anchor aria-hidden=true></a></h3><p>Since APKMirror has removed encryption from their APKM files, it’s no\nlonger necessary to decrypt them. As a result, the option to decrypt\nAPKM files has been removed. Instead, this option is now provided by the\nUnAPKM extension which you can grab from <a href=https://f-droid.org/packages/io.github.muntashirakon.unapkm/>F-Droid</a>.\nSo, if you have an encrypted APKM file and have this extension\ninstalled, you can open the file directly in AM.</section></section><section id=sec:v2.5.20-(375) class=level2 data-number=6.10><h2 data-number=6.10><span class=header-section-number>6.10</span>\n<a href=#toc:sec:v2.5.20-(375)>v2.5.20 (375)</a><a href=#sec:v2.5.20-(375) class=anchor aria-hidden=true></a></h2><section id=subsec:introducing-profiles class=level3 data-number=6.10.1><h3 data-number=6.10.1><span class=header-section-number>6.10.1</span> <a href=#toc:subsec:introducing-profiles>Introducing Profiles</a><a href=#subsec:introducing-profiles class=anchor aria-hidden=true></a></h3><p><a href=#sec:profile-page>Profiles</a> finally closes the <a href=https://github.com/MuntashirAkon/AppManager/issues/72>related\nissue</a>. Profiles can be used to execute certain tasks repeatedly\nwithout doing everything manually. A profile can be applied (or invoked)\neither from the <a href=#sec:profiles-page>Profiles page</a> or from\nthe home screen by creating shortcuts. There are also some presets which\nconsist of debloating profiles taken from <a href=https://gitlab.com/W1nst0n/universal-android-debloater>Universal\nAndroid Debloater</a>.<section id=known-limitations class=level5 data-number=6.10.1.0.1><h5 data-number=6.10.1.0.1><span class=header-section-number>6.10.1.0.1</span> Known limitations<a href=#known-limitations class=anchor aria-hidden=true></a></h5><ul class=incremental><li><p>Exporting rules and applying permissions are not currently\nworking.<li><p>Profiles are applied for all users.</ul></section></section><section id=subsec:the-interceptor class=level3 data-number=6.10.2><h3 data-number=6.10.2><span class=header-section-number>6.10.2</span> <a href=#toc:subsec:the-interceptor>The Interceptor</a><a href=#subsec:the-interceptor class=anchor aria-hidden=true></a></h3><p><a href=https://github.com/MuntashirAkon/intent-intercept>Intent\nIntercept</a> works as a man-in-the-middle between source and\ndestination, that is, when you open a file or URL with another app, you\ncan see what is being shared by opening it with Interceptor first. You\ncan also add or modify the intents before sending them to the\ndestination. Additionally, you can double-click on any exportable\nactivities in the Activities tab in the App Details page to open them in\nthe Interceptor to add more configurations.<section id=known-limitation-2 class=level5 data-number=6.10.2.0.1><h5 data-number=6.10.2.0.1><span class=header-section-number>6.10.2.0.1</span> Known limitation<a href=#known-limitation-2 class=anchor aria-hidden=true></a></h5><p>Editing extras is not currently possible.</section></section><section id=subsec:unapkm:-dedrm-the-apkm-files class=level3 data-number=6.10.3><h3 data-number=6.10.3><span class=header-section-number>6.10.3</span> <a href=#toc:subsec:unapkm:-dedrm-the-apkm-files>UnAPKM: DeDRM the APKM\nfiles</a><a href=#subsec:unapkm:-dedrm-the-apkm-files class=anchor aria-hidden=true></a></h3><p>When I released a small tool called <a href=https://f-droid.org/en/packages/io.github.muntashirakon.unapkm>UnAPKM</a>,\nI promised that similar feature will be available in App Manager. I am\nproud to announce that you can open APKM files directly in the App Info\npage or convert them to APKS or install them directly.</section><section id=subsec:multiple-user class=level3 data-number=6.10.4><h3 data-number=6.10.4><span class=header-section-number>6.10.4</span> <a href=#toc:subsec:multiple-user>Multiple user</a><a href=#subsec:multiple-user class=anchor aria-hidden=true></a></h3><p>App manager now supports multiple users! For now, this requires root\nor ADB. But no-root support is also being considered. If you have\nmultiple users enabled and click on an app installed in multiple\nprofiles, an alert prompt will be displayed where you can select the\nuser.</section><section id=vive-la-france class=level3 data-number=6.10.5><h3 data-number=6.10.5><span class=header-section-number>6.10.5</span> <a href=#toc:vive-la-france>Vive la France!</a><a href=#vive-la-france class=anchor aria-hidden=true></a></h3><p>Thanks to the contributors, we have one more addition to the language\nclub: French. You can add more languages or improve existing\ntranslations at <a href=https://hosted.weblate.org/engage/app-manager>Weblate</a>.</section><section id=report-crashes class=level3 data-number=6.10.6><h3 data-number=6.10.6><span class=header-section-number>6.10.6</span> <a href=#toc:report-crashes>Report crashes</a><a href=#report-crashes class=anchor aria-hidden=true></a></h3><p>If App Manager crashes, you can now easily report the crash from the\nnotifications which opens the share options. Crashes are not reported by\nApp Manager, it only redirects you to your favourite Email client.</section><section id=android-11 class=level3 data-number=6.10.7><h3 data-number=6.10.7><span class=header-section-number>6.10.7</span> <a href=#toc:android-11>Android 11</a><a href=#android-11 class=anchor aria-hidden=true></a></h3><p>Added support for Android 11. Not everything may work as expected\nthough.</section><section id=app-installer-improvements class=level3 data-number=6.10.8><h3 data-number=6.10.8><span class=header-section-number>6.10.8</span> <a href=#toc:app-installer-improvements>App Installer Improvements</a><a href=#app-installer-improvements class=anchor aria-hidden=true></a></h3><section id=set-installation-locations class=level4 data-number=6.10.8.1><h4 data-number=6.10.8.1><span class=header-section-number>6.10.8.1</span> Set installation\nlocations<a href=#set-installation-locations class=anchor aria-hidden=true></a></h4><p>In settings page, you can set install locations such as auto\n(default), internal only and prefer external.</section><section id=set-apk-installer class=level4 data-number=6.10.8.2><h4 data-number=6.10.8.2><span class=header-section-number>6.10.8.2</span> Set APK installer<a href=#set-apk-installer class=anchor aria-hidden=true></a></h4><p>In settings page, you can also set default APK installer (root/ADB\nonly) instead of App Manager.</section><section id=multiple-users class=level4 data-number=6.10.8.3><h4 data-number=6.10.8.3><span class=header-section-number>6.10.8.3</span> Multiple users<a href=#multiple-users class=anchor aria-hidden=true></a></h4><p>In settings page, you can allow App Manager to display multiple users\nduring APK installation.</section><section id=signing-apk-files class=level4 data-number=6.10.8.4><h4 data-number=6.10.8.4><span class=header-section-number>6.10.8.4</span> Signing APK files<a href=#signing-apk-files class=anchor aria-hidden=true></a></h4><p>In settings page, you can choose to sign APK files before installing\nthem. You can also select which signature scheme to use in the <em>APK\nsigning</em> option in settings.<section id=known-limitation-3 class=level5 data-number=6.10.8.4.1><h5 data-number=6.10.8.4.1><span class=header-section-number>6.10.8.4.1</span> Known limitation<a href=#known-limitation-3 class=anchor aria-hidden=true></a></h5><p>Currently, only a generic key is used to sign APK files</section></section></section></section><section id=v2.5.17-368 class=level2 data-number=6.11><h2 data-number=6.11><span class=header-section-number>6.11</span>\n<a href=#toc:v2.5.17-368>v2.5.17 (368)</a><a href=#v2.5.17-368 class=anchor aria-hidden=true></a></h2><section id=app-installer class=level3 data-number=6.11.1><h3 data-number=6.11.1><span class=header-section-number>6.11.1</span> <a href=#toc:app-installer>App Installer</a><a href=#app-installer class=anchor aria-hidden=true></a></h3><p>As promised, it is now possible to select splits. AM also provides\nrecommendations based on device configurations. If the app is already\ninstalled, recommendations are provided based on the installed app. It\nis also possible to downgrade to a lower version without data loss if\nthe device has root or ADB. But it should be noted that not all app can\nbe downgraded. Installer is also improved to speed up the installation\nprocess, especially, for root users. If the app has already been\ninstalled and the new (x)apk(s) is newer or older or the same version\nwith a different signature, AM will display a list of changes similar to\n<strong>What’s New</strong> before prompting the user to install the\napp. This is useful if the app has introduced tracker components, new\npermissions, etc.<section id=known-limitations-1 class=level5 data-number=6.11.1.0.1><h5 data-number=6.11.1.0.1><span class=header-section-number>6.11.1.0.1</span> Known Limitations<a href=#known-limitations-1 class=anchor aria-hidden=true></a></h5><ul class=incremental><li><p>Large app can take a long time to fetch app info, and therefore,\nit may take a long time display the installation prompt.<li><p>If the apk is not located in the internal storage, the app has to\nbe cached first which might also take a long time depending on the size\nof the apk.</ul></section></section><section id=scanner-replacement-for-exodus-page class=level3 data-number=6.11.2><h3 data-number=6.11.2><span class=header-section-number>6.11.2</span> <a href=#toc:scanner-replacement-for-exodus-page>Scanner: Replacement for\nExodus Page</a><a href=#scanner-replacement-for-exodus-page class=anchor aria-hidden=true></a></h3><p>Exodus page is now replaced with scanner page. <a href=#sec:scanner-page>Scanner page</a> contains not only a list of\ntrackers but also a list of used libraries. This is just a start. In the\nfuture, this page will contain more in depth analysis of the app.</section><section id=introducing-system-config class=level3 data-number=6.11.3><h3 data-number=6.11.3><span class=header-section-number>6.11.3</span> <a href=#toc:introducing-system-config>Introducing System Config</a><a href=#introducing-system-config class=anchor aria-hidden=true></a></h3><p>System Config lists various system configurations and\nwhitelists/blacklists included in Android by either OEM/vendor, AOSP or\neven some Magisk modules. Root users can access this option from the\noverflow menu in the main page. There isn’t any official documentation\nfor these options therefore it’s difficult to write a complete\ndocumentation for this page. I will gradually add documentations using\nmy own knowledge. However, some functions should be understandable by\ntheir name.</section><section id=more-languages class=level3 data-number=6.11.4><h3 data-number=6.11.4><span class=header-section-number>6.11.4</span> <a href=#toc:more-languages>More Languages</a><a href=#more-languages class=anchor aria-hidden=true></a></h3><p>Thanks to the contributors, AM now has more than 12 languages. New\nlanguages include Bengali, Hindi, Norwegian, Polish, Russian, Simplified\nChinese, Turkish and Ukrainian.</section><section id=app-info-tab class=level3 data-number=6.11.5><h3 data-number=6.11.5><span class=header-section-number>6.11.5</span> <a href=#toc:app-info-tab>App Info Tab</a><a href=#app-info-tab class=anchor aria-hidden=true></a></h3><p>More tags are added in the <a href=#subsec:app-info-tab>app info\ntab</a> such as <strong>KeyStore</strong> (apps with KeyStore items),\n<strong>Systemless app</strong> (apps installed via Magisk),\n<strong>Running</strong> (apps that are running). For external apk, two\nmore options are added namely <strong>Reinstall</strong> and\n<strong>Downgrade</strong>. Now it is possible to share an apk via\nBluetooth. For system apps, it is possible to uninstall updates for\nroot/ADB users. But like the similar option in the system settings, this\noperation will clear all app data. As stated above, exodus has been\nreplaced with scanner.</section><section id=navigation-improvements class=level3 data-number=6.11.6><h3 data-number=6.11.6><span class=header-section-number>6.11.6</span> <a href=#toc:navigation-improvements>Navigation Improvements</a><a href=#navigation-improvements class=anchor aria-hidden=true></a></h3><p>It’s now relatively easy to navigate to various UI components using\nkeyboard. You can use up/down button to navigate between list items and\ntab button to navigate to UI components inside an item.</section><section id=running-apps-page class=level3 data-number=6.11.7><h3 data-number=6.11.7><span class=header-section-number>6.11.7</span> <a href=#toc:running-apps-page>Running Apps Page</a><a href=#running-apps-page class=anchor aria-hidden=true></a></h3><p>It is now possible to sort and filter processes in this tab. Also,\nthe three big buttons are replaced with an easy-to-use three dot menu.\nPreviously the memory usage was wrong which is fixed in this\nversion.</section><section id=built-in-toybox class=level3 data-number=6.11.8><h3 data-number=6.11.8><span class=header-section-number>6.11.8</span> <a href=#toc:built-in-toybox>Built-in Toybox</a><a href=#built-in-toybox class=anchor aria-hidden=true></a></h3><p>Toybox (an alternative to busybox) is bundled with AM. Although\nAndroid has this utility built-in from API 23, toybox is bundled in\norder to prevent buggy implementations and to support API &lt; 23.</section><section id=component-blocker-improvements class=level3 data-number=6.11.9><h3 data-number=6.11.9><span class=header-section-number>6.11.9</span> <a href=#toc:component-blocker-improvements>Component Blocker\nImprovements</a><a href=#component-blocker-improvements class=anchor aria-hidden=true></a></h3><p>Component blocker seemed to be problematic in the previous version,\nespecially when global component blocking is enabled. The issues are\nmostly fixed now.<div class=\"amalert warning\"><p><strong><em>Caution :</em></strong><p>The component blocking mechanism is no longer compatible with v2.5.6\ndue to various security issues. If you have this version, upgrade to\nv2.5.13 or earlier versions first. After that, enable <a href=#subsubsec:instant-component-blocking>global component\nblocking</a> and disable it again.</div></section><section id=improvements-in-the-app-details-page class=level3 data-number=6.11.10><h3 data-number=6.11.10><span class=header-section-number>6.11.10</span> <a href=#toc:improvements-in-the-app-details-page>Improvements in the App\nDetails Page</a><a href=#improvements-in-the-app-details-page class=anchor aria-hidden=true></a></h3><p>Value of various app ops depend on their parent app ops. Therefore,\nwhen you allow/deny an app op, the parent of the app op gets modified.\nThis fixes the issues some users have been complaining regarding some\napp ops that couldn’t be changed.<p>If an app has the target API 23 or less, its permissions cannot be\nmodified using the <code>pm grant …</code> command. Therefore, for such\napps, option to toggle permission has been disabled.<p>The signature tab is improved to support localization. It also\ndisplays multiple checksums for a signature.</section><section id=app-manifest class=level3 data-number=6.11.11><h3 data-number=6.11.11><span class=header-section-number>6.11.11</span> <a href=#toc:app-manifest>App Manifest</a><a href=#app-manifest class=anchor aria-hidden=true></a></h3><p>Manifest no longer crashes if the size of the manifest is too long.\nGenerated manifest are now more accurate than before.</section></section><section id=v2.5.13-348 class=level2 data-number=6.12><h2 data-number=6.12><span class=header-section-number>6.12</span>\n<a href=#toc:v2.5.13-348>v2.5.13 (348)</a><a href=#v2.5.13-348 class=anchor aria-hidden=true></a></h2><section id=bundled-app-split-apk class=level3 data-number=6.12.1><h3 data-number=6.12.1><span class=header-section-number>6.12.1</span> <a href=#toc:bundled-app-split-apk>Bundled App (Split APK)</a><a href=#bundled-app-split-apk class=anchor aria-hidden=true></a></h3><p>Bundled app formats such as <strong>apks</strong> and\n<strong>xapk</strong> are now supported. You can install these apps\nusing the regular installation buttons. For root and adb users, apps are\ninstalled using shell, and for non-root users, the platform default\nmethod is used.<section id=known-limitations-2 class=level5 data-number=6.12.1.0.1><h5 data-number=6.12.1.0.1><span class=header-section-number>6.12.1.0.1</span> Known Limitations<a href=#known-limitations-2 class=anchor aria-hidden=true></a></h5><ul class=incremental><li><p>Currently <em>all</em> splits apks are installed. But this\nbehaviour is going to change in the next release. If you only need a few\nsplits instead of all, extract the <strong>APKS</strong> or\n<strong>XAPK</strong> file, and then, create a new zip file with your\ndesired split apks and replace the <strong>ZIP</strong> extension with\n<strong>APKS</strong>. Now, open it with AM.<li><p>There is no progress dialog to display the installation\nprogress.</ul></section></section><section id=direct-install-support class=level3 data-number=6.12.2><h3 data-number=6.12.2><span class=header-section-number>6.12.2</span> <a href=#toc:direct-install-support>Direct Install Support</a><a href=#direct-install-support class=anchor aria-hidden=true></a></h3><p>You can now install <strong>APK</strong>, <strong>APKS</strong> or\n<strong>XAPK</strong> directly from your favourite browser or file\nmanager. For apps that need updates, a <strong>What’s New</strong>\ndialog is displayed showing the changes in the new version.<section id=known-limitations-3 class=level5 data-number=6.12.2.0.1><h5 data-number=6.12.2.0.1><span class=header-section-number>6.12.2.0.1</span> Known Limitations<a href=#known-limitations-3 class=anchor aria-hidden=true></a></h5><ul class=incremental><li><p>Downgrade is not yet possible.<li><p>There is no progress dialog to display the installation progress.\nIf you cannot interact with the current page, wait until the\ninstallation is finished.</ul></section></section><section id=remove-all-blocking-rules class=level3 data-number=6.12.3><h3 data-number=6.12.3><span class=header-section-number>6.12.3</span> <a href=#toc:remove-all-blocking-rules>Remove All Blocking Rules</a><a href=#remove-all-blocking-rules class=anchor aria-hidden=true></a></h3><p>In the Settings page, a new option is added which can be used to\nremove all blocking rules configured within App Manager.</section><section id=app-ops-1 class=level3 data-number=6.12.4><h3 data-number=6.12.4><span class=header-section-number>6.12.4</span> <a href=#toc:app-ops-1>App\nOps</a><a href=#app-ops-1 class=anchor aria-hidden=true></a></h3><ul class=incremental><li><p>App Ops are now generated using a technique similar to AppOpsX.\nThis should decrease the loading time significantly in the App Ops\ntab.<li><p>In the App Ops tab, a menu item is added which can be used to\nlist only active app ops without including the default app ops. The\npreference is saved in the shared preferences.</ul><section id=known-limitation-4 class=level5 data-number=6.12.4.0.1><h5 data-number=6.12.4.0.1><span class=header-section-number>6.12.4.0.1</span> Known Limitation<a href=#known-limitation-4 class=anchor aria-hidden=true></a></h5><p>Often the App Ops tab may not be responsive. If that’s the case,\nrestart App Manager.</section></section><section id=enhanced-adb-support class=level3 data-number=6.12.5><h3 data-number=6.12.5><span class=header-section-number>6.12.5</span> <a href=#toc:enhanced-adb-support>Enhanced ADB Support</a><a href=#enhanced-adb-support class=anchor aria-hidden=true></a></h3><p>ADB shell commands are now executed using a technique similar to\nAppOpsX (This is the <em>free</em> alternative of AppOps by Rikka.).\nThis should dramatically increase the execution time.<section id=known-limitation-5 class=level5 data-number=6.12.5.0.1><h5 data-number=6.12.5.0.1><span class=header-section-number>6.12.5.0.1</span> Known Limitation<a href=#known-limitation-5 class=anchor aria-hidden=true></a></h5><p>AM can often crash or become not responsive. If that’s the case,\nrestart App Manager.</section></section><section id=filtering-in-main-page class=level3 data-number=6.12.6><h3 data-number=6.12.6><span class=header-section-number>6.12.6</span> <a href=#toc:filtering-in-main-page>Filtering in Main Page</a><a href=#filtering-in-main-page class=anchor aria-hidden=true></a></h3><p>Add an option to filter apps that has at least one activity.</section><section id=apk-backupsharing class=level3 data-number=6.12.7><h3 data-number=6.12.7><span class=header-section-number>6.12.7</span> <a href=#toc:apk-backupsharing>Apk Backup/Sharing</a><a href=#apk-backupsharing class=anchor aria-hidden=true></a></h3><p>Apk files are now saved as <code>app name_version.extension</code>\ninstead of <code>package.name.extension</code>.</section><section id=batch-ops class=level3 data-number=6.12.8><h3 data-number=6.12.8><span class=header-section-number>6.12.8</span> <a href=#toc:batch-ops>Batch Ops</a><a href=#batch-ops class=anchor aria-hidden=true></a></h3><ul class=incremental><li><p>Added a foreground service to run batch operations. The result of\nthe operation is displayed in a notification. If an operation has failed\nfor some packages, clicking on the notification will open a dialog box\nlisting the failed packages. There is also a <strong>Try Again</strong>\nbutton on the bottom which can be used to perform the operation again\nfor the failed packages.<li><p>Replaced Linux <em>kill</em> with\n<strong>force-stop</strong>.</ul></section><section id=translations class=level3 data-number=6.12.9><h3 data-number=6.12.9><span class=header-section-number>6.12.9</span> <a href=#toc:translations>Translations</a><a href=#translations class=anchor aria-hidden=true></a></h3><p>Added German and Portuguese (Brazilian) translations.<section id=known-limitation-6 class=level5 data-number=6.12.9.0.1><h5 data-number=6.12.9.0.1><span class=header-section-number>6.12.9.0.1</span> Known Limitation<a href=#known-limitation-6 class=anchor aria-hidden=true></a></h5><p>Not all translations are verified yet.</section></section><section id=app-data-backup class=level3 data-number=6.12.10><h3 data-number=6.12.10><span class=header-section-number>6.12.10</span> <a href=#toc:app-data-backup>App Data Backup</a><a href=#app-data-backup class=anchor aria-hidden=true></a></h3><p>Install app only for the current user at the time of restoring\nbackups. Support for split apks is also added.<p><em>Data backup feature is now considered unstable. If you encounter\nany problem, please report to me without hesitation.</em></section></section></section><section id=ch:app-ops class=level1 data-number=7><h1 data-number=7><span class=header-section-number>7</span> <a href=#toc:ch:app-ops>App Ops</a><a href=#ch:app-ops class=anchor aria-hidden=true></a></h1><section id=sec:app-ops-background class=level2 data-number=7.1><h2 data-number=7.1><span class=header-section-number>7.1</span> <a href=#toc:sec:app-ops-background>Background</a><a href=#sec:app-ops-background class=anchor aria-hidden=true></a></h2><p><strong>App Ops</strong> (short hand for <strong>Application\nOperations</strong>) are used by Android system (since Android 4.3) to\ncontrol application permissions. The user <em>can</em> control some\npermissions, but only the permissions that are considered dangerous (and\nGoogle thinks knowing your phone number isn’t a dangerous thing). So,\napp ops seems to be the one we need if we want to install apps like\nFacebook and it’s Messenger (the latter literary records everything if\nyou live outside the EU) and still want <em>some</em> privacy and/or\nsecurity. Although certain features of app ops were available in\nSettings and later in hidden settings in older version of Android, it’s\ncompletely hidden in newer versions of Android and is continued to be\nkept hidden. Now, any app with\n<strong>android.Manifest.permission.GET_APP_OPS_STATS</strong>\npermission can get the app ops information for other applications but\nthis permission is hidden from users and can only be enabled using ADB\nor root. Still, the app with this permission cannot grant or revoke\npermissions (actually mode of operation) for apps other than itself\n(with limited capacity, of course). To modify the ops of other app, the\napp needs\n<strong>android.Manifest.permission.UPDATE_APP_OPS_STATS</strong>\npermissions which isn’t accessible via <code>pm</code> command. So, you\ncannot grant it via root or ADB, the permission is only granted to the\nsystem apps. There are very few apps who support disabling permissions\nvia app ops. The best one to my knowledge is <a href=https://github.com/8enet/AppOpsX>AppOpsX</a>. The main (visible)\ndifference between my app (AppManager) and this app is that the latter\nalso provides you the ability to revoke internet permissions (by writing\nip tables). One crucial problem that I faced during the development of\nthe app ops API is the lack of documentation in English language.</section><section id=sec:introduction-to-app-ops class=level2 data-number=7.2><h2 data-number=7.2><span class=header-section-number>7.2</span> <a href=#toc:sec:introduction-to-app-ops>Introduction to App Ops</a><a href=#sec:introduction-to-app-ops class=anchor aria-hidden=true></a></h2><figure id=fig:appops><figure><object data=../images/appops.svg type=image/svg+xml></object></figure><figcaption>Figure 2: How app ops work</figcaption></figure><p>Figure <a href=#fig:appops>1</a> describes the process of changing\nand processing permission. <a href=#sec:appopsmanager>AppOpsManager</a> can be used to manage\npermissions in Settings app. <strong>AppOpsManager</strong> is also\nuseful in determining if a certain permission (or operation) is granted\nto the application. Most of the methods of\n<strong>AppOpsManager</strong> are accessible to the user app but unlike\na system app, it can only be used to check permissions for any app or\nfor the app itself and start or terminating certain operations.\nMoreover, not all operations are actually accessible from this Java\nclass. <strong>AppOpsManager</strong> holds all the necessary constants\nsuch as <a href=#subsec:op-constants><code>OP_*</code></a>,\n<code>OPSTR_*</code>, <a href=#subsec:mode-constants><code>MODE_*</code></a> which describes\noperation code, operation string and mode of operations respectively. It\nalso holds necessary data structures such as <a href=#subsec:package-ops>PackageOps</a> and <strong>OpEntry</strong>.\n<strong>PackageOps</strong> holds <strong>OpEntry</strong> for a\npackage, and <strong>OpEntry</strong>, as the name suggests, describes\neach operation.<p><code>AppOpService</code> is completely hidden from a user\napplication but accessible to the system applications. As it can be seen\nin Figure <a href=#fig:appops>1</a>, this is the class that does the\nactual management stuff. It contains data structures such as\n<strong>Ops</strong> to store basic package info and <strong>Op</strong>\nwhich is similar to <strong>OpEntry</strong> of\n<strong>AppOpsManager</strong>. It also has <strong>Shell</strong> which\nis actually the source code of the <a href=#sec:appops-cli><em>appops</em> command line tool</a>. It writes\nconfigurations to or read configurations from <a href=#sec:appops-xml><code>/data/system/appops.xml</code></a>. System\nservices calls <strong>AppOpsService</strong> to find out what an\napplication is allowed and what is not allowed to perform, and\n<strong>AppOpsService</strong> determines these permissions by parsing\n<code>/data/system/appops.xml</code>. If no custom values are present in\n<em>appops.xml</em>, it returns the default mode available in\n<strong>AppOpsManager</strong>.</section><section id=sec:appopsmanager class=level2 data-number=7.3><h2 data-number=7.3><span class=header-section-number>7.3</span> <a href=#toc:sec:appopsmanager>AppOpsManager</a><a href=#sec:appopsmanager class=anchor aria-hidden=true></a></h2><p><a href=https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/app/AppOpsManager.java>AppOpsManager</a>\nstands for application operations manager. It consists of various\nconstants and classes to modify app operations.<div class=seealso-inline><p><em>Voir aussi : <span><a href=https://developer.android.com/reference/android/app/AppOpsManager>AppOpsManager\ndocumentation</a></span></em></div><section id=subsec:op-constants class=level3 data-number=7.3.1><h3 data-number=7.3.1><span class=header-section-number>7.3.1</span>\n<a href=#toc:subsec:op-constants><code>OP_*</code> Constants</a><a href=#subsec:op-constants class=anchor aria-hidden=true></a></h3><p><code>OP_*</code> are the integer constants starting from\n<code>0</code>. <code>OP_NONE</code> implies that no operations are\nspecified whereas <code>_NUM_OP</code> denotes the number of operations\ndefined in <code>OP_*</code> prefix. While they denote each operation,\nthe operations are not necessarily unique. In fact, there are many\noperations that are actually a single operation denoted by multiple\n<code>OP_*</code> constant (possibly for future use). Vendors may define\ntheir own op based on their requirements. MIUI is one of the vendors who\nare known to do that.<div class=listing><div class=sourceCode id=cb11 data-frame=lines><pre class=\"sourceCode java\"><code class=\"sourceCode java\"><span id=cb11-1><a href=#cb11-1 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=dt>final</span> <span class=dt>int</span> OP_NONE <span class=op>=</span> <span class=op>-</span><span class=dv>1</span><span class=op>;</span></span>\n<span id=cb11-2><a href=#cb11-2 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=dt>final</span> <span class=dt>int</span> OP_COARSE_LOCATION <span class=op>=</span> <span class=dv>0</span><span class=op>;</span></span>\n<span id=cb11-3><a href=#cb11-3 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=dt>final</span> <span class=dt>int</span> OP_FINE_LOCATION <span class=op>=</span> <span class=dv>1</span><span class=op>;</span></span>\n<span id=cb11-4><a href=#cb11-4 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=dt>final</span> <span class=dt>int</span> OP_GPS <span class=op>=</span> <span class=dv>2</span><span class=op>;</span></span>\n<span id=cb11-5><a href=#cb11-5 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=dt>final</span> <span class=dt>int</span> OP_VIBRATE <span class=op>=</span> <span class=dv>3</span><span class=op>;</span></span>\n<span id=cb11-6><a href=#cb11-6 aria-hidden=true tabindex=-1></a><span class=kw>...</span></span>\n<span id=cb11-7><a href=#cb11-7 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=dt>final</span> <span class=dt>int</span> OP_READ_DEVICE_IDENTIFIERS <span class=op>=</span> <span class=dv>89</span><span class=op>;</span></span>\n<span id=cb11-8><a href=#cb11-8 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=dt>final</span> <span class=dt>int</span> OP_ACCESS_MEDIA_LOCATION <span class=op>=</span> <span class=dv>90</span><span class=op>;</span></span>\n<span id=cb11-9><a href=#cb11-9 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=dt>final</span> <span class=dt>int</span> OP_ACTIVATE_PLATFORM_VPN <span class=op>=</span> <span class=dv>91</span><span class=op>;</span></span>\n<span id=cb11-10><a href=#cb11-10 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=dt>final</span> <span class=dt>int</span> _NUM_OP <span class=op>=</span> <span class=dv>92</span><span class=op>;</span></span></code></pre></div></div><p>Whether an operation is unique is defined by\n<code>sOpToSwitch</code>. It maps each operation to another operation or\nto itself (if it’s a unique operation). For instance,\n<code>OP_FINE_LOCATION</code> and <code>OP_GPS</code> are mapped to\n<code>OP_COARSE_LOCATION</code>.<p>Each operation has a private name which are described by\n<code>sOpNames</code>. These names are usually the same names as the\nconstants without the <code>OP_</code> prefix. Some operations have\npublic names as well which are described by <code>sOpToString</code>.\nFor instance, <code>OP_COARSE_LOCATION</code> has the public name\n<strong>android:coarse_location</strong>.<p>As a gradual process of moving permissions to app ops, there are\nalready many permissions that are defined under some operations. These\npermissions are mapped in <code>sOpPerms</code>. For example, the\npermission\n<strong>android.Manifest.permission.ACCESS_COARSE_LOCATION</strong> is\nmapped to <code>OP_COARSE_LOCATION</code>. Some operations may not have\nany associated permissions which have <code>null</code> values.<p>As described in the previous section, operations that are configured\nfor an app are stored at <a href=#sec:appops-xml><code>/data/system/appops.xml</code></a>. If an\noperation is not configured, then whether system will allow that\noperation is determined from <code>sOpDefaultMode</code>. It lists the\n<em>default mode</em> for each operation.</section><section id=subsec:mode-constants class=level3 data-number=7.3.2><h3 data-number=7.3.2><span class=header-section-number>7.3.2</span>\n<a href=#toc:subsec:mode-constants><code>MODE_*</code> Constants</a><a href=#subsec:mode-constants class=anchor aria-hidden=true></a></h3><p><code>MODE_*</code> constants also integer constants starting from\n<code>0</code>. These constants are assigned to each operation\ndescribing whether an app is authorised to perform that operation. These\nmodes usually have associated names such as <strong>allow</strong> for\n<code>MODE_ALLOWED</code>, <strong>ignore</strong> for\n<code>MODE_IGNORED</code>, <strong>deny</strong> for\n<code>MODE_ERRORED</code> (a rather misnomer), <strong>default</strong>\nfor <code>MODE_DEFAULT</code> and <strong>foreground</strong> for\n<code>MODE_FOREGROUND</code>.<ol class=incremental><li><p><strong><code>MODE_ALLOWED</code>.</strong> The app is allowed to\nperform the given operation<li><p><strong><code>MODE_IGNORED</code>.</strong> The app is not\nallowed to perform the given operation, and any attempt to perform the\noperation should <em>silently fail</em>, i.e. it should not cause the\napp to crash<li><p><strong><code>MODE_ERRORED</code>.</strong> The app is not\nallowed to perform the given operation, and this attempt should cause it\nto have a fatal error, typically a\n<code>SecurityException</code><li><p><strong><code>MODE_DEFAULT</code>.</strong> The app should use\nits default security check, specified in\n<code>AppOpsManager</code><li><p><strong><code>MODE_FOREGROUND</code>.</strong> Special mode that\nmeans “allow only when app is in foreground.” This mode was added in\nAndroid 10<li><p><strong><code>MODE_ASK</code>.</strong> This is a custom mode\nused by MIUI whose uses are unknown.</ol></section><section id=subsec:package-ops class=level3 data-number=7.3.3><h3 data-number=7.3.3><span class=header-section-number>7.3.3</span>\n<a href=#toc:subsec:package-ops>PackageOps</a><a href=#subsec:package-ops class=anchor aria-hidden=true></a></h3><p><strong>AppOpsManager.PackageOps</strong> is a data structure to\nstore all the <strong>OpEntry</strong> for a package. In simple terms,\nit stores all the customised operations for a package.<div class=listing><div class=sourceCode id=cb12 data-frame=lines><pre class=\"sourceCode java\"><code class=\"sourceCode java\"><span id=cb12-1><a href=#cb12-1 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=kw>class</span> PackageOps <span class=kw>implements</span> Parcelable <span class=op>{</span></span>\n<span id=cb12-2><a href=#cb12-2 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=bu>String</span> mPackageName<span class=op>;</span></span>\n<span id=cb12-3><a href=#cb12-3 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=dt>int</span> mUid<span class=op>;</span></span>\n<span id=cb12-4><a href=#cb12-4 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=bu>List</span><span class=op>&lt;</span>OpEntry<span class=op>&gt;</span> mEntries<span class=op>;</span></span>\n<span id=cb12-5><a href=#cb12-5 aria-hidden=true tabindex=-1></a>    <span class=kw>...</span></span>\n<span id=cb12-6><a href=#cb12-6 aria-hidden=true tabindex=-1></a><span class=op>}</span></span></code></pre></div></div><p>As can be seen in Listing <a href=#lst:package-ops-class>2</a>, it\nstores all <strong>OpEntry</strong> for a package as well as the\ncorresponding package name and its kernel user ID.</section><section id=subsec:opentry class=level3 data-number=7.3.4><h3 data-number=7.3.4><span class=header-section-number>7.3.4</span>\n<a href=#toc:subsec:opentry>OpEntry</a><a href=#subsec:opentry class=anchor aria-hidden=true></a></h3><p><strong>AppOpsManager.OpEntry</strong> is a data structure that\nstores a single operation for any package.<div class=listing><div class=sourceCode id=cb13 data-frame=lines><pre class=\"sourceCode java\"><code class=\"sourceCode java\"><span id=cb13-1><a href=#cb13-1 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=dt>final</span> <span class=kw>class</span> OpEntry <span class=kw>implements</span> Parcelable <span class=op>{</span></span>\n<span id=cb13-2><a href=#cb13-2 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=dt>int</span> mOp<span class=op>;</span></span>\n<span id=cb13-3><a href=#cb13-3 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=dt>boolean</span> mRunning<span class=op>;</span></span>\n<span id=cb13-4><a href=#cb13-4 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=at>@Mode</span> <span class=dt>int</span> mMode<span class=op>;</span></span>\n<span id=cb13-5><a href=#cb13-5 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=at>@Nullable</span> LongSparseLongArray mAccessTimes<span class=op>;</span></span>\n<span id=cb13-6><a href=#cb13-6 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=at>@Nullable</span> LongSparseLongArray mRejectTimes<span class=op>;</span></span>\n<span id=cb13-7><a href=#cb13-7 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=at>@Nullable</span> LongSparseLongArray mDurations<span class=op>;</span></span>\n<span id=cb13-8><a href=#cb13-8 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=at>@Nullable</span> LongSparseLongArray mProxyUids<span class=op>;</span></span>\n<span id=cb13-9><a href=#cb13-9 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=at>@Nullable</span> LongSparseArray<span class=op>&lt;</span><span class=bu>String</span><span class=op>&gt;</span> mProxyPackageNames<span class=op>;</span></span>\n<span id=cb13-10><a href=#cb13-10 aria-hidden=true tabindex=-1></a>    <span class=kw>...</span></span>\n<span id=cb13-11><a href=#cb13-11 aria-hidden=true tabindex=-1></a><span class=op>}</span></span></code></pre></div></div><p>Here:<ul class=incremental><li><p><code>mOp</code>: Denotes one of the <a href=#subsec:op-constants><code>OP_*</code> constants</a><li><p><code>mRunning</code>: Whether the operation is in progress\n(i.e. the operation has started but not finished yet). Not all\noperations can be started or finished this way<li><p><code>mMOde</code>: One of the <a href=#subsec:mode-constants><code>MODE_*</code> constants</a><li><p><code>mAccessTimes</code>: Stores all the available access\ntimes<li><p><code>mRejectTimes</code>: Stores all the available reject\ntimes<li><p><code>mDurations</code>: All available access durations, checking\nthis with <code>mRunning</code> will tell you for how long the app is\nperforming a certain app operation<li><p><code>mProxyUids</code>: No documentation found<li><p><code>mProxyPackageNames:</code> No documentation found</ul></section><section id=subsec:usage class=level3 data-number=7.3.5><h3 data-number=7.3.5><span class=header-section-number>7.3.5</span>\n<a href=#toc:subsec:usage>Usage</a><a href=#subsec:usage class=anchor aria-hidden=true></a></h3><p>TODO</section></section><section id=sec:appopsservice class=level2 data-number=7.4><h2 data-number=7.4><span class=header-section-number>7.4</span> <a href=#toc:sec:appopsservice>AppOpsService</a><a href=#sec:appopsservice class=anchor aria-hidden=true></a></h2><p>TODO</section><section id=sec:appops-xml class=level2 data-number=7.5><h2 data-number=7.5><span class=header-section-number>7.5</span> <a href=#toc:sec:appops-xml>appops.xml</a><a href=#sec:appops-xml class=anchor aria-hidden=true></a></h2><p>Latest <code>appops.xml</code> has the following format: (This DTD is\nmade by me and by no means perfect, has compatibility issues.)<pre><code>&lt;!DOCTYPE app-ops [\n\n&lt;!ELEMENT app-ops (uid|pkg)*&gt;\n&lt;!ATTLIST app-ops v CDATA #IMPLIED&gt;\n\n&lt;!ELEMENT uid (op)*&gt;\n&lt;!ATTLIST uid n CDATA #REQUIRED&gt;\n\n&lt;!ELEMENT pkg (uid)*&gt;\n&lt;!ATTLIST pkg n CDATA #REQUIRED&gt;\n\n&lt;!ELEMENT uid (op)*&gt;\n&lt;!ATTLIST uid\nn CDATA #REQUIRED\np CDATA #IMPLIED&gt;\n\n&lt;!ELEMENT op (st)*&gt;\n&lt;!ATTLIST op\nn CDATA #REQUIRED\nm CDATA #REQUIRED&gt;\n\n&lt;!ELEMENT st EMPTY&gt;\n&lt;!ATTLIST st\nn CDATA #REQUIRED\nt CDATA #IMPLIED\nr CDATA #IMPLIED\nd CDATA #IMPLIED\npp CDATA #IMPLIED\npu CDATA #IMPLIED&gt;\n\n]&gt;</code></pre><p>The instruction below follows the exact order given above:<ul class=incremental><li><p><code>app-ops</code>: The root element. It can contain any number\nof <code>pkg</code> or package <code>uid</code><ul class=incremental><li><p><code>v</code>: (optional, integer) The version number (default:\n<code>NO_VERSION</code> or <code>-1</code>)</ul><li><p><code>pkg</code>: Stores package info. It can contain any number\nof <code>uid</code><ul class=incremental><li><p><code>n</code>: (required, string) Name of the package</ul><li><p>Package <code>uid</code>: Stores package or packages info<ul class=incremental><li><p><code>n</code>: (required, integer) The user ID</ul><li><p><code>uid</code>: The package user ID. It can contain any number\nof <code>op</code><ul class=incremental><li><p><code>n</code>: (required, integer) The user ID<li><p><code>p</code>: (optional, boolean) Is the app is a\nprivate/system app</ul><li><p><code>op</code>: The operation, can contain <code>st</code> or\nnothing at all<ul class=incremental><li><p><code>n</code>: (required, integer) The op name in integer,\ni.e. AppOpsManager.OP_*<li><p><code>m</code>: (required, integer) The op mode,\ni.e. AppOpsManager.MODE_*</ul><li><p><code>st</code>: State of operation: whether the operation is\naccessed, rejected or running (not available on old versions)<ul class=incremental><li><p><code>n</code>: (required, long) Key containing flags and\nuid<li><p><code>t</code>: (optional, long) Access time (default:\n<code>0</code>)<li><p><code>r</code>: (optional, long) Reject time (default:\n<code>0</code>)<li><p><code>d</code>: (optional, long) Access duration (default:\n<code>0</code>)<li><p><code>pp</code>: (optional, string) Proxy package name<li><p><code>pu</code>: (optional, integer) Proxy package uid</ul></ul><p>This definition can be found at <a href=https://android.googlesource.com/platform/frameworks/base/+/master/services/core/java/com/android/server/appop/AppOpsService.java>AppOpsService</a>.</section><section id=sec:appops-cli class=level2 data-number=7.6><h2 data-number=7.6><span class=header-section-number>7.6</span> <a href=#toc:sec:appops-cli>Command Line Interface</a><a href=#sec:appops-cli class=anchor aria-hidden=true></a></h2><p><code>appops</code> or <code>cmd appops</code> (on latest versions)\ncan be accessible via ADB or root. This is an easier method to get or\nupdate any operation for a package (provided the package name is known).\nThe help page of this command is self-explanatory:<pre><code>AppOps service (appops) commands:\nhelp\nPrint this help text.\nstart [--user &lt;USER_ID&gt;] &lt;PACKAGE | UID&gt; &lt;OP&gt;\nStarts a given operation for a particular application.\nstop [--user &lt;USER_ID&gt;] &lt;PACKAGE | UID&gt; &lt;OP&gt;\nStops a given operation for a particular application.\nset [--user &lt;USER_ID&gt;] &lt;[--uid] PACKAGE | UID&gt; &lt;OP&gt; &lt;MODE&gt;\nSet the mode for a particular application and operation.\nget [--user &lt;USER_ID&gt;] &lt;PACKAGE | UID&gt; [&lt;OP&gt;]\nReturn the mode for a particular application and optional operation.\nquery-op [--user &lt;USER_ID&gt;] &lt;OP&gt; [&lt;MODE&gt;]\nPrint all packages that currently have the given op in the given mode.\nreset [--user &lt;USER_ID&gt;] [&lt;PACKAGE&gt;]\nReset the given application or all applications to default modes.\nwrite-settings\nImmediately write pending changes to storage.\nread-settings\nRead the last written settings, replacing current state in RAM.\noptions:\n&lt;PACKAGE&gt; an Android package name or its UID if prefixed by --uid\n&lt;OP&gt;      an AppOps operation.\n&lt;MODE&gt;    one of allow, ignore, deny, or default\n&lt;USER_ID&gt; the user id under which the package is installed. If --user is not\nspecified, the current user is assumed.</code></pre></section></section><section id=footnotes class=\"footnotes footnotes-end-of-document\" role=doc-endnotes><hr><ol><li id=fn1><p>For distributing normal releases only<a href=#fnref1 class=footnote-back role=doc-backlink>↩︎</a><li id=fn2><p>GitHub pull requests will be merged manually using the\ncorresponding patches. As a result, GitHub may wrongfully mark them\nclosed instead of merged.<a href=#fnref2 class=footnote-back role=doc-backlink>↩︎</a><li id=fn3><p>You can also address me as “Muntashir Akon”<a href=#fnref3 class=footnote-back role=doc-backlink>↩︎</a></ol></section>"
  },
  {
    "path": "docs/raw/fr/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"intro$main$$translations-title\">Traductions</string>\n    <string name=\"intro$main$$contributing-title\">Contribuer</string>\n    <string name=\"intro$main$$donation-title\">Dons et Financement</string>\n    <string name=\"intro$main$$contact-title\">Contact</string>\n    <string name=\"intro$main$$official-sources-title\">Sources Officielles</string>\n    <string name=\"intro$main$$supported-versions-title\">Versions Supportées</string>\n    <string name=\"intro$main$$terminologies-title\">Terminologies</string>\n    <string name=\"intro$main$intro\">App Manager est un gestionnaire avancé de packets pour Android. Il offre un multitude de fonctionnalités, et par conséquent, requiert\n\\nun manuel utilisateur pour aider ses utilisateurs. Ce document fait office de manuel utilisateur pour App Manage, au sens qu\\'il s\\'efforce de décrire\n\\nchaque fonctionnalité qu\\'App Manager a à offrir. Ce document peut aussi être considéré comme directives officielles\n\\npour App Manager, et représente le comportement attendu de App Manager. Les traductions peuvent mésinterpréter ce document (qui est\n\\nécrite en anglais). C\\'est pourquoi tout utilisateur capable de le faire, devrait lire la version anglaise du document pour tirer le meilleur\n\\nde App Manager. Il pourrait y avoir d\\'autres ressources tierces ou non-officielles telles que des articles de blogs, vidéos, groupes de\n\\ndiscussion, etc. Bien que ces ressources puissent être utiles pour certains, elles pourraient ne pas être à jour avec la version actuelle de\n\\nApp Manager. S\\'il y a des differences entre App Manager et ce document, elles devraient être signalées sur\n\\n\\\\href{https://github.com/MuntashirAkon/AppManager/issues}{App Manager issue tracker}.</string>\n    <string name=\"intro$main$translations\">App Manager n\\'accepte pas des traductions directement via des requêtes pull/merge. Les traductions sont automatiquement merge via\n\\nWeblate. Pour rejoindre l\\'équipe de traduction, allez sur \\\\url{https://hosted.weblate.org/engage/app-manager/}.</string>\n    <string name=\"intro$main$buiding\">Des instructions de build sont disponibles dans le fichier BUILDING situé à la racine du code source.</string>\n    <string name=\"keywords$chapter\">\\\\newcommand{\\\\KeywordChapter}{Chapitre}</string>\n    <string name=\"keywords$see_also\">\\\\newcommand{\\\\KeywordSeeAlso}{Voir aussi :}</string>\n    <string name=\"keywords$end_of_keyword_in_alert\">\\\\newcommand{\\\\KeywordEndOfKeyWordInAlert}{ :}</string>\n    <string name=\"titlepage$user_manual\">{\\\\huge\\\\bfseries Manuel Utilisateur\\\\par}</string>\n    <string name=\"intro$main$$introduction-chapter-title\">Introduction</string>\n    <string name=\"intro$main$supported-versions\">Actuellement, les versions maintenues sont v2.6.0 (stable), v3.0.0 (versions alpha et debug). Les versions précédentes de App\n\\nManager pourraient contenir des vulnérabilités et ne devraient pas être utilisées.</string>\n    <string name=\"intro$main$source-code-links\">Tous sauf GitHub sont des liens miroirs. Les étiquettes devraient toujours être à jour, mais la branche master n\\'est pas garantie\n\\nd\\'être à jour. Si le but est de cloner la branche master, utilisez le lien GitHub plutôt que les autres.</string>\n    <string name=\"intro$main$contributing\">Il y a plusieurs possibilités pour un utilisateur de contribuer, comme poser des questions utiles, participer aux discussions, améliorer\n\\nla documentation et les traductions, ajouter des librairies ou des trackers non reconnus, examiner le code source ainsi que\n\\nsignaler des vulnérabilités de sécurité.</string>\n    <string name=\"intro$main$$bin-sources-title\">Sources de distribution de binaires</string>\n    <string name=\"intro$main$$source-code-links-title\">Liens vers code source</string>\n    <string name=\"intro$main$$buiding-title\">Instructions de build</string>\n    <string name=\"intro$main$$submit-patches-title\">Soumettre des patchs</string>\n</resources>"
  },
  {
    "path": "docs/raw/index.html",
    "content": "<!DOCTYPE html><!-- SPDX-License-Identifier: GPL-3.0-or-later OR CC-BY-SA-4.0 -->\n<html lang=\"en\">\n  <head>\n    <title>App Manager Docs</title>\n    <meta name=\"viewport\" content=\"width=device-width, initial-scale=1\">\n    <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\n    <meta charset=\"utf-8\" />\n    <meta name=\"Description\" content=\"User manual for App Manager\" />\n    <link rel=\"stylesheet\" href=\"css/custom.css\">\n    <style>\n        body {\n            max-width: 1080px;\n            margin: 0 auto;\n        }\n\n        #middle {\n            display: flex;\n            align-items: center;\n            justify-content: center;\n            min-height: 100vh;\n        }\n\n        #flex {\n            display: flex;\n            flex-direction: row;\n            flex-wrap: wrap;\n            justify-content: center;\n        }\n\n        #logo-holder {\n            flex: 1 0 0;\n            padding: 10px;\n            max-width: 200px;\n        }\n\n        #logo {\n            max-width: 100%;\n            min-width: 180px;\n            box-shadow: inset 0 0 1px 1px #212121, 0 0 5px 0 #212121;\n            border-radius: 50%;\n        }\n\n        #content {\n            flex: 2 0 0;\n            padding: 10px;\n            text-align: start;\n            line-height: normal;\n            word-break: keep-all;\n        }\n\n        #app {\n            font-size: 500%;\n            text-shadow: 0 0 2px #212121;\n            font-family: Helvetica Nueue, Helvetica, sans-serif;\n        }\n\n        #manager {\n            font-size: 500%;\n            font-weight: bold;\n            text-shadow: 0 0 2px #212121;\n            font-family: Helvetica Nueue, Helvetica, sans-serif;\n        }\n\n        a.link {\n            display: inline-block;\n        }\n\n        @media (any-pointer: coarse) {\n            a.link {\n                padding: 8px 8px;\n            }\n        }\n    </style>\n    <script>\n        // noinspection JSUnusedGlobalSymbols\n        function setLanguage(language) {\n            const date = new Date();\n            date.setTime(date.getTime() + (365 * 24 * 60 * 60 * 1000));\n            let expires = \"expires=\" + date.toUTCString();\n            document.cookie = \"lang=\" + language + \";\" + expires + \";path=/\";\n            loadLanguage(language)\n            return false\n        }\n\n        function getLanguage() {\n            const name = \"lang=\";\n            let cookies = decodeURIComponent(document.cookie).split(';');\n            for(let cookie of cookies) {\n                while (cookie.charAt(0) === ' ') {\n                    cookie = cookie.substring(1);\n                }\n                if (cookie.indexOf(name) === 0) {\n                    return cookie.substring(name.length, cookie.length);\n                }\n            }\n            return null;\n        }\n\n        function loadLanguage(lang) {\n            const protocol = document.location.protocol + '//';\n            const host = document.location.host;\n            let path = document.location.pathname;\n            const queries = document.location.search;\n            const hash = document.location.hash;\n            if (path.endsWith(\"index.html\")) {\n                path = path.replace(\"index.html\", \"\")\n            }\n            if (!path.endsWith(\"/\")) {\n                path += '/';\n            }\n            document.location.assign(protocol + host + path + lang + '/' + (queries ? queries : '') + (hash ? hash : ''));\n        }\n\n        const supportedLanguages = ['PLACEHOLDER_LANGUAGES_AS_ARRAY'];\n\n        // noinspection JSUnusedGlobalSymbols\n        function onLoadDocument() {\n            const lang = getLanguage();\n            if (lang != null) {\n                if (supportedLanguages.includes(lang)) {\n                    loadLanguage(lang);\n                    return;\n                }\n                // Try without region\n                if (lang.includes('-')) {\n                    loadLanguage(lang.split('-')[0]);\n                }\n            }\n        }\n    </script>\n  </head>\n  <body onLoad=\"onLoadDocument()\">\n    <div id=\"middle\">\n      <div id=\"flex\">\n        <div id=\"logo-holder\">\n          <img src=\"./images/icon.png\" id=\"logo\" alt=\"App Manager logo\" />\n        </div>\n        <div id=\"content\">\n          <div id=\"app\">App</div>\n          <div id=\"manager\">Manager</div>\n          <div id=\"combobox\">\n<span><!-- PLACEHOLDER_LANGUAGES_AS_HTML --></span>\n            <hr />\n            <small style=\"font-style: oblique;\">This site uses a cookie to remember your language preference in this browser. Disable JavaScript if you do not wish to use this feature.</small>\n          </div>\n        </div>\n      </div>\n    </div>\n  </body>\n</html>\n"
  },
  {
    "path": "docs/raw/ja/index.html",
    "content": "<!doctype html><html xmlns=http://www.w3.org/1999/xhtml lang=ja xml:lang=ja><meta charset=utf-8><meta name=generator content=\"pandoc\"><meta name=viewport content=\"width=device-width,initial-scale=1,user-scalable=yes\"><meta name=author content=\"Muntashir Al-Islam\"><title>App Manager</title><style>code{white-space:pre-wrap}span.smallcaps{font-variant:small-caps}div.columns{display:flex;gap:min(4vw,1.5em)}div.column{flex:auto;overflow-x:auto}div.hanging-indent{margin-left:1.5em;text-indent:-1.5em}ul.task-list[class]{list-style:none}ul.task-list li input[type=checkbox]{font-size:inherit;width:.8em;margin:0 .8em .2em -1.6em;vertical-align:middle}.display.math{display:block;text-align:center;margin:.5rem auto}html{-webkit-text-size-adjust:100%}pre>code.sourceCode{white-space:pre;position:relative}pre>code.sourceCode>span{display:inline-block;line-height:1.25}pre>code.sourceCode>span:empty{height:1.2em}.sourceCode{overflow:visible}code.sourceCode>span{color:inherit;text-decoration:inherit}div.sourceCode{margin:1em 0}pre.sourceCode{margin:0}@media screen{div.sourceCode{overflow:auto}}@media print{pre>code.sourceCode{white-space:pre-wrap}pre>code.sourceCode>span{text-indent:-5em;padding-left:5em}}pre.numberSource code{counter-reset:source-line 0}pre.numberSource code>span{position:relative;left:-4em;counter-increment:source-line}pre.numberSource code>span>a:first-child::before{content:counter(source-line);position:relative;left:-1em;text-align:right;vertical-align:baseline;border:none;display:inline-block;-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;padding:0 4px;width:4em}pre.numberSource{margin-left:3em;padding-left:4px}div.sourceCode{}@media screen{pre>code.sourceCode>span>a:first-child::before{text-decoration:underline}}code span.al{font-weight:700}code span.an{font-style:italic}code span.cf{font-weight:700}code span.co{font-style:italic}code span.cv{font-style:italic}code span.do{font-style:italic}code span.dt{text-decoration:underline}code span.er{font-weight:700}code span.in{font-style:italic}code span.kw{font-weight:700}code span.pp{font-weight:700}code span.wa{font-style:italic}</style><link rel=stylesheet href=../css/custom.css><header id=title-block-header><h1 class=title>App Manager</h1><p class=author>Muntashir Al-Islam</header><nav id=TOC role=doc-toc><ul class=incremental><li><span><span class=toc-section-number>1</span> <a href=#ch:introduction id=toc:ch:introduction>はじめに</a></span><ul class=incremental><li><span><span class=toc-section-number>1.1</span> <a href=#sec:terminologies id=toc:sec:terminologies>用語の定義</a></span><li><span><span class=toc-section-number>1.2</span> <a href=#sec:supported-versions id=toc:sec:supported-versions>対応バージョン</a></span><li><span><span class=toc-section-number>1.3</span> <a href=#sec:official-sources id=toc:sec:official-sources>公式ソース</a></span><ul class=incremental><li><span><span class=toc-section-number>1.3.1</span> <a href=#subsec:binary-distribution-sources id=toc:subsec:binary-distribution-sources>バイナリ配布ソース</a></span><li><span><span class=toc-section-number>1.3.2</span> <a href=#subsec:links-to-source-code id=toc:subsec:links-to-source-code>ソースコードへのリンク</a></span><li><span><span class=toc-section-number>1.3.3</span> <a href=#subsec:translations id=toc:subsec:translations>翻訳</a></span></ul><li><span><span class=toc-section-number>1.4</span> <a href=#sec:contributing id=toc:sec:contributing>貢献する</a></span><ul class=incremental><li><span><span class=toc-section-number>1.4.1</span> <a href=#subsec:build-instructions id=toc:subsec:build-instructions>ビルド手順</a></span><li><span><span class=toc-section-number>1.4.2</span> <a href=#subsec:submitting-patches id=toc:subsec:submitting-patches>パッチを提出する</a></span></ul><li><span><span class=toc-section-number>1.5</span> <a href=#sec:donation-&-funding id=toc:sec:donation-&-funding>寄付、出資</a></span><li><span><span class=toc-section-number>1.6</span> <a href=#sec:contact id=toc:sec:contact>連絡先</a></span></ul><li><span><span class=toc-section-number>2</span> <a href=#ch:pages id=toc:ch:pages>ページ</a></span><ul class=incremental><li><span><span class=toc-section-number>2.1</span> <a href=#sec:main-page id=toc:sec:main-page>メインページ</a></span><ul class=incremental><li><span><span class=toc-section-number>2.1.1</span> <a href=#subsec:batch-operations id=toc:subsec:batch-operations>バッチ処理</a></span><li><span><span class=toc-section-number>2.1.2</span> <a href=#subsec:main-colour-codes id=toc:subsec:main-colour-codes>カラーコード</a></span><li><span><span class=toc-section-number>2.1.3</span> <a href=#subsec:main-page-application-types id=toc:subsec:main-page-application-types>アプリケーションタイプ</a></span><li><span><span class=toc-section-number>2.1.4</span> <a href=#subsec:main-page-version-info id=toc:subsec:main-page-version-info>バージョン情報</a></span><li><span><span class=toc-section-number>2.1.5</span> <a href=#subsec:main-page-options-menu id=toc:subsec:main-page-options-menu>オプションメニュー</a></span></ul><li><span><span class=toc-section-number>2.2</span> <a href=#sec:app-details-page id=toc:sec:app-details-page>アプリ詳細画面</a></span><ul class=incremental><li><span><span class=toc-section-number>2.2.1</span> <a href=#subsec:app-details-colour-codes id=toc:subsec:app-details-colour-codes>カラーコード</a></span><li><span><span class=toc-section-number>2.2.2</span> <a href=#subsec:app-info-tab id=toc:subsec:app-info-tab>アプリ情報タブ</a></span><li><span><span class=toc-section-number>2.2.3</span> <a href=#subsec:component-tabs id=toc:subsec:component-tabs>コンポーネントタブ</a></span><li><span><span class=toc-section-number>2.2.4</span> <a href=#subsec:permission-tabs id=toc:subsec:permission-tabs>権限タブ</a></span><li><span><span class=toc-section-number>2.2.5</span> <a href=#subsec:signatures-tab id=toc:subsec:signatures-tab>署名情報タブ</a></span><li><span><span class=toc-section-number>2.2.6</span> <a href=#subsec:uses-features-tab id=toc:subsec:uses-features-tab>Uses\nFeatures tab</a></span><li><span><span class=toc-section-number>2.2.7</span> <a href=#subsec:configurations-tab id=toc:subsec:configurations-tab>Configurations tab</a></span><li><span><span class=toc-section-number>2.2.8</span> <a href=#subsec:shared-libs-tab id=toc:subsec:shared-libs-tab>共有ライブラリタブ</a></span></ul><li><span><span class=toc-section-number>2.3</span> <a href=#sec:1-click-ops-page id=toc:sec:1-click-ops-page>ワンタップ一括処理</a></span><ul class=incremental><li><span><span class=toc-section-number>2.3.1</span> <a href=#subsec:block-unblock-trackers id=toc:subsec:block-unblock-trackers>トラッカーのブロック/ブロック解除</a></span><li><span><span class=toc-section-number>2.3.2</span> <a href=#subsec:block-components-dots id=toc:subsec:block-components-dots>コンポーネントのブロック…</a></span><li><span><span class=toc-section-number>2.3.3</span> <a href=#subsec:set-mode-for-app-ops-dots id=toc:subsec:set-mode-for-app-ops-dots>AppOpsモードの設定…</a></span><li><span><span class=toc-section-number>2.3.4</span> <a href=#subsec:1-click-back-up id=toc:subsec:1-click-back-up>バックアップ</a></span><li><span><span class=toc-section-number>2.3.5</span> <a href=#subsec:1-click-restore id=toc:subsec:1-click-restore>復元</a></span><li><span><span class=toc-section-number>2.3.6</span> <a href=#subsec:trim-caches-in-all-apps id=toc:subsec:trim-caches-in-all-apps>Trim Caches in All\nApps</a></span></ul><li><span><span class=toc-section-number>2.4</span> <a href=#sec:profiles-page id=toc:sec:profiles-page>Profiles\nPage</a></span><ul class=incremental><li><span><span class=toc-section-number>2.4.1</span> <a href=#subsec:profiles-options-menu id=toc:subsec:profiles-options-menu>Options Menu</a></span></ul><li><span><span class=toc-section-number>2.5</span> <a href=#sec:profile-page id=toc:sec:profile-page>Profile\nPage</a></span><ul class=incremental><li><span><span class=toc-section-number>2.5.1</span> <a href=#subsec:profile-options-menu id=toc:subsec:profile-options-menu>Options Menu</a></span><li><span><span class=toc-section-number>2.5.2</span> <a href=#subsec:profile-apps-tab id=toc:subsec:profile-apps-tab>Apps\nTab</a></span><li><span><span class=toc-section-number>2.5.3</span> <a href=#subsec:profile-configurations-tab id=toc:subsec:profile-configurations-tab>Configurations\nTab</a></span></ul><li><span><span class=toc-section-number>2.6</span> <a href=#sec:settings-page id=toc:sec:settings-page>Settings\nPage</a></span><ul class=incremental><li><span><span class=toc-section-number>2.6.1</span> <a href=#subsec:language id=toc:subsec:language>Language</a></span><li><span><span class=toc-section-number>2.6.2</span> <a href=#subsec:appearance id=toc:subsec:appearance>Appearance</a></span><li><span><span class=toc-section-number>2.6.3</span> <a href=#subsec:privacy id=toc:subsec:privacy>Privacy</a></span><li><span><span class=toc-section-number>2.6.4</span> <a href=#subsec:mode-of-operation id=toc:subsec:mode-of-operation>Mode\nof Operation</a></span><li><span><span class=toc-section-number>2.6.5</span> <a href=#subsec:apk-signing id=toc:subsec:apk-signing>APK\nSigning</a></span><li><span><span class=toc-section-number>2.6.6</span> <a href=#subsec:installer id=toc:subsec:installer>Installer</a></span><li><span><span class=toc-section-number>2.6.7</span> <a href=#subsec:backup/restore id=toc:subsec:backup/restore>Back\nup/Restore</a></span><li><span><span class=toc-section-number>2.6.8</span> <a href=#subsec:rules id=toc:subsec:rules>Rules</a></span><li><span><span class=toc-section-number>2.6.9</span> <a href=#subsec:advanced id=toc:subsec:advanced>Advanced</a></span><li><span><span class=toc-section-number>2.6.10</span> <a href=#subsec:device-info id=toc:subsec:device-info>About the\ndevice</a></span></ul><li><span><span class=toc-section-number>2.7</span> <a href=#sec:scanner-page id=toc:sec:scanner-page>Scanner\nPage</a></span><li><span><span class=toc-section-number>2.8</span> <a href=#sec:interceptor-page id=toc:sec:interceptor-page>Interceptor\nPage</a></span><ul class=incremental><li><span><span class=toc-section-number>2.8.1</span> <a href=#subsec:intent-filters id=toc:subsec:intent-filters>Intent\nFilters</a></span><li><span><span class=toc-section-number>2.8.2</span> <a href=#subsec:matching-activities id=toc:subsec:matching-activities>Matching Activities</a></span><li><span><span class=toc-section-number>2.8.3</span> <a href=#subsec:interceptor-reset-to-default id=toc:subsec:interceptor-reset-to-default>Reset to\nDefault</a></span><li><span><span class=toc-section-number>2.8.4</span> <a href=#subsec:interceptor-send-edited-intent id=toc:subsec:interceptor-send-edited-intent>Send Edited\nIntent</a></span></ul><li><span><span class=toc-section-number>2.9</span> <a href=#sec:shared-preferences-editor-page id=toc:sec:shared-preferences-editor-page>Shared Preferences Editor\nPage</a></span></ul><li><span><span class=toc-section-number>3</span> <a href=#ch:guides id=toc:ch:guides>Guides</a></span><ul class=incremental><li><span><span class=toc-section-number>3.1</span> <a href=#sec:adb-over-tcp id=toc:sec:adb-over-tcp>ADB over\nTCP</a></span><ul class=incremental><li><span><span class=toc-section-number>3.1.1</span> <a href=#subsec:enable-developer-options id=toc:subsec:enable-developer-options>Enable developer\noptions</a></span><li><span><span class=toc-section-number>3.1.2</span> <a href=#subsec:enable-usb-debugging id=toc:subsec:enable-usb-debugging>Enable USB\ndebugging</a></span><li><span><span class=toc-section-number>3.1.3</span> <a href=#subsec:setup-adb-on-pc-or-mac id=toc:subsec:setup-adb-on-pc-or-mac>Setup ADB on PC or\nMac</a></span><li><span><span class=toc-section-number>3.1.4</span> <a href=#subsec:configure-adb-over-tcp id=toc:subsec:configure-adb-over-tcp>Configure ADB over\nTCP</a></span></ul><li><span><span class=toc-section-number>3.2</span> <a href=#sec:wireless-debugging id=toc:sec:wireless-debugging>Wireless\nDebugging</a></span><ul class=incremental><li><span><span class=toc-section-number>3.2.1</span> <a href=#subsec:enable-developer-options-and-usb-debugging id=toc:subsec:enable-developer-options-and-usb-debugging>Enable\ndeveloper options and USB Debugging</a></span><li><span><span class=toc-section-number>3.2.2</span> <a href=#subsec:enable-wireless-debugging id=toc:subsec:enable-wireless-debugging>Enable Wireless\nDebugging</a></span><li><span><span class=toc-section-number>3.2.3</span> <a href=#subsec:pair-adb-with-app-manager id=toc:subsec:pair-adb-with-app-manager>Pair ADB with App\nManager</a></span><li><span><span class=toc-section-number>3.2.4</span> <a href=#subsec:connect-app-manager-to-adb id=toc:subsec:connect-app-manager-to-adb>Connect App Manager to\nADB</a></span></ul><li><span><span class=toc-section-number>3.3</span> <a href=#sec:backup-restore id=toc:sec:backup-restore>Back\nup/Restore</a></span><ul class=incremental><li><span><span class=toc-section-number>3.3.1</span> <a href=#subsec:backup-location id=toc:subsec:backup-location>Location</a></span><li><span><span class=toc-section-number>3.3.2</span> <a href=#subsec:backup-restore-backup-options id=toc:subsec:backup-restore-backup-options>Backup\nOptions</a></span><li><span><span class=toc-section-number>3.3.3</span> <a href=#subsec:backup-restore-backup id=toc:subsec:backup-restore-backup>Backup</a></span><li><span><span class=toc-section-number>3.3.4</span> <a href=#subsec:backup-restore-restore id=toc:subsec:backup-restore-restore>Restore</a></span><li><span><span class=toc-section-number>3.3.5</span> <a href=#subsec:backup-restore-delete-backup id=toc:subsec:backup-restore-delete-backup>Delete\nBackup</a></span></ul><li><span><span class=toc-section-number>3.4</span> <a href=#sec:automating-tasks id=toc:sec:automating-tasks>Automating\nTasks</a></span><ul class=incremental><li><span><span class=toc-section-number>3.4.1</span> <a href=#subsec:generating-authorization-key id=toc:subsec:generating-authorization-key>Generating authorization\nkey</a></span><li><span><span class=toc-section-number>3.4.2</span> <a href=#subsec:at:general-configuration id=toc:subsec:at:general-configuration>Configuring\ntasks</a></span><li><span><span class=toc-section-number>3.4.3</span> <a href=#subsec:at:features id=toc:subsec:at:features>Features</a></span><li><span><span class=toc-section-number>3.4.4</span> <a href=#subsec:triggering-a-profile id=toc:subsec:triggering-a-profile>Triggering a\nprofile</a></span></ul><li><span><span class=toc-section-number>3.5</span> <a href=#sec:net-policy id=toc:sec:net-policy>Net\nPolicy</a></span></ul><li><span><span class=toc-section-number>4</span> <a href=#ch:faq id=toc:ch:faq>Frequently Asked Questions</a></span><ul class=incremental><li><span><span class=toc-section-number>4.1</span> <a href=#sec:faq:app-components id=toc:sec:faq:app-components>App\nComponents</a></span><ul class=incremental><li><span><span class=toc-section-number>4.1.1</span> <a href=#subsec:faq:what-are-app-components id=toc:subsec:faq:what-are-app-components>What are the application\ncomponents?</a></span><li><span><span class=toc-section-number>4.1.2</span> <a href=#subsec:faq:how-components-blocked id=toc:subsec:faq:how-components-blocked>How are the tracker and other\ncomponents blocked in App Manager? What are its\nlimitations?</a></span><li><span><span class=toc-section-number>4.1.3</span> <a href=#subsec:faq:components-blocked-by-others id=toc:subsec:faq:components-blocked-by-others>Does app components\nblocked by other tools retained in App Manager?</a></span><li><span><span class=toc-section-number>4.1.4</span> <a href=#subsec:faq:components-reblocked-in-am id=toc:subsec:faq:components-reblocked-in-am>What happens to the\ncomponents blocked by App Manager which were previously blocked by other\ntools?</a></span><li><span><span class=toc-section-number>4.1.5</span> <a href=#subsec:faq:what-is-instant-component-blocking id=toc:subsec:faq:what-is-instant-component-blocking>What is instant\ncomponent blocking?</a></span><li><span><span class=toc-section-number>4.1.6</span> <a href=#subsec:tracker-classes-versus-tracker-components id=toc:subsec:tracker-classes-versus-tracker-components>Tracker\nclasses versus tracker components</a></span></ul><li><span><span class=toc-section-number>4.2</span> <a href=#sec:faq:adb-over-tcp id=toc:sec:faq:adb-over-tcp>TCP経由のADB</a></span><ul class=incremental><li><span><span class=toc-section-number>4.2.1</span> <a href=#subsec:faq:enable-adb-on-every-restart id=toc:subsec:faq:enable-adb-on-every-restart>再起動するたびにTCP経由のADBを再度有効にしなければなりませんか？</a></span><li><span><span class=toc-section-number>4.2.2</span> <a href=#subsec:faq:usb-debugging id=toc:subsec:faq:usb-debugging>USBデバッグを有効にできません。どうすればよいですか？</a></span><li><span><span class=toc-section-number>4.2.3</span> <a href=#subsec:faq:block-components-using-adb id=toc:subsec:faq:block-components-using-adb>ADBモードでもトラッカーやその他のアプリコンポーネントをブロックすることができますか？</a></span><li><span><span class=toc-section-number>4.2.4</span> <a href=#subsec:faq:adb-features id=toc:subsec:faq:adb-features>ADBモードではどのような機能が利用できますか？</a></span></ul><li><span><span class=toc-section-number>4.3</span> <a href=#sec:faq:miscellanea id=toc:sec:faq:miscellanea>Miscellanea</a></span><ul class=incremental><li><span><span class=toc-section-number>4.3.1</span> <a href=#subsec:faq:no-root-no-harms id=toc:subsec:faq:no-root-no-harms>I don’t use root/ADB. Am I\ncompletely safe from any harms?</a></span><li><span><span class=toc-section-number>4.3.2</span> <a href=#subsec:faq:how-trackers-libs-updated id=toc:subsec:faq:how-trackers-libs-updated>How are the trackers and\nlibraries are updated?</a></span><li><span><span class=toc-section-number>4.3.3</span> <a href=#subsec:faq:apks-deleted-after-installed id=toc:subsec:faq:apks-deleted-after-installed>Are APKs deleted after\ninstalled?</a></span><li><span><span class=toc-section-number>4.3.4</span> <a href=#subsec:faq:shizuku-support id=toc:subsec:faq:shizuku-support>Any plans for\nShizuku?</a></span><li><span><span class=toc-section-number>4.3.5</span> <a href=#subsec:faq:what-are-bloatware id=toc:subsec:faq:what-are-bloatware>What are bloatware and how to\nremove them?</a></span></ul></ul><li><span><span class=toc-section-number>5</span> <a href=#ch:specifications id=toc:ch:specifications>Specifications</a></span><ul class=incremental><li><span><span class=toc-section-number>5.1</span> <a href=#sec:rules-specification id=toc:sec:rules-specification>Rules\nSpecification</a></span><ul class=incremental><li><span><span class=toc-section-number>5.1.1</span> <a href=#background id=toc:background>Background</a></span><li><span><span class=toc-section-number>5.1.2</span> <a href=#rules-file-format id=toc:rules-file-format>Rules File\nFormat</a></span></ul></ul><li><span><span class=toc-section-number>6</span> <a href=#ch:changelogs id=toc:ch:changelogs>Changelogs</a></span><ul class=incremental><li><span><span class=toc-section-number>6.1</span> <a href=#sec:v4.0.5-(445) id=toc:sec:v4.0.5-(445)>v4.0.5\n(445)</a></span><li><span><span class=toc-section-number>6.2</span> <a href=#sec:v4.0.4-(444) id=toc:sec:v4.0.4-(444)>v4.0.4\n(444)</a></span><li><span><span class=toc-section-number>6.3</span> <a href=#sec:v4.0.3-(443) id=toc:sec:v4.0.3-(443)>v4.0.3\n(443)</a></span><li><span><span class=toc-section-number>6.4</span> <a href=#sec:v4.0.2-(442) id=toc:sec:v4.0.2-(442)>v4.0.2\n(442)</a></span><li><span><span class=toc-section-number>6.5</span> <a href=#sec:v4.0.1-(441) id=toc:sec:v4.0.1-(441)>v4.0.1\n(441)</a></span><ul class=incremental><li><span><span class=toc-section-number>6.5.1</span> <a href=#overlay-management id=toc:overlay-management>Overlay\nmanagement</a></span><li><span><span class=toc-section-number>6.5.2</span> <a href=#unfreeze-option-in-activity-shortcuts id=toc:unfreeze-option-in-activity-shortcuts>Unfreeze option in\nactivity shortcuts</a></span><li><span><span class=toc-section-number>6.5.3</span> <a href=#market-like-url-support id=toc:market-like-url-support><code>market</code>-like URL\nsupport</a></span><li><span><span class=toc-section-number>6.5.4</span> <a href=#updated-color-codes id=toc:updated-color-codes>Updated color\ncodes</a></span><li><span><span class=toc-section-number>6.5.5</span> <a href=#others id=toc:others>Others</a></span></ul><li><span><span class=toc-section-number>6.6</span> <a href=#sec:v4.0.0-(440) id=toc:sec:v4.0.0-(440)>v4.0.0\n(440)</a></span><ul class=incremental><li><span><span class=toc-section-number>6.6.1</span> <a href=#new-logo id=toc:new-logo>New logo!</a></span><li><span><span class=toc-section-number>6.6.2</span> <a href=#android-14-and-15-support id=toc:android-14-and-15-support>Android 14 and 15\nsupport</a></span><li><span><span class=toc-section-number>6.6.3</span> <a href=#revamped-debloater id=toc:revamped-debloater>Revamped\ndebloater</a></span><li><span><span class=toc-section-number>6.6.4</span> <a href=#introducing-file-manager id=toc:introducing-file-manager>Introducing file\nmanager</a></span><li><span><span class=toc-section-number>6.6.5</span> <a href=#integrated-code-editor id=toc:integrated-code-editor>Integrated code editor</a></span><li><span><span class=toc-section-number>6.6.6</span> <a href=#history-of-operations id=toc:history-of-operations>History of\noperations</a></span><li><span><span class=toc-section-number>6.6.7</span> <a href=#per-app-freezing-and-more id=toc:per-app-freezing-and-more>Per-app freezing, and\nmore</a></span><li><span><span class=toc-section-number>6.6.8</span> <a href=#log-viewer-enhancements id=toc:log-viewer-enhancements>Log\nviewer enhancements</a></span><li><span><span class=toc-section-number>6.6.9</span> <a href=#launching-non-exported-activities id=toc:launching-non-exported-activities>Launching non-exported\nactivities</a></span><li><span><span class=toc-section-number>6.6.10</span> <a href=#new-tags-in-app-info-tab id=toc:new-tags-in-app-info-tab>New\ntags in App Info tab</a></span><li><span><span class=toc-section-number>6.6.11</span> <a href=#per-session-installer-options id=toc:per-session-installer-options>Per-session installer\noptions</a></span><li><span><span class=toc-section-number>6.6.12</span> <a href=#advanced-mode-of-operations-adb-enhancements id=toc:advanced-mode-of-operations-adb-enhancements>Advanced mode of\noperations, ADB enhancements, …</a></span><li><span><span class=toc-section-number>6.6.13</span> <a href=#data-usage-widget-and-more id=toc:data-usage-widget-and-more>Data usage widget, and\nmore</a></span><li><span><span class=toc-section-number>6.6.14</span> <a href=#others-1 id=toc:others-1>Others</a></span></ul><li><span><span class=toc-section-number>6.7</span> <a href=#sec:v3.1.0-(423) id=toc:sec:v3.1.0-(423)>v3.1.0\n(423)</a></span><ul class=incremental><li><span><span class=toc-section-number>6.7.1</span> <a href=#android-13-support id=toc:android-13-support>Android 13\nsupport</a></span><li><span><span class=toc-section-number>6.7.2</span> <a href=#introducing-freezeunfreeze id=toc:introducing-freezeunfreeze>Introducing\nfreeze/unfreeze</a></span><li><span><span class=toc-section-number>6.7.3</span> <a href=#export-app-list id=toc:export-app-list>Export app\nlist</a></span><li><span><span class=toc-section-number>6.7.4</span> <a href=#elliptic-curve-crypography-ecc id=toc:elliptic-curve-crypography-ecc>Elliptic Curve Crypography\n(ECC)</a></span><li><span><span class=toc-section-number>6.7.5</span> <a href=#new-languages id=toc:new-languages>New\nlanguages</a></span><li><span><span class=toc-section-number>6.7.6</span> <a href=#more-list-options id=toc:more-list-options>More list\noptions</a></span><li><span><span class=toc-section-number>6.7.7</span> <a href=#improved-handling-of-mode-of-operation id=toc:improved-handling-of-mode-of-operation>Improved handling of\nmode of operation</a></span><li><span><span class=toc-section-number>6.7.8</span> <a href=#handling-multiple-users id=toc:handling-multiple-users>Handling multiple users</a></span><li><span><span class=toc-section-number>6.7.9</span> <a href=#explorer-enhancements id=toc:explorer-enhancements>Explorer\nenhancements</a></span><li><span><span class=toc-section-number>6.7.10</span> <a href=#new-tag-wx id=toc:new-tag-wx>New tag: WX</a></span><li><span><span class=toc-section-number>6.7.11</span> <a href=#app-ops-management id=toc:app-ops-management>App ops\nmanagement</a></span><li><span><span class=toc-section-number>6.7.12</span> <a href=#batch-uninstallation id=toc:batch-uninstallation>Batch\nuninstallation</a></span><li><span><span class=toc-section-number>6.7.13</span> <a href=#running-apps id=toc:running-apps>Running apps</a></span><li><span><span class=toc-section-number>6.7.14</span> <a href=#interceptor id=toc:interceptor>Interceptor</a></span><li><span><span class=toc-section-number>6.7.15</span> <a href=#device-specific-changes id=toc:device-specific-changes>Device-specific changes</a></span><li><span><span class=toc-section-number>6.7.16</span> <a href=#others-2 id=toc:others-2>Others</a></span></ul><li><span><span class=toc-section-number>6.8</span> <a href=#sec:v3.0.0-(410) id=toc:sec:v3.0.0-(410)>v3.0.0\n(410)</a></span><ul class=incremental><li><span><span class=toc-section-number>6.8.1</span> <a href=#material-3-and-more id=toc:material-3-and-more>Material 3 and\nMore</a></span><li><span><span class=toc-section-number>6.8.2</span> <a href=#wireless-debugging id=toc:wireless-debugging>Wireless\nDebugging</a></span><li><span><span class=toc-section-number>6.8.3</span> <a href=#languages id=toc:languages>Languages</a></span><li><span><span class=toc-section-number>6.8.4</span> <a href=#introducing-app-explorer id=toc:introducing-app-explorer>Introducing App\nExplorer</a></span><li><span><span class=toc-section-number>6.8.5</span> <a href=#import-backups-from-other-applications id=toc:import-backups-from-other-applications>Import Backups from\nOther Applications</a></span><li><span><span class=toc-section-number>6.8.6</span> <a href=#virustotal id=toc:virustotal>VirusTotal</a></span><li><span><span class=toc-section-number>6.8.7</span> <a href=#trigger-profiles-from-the-automation-software id=toc:trigger-profiles-from-the-automation-software>Trigger Profiles\nfrom the Automation Software</a></span><li><span><span class=toc-section-number>6.8.8</span> <a href=#improved-application-installer id=toc:improved-application-installer>Improved Application\nInstaller</a></span><li><span><span class=toc-section-number>6.8.9</span> <a href=#component-blocking id=toc:component-blocking>Component\nBlocking</a></span><li><span><span class=toc-section-number>6.8.10</span> <a href=#advanced-searching id=toc:advanced-searching>Advanced\nSearching</a></span><li><span><span class=toc-section-number>6.8.11</span> <a href=#shared-libraries id=toc:shared-libraries>Shared\nLibraries</a></span><li><span><span class=toc-section-number>6.8.12</span> <a href=#make-the-best-use-of-interceptor id=toc:make-the-best-use-of-interceptor>Make the Best Use of\nInterceptor</a></span><li><span><span class=toc-section-number>6.8.13</span> <a href=#widget-screen-time id=toc:widget-screen-time>Widget: Screen\nTime</a></span><li><span><span class=toc-section-number>6.8.14</span> <a href=#widget-clear-cache id=toc:widget-clear-cache>Widget: Clear\nCache</a></span></ul><li><span><span class=toc-section-number>6.9</span> <a href=#sec:v2.6.0-(385) id=toc:sec:v2.6.0-(385)>v2.6.0\n(385)</a></span><ul class=incremental><li><span><span class=toc-section-number>6.9.1</span> <a href=#introducing-backups id=toc:introducing-backups>Introducing\nBackups</a></span><li><span><span class=toc-section-number>6.9.2</span> <a href=#introducing-log-viewer id=toc:introducing-log-viewer>Introducing Log Viewer</a></span><li><span><span class=toc-section-number>6.9.3</span> <a href=#lock-app-manager id=toc:lock-app-manager>Lock App\nManager</a></span><li><span><span class=toc-section-number>6.9.4</span> <a href=#extended-modes-for-app-ops id=toc:extended-modes-for-app-ops>Extended Modes for App\nOps</a></span><li><span><span class=toc-section-number>6.9.5</span> <a href=#new-batch-ops-add-to-profile id=toc:new-batch-ops-add-to-profile>New Batch Ops: Add to\nProfile</a></span><li><span><span class=toc-section-number>6.9.6</span> <a href=#app-info-improved id=toc:app-info-improved>App Info:\nImproved</a></span><li><span><span class=toc-section-number>6.9.7</span> <a href=#advanced-sort-and-filtering-options-in-the-main-page id=toc:advanced-sort-and-filtering-options-in-the-main-page>Advanced\nSort and Filtering Options in the Main Page</a></span><li><span><span class=toc-section-number>6.9.8</span> <a href=#about-this-device id=toc:about-this-device>About This\nDevice</a></span><li><span><span class=toc-section-number>6.9.9</span> <a href=#enabledisable-features id=toc:enabledisable-features>Enable/disable Features</a></span><li><span><span class=toc-section-number>6.9.10</span> <a href=#new-languages-1 id=toc:new-languages-1>New\nLanguages</a></span><li><span><span class=toc-section-number>6.9.11</span> <a href=#signing-the-apk-files id=toc:signing-the-apk-files>Signing the\nAPK Files</a></span><li><span><span class=toc-section-number>6.9.12</span> <a href=#new-extension-unapkm id=toc:new-extension-unapkm>New\nExtension: UnAPKM</a></span></ul><li><span><span class=toc-section-number>6.10</span> <a href=#sec:v2.5.20-(375) id=toc:sec:v2.5.20-(375)>v2.5.20\n(375)</a></span><ul class=incremental><li><span><span class=toc-section-number>6.10.1</span> <a href=#subsec:introducing-profiles id=toc:subsec:introducing-profiles>Introducing\nProfiles</a></span><li><span><span class=toc-section-number>6.10.2</span> <a href=#subsec:the-interceptor id=toc:subsec:the-interceptor>The\nInterceptor</a></span><li><span><span class=toc-section-number>6.10.3</span> <a href=#subsec:unapkm:-dedrm-the-apkm-files id=toc:subsec:unapkm:-dedrm-the-apkm-files>UnAPKM: DeDRM the APKM\nfiles</a></span><li><span><span class=toc-section-number>6.10.4</span> <a href=#subsec:multiple-user id=toc:subsec:multiple-user>Multiple\nuser</a></span><li><span><span class=toc-section-number>6.10.5</span> <a href=#vive-la-france id=toc:vive-la-france>Vive la\nFrance!</a></span><li><span><span class=toc-section-number>6.10.6</span> <a href=#report-crashes id=toc:report-crashes>Report\ncrashes</a></span><li><span><span class=toc-section-number>6.10.7</span> <a href=#android-11 id=toc:android-11>Android 11</a></span><li><span><span class=toc-section-number>6.10.8</span> <a href=#app-installer-improvements id=toc:app-installer-improvements>App Installer\nImprovements</a></span></ul><li><span><span class=toc-section-number>6.11</span> <a href=#v2.5.17-368 id=toc:v2.5.17-368>v2.5.17 (368)</a></span><ul class=incremental><li><span><span class=toc-section-number>6.11.1</span> <a href=#app-installer id=toc:app-installer>App\nInstaller</a></span><li><span><span class=toc-section-number>6.11.2</span> <a href=#scanner-replacement-for-exodus-page id=toc:scanner-replacement-for-exodus-page>Scanner: Replacement for\nExodus Page</a></span><li><span><span class=toc-section-number>6.11.3</span> <a href=#introducing-system-config id=toc:introducing-system-config>Introducing System\nConfig</a></span><li><span><span class=toc-section-number>6.11.4</span> <a href=#more-languages id=toc:more-languages>More\nLanguages</a></span><li><span><span class=toc-section-number>6.11.5</span> <a href=#app-info-tab id=toc:app-info-tab>App Info Tab</a></span><li><span><span class=toc-section-number>6.11.6</span> <a href=#navigation-improvements id=toc:navigation-improvements>Navigation Improvements</a></span><li><span><span class=toc-section-number>6.11.7</span> <a href=#running-apps-page id=toc:running-apps-page>Running Apps\nPage</a></span><li><span><span class=toc-section-number>6.11.8</span> <a href=#built-in-toybox id=toc:built-in-toybox>Built-in\nToybox</a></span><li><span><span class=toc-section-number>6.11.9</span> <a href=#component-blocker-improvements id=toc:component-blocker-improvements>Component Blocker\nImprovements</a></span><li><span><span class=toc-section-number>6.11.10</span> <a href=#improvements-in-the-app-details-page id=toc:improvements-in-the-app-details-page>Improvements in the App\nDetails Page</a></span><li><span><span class=toc-section-number>6.11.11</span> <a href=#app-manifest id=toc:app-manifest>App Manifest</a></span></ul><li><span><span class=toc-section-number>6.12</span> <a href=#v2.5.13-348 id=toc:v2.5.13-348>v2.5.13 (348)</a></span><ul class=incremental><li><span><span class=toc-section-number>6.12.1</span> <a href=#bundled-app-split-apk id=toc:bundled-app-split-apk>Bundled App\n(Split APK)</a></span><li><span><span class=toc-section-number>6.12.2</span> <a href=#direct-install-support id=toc:direct-install-support>Direct\nInstall Support</a></span><li><span><span class=toc-section-number>6.12.3</span> <a href=#remove-all-blocking-rules id=toc:remove-all-blocking-rules>Remove All Blocking\nRules</a></span><li><span><span class=toc-section-number>6.12.4</span> <a href=#app-ops-1 id=toc:app-ops-1>App Ops</a></span><li><span><span class=toc-section-number>6.12.5</span> <a href=#enhanced-adb-support id=toc:enhanced-adb-support>Enhanced ADB\nSupport</a></span><li><span><span class=toc-section-number>6.12.6</span> <a href=#filtering-in-main-page id=toc:filtering-in-main-page>Filtering\nin Main Page</a></span><li><span><span class=toc-section-number>6.12.7</span> <a href=#apk-backupsharing id=toc:apk-backupsharing>Apk\nBackup/Sharing</a></span><li><span><span class=toc-section-number>6.12.8</span> <a href=#batch-ops id=toc:batch-ops>Batch Ops</a></span><li><span><span class=toc-section-number>6.12.9</span> <a href=#translations id=toc:translations>Translations</a></span><li><span><span class=toc-section-number>6.12.10</span> <a href=#app-data-backup id=toc:app-data-backup>App Data\nBackup</a></span></ul></ul><li><span><span class=toc-section-number>7</span> <a href=#ch:app-ops id=toc:ch:app-ops>App Ops</a></span><ul class=incremental><li><span><span class=toc-section-number>7.1</span> <a href=#sec:app-ops-background id=toc:sec:app-ops-background>Background</a></span><li><span><span class=toc-section-number>7.2</span> <a href=#sec:introduction-to-app-ops id=toc:sec:introduction-to-app-ops>Introduction to App\nOps</a></span><li><span><span class=toc-section-number>7.3</span> <a href=#sec:appopsmanager id=toc:sec:appopsmanager>AppOpsManager</a></span><ul class=incremental><li><span><span class=toc-section-number>7.3.1</span> <a href=#subsec:op-constants id=toc:subsec:op-constants><code>OP_*</code> Constants</a></span><li><span><span class=toc-section-number>7.3.2</span> <a href=#subsec:mode-constants id=toc:subsec:mode-constants><code>MODE_*</code>\nConstants</a></span><li><span><span class=toc-section-number>7.3.3</span> <a href=#subsec:package-ops id=toc:subsec:package-ops>PackageOps</a></span><li><span><span class=toc-section-number>7.3.4</span> <a href=#subsec:opentry id=toc:subsec:opentry>OpEntry</a></span><li><span><span class=toc-section-number>7.3.5</span> <a href=#subsec:usage id=toc:subsec:usage>Usage</a></span></ul><li><span><span class=toc-section-number>7.4</span> <a href=#sec:appopsservice id=toc:sec:appopsservice>AppOpsService</a></span><li><span><span class=toc-section-number>7.5</span> <a href=#sec:appops-xml id=toc:sec:appops-xml>appops.xml</a></span><li><span><span class=toc-section-number>7.6</span> <a href=#sec:appops-cli id=toc:sec:appops-cli>Command Line\nInterface</a></span></ul></ul></nav><div class=titlingpage><div class=center><p><img src=../images/icon.png style=width:1in alt=image><p><strong><span class=smallcaps>App Manager</span></strong><p><strong>ユーザーマニュアル</strong><p><em>v4.0.5</em><p>27 7月 2025<p>Copyright © 2020–2025 Muntashir Al-Islam<blockquote><p>“賢明に、そして、ゆっくりと。速く走る者たちは、つまずきますからな”\n<span>— 修道士ロレンス, <em>ロメオとジュリエット</em></span></blockquote></div></div><section id=ch:introduction class=level1 data-number=1><h1 data-number=1><span class=header-section-number>1</span> <a href=#toc:ch:introduction>はじめに</a><a href=#ch:introduction class=anchor aria-hidden=true></a></h1><p>App Manager は、Android 用の高度なパッケージマネージャです。\n数え切れないほどの機能を備えているため、ユーザーを支援するためのユーザーマニュアルが必要です。\nこのドキュメントは、App Manager\nが提供するすべての機能を説明することを目的としており、App Manager\nのユーザーマニュアルとして機能します。 また、このドキュメントは、App\nManagerの「公式」ガイドラインと考えることもでき、App\nManagerに期待される動作を表しています。\n翻訳によって、このドキュメント（英語で書かれている）が誤解される可能性があります。\nしたがって、すべての有能なユーザは、App\nManagerを最大限に活用するために、英語版のドキュメントを読む必要があります。\nブログ記事、ビデオ、チャットグループなど、他の非公式またはサードパーティのリソースも同様に存在するかもしれません。\nこれらのリソースは多くの人にとって有用かもしれませんが、App\nManagerの最新バージョンに対応していない可能性があります。App\nManagerでこのドキュメントからの逸脱が検出された場合、App Managerの<a href=https://github.com/MuntashirAkon/AppManager/issues>イシュートラッカー</a>からご報告ください。<section id=sec:terminologies class=level2 data-number=1.1><h2 data-number=1.1><span class=header-section-number>1.1</span> <a href=#toc:sec:terminologies>用語の定義</a><a href=#sec:terminologies class=anchor aria-hidden=true></a></h2><ul class=incremental><li><p><strong>AM</strong> — App Managerの略称です。<li><p><strong>ブロック/ブロック解除</strong> —\nコンポーネントのブロックまたはブロック解除に使用されます。コンポーネントをどのようにブロックするかは、ユーザーの設定に依存します。<li><p><strong>IFW</strong> —\nインテントファイアウォールの略称です。<li><p><strong>Ops</strong> —\nOperations（操作)の略称です。例：AppOps、バッチ操作<li><p><strong>SSAID</strong> —\n<code>Settings.Secure.ANDROID_ID</code>の略称です。各アプリに割り当てられる端末識別子（Android\nOreo以降）で、\nアプリの署名証明書とパッケージ<code>android</code>に設定されたSSAIDの組み合わせから生成されます。\nそのため、ユーザーが端末のフォーマットを選択しない限り、\nアプリに対して同一であることが保証されます。ユーザーの追跡に広く利用されています。<li><p><strong>トラッカー</strong> — <a href=#sec:scanner-page>スキャナーページ</a>を除き、このドキュメント全体およびApp\nManagerでトラッカーコンポーネントのことを表します。トラッカーには、クラッシュレポーター、アナリティクス、プロファイリング、識別、広告、位置情報などのライブラリが含まれます。したがって、これらの機能は同等ではありません。また、トラッキングを促進するライブラリにはオープンソース、クローズドソースの区別や偏りはありません。</ul></section><section id=sec:supported-versions class=level2 data-number=1.2><h2 data-number=1.2><span class=header-section-number>1.2</span> <a href=#toc:sec:supported-versions>対応バージョン</a><a href=#sec:supported-versions class=anchor aria-hidden=true></a></h2><p>現在、サポートされているバージョンは、v2.6.0 (安定版)、 v3.0.0 (alpha\nと デバッグビルド)です。 App\nManagerの旧バージョンは、セキュリティ上の脆弱性が含まれている可能性があるため、使用しないでください。</section><section id=sec:official-sources class=level2 data-number=1.3><h2 data-number=1.3><span class=header-section-number>1.3</span> <a href=#toc:sec:official-sources>公式ソース</a><a href=#sec:official-sources class=anchor aria-hidden=true></a></h2><section id=subsec:binary-distribution-sources class=level3 data-number=1.3.1><h3 data-number=1.3.1><span class=header-section-number>1.3.1</span>\n<a href=#toc:subsec:binary-distribution-sources>バイナリ配布ソース</a><a href=#subsec:binary-distribution-sources class=anchor aria-hidden=true></a></h3><p>App\nManagerは、以下のソースを使用して配布されています。非公式なソースは、App\nManagerの修正されたバージョンを配布する可能性があり、\nそのようなバージョンを使用した結果について、一切の責任を負わないものとします。<ol class=incremental><li><p>Official F-Droid repository.<a href=#fn1 class=footnote-ref id=fnref1 role=doc-noteref><sup>1</sup></a><br><em>リンク:</em> <a href=https://f-droid.org/packages/io.github.muntashirakon.AppManager class=uri>https://f-droid.org/packages/io.github.muntashirakon.AppManager</a><li><p>GitHub repository.<br><em>安定版:</em> <a href=https://github.com/MuntashirAkon/AppManager/releases class=uri>https://github.com/MuntashirAkon/AppManager/releases</a><br><em>デバッグビルド:</em> <a href=https://github.com/MuntashirAkon/AppManager/actions class=uri>https://github.com/MuntashirAkon/AppManager/actions</a><li><p>Telegram.<br><em>安定版:</em> <a href=https://t.me/AppManagerChannel class=uri>https://t.me/AppManagerChannel</a><br><em>デバッグビルド:</em> <a href=https://t.me/AppManagerDebug class=uri>https://t.me/AppManagerDebug</a></ol></section><section id=subsec:links-to-source-code class=level3 data-number=1.3.2><h3 data-number=1.3.2><span class=header-section-number>1.3.2</span>\n<a href=#toc:subsec:links-to-source-code>ソースコードへのリンク</a><a href=#subsec:links-to-source-code class=anchor aria-hidden=true></a></h3><p>GitHub以外はそのミラーです。タグは常に最新であるべきですが、masterブランチが最新であることは保証されていません。\nmasterブランチのクローンを作成することが目的であれば、他のリンクではなくGitHubのリンクを使用してください。<ol class=incremental><li><p>GitHub: <a href=https://github.com/MuntashirAkon/AppManager class=uri>https://github.com/MuntashirAkon/AppManager</a><li><p>Codeberg: <a href=https://codeberg.org/muntashir/AppManager class=uri>https://codeberg.org/muntashir/AppManager</a><li><p>GitLab: <a href=https://gitlab.com/muntashir/AppManager class=uri>https://gitlab.com/muntashir/AppManager</a><li><p>Riseup: <a href=https://0xacab.org/muntashir/AppManager class=uri>https://0xacab.org/muntashir/AppManager</a><li><p>sourcehut: <a href=https://git.sr.ht/~muntashir/AppManager class=uri>https://git.sr.ht/~muntashir/AppManager</a></ol></section><section id=subsec:translations class=level3 data-number=1.3.3><h3 data-number=1.3.3><span class=header-section-number>1.3.3</span>\n<a href=#toc:subsec:translations>翻訳</a><a href=#subsec:translations class=anchor aria-hidden=true></a></h3><p>App\nManagerは、プル/マージリクエストによる翻訳を直接受け付けていません。翻訳は、Weblate\nを介して自動的に管理されます。 翻訳チームに参加するには、<a href=https://hosted.weblate.org/engage/app-manager/ class=uri>https://hosted.weblate.org/engage/app-manager/</a>をご覧ください。</section></section><section id=sec:contributing class=level2 data-number=1.4><h2 data-number=1.4><span class=header-section-number>1.4</span> <a href=#toc:sec:contributing>貢献する</a><a href=#sec:contributing class=anchor aria-hidden=true></a></h2><p>ユーザーは、役に立つ課題の作成、議論への参加、ドキュメントや翻訳の改善、未認識のライブラリやトラッカーの追加、\nソースコードのレビュー、セキュリティ脆弱性の報告など、さまざまな方法でAppManagerの開発に貢献することができます。<section id=subsec:build-instructions class=level3 data-number=1.4.1><h3 data-number=1.4.1><span class=header-section-number>1.4.1</span>\n<a href=#toc:subsec:build-instructions>ビルド手順</a><a href=#subsec:build-instructions class=anchor aria-hidden=true></a></h3><p>ビルド手順は、ソースコードのルートディレクトリにあるBUILDINGファイルに記載されています。</section><section id=subsec:submitting-patches class=level3 data-number=1.4.2><h3 data-number=1.4.2><span class=header-section-number>1.4.2</span>\n<a href=#toc:subsec:submitting-patches>パッチを提出する</a><a href=#subsec:submitting-patches class=anchor aria-hidden=true></a></h3><p>現在、GitHub以外のリポジトリはそのミラーであり、これらのサイトで提出されたプル/マージリクエストは受け付けていません。<a href=#fn2 class=footnote-ref id=fnref2 role=doc-noteref><sup>2</sup></a>\nその代わり、パッチ（<code>.patch</code>ファイル）を電子メールに添付して提出することができます。コミットに<em>サインオフを行う</em>必要があります。\n詳細は、ソースのルートディレクトリにあるCONTRIBUTINGファイルをご参照してください。<div class=\"amalert warning\"><p><strong><em>Notice.</em></strong><p>電子メールでパッチを提出する場合、将来的に会話全体が公にアクセス可能となる可能性があります。\nそのため、名前とメールアドレス以外の個人を特定できる情報（PII）は記載しないでください。</div></section></section><section id=sec:donation-&-funding class=level2 data-number=1.5><h2 data-number=1.5><span class=header-section-number>1.5</span> <a href=#toc:sec:donation-&-funding>寄付、出資</a><a href=#sec:donation-&-funding class=anchor aria-hidden=true></a></h2><p><em>App\nManagerを使用するのに、寄付や購入は必須ではありません。</em>App\nManagerは購入をサポートしていませんが、 Open Source\nCollectiveを通じてApp Managerの開発者に寄付を送ることができます。<p>Open Source\nCollectiveは、オープンソースプロジェクトの財政管理を支援するOpen\nCollectiveプラットフォーム内の財政ホストです。\n現在は銀行振り込み、PayPal、クレジットカード、デビットカード、暗号通貨による寄付に対応しています。<p><em>リンク:</em> <a href=https://opencollective.com/muntashir class=uri>https://opencollective.com/muntashir</a>.<p>寄付を送ることにより、あなたは寄付を利用して要求された機能を優先させないことに同意するものとします。\n機能リクエストは、賞金や寄付を必要とせず、開発者の好みに応じて優先順位がつけられます。<p><em>App\nManagerは、資金提供や助成金の申し出を受け付けています。</em>利害関係のある組織の代表者は、§<a href=#sec:contact data-reference-type=ref data-reference=sec:contact>1.6</a>に記載されている連絡先を使用して開発者に直接連絡することができます。<p>In addition, the maintainers and contributors of this project DO NOT\nconsent to the creation, sale, or promotion of tokens, cryptocurrencies,\nNFTs, or any other financial instruments that claim to represent this\nproject, its code, or its community. Any such attempts are unauthorized\nand not affiliated with this project in any way.</section><section id=sec:contact class=level2 data-number=1.6><h2 data-number=1.6><span class=header-section-number>1.6</span> <a href=#toc:sec:contact>連絡先</a><a href=#sec:contact class=anchor aria-hidden=true></a></h2><p>Muntashir Al-Islam<a href=#fn3 class=footnote-ref id=fnref3 role=doc-noteref><sup>3</sup></a><br>Eメール: <a href=mailto:muntashirakon@riseup.net>muntashirakon [at]\nriseup [dot] net</a><br>GPG鍵フィンガープリント:\n<code>7bad37c2981e41f8f6abea7f58f0b4f26c346fce</code><br>GitHub: <a href=https://github.com/MuntashirAkon class=uri>https://github.com/MuntashirAkon</a><br>Twitter: <a href=https://twitter.com/Muntashir class=uri>https://twitter.com/Muntashir</a></section></section><section id=ch:pages class=level1 data-number=2><h1 data-number=2><span class=header-section-number>2</span> <a href=#toc:ch:pages>ページ</a><a href=#ch:pages class=anchor aria-hidden=true></a></h1><section id=sec:main-page class=level2 data-number=2.1><h2 data-number=2.1><span class=header-section-number>2.1</span> <a href=#toc:sec:main-page>メインページ</a><a href=#sec:main-page class=anchor aria-hidden=true></a></h2><p>メインページには、インストールされているアプリケーション、アンインストールされているアプリケーション、バックアップされているアプリケーションがすべて表示されます。\nインストールされているアプリケーションの項目をタップすると、それぞれのアプリケーションの<a href=#sec:app-details-page>詳細ページ</a>が表示されます。\nアンインストールされたシステムアプリの場合は、アプリの再インストールを行うことができるプロンプトが表示されます。\n表示オプションの<a href=#par:main-page-sort>並び替え</a>\nを使用して、アプリの項目をさまざまな方法でソートし、終了時に保存することができます。\nまた、<a href=#par:main-page-filter>フィルタ</a>を使用して、項目を絞り込むことも可能です。\n検索バーを使ったフィルタリングも可能で、正規表現もサポートされています。<figure id=fig:main_page_entry_info_labeled><figure><object data=../images/main_page_entry_info_labeled.svg type=image/svg+xml></object></figure><figcaption>Figure 1:\nメインページのアプリケーションリスト内の表示項目</figcaption></figure><section id=subsec:batch-operations class=level3 data-number=2.1.1><h3 data-number=2.1.1><span class=header-section-number>2.1.1</span>\n<a href=#toc:subsec:batch-operations>バッチ処理</a><a href=#subsec:batch-operations class=anchor aria-hidden=true></a></h3><p>このページでは、一括操作や複数のアプリケーションに対する操作も可能です。\n複数選択モードは、アプリのアイコンをタップするか、リスト内の任意の項目を長押しすることで有効になります。\n一度アクティブにすると、アプリの詳細ページを開く代わりに、リストの項目をシングルクリックすることでそのアプリが選択されます。\nこのモードで、一括操作はページ下部の複数選択メニューに表示されます。次のような操作が含まれます:<ul class=incremental><li><p>選択したアプリケーションを<a href=#sec:profiles-page>プロファイル</a>に追加する<li><p>アプリケーションの<a href=#sec:backup-restore>バックアップ、リストア、削除</a><li><p>アプリケーションからのトラッカーをブロックする<li><p>アプリケーションのデータまたはキャッシュを消去する<li><p>アプリケーションの有効化/無効化/強制停止/アンインストール<li><p>App Managerに保存したブロッキングルールをエクスポート<li><p>アプリケーションのバックグラウンド動作を禁止する（Android\n7以降）<li><p>APKファイルを <code>AppManager/apks</code> に保存する<li><p><a href=#sec:net-policy>ネット接続ポリシー</a>を適用する</ul><div class=\"amalert tip\"><p><strong><em>Accessibility.</em></strong><p>複数選択モードを有効にした後、キーボードまたはリモコンの左右キーで複数選択メニューにナビゲートすることが可能です。</div></section><section id=subsec:main-colour-codes class=level3 data-number=2.1.2><h3 data-number=2.1.2><span class=header-section-number>2.1.2</span>\n<a href=#toc:subsec:main-colour-codes>カラーコード</a><a href=#subsec:main-colour-codes class=anchor aria-hidden=true></a></h3><ul class=incremental><li><p><span class=colorbox style=background-color:#fceed1><span style=color:#000>ライトグレーオレンジ(ライトモード)</span></span> /\n<span class=colorbox style=background-color:#091f36><span style=color:#fff>紺色 (ナイトモード)</span></span> –\nバッチ処理で選択したアプリ<li><p><span class=colorbox style=background-color:#ff8a80><span style=color:#000>薄い赤色(ライトモード)</span></span> / <span class=colorbox style=background-color:#4f1c14><span style=color:#fff>茶色(ナイトモード)</span></span> –\n無効化されたアプリ<li><p><span class=colorbox style=background-color:#ff0><span style=color:#000>黄色</span></span> – デバッグ可能なアプリ<li><p><span style=color:#e05915>オレンジ色の <em>日付</em></span> –\nアプリはシステムログにアクセス可能<li><p><span style=color:#e05915>オレンジ色の <em>UID</em></span> –\n複数のアプリでユーザーIDを共有している<li><p><span style=color:#e05915>オレンジ色の <em>SDK</em></span> –\nアプリケーションが平文（HTTPなど）のトラフィックを使用している可能性がある<li><p><span style=color:red>赤色の <em>パッケージ名</em></span> –\nデータの消去を許可していないアプリ<li><p><span style=color:red>赤色の <em>バックアップ</em></span> –\nAppManager に 1\nつ以上のバックアップが存在するアンインストールされたアプリケーション<li><p><span style=color:#e05915>オレンジ色の\n<em>バックアップ</em></span> –\n古いバックアップ,つまり、ベースバックアップにインストールされたアプリケーションの古いバージョンが含まれています<li><p><span style=color:#09868b>シアン色の\n<em>バックアップ</em></span> – 最新のバックアップ,\nつまり、ベースバックアップには、インストールされたアプリケーションと同じかそれ以上のバージョンが含まれています<li><p><span style=color:#09868b>シアン色の\n<em>パッケージ名</em></span> – 強制停止されたアプリ<li><p><span style=color:#09868b>シアン色の\n<em>バージョン</em></span> – 非アクティブなアプリ<li><p><span style=color:#f0f>マゼンダ</span> –\n永続的なアプリケーション、つまり、常に実行状態のままです</ul></section><section id=subsec:main-page-application-types class=level3 data-number=2.1.3><h3 data-number=2.1.3><span class=header-section-number>2.1.3</span>\n<a href=#toc:subsec:main-page-application-types>アプリケーションタイプ</a><a href=#subsec:main-page-application-types class=anchor aria-hidden=true></a></h3><p>アプリには、<strong>ユーザー</strong>アプリと<strong>システム</strong>アプリがあり、次の接尾辞が付きます:<ul class=incremental><li><p><code>X</code> –\nマルチアーキテクチャをサポートしています<li><p><code>0</code> – アプリにDEXファイルが存在しません<li><p><code>°</code> – 休止したアプリ<li><p><code>#</code> –\nアプリはシステムに大きなヒープ、すなわち大きな実行時メモリを割り当てるよう要求しています<li><p><code>?</code> –\nアプリは仮想マシンをセーフモードにするよう要求しています</ul></section><section id=subsec:main-page-version-info class=level3 data-number=2.1.4><h3 data-number=2.1.4><span class=header-section-number>2.1.4</span>\n<a href=#toc:subsec:main-page-version-info>バージョン情報</a><a href=#subsec:main-page-version-info class=anchor aria-hidden=true></a></h3><p>バージョン名の後には、次の接頭辞が付きます:<ul class=incremental><li><p><code>_</code> –\nハードウェアアクセラレーションを使用していません（アプリ内のアニメーションや透明度が壊れる）<li><p><code>~</code> – テストビルドのアプリ<li><p><code>debug</code> – デバッグ可能なアプリ</ul></section><section id=subsec:main-page-options-menu class=level3 data-number=2.1.5><h3 data-number=2.1.5><span class=header-section-number>2.1.5</span>\n<a href=#toc:subsec:main-page-options-menu>オプションメニュー</a><a href=#subsec:main-page-options-menu class=anchor aria-hidden=true></a></h3><p>オプションメニューには、表示されたアプリの並べ替えやフィルタリング、App\nManager内外のさまざまなページへの移動に使用できるオプションが\nいくつか用意されています。<section id=subsubsec:main-list-options class=level4 data-number=2.1.5.1><h4 data-number=2.1.5.1><span class=header-section-number>2.1.5.1</span> 表示オプション<a href=#subsubsec:main-list-options class=anchor aria-hidden=true></a></h4><p><strong>表示オプション</strong>には、メインページのリストの並び替えやフィルタリングのためのオプションが含まれています。<section id=並び替え class=level5 data-number=2.1.5.1.1><h5 data-number=2.1.5.1.1><span class=header-section-number>2.1.5.1.1</span> 並び替え<a href=#並び替え class=anchor aria-hidden=true></a></h5><div id=par:main-page-sort></div><p>メインページに表示されるアプリケーションは、次の方法で並び替えることができます:<ul class=incremental><li><p><strong>ユーザーアプリを優先</strong>\nユーザーアプリが上位に表示します<li><p><strong>アプリ名</strong>\nアプリ名で昇順にリストを並べ替えます。これはデフォルトの並べ替え設定です<li><p><strong>パッケージ名</strong>\nパッケージ名で昇順に並び替えます<li><p><strong>最後の更新</strong>\n最終更新日を基準に降順で並べ替えます<li><p><strong>共有UID</strong>\nカーネルユーザーIDを基準に降順で並べ替えます<li><p><strong>ターゲットSDK</strong>\nターゲットSDKに基づいてリストを昇順で並べ替えます<li><p><strong>署名</strong> 署名情報をもとに昇順に並べ替えます<li><p><strong>無効のものを優先</strong>\n無効にされたアプリを上位に表示します<li><p><strong>ブロック済みのものを優先</strong>\n各アプリケーションが持つブロックされたコンポーネントの数に基づいて、リストを降順に並べ替えます<li><p><strong>バックアップ済みを優先</strong>\nバックアップをとっているアプリケーションを上位に表示します<li><p><strong>トラッカー</strong>\n各アプリケーションが持つトラッカーコンポーネントの数に基づいて、リストを降順に並べ替えます<li><p><strong>最終アクション</strong> App\nManager内でアプリケーションに行われたアクションの最新日時に基づいて、リストを降順に並べ替えます。</ul><p>さらに、リストを反転させる<em>リバース</em>オプションもあります。ソートの設定にかかわらず、ランダムなソート結果を生成しないようにするために、アプリは最初にアルファベット順にソートされます。</section><section id=フィルタ class=level5 data-number=2.1.5.1.2><h5 data-number=2.1.5.1.2><span class=header-section-number>2.1.5.1.2</span> フィルタ<a href=#フィルタ class=anchor aria-hidden=true></a></h5><div id=par:main-page-filter></div><p>メインページに表示されるアプリケーションは、次の方法でフィルタリングすることができます:<ul class=incremental><li><p><strong>ユーザーアプリ</strong>\nユーザーアプリのみを表示します<li><p><strong>システムアプリ</strong>\nシステムアプリのみを表示します<li><p><strong>無効になっているアプリ</strong>\n無効になっているアプリを表示します<li><p><strong>ルールを適用済みのアプリ</strong>\n1つ以上のブロッキングルールがあるアプリを表示します<li><p><strong>アクティビティが存在するアプリ</strong>\n1つ以上のアクティビティを持つアプリを表示します<li><p><strong>バックアップ済みのアプリ</strong>\nバックアップが1つ以上あるアプリを表示します<li><p><strong>起動中のアプリ</strong>\n現在実行されているアプリを表示します<li><p><strong>分割データを含むアプリ</strong>\n1つ以上の分割APKファイルを持つアプリを表示します<li><p><strong>インストール済みのアプリ</strong>\nインストールされているアプリのみを表示します<li><p><strong>未インストールのアプリ</strong>\nインストールされていないアプリのみを表示します<li><p><strong>バックアップされたいないアプリ</strong>バックアップが存在しないアプリを表示します</ul><p>並べ替えとは異なり、複数のフィルタリングを同時に適用することが可能です。たとえば、「<em>ユーザーアプリ</em>」と「<em>無効のアプリ</em>」の両方を選択して無効になっているユーザーアプリを一覧表示することができます。この機能は、特定の操作を安全に実行するためにユーザーアプリのフィルタリングが必要な<a href=#subsec:batch-operations>バッチ処理</a>に特に役立ちます。</section><section id=プロファイル名 class=level5 data-number=2.1.5.1.3><h5 data-number=2.1.5.1.3><span class=header-section-number>2.1.5.1.3</span> プロファイル名<a href=#プロファイル名 class=anchor aria-hidden=true></a></h5><p>また、<a href=#sec:profiles-page>プロファイル</a>に存在するアプリケーションのみを表示することも可能です。\nこれは、<a href=#sec:profiles-page>プロファイルページ</a>では行えない特定の操作（プロファイル内のすべてのアプリケーションのアンインストールなど）\nをプロファイルに対して行う場合に便利です。</section></section><section id=手順 class=level4 data-number=2.1.5.2><h4 data-number=2.1.5.2><span class=header-section-number>2.1.5.2</span> 手順<a href=#手順 class=anchor aria-hidden=true></a></h4><p><strong>ヘルプ</strong>をタップすると、オフライン版のApp\nManagerユーザーマニュアルが開きます。\n対応する機能スプリット<code>feat_docs</code>がインストールされていない場合や、\nマニュアルを読み込むためのWebViewがシステムに存在しない場合、オンライン版が開かれることもあります。</section><section id=subsubsec:main:1-click-ops class=level4 data-number=2.1.5.3><h4 data-number=2.1.5.3><span class=header-section-number>2.1.5.3</span> ワンタップ一括処理<a href=#subsubsec:main:1-click-ops class=anchor aria-hidden=true></a></h4><p><strong>ワンタップ一括処理</strong>\nでは様々な操作をワンタップで行うことができます。 <a href=#sec:1-click-ops-page>対応するページ</a>を新しいアクティビティで開きます。</section><section id=アプリの使用状況 class=level4 data-number=2.1.5.4><h4 data-number=2.1.5.4><span class=header-section-number>2.1.5.4</span> アプリの使用状況<a href=#アプリの使用状況 class=anchor aria-hidden=true></a></h4><p><em>画面の使用時間</em>、<em>データ使用量</em>（モバイルとWi-Fiの両方）、<em>アプリを開いた回数</em>などのアプリ使用統計は、\nメニューの<strong>アプリ使用状況</strong>オプションをクリックすることでアクセス可能です。\nただし、これには<em>使用状況へのアクセス権限</em>が必要です。 <a href=#subsec:enable/disable-features>設定</a>で使用状況アクセス機能を無効にしている場合、このメニュー項目は表示されません。</section><section id=subsubsec:main:running-apps class=level4 data-number=2.1.5.5><h4 data-number=2.1.5.5><span class=header-section-number>2.1.5.5</span> 実行中のアプリ<a href=#subsubsec:main:running-apps class=anchor aria-hidden=true></a></h4><p>このメニューでは、実行中のアプリケーションまたはプロセスの一覧を表示する新しいページを開きます。\nまた、現在のメモリとキャッシュ（利用可能な場合）の使用量も表示されます。\nルートまたはADBがApp\nManagerで利用できない場合、Androidの最近のバージョンでのみ表示されます。\n実行中のアプリケーションまたはプロセスは、結果ページ内で強制停止またはキルすることもできます。\n<a href=#subsubsec:log-viewer>ログビューア</a>でプロセスID（PID）ごとのログを確認することもできます。\nまた、アイコンをタップするか、項目を長押しすることで、バッチ処理を行うことができます。各項目をタップすると、より詳細な情報が表示されるダイアログが開きます。</section><section id=プロファイル class=level4 data-number=2.1.5.6><h4 data-number=2.1.5.6><span class=header-section-number>2.1.5.6</span> プロファイル<a href=#プロファイル class=anchor aria-hidden=true></a></h4><p>このメニュー項目は、<a href=#sec:profiles-page>プロファイルページ</a>を開きます。プロファイルは、定期的に実行するタスクを設定するための方法です。\nまた、ショートカットで呼び出すこともできます。</section><section id=apk-updater class=level4 data-number=2.1.5.7><h4 data-number=2.1.5.7><span class=header-section-number>2.1.5.7</span> APK Updater<a href=#apk-updater class=anchor aria-hidden=true></a></h4><p><a href=https://github.com/rumboalla/apkupdater>APK\nUpdater</a>というアプリがシステムにインストールされている場合、\nこのメニュー項目から直接開くことができます。アプリがシステムにインストールされていない場合、このオプションは表示されません。</section><section id=termux class=level4 data-number=2.1.5.8><h4 data-number=2.1.5.8><span class=header-section-number>2.1.5.8</span> Termux<a href=#termux class=anchor aria-hidden=true></a></h4><p><a href=https://github.com/termux/termux-app>Termux</a>アプリがシステムにインストールされている場合、\nこのメニュー項目から実行中のセッション(または新しいセッション)を直接開くことができます。\nアプリがシステムにインストールされていない場合、このオプションは表示されません。</section><section id=debloater class=level4 data-number=2.1.5.9><h4 data-number=2.1.5.9><span class=header-section-number>2.1.5.9</span> Debloater<a href=#debloater class=anchor aria-hidden=true></a></h4><p>This menu item opens the debloater page that lists all the bloatware\navailable in the device and in App Manager. It also suggests alternative\napplications based on the criteria set by the <a href=https://github.com/MuntashirAkon/android-debloat-list>Android\nDebloat List</a> project.</section><section id=subsubsec:main:labs class=level4 data-number=2.1.5.10><h4 data-number=2.1.5.10><span class=header-section-number>2.1.5.10</span> Labs<a href=#subsubsec:main:labs class=anchor aria-hidden=true></a></h4><p>This menu item opens the labs page that lists all the additional\nfeatures. They include Log Viewer, System Config, Terminal, File Manager\n(as Files), UI Tracker, Interceptor, and Code Editor pages.</section><section id=設定 class=level4 data-number=2.1.5.11><h4 data-number=2.1.5.11><span class=header-section-number>2.1.5.11</span> 設定<a href=#設定 class=anchor aria-hidden=true></a></h4><p>アプリ内の<a href=#sec:settings-page>設定画面</a>を表示するメニューです。</section></section></section><section id=sec:app-details-page class=level2 data-number=2.2><h2 data-number=2.2><span class=header-section-number>2.2</span> <a href=#toc:sec:app-details-page>アプリ詳細画面</a><a href=#sec:app-details-page class=anchor aria-hidden=true></a></h2><p><strong>アプリ詳細</strong>ページは、11個のタブで構成されています。\nマニフェストのすべての属性、<a href=#ch:app-ops>AppOps</a>、署名情報、ライブラリなど、\nアプリが持ちうるほぼすべての情報が記述されています。<section id=subsec:app-details-colour-codes class=level3 data-number=2.2.1><h3 data-number=2.2.1><span class=header-section-number>2.2.1</span>\n<a href=#toc:subsec:app-details-colour-codes>カラーコード</a><a href=#subsec:app-details-colour-codes class=anchor aria-hidden=true></a></h3><p>このページで使用している背景色とその意味の一覧です:<ul class=incremental><li><p><span class=colorbox style=background-color:red><span style=color:#000>赤 (ライト)</span></span> / <span class=colorbox style=background-color:#790d0d><span style=color:#fff>紅赤\n(ナイト)</span></span> – Dangerousフラグを持つAppOpsや権限、またはApp\nManager内でブロックされたコンポーネントを表します。<li><p><span class=colorbox style=background-color:#ff8a80><span style=color:#000>うすだいだい (ライト)</span></span> / <span class=colorbox style=background-color:#4f1c14><span style=color:#fff>茶色\n(ナイト)</span></span> – App\nManagerの外部で無効化されているコンポーネントを表します。<div class=\"amalert tip\"><p><strong><em>Note.</em></strong><p>無効とマークされたコンポーネントは、必ずしもユーザーによって無効化されたことを意味するものではありません。\nシステムによって無効にされているか、マニフェストで無効とマークされている可能性もあります。\n無効なアプリケーションのコンポーネントは、システム (および App Manager)\nによっても無効とみなされます。</div><li><p><span class=colorbox style=background-color:#ff8017><span style=color:#000>オレンジ (ライト)</span></span> / <span class=colorbox style=background-color:#ff801780><span style=color:#fff>うすいオレンジ (night)</span></span> –\nトラッカーコンポーネントを表します。<li><p><span class=colorbox style=background-color:#ea80fc><span style=color:#000>Soft magenta (day)</span></span> / <span class=colorbox style=background-color:#431c5d><span style=color:#fff>very dark violet (night)</span></span> –\n実行中のサービスを表します。</ul></section><section id=subsec:app-info-tab class=level3 data-number=2.2.2><h3 data-number=2.2.2><span class=header-section-number>2.2.2</span>\n<a href=#toc:subsec:app-info-tab>アプリ情報タブ</a><a href=#subsec:app-info-tab class=anchor aria-hidden=true></a></h3><p><strong>アプリ情報</strong>タブには、アプリケーションに関する一般的な情報が含まれています。\nまた、このタブ内で実行可能な多くのアクションが表示されます。<section id=subsubsec:app-info-general-information class=level4 data-number=2.2.2.1><h4 data-number=2.2.2.1><span class=header-section-number>2.2.2.1</span> 基本情報<a href=#subsubsec:app-info-general-information class=anchor aria-hidden=true></a></h4><p>以下のリストは、アプリ情報タブに記載されている順番と同じです。<ul class=incremental><li><p><strong>アプリ名</strong>\nアプリのアイコンです。アプリにアイコンがない場合は、システムデフォルトのアイコンが表示されます。<li><p><strong>アプリ名</strong> アプリの名称です。<li><p><strong>バージョン</strong>\nアプリケーションのバージョンは、2つの部分に分かれています。最初の部分は<em>バージョン名</em>と呼ばれ、この部分のフォーマットは様々ですが、多くの場合ドットで区切られた複数の整数から構成されています。2つ目の部分は<em>バージョンコード</em>と呼ばれ、バージョン名の横の括弧内に記載されています。バージョンコードは整数で、通常はアプリのバージョンを区別するために使用されます。（バージョン名は機械では読めないことが多いため）一般に、新しいバージョンのアプリは、古いバージョンのアプリよりもバージョンコードが高くなります。たとえば、あるアプリのバージョンコードが<code>123</code>と<code>125</code>の場合、後者のバージョンコードの方が高いので、後者は前者よりも更新されていると言えます。プラットフォーム（モバイル、タブ、デスクトップなど）に依存するアプリケーションの場合、これらのバージョン名は、プラットフォームごとに接頭辞を使用しているため、誤解を招く可能性があります。<li><p><strong>タグ</strong>\nタグには、アプリの基本的で簡潔な、有用な情報が含まれています。例えば、<em>トラッカー情報</em>（トラッカーコンポーネントの数など）、<em>アプリの種類</em>（ユーザーアプリかシステムアプリか、アプリがシステムアプリの更新版かMagiskを使ってシステムレスでインストールされたか）、<em>実行中</em>（アプリのサービスがバックグラウンドで実行されているか）、<em>分割APK情報</em>（例.\nsplit APK\ninfo（分割数）、<em>debuggable</em>（アプリはデバッグバージョン）、<em>test\nonly</em>（アプリはテスト専用アプリ）、<em>ラージヒープ</em>（アプリは大きなヒープサイズを要求）、<em>停止</em>（アプリは強制停止）、<em>無効</em>（アプリは無効）、<em>キーストア</em>（アプリはAndroid\nKeyStoreにアイテムがある）、<em>no\ncode</em>（アプリにはコードが関連付けられていない）、<a href=#sec:terminologies><em>SSAID</em></a>、<em>netpolicy</em>（バックグラウンドデータ使用などネットワークポリシー）、<em>バッテリー最適化</em>が表示されます。<em>test\nonly</em>と<em>debuggable</em>を含めることの重要性は、これらのプロパティを持つアプリが追加のタスクを実行できること、またはこれらのアプリが個人情報を保存する場合、セキュリティ上の問題を引き起こす可能性のあるルートなしで実行できることにあります。<em>ラージヒープ</em>は、アプリが必要に応じてより多くのメモリ（RAM）を割り当てられることを意味します。ほとんどの場合、これは有害ではないかもしれませんが、大きなヒープを要求する不審なアプリは慎重に考慮する必要があります。<li><p><strong>アクションパネル</strong>\nアプリに関する様々なアクションを含むアクションパネルです。ここで利用できるアクションの一覧は、<a href=#subsubsec:horizontal-action-panel data-reference-type=ref data-reference=subsubsec:horizontal-action-panel>2.2.2.3</a>節を参照してください。<li><p><strong>パスとディレクトリ</strong>\n<em>アプリディレクトリ</em>（APK\nファイルが格納される場所）、<em>データディレクトリ</em>（内部、デバイス保護、外部）、<em>分割\nAPK ディレクトリ</em>（分割名と共に）、<em>ネイティブ JNI\nライブラリ</em>（存在する場合）を含むアプリケーションパスに関するさまざまな情報が含まれています。JNI\nライブラリは、通常 C/C++\nで記述されたネイティブコードを呼び出すために使用されます。ネイティブライブラリを使用すると、アプリの実行速度が向上したり、ほとんどのゲームのようにJava以外の言語で書かれたサードパーティライブラリをアプリが使用できるようになります。これらのディレクトリは、各項目の右側にある起動アイコンをクリックして、お気に入りのファイルマネージャ（サポートしており、必要なパーミッションがある場合）を使用して開くこともできます。<li><p><strong>最終起動時からのデータ使用量</strong>\n説明不要のオプションです。しかし、いくつかの問題のために、結果はしばしば誤解を招き、単に間違っている可能性があることに注意してください。この部分は、新しいデバイスで<em>使用状況</em>へのアクセス許可が与えられていない場合、隠されたままになります。<li><p><strong>ストレージとキャッシュ</strong>\nアプリ（APKファイル）、データ、キャッシュのサイズに関する情報を表示します。古い端末では、外部データ、キャッシュ、メディア、OBBフォルダのサイズも表示されます。この部分は、新しいデバイスで\n<em>使用状況</em>へのアクセス許可が与えられていない場合、隠されたままになります。<li><p><strong>詳細情報</strong> 次のような情報を表示します。<ul class=incremental><li><p><strong>SDK</strong> Android\nSDKに関連する情報を表示します。値は2つ（古い端末では1つ）あります。<em>最大</em>はターゲットSDK、<em>最小</em>は最小SDKを表します（後者はそれ以上古い端末では利用できません）。現在プラットフォームがサポートしている最大のSDKを持つアプリを使用するのが好ましいです。SDKは、<strong>APIレベル</strong>とも呼ばれます。<div class=seealso-inline><p><em>こちらもご覧ください: <span><a href=https://ja.wikipedia.org/wiki/Android%E3%81%AE%E3%83%90%E3%83%BC%E3%82%B8%E3%83%A7%E3%83%B3%E5%B1%A5%E6%AD%B4>Androidのバージョン履歴</a></span></em></div><li><p><strong>フラグ</strong> The application flags used at the time of\nbuilding the app. For a complete list of flags and what they do, visit\nthe <a href=https://developer.android.com/reference/android/content/pm/ApplicationInfo#flags>official\ndocumentation</a>.\nアプリのビルド時に使用するアプリケーションフラグです。フラグの完全なリストとその役割については、<a href=https://developer.android.com/reference/android/content/pm/ApplicationInfo#flags>公式ドキュメント</a>を参照してください。<li><p><strong>インストール日時</strong>\nアプリが最初にインストールされた日時です。<li><p><strong>アップデート日時</strong>\nアプリが最後に更新された日時です。アプリが更新されていない場合は、<em>インストール日時</em>と同じになります。<li><p><strong>インストール日時</strong>\nこのアプリをインストールしたアプリです。すべてのアプリが、インストーラアプリを登録するためにパッケージマネージャに使用する情報を提供するわけではありません。そのため、この値を鵜呑みにするべきではありません。<li><p><strong>ユーザーID</strong>\nAndroidシステムがアプリに設定した固有のユーザーIDです。共有アプリケーションの場合、同じ<em>共有ユーザーID</em>を持つ複数のアプリケーションに同じユーザーIDが割り当てられます。<li><p><strong>共有UID</strong>\n一緒に共有するアプリケーションに適用されます。IDとありますが、実際は文字列の値です。共有するアプリケーションは、同じ<a href=#subsec:signatures-tab>署名</a>を持つ必要があります。<li><p><strong>メインアクティビティ</strong> アプリ起動時の<a href=#subsubsec:activities>アクティビティ</a>です。アプリにアクティビティがあり、そのいずれかがランチャーから開くことができる場合にのみ表示されます。また、右側には起動ボタンがあり、このアクティビティを起動するために使用することができます。</ul></ul></section><section id=subsubsec:tags class=level4 data-number=2.2.2.2><h4 data-number=2.2.2.2><span class=header-section-number>2.2.2.2</span> Tags<a href=#subsubsec:tags class=anchor aria-hidden=true></a></h4><ul class=incremental><li><p><strong>Tracker info.</strong> Number of tracker components in\nthe application (e.g., <em>5 trackers</em>) The colour of the tag\nappears orange if the trackers are unblocked and dark cyan if they are\nblocked in App Manager. Clicking on the tag opens a dialog containing\nthe list of tracker components which can also be blocked or unblocked\nprovided App Manager has sufficient privileges.<li><p><strong>Application type.</strong> User application or system\napplication. For a system application, it displays whether the\napplication is an updated version of the system application or the\napplication is installed systemless-ly via Magisk.<li><p><strong>Split APK info.</strong> Number of splits in the APK\nexcluding the base APK (e.g., <em>5 splits</em>). Clicking on the tag\nopens a dialog containing a few additional information, such as name,\ntype, and size.<li><p><strong>Debuggable.</strong> The application can be debugged over\nADB. Debuggable applications can enjoy certain functions unavailable to\na regular application. The data of the application might be accessible\nvia ADB (e.g. using <code>run-as</code> command) without any additional\npermissions.<li><p><strong>Test only.</strong> The application is a test-only\napplication. Test-only applications can enjoy certain functions\nunavailable to a regular application. The data of the application might\nbe accessible via ADB (e.g. using <code>run-as</code> command) without\nany additional permissions.<li><p><strong>No code.</strong> The application does not have any code\nassociated with it i.e., DEX files aren’t present. In some system\napplications, the actual code might be located in another\nplace.<li><p><strong>Large heap.</strong> The application has requested large\nheap size i.e., more space in memory (RAM) is requested for dynamic\nallocation. It is still up to the operating system to decide whether to\nallocate large space for the application. App Manager, for example,\nrequests large heap size because it needs to load an entire APK into\nmemory while scanning an APK.<li><p><strong>Open links.</strong> The application may open certain\nlinks from any applications. If the application can open any links by\ndefault, the color of the tag would be red, dark cyan if otherwise.\nClicking on the tag opens a dialog with the supported hosts or domains\nlisted. In Android 12 onwards, it displays an option to enable or\ndisable opening links by default provided App Manager has sufficient\npermissions. Otherwise, it displays an option to open the system\nsettings page for the application.<li><p><strong>Running.</strong> One or more services of the application\nis currently running in the background. Clicking on the tag opens a\ndialog containing the list of running services. Clicking on any services\nopens the log viewer with default filter set to the UID associated with\nthe service (which can be different from the UID of the application if\nit is running in a separate or isolated process) provided the log viewer\nfeature is enabled. There’s also an option to force-stop the\napplication.<li><p><strong>Stopped.</strong> The application is force stopped. This\nmay not prevent it from running automatically later.<li><p><strong>Disabled.</strong> Denotes that the application is\ndisabled (hidden from the launcher).<li><p><strong>Suspended.</strong> Denotes that the application is\nsuspended (grayed out in the launcher).<li><p><strong>Hidden.</strong> Denotes that the application is hidden\n(hidden from the launcher).<li><p><strong>MagiskHide.</strong> MagiskHide is enabled for the\napplication. Clicking on the tag opens a dialog containing the list of\nprocess names within the application that can be added to or removed\nfrom the MagiskHide list.<li><p><strong>MagiskDenyList.</strong> The application is present in\nMagisk DenyList. Clicking on the tag opens a dialog containing the list\nof process names within the application that can be added to or removed\nfrom Magisk DenyList.<li><p><strong>WX.</strong> The application violates the “W^X policy”\nand is capable of writing and executing in the same directory or in the\nsame portion of memory. This allows the execution of arbitrary\nexecutables either by the modification of executables embedded within\nthe application or by downloading them from the Internet.<br><div class=seealso-inline><p><em>こちらもご覧ください: <span><a href=https://en.wikipedia.org/wiki/W%5EX>W^X in\nWikipedia</a></span></em></div><li><p><strong>Bloatware.</strong> The application may be a known\nbloatware. Clicking on the tag opens a dialog containing detailed\ninformation in addition to suggestions (if available).<li><p><strong>KeyStore.</strong> The application has items in the\nAndroid KeyStore. Clicking on the tag opens a dialog containing all the\nKeyStore files that belong to the application.<li><p><strong>Backup.</strong> The application was backed up using App\nManager at least once. Clicking on the tag opens a dialog containing all\nthe available backups along with metadata.<li><p><strong>No battery optimisation.</strong> Battery optimisation is\ndisabled for the application. It is possible to re-enable battery\noptimisation by clicking on the tag.<li><p><strong>Sensors disabled.</strong> Sensors are disabled for the\napplication. Sensors are disabled for most applications by\ndefault.<li><p><a href=#sec:net-policy><strong>Net policy.</strong></a>\nNetwork policy (e.g., background data usage) is configured for the\napplication. Clicking on the tag displays a dialog containing the\nsupported policies for the platform along with the options to configure\nthem.<li><p><a href=#sec:terminologies><strong>SSAID.</strong></a> Clicking\non the tag opens a dialog containing the current SSAID assigned to the\napplication. It is also possible to reset/regenerate the SSAID if\nneeded.<li><p><strong>SAF.</strong> Denotes that the application has been\ngranted to access one or more storage locations or files i.e. URIs via\nStorage Access Framework (SAF). Clicking on the tag opens a dialog\ncontaining the list of granted URIs.<li><p><strong>Play App Signing.</strong> Indicates that the application\nmight be signed by Google.<li><p><strong>Xposed.</strong> Indicates that the application may be an\nXposed module. Clicking on the tag displays a dialog with additional\ninformation.<li><p><strong>Static Shared Library.</strong> Denotes that the\napplication serves as a static shared library for one or more\napplications. Clicking on the tag opens a dialog containing a list of\ninstalled versions of the library along with an option to uninstall\nthem.<div class=\"amalert tip\"><p><strong><em>Notice.</em></strong><p>The trichrome library (supplied by Google Chrome, Vanadium or similar\nprojects) is currently the only known static shared library on\nAndroid.</div></ul></section><section id=subsubsec:horizontal-action-panel class=level4 data-number=2.2.2.3><h4 data-number=2.2.2.3><span class=header-section-number>2.2.2.3</span> 横長アクションパネル<a href=#subsubsec:horizontal-action-panel class=anchor aria-hidden=true></a></h4><p>前項のアクションパネルは、次のようなアプリに関連するさまざまなアクションで構成されています。<ul class=incremental><li><p><strong>起動</strong> ランチャー<a href=#subsubsec:activities>アクティビティ</a>を持つアプリケーションは、このボタンから起動することができます。<li><p><strong>無効化</strong>\nアプリを無効化します。アプリがすでに無効になっている場合や、Rootアクセスや<a href=#sec:adb-over-tcp>ADB</a>を持っていないユーザーには、このボタンは表示されません。アプリを無効にすると、そのアプリはランチャーアプリに表示されなくなります。また、そのアプリのショートカットも削除されます。ユーザーアプリを無効にした場合、App\nManagerまたはそれに対応する他のツールからのみ有効にすることができます。Androidの設定には、無効にしたユーザーアプリを有効にするオプションはありません。<li><p><strong>アンインストール</strong>\nアプリをアンインストールします。<li><p><strong>有効化</strong>\nアプリを有効化します。アプリがすでに有効化されている場合や、RootアクセスやADBを持っていないユーザーには、このボタンは表示されません。<li><p><strong>強制終了</strong> アプリを強制停止します。\nアプリを強制停止すると、明示的にアプリを開いてからでないと、そのアプリはバックグラウンドで実行できなくなります。しかし、これは必ずしも正しいとは限りません。<li><p><strong>データを消去</strong>\nアプリのデータを消去します。これには、アカウント（アプリによって設定されている場合）、キャッシュなど、内部および多くの場合外部のディレクトリに保存されているすべての情報が含まれます。例えば、App\nManagerからデータを消去すると、アプリ内に保存されているすべてのルールが削除されます（ただし、ブロックは削除されません）。そのため、ルールのバックアップを常に取っておく必要があります。このボタンは、RootアクセスまたはADBを持っていないユーザーには表示されません。<li><p><strong>キャッシュを消去</strong>\nアプリのキャッシュのみをクリアします。アプリのキャッシュをクリアする方法は、Android自体にはありません。そのため、アプリの内部ストレージからキャッシュをクリアするには、Root権限が必要です。<li><p><strong>インストール</strong>\nサードパーティのアプリで開いたAPKをインストールします。このボタンは、インストールされていない外部APKの場合のみ表示されます。<li><p><strong>最新情報</strong>\nインストールされているAPKよりもバージョンコードの高いAPKに対して表示されるボタンです。このボタンをクリックすると、バージョン間の差分がダイアログで表示されます。表示される情報は、<em>バージョン</em>、<em>トラッカー</em>、<em>パーミッション</em>、<em>コンポーネント</em>、<em>署名情報</em>（チェックサムの変更）、<em>機能</em>、<em>共有ライブラリ</em>、<em>SDK</em>などです。<li><p><strong>アップデート</strong>\nインストールされているアプリよりバージョンコードが高いアプリに対して表示されます。<li><p><strong>再インストール</strong>\nインストールされているアプリと同じバージョンコードを持つアプリに対して表示されます。<li><p><strong>ダウングレード</strong>\nインストールされているアプリよりバージョンコードが低いアプリに対して表示されます。<li><p><strong>マニフェスト</strong>\nこのボタンをクリックすると、アプリのマニフェストファイルが別ページで表示されます。マニフェストファイルは、対応するトグルボタン\n(右上)\nを使用してラップまたはアンラップすることができ、保存ボタンを使用して共有ストレージに保存することができます。<li><p><strong>スキャナー</strong>\nこのボタンをクリックすると、アプリのトラッカーとライブラリの情報が表示されます。まず、アプリをスキャンして、クラスのリストを抽出し、クラス一覧と複数のシグネチャをマッチングさせます。その後、スキャン結果が表示されます。<br><div class=seealso-inline><p><em>こちらもご覧ください: <span><a href=#sec:scanner-page>スキャナーページ</a></span></em></div><li><p><strong>共有設定</strong>\nこのボタンをクリックすると、アプリで使用されている共有環境設定の一覧が表示されます。リスト内の設定項目をクリックすると、<a href=#sec:shared-preferences-editor-page>共有設定エディター</a>が表示されます。このオプションは、Rootユーザーのみに表示されます。<li><p><strong>データベース</strong>\nこのボタンをクリックすると、アプリが使用しているデータベースの一覧が表示されます。これはもっと改良が必要で、将来的にはデータベース・エディターが追加されるかもしれません。このオプションは、Rootユーザーのみに表示されます。<li><p><strong>F-Droid</strong>\n任意の<em>F-Droid</em>クライアントでアプリのページを開きます。<li><p><strong>ストア</strong> <em>Aurora\nStore</em>でアプリのページを開きます。このオプションは、<em>Aurora\nStore</em>がインストールされている場合のみ表示されます。</ul></section><section id=subsubsec:app-info-options-menu class=level4 data-number=2.2.2.4><h4 data-number=2.2.2.4><span class=header-section-number>2.2.2.4</span> オプションメニュー<a href=#subsubsec:app-info-options-menu class=anchor aria-hidden=true></a></h4><p>ページの右上にあるのが、オプションメニューです。そこにあるオプションとその説明は以下の通りです:<ul class=incremental><li><p><strong>共有</strong>\n共有ボタンでAPKファイルを共有したり、<em>APKSファイル</em>（アプリが複数分割されている場合）を<a href=https://github.com/Aefyr/SAI>SAI</a>にインポートすることができます。任意のファイルマネージャーから共有し、ストレージにファイルを保存することができます。<li><p><strong>更新</strong> アプリ情報タブの内容を更新します。<li><p><strong>設定画面で開く</strong>\nAndroid設定画面でアプリの詳細画面を開きます。<li><p><strong>バックアップ/復元</strong>\nバックアップ・復元を行うダイアログを開きます。<li><p><strong>ブロッキングルールをエクスポート</strong> App\nManagerでこのアプリに対して設定されたルールをエクスポートします。<li><p><strong>Termuxで開く</strong>\nTermuxでアプリを開きます。これは実際には <code>su - user_id</code>\nを実行します。ここで <code>user_id</code>\nはアプリのカーネルユーザーID（<a href=#subsubsec:app-info-general-information>基本情報セクション</a>で説明されています）を表します。このオプションはRootユーザーにのみ表示されます。サードパーティアプリケーションからコマンドを実行するように\nTermux を設定する方法については §<a href=#subsubsec:config-termux data-reference-type=ref data-reference=subsubsec:config-termux>2.2.2.5</a>\nを参照してください。<li><p><strong>Termuxで実行</strong>\nTermuxで<code>run-as package_name</code>を使用してアプリを開きます。これはデバッグ可能アプリにのみ適用され、Root及びADBの両方で動作します。サードパーティアプリケーションからコマンドを実行するように\nTermux を設定する方法については §<a href=#subsubsec:config-termux data-reference-type=ref data-reference=subsubsec:config-termux>2.2.2.5</a>\nを参照してください。<li><p><strong>アイコンを抽出</strong>\nアプリのアイコンを抽出して任意の場所に保存します。</ul></section><section id=subsubsec:config-termux class=level4 data-number=2.2.2.5><h4 data-number=2.2.2.5><span class=header-section-number>2.2.2.5</span> Termuxを構成<a href=#subsubsec:config-termux class=anchor aria-hidden=true></a></h4><p>デフォルトでは、Termuxはサードパーティアプリケーションからのコマンドの実行が許可されていません。\nこのオプションを有効にするには、<code>~/.termux/termux.properties</code>\nに <code>allow-external-apps=true</code> を追加し、 Termux v0.96\n以降を実行している必要があります。<div class=\"amalert tip\"><p><strong><em>Info.</em></strong><p>このオプションを有効にしても、Termuxのセキュリティは低下しません。\nサードパーティアプリは、他の権限と同様に、Termuxで任意のコマンドを実行できるようにユーザーに要求する必要があります。</div></section></section><section id=subsec:component-tabs class=level3 data-number=2.2.3><h3 data-number=2.2.3><span class=header-section-number>2.2.3</span>\n<a href=#toc:subsec:component-tabs>コンポーネントタブ</a><a href=#subsec:component-tabs class=anchor aria-hidden=true></a></h3><p><strong>アクティビティ</strong>、<strong>サービス</strong>、<strong>レシーバ</strong>（<em>ブロードキャストレシーバ</em>）、<strong>プロバイダ</strong>（<em>コンテンツプロバイダ</em>）を合わせてアプリケーションコンポーネントと呼びます。\nそれらは多くの点で同様の機能を共有しているからです。例えば、それらはすべて<em>名前</em>と<em>ラベル</em>を持っています。\nコンポーネントは、あらゆるアプリケーションの構成要素であり、そのほとんどはアプリケーションマニフェストで宣言されなければなりません。\nアプリケーションマニフェストは、アプリケーション固有のメタデータが格納されるファイルです。\nAndroidシステムは、メタデータを読み取ることで、アプリケーションで何を行うかを学習します。\nこれらのタブで使用される色については、§<a href=#subsec:app-details-colour-codes data-reference-type=ref data-reference=subsec:app-details-colour-codes>2.2.1</a>で説明しています。\nまた、オーバーフローメニューのソートオプションを使用して、ブロックされたコンポーネントやトラッカーコンポーネントをリストの上位に表示するよう、\nコンポーネントのリストを<strong>並び替え</strong>る機能があります。<section id=subsubsec:activities class=level4 data-number=2.2.3.1><h4 data-number=2.2.3.1><span class=header-section-number>2.2.3.1</span> アクティビティ<a href=#subsubsec:activities class=anchor aria-hidden=true></a></h4><p><strong>アクティビティ</strong>は、アプリ内の閲覧できるウィンドウやページです（例えば、<em>メインページ</em>と<em>アプリ詳細ページ</em>は別のアクティビティです）。つまり、アクティビティは、ユーザーインターフェース（UI）のコンポーネントです。各アクティビティは、<em>ウィジェット</em>や<em>フラグメント</em>と呼ばれる複数のUIコンポーネントを持つことができ、同様に、後者のコンポーネントも、それぞれ複数のものを入れ子にしたり、オーバーレイすることができます。しかし、アクティビティはマスターコンポーネントです。アクティビティを2つネストさせることはできません。アプリケーションの開発者は、<em>インテントフィルター</em>と呼ばれる方法を使用して、アクティビティ内で外部ファイルを開くことを選択することもできます。ファイルマネージャーを使ってファイルを開こうとすると、ファイルマネージャーかシステムがインテントフィルターをスキャンして、どのアクティビティーがその特定のファイルを開けるかを決め、これらのアクティビティーでファイルを開けるように提案します。（したがって、アプリケーション自体には何の関係もありません）<p><em>エクスポート可能</em>なアクティビティは、通常、サードパーティアプリで開くことができます（一部のアクティビティには権限が必要なため、その場合はその権限を持つアプリケーションのみが開くことができます）。<em>アクティビティ</em>タブでは、アクティビティ名（各リスト項目の上部）がボタンとなっています。これは、<em>エクスポート可能</em>なアクティビティでは有効で、それ以外では無効になっています（Rootユーザーはどのアクティビティでも開くことができます）。ボタンをクリックすると、App\nManagerでアクティビティを直接開くことができます。また、アクティビティを長押しすることで、インタセプターのページを開くことができます。現在は、<em>エクスポート可能</em>なアクティビティに対してのみ機能します。<div class=\"amalert warning\"><p><strong><em>Notice.</em></strong><p>例えば、<em>アプリ詳細アクティビティ</em>は、少なくともパッケージ名を提供する必要があるため、開くことができません。これらの依存関係は、常にプログラムで推論することはできません。したがって、App\nManagerを使用してそれらを開くことはできません。</div><p>また、これらのエクスポート可能なアクティビティのショートカットを作成し（専用ボタンを使用）、必要であれば、ショートカットの編集ボタンでショートカットも編集することができます。<div class=\"amalert danger\"><p><strong><em>Caution.</em></strong><p>App Managerをアンインストールすると、App\nManagerで作成したショートカットはすべて失われます。</div></section><section id=subsubsec:details:servcies class=level4 data-number=2.2.3.2><h4 data-number=2.2.3.2><span class=header-section-number>2.2.3.2</span> サービス<a href=#subsubsec:details:servcies class=anchor aria-hidden=true></a></h4><p>ユーザーが閲覧することができる<a href=#subsubsec:activities>アクティビティ</a>とは異なり、<strong>サービス</strong>はバックグラウンドタスクを処理します。\n例えば、スマートフォンのブラウザを使ってインターネットからファイルをダウンロードする場合、ブラウザはコンテンツをダウンロードするためにバックグラウンドサービスを使用しています。<p>アクティビティを終了すると、通常はすぐにメモリ上から破棄されます（端末の空きメモリの量など、多くの要因に依存します）。しかしサービスは、必要に応じて無期限に実行することができます。より多くのサービスがバックグラウンドで実行されている場合、メモリや処理能力が不足するため、携帯電話の動作が遅くなり、携帯電話のバッテリーがより速く消耗する可能性があります。新しいAndroidのバージョンでは、すべてのアプリでバッテリーの最適化機能がデフォルトで有効になっています。この機能を有効にすると、システムは任意のサービスをランダムに終了させることができます。<p>ところで、アクティビティもサービスもメイン<a href=https://stackoverflow.com/questions/7597742>ルーパー</a>と呼ばれる同じルーパーで実行されるため、サービスが本当にバックグラウンドで実行されているとは限りません。それを保証するのは、アプリケーションの開発者の仕事です。アプリケーションとサービスは<a href=#subsubsec:app-details-receivers>ブロードキャストレシーバー</a>を使って通信しています。</section><section id=subsubsec:app-details-receivers class=level4 data-number=2.2.3.3><h4 data-number=2.2.3.3><span class=header-section-number>2.2.3.3</span> レシーバ<a href=#subsubsec:app-details-receivers class=anchor aria-hidden=true></a></h4><p><strong>レシーバー</strong>（<em>ブロードキャストレシーバー</em>とも呼ばれる）は、特定のイベントに対して特定のタスクの実行を呼び出すために使用することができます。これらのコンポーネントは、ブロードキャストメッセージを受信するとすぐに実行されるため、ブロードキャストレシーバーと呼ばれます。これらのブロードキャストメッセージは、インテントと呼ばれるメソッドを使用して送信されます。インテントはAndroidの特別な機能で、アプリケーションやアクティビティ、サービスを開いたり、ブロードキャストメッセージを送信したりするために使われます。そのため、<a href=#subsubsec:activities>アクティビティ</a>と同様に、ブロードキャストレシーバもインテントフィルターを用いて、必要なブロードキャストメッセージのみを受信することができます。ブロードキャストメッセージは、システムまたはアプリケーション自体のいずれかによって送信することができます。ブロードキャストメッセージが送信されると、対応するレシーバーはシステムによって起動され、タスクを実行できるようになります。例えば、メモリが少ない場合、モバイルデータを有効にしたり、Wifiに接続した後に、端末がフリーズしたり、一瞬ラグが発生することがあります。なぜだか不思議に思ったことはありませんか？これは、「android.net.conn.CONNECTIVITY_CHANGE」を受信できるブロードキャストレシーバーが、データ接続を有効にすると同時に、システムによって起こされるからです。多くのアプリがこのインテントフィルタを使っているため、これらのアプリはすべて、システムによってほとんどすぐに起こされ、フリーズや遅延の原因になっています。要するに、レシーバはプロセス間通信（IPC）、つまり異なるアプリ間（必要な権限がある場合）、あるいは単一アプリケーションの異なるコンポーネント間の通信に使用できます。</section><section id=subsubsec:providers class=level4 data-number=2.2.3.4><h4 data-number=2.2.3.4><span class=header-section-number>2.2.3.4</span> プロバイダ<a href=#subsubsec:providers class=anchor aria-hidden=true></a></h4><p><strong>プロバイダ</strong>（<em>コンテンツプロバイダ</em>ともいう）は、アプリ内のデータ管理に使用されます。例えば、App\nManagerでAPKファイルの保存やルールのエクスポートを行う場合、「androidx.core.content.FileProvider」というコンテンツプロバイダを使用します。データベース管理、トラッキング、検索など、様々なコンテンツ関連のタスクを管理するために、他のコンテンツプロバイダや、カスタムプロバイダーもあります。各コンテンツプロバイダは、パッケージ名と同様に、Androidエコシステム全体でその特定のアプリケーションに固有のAuthorityと呼ばれるフィールドを持っています。</section><section id=root化された端末向けの追加機能 class=level4 data-number=2.2.3.5><h4 data-number=2.2.3.5><span class=header-section-number>2.2.3.5</span>\nRoot化された端末向けの追加機能<a href=#root化された端末向けの追加機能 class=anchor aria-hidden=true></a></h4><p>これらのタブでは非Rootユーザーよりも、Rootユーザーは様々な操作を行うことができます。<section id=コンポーネントをブロックする class=level5 data-number=2.2.3.5.1><h5 data-number=2.2.3.5.1><span class=header-section-number>2.2.3.5.1</span>\nコンポーネントをブロックする<a href=#コンポーネントをブロックする class=anchor aria-hidden=true></a></h5><p>各コンポーネント項目の右端には、「ブロック」ボタンがあります。（ブロックされているときは「ブロック解除」ボタンとなります）\nこのボタンを使って、そのコンポーネントのブロックの状態を切り替えることができます。\n<a href=#subsubsec:instant-component-blocking>インスタントブロッキング</a>を有効にしていない場合、\nまたは以前にアプリケーションにブロックを適用していない場合は、\n3点メニューの<strong>ルールを反映</strong>オプションで変更を適用する必要があります。\nまた、<strong>ルールを除去</strong>オプションから、すでに適用されたルールを削除することもできます。<div class=seealso-inline><p><em>こちらもご覧ください: <span><a href=#sec:faq:app-components>FAQ:\nアプリのコンポーネント</a></span></em></div></section><section id=par:appdetails:blocking-trackers class=level5 data-number=2.2.3.5.2><h5 data-number=2.2.3.5.2><span class=header-section-number>2.2.3.5.2</span>\nトラッカーをブロックする<a href=#par:appdetails:blocking-trackers class=anchor aria-hidden=true></a></h5><p>トラッカーコンポーネントを無効にするには、三点メニューの「トラッカーをブロック」を使用します。\n現在表示されているタブに関係なく、すべてのトラッカーコンポーネントがブロックされます。<div class=\"amalert tip\"><p><strong><em>Info.</em></strong><p>トラッカーコンポーネントは、アプリのコンポーネントの部分集合です。\nしたがって、他のコンポーネントのブロックに使用されるのと同じ方法によりブロックされます。</div><div class=seealso><p><em>こちらもご覧ください:</em><ul class=incremental><li><p><a href=#subsec:tracker-classes-versus-tracker-components>FAQ:\nトラッカーのクラスとトラッカーコンポーネント</a><li><p><a href=#sec:scanner-page>スキャナーページ</a><li><p><a href=#subsec:block-unblock-trackers>ワンタップ一括処理:\nトラッカーをブロック/ブロック解除</a></ul></div></section></section></section><section id=subsec:permission-tabs class=level3 data-number=2.2.4><h3 data-number=2.2.4><span class=header-section-number>2.2.4</span>\n<a href=#toc:subsec:permission-tabs>権限タブ</a><a href=#subsec:permission-tabs class=anchor aria-hidden=true></a></h3><p><strong>App Ops</strong>、<strong>Uses\nPermissions</strong>、<strong>Permissions</strong>タブは、権限に関連しています。\nAndroidでは、同じID(<em>共有ID</em>として知られます)を持たないアプリやプロセス間の通信は、しばしばパーミッション（複数可）を必要とします。\nこれらの権限は、権限コントローラーによって管理されます。\nアプリケーションのマニフェストに記載されていれば自動的に付与される<em>通常</em>の権限もありますが、\n<em>dangerous</em>、<em>development</em>パーミッションはユーザーの確認が必要です。\nこれらのタブで使用される色については、<a href=#subsec:app-details-colour-codes data-reference-type=ref data-reference=subsec:app-details-colour-codes>2.2.1</a>節で説明しています。<section id=subsubsec:app-ops class=level4 data-number=2.2.4.1><h4 data-number=2.2.4.1><span class=header-section-number>2.2.4.1</span> App Ops<a href=#subsubsec:app-ops class=anchor aria-hidden=true></a></h4><p><strong>App Ops</strong> は、<strong>Application\nOperations</strong>(アプリケーションの操作)の略です。 Android\n4.3以降、<em>App\nOps</em>はAndroidシステムによってアプリ権限の大部分を制御するために使用されています。\n各AppOpsは、それらに関連付けられた一意の番号を持っており、それはApp\nOpsタブの最初の括弧内に閉じられています。\nまた、プライベート名を持ち、任意でパブリック名を持つことができます。\nいくつかのAppOpsは、<em>権限</em>とも関連付けられています。\nAppOpsの保護レベルは、関連付けられた権限に基づいて決定されます。\n<em>フラグ</em>、<em>権限名</em>、<em>権限の説明</em>、<em>パッケージ名</em>、<em>グループ</em>のような情報は、\n関連付けられた<a href=#subsubsec:permissions>権限</a>から取得されます。\nその他の情報としては、以下のようなものがあります:<ul class=incremental><li><p><strong>モード</strong> 現在の認可状態を表し、\nallow、deny（やや語弊がありますが、単にエラーを意味します）、\nignore（実際には拒否を意味します）、default（ベンダーが内部で設定したデフォルトのリストから推測されます）、\nforeground（新しいAndroidシステムでは、アプリケーションがフォアグラウンドで実行中のときのみAppOpsが使用できることを意味します）があります。\nまた、ベンダーが設定したいくつかのカスタムモード（例えば、MIUIの場合はask）があります。<li><p><strong>使用した時間</strong>\nこのAppOpsが使用された時間を表します。<li><p><strong>許可した時間</strong>\nこのAppOpsが最後に許可された時間を表します。<li><p><strong>拒否した時間</strong>\nこのAppOpsが最後に拒否された時間を表します。</ul><div class=\"amalert tip\"><p><strong><em>Info.</em></strong><p>このタブの内容は、ADBにてtexttt<span>android.permission.GET_APP_OPS_STATS</span>権限が付与されている場合、非Rootユーザーでも見ることができます。</div><p>各AppOpsの項目の横にトグルボタンがあり、AppOpsを許可または拒否（無視）するために使用することができます。\nデバイスで利用可能な他のモードを設定する必要がある場合は、項目を長押ししてください。\nタブに表示されていないAppOpsを追加で設定する必要がある場合は、\nメニューの<em>カスタムAppOpsを適用</em>オプションを使用します。\nまた、<em>デフォルトに戻す</em>オプションを使用して変更内容をリセットしたり、\nメニューの対応するオプションを使用して危険なAppOpsをすべて拒否したりすることができます。\nまた、AppOpsの名前と関連する一意の番号（または値）で昇順に並べ替えることもできます。\nまた、対応するソートオプションを使用して、拒否されたAppOpsを最初に表示することができます。<div class=\"amalert warning\"><p><strong><em>Warning.</em></strong><p>AppOpsを拒否すると、アプリケーションが誤動作することがあります。\nそのような場合は、<em>デフォルトに戻す</em>オプションを使用してください。\nAppOpsの動作の性質上、システムがそれを適用するのに時間がかかることがあります。</div><div class=seealso-inline><p><em>こちらもご覧ください: <span><a href=#ch:app-ops>付録: App\nOps</a></span></em></div></section><section id=使用する権限 class=level4 data-number=2.2.4.2><h4 data-number=2.2.4.2><span class=header-section-number>2.2.4.2</span> 使用する権限<a href=#使用する権限 class=anchor aria-hidden=true></a></h4><p><strong>Uses\nPermissions</strong>は、アプリケーションで使用される権限です。マニフェストで<code>uses-permission</code>タグを使用して宣言されます。\n<em>フラグ</em>、<em>パーミッション名</em>、<em>パーミッションの説明</em>、<em>パッケージ名</em>、<em>グループ</em>などの情報は、\n関連する<a href=#subsubsec:permissions>権限</a>から取得されます。<p><strong>RootおよびADBユーザー</strong>は、各権限項目の右側にあるトグルボタンを使用して、\n<em>dangerous</em>権限と<em>development</em>権限を許可したり、取り消したりすることができます。\nまた、メニューの対応するオプションを使用して、危険なパーミッションを一度に取り消すこともできます。\nAndroidは<em>通常の</em>\nパーミッション（そのほとんどがそうですが）を変更することができないので、\nこの2種類のパーミッションのみ取り消すことができます。\n唯一の選択肢は、アプリケーションマニフェストを編集し、そこからこれらの権限を削除することです。<div class=\"amalert tip\"><p><strong><em>Info.</em></strong><p>dangerous権限はシステムによってデフォルトで拒否されているため、\nすべてのdangerous権限を取り消すことは、すべての権限をリセットすることと同じです。</div><div class=\"amalert tip\"><p><strong><em>Notice.</em></strong><p>API23以前を対象としたアプリは、権限を変更することができません。\nそのため、そのようなアプリではパーミッションの切り替えは無効です。</div><p>ユーザーは、権限名でソートしたり（昇順）、メニューの対応するオプションを使用して、拒否された権限や\ndangerous権限を最初に表示するように選択することができます。</section><section id=subsubsec:permissions class=level4 data-number=2.2.4.3><h4 data-number=2.2.4.3><span class=header-section-number>2.2.4.3</span> 権限<a href=#subsubsec:permissions class=anchor aria-hidden=true></a></h4><p><strong>パーミッション</strong>は通常、アプリケーション自身によって定義されるカスタム権限です。\n主に古いアプリケーションでは、通常の権限も含まれることがあります。そこに表示される各項目の完全な説明は次の通りです:<ul class=incremental><li><p><strong>権限名</strong>\n各権限は<code>android.permission.INTERNET</code>のような一意の名前を持っており、\n複数のアプリケーションがその権限を要求することができます。<li><p><strong>アイコン</strong>\n各権限は任意のアイコンを持つことができます。\n他の権限タブでは、アプリケーションマニフェストにアイコンが含まれていないため、アイコンを持ちません。<li><p><strong>詳細</strong>\nこのフィールドは、権限についての詳細な説明です。権限に関連する説明がない場合、このフィールドは表示されません。<li><p><strong>フラグ</strong>\n(フラグシンボルまたは<strong>保護レベル</strong>名を使用）\ntextit<span>normal</span>, <em>development</em>, <em>dangerous</em>,\n<em>instant</em>, <em>granted</em>, <em>revoked</em>,<em>signature</em>,\n<em>privileged</em>などの権限フラグを表します。<li><p><strong>パッケージ名</strong>\n権限に関連するパッケージ名、すなわちその権限を定義したパッケージを表します。<li><p><strong>グループ</strong>\n権限に関連するグループ名を表します。新しいAndroidシステムではグループ名を使用しないため、\n通常<code>android.permission-group.UNDEFINED</code>やグループ名が全く表示されないことになるでしょう。</ul></section></section><section id=subsec:signatures-tab class=level3 data-number=2.2.5><h3 data-number=2.2.5><span class=header-section-number>2.2.5</span>\n<a href=#toc:subsec:signatures-tab>署名情報タブ</a><a href=#subsec:signatures-tab class=anchor aria-hidden=true></a></h3><p><strong>署名</strong>は、実際には署名情報と呼ばれ、アプリケーションは公開する前に、\nアプリケーション開発者によって1つ以上の署名証明書によって署名されます。\nアプリケーションの完全性（そのアプリケーションが実際の開発者のものかどうか、\n他の人によって変更されていないかどうか）は、署名情報を使って確認できます。\nなぜなら、アプリケーションを第三者が変更した場合、署名情報は実際の開発者によって秘密にされているため、\n元の証明書を使って再び署名することができないからです。\nこれらの署名はチェックサムで検証することができます。チェックサムは、証明書自体から生成されます。\n開発者がチェックサムを提供する場合、<strong>署名</strong>タブで表示されたチェックサムを照合することができます。\n例えば、Github、Telegramチャンネル、IzzyOnDroidのリポジトリからApp\nManagerをダウンロードした場合、次の<em>SHA256</em>チェックサムをこのタブに表示されるものと照合するだけで、そのアプリケーションが実際に私がリリースしたものかどうか確認することができます:<pre><code>320c0c0fe8cef873f2b554cb88c837f1512589dcced50c5b25c43c04596760ab</code></pre><p>ここに表示されるチェックサムは、<em>MD5</em>、<em>SHA1</em>、<em>SHA256</em>の3種類です。<div class=\"amalert danger\"><p><strong><em>Caution.</em></strong><p>署名情報の検証には、<em>SHA256</em>チェックサムのみ、もしくはこれら3つすべてを使用することを推奨します。\n<em>MD5</em>や<em>SHA1</em>のチェックサムだけでは、複数の証明書に対して同じハッシュを生成する可能性あるので、\nそれらのみに依存しないようにしてください。</div></section><section id=subsec:uses-features-tab class=level3 data-number=2.2.6><h3 data-number=2.2.6><span class=header-section-number>2.2.6</span>\n<a href=#toc:subsec:uses-features-tab>Uses Features tab</a><a href=#subsec:uses-features-tab class=anchor aria-hidden=true></a></h3><p><strong>Uses Features</strong> tab lists the features declared by the\napplication, such as OpenGL ES, telephony, and leanback. Some features\ncan be required by the application, and some features can be optional.\nRequired features must be present in the system along with the required\nversion. Otherwise, any attempt to install the application will be\ndenied by the system. Colours used in this tab are explained in §<a href=#subsec:app-details-colour-codes data-reference-type=ref data-reference=subsec:app-details-colour-codes>2.2.1</a>.</section><section id=subsec:configurations-tab class=level3 data-number=2.2.7><h3 data-number=2.2.7><span class=header-section-number>2.2.7</span>\n<a href=#toc:subsec:configurations-tab>Configurations tab</a><a href=#subsec:configurations-tab class=anchor aria-hidden=true></a></h3><p><strong>Configurations</strong> tab lists the configurations required\nby the application, such as input method type (qwerty, 12 key), touch\nscreen type (finger, stylus, etc.), and navigation type (dial pad,\ntrackball, wheel). This tab is going to be empty for most\napplications.</section><section id=subsec:shared-libs-tab class=level3 data-number=2.2.8><h3 data-number=2.2.8><span class=header-section-number>2.2.8</span>\n<a href=#toc:subsec:shared-libs-tab>共有ライブラリタブ</a><a href=#subsec:shared-libs-tab class=anchor aria-hidden=true></a></h3><p><strong>Shared libraries</strong> tab lists the legacy JAR\ndependencies, any static shared library dependencies (currently, the\nonly known cases are the Chromium-based browsers and WebViews) as well\nas the JNI (Java native interface) libraries. For JNI libraries, it\nspecifies platform (x86/x86_64/ARM/AArch64), architecture (32/64 bit),\nobject type (shared object or executable), etc.</section></section><section id=sec:1-click-ops-page class=level2 data-number=2.3><h2 data-number=2.3><span class=header-section-number>2.3</span> <a href=#toc:sec:1-click-ops-page>ワンタップ一括処理</a><a href=#sec:1-click-ops-page class=anchor aria-hidden=true></a></h2><p>This page is displayed on selecting the <a href=#subsubsec:main:1-click-ops>1-Click Ops option</a> in the <a href=#subsec:main-page-options-menu>main menu</a>.<section id=subsec:block-unblock-trackers class=level3 data-number=2.3.1><h3 data-number=2.3.1><span class=header-section-number>2.3.1</span>\n<a href=#toc:subsec:block-unblock-trackers>トラッカーのブロック/ブロック解除</a><a href=#subsec:block-unblock-trackers class=anchor aria-hidden=true></a></h3><p>This option can be used to block or unblock the ad/tracker components\nfrom the installed applications. On selecting this option, App Manager\nwill ask if it should list trackers from all the applications or only\nfrom the user applications. Novice users should avoid blocking trackers\nfrom the system applications in order to avoid bad consequences. After\nthat, a multi-choice dialog box will appear where it is possible to\nexclude one or more applications from this operation. The changes are\napplied immediately on pressing the <em>block</em> or <em>unblock</em>\nbutton.<div class=\"amalert warning\"><p><strong><em>Notice.</em></strong><p>Certain applications may not function as expected after blocking\ntheir trackers. If that is the case, remove the blocking rules all at\nonce or one by one in the component tabs of the <a href=#sec:app-details-page>App Details page</a> for the corresponding\napplication.</div><div class=seealso-inline><p><em>こちらもご覧ください: <span><a href=#par:appdetails:blocking-trackers>App Details Page: Blocking\nTrackers</a></span></em></div></section><section id=subsec:block-components-dots class=level3 data-number=2.3.2><h3 data-number=2.3.2><span class=header-section-number>2.3.2</span>\n<a href=#toc:subsec:block-components-dots>コンポーネントのブロック…</a><a href=#subsec:block-components-dots class=anchor aria-hidden=true></a></h3><p>This option can be used to block certain application components as\nspecified by their signatures. A signature of a component is the full\nname or partial name of the component. For safety, it is recommended to\nadd a <code>.</code> (dot) at the end of each partial signature, because\nthe underlying algorithm searches and matches the components in a greedy\nmanner. It is also possible to insert more than one signature in which\ncase all the signatures have to be separated by white spaces. Similar to\nthe option above, there is also an option to apply blocking to the\nsystem applications.<div class=\"amalert danger\"><p><strong><em>Caution.</em></strong><p>If you are not aware of the consequences of blocking applcations\ncomponents by their signatures, you should avoid using this option as it\nmay result in bootloop or soft brick, and you may have to apply factory\nreset as a result.</div></section><section id=subsec:set-mode-for-app-ops-dots class=level3 data-number=2.3.3><h3 data-number=2.3.3><span class=header-section-number>2.3.3</span>\n<a href=#toc:subsec:set-mode-for-app-ops-dots>AppOpsモードの設定…</a><a href=#subsec:set-mode-for-app-ops-dots class=anchor aria-hidden=true></a></h3><p>This option can be used to configure certain <a href=#ch:app-ops>applcation operations</a> of all or selected\napplications. There are two fields. The first field can be used to\ninsert more than one app op constants (either names or values) separated\nby white spaces. It is not always possible to know in advance about all\nthe app op constants as they vary from device to device and from OS to\nOS. Desired app op constant can be found in the <em>App Ops</em> tab\nlocated in the <a href=#sec:app-details-page>App Details page</a>. The\nsecond field can be used to insert or select one of the <a href=#subsec:mode-constants>modes</a> that will be set against the\nspecified app ops.<div class=\"amalert danger\"><p><strong><em>Caution.</em></strong><p>Unless you are well-informed about app ops and the consequences of\nblocking them, you should avoid using this option.</div></section><section id=subsec:1-click-back-up class=level3 data-number=2.3.4><h3 data-number=2.3.4><span class=header-section-number>2.3.4</span>\n<a href=#toc:subsec:1-click-back-up>バックアップ</a><a href=#subsec:1-click-back-up class=anchor aria-hidden=true></a></h3><p>1-Click options for back up. As a precaution, it lists the affected\nbackups before performing any operation.<section id=back-up-all-apps. class=level5 data-number=2.3.4.0.1><h5 data-number=2.3.4.0.1><span class=header-section-number>2.3.4.0.1</span> Back up all apps.<a href=#back-up-all-apps. class=anchor aria-hidden=true></a></h5><p>Back up all the installed applications.</section><section id=redo-existing-backups. class=level5 data-number=2.3.4.0.2><h5 data-number=2.3.4.0.2><span class=header-section-number>2.3.4.0.2</span> Redo existing backups.<a href=#redo-existing-backups. class=anchor aria-hidden=true></a></h5><p>Back up all the installed applications that have a previous\nbackup.</section><section id=back-up-apps-without-backups. class=level5 data-number=2.3.4.0.3><h5 data-number=2.3.4.0.3><span class=header-section-number>2.3.4.0.3</span> Back up apps without\nbackups.<a href=#back-up-apps-without-backups. class=anchor aria-hidden=true></a></h5><p>Back up all the installed applications without a previous backup.</section><section id=verify-and-redo-backups. class=level5 data-number=2.3.4.0.4><h5 data-number=2.3.4.0.4><span class=header-section-number>2.3.4.0.4</span> Verify and redo\nbackups.<a href=#verify-and-redo-backups. class=anchor aria-hidden=true></a></h5><p>Verify the recently made backups of the installed applications and\nredo backup if necessary.</section><section id=back-up-apps-with-changes. class=level5 data-number=2.3.4.0.5><h5 data-number=2.3.4.0.5><span class=header-section-number>2.3.4.0.5</span> Back up apps with\nchanges.<a href=#back-up-apps-with-changes. class=anchor aria-hidden=true></a></h5><p>If an app has changed since the last backup, redo its backup. It\nchecks a number of indices including application version, last update\ndate, last launch date, integrity and file hashes. Directory hashes are\ntaken during the backup process and are stored in a database. On running\nthis operation, new hashes are taken and compared with the ones kept in\nthe database.</section></section><section id=subsec:1-click-restore class=level3 data-number=2.3.5><h3 data-number=2.3.5><span class=header-section-number>2.3.5</span>\n<a href=#toc:subsec:1-click-restore>復元</a><a href=#subsec:1-click-restore class=anchor aria-hidden=true></a></h3><p>1-Click options for restore. As a precaution, it lists the affected\nbackups before performing any operation.<section id=restore-all-apps. class=level5 data-number=2.3.5.0.1><h5 data-number=2.3.5.0.1><span class=header-section-number>2.3.5.0.1</span> Restore all apps.<a href=#restore-all-apps. class=anchor aria-hidden=true></a></h5><p>Restore <em>base backup</em> of all the backed up applications.</section><section id=restore-not-installed-apps. class=level5 data-number=2.3.5.0.2><h5 data-number=2.3.5.0.2><span class=header-section-number>2.3.5.0.2</span> Restore not installed\napps.<a href=#restore-not-installed-apps. class=anchor aria-hidden=true></a></h5><p>Restore <em>base backup</em> of all the backed up applications that\nare not currently installed.</section><section id=restore-latest-backups. class=level5 data-number=2.3.5.0.3><h5 data-number=2.3.5.0.3><span class=header-section-number>2.3.5.0.3</span> Restore latest backups.<a href=#restore-latest-backups. class=anchor aria-hidden=true></a></h5><p>Restore <em>base backup</em> of already installed applications whose\nversion codes are higher than the installed version code.</section></section><section id=subsec:trim-caches-in-all-apps class=level3 data-number=2.3.6><h3 data-number=2.3.6><span class=header-section-number>2.3.6</span>\n<a href=#toc:subsec:trim-caches-in-all-apps>Trim Caches in All\nApps</a><a href=#subsec:trim-caches-in-all-apps class=anchor aria-hidden=true></a></h3><p>Delete caches from all applications, including Android system. During\nthis operation, caches of all the running applications may not be\ncleared as expected.</section></section><section id=sec:profiles-page class=level2 data-number=2.4><h2 data-number=2.4><span class=header-section-number>2.4</span> <a href=#toc:sec:profiles-page>Profiles Page</a><a href=#sec:profiles-page class=anchor aria-hidden=true></a></h2><p>Profiles page can be accessed from the <a href=#subsec:main-page-options-menu>options-menu</a> in the main page.\nIt primarily displays a list of configured profiles along with the\ntypical options to perform operations on them. New profiles can also be\nadded using the <em>plus</em> button at the bottom-right corner.\nProfiles can be imported, duplicated or deleted. Clicking on a profile\nitem opens its <a href=#sec:profile-page>profile page</a>.<section id=subsec:profiles-options-menu class=level3 data-number=2.4.1><h3 data-number=2.4.1><span class=header-section-number>2.4.1</span>\n<a href=#toc:subsec:profiles-options-menu>Options Menu</a><a href=#subsec:profiles-options-menu class=anchor aria-hidden=true></a></h3><p>The three-dots menu in the top-right corner opens the global option\nmenu. It has an option to import an existing profile that was previously\nexported from App Manager.<p>Long clicking on any profile item brings up another options-menu. It\noffers the following options:<ul class=incremental><li><p><strong>Apply now….</strong> This option can be used to apply the\nprofile directly. When clicked, a dialog is displayed where it is\npossible to select a <a href=#subsubsec:profile-state>profile\nstate</a>. On selecting one of the states, the profile will be applied\nimmediately.<li><p><strong>Delete.</strong> Clicking on this option will remove the\nprofile immediately without a warning.<li><p><strong>Duplicate.</strong> This option can be used to duplicate\nthe profile. When clicked, a dialog is displayed where it is possible to\nset a name for the new profile. On clicking “OK”, the <a href=#sec:profile-page>profile page</a> will be loaded by duplicating\nall the configurations that this profile have. However, the profile will\nnot be saved until it is saved manually.<li><p><strong>Copy profile ID.</strong> This option is used to copy the\nunique profile ID of the profile. The profile ID can be used to <a href=#subsec:triggering-a-profile>trigger the profile</a> from a\nthird-party application.<li><p><strong>Export.</strong> Export the profile to an external\nstorage. Profiles exported this way can be imported via the\n<em>import</em> option as mentioned above.<li><p><strong>Create shortcut.</strong> This option can be used to\ncreate a shortcut for the profile. There are two options:\n<em>Simple</em> and <em>Advanced</em>. When configured with the latter\noption, it prompts the user to select a profile state when the shortcut\nis invoked. The former option, on the other hand, always uses the\ndefault state that was configured when the profile was last\nsaved.</ul></section></section><section id=sec:profile-page class=level2 data-number=2.5><h2 data-number=2.5><span class=header-section-number>2.5</span> <a href=#toc:sec:profile-page>Profile Page</a><a href=#sec:profile-page class=anchor aria-hidden=true></a></h2><p>Profile page displays the configurations for a profile. It also\noffers the options to edit them.<section id=subsec:profile-options-menu class=level3 data-number=2.5.1><h3 data-number=2.5.1><span class=header-section-number>2.5.1</span>\n<a href=#toc:subsec:profile-options-menu>Options Menu</a><a href=#subsec:profile-options-menu class=anchor aria-hidden=true></a></h3><p>The three dots menu in the top-right corner opens the options-menu.\nIt contains several options such as–<ul class=incremental><li><p><strong>Apply.</strong> This option can be used to apply the\nprofile directly. When clicked, a dialog is displayed where it is\npossible to select a <a href=#subsubsec:profile-state>profile\nstate</a>. On selecting one of the states, the profile will be applied\nimmediately.<div class=\"amalert tip\"><p><strong><em>Notice.</em></strong><p>When you apply a profile, if some packages do not match the criteria,\nthey will simply be ignored.</div><li><p><strong>Save.</strong> Save changes to the profile.<li><p><strong>Discard.</strong> Discard any modifications made since\nthe last time it was saved.<li><p><strong>Delete.</strong> Clicking on this option will remove the\nprofile immediately without a warning.<li><p><strong>Duplicate.</strong> This option can be used to duplicate\nthe profile. When clicked, a dialog is displayed where it is possible to\nset a name for the new profile. On clicking “OK”, this page will be\nreloaded by duplicating all the configurations that this profile have.\nHowever, the new profile will not be saved until it is saved\nmanually.<li><p><strong>Create shortcut.</strong> This option can be used to\ncreate a shortcut for the profile. There are two options:\n<em>Simple</em> and <em>Advanced</em>. When configured with the latter\noption, it prompts the user to select a profile state when the shortcut\nis invoked. The former option, on the other hand, always uses the\ndefault state that was configured when the profile was last\nsaved.</ul></section><section id=subsec:profile-apps-tab class=level3 data-number=2.5.2><h3 data-number=2.5.2><span class=header-section-number>2.5.2</span>\n<a href=#toc:subsec:profile-apps-tab>Apps Tab</a><a href=#subsec:profile-apps-tab class=anchor aria-hidden=true></a></h3><p>Apps tab lists the packages configured for this profile. Packages can\nbe added or removed using the <em>plus</em> button located near the\nbottom of the screen. A package can also be removed by long clicking on\nit (in which case, a popup will be displayed with the only option,\n<em>delete</em>).</section><section id=subsec:profile-configurations-tab class=level3 data-number=2.5.3><h3 data-number=2.5.3><span class=header-section-number>2.5.3</span>\n<a href=#toc:subsec:profile-configurations-tab>Configurations\nTab</a><a href=#subsec:profile-configurations-tab class=anchor aria-hidden=true></a></h3><p>Configurations tab can be used to configure the selected\npackages.<section id=profile-id class=level4 data-number=2.5.3.1><h4 data-number=2.5.3.1><span class=header-section-number>2.5.3.1</span> Profile ID<a href=#profile-id class=anchor aria-hidden=true></a></h4><p>The unique ID for this profile, currently set based on the profile\nname. The profile ID can be used to <a href=#subsec:triggering-a-profile>trigger the profile</a> from a\nthird-party application.</section><section id=comment class=level4 data-number=2.5.3.2><h4 data-number=2.5.3.2><span class=header-section-number>2.5.3.2</span> Comment<a href=#comment class=anchor aria-hidden=true></a></h4><p>This is the text that will be displayed in the <a href=#sec:profiles-page>profiles page</a>. If not set, the current\nconfigurations will be displayed instead.</section><section id=subsubsec:profile-state class=level4 data-number=2.5.3.3><h4 data-number=2.5.3.3><span class=header-section-number>2.5.3.3</span> State<a href=#subsubsec:profile-state class=anchor aria-hidden=true></a></h4><p>Denotes how certain configured options will behave by default. For\ninstance, if <em>disable</em> option is turned on, the applications will\nbe disabled if the state is <em>on</em> and will be enabled if the state\nis <em>off</em>. Currently, it only supports <em>on</em> and\n<em>off</em> values.</section><section id=users class=level4 data-number=2.5.3.4><h4 data-number=2.5.3.4><span class=header-section-number>2.5.3.4</span> Users<a href=#users class=anchor aria-hidden=true></a></h4><p>Select users for which is the profile will be applied. All users are\nselected by default.</section><section id=components class=level4 data-number=2.5.3.5><h4 data-number=2.5.3.5><span class=header-section-number>2.5.3.5</span> Components<a href=#components class=anchor aria-hidden=true></a></h4><p>This behaves the same way as the <a href=#subsec:block-components-dots>Block Components…</a> option does\nin the 1-Click Ops page. However, the blocking here is only applied to\nthe selected packages. If the <a href=#subsubsec:profile-state>state</a> is <em>on</em>, the components\nwill be blocked, and if the state is <em>off</em>, the components will\nbe unblocked. The option can be disabled (regardless of the inserted\nvalues) by clicking on the <em>disabled</em> button on the input\ndialog.<div class=seealso-inline><p><em>こちらもご覧ください: <span><a href=#subsec:faq:what-are-app-components>What are the app\ncomponents?</a></span></em></div></section><section id=app-ops class=level4 data-number=2.5.3.6><h4 data-number=2.5.3.6><span class=header-section-number>2.5.3.6</span> App Ops<a href=#app-ops class=anchor aria-hidden=true></a></h4><p>This behaves the same way as the <a href=#subsec:set-mode-for-app-ops-dots>Set Mode for App Ops…</a>\noption does in the 1-Click Ops page. However, the operation here is only\napplied to the selected packages. If the <a href=#subsubsec:profile-state>state</a> is <em>on</em>, the app ops\nwill be denied (i.e. ignored), and if the state is <em>off</em>, the app\nops will be allowed. The option can be disabled (regardless of the\ninserted values) by clicking on the <em>disable</em> button in the input\ndialog.</section><section id=permissions class=level4 data-number=2.5.3.7><h4 data-number=2.5.3.7><span class=header-section-number>2.5.3.7</span> Permissions<a href=#permissions class=anchor aria-hidden=true></a></h4><p>This option can be used to grant or revoke certain permissions from\nthe selected packages. Like others above, permissions must be separated\nby white spaces. If the <a href=#subsubsec:profile-state>state</a> is\n<em>on</em>, the permissions will be revoked, and if the state is\n<em>off</em>, the permissions will be allowed. The option can be\ndisabled (regardless of the inserted values) by clicking on the\n<em>disable</em> button in the input dialog.</section><section id=backuprestore class=level4 data-number=2.5.3.8><h4 data-number=2.5.3.8><span class=header-section-number>2.5.3.8</span> Backup/Restore<a href=#backuprestore class=anchor aria-hidden=true></a></h4><p>This option can be used to take a backup of the selected applications\nand its data or restore them. Two options are available here: <em>Backup\noptions</em> and <em>backup name</em>.<ul class=incremental><li><p><strong>Backup options.</strong> Same as the <a href=#subsec:backup-restore-backup-options>backup options</a> of the\nbackup/restore feature. If not set, the default options will be\nused.<li><p><strong>Backup name.</strong> Set a custom name for the backup.\nIf the backup name is set, each time a backup is made, it will be given\na unique name with backup-name as the suffix. This behaviour will be\nfixed in a future release. Leave this field empty for regular “base”\nbackups (also, make sure not to enable <em>backup multiple</em> in the\nbackup options).</ul><p>If the <a href=#subsubsec:profile-state>state</a> is <em>on</em>,\nthe packages will be backed up, and if the state is <em>off</em>, the\npackages will be restored. The option can be disabled by clicking on the\n<em>disable</em> button in the input dialog.</section><section id=export-blocking-rules class=level4 data-number=2.5.3.9><h4 data-number=2.5.3.9><span class=header-section-number>2.5.3.9</span> Export Blocking Rules<a href=#export-blocking-rules class=anchor aria-hidden=true></a></h4><div class=\"amalert danger\"><p><strong><em>Danger.</em></strong><p>This option is not yet implemented.</div></section><section id=freeze class=level4 data-number=2.5.3.10><h4 data-number=2.5.3.10><span class=header-section-number>2.5.3.10</span> Freeze<a href=#freeze class=anchor aria-hidden=true></a></h4><p>Allow freezing or unfreezing the selected packages depending on the\nvalue of the <a href=#subsubsec:profile-state>state</a>. If the state\nis <em>on</em>, the packages will be frozen, and if the state is\n<em>off</em>, they will be unfrozen.</section><section id=force-stop class=level4 data-number=2.5.3.11><h4 data-number=2.5.3.11><span class=header-section-number>2.5.3.11</span> Force-stop<a href=#force-stop class=anchor aria-hidden=true></a></h4><p>Allow the selected packages to be force-stopped.</section><section id=clear-cache class=level4 data-number=2.5.3.12><h4 data-number=2.5.3.12><span class=header-section-number>2.5.3.12</span> Clear Cache<a href=#clear-cache class=anchor aria-hidden=true></a></h4><p>Enable clearing cache for the selected packages.</section><section id=clear-data class=level4 data-number=2.5.3.13><h4 data-number=2.5.3.13><span class=header-section-number>2.5.3.13</span> Clear Data<a href=#clear-data class=anchor aria-hidden=true></a></h4><p>Enable clearing data for the selected packages.</section><section id=block-trackers class=level4 data-number=2.5.3.14><h4 data-number=2.5.3.14><span class=header-section-number>2.5.3.14</span> Block Trackers<a href=#block-trackers class=anchor aria-hidden=true></a></h4><p>Enable blocking or unblocking of the tracker components from the\nselected packages depending on the value of the <a href=#subsubsec:profile-state>state</a>. If the state is <em>on</em>,\nthe trackers will be blocked, and if the state is <em>off</em>, the\ntrackers will be unblocked.</section><section id=save-apk class=level4 data-number=2.5.3.15><h4 data-number=2.5.3.15><span class=header-section-number>2.5.3.15</span> Save APK<a href=#save-apk class=anchor aria-hidden=true></a></h4><p>Enable saving APK files at <code>AppManager/apks</code> (or in the\ndirectory selected in the settings page) of the selected packages.</section></section></section><section id=sec:settings-page class=level2 data-number=2.6><h2 data-number=2.6><span class=header-section-number>2.6</span> <a href=#toc:sec:settings-page>Settings Page</a><a href=#sec:settings-page class=anchor aria-hidden=true></a></h2><p>Settings page can be used to customise the behaviour of App\nManager.<section id=subsec:language class=level3 data-number=2.6.1><h3 data-number=2.6.1><span class=header-section-number>2.6.1</span>\n<a href=#toc:subsec:language>Language</a><a href=#subsec:language class=anchor aria-hidden=true></a></h3><p>Configure in-app language. App Manager currently supports 22\n(twenty-two) languages.</section><section id=subsec:appearance class=level3 data-number=2.6.2><h3 data-number=2.6.2><span class=header-section-number>2.6.2</span>\n<a href=#toc:subsec:appearance>Appearance</a><a href=#subsec:appearance class=anchor aria-hidden=true></a></h3><section id=subsubsec:app-theme class=level4 data-number=2.6.2.1><h4 data-number=2.6.2.1><span class=header-section-number>2.6.2.1</span> App Theme<a href=#subsubsec:app-theme class=anchor aria-hidden=true></a></h4><p>Configure in-app theme.</section><section id=subsubsec:pure-black-theme class=level4 data-number=2.6.2.2><h4 data-number=2.6.2.2><span class=header-section-number>2.6.2.2</span> Pure Black Theme<a href=#subsubsec:pure-black-theme class=anchor aria-hidden=true></a></h4><p>Whether to use a black background instead of the material themed\nbackground.</section><section id=subsubsec:layout-direction class=level4 data-number=2.6.2.3><h4 data-number=2.6.2.3><span class=header-section-number>2.6.2.3</span> Layout Direction<a href=#subsubsec:layout-direction class=anchor aria-hidden=true></a></h4><p>Change layout direction, either left to right or right to left. This\nis usually set using the selected language but not everybody prefers the\nsame direction.</section><section id=subsubsec:enable/disable-features class=level4 data-number=2.6.2.4><h4 data-number=2.6.2.4><span class=header-section-number>2.6.2.4</span> Enable/Disable Features<a href=#subsubsec:enable/disable-features class=anchor aria-hidden=true></a></h4><p>Enable or disable certain features in App Manager, such as<ul class=incremental><li><p><strong>Interceptor</strong><li><p><strong>Manifest viewer</strong><li><p><strong>Scanner</strong><li><p><strong>Package installer</strong><li><p><strong>Usage access.</strong> With this feature turned off, App\nManager will never ask for the <em>Usage Access</em>\npermission.<li><p><strong>Log viewer</strong><li><p><strong>App explorer.</strong> The “Explore” option will not be\navailable while trying to open an APK file.<li><p><strong>App info.</strong> The “App info” option displayed while\ntrying to open an APK file.<li><p><strong>Code Editor</strong><li><p><strong>VirusTotal</strong></ul></section></section><section id=subsec:privacy class=level3 data-number=2.6.3><h3 data-number=2.6.3><span class=header-section-number>2.6.3</span>\n<a href=#toc:subsec:privacy>Privacy</a><a href=#subsec:privacy class=anchor aria-hidden=true></a></h3><section id=subsubsec:screen-lock class=level4 data-number=2.6.3.1><h4 data-number=2.6.3.1><span class=header-section-number>2.6.3.1</span> Screen Lock<a href=#subsubsec:screen-lock class=anchor aria-hidden=true></a></h4><p>Lock App Manager using Android screen lock provided a screen lock is\nconfigured.<div class=\"amalert warning\"><p><strong><em>Warning.</em></strong><p>If screen lock is disabled in Android after enabling this setting,\nApp Manager will not open until it is enabled again.</div></section><section id=subsubsec:run-am-in-background class=level4 data-number=2.6.3.2><h4 data-number=2.6.3.2><span class=header-section-number>2.6.3.2</span> Run App Manager in the\nBackground<a href=#subsubsec:run-am-in-background class=anchor aria-hidden=true></a></h4><p>Whether to run App Manager in the background to reduce the\ninitialisation delay. On certain devices, this can also help if you’re\nfrequently disconnected from ADB.</section><section id=subsubsec:use-the-internet class=level4 data-number=2.6.3.3><h4 data-number=2.6.3.3><span class=header-section-number>2.6.3.3</span> Use the Internet<a href=#subsubsec:use-the-internet class=anchor aria-hidden=true></a></h4><p>Whether to activate the Internet features in App Manager. This\ncurrently include VirusTotal and Pithus scanning in the <a href=#sec:scanner-page>Scanner page</a>.</section><section id=subsubsec:auth-manager class=level4 data-number=2.6.3.4><h4 data-number=2.6.3.4><span class=header-section-number>2.6.3.4</span> Authorization Manager<a href=#subsubsec:auth-manager class=anchor aria-hidden=true></a></h4><p>This setting allows a third-party application to get access to\ncertain features, such as profiles.</section></section><section id=subsec:mode-of-operation class=level3 data-number=2.6.4><h3 data-number=2.6.4><span class=header-section-number>2.6.4</span>\n<a href=#toc:subsec:mode-of-operation>Mode of Operation</a><a href=#subsec:mode-of-operation class=anchor aria-hidden=true></a></h3><p>Mode of operation defines how App Manager works as a whole. It has\nthe following options:<ul class=incremental><li><p><strong>Auto.</strong> Let App Manager decide the suitable\noption. Although this is the default option, non-rooted users should use\nthe <em>no-root</em> mode.<li><p><strong>Root.</strong> Operate App Manager in root mode. App\nManager will fall back to <em>no-root</em> mode if root is not detected,\nor in rare cases when Binder communication through root is disabled\n(e.g. in <a href=https://github.com/MuntashirAkon/AppManager/issues/606>Phh\nSuperUser</a>).<li><p><strong>ADB over TCP.</strong> Operate App Manager in ADB mode\nvia <a href=#sec:adb-over-tcp>ADB over TCP</a>. App Manager will fall\nback to <em>no-root</em> mode if ADB over TCP is not enabled.<li><p><strong>Wireless debugging.</strong> Enable ADB via Wireless\nDebugging. It will try to connect to the configured port automatically\nat first. On failure, it will ask the user to either pair or connect to\nthe ADB daemon manually. App Manager will fall back to <em>no-root</em>\nmode if it fails to connect to the ADB daemon this way.<div class=\"amalert tip\"><p><strong><em>Info.</em></strong><p>This option is only displayed in devices running Android 11 or later\nas Wireless Debugging was introduced in Android 11.</div><li><p><strong>No-root.</strong> Operate App Manager in no-root mode.\nWhile App Manager performs better in this mode, all the root- or\nADB-specific features will be disabled.</ul><p>It also displays the actual mode of operation at the top. The actual\nmode of operations are <em>root</em>, <em>ABD</em> and\n<em>no-root</em>.<div class=\"amalert tip\"><p><strong><em>Notice.</em></strong><p>“Remote service” is only required for ADB users or when you use the\ncustom commands.</div></section><section id=subsec:apk-signing class=level3 data-number=2.6.5><h3 data-number=2.6.5><span class=header-section-number>2.6.5</span>\n<a href=#toc:subsec:apk-signing>APK Signing</a><a href=#subsec:apk-signing class=anchor aria-hidden=true></a></h3><section id=signature-schemes class=level4 data-number=2.6.5.1><h4 data-number=2.6.5.1><span class=header-section-number>2.6.5.1</span> Signature Schemes<a href=#signature-schemes class=anchor aria-hidden=true></a></h4><p>Configure the <a href=https://source.android.com/security/apksigning>signature\nschemes</a> to be used when APK signing is enabled. v1 and v2 signature\nschemes are enabled by default, but v3 should also be enabled to ensure\nproper security in Android 9 or later.</section><section id=signing-key class=level4 data-number=2.6.5.2><h4 data-number=2.6.5.2><span class=header-section-number>2.6.5.2</span> Signing Key<a href=#signing-key class=anchor aria-hidden=true></a></h4><p>Configure the signing key for signing APK files. Keys from an\nexisting KeyStore can be imported to App Manager, or a new key can be\ngenerated.<div class=\"amalert tip\"><p><strong><em>Tip.</em></strong><p>If you need to use the key in the future, it is recommended that you\ncreate a KeyStore yourself and import the key here. Without a proper\nbackup, keys generated within App Manager are at the risk of being\ndeleted.</div></section><section id=align-apk-files class=level4 data-number=2.6.5.3><h4 data-number=2.6.5.3><span class=header-section-number>2.6.5.3</span> Align APK Files<a href=#align-apk-files class=anchor aria-hidden=true></a></h4><p>Performs zip alignment when App Manager signs an APK file. Zip\nalignment stores the files in the APK file (which is actually a zip\nfile) in a way that a zip file reader can access the files quite easily\nusing random access instead of loading the entire APK file in the\nmemory, which results in the reduction of Android’s memory usage. Note\nthat this step is required if an application’s manifest has\n<code>extractNativeLibs</code> set to <code>true</code>.</section></section><section id=subsec:installer class=level3 data-number=2.6.6><h3 data-number=2.6.6><span class=header-section-number>2.6.6</span>\n<a href=#toc:subsec:installer>Installer</a><a href=#subsec:installer class=anchor aria-hidden=true></a></h3><p>Configure the default behaviour of the installer. You can also find\nmost of the settings by clicking on the <em>cog</em> icon when you\ninstall an application.<section id=install-location class=level4 data-number=2.6.6.1><h4 data-number=2.6.6.1><span class=header-section-number>2.6.6.1</span> Install Location<a href=#install-location class=anchor aria-hidden=true></a></h4><p>Define APK installation location. This can be one of <em>auto</em>,\n<em>internal only</em> and <em>prefer external</em>. In newer Android\nversions, selecting the last option does not guarantee that the\napplication will be installed in the external storage.</section><section id=block-trackers-1 class=level4 data-number=2.6.6.2><h4 data-number=2.6.6.2><span class=header-section-number>2.6.6.2</span> Block Trackers<a href=#block-trackers-1 class=anchor aria-hidden=true></a></h4><p>Whether to block the tracking components immediately after installing\nthe application.</section><section id=display-changes class=level4 data-number=2.6.6.3><h4 data-number=2.6.6.3><span class=header-section-number>2.6.6.3</span> Display Changes<a href=#display-changes class=anchor aria-hidden=true></a></h4><p>Whether to display changes in version, trackers, components,\npermissions, signatures, SDK, etc. in a version controlled style before\ninstalling the application if the application has already been\ninstalled.</section><section id=installer-app class=level4 data-number=2.6.6.4><h4 data-number=2.6.6.4><span class=header-section-number>2.6.6.4</span> Installer App<a href=#installer-app class=anchor aria-hidden=true></a></h4><p>Select the installer application. This is useful for applications\nthat explicitly checks the installer as a way to verify if the\napplication is installed legitimately. This only works for root or ADB\nusers.<div class=\"amalert tip\"><p><strong><em>Notice.</em></strong><p>While checking for the installer might seem a legitimate concern for\nan application, the Android framework already deals with this during the\ninstallation. Checking for the installer is simply the wrong way to\nprove the legitimacy of the source of an application.</div></section><section id=sign-apk class=level4 data-number=2.6.6.5><h4 data-number=2.6.6.5><span class=header-section-number>2.6.6.5</span> Sign APK<a href=#sign-apk class=anchor aria-hidden=true></a></h4><p>Whether to sign the APK files before installing the application. A\nsigning key has to be added or generated before this option can be\nenabled. This can be done in the <a href=#subsec:apk-signing>APK\nsigning</a> page.</section><section id=immediately-perform-dex-optimization class=level4 data-number=2.6.6.6><h4 data-number=2.6.6.6><span class=header-section-number>2.6.6.6</span> Immediately Perform DEX\nOptimization<a href=#immediately-perform-dex-optimization class=anchor aria-hidden=true></a></h4><p>Whether to perform DEX optimization immediately after installing the\napplication. This can be useful for heavy applications, such as the\ngaming applications.</section><section id=install-in-the-background class=level4 data-number=2.6.6.7><h4 data-number=2.6.6.7><span class=header-section-number>2.6.6.7</span> Install in the Background<a href=#install-in-the-background class=anchor aria-hidden=true></a></h4><p>Whether to always install applications in the background. A\nnotification will be issued once the installation is finished.</section></section><section id=subsec:backup/restore class=level3 data-number=2.6.7><h3 data-number=2.6.7><span class=header-section-number>2.6.7</span>\n<a href=#toc:subsec:backup/restore>Back up/Restore</a><a href=#subsec:backup/restore class=anchor aria-hidden=true></a></h3><p>Settings related to <a href=#sec:backup-restore>back\nup/restore</a>.<section id=compression-method class=level4 data-number=2.6.7.1><h4 data-number=2.6.7.1><span class=header-section-number>2.6.7.1</span> Compression method<a href=#compression-method class=anchor aria-hidden=true></a></h4><p>Set the compression method to be used during backups. App Manager\nsupports GZip, BZip2 and Zstandard compression methods, GZip being the\ndefault compression method. It doesn’t affect the restore of an existing\nbackup.</section><section id=subsubsec:settings-backup-options class=level4 data-number=2.6.7.2><h4 data-number=2.6.7.2><span class=header-section-number>2.6.7.2</span> Backup Options<a href=#subsubsec:settings-backup-options class=anchor aria-hidden=true></a></h4><p>Customise the <em>back up/restore dialog</em> displayed while taking\na backup.<div class=seealso-inline><p><em>こちらもご覧ください: <span><a href=#subsec:backup-restore-backup-options>Backup\noptions</a></span></em></div></section><section id=backup-apps-with-android-keystore class=level4 data-number=2.6.7.3><h4 data-number=2.6.7.3><span class=header-section-number>2.6.7.3</span> Backup apps with Android\nKeyStore<a href=#backup-apps-with-android-keystore class=anchor aria-hidden=true></a></h4><p>Allow backup of applications that has entries in the Android\nKeyStore. This option is disabled by default because a few apps (such as\nSignal or Element) may crash if restored.</section><section id=subsubsec:settings-encryption class=level4 data-number=2.6.7.4><h4 data-number=2.6.7.4><span class=header-section-number>2.6.7.4</span> Encryption<a href=#subsubsec:settings-encryption class=anchor aria-hidden=true></a></h4><p>Set an encryption method for the backups. App Manager currently\nsupports OpenPGP (via <a href=https://f-droid.org/packages/org.sufficientlysecure.keychain/>OpenKeyChain</a>),\nAES, RSA and ECC. Like <a href=#subsec:apk-signing>APK signing</a>,\nThe AES, RSA and ECC keys are stored in the KeyStore and can be imported\nfrom other KeyStores.<div class=\"amalert danger\"><p><strong><em>Danger.</em></strong><p>For your own safety, it is not recommended generating RSA and ECC\nkeys inside App Manager. Instead, they should be imported from a\nKeyStore stored in a secure place.<br>In case of AES, the generated key should be stored in a secure place,\nsuch as in a password manager.</div></section><section id=subsubsec:backup-volume class=level4 data-number=2.6.7.5><h4 data-number=2.6.7.5><span class=header-section-number>2.6.7.5</span> Backup Volume<a href=#subsubsec:backup-volume class=anchor aria-hidden=true></a></h4><p>Select the storage where the backups will be stored. This is also\nwhere logs and exported APK files are saved.<div class=\"amalert tip\"><p><strong><em>Notice.</em></strong><p>The backup volume only specifies the storage, not the path. Backups\nare traditionally stored in the <code>AppManager</code> folder inside\nthe storage path. But when the path is selected using Storage Access\nFramework (SAF), the selected path or directory is used directly.</div></section><section id=import-backups class=level4 data-number=2.6.7.6><h4 data-number=2.6.7.6><span class=header-section-number>2.6.7.6</span> Import Backups<a href=#import-backups class=anchor aria-hidden=true></a></h4><p>Import backups from old and discontinued projects such as Titanium\nBackup, OAndBackup, and Swift Backup (version 3.0 to 3.2). The backups\nare not deleted after importing to prevent data loss in case the\nimported backups cannot be restored properly.</section></section><section id=subsec:rules class=level3 data-number=2.6.8><h3 data-number=2.6.8><span class=header-section-number>2.6.8</span>\n<a href=#toc:subsec:rules>Rules</a><a href=#subsec:rules class=anchor aria-hidden=true></a></h3><section id=subsubsec:instant-component-blocking class=level4 data-number=2.6.8.1><h4 data-number=2.6.8.1><span class=header-section-number>2.6.8.1</span> Instant Component\nBlocking<a href=#subsubsec:instant-component-blocking class=anchor aria-hidden=true></a></h4><p>By default, blocking rules are not applied unless they are applied\nexplicitly in <a href=#sec:app-details-page>the App Details page</a>\nfor any application. After enabling this option, all (old and new) rules\nare applied immediately for all applications without explicitly enabling\nblocking for an application.<div class=seealso-inline><p><em>こちらもご覧ください: <span><a href=#subsec:faq:what-is-instant-component-blocking>FAQ: What is\ninstant component blocking?</a></span></em></div></section><section id=importexport-blocking-rules class=level4 data-number=2.6.8.2><h4 data-number=2.6.8.2><span class=header-section-number>2.6.8.2</span> Import/Export Blocking\nRules<a href=#importexport-blocking-rules class=anchor aria-hidden=true></a></h4><p>It is possible to import or export blocking rules within App Manager\nfor all applications. The types of rules (components, app ops or\npermissions) that should be imported or exported can also be selected.\nIt is also possible to import blocking rules from <a href=https://github.com/lihenggui/blocker>Blocker</a> and <a href=https://github.com/tuyafeng/Watt>Watt</a>. If it is necessary to\nexport blocking rules for a single application, the corresponding <a href=#sec:app-details-page>App Details page</a> can be used to export\nrules, or for multiple apps, <a href=#subsec:batch-operations>batch\noperations</a> can be used.<div class=seealso-inline><p><em>こちらもご覧ください: <span><a href=#sec:rules-specification>Rules Specification</a></span></em></div><section id=export class=level5 data-number=2.6.8.2.1><h5 data-number=2.6.8.2.1><span class=header-section-number>2.6.8.2.1</span> Export<a href=#export class=anchor aria-hidden=true></a></h5><p>Export blocking rules for all applications configured within App\nManager. This may include <a href=#subsec:faq:what-are-app-components>app components</a>, app ops\nand permissions based on the options selected in the multi-choice\noptions.</section><section id=import class=level5 data-number=2.6.8.2.2><h5 data-number=2.6.8.2.2><span class=header-section-number>2.6.8.2.2</span> Import<a href=#import class=anchor aria-hidden=true></a></h5><p>Import previously exported blocking rules from App Manager. Similar\nto export, this may include <a href=#subsec:faq:what-are-app-components>app components</a>, app ops\nand permissions based on the options selected in the multi-choice\noptions.</section><section id=par:import-existing-rules class=level5 data-number=2.6.8.2.3><h5 data-number=2.6.8.2.3><span class=header-section-number>2.6.8.2.3</span> Import Existing Rules<a href=#par:import-existing-rules class=anchor aria-hidden=true></a></h5><p>Add components disabled by other applications to App Manager. App\nManager only keeps track of the components disabled within App Manager.\nIf application components are blocked or disabled by other tools or\napplications, this option can be utilised to import them. On clicking\nthis option, App Manager will find the components potentially disabled\nby other applications or tools and list only the name of the\napplications along with the number of matched components. For safety,\nall the applications are unselected by default. They have to be selected\nmanually, and the blocking has to be re-applied via App Manager.<div class=\"amalert danger\"><p><strong><em>Caution.</em></strong><p>Be careful when using this tool as there can be many false positives.\nChoose only the applications that you are certain about.</div></section><section id=import-from-watt class=level5 data-number=2.6.8.2.4><h5 data-number=2.6.8.2.4><span class=header-section-number>2.6.8.2.4</span> Import from Watt<a href=#import-from-watt class=anchor aria-hidden=true></a></h5><p>Import configuration files from <a href=https://github.com/tuyafeng/Watt>Watt</a>, each file containing\nrules for a single package and file name being the name of the package\nwith <code>.xml</code> extension.<div class=\"amalert tip\"><p><strong><em>Tip.</em></strong><p>Location of configuration files in Watt:\n<code>/sdcard/Android/data/com.tuyafeng.watt/files/ifw</code></div></section><section id=import-from-blocker class=level5 data-number=2.6.8.2.5><h5 data-number=2.6.8.2.5><span class=header-section-number>2.6.8.2.5</span> Import from Blocker<a href=#import-from-blocker class=anchor aria-hidden=true></a></h5><p>Import blocking rules from <a href=https://github.com/lihenggui/blocker>Blocker</a>, each file\ncontaining rules for a single package. These files have a\n<code>.json</code> extension.</section></section><section id=remove-all-rules class=level4 data-number=2.6.8.3><h4 data-number=2.6.8.3><span class=header-section-number>2.6.8.3</span> Remove all rules<a href=#remove-all-rules class=anchor aria-hidden=true></a></h4><p>One-click option to remove all rules configured within App Manager.\nThis will enable all blocked components, app ops will be set to their\ndefault values and permissions will be granted.</section></section><section id=subsec:advanced class=level3 data-number=2.6.9><h3 data-number=2.6.9><span class=header-section-number>2.6.9</span>\n<a href=#toc:subsec:advanced>Advanced</a><a href=#subsec:advanced class=anchor aria-hidden=true></a></h3><section id=subsubsec:selected-users class=level4 data-number=2.6.9.1><h4 data-number=2.6.9.1><span class=header-section-number>2.6.9.1</span> Selected Users<a href=#subsubsec:selected-users class=anchor aria-hidden=true></a></h4><p>This option lets you control the users App Manager should operate on.\nApp Manager operates on all users in root or ADB mode by default.</section><section id=subsubsec:saved-apk-name-format class=level4 data-number=2.6.9.2><h4 data-number=2.6.9.2><span class=header-section-number>2.6.9.2</span> Saved APK Name Format<a href=#subsubsec:saved-apk-name-format class=anchor aria-hidden=true></a></h4><p>Defines the format of the APK name to be used while saving it via\nbatch operations or through profiles. App Manager offers some special\nkeywords enclosed inside <code>%</code> (percentage) signs and available\nbelow the input box. These keywords are:<ul class=incremental><li><p><strong><code>label</code>.</strong> Denotes the name or label of\nthe application. This can be localised to the configured language\ndepending on the app.<li><p><strong><code>package_name</code>.</strong> Denotes the name of\nthe package or application ID, the unique identifier that each\napplication has.<li><p><strong><code>version</code>.</strong> Denotes the current\nversion of the application extracted from its manifest.<li><p><strong><code>version_code</code>.</strong> Denotes the current\nversion code of the application that can be used to separate two\nversions of the same application.<li><p><strong><code>min_sdk</code>.</strong> Denotes the minimum SDK\n(i.e. Android framework version) that the application can operate on.\nThis data is only available since Android 7 (Nougat).<li><p><strong><code>target_sdk</code>.</strong> Denotes the SDK that\nthis application targets. The application can operate on higher SDK but\nonly in the compatibility mode.<li><p><strong><code>datetime</code>.</strong> Denotes the time and date\nwhen the APK is exported.</ul></section><section id=subsubsec:import/export-keystore class=level4 data-number=2.6.9.3><h4 data-number=2.6.9.3><span class=header-section-number>2.6.9.3</span> Import/Export Keystore<a href=#subsubsec:import/export-keystore class=anchor aria-hidden=true></a></h4><p>Import or export the KeyStore used by App Manager. This is a Bouncy\nCastle KeyStore with <code>bks</code> extension. Therefore, other\nKeyStore such as Java KeyStore (JKS) or PKCS #12 are not supported. If a\nkey is needed to be imported from such a KeyStore, the relevant options\nshould be should as specified above.</section></section><section id=subsec:device-info class=level3 data-number=2.6.10><h3 data-number=2.6.10><span class=header-section-number>2.6.10</span> <a href=#toc:subsec:device-info>About the device</a><a href=#subsec:device-info class=anchor aria-hidden=true></a></h3><p>Display Android version, security, CPU, GPU, battery, memory, screen,\nlanguages, user info, etc.</section></section><section id=sec:scanner-page class=level2 data-number=2.7><h2 data-number=2.7><span class=header-section-number>2.7</span> <a href=#toc:sec:scanner-page>Scanner Page</a><a href=#sec:scanner-page class=anchor aria-hidden=true></a></h2><p><strong>Scanner page</strong> appears after clicking on the\n<em>scanner</em> button in the <a href=#subsec:app-info-tab>App Info\ntab</a>. External APK files can also be opened for scanning from file\nmanagers, web browsers, etc.<p>It scans for trackers and libraries, and displays the number of\ntrackers and libraries as a summary. It also displays checksums of the\nAPK file as well as the signing certificates. If VirusTotal is\nconfigured in the settings, it also attempts to retrieve reports from\nVirusTotal, or uploads the APK file if it is not in the database. It\nalso display a link to the <a href=https://beta.pithus.org>Pithus</a>\nreport provided the Internet features are enabled.<div class=\"amalert danger\"><p><strong><em>Disclaimer.</em></strong><p>App Manager only scans an application statically without prejudice.\nThe application may provide the options for opting out, or in some\ncases, certain features of the tracker may not be used at all by the\napplication (e.g. F-Droid), or some applications may simply use them as\nplaceholders to prevent the breaking of certain features (e.g. Fennec\nF-Droid). <strong>The intention of the scanner is to give you an idea\nabout what the APK might contain. It should be taken as an initial step\nfor further investigations.</strong></div><p>Clicking on the first item (i.e. number of classes) opens a new page\ncontaining a list of tracker classes for the application. All classes\ncan also be viewed by clicking on the <em>Toggle Class Listing</em>\nmenu. The SMALI or Java version of the class can be viewed by simply\nclicking on an item.<div class=\"amalert tip\"><p><strong><em>Notice.</em></strong><p>Due to various limitations, it is not possible to scan all the\ncomponents of an APK file. This is especially true if an APK is highly\nobfuscated or packed. The scanner also does not check strings (or\nwebsite signatures).</div><p>The second item lists the number of trackers along with their names.\nClicking on the item displays a dialog containing the name of trackers,\nmatched signatures, and the number of classes against each signature.\nSome tracker names may have <span class=\"math inline\"><sup>2</sup></span> prefix which indicates that the\ntrackers are in the <a href=https://etip.exodus-privacy.eu.org>ETIP</a> stand-by list, i.e.,\nwhether they are actual trackers is still being investigated.<p>The third item lists the number of libraries along with their names.\nThe information are mostly taken from <a href=https://gitlab.com/IzzyOnDroid/repo>IzzyOnDroid repo</a>.<div class=seealso-inline><p><em>こちらもご覧ください: <span><a href=#subsec:tracker-classes-versus-tracker-components>FAQ: Tracker\nclasses vs tracker components</a></span></em></div></section><section id=sec:interceptor-page class=level2 data-number=2.8><h2 data-number=2.8><span class=header-section-number>2.8</span> <a href=#toc:sec:interceptor-page>Interceptor Page</a><a href=#sec:interceptor-page class=anchor aria-hidden=true></a></h2><p>Interceptor can be used to intercept communication between\napplications using <code>Intent</code>. It works as a man-in-the-middle\nbetween the source and the destination applications. It offers a\nfeature-complete user interface for editing <code>Intent</code>s.<div class=\"amalert warning\"><p><strong><em>Warning.</em></strong><p>Interceptor only works for <em>implicit</em> intents where the <a href=#subsec:faq:what-are-app-components>app component</a> isn’t\nspecified.</div><div class=seealso><p><em>こちらもご覧ください:</em><ul class=incremental><li><p><a href=https://developer.android.com/guide/components/intents-common>Common\nIntents</a><li><p><a href=https://developer.android.com/guide/components/intents-filters>Intents\nand Intent Filters</a></ul></div><section id=subsec:intent-filters class=level3 data-number=2.8.1><h3 data-number=2.8.1><span class=header-section-number>2.8.1</span>\n<a href=#toc:subsec:intent-filters>Intent Filters</a><a href=#subsec:intent-filters class=anchor aria-hidden=true></a></h3><p>Intent filters are used by the applications to specify the tasks they\nare able to perform or the tasks they are going to perform using other\napplications. For example, when you’re opening a PDF file using a file\nmanager, the file manager will try to find the applications to open the\nPDF with. To find the right applications, the file manager will create\nan Intent with filters such as the MIME type and ask the system to\nretrieve the applications capable of opening this filter. The system\nwill search through the Manifest of the installed applications to match\nthe filter and list the application components that are able to open\nthis filter (in our case the PDF). At this, either the file manager will\nopen the desired application component all by itself or use a system\nprovided option to open it. If multiple application components are able\nto open it and no default is set, you may get a prompt where you have to\nchoose the right application component.<section id=subsubsec:action class=level4 data-number=2.8.1.1><h4 data-number=2.8.1.1><span class=header-section-number>2.8.1.1</span> Action<a href=#subsubsec:action class=anchor aria-hidden=true></a></h4><p>Action specifies the generic action to perform such as\n<code>android.intent.action.VIEW</code>. Applications often declare the\nrelevant actions in the Manifest file to catch the desired Intents. The\naction is particularly useful for broadcast Intent where it plays a\nvital rule. In other cases, it works as an initial way to filter out the\nrelevant application components. Generic actions such as\n<code>android.intent.action.VIEW</code> and\n<code>android.intent.action.SEND</code> are widely used by applications.\nHence, setting this alone may match many application components.</section><section id=subsubsec:data class=level4 data-number=2.8.1.2><h4 data-number=2.8.1.2><span class=header-section-number>2.8.1.2</span> Data<a href=#subsubsec:data class=anchor aria-hidden=true></a></h4><p>Data is originally known as URI (Uniform Resource Identifier) defined\nin <a href=http://www.faqs.org/rfcs/rfc2396.html>RFC 2396</a>. It can\nbe web links, file location, or a special feature called\n<em>content</em>. Contents are an Android feature managed by the <a href=#subsubsec:providers>content providers</a>. Data are often\nassociated with a <a href=#subsubsec:mime-type>MIME type</a>.<p>Examples:<pre><code>http://search.disroot.org/?q=URI%20in%20Android%20scheme&amp;categories=general&amp;language=en-US\nhttps://developer.android.com/reference/android/net/Uri\nfile:///sdcard/AppManager.apk\nmailto:email@example.com\ncontent://io.github.muntashirakon.AppManager.provider/23485af89b08d87e898a90c7e/AppManager.apk</code></pre></section><section id=subsubsec:mime-type class=level4 data-number=2.8.1.3><h4 data-number=2.8.1.3><span class=header-section-number>2.8.1.3</span> MIME Type<a href=#subsubsec:mime-type class=anchor aria-hidden=true></a></h4><p>MIME type of the <a href=#subsubsec:data>data</a>. For example, if\nthe data field is set to <code>file:///sdcard/AppManager.apk</code>, the\nassociated MIME type can be\n<code>application/vnd.android.package-archive</code>.</section><section id=categories class=level4 data-number=2.8.1.4><h4 data-number=2.8.1.4><span class=header-section-number>2.8.1.4</span> Categories<a href=#categories class=anchor aria-hidden=true></a></h4><p>This is similar to <a href=#subsubsec:action>action</a> in the\nsense that it is also used by the system to filter application\ncomponents. This has no further benefits. Unlike <em>action</em>, there\ncan be more than one category. Clicking on the <em>plus</em> button next\nto the title allows adding more categories.</section><section id=flags class=level4 data-number=2.8.1.5><h4 data-number=2.8.1.5><span class=header-section-number>2.8.1.5</span> Flags<a href=#flags class=anchor aria-hidden=true></a></h4><p>Flags are useful in determining how system should behave during the\nlaunch or after the launch of an activity. This should not be touched as\nit requires some technical background. The <em>plus</em> button next to\nthe title can be used to add one or more flags.</section><section id=extras class=level4 data-number=2.8.1.6><h4 data-number=2.8.1.6><span class=header-section-number>2.8.1.6</span> Extras<a href=#extras class=anchor aria-hidden=true></a></h4><p>Extras are the key-value pairs used for supplying additional\ninformation to the destination component. More extras can be added using\nthe <em>plus</em> button next to the title.</section><section id=uri class=level4 data-number=2.8.1.7><h4 data-number=2.8.1.7><span class=header-section-number>2.8.1.7</span> URI<a href=#uri class=anchor aria-hidden=true></a></h4><p>Represents the entire Intent as a URI (e.g. <code>intent://…</code>).\nSome data cannot be converted to string, and as a result, they might not\nappear here.</section></section><section id=subsec:matching-activities class=level3 data-number=2.8.2><h3 data-number=2.8.2><span class=header-section-number>2.8.2</span>\n<a href=#toc:subsec:matching-activities>Matching Activities</a><a href=#subsec:matching-activities class=anchor aria-hidden=true></a></h3><p>List all the activity components that matches the Intent. This is\ninternally determined by the system (rather than App Manager). The\nlaunch button next to each component can be used to launch them directly\nfrom App Manager.</section><section id=subsec:interceptor-reset-to-default class=level3 data-number=2.8.3><h3 data-number=2.8.3><span class=header-section-number>2.8.3</span>\n<a href=#toc:subsec:interceptor-reset-to-default>Reset to\nDefault</a><a href=#subsec:interceptor-reset-to-default class=anchor aria-hidden=true></a></h3><p>Reset the Intent to its initial state.</section><section id=subsec:interceptor-send-edited-intent class=level3 data-number=2.8.4><h3 data-number=2.8.4><span class=header-section-number>2.8.4</span>\n<a href=#toc:subsec:interceptor-send-edited-intent>Send Edited\nIntent</a><a href=#subsec:interceptor-send-edited-intent class=anchor aria-hidden=true></a></h3><p>Resend the edited Intent to the destination application. This may\nopen a list of applications where the desired application is needed to\nbe selected. The result received from the target application will be\nsent to the source application. As a result, the source application will\nnot know if there was a man-in-the-middle.</section></section><section id=sec:shared-preferences-editor-page class=level2 data-number=2.9><h2 data-number=2.9><span class=header-section-number>2.9</span> <a href=#toc:sec:shared-preferences-editor-page>Shared Preferences Editor\nPage</a><a href=#sec:shared-preferences-editor-page class=anchor aria-hidden=true></a></h2><p>Shared preferences can be edited in this page. Clicking any item on\nthe list opens the edit dialog where the item can be edited. The\nfloating action button in the bottom-right corner can be used to add a\nnew item. To save or delete the file, or to discard current changes, the\nrespective options in the menu can be used.</section></section><section id=ch:guides class=level1 data-number=3><h1 data-number=3><span class=header-section-number>3</span> <a href=#toc:ch:guides>Guides</a><a href=#ch:guides class=anchor aria-hidden=true></a></h1><section id=sec:adb-over-tcp class=level2 data-number=3.1><h2 data-number=3.1><span class=header-section-number>3.1</span> <a href=#toc:sec:adb-over-tcp>ADB over TCP</a><a href=#sec:adb-over-tcp class=anchor aria-hidden=true></a></h2><p>Many root-only features can still be used by enabling ADB over TCP.\nTo do that, a PC or Mac is required with Android platform-tools\ninstalled, and an Android phone with developer options & USB\ndebugging enabled.<div class=\"amalert tip\"><p><strong><em>Root users.</em></strong><p>If superuser permission has been granted to App Manager, it can\nalready execute privileged code without any problem. <strong>Therefore,\nroot users do not need to enable ADB over TCP.</strong> But if you\ninsist on using ADB over TCP, you must revoke superuser permission for\nApp Manager.</div><div class=seealso-inline><p><em>こちらもご覧ください: <span><a href=#sec:faq:adb-over-tcp>FAQ:\nADB over TCP</a></span></em></div><section id=subsec:enable-developer-options class=level3 data-number=3.1.1><h3 data-number=3.1.1><span class=header-section-number>3.1.1</span>\n<a href=#toc:subsec:enable-developer-options>Enable developer\noptions</a><a href=#subsec:enable-developer-options class=anchor aria-hidden=true></a></h3><section id=subsubsec:location-of-developer-options class=level4 data-number=3.1.1.1><h4 data-number=3.1.1.1><span class=header-section-number>3.1.1.1</span> Location of developer\noptions<a href=#subsubsec:location-of-developer-options class=anchor aria-hidden=true></a></h4><p><strong>Developer options</strong> is located in Android\n<strong>Settings</strong>, either directly near the bottom of the page\n(in most ROMs) or under some other settings, such as\n<strong>System</strong> (Google Pixel, Lineage OS, Asus Zenfone 8.0+),\n<strong>Additional Settings</strong> (Xiaomi MIUI, Oppo ColorOS),\n<strong>More Settings</strong> (Vivo FuntouchOS), <strong>More</strong>\n(ZTE Nubia). Unlike other options, it is not visible until explicitly\nenabled by the user. If it is already enabled, you can use the search\nbox in Android <strong>Settings</strong> to locate it as well.</section><section id=how-to-enable-developer-options class=level4 data-number=3.1.1.2><h4 data-number=3.1.1.2><span class=header-section-number>3.1.1.2</span> How to enable developer\noptions<a href=#how-to-enable-developer-options class=anchor aria-hidden=true></a></h4><p>This option is available within Android <strong>Settings</strong> as\nwell but like the location of the developer options, it also differs\nfrom device to device. But in general, you have to find <strong>Build\nnumber</strong> (or <strong>MIUI version</strong> for MIUI ROMs and\n<strong>Software version</strong> for Vivo FuntouchOS,\n<strong>Version</strong> for Oppo ColorOS) and tap it at least 7 (seven)\ntimes until you finally get a message saying <em>You are now a\ndeveloper</em> (you may be prompted to insert pin/password/pattern or\nsolve captchas at this point). In most devices, it is located at the\nbottom of the settings page, inside <strong>About Phone</strong>. But\nthe best way to find it is to use the search box.</section></section><section id=subsec:enable-usb-debugging class=level3 data-number=3.1.2><h3 data-number=3.1.2><span class=header-section-number>3.1.2</span>\n<a href=#toc:subsec:enable-usb-debugging>Enable USB debugging</a><a href=#subsec:enable-usb-debugging class=anchor aria-hidden=true></a></h3><p>After <a href=#subsubsec:location-of-developer-options>locating the\ndeveloper options</a>, enable <strong>Developer option</strong> (if not\nalready). After that, scroll down a bit until you will find the option\n<strong>USB debugging</strong>. Use the toggle button on the right-hand\nside to enable it. At this point, you may get an alert prompt where you\nmay have to click <em>OK</em> to actually enable it. You may also have\nto enable some other options depending on device vendor and ROM. Here\nare some examples:<section id=xiaomi-miui class=level4 data-number=3.1.2.1><h4 data-number=3.1.2.1><span class=header-section-number>3.1.2.1</span> Xiaomi (MIUI)<a href=#xiaomi-miui class=anchor aria-hidden=true></a></h4><p>Enable <strong>USB debugging (Security settings)</strong> as\nwell.</section><section id=huawei-emui class=level4 data-number=3.1.2.2><h4 data-number=3.1.2.2><span class=header-section-number>3.1.2.2</span> Huawei (EMUI)<a href=#huawei-emui class=anchor aria-hidden=true></a></h4><p>Enable <strong>Allow ADB debugging in charge only mode</strong> as\nwell. When connecting to your PC or Mac, you may get a prompt saying\n<strong>Allow access to device data?</strong> in which case click\n<strong>YES, ALLOW ACCESS</strong>.<div class=\"amalert tip\"><p><strong><em>Notice.</em></strong><p>Often the <strong>USB debugging</strong> mode could be disabled\nautomatically by the system. If that’s the case, repeat the above\nprocedure.</div></section><section id=realme class=level4 data-number=3.1.2.3><h4 data-number=3.1.2.3><span class=header-section-number>3.1.2.3</span> Realme<a href=#realme class=anchor aria-hidden=true></a></h4><p>Depending on the device and the version of operating system, you have\nto enable <strong>Disable Permission Monitoring</strong>, or <strong>USB\ndebugging (Security settings)</strong> along with <strong>Install via\nUSB</strong>.</section><section id=oneplus-oxygen-os class=level4 data-number=3.1.2.4><h4 data-number=3.1.2.4><span class=header-section-number>3.1.2.4</span> OnePlus (Oxygen OS)<a href=#oneplus-oxygen-os class=anchor aria-hidden=true></a></h4><p>Depending on the device and the version of operating system, you have\nto enable <strong>Disable Permission Monitoring</strong>.</section><section id=lg class=level4 data-number=3.1.2.5><h4 data-number=3.1.2.5><span class=header-section-number>3.1.2.5</span> LG<a href=#lg class=anchor aria-hidden=true></a></h4><p>Make sure you have <strong>USB tethering</strong> enabled.</section><section id=troubleshooting class=level4 data-number=3.1.2.6><h4 data-number=3.1.2.6><span class=header-section-number>3.1.2.6</span> Troubleshooting<a href=#troubleshooting class=anchor aria-hidden=true></a></h4><p>In case <strong>USB Debugging</strong> is greyed out, you can do the\nfollowing:<ol class=incremental><li><p>Make sure you enabled USB debugging before connecting your phone\nto the PC or Mac via USB cable<li><p>Enable USB tethering after connecting to PC or Mac via USB\ncable<li><p>(For Samsung) If your device is running KNOX, you may have to\nfollow some additional steps. See official documentations or consult\nsupport for further assistant</ol></section></section><section id=subsec:setup-adb-on-pc-or-mac class=level3 data-number=3.1.3><h3 data-number=3.1.3><span class=header-section-number>3.1.3</span>\n<a href=#toc:subsec:setup-adb-on-pc-or-mac>Setup ADB on PC or\nMac</a><a href=#subsec:setup-adb-on-pc-or-mac class=anchor aria-hidden=true></a></h3><p>In order to enable ADB over TCP, you have to set up ADB in your PC or\nMac. <strong><em>Lineage OS users can skip to §<a href=#subsubsec:lineage-os data-reference-type=ref data-reference=subsubsec:lineage-os>3.1.4.1</a>.</em></strong><section id=windows class=level4 data-number=3.1.3.1><h4 data-number=3.1.3.1><span class=header-section-number>3.1.3.1</span> Windows<a href=#windows class=anchor aria-hidden=true></a></h4><ol class=incremental><li><p>Download the latest version of <a href=https://dl.google.com/android/repository/platform-tools-latest-windows.zip>Android\nSDK Platform-Tools</a> for Windows<li><p>Extract the contents of the zip file into any directory (such as\n<code>C:\\</code><span><code>adb</code></span>) and navigate to that\ndirectory using <em>Explorer</em><li><p>Open <strong>Command Prompt</strong>,\n<strong>PowerShell</strong>, or <strong>Terminal</strong> from this\ndirectory. You can do it manually from the start menu or by holding\n<code>Shift</code> and right clicking within the directory in <em>File\nExplorer</em> and then clicking either on <em>Open command window\nhere</em>, or <em>Open PowerShell window here</em> (depending on what\nyou have installed). You can now access ADB by typing <code>adb</code>\n(Command Prompt) or <code>./adb</code> (PowerShell). Do not close this\nwindow yet.</ol><div class=\"amalert tip\"><p><strong><em>Tip.</em></strong><p>If you have <a href=https://learn.microsoft.com/en-us/windows/package-manager/winget/>WinGet</a>\ninstalled, you can install ADB using the following command:<div class=sourceCode id=cb3 data-frame=lines><pre class=\"sourceCode bash\"><code class=\"sourceCode bash\"><span id=cb3-1><a href=#cb3-1 aria-hidden=true tabindex=-1></a><span class=ex>winget</span> install <span class=at>--id</span> Google.PlatformTools</span></code></pre></div><p>After that, you can simply type <code>adb</code> to access ADB.</div></section><section id=macos class=level4 data-number=3.1.3.2><h4 data-number=3.1.3.2><span class=header-section-number>3.1.3.2</span> macOS<a href=#macos class=anchor aria-hidden=true></a></h4><ol class=incremental><li><p>Download the latest version of <a href=https://dl.google.com/android/repository/platform-tools-latest-darwin.zip>Android\nSDK Platform-Tools</a> for macOS<li><p>Extract the contents of the zip file into a directory by clicking\non it. After that, navigate to that directory using <em>Finder</em> and\nlocate <code>adb</code><li><p>Open <strong>Terminal</strong> using <em>Launchpad</em> or\n<em>Spotlight</em> and drag-and-drop <code>adb</code> from the\n<em>Finder</em> window into the <em>Terminal</em> window. Do not close\nthe <em>Terminal</em> window yet</ol><div class=\"amalert tip\"><p><strong><em>Tip.</em></strong><p>If you have <a href=https://brew.sh>Homebrew</a> installed, you can\ninstall ADB using the following command:<div class=sourceCode id=cb4 data-frame=lines><pre class=\"sourceCode bash\"><code class=\"sourceCode bash\"><span id=cb4-1><a href=#cb4-1 aria-hidden=true tabindex=-1></a><span class=ex>brew</span> install <span class=at>--cask</span> android-platform-tools</span></code></pre></div><p>After that, you can simply type <code>adb</code> in any\n<em>Terminal</em> window to access ADB.</div></section><section id=linux class=level4 data-number=3.1.3.3><h4 data-number=3.1.3.3><span class=header-section-number>3.1.3.3</span> Linux<a href=#linux class=anchor aria-hidden=true></a></h4><ol class=incremental><li><p>In your favourite terminal emulator, run the following\ncommand:<div class=sourceCode id=cb5 data-frame=lines data-autogobble><pre class=\"sourceCode bash\"><code class=\"sourceCode bash\"><span id=cb5-1><a href=#cb5-1 aria-hidden=true tabindex=-1></a><span class=bu>cd</span> ~/Downloads <span class=kw>&amp;&amp;</span> <span class=ex>curl</span> <span class=at>-o</span> platform-tools.zip <span class=at>-L</span> <span class=dt>\\</span></span>\n<span id=cb5-2><a href=#cb5-2 aria-hidden=true tabindex=-1></a>https://dl.google.com/android/repository/platform-tools-latest-linux.zip <span class=kw>&amp;&amp;</span> <span class=dt>\\</span></span>\n<span id=cb5-3><a href=#cb5-3 aria-hidden=true tabindex=-1></a><span class=fu>unzip</span> platform-tools.zip <span class=kw>&amp;&amp;</span> <span class=fu>rm</span> platform-tools.zip <span class=kw>&amp;&amp;</span> <span class=bu>cd</span> platform-tools</span></code></pre></div><li><p>If it is successful, you can simply type <code>./adb</code> in\nthe in <em>same</em> terminal emulator window or type\n<code>~/Downloads/platform-tools/adb</code> in any terminal emulator to\naccess ADB.</ol></section></section><section id=subsec:configure-adb-over-tcp class=level3 data-number=3.1.4><h3 data-number=3.1.4><span class=header-section-number>3.1.4</span>\n<a href=#toc:subsec:configure-adb-over-tcp>Configure ADB over\nTCP</a><a href=#subsec:configure-adb-over-tcp class=anchor aria-hidden=true></a></h3><section id=subsubsec:lineage-os class=level4 data-number=3.1.4.1><h4 data-number=3.1.4.1><span class=header-section-number>3.1.4.1</span> Lineage OS 17.1 and\nEarlier<a href=#subsubsec:lineage-os class=anchor aria-hidden=true></a></h4><p>Lineage OS (or its derivatives) users can directly enable ADB over\nTCP using the developer options. To enable that, go to the\n<strong>Developer options</strong>, scroll down until you find\n<strong>ADB over Network</strong>. Now, use the toggle button on the\nright-hand side to enable it and skip to §<a href=#subsubsec:adb-mode-in-app-manager data-reference-type=ref data-reference=subsubsec:adb-mode-in-app-manager>3.1.4.3</a>.<div class=\"amalert warning\"><p><strong><em>Warning.</em></strong><p>You can turn off <strong>ADB over Network</strong> in developer\noptions, but turning off this option will also stop App Manager’s remote\nserver. So, turn it off only when you’re not going to use App Manager in\nADB over TCP mode.</div></section><section id=subsubsec:enable-adb-over-tcp-via-pc-or-mac class=level4 data-number=3.1.4.2><h4 data-number=3.1.4.2><span class=header-section-number>3.1.4.2</span> Enable ADB over TCP via PC\nor Mac<a href=#subsubsec:enable-adb-over-tcp-via-pc-or-mac class=anchor aria-hidden=true></a></h4><p>For other ROMs, you can do this using the command\nprompt/PowerShell/terminal emulator that you’ve opened in the step 3 of\nthe previous section. In this section, I will use <code>adb</code> to\ndenote <code>./adb</code>, <code>adb</code> or any other command that\nyou needed to use based on your platform and software in the previous\nsection.<ol class=incremental><li><p>Connect your device to your PC or Mac using a USB cable. For some\ndevices, it is necessary to turn on <em>File transfer mode (MTP)</em> as\nwell<li><p>To confirm that everything is working as expected, type\n<code>adb devices</code> in your terminal. If your device is connected\nsuccessfully, you will see something like this:<pre><code>List of devices attached\nxxxxxxxx  device</code></pre><div class=\"amalert tip\"><p><strong><em>Notice.</em></strong><p>In some Android phones, an alert prompt will be appeared with a\nmessage <strong>Allow USB Debugging</strong> in which case, check\n<em>Always allow from this computer</em> and click\n<strong>Allow</strong>.</div><li><p>Finally, run the following command to enable ADB over TCP:<div class=sourceCode id=cb7 data-frame=lines data-autogobble><pre class=\"sourceCode bash\"><code class=\"sourceCode bash\"><span id=cb7-1><a href=#cb7-1 aria-hidden=true tabindex=-1></a><span class=ex>adb</span> tcpip 5555</span></code></pre></div></ol><div class=\"amalert danger\"><p><strong><em>Danger.</em></strong><p>You cannot disable developer options or USB debugging after enabling\nADB over TCP.</div></section><section id=subsubsec:adb-mode-in-app-manager class=level4 data-number=3.1.4.3><h4 data-number=3.1.4.3><span class=header-section-number>3.1.4.3</span> Enable ADB mode in App\nManager<a href=#subsubsec:adb-mode-in-app-manager class=anchor aria-hidden=true></a></h4><p>After enabling ADB over TCP, relaunch App Manager. App Manager should\ndetect ADB mode automatically. If it cannot, you can change the mode of\noperation to ADB over TCP in the <a href=#subsec:mode-of-operation>settings page</a>. There, you can also\nverify whether App Manager has correctly detected ADB as indicated by\nthe <em>inferred mode</em>.<div class=\"amalert tip\"><p><strong><em>Notice.</em></strong><p>In some Android devices, the USB cable is needed to be disconnected\nfrom the PC before connecting to App Manager.</div><div class=\"amalert warning\"><p><strong><em>Warning.</em></strong><p>ADB over TCP will be disabled after a reboot. In that case, you have\nto follow §<a href=#subsubsec:enable-adb-over-tcp-via-pc-or-mac data-reference-type=ref data-reference=subsubsec:enable-adb-over-tcp-via-pc-or-mac>3.1.4.2</a>\nagain.</div></section></section></section><section id=sec:wireless-debugging class=level2 data-number=3.2><h2 data-number=3.2><span class=header-section-number>3.2</span> <a href=#toc:sec:wireless-debugging>Wireless Debugging</a><a href=#sec:wireless-debugging class=anchor aria-hidden=true></a></h2><p>If you are running Android 11 or later and capable of connecting to a\nWi-Fi network for, at least, a few moments, Wireless Debugging is the\nrecommended approach as it offers more protection than <a href=#sec:adb-over-tcp>ADB over TCP</a>. It requires two steps:<ol class=incremental><li><p><strong>ADB pairing.</strong> The initial and a bit complex step\nfor a novice user. Fortunately, this step is not required all the\ntime.<li><p><strong>Connecting to ADB.</strong> Needs to be done every time\nyou reboot your phone. App Manager can also automate this step in most\ndevices.</ol><section id=subsec:enable-developer-options-and-usb-debugging class=level3 data-number=3.2.1><h3 data-number=3.2.1><span class=header-section-number>3.2.1</span>\n<a href=#toc:subsec:enable-developer-options-and-usb-debugging>Enable\ndeveloper options and USB Debugging</a><a href=#subsec:enable-developer-options-and-usb-debugging class=anchor aria-hidden=true></a></h3><p>See §<a href=#subsec:enable-developer-options data-reference-type=ref data-reference=subsec:enable-developer-options>3.1.1</a> and §<a href=#subsec:enable-usb-debugging data-reference-type=ref data-reference=subsec:enable-usb-debugging>3.1.2</a>.</section><section id=subsec:enable-wireless-debugging class=level3 data-number=3.2.2><h3 data-number=3.2.2><span class=header-section-number>3.2.2</span>\n<a href=#toc:subsec:enable-wireless-debugging>Enable Wireless\nDebugging</a><a href=#subsec:enable-wireless-debugging class=anchor aria-hidden=true></a></h3><p>In the <strong>Developer options</strong> page, find <strong>Wireless\ndebugging</strong> and click to open it. In the new page, turn on\n<em>Use wireless debugging</em>. Depending on the operating system, you\nmight see a dialog prompt asking you to verify your decision. If that is\nthe case, click <em>Allow</em>.<div class=\"amalert tip\"><p><strong><em>Tip.</em></strong><p>For easy access, you might want to add <strong>Wireless\ndebugging</strong> in the notification tiles section. To do this, find\n<strong>Quick settings developer tiles</strong> in the <strong>Developer\noptions</strong> page and click to open it. In the new window, enable\n<em>Wireless debugging</em>. In case you do not see this setting, you\nmay find a <strong>Wireless debugging</strong> tile in the tile\ncustomization panel.</div></section><section id=subsec:pair-adb-with-app-manager class=level3 data-number=3.2.3><h3 data-number=3.2.3><span class=header-section-number>3.2.3</span>\n<a href=#toc:subsec:pair-adb-with-app-manager>Pair ADB with App\nManager</a><a href=#subsec:pair-adb-with-app-manager class=anchor aria-hidden=true></a></h3><p>In App Manager, navigate to <strong>Settings</strong> > <a href=#subsec:mode-of-operation>Mode of operation</a> and then enable\n<em>Wireless debugging</em>. At this, App Manager will try to establish\na wireless debugging connection automatically which will fail if it has\nnot been paired before. Once it fails, it will ask you to either connect\nor pair ADB. Select <em>pair</em> and a new dialog will appear. It will\nask you to navigate to the <strong>Wireless debugging</strong> page.<div class=\"amalert tip\"><p><strong><em>Note.</em></strong><p>As of v4.0.0, pairing is done using a notification prompt. So, if you\nhave disabled notification for App Manager, you must enable it\nfirst.</div><p>In the <strong>Wireless debugging</strong> page, select <strong>Pair\ndevice with pairing code</strong>. At this, a dialog containing a\npairing code will be displayed. A notification asking for the pairing\ncode will also be visible almost instantly. Insert the pairing code in\nthe input box in the notification and click <em>pair</em>. If the\npairing is successful, App Manager will display notification with the\nmessage “paired”, and the dialog in the <strong>Wireless\ndebugging</strong> page will be dismissed automatically. You will also\nbe able to see App Manager listed as an ADB client in the same page.<div class=\"amalert tip\"><p><strong><em>Notice.</em></strong><p>If you do not use App Manager in ADB mode for a while, App Manager\nmight be removed from the list of clients. In that case, you have to\nrepeat the above procedure.</div></section><section id=subsec:connect-app-manager-to-adb class=level3 data-number=3.2.4><h3 data-number=3.2.4><span class=header-section-number>3.2.4</span>\n<a href=#toc:subsec:connect-app-manager-to-adb>Connect App Manager to\nADB</a><a href=#subsec:connect-app-manager-to-adb class=anchor aria-hidden=true></a></h3><p>App Manager should be able to connect to ADB automatically if the\nmode of operation is set to <em>auto</em>, <em>ADB over TCP</em> or\n<em>Wireless debugging</em>. If this is not the case, select\n<em>Wireless debugging</em> in <strong>Settings</strong> > <a href=#subsec:mode-of-operation>Mode of operation</a>. If App Manager\nfails to detect or connect to ADB, it will ask you to connect or pair\nADB. Select <em>connect</em>.<p>Now, navigate to the <strong>Wireless debugging</strong> page in\nAndroid settings, and note down the port number displayed in the page.\nIn App Manager’s dialog prompt, replace the port number with the one you\nhave noted earlier, and click <em>connect</em>.<p>Once a connection has been established, you can disable\n<strong>Wireless debugging</strong> in Android settings.<div class=\"amalert danger\"><p><strong><em>Caution.</em></strong><p>Never disable <strong>USB Debugging</strong> or any other additional\noptions described in §<a href=#subsec:enable-developer-options-and-usb-debugging data-reference-type=ref data-reference=subsec:enable-developer-options-and-usb-debugging>3.2.1</a>.\nIf you do this, the remote server used by App Manager will be stopped,\nand you may have to start all over again.</div></section></section><section id=sec:backup-restore class=level2 data-number=3.3><h2 data-number=3.3><span class=header-section-number>3.3</span> <a href=#toc:sec:backup-restore>Back up/Restore</a><a href=#sec:backup-restore class=anchor aria-hidden=true></a></h2><p>App Manager has a modern, advanced and easy-to-use backup/restore\nsystem implemented from the scratch. This is probably the only app that\nhas the ability to restore not only the app or its data but also\npermissions and rules that you’ve configured within App Manager. You can\nalso choose to back up an app multiple times (with custom names) or for\nall users.<div class=seealso><p><em>こちらもご覧ください:</em><ul class=incremental><li><p><a href=#subsec:1-click-back-up>1-Click Ops: Back\nup</a><li><p><a href=#subsec:1-click-restore>1-Click Ops:\nRestore</a></ul></div><section id=subsec:backup-location class=level3 data-number=3.3.1><h3 data-number=3.3.1><span class=header-section-number>3.3.1</span>\n<a href=#toc:subsec:backup-location>Location</a><a href=#subsec:backup-location class=anchor aria-hidden=true></a></h3><p>Back up/restore is a part of <a href=#subsec:batch-operations>batch\noperations</a>. It is also located inside the <a href=#subsubsec:app-info-options-menu>options menu</a> in the <a href=#subsec:app-info-tab>App Info tab</a>. Clicking on\n<strong>Backup/Restore</strong> opens the <strong>Backup\nOptions</strong>. Backups are located at\n<code>/storage/emulated/0/AppManager</code> by default. You can\nconfigure custom backup location in the <a href=#subsubsec:backup-volume>settings page</a> in which case the\nbackups will be located at the <code>AppManager</code> folder in the\nselected volume.<div class=\"amalert tip\"><p><strong><em>Note.</em></strong><p>If one or more selected apps do not have any backup, the\n<strong>Restore</strong> and <strong>Delete Backup</strong> options will\nnot be displayed.</div></section><section id=subsec:backup-restore-backup-options class=level3 data-number=3.3.2><h3 data-number=3.3.2><span class=header-section-number>3.3.2</span>\n<a href=#toc:subsec:backup-restore-backup-options>Backup Options</a><a href=#subsec:backup-restore-backup-options class=anchor aria-hidden=true></a></h3><p>Backup options (internally known as backup flags) let you customise\nthe backups on the fly. However, the customisations will not be\nremembered for the future backups. If you want to customise this dialog,\nuse <a href=#subsubsec:settings-backup-options>Backup Options</a> in\nthe <a href=#sec:settings-page>Settings page</a>.<p>A complete description of the backup options is given below:<ul class=incremental><li><p><strong>APK files.</strong> Whether to back up the APK files.\nThis includes the <em>base APK</em> file along with the\n<code>split APK</code> files if they exist.<li><p><strong>Internal data.</strong> Whether to back up the internal\ndata directories. These directories are located at\n<code>/data/user/&lt;user_id></code> and (for Android N or later)\n<code>/data/user_de/&lt;user_id></code>.<li><p><strong>External data.</strong> Whether to back up data\ndirectories located in the internal memory as well as SD Card (if\nexists). External data directories often contain non-essential app data\nor media files (instead of using the dedicated media folder) and may\nincrease the backup size. However, it might be essential for some apps.\nAlthough it isn’t checked by default (as it might dramatically increase\nthe size of the backups), you may have to check it in order to ensure a\nsmooth restore of your backups.<div class=\"amalert warning\"><p><strong><em>Caution.</em></strong><p>Internal data folders should always be backed up if you are going to\nback up the external data folders. However, it could be useful to back\nup only the external folders if the app in question downloads a lot of\nassets from the Internet.</div><li><p><strong>OBB and media.</strong> Whether to back up or restore the\nOBB and the media directories located in the external storage or the SD\nCard. This is useful for games and the graphical software which actually\nuse these folders.<li><p><strong>Cache.</strong> Android apps have multiple cache\ndirectories located at every data directories (both internal and\nexternal). There are two types of cache: <strong>cache</strong> and\n<strong>code cache</strong>. Disabling this option excludes both cache\ndirectories from all the data directories. It is generally advised to\nexclude cache directories since most apps do not clear the cache\nregularly and usually handled by the OS itself. Apps such as Telegram\nmay use a very large cache (depending on the storage space) which may\ndramatically increase the backup size. When it is disabled, AM also\nignores the <strong>no_backup</strong> directories.<li><p><strong>Extras.</strong> Backup/restore app permissions, net\npolicy, battery optimization, SSAID, etc., enabled by default. Note\nthat, blocking rules are applied <em>after</em> applying the extras. So,\nif an item is present in both places, it will be overwritten (i.e., the\none from the blocking rules will be used).<li><p><strong>Rules.</strong> This option lets you back up blocking\nrules configured within App Manager. This might come in handy if you\nhave customised permissions or block some components using App Manager\nas they will also be backed up or restored when you enable this\noption.<li><p><strong>Backup Multiple.</strong> Whether this is a multiple\nbackup. By default, backups are saved using their user ID. Enabling this\noption allows you to create additional backups. These backups use the\ncurrent date-time as the default backup name, but you can also specify\ncustom backup name using the input field displayed when you click on the\n<strong>Backup</strong> button.<li><p><strong>Custom users.</strong> Backup or restore for the selected\nusers instead of only the current user. This option is only displayed if\nthe system has more than one user.<li><p><strong>Skip signature checks.</strong> When taking a backup,\nchecksum of every file (as well as the signing certificate(s) of the\nbase APK file) is generated and stored in the <code>checksums.txt</code>\nfile. When you restore the backup, the checksums are generated again and\nare matched with the checksums stored in the said file. Enabling this\noption will disable the signature checks. This option is applied only\nwhen you restore a backup. During backup, the checksums are generated\nregardless of this option.<div class=\"amalert warning\"><p><strong><em>Caution.</em></strong><p>You should always disable this option to ensure that your backups are\nnot modified by any third-party applications. However, this would only\nwork if you enabled encryption.</div></ul><div class=seealso-inline><p><em>こちらもご覧ください: <span><a href=#subsubsec:settings-encryption>Settings:\nEncryption</a></span></em></div></section><section id=subsec:backup-restore-backup class=level3 data-number=3.3.3><h3 data-number=3.3.3><span class=header-section-number>3.3.3</span>\n<a href=#toc:subsec:backup-restore-backup>Backup</a><a href=#subsec:backup-restore-backup class=anchor aria-hidden=true></a></h3><p>Backup respects all the backup options except <strong>Skip signature\nchecks</strong>. If base backups (i.e., backups that don’t have the\n<strong>Backup Multiple</strong> option) already exist, you will get a\nwarning as the backups will be overwritten. If <strong>Backup\nMultiple</strong> is set, you have an option to input the backup name,\nor you can leave it blank to use the current date-time.</section><section id=subsec:backup-restore-restore class=level3 data-number=3.3.4><h3 data-number=3.3.4><span class=header-section-number>3.3.4</span>\n<a href=#toc:subsec:backup-restore-restore>Restore</a><a href=#subsec:backup-restore-restore class=anchor aria-hidden=true></a></h3><p>Restore respects all the backup options and will fail if <strong>APK\nfiles</strong> option is set, but the backup doesn’t contain such\nbackups or in other cases, if the app isn’t installed. When restoring\nbackups for multiple packages, you can only restore the base backups\n(see <a href=#subsec:backup-restore-backup>backup</a> section for an\nexplanation). However, when restoring backups for a single package, you\nhave the option to select which backup to restore. If <strong>All\nusers</strong> option is set, AM will restore the selected backup for\nall users in the latter case but in the former case, it will restore\nbase backups for the respective users.<div class=\"amalert tip\"><p><strong><em>Notice.</em></strong><p>Apps that use storage access framework (SAF), SSAID or Android\nKeyStore works properly only after an immediate restart.</div></section><section id=subsec:backup-restore-delete-backup class=level3 data-number=3.3.5><h3 data-number=3.3.5><span class=header-section-number>3.3.5</span>\n<a href=#toc:subsec:backup-restore-delete-backup>Delete Backup</a><a href=#subsec:backup-restore-delete-backup class=anchor aria-hidden=true></a></h3><p>Delete backup only respects <strong>All users</strong> option and\nwhen it is selected, only the base backups for all users will be deleted\nwith a prompt. When deleting backups for a single package, another\ndialog will be displayed where you can select the backups to delete.</section></section><section id=sec:automating-tasks class=level2 data-number=3.4><h2 data-number=3.4><span class=header-section-number>3.4</span> <a href=#toc:sec:automating-tasks>Automating Tasks</a><a href=#sec:automating-tasks class=anchor aria-hidden=true></a></h2><p>It is possible to trigger profiles configured inside App Manager via\nthird-party applications such as <strong>Automation</strong> or\n<strong>Tasker</strong>. Traditionally, <code>Intent</code>s are used to\ntrigger such operations.<section id=subsec:generating-authorization-key class=level3 data-number=3.4.1><h3 data-number=3.4.1><span class=header-section-number>3.4.1</span>\n<a href=#toc:subsec:generating-authorization-key>Generating\nauthorization key</a><a href=#subsec:generating-authorization-key class=anchor aria-hidden=true></a></h3><p>In order to ensure proper security, an authorization key is required.\nTo generate a authorization key, go to <strong>Settings</strong> page\nand then <strong>Privacy</strong> > <strong>Authorization\nManager</strong>. If an authorization key has not been generated, it\nwill be generated automatically. The key can be regenerated as\nrequired.<div class=\"amalert danger\"><p><strong><em>Caution.</em></strong><p>Regenerating the authorization key can have some side effects such as\ninvalidation of all the previously configured Intents.</div></section><section id=subsec:at:general-configuration class=level3 data-number=3.4.2><h3 data-number=3.4.2><span class=header-section-number>3.4.2</span>\n<a href=#toc:subsec:at:general-configuration>Configuring tasks</a><a href=#subsec:at:general-configuration class=anchor aria-hidden=true></a></h3><p>The activity\n<code>io.github.muntashirakon.AppManager.crypto.auth.AuthFeatureDemultiplexer</code>\nis responsible for handling all the automations. Sending an intent to\nthe activity lets App Manager perform the designated operation by\nredirecting the <code>Intent</code> to the designated activity or\nservice.<section id=required-extras class=level4 data-number=3.4.2.1><h4 data-number=3.4.2.1><span class=header-section-number>3.4.2.1</span> Required extras<a href=#required-extras class=anchor aria-hidden=true></a></h4><p>It has two primary extras required in all conditions. The key names,\ndata types are all follows:<ol class=incremental><li><p><strong><code>auth</code>.</strong> (String value) The\nauthorization key as described in the earlier section.<li><p><strong><code>feature</code>.</strong> (String value) Name of the\nfeature. Supported features are described in the next section.</ol></section></section><section id=subsec:at:features class=level3 data-number=3.4.3><h3 data-number=3.4.3><span class=header-section-number>3.4.3</span>\n<a href=#toc:subsec:at:features>Features</a><a href=#subsec:at:features class=anchor aria-hidden=true></a></h3><p>App Manager current support a single feature, namely\n<code>profile</code>.</section><section id=subsec:triggering-a-profile class=level3 data-number=3.4.4><h3 data-number=3.4.4><span class=header-section-number>3.4.4</span>\n<a href=#toc:subsec:triggering-a-profile>Triggering a profile</a><a href=#subsec:triggering-a-profile class=anchor aria-hidden=true></a></h3><p>In order to trigger a profile, <code>feature</code> must have the\nvalue <code>profile</code>. In addition, the following extras can be\nincluded:<ol class=incremental><li><p><strong><code>prof</code>.</strong> (String value – required) The\nname of the profile as displayed in the <a href=#sec:profiles-page>Profiles page</a>.<li><p><strong><code>state</code>.</strong> (String value – optional)\nState of the profile – currently <code>on</code> or <code>off</code> –\nas specified in the documentation. If this extra is not set, App Manager\nwill display a prompt where a state must be selected. Therefore, for\ncomplete automation, this option should be set.</ol></section></section><section id=sec:net-policy class=level2 data-number=3.5><h2 data-number=3.5><span class=header-section-number>3.5</span> <a href=#toc:sec:net-policy>Net Policy</a><a href=#sec:net-policy class=anchor aria-hidden=true></a></h2><p>Short for <strong>Network policy</strong> or network policies. It is\nusually located in the Android settings under <strong>Mobile data &\nWifi</strong> section in the app info page of an app. Not all policies\nare guaranteed to be included in this page (e.g. Samsung), and not all\nsettings are well-understood due to lack of documentation. App Manager\ncan display all the net policies declared in the <a href=https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/net/NetworkPolicyManager.java>NetworkPolicyManager</a>.\nPolicies unknown to App Manager will have a <em>Unknown</em> prefix\nalong with the policy constant name and number in the hexadecimal\nformat. Unknown policies should be reported to App Manager for\ninclusion.<p>Net policy allows a user to configure certain networking behaviour of\nan app without modifying the ip tables directly and/or running a\nfirewall app. However, the features it offers largely depend on Android\nversion and ROM. A list of known net policies are listed below:<ol class=incremental><li><p><strong>None</strong> or\n<strong><code>POLICY_NONE</code></strong>: (AOSP) No specific network\npolicy is set. System can still assign rules depending on the nature of\nthe app.<li><p><strong>Reject background data on metered networks</strong> or\n<strong><code>POLICY_REJECT_METERED_BACKGROUND</code></strong>: (AOSP)\nReject network usage on metered networks when the application is in\nbackground.<li><p><strong>Allow background data on metered networks even when Data\nSaver is on</strong> or\n<strong><code>POLICY_ALLOW_METERED_BACKGROUND</code></strong>: (AOSP)\nAllow metered network use in the background even when data saving mode\nis enabled.<li><p><strong>Reject cellular data</strong> or\n<strong><code>POLICY_REJECT_CELLULAR</code></strong> (Android 11+) or\n<strong><code>POLICY_REJECT_ON_DATA</code></strong> (up to Android 10):\n(Lineage OS) Reject mobile/cellular data. Signals network unavailable to\nthe configured app as if the mobile data is inactive.<li><p><strong>Reject VPN data</strong> or\n<strong><code>POLICY_REJECT_VPN</code></strong> (Android 11+) or\n<strong><code>POLICY_REJECT_ON_VPN</code></strong> (up to Android 10):\n(Lineage OS) Reject VPN data. Signals network unavailable to the\nconfigured app as if the VPN is inactive.<li><p><strong>Reject Wi-Fi data</strong> or\n<strong><code>POLICY_REJECT_WIFI</code></strong> (Android 11+) or\n<strong><code>POLICY_REJECT_ON_WLAN</code></strong> (up to Android 10):\n(Lineage OS) Reject Wi-Fi data. Signals network unavailable to the\nconfigured app as if the device is not connected to a Wi-Fi\nnetwork.<li><p><strong>Disable network access</strong> or\n<strong><code>POLICY_REJECT_ALL</code></strong> (Android 11+) or\n<strong><code>POLICY_NETWORK_ISOLATED</code></strong> (up to Android\n10): (Lineage OS) Reject network access in all circumstances. This is\nnot the same as enforcing the other three policies above, and is the\nrecommended policy for dodgy apps. If this policy is enforced, there is\nno need to enforce the other policies.<li><p><strong><code>POLICY_ALLOW_METERED_IN_ROAMING</code></strong>:\n(Samsung) Possibly allow metered network use during roaming. Exact\nmeaning is currently unknown.<li><p><strong><code>POLICY_ALLOW_WHITELIST_IN_ROAMING</code></strong>:\n(Samsung) Possibly allow network use during roaming. Exact meaning is\ncurrently unknown.<li><p><strong>Reject data on metered networks</strong> or\n<strong><code>POLICY_REJECT_METERED</code></strong>: (Motorola) Reject\nnetwork usage if it is a metered network.<li><p><strong>Reject background data</strong> or\n<strong><code>POLICY_REJECT_BACKGROUND</code></strong>: (Motorola)\nReject network usage in the background.<li><p><strong>Disable network access</strong> or\n<strong><code>POLICY_REJECT_ALL</code></strong>: (Motorola) Reject\nnetwork access altogether. Like Lineage OS, it blocks internet\nconnections via iptables. But whether it signals the unavailability of\nnetwork to the configured app is not known.</ol><div class=\"amalert tip\"><p><strong><em>Note.</em></strong><p>Corresponding Lineage OS patches are as follows:<ol class=incremental><li><p><a href=https://github.com/LineageOS/android_frameworks_base/commit/a04932bafbbf7d99efd18276152cc2c9c9b2073e>fw/b:\nSquash of app fw restriction commits</a><li><p><a href=https://github.com/LineageOS/android_frameworks_base/commit/02c8c82854348f52afe2199f310f44b5f578b5b8>fw/b:\nAdd support for per app network isolation</a></ol></div></section></section><section id=ch:faq class=level1 data-number=4><h1 data-number=4><span class=header-section-number>4</span> <a href=#toc:ch:faq>Frequently Asked Questions</a><a href=#ch:faq class=anchor aria-hidden=true></a></h1><section id=sec:faq:app-components class=level2 data-number=4.1><h2 data-number=4.1><span class=header-section-number>4.1</span> <a href=#toc:sec:faq:app-components>App Components</a><a href=#sec:faq:app-components class=anchor aria-hidden=true></a></h2><section id=subsec:faq:what-are-app-components class=level3 data-number=4.1.1><h3 data-number=4.1.1><span class=header-section-number>4.1.1</span>\n<a href=#toc:subsec:faq:what-are-app-components>What are the\napplication components?</a><a href=#subsec:faq:what-are-app-components class=anchor aria-hidden=true></a></h3><p>Activities, services, broadcast receivers (or only receivers) and\ncontent providers (or only providers) are jointly called application\ncomponents. More technically, they all inherit the <a href=https://developer.android.com/reference/android/content/pm/ComponentInfo>ComponentInfo</a>\nclass and can be launched via Intent.</section><section id=subsec:faq:how-components-blocked class=level3 data-number=4.1.2><h3 data-number=4.1.2><span class=header-section-number>4.1.2</span>\n<a href=#toc:subsec:faq:how-components-blocked>How are the tracker and\nother components blocked in App Manager? What are its limitations?</a><a href=#subsec:faq:how-components-blocked class=anchor aria-hidden=true></a></h3><p>App Manager typically blocks application components (or tracker\ncomponents) using a method called <a href=https://carteryagemann.com/pages/android-intent-firewall.html>Intent\nFirewall (IFW)</a>, it is superior to other methods such as <em>pm</em>\n(PackageManager), <a href=https://github.com/RikkaApps/Shizuku>Shizuku</a> or any other\nmethod that uses the package manager to enable or disable the\ncomponents. If a component is disabled by the latter methods, the\napplication itself can detect that the component is being blocked and\ncan re-enable it as it has full access to its own components. (Many\ndeceptive applications actually do this in order to keep the tracker\ncomponents unblocked.) On the other hand, IFW is a true firewall and the\napplication cannot detect if its components are being blocked. App\nManager uses the term <em>block</em> rather than <em>disable</em> for\nthis reason.<p>Even IFW has some limitations which are primarily applicable for the\nsystem applications:<ul class=incremental><li><p>The application in question is whitelisted by the system i.e. the\nsystem cannot function properly without these applications and may cause\nrandom crashes. These applications include but not limited to Android\nSystem, System UI, Phone Services. They will continue to work even if\nthey are disabled or blocked.<li><p>Another system application or system process has activated a\nspecific component of the application in question via interprocess\ncommunication (IPC). In this case, the component will be activated\nregardless of blocking status or even if the entire application is\ndisabled. If there is such a system application that is not needed, the\nonly way to prevent it from running is by getting rid of it.</ul></section><section id=subsec:faq:components-blocked-by-others class=level3 data-number=4.1.3><h3 data-number=4.1.3><span class=header-section-number>4.1.3</span>\n<a href=#toc:subsec:faq:components-blocked-by-others>Does app\ncomponents blocked by other tools retained in App Manager?</a><a href=#subsec:faq:components-blocked-by-others class=anchor aria-hidden=true></a></h3><p><strong>No.</strong> But the application components blocked by the\nsystem or any other tools are displayed in the <a href=#subsec:component-tabs>component tabs</a>. These rules can be\nimported from <a href=#par:import-existing-rules>Settings</a>.\nHowever, it is not possible for App Manager to distinguish the\ncomponents blocked by the third-party tools and components blocked by\nthe system. Therefore, the applications listed in the import page should\nbe selected with care.</section><section id=subsec:faq:components-reblocked-in-am class=level3 data-number=4.1.4><h3 data-number=4.1.4><span class=header-section-number>4.1.4</span>\n<a href=#toc:subsec:faq:components-reblocked-in-am>What happens to the\ncomponents blocked by App Manager which were previously blocked by other\ntools?</a><a href=#subsec:faq:components-reblocked-in-am class=anchor aria-hidden=true></a></h3><p><em>App Manager blocks the components again</em> if requested. In\ncase of unblocking, they will be reverted to the default state as\nspecified in the manifest of the application. But if the components were\nblocked by <a href=https://www.myandroidtools.com>MyAndroidTools\n(MAT)</a> with IFW method, they will not be unblocked by App Manager as\nit uses a different format. To fix this issue, the rules have to be\nimported from <a href=#par:import-existing-rules>Settings</a> at\nfirst, in which case MAT’s configurations will be permanently\nremoved.</section><section id=subsec:faq:what-is-instant-component-blocking class=level3 data-number=4.1.5><h3 data-number=4.1.5><span class=header-section-number>4.1.5</span>\n<a href=#toc:subsec:faq:what-is-instant-component-blocking>What is\ninstant component blocking?</a><a href=#subsec:faq:what-is-instant-component-blocking class=anchor aria-hidden=true></a></h3><p>When you block a component in the <a href=#sec:app-details-page>App\nDetails page</a>, the blocking is not applied by default. It is only\napplied when you apply blocking using the <em>Apply rules</em> option in\nthe top-right menu. If you enable <a href=#subsubsec:instant-component-blocking>instant component\nblocking</a>, blocking will be applied as soon as you block a component.\nIf you choose to block tracker components, however, blocking is applied\nautomatically regardless of this setting. You can also remove blocking\nfor an application by simply clicking on <em>Remove rules</em> in the\nsame menu in the <strong>App Details page</strong>. Since the default\nbehaviour gives you more control over applications, it is better to keep\n<em>instant component blocking</em> option disabled.</section><section id=subsec:tracker-classes-versus-tracker-components class=level3 data-number=4.1.6><h3 data-number=4.1.6><span class=header-section-number>4.1.6</span>\n<a href=#toc:subsec:tracker-classes-versus-tracker-components>Tracker\nclasses versus tracker components</a><a href=#subsec:tracker-classes-versus-tracker-components class=anchor aria-hidden=true></a></h3><p>All application components are classes but not all classes are\ncomponents. In fact, only a few of the classes are components. That\nbeing said, <a href=#sec:scanner-page>scanner page</a> displays a list\nof trackers along with the number of classes, not just the components.\nIn all other pages, trackers and tracker components are used\nsynonymously to denote tracker components, i.e. blocking tracker means\nblocking tracker components, not tracker classes.<div class=\"amalert tip\"><p><strong><em>Info.</em></strong><p>Tracker classes that are not components cannot be blocked. They can\nonly be removed by editing the application itself.</div></section></section><section id=sec:faq:adb-over-tcp class=level2 data-number=4.2><h2 data-number=4.2><span class=header-section-number>4.2</span> <a href=#toc:sec:faq:adb-over-tcp>TCP経由のADB</a><a href=#sec:faq:adb-over-tcp class=anchor aria-hidden=true></a></h2><section id=subsec:faq:enable-adb-on-every-restart class=level3 data-number=4.2.1><h3 data-number=4.2.1><span class=header-section-number>4.2.1</span>\n<a href=#toc:subsec:faq:enable-adb-on-every-restart>再起動するたびにTCP経由のADBを再度有効にしなければなりませんか？</a><a href=#subsec:faq:enable-adb-on-every-restart class=anchor aria-hidden=true></a></h3><p>残念ながらそうです。しかしv2.5.13以降では、サーバー・クライアント方式によりシステムと対話的に動作するため、\nTCP経由のADBを常に有効にしておく必要はありません。但し<strong>開発者向けオプション</strong>の\n<strong>USBデバッグ</strong>を有効にしておく必要があります。そのためには、<a href=#sec:adb-over-tcp>TCP経由のADB</a>を有効にした状態でApp Manager\nを起動してください。そうすると、<em>ADBモードで動作中</em>とトースト通知が画面下部に表示されます。その後はTCPサーバーを停止させて構いません。\nLineageやその派生システムではTCP経由のADBをPCなしでも切り替えできます。\n<strong>ネットワーク経由のADB</strong>\nオプションが<strong>USBデバッグ</strong>オプションの下部に存在します。但し後者の場合ではTCPサーバーを停止できません。</section><section id=subsec:faq:usb-debugging class=level3 data-number=4.2.2><h3 data-number=4.2.2><span class=header-section-number>4.2.2</span>\n<a href=#toc:subsec:faq:usb-debugging>USBデバッグを有効にできません。どうすればよいですか？</a><a href=#subsec:faq:usb-debugging class=anchor aria-hidden=true></a></h3><p>チャプター <a href=#ch:guides data-reference-type=ref data-reference=ch:guides>3</a>の§<a href=#subsec:enable-usb-debugging data-reference-type=ref data-reference=subsec:enable-usb-debugging>3.1.2</a>をご確認ください。</section><section id=subsec:faq:block-components-using-adb class=level3 data-number=4.2.3><h3 data-number=4.2.3><span class=header-section-number>4.2.3</span>\n<a href=#toc:subsec:faq:block-components-using-adb>ADBモードでもトラッカーやその他のアプリコンポーネントをブロックすることができますか？</a><a href=#subsec:faq:block-components-using-adb class=anchor aria-hidden=true></a></h3><p>残念ながらできません。ADBでは限られた <a href=https://github.com/aosp-mirror/platform_frameworks_base/blob/master/packages/Shell/AndroidManifest.xml>権限</a>\nしか利用できず、アプリのコンポーネント制御はこの中に含まれません。</section><section id=subsec:faq:adb-features class=level3 data-number=4.2.4><h3 data-number=4.2.4><span class=header-section-number>4.2.4</span>\n<a href=#toc:subsec:faq:adb-features>ADBモードではどのような機能が利用できますか？</a><a href=#subsec:faq:adb-features class=anchor aria-hidden=true></a></h3><p>ADBモードではAppManagerの殆どの機能が利用でき、ADBモードが検出された際、自動的に有効になります。\nアプリを無効化、強制停止、データーを消去、AppOpsやアプリ権限を拒否/許可などの機能も含まれます。\nまたアプリを確認画面無しでインストールしたり、 <a href=#subsubsec:main:running-apps>実行中のアプリ/プロセス</a>の確認も可能です。</section></section><section id=sec:faq:miscellanea class=level2 data-number=4.3><h2 data-number=4.3><span class=header-section-number>4.3</span> <a href=#toc:sec:faq:miscellanea>Miscellanea</a><a href=#sec:faq:miscellanea class=anchor aria-hidden=true></a></h2><section id=subsec:faq:no-root-no-harms class=level3 data-number=4.3.1><h3 data-number=4.3.1><span class=header-section-number>4.3.1</span>\n<a href=#toc:subsec:faq:no-root-no-harms>I don’t use root/ADB. Am I\ncompletely safe from any harms?</a><a href=#subsec:faq:no-root-no-harms class=anchor aria-hidden=true></a></h3><p>Yes. AM cannot modify any system settings without root or ADB.</section><section id=subsec:faq:how-trackers-libs-updated class=level3 data-number=4.3.2><h3 data-number=4.3.2><span class=header-section-number>4.3.2</span>\n<a href=#toc:subsec:faq:how-trackers-libs-updated>How are the trackers\nand libraries are updated?</a><a href=#subsec:faq:how-trackers-libs-updated class=anchor aria-hidden=true></a></h3><p>Trackers and libraries are updated manually before making a new\nrelease.</section><section id=subsec:faq:apks-deleted-after-installed class=level3 data-number=4.3.3><h3 data-number=4.3.3><span class=header-section-number>4.3.3</span>\n<a href=#toc:subsec:faq:apks-deleted-after-installed>Are APKs deleted\nafter installed?</a><a href=#subsec:faq:apks-deleted-after-installed class=anchor aria-hidden=true></a></h3><p>No, APKs aren’t deleted by App Manager after they are installed.</section><section id=subsec:faq:shizuku-support class=level3 data-number=4.3.4><h3 data-number=4.3.4><span class=header-section-number>4.3.4</span>\n<a href=#toc:subsec:faq:shizuku-support>Any plans for Shizuku?</a><a href=#subsec:faq:shizuku-support class=anchor aria-hidden=true></a></h3><p>App Manager’s use of hidden API and privileged code execution is now\nmuch more complex and cannot be integrated with other third party apps\nsuch as <a href=https://shizuku.rikka.app>Shizuku</a>. Here are some\nreasons for not considering Shizuku (which now has Apache 2.0 license)\nfor App Manager:<ol class=incremental><li><p>Shizuku was initially non-free which led me to use a similar\napproach for App Manager to support both root and ADB<li><p>App Manager already supports both ADB and root which in some\ncases is more capable than Shizuku<li><p>Relying on a third-party app for the major functionalities is not\na good design choice<li><p>Integration of Shizuku will increase the complexity of App\nManager.</ol></section><section id=subsec:faq:what-are-bloatware class=level3 data-number=4.3.5><h3 data-number=4.3.5><span class=header-section-number>4.3.5</span>\n<a href=#toc:subsec:faq:what-are-bloatware>What are bloatware and how\nto remove them?</a><a href=#subsec:faq:what-are-bloatware class=anchor aria-hidden=true></a></h3><p>Bloatware are the unnecessary pre-installed apps, usually system\napps. Some of the apps are often used to track users and collect user\ndata which they might sell for profits. Many system apps do not need to\nrequest any permission to access device info, contacts and messaging\ndata, and other usage info, such as your phone usage habits and\neverything you store on your shared storage(s).<p>The bloatware may also include Google apps, Meta apps, and Twitter/X\nwhich can also track users and/or collect user data without consent. You\ncan disable a few permissions from Android settings but be aware that\nAndroid settings hides many permissions a security researcher would call\npotentially <em>dangerous</em> (e.g., internet, sensor).<p>Were the bloatware user apps, they could be easily uninstalled either\nfrom Android settings or AM. Uninstalling system apps is not possible\nwithout privileged permission, but even then, it cannot <em>remove</em>\nthe system apps completely as they are located in the <em>system</em>\npartition which is a read-only partition. If you have root, you can\nremount this partition to manually <em>purge</em> these apps but this\nwill break Over the Air (OTA) updates since data in the system partition\nhas been modified. There are two kind of updates, delta (small-size,\nconsisting of only the changes between two versions) and full updates.\nYou may still be able to apply full updates, but the bloatware will be\ninstalled again, and consequently, you have to delete them all over\nagain.<p>Another solution is to disable these apps either from Android\nsettings or AM, but certain services can still run in the background as\nthey can be started by other system apps using Inter-process\nCommunication (IPC). One possible solution is to disable all bloatware\nuntil the service has finally stopped (after a restart). However, due to\nheavy modifications of the Android frameworks by the vendors, removing\nor disabling certain bloatware may cause the System UI to crash or even\ncause bootloop. From v4.0.0, AM has a new feature called\n<strong>Debloater</strong> which can be used as a starting point to\nmonitor, disable, and remove the bloatware from a proprietary Android\noperating system.<div class=\"amalert warning\"><p><strong><em>Note.</em></strong><p>In most cases, you cannot completely debloat your device. Therefore,\nit is recommended that you use a custom ROM free from bloatware, such as\nGraphene OS, Lineage OS or their derivatives.</div></section></section></section><section id=ch:specifications class=level1 data-number=5><h1 data-number=5><span class=header-section-number>5</span> <a href=#toc:ch:specifications>Specifications</a><a href=#ch:specifications class=anchor aria-hidden=true></a></h1><section id=sec:rules-specification class=level2 data-number=5.1><h2 data-number=5.1><span class=header-section-number>5.1</span> <a href=#toc:sec:rules-specification>Rules Specification</a><a href=#sec:rules-specification class=anchor aria-hidden=true></a></h2><section id=background class=level3 data-number=5.1.1><h3 data-number=5.1.1><span class=header-section-number>5.1.1</span>\n<a href=#toc:background>Background</a><a href=#background class=anchor aria-hidden=true></a></h3><p>AM currently supports blocking activities, broadcast receivers,\ncontent providers, services, app ops and permissions, and in future I\nmay add more blocking options. In order to add more portability, it is\nnecessary to import/export all these data.<p>Maintaining a database should be the best choice when it comes to\nstoring data. For now, several <code>tsv</code> files with each file\nhaving the name of the package and a <code>.tsv</code> extension. The\nfile/database will be queried/processed by the\n<code>RulesStorageManager</code> class. Due to this abstraction, it\nshould be easier to switch to database or encrypted database systems in\nfuture without changing the design of the entire project. Currently, All\nconfiguration files are stored at\n<code>/data/data/io.github.muntashirakon.AppManager/Files/conf</code>.</section><section id=rules-file-format class=level3 data-number=5.1.2><h3 data-number=5.1.2><span class=header-section-number>5.1.2</span>\n<a href=#toc:rules-file-format>Rules File Format</a><a href=#rules-file-format class=anchor aria-hidden=true></a></h3><section id=internal class=level4 data-number=5.1.2.1><h4 data-number=5.1.2.1><span class=header-section-number>5.1.2.1</span> Internal<a href=#internal class=anchor aria-hidden=true></a></h4><p>The format below is used internally within App Manager and is <em>not\ncompatible with the external format.</em><pre><code>    &lt;name&gt; &lt;type&gt; &lt;mode&gt;|&lt;component_status&gt;|&lt;is_granted&gt;</code></pre><p>Here:<ul class=incremental><li><p><code>&lt;name></code> – Component/permission/app op name (in\ncase of app op, it could be string or integer)<li><p><code>&lt;type></code> – One of the <code>ACTIVITY</code>,\n<code>RECEIVER</code>, <code>PROVIDER</code>, <code>SERVICE</code>,\n<code>APP_OP</code>, <code>PERMISSION</code><li><p><code>&lt;mode></code> – (For app ops) The associated <a href=#subsec:mode-constants>mode constant</a><li><p><code>&lt;component_status></code> – (For components)\nComponent status<ul class=incremental><li><p><code>true</code> – Component has been applied (<code>true</code>\nvalue is kept for compatibility)<li><p><code>false</code> – Component hasn’t been applied yet, but will\nbe applied in future (<code>false</code> value is kept for\ncompatibility)<li><p><code>unblocked</code> – Component is scheduled to be\nunblocked</ul><li><p><code>&lt;is_granted></code> – (For permissions) Whether the\npermission is granted or revoked</ul></section><section id=external class=level4 data-number=5.1.2.2><h4 data-number=5.1.2.2><span class=header-section-number>5.1.2.2</span> External<a href=#external class=anchor aria-hidden=true></a></h4><p>External format is used for importing or exporting rules in App\nManager.<pre><code>    &lt;package_name&gt; &lt;component_name&gt; &lt;type&gt; &lt;mode&gt;|&lt;component_status&gt;|&lt;is_granted&gt;</code></pre><p>This the format is essentially the same as above except for the first\nitem which is the name of the package.<div class=\"amalert danger\"><p><strong><em>Caution.</em></strong><p>The exported rules have a different format than the internal one and\nshould not be copied directly to the <strong>conf</strong> folder.</div></section></section></section></section><section id=ch:changelogs class=level1 data-number=6><h1 data-number=6><span class=header-section-number>6</span> <a href=#toc:ch:changelogs>Changelogs</a><a href=#ch:changelogs class=anchor aria-hidden=true></a></h1><section id=sec:v4.0.5-(445) class=level2 data-number=6.1><h2 data-number=6.1><span class=header-section-number>6.1</span> <a href=#toc:sec:v4.0.5-(445)>v4.0.5 (445)</a><a href=#sec:v4.0.5-(445) class=anchor aria-hidden=true></a></h2><ul class=incremental><li><p>Added option to allow installing the existing applications in the\ninstaller page<li><p>Display unsafe bloatware info<li><p>Display vector icon on the splash screen in Android 7.1 and\nearlier<li><p>Enabled “Clear data from uninstalled apps” to no-root users in\n1-click ops page<li><p>Enabled predictive back in Android 14 onwards<li><p>Improved accessibility by updating the content description of the\naction items<li><p>In app info tab, open “Open by default” setting in the “Open\nlinks” dialog<li><p>In debloater page, sort by app label (or app name) rather than\npackage name<li><p>Fixed freezing an app with “Remember for this app” turned\non<li><p>Fixed selecting texts in the list items due to framework\nbugs<li><p>Fixed setting app ops in custom ROMs with MIUI properties\ninjected<li><p>Fixed updating profile modification status when an application is\ndeleted from the list<li><p>Handled common colors and cursor movements in terminal\noutput.</ul></section><section id=sec:v4.0.4-(444) class=level2 data-number=6.2><h2 data-number=6.2><span class=header-section-number>6.2</span> <a href=#toc:sec:v4.0.4-(444)>v4.0.4 (444)</a><a href=#sec:v4.0.4-(444) class=anchor aria-hidden=true></a></h2><ul class=incremental><li><p>Optimized searching and filtering in the main page<li><p>Adopted sentence-case for the titles<li><p>Use the configured state to execute a profile for the simple\nshortcuts<li><p>Prevented crashing while searching throughout the\napplication<li><p>Fixed integer overflow issue in the tar compression.</ul></section><section id=sec:v4.0.3-(443) class=level2 data-number=6.3><h2 data-number=6.3><span class=header-section-number>6.3</span> <a href=#toc:sec:v4.0.3-(443)>v4.0.3 (443)</a><a href=#sec:v4.0.3-(443) class=anchor aria-hidden=true></a></h2><ul class=incremental><li><p>Updated translations<li><p>Improved handling the list items throughout App Manager<li><p>Fixed a regression error in file manager<li><p>Fixed spinners in the App Usage and the System Config\npages.</ul></section><section id=sec:v4.0.2-(442) class=level2 data-number=6.4><h2 data-number=6.4><span class=header-section-number>6.4</span> <a href=#toc:sec:v4.0.2-(442)>v4.0.2 (442)</a><a href=#sec:v4.0.2-(442) class=anchor aria-hidden=true></a></h2><ul class=incremental><li><p>Updated bloatware<li><p>Fixed fetching applications in multi-user environment in no-root\nmode<li><p>Fixed opening <code>app-manager</code> URLs from the web\nbrowsers<li><p>Fixed updating SSAID<li><p>Prevented a crash in Android &lt; 9.0 that occurs due to invalid\napp ops.</ul></section><section id=sec:v4.0.1-(441) class=level2 data-number=6.5><h2 data-number=6.5><span class=header-section-number>6.5</span> <a href=#toc:sec:v4.0.1-(441)>v4.0.1 (441)</a><a href=#sec:v4.0.1-(441) class=anchor aria-hidden=true></a></h2><section id=overlay-management class=level3 data-number=6.5.1><h3 data-number=6.5.1><span class=header-section-number>6.5.1</span>\n<a href=#toc:overlay-management>Overlay management</a><a href=#overlay-management class=anchor aria-hidden=true></a></h3><p>In the App Details page, a new tab “Overlays” is added where per-app\noverlays are displayed. They can also be enabled or disabled using the\ntoggle button. In addition, if the App Details page of an overlay\npackage is opened, a “Overlay” tag will be displayed in the App Info\ntab. Clicking on the tag opens a dialog containing additional info along\nwith a button that allows navigating to the App Details page of the\noverlay target package if it is installed.<section id=known-limitation class=level5 data-number=6.5.1.0.1><h5 data-number=6.5.1.0.1><span class=header-section-number>6.5.1.0.1</span> Known limitation<a href=#known-limitation class=anchor aria-hidden=true></a></h5><p>At present, it only works for root/ADB users in Android 8 (Oreo) and\nlater.</section></section><section id=unfreeze-option-in-activity-shortcuts class=level3 data-number=6.5.2><h3 data-number=6.5.2><span class=header-section-number>6.5.2</span>\n<a href=#toc:unfreeze-option-in-activity-shortcuts>Unfreeze option in\nactivity shortcuts</a><a href=#unfreeze-option-in-activity-shortcuts class=anchor aria-hidden=true></a></h3><p>If the application corresponding to the shortcut being launched is\nfrozen, App Manager will now offer you to unfreeze the app temporarily\nso that the shortcut can be launched. The app will be frozen again once\nthe screen is locked.<section id=known-limitation-1 class=level5 data-number=6.5.2.0.1><h5 data-number=6.5.2.0.1><span class=header-section-number>6.5.2.0.1</span> Known limitation<a href=#known-limitation-1 class=anchor aria-hidden=true></a></h5><p>This may not work on devices without a screen lock or if the screen\nis locked some time after the display goes off.</section></section><section id=market-like-url-support class=level3 data-number=6.5.3><h3 data-number=6.5.3><span class=header-section-number>6.5.3</span>\n<a href=#toc:market-like-url-support><code>market</code>-like URL\nsupport</a><a href=#market-like-url-support class=anchor aria-hidden=true></a></h3><p>Third-party applications can now open the App Details page of any\ninstalled package by invoking an Intent with an URL with the following\nformat:<pre><code>app-manager://details?id=&lt;pkg&gt;&amp;user=&lt;user_id&gt;</code></pre><p>where <code>&lt;pkg></code> stands for package name, and\n<code>&lt;user_id></code> stands for the user ID which is\noptional.</section><section id=updated-color-codes class=level3 data-number=6.5.4><h3 data-number=6.5.4><span class=header-section-number>6.5.4</span>\n<a href=#toc:updated-color-codes>Updated color codes</a><a href=#updated-color-codes class=anchor aria-hidden=true></a></h3><p>In order to improve accessibility, certain color codes have been\nimproved. Visit <a href=app-manager://settings/about/version>Settings\n> About > Version/Changelog</a> for details.</section><section id=others class=level3 data-number=6.5.5><h3 data-number=6.5.5><span class=header-section-number>6.5.5</span>\n<a href=#toc:others>Others</a><a href=#others class=anchor aria-hidden=true></a></h3><ul class=incremental><li><p>Avoided waiting for the remote server to respond when no-root\nmode is set<li><p>Fixed downgrading apps in Android 10 onwards<li><p>Fixed installer issues in the Huawei stock operating\nsystems<li><p>Improved text formatting in the “What’s New” dialog<li><p>In the UI tracker window, fixed clicking on the icon after it is\niconified<li><p>Updated bloatware and suggestions</ul></section></section><section id=sec:v4.0.0-(440) class=level2 data-number=6.6><h2 data-number=6.6><span class=header-section-number>6.6</span> <a href=#toc:sec:v4.0.0-(440)>v4.0.0 (440)</a><a href=#sec:v4.0.0-(440) class=anchor aria-hidden=true></a></h2><p>App Manager v4.0.0 comes with a lot of new features and improvements.\nVisit <a href=app-manager://settings/about/version>Settings > About\n> Version/Changelog</a> for details.<section id=new-logo class=level3 data-number=6.6.1><h3 data-number=6.6.1><span class=header-section-number>6.6.1</span>\n<a href=#toc:new-logo>New logo!</a><a href=#new-logo class=anchor aria-hidden=true></a></h3><p>The new logo is just a cursive “A”. The design is based on the <a href=https://freetengwar.sourceforge.net/>Tengwar Telcontar</a> font\nwhich was created to bring the Tengwar script, originally created by J.\nR. R. Tolkien, to the digital world. The letter has the classic App\nManager color (i.e., #dcaf74) and uses a pure black background instead\nof a shade of grey.</section><section id=android-14-and-15-support class=level3 data-number=6.6.2><h3 data-number=6.6.2><span class=header-section-number>6.6.2</span>\n<a href=#toc:android-14-and-15-support>Android 14 and 15 support</a><a href=#android-14-and-15-support class=anchor aria-hidden=true></a></h3><p>App Manager now targets Android 14 and fully supports Android 15.<section id=known-issue class=level5 data-number=6.6.2.0.1><h5 data-number=6.6.2.0.1><span class=header-section-number>6.6.2.0.1</span> Known issue<a href=#known-issue class=anchor aria-hidden=true></a></h5><p>KeyStore backup/restore is not working in Android 12 and later.</section></section><section id=revamped-debloater class=level3 data-number=6.6.3><h3 data-number=6.6.3><span class=header-section-number>6.6.3</span>\n<a href=#toc:revamped-debloater>Revamped debloater</a><a href=#revamped-debloater class=anchor aria-hidden=true></a></h3><p>Debloating profiles were available as “Presets” in the Profiles page\nwhich has now been replaced with the Debloater page and can be accessed\nfrom the three-dots menu in the Main page. <a href=https://github.com/MuntashirAkon/android-debloat-list>ADL</a> is\na new project that focuses on maintaining a list of bloatware as well as\npotential open source alternatives. Contributions are welcome!</section><section id=introducing-file-manager class=level3 data-number=6.6.4><h3 data-number=6.6.4><span class=header-section-number>6.6.4</span>\n<a href=#toc:introducing-file-manager>Introducing file manager</a><a href=#introducing-file-manager class=anchor aria-hidden=true></a></h3><p>App Manager offers an (almost) fully-featured file manager with basic\nfile operations, such as copy, cut, rename, and delete along with the\nbatch operations. It also offers an extensive “Open with…” dialog to\nopen a file with another app, and a comprehensive file properties\nviewer. Folders can also be added to the list of favorites for quick\naccess. And many more.</section><section id=integrated-code-editor class=level3 data-number=6.6.5><h3 data-number=6.6.5><span class=header-section-number>6.6.5</span>\n<a href=#toc:integrated-code-editor>Integrated code editor</a><a href=#integrated-code-editor class=anchor aria-hidden=true></a></h3><p>Manifest and code viewers have been replaced with this new editor.\nAmong other regular features, it includes proper syntax highlighting and\nadvanced searching options. In addition, files from third-party apps can\nalso be opened for editing.</section><section id=history-of-operations class=level3 data-number=6.6.6><h3 data-number=6.6.6><span class=header-section-number>6.6.6</span>\n<a href=#toc:history-of-operations>History of operations</a><a href=#history-of-operations class=anchor aria-hidden=true></a></h3><p>All 1-click operations, batch operations, and profile invocations are\nnow stored as history. The history items can also be executed from the\nHistory page. To ensure consistency, the profile state, configurations,\npackage list are also stored, and this stored version is executed\ninstead of the actual profile. As a result, this works even if the\nprofile is deleted.</section><section id=per-app-freezing-and-more class=level3 data-number=6.6.7><h3 data-number=6.6.7><span class=header-section-number>6.6.7</span>\n<a href=#toc:per-app-freezing-and-more>Per-app freezing, and\nmore</a><a href=#per-app-freezing-and-more class=anchor aria-hidden=true></a></h3><p>Freeze/unfreeze feature now supports setting per-app freezing method\nwhich is beneficial in certain scenarios, such as when a user want to\nsuspend some apps while using the disable method as the default. In\naddition, an “Advanced suspend” option is added which force-stops an\napplication before suspending it, thus, prevent it’s services from\nrunning in the background.</section><section id=log-viewer-enhancements class=level3 data-number=6.6.8><h3 data-number=6.6.8><span class=header-section-number>6.6.8</span>\n<a href=#toc:log-viewer-enhancements>Log viewer enhancements</a><a href=#log-viewer-enhancements class=anchor aria-hidden=true></a></h3><p>Log viewer now supports enhanced searching and filtering options,\nsuch as keyword- and regular expression-based searching and filtering.\nPlease read the in-app changelog for details. Support for batch\noperations has also been added.</section><section id=launching-non-exported-activities class=level3 data-number=6.6.9><h3 data-number=6.6.9><span class=header-section-number>6.6.9</span>\n<a href=#toc:launching-non-exported-activities>Launching non-exported\nactivities</a><a href=#launching-non-exported-activities class=anchor aria-hidden=true></a></h3><p>App Manager now supports launching non-exported activities in no-root\nand ADB mode. However, in no-root mode,\n<code>android.permission.WRITE_SECURE_SETTINGS</code> permission is\nrequired.</section><section id=new-tags-in-app-info-tab class=level3 data-number=6.6.10><h3 data-number=6.6.10><span class=header-section-number>6.6.10</span> <a href=#toc:new-tags-in-app-info-tab>New tags in App Info tab</a><a href=#new-tags-in-app-info-tab class=anchor aria-hidden=true></a></h3><p>Five new tags are added in the App Info tab. They are: bloatware,\nXposed, sensors disabled, open links, and static shared libs. Clicking\non “bloatware” will display more information regarding the bloatware and\nsuggest alternatives, “Xposed” tag will display dependency information,\n“open links” will display a list of links supported by the application,\nand “static shared libs” will display all version of the application\ninstalled in the system along with an option to uninstall them. The\nlatter is useful for applications, such as Trichrome.<section id=known-issue-1 class=level5 data-number=6.6.10.0.1><h5 data-number=6.6.10.0.1><span class=header-section-number>6.6.10.0.1</span> Known issue<a href=#known-issue-1 class=anchor aria-hidden=true></a></h5><p>“Sensors disabled” only works real-time. That means if the\napplication is not currently active, this tag will always display even\nthough the applications may use sensors while it is running. This is a\nframework limitation and nothing can be done to avoid it\neffectively.</section></section><section id=per-session-installer-options class=level3 data-number=6.6.11><h3 data-number=6.6.11><span class=header-section-number>6.6.11</span> <a href=#toc:per-session-installer-options>Per-session installer\noptions</a><a href=#per-session-installer-options class=anchor aria-hidden=true></a></h3><p>It is not possible to modify installer options during the\ninstallation by clicking on the “settings” button in the installation\ndialog. The installer options will be applied to all the applications\ninstalled in the same session (i.e., the installer queue).</section><section id=advanced-mode-of-operations-adb-enhancements class=level3 data-number=6.6.12><h3 data-number=6.6.12><span class=header-section-number>6.6.12</span> <a href=#toc:advanced-mode-of-operations-adb-enhancements>Advanced mode\nof operations, ADB enhancements, …</a><a href=#advanced-mode-of-operations-adb-enhancements class=anchor aria-hidden=true></a></h3><p>App Manager now supports running its remote server (which is used as\na proxy for running privileged operations) as any supported user (UID).\nThis includes root (0), system (1000), and shell/ADB (2000) through the\ncustom commands. This is also useful for Fire TVs which have disabled\nconnecting to ADB from localhost through socket connection. In addition,\nADB pairing is now done using notifications rather than split screen.\nADB connection speed can also be improved by choosing to run App Manager\nin the background which can be configured in the settings.</section><section id=data-usage-widget-and-more class=level3 data-number=6.6.13><h3 data-number=6.6.13><span class=header-section-number>6.6.13</span> <a href=#toc:data-usage-widget-and-more>Data usage widget, and more</a><a href=#data-usage-widget-and-more class=anchor aria-hidden=true></a></h3><p>Data usage widget display the total data usage for the day, similar\nto the screen time widget which displays the total screen time for the\nday. In addition, existing widgets have been improved.</section><section id=others-1 class=level3 data-number=6.6.14><h3 data-number=6.6.14><span class=header-section-number>6.6.14</span> <a href=#toc:others-1>Others</a><a href=#others-1 class=anchor aria-hidden=true></a></h3><ul class=incremental><li><p>Replaced log viewer, sys config, Terminal, etc. with Labs\npage<li><p>Added an option to disable sensors for each app in the App Info\ntab<li><p>Added an option to perform runtime optimization of applications\nin the 1-click Ops page and in the App Info tab<li><p>Added support for Zstandard compression for\nbackup/restore<li><p>Enabling APK signing now automatically enables zip align\nfeature<li><p>Support exporting application list as CSV or JSON in the batch\noperations<li><p>Added pure black theme support<li><p>Display current activity name (when possible) in the UI Tracker\nwindow<li><p>Added an option to filter apps by user in the Main page<li><p>Display a link to Pithus report in the scanner page if\navailable.</ul></section></section><section id=sec:v3.1.0-(423) class=level2 data-number=6.7><h2 data-number=6.7><span class=header-section-number>6.7</span> <a href=#toc:sec:v3.1.0-(423)>v3.1.0 (423)</a><a href=#sec:v3.1.0-(423) class=anchor aria-hidden=true></a></h2><p>App Manager v3.1.0 comes with a few new features and a lot of\nimprovements. Visit <a href=app-manager://settings/about/version>Settings > About >\nVersion/Changelog</a> for details.<section id=android-13-support class=level3 data-number=6.7.1><h3 data-number=6.7.1><span class=header-section-number>6.7.1</span>\n<a href=#toc:android-13-support>Android 13 support</a><a href=#android-13-support class=anchor aria-hidden=true></a></h3><p>App Manager now targets Android 13 which means most issues in Android\n12 and 13 has been addressed, including SSAID and SAF issues as well as\nmonochrome icons and other theming issues.<section id=known-issue-2 class=level5 data-number=6.7.1.0.1><h5 data-number=6.7.1.0.1><span class=header-section-number>6.7.1.0.1</span> Known issue<a href=#known-issue-2 class=anchor aria-hidden=true></a></h5><p>KeyStore backup/restore not working in Android 12 and later.</section></section><section id=introducing-freezeunfreeze class=level3 data-number=6.7.2><h3 data-number=6.7.2><span class=header-section-number>6.7.2</span>\n<a href=#toc:introducing-freezeunfreeze>Introducing\nfreeze/unfreeze</a><a href=#introducing-freezeunfreeze class=anchor aria-hidden=true></a></h3><p>Enable/disable is replaced with freeze/unfreeze to allow greater\ncontrol on the behaviours of an app. It supports suspend, disable and\nhide functionalities which can be controlled at <a href=app-manager://settings/rules_prefs/freeze_type>Settings >\nRules > Default freezing method</a>. In order to make it easy to\nfreeze or unfreeze an app, shortcuts can also be created from the App\nInfo tab by long clicking on the freeze or unfreeze button.</section><section id=export-app-list class=level3 data-number=6.7.3><h3 data-number=6.7.3><span class=header-section-number>6.7.3</span>\n<a href=#toc:export-app-list>Export app list</a><a href=#export-app-list class=anchor aria-hidden=true></a></h3><p>In the Main page, it is now possible to export the list of apps in\neither XML or Markdown format using batch operations. In the future, the\nXML file may also be imported to App Manager.</section><section id=elliptic-curve-crypography-ecc class=level3 data-number=6.7.4><h3 data-number=6.7.4><span class=header-section-number>6.7.4</span>\n<a href=#toc:elliptic-curve-crypography-ecc>Elliptic Curve Crypography\n(ECC)</a><a href=#elliptic-curve-crypography-ecc class=anchor aria-hidden=true></a></h3><p>App Manager now fully supports encrypting backups using ECC in\naddition to offering AES, RSA and OpenPGP.</section><section id=new-languages class=level3 data-number=6.7.5><h3 data-number=6.7.5><span class=header-section-number>6.7.5</span>\n<a href=#toc:new-languages>New languages</a><a href=#new-languages class=anchor aria-hidden=true></a></h3><p>Two new languages are added: Korean and Romanian.</section><section id=more-list-options class=level3 data-number=6.7.6><h3 data-number=6.7.6><span class=header-section-number>6.7.6</span>\n<a href=#toc:more-list-options>More list options</a><a href=#more-list-options class=anchor aria-hidden=true></a></h3><p>In the main page, more sorting and filtering options are added.\nSorting options include sorting the apps by total size, total data\nusage, launch count, screen time and last usage time. Filtering options\ninclude filtering the apps having at least one item in the Android\nKeyStore, filtering apps with URIs granted via SAF, and filtering apps\nwith SSAID.</section><section id=improved-handling-of-mode-of-operation class=level3 data-number=6.7.7><h3 data-number=6.7.7><span class=header-section-number>6.7.7</span>\n<a href=#toc:improved-handling-of-mode-of-operation>Improved handling\nof mode of operation</a><a href=#improved-handling-of-mode-of-operation class=anchor aria-hidden=true></a></h3><p>Fixed various issues with ADB pairing, handled incomplete USB\ndebugging. Some rooting methods cannot allow interprocess communication\nvia Binder. In those cases, ADB mode is used as a fallback method by\nenabling it automatically if possible.</section><section id=handling-multiple-users class=level3 data-number=6.7.8><h3 data-number=6.7.8><span class=header-section-number>6.7.8</span>\n<a href=#toc:handling-multiple-users>Handling multiple users</a><a href=#handling-multiple-users class=anchor aria-hidden=true></a></h3><p>When possible, App Manager will be able to display apps from work\nprofile in no-root mode in addition to allowing basic operations such as\nlaunching the app or navigating to the system settings. For backups, it\nis now possible to restore backups for other users, but for work\nprofile, some apps may only work properly after re-enabling the work\nprofile. In the installer page, selecting <em>All users</em> will now\ninstall the app for all users instead of only the current user. Finally,\nin the app info tab, current app can be installed in another profile\nusing the <em>Install for…</em> option available in the three-dots menu.\nThis is analogous to the <code>pm install-existing</code> command,\nthereby, making the installation process a lot faster.</section><section id=explorer-enhancements class=level3 data-number=6.7.9><h3 data-number=6.7.9><span class=header-section-number>6.7.9</span>\n<a href=#toc:explorer-enhancements>Explorer enhancements</a><a href=#explorer-enhancements class=anchor aria-hidden=true></a></h3><p>Explorer can now open DEX and JAR files in addition to APK files.\nSeveral sorting options as well as folder options are also added as the\nlist options.</section><section id=new-tag-wx class=level3 data-number=6.7.10><h3 data-number=6.7.10><span class=header-section-number>6.7.10</span> <a href=#toc:new-tag-wx>New tag: WX</a><a href=#new-tag-wx class=anchor aria-hidden=true></a></h3><p>In app info tab, a new tag called WX is added. It is displayed in\nAndroid 10 and later if the application targets Android 9 or earlier. It\nindicates <a href=https://en.wikipedia.org/wiki/W%5EX>W^X</a>\nviolation which allows the app to execute arbitrary executable files\neither by the modification of executables embedded within the app or by\ndownloading them from the Internet.</section><section id=app-ops-management class=level3 data-number=6.7.11><h3 data-number=6.7.11><span class=header-section-number>6.7.11</span> <a href=#toc:app-ops-management>App ops management</a><a href=#app-ops-management class=anchor aria-hidden=true></a></h3><p>App ops are now managed automatically to avoid various app ops\nrelated crashes in various platforms. This will also lessen the amount\nof crashes in an unsupported operating system.</section><section id=batch-uninstallation class=level3 data-number=6.7.12><h3 data-number=6.7.12><span class=header-section-number>6.7.12</span> <a href=#toc:batch-uninstallation>Batch uninstallation</a><a href=#batch-uninstallation class=anchor aria-hidden=true></a></h3><p>In the Main page, enabled batch uninstallation in no-root mode.</section><section id=running-apps class=level3 data-number=6.7.13><h3 data-number=6.7.13><span class=header-section-number>6.7.13</span> <a href=#toc:running-apps>Running apps</a><a href=#running-apps class=anchor aria-hidden=true></a></h3><p>Enabled advanced searching. Searching now matches not only app labels\nbut also package names.</section><section id=interceptor class=level3 data-number=6.7.14><h3 data-number=6.7.14><span class=header-section-number>6.7.14</span> <a href=#toc:interceptor>Interceptor</a><a href=#interceptor class=anchor aria-hidden=true></a></h3><p>Copy the intercepted Intent as am command which can be run from\neither an ADB shell or a terminal using root with the same\neffectiveness.</section><section id=device-specific-changes class=level3 data-number=6.7.15><h3 data-number=6.7.15><span class=header-section-number>6.7.15</span> <a href=#toc:device-specific-changes>Device-specific changes</a><a href=#device-specific-changes class=anchor aria-hidden=true></a></h3><section id=graphene-os class=level5 data-number=6.7.15.0.1><h5 data-number=6.7.15.0.1><span class=header-section-number>6.7.15.0.1</span> Graphene OS<a href=#graphene-os class=anchor aria-hidden=true></a></h5><p>Explicitly handle the Internet permission which is a runtime\npermission in the OS.</section><section id=miui class=level5 data-number=6.7.15.0.2><h5 data-number=6.7.15.0.2><span class=header-section-number>6.7.15.0.2</span> MIUI<a href=#miui class=anchor aria-hidden=true></a></h5><p>Fixed permission denied issues in the installer due to a framework\nissue introduced in MIUI 12.5.</section><section id=motorola class=level5 data-number=6.7.15.0.3><h5 data-number=6.7.15.0.3><span class=header-section-number>6.7.15.0.3</span> Motorola<a href=#motorola class=anchor aria-hidden=true></a></h5><p>Fixed crashes in the Interceptor page due to a framework issue\nintroduced in Android 11.</section></section><section id=others-2 class=level3 data-number=6.7.16><h3 data-number=6.7.16><span class=header-section-number>6.7.16</span> <a href=#toc:others-2>Others</a><a href=#others-2 class=anchor aria-hidden=true></a></h3><ul class=incremental><li><p>Improved Java-Smali conversion by including all the subclasses\nduring conversion<li><p>Improved scanning performance in the Scanner page<li><p>Improved updating the list of apps in the Main page<li><p>Scan all the available paths to detect systemless-ly installed\nsystem apps<li><p><code>vacuum</code> SQLite database before opening it for viewing\nor editing.</ul></section></section><section id=sec:v3.0.0-(410) class=level2 data-number=6.8><h2 data-number=6.8><span class=header-section-number>6.8</span> <a href=#toc:sec:v3.0.0-(410)>v3.0.0 (410)</a><a href=#sec:v3.0.0-(410) class=anchor aria-hidden=true></a></h2><p>App Manager v3.0.0 comes with a lot of features and improvements. See\n<a href=app-manager://settings/about/version>Settings > About >\nVersion/Changelog</a> to see a more detailed changelog.<section id=material-3-and-more class=level3 data-number=6.8.1><h3 data-number=6.8.1><span class=header-section-number>6.8.1</span>\n<a href=#toc:material-3-and-more>Material 3 and More</a><a href=#material-3-and-more class=anchor aria-hidden=true></a></h3><p>Material 3, somewhat similar to <em>Material You</em>, is a\nsignificant improvement over Material Design 2 with support for dynamic\ncolours in Android 12 and later. In addition, many design changes have\nbeen made in App Manager without any significant changes in the overall\nuser experience.<section id=known-issue-3 class=level5 data-number=6.8.1.0.1><h5 data-number=6.8.1.0.1><span class=header-section-number>6.8.1.0.1</span> Known issue<a href=#known-issue-3 class=anchor aria-hidden=true></a></h5><p>Switches are still based on Material Design 2 which will be fixed in\na future release.</section></section><section id=wireless-debugging class=level3 data-number=6.8.2><h3 data-number=6.8.2><span class=header-section-number>6.8.2</span>\n<a href=#toc:wireless-debugging>Wireless Debugging</a><a href=#wireless-debugging class=anchor aria-hidden=true></a></h3><p>Wireless debugging support has been fully implemented. Head over to\n§<a href=#sec:wireless-debugging data-reference-type=ref data-reference=sec:wireless-debugging>3.2</a> for instructions on how\nto configure wireless debugging.<div class=\"amalert tip\"><p><strong><em>No-root users.</em></strong><p>Due to auto-detection feature, startup time might be large for\nno-root users when the mode of operation is set to <em>auto</em>.\nInstead, no-root users should select <em>no-root</em> instead of\n<em>auto</em>.</div></section><section id=languages class=level3 data-number=6.8.3><h3 data-number=6.8.3><span class=header-section-number>6.8.3</span>\n<a href=#toc:languages>Languages</a><a href=#languages class=anchor aria-hidden=true></a></h3><p>App Manager is fully translated into Indonesian and Italian languages\nand can be enabled in settings. Bengali is removed due to lack of\ntranslators.</section><section id=introducing-app-explorer class=level3 data-number=6.8.4><h3 data-number=6.8.4><span class=header-section-number>6.8.4</span>\n<a href=#toc:introducing-app-explorer>Introducing App Explorer</a><a href=#introducing-app-explorer class=anchor aria-hidden=true></a></h3><p>App Explorer can be used to browse the contents of an application.\nThis includes binary XML files, DEX contents or any other media files.\nDEX contents can only be explored in Android Oreo (Android 8) and later.\nIt’s also possible to convert an <code>.smali</code> file into\n<code>.java</code> for a better understanding of the reversed code. This\nfeature, if not needed, can be disabled in Settings > Enable/disable\nfeatures.</section><section id=import-backups-from-other-applications class=level3 data-number=6.8.5><h3 data-number=6.8.5><span class=header-section-number>6.8.5</span>\n<a href=#toc:import-backups-from-other-applications>Import Backups\nfrom Other Applications</a><a href=#import-backups-from-other-applications class=anchor aria-hidden=true></a></h3><p>It is possible to import backups from discontinued or obsolete\napplications such as Titanium Backup, OAndBackup and Swift Backup\n(version 3.0 to 3.2). Go to Setting > Backup/restore to find this\noption.</section><section id=virustotal class=level3 data-number=6.8.6><h3 data-number=6.8.6><span class=header-section-number>6.8.6</span>\n<a href=#toc:virustotal>VirusTotal</a><a href=#virustotal class=anchor aria-hidden=true></a></h3><p>VirusTotal is a widely used tool to scan files and URLs for viruses.\nIn the scanner page and in the running apps page, an option to scan\nfiles with VirusTotal has been added. But the option is hidden by\ndefault. To enable the option, it is necessary to obtain an API key from\nVirusTotal. Go to Settings > VirusTotal API Key for more\ninformation.<div class=\"amalert warning\"><p><strong><em>Internet feature.</em></strong><p>This is currently the only feature which require an Internet\nconnection. If you wish to use any Internet feature that might also be\nadded in the future, enable <em>Use the Internet</em> in Settings >\nEnable/disable features.</div></section><section id=trigger-profiles-from-the-automation-software class=level3 data-number=6.8.7><h3 data-number=6.8.7><span class=header-section-number>6.8.7</span>\n<a href=#toc:trigger-profiles-from-the-automation-software>Trigger\nProfiles from the Automation Software</a><a href=#trigger-profiles-from-the-automation-software class=anchor aria-hidden=true></a></h3><p>As the implementation of routine operations is being delayed, an\noption to trigger profiles from the external automation software is\nadded. See §<a href=#sec:automating-tasks data-reference-type=ref data-reference=sec:automating-tasks>3.4</a> for instructions on how to\nconfigure profile automation.</section><section id=improved-application-installer class=level3 data-number=6.8.8><h3 data-number=6.8.8><span class=header-section-number>6.8.8</span>\n<a href=#toc:improved-application-installer>Improved Application\nInstaller</a><a href=#improved-application-installer class=anchor aria-hidden=true></a></h3><p>Application installer includes several improvements including the\nability to downgrade applications in no-root mode, installing multiple\napplications at once and blocking trackers after installation. In\nAndroid 12 and later, no-root users can update applications without any\nuser interactions.</section><section id=component-blocking class=level3 data-number=6.8.9><h3 data-number=6.8.9><span class=header-section-number>6.8.9</span>\n<a href=#toc:component-blocking>Component Blocking</a><a href=#component-blocking class=anchor aria-hidden=true></a></h3><p>It is now possible to configure how App Manager should block a\ncomponent. Visit Settings > Rules > Default blocking method for\nmore information. In the components tab, long clicking the block/unblock\nbutton opens a context menu which allows per-component blocking in a\nsimilar manner. ADB users can also block the components of a <em>Test\nonly</em> app.</section><section id=advanced-searching class=level3 data-number=6.8.10><h3 data-number=6.8.10><span class=header-section-number>6.8.10</span> <a href=#toc:advanced-searching>Advanced Searching</a><a href=#advanced-searching class=anchor aria-hidden=true></a></h3><p>In some pages, the search bar supports additional searching which\nincludes searching via prefix, suffix or even regular expressions. In\nthe main page, it is also possible to search for applications using the\nfirst letters of each word, e.g. <em>App Manager</em> can be listed by\nsearching for <em>am</em>.</section><section id=shared-libraries class=level3 data-number=6.8.11><h3 data-number=6.8.11><span class=header-section-number>6.8.11</span> <a href=#toc:shared-libraries>Shared Libraries</a><a href=#shared-libraries class=anchor aria-hidden=true></a></h3><p>Shared libraries tab has received a significant improvements. It can\ndisplay three types of libraries, such as native, jar and APK files.</section><section id=make-the-best-use-of-interceptor class=level3 data-number=6.8.12><h3 data-number=6.8.12><span class=header-section-number>6.8.12</span> <a href=#toc:make-the-best-use-of-interceptor>Make the Best Use of\nInterceptor</a><a href=#make-the-best-use-of-interceptor class=anchor aria-hidden=true></a></h3><p>Activity interceptor can be opened directly from the activities tab\nby long clicking on the launch button, and similarly, activities can be\nlaunched from the activity interceptor page with or without root, for\nany users.<div class=\"amalert tip\"><p><strong><em>Notice.</em></strong><p>Currently, activities opened via root cannot send the results back to\nthe original applications.</div></section><section id=widget-screen-time class=level3 data-number=6.8.13><h3 data-number=6.8.13><span class=header-section-number>6.8.13</span> <a href=#toc:widget-screen-time>Widget: Screen Time</a><a href=#widget-screen-time class=anchor aria-hidden=true></a></h3><p>Screen time widget is quite similar to Digital Wellbeing’s widget by\nthe same name. It displays the total screen time for the day along with\nthe top three apps from all users.</section><section id=widget-clear-cache class=level3 data-number=6.8.14><h3 data-number=6.8.14><span class=header-section-number>6.8.14</span> <a href=#toc:widget-clear-cache>Widget: Clear Cache</a><a href=#widget-clear-cache class=anchor aria-hidden=true></a></h3><p>Clear cache widget can be to clear cache from all the applications\ndirectly from the home screen.</section></section><section id=sec:v2.6.0-(385) class=level2 data-number=6.9><h2 data-number=6.9><span class=header-section-number>6.9</span> <a href=#toc:sec:v2.6.0-(385)>v2.6.0 (385)</a><a href=#sec:v2.6.0-(385) class=anchor aria-hidden=true></a></h2><section id=introducing-backups class=level3 data-number=6.9.1><h3 data-number=6.9.1><span class=header-section-number>6.9.1</span>\n<a href=#toc:introducing-backups>Introducing Backups</a><a href=#introducing-backups class=anchor aria-hidden=true></a></h3><p>Back up/restore feature is now finally out of beta! Read <a href=#sec:backup-restore>the corresponding guide</a> to understand how\nit works.</section><section id=introducing-log-viewer class=level3 data-number=6.9.2><h3 data-number=6.9.2><span class=header-section-number>6.9.2</span>\n<a href=#toc:introducing-log-viewer>Introducing Log Viewer</a><a href=#introducing-log-viewer class=anchor aria-hidden=true></a></h3><p><a href=#subsubsec:log-viewer>Log viewer</a> is essentially a\nfront-end for <code>logcat</code>. It can be used to filter logs by\n<em>tag</em> or <em>pid</em> (process ID), or even by custom filters.\nLog levels AKA verbosity can also be configured. You can also save,\nshare and manage logs.</section><section id=lock-app-manager class=level3 data-number=6.9.3><h3 data-number=6.9.3><span class=header-section-number>6.9.3</span>\n<a href=#toc:lock-app-manager>Lock App Manager</a><a href=#lock-app-manager class=anchor aria-hidden=true></a></h3><p><a href=#subsubsec:screen-lock>Lock App Manager</a> with the screen\nlock configured for your device.</section><section id=extended-modes-for-app-ops class=level3 data-number=6.9.4><h3 data-number=6.9.4><span class=header-section-number>6.9.4</span>\n<a href=#toc:extended-modes-for-app-ops>Extended Modes for App\nOps</a><a href=#extended-modes-for-app-ops class=anchor aria-hidden=true></a></h3><p>You can set any mode for any app ops that your device supports,\neither from the <a href=#subsec:set-mode-for-app-ops-dots>1-click ops\npage</a> or from the <a href=#subsubsec:app-ops>app ops tab</a>.</section><section id=new-batch-ops-add-to-profile class=level3 data-number=6.9.5><h3 data-number=6.9.5><span class=header-section-number>6.9.5</span>\n<a href=#toc:new-batch-ops-add-to-profile>New Batch Ops: Add to\nProfile</a><a href=#new-batch-ops-add-to-profile class=anchor aria-hidden=true></a></h3><p>You can now easily add selected apps to an existing profile using the\nbatch operations.</section><section id=app-info-improved class=level3 data-number=6.9.6><h3 data-number=6.9.6><span class=header-section-number>6.9.6</span>\n<a href=#toc:app-info-improved>App Info: Improved</a><a href=#app-info-improved class=anchor aria-hidden=true></a></h3><p>App info tab now has many options, including the ability to change <a href=#sec:terminologies>SSAID</a>, network policy (i.e. background\nnetwork usage), battery optimization, etc. Most of the tags used in this\ntab are also clickable, and if you click on them, you will be able to\nlook at the current state or configure them right away.</section><section id=advanced-sort-and-filtering-options-in-the-main-page class=level3 data-number=6.9.7><h3 data-number=6.9.7><span class=header-section-number>6.9.7</span>\n<a href=#toc:advanced-sort-and-filtering-options-in-the-main-page>Advanced\nSort and Filtering Options in the Main Page</a><a href=#advanced-sort-and-filtering-options-in-the-main-page class=anchor aria-hidden=true></a></h3><p>Sort and filter options are now replaced by <a href=#subsubsec:main-list-options>List Options</a> which is highly\nconfigurable, including the ability to filter using profiles.</section><section id=about-this-device class=level3 data-number=6.9.8><h3 data-number=6.9.8><span class=header-section-number>6.9.8</span>\n<a href=#toc:about-this-device>About This Device</a><a href=#about-this-device class=anchor aria-hidden=true></a></h3><p>Interested in knowing about your device in just one page? Go to the\nbottom of the <a href=#subsec:device-info>settings page</a>.</section><section id=enabledisable-features class=level3 data-number=6.9.9><h3 data-number=6.9.9><span class=header-section-number>6.9.9</span>\n<a href=#toc:enabledisable-features>Enable/disable Features</a><a href=#enabledisable-features class=anchor aria-hidden=true></a></h3><p>Not interested in all the features that AM offers? You can disable\nsome features in <a href=#subsubsec:enable/disable-features>settings</a>.</section><section id=new-languages-1 class=level3 data-number=6.9.10><h3 data-number=6.9.10><span class=header-section-number>6.9.10</span> <a href=#toc:new-languages-1>New Languages</a><a href=#new-languages-1 class=anchor aria-hidden=true></a></h3><p>AM now has more than 19 languages! New languages include Farsi,\nJapanese and Traditional Chinese.</section><section id=signing-the-apk-files class=level3 data-number=6.9.11><h3 data-number=6.9.11><span class=header-section-number>6.9.11</span> <a href=#toc:signing-the-apk-files>Signing the APK Files</a><a href=#signing-the-apk-files class=anchor aria-hidden=true></a></h3><p>You can now import external signing keys in AM! For security, App\nManager has its own encrypted KeyStore which can also be <a href=#subsubsec:import/export-keystore>imported or exported</a>.</section><section id=new-extension-unapkm class=level3 data-number=6.9.12><h3 data-number=6.9.12><span class=header-section-number>6.9.12</span> <a href=#toc:new-extension-unapkm>New Extension: UnAPKM</a><a href=#new-extension-unapkm class=anchor aria-hidden=true></a></h3><p>Since APKMirror has removed encryption from their APKM files, it’s no\nlonger necessary to decrypt them. As a result, the option to decrypt\nAPKM files has been removed. Instead, this option is now provided by the\nUnAPKM extension which you can grab from <a href=https://f-droid.org/packages/io.github.muntashirakon.unapkm/>F-Droid</a>.\nSo, if you have an encrypted APKM file and have this extension\ninstalled, you can open the file directly in AM.</section></section><section id=sec:v2.5.20-(375) class=level2 data-number=6.10><h2 data-number=6.10><span class=header-section-number>6.10</span>\n<a href=#toc:sec:v2.5.20-(375)>v2.5.20 (375)</a><a href=#sec:v2.5.20-(375) class=anchor aria-hidden=true></a></h2><section id=subsec:introducing-profiles class=level3 data-number=6.10.1><h3 data-number=6.10.1><span class=header-section-number>6.10.1</span> <a href=#toc:subsec:introducing-profiles>Introducing Profiles</a><a href=#subsec:introducing-profiles class=anchor aria-hidden=true></a></h3><p><a href=#sec:profile-page>Profiles</a> finally closes the <a href=https://github.com/MuntashirAkon/AppManager/issues/72>related\nissue</a>. Profiles can be used to execute certain tasks repeatedly\nwithout doing everything manually. A profile can be applied (or invoked)\neither from the <a href=#sec:profiles-page>Profiles page</a> or from\nthe home screen by creating shortcuts. There are also some presets which\nconsist of debloating profiles taken from <a href=https://gitlab.com/W1nst0n/universal-android-debloater>Universal\nAndroid Debloater</a>.<section id=known-limitations class=level5 data-number=6.10.1.0.1><h5 data-number=6.10.1.0.1><span class=header-section-number>6.10.1.0.1</span> Known limitations<a href=#known-limitations class=anchor aria-hidden=true></a></h5><ul class=incremental><li><p>Exporting rules and applying permissions are not currently\nworking.<li><p>Profiles are applied for all users.</ul></section></section><section id=subsec:the-interceptor class=level3 data-number=6.10.2><h3 data-number=6.10.2><span class=header-section-number>6.10.2</span> <a href=#toc:subsec:the-interceptor>The Interceptor</a><a href=#subsec:the-interceptor class=anchor aria-hidden=true></a></h3><p><a href=https://github.com/MuntashirAkon/intent-intercept>Intent\nIntercept</a> works as a man-in-the-middle between source and\ndestination, that is, when you open a file or URL with another app, you\ncan see what is being shared by opening it with Interceptor first. You\ncan also add or modify the intents before sending them to the\ndestination. Additionally, you can double-click on any exportable\nactivities in the Activities tab in the App Details page to open them in\nthe Interceptor to add more configurations.<section id=known-limitation-2 class=level5 data-number=6.10.2.0.1><h5 data-number=6.10.2.0.1><span class=header-section-number>6.10.2.0.1</span> Known limitation<a href=#known-limitation-2 class=anchor aria-hidden=true></a></h5><p>Editing extras is not currently possible.</section></section><section id=subsec:unapkm:-dedrm-the-apkm-files class=level3 data-number=6.10.3><h3 data-number=6.10.3><span class=header-section-number>6.10.3</span> <a href=#toc:subsec:unapkm:-dedrm-the-apkm-files>UnAPKM: DeDRM the APKM\nfiles</a><a href=#subsec:unapkm:-dedrm-the-apkm-files class=anchor aria-hidden=true></a></h3><p>When I released a small tool called <a href=https://f-droid.org/en/packages/io.github.muntashirakon.unapkm>UnAPKM</a>,\nI promised that similar feature will be available in App Manager. I am\nproud to announce that you can open APKM files directly in the App Info\npage or convert them to APKS or install them directly.</section><section id=subsec:multiple-user class=level3 data-number=6.10.4><h3 data-number=6.10.4><span class=header-section-number>6.10.4</span> <a href=#toc:subsec:multiple-user>Multiple user</a><a href=#subsec:multiple-user class=anchor aria-hidden=true></a></h3><p>App manager now supports multiple users! For now, this requires root\nor ADB. But no-root support is also being considered. If you have\nmultiple users enabled and click on an app installed in multiple\nprofiles, an alert prompt will be displayed where you can select the\nuser.</section><section id=vive-la-france class=level3 data-number=6.10.5><h3 data-number=6.10.5><span class=header-section-number>6.10.5</span> <a href=#toc:vive-la-france>Vive la France!</a><a href=#vive-la-france class=anchor aria-hidden=true></a></h3><p>Thanks to the contributors, we have one more addition to the language\nclub: French. You can add more languages or improve existing\ntranslations at <a href=https://hosted.weblate.org/engage/app-manager>Weblate</a>.</section><section id=report-crashes class=level3 data-number=6.10.6><h3 data-number=6.10.6><span class=header-section-number>6.10.6</span> <a href=#toc:report-crashes>Report crashes</a><a href=#report-crashes class=anchor aria-hidden=true></a></h3><p>If App Manager crashes, you can now easily report the crash from the\nnotifications which opens the share options. Crashes are not reported by\nApp Manager, it only redirects you to your favourite Email client.</section><section id=android-11 class=level3 data-number=6.10.7><h3 data-number=6.10.7><span class=header-section-number>6.10.7</span> <a href=#toc:android-11>Android 11</a><a href=#android-11 class=anchor aria-hidden=true></a></h3><p>Added support for Android 11. Not everything may work as expected\nthough.</section><section id=app-installer-improvements class=level3 data-number=6.10.8><h3 data-number=6.10.8><span class=header-section-number>6.10.8</span> <a href=#toc:app-installer-improvements>App Installer Improvements</a><a href=#app-installer-improvements class=anchor aria-hidden=true></a></h3><section id=set-installation-locations class=level4 data-number=6.10.8.1><h4 data-number=6.10.8.1><span class=header-section-number>6.10.8.1</span> Set installation\nlocations<a href=#set-installation-locations class=anchor aria-hidden=true></a></h4><p>In settings page, you can set install locations such as auto\n(default), internal only and prefer external.</section><section id=set-apk-installer class=level4 data-number=6.10.8.2><h4 data-number=6.10.8.2><span class=header-section-number>6.10.8.2</span> Set APK installer<a href=#set-apk-installer class=anchor aria-hidden=true></a></h4><p>In settings page, you can also set default APK installer (root/ADB\nonly) instead of App Manager.</section><section id=multiple-users class=level4 data-number=6.10.8.3><h4 data-number=6.10.8.3><span class=header-section-number>6.10.8.3</span> Multiple users<a href=#multiple-users class=anchor aria-hidden=true></a></h4><p>In settings page, you can allow App Manager to display multiple users\nduring APK installation.</section><section id=signing-apk-files class=level4 data-number=6.10.8.4><h4 data-number=6.10.8.4><span class=header-section-number>6.10.8.4</span> Signing APK files<a href=#signing-apk-files class=anchor aria-hidden=true></a></h4><p>In settings page, you can choose to sign APK files before installing\nthem. You can also select which signature scheme to use in the <em>APK\nsigning</em> option in settings.<section id=known-limitation-3 class=level5 data-number=6.10.8.4.1><h5 data-number=6.10.8.4.1><span class=header-section-number>6.10.8.4.1</span> Known limitation<a href=#known-limitation-3 class=anchor aria-hidden=true></a></h5><p>Currently, only a generic key is used to sign APK files</section></section></section></section><section id=v2.5.17-368 class=level2 data-number=6.11><h2 data-number=6.11><span class=header-section-number>6.11</span>\n<a href=#toc:v2.5.17-368>v2.5.17 (368)</a><a href=#v2.5.17-368 class=anchor aria-hidden=true></a></h2><section id=app-installer class=level3 data-number=6.11.1><h3 data-number=6.11.1><span class=header-section-number>6.11.1</span> <a href=#toc:app-installer>App Installer</a><a href=#app-installer class=anchor aria-hidden=true></a></h3><p>As promised, it is now possible to select splits. AM also provides\nrecommendations based on device configurations. If the app is already\ninstalled, recommendations are provided based on the installed app. It\nis also possible to downgrade to a lower version without data loss if\nthe device has root or ADB. But it should be noted that not all app can\nbe downgraded. Installer is also improved to speed up the installation\nprocess, especially, for root users. If the app has already been\ninstalled and the new (x)apk(s) is newer or older or the same version\nwith a different signature, AM will display a list of changes similar to\n<strong>What’s New</strong> before prompting the user to install the\napp. This is useful if the app has introduced tracker components, new\npermissions, etc.<section id=known-limitations-1 class=level5 data-number=6.11.1.0.1><h5 data-number=6.11.1.0.1><span class=header-section-number>6.11.1.0.1</span> Known Limitations<a href=#known-limitations-1 class=anchor aria-hidden=true></a></h5><ul class=incremental><li><p>Large app can take a long time to fetch app info, and therefore,\nit may take a long time display the installation prompt.<li><p>If the apk is not located in the internal storage, the app has to\nbe cached first which might also take a long time depending on the size\nof the apk.</ul></section></section><section id=scanner-replacement-for-exodus-page class=level3 data-number=6.11.2><h3 data-number=6.11.2><span class=header-section-number>6.11.2</span> <a href=#toc:scanner-replacement-for-exodus-page>Scanner: Replacement for\nExodus Page</a><a href=#scanner-replacement-for-exodus-page class=anchor aria-hidden=true></a></h3><p>Exodus page is now replaced with scanner page. <a href=#sec:scanner-page>Scanner page</a> contains not only a list of\ntrackers but also a list of used libraries. This is just a start. In the\nfuture, this page will contain more in depth analysis of the app.</section><section id=introducing-system-config class=level3 data-number=6.11.3><h3 data-number=6.11.3><span class=header-section-number>6.11.3</span> <a href=#toc:introducing-system-config>Introducing System Config</a><a href=#introducing-system-config class=anchor aria-hidden=true></a></h3><p>System Config lists various system configurations and\nwhitelists/blacklists included in Android by either OEM/vendor, AOSP or\neven some Magisk modules. Root users can access this option from the\noverflow menu in the main page. There isn’t any official documentation\nfor these options therefore it’s difficult to write a complete\ndocumentation for this page. I will gradually add documentations using\nmy own knowledge. However, some functions should be understandable by\ntheir name.</section><section id=more-languages class=level3 data-number=6.11.4><h3 data-number=6.11.4><span class=header-section-number>6.11.4</span> <a href=#toc:more-languages>More Languages</a><a href=#more-languages class=anchor aria-hidden=true></a></h3><p>Thanks to the contributors, AM now has more than 12 languages. New\nlanguages include Bengali, Hindi, Norwegian, Polish, Russian, Simplified\nChinese, Turkish and Ukrainian.</section><section id=app-info-tab class=level3 data-number=6.11.5><h3 data-number=6.11.5><span class=header-section-number>6.11.5</span> <a href=#toc:app-info-tab>App Info Tab</a><a href=#app-info-tab class=anchor aria-hidden=true></a></h3><p>More tags are added in the <a href=#subsec:app-info-tab>app info\ntab</a> such as <strong>KeyStore</strong> (apps with KeyStore items),\n<strong>Systemless app</strong> (apps installed via Magisk),\n<strong>Running</strong> (apps that are running). For external apk, two\nmore options are added namely <strong>Reinstall</strong> and\n<strong>Downgrade</strong>. Now it is possible to share an apk via\nBluetooth. For system apps, it is possible to uninstall updates for\nroot/ADB users. But like the similar option in the system settings, this\noperation will clear all app data. As stated above, exodus has been\nreplaced with scanner.</section><section id=navigation-improvements class=level3 data-number=6.11.6><h3 data-number=6.11.6><span class=header-section-number>6.11.6</span> <a href=#toc:navigation-improvements>Navigation Improvements</a><a href=#navigation-improvements class=anchor aria-hidden=true></a></h3><p>It’s now relatively easy to navigate to various UI components using\nkeyboard. You can use up/down button to navigate between list items and\ntab button to navigate to UI components inside an item.</section><section id=running-apps-page class=level3 data-number=6.11.7><h3 data-number=6.11.7><span class=header-section-number>6.11.7</span> <a href=#toc:running-apps-page>Running Apps Page</a><a href=#running-apps-page class=anchor aria-hidden=true></a></h3><p>It is now possible to sort and filter processes in this tab. Also,\nthe three big buttons are replaced with an easy-to-use three dot menu.\nPreviously the memory usage was wrong which is fixed in this\nversion.</section><section id=built-in-toybox class=level3 data-number=6.11.8><h3 data-number=6.11.8><span class=header-section-number>6.11.8</span> <a href=#toc:built-in-toybox>Built-in Toybox</a><a href=#built-in-toybox class=anchor aria-hidden=true></a></h3><p>Toybox (an alternative to busybox) is bundled with AM. Although\nAndroid has this utility built-in from API 23, toybox is bundled in\norder to prevent buggy implementations and to support API &lt; 23.</section><section id=component-blocker-improvements class=level3 data-number=6.11.9><h3 data-number=6.11.9><span class=header-section-number>6.11.9</span> <a href=#toc:component-blocker-improvements>Component Blocker\nImprovements</a><a href=#component-blocker-improvements class=anchor aria-hidden=true></a></h3><p>Component blocker seemed to be problematic in the previous version,\nespecially when global component blocking is enabled. The issues are\nmostly fixed now.<div class=\"amalert warning\"><p><strong><em>Caution.</em></strong><p>The component blocking mechanism is no longer compatible with v2.5.6\ndue to various security issues. If you have this version, upgrade to\nv2.5.13 or earlier versions first. After that, enable <a href=#subsubsec:instant-component-blocking>global component\nblocking</a> and disable it again.</div></section><section id=improvements-in-the-app-details-page class=level3 data-number=6.11.10><h3 data-number=6.11.10><span class=header-section-number>6.11.10</span> <a href=#toc:improvements-in-the-app-details-page>Improvements in the App\nDetails Page</a><a href=#improvements-in-the-app-details-page class=anchor aria-hidden=true></a></h3><p>Value of various app ops depend on their parent app ops. Therefore,\nwhen you allow/deny an app op, the parent of the app op gets modified.\nThis fixes the issues some users have been complaining regarding some\napp ops that couldn’t be changed.<p>If an app has the target API 23 or less, its permissions cannot be\nmodified using the <code>pm grant …</code> command. Therefore, for such\napps, option to toggle permission has been disabled.<p>The signature tab is improved to support localization. It also\ndisplays multiple checksums for a signature.</section><section id=app-manifest class=level3 data-number=6.11.11><h3 data-number=6.11.11><span class=header-section-number>6.11.11</span> <a href=#toc:app-manifest>App Manifest</a><a href=#app-manifest class=anchor aria-hidden=true></a></h3><p>Manifest no longer crashes if the size of the manifest is too long.\nGenerated manifest are now more accurate than before.</section></section><section id=v2.5.13-348 class=level2 data-number=6.12><h2 data-number=6.12><span class=header-section-number>6.12</span>\n<a href=#toc:v2.5.13-348>v2.5.13 (348)</a><a href=#v2.5.13-348 class=anchor aria-hidden=true></a></h2><section id=bundled-app-split-apk class=level3 data-number=6.12.1><h3 data-number=6.12.1><span class=header-section-number>6.12.1</span> <a href=#toc:bundled-app-split-apk>Bundled App (Split APK)</a><a href=#bundled-app-split-apk class=anchor aria-hidden=true></a></h3><p>Bundled app formats such as <strong>apks</strong> and\n<strong>xapk</strong> are now supported. You can install these apps\nusing the regular installation buttons. For root and adb users, apps are\ninstalled using shell, and for non-root users, the platform default\nmethod is used.<section id=known-limitations-2 class=level5 data-number=6.12.1.0.1><h5 data-number=6.12.1.0.1><span class=header-section-number>6.12.1.0.1</span> Known Limitations<a href=#known-limitations-2 class=anchor aria-hidden=true></a></h5><ul class=incremental><li><p>Currently <em>all</em> splits apks are installed. But this\nbehaviour is going to change in the next release. If you only need a few\nsplits instead of all, extract the <strong>APKS</strong> or\n<strong>XAPK</strong> file, and then, create a new zip file with your\ndesired split apks and replace the <strong>ZIP</strong> extension with\n<strong>APKS</strong>. Now, open it with AM.<li><p>There is no progress dialog to display the installation\nprogress.</ul></section></section><section id=direct-install-support class=level3 data-number=6.12.2><h3 data-number=6.12.2><span class=header-section-number>6.12.2</span> <a href=#toc:direct-install-support>Direct Install Support</a><a href=#direct-install-support class=anchor aria-hidden=true></a></h3><p>You can now install <strong>APK</strong>, <strong>APKS</strong> or\n<strong>XAPK</strong> directly from your favourite browser or file\nmanager. For apps that need updates, a <strong>What’s New</strong>\ndialog is displayed showing the changes in the new version.<section id=known-limitations-3 class=level5 data-number=6.12.2.0.1><h5 data-number=6.12.2.0.1><span class=header-section-number>6.12.2.0.1</span> Known Limitations<a href=#known-limitations-3 class=anchor aria-hidden=true></a></h5><ul class=incremental><li><p>Downgrade is not yet possible.<li><p>There is no progress dialog to display the installation progress.\nIf you cannot interact with the current page, wait until the\ninstallation is finished.</ul></section></section><section id=remove-all-blocking-rules class=level3 data-number=6.12.3><h3 data-number=6.12.3><span class=header-section-number>6.12.3</span> <a href=#toc:remove-all-blocking-rules>Remove All Blocking Rules</a><a href=#remove-all-blocking-rules class=anchor aria-hidden=true></a></h3><p>In the Settings page, a new option is added which can be used to\nremove all blocking rules configured within App Manager.</section><section id=app-ops-1 class=level3 data-number=6.12.4><h3 data-number=6.12.4><span class=header-section-number>6.12.4</span> <a href=#toc:app-ops-1>App\nOps</a><a href=#app-ops-1 class=anchor aria-hidden=true></a></h3><ul class=incremental><li><p>App Ops are now generated using a technique similar to AppOpsX.\nThis should decrease the loading time significantly in the App Ops\ntab.<li><p>In the App Ops tab, a menu item is added which can be used to\nlist only active app ops without including the default app ops. The\npreference is saved in the shared preferences.</ul><section id=known-limitation-4 class=level5 data-number=6.12.4.0.1><h5 data-number=6.12.4.0.1><span class=header-section-number>6.12.4.0.1</span> Known Limitation<a href=#known-limitation-4 class=anchor aria-hidden=true></a></h5><p>Often the App Ops tab may not be responsive. If that’s the case,\nrestart App Manager.</section></section><section id=enhanced-adb-support class=level3 data-number=6.12.5><h3 data-number=6.12.5><span class=header-section-number>6.12.5</span> <a href=#toc:enhanced-adb-support>Enhanced ADB Support</a><a href=#enhanced-adb-support class=anchor aria-hidden=true></a></h3><p>ADB shell commands are now executed using a technique similar to\nAppOpsX (This is the <em>free</em> alternative of AppOps by Rikka.).\nThis should dramatically increase the execution time.<section id=known-limitation-5 class=level5 data-number=6.12.5.0.1><h5 data-number=6.12.5.0.1><span class=header-section-number>6.12.5.0.1</span> Known Limitation<a href=#known-limitation-5 class=anchor aria-hidden=true></a></h5><p>AM can often crash or become not responsive. If that’s the case,\nrestart App Manager.</section></section><section id=filtering-in-main-page class=level3 data-number=6.12.6><h3 data-number=6.12.6><span class=header-section-number>6.12.6</span> <a href=#toc:filtering-in-main-page>Filtering in Main Page</a><a href=#filtering-in-main-page class=anchor aria-hidden=true></a></h3><p>Add an option to filter apps that has at least one activity.</section><section id=apk-backupsharing class=level3 data-number=6.12.7><h3 data-number=6.12.7><span class=header-section-number>6.12.7</span> <a href=#toc:apk-backupsharing>Apk Backup/Sharing</a><a href=#apk-backupsharing class=anchor aria-hidden=true></a></h3><p>Apk files are now saved as <code>app name_version.extension</code>\ninstead of <code>package.name.extension</code>.</section><section id=batch-ops class=level3 data-number=6.12.8><h3 data-number=6.12.8><span class=header-section-number>6.12.8</span> <a href=#toc:batch-ops>Batch Ops</a><a href=#batch-ops class=anchor aria-hidden=true></a></h3><ul class=incremental><li><p>Added a foreground service to run batch operations. The result of\nthe operation is displayed in a notification. If an operation has failed\nfor some packages, clicking on the notification will open a dialog box\nlisting the failed packages. There is also a <strong>Try Again</strong>\nbutton on the bottom which can be used to perform the operation again\nfor the failed packages.<li><p>Replaced Linux <em>kill</em> with\n<strong>force-stop</strong>.</ul></section><section id=translations class=level3 data-number=6.12.9><h3 data-number=6.12.9><span class=header-section-number>6.12.9</span> <a href=#toc:translations>Translations</a><a href=#translations class=anchor aria-hidden=true></a></h3><p>Added German and Portuguese (Brazilian) translations.<section id=known-limitation-6 class=level5 data-number=6.12.9.0.1><h5 data-number=6.12.9.0.1><span class=header-section-number>6.12.9.0.1</span> Known Limitation<a href=#known-limitation-6 class=anchor aria-hidden=true></a></h5><p>Not all translations are verified yet.</section></section><section id=app-data-backup class=level3 data-number=6.12.10><h3 data-number=6.12.10><span class=header-section-number>6.12.10</span> <a href=#toc:app-data-backup>App Data Backup</a><a href=#app-data-backup class=anchor aria-hidden=true></a></h3><p>Install app only for the current user at the time of restoring\nbackups. Support for split apks is also added.<p><em>Data backup feature is now considered unstable. If you encounter\nany problem, please report to me without hesitation.</em></section></section></section><section id=ch:app-ops class=level1 data-number=7><h1 data-number=7><span class=header-section-number>7</span> <a href=#toc:ch:app-ops>App Ops</a><a href=#ch:app-ops class=anchor aria-hidden=true></a></h1><section id=sec:app-ops-background class=level2 data-number=7.1><h2 data-number=7.1><span class=header-section-number>7.1</span> <a href=#toc:sec:app-ops-background>Background</a><a href=#sec:app-ops-background class=anchor aria-hidden=true></a></h2><p><strong>App Ops</strong> (short hand for <strong>Application\nOperations</strong>) are used by Android system (since Android 4.3) to\ncontrol application permissions. The user <em>can</em> control some\npermissions, but only the permissions that are considered dangerous (and\nGoogle thinks knowing your phone number isn’t a dangerous thing). So,\napp ops seems to be the one we need if we want to install apps like\nFacebook and it’s Messenger (the latter literary records everything if\nyou live outside the EU) and still want <em>some</em> privacy and/or\nsecurity. Although certain features of app ops were available in\nSettings and later in hidden settings in older version of Android, it’s\ncompletely hidden in newer versions of Android and is continued to be\nkept hidden. Now, any app with\n<strong>android.Manifest.permission.GET_APP_OPS_STATS</strong>\npermission can get the app ops information for other applications but\nthis permission is hidden from users and can only be enabled using ADB\nor root. Still, the app with this permission cannot grant or revoke\npermissions (actually mode of operation) for apps other than itself\n(with limited capacity, of course). To modify the ops of other app, the\napp needs\n<strong>android.Manifest.permission.UPDATE_APP_OPS_STATS</strong>\npermissions which isn’t accessible via <code>pm</code> command. So, you\ncannot grant it via root or ADB, the permission is only granted to the\nsystem apps. There are very few apps who support disabling permissions\nvia app ops. The best one to my knowledge is <a href=https://github.com/8enet/AppOpsX>AppOpsX</a>. The main (visible)\ndifference between my app (AppManager) and this app is that the latter\nalso provides you the ability to revoke internet permissions (by writing\nip tables). One crucial problem that I faced during the development of\nthe app ops API is the lack of documentation in English language.</section><section id=sec:introduction-to-app-ops class=level2 data-number=7.2><h2 data-number=7.2><span class=header-section-number>7.2</span> <a href=#toc:sec:introduction-to-app-ops>Introduction to App Ops</a><a href=#sec:introduction-to-app-ops class=anchor aria-hidden=true></a></h2><figure id=fig:appops><figure><object data=../images/appops.svg type=image/svg+xml></object></figure><figcaption>Figure 2: How app ops work</figcaption></figure><p>Figure <a href=#fig:appops>1</a> describes the process of changing\nand processing permission. <a href=#sec:appopsmanager>AppOpsManager</a> can be used to manage\npermissions in Settings app. <strong>AppOpsManager</strong> is also\nuseful in determining if a certain permission (or operation) is granted\nto the application. Most of the methods of\n<strong>AppOpsManager</strong> are accessible to the user app but unlike\na system app, it can only be used to check permissions for any app or\nfor the app itself and start or terminating certain operations.\nMoreover, not all operations are actually accessible from this Java\nclass. <strong>AppOpsManager</strong> holds all the necessary constants\nsuch as <a href=#subsec:op-constants><code>OP_*</code></a>,\n<code>OPSTR_*</code>, <a href=#subsec:mode-constants><code>MODE_*</code></a> which describes\noperation code, operation string and mode of operations respectively. It\nalso holds necessary data structures such as <a href=#subsec:package-ops>PackageOps</a> and <strong>OpEntry</strong>.\n<strong>PackageOps</strong> holds <strong>OpEntry</strong> for a\npackage, and <strong>OpEntry</strong>, as the name suggests, describes\neach operation.<p><code>AppOpService</code> is completely hidden from a user\napplication but accessible to the system applications. As it can be seen\nin Figure <a href=#fig:appops>1</a>, this is the class that does the\nactual management stuff. It contains data structures such as\n<strong>Ops</strong> to store basic package info and <strong>Op</strong>\nwhich is similar to <strong>OpEntry</strong> of\n<strong>AppOpsManager</strong>. It also has <strong>Shell</strong> which\nis actually the source code of the <a href=#sec:appops-cli><em>appops</em> command line tool</a>. It writes\nconfigurations to or read configurations from <a href=#sec:appops-xml><code>/data/system/appops.xml</code></a>. System\nservices calls <strong>AppOpsService</strong> to find out what an\napplication is allowed and what is not allowed to perform, and\n<strong>AppOpsService</strong> determines these permissions by parsing\n<code>/data/system/appops.xml</code>. If no custom values are present in\n<em>appops.xml</em>, it returns the default mode available in\n<strong>AppOpsManager</strong>.</section><section id=sec:appopsmanager class=level2 data-number=7.3><h2 data-number=7.3><span class=header-section-number>7.3</span> <a href=#toc:sec:appopsmanager>AppOpsManager</a><a href=#sec:appopsmanager class=anchor aria-hidden=true></a></h2><p><a href=https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/app/AppOpsManager.java>AppOpsManager</a>\nstands for application operations manager. It consists of various\nconstants and classes to modify app operations.<div class=seealso-inline><p><em>こちらもご覧ください: <span><a href=https://developer.android.com/reference/android/app/AppOpsManager>AppOpsManager\ndocumentation</a></span></em></div><section id=subsec:op-constants class=level3 data-number=7.3.1><h3 data-number=7.3.1><span class=header-section-number>7.3.1</span>\n<a href=#toc:subsec:op-constants><code>OP_*</code> Constants</a><a href=#subsec:op-constants class=anchor aria-hidden=true></a></h3><p><code>OP_*</code> are the integer constants starting from\n<code>0</code>. <code>OP_NONE</code> implies that no operations are\nspecified whereas <code>_NUM_OP</code> denotes the number of operations\ndefined in <code>OP_*</code> prefix. While they denote each operation,\nthe operations are not necessarily unique. In fact, there are many\noperations that are actually a single operation denoted by multiple\n<code>OP_*</code> constant (possibly for future use). Vendors may define\ntheir own op based on their requirements. MIUI is one of the vendors who\nare known to do that.<div class=listing><div class=sourceCode id=cb11 data-frame=lines><pre class=\"sourceCode java\"><code class=\"sourceCode java\"><span id=cb11-1><a href=#cb11-1 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=dt>final</span> <span class=dt>int</span> OP_NONE <span class=op>=</span> <span class=op>-</span><span class=dv>1</span><span class=op>;</span></span>\n<span id=cb11-2><a href=#cb11-2 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=dt>final</span> <span class=dt>int</span> OP_COARSE_LOCATION <span class=op>=</span> <span class=dv>0</span><span class=op>;</span></span>\n<span id=cb11-3><a href=#cb11-3 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=dt>final</span> <span class=dt>int</span> OP_FINE_LOCATION <span class=op>=</span> <span class=dv>1</span><span class=op>;</span></span>\n<span id=cb11-4><a href=#cb11-4 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=dt>final</span> <span class=dt>int</span> OP_GPS <span class=op>=</span> <span class=dv>2</span><span class=op>;</span></span>\n<span id=cb11-5><a href=#cb11-5 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=dt>final</span> <span class=dt>int</span> OP_VIBRATE <span class=op>=</span> <span class=dv>3</span><span class=op>;</span></span>\n<span id=cb11-6><a href=#cb11-6 aria-hidden=true tabindex=-1></a><span class=kw>...</span></span>\n<span id=cb11-7><a href=#cb11-7 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=dt>final</span> <span class=dt>int</span> OP_READ_DEVICE_IDENTIFIERS <span class=op>=</span> <span class=dv>89</span><span class=op>;</span></span>\n<span id=cb11-8><a href=#cb11-8 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=dt>final</span> <span class=dt>int</span> OP_ACCESS_MEDIA_LOCATION <span class=op>=</span> <span class=dv>90</span><span class=op>;</span></span>\n<span id=cb11-9><a href=#cb11-9 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=dt>final</span> <span class=dt>int</span> OP_ACTIVATE_PLATFORM_VPN <span class=op>=</span> <span class=dv>91</span><span class=op>;</span></span>\n<span id=cb11-10><a href=#cb11-10 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=dt>final</span> <span class=dt>int</span> _NUM_OP <span class=op>=</span> <span class=dv>92</span><span class=op>;</span></span></code></pre></div></div><p>Whether an operation is unique is defined by\n<code>sOpToSwitch</code>. It maps each operation to another operation or\nto itself (if it’s a unique operation). For instance,\n<code>OP_FINE_LOCATION</code> and <code>OP_GPS</code> are mapped to\n<code>OP_COARSE_LOCATION</code>.<p>Each operation has a private name which are described by\n<code>sOpNames</code>. These names are usually the same names as the\nconstants without the <code>OP_</code> prefix. Some operations have\npublic names as well which are described by <code>sOpToString</code>.\nFor instance, <code>OP_COARSE_LOCATION</code> has the public name\n<strong>android:coarse_location</strong>.<p>As a gradual process of moving permissions to app ops, there are\nalready many permissions that are defined under some operations. These\npermissions are mapped in <code>sOpPerms</code>. For example, the\npermission\n<strong>android.Manifest.permission.ACCESS_COARSE_LOCATION</strong> is\nmapped to <code>OP_COARSE_LOCATION</code>. Some operations may not have\nany associated permissions which have <code>null</code> values.<p>As described in the previous section, operations that are configured\nfor an app are stored at <a href=#sec:appops-xml><code>/data/system/appops.xml</code></a>. If an\noperation is not configured, then whether system will allow that\noperation is determined from <code>sOpDefaultMode</code>. It lists the\n<em>default mode</em> for each operation.</section><section id=subsec:mode-constants class=level3 data-number=7.3.2><h3 data-number=7.3.2><span class=header-section-number>7.3.2</span>\n<a href=#toc:subsec:mode-constants><code>MODE_*</code> Constants</a><a href=#subsec:mode-constants class=anchor aria-hidden=true></a></h3><p><code>MODE_*</code> constants also integer constants starting from\n<code>0</code>. These constants are assigned to each operation\ndescribing whether an app is authorised to perform that operation. These\nmodes usually have associated names such as <strong>allow</strong> for\n<code>MODE_ALLOWED</code>, <strong>ignore</strong> for\n<code>MODE_IGNORED</code>, <strong>deny</strong> for\n<code>MODE_ERRORED</code> (a rather misnomer), <strong>default</strong>\nfor <code>MODE_DEFAULT</code> and <strong>foreground</strong> for\n<code>MODE_FOREGROUND</code>.<ol class=incremental><li><p><strong><code>MODE_ALLOWED</code>.</strong> The app is allowed to\nperform the given operation<li><p><strong><code>MODE_IGNORED</code>.</strong> The app is not\nallowed to perform the given operation, and any attempt to perform the\noperation should <em>silently fail</em>, i.e. it should not cause the\napp to crash<li><p><strong><code>MODE_ERRORED</code>.</strong> The app is not\nallowed to perform the given operation, and this attempt should cause it\nto have a fatal error, typically a\n<code>SecurityException</code><li><p><strong><code>MODE_DEFAULT</code>.</strong> The app should use\nits default security check, specified in\n<code>AppOpsManager</code><li><p><strong><code>MODE_FOREGROUND</code>.</strong> Special mode that\nmeans “allow only when app is in foreground.” This mode was added in\nAndroid 10<li><p><strong><code>MODE_ASK</code>.</strong> This is a custom mode\nused by MIUI whose uses are unknown.</ol></section><section id=subsec:package-ops class=level3 data-number=7.3.3><h3 data-number=7.3.3><span class=header-section-number>7.3.3</span>\n<a href=#toc:subsec:package-ops>PackageOps</a><a href=#subsec:package-ops class=anchor aria-hidden=true></a></h3><p><strong>AppOpsManager.PackageOps</strong> is a data structure to\nstore all the <strong>OpEntry</strong> for a package. In simple terms,\nit stores all the customised operations for a package.<div class=listing><div class=sourceCode id=cb12 data-frame=lines><pre class=\"sourceCode java\"><code class=\"sourceCode java\"><span id=cb12-1><a href=#cb12-1 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=kw>class</span> PackageOps <span class=kw>implements</span> Parcelable <span class=op>{</span></span>\n<span id=cb12-2><a href=#cb12-2 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=bu>String</span> mPackageName<span class=op>;</span></span>\n<span id=cb12-3><a href=#cb12-3 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=dt>int</span> mUid<span class=op>;</span></span>\n<span id=cb12-4><a href=#cb12-4 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=bu>List</span><span class=op>&lt;</span>OpEntry<span class=op>&gt;</span> mEntries<span class=op>;</span></span>\n<span id=cb12-5><a href=#cb12-5 aria-hidden=true tabindex=-1></a>    <span class=kw>...</span></span>\n<span id=cb12-6><a href=#cb12-6 aria-hidden=true tabindex=-1></a><span class=op>}</span></span></code></pre></div></div><p>As can be seen in Listing <a href=#lst:package-ops-class>2</a>, it\nstores all <strong>OpEntry</strong> for a package as well as the\ncorresponding package name and its kernel user ID.</section><section id=subsec:opentry class=level3 data-number=7.3.4><h3 data-number=7.3.4><span class=header-section-number>7.3.4</span>\n<a href=#toc:subsec:opentry>OpEntry</a><a href=#subsec:opentry class=anchor aria-hidden=true></a></h3><p><strong>AppOpsManager.OpEntry</strong> is a data structure that\nstores a single operation for any package.<div class=listing><div class=sourceCode id=cb13 data-frame=lines><pre class=\"sourceCode java\"><code class=\"sourceCode java\"><span id=cb13-1><a href=#cb13-1 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=dt>final</span> <span class=kw>class</span> OpEntry <span class=kw>implements</span> Parcelable <span class=op>{</span></span>\n<span id=cb13-2><a href=#cb13-2 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=dt>int</span> mOp<span class=op>;</span></span>\n<span id=cb13-3><a href=#cb13-3 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=dt>boolean</span> mRunning<span class=op>;</span></span>\n<span id=cb13-4><a href=#cb13-4 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=at>@Mode</span> <span class=dt>int</span> mMode<span class=op>;</span></span>\n<span id=cb13-5><a href=#cb13-5 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=at>@Nullable</span> LongSparseLongArray mAccessTimes<span class=op>;</span></span>\n<span id=cb13-6><a href=#cb13-6 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=at>@Nullable</span> LongSparseLongArray mRejectTimes<span class=op>;</span></span>\n<span id=cb13-7><a href=#cb13-7 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=at>@Nullable</span> LongSparseLongArray mDurations<span class=op>;</span></span>\n<span id=cb13-8><a href=#cb13-8 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=at>@Nullable</span> LongSparseLongArray mProxyUids<span class=op>;</span></span>\n<span id=cb13-9><a href=#cb13-9 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=at>@Nullable</span> LongSparseArray<span class=op>&lt;</span><span class=bu>String</span><span class=op>&gt;</span> mProxyPackageNames<span class=op>;</span></span>\n<span id=cb13-10><a href=#cb13-10 aria-hidden=true tabindex=-1></a>    <span class=kw>...</span></span>\n<span id=cb13-11><a href=#cb13-11 aria-hidden=true tabindex=-1></a><span class=op>}</span></span></code></pre></div></div><p>Here:<ul class=incremental><li><p><code>mOp</code>: Denotes one of the <a href=#subsec:op-constants><code>OP_*</code> constants</a><li><p><code>mRunning</code>: Whether the operation is in progress\n(i.e. the operation has started but not finished yet). Not all\noperations can be started or finished this way<li><p><code>mMOde</code>: One of the <a href=#subsec:mode-constants><code>MODE_*</code> constants</a><li><p><code>mAccessTimes</code>: Stores all the available access\ntimes<li><p><code>mRejectTimes</code>: Stores all the available reject\ntimes<li><p><code>mDurations</code>: All available access durations, checking\nthis with <code>mRunning</code> will tell you for how long the app is\nperforming a certain app operation<li><p><code>mProxyUids</code>: No documentation found<li><p><code>mProxyPackageNames:</code> No documentation found</ul></section><section id=subsec:usage class=level3 data-number=7.3.5><h3 data-number=7.3.5><span class=header-section-number>7.3.5</span>\n<a href=#toc:subsec:usage>Usage</a><a href=#subsec:usage class=anchor aria-hidden=true></a></h3><p>TODO</section></section><section id=sec:appopsservice class=level2 data-number=7.4><h2 data-number=7.4><span class=header-section-number>7.4</span> <a href=#toc:sec:appopsservice>AppOpsService</a><a href=#sec:appopsservice class=anchor aria-hidden=true></a></h2><p>TODO</section><section id=sec:appops-xml class=level2 data-number=7.5><h2 data-number=7.5><span class=header-section-number>7.5</span> <a href=#toc:sec:appops-xml>appops.xml</a><a href=#sec:appops-xml class=anchor aria-hidden=true></a></h2><p>Latest <code>appops.xml</code> has the following format: (This DTD is\nmade by me and by no means perfect, has compatibility issues.)<pre><code>&lt;!DOCTYPE app-ops [\n\n&lt;!ELEMENT app-ops (uid|pkg)*&gt;\n&lt;!ATTLIST app-ops v CDATA #IMPLIED&gt;\n\n&lt;!ELEMENT uid (op)*&gt;\n&lt;!ATTLIST uid n CDATA #REQUIRED&gt;\n\n&lt;!ELEMENT pkg (uid)*&gt;\n&lt;!ATTLIST pkg n CDATA #REQUIRED&gt;\n\n&lt;!ELEMENT uid (op)*&gt;\n&lt;!ATTLIST uid\nn CDATA #REQUIRED\np CDATA #IMPLIED&gt;\n\n&lt;!ELEMENT op (st)*&gt;\n&lt;!ATTLIST op\nn CDATA #REQUIRED\nm CDATA #REQUIRED&gt;\n\n&lt;!ELEMENT st EMPTY&gt;\n&lt;!ATTLIST st\nn CDATA #REQUIRED\nt CDATA #IMPLIED\nr CDATA #IMPLIED\nd CDATA #IMPLIED\npp CDATA #IMPLIED\npu CDATA #IMPLIED&gt;\n\n]&gt;</code></pre><p>The instruction below follows the exact order given above:<ul class=incremental><li><p><code>app-ops</code>: The root element. It can contain any number\nof <code>pkg</code> or package <code>uid</code><ul class=incremental><li><p><code>v</code>: (optional, integer) The version number (default:\n<code>NO_VERSION</code> or <code>-1</code>)</ul><li><p><code>pkg</code>: Stores package info. It can contain any number\nof <code>uid</code><ul class=incremental><li><p><code>n</code>: (required, string) Name of the package</ul><li><p>Package <code>uid</code>: Stores package or packages info<ul class=incremental><li><p><code>n</code>: (required, integer) The user ID</ul><li><p><code>uid</code>: The package user ID. It can contain any number\nof <code>op</code><ul class=incremental><li><p><code>n</code>: (required, integer) The user ID<li><p><code>p</code>: (optional, boolean) Is the app is a\nprivate/system app</ul><li><p><code>op</code>: The operation, can contain <code>st</code> or\nnothing at all<ul class=incremental><li><p><code>n</code>: (required, integer) The op name in integer,\ni.e. AppOpsManager.OP_*<li><p><code>m</code>: (required, integer) The op mode,\ni.e. AppOpsManager.MODE_*</ul><li><p><code>st</code>: State of operation: whether the operation is\naccessed, rejected or running (not available on old versions)<ul class=incremental><li><p><code>n</code>: (required, long) Key containing flags and\nuid<li><p><code>t</code>: (optional, long) Access time (default:\n<code>0</code>)<li><p><code>r</code>: (optional, long) Reject time (default:\n<code>0</code>)<li><p><code>d</code>: (optional, long) Access duration (default:\n<code>0</code>)<li><p><code>pp</code>: (optional, string) Proxy package name<li><p><code>pu</code>: (optional, integer) Proxy package uid</ul></ul><p>This definition can be found at <a href=https://android.googlesource.com/platform/frameworks/base/+/master/services/core/java/com/android/server/appop/AppOpsService.java>AppOpsService</a>.</section><section id=sec:appops-cli class=level2 data-number=7.6><h2 data-number=7.6><span class=header-section-number>7.6</span> <a href=#toc:sec:appops-cli>Command Line Interface</a><a href=#sec:appops-cli class=anchor aria-hidden=true></a></h2><p><code>appops</code> or <code>cmd appops</code> (on latest versions)\ncan be accessible via ADB or root. This is an easier method to get or\nupdate any operation for a package (provided the package name is known).\nThe help page of this command is self-explanatory:<pre><code>AppOps service (appops) commands:\nhelp\nPrint this help text.\nstart [--user &lt;USER_ID&gt;] &lt;PACKAGE | UID&gt; &lt;OP&gt;\nStarts a given operation for a particular application.\nstop [--user &lt;USER_ID&gt;] &lt;PACKAGE | UID&gt; &lt;OP&gt;\nStops a given operation for a particular application.\nset [--user &lt;USER_ID&gt;] &lt;[--uid] PACKAGE | UID&gt; &lt;OP&gt; &lt;MODE&gt;\nSet the mode for a particular application and operation.\nget [--user &lt;USER_ID&gt;] &lt;PACKAGE | UID&gt; [&lt;OP&gt;]\nReturn the mode for a particular application and optional operation.\nquery-op [--user &lt;USER_ID&gt;] &lt;OP&gt; [&lt;MODE&gt;]\nPrint all packages that currently have the given op in the given mode.\nreset [--user &lt;USER_ID&gt;] [&lt;PACKAGE&gt;]\nReset the given application or all applications to default modes.\nwrite-settings\nImmediately write pending changes to storage.\nread-settings\nRead the last written settings, replacing current state in RAM.\noptions:\n&lt;PACKAGE&gt; an Android package name or its UID if prefixed by --uid\n&lt;OP&gt;      an AppOps operation.\n&lt;MODE&gt;    one of allow, ignore, deny, or default\n&lt;USER_ID&gt; the user id under which the package is installed. If --user is not\nspecified, the current user is assumed.</code></pre></section></section><section id=footnotes class=\"footnotes footnotes-end-of-document\" role=doc-endnotes><hr><ol><li id=fn1><p>安定版リリースのみ<a href=#fnref1 class=footnote-back role=doc-backlink>↩︎</a><li id=fn2><p>GitHubのプルリクエストは、対応するパッチを使用して手動でマージされます。そのため、GitHub\nは誤ってそれらをマージせずにクローズしたとして認識してしまいます。<a href=#fnref2 class=footnote-back role=doc-backlink>↩︎</a><li id=fn3><p>“Muntashir Akon”と呼ぶこともできます。<a href=#fnref3 class=footnote-back role=doc-backlink>↩︎</a></ol></section>"
  },
  {
    "path": "docs/raw/ja/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources xmlns:xliff=\"urn:oasis:names:tc:xliff:document:1.2\">\n    <string name=\"faq$aot$$section-title\">TCP経由のADB</string>\n    <string name=\"faq$aot$$restart-title\">再起動するたびにTCP経由のADBを再度有効にしなければなりませんか？</string>\n    <string name=\"faq$aot$$usb-debugging-title\">USBデバッグを有効にできません。どうすればよいですか？</string>\n    <string name=\"faq$aot$$block-tracker-title\">ADBモードでもトラッカーやその他のアプリコンポーネントをブロックすることができますか？</string>\n    <string name=\"faq$aot$$feature-adb-title\">ADBモードではどのような機能が利用できますか？</string>\n    <string name=\"faq$aot$restart\">残念ながらそうです。しかしv2.5.13以降では、サーバー・クライアント方式によりシステムと対話的に動作するため、\n\\nTCP経由のADBを常に有効にしておく必要はありません。但し\\\\textbf{開発者向けオプション}の\n\\n\\\\textbf{USBデバッグ}を有効にしておく必要があります。そのためには、\\\\hyperref[sec:adb-over-tcp]{TCP経由のADB}を有効にした状態でApp Manager\n\\nを起動してください。そうすると、\\\\textit{ADBモードで動作中}とトースト通知が画面下部に表示されます。その後はTCPサーバーを停止させて構いません。\n\\nLineageやその派生システムではTCP経由のADBをPCなしでも切り替えできます。\n\\n\\\\textbf{ネットワーク経由のADB} オプションが\\\\textbf{USBデバッグ}オプションの下部に存在します。但し後者の場合ではTCPサーバーを停止できません。</string>\n    <string name=\"faq$aot$usb-debugging\">チャプター \\\\ref{ch:guides}の§\\\\ref{subsec:enable-usb-debugging}をご確認ください。</string>\n    <string name=\"faq$aot$block-tracker\">残念ながらできません。ADBでは限られた \\\\href{https://github.com/aosp-mirror/platform_frameworks_base/blob/master/packages/Shell/AndroidManifest.xml}{権限}\n\\nしか利用できず、アプリのコンポーネント制御はこの中に含まれません。</string>\n    <string name=\"faq$aot$feature-adb\">ADBモードではAppManagerの殆どの機能が利用でき、ADBモードが検出された際、自動的に有効になります。\n\\nアプリを無効化、強制停止、データーを消去、AppOpsやアプリ権限を拒否/許可などの機能も含まれます。\n\\nまたアプリを確認画面無しでインストールしたり、 \\\\hyperref[subsubsec:main:running-apps]{実行中のアプリ/プロセス}の確認も可能です。</string>\n    <string name=\"intro$main$$introduction-chapter-title\">はじめに</string>\n    <string name=\"intro$main$$terminologies-title\">用語の定義</string>\n    <string name=\"intro$main$$supported-versions-title\">対応バージョン</string>\n    <string name=\"intro$main$$official-sources-title\">公式ソース</string>\n    <string name=\"intro$main$$bin-sources-title\">バイナリ配布ソース</string>\n    <string name=\"intro$main$$source-code-links-title\">ソースコードへのリンク</string>\n    <string name=\"intro$main$$translations-title\">翻訳</string>\n    <string name=\"intro$main$$contributing-title\">貢献する</string>\n    <string name=\"intro$main$$buiding-title\">ビルド手順</string>\n    <string name=\"intro$main$$submit-patches-title\">パッチを提出する</string>\n    <string name=\"intro$main$$donation-title\">寄付、出資</string>\n    <string name=\"intro$main$$contact-title\">連絡先</string>\n    <string name=\"intro$main$supported-versions\">現在、サポートされているバージョンは、v2.6.0 (安定版)、 v3.0.0 (alpha と デバッグビルド)です。\n\\nApp Managerの旧バージョンは、セキュリティ上の脆弱性が含まれている可能性があるため、使用しないでください。</string>\n    <string name=\"intro$main$translations\">App Managerは、プル/マージリクエストによる翻訳を直接受け付けていません。翻訳は、Weblate を介して自動的に管理されます。\n\\n翻訳チームに参加するには、\\\\url{https://hosted.weblate.org/engage/app-manager/}をご覧ください。</string>\n    <string name=\"intro$main$buiding\">ビルド手順は、ソースコードのルートディレクトリにあるBUILDINGファイルに記載されています。</string>\n    <string name=\"pages$main$$pages-chapter-title\">ページ</string>\n    <string name=\"pages$main-page$$section-title\">メインページ</string>\n    <string name=\"pages$main-page$$how-app-ops-work-title\">メインページのアプリケーションリスト内の表示項目</string>\n    <string name=\"pages$main-page$$batch-operations-title\">バッチ処理</string>\n    <string name=\"pages$main-page$$colour-codes-title\">カラーコード</string>\n    <string name=\"pages$main-page$$application-types-title\">アプリケーションタイプ</string>\n    <string name=\"pages$main-page$$version-info-title\">バージョン情報</string>\n    <string name=\"pages$main-page$$instructions-title\">手順</string>\n    <string name=\"pages$main-page$$sort-title\">並び替え</string>\n    <string name=\"pages$main-page$$filter-title\">フィルタ</string>\n    <string name=\"pages$main-page$$profile_name-title\">プロファイル名</string>\n    <string name=\"pages$main-page$$1-click-ops-title\">ワンタップ一括処理</string>\n    <string name=\"pages$main-page$$running-apps-title\">実行中のアプリ</string>\n    <string name=\"pages$main-page$$profiles-title\">プロファイル</string>\n    <string name=\"pages$main-page$$apk-updater-title\">APK Updater</string>\n    <string name=\"pages$main-page$$settings-title\">設定</string>\n    <string name=\"pages$main-page$instructions\">\\\\textbf{ヘルプ}をタップすると、オフライン版のApp Managerユーザーマニュアルが開きます。\n\\n対応する機能スプリット\\\\texttt{feat\\\\_docs}がインストールされていない場合や、\n\\nマニュアルを読み込むためのWebViewがシステムに存在しない場合、オンライン版が開かれることもあります。</string>\n    <string name=\"pages$main-page$list-options\">\\\\textbf{表示オプション}には、メインページのリストの並び替えやフィルタリングのためのオプションが含まれています。</string>\n    <string name=\"pages$main-page$1-click-ops\">\\\\textbf{ワンタップ一括処理} では様々な操作をワンタップで行うことができます。\n\\n\\\\hyperref[sec:1-click-ops-page]{対応するページ}を新しいアクティビティで開きます。</string>\n    <string name=\"titlepage$quotation\">\\\\begin{quotation}\n\\n ``賢明に、そして、ゆっくりと。速く走る者たちは、つまずきますからな\\'\\'\n\\n %\\\\sourceatright\n\\n {--- 修道士ロレンス, \\\\textit{ロメオとジュリエット}}\n\\n \\\\end{quotation}</string>\n    <string name=\"titlepage$user_manual\">{\\\\huge\\\\bfseries ユーザーマニュアル\\\\par}</string>\n    <string name=\"intro$main$intro\">App Manager は、Android 用の高度なパッケージマネージャです。\n\\n数え切れないほどの機能を備えているため、ユーザーを支援するためのユーザーマニュアルが必要です。\n\\nこのドキュメントは、App Manager が提供するすべての機能を説明することを目的としており、App Manager のユーザーマニュアルとして機能します。\n\\nまた、このドキュメントは、App Managerの「公式」ガイドラインと考えることもでき、App Managerに期待される動作を表しています。\n\\n翻訳によって、このドキュメント（英語で書かれている）が誤解される可能性があります。\n\\nしたがって、すべての有能なユーザは、App Managerを最大限に活用するために、英語版のドキュメントを読む必要があります。\n\\nブログ記事、ビデオ、チャットグループなど、他の非公式またはサードパーティのリソースも同様に存在するかもしれません。\n\\nこれらのリソースは多くの人にとって有用かもしれませんが、App Managerの最新バージョンに対応していない可能性があります。App Managerでこのドキュメントからの逸脱が検出された場合、App Managerの\\\\href{https://github.com/MuntashirAkon/AppManager/issues}{イシュートラッカー}からご報告ください。</string>\n    <string name=\"intro$main$terminologies\">\\\\begin{itemize}\n\\n \\\\item \\\\textbf{AM} --- App Managerの略称です。\n\\n \\\\item \\\\textbf{ブロック/ブロック解除} --- コンポーネントのブロックまたはブロック解除に使用されます。コンポーネントをどのようにブロックするかは、ユーザーの設定に依存します。\n\\n \\\\item \\\\textbf{IFW} --- インテントファイアウォールの略称です。\n\\n \\\\item \\\\textbf{Ops} --- Operations（操作)の略称です。例：AppOps、バッチ操作\n\\n \\\\item \\\\textbf{SSAID} --- \\\\texttt{Settings.Secure.ANDROID\\\\_ID}の略称です。各アプリに割り当てられる端末識別子（Android Oreo以降）で、\n\\nアプリの署名証明書とパッケージ\\\\texttt{android}に設定されたSSAIDの組み合わせから生成されます。\n\\nそのため、ユーザーが端末のフォーマットを選択しない限り、\n\\nアプリに対して同一であることが保証されます。ユーザーの追跡に広く利用されています。\n\\n \\\\item \\\\textbf{トラッカー} --- \\\\hyperref[sec:scanner-page]{スキャナーページ}を除き、このドキュメント全体およびApp Managerでトラッカーコンポーネントのことを表します。トラッカーには、クラッシュレポーター、アナリティクス、プロファイリング、識別、広告、位置情報などのライブラリが含まれます。したがって、これらの機能は同等ではありません。また、トラッキングを促進するライブラリにはオープンソース、クローズドソースの区別や偏りはありません。\n\\n\\\\end{itemize}</string>\n    <string name=\"pages$main-page$$list-options-title\">表示オプション</string>\n    <string name=\"pages$main-page$$termux-title\">Termux</string>\n    <string name=\"pages$main-page$intro\">メインページには、インストールされているアプリケーション、アンインストールされているアプリケーション、バックアップされているアプリケーションがすべて表示されます。\n\\nインストールされているアプリケーションの項目をタップすると、それぞれのアプリケーションの\\\\hyperref[sec:app-details-page]{詳細ページ}が表示されます。\n\\nアンインストールされたシステムアプリの場合は、アプリの再インストールを行うことができるプロンプトが表示されます。\n\\n表示オプションの\\\\hyperlink{par:main-page-sort}{並び替え} を使用して、アプリの項目をさまざまな方法でソートし、終了時に保存することができます。\n\\nまた、\\\\hyperlink{par:main-page-filter}{フィルタ}を使用して、項目を絞り込むことも可能です。\n\\n検索バーを使ったフィルタリングも可能で、正規表現もサポートされています。</string>\n    <string name=\"pages$main-page$batch-operations\">このページでは、一括操作や複数のアプリケーションに対する操作も可能です。\n\\n複数選択モードは、アプリのアイコンをタップするか、リスト内の任意の項目を長押しすることで有効になります。\n\\n一度アクティブにすると、アプリの詳細ページを開く代わりに、リストの項目をシングルクリックすることでそのアプリが選択されます。\n\\nこのモードで、一括操作はページ下部の複数選択メニューに表示されます。次のような操作が含まれます:\n\\n\\\\begin{itemize}\n\\n \\\\item 選択したアプリケーションを\\\\hyperref[sec:profiles-page]{プロファイル}に追加する\n\\n \\\\item アプリケーションの\\\\hyperref[sec:backup-restore]{バックアップ、リストア、削除}\n\\n \\\\item アプリケーションからのトラッカーをブロックする\n\\n \\\\item アプリケーションのデータまたはキャッシュを消去する\n\\n \\\\item アプリケーションの有効化/無効化/強制停止/アンインストール\n\\n \\\\item App Managerに保存したブロッキングルールをエクスポート\n\\n \\\\item アプリケーションのバックグラウンド動作を禁止する（Android 7以降）\n\\n \\\\item APKファイルを \\\\texttt{AppManager/apks} に保存する\n\\n \\\\item \\\\hyperref[sec:net-policy]{ネット接続ポリシー}を適用する\n\\n\\\\end{itemize}\n\\n\n\\n\\\\begin{tip}{Accessibility}\n\\n複数選択モードを有効にした後、キーボードまたはリモコンの左右キーで複数選択メニューにナビゲートすることが可能です。\n\\n\\\\end{tip}</string>\n    <string name=\"pages$main-page$colour-codes\">\\\\begin{itemize}\n\\n \\\\item \\\\colorbox{AMLightGreyishOrange}{\\\\textcolor{black}{ライトグレーオレンジ(ライトモード)}} / \\\\colorbox{AMDarkBlue}{\n\\n \\\\textcolor{white}{紺色 (ナイトモード)}} -- バッチ処理で選択したアプリ\n\\n \\\\item \\\\colorbox{AMLightRed}{\\\\textcolor{black}{薄い赤色(ライトモード)}} / \\\\colorbox{AMVeryDarkRed}{\\\\textcolor{white}\n\\n {茶色(ナイトモード)}} -- 無効化されたアプリ\n\\n \\\\item \\\\colorbox{AMYellow}{\\\\textcolor{black}{黄色}} -- デバッグ可能なアプリ\n\\n \\\\item \\\\textcolor{AMOrange}{オレンジ色の \\\\textit{日付}} -- アプリはシステムログにアクセス可能\n\\n \\\\item \\\\textcolor{AMOrange}{オレンジ色の \\\\textit{UID}} -- 複数のアプリでユーザーIDを共有している\n\\n \\\\item \\\\textcolor{AMOrange}{オレンジ色の \\\\textit{SDK}} -- アプリケーションが平文（HTTPなど）のトラフィックを使用している可能性がある\n\\n \\\\item \\\\textcolor{red}{赤色の \\\\textit{パッケージ名}} -- データの消去を許可していないアプリ\n\\n \\\\item \\\\textcolor{red}{赤色の \\\\textit{バックアップ}} -- AppManager に 1 つ以上のバックアップが存在するアンインストールされたアプリケーション\n\\n \\\\item \\\\textcolor{AMOrange}{オレンジ色の \\\\textit{バックアップ}} -- 古いバックアップ,つまり、ベースバックアップにインストールされたアプリケーションの古いバージョンが含まれています\n\\n \\\\item \\\\textcolor{AMDarkCyan}{シアン色の \\\\textit{バックアップ}} -- 最新のバックアップ, つまり、ベースバックアップには、インストールされたアプリケーションと同じかそれ以上のバージョンが含まれています\n\\n \\\\item \\\\textcolor{AMDarkCyan}{シアン色の \\\\textit{パッケージ名}} -- 強制停止されたアプリ\n\\n \\\\item \\\\textcolor{AMDarkCyan}{シアン色の \\\\textit{バージョン}} -- 非アクティブなアプリ\n\\n \\\\item \\\\textcolor{magenta}{マゼンダ} -- 永続的なアプリケーション、つまり、常に実行状態のままです\n\\n\\\\end{itemize}</string>\n    <string name=\"pages$main-page$application-types\">アプリには、\\\\textbf{ユーザー}アプリと\\\\textbf{システム}アプリがあり、次の接尾辞が付きます:\n\\n\\\\begin{itemize}\n\\n \\\\item \\\\texttt{X} -- マルチアーキテクチャをサポートしています\n\\n \\\\item \\\\texttt{0} -- アプリにDEXファイルが存在しません\n\\n \\\\item \\\\texttt{°} -- 休止したアプリ\n\\n \\\\item \\\\texttt{\\\\#} -- アプリはシステムに大きなヒープ、すなわち大きな実行時メモリを割り当てるよう要求しています\n\\n \\\\item \\\\texttt{\\?} -- アプリは仮想マシンをセーフモードにするよう要求しています\n\\n\\\\end{itemize}</string>\n    <string name=\"pages$main-page$version-info\">バージョン名の後には、次の接頭辞が付きます:\n\\n\\\\begin{itemize}\n\\n \\\\item \\\\texttt{\\\\_} -- ハードウェアアクセラレーションを使用していません（アプリ内のアニメーションや透明度が壊れる）\n\\n \\\\item \\\\texttt{\\\\textasciitilde} -- テストビルドのアプリ\n\\n \\\\item \\\\texttt{debug} -- デバッグ可能なアプリ\n\\n\\\\end{itemize}</string>\n    <string name=\"pages$main-page$options-menu\">オプションメニューには、表示されたアプリの並べ替えやフィルタリング、App Manager内外のさまざまなページへの移動に使用できるオプションが\n\\nいくつか用意されています。</string>\n    <string name=\"intro$main$bin-sources\">App Managerは、以下のソースを使用して配布されています。非公式なソースは、App Managerの修正されたバージョンを配布する可能性があり、\n\\nそのようなバージョンを使用した結果について、一切の責任を負わないものとします。\n\\n\\\\begin{enumerate}\n\\n \\\\item Official F-Droid repository.\\\\footnote{安定版リリースのみ}\\\\\\\\\n\\n \\\\textit{リンク:} \\\\url{https://f-droid.org/packages/io.github.muntashirakon.AppManager}\n\\n \\\\item GitHub repository.\\\\\\\\\n\\n \\\\textit{安定版:} \\\\url{https://github.com/MuntashirAkon/AppManager/releases}\\\\\\\\\n\\n \\\\textit{デバッグビルド:} \\\\url{https://github.com/MuntashirAkon/AppManager/actions}\n\\n \\\\item Telegram.\\\\\\\\\n\\n \\\\textit{安定版:} \\\\url{https://t.me/AppManagerChannel}\\\\\\\\\n\\n \\\\textit{デバッグビルド:} \\\\url{https://t.me/AppManagerDebug}\n\\n\\\\end{enumerate}</string>\n    <string name=\"intro$main$contributing\">ユーザーは、役に立つ課題の作成、議論への参加、ドキュメントや翻訳の改善、未認識のライブラリやトラッカーの追加、\n\\nソースコードのレビュー、セキュリティ脆弱性の報告など、さまざまな方法でAppManagerの開発に貢献することができます。</string>\n    <string name=\"intro$main$donation\">\\\\emph{App Managerを使用するのに、寄付や購入は必須ではありません。}App Managerは購入をサポートしていませんが、\n\\nOpen Source Collectiveを通じてApp Managerの開発者に寄付を送ることができます。\n\\n\n\\nOpen Source Collectiveは、オープンソースプロジェクトの財政管理を支援するOpen Collectiveプラットフォーム内の財政ホストです。\n\\n現在は銀行振り込み、PayPal、クレジットカード、デビットカード、暗号通貨による寄付に対応しています。\n\\n\n\\n\\\\textit{リンク:} \\\\url{https://opencollective.com/muntashir}.\n\\n\n\\n寄付を送ることにより、あなたは寄付を利用して要求された機能を優先させないことに同意するものとします。\n\\n機能リクエストは、賞金や寄付を必要とせず、開発者の好みに応じて優先順位がつけられます。\n\\n\n\\n\\\\emph{App Managerは、資金提供や助成金の申し出を受け付けています。}利害関係のある組織の代表者は、§\\\\ref{sec:contact}に記載されている連絡先を使用して開発者に直接連絡することができます。</string>\n    <string name=\"intro$main$source-code-links\">GitHub以外はそのミラーです。タグは常に最新であるべきですが、masterブランチが最新であることは保証されていません。\n\\nmasterブランチのクローンを作成することが目的であれば、他のリンクではなくGitHubのリンクを使用してください。</string>\n    <string name=\"pages$main-page$$options-menu-title\">オプションメニュー</string>\n    <string name=\"pages$main-page$$app-usage-title\">アプリの使用状況</string>\n    <string name=\"intro$main$submit-patches\">現在、GitHub以外のリポジトリはそのミラーであり、これらのサイトで提出されたプル/マージリクエストは受け付けていません。\\\\footnote{GitHubのプルリクエストは、対応するパッチを使用して手動でマージされます。そのため、GitHub は誤ってそれらをマージせずにクローズしたとして認識してしまいます。}\n\\nその代わり、パッチ（\\\\texttt{.patch}ファイル）を電子メールに添付して提出することができます。コミットに\\\\textit{サインオフを行う}必要があります。\n\\n詳細は、ソースのルートディレクトリにあるCONTRIBUTINGファイルをご参照してください。\n\\n\n\\n\\\\begin{warning}{Notice}\n\\n電子メールでパッチを提出する場合、将来的に会話全体が公にアクセス可能となる可能性があります。\n\\nそのため、名前とメールアドレス以外の個人を特定できる情報（PII）は記載しないでください。\n\\n\\\\end{warning}</string>\n    <string name=\"intro$main$contact\">Muntashir Al-Islam\\\\footnote{``Muntashir Akon\\'\\'と呼ぶこともできます。}\\\\\\\\\n\\nEメール: \\\\href{mailto:muntashirakon@riseup.net}{muntashirakon [at] riseup [dot] net}\\\\\\\\\n\\nGPG鍵フィンガープリント: \\\\texttt{7bad37c2981e41f8f6abea7f58f0b4f26c346fce}\\\\\\\\\n\\nGitHub: \\\\url{https://github.com/MuntashirAkon}\\\\\\\\\n\\nTwitter: \\\\url{https://twitter.com/Muntashir}</string>\n    <string name=\"pages$main-page$sort\">メインページに表示されるアプリケーションは、次の方法で並び替えることができます:\n\\n\\\\begin{itemize}\n\\n \\\\item \\\\textbf{ユーザーアプリを優先} ユーザーアプリが上位に表示します\n\\n \\\\item \\\\textbf{アプリ名} アプリ名で昇順にリストを並べ替えます。これはデフォルトの並べ替え設定です\n\\n \\\\item \\\\textbf{パッケージ名} パッケージ名で昇順に並び替えます\n\\n \\\\item \\\\textbf{最後の更新} 最終更新日を基準に降順で並べ替えます\n\\n \\\\item \\\\textbf{共有UID} カーネルユーザーIDを基準に降順で並べ替えます\n\\n \\\\item \\\\textbf{ターゲットSDK} ターゲットSDKに基づいてリストを昇順で並べ替えます\n\\n \\\\item \\\\textbf{署名} 署名情報をもとに昇順に並べ替えます\n\\n \\\\item \\\\textbf{無効のものを優先} 無効にされたアプリを上位に表示します\n\\n \\\\item \\\\textbf{ブロック済みのものを優先} 各アプリケーションが持つブロックされたコンポーネントの数に基づいて、リストを降順に並べ替えます\n\\n \\\\item \\\\textbf{バックアップ済みを優先} バックアップをとっているアプリケーションを上位に表示します\n\\n \\\\item \\\\textbf{トラッカー} 各アプリケーションが持つトラッカーコンポーネントの数に基づいて、リストを降順に並べ替えます\n\\n \\\\item \\\\textbf{最終アクション} App Manager内でアプリケーションに行われたアクションの最新日時に基づいて、リストを降順に並べ替えます。\n\\n\\\\end{itemize}\n\\n\n\\nさらに、リストを反転させる\\\\textit{リバース}オプションもあります。ソートの設定にかかわらず、ランダムなソート結果を生成しないようにするために、アプリは最初にアルファベット順にソートされます。</string>\n    <string name=\"pages$main-page$profile_name\">また、\\\\hyperref[sec:profiles-page]{プロファイル}に存在するアプリケーションのみを表示することも可能です。\n\\nこれは、\\\\hyperref[sec:profiles-page]{プロファイルページ}では行えない特定の操作（プロファイル内のすべてのアプリケーションのアンインストールなど）\n\\nをプロファイルに対して行う場合に便利です。</string>\n    <string name=\"pages$main-page$filter\">メインページに表示されるアプリケーションは、次の方法でフィルタリングすることができます:\n\\n\\\\begin{itemize}\n\\n \\\\item \\\\textbf{ユーザーアプリ} ユーザーアプリのみを表示します\n\\n \\\\item \\\\textbf{システムアプリ} システムアプリのみを表示します\n\\n \\\\item \\\\textbf{無効になっているアプリ} 無効になっているアプリを表示します\n\\n \\\\item \\\\textbf{ルールを適用済みのアプリ} 1つ以上のブロッキングルールがあるアプリを表示します\n\\n \\\\item \\\\textbf{アクティビティが存在するアプリ} 1つ以上のアクティビティを持つアプリを表示します\n\\n \\\\item \\\\textbf{バックアップ済みのアプリ} バックアップが1つ以上あるアプリを表示します\n\\n \\\\item \\\\textbf{起動中のアプリ} 現在実行されているアプリを表示します\n\\n \\\\item \\\\textbf{分割データを含むアプリ} 1つ以上の分割APKファイルを持つアプリを表示します\n\\n \\\\item \\\\textbf{インストール済みのアプリ} インストールされているアプリのみを表示します\n\\n \\\\item \\\\textbf{未インストールのアプリ} インストールされていないアプリのみを表示します\n\\n \\\\item \\\\textbf{バックアップされたいないアプリ}バックアップが存在しないアプリを表示します\n\\n\\\\end{itemize}\n\\n\n\\n並べ替えとは異なり、複数のフィルタリングを同時に適用することが可能です。たとえば、「\\\\textit{ユーザーアプリ}」と「\\\\textit{無効のアプリ}」の両方を選択して無効になっているユーザーアプリを一覧表示することができます。この機能は、特定の操作を安全に実行するためにユーザーアプリのフィルタリングが必要な\\\\hyperref[subsec:batch-operations]{バッチ処理}に特に役立ちます。</string>\n    <string name=\"pages$app-details-page$$section-title\">アプリ詳細画面</string>\n    <string name=\"pages$app-details-page$$colour-codes-title\">カラーコード</string>\n    <string name=\"pages$app-details-page$$app-info-tab-title\">アプリ情報タブ</string>\n    <string name=\"pages$app-details-page$$app-info-general-information-title\">基本情報</string>\n    <string name=\"pages$app-details-page$$horizontal-action-panel-title\">横長アクションパネル</string>\n    <string name=\"pages$app-details-page$$activities-title\">アクティビティ</string>\n    <string name=\"pages$app-details-page$$servcies-title\">サービス</string>\n    <string name=\"pages$app-details-page$$providers-title\">プロバイダ</string>\n    <string name=\"pages$app-details-page$$additional-features-for-rooted-phones-title\">Root化された端末向けの追加機能</string>\n    <string name=\"pages$app-details-page$$blocking-trackers-title\">トラッカーをブロックする</string>\n    <string name=\"pages$app-details-page$$permission-tabs-title\">権限タブ</string>\n    <string name=\"pages$app-details-page$$uses-permissions-title\">使用する権限</string>\n    <string name=\"pages$app-details-page$$signatures-tab-title\">署名情報タブ</string>\n    <string name=\"pages$main-page$app-usage\">\\\\textit{画面の使用時間}、\\\\textit{データ使用量}（モバイルとWi-Fiの両方）、\\\\textit{アプリを開いた回数}などのアプリ使用統計は、\n\\nメニューの\\\\textbf{アプリ使用状況}オプションをクリックすることでアクセス可能です。\n\\nただし、これには\\\\textit{使用状況へのアクセス権限}が必要です。\n\\n\\\\hyperref[subsec:enable/disable-features]{設定}で使用状況アクセス機能を無効にしている場合、このメニュー項目は表示されません。</string>\n    <string name=\"pages$main-page$running-apps\">このメニューでは、実行中のアプリケーションまたはプロセスの一覧を表示する新しいページを開きます。\n\\nまた、現在のメモリとキャッシュ（利用可能な場合）の使用量も表示されます。\n\\nルートまたはADBがApp Managerで利用できない場合、Androidの最近のバージョンでのみ表示されます。\n\\n実行中のアプリケーションまたはプロセスは、結果ページ内で強制停止またはキルすることもできます。\n\\n\\\\hyperref[subsubsec:log-viewer]{ログビューア}でプロセスID（PID）ごとのログを確認することもできます。\n\\nまた、アイコンをタップするか、項目を長押しすることで、バッチ処理を行うことができます。各項目をタップすると、より詳細な情報が表示されるダイアログが開きます。</string>\n    <string name=\"pages$main-page$profiles\">このメニュー項目は、\\\\hyperref[sec:profiles-page]{プロファイルページ}を開きます。プロファイルは、定期的に実行するタスクを設定するための方法です。\n\\nまた、ショートカットで呼び出すこともできます。</string>\n    <string name=\"pages$main-page$apk-updater\">\\\\href{https://github.com/rumboalla/apkupdater}{APK Updater}というアプリがシステムにインストールされている場合、\n\\nこのメニュー項目から直接開くことができます。アプリがシステムにインストールされていない場合、このオプションは表示されません。</string>\n    <string name=\"pages$app-details-page$$permissions-title\">権限</string>\n    <string name=\"pages$main-page$termux\">\\\\href{https://github.com/termux/termux-app}{Termux}アプリがシステムにインストールされている場合、\n\\nこのメニュー項目から実行中のセッション(または新しいセッション)を直接開くことができます。\n\\nアプリがシステムにインストールされていない場合、このオプションは表示されません。</string>\n    <string name=\"pages$app-details-page$$app-info-options-menu-title\">オプションメニュー</string>\n    <string name=\"pages$app-details-page$$config-termux-title\">Termuxを構成</string>\n    <string name=\"pages$app-details-page$$component-tabs-title\">コンポーネントタブ</string>\n    <string name=\"pages$app-details-page$$receivers-title\">レシーバ</string>\n    <string name=\"pages$app-details-page$$blocking-components-title\">コンポーネントをブロックする</string>\n    <string name=\"pages$app-details-page$$app-ops-title\">App Ops</string>\n    <string name=\"pages$main-page$settings\">アプリ内の\\\\hyperref[sec:settings-page]{設定画面}を表示するメニューです。</string>\n    <string name=\"pages$app-details-page$colour-codes\">このページで使用している背景色とその意味の一覧です:\n\\n\\\\begin{itemize}\n\\n \\\\item \\\\colorbox{AMRed}{\\\\textcolor{black}{赤 (ライト)}} / \\\\colorbox{AMDarkRed}{\\\\textcolor{white}{紅赤 (ナイト)}}\n\\n -- Dangerousフラグを持つAppOpsや権限、またはApp Manager内でブロックされたコンポーネントを表します。\n\\n\n\\n \\\\item \\\\colorbox{AMLightRed}{\\\\textcolor{black}{うすだいだい (ライト)}} / \\\\colorbox{AMVeryDarkRed}{\\\\textcolor{white}{茶色\n\\n(ナイト)}} -- App Managerの外部で無効化されているコンポーネントを表します。\n\\n\n\\n \\\\begin{tip}{Note}\n\\n無効とマークされたコンポーネントは、必ずしもユーザーによって無効化されたことを意味するものではありません。\n\\nシステムによって無効にされているか、マニフェストで無効とマークされている可能性もあります。\n\\n無効なアプリケーションのコンポーネントは、システム (および App Manager) によっても無効とみなされます。\n\\n \\\\end{tip}\n\\n\n\\n \\\\item \\\\colorbox{AMVividOrange}{\\\\textcolor{black}{オレンジ (ライト)}} / \\\\colorbox{AMVeryDarkOrange}{\n\\n \\\\textcolor{white}{うすいオレンジ (night)}} -- トラッカーコンポーネントを表します。\n\\n\n\\n \\\\item \\\\colorbox{AMSoftMagenta}{\\\\textcolor{black}{Soft magenta (day)}} / \\\\colorbox{AMVeryDarkViolet}{\n\\n \\\\textcolor{white}{very dark violet (night)}} -- 実行中のサービスを表します。\n\\n\\\\end{itemize}</string>\n    <string name=\"pages$app-details-page$intro\">\\\\textbf{アプリ詳細}ページは、11個のタブで構成されています。\n\\nマニフェストのすべての属性、\\\\hyperref[ch:app-ops]{AppOps}、署名情報、ライブラリなど、\n\\nアプリが持ちうるほぼすべての情報が記述されています。</string>\n    <string name=\"pages$app-details-page$app-info-tab\">\\\\textbf{アプリ情報}タブには、アプリケーションに関する一般的な情報が含まれています。\n\\nまた、このタブ内で実行可能な多くのアクションが表示されます。</string>\n    <string name=\"pages$app-details-page$app-info-general-information\">以下のリストは、アプリ情報タブに記載されている順番と同じです。\n\\n\\\\begin{itemize}\n\\n \\\\item \\\\textbf{アプリ名} アプリのアイコンです。アプリにアイコンがない場合は、システムデフォルトのアイコンが表示されます。\n\\n\n\\n \\\\item \\\\textbf{アプリ名} アプリの名称です。\n\\n\n\\n \\\\item \\\\textbf{バージョン} アプリケーションのバージョンは、2つの部分に分かれています。最初の部分は\\\\textit{バージョン名}と呼ばれ、この部分のフォーマットは様々ですが、多くの場合ドットで区切られた複数の整数から構成されています。2つ目の部分は\\\\textit{バージョンコード}と呼ばれ、バージョン名の横の括弧内に記載されています。バージョンコードは整数で、通常はアプリのバージョンを区別するために使用されます。（バージョン名は機械では読めないことが多いため）一般に、新しいバージョンのアプリは、古いバージョンのアプリよりもバージョンコードが高くなります。たとえば、あるアプリのバージョンコードが\\\\texttt{123}と\\\\texttt{125}の場合、後者のバージョンコードの方が高いので、後者は前者よりも更新されていると言えます。プラットフォーム（モバイル、タブ、デスクトップなど）に依存するアプリケーションの場合、これらのバージョン名は、プラットフォームごとに接頭辞を使用しているため、誤解を招く可能性があります。\n\\n\n\\n \\\\item \\\\textbf{タグ} タグには、アプリの基本的で簡潔な、有用な情報が含まれています。例えば、\\\\textit{トラッカー情報}（トラッカーコンポーネントの数など）、\\\\textit{アプリの種類}（ユーザーアプリかシステムアプリか、アプリがシステムアプリの更新版かMagiskを使ってシステムレスでインストールされたか）、\\\\textit{実行中}（アプリのサービスがバックグラウンドで実行されているか）、\\\\textit{分割APK情報}（例. split APK info（分割数）、\\\\textit{debuggable}（アプリはデバッグバージョン）、\\\\textit{test only}（アプリはテスト専用アプリ）、\\\\textit{ラージヒープ}（アプリは大きなヒープサイズを要求）、\\\\textit{停止}（アプリは強制停止）、\\\\textit{無効}（アプリは無効）、\\\\textit{キーストア}（アプリはAndroid KeyStoreにアイテムがある）、\\\\textit{no code}（アプリにはコードが関連付けられていない）、\\\\hyperref[sec:terminologies]{\\\\textit{SSAID}}、\\\\textit{netpolicy}（バックグラウンドデータ使用などネットワークポリシー）、\\\\textit{バッテリー最適化}が表示されます。\\\\textit{test only}と\\\\textit{debuggable}を含めることの重要性は、これらのプロパティを持つアプリが追加のタスクを実行できること、またはこれらのアプリが個人情報を保存する場合、セキュリティ上の問題を引き起こす可能性のあるルートなしで実行できることにあります。\\\\textit{ラージヒープ}は、アプリが必要に応じてより多くのメモリ（RAM）を割り当てられることを意味します。ほとんどの場合、これは有害ではないかもしれませんが、大きなヒープを要求する不審なアプリは慎重に考慮する必要があります。\n\\n\n\\n \\\\item \\\\textbf{アクションパネル} アプリに関する様々なアクションを含むアクションパネルです。ここで利用できるアクションの一覧は、\\\\ref{subsubsec:horizontal-action-panel}節を参照してください。\n\\n\n\\n \\\\item \\\\textbf{パスとディレクトリ} \\\\textit{アプリディレクトリ}（APK ファイルが格納される場所）、\\\\textit{データディレクトリ}（内部、デバイス保護、外部）、\\\\textit{分割 APK ディレクトリ}（分割名と共に）、\\\\textit{ネイティブ JNI ライブラリ}（存在する場合）を含むアプリケーションパスに関するさまざまな情報が含まれています。JNI ライブラリは、通常 C/C++ で記述されたネイティブコードを呼び出すために使用されます。ネイティブライブラリを使用すると、アプリの実行速度が向上したり、ほとんどのゲームのようにJava以外の言語で書かれたサードパーティライブラリをアプリが使用できるようになります。これらのディレクトリは、各項目の右側にある起動アイコンをクリックして、お気に入りのファイルマネージャ（サポートしており、必要なパーミッションがある場合）を使用して開くこともできます。\n\\n\n\\n \\\\item \\\\textbf{最終起動時からのデータ使用量} 説明不要のオプションです。しかし、いくつかの問題のために、結果はしばしば誤解を招き、単に間違っている可能性があることに注意してください。この部分は、新しいデバイスで\\\\textit{使用状況}へのアクセス許可が与えられていない場合、隠されたままになります。\n\\n\n\\n \\\\item \\\\textbf{ストレージとキャッシュ} アプリ（APKファイル）、データ、キャッシュのサイズに関する情報を表示します。古い端末では、外部データ、キャッシュ、メディア、OBBフォルダのサイズも表示されます。この部分は、新しいデバイスで \\\\textit{使用状況}へのアクセス許可が与えられていない場合、隠されたままになります。\n\\n\n\\n \\\\item \\\\textbf{詳細情報} 次のような情報を表示します。\n\\n \\\\begin{itemize}\n\\n \\\\item \\\\textbf{SDK} Android SDKに関連する情報を表示します。値は2つ（古い端末では1つ）あります。\\\\textit{最大}はターゲットSDK、\\\\textit{最小}は最小SDKを表します（後者はそれ以上古い端末では利用できません）。現在プラットフォームがサポートしている最大のSDKを持つアプリを使用するのが好ましいです。SDKは、\\\\textbf{APIレベル}とも呼ばれます。\n\\n \\\\seealsoinline{\\\\href{https://ja.wikipedia.org/wiki/Android\\\\%E3\\\\%81\\\\%AE\\\\%E3\\\\%83\\\\%90\\\\%E3\\\\%83\\\\%BC\\\\%E3\\\\%82\\\\%B8\\\\%E3\\\\%83\\\\%A7\\\\%E3\\\\%83\\\\%B3\\\\%E5\\\\%B1\\\\%A5\\\\%E6\\\\%AD\\\\%B4}{Androidのバージョン履歴}}\n\\n\n\\n \\\\item \\\\textbf{フラグ} The application flags used at the time of building the app. For a complete list of flags\n\\n and what they do, visit the\n\\n \\\\href{https://developer.android.com/reference/android/content/pm/ApplicationInfo\\\\#flags}{official documentation}.\n\\nアプリのビルド時に使用するアプリケーションフラグです。フラグの完全なリストとその役割については、\\\\href{https://developer.android.com/reference/android/content/pm/ApplicationInfo\\\\#flags}{公式ドキュメント}を参照してください。\n\\n\n\\n \\\\item \\\\textbf{インストール日時} アプリが最初にインストールされた日時です。\n\\n\n\\n \\\\item \\\\textbf{アップデート日時} アプリが最後に更新された日時です。アプリが更新されていない場合は、\\\\textit{インストール日時}と同じになります。\n\\n\n\\n \\\\item \\\\textbf{インストール日時} このアプリをインストールしたアプリです。すべてのアプリが、インストーラアプリを登録するためにパッケージマネージャに使用する情報を提供するわけではありません。そのため、この値を鵜呑みにするべきではありません。\n\\n\n\\n \\\\item \\\\textbf{ユーザーID} Androidシステムがアプリに設定した固有のユーザーIDです。共有アプリケーションの場合、同じ\\\\textit{共有ユーザーID}を持つ複数のアプリケーションに同じユーザーIDが割り当てられます。\n\\n\n\\n \\\\item \\\\textbf{共有UID} 一緒に共有するアプリケーションに適用されます。IDとありますが、実際は文字列の値です。共有するアプリケーションは、同じ\\\\hyperref[subsec:signatures-tab]{署名}を持つ必要があります。\n\\n\n\\n \\\\item \\\\textbf{メインアクティビティ} アプリ起動時の\\\\hyperref[subsubsec:activities]{アクティビティ}です。アプリにアクティビティがあり、そのいずれかがランチャーから開くことができる場合にのみ表示されます。また、右側には起動ボタンがあり、このアクティビティを起動するために使用することができます。\n\\n \\\\end{itemize}\n\\n\\\\end{itemize}</string>\n    <string name=\"pages$app-details-page$horizontal-action-panel\">前項のアクションパネルは、次のようなアプリに関連するさまざまなアクションで構成されています。\n\\n\\\\begin{itemize}\n\\n \\\\item \\\\textbf{起動} ランチャー\\\\hyperref[subsubsec:activities]{アクティビティ}を持つアプリケーションは、このボタンから起動することができます。\n\\n\n\\n \\\\item \\\\textbf{無効化} アプリを無効化します。アプリがすでに無効になっている場合や、Rootアクセスや\\\\hyperref[sec:adb-over-tcp]{ADB}を持っていないユーザーには、このボタンは表示されません。アプリを無効にすると、そのアプリはランチャーアプリに表示されなくなります。また、そのアプリのショートカットも削除されます。ユーザーアプリを無効にした場合、App Managerまたはそれに対応する他のツールからのみ有効にすることができます。Androidの設定には、無効にしたユーザーアプリを有効にするオプションはありません。\n\\n\n\\n \\\\item \\\\textbf{アンインストール} アプリをアンインストールします。\n\\n\n\\n \\\\item \\\\textbf{有効化} アプリを有効化します。アプリがすでに有効化されている場合や、RootアクセスやADBを持っていないユーザーには、このボタンは表示されません。\n\\n\n\\n \\\\item \\\\textbf{強制終了} アプリを強制停止します。 アプリを強制停止すると、明示的にアプリを開いてからでないと、そのアプリはバックグラウンドで実行できなくなります。しかし、これは必ずしも正しいとは限りません。\n\\n\n\\n \\\\item \\\\textbf{データを消去} アプリのデータを消去します。これには、アカウント（アプリによって設定されている場合）、キャッシュなど、内部および多くの場合外部のディレクトリに保存されているすべての情報が含まれます。例えば、App Managerからデータを消去すると、アプリ内に保存されているすべてのルールが削除されます（ただし、ブロックは削除されません）。そのため、ルールのバックアップを常に取っておく必要があります。このボタンは、RootアクセスまたはADBを持っていないユーザーには表示されません。\n\\n\n\\n \\\\item \\\\textbf{キャッシュを消去} アプリのキャッシュのみをクリアします。アプリのキャッシュをクリアする方法は、Android自体にはありません。そのため、アプリの内部ストレージからキャッシュをクリアするには、Root権限が必要です。\n\\n\n\\n \\\\item \\\\textbf{インストール} サードパーティのアプリで開いたAPKをインストールします。このボタンは、インストールされていない外部APKの場合のみ表示されます。\n\\n\n\\n \\\\item \\\\textbf{最新情報} インストールされているAPKよりもバージョンコードの高いAPKに対して表示されるボタンです。このボタンをクリックすると、バージョン間の差分がダイアログで表示されます。表示される情報は、\\\\textit{バージョン}、\\\\textit{トラッカー}、\\\\textit{パーミッション}、\\\\textit{コンポーネント}、\\\\textit{署名情報}（チェックサムの変更）、\\\\textit{機能}、\\\\textit{共有ライブラリ}、\\\\textit{SDK}などです。\n\\n\n\\n \\\\item \\\\textbf{アップデート} インストールされているアプリよりバージョンコードが高いアプリに対して表示されます。\n\\n\n\\n \\\\item \\\\textbf{再インストール} インストールされているアプリと同じバージョンコードを持つアプリに対して表示されます。\n\\n\n\\n \\\\item \\\\textbf{ダウングレード} インストールされているアプリよりバージョンコードが低いアプリに対して表示されます。\n\\n\n\\n \\\\item \\\\textbf{マニフェスト} このボタンをクリックすると、アプリのマニフェストファイルが別ページで表示されます。マニフェストファイルは、対応するトグルボタン (右上) を使用してラップまたはアンラップすることができ、保存ボタンを使用して共有ストレージに保存することができます。\n\\n\n\\n \\\\item \\\\textbf{スキャナー} このボタンをクリックすると、アプリのトラッカーとライブラリの情報が表示されます。まず、アプリをスキャンして、クラスのリストを抽出し、クラス一覧と複数のシグネチャをマッチングさせます。その後、スキャン結果が表示されます。\\\\\\\\\n\\n \\\\seealsoinline{\\\\hyperref[sec:scanner-page]{スキャナーページ}}\n\\n\n\\n \\\\item \\\\textbf{共有設定} このボタンをクリックすると、アプリで使用されている共有環境設定の一覧が表示されます。リスト内の設定項目をクリックすると、\\\\hyperref[sec:shared-preferences-editor-page]{共有設定エディター}が表示されます。このオプションは、Rootユーザーのみに表示されます。\n\\n\n\\n \\\\item \\\\textbf{データベース} このボタンをクリックすると、アプリが使用しているデータベースの一覧が表示されます。これはもっと改良が必要で、将来的にはデータベース・エディターが追加されるかもしれません。このオプションは、Rootユーザーのみに表示されます。\n\\n\n\\n \\\\item \\\\textbf{F-Droid} 任意の\\\\textit{F-Droid}クライアントでアプリのページを開きます。\n\\n\n\\n \\\\item \\\\textbf{ストア} \\\\textit{Aurora Store}でアプリのページを開きます。このオプションは、\\\\textit{Aurora Store}がインストールされている場合のみ表示されます。\n\\n\\\\end{itemize}</string>\n    <string name=\"pages$app-details-page$app-info-options-menu\">ページの右上にあるのが、オプションメニューです。そこにあるオプションとその説明は以下の通りです:\n\\n\\\\begin{itemize}\n\\n \\\\item \\\\textbf{共有} 共有ボタンでAPKファイルを共有したり、\\\\textit{APKSファイル}（アプリが複数分割されている場合）を\\\\href{https://github.com/Aefyr/SAI}{SAI}にインポートすることができます。任意のファイルマネージャーから共有し、ストレージにファイルを保存することができます。\n\\n\n\\n \\\\item \\\\textbf{更新} アプリ情報タブの内容を更新します。\n\\n \\\\item \\\\textbf{設定画面で開く} Android設定画面でアプリの詳細画面を開きます。\n\\n \\\\item \\\\textbf{バックアップ/復元} バックアップ・復元を行うダイアログを開きます。\n\\n \\\\item \\\\textbf{ブロッキングルールをエクスポート} App Managerでこのアプリに対して設定されたルールをエクスポートします。\n\\n\n\\n \\\\item \\\\textbf{Termuxで開く} Termuxでアプリを開きます。これは実際には \\\\texttt{su - user\\\\_id} を実行します。ここで \\\\texttt{user\\\\_id} はアプリのカーネルユーザーID（\\\\hyperref[subsubsec:app-info-general-information]{基本情報セクション}で説明されています）を表します。このオプションはRootユーザーにのみ表示されます。サードパーティアプリケーションからコマンドを実行するように Termux を設定する方法については §\\\\ref{subsubsec:config-termux} を参照してください。\n\\n\n\\n \\\\item \\\\textbf{Termuxで実行} Termuxで\\\\texttt{run-as package\\\\_name}を使用してアプリを開きます。これはデバッグ可能アプリにのみ適用され、Root及びADBの両方で動作します。サードパーティアプリケーションからコマンドを実行するように Termux を設定する方法については §\\\\ref{subsubsec:config-termux} を参照してください。\n\\n\n\\n \\\\item \\\\textbf{アイコンを抽出} アプリのアイコンを抽出して任意の場所に保存します。\n\\n\\\\end{itemize}</string>\n    <string name=\"pages$app-details-page$servcies\">ユーザーが閲覧することができる\\\\hyperref[subsubsec:activities]{アクティビティ}とは異なり、\\\\textbf{サービス}はバックグラウンドタスクを処理します。\n\\n例えば、スマートフォンのブラウザを使ってインターネットからファイルをダウンロードする場合、ブラウザはコンテンツをダウンロードするためにバックグラウンドサービスを使用しています。\n\\n\n\\nアクティビティを終了すると、通常はすぐにメモリ上から破棄されます（端末の空きメモリの量など、多くの要因に依存します）。しかしサービスは、必要に応じて無期限に実行することができます。より多くのサービスがバックグラウンドで実行されている場合、メモリや処理能力が不足するため、携帯電話の動作が遅くなり、携帯電話のバッテリーがより速く消耗する可能性があります。新しいAndroidのバージョンでは、すべてのアプリでバッテリーの最適化機能がデフォルトで有効になっています。この機能を有効にすると、システムは任意のサービスをランダムに終了させることができます。\n\\n\n\\nところで、アクティビティもサービスもメイン\\\\href{https://stackoverflow.com/questions/7597742}{ルーパー}と呼ばれる同じルーパーで実行されるため、サービスが本当にバックグラウンドで実行されているとは限りません。それを保証するのは、アプリケーションの開発者の仕事です。アプリケーションとサービスは\\\\hyperref[subsubsec:app-details-receivers]{ブロードキャストレシーバー}を使って通信しています。</string>\n    <string name=\"pages$app-details-page$receivers\">\\\\textbf{レシーバー}（\\\\textit{ブロードキャストレシーバー}とも呼ばれる）は、特定のイベントに対して特定のタスクの実行を呼び出すために使用することができます。これらのコンポーネントは、ブロードキャストメッセージを受信するとすぐに実行されるため、ブロードキャストレシーバーと呼ばれます。これらのブロードキャストメッセージは、インテントと呼ばれるメソッドを使用して送信されます。インテントはAndroidの特別な機能で、アプリケーションやアクティビティ、サービスを開いたり、ブロードキャストメッセージを送信したりするために使われます。そのため、\\\\hyperref[subsubsec:activities]{アクティビティ}と同様に、ブロードキャストレシーバもインテントフィルターを用いて、必要なブロードキャストメッセージのみを受信することができます。ブロードキャストメッセージは、システムまたはアプリケーション自体のいずれかによって送信することができます。ブロードキャストメッセージが送信されると、対応するレシーバーはシステムによって起動され、タスクを実行できるようになります。例えば、メモリが少ない場合、モバイルデータを有効にしたり、Wifiに接続した後に、端末がフリーズしたり、一瞬ラグが発生することがあります。なぜだか不思議に思ったことはありませんか？これは、「android.net.conn.CONNECTIVITY_CHANGE」を受信できるブロードキャストレシーバーが、データ接続を有効にすると同時に、システムによって起こされるからです。多くのアプリがこのインテントフィルタを使っているため、これらのアプリはすべて、システムによってほとんどすぐに起こされ、フリーズや遅延の原因になっています。要するに、レシーバはプロセス間通信（IPC）、つまり異なるアプリ間（必要な権限がある場合）、あるいは単一アプリケーションの異なるコンポーネント間の通信に使用できます。</string>\n    <string name=\"pages$app-details-page$providers\">\\\\textbf{プロバイダ}（\\\\textit{コンテンツプロバイダ}ともいう）は、アプリ内のデータ管理に使用されます。例えば、App ManagerでAPKファイルの保存やルールのエクスポートを行う場合、「androidx.core.content.FileProvider」というコンテンツプロバイダを使用します。データベース管理、トラッキング、検索など、様々なコンテンツ関連のタスクを管理するために、他のコンテンツプロバイダや、カスタムプロバイダーもあります。各コンテンツプロバイダは、パッケージ名と同様に、Androidエコシステム全体でその特定のアプリケーションに固有のAuthorityと呼ばれるフィールドを持っています。</string>\n    <string name=\"pages$app-details-page$config-termux\">デフォルトでは、Termuxはサードパーティアプリケーションからのコマンドの実行が許可されていません。\n\\nこのオプションを有効にするには、\\\\texttt{\\\\textasciitilde/.termux/termux.properties} に \\\\texttt{allow-external-apps=true} を追加し、\n\\nTermux v0.96 以降を実行している必要があります。\n\\n\n\\n\\\\begin{tip}{Info}\n\\nこのオプションを有効にしても、Termuxのセキュリティは低下しません。\n\\nサードパーティアプリは、他の権限と同様に、Termuxで任意のコマンドを実行できるようにユーザーに要求する必要があります。\n\\n\\\\end{tip}</string>\n    <string name=\"pages$app-details-page$component-tabs\">\\\\textbf{アクティビティ}、\\\\textbf{サービス}、\\\\textbf{レシーバ}（\\\\textit{ブロードキャストレシーバ}）、\\\\textbf{プロバイダ}（\\\\textit{コンテンツプロバイダ}）を合わせてアプリケーションコンポーネントと呼びます。\n\\nそれらは多くの点で同様の機能を共有しているからです。例えば、それらはすべて\\\\textit{名前}と\\\\textit{ラベル}を持っています。\n\\nコンポーネントは、あらゆるアプリケーションの構成要素であり、そのほとんどはアプリケーションマニフェストで宣言されなければなりません。\n\\nアプリケーションマニフェストは、アプリケーション固有のメタデータが格納されるファイルです。\n\\nAndroidシステムは、メタデータを読み取ることで、アプリケーションで何を行うかを学習します。\n\\nこれらのタブで使用される色については、§\\\\ref{subsec:app-details-colour-codes}で説明しています。\n\\nまた、オーバーフローメニューのソートオプションを使用して、ブロックされたコンポーネントやトラッカーコンポーネントをリストの上位に表示するよう、\n\\nコンポーネントのリストを\\\\textbf{並び替え}る機能があります。</string>\n    <string name=\"pages$app-details-page$activities\">\\\\textbf{アクティビティ}は、アプリ内の閲覧できるウィンドウやページです（例えば、\\\\textit{メインページ}と\\\\textit{アプリ詳細ページ}は別のアクティビティです）。つまり、アクティビティは、ユーザーインターフェース（UI）のコンポーネントです。各アクティビティは、\\\\textit{ウィジェット}や\\\\textit{フラグメント}と呼ばれる複数のUIコンポーネントを持つことができ、同様に、後者のコンポーネントも、それぞれ複数のものを入れ子にしたり、オーバーレイすることができます。しかし、アクティビティはマスターコンポーネントです。アクティビティを2つネストさせることはできません。アプリケーションの開発者は、\\\\textit{インテントフィルター}と呼ばれる方法を使用して、アクティビティ内で外部ファイルを開くことを選択することもできます。ファイルマネージャーを使ってファイルを開こうとすると、ファイルマネージャーかシステムがインテントフィルターをスキャンして、どのアクティビティーがその特定のファイルを開けるかを決め、これらのアクティビティーでファイルを開けるように提案します。（したがって、アプリケーション自体には何の関係もありません）\n\\n\n\\n\\\\textit{エクスポート可能}なアクティビティは、通常、サードパーティアプリで開くことができます（一部のアクティビティには権限が必要なため、その場合はその権限を持つアプリケーションのみが開くことができます）。\\\\textit{アクティビティ}タブでは、アクティビティ名（各リスト項目の上部）がボタンとなっています。これは、\\\\textit{エクスポート可能}なアクティビティでは有効で、それ以外では無効になっています（Rootユーザーはどのアクティビティでも開くことができます）。ボタンをクリックすると、App Managerでアクティビティを直接開くことができます。また、アクティビティを長押しすることで、インタセプターのページを開くことができます。現在は、\\\\textit{エクスポート可能}なアクティビティに対してのみ機能します。\n\\n\n\\n\\\\begin{warning}{Notice}\n\\n例えば、\\\\textit{アプリ詳細アクティビティ}は、少なくともパッケージ名を提供する必要があるため、開くことができません。これらの依存関係は、常にプログラムで推論することはできません。したがって、App Managerを使用してそれらを開くことはできません。\n\\n\\\\end{warning}\n\\n\n\\nまた、これらのエクスポート可能なアクティビティのショートカットを作成し（専用ボタンを使用）、必要であれば、ショートカットの編集ボタンでショートカットも編集することができます。\n\\n\n\\n\\\\begin{danger}{Caution}\n\\nApp Managerをアンインストールすると、App Managerで作成したショートカットはすべて失われます。\n\\n\\\\end{danger}</string>\n    <string name=\"pages$app-details-page$additional-features-for-rooted-phones\">これらのタブでは非Rootユーザーよりも、Rootユーザーは様々な操作を行うことができます。</string>\n    <string name=\"pages$app-details-page$blocking-trackers\">トラッカーコンポーネントを無効にするには、三点メニューの「トラッカーをブロック」を使用します。\n\\n現在表示されているタブに関係なく、すべてのトラッカーコンポーネントがブロックされます。\n\\n\n\\n\\\\begin{tip}{Info}\n\\nトラッカーコンポーネントは、アプリのコンポーネントの部分集合です。\n\\nしたがって、他のコンポーネントのブロックに使用されるのと同じ方法によりブロックされます。\n\\n\\\\end{tip}\n\\n\n\\n\\\\begin{amseealso}\n\\n \\\\item \\\\hyperref[subsec:tracker-classes-versus-tracker-components]{FAQ: トラッカーのクラスとトラッカーコンポーネント}\n\\n \\\\item \\\\hyperref[sec:scanner-page]{スキャナーページ}\n\\n \\\\item \\\\hyperref[subsec:block-unblock-trackers]{ワンタップ一括処理: トラッカーをブロック/ブロック解除}\n\\n\\\\end{amseealso}</string>\n    <string name=\"pages$app-details-page$signatures-tab_2\">ここに表示されるチェックサムは、\\\\textit{MD5}、\\\\textit{SHA1}、\\\\textit{SHA256}の3種類です。\n\\n\n\\n\\\\begin{danger}{Caution}\n\\n署名情報の検証には、\\\\textit{SHA256}チェックサムのみ、もしくはこれら3つすべてを使用することを推奨します。\n\\n\\\\textit{MD5}や\\\\textit{SHA1}のチェックサムだけでは、複数の証明書に対して同じハッシュを生成する可能性あるので、\n\\nそれらのみに依存しないようにしてください。\n\\n\\\\end{danger}</string>\n    <string name=\"pages$app-details-page$blocking-components\">各コンポーネント項目の右端には、「ブロック」ボタンがあります。（ブロックされているときは「ブロック解除」ボタンとなります）\n\\nこのボタンを使って、そのコンポーネントのブロックの状態を切り替えることができます。\n\\n\\\\hyperref[subsubsec:instant-component-blocking]{インスタントブロッキング}を有効にしていない場合、\n\\nまたは以前にアプリケーションにブロックを適用していない場合は、\n\\n3点メニューの\\\\textbf{ルールを反映}オプションで変更を適用する必要があります。\n\\nまた、\\\\textbf{ルールを除去}オプションから、すでに適用されたルールを削除することもできます。\n\\n\n\\n\\\\seealsoinline{\\\\hyperref[sec:faq:app-components]{FAQ: アプリのコンポーネント}}</string>\n    <string name=\"pages$app-details-page$permission-tabs\">\\\\textbf{App Ops}、\\\\textbf{Uses Permissions}、\\\\textbf{Permissions}タブは、権限に関連しています。\n\\nAndroidでは、同じID(\\\\textit{共有ID}として知られます)を持たないアプリやプロセス間の通信は、しばしばパーミッション（複数可）を必要とします。\n\\nこれらの権限は、権限コントローラーによって管理されます。\n\\nアプリケーションのマニフェストに記載されていれば自動的に付与される\\\\textit{通常}の権限もありますが、\n\\n\\\\textit{dangerous}、\\\\textit{development}パーミッションはユーザーの確認が必要です。\n\\nこれらのタブで使用される色については、\\\\ref{subsec:app-details-colour-codes}節で説明しています。</string>\n    <string name=\"pages$app-details-page$app-ops\">\\\\textbf{App Ops} は、\\\\textbf{Application Operations}(アプリケーションの操作)の略です。\n\\nAndroid 4.3以降、\\\\textit{App Ops}はAndroidシステムによってアプリ権限の大部分を制御するために使用されています。\n\\n各AppOpsは、それらに関連付けられた一意の番号を持っており、それはApp Opsタブの最初の括弧内に閉じられています。\n\\nまた、プライベート名を持ち、任意でパブリック名を持つことができます。\n\\nいくつかのAppOpsは、\\\\textit{権限}とも関連付けられています。\n\\nAppOpsの保護レベルは、関連付けられた権限に基づいて決定されます。\n\\n\\\\textit{フラグ}、\\\\textit{権限名}、\\\\textit{権限の説明}、\\\\textit{パッケージ名}、\\\\textit{グループ}のような情報は、\n\\n関連付けられた\\\\hyperref[subsubsec:permissions]{権限}から取得されます。\n\\nその他の情報としては、以下のようなものがあります:\n\\n\\\\begin{itemize}\n\\n \\\\item \\\\textbf{モード} 現在の認可状態を表し、\n\\nallow、deny（やや語弊がありますが、単にエラーを意味します）、\n\\nignore（実際には拒否を意味します）、default（ベンダーが内部で設定したデフォルトのリストから推測されます）、\n\\nforeground（新しいAndroidシステムでは、アプリケーションがフォアグラウンドで実行中のときのみAppOpsが使用できることを意味します）があります。\n\\nまた、ベンダーが設定したいくつかのカスタムモード（例えば、MIUIの場合はask）があります。\n\\n\n\\n \\\\item \\\\textbf{使用した時間} このAppOpsが使用された時間を表します。\n\\n\n\\n \\\\item \\\\textbf{許可した時間} このAppOpsが最後に許可された時間を表します。\n\\n\n\\n \\\\item \\\\textbf{拒否した時間} このAppOpsが最後に拒否された時間を表します。\n\\n\\\\end{itemize}\n\\n\n\\n\\\\begin{tip}{Info}\n\\n このタブの内容は、ADBにてtexttt{android.permission.GET\\\\_APP\\\\_OPS\\\\_STATS}権限が付与されている場合、非Rootユーザーでも見ることができます。\n\\n\\\\end{tip}\n\\n\n\\n各AppOpsの項目の横にトグルボタンがあり、AppOpsを許可または拒否（無視）するために使用することができます。\n\\nデバイスで利用可能な他のモードを設定する必要がある場合は、項目を長押ししてください。\n\\nタブに表示されていないAppOpsを追加で設定する必要がある場合は、\n\\nメニューの\\\\textit{カスタムAppOpsを適用}オプションを使用します。\n\\nまた、\\\\textit{デフォルトに戻す}オプションを使用して変更内容をリセットしたり、\n\\nメニューの対応するオプションを使用して危険なAppOpsをすべて拒否したりすることができます。\n\\nまた、AppOpsの名前と関連する一意の番号（または値）で昇順に並べ替えることもできます。\n\\nまた、対応するソートオプションを使用して、拒否されたAppOpsを最初に表示することができます。\n\\n\n\\n\\\\begin{warning}{Warning}\n\\nAppOpsを拒否すると、アプリケーションが誤動作することがあります。\n\\nそのような場合は、\\\\textit{デフォルトに戻す}オプションを使用してください。\n\\nAppOpsの動作の性質上、システムがそれを適用するのに時間がかかることがあります。\n\\n\\\\end{warning}\n\\n\n\\n\\\\seealsoinline{\\\\hyperref[ch:app-ops]{付録: App Ops}}</string>\n    <string name=\"pages$app-details-page$uses-permissions\">\\\\textbf{Uses Permissions}は、アプリケーションで使用される権限です。マニフェストで\\\\texttt{uses-permission}タグを使用して宣言されます。\n\\n\\\\textit{フラグ}、\\\\textit{パーミッション名}、\\\\textit{パーミッションの説明}、\\\\textit{パッケージ名}、\\\\textit{グループ}などの情報は、\n\\n関連する\\\\hyperref[subsubsec:permissions]{権限}から取得されます。\n\\n\n\\n\\\\textbf{RootおよびADBユーザー}は、各権限項目の右側にあるトグルボタンを使用して、\n\\n\\\\textit{dangerous}権限と\\\\textit{development}権限を許可したり、取り消したりすることができます。\n\\nまた、メニューの対応するオプションを使用して、危険なパーミッションを一度に取り消すこともできます。\n\\nAndroidは\\\\textit{通常の} パーミッション（そのほとんどがそうですが）を変更することができないので、\n\\nこの2種類のパーミッションのみ取り消すことができます。\n\\n唯一の選択肢は、アプリケーションマニフェストを編集し、そこからこれらの権限を削除することです。\n\\n\n\\n\\\\begin{tip}{Info}\n\\ndangerous権限はシステムによってデフォルトで拒否されているため、\n\\nすべてのdangerous権限を取り消すことは、すべての権限をリセットすることと同じです。\n\\n\\\\end{tip}\n\\n\n\\n\\\\begin{tip}{Notice}\n\\nAPI23以前を対象としたアプリは、権限を変更することができません。\n\\nそのため、そのようなアプリではパーミッションの切り替えは無効です。\n\\n\\\\end{tip}\n\\n\n\\nユーザーは、権限名でソートしたり（昇順）、メニューの対応するオプションを使用して、拒否された権限や\n\\ndangerous権限を最初に表示するように選択することができます。</string>\n    <string name=\"pages$app-details-page$signatures-tab_1\">\\\\textbf{署名}は、実際には署名情報と呼ばれ、アプリケーションは公開する前に、\n\\nアプリケーション開発者によって1つ以上の署名証明書によって署名されます。\n\\nアプリケーションの完全性（そのアプリケーションが実際の開発者のものかどうか、\n\\n他の人によって変更されていないかどうか）は、署名情報を使って確認できます。\n\\nなぜなら、アプリケーションを第三者が変更した場合、署名情報は実際の開発者によって秘密にされているため、\n\\n元の証明書を使って再び署名することができないからです。\n\\nこれらの署名はチェックサムで検証することができます。チェックサムは、証明書自体から生成されます。\n\\n開発者がチェックサムを提供する場合、\\\\textbf{署名}タブで表示されたチェックサムを照合することができます。\n\\n例えば、Github、Telegramチャンネル、IzzyOnDroidのリポジトリからApp Managerをダウンロードした場合、次の\\\\textit{SHA256}チェックサムをこのタブに表示されるものと照合するだけで、そのアプリケーションが実際に私がリリースしたものかどうか確認することができます:</string>\n    <string name=\"pages$app-details-page$permissions\">\\\\textbf{パーミッション}は通常、アプリケーション自身によって定義されるカスタム権限です。\n\\n主に古いアプリケーションでは、通常の権限も含まれることがあります。そこに表示される各項目の完全な説明は次の通りです:\n\\n\\\\begin{itemize}\n\\n \\\\item \\\\textbf{権限名} 各権限は\\\\texttt{android.permission.INTERNET}のような一意の名前を持っており、\n\\n複数のアプリケーションがその権限を要求することができます。\n\\n\n\\n \\\\item \\\\textbf{アイコン} 各権限は任意のアイコンを持つことができます。\n\\n他の権限タブでは、アプリケーションマニフェストにアイコンが含まれていないため、アイコンを持ちません。\n\\n\n\\n \\\\item \\\\textbf{詳細} このフィールドは、権限についての詳細な説明です。権限に関連する説明がない場合、このフィールドは表示されません。\n\\n\n\\n \\\\item \\\\textbf{フラグ} (フラグシンボルまたは\\\\textbf{保護レベル}名を使用） \n\\ntextit{normal}, \\\\textit{development}, \\\\textit{dangerous}, \\\\textit{instant}, \\\\textit{granted}, \\\\textit{revoked},\\\\textit{signature}, \\\\textit{privileged}などの権限フラグを表します。\n\\n\n\\n \\\\item \\\\textbf{パッケージ名} 権限に関連するパッケージ名、すなわちその権限を定義したパッケージを表します。\n\\n\n\\n \\\\item \\\\textbf{グループ} 権限に関連するグループ名を表します。新しいAndroidシステムではグループ名を使用しないため、\n\\n通常\\\\texttt{android.permission-group.UNDEFINED}やグループ名が全く表示されないことになるでしょう。\n\\n\\\\end{itemize}</string>\n    <string name=\"keywords$see_also\">\\\\newcommand{\\\\KeywordSeeAlso}{こちらもご覧ください:}</string>\n    <string name=\"keywords$end_of_keyword_in_alert\">\\\\newcommand{\\\\KeywordEndOfKeyWordInAlert}{.}</string>\n    <string name=\"pages$one-click-ops-page$$block-unblock-trackers-title\">トラッカーのブロック/ブロック解除</string>\n    <string name=\"pages$one-click-ops-page$$set-mode-for-app-ops-dots-title\">AppOpsモードの設定\\\\dots</string>\n    <string name=\"pages$one-click-ops-page$$1-click-restore-title\">復元</string>\n    <string name=\"pages$one-click-ops-page$$section-title\">ワンタップ一括処理</string>\n    <string name=\"pages$one-click-ops-page$$block-components-dots-title\">コンポーネントのブロック\\\\dots</string>\n    <string name=\"pages$one-click-ops-page$$1-click-back-up-title\">バックアップ</string>\n    <string name=\"pages$app-details-page$$shared-libs-tab-title\">共有ライブラリタブ</string>\n</resources>"
  },
  {
    "path": "docs/raw/ko/index.html",
    "content": "<!doctype html><html xmlns=http://www.w3.org/1999/xhtml lang=ko xml:lang=ko><meta charset=utf-8><meta name=generator content=\"pandoc\"><meta name=viewport content=\"width=device-width,initial-scale=1,user-scalable=yes\"><meta name=author content=\"Muntashir Al-Islam\"><title>App Manager</title><style>code{white-space:pre-wrap}span.smallcaps{font-variant:small-caps}div.columns{display:flex;gap:min(4vw,1.5em)}div.column{flex:auto;overflow-x:auto}div.hanging-indent{margin-left:1.5em;text-indent:-1.5em}ul.task-list[class]{list-style:none}ul.task-list li input[type=checkbox]{font-size:inherit;width:.8em;margin:0 .8em .2em -1.6em;vertical-align:middle}.display.math{display:block;text-align:center;margin:.5rem auto}html{-webkit-text-size-adjust:100%}pre>code.sourceCode{white-space:pre;position:relative}pre>code.sourceCode>span{display:inline-block;line-height:1.25}pre>code.sourceCode>span:empty{height:1.2em}.sourceCode{overflow:visible}code.sourceCode>span{color:inherit;text-decoration:inherit}div.sourceCode{margin:1em 0}pre.sourceCode{margin:0}@media screen{div.sourceCode{overflow:auto}}@media print{pre>code.sourceCode{white-space:pre-wrap}pre>code.sourceCode>span{text-indent:-5em;padding-left:5em}}pre.numberSource code{counter-reset:source-line 0}pre.numberSource code>span{position:relative;left:-4em;counter-increment:source-line}pre.numberSource code>span>a:first-child::before{content:counter(source-line);position:relative;left:-1em;text-align:right;vertical-align:baseline;border:none;display:inline-block;-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;padding:0 4px;width:4em}pre.numberSource{margin-left:3em;padding-left:4px}div.sourceCode{}@media screen{pre>code.sourceCode>span>a:first-child::before{text-decoration:underline}}code span.al{font-weight:700}code span.an{font-style:italic}code span.cf{font-weight:700}code span.co{font-style:italic}code span.cv{font-style:italic}code span.do{font-style:italic}code span.dt{text-decoration:underline}code span.er{font-weight:700}code span.in{font-style:italic}code span.kw{font-weight:700}code span.pp{font-weight:700}code span.wa{font-style:italic}</style><link rel=stylesheet href=../css/custom.css><header id=title-block-header><h1 class=title>App Manager</h1><p class=author>Muntashir Al-Islam</header><nav id=TOC role=doc-toc><ul class=incremental><li><span><span class=toc-section-number>1</span> <a href=#ch:introduction id=toc:ch:introduction>소개</a></span><ul class=incremental><li><span><span class=toc-section-number>1.1</span> <a href=#sec:terminologies id=toc:sec:terminologies>용어</a></span><li><span><span class=toc-section-number>1.2</span> <a href=#sec:supported-versions id=toc:sec:supported-versions>지원되는\n버전</a></span><li><span><span class=toc-section-number>1.3</span> <a href=#sec:official-sources id=toc:sec:official-sources>공식\n출처</a></span><ul class=incremental><li><span><span class=toc-section-number>1.3.1</span> <a href=#subsec:binary-distribution-sources id=toc:subsec:binary-distribution-sources>이진 배포\n소스</a></span><li><span><span class=toc-section-number>1.3.2</span> <a href=#subsec:links-to-source-code id=toc:subsec:links-to-source-code>소스 코드 링크</a></span><li><span><span class=toc-section-number>1.3.3</span> <a href=#subsec:translations id=toc:subsec:translations>번역</a></span></ul><li><span><span class=toc-section-number>1.4</span> <a href=#sec:contributing id=toc:sec:contributing>기여</a></span><ul class=incremental><li><span><span class=toc-section-number>1.4.1</span> <a href=#subsec:build-instructions id=toc:subsec:build-instructions>빌드 설명</a></span><li><span><span class=toc-section-number>1.4.2</span> <a href=#subsec:submitting-patches id=toc:subsec:submitting-patches>패치 제출</a></span></ul><li><span><span class=toc-section-number>1.5</span> <a href=#sec:donation-&-funding id=toc:sec:donation-&-funding>기부 & 자금</a></span><li><span><span class=toc-section-number>1.6</span> <a href=#sec:contact id=toc:sec:contact>연락처</a></span></ul><li><span><span class=toc-section-number>2</span> <a href=#ch:pages id=toc:ch:pages>페이지</a></span><ul class=incremental><li><span><span class=toc-section-number>2.1</span> <a href=#sec:main-page id=toc:sec:main-page>메인 페이지</a></span><ul class=incremental><li><span><span class=toc-section-number>2.1.1</span> <a href=#subsec:batch-operations id=toc:subsec:batch-operations>일괄\n작업</a></span><li><span><span class=toc-section-number>2.1.2</span> <a href=#subsec:main-colour-codes id=toc:subsec:main-colour-codes>색상\n코드</a></span><li><span><span class=toc-section-number>2.1.3</span> <a href=#subsec:main-page-application-types id=toc:subsec:main-page-application-types>앱 종류</a></span><li><span><span class=toc-section-number>2.1.4</span> <a href=#subsec:main-page-version-info id=toc:subsec:main-page-version-info>버전 정보</a></span><li><span><span class=toc-section-number>2.1.5</span> <a href=#subsec:main-page-options-menu id=toc:subsec:main-page-options-menu>옵션 메뉴</a></span></ul><li><span><span class=toc-section-number>2.2</span> <a href=#sec:app-details-page id=toc:sec:app-details-page>앱 세부정보\n페이지</a></span><ul class=incremental><li><span><span class=toc-section-number>2.2.1</span> <a href=#subsec:app-details-colour-codes id=toc:subsec:app-details-colour-codes>색상 코드</a></span><li><span><span class=toc-section-number>2.2.2</span> <a href=#subsec:app-info-tab id=toc:subsec:app-info-tab>앱 정보\n탭</a></span><li><span><span class=toc-section-number>2.2.3</span> <a href=#subsec:component-tabs id=toc:subsec:component-tabs>구성 요소\n탭</a></span><li><span><span class=toc-section-number>2.2.4</span> <a href=#subsec:permission-tabs id=toc:subsec:permission-tabs>권한\n탭</a></span><li><span><span class=toc-section-number>2.2.5</span> <a href=#subsec:signatures-tab id=toc:subsec:signatures-tab>서명\n탭</a></span><li><span><span class=toc-section-number>2.2.6</span> <a href=#subsec:uses-features-tab id=toc:subsec:uses-features-tab>Uses\nFeatures tab</a></span><li><span><span class=toc-section-number>2.2.7</span> <a href=#subsec:configurations-tab id=toc:subsec:configurations-tab>Configurations tab</a></span><li><span><span class=toc-section-number>2.2.8</span> <a href=#subsec:shared-libs-tab id=toc:subsec:shared-libs-tab>공유\n라이브러리 탭</a></span></ul><li><span><span class=toc-section-number>2.3</span> <a href=#sec:1-click-ops-page id=toc:sec:1-click-ops-page>1-Click Ops\nPage</a></span><ul class=incremental><li><span><span class=toc-section-number>2.3.1</span> <a href=#subsec:block-unblock-trackers id=toc:subsec:block-unblock-trackers>Block/Unblock\nTrackers</a></span><li><span><span class=toc-section-number>2.3.2</span> <a href=#subsec:block-components-dots id=toc:subsec:block-components-dots>Block Components…</a></span><li><span><span class=toc-section-number>2.3.3</span> <a href=#subsec:set-mode-for-app-ops-dots id=toc:subsec:set-mode-for-app-ops-dots>Set Mode for App\nOps…</a></span><li><span><span class=toc-section-number>2.3.4</span> <a href=#subsec:1-click-back-up id=toc:subsec:1-click-back-up>Back\nup</a></span><li><span><span class=toc-section-number>2.3.5</span> <a href=#subsec:1-click-restore id=toc:subsec:1-click-restore>Restore</a></span><li><span><span class=toc-section-number>2.3.6</span> <a href=#subsec:trim-caches-in-all-apps id=toc:subsec:trim-caches-in-all-apps>Trim Caches in All\nApps</a></span></ul><li><span><span class=toc-section-number>2.4</span> <a href=#sec:profiles-page id=toc:sec:profiles-page>Profiles\nPage</a></span><ul class=incremental><li><span><span class=toc-section-number>2.4.1</span> <a href=#subsec:profiles-options-menu id=toc:subsec:profiles-options-menu>Options Menu</a></span></ul><li><span><span class=toc-section-number>2.5</span> <a href=#sec:profile-page id=toc:sec:profile-page>Profile\nPage</a></span><ul class=incremental><li><span><span class=toc-section-number>2.5.1</span> <a href=#subsec:profile-options-menu id=toc:subsec:profile-options-menu>Options Menu</a></span><li><span><span class=toc-section-number>2.5.2</span> <a href=#subsec:profile-apps-tab id=toc:subsec:profile-apps-tab>Apps\nTab</a></span><li><span><span class=toc-section-number>2.5.3</span> <a href=#subsec:profile-configurations-tab id=toc:subsec:profile-configurations-tab>Configurations\nTab</a></span></ul><li><span><span class=toc-section-number>2.6</span> <a href=#sec:settings-page id=toc:sec:settings-page>Settings\nPage</a></span><ul class=incremental><li><span><span class=toc-section-number>2.6.1</span> <a href=#subsec:language id=toc:subsec:language>Language</a></span><li><span><span class=toc-section-number>2.6.2</span> <a href=#subsec:appearance id=toc:subsec:appearance>Appearance</a></span><li><span><span class=toc-section-number>2.6.3</span> <a href=#subsec:privacy id=toc:subsec:privacy>Privacy</a></span><li><span><span class=toc-section-number>2.6.4</span> <a href=#subsec:mode-of-operation id=toc:subsec:mode-of-operation>Mode\nof Operation</a></span><li><span><span class=toc-section-number>2.6.5</span> <a href=#subsec:apk-signing id=toc:subsec:apk-signing>APK\nSigning</a></span><li><span><span class=toc-section-number>2.6.6</span> <a href=#subsec:installer id=toc:subsec:installer>Installer</a></span><li><span><span class=toc-section-number>2.6.7</span> <a href=#subsec:backup/restore id=toc:subsec:backup/restore>Back\nup/Restore</a></span><li><span><span class=toc-section-number>2.6.8</span> <a href=#subsec:rules id=toc:subsec:rules>Rules</a></span><li><span><span class=toc-section-number>2.6.9</span> <a href=#subsec:advanced id=toc:subsec:advanced>Advanced</a></span><li><span><span class=toc-section-number>2.6.10</span> <a href=#subsec:device-info id=toc:subsec:device-info>About the\ndevice</a></span></ul><li><span><span class=toc-section-number>2.7</span> <a href=#sec:scanner-page id=toc:sec:scanner-page>Scanner\nPage</a></span><li><span><span class=toc-section-number>2.8</span> <a href=#sec:interceptor-page id=toc:sec:interceptor-page>Interceptor\nPage</a></span><ul class=incremental><li><span><span class=toc-section-number>2.8.1</span> <a href=#subsec:intent-filters id=toc:subsec:intent-filters>Intent\nFilters</a></span><li><span><span class=toc-section-number>2.8.2</span> <a href=#subsec:matching-activities id=toc:subsec:matching-activities>Matching Activities</a></span><li><span><span class=toc-section-number>2.8.3</span> <a href=#subsec:interceptor-reset-to-default id=toc:subsec:interceptor-reset-to-default>Reset to\nDefault</a></span><li><span><span class=toc-section-number>2.8.4</span> <a href=#subsec:interceptor-send-edited-intent id=toc:subsec:interceptor-send-edited-intent>Send Edited\nIntent</a></span></ul><li><span><span class=toc-section-number>2.9</span> <a href=#sec:shared-preferences-editor-page id=toc:sec:shared-preferences-editor-page>Shared Preferences Editor\nPage</a></span></ul><li><span><span class=toc-section-number>3</span> <a href=#ch:guides id=toc:ch:guides>Guides</a></span><ul class=incremental><li><span><span class=toc-section-number>3.1</span> <a href=#sec:adb-over-tcp id=toc:sec:adb-over-tcp>ADB over\nTCP</a></span><ul class=incremental><li><span><span class=toc-section-number>3.1.1</span> <a href=#subsec:enable-developer-options id=toc:subsec:enable-developer-options>Enable developer\noptions</a></span><li><span><span class=toc-section-number>3.1.2</span> <a href=#subsec:enable-usb-debugging id=toc:subsec:enable-usb-debugging>Enable USB\ndebugging</a></span><li><span><span class=toc-section-number>3.1.3</span> <a href=#subsec:setup-adb-on-pc-or-mac id=toc:subsec:setup-adb-on-pc-or-mac>Setup ADB on PC or\nMac</a></span><li><span><span class=toc-section-number>3.1.4</span> <a href=#subsec:configure-adb-over-tcp id=toc:subsec:configure-adb-over-tcp>Configure ADB over\nTCP</a></span></ul><li><span><span class=toc-section-number>3.2</span> <a href=#sec:wireless-debugging id=toc:sec:wireless-debugging>Wireless\nDebugging</a></span><ul class=incremental><li><span><span class=toc-section-number>3.2.1</span> <a href=#subsec:enable-developer-options-and-usb-debugging id=toc:subsec:enable-developer-options-and-usb-debugging>Enable\ndeveloper options and USB Debugging</a></span><li><span><span class=toc-section-number>3.2.2</span> <a href=#subsec:enable-wireless-debugging id=toc:subsec:enable-wireless-debugging>Enable Wireless\nDebugging</a></span><li><span><span class=toc-section-number>3.2.3</span> <a href=#subsec:pair-adb-with-app-manager id=toc:subsec:pair-adb-with-app-manager>Pair ADB with App\nManager</a></span><li><span><span class=toc-section-number>3.2.4</span> <a href=#subsec:connect-app-manager-to-adb id=toc:subsec:connect-app-manager-to-adb>Connect App Manager to\nADB</a></span></ul><li><span><span class=toc-section-number>3.3</span> <a href=#sec:backup-restore id=toc:sec:backup-restore>Back\nup/Restore</a></span><ul class=incremental><li><span><span class=toc-section-number>3.3.1</span> <a href=#subsec:backup-location id=toc:subsec:backup-location>Location</a></span><li><span><span class=toc-section-number>3.3.2</span> <a href=#subsec:backup-restore-backup-options id=toc:subsec:backup-restore-backup-options>Backup\nOptions</a></span><li><span><span class=toc-section-number>3.3.3</span> <a href=#subsec:backup-restore-backup id=toc:subsec:backup-restore-backup>Backup</a></span><li><span><span class=toc-section-number>3.3.4</span> <a href=#subsec:backup-restore-restore id=toc:subsec:backup-restore-restore>Restore</a></span><li><span><span class=toc-section-number>3.3.5</span> <a href=#subsec:backup-restore-delete-backup id=toc:subsec:backup-restore-delete-backup>Delete\nBackup</a></span></ul><li><span><span class=toc-section-number>3.4</span> <a href=#sec:automating-tasks id=toc:sec:automating-tasks>Automating\nTasks</a></span><ul class=incremental><li><span><span class=toc-section-number>3.4.1</span> <a href=#subsec:generating-authorization-key id=toc:subsec:generating-authorization-key>Generating authorization\nkey</a></span><li><span><span class=toc-section-number>3.4.2</span> <a href=#subsec:at:general-configuration id=toc:subsec:at:general-configuration>Configuring\ntasks</a></span><li><span><span class=toc-section-number>3.4.3</span> <a href=#subsec:at:features id=toc:subsec:at:features>Features</a></span><li><span><span class=toc-section-number>3.4.4</span> <a href=#subsec:triggering-a-profile id=toc:subsec:triggering-a-profile>Triggering a\nprofile</a></span></ul><li><span><span class=toc-section-number>3.5</span> <a href=#sec:net-policy id=toc:sec:net-policy>Net\nPolicy</a></span></ul><li><span><span class=toc-section-number>4</span> <a href=#ch:faq id=toc:ch:faq>Frequently Asked Questions</a></span><ul class=incremental><li><span><span class=toc-section-number>4.1</span> <a href=#sec:faq:app-components id=toc:sec:faq:app-components>App\nComponents</a></span><ul class=incremental><li><span><span class=toc-section-number>4.1.1</span> <a href=#subsec:faq:what-are-app-components id=toc:subsec:faq:what-are-app-components>What are the application\ncomponents?</a></span><li><span><span class=toc-section-number>4.1.2</span> <a href=#subsec:faq:how-components-blocked id=toc:subsec:faq:how-components-blocked>How are the tracker and other\ncomponents blocked in App Manager? What are its\nlimitations?</a></span><li><span><span class=toc-section-number>4.1.3</span> <a href=#subsec:faq:components-blocked-by-others id=toc:subsec:faq:components-blocked-by-others>Does app components\nblocked by other tools retained in App Manager?</a></span><li><span><span class=toc-section-number>4.1.4</span> <a href=#subsec:faq:components-reblocked-in-am id=toc:subsec:faq:components-reblocked-in-am>What happens to the\ncomponents blocked by App Manager which were previously blocked by other\ntools?</a></span><li><span><span class=toc-section-number>4.1.5</span> <a href=#subsec:faq:what-is-instant-component-blocking id=toc:subsec:faq:what-is-instant-component-blocking>What is instant\ncomponent blocking?</a></span><li><span><span class=toc-section-number>4.1.6</span> <a href=#subsec:tracker-classes-versus-tracker-components id=toc:subsec:tracker-classes-versus-tracker-components>Tracker\nclasses versus tracker components</a></span></ul><li><span><span class=toc-section-number>4.2</span> <a href=#sec:faq:adb-over-tcp id=toc:sec:faq:adb-over-tcp>ADB over\nTCP</a></span><ul class=incremental><li><span><span class=toc-section-number>4.2.1</span> <a href=#subsec:faq:enable-adb-on-every-restart id=toc:subsec:faq:enable-adb-on-every-restart>Do I have to enable ADB\nover TCP everytime I restart?</a></span><li><span><span class=toc-section-number>4.2.2</span> <a href=#subsec:faq:usb-debugging id=toc:subsec:faq:usb-debugging>Cannot enable USB debugging. What to\ndo?</a></span><li><span><span class=toc-section-number>4.2.3</span> <a href=#subsec:faq:block-components-using-adb id=toc:subsec:faq:block-components-using-adb>Can I block tracker or\nany other application components using ADB over TCP?</a></span><li><span><span class=toc-section-number>4.2.4</span> <a href=#subsec:faq:adb-features id=toc:subsec:faq:adb-features>Which\nfeatures can be used in ADB mode?</a></span></ul><li><span><span class=toc-section-number>4.3</span> <a href=#sec:faq:miscellanea id=toc:sec:faq:miscellanea>Miscellanea</a></span><ul class=incremental><li><span><span class=toc-section-number>4.3.1</span> <a href=#subsec:faq:no-root-no-harms id=toc:subsec:faq:no-root-no-harms>I don’t use root/ADB. Am I\ncompletely safe from any harms?</a></span><li><span><span class=toc-section-number>4.3.2</span> <a href=#subsec:faq:how-trackers-libs-updated id=toc:subsec:faq:how-trackers-libs-updated>How are the trackers and\nlibraries are updated?</a></span><li><span><span class=toc-section-number>4.3.3</span> <a href=#subsec:faq:apks-deleted-after-installed id=toc:subsec:faq:apks-deleted-after-installed>Are APKs deleted after\ninstalled?</a></span><li><span><span class=toc-section-number>4.3.4</span> <a href=#subsec:faq:shizuku-support id=toc:subsec:faq:shizuku-support>Any plans for\nShizuku?</a></span><li><span><span class=toc-section-number>4.3.5</span> <a href=#subsec:faq:what-are-bloatware id=toc:subsec:faq:what-are-bloatware>What are bloatware and how to\nremove them?</a></span></ul></ul><li><span><span class=toc-section-number>5</span> <a href=#ch:specifications id=toc:ch:specifications>Specifications</a></span><ul class=incremental><li><span><span class=toc-section-number>5.1</span> <a href=#sec:rules-specification id=toc:sec:rules-specification>Rules\nSpecification</a></span><ul class=incremental><li><span><span class=toc-section-number>5.1.1</span> <a href=#background id=toc:background>Background</a></span><li><span><span class=toc-section-number>5.1.2</span> <a href=#rules-file-format id=toc:rules-file-format>Rules File\nFormat</a></span></ul></ul><li><span><span class=toc-section-number>6</span> <a href=#ch:changelogs id=toc:ch:changelogs>Changelogs</a></span><ul class=incremental><li><span><span class=toc-section-number>6.1</span> <a href=#sec:v4.0.5-(445) id=toc:sec:v4.0.5-(445)>v4.0.5\n(445)</a></span><li><span><span class=toc-section-number>6.2</span> <a href=#sec:v4.0.4-(444) id=toc:sec:v4.0.4-(444)>v4.0.4\n(444)</a></span><li><span><span class=toc-section-number>6.3</span> <a href=#sec:v4.0.3-(443) id=toc:sec:v4.0.3-(443)>v4.0.3\n(443)</a></span><li><span><span class=toc-section-number>6.4</span> <a href=#sec:v4.0.2-(442) id=toc:sec:v4.0.2-(442)>v4.0.2\n(442)</a></span><li><span><span class=toc-section-number>6.5</span> <a href=#sec:v4.0.1-(441) id=toc:sec:v4.0.1-(441)>v4.0.1\n(441)</a></span><ul class=incremental><li><span><span class=toc-section-number>6.5.1</span> <a href=#overlay-management id=toc:overlay-management>Overlay\nmanagement</a></span><li><span><span class=toc-section-number>6.5.2</span> <a href=#unfreeze-option-in-activity-shortcuts id=toc:unfreeze-option-in-activity-shortcuts>Unfreeze option in\nactivity shortcuts</a></span><li><span><span class=toc-section-number>6.5.3</span> <a href=#market-like-url-support id=toc:market-like-url-support><code>market</code>-like URL\nsupport</a></span><li><span><span class=toc-section-number>6.5.4</span> <a href=#updated-color-codes id=toc:updated-color-codes>Updated color\ncodes</a></span><li><span><span class=toc-section-number>6.5.5</span> <a href=#others id=toc:others>Others</a></span></ul><li><span><span class=toc-section-number>6.6</span> <a href=#sec:v4.0.0-(440) id=toc:sec:v4.0.0-(440)>v4.0.0\n(440)</a></span><ul class=incremental><li><span><span class=toc-section-number>6.6.1</span> <a href=#new-logo id=toc:new-logo>New logo!</a></span><li><span><span class=toc-section-number>6.6.2</span> <a href=#android-14-and-15-support id=toc:android-14-and-15-support>Android 14 and 15\nsupport</a></span><li><span><span class=toc-section-number>6.6.3</span> <a href=#revamped-debloater id=toc:revamped-debloater>Revamped\ndebloater</a></span><li><span><span class=toc-section-number>6.6.4</span> <a href=#introducing-file-manager id=toc:introducing-file-manager>Introducing file\nmanager</a></span><li><span><span class=toc-section-number>6.6.5</span> <a href=#integrated-code-editor id=toc:integrated-code-editor>Integrated code editor</a></span><li><span><span class=toc-section-number>6.6.6</span> <a href=#history-of-operations id=toc:history-of-operations>History of\noperations</a></span><li><span><span class=toc-section-number>6.6.7</span> <a href=#per-app-freezing-and-more id=toc:per-app-freezing-and-more>Per-app freezing, and\nmore</a></span><li><span><span class=toc-section-number>6.6.8</span> <a href=#log-viewer-enhancements id=toc:log-viewer-enhancements>Log\nviewer enhancements</a></span><li><span><span class=toc-section-number>6.6.9</span> <a href=#launching-non-exported-activities id=toc:launching-non-exported-activities>Launching non-exported\nactivities</a></span><li><span><span class=toc-section-number>6.6.10</span> <a href=#new-tags-in-app-info-tab id=toc:new-tags-in-app-info-tab>New\ntags in App Info tab</a></span><li><span><span class=toc-section-number>6.6.11</span> <a href=#per-session-installer-options id=toc:per-session-installer-options>Per-session installer\noptions</a></span><li><span><span class=toc-section-number>6.6.12</span> <a href=#advanced-mode-of-operations-adb-enhancements id=toc:advanced-mode-of-operations-adb-enhancements>Advanced mode of\noperations, ADB enhancements, …</a></span><li><span><span class=toc-section-number>6.6.13</span> <a href=#data-usage-widget-and-more id=toc:data-usage-widget-and-more>Data usage widget, and\nmore</a></span><li><span><span class=toc-section-number>6.6.14</span> <a href=#others-1 id=toc:others-1>Others</a></span></ul><li><span><span class=toc-section-number>6.7</span> <a href=#sec:v3.1.0-(423) id=toc:sec:v3.1.0-(423)>v3.1.0\n(423)</a></span><ul class=incremental><li><span><span class=toc-section-number>6.7.1</span> <a href=#android-13-support id=toc:android-13-support>Android 13\nsupport</a></span><li><span><span class=toc-section-number>6.7.2</span> <a href=#introducing-freezeunfreeze id=toc:introducing-freezeunfreeze>Introducing\nfreeze/unfreeze</a></span><li><span><span class=toc-section-number>6.7.3</span> <a href=#export-app-list id=toc:export-app-list>Export app\nlist</a></span><li><span><span class=toc-section-number>6.7.4</span> <a href=#elliptic-curve-crypography-ecc id=toc:elliptic-curve-crypography-ecc>Elliptic Curve Crypography\n(ECC)</a></span><li><span><span class=toc-section-number>6.7.5</span> <a href=#new-languages id=toc:new-languages>New\nlanguages</a></span><li><span><span class=toc-section-number>6.7.6</span> <a href=#more-list-options id=toc:more-list-options>More list\noptions</a></span><li><span><span class=toc-section-number>6.7.7</span> <a href=#improved-handling-of-mode-of-operation id=toc:improved-handling-of-mode-of-operation>Improved handling of\nmode of operation</a></span><li><span><span class=toc-section-number>6.7.8</span> <a href=#handling-multiple-users id=toc:handling-multiple-users>Handling multiple users</a></span><li><span><span class=toc-section-number>6.7.9</span> <a href=#explorer-enhancements id=toc:explorer-enhancements>Explorer\nenhancements</a></span><li><span><span class=toc-section-number>6.7.10</span> <a href=#new-tag-wx id=toc:new-tag-wx>New tag: WX</a></span><li><span><span class=toc-section-number>6.7.11</span> <a href=#app-ops-management id=toc:app-ops-management>App ops\nmanagement</a></span><li><span><span class=toc-section-number>6.7.12</span> <a href=#batch-uninstallation id=toc:batch-uninstallation>Batch\nuninstallation</a></span><li><span><span class=toc-section-number>6.7.13</span> <a href=#running-apps id=toc:running-apps>Running apps</a></span><li><span><span class=toc-section-number>6.7.14</span> <a href=#interceptor id=toc:interceptor>Interceptor</a></span><li><span><span class=toc-section-number>6.7.15</span> <a href=#device-specific-changes id=toc:device-specific-changes>Device-specific changes</a></span><li><span><span class=toc-section-number>6.7.16</span> <a href=#others-2 id=toc:others-2>Others</a></span></ul><li><span><span class=toc-section-number>6.8</span> <a href=#sec:v3.0.0-(410) id=toc:sec:v3.0.0-(410)>v3.0.0\n(410)</a></span><ul class=incremental><li><span><span class=toc-section-number>6.8.1</span> <a href=#material-3-and-more id=toc:material-3-and-more>Material 3 and\nMore</a></span><li><span><span class=toc-section-number>6.8.2</span> <a href=#wireless-debugging id=toc:wireless-debugging>Wireless\nDebugging</a></span><li><span><span class=toc-section-number>6.8.3</span> <a href=#languages id=toc:languages>Languages</a></span><li><span><span class=toc-section-number>6.8.4</span> <a href=#introducing-app-explorer id=toc:introducing-app-explorer>Introducing App\nExplorer</a></span><li><span><span class=toc-section-number>6.8.5</span> <a href=#import-backups-from-other-applications id=toc:import-backups-from-other-applications>Import Backups from\nOther Applications</a></span><li><span><span class=toc-section-number>6.8.6</span> <a href=#virustotal id=toc:virustotal>VirusTotal</a></span><li><span><span class=toc-section-number>6.8.7</span> <a href=#trigger-profiles-from-the-automation-software id=toc:trigger-profiles-from-the-automation-software>Trigger Profiles\nfrom the Automation Software</a></span><li><span><span class=toc-section-number>6.8.8</span> <a href=#improved-application-installer id=toc:improved-application-installer>Improved Application\nInstaller</a></span><li><span><span class=toc-section-number>6.8.9</span> <a href=#component-blocking id=toc:component-blocking>Component\nBlocking</a></span><li><span><span class=toc-section-number>6.8.10</span> <a href=#advanced-searching id=toc:advanced-searching>Advanced\nSearching</a></span><li><span><span class=toc-section-number>6.8.11</span> <a href=#shared-libraries id=toc:shared-libraries>Shared\nLibraries</a></span><li><span><span class=toc-section-number>6.8.12</span> <a href=#make-the-best-use-of-interceptor id=toc:make-the-best-use-of-interceptor>Make the Best Use of\nInterceptor</a></span><li><span><span class=toc-section-number>6.8.13</span> <a href=#widget-screen-time id=toc:widget-screen-time>Widget: Screen\nTime</a></span><li><span><span class=toc-section-number>6.8.14</span> <a href=#widget-clear-cache id=toc:widget-clear-cache>Widget: Clear\nCache</a></span></ul><li><span><span class=toc-section-number>6.9</span> <a href=#sec:v2.6.0-(385) id=toc:sec:v2.6.0-(385)>v2.6.0\n(385)</a></span><ul class=incremental><li><span><span class=toc-section-number>6.9.1</span> <a href=#introducing-backups id=toc:introducing-backups>Introducing\nBackups</a></span><li><span><span class=toc-section-number>6.9.2</span> <a href=#introducing-log-viewer id=toc:introducing-log-viewer>Introducing Log Viewer</a></span><li><span><span class=toc-section-number>6.9.3</span> <a href=#lock-app-manager id=toc:lock-app-manager>Lock App\nManager</a></span><li><span><span class=toc-section-number>6.9.4</span> <a href=#extended-modes-for-app-ops id=toc:extended-modes-for-app-ops>Extended Modes for App\nOps</a></span><li><span><span class=toc-section-number>6.9.5</span> <a href=#new-batch-ops-add-to-profile id=toc:new-batch-ops-add-to-profile>New Batch Ops: Add to\nProfile</a></span><li><span><span class=toc-section-number>6.9.6</span> <a href=#app-info-improved id=toc:app-info-improved>App Info:\nImproved</a></span><li><span><span class=toc-section-number>6.9.7</span> <a href=#advanced-sort-and-filtering-options-in-the-main-page id=toc:advanced-sort-and-filtering-options-in-the-main-page>Advanced\nSort and Filtering Options in the Main Page</a></span><li><span><span class=toc-section-number>6.9.8</span> <a href=#about-this-device id=toc:about-this-device>About This\nDevice</a></span><li><span><span class=toc-section-number>6.9.9</span> <a href=#enabledisable-features id=toc:enabledisable-features>Enable/disable Features</a></span><li><span><span class=toc-section-number>6.9.10</span> <a href=#new-languages-1 id=toc:new-languages-1>New\nLanguages</a></span><li><span><span class=toc-section-number>6.9.11</span> <a href=#signing-the-apk-files id=toc:signing-the-apk-files>Signing the\nAPK Files</a></span><li><span><span class=toc-section-number>6.9.12</span> <a href=#new-extension-unapkm id=toc:new-extension-unapkm>New\nExtension: UnAPKM</a></span></ul><li><span><span class=toc-section-number>6.10</span> <a href=#sec:v2.5.20-(375) id=toc:sec:v2.5.20-(375)>v2.5.20\n(375)</a></span><ul class=incremental><li><span><span class=toc-section-number>6.10.1</span> <a href=#subsec:introducing-profiles id=toc:subsec:introducing-profiles>Introducing\nProfiles</a></span><li><span><span class=toc-section-number>6.10.2</span> <a href=#subsec:the-interceptor id=toc:subsec:the-interceptor>The\nInterceptor</a></span><li><span><span class=toc-section-number>6.10.3</span> <a href=#subsec:unapkm:-dedrm-the-apkm-files id=toc:subsec:unapkm:-dedrm-the-apkm-files>UnAPKM: DeDRM the APKM\nfiles</a></span><li><span><span class=toc-section-number>6.10.4</span> <a href=#subsec:multiple-user id=toc:subsec:multiple-user>Multiple\nuser</a></span><li><span><span class=toc-section-number>6.10.5</span> <a href=#vive-la-france id=toc:vive-la-france>Vive la\nFrance!</a></span><li><span><span class=toc-section-number>6.10.6</span> <a href=#report-crashes id=toc:report-crashes>Report\ncrashes</a></span><li><span><span class=toc-section-number>6.10.7</span> <a href=#android-11 id=toc:android-11>Android 11</a></span><li><span><span class=toc-section-number>6.10.8</span> <a href=#app-installer-improvements id=toc:app-installer-improvements>App Installer\nImprovements</a></span></ul><li><span><span class=toc-section-number>6.11</span> <a href=#v2.5.17-368 id=toc:v2.5.17-368>v2.5.17 (368)</a></span><ul class=incremental><li><span><span class=toc-section-number>6.11.1</span> <a href=#app-installer id=toc:app-installer>App\nInstaller</a></span><li><span><span class=toc-section-number>6.11.2</span> <a href=#scanner-replacement-for-exodus-page id=toc:scanner-replacement-for-exodus-page>Scanner: Replacement for\nExodus Page</a></span><li><span><span class=toc-section-number>6.11.3</span> <a href=#introducing-system-config id=toc:introducing-system-config>Introducing System\nConfig</a></span><li><span><span class=toc-section-number>6.11.4</span> <a href=#more-languages id=toc:more-languages>More\nLanguages</a></span><li><span><span class=toc-section-number>6.11.5</span> <a href=#app-info-tab id=toc:app-info-tab>App Info Tab</a></span><li><span><span class=toc-section-number>6.11.6</span> <a href=#navigation-improvements id=toc:navigation-improvements>Navigation Improvements</a></span><li><span><span class=toc-section-number>6.11.7</span> <a href=#running-apps-page id=toc:running-apps-page>Running Apps\nPage</a></span><li><span><span class=toc-section-number>6.11.8</span> <a href=#built-in-toybox id=toc:built-in-toybox>Built-in\nToybox</a></span><li><span><span class=toc-section-number>6.11.9</span> <a href=#component-blocker-improvements id=toc:component-blocker-improvements>Component Blocker\nImprovements</a></span><li><span><span class=toc-section-number>6.11.10</span> <a href=#improvements-in-the-app-details-page id=toc:improvements-in-the-app-details-page>Improvements in the App\nDetails Page</a></span><li><span><span class=toc-section-number>6.11.11</span> <a href=#app-manifest id=toc:app-manifest>App Manifest</a></span></ul><li><span><span class=toc-section-number>6.12</span> <a href=#v2.5.13-348 id=toc:v2.5.13-348>v2.5.13 (348)</a></span><ul class=incremental><li><span><span class=toc-section-number>6.12.1</span> <a href=#bundled-app-split-apk id=toc:bundled-app-split-apk>Bundled App\n(Split APK)</a></span><li><span><span class=toc-section-number>6.12.2</span> <a href=#direct-install-support id=toc:direct-install-support>Direct\nInstall Support</a></span><li><span><span class=toc-section-number>6.12.3</span> <a href=#remove-all-blocking-rules id=toc:remove-all-blocking-rules>Remove All Blocking\nRules</a></span><li><span><span class=toc-section-number>6.12.4</span> <a href=#app-ops-1 id=toc:app-ops-1>App Ops</a></span><li><span><span class=toc-section-number>6.12.5</span> <a href=#enhanced-adb-support id=toc:enhanced-adb-support>Enhanced ADB\nSupport</a></span><li><span><span class=toc-section-number>6.12.6</span> <a href=#filtering-in-main-page id=toc:filtering-in-main-page>Filtering\nin Main Page</a></span><li><span><span class=toc-section-number>6.12.7</span> <a href=#apk-backupsharing id=toc:apk-backupsharing>Apk\nBackup/Sharing</a></span><li><span><span class=toc-section-number>6.12.8</span> <a href=#batch-ops id=toc:batch-ops>Batch Ops</a></span><li><span><span class=toc-section-number>6.12.9</span> <a href=#translations id=toc:translations>Translations</a></span><li><span><span class=toc-section-number>6.12.10</span> <a href=#app-data-backup id=toc:app-data-backup>App Data\nBackup</a></span></ul></ul><li><span><span class=toc-section-number>7</span> <a href=#ch:app-ops id=toc:ch:app-ops>App Ops</a></span><ul class=incremental><li><span><span class=toc-section-number>7.1</span> <a href=#sec:app-ops-background id=toc:sec:app-ops-background>Background</a></span><li><span><span class=toc-section-number>7.2</span> <a href=#sec:introduction-to-app-ops id=toc:sec:introduction-to-app-ops>Introduction to App\nOps</a></span><li><span><span class=toc-section-number>7.3</span> <a href=#sec:appopsmanager id=toc:sec:appopsmanager>AppOpsManager</a></span><ul class=incremental><li><span><span class=toc-section-number>7.3.1</span> <a href=#subsec:op-constants id=toc:subsec:op-constants><code>OP_*</code> Constants</a></span><li><span><span class=toc-section-number>7.3.2</span> <a href=#subsec:mode-constants id=toc:subsec:mode-constants><code>MODE_*</code>\nConstants</a></span><li><span><span class=toc-section-number>7.3.3</span> <a href=#subsec:package-ops id=toc:subsec:package-ops>PackageOps</a></span><li><span><span class=toc-section-number>7.3.4</span> <a href=#subsec:opentry id=toc:subsec:opentry>OpEntry</a></span><li><span><span class=toc-section-number>7.3.5</span> <a href=#subsec:usage id=toc:subsec:usage>Usage</a></span></ul><li><span><span class=toc-section-number>7.4</span> <a href=#sec:appopsservice id=toc:sec:appopsservice>AppOpsService</a></span><li><span><span class=toc-section-number>7.5</span> <a href=#sec:appops-xml id=toc:sec:appops-xml>appops.xml</a></span><li><span><span class=toc-section-number>7.6</span> <a href=#sec:appops-cli id=toc:sec:appops-cli>Command Line\nInterface</a></span></ul></ul></nav><div class=titlingpage><div class=center><p><img src=../images/icon.png style=width:1in alt=image><p><strong><span class=smallcaps>App Manager</span></strong><p>영어<p><strong>사용자 매뉴얼</strong><p><em>v4.0.5</em><p>27 7월 2025<p>Copyright © 2020–2025 Muntashir Al-Islam<blockquote><p>“현명하고 신중해라. 빨리 달리면 넘어지게 마련이다.” <span>— 수도사\n로렌스, <em>로미오와 줄리엣</em></span></blockquote></div></div><section id=ch:introduction class=level1 data-number=1><h1 data-number=1><span class=header-section-number>1</span> <a href=#toc:ch:introduction>소개</a><a href=#ch:introduction class=anchor aria-hidden=true></a></h1><p>App Manager는 안드로이드용 고급 패키지 매니저입니다. 수많은 기능을\n갖추고 있어 사용자를 지원하기 위한 사용자 매뉴얼이 필요합니다. 이 문서는\nApp Manager가 제공하는 모든 기능을 설명하는 것을 목적으로 하며 App\nManager 의 사용자 매뉴얼로 기능합니다. 또한 이 문서는 App Manager의 공식\n가이드라인으로 볼 수도 있고 App Manager가 원하는 동작을 나타내기도\n합니다. 번역에 의해 이 문서(영어로 쓰여저 있다)가 오해 받을 가능성이\n있습니다. 따라서, 모든 유능한 사용자는 App Manager를 최대한 활용하기\n위해 영문 문서를 읽어야 합니다. 블로그 기사, 비디오, 채팅 그룹 등 다른\n비공식 또는 서드파티의 자원 역시 존재할 수 있습니다. 이러한 리소스는\n많은 사람들에게 유용할 수 있지만 App Manager의 최신 버전을 지원하지 않을\n수 있습니다. App Manager에서 해당 문서에서 일탈이 검출되면 App Manager의\n<a href=https://github.com/MuntashirAkon/AppManager/issues>App Manager\n이슈 트래커</a>에서 보고해야 합니다.<section id=sec:terminologies class=level2 data-number=1.1><h2 data-number=1.1><span class=header-section-number>1.1</span> <a href=#toc:sec:terminologies>용어</a><a href=#sec:terminologies class=anchor aria-hidden=true></a></h2><ul class=incremental><li><p><strong>AM</strong> — App Manager의 약칭.<li><p><strong>Block/Unblock</strong> — 구성 요소 차단 또는 차단 해제에\n사용됩니다. 구성 요소가 차단되는 방법은 사용자 기본 설정에 따라\n설정됩니다.<li><p><strong>IFW</strong> — 의도된 방화벽의 약식입니다.<li><p><strong>Ops</strong> — 작업의 단축형 작업 이름(예: app ops, 배치\nops, 원클릭 ops)<li><p><strong>SSAID</strong> —\n<code>Settings.Secure.ANDROID_ID</code>의 짧은 형식입니다. 각\n앱(안드로이드 오레오 이상)에 할당된 장치 식별자이다. 앱의 서명 인증서와\n패키지 <code>android</code>에 대한 SSAID 세트의 조합에서 생성됩니다.\nSSAID는 사용자가 장치를 초기화하지 않는 한 그 앱의 ID는 동일합니다.\n그것은 추적에 널리 사용된다.<li><p><strong>Tracker</strong> — <a href=#sec:scanner-page>scanner\npage</a>를 제외하고 문서 전체와 장치 관리자에서 추적기 구성 요소를\n나타냅니다. 추적기에는 충돌 리포터, 분석, 자료 수집, 식별, 광고, 위치\n등의 라이브러리가 포함됩니다. 따라서, 그들은 기능 면에서 같지 않습니다.\n추적을 촉진하는 오픈 소스 라이브러리와 클로즈드 소스 라이브러리 사이에는\n차이가 없습니다.</ul></section><section id=sec:supported-versions class=level2 data-number=1.2><h2 data-number=1.2><span class=header-section-number>1.2</span> <a href=#toc:sec:supported-versions>지원되는 버전</a><a href=#sec:supported-versions class=anchor aria-hidden=true></a></h2><p>현재 지원되는 버전은 v3.0.4와 v3.1.0 (안정), v3.2.0 (알파 &\n디버그 릴리즈)입니다. App Manager의 이전 버전에는 보안 취약점이 있을 수\n있으므로 사용하지 마십시오.</section><section id=sec:official-sources class=level2 data-number=1.3><h2 data-number=1.3><span class=header-section-number>1.3</span> <a href=#toc:sec:official-sources>공식 출처</a><a href=#sec:official-sources class=anchor aria-hidden=true></a></h2><section id=subsec:binary-distribution-sources class=level3 data-number=1.3.1><h3 data-number=1.3.1><span class=header-section-number>1.3.1</span>\n<a href=#toc:subsec:binary-distribution-sources>이진 배포 소스</a><a href=#subsec:binary-distribution-sources class=anchor aria-hidden=true></a></h3><p>App Manager는 다음 소스들을기반으로 배포하고 있습니다. 비공식\n소스들은 App Manager의 변형된 버전을 배포할 수 있으며, 이러한 배포\n버전을 사용했을 경우 모든 책임은 귀하에게 있습니다.<ol class=incremental><li><p>공식 F-Droid Repository.<a href=#fn1 class=footnote-ref id=fnref1 role=doc-noteref><sup>1</sup></a><br><em>Link:</em> <a href=https://f-droid.org/packages/io.github.muntashirakon.AppManager class=uri>https://f-droid.org/packages/io.github.muntashirakon.AppManager</a><li><p>GitHub repository.<br><em>Normal releases:</em> <a href=https://github.com/MuntashirAkon/AppManager/releases class=uri>https://github.com/MuntashirAkon/AppManager/releases</a><br><em>Debug releases:</em> <a href=https://github.com/MuntashirAkon/AppManager/actions class=uri>https://github.com/MuntashirAkon/AppManager/actions</a><li><p>텔레그램.<br><em>Normal releases:</em> <a href=https://t.me/AppManagerChannel class=uri>https://t.me/AppManagerChannel</a><br><em>Debug releases:</em> <a href=https://t.me/AppManagerDebug class=uri>https://t.me/AppManagerDebug</a></ol></section><section id=subsec:links-to-source-code class=level3 data-number=1.3.2><h3 data-number=1.3.2><span class=header-section-number>1.3.2</span>\n<a href=#toc:subsec:links-to-source-code>소스 코드 링크</a><a href=#subsec:links-to-source-code class=anchor aria-hidden=true></a></h3><p>GitHub를 제외한 모두 미러 링크입니다. 태그는 항상 최신 상태이지만,\n마스터 브랜치는 최신 상태를 보장할 수 없습니다. 마스터 브랜치를\n복제(clone)하는 것이 목적이면, 다른 링크 대신 GitHub 링크를\n사용하십시오.<ol class=incremental><li><p>GitHub: <a href=https://github.com/MuntashirAkon/AppManager class=uri>https://github.com/MuntashirAkon/AppManager</a><li><p>Codeberg: <a href=https://codeberg.org/muntashir/AppManager class=uri>https://codeberg.org/muntashir/AppManager</a><li><p>GitLab: <a href=https://gitlab.com/muntashir/AppManager class=uri>https://gitlab.com/muntashir/AppManager</a><li><p>Riseup: <a href=https://0xacab.org/muntashir/AppManager class=uri>https://0xacab.org/muntashir/AppManager</a><li><p>sourcehut: <a href=https://git.sr.ht/~muntashir/AppManager class=uri>https://git.sr.ht/~muntashir/AppManager</a></ol></section><section id=subsec:translations class=level3 data-number=1.3.3><h3 data-number=1.3.3><span class=header-section-number>1.3.3</span>\n<a href=#toc:subsec:translations>번역</a><a href=#subsec:translations class=anchor aria-hidden=true></a></h3><p>App Manager는 직접적인 pull/merge 요청의 번역은 수락하지 않습니다.\n번역은 Hosted Weblate를 통해서 진행됩니다. App Manager를 번역하시려면,\n<a href=https://hosted.weblate.org/engage/app-manager/ class=uri>https://hosted.weblate.org/engage/app-manager/</a>을 방문해\n주십시오.</section></section><section id=sec:contributing class=level2 data-number=1.4><h2 data-number=1.4><span class=header-section-number>1.4</span> <a href=#toc:sec:contributing>기여</a><a href=#sec:contributing class=anchor aria-hidden=true></a></h2><p>사용자가 기여할 수 있는 여러 방법이 있습니다. 예를 들어 유용한 문제를\n제기, 토론에 참여, 문서화 및 번역을 개선, 인식되지 않은 라이브러리와\n트래커 추가, 소스 코드 검토 및 보안 취약성 보고하기 등이 있습니다.<section id=subsec:build-instructions class=level3 data-number=1.4.1><h3 data-number=1.4.1><span class=header-section-number>1.4.1</span>\n<a href=#toc:subsec:build-instructions>빌드 설명</a><a href=#subsec:build-instructions class=anchor aria-hidden=true></a></h3><p>빌드 지침은 소스의 루트 디렉터리에 있는 BUILDING 파일에서 찾을 수\n있습니다.</section><section id=subsec:submitting-patches class=level3 data-number=1.4.2><h3 data-number=1.4.2><span class=header-section-number>1.4.2</span>\n<a href=#toc:subsec:submitting-patches>패치 제출</a><a href=#subsec:submitting-patches class=anchor aria-hidden=true></a></h3><p>GitHub 이외의 사이트에 위치한 repository는 현재 미러로 간주되며, 미러\n사이트에서 pull/merge 요청은 받아들여지지 않을 것입니다. <a href=#fn2 class=footnote-ref id=fnref2 role=doc-noteref><sup>2</sup></a>\n대신, 패치(<code>.patch</code> 파일 형식)들은 이메일 첨부 파일로 제출할\n수 있습니다. <em>Signing-off 서명은 필수입니다.</em> 자세한 내용은\n소스의 루트 디렉토리에 CONTRIBUTING 파일은 참고하십시오.<div class=\"amalert warning\"><p><strong><em>Notice.</em></strong><p>이메일로 패치 제출, 향후 대화 전체를 공개적으로 접근할 수도 있습니다\n. 그러므로 이름과 이메일 주소 외에는 개인 식별 정보(PII)는 포함하지\n마십시오.</div></section></section><section id=sec:donation-&-funding class=level2 data-number=1.5><h2 data-number=1.5><span class=header-section-number>1.5</span> <a href=#toc:sec:donation-&-funding>기부 & 자금</a><a href=#sec:donation-&-funding class=anchor aria-hidden=true></a></h2><p><em>기부금이나 구매는 App Manager사용을 위한 필수 조건이\n아닙니다.</em> App Manager 어떤 구매도 지원하지 않지만, Open Source\nCollective를 통해 기부금을 보낼 수 있습니다.<p>Open Source Collective는 오픈소스 프로젝트들의 재정 관리를 도와주는\nOpen Collective 플랫폼의 재정 호스트입니다. 현재는 계좌 이체, 페이팔,\n신용카드나 암호화폐를 통한 결제를 지원하고 있습니다.<p><em>링:</em> <a href=https://opencollective.com/muntashir class=uri>https://opencollective.com/muntashir</a>.<p>기부금을 보내는 사람들은 자신들이 요청하는 기능이 우선적으로\n추가되도록 요구하는 지렛대가 되도록 기부금을 사용해서는 안 된다는 데\n동의한다. 기능 요청은 어떠한 현상금이나 기부도 필요하지 않으며, 개발자의\n선호도에 따라 우선순위가 정해집니다.<p><em>App Manager는 모든 지원금이나 보조금을 제안을 수락합니 .</em>\n관심있는 조직들의 대표자분들은 §<a href=#sec:contact data-reference-type=ref data-reference=sec:contact>1.6</a>에 주어진\n옵션을 통해 소유자에게 직접 연락을 취할 수 있습니다.<p>In addition, the maintainers and contributors of this project DO NOT\nconsent to the creation, sale, or promotion of tokens, cryptocurrencies,\nNFTs, or any other financial instruments that claim to represent this\nproject, its code, or its community. Any such attempts are unauthorized\nand not affiliated with this project in any way.</section><section id=sec:contact class=level2 data-number=1.6><h2 data-number=1.6><span class=header-section-number>1.6</span> <a href=#toc:sec:contact>연락처</a><a href=#sec:contact class=anchor aria-hidden=true></a></h2><p>Muntashir Al-Islam<a href=#fn3 class=footnote-ref id=fnref3 role=doc-noteref><sup>3</sup></a><br>이메일: <a href=mailto:muntashirakon@riseup.net>muntashirakon [at]\nriseup [dot] net</a><br>Key 지문: <code>7bad37c2981e41f8f6abea7f58f0b4f26c346fce</code><br>GitHub: <a href=https://github.com/MuntashirAkon class=uri>https://github.com/MuntashirAkon</a><br>트위터: <a href=https://twitter.com/Muntashir class=uri>https://twitter.com/Muntashir</a></section></section><section id=ch:pages class=level1 data-number=2><h1 data-number=2><span class=header-section-number>2</span> <a href=#toc:ch:pages>페이지</a><a href=#ch:pages class=anchor aria-hidden=true></a></h1><section id=sec:main-page class=level2 data-number=2.1><h2 data-number=2.1><span class=header-section-number>2.1</span> <a href=#toc:sec:main-page>메인 페이지</a><a href=#sec:main-page class=anchor aria-hidden=true></a></h2><p>메인 페이지에는 설치, 제거 또는 백업된 모든 앱이 나열됩니다. 설치된\n앱 항복을 클릭하면 해당되는 <a href=#sec:app-details-page>앱 세부정보\n페이지</a>를 엽니다. 제거된 시스템 앱의 경우, 앱을 다시 설치할 수 있는\n대화 상자 프롬프트가 표시됩니다. 목록 옵션에서 <a href=#par:main-page-sort>정렬</a> 옵션을 사용하면, 앱 항목들을 다양한\n방법으로 정렬하고 종료 시 저장할 수 있습니다. 목록 옵션에서 <a href=#par:main-page-filter>filter</a> 옵션을 사용해서 항목을 필터링할\n수도 있습니다. 정규식을 추가적으로 지원하는 검색창을 통해서도 필터링이\n가능합니다.<figure id=fig:main_page_entry_info_labeled><figure><object data=../images/main_page_entry_info_labeled.svg type=image/svg+xml></object></figure><figcaption>Figure 1: 메인 페이지의 앱 목록 항목</figcaption></figure><section id=subsec:batch-operations class=level3 data-number=2.1.1><h3 data-number=2.1.1><span class=header-section-number>2.1.1</span>\n<a href=#toc:subsec:batch-operations>일괄 작업</a><a href=#subsec:batch-operations class=anchor aria-hidden=true></a></h3><p>여러 앱에서의 배치 작업 혹은 작업도 이 페이지에서 가능합니다. 앱\n아이콘을 클릭하거나 목록의 항목을 길게 클릭하여 다중 선택 모드를\n활성화할 수 있습니다. 활성화 후, 목록 항목을 클릭하면 앱 세부 정보\n페이지를 여는 대신 해당 항목이 선택됩니다. 이 모드에서, 배치 작업은\n페이지 하단의 다중 선택 메뉴에 있습니다. 포함된 작업은:<ul class=incremental><li><p>선택된 앱을 <a href=#sec:profiles-page>프로필</a>에\n추가하기<li><p>앱을 <a href=#sec:backup-restore>백업, 복구 혹은\n삭제</a><li><p>앱에서의 트래커를 차단하기<li><p>앱에서 데이터 혹은 캐시 삭제하기<li><p>앱을 활성화/비활성화/강제종료/제거하기<li><p>App Manager에 저장된 블록킹 규칙을 내보내기<li><p>앱의 백그라운드 실행을 방지하기 (안드로이드 7부터)<li><p>APK 파일을 <code>AppManager/apks</code>에 저장하기<li><p><a href=#sec:net-policy>네트워크 정책</a> 설정하기</ul><div class=\"amalert tip\"><p><strong><em>Accessibility.</em></strong><p>다중 선택 모드 활성화 후, 키보드 혹은 리모컨의 좌우 버튼을 사용해서\n다중 선택 영역 탐색이 가능합니다.</div></section><section id=subsec:main-colour-codes class=level3 data-number=2.1.2><h3 data-number=2.1.2><span class=header-section-number>2.1.2</span>\n<a href=#toc:subsec:main-colour-codes>색상 코드</a><a href=#subsec:main-colour-codes class=anchor aria-hidden=true></a></h3><ul class=incremental><li><p><span class=colorbox style=background-color:#fceed1><span style=color:#000>Light greyish orange (day)</span></span> / <span class=colorbox style=background-color:#091f36><span style=color:#fff>dark\nblue (night)</span></span> – 앱이 일괄 작업의 대상으로\n선택되었습니다<li><p><span class=colorbox style=background-color:#ff8a80><span style=color:#000>Light red (day)</span></span> / <span class=colorbox style=background-color:#4f1c14><span style=color:#fff>dark\nred (night)</span></span> – Frozen app<li><p><span class=colorbox style=background-color:#ff0><span style=color:#000>Yellow Star</span></span> – Debuggable\napplication<li><p><span style=color:#e05915>Orange <em>Date</em></span> – 이\n앱은 시스템 로그 접근 권한이 있습니다<li><p><span style=color:#e05915>Orange <em>UID</em></span> – 사용자\nID가 여러 앱에서 공유되고 있습니다<li><p><span style=color:#e05915>Orange <em>SDK</em></span> – 이\n앱은 클리어 텍스트를 사용할 수도 있습니다 (i.e. HTTP)<li><p><span style=color:red>Red <em>package name</em></span> – 이\n앱은 데이터 삭제를 허용하지 않습니다<li><p><span style=color:red>Red <em>backup</em></span> – 제거된 앱이\nApp Manager에 하나 이상의 백업을 가지고 있습니다<li><p><span style=color:#e05915>Orange <em>backup</em></span> –\n기존 백업이 설치된 앱의 구 버전을 포함하고 있습니다<li><p><span style=color:#09868b>Dark cyan <em>backup</em></span>\n– 즉 기존 백입이 설치된 앱과 동일하거나 상위 버전을 포함하고\n있습니다.<li><p><span style=color:#09868b>Dark cyan <em>package\nname</em></span> – 강제 중지된 앱<li><p><span style=color:#09868b>Dark cyan <em>version</em></span>\n– 비활성화된 앱<li><p><span style=color:#f0f>Magenta</span> – Persistent 앱 i.e.\n항상 실행 중인 앱.</ul></section><section id=subsec:main-page-application-types class=level3 data-number=2.1.3><h3 data-number=2.1.3><span class=header-section-number>2.1.3</span>\n<a href=#toc:subsec:main-page-application-types>앱 종류</a><a href=#subsec:main-page-application-types class=anchor aria-hidden=true></a></h3><p>앱은 다음 접미사를 가지는 <strong>사용자</strong> 혹은\n<strong>시스템</strong> 앱일 수 있습니다:<ul class=incremental><li><p><code>X</code> – 다수의 아키텍쳐 지원<li><p><code>0</code> – 앱에 dex 파일이 존재하지 않습니다<li><p><code>°</code> – 일시정지된 앱<li><p><code>#</code> – 앱이 시스템에 큰 힙 할당을 요청했습니다 (i.e. 큰\n런타임 메모리)<li><p><code>?</code> – 앱이 가상 머신이 안전 모드에 있도록\n요청했습니다.</ul></section><section id=subsec:main-page-version-info class=level3 data-number=2.1.4><h3 data-number=2.1.4><span class=header-section-number>2.1.4</span>\n<a href=#toc:subsec:main-page-version-info>버전 정보</a><a href=#subsec:main-page-version-info class=anchor aria-hidden=true></a></h3><p>버전 이름 뒤에는 아래의 접두사가 붙습니다:<ul class=incremental><li><p><code>_</code> – 하드웨어 가속 없음(앱 내 애니메이션 또는 투명도\n저하)<li><p><code>~</code> – 테스트 전용 앱<li><p><code>debug</code> – 디버깅 가능 앱</ul></section><section id=subsec:main-page-options-menu class=level3 data-number=2.1.5><h3 data-number=2.1.5><span class=header-section-number>2.1.5</span>\n<a href=#toc:subsec:main-page-options-menu>옵션 메뉴</a><a href=#subsec:main-page-options-menu class=anchor aria-hidden=true></a></h3><p>옵션 메뉴는 나열된 앱을 정렬 및 필터링하고 App Manager 내부 또는\n외부의 다른 페이지로 이동하는 데 사용할 수 있는 여러가지 옵션을\n제공합니다.<section id=subsubsec:main-list-options class=level4 data-number=2.1.5.1><h4 data-number=2.1.5.1><span class=header-section-number>2.1.5.1</span> 옵션 나열<a href=#subsubsec:main-list-options class=anchor aria-hidden=true></a></h4><p><strong>List options</strong> 는 메인 페이지의 리스트 정렬 및\n필터링을 하는 옵션이 있습니다.<section id=정렬 class=level5 data-number=2.1.5.1.1><h5 data-number=2.1.5.1.1><span class=header-section-number>2.1.5.1.1</span> 정렬<a href=#정렬 class=anchor aria-hidden=true></a></h5><div id=par:main-page-sort></div><p>메인 페이지에 나열된 앱은 다음과 같은 방법으로 정렬될 수\n있습니다:<ul class=incremental><li><p><strong>사용자 앱 우선.</strong> 사용자 앱을 위에 표시<li><p><strong>앱 이름.</strong> 앱 라벨에 따라 오름차순으로 정렬 (앱\n라벨이란 <em>앱 이름</em>). 이것이 정렬 기본값입니다.<li><p><strong>패키지 이름.</strong> 패키지 이름에 따라 오름차순으로\n정렬<li><p><strong>마지막 업데이트.</strong> 마지막 업데이트 된 날짜를\n기준으로 내림차순 정렬<li><p><strong>공유 사용자 ID.</strong> 공유 사용자의 커널 User ID에\n따라 내림차순 정렬<li><p><strong>목표 SDK.</strong> 목표 SDK에 따라 오름차순 정렬<li><p><strong>서명.</strong> 서명 정보에 따라 오름차순 정렬<li><p><strong>비활성화 우선.</strong> 비활성화 앱을 위에 표시<li><p><strong>차단 우션.</strong> 각 앱의 차단된 구성 요소 개수에 따라\n내림차순 정렬<li><p><strong>백업 완료 우선.</strong> 백업이 된 앱을 위에\n표시<li><p><strong>트래커.</strong> 각 앱의 트래커 요소 개수에 따라 내림차순\n정렬<li><p><strong>마지막 활동.</strong> App Manager 내부 앱에 활동한 가장\n최근 날짜와 시각에 따라 내림차순 정렬</ul><p>추가적으로, 목록을 역순으로 정렬하는 데 사용할 수 있는\n<em>반대로</em> 옵션이 있습니다. 정렬 설정에 상관없이 앱은 임의의 정렬\n결과를 생성하지 않도록 처음에는 알파벳 순으로 정렬됩니다.</section><section id=필터 class=level5 data-number=2.1.5.1.2><h5 data-number=2.1.5.1.2><span class=header-section-number>2.1.5.1.2</span> 필터<a href=#필터 class=anchor aria-hidden=true></a></h5><div id=par:main-page-filter></div><p>메인 페이지에 나열된 앱은 다음과 같이 필터링을 할 수 있습니다:<ul class=incremental><li><p><strong>사용자 앱.</strong> 사용자 앱만 표시<li><p><strong>시스템 앱.</strong> 시스템 앱만 표시<li><p><strong>비활성화 앱.</strong> 비활성화 앱만 표시<li><p><strong>규칙 보유 앱.</strong> 하나 이상의 블로킹 규칙이 있는 앱\n표시<li><p><strong>활성화 앱.</strong> 하나 이상의 활동 기록이 있는 앱\n표시<li><p><strong>백업된 앱.</strong> 하나 이상의 백업이 있는 앱\n표시<li><p><strong>실행 중 앱.</strong> 현재 실행 중인 앱 표시<li><p><strong>분기 앱.</strong> 하나 이상의 분기 APK 파일이 있는 앱\n표시<li><p><strong>설치된 앱.</strong> 설치된 앱만 표시<li><p><strong>제거된 앱.</strong> 제거된 앱만 표시<li><p><strong>백업 없는 앱.</strong> 백업이 존재하지 않는 앱\n표시</ul><p>정렬과 달리 두 개 이상의 필터링 옵션을 동시에 적용할 수 있습니다.\n예를 들어, <em>사용자 앱</em> 및 <em>비활성화 앱</em> 옵션을 둘 다\n선택하여 사용하지 않도록 설정된 사용자 애플리케이션을 나열할 수\n있습니다. 이는 특정 작업을 안전하게 수행하기 위해 사용자 앱을 필터링할\n필요가 있는 <a href=#subsec:batch-operations>배치 작업</a>에 특히\n유용할 수 있다.</section><section id=프로필-이름 class=level5 data-number=2.1.5.1.3><h5 data-number=2.1.5.1.3><span class=header-section-number>2.1.5.1.3</span> 프로필 이름<a href=#프로필-이름 class=anchor aria-hidden=true></a></h5><p><a href=#sec:profiles-page>프로필</a>에만 존재하는 앱을 나열할 수도\n있습니다. 이는 <a href=#sec:profiles-page>프로필 페이지</a>에서 할 수\n없는 특정 작업을 프로필에서 실행하는데 유용할 수 있습니다 (예를 들어,\n해당 프로필의 앱을 전부 제거하기).</section></section><section id=사용-설명서 class=level4 data-number=2.1.5.2><h4 data-number=2.1.5.2><span class=header-section-number>2.1.5.2</span> 사용 설명서<a href=#사용-설명서 class=anchor aria-hidden=true></a></h4><p><strong>Instructions</strong> 를 클릭하면 App Manager 사용 설명서의\n오프라인 버전이 열립니다. 해당 기능 (i.e. <code>feat_docs</code>)이\n설치되어 있지 않거나, 설명서를 로드할 WebView가 시스템에 존재하지 않을\n경우 온라인 버전이 열릴 수 있습니다.</section><section id=subsubsec:main:1-click-ops class=level4 data-number=2.1.5.3><h4 data-number=2.1.5.3><span class=header-section-number>2.1.5.3</span> 원터치 작업<a href=#subsubsec:main:1-click-ops class=anchor aria-hidden=true></a></h4><p><strong>1-Click Ops</strong> stands for the single-click operations.\nIt opens the <a href=#sec:1-click-ops-page>corresponding page</a> in a\nnew activity.</section><section id=앱-사용량 class=level4 data-number=2.1.5.4><h4 data-number=2.1.5.4><span class=header-section-number>2.1.5.4</span> 앱 사용량<a href=#앱-사용량 class=anchor aria-hidden=true></a></h4><p>Application usage statistics, such as <em>screen time</em>, <em>data\nusage</em> (both mobile and Wi-Fi), <em>number of times an app was\nopened</em>, can be accessed by clicking on the <strong>App\nUsage</strong> option in the menu. However, it requires the <em>Usage\nAccess</em> permission. This menu item will not be listed if the usage\naccess feature is disabled in <a href=#subsubsec:enable/disable-features>settings</a>.</section><section id=subsubsec:main:running-apps class=level4 data-number=2.1.5.5><h4 data-number=2.1.5.5><span class=header-section-number>2.1.5.5</span> 실행 중인 앱<a href=#subsubsec:main:running-apps class=anchor aria-hidden=true></a></h4><p>이 메뉴 항목은 실행 중인 앱 또는 프로세스 목록이 표시되는 새 페이지를\n엽니다. 추가적으로 현재 메모리 및 캐시 사용량(있을 경우)도 표시합니다.\nroot 또는 ADB를 App Manager에서 사용할 수 없는 경우 안드로이드 최신\n버전에서만 표시됩니다. 실행 중인 앱 또는 프로세스는 해당 페이지 내에서\n강제종료되거나 종료될 수도 있습니다 .각 프로세스 ID(PID)에 대한 로그는\n<a href=#subsec:log-viewer>log viewer</a>에서도 볼 수 있습니다.\n추가적으로, 아이콘을 클릭하거나 항목을 길게 클릭하여 배치 작업을 수행할\n수도 있습니다. 항목을 그냥 클릭하면 세부정보가 표시되는 대화창이\n열립니다.</section><section id=프로필 class=level4 data-number=2.1.5.6><h4 data-number=2.1.5.6><span class=header-section-number>2.1.5.6</span> 프로필<a href=#프로필 class=anchor aria-hidden=true></a></h4><p>This menu item opens the <a href=#sec:profiles-page>profiles\npage</a>. Profiles are a way to configure regularly used tasks. They can\nalso be invoked via shortcuts.</section><section id=apk-업데이터 class=level4 data-number=2.1.5.7><h4 data-number=2.1.5.7><span class=header-section-number>2.1.5.7</span> APK 업데이터<a href=#apk-업데이터 class=anchor aria-hidden=true></a></h4><p>If the app <a href=https://github.com/rumboalla/apkupdater>APK\nUpdater</a> is installed in the system, it can be opened directly via\nthis menu item. The option remains hidden if the app is not present in\nthe system.</section><section id=termux class=level4 data-number=2.1.5.8><h4 data-number=2.1.5.8><span class=header-section-number>2.1.5.8</span> Termux<a href=#termux class=anchor aria-hidden=true></a></h4><p>If the app <a href=https://github.com/termux/termux-app>Termux</a>\nis installed in the system, the running session (or a new session) can\nbe opened directly via this menu item. The option remains hidden if the\napp is not present in the system.</section><section id=debloater class=level4 data-number=2.1.5.9><h4 data-number=2.1.5.9><span class=header-section-number>2.1.5.9</span> Debloater<a href=#debloater class=anchor aria-hidden=true></a></h4><p>This menu item opens the debloater page that lists all the bloatware\navailable in the device and in App Manager. It also suggests alternative\napplications based on the criteria set by the <a href=https://github.com/MuntashirAkon/android-debloat-list>Android\nDebloat List</a> project.</section><section id=subsubsec:main:labs class=level4 data-number=2.1.5.10><h4 data-number=2.1.5.10><span class=header-section-number>2.1.5.10</span> Labs<a href=#subsubsec:main:labs class=anchor aria-hidden=true></a></h4><p>This menu item opens the labs page that lists all the additional\nfeatures. They include Log Viewer, System Config, Terminal, File Manager\n(as Files), UI Tracker, Interceptor, and Code Editor pages.</section><section id=설정 class=level4 data-number=2.1.5.11><h4 data-number=2.1.5.11><span class=header-section-number>2.1.5.11</span> 설정<a href=#설정 class=anchor aria-hidden=true></a></h4><p>This menu item opens the in-app <a href=#sec:settings-page>Settings\npage</a>.</section></section></section><section id=sec:app-details-page class=level2 data-number=2.2><h2 data-number=2.2><span class=header-section-number>2.2</span> <a href=#toc:sec:app-details-page>앱 세부정보 페이지</a><a href=#sec:app-details-page class=anchor aria-hidden=true></a></h2><p><strong>앱 세부정보</strong> 페이지는11 (십일)개의 탭으로\n구성되있습니다. Manifest의 모든 속성, <a href=#ch:app-ops>앱 작업</a>,\n서명 정보, 라이브러리 등을 포함하여 앱이 가질 수 있는 거의 모든 정보를\n설명합니다.<section id=subsec:app-details-colour-codes class=level3 data-number=2.2.1><h3 data-number=2.2.1><span class=header-section-number>2.2.1</span>\n<a href=#toc:subsec:app-details-colour-codes>색상 코드</a><a href=#subsec:app-details-colour-codes class=anchor aria-hidden=true></a></h3><p>이 페이지에 사용된 색상과, 각 색상의 의미:<ul class=incremental><li><p><span class=colorbox style=background-color:red><span style=color:#000>Red (day)</span></span> / <span class=colorbox style=background-color:#790d0d><span style=color:#fff>dark red\n(night)</span></span> – 위험 플래그가 있는 앱 권한 혹은 앱 관리자 내에서\n차단된 구성 요소를 나타냅니다.<li><p><span class=colorbox style=background-color:#ff8a80><span style=color:#000>Light red (day)</span></span> / <span class=colorbox style=background-color:#4f1c14><span style=color:#fff>very\ndark red (night)</span></span> – App Manager 외부에서는 비활성화 되는\n구성 요소를 나타냅니다.<div class=\"amalert tip\"><p><strong><em>Note.</em></strong><p>구성 요소가 비활성화로 표시된 경우 항상 사용자에 의해 비활성화된 것은\n아닙니다. 시스템에서 비활성화하거나 Manifest에서 비활성화로 표시될 수도\n있습니다. 비활성화된 앱의 구성 요소도 시스템(및 App Manager)에 의해\n비활성화된 것으로 간주됩니다.</div><li><p><span class=colorbox style=background-color:#ff8017><span style=color:#000>Vivid orange (day)</span></span> / <span class=colorbox style=background-color:#ff801780><span style=color:#fff>very dark orange (night)</span></span> – 트래커\n구성 요소를 나타냅니다.<li><p><span class=colorbox style=background-color:#ea80fc><span style=color:#000>Soft magenta (day)</span></span> / <span class=colorbox style=background-color:#431c5d><span style=color:#fff>very dark violet (night)</span></span> – 실행 중인\n서비스를 나타냅니다.</ul></section><section id=subsec:app-info-tab class=level3 data-number=2.2.2><h3 data-number=2.2.2><span class=header-section-number>2.2.2</span>\n<a href=#toc:subsec:app-info-tab>앱 정보 탭</a><a href=#subsec:app-info-tab class=anchor aria-hidden=true></a></h3><p><strong>앱 정보</strong> 탭에는 앱에 대한 일반 정보가 포함되어\n있습니다. 또한 이 탭에서 수행할 수 있는 여러 작업도 나열됩니다.<section id=subsubsec:app-info-general-information class=level4 data-number=2.2.2.1><h4 data-number=2.2.2.1><span class=header-section-number>2.2.2.1</span> 일반 정보<a href=#subsubsec:app-info-general-information class=anchor aria-hidden=true></a></h4><p>The list below is in the same order as listed in the App Info\ntab.<ul class=incremental><li><p><strong>Application Icon.</strong> The application icon. If the\napplication does not have an icon, the system default icon will be\ndisplayed. It is also possible to verify the APK signature via SHA or\nMD5 sums stored in the clipboard by simply clicking on it.<li><p><strong>Application Label.</strong> The application label or the\nname of the application.<li><p><strong>Package Name.</strong> The name of the application\npackage. Clicking on the name stores it in the clipboard.<li><p><strong>Version.</strong> The application version is divided into\ntwo parts. The first part is called <em>version name</em>. The format of\nthis part varies but often consists of multiple integers separated by\ndots. The second part is called <em>version code</em>. It is enclosed by\nthe first brackets. The version code is an integer used to differentiate\nbetween application versions (since a version name can be unreadable to\na machine). In general, a new version of an application has higher\nversion code than the old ones. For example, if <code>123</code> and\n<code>125</code> are two version codes of an application, we can say\nthat the latter is more updated than the former because the version code\nof the latter is higher. An application that serves different APK files\nfor the same version on different platforms (mobile, tabs, desktops,\netc.) or architectures (32/64 bit, ARM or Intel), the version numbers\ncan be misleading as they often add prefixes for each platform.<li><p><strong>Tags.</strong> (Also known as tag clouds) Tags include\nthe most basic, concise and useful information of an application. See\n§<a href=#subsubsec:tags data-reference-type=ref data-reference=subsubsec:tags>2.2.2.2</a> for a complete list of tags\nshown here.<li><p><strong>Horizontal Action Panel.</strong> An action panel\nconsisting of various actions that can be carried out for the\napplication. See §<a href=#subsubsec:horizontal-action-panel data-reference-type=ref data-reference=subsubsec:horizontal-action-panel>2.2.2.3</a> for a\ncomplete list of actions available here. Additional actions are\navailable in the <a href=#subsubsec:app-info-options-menu>options\nmenu</a>.<li><p><strong>Paths & Directories.</strong> Contains various\ninformation regarding application paths including <em>app directory</em>\n(where the APK files reside), <em>data directories</em> (internal,\ndevice protected and externals), and <em>JNI library directory</em> (if\npresent). JNI libraries are used to invoke native codes usually written\nin C/C++. Use of native library can make the application run faster or\nhelp an application use third-party libraries written using languages\nother than Java like in most games. The directories can be opened via\nfile managers provided they support it and have the necessary\npermissions, by clicking on the launch button on the right-hand side of\na directory item.<li><p><strong>Data Usage.</strong> Amount of data used by the\napplication as reported by the operating system. Depending on Android\nversion, this may require a wide range of permissions including\n<em>Usage Access</em> and <em>Telephony</em> permissions.<li><p><strong>Storage & Cache.</strong> Displays information\nregarding the size of the application (APK files, optimised files), data\nand cache. In older devices, size of external data, cache, media and OBB\nfolders are also displayed. This part remains hidden if <em>Usage\nAccess</em> permission is not granted in the newer devices.<li><p><strong>More Info.</strong> Displays other information such\nas–<ul class=incremental><li><p><strong>SDK.</strong> Displays information related to the Android\nSDK: <em>Max</em> denotes the target SDK and <em>Min</em> denotes the\nminimum SDK (the latter is not available in Android Lollipop). If the\ntarget SDK value is less than the platform SDK (i.e., the highest SDK\nthe current operating system supports), the application will run in the\ncompatibility mode. This means the application may have access to\ncertain features that are unavailable or restricted in a newer version\nof Android, which can be a security and/or privacy issue. SDK is also\nknown as <strong>API Level</strong>.<br><div class=seealso-inline><p><em>See also: <span><a href=https://en.wikipedia.org/wiki/Android_version_history#Overview>Android\nVersion History</a></span></em></div><li><p><strong>Flags.</strong> The application flags used at the time of\nbuilding the application. For a complete list of flags and what they do,\nread the <a href=https://developer.android.com/reference/android/content/pm/ApplicationInfo#flags>official\ndocumentation</a>.<li><p><strong>Date Installed.</strong> The date when the application\nwas first installed.<li><p><strong>Date Updated.</strong> The date when the application was\nlast updated. This is the same as <em>Date Installed</em> if the\napplication hasn’t been updated.<li><p><strong>Process Name.</strong> The name of the process if it is\ndifferent from the package name. Process name is set when an application\nis being started by the system, and is usually the same as the package\nname.<li><p><strong>Installer App.</strong> The application that installed\nthis application. The installer application may not always be the same\nas the application that installed this application, because Android\nallows setting an arbitrary value for this field. In Android 11 onwards,\nthe actual installer application is also stored by the system which can\nbe accessed by clicking the “Info” button on the right-hand side of the\nitem. The field will not be visible if the installer application is not\nreported by the system (e.g., due to the installer application being\nuninstalled or hidden). Installer application may be granted additional\nprivileges by the system so that it can control certain behaviour of the\napplication it installs.<li><p><strong>User ID.</strong> The unique user ID set by the system to\nthe application. For shared applications, the same user ID is assigned\nto multiple applications having the same <em>Shared User\nID</em>.<li><p><strong>Shared User ID.</strong> Applicable for applications that\nare shared together. The shared application must have the same <a href=#subsec:signatures-tab>signatures</a>.<li><p><strong>Primary ABI.</strong> Architecture supported by this\nplatform for this application.<li><p><strong>Zygote preload name.</strong> Responsible for preloading\napplication code and data shared across all the isolated services that\nuses app zygote.<li><p><strong>Hidden API enforcement policy.</strong> Since Android 9,\nmany methods and classes in Android framework have been made\ninaccessible to the third-party applications through hidden API\nenforcement policy. It has the following options:<ul class=incremental><li><p><em>Default.</em> Based on the type of application. For system\napplications, it should be disabled, and for others, it should be\nenforced.<li><p><em>None/disabled.</em> The application has full access to the\nhidden API as it used to be before Android 9.<li><p><em>Warn.</em> Same as above, except that warnings will be logged\neach time the application accesses the hidden API. This is mostly\nunused.<li><p><em>Enforce.</em> The application cannot access hidden API,\neither dark-grey list or blacklist, or both of them. This is the default\noption for the third-party applications in Android 9 onwards unless the\napplication is whitelisted by the OEM or the vendor.<div class=\"amalert warning\"><p><strong><em>Warning.</em></strong><p>Hidden API enforcement policy is not properly implemented in Android\nand can be bypassed by the application. As a result, this value should\nnot be trusted.</div></ul><li><p><strong>SELinux.</strong> Mandatory access control (MAC) policy\nset by the operating system via SELinux.<li><p><strong>Main Activity.</strong> The main entry point to the\napplication. This is only visible if the application has <a href=#subsubsec:activities>activities</a> and any of those are\nopenable from the Launcher. There’s also a launch button on the\nright-hand side which can be used to launch this activity.</ul></ul></section><section id=subsubsec:tags class=level4 data-number=2.2.2.2><h4 data-number=2.2.2.2><span class=header-section-number>2.2.2.2</span> Tags<a href=#subsubsec:tags class=anchor aria-hidden=true></a></h4><ul class=incremental><li><p><strong>Tracker info.</strong> Number of tracker components in\nthe application (e.g., <em>5 trackers</em>) The colour of the tag\nappears orange if the trackers are unblocked and dark cyan if they are\nblocked in App Manager. Clicking on the tag opens a dialog containing\nthe list of tracker components which can also be blocked or unblocked\nprovided App Manager has sufficient privileges.<li><p><strong>Application type.</strong> User application or system\napplication. For a system application, it displays whether the\napplication is an updated version of the system application or the\napplication is installed systemless-ly via Magisk.<li><p><strong>Split APK info.</strong> Number of splits in the APK\nexcluding the base APK (e.g., <em>5 splits</em>). Clicking on the tag\nopens a dialog containing a few additional information, such as name,\ntype, and size.<li><p><strong>Debuggable.</strong> The application can be debugged over\nADB. Debuggable applications can enjoy certain functions unavailable to\na regular application. The data of the application might be accessible\nvia ADB (e.g. using <code>run-as</code> command) without any additional\npermissions.<li><p><strong>Test only.</strong> The application is a test-only\napplication. Test-only applications can enjoy certain functions\nunavailable to a regular application. The data of the application might\nbe accessible via ADB (e.g. using <code>run-as</code> command) without\nany additional permissions.<li><p><strong>No code.</strong> The application does not have any code\nassociated with it i.e., DEX files aren’t present. In some system\napplications, the actual code might be located in another\nplace.<li><p><strong>Large heap.</strong> The application has requested large\nheap size i.e., more space in memory (RAM) is requested for dynamic\nallocation. It is still up to the operating system to decide whether to\nallocate large space for the application. App Manager, for example,\nrequests large heap size because it needs to load an entire APK into\nmemory while scanning an APK.<li><p><strong>Open links.</strong> The application may open certain\nlinks from any applications. If the application can open any links by\ndefault, the color of the tag would be red, dark cyan if otherwise.\nClicking on the tag opens a dialog with the supported hosts or domains\nlisted. In Android 12 onwards, it displays an option to enable or\ndisable opening links by default provided App Manager has sufficient\npermissions. Otherwise, it displays an option to open the system\nsettings page for the application.<li><p><strong>Running.</strong> One or more services of the application\nis currently running in the background. Clicking on the tag opens a\ndialog containing the list of running services. Clicking on any services\nopens the log viewer with default filter set to the UID associated with\nthe service (which can be different from the UID of the application if\nit is running in a separate or isolated process) provided the log viewer\nfeature is enabled. There’s also an option to force-stop the\napplication.<li><p><strong>Stopped.</strong> The application is force stopped. This\nmay not prevent it from running automatically later.<li><p><strong>Disabled.</strong> Denotes that the application is\ndisabled (hidden from the launcher).<li><p><strong>Suspended.</strong> Denotes that the application is\nsuspended (grayed out in the launcher).<li><p><strong>Hidden.</strong> Denotes that the application is hidden\n(hidden from the launcher).<li><p><strong>MagiskHide.</strong> MagiskHide is enabled for the\napplication. Clicking on the tag opens a dialog containing the list of\nprocess names within the application that can be added to or removed\nfrom the MagiskHide list.<li><p><strong>MagiskDenyList.</strong> The application is present in\nMagisk DenyList. Clicking on the tag opens a dialog containing the list\nof process names within the application that can be added to or removed\nfrom Magisk DenyList.<li><p><strong>WX.</strong> The application violates the “W^X policy”\nand is capable of writing and executing in the same directory or in the\nsame portion of memory. This allows the execution of arbitrary\nexecutables either by the modification of executables embedded within\nthe application or by downloading them from the Internet.<br><div class=seealso-inline><p><em>See also: <span><a href=https://en.wikipedia.org/wiki/W%5EX>W^X\nin Wikipedia</a></span></em></div><li><p><strong>Bloatware.</strong> The application may be a known\nbloatware. Clicking on the tag opens a dialog containing detailed\ninformation in addition to suggestions (if available).<li><p><strong>KeyStore.</strong> The application has items in the\nAndroid KeyStore. Clicking on the tag opens a dialog containing all the\nKeyStore files that belong to the application.<li><p><strong>Backup.</strong> The application was backed up using App\nManager at least once. Clicking on the tag opens a dialog containing all\nthe available backups along with metadata.<li><p><strong>No battery optimisation.</strong> Battery optimisation is\ndisabled for the application. It is possible to re-enable battery\noptimisation by clicking on the tag.<li><p><strong>Sensors disabled.</strong> Sensors are disabled for the\napplication. Sensors are disabled for most applications by\ndefault.<li><p><a href=#sec:net-policy><strong>Net policy.</strong></a>\nNetwork policy (e.g., background data usage) is configured for the\napplication. Clicking on the tag displays a dialog containing the\nsupported policies for the platform along with the options to configure\nthem.<li><p><a href=#sec:terminologies><strong>SSAID.</strong></a> Clicking\non the tag opens a dialog containing the current SSAID assigned to the\napplication. It is also possible to reset/regenerate the SSAID if\nneeded.<li><p><strong>SAF.</strong> Denotes that the application has been\ngranted to access one or more storage locations or files i.e. URIs via\nStorage Access Framework (SAF). Clicking on the tag opens a dialog\ncontaining the list of granted URIs.<li><p><strong>Play App Signing.</strong> Indicates that the application\nmight be signed by Google.<li><p><strong>Xposed.</strong> Indicates that the application may be an\nXposed module. Clicking on the tag displays a dialog with additional\ninformation.<li><p><strong>Static Shared Library.</strong> Denotes that the\napplication serves as a static shared library for one or more\napplications. Clicking on the tag opens a dialog containing a list of\ninstalled versions of the library along with an option to uninstall\nthem.<div class=\"amalert tip\"><p><strong><em>Notice.</em></strong><p>The trichrome library (supplied by Google Chrome, Vanadium or similar\nprojects) is currently the only known static shared library on\nAndroid.</div></ul></section><section id=subsubsec:horizontal-action-panel class=level4 data-number=2.2.2.3><h4 data-number=2.2.2.3><span class=header-section-number>2.2.2.3</span> Horizontal Action Panel<a href=#subsubsec:horizontal-action-panel class=anchor aria-hidden=true></a></h4><p>Horizontal Action Panel, as described in the previous section,\nconsists of various application-related actions, such as–<ul class=incremental><li><p><strong>Launch.</strong> Launch the application provided it has a\nlauncher <a href=#subsubsec:activities>activity</a>.<li><p><strong>Freeze.</strong> Freeze the application. This button is\nnot displayed if it is already frozen or the user does not have enough\nprivileges. After the application is frozen, it may be hidden from the\napp drawer depending on how it was configured. Shortcuts configured by\nthe application may also be removed. The application may only be\nunfrozen via App Manager, <code>pm</code> command or any other tools\nthat offer such a feature. Long clicking on the button opens a dialog\nwhere a shortcut can be configured to quickly freeze or unfreeze the\napplication.<li><p><strong>Uninstall.</strong> Uninstall the application with a\nprompt. In the dialog prompt, it is possible to uninstall updates of a\nsystem application, or if App Manager has enough privileges or the\noperating system supports it, it is possible to uninstall the\napplication without clearing its data and signature. For the latter\ncase, the installed application must match the signature with the\npreviously installed application if it is installed again.<div class=\"amalert tip\"><p><strong><em>Tips.</em></strong><p>A better way to reinstall an application with a different signature\nwould be to back up its data using App Manager and restore it again\nafter installing the application instead of opting to preserving data\nand signature of the application during uninstallation as this option\nmay cause undefined behaviour in the future.</div><li><p><strong>Unfreeze.</strong> Unfreeze the application. This button\nis not displayed if it is already enabled or the user does not have\nenough privileges. Similar to the <em>Freeze</em> button, long clicking\non the button opens a dialog where a shortcut can be configured to\nquickly freeze or unfreeze the application.<li><p><strong>Force Stop.</strong> Force-stop the application.<li><p><strong>Clear Data.</strong> Clear data from the application.\nThis includes any information stored in the internal and, recently, the\nexternal directories, including accounts (if set by the application),\ncache, etc. Clearing data from App Manager, for example, removes all the\nrules (the blocking is not removed though) saved within the application\n(Which is why you should always take backups of your rules). This button\nis not displayed if the user does not have enough privileges.<li><p><strong>Clear Cache.</strong> Clear the application cache. If the\napplication is running during the operation, the cache may not be\ncleared as expected.<li><p><strong>Install.</strong> Install the application, only displayed\nif the application hasn’t already been installed.<li><p><strong>What’s New.</strong> Displayed for an external\napplication if an older version of it is already installed. Clicking on\nthis button opens a dialog containing the differences between this and\nthe installed version in a version control manner. Changes include\n<em>version</em>, <em>trackers</em>, <em>permissions</em>,\n<em>components</em>, <em>signatures</em> (only checksum changes),\n<em>features</em>, <em>shared libraries</em> and <em>SDK</em>.<li><p><strong>Update.</strong> Displayed if the application has a\nhigher version code than the installed application.<li><p><strong>Reinstall.</strong> Displayed if the application has the\nsame version code as the installed application.<li><p><strong>Downgrade.</strong> Displayed if the application has a\nlower version code than the installed application.<li><p><strong>Manifest.</strong> Opens the application’s manifest file\nin a separate page. If the application has more than one split, it will\ndisplay the list of split APK files, and clicking on an item will open\nthe corresponding manifest file instead.<li><p><strong>Scanner.</strong> Scan the application in order to list\npotential trackers and libraries. It also scans the file using\nVirusTotal and fetch results from Pithus if configured.<br><div class=seealso-inline><p><em>See also: <span><a href=#sec:scanner-page>Scanner\npage</a></span></em></div><li><p><strong>Shared Prefs.</strong> Displays a list of shared\npreferences used by the application. Clicking on a preference item in\nthe list opens the <a href=#sec:shared-preferences-editor-page>Shared\nPreferences Editor page</a>. This option is only visible if the user has\nthe required privileges.<li><p><strong>Databases.</strong> Displays a list of databases used by\nthe application. Clicking on an item opens a list of activities that can\nopen the database. This option is only visible if the user has the\nrequired privileges.<li><p><strong>F-Droid.</strong> Open the application in the selected\n<em>F-Droid</em> client.<li><p><strong>Store.</strong> Open the application in <em>Aurora\nStore</em>. The option is only visible if <em>Aurora Store</em> is\ninstalled.</ul></section><section id=subsubsec:app-info-options-menu class=level4 data-number=2.2.2.4><h4 data-number=2.2.2.4><span class=header-section-number>2.2.2.4</span> 옵션 메뉴<a href=#subsubsec:app-info-options-menu class=anchor aria-hidden=true></a></h4><p>Options-menu is located in the top-right corner of the page. A\ncomplete description of the options present there are given below:<ul class=incremental><li><p><strong>Share.</strong> Share button can be used to share the APK\nor (if the application is has multiple splits, OBB files or any\ndependencies) <em>APKS</em> file extracted from the\napplication.<li><p><strong>Refresh.</strong> Refresh the App Info tab.<li><p><strong>View in Settings.</strong> Open the application in\nAndroid Settings.<li><p><strong>Backup/restore.</strong> Open the backup/restore\ndialog.<li><p><strong>Export blocking rules.</strong> Export rules configured\nfor the application within App Manager.<li><p><strong>Open in Termux.</strong> Open the application in Termux.\nThis actually runs <code>su - user_id</code> where <code>user_id</code>\ndenotes the application’s kernel user ID (described in §<a href=#subsubsec:app-info-general-information data-reference-type=ref data-reference=subsubsec:app-info-general-information>2.2.2.1</a>).\nThis option is only visible to the root users. See §<a href=#subsubsec:config-termux data-reference-type=ref data-reference=subsubsec:config-termux>2.2.2.5</a> to learn how to\nconfigure Termux to run commands from third-party applications.<li><p><strong>Run in Termux.</strong> Open the application via\n<code>run-as package_name</code> in Termux. This is only applicable to\nthe debuggable applications and works for both root and ADB users. See\n§<a href=#subsubsec:config-termux data-reference-type=ref data-reference=subsubsec:config-termux>2.2.2.5</a> to learn how to\nconfigure Termux to run commands from third-party applications.<li><p><strong>MagiskHide.</strong> Open a dialog containing the list of\nprocess names within the application that can be added or removed from\nthe MagiskHide list.<li><p><strong>Magisk DenyList.</strong> Open a dialog containing the\nlist of process namees within the application that can be added or\nremoved from Magisk DenyList.<li><p><strong>Battery optimisation.</strong> Enable/disable battery\noptimisation for this application.<li><p><strong>Sensors.</strong> Enable/disable sensors for this\napplication.<li><p><a href=#sec:net-policy><strong>Net policy.</strong></a>\nConfigure network policy (e.g., background data usage) for the\napplication.<li><p><strong>Extract Icon.</strong> Extract and save the application’s\nicon in the shared storage.<li><p><strong>Optimize.</strong> Perform optimisation for this\napplication. This option is for advanced users only.<li><p><strong>Add to profile.</strong> Add the application to one of\nthe configured <a href=#sec:profile-page>profiles</a>.<li><p><strong>Install for….</strong> Install the application for\nanother user and/or in the work profile if configured.</ul></section><section id=subsubsec:config-termux class=level4 data-number=2.2.2.5><h4 data-number=2.2.2.5><span class=header-section-number>2.2.2.5</span> Configuring Termux<a href=#subsubsec:config-termux class=anchor aria-hidden=true></a></h4><p>By default, Termux does not allow running commands from a third-party\napplication. To use this option, Termux v0.96 or later is required and\n<code>allow-external-apps=true</code> must be added in\n<code>~/.termux/termux.properties</code>.<div class=\"amalert tip\"><p><strong><em>Info.</em></strong><p>Enabling this option does not weaken Termux’ security. The\nthird-party applications still need to ask the user to allow running\narbitrary commands in Termux.</div></section></section><section id=subsec:component-tabs class=level3 data-number=2.2.3><h3 data-number=2.2.3><span class=header-section-number>2.2.3</span>\n<a href=#toc:subsec:component-tabs>구성 요소 탭</a><a href=#subsec:component-tabs class=anchor aria-hidden=true></a></h3><p><strong>Activities</strong>, <strong>Services</strong>,\n<strong>Receivers</strong> (i.e., broadcast receivers) and\n<strong>Providers</strong> (e.g., content providers) are collectively\nknown as the application components, because they offer similar features\nand share similar properties. For example, they all have a\n<em>name</em>, a <em>label</em>, an <em>icon</em>, can be enabled or\ndisabled, and can be executed via <em>Intent</em>. Application\ncomponents are the building blocks of an application and must be\ndeclared in the application manifest (with a few exceptions).\nApplication manifest is a file where application specific metadata are\nstored. The Android operating system learns what to do with the\napplication by reading the metadata.<p>Colours used in these tabs are explained in §<a href=#subsec:app-details-colour-codes data-reference-type=ref data-reference=subsec:app-details-colour-codes>2.2.1</a>. It is also\npossible to sort the list of components to display blocked or tracker\ncomponents on top of the list via the <strong>Sort</strong> option\nlocated in the three-dots menu.<section id=subsubsec:activities class=level4 data-number=2.2.3.1><h4 data-number=2.2.3.1><span class=header-section-number>2.2.3.1</span> Activities<a href=#subsubsec:activities class=anchor aria-hidden=true></a></h4><p><strong>Activities</strong> are the windows or pages that can be\nuniquely identified by the Android operating system (e.g., <em>Main\npage</em> and <em>App Details page</em> are two activities). Each\nactivity can have multiple UI components known as <em>widgets</em> or\n<em>fragments</em>, and each component can be nested or placed on top of\neach other. The developer can also choose to open external files, links,\netc. within an activity using a method called <em>intent filters</em>.\nFor example, when you open a file in your file manager, either your file\nmanager or the operating system scans the intent filters via\nPackageManager, find the activities capable of opening the file, and\nlist those activities so that you can choose your preferred\nactivity.<p>Activities that are <em>exportable</em> can be opened by any\nthird-party applications. However, Some activities may require\npermissions, and only an application having those permissions can open\nthem. In the <em>Activities</em> tab, certain activities can be launched\nvia the <strong>Launch</strong> button. If it is necessary to supply\nadditional information, such as Intent extras, data or action, long\nclicking on the <strong>Launch</strong> button opens the <a href=#sec:interceptor-page>Activity Interceptor</a> page which\nprovides such features.<div class=\"amalert tip\"><p><strong><em>Tip.</em></strong><p>No-root users can grant\n<code>android.permission.WRITE_SECURE_SETTINGS</code> via ADB to launch\n<em>non-exportable</em> activities.</div><div class=\"amalert tip\"><p><strong><em>Notice.</em></strong><p>If launching an activity throws an error, it may have certain\ndependencies which are not met (e.g., <em>App Details</em> page in App\nManager cannot be launched using the launch button, because it requires\na package name). Since the dependencies cannot be inferred\nprogrammatically, the activity may not be opened from App Manager by\ndefault.</div><p>It is also possible to create shortcuts of an activity-launch using\nthe <strong>Create shortcut</strong> button. If you need to supply\nadditional information, you can create a shortcut from the Activity\nInterceptor page instead.<div class=\"amalert danger\"><p><strong><em>Caution.</em></strong><p>If you uninstall App Manager, all shortcuts created by App Manager\nwill be lost.</div></section><section id=subsubsec:details:servcies class=level4 data-number=2.2.3.2><h4 data-number=2.2.3.2><span class=header-section-number>2.2.3.2</span> 서비스<a href=#subsubsec:details:servcies class=anchor aria-hidden=true></a></h4><p>Unlike <a href=#subsubsec:activities>activities</a> that users can\nsee, <strong>Services</strong> handle background tasks. For example, if\nyou’re downloading a video from the internet using your phone’s Internet\nbrowser, the Internet browser is using a <em>foreground service</em> to\ndownload the content.<p>When an activity is closed or removed from the <em>Recents</em> page,\nit may be destroyed immediately depending on the amount free memory the\nphone has, battery statistics, or how the activity is configured. But\nservices can be run indefinitely if desired. If more services run in the\nbackground, the phone may become slower due to the shortage of memory\nand/or processing power, and the phone’s battery will be drained more\nquickly. Newer versions of Android come with a battery optimisation\nfeature enabled by default for all applications. With this feature\nenabled, the system can randomly terminate any service depending on the\namount of resources the system has or the service requires. However,\nforeground services (i.e., services that run with a fixed notification,\nsuch as music player or downloader) are not typically terminated unless\nthe system is very low on resources (memory, battery, etc.). Certain\nstock ROMs can offer more aggressive optimisation. MIUI, for example,\nhas a very aggressive optimisation feature known as the <em>MIUI\noptimisation</em>.<p>Both activities and services are run in the same <a href=https://stackoverflow.com/questions/7597742>looper</a> called the\nmain looper, which means the services do not really run in the\nbackground. It is the task of the developer to ensure this. How do the\napplication communicate with the services? It uses <a href=#subsubsec:app-details-receivers>broadcast receiver</a> or\nBinder.</section><section id=subsubsec:app-details-receivers class=level4 data-number=2.2.3.3><h4 data-number=2.2.3.3><span class=header-section-number>2.2.3.3</span> 수신자<a href=#subsubsec:app-details-receivers class=anchor aria-hidden=true></a></h4><p><strong>Receivers</strong> (also called <em>broadcast receivers</em>)\ncan be used to trigger execution of certain tasks when certain events\noccur. These components are called broadcast receivers, because they are\nexecuted as soon as a broadcast message is received. These broadcast\nmessages are sent using a method called <em>Intent</em>. Intent is a\nspecial feature in Android that can be used to open applications (i.e.,\nactivities), run services and send broadcast messages. Therefore, like\n<a href=#subsubsec:activities>activities</a>, broadcast receivers use\n<em>intent filters</em> to receive the desired broadcast messages.\nBroadcast messages can be sent by the system or the application itself.\nWhen a broadcast message is sent, the corresponding receivers are\nactivated by the system so that they can execute tasks. For example, if\nyour phone is low on resources, it may freeze or experience lags for a\nmoment after you enable mobile data or connect it to the Wi-Fi. This is\nbecause broadcast receivers that can receive\n<code>android.net.conn.CONNECTIVITY_CHANGE</code> are activated by the\nsystem as soon as the data connection is enabled. Since many\napplications typically use this intent filter, they are all activated\nalmost immediately by the system which causes the freezing or lags.<p>Receivers can also be used for inter-process communication (IPC),\ni.e., it can be used to communicate across multiple applications or even\ndifferent components of a single application.</section><section id=subsubsec:providers class=level4 data-number=2.2.3.4><h4 data-number=2.2.3.4><span class=header-section-number>2.2.3.4</span> 공급자<a href=#subsubsec:providers class=anchor aria-hidden=true></a></h4><p><strong>Providers</strong> are primarily used for data management.\nFor example, when you save an APK file or export rules in App Manager,\nit uses a content provider called <code>.fm.FmProvider</code> to save\nthe APK or export the rules. There are many providers, including the\nones provided by the system, that can be used to manage various\ncontent-related tasks, such as database management, tracking, searching,\netc. Each provider has a field called <em>Authority</em> which is unique\nto the application in the entire Android ecosystem just as the package\nname.</section><section id=루팅된-폰을-위한-추가-기능 class=level4 data-number=2.2.3.5><h4 data-number=2.2.3.5><span class=header-section-number>2.2.3.5</span> 루팅된 폰을 위한 추가\n기능<a href=#루팅된-폰을-위한-추가-기능 class=anchor aria-hidden=true></a></h4><p>Unlike the no-root users who are mostly spectators in these tabs,\nroot users can perform various operations.<section id=블로킹-구성-요소 class=level5 data-number=2.2.3.5.1><h5 data-number=2.2.3.5.1><span class=header-section-number>2.2.3.5.1</span> 블로킹 구성 요소<a href=#블로킹-구성-요소 class=anchor aria-hidden=true></a></h5><p>On the right-most side of each component item, there is a switch\nwhich can be used to toggle the blocking status of that particular\ncomponent. If <a href=#subsubsec:instant-component-blocking>Instant\nComponent Blocking</a> is not enabled or blocking is never applied to\nthe application before, it is required to apply the changes using the\n<strong>Apply rules</strong> option in three-dots menu. It is also\npossible to remove the already-applied rules using the same option\n(which would be read as <strong>Remove rules</strong> this time).<p>It is also possible to block the component using one of the several\nmethods by long clicking on the button.<div class=seealso-inline><p><em>See also: <span><a href=#sec:faq:app-components>FAQ: App\nComponents</a></span></em></div></section><section id=par:appdetails:blocking-trackers class=level5 data-number=2.2.3.5.2><h5 data-number=2.2.3.5.2><span class=header-section-number>2.2.3.5.2</span> Blocking Trackers.<a href=#par:appdetails:blocking-trackers class=anchor aria-hidden=true></a></h5><p>It is possible to disable tracker components using the <strong>Block\ntracker</strong> option in the three-dots menu. All tracker components\nwill be blocked regardless of the tab you’re currently in.<div class=\"amalert tip\"><p><strong><em>Info.</em></strong><p>Tracker components are a subset of application components. Therefore,\nthey are blocked using the same method used for blocking any other\ncomponents.</div><div class=seealso><p><em>See also:</em><ul class=incremental><li><p><a href=#subsec:tracker-classes-versus-tracker-components>FAQ:\nTracker classes versus tracker components</a><li><p><a href=#sec:scanner-page>Scanner Page</a><li><p><a href=#subsec:block-unblock-trackers>1-Click Ops Page:\nBlock/Unblock Trackers</a></ul></div></section></section></section><section id=subsec:permission-tabs class=level3 data-number=2.2.4><h3 data-number=2.2.4><span class=header-section-number>2.2.4</span>\n<a href=#toc:subsec:permission-tabs>권한 탭</a><a href=#subsec:permission-tabs class=anchor aria-hidden=true></a></h3><p><strong>App Ops</strong>, <strong>Uses Permissions</strong> and\n<strong>Permissions</strong> tabs are related to permissions. In Android\ncommunication across applications or processes not having the same\nidentity (known as <em>shared ID</em>) often require permissions. These\npermissions are managed by the permission controller. Some permissions\nare considered <em>normal</em> permissions which are granted\nautomatically if they appear in the application manifest, but\n<em>dangerous</em> and <em>development</em> permissions require\nconfirmation from the user. Colours used in these tabs are explained in\n§<a href=#subsec:app-details-colour-codes data-reference-type=ref data-reference=subsec:app-details-colour-codes>2.2.1</a>.<section id=subsubsec:app-ops class=level4 data-number=2.2.4.1><h4 data-number=2.2.4.1><span class=header-section-number>2.2.4.1</span> App Ops<a href=#subsubsec:app-ops class=anchor aria-hidden=true></a></h4><p><strong>App Ops</strong> stands for <strong>Application\nOperations</strong>. Since Android 4.3, <em>App Ops</em> are used by\nAndroid to control many system permissions. Each app op has a unique\nnumber associated with it which is displayed along with the private name\nof the operation in the App Ops tab. Some app ops also have a public\nname. A large number of app ops are also associated with\n<em>permissions</em>. In this tab, an app op is considered dangerous if\nits associated permission is marked as dangerous. Other information such\nas <em>flags</em>, <em>permission name</em>, <em>permission\ndescription</em>, <em>package name</em>, <em>group</em> are also taken\nfrom the associated <a href=#subsubsec:permissions>permission</a>.\nOthers may include the following:<ul class=incremental><li><p><strong>Mode.</strong> It describes the current authorisation\nstatus which can be <em>allow</em>, <em>deny</em> (a rather misnomer, it\nsimply means error), <em>ignore</em> (it actually means deny),\n<em>default</em> (inferred from a list of defaults set internally by the\nvendor or the AOSP), <em>foreground</em> (in newer Android versions, it\nmeans the app op can only be used when the application is running in\nforeground), and some custom modes set by the vendors (MIUI uses\n<em>ask</em>, for example).<li><p><strong>Duration.</strong> The amount of time this app op has\nbeen used (there can be negative durations whose use cases are currently\nunknown to me).<li><p><strong>Accept Time.</strong> Last time the app op was\naccepted.<li><p><strong>Reject Time.</strong> Last time the app op was\nrejected.</ul><div class=\"amalert tip\"><p><strong><em>Info.</em></strong><p>Contents of this tab are visible to no-root users if\n<code>android.permission.GET_APP_OPS_STATS</code> is granted via\nADB.</div><p>There is a toggle button next to each app op item which can be used\nto allow or deny (ignore) it. Other supported modes can also be set by\nlong clicking on the toggle button. If the desired app op is not listed\nin the tab, <em>Set custom app op</em> option in the menu can be used\ninstead. It is also possible to reset the changes using the <em>Reset to\ndefault</em> option, or deny all the dangerous app ops using the\ncorresponding option in the menu. Due to the nature how app ops work,\nthe system may take some time to apply them.<div class=\"amalert tip\"><p><strong><em>Tip.</em></strong><p>Denying certain app ops may cause the application to misbehave. If\nall attempts fail, <em>reset to default</em> option can be used as the\nlast resort.</div><p>It is possible to sort the list in ascending order by app op names\nand the associated unique numbers (or values), or list the denied app\nops first using the corresponding sorting options.<div class=seealso-inline><p><em>See also: <span><a href=#ch:app-ops>Appendix: App\nOps</a></span></em></div></section><section id=권한-사용함 class=level4 data-number=2.2.4.2><h4 data-number=2.2.4.2><span class=header-section-number>2.2.4.2</span> 권한 사용함<a href=#권한-사용함 class=anchor aria-hidden=true></a></h4><p><strong>Uses Permissions</strong> are the permissions used by the\napplication. This is named so because they are specified in the manifest\nusing <code>uses-permission</code> tags. Information such as\n<em>flags</em>, <em>permission name</em>, <em>permission\ndescription</em>, <em>package name</em>, <em>group</em> are taken from\nthe associated <a href=#subsubsec:permissions>permission</a>.<p>Privileged users can grant or revoke the <em>dangerous</em> and\n<em>development</em> permissions via the toggle button on the right side\nof each permission item. It is also possible revoke dangerous\npermissions all at once using the corresponding option in the menu. Only\nthese two types of permissions can be revoked because Android does not\nallow the modification of <em>normal</em> permissions (which most of\nthem are). It might still be possible to revoke them by editing\n<code>runtime-permissions.xml</code> itself, but whether this is a\npossibility is still being investigated.<div class=\"amalert tip\"><p><strong><em>Info.</em></strong><p>Since dangerous permissions are revoked by default by the system,\nrevoking all dangerous permissions is the same as resetting all the\npermissions.</div><p>It is possible to sort the permissions by their name (in ascending\norder) or choose to display denied or dangerous permissions at first\nusing the corresponding options in the menu.</section><section id=subsubsec:permissions class=level4 data-number=2.2.4.3><h4 data-number=2.2.4.3><span class=header-section-number>2.2.4.3</span> 권한<a href=#subsubsec:permissions class=anchor aria-hidden=true></a></h4><p><strong>권한</strong>은 보통 앱 내에서 정의된 커스텀 권한입니다.\n이러한 종류의 권한은 <em>내부</em> 권한으로 표시됩니다. 다른 앱에서도\n선언되고 <em>외부</em> 권한으로 표시된 권한도 포함됩니다. 외부 권한은 앱\n구성 요소에서 종속적인 권한으로 지정됩니다. 즉, 앱은 지정된 권한을 직접\n보유하는 경우에만 구성 요소를 호출할 수 있습니다. 다음은 표시되는 각\n항목에 대한 전체 설명입니다.<ul class=incremental><li><p><strong>이름.</strong> 각 권한은\n<code>android.permission.INTERNET</code>와 같은 고유한 이름이 있지만\n여러 앱이 동일한 권한을 요청할 수 있습니다.<li><p><strong>아이콘.</strong> 각 권한은 커스텀 아이콘을 가질 수\n있습니다. 다른 권한 탭들은 앱 manifest에 아이콘이 없기 때문에, 아이콘이\n없습니다.<li><p><strong>설명.</strong> 이 선택 필드는 권한을 설명합니다. 권한과\n관련된 설명이 없으면 이 필드가 표시되지 않습니다.<li><p><strong>플래그.</strong> (Uses the flag symbol or\n<strong>Protection Level</strong> name) <em>normal</em>,\n<em>development</em>, <em>dangerous</em>, <em>instant</em>,\n<em>granted</em>, <em>revoked</em>, <em>signature</em>,\n<em>privileged</em>, 등과 같은 다양한 권한 플래그를 설명합니다.<li><p><strong>패키지 이름.</strong> 권한과 연결된 패키지 이름을\n나타냅니다 (권한을 정의한 패키지 이름)<li><p><strong>그룹.</strong> 권한과 관련된 그룹 이름(있을 경우). 서로\n연관된 여러 권한이 그룹으로 묶일 수 있습니다.</ul></section></section><section id=subsec:signatures-tab class=level3 data-number=2.2.5><h3 data-number=2.2.5><span class=header-section-number>2.2.5</span>\n<a href=#toc:subsec:signatures-tab>서명 탭</a><a href=#subsec:signatures-tab class=anchor aria-hidden=true></a></h3><p><strong>Signatures</strong> are actually called signing information.\nAn application is signed with one or more signing keys by its developer\nbefore publishing it. The integrity of an application, i.e., whether the\napplication is from the actual developer and has not been modified by\nanother person, can be checked using the signing certificate included in\nthe APK files. This is because when an application is modified by an\nunauthorised entity, the application can longer be signed with the\noriginal signing keys since the signing keys are unknown to the entity.\nOne way to verify the integrity of an application is via the checksums\ngenerated from the certificates. If the developer supplies the checksums\nfor the signing certificates, they can be compared against the checksums\ngenerated in the <strong>Signatures</strong> tab to verify the\napplication. For example, if you have downloaded App Manager from GitHub\nor Telegram Channel, you can verify whether the application was actually\nreleased by me by simply matching the following <em>SHA256</em> checksum\nwith the one displayed in this tab:<pre><code>320c0c0fe8cef873f2b554cb88c837f1512589dcced50c5b25c43c04596760ab</code></pre><p>Several hashing algorithms are used to generate checksums in this\ntab. They include <em>MD5</em>, <em>SHA1</em>, <em>SHA256</em> and\n<em>SHA512</em>.<div class=\"amalert danger\"><p><strong><em>Caution.</em></strong><p>Signing information should be verified using a reliable hashing\nalgorithm, such as <em>SHA256</em>. DO NOT rely on <em>MD5</em> or\n<em>SHA1</em> checksums as they are known to generate the same checksums\nfor multiple certificates.</div></section><section id=subsec:uses-features-tab class=level3 data-number=2.2.6><h3 data-number=2.2.6><span class=header-section-number>2.2.6</span>\n<a href=#toc:subsec:uses-features-tab>Uses Features tab</a><a href=#subsec:uses-features-tab class=anchor aria-hidden=true></a></h3><p><strong>Uses Features</strong> tab lists the features declared by the\napplication, such as OpenGL ES, telephony, and leanback. Some features\ncan be required by the application, and some features can be optional.\nRequired features must be present in the system along with the required\nversion. Otherwise, any attempt to install the application will be\ndenied by the system. Colours used in this tab are explained in §<a href=#subsec:app-details-colour-codes data-reference-type=ref data-reference=subsec:app-details-colour-codes>2.2.1</a>.</section><section id=subsec:configurations-tab class=level3 data-number=2.2.7><h3 data-number=2.2.7><span class=header-section-number>2.2.7</span>\n<a href=#toc:subsec:configurations-tab>Configurations tab</a><a href=#subsec:configurations-tab class=anchor aria-hidden=true></a></h3><p><strong>Configurations</strong> tab lists the configurations required\nby the application, such as input method type (qwerty, 12 key), touch\nscreen type (finger, stylus, etc.), and navigation type (dial pad,\ntrackball, wheel). This tab is going to be empty for most\napplications.</section><section id=subsec:shared-libs-tab class=level3 data-number=2.2.8><h3 data-number=2.2.8><span class=header-section-number>2.2.8</span>\n<a href=#toc:subsec:shared-libs-tab>공유 라이브러리 탭</a><a href=#subsec:shared-libs-tab class=anchor aria-hidden=true></a></h3><p><strong>Shared libraries</strong> tab lists the legacy JAR\ndependencies, any static shared library dependencies (currently, the\nonly known cases are the Chromium-based browsers and WebViews) as well\nas the JNI (Java native interface) libraries. For JNI libraries, it\nspecifies platform (x86/x86_64/ARM/AArch64), architecture (32/64 bit),\nobject type (shared object or executable), etc.</section></section><section id=sec:1-click-ops-page class=level2 data-number=2.3><h2 data-number=2.3><span class=header-section-number>2.3</span> <a href=#toc:sec:1-click-ops-page>1-Click Ops Page</a><a href=#sec:1-click-ops-page class=anchor aria-hidden=true></a></h2><p>This page is displayed on selecting the <a href=#subsubsec:main:1-click-ops>1-Click Ops option</a> in the <a href=#subsec:main-page-options-menu>main menu</a>.<section id=subsec:block-unblock-trackers class=level3 data-number=2.3.1><h3 data-number=2.3.1><span class=header-section-number>2.3.1</span>\n<a href=#toc:subsec:block-unblock-trackers>Block/Unblock\nTrackers</a><a href=#subsec:block-unblock-trackers class=anchor aria-hidden=true></a></h3><p>This option can be used to block or unblock the ad/tracker components\nfrom the installed applications. On selecting this option, App Manager\nwill ask if it should list trackers from all the applications or only\nfrom the user applications. Novice users should avoid blocking trackers\nfrom the system applications in order to avoid bad consequences. After\nthat, a multi-choice dialog box will appear where it is possible to\nexclude one or more applications from this operation. The changes are\napplied immediately on pressing the <em>block</em> or <em>unblock</em>\nbutton.<div class=\"amalert warning\"><p><strong><em>Notice.</em></strong><p>Certain applications may not function as expected after blocking\ntheir trackers. If that is the case, remove the blocking rules all at\nonce or one by one in the component tabs of the <a href=#sec:app-details-page>App Details page</a> for the corresponding\napplication.</div><div class=seealso-inline><p><em>See also: <span><a href=#par:appdetails:blocking-trackers>App\nDetails Page: Blocking Trackers</a></span></em></div></section><section id=subsec:block-components-dots class=level3 data-number=2.3.2><h3 data-number=2.3.2><span class=header-section-number>2.3.2</span>\n<a href=#toc:subsec:block-components-dots>Block Components…</a><a href=#subsec:block-components-dots class=anchor aria-hidden=true></a></h3><p>This option can be used to block certain application components as\nspecified by their signatures. A signature of a component is the full\nname or partial name of the component. For safety, it is recommended to\nadd a <code>.</code> (dot) at the end of each partial signature, because\nthe underlying algorithm searches and matches the components in a greedy\nmanner. It is also possible to insert more than one signature in which\ncase all the signatures have to be separated by white spaces. Similar to\nthe option above, there is also an option to apply blocking to the\nsystem applications.<div class=\"amalert danger\"><p><strong><em>Caution.</em></strong><p>If you are not aware of the consequences of blocking applcations\ncomponents by their signatures, you should avoid using this option as it\nmay result in bootloop or soft brick, and you may have to apply factory\nreset as a result.</div></section><section id=subsec:set-mode-for-app-ops-dots class=level3 data-number=2.3.3><h3 data-number=2.3.3><span class=header-section-number>2.3.3</span>\n<a href=#toc:subsec:set-mode-for-app-ops-dots>Set Mode for App\nOps…</a><a href=#subsec:set-mode-for-app-ops-dots class=anchor aria-hidden=true></a></h3><p>This option can be used to configure certain <a href=#ch:app-ops>applcation operations</a> of all or selected\napplications. There are two fields. The first field can be used to\ninsert more than one app op constants (either names or values) separated\nby white spaces. It is not always possible to know in advance about all\nthe app op constants as they vary from device to device and from OS to\nOS. Desired app op constant can be found in the <em>App Ops</em> tab\nlocated in the <a href=#sec:app-details-page>App Details page</a>. The\nsecond field can be used to insert or select one of the <a href=#subsec:mode-constants>modes</a> that will be set against the\nspecified app ops.<div class=\"amalert danger\"><p><strong><em>Caution.</em></strong><p>Unless you are well-informed about app ops and the consequences of\nblocking them, you should avoid using this option.</div></section><section id=subsec:1-click-back-up class=level3 data-number=2.3.4><h3 data-number=2.3.4><span class=header-section-number>2.3.4</span>\n<a href=#toc:subsec:1-click-back-up>Back up</a><a href=#subsec:1-click-back-up class=anchor aria-hidden=true></a></h3><p>1-Click options for back up. As a precaution, it lists the affected\nbackups before performing any operation.<section id=back-up-all-apps. class=level5 data-number=2.3.4.0.1><h5 data-number=2.3.4.0.1><span class=header-section-number>2.3.4.0.1</span> Back up all apps.<a href=#back-up-all-apps. class=anchor aria-hidden=true></a></h5><p>Back up all the installed applications.</section><section id=redo-existing-backups. class=level5 data-number=2.3.4.0.2><h5 data-number=2.3.4.0.2><span class=header-section-number>2.3.4.0.2</span> Redo existing backups.<a href=#redo-existing-backups. class=anchor aria-hidden=true></a></h5><p>Back up all the installed applications that have a previous\nbackup.</section><section id=back-up-apps-without-backups. class=level5 data-number=2.3.4.0.3><h5 data-number=2.3.4.0.3><span class=header-section-number>2.3.4.0.3</span> Back up apps without\nbackups.<a href=#back-up-apps-without-backups. class=anchor aria-hidden=true></a></h5><p>Back up all the installed applications without a previous backup.</section><section id=verify-and-redo-backups. class=level5 data-number=2.3.4.0.4><h5 data-number=2.3.4.0.4><span class=header-section-number>2.3.4.0.4</span> Verify and redo\nbackups.<a href=#verify-and-redo-backups. class=anchor aria-hidden=true></a></h5><p>Verify the recently made backups of the installed applications and\nredo backup if necessary.</section><section id=back-up-apps-with-changes. class=level5 data-number=2.3.4.0.5><h5 data-number=2.3.4.0.5><span class=header-section-number>2.3.4.0.5</span> Back up apps with\nchanges.<a href=#back-up-apps-with-changes. class=anchor aria-hidden=true></a></h5><p>If an app has changed since the last backup, redo its backup. It\nchecks a number of indices including application version, last update\ndate, last launch date, integrity and file hashes. Directory hashes are\ntaken during the backup process and are stored in a database. On running\nthis operation, new hashes are taken and compared with the ones kept in\nthe database.</section></section><section id=subsec:1-click-restore class=level3 data-number=2.3.5><h3 data-number=2.3.5><span class=header-section-number>2.3.5</span>\n<a href=#toc:subsec:1-click-restore>Restore</a><a href=#subsec:1-click-restore class=anchor aria-hidden=true></a></h3><p>1-Click options for restore. As a precaution, it lists the affected\nbackups before performing any operation.<section id=restore-all-apps. class=level5 data-number=2.3.5.0.1><h5 data-number=2.3.5.0.1><span class=header-section-number>2.3.5.0.1</span> Restore all apps.<a href=#restore-all-apps. class=anchor aria-hidden=true></a></h5><p>Restore <em>base backup</em> of all the backed up applications.</section><section id=restore-not-installed-apps. class=level5 data-number=2.3.5.0.2><h5 data-number=2.3.5.0.2><span class=header-section-number>2.3.5.0.2</span> Restore not installed\napps.<a href=#restore-not-installed-apps. class=anchor aria-hidden=true></a></h5><p>Restore <em>base backup</em> of all the backed up applications that\nare not currently installed.</section><section id=restore-latest-backups. class=level5 data-number=2.3.5.0.3><h5 data-number=2.3.5.0.3><span class=header-section-number>2.3.5.0.3</span> Restore latest backups.<a href=#restore-latest-backups. class=anchor aria-hidden=true></a></h5><p>Restore <em>base backup</em> of already installed applications whose\nversion codes are higher than the installed version code.</section></section><section id=subsec:trim-caches-in-all-apps class=level3 data-number=2.3.6><h3 data-number=2.3.6><span class=header-section-number>2.3.6</span>\n<a href=#toc:subsec:trim-caches-in-all-apps>Trim Caches in All\nApps</a><a href=#subsec:trim-caches-in-all-apps class=anchor aria-hidden=true></a></h3><p>Delete caches from all applications, including Android system. During\nthis operation, caches of all the running applications may not be\ncleared as expected.</section></section><section id=sec:profiles-page class=level2 data-number=2.4><h2 data-number=2.4><span class=header-section-number>2.4</span> <a href=#toc:sec:profiles-page>Profiles Page</a><a href=#sec:profiles-page class=anchor aria-hidden=true></a></h2><p>Profiles page can be accessed from the <a href=#subsec:main-page-options-menu>options-menu</a> in the main page.\nIt primarily displays a list of configured profiles along with the\ntypical options to perform operations on them. New profiles can also be\nadded using the <em>plus</em> button at the bottom-right corner.\nProfiles can be imported, duplicated or deleted. Clicking on a profile\nitem opens its <a href=#sec:profile-page>profile page</a>.<section id=subsec:profiles-options-menu class=level3 data-number=2.4.1><h3 data-number=2.4.1><span class=header-section-number>2.4.1</span>\n<a href=#toc:subsec:profiles-options-menu>Options Menu</a><a href=#subsec:profiles-options-menu class=anchor aria-hidden=true></a></h3><p>The three-dots menu in the top-right corner opens the global option\nmenu. It has an option to import an existing profile that was previously\nexported from App Manager.<p>Long clicking on any profile item brings up another options-menu. It\noffers the following options:<ul class=incremental><li><p><strong>Apply now….</strong> This option can be used to apply the\nprofile directly. When clicked, a dialog is displayed where it is\npossible to select a <a href=#subsubsec:profile-state>profile\nstate</a>. On selecting one of the states, the profile will be applied\nimmediately.<li><p><strong>Delete.</strong> Clicking on this option will remove the\nprofile immediately without a warning.<li><p><strong>Duplicate.</strong> This option can be used to duplicate\nthe profile. When clicked, a dialog is displayed where it is possible to\nset a name for the new profile. On clicking “OK”, the <a href=#sec:profile-page>profile page</a> will be loaded by duplicating\nall the configurations that this profile have. However, the profile will\nnot be saved until it is saved manually.<li><p><strong>Copy profile ID.</strong> This option is used to copy the\nunique profile ID of the profile. The profile ID can be used to <a href=#subsec:triggering-a-profile>trigger the profile</a> from a\nthird-party application.<li><p><strong>Export.</strong> Export the profile to an external\nstorage. Profiles exported this way can be imported via the\n<em>import</em> option as mentioned above.<li><p><strong>Create shortcut.</strong> This option can be used to\ncreate a shortcut for the profile. There are two options:\n<em>Simple</em> and <em>Advanced</em>. When configured with the latter\noption, it prompts the user to select a profile state when the shortcut\nis invoked. The former option, on the other hand, always uses the\ndefault state that was configured when the profile was last\nsaved.</ul></section></section><section id=sec:profile-page class=level2 data-number=2.5><h2 data-number=2.5><span class=header-section-number>2.5</span> <a href=#toc:sec:profile-page>Profile Page</a><a href=#sec:profile-page class=anchor aria-hidden=true></a></h2><p>Profile page displays the configurations for a profile. It also\noffers the options to edit them.<section id=subsec:profile-options-menu class=level3 data-number=2.5.1><h3 data-number=2.5.1><span class=header-section-number>2.5.1</span>\n<a href=#toc:subsec:profile-options-menu>Options Menu</a><a href=#subsec:profile-options-menu class=anchor aria-hidden=true></a></h3><p>The three dots menu in the top-right corner opens the options-menu.\nIt contains several options such as–<ul class=incremental><li><p><strong>Apply.</strong> This option can be used to apply the\nprofile directly. When clicked, a dialog is displayed where it is\npossible to select a <a href=#subsubsec:profile-state>profile\nstate</a>. On selecting one of the states, the profile will be applied\nimmediately.<div class=\"amalert tip\"><p><strong><em>Notice.</em></strong><p>When you apply a profile, if some packages do not match the criteria,\nthey will simply be ignored.</div><li><p><strong>Save.</strong> Save changes to the profile.<li><p><strong>Discard.</strong> Discard any modifications made since\nthe last time it was saved.<li><p><strong>Delete.</strong> Clicking on this option will remove the\nprofile immediately without a warning.<li><p><strong>Duplicate.</strong> This option can be used to duplicate\nthe profile. When clicked, a dialog is displayed where it is possible to\nset a name for the new profile. On clicking “OK”, this page will be\nreloaded by duplicating all the configurations that this profile have.\nHowever, the new profile will not be saved until it is saved\nmanually.<li><p><strong>Create shortcut.</strong> This option can be used to\ncreate a shortcut for the profile. There are two options:\n<em>Simple</em> and <em>Advanced</em>. When configured with the latter\noption, it prompts the user to select a profile state when the shortcut\nis invoked. The former option, on the other hand, always uses the\ndefault state that was configured when the profile was last\nsaved.</ul></section><section id=subsec:profile-apps-tab class=level3 data-number=2.5.2><h3 data-number=2.5.2><span class=header-section-number>2.5.2</span>\n<a href=#toc:subsec:profile-apps-tab>Apps Tab</a><a href=#subsec:profile-apps-tab class=anchor aria-hidden=true></a></h3><p>Apps tab lists the packages configured for this profile. Packages can\nbe added or removed using the <em>plus</em> button located near the\nbottom of the screen. A package can also be removed by long clicking on\nit (in which case, a popup will be displayed with the only option,\n<em>delete</em>).</section><section id=subsec:profile-configurations-tab class=level3 data-number=2.5.3><h3 data-number=2.5.3><span class=header-section-number>2.5.3</span>\n<a href=#toc:subsec:profile-configurations-tab>Configurations\nTab</a><a href=#subsec:profile-configurations-tab class=anchor aria-hidden=true></a></h3><p>Configurations tab can be used to configure the selected\npackages.<section id=profile-id class=level4 data-number=2.5.3.1><h4 data-number=2.5.3.1><span class=header-section-number>2.5.3.1</span> Profile ID<a href=#profile-id class=anchor aria-hidden=true></a></h4><p>The unique ID for this profile, currently set based on the profile\nname. The profile ID can be used to <a href=#subsec:triggering-a-profile>trigger the profile</a> from a\nthird-party application.</section><section id=comment class=level4 data-number=2.5.3.2><h4 data-number=2.5.3.2><span class=header-section-number>2.5.3.2</span> Comment<a href=#comment class=anchor aria-hidden=true></a></h4><p>This is the text that will be displayed in the <a href=#sec:profiles-page>profiles page</a>. If not set, the current\nconfigurations will be displayed instead.</section><section id=subsubsec:profile-state class=level4 data-number=2.5.3.3><h4 data-number=2.5.3.3><span class=header-section-number>2.5.3.3</span> State<a href=#subsubsec:profile-state class=anchor aria-hidden=true></a></h4><p>Denotes how certain configured options will behave by default. For\ninstance, if <em>disable</em> option is turned on, the applications will\nbe disabled if the state is <em>on</em> and will be enabled if the state\nis <em>off</em>. Currently, it only supports <em>on</em> and\n<em>off</em> values.</section><section id=users class=level4 data-number=2.5.3.4><h4 data-number=2.5.3.4><span class=header-section-number>2.5.3.4</span> Users<a href=#users class=anchor aria-hidden=true></a></h4><p>Select users for which is the profile will be applied. All users are\nselected by default.</section><section id=components class=level4 data-number=2.5.3.5><h4 data-number=2.5.3.5><span class=header-section-number>2.5.3.5</span> Components<a href=#components class=anchor aria-hidden=true></a></h4><p>This behaves the same way as the <a href=#subsec:block-components-dots>Block Components…</a> option does\nin the 1-Click Ops page. However, the blocking here is only applied to\nthe selected packages. If the <a href=#subsubsec:profile-state>state</a> is <em>on</em>, the components\nwill be blocked, and if the state is <em>off</em>, the components will\nbe unblocked. The option can be disabled (regardless of the inserted\nvalues) by clicking on the <em>disabled</em> button on the input\ndialog.<div class=seealso-inline><p><em>See also: <span><a href=#subsec:faq:what-are-app-components>What are the app\ncomponents?</a></span></em></div></section><section id=app-ops class=level4 data-number=2.5.3.6><h4 data-number=2.5.3.6><span class=header-section-number>2.5.3.6</span> App Ops<a href=#app-ops class=anchor aria-hidden=true></a></h4><p>This behaves the same way as the <a href=#subsec:set-mode-for-app-ops-dots>Set Mode for App Ops…</a>\noption does in the 1-Click Ops page. However, the operation here is only\napplied to the selected packages. If the <a href=#subsubsec:profile-state>state</a> is <em>on</em>, the app ops\nwill be denied (i.e. ignored), and if the state is <em>off</em>, the app\nops will be allowed. The option can be disabled (regardless of the\ninserted values) by clicking on the <em>disable</em> button in the input\ndialog.</section><section id=permissions class=level4 data-number=2.5.3.7><h4 data-number=2.5.3.7><span class=header-section-number>2.5.3.7</span> Permissions<a href=#permissions class=anchor aria-hidden=true></a></h4><p>This option can be used to grant or revoke certain permissions from\nthe selected packages. Like others above, permissions must be separated\nby white spaces. If the <a href=#subsubsec:profile-state>state</a> is\n<em>on</em>, the permissions will be revoked, and if the state is\n<em>off</em>, the permissions will be allowed. The option can be\ndisabled (regardless of the inserted values) by clicking on the\n<em>disable</em> button in the input dialog.</section><section id=backuprestore class=level4 data-number=2.5.3.8><h4 data-number=2.5.3.8><span class=header-section-number>2.5.3.8</span> Backup/Restore<a href=#backuprestore class=anchor aria-hidden=true></a></h4><p>This option can be used to take a backup of the selected applications\nand its data or restore them. Two options are available here: <em>Backup\noptions</em> and <em>backup name</em>.<ul class=incremental><li><p><strong>Backup options.</strong> Same as the <a href=#subsec:backup-restore-backup-options>backup options</a> of the\nbackup/restore feature. If not set, the default options will be\nused.<li><p><strong>Backup name.</strong> Set a custom name for the backup.\nIf the backup name is set, each time a backup is made, it will be given\na unique name with backup-name as the suffix. This behaviour will be\nfixed in a future release. Leave this field empty for regular “base”\nbackups (also, make sure not to enable <em>backup multiple</em> in the\nbackup options).</ul><p>If the <a href=#subsubsec:profile-state>state</a> is <em>on</em>,\nthe packages will be backed up, and if the state is <em>off</em>, the\npackages will be restored. The option can be disabled by clicking on the\n<em>disable</em> button in the input dialog.</section><section id=export-blocking-rules class=level4 data-number=2.5.3.9><h4 data-number=2.5.3.9><span class=header-section-number>2.5.3.9</span> Export Blocking Rules<a href=#export-blocking-rules class=anchor aria-hidden=true></a></h4><div class=\"amalert danger\"><p><strong><em>Danger.</em></strong><p>This option is not yet implemented.</div></section><section id=freeze class=level4 data-number=2.5.3.10><h4 data-number=2.5.3.10><span class=header-section-number>2.5.3.10</span> Freeze<a href=#freeze class=anchor aria-hidden=true></a></h4><p>Allow freezing or unfreezing the selected packages depending on the\nvalue of the <a href=#subsubsec:profile-state>state</a>. If the state\nis <em>on</em>, the packages will be frozen, and if the state is\n<em>off</em>, they will be unfrozen.</section><section id=force-stop class=level4 data-number=2.5.3.11><h4 data-number=2.5.3.11><span class=header-section-number>2.5.3.11</span> Force-stop<a href=#force-stop class=anchor aria-hidden=true></a></h4><p>Allow the selected packages to be force-stopped.</section><section id=clear-cache class=level4 data-number=2.5.3.12><h4 data-number=2.5.3.12><span class=header-section-number>2.5.3.12</span> Clear Cache<a href=#clear-cache class=anchor aria-hidden=true></a></h4><p>Enable clearing cache for the selected packages.</section><section id=clear-data class=level4 data-number=2.5.3.13><h4 data-number=2.5.3.13><span class=header-section-number>2.5.3.13</span> Clear Data<a href=#clear-data class=anchor aria-hidden=true></a></h4><p>Enable clearing data for the selected packages.</section><section id=block-trackers class=level4 data-number=2.5.3.14><h4 data-number=2.5.3.14><span class=header-section-number>2.5.3.14</span> Block Trackers<a href=#block-trackers class=anchor aria-hidden=true></a></h4><p>Enable blocking or unblocking of the tracker components from the\nselected packages depending on the value of the <a href=#subsubsec:profile-state>state</a>. If the state is <em>on</em>,\nthe trackers will be blocked, and if the state is <em>off</em>, the\ntrackers will be unblocked.</section><section id=save-apk class=level4 data-number=2.5.3.15><h4 data-number=2.5.3.15><span class=header-section-number>2.5.3.15</span> Save APK<a href=#save-apk class=anchor aria-hidden=true></a></h4><p>Enable saving APK files at <code>AppManager/apks</code> (or in the\ndirectory selected in the settings page) of the selected packages.</section></section></section><section id=sec:settings-page class=level2 data-number=2.6><h2 data-number=2.6><span class=header-section-number>2.6</span> <a href=#toc:sec:settings-page>Settings Page</a><a href=#sec:settings-page class=anchor aria-hidden=true></a></h2><p>Settings page can be used to customise the behaviour of App\nManager.<section id=subsec:language class=level3 data-number=2.6.1><h3 data-number=2.6.1><span class=header-section-number>2.6.1</span>\n<a href=#toc:subsec:language>Language</a><a href=#subsec:language class=anchor aria-hidden=true></a></h3><p>Configure in-app language. App Manager currently supports 22\n(twenty-two) languages.</section><section id=subsec:appearance class=level3 data-number=2.6.2><h3 data-number=2.6.2><span class=header-section-number>2.6.2</span>\n<a href=#toc:subsec:appearance>Appearance</a><a href=#subsec:appearance class=anchor aria-hidden=true></a></h3><section id=subsubsec:app-theme class=level4 data-number=2.6.2.1><h4 data-number=2.6.2.1><span class=header-section-number>2.6.2.1</span> App Theme<a href=#subsubsec:app-theme class=anchor aria-hidden=true></a></h4><p>Configure in-app theme.</section><section id=subsubsec:pure-black-theme class=level4 data-number=2.6.2.2><h4 data-number=2.6.2.2><span class=header-section-number>2.6.2.2</span> Pure Black Theme<a href=#subsubsec:pure-black-theme class=anchor aria-hidden=true></a></h4><p>Whether to use a black background instead of the material themed\nbackground.</section><section id=subsubsec:layout-direction class=level4 data-number=2.6.2.3><h4 data-number=2.6.2.3><span class=header-section-number>2.6.2.3</span> Layout Direction<a href=#subsubsec:layout-direction class=anchor aria-hidden=true></a></h4><p>Change layout direction, either left to right or right to left. This\nis usually set using the selected language but not everybody prefers the\nsame direction.</section><section id=subsubsec:enable/disable-features class=level4 data-number=2.6.2.4><h4 data-number=2.6.2.4><span class=header-section-number>2.6.2.4</span> Enable/Disable Features<a href=#subsubsec:enable/disable-features class=anchor aria-hidden=true></a></h4><p>Enable or disable certain features in App Manager, such as<ul class=incremental><li><p><strong>Interceptor</strong><li><p><strong>Manifest viewer</strong><li><p><strong>Scanner</strong><li><p><strong>Package installer</strong><li><p><strong>Usage access.</strong> With this feature turned off, App\nManager will never ask for the <em>Usage Access</em>\npermission.<li><p><strong>Log viewer</strong><li><p><strong>App explorer.</strong> The “Explore” option will not be\navailable while trying to open an APK file.<li><p><strong>App info.</strong> The “App info” option displayed while\ntrying to open an APK file.<li><p><strong>Code Editor</strong><li><p><strong>VirusTotal</strong></ul></section></section><section id=subsec:privacy class=level3 data-number=2.6.3><h3 data-number=2.6.3><span class=header-section-number>2.6.3</span>\n<a href=#toc:subsec:privacy>Privacy</a><a href=#subsec:privacy class=anchor aria-hidden=true></a></h3><section id=subsubsec:screen-lock class=level4 data-number=2.6.3.1><h4 data-number=2.6.3.1><span class=header-section-number>2.6.3.1</span> Screen Lock<a href=#subsubsec:screen-lock class=anchor aria-hidden=true></a></h4><p>Lock App Manager using Android screen lock provided a screen lock is\nconfigured.<div class=\"amalert warning\"><p><strong><em>Warning.</em></strong><p>If screen lock is disabled in Android after enabling this setting,\nApp Manager will not open until it is enabled again.</div></section><section id=subsubsec:run-am-in-background class=level4 data-number=2.6.3.2><h4 data-number=2.6.3.2><span class=header-section-number>2.6.3.2</span> Run App Manager in the\nBackground<a href=#subsubsec:run-am-in-background class=anchor aria-hidden=true></a></h4><p>Whether to run App Manager in the background to reduce the\ninitialisation delay. On certain devices, this can also help if you’re\nfrequently disconnected from ADB.</section><section id=subsubsec:use-the-internet class=level4 data-number=2.6.3.3><h4 data-number=2.6.3.3><span class=header-section-number>2.6.3.3</span> Use the Internet<a href=#subsubsec:use-the-internet class=anchor aria-hidden=true></a></h4><p>Whether to activate the Internet features in App Manager. This\ncurrently include VirusTotal and Pithus scanning in the <a href=#sec:scanner-page>Scanner page</a>.</section><section id=subsubsec:auth-manager class=level4 data-number=2.6.3.4><h4 data-number=2.6.3.4><span class=header-section-number>2.6.3.4</span> Authorization Manager<a href=#subsubsec:auth-manager class=anchor aria-hidden=true></a></h4><p>This setting allows a third-party application to get access to\ncertain features, such as profiles.</section></section><section id=subsec:mode-of-operation class=level3 data-number=2.6.4><h3 data-number=2.6.4><span class=header-section-number>2.6.4</span>\n<a href=#toc:subsec:mode-of-operation>Mode of Operation</a><a href=#subsec:mode-of-operation class=anchor aria-hidden=true></a></h3><p>Mode of operation defines how App Manager works as a whole. It has\nthe following options:<ul class=incremental><li><p><strong>Auto.</strong> Let App Manager decide the suitable\noption. Although this is the default option, non-rooted users should use\nthe <em>no-root</em> mode.<li><p><strong>Root.</strong> Operate App Manager in root mode. App\nManager will fall back to <em>no-root</em> mode if root is not detected,\nor in rare cases when Binder communication through root is disabled\n(e.g. in <a href=https://github.com/MuntashirAkon/AppManager/issues/606>Phh\nSuperUser</a>).<li><p><strong>ADB over TCP.</strong> Operate App Manager in ADB mode\nvia <a href=#sec:adb-over-tcp>ADB over TCP</a>. App Manager will fall\nback to <em>no-root</em> mode if ADB over TCP is not enabled.<li><p><strong>Wireless debugging.</strong> Enable ADB via Wireless\nDebugging. It will try to connect to the configured port automatically\nat first. On failure, it will ask the user to either pair or connect to\nthe ADB daemon manually. App Manager will fall back to <em>no-root</em>\nmode if it fails to connect to the ADB daemon this way.<div class=\"amalert tip\"><p><strong><em>Info.</em></strong><p>This option is only displayed in devices running Android 11 or later\nas Wireless Debugging was introduced in Android 11.</div><li><p><strong>No-root.</strong> Operate App Manager in no-root mode.\nWhile App Manager performs better in this mode, all the root- or\nADB-specific features will be disabled.</ul><p>It also displays the actual mode of operation at the top. The actual\nmode of operations are <em>root</em>, <em>ABD</em> and\n<em>no-root</em>.<div class=\"amalert tip\"><p><strong><em>Notice.</em></strong><p>“Remote service” is only required for ADB users or when you use the\ncustom commands.</div></section><section id=subsec:apk-signing class=level3 data-number=2.6.5><h3 data-number=2.6.5><span class=header-section-number>2.6.5</span>\n<a href=#toc:subsec:apk-signing>APK Signing</a><a href=#subsec:apk-signing class=anchor aria-hidden=true></a></h3><section id=signature-schemes class=level4 data-number=2.6.5.1><h4 data-number=2.6.5.1><span class=header-section-number>2.6.5.1</span> Signature Schemes<a href=#signature-schemes class=anchor aria-hidden=true></a></h4><p>Configure the <a href=https://source.android.com/security/apksigning>signature\nschemes</a> to be used when APK signing is enabled. v1 and v2 signature\nschemes are enabled by default, but v3 should also be enabled to ensure\nproper security in Android 9 or later.</section><section id=signing-key class=level4 data-number=2.6.5.2><h4 data-number=2.6.5.2><span class=header-section-number>2.6.5.2</span> Signing Key<a href=#signing-key class=anchor aria-hidden=true></a></h4><p>Configure the signing key for signing APK files. Keys from an\nexisting KeyStore can be imported to App Manager, or a new key can be\ngenerated.<div class=\"amalert tip\"><p><strong><em>Tip.</em></strong><p>If you need to use the key in the future, it is recommended that you\ncreate a KeyStore yourself and import the key here. Without a proper\nbackup, keys generated within App Manager are at the risk of being\ndeleted.</div></section><section id=align-apk-files class=level4 data-number=2.6.5.3><h4 data-number=2.6.5.3><span class=header-section-number>2.6.5.3</span> Align APK Files<a href=#align-apk-files class=anchor aria-hidden=true></a></h4><p>Performs zip alignment when App Manager signs an APK file. Zip\nalignment stores the files in the APK file (which is actually a zip\nfile) in a way that a zip file reader can access the files quite easily\nusing random access instead of loading the entire APK file in the\nmemory, which results in the reduction of Android’s memory usage. Note\nthat this step is required if an application’s manifest has\n<code>extractNativeLibs</code> set to <code>true</code>.</section></section><section id=subsec:installer class=level3 data-number=2.6.6><h3 data-number=2.6.6><span class=header-section-number>2.6.6</span>\n<a href=#toc:subsec:installer>Installer</a><a href=#subsec:installer class=anchor aria-hidden=true></a></h3><p>Configure the default behaviour of the installer. You can also find\nmost of the settings by clicking on the <em>cog</em> icon when you\ninstall an application.<section id=install-location class=level4 data-number=2.6.6.1><h4 data-number=2.6.6.1><span class=header-section-number>2.6.6.1</span> Install Location<a href=#install-location class=anchor aria-hidden=true></a></h4><p>Define APK installation location. This can be one of <em>auto</em>,\n<em>internal only</em> and <em>prefer external</em>. In newer Android\nversions, selecting the last option does not guarantee that the\napplication will be installed in the external storage.</section><section id=block-trackers-1 class=level4 data-number=2.6.6.2><h4 data-number=2.6.6.2><span class=header-section-number>2.6.6.2</span> Block Trackers<a href=#block-trackers-1 class=anchor aria-hidden=true></a></h4><p>Whether to block the tracking components immediately after installing\nthe application.</section><section id=display-changes class=level4 data-number=2.6.6.3><h4 data-number=2.6.6.3><span class=header-section-number>2.6.6.3</span> Display Changes<a href=#display-changes class=anchor aria-hidden=true></a></h4><p>Whether to display changes in version, trackers, components,\npermissions, signatures, SDK, etc. in a version controlled style before\ninstalling the application if the application has already been\ninstalled.</section><section id=installer-app class=level4 data-number=2.6.6.4><h4 data-number=2.6.6.4><span class=header-section-number>2.6.6.4</span> Installer App<a href=#installer-app class=anchor aria-hidden=true></a></h4><p>Select the installer application. This is useful for applications\nthat explicitly checks the installer as a way to verify if the\napplication is installed legitimately. This only works for root or ADB\nusers.<div class=\"amalert tip\"><p><strong><em>Notice.</em></strong><p>While checking for the installer might seem a legitimate concern for\nan application, the Android framework already deals with this during the\ninstallation. Checking for the installer is simply the wrong way to\nprove the legitimacy of the source of an application.</div></section><section id=sign-apk class=level4 data-number=2.6.6.5><h4 data-number=2.6.6.5><span class=header-section-number>2.6.6.5</span> Sign APK<a href=#sign-apk class=anchor aria-hidden=true></a></h4><p>Whether to sign the APK files before installing the application. A\nsigning key has to be added or generated before this option can be\nenabled. This can be done in the <a href=#subsec:apk-signing>APK\nsigning</a> page.</section><section id=immediately-perform-dex-optimization class=level4 data-number=2.6.6.6><h4 data-number=2.6.6.6><span class=header-section-number>2.6.6.6</span> Immediately Perform DEX\nOptimization<a href=#immediately-perform-dex-optimization class=anchor aria-hidden=true></a></h4><p>Whether to perform DEX optimization immediately after installing the\napplication. This can be useful for heavy applications, such as the\ngaming applications.</section><section id=install-in-the-background class=level4 data-number=2.6.6.7><h4 data-number=2.6.6.7><span class=header-section-number>2.6.6.7</span> Install in the Background<a href=#install-in-the-background class=anchor aria-hidden=true></a></h4><p>Whether to always install applications in the background. A\nnotification will be issued once the installation is finished.</section></section><section id=subsec:backup/restore class=level3 data-number=2.6.7><h3 data-number=2.6.7><span class=header-section-number>2.6.7</span>\n<a href=#toc:subsec:backup/restore>Back up/Restore</a><a href=#subsec:backup/restore class=anchor aria-hidden=true></a></h3><p>Settings related to <a href=#sec:backup-restore>back\nup/restore</a>.<section id=compression-method class=level4 data-number=2.6.7.1><h4 data-number=2.6.7.1><span class=header-section-number>2.6.7.1</span> Compression method<a href=#compression-method class=anchor aria-hidden=true></a></h4><p>Set the compression method to be used during backups. App Manager\nsupports GZip, BZip2 and Zstandard compression methods, GZip being the\ndefault compression method. It doesn’t affect the restore of an existing\nbackup.</section><section id=subsubsec:settings-backup-options class=level4 data-number=2.6.7.2><h4 data-number=2.6.7.2><span class=header-section-number>2.6.7.2</span> Backup Options<a href=#subsubsec:settings-backup-options class=anchor aria-hidden=true></a></h4><p>Customise the <em>back up/restore dialog</em> displayed while taking\na backup.<div class=seealso-inline><p><em>See also: <span><a href=#subsec:backup-restore-backup-options>Backup\noptions</a></span></em></div></section><section id=backup-apps-with-android-keystore class=level4 data-number=2.6.7.3><h4 data-number=2.6.7.3><span class=header-section-number>2.6.7.3</span> Backup apps with Android\nKeyStore<a href=#backup-apps-with-android-keystore class=anchor aria-hidden=true></a></h4><p>Allow backup of applications that has entries in the Android\nKeyStore. This option is disabled by default because a few apps (such as\nSignal or Element) may crash if restored.</section><section id=subsubsec:settings-encryption class=level4 data-number=2.6.7.4><h4 data-number=2.6.7.4><span class=header-section-number>2.6.7.4</span> Encryption<a href=#subsubsec:settings-encryption class=anchor aria-hidden=true></a></h4><p>Set an encryption method for the backups. App Manager currently\nsupports OpenPGP (via <a href=https://f-droid.org/packages/org.sufficientlysecure.keychain/>OpenKeyChain</a>),\nAES, RSA and ECC. Like <a href=#subsec:apk-signing>APK signing</a>,\nThe AES, RSA and ECC keys are stored in the KeyStore and can be imported\nfrom other KeyStores.<div class=\"amalert danger\"><p><strong><em>Danger.</em></strong><p>For your own safety, it is not recommended generating RSA and ECC\nkeys inside App Manager. Instead, they should be imported from a\nKeyStore stored in a secure place.<br>In case of AES, the generated key should be stored in a secure place,\nsuch as in a password manager.</div></section><section id=subsubsec:backup-volume class=level4 data-number=2.6.7.5><h4 data-number=2.6.7.5><span class=header-section-number>2.6.7.5</span> Backup Volume<a href=#subsubsec:backup-volume class=anchor aria-hidden=true></a></h4><p>Select the storage where the backups will be stored. This is also\nwhere logs and exported APK files are saved.<div class=\"amalert tip\"><p><strong><em>Notice.</em></strong><p>The backup volume only specifies the storage, not the path. Backups\nare traditionally stored in the <code>AppManager</code> folder inside\nthe storage path. But when the path is selected using Storage Access\nFramework (SAF), the selected path or directory is used directly.</div></section><section id=import-backups class=level4 data-number=2.6.7.6><h4 data-number=2.6.7.6><span class=header-section-number>2.6.7.6</span> Import Backups<a href=#import-backups class=anchor aria-hidden=true></a></h4><p>Import backups from old and discontinued projects such as Titanium\nBackup, OAndBackup, and Swift Backup (version 3.0 to 3.2). The backups\nare not deleted after importing to prevent data loss in case the\nimported backups cannot be restored properly.</section></section><section id=subsec:rules class=level3 data-number=2.6.8><h3 data-number=2.6.8><span class=header-section-number>2.6.8</span>\n<a href=#toc:subsec:rules>Rules</a><a href=#subsec:rules class=anchor aria-hidden=true></a></h3><section id=subsubsec:instant-component-blocking class=level4 data-number=2.6.8.1><h4 data-number=2.6.8.1><span class=header-section-number>2.6.8.1</span> Instant Component\nBlocking<a href=#subsubsec:instant-component-blocking class=anchor aria-hidden=true></a></h4><p>By default, blocking rules are not applied unless they are applied\nexplicitly in <a href=#sec:app-details-page>the App Details page</a>\nfor any application. After enabling this option, all (old and new) rules\nare applied immediately for all applications without explicitly enabling\nblocking for an application.<div class=seealso-inline><p><em>See also: <span><a href=#subsec:faq:what-is-instant-component-blocking>FAQ: What is\ninstant component blocking?</a></span></em></div></section><section id=importexport-blocking-rules class=level4 data-number=2.6.8.2><h4 data-number=2.6.8.2><span class=header-section-number>2.6.8.2</span> Import/Export Blocking\nRules<a href=#importexport-blocking-rules class=anchor aria-hidden=true></a></h4><p>It is possible to import or export blocking rules within App Manager\nfor all applications. The types of rules (components, app ops or\npermissions) that should be imported or exported can also be selected.\nIt is also possible to import blocking rules from <a href=https://github.com/lihenggui/blocker>Blocker</a> and <a href=https://github.com/tuyafeng/Watt>Watt</a>. If it is necessary to\nexport blocking rules for a single application, the corresponding <a href=#sec:app-details-page>App Details page</a> can be used to export\nrules, or for multiple apps, <a href=#subsec:batch-operations>batch\noperations</a> can be used.<div class=seealso-inline><p><em>See also: <span><a href=#sec:rules-specification>Rules\nSpecification</a></span></em></div><section id=export class=level5 data-number=2.6.8.2.1><h5 data-number=2.6.8.2.1><span class=header-section-number>2.6.8.2.1</span> Export<a href=#export class=anchor aria-hidden=true></a></h5><p>Export blocking rules for all applications configured within App\nManager. This may include <a href=#subsec:faq:what-are-app-components>app components</a>, app ops\nand permissions based on the options selected in the multi-choice\noptions.</section><section id=import class=level5 data-number=2.6.8.2.2><h5 data-number=2.6.8.2.2><span class=header-section-number>2.6.8.2.2</span> Import<a href=#import class=anchor aria-hidden=true></a></h5><p>Import previously exported blocking rules from App Manager. Similar\nto export, this may include <a href=#subsec:faq:what-are-app-components>app components</a>, app ops\nand permissions based on the options selected in the multi-choice\noptions.</section><section id=par:import-existing-rules class=level5 data-number=2.6.8.2.3><h5 data-number=2.6.8.2.3><span class=header-section-number>2.6.8.2.3</span> Import Existing Rules<a href=#par:import-existing-rules class=anchor aria-hidden=true></a></h5><p>Add components disabled by other applications to App Manager. App\nManager only keeps track of the components disabled within App Manager.\nIf application components are blocked or disabled by other tools or\napplications, this option can be utilised to import them. On clicking\nthis option, App Manager will find the components potentially disabled\nby other applications or tools and list only the name of the\napplications along with the number of matched components. For safety,\nall the applications are unselected by default. They have to be selected\nmanually, and the blocking has to be re-applied via App Manager.<div class=\"amalert danger\"><p><strong><em>Caution.</em></strong><p>Be careful when using this tool as there can be many false positives.\nChoose only the applications that you are certain about.</div></section><section id=import-from-watt class=level5 data-number=2.6.8.2.4><h5 data-number=2.6.8.2.4><span class=header-section-number>2.6.8.2.4</span> Import from Watt<a href=#import-from-watt class=anchor aria-hidden=true></a></h5><p>Import configuration files from <a href=https://github.com/tuyafeng/Watt>Watt</a>, each file containing\nrules for a single package and file name being the name of the package\nwith <code>.xml</code> extension.<div class=\"amalert tip\"><p><strong><em>Tip.</em></strong><p>Location of configuration files in Watt:\n<code>/sdcard/Android/data/com.tuyafeng.watt/files/ifw</code></div></section><section id=import-from-blocker class=level5 data-number=2.6.8.2.5><h5 data-number=2.6.8.2.5><span class=header-section-number>2.6.8.2.5</span> Import from Blocker<a href=#import-from-blocker class=anchor aria-hidden=true></a></h5><p>Import blocking rules from <a href=https://github.com/lihenggui/blocker>Blocker</a>, each file\ncontaining rules for a single package. These files have a\n<code>.json</code> extension.</section></section><section id=remove-all-rules class=level4 data-number=2.6.8.3><h4 data-number=2.6.8.3><span class=header-section-number>2.6.8.3</span> Remove all rules<a href=#remove-all-rules class=anchor aria-hidden=true></a></h4><p>One-click option to remove all rules configured within App Manager.\nThis will enable all blocked components, app ops will be set to their\ndefault values and permissions will be granted.</section></section><section id=subsec:advanced class=level3 data-number=2.6.9><h3 data-number=2.6.9><span class=header-section-number>2.6.9</span>\n<a href=#toc:subsec:advanced>Advanced</a><a href=#subsec:advanced class=anchor aria-hidden=true></a></h3><section id=subsubsec:selected-users class=level4 data-number=2.6.9.1><h4 data-number=2.6.9.1><span class=header-section-number>2.6.9.1</span> Selected Users<a href=#subsubsec:selected-users class=anchor aria-hidden=true></a></h4><p>This option lets you control the users App Manager should operate on.\nApp Manager operates on all users in root or ADB mode by default.</section><section id=subsubsec:saved-apk-name-format class=level4 data-number=2.6.9.2><h4 data-number=2.6.9.2><span class=header-section-number>2.6.9.2</span> Saved APK Name Format<a href=#subsubsec:saved-apk-name-format class=anchor aria-hidden=true></a></h4><p>Defines the format of the APK name to be used while saving it via\nbatch operations or through profiles. App Manager offers some special\nkeywords enclosed inside <code>%</code> (percentage) signs and available\nbelow the input box. These keywords are:<ul class=incremental><li><p><strong><code>label</code>.</strong> Denotes the name or label of\nthe application. This can be localised to the configured language\ndepending on the app.<li><p><strong><code>package_name</code>.</strong> Denotes the name of\nthe package or application ID, the unique identifier that each\napplication has.<li><p><strong><code>version</code>.</strong> Denotes the current\nversion of the application extracted from its manifest.<li><p><strong><code>version_code</code>.</strong> Denotes the current\nversion code of the application that can be used to separate two\nversions of the same application.<li><p><strong><code>min_sdk</code>.</strong> Denotes the minimum SDK\n(i.e. Android framework version) that the application can operate on.\nThis data is only available since Android 7 (Nougat).<li><p><strong><code>target_sdk</code>.</strong> Denotes the SDK that\nthis application targets. The application can operate on higher SDK but\nonly in the compatibility mode.<li><p><strong><code>datetime</code>.</strong> Denotes the time and date\nwhen the APK is exported.</ul></section><section id=subsubsec:import/export-keystore class=level4 data-number=2.6.9.3><h4 data-number=2.6.9.3><span class=header-section-number>2.6.9.3</span> Import/Export Keystore<a href=#subsubsec:import/export-keystore class=anchor aria-hidden=true></a></h4><p>Import or export the KeyStore used by App Manager. This is a Bouncy\nCastle KeyStore with <code>bks</code> extension. Therefore, other\nKeyStore such as Java KeyStore (JKS) or PKCS #12 are not supported. If a\nkey is needed to be imported from such a KeyStore, the relevant options\nshould be should as specified above.</section></section><section id=subsec:device-info class=level3 data-number=2.6.10><h3 data-number=2.6.10><span class=header-section-number>2.6.10</span> <a href=#toc:subsec:device-info>About the device</a><a href=#subsec:device-info class=anchor aria-hidden=true></a></h3><p>Display Android version, security, CPU, GPU, battery, memory, screen,\nlanguages, user info, etc.</section></section><section id=sec:scanner-page class=level2 data-number=2.7><h2 data-number=2.7><span class=header-section-number>2.7</span> <a href=#toc:sec:scanner-page>Scanner Page</a><a href=#sec:scanner-page class=anchor aria-hidden=true></a></h2><p><strong>Scanner page</strong> appears after clicking on the\n<em>scanner</em> button in the <a href=#subsec:app-info-tab>App Info\ntab</a>. External APK files can also be opened for scanning from file\nmanagers, web browsers, etc.<p>It scans for trackers and libraries, and displays the number of\ntrackers and libraries as a summary. It also displays checksums of the\nAPK file as well as the signing certificates. If VirusTotal is\nconfigured in the settings, it also attempts to retrieve reports from\nVirusTotal, or uploads the APK file if it is not in the database. It\nalso display a link to the <a href=https://beta.pithus.org>Pithus</a>\nreport provided the Internet features are enabled.<div class=\"amalert danger\"><p><strong><em>Disclaimer.</em></strong><p>App Manager only scans an application statically without prejudice.\nThe application may provide the options for opting out, or in some\ncases, certain features of the tracker may not be used at all by the\napplication (e.g. F-Droid), or some applications may simply use them as\nplaceholders to prevent the breaking of certain features (e.g. Fennec\nF-Droid). <strong>The intention of the scanner is to give you an idea\nabout what the APK might contain. It should be taken as an initial step\nfor further investigations.</strong></div><p>Clicking on the first item (i.e. number of classes) opens a new page\ncontaining a list of tracker classes for the application. All classes\ncan also be viewed by clicking on the <em>Toggle Class Listing</em>\nmenu. The SMALI or Java version of the class can be viewed by simply\nclicking on an item.<div class=\"amalert tip\"><p><strong><em>Notice.</em></strong><p>Due to various limitations, it is not possible to scan all the\ncomponents of an APK file. This is especially true if an APK is highly\nobfuscated or packed. The scanner also does not check strings (or\nwebsite signatures).</div><p>The second item lists the number of trackers along with their names.\nClicking on the item displays a dialog containing the name of trackers,\nmatched signatures, and the number of classes against each signature.\nSome tracker names may have <span class=\"math inline\"><sup>2</sup></span> prefix which indicates that the\ntrackers are in the <a href=https://etip.exodus-privacy.eu.org>ETIP</a> stand-by list, i.e.,\nwhether they are actual trackers is still being investigated.<p>The third item lists the number of libraries along with their names.\nThe information are mostly taken from <a href=https://gitlab.com/IzzyOnDroid/repo>IzzyOnDroid repo</a>.<div class=seealso-inline><p><em>See also: <span><a href=#subsec:tracker-classes-versus-tracker-components>FAQ: Tracker\nclasses vs tracker components</a></span></em></div></section><section id=sec:interceptor-page class=level2 data-number=2.8><h2 data-number=2.8><span class=header-section-number>2.8</span> <a href=#toc:sec:interceptor-page>Interceptor Page</a><a href=#sec:interceptor-page class=anchor aria-hidden=true></a></h2><p>Interceptor can be used to intercept communication between\napplications using <code>Intent</code>. It works as a man-in-the-middle\nbetween the source and the destination applications. It offers a\nfeature-complete user interface for editing <code>Intent</code>s.<div class=\"amalert warning\"><p><strong><em>Warning.</em></strong><p>Interceptor only works for <em>implicit</em> intents where the <a href=#subsec:faq:what-are-app-components>app component</a> isn’t\nspecified.</div><div class=seealso><p><em>See also:</em><ul class=incremental><li><p><a href=https://developer.android.com/guide/components/intents-common>Common\nIntents</a><li><p><a href=https://developer.android.com/guide/components/intents-filters>Intents\nand Intent Filters</a></ul></div><section id=subsec:intent-filters class=level3 data-number=2.8.1><h3 data-number=2.8.1><span class=header-section-number>2.8.1</span>\n<a href=#toc:subsec:intent-filters>Intent Filters</a><a href=#subsec:intent-filters class=anchor aria-hidden=true></a></h3><p>Intent filters are used by the applications to specify the tasks they\nare able to perform or the tasks they are going to perform using other\napplications. For example, when you’re opening a PDF file using a file\nmanager, the file manager will try to find the applications to open the\nPDF with. To find the right applications, the file manager will create\nan Intent with filters such as the MIME type and ask the system to\nretrieve the applications capable of opening this filter. The system\nwill search through the Manifest of the installed applications to match\nthe filter and list the application components that are able to open\nthis filter (in our case the PDF). At this, either the file manager will\nopen the desired application component all by itself or use a system\nprovided option to open it. If multiple application components are able\nto open it and no default is set, you may get a prompt where you have to\nchoose the right application component.<section id=subsubsec:action class=level4 data-number=2.8.1.1><h4 data-number=2.8.1.1><span class=header-section-number>2.8.1.1</span> Action<a href=#subsubsec:action class=anchor aria-hidden=true></a></h4><p>Action specifies the generic action to perform such as\n<code>android.intent.action.VIEW</code>. Applications often declare the\nrelevant actions in the Manifest file to catch the desired Intents. The\naction is particularly useful for broadcast Intent where it plays a\nvital rule. In other cases, it works as an initial way to filter out the\nrelevant application components. Generic actions such as\n<code>android.intent.action.VIEW</code> and\n<code>android.intent.action.SEND</code> are widely used by applications.\nHence, setting this alone may match many application components.</section><section id=subsubsec:data class=level4 data-number=2.8.1.2><h4 data-number=2.8.1.2><span class=header-section-number>2.8.1.2</span> Data<a href=#subsubsec:data class=anchor aria-hidden=true></a></h4><p>Data is originally known as URI (Uniform Resource Identifier) defined\nin <a href=http://www.faqs.org/rfcs/rfc2396.html>RFC 2396</a>. It can\nbe web links, file location, or a special feature called\n<em>content</em>. Contents are an Android feature managed by the <a href=#subsubsec:providers>content providers</a>. Data are often\nassociated with a <a href=#subsubsec:mime-type>MIME type</a>.<p>Examples:<pre><code>http://search.disroot.org/?q=URI%20in%20Android%20scheme&amp;categories=general&amp;language=en-US\nhttps://developer.android.com/reference/android/net/Uri\nfile:///sdcard/AppManager.apk\nmailto:email@example.com\ncontent://io.github.muntashirakon.AppManager.provider/23485af89b08d87e898a90c7e/AppManager.apk</code></pre></section><section id=subsubsec:mime-type class=level4 data-number=2.8.1.3><h4 data-number=2.8.1.3><span class=header-section-number>2.8.1.3</span> MIME Type<a href=#subsubsec:mime-type class=anchor aria-hidden=true></a></h4><p>MIME type of the <a href=#subsubsec:data>data</a>. For example, if\nthe data field is set to <code>file:///sdcard/AppManager.apk</code>, the\nassociated MIME type can be\n<code>application/vnd.android.package-archive</code>.</section><section id=categories class=level4 data-number=2.8.1.4><h4 data-number=2.8.1.4><span class=header-section-number>2.8.1.4</span> Categories<a href=#categories class=anchor aria-hidden=true></a></h4><p>This is similar to <a href=#subsubsec:action>action</a> in the\nsense that it is also used by the system to filter application\ncomponents. This has no further benefits. Unlike <em>action</em>, there\ncan be more than one category. Clicking on the <em>plus</em> button next\nto the title allows adding more categories.</section><section id=flags class=level4 data-number=2.8.1.5><h4 data-number=2.8.1.5><span class=header-section-number>2.8.1.5</span> Flags<a href=#flags class=anchor aria-hidden=true></a></h4><p>Flags are useful in determining how system should behave during the\nlaunch or after the launch of an activity. This should not be touched as\nit requires some technical background. The <em>plus</em> button next to\nthe title can be used to add one or more flags.</section><section id=extras class=level4 data-number=2.8.1.6><h4 data-number=2.8.1.6><span class=header-section-number>2.8.1.6</span> Extras<a href=#extras class=anchor aria-hidden=true></a></h4><p>Extras are the key-value pairs used for supplying additional\ninformation to the destination component. More extras can be added using\nthe <em>plus</em> button next to the title.</section><section id=uri class=level4 data-number=2.8.1.7><h4 data-number=2.8.1.7><span class=header-section-number>2.8.1.7</span> URI<a href=#uri class=anchor aria-hidden=true></a></h4><p>Represents the entire Intent as a URI (e.g. <code>intent://…</code>).\nSome data cannot be converted to string, and as a result, they might not\nappear here.</section></section><section id=subsec:matching-activities class=level3 data-number=2.8.2><h3 data-number=2.8.2><span class=header-section-number>2.8.2</span>\n<a href=#toc:subsec:matching-activities>Matching Activities</a><a href=#subsec:matching-activities class=anchor aria-hidden=true></a></h3><p>List all the activity components that matches the Intent. This is\ninternally determined by the system (rather than App Manager). The\nlaunch button next to each component can be used to launch them directly\nfrom App Manager.</section><section id=subsec:interceptor-reset-to-default class=level3 data-number=2.8.3><h3 data-number=2.8.3><span class=header-section-number>2.8.3</span>\n<a href=#toc:subsec:interceptor-reset-to-default>Reset to\nDefault</a><a href=#subsec:interceptor-reset-to-default class=anchor aria-hidden=true></a></h3><p>Reset the Intent to its initial state.</section><section id=subsec:interceptor-send-edited-intent class=level3 data-number=2.8.4><h3 data-number=2.8.4><span class=header-section-number>2.8.4</span>\n<a href=#toc:subsec:interceptor-send-edited-intent>Send Edited\nIntent</a><a href=#subsec:interceptor-send-edited-intent class=anchor aria-hidden=true></a></h3><p>Resend the edited Intent to the destination application. This may\nopen a list of applications where the desired application is needed to\nbe selected. The result received from the target application will be\nsent to the source application. As a result, the source application will\nnot know if there was a man-in-the-middle.</section></section><section id=sec:shared-preferences-editor-page class=level2 data-number=2.9><h2 data-number=2.9><span class=header-section-number>2.9</span> <a href=#toc:sec:shared-preferences-editor-page>Shared Preferences Editor\nPage</a><a href=#sec:shared-preferences-editor-page class=anchor aria-hidden=true></a></h2><p>Shared preferences can be edited in this page. Clicking any item on\nthe list opens the edit dialog where the item can be edited. The\nfloating action button in the bottom-right corner can be used to add a\nnew item. To save or delete the file, or to discard current changes, the\nrespective options in the menu can be used.</section></section><section id=ch:guides class=level1 data-number=3><h1 data-number=3><span class=header-section-number>3</span> <a href=#toc:ch:guides>Guides</a><a href=#ch:guides class=anchor aria-hidden=true></a></h1><section id=sec:adb-over-tcp class=level2 data-number=3.1><h2 data-number=3.1><span class=header-section-number>3.1</span> <a href=#toc:sec:adb-over-tcp>ADB over TCP</a><a href=#sec:adb-over-tcp class=anchor aria-hidden=true></a></h2><p>Many root-only features can still be used by enabling ADB over TCP.\nTo do that, a PC or Mac is required with Android platform-tools\ninstalled, and an Android phone with developer options & USB\ndebugging enabled.<div class=\"amalert tip\"><p><strong><em>Root users.</em></strong><p>If superuser permission has been granted to App Manager, it can\nalready execute privileged code without any problem. <strong>Therefore,\nroot users do not need to enable ADB over TCP.</strong> But if you\ninsist on using ADB over TCP, you must revoke superuser permission for\nApp Manager.</div><div class=seealso-inline><p><em>See also: <span><a href=#sec:faq:adb-over-tcp>FAQ: ADB over\nTCP</a></span></em></div><section id=subsec:enable-developer-options class=level3 data-number=3.1.1><h3 data-number=3.1.1><span class=header-section-number>3.1.1</span>\n<a href=#toc:subsec:enable-developer-options>Enable developer\noptions</a><a href=#subsec:enable-developer-options class=anchor aria-hidden=true></a></h3><section id=subsubsec:location-of-developer-options class=level4 data-number=3.1.1.1><h4 data-number=3.1.1.1><span class=header-section-number>3.1.1.1</span> Location of developer\noptions<a href=#subsubsec:location-of-developer-options class=anchor aria-hidden=true></a></h4><p><strong>Developer options</strong> is located in Android\n<strong>Settings</strong>, either directly near the bottom of the page\n(in most ROMs) or under some other settings, such as\n<strong>System</strong> (Google Pixel, Lineage OS, Asus Zenfone 8.0+),\n<strong>Additional Settings</strong> (Xiaomi MIUI, Oppo ColorOS),\n<strong>More Settings</strong> (Vivo FuntouchOS), <strong>More</strong>\n(ZTE Nubia). Unlike other options, it is not visible until explicitly\nenabled by the user. If it is already enabled, you can use the search\nbox in Android <strong>Settings</strong> to locate it as well.</section><section id=how-to-enable-developer-options class=level4 data-number=3.1.1.2><h4 data-number=3.1.1.2><span class=header-section-number>3.1.1.2</span> How to enable developer\noptions<a href=#how-to-enable-developer-options class=anchor aria-hidden=true></a></h4><p>This option is available within Android <strong>Settings</strong> as\nwell but like the location of the developer options, it also differs\nfrom device to device. But in general, you have to find <strong>Build\nnumber</strong> (or <strong>MIUI version</strong> for MIUI ROMs and\n<strong>Software version</strong> for Vivo FuntouchOS,\n<strong>Version</strong> for Oppo ColorOS) and tap it at least 7 (seven)\ntimes until you finally get a message saying <em>You are now a\ndeveloper</em> (you may be prompted to insert pin/password/pattern or\nsolve captchas at this point). In most devices, it is located at the\nbottom of the settings page, inside <strong>About Phone</strong>. But\nthe best way to find it is to use the search box.</section></section><section id=subsec:enable-usb-debugging class=level3 data-number=3.1.2><h3 data-number=3.1.2><span class=header-section-number>3.1.2</span>\n<a href=#toc:subsec:enable-usb-debugging>Enable USB debugging</a><a href=#subsec:enable-usb-debugging class=anchor aria-hidden=true></a></h3><p>After <a href=#subsubsec:location-of-developer-options>locating the\ndeveloper options</a>, enable <strong>Developer option</strong> (if not\nalready). After that, scroll down a bit until you will find the option\n<strong>USB debugging</strong>. Use the toggle button on the right-hand\nside to enable it. At this point, you may get an alert prompt where you\nmay have to click <em>OK</em> to actually enable it. You may also have\nto enable some other options depending on device vendor and ROM. Here\nare some examples:<section id=xiaomi-miui class=level4 data-number=3.1.2.1><h4 data-number=3.1.2.1><span class=header-section-number>3.1.2.1</span> Xiaomi (MIUI)<a href=#xiaomi-miui class=anchor aria-hidden=true></a></h4><p>Enable <strong>USB debugging (Security settings)</strong> as\nwell.</section><section id=huawei-emui class=level4 data-number=3.1.2.2><h4 data-number=3.1.2.2><span class=header-section-number>3.1.2.2</span> Huawei (EMUI)<a href=#huawei-emui class=anchor aria-hidden=true></a></h4><p>Enable <strong>Allow ADB debugging in charge only mode</strong> as\nwell. When connecting to your PC or Mac, you may get a prompt saying\n<strong>Allow access to device data?</strong> in which case click\n<strong>YES, ALLOW ACCESS</strong>.<div class=\"amalert tip\"><p><strong><em>Notice.</em></strong><p>Often the <strong>USB debugging</strong> mode could be disabled\nautomatically by the system. If that’s the case, repeat the above\nprocedure.</div></section><section id=realme class=level4 data-number=3.1.2.3><h4 data-number=3.1.2.3><span class=header-section-number>3.1.2.3</span> Realme<a href=#realme class=anchor aria-hidden=true></a></h4><p>Depending on the device and the version of operating system, you have\nto enable <strong>Disable Permission Monitoring</strong>, or <strong>USB\ndebugging (Security settings)</strong> along with <strong>Install via\nUSB</strong>.</section><section id=oneplus-oxygen-os class=level4 data-number=3.1.2.4><h4 data-number=3.1.2.4><span class=header-section-number>3.1.2.4</span> OnePlus (Oxygen OS)<a href=#oneplus-oxygen-os class=anchor aria-hidden=true></a></h4><p>Depending on the device and the version of operating system, you have\nto enable <strong>Disable Permission Monitoring</strong>.</section><section id=lg class=level4 data-number=3.1.2.5><h4 data-number=3.1.2.5><span class=header-section-number>3.1.2.5</span> LG<a href=#lg class=anchor aria-hidden=true></a></h4><p>Make sure you have <strong>USB tethering</strong> enabled.</section><section id=troubleshooting class=level4 data-number=3.1.2.6><h4 data-number=3.1.2.6><span class=header-section-number>3.1.2.6</span> Troubleshooting<a href=#troubleshooting class=anchor aria-hidden=true></a></h4><p>In case <strong>USB Debugging</strong> is greyed out, you can do the\nfollowing:<ol class=incremental><li><p>Make sure you enabled USB debugging before connecting your phone\nto the PC or Mac via USB cable<li><p>Enable USB tethering after connecting to PC or Mac via USB\ncable<li><p>(For Samsung) If your device is running KNOX, you may have to\nfollow some additional steps. See official documentations or consult\nsupport for further assistant</ol></section></section><section id=subsec:setup-adb-on-pc-or-mac class=level3 data-number=3.1.3><h3 data-number=3.1.3><span class=header-section-number>3.1.3</span>\n<a href=#toc:subsec:setup-adb-on-pc-or-mac>Setup ADB on PC or\nMac</a><a href=#subsec:setup-adb-on-pc-or-mac class=anchor aria-hidden=true></a></h3><p>In order to enable ADB over TCP, you have to set up ADB in your PC or\nMac. <strong><em>Lineage OS users can skip to §<a href=#subsubsec:lineage-os data-reference-type=ref data-reference=subsubsec:lineage-os>3.1.4.1</a>.</em></strong><section id=windows class=level4 data-number=3.1.3.1><h4 data-number=3.1.3.1><span class=header-section-number>3.1.3.1</span> Windows<a href=#windows class=anchor aria-hidden=true></a></h4><ol class=incremental><li><p>Download the latest version of <a href=https://dl.google.com/android/repository/platform-tools-latest-windows.zip>Android\nSDK Platform-Tools</a> for Windows<li><p>Extract the contents of the zip file into any directory (such as\n<code>C:\\</code><span><code>adb</code></span>) and navigate to that\ndirectory using <em>Explorer</em><li><p>Open <strong>Command Prompt</strong>,\n<strong>PowerShell</strong>, or <strong>Terminal</strong> from this\ndirectory. You can do it manually from the start menu or by holding\n<code>Shift</code> and right clicking within the directory in <em>File\nExplorer</em> and then clicking either on <em>Open command window\nhere</em>, or <em>Open PowerShell window here</em> (depending on what\nyou have installed). You can now access ADB by typing <code>adb</code>\n(Command Prompt) or <code>./adb</code> (PowerShell). Do not close this\nwindow yet.</ol><div class=\"amalert tip\"><p><strong><em>Tip.</em></strong><p>If you have <a href=https://learn.microsoft.com/en-us/windows/package-manager/winget/>WinGet</a>\ninstalled, you can install ADB using the following command:<div class=sourceCode id=cb3 data-frame=lines><pre class=\"sourceCode bash\"><code class=\"sourceCode bash\"><span id=cb3-1><a href=#cb3-1 aria-hidden=true tabindex=-1></a><span class=ex>winget</span> install <span class=at>--id</span> Google.PlatformTools</span></code></pre></div><p>After that, you can simply type <code>adb</code> to access ADB.</div></section><section id=macos class=level4 data-number=3.1.3.2><h4 data-number=3.1.3.2><span class=header-section-number>3.1.3.2</span> macOS<a href=#macos class=anchor aria-hidden=true></a></h4><ol class=incremental><li><p>Download the latest version of <a href=https://dl.google.com/android/repository/platform-tools-latest-darwin.zip>Android\nSDK Platform-Tools</a> for macOS<li><p>Extract the contents of the zip file into a directory by clicking\non it. After that, navigate to that directory using <em>Finder</em> and\nlocate <code>adb</code><li><p>Open <strong>Terminal</strong> using <em>Launchpad</em> or\n<em>Spotlight</em> and drag-and-drop <code>adb</code> from the\n<em>Finder</em> window into the <em>Terminal</em> window. Do not close\nthe <em>Terminal</em> window yet</ol><div class=\"amalert tip\"><p><strong><em>Tip.</em></strong><p>If you have <a href=https://brew.sh>Homebrew</a> installed, you can\ninstall ADB using the following command:<div class=sourceCode id=cb4 data-frame=lines><pre class=\"sourceCode bash\"><code class=\"sourceCode bash\"><span id=cb4-1><a href=#cb4-1 aria-hidden=true tabindex=-1></a><span class=ex>brew</span> install <span class=at>--cask</span> android-platform-tools</span></code></pre></div><p>After that, you can simply type <code>adb</code> in any\n<em>Terminal</em> window to access ADB.</div></section><section id=linux class=level4 data-number=3.1.3.3><h4 data-number=3.1.3.3><span class=header-section-number>3.1.3.3</span> Linux<a href=#linux class=anchor aria-hidden=true></a></h4><ol class=incremental><li><p>In your favourite terminal emulator, run the following\ncommand:<div class=sourceCode id=cb5 data-frame=lines data-autogobble><pre class=\"sourceCode bash\"><code class=\"sourceCode bash\"><span id=cb5-1><a href=#cb5-1 aria-hidden=true tabindex=-1></a><span class=bu>cd</span> ~/Downloads <span class=kw>&amp;&amp;</span> <span class=ex>curl</span> <span class=at>-o</span> platform-tools.zip <span class=at>-L</span> <span class=dt>\\</span></span>\n<span id=cb5-2><a href=#cb5-2 aria-hidden=true tabindex=-1></a>https://dl.google.com/android/repository/platform-tools-latest-linux.zip <span class=kw>&amp;&amp;</span> <span class=dt>\\</span></span>\n<span id=cb5-3><a href=#cb5-3 aria-hidden=true tabindex=-1></a><span class=fu>unzip</span> platform-tools.zip <span class=kw>&amp;&amp;</span> <span class=fu>rm</span> platform-tools.zip <span class=kw>&amp;&amp;</span> <span class=bu>cd</span> platform-tools</span></code></pre></div><li><p>If it is successful, you can simply type <code>./adb</code> in\nthe in <em>same</em> terminal emulator window or type\n<code>~/Downloads/platform-tools/adb</code> in any terminal emulator to\naccess ADB.</ol></section></section><section id=subsec:configure-adb-over-tcp class=level3 data-number=3.1.4><h3 data-number=3.1.4><span class=header-section-number>3.1.4</span>\n<a href=#toc:subsec:configure-adb-over-tcp>Configure ADB over\nTCP</a><a href=#subsec:configure-adb-over-tcp class=anchor aria-hidden=true></a></h3><section id=subsubsec:lineage-os class=level4 data-number=3.1.4.1><h4 data-number=3.1.4.1><span class=header-section-number>3.1.4.1</span> Lineage OS 17.1 and\nEarlier<a href=#subsubsec:lineage-os class=anchor aria-hidden=true></a></h4><p>Lineage OS (or its derivatives) users can directly enable ADB over\nTCP using the developer options. To enable that, go to the\n<strong>Developer options</strong>, scroll down until you find\n<strong>ADB over Network</strong>. Now, use the toggle button on the\nright-hand side to enable it and skip to §<a href=#subsubsec:adb-mode-in-app-manager data-reference-type=ref data-reference=subsubsec:adb-mode-in-app-manager>3.1.4.3</a>.<div class=\"amalert warning\"><p><strong><em>Warning.</em></strong><p>You can turn off <strong>ADB over Network</strong> in developer\noptions, but turning off this option will also stop App Manager’s remote\nserver. So, turn it off only when you’re not going to use App Manager in\nADB over TCP mode.</div></section><section id=subsubsec:enable-adb-over-tcp-via-pc-or-mac class=level4 data-number=3.1.4.2><h4 data-number=3.1.4.2><span class=header-section-number>3.1.4.2</span> Enable ADB over TCP via PC\nor Mac<a href=#subsubsec:enable-adb-over-tcp-via-pc-or-mac class=anchor aria-hidden=true></a></h4><p>For other ROMs, you can do this using the command\nprompt/PowerShell/terminal emulator that you’ve opened in the step 3 of\nthe previous section. In this section, I will use <code>adb</code> to\ndenote <code>./adb</code>, <code>adb</code> or any other command that\nyou needed to use based on your platform and software in the previous\nsection.<ol class=incremental><li><p>Connect your device to your PC or Mac using a USB cable. For some\ndevices, it is necessary to turn on <em>File transfer mode (MTP)</em> as\nwell<li><p>To confirm that everything is working as expected, type\n<code>adb devices</code> in your terminal. If your device is connected\nsuccessfully, you will see something like this:<pre><code>List of devices attached\nxxxxxxxx  device</code></pre><div class=\"amalert tip\"><p><strong><em>Notice.</em></strong><p>In some Android phones, an alert prompt will be appeared with a\nmessage <strong>Allow USB Debugging</strong> in which case, check\n<em>Always allow from this computer</em> and click\n<strong>Allow</strong>.</div><li><p>Finally, run the following command to enable ADB over TCP:<div class=sourceCode id=cb7 data-frame=lines data-autogobble><pre class=\"sourceCode bash\"><code class=\"sourceCode bash\"><span id=cb7-1><a href=#cb7-1 aria-hidden=true tabindex=-1></a><span class=ex>adb</span> tcpip 5555</span></code></pre></div></ol><div class=\"amalert danger\"><p><strong><em>Danger.</em></strong><p>You cannot disable developer options or USB debugging after enabling\nADB over TCP.</div></section><section id=subsubsec:adb-mode-in-app-manager class=level4 data-number=3.1.4.3><h4 data-number=3.1.4.3><span class=header-section-number>3.1.4.3</span> Enable ADB mode in App\nManager<a href=#subsubsec:adb-mode-in-app-manager class=anchor aria-hidden=true></a></h4><p>After enabling ADB over TCP, relaunch App Manager. App Manager should\ndetect ADB mode automatically. If it cannot, you can change the mode of\noperation to ADB over TCP in the <a href=#subsec:mode-of-operation>settings page</a>. There, you can also\nverify whether App Manager has correctly detected ADB as indicated by\nthe <em>inferred mode</em>.<div class=\"amalert tip\"><p><strong><em>Notice.</em></strong><p>In some Android devices, the USB cable is needed to be disconnected\nfrom the PC before connecting to App Manager.</div><div class=\"amalert warning\"><p><strong><em>Warning.</em></strong><p>ADB over TCP will be disabled after a reboot. In that case, you have\nto follow §<a href=#subsubsec:enable-adb-over-tcp-via-pc-or-mac data-reference-type=ref data-reference=subsubsec:enable-adb-over-tcp-via-pc-or-mac>3.1.4.2</a>\nagain.</div></section></section></section><section id=sec:wireless-debugging class=level2 data-number=3.2><h2 data-number=3.2><span class=header-section-number>3.2</span> <a href=#toc:sec:wireless-debugging>Wireless Debugging</a><a href=#sec:wireless-debugging class=anchor aria-hidden=true></a></h2><p>If you are running Android 11 or later and capable of connecting to a\nWi-Fi network for, at least, a few moments, Wireless Debugging is the\nrecommended approach as it offers more protection than <a href=#sec:adb-over-tcp>ADB over TCP</a>. It requires two steps:<ol class=incremental><li><p><strong>ADB pairing.</strong> The initial and a bit complex step\nfor a novice user. Fortunately, this step is not required all the\ntime.<li><p><strong>Connecting to ADB.</strong> Needs to be done every time\nyou reboot your phone. App Manager can also automate this step in most\ndevices.</ol><section id=subsec:enable-developer-options-and-usb-debugging class=level3 data-number=3.2.1><h3 data-number=3.2.1><span class=header-section-number>3.2.1</span>\n<a href=#toc:subsec:enable-developer-options-and-usb-debugging>Enable\ndeveloper options and USB Debugging</a><a href=#subsec:enable-developer-options-and-usb-debugging class=anchor aria-hidden=true></a></h3><p>See §<a href=#subsec:enable-developer-options data-reference-type=ref data-reference=subsec:enable-developer-options>3.1.1</a> and §<a href=#subsec:enable-usb-debugging data-reference-type=ref data-reference=subsec:enable-usb-debugging>3.1.2</a>.</section><section id=subsec:enable-wireless-debugging class=level3 data-number=3.2.2><h3 data-number=3.2.2><span class=header-section-number>3.2.2</span>\n<a href=#toc:subsec:enable-wireless-debugging>Enable Wireless\nDebugging</a><a href=#subsec:enable-wireless-debugging class=anchor aria-hidden=true></a></h3><p>In the <strong>Developer options</strong> page, find <strong>Wireless\ndebugging</strong> and click to open it. In the new page, turn on\n<em>Use wireless debugging</em>. Depending on the operating system, you\nmight see a dialog prompt asking you to verify your decision. If that is\nthe case, click <em>Allow</em>.<div class=\"amalert tip\"><p><strong><em>Tip.</em></strong><p>For easy access, you might want to add <strong>Wireless\ndebugging</strong> in the notification tiles section. To do this, find\n<strong>Quick settings developer tiles</strong> in the <strong>Developer\noptions</strong> page and click to open it. In the new window, enable\n<em>Wireless debugging</em>. In case you do not see this setting, you\nmay find a <strong>Wireless debugging</strong> tile in the tile\ncustomization panel.</div></section><section id=subsec:pair-adb-with-app-manager class=level3 data-number=3.2.3><h3 data-number=3.2.3><span class=header-section-number>3.2.3</span>\n<a href=#toc:subsec:pair-adb-with-app-manager>Pair ADB with App\nManager</a><a href=#subsec:pair-adb-with-app-manager class=anchor aria-hidden=true></a></h3><p>In App Manager, navigate to <strong>Settings</strong> > <a href=#subsec:mode-of-operation>Mode of operation</a> and then enable\n<em>Wireless debugging</em>. At this, App Manager will try to establish\na wireless debugging connection automatically which will fail if it has\nnot been paired before. Once it fails, it will ask you to either connect\nor pair ADB. Select <em>pair</em> and a new dialog will appear. It will\nask you to navigate to the <strong>Wireless debugging</strong> page.<div class=\"amalert tip\"><p><strong><em>Note.</em></strong><p>As of v4.0.0, pairing is done using a notification prompt. So, if you\nhave disabled notification for App Manager, you must enable it\nfirst.</div><p>In the <strong>Wireless debugging</strong> page, select <strong>Pair\ndevice with pairing code</strong>. At this, a dialog containing a\npairing code will be displayed. A notification asking for the pairing\ncode will also be visible almost instantly. Insert the pairing code in\nthe input box in the notification and click <em>pair</em>. If the\npairing is successful, App Manager will display notification with the\nmessage “paired”, and the dialog in the <strong>Wireless\ndebugging</strong> page will be dismissed automatically. You will also\nbe able to see App Manager listed as an ADB client in the same page.<div class=\"amalert tip\"><p><strong><em>Notice.</em></strong><p>If you do not use App Manager in ADB mode for a while, App Manager\nmight be removed from the list of clients. In that case, you have to\nrepeat the above procedure.</div></section><section id=subsec:connect-app-manager-to-adb class=level3 data-number=3.2.4><h3 data-number=3.2.4><span class=header-section-number>3.2.4</span>\n<a href=#toc:subsec:connect-app-manager-to-adb>Connect App Manager to\nADB</a><a href=#subsec:connect-app-manager-to-adb class=anchor aria-hidden=true></a></h3><p>App Manager should be able to connect to ADB automatically if the\nmode of operation is set to <em>auto</em>, <em>ADB over TCP</em> or\n<em>Wireless debugging</em>. If this is not the case, select\n<em>Wireless debugging</em> in <strong>Settings</strong> > <a href=#subsec:mode-of-operation>Mode of operation</a>. If App Manager\nfails to detect or connect to ADB, it will ask you to connect or pair\nADB. Select <em>connect</em>.<p>Now, navigate to the <strong>Wireless debugging</strong> page in\nAndroid settings, and note down the port number displayed in the page.\nIn App Manager’s dialog prompt, replace the port number with the one you\nhave noted earlier, and click <em>connect</em>.<p>Once a connection has been established, you can disable\n<strong>Wireless debugging</strong> in Android settings.<div class=\"amalert danger\"><p><strong><em>Caution.</em></strong><p>Never disable <strong>USB Debugging</strong> or any other additional\noptions described in §<a href=#subsec:enable-developer-options-and-usb-debugging data-reference-type=ref data-reference=subsec:enable-developer-options-and-usb-debugging>3.2.1</a>.\nIf you do this, the remote server used by App Manager will be stopped,\nand you may have to start all over again.</div></section></section><section id=sec:backup-restore class=level2 data-number=3.3><h2 data-number=3.3><span class=header-section-number>3.3</span> <a href=#toc:sec:backup-restore>Back up/Restore</a><a href=#sec:backup-restore class=anchor aria-hidden=true></a></h2><p>App Manager has a modern, advanced and easy-to-use backup/restore\nsystem implemented from the scratch. This is probably the only app that\nhas the ability to restore not only the app or its data but also\npermissions and rules that you’ve configured within App Manager. You can\nalso choose to back up an app multiple times (with custom names) or for\nall users.<div class=seealso><p><em>See also:</em><ul class=incremental><li><p><a href=#subsec:1-click-back-up>1-Click Ops: Back\nup</a><li><p><a href=#subsec:1-click-restore>1-Click Ops:\nRestore</a></ul></div><section id=subsec:backup-location class=level3 data-number=3.3.1><h3 data-number=3.3.1><span class=header-section-number>3.3.1</span>\n<a href=#toc:subsec:backup-location>Location</a><a href=#subsec:backup-location class=anchor aria-hidden=true></a></h3><p>Back up/restore is a part of <a href=#subsec:batch-operations>batch\noperations</a>. It is also located inside the <a href=#subsubsec:app-info-options-menu>options menu</a> in the <a href=#subsec:app-info-tab>App Info tab</a>. Clicking on\n<strong>Backup/Restore</strong> opens the <strong>Backup\nOptions</strong>. Backups are located at\n<code>/storage/emulated/0/AppManager</code> by default. You can\nconfigure custom backup location in the <a href=#subsubsec:backup-volume>settings page</a> in which case the\nbackups will be located at the <code>AppManager</code> folder in the\nselected volume.<div class=\"amalert tip\"><p><strong><em>Note.</em></strong><p>If one or more selected apps do not have any backup, the\n<strong>Restore</strong> and <strong>Delete Backup</strong> options will\nnot be displayed.</div></section><section id=subsec:backup-restore-backup-options class=level3 data-number=3.3.2><h3 data-number=3.3.2><span class=header-section-number>3.3.2</span>\n<a href=#toc:subsec:backup-restore-backup-options>Backup Options</a><a href=#subsec:backup-restore-backup-options class=anchor aria-hidden=true></a></h3><p>Backup options (internally known as backup flags) let you customise\nthe backups on the fly. However, the customisations will not be\nremembered for the future backups. If you want to customise this dialog,\nuse <a href=#subsubsec:settings-backup-options>Backup Options</a> in\nthe <a href=#sec:settings-page>Settings page</a>.<p>A complete description of the backup options is given below:<ul class=incremental><li><p><strong>APK files.</strong> Whether to back up the APK files.\nThis includes the <em>base APK</em> file along with the\n<code>split APK</code> files if they exist.<li><p><strong>Internal data.</strong> Whether to back up the internal\ndata directories. These directories are located at\n<code>/data/user/&lt;user_id></code> and (for Android N or later)\n<code>/data/user_de/&lt;user_id></code>.<li><p><strong>External data.</strong> Whether to back up data\ndirectories located in the internal memory as well as SD Card (if\nexists). External data directories often contain non-essential app data\nor media files (instead of using the dedicated media folder) and may\nincrease the backup size. However, it might be essential for some apps.\nAlthough it isn’t checked by default (as it might dramatically increase\nthe size of the backups), you may have to check it in order to ensure a\nsmooth restore of your backups.<div class=\"amalert warning\"><p><strong><em>Caution.</em></strong><p>Internal data folders should always be backed up if you are going to\nback up the external data folders. However, it could be useful to back\nup only the external folders if the app in question downloads a lot of\nassets from the Internet.</div><li><p><strong>OBB and media.</strong> Whether to back up or restore the\nOBB and the media directories located in the external storage or the SD\nCard. This is useful for games and the graphical software which actually\nuse these folders.<li><p><strong>Cache.</strong> Android apps have multiple cache\ndirectories located at every data directories (both internal and\nexternal). There are two types of cache: <strong>cache</strong> and\n<strong>code cache</strong>. Disabling this option excludes both cache\ndirectories from all the data directories. It is generally advised to\nexclude cache directories since most apps do not clear the cache\nregularly and usually handled by the OS itself. Apps such as Telegram\nmay use a very large cache (depending on the storage space) which may\ndramatically increase the backup size. When it is disabled, AM also\nignores the <strong>no_backup</strong> directories.<li><p><strong>Extras.</strong> Backup/restore app permissions, net\npolicy, battery optimization, SSAID, etc., enabled by default. Note\nthat, blocking rules are applied <em>after</em> applying the extras. So,\nif an item is present in both places, it will be overwritten (i.e., the\none from the blocking rules will be used).<li><p><strong>Rules.</strong> This option lets you back up blocking\nrules configured within App Manager. This might come in handy if you\nhave customised permissions or block some components using App Manager\nas they will also be backed up or restored when you enable this\noption.<li><p><strong>Backup Multiple.</strong> Whether this is a multiple\nbackup. By default, backups are saved using their user ID. Enabling this\noption allows you to create additional backups. These backups use the\ncurrent date-time as the default backup name, but you can also specify\ncustom backup name using the input field displayed when you click on the\n<strong>Backup</strong> button.<li><p><strong>Custom users.</strong> Backup or restore for the selected\nusers instead of only the current user. This option is only displayed if\nthe system has more than one user.<li><p><strong>Skip signature checks.</strong> When taking a backup,\nchecksum of every file (as well as the signing certificate(s) of the\nbase APK file) is generated and stored in the <code>checksums.txt</code>\nfile. When you restore the backup, the checksums are generated again and\nare matched with the checksums stored in the said file. Enabling this\noption will disable the signature checks. This option is applied only\nwhen you restore a backup. During backup, the checksums are generated\nregardless of this option.<div class=\"amalert warning\"><p><strong><em>Caution.</em></strong><p>You should always disable this option to ensure that your backups are\nnot modified by any third-party applications. However, this would only\nwork if you enabled encryption.</div></ul><div class=seealso-inline><p><em>See also: <span><a href=#subsubsec:settings-encryption>Settings:\nEncryption</a></span></em></div></section><section id=subsec:backup-restore-backup class=level3 data-number=3.3.3><h3 data-number=3.3.3><span class=header-section-number>3.3.3</span>\n<a href=#toc:subsec:backup-restore-backup>Backup</a><a href=#subsec:backup-restore-backup class=anchor aria-hidden=true></a></h3><p>Backup respects all the backup options except <strong>Skip signature\nchecks</strong>. If base backups (i.e., backups that don’t have the\n<strong>Backup Multiple</strong> option) already exist, you will get a\nwarning as the backups will be overwritten. If <strong>Backup\nMultiple</strong> is set, you have an option to input the backup name,\nor you can leave it blank to use the current date-time.</section><section id=subsec:backup-restore-restore class=level3 data-number=3.3.4><h3 data-number=3.3.4><span class=header-section-number>3.3.4</span>\n<a href=#toc:subsec:backup-restore-restore>Restore</a><a href=#subsec:backup-restore-restore class=anchor aria-hidden=true></a></h3><p>Restore respects all the backup options and will fail if <strong>APK\nfiles</strong> option is set, but the backup doesn’t contain such\nbackups or in other cases, if the app isn’t installed. When restoring\nbackups for multiple packages, you can only restore the base backups\n(see <a href=#subsec:backup-restore-backup>backup</a> section for an\nexplanation). However, when restoring backups for a single package, you\nhave the option to select which backup to restore. If <strong>All\nusers</strong> option is set, AM will restore the selected backup for\nall users in the latter case but in the former case, it will restore\nbase backups for the respective users.<div class=\"amalert tip\"><p><strong><em>Notice.</em></strong><p>Apps that use storage access framework (SAF), SSAID or Android\nKeyStore works properly only after an immediate restart.</div></section><section id=subsec:backup-restore-delete-backup class=level3 data-number=3.3.5><h3 data-number=3.3.5><span class=header-section-number>3.3.5</span>\n<a href=#toc:subsec:backup-restore-delete-backup>Delete Backup</a><a href=#subsec:backup-restore-delete-backup class=anchor aria-hidden=true></a></h3><p>Delete backup only respects <strong>All users</strong> option and\nwhen it is selected, only the base backups for all users will be deleted\nwith a prompt. When deleting backups for a single package, another\ndialog will be displayed where you can select the backups to delete.</section></section><section id=sec:automating-tasks class=level2 data-number=3.4><h2 data-number=3.4><span class=header-section-number>3.4</span> <a href=#toc:sec:automating-tasks>Automating Tasks</a><a href=#sec:automating-tasks class=anchor aria-hidden=true></a></h2><p>It is possible to trigger profiles configured inside App Manager via\nthird-party applications such as <strong>Automation</strong> or\n<strong>Tasker</strong>. Traditionally, <code>Intent</code>s are used to\ntrigger such operations.<section id=subsec:generating-authorization-key class=level3 data-number=3.4.1><h3 data-number=3.4.1><span class=header-section-number>3.4.1</span>\n<a href=#toc:subsec:generating-authorization-key>Generating\nauthorization key</a><a href=#subsec:generating-authorization-key class=anchor aria-hidden=true></a></h3><p>In order to ensure proper security, an authorization key is required.\nTo generate a authorization key, go to <strong>Settings</strong> page\nand then <strong>Privacy</strong> > <strong>Authorization\nManager</strong>. If an authorization key has not been generated, it\nwill be generated automatically. The key can be regenerated as\nrequired.<div class=\"amalert danger\"><p><strong><em>Caution.</em></strong><p>Regenerating the authorization key can have some side effects such as\ninvalidation of all the previously configured Intents.</div></section><section id=subsec:at:general-configuration class=level3 data-number=3.4.2><h3 data-number=3.4.2><span class=header-section-number>3.4.2</span>\n<a href=#toc:subsec:at:general-configuration>Configuring tasks</a><a href=#subsec:at:general-configuration class=anchor aria-hidden=true></a></h3><p>The activity\n<code>io.github.muntashirakon.AppManager.crypto.auth.AuthFeatureDemultiplexer</code>\nis responsible for handling all the automations. Sending an intent to\nthe activity lets App Manager perform the designated operation by\nredirecting the <code>Intent</code> to the designated activity or\nservice.<section id=required-extras class=level4 data-number=3.4.2.1><h4 data-number=3.4.2.1><span class=header-section-number>3.4.2.1</span> Required extras<a href=#required-extras class=anchor aria-hidden=true></a></h4><p>It has two primary extras required in all conditions. The key names,\ndata types are all follows:<ol class=incremental><li><p><strong><code>auth</code>.</strong> (String value) The\nauthorization key as described in the earlier section.<li><p><strong><code>feature</code>.</strong> (String value) Name of the\nfeature. Supported features are described in the next section.</ol></section></section><section id=subsec:at:features class=level3 data-number=3.4.3><h3 data-number=3.4.3><span class=header-section-number>3.4.3</span>\n<a href=#toc:subsec:at:features>Features</a><a href=#subsec:at:features class=anchor aria-hidden=true></a></h3><p>App Manager current support a single feature, namely\n<code>profile</code>.</section><section id=subsec:triggering-a-profile class=level3 data-number=3.4.4><h3 data-number=3.4.4><span class=header-section-number>3.4.4</span>\n<a href=#toc:subsec:triggering-a-profile>Triggering a profile</a><a href=#subsec:triggering-a-profile class=anchor aria-hidden=true></a></h3><p>In order to trigger a profile, <code>feature</code> must have the\nvalue <code>profile</code>. In addition, the following extras can be\nincluded:<ol class=incremental><li><p><strong><code>prof</code>.</strong> (String value – required) The\nname of the profile as displayed in the <a href=#sec:profiles-page>Profiles page</a>.<li><p><strong><code>state</code>.</strong> (String value – optional)\nState of the profile – currently <code>on</code> or <code>off</code> –\nas specified in the documentation. If this extra is not set, App Manager\nwill display a prompt where a state must be selected. Therefore, for\ncomplete automation, this option should be set.</ol></section></section><section id=sec:net-policy class=level2 data-number=3.5><h2 data-number=3.5><span class=header-section-number>3.5</span> <a href=#toc:sec:net-policy>Net Policy</a><a href=#sec:net-policy class=anchor aria-hidden=true></a></h2><p>Short for <strong>Network policy</strong> or network policies. It is\nusually located in the Android settings under <strong>Mobile data &\nWifi</strong> section in the app info page of an app. Not all policies\nare guaranteed to be included in this page (e.g. Samsung), and not all\nsettings are well-understood due to lack of documentation. App Manager\ncan display all the net policies declared in the <a href=https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/net/NetworkPolicyManager.java>NetworkPolicyManager</a>.\nPolicies unknown to App Manager will have a <em>Unknown</em> prefix\nalong with the policy constant name and number in the hexadecimal\nformat. Unknown policies should be reported to App Manager for\ninclusion.<p>Net policy allows a user to configure certain networking behaviour of\nan app without modifying the ip tables directly and/or running a\nfirewall app. However, the features it offers largely depend on Android\nversion and ROM. A list of known net policies are listed below:<ol class=incremental><li><p><strong>None</strong> or\n<strong><code>POLICY_NONE</code></strong>: (AOSP) No specific network\npolicy is set. System can still assign rules depending on the nature of\nthe app.<li><p><strong>Reject background data on metered networks</strong> or\n<strong><code>POLICY_REJECT_METERED_BACKGROUND</code></strong>: (AOSP)\nReject network usage on metered networks when the application is in\nbackground.<li><p><strong>Allow background data on metered networks even when Data\nSaver is on</strong> or\n<strong><code>POLICY_ALLOW_METERED_BACKGROUND</code></strong>: (AOSP)\nAllow metered network use in the background even when data saving mode\nis enabled.<li><p><strong>Reject cellular data</strong> or\n<strong><code>POLICY_REJECT_CELLULAR</code></strong> (Android 11+) or\n<strong><code>POLICY_REJECT_ON_DATA</code></strong> (up to Android 10):\n(Lineage OS) Reject mobile/cellular data. Signals network unavailable to\nthe configured app as if the mobile data is inactive.<li><p><strong>Reject VPN data</strong> or\n<strong><code>POLICY_REJECT_VPN</code></strong> (Android 11+) or\n<strong><code>POLICY_REJECT_ON_VPN</code></strong> (up to Android 10):\n(Lineage OS) Reject VPN data. Signals network unavailable to the\nconfigured app as if the VPN is inactive.<li><p><strong>Reject Wi-Fi data</strong> or\n<strong><code>POLICY_REJECT_WIFI</code></strong> (Android 11+) or\n<strong><code>POLICY_REJECT_ON_WLAN</code></strong> (up to Android 10):\n(Lineage OS) Reject Wi-Fi data. Signals network unavailable to the\nconfigured app as if the device is not connected to a Wi-Fi\nnetwork.<li><p><strong>Disable network access</strong> or\n<strong><code>POLICY_REJECT_ALL</code></strong> (Android 11+) or\n<strong><code>POLICY_NETWORK_ISOLATED</code></strong> (up to Android\n10): (Lineage OS) Reject network access in all circumstances. This is\nnot the same as enforcing the other three policies above, and is the\nrecommended policy for dodgy apps. If this policy is enforced, there is\nno need to enforce the other policies.<li><p><strong><code>POLICY_ALLOW_METERED_IN_ROAMING</code></strong>:\n(Samsung) Possibly allow metered network use during roaming. Exact\nmeaning is currently unknown.<li><p><strong><code>POLICY_ALLOW_WHITELIST_IN_ROAMING</code></strong>:\n(Samsung) Possibly allow network use during roaming. Exact meaning is\ncurrently unknown.<li><p><strong>Reject data on metered networks</strong> or\n<strong><code>POLICY_REJECT_METERED</code></strong>: (Motorola) Reject\nnetwork usage if it is a metered network.<li><p><strong>Reject background data</strong> or\n<strong><code>POLICY_REJECT_BACKGROUND</code></strong>: (Motorola)\nReject network usage in the background.<li><p><strong>Disable network access</strong> or\n<strong><code>POLICY_REJECT_ALL</code></strong>: (Motorola) Reject\nnetwork access altogether. Like Lineage OS, it blocks internet\nconnections via iptables. But whether it signals the unavailability of\nnetwork to the configured app is not known.</ol><div class=\"amalert tip\"><p><strong><em>Note.</em></strong><p>Corresponding Lineage OS patches are as follows:<ol class=incremental><li><p><a href=https://github.com/LineageOS/android_frameworks_base/commit/a04932bafbbf7d99efd18276152cc2c9c9b2073e>fw/b:\nSquash of app fw restriction commits</a><li><p><a href=https://github.com/LineageOS/android_frameworks_base/commit/02c8c82854348f52afe2199f310f44b5f578b5b8>fw/b:\nAdd support for per app network isolation</a></ol></div></section></section><section id=ch:faq class=level1 data-number=4><h1 data-number=4><span class=header-section-number>4</span> <a href=#toc:ch:faq>Frequently Asked Questions</a><a href=#ch:faq class=anchor aria-hidden=true></a></h1><section id=sec:faq:app-components class=level2 data-number=4.1><h2 data-number=4.1><span class=header-section-number>4.1</span> <a href=#toc:sec:faq:app-components>App Components</a><a href=#sec:faq:app-components class=anchor aria-hidden=true></a></h2><section id=subsec:faq:what-are-app-components class=level3 data-number=4.1.1><h3 data-number=4.1.1><span class=header-section-number>4.1.1</span>\n<a href=#toc:subsec:faq:what-are-app-components>What are the\napplication components?</a><a href=#subsec:faq:what-are-app-components class=anchor aria-hidden=true></a></h3><p>Activities, services, broadcast receivers (or only receivers) and\ncontent providers (or only providers) are jointly called application\ncomponents. More technically, they all inherit the <a href=https://developer.android.com/reference/android/content/pm/ComponentInfo>ComponentInfo</a>\nclass and can be launched via Intent.</section><section id=subsec:faq:how-components-blocked class=level3 data-number=4.1.2><h3 data-number=4.1.2><span class=header-section-number>4.1.2</span>\n<a href=#toc:subsec:faq:how-components-blocked>How are the tracker and\nother components blocked in App Manager? What are its limitations?</a><a href=#subsec:faq:how-components-blocked class=anchor aria-hidden=true></a></h3><p>App Manager typically blocks application components (or tracker\ncomponents) using a method called <a href=https://carteryagemann.com/pages/android-intent-firewall.html>Intent\nFirewall (IFW)</a>, it is superior to other methods such as <em>pm</em>\n(PackageManager), <a href=https://github.com/RikkaApps/Shizuku>Shizuku</a> or any other\nmethod that uses the package manager to enable or disable the\ncomponents. If a component is disabled by the latter methods, the\napplication itself can detect that the component is being blocked and\ncan re-enable it as it has full access to its own components. (Many\ndeceptive applications actually do this in order to keep the tracker\ncomponents unblocked.) On the other hand, IFW is a true firewall and the\napplication cannot detect if its components are being blocked. App\nManager uses the term <em>block</em> rather than <em>disable</em> for\nthis reason.<p>Even IFW has some limitations which are primarily applicable for the\nsystem applications:<ul class=incremental><li><p>The application in question is whitelisted by the system i.e. the\nsystem cannot function properly without these applications and may cause\nrandom crashes. These applications include but not limited to Android\nSystem, System UI, Phone Services. They will continue to work even if\nthey are disabled or blocked.<li><p>Another system application or system process has activated a\nspecific component of the application in question via interprocess\ncommunication (IPC). In this case, the component will be activated\nregardless of blocking status or even if the entire application is\ndisabled. If there is such a system application that is not needed, the\nonly way to prevent it from running is by getting rid of it.</ul></section><section id=subsec:faq:components-blocked-by-others class=level3 data-number=4.1.3><h3 data-number=4.1.3><span class=header-section-number>4.1.3</span>\n<a href=#toc:subsec:faq:components-blocked-by-others>Does app\ncomponents blocked by other tools retained in App Manager?</a><a href=#subsec:faq:components-blocked-by-others class=anchor aria-hidden=true></a></h3><p><strong>No.</strong> But the application components blocked by the\nsystem or any other tools are displayed in the <a href=#subsec:component-tabs>component tabs</a>. These rules can be\nimported from <a href=#par:import-existing-rules>Settings</a>.\nHowever, it is not possible for App Manager to distinguish the\ncomponents blocked by the third-party tools and components blocked by\nthe system. Therefore, the applications listed in the import page should\nbe selected with care.</section><section id=subsec:faq:components-reblocked-in-am class=level3 data-number=4.1.4><h3 data-number=4.1.4><span class=header-section-number>4.1.4</span>\n<a href=#toc:subsec:faq:components-reblocked-in-am>What happens to the\ncomponents blocked by App Manager which were previously blocked by other\ntools?</a><a href=#subsec:faq:components-reblocked-in-am class=anchor aria-hidden=true></a></h3><p><em>App Manager blocks the components again</em> if requested. In\ncase of unblocking, they will be reverted to the default state as\nspecified in the manifest of the application. But if the components were\nblocked by <a href=https://www.myandroidtools.com>MyAndroidTools\n(MAT)</a> with IFW method, they will not be unblocked by App Manager as\nit uses a different format. To fix this issue, the rules have to be\nimported from <a href=#par:import-existing-rules>Settings</a> at\nfirst, in which case MAT’s configurations will be permanently\nremoved.</section><section id=subsec:faq:what-is-instant-component-blocking class=level3 data-number=4.1.5><h3 data-number=4.1.5><span class=header-section-number>4.1.5</span>\n<a href=#toc:subsec:faq:what-is-instant-component-blocking>What is\ninstant component blocking?</a><a href=#subsec:faq:what-is-instant-component-blocking class=anchor aria-hidden=true></a></h3><p>When you block a component in the <a href=#sec:app-details-page>App\nDetails page</a>, the blocking is not applied by default. It is only\napplied when you apply blocking using the <em>Apply rules</em> option in\nthe top-right menu. If you enable <a href=#subsubsec:instant-component-blocking>instant component\nblocking</a>, blocking will be applied as soon as you block a component.\nIf you choose to block tracker components, however, blocking is applied\nautomatically regardless of this setting. You can also remove blocking\nfor an application by simply clicking on <em>Remove rules</em> in the\nsame menu in the <strong>App Details page</strong>. Since the default\nbehaviour gives you more control over applications, it is better to keep\n<em>instant component blocking</em> option disabled.</section><section id=subsec:tracker-classes-versus-tracker-components class=level3 data-number=4.1.6><h3 data-number=4.1.6><span class=header-section-number>4.1.6</span>\n<a href=#toc:subsec:tracker-classes-versus-tracker-components>Tracker\nclasses versus tracker components</a><a href=#subsec:tracker-classes-versus-tracker-components class=anchor aria-hidden=true></a></h3><p>All application components are classes but not all classes are\ncomponents. In fact, only a few of the classes are components. That\nbeing said, <a href=#sec:scanner-page>scanner page</a> displays a list\nof trackers along with the number of classes, not just the components.\nIn all other pages, trackers and tracker components are used\nsynonymously to denote tracker components, i.e. blocking tracker means\nblocking tracker components, not tracker classes.<div class=\"amalert tip\"><p><strong><em>Info.</em></strong><p>Tracker classes that are not components cannot be blocked. They can\nonly be removed by editing the application itself.</div></section></section><section id=sec:faq:adb-over-tcp class=level2 data-number=4.2><h2 data-number=4.2><span class=header-section-number>4.2</span> <a href=#toc:sec:faq:adb-over-tcp>ADB over TCP</a><a href=#sec:faq:adb-over-tcp class=anchor aria-hidden=true></a></h2><section id=subsec:faq:enable-adb-on-every-restart class=level3 data-number=4.2.1><h3 data-number=4.2.1><span class=header-section-number>4.2.1</span>\n<a href=#toc:subsec:faq:enable-adb-on-every-restart>Do I have to\nenable ADB over TCP everytime I restart?</a><a href=#subsec:faq:enable-adb-on-every-restart class=anchor aria-hidden=true></a></h3><p>Unfortunately, yes. This is because the ADB daemon, the process\nresponsible for ADB connection, is also restarted after a reboot, and it\ndoes not re-enable ADB over TCP.</section><section id=subsec:faq:usb-debugging class=level3 data-number=4.2.2><h3 data-number=4.2.2><span class=header-section-number>4.2.2</span>\n<a href=#toc:subsec:faq:usb-debugging>Cannot enable USB debugging.\nWhat to do?</a><a href=#subsec:faq:usb-debugging class=anchor aria-hidden=true></a></h3><p>See §<a href=#subsec:enable-usb-debugging data-reference-type=ref data-reference=subsec:enable-usb-debugging>3.1.2</a> in Chapter <a href=#ch:guides data-reference-type=ref data-reference=ch:guides>3</a>.</section><section id=subsec:faq:block-components-using-adb class=level3 data-number=4.2.3><h3 data-number=4.2.3><span class=header-section-number>4.2.3</span>\n<a href=#toc:subsec:faq:block-components-using-adb>Can I block tracker\nor any other application components using ADB over TCP?</a><a href=#subsec:faq:block-components-using-adb class=anchor aria-hidden=true></a></h3><p>ADB has limited number of <a href=https://github.com/aosp-mirror/platform_frameworks_base/blob/master/packages/Shell/AndroidManifest.xml>permissions</a>\nand controlling application components is not one of them. However, the\ncomponents of a <em>test-only</em> app can be controlled via ADB. If App\nManager detects such an application, it enables the blocking options\nautomatically.</section><section id=subsec:faq:adb-features class=level3 data-number=4.2.4><h3 data-number=4.2.4><span class=header-section-number>4.2.4</span>\n<a href=#toc:subsec:faq:adb-features>Which features can be used in ADB\nmode?</a><a href=#subsec:faq:adb-features class=anchor aria-hidden=true></a></h3><p>Supported features are enabled automatically in the ADB mode.\nSupported features include disabling, force-stopping, clearing\napplication data, granting or revoking app ops and permissions, and so\non. It is also possible to install or uninstall applications without any\nprompt from the system.</section></section><section id=sec:faq:miscellanea class=level2 data-number=4.3><h2 data-number=4.3><span class=header-section-number>4.3</span> <a href=#toc:sec:faq:miscellanea>Miscellanea</a><a href=#sec:faq:miscellanea class=anchor aria-hidden=true></a></h2><section id=subsec:faq:no-root-no-harms class=level3 data-number=4.3.1><h3 data-number=4.3.1><span class=header-section-number>4.3.1</span>\n<a href=#toc:subsec:faq:no-root-no-harms>I don’t use root/ADB. Am I\ncompletely safe from any harms?</a><a href=#subsec:faq:no-root-no-harms class=anchor aria-hidden=true></a></h3><p>Yes. AM cannot modify any system settings without root or ADB.</section><section id=subsec:faq:how-trackers-libs-updated class=level3 data-number=4.3.2><h3 data-number=4.3.2><span class=header-section-number>4.3.2</span>\n<a href=#toc:subsec:faq:how-trackers-libs-updated>How are the trackers\nand libraries are updated?</a><a href=#subsec:faq:how-trackers-libs-updated class=anchor aria-hidden=true></a></h3><p>Trackers and libraries are updated manually before making a new\nrelease.</section><section id=subsec:faq:apks-deleted-after-installed class=level3 data-number=4.3.3><h3 data-number=4.3.3><span class=header-section-number>4.3.3</span>\n<a href=#toc:subsec:faq:apks-deleted-after-installed>Are APKs deleted\nafter installed?</a><a href=#subsec:faq:apks-deleted-after-installed class=anchor aria-hidden=true></a></h3><p>No, APKs aren’t deleted by App Manager after they are installed.</section><section id=subsec:faq:shizuku-support class=level3 data-number=4.3.4><h3 data-number=4.3.4><span class=header-section-number>4.3.4</span>\n<a href=#toc:subsec:faq:shizuku-support>Any plans for Shizuku?</a><a href=#subsec:faq:shizuku-support class=anchor aria-hidden=true></a></h3><p>App Manager’s use of hidden API and privileged code execution is now\nmuch more complex and cannot be integrated with other third party apps\nsuch as <a href=https://shizuku.rikka.app>Shizuku</a>. Here are some\nreasons for not considering Shizuku (which now has Apache 2.0 license)\nfor App Manager:<ol class=incremental><li><p>Shizuku was initially non-free which led me to use a similar\napproach for App Manager to support both root and ADB<li><p>App Manager already supports both ADB and root which in some\ncases is more capable than Shizuku<li><p>Relying on a third-party app for the major functionalities is not\na good design choice<li><p>Integration of Shizuku will increase the complexity of App\nManager.</ol></section><section id=subsec:faq:what-are-bloatware class=level3 data-number=4.3.5><h3 data-number=4.3.5><span class=header-section-number>4.3.5</span>\n<a href=#toc:subsec:faq:what-are-bloatware>What are bloatware and how\nto remove them?</a><a href=#subsec:faq:what-are-bloatware class=anchor aria-hidden=true></a></h3><p>Bloatware are the unnecessary pre-installed apps, usually system\napps. Some of the apps are often used to track users and collect user\ndata which they might sell for profits. Many system apps do not need to\nrequest any permission to access device info, contacts and messaging\ndata, and other usage info, such as your phone usage habits and\neverything you store on your shared storage(s).<p>The bloatware may also include Google apps, Meta apps, and Twitter/X\nwhich can also track users and/or collect user data without consent. You\ncan disable a few permissions from Android settings but be aware that\nAndroid settings hides many permissions a security researcher would call\npotentially <em>dangerous</em> (e.g., internet, sensor).<p>Were the bloatware user apps, they could be easily uninstalled either\nfrom Android settings or AM. Uninstalling system apps is not possible\nwithout privileged permission, but even then, it cannot <em>remove</em>\nthe system apps completely as they are located in the <em>system</em>\npartition which is a read-only partition. If you have root, you can\nremount this partition to manually <em>purge</em> these apps but this\nwill break Over the Air (OTA) updates since data in the system partition\nhas been modified. There are two kind of updates, delta (small-size,\nconsisting of only the changes between two versions) and full updates.\nYou may still be able to apply full updates, but the bloatware will be\ninstalled again, and consequently, you have to delete them all over\nagain.<p>Another solution is to disable these apps either from Android\nsettings or AM, but certain services can still run in the background as\nthey can be started by other system apps using Inter-process\nCommunication (IPC). One possible solution is to disable all bloatware\nuntil the service has finally stopped (after a restart). However, due to\nheavy modifications of the Android frameworks by the vendors, removing\nor disabling certain bloatware may cause the System UI to crash or even\ncause bootloop. From v4.0.0, AM has a new feature called\n<strong>Debloater</strong> which can be used as a starting point to\nmonitor, disable, and remove the bloatware from a proprietary Android\noperating system.<div class=\"amalert warning\"><p><strong><em>Note.</em></strong><p>In most cases, you cannot completely debloat your device. Therefore,\nit is recommended that you use a custom ROM free from bloatware, such as\nGraphene OS, Lineage OS or their derivatives.</div></section></section></section><section id=ch:specifications class=level1 data-number=5><h1 data-number=5><span class=header-section-number>5</span> <a href=#toc:ch:specifications>Specifications</a><a href=#ch:specifications class=anchor aria-hidden=true></a></h1><section id=sec:rules-specification class=level2 data-number=5.1><h2 data-number=5.1><span class=header-section-number>5.1</span> <a href=#toc:sec:rules-specification>Rules Specification</a><a href=#sec:rules-specification class=anchor aria-hidden=true></a></h2><section id=background class=level3 data-number=5.1.1><h3 data-number=5.1.1><span class=header-section-number>5.1.1</span>\n<a href=#toc:background>Background</a><a href=#background class=anchor aria-hidden=true></a></h3><p>AM currently supports blocking activities, broadcast receivers,\ncontent providers, services, app ops and permissions, and in future I\nmay add more blocking options. In order to add more portability, it is\nnecessary to import/export all these data.<p>Maintaining a database should be the best choice when it comes to\nstoring data. For now, several <code>tsv</code> files with each file\nhaving the name of the package and a <code>.tsv</code> extension. The\nfile/database will be queried/processed by the\n<code>RulesStorageManager</code> class. Due to this abstraction, it\nshould be easier to switch to database or encrypted database systems in\nfuture without changing the design of the entire project. Currently, All\nconfiguration files are stored at\n<code>/data/data/io.github.muntashirakon.AppManager/Files/conf</code>.</section><section id=rules-file-format class=level3 data-number=5.1.2><h3 data-number=5.1.2><span class=header-section-number>5.1.2</span>\n<a href=#toc:rules-file-format>Rules File Format</a><a href=#rules-file-format class=anchor aria-hidden=true></a></h3><section id=internal class=level4 data-number=5.1.2.1><h4 data-number=5.1.2.1><span class=header-section-number>5.1.2.1</span> Internal<a href=#internal class=anchor aria-hidden=true></a></h4><p>The format below is used internally within App Manager and is <em>not\ncompatible with the external format.</em><pre><code>    &lt;name&gt; &lt;type&gt; &lt;mode&gt;|&lt;component_status&gt;|&lt;is_granted&gt;</code></pre><p>Here:<ul class=incremental><li><p><code>&lt;name></code> – Component/permission/app op name (in\ncase of app op, it could be string or integer)<li><p><code>&lt;type></code> – One of the <code>ACTIVITY</code>,\n<code>RECEIVER</code>, <code>PROVIDER</code>, <code>SERVICE</code>,\n<code>APP_OP</code>, <code>PERMISSION</code><li><p><code>&lt;mode></code> – (For app ops) The associated <a href=#subsec:mode-constants>mode constant</a><li><p><code>&lt;component_status></code> – (For components)\nComponent status<ul class=incremental><li><p><code>true</code> – Component has been applied (<code>true</code>\nvalue is kept for compatibility)<li><p><code>false</code> – Component hasn’t been applied yet, but will\nbe applied in future (<code>false</code> value is kept for\ncompatibility)<li><p><code>unblocked</code> – Component is scheduled to be\nunblocked</ul><li><p><code>&lt;is_granted></code> – (For permissions) Whether the\npermission is granted or revoked</ul></section><section id=external class=level4 data-number=5.1.2.2><h4 data-number=5.1.2.2><span class=header-section-number>5.1.2.2</span> External<a href=#external class=anchor aria-hidden=true></a></h4><p>External format is used for importing or exporting rules in App\nManager.<pre><code>    &lt;package_name&gt; &lt;component_name&gt; &lt;type&gt; &lt;mode&gt;|&lt;component_status&gt;|&lt;is_granted&gt;</code></pre><p>This the format is essentially the same as above except for the first\nitem which is the name of the package.<div class=\"amalert danger\"><p><strong><em>Caution.</em></strong><p>The exported rules have a different format than the internal one and\nshould not be copied directly to the <strong>conf</strong> folder.</div></section></section></section></section><section id=ch:changelogs class=level1 data-number=6><h1 data-number=6><span class=header-section-number>6</span> <a href=#toc:ch:changelogs>Changelogs</a><a href=#ch:changelogs class=anchor aria-hidden=true></a></h1><section id=sec:v4.0.5-(445) class=level2 data-number=6.1><h2 data-number=6.1><span class=header-section-number>6.1</span> <a href=#toc:sec:v4.0.5-(445)>v4.0.5 (445)</a><a href=#sec:v4.0.5-(445) class=anchor aria-hidden=true></a></h2><ul class=incremental><li><p>Added option to allow installing the existing applications in the\ninstaller page<li><p>Display unsafe bloatware info<li><p>Display vector icon on the splash screen in Android 7.1 and\nearlier<li><p>Enabled “Clear data from uninstalled apps” to no-root users in\n1-click ops page<li><p>Enabled predictive back in Android 14 onwards<li><p>Improved accessibility by updating the content description of the\naction items<li><p>In app info tab, open “Open by default” setting in the “Open\nlinks” dialog<li><p>In debloater page, sort by app label (or app name) rather than\npackage name<li><p>Fixed freezing an app with “Remember for this app” turned\non<li><p>Fixed selecting texts in the list items due to framework\nbugs<li><p>Fixed setting app ops in custom ROMs with MIUI properties\ninjected<li><p>Fixed updating profile modification status when an application is\ndeleted from the list<li><p>Handled common colors and cursor movements in terminal\noutput.</ul></section><section id=sec:v4.0.4-(444) class=level2 data-number=6.2><h2 data-number=6.2><span class=header-section-number>6.2</span> <a href=#toc:sec:v4.0.4-(444)>v4.0.4 (444)</a><a href=#sec:v4.0.4-(444) class=anchor aria-hidden=true></a></h2><ul class=incremental><li><p>Optimized searching and filtering in the main page<li><p>Adopted sentence-case for the titles<li><p>Use the configured state to execute a profile for the simple\nshortcuts<li><p>Prevented crashing while searching throughout the\napplication<li><p>Fixed integer overflow issue in the tar compression.</ul></section><section id=sec:v4.0.3-(443) class=level2 data-number=6.3><h2 data-number=6.3><span class=header-section-number>6.3</span> <a href=#toc:sec:v4.0.3-(443)>v4.0.3 (443)</a><a href=#sec:v4.0.3-(443) class=anchor aria-hidden=true></a></h2><ul class=incremental><li><p>Updated translations<li><p>Improved handling the list items throughout App Manager<li><p>Fixed a regression error in file manager<li><p>Fixed spinners in the App Usage and the System Config\npages.</ul></section><section id=sec:v4.0.2-(442) class=level2 data-number=6.4><h2 data-number=6.4><span class=header-section-number>6.4</span> <a href=#toc:sec:v4.0.2-(442)>v4.0.2 (442)</a><a href=#sec:v4.0.2-(442) class=anchor aria-hidden=true></a></h2><ul class=incremental><li><p>Updated bloatware<li><p>Fixed fetching applications in multi-user environment in no-root\nmode<li><p>Fixed opening <code>app-manager</code> URLs from the web\nbrowsers<li><p>Fixed updating SSAID<li><p>Prevented a crash in Android &lt; 9.0 that occurs due to invalid\napp ops.</ul></section><section id=sec:v4.0.1-(441) class=level2 data-number=6.5><h2 data-number=6.5><span class=header-section-number>6.5</span> <a href=#toc:sec:v4.0.1-(441)>v4.0.1 (441)</a><a href=#sec:v4.0.1-(441) class=anchor aria-hidden=true></a></h2><section id=overlay-management class=level3 data-number=6.5.1><h3 data-number=6.5.1><span class=header-section-number>6.5.1</span>\n<a href=#toc:overlay-management>Overlay management</a><a href=#overlay-management class=anchor aria-hidden=true></a></h3><p>In the App Details page, a new tab “Overlays” is added where per-app\noverlays are displayed. They can also be enabled or disabled using the\ntoggle button. In addition, if the App Details page of an overlay\npackage is opened, a “Overlay” tag will be displayed in the App Info\ntab. Clicking on the tag opens a dialog containing additional info along\nwith a button that allows navigating to the App Details page of the\noverlay target package if it is installed.<section id=known-limitation class=level5 data-number=6.5.1.0.1><h5 data-number=6.5.1.0.1><span class=header-section-number>6.5.1.0.1</span> Known limitation<a href=#known-limitation class=anchor aria-hidden=true></a></h5><p>At present, it only works for root/ADB users in Android 8 (Oreo) and\nlater.</section></section><section id=unfreeze-option-in-activity-shortcuts class=level3 data-number=6.5.2><h3 data-number=6.5.2><span class=header-section-number>6.5.2</span>\n<a href=#toc:unfreeze-option-in-activity-shortcuts>Unfreeze option in\nactivity shortcuts</a><a href=#unfreeze-option-in-activity-shortcuts class=anchor aria-hidden=true></a></h3><p>If the application corresponding to the shortcut being launched is\nfrozen, App Manager will now offer you to unfreeze the app temporarily\nso that the shortcut can be launched. The app will be frozen again once\nthe screen is locked.<section id=known-limitation-1 class=level5 data-number=6.5.2.0.1><h5 data-number=6.5.2.0.1><span class=header-section-number>6.5.2.0.1</span> Known limitation<a href=#known-limitation-1 class=anchor aria-hidden=true></a></h5><p>This may not work on devices without a screen lock or if the screen\nis locked some time after the display goes off.</section></section><section id=market-like-url-support class=level3 data-number=6.5.3><h3 data-number=6.5.3><span class=header-section-number>6.5.3</span>\n<a href=#toc:market-like-url-support><code>market</code>-like URL\nsupport</a><a href=#market-like-url-support class=anchor aria-hidden=true></a></h3><p>Third-party applications can now open the App Details page of any\ninstalled package by invoking an Intent with an URL with the following\nformat:<pre><code>app-manager://details?id=&lt;pkg&gt;&amp;user=&lt;user_id&gt;</code></pre><p>where <code>&lt;pkg></code> stands for package name, and\n<code>&lt;user_id></code> stands for the user ID which is\noptional.</section><section id=updated-color-codes class=level3 data-number=6.5.4><h3 data-number=6.5.4><span class=header-section-number>6.5.4</span>\n<a href=#toc:updated-color-codes>Updated color codes</a><a href=#updated-color-codes class=anchor aria-hidden=true></a></h3><p>In order to improve accessibility, certain color codes have been\nimproved. Visit <a href=app-manager://settings/about/version>Settings\n> About > Version/Changelog</a> for details.</section><section id=others class=level3 data-number=6.5.5><h3 data-number=6.5.5><span class=header-section-number>6.5.5</span>\n<a href=#toc:others>Others</a><a href=#others class=anchor aria-hidden=true></a></h3><ul class=incremental><li><p>Avoided waiting for the remote server to respond when no-root\nmode is set<li><p>Fixed downgrading apps in Android 10 onwards<li><p>Fixed installer issues in the Huawei stock operating\nsystems<li><p>Improved text formatting in the “What’s New” dialog<li><p>In the UI tracker window, fixed clicking on the icon after it is\niconified<li><p>Updated bloatware and suggestions</ul></section></section><section id=sec:v4.0.0-(440) class=level2 data-number=6.6><h2 data-number=6.6><span class=header-section-number>6.6</span> <a href=#toc:sec:v4.0.0-(440)>v4.0.0 (440)</a><a href=#sec:v4.0.0-(440) class=anchor aria-hidden=true></a></h2><p>App Manager v4.0.0 comes with a lot of new features and improvements.\nVisit <a href=app-manager://settings/about/version>Settings > About\n> Version/Changelog</a> for details.<section id=new-logo class=level3 data-number=6.6.1><h3 data-number=6.6.1><span class=header-section-number>6.6.1</span>\n<a href=#toc:new-logo>New logo!</a><a href=#new-logo class=anchor aria-hidden=true></a></h3><p>The new logo is just a cursive “A”. The design is based on the <a href=https://freetengwar.sourceforge.net/>Tengwar Telcontar</a> font\nwhich was created to bring the Tengwar script, originally created by J.\nR. R. Tolkien, to the digital world. The letter has the classic App\nManager color (i.e., #dcaf74) and uses a pure black background instead\nof a shade of grey.</section><section id=android-14-and-15-support class=level3 data-number=6.6.2><h3 data-number=6.6.2><span class=header-section-number>6.6.2</span>\n<a href=#toc:android-14-and-15-support>Android 14 and 15 support</a><a href=#android-14-and-15-support class=anchor aria-hidden=true></a></h3><p>App Manager now targets Android 14 and fully supports Android 15.<section id=known-issue class=level5 data-number=6.6.2.0.1><h5 data-number=6.6.2.0.1><span class=header-section-number>6.6.2.0.1</span> Known issue<a href=#known-issue class=anchor aria-hidden=true></a></h5><p>KeyStore backup/restore is not working in Android 12 and later.</section></section><section id=revamped-debloater class=level3 data-number=6.6.3><h3 data-number=6.6.3><span class=header-section-number>6.6.3</span>\n<a href=#toc:revamped-debloater>Revamped debloater</a><a href=#revamped-debloater class=anchor aria-hidden=true></a></h3><p>Debloating profiles were available as “Presets” in the Profiles page\nwhich has now been replaced with the Debloater page and can be accessed\nfrom the three-dots menu in the Main page. <a href=https://github.com/MuntashirAkon/android-debloat-list>ADL</a> is\na new project that focuses on maintaining a list of bloatware as well as\npotential open source alternatives. Contributions are welcome!</section><section id=introducing-file-manager class=level3 data-number=6.6.4><h3 data-number=6.6.4><span class=header-section-number>6.6.4</span>\n<a href=#toc:introducing-file-manager>Introducing file manager</a><a href=#introducing-file-manager class=anchor aria-hidden=true></a></h3><p>App Manager offers an (almost) fully-featured file manager with basic\nfile operations, such as copy, cut, rename, and delete along with the\nbatch operations. It also offers an extensive “Open with…” dialog to\nopen a file with another app, and a comprehensive file properties\nviewer. Folders can also be added to the list of favorites for quick\naccess. And many more.</section><section id=integrated-code-editor class=level3 data-number=6.6.5><h3 data-number=6.6.5><span class=header-section-number>6.6.5</span>\n<a href=#toc:integrated-code-editor>Integrated code editor</a><a href=#integrated-code-editor class=anchor aria-hidden=true></a></h3><p>Manifest and code viewers have been replaced with this new editor.\nAmong other regular features, it includes proper syntax highlighting and\nadvanced searching options. In addition, files from third-party apps can\nalso be opened for editing.</section><section id=history-of-operations class=level3 data-number=6.6.6><h3 data-number=6.6.6><span class=header-section-number>6.6.6</span>\n<a href=#toc:history-of-operations>History of operations</a><a href=#history-of-operations class=anchor aria-hidden=true></a></h3><p>All 1-click operations, batch operations, and profile invocations are\nnow stored as history. The history items can also be executed from the\nHistory page. To ensure consistency, the profile state, configurations,\npackage list are also stored, and this stored version is executed\ninstead of the actual profile. As a result, this works even if the\nprofile is deleted.</section><section id=per-app-freezing-and-more class=level3 data-number=6.6.7><h3 data-number=6.6.7><span class=header-section-number>6.6.7</span>\n<a href=#toc:per-app-freezing-and-more>Per-app freezing, and\nmore</a><a href=#per-app-freezing-and-more class=anchor aria-hidden=true></a></h3><p>Freeze/unfreeze feature now supports setting per-app freezing method\nwhich is beneficial in certain scenarios, such as when a user want to\nsuspend some apps while using the disable method as the default. In\naddition, an “Advanced suspend” option is added which force-stops an\napplication before suspending it, thus, prevent it’s services from\nrunning in the background.</section><section id=log-viewer-enhancements class=level3 data-number=6.6.8><h3 data-number=6.6.8><span class=header-section-number>6.6.8</span>\n<a href=#toc:log-viewer-enhancements>Log viewer enhancements</a><a href=#log-viewer-enhancements class=anchor aria-hidden=true></a></h3><p>Log viewer now supports enhanced searching and filtering options,\nsuch as keyword- and regular expression-based searching and filtering.\nPlease read the in-app changelog for details. Support for batch\noperations has also been added.</section><section id=launching-non-exported-activities class=level3 data-number=6.6.9><h3 data-number=6.6.9><span class=header-section-number>6.6.9</span>\n<a href=#toc:launching-non-exported-activities>Launching non-exported\nactivities</a><a href=#launching-non-exported-activities class=anchor aria-hidden=true></a></h3><p>App Manager now supports launching non-exported activities in no-root\nand ADB mode. However, in no-root mode,\n<code>android.permission.WRITE_SECURE_SETTINGS</code> permission is\nrequired.</section><section id=new-tags-in-app-info-tab class=level3 data-number=6.6.10><h3 data-number=6.6.10><span class=header-section-number>6.6.10</span> <a href=#toc:new-tags-in-app-info-tab>New tags in App Info tab</a><a href=#new-tags-in-app-info-tab class=anchor aria-hidden=true></a></h3><p>Five new tags are added in the App Info tab. They are: bloatware,\nXposed, sensors disabled, open links, and static shared libs. Clicking\non “bloatware” will display more information regarding the bloatware and\nsuggest alternatives, “Xposed” tag will display dependency information,\n“open links” will display a list of links supported by the application,\nand “static shared libs” will display all version of the application\ninstalled in the system along with an option to uninstall them. The\nlatter is useful for applications, such as Trichrome.<section id=known-issue-1 class=level5 data-number=6.6.10.0.1><h5 data-number=6.6.10.0.1><span class=header-section-number>6.6.10.0.1</span> Known issue<a href=#known-issue-1 class=anchor aria-hidden=true></a></h5><p>“Sensors disabled” only works real-time. That means if the\napplication is not currently active, this tag will always display even\nthough the applications may use sensors while it is running. This is a\nframework limitation and nothing can be done to avoid it\neffectively.</section></section><section id=per-session-installer-options class=level3 data-number=6.6.11><h3 data-number=6.6.11><span class=header-section-number>6.6.11</span> <a href=#toc:per-session-installer-options>Per-session installer\noptions</a><a href=#per-session-installer-options class=anchor aria-hidden=true></a></h3><p>It is not possible to modify installer options during the\ninstallation by clicking on the “settings” button in the installation\ndialog. The installer options will be applied to all the applications\ninstalled in the same session (i.e., the installer queue).</section><section id=advanced-mode-of-operations-adb-enhancements class=level3 data-number=6.6.12><h3 data-number=6.6.12><span class=header-section-number>6.6.12</span> <a href=#toc:advanced-mode-of-operations-adb-enhancements>Advanced mode\nof operations, ADB enhancements, …</a><a href=#advanced-mode-of-operations-adb-enhancements class=anchor aria-hidden=true></a></h3><p>App Manager now supports running its remote server (which is used as\na proxy for running privileged operations) as any supported user (UID).\nThis includes root (0), system (1000), and shell/ADB (2000) through the\ncustom commands. This is also useful for Fire TVs which have disabled\nconnecting to ADB from localhost through socket connection. In addition,\nADB pairing is now done using notifications rather than split screen.\nADB connection speed can also be improved by choosing to run App Manager\nin the background which can be configured in the settings.</section><section id=data-usage-widget-and-more class=level3 data-number=6.6.13><h3 data-number=6.6.13><span class=header-section-number>6.6.13</span> <a href=#toc:data-usage-widget-and-more>Data usage widget, and more</a><a href=#data-usage-widget-and-more class=anchor aria-hidden=true></a></h3><p>Data usage widget display the total data usage for the day, similar\nto the screen time widget which displays the total screen time for the\nday. In addition, existing widgets have been improved.</section><section id=others-1 class=level3 data-number=6.6.14><h3 data-number=6.6.14><span class=header-section-number>6.6.14</span> <a href=#toc:others-1>Others</a><a href=#others-1 class=anchor aria-hidden=true></a></h3><ul class=incremental><li><p>Replaced log viewer, sys config, Terminal, etc. with Labs\npage<li><p>Added an option to disable sensors for each app in the App Info\ntab<li><p>Added an option to perform runtime optimization of applications\nin the 1-click Ops page and in the App Info tab<li><p>Added support for Zstandard compression for\nbackup/restore<li><p>Enabling APK signing now automatically enables zip align\nfeature<li><p>Support exporting application list as CSV or JSON in the batch\noperations<li><p>Added pure black theme support<li><p>Display current activity name (when possible) in the UI Tracker\nwindow<li><p>Added an option to filter apps by user in the Main page<li><p>Display a link to Pithus report in the scanner page if\navailable.</ul></section></section><section id=sec:v3.1.0-(423) class=level2 data-number=6.7><h2 data-number=6.7><span class=header-section-number>6.7</span> <a href=#toc:sec:v3.1.0-(423)>v3.1.0 (423)</a><a href=#sec:v3.1.0-(423) class=anchor aria-hidden=true></a></h2><p>App Manager v3.1.0 comes with a few new features and a lot of\nimprovements. Visit <a href=app-manager://settings/about/version>Settings > About >\nVersion/Changelog</a> for details.<section id=android-13-support class=level3 data-number=6.7.1><h3 data-number=6.7.1><span class=header-section-number>6.7.1</span>\n<a href=#toc:android-13-support>Android 13 support</a><a href=#android-13-support class=anchor aria-hidden=true></a></h3><p>App Manager now targets Android 13 which means most issues in Android\n12 and 13 has been addressed, including SSAID and SAF issues as well as\nmonochrome icons and other theming issues.<section id=known-issue-2 class=level5 data-number=6.7.1.0.1><h5 data-number=6.7.1.0.1><span class=header-section-number>6.7.1.0.1</span> Known issue<a href=#known-issue-2 class=anchor aria-hidden=true></a></h5><p>KeyStore backup/restore not working in Android 12 and later.</section></section><section id=introducing-freezeunfreeze class=level3 data-number=6.7.2><h3 data-number=6.7.2><span class=header-section-number>6.7.2</span>\n<a href=#toc:introducing-freezeunfreeze>Introducing\nfreeze/unfreeze</a><a href=#introducing-freezeunfreeze class=anchor aria-hidden=true></a></h3><p>Enable/disable is replaced with freeze/unfreeze to allow greater\ncontrol on the behaviours of an app. It supports suspend, disable and\nhide functionalities which can be controlled at <a href=app-manager://settings/rules_prefs/freeze_type>Settings >\nRules > Default freezing method</a>. In order to make it easy to\nfreeze or unfreeze an app, shortcuts can also be created from the App\nInfo tab by long clicking on the freeze or unfreeze button.</section><section id=export-app-list class=level3 data-number=6.7.3><h3 data-number=6.7.3><span class=header-section-number>6.7.3</span>\n<a href=#toc:export-app-list>Export app list</a><a href=#export-app-list class=anchor aria-hidden=true></a></h3><p>In the Main page, it is now possible to export the list of apps in\neither XML or Markdown format using batch operations. In the future, the\nXML file may also be imported to App Manager.</section><section id=elliptic-curve-crypography-ecc class=level3 data-number=6.7.4><h3 data-number=6.7.4><span class=header-section-number>6.7.4</span>\n<a href=#toc:elliptic-curve-crypography-ecc>Elliptic Curve Crypography\n(ECC)</a><a href=#elliptic-curve-crypography-ecc class=anchor aria-hidden=true></a></h3><p>App Manager now fully supports encrypting backups using ECC in\naddition to offering AES, RSA and OpenPGP.</section><section id=new-languages class=level3 data-number=6.7.5><h3 data-number=6.7.5><span class=header-section-number>6.7.5</span>\n<a href=#toc:new-languages>New languages</a><a href=#new-languages class=anchor aria-hidden=true></a></h3><p>Two new languages are added: Korean and Romanian.</section><section id=more-list-options class=level3 data-number=6.7.6><h3 data-number=6.7.6><span class=header-section-number>6.7.6</span>\n<a href=#toc:more-list-options>More list options</a><a href=#more-list-options class=anchor aria-hidden=true></a></h3><p>In the main page, more sorting and filtering options are added.\nSorting options include sorting the apps by total size, total data\nusage, launch count, screen time and last usage time. Filtering options\ninclude filtering the apps having at least one item in the Android\nKeyStore, filtering apps with URIs granted via SAF, and filtering apps\nwith SSAID.</section><section id=improved-handling-of-mode-of-operation class=level3 data-number=6.7.7><h3 data-number=6.7.7><span class=header-section-number>6.7.7</span>\n<a href=#toc:improved-handling-of-mode-of-operation>Improved handling\nof mode of operation</a><a href=#improved-handling-of-mode-of-operation class=anchor aria-hidden=true></a></h3><p>Fixed various issues with ADB pairing, handled incomplete USB\ndebugging. Some rooting methods cannot allow interprocess communication\nvia Binder. In those cases, ADB mode is used as a fallback method by\nenabling it automatically if possible.</section><section id=handling-multiple-users class=level3 data-number=6.7.8><h3 data-number=6.7.8><span class=header-section-number>6.7.8</span>\n<a href=#toc:handling-multiple-users>Handling multiple users</a><a href=#handling-multiple-users class=anchor aria-hidden=true></a></h3><p>When possible, App Manager will be able to display apps from work\nprofile in no-root mode in addition to allowing basic operations such as\nlaunching the app or navigating to the system settings. For backups, it\nis now possible to restore backups for other users, but for work\nprofile, some apps may only work properly after re-enabling the work\nprofile. In the installer page, selecting <em>All users</em> will now\ninstall the app for all users instead of only the current user. Finally,\nin the app info tab, current app can be installed in another profile\nusing the <em>Install for…</em> option available in the three-dots menu.\nThis is analogous to the <code>pm install-existing</code> command,\nthereby, making the installation process a lot faster.</section><section id=explorer-enhancements class=level3 data-number=6.7.9><h3 data-number=6.7.9><span class=header-section-number>6.7.9</span>\n<a href=#toc:explorer-enhancements>Explorer enhancements</a><a href=#explorer-enhancements class=anchor aria-hidden=true></a></h3><p>Explorer can now open DEX and JAR files in addition to APK files.\nSeveral sorting options as well as folder options are also added as the\nlist options.</section><section id=new-tag-wx class=level3 data-number=6.7.10><h3 data-number=6.7.10><span class=header-section-number>6.7.10</span> <a href=#toc:new-tag-wx>New tag: WX</a><a href=#new-tag-wx class=anchor aria-hidden=true></a></h3><p>In app info tab, a new tag called WX is added. It is displayed in\nAndroid 10 and later if the application targets Android 9 or earlier. It\nindicates <a href=https://en.wikipedia.org/wiki/W%5EX>W^X</a>\nviolation which allows the app to execute arbitrary executable files\neither by the modification of executables embedded within the app or by\ndownloading them from the Internet.</section><section id=app-ops-management class=level3 data-number=6.7.11><h3 data-number=6.7.11><span class=header-section-number>6.7.11</span> <a href=#toc:app-ops-management>App ops management</a><a href=#app-ops-management class=anchor aria-hidden=true></a></h3><p>App ops are now managed automatically to avoid various app ops\nrelated crashes in various platforms. This will also lessen the amount\nof crashes in an unsupported operating system.</section><section id=batch-uninstallation class=level3 data-number=6.7.12><h3 data-number=6.7.12><span class=header-section-number>6.7.12</span> <a href=#toc:batch-uninstallation>Batch uninstallation</a><a href=#batch-uninstallation class=anchor aria-hidden=true></a></h3><p>In the Main page, enabled batch uninstallation in no-root mode.</section><section id=running-apps class=level3 data-number=6.7.13><h3 data-number=6.7.13><span class=header-section-number>6.7.13</span> <a href=#toc:running-apps>Running apps</a><a href=#running-apps class=anchor aria-hidden=true></a></h3><p>Enabled advanced searching. Searching now matches not only app labels\nbut also package names.</section><section id=interceptor class=level3 data-number=6.7.14><h3 data-number=6.7.14><span class=header-section-number>6.7.14</span> <a href=#toc:interceptor>Interceptor</a><a href=#interceptor class=anchor aria-hidden=true></a></h3><p>Copy the intercepted Intent as am command which can be run from\neither an ADB shell or a terminal using root with the same\neffectiveness.</section><section id=device-specific-changes class=level3 data-number=6.7.15><h3 data-number=6.7.15><span class=header-section-number>6.7.15</span> <a href=#toc:device-specific-changes>Device-specific changes</a><a href=#device-specific-changes class=anchor aria-hidden=true></a></h3><section id=graphene-os class=level5 data-number=6.7.15.0.1><h5 data-number=6.7.15.0.1><span class=header-section-number>6.7.15.0.1</span> Graphene OS<a href=#graphene-os class=anchor aria-hidden=true></a></h5><p>Explicitly handle the Internet permission which is a runtime\npermission in the OS.</section><section id=miui class=level5 data-number=6.7.15.0.2><h5 data-number=6.7.15.0.2><span class=header-section-number>6.7.15.0.2</span> MIUI<a href=#miui class=anchor aria-hidden=true></a></h5><p>Fixed permission denied issues in the installer due to a framework\nissue introduced in MIUI 12.5.</section><section id=motorola class=level5 data-number=6.7.15.0.3><h5 data-number=6.7.15.0.3><span class=header-section-number>6.7.15.0.3</span> Motorola<a href=#motorola class=anchor aria-hidden=true></a></h5><p>Fixed crashes in the Interceptor page due to a framework issue\nintroduced in Android 11.</section></section><section id=others-2 class=level3 data-number=6.7.16><h3 data-number=6.7.16><span class=header-section-number>6.7.16</span> <a href=#toc:others-2>Others</a><a href=#others-2 class=anchor aria-hidden=true></a></h3><ul class=incremental><li><p>Improved Java-Smali conversion by including all the subclasses\nduring conversion<li><p>Improved scanning performance in the Scanner page<li><p>Improved updating the list of apps in the Main page<li><p>Scan all the available paths to detect systemless-ly installed\nsystem apps<li><p><code>vacuum</code> SQLite database before opening it for viewing\nor editing.</ul></section></section><section id=sec:v3.0.0-(410) class=level2 data-number=6.8><h2 data-number=6.8><span class=header-section-number>6.8</span> <a href=#toc:sec:v3.0.0-(410)>v3.0.0 (410)</a><a href=#sec:v3.0.0-(410) class=anchor aria-hidden=true></a></h2><p>App Manager v3.0.0 comes with a lot of features and improvements. See\n<a href=app-manager://settings/about/version>Settings > About >\nVersion/Changelog</a> to see a more detailed changelog.<section id=material-3-and-more class=level3 data-number=6.8.1><h3 data-number=6.8.1><span class=header-section-number>6.8.1</span>\n<a href=#toc:material-3-and-more>Material 3 and More</a><a href=#material-3-and-more class=anchor aria-hidden=true></a></h3><p>Material 3, somewhat similar to <em>Material You</em>, is a\nsignificant improvement over Material Design 2 with support for dynamic\ncolours in Android 12 and later. In addition, many design changes have\nbeen made in App Manager without any significant changes in the overall\nuser experience.<section id=known-issue-3 class=level5 data-number=6.8.1.0.1><h5 data-number=6.8.1.0.1><span class=header-section-number>6.8.1.0.1</span> Known issue<a href=#known-issue-3 class=anchor aria-hidden=true></a></h5><p>Switches are still based on Material Design 2 which will be fixed in\na future release.</section></section><section id=wireless-debugging class=level3 data-number=6.8.2><h3 data-number=6.8.2><span class=header-section-number>6.8.2</span>\n<a href=#toc:wireless-debugging>Wireless Debugging</a><a href=#wireless-debugging class=anchor aria-hidden=true></a></h3><p>Wireless debugging support has been fully implemented. Head over to\n§<a href=#sec:wireless-debugging data-reference-type=ref data-reference=sec:wireless-debugging>3.2</a> for instructions on how\nto configure wireless debugging.<div class=\"amalert tip\"><p><strong><em>No-root users.</em></strong><p>Due to auto-detection feature, startup time might be large for\nno-root users when the mode of operation is set to <em>auto</em>.\nInstead, no-root users should select <em>no-root</em> instead of\n<em>auto</em>.</div></section><section id=languages class=level3 data-number=6.8.3><h3 data-number=6.8.3><span class=header-section-number>6.8.3</span>\n<a href=#toc:languages>Languages</a><a href=#languages class=anchor aria-hidden=true></a></h3><p>App Manager is fully translated into Indonesian and Italian languages\nand can be enabled in settings. Bengali is removed due to lack of\ntranslators.</section><section id=introducing-app-explorer class=level3 data-number=6.8.4><h3 data-number=6.8.4><span class=header-section-number>6.8.4</span>\n<a href=#toc:introducing-app-explorer>Introducing App Explorer</a><a href=#introducing-app-explorer class=anchor aria-hidden=true></a></h3><p>App Explorer can be used to browse the contents of an application.\nThis includes binary XML files, DEX contents or any other media files.\nDEX contents can only be explored in Android Oreo (Android 8) and later.\nIt’s also possible to convert an <code>.smali</code> file into\n<code>.java</code> for a better understanding of the reversed code. This\nfeature, if not needed, can be disabled in Settings > Enable/disable\nfeatures.</section><section id=import-backups-from-other-applications class=level3 data-number=6.8.5><h3 data-number=6.8.5><span class=header-section-number>6.8.5</span>\n<a href=#toc:import-backups-from-other-applications>Import Backups\nfrom Other Applications</a><a href=#import-backups-from-other-applications class=anchor aria-hidden=true></a></h3><p>It is possible to import backups from discontinued or obsolete\napplications such as Titanium Backup, OAndBackup and Swift Backup\n(version 3.0 to 3.2). Go to Setting > Backup/restore to find this\noption.</section><section id=virustotal class=level3 data-number=6.8.6><h3 data-number=6.8.6><span class=header-section-number>6.8.6</span>\n<a href=#toc:virustotal>VirusTotal</a><a href=#virustotal class=anchor aria-hidden=true></a></h3><p>VirusTotal is a widely used tool to scan files and URLs for viruses.\nIn the scanner page and in the running apps page, an option to scan\nfiles with VirusTotal has been added. But the option is hidden by\ndefault. To enable the option, it is necessary to obtain an API key from\nVirusTotal. Go to Settings > VirusTotal API Key for more\ninformation.<div class=\"amalert warning\"><p><strong><em>Internet feature.</em></strong><p>This is currently the only feature which require an Internet\nconnection. If you wish to use any Internet feature that might also be\nadded in the future, enable <em>Use the Internet</em> in Settings >\nEnable/disable features.</div></section><section id=trigger-profiles-from-the-automation-software class=level3 data-number=6.8.7><h3 data-number=6.8.7><span class=header-section-number>6.8.7</span>\n<a href=#toc:trigger-profiles-from-the-automation-software>Trigger\nProfiles from the Automation Software</a><a href=#trigger-profiles-from-the-automation-software class=anchor aria-hidden=true></a></h3><p>As the implementation of routine operations is being delayed, an\noption to trigger profiles from the external automation software is\nadded. See §<a href=#sec:automating-tasks data-reference-type=ref data-reference=sec:automating-tasks>3.4</a> for instructions on how to\nconfigure profile automation.</section><section id=improved-application-installer class=level3 data-number=6.8.8><h3 data-number=6.8.8><span class=header-section-number>6.8.8</span>\n<a href=#toc:improved-application-installer>Improved Application\nInstaller</a><a href=#improved-application-installer class=anchor aria-hidden=true></a></h3><p>Application installer includes several improvements including the\nability to downgrade applications in no-root mode, installing multiple\napplications at once and blocking trackers after installation. In\nAndroid 12 and later, no-root users can update applications without any\nuser interactions.</section><section id=component-blocking class=level3 data-number=6.8.9><h3 data-number=6.8.9><span class=header-section-number>6.8.9</span>\n<a href=#toc:component-blocking>Component Blocking</a><a href=#component-blocking class=anchor aria-hidden=true></a></h3><p>It is now possible to configure how App Manager should block a\ncomponent. Visit Settings > Rules > Default blocking method for\nmore information. In the components tab, long clicking the block/unblock\nbutton opens a context menu which allows per-component blocking in a\nsimilar manner. ADB users can also block the components of a <em>Test\nonly</em> app.</section><section id=advanced-searching class=level3 data-number=6.8.10><h3 data-number=6.8.10><span class=header-section-number>6.8.10</span> <a href=#toc:advanced-searching>Advanced Searching</a><a href=#advanced-searching class=anchor aria-hidden=true></a></h3><p>In some pages, the search bar supports additional searching which\nincludes searching via prefix, suffix or even regular expressions. In\nthe main page, it is also possible to search for applications using the\nfirst letters of each word, e.g. <em>App Manager</em> can be listed by\nsearching for <em>am</em>.</section><section id=shared-libraries class=level3 data-number=6.8.11><h3 data-number=6.8.11><span class=header-section-number>6.8.11</span> <a href=#toc:shared-libraries>Shared Libraries</a><a href=#shared-libraries class=anchor aria-hidden=true></a></h3><p>Shared libraries tab has received a significant improvements. It can\ndisplay three types of libraries, such as native, jar and APK files.</section><section id=make-the-best-use-of-interceptor class=level3 data-number=6.8.12><h3 data-number=6.8.12><span class=header-section-number>6.8.12</span> <a href=#toc:make-the-best-use-of-interceptor>Make the Best Use of\nInterceptor</a><a href=#make-the-best-use-of-interceptor class=anchor aria-hidden=true></a></h3><p>Activity interceptor can be opened directly from the activities tab\nby long clicking on the launch button, and similarly, activities can be\nlaunched from the activity interceptor page with or without root, for\nany users.<div class=\"amalert tip\"><p><strong><em>Notice.</em></strong><p>Currently, activities opened via root cannot send the results back to\nthe original applications.</div></section><section id=widget-screen-time class=level3 data-number=6.8.13><h3 data-number=6.8.13><span class=header-section-number>6.8.13</span> <a href=#toc:widget-screen-time>Widget: Screen Time</a><a href=#widget-screen-time class=anchor aria-hidden=true></a></h3><p>Screen time widget is quite similar to Digital Wellbeing’s widget by\nthe same name. It displays the total screen time for the day along with\nthe top three apps from all users.</section><section id=widget-clear-cache class=level3 data-number=6.8.14><h3 data-number=6.8.14><span class=header-section-number>6.8.14</span> <a href=#toc:widget-clear-cache>Widget: Clear Cache</a><a href=#widget-clear-cache class=anchor aria-hidden=true></a></h3><p>Clear cache widget can be to clear cache from all the applications\ndirectly from the home screen.</section></section><section id=sec:v2.6.0-(385) class=level2 data-number=6.9><h2 data-number=6.9><span class=header-section-number>6.9</span> <a href=#toc:sec:v2.6.0-(385)>v2.6.0 (385)</a><a href=#sec:v2.6.0-(385) class=anchor aria-hidden=true></a></h2><section id=introducing-backups class=level3 data-number=6.9.1><h3 data-number=6.9.1><span class=header-section-number>6.9.1</span>\n<a href=#toc:introducing-backups>Introducing Backups</a><a href=#introducing-backups class=anchor aria-hidden=true></a></h3><p>Back up/restore feature is now finally out of beta! Read <a href=#sec:backup-restore>the corresponding guide</a> to understand how\nit works.</section><section id=introducing-log-viewer class=level3 data-number=6.9.2><h3 data-number=6.9.2><span class=header-section-number>6.9.2</span>\n<a href=#toc:introducing-log-viewer>Introducing Log Viewer</a><a href=#introducing-log-viewer class=anchor aria-hidden=true></a></h3><p><a href=#subsubsec:log-viewer>Log viewer</a> is essentially a\nfront-end for <code>logcat</code>. It can be used to filter logs by\n<em>tag</em> or <em>pid</em> (process ID), or even by custom filters.\nLog levels AKA verbosity can also be configured. You can also save,\nshare and manage logs.</section><section id=lock-app-manager class=level3 data-number=6.9.3><h3 data-number=6.9.3><span class=header-section-number>6.9.3</span>\n<a href=#toc:lock-app-manager>Lock App Manager</a><a href=#lock-app-manager class=anchor aria-hidden=true></a></h3><p><a href=#subsubsec:screen-lock>Lock App Manager</a> with the screen\nlock configured for your device.</section><section id=extended-modes-for-app-ops class=level3 data-number=6.9.4><h3 data-number=6.9.4><span class=header-section-number>6.9.4</span>\n<a href=#toc:extended-modes-for-app-ops>Extended Modes for App\nOps</a><a href=#extended-modes-for-app-ops class=anchor aria-hidden=true></a></h3><p>You can set any mode for any app ops that your device supports,\neither from the <a href=#subsec:set-mode-for-app-ops-dots>1-click ops\npage</a> or from the <a href=#subsubsec:app-ops>app ops tab</a>.</section><section id=new-batch-ops-add-to-profile class=level3 data-number=6.9.5><h3 data-number=6.9.5><span class=header-section-number>6.9.5</span>\n<a href=#toc:new-batch-ops-add-to-profile>New Batch Ops: Add to\nProfile</a><a href=#new-batch-ops-add-to-profile class=anchor aria-hidden=true></a></h3><p>You can now easily add selected apps to an existing profile using the\nbatch operations.</section><section id=app-info-improved class=level3 data-number=6.9.6><h3 data-number=6.9.6><span class=header-section-number>6.9.6</span>\n<a href=#toc:app-info-improved>App Info: Improved</a><a href=#app-info-improved class=anchor aria-hidden=true></a></h3><p>App info tab now has many options, including the ability to change <a href=#sec:terminologies>SSAID</a>, network policy (i.e. background\nnetwork usage), battery optimization, etc. Most of the tags used in this\ntab are also clickable, and if you click on them, you will be able to\nlook at the current state or configure them right away.</section><section id=advanced-sort-and-filtering-options-in-the-main-page class=level3 data-number=6.9.7><h3 data-number=6.9.7><span class=header-section-number>6.9.7</span>\n<a href=#toc:advanced-sort-and-filtering-options-in-the-main-page>Advanced\nSort and Filtering Options in the Main Page</a><a href=#advanced-sort-and-filtering-options-in-the-main-page class=anchor aria-hidden=true></a></h3><p>Sort and filter options are now replaced by <a href=#subsubsec:main-list-options>List Options</a> which is highly\nconfigurable, including the ability to filter using profiles.</section><section id=about-this-device class=level3 data-number=6.9.8><h3 data-number=6.9.8><span class=header-section-number>6.9.8</span>\n<a href=#toc:about-this-device>About This Device</a><a href=#about-this-device class=anchor aria-hidden=true></a></h3><p>Interested in knowing about your device in just one page? Go to the\nbottom of the <a href=#subsec:device-info>settings page</a>.</section><section id=enabledisable-features class=level3 data-number=6.9.9><h3 data-number=6.9.9><span class=header-section-number>6.9.9</span>\n<a href=#toc:enabledisable-features>Enable/disable Features</a><a href=#enabledisable-features class=anchor aria-hidden=true></a></h3><p>Not interested in all the features that AM offers? You can disable\nsome features in <a href=#subsubsec:enable/disable-features>settings</a>.</section><section id=new-languages-1 class=level3 data-number=6.9.10><h3 data-number=6.9.10><span class=header-section-number>6.9.10</span> <a href=#toc:new-languages-1>New Languages</a><a href=#new-languages-1 class=anchor aria-hidden=true></a></h3><p>AM now has more than 19 languages! New languages include Farsi,\nJapanese and Traditional Chinese.</section><section id=signing-the-apk-files class=level3 data-number=6.9.11><h3 data-number=6.9.11><span class=header-section-number>6.9.11</span> <a href=#toc:signing-the-apk-files>Signing the APK Files</a><a href=#signing-the-apk-files class=anchor aria-hidden=true></a></h3><p>You can now import external signing keys in AM! For security, App\nManager has its own encrypted KeyStore which can also be <a href=#subsubsec:import/export-keystore>imported or exported</a>.</section><section id=new-extension-unapkm class=level3 data-number=6.9.12><h3 data-number=6.9.12><span class=header-section-number>6.9.12</span> <a href=#toc:new-extension-unapkm>New Extension: UnAPKM</a><a href=#new-extension-unapkm class=anchor aria-hidden=true></a></h3><p>Since APKMirror has removed encryption from their APKM files, it’s no\nlonger necessary to decrypt them. As a result, the option to decrypt\nAPKM files has been removed. Instead, this option is now provided by the\nUnAPKM extension which you can grab from <a href=https://f-droid.org/packages/io.github.muntashirakon.unapkm/>F-Droid</a>.\nSo, if you have an encrypted APKM file and have this extension\ninstalled, you can open the file directly in AM.</section></section><section id=sec:v2.5.20-(375) class=level2 data-number=6.10><h2 data-number=6.10><span class=header-section-number>6.10</span>\n<a href=#toc:sec:v2.5.20-(375)>v2.5.20 (375)</a><a href=#sec:v2.5.20-(375) class=anchor aria-hidden=true></a></h2><section id=subsec:introducing-profiles class=level3 data-number=6.10.1><h3 data-number=6.10.1><span class=header-section-number>6.10.1</span> <a href=#toc:subsec:introducing-profiles>Introducing Profiles</a><a href=#subsec:introducing-profiles class=anchor aria-hidden=true></a></h3><p><a href=#sec:profile-page>Profiles</a> finally closes the <a href=https://github.com/MuntashirAkon/AppManager/issues/72>related\nissue</a>. Profiles can be used to execute certain tasks repeatedly\nwithout doing everything manually. A profile can be applied (or invoked)\neither from the <a href=#sec:profiles-page>Profiles page</a> or from\nthe home screen by creating shortcuts. There are also some presets which\nconsist of debloating profiles taken from <a href=https://gitlab.com/W1nst0n/universal-android-debloater>Universal\nAndroid Debloater</a>.<section id=known-limitations class=level5 data-number=6.10.1.0.1><h5 data-number=6.10.1.0.1><span class=header-section-number>6.10.1.0.1</span> Known limitations<a href=#known-limitations class=anchor aria-hidden=true></a></h5><ul class=incremental><li><p>Exporting rules and applying permissions are not currently\nworking.<li><p>Profiles are applied for all users.</ul></section></section><section id=subsec:the-interceptor class=level3 data-number=6.10.2><h3 data-number=6.10.2><span class=header-section-number>6.10.2</span> <a href=#toc:subsec:the-interceptor>The Interceptor</a><a href=#subsec:the-interceptor class=anchor aria-hidden=true></a></h3><p><a href=https://github.com/MuntashirAkon/intent-intercept>Intent\nIntercept</a> works as a man-in-the-middle between source and\ndestination, that is, when you open a file or URL with another app, you\ncan see what is being shared by opening it with Interceptor first. You\ncan also add or modify the intents before sending them to the\ndestination. Additionally, you can double-click on any exportable\nactivities in the Activities tab in the App Details page to open them in\nthe Interceptor to add more configurations.<section id=known-limitation-2 class=level5 data-number=6.10.2.0.1><h5 data-number=6.10.2.0.1><span class=header-section-number>6.10.2.0.1</span> Known limitation<a href=#known-limitation-2 class=anchor aria-hidden=true></a></h5><p>Editing extras is not currently possible.</section></section><section id=subsec:unapkm:-dedrm-the-apkm-files class=level3 data-number=6.10.3><h3 data-number=6.10.3><span class=header-section-number>6.10.3</span> <a href=#toc:subsec:unapkm:-dedrm-the-apkm-files>UnAPKM: DeDRM the APKM\nfiles</a><a href=#subsec:unapkm:-dedrm-the-apkm-files class=anchor aria-hidden=true></a></h3><p>When I released a small tool called <a href=https://f-droid.org/en/packages/io.github.muntashirakon.unapkm>UnAPKM</a>,\nI promised that similar feature will be available in App Manager. I am\nproud to announce that you can open APKM files directly in the App Info\npage or convert them to APKS or install them directly.</section><section id=subsec:multiple-user class=level3 data-number=6.10.4><h3 data-number=6.10.4><span class=header-section-number>6.10.4</span> <a href=#toc:subsec:multiple-user>Multiple user</a><a href=#subsec:multiple-user class=anchor aria-hidden=true></a></h3><p>App manager now supports multiple users! For now, this requires root\nor ADB. But no-root support is also being considered. If you have\nmultiple users enabled and click on an app installed in multiple\nprofiles, an alert prompt will be displayed where you can select the\nuser.</section><section id=vive-la-france class=level3 data-number=6.10.5><h3 data-number=6.10.5><span class=header-section-number>6.10.5</span> <a href=#toc:vive-la-france>Vive la France!</a><a href=#vive-la-france class=anchor aria-hidden=true></a></h3><p>Thanks to the contributors, we have one more addition to the language\nclub: French. You can add more languages or improve existing\ntranslations at <a href=https://hosted.weblate.org/engage/app-manager>Weblate</a>.</section><section id=report-crashes class=level3 data-number=6.10.6><h3 data-number=6.10.6><span class=header-section-number>6.10.6</span> <a href=#toc:report-crashes>Report crashes</a><a href=#report-crashes class=anchor aria-hidden=true></a></h3><p>If App Manager crashes, you can now easily report the crash from the\nnotifications which opens the share options. Crashes are not reported by\nApp Manager, it only redirects you to your favourite Email client.</section><section id=android-11 class=level3 data-number=6.10.7><h3 data-number=6.10.7><span class=header-section-number>6.10.7</span> <a href=#toc:android-11>Android 11</a><a href=#android-11 class=anchor aria-hidden=true></a></h3><p>Added support for Android 11. Not everything may work as expected\nthough.</section><section id=app-installer-improvements class=level3 data-number=6.10.8><h3 data-number=6.10.8><span class=header-section-number>6.10.8</span> <a href=#toc:app-installer-improvements>App Installer Improvements</a><a href=#app-installer-improvements class=anchor aria-hidden=true></a></h3><section id=set-installation-locations class=level4 data-number=6.10.8.1><h4 data-number=6.10.8.1><span class=header-section-number>6.10.8.1</span> Set installation\nlocations<a href=#set-installation-locations class=anchor aria-hidden=true></a></h4><p>In settings page, you can set install locations such as auto\n(default), internal only and prefer external.</section><section id=set-apk-installer class=level4 data-number=6.10.8.2><h4 data-number=6.10.8.2><span class=header-section-number>6.10.8.2</span> Set APK installer<a href=#set-apk-installer class=anchor aria-hidden=true></a></h4><p>In settings page, you can also set default APK installer (root/ADB\nonly) instead of App Manager.</section><section id=multiple-users class=level4 data-number=6.10.8.3><h4 data-number=6.10.8.3><span class=header-section-number>6.10.8.3</span> Multiple users<a href=#multiple-users class=anchor aria-hidden=true></a></h4><p>In settings page, you can allow App Manager to display multiple users\nduring APK installation.</section><section id=signing-apk-files class=level4 data-number=6.10.8.4><h4 data-number=6.10.8.4><span class=header-section-number>6.10.8.4</span> Signing APK files<a href=#signing-apk-files class=anchor aria-hidden=true></a></h4><p>In settings page, you can choose to sign APK files before installing\nthem. You can also select which signature scheme to use in the <em>APK\nsigning</em> option in settings.<section id=known-limitation-3 class=level5 data-number=6.10.8.4.1><h5 data-number=6.10.8.4.1><span class=header-section-number>6.10.8.4.1</span> Known limitation<a href=#known-limitation-3 class=anchor aria-hidden=true></a></h5><p>Currently, only a generic key is used to sign APK files</section></section></section></section><section id=v2.5.17-368 class=level2 data-number=6.11><h2 data-number=6.11><span class=header-section-number>6.11</span>\n<a href=#toc:v2.5.17-368>v2.5.17 (368)</a><a href=#v2.5.17-368 class=anchor aria-hidden=true></a></h2><section id=app-installer class=level3 data-number=6.11.1><h3 data-number=6.11.1><span class=header-section-number>6.11.1</span> <a href=#toc:app-installer>App Installer</a><a href=#app-installer class=anchor aria-hidden=true></a></h3><p>As promised, it is now possible to select splits. AM also provides\nrecommendations based on device configurations. If the app is already\ninstalled, recommendations are provided based on the installed app. It\nis also possible to downgrade to a lower version without data loss if\nthe device has root or ADB. But it should be noted that not all app can\nbe downgraded. Installer is also improved to speed up the installation\nprocess, especially, for root users. If the app has already been\ninstalled and the new (x)apk(s) is newer or older or the same version\nwith a different signature, AM will display a list of changes similar to\n<strong>What’s New</strong> before prompting the user to install the\napp. This is useful if the app has introduced tracker components, new\npermissions, etc.<section id=known-limitations-1 class=level5 data-number=6.11.1.0.1><h5 data-number=6.11.1.0.1><span class=header-section-number>6.11.1.0.1</span> Known Limitations<a href=#known-limitations-1 class=anchor aria-hidden=true></a></h5><ul class=incremental><li><p>Large app can take a long time to fetch app info, and therefore,\nit may take a long time display the installation prompt.<li><p>If the apk is not located in the internal storage, the app has to\nbe cached first which might also take a long time depending on the size\nof the apk.</ul></section></section><section id=scanner-replacement-for-exodus-page class=level3 data-number=6.11.2><h3 data-number=6.11.2><span class=header-section-number>6.11.2</span> <a href=#toc:scanner-replacement-for-exodus-page>Scanner: Replacement for\nExodus Page</a><a href=#scanner-replacement-for-exodus-page class=anchor aria-hidden=true></a></h3><p>Exodus page is now replaced with scanner page. <a href=#sec:scanner-page>Scanner page</a> contains not only a list of\ntrackers but also a list of used libraries. This is just a start. In the\nfuture, this page will contain more in depth analysis of the app.</section><section id=introducing-system-config class=level3 data-number=6.11.3><h3 data-number=6.11.3><span class=header-section-number>6.11.3</span> <a href=#toc:introducing-system-config>Introducing System Config</a><a href=#introducing-system-config class=anchor aria-hidden=true></a></h3><p>System Config lists various system configurations and\nwhitelists/blacklists included in Android by either OEM/vendor, AOSP or\neven some Magisk modules. Root users can access this option from the\noverflow menu in the main page. There isn’t any official documentation\nfor these options therefore it’s difficult to write a complete\ndocumentation for this page. I will gradually add documentations using\nmy own knowledge. However, some functions should be understandable by\ntheir name.</section><section id=more-languages class=level3 data-number=6.11.4><h3 data-number=6.11.4><span class=header-section-number>6.11.4</span> <a href=#toc:more-languages>More Languages</a><a href=#more-languages class=anchor aria-hidden=true></a></h3><p>Thanks to the contributors, AM now has more than 12 languages. New\nlanguages include Bengali, Hindi, Norwegian, Polish, Russian, Simplified\nChinese, Turkish and Ukrainian.</section><section id=app-info-tab class=level3 data-number=6.11.5><h3 data-number=6.11.5><span class=header-section-number>6.11.5</span> <a href=#toc:app-info-tab>App Info Tab</a><a href=#app-info-tab class=anchor aria-hidden=true></a></h3><p>More tags are added in the <a href=#subsec:app-info-tab>app info\ntab</a> such as <strong>KeyStore</strong> (apps with KeyStore items),\n<strong>Systemless app</strong> (apps installed via Magisk),\n<strong>Running</strong> (apps that are running). For external apk, two\nmore options are added namely <strong>Reinstall</strong> and\n<strong>Downgrade</strong>. Now it is possible to share an apk via\nBluetooth. For system apps, it is possible to uninstall updates for\nroot/ADB users. But like the similar option in the system settings, this\noperation will clear all app data. As stated above, exodus has been\nreplaced with scanner.</section><section id=navigation-improvements class=level3 data-number=6.11.6><h3 data-number=6.11.6><span class=header-section-number>6.11.6</span> <a href=#toc:navigation-improvements>Navigation Improvements</a><a href=#navigation-improvements class=anchor aria-hidden=true></a></h3><p>It’s now relatively easy to navigate to various UI components using\nkeyboard. You can use up/down button to navigate between list items and\ntab button to navigate to UI components inside an item.</section><section id=running-apps-page class=level3 data-number=6.11.7><h3 data-number=6.11.7><span class=header-section-number>6.11.7</span> <a href=#toc:running-apps-page>Running Apps Page</a><a href=#running-apps-page class=anchor aria-hidden=true></a></h3><p>It is now possible to sort and filter processes in this tab. Also,\nthe three big buttons are replaced with an easy-to-use three dot menu.\nPreviously the memory usage was wrong which is fixed in this\nversion.</section><section id=built-in-toybox class=level3 data-number=6.11.8><h3 data-number=6.11.8><span class=header-section-number>6.11.8</span> <a href=#toc:built-in-toybox>Built-in Toybox</a><a href=#built-in-toybox class=anchor aria-hidden=true></a></h3><p>Toybox (an alternative to busybox) is bundled with AM. Although\nAndroid has this utility built-in from API 23, toybox is bundled in\norder to prevent buggy implementations and to support API &lt; 23.</section><section id=component-blocker-improvements class=level3 data-number=6.11.9><h3 data-number=6.11.9><span class=header-section-number>6.11.9</span> <a href=#toc:component-blocker-improvements>Component Blocker\nImprovements</a><a href=#component-blocker-improvements class=anchor aria-hidden=true></a></h3><p>Component blocker seemed to be problematic in the previous version,\nespecially when global component blocking is enabled. The issues are\nmostly fixed now.<div class=\"amalert warning\"><p><strong><em>Caution.</em></strong><p>The component blocking mechanism is no longer compatible with v2.5.6\ndue to various security issues. If you have this version, upgrade to\nv2.5.13 or earlier versions first. After that, enable <a href=#subsubsec:instant-component-blocking>global component\nblocking</a> and disable it again.</div></section><section id=improvements-in-the-app-details-page class=level3 data-number=6.11.10><h3 data-number=6.11.10><span class=header-section-number>6.11.10</span> <a href=#toc:improvements-in-the-app-details-page>Improvements in the App\nDetails Page</a><a href=#improvements-in-the-app-details-page class=anchor aria-hidden=true></a></h3><p>Value of various app ops depend on their parent app ops. Therefore,\nwhen you allow/deny an app op, the parent of the app op gets modified.\nThis fixes the issues some users have been complaining regarding some\napp ops that couldn’t be changed.<p>If an app has the target API 23 or less, its permissions cannot be\nmodified using the <code>pm grant …</code> command. Therefore, for such\napps, option to toggle permission has been disabled.<p>The signature tab is improved to support localization. It also\ndisplays multiple checksums for a signature.</section><section id=app-manifest class=level3 data-number=6.11.11><h3 data-number=6.11.11><span class=header-section-number>6.11.11</span> <a href=#toc:app-manifest>App Manifest</a><a href=#app-manifest class=anchor aria-hidden=true></a></h3><p>Manifest no longer crashes if the size of the manifest is too long.\nGenerated manifest are now more accurate than before.</section></section><section id=v2.5.13-348 class=level2 data-number=6.12><h2 data-number=6.12><span class=header-section-number>6.12</span>\n<a href=#toc:v2.5.13-348>v2.5.13 (348)</a><a href=#v2.5.13-348 class=anchor aria-hidden=true></a></h2><section id=bundled-app-split-apk class=level3 data-number=6.12.1><h3 data-number=6.12.1><span class=header-section-number>6.12.1</span> <a href=#toc:bundled-app-split-apk>Bundled App (Split APK)</a><a href=#bundled-app-split-apk class=anchor aria-hidden=true></a></h3><p>Bundled app formats such as <strong>apks</strong> and\n<strong>xapk</strong> are now supported. You can install these apps\nusing the regular installation buttons. For root and adb users, apps are\ninstalled using shell, and for non-root users, the platform default\nmethod is used.<section id=known-limitations-2 class=level5 data-number=6.12.1.0.1><h5 data-number=6.12.1.0.1><span class=header-section-number>6.12.1.0.1</span> Known Limitations<a href=#known-limitations-2 class=anchor aria-hidden=true></a></h5><ul class=incremental><li><p>Currently <em>all</em> splits apks are installed. But this\nbehaviour is going to change in the next release. If you only need a few\nsplits instead of all, extract the <strong>APKS</strong> or\n<strong>XAPK</strong> file, and then, create a new zip file with your\ndesired split apks and replace the <strong>ZIP</strong> extension with\n<strong>APKS</strong>. Now, open it with AM.<li><p>There is no progress dialog to display the installation\nprogress.</ul></section></section><section id=direct-install-support class=level3 data-number=6.12.2><h3 data-number=6.12.2><span class=header-section-number>6.12.2</span> <a href=#toc:direct-install-support>Direct Install Support</a><a href=#direct-install-support class=anchor aria-hidden=true></a></h3><p>You can now install <strong>APK</strong>, <strong>APKS</strong> or\n<strong>XAPK</strong> directly from your favourite browser or file\nmanager. For apps that need updates, a <strong>What’s New</strong>\ndialog is displayed showing the changes in the new version.<section id=known-limitations-3 class=level5 data-number=6.12.2.0.1><h5 data-number=6.12.2.0.1><span class=header-section-number>6.12.2.0.1</span> Known Limitations<a href=#known-limitations-3 class=anchor aria-hidden=true></a></h5><ul class=incremental><li><p>Downgrade is not yet possible.<li><p>There is no progress dialog to display the installation progress.\nIf you cannot interact with the current page, wait until the\ninstallation is finished.</ul></section></section><section id=remove-all-blocking-rules class=level3 data-number=6.12.3><h3 data-number=6.12.3><span class=header-section-number>6.12.3</span> <a href=#toc:remove-all-blocking-rules>Remove All Blocking Rules</a><a href=#remove-all-blocking-rules class=anchor aria-hidden=true></a></h3><p>In the Settings page, a new option is added which can be used to\nremove all blocking rules configured within App Manager.</section><section id=app-ops-1 class=level3 data-number=6.12.4><h3 data-number=6.12.4><span class=header-section-number>6.12.4</span> <a href=#toc:app-ops-1>App\nOps</a><a href=#app-ops-1 class=anchor aria-hidden=true></a></h3><ul class=incremental><li><p>App Ops are now generated using a technique similar to AppOpsX.\nThis should decrease the loading time significantly in the App Ops\ntab.<li><p>In the App Ops tab, a menu item is added which can be used to\nlist only active app ops without including the default app ops. The\npreference is saved in the shared preferences.</ul><section id=known-limitation-4 class=level5 data-number=6.12.4.0.1><h5 data-number=6.12.4.0.1><span class=header-section-number>6.12.4.0.1</span> Known Limitation<a href=#known-limitation-4 class=anchor aria-hidden=true></a></h5><p>Often the App Ops tab may not be responsive. If that’s the case,\nrestart App Manager.</section></section><section id=enhanced-adb-support class=level3 data-number=6.12.5><h3 data-number=6.12.5><span class=header-section-number>6.12.5</span> <a href=#toc:enhanced-adb-support>Enhanced ADB Support</a><a href=#enhanced-adb-support class=anchor aria-hidden=true></a></h3><p>ADB shell commands are now executed using a technique similar to\nAppOpsX (This is the <em>free</em> alternative of AppOps by Rikka.).\nThis should dramatically increase the execution time.<section id=known-limitation-5 class=level5 data-number=6.12.5.0.1><h5 data-number=6.12.5.0.1><span class=header-section-number>6.12.5.0.1</span> Known Limitation<a href=#known-limitation-5 class=anchor aria-hidden=true></a></h5><p>AM can often crash or become not responsive. If that’s the case,\nrestart App Manager.</section></section><section id=filtering-in-main-page class=level3 data-number=6.12.6><h3 data-number=6.12.6><span class=header-section-number>6.12.6</span> <a href=#toc:filtering-in-main-page>Filtering in Main Page</a><a href=#filtering-in-main-page class=anchor aria-hidden=true></a></h3><p>Add an option to filter apps that has at least one activity.</section><section id=apk-backupsharing class=level3 data-number=6.12.7><h3 data-number=6.12.7><span class=header-section-number>6.12.7</span> <a href=#toc:apk-backupsharing>Apk Backup/Sharing</a><a href=#apk-backupsharing class=anchor aria-hidden=true></a></h3><p>Apk files are now saved as <code>app name_version.extension</code>\ninstead of <code>package.name.extension</code>.</section><section id=batch-ops class=level3 data-number=6.12.8><h3 data-number=6.12.8><span class=header-section-number>6.12.8</span> <a href=#toc:batch-ops>Batch Ops</a><a href=#batch-ops class=anchor aria-hidden=true></a></h3><ul class=incremental><li><p>Added a foreground service to run batch operations. The result of\nthe operation is displayed in a notification. If an operation has failed\nfor some packages, clicking on the notification will open a dialog box\nlisting the failed packages. There is also a <strong>Try Again</strong>\nbutton on the bottom which can be used to perform the operation again\nfor the failed packages.<li><p>Replaced Linux <em>kill</em> with\n<strong>force-stop</strong>.</ul></section><section id=translations class=level3 data-number=6.12.9><h3 data-number=6.12.9><span class=header-section-number>6.12.9</span> <a href=#toc:translations>Translations</a><a href=#translations class=anchor aria-hidden=true></a></h3><p>Added German and Portuguese (Brazilian) translations.<section id=known-limitation-6 class=level5 data-number=6.12.9.0.1><h5 data-number=6.12.9.0.1><span class=header-section-number>6.12.9.0.1</span> Known Limitation<a href=#known-limitation-6 class=anchor aria-hidden=true></a></h5><p>Not all translations are verified yet.</section></section><section id=app-data-backup class=level3 data-number=6.12.10><h3 data-number=6.12.10><span class=header-section-number>6.12.10</span> <a href=#toc:app-data-backup>App Data Backup</a><a href=#app-data-backup class=anchor aria-hidden=true></a></h3><p>Install app only for the current user at the time of restoring\nbackups. Support for split apks is also added.<p><em>Data backup feature is now considered unstable. If you encounter\nany problem, please report to me without hesitation.</em></section></section></section><section id=ch:app-ops class=level1 data-number=7><h1 data-number=7><span class=header-section-number>7</span> <a href=#toc:ch:app-ops>App Ops</a><a href=#ch:app-ops class=anchor aria-hidden=true></a></h1><section id=sec:app-ops-background class=level2 data-number=7.1><h2 data-number=7.1><span class=header-section-number>7.1</span> <a href=#toc:sec:app-ops-background>Background</a><a href=#sec:app-ops-background class=anchor aria-hidden=true></a></h2><p><strong>App Ops</strong> (short hand for <strong>Application\nOperations</strong>) are used by Android system (since Android 4.3) to\ncontrol application permissions. The user <em>can</em> control some\npermissions, but only the permissions that are considered dangerous (and\nGoogle thinks knowing your phone number isn’t a dangerous thing). So,\napp ops seems to be the one we need if we want to install apps like\nFacebook and it’s Messenger (the latter literary records everything if\nyou live outside the EU) and still want <em>some</em> privacy and/or\nsecurity. Although certain features of app ops were available in\nSettings and later in hidden settings in older version of Android, it’s\ncompletely hidden in newer versions of Android and is continued to be\nkept hidden. Now, any app with\n<strong>android.Manifest.permission.GET_APP_OPS_STATS</strong>\npermission can get the app ops information for other applications but\nthis permission is hidden from users and can only be enabled using ADB\nor root. Still, the app with this permission cannot grant or revoke\npermissions (actually mode of operation) for apps other than itself\n(with limited capacity, of course). To modify the ops of other app, the\napp needs\n<strong>android.Manifest.permission.UPDATE_APP_OPS_STATS</strong>\npermissions which isn’t accessible via <code>pm</code> command. So, you\ncannot grant it via root or ADB, the permission is only granted to the\nsystem apps. There are very few apps who support disabling permissions\nvia app ops. The best one to my knowledge is <a href=https://github.com/8enet/AppOpsX>AppOpsX</a>. The main (visible)\ndifference between my app (AppManager) and this app is that the latter\nalso provides you the ability to revoke internet permissions (by writing\nip tables). One crucial problem that I faced during the development of\nthe app ops API is the lack of documentation in English language.</section><section id=sec:introduction-to-app-ops class=level2 data-number=7.2><h2 data-number=7.2><span class=header-section-number>7.2</span> <a href=#toc:sec:introduction-to-app-ops>Introduction to App Ops</a><a href=#sec:introduction-to-app-ops class=anchor aria-hidden=true></a></h2><figure id=fig:appops><figure><object data=../images/appops.svg type=image/svg+xml></object></figure><figcaption>Figure 2: How app ops work</figcaption></figure><p>Figure <a href=#fig:appops>1</a> describes the process of changing\nand processing permission. <a href=#sec:appopsmanager>AppOpsManager</a> can be used to manage\npermissions in Settings app. <strong>AppOpsManager</strong> is also\nuseful in determining if a certain permission (or operation) is granted\nto the application. Most of the methods of\n<strong>AppOpsManager</strong> are accessible to the user app but unlike\na system app, it can only be used to check permissions for any app or\nfor the app itself and start or terminating certain operations.\nMoreover, not all operations are actually accessible from this Java\nclass. <strong>AppOpsManager</strong> holds all the necessary constants\nsuch as <a href=#subsec:op-constants><code>OP_*</code></a>,\n<code>OPSTR_*</code>, <a href=#subsec:mode-constants><code>MODE_*</code></a> which describes\noperation code, operation string and mode of operations respectively. It\nalso holds necessary data structures such as <a href=#subsec:package-ops>PackageOps</a> and <strong>OpEntry</strong>.\n<strong>PackageOps</strong> holds <strong>OpEntry</strong> for a\npackage, and <strong>OpEntry</strong>, as the name suggests, describes\neach operation.<p><code>AppOpService</code> is completely hidden from a user\napplication but accessible to the system applications. As it can be seen\nin Figure <a href=#fig:appops>1</a>, this is the class that does the\nactual management stuff. It contains data structures such as\n<strong>Ops</strong> to store basic package info and <strong>Op</strong>\nwhich is similar to <strong>OpEntry</strong> of\n<strong>AppOpsManager</strong>. It also has <strong>Shell</strong> which\nis actually the source code of the <a href=#sec:appops-cli><em>appops</em> command line tool</a>. It writes\nconfigurations to or read configurations from <a href=#sec:appops-xml><code>/data/system/appops.xml</code></a>. System\nservices calls <strong>AppOpsService</strong> to find out what an\napplication is allowed and what is not allowed to perform, and\n<strong>AppOpsService</strong> determines these permissions by parsing\n<code>/data/system/appops.xml</code>. If no custom values are present in\n<em>appops.xml</em>, it returns the default mode available in\n<strong>AppOpsManager</strong>.</section><section id=sec:appopsmanager class=level2 data-number=7.3><h2 data-number=7.3><span class=header-section-number>7.3</span> <a href=#toc:sec:appopsmanager>AppOpsManager</a><a href=#sec:appopsmanager class=anchor aria-hidden=true></a></h2><p><a href=https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/app/AppOpsManager.java>AppOpsManager</a>\nstands for application operations manager. It consists of various\nconstants and classes to modify app operations.<div class=seealso-inline><p><em>See also: <span><a href=https://developer.android.com/reference/android/app/AppOpsManager>AppOpsManager\ndocumentation</a></span></em></div><section id=subsec:op-constants class=level3 data-number=7.3.1><h3 data-number=7.3.1><span class=header-section-number>7.3.1</span>\n<a href=#toc:subsec:op-constants><code>OP_*</code> Constants</a><a href=#subsec:op-constants class=anchor aria-hidden=true></a></h3><p><code>OP_*</code> are the integer constants starting from\n<code>0</code>. <code>OP_NONE</code> implies that no operations are\nspecified whereas <code>_NUM_OP</code> denotes the number of operations\ndefined in <code>OP_*</code> prefix. While they denote each operation,\nthe operations are not necessarily unique. In fact, there are many\noperations that are actually a single operation denoted by multiple\n<code>OP_*</code> constant (possibly for future use). Vendors may define\ntheir own op based on their requirements. MIUI is one of the vendors who\nare known to do that.<div class=listing><div class=sourceCode id=cb11 data-frame=lines><pre class=\"sourceCode java\"><code class=\"sourceCode java\"><span id=cb11-1><a href=#cb11-1 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=dt>final</span> <span class=dt>int</span> OP_NONE <span class=op>=</span> <span class=op>-</span><span class=dv>1</span><span class=op>;</span></span>\n<span id=cb11-2><a href=#cb11-2 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=dt>final</span> <span class=dt>int</span> OP_COARSE_LOCATION <span class=op>=</span> <span class=dv>0</span><span class=op>;</span></span>\n<span id=cb11-3><a href=#cb11-3 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=dt>final</span> <span class=dt>int</span> OP_FINE_LOCATION <span class=op>=</span> <span class=dv>1</span><span class=op>;</span></span>\n<span id=cb11-4><a href=#cb11-4 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=dt>final</span> <span class=dt>int</span> OP_GPS <span class=op>=</span> <span class=dv>2</span><span class=op>;</span></span>\n<span id=cb11-5><a href=#cb11-5 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=dt>final</span> <span class=dt>int</span> OP_VIBRATE <span class=op>=</span> <span class=dv>3</span><span class=op>;</span></span>\n<span id=cb11-6><a href=#cb11-6 aria-hidden=true tabindex=-1></a><span class=kw>...</span></span>\n<span id=cb11-7><a href=#cb11-7 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=dt>final</span> <span class=dt>int</span> OP_READ_DEVICE_IDENTIFIERS <span class=op>=</span> <span class=dv>89</span><span class=op>;</span></span>\n<span id=cb11-8><a href=#cb11-8 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=dt>final</span> <span class=dt>int</span> OP_ACCESS_MEDIA_LOCATION <span class=op>=</span> <span class=dv>90</span><span class=op>;</span></span>\n<span id=cb11-9><a href=#cb11-9 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=dt>final</span> <span class=dt>int</span> OP_ACTIVATE_PLATFORM_VPN <span class=op>=</span> <span class=dv>91</span><span class=op>;</span></span>\n<span id=cb11-10><a href=#cb11-10 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=dt>final</span> <span class=dt>int</span> _NUM_OP <span class=op>=</span> <span class=dv>92</span><span class=op>;</span></span></code></pre></div></div><p>Whether an operation is unique is defined by\n<code>sOpToSwitch</code>. It maps each operation to another operation or\nto itself (if it’s a unique operation). For instance,\n<code>OP_FINE_LOCATION</code> and <code>OP_GPS</code> are mapped to\n<code>OP_COARSE_LOCATION</code>.<p>Each operation has a private name which are described by\n<code>sOpNames</code>. These names are usually the same names as the\nconstants without the <code>OP_</code> prefix. Some operations have\npublic names as well which are described by <code>sOpToString</code>.\nFor instance, <code>OP_COARSE_LOCATION</code> has the public name\n<strong>android:coarse_location</strong>.<p>As a gradual process of moving permissions to app ops, there are\nalready many permissions that are defined under some operations. These\npermissions are mapped in <code>sOpPerms</code>. For example, the\npermission\n<strong>android.Manifest.permission.ACCESS_COARSE_LOCATION</strong> is\nmapped to <code>OP_COARSE_LOCATION</code>. Some operations may not have\nany associated permissions which have <code>null</code> values.<p>As described in the previous section, operations that are configured\nfor an app are stored at <a href=#sec:appops-xml><code>/data/system/appops.xml</code></a>. If an\noperation is not configured, then whether system will allow that\noperation is determined from <code>sOpDefaultMode</code>. It lists the\n<em>default mode</em> for each operation.</section><section id=subsec:mode-constants class=level3 data-number=7.3.2><h3 data-number=7.3.2><span class=header-section-number>7.3.2</span>\n<a href=#toc:subsec:mode-constants><code>MODE_*</code> Constants</a><a href=#subsec:mode-constants class=anchor aria-hidden=true></a></h3><p><code>MODE_*</code> constants also integer constants starting from\n<code>0</code>. These constants are assigned to each operation\ndescribing whether an app is authorised to perform that operation. These\nmodes usually have associated names such as <strong>allow</strong> for\n<code>MODE_ALLOWED</code>, <strong>ignore</strong> for\n<code>MODE_IGNORED</code>, <strong>deny</strong> for\n<code>MODE_ERRORED</code> (a rather misnomer), <strong>default</strong>\nfor <code>MODE_DEFAULT</code> and <strong>foreground</strong> for\n<code>MODE_FOREGROUND</code>.<ol class=incremental><li><p><strong><code>MODE_ALLOWED</code>.</strong> The app is allowed to\nperform the given operation<li><p><strong><code>MODE_IGNORED</code>.</strong> The app is not\nallowed to perform the given operation, and any attempt to perform the\noperation should <em>silently fail</em>, i.e. it should not cause the\napp to crash<li><p><strong><code>MODE_ERRORED</code>.</strong> The app is not\nallowed to perform the given operation, and this attempt should cause it\nto have a fatal error, typically a\n<code>SecurityException</code><li><p><strong><code>MODE_DEFAULT</code>.</strong> The app should use\nits default security check, specified in\n<code>AppOpsManager</code><li><p><strong><code>MODE_FOREGROUND</code>.</strong> Special mode that\nmeans “allow only when app is in foreground.” This mode was added in\nAndroid 10<li><p><strong><code>MODE_ASK</code>.</strong> This is a custom mode\nused by MIUI whose uses are unknown.</ol></section><section id=subsec:package-ops class=level3 data-number=7.3.3><h3 data-number=7.3.3><span class=header-section-number>7.3.3</span>\n<a href=#toc:subsec:package-ops>PackageOps</a><a href=#subsec:package-ops class=anchor aria-hidden=true></a></h3><p><strong>AppOpsManager.PackageOps</strong> is a data structure to\nstore all the <strong>OpEntry</strong> for a package. In simple terms,\nit stores all the customised operations for a package.<div class=listing><div class=sourceCode id=cb12 data-frame=lines><pre class=\"sourceCode java\"><code class=\"sourceCode java\"><span id=cb12-1><a href=#cb12-1 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=kw>class</span> PackageOps <span class=kw>implements</span> Parcelable <span class=op>{</span></span>\n<span id=cb12-2><a href=#cb12-2 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=bu>String</span> mPackageName<span class=op>;</span></span>\n<span id=cb12-3><a href=#cb12-3 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=dt>int</span> mUid<span class=op>;</span></span>\n<span id=cb12-4><a href=#cb12-4 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=bu>List</span><span class=op>&lt;</span>OpEntry<span class=op>&gt;</span> mEntries<span class=op>;</span></span>\n<span id=cb12-5><a href=#cb12-5 aria-hidden=true tabindex=-1></a>    <span class=kw>...</span></span>\n<span id=cb12-6><a href=#cb12-6 aria-hidden=true tabindex=-1></a><span class=op>}</span></span></code></pre></div></div><p>As can be seen in Listing <a href=#lst:package-ops-class>2</a>, it\nstores all <strong>OpEntry</strong> for a package as well as the\ncorresponding package name and its kernel user ID.</section><section id=subsec:opentry class=level3 data-number=7.3.4><h3 data-number=7.3.4><span class=header-section-number>7.3.4</span>\n<a href=#toc:subsec:opentry>OpEntry</a><a href=#subsec:opentry class=anchor aria-hidden=true></a></h3><p><strong>AppOpsManager.OpEntry</strong> is a data structure that\nstores a single operation for any package.<div class=listing><div class=sourceCode id=cb13 data-frame=lines><pre class=\"sourceCode java\"><code class=\"sourceCode java\"><span id=cb13-1><a href=#cb13-1 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=dt>final</span> <span class=kw>class</span> OpEntry <span class=kw>implements</span> Parcelable <span class=op>{</span></span>\n<span id=cb13-2><a href=#cb13-2 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=dt>int</span> mOp<span class=op>;</span></span>\n<span id=cb13-3><a href=#cb13-3 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=dt>boolean</span> mRunning<span class=op>;</span></span>\n<span id=cb13-4><a href=#cb13-4 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=at>@Mode</span> <span class=dt>int</span> mMode<span class=op>;</span></span>\n<span id=cb13-5><a href=#cb13-5 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=at>@Nullable</span> LongSparseLongArray mAccessTimes<span class=op>;</span></span>\n<span id=cb13-6><a href=#cb13-6 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=at>@Nullable</span> LongSparseLongArray mRejectTimes<span class=op>;</span></span>\n<span id=cb13-7><a href=#cb13-7 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=at>@Nullable</span> LongSparseLongArray mDurations<span class=op>;</span></span>\n<span id=cb13-8><a href=#cb13-8 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=at>@Nullable</span> LongSparseLongArray mProxyUids<span class=op>;</span></span>\n<span id=cb13-9><a href=#cb13-9 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=at>@Nullable</span> LongSparseArray<span class=op>&lt;</span><span class=bu>String</span><span class=op>&gt;</span> mProxyPackageNames<span class=op>;</span></span>\n<span id=cb13-10><a href=#cb13-10 aria-hidden=true tabindex=-1></a>    <span class=kw>...</span></span>\n<span id=cb13-11><a href=#cb13-11 aria-hidden=true tabindex=-1></a><span class=op>}</span></span></code></pre></div></div><p>Here:<ul class=incremental><li><p><code>mOp</code>: Denotes one of the <a href=#subsec:op-constants><code>OP_*</code> constants</a><li><p><code>mRunning</code>: Whether the operation is in progress\n(i.e. the operation has started but not finished yet). Not all\noperations can be started or finished this way<li><p><code>mMOde</code>: One of the <a href=#subsec:mode-constants><code>MODE_*</code> constants</a><li><p><code>mAccessTimes</code>: Stores all the available access\ntimes<li><p><code>mRejectTimes</code>: Stores all the available reject\ntimes<li><p><code>mDurations</code>: All available access durations, checking\nthis with <code>mRunning</code> will tell you for how long the app is\nperforming a certain app operation<li><p><code>mProxyUids</code>: No documentation found<li><p><code>mProxyPackageNames:</code> No documentation found</ul></section><section id=subsec:usage class=level3 data-number=7.3.5><h3 data-number=7.3.5><span class=header-section-number>7.3.5</span>\n<a href=#toc:subsec:usage>Usage</a><a href=#subsec:usage class=anchor aria-hidden=true></a></h3><p>TODO</section></section><section id=sec:appopsservice class=level2 data-number=7.4><h2 data-number=7.4><span class=header-section-number>7.4</span> <a href=#toc:sec:appopsservice>AppOpsService</a><a href=#sec:appopsservice class=anchor aria-hidden=true></a></h2><p>TODO</section><section id=sec:appops-xml class=level2 data-number=7.5><h2 data-number=7.5><span class=header-section-number>7.5</span> <a href=#toc:sec:appops-xml>appops.xml</a><a href=#sec:appops-xml class=anchor aria-hidden=true></a></h2><p>Latest <code>appops.xml</code> has the following format: (This DTD is\nmade by me and by no means perfect, has compatibility issues.)<pre><code>&lt;!DOCTYPE app-ops [\n\n&lt;!ELEMENT app-ops (uid|pkg)*&gt;\n&lt;!ATTLIST app-ops v CDATA #IMPLIED&gt;\n\n&lt;!ELEMENT uid (op)*&gt;\n&lt;!ATTLIST uid n CDATA #REQUIRED&gt;\n\n&lt;!ELEMENT pkg (uid)*&gt;\n&lt;!ATTLIST pkg n CDATA #REQUIRED&gt;\n\n&lt;!ELEMENT uid (op)*&gt;\n&lt;!ATTLIST uid\nn CDATA #REQUIRED\np CDATA #IMPLIED&gt;\n\n&lt;!ELEMENT op (st)*&gt;\n&lt;!ATTLIST op\nn CDATA #REQUIRED\nm CDATA #REQUIRED&gt;\n\n&lt;!ELEMENT st EMPTY&gt;\n&lt;!ATTLIST st\nn CDATA #REQUIRED\nt CDATA #IMPLIED\nr CDATA #IMPLIED\nd CDATA #IMPLIED\npp CDATA #IMPLIED\npu CDATA #IMPLIED&gt;\n\n]&gt;</code></pre><p>The instruction below follows the exact order given above:<ul class=incremental><li><p><code>app-ops</code>: The root element. It can contain any number\nof <code>pkg</code> or package <code>uid</code><ul class=incremental><li><p><code>v</code>: (optional, integer) The version number (default:\n<code>NO_VERSION</code> or <code>-1</code>)</ul><li><p><code>pkg</code>: Stores package info. It can contain any number\nof <code>uid</code><ul class=incremental><li><p><code>n</code>: (required, string) Name of the package</ul><li><p>Package <code>uid</code>: Stores package or packages info<ul class=incremental><li><p><code>n</code>: (required, integer) The user ID</ul><li><p><code>uid</code>: The package user ID. It can contain any number\nof <code>op</code><ul class=incremental><li><p><code>n</code>: (required, integer) The user ID<li><p><code>p</code>: (optional, boolean) Is the app is a\nprivate/system app</ul><li><p><code>op</code>: The operation, can contain <code>st</code> or\nnothing at all<ul class=incremental><li><p><code>n</code>: (required, integer) The op name in integer,\ni.e. AppOpsManager.OP_*<li><p><code>m</code>: (required, integer) The op mode,\ni.e. AppOpsManager.MODE_*</ul><li><p><code>st</code>: State of operation: whether the operation is\naccessed, rejected or running (not available on old versions)<ul class=incremental><li><p><code>n</code>: (required, long) Key containing flags and\nuid<li><p><code>t</code>: (optional, long) Access time (default:\n<code>0</code>)<li><p><code>r</code>: (optional, long) Reject time (default:\n<code>0</code>)<li><p><code>d</code>: (optional, long) Access duration (default:\n<code>0</code>)<li><p><code>pp</code>: (optional, string) Proxy package name<li><p><code>pu</code>: (optional, integer) Proxy package uid</ul></ul><p>This definition can be found at <a href=https://android.googlesource.com/platform/frameworks/base/+/master/services/core/java/com/android/server/appop/AppOpsService.java>AppOpsService</a>.</section><section id=sec:appops-cli class=level2 data-number=7.6><h2 data-number=7.6><span class=header-section-number>7.6</span> <a href=#toc:sec:appops-cli>Command Line Interface</a><a href=#sec:appops-cli class=anchor aria-hidden=true></a></h2><p><code>appops</code> or <code>cmd appops</code> (on latest versions)\ncan be accessible via ADB or root. This is an easier method to get or\nupdate any operation for a package (provided the package name is known).\nThe help page of this command is self-explanatory:<pre><code>AppOps service (appops) commands:\nhelp\nPrint this help text.\nstart [--user &lt;USER_ID&gt;] &lt;PACKAGE | UID&gt; &lt;OP&gt;\nStarts a given operation for a particular application.\nstop [--user &lt;USER_ID&gt;] &lt;PACKAGE | UID&gt; &lt;OP&gt;\nStops a given operation for a particular application.\nset [--user &lt;USER_ID&gt;] &lt;[--uid] PACKAGE | UID&gt; &lt;OP&gt; &lt;MODE&gt;\nSet the mode for a particular application and operation.\nget [--user &lt;USER_ID&gt;] &lt;PACKAGE | UID&gt; [&lt;OP&gt;]\nReturn the mode for a particular application and optional operation.\nquery-op [--user &lt;USER_ID&gt;] &lt;OP&gt; [&lt;MODE&gt;]\nPrint all packages that currently have the given op in the given mode.\nreset [--user &lt;USER_ID&gt;] [&lt;PACKAGE&gt;]\nReset the given application or all applications to default modes.\nwrite-settings\nImmediately write pending changes to storage.\nread-settings\nRead the last written settings, replacing current state in RAM.\noptions:\n&lt;PACKAGE&gt; an Android package name or its UID if prefixed by --uid\n&lt;OP&gt;      an AppOps operation.\n&lt;MODE&gt;    one of allow, ignore, deny, or default\n&lt;USER_ID&gt; the user id under which the package is installed. If --user is not\nspecified, the current user is assumed.</code></pre></section></section><section id=footnotes class=\"footnotes footnotes-end-of-document\" role=doc-endnotes><hr><ol><li id=fn1><p>For distributing normal releases only<a href=#fnref1 class=footnote-back role=doc-backlink>↩︎</a><li id=fn2><p>GitHub pull 요청은 해당되는 패치를 통해 수동으로\nmerge됩니다. 그 결과로, GitHub에 merged대신 closed로 잘못 표기될 수\n있습니다.<a href=#fnref2 class=footnote-back role=doc-backlink>↩︎</a><li id=fn3><p>“Muntashir Akon” 이라고 불러도 됩니다<a href=#fnref3 class=footnote-back role=doc-backlink>↩︎</a></ol></section>"
  },
  {
    "path": "docs/raw/ko/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"titlepage$user_manual\">영어 \n\\n{\\\\huge\\\\bfseries 사용자 매뉴얼\\\\par}</string>\n    <string name=\"intro$main$intro\">App Manager는 안드로이드용 고급 패키지 매니저입니다. 수많은 기능을 갖추고 있어 사용자를\n\\n지원하기 위한 사용자 매뉴얼이 필요합니다. 이 문서는 App Manager가 제공하는 모든 기능을 설명하는 것을 목적으로\n\\n하며 App Manager 의 사용자 매뉴얼로 기능합니다. 또한 이 문서는 App Manager의 공식 가이드라인으로 볼 수도 있고\n\\nApp Manager가 원하는 동작을 나타내기도 합니다. 번역에 의해 이 문서(영어로 쓰여저 있다)가 오해 받을\n\\n가능성이 있습니다. 따라서, 모든 유능한 사용자는 App Manager를 최대한 활용하기 위해 영문 문서를\n\\n읽어야 합니다. 블로그 기사, 비디오, 채팅 그룹 등 다른 비공식 또는 서드파티의 자원 역시 존재할 수\n\\n있습니다. 이러한 리소스는 많은 사람들에게 유용할 수 있지만 App Manager의 최신 버전을 지원하지\n\\n않을 수 있습니다. App Manager에서 해당 문서에서 일탈이 검출되면 App Manager의\n\\n\\\\href{https://github.com/MuntashirAkon/AppManager/issues}{App Manager 이슈 트래커}에서 보고해야 합니다.</string>\n    <string name=\"keywords$see_also\">\\\\newcommand{\\\\KeywordSeeAlso}{See also:}</string>\n    <string name=\"keywords$end_of_keyword_in_alert\">\\\\newcommand{\\\\KeywordEndOfKeyWordInAlert}{.}</string>\n    <string name=\"titlepage$quotation\">\\\\begin{quotation}\n\\n ``현명하고 신중해라. 빨리 달리면 넘어지게 마련이다.\\'\\'\n\\n %\\\\sourceatright\n\\n {--- 수도사 로렌스, \\\\textit{로미오와 줄리엣}}\n\\n \\\\end{quotation}</string>\n    <string name=\"intro$main$$introduction-chapter-title\">소개</string>\n    <string name=\"intro$main$$terminologies-title\">용어</string>\n    <string name=\"intro$main$$supported-versions-title\">지원되는 버전</string>\n    <string name=\"intro$main$$official-sources-title\">공식 출처</string>\n    <string name=\"intro$main$$bin-sources-title\">이진 배포 소스</string>\n    <string name=\"intro$main$$source-code-links-title\">소스 코드 링크</string>\n    <string name=\"intro$main$$translations-title\">번역</string>\n    <string name=\"intro$main$$contributing-title\">기여</string>\n    <string name=\"intro$main$$buiding-title\">빌드 설명</string>\n    <string name=\"intro$main$$submit-patches-title\">패치 제출</string>\n    <string name=\"intro$main$$donation-title\">기부 \\\\&amp; 자금</string>\n    <string name=\"intro$main$$contact-title\">연락처</string>\n    <string name=\"intro$main$terminologies\">\\\\begin{itemize}\n\\n \\\\item \\\\textbf{AM} --- App Manager의 약칭.\n\\n \\\\item \\\\textbf{Block/Unblock} --- 구성 요소 차단 또는 차단 해제에 사용됩니다. 구성 요소가 차단되는 방법은 사용자 기본 설정에 따라 설정됩니다.\n\\n \\\\item \\\\textbf{IFW} --- 의도된 방화벽의 약식입니다.\n\\n \\\\item \\\\textbf{Ops} --- 작업의 단축형 작업 이름(예:\\\\ app ops, 배치 ops, 원클릭 ops)\n\\n \\\\item \\\\textbf{SSAID} --- \\\\texttt{Settings.Secure.ANDROID\\\\_ID}의 짧은 형식입니다. 각 앱(안드로이드 오레오 이상)에 할당된 장치 식별자이다.\n\\n앱의 서명 인증서와 패키지 \\\\texttt{android}에 대한 SSAID 세트의 조합에서 생성됩니다. SSAID는 사용자가 장치를 초기화하지 않는 한 그 앱의 ID는 동일합니다.\n\\n그것은 추적에 널리 사용된다.\n\\n \\\\item \\\\textbf{Tracker} --- \\\\hyperref[sec:scanner-page]{scanner page}를 제외하고 문서 전체와 장치 관리자에서 추적기 구성 요소를 나타냅니다.\n\\n추적기에는 충돌 리포터, 분석, 자료 수집, 식별, 광고, 위치 등의 라이브러리가 포함됩니다. 따라서, 그들은 기능 면에서 같지 않습니다.\n\\n추적을 촉진하는 오픈 소스 라이브러리와 클로즈드 소스 라이브러리 사이에는 차이가 없습니다.\n\\n\\\\end{itemize}</string>\n    <string name=\"keywords$chapter\">\\\\newcommand{\\\\KeywordChapter}{Chapter}</string>\n    <string name=\"intro$main$source-code-links\">GitHub를 제외한 모두 미러 링크입니다. 태그는 항상 최신 상태이지만, 마스터 브랜치는 최신 상태를 보장할 수 없습니다. \n\\n마스터 브랜치를 복제(clone)하는 것이 목적이면, 다른 링크 대신 GitHub 링크를 사용하십시오.</string>\n    <string name=\"intro$main$contributing\">사용자가 기여할 수 있는 여러 방법이 있습니다. 예를 들어 유용한 문제를 제기, 토론에 참여,\n\\n문서화 및 번역을 개선, 인식되지 않은 라이브러리와 트래커 추가,\n\\n소스 코드 검토 및 보안 취약성 보고하기 등이 있습니다.</string>\n    <string name=\"intro$main$buiding\">빌드 지침은 소스의 루트 디렉터리에 있는 BUILDING 파일에서 찾을 수 있습니다.</string>\n    <string name=\"pages$main-page$$section-title\">메인 페이지</string>\n    <string name=\"pages$main-page$$how-app-ops-work-title\">메인 페이지의 앱 목록 항목</string>\n    <string name=\"intro$main$contact\">Muntashir Al-Islam\\\\footnote{``Muntashir Akon\\'\\' 이라고 불러도 됩니다}\\\\\\\\\n\\n이메일: \\\\href{mailto:muntashirakon@riseup.net}{muntashirakon [at] riseup [dot] net}\\\\\\\\\n\\nKey 지문: \\\\texttt{7bad37c2981e41f8f6abea7f58f0b4f26c346fce}\\\\\\\\\n\\nGitHub: \\\\url{https://github.com/MuntashirAkon}\\\\\\\\\n\\n트위터: \\\\url{https://twitter.com/Muntashir}</string>\n    <string name=\"pages$main-page$$instructions-title\">사용 설명서</string>\n    <string name=\"pages$main-page$$options-menu-title\">옵션 메뉴</string>\n    <string name=\"pages$main-page$$list-options-title\">옵션 나열</string>\n    <string name=\"pages$main-page$$sort-title\">정렬</string>\n    <string name=\"pages$main-page$$version-info-title\">버전 정보</string>\n    <string name=\"pages$main-page$$profile_name-title\">프로필 이름</string>\n    <string name=\"pages$main-page$$app-usage-title\">앱 사용량</string>\n    <string name=\"pages$main-page$$filter-title\">필터</string>\n    <string name=\"pages$main-page$profile_name\">\\\\hyperref[sec:profiles-page]{프로필}에만 존재하는 앱을 나열할 수도 있습니다. 이는\n\\n\\\\hyperref[sec:profiles-page]{프로필 페이지}에서 할 수 없는 특정 작업을 프로필에서\n\\n실행하는데 유용할 수 있습니다 (예를 들어, 해당 프로필의 앱을 전부 제거하기).</string>\n    <string name=\"pages$app-details-page$$servcies-title\">서비스</string>\n    <string name=\"pages$app-details-page$$receivers-title\">수신자</string>\n    <string name=\"pages$app-details-page$$providers-title\">공급자</string>\n    <string name=\"pages$app-details-page$$additional-features-for-rooted-phones-title\">루팅된 폰을 위한 추가 기능</string>\n    <string name=\"pages$app-details-page$$app-info-options-menu-title\">옵션 메뉴</string>\n    <string name=\"pages$app-details-page$$component-tabs-title\">구성 요소 탭</string>\n    <string name=\"pages$app-details-page$app-info-tab\">\\\\textbf{앱 정보} 탭에는 앱에 대한 일반 정보가 포함되어 있습니다. 또한 이 탭에서 수행할 수 있는\n\\n여러 작업도 나열됩니다.</string>\n    <string name=\"intro$main$supported-versions\">현재 지원되는 버전은 v3.0.4와 v3.1.0 (안정), v3.2.0 (알파 &amp; 디버그 릴리즈)입니다.\n\\nApp Manager의 이전 버전에는 보안 취약점이 있을 수 있으므로 사용하지 마십시오.</string>\n    <string name=\"pages$main-page$$colour-codes-title\">색상 코드</string>\n    <string name=\"pages$main-page$$application-types-title\">앱 종류</string>\n    <string name=\"pages$main-page$$running-apps-title\">실행 중인 앱</string>\n    <string name=\"pages$main-page$$profiles-title\">프로필</string>\n    <string name=\"pages$main-page$$apk-updater-title\">APK 업데이터</string>\n    <string name=\"pages$main-page$$settings-title\">설정</string>\n    <string name=\"pages$main-page$options-menu\">옵션 메뉴는 나열된 앱을 정렬 및 필터링하고 App Manager 내부 또는 외부의 다른 페이지로 이동하는 데\n\\n사용할 수 있는 여러가지 옵션을 제공합니다.</string>\n    <string name=\"pages$app-details-page$$section-title\">앱 세부정보 페이지</string>\n    <string name=\"pages$app-details-page$$colour-codes-title\">색상 코드</string>\n    <string name=\"pages$app-details-page$$app-info-tab-title\">앱 정보 탭</string>\n    <string name=\"pages$app-details-page$$app-info-general-information-title\">일반 정보</string>\n    <string name=\"pages$app-details-page$$permissions-title\">권한</string>\n    <string name=\"pages$app-details-page$$signatures-tab-title\">서명 탭</string>\n    <string name=\"pages$app-details-page$$shared-libs-tab-title\">공유 라이브러리 탭</string>\n    <string name=\"pages$app-details-page$intro\">\\\\textbf{앱 세부정보} 페이지는11 (십일)개의 탭으로 구성되있습니다. Manifest의 모든 속성,\n\\n\\\\hyperref[ch:app-ops]{앱 작업}, 서명 정보, 라이브러리 등을 포함하여\n\\n앱이 가질 수 있는 거의 모든 정보를 설명합니다.</string>\n    <string name=\"pages$main$$pages-chapter-title\">페이지</string>\n    <string name=\"pages$main-page$$batch-operations-title\">일괄 작업</string>\n    <string name=\"pages$app-details-page$$uses-permissions-title\">권한 사용함</string>\n    <string name=\"pages$app-details-page$$blocking-components-title\">블로킹 구성 요소</string>\n    <string name=\"pages$main-page$$termux-title\">Termux</string>\n    <string name=\"pages$main-page$sort\">메인 페이지에 나열된 앱은 다음과 같은 방법으로 정렬될 수 있습니다:\n\\n\\\\begin{itemize}\n\\n \\\\item \\\\textbf{사용자 앱 우선.} 사용자 앱을 위에 표시\n\\n \\\\item \\\\textbf{앱 이름.} 앱 라벨에 따라 오름차순으로 정렬 (앱 라벨이란\n\\n \\\\textit{앱 이름}). 이것이 정렬 기본값입니다.\n\\n \\\\item \\\\textbf{패키지 이름.} 패키지 이름에 따라 오름차순으로 정렬\n\\n \\\\item \\\\textbf{마지막 업데이트.} 마지막 업데이트 된 날짜를 기준으로 내림차순 정렬\n\\n \\\\item \\\\textbf{공유 사용자 ID.} 공유 사용자의 커널 User ID에 따라 내림차순 정렬\n\\n \\\\item \\\\textbf{목표 SDK.} 목표 SDK에 따라 오름차순 정렬\n\\n \\\\item \\\\textbf{서명.} 서명 정보에 따라 오름차순 정렬\n\\n \\\\item \\\\textbf{비활성화 우선.} 비활성화 앱을 위에 표시\n\\n \\\\item \\\\textbf{차단 우션.} 각 앱의 차단된 구성 요소 개수에 따라 내림차순 정렬\n\\n \\\\item \\\\textbf{백업 완료 우선.} 백업이 된 앱을 위에 표시\n\\n \\\\item \\\\textbf{트래커.} 각 앱의 트래커 요소 개수에 따라 내림차순 정렬\n\\n \\\\item \\\\textbf{마지막 활동.} App Manager 내부 앱에 활동한 가장 최근 날짜와 시각에 따라 내림차순 정렬\n\\n\\\\end{itemize}\n\\n\n\\n추가적으로, 목록을 역순으로 정렬하는 데 사용할 수 있는 \\\\textit{반대로} 옵션이 있습니다.\n\\n정렬 설정에 상관없이 앱은 임의의 정렬 결과를 생성하지 않도록 처음에는\n\\n알파벳 순으로 정렬됩니다.</string>\n    <string name=\"pages$main-page$filter\">메인 페이지에 나열된 앱은 다음과 같이 필터링을 할 수 있습니다:\n\\n\\\\begin{itemize}\n\\n \\\\item \\\\textbf{사용자 앱.} 사용자 앱만 표시\n\\n \\\\item \\\\textbf{시스템 앱.} 시스템 앱만 표시\n\\n \\\\item \\\\textbf{비활성화 앱.} 비활성화 앱만 표시\n\\n \\\\item \\\\textbf{규칙 보유 앱.} 하나 이상의 블로킹 규칙이 있는 앱 표시\n\\n \\\\item \\\\textbf{활성화 앱.} 하나 이상의 활동 기록이 있는 앱 표시\n\\n \\\\item \\\\textbf{백업된 앱.} 하나 이상의 백업이 있는 앱 표시\n\\n \\\\item \\\\textbf{실행 중 앱.} 현재 실행 중인 앱 표시\n\\n \\\\item \\\\textbf{분기 앱.} 하나 이상의 분기 APK 파일이 있는 앱 표시\n\\n \\\\item \\\\textbf{설치된 앱.} 설치된 앱만 표시\n\\n \\\\item \\\\textbf{제거된 앱.} 제거된 앱만 표시\n\\n \\\\item \\\\textbf{백업 없는 앱.} 백업이 존재하지 않는 앱 표시\n\\n\\\\end{itemize}\n\\n\n\\n정렬과 달리 두 개 이상의 필터링 옵션을 동시에 적용할 수 있습니다. 예를 들어, \\\\textit{사용자 앱} 및 \\\\textit{비활성화 앱} 옵션을\n\\n둘 다 선택하여 사용하지 않도록 설정된 사용자 애플리케이션을 나열할 수 있습니다. 이는 특정 작업을\n\\n안전하게 수행하기 위해 사용자 앱을 필터링할 필요가 있는 \\\\hyperref[subsec:batch-operations]{배치 작업}에\n\\n특히 유용할 수 있다.</string>\n    <string name=\"intro$main$bin-sources\">App Manager는 다음 소스들을기반으로 배포하고 있습니다. 비공식 소스들은 App Manager의\n\\n변형된 버전을 배포할 수 있으며, 이러한 배포 버전을 사용했을 경우 모든 책임은 귀하에게 있습니다.\n\\n\\\\begin{enumerate}\n\\n \\\\item 공식 F-Droid Repository.\\\\footnote{For distributing normal releases only}\\\\\\\\\n\\n \\\\textit{Link:} \\\\url{https://f-droid.org/packages/io.github.muntashirakon.AppManager}\n\\n \\\\item GitHub repository.\\\\\\\\\n\\n \\\\textit{Normal releases:} \\\\url{https://github.com/MuntashirAkon/AppManager/releases}\\\\\\\\\n\\n \\\\textit{Debug releases:} \\\\url{https://github.com/MuntashirAkon/AppManager/actions}\n\\n \\\\item 텔레그램.\\\\\\\\\n\\n \\\\textit{Normal releases:} \\\\url{https://t.me/AppManagerChannel}\\\\\\\\\n\\n \\\\textit{Debug releases:} \\\\url{https://t.me/AppManagerDebug}\n\\n\\\\end{enumerate}</string>\n    <string name=\"intro$main$translations\">App Manager는 직접적인 pull/merge 요청의 번역은 수락하지 않습니다. 번역은 Hosted Weblate를 통해서 진행됩니다.\n\\nApp Manager를 번역하시려면, \\\\url{https://hosted.weblate.org/engage/app-manager/}을 방문해 주십시오.</string>\n    <string name=\"pages$main-page$colour-codes\">\\\\begin{itemize}\n\\n \\\\item \\\\colorbox{AMLightGreyishOrange}{\\\\textcolor{black}{Light greyish orange (day)}} / \\\\colorbox{AMDarkBlue}{\n\\n \\\\textcolor{white}{dark blue (night)}} -- 앱이 일괄 작업의 대상으로 선택되었습니다\n\\n \\\\item \\\\colorbox{AMLightRed}{\\\\textcolor{black}{Light red (day)}} / \\\\colorbox{AMVeryDarkRed}{\\\\textcolor{white}\n\\n {dark red (night)}} -- Frozen app\n\\n \\\\item \\\\colorbox{AMYellow}{\\\\textcolor{black}{Yellow Star}} -- Debuggable application\n\\n \\\\item \\\\textcolor{AMOrange}{Orange \\\\textit{Date}} -- 이 앱은 시스템 로그 접근 권한이 있습니다\n\\n \\\\item \\\\textcolor{AMOrange}{Orange \\\\textit{UID}} -- 사용자 ID가 여러 앱에서 공유되고 있습니다\n\\n \\\\item \\\\textcolor{AMOrange}{Orange \\\\textit{SDK}} -- 이 앱은 클리어 텍스트를 사용할 수도 있습니다 (i.e. HTTP)\n\\n \\\\item \\\\textcolor{red}{Red \\\\textit{package name}} -- 이 앱은 데이터 삭제를 허용하지 않습니다\n\\n \\\\item \\\\textcolor{red}{Red \\\\textit{backup}} -- 제거된 앱이 App Manager에 하나 이상의 백업을 가지고 있습니다\n\\n \\\\item \\\\textcolor{AMOrange}{Orange \\\\textit{backup}} -- 기존 백업이 설치된 앱의 구 버전을 포함하고 있습니다\n\\n \\\\item \\\\textcolor{AMDarkCyan}{Dark cyan \\\\textit{backup}} -- 즉 기존 백입이 설치된 앱과 동일하거나 상위 버전을 포함하고 있습니다.\n\\n \\\\item \\\\textcolor{AMDarkCyan}{Dark cyan \\\\textit{package name}} -- 강제 중지된 앱\n\\n \\\\item \\\\textcolor{AMDarkCyan}{Dark cyan \\\\textit{version}} -- 비활성화된 앱\n\\n \\\\item \\\\textcolor{magenta}{Magenta} -- Persistent 앱 i.e. 항상 실행 중인 앱.\n\\n\\\\end{itemize}</string>\n    <string name=\"pages$main-page$running-apps\">이 메뉴 항목은 실행 중인 앱 또는 프로세스 목록이 표시되는 새 페이지를 엽니다. 추가적으로 현재 메모리 및\n\\n캐시 사용량(있을 경우)도 표시합니다. root 또는 ADB를 App Manager에서 사용할 수 없는 경우 안드로이드\n\\n최신 버전에서만 표시됩니다. 실행 중인 앱 또는 프로세스는 해당 페이지 내에서 강제종료되거나 종료될\n\\n수도 있습니다 .각 프로세스 ID(PID)에 대한 로그는 \\\\hyperref[subsec:log-viewer]{log viewer}에서도 볼 수 있습니다.\n\\n추가적으로, 아이콘을 클릭하거나 항목을 길게 클릭하여 배치 작업을 수행할 수도 있습니다.\n\\n항목을 그냥 클릭하면 세부정보가 표시되는 대화창이 열립니다.</string>\n    <string name=\"intro$main$submit-patches\">GitHub 이외의 사이트에 위치한 repository는 현재 미러로 간주되며, 미러 사이트에서 pull/merge 요청은\n\\n받아들여지지 않을 것입니다. \\\\footnote{GitHub pull 요청은 해당되는 패치를 통해 수동으로 merge됩니다.\n\\n그 결과로, GitHub에 merged대신 closed로 잘못 표기될 수 있습니다.} 대신, 패치(\\\\texttt{.patch} 파일 형식)들은\n\\n이메일 첨부 파일로 제출할 수 있습니다. \\\\textit{Signing-off 서명은 필수입니다.} 자세한 내용은 소스의 \n\\n루트 디렉토리에 CONTRIBUTING 파일은 참고하십시오.\n\\n\n\\n\\\\begin{warning}{Notice}\n\\n 이메일로 패치 제출, 향후 대화 전체를 공개적으로 접근할 수도 있습니다 . 그러므로\n\\n 이름과 이메일 주소 외에는 개인 식별 정보(PII)는 포함하지 마십시오.\n\\n\\\\end{warning}</string>\n    <string name=\"intro$main$donation\">\\\\emph{기부금이나 구매는 App Manager사용을 위한 필수 조건이 아닙니다.} App Manager 어떤 구매도 지원하지 않지만,\n\\nOpen Source Collective를 통해 기부금을 보낼 수 있습니다.\n\\n\n\\nOpen Source Collective는 오픈소스 프로젝트들의 재정 관리를 도와주는 Open Collective 플랫폼의\n\\n재정 호스트입니다. 현재는 계좌 이체, 페이팔, 신용카드나 암호화폐를 통한\n\\n결제를 지원하고 있습니다.\n\\n\n\\n\\\\textit{링:} \\\\url{https://opencollective.com/muntashir}.\n\\n\n\\n기부금을 보내는 사람들은 자신들이 요청하는 기능이 우선적으로 추가되도록 요구하는 지렛대가 되도록 기부금을\n\\n사용해서는 안 된다는 데 동의한다. 기능 요청은 어떠한 현상금이나 기부도 필요하지 않으며,\n\\n개발자의 선호도에 따라 우선순위가 정해집니다.\n\\n\n\\n\\\\emph{App Manager는 모든 지원금이나 보조금을 제안을 수락합니 .} 관심있는 조직들의 대표자분들은 \n\\n\\\\Sref{sec:contact}에 주어진 옵션을 통해 소유자에게 직접 연락을 취할 수 있습니다.</string>\n    <string name=\"pages$app-details-page$$permission-tabs-title\">권한 탭</string>\n    <string name=\"pages$main-page$intro\">메인 페이지에는 설치, 제거 또는 백업된 모든 앱이 나열됩니다. 설치된 앱 항복을 클릭하면\n\\n해당되는 \\\\hyperref[sec:app-details-page]{앱 세부정보 페이지}를 엽니다. 제거된 시스템 앱의 경우, 앱을 다시\n\\n설치할 수 있는 대화 상자 프롬프트가 표시됩니다. 목록 옵션에서 \\\\hyperlink{par:main-page-sort}{정렬} 옵션을\n\\n사용하면, 앱 항목들을 다양한 방법으로 정렬하고 종료 시 저장할 수 있습니다. 목록 옵션에서\n\\n\\\\hyperlink{par:main-page-filter}{filter} 옵션을 사용해서 항목을 필터링할 수도 있습니다. 정규식을 추가적으로 지원하는\n\\n검색창을 통해서도 필터링이 가능합니다.</string>\n    <string name=\"pages$main-page$batch-operations\">여러 앱에서의 배치 작업 혹은 작업도 이 페이지에서 가능합니다. 앱 아이콘을 클릭하거나 목록의 항목을\n\\n길게 클릭하여 다중 선택 모드를 활성화할 수 있습니다. 활성화 후, 목록 항목을 클릭하면\n\\n앱 세부 정보 페이지를 여는 대신 해당 항목이 선택됩니다. 이 모드에서, 배치 작업은 페이지 하단의\n\\n다중 선택 메뉴에 있습니다. 포함된 작업은:\n\\n\\\\begin{itemize}\n\\n \\\\item 선택된 앱을 \\\\hyperref[sec:profiles-page]{프로필}에 추가하기\n\\n \\\\item 앱을 \\\\hyperref[sec:backup-restore]{백업, 복구 혹은 삭제} \n\\n \\\\item 앱에서의 트래커를 차단하기\n\\n \\\\item 앱에서 데이터 혹은 캐시 삭제하기\n\\n \\\\item 앱을 활성화/비활성화/강제종료/제거하기\n\\n \\\\item App Manager에 저장된 블록킹 규칙을 내보내기\n\\n \\\\item 앱의 백그라운드 실행을 방지하기 (안드로이드 7부터)\n\\n \\\\item APK 파일을 \\\\texttt{AppManager/apks}에 저장하기\n\\n \\\\item \\\\hyperref[sec:net-policy]{네트워크 정책} 설정하기\n\\n\\\\end{itemize}\n\\n\n\\n\\\\begin{tip}{Accessibility}\n\\n 다중 선택 모드 활성화 후, 키보드 혹은 리모컨의 좌우 버튼을 사용해서\n\\n다중 선택 영역 탐색이 가능합니다.\n\\n\\\\end{tip}</string>\n    <string name=\"pages$main-page$application-types\">앱은 다음 접미사를 가지는 \\\\textbf{사용자} 혹은 \\\\textbf{시스템} 앱일 수 있습니다:\n\\n\\\\begin{itemize}\n\\n \\\\item \\\\texttt{X} -- 다수의 아키텍쳐 지원\n\\n \\\\item \\\\texttt{0} -- 앱에 dex 파일이 존재하지 않습니다\n\\n \\\\item \\\\texttt{°} -- 일시정지된 앱\n\\n \\\\item \\\\texttt{\\\\#} -- 앱이 시스템에 큰 힙 할당을 요청했습니다 (i.e. 큰 런타임 메모리)\n\\n \\\\item \\\\texttt{\\?} -- 앱이 가상 머신이 안전 모드에 있도록 요청했습니다.\n\\n\\\\end{itemize}</string>\n    <string name=\"pages$main-page$version-info\">버전 이름 뒤에는 아래의 접두사가 붙습니다:\n\\n\\\\begin{itemize}\n\\n \\\\item \\\\texttt{\\\\_} -- 하드웨어 가속 없음(앱 내 애니메이션 또는 투명도 저하)\n\\n \\\\item \\\\texttt{\\\\textasciitilde} -- 테스트 전용 앱\n\\n \\\\item \\\\texttt{debug} -- 디버깅 가능 앱\n\\n\\\\end{itemize}</string>\n    <string name=\"pages$main-page$instructions\">\\\\textbf{Instructions} 를 클릭하면 App Manager 사용 설명서의 오프라인 버전이 열립니다. 해당 기능\n\\n(i.e.\\\\ \\\\texttt{feat\\\\_docs})이 설치되어 있지 않거나, 설명서를 로드할 WebView가 시스템에 존재하지 않을 경우\n\\n온라인 버전이 열릴 수 있습니다.</string>\n    <string name=\"pages$main-page$list-options\">\\\\textbf{List options} 는 메인 페이지의 리스트 정렬 및 필터링을 하는 옵션이 있습니다.</string>\n    <string name=\"pages$app-details-page$colour-codes\">이 페이지에 사용된 색상과, 각 색상의 의미:\n\\n\\\\begin{itemize}\n\\n \\\\item \\\\colorbox{AMRed}{\\\\textcolor{black}{Red (day)}} / \\\\colorbox{AMDarkRed}{\\\\textcolor{white}{dark red (night)}}\n\\n -- 위험 플래그가 있는 앱 권한 혹은 앱 관리자 내에서 차단된 구성 요소를 나타냅니다.\n\\n\n\\n \\\\item \\\\colorbox{AMLightRed}{\\\\textcolor{black}{Light red (day)}} / \\\\colorbox{AMVeryDarkRed}{\\\\textcolor{white}{very\n\\n dark red (night)}} -- App Manager 외부에서는 비활성화 되는 구성 요소를 나타냅니다.\n\\n\n\\n \\\\begin{tip}{Note}\n\\n 구성 요소가 비활성화로 표시된 경우 항상 사용자에 의해 비활성화된 것은 아닙니다. 시스템에서 비활성화하거나\n\\n Manifest에서 비활성화로 표시될 수도 있습니다. 비활성화된 앱의 구성 요소도 시스템(및 App Manager)에 의해\n\\n비활성화된 것으로 간주됩니다.\n\\n \\\\end{tip}\n\\n\n\\n \\\\item \\\\colorbox{AMVividOrange}{\\\\textcolor{black}{Vivid orange (day)}} / \\\\colorbox{AMVeryDarkOrange}{\n\\n \\\\textcolor{white}{very dark orange (night)}} -- 트래커 구성 요소를 나타냅니다.\n\\n\n\\n \\\\item \\\\colorbox{AMSoftMagenta}{\\\\textcolor{black}{Soft magenta (day)}} / \\\\colorbox{AMVeryDarkViolet}{\n\\n \\\\textcolor{white}{very dark violet (night)}} -- 실행 중인 서비스를 나타냅니다.\n\\n\\\\end{itemize}</string>\n    <string name=\"pages$app-details-page$permissions\">\\\\textbf{권한}은 보통 앱 내에서 정의된 커스텀 권한입니다. 이러한 종류의 권한은\n\\n\\\\textit{내부} 권한으로 표시됩니다. 다른 앱에서도 선언되고 \\\\textit{외부} 권한으로\n\\n표시된 권한도 포함됩니다. 외부 권한은 앱 구성 요소에서 종속적인 권한으로 지정됩니다.\n\\n즉, 앱은 지정된 권한을 직접 보유하는 경우에만 구성 요소를 호출할 수 있습니다.\n\\n다음은 표시되는 각 항목에 대한 전체 설명입니다.\n\\n\\\\begin{itemize}\n\\n \\\\item \\\\textbf{이름.} 각 권한은 \\\\texttt{android.permission.INTERNET}와 같은 고유한 이름이 있지만\n\\n여러 앱이 동일한 권한을 요청할 수 있습니다.\n\\n\n\\n \\\\item \\\\textbf{아이콘.} 각 권한은 커스텀 아이콘을 가질 수 있습니다. 다른 권한 탭들은 앱 manifest에\n\\n아이콘이 없기 때문에, 아이콘이 없습니다.\n\\n\n\\n \\\\item \\\\textbf{설명.} 이 선택 필드는 권한을 설명합니다. 권한과 관련된 설명이 없으면\n\\n이 필드가 표시되지 않습니다.\n\\n\n\\n \\\\item \\\\textbf{플래그.} (Uses the flag symbol or \\\\textbf{Protection Level} name) \\\\textit{normal}, \\\\textit{development},\n\\n\\\\textit{dangerous}, \\\\textit{instant}, \\\\textit{granted}, \\\\textit{revoked}, \\\\textit{signature}, \\\\textit{privileged},\n\\n등과 같은 다양한 권한 플래그를 설명합니다.\n\\n\n\\n \\\\item \\\\textbf{패키지 이름.} 권한과 연결된 패키지 이름을 나타냅니다\n\\n(권한을 정의한 패키지 이름)\n\\n\n\\n \\\\item \\\\textbf{그룹.} 권한과 관련된 그룹 이름(있을 경우). 서로 연관된 여러 권한이\n\\n그룹으로 묶일 수 있습니다.\n\\n\\\\end{itemize}</string>\n    <string name=\"pages$main-page$$1-click-ops-title\">원터치 작업</string>\n</resources>"
  },
  {
    "path": "docs/raw/pt/index.html",
    "content": "<!doctype html><html xmlns=http://www.w3.org/1999/xhtml lang=pt xml:lang=pt><meta charset=utf-8><meta name=generator content=\"pandoc\"><meta name=viewport content=\"width=device-width,initial-scale=1,user-scalable=yes\"><meta name=author content=\"Muntashir Al-Islam\"><title>App Manager</title><style>code{white-space:pre-wrap}span.smallcaps{font-variant:small-caps}div.columns{display:flex;gap:min(4vw,1.5em)}div.column{flex:auto;overflow-x:auto}div.hanging-indent{margin-left:1.5em;text-indent:-1.5em}ul.task-list[class]{list-style:none}ul.task-list li input[type=checkbox]{font-size:inherit;width:.8em;margin:0 .8em .2em -1.6em;vertical-align:middle}.display.math{display:block;text-align:center;margin:.5rem auto}html{-webkit-text-size-adjust:100%}pre>code.sourceCode{white-space:pre;position:relative}pre>code.sourceCode>span{display:inline-block;line-height:1.25}pre>code.sourceCode>span:empty{height:1.2em}.sourceCode{overflow:visible}code.sourceCode>span{color:inherit;text-decoration:inherit}div.sourceCode{margin:1em 0}pre.sourceCode{margin:0}@media screen{div.sourceCode{overflow:auto}}@media print{pre>code.sourceCode{white-space:pre-wrap}pre>code.sourceCode>span{text-indent:-5em;padding-left:5em}}pre.numberSource code{counter-reset:source-line 0}pre.numberSource code>span{position:relative;left:-4em;counter-increment:source-line}pre.numberSource code>span>a:first-child::before{content:counter(source-line);position:relative;left:-1em;text-align:right;vertical-align:baseline;border:none;display:inline-block;-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;padding:0 4px;width:4em}pre.numberSource{margin-left:3em;padding-left:4px}div.sourceCode{}@media screen{pre>code.sourceCode>span>a:first-child::before{text-decoration:underline}}code span.al{font-weight:700}code span.an{font-style:italic}code span.cf{font-weight:700}code span.co{font-style:italic}code span.cv{font-style:italic}code span.do{font-style:italic}code span.dt{text-decoration:underline}code span.er{font-weight:700}code span.in{font-style:italic}code span.kw{font-weight:700}code span.pp{font-weight:700}code span.wa{font-style:italic}</style><link rel=stylesheet href=../css/custom.css><header id=title-block-header><h1 class=title>App Manager</h1><p class=author>Muntashir Al-Islam</header><nav id=TOC role=doc-toc><ul class=incremental><li><span><span class=toc-section-number>1</span> <a href=#ch:introduction id=toc:ch:introduction>Introduction</a></span><ul class=incremental><li><span><span class=toc-section-number>1.1</span> <a href=#sec:terminologies id=toc:sec:terminologies>Terminologies</a></span><li><span><span class=toc-section-number>1.2</span> <a href=#sec:supported-versions id=toc:sec:supported-versions>Supported\nVersions</a></span><li><span><span class=toc-section-number>1.3</span> <a href=#sec:official-sources id=toc:sec:official-sources>Official\nSources</a></span><ul class=incremental><li><span><span class=toc-section-number>1.3.1</span> <a href=#subsec:binary-distribution-sources id=toc:subsec:binary-distribution-sources>Binary Distribution\nSources</a></span><li><span><span class=toc-section-number>1.3.2</span> <a href=#subsec:links-to-source-code id=toc:subsec:links-to-source-code>Links to the Source\nCode</a></span><li><span><span class=toc-section-number>1.3.3</span> <a href=#subsec:translations id=toc:subsec:translations>Translations</a></span></ul><li><span><span class=toc-section-number>1.4</span> <a href=#sec:contributing id=toc:sec:contributing>Contributing</a></span><ul class=incremental><li><span><span class=toc-section-number>1.4.1</span> <a href=#subsec:build-instructions id=toc:subsec:build-instructions>Build Instructions</a></span><li><span><span class=toc-section-number>1.4.2</span> <a href=#subsec:submitting-patches id=toc:subsec:submitting-patches>Submitting patches</a></span></ul><li><span><span class=toc-section-number>1.5</span> <a href=#sec:donation-&-funding id=toc:sec:donation-&-funding>Donation &\nFunding</a></span><li><span><span class=toc-section-number>1.6</span> <a href=#sec:contact id=toc:sec:contact>Contact</a></span></ul><li><span><span class=toc-section-number>2</span> <a href=#ch:pages id=toc:ch:pages>Pages</a></span><ul class=incremental><li><span><span class=toc-section-number>2.1</span> <a href=#sec:main-page id=toc:sec:main-page>Main Page</a></span><ul class=incremental><li><span><span class=toc-section-number>2.1.1</span> <a href=#subsec:batch-operations id=toc:subsec:batch-operations>Batch\nOperations</a></span><li><span><span class=toc-section-number>2.1.2</span> <a href=#subsec:main-colour-codes id=toc:subsec:main-colour-codes>Colour Codes</a></span><li><span><span class=toc-section-number>2.1.3</span> <a href=#subsec:main-page-application-types id=toc:subsec:main-page-application-types>Application\nTypes</a></span><li><span><span class=toc-section-number>2.1.4</span> <a href=#subsec:main-page-version-info id=toc:subsec:main-page-version-info>Version Info</a></span><li><span><span class=toc-section-number>2.1.5</span> <a href=#subsec:main-page-options-menu id=toc:subsec:main-page-options-menu>Options Menu</a></span></ul><li><span><span class=toc-section-number>2.2</span> <a href=#sec:app-details-page id=toc:sec:app-details-page>App Details\nPage</a></span><ul class=incremental><li><span><span class=toc-section-number>2.2.1</span> <a href=#subsec:app-details-colour-codes id=toc:subsec:app-details-colour-codes>Colour Codes</a></span><li><span><span class=toc-section-number>2.2.2</span> <a href=#subsec:app-info-tab id=toc:subsec:app-info-tab>App Info\nTab</a></span><li><span><span class=toc-section-number>2.2.3</span> <a href=#subsec:component-tabs id=toc:subsec:component-tabs>Component\nTabs</a></span><li><span><span class=toc-section-number>2.2.4</span> <a href=#subsec:permission-tabs id=toc:subsec:permission-tabs>Permission Tabs</a></span><li><span><span class=toc-section-number>2.2.5</span> <a href=#subsec:signatures-tab id=toc:subsec:signatures-tab>Signatures\nTab</a></span><li><span><span class=toc-section-number>2.2.6</span> <a href=#subsec:uses-features-tab id=toc:subsec:uses-features-tab>Uses\nFeatures tab</a></span><li><span><span class=toc-section-number>2.2.7</span> <a href=#subsec:configurations-tab id=toc:subsec:configurations-tab>Configurations tab</a></span><li><span><span class=toc-section-number>2.2.8</span> <a href=#subsec:shared-libs-tab id=toc:subsec:shared-libs-tab>Shared\nLibraries Tab</a></span></ul><li><span><span class=toc-section-number>2.3</span> <a href=#sec:1-click-ops-page id=toc:sec:1-click-ops-page>1-Click Ops\nPage</a></span><ul class=incremental><li><span><span class=toc-section-number>2.3.1</span> <a href=#subsec:block-unblock-trackers id=toc:subsec:block-unblock-trackers>Block/Unblock\nTrackers</a></span><li><span><span class=toc-section-number>2.3.2</span> <a href=#subsec:block-components-dots id=toc:subsec:block-components-dots>Block Components…</a></span><li><span><span class=toc-section-number>2.3.3</span> <a href=#subsec:set-mode-for-app-ops-dots id=toc:subsec:set-mode-for-app-ops-dots>Set Mode for App\nOps…</a></span><li><span><span class=toc-section-number>2.3.4</span> <a href=#subsec:1-click-back-up id=toc:subsec:1-click-back-up>Back\nup</a></span><li><span><span class=toc-section-number>2.3.5</span> <a href=#subsec:1-click-restore id=toc:subsec:1-click-restore>Restore</a></span><li><span><span class=toc-section-number>2.3.6</span> <a href=#subsec:trim-caches-in-all-apps id=toc:subsec:trim-caches-in-all-apps>Trim Caches in All\nApps</a></span></ul><li><span><span class=toc-section-number>2.4</span> <a href=#sec:profiles-page id=toc:sec:profiles-page>Profiles\nPage</a></span><ul class=incremental><li><span><span class=toc-section-number>2.4.1</span> <a href=#subsec:profiles-options-menu id=toc:subsec:profiles-options-menu>Options Menu</a></span></ul><li><span><span class=toc-section-number>2.5</span> <a href=#sec:profile-page id=toc:sec:profile-page>Profile\nPage</a></span><ul class=incremental><li><span><span class=toc-section-number>2.5.1</span> <a href=#subsec:profile-options-menu id=toc:subsec:profile-options-menu>Options Menu</a></span><li><span><span class=toc-section-number>2.5.2</span> <a href=#subsec:profile-apps-tab id=toc:subsec:profile-apps-tab>Apps\nTab</a></span><li><span><span class=toc-section-number>2.5.3</span> <a href=#subsec:profile-configurations-tab id=toc:subsec:profile-configurations-tab>Configurations\nTab</a></span></ul><li><span><span class=toc-section-number>2.6</span> <a href=#sec:settings-page id=toc:sec:settings-page>Settings\nPage</a></span><ul class=incremental><li><span><span class=toc-section-number>2.6.1</span> <a href=#subsec:language id=toc:subsec:language>Language</a></span><li><span><span class=toc-section-number>2.6.2</span> <a href=#subsec:appearance id=toc:subsec:appearance>Appearance</a></span><li><span><span class=toc-section-number>2.6.3</span> <a href=#subsec:privacy id=toc:subsec:privacy>Privacy</a></span><li><span><span class=toc-section-number>2.6.4</span> <a href=#subsec:mode-of-operation id=toc:subsec:mode-of-operation>Mode\nof Operation</a></span><li><span><span class=toc-section-number>2.6.5</span> <a href=#subsec:apk-signing id=toc:subsec:apk-signing>APK\nSigning</a></span><li><span><span class=toc-section-number>2.6.6</span> <a href=#subsec:installer id=toc:subsec:installer>Installer</a></span><li><span><span class=toc-section-number>2.6.7</span> <a href=#subsec:backup/restore id=toc:subsec:backup/restore>Back\nup/Restore</a></span><li><span><span class=toc-section-number>2.6.8</span> <a href=#subsec:rules id=toc:subsec:rules>Rules</a></span><li><span><span class=toc-section-number>2.6.9</span> <a href=#subsec:advanced id=toc:subsec:advanced>Advanced</a></span><li><span><span class=toc-section-number>2.6.10</span> <a href=#subsec:device-info id=toc:subsec:device-info>About the\ndevice</a></span></ul><li><span><span class=toc-section-number>2.7</span> <a href=#sec:scanner-page id=toc:sec:scanner-page>Scanner\nPage</a></span><li><span><span class=toc-section-number>2.8</span> <a href=#sec:interceptor-page id=toc:sec:interceptor-page>Interceptor\nPage</a></span><ul class=incremental><li><span><span class=toc-section-number>2.8.1</span> <a href=#subsec:intent-filters id=toc:subsec:intent-filters>Intent\nFilters</a></span><li><span><span class=toc-section-number>2.8.2</span> <a href=#subsec:matching-activities id=toc:subsec:matching-activities>Matching Activities</a></span><li><span><span class=toc-section-number>2.8.3</span> <a href=#subsec:interceptor-reset-to-default id=toc:subsec:interceptor-reset-to-default>Reset to\nDefault</a></span><li><span><span class=toc-section-number>2.8.4</span> <a href=#subsec:interceptor-send-edited-intent id=toc:subsec:interceptor-send-edited-intent>Send Edited\nIntent</a></span></ul><li><span><span class=toc-section-number>2.9</span> <a href=#sec:shared-preferences-editor-page id=toc:sec:shared-preferences-editor-page>Shared Preferences Editor\nPage</a></span></ul><li><span><span class=toc-section-number>3</span> <a href=#ch:guides id=toc:ch:guides>Guides</a></span><ul class=incremental><li><span><span class=toc-section-number>3.1</span> <a href=#sec:adb-over-tcp id=toc:sec:adb-over-tcp>ADB over\nTCP</a></span><ul class=incremental><li><span><span class=toc-section-number>3.1.1</span> <a href=#subsec:enable-developer-options id=toc:subsec:enable-developer-options>Enable developer\noptions</a></span><li><span><span class=toc-section-number>3.1.2</span> <a href=#subsec:enable-usb-debugging id=toc:subsec:enable-usb-debugging>Enable USB\ndebugging</a></span><li><span><span class=toc-section-number>3.1.3</span> <a href=#subsec:setup-adb-on-pc-or-mac id=toc:subsec:setup-adb-on-pc-or-mac>Setup ADB on PC or\nMac</a></span><li><span><span class=toc-section-number>3.1.4</span> <a href=#subsec:configure-adb-over-tcp id=toc:subsec:configure-adb-over-tcp>Configure ADB over\nTCP</a></span></ul><li><span><span class=toc-section-number>3.2</span> <a href=#sec:wireless-debugging id=toc:sec:wireless-debugging>Wireless\nDebugging</a></span><ul class=incremental><li><span><span class=toc-section-number>3.2.1</span> <a href=#subsec:enable-developer-options-and-usb-debugging id=toc:subsec:enable-developer-options-and-usb-debugging>Enable\ndeveloper options and USB Debugging</a></span><li><span><span class=toc-section-number>3.2.2</span> <a href=#subsec:enable-wireless-debugging id=toc:subsec:enable-wireless-debugging>Enable Wireless\nDebugging</a></span><li><span><span class=toc-section-number>3.2.3</span> <a href=#subsec:pair-adb-with-app-manager id=toc:subsec:pair-adb-with-app-manager>Pair ADB with App\nManager</a></span><li><span><span class=toc-section-number>3.2.4</span> <a href=#subsec:connect-app-manager-to-adb id=toc:subsec:connect-app-manager-to-adb>Connect App Manager to\nADB</a></span></ul><li><span><span class=toc-section-number>3.3</span> <a href=#sec:backup-restore id=toc:sec:backup-restore>Back\nup/Restore</a></span><ul class=incremental><li><span><span class=toc-section-number>3.3.1</span> <a href=#subsec:backup-location id=toc:subsec:backup-location>Location</a></span><li><span><span class=toc-section-number>3.3.2</span> <a href=#subsec:backup-restore-backup-options id=toc:subsec:backup-restore-backup-options>Backup\nOptions</a></span><li><span><span class=toc-section-number>3.3.3</span> <a href=#subsec:backup-restore-backup id=toc:subsec:backup-restore-backup>Backup</a></span><li><span><span class=toc-section-number>3.3.4</span> <a href=#subsec:backup-restore-restore id=toc:subsec:backup-restore-restore>Restore</a></span><li><span><span class=toc-section-number>3.3.5</span> <a href=#subsec:backup-restore-delete-backup id=toc:subsec:backup-restore-delete-backup>Delete\nBackup</a></span></ul><li><span><span class=toc-section-number>3.4</span> <a href=#sec:automating-tasks id=toc:sec:automating-tasks>Automating\nTasks</a></span><ul class=incremental><li><span><span class=toc-section-number>3.4.1</span> <a href=#subsec:generating-authorization-key id=toc:subsec:generating-authorization-key>Generating authorization\nkey</a></span><li><span><span class=toc-section-number>3.4.2</span> <a href=#subsec:at:general-configuration id=toc:subsec:at:general-configuration>Configuring\ntasks</a></span><li><span><span class=toc-section-number>3.4.3</span> <a href=#subsec:at:features id=toc:subsec:at:features>Features</a></span><li><span><span class=toc-section-number>3.4.4</span> <a href=#subsec:triggering-a-profile id=toc:subsec:triggering-a-profile>Triggering a\nprofile</a></span></ul><li><span><span class=toc-section-number>3.5</span> <a href=#sec:net-policy id=toc:sec:net-policy>Net\nPolicy</a></span></ul><li><span><span class=toc-section-number>4</span> <a href=#ch:faq id=toc:ch:faq>Frequently Asked Questions</a></span><ul class=incremental><li><span><span class=toc-section-number>4.1</span> <a href=#sec:faq:app-components id=toc:sec:faq:app-components>App\nComponents</a></span><ul class=incremental><li><span><span class=toc-section-number>4.1.1</span> <a href=#subsec:faq:what-are-app-components id=toc:subsec:faq:what-are-app-components>What are the application\ncomponents?</a></span><li><span><span class=toc-section-number>4.1.2</span> <a href=#subsec:faq:how-components-blocked id=toc:subsec:faq:how-components-blocked>How are the tracker and other\ncomponents blocked in App Manager? What are its\nlimitations?</a></span><li><span><span class=toc-section-number>4.1.3</span> <a href=#subsec:faq:components-blocked-by-others id=toc:subsec:faq:components-blocked-by-others>Does app components\nblocked by other tools retained in App Manager?</a></span><li><span><span class=toc-section-number>4.1.4</span> <a href=#subsec:faq:components-reblocked-in-am id=toc:subsec:faq:components-reblocked-in-am>What happens to the\ncomponents blocked by App Manager which were previously blocked by other\ntools?</a></span><li><span><span class=toc-section-number>4.1.5</span> <a href=#subsec:faq:what-is-instant-component-blocking id=toc:subsec:faq:what-is-instant-component-blocking>What is instant\ncomponent blocking?</a></span><li><span><span class=toc-section-number>4.1.6</span> <a href=#subsec:tracker-classes-versus-tracker-components id=toc:subsec:tracker-classes-versus-tracker-components>Tracker\nclasses versus tracker components</a></span></ul><li><span><span class=toc-section-number>4.2</span> <a href=#sec:faq:adb-over-tcp id=toc:sec:faq:adb-over-tcp>ADB over\nTCP</a></span><ul class=incremental><li><span><span class=toc-section-number>4.2.1</span> <a href=#subsec:faq:enable-adb-on-every-restart id=toc:subsec:faq:enable-adb-on-every-restart>Do I have to enable ADB\nover TCP everytime I restart?</a></span><li><span><span class=toc-section-number>4.2.2</span> <a href=#subsec:faq:usb-debugging id=toc:subsec:faq:usb-debugging>Cannot enable USB debugging. What to\ndo?</a></span><li><span><span class=toc-section-number>4.2.3</span> <a href=#subsec:faq:block-components-using-adb id=toc:subsec:faq:block-components-using-adb>Can I block tracker or\nany other application components using ADB over TCP?</a></span><li><span><span class=toc-section-number>4.2.4</span> <a href=#subsec:faq:adb-features id=toc:subsec:faq:adb-features>Which\nfeatures can be used in ADB mode?</a></span></ul><li><span><span class=toc-section-number>4.3</span> <a href=#sec:faq:miscellanea id=toc:sec:faq:miscellanea>Miscellanea</a></span><ul class=incremental><li><span><span class=toc-section-number>4.3.1</span> <a href=#subsec:faq:no-root-no-harms id=toc:subsec:faq:no-root-no-harms>I don’t use root/ADB. Am I\ncompletely safe from any harms?</a></span><li><span><span class=toc-section-number>4.3.2</span> <a href=#subsec:faq:how-trackers-libs-updated id=toc:subsec:faq:how-trackers-libs-updated>How are the trackers and\nlibraries are updated?</a></span><li><span><span class=toc-section-number>4.3.3</span> <a href=#subsec:faq:apks-deleted-after-installed id=toc:subsec:faq:apks-deleted-after-installed>Are APKs deleted after\ninstalled?</a></span><li><span><span class=toc-section-number>4.3.4</span> <a href=#subsec:faq:shizuku-support id=toc:subsec:faq:shizuku-support>Any plans for\nShizuku?</a></span><li><span><span class=toc-section-number>4.3.5</span> <a href=#subsec:faq:what-are-bloatware id=toc:subsec:faq:what-are-bloatware>What are bloatware and how to\nremove them?</a></span></ul></ul><li><span><span class=toc-section-number>5</span> <a href=#ch:specifications id=toc:ch:specifications>Specifications</a></span><ul class=incremental><li><span><span class=toc-section-number>5.1</span> <a href=#sec:rules-specification id=toc:sec:rules-specification>Rules\nSpecification</a></span><ul class=incremental><li><span><span class=toc-section-number>5.1.1</span> <a href=#background id=toc:background>Background</a></span><li><span><span class=toc-section-number>5.1.2</span> <a href=#rules-file-format id=toc:rules-file-format>Rules File\nFormat</a></span></ul></ul><li><span><span class=toc-section-number>6</span> <a href=#ch:changelogs id=toc:ch:changelogs>Changelogs</a></span><ul class=incremental><li><span><span class=toc-section-number>6.1</span> <a href=#sec:v4.0.5-(445) id=toc:sec:v4.0.5-(445)>v4.0.5\n(445)</a></span><li><span><span class=toc-section-number>6.2</span> <a href=#sec:v4.0.4-(444) id=toc:sec:v4.0.4-(444)>v4.0.4\n(444)</a></span><li><span><span class=toc-section-number>6.3</span> <a href=#sec:v4.0.3-(443) id=toc:sec:v4.0.3-(443)>v4.0.3\n(443)</a></span><li><span><span class=toc-section-number>6.4</span> <a href=#sec:v4.0.2-(442) id=toc:sec:v4.0.2-(442)>v4.0.2\n(442)</a></span><li><span><span class=toc-section-number>6.5</span> <a href=#sec:v4.0.1-(441) id=toc:sec:v4.0.1-(441)>v4.0.1\n(441)</a></span><ul class=incremental><li><span><span class=toc-section-number>6.5.1</span> <a href=#overlay-management id=toc:overlay-management>Overlay\nmanagement</a></span><li><span><span class=toc-section-number>6.5.2</span> <a href=#unfreeze-option-in-activity-shortcuts id=toc:unfreeze-option-in-activity-shortcuts>Unfreeze option in\nactivity shortcuts</a></span><li><span><span class=toc-section-number>6.5.3</span> <a href=#market-like-url-support id=toc:market-like-url-support><code>market</code>-like URL\nsupport</a></span><li><span><span class=toc-section-number>6.5.4</span> <a href=#updated-color-codes id=toc:updated-color-codes>Updated color\ncodes</a></span><li><span><span class=toc-section-number>6.5.5</span> <a href=#others id=toc:others>Others</a></span></ul><li><span><span class=toc-section-number>6.6</span> <a href=#sec:v4.0.0-(440) id=toc:sec:v4.0.0-(440)>v4.0.0\n(440)</a></span><ul class=incremental><li><span><span class=toc-section-number>6.6.1</span> <a href=#new-logo id=toc:new-logo>New logo!</a></span><li><span><span class=toc-section-number>6.6.2</span> <a href=#android-14-and-15-support id=toc:android-14-and-15-support>Android 14 and 15\nsupport</a></span><li><span><span class=toc-section-number>6.6.3</span> <a href=#revamped-debloater id=toc:revamped-debloater>Revamped\ndebloater</a></span><li><span><span class=toc-section-number>6.6.4</span> <a href=#introducing-file-manager id=toc:introducing-file-manager>Introducing file\nmanager</a></span><li><span><span class=toc-section-number>6.6.5</span> <a href=#integrated-code-editor id=toc:integrated-code-editor>Integrated code editor</a></span><li><span><span class=toc-section-number>6.6.6</span> <a href=#history-of-operations id=toc:history-of-operations>History of\noperations</a></span><li><span><span class=toc-section-number>6.6.7</span> <a href=#per-app-freezing-and-more id=toc:per-app-freezing-and-more>Per-app freezing, and\nmore</a></span><li><span><span class=toc-section-number>6.6.8</span> <a href=#log-viewer-enhancements id=toc:log-viewer-enhancements>Log\nviewer enhancements</a></span><li><span><span class=toc-section-number>6.6.9</span> <a href=#launching-non-exported-activities id=toc:launching-non-exported-activities>Launching non-exported\nactivities</a></span><li><span><span class=toc-section-number>6.6.10</span> <a href=#new-tags-in-app-info-tab id=toc:new-tags-in-app-info-tab>New\ntags in App Info tab</a></span><li><span><span class=toc-section-number>6.6.11</span> <a href=#per-session-installer-options id=toc:per-session-installer-options>Per-session installer\noptions</a></span><li><span><span class=toc-section-number>6.6.12</span> <a href=#advanced-mode-of-operations-adb-enhancements id=toc:advanced-mode-of-operations-adb-enhancements>Advanced mode of\noperations, ADB enhancements, …</a></span><li><span><span class=toc-section-number>6.6.13</span> <a href=#data-usage-widget-and-more id=toc:data-usage-widget-and-more>Data usage widget, and\nmore</a></span><li><span><span class=toc-section-number>6.6.14</span> <a href=#others-1 id=toc:others-1>Others</a></span></ul><li><span><span class=toc-section-number>6.7</span> <a href=#sec:v3.1.0-(423) id=toc:sec:v3.1.0-(423)>v3.1.0\n(423)</a></span><ul class=incremental><li><span><span class=toc-section-number>6.7.1</span> <a href=#android-13-support id=toc:android-13-support>Android 13\nsupport</a></span><li><span><span class=toc-section-number>6.7.2</span> <a href=#introducing-freezeunfreeze id=toc:introducing-freezeunfreeze>Introducing\nfreeze/unfreeze</a></span><li><span><span class=toc-section-number>6.7.3</span> <a href=#export-app-list id=toc:export-app-list>Export app\nlist</a></span><li><span><span class=toc-section-number>6.7.4</span> <a href=#elliptic-curve-crypography-ecc id=toc:elliptic-curve-crypography-ecc>Elliptic Curve Crypography\n(ECC)</a></span><li><span><span class=toc-section-number>6.7.5</span> <a href=#new-languages id=toc:new-languages>New\nlanguages</a></span><li><span><span class=toc-section-number>6.7.6</span> <a href=#more-list-options id=toc:more-list-options>More list\noptions</a></span><li><span><span class=toc-section-number>6.7.7</span> <a href=#improved-handling-of-mode-of-operation id=toc:improved-handling-of-mode-of-operation>Improved handling of\nmode of operation</a></span><li><span><span class=toc-section-number>6.7.8</span> <a href=#handling-multiple-users id=toc:handling-multiple-users>Handling multiple users</a></span><li><span><span class=toc-section-number>6.7.9</span> <a href=#explorer-enhancements id=toc:explorer-enhancements>Explorer\nenhancements</a></span><li><span><span class=toc-section-number>6.7.10</span> <a href=#new-tag-wx id=toc:new-tag-wx>New tag: WX</a></span><li><span><span class=toc-section-number>6.7.11</span> <a href=#app-ops-management id=toc:app-ops-management>App ops\nmanagement</a></span><li><span><span class=toc-section-number>6.7.12</span> <a href=#batch-uninstallation id=toc:batch-uninstallation>Batch\nuninstallation</a></span><li><span><span class=toc-section-number>6.7.13</span> <a href=#running-apps id=toc:running-apps>Running apps</a></span><li><span><span class=toc-section-number>6.7.14</span> <a href=#interceptor id=toc:interceptor>Interceptor</a></span><li><span><span class=toc-section-number>6.7.15</span> <a href=#device-specific-changes id=toc:device-specific-changes>Device-specific changes</a></span><li><span><span class=toc-section-number>6.7.16</span> <a href=#others-2 id=toc:others-2>Others</a></span></ul><li><span><span class=toc-section-number>6.8</span> <a href=#sec:v3.0.0-(410) id=toc:sec:v3.0.0-(410)>v3.0.0\n(410)</a></span><ul class=incremental><li><span><span class=toc-section-number>6.8.1</span> <a href=#material-3-and-more id=toc:material-3-and-more>Material 3 and\nMore</a></span><li><span><span class=toc-section-number>6.8.2</span> <a href=#wireless-debugging id=toc:wireless-debugging>Wireless\nDebugging</a></span><li><span><span class=toc-section-number>6.8.3</span> <a href=#languages id=toc:languages>Languages</a></span><li><span><span class=toc-section-number>6.8.4</span> <a href=#introducing-app-explorer id=toc:introducing-app-explorer>Introducing App\nExplorer</a></span><li><span><span class=toc-section-number>6.8.5</span> <a href=#import-backups-from-other-applications id=toc:import-backups-from-other-applications>Import Backups from\nOther Applications</a></span><li><span><span class=toc-section-number>6.8.6</span> <a href=#virustotal id=toc:virustotal>VirusTotal</a></span><li><span><span class=toc-section-number>6.8.7</span> <a href=#trigger-profiles-from-the-automation-software id=toc:trigger-profiles-from-the-automation-software>Trigger Profiles\nfrom the Automation Software</a></span><li><span><span class=toc-section-number>6.8.8</span> <a href=#improved-application-installer id=toc:improved-application-installer>Improved Application\nInstaller</a></span><li><span><span class=toc-section-number>6.8.9</span> <a href=#component-blocking id=toc:component-blocking>Component\nBlocking</a></span><li><span><span class=toc-section-number>6.8.10</span> <a href=#advanced-searching id=toc:advanced-searching>Advanced\nSearching</a></span><li><span><span class=toc-section-number>6.8.11</span> <a href=#shared-libraries id=toc:shared-libraries>Shared\nLibraries</a></span><li><span><span class=toc-section-number>6.8.12</span> <a href=#make-the-best-use-of-interceptor id=toc:make-the-best-use-of-interceptor>Make the Best Use of\nInterceptor</a></span><li><span><span class=toc-section-number>6.8.13</span> <a href=#widget-screen-time id=toc:widget-screen-time>Widget: Screen\nTime</a></span><li><span><span class=toc-section-number>6.8.14</span> <a href=#widget-clear-cache id=toc:widget-clear-cache>Widget: Clear\nCache</a></span></ul><li><span><span class=toc-section-number>6.9</span> <a href=#sec:v2.6.0-(385) id=toc:sec:v2.6.0-(385)>v2.6.0\n(385)</a></span><ul class=incremental><li><span><span class=toc-section-number>6.9.1</span> <a href=#introducing-backups id=toc:introducing-backups>Introducing\nBackups</a></span><li><span><span class=toc-section-number>6.9.2</span> <a href=#introducing-log-viewer id=toc:introducing-log-viewer>Introducing Log Viewer</a></span><li><span><span class=toc-section-number>6.9.3</span> <a href=#lock-app-manager id=toc:lock-app-manager>Lock App\nManager</a></span><li><span><span class=toc-section-number>6.9.4</span> <a href=#extended-modes-for-app-ops id=toc:extended-modes-for-app-ops>Extended Modes for App\nOps</a></span><li><span><span class=toc-section-number>6.9.5</span> <a href=#new-batch-ops-add-to-profile id=toc:new-batch-ops-add-to-profile>New Batch Ops: Add to\nProfile</a></span><li><span><span class=toc-section-number>6.9.6</span> <a href=#app-info-improved id=toc:app-info-improved>App Info:\nImproved</a></span><li><span><span class=toc-section-number>6.9.7</span> <a href=#advanced-sort-and-filtering-options-in-the-main-page id=toc:advanced-sort-and-filtering-options-in-the-main-page>Advanced\nSort and Filtering Options in the Main Page</a></span><li><span><span class=toc-section-number>6.9.8</span> <a href=#about-this-device id=toc:about-this-device>About This\nDevice</a></span><li><span><span class=toc-section-number>6.9.9</span> <a href=#enabledisable-features id=toc:enabledisable-features>Enable/disable Features</a></span><li><span><span class=toc-section-number>6.9.10</span> <a href=#new-languages-1 id=toc:new-languages-1>New\nLanguages</a></span><li><span><span class=toc-section-number>6.9.11</span> <a href=#signing-the-apk-files id=toc:signing-the-apk-files>Signing the\nAPK Files</a></span><li><span><span class=toc-section-number>6.9.12</span> <a href=#new-extension-unapkm id=toc:new-extension-unapkm>New\nExtension: UnAPKM</a></span></ul><li><span><span class=toc-section-number>6.10</span> <a href=#sec:v2.5.20-(375) id=toc:sec:v2.5.20-(375)>v2.5.20\n(375)</a></span><ul class=incremental><li><span><span class=toc-section-number>6.10.1</span> <a href=#subsec:introducing-profiles id=toc:subsec:introducing-profiles>Introducing\nProfiles</a></span><li><span><span class=toc-section-number>6.10.2</span> <a href=#subsec:the-interceptor id=toc:subsec:the-interceptor>The\nInterceptor</a></span><li><span><span class=toc-section-number>6.10.3</span> <a href=#subsec:unapkm:-dedrm-the-apkm-files id=toc:subsec:unapkm:-dedrm-the-apkm-files>UnAPKM: DeDRM the APKM\nfiles</a></span><li><span><span class=toc-section-number>6.10.4</span> <a href=#subsec:multiple-user id=toc:subsec:multiple-user>Multiple\nuser</a></span><li><span><span class=toc-section-number>6.10.5</span> <a href=#vive-la-france id=toc:vive-la-france>Vive la\nFrance!</a></span><li><span><span class=toc-section-number>6.10.6</span> <a href=#report-crashes id=toc:report-crashes>Report\ncrashes</a></span><li><span><span class=toc-section-number>6.10.7</span> <a href=#android-11 id=toc:android-11>Android 11</a></span><li><span><span class=toc-section-number>6.10.8</span> <a href=#app-installer-improvements id=toc:app-installer-improvements>App Installer\nImprovements</a></span></ul><li><span><span class=toc-section-number>6.11</span> <a href=#v2.5.17-368 id=toc:v2.5.17-368>v2.5.17 (368)</a></span><ul class=incremental><li><span><span class=toc-section-number>6.11.1</span> <a href=#app-installer id=toc:app-installer>App\nInstaller</a></span><li><span><span class=toc-section-number>6.11.2</span> <a href=#scanner-replacement-for-exodus-page id=toc:scanner-replacement-for-exodus-page>Scanner: Replacement for\nExodus Page</a></span><li><span><span class=toc-section-number>6.11.3</span> <a href=#introducing-system-config id=toc:introducing-system-config>Introducing System\nConfig</a></span><li><span><span class=toc-section-number>6.11.4</span> <a href=#more-languages id=toc:more-languages>More\nLanguages</a></span><li><span><span class=toc-section-number>6.11.5</span> <a href=#app-info-tab id=toc:app-info-tab>App Info Tab</a></span><li><span><span class=toc-section-number>6.11.6</span> <a href=#navigation-improvements id=toc:navigation-improvements>Navigation Improvements</a></span><li><span><span class=toc-section-number>6.11.7</span> <a href=#running-apps-page id=toc:running-apps-page>Running Apps\nPage</a></span><li><span><span class=toc-section-number>6.11.8</span> <a href=#built-in-toybox id=toc:built-in-toybox>Built-in\nToybox</a></span><li><span><span class=toc-section-number>6.11.9</span> <a href=#component-blocker-improvements id=toc:component-blocker-improvements>Component Blocker\nImprovements</a></span><li><span><span class=toc-section-number>6.11.10</span> <a href=#improvements-in-the-app-details-page id=toc:improvements-in-the-app-details-page>Improvements in the App\nDetails Page</a></span><li><span><span class=toc-section-number>6.11.11</span> <a href=#app-manifest id=toc:app-manifest>App Manifest</a></span></ul><li><span><span class=toc-section-number>6.12</span> <a href=#v2.5.13-348 id=toc:v2.5.13-348>v2.5.13 (348)</a></span><ul class=incremental><li><span><span class=toc-section-number>6.12.1</span> <a href=#bundled-app-split-apk id=toc:bundled-app-split-apk>Bundled App\n(Split APK)</a></span><li><span><span class=toc-section-number>6.12.2</span> <a href=#direct-install-support id=toc:direct-install-support>Direct\nInstall Support</a></span><li><span><span class=toc-section-number>6.12.3</span> <a href=#remove-all-blocking-rules id=toc:remove-all-blocking-rules>Remove All Blocking\nRules</a></span><li><span><span class=toc-section-number>6.12.4</span> <a href=#app-ops-1 id=toc:app-ops-1>App Ops</a></span><li><span><span class=toc-section-number>6.12.5</span> <a href=#enhanced-adb-support id=toc:enhanced-adb-support>Enhanced ADB\nSupport</a></span><li><span><span class=toc-section-number>6.12.6</span> <a href=#filtering-in-main-page id=toc:filtering-in-main-page>Filtering\nin Main Page</a></span><li><span><span class=toc-section-number>6.12.7</span> <a href=#apk-backupsharing id=toc:apk-backupsharing>Apk\nBackup/Sharing</a></span><li><span><span class=toc-section-number>6.12.8</span> <a href=#batch-ops id=toc:batch-ops>Batch Ops</a></span><li><span><span class=toc-section-number>6.12.9</span> <a href=#translations id=toc:translations>Translations</a></span><li><span><span class=toc-section-number>6.12.10</span> <a href=#app-data-backup id=toc:app-data-backup>App Data\nBackup</a></span></ul></ul><li><span><span class=toc-section-number>7</span> <a href=#ch:app-ops id=toc:ch:app-ops>App Ops</a></span><ul class=incremental><li><span><span class=toc-section-number>7.1</span> <a href=#sec:app-ops-background id=toc:sec:app-ops-background>Background</a></span><li><span><span class=toc-section-number>7.2</span> <a href=#sec:introduction-to-app-ops id=toc:sec:introduction-to-app-ops>Introduction to App\nOps</a></span><li><span><span class=toc-section-number>7.3</span> <a href=#sec:appopsmanager id=toc:sec:appopsmanager>AppOpsManager</a></span><ul class=incremental><li><span><span class=toc-section-number>7.3.1</span> <a href=#subsec:op-constants id=toc:subsec:op-constants><code>OP_*</code> Constants</a></span><li><span><span class=toc-section-number>7.3.2</span> <a href=#subsec:mode-constants id=toc:subsec:mode-constants><code>MODE_*</code>\nConstants</a></span><li><span><span class=toc-section-number>7.3.3</span> <a href=#subsec:package-ops id=toc:subsec:package-ops>PackageOps</a></span><li><span><span class=toc-section-number>7.3.4</span> <a href=#subsec:opentry id=toc:subsec:opentry>OpEntry</a></span><li><span><span class=toc-section-number>7.3.5</span> <a href=#subsec:usage id=toc:subsec:usage>Usage</a></span></ul><li><span><span class=toc-section-number>7.4</span> <a href=#sec:appopsservice id=toc:sec:appopsservice>AppOpsService</a></span><li><span><span class=toc-section-number>7.5</span> <a href=#sec:appops-xml id=toc:sec:appops-xml>appops.xml</a></span><li><span><span class=toc-section-number>7.6</span> <a href=#sec:appops-cli id=toc:sec:appops-cli>Command Line\nInterface</a></span></ul></ul></nav><div class=titlingpage><div class=center><p><img src=../images/icon.png style=width:1in alt=image><p><strong><span class=smallcaps>App Manager</span></strong><p><strong>User Manual</strong><p><em>v4.0.5</em><p>27 julho 2025<p>Copyright © 2020–2025 Muntashir Al-Islam<blockquote><p>“Wisely and slow. They stumble that run fast.” <span>— Friar\nLaurence, <em>Romeo and Juliet</em></span></blockquote></div></div><section id=ch:introduction class=level1 data-number=1><h1 data-number=1><span class=header-section-number>1</span> <a href=#toc:ch:introduction>Introduction</a><a href=#ch:introduction class=anchor aria-hidden=true></a></h1><p>App Manager is an advanced package manager for Android. It offers\nnumerous features and thus, requires a user manual to assist its users.\nThis document acts as a user manual for App Manager in the sense that it\naims to describe every feature that App Manager has to offer. This\ndocument also serves as the “official” guidelines for App Manager and\nrepresents the expected behavior of App Manager. Translations can\nmisinterpret this document (which is in English). Therefore, a capable\nuser should read the English version of the document to get the most out\nof it. There may as well be other unofficial or third-party resources,\nsuch as blog articles, videos, forums, and chat groups. While these\nresources may be useful to many people, they may not be up-to-date with\nthe latest version of App Manager. In case of any deviations detected in\nApp Manager from this document, they should be reported in the <a href=https://github.com/MuntashirAkon/AppManager/issues>App Manager\nissue tracker</a>.<section id=sec:terminologies class=level2 data-number=1.1><h2 data-number=1.1><span class=header-section-number>1.1</span> <a href=#toc:sec:terminologies>Terminologies</a><a href=#sec:terminologies class=anchor aria-hidden=true></a></h2><ul class=incremental><li><p><strong>AM</strong> — Short name for App Manager.<li><p><strong>Block/Unblock</strong> — Used for component blocking or\nunblocking. How components are blocked depends on the user\npreferences.<li><p><strong>IFW</strong> — Short form of Intent Firewall.<li><p><strong>Ops</strong> — Short name for operations, e.g. app ops,\nbatch ops, 1-click ops<li><p><strong>SAF</strong> — Short for Storage Access Framework, an\nabstraction used by Android to allow apps to use or serve files without\nworrying about the underlying file system.<li><p><strong>SSAID</strong> — Short form of\n<code>Settings.Secure.ANDROID_ID</code>. It is a device identifier\nassigned to each app (Android Oreo onwards). It is generated from the\ncombination of the signing certificate of the app and the SSAID set for\nthe package <code>android</code>. As a result, it is guaranteed to be\nthe same for an app unless the user chooses to format the device. It is\nwidely used for tracking.<li><p><strong>Tracker</strong> — Denotes tracker components throughout\nthe document and in App Manager except in the <a href=#sec:scanner-page>scanner page</a>. Trackers include libraries\nsuch as crash reporters, analytics, profiling, identification, ad,\nlocation, etc. Thus, they are not equal in functions. There is no\ndistinction or bias among the open-source and closed-source libraries\nthat promote tracking.</ul></section><section id=sec:supported-versions class=level2 data-number=1.2><h2 data-number=1.2><span class=header-section-number>1.2</span> <a href=#toc:sec:supported-versions>Supported Versions</a><a href=#sec:supported-versions class=anchor aria-hidden=true></a></h2><p>At present, the supported version is v4.0.1. Previous versions of App\nManager may contain security vulnerabilities and should not be used.</section><section id=sec:official-sources class=level2 data-number=1.3><h2 data-number=1.3><span class=header-section-number>1.3</span> <a href=#toc:sec:official-sources>Official Sources</a><a href=#sec:official-sources class=anchor aria-hidden=true></a></h2><section id=subsec:binary-distribution-sources class=level3 data-number=1.3.1><h3 data-number=1.3.1><span class=header-section-number>1.3.1</span>\n<a href=#toc:subsec:binary-distribution-sources>Binary Distribution\nSources</a><a href=#subsec:binary-distribution-sources class=anchor aria-hidden=true></a></h3><p>App Manager is distributed using the following sources. Unofficial\nsources may distribute modified versions of App Manager, and you alone\nshall be responsible for the consequences of using such a\ndistribution.<ol class=incremental><li><p>Official F-Droid repository.<a href=#fn1 class=footnote-ref id=fnref1 role=doc-noteref><sup>1</sup></a><br><em>Link:</em> <a href=https://f-droid.org/packages/io.github.muntashirakon.AppManager class=uri>https://f-droid.org/packages/io.github.muntashirakon.AppManager</a><li><p>GitHub repository.<br><em>Normal releases:</em> <a href=https://github.com/MuntashirAkon/AppManager/releases class=uri>https://github.com/MuntashirAkon/AppManager/releases</a><br><em>Debug releases:</em> <a href=https://github.com/MuntashirAkon/AMInsecureDebugBuilds class=uri>https://github.com/MuntashirAkon/AMInsecureDebugBuilds</a><li><p>Telegram.<br><em>Normal releases:</em> <a href=https://t.me/AppManagerChannel class=uri>https://t.me/AppManagerChannel</a><br><em>Debug releases:</em> <a href=https://t.me/AppManagerDebug class=uri>https://t.me/AppManagerDebug</a></ol></section><section id=subsec:links-to-source-code class=level3 data-number=1.3.2><h3 data-number=1.3.2><span class=header-section-number>1.3.2</span>\n<a href=#toc:subsec:links-to-source-code>Links to the Source\nCode</a><a href=#subsec:links-to-source-code class=anchor aria-hidden=true></a></h3><p>All but GitHub are mirrors. The tags should always be up-to-date, but\nthe master branch may not. If you want to clone the master branch, use\nthe GitHub link instead of the others.<ol class=incremental><li><p>GitHub: <a href=https://github.com/MuntashirAkon/AppManager class=uri>https://github.com/MuntashirAkon/AppManager</a><li><p>Codeberg: <a href=https://codeberg.org/muntashir/AppManager class=uri>https://codeberg.org/muntashir/AppManager</a><li><p>GitLab: <a href=https://gitlab.com/muntashir/AppManager class=uri>https://gitlab.com/muntashir/AppManager</a><li><p>Riseup: <a href=https://0xacab.org/muntashir/AppManager class=uri>https://0xacab.org/muntashir/AppManager</a><li><p>sourcehut: <a href=https://git.sr.ht/~muntashir/AppManager class=uri>https://git.sr.ht/~muntashir/AppManager</a></ol></section><section id=subsec:translations class=level3 data-number=1.3.3><h3 data-number=1.3.3><span class=header-section-number>1.3.3</span>\n<a href=#toc:subsec:translations>Translations</a><a href=#subsec:translations class=anchor aria-hidden=true></a></h3><p>App Manager does not accept translations via pull/merge requests.\nTranslations are managed through Hosted Weblate. To translate App\nManager, visit <a href=https://hosted.weblate.org/engage/app-manager/ class=uri>https://hosted.weblate.org/engage/app-manager/</a>. Please\nread the <strong>Info</strong> section before getting started.</section></section><section id=sec:contributing class=level2 data-number=1.4><h2 data-number=1.4><span class=header-section-number>1.4</span> <a href=#toc:sec:contributing>Contributing</a><a href=#sec:contributing class=anchor aria-hidden=true></a></h2><p>There are many ways a user can contribute, such as creating helpful\nissues, attending discussions, improving documentation and translations,\nreporting unknown libraries or trackers, reviewing the source code, and\nreporting security vulnerabilities.<section id=subsec:build-instructions class=level3 data-number=1.4.1><h3 data-number=1.4.1><span class=header-section-number>1.4.1</span>\n<a href=#toc:subsec:build-instructions>Build Instructions</a><a href=#subsec:build-instructions class=anchor aria-hidden=true></a></h3><p>Build instructions are available in the BUILDING file located in the\nsource root.</section><section id=subsec:submitting-patches class=level3 data-number=1.4.2><h3 data-number=1.4.2><span class=header-section-number>1.4.2</span>\n<a href=#toc:subsec:submitting-patches>Submitting patches</a><a href=#subsec:submitting-patches class=anchor aria-hidden=true></a></h3><p>Repositories located on sites other than GitHub are currently\nconsidered mirrors, and pull/merge requests submitted on those sites\nwill not be accepted.<a href=#fn2 class=footnote-ref id=fnref2 role=doc-noteref><sup>2</sup></a> Instead, patches (as\n<code>.patch</code> files) can be submitted via email attachments.\n<em>Signing-off is a requirement.</em> See the CONTRIBUTING file located\nat the source root for more information.<div class=\"amalert warning\"><p><strong><em>Notice.</em></strong><p>In the case of submitting patches via email, the whole conversation\nmay be publicly accessible in the future. So, please do not include\npersonally identifiable information (PII) other than your name or email\naddress.</div></section></section><section id=sec:donation-&-funding class=level2 data-number=1.5><h2 data-number=1.5><span class=header-section-number>1.5</span> <a href=#toc:sec:donation-&-funding>Donation & Funding</a><a href=#sec:donation-&-funding class=anchor aria-hidden=true></a></h2><p>As of September 2024, App Manager is not accepting financial support\nuntil further notice. But you may still be able to send gifts (e.g.,\ngift cards, subscriptions, food and drink, flowers, or even cash).\nPlease reach out to the maintainer using the options given in §<a href=#sec:contact data-reference-type=ref data-reference=sec:contact>1.6</a> for further assistance.<p>In addition, the maintainers and contributors of this project DO NOT\nconsent to the creation, sale, or promotion of tokens, cryptocurrencies,\nNFTs, or any other financial instruments that claim to represent this\nproject, its code, or its community. Any such attempts are unauthorized\nand not affiliated with this project in any way.</section><section id=sec:contact class=level2 data-number=1.6><h2 data-number=1.6><span class=header-section-number>1.6</span> <a href=#toc:sec:contact>Contact</a><a href=#sec:contact class=anchor aria-hidden=true></a></h2><p>App Manager Community<br>Email: <a href=mailto:am4android@riseup.net>am4android [at] riseup\n[dot] net</a><br>GitHub: <a href=https://github.com/AMCommunity class=uri>https://github.com/AMCommunity</a><br>Twitter/X: <a href=https://x.com/AppManagerNews class=uri>https://x.com/AppManagerNews</a><br>Mastodon: <a href=https://floss.social/@appmanager>@appmanager@floss.social</a><br><br>Muntashir Al-Islam<a href=#fn3 class=footnote-ref id=fnref3 role=doc-noteref><sup>3</sup></a><br>Email: <a href=mailto:muntashirakon@riseup.net>muntashirakon [at]\nriseup [dot] net</a><br>GitHub: <a href=https://github.com/MuntashirAkon class=uri>https://github.com/MuntashirAkon</a><br>Twitter/X: <a href=https://x.com/Muntashir class=uri>https://x.com/Muntashir</a><br>Mastodon: <a href=https://infosec.exchange/@muntashir>@muntashir@infosec.exchange</a></section></section><section id=ch:pages class=level1 data-number=2><h1 data-number=2><span class=header-section-number>2</span> <a href=#toc:ch:pages>Pages</a><a href=#ch:pages class=anchor aria-hidden=true></a></h1><section id=sec:main-page class=level2 data-number=2.1><h2 data-number=2.1><span class=header-section-number>2.1</span> <a href=#toc:sec:main-page>Main Page</a><a href=#sec:main-page class=anchor aria-hidden=true></a></h2><p>Main page lists all the installed, uninstalled and backed up\napplications. A single click on any installed application item opens the\nrespective <a href=#sec:app-details-page>App Details page</a>. For the\nuninstalled system applications, a dialog prompt is displayed with an\noption reinstall them. The applications uninstalled without removing\ntheir data and signatures are also displayed in this page with an option\nto perform a full uninstallation. For the uninstalled applications\nhaving one or more backups, the restore dialog is displayed. Using the\n<a href=#par:main-page-sort>sort</a> option from the list options, the\nitems can be sorted in various ways. It is also possible to filter items\nusing the <a href=#par:main-page-filter>filter</a> option in the list\noptions. Filtering is also possible from the search bar with additional\nsupport for the regular expressions.<figure id=fig:main_page_entry_info_labeled><figure><object data=../images/main_page_entry_info_labeled.svg type=image/svg+xml></object></figure><figcaption>Figure 1: An application list item in the main\npage</figcaption></figure><section id=subsec:batch-operations class=level3 data-number=2.1.1><h3 data-number=2.1.1><span class=header-section-number>2.1.1</span>\n<a href=#toc:subsec:batch-operations>Batch Operations</a><a href=#subsec:batch-operations class=anchor aria-hidden=true></a></h3><p>Batch operations or operations on multiple applications are also\navailable within this page. Multiple selection mode can be activated by\nclicking on the app icon of an item or by long-clicking on any items in\nthe list. Once activated, a click on an item selects it instead of\nopening the App Details page. In this mode, the batch operations are\nlocated in the multiple selection menu at the bottom of the page. The\noperations include:<ul class=incremental><li><p>Adding the selected applications to a <a href=#sec:profiles-page>profile</a><li><p><a href=#sec:backup-restore>Backing up applications</a>, or\nrestoring and deleting the existing backups<li><p>Blocking the trackers from the applications<li><p>Clearing data or cache from the applications<li><p>Exporting the blocking rules configured inside App\nManager<li><p>Exporting the list of applications in Markdown, CSV, JSON or XML\nformat<li><p>Freezing/unfreezing/force-stopping/uninstalling the\napplications<li><p>Performing run-time optimization of the applications (Android 7\nonwards)<li><p>Preventing the background operations of the applications (Android\n7 onwards)<li><p>Saving the APK files to <code>AppManager/apks</code><li><p>Setting <a href=#sec:net-policy>net policies</a></ul><div class=\"amalert tip\"><p><strong><em>Accessibility.</em></strong><p>After the multiple selection mode has been activated, it is possible\nto navigate in or out of the multiple selection menu using the right or\nleft keys of the keyboard or remote.</div></section><section id=subsec:main-colour-codes class=level3 data-number=2.1.2><h3 data-number=2.1.2><span class=header-section-number>2.1.2</span>\n<a href=#toc:subsec:main-colour-codes>Colour Codes</a><a href=#subsec:main-colour-codes class=anchor aria-hidden=true></a></h3><ul class=incremental><li><p><span class=colorbox style=background-color:#ff0000b3><span style=color:#000>Red (day)</span></span> / <span class=colorbox style=background-color:#790d0d><span style=color:#fff>dark red (night)</span></span> – Uninstalled\napplication<li><p><span class=colorbox style=background-color:#ff8a80><span style=color:#000>Light red (day)</span></span> / <span class=colorbox style=background-color:#4f1c14bf><span style=color:#fff>very\ndark red (night)</span></span> – Frozen application<li><p><span class=colorbox style=background-color:#09868b><span style=color:#fff>Dark cyan</span></span> – Force-stopped\napplication<li><p><span class=colorbox style=background-color:#ff0><span style=color:#000>Yellow Star</span></span> – Debuggable\napplication<li><p><span style=color:#e05915>Orange <em>Date</em></span> – The\napplication can read system logs<li><p><span style=color:#e05915>Orange <em>UID</em></span> – The\nuser ID is being shared among multiple applications<li><p><span style=color:#e05915>Orange <em>SDK</em></span> – The\napplication possibly uses cleartext (i.e. HTTP) traffic<li><p><span style=color:#ff8017>Light orange <em>package\nname</em></span> – The application has one or more trackers<li><p><span style=color:red>Red <em>app label</em></span> – The\napplication does not allow clearing its data<li><p><span style=color:#09868b>Dark cyan <em>version</em></span>\n– Inactive application<li><p><span style=color:#f0f>Magenta type</span> – Persistent\napplication i.e. it remains running all the time<li><p><span style=color:red>Red <em>backup</em></span> – The\nuninstalled application with one or more backups present in App\nManager<li><p><span style=color:#e05915>Orange <em>backup</em></span> –\nOutdated backup, i.e. the base backup contains an older version of the\ninstalled application<li><p><span style=color:#09868b>Dark cyan <em>backup</em></span>\n– Up to date backup, i.e. the base backup contains the same or higher\nversion of the installed application.</ul></section><section id=subsec:main-page-application-types class=level3 data-number=2.1.3><h3 data-number=2.1.3><span class=header-section-number>2.1.3</span>\n<a href=#toc:subsec:main-page-application-types>Application\nTypes</a><a href=#subsec:main-page-application-types class=anchor aria-hidden=true></a></h3><p>An application can be either a <strong>User</strong> or a\n<strong>System</strong> application along with the following\nsuffixes:<ul class=incremental><li><p><code>X</code> – Supports multiple architectures<li><p><code>0</code> – No dex files present in the application<li><p><code>°</code> – Suspended application<li><p><code>#</code> – The application requested the system to allocate\na large heap i.e. large runtime memory<li><p><code>?</code> – The application requested the virtual machine to\nbe in the safe mode.</ul></section><section id=subsec:main-page-version-info class=level3 data-number=2.1.4><h3 data-number=2.1.4><span class=header-section-number>2.1.4</span>\n<a href=#toc:subsec:main-page-version-info>Version Info</a><a href=#subsec:main-page-version-info class=anchor aria-hidden=true></a></h3><p>Version name is followed by the prefixes below:<ul class=incremental><li><p><code>_</code> – No hardware acceleration (breaking the in-app\nanimations or transparencies)<li><p><code>~</code> – Test-only application<li><p><code>debug</code> – Debuggable application</ul></section><section id=subsec:main-page-options-menu class=level3 data-number=2.1.5><h3 data-number=2.1.5><span class=header-section-number>2.1.5</span>\n<a href=#toc:subsec:main-page-options-menu>Options Menu</a><a href=#subsec:main-page-options-menu class=anchor aria-hidden=true></a></h3><p>Options menu offers several options that can be used to sort and\nfilter the listed applications as well as to navigate to different pages\nwithin or outside App Manager.<section id=subsubsec:main-list-options class=level4 data-number=2.1.5.1><h4 data-number=2.1.5.1><span class=header-section-number>2.1.5.1</span> List Options<a href=#subsubsec:main-list-options class=anchor aria-hidden=true></a></h4><p><strong>List options</strong> contain the options to sort and filter\nthe list in the main page.<section id=sort class=level5 data-number=2.1.5.1.1><h5 data-number=2.1.5.1.1><span class=header-section-number>2.1.5.1.1</span> Sort<a href=#sort class=anchor aria-hidden=true></a></h5><div id=par:main-page-sort></div><p>The applications listed in the main page can be sorted in the\nfollowing ways:<ul class=incremental><li><p><strong>User apps first.</strong> The user applications are\nlisted on top<li><p><strong>App label.</strong> Sort the list in ascending order\nbased on their application labels (also known as <em>application\nnames</em>). This is the default sorting preference<li><p><strong>Package name.</strong> Sort the list in ascending order\nbased on their package names<li><p><strong>Last update.</strong> Sort the list in descending order\nbased on the date they were last updated<li><p><strong>Shared user ID.</strong> Sort the list in descending\norder based on their kernel user ID<li><p><strong>Target SDK.</strong> Sort the list in ascending order\nbased on their target SDK<li><p><strong>Signature.</strong> Sort the list in ascending order\nbased on their signing information<li><p><strong>Frozen first.</strong> The frozen applications are listed\non the top<li><p><strong>Blocked first.</strong> Sort the list in descending order\nbased on the number of blocked components each application has<li><p><strong>Backed up first.</strong> Display the applications with\nbackups on the top<li><p><strong>Trackers.</strong> Sort the list in descending order\nbased on the number of tracker components each application has<li><p><strong>Last actions.</strong> Sort the list in descending order\nbased on the latest time and date of any actions made to the\napplications within App Manager.<li><p><strong>Installation date.</strong> Sort the list by the date of\ninstallation in descending order.<li><p><strong>Total size.</strong> Sort the list by the total size of\nthe applications and their data in descending order. Requires\n<code>Usage Access</code> permission.<li><p><strong>Data usage.</strong> Sort the list by the total data\nusage in descending order. Requires <code>Usage Access</code>\npermission.<li><p><strong>Times opened.</strong> List frequently used applications\non top. Requires <code>Usage Access</code> permission.<li><p><strong>Screen time.</strong> List the applications with the\nhighest engagements on top. Requires <code>Usage Access</code>\npermission.<li><p><strong>Last used.</strong> List last used apps on top. Requires\n<code>Usage Access</code> permission.</ul><p>In addition, there is the <em>reverse</em> option that can be used to\nsort the list in the reverse order. Regardless of the sorting\npreferences, the applications are sorted alphabetically at first in\norder to prevent producing any random sorting results.</section><section id=filter class=level5 data-number=2.1.5.1.2><h5 data-number=2.1.5.1.2><span class=header-section-number>2.1.5.1.2</span> Filter<a href=#filter class=anchor aria-hidden=true></a></h5><div id=par:main-page-filter></div><p>The applications listed in the main page can be filtered in the\nfollowing ways:<ul class=incremental><li><p><strong>User apps.</strong> List only the user\napplications<li><p><strong>System apps.</strong> List only the system\napplications<li><p><strong>Frozen apps.</strong> List only the frozen\napplications<li><p><strong>Stopped apps.</strong> List only the applications that\nwere forced-stopped<li><p><strong>Installed apps.</strong> List only the installed\napplications<li><p><strong>Uninstalled apps.</strong> List only the uninstalled\napplications<li><p><strong>With rules.</strong> List the applications with one or\nmore blocking rules<li><p><strong>With activities.</strong> List the applications with one\nor more activities<li><p><strong>With backups.</strong> List the applications with one or\nmore backups<li><p><strong>Without backups.</strong> List the applications with no\nbackups present.<li><p><strong>Running apps.</strong> List the applications that are\ncurrently running<li><p><strong>With splits.</strong> List the applications with one or\nmore split APK files<li><p><strong>With KeyStore.</strong> List only the applications with\nAndroid KeyStore.<li><p><strong>With SAF.</strong> List only the applications with SAF\naccess.<li><p><strong>With SSAID.</strong> List only the applications with a\nvalid SSAID.</ul><p>Unlike sorting, it is possible to apply more than one filtering\noptions at the same time. For example, the frozen user applications can\nbe listed by selecting both <em>User apps</em> and <em>Frozen apps</em>.\nThis can be particularly useful for <a href=#subsec:batch-operations>batch operations</a> where filtering the\nuser applications may be necessary to carry out certain operations\nsafely.<div class=\"amalert warning\"><p><strong><em>Inconsistencies.</em></strong><p>App Manager extensively caches everything in this page. Therefore,\ncertain states (e.g., freeze and stopped states) may not always be\nup-to-date.</div></section><section id=profile-name class=level5 data-number=2.1.5.1.3><h5 data-number=2.1.5.1.3><span class=header-section-number>2.1.5.1.3</span> Profile Name<a href=#profile-name class=anchor aria-hidden=true></a></h5><p>It is also possible to list the applications that are only present in\na <a href=#sec:profiles-page>profile</a>. This can be useful for\ncarrying out certain operations on a profile (e.g., uninstalling all the\napplications in a profile) that cannot be done via the <a href=#sec:profiles-page>Profiles page</a>.</section></section><section id=user-manual class=level4 data-number=2.1.5.2><h4 data-number=2.1.5.2><span class=header-section-number>2.1.5.2</span> User Manual<a href=#user-manual class=anchor aria-hidden=true></a></h4><p>Clicking on the <strong>User manual</strong> opens the offline\nversion of the App Manager user manual. It may also open the online\nversion if the corresponding feature split i.e. <code>feat_docs</code>\nis not installed, or if an WebView is not present in the system to load\nthe manual.</section><section id=subsubsec:main:1-click-ops class=level4 data-number=2.1.5.3><h4 data-number=2.1.5.3><span class=header-section-number>2.1.5.3</span> 1-Click Ops<a href=#subsubsec:main:1-click-ops class=anchor aria-hidden=true></a></h4><p><strong>1-Click Ops</strong> stands for the single-click operations.\nIt opens the <a href=#sec:1-click-ops-page>corresponding page</a> in a\nnew activity.</section><section id=app-usage class=level4 data-number=2.1.5.4><h4 data-number=2.1.5.4><span class=header-section-number>2.1.5.4</span> App Usage<a href=#app-usage class=anchor aria-hidden=true></a></h4><p>Application usage statistics, such as <em>screen time</em>, <em>data\nusage</em> (both mobile and Wi-Fi), <em>number of times an app was\nopened</em>, can be accessed by clicking on the <strong>App\nUsage</strong> option in the menu. However, it requires the <em>Usage\nAccess</em> permission. This menu item will not be listed if the usage\naccess feature is disabled in <a href=#subsubsec:enable/disable-features>settings</a>.</section><section id=subsubsec:main:running-apps class=level4 data-number=2.1.5.5><h4 data-number=2.1.5.5><span class=header-section-number>2.1.5.5</span> Running Apps<a href=#subsubsec:main:running-apps class=anchor aria-hidden=true></a></h4><p>This menu item opens a new page where a list of running applications\nor processes are displayed. It also displays the current memory and\ncache (if available) usage. If root or ADB is not available to App\nManager, it only displays itself in the recent versions of Android. The\nrunning applications or processes can also be force-stopped or killed\nwithin the resultant page. Logs for each process ID (PID) can also be\nviewed in the <a href=#subsubsec:main:labs>log viewer</a>. In\naddition, it is also possible to carry out batch operations either by\nclicking on the icon or by long-clicking on an item. Normal click on any\nitems opens a dialog where a more detailed information is displayed.</section><section id=profiles class=level4 data-number=2.1.5.6><h4 data-number=2.1.5.6><span class=header-section-number>2.1.5.6</span> Profiles<a href=#profiles class=anchor aria-hidden=true></a></h4><p>This menu item opens the <a href=#sec:profiles-page>profiles\npage</a>. Profiles are a way to configure regularly used tasks. They can\nalso be invoked via shortcuts.</section><section id=apk-updater class=level4 data-number=2.1.5.7><h4 data-number=2.1.5.7><span class=header-section-number>2.1.5.7</span> APK Updater<a href=#apk-updater class=anchor aria-hidden=true></a></h4><p>If the app <a href=https://github.com/rumboalla/apkupdater>APK\nUpdater</a> is installed in the system, it can be opened directly via\nthis menu item. The option remains hidden if the app is not present in\nthe system.</section><section id=termux class=level4 data-number=2.1.5.8><h4 data-number=2.1.5.8><span class=header-section-number>2.1.5.8</span> Termux<a href=#termux class=anchor aria-hidden=true></a></h4><p>If the app <a href=https://github.com/termux/termux-app>Termux</a>\nis installed in the system, the running session (or a new session) can\nbe opened directly via this menu item. The option remains hidden if the\napp is not present in the system.</section><section id=debloater class=level4 data-number=2.1.5.9><h4 data-number=2.1.5.9><span class=header-section-number>2.1.5.9</span> Debloater<a href=#debloater class=anchor aria-hidden=true></a></h4><p>This menu item opens the debloater page that lists all the bloatware\navailable in the device and in App Manager. It also suggests alternative\napplications based on the criteria set by the <a href=https://github.com/MuntashirAkon/android-debloat-list>Android\nDebloat List</a> project.</section><section id=subsubsec:main:labs class=level4 data-number=2.1.5.10><h4 data-number=2.1.5.10><span class=header-section-number>2.1.5.10</span> Labs<a href=#subsubsec:main:labs class=anchor aria-hidden=true></a></h4><p>This menu item opens the labs page that lists all the additional\nfeatures. They include Log Viewer, System Config, Terminal, File Manager\n(as Files), UI Tracker, Interceptor, and Code Editor pages.</section><section id=settings class=level4 data-number=2.1.5.11><h4 data-number=2.1.5.11><span class=header-section-number>2.1.5.11</span> Settings<a href=#settings class=anchor aria-hidden=true></a></h4><p>This menu item opens the in-app <a href=#sec:settings-page>Settings\npage</a>.</section></section></section><section id=sec:app-details-page class=level2 data-number=2.2><h2 data-number=2.2><span class=header-section-number>2.2</span> <a href=#toc:sec:app-details-page>App Details Page</a><a href=#sec:app-details-page class=anchor aria-hidden=true></a></h2><p><strong>App Details</strong> page consists of 11 (eleven) tabs. It\ndescribes almost every bit of information an application usually has,\nincluding all attributes from its manifest, <a href=#ch:app-ops>application operations</a> (app ops), signing\ninformation, libraries, and so on.<section id=subsec:app-details-colour-codes class=level3 data-number=2.2.1><h3 data-number=2.2.1><span class=header-section-number>2.2.1</span>\n<a href=#toc:subsec:app-details-colour-codes>Colour Codes</a><a href=#subsec:app-details-colour-codes class=anchor aria-hidden=true></a></h3><p>List of colours used in this page, and their meaning:<ul class=incremental><li><p><span class=colorbox style=background-color:#ff0000b3><span style=color:#000>Red (day)</span></span> / <span class=colorbox style=background-color:#790d0d><span style=color:#fff>dark red (night)</span></span> – Denotes any app\nops or permissions having the dangerous flag, or any components blocked\nwithin App Manager, or any unsupported but required features.<li><p><span class=colorbox style=background-color:#ff8a80><span style=color:#000>Light red (day)</span></span> / <span class=colorbox style=background-color:#4f1c14bf><span style=color:#fff>very\ndark red (night)</span></span> – Denotes the components disabled outside\nof App Manager, or any unsupported but optional features.<div class=\"amalert tip\"><p><strong><em>Note.</em></strong><p>A component marked as disabled does not always mean that it is\ndisabled by the user: It could also be disabled by the system or marked\nas disabled in its manifest. The components of a disabled application\nare also considered disabled by the system (and App Manager).</div><li><p><span class=colorbox style=background-color:#ff8017><span style=color:#000>Vivid orange (day)</span></span> / <span class=colorbox style=background-color:#ff801780><span style=color:#fff>very\ndark orange (night)</span></span> – Denotes the tracker\ncomponents<li><p><span class=colorbox style=background-color:#ea80fc><span style=color:#000>Soft magenta (day)</span></span> / <span class=colorbox style=background-color:#431c5d><span style=color:#fff>very dark violet (night)</span></span> – Denotes\nthe running services.<li><p><span class=colorbox style=background-color:#1b8654><span style=color:#fff>Green</span></span> – Used in the tracker-indicator\ntag to denote that all the trackers in the application are\nblocked.</ul></section><section id=subsec:app-info-tab class=level3 data-number=2.2.2><h3 data-number=2.2.2><span class=header-section-number>2.2.2</span>\n<a href=#toc:subsec:app-info-tab>App Info Tab</a><a href=#subsec:app-info-tab class=anchor aria-hidden=true></a></h3><p><strong>App Info</strong> tab contains general information about an\napplication. It also lists many actions that can be performed within\nthis tab.<section id=subsubsec:app-info-general-information class=level4 data-number=2.2.2.1><h4 data-number=2.2.2.1><span class=header-section-number>2.2.2.1</span> General Information<a href=#subsubsec:app-info-general-information class=anchor aria-hidden=true></a></h4><p>The list below is in the same order as listed in the App Info\ntab.<ul class=incremental><li><p><strong>Application Icon.</strong> The application icon. If the\napplication does not have an icon, the system default icon will be\ndisplayed. It is also possible to verify the APK signature via SHA or\nMD5 sums stored in the clipboard by simply clicking on it.<li><p><strong>Application Label.</strong> The application label or the\nname of the application.<li><p><strong>Package Name.</strong> The name of the application\npackage. Clicking on the name stores it in the clipboard.<li><p><strong>Version.</strong> The application version is divided into\ntwo parts. The first part is called <em>version name</em>. The format of\nthis part varies but often consists of multiple integers separated by\ndots. The second part is called <em>version code</em>. It is enclosed by\nthe first brackets. The version code is an integer used to differentiate\nbetween application versions (since a version name can be unreadable to\na machine). In general, a new version of an application has higher\nversion code than the old ones. For example, if <code>123</code> and\n<code>125</code> are two version codes of an application, we can say\nthat the latter is more updated than the former because the version code\nof the latter is higher. An application that serves different APK files\nfor the same version on different platforms (mobile, tabs, desktops,\netc.) or architectures (32/64 bit, ARM or Intel), the version numbers\ncan be misleading as they often add prefixes for each platform.<li><p><strong>Tags.</strong> (Also known as tag clouds) Tags include\nthe most basic, concise and useful information of an application. See\n§<a href=#subsubsec:tags data-reference-type=ref data-reference=subsubsec:tags>2.2.2.2</a> for a complete list of tags\nshown here.<li><p><strong>Horizontal Action Panel.</strong> An action panel\nconsisting of various actions that can be carried out for the\napplication. See §<a href=#subsubsec:horizontal-action-panel data-reference-type=ref data-reference=subsubsec:horizontal-action-panel>2.2.2.3</a> for a\ncomplete list of actions available here. Additional actions are\navailable in the <a href=#subsubsec:app-info-options-menu>options\nmenu</a>.<li><p><strong>Paths & Directories.</strong> Contains various\ninformation regarding application paths including <em>app directory</em>\n(where the APK files reside), <em>data directories</em> (internal,\ndevice protected and externals), and <em>JNI library directory</em> (if\npresent). JNI libraries are used to invoke native codes usually written\nin C/C++. Use of native library can make the application run faster or\nhelp an application use third-party libraries written using languages\nother than Java like in most games. The directories can be opened via\nfile managers provided they support it and have the necessary\npermissions, by clicking on the launch button on the right-hand side of\na directory item.<li><p><strong>Data Usage.</strong> Amount of data used by the\napplication as reported by the operating system. Depending on Android\nversion, this may require a wide range of permissions including\n<em>Usage Access</em> and <em>Telephony</em> permissions.<li><p><strong>Storage & Cache.</strong> Displays information\nregarding the size of the application (APK files, optimised files), data\nand cache. In older devices, size of external data, cache, media and OBB\nfolders are also displayed. This part remains hidden if <em>Usage\nAccess</em> permission is not granted in the newer devices.<li><p><strong>More Info.</strong> Displays other information such\nas–<ul class=incremental><li><p><strong>SDK.</strong> Displays information related to the Android\nSDK: <em>Max</em> denotes the target SDK and <em>Min</em> denotes the\nminimum SDK (the latter is not available in Android Lollipop). If the\ntarget SDK value is less than the platform SDK (i.e., the highest SDK\nthe current operating system supports), the application will run in the\ncompatibility mode. This means the application may have access to\ncertain features that are unavailable or restricted in a newer version\nof Android, which can be a security and/or privacy issue. SDK is also\nknown as <strong>API Level</strong>.<br><div class=seealso-inline><p><em>See also: <span><a href=https://en.wikipedia.org/wiki/Android_version_history#Overview>Android\nVersion History</a></span></em></div><li><p><strong>Flags.</strong> The application flags used at the time of\nbuilding the application. For a complete list of flags and what they do,\nread the <a href=https://developer.android.com/reference/android/content/pm/ApplicationInfo#flags>official\ndocumentation</a>.<li><p><strong>Date Installed.</strong> The date when the application\nwas first installed.<li><p><strong>Date Updated.</strong> The date when the application was\nlast updated. This is the same as <em>Date Installed</em> if the\napplication hasn’t been updated.<li><p><strong>Process Name.</strong> The name of the process if it is\ndifferent from the package name. Process name is set when an application\nis being started by the system, and is usually the same as the package\nname.<li><p><strong>Installer App.</strong> The application that installed\nthis application. The installer application may not always be the same\nas the application that installed this application, because Android\nallows setting an arbitrary value for this field. In Android 11 onwards,\nthe actual installer application is also stored by the system which can\nbe accessed by clicking the “Info” button on the right-hand side of the\nitem. The field will not be visible if the installer application is not\nreported by the system (e.g., due to the installer application being\nuninstalled or hidden). Installer application may be granted additional\nprivileges by the system so that it can control certain behaviour of the\napplication it installs.<li><p><strong>User ID.</strong> The unique user ID set by the system to\nthe application. For shared applications, the same user ID is assigned\nto multiple applications having the same <em>Shared User\nID</em>.<li><p><strong>Shared User ID.</strong> Applicable for applications that\nare shared together. The shared application must have the same <a href=#subsec:signatures-tab>signatures</a>.<li><p><strong>Primary ABI.</strong> Architecture supported by this\nplatform for this application.<li><p><strong>Zygote preload name.</strong> Responsible for preloading\napplication code and data shared across all the isolated services that\nuses app zygote.<li><p><strong>Hidden API enforcement policy.</strong> Since Android 9,\nmany methods and classes in Android framework have been made\ninaccessible to the third-party applications through hidden API\nenforcement policy. It has the following options:<ul class=incremental><li><p><em>Default.</em> Based on the type of application. For system\napplications, it should be disabled, and for others, it should be\nenforced.<li><p><em>None/disabled.</em> The application has full access to the\nhidden API as it used to be before Android 9.<li><p><em>Warn.</em> Same as above, except that warnings will be logged\neach time the application accesses the hidden API. This is mostly\nunused.<li><p><em>Enforce.</em> The application cannot access hidden API,\neither dark-grey list or blacklist, or both of them. This is the default\noption for the third-party applications in Android 9 onwards unless the\napplication is whitelisted by the OEM or the vendor.<div class=\"amalert warning\"><p><strong><em>Warning.</em></strong><p>Hidden API enforcement policy is not properly implemented in Android\nand can be bypassed by the application. As a result, this value should\nnot be trusted.</div></ul><li><p><strong>SELinux.</strong> Mandatory access control (MAC) policy\nset by the operating system via SELinux.<li><p><strong>Main Activity.</strong> The main entry point to the\napplication. This is only visible if the application has <a href=#subsubsec:activities>activities</a> and any of those are\nopenable from the Launcher. There’s also a launch button on the\nright-hand side which can be used to launch this activity.</ul></ul></section><section id=subsubsec:tags class=level4 data-number=2.2.2.2><h4 data-number=2.2.2.2><span class=header-section-number>2.2.2.2</span> Tags<a href=#subsubsec:tags class=anchor aria-hidden=true></a></h4><ul class=incremental><li><p><strong>Tracker info.</strong> Number of tracker components in\nthe application (e.g., <em>5 trackers</em>) The colour of the tag\nappears orange if the trackers are unblocked and dark cyan if they are\nblocked in App Manager. Clicking on the tag opens a dialog containing\nthe list of tracker components which can also be blocked or unblocked\nprovided App Manager has sufficient privileges.<li><p><strong>Application type.</strong> User application or system\napplication. For a system application, it displays whether the\napplication is an updated version of the system application or the\napplication is installed systemless-ly via Magisk.<li><p><strong>Split APK info.</strong> Number of splits in the APK\nexcluding the base APK (e.g., <em>5 splits</em>). Clicking on the tag\nopens a dialog containing a few additional information, such as name,\ntype, and size.<li><p><strong>Debuggable.</strong> The application can be debugged over\nADB. Debuggable applications can enjoy certain functions unavailable to\na regular application. The data of the application might be accessible\nvia ADB (e.g. using <code>run-as</code> command) without any additional\npermissions.<li><p><strong>Test only.</strong> The application is a test-only\napplication. Test-only applications can enjoy certain functions\nunavailable to a regular application. The data of the application might\nbe accessible via ADB (e.g. using <code>run-as</code> command) without\nany additional permissions.<li><p><strong>No code.</strong> The application does not have any code\nassociated with it i.e., DEX files aren’t present. In some system\napplications, the actual code might be located in another\nplace.<li><p><strong>Large heap.</strong> The application has requested large\nheap size i.e., more space in memory (RAM) is requested for dynamic\nallocation. It is still up to the operating system to decide whether to\nallocate large space for the application. App Manager, for example,\nrequests large heap size because it needs to load an entire APK into\nmemory while scanning an APK.<li><p><strong>Open links.</strong> The application may open certain\nlinks from any applications. If the application can open any links by\ndefault, the color of the tag would be red, dark cyan if otherwise.\nClicking on the tag opens a dialog with the supported hosts or domains\nlisted. In Android 12 onwards, it displays an option to enable or\ndisable opening links by default provided App Manager has sufficient\npermissions. Otherwise, it displays an option to open the system\nsettings page for the application.<li><p><strong>Running.</strong> One or more services of the application\nis currently running in the background. Clicking on the tag opens a\ndialog containing the list of running services. Clicking on any services\nopens the log viewer with default filter set to the UID associated with\nthe service (which can be different from the UID of the application if\nit is running in a separate or isolated process) provided the log viewer\nfeature is enabled. There’s also an option to force-stop the\napplication.<li><p><strong>Stopped.</strong> The application is force stopped. This\nmay not prevent it from running automatically later.<li><p><strong>Disabled.</strong> Denotes that the application is\ndisabled (hidden from the launcher).<li><p><strong>Suspended.</strong> Denotes that the application is\nsuspended (grayed out in the launcher).<li><p><strong>Hidden.</strong> Denotes that the application is hidden\n(hidden from the launcher).<li><p><strong>MagiskHide.</strong> MagiskHide is enabled for the\napplication. Clicking on the tag opens a dialog containing the list of\nprocess names within the application that can be added to or removed\nfrom the MagiskHide list.<li><p><strong>MagiskDenyList.</strong> The application is present in\nMagisk DenyList. Clicking on the tag opens a dialog containing the list\nof process names within the application that can be added to or removed\nfrom Magisk DenyList.<li><p><strong>WX.</strong> The application violates the “W^X policy”\nand is capable of writing and executing in the same directory or in the\nsame portion of memory. This allows the execution of arbitrary\nexecutables either by the modification of executables embedded within\nthe application or by downloading them from the Internet.<br><div class=seealso-inline><p><em>See also: <span><a href=https://en.wikipedia.org/wiki/W%5EX>W^X\nin Wikipedia</a></span></em></div><li><p><strong>Bloatware.</strong> The application may be a known\nbloatware. Clicking on the tag opens a dialog containing detailed\ninformation in addition to suggestions (if available).<li><p><strong>KeyStore.</strong> The application has items in the\nAndroid KeyStore. Clicking on the tag opens a dialog containing all the\nKeyStore files that belong to the application.<li><p><strong>Backup.</strong> The application was backed up using App\nManager at least once. Clicking on the tag opens a dialog containing all\nthe available backups along with metadata.<li><p><strong>No battery optimisation.</strong> Battery optimisation is\ndisabled for the application. It is possible to re-enable battery\noptimisation by clicking on the tag.<li><p><strong>Sensors disabled.</strong> Sensors are disabled for the\napplication. Sensors are disabled for most applications by\ndefault.<li><p><a href=#sec:net-policy><strong>Net policy.</strong></a>\nNetwork policy (e.g., background data usage) is configured for the\napplication. Clicking on the tag displays a dialog containing the\nsupported policies for the platform along with the options to configure\nthem.<li><p><a href=#sec:terminologies><strong>SSAID.</strong></a> Clicking\non the tag opens a dialog containing the current SSAID assigned to the\napplication. It is also possible to reset/regenerate the SSAID if\nneeded.<li><p><strong>SAF.</strong> Denotes that the application has been\ngranted to access one or more storage locations or files i.e. URIs via\nStorage Access Framework (SAF). Clicking on the tag opens a dialog\ncontaining the list of granted URIs.<li><p><strong>Play App Signing.</strong> Indicates that the application\nmight be signed by Google.<li><p><strong>Xposed.</strong> Indicates that the application may be an\nXposed module. Clicking on the tag displays a dialog with additional\ninformation.<li><p><strong>Static Shared Library.</strong> Denotes that the\napplication serves as a static shared library for one or more\napplications. Clicking on the tag opens a dialog containing a list of\ninstalled versions of the library along with an option to uninstall\nthem.<div class=\"amalert tip\"><p><strong><em>Notice.</em></strong><p>The trichrome library (supplied by Google Chrome, Vanadium or similar\nprojects) is currently the only known static shared library on\nAndroid.</div></ul></section><section id=subsubsec:horizontal-action-panel class=level4 data-number=2.2.2.3><h4 data-number=2.2.2.3><span class=header-section-number>2.2.2.3</span> Horizontal Action Panel<a href=#subsubsec:horizontal-action-panel class=anchor aria-hidden=true></a></h4><p>Horizontal Action Panel, as described in the previous section,\nconsists of various application-related actions, such as–<ul class=incremental><li><p><strong>Launch.</strong> Launch the application provided it has a\nlauncher <a href=#subsubsec:activities>activity</a>.<li><p><strong>Freeze.</strong> Freeze the application. This button is\nnot displayed if it is already frozen or the user does not have enough\nprivileges. After the application is frozen, it may be hidden from the\napp drawer depending on how it was configured. Shortcuts configured by\nthe application may also be removed. The application may only be\nunfrozen via App Manager, <code>pm</code> command or any other tools\nthat offer such a feature. Long clicking on the button opens a dialog\nwhere a shortcut can be configured to quickly freeze or unfreeze the\napplication.<li><p><strong>Uninstall.</strong> Uninstall the application with a\nprompt. In the dialog prompt, it is possible to uninstall updates of a\nsystem application, or if App Manager has enough privileges or the\noperating system supports it, it is possible to uninstall the\napplication without clearing its data and signature. For the latter\ncase, the installed application must match the signature with the\npreviously installed application if it is installed again.<div class=\"amalert tip\"><p><strong><em>Tips.</em></strong><p>A better way to reinstall an application with a different signature\nwould be to back up its data using App Manager and restore it again\nafter installing the application instead of opting to preserving data\nand signature of the application during uninstallation as this option\nmay cause undefined behaviour in the future.</div><li><p><strong>Unfreeze.</strong> Unfreeze the application. This button\nis not displayed if it is already enabled or the user does not have\nenough privileges. Similar to the <em>Freeze</em> button, long clicking\non the button opens a dialog where a shortcut can be configured to\nquickly freeze or unfreeze the application.<li><p><strong>Force Stop.</strong> Force-stop the application.<li><p><strong>Clear Data.</strong> Clear data from the application.\nThis includes any information stored in the internal and, recently, the\nexternal directories, including accounts (if set by the application),\ncache, etc. Clearing data from App Manager, for example, removes all the\nrules (the blocking is not removed though) saved within the application\n(Which is why you should always take backups of your rules). This button\nis not displayed if the user does not have enough privileges.<li><p><strong>Clear Cache.</strong> Clear the application cache. If the\napplication is running during the operation, the cache may not be\ncleared as expected.<li><p><strong>Install.</strong> Install the application, only displayed\nif the application hasn’t already been installed.<li><p><strong>What’s New.</strong> Displayed for an external\napplication if an older version of it is already installed. Clicking on\nthis button opens a dialog containing the differences between this and\nthe installed version in a version control manner. Changes include\n<em>version</em>, <em>trackers</em>, <em>permissions</em>,\n<em>components</em>, <em>signatures</em> (only checksum changes),\n<em>features</em>, <em>shared libraries</em> and <em>SDK</em>.<li><p><strong>Update.</strong> Displayed if the application has a\nhigher version code than the installed application.<li><p><strong>Reinstall.</strong> Displayed if the application has the\nsame version code as the installed application.<li><p><strong>Downgrade.</strong> Displayed if the application has a\nlower version code than the installed application.<li><p><strong>Manifest.</strong> Opens the application’s manifest file\nin a separate page. If the application has more than one split, it will\ndisplay the list of split APK files, and clicking on an item will open\nthe corresponding manifest file instead.<li><p><strong>Scanner.</strong> Scan the application in order to list\npotential trackers and libraries. It also scans the file using\nVirusTotal and fetch results from Pithus if configured.<br><div class=seealso-inline><p><em>See also: <span><a href=#sec:scanner-page>Scanner\npage</a></span></em></div><li><p><strong>Shared Prefs.</strong> Displays a list of shared\npreferences used by the application. Clicking on a preference item in\nthe list opens the <a href=#sec:shared-preferences-editor-page>Shared\nPreferences Editor page</a>. This option is only visible if the user has\nthe required privileges.<li><p><strong>Databases.</strong> Displays a list of databases used by\nthe application. Clicking on an item opens a list of activities that can\nopen the database. This option is only visible if the user has the\nrequired privileges.<li><p><strong>F-Droid.</strong> Open the application in the selected\n<em>F-Droid</em> client.<li><p><strong>Store.</strong> Open the application in <em>Aurora\nStore</em>. The option is only visible if <em>Aurora Store</em> is\ninstalled.</ul></section><section id=subsubsec:app-info-options-menu class=level4 data-number=2.2.2.4><h4 data-number=2.2.2.4><span class=header-section-number>2.2.2.4</span> Options Menu<a href=#subsubsec:app-info-options-menu class=anchor aria-hidden=true></a></h4><p>Options-menu is located in the top-right corner of the page. A\ncomplete description of the options present there are given below:<ul class=incremental><li><p><strong>Share.</strong> Share button can be used to share the APK\nor (if the application is has multiple splits, OBB files or any\ndependencies) <em>APKS</em> file extracted from the\napplication.<li><p><strong>Refresh.</strong> Refresh the App Info tab.<li><p><strong>View in Settings.</strong> Open the application in\nAndroid Settings.<li><p><strong>Backup/restore.</strong> Open the backup/restore\ndialog.<li><p><strong>Export blocking rules.</strong> Export rules configured\nfor the application within App Manager.<li><p><strong>Open in Termux.</strong> Open the application in Termux.\nThis actually runs <code>su - user_id</code> where <code>user_id</code>\ndenotes the application’s kernel user ID (described in §<a href=#subsubsec:app-info-general-information data-reference-type=ref data-reference=subsubsec:app-info-general-information>2.2.2.1</a>).\nThis option is only visible to the root users. See §<a href=#subsubsec:config-termux data-reference-type=ref data-reference=subsubsec:config-termux>2.2.2.5</a> to learn how to\nconfigure Termux to run commands from third-party applications.<li><p><strong>Run in Termux.</strong> Open the application via\n<code>run-as package_name</code> in Termux. This is only applicable to\nthe debuggable applications and works for both root and ADB users. See\n§<a href=#subsubsec:config-termux data-reference-type=ref data-reference=subsubsec:config-termux>2.2.2.5</a> to learn how to\nconfigure Termux to run commands from third-party applications.<li><p><strong>MagiskHide.</strong> Open a dialog containing the list of\nprocess names within the application that can be added or removed from\nthe MagiskHide list.<li><p><strong>Magisk DenyList.</strong> Open a dialog containing the\nlist of process namees within the application that can be added or\nremoved from Magisk DenyList.<li><p><strong>Battery optimisation.</strong> Enable/disable battery\noptimisation for this application.<li><p><strong>Sensors.</strong> Enable/disable sensors for this\napplication.<li><p><a href=#sec:net-policy><strong>Net policy.</strong></a>\nConfigure network policy (e.g., background data usage) for the\napplication.<li><p><strong>Extract Icon.</strong> Extract and save the application’s\nicon in the shared storage.<li><p><strong>Optimize.</strong> Perform optimisation for this\napplication. This option is for advanced users only.<li><p><strong>Add to profile.</strong> Add the application to one of\nthe configured <a href=#sec:profile-page>profiles</a>.<li><p><strong>Install for….</strong> Install the application for\nanother user and/or in the work profile if configured.</ul></section><section id=subsubsec:config-termux class=level4 data-number=2.2.2.5><h4 data-number=2.2.2.5><span class=header-section-number>2.2.2.5</span> Configuring Termux<a href=#subsubsec:config-termux class=anchor aria-hidden=true></a></h4><p>By default, Termux does not allow running commands from a third-party\napplication. To use this option, Termux v0.96 or later is required and\n<code>allow-external-apps=true</code> must be added in\n<code>~/.termux/termux.properties</code>.<div class=\"amalert tip\"><p><strong><em>Info.</em></strong><p>Enabling this option does not weaken Termux’ security. The\nthird-party applications still need to ask the user to allow running\narbitrary commands in Termux.</div></section></section><section id=subsec:component-tabs class=level3 data-number=2.2.3><h3 data-number=2.2.3><span class=header-section-number>2.2.3</span>\n<a href=#toc:subsec:component-tabs>Component Tabs</a><a href=#subsec:component-tabs class=anchor aria-hidden=true></a></h3><p><strong>Activities</strong>, <strong>Services</strong>,\n<strong>Receivers</strong> (i.e., broadcast receivers) and\n<strong>Providers</strong> (e.g., content providers) are collectively\nknown as the application components, because they offer similar features\nand share similar properties. For example, they all have a\n<em>name</em>, a <em>label</em>, an <em>icon</em>, can be enabled or\ndisabled, and can be executed via <em>Intent</em>. Application\ncomponents are the building blocks of an application and must be\ndeclared in the application manifest (with a few exceptions).\nApplication manifest is a file where application specific metadata are\nstored. The Android operating system learns what to do with the\napplication by reading the metadata.<p>Colours used in these tabs are explained in §<a href=#subsec:app-details-colour-codes data-reference-type=ref data-reference=subsec:app-details-colour-codes>2.2.1</a>. It is also\npossible to sort the list of components to display blocked or tracker\ncomponents on top of the list via the <strong>Sort</strong> option\nlocated in the three-dots menu.<section id=subsubsec:activities class=level4 data-number=2.2.3.1><h4 data-number=2.2.3.1><span class=header-section-number>2.2.3.1</span> Activities<a href=#subsubsec:activities class=anchor aria-hidden=true></a></h4><p><strong>Activities</strong> are the windows or pages that can be\nuniquely identified by the Android operating system (e.g., <em>Main\npage</em> and <em>App Details page</em> are two activities). Each\nactivity can have multiple UI components known as <em>widgets</em> or\n<em>fragments</em>, and each component can be nested or placed on top of\neach other. The developer can also choose to open external files, links,\netc. within an activity using a method called <em>intent filters</em>.\nFor example, when you open a file in your file manager, either your file\nmanager or the operating system scans the intent filters via\nPackageManager, find the activities capable of opening the file, and\nlist those activities so that you can choose your preferred\nactivity.<p>Activities that are <em>exportable</em> can be opened by any\nthird-party applications. However, Some activities may require\npermissions, and only an application having those permissions can open\nthem. In the <em>Activities</em> tab, certain activities can be launched\nvia the <strong>Launch</strong> button. If it is necessary to supply\nadditional information, such as Intent extras, data or action, long\nclicking on the <strong>Launch</strong> button opens the <a href=#sec:interceptor-page>Activity Interceptor</a> page which\nprovides such features.<div class=\"amalert tip\"><p><strong><em>Tip.</em></strong><p>No-root users can grant\n<code>android.permission.WRITE_SECURE_SETTINGS</code> via ADB to launch\n<em>non-exportable</em> activities.</div><div class=\"amalert tip\"><p><strong><em>Notice.</em></strong><p>If launching an activity throws an error, it may have certain\ndependencies which are not met (e.g., <em>App Details</em> page in App\nManager cannot be launched using the launch button, because it requires\na package name). Since the dependencies cannot be inferred\nprogrammatically, the activity may not be opened from App Manager by\ndefault.</div><p>It is also possible to create shortcuts of an activity-launch using\nthe <strong>Create shortcut</strong> button. If you need to supply\nadditional information, you can create a shortcut from the Activity\nInterceptor page instead.<div class=\"amalert danger\"><p><strong><em>Caution.</em></strong><p>If you uninstall App Manager, all shortcuts created by App Manager\nwill be lost.</div></section><section id=subsubsec:details:servcies class=level4 data-number=2.2.3.2><h4 data-number=2.2.3.2><span class=header-section-number>2.2.3.2</span> Services<a href=#subsubsec:details:servcies class=anchor aria-hidden=true></a></h4><p>Unlike <a href=#subsubsec:activities>activities</a> that users can\nsee, <strong>Services</strong> handle background tasks. For example, if\nyou’re downloading a video from the internet using your phone’s Internet\nbrowser, the Internet browser is using a <em>foreground service</em> to\ndownload the content.<p>When an activity is closed or removed from the <em>Recents</em> page,\nit may be destroyed immediately depending on the amount free memory the\nphone has, battery statistics, or how the activity is configured. But\nservices can be run indefinitely if desired. If more services run in the\nbackground, the phone may become slower due to the shortage of memory\nand/or processing power, and the phone’s battery will be drained more\nquickly. Newer versions of Android come with a battery optimisation\nfeature enabled by default for all applications. With this feature\nenabled, the system can randomly terminate any service depending on the\namount of resources the system has or the service requires. However,\nforeground services (i.e., services that run with a fixed notification,\nsuch as music player or downloader) are not typically terminated unless\nthe system is very low on resources (memory, battery, etc.). Certain\nstock ROMs can offer more aggressive optimisation. MIUI, for example,\nhas a very aggressive optimisation feature known as the <em>MIUI\noptimisation</em>.<p>Both activities and services are run in the same <a href=https://stackoverflow.com/questions/7597742>looper</a> called the\nmain looper, which means the services do not really run in the\nbackground. It is the task of the developer to ensure this. How do the\napplication communicate with the services? It uses <a href=#subsubsec:app-details-receivers>broadcast receiver</a> or\nBinder.</section><section id=subsubsec:app-details-receivers class=level4 data-number=2.2.3.3><h4 data-number=2.2.3.3><span class=header-section-number>2.2.3.3</span> Receivers<a href=#subsubsec:app-details-receivers class=anchor aria-hidden=true></a></h4><p><strong>Receivers</strong> (also called <em>broadcast receivers</em>)\ncan be used to trigger execution of certain tasks when certain events\noccur. These components are called broadcast receivers, because they are\nexecuted as soon as a broadcast message is received. These broadcast\nmessages are sent using a method called <em>Intent</em>. Intent is a\nspecial feature in Android that can be used to open applications (i.e.,\nactivities), run services and send broadcast messages. Therefore, like\n<a href=#subsubsec:activities>activities</a>, broadcast receivers use\n<em>intent filters</em> to receive the desired broadcast messages.\nBroadcast messages can be sent by the system or the application itself.\nWhen a broadcast message is sent, the corresponding receivers are\nactivated by the system so that they can execute tasks. For example, if\nyour phone is low on resources, it may freeze or experience lags for a\nmoment after you enable mobile data or connect it to the Wi-Fi. This is\nbecause broadcast receivers that can receive\n<code>android.net.conn.CONNECTIVITY_CHANGE</code> are activated by the\nsystem as soon as the data connection is enabled. Since many\napplications typically use this intent filter, they are all activated\nalmost immediately by the system which causes the freezing or lags.<p>Receivers can also be used for inter-process communication (IPC),\ni.e., it can be used to communicate across multiple applications or even\ndifferent components of a single application.</section><section id=subsubsec:providers class=level4 data-number=2.2.3.4><h4 data-number=2.2.3.4><span class=header-section-number>2.2.3.4</span> Providers<a href=#subsubsec:providers class=anchor aria-hidden=true></a></h4><p><strong>Providers</strong> are primarily used for data management.\nFor example, when you save an APK file or export rules in App Manager,\nit uses a content provider called <code>.fm.FmProvider</code> to save\nthe APK or export the rules. There are many providers, including the\nones provided by the system, that can be used to manage various\ncontent-related tasks, such as database management, tracking, searching,\netc. Each provider has a field called <em>Authority</em> which is unique\nto the application in the entire Android ecosystem just as the package\nname.</section><section id=additional-features-for-rooted-phones class=level4 data-number=2.2.3.5><h4 data-number=2.2.3.5><span class=header-section-number>2.2.3.5</span> Additional Features for\nRooted Phones<a href=#additional-features-for-rooted-phones class=anchor aria-hidden=true></a></h4><p>Unlike the no-root users who are mostly spectators in these tabs,\nroot users can perform various operations.<section id=blocking-components. class=level5 data-number=2.2.3.5.1><h5 data-number=2.2.3.5.1><span class=header-section-number>2.2.3.5.1</span> Blocking Components.<a href=#blocking-components. class=anchor aria-hidden=true></a></h5><p>On the right-most side of each component item, there is a switch\nwhich can be used to toggle the blocking status of that particular\ncomponent. If <a href=#subsubsec:instant-component-blocking>Instant\nComponent Blocking</a> is not enabled or blocking is never applied to\nthe application before, it is required to apply the changes using the\n<strong>Apply rules</strong> option in three-dots menu. It is also\npossible to remove the already-applied rules using the same option\n(which would be read as <strong>Remove rules</strong> this time).<p>It is also possible to block the component using one of the several\nmethods by long clicking on the button.<div class=seealso-inline><p><em>See also: <span><a href=#sec:faq:app-components>FAQ: App\nComponents</a></span></em></div></section><section id=par:appdetails:blocking-trackers class=level5 data-number=2.2.3.5.2><h5 data-number=2.2.3.5.2><span class=header-section-number>2.2.3.5.2</span> Blocking Trackers.<a href=#par:appdetails:blocking-trackers class=anchor aria-hidden=true></a></h5><p>It is possible to disable tracker components using the <strong>Block\ntracker</strong> option in the three-dots menu. All tracker components\nwill be blocked regardless of the tab you’re currently in.<div class=\"amalert tip\"><p><strong><em>Info.</em></strong><p>Tracker components are a subset of application components. Therefore,\nthey are blocked using the same method used for blocking any other\ncomponents.</div><div class=seealso><p><em>See also:</em><ul class=incremental><li><p><a href=#subsec:tracker-classes-versus-tracker-components>FAQ:\nTracker classes versus tracker components</a><li><p><a href=#sec:scanner-page>Scanner Page</a><li><p><a href=#subsec:block-unblock-trackers>1-Click Ops Page:\nBlock/Unblock Trackers</a></ul></div></section></section></section><section id=subsec:permission-tabs class=level3 data-number=2.2.4><h3 data-number=2.2.4><span class=header-section-number>2.2.4</span>\n<a href=#toc:subsec:permission-tabs>Permission Tabs</a><a href=#subsec:permission-tabs class=anchor aria-hidden=true></a></h3><p><strong>App Ops</strong>, <strong>Uses Permissions</strong> and\n<strong>Permissions</strong> tabs are related to permissions. In Android\ncommunication across applications or processes not having the same\nidentity (known as <em>shared ID</em>) often require permissions. These\npermissions are managed by the permission controller. Some permissions\nare considered <em>normal</em> permissions which are granted\nautomatically if they appear in the application manifest, but\n<em>dangerous</em> and <em>development</em> permissions require\nconfirmation from the user. Colours used in these tabs are explained in\n§<a href=#subsec:app-details-colour-codes data-reference-type=ref data-reference=subsec:app-details-colour-codes>2.2.1</a>.<section id=subsubsec:app-ops class=level4 data-number=2.2.4.1><h4 data-number=2.2.4.1><span class=header-section-number>2.2.4.1</span> App Ops<a href=#subsubsec:app-ops class=anchor aria-hidden=true></a></h4><p><strong>App Ops</strong> stands for <strong>Application\nOperations</strong>. Since Android 4.3, <em>App Ops</em> are used by\nAndroid to control many system permissions. Each app op has a unique\nnumber associated with it which is displayed along with the private name\nof the operation in the App Ops tab. Some app ops also have a public\nname. A large number of app ops are also associated with\n<em>permissions</em>. In this tab, an app op is considered dangerous if\nits associated permission is marked as dangerous. Other information such\nas <em>flags</em>, <em>permission name</em>, <em>permission\ndescription</em>, <em>package name</em>, <em>group</em> are also taken\nfrom the associated <a href=#subsubsec:permissions>permission</a>.\nOthers may include the following:<ul class=incremental><li><p><strong>Mode.</strong> It describes the current authorisation\nstatus which can be <em>allow</em>, <em>deny</em> (a rather misnomer, it\nsimply means error), <em>ignore</em> (it actually means deny),\n<em>default</em> (inferred from a list of defaults set internally by the\nvendor or the AOSP), <em>foreground</em> (in newer Android versions, it\nmeans the app op can only be used when the application is running in\nforeground), and some custom modes set by the vendors (MIUI uses\n<em>ask</em>, for example).<li><p><strong>Duration.</strong> The amount of time this app op has\nbeen used (there can be negative durations whose use cases are currently\nunknown to me).<li><p><strong>Accept Time.</strong> Last time the app op was\naccepted.<li><p><strong>Reject Time.</strong> Last time the app op was\nrejected.</ul><div class=\"amalert tip\"><p><strong><em>Info.</em></strong><p>Contents of this tab are visible to no-root users if\n<code>android.permission.GET_APP_OPS_STATS</code> is granted via\nADB.</div><p>There is a toggle button next to each app op item which can be used\nto allow or deny (ignore) it. Other supported modes can also be set by\nlong clicking on the toggle button. If the desired app op is not listed\nin the tab, <em>Set custom app op</em> option in the menu can be used\ninstead. It is also possible to reset the changes using the <em>Reset to\ndefault</em> option, or deny all the dangerous app ops using the\ncorresponding option in the menu. Due to the nature how app ops work,\nthe system may take some time to apply them.<div class=\"amalert tip\"><p><strong><em>Tip.</em></strong><p>Denying certain app ops may cause the application to misbehave. If\nall attempts fail, <em>reset to default</em> option can be used as the\nlast resort.</div><p>It is possible to sort the list in ascending order by app op names\nand the associated unique numbers (or values), or list the denied app\nops first using the corresponding sorting options.<div class=seealso-inline><p><em>See also: <span><a href=#ch:app-ops>Appendix: App\nOps</a></span></em></div></section><section id=uses-permissions class=level4 data-number=2.2.4.2><h4 data-number=2.2.4.2><span class=header-section-number>2.2.4.2</span> Uses Permissions<a href=#uses-permissions class=anchor aria-hidden=true></a></h4><p><strong>Uses Permissions</strong> are the permissions used by the\napplication. This is named so because they are specified in the manifest\nusing <code>uses-permission</code> tags. Information such as\n<em>flags</em>, <em>permission name</em>, <em>permission\ndescription</em>, <em>package name</em>, <em>group</em> are taken from\nthe associated <a href=#subsubsec:permissions>permission</a>.<p>Privileged users can grant or revoke the <em>dangerous</em> and\n<em>development</em> permissions via the toggle button on the right side\nof each permission item. It is also possible revoke dangerous\npermissions all at once using the corresponding option in the menu. Only\nthese two types of permissions can be revoked because Android does not\nallow the modification of <em>normal</em> permissions (which most of\nthem are). It might still be possible to revoke them by editing\n<code>runtime-permissions.xml</code> itself, but whether this is a\npossibility is still being investigated.<div class=\"amalert tip\"><p><strong><em>Info.</em></strong><p>Since dangerous permissions are revoked by default by the system,\nrevoking all dangerous permissions is the same as resetting all the\npermissions.</div><p>It is possible to sort the permissions by their name (in ascending\norder) or choose to display denied or dangerous permissions at first\nusing the corresponding options in the menu.</section><section id=subsubsec:permissions class=level4 data-number=2.2.4.3><h4 data-number=2.2.4.3><span class=header-section-number>2.2.4.3</span> Permissions<a href=#subsubsec:permissions class=anchor aria-hidden=true></a></h4><p><strong>Permissions</strong> are usually custom permissions defined\nby the application itself. These type of permissions are marked as\n<em>Internal</em> permissions. It also contains permissions declared by\nother applications which are marked as <em>External</em> permissions. An\nexternal permission can be specified in an <em>exported</em> application\ncomponent so that another application may invoke the component only if\nit holds the permission. Below is a complete description of each item\ndisplayed in this tab:<ul class=incremental><li><p><strong>Name.</strong> A permission has a unique name (e.g.,\n<code>android.permission.INTERNET</code>) that multiple applications can\nrequest. The application that declared the permission is automatically\ngranted and cannot be revoked.<li><p><strong>Icon.</strong> Each permission can have a custom icon.\nThe other permission tabs do not have any icon because they do not\ncontain any icon in the application manifest.<li><p><strong>Description.</strong> This optional field describes the\npermission. If there isn’t any description associated with the\npermission, the field is not displayed.<li><p><strong>Flags.</strong> (Uses the flag symbol or\n<strong>Protection Level</strong> name) This describes various\npermission flags such as <em>normal</em>, <em>development</em>,\n<em>dangerous</em>, <em>instant</em>, <em>granted</em>,\n<em>revoked</em>, <em>signature</em>, <em>privileged</em>, etc.<li><p><strong>Package Name.</strong> Denotes the package name\nassociated with the permission, i.e. the package that defined the\npermission.<li><p><strong>Group.</strong> The group name associated with the\npermission (if any). Several related permissions can often be grouped\ntogether.</ul></section></section><section id=subsec:signatures-tab class=level3 data-number=2.2.5><h3 data-number=2.2.5><span class=header-section-number>2.2.5</span>\n<a href=#toc:subsec:signatures-tab>Signatures Tab</a><a href=#subsec:signatures-tab class=anchor aria-hidden=true></a></h3><p><strong>Signatures</strong> are actually called signing information.\nAn application is signed with one or more signing keys by its developer\nbefore publishing it. The integrity of an application, i.e., whether the\napplication is from the actual developer and has not been modified by\nanother person, can be checked using the signing certificate included in\nthe APK files. This is because when an application is modified by an\nunauthorised entity, the application can longer be signed with the\noriginal signing keys since the signing keys are unknown to the entity.\nOne way to verify the integrity of an application is via the checksums\ngenerated from the certificates. If the developer supplies the checksums\nfor the signing certificates, they can be compared against the checksums\ngenerated in the <strong>Signatures</strong> tab to verify the\napplication. For example, if you have downloaded App Manager from GitHub\nor Telegram Channel, you can verify whether the application was actually\nreleased by me by simply matching the following <em>SHA256</em> checksum\nwith the one displayed in this tab:<pre><code>320c0c0fe8cef873f2b554cb88c837f1512589dcced50c5b25c43c04596760ab</code></pre><p>Several hashing algorithms are used to generate checksums in this\ntab. They include <em>MD5</em>, <em>SHA1</em>, <em>SHA256</em> and\n<em>SHA512</em>.<div class=\"amalert danger\"><p><strong><em>Caution.</em></strong><p>Signing information should be verified using a reliable hashing\nalgorithm, such as <em>SHA256</em>. DO NOT rely on <em>MD5</em> or\n<em>SHA1</em> checksums as they are known to generate the same checksums\nfor multiple certificates.</div></section><section id=subsec:uses-features-tab class=level3 data-number=2.2.6><h3 data-number=2.2.6><span class=header-section-number>2.2.6</span>\n<a href=#toc:subsec:uses-features-tab>Uses Features tab</a><a href=#subsec:uses-features-tab class=anchor aria-hidden=true></a></h3><p><strong>Uses Features</strong> tab lists the features declared by the\napplication, such as OpenGL ES, telephony, and leanback. Some features\ncan be required by the application, and some features can be optional.\nRequired features must be present in the system along with the required\nversion. Otherwise, any attempt to install the application will be\ndenied by the system. Colours used in this tab are explained in §<a href=#subsec:app-details-colour-codes data-reference-type=ref data-reference=subsec:app-details-colour-codes>2.2.1</a>.</section><section id=subsec:configurations-tab class=level3 data-number=2.2.7><h3 data-number=2.2.7><span class=header-section-number>2.2.7</span>\n<a href=#toc:subsec:configurations-tab>Configurations tab</a><a href=#subsec:configurations-tab class=anchor aria-hidden=true></a></h3><p><strong>Configurations</strong> tab lists the configurations required\nby the application, such as input method type (qwerty, 12 key), touch\nscreen type (finger, stylus, etc.), and navigation type (dial pad,\ntrackball, wheel). This tab is going to be empty for most\napplications.</section><section id=subsec:shared-libs-tab class=level3 data-number=2.2.8><h3 data-number=2.2.8><span class=header-section-number>2.2.8</span>\n<a href=#toc:subsec:shared-libs-tab>Shared Libraries Tab</a><a href=#subsec:shared-libs-tab class=anchor aria-hidden=true></a></h3><p><strong>Shared libraries</strong> tab lists the legacy JAR\ndependencies, any static shared library dependencies (currently, the\nonly known cases are the Chromium-based browsers and WebViews) as well\nas the JNI (Java native interface) libraries. For JNI libraries, it\nspecifies platform (x86/x86_64/ARM/AArch64), architecture (32/64 bit),\nobject type (shared object or executable), etc.</section></section><section id=sec:1-click-ops-page class=level2 data-number=2.3><h2 data-number=2.3><span class=header-section-number>2.3</span> <a href=#toc:sec:1-click-ops-page>1-Click Ops Page</a><a href=#sec:1-click-ops-page class=anchor aria-hidden=true></a></h2><p>This page is displayed on selecting the <a href=#subsubsec:main:1-click-ops>1-Click Ops option</a> in the <a href=#subsec:main-page-options-menu>main menu</a>.<section id=subsec:block-unblock-trackers class=level3 data-number=2.3.1><h3 data-number=2.3.1><span class=header-section-number>2.3.1</span>\n<a href=#toc:subsec:block-unblock-trackers>Block/Unblock\nTrackers</a><a href=#subsec:block-unblock-trackers class=anchor aria-hidden=true></a></h3><p>This option can be used to block or unblock the ad/tracker components\nfrom the installed applications. On selecting this option, App Manager\nwill ask if it should list trackers from all the applications or only\nfrom the user applications. Novice users should avoid blocking trackers\nfrom the system applications in order to avoid bad consequences. After\nthat, a multi-choice dialog box will appear where it is possible to\nexclude one or more applications from this operation. The changes are\napplied immediately on pressing the <em>block</em> or <em>unblock</em>\nbutton.<div class=\"amalert warning\"><p><strong><em>Notice.</em></strong><p>Certain applications may not function as expected after blocking\ntheir trackers. If that is the case, remove the blocking rules all at\nonce or one by one in the component tabs of the <a href=#sec:app-details-page>App Details page</a> for the corresponding\napplication.</div><div class=seealso-inline><p><em>See also: <span><a href=#par:appdetails:blocking-trackers>App\nDetails Page: Blocking Trackers</a></span></em></div></section><section id=subsec:block-components-dots class=level3 data-number=2.3.2><h3 data-number=2.3.2><span class=header-section-number>2.3.2</span>\n<a href=#toc:subsec:block-components-dots>Block Components…</a><a href=#subsec:block-components-dots class=anchor aria-hidden=true></a></h3><p>This option can be used to block certain application components as\nspecified by their signatures. A signature of a component is the full\nname or partial name of the component. For safety, it is recommended to\nadd a <code>.</code> (dot) at the end of each partial signature, because\nthe underlying algorithm searches and matches the components in a greedy\nmanner. It is also possible to insert more than one signature in which\ncase all the signatures have to be separated by white spaces. Similar to\nthe option above, there is also an option to apply blocking to the\nsystem applications.<div class=\"amalert danger\"><p><strong><em>Caution.</em></strong><p>If you are not aware of the consequences of blocking applcations\ncomponents by their signatures, you should avoid using this option as it\nmay result in bootloop or soft brick, and you may have to apply factory\nreset as a result.</div></section><section id=subsec:set-mode-for-app-ops-dots class=level3 data-number=2.3.3><h3 data-number=2.3.3><span class=header-section-number>2.3.3</span>\n<a href=#toc:subsec:set-mode-for-app-ops-dots>Set Mode for App\nOps…</a><a href=#subsec:set-mode-for-app-ops-dots class=anchor aria-hidden=true></a></h3><p>This option can be used to configure certain <a href=#ch:app-ops>applcation operations</a> of all or selected\napplications. There are two fields. The first field can be used to\ninsert more than one app op constants (either names or values) separated\nby white spaces. It is not always possible to know in advance about all\nthe app op constants as they vary from device to device and from OS to\nOS. Desired app op constant can be found in the <em>App Ops</em> tab\nlocated in the <a href=#sec:app-details-page>App Details page</a>. The\nsecond field can be used to insert or select one of the <a href=#subsec:mode-constants>modes</a> that will be set against the\nspecified app ops.<div class=\"amalert danger\"><p><strong><em>Caution.</em></strong><p>Unless you are well-informed about app ops and the consequences of\nblocking them, you should avoid using this option.</div></section><section id=subsec:1-click-back-up class=level3 data-number=2.3.4><h3 data-number=2.3.4><span class=header-section-number>2.3.4</span>\n<a href=#toc:subsec:1-click-back-up>Back up</a><a href=#subsec:1-click-back-up class=anchor aria-hidden=true></a></h3><p>1-Click options for back up. As a precaution, it lists the affected\nbackups before performing any operation.<section id=back-up-all-apps. class=level5 data-number=2.3.4.0.1><h5 data-number=2.3.4.0.1><span class=header-section-number>2.3.4.0.1</span> Back up all apps.<a href=#back-up-all-apps. class=anchor aria-hidden=true></a></h5><p>Back up all the installed applications.</section><section id=redo-existing-backups. class=level5 data-number=2.3.4.0.2><h5 data-number=2.3.4.0.2><span class=header-section-number>2.3.4.0.2</span> Redo existing backups.<a href=#redo-existing-backups. class=anchor aria-hidden=true></a></h5><p>Back up all the installed applications that have a previous\nbackup.</section><section id=back-up-apps-without-backups. class=level5 data-number=2.3.4.0.3><h5 data-number=2.3.4.0.3><span class=header-section-number>2.3.4.0.3</span> Back up apps without\nbackups.<a href=#back-up-apps-without-backups. class=anchor aria-hidden=true></a></h5><p>Back up all the installed applications without a previous backup.</section><section id=verify-and-redo-backups. class=level5 data-number=2.3.4.0.4><h5 data-number=2.3.4.0.4><span class=header-section-number>2.3.4.0.4</span> Verify and redo\nbackups.<a href=#verify-and-redo-backups. class=anchor aria-hidden=true></a></h5><p>Verify the recently made backups of the installed applications and\nredo backup if necessary.</section><section id=back-up-apps-with-changes. class=level5 data-number=2.3.4.0.5><h5 data-number=2.3.4.0.5><span class=header-section-number>2.3.4.0.5</span> Back up apps with\nchanges.<a href=#back-up-apps-with-changes. class=anchor aria-hidden=true></a></h5><p>If an app has changed since the last backup, redo its backup. It\nchecks a number of indices including application version, last update\ndate, last launch date, integrity and file hashes. Directory hashes are\ntaken during the backup process and are stored in a database. On running\nthis operation, new hashes are taken and compared with the ones kept in\nthe database.</section></section><section id=subsec:1-click-restore class=level3 data-number=2.3.5><h3 data-number=2.3.5><span class=header-section-number>2.3.5</span>\n<a href=#toc:subsec:1-click-restore>Restore</a><a href=#subsec:1-click-restore class=anchor aria-hidden=true></a></h3><p>1-Click options for restore. As a precaution, it lists the affected\nbackups before performing any operation.<section id=restore-all-apps. class=level5 data-number=2.3.5.0.1><h5 data-number=2.3.5.0.1><span class=header-section-number>2.3.5.0.1</span> Restore all apps.<a href=#restore-all-apps. class=anchor aria-hidden=true></a></h5><p>Restore <em>base backup</em> of all the backed up applications.</section><section id=restore-not-installed-apps. class=level5 data-number=2.3.5.0.2><h5 data-number=2.3.5.0.2><span class=header-section-number>2.3.5.0.2</span> Restore not installed\napps.<a href=#restore-not-installed-apps. class=anchor aria-hidden=true></a></h5><p>Restore <em>base backup</em> of all the backed up applications that\nare not currently installed.</section><section id=restore-latest-backups. class=level5 data-number=2.3.5.0.3><h5 data-number=2.3.5.0.3><span class=header-section-number>2.3.5.0.3</span> Restore latest backups.<a href=#restore-latest-backups. class=anchor aria-hidden=true></a></h5><p>Restore <em>base backup</em> of already installed applications whose\nversion codes are higher than the installed version code.</section></section><section id=subsec:trim-caches-in-all-apps class=level3 data-number=2.3.6><h3 data-number=2.3.6><span class=header-section-number>2.3.6</span>\n<a href=#toc:subsec:trim-caches-in-all-apps>Trim Caches in All\nApps</a><a href=#subsec:trim-caches-in-all-apps class=anchor aria-hidden=true></a></h3><p>Delete caches from all applications, including Android system. During\nthis operation, caches of all the running applications may not be\ncleared as expected.</section></section><section id=sec:profiles-page class=level2 data-number=2.4><h2 data-number=2.4><span class=header-section-number>2.4</span> <a href=#toc:sec:profiles-page>Profiles Page</a><a href=#sec:profiles-page class=anchor aria-hidden=true></a></h2><p>Profiles page can be accessed from the <a href=#subsec:main-page-options-menu>options-menu</a> in the main page.\nIt primarily displays a list of configured profiles along with the\ntypical options to perform operations on them. New profiles can also be\nadded using the <em>plus</em> button at the bottom-right corner.\nProfiles can be imported, duplicated or deleted. Clicking on a profile\nitem opens its <a href=#sec:profile-page>profile page</a>.<section id=subsec:profiles-options-menu class=level3 data-number=2.4.1><h3 data-number=2.4.1><span class=header-section-number>2.4.1</span>\n<a href=#toc:subsec:profiles-options-menu>Options Menu</a><a href=#subsec:profiles-options-menu class=anchor aria-hidden=true></a></h3><p>The three-dots menu in the top-right corner opens the global option\nmenu. It has an option to import an existing profile that was previously\nexported from App Manager.<p>Long clicking on any profile item brings up another options-menu. It\noffers the following options:<ul class=incremental><li><p><strong>Apply now….</strong> This option can be used to apply the\nprofile directly. When clicked, a dialog is displayed where it is\npossible to select a <a href=#subsubsec:profile-state>profile\nstate</a>. On selecting one of the states, the profile will be applied\nimmediately.<li><p><strong>Delete.</strong> Clicking on this option will remove the\nprofile immediately without a warning.<li><p><strong>Duplicate.</strong> This option can be used to duplicate\nthe profile. When clicked, a dialog is displayed where it is possible to\nset a name for the new profile. On clicking “OK”, the <a href=#sec:profile-page>profile page</a> will be loaded by duplicating\nall the configurations that this profile have. However, the profile will\nnot be saved until it is saved manually.<li><p><strong>Copy profile ID.</strong> This option is used to copy the\nunique profile ID of the profile. The profile ID can be used to <a href=#subsec:triggering-a-profile>trigger the profile</a> from a\nthird-party application.<li><p><strong>Export.</strong> Export the profile to an external\nstorage. Profiles exported this way can be imported via the\n<em>import</em> option as mentioned above.<li><p><strong>Create shortcut.</strong> This option can be used to\ncreate a shortcut for the profile. There are two options:\n<em>Simple</em> and <em>Advanced</em>. When configured with the latter\noption, it prompts the user to select a profile state when the shortcut\nis invoked. The former option, on the other hand, always uses the\ndefault state that was configured when the profile was last\nsaved.</ul></section></section><section id=sec:profile-page class=level2 data-number=2.5><h2 data-number=2.5><span class=header-section-number>2.5</span> <a href=#toc:sec:profile-page>Profile Page</a><a href=#sec:profile-page class=anchor aria-hidden=true></a></h2><p>Profile page displays the configurations for a profile. It also\noffers the options to edit them.<section id=subsec:profile-options-menu class=level3 data-number=2.5.1><h3 data-number=2.5.1><span class=header-section-number>2.5.1</span>\n<a href=#toc:subsec:profile-options-menu>Options Menu</a><a href=#subsec:profile-options-menu class=anchor aria-hidden=true></a></h3><p>The three dots menu in the top-right corner opens the options-menu.\nIt contains several options such as–<ul class=incremental><li><p><strong>Apply.</strong> This option can be used to apply the\nprofile directly. When clicked, a dialog is displayed where it is\npossible to select a <a href=#subsubsec:profile-state>profile\nstate</a>. On selecting one of the states, the profile will be applied\nimmediately.<div class=\"amalert tip\"><p><strong><em>Notice.</em></strong><p>When you apply a profile, if some packages do not match the criteria,\nthey will simply be ignored.</div><li><p><strong>Save.</strong> Save changes to the profile.<li><p><strong>Discard.</strong> Discard any modifications made since\nthe last time it was saved.<li><p><strong>Delete.</strong> Clicking on this option will remove the\nprofile immediately without a warning.<li><p><strong>Duplicate.</strong> This option can be used to duplicate\nthe profile. When clicked, a dialog is displayed where it is possible to\nset a name for the new profile. On clicking “OK”, this page will be\nreloaded by duplicating all the configurations that this profile have.\nHowever, the new profile will not be saved until it is saved\nmanually.<li><p><strong>Create shortcut.</strong> This option can be used to\ncreate a shortcut for the profile. There are two options:\n<em>Simple</em> and <em>Advanced</em>. When configured with the latter\noption, it prompts the user to select a profile state when the shortcut\nis invoked. The former option, on the other hand, always uses the\ndefault state that was configured when the profile was last\nsaved.</ul></section><section id=subsec:profile-apps-tab class=level3 data-number=2.5.2><h3 data-number=2.5.2><span class=header-section-number>2.5.2</span>\n<a href=#toc:subsec:profile-apps-tab>Apps Tab</a><a href=#subsec:profile-apps-tab class=anchor aria-hidden=true></a></h3><p>Apps tab lists the packages configured for this profile. Packages can\nbe added or removed using the <em>plus</em> button located near the\nbottom of the screen. A package can also be removed by long clicking on\nit (in which case, a popup will be displayed with the only option,\n<em>delete</em>).</section><section id=subsec:profile-configurations-tab class=level3 data-number=2.5.3><h3 data-number=2.5.3><span class=header-section-number>2.5.3</span>\n<a href=#toc:subsec:profile-configurations-tab>Configurations\nTab</a><a href=#subsec:profile-configurations-tab class=anchor aria-hidden=true></a></h3><p>Configurations tab can be used to configure the selected\npackages.<section id=profile-id class=level4 data-number=2.5.3.1><h4 data-number=2.5.3.1><span class=header-section-number>2.5.3.1</span> Profile ID<a href=#profile-id class=anchor aria-hidden=true></a></h4><p>The unique ID for this profile, currently set based on the profile\nname. The profile ID can be used to <a href=#subsec:triggering-a-profile>trigger the profile</a> from a\nthird-party application.</section><section id=comment class=level4 data-number=2.5.3.2><h4 data-number=2.5.3.2><span class=header-section-number>2.5.3.2</span> Comment<a href=#comment class=anchor aria-hidden=true></a></h4><p>This is the text that will be displayed in the <a href=#sec:profiles-page>profiles page</a>. If not set, the current\nconfigurations will be displayed instead.</section><section id=subsubsec:profile-state class=level4 data-number=2.5.3.3><h4 data-number=2.5.3.3><span class=header-section-number>2.5.3.3</span> State<a href=#subsubsec:profile-state class=anchor aria-hidden=true></a></h4><p>Denotes how certain configured options will behave by default. For\ninstance, if <em>disable</em> option is turned on, the applications will\nbe disabled if the state is <em>on</em> and will be enabled if the state\nis <em>off</em>. Currently, it only supports <em>on</em> and\n<em>off</em> values.</section><section id=users class=level4 data-number=2.5.3.4><h4 data-number=2.5.3.4><span class=header-section-number>2.5.3.4</span> Users<a href=#users class=anchor aria-hidden=true></a></h4><p>Select users for which is the profile will be applied. All users are\nselected by default.</section><section id=components class=level4 data-number=2.5.3.5><h4 data-number=2.5.3.5><span class=header-section-number>2.5.3.5</span> Components<a href=#components class=anchor aria-hidden=true></a></h4><p>This behaves the same way as the <a href=#subsec:block-components-dots>Block Components…</a> option does\nin the 1-Click Ops page. However, the blocking here is only applied to\nthe selected packages. If the <a href=#subsubsec:profile-state>state</a> is <em>on</em>, the components\nwill be blocked, and if the state is <em>off</em>, the components will\nbe unblocked. The option can be disabled (regardless of the inserted\nvalues) by clicking on the <em>disabled</em> button on the input\ndialog.<div class=seealso-inline><p><em>See also: <span><a href=#subsec:faq:what-are-app-components>What are the app\ncomponents?</a></span></em></div></section><section id=app-ops class=level4 data-number=2.5.3.6><h4 data-number=2.5.3.6><span class=header-section-number>2.5.3.6</span> App Ops<a href=#app-ops class=anchor aria-hidden=true></a></h4><p>This behaves the same way as the <a href=#subsec:set-mode-for-app-ops-dots>Set Mode for App Ops…</a>\noption does in the 1-Click Ops page. However, the operation here is only\napplied to the selected packages. If the <a href=#subsubsec:profile-state>state</a> is <em>on</em>, the app ops\nwill be denied (i.e. ignored), and if the state is <em>off</em>, the app\nops will be allowed. The option can be disabled (regardless of the\ninserted values) by clicking on the <em>disable</em> button in the input\ndialog.</section><section id=permissions class=level4 data-number=2.5.3.7><h4 data-number=2.5.3.7><span class=header-section-number>2.5.3.7</span> Permissions<a href=#permissions class=anchor aria-hidden=true></a></h4><p>This option can be used to grant or revoke certain permissions from\nthe selected packages. Like others above, permissions must be separated\nby white spaces. If the <a href=#subsubsec:profile-state>state</a> is\n<em>on</em>, the permissions will be revoked, and if the state is\n<em>off</em>, the permissions will be allowed. The option can be\ndisabled (regardless of the inserted values) by clicking on the\n<em>disable</em> button in the input dialog.</section><section id=backuprestore class=level4 data-number=2.5.3.8><h4 data-number=2.5.3.8><span class=header-section-number>2.5.3.8</span> Backup/Restore<a href=#backuprestore class=anchor aria-hidden=true></a></h4><p>This option can be used to take a backup of the selected applications\nand its data or restore them. Two options are available here: <em>Backup\noptions</em> and <em>backup name</em>.<ul class=incremental><li><p><strong>Backup options.</strong> Same as the <a href=#subsec:backup-restore-backup-options>backup options</a> of the\nbackup/restore feature. If not set, the default options will be\nused.<li><p><strong>Backup name.</strong> Set a custom name for the backup.\nIf the backup name is set, each time a backup is made, it will be given\na unique name with backup-name as the suffix. This behaviour will be\nfixed in a future release. Leave this field empty for regular “base”\nbackups (also, make sure not to enable <em>backup multiple</em> in the\nbackup options).</ul><p>If the <a href=#subsubsec:profile-state>state</a> is <em>on</em>,\nthe packages will be backed up, and if the state is <em>off</em>, the\npackages will be restored. The option can be disabled by clicking on the\n<em>disable</em> button in the input dialog.</section><section id=export-blocking-rules class=level4 data-number=2.5.3.9><h4 data-number=2.5.3.9><span class=header-section-number>2.5.3.9</span> Export Blocking Rules<a href=#export-blocking-rules class=anchor aria-hidden=true></a></h4><div class=\"amalert danger\"><p><strong><em>Danger.</em></strong><p>This option is not yet implemented.</div></section><section id=freeze class=level4 data-number=2.5.3.10><h4 data-number=2.5.3.10><span class=header-section-number>2.5.3.10</span> Freeze<a href=#freeze class=anchor aria-hidden=true></a></h4><p>Allow freezing or unfreezing the selected packages depending on the\nvalue of the <a href=#subsubsec:profile-state>state</a>. If the state\nis <em>on</em>, the packages will be frozen, and if the state is\n<em>off</em>, they will be unfrozen.</section><section id=force-stop class=level4 data-number=2.5.3.11><h4 data-number=2.5.3.11><span class=header-section-number>2.5.3.11</span> Force-stop<a href=#force-stop class=anchor aria-hidden=true></a></h4><p>Allow the selected packages to be force-stopped.</section><section id=clear-cache class=level4 data-number=2.5.3.12><h4 data-number=2.5.3.12><span class=header-section-number>2.5.3.12</span> Clear Cache<a href=#clear-cache class=anchor aria-hidden=true></a></h4><p>Enable clearing cache for the selected packages.</section><section id=clear-data class=level4 data-number=2.5.3.13><h4 data-number=2.5.3.13><span class=header-section-number>2.5.3.13</span> Clear Data<a href=#clear-data class=anchor aria-hidden=true></a></h4><p>Enable clearing data for the selected packages.</section><section id=block-trackers class=level4 data-number=2.5.3.14><h4 data-number=2.5.3.14><span class=header-section-number>2.5.3.14</span> Block Trackers<a href=#block-trackers class=anchor aria-hidden=true></a></h4><p>Enable blocking or unblocking of the tracker components from the\nselected packages depending on the value of the <a href=#subsubsec:profile-state>state</a>. If the state is <em>on</em>,\nthe trackers will be blocked, and if the state is <em>off</em>, the\ntrackers will be unblocked.</section><section id=save-apk class=level4 data-number=2.5.3.15><h4 data-number=2.5.3.15><span class=header-section-number>2.5.3.15</span> Save APK<a href=#save-apk class=anchor aria-hidden=true></a></h4><p>Enable saving APK files at <code>AppManager/apks</code> (or in the\ndirectory selected in the settings page) of the selected packages.</section></section></section><section id=sec:settings-page class=level2 data-number=2.6><h2 data-number=2.6><span class=header-section-number>2.6</span> <a href=#toc:sec:settings-page>Settings Page</a><a href=#sec:settings-page class=anchor aria-hidden=true></a></h2><p>Settings page can be used to customise the behaviour of App\nManager.<section id=subsec:language class=level3 data-number=2.6.1><h3 data-number=2.6.1><span class=header-section-number>2.6.1</span>\n<a href=#toc:subsec:language>Language</a><a href=#subsec:language class=anchor aria-hidden=true></a></h3><p>Configure in-app language. App Manager currently supports 22\n(twenty-two) languages.</section><section id=subsec:appearance class=level3 data-number=2.6.2><h3 data-number=2.6.2><span class=header-section-number>2.6.2</span>\n<a href=#toc:subsec:appearance>Appearance</a><a href=#subsec:appearance class=anchor aria-hidden=true></a></h3><section id=subsubsec:app-theme class=level4 data-number=2.6.2.1><h4 data-number=2.6.2.1><span class=header-section-number>2.6.2.1</span> App Theme<a href=#subsubsec:app-theme class=anchor aria-hidden=true></a></h4><p>Configure in-app theme.</section><section id=subsubsec:pure-black-theme class=level4 data-number=2.6.2.2><h4 data-number=2.6.2.2><span class=header-section-number>2.6.2.2</span> Pure Black Theme<a href=#subsubsec:pure-black-theme class=anchor aria-hidden=true></a></h4><p>Whether to use a black background instead of the material themed\nbackground.</section><section id=subsubsec:layout-direction class=level4 data-number=2.6.2.3><h4 data-number=2.6.2.3><span class=header-section-number>2.6.2.3</span> Layout Direction<a href=#subsubsec:layout-direction class=anchor aria-hidden=true></a></h4><p>Change layout direction, either left to right or right to left. This\nis usually set using the selected language but not everybody prefers the\nsame direction.</section><section id=subsubsec:enable/disable-features class=level4 data-number=2.6.2.4><h4 data-number=2.6.2.4><span class=header-section-number>2.6.2.4</span> Enable/Disable Features<a href=#subsubsec:enable/disable-features class=anchor aria-hidden=true></a></h4><p>Enable or disable certain features in App Manager, such as<ul class=incremental><li><p><strong>Interceptor</strong><li><p><strong>Manifest viewer</strong><li><p><strong>Scanner</strong><li><p><strong>Package installer</strong><li><p><strong>Usage access.</strong> With this feature turned off, App\nManager will never ask for the <em>Usage Access</em>\npermission.<li><p><strong>Log viewer</strong><li><p><strong>App explorer.</strong> The “Explore” option will not be\navailable while trying to open an APK file.<li><p><strong>App info.</strong> The “App info” option displayed while\ntrying to open an APK file.<li><p><strong>Code Editor</strong><li><p><strong>VirusTotal</strong></ul></section></section><section id=subsec:privacy class=level3 data-number=2.6.3><h3 data-number=2.6.3><span class=header-section-number>2.6.3</span>\n<a href=#toc:subsec:privacy>Privacy</a><a href=#subsec:privacy class=anchor aria-hidden=true></a></h3><section id=subsubsec:screen-lock class=level4 data-number=2.6.3.1><h4 data-number=2.6.3.1><span class=header-section-number>2.6.3.1</span> Screen Lock<a href=#subsubsec:screen-lock class=anchor aria-hidden=true></a></h4><p>Lock App Manager using Android screen lock provided a screen lock is\nconfigured.<div class=\"amalert warning\"><p><strong><em>Warning.</em></strong><p>If screen lock is disabled in Android after enabling this setting,\nApp Manager will not open until it is enabled again.</div></section><section id=subsubsec:run-am-in-background class=level4 data-number=2.6.3.2><h4 data-number=2.6.3.2><span class=header-section-number>2.6.3.2</span> Run App Manager in the\nBackground<a href=#subsubsec:run-am-in-background class=anchor aria-hidden=true></a></h4><p>Whether to run App Manager in the background to reduce the\ninitialisation delay. On certain devices, this can also help if you’re\nfrequently disconnected from ADB.</section><section id=subsubsec:use-the-internet class=level4 data-number=2.6.3.3><h4 data-number=2.6.3.3><span class=header-section-number>2.6.3.3</span> Use the Internet<a href=#subsubsec:use-the-internet class=anchor aria-hidden=true></a></h4><p>Whether to activate the Internet features in App Manager. This\ncurrently include VirusTotal and Pithus scanning in the <a href=#sec:scanner-page>Scanner page</a>.</section><section id=subsubsec:auth-manager class=level4 data-number=2.6.3.4><h4 data-number=2.6.3.4><span class=header-section-number>2.6.3.4</span> Authorization Manager<a href=#subsubsec:auth-manager class=anchor aria-hidden=true></a></h4><p>This setting allows a third-party application to get access to\ncertain features, such as profiles.</section></section><section id=subsec:mode-of-operation class=level3 data-number=2.6.4><h3 data-number=2.6.4><span class=header-section-number>2.6.4</span>\n<a href=#toc:subsec:mode-of-operation>Mode of Operation</a><a href=#subsec:mode-of-operation class=anchor aria-hidden=true></a></h3><p>Mode of operation defines how App Manager works as a whole. It has\nthe following options:<ul class=incremental><li><p><strong>Auto.</strong> Let App Manager decide the suitable\noption. Although this is the default option, non-rooted users should use\nthe <em>no-root</em> mode.<li><p><strong>Root.</strong> Operate App Manager in root mode. App\nManager will fall back to <em>no-root</em> mode if root is not detected,\nor in rare cases when Binder communication through root is disabled\n(e.g. in <a href=https://github.com/MuntashirAkon/AppManager/issues/606>Phh\nSuperUser</a>).<li><p><strong>ADB over TCP.</strong> Operate App Manager in ADB mode\nvia <a href=#sec:adb-over-tcp>ADB over TCP</a>. App Manager will fall\nback to <em>no-root</em> mode if ADB over TCP is not enabled.<li><p><strong>Wireless debugging.</strong> Enable ADB via Wireless\nDebugging. It will try to connect to the configured port automatically\nat first. On failure, it will ask the user to either pair or connect to\nthe ADB daemon manually. App Manager will fall back to <em>no-root</em>\nmode if it fails to connect to the ADB daemon this way.<div class=\"amalert tip\"><p><strong><em>Info.</em></strong><p>This option is only displayed in devices running Android 11 or later\nas Wireless Debugging was introduced in Android 11.</div><li><p><strong>No-root.</strong> Operate App Manager in no-root mode.\nWhile App Manager performs better in this mode, all the root- or\nADB-specific features will be disabled.</ul><p>It also displays the actual mode of operation at the top. The actual\nmode of operations are <em>root</em>, <em>ABD</em> and\n<em>no-root</em>.<div class=\"amalert tip\"><p><strong><em>Notice.</em></strong><p>“Remote service” is only required for ADB users or when you use the\ncustom commands.</div></section><section id=subsec:apk-signing class=level3 data-number=2.6.5><h3 data-number=2.6.5><span class=header-section-number>2.6.5</span>\n<a href=#toc:subsec:apk-signing>APK Signing</a><a href=#subsec:apk-signing class=anchor aria-hidden=true></a></h3><section id=signature-schemes class=level4 data-number=2.6.5.1><h4 data-number=2.6.5.1><span class=header-section-number>2.6.5.1</span> Signature Schemes<a href=#signature-schemes class=anchor aria-hidden=true></a></h4><p>Configure the <a href=https://source.android.com/security/apksigning>signature\nschemes</a> to be used when APK signing is enabled. v1 and v2 signature\nschemes are enabled by default, but v3 should also be enabled to ensure\nproper security in Android 9 or later.</section><section id=signing-key class=level4 data-number=2.6.5.2><h4 data-number=2.6.5.2><span class=header-section-number>2.6.5.2</span> Signing Key<a href=#signing-key class=anchor aria-hidden=true></a></h4><p>Configure the signing key for signing APK files. Keys from an\nexisting KeyStore can be imported to App Manager, or a new key can be\ngenerated.<div class=\"amalert tip\"><p><strong><em>Tip.</em></strong><p>If you need to use the key in the future, it is recommended that you\ncreate a KeyStore yourself and import the key here. Without a proper\nbackup, keys generated within App Manager are at the risk of being\ndeleted.</div></section><section id=align-apk-files class=level4 data-number=2.6.5.3><h4 data-number=2.6.5.3><span class=header-section-number>2.6.5.3</span> Align APK Files<a href=#align-apk-files class=anchor aria-hidden=true></a></h4><p>Performs zip alignment when App Manager signs an APK file. Zip\nalignment stores the files in the APK file (which is actually a zip\nfile) in a way that a zip file reader can access the files quite easily\nusing random access instead of loading the entire APK file in the\nmemory, which results in the reduction of Android’s memory usage. Note\nthat this step is required if an application’s manifest has\n<code>extractNativeLibs</code> set to <code>true</code>.</section></section><section id=subsec:installer class=level3 data-number=2.6.6><h3 data-number=2.6.6><span class=header-section-number>2.6.6</span>\n<a href=#toc:subsec:installer>Installer</a><a href=#subsec:installer class=anchor aria-hidden=true></a></h3><p>Configure the default behaviour of the installer. You can also find\nmost of the settings by clicking on the <em>cog</em> icon when you\ninstall an application.<section id=install-location class=level4 data-number=2.6.6.1><h4 data-number=2.6.6.1><span class=header-section-number>2.6.6.1</span> Install Location<a href=#install-location class=anchor aria-hidden=true></a></h4><p>Define APK installation location. This can be one of <em>auto</em>,\n<em>internal only</em> and <em>prefer external</em>. In newer Android\nversions, selecting the last option does not guarantee that the\napplication will be installed in the external storage.</section><section id=block-trackers-1 class=level4 data-number=2.6.6.2><h4 data-number=2.6.6.2><span class=header-section-number>2.6.6.2</span> Block Trackers<a href=#block-trackers-1 class=anchor aria-hidden=true></a></h4><p>Whether to block the tracking components immediately after installing\nthe application.</section><section id=display-changes class=level4 data-number=2.6.6.3><h4 data-number=2.6.6.3><span class=header-section-number>2.6.6.3</span> Display Changes<a href=#display-changes class=anchor aria-hidden=true></a></h4><p>Whether to display changes in version, trackers, components,\npermissions, signatures, SDK, etc. in a version controlled style before\ninstalling the application if the application has already been\ninstalled.</section><section id=installer-app class=level4 data-number=2.6.6.4><h4 data-number=2.6.6.4><span class=header-section-number>2.6.6.4</span> Installer App<a href=#installer-app class=anchor aria-hidden=true></a></h4><p>Select the installer application. This is useful for applications\nthat explicitly checks the installer as a way to verify if the\napplication is installed legitimately. This only works for root or ADB\nusers.<div class=\"amalert tip\"><p><strong><em>Notice.</em></strong><p>While checking for the installer might seem a legitimate concern for\nan application, the Android framework already deals with this during the\ninstallation. Checking for the installer is simply the wrong way to\nprove the legitimacy of the source of an application.</div></section><section id=sign-apk class=level4 data-number=2.6.6.5><h4 data-number=2.6.6.5><span class=header-section-number>2.6.6.5</span> Sign APK<a href=#sign-apk class=anchor aria-hidden=true></a></h4><p>Whether to sign the APK files before installing the application. A\nsigning key has to be added or generated before this option can be\nenabled. This can be done in the <a href=#subsec:apk-signing>APK\nsigning</a> page.</section><section id=immediately-perform-dex-optimization class=level4 data-number=2.6.6.6><h4 data-number=2.6.6.6><span class=header-section-number>2.6.6.6</span> Immediately Perform DEX\nOptimization<a href=#immediately-perform-dex-optimization class=anchor aria-hidden=true></a></h4><p>Whether to perform DEX optimization immediately after installing the\napplication. This can be useful for heavy applications, such as the\ngaming applications.</section><section id=install-in-the-background class=level4 data-number=2.6.6.7><h4 data-number=2.6.6.7><span class=header-section-number>2.6.6.7</span> Install in the Background<a href=#install-in-the-background class=anchor aria-hidden=true></a></h4><p>Whether to always install applications in the background. A\nnotification will be issued once the installation is finished.</section></section><section id=subsec:backup/restore class=level3 data-number=2.6.7><h3 data-number=2.6.7><span class=header-section-number>2.6.7</span>\n<a href=#toc:subsec:backup/restore>Back up/Restore</a><a href=#subsec:backup/restore class=anchor aria-hidden=true></a></h3><p>Settings related to <a href=#sec:backup-restore>back\nup/restore</a>.<section id=compression-method class=level4 data-number=2.6.7.1><h4 data-number=2.6.7.1><span class=header-section-number>2.6.7.1</span> Compression method<a href=#compression-method class=anchor aria-hidden=true></a></h4><p>Set the compression method to be used during backups. App Manager\nsupports GZip, BZip2 and Zstandard compression methods, GZip being the\ndefault compression method. It doesn’t affect the restore of an existing\nbackup.</section><section id=subsubsec:settings-backup-options class=level4 data-number=2.6.7.2><h4 data-number=2.6.7.2><span class=header-section-number>2.6.7.2</span> Backup Options<a href=#subsubsec:settings-backup-options class=anchor aria-hidden=true></a></h4><p>Customise the <em>back up/restore dialog</em> displayed while taking\na backup.<div class=seealso-inline><p><em>See also: <span><a href=#subsec:backup-restore-backup-options>Backup\noptions</a></span></em></div></section><section id=backup-apps-with-android-keystore class=level4 data-number=2.6.7.3><h4 data-number=2.6.7.3><span class=header-section-number>2.6.7.3</span> Backup apps with Android\nKeyStore<a href=#backup-apps-with-android-keystore class=anchor aria-hidden=true></a></h4><p>Allow backup of applications that has entries in the Android\nKeyStore. This option is disabled by default because a few apps (such as\nSignal or Element) may crash if restored.</section><section id=subsubsec:settings-encryption class=level4 data-number=2.6.7.4><h4 data-number=2.6.7.4><span class=header-section-number>2.6.7.4</span> Encryption<a href=#subsubsec:settings-encryption class=anchor aria-hidden=true></a></h4><p>Set an encryption method for the backups. App Manager currently\nsupports OpenPGP (via <a href=https://f-droid.org/packages/org.sufficientlysecure.keychain/>OpenKeyChain</a>),\nAES, RSA and ECC. Like <a href=#subsec:apk-signing>APK signing</a>,\nThe AES, RSA and ECC keys are stored in the KeyStore and can be imported\nfrom other KeyStores.<div class=\"amalert danger\"><p><strong><em>Danger.</em></strong><p>For your own safety, it is not recommended generating RSA and ECC\nkeys inside App Manager. Instead, they should be imported from a\nKeyStore stored in a secure place.<br>In case of AES, the generated key should be stored in a secure place,\nsuch as in a password manager.</div></section><section id=subsubsec:backup-volume class=level4 data-number=2.6.7.5><h4 data-number=2.6.7.5><span class=header-section-number>2.6.7.5</span> Backup Volume<a href=#subsubsec:backup-volume class=anchor aria-hidden=true></a></h4><p>Select the storage where the backups will be stored. This is also\nwhere logs and exported APK files are saved.<div class=\"amalert tip\"><p><strong><em>Notice.</em></strong><p>The backup volume only specifies the storage, not the path. Backups\nare traditionally stored in the <code>AppManager</code> folder inside\nthe storage path. But when the path is selected using Storage Access\nFramework (SAF), the selected path or directory is used directly.</div></section><section id=import-backups class=level4 data-number=2.6.7.6><h4 data-number=2.6.7.6><span class=header-section-number>2.6.7.6</span> Import Backups<a href=#import-backups class=anchor aria-hidden=true></a></h4><p>Import backups from old and discontinued projects such as Titanium\nBackup, OAndBackup, and Swift Backup (version 3.0 to 3.2). The backups\nare not deleted after importing to prevent data loss in case the\nimported backups cannot be restored properly.</section></section><section id=subsec:rules class=level3 data-number=2.6.8><h3 data-number=2.6.8><span class=header-section-number>2.6.8</span>\n<a href=#toc:subsec:rules>Rules</a><a href=#subsec:rules class=anchor aria-hidden=true></a></h3><section id=subsubsec:instant-component-blocking class=level4 data-number=2.6.8.1><h4 data-number=2.6.8.1><span class=header-section-number>2.6.8.1</span> Instant Component\nBlocking<a href=#subsubsec:instant-component-blocking class=anchor aria-hidden=true></a></h4><p>By default, blocking rules are not applied unless they are applied\nexplicitly in <a href=#sec:app-details-page>the App Details page</a>\nfor any application. After enabling this option, all (old and new) rules\nare applied immediately for all applications without explicitly enabling\nblocking for an application.<div class=seealso-inline><p><em>See also: <span><a href=#subsec:faq:what-is-instant-component-blocking>FAQ: What is\ninstant component blocking?</a></span></em></div></section><section id=importexport-blocking-rules class=level4 data-number=2.6.8.2><h4 data-number=2.6.8.2><span class=header-section-number>2.6.8.2</span> Import/Export Blocking\nRules<a href=#importexport-blocking-rules class=anchor aria-hidden=true></a></h4><p>It is possible to import or export blocking rules within App Manager\nfor all applications. The types of rules (components, app ops or\npermissions) that should be imported or exported can also be selected.\nIt is also possible to import blocking rules from <a href=https://github.com/lihenggui/blocker>Blocker</a> and <a href=https://github.com/tuyafeng/Watt>Watt</a>. If it is necessary to\nexport blocking rules for a single application, the corresponding <a href=#sec:app-details-page>App Details page</a> can be used to export\nrules, or for multiple apps, <a href=#subsec:batch-operations>batch\noperations</a> can be used.<div class=seealso-inline><p><em>See also: <span><a href=#sec:rules-specification>Rules\nSpecification</a></span></em></div><section id=export class=level5 data-number=2.6.8.2.1><h5 data-number=2.6.8.2.1><span class=header-section-number>2.6.8.2.1</span> Export<a href=#export class=anchor aria-hidden=true></a></h5><p>Export blocking rules for all applications configured within App\nManager. This may include <a href=#subsec:faq:what-are-app-components>app components</a>, app ops\nand permissions based on the options selected in the multi-choice\noptions.</section><section id=import class=level5 data-number=2.6.8.2.2><h5 data-number=2.6.8.2.2><span class=header-section-number>2.6.8.2.2</span> Import<a href=#import class=anchor aria-hidden=true></a></h5><p>Import previously exported blocking rules from App Manager. Similar\nto export, this may include <a href=#subsec:faq:what-are-app-components>app components</a>, app ops\nand permissions based on the options selected in the multi-choice\noptions.</section><section id=par:import-existing-rules class=level5 data-number=2.6.8.2.3><h5 data-number=2.6.8.2.3><span class=header-section-number>2.6.8.2.3</span> Import Existing Rules<a href=#par:import-existing-rules class=anchor aria-hidden=true></a></h5><p>Add components disabled by other applications to App Manager. App\nManager only keeps track of the components disabled within App Manager.\nIf application components are blocked or disabled by other tools or\napplications, this option can be utilised to import them. On clicking\nthis option, App Manager will find the components potentially disabled\nby other applications or tools and list only the name of the\napplications along with the number of matched components. For safety,\nall the applications are unselected by default. They have to be selected\nmanually, and the blocking has to be re-applied via App Manager.<div class=\"amalert danger\"><p><strong><em>Caution.</em></strong><p>Be careful when using this tool as there can be many false positives.\nChoose only the applications that you are certain about.</div></section><section id=import-from-watt class=level5 data-number=2.6.8.2.4><h5 data-number=2.6.8.2.4><span class=header-section-number>2.6.8.2.4</span> Import from Watt<a href=#import-from-watt class=anchor aria-hidden=true></a></h5><p>Import configuration files from <a href=https://github.com/tuyafeng/Watt>Watt</a>, each file containing\nrules for a single package and file name being the name of the package\nwith <code>.xml</code> extension.<div class=\"amalert tip\"><p><strong><em>Tip.</em></strong><p>Location of configuration files in Watt:\n<code>/sdcard/Android/data/com.tuyafeng.watt/files/ifw</code></div></section><section id=import-from-blocker class=level5 data-number=2.6.8.2.5><h5 data-number=2.6.8.2.5><span class=header-section-number>2.6.8.2.5</span> Import from Blocker<a href=#import-from-blocker class=anchor aria-hidden=true></a></h5><p>Import blocking rules from <a href=https://github.com/lihenggui/blocker>Blocker</a>, each file\ncontaining rules for a single package. These files have a\n<code>.json</code> extension.</section></section><section id=remove-all-rules class=level4 data-number=2.6.8.3><h4 data-number=2.6.8.3><span class=header-section-number>2.6.8.3</span> Remove all rules<a href=#remove-all-rules class=anchor aria-hidden=true></a></h4><p>One-click option to remove all rules configured within App Manager.\nThis will enable all blocked components, app ops will be set to their\ndefault values and permissions will be granted.</section></section><section id=subsec:advanced class=level3 data-number=2.6.9><h3 data-number=2.6.9><span class=header-section-number>2.6.9</span>\n<a href=#toc:subsec:advanced>Advanced</a><a href=#subsec:advanced class=anchor aria-hidden=true></a></h3><section id=subsubsec:selected-users class=level4 data-number=2.6.9.1><h4 data-number=2.6.9.1><span class=header-section-number>2.6.9.1</span> Selected Users<a href=#subsubsec:selected-users class=anchor aria-hidden=true></a></h4><p>This option lets you control the users App Manager should operate on.\nApp Manager operates on all users in root or ADB mode by default.</section><section id=subsubsec:saved-apk-name-format class=level4 data-number=2.6.9.2><h4 data-number=2.6.9.2><span class=header-section-number>2.6.9.2</span> Saved APK Name Format<a href=#subsubsec:saved-apk-name-format class=anchor aria-hidden=true></a></h4><p>Defines the format of the APK name to be used while saving it via\nbatch operations or through profiles. App Manager offers some special\nkeywords enclosed inside <code>%</code> (percentage) signs and available\nbelow the input box. These keywords are:<ul class=incremental><li><p><strong><code>label</code>.</strong> Denotes the name or label of\nthe application. This can be localised to the configured language\ndepending on the app.<li><p><strong><code>package_name</code>.</strong> Denotes the name of\nthe package or application ID, the unique identifier that each\napplication has.<li><p><strong><code>version</code>.</strong> Denotes the current\nversion of the application extracted from its manifest.<li><p><strong><code>version_code</code>.</strong> Denotes the current\nversion code of the application that can be used to separate two\nversions of the same application.<li><p><strong><code>min_sdk</code>.</strong> Denotes the minimum SDK\n(i.e. Android framework version) that the application can operate on.\nThis data is only available since Android 7 (Nougat).<li><p><strong><code>target_sdk</code>.</strong> Denotes the SDK that\nthis application targets. The application can operate on higher SDK but\nonly in the compatibility mode.<li><p><strong><code>datetime</code>.</strong> Denotes the time and date\nwhen the APK is exported.</ul></section><section id=subsubsec:import/export-keystore class=level4 data-number=2.6.9.3><h4 data-number=2.6.9.3><span class=header-section-number>2.6.9.3</span> Import/Export Keystore<a href=#subsubsec:import/export-keystore class=anchor aria-hidden=true></a></h4><p>Import or export the KeyStore used by App Manager. This is a Bouncy\nCastle KeyStore with <code>bks</code> extension. Therefore, other\nKeyStore such as Java KeyStore (JKS) or PKCS #12 are not supported. If a\nkey is needed to be imported from such a KeyStore, the relevant options\nshould be should as specified above.</section></section><section id=subsec:device-info class=level3 data-number=2.6.10><h3 data-number=2.6.10><span class=header-section-number>2.6.10</span> <a href=#toc:subsec:device-info>About the device</a><a href=#subsec:device-info class=anchor aria-hidden=true></a></h3><p>Display Android version, security, CPU, GPU, battery, memory, screen,\nlanguages, user info, etc.</section></section><section id=sec:scanner-page class=level2 data-number=2.7><h2 data-number=2.7><span class=header-section-number>2.7</span> <a href=#toc:sec:scanner-page>Scanner Page</a><a href=#sec:scanner-page class=anchor aria-hidden=true></a></h2><p><strong>Scanner page</strong> appears after clicking on the\n<em>scanner</em> button in the <a href=#subsec:app-info-tab>App Info\ntab</a>. External APK files can also be opened for scanning from file\nmanagers, web browsers, etc.<p>It scans for trackers and libraries, and displays the number of\ntrackers and libraries as a summary. It also displays checksums of the\nAPK file as well as the signing certificates. If VirusTotal is\nconfigured in the settings, it also attempts to retrieve reports from\nVirusTotal, or uploads the APK file if it is not in the database. It\nalso display a link to the <a href=https://beta.pithus.org>Pithus</a>\nreport provided the Internet features are enabled.<div class=\"amalert danger\"><p><strong><em>Disclaimer.</em></strong><p>App Manager only scans an application statically without prejudice.\nThe application may provide the options for opting out, or in some\ncases, certain features of the tracker may not be used at all by the\napplication (e.g. F-Droid), or some applications may simply use them as\nplaceholders to prevent the breaking of certain features (e.g. Fennec\nF-Droid). <strong>The intention of the scanner is to give you an idea\nabout what the APK might contain. It should be taken as an initial step\nfor further investigations.</strong></div><p>Clicking on the first item (i.e. number of classes) opens a new page\ncontaining a list of tracker classes for the application. All classes\ncan also be viewed by clicking on the <em>Toggle Class Listing</em>\nmenu. The SMALI or Java version of the class can be viewed by simply\nclicking on an item.<div class=\"amalert tip\"><p><strong><em>Notice.</em></strong><p>Due to various limitations, it is not possible to scan all the\ncomponents of an APK file. This is especially true if an APK is highly\nobfuscated or packed. The scanner also does not check strings (or\nwebsite signatures).</div><p>The second item lists the number of trackers along with their names.\nClicking on the item displays a dialog containing the name of trackers,\nmatched signatures, and the number of classes against each signature.\nSome tracker names may have <span class=\"math inline\"><sup>2</sup></span> prefix which indicates that the\ntrackers are in the <a href=https://etip.exodus-privacy.eu.org>ETIP</a> stand-by list, i.e.,\nwhether they are actual trackers is still being investigated.<p>The third item lists the number of libraries along with their names.\nThe information are mostly taken from <a href=https://gitlab.com/IzzyOnDroid/repo>IzzyOnDroid repo</a>.<div class=seealso-inline><p><em>See also: <span><a href=#subsec:tracker-classes-versus-tracker-components>FAQ: Tracker\nclasses vs tracker components</a></span></em></div></section><section id=sec:interceptor-page class=level2 data-number=2.8><h2 data-number=2.8><span class=header-section-number>2.8</span> <a href=#toc:sec:interceptor-page>Interceptor Page</a><a href=#sec:interceptor-page class=anchor aria-hidden=true></a></h2><p>Interceptor can be used to intercept communication between\napplications using <code>Intent</code>. It works as a man-in-the-middle\nbetween the source and the destination applications. It offers a\nfeature-complete user interface for editing <code>Intent</code>s.<div class=\"amalert warning\"><p><strong><em>Warning.</em></strong><p>Interceptor only works for <em>implicit</em> intents where the <a href=#subsec:faq:what-are-app-components>app component</a> isn’t\nspecified.</div><div class=seealso><p><em>See also:</em><ul class=incremental><li><p><a href=https://developer.android.com/guide/components/intents-common>Common\nIntents</a><li><p><a href=https://developer.android.com/guide/components/intents-filters>Intents\nand Intent Filters</a></ul></div><section id=subsec:intent-filters class=level3 data-number=2.8.1><h3 data-number=2.8.1><span class=header-section-number>2.8.1</span>\n<a href=#toc:subsec:intent-filters>Intent Filters</a><a href=#subsec:intent-filters class=anchor aria-hidden=true></a></h3><p>Intent filters are used by the applications to specify the tasks they\nare able to perform or the tasks they are going to perform using other\napplications. For example, when you’re opening a PDF file using a file\nmanager, the file manager will try to find the applications to open the\nPDF with. To find the right applications, the file manager will create\nan Intent with filters such as the MIME type and ask the system to\nretrieve the applications capable of opening this filter. The system\nwill search through the Manifest of the installed applications to match\nthe filter and list the application components that are able to open\nthis filter (in our case the PDF). At this, either the file manager will\nopen the desired application component all by itself or use a system\nprovided option to open it. If multiple application components are able\nto open it and no default is set, you may get a prompt where you have to\nchoose the right application component.<section id=subsubsec:action class=level4 data-number=2.8.1.1><h4 data-number=2.8.1.1><span class=header-section-number>2.8.1.1</span> Action<a href=#subsubsec:action class=anchor aria-hidden=true></a></h4><p>Action specifies the generic action to perform such as\n<code>android.intent.action.VIEW</code>. Applications often declare the\nrelevant actions in the Manifest file to catch the desired Intents. The\naction is particularly useful for broadcast Intent where it plays a\nvital rule. In other cases, it works as an initial way to filter out the\nrelevant application components. Generic actions such as\n<code>android.intent.action.VIEW</code> and\n<code>android.intent.action.SEND</code> are widely used by applications.\nHence, setting this alone may match many application components.</section><section id=subsubsec:data class=level4 data-number=2.8.1.2><h4 data-number=2.8.1.2><span class=header-section-number>2.8.1.2</span> Data<a href=#subsubsec:data class=anchor aria-hidden=true></a></h4><p>Data is originally known as URI (Uniform Resource Identifier) defined\nin <a href=http://www.faqs.org/rfcs/rfc2396.html>RFC 2396</a>. It can\nbe web links, file location, or a special feature called\n<em>content</em>. Contents are an Android feature managed by the <a href=#subsubsec:providers>content providers</a>. Data are often\nassociated with a <a href=#subsubsec:mime-type>MIME type</a>.<p>Examples:<pre><code>http://search.disroot.org/?q=URI%20in%20Android%20scheme&amp;categories=general&amp;language=en-US\nhttps://developer.android.com/reference/android/net/Uri\nfile:///sdcard/AppManager.apk\nmailto:email@example.com\ncontent://io.github.muntashirakon.AppManager.provider/23485af89b08d87e898a90c7e/AppManager.apk</code></pre></section><section id=subsubsec:mime-type class=level4 data-number=2.8.1.3><h4 data-number=2.8.1.3><span class=header-section-number>2.8.1.3</span> MIME Type<a href=#subsubsec:mime-type class=anchor aria-hidden=true></a></h4><p>MIME type of the <a href=#subsubsec:data>data</a>. For example, if\nthe data field is set to <code>file:///sdcard/AppManager.apk</code>, the\nassociated MIME type can be\n<code>application/vnd.android.package-archive</code>.</section><section id=categories class=level4 data-number=2.8.1.4><h4 data-number=2.8.1.4><span class=header-section-number>2.8.1.4</span> Categories<a href=#categories class=anchor aria-hidden=true></a></h4><p>This is similar to <a href=#subsubsec:action>action</a> in the\nsense that it is also used by the system to filter application\ncomponents. This has no further benefits. Unlike <em>action</em>, there\ncan be more than one category. Clicking on the <em>plus</em> button next\nto the title allows adding more categories.</section><section id=flags class=level4 data-number=2.8.1.5><h4 data-number=2.8.1.5><span class=header-section-number>2.8.1.5</span> Flags<a href=#flags class=anchor aria-hidden=true></a></h4><p>Flags are useful in determining how system should behave during the\nlaunch or after the launch of an activity. This should not be touched as\nit requires some technical background. The <em>plus</em> button next to\nthe title can be used to add one or more flags.</section><section id=extras class=level4 data-number=2.8.1.6><h4 data-number=2.8.1.6><span class=header-section-number>2.8.1.6</span> Extras<a href=#extras class=anchor aria-hidden=true></a></h4><p>Extras are the key-value pairs used for supplying additional\ninformation to the destination component. More extras can be added using\nthe <em>plus</em> button next to the title.</section><section id=uri class=level4 data-number=2.8.1.7><h4 data-number=2.8.1.7><span class=header-section-number>2.8.1.7</span> URI<a href=#uri class=anchor aria-hidden=true></a></h4><p>Represents the entire Intent as a URI (e.g. <code>intent://…</code>).\nSome data cannot be converted to string, and as a result, they might not\nappear here.</section></section><section id=subsec:matching-activities class=level3 data-number=2.8.2><h3 data-number=2.8.2><span class=header-section-number>2.8.2</span>\n<a href=#toc:subsec:matching-activities>Matching Activities</a><a href=#subsec:matching-activities class=anchor aria-hidden=true></a></h3><p>List all the activity components that matches the Intent. This is\ninternally determined by the system (rather than App Manager). The\nlaunch button next to each component can be used to launch them directly\nfrom App Manager.</section><section id=subsec:interceptor-reset-to-default class=level3 data-number=2.8.3><h3 data-number=2.8.3><span class=header-section-number>2.8.3</span>\n<a href=#toc:subsec:interceptor-reset-to-default>Reset to\nDefault</a><a href=#subsec:interceptor-reset-to-default class=anchor aria-hidden=true></a></h3><p>Reset the Intent to its initial state.</section><section id=subsec:interceptor-send-edited-intent class=level3 data-number=2.8.4><h3 data-number=2.8.4><span class=header-section-number>2.8.4</span>\n<a href=#toc:subsec:interceptor-send-edited-intent>Send Edited\nIntent</a><a href=#subsec:interceptor-send-edited-intent class=anchor aria-hidden=true></a></h3><p>Resend the edited Intent to the destination application. This may\nopen a list of applications where the desired application is needed to\nbe selected. The result received from the target application will be\nsent to the source application. As a result, the source application will\nnot know if there was a man-in-the-middle.</section></section><section id=sec:shared-preferences-editor-page class=level2 data-number=2.9><h2 data-number=2.9><span class=header-section-number>2.9</span> <a href=#toc:sec:shared-preferences-editor-page>Shared Preferences Editor\nPage</a><a href=#sec:shared-preferences-editor-page class=anchor aria-hidden=true></a></h2><p>Shared preferences can be edited in this page. Clicking any item on\nthe list opens the edit dialog where the item can be edited. The\nfloating action button in the bottom-right corner can be used to add a\nnew item. To save or delete the file, or to discard current changes, the\nrespective options in the menu can be used.</section></section><section id=ch:guides class=level1 data-number=3><h1 data-number=3><span class=header-section-number>3</span> <a href=#toc:ch:guides>Guides</a><a href=#ch:guides class=anchor aria-hidden=true></a></h1><section id=sec:adb-over-tcp class=level2 data-number=3.1><h2 data-number=3.1><span class=header-section-number>3.1</span> <a href=#toc:sec:adb-over-tcp>ADB over TCP</a><a href=#sec:adb-over-tcp class=anchor aria-hidden=true></a></h2><p>Many root-only features can still be used by enabling ADB over TCP.\nTo do that, a PC or Mac is required with Android platform-tools\ninstalled, and an Android phone with developer options & USB\ndebugging enabled.<div class=\"amalert tip\"><p><strong><em>Root users.</em></strong><p>If superuser permission has been granted to App Manager, it can\nalready execute privileged code without any problem. <strong>Therefore,\nroot users do not need to enable ADB over TCP.</strong> But if you\ninsist on using ADB over TCP, you must revoke superuser permission for\nApp Manager.</div><div class=seealso-inline><p><em>See also: <span><a href=#sec:faq:adb-over-tcp>FAQ: ADB over\nTCP</a></span></em></div><section id=subsec:enable-developer-options class=level3 data-number=3.1.1><h3 data-number=3.1.1><span class=header-section-number>3.1.1</span>\n<a href=#toc:subsec:enable-developer-options>Enable developer\noptions</a><a href=#subsec:enable-developer-options class=anchor aria-hidden=true></a></h3><section id=subsubsec:location-of-developer-options class=level4 data-number=3.1.1.1><h4 data-number=3.1.1.1><span class=header-section-number>3.1.1.1</span> Location of developer\noptions<a href=#subsubsec:location-of-developer-options class=anchor aria-hidden=true></a></h4><p><strong>Developer options</strong> is located in Android\n<strong>Settings</strong>, either directly near the bottom of the page\n(in most ROMs) or under some other settings, such as\n<strong>System</strong> (Google Pixel, Lineage OS, Asus Zenfone 8.0+),\n<strong>Additional Settings</strong> (Xiaomi MIUI, Oppo ColorOS),\n<strong>More Settings</strong> (Vivo FuntouchOS), <strong>More</strong>\n(ZTE Nubia). Unlike other options, it is not visible until explicitly\nenabled by the user. If it is already enabled, you can use the search\nbox in Android <strong>Settings</strong> to locate it as well.</section><section id=how-to-enable-developer-options class=level4 data-number=3.1.1.2><h4 data-number=3.1.1.2><span class=header-section-number>3.1.1.2</span> How to enable developer\noptions<a href=#how-to-enable-developer-options class=anchor aria-hidden=true></a></h4><p>This option is available within Android <strong>Settings</strong> as\nwell but like the location of the developer options, it also differs\nfrom device to device. But in general, you have to find <strong>Build\nnumber</strong> (or <strong>MIUI version</strong> for MIUI ROMs and\n<strong>Software version</strong> for Vivo FuntouchOS,\n<strong>Version</strong> for Oppo ColorOS) and tap it at least 7 (seven)\ntimes until you finally get a message saying <em>You are now a\ndeveloper</em> (you may be prompted to insert pin/password/pattern or\nsolve captchas at this point). In most devices, it is located at the\nbottom of the settings page, inside <strong>About Phone</strong>. But\nthe best way to find it is to use the search box.</section></section><section id=subsec:enable-usb-debugging class=level3 data-number=3.1.2><h3 data-number=3.1.2><span class=header-section-number>3.1.2</span>\n<a href=#toc:subsec:enable-usb-debugging>Enable USB debugging</a><a href=#subsec:enable-usb-debugging class=anchor aria-hidden=true></a></h3><p>After <a href=#subsubsec:location-of-developer-options>locating the\ndeveloper options</a>, enable <strong>Developer option</strong> (if not\nalready). After that, scroll down a bit until you will find the option\n<strong>USB debugging</strong>. Use the toggle button on the right-hand\nside to enable it. At this point, you may get an alert prompt where you\nmay have to click <em>OK</em> to actually enable it. You may also have\nto enable some other options depending on device vendor and ROM. Here\nare some examples:<section id=xiaomi-miui class=level4 data-number=3.1.2.1><h4 data-number=3.1.2.1><span class=header-section-number>3.1.2.1</span> Xiaomi (MIUI)<a href=#xiaomi-miui class=anchor aria-hidden=true></a></h4><p>Enable <strong>USB debugging (Security settings)</strong> as\nwell.</section><section id=huawei-emui class=level4 data-number=3.1.2.2><h4 data-number=3.1.2.2><span class=header-section-number>3.1.2.2</span> Huawei (EMUI)<a href=#huawei-emui class=anchor aria-hidden=true></a></h4><p>Enable <strong>Allow ADB debugging in charge only mode</strong> as\nwell. When connecting to your PC or Mac, you may get a prompt saying\n<strong>Allow access to device data?</strong> in which case click\n<strong>YES, ALLOW ACCESS</strong>.<div class=\"amalert tip\"><p><strong><em>Notice.</em></strong><p>Often the <strong>USB debugging</strong> mode could be disabled\nautomatically by the system. If that’s the case, repeat the above\nprocedure.</div></section><section id=realme class=level4 data-number=3.1.2.3><h4 data-number=3.1.2.3><span class=header-section-number>3.1.2.3</span> Realme<a href=#realme class=anchor aria-hidden=true></a></h4><p>Depending on the device and the version of operating system, you have\nto enable <strong>Disable Permission Monitoring</strong>, or <strong>USB\ndebugging (Security settings)</strong> along with <strong>Install via\nUSB</strong>.</section><section id=oneplus-oxygen-os class=level4 data-number=3.1.2.4><h4 data-number=3.1.2.4><span class=header-section-number>3.1.2.4</span> OnePlus (Oxygen OS)<a href=#oneplus-oxygen-os class=anchor aria-hidden=true></a></h4><p>Depending on the device and the version of operating system, you have\nto enable <strong>Disable Permission Monitoring</strong>.</section><section id=lg class=level4 data-number=3.1.2.5><h4 data-number=3.1.2.5><span class=header-section-number>3.1.2.5</span> LG<a href=#lg class=anchor aria-hidden=true></a></h4><p>Make sure you have <strong>USB tethering</strong> enabled.</section><section id=troubleshooting class=level4 data-number=3.1.2.6><h4 data-number=3.1.2.6><span class=header-section-number>3.1.2.6</span> Troubleshooting<a href=#troubleshooting class=anchor aria-hidden=true></a></h4><p>In case <strong>USB Debugging</strong> is greyed out, you can do the\nfollowing:<ol class=incremental><li><p>Make sure you enabled USB debugging before connecting your phone\nto the PC or Mac via USB cable<li><p>Enable USB tethering after connecting to PC or Mac via USB\ncable<li><p>(For Samsung) If your device is running KNOX, you may have to\nfollow some additional steps. See official documentations or consult\nsupport for further assistant</ol></section></section><section id=subsec:setup-adb-on-pc-or-mac class=level3 data-number=3.1.3><h3 data-number=3.1.3><span class=header-section-number>3.1.3</span>\n<a href=#toc:subsec:setup-adb-on-pc-or-mac>Setup ADB on PC or\nMac</a><a href=#subsec:setup-adb-on-pc-or-mac class=anchor aria-hidden=true></a></h3><p>In order to enable ADB over TCP, you have to set up ADB in your PC or\nMac. <strong><em>Lineage OS users can skip to §<a href=#subsubsec:lineage-os data-reference-type=ref data-reference=subsubsec:lineage-os>3.1.4.1</a>.</em></strong><section id=windows class=level4 data-number=3.1.3.1><h4 data-number=3.1.3.1><span class=header-section-number>3.1.3.1</span> Windows<a href=#windows class=anchor aria-hidden=true></a></h4><ol class=incremental><li><p>Download the latest version of <a href=https://dl.google.com/android/repository/platform-tools-latest-windows.zip>Android\nSDK Platform-Tools</a> for Windows<li><p>Extract the contents of the zip file into any directory (such as\n<code>C:\\</code><span><code>adb</code></span>) and navigate to that\ndirectory using <em>Explorer</em><li><p>Open <strong>Command Prompt</strong>,\n<strong>PowerShell</strong>, or <strong>Terminal</strong> from this\ndirectory. You can do it manually from the start menu or by holding\n<code>Shift</code> and right clicking within the directory in <em>File\nExplorer</em> and then clicking either on <em>Open command window\nhere</em>, or <em>Open PowerShell window here</em> (depending on what\nyou have installed). You can now access ADB by typing <code>adb</code>\n(Command Prompt) or <code>./adb</code> (PowerShell). Do not close this\nwindow yet.</ol><div class=\"amalert tip\"><p><strong><em>Tip.</em></strong><p>If you have <a href=https://learn.microsoft.com/en-us/windows/package-manager/winget/>WinGet</a>\ninstalled, you can install ADB using the following command:<div class=sourceCode id=cb3 data-frame=lines><pre class=\"sourceCode bash\"><code class=\"sourceCode bash\"><span id=cb3-1><a href=#cb3-1 aria-hidden=true tabindex=-1></a><span class=ex>winget</span> install <span class=at>--id</span> Google.PlatformTools</span></code></pre></div><p>After that, you can simply type <code>adb</code> to access ADB.</div></section><section id=macos class=level4 data-number=3.1.3.2><h4 data-number=3.1.3.2><span class=header-section-number>3.1.3.2</span> macOS<a href=#macos class=anchor aria-hidden=true></a></h4><ol class=incremental><li><p>Download the latest version of <a href=https://dl.google.com/android/repository/platform-tools-latest-darwin.zip>Android\nSDK Platform-Tools</a> for macOS<li><p>Extract the contents of the zip file into a directory by clicking\non it. After that, navigate to that directory using <em>Finder</em> and\nlocate <code>adb</code><li><p>Open <strong>Terminal</strong> using <em>Launchpad</em> or\n<em>Spotlight</em> and drag-and-drop <code>adb</code> from the\n<em>Finder</em> window into the <em>Terminal</em> window. Do not close\nthe <em>Terminal</em> window yet</ol><div class=\"amalert tip\"><p><strong><em>Tip.</em></strong><p>If you have <a href=https://brew.sh>Homebrew</a> installed, you can\ninstall ADB using the following command:<div class=sourceCode id=cb4 data-frame=lines><pre class=\"sourceCode bash\"><code class=\"sourceCode bash\"><span id=cb4-1><a href=#cb4-1 aria-hidden=true tabindex=-1></a><span class=ex>brew</span> install <span class=at>--cask</span> android-platform-tools</span></code></pre></div><p>After that, you can simply type <code>adb</code> in any\n<em>Terminal</em> window to access ADB.</div></section><section id=linux class=level4 data-number=3.1.3.3><h4 data-number=3.1.3.3><span class=header-section-number>3.1.3.3</span> Linux<a href=#linux class=anchor aria-hidden=true></a></h4><ol class=incremental><li><p>In your favourite terminal emulator, run the following\ncommand:<div class=sourceCode id=cb5 data-frame=lines data-autogobble><pre class=\"sourceCode bash\"><code class=\"sourceCode bash\"><span id=cb5-1><a href=#cb5-1 aria-hidden=true tabindex=-1></a><span class=bu>cd</span> ~/Downloads <span class=kw>&amp;&amp;</span> <span class=ex>curl</span> <span class=at>-o</span> platform-tools.zip <span class=at>-L</span> <span class=dt>\\</span></span>\n<span id=cb5-2><a href=#cb5-2 aria-hidden=true tabindex=-1></a>https://dl.google.com/android/repository/platform-tools-latest-linux.zip <span class=kw>&amp;&amp;</span> <span class=dt>\\</span></span>\n<span id=cb5-3><a href=#cb5-3 aria-hidden=true tabindex=-1></a><span class=fu>unzip</span> platform-tools.zip <span class=kw>&amp;&amp;</span> <span class=fu>rm</span> platform-tools.zip <span class=kw>&amp;&amp;</span> <span class=bu>cd</span> platform-tools</span></code></pre></div><li><p>If it is successful, you can simply type <code>./adb</code> in\nthe in <em>same</em> terminal emulator window or type\n<code>~/Downloads/platform-tools/adb</code> in any terminal emulator to\naccess ADB.</ol></section></section><section id=subsec:configure-adb-over-tcp class=level3 data-number=3.1.4><h3 data-number=3.1.4><span class=header-section-number>3.1.4</span>\n<a href=#toc:subsec:configure-adb-over-tcp>Configure ADB over\nTCP</a><a href=#subsec:configure-adb-over-tcp class=anchor aria-hidden=true></a></h3><section id=subsubsec:lineage-os class=level4 data-number=3.1.4.1><h4 data-number=3.1.4.1><span class=header-section-number>3.1.4.1</span> Lineage OS 17.1 and\nEarlier<a href=#subsubsec:lineage-os class=anchor aria-hidden=true></a></h4><p>Lineage OS (or its derivatives) users can directly enable ADB over\nTCP using the developer options. To enable that, go to the\n<strong>Developer options</strong>, scroll down until you find\n<strong>ADB over Network</strong>. Now, use the toggle button on the\nright-hand side to enable it and skip to §<a href=#subsubsec:adb-mode-in-app-manager data-reference-type=ref data-reference=subsubsec:adb-mode-in-app-manager>3.1.4.3</a>.<div class=\"amalert warning\"><p><strong><em>Warning.</em></strong><p>You can turn off <strong>ADB over Network</strong> in developer\noptions, but turning off this option will also stop App Manager’s remote\nserver. So, turn it off only when you’re not going to use App Manager in\nADB over TCP mode.</div></section><section id=subsubsec:enable-adb-over-tcp-via-pc-or-mac class=level4 data-number=3.1.4.2><h4 data-number=3.1.4.2><span class=header-section-number>3.1.4.2</span> Enable ADB over TCP via PC\nor Mac<a href=#subsubsec:enable-adb-over-tcp-via-pc-or-mac class=anchor aria-hidden=true></a></h4><p>For other ROMs, you can do this using the command\nprompt/PowerShell/terminal emulator that you’ve opened in the step 3 of\nthe previous section. In this section, I will use <code>adb</code> to\ndenote <code>./adb</code>, <code>adb</code> or any other command that\nyou needed to use based on your platform and software in the previous\nsection.<ol class=incremental><li><p>Connect your device to your PC or Mac using a USB cable. For some\ndevices, it is necessary to turn on <em>File transfer mode (MTP)</em> as\nwell<li><p>To confirm that everything is working as expected, type\n<code>adb devices</code> in your terminal. If your device is connected\nsuccessfully, you will see something like this:<pre><code>List of devices attached\nxxxxxxxx  device</code></pre><div class=\"amalert tip\"><p><strong><em>Notice.</em></strong><p>In some Android phones, an alert prompt will be appeared with a\nmessage <strong>Allow USB Debugging</strong> in which case, check\n<em>Always allow from this computer</em> and click\n<strong>Allow</strong>.</div><li><p>Finally, run the following command to enable ADB over TCP:<div class=sourceCode id=cb7 data-frame=lines data-autogobble><pre class=\"sourceCode bash\"><code class=\"sourceCode bash\"><span id=cb7-1><a href=#cb7-1 aria-hidden=true tabindex=-1></a><span class=ex>adb</span> tcpip 5555</span></code></pre></div></ol><div class=\"amalert danger\"><p><strong><em>Danger.</em></strong><p>You cannot disable developer options or USB debugging after enabling\nADB over TCP.</div></section><section id=subsubsec:adb-mode-in-app-manager class=level4 data-number=3.1.4.3><h4 data-number=3.1.4.3><span class=header-section-number>3.1.4.3</span> Enable ADB mode in App\nManager<a href=#subsubsec:adb-mode-in-app-manager class=anchor aria-hidden=true></a></h4><p>After enabling ADB over TCP, relaunch App Manager. App Manager should\ndetect ADB mode automatically. If it cannot, you can change the mode of\noperation to ADB over TCP in the <a href=#subsec:mode-of-operation>settings page</a>. There, you can also\nverify whether App Manager has correctly detected ADB as indicated by\nthe <em>inferred mode</em>.<div class=\"amalert tip\"><p><strong><em>Notice.</em></strong><p>In some Android devices, the USB cable is needed to be disconnected\nfrom the PC before connecting to App Manager.</div><div class=\"amalert warning\"><p><strong><em>Warning.</em></strong><p>ADB over TCP will be disabled after a reboot. In that case, you have\nto follow §<a href=#subsubsec:enable-adb-over-tcp-via-pc-or-mac data-reference-type=ref data-reference=subsubsec:enable-adb-over-tcp-via-pc-or-mac>3.1.4.2</a>\nagain.</div></section></section></section><section id=sec:wireless-debugging class=level2 data-number=3.2><h2 data-number=3.2><span class=header-section-number>3.2</span> <a href=#toc:sec:wireless-debugging>Wireless Debugging</a><a href=#sec:wireless-debugging class=anchor aria-hidden=true></a></h2><p>If you are running Android 11 or later and capable of connecting to a\nWi-Fi network for, at least, a few moments, Wireless Debugging is the\nrecommended approach as it offers more protection than <a href=#sec:adb-over-tcp>ADB over TCP</a>. It requires two steps:<ol class=incremental><li><p><strong>ADB pairing.</strong> The initial and a bit complex step\nfor a novice user. Fortunately, this step is not required all the\ntime.<li><p><strong>Connecting to ADB.</strong> Needs to be done every time\nyou reboot your phone. App Manager can also automate this step in most\ndevices.</ol><section id=subsec:enable-developer-options-and-usb-debugging class=level3 data-number=3.2.1><h3 data-number=3.2.1><span class=header-section-number>3.2.1</span>\n<a href=#toc:subsec:enable-developer-options-and-usb-debugging>Enable\ndeveloper options and USB Debugging</a><a href=#subsec:enable-developer-options-and-usb-debugging class=anchor aria-hidden=true></a></h3><p>See §<a href=#subsec:enable-developer-options data-reference-type=ref data-reference=subsec:enable-developer-options>3.1.1</a> and §<a href=#subsec:enable-usb-debugging data-reference-type=ref data-reference=subsec:enable-usb-debugging>3.1.2</a>.</section><section id=subsec:enable-wireless-debugging class=level3 data-number=3.2.2><h3 data-number=3.2.2><span class=header-section-number>3.2.2</span>\n<a href=#toc:subsec:enable-wireless-debugging>Enable Wireless\nDebugging</a><a href=#subsec:enable-wireless-debugging class=anchor aria-hidden=true></a></h3><p>In the <strong>Developer options</strong> page, find <strong>Wireless\ndebugging</strong> and click to open it. In the new page, turn on\n<em>Use wireless debugging</em>. Depending on the operating system, you\nmight see a dialog prompt asking you to verify your decision. If that is\nthe case, click <em>Allow</em>.<div class=\"amalert tip\"><p><strong><em>Tip.</em></strong><p>For easy access, you might want to add <strong>Wireless\ndebugging</strong> in the notification tiles section. To do this, find\n<strong>Quick settings developer tiles</strong> in the <strong>Developer\noptions</strong> page and click to open it. In the new window, enable\n<em>Wireless debugging</em>. In case you do not see this setting, you\nmay find a <strong>Wireless debugging</strong> tile in the tile\ncustomization panel.</div></section><section id=subsec:pair-adb-with-app-manager class=level3 data-number=3.2.3><h3 data-number=3.2.3><span class=header-section-number>3.2.3</span>\n<a href=#toc:subsec:pair-adb-with-app-manager>Pair ADB with App\nManager</a><a href=#subsec:pair-adb-with-app-manager class=anchor aria-hidden=true></a></h3><p>In App Manager, navigate to <strong>Settings</strong> > <a href=#subsec:mode-of-operation>Mode of operation</a> and then enable\n<em>Wireless debugging</em>. At this, App Manager will try to establish\na wireless debugging connection automatically which will fail if it has\nnot been paired before. Once it fails, it will ask you to either connect\nor pair ADB. Select <em>pair</em> and a new dialog will appear. It will\nask you to navigate to the <strong>Wireless debugging</strong> page.<div class=\"amalert tip\"><p><strong><em>Note.</em></strong><p>As of v4.0.0, pairing is done using a notification prompt. So, if you\nhave disabled notification for App Manager, you must enable it\nfirst.</div><p>In the <strong>Wireless debugging</strong> page, select <strong>Pair\ndevice with pairing code</strong>. At this, a dialog containing a\npairing code will be displayed. A notification asking for the pairing\ncode will also be visible almost instantly. Insert the pairing code in\nthe input box in the notification and click <em>pair</em>. If the\npairing is successful, App Manager will display notification with the\nmessage “paired”, and the dialog in the <strong>Wireless\ndebugging</strong> page will be dismissed automatically. You will also\nbe able to see App Manager listed as an ADB client in the same page.<div class=\"amalert tip\"><p><strong><em>Notice.</em></strong><p>If you do not use App Manager in ADB mode for a while, App Manager\nmight be removed from the list of clients. In that case, you have to\nrepeat the above procedure.</div></section><section id=subsec:connect-app-manager-to-adb class=level3 data-number=3.2.4><h3 data-number=3.2.4><span class=header-section-number>3.2.4</span>\n<a href=#toc:subsec:connect-app-manager-to-adb>Connect App Manager to\nADB</a><a href=#subsec:connect-app-manager-to-adb class=anchor aria-hidden=true></a></h3><p>App Manager should be able to connect to ADB automatically if the\nmode of operation is set to <em>auto</em>, <em>ADB over TCP</em> or\n<em>Wireless debugging</em>. If this is not the case, select\n<em>Wireless debugging</em> in <strong>Settings</strong> > <a href=#subsec:mode-of-operation>Mode of operation</a>. If App Manager\nfails to detect or connect to ADB, it will ask you to connect or pair\nADB. Select <em>connect</em>.<p>Now, navigate to the <strong>Wireless debugging</strong> page in\nAndroid settings, and note down the port number displayed in the page.\nIn App Manager’s dialog prompt, replace the port number with the one you\nhave noted earlier, and click <em>connect</em>.<p>Once a connection has been established, you can disable\n<strong>Wireless debugging</strong> in Android settings.<div class=\"amalert danger\"><p><strong><em>Caution.</em></strong><p>Never disable <strong>USB Debugging</strong> or any other additional\noptions described in §<a href=#subsec:enable-developer-options-and-usb-debugging data-reference-type=ref data-reference=subsec:enable-developer-options-and-usb-debugging>3.2.1</a>.\nIf you do this, the remote server used by App Manager will be stopped,\nand you may have to start all over again.</div></section></section><section id=sec:backup-restore class=level2 data-number=3.3><h2 data-number=3.3><span class=header-section-number>3.3</span> <a href=#toc:sec:backup-restore>Back up/Restore</a><a href=#sec:backup-restore class=anchor aria-hidden=true></a></h2><p>App Manager has a modern, advanced and easy-to-use backup/restore\nsystem implemented from the scratch. This is probably the only app that\nhas the ability to restore not only the app or its data but also\npermissions and rules that you’ve configured within App Manager. You can\nalso choose to back up an app multiple times (with custom names) or for\nall users.<div class=seealso><p><em>See also:</em><ul class=incremental><li><p><a href=#subsec:1-click-back-up>1-Click Ops: Back\nup</a><li><p><a href=#subsec:1-click-restore>1-Click Ops:\nRestore</a></ul></div><section id=subsec:backup-location class=level3 data-number=3.3.1><h3 data-number=3.3.1><span class=header-section-number>3.3.1</span>\n<a href=#toc:subsec:backup-location>Location</a><a href=#subsec:backup-location class=anchor aria-hidden=true></a></h3><p>Back up/restore is a part of <a href=#subsec:batch-operations>batch\noperations</a>. It is also located inside the <a href=#subsubsec:app-info-options-menu>options menu</a> in the <a href=#subsec:app-info-tab>App Info tab</a>. Clicking on\n<strong>Backup/Restore</strong> opens the <strong>Backup\nOptions</strong>. Backups are located at\n<code>/storage/emulated/0/AppManager</code> by default. You can\nconfigure custom backup location in the <a href=#subsubsec:backup-volume>settings page</a> in which case the\nbackups will be located at the <code>AppManager</code> folder in the\nselected volume.<div class=\"amalert tip\"><p><strong><em>Note.</em></strong><p>If one or more selected apps do not have any backup, the\n<strong>Restore</strong> and <strong>Delete Backup</strong> options will\nnot be displayed.</div></section><section id=subsec:backup-restore-backup-options class=level3 data-number=3.3.2><h3 data-number=3.3.2><span class=header-section-number>3.3.2</span>\n<a href=#toc:subsec:backup-restore-backup-options>Backup Options</a><a href=#subsec:backup-restore-backup-options class=anchor aria-hidden=true></a></h3><p>Backup options (internally known as backup flags) let you customise\nthe backups on the fly. However, the customisations will not be\nremembered for the future backups. If you want to customise this dialog,\nuse <a href=#subsubsec:settings-backup-options>Backup Options</a> in\nthe <a href=#sec:settings-page>Settings page</a>.<p>A complete description of the backup options is given below:<ul class=incremental><li><p><strong>APK files.</strong> Whether to back up the APK files.\nThis includes the <em>base APK</em> file along with the\n<code>split APK</code> files if they exist.<li><p><strong>Internal data.</strong> Whether to back up the internal\ndata directories. These directories are located at\n<code>/data/user/&lt;user_id></code> and (for Android N or later)\n<code>/data/user_de/&lt;user_id></code>.<li><p><strong>External data.</strong> Whether to back up data\ndirectories located in the internal memory as well as SD Card (if\nexists). External data directories often contain non-essential app data\nor media files (instead of using the dedicated media folder) and may\nincrease the backup size. However, it might be essential for some apps.\nAlthough it isn’t checked by default (as it might dramatically increase\nthe size of the backups), you may have to check it in order to ensure a\nsmooth restore of your backups.<div class=\"amalert warning\"><p><strong><em>Caution.</em></strong><p>Internal data folders should always be backed up if you are going to\nback up the external data folders. However, it could be useful to back\nup only the external folders if the app in question downloads a lot of\nassets from the Internet.</div><li><p><strong>OBB and media.</strong> Whether to back up or restore the\nOBB and the media directories located in the external storage or the SD\nCard. This is useful for games and the graphical software which actually\nuse these folders.<li><p><strong>Cache.</strong> Android apps have multiple cache\ndirectories located at every data directories (both internal and\nexternal). There are two types of cache: <strong>cache</strong> and\n<strong>code cache</strong>. Disabling this option excludes both cache\ndirectories from all the data directories. It is generally advised to\nexclude cache directories since most apps do not clear the cache\nregularly and usually handled by the OS itself. Apps such as Telegram\nmay use a very large cache (depending on the storage space) which may\ndramatically increase the backup size. When it is disabled, AM also\nignores the <strong>no_backup</strong> directories.<li><p><strong>Extras.</strong> Backup/restore app permissions, net\npolicy, battery optimization, SSAID, etc., enabled by default. Note\nthat, blocking rules are applied <em>after</em> applying the extras. So,\nif an item is present in both places, it will be overwritten (i.e., the\none from the blocking rules will be used).<li><p><strong>Rules.</strong> This option lets you back up blocking\nrules configured within App Manager. This might come in handy if you\nhave customised permissions or block some components using App Manager\nas they will also be backed up or restored when you enable this\noption.<li><p><strong>Backup Multiple.</strong> Whether this is a multiple\nbackup. By default, backups are saved using their user ID. Enabling this\noption allows you to create additional backups. These backups use the\ncurrent date-time as the default backup name, but you can also specify\ncustom backup name using the input field displayed when you click on the\n<strong>Backup</strong> button.<li><p><strong>Custom users.</strong> Backup or restore for the selected\nusers instead of only the current user. This option is only displayed if\nthe system has more than one user.<li><p><strong>Skip signature checks.</strong> When taking a backup,\nchecksum of every file (as well as the signing certificate(s) of the\nbase APK file) is generated and stored in the <code>checksums.txt</code>\nfile. When you restore the backup, the checksums are generated again and\nare matched with the checksums stored in the said file. Enabling this\noption will disable the signature checks. This option is applied only\nwhen you restore a backup. During backup, the checksums are generated\nregardless of this option.<div class=\"amalert warning\"><p><strong><em>Caution.</em></strong><p>You should always disable this option to ensure that your backups are\nnot modified by any third-party applications. However, this would only\nwork if you enabled encryption.</div></ul><div class=seealso-inline><p><em>See also: <span><a href=#subsubsec:settings-encryption>Settings:\nEncryption</a></span></em></div></section><section id=subsec:backup-restore-backup class=level3 data-number=3.3.3><h3 data-number=3.3.3><span class=header-section-number>3.3.3</span>\n<a href=#toc:subsec:backup-restore-backup>Backup</a><a href=#subsec:backup-restore-backup class=anchor aria-hidden=true></a></h3><p>Backup respects all the backup options except <strong>Skip signature\nchecks</strong>. If base backups (i.e., backups that don’t have the\n<strong>Backup Multiple</strong> option) already exist, you will get a\nwarning as the backups will be overwritten. If <strong>Backup\nMultiple</strong> is set, you have an option to input the backup name,\nor you can leave it blank to use the current date-time.</section><section id=subsec:backup-restore-restore class=level3 data-number=3.3.4><h3 data-number=3.3.4><span class=header-section-number>3.3.4</span>\n<a href=#toc:subsec:backup-restore-restore>Restore</a><a href=#subsec:backup-restore-restore class=anchor aria-hidden=true></a></h3><p>Restore respects all the backup options and will fail if <strong>APK\nfiles</strong> option is set, but the backup doesn’t contain such\nbackups or in other cases, if the app isn’t installed. When restoring\nbackups for multiple packages, you can only restore the base backups\n(see <a href=#subsec:backup-restore-backup>backup</a> section for an\nexplanation). However, when restoring backups for a single package, you\nhave the option to select which backup to restore. If <strong>All\nusers</strong> option is set, AM will restore the selected backup for\nall users in the latter case but in the former case, it will restore\nbase backups for the respective users.<div class=\"amalert tip\"><p><strong><em>Notice.</em></strong><p>Apps that use storage access framework (SAF), SSAID or Android\nKeyStore works properly only after an immediate restart.</div></section><section id=subsec:backup-restore-delete-backup class=level3 data-number=3.3.5><h3 data-number=3.3.5><span class=header-section-number>3.3.5</span>\n<a href=#toc:subsec:backup-restore-delete-backup>Delete Backup</a><a href=#subsec:backup-restore-delete-backup class=anchor aria-hidden=true></a></h3><p>Delete backup only respects <strong>All users</strong> option and\nwhen it is selected, only the base backups for all users will be deleted\nwith a prompt. When deleting backups for a single package, another\ndialog will be displayed where you can select the backups to delete.</section></section><section id=sec:automating-tasks class=level2 data-number=3.4><h2 data-number=3.4><span class=header-section-number>3.4</span> <a href=#toc:sec:automating-tasks>Automating Tasks</a><a href=#sec:automating-tasks class=anchor aria-hidden=true></a></h2><p>It is possible to trigger profiles configured inside App Manager via\nthird-party applications such as <strong>Automation</strong> or\n<strong>Tasker</strong>. Traditionally, <code>Intent</code>s are used to\ntrigger such operations.<section id=subsec:generating-authorization-key class=level3 data-number=3.4.1><h3 data-number=3.4.1><span class=header-section-number>3.4.1</span>\n<a href=#toc:subsec:generating-authorization-key>Generating\nauthorization key</a><a href=#subsec:generating-authorization-key class=anchor aria-hidden=true></a></h3><p>In order to ensure proper security, an authorization key is required.\nTo generate a authorization key, go to <strong>Settings</strong> page\nand then <strong>Privacy</strong> > <strong>Authorization\nManager</strong>. If an authorization key has not been generated, it\nwill be generated automatically. The key can be regenerated as\nrequired.<div class=\"amalert danger\"><p><strong><em>Caution.</em></strong><p>Regenerating the authorization key can have some side effects such as\ninvalidation of all the previously configured Intents.</div></section><section id=subsec:at:general-configuration class=level3 data-number=3.4.2><h3 data-number=3.4.2><span class=header-section-number>3.4.2</span>\n<a href=#toc:subsec:at:general-configuration>Configuring tasks</a><a href=#subsec:at:general-configuration class=anchor aria-hidden=true></a></h3><p>The activity\n<code>io.github.muntashirakon.AppManager.crypto.auth.AuthFeatureDemultiplexer</code>\nis responsible for handling all the automations. Sending an intent to\nthe activity lets App Manager perform the designated operation by\nredirecting the <code>Intent</code> to the designated activity or\nservice.<section id=required-extras class=level4 data-number=3.4.2.1><h4 data-number=3.4.2.1><span class=header-section-number>3.4.2.1</span> Required extras<a href=#required-extras class=anchor aria-hidden=true></a></h4><p>It has two primary extras required in all conditions. The key names,\ndata types are all follows:<ol class=incremental><li><p><strong><code>auth</code>.</strong> (String value) The\nauthorization key as described in the earlier section.<li><p><strong><code>feature</code>.</strong> (String value) Name of the\nfeature. Supported features are described in the next section.</ol></section></section><section id=subsec:at:features class=level3 data-number=3.4.3><h3 data-number=3.4.3><span class=header-section-number>3.4.3</span>\n<a href=#toc:subsec:at:features>Features</a><a href=#subsec:at:features class=anchor aria-hidden=true></a></h3><p>App Manager current support a single feature, namely\n<code>profile</code>.</section><section id=subsec:triggering-a-profile class=level3 data-number=3.4.4><h3 data-number=3.4.4><span class=header-section-number>3.4.4</span>\n<a href=#toc:subsec:triggering-a-profile>Triggering a profile</a><a href=#subsec:triggering-a-profile class=anchor aria-hidden=true></a></h3><p>In order to trigger a profile, <code>feature</code> must have the\nvalue <code>profile</code>. In addition, the following extras can be\nincluded:<ol class=incremental><li><p><strong><code>prof</code>.</strong> (String value – required) The\nname of the profile as displayed in the <a href=#sec:profiles-page>Profiles page</a>.<li><p><strong><code>state</code>.</strong> (String value – optional)\nState of the profile – currently <code>on</code> or <code>off</code> –\nas specified in the documentation. If this extra is not set, App Manager\nwill display a prompt where a state must be selected. Therefore, for\ncomplete automation, this option should be set.</ol></section></section><section id=sec:net-policy class=level2 data-number=3.5><h2 data-number=3.5><span class=header-section-number>3.5</span> <a href=#toc:sec:net-policy>Net Policy</a><a href=#sec:net-policy class=anchor aria-hidden=true></a></h2><p>Short for <strong>Network policy</strong> or network policies. It is\nusually located in the Android settings under <strong>Mobile data &\nWifi</strong> section in the app info page of an app. Not all policies\nare guaranteed to be included in this page (e.g. Samsung), and not all\nsettings are well-understood due to lack of documentation. App Manager\ncan display all the net policies declared in the <a href=https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/net/NetworkPolicyManager.java>NetworkPolicyManager</a>.\nPolicies unknown to App Manager will have a <em>Unknown</em> prefix\nalong with the policy constant name and number in the hexadecimal\nformat. Unknown policies should be reported to App Manager for\ninclusion.<p>Net policy allows a user to configure certain networking behaviour of\nan app without modifying the ip tables directly and/or running a\nfirewall app. However, the features it offers largely depend on Android\nversion and ROM. A list of known net policies are listed below:<ol class=incremental><li><p><strong>None</strong> or\n<strong><code>POLICY_NONE</code></strong>: (AOSP) No specific network\npolicy is set. System can still assign rules depending on the nature of\nthe app.<li><p><strong>Reject background data on metered networks</strong> or\n<strong><code>POLICY_REJECT_METERED_BACKGROUND</code></strong>: (AOSP)\nReject network usage on metered networks when the application is in\nbackground.<li><p><strong>Allow background data on metered networks even when Data\nSaver is on</strong> or\n<strong><code>POLICY_ALLOW_METERED_BACKGROUND</code></strong>: (AOSP)\nAllow metered network use in the background even when data saving mode\nis enabled.<li><p><strong>Reject cellular data</strong> or\n<strong><code>POLICY_REJECT_CELLULAR</code></strong> (Android 11+) or\n<strong><code>POLICY_REJECT_ON_DATA</code></strong> (up to Android 10):\n(Lineage OS) Reject mobile/cellular data. Signals network unavailable to\nthe configured app as if the mobile data is inactive.<li><p><strong>Reject VPN data</strong> or\n<strong><code>POLICY_REJECT_VPN</code></strong> (Android 11+) or\n<strong><code>POLICY_REJECT_ON_VPN</code></strong> (up to Android 10):\n(Lineage OS) Reject VPN data. Signals network unavailable to the\nconfigured app as if the VPN is inactive.<li><p><strong>Reject Wi-Fi data</strong> or\n<strong><code>POLICY_REJECT_WIFI</code></strong> (Android 11+) or\n<strong><code>POLICY_REJECT_ON_WLAN</code></strong> (up to Android 10):\n(Lineage OS) Reject Wi-Fi data. Signals network unavailable to the\nconfigured app as if the device is not connected to a Wi-Fi\nnetwork.<li><p><strong>Disable network access</strong> or\n<strong><code>POLICY_REJECT_ALL</code></strong> (Android 11+) or\n<strong><code>POLICY_NETWORK_ISOLATED</code></strong> (up to Android\n10): (Lineage OS) Reject network access in all circumstances. This is\nnot the same as enforcing the other three policies above, and is the\nrecommended policy for dodgy apps. If this policy is enforced, there is\nno need to enforce the other policies.<li><p><strong><code>POLICY_ALLOW_METERED_IN_ROAMING</code></strong>:\n(Samsung) Possibly allow metered network use during roaming. Exact\nmeaning is currently unknown.<li><p><strong><code>POLICY_ALLOW_WHITELIST_IN_ROAMING</code></strong>:\n(Samsung) Possibly allow network use during roaming. Exact meaning is\ncurrently unknown.<li><p><strong>Reject data on metered networks</strong> or\n<strong><code>POLICY_REJECT_METERED</code></strong>: (Motorola) Reject\nnetwork usage if it is a metered network.<li><p><strong>Reject background data</strong> or\n<strong><code>POLICY_REJECT_BACKGROUND</code></strong>: (Motorola)\nReject network usage in the background.<li><p><strong>Disable network access</strong> or\n<strong><code>POLICY_REJECT_ALL</code></strong>: (Motorola) Reject\nnetwork access altogether. Like Lineage OS, it blocks internet\nconnections via iptables. But whether it signals the unavailability of\nnetwork to the configured app is not known.</ol><div class=\"amalert tip\"><p><strong><em>Note.</em></strong><p>Corresponding Lineage OS patches are as follows:<ol class=incremental><li><p><a href=https://github.com/LineageOS/android_frameworks_base/commit/a04932bafbbf7d99efd18276152cc2c9c9b2073e>fw/b:\nSquash of app fw restriction commits</a><li><p><a href=https://github.com/LineageOS/android_frameworks_base/commit/02c8c82854348f52afe2199f310f44b5f578b5b8>fw/b:\nAdd support for per app network isolation</a></ol></div></section></section><section id=ch:faq class=level1 data-number=4><h1 data-number=4><span class=header-section-number>4</span> <a href=#toc:ch:faq>Frequently Asked Questions</a><a href=#ch:faq class=anchor aria-hidden=true></a></h1><section id=sec:faq:app-components class=level2 data-number=4.1><h2 data-number=4.1><span class=header-section-number>4.1</span> <a href=#toc:sec:faq:app-components>App Components</a><a href=#sec:faq:app-components class=anchor aria-hidden=true></a></h2><section id=subsec:faq:what-are-app-components class=level3 data-number=4.1.1><h3 data-number=4.1.1><span class=header-section-number>4.1.1</span>\n<a href=#toc:subsec:faq:what-are-app-components>What are the\napplication components?</a><a href=#subsec:faq:what-are-app-components class=anchor aria-hidden=true></a></h3><p>Activities, services, broadcast receivers (or only receivers) and\ncontent providers (or only providers) are jointly called application\ncomponents. More technically, they all inherit the <a href=https://developer.android.com/reference/android/content/pm/ComponentInfo>ComponentInfo</a>\nclass and can be launched via Intent.</section><section id=subsec:faq:how-components-blocked class=level3 data-number=4.1.2><h3 data-number=4.1.2><span class=header-section-number>4.1.2</span>\n<a href=#toc:subsec:faq:how-components-blocked>How are the tracker and\nother components blocked in App Manager? What are its limitations?</a><a href=#subsec:faq:how-components-blocked class=anchor aria-hidden=true></a></h3><p>App Manager typically blocks application components (or tracker\ncomponents) using a method called <a href=https://carteryagemann.com/pages/android-intent-firewall.html>Intent\nFirewall (IFW)</a>, it is superior to other methods such as <em>pm</em>\n(PackageManager), <a href=https://github.com/RikkaApps/Shizuku>Shizuku</a> or any other\nmethod that uses the package manager to enable or disable the\ncomponents. If a component is disabled by the latter methods, the\napplication itself can detect that the component is being blocked and\ncan re-enable it as it has full access to its own components. (Many\ndeceptive applications actually do this in order to keep the tracker\ncomponents unblocked.) On the other hand, IFW is a true firewall and the\napplication cannot detect if its components are being blocked. App\nManager uses the term <em>block</em> rather than <em>disable</em> for\nthis reason.<p>Even IFW has some limitations which are primarily applicable for the\nsystem applications:<ul class=incremental><li><p>The application in question is whitelisted by the system i.e. the\nsystem cannot function properly without these applications and may cause\nrandom crashes. These applications include but not limited to Android\nSystem, System UI, Phone Services. They will continue to work even if\nthey are disabled or blocked.<li><p>Another system application or system process has activated a\nspecific component of the application in question via interprocess\ncommunication (IPC). In this case, the component will be activated\nregardless of blocking status or even if the entire application is\ndisabled. If there is such a system application that is not needed, the\nonly way to prevent it from running is by getting rid of it.</ul></section><section id=subsec:faq:components-blocked-by-others class=level3 data-number=4.1.3><h3 data-number=4.1.3><span class=header-section-number>4.1.3</span>\n<a href=#toc:subsec:faq:components-blocked-by-others>Does app\ncomponents blocked by other tools retained in App Manager?</a><a href=#subsec:faq:components-blocked-by-others class=anchor aria-hidden=true></a></h3><p><strong>No.</strong> But the application components blocked by the\nsystem or any other tools are displayed in the <a href=#subsec:component-tabs>component tabs</a>. These rules can be\nimported from <a href=#par:import-existing-rules>Settings</a>.\nHowever, it is not possible for App Manager to distinguish the\ncomponents blocked by the third-party tools and components blocked by\nthe system. Therefore, the applications listed in the import page should\nbe selected with care.</section><section id=subsec:faq:components-reblocked-in-am class=level3 data-number=4.1.4><h3 data-number=4.1.4><span class=header-section-number>4.1.4</span>\n<a href=#toc:subsec:faq:components-reblocked-in-am>What happens to the\ncomponents blocked by App Manager which were previously blocked by other\ntools?</a><a href=#subsec:faq:components-reblocked-in-am class=anchor aria-hidden=true></a></h3><p><em>App Manager blocks the components again</em> if requested. In\ncase of unblocking, they will be reverted to the default state as\nspecified in the manifest of the application. But if the components were\nblocked by <a href=https://www.myandroidtools.com>MyAndroidTools\n(MAT)</a> with IFW method, they will not be unblocked by App Manager as\nit uses a different format. To fix this issue, the rules have to be\nimported from <a href=#par:import-existing-rules>Settings</a> at\nfirst, in which case MAT’s configurations will be permanently\nremoved.</section><section id=subsec:faq:what-is-instant-component-blocking class=level3 data-number=4.1.5><h3 data-number=4.1.5><span class=header-section-number>4.1.5</span>\n<a href=#toc:subsec:faq:what-is-instant-component-blocking>What is\ninstant component blocking?</a><a href=#subsec:faq:what-is-instant-component-blocking class=anchor aria-hidden=true></a></h3><p>When you block a component in the <a href=#sec:app-details-page>App\nDetails page</a>, the blocking is not applied by default. It is only\napplied when you apply blocking using the <em>Apply rules</em> option in\nthe top-right menu. If you enable <a href=#subsubsec:instant-component-blocking>instant component\nblocking</a>, blocking will be applied as soon as you block a component.\nIf you choose to block tracker components, however, blocking is applied\nautomatically regardless of this setting. You can also remove blocking\nfor an application by simply clicking on <em>Remove rules</em> in the\nsame menu in the <strong>App Details page</strong>. Since the default\nbehaviour gives you more control over applications, it is better to keep\n<em>instant component blocking</em> option disabled.</section><section id=subsec:tracker-classes-versus-tracker-components class=level3 data-number=4.1.6><h3 data-number=4.1.6><span class=header-section-number>4.1.6</span>\n<a href=#toc:subsec:tracker-classes-versus-tracker-components>Tracker\nclasses versus tracker components</a><a href=#subsec:tracker-classes-versus-tracker-components class=anchor aria-hidden=true></a></h3><p>All application components are classes but not all classes are\ncomponents. In fact, only a few of the classes are components. That\nbeing said, <a href=#sec:scanner-page>scanner page</a> displays a list\nof trackers along with the number of classes, not just the components.\nIn all other pages, trackers and tracker components are used\nsynonymously to denote tracker components, i.e. blocking tracker means\nblocking tracker components, not tracker classes.<div class=\"amalert tip\"><p><strong><em>Info.</em></strong><p>Tracker classes that are not components cannot be blocked. They can\nonly be removed by editing the application itself.</div></section></section><section id=sec:faq:adb-over-tcp class=level2 data-number=4.2><h2 data-number=4.2><span class=header-section-number>4.2</span> <a href=#toc:sec:faq:adb-over-tcp>ADB over TCP</a><a href=#sec:faq:adb-over-tcp class=anchor aria-hidden=true></a></h2><section id=subsec:faq:enable-adb-on-every-restart class=level3 data-number=4.2.1><h3 data-number=4.2.1><span class=header-section-number>4.2.1</span>\n<a href=#toc:subsec:faq:enable-adb-on-every-restart>Do I have to\nenable ADB over TCP everytime I restart?</a><a href=#subsec:faq:enable-adb-on-every-restart class=anchor aria-hidden=true></a></h3><p>Unfortunately, yes. This is because the ADB daemon, the process\nresponsible for ADB connection, is also restarted after a reboot, and it\ndoes not re-enable ADB over TCP.</section><section id=subsec:faq:usb-debugging class=level3 data-number=4.2.2><h3 data-number=4.2.2><span class=header-section-number>4.2.2</span>\n<a href=#toc:subsec:faq:usb-debugging>Cannot enable USB debugging.\nWhat to do?</a><a href=#subsec:faq:usb-debugging class=anchor aria-hidden=true></a></h3><p>See §<a href=#subsec:enable-usb-debugging data-reference-type=ref data-reference=subsec:enable-usb-debugging>3.1.2</a> in Chapter <a href=#ch:guides data-reference-type=ref data-reference=ch:guides>3</a>.</section><section id=subsec:faq:block-components-using-adb class=level3 data-number=4.2.3><h3 data-number=4.2.3><span class=header-section-number>4.2.3</span>\n<a href=#toc:subsec:faq:block-components-using-adb>Can I block tracker\nor any other application components using ADB over TCP?</a><a href=#subsec:faq:block-components-using-adb class=anchor aria-hidden=true></a></h3><p>ADB has limited number of <a href=https://github.com/aosp-mirror/platform_frameworks_base/blob/master/packages/Shell/AndroidManifest.xml>permissions</a>\nand controlling application components is not one of them. However, the\ncomponents of a <em>test-only</em> app can be controlled via ADB. If App\nManager detects such an application, it enables the blocking options\nautomatically.</section><section id=subsec:faq:adb-features class=level3 data-number=4.2.4><h3 data-number=4.2.4><span class=header-section-number>4.2.4</span>\n<a href=#toc:subsec:faq:adb-features>Which features can be used in ADB\nmode?</a><a href=#subsec:faq:adb-features class=anchor aria-hidden=true></a></h3><p>Supported features are enabled automatically in the ADB mode.\nSupported features include disabling, force-stopping, clearing\napplication data, granting or revoking app ops and permissions, and so\non. It is also possible to install or uninstall applications without any\nprompt from the system.</section></section><section id=sec:faq:miscellanea class=level2 data-number=4.3><h2 data-number=4.3><span class=header-section-number>4.3</span> <a href=#toc:sec:faq:miscellanea>Miscellanea</a><a href=#sec:faq:miscellanea class=anchor aria-hidden=true></a></h2><section id=subsec:faq:no-root-no-harms class=level3 data-number=4.3.1><h3 data-number=4.3.1><span class=header-section-number>4.3.1</span>\n<a href=#toc:subsec:faq:no-root-no-harms>I don’t use root/ADB. Am I\ncompletely safe from any harms?</a><a href=#subsec:faq:no-root-no-harms class=anchor aria-hidden=true></a></h3><p>Yes. AM cannot modify any system settings without root or ADB.</section><section id=subsec:faq:how-trackers-libs-updated class=level3 data-number=4.3.2><h3 data-number=4.3.2><span class=header-section-number>4.3.2</span>\n<a href=#toc:subsec:faq:how-trackers-libs-updated>How are the trackers\nand libraries are updated?</a><a href=#subsec:faq:how-trackers-libs-updated class=anchor aria-hidden=true></a></h3><p>Trackers and libraries are updated manually before making a new\nrelease.</section><section id=subsec:faq:apks-deleted-after-installed class=level3 data-number=4.3.3><h3 data-number=4.3.3><span class=header-section-number>4.3.3</span>\n<a href=#toc:subsec:faq:apks-deleted-after-installed>Are APKs deleted\nafter installed?</a><a href=#subsec:faq:apks-deleted-after-installed class=anchor aria-hidden=true></a></h3><p>No, APKs aren’t deleted by App Manager after they are installed.</section><section id=subsec:faq:shizuku-support class=level3 data-number=4.3.4><h3 data-number=4.3.4><span class=header-section-number>4.3.4</span>\n<a href=#toc:subsec:faq:shizuku-support>Any plans for Shizuku?</a><a href=#subsec:faq:shizuku-support class=anchor aria-hidden=true></a></h3><p>App Manager’s use of hidden API and privileged code execution is now\nmuch more complex and cannot be integrated with other third party apps\nsuch as <a href=https://shizuku.rikka.app>Shizuku</a>. Here are some\nreasons for not considering Shizuku (which now has Apache 2.0 license)\nfor App Manager:<ol class=incremental><li><p>Shizuku was initially non-free which led me to use a similar\napproach for App Manager to support both root and ADB<li><p>App Manager already supports both ADB and root which in some\ncases is more capable than Shizuku<li><p>Relying on a third-party app for the major functionalities is not\na good design choice<li><p>Integration of Shizuku will increase the complexity of App\nManager.</ol></section><section id=subsec:faq:what-are-bloatware class=level3 data-number=4.3.5><h3 data-number=4.3.5><span class=header-section-number>4.3.5</span>\n<a href=#toc:subsec:faq:what-are-bloatware>What are bloatware and how\nto remove them?</a><a href=#subsec:faq:what-are-bloatware class=anchor aria-hidden=true></a></h3><p>Bloatware are the unnecessary pre-installed apps, usually system\napps. Some of the apps are often used to track users and collect user\ndata which they might sell for profits. Many system apps do not need to\nrequest any permission to access device info, contacts and messaging\ndata, and other usage info, such as your phone usage habits and\neverything you store on your shared storage(s).<p>The bloatware may also include Google apps, Meta apps, and Twitter/X\nwhich can also track users and/or collect user data without consent. You\ncan disable a few permissions from Android settings but be aware that\nAndroid settings hides many permissions a security researcher would call\npotentially <em>dangerous</em> (e.g., internet, sensor).<p>Were the bloatware user apps, they could be easily uninstalled either\nfrom Android settings or AM. Uninstalling system apps is not possible\nwithout privileged permission, but even then, it cannot <em>remove</em>\nthe system apps completely as they are located in the <em>system</em>\npartition which is a read-only partition. If you have root, you can\nremount this partition to manually <em>purge</em> these apps but this\nwill break Over the Air (OTA) updates since data in the system partition\nhas been modified. There are two kind of updates, delta (small-size,\nconsisting of only the changes between two versions) and full updates.\nYou may still be able to apply full updates, but the bloatware will be\ninstalled again, and consequently, you have to delete them all over\nagain.<p>Another solution is to disable these apps either from Android\nsettings or AM, but certain services can still run in the background as\nthey can be started by other system apps using Inter-process\nCommunication (IPC). One possible solution is to disable all bloatware\nuntil the service has finally stopped (after a restart). However, due to\nheavy modifications of the Android frameworks by the vendors, removing\nor disabling certain bloatware may cause the System UI to crash or even\ncause bootloop. From v4.0.0, AM has a new feature called\n<strong>Debloater</strong> which can be used as a starting point to\nmonitor, disable, and remove the bloatware from a proprietary Android\noperating system.<div class=\"amalert warning\"><p><strong><em>Note.</em></strong><p>In most cases, you cannot completely debloat your device. Therefore,\nit is recommended that you use a custom ROM free from bloatware, such as\nGraphene OS, Lineage OS or their derivatives.</div></section></section></section><section id=ch:specifications class=level1 data-number=5><h1 data-number=5><span class=header-section-number>5</span> <a href=#toc:ch:specifications>Specifications</a><a href=#ch:specifications class=anchor aria-hidden=true></a></h1><section id=sec:rules-specification class=level2 data-number=5.1><h2 data-number=5.1><span class=header-section-number>5.1</span> <a href=#toc:sec:rules-specification>Rules Specification</a><a href=#sec:rules-specification class=anchor aria-hidden=true></a></h2><section id=background class=level3 data-number=5.1.1><h3 data-number=5.1.1><span class=header-section-number>5.1.1</span>\n<a href=#toc:background>Background</a><a href=#background class=anchor aria-hidden=true></a></h3><p>AM currently supports blocking activities, broadcast receivers,\ncontent providers, services, app ops and permissions, and in future I\nmay add more blocking options. In order to add more portability, it is\nnecessary to import/export all these data.<p>Maintaining a database should be the best choice when it comes to\nstoring data. For now, several <code>tsv</code> files with each file\nhaving the name of the package and a <code>.tsv</code> extension. The\nfile/database will be queried/processed by the\n<code>RulesStorageManager</code> class. Due to this abstraction, it\nshould be easier to switch to database or encrypted database systems in\nfuture without changing the design of the entire project. Currently, All\nconfiguration files are stored at\n<code>/data/data/io.github.muntashirakon.AppManager/Files/conf</code>.</section><section id=rules-file-format class=level3 data-number=5.1.2><h3 data-number=5.1.2><span class=header-section-number>5.1.2</span>\n<a href=#toc:rules-file-format>Rules File Format</a><a href=#rules-file-format class=anchor aria-hidden=true></a></h3><section id=internal class=level4 data-number=5.1.2.1><h4 data-number=5.1.2.1><span class=header-section-number>5.1.2.1</span> Internal<a href=#internal class=anchor aria-hidden=true></a></h4><p>The format below is used internally within App Manager and is <em>not\ncompatible with the external format.</em><pre><code>    &lt;name&gt; &lt;type&gt; &lt;mode&gt;|&lt;component_status&gt;|&lt;is_granted&gt;</code></pre><p>Here:<ul class=incremental><li><p><code>&lt;name></code> – Component/permission/app op name (in\ncase of app op, it could be string or integer)<li><p><code>&lt;type></code> – One of the <code>ACTIVITY</code>,\n<code>RECEIVER</code>, <code>PROVIDER</code>, <code>SERVICE</code>,\n<code>APP_OP</code>, <code>PERMISSION</code><li><p><code>&lt;mode></code> – (For app ops) The associated <a href=#subsec:mode-constants>mode constant</a><li><p><code>&lt;component_status></code> – (For components)\nComponent status<ul class=incremental><li><p><code>true</code> – Component has been applied (<code>true</code>\nvalue is kept for compatibility)<li><p><code>false</code> – Component hasn’t been applied yet, but will\nbe applied in future (<code>false</code> value is kept for\ncompatibility)<li><p><code>unblocked</code> – Component is scheduled to be\nunblocked</ul><li><p><code>&lt;is_granted></code> – (For permissions) Whether the\npermission is granted or revoked</ul></section><section id=external class=level4 data-number=5.1.2.2><h4 data-number=5.1.2.2><span class=header-section-number>5.1.2.2</span> External<a href=#external class=anchor aria-hidden=true></a></h4><p>External format is used for importing or exporting rules in App\nManager.<pre><code>    &lt;package_name&gt; &lt;component_name&gt; &lt;type&gt; &lt;mode&gt;|&lt;component_status&gt;|&lt;is_granted&gt;</code></pre><p>This the format is essentially the same as above except for the first\nitem which is the name of the package.<div class=\"amalert danger\"><p><strong><em>Caution.</em></strong><p>The exported rules have a different format than the internal one and\nshould not be copied directly to the <strong>conf</strong> folder.</div></section></section></section></section><section id=ch:changelogs class=level1 data-number=6><h1 data-number=6><span class=header-section-number>6</span> <a href=#toc:ch:changelogs>Changelogs</a><a href=#ch:changelogs class=anchor aria-hidden=true></a></h1><section id=sec:v4.0.5-(445) class=level2 data-number=6.1><h2 data-number=6.1><span class=header-section-number>6.1</span> <a href=#toc:sec:v4.0.5-(445)>v4.0.5 (445)</a><a href=#sec:v4.0.5-(445) class=anchor aria-hidden=true></a></h2><ul class=incremental><li><p>Added option to allow installing the existing applications in the\ninstaller page<li><p>Display unsafe bloatware info<li><p>Display vector icon on the splash screen in Android 7.1 and\nearlier<li><p>Enabled “Clear data from uninstalled apps” to no-root users in\n1-click ops page<li><p>Enabled predictive back in Android 14 onwards<li><p>Improved accessibility by updating the content description of the\naction items<li><p>In app info tab, open “Open by default” setting in the “Open\nlinks” dialog<li><p>In debloater page, sort by app label (or app name) rather than\npackage name<li><p>Fixed freezing an app with “Remember for this app” turned\non<li><p>Fixed selecting texts in the list items due to framework\nbugs<li><p>Fixed setting app ops in custom ROMs with MIUI properties\ninjected<li><p>Fixed updating profile modification status when an application is\ndeleted from the list<li><p>Handled common colors and cursor movements in terminal\noutput.</ul></section><section id=sec:v4.0.4-(444) class=level2 data-number=6.2><h2 data-number=6.2><span class=header-section-number>6.2</span> <a href=#toc:sec:v4.0.4-(444)>v4.0.4 (444)</a><a href=#sec:v4.0.4-(444) class=anchor aria-hidden=true></a></h2><ul class=incremental><li><p>Optimized searching and filtering in the main page<li><p>Adopted sentence-case for the titles<li><p>Use the configured state to execute a profile for the simple\nshortcuts<li><p>Prevented crashing while searching throughout the\napplication<li><p>Fixed integer overflow issue in the tar compression.</ul></section><section id=sec:v4.0.3-(443) class=level2 data-number=6.3><h2 data-number=6.3><span class=header-section-number>6.3</span> <a href=#toc:sec:v4.0.3-(443)>v4.0.3 (443)</a><a href=#sec:v4.0.3-(443) class=anchor aria-hidden=true></a></h2><ul class=incremental><li><p>Updated translations<li><p>Improved handling the list items throughout App Manager<li><p>Fixed a regression error in file manager<li><p>Fixed spinners in the App Usage and the System Config\npages.</ul></section><section id=sec:v4.0.2-(442) class=level2 data-number=6.4><h2 data-number=6.4><span class=header-section-number>6.4</span> <a href=#toc:sec:v4.0.2-(442)>v4.0.2 (442)</a><a href=#sec:v4.0.2-(442) class=anchor aria-hidden=true></a></h2><ul class=incremental><li><p>Updated bloatware<li><p>Fixed fetching applications in multi-user environment in no-root\nmode<li><p>Fixed opening <code>app-manager</code> URLs from the web\nbrowsers<li><p>Fixed updating SSAID<li><p>Prevented a crash in Android &lt; 9.0 that occurs due to invalid\napp ops.</ul></section><section id=sec:v4.0.1-(441) class=level2 data-number=6.5><h2 data-number=6.5><span class=header-section-number>6.5</span> <a href=#toc:sec:v4.0.1-(441)>v4.0.1 (441)</a><a href=#sec:v4.0.1-(441) class=anchor aria-hidden=true></a></h2><section id=overlay-management class=level3 data-number=6.5.1><h3 data-number=6.5.1><span class=header-section-number>6.5.1</span>\n<a href=#toc:overlay-management>Overlay management</a><a href=#overlay-management class=anchor aria-hidden=true></a></h3><p>In the App Details page, a new tab “Overlays” is added where per-app\noverlays are displayed. They can also be enabled or disabled using the\ntoggle button. In addition, if the App Details page of an overlay\npackage is opened, a “Overlay” tag will be displayed in the App Info\ntab. Clicking on the tag opens a dialog containing additional info along\nwith a button that allows navigating to the App Details page of the\noverlay target package if it is installed.<section id=known-limitation class=level5 data-number=6.5.1.0.1><h5 data-number=6.5.1.0.1><span class=header-section-number>6.5.1.0.1</span> Known limitation<a href=#known-limitation class=anchor aria-hidden=true></a></h5><p>At present, it only works for root/ADB users in Android 8 (Oreo) and\nlater.</section></section><section id=unfreeze-option-in-activity-shortcuts class=level3 data-number=6.5.2><h3 data-number=6.5.2><span class=header-section-number>6.5.2</span>\n<a href=#toc:unfreeze-option-in-activity-shortcuts>Unfreeze option in\nactivity shortcuts</a><a href=#unfreeze-option-in-activity-shortcuts class=anchor aria-hidden=true></a></h3><p>If the application corresponding to the shortcut being launched is\nfrozen, App Manager will now offer you to unfreeze the app temporarily\nso that the shortcut can be launched. The app will be frozen again once\nthe screen is locked.<section id=known-limitation-1 class=level5 data-number=6.5.2.0.1><h5 data-number=6.5.2.0.1><span class=header-section-number>6.5.2.0.1</span> Known limitation<a href=#known-limitation-1 class=anchor aria-hidden=true></a></h5><p>This may not work on devices without a screen lock or if the screen\nis locked some time after the display goes off.</section></section><section id=market-like-url-support class=level3 data-number=6.5.3><h3 data-number=6.5.3><span class=header-section-number>6.5.3</span>\n<a href=#toc:market-like-url-support><code>market</code>-like URL\nsupport</a><a href=#market-like-url-support class=anchor aria-hidden=true></a></h3><p>Third-party applications can now open the App Details page of any\ninstalled package by invoking an Intent with an URL with the following\nformat:<pre><code>app-manager://details?id=&lt;pkg&gt;&amp;user=&lt;user_id&gt;</code></pre><p>where <code>&lt;pkg></code> stands for package name, and\n<code>&lt;user_id></code> stands for the user ID which is\noptional.</section><section id=updated-color-codes class=level3 data-number=6.5.4><h3 data-number=6.5.4><span class=header-section-number>6.5.4</span>\n<a href=#toc:updated-color-codes>Updated color codes</a><a href=#updated-color-codes class=anchor aria-hidden=true></a></h3><p>In order to improve accessibility, certain color codes have been\nimproved. Visit <a href=app-manager://settings/about/version>Settings\n> About > Version/Changelog</a> for details.</section><section id=others class=level3 data-number=6.5.5><h3 data-number=6.5.5><span class=header-section-number>6.5.5</span>\n<a href=#toc:others>Others</a><a href=#others class=anchor aria-hidden=true></a></h3><ul class=incremental><li><p>Avoided waiting for the remote server to respond when no-root\nmode is set<li><p>Fixed downgrading apps in Android 10 onwards<li><p>Fixed installer issues in the Huawei stock operating\nsystems<li><p>Improved text formatting in the “What’s New” dialog<li><p>In the UI tracker window, fixed clicking on the icon after it is\niconified<li><p>Updated bloatware and suggestions</ul></section></section><section id=sec:v4.0.0-(440) class=level2 data-number=6.6><h2 data-number=6.6><span class=header-section-number>6.6</span> <a href=#toc:sec:v4.0.0-(440)>v4.0.0 (440)</a><a href=#sec:v4.0.0-(440) class=anchor aria-hidden=true></a></h2><p>App Manager v4.0.0 comes with a lot of new features and improvements.\nVisit <a href=app-manager://settings/about/version>Settings > About\n> Version/Changelog</a> for details.<section id=new-logo class=level3 data-number=6.6.1><h3 data-number=6.6.1><span class=header-section-number>6.6.1</span>\n<a href=#toc:new-logo>New logo!</a><a href=#new-logo class=anchor aria-hidden=true></a></h3><p>The new logo is just a cursive “A”. The design is based on the <a href=https://freetengwar.sourceforge.net/>Tengwar Telcontar</a> font\nwhich was created to bring the Tengwar script, originally created by J.\nR. R. Tolkien, to the digital world. The letter has the classic App\nManager color (i.e., #dcaf74) and uses a pure black background instead\nof a shade of grey.</section><section id=android-14-and-15-support class=level3 data-number=6.6.2><h3 data-number=6.6.2><span class=header-section-number>6.6.2</span>\n<a href=#toc:android-14-and-15-support>Android 14 and 15 support</a><a href=#android-14-and-15-support class=anchor aria-hidden=true></a></h3><p>App Manager now targets Android 14 and fully supports Android 15.<section id=known-issue class=level5 data-number=6.6.2.0.1><h5 data-number=6.6.2.0.1><span class=header-section-number>6.6.2.0.1</span> Known issue<a href=#known-issue class=anchor aria-hidden=true></a></h5><p>KeyStore backup/restore is not working in Android 12 and later.</section></section><section id=revamped-debloater class=level3 data-number=6.6.3><h3 data-number=6.6.3><span class=header-section-number>6.6.3</span>\n<a href=#toc:revamped-debloater>Revamped debloater</a><a href=#revamped-debloater class=anchor aria-hidden=true></a></h3><p>Debloating profiles were available as “Presets” in the Profiles page\nwhich has now been replaced with the Debloater page and can be accessed\nfrom the three-dots menu in the Main page. <a href=https://github.com/MuntashirAkon/android-debloat-list>ADL</a> is\na new project that focuses on maintaining a list of bloatware as well as\npotential open source alternatives. Contributions are welcome!</section><section id=introducing-file-manager class=level3 data-number=6.6.4><h3 data-number=6.6.4><span class=header-section-number>6.6.4</span>\n<a href=#toc:introducing-file-manager>Introducing file manager</a><a href=#introducing-file-manager class=anchor aria-hidden=true></a></h3><p>App Manager offers an (almost) fully-featured file manager with basic\nfile operations, such as copy, cut, rename, and delete along with the\nbatch operations. It also offers an extensive “Open with…” dialog to\nopen a file with another app, and a comprehensive file properties\nviewer. Folders can also be added to the list of favorites for quick\naccess. And many more.</section><section id=integrated-code-editor class=level3 data-number=6.6.5><h3 data-number=6.6.5><span class=header-section-number>6.6.5</span>\n<a href=#toc:integrated-code-editor>Integrated code editor</a><a href=#integrated-code-editor class=anchor aria-hidden=true></a></h3><p>Manifest and code viewers have been replaced with this new editor.\nAmong other regular features, it includes proper syntax highlighting and\nadvanced searching options. In addition, files from third-party apps can\nalso be opened for editing.</section><section id=history-of-operations class=level3 data-number=6.6.6><h3 data-number=6.6.6><span class=header-section-number>6.6.6</span>\n<a href=#toc:history-of-operations>History of operations</a><a href=#history-of-operations class=anchor aria-hidden=true></a></h3><p>All 1-click operations, batch operations, and profile invocations are\nnow stored as history. The history items can also be executed from the\nHistory page. To ensure consistency, the profile state, configurations,\npackage list are also stored, and this stored version is executed\ninstead of the actual profile. As a result, this works even if the\nprofile is deleted.</section><section id=per-app-freezing-and-more class=level3 data-number=6.6.7><h3 data-number=6.6.7><span class=header-section-number>6.6.7</span>\n<a href=#toc:per-app-freezing-and-more>Per-app freezing, and\nmore</a><a href=#per-app-freezing-and-more class=anchor aria-hidden=true></a></h3><p>Freeze/unfreeze feature now supports setting per-app freezing method\nwhich is beneficial in certain scenarios, such as when a user want to\nsuspend some apps while using the disable method as the default. In\naddition, an “Advanced suspend” option is added which force-stops an\napplication before suspending it, thus, prevent it’s services from\nrunning in the background.</section><section id=log-viewer-enhancements class=level3 data-number=6.6.8><h3 data-number=6.6.8><span class=header-section-number>6.6.8</span>\n<a href=#toc:log-viewer-enhancements>Log viewer enhancements</a><a href=#log-viewer-enhancements class=anchor aria-hidden=true></a></h3><p>Log viewer now supports enhanced searching and filtering options,\nsuch as keyword- and regular expression-based searching and filtering.\nPlease read the in-app changelog for details. Support for batch\noperations has also been added.</section><section id=launching-non-exported-activities class=level3 data-number=6.6.9><h3 data-number=6.6.9><span class=header-section-number>6.6.9</span>\n<a href=#toc:launching-non-exported-activities>Launching non-exported\nactivities</a><a href=#launching-non-exported-activities class=anchor aria-hidden=true></a></h3><p>App Manager now supports launching non-exported activities in no-root\nand ADB mode. However, in no-root mode,\n<code>android.permission.WRITE_SECURE_SETTINGS</code> permission is\nrequired.</section><section id=new-tags-in-app-info-tab class=level3 data-number=6.6.10><h3 data-number=6.6.10><span class=header-section-number>6.6.10</span> <a href=#toc:new-tags-in-app-info-tab>New tags in App Info tab</a><a href=#new-tags-in-app-info-tab class=anchor aria-hidden=true></a></h3><p>Five new tags are added in the App Info tab. They are: bloatware,\nXposed, sensors disabled, open links, and static shared libs. Clicking\non “bloatware” will display more information regarding the bloatware and\nsuggest alternatives, “Xposed” tag will display dependency information,\n“open links” will display a list of links supported by the application,\nand “static shared libs” will display all version of the application\ninstalled in the system along with an option to uninstall them. The\nlatter is useful for applications, such as Trichrome.<section id=known-issue-1 class=level5 data-number=6.6.10.0.1><h5 data-number=6.6.10.0.1><span class=header-section-number>6.6.10.0.1</span> Known issue<a href=#known-issue-1 class=anchor aria-hidden=true></a></h5><p>“Sensors disabled” only works real-time. That means if the\napplication is not currently active, this tag will always display even\nthough the applications may use sensors while it is running. This is a\nframework limitation and nothing can be done to avoid it\neffectively.</section></section><section id=per-session-installer-options class=level3 data-number=6.6.11><h3 data-number=6.6.11><span class=header-section-number>6.6.11</span> <a href=#toc:per-session-installer-options>Per-session installer\noptions</a><a href=#per-session-installer-options class=anchor aria-hidden=true></a></h3><p>It is not possible to modify installer options during the\ninstallation by clicking on the “settings” button in the installation\ndialog. The installer options will be applied to all the applications\ninstalled in the same session (i.e., the installer queue).</section><section id=advanced-mode-of-operations-adb-enhancements class=level3 data-number=6.6.12><h3 data-number=6.6.12><span class=header-section-number>6.6.12</span> <a href=#toc:advanced-mode-of-operations-adb-enhancements>Advanced mode\nof operations, ADB enhancements, …</a><a href=#advanced-mode-of-operations-adb-enhancements class=anchor aria-hidden=true></a></h3><p>App Manager now supports running its remote server (which is used as\na proxy for running privileged operations) as any supported user (UID).\nThis includes root (0), system (1000), and shell/ADB (2000) through the\ncustom commands. This is also useful for Fire TVs which have disabled\nconnecting to ADB from localhost through socket connection. In addition,\nADB pairing is now done using notifications rather than split screen.\nADB connection speed can also be improved by choosing to run App Manager\nin the background which can be configured in the settings.</section><section id=data-usage-widget-and-more class=level3 data-number=6.6.13><h3 data-number=6.6.13><span class=header-section-number>6.6.13</span> <a href=#toc:data-usage-widget-and-more>Data usage widget, and more</a><a href=#data-usage-widget-and-more class=anchor aria-hidden=true></a></h3><p>Data usage widget display the total data usage for the day, similar\nto the screen time widget which displays the total screen time for the\nday. In addition, existing widgets have been improved.</section><section id=others-1 class=level3 data-number=6.6.14><h3 data-number=6.6.14><span class=header-section-number>6.6.14</span> <a href=#toc:others-1>Others</a><a href=#others-1 class=anchor aria-hidden=true></a></h3><ul class=incremental><li><p>Replaced log viewer, sys config, Terminal, etc. with Labs\npage<li><p>Added an option to disable sensors for each app in the App Info\ntab<li><p>Added an option to perform runtime optimization of applications\nin the 1-click Ops page and in the App Info tab<li><p>Added support for Zstandard compression for\nbackup/restore<li><p>Enabling APK signing now automatically enables zip align\nfeature<li><p>Support exporting application list as CSV or JSON in the batch\noperations<li><p>Added pure black theme support<li><p>Display current activity name (when possible) in the UI Tracker\nwindow<li><p>Added an option to filter apps by user in the Main page<li><p>Display a link to Pithus report in the scanner page if\navailable.</ul></section></section><section id=sec:v3.1.0-(423) class=level2 data-number=6.7><h2 data-number=6.7><span class=header-section-number>6.7</span> <a href=#toc:sec:v3.1.0-(423)>v3.1.0 (423)</a><a href=#sec:v3.1.0-(423) class=anchor aria-hidden=true></a></h2><p>App Manager v3.1.0 comes with a few new features and a lot of\nimprovements. Visit <a href=app-manager://settings/about/version>Settings > About >\nVersion/Changelog</a> for details.<section id=android-13-support class=level3 data-number=6.7.1><h3 data-number=6.7.1><span class=header-section-number>6.7.1</span>\n<a href=#toc:android-13-support>Android 13 support</a><a href=#android-13-support class=anchor aria-hidden=true></a></h3><p>App Manager now targets Android 13 which means most issues in Android\n12 and 13 has been addressed, including SSAID and SAF issues as well as\nmonochrome icons and other theming issues.<section id=known-issue-2 class=level5 data-number=6.7.1.0.1><h5 data-number=6.7.1.0.1><span class=header-section-number>6.7.1.0.1</span> Known issue<a href=#known-issue-2 class=anchor aria-hidden=true></a></h5><p>KeyStore backup/restore not working in Android 12 and later.</section></section><section id=introducing-freezeunfreeze class=level3 data-number=6.7.2><h3 data-number=6.7.2><span class=header-section-number>6.7.2</span>\n<a href=#toc:introducing-freezeunfreeze>Introducing\nfreeze/unfreeze</a><a href=#introducing-freezeunfreeze class=anchor aria-hidden=true></a></h3><p>Enable/disable is replaced with freeze/unfreeze to allow greater\ncontrol on the behaviours of an app. It supports suspend, disable and\nhide functionalities which can be controlled at <a href=app-manager://settings/rules_prefs/freeze_type>Settings >\nRules > Default freezing method</a>. In order to make it easy to\nfreeze or unfreeze an app, shortcuts can also be created from the App\nInfo tab by long clicking on the freeze or unfreeze button.</section><section id=export-app-list class=level3 data-number=6.7.3><h3 data-number=6.7.3><span class=header-section-number>6.7.3</span>\n<a href=#toc:export-app-list>Export app list</a><a href=#export-app-list class=anchor aria-hidden=true></a></h3><p>In the Main page, it is now possible to export the list of apps in\neither XML or Markdown format using batch operations. In the future, the\nXML file may also be imported to App Manager.</section><section id=elliptic-curve-crypography-ecc class=level3 data-number=6.7.4><h3 data-number=6.7.4><span class=header-section-number>6.7.4</span>\n<a href=#toc:elliptic-curve-crypography-ecc>Elliptic Curve Crypography\n(ECC)</a><a href=#elliptic-curve-crypography-ecc class=anchor aria-hidden=true></a></h3><p>App Manager now fully supports encrypting backups using ECC in\naddition to offering AES, RSA and OpenPGP.</section><section id=new-languages class=level3 data-number=6.7.5><h3 data-number=6.7.5><span class=header-section-number>6.7.5</span>\n<a href=#toc:new-languages>New languages</a><a href=#new-languages class=anchor aria-hidden=true></a></h3><p>Two new languages are added: Korean and Romanian.</section><section id=more-list-options class=level3 data-number=6.7.6><h3 data-number=6.7.6><span class=header-section-number>6.7.6</span>\n<a href=#toc:more-list-options>More list options</a><a href=#more-list-options class=anchor aria-hidden=true></a></h3><p>In the main page, more sorting and filtering options are added.\nSorting options include sorting the apps by total size, total data\nusage, launch count, screen time and last usage time. Filtering options\ninclude filtering the apps having at least one item in the Android\nKeyStore, filtering apps with URIs granted via SAF, and filtering apps\nwith SSAID.</section><section id=improved-handling-of-mode-of-operation class=level3 data-number=6.7.7><h3 data-number=6.7.7><span class=header-section-number>6.7.7</span>\n<a href=#toc:improved-handling-of-mode-of-operation>Improved handling\nof mode of operation</a><a href=#improved-handling-of-mode-of-operation class=anchor aria-hidden=true></a></h3><p>Fixed various issues with ADB pairing, handled incomplete USB\ndebugging. Some rooting methods cannot allow interprocess communication\nvia Binder. In those cases, ADB mode is used as a fallback method by\nenabling it automatically if possible.</section><section id=handling-multiple-users class=level3 data-number=6.7.8><h3 data-number=6.7.8><span class=header-section-number>6.7.8</span>\n<a href=#toc:handling-multiple-users>Handling multiple users</a><a href=#handling-multiple-users class=anchor aria-hidden=true></a></h3><p>When possible, App Manager will be able to display apps from work\nprofile in no-root mode in addition to allowing basic operations such as\nlaunching the app or navigating to the system settings. For backups, it\nis now possible to restore backups for other users, but for work\nprofile, some apps may only work properly after re-enabling the work\nprofile. In the installer page, selecting <em>All users</em> will now\ninstall the app for all users instead of only the current user. Finally,\nin the app info tab, current app can be installed in another profile\nusing the <em>Install for…</em> option available in the three-dots menu.\nThis is analogous to the <code>pm install-existing</code> command,\nthereby, making the installation process a lot faster.</section><section id=explorer-enhancements class=level3 data-number=6.7.9><h3 data-number=6.7.9><span class=header-section-number>6.7.9</span>\n<a href=#toc:explorer-enhancements>Explorer enhancements</a><a href=#explorer-enhancements class=anchor aria-hidden=true></a></h3><p>Explorer can now open DEX and JAR files in addition to APK files.\nSeveral sorting options as well as folder options are also added as the\nlist options.</section><section id=new-tag-wx class=level3 data-number=6.7.10><h3 data-number=6.7.10><span class=header-section-number>6.7.10</span> <a href=#toc:new-tag-wx>New tag: WX</a><a href=#new-tag-wx class=anchor aria-hidden=true></a></h3><p>In app info tab, a new tag called WX is added. It is displayed in\nAndroid 10 and later if the application targets Android 9 or earlier. It\nindicates <a href=https://en.wikipedia.org/wiki/W%5EX>W^X</a>\nviolation which allows the app to execute arbitrary executable files\neither by the modification of executables embedded within the app or by\ndownloading them from the Internet.</section><section id=app-ops-management class=level3 data-number=6.7.11><h3 data-number=6.7.11><span class=header-section-number>6.7.11</span> <a href=#toc:app-ops-management>App ops management</a><a href=#app-ops-management class=anchor aria-hidden=true></a></h3><p>App ops are now managed automatically to avoid various app ops\nrelated crashes in various platforms. This will also lessen the amount\nof crashes in an unsupported operating system.</section><section id=batch-uninstallation class=level3 data-number=6.7.12><h3 data-number=6.7.12><span class=header-section-number>6.7.12</span> <a href=#toc:batch-uninstallation>Batch uninstallation</a><a href=#batch-uninstallation class=anchor aria-hidden=true></a></h3><p>In the Main page, enabled batch uninstallation in no-root mode.</section><section id=running-apps class=level3 data-number=6.7.13><h3 data-number=6.7.13><span class=header-section-number>6.7.13</span> <a href=#toc:running-apps>Running apps</a><a href=#running-apps class=anchor aria-hidden=true></a></h3><p>Enabled advanced searching. Searching now matches not only app labels\nbut also package names.</section><section id=interceptor class=level3 data-number=6.7.14><h3 data-number=6.7.14><span class=header-section-number>6.7.14</span> <a href=#toc:interceptor>Interceptor</a><a href=#interceptor class=anchor aria-hidden=true></a></h3><p>Copy the intercepted Intent as am command which can be run from\neither an ADB shell or a terminal using root with the same\neffectiveness.</section><section id=device-specific-changes class=level3 data-number=6.7.15><h3 data-number=6.7.15><span class=header-section-number>6.7.15</span> <a href=#toc:device-specific-changes>Device-specific changes</a><a href=#device-specific-changes class=anchor aria-hidden=true></a></h3><section id=graphene-os class=level5 data-number=6.7.15.0.1><h5 data-number=6.7.15.0.1><span class=header-section-number>6.7.15.0.1</span> Graphene OS<a href=#graphene-os class=anchor aria-hidden=true></a></h5><p>Explicitly handle the Internet permission which is a runtime\npermission in the OS.</section><section id=miui class=level5 data-number=6.7.15.0.2><h5 data-number=6.7.15.0.2><span class=header-section-number>6.7.15.0.2</span> MIUI<a href=#miui class=anchor aria-hidden=true></a></h5><p>Fixed permission denied issues in the installer due to a framework\nissue introduced in MIUI 12.5.</section><section id=motorola class=level5 data-number=6.7.15.0.3><h5 data-number=6.7.15.0.3><span class=header-section-number>6.7.15.0.3</span> Motorola<a href=#motorola class=anchor aria-hidden=true></a></h5><p>Fixed crashes in the Interceptor page due to a framework issue\nintroduced in Android 11.</section></section><section id=others-2 class=level3 data-number=6.7.16><h3 data-number=6.7.16><span class=header-section-number>6.7.16</span> <a href=#toc:others-2>Others</a><a href=#others-2 class=anchor aria-hidden=true></a></h3><ul class=incremental><li><p>Improved Java-Smali conversion by including all the subclasses\nduring conversion<li><p>Improved scanning performance in the Scanner page<li><p>Improved updating the list of apps in the Main page<li><p>Scan all the available paths to detect systemless-ly installed\nsystem apps<li><p><code>vacuum</code> SQLite database before opening it for viewing\nor editing.</ul></section></section><section id=sec:v3.0.0-(410) class=level2 data-number=6.8><h2 data-number=6.8><span class=header-section-number>6.8</span> <a href=#toc:sec:v3.0.0-(410)>v3.0.0 (410)</a><a href=#sec:v3.0.0-(410) class=anchor aria-hidden=true></a></h2><p>App Manager v3.0.0 comes with a lot of features and improvements. See\n<a href=app-manager://settings/about/version>Settings > About >\nVersion/Changelog</a> to see a more detailed changelog.<section id=material-3-and-more class=level3 data-number=6.8.1><h3 data-number=6.8.1><span class=header-section-number>6.8.1</span>\n<a href=#toc:material-3-and-more>Material 3 and More</a><a href=#material-3-and-more class=anchor aria-hidden=true></a></h3><p>Material 3, somewhat similar to <em>Material You</em>, is a\nsignificant improvement over Material Design 2 with support for dynamic\ncolours in Android 12 and later. In addition, many design changes have\nbeen made in App Manager without any significant changes in the overall\nuser experience.<section id=known-issue-3 class=level5 data-number=6.8.1.0.1><h5 data-number=6.8.1.0.1><span class=header-section-number>6.8.1.0.1</span> Known issue<a href=#known-issue-3 class=anchor aria-hidden=true></a></h5><p>Switches are still based on Material Design 2 which will be fixed in\na future release.</section></section><section id=wireless-debugging class=level3 data-number=6.8.2><h3 data-number=6.8.2><span class=header-section-number>6.8.2</span>\n<a href=#toc:wireless-debugging>Wireless Debugging</a><a href=#wireless-debugging class=anchor aria-hidden=true></a></h3><p>Wireless debugging support has been fully implemented. Head over to\n§<a href=#sec:wireless-debugging data-reference-type=ref data-reference=sec:wireless-debugging>3.2</a> for instructions on how\nto configure wireless debugging.<div class=\"amalert tip\"><p><strong><em>No-root users.</em></strong><p>Due to auto-detection feature, startup time might be large for\nno-root users when the mode of operation is set to <em>auto</em>.\nInstead, no-root users should select <em>no-root</em> instead of\n<em>auto</em>.</div></section><section id=languages class=level3 data-number=6.8.3><h3 data-number=6.8.3><span class=header-section-number>6.8.3</span>\n<a href=#toc:languages>Languages</a><a href=#languages class=anchor aria-hidden=true></a></h3><p>App Manager is fully translated into Indonesian and Italian languages\nand can be enabled in settings. Bengali is removed due to lack of\ntranslators.</section><section id=introducing-app-explorer class=level3 data-number=6.8.4><h3 data-number=6.8.4><span class=header-section-number>6.8.4</span>\n<a href=#toc:introducing-app-explorer>Introducing App Explorer</a><a href=#introducing-app-explorer class=anchor aria-hidden=true></a></h3><p>App Explorer can be used to browse the contents of an application.\nThis includes binary XML files, DEX contents or any other media files.\nDEX contents can only be explored in Android Oreo (Android 8) and later.\nIt’s also possible to convert an <code>.smali</code> file into\n<code>.java</code> for a better understanding of the reversed code. This\nfeature, if not needed, can be disabled in Settings > Enable/disable\nfeatures.</section><section id=import-backups-from-other-applications class=level3 data-number=6.8.5><h3 data-number=6.8.5><span class=header-section-number>6.8.5</span>\n<a href=#toc:import-backups-from-other-applications>Import Backups\nfrom Other Applications</a><a href=#import-backups-from-other-applications class=anchor aria-hidden=true></a></h3><p>It is possible to import backups from discontinued or obsolete\napplications such as Titanium Backup, OAndBackup and Swift Backup\n(version 3.0 to 3.2). Go to Setting > Backup/restore to find this\noption.</section><section id=virustotal class=level3 data-number=6.8.6><h3 data-number=6.8.6><span class=header-section-number>6.8.6</span>\n<a href=#toc:virustotal>VirusTotal</a><a href=#virustotal class=anchor aria-hidden=true></a></h3><p>VirusTotal is a widely used tool to scan files and URLs for viruses.\nIn the scanner page and in the running apps page, an option to scan\nfiles with VirusTotal has been added. But the option is hidden by\ndefault. To enable the option, it is necessary to obtain an API key from\nVirusTotal. Go to Settings > VirusTotal API Key for more\ninformation.<div class=\"amalert warning\"><p><strong><em>Internet feature.</em></strong><p>This is currently the only feature which require an Internet\nconnection. If you wish to use any Internet feature that might also be\nadded in the future, enable <em>Use the Internet</em> in Settings >\nEnable/disable features.</div></section><section id=trigger-profiles-from-the-automation-software class=level3 data-number=6.8.7><h3 data-number=6.8.7><span class=header-section-number>6.8.7</span>\n<a href=#toc:trigger-profiles-from-the-automation-software>Trigger\nProfiles from the Automation Software</a><a href=#trigger-profiles-from-the-automation-software class=anchor aria-hidden=true></a></h3><p>As the implementation of routine operations is being delayed, an\noption to trigger profiles from the external automation software is\nadded. See §<a href=#sec:automating-tasks data-reference-type=ref data-reference=sec:automating-tasks>3.4</a> for instructions on how to\nconfigure profile automation.</section><section id=improved-application-installer class=level3 data-number=6.8.8><h3 data-number=6.8.8><span class=header-section-number>6.8.8</span>\n<a href=#toc:improved-application-installer>Improved Application\nInstaller</a><a href=#improved-application-installer class=anchor aria-hidden=true></a></h3><p>Application installer includes several improvements including the\nability to downgrade applications in no-root mode, installing multiple\napplications at once and blocking trackers after installation. In\nAndroid 12 and later, no-root users can update applications without any\nuser interactions.</section><section id=component-blocking class=level3 data-number=6.8.9><h3 data-number=6.8.9><span class=header-section-number>6.8.9</span>\n<a href=#toc:component-blocking>Component Blocking</a><a href=#component-blocking class=anchor aria-hidden=true></a></h3><p>It is now possible to configure how App Manager should block a\ncomponent. Visit Settings > Rules > Default blocking method for\nmore information. In the components tab, long clicking the block/unblock\nbutton opens a context menu which allows per-component blocking in a\nsimilar manner. ADB users can also block the components of a <em>Test\nonly</em> app.</section><section id=advanced-searching class=level3 data-number=6.8.10><h3 data-number=6.8.10><span class=header-section-number>6.8.10</span> <a href=#toc:advanced-searching>Advanced Searching</a><a href=#advanced-searching class=anchor aria-hidden=true></a></h3><p>In some pages, the search bar supports additional searching which\nincludes searching via prefix, suffix or even regular expressions. In\nthe main page, it is also possible to search for applications using the\nfirst letters of each word, e.g. <em>App Manager</em> can be listed by\nsearching for <em>am</em>.</section><section id=shared-libraries class=level3 data-number=6.8.11><h3 data-number=6.8.11><span class=header-section-number>6.8.11</span> <a href=#toc:shared-libraries>Shared Libraries</a><a href=#shared-libraries class=anchor aria-hidden=true></a></h3><p>Shared libraries tab has received a significant improvements. It can\ndisplay three types of libraries, such as native, jar and APK files.</section><section id=make-the-best-use-of-interceptor class=level3 data-number=6.8.12><h3 data-number=6.8.12><span class=header-section-number>6.8.12</span> <a href=#toc:make-the-best-use-of-interceptor>Make the Best Use of\nInterceptor</a><a href=#make-the-best-use-of-interceptor class=anchor aria-hidden=true></a></h3><p>Activity interceptor can be opened directly from the activities tab\nby long clicking on the launch button, and similarly, activities can be\nlaunched from the activity interceptor page with or without root, for\nany users.<div class=\"amalert tip\"><p><strong><em>Notice.</em></strong><p>Currently, activities opened via root cannot send the results back to\nthe original applications.</div></section><section id=widget-screen-time class=level3 data-number=6.8.13><h3 data-number=6.8.13><span class=header-section-number>6.8.13</span> <a href=#toc:widget-screen-time>Widget: Screen Time</a><a href=#widget-screen-time class=anchor aria-hidden=true></a></h3><p>Screen time widget is quite similar to Digital Wellbeing’s widget by\nthe same name. It displays the total screen time for the day along with\nthe top three apps from all users.</section><section id=widget-clear-cache class=level3 data-number=6.8.14><h3 data-number=6.8.14><span class=header-section-number>6.8.14</span> <a href=#toc:widget-clear-cache>Widget: Clear Cache</a><a href=#widget-clear-cache class=anchor aria-hidden=true></a></h3><p>Clear cache widget can be to clear cache from all the applications\ndirectly from the home screen.</section></section><section id=sec:v2.6.0-(385) class=level2 data-number=6.9><h2 data-number=6.9><span class=header-section-number>6.9</span> <a href=#toc:sec:v2.6.0-(385)>v2.6.0 (385)</a><a href=#sec:v2.6.0-(385) class=anchor aria-hidden=true></a></h2><section id=introducing-backups class=level3 data-number=6.9.1><h3 data-number=6.9.1><span class=header-section-number>6.9.1</span>\n<a href=#toc:introducing-backups>Introducing Backups</a><a href=#introducing-backups class=anchor aria-hidden=true></a></h3><p>Back up/restore feature is now finally out of beta! Read <a href=#sec:backup-restore>the corresponding guide</a> to understand how\nit works.</section><section id=introducing-log-viewer class=level3 data-number=6.9.2><h3 data-number=6.9.2><span class=header-section-number>6.9.2</span>\n<a href=#toc:introducing-log-viewer>Introducing Log Viewer</a><a href=#introducing-log-viewer class=anchor aria-hidden=true></a></h3><p><a href=#subsubsec:log-viewer>Log viewer</a> is essentially a\nfront-end for <code>logcat</code>. It can be used to filter logs by\n<em>tag</em> or <em>pid</em> (process ID), or even by custom filters.\nLog levels AKA verbosity can also be configured. You can also save,\nshare and manage logs.</section><section id=lock-app-manager class=level3 data-number=6.9.3><h3 data-number=6.9.3><span class=header-section-number>6.9.3</span>\n<a href=#toc:lock-app-manager>Lock App Manager</a><a href=#lock-app-manager class=anchor aria-hidden=true></a></h3><p><a href=#subsubsec:screen-lock>Lock App Manager</a> with the screen\nlock configured for your device.</section><section id=extended-modes-for-app-ops class=level3 data-number=6.9.4><h3 data-number=6.9.4><span class=header-section-number>6.9.4</span>\n<a href=#toc:extended-modes-for-app-ops>Extended Modes for App\nOps</a><a href=#extended-modes-for-app-ops class=anchor aria-hidden=true></a></h3><p>You can set any mode for any app ops that your device supports,\neither from the <a href=#subsec:set-mode-for-app-ops-dots>1-click ops\npage</a> or from the <a href=#subsubsec:app-ops>app ops tab</a>.</section><section id=new-batch-ops-add-to-profile class=level3 data-number=6.9.5><h3 data-number=6.9.5><span class=header-section-number>6.9.5</span>\n<a href=#toc:new-batch-ops-add-to-profile>New Batch Ops: Add to\nProfile</a><a href=#new-batch-ops-add-to-profile class=anchor aria-hidden=true></a></h3><p>You can now easily add selected apps to an existing profile using the\nbatch operations.</section><section id=app-info-improved class=level3 data-number=6.9.6><h3 data-number=6.9.6><span class=header-section-number>6.9.6</span>\n<a href=#toc:app-info-improved>App Info: Improved</a><a href=#app-info-improved class=anchor aria-hidden=true></a></h3><p>App info tab now has many options, including the ability to change <a href=#sec:terminologies>SSAID</a>, network policy (i.e. background\nnetwork usage), battery optimization, etc. Most of the tags used in this\ntab are also clickable, and if you click on them, you will be able to\nlook at the current state or configure them right away.</section><section id=advanced-sort-and-filtering-options-in-the-main-page class=level3 data-number=6.9.7><h3 data-number=6.9.7><span class=header-section-number>6.9.7</span>\n<a href=#toc:advanced-sort-and-filtering-options-in-the-main-page>Advanced\nSort and Filtering Options in the Main Page</a><a href=#advanced-sort-and-filtering-options-in-the-main-page class=anchor aria-hidden=true></a></h3><p>Sort and filter options are now replaced by <a href=#subsubsec:main-list-options>List Options</a> which is highly\nconfigurable, including the ability to filter using profiles.</section><section id=about-this-device class=level3 data-number=6.9.8><h3 data-number=6.9.8><span class=header-section-number>6.9.8</span>\n<a href=#toc:about-this-device>About This Device</a><a href=#about-this-device class=anchor aria-hidden=true></a></h3><p>Interested in knowing about your device in just one page? Go to the\nbottom of the <a href=#subsec:device-info>settings page</a>.</section><section id=enabledisable-features class=level3 data-number=6.9.9><h3 data-number=6.9.9><span class=header-section-number>6.9.9</span>\n<a href=#toc:enabledisable-features>Enable/disable Features</a><a href=#enabledisable-features class=anchor aria-hidden=true></a></h3><p>Not interested in all the features that AM offers? You can disable\nsome features in <a href=#subsubsec:enable/disable-features>settings</a>.</section><section id=new-languages-1 class=level3 data-number=6.9.10><h3 data-number=6.9.10><span class=header-section-number>6.9.10</span> <a href=#toc:new-languages-1>New Languages</a><a href=#new-languages-1 class=anchor aria-hidden=true></a></h3><p>AM now has more than 19 languages! New languages include Farsi,\nJapanese and Traditional Chinese.</section><section id=signing-the-apk-files class=level3 data-number=6.9.11><h3 data-number=6.9.11><span class=header-section-number>6.9.11</span> <a href=#toc:signing-the-apk-files>Signing the APK Files</a><a href=#signing-the-apk-files class=anchor aria-hidden=true></a></h3><p>You can now import external signing keys in AM! For security, App\nManager has its own encrypted KeyStore which can also be <a href=#subsubsec:import/export-keystore>imported or exported</a>.</section><section id=new-extension-unapkm class=level3 data-number=6.9.12><h3 data-number=6.9.12><span class=header-section-number>6.9.12</span> <a href=#toc:new-extension-unapkm>New Extension: UnAPKM</a><a href=#new-extension-unapkm class=anchor aria-hidden=true></a></h3><p>Since APKMirror has removed encryption from their APKM files, it’s no\nlonger necessary to decrypt them. As a result, the option to decrypt\nAPKM files has been removed. Instead, this option is now provided by the\nUnAPKM extension which you can grab from <a href=https://f-droid.org/packages/io.github.muntashirakon.unapkm/>F-Droid</a>.\nSo, if you have an encrypted APKM file and have this extension\ninstalled, you can open the file directly in AM.</section></section><section id=sec:v2.5.20-(375) class=level2 data-number=6.10><h2 data-number=6.10><span class=header-section-number>6.10</span>\n<a href=#toc:sec:v2.5.20-(375)>v2.5.20 (375)</a><a href=#sec:v2.5.20-(375) class=anchor aria-hidden=true></a></h2><section id=subsec:introducing-profiles class=level3 data-number=6.10.1><h3 data-number=6.10.1><span class=header-section-number>6.10.1</span> <a href=#toc:subsec:introducing-profiles>Introducing Profiles</a><a href=#subsec:introducing-profiles class=anchor aria-hidden=true></a></h3><p><a href=#sec:profile-page>Profiles</a> finally closes the <a href=https://github.com/MuntashirAkon/AppManager/issues/72>related\nissue</a>. Profiles can be used to execute certain tasks repeatedly\nwithout doing everything manually. A profile can be applied (or invoked)\neither from the <a href=#sec:profiles-page>Profiles page</a> or from\nthe home screen by creating shortcuts. There are also some presets which\nconsist of debloating profiles taken from <a href=https://gitlab.com/W1nst0n/universal-android-debloater>Universal\nAndroid Debloater</a>.<section id=known-limitations class=level5 data-number=6.10.1.0.1><h5 data-number=6.10.1.0.1><span class=header-section-number>6.10.1.0.1</span> Known limitations<a href=#known-limitations class=anchor aria-hidden=true></a></h5><ul class=incremental><li><p>Exporting rules and applying permissions are not currently\nworking.<li><p>Profiles are applied for all users.</ul></section></section><section id=subsec:the-interceptor class=level3 data-number=6.10.2><h3 data-number=6.10.2><span class=header-section-number>6.10.2</span> <a href=#toc:subsec:the-interceptor>The Interceptor</a><a href=#subsec:the-interceptor class=anchor aria-hidden=true></a></h3><p><a href=https://github.com/MuntashirAkon/intent-intercept>Intent\nIntercept</a> works as a man-in-the-middle between source and\ndestination, that is, when you open a file or URL with another app, you\ncan see what is being shared by opening it with Interceptor first. You\ncan also add or modify the intents before sending them to the\ndestination. Additionally, you can double-click on any exportable\nactivities in the Activities tab in the App Details page to open them in\nthe Interceptor to add more configurations.<section id=known-limitation-2 class=level5 data-number=6.10.2.0.1><h5 data-number=6.10.2.0.1><span class=header-section-number>6.10.2.0.1</span> Known limitation<a href=#known-limitation-2 class=anchor aria-hidden=true></a></h5><p>Editing extras is not currently possible.</section></section><section id=subsec:unapkm:-dedrm-the-apkm-files class=level3 data-number=6.10.3><h3 data-number=6.10.3><span class=header-section-number>6.10.3</span> <a href=#toc:subsec:unapkm:-dedrm-the-apkm-files>UnAPKM: DeDRM the APKM\nfiles</a><a href=#subsec:unapkm:-dedrm-the-apkm-files class=anchor aria-hidden=true></a></h3><p>When I released a small tool called <a href=https://f-droid.org/en/packages/io.github.muntashirakon.unapkm>UnAPKM</a>,\nI promised that similar feature will be available in App Manager. I am\nproud to announce that you can open APKM files directly in the App Info\npage or convert them to APKS or install them directly.</section><section id=subsec:multiple-user class=level3 data-number=6.10.4><h3 data-number=6.10.4><span class=header-section-number>6.10.4</span> <a href=#toc:subsec:multiple-user>Multiple user</a><a href=#subsec:multiple-user class=anchor aria-hidden=true></a></h3><p>App manager now supports multiple users! For now, this requires root\nor ADB. But no-root support is also being considered. If you have\nmultiple users enabled and click on an app installed in multiple\nprofiles, an alert prompt will be displayed where you can select the\nuser.</section><section id=vive-la-france class=level3 data-number=6.10.5><h3 data-number=6.10.5><span class=header-section-number>6.10.5</span> <a href=#toc:vive-la-france>Vive la France!</a><a href=#vive-la-france class=anchor aria-hidden=true></a></h3><p>Thanks to the contributors, we have one more addition to the language\nclub: French. You can add more languages or improve existing\ntranslations at <a href=https://hosted.weblate.org/engage/app-manager>Weblate</a>.</section><section id=report-crashes class=level3 data-number=6.10.6><h3 data-number=6.10.6><span class=header-section-number>6.10.6</span> <a href=#toc:report-crashes>Report crashes</a><a href=#report-crashes class=anchor aria-hidden=true></a></h3><p>If App Manager crashes, you can now easily report the crash from the\nnotifications which opens the share options. Crashes are not reported by\nApp Manager, it only redirects you to your favourite Email client.</section><section id=android-11 class=level3 data-number=6.10.7><h3 data-number=6.10.7><span class=header-section-number>6.10.7</span> <a href=#toc:android-11>Android 11</a><a href=#android-11 class=anchor aria-hidden=true></a></h3><p>Added support for Android 11. Not everything may work as expected\nthough.</section><section id=app-installer-improvements class=level3 data-number=6.10.8><h3 data-number=6.10.8><span class=header-section-number>6.10.8</span> <a href=#toc:app-installer-improvements>App Installer Improvements</a><a href=#app-installer-improvements class=anchor aria-hidden=true></a></h3><section id=set-installation-locations class=level4 data-number=6.10.8.1><h4 data-number=6.10.8.1><span class=header-section-number>6.10.8.1</span> Set installation\nlocations<a href=#set-installation-locations class=anchor aria-hidden=true></a></h4><p>In settings page, you can set install locations such as auto\n(default), internal only and prefer external.</section><section id=set-apk-installer class=level4 data-number=6.10.8.2><h4 data-number=6.10.8.2><span class=header-section-number>6.10.8.2</span> Set APK installer<a href=#set-apk-installer class=anchor aria-hidden=true></a></h4><p>In settings page, you can also set default APK installer (root/ADB\nonly) instead of App Manager.</section><section id=multiple-users class=level4 data-number=6.10.8.3><h4 data-number=6.10.8.3><span class=header-section-number>6.10.8.3</span> Multiple users<a href=#multiple-users class=anchor aria-hidden=true></a></h4><p>In settings page, you can allow App Manager to display multiple users\nduring APK installation.</section><section id=signing-apk-files class=level4 data-number=6.10.8.4><h4 data-number=6.10.8.4><span class=header-section-number>6.10.8.4</span> Signing APK files<a href=#signing-apk-files class=anchor aria-hidden=true></a></h4><p>In settings page, you can choose to sign APK files before installing\nthem. You can also select which signature scheme to use in the <em>APK\nsigning</em> option in settings.<section id=known-limitation-3 class=level5 data-number=6.10.8.4.1><h5 data-number=6.10.8.4.1><span class=header-section-number>6.10.8.4.1</span> Known limitation<a href=#known-limitation-3 class=anchor aria-hidden=true></a></h5><p>Currently, only a generic key is used to sign APK files</section></section></section></section><section id=v2.5.17-368 class=level2 data-number=6.11><h2 data-number=6.11><span class=header-section-number>6.11</span>\n<a href=#toc:v2.5.17-368>v2.5.17 (368)</a><a href=#v2.5.17-368 class=anchor aria-hidden=true></a></h2><section id=app-installer class=level3 data-number=6.11.1><h3 data-number=6.11.1><span class=header-section-number>6.11.1</span> <a href=#toc:app-installer>App Installer</a><a href=#app-installer class=anchor aria-hidden=true></a></h3><p>As promised, it is now possible to select splits. AM also provides\nrecommendations based on device configurations. If the app is already\ninstalled, recommendations are provided based on the installed app. It\nis also possible to downgrade to a lower version without data loss if\nthe device has root or ADB. But it should be noted that not all app can\nbe downgraded. Installer is also improved to speed up the installation\nprocess, especially, for root users. If the app has already been\ninstalled and the new (x)apk(s) is newer or older or the same version\nwith a different signature, AM will display a list of changes similar to\n<strong>What’s New</strong> before prompting the user to install the\napp. This is useful if the app has introduced tracker components, new\npermissions, etc.<section id=known-limitations-1 class=level5 data-number=6.11.1.0.1><h5 data-number=6.11.1.0.1><span class=header-section-number>6.11.1.0.1</span> Known Limitations<a href=#known-limitations-1 class=anchor aria-hidden=true></a></h5><ul class=incremental><li><p>Large app can take a long time to fetch app info, and therefore,\nit may take a long time display the installation prompt.<li><p>If the apk is not located in the internal storage, the app has to\nbe cached first which might also take a long time depending on the size\nof the apk.</ul></section></section><section id=scanner-replacement-for-exodus-page class=level3 data-number=6.11.2><h3 data-number=6.11.2><span class=header-section-number>6.11.2</span> <a href=#toc:scanner-replacement-for-exodus-page>Scanner: Replacement for\nExodus Page</a><a href=#scanner-replacement-for-exodus-page class=anchor aria-hidden=true></a></h3><p>Exodus page is now replaced with scanner page. <a href=#sec:scanner-page>Scanner page</a> contains not only a list of\ntrackers but also a list of used libraries. This is just a start. In the\nfuture, this page will contain more in depth analysis of the app.</section><section id=introducing-system-config class=level3 data-number=6.11.3><h3 data-number=6.11.3><span class=header-section-number>6.11.3</span> <a href=#toc:introducing-system-config>Introducing System Config</a><a href=#introducing-system-config class=anchor aria-hidden=true></a></h3><p>System Config lists various system configurations and\nwhitelists/blacklists included in Android by either OEM/vendor, AOSP or\neven some Magisk modules. Root users can access this option from the\noverflow menu in the main page. There isn’t any official documentation\nfor these options therefore it’s difficult to write a complete\ndocumentation for this page. I will gradually add documentations using\nmy own knowledge. However, some functions should be understandable by\ntheir name.</section><section id=more-languages class=level3 data-number=6.11.4><h3 data-number=6.11.4><span class=header-section-number>6.11.4</span> <a href=#toc:more-languages>More Languages</a><a href=#more-languages class=anchor aria-hidden=true></a></h3><p>Thanks to the contributors, AM now has more than 12 languages. New\nlanguages include Bengali, Hindi, Norwegian, Polish, Russian, Simplified\nChinese, Turkish and Ukrainian.</section><section id=app-info-tab class=level3 data-number=6.11.5><h3 data-number=6.11.5><span class=header-section-number>6.11.5</span> <a href=#toc:app-info-tab>App Info Tab</a><a href=#app-info-tab class=anchor aria-hidden=true></a></h3><p>More tags are added in the <a href=#subsec:app-info-tab>app info\ntab</a> such as <strong>KeyStore</strong> (apps with KeyStore items),\n<strong>Systemless app</strong> (apps installed via Magisk),\n<strong>Running</strong> (apps that are running). For external apk, two\nmore options are added namely <strong>Reinstall</strong> and\n<strong>Downgrade</strong>. Now it is possible to share an apk via\nBluetooth. For system apps, it is possible to uninstall updates for\nroot/ADB users. But like the similar option in the system settings, this\noperation will clear all app data. As stated above, exodus has been\nreplaced with scanner.</section><section id=navigation-improvements class=level3 data-number=6.11.6><h3 data-number=6.11.6><span class=header-section-number>6.11.6</span> <a href=#toc:navigation-improvements>Navigation Improvements</a><a href=#navigation-improvements class=anchor aria-hidden=true></a></h3><p>It’s now relatively easy to navigate to various UI components using\nkeyboard. You can use up/down button to navigate between list items and\ntab button to navigate to UI components inside an item.</section><section id=running-apps-page class=level3 data-number=6.11.7><h3 data-number=6.11.7><span class=header-section-number>6.11.7</span> <a href=#toc:running-apps-page>Running Apps Page</a><a href=#running-apps-page class=anchor aria-hidden=true></a></h3><p>It is now possible to sort and filter processes in this tab. Also,\nthe three big buttons are replaced with an easy-to-use three dot menu.\nPreviously the memory usage was wrong which is fixed in this\nversion.</section><section id=built-in-toybox class=level3 data-number=6.11.8><h3 data-number=6.11.8><span class=header-section-number>6.11.8</span> <a href=#toc:built-in-toybox>Built-in Toybox</a><a href=#built-in-toybox class=anchor aria-hidden=true></a></h3><p>Toybox (an alternative to busybox) is bundled with AM. Although\nAndroid has this utility built-in from API 23, toybox is bundled in\norder to prevent buggy implementations and to support API &lt; 23.</section><section id=component-blocker-improvements class=level3 data-number=6.11.9><h3 data-number=6.11.9><span class=header-section-number>6.11.9</span> <a href=#toc:component-blocker-improvements>Component Blocker\nImprovements</a><a href=#component-blocker-improvements class=anchor aria-hidden=true></a></h3><p>Component blocker seemed to be problematic in the previous version,\nespecially when global component blocking is enabled. The issues are\nmostly fixed now.<div class=\"amalert warning\"><p><strong><em>Caution.</em></strong><p>The component blocking mechanism is no longer compatible with v2.5.6\ndue to various security issues. If you have this version, upgrade to\nv2.5.13 or earlier versions first. After that, enable <a href=#subsubsec:instant-component-blocking>global component\nblocking</a> and disable it again.</div></section><section id=improvements-in-the-app-details-page class=level3 data-number=6.11.10><h3 data-number=6.11.10><span class=header-section-number>6.11.10</span> <a href=#toc:improvements-in-the-app-details-page>Improvements in the App\nDetails Page</a><a href=#improvements-in-the-app-details-page class=anchor aria-hidden=true></a></h3><p>Value of various app ops depend on their parent app ops. Therefore,\nwhen you allow/deny an app op, the parent of the app op gets modified.\nThis fixes the issues some users have been complaining regarding some\napp ops that couldn’t be changed.<p>If an app has the target API 23 or less, its permissions cannot be\nmodified using the <code>pm grant …</code> command. Therefore, for such\napps, option to toggle permission has been disabled.<p>The signature tab is improved to support localization. It also\ndisplays multiple checksums for a signature.</section><section id=app-manifest class=level3 data-number=6.11.11><h3 data-number=6.11.11><span class=header-section-number>6.11.11</span> <a href=#toc:app-manifest>App Manifest</a><a href=#app-manifest class=anchor aria-hidden=true></a></h3><p>Manifest no longer crashes if the size of the manifest is too long.\nGenerated manifest are now more accurate than before.</section></section><section id=v2.5.13-348 class=level2 data-number=6.12><h2 data-number=6.12><span class=header-section-number>6.12</span>\n<a href=#toc:v2.5.13-348>v2.5.13 (348)</a><a href=#v2.5.13-348 class=anchor aria-hidden=true></a></h2><section id=bundled-app-split-apk class=level3 data-number=6.12.1><h3 data-number=6.12.1><span class=header-section-number>6.12.1</span> <a href=#toc:bundled-app-split-apk>Bundled App (Split APK)</a><a href=#bundled-app-split-apk class=anchor aria-hidden=true></a></h3><p>Bundled app formats such as <strong>apks</strong> and\n<strong>xapk</strong> are now supported. You can install these apps\nusing the regular installation buttons. For root and adb users, apps are\ninstalled using shell, and for non-root users, the platform default\nmethod is used.<section id=known-limitations-2 class=level5 data-number=6.12.1.0.1><h5 data-number=6.12.1.0.1><span class=header-section-number>6.12.1.0.1</span> Known Limitations<a href=#known-limitations-2 class=anchor aria-hidden=true></a></h5><ul class=incremental><li><p>Currently <em>all</em> splits apks are installed. But this\nbehaviour is going to change in the next release. If you only need a few\nsplits instead of all, extract the <strong>APKS</strong> or\n<strong>XAPK</strong> file, and then, create a new zip file with your\ndesired split apks and replace the <strong>ZIP</strong> extension with\n<strong>APKS</strong>. Now, open it with AM.<li><p>There is no progress dialog to display the installation\nprogress.</ul></section></section><section id=direct-install-support class=level3 data-number=6.12.2><h3 data-number=6.12.2><span class=header-section-number>6.12.2</span> <a href=#toc:direct-install-support>Direct Install Support</a><a href=#direct-install-support class=anchor aria-hidden=true></a></h3><p>You can now install <strong>APK</strong>, <strong>APKS</strong> or\n<strong>XAPK</strong> directly from your favourite browser or file\nmanager. For apps that need updates, a <strong>What’s New</strong>\ndialog is displayed showing the changes in the new version.<section id=known-limitations-3 class=level5 data-number=6.12.2.0.1><h5 data-number=6.12.2.0.1><span class=header-section-number>6.12.2.0.1</span> Known Limitations<a href=#known-limitations-3 class=anchor aria-hidden=true></a></h5><ul class=incremental><li><p>Downgrade is not yet possible.<li><p>There is no progress dialog to display the installation progress.\nIf you cannot interact with the current page, wait until the\ninstallation is finished.</ul></section></section><section id=remove-all-blocking-rules class=level3 data-number=6.12.3><h3 data-number=6.12.3><span class=header-section-number>6.12.3</span> <a href=#toc:remove-all-blocking-rules>Remove All Blocking Rules</a><a href=#remove-all-blocking-rules class=anchor aria-hidden=true></a></h3><p>In the Settings page, a new option is added which can be used to\nremove all blocking rules configured within App Manager.</section><section id=app-ops-1 class=level3 data-number=6.12.4><h3 data-number=6.12.4><span class=header-section-number>6.12.4</span> <a href=#toc:app-ops-1>App\nOps</a><a href=#app-ops-1 class=anchor aria-hidden=true></a></h3><ul class=incremental><li><p>App Ops are now generated using a technique similar to AppOpsX.\nThis should decrease the loading time significantly in the App Ops\ntab.<li><p>In the App Ops tab, a menu item is added which can be used to\nlist only active app ops without including the default app ops. The\npreference is saved in the shared preferences.</ul><section id=known-limitation-4 class=level5 data-number=6.12.4.0.1><h5 data-number=6.12.4.0.1><span class=header-section-number>6.12.4.0.1</span> Known Limitation<a href=#known-limitation-4 class=anchor aria-hidden=true></a></h5><p>Often the App Ops tab may not be responsive. If that’s the case,\nrestart App Manager.</section></section><section id=enhanced-adb-support class=level3 data-number=6.12.5><h3 data-number=6.12.5><span class=header-section-number>6.12.5</span> <a href=#toc:enhanced-adb-support>Enhanced ADB Support</a><a href=#enhanced-adb-support class=anchor aria-hidden=true></a></h3><p>ADB shell commands are now executed using a technique similar to\nAppOpsX (This is the <em>free</em> alternative of AppOps by Rikka.).\nThis should dramatically increase the execution time.<section id=known-limitation-5 class=level5 data-number=6.12.5.0.1><h5 data-number=6.12.5.0.1><span class=header-section-number>6.12.5.0.1</span> Known Limitation<a href=#known-limitation-5 class=anchor aria-hidden=true></a></h5><p>AM can often crash or become not responsive. If that’s the case,\nrestart App Manager.</section></section><section id=filtering-in-main-page class=level3 data-number=6.12.6><h3 data-number=6.12.6><span class=header-section-number>6.12.6</span> <a href=#toc:filtering-in-main-page>Filtering in Main Page</a><a href=#filtering-in-main-page class=anchor aria-hidden=true></a></h3><p>Add an option to filter apps that has at least one activity.</section><section id=apk-backupsharing class=level3 data-number=6.12.7><h3 data-number=6.12.7><span class=header-section-number>6.12.7</span> <a href=#toc:apk-backupsharing>Apk Backup/Sharing</a><a href=#apk-backupsharing class=anchor aria-hidden=true></a></h3><p>Apk files are now saved as <code>app name_version.extension</code>\ninstead of <code>package.name.extension</code>.</section><section id=batch-ops class=level3 data-number=6.12.8><h3 data-number=6.12.8><span class=header-section-number>6.12.8</span> <a href=#toc:batch-ops>Batch Ops</a><a href=#batch-ops class=anchor aria-hidden=true></a></h3><ul class=incremental><li><p>Added a foreground service to run batch operations. The result of\nthe operation is displayed in a notification. If an operation has failed\nfor some packages, clicking on the notification will open a dialog box\nlisting the failed packages. There is also a <strong>Try Again</strong>\nbutton on the bottom which can be used to perform the operation again\nfor the failed packages.<li><p>Replaced Linux <em>kill</em> with\n<strong>force-stop</strong>.</ul></section><section id=translations class=level3 data-number=6.12.9><h3 data-number=6.12.9><span class=header-section-number>6.12.9</span> <a href=#toc:translations>Translations</a><a href=#translations class=anchor aria-hidden=true></a></h3><p>Added German and Portuguese (Brazilian) translations.<section id=known-limitation-6 class=level5 data-number=6.12.9.0.1><h5 data-number=6.12.9.0.1><span class=header-section-number>6.12.9.0.1</span> Known Limitation<a href=#known-limitation-6 class=anchor aria-hidden=true></a></h5><p>Not all translations are verified yet.</section></section><section id=app-data-backup class=level3 data-number=6.12.10><h3 data-number=6.12.10><span class=header-section-number>6.12.10</span> <a href=#toc:app-data-backup>App Data Backup</a><a href=#app-data-backup class=anchor aria-hidden=true></a></h3><p>Install app only for the current user at the time of restoring\nbackups. Support for split apks is also added.<p><em>Data backup feature is now considered unstable. If you encounter\nany problem, please report to me without hesitation.</em></section></section></section><section id=ch:app-ops class=level1 data-number=7><h1 data-number=7><span class=header-section-number>7</span> <a href=#toc:ch:app-ops>App Ops</a><a href=#ch:app-ops class=anchor aria-hidden=true></a></h1><section id=sec:app-ops-background class=level2 data-number=7.1><h2 data-number=7.1><span class=header-section-number>7.1</span> <a href=#toc:sec:app-ops-background>Background</a><a href=#sec:app-ops-background class=anchor aria-hidden=true></a></h2><p><strong>App Ops</strong> (short hand for <strong>Application\nOperations</strong>) are used by Android system (since Android 4.3) to\ncontrol application permissions. The user <em>can</em> control some\npermissions, but only the permissions that are considered dangerous (and\nGoogle thinks knowing your phone number isn’t a dangerous thing). So,\napp ops seems to be the one we need if we want to install apps like\nFacebook and it’s Messenger (the latter literary records everything if\nyou live outside the EU) and still want <em>some</em> privacy and/or\nsecurity. Although certain features of app ops were available in\nSettings and later in hidden settings in older version of Android, it’s\ncompletely hidden in newer versions of Android and is continued to be\nkept hidden. Now, any app with\n<strong>android.Manifest.permission.GET_APP_OPS_STATS</strong>\npermission can get the app ops information for other applications but\nthis permission is hidden from users and can only be enabled using ADB\nor root. Still, the app with this permission cannot grant or revoke\npermissions (actually mode of operation) for apps other than itself\n(with limited capacity, of course). To modify the ops of other app, the\napp needs\n<strong>android.Manifest.permission.UPDATE_APP_OPS_STATS</strong>\npermissions which isn’t accessible via <code>pm</code> command. So, you\ncannot grant it via root or ADB, the permission is only granted to the\nsystem apps. There are very few apps who support disabling permissions\nvia app ops. The best one to my knowledge is <a href=https://github.com/8enet/AppOpsX>AppOpsX</a>. The main (visible)\ndifference between my app (AppManager) and this app is that the latter\nalso provides you the ability to revoke internet permissions (by writing\nip tables). One crucial problem that I faced during the development of\nthe app ops API is the lack of documentation in English language.</section><section id=sec:introduction-to-app-ops class=level2 data-number=7.2><h2 data-number=7.2><span class=header-section-number>7.2</span> <a href=#toc:sec:introduction-to-app-ops>Introduction to App Ops</a><a href=#sec:introduction-to-app-ops class=anchor aria-hidden=true></a></h2><figure id=fig:appops><figure><object data=../images/appops.svg type=image/svg+xml></object></figure><figcaption>Figure 2: How app ops work</figcaption></figure><p>Figure <a href=#fig:appops>1</a> describes the process of changing\nand processing permission. <a href=#sec:appopsmanager>AppOpsManager</a> can be used to manage\npermissions in Settings app. <strong>AppOpsManager</strong> is also\nuseful in determining if a certain permission (or operation) is granted\nto the application. Most of the methods of\n<strong>AppOpsManager</strong> are accessible to the user app but unlike\na system app, it can only be used to check permissions for any app or\nfor the app itself and start or terminating certain operations.\nMoreover, not all operations are actually accessible from this Java\nclass. <strong>AppOpsManager</strong> holds all the necessary constants\nsuch as <a href=#subsec:op-constants><code>OP_*</code></a>,\n<code>OPSTR_*</code>, <a href=#subsec:mode-constants><code>MODE_*</code></a> which describes\noperation code, operation string and mode of operations respectively. It\nalso holds necessary data structures such as <a href=#subsec:package-ops>PackageOps</a> and <strong>OpEntry</strong>.\n<strong>PackageOps</strong> holds <strong>OpEntry</strong> for a\npackage, and <strong>OpEntry</strong>, as the name suggests, describes\neach operation.<p><code>AppOpService</code> is completely hidden from a user\napplication but accessible to the system applications. As it can be seen\nin Figure <a href=#fig:appops>1</a>, this is the class that does the\nactual management stuff. It contains data structures such as\n<strong>Ops</strong> to store basic package info and <strong>Op</strong>\nwhich is similar to <strong>OpEntry</strong> of\n<strong>AppOpsManager</strong>. It also has <strong>Shell</strong> which\nis actually the source code of the <a href=#sec:appops-cli><em>appops</em> command line tool</a>. It writes\nconfigurations to or read configurations from <a href=#sec:appops-xml><code>/data/system/appops.xml</code></a>. System\nservices calls <strong>AppOpsService</strong> to find out what an\napplication is allowed and what is not allowed to perform, and\n<strong>AppOpsService</strong> determines these permissions by parsing\n<code>/data/system/appops.xml</code>. If no custom values are present in\n<em>appops.xml</em>, it returns the default mode available in\n<strong>AppOpsManager</strong>.</section><section id=sec:appopsmanager class=level2 data-number=7.3><h2 data-number=7.3><span class=header-section-number>7.3</span> <a href=#toc:sec:appopsmanager>AppOpsManager</a><a href=#sec:appopsmanager class=anchor aria-hidden=true></a></h2><p><a href=https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/app/AppOpsManager.java>AppOpsManager</a>\nstands for application operations manager. It consists of various\nconstants and classes to modify app operations.<div class=seealso-inline><p><em>See also: <span><a href=https://developer.android.com/reference/android/app/AppOpsManager>AppOpsManager\ndocumentation</a></span></em></div><section id=subsec:op-constants class=level3 data-number=7.3.1><h3 data-number=7.3.1><span class=header-section-number>7.3.1</span>\n<a href=#toc:subsec:op-constants><code>OP_*</code> Constants</a><a href=#subsec:op-constants class=anchor aria-hidden=true></a></h3><p><code>OP_*</code> are the integer constants starting from\n<code>0</code>. <code>OP_NONE</code> implies that no operations are\nspecified whereas <code>_NUM_OP</code> denotes the number of operations\ndefined in <code>OP_*</code> prefix. While they denote each operation,\nthe operations are not necessarily unique. In fact, there are many\noperations that are actually a single operation denoted by multiple\n<code>OP_*</code> constant (possibly for future use). Vendors may define\ntheir own op based on their requirements. MIUI is one of the vendors who\nare known to do that.<div class=listing><div class=sourceCode id=cb11 data-frame=lines><pre class=\"sourceCode java\"><code class=\"sourceCode java\"><span id=cb11-1><a href=#cb11-1 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=dt>final</span> <span class=dt>int</span> OP_NONE <span class=op>=</span> <span class=op>-</span><span class=dv>1</span><span class=op>;</span></span>\n<span id=cb11-2><a href=#cb11-2 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=dt>final</span> <span class=dt>int</span> OP_COARSE_LOCATION <span class=op>=</span> <span class=dv>0</span><span class=op>;</span></span>\n<span id=cb11-3><a href=#cb11-3 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=dt>final</span> <span class=dt>int</span> OP_FINE_LOCATION <span class=op>=</span> <span class=dv>1</span><span class=op>;</span></span>\n<span id=cb11-4><a href=#cb11-4 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=dt>final</span> <span class=dt>int</span> OP_GPS <span class=op>=</span> <span class=dv>2</span><span class=op>;</span></span>\n<span id=cb11-5><a href=#cb11-5 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=dt>final</span> <span class=dt>int</span> OP_VIBRATE <span class=op>=</span> <span class=dv>3</span><span class=op>;</span></span>\n<span id=cb11-6><a href=#cb11-6 aria-hidden=true tabindex=-1></a><span class=kw>...</span></span>\n<span id=cb11-7><a href=#cb11-7 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=dt>final</span> <span class=dt>int</span> OP_READ_DEVICE_IDENTIFIERS <span class=op>=</span> <span class=dv>89</span><span class=op>;</span></span>\n<span id=cb11-8><a href=#cb11-8 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=dt>final</span> <span class=dt>int</span> OP_ACCESS_MEDIA_LOCATION <span class=op>=</span> <span class=dv>90</span><span class=op>;</span></span>\n<span id=cb11-9><a href=#cb11-9 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=dt>final</span> <span class=dt>int</span> OP_ACTIVATE_PLATFORM_VPN <span class=op>=</span> <span class=dv>91</span><span class=op>;</span></span>\n<span id=cb11-10><a href=#cb11-10 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=dt>final</span> <span class=dt>int</span> _NUM_OP <span class=op>=</span> <span class=dv>92</span><span class=op>;</span></span></code></pre></div></div><p>Whether an operation is unique is defined by\n<code>sOpToSwitch</code>. It maps each operation to another operation or\nto itself (if it’s a unique operation). For instance,\n<code>OP_FINE_LOCATION</code> and <code>OP_GPS</code> are mapped to\n<code>OP_COARSE_LOCATION</code>.<p>Each operation has a private name which are described by\n<code>sOpNames</code>. These names are usually the same names as the\nconstants without the <code>OP_</code> prefix. Some operations have\npublic names as well which are described by <code>sOpToString</code>.\nFor instance, <code>OP_COARSE_LOCATION</code> has the public name\n<strong>android:coarse_location</strong>.<p>As a gradual process of moving permissions to app ops, there are\nalready many permissions that are defined under some operations. These\npermissions are mapped in <code>sOpPerms</code>. For example, the\npermission\n<strong>android.Manifest.permission.ACCESS_COARSE_LOCATION</strong> is\nmapped to <code>OP_COARSE_LOCATION</code>. Some operations may not have\nany associated permissions which have <code>null</code> values.<p>As described in the previous section, operations that are configured\nfor an app are stored at <a href=#sec:appops-xml><code>/data/system/appops.xml</code></a>. If an\noperation is not configured, then whether system will allow that\noperation is determined from <code>sOpDefaultMode</code>. It lists the\n<em>default mode</em> for each operation.</section><section id=subsec:mode-constants class=level3 data-number=7.3.2><h3 data-number=7.3.2><span class=header-section-number>7.3.2</span>\n<a href=#toc:subsec:mode-constants><code>MODE_*</code> Constants</a><a href=#subsec:mode-constants class=anchor aria-hidden=true></a></h3><p><code>MODE_*</code> constants also integer constants starting from\n<code>0</code>. These constants are assigned to each operation\ndescribing whether an app is authorised to perform that operation. These\nmodes usually have associated names such as <strong>allow</strong> for\n<code>MODE_ALLOWED</code>, <strong>ignore</strong> for\n<code>MODE_IGNORED</code>, <strong>deny</strong> for\n<code>MODE_ERRORED</code> (a rather misnomer), <strong>default</strong>\nfor <code>MODE_DEFAULT</code> and <strong>foreground</strong> for\n<code>MODE_FOREGROUND</code>.<ol class=incremental><li><p><strong><code>MODE_ALLOWED</code>.</strong> The app is allowed to\nperform the given operation<li><p><strong><code>MODE_IGNORED</code>.</strong> The app is not\nallowed to perform the given operation, and any attempt to perform the\noperation should <em>silently fail</em>, i.e. it should not cause the\napp to crash<li><p><strong><code>MODE_ERRORED</code>.</strong> The app is not\nallowed to perform the given operation, and this attempt should cause it\nto have a fatal error, typically a\n<code>SecurityException</code><li><p><strong><code>MODE_DEFAULT</code>.</strong> The app should use\nits default security check, specified in\n<code>AppOpsManager</code><li><p><strong><code>MODE_FOREGROUND</code>.</strong> Special mode that\nmeans “allow only when app is in foreground.” This mode was added in\nAndroid 10<li><p><strong><code>MODE_ASK</code>.</strong> This is a custom mode\nused by MIUI whose uses are unknown.</ol></section><section id=subsec:package-ops class=level3 data-number=7.3.3><h3 data-number=7.3.3><span class=header-section-number>7.3.3</span>\n<a href=#toc:subsec:package-ops>PackageOps</a><a href=#subsec:package-ops class=anchor aria-hidden=true></a></h3><p><strong>AppOpsManager.PackageOps</strong> is a data structure to\nstore all the <strong>OpEntry</strong> for a package. In simple terms,\nit stores all the customised operations for a package.<div class=listing><div class=sourceCode id=cb12 data-frame=lines><pre class=\"sourceCode java\"><code class=\"sourceCode java\"><span id=cb12-1><a href=#cb12-1 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=kw>class</span> PackageOps <span class=kw>implements</span> Parcelable <span class=op>{</span></span>\n<span id=cb12-2><a href=#cb12-2 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=bu>String</span> mPackageName<span class=op>;</span></span>\n<span id=cb12-3><a href=#cb12-3 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=dt>int</span> mUid<span class=op>;</span></span>\n<span id=cb12-4><a href=#cb12-4 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=bu>List</span><span class=op>&lt;</span>OpEntry<span class=op>&gt;</span> mEntries<span class=op>;</span></span>\n<span id=cb12-5><a href=#cb12-5 aria-hidden=true tabindex=-1></a>    <span class=kw>...</span></span>\n<span id=cb12-6><a href=#cb12-6 aria-hidden=true tabindex=-1></a><span class=op>}</span></span></code></pre></div></div><p>As can be seen in Listing <a href=#lst:package-ops-class>2</a>, it\nstores all <strong>OpEntry</strong> for a package as well as the\ncorresponding package name and its kernel user ID.</section><section id=subsec:opentry class=level3 data-number=7.3.4><h3 data-number=7.3.4><span class=header-section-number>7.3.4</span>\n<a href=#toc:subsec:opentry>OpEntry</a><a href=#subsec:opentry class=anchor aria-hidden=true></a></h3><p><strong>AppOpsManager.OpEntry</strong> is a data structure that\nstores a single operation for any package.<div class=listing><div class=sourceCode id=cb13 data-frame=lines><pre class=\"sourceCode java\"><code class=\"sourceCode java\"><span id=cb13-1><a href=#cb13-1 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=dt>final</span> <span class=kw>class</span> OpEntry <span class=kw>implements</span> Parcelable <span class=op>{</span></span>\n<span id=cb13-2><a href=#cb13-2 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=dt>int</span> mOp<span class=op>;</span></span>\n<span id=cb13-3><a href=#cb13-3 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=dt>boolean</span> mRunning<span class=op>;</span></span>\n<span id=cb13-4><a href=#cb13-4 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=at>@Mode</span> <span class=dt>int</span> mMode<span class=op>;</span></span>\n<span id=cb13-5><a href=#cb13-5 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=at>@Nullable</span> LongSparseLongArray mAccessTimes<span class=op>;</span></span>\n<span id=cb13-6><a href=#cb13-6 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=at>@Nullable</span> LongSparseLongArray mRejectTimes<span class=op>;</span></span>\n<span id=cb13-7><a href=#cb13-7 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=at>@Nullable</span> LongSparseLongArray mDurations<span class=op>;</span></span>\n<span id=cb13-8><a href=#cb13-8 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=at>@Nullable</span> LongSparseLongArray mProxyUids<span class=op>;</span></span>\n<span id=cb13-9><a href=#cb13-9 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=at>@Nullable</span> LongSparseArray<span class=op>&lt;</span><span class=bu>String</span><span class=op>&gt;</span> mProxyPackageNames<span class=op>;</span></span>\n<span id=cb13-10><a href=#cb13-10 aria-hidden=true tabindex=-1></a>    <span class=kw>...</span></span>\n<span id=cb13-11><a href=#cb13-11 aria-hidden=true tabindex=-1></a><span class=op>}</span></span></code></pre></div></div><p>Here:<ul class=incremental><li><p><code>mOp</code>: Denotes one of the <a href=#subsec:op-constants><code>OP_*</code> constants</a><li><p><code>mRunning</code>: Whether the operation is in progress\n(i.e. the operation has started but not finished yet). Not all\noperations can be started or finished this way<li><p><code>mMOde</code>: One of the <a href=#subsec:mode-constants><code>MODE_*</code> constants</a><li><p><code>mAccessTimes</code>: Stores all the available access\ntimes<li><p><code>mRejectTimes</code>: Stores all the available reject\ntimes<li><p><code>mDurations</code>: All available access durations, checking\nthis with <code>mRunning</code> will tell you for how long the app is\nperforming a certain app operation<li><p><code>mProxyUids</code>: No documentation found<li><p><code>mProxyPackageNames:</code> No documentation found</ul></section><section id=subsec:usage class=level3 data-number=7.3.5><h3 data-number=7.3.5><span class=header-section-number>7.3.5</span>\n<a href=#toc:subsec:usage>Usage</a><a href=#subsec:usage class=anchor aria-hidden=true></a></h3><p>TODO</section></section><section id=sec:appopsservice class=level2 data-number=7.4><h2 data-number=7.4><span class=header-section-number>7.4</span> <a href=#toc:sec:appopsservice>AppOpsService</a><a href=#sec:appopsservice class=anchor aria-hidden=true></a></h2><p>TODO</section><section id=sec:appops-xml class=level2 data-number=7.5><h2 data-number=7.5><span class=header-section-number>7.5</span> <a href=#toc:sec:appops-xml>appops.xml</a><a href=#sec:appops-xml class=anchor aria-hidden=true></a></h2><p>Latest <code>appops.xml</code> has the following format: (This DTD is\nmade by me and by no means perfect, has compatibility issues.)<pre><code>&lt;!DOCTYPE app-ops [\n\n&lt;!ELEMENT app-ops (uid|pkg)*&gt;\n&lt;!ATTLIST app-ops v CDATA #IMPLIED&gt;\n\n&lt;!ELEMENT uid (op)*&gt;\n&lt;!ATTLIST uid n CDATA #REQUIRED&gt;\n\n&lt;!ELEMENT pkg (uid)*&gt;\n&lt;!ATTLIST pkg n CDATA #REQUIRED&gt;\n\n&lt;!ELEMENT uid (op)*&gt;\n&lt;!ATTLIST uid\nn CDATA #REQUIRED\np CDATA #IMPLIED&gt;\n\n&lt;!ELEMENT op (st)*&gt;\n&lt;!ATTLIST op\nn CDATA #REQUIRED\nm CDATA #REQUIRED&gt;\n\n&lt;!ELEMENT st EMPTY&gt;\n&lt;!ATTLIST st\nn CDATA #REQUIRED\nt CDATA #IMPLIED\nr CDATA #IMPLIED\nd CDATA #IMPLIED\npp CDATA #IMPLIED\npu CDATA #IMPLIED&gt;\n\n]&gt;</code></pre><p>The instruction below follows the exact order given above:<ul class=incremental><li><p><code>app-ops</code>: The root element. It can contain any number\nof <code>pkg</code> or package <code>uid</code><ul class=incremental><li><p><code>v</code>: (optional, integer) The version number (default:\n<code>NO_VERSION</code> or <code>-1</code>)</ul><li><p><code>pkg</code>: Stores package info. It can contain any number\nof <code>uid</code><ul class=incremental><li><p><code>n</code>: (required, string) Name of the package</ul><li><p>Package <code>uid</code>: Stores package or packages info<ul class=incremental><li><p><code>n</code>: (required, integer) The user ID</ul><li><p><code>uid</code>: The package user ID. It can contain any number\nof <code>op</code><ul class=incremental><li><p><code>n</code>: (required, integer) The user ID<li><p><code>p</code>: (optional, boolean) Is the app is a\nprivate/system app</ul><li><p><code>op</code>: The operation, can contain <code>st</code> or\nnothing at all<ul class=incremental><li><p><code>n</code>: (required, integer) The op name in integer,\ni.e. AppOpsManager.OP_*<li><p><code>m</code>: (required, integer) The op mode,\ni.e. AppOpsManager.MODE_*</ul><li><p><code>st</code>: State of operation: whether the operation is\naccessed, rejected or running (not available on old versions)<ul class=incremental><li><p><code>n</code>: (required, long) Key containing flags and\nuid<li><p><code>t</code>: (optional, long) Access time (default:\n<code>0</code>)<li><p><code>r</code>: (optional, long) Reject time (default:\n<code>0</code>)<li><p><code>d</code>: (optional, long) Access duration (default:\n<code>0</code>)<li><p><code>pp</code>: (optional, string) Proxy package name<li><p><code>pu</code>: (optional, integer) Proxy package uid</ul></ul><p>This definition can be found at <a href=https://android.googlesource.com/platform/frameworks/base/+/master/services/core/java/com/android/server/appop/AppOpsService.java>AppOpsService</a>.</section><section id=sec:appops-cli class=level2 data-number=7.6><h2 data-number=7.6><span class=header-section-number>7.6</span> <a href=#toc:sec:appops-cli>Command Line Interface</a><a href=#sec:appops-cli class=anchor aria-hidden=true></a></h2><p><code>appops</code> or <code>cmd appops</code> (on latest versions)\ncan be accessible via ADB or root. This is an easier method to get or\nupdate any operation for a package (provided the package name is known).\nThe help page of this command is self-explanatory:<pre><code>AppOps service (appops) commands:\nhelp\nPrint this help text.\nstart [--user &lt;USER_ID&gt;] &lt;PACKAGE | UID&gt; &lt;OP&gt;\nStarts a given operation for a particular application.\nstop [--user &lt;USER_ID&gt;] &lt;PACKAGE | UID&gt; &lt;OP&gt;\nStops a given operation for a particular application.\nset [--user &lt;USER_ID&gt;] &lt;[--uid] PACKAGE | UID&gt; &lt;OP&gt; &lt;MODE&gt;\nSet the mode for a particular application and operation.\nget [--user &lt;USER_ID&gt;] &lt;PACKAGE | UID&gt; [&lt;OP&gt;]\nReturn the mode for a particular application and optional operation.\nquery-op [--user &lt;USER_ID&gt;] &lt;OP&gt; [&lt;MODE&gt;]\nPrint all packages that currently have the given op in the given mode.\nreset [--user &lt;USER_ID&gt;] [&lt;PACKAGE&gt;]\nReset the given application or all applications to default modes.\nwrite-settings\nImmediately write pending changes to storage.\nread-settings\nRead the last written settings, replacing current state in RAM.\noptions:\n&lt;PACKAGE&gt; an Android package name or its UID if prefixed by --uid\n&lt;OP&gt;      an AppOps operation.\n&lt;MODE&gt;    one of allow, ignore, deny, or default\n&lt;USER_ID&gt; the user id under which the package is installed. If --user is not\nspecified, the current user is assumed.</code></pre></section></section><section id=footnotes class=\"footnotes footnotes-end-of-document\" role=doc-endnotes><hr><ol><li id=fn1><p>For distributing normal releases only<a href=#fnref1 class=footnote-back role=doc-backlink>↩︎</a><li id=fn2><p>GitHub pull requests will be merged manually using the\ncorresponding patches. As a result, GitHub may wrongfully mark them\nclosed instead of merged.<a href=#fnref2 class=footnote-back role=doc-backlink>↩︎</a><li id=fn3><p>You can also address me as “Muntashir Akon”<a href=#fnref3 class=footnote-back role=doc-backlink>↩︎</a></ol></section>"
  },
  {
    "path": "docs/raw/pt/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources></resources>"
  },
  {
    "path": "docs/raw/pt-rBR/index.html",
    "content": "<!doctype html><html xmlns=http://www.w3.org/1999/xhtml lang=pt-BR xml:lang=pt-BR><meta charset=utf-8><meta name=generator content=\"pandoc\"><meta name=viewport content=\"width=device-width,initial-scale=1,user-scalable=yes\"><meta name=author content=\"Muntashir Al-Islam\"><title>App Manager</title><style>code{white-space:pre-wrap}span.smallcaps{font-variant:small-caps}div.columns{display:flex;gap:min(4vw,1.5em)}div.column{flex:auto;overflow-x:auto}div.hanging-indent{margin-left:1.5em;text-indent:-1.5em}ul.task-list[class]{list-style:none}ul.task-list li input[type=checkbox]{font-size:inherit;width:.8em;margin:0 .8em .2em -1.6em;vertical-align:middle}.display.math{display:block;text-align:center;margin:.5rem auto}html{-webkit-text-size-adjust:100%}pre>code.sourceCode{white-space:pre;position:relative}pre>code.sourceCode>span{display:inline-block;line-height:1.25}pre>code.sourceCode>span:empty{height:1.2em}.sourceCode{overflow:visible}code.sourceCode>span{color:inherit;text-decoration:inherit}div.sourceCode{margin:1em 0}pre.sourceCode{margin:0}@media screen{div.sourceCode{overflow:auto}}@media print{pre>code.sourceCode{white-space:pre-wrap}pre>code.sourceCode>span{text-indent:-5em;padding-left:5em}}pre.numberSource code{counter-reset:source-line 0}pre.numberSource code>span{position:relative;left:-4em;counter-increment:source-line}pre.numberSource code>span>a:first-child::before{content:counter(source-line);position:relative;left:-1em;text-align:right;vertical-align:baseline;border:none;display:inline-block;-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;padding:0 4px;width:4em}pre.numberSource{margin-left:3em;padding-left:4px}div.sourceCode{}@media screen{pre>code.sourceCode>span>a:first-child::before{text-decoration:underline}}code span.al{font-weight:700}code span.an{font-style:italic}code span.cf{font-weight:700}code span.co{font-style:italic}code span.cv{font-style:italic}code span.do{font-style:italic}code span.dt{text-decoration:underline}code span.er{font-weight:700}code span.in{font-style:italic}code span.kw{font-weight:700}code span.pp{font-weight:700}code span.wa{font-style:italic}</style><link rel=stylesheet href=../css/custom.css><header id=title-block-header><h1 class=title>App Manager</h1><p class=author>Muntashir Al-Islam</header><nav id=TOC role=doc-toc><ul class=incremental><li><span><span class=toc-section-number>1</span> <a href=#ch:introduction id=toc:ch:introduction>Introdução</a></span><ul class=incremental><li><span><span class=toc-section-number>1.1</span> <a href=#sec:terminologies id=toc:sec:terminologies>Terminologias</a></span><li><span><span class=toc-section-number>1.2</span> <a href=#sec:supported-versions id=toc:sec:supported-versions>Versões\nsuportadas</a></span><li><span><span class=toc-section-number>1.3</span> <a href=#sec:official-sources id=toc:sec:official-sources>Fontes\nOficiais</a></span><ul class=incremental><li><span><span class=toc-section-number>1.3.1</span> <a href=#subsec:binary-distribution-sources id=toc:subsec:binary-distribution-sources>Fontes de Distribuição\nBinária</a></span><li><span><span class=toc-section-number>1.3.2</span> <a href=#subsec:links-to-source-code id=toc:subsec:links-to-source-code>Links para o Código\nFonte</a></span><li><span><span class=toc-section-number>1.3.3</span> <a href=#subsec:translations id=toc:subsec:translations>Traduções</a></span></ul><li><span><span class=toc-section-number>1.4</span> <a href=#sec:contributing id=toc:sec:contributing>Contribuição</a></span><ul class=incremental><li><span><span class=toc-section-number>1.4.1</span> <a href=#subsec:build-instructions id=toc:subsec:build-instructions>Instruções de\nContrução</a></span><li><span><span class=toc-section-number>1.4.2</span> <a href=#subsec:submitting-patches id=toc:subsec:submitting-patches>Submissão de\ncorreções</a></span></ul><li><span><span class=toc-section-number>1.5</span> <a href=#sec:donation-&-funding id=toc:sec:donation-&-funding>Doação &\nFinanciamento</a></span><li><span><span class=toc-section-number>1.6</span> <a href=#sec:contact id=toc:sec:contact>Contato</a></span></ul><li><span><span class=toc-section-number>2</span> <a href=#ch:pages id=toc:ch:pages>Pages</a></span><ul class=incremental><li><span><span class=toc-section-number>2.1</span> <a href=#sec:main-page id=toc:sec:main-page>Main Page</a></span><ul class=incremental><li><span><span class=toc-section-number>2.1.1</span> <a href=#subsec:batch-operations id=toc:subsec:batch-operations>Batch\nOperations</a></span><li><span><span class=toc-section-number>2.1.2</span> <a href=#subsec:main-colour-codes id=toc:subsec:main-colour-codes>Colour Codes</a></span><li><span><span class=toc-section-number>2.1.3</span> <a href=#subsec:main-page-application-types id=toc:subsec:main-page-application-types>Application\nTypes</a></span><li><span><span class=toc-section-number>2.1.4</span> <a href=#subsec:main-page-version-info id=toc:subsec:main-page-version-info>Version Info</a></span><li><span><span class=toc-section-number>2.1.5</span> <a href=#subsec:main-page-options-menu id=toc:subsec:main-page-options-menu>Options Menu</a></span></ul><li><span><span class=toc-section-number>2.2</span> <a href=#sec:app-details-page id=toc:sec:app-details-page>App Details\nPage</a></span><ul class=incremental><li><span><span class=toc-section-number>2.2.1</span> <a href=#subsec:app-details-colour-codes id=toc:subsec:app-details-colour-codes>Colour Codes</a></span><li><span><span class=toc-section-number>2.2.2</span> <a href=#subsec:app-info-tab id=toc:subsec:app-info-tab>App Info\nTab</a></span><li><span><span class=toc-section-number>2.2.3</span> <a href=#subsec:component-tabs id=toc:subsec:component-tabs>Component\nTabs</a></span><li><span><span class=toc-section-number>2.2.4</span> <a href=#subsec:permission-tabs id=toc:subsec:permission-tabs>Permission Tabs</a></span><li><span><span class=toc-section-number>2.2.5</span> <a href=#subsec:signatures-tab id=toc:subsec:signatures-tab>Signatures\nTab</a></span><li><span><span class=toc-section-number>2.2.6</span> <a href=#subsec:uses-features-tab id=toc:subsec:uses-features-tab>Uses\nFeatures tab</a></span><li><span><span class=toc-section-number>2.2.7</span> <a href=#subsec:configurations-tab id=toc:subsec:configurations-tab>Configurations tab</a></span><li><span><span class=toc-section-number>2.2.8</span> <a href=#subsec:shared-libs-tab id=toc:subsec:shared-libs-tab>Shared\nLibraries Tab</a></span></ul><li><span><span class=toc-section-number>2.3</span> <a href=#sec:1-click-ops-page id=toc:sec:1-click-ops-page>1-Click Ops\nPage</a></span><ul class=incremental><li><span><span class=toc-section-number>2.3.1</span> <a href=#subsec:block-unblock-trackers id=toc:subsec:block-unblock-trackers>Block/Unblock\nTrackers</a></span><li><span><span class=toc-section-number>2.3.2</span> <a href=#subsec:block-components-dots id=toc:subsec:block-components-dots>Block Components…</a></span><li><span><span class=toc-section-number>2.3.3</span> <a href=#subsec:set-mode-for-app-ops-dots id=toc:subsec:set-mode-for-app-ops-dots>Set Mode for App\nOps…</a></span><li><span><span class=toc-section-number>2.3.4</span> <a href=#subsec:1-click-back-up id=toc:subsec:1-click-back-up>Back\nup</a></span><li><span><span class=toc-section-number>2.3.5</span> <a href=#subsec:1-click-restore id=toc:subsec:1-click-restore>Restore</a></span><li><span><span class=toc-section-number>2.3.6</span> <a href=#subsec:trim-caches-in-all-apps id=toc:subsec:trim-caches-in-all-apps>Trim Caches in All\nApps</a></span></ul><li><span><span class=toc-section-number>2.4</span> <a href=#sec:profiles-page id=toc:sec:profiles-page>Profiles\nPage</a></span><ul class=incremental><li><span><span class=toc-section-number>2.4.1</span> <a href=#subsec:profiles-options-menu id=toc:subsec:profiles-options-menu>Options Menu</a></span></ul><li><span><span class=toc-section-number>2.5</span> <a href=#sec:profile-page id=toc:sec:profile-page>Profile\nPage</a></span><ul class=incremental><li><span><span class=toc-section-number>2.5.1</span> <a href=#subsec:profile-options-menu id=toc:subsec:profile-options-menu>Options Menu</a></span><li><span><span class=toc-section-number>2.5.2</span> <a href=#subsec:profile-apps-tab id=toc:subsec:profile-apps-tab>Apps\nTab</a></span><li><span><span class=toc-section-number>2.5.3</span> <a href=#subsec:profile-configurations-tab id=toc:subsec:profile-configurations-tab>Configurations\nTab</a></span></ul><li><span><span class=toc-section-number>2.6</span> <a href=#sec:settings-page id=toc:sec:settings-page>Settings\nPage</a></span><ul class=incremental><li><span><span class=toc-section-number>2.6.1</span> <a href=#subsec:language id=toc:subsec:language>Language</a></span><li><span><span class=toc-section-number>2.6.2</span> <a href=#subsec:appearance id=toc:subsec:appearance>Appearance</a></span><li><span><span class=toc-section-number>2.6.3</span> <a href=#subsec:privacy id=toc:subsec:privacy>Privacy</a></span><li><span><span class=toc-section-number>2.6.4</span> <a href=#subsec:mode-of-operation id=toc:subsec:mode-of-operation>Mode\nof Operation</a></span><li><span><span class=toc-section-number>2.6.5</span> <a href=#subsec:apk-signing id=toc:subsec:apk-signing>APK\nSigning</a></span><li><span><span class=toc-section-number>2.6.6</span> <a href=#subsec:installer id=toc:subsec:installer>Installer</a></span><li><span><span class=toc-section-number>2.6.7</span> <a href=#subsec:backup/restore id=toc:subsec:backup/restore>Back\nup/Restore</a></span><li><span><span class=toc-section-number>2.6.8</span> <a href=#subsec:rules id=toc:subsec:rules>Rules</a></span><li><span><span class=toc-section-number>2.6.9</span> <a href=#subsec:advanced id=toc:subsec:advanced>Advanced</a></span><li><span><span class=toc-section-number>2.6.10</span> <a href=#subsec:device-info id=toc:subsec:device-info>About the\ndevice</a></span></ul><li><span><span class=toc-section-number>2.7</span> <a href=#sec:scanner-page id=toc:sec:scanner-page>Scanner\nPage</a></span><li><span><span class=toc-section-number>2.8</span> <a href=#sec:interceptor-page id=toc:sec:interceptor-page>Interceptor\nPage</a></span><ul class=incremental><li><span><span class=toc-section-number>2.8.1</span> <a href=#subsec:intent-filters id=toc:subsec:intent-filters>Intent\nFilters</a></span><li><span><span class=toc-section-number>2.8.2</span> <a href=#subsec:matching-activities id=toc:subsec:matching-activities>Matching Activities</a></span><li><span><span class=toc-section-number>2.8.3</span> <a href=#subsec:interceptor-reset-to-default id=toc:subsec:interceptor-reset-to-default>Reset to\nDefault</a></span><li><span><span class=toc-section-number>2.8.4</span> <a href=#subsec:interceptor-send-edited-intent id=toc:subsec:interceptor-send-edited-intent>Send Edited\nIntent</a></span></ul><li><span><span class=toc-section-number>2.9</span> <a href=#sec:shared-preferences-editor-page id=toc:sec:shared-preferences-editor-page>Shared Preferences Editor\nPage</a></span></ul><li><span><span class=toc-section-number>3</span> <a href=#ch:guides id=toc:ch:guides>Guides</a></span><ul class=incremental><li><span><span class=toc-section-number>3.1</span> <a href=#sec:adb-over-tcp id=toc:sec:adb-over-tcp>ADB over\nTCP</a></span><ul class=incremental><li><span><span class=toc-section-number>3.1.1</span> <a href=#subsec:enable-developer-options id=toc:subsec:enable-developer-options>Enable developer\noptions</a></span><li><span><span class=toc-section-number>3.1.2</span> <a href=#subsec:enable-usb-debugging id=toc:subsec:enable-usb-debugging>Enable USB\ndebugging</a></span><li><span><span class=toc-section-number>3.1.3</span> <a href=#subsec:setup-adb-on-pc-or-mac id=toc:subsec:setup-adb-on-pc-or-mac>Setup ADB on PC or\nMac</a></span><li><span><span class=toc-section-number>3.1.4</span> <a href=#subsec:configure-adb-over-tcp id=toc:subsec:configure-adb-over-tcp>Configure ADB over\nTCP</a></span></ul><li><span><span class=toc-section-number>3.2</span> <a href=#sec:wireless-debugging id=toc:sec:wireless-debugging>Wireless\nDebugging</a></span><ul class=incremental><li><span><span class=toc-section-number>3.2.1</span> <a href=#subsec:enable-developer-options-and-usb-debugging id=toc:subsec:enable-developer-options-and-usb-debugging>Enable\ndeveloper options and USB Debugging</a></span><li><span><span class=toc-section-number>3.2.2</span> <a href=#subsec:enable-wireless-debugging id=toc:subsec:enable-wireless-debugging>Enable Wireless\nDebugging</a></span><li><span><span class=toc-section-number>3.2.3</span> <a href=#subsec:pair-adb-with-app-manager id=toc:subsec:pair-adb-with-app-manager>Pair ADB with App\nManager</a></span><li><span><span class=toc-section-number>3.2.4</span> <a href=#subsec:connect-app-manager-to-adb id=toc:subsec:connect-app-manager-to-adb>Connect App Manager to\nADB</a></span></ul><li><span><span class=toc-section-number>3.3</span> <a href=#sec:backup-restore id=toc:sec:backup-restore>Back\nup/Restore</a></span><ul class=incremental><li><span><span class=toc-section-number>3.3.1</span> <a href=#subsec:backup-location id=toc:subsec:backup-location>Location</a></span><li><span><span class=toc-section-number>3.3.2</span> <a href=#subsec:backup-restore-backup-options id=toc:subsec:backup-restore-backup-options>Backup\nOptions</a></span><li><span><span class=toc-section-number>3.3.3</span> <a href=#subsec:backup-restore-backup id=toc:subsec:backup-restore-backup>Backup</a></span><li><span><span class=toc-section-number>3.3.4</span> <a href=#subsec:backup-restore-restore id=toc:subsec:backup-restore-restore>Restore</a></span><li><span><span class=toc-section-number>3.3.5</span> <a href=#subsec:backup-restore-delete-backup id=toc:subsec:backup-restore-delete-backup>Delete\nBackup</a></span></ul><li><span><span class=toc-section-number>3.4</span> <a href=#sec:automating-tasks id=toc:sec:automating-tasks>Automating\nTasks</a></span><ul class=incremental><li><span><span class=toc-section-number>3.4.1</span> <a href=#subsec:generating-authorization-key id=toc:subsec:generating-authorization-key>Generating authorization\nkey</a></span><li><span><span class=toc-section-number>3.4.2</span> <a href=#subsec:at:general-configuration id=toc:subsec:at:general-configuration>Configuring\ntasks</a></span><li><span><span class=toc-section-number>3.4.3</span> <a href=#subsec:at:features id=toc:subsec:at:features>Features</a></span><li><span><span class=toc-section-number>3.4.4</span> <a href=#subsec:triggering-a-profile id=toc:subsec:triggering-a-profile>Triggering a\nprofile</a></span></ul><li><span><span class=toc-section-number>3.5</span> <a href=#sec:net-policy id=toc:sec:net-policy>Net\nPolicy</a></span></ul><li><span><span class=toc-section-number>4</span> <a href=#ch:faq id=toc:ch:faq>Frequently Asked Questions</a></span><ul class=incremental><li><span><span class=toc-section-number>4.1</span> <a href=#sec:faq:app-components id=toc:sec:faq:app-components>App\nComponents</a></span><ul class=incremental><li><span><span class=toc-section-number>4.1.1</span> <a href=#subsec:faq:what-are-app-components id=toc:subsec:faq:what-are-app-components>What are the application\ncomponents?</a></span><li><span><span class=toc-section-number>4.1.2</span> <a href=#subsec:faq:how-components-blocked id=toc:subsec:faq:how-components-blocked>How are the tracker and other\ncomponents blocked in App Manager? What are its\nlimitations?</a></span><li><span><span class=toc-section-number>4.1.3</span> <a href=#subsec:faq:components-blocked-by-others id=toc:subsec:faq:components-blocked-by-others>Does app components\nblocked by other tools retained in App Manager?</a></span><li><span><span class=toc-section-number>4.1.4</span> <a href=#subsec:faq:components-reblocked-in-am id=toc:subsec:faq:components-reblocked-in-am>What happens to the\ncomponents blocked by App Manager which were previously blocked by other\ntools?</a></span><li><span><span class=toc-section-number>4.1.5</span> <a href=#subsec:faq:what-is-instant-component-blocking id=toc:subsec:faq:what-is-instant-component-blocking>What is instant\ncomponent blocking?</a></span><li><span><span class=toc-section-number>4.1.6</span> <a href=#subsec:tracker-classes-versus-tracker-components id=toc:subsec:tracker-classes-versus-tracker-components>Tracker\nclasses versus tracker components</a></span></ul><li><span><span class=toc-section-number>4.2</span> <a href=#sec:faq:adb-over-tcp id=toc:sec:faq:adb-over-tcp>ADB over\nTCP</a></span><ul class=incremental><li><span><span class=toc-section-number>4.2.1</span> <a href=#subsec:faq:enable-adb-on-every-restart id=toc:subsec:faq:enable-adb-on-every-restart>Do I have to enable ADB\nover TCP everytime I restart?</a></span><li><span><span class=toc-section-number>4.2.2</span> <a href=#subsec:faq:usb-debugging id=toc:subsec:faq:usb-debugging>Cannot enable USB debugging. What to\ndo?</a></span><li><span><span class=toc-section-number>4.2.3</span> <a href=#subsec:faq:block-components-using-adb id=toc:subsec:faq:block-components-using-adb>Can I block tracker or\nany other application components using ADB over TCP?</a></span><li><span><span class=toc-section-number>4.2.4</span> <a href=#subsec:faq:adb-features id=toc:subsec:faq:adb-features>Which\nfeatures can be used in ADB mode?</a></span></ul><li><span><span class=toc-section-number>4.3</span> <a href=#sec:faq:miscellanea id=toc:sec:faq:miscellanea>Miscellanea</a></span><ul class=incremental><li><span><span class=toc-section-number>4.3.1</span> <a href=#subsec:faq:no-root-no-harms id=toc:subsec:faq:no-root-no-harms>I don’t use root/ADB. Am I\ncompletely safe from any harms?</a></span><li><span><span class=toc-section-number>4.3.2</span> <a href=#subsec:faq:how-trackers-libs-updated id=toc:subsec:faq:how-trackers-libs-updated>How are the trackers and\nlibraries are updated?</a></span><li><span><span class=toc-section-number>4.3.3</span> <a href=#subsec:faq:apks-deleted-after-installed id=toc:subsec:faq:apks-deleted-after-installed>Are APKs deleted after\ninstalled?</a></span><li><span><span class=toc-section-number>4.3.4</span> <a href=#subsec:faq:shizuku-support id=toc:subsec:faq:shizuku-support>Any plans for\nShizuku?</a></span><li><span><span class=toc-section-number>4.3.5</span> <a href=#subsec:faq:what-are-bloatware id=toc:subsec:faq:what-are-bloatware>What are bloatware and how to\nremove them?</a></span></ul></ul><li><span><span class=toc-section-number>5</span> <a href=#ch:specifications id=toc:ch:specifications>Specifications</a></span><ul class=incremental><li><span><span class=toc-section-number>5.1</span> <a href=#sec:rules-specification id=toc:sec:rules-specification>Rules\nSpecification</a></span><ul class=incremental><li><span><span class=toc-section-number>5.1.1</span> <a href=#background id=toc:background>Background</a></span><li><span><span class=toc-section-number>5.1.2</span> <a href=#rules-file-format id=toc:rules-file-format>Rules File\nFormat</a></span></ul></ul><li><span><span class=toc-section-number>6</span> <a href=#ch:changelogs id=toc:ch:changelogs>Changelogs</a></span><ul class=incremental><li><span><span class=toc-section-number>6.1</span> <a href=#sec:v4.0.5-(445) id=toc:sec:v4.0.5-(445)>v4.0.5\n(445)</a></span><li><span><span class=toc-section-number>6.2</span> <a href=#sec:v4.0.4-(444) id=toc:sec:v4.0.4-(444)>v4.0.4\n(444)</a></span><li><span><span class=toc-section-number>6.3</span> <a href=#sec:v4.0.3-(443) id=toc:sec:v4.0.3-(443)>v4.0.3\n(443)</a></span><li><span><span class=toc-section-number>6.4</span> <a href=#sec:v4.0.2-(442) id=toc:sec:v4.0.2-(442)>v4.0.2\n(442)</a></span><li><span><span class=toc-section-number>6.5</span> <a href=#sec:v4.0.1-(441) id=toc:sec:v4.0.1-(441)>v4.0.1\n(441)</a></span><ul class=incremental><li><span><span class=toc-section-number>6.5.1</span> <a href=#overlay-management id=toc:overlay-management>Overlay\nmanagement</a></span><li><span><span class=toc-section-number>6.5.2</span> <a href=#unfreeze-option-in-activity-shortcuts id=toc:unfreeze-option-in-activity-shortcuts>Unfreeze option in\nactivity shortcuts</a></span><li><span><span class=toc-section-number>6.5.3</span> <a href=#market-like-url-support id=toc:market-like-url-support><code>market</code>-like URL\nsupport</a></span><li><span><span class=toc-section-number>6.5.4</span> <a href=#updated-color-codes id=toc:updated-color-codes>Updated color\ncodes</a></span><li><span><span class=toc-section-number>6.5.5</span> <a href=#others id=toc:others>Others</a></span></ul><li><span><span class=toc-section-number>6.6</span> <a href=#sec:v4.0.0-(440) id=toc:sec:v4.0.0-(440)>v4.0.0\n(440)</a></span><ul class=incremental><li><span><span class=toc-section-number>6.6.1</span> <a href=#new-logo id=toc:new-logo>New logo!</a></span><li><span><span class=toc-section-number>6.6.2</span> <a href=#android-14-and-15-support id=toc:android-14-and-15-support>Android 14 and 15\nsupport</a></span><li><span><span class=toc-section-number>6.6.3</span> <a href=#revamped-debloater id=toc:revamped-debloater>Revamped\ndebloater</a></span><li><span><span class=toc-section-number>6.6.4</span> <a href=#introducing-file-manager id=toc:introducing-file-manager>Introducing file\nmanager</a></span><li><span><span class=toc-section-number>6.6.5</span> <a href=#integrated-code-editor id=toc:integrated-code-editor>Integrated code editor</a></span><li><span><span class=toc-section-number>6.6.6</span> <a href=#history-of-operations id=toc:history-of-operations>History of\noperations</a></span><li><span><span class=toc-section-number>6.6.7</span> <a href=#per-app-freezing-and-more id=toc:per-app-freezing-and-more>Per-app freezing, and\nmore</a></span><li><span><span class=toc-section-number>6.6.8</span> <a href=#log-viewer-enhancements id=toc:log-viewer-enhancements>Log\nviewer enhancements</a></span><li><span><span class=toc-section-number>6.6.9</span> <a href=#launching-non-exported-activities id=toc:launching-non-exported-activities>Launching non-exported\nactivities</a></span><li><span><span class=toc-section-number>6.6.10</span> <a href=#new-tags-in-app-info-tab id=toc:new-tags-in-app-info-tab>New\ntags in App Info tab</a></span><li><span><span class=toc-section-number>6.6.11</span> <a href=#per-session-installer-options id=toc:per-session-installer-options>Per-session installer\noptions</a></span><li><span><span class=toc-section-number>6.6.12</span> <a href=#advanced-mode-of-operations-adb-enhancements id=toc:advanced-mode-of-operations-adb-enhancements>Advanced mode of\noperations, ADB enhancements, …</a></span><li><span><span class=toc-section-number>6.6.13</span> <a href=#data-usage-widget-and-more id=toc:data-usage-widget-and-more>Data usage widget, and\nmore</a></span><li><span><span class=toc-section-number>6.6.14</span> <a href=#others-1 id=toc:others-1>Others</a></span></ul><li><span><span class=toc-section-number>6.7</span> <a href=#sec:v3.1.0-(423) id=toc:sec:v3.1.0-(423)>v3.1.0\n(423)</a></span><ul class=incremental><li><span><span class=toc-section-number>6.7.1</span> <a href=#android-13-support id=toc:android-13-support>Android 13\nsupport</a></span><li><span><span class=toc-section-number>6.7.2</span> <a href=#introducing-freezeunfreeze id=toc:introducing-freezeunfreeze>Introducing\nfreeze/unfreeze</a></span><li><span><span class=toc-section-number>6.7.3</span> <a href=#export-app-list id=toc:export-app-list>Export app\nlist</a></span><li><span><span class=toc-section-number>6.7.4</span> <a href=#elliptic-curve-crypography-ecc id=toc:elliptic-curve-crypography-ecc>Elliptic Curve Crypography\n(ECC)</a></span><li><span><span class=toc-section-number>6.7.5</span> <a href=#new-languages id=toc:new-languages>New\nlanguages</a></span><li><span><span class=toc-section-number>6.7.6</span> <a href=#more-list-options id=toc:more-list-options>More list\noptions</a></span><li><span><span class=toc-section-number>6.7.7</span> <a href=#improved-handling-of-mode-of-operation id=toc:improved-handling-of-mode-of-operation>Improved handling of\nmode of operation</a></span><li><span><span class=toc-section-number>6.7.8</span> <a href=#handling-multiple-users id=toc:handling-multiple-users>Handling multiple users</a></span><li><span><span class=toc-section-number>6.7.9</span> <a href=#explorer-enhancements id=toc:explorer-enhancements>Explorer\nenhancements</a></span><li><span><span class=toc-section-number>6.7.10</span> <a href=#new-tag-wx id=toc:new-tag-wx>New tag: WX</a></span><li><span><span class=toc-section-number>6.7.11</span> <a href=#app-ops-management id=toc:app-ops-management>App ops\nmanagement</a></span><li><span><span class=toc-section-number>6.7.12</span> <a href=#batch-uninstallation id=toc:batch-uninstallation>Batch\nuninstallation</a></span><li><span><span class=toc-section-number>6.7.13</span> <a href=#running-apps id=toc:running-apps>Running apps</a></span><li><span><span class=toc-section-number>6.7.14</span> <a href=#interceptor id=toc:interceptor>Interceptor</a></span><li><span><span class=toc-section-number>6.7.15</span> <a href=#device-specific-changes id=toc:device-specific-changes>Device-specific changes</a></span><li><span><span class=toc-section-number>6.7.16</span> <a href=#others-2 id=toc:others-2>Others</a></span></ul><li><span><span class=toc-section-number>6.8</span> <a href=#sec:v3.0.0-(410) id=toc:sec:v3.0.0-(410)>v3.0.0\n(410)</a></span><ul class=incremental><li><span><span class=toc-section-number>6.8.1</span> <a href=#material-3-and-more id=toc:material-3-and-more>Material 3 and\nMore</a></span><li><span><span class=toc-section-number>6.8.2</span> <a href=#wireless-debugging id=toc:wireless-debugging>Wireless\nDebugging</a></span><li><span><span class=toc-section-number>6.8.3</span> <a href=#languages id=toc:languages>Languages</a></span><li><span><span class=toc-section-number>6.8.4</span> <a href=#introducing-app-explorer id=toc:introducing-app-explorer>Introducing App\nExplorer</a></span><li><span><span class=toc-section-number>6.8.5</span> <a href=#import-backups-from-other-applications id=toc:import-backups-from-other-applications>Import Backups from\nOther Applications</a></span><li><span><span class=toc-section-number>6.8.6</span> <a href=#virustotal id=toc:virustotal>VirusTotal</a></span><li><span><span class=toc-section-number>6.8.7</span> <a href=#trigger-profiles-from-the-automation-software id=toc:trigger-profiles-from-the-automation-software>Trigger Profiles\nfrom the Automation Software</a></span><li><span><span class=toc-section-number>6.8.8</span> <a href=#improved-application-installer id=toc:improved-application-installer>Improved Application\nInstaller</a></span><li><span><span class=toc-section-number>6.8.9</span> <a href=#component-blocking id=toc:component-blocking>Component\nBlocking</a></span><li><span><span class=toc-section-number>6.8.10</span> <a href=#advanced-searching id=toc:advanced-searching>Advanced\nSearching</a></span><li><span><span class=toc-section-number>6.8.11</span> <a href=#shared-libraries id=toc:shared-libraries>Shared\nLibraries</a></span><li><span><span class=toc-section-number>6.8.12</span> <a href=#make-the-best-use-of-interceptor id=toc:make-the-best-use-of-interceptor>Make the Best Use of\nInterceptor</a></span><li><span><span class=toc-section-number>6.8.13</span> <a href=#widget-screen-time id=toc:widget-screen-time>Widget: Screen\nTime</a></span><li><span><span class=toc-section-number>6.8.14</span> <a href=#widget-clear-cache id=toc:widget-clear-cache>Widget: Clear\nCache</a></span></ul><li><span><span class=toc-section-number>6.9</span> <a href=#sec:v2.6.0-(385) id=toc:sec:v2.6.0-(385)>v2.6.0\n(385)</a></span><ul class=incremental><li><span><span class=toc-section-number>6.9.1</span> <a href=#introducing-backups id=toc:introducing-backups>Introducing\nBackups</a></span><li><span><span class=toc-section-number>6.9.2</span> <a href=#introducing-log-viewer id=toc:introducing-log-viewer>Introducing Log Viewer</a></span><li><span><span class=toc-section-number>6.9.3</span> <a href=#lock-app-manager id=toc:lock-app-manager>Lock App\nManager</a></span><li><span><span class=toc-section-number>6.9.4</span> <a href=#extended-modes-for-app-ops id=toc:extended-modes-for-app-ops>Extended Modes for App\nOps</a></span><li><span><span class=toc-section-number>6.9.5</span> <a href=#new-batch-ops-add-to-profile id=toc:new-batch-ops-add-to-profile>New Batch Ops: Add to\nProfile</a></span><li><span><span class=toc-section-number>6.9.6</span> <a href=#app-info-improved id=toc:app-info-improved>App Info:\nImproved</a></span><li><span><span class=toc-section-number>6.9.7</span> <a href=#advanced-sort-and-filtering-options-in-the-main-page id=toc:advanced-sort-and-filtering-options-in-the-main-page>Advanced\nSort and Filtering Options in the Main Page</a></span><li><span><span class=toc-section-number>6.9.8</span> <a href=#about-this-device id=toc:about-this-device>About This\nDevice</a></span><li><span><span class=toc-section-number>6.9.9</span> <a href=#enabledisable-features id=toc:enabledisable-features>Enable/disable Features</a></span><li><span><span class=toc-section-number>6.9.10</span> <a href=#new-languages-1 id=toc:new-languages-1>New\nLanguages</a></span><li><span><span class=toc-section-number>6.9.11</span> <a href=#signing-the-apk-files id=toc:signing-the-apk-files>Signing the\nAPK Files</a></span><li><span><span class=toc-section-number>6.9.12</span> <a href=#new-extension-unapkm id=toc:new-extension-unapkm>New\nExtension: UnAPKM</a></span></ul><li><span><span class=toc-section-number>6.10</span> <a href=#sec:v2.5.20-(375) id=toc:sec:v2.5.20-(375)>v2.5.20\n(375)</a></span><ul class=incremental><li><span><span class=toc-section-number>6.10.1</span> <a href=#subsec:introducing-profiles id=toc:subsec:introducing-profiles>Introducing\nProfiles</a></span><li><span><span class=toc-section-number>6.10.2</span> <a href=#subsec:the-interceptor id=toc:subsec:the-interceptor>The\nInterceptor</a></span><li><span><span class=toc-section-number>6.10.3</span> <a href=#subsec:unapkm:-dedrm-the-apkm-files id=toc:subsec:unapkm:-dedrm-the-apkm-files>UnAPKM: DeDRM the APKM\nfiles</a></span><li><span><span class=toc-section-number>6.10.4</span> <a href=#subsec:multiple-user id=toc:subsec:multiple-user>Multiple\nuser</a></span><li><span><span class=toc-section-number>6.10.5</span> <a href=#vive-la-france id=toc:vive-la-france>Vive la\nFrance!</a></span><li><span><span class=toc-section-number>6.10.6</span> <a href=#report-crashes id=toc:report-crashes>Report\ncrashes</a></span><li><span><span class=toc-section-number>6.10.7</span> <a href=#android-11 id=toc:android-11>Android 11</a></span><li><span><span class=toc-section-number>6.10.8</span> <a href=#app-installer-improvements id=toc:app-installer-improvements>App Installer\nImprovements</a></span></ul><li><span><span class=toc-section-number>6.11</span> <a href=#v2.5.17-368 id=toc:v2.5.17-368>v2.5.17 (368)</a></span><ul class=incremental><li><span><span class=toc-section-number>6.11.1</span> <a href=#app-installer id=toc:app-installer>App\nInstaller</a></span><li><span><span class=toc-section-number>6.11.2</span> <a href=#scanner-replacement-for-exodus-page id=toc:scanner-replacement-for-exodus-page>Scanner: Replacement for\nExodus Page</a></span><li><span><span class=toc-section-number>6.11.3</span> <a href=#introducing-system-config id=toc:introducing-system-config>Introducing System\nConfig</a></span><li><span><span class=toc-section-number>6.11.4</span> <a href=#more-languages id=toc:more-languages>More\nLanguages</a></span><li><span><span class=toc-section-number>6.11.5</span> <a href=#app-info-tab id=toc:app-info-tab>App Info Tab</a></span><li><span><span class=toc-section-number>6.11.6</span> <a href=#navigation-improvements id=toc:navigation-improvements>Navigation Improvements</a></span><li><span><span class=toc-section-number>6.11.7</span> <a href=#running-apps-page id=toc:running-apps-page>Running Apps\nPage</a></span><li><span><span class=toc-section-number>6.11.8</span> <a href=#built-in-toybox id=toc:built-in-toybox>Built-in\nToybox</a></span><li><span><span class=toc-section-number>6.11.9</span> <a href=#component-blocker-improvements id=toc:component-blocker-improvements>Component Blocker\nImprovements</a></span><li><span><span class=toc-section-number>6.11.10</span> <a href=#improvements-in-the-app-details-page id=toc:improvements-in-the-app-details-page>Improvements in the App\nDetails Page</a></span><li><span><span class=toc-section-number>6.11.11</span> <a href=#app-manifest id=toc:app-manifest>App Manifest</a></span></ul><li><span><span class=toc-section-number>6.12</span> <a href=#v2.5.13-348 id=toc:v2.5.13-348>v2.5.13 (348)</a></span><ul class=incremental><li><span><span class=toc-section-number>6.12.1</span> <a href=#bundled-app-split-apk id=toc:bundled-app-split-apk>Bundled App\n(Split APK)</a></span><li><span><span class=toc-section-number>6.12.2</span> <a href=#direct-install-support id=toc:direct-install-support>Direct\nInstall Support</a></span><li><span><span class=toc-section-number>6.12.3</span> <a href=#remove-all-blocking-rules id=toc:remove-all-blocking-rules>Remove All Blocking\nRules</a></span><li><span><span class=toc-section-number>6.12.4</span> <a href=#app-ops-1 id=toc:app-ops-1>App Ops</a></span><li><span><span class=toc-section-number>6.12.5</span> <a href=#enhanced-adb-support id=toc:enhanced-adb-support>Enhanced ADB\nSupport</a></span><li><span><span class=toc-section-number>6.12.6</span> <a href=#filtering-in-main-page id=toc:filtering-in-main-page>Filtering\nin Main Page</a></span><li><span><span class=toc-section-number>6.12.7</span> <a href=#apk-backupsharing id=toc:apk-backupsharing>Apk\nBackup/Sharing</a></span><li><span><span class=toc-section-number>6.12.8</span> <a href=#batch-ops id=toc:batch-ops>Batch Ops</a></span><li><span><span class=toc-section-number>6.12.9</span> <a href=#translations id=toc:translations>Translations</a></span><li><span><span class=toc-section-number>6.12.10</span> <a href=#app-data-backup id=toc:app-data-backup>App Data\nBackup</a></span></ul></ul><li><span><span class=toc-section-number>7</span> <a href=#ch:app-ops id=toc:ch:app-ops>App Ops</a></span><ul class=incremental><li><span><span class=toc-section-number>7.1</span> <a href=#sec:app-ops-background id=toc:sec:app-ops-background>Background</a></span><li><span><span class=toc-section-number>7.2</span> <a href=#sec:introduction-to-app-ops id=toc:sec:introduction-to-app-ops>Introduction to App\nOps</a></span><li><span><span class=toc-section-number>7.3</span> <a href=#sec:appopsmanager id=toc:sec:appopsmanager>AppOpsManager</a></span><ul class=incremental><li><span><span class=toc-section-number>7.3.1</span> <a href=#subsec:op-constants id=toc:subsec:op-constants><code>OP_*</code> Constants</a></span><li><span><span class=toc-section-number>7.3.2</span> <a href=#subsec:mode-constants id=toc:subsec:mode-constants><code>MODE_*</code>\nConstants</a></span><li><span><span class=toc-section-number>7.3.3</span> <a href=#subsec:package-ops id=toc:subsec:package-ops>PackageOps</a></span><li><span><span class=toc-section-number>7.3.4</span> <a href=#subsec:opentry id=toc:subsec:opentry>OpEntry</a></span><li><span><span class=toc-section-number>7.3.5</span> <a href=#subsec:usage id=toc:subsec:usage>Usage</a></span></ul><li><span><span class=toc-section-number>7.4</span> <a href=#sec:appopsservice id=toc:sec:appopsservice>AppOpsService</a></span><li><span><span class=toc-section-number>7.5</span> <a href=#sec:appops-xml id=toc:sec:appops-xml>appops.xml</a></span><li><span><span class=toc-section-number>7.6</span> <a href=#sec:appops-cli id=toc:sec:appops-cli>Command Line\nInterface</a></span></ul></ul></nav><div class=titlingpage><div class=center><p><img src=../images/icon.png style=width:1in alt=image><p><strong><span class=smallcaps>App Manager</span></strong><p><strong>Manual do Usuário</strong><p><em>v4.0.5</em><p>27 julho 2025<p>Copyright © 2020–2025 Muntashir Al-Islam<blockquote><p>“Devagar e sabiamente. Os que correm rápido, tropeçam.” <span>— Friar\nLaurence, <em>Romeu e Julieta</em></span></blockquote></div></div><section id=ch:introduction class=level1 data-number=1><h1 data-number=1><span class=header-section-number>1</span> <a href=#toc:ch:introduction>Introdução</a><a href=#ch:introduction class=anchor aria-hidden=true></a></h1><p>App Manager é um gerenciador de pacotes avançado para Android.\nOferece inúmeros recursos e, consequentemente, exige um usuário manual\npara auxiliar seus usuários. Este documento funciona como um manual do\nusuário para o App Manager no sentido de que visa descrever todos os\nrecursos que o App Manager tem a oferecer. Este documento também pode\nser considerado como as diretrizes “oficiais” para App Manager e\nrepresenta o comportamento esperado do App Manager. As traduções podem\ninterpretar mal este documento (que é escrito em inglês). Portanto, todo\nusuário competente deve ler a versão em inglês do documento para obter o\nmelhor do Gerenciador de Aplicativos. Também pode haver outros recursos\nnão oficiais ou de terceiros, como artigos de blog, vídeos, bate-papo\ngrupos, etc. Embora esses recursos possam ser úteis para muitas pessoas,\neles podem não estar atualizados com o atual versão do Gerenciador de\nAplicativos. Se quaisquer desvios forem detectados no App Manager a\npartir deste documento, eles devem ser relatados no <a href=https://github.com/MuntashirAkon/AppManager/issues>Rastreador de\nproblemas do App Manager</a>.<section id=sec:terminologies class=level2 data-number=1.1><h2 data-number=1.1><span class=header-section-number>1.1</span> <a href=#toc:sec:terminologies>Terminologias</a><a href=#sec:terminologies class=anchor aria-hidden=true></a></h2><ul class=incremental><li><p><strong>AM</strong> — nome curto para Gerenciador de\naplicativos.<li><p><strong>Block/Unblock</strong> — Usado para bloquear ou\ndesbloquear componentes. Como os componentes são bloqueados depende as\npreferências do usuário.<li><p><strong>IFW</strong> — forma curta de Firewall de\nIntenção.<li><p><strong>Ops</strong> — Nome curto para operações, ops de\naplicativos por exemplo, ops em lote, ops de 1 clique<li><p><strong>SSAID</strong> — forma curta de\n<code>Configurações.Secure.ANDROID_ID</code>. É um identificador de\ndispositivo atribuído a cada aplicativo (Android Oreo e em diante). É\ngerado a partir da combinação do certificado de assinatura do aplicativo\ne o conjunto SSAID para o pacote <code>android</code>. Como resultado, é\ngarantido ser o mesmo para um aplicativo, a menos que o usuário opta por\nformatar o dispositivo. É amplamente utilizado para\nrastreamento.<li><p><strong>Tracker</strong> — Denota componentes rastreadores em\ntodo o documento e no Gerenciador de Aplicativos, exceto no App Manager,\nexceto no <a href=#sec:scanner-page>página do scanner</a>. Os\nrastreadores incluem bibliotecas como repórteres de acidentes, análises,\nperfil, identificação, anúncio, localização, etc. Assim, não são iguais\nem funções. Não há distinção ou preconceito entre bibliotecas de código\naberto e de código fechado que promovem o rastreamento.</ul></section><section id=sec:supported-versions class=level2 data-number=1.2><h2 data-number=1.2><span class=header-section-number>1.2</span> <a href=#toc:sec:supported-versions>Versões suportadas</a><a href=#sec:supported-versions class=anchor aria-hidden=true></a></h2><p>Atualmente, as versões suportadas são v3.0.0 – v3.0.3 (estável),\nv3.1.0 (alpha e de debug). Verções anteriores do App Manager pode conter\nvulnerabilidades de segurança e não deve usal-las.</section><section id=sec:official-sources class=level2 data-number=1.3><h2 data-number=1.3><span class=header-section-number>1.3</span> <a href=#toc:sec:official-sources>Fontes Oficiais</a><a href=#sec:official-sources class=anchor aria-hidden=true></a></h2><section id=subsec:binary-distribution-sources class=level3 data-number=1.3.1><h3 data-number=1.3.1><span class=header-section-number>1.3.1</span>\n<a href=#toc:subsec:binary-distribution-sources>Fontes de Distribuição\nBinária</a><a href=#subsec:binary-distribution-sources class=anchor aria-hidden=true></a></h3><p>O App Manager é distribuído usando as seguintes fontes. Fontes não\noficiais podem distribuir versões modificadas do App Gerente, e ninguém\nalém de você será responsável pelas consequências do uso de tais\ndistribuições.<ol class=incremental><li><p>Official F-Droid repository.<a href=#fn1 class=footnote-ref id=fnref1 role=doc-noteref><sup>1</sup></a><br><em>Link:</em> <a href=https://f-droid.org/packages/io.github.muntashirakon.AppManager class=uri>https://f-droid.org/packages/io.github.muntashirakon.AppManager</a><li><p>GitHub repository.<br><em>Normal releases:</em> <a href=https://github.com/MuntashirAkon/AppManager/releases class=uri>https://github.com/MuntashirAkon/AppManager/releases</a><br><em>Debug releases:</em> <a href=https://github.com/MuntashirAkon/AppManager/actions class=uri>https://github.com/MuntashirAkon/AppManager/actions</a><li><p>Telegram.<br><em>Normal releases:</em> <a href=https://t.me/AppManagerChannel class=uri>https://t.me/AppManagerChannel</a><br><em>Debug releases:</em> <a href=https://t.me/AppManagerDebug class=uri>https://t.me/AppManagerDebug</a></ol></section><section id=subsec:links-to-source-code class=level3 data-number=1.3.2><h3 data-number=1.3.2><span class=header-section-number>1.3.2</span>\n<a href=#toc:subsec:links-to-source-code>Links para o Código\nFonte</a><a href=#subsec:links-to-source-code class=anchor aria-hidden=true></a></h3><p>All but GitHub are mirrors. The tags should always be up-to-date, but\nthe master branch may not. If you want to clone the master branch, use\nthe GitHub link instead of the others.<ol class=incremental><li><p>GitHub: <a href=https://github.com/MuntashirAkon/AppManager class=uri>https://github.com/MuntashirAkon/AppManager</a><li><p>Codeberg: <a href=https://codeberg.org/muntashir/AppManager class=uri>https://codeberg.org/muntashir/AppManager</a><li><p>GitLab: <a href=https://gitlab.com/muntashir/AppManager class=uri>https://gitlab.com/muntashir/AppManager</a><li><p>Riseup: <a href=https://0xacab.org/muntashir/AppManager class=uri>https://0xacab.org/muntashir/AppManager</a><li><p>sourcehut: <a href=https://git.sr.ht/~muntashir/AppManager class=uri>https://git.sr.ht/~muntashir/AppManager</a></ol></section><section id=subsec:translations class=level3 data-number=1.3.3><h3 data-number=1.3.3><span class=header-section-number>1.3.3</span>\n<a href=#toc:subsec:translations>Traduções</a><a href=#subsec:translations class=anchor aria-hidden=true></a></h3><p>O App Manager não aceita traduções diretamente por meio de\nsolicitações pull/merge. As traduções são gerenciadas automaticamente\nvia Weblate. Para participar da equipe de tradução, visite <a href=https://hosted.weblate.org/engage/app-manager/ class=uri>https://hosted.weblate.org/engage/app-manager/</a>.</section></section><section id=sec:contributing class=level2 data-number=1.4><h2 data-number=1.4><span class=header-section-number>1.4</span> <a href=#toc:sec:contributing>Contribuição</a><a href=#sec:contributing class=anchor aria-hidden=true></a></h2><p>Há várias maneiras pelas quais um usuário pode contribuir, criando\ntópicos de ajuda, participar de discussões, melhorando documentações e\ntraduções, adicionando bibliotecas ou rastreadores não reconhecidos,\nrevisando o código-fonte,bem como<p>relatar vulnerabilidades de segurança.<section id=subsec:build-instructions class=level3 data-number=1.4.1><h3 data-number=1.4.1><span class=header-section-number>1.4.1</span>\n<a href=#toc:subsec:build-instructions>Instruções de Contrução</a><a href=#subsec:build-instructions class=anchor aria-hidden=true></a></h3><p>As instruções de compilação estão disponíveis no arquivo BUILDING\nlocalizado no diretório raiz do código.</section><section id=subsec:submitting-patches class=level3 data-number=1.4.2><h3 data-number=1.4.2><span class=header-section-number>1.4.2</span>\n<a href=#toc:subsec:submitting-patches>Submissão de correções</a><a href=#subsec:submitting-patches class=anchor aria-hidden=true></a></h3><p>Repositories located on sites other than GitHub are currently\nconsidered mirrors, and pull/merge requests submitted on those sites\nwill not be accepted.<a href=#fn2 class=footnote-ref id=fnref2 role=doc-noteref><sup>2</sup></a> Instead, patches (as\n<code>.patch</code> files) can be submitted via email attachments.\n<em>Signing-off is a requirement.</em> See the CONTRIBUTING file located\nat the source root for more information.<div class=\"amalert warning\"><p><strong><em>Notice.</em></strong><p>In the case of submitting patches via email, the whole conversation\nmay be publicly accessible in the future. So, please do not include\npersonally identifiable information (PII) other than your name or email\naddress.</div></section></section><section id=sec:donation-&-funding class=level2 data-number=1.5><h2 data-number=1.5><span class=header-section-number>1.5</span> <a href=#toc:sec:donation-&-funding>Doação & Financiamento</a><a href=#sec:donation-&-funding class=anchor aria-hidden=true></a></h2><p>As of September 2024, App Manager is not accepting financial support\nuntil further notice. But you may still be able to send gifts (e.g.,\ngift cards, subscriptions, food and drink, flowers, or even cash).\nPlease reach out to the maintainer using the options given in §<a href=#sec:contact data-reference-type=ref data-reference=sec:contact>1.6</a> for further assistance.<p>In addition, the maintainers and contributors of this project DO NOT\nconsent to the creation, sale, or promotion of tokens, cryptocurrencies,\nNFTs, or any other financial instruments that claim to represent this\nproject, its code, or its community. Any such attempts are unauthorized\nand not affiliated with this project in any way.</section><section id=sec:contact class=level2 data-number=1.6><h2 data-number=1.6><span class=header-section-number>1.6</span> <a href=#toc:sec:contact>Contato</a><a href=#sec:contact class=anchor aria-hidden=true></a></h2><p>App Manager Community<br>Email: <a href=mailto:am4android@riseup.net>am4android [at] riseup\n[dot] net</a><br>GitHub: <a href=https://github.com/AMCommunity class=uri>https://github.com/AMCommunity</a><br>Twitter/X: <a href=https://x.com/AppManagerNews class=uri>https://x.com/AppManagerNews</a><br>Mastodon: <a href=https://floss.social/@appmanager>@appmanager@floss.social</a><br><br>Muntashir Al-Islam<a href=#fn3 class=footnote-ref id=fnref3 role=doc-noteref><sup>3</sup></a><br>Email: <a href=mailto:muntashirakon@riseup.net>muntashirakon [at]\nriseup [dot] net</a><br>GitHub: <a href=https://github.com/MuntashirAkon class=uri>https://github.com/MuntashirAkon</a><br>Twitter/X: <a href=https://x.com/Muntashir class=uri>https://x.com/Muntashir</a><br>Mastodon: <a href=https://infosec.exchange/@muntashir>@muntashir@infosec.exchange</a></section></section><section id=ch:pages class=level1 data-number=2><h1 data-number=2><span class=header-section-number>2</span> <a href=#toc:ch:pages>Pages</a><a href=#ch:pages class=anchor aria-hidden=true></a></h1><section id=sec:main-page class=level2 data-number=2.1><h2 data-number=2.1><span class=header-section-number>2.1</span> <a href=#toc:sec:main-page>Main Page</a><a href=#sec:main-page class=anchor aria-hidden=true></a></h2><p>Main page lists all the installed, uninstalled and backed up\napplications. A single click on any installed application item opens the\nrespective <a href=#sec:app-details-page>App Details page</a>. For the\nuninstalled system applications, a dialog prompt is displayed with an\noption reinstall them. The applications uninstalled without removing\ntheir data and signatures are also displayed in this page with an option\nto perform a full uninstallation. For the uninstalled applications\nhaving one or more backups, the restore dialog is displayed. Using the\n<a href=#par:main-page-sort>sort</a> option from the list options, the\nitems can be sorted in various ways. It is also possible to filter items\nusing the <a href=#par:main-page-filter>filter</a> option in the list\noptions. Filtering is also possible from the search bar with additional\nsupport for the regular expressions.<figure id=fig:main_page_entry_info_labeled><figure><object data=../images/main_page_entry_info_labeled.svg type=image/svg+xml></object></figure><figcaption>Figure 1: An application list item in the main\npage</figcaption></figure><section id=subsec:batch-operations class=level3 data-number=2.1.1><h3 data-number=2.1.1><span class=header-section-number>2.1.1</span>\n<a href=#toc:subsec:batch-operations>Batch Operations</a><a href=#subsec:batch-operations class=anchor aria-hidden=true></a></h3><p>Batch operations or operations on multiple applications are also\navailable within this page. Multiple selection mode can be activated by\nclicking on the app icon of an item or by long-clicking on any items in\nthe list. Once activated, a click on an item selects it instead of\nopening the App Details page. In this mode, the batch operations are\nlocated in the multiple selection menu at the bottom of the page. The\noperations include:<ul class=incremental><li><p>Adding the selected applications to a <a href=#sec:profiles-page>profile</a><li><p><a href=#sec:backup-restore>Backing up applications</a>, or\nrestoring and deleting the existing backups<li><p>Blocking the trackers from the applications<li><p>Clearing data or cache from the applications<li><p>Exporting the blocking rules configured inside App\nManager<li><p>Exporting the list of applications in Markdown, CSV, JSON or XML\nformat<li><p>Freezing/unfreezing/force-stopping/uninstalling the\napplications<li><p>Performing run-time optimization of the applications (Android 7\nonwards)<li><p>Preventing the background operations of the applications (Android\n7 onwards)<li><p>Saving the APK files to <code>AppManager/apks</code><li><p>Setting <a href=#sec:net-policy>net policies</a></ul><div class=\"amalert tip\"><p><strong><em>Accessibility.</em></strong><p>After the multiple selection mode has been activated, it is possible\nto navigate in or out of the multiple selection menu using the right or\nleft keys of the keyboard or remote.</div></section><section id=subsec:main-colour-codes class=level3 data-number=2.1.2><h3 data-number=2.1.2><span class=header-section-number>2.1.2</span>\n<a href=#toc:subsec:main-colour-codes>Colour Codes</a><a href=#subsec:main-colour-codes class=anchor aria-hidden=true></a></h3><ul class=incremental><li><p><span class=colorbox style=background-color:#ff0000b3><span style=color:#000>Red (day)</span></span> / <span class=colorbox style=background-color:#790d0d><span style=color:#fff>dark red (night)</span></span> – Uninstalled\napplication<li><p><span class=colorbox style=background-color:#ff8a80><span style=color:#000>Light red (day)</span></span> / <span class=colorbox style=background-color:#4f1c14bf><span style=color:#fff>very\ndark red (night)</span></span> – Frozen application<li><p><span class=colorbox style=background-color:#09868b><span style=color:#fff>Dark cyan</span></span> – Force-stopped\napplication<li><p><span class=colorbox style=background-color:#ff0><span style=color:#000>Yellow Star</span></span> – Debuggable\napplication<li><p><span style=color:#e05915>Orange <em>Date</em></span> – The\napplication can read system logs<li><p><span style=color:#e05915>Orange <em>UID</em></span> – The\nuser ID is being shared among multiple applications<li><p><span style=color:#e05915>Orange <em>SDK</em></span> – The\napplication possibly uses cleartext (i.e. HTTP) traffic<li><p><span style=color:#ff8017>Light orange <em>package\nname</em></span> – The application has one or more trackers<li><p><span style=color:red>Red <em>app label</em></span> – The\napplication does not allow clearing its data<li><p><span style=color:#09868b>Dark cyan <em>version</em></span>\n– Inactive application<li><p><span style=color:#f0f>Magenta type</span> – Persistent\napplication i.e. it remains running all the time<li><p><span style=color:red>Red <em>backup</em></span> – The\nuninstalled application with one or more backups present in App\nManager<li><p><span style=color:#e05915>Orange <em>backup</em></span> –\nOutdated backup, i.e. the base backup contains an older version of the\ninstalled application<li><p><span style=color:#09868b>Dark cyan <em>backup</em></span>\n– Up to date backup, i.e. the base backup contains the same or higher\nversion of the installed application.</ul></section><section id=subsec:main-page-application-types class=level3 data-number=2.1.3><h3 data-number=2.1.3><span class=header-section-number>2.1.3</span>\n<a href=#toc:subsec:main-page-application-types>Application\nTypes</a><a href=#subsec:main-page-application-types class=anchor aria-hidden=true></a></h3><p>An application can be either a <strong>User</strong> or a\n<strong>System</strong> application along with the following\nsuffixes:<ul class=incremental><li><p><code>X</code> – Supports multiple architectures<li><p><code>0</code> – No dex files present in the application<li><p><code>°</code> – Suspended application<li><p><code>#</code> – The application requested the system to allocate\na large heap i.e. large runtime memory<li><p><code>?</code> – The application requested the virtual machine to\nbe in the safe mode.</ul></section><section id=subsec:main-page-version-info class=level3 data-number=2.1.4><h3 data-number=2.1.4><span class=header-section-number>2.1.4</span>\n<a href=#toc:subsec:main-page-version-info>Version Info</a><a href=#subsec:main-page-version-info class=anchor aria-hidden=true></a></h3><p>Version name is followed by the prefixes below:<ul class=incremental><li><p><code>_</code> – No hardware acceleration (breaking the in-app\nanimations or transparencies)<li><p><code>~</code> – Test-only application<li><p><code>debug</code> – Debuggable application</ul></section><section id=subsec:main-page-options-menu class=level3 data-number=2.1.5><h3 data-number=2.1.5><span class=header-section-number>2.1.5</span>\n<a href=#toc:subsec:main-page-options-menu>Options Menu</a><a href=#subsec:main-page-options-menu class=anchor aria-hidden=true></a></h3><p>Options menu offers several options that can be used to sort and\nfilter the listed applications as well as to navigate to different pages\nwithin or outside App Manager.<section id=subsubsec:main-list-options class=level4 data-number=2.1.5.1><h4 data-number=2.1.5.1><span class=header-section-number>2.1.5.1</span> List Options<a href=#subsubsec:main-list-options class=anchor aria-hidden=true></a></h4><p><strong>List options</strong> contain the options to sort and filter\nthe list in the main page.<section id=sort class=level5 data-number=2.1.5.1.1><h5 data-number=2.1.5.1.1><span class=header-section-number>2.1.5.1.1</span> Sort<a href=#sort class=anchor aria-hidden=true></a></h5><div id=par:main-page-sort></div><p>The applications listed in the main page can be sorted in the\nfollowing ways:<ul class=incremental><li><p><strong>User apps first.</strong> The user applications are\nlisted on top<li><p><strong>App label.</strong> Sort the list in ascending order\nbased on their application labels (also known as <em>application\nnames</em>). This is the default sorting preference<li><p><strong>Package name.</strong> Sort the list in ascending order\nbased on their package names<li><p><strong>Last update.</strong> Sort the list in descending order\nbased on the date they were last updated<li><p><strong>Shared user ID.</strong> Sort the list in descending\norder based on their kernel user ID<li><p><strong>Target SDK.</strong> Sort the list in ascending order\nbased on their target SDK<li><p><strong>Signature.</strong> Sort the list in ascending order\nbased on their signing information<li><p><strong>Frozen first.</strong> The frozen applications are listed\non the top<li><p><strong>Blocked first.</strong> Sort the list in descending order\nbased on the number of blocked components each application has<li><p><strong>Backed up first.</strong> Display the applications with\nbackups on the top<li><p><strong>Trackers.</strong> Sort the list in descending order\nbased on the number of tracker components each application has<li><p><strong>Last actions.</strong> Sort the list in descending order\nbased on the latest time and date of any actions made to the\napplications within App Manager.<li><p><strong>Installation date.</strong> Sort the list by the date of\ninstallation in descending order.<li><p><strong>Total size.</strong> Sort the list by the total size of\nthe applications and their data in descending order. Requires\n<code>Usage Access</code> permission.<li><p><strong>Data usage.</strong> Sort the list by the total data\nusage in descending order. Requires <code>Usage Access</code>\npermission.<li><p><strong>Times opened.</strong> List frequently used applications\non top. Requires <code>Usage Access</code> permission.<li><p><strong>Screen time.</strong> List the applications with the\nhighest engagements on top. Requires <code>Usage Access</code>\npermission.<li><p><strong>Last used.</strong> List last used apps on top. Requires\n<code>Usage Access</code> permission.</ul><p>In addition, there is the <em>reverse</em> option that can be used to\nsort the list in the reverse order. Regardless of the sorting\npreferences, the applications are sorted alphabetically at first in\norder to prevent producing any random sorting results.</section><section id=filter class=level5 data-number=2.1.5.1.2><h5 data-number=2.1.5.1.2><span class=header-section-number>2.1.5.1.2</span> Filter<a href=#filter class=anchor aria-hidden=true></a></h5><div id=par:main-page-filter></div><p>The applications listed in the main page can be filtered in the\nfollowing ways:<ul class=incremental><li><p><strong>User apps.</strong> List only the user\napplications<li><p><strong>System apps.</strong> List only the system\napplications<li><p><strong>Frozen apps.</strong> List only the frozen\napplications<li><p><strong>Stopped apps.</strong> List only the applications that\nwere forced-stopped<li><p><strong>Installed apps.</strong> List only the installed\napplications<li><p><strong>Uninstalled apps.</strong> List only the uninstalled\napplications<li><p><strong>With rules.</strong> List the applications with one or\nmore blocking rules<li><p><strong>With activities.</strong> List the applications with one\nor more activities<li><p><strong>With backups.</strong> List the applications with one or\nmore backups<li><p><strong>Without backups.</strong> List the applications with no\nbackups present.<li><p><strong>Running apps.</strong> List the applications that are\ncurrently running<li><p><strong>With splits.</strong> List the applications with one or\nmore split APK files<li><p><strong>With KeyStore.</strong> List only the applications with\nAndroid KeyStore.<li><p><strong>With SAF.</strong> List only the applications with SAF\naccess.<li><p><strong>With SSAID.</strong> List only the applications with a\nvalid SSAID.</ul><p>Unlike sorting, it is possible to apply more than one filtering\noptions at the same time. For example, the frozen user applications can\nbe listed by selecting both <em>User apps</em> and <em>Frozen apps</em>.\nThis can be particularly useful for <a href=#subsec:batch-operations>batch operations</a> where filtering the\nuser applications may be necessary to carry out certain operations\nsafely.<div class=\"amalert warning\"><p><strong><em>Inconsistencies.</em></strong><p>App Manager extensively caches everything in this page. Therefore,\ncertain states (e.g., freeze and stopped states) may not always be\nup-to-date.</div></section><section id=profile-name class=level5 data-number=2.1.5.1.3><h5 data-number=2.1.5.1.3><span class=header-section-number>2.1.5.1.3</span> Profile Name<a href=#profile-name class=anchor aria-hidden=true></a></h5><p>It is also possible to list the applications that are only present in\na <a href=#sec:profiles-page>profile</a>. This can be useful for\ncarrying out certain operations on a profile (e.g., uninstalling all the\napplications in a profile) that cannot be done via the <a href=#sec:profiles-page>Profiles page</a>.</section></section><section id=user-manual class=level4 data-number=2.1.5.2><h4 data-number=2.1.5.2><span class=header-section-number>2.1.5.2</span> User Manual<a href=#user-manual class=anchor aria-hidden=true></a></h4><p>Clicking on the <strong>User manual</strong> opens the offline\nversion of the App Manager user manual. It may also open the online\nversion if the corresponding feature split i.e. <code>feat_docs</code>\nis not installed, or if an WebView is not present in the system to load\nthe manual.</section><section id=subsubsec:main:1-click-ops class=level4 data-number=2.1.5.3><h4 data-number=2.1.5.3><span class=header-section-number>2.1.5.3</span> 1-Click Ops<a href=#subsubsec:main:1-click-ops class=anchor aria-hidden=true></a></h4><p><strong>1-Click Ops</strong> stands for the single-click operations.\nIt opens the <a href=#sec:1-click-ops-page>corresponding page</a> in a\nnew activity.</section><section id=app-usage class=level4 data-number=2.1.5.4><h4 data-number=2.1.5.4><span class=header-section-number>2.1.5.4</span> App Usage<a href=#app-usage class=anchor aria-hidden=true></a></h4><p>Application usage statistics, such as <em>screen time</em>, <em>data\nusage</em> (both mobile and Wi-Fi), <em>number of times an app was\nopened</em>, can be accessed by clicking on the <strong>App\nUsage</strong> option in the menu. However, it requires the <em>Usage\nAccess</em> permission. This menu item will not be listed if the usage\naccess feature is disabled in <a href=#subsubsec:enable/disable-features>settings</a>.</section><section id=subsubsec:main:running-apps class=level4 data-number=2.1.5.5><h4 data-number=2.1.5.5><span class=header-section-number>2.1.5.5</span> Running Apps<a href=#subsubsec:main:running-apps class=anchor aria-hidden=true></a></h4><p>This menu item opens a new page where a list of running applications\nor processes are displayed. It also displays the current memory and\ncache (if available) usage. If root or ADB is not available to App\nManager, it only displays itself in the recent versions of Android. The\nrunning applications or processes can also be force-stopped or killed\nwithin the resultant page. Logs for each process ID (PID) can also be\nviewed in the <a href=#subsubsec:main:labs>log viewer</a>. In\naddition, it is also possible to carry out batch operations either by\nclicking on the icon or by long-clicking on an item. Normal click on any\nitems opens a dialog where a more detailed information is displayed.</section><section id=profiles class=level4 data-number=2.1.5.6><h4 data-number=2.1.5.6><span class=header-section-number>2.1.5.6</span> Profiles<a href=#profiles class=anchor aria-hidden=true></a></h4><p>This menu item opens the <a href=#sec:profiles-page>profiles\npage</a>. Profiles are a way to configure regularly used tasks. They can\nalso be invoked via shortcuts.</section><section id=apk-updater class=level4 data-number=2.1.5.7><h4 data-number=2.1.5.7><span class=header-section-number>2.1.5.7</span> APK Updater<a href=#apk-updater class=anchor aria-hidden=true></a></h4><p>If the app <a href=https://github.com/rumboalla/apkupdater>APK\nUpdater</a> is installed in the system, it can be opened directly via\nthis menu item. The option remains hidden if the app is not present in\nthe system.</section><section id=termux class=level4 data-number=2.1.5.8><h4 data-number=2.1.5.8><span class=header-section-number>2.1.5.8</span> Termux<a href=#termux class=anchor aria-hidden=true></a></h4><p>If the app <a href=https://github.com/termux/termux-app>Termux</a>\nis installed in the system, the running session (or a new session) can\nbe opened directly via this menu item. The option remains hidden if the\napp is not present in the system.</section><section id=debloater class=level4 data-number=2.1.5.9><h4 data-number=2.1.5.9><span class=header-section-number>2.1.5.9</span> Debloater<a href=#debloater class=anchor aria-hidden=true></a></h4><p>This menu item opens the debloater page that lists all the bloatware\navailable in the device and in App Manager. It also suggests alternative\napplications based on the criteria set by the <a href=https://github.com/MuntashirAkon/android-debloat-list>Android\nDebloat List</a> project.</section><section id=subsubsec:main:labs class=level4 data-number=2.1.5.10><h4 data-number=2.1.5.10><span class=header-section-number>2.1.5.10</span> Labs<a href=#subsubsec:main:labs class=anchor aria-hidden=true></a></h4><p>This menu item opens the labs page that lists all the additional\nfeatures. They include Log Viewer, System Config, Terminal, File Manager\n(as Files), UI Tracker, Interceptor, and Code Editor pages.</section><section id=settings class=level4 data-number=2.1.5.11><h4 data-number=2.1.5.11><span class=header-section-number>2.1.5.11</span> Settings<a href=#settings class=anchor aria-hidden=true></a></h4><p>This menu item opens the in-app <a href=#sec:settings-page>Settings\npage</a>.</section></section></section><section id=sec:app-details-page class=level2 data-number=2.2><h2 data-number=2.2><span class=header-section-number>2.2</span> <a href=#toc:sec:app-details-page>App Details Page</a><a href=#sec:app-details-page class=anchor aria-hidden=true></a></h2><p><strong>App Details</strong> page consists of 11 (eleven) tabs. It\ndescribes almost every bit of information an application usually has,\nincluding all attributes from its manifest, <a href=#ch:app-ops>application operations</a> (app ops), signing\ninformation, libraries, and so on.<section id=subsec:app-details-colour-codes class=level3 data-number=2.2.1><h3 data-number=2.2.1><span class=header-section-number>2.2.1</span>\n<a href=#toc:subsec:app-details-colour-codes>Colour Codes</a><a href=#subsec:app-details-colour-codes class=anchor aria-hidden=true></a></h3><p>List of colours used in this page, and their meaning:<ul class=incremental><li><p><span class=colorbox style=background-color:#ff0000b3><span style=color:#000>Red (day)</span></span> / <span class=colorbox style=background-color:#790d0d><span style=color:#fff>dark red (night)</span></span> – Denotes any app\nops or permissions having the dangerous flag, or any components blocked\nwithin App Manager, or any unsupported but required features.<li><p><span class=colorbox style=background-color:#ff8a80><span style=color:#000>Light red (day)</span></span> / <span class=colorbox style=background-color:#4f1c14bf><span style=color:#fff>very\ndark red (night)</span></span> – Denotes the components disabled outside\nof App Manager, or any unsupported but optional features.<div class=\"amalert tip\"><p><strong><em>Note.</em></strong><p>A component marked as disabled does not always mean that it is\ndisabled by the user: It could also be disabled by the system or marked\nas disabled in its manifest. The components of a disabled application\nare also considered disabled by the system (and App Manager).</div><li><p><span class=colorbox style=background-color:#ff8017><span style=color:#000>Vivid orange (day)</span></span> / <span class=colorbox style=background-color:#ff801780><span style=color:#fff>very\ndark orange (night)</span></span> – Denotes the tracker\ncomponents<li><p><span class=colorbox style=background-color:#ea80fc><span style=color:#000>Soft magenta (day)</span></span> / <span class=colorbox style=background-color:#431c5d><span style=color:#fff>very dark violet (night)</span></span> – Denotes\nthe running services.<li><p><span class=colorbox style=background-color:#1b8654><span style=color:#fff>Green</span></span> – Used in the tracker-indicator\ntag to denote that all the trackers in the application are\nblocked.</ul></section><section id=subsec:app-info-tab class=level3 data-number=2.2.2><h3 data-number=2.2.2><span class=header-section-number>2.2.2</span>\n<a href=#toc:subsec:app-info-tab>App Info Tab</a><a href=#subsec:app-info-tab class=anchor aria-hidden=true></a></h3><p><strong>App Info</strong> tab contains general information about an\napplication. It also lists many actions that can be performed within\nthis tab.<section id=subsubsec:app-info-general-information class=level4 data-number=2.2.2.1><h4 data-number=2.2.2.1><span class=header-section-number>2.2.2.1</span> General Information<a href=#subsubsec:app-info-general-information class=anchor aria-hidden=true></a></h4><p>The list below is in the same order as listed in the App Info\ntab.<ul class=incremental><li><p><strong>Application Icon.</strong> The application icon. If the\napplication does not have an icon, the system default icon will be\ndisplayed. It is also possible to verify the APK signature via SHA or\nMD5 sums stored in the clipboard by simply clicking on it.<li><p><strong>Application Label.</strong> The application label or the\nname of the application.<li><p><strong>Package Name.</strong> The name of the application\npackage. Clicking on the name stores it in the clipboard.<li><p><strong>Version.</strong> The application version is divided into\ntwo parts. The first part is called <em>version name</em>. The format of\nthis part varies but often consists of multiple integers separated by\ndots. The second part is called <em>version code</em>. It is enclosed by\nthe first brackets. The version code is an integer used to differentiate\nbetween application versions (since a version name can be unreadable to\na machine). In general, a new version of an application has higher\nversion code than the old ones. For example, if <code>123</code> and\n<code>125</code> are two version codes of an application, we can say\nthat the latter is more updated than the former because the version code\nof the latter is higher. An application that serves different APK files\nfor the same version on different platforms (mobile, tabs, desktops,\netc.) or architectures (32/64 bit, ARM or Intel), the version numbers\ncan be misleading as they often add prefixes for each platform.<li><p><strong>Tags.</strong> (Also known as tag clouds) Tags include\nthe most basic, concise and useful information of an application. See\n§<a href=#subsubsec:tags data-reference-type=ref data-reference=subsubsec:tags>2.2.2.2</a> for a complete list of tags\nshown here.<li><p><strong>Horizontal Action Panel.</strong> An action panel\nconsisting of various actions that can be carried out for the\napplication. See §<a href=#subsubsec:horizontal-action-panel data-reference-type=ref data-reference=subsubsec:horizontal-action-panel>2.2.2.3</a> for a\ncomplete list of actions available here. Additional actions are\navailable in the <a href=#subsubsec:app-info-options-menu>options\nmenu</a>.<li><p><strong>Paths & Directories.</strong> Contains various\ninformation regarding application paths including <em>app directory</em>\n(where the APK files reside), <em>data directories</em> (internal,\ndevice protected and externals), and <em>JNI library directory</em> (if\npresent). JNI libraries are used to invoke native codes usually written\nin C/C++. Use of native library can make the application run faster or\nhelp an application use third-party libraries written using languages\nother than Java like in most games. The directories can be opened via\nfile managers provided they support it and have the necessary\npermissions, by clicking on the launch button on the right-hand side of\na directory item.<li><p><strong>Data Usage.</strong> Amount of data used by the\napplication as reported by the operating system. Depending on Android\nversion, this may require a wide range of permissions including\n<em>Usage Access</em> and <em>Telephony</em> permissions.<li><p><strong>Storage & Cache.</strong> Displays information\nregarding the size of the application (APK files, optimised files), data\nand cache. In older devices, size of external data, cache, media and OBB\nfolders are also displayed. This part remains hidden if <em>Usage\nAccess</em> permission is not granted in the newer devices.<li><p><strong>More Info.</strong> Displays other information such\nas–<ul class=incremental><li><p><strong>SDK.</strong> Displays information related to the Android\nSDK: <em>Max</em> denotes the target SDK and <em>Min</em> denotes the\nminimum SDK (the latter is not available in Android Lollipop). If the\ntarget SDK value is less than the platform SDK (i.e., the highest SDK\nthe current operating system supports), the application will run in the\ncompatibility mode. This means the application may have access to\ncertain features that are unavailable or restricted in a newer version\nof Android, which can be a security and/or privacy issue. SDK is also\nknown as <strong>API Level</strong>.<br><div class=seealso-inline><p><em>Ver também: <span><a href=https://en.wikipedia.org/wiki/Android_version_history#Overview>Android\nVersion History</a></span></em></div><li><p><strong>Flags.</strong> The application flags used at the time of\nbuilding the application. For a complete list of flags and what they do,\nread the <a href=https://developer.android.com/reference/android/content/pm/ApplicationInfo#flags>official\ndocumentation</a>.<li><p><strong>Date Installed.</strong> The date when the application\nwas first installed.<li><p><strong>Date Updated.</strong> The date when the application was\nlast updated. This is the same as <em>Date Installed</em> if the\napplication hasn’t been updated.<li><p><strong>Process Name.</strong> The name of the process if it is\ndifferent from the package name. Process name is set when an application\nis being started by the system, and is usually the same as the package\nname.<li><p><strong>Installer App.</strong> The application that installed\nthis application. The installer application may not always be the same\nas the application that installed this application, because Android\nallows setting an arbitrary value for this field. In Android 11 onwards,\nthe actual installer application is also stored by the system which can\nbe accessed by clicking the “Info” button on the right-hand side of the\nitem. The field will not be visible if the installer application is not\nreported by the system (e.g., due to the installer application being\nuninstalled or hidden). Installer application may be granted additional\nprivileges by the system so that it can control certain behaviour of the\napplication it installs.<li><p><strong>User ID.</strong> The unique user ID set by the system to\nthe application. For shared applications, the same user ID is assigned\nto multiple applications having the same <em>Shared User\nID</em>.<li><p><strong>Shared User ID.</strong> Applicable for applications that\nare shared together. The shared application must have the same <a href=#subsec:signatures-tab>signatures</a>.<li><p><strong>Primary ABI.</strong> Architecture supported by this\nplatform for this application.<li><p><strong>Zygote preload name.</strong> Responsible for preloading\napplication code and data shared across all the isolated services that\nuses app zygote.<li><p><strong>Hidden API enforcement policy.</strong> Since Android 9,\nmany methods and classes in Android framework have been made\ninaccessible to the third-party applications through hidden API\nenforcement policy. It has the following options:<ul class=incremental><li><p><em>Default.</em> Based on the type of application. For system\napplications, it should be disabled, and for others, it should be\nenforced.<li><p><em>None/disabled.</em> The application has full access to the\nhidden API as it used to be before Android 9.<li><p><em>Warn.</em> Same as above, except that warnings will be logged\neach time the application accesses the hidden API. This is mostly\nunused.<li><p><em>Enforce.</em> The application cannot access hidden API,\neither dark-grey list or blacklist, or both of them. This is the default\noption for the third-party applications in Android 9 onwards unless the\napplication is whitelisted by the OEM or the vendor.<div class=\"amalert warning\"><p><strong><em>Warning.</em></strong><p>Hidden API enforcement policy is not properly implemented in Android\nand can be bypassed by the application. As a result, this value should\nnot be trusted.</div></ul><li><p><strong>SELinux.</strong> Mandatory access control (MAC) policy\nset by the operating system via SELinux.<li><p><strong>Main Activity.</strong> The main entry point to the\napplication. This is only visible if the application has <a href=#subsubsec:activities>activities</a> and any of those are\nopenable from the Launcher. There’s also a launch button on the\nright-hand side which can be used to launch this activity.</ul></ul></section><section id=subsubsec:tags class=level4 data-number=2.2.2.2><h4 data-number=2.2.2.2><span class=header-section-number>2.2.2.2</span> Tags<a href=#subsubsec:tags class=anchor aria-hidden=true></a></h4><ul class=incremental><li><p><strong>Tracker info.</strong> Number of tracker components in\nthe application (e.g., <em>5 trackers</em>) The colour of the tag\nappears orange if the trackers are unblocked and dark cyan if they are\nblocked in App Manager. Clicking on the tag opens a dialog containing\nthe list of tracker components which can also be blocked or unblocked\nprovided App Manager has sufficient privileges.<li><p><strong>Application type.</strong> User application or system\napplication. For a system application, it displays whether the\napplication is an updated version of the system application or the\napplication is installed systemless-ly via Magisk.<li><p><strong>Split APK info.</strong> Number of splits in the APK\nexcluding the base APK (e.g., <em>5 splits</em>). Clicking on the tag\nopens a dialog containing a few additional information, such as name,\ntype, and size.<li><p><strong>Debuggable.</strong> The application can be debugged over\nADB. Debuggable applications can enjoy certain functions unavailable to\na regular application. The data of the application might be accessible\nvia ADB (e.g. using <code>run-as</code> command) without any additional\npermissions.<li><p><strong>Test only.</strong> The application is a test-only\napplication. Test-only applications can enjoy certain functions\nunavailable to a regular application. The data of the application might\nbe accessible via ADB (e.g. using <code>run-as</code> command) without\nany additional permissions.<li><p><strong>No code.</strong> The application does not have any code\nassociated with it i.e., DEX files aren’t present. In some system\napplications, the actual code might be located in another\nplace.<li><p><strong>Large heap.</strong> The application has requested large\nheap size i.e., more space in memory (RAM) is requested for dynamic\nallocation. It is still up to the operating system to decide whether to\nallocate large space for the application. App Manager, for example,\nrequests large heap size because it needs to load an entire APK into\nmemory while scanning an APK.<li><p><strong>Open links.</strong> The application may open certain\nlinks from any applications. If the application can open any links by\ndefault, the color of the tag would be red, dark cyan if otherwise.\nClicking on the tag opens a dialog with the supported hosts or domains\nlisted. In Android 12 onwards, it displays an option to enable or\ndisable opening links by default provided App Manager has sufficient\npermissions. Otherwise, it displays an option to open the system\nsettings page for the application.<li><p><strong>Running.</strong> One or more services of the application\nis currently running in the background. Clicking on the tag opens a\ndialog containing the list of running services. Clicking on any services\nopens the log viewer with default filter set to the UID associated with\nthe service (which can be different from the UID of the application if\nit is running in a separate or isolated process) provided the log viewer\nfeature is enabled. There’s also an option to force-stop the\napplication.<li><p><strong>Stopped.</strong> The application is force stopped. This\nmay not prevent it from running automatically later.<li><p><strong>Disabled.</strong> Denotes that the application is\ndisabled (hidden from the launcher).<li><p><strong>Suspended.</strong> Denotes that the application is\nsuspended (grayed out in the launcher).<li><p><strong>Hidden.</strong> Denotes that the application is hidden\n(hidden from the launcher).<li><p><strong>MagiskHide.</strong> MagiskHide is enabled for the\napplication. Clicking on the tag opens a dialog containing the list of\nprocess names within the application that can be added to or removed\nfrom the MagiskHide list.<li><p><strong>MagiskDenyList.</strong> The application is present in\nMagisk DenyList. Clicking on the tag opens a dialog containing the list\nof process names within the application that can be added to or removed\nfrom Magisk DenyList.<li><p><strong>WX.</strong> The application violates the “W^X policy”\nand is capable of writing and executing in the same directory or in the\nsame portion of memory. This allows the execution of arbitrary\nexecutables either by the modification of executables embedded within\nthe application or by downloading them from the Internet.<br><div class=seealso-inline><p><em>Ver também: <span><a href=https://en.wikipedia.org/wiki/W%5EX>W^X in\nWikipedia</a></span></em></div><li><p><strong>Bloatware.</strong> The application may be a known\nbloatware. Clicking on the tag opens a dialog containing detailed\ninformation in addition to suggestions (if available).<li><p><strong>KeyStore.</strong> The application has items in the\nAndroid KeyStore. Clicking on the tag opens a dialog containing all the\nKeyStore files that belong to the application.<li><p><strong>Backup.</strong> The application was backed up using App\nManager at least once. Clicking on the tag opens a dialog containing all\nthe available backups along with metadata.<li><p><strong>No battery optimisation.</strong> Battery optimisation is\ndisabled for the application. It is possible to re-enable battery\noptimisation by clicking on the tag.<li><p><strong>Sensors disabled.</strong> Sensors are disabled for the\napplication. Sensors are disabled for most applications by\ndefault.<li><p><a href=#sec:net-policy><strong>Net policy.</strong></a>\nNetwork policy (e.g., background data usage) is configured for the\napplication. Clicking on the tag displays a dialog containing the\nsupported policies for the platform along with the options to configure\nthem.<li><p><a href=#sec:terminologies><strong>SSAID.</strong></a> Clicking\non the tag opens a dialog containing the current SSAID assigned to the\napplication. It is also possible to reset/regenerate the SSAID if\nneeded.<li><p><strong>SAF.</strong> Denotes that the application has been\ngranted to access one or more storage locations or files i.e. URIs via\nStorage Access Framework (SAF). Clicking on the tag opens a dialog\ncontaining the list of granted URIs.<li><p><strong>Play App Signing.</strong> Indicates that the application\nmight be signed by Google.<li><p><strong>Xposed.</strong> Indicates that the application may be an\nXposed module. Clicking on the tag displays a dialog with additional\ninformation.<li><p><strong>Static Shared Library.</strong> Denotes that the\napplication serves as a static shared library for one or more\napplications. Clicking on the tag opens a dialog containing a list of\ninstalled versions of the library along with an option to uninstall\nthem.<div class=\"amalert tip\"><p><strong><em>Notice.</em></strong><p>The trichrome library (supplied by Google Chrome, Vanadium or similar\nprojects) is currently the only known static shared library on\nAndroid.</div></ul></section><section id=subsubsec:horizontal-action-panel class=level4 data-number=2.2.2.3><h4 data-number=2.2.2.3><span class=header-section-number>2.2.2.3</span> Horizontal Action Panel<a href=#subsubsec:horizontal-action-panel class=anchor aria-hidden=true></a></h4><p>Horizontal Action Panel, as described in the previous section,\nconsists of various application-related actions, such as–<ul class=incremental><li><p><strong>Launch.</strong> Launch the application provided it has a\nlauncher <a href=#subsubsec:activities>activity</a>.<li><p><strong>Freeze.</strong> Freeze the application. This button is\nnot displayed if it is already frozen or the user does not have enough\nprivileges. After the application is frozen, it may be hidden from the\napp drawer depending on how it was configured. Shortcuts configured by\nthe application may also be removed. The application may only be\nunfrozen via App Manager, <code>pm</code> command or any other tools\nthat offer such a feature. Long clicking on the button opens a dialog\nwhere a shortcut can be configured to quickly freeze or unfreeze the\napplication.<li><p><strong>Uninstall.</strong> Uninstall the application with a\nprompt. In the dialog prompt, it is possible to uninstall updates of a\nsystem application, or if App Manager has enough privileges or the\noperating system supports it, it is possible to uninstall the\napplication without clearing its data and signature. For the latter\ncase, the installed application must match the signature with the\npreviously installed application if it is installed again.<div class=\"amalert tip\"><p><strong><em>Tips.</em></strong><p>A better way to reinstall an application with a different signature\nwould be to back up its data using App Manager and restore it again\nafter installing the application instead of opting to preserving data\nand signature of the application during uninstallation as this option\nmay cause undefined behaviour in the future.</div><li><p><strong>Unfreeze.</strong> Unfreeze the application. This button\nis not displayed if it is already enabled or the user does not have\nenough privileges. Similar to the <em>Freeze</em> button, long clicking\non the button opens a dialog where a shortcut can be configured to\nquickly freeze or unfreeze the application.<li><p><strong>Force Stop.</strong> Force-stop the application.<li><p><strong>Clear Data.</strong> Clear data from the application.\nThis includes any information stored in the internal and, recently, the\nexternal directories, including accounts (if set by the application),\ncache, etc. Clearing data from App Manager, for example, removes all the\nrules (the blocking is not removed though) saved within the application\n(Which is why you should always take backups of your rules). This button\nis not displayed if the user does not have enough privileges.<li><p><strong>Clear Cache.</strong> Clear the application cache. If the\napplication is running during the operation, the cache may not be\ncleared as expected.<li><p><strong>Install.</strong> Install the application, only displayed\nif the application hasn’t already been installed.<li><p><strong>What’s New.</strong> Displayed for an external\napplication if an older version of it is already installed. Clicking on\nthis button opens a dialog containing the differences between this and\nthe installed version in a version control manner. Changes include\n<em>version</em>, <em>trackers</em>, <em>permissions</em>,\n<em>components</em>, <em>signatures</em> (only checksum changes),\n<em>features</em>, <em>shared libraries</em> and <em>SDK</em>.<li><p><strong>Update.</strong> Displayed if the application has a\nhigher version code than the installed application.<li><p><strong>Reinstall.</strong> Displayed if the application has the\nsame version code as the installed application.<li><p><strong>Downgrade.</strong> Displayed if the application has a\nlower version code than the installed application.<li><p><strong>Manifest.</strong> Opens the application’s manifest file\nin a separate page. If the application has more than one split, it will\ndisplay the list of split APK files, and clicking on an item will open\nthe corresponding manifest file instead.<li><p><strong>Scanner.</strong> Scan the application in order to list\npotential trackers and libraries. It also scans the file using\nVirusTotal and fetch results from Pithus if configured.<br><div class=seealso-inline><p><em>Ver também: <span><a href=#sec:scanner-page>Scanner\npage</a></span></em></div><li><p><strong>Shared Prefs.</strong> Displays a list of shared\npreferences used by the application. Clicking on a preference item in\nthe list opens the <a href=#sec:shared-preferences-editor-page>Shared\nPreferences Editor page</a>. This option is only visible if the user has\nthe required privileges.<li><p><strong>Databases.</strong> Displays a list of databases used by\nthe application. Clicking on an item opens a list of activities that can\nopen the database. This option is only visible if the user has the\nrequired privileges.<li><p><strong>F-Droid.</strong> Open the application in the selected\n<em>F-Droid</em> client.<li><p><strong>Store.</strong> Open the application in <em>Aurora\nStore</em>. The option is only visible if <em>Aurora Store</em> is\ninstalled.</ul></section><section id=subsubsec:app-info-options-menu class=level4 data-number=2.2.2.4><h4 data-number=2.2.2.4><span class=header-section-number>2.2.2.4</span> Options Menu<a href=#subsubsec:app-info-options-menu class=anchor aria-hidden=true></a></h4><p>Options-menu is located in the top-right corner of the page. A\ncomplete description of the options present there are given below:<ul class=incremental><li><p><strong>Share.</strong> Share button can be used to share the APK\nor (if the application is has multiple splits, OBB files or any\ndependencies) <em>APKS</em> file extracted from the\napplication.<li><p><strong>Refresh.</strong> Refresh the App Info tab.<li><p><strong>View in Settings.</strong> Open the application in\nAndroid Settings.<li><p><strong>Backup/restore.</strong> Open the backup/restore\ndialog.<li><p><strong>Export blocking rules.</strong> Export rules configured\nfor the application within App Manager.<li><p><strong>Open in Termux.</strong> Open the application in Termux.\nThis actually runs <code>su - user_id</code> where <code>user_id</code>\ndenotes the application’s kernel user ID (described in §<a href=#subsubsec:app-info-general-information data-reference-type=ref data-reference=subsubsec:app-info-general-information>2.2.2.1</a>).\nThis option is only visible to the root users. See §<a href=#subsubsec:config-termux data-reference-type=ref data-reference=subsubsec:config-termux>2.2.2.5</a> to learn how to\nconfigure Termux to run commands from third-party applications.<li><p><strong>Run in Termux.</strong> Open the application via\n<code>run-as package_name</code> in Termux. This is only applicable to\nthe debuggable applications and works for both root and ADB users. See\n§<a href=#subsubsec:config-termux data-reference-type=ref data-reference=subsubsec:config-termux>2.2.2.5</a> to learn how to\nconfigure Termux to run commands from third-party applications.<li><p><strong>MagiskHide.</strong> Open a dialog containing the list of\nprocess names within the application that can be added or removed from\nthe MagiskHide list.<li><p><strong>Magisk DenyList.</strong> Open a dialog containing the\nlist of process namees within the application that can be added or\nremoved from Magisk DenyList.<li><p><strong>Battery optimisation.</strong> Enable/disable battery\noptimisation for this application.<li><p><strong>Sensors.</strong> Enable/disable sensors for this\napplication.<li><p><a href=#sec:net-policy><strong>Net policy.</strong></a>\nConfigure network policy (e.g., background data usage) for the\napplication.<li><p><strong>Extract Icon.</strong> Extract and save the application’s\nicon in the shared storage.<li><p><strong>Optimize.</strong> Perform optimisation for this\napplication. This option is for advanced users only.<li><p><strong>Add to profile.</strong> Add the application to one of\nthe configured <a href=#sec:profile-page>profiles</a>.<li><p><strong>Install for….</strong> Install the application for\nanother user and/or in the work profile if configured.</ul></section><section id=subsubsec:config-termux class=level4 data-number=2.2.2.5><h4 data-number=2.2.2.5><span class=header-section-number>2.2.2.5</span> Configuring Termux<a href=#subsubsec:config-termux class=anchor aria-hidden=true></a></h4><p>By default, Termux does not allow running commands from a third-party\napplication. To use this option, Termux v0.96 or later is required and\n<code>allow-external-apps=true</code> must be added in\n<code>~/.termux/termux.properties</code>.<div class=\"amalert tip\"><p><strong><em>Info.</em></strong><p>Enabling this option does not weaken Termux’ security. The\nthird-party applications still need to ask the user to allow running\narbitrary commands in Termux.</div></section></section><section id=subsec:component-tabs class=level3 data-number=2.2.3><h3 data-number=2.2.3><span class=header-section-number>2.2.3</span>\n<a href=#toc:subsec:component-tabs>Component Tabs</a><a href=#subsec:component-tabs class=anchor aria-hidden=true></a></h3><p><strong>Activities</strong>, <strong>Services</strong>,\n<strong>Receivers</strong> (i.e., broadcast receivers) and\n<strong>Providers</strong> (e.g., content providers) are collectively\nknown as the application components, because they offer similar features\nand share similar properties. For example, they all have a\n<em>name</em>, a <em>label</em>, an <em>icon</em>, can be enabled or\ndisabled, and can be executed via <em>Intent</em>. Application\ncomponents are the building blocks of an application and must be\ndeclared in the application manifest (with a few exceptions).\nApplication manifest is a file where application specific metadata are\nstored. The Android operating system learns what to do with the\napplication by reading the metadata.<p>Colours used in these tabs are explained in §<a href=#subsec:app-details-colour-codes data-reference-type=ref data-reference=subsec:app-details-colour-codes>2.2.1</a>. It is also\npossible to sort the list of components to display blocked or tracker\ncomponents on top of the list via the <strong>Sort</strong> option\nlocated in the three-dots menu.<section id=subsubsec:activities class=level4 data-number=2.2.3.1><h4 data-number=2.2.3.1><span class=header-section-number>2.2.3.1</span> Activities<a href=#subsubsec:activities class=anchor aria-hidden=true></a></h4><p><strong>Activities</strong> are the windows or pages that can be\nuniquely identified by the Android operating system (e.g., <em>Main\npage</em> and <em>App Details page</em> are two activities). Each\nactivity can have multiple UI components known as <em>widgets</em> or\n<em>fragments</em>, and each component can be nested or placed on top of\neach other. The developer can also choose to open external files, links,\netc. within an activity using a method called <em>intent filters</em>.\nFor example, when you open a file in your file manager, either your file\nmanager or the operating system scans the intent filters via\nPackageManager, find the activities capable of opening the file, and\nlist those activities so that you can choose your preferred\nactivity.<p>Activities that are <em>exportable</em> can be opened by any\nthird-party applications. However, Some activities may require\npermissions, and only an application having those permissions can open\nthem. In the <em>Activities</em> tab, certain activities can be launched\nvia the <strong>Launch</strong> button. If it is necessary to supply\nadditional information, such as Intent extras, data or action, long\nclicking on the <strong>Launch</strong> button opens the <a href=#sec:interceptor-page>Activity Interceptor</a> page which\nprovides such features.<div class=\"amalert tip\"><p><strong><em>Tip.</em></strong><p>No-root users can grant\n<code>android.permission.WRITE_SECURE_SETTINGS</code> via ADB to launch\n<em>non-exportable</em> activities.</div><div class=\"amalert tip\"><p><strong><em>Notice.</em></strong><p>If launching an activity throws an error, it may have certain\ndependencies which are not met (e.g., <em>App Details</em> page in App\nManager cannot be launched using the launch button, because it requires\na package name). Since the dependencies cannot be inferred\nprogrammatically, the activity may not be opened from App Manager by\ndefault.</div><p>It is also possible to create shortcuts of an activity-launch using\nthe <strong>Create shortcut</strong> button. If you need to supply\nadditional information, you can create a shortcut from the Activity\nInterceptor page instead.<div class=\"amalert danger\"><p><strong><em>Caution.</em></strong><p>If you uninstall App Manager, all shortcuts created by App Manager\nwill be lost.</div></section><section id=subsubsec:details:servcies class=level4 data-number=2.2.3.2><h4 data-number=2.2.3.2><span class=header-section-number>2.2.3.2</span> Services<a href=#subsubsec:details:servcies class=anchor aria-hidden=true></a></h4><p>Unlike <a href=#subsubsec:activities>activities</a> that users can\nsee, <strong>Services</strong> handle background tasks. For example, if\nyou’re downloading a video from the internet using your phone’s Internet\nbrowser, the Internet browser is using a <em>foreground service</em> to\ndownload the content.<p>When an activity is closed or removed from the <em>Recents</em> page,\nit may be destroyed immediately depending on the amount free memory the\nphone has, battery statistics, or how the activity is configured. But\nservices can be run indefinitely if desired. If more services run in the\nbackground, the phone may become slower due to the shortage of memory\nand/or processing power, and the phone’s battery will be drained more\nquickly. Newer versions of Android come with a battery optimisation\nfeature enabled by default for all applications. With this feature\nenabled, the system can randomly terminate any service depending on the\namount of resources the system has or the service requires. However,\nforeground services (i.e., services that run with a fixed notification,\nsuch as music player or downloader) are not typically terminated unless\nthe system is very low on resources (memory, battery, etc.). Certain\nstock ROMs can offer more aggressive optimisation. MIUI, for example,\nhas a very aggressive optimisation feature known as the <em>MIUI\noptimisation</em>.<p>Both activities and services are run in the same <a href=https://stackoverflow.com/questions/7597742>looper</a> called the\nmain looper, which means the services do not really run in the\nbackground. It is the task of the developer to ensure this. How do the\napplication communicate with the services? It uses <a href=#subsubsec:app-details-receivers>broadcast receiver</a> or\nBinder.</section><section id=subsubsec:app-details-receivers class=level4 data-number=2.2.3.3><h4 data-number=2.2.3.3><span class=header-section-number>2.2.3.3</span> Receivers<a href=#subsubsec:app-details-receivers class=anchor aria-hidden=true></a></h4><p><strong>Receivers</strong> (also called <em>broadcast receivers</em>)\ncan be used to trigger execution of certain tasks when certain events\noccur. These components are called broadcast receivers, because they are\nexecuted as soon as a broadcast message is received. These broadcast\nmessages are sent using a method called <em>Intent</em>. Intent is a\nspecial feature in Android that can be used to open applications (i.e.,\nactivities), run services and send broadcast messages. Therefore, like\n<a href=#subsubsec:activities>activities</a>, broadcast receivers use\n<em>intent filters</em> to receive the desired broadcast messages.\nBroadcast messages can be sent by the system or the application itself.\nWhen a broadcast message is sent, the corresponding receivers are\nactivated by the system so that they can execute tasks. For example, if\nyour phone is low on resources, it may freeze or experience lags for a\nmoment after you enable mobile data or connect it to the Wi-Fi. This is\nbecause broadcast receivers that can receive\n<code>android.net.conn.CONNECTIVITY_CHANGE</code> are activated by the\nsystem as soon as the data connection is enabled. Since many\napplications typically use this intent filter, they are all activated\nalmost immediately by the system which causes the freezing or lags.<p>Receivers can also be used for inter-process communication (IPC),\ni.e., it can be used to communicate across multiple applications or even\ndifferent components of a single application.</section><section id=subsubsec:providers class=level4 data-number=2.2.3.4><h4 data-number=2.2.3.4><span class=header-section-number>2.2.3.4</span> Providers<a href=#subsubsec:providers class=anchor aria-hidden=true></a></h4><p><strong>Providers</strong> are primarily used for data management.\nFor example, when you save an APK file or export rules in App Manager,\nit uses a content provider called <code>.fm.FmProvider</code> to save\nthe APK or export the rules. There are many providers, including the\nones provided by the system, that can be used to manage various\ncontent-related tasks, such as database management, tracking, searching,\netc. Each provider has a field called <em>Authority</em> which is unique\nto the application in the entire Android ecosystem just as the package\nname.</section><section id=additional-features-for-rooted-phones class=level4 data-number=2.2.3.5><h4 data-number=2.2.3.5><span class=header-section-number>2.2.3.5</span> Additional Features for\nRooted Phones<a href=#additional-features-for-rooted-phones class=anchor aria-hidden=true></a></h4><p>Unlike the no-root users who are mostly spectators in these tabs,\nroot users can perform various operations.<section id=blocking-components. class=level5 data-number=2.2.3.5.1><h5 data-number=2.2.3.5.1><span class=header-section-number>2.2.3.5.1</span> Blocking Components.<a href=#blocking-components. class=anchor aria-hidden=true></a></h5><p>On the right-most side of each component item, there is a switch\nwhich can be used to toggle the blocking status of that particular\ncomponent. If <a href=#subsubsec:instant-component-blocking>Instant\nComponent Blocking</a> is not enabled or blocking is never applied to\nthe application before, it is required to apply the changes using the\n<strong>Apply rules</strong> option in three-dots menu. It is also\npossible to remove the already-applied rules using the same option\n(which would be read as <strong>Remove rules</strong> this time).<p>It is also possible to block the component using one of the several\nmethods by long clicking on the button.<div class=seealso-inline><p><em>Ver também: <span><a href=#sec:faq:app-components>FAQ: App\nComponents</a></span></em></div></section><section id=par:appdetails:blocking-trackers class=level5 data-number=2.2.3.5.2><h5 data-number=2.2.3.5.2><span class=header-section-number>2.2.3.5.2</span> Blocking Trackers.<a href=#par:appdetails:blocking-trackers class=anchor aria-hidden=true></a></h5><p>It is possible to disable tracker components using the <strong>Block\ntracker</strong> option in the three-dots menu. All tracker components\nwill be blocked regardless of the tab you’re currently in.<div class=\"amalert tip\"><p><strong><em>Info.</em></strong><p>Tracker components are a subset of application components. Therefore,\nthey are blocked using the same method used for blocking any other\ncomponents.</div><div class=seealso><p><em>Ver também:</em><ul class=incremental><li><p><a href=#subsec:tracker-classes-versus-tracker-components>FAQ:\nTracker classes versus tracker components</a><li><p><a href=#sec:scanner-page>Scanner Page</a><li><p><a href=#subsec:block-unblock-trackers>1-Click Ops Page:\nBlock/Unblock Trackers</a></ul></div></section></section></section><section id=subsec:permission-tabs class=level3 data-number=2.2.4><h3 data-number=2.2.4><span class=header-section-number>2.2.4</span>\n<a href=#toc:subsec:permission-tabs>Permission Tabs</a><a href=#subsec:permission-tabs class=anchor aria-hidden=true></a></h3><p><strong>App Ops</strong>, <strong>Uses Permissions</strong> and\n<strong>Permissions</strong> tabs are related to permissions. In Android\ncommunication across applications or processes not having the same\nidentity (known as <em>shared ID</em>) often require permissions. These\npermissions are managed by the permission controller. Some permissions\nare considered <em>normal</em> permissions which are granted\nautomatically if they appear in the application manifest, but\n<em>dangerous</em> and <em>development</em> permissions require\nconfirmation from the user. Colours used in these tabs are explained in\n§<a href=#subsec:app-details-colour-codes data-reference-type=ref data-reference=subsec:app-details-colour-codes>2.2.1</a>.<section id=subsubsec:app-ops class=level4 data-number=2.2.4.1><h4 data-number=2.2.4.1><span class=header-section-number>2.2.4.1</span> App Ops<a href=#subsubsec:app-ops class=anchor aria-hidden=true></a></h4><p><strong>App Ops</strong> stands for <strong>Application\nOperations</strong>. Since Android 4.3, <em>App Ops</em> are used by\nAndroid to control many system permissions. Each app op has a unique\nnumber associated with it which is displayed along with the private name\nof the operation in the App Ops tab. Some app ops also have a public\nname. A large number of app ops are also associated with\n<em>permissions</em>. In this tab, an app op is considered dangerous if\nits associated permission is marked as dangerous. Other information such\nas <em>flags</em>, <em>permission name</em>, <em>permission\ndescription</em>, <em>package name</em>, <em>group</em> are also taken\nfrom the associated <a href=#subsubsec:permissions>permission</a>.\nOthers may include the following:<ul class=incremental><li><p><strong>Mode.</strong> It describes the current authorisation\nstatus which can be <em>allow</em>, <em>deny</em> (a rather misnomer, it\nsimply means error), <em>ignore</em> (it actually means deny),\n<em>default</em> (inferred from a list of defaults set internally by the\nvendor or the AOSP), <em>foreground</em> (in newer Android versions, it\nmeans the app op can only be used when the application is running in\nforeground), and some custom modes set by the vendors (MIUI uses\n<em>ask</em>, for example).<li><p><strong>Duration.</strong> The amount of time this app op has\nbeen used (there can be negative durations whose use cases are currently\nunknown to me).<li><p><strong>Accept Time.</strong> Last time the app op was\naccepted.<li><p><strong>Reject Time.</strong> Last time the app op was\nrejected.</ul><div class=\"amalert tip\"><p><strong><em>Info.</em></strong><p>Contents of this tab are visible to no-root users if\n<code>android.permission.GET_APP_OPS_STATS</code> is granted via\nADB.</div><p>There is a toggle button next to each app op item which can be used\nto allow or deny (ignore) it. Other supported modes can also be set by\nlong clicking on the toggle button. If the desired app op is not listed\nin the tab, <em>Set custom app op</em> option in the menu can be used\ninstead. It is also possible to reset the changes using the <em>Reset to\ndefault</em> option, or deny all the dangerous app ops using the\ncorresponding option in the menu. Due to the nature how app ops work,\nthe system may take some time to apply them.<div class=\"amalert tip\"><p><strong><em>Tip.</em></strong><p>Denying certain app ops may cause the application to misbehave. If\nall attempts fail, <em>reset to default</em> option can be used as the\nlast resort.</div><p>It is possible to sort the list in ascending order by app op names\nand the associated unique numbers (or values), or list the denied app\nops first using the corresponding sorting options.<div class=seealso-inline><p><em>Ver também: <span><a href=#ch:app-ops>Appendix: App\nOps</a></span></em></div></section><section id=uses-permissions class=level4 data-number=2.2.4.2><h4 data-number=2.2.4.2><span class=header-section-number>2.2.4.2</span> Uses Permissions<a href=#uses-permissions class=anchor aria-hidden=true></a></h4><p><strong>Uses Permissions</strong> are the permissions used by the\napplication. This is named so because they are specified in the manifest\nusing <code>uses-permission</code> tags. Information such as\n<em>flags</em>, <em>permission name</em>, <em>permission\ndescription</em>, <em>package name</em>, <em>group</em> are taken from\nthe associated <a href=#subsubsec:permissions>permission</a>.<p>Privileged users can grant or revoke the <em>dangerous</em> and\n<em>development</em> permissions via the toggle button on the right side\nof each permission item. It is also possible revoke dangerous\npermissions all at once using the corresponding option in the menu. Only\nthese two types of permissions can be revoked because Android does not\nallow the modification of <em>normal</em> permissions (which most of\nthem are). It might still be possible to revoke them by editing\n<code>runtime-permissions.xml</code> itself, but whether this is a\npossibility is still being investigated.<div class=\"amalert tip\"><p><strong><em>Info.</em></strong><p>Since dangerous permissions are revoked by default by the system,\nrevoking all dangerous permissions is the same as resetting all the\npermissions.</div><p>It is possible to sort the permissions by their name (in ascending\norder) or choose to display denied or dangerous permissions at first\nusing the corresponding options in the menu.</section><section id=subsubsec:permissions class=level4 data-number=2.2.4.3><h4 data-number=2.2.4.3><span class=header-section-number>2.2.4.3</span> Permissions<a href=#subsubsec:permissions class=anchor aria-hidden=true></a></h4><p><strong>Permissions</strong> are usually custom permissions defined\nby the application itself. These type of permissions are marked as\n<em>Internal</em> permissions. It also contains permissions declared by\nother applications which are marked as <em>External</em> permissions. An\nexternal permission can be specified in an <em>exported</em> application\ncomponent so that another application may invoke the component only if\nit holds the permission. Below is a complete description of each item\ndisplayed in this tab:<ul class=incremental><li><p><strong>Name.</strong> A permission has a unique name (e.g.,\n<code>android.permission.INTERNET</code>) that multiple applications can\nrequest. The application that declared the permission is automatically\ngranted and cannot be revoked.<li><p><strong>Icon.</strong> Each permission can have a custom icon.\nThe other permission tabs do not have any icon because they do not\ncontain any icon in the application manifest.<li><p><strong>Description.</strong> This optional field describes the\npermission. If there isn’t any description associated with the\npermission, the field is not displayed.<li><p><strong>Flags.</strong> (Uses the flag symbol or\n<strong>Protection Level</strong> name) This describes various\npermission flags such as <em>normal</em>, <em>development</em>,\n<em>dangerous</em>, <em>instant</em>, <em>granted</em>,\n<em>revoked</em>, <em>signature</em>, <em>privileged</em>, etc.<li><p><strong>Package Name.</strong> Denotes the package name\nassociated with the permission, i.e. the package that defined the\npermission.<li><p><strong>Group.</strong> The group name associated with the\npermission (if any). Several related permissions can often be grouped\ntogether.</ul></section></section><section id=subsec:signatures-tab class=level3 data-number=2.2.5><h3 data-number=2.2.5><span class=header-section-number>2.2.5</span>\n<a href=#toc:subsec:signatures-tab>Signatures Tab</a><a href=#subsec:signatures-tab class=anchor aria-hidden=true></a></h3><p><strong>Signatures</strong> are actually called signing information.\nAn application is signed with one or more signing keys by its developer\nbefore publishing it. The integrity of an application, i.e., whether the\napplication is from the actual developer and has not been modified by\nanother person, can be checked using the signing certificate included in\nthe APK files. This is because when an application is modified by an\nunauthorised entity, the application can longer be signed with the\noriginal signing keys since the signing keys are unknown to the entity.\nOne way to verify the integrity of an application is via the checksums\ngenerated from the certificates. If the developer supplies the checksums\nfor the signing certificates, they can be compared against the checksums\ngenerated in the <strong>Signatures</strong> tab to verify the\napplication. For example, if you have downloaded App Manager from GitHub\nor Telegram Channel, you can verify whether the application was actually\nreleased by me by simply matching the following <em>SHA256</em> checksum\nwith the one displayed in this tab:<pre><code>320c0c0fe8cef873f2b554cb88c837f1512589dcced50c5b25c43c04596760ab</code></pre><p>Several hashing algorithms are used to generate checksums in this\ntab. They include <em>MD5</em>, <em>SHA1</em>, <em>SHA256</em> and\n<em>SHA512</em>.<div class=\"amalert danger\"><p><strong><em>Caution.</em></strong><p>Signing information should be verified using a reliable hashing\nalgorithm, such as <em>SHA256</em>. DO NOT rely on <em>MD5</em> or\n<em>SHA1</em> checksums as they are known to generate the same checksums\nfor multiple certificates.</div></section><section id=subsec:uses-features-tab class=level3 data-number=2.2.6><h3 data-number=2.2.6><span class=header-section-number>2.2.6</span>\n<a href=#toc:subsec:uses-features-tab>Uses Features tab</a><a href=#subsec:uses-features-tab class=anchor aria-hidden=true></a></h3><p><strong>Uses Features</strong> tab lists the features declared by the\napplication, such as OpenGL ES, telephony, and leanback. Some features\ncan be required by the application, and some features can be optional.\nRequired features must be present in the system along with the required\nversion. Otherwise, any attempt to install the application will be\ndenied by the system. Colours used in this tab are explained in §<a href=#subsec:app-details-colour-codes data-reference-type=ref data-reference=subsec:app-details-colour-codes>2.2.1</a>.</section><section id=subsec:configurations-tab class=level3 data-number=2.2.7><h3 data-number=2.2.7><span class=header-section-number>2.2.7</span>\n<a href=#toc:subsec:configurations-tab>Configurations tab</a><a href=#subsec:configurations-tab class=anchor aria-hidden=true></a></h3><p><strong>Configurations</strong> tab lists the configurations required\nby the application, such as input method type (qwerty, 12 key), touch\nscreen type (finger, stylus, etc.), and navigation type (dial pad,\ntrackball, wheel). This tab is going to be empty for most\napplications.</section><section id=subsec:shared-libs-tab class=level3 data-number=2.2.8><h3 data-number=2.2.8><span class=header-section-number>2.2.8</span>\n<a href=#toc:subsec:shared-libs-tab>Shared Libraries Tab</a><a href=#subsec:shared-libs-tab class=anchor aria-hidden=true></a></h3><p><strong>Shared libraries</strong> tab lists the legacy JAR\ndependencies, any static shared library dependencies (currently, the\nonly known cases are the Chromium-based browsers and WebViews) as well\nas the JNI (Java native interface) libraries. For JNI libraries, it\nspecifies platform (x86/x86_64/ARM/AArch64), architecture (32/64 bit),\nobject type (shared object or executable), etc.</section></section><section id=sec:1-click-ops-page class=level2 data-number=2.3><h2 data-number=2.3><span class=header-section-number>2.3</span> <a href=#toc:sec:1-click-ops-page>1-Click Ops Page</a><a href=#sec:1-click-ops-page class=anchor aria-hidden=true></a></h2><p>This page is displayed on selecting the <a href=#subsubsec:main:1-click-ops>1-Click Ops option</a> in the <a href=#subsec:main-page-options-menu>main menu</a>.<section id=subsec:block-unblock-trackers class=level3 data-number=2.3.1><h3 data-number=2.3.1><span class=header-section-number>2.3.1</span>\n<a href=#toc:subsec:block-unblock-trackers>Block/Unblock\nTrackers</a><a href=#subsec:block-unblock-trackers class=anchor aria-hidden=true></a></h3><p>This option can be used to block or unblock the ad/tracker components\nfrom the installed applications. On selecting this option, App Manager\nwill ask if it should list trackers from all the applications or only\nfrom the user applications. Novice users should avoid blocking trackers\nfrom the system applications in order to avoid bad consequences. After\nthat, a multi-choice dialog box will appear where it is possible to\nexclude one or more applications from this operation. The changes are\napplied immediately on pressing the <em>block</em> or <em>unblock</em>\nbutton.<div class=\"amalert warning\"><p><strong><em>Notice.</em></strong><p>Certain applications may not function as expected after blocking\ntheir trackers. If that is the case, remove the blocking rules all at\nonce or one by one in the component tabs of the <a href=#sec:app-details-page>App Details page</a> for the corresponding\napplication.</div><div class=seealso-inline><p><em>Ver também: <span><a href=#par:appdetails:blocking-trackers>App\nDetails Page: Blocking Trackers</a></span></em></div></section><section id=subsec:block-components-dots class=level3 data-number=2.3.2><h3 data-number=2.3.2><span class=header-section-number>2.3.2</span>\n<a href=#toc:subsec:block-components-dots>Block Components…</a><a href=#subsec:block-components-dots class=anchor aria-hidden=true></a></h3><p>This option can be used to block certain application components as\nspecified by their signatures. A signature of a component is the full\nname or partial name of the component. For safety, it is recommended to\nadd a <code>.</code> (dot) at the end of each partial signature, because\nthe underlying algorithm searches and matches the components in a greedy\nmanner. It is also possible to insert more than one signature in which\ncase all the signatures have to be separated by white spaces. Similar to\nthe option above, there is also an option to apply blocking to the\nsystem applications.<div class=\"amalert danger\"><p><strong><em>Caution.</em></strong><p>If you are not aware of the consequences of blocking applcations\ncomponents by their signatures, you should avoid using this option as it\nmay result in bootloop or soft brick, and you may have to apply factory\nreset as a result.</div></section><section id=subsec:set-mode-for-app-ops-dots class=level3 data-number=2.3.3><h3 data-number=2.3.3><span class=header-section-number>2.3.3</span>\n<a href=#toc:subsec:set-mode-for-app-ops-dots>Set Mode for App\nOps…</a><a href=#subsec:set-mode-for-app-ops-dots class=anchor aria-hidden=true></a></h3><p>This option can be used to configure certain <a href=#ch:app-ops>applcation operations</a> of all or selected\napplications. There are two fields. The first field can be used to\ninsert more than one app op constants (either names or values) separated\nby white spaces. It is not always possible to know in advance about all\nthe app op constants as they vary from device to device and from OS to\nOS. Desired app op constant can be found in the <em>App Ops</em> tab\nlocated in the <a href=#sec:app-details-page>App Details page</a>. The\nsecond field can be used to insert or select one of the <a href=#subsec:mode-constants>modes</a> that will be set against the\nspecified app ops.<div class=\"amalert danger\"><p><strong><em>Caution.</em></strong><p>Unless you are well-informed about app ops and the consequences of\nblocking them, you should avoid using this option.</div></section><section id=subsec:1-click-back-up class=level3 data-number=2.3.4><h3 data-number=2.3.4><span class=header-section-number>2.3.4</span>\n<a href=#toc:subsec:1-click-back-up>Back up</a><a href=#subsec:1-click-back-up class=anchor aria-hidden=true></a></h3><p>1-Click options for back up. As a precaution, it lists the affected\nbackups before performing any operation.<section id=back-up-all-apps. class=level5 data-number=2.3.4.0.1><h5 data-number=2.3.4.0.1><span class=header-section-number>2.3.4.0.1</span> Back up all apps.<a href=#back-up-all-apps. class=anchor aria-hidden=true></a></h5><p>Back up all the installed applications.</section><section id=redo-existing-backups. class=level5 data-number=2.3.4.0.2><h5 data-number=2.3.4.0.2><span class=header-section-number>2.3.4.0.2</span> Redo existing backups.<a href=#redo-existing-backups. class=anchor aria-hidden=true></a></h5><p>Back up all the installed applications that have a previous\nbackup.</section><section id=back-up-apps-without-backups. class=level5 data-number=2.3.4.0.3><h5 data-number=2.3.4.0.3><span class=header-section-number>2.3.4.0.3</span> Back up apps without\nbackups.<a href=#back-up-apps-without-backups. class=anchor aria-hidden=true></a></h5><p>Back up all the installed applications without a previous backup.</section><section id=verify-and-redo-backups. class=level5 data-number=2.3.4.0.4><h5 data-number=2.3.4.0.4><span class=header-section-number>2.3.4.0.4</span> Verify and redo\nbackups.<a href=#verify-and-redo-backups. class=anchor aria-hidden=true></a></h5><p>Verify the recently made backups of the installed applications and\nredo backup if necessary.</section><section id=back-up-apps-with-changes. class=level5 data-number=2.3.4.0.5><h5 data-number=2.3.4.0.5><span class=header-section-number>2.3.4.0.5</span> Back up apps with\nchanges.<a href=#back-up-apps-with-changes. class=anchor aria-hidden=true></a></h5><p>If an app has changed since the last backup, redo its backup. It\nchecks a number of indices including application version, last update\ndate, last launch date, integrity and file hashes. Directory hashes are\ntaken during the backup process and are stored in a database. On running\nthis operation, new hashes are taken and compared with the ones kept in\nthe database.</section></section><section id=subsec:1-click-restore class=level3 data-number=2.3.5><h3 data-number=2.3.5><span class=header-section-number>2.3.5</span>\n<a href=#toc:subsec:1-click-restore>Restore</a><a href=#subsec:1-click-restore class=anchor aria-hidden=true></a></h3><p>1-Click options for restore. As a precaution, it lists the affected\nbackups before performing any operation.<section id=restore-all-apps. class=level5 data-number=2.3.5.0.1><h5 data-number=2.3.5.0.1><span class=header-section-number>2.3.5.0.1</span> Restore all apps.<a href=#restore-all-apps. class=anchor aria-hidden=true></a></h5><p>Restore <em>base backup</em> of all the backed up applications.</section><section id=restore-not-installed-apps. class=level5 data-number=2.3.5.0.2><h5 data-number=2.3.5.0.2><span class=header-section-number>2.3.5.0.2</span> Restore not installed\napps.<a href=#restore-not-installed-apps. class=anchor aria-hidden=true></a></h5><p>Restore <em>base backup</em> of all the backed up applications that\nare not currently installed.</section><section id=restore-latest-backups. class=level5 data-number=2.3.5.0.3><h5 data-number=2.3.5.0.3><span class=header-section-number>2.3.5.0.3</span> Restore latest backups.<a href=#restore-latest-backups. class=anchor aria-hidden=true></a></h5><p>Restore <em>base backup</em> of already installed applications whose\nversion codes are higher than the installed version code.</section></section><section id=subsec:trim-caches-in-all-apps class=level3 data-number=2.3.6><h3 data-number=2.3.6><span class=header-section-number>2.3.6</span>\n<a href=#toc:subsec:trim-caches-in-all-apps>Trim Caches in All\nApps</a><a href=#subsec:trim-caches-in-all-apps class=anchor aria-hidden=true></a></h3><p>Delete caches from all applications, including Android system. During\nthis operation, caches of all the running applications may not be\ncleared as expected.</section></section><section id=sec:profiles-page class=level2 data-number=2.4><h2 data-number=2.4><span class=header-section-number>2.4</span> <a href=#toc:sec:profiles-page>Profiles Page</a><a href=#sec:profiles-page class=anchor aria-hidden=true></a></h2><p>Profiles page can be accessed from the <a href=#subsec:main-page-options-menu>options-menu</a> in the main page.\nIt primarily displays a list of configured profiles along with the\ntypical options to perform operations on them. New profiles can also be\nadded using the <em>plus</em> button at the bottom-right corner.\nProfiles can be imported, duplicated or deleted. Clicking on a profile\nitem opens its <a href=#sec:profile-page>profile page</a>.<section id=subsec:profiles-options-menu class=level3 data-number=2.4.1><h3 data-number=2.4.1><span class=header-section-number>2.4.1</span>\n<a href=#toc:subsec:profiles-options-menu>Options Menu</a><a href=#subsec:profiles-options-menu class=anchor aria-hidden=true></a></h3><p>The three-dots menu in the top-right corner opens the global option\nmenu. It has an option to import an existing profile that was previously\nexported from App Manager.<p>Long clicking on any profile item brings up another options-menu. It\noffers the following options:<ul class=incremental><li><p><strong>Apply now….</strong> This option can be used to apply the\nprofile directly. When clicked, a dialog is displayed where it is\npossible to select a <a href=#subsubsec:profile-state>profile\nstate</a>. On selecting one of the states, the profile will be applied\nimmediately.<li><p><strong>Delete.</strong> Clicking on this option will remove the\nprofile immediately without a warning.<li><p><strong>Duplicate.</strong> This option can be used to duplicate\nthe profile. When clicked, a dialog is displayed where it is possible to\nset a name for the new profile. On clicking “OK”, the <a href=#sec:profile-page>profile page</a> will be loaded by duplicating\nall the configurations that this profile have. However, the profile will\nnot be saved until it is saved manually.<li><p><strong>Copy profile ID.</strong> This option is used to copy the\nunique profile ID of the profile. The profile ID can be used to <a href=#subsec:triggering-a-profile>trigger the profile</a> from a\nthird-party application.<li><p><strong>Export.</strong> Export the profile to an external\nstorage. Profiles exported this way can be imported via the\n<em>import</em> option as mentioned above.<li><p><strong>Create shortcut.</strong> This option can be used to\ncreate a shortcut for the profile. There are two options:\n<em>Simple</em> and <em>Advanced</em>. When configured with the latter\noption, it prompts the user to select a profile state when the shortcut\nis invoked. The former option, on the other hand, always uses the\ndefault state that was configured when the profile was last\nsaved.</ul></section></section><section id=sec:profile-page class=level2 data-number=2.5><h2 data-number=2.5><span class=header-section-number>2.5</span> <a href=#toc:sec:profile-page>Profile Page</a><a href=#sec:profile-page class=anchor aria-hidden=true></a></h2><p>Profile page displays the configurations for a profile. It also\noffers the options to edit them.<section id=subsec:profile-options-menu class=level3 data-number=2.5.1><h3 data-number=2.5.1><span class=header-section-number>2.5.1</span>\n<a href=#toc:subsec:profile-options-menu>Options Menu</a><a href=#subsec:profile-options-menu class=anchor aria-hidden=true></a></h3><p>The three dots menu in the top-right corner opens the options-menu.\nIt contains several options such as–<ul class=incremental><li><p><strong>Apply.</strong> This option can be used to apply the\nprofile directly. When clicked, a dialog is displayed where it is\npossible to select a <a href=#subsubsec:profile-state>profile\nstate</a>. On selecting one of the states, the profile will be applied\nimmediately.<div class=\"amalert tip\"><p><strong><em>Notice.</em></strong><p>When you apply a profile, if some packages do not match the criteria,\nthey will simply be ignored.</div><li><p><strong>Save.</strong> Save changes to the profile.<li><p><strong>Discard.</strong> Discard any modifications made since\nthe last time it was saved.<li><p><strong>Delete.</strong> Clicking on this option will remove the\nprofile immediately without a warning.<li><p><strong>Duplicate.</strong> This option can be used to duplicate\nthe profile. When clicked, a dialog is displayed where it is possible to\nset a name for the new profile. On clicking “OK”, this page will be\nreloaded by duplicating all the configurations that this profile have.\nHowever, the new profile will not be saved until it is saved\nmanually.<li><p><strong>Create shortcut.</strong> This option can be used to\ncreate a shortcut for the profile. There are two options:\n<em>Simple</em> and <em>Advanced</em>. When configured with the latter\noption, it prompts the user to select a profile state when the shortcut\nis invoked. The former option, on the other hand, always uses the\ndefault state that was configured when the profile was last\nsaved.</ul></section><section id=subsec:profile-apps-tab class=level3 data-number=2.5.2><h3 data-number=2.5.2><span class=header-section-number>2.5.2</span>\n<a href=#toc:subsec:profile-apps-tab>Apps Tab</a><a href=#subsec:profile-apps-tab class=anchor aria-hidden=true></a></h3><p>Apps tab lists the packages configured for this profile. Packages can\nbe added or removed using the <em>plus</em> button located near the\nbottom of the screen. A package can also be removed by long clicking on\nit (in which case, a popup will be displayed with the only option,\n<em>delete</em>).</section><section id=subsec:profile-configurations-tab class=level3 data-number=2.5.3><h3 data-number=2.5.3><span class=header-section-number>2.5.3</span>\n<a href=#toc:subsec:profile-configurations-tab>Configurations\nTab</a><a href=#subsec:profile-configurations-tab class=anchor aria-hidden=true></a></h3><p>Configurations tab can be used to configure the selected\npackages.<section id=profile-id class=level4 data-number=2.5.3.1><h4 data-number=2.5.3.1><span class=header-section-number>2.5.3.1</span> Profile ID<a href=#profile-id class=anchor aria-hidden=true></a></h4><p>The unique ID for this profile, currently set based on the profile\nname. The profile ID can be used to <a href=#subsec:triggering-a-profile>trigger the profile</a> from a\nthird-party application.</section><section id=comment class=level4 data-number=2.5.3.2><h4 data-number=2.5.3.2><span class=header-section-number>2.5.3.2</span> Comment<a href=#comment class=anchor aria-hidden=true></a></h4><p>This is the text that will be displayed in the <a href=#sec:profiles-page>profiles page</a>. If not set, the current\nconfigurations will be displayed instead.</section><section id=subsubsec:profile-state class=level4 data-number=2.5.3.3><h4 data-number=2.5.3.3><span class=header-section-number>2.5.3.3</span> State<a href=#subsubsec:profile-state class=anchor aria-hidden=true></a></h4><p>Denotes how certain configured options will behave by default. For\ninstance, if <em>disable</em> option is turned on, the applications will\nbe disabled if the state is <em>on</em> and will be enabled if the state\nis <em>off</em>. Currently, it only supports <em>on</em> and\n<em>off</em> values.</section><section id=users class=level4 data-number=2.5.3.4><h4 data-number=2.5.3.4><span class=header-section-number>2.5.3.4</span> Users<a href=#users class=anchor aria-hidden=true></a></h4><p>Select users for which is the profile will be applied. All users are\nselected by default.</section><section id=components class=level4 data-number=2.5.3.5><h4 data-number=2.5.3.5><span class=header-section-number>2.5.3.5</span> Components<a href=#components class=anchor aria-hidden=true></a></h4><p>This behaves the same way as the <a href=#subsec:block-components-dots>Block Components…</a> option does\nin the 1-Click Ops page. However, the blocking here is only applied to\nthe selected packages. If the <a href=#subsubsec:profile-state>state</a> is <em>on</em>, the components\nwill be blocked, and if the state is <em>off</em>, the components will\nbe unblocked. The option can be disabled (regardless of the inserted\nvalues) by clicking on the <em>disabled</em> button on the input\ndialog.<div class=seealso-inline><p><em>Ver também: <span><a href=#subsec:faq:what-are-app-components>What are the app\ncomponents?</a></span></em></div></section><section id=app-ops class=level4 data-number=2.5.3.6><h4 data-number=2.5.3.6><span class=header-section-number>2.5.3.6</span> App Ops<a href=#app-ops class=anchor aria-hidden=true></a></h4><p>This behaves the same way as the <a href=#subsec:set-mode-for-app-ops-dots>Set Mode for App Ops…</a>\noption does in the 1-Click Ops page. However, the operation here is only\napplied to the selected packages. If the <a href=#subsubsec:profile-state>state</a> is <em>on</em>, the app ops\nwill be denied (i.e. ignored), and if the state is <em>off</em>, the app\nops will be allowed. The option can be disabled (regardless of the\ninserted values) by clicking on the <em>disable</em> button in the input\ndialog.</section><section id=permissions class=level4 data-number=2.5.3.7><h4 data-number=2.5.3.7><span class=header-section-number>2.5.3.7</span> Permissions<a href=#permissions class=anchor aria-hidden=true></a></h4><p>This option can be used to grant or revoke certain permissions from\nthe selected packages. Like others above, permissions must be separated\nby white spaces. If the <a href=#subsubsec:profile-state>state</a> is\n<em>on</em>, the permissions will be revoked, and if the state is\n<em>off</em>, the permissions will be allowed. The option can be\ndisabled (regardless of the inserted values) by clicking on the\n<em>disable</em> button in the input dialog.</section><section id=backuprestore class=level4 data-number=2.5.3.8><h4 data-number=2.5.3.8><span class=header-section-number>2.5.3.8</span> Backup/Restore<a href=#backuprestore class=anchor aria-hidden=true></a></h4><p>This option can be used to take a backup of the selected applications\nand its data or restore them. Two options are available here: <em>Backup\noptions</em> and <em>backup name</em>.<ul class=incremental><li><p><strong>Backup options.</strong> Same as the <a href=#subsec:backup-restore-backup-options>backup options</a> of the\nbackup/restore feature. If not set, the default options will be\nused.<li><p><strong>Backup name.</strong> Set a custom name for the backup.\nIf the backup name is set, each time a backup is made, it will be given\na unique name with backup-name as the suffix. This behaviour will be\nfixed in a future release. Leave this field empty for regular “base”\nbackups (also, make sure not to enable <em>backup multiple</em> in the\nbackup options).</ul><p>If the <a href=#subsubsec:profile-state>state</a> is <em>on</em>,\nthe packages will be backed up, and if the state is <em>off</em>, the\npackages will be restored. The option can be disabled by clicking on the\n<em>disable</em> button in the input dialog.</section><section id=export-blocking-rules class=level4 data-number=2.5.3.9><h4 data-number=2.5.3.9><span class=header-section-number>2.5.3.9</span> Export Blocking Rules<a href=#export-blocking-rules class=anchor aria-hidden=true></a></h4><div class=\"amalert danger\"><p><strong><em>Danger.</em></strong><p>This option is not yet implemented.</div></section><section id=freeze class=level4 data-number=2.5.3.10><h4 data-number=2.5.3.10><span class=header-section-number>2.5.3.10</span> Freeze<a href=#freeze class=anchor aria-hidden=true></a></h4><p>Allow freezing or unfreezing the selected packages depending on the\nvalue of the <a href=#subsubsec:profile-state>state</a>. If the state\nis <em>on</em>, the packages will be frozen, and if the state is\n<em>off</em>, they will be unfrozen.</section><section id=force-stop class=level4 data-number=2.5.3.11><h4 data-number=2.5.3.11><span class=header-section-number>2.5.3.11</span> Force-stop<a href=#force-stop class=anchor aria-hidden=true></a></h4><p>Allow the selected packages to be force-stopped.</section><section id=clear-cache class=level4 data-number=2.5.3.12><h4 data-number=2.5.3.12><span class=header-section-number>2.5.3.12</span> Clear Cache<a href=#clear-cache class=anchor aria-hidden=true></a></h4><p>Enable clearing cache for the selected packages.</section><section id=clear-data class=level4 data-number=2.5.3.13><h4 data-number=2.5.3.13><span class=header-section-number>2.5.3.13</span> Clear Data<a href=#clear-data class=anchor aria-hidden=true></a></h4><p>Enable clearing data for the selected packages.</section><section id=block-trackers class=level4 data-number=2.5.3.14><h4 data-number=2.5.3.14><span class=header-section-number>2.5.3.14</span> Block Trackers<a href=#block-trackers class=anchor aria-hidden=true></a></h4><p>Enable blocking or unblocking of the tracker components from the\nselected packages depending on the value of the <a href=#subsubsec:profile-state>state</a>. If the state is <em>on</em>,\nthe trackers will be blocked, and if the state is <em>off</em>, the\ntrackers will be unblocked.</section><section id=save-apk class=level4 data-number=2.5.3.15><h4 data-number=2.5.3.15><span class=header-section-number>2.5.3.15</span> Save APK<a href=#save-apk class=anchor aria-hidden=true></a></h4><p>Enable saving APK files at <code>AppManager/apks</code> (or in the\ndirectory selected in the settings page) of the selected packages.</section></section></section><section id=sec:settings-page class=level2 data-number=2.6><h2 data-number=2.6><span class=header-section-number>2.6</span> <a href=#toc:sec:settings-page>Settings Page</a><a href=#sec:settings-page class=anchor aria-hidden=true></a></h2><p>Settings page can be used to customise the behaviour of App\nManager.<section id=subsec:language class=level3 data-number=2.6.1><h3 data-number=2.6.1><span class=header-section-number>2.6.1</span>\n<a href=#toc:subsec:language>Language</a><a href=#subsec:language class=anchor aria-hidden=true></a></h3><p>Configure in-app language. App Manager currently supports 22\n(twenty-two) languages.</section><section id=subsec:appearance class=level3 data-number=2.6.2><h3 data-number=2.6.2><span class=header-section-number>2.6.2</span>\n<a href=#toc:subsec:appearance>Appearance</a><a href=#subsec:appearance class=anchor aria-hidden=true></a></h3><section id=subsubsec:app-theme class=level4 data-number=2.6.2.1><h4 data-number=2.6.2.1><span class=header-section-number>2.6.2.1</span> App Theme<a href=#subsubsec:app-theme class=anchor aria-hidden=true></a></h4><p>Configure in-app theme.</section><section id=subsubsec:pure-black-theme class=level4 data-number=2.6.2.2><h4 data-number=2.6.2.2><span class=header-section-number>2.6.2.2</span> Pure Black Theme<a href=#subsubsec:pure-black-theme class=anchor aria-hidden=true></a></h4><p>Whether to use a black background instead of the material themed\nbackground.</section><section id=subsubsec:layout-direction class=level4 data-number=2.6.2.3><h4 data-number=2.6.2.3><span class=header-section-number>2.6.2.3</span> Layout Direction<a href=#subsubsec:layout-direction class=anchor aria-hidden=true></a></h4><p>Change layout direction, either left to right or right to left. This\nis usually set using the selected language but not everybody prefers the\nsame direction.</section><section id=subsubsec:enable/disable-features class=level4 data-number=2.6.2.4><h4 data-number=2.6.2.4><span class=header-section-number>2.6.2.4</span> Enable/Disable Features<a href=#subsubsec:enable/disable-features class=anchor aria-hidden=true></a></h4><p>Enable or disable certain features in App Manager, such as<ul class=incremental><li><p><strong>Interceptor</strong><li><p><strong>Manifest viewer</strong><li><p><strong>Scanner</strong><li><p><strong>Package installer</strong><li><p><strong>Usage access.</strong> With this feature turned off, App\nManager will never ask for the <em>Usage Access</em>\npermission.<li><p><strong>Log viewer</strong><li><p><strong>App explorer.</strong> The “Explore” option will not be\navailable while trying to open an APK file.<li><p><strong>App info.</strong> The “App info” option displayed while\ntrying to open an APK file.<li><p><strong>Code Editor</strong><li><p><strong>VirusTotal</strong></ul></section></section><section id=subsec:privacy class=level3 data-number=2.6.3><h3 data-number=2.6.3><span class=header-section-number>2.6.3</span>\n<a href=#toc:subsec:privacy>Privacy</a><a href=#subsec:privacy class=anchor aria-hidden=true></a></h3><section id=subsubsec:screen-lock class=level4 data-number=2.6.3.1><h4 data-number=2.6.3.1><span class=header-section-number>2.6.3.1</span> Screen Lock<a href=#subsubsec:screen-lock class=anchor aria-hidden=true></a></h4><p>Lock App Manager using Android screen lock provided a screen lock is\nconfigured.<div class=\"amalert warning\"><p><strong><em>Warning.</em></strong><p>If screen lock is disabled in Android after enabling this setting,\nApp Manager will not open until it is enabled again.</div></section><section id=subsubsec:run-am-in-background class=level4 data-number=2.6.3.2><h4 data-number=2.6.3.2><span class=header-section-number>2.6.3.2</span> Run App Manager in the\nBackground<a href=#subsubsec:run-am-in-background class=anchor aria-hidden=true></a></h4><p>Whether to run App Manager in the background to reduce the\ninitialisation delay. On certain devices, this can also help if you’re\nfrequently disconnected from ADB.</section><section id=subsubsec:use-the-internet class=level4 data-number=2.6.3.3><h4 data-number=2.6.3.3><span class=header-section-number>2.6.3.3</span> Use the Internet<a href=#subsubsec:use-the-internet class=anchor aria-hidden=true></a></h4><p>Whether to activate the Internet features in App Manager. This\ncurrently include VirusTotal and Pithus scanning in the <a href=#sec:scanner-page>Scanner page</a>.</section><section id=subsubsec:auth-manager class=level4 data-number=2.6.3.4><h4 data-number=2.6.3.4><span class=header-section-number>2.6.3.4</span> Authorization Manager<a href=#subsubsec:auth-manager class=anchor aria-hidden=true></a></h4><p>This setting allows a third-party application to get access to\ncertain features, such as profiles.</section></section><section id=subsec:mode-of-operation class=level3 data-number=2.6.4><h3 data-number=2.6.4><span class=header-section-number>2.6.4</span>\n<a href=#toc:subsec:mode-of-operation>Mode of Operation</a><a href=#subsec:mode-of-operation class=anchor aria-hidden=true></a></h3><p>Mode of operation defines how App Manager works as a whole. It has\nthe following options:<ul class=incremental><li><p><strong>Auto.</strong> Let App Manager decide the suitable\noption. Although this is the default option, non-rooted users should use\nthe <em>no-root</em> mode.<li><p><strong>Root.</strong> Operate App Manager in root mode. App\nManager will fall back to <em>no-root</em> mode if root is not detected,\nor in rare cases when Binder communication through root is disabled\n(e.g. in <a href=https://github.com/MuntashirAkon/AppManager/issues/606>Phh\nSuperUser</a>).<li><p><strong>ADB over TCP.</strong> Operate App Manager in ADB mode\nvia <a href=#sec:adb-over-tcp>ADB over TCP</a>. App Manager will fall\nback to <em>no-root</em> mode if ADB over TCP is not enabled.<li><p><strong>Wireless debugging.</strong> Enable ADB via Wireless\nDebugging. It will try to connect to the configured port automatically\nat first. On failure, it will ask the user to either pair or connect to\nthe ADB daemon manually. App Manager will fall back to <em>no-root</em>\nmode if it fails to connect to the ADB daemon this way.<div class=\"amalert tip\"><p><strong><em>Info.</em></strong><p>This option is only displayed in devices running Android 11 or later\nas Wireless Debugging was introduced in Android 11.</div><li><p><strong>No-root.</strong> Operate App Manager in no-root mode.\nWhile App Manager performs better in this mode, all the root- or\nADB-specific features will be disabled.</ul><p>It also displays the actual mode of operation at the top. The actual\nmode of operations are <em>root</em>, <em>ABD</em> and\n<em>no-root</em>.<div class=\"amalert tip\"><p><strong><em>Notice.</em></strong><p>“Remote service” is only required for ADB users or when you use the\ncustom commands.</div></section><section id=subsec:apk-signing class=level3 data-number=2.6.5><h3 data-number=2.6.5><span class=header-section-number>2.6.5</span>\n<a href=#toc:subsec:apk-signing>APK Signing</a><a href=#subsec:apk-signing class=anchor aria-hidden=true></a></h3><section id=signature-schemes class=level4 data-number=2.6.5.1><h4 data-number=2.6.5.1><span class=header-section-number>2.6.5.1</span> Signature Schemes<a href=#signature-schemes class=anchor aria-hidden=true></a></h4><p>Configure the <a href=https://source.android.com/security/apksigning>signature\nschemes</a> to be used when APK signing is enabled. v1 and v2 signature\nschemes are enabled by default, but v3 should also be enabled to ensure\nproper security in Android 9 or later.</section><section id=signing-key class=level4 data-number=2.6.5.2><h4 data-number=2.6.5.2><span class=header-section-number>2.6.5.2</span> Signing Key<a href=#signing-key class=anchor aria-hidden=true></a></h4><p>Configure the signing key for signing APK files. Keys from an\nexisting KeyStore can be imported to App Manager, or a new key can be\ngenerated.<div class=\"amalert tip\"><p><strong><em>Tip.</em></strong><p>If you need to use the key in the future, it is recommended that you\ncreate a KeyStore yourself and import the key here. Without a proper\nbackup, keys generated within App Manager are at the risk of being\ndeleted.</div></section><section id=align-apk-files class=level4 data-number=2.6.5.3><h4 data-number=2.6.5.3><span class=header-section-number>2.6.5.3</span> Align APK Files<a href=#align-apk-files class=anchor aria-hidden=true></a></h4><p>Performs zip alignment when App Manager signs an APK file. Zip\nalignment stores the files in the APK file (which is actually a zip\nfile) in a way that a zip file reader can access the files quite easily\nusing random access instead of loading the entire APK file in the\nmemory, which results in the reduction of Android’s memory usage. Note\nthat this step is required if an application’s manifest has\n<code>extractNativeLibs</code> set to <code>true</code>.</section></section><section id=subsec:installer class=level3 data-number=2.6.6><h3 data-number=2.6.6><span class=header-section-number>2.6.6</span>\n<a href=#toc:subsec:installer>Installer</a><a href=#subsec:installer class=anchor aria-hidden=true></a></h3><p>Configure the default behaviour of the installer. You can also find\nmost of the settings by clicking on the <em>cog</em> icon when you\ninstall an application.<section id=install-location class=level4 data-number=2.6.6.1><h4 data-number=2.6.6.1><span class=header-section-number>2.6.6.1</span> Install Location<a href=#install-location class=anchor aria-hidden=true></a></h4><p>Define APK installation location. This can be one of <em>auto</em>,\n<em>internal only</em> and <em>prefer external</em>. In newer Android\nversions, selecting the last option does not guarantee that the\napplication will be installed in the external storage.</section><section id=block-trackers-1 class=level4 data-number=2.6.6.2><h4 data-number=2.6.6.2><span class=header-section-number>2.6.6.2</span> Block Trackers<a href=#block-trackers-1 class=anchor aria-hidden=true></a></h4><p>Whether to block the tracking components immediately after installing\nthe application.</section><section id=display-changes class=level4 data-number=2.6.6.3><h4 data-number=2.6.6.3><span class=header-section-number>2.6.6.3</span> Display Changes<a href=#display-changes class=anchor aria-hidden=true></a></h4><p>Whether to display changes in version, trackers, components,\npermissions, signatures, SDK, etc. in a version controlled style before\ninstalling the application if the application has already been\ninstalled.</section><section id=installer-app class=level4 data-number=2.6.6.4><h4 data-number=2.6.6.4><span class=header-section-number>2.6.6.4</span> Installer App<a href=#installer-app class=anchor aria-hidden=true></a></h4><p>Select the installer application. This is useful for applications\nthat explicitly checks the installer as a way to verify if the\napplication is installed legitimately. This only works for root or ADB\nusers.<div class=\"amalert tip\"><p><strong><em>Notice.</em></strong><p>While checking for the installer might seem a legitimate concern for\nan application, the Android framework already deals with this during the\ninstallation. Checking for the installer is simply the wrong way to\nprove the legitimacy of the source of an application.</div></section><section id=sign-apk class=level4 data-number=2.6.6.5><h4 data-number=2.6.6.5><span class=header-section-number>2.6.6.5</span> Sign APK<a href=#sign-apk class=anchor aria-hidden=true></a></h4><p>Whether to sign the APK files before installing the application. A\nsigning key has to be added or generated before this option can be\nenabled. This can be done in the <a href=#subsec:apk-signing>APK\nsigning</a> page.</section><section id=immediately-perform-dex-optimization class=level4 data-number=2.6.6.6><h4 data-number=2.6.6.6><span class=header-section-number>2.6.6.6</span> Immediately Perform DEX\nOptimization<a href=#immediately-perform-dex-optimization class=anchor aria-hidden=true></a></h4><p>Whether to perform DEX optimization immediately after installing the\napplication. This can be useful for heavy applications, such as the\ngaming applications.</section><section id=install-in-the-background class=level4 data-number=2.6.6.7><h4 data-number=2.6.6.7><span class=header-section-number>2.6.6.7</span> Install in the Background<a href=#install-in-the-background class=anchor aria-hidden=true></a></h4><p>Whether to always install applications in the background. A\nnotification will be issued once the installation is finished.</section></section><section id=subsec:backup/restore class=level3 data-number=2.6.7><h3 data-number=2.6.7><span class=header-section-number>2.6.7</span>\n<a href=#toc:subsec:backup/restore>Back up/Restore</a><a href=#subsec:backup/restore class=anchor aria-hidden=true></a></h3><p>Settings related to <a href=#sec:backup-restore>back\nup/restore</a>.<section id=compression-method class=level4 data-number=2.6.7.1><h4 data-number=2.6.7.1><span class=header-section-number>2.6.7.1</span> Compression method<a href=#compression-method class=anchor aria-hidden=true></a></h4><p>Set the compression method to be used during backups. App Manager\nsupports GZip, BZip2 and Zstandard compression methods, GZip being the\ndefault compression method. It doesn’t affect the restore of an existing\nbackup.</section><section id=subsubsec:settings-backup-options class=level4 data-number=2.6.7.2><h4 data-number=2.6.7.2><span class=header-section-number>2.6.7.2</span> Backup Options<a href=#subsubsec:settings-backup-options class=anchor aria-hidden=true></a></h4><p>Customise the <em>back up/restore dialog</em> displayed while taking\na backup.<div class=seealso-inline><p><em>Ver também: <span><a href=#subsec:backup-restore-backup-options>Backup\noptions</a></span></em></div></section><section id=backup-apps-with-android-keystore class=level4 data-number=2.6.7.3><h4 data-number=2.6.7.3><span class=header-section-number>2.6.7.3</span> Backup apps with Android\nKeyStore<a href=#backup-apps-with-android-keystore class=anchor aria-hidden=true></a></h4><p>Allow backup of applications that has entries in the Android\nKeyStore. This option is disabled by default because a few apps (such as\nSignal or Element) may crash if restored.</section><section id=subsubsec:settings-encryption class=level4 data-number=2.6.7.4><h4 data-number=2.6.7.4><span class=header-section-number>2.6.7.4</span> Encryption<a href=#subsubsec:settings-encryption class=anchor aria-hidden=true></a></h4><p>Set an encryption method for the backups. App Manager currently\nsupports OpenPGP (via <a href=https://f-droid.org/packages/org.sufficientlysecure.keychain/>OpenKeyChain</a>),\nAES, RSA and ECC. Like <a href=#subsec:apk-signing>APK signing</a>,\nThe AES, RSA and ECC keys are stored in the KeyStore and can be imported\nfrom other KeyStores.<div class=\"amalert danger\"><p><strong><em>Danger.</em></strong><p>For your own safety, it is not recommended generating RSA and ECC\nkeys inside App Manager. Instead, they should be imported from a\nKeyStore stored in a secure place.<br>In case of AES, the generated key should be stored in a secure place,\nsuch as in a password manager.</div></section><section id=subsubsec:backup-volume class=level4 data-number=2.6.7.5><h4 data-number=2.6.7.5><span class=header-section-number>2.6.7.5</span> Backup Volume<a href=#subsubsec:backup-volume class=anchor aria-hidden=true></a></h4><p>Select the storage where the backups will be stored. This is also\nwhere logs and exported APK files are saved.<div class=\"amalert tip\"><p><strong><em>Notice.</em></strong><p>The backup volume only specifies the storage, not the path. Backups\nare traditionally stored in the <code>AppManager</code> folder inside\nthe storage path. But when the path is selected using Storage Access\nFramework (SAF), the selected path or directory is used directly.</div></section><section id=import-backups class=level4 data-number=2.6.7.6><h4 data-number=2.6.7.6><span class=header-section-number>2.6.7.6</span> Import Backups<a href=#import-backups class=anchor aria-hidden=true></a></h4><p>Import backups from old and discontinued projects such as Titanium\nBackup, OAndBackup, and Swift Backup (version 3.0 to 3.2). The backups\nare not deleted after importing to prevent data loss in case the\nimported backups cannot be restored properly.</section></section><section id=subsec:rules class=level3 data-number=2.6.8><h3 data-number=2.6.8><span class=header-section-number>2.6.8</span>\n<a href=#toc:subsec:rules>Rules</a><a href=#subsec:rules class=anchor aria-hidden=true></a></h3><section id=subsubsec:instant-component-blocking class=level4 data-number=2.6.8.1><h4 data-number=2.6.8.1><span class=header-section-number>2.6.8.1</span> Instant Component\nBlocking<a href=#subsubsec:instant-component-blocking class=anchor aria-hidden=true></a></h4><p>By default, blocking rules are not applied unless they are applied\nexplicitly in <a href=#sec:app-details-page>the App Details page</a>\nfor any application. After enabling this option, all (old and new) rules\nare applied immediately for all applications without explicitly enabling\nblocking for an application.<div class=seealso-inline><p><em>Ver também: <span><a href=#subsec:faq:what-is-instant-component-blocking>FAQ: What is\ninstant component blocking?</a></span></em></div></section><section id=importexport-blocking-rules class=level4 data-number=2.6.8.2><h4 data-number=2.6.8.2><span class=header-section-number>2.6.8.2</span> Import/Export Blocking\nRules<a href=#importexport-blocking-rules class=anchor aria-hidden=true></a></h4><p>It is possible to import or export blocking rules within App Manager\nfor all applications. The types of rules (components, app ops or\npermissions) that should be imported or exported can also be selected.\nIt is also possible to import blocking rules from <a href=https://github.com/lihenggui/blocker>Blocker</a> and <a href=https://github.com/tuyafeng/Watt>Watt</a>. If it is necessary to\nexport blocking rules for a single application, the corresponding <a href=#sec:app-details-page>App Details page</a> can be used to export\nrules, or for multiple apps, <a href=#subsec:batch-operations>batch\noperations</a> can be used.<div class=seealso-inline><p><em>Ver também: <span><a href=#sec:rules-specification>Rules\nSpecification</a></span></em></div><section id=export class=level5 data-number=2.6.8.2.1><h5 data-number=2.6.8.2.1><span class=header-section-number>2.6.8.2.1</span> Export<a href=#export class=anchor aria-hidden=true></a></h5><p>Export blocking rules for all applications configured within App\nManager. This may include <a href=#subsec:faq:what-are-app-components>app components</a>, app ops\nand permissions based on the options selected in the multi-choice\noptions.</section><section id=import class=level5 data-number=2.6.8.2.2><h5 data-number=2.6.8.2.2><span class=header-section-number>2.6.8.2.2</span> Import<a href=#import class=anchor aria-hidden=true></a></h5><p>Import previously exported blocking rules from App Manager. Similar\nto export, this may include <a href=#subsec:faq:what-are-app-components>app components</a>, app ops\nand permissions based on the options selected in the multi-choice\noptions.</section><section id=par:import-existing-rules class=level5 data-number=2.6.8.2.3><h5 data-number=2.6.8.2.3><span class=header-section-number>2.6.8.2.3</span> Import Existing Rules<a href=#par:import-existing-rules class=anchor aria-hidden=true></a></h5><p>Add components disabled by other applications to App Manager. App\nManager only keeps track of the components disabled within App Manager.\nIf application components are blocked or disabled by other tools or\napplications, this option can be utilised to import them. On clicking\nthis option, App Manager will find the components potentially disabled\nby other applications or tools and list only the name of the\napplications along with the number of matched components. For safety,\nall the applications are unselected by default. They have to be selected\nmanually, and the blocking has to be re-applied via App Manager.<div class=\"amalert danger\"><p><strong><em>Caution.</em></strong><p>Be careful when using this tool as there can be many false positives.\nChoose only the applications that you are certain about.</div></section><section id=import-from-watt class=level5 data-number=2.6.8.2.4><h5 data-number=2.6.8.2.4><span class=header-section-number>2.6.8.2.4</span> Import from Watt<a href=#import-from-watt class=anchor aria-hidden=true></a></h5><p>Import configuration files from <a href=https://github.com/tuyafeng/Watt>Watt</a>, each file containing\nrules for a single package and file name being the name of the package\nwith <code>.xml</code> extension.<div class=\"amalert tip\"><p><strong><em>Tip.</em></strong><p>Location of configuration files in Watt:\n<code>/sdcard/Android/data/com.tuyafeng.watt/files/ifw</code></div></section><section id=import-from-blocker class=level5 data-number=2.6.8.2.5><h5 data-number=2.6.8.2.5><span class=header-section-number>2.6.8.2.5</span> Import from Blocker<a href=#import-from-blocker class=anchor aria-hidden=true></a></h5><p>Import blocking rules from <a href=https://github.com/lihenggui/blocker>Blocker</a>, each file\ncontaining rules for a single package. These files have a\n<code>.json</code> extension.</section></section><section id=remove-all-rules class=level4 data-number=2.6.8.3><h4 data-number=2.6.8.3><span class=header-section-number>2.6.8.3</span> Remove all rules<a href=#remove-all-rules class=anchor aria-hidden=true></a></h4><p>One-click option to remove all rules configured within App Manager.\nThis will enable all blocked components, app ops will be set to their\ndefault values and permissions will be granted.</section></section><section id=subsec:advanced class=level3 data-number=2.6.9><h3 data-number=2.6.9><span class=header-section-number>2.6.9</span>\n<a href=#toc:subsec:advanced>Advanced</a><a href=#subsec:advanced class=anchor aria-hidden=true></a></h3><section id=subsubsec:selected-users class=level4 data-number=2.6.9.1><h4 data-number=2.6.9.1><span class=header-section-number>2.6.9.1</span> Selected Users<a href=#subsubsec:selected-users class=anchor aria-hidden=true></a></h4><p>This option lets you control the users App Manager should operate on.\nApp Manager operates on all users in root or ADB mode by default.</section><section id=subsubsec:saved-apk-name-format class=level4 data-number=2.6.9.2><h4 data-number=2.6.9.2><span class=header-section-number>2.6.9.2</span> Saved APK Name Format<a href=#subsubsec:saved-apk-name-format class=anchor aria-hidden=true></a></h4><p>Defines the format of the APK name to be used while saving it via\nbatch operations or through profiles. App Manager offers some special\nkeywords enclosed inside <code>%</code> (percentage) signs and available\nbelow the input box. These keywords are:<ul class=incremental><li><p><strong><code>label</code>.</strong> Denotes the name or label of\nthe application. This can be localised to the configured language\ndepending on the app.<li><p><strong><code>package_name</code>.</strong> Denotes the name of\nthe package or application ID, the unique identifier that each\napplication has.<li><p><strong><code>version</code>.</strong> Denotes the current\nversion of the application extracted from its manifest.<li><p><strong><code>version_code</code>.</strong> Denotes the current\nversion code of the application that can be used to separate two\nversions of the same application.<li><p><strong><code>min_sdk</code>.</strong> Denotes the minimum SDK\n(i.e. Android framework version) that the application can operate on.\nThis data is only available since Android 7 (Nougat).<li><p><strong><code>target_sdk</code>.</strong> Denotes the SDK that\nthis application targets. The application can operate on higher SDK but\nonly in the compatibility mode.<li><p><strong><code>datetime</code>.</strong> Denotes the time and date\nwhen the APK is exported.</ul></section><section id=subsubsec:import/export-keystore class=level4 data-number=2.6.9.3><h4 data-number=2.6.9.3><span class=header-section-number>2.6.9.3</span> Import/Export Keystore<a href=#subsubsec:import/export-keystore class=anchor aria-hidden=true></a></h4><p>Import or export the KeyStore used by App Manager. This is a Bouncy\nCastle KeyStore with <code>bks</code> extension. Therefore, other\nKeyStore such as Java KeyStore (JKS) or PKCS #12 are not supported. If a\nkey is needed to be imported from such a KeyStore, the relevant options\nshould be should as specified above.</section></section><section id=subsec:device-info class=level3 data-number=2.6.10><h3 data-number=2.6.10><span class=header-section-number>2.6.10</span> <a href=#toc:subsec:device-info>About the device</a><a href=#subsec:device-info class=anchor aria-hidden=true></a></h3><p>Display Android version, security, CPU, GPU, battery, memory, screen,\nlanguages, user info, etc.</section></section><section id=sec:scanner-page class=level2 data-number=2.7><h2 data-number=2.7><span class=header-section-number>2.7</span> <a href=#toc:sec:scanner-page>Scanner Page</a><a href=#sec:scanner-page class=anchor aria-hidden=true></a></h2><p><strong>Scanner page</strong> appears after clicking on the\n<em>scanner</em> button in the <a href=#subsec:app-info-tab>App Info\ntab</a>. External APK files can also be opened for scanning from file\nmanagers, web browsers, etc.<p>It scans for trackers and libraries, and displays the number of\ntrackers and libraries as a summary. It also displays checksums of the\nAPK file as well as the signing certificates. If VirusTotal is\nconfigured in the settings, it also attempts to retrieve reports from\nVirusTotal, or uploads the APK file if it is not in the database. It\nalso display a link to the <a href=https://beta.pithus.org>Pithus</a>\nreport provided the Internet features are enabled.<div class=\"amalert danger\"><p><strong><em>Disclaimer.</em></strong><p>App Manager only scans an application statically without prejudice.\nThe application may provide the options for opting out, or in some\ncases, certain features of the tracker may not be used at all by the\napplication (e.g. F-Droid), or some applications may simply use them as\nplaceholders to prevent the breaking of certain features (e.g. Fennec\nF-Droid). <strong>The intention of the scanner is to give you an idea\nabout what the APK might contain. It should be taken as an initial step\nfor further investigations.</strong></div><p>Clicking on the first item (i.e. number of classes) opens a new page\ncontaining a list of tracker classes for the application. All classes\ncan also be viewed by clicking on the <em>Toggle Class Listing</em>\nmenu. The SMALI or Java version of the class can be viewed by simply\nclicking on an item.<div class=\"amalert tip\"><p><strong><em>Notice.</em></strong><p>Due to various limitations, it is not possible to scan all the\ncomponents of an APK file. This is especially true if an APK is highly\nobfuscated or packed. The scanner also does not check strings (or\nwebsite signatures).</div><p>The second item lists the number of trackers along with their names.\nClicking on the item displays a dialog containing the name of trackers,\nmatched signatures, and the number of classes against each signature.\nSome tracker names may have <span class=\"math inline\"><sup>2</sup></span> prefix which indicates that the\ntrackers are in the <a href=https://etip.exodus-privacy.eu.org>ETIP</a> stand-by list, i.e.,\nwhether they are actual trackers is still being investigated.<p>The third item lists the number of libraries along with their names.\nThe information are mostly taken from <a href=https://gitlab.com/IzzyOnDroid/repo>IzzyOnDroid repo</a>.<div class=seealso-inline><p><em>Ver também: <span><a href=#subsec:tracker-classes-versus-tracker-components>FAQ: Tracker\nclasses vs tracker components</a></span></em></div></section><section id=sec:interceptor-page class=level2 data-number=2.8><h2 data-number=2.8><span class=header-section-number>2.8</span> <a href=#toc:sec:interceptor-page>Interceptor Page</a><a href=#sec:interceptor-page class=anchor aria-hidden=true></a></h2><p>Interceptor can be used to intercept communication between\napplications using <code>Intent</code>. It works as a man-in-the-middle\nbetween the source and the destination applications. It offers a\nfeature-complete user interface for editing <code>Intent</code>s.<div class=\"amalert warning\"><p><strong><em>Warning.</em></strong><p>Interceptor only works for <em>implicit</em> intents where the <a href=#subsec:faq:what-are-app-components>app component</a> isn’t\nspecified.</div><div class=seealso><p><em>Ver também:</em><ul class=incremental><li><p><a href=https://developer.android.com/guide/components/intents-common>Common\nIntents</a><li><p><a href=https://developer.android.com/guide/components/intents-filters>Intents\nand Intent Filters</a></ul></div><section id=subsec:intent-filters class=level3 data-number=2.8.1><h3 data-number=2.8.1><span class=header-section-number>2.8.1</span>\n<a href=#toc:subsec:intent-filters>Intent Filters</a><a href=#subsec:intent-filters class=anchor aria-hidden=true></a></h3><p>Intent filters are used by the applications to specify the tasks they\nare able to perform or the tasks they are going to perform using other\napplications. For example, when you’re opening a PDF file using a file\nmanager, the file manager will try to find the applications to open the\nPDF with. To find the right applications, the file manager will create\nan Intent with filters such as the MIME type and ask the system to\nretrieve the applications capable of opening this filter. The system\nwill search through the Manifest of the installed applications to match\nthe filter and list the application components that are able to open\nthis filter (in our case the PDF). At this, either the file manager will\nopen the desired application component all by itself or use a system\nprovided option to open it. If multiple application components are able\nto open it and no default is set, you may get a prompt where you have to\nchoose the right application component.<section id=subsubsec:action class=level4 data-number=2.8.1.1><h4 data-number=2.8.1.1><span class=header-section-number>2.8.1.1</span> Action<a href=#subsubsec:action class=anchor aria-hidden=true></a></h4><p>Action specifies the generic action to perform such as\n<code>android.intent.action.VIEW</code>. Applications often declare the\nrelevant actions in the Manifest file to catch the desired Intents. The\naction is particularly useful for broadcast Intent where it plays a\nvital rule. In other cases, it works as an initial way to filter out the\nrelevant application components. Generic actions such as\n<code>android.intent.action.VIEW</code> and\n<code>android.intent.action.SEND</code> are widely used by applications.\nHence, setting this alone may match many application components.</section><section id=subsubsec:data class=level4 data-number=2.8.1.2><h4 data-number=2.8.1.2><span class=header-section-number>2.8.1.2</span> Data<a href=#subsubsec:data class=anchor aria-hidden=true></a></h4><p>Data is originally known as URI (Uniform Resource Identifier) defined\nin <a href=http://www.faqs.org/rfcs/rfc2396.html>RFC 2396</a>. It can\nbe web links, file location, or a special feature called\n<em>content</em>. Contents are an Android feature managed by the <a href=#subsubsec:providers>content providers</a>. Data are often\nassociated with a <a href=#subsubsec:mime-type>MIME type</a>.<p>Examples:<pre><code>http://search.disroot.org/?q=URI%20in%20Android%20scheme&amp;categories=general&amp;language=en-US\nhttps://developer.android.com/reference/android/net/Uri\nfile:///sdcard/AppManager.apk\nmailto:email@example.com\ncontent://io.github.muntashirakon.AppManager.provider/23485af89b08d87e898a90c7e/AppManager.apk</code></pre></section><section id=subsubsec:mime-type class=level4 data-number=2.8.1.3><h4 data-number=2.8.1.3><span class=header-section-number>2.8.1.3</span> MIME Type<a href=#subsubsec:mime-type class=anchor aria-hidden=true></a></h4><p>MIME type of the <a href=#subsubsec:data>data</a>. For example, if\nthe data field is set to <code>file:///sdcard/AppManager.apk</code>, the\nassociated MIME type can be\n<code>application/vnd.android.package-archive</code>.</section><section id=categories class=level4 data-number=2.8.1.4><h4 data-number=2.8.1.4><span class=header-section-number>2.8.1.4</span> Categories<a href=#categories class=anchor aria-hidden=true></a></h4><p>This is similar to <a href=#subsubsec:action>action</a> in the\nsense that it is also used by the system to filter application\ncomponents. This has no further benefits. Unlike <em>action</em>, there\ncan be more than one category. Clicking on the <em>plus</em> button next\nto the title allows adding more categories.</section><section id=flags class=level4 data-number=2.8.1.5><h4 data-number=2.8.1.5><span class=header-section-number>2.8.1.5</span> Flags<a href=#flags class=anchor aria-hidden=true></a></h4><p>Flags are useful in determining how system should behave during the\nlaunch or after the launch of an activity. This should not be touched as\nit requires some technical background. The <em>plus</em> button next to\nthe title can be used to add one or more flags.</section><section id=extras class=level4 data-number=2.8.1.6><h4 data-number=2.8.1.6><span class=header-section-number>2.8.1.6</span> Extras<a href=#extras class=anchor aria-hidden=true></a></h4><p>Extras are the key-value pairs used for supplying additional\ninformation to the destination component. More extras can be added using\nthe <em>plus</em> button next to the title.</section><section id=uri class=level4 data-number=2.8.1.7><h4 data-number=2.8.1.7><span class=header-section-number>2.8.1.7</span> URI<a href=#uri class=anchor aria-hidden=true></a></h4><p>Represents the entire Intent as a URI (e.g. <code>intent://…</code>).\nSome data cannot be converted to string, and as a result, they might not\nappear here.</section></section><section id=subsec:matching-activities class=level3 data-number=2.8.2><h3 data-number=2.8.2><span class=header-section-number>2.8.2</span>\n<a href=#toc:subsec:matching-activities>Matching Activities</a><a href=#subsec:matching-activities class=anchor aria-hidden=true></a></h3><p>List all the activity components that matches the Intent. This is\ninternally determined by the system (rather than App Manager). The\nlaunch button next to each component can be used to launch them directly\nfrom App Manager.</section><section id=subsec:interceptor-reset-to-default class=level3 data-number=2.8.3><h3 data-number=2.8.3><span class=header-section-number>2.8.3</span>\n<a href=#toc:subsec:interceptor-reset-to-default>Reset to\nDefault</a><a href=#subsec:interceptor-reset-to-default class=anchor aria-hidden=true></a></h3><p>Reset the Intent to its initial state.</section><section id=subsec:interceptor-send-edited-intent class=level3 data-number=2.8.4><h3 data-number=2.8.4><span class=header-section-number>2.8.4</span>\n<a href=#toc:subsec:interceptor-send-edited-intent>Send Edited\nIntent</a><a href=#subsec:interceptor-send-edited-intent class=anchor aria-hidden=true></a></h3><p>Resend the edited Intent to the destination application. This may\nopen a list of applications where the desired application is needed to\nbe selected. The result received from the target application will be\nsent to the source application. As a result, the source application will\nnot know if there was a man-in-the-middle.</section></section><section id=sec:shared-preferences-editor-page class=level2 data-number=2.9><h2 data-number=2.9><span class=header-section-number>2.9</span> <a href=#toc:sec:shared-preferences-editor-page>Shared Preferences Editor\nPage</a><a href=#sec:shared-preferences-editor-page class=anchor aria-hidden=true></a></h2><p>Shared preferences can be edited in this page. Clicking any item on\nthe list opens the edit dialog where the item can be edited. The\nfloating action button in the bottom-right corner can be used to add a\nnew item. To save or delete the file, or to discard current changes, the\nrespective options in the menu can be used.</section></section><section id=ch:guides class=level1 data-number=3><h1 data-number=3><span class=header-section-number>3</span> <a href=#toc:ch:guides>Guides</a><a href=#ch:guides class=anchor aria-hidden=true></a></h1><section id=sec:adb-over-tcp class=level2 data-number=3.1><h2 data-number=3.1><span class=header-section-number>3.1</span> <a href=#toc:sec:adb-over-tcp>ADB over TCP</a><a href=#sec:adb-over-tcp class=anchor aria-hidden=true></a></h2><p>Many root-only features can still be used by enabling ADB over TCP.\nTo do that, a PC or Mac is required with Android platform-tools\ninstalled, and an Android phone with developer options & USB\ndebugging enabled.<div class=\"amalert tip\"><p><strong><em>Root users.</em></strong><p>If superuser permission has been granted to App Manager, it can\nalready execute privileged code without any problem. <strong>Therefore,\nroot users do not need to enable ADB over TCP.</strong> But if you\ninsist on using ADB over TCP, you must revoke superuser permission for\nApp Manager.</div><div class=seealso-inline><p><em>Ver também: <span><a href=#sec:faq:adb-over-tcp>FAQ: ADB over\nTCP</a></span></em></div><section id=subsec:enable-developer-options class=level3 data-number=3.1.1><h3 data-number=3.1.1><span class=header-section-number>3.1.1</span>\n<a href=#toc:subsec:enable-developer-options>Enable developer\noptions</a><a href=#subsec:enable-developer-options class=anchor aria-hidden=true></a></h3><section id=subsubsec:location-of-developer-options class=level4 data-number=3.1.1.1><h4 data-number=3.1.1.1><span class=header-section-number>3.1.1.1</span> Location of developer\noptions<a href=#subsubsec:location-of-developer-options class=anchor aria-hidden=true></a></h4><p><strong>Developer options</strong> is located in Android\n<strong>Settings</strong>, either directly near the bottom of the page\n(in most ROMs) or under some other settings, such as\n<strong>System</strong> (Google Pixel, Lineage OS, Asus Zenfone 8.0+),\n<strong>Additional Settings</strong> (Xiaomi MIUI, Oppo ColorOS),\n<strong>More Settings</strong> (Vivo FuntouchOS), <strong>More</strong>\n(ZTE Nubia). Unlike other options, it is not visible until explicitly\nenabled by the user. If it is already enabled, you can use the search\nbox in Android <strong>Settings</strong> to locate it as well.</section><section id=how-to-enable-developer-options class=level4 data-number=3.1.1.2><h4 data-number=3.1.1.2><span class=header-section-number>3.1.1.2</span> How to enable developer\noptions<a href=#how-to-enable-developer-options class=anchor aria-hidden=true></a></h4><p>This option is available within Android <strong>Settings</strong> as\nwell but like the location of the developer options, it also differs\nfrom device to device. But in general, you have to find <strong>Build\nnumber</strong> (or <strong>MIUI version</strong> for MIUI ROMs and\n<strong>Software version</strong> for Vivo FuntouchOS,\n<strong>Version</strong> for Oppo ColorOS) and tap it at least 7 (seven)\ntimes until you finally get a message saying <em>You are now a\ndeveloper</em> (you may be prompted to insert pin/password/pattern or\nsolve captchas at this point). In most devices, it is located at the\nbottom of the settings page, inside <strong>About Phone</strong>. But\nthe best way to find it is to use the search box.</section></section><section id=subsec:enable-usb-debugging class=level3 data-number=3.1.2><h3 data-number=3.1.2><span class=header-section-number>3.1.2</span>\n<a href=#toc:subsec:enable-usb-debugging>Enable USB debugging</a><a href=#subsec:enable-usb-debugging class=anchor aria-hidden=true></a></h3><p>After <a href=#subsubsec:location-of-developer-options>locating the\ndeveloper options</a>, enable <strong>Developer option</strong> (if not\nalready). After that, scroll down a bit until you will find the option\n<strong>USB debugging</strong>. Use the toggle button on the right-hand\nside to enable it. At this point, you may get an alert prompt where you\nmay have to click <em>OK</em> to actually enable it. You may also have\nto enable some other options depending on device vendor and ROM. Here\nare some examples:<section id=xiaomi-miui class=level4 data-number=3.1.2.1><h4 data-number=3.1.2.1><span class=header-section-number>3.1.2.1</span> Xiaomi (MIUI)<a href=#xiaomi-miui class=anchor aria-hidden=true></a></h4><p>Enable <strong>USB debugging (Security settings)</strong> as\nwell.</section><section id=huawei-emui class=level4 data-number=3.1.2.2><h4 data-number=3.1.2.2><span class=header-section-number>3.1.2.2</span> Huawei (EMUI)<a href=#huawei-emui class=anchor aria-hidden=true></a></h4><p>Enable <strong>Allow ADB debugging in charge only mode</strong> as\nwell. When connecting to your PC or Mac, you may get a prompt saying\n<strong>Allow access to device data?</strong> in which case click\n<strong>YES, ALLOW ACCESS</strong>.<div class=\"amalert tip\"><p><strong><em>Notice.</em></strong><p>Often the <strong>USB debugging</strong> mode could be disabled\nautomatically by the system. If that’s the case, repeat the above\nprocedure.</div></section><section id=realme class=level4 data-number=3.1.2.3><h4 data-number=3.1.2.3><span class=header-section-number>3.1.2.3</span> Realme<a href=#realme class=anchor aria-hidden=true></a></h4><p>Depending on the device and the version of operating system, you have\nto enable <strong>Disable Permission Monitoring</strong>, or <strong>USB\ndebugging (Security settings)</strong> along with <strong>Install via\nUSB</strong>.</section><section id=oneplus-oxygen-os class=level4 data-number=3.1.2.4><h4 data-number=3.1.2.4><span class=header-section-number>3.1.2.4</span> OnePlus (Oxygen OS)<a href=#oneplus-oxygen-os class=anchor aria-hidden=true></a></h4><p>Depending on the device and the version of operating system, you have\nto enable <strong>Disable Permission Monitoring</strong>.</section><section id=lg class=level4 data-number=3.1.2.5><h4 data-number=3.1.2.5><span class=header-section-number>3.1.2.5</span> LG<a href=#lg class=anchor aria-hidden=true></a></h4><p>Make sure you have <strong>USB tethering</strong> enabled.</section><section id=troubleshooting class=level4 data-number=3.1.2.6><h4 data-number=3.1.2.6><span class=header-section-number>3.1.2.6</span> Troubleshooting<a href=#troubleshooting class=anchor aria-hidden=true></a></h4><p>In case <strong>USB Debugging</strong> is greyed out, you can do the\nfollowing:<ol class=incremental><li><p>Make sure you enabled USB debugging before connecting your phone\nto the PC or Mac via USB cable<li><p>Enable USB tethering after connecting to PC or Mac via USB\ncable<li><p>(For Samsung) If your device is running KNOX, you may have to\nfollow some additional steps. See official documentations or consult\nsupport for further assistant</ol></section></section><section id=subsec:setup-adb-on-pc-or-mac class=level3 data-number=3.1.3><h3 data-number=3.1.3><span class=header-section-number>3.1.3</span>\n<a href=#toc:subsec:setup-adb-on-pc-or-mac>Setup ADB on PC or\nMac</a><a href=#subsec:setup-adb-on-pc-or-mac class=anchor aria-hidden=true></a></h3><p>In order to enable ADB over TCP, you have to set up ADB in your PC or\nMac. <strong><em>Lineage OS users can skip to §<a href=#subsubsec:lineage-os data-reference-type=ref data-reference=subsubsec:lineage-os>3.1.4.1</a>.</em></strong><section id=windows class=level4 data-number=3.1.3.1><h4 data-number=3.1.3.1><span class=header-section-number>3.1.3.1</span> Windows<a href=#windows class=anchor aria-hidden=true></a></h4><ol class=incremental><li><p>Download the latest version of <a href=https://dl.google.com/android/repository/platform-tools-latest-windows.zip>Android\nSDK Platform-Tools</a> for Windows<li><p>Extract the contents of the zip file into any directory (such as\n<code>C:\\</code><span><code>adb</code></span>) and navigate to that\ndirectory using <em>Explorer</em><li><p>Open <strong>Command Prompt</strong>,\n<strong>PowerShell</strong>, or <strong>Terminal</strong> from this\ndirectory. You can do it manually from the start menu or by holding\n<code>Shift</code> and right clicking within the directory in <em>File\nExplorer</em> and then clicking either on <em>Open command window\nhere</em>, or <em>Open PowerShell window here</em> (depending on what\nyou have installed). You can now access ADB by typing <code>adb</code>\n(Command Prompt) or <code>./adb</code> (PowerShell). Do not close this\nwindow yet.</ol><div class=\"amalert tip\"><p><strong><em>Tip.</em></strong><p>If you have <a href=https://learn.microsoft.com/en-us/windows/package-manager/winget/>WinGet</a>\ninstalled, you can install ADB using the following command:<div class=sourceCode id=cb3 data-frame=lines><pre class=\"sourceCode bash\"><code class=\"sourceCode bash\"><span id=cb3-1><a href=#cb3-1 aria-hidden=true tabindex=-1></a><span class=ex>winget</span> install <span class=at>--id</span> Google.PlatformTools</span></code></pre></div><p>After that, you can simply type <code>adb</code> to access ADB.</div></section><section id=macos class=level4 data-number=3.1.3.2><h4 data-number=3.1.3.2><span class=header-section-number>3.1.3.2</span> macOS<a href=#macos class=anchor aria-hidden=true></a></h4><ol class=incremental><li><p>Download the latest version of <a href=https://dl.google.com/android/repository/platform-tools-latest-darwin.zip>Android\nSDK Platform-Tools</a> for macOS<li><p>Extract the contents of the zip file into a directory by clicking\non it. After that, navigate to that directory using <em>Finder</em> and\nlocate <code>adb</code><li><p>Open <strong>Terminal</strong> using <em>Launchpad</em> or\n<em>Spotlight</em> and drag-and-drop <code>adb</code> from the\n<em>Finder</em> window into the <em>Terminal</em> window. Do not close\nthe <em>Terminal</em> window yet</ol><div class=\"amalert tip\"><p><strong><em>Tip.</em></strong><p>If you have <a href=https://brew.sh>Homebrew</a> installed, you can\ninstall ADB using the following command:<div class=sourceCode id=cb4 data-frame=lines><pre class=\"sourceCode bash\"><code class=\"sourceCode bash\"><span id=cb4-1><a href=#cb4-1 aria-hidden=true tabindex=-1></a><span class=ex>brew</span> install <span class=at>--cask</span> android-platform-tools</span></code></pre></div><p>After that, you can simply type <code>adb</code> in any\n<em>Terminal</em> window to access ADB.</div></section><section id=linux class=level4 data-number=3.1.3.3><h4 data-number=3.1.3.3><span class=header-section-number>3.1.3.3</span> Linux<a href=#linux class=anchor aria-hidden=true></a></h4><ol class=incremental><li><p>In your favourite terminal emulator, run the following\ncommand:<div class=sourceCode id=cb5 data-frame=lines data-autogobble><pre class=\"sourceCode bash\"><code class=\"sourceCode bash\"><span id=cb5-1><a href=#cb5-1 aria-hidden=true tabindex=-1></a><span class=bu>cd</span> ~/Downloads <span class=kw>&amp;&amp;</span> <span class=ex>curl</span> <span class=at>-o</span> platform-tools.zip <span class=at>-L</span> <span class=dt>\\</span></span>\n<span id=cb5-2><a href=#cb5-2 aria-hidden=true tabindex=-1></a>https://dl.google.com/android/repository/platform-tools-latest-linux.zip <span class=kw>&amp;&amp;</span> <span class=dt>\\</span></span>\n<span id=cb5-3><a href=#cb5-3 aria-hidden=true tabindex=-1></a><span class=fu>unzip</span> platform-tools.zip <span class=kw>&amp;&amp;</span> <span class=fu>rm</span> platform-tools.zip <span class=kw>&amp;&amp;</span> <span class=bu>cd</span> platform-tools</span></code></pre></div><li><p>If it is successful, you can simply type <code>./adb</code> in\nthe in <em>same</em> terminal emulator window or type\n<code>~/Downloads/platform-tools/adb</code> in any terminal emulator to\naccess ADB.</ol></section></section><section id=subsec:configure-adb-over-tcp class=level3 data-number=3.1.4><h3 data-number=3.1.4><span class=header-section-number>3.1.4</span>\n<a href=#toc:subsec:configure-adb-over-tcp>Configure ADB over\nTCP</a><a href=#subsec:configure-adb-over-tcp class=anchor aria-hidden=true></a></h3><section id=subsubsec:lineage-os class=level4 data-number=3.1.4.1><h4 data-number=3.1.4.1><span class=header-section-number>3.1.4.1</span> Lineage OS 17.1 and\nEarlier<a href=#subsubsec:lineage-os class=anchor aria-hidden=true></a></h4><p>Lineage OS (or its derivatives) users can directly enable ADB over\nTCP using the developer options. To enable that, go to the\n<strong>Developer options</strong>, scroll down until you find\n<strong>ADB over Network</strong>. Now, use the toggle button on the\nright-hand side to enable it and skip to §<a href=#subsubsec:adb-mode-in-app-manager data-reference-type=ref data-reference=subsubsec:adb-mode-in-app-manager>3.1.4.3</a>.<div class=\"amalert warning\"><p><strong><em>Warning.</em></strong><p>You can turn off <strong>ADB over Network</strong> in developer\noptions, but turning off this option will also stop App Manager’s remote\nserver. So, turn it off only when you’re not going to use App Manager in\nADB over TCP mode.</div></section><section id=subsubsec:enable-adb-over-tcp-via-pc-or-mac class=level4 data-number=3.1.4.2><h4 data-number=3.1.4.2><span class=header-section-number>3.1.4.2</span> Enable ADB over TCP via PC\nor Mac<a href=#subsubsec:enable-adb-over-tcp-via-pc-or-mac class=anchor aria-hidden=true></a></h4><p>For other ROMs, you can do this using the command\nprompt/PowerShell/terminal emulator that you’ve opened in the step 3 of\nthe previous section. In this section, I will use <code>adb</code> to\ndenote <code>./adb</code>, <code>adb</code> or any other command that\nyou needed to use based on your platform and software in the previous\nsection.<ol class=incremental><li><p>Connect your device to your PC or Mac using a USB cable. For some\ndevices, it is necessary to turn on <em>File transfer mode (MTP)</em> as\nwell<li><p>To confirm that everything is working as expected, type\n<code>adb devices</code> in your terminal. If your device is connected\nsuccessfully, you will see something like this:<pre><code>List of devices attached\nxxxxxxxx  device</code></pre><div class=\"amalert tip\"><p><strong><em>Notice.</em></strong><p>In some Android phones, an alert prompt will be appeared with a\nmessage <strong>Allow USB Debugging</strong> in which case, check\n<em>Always allow from this computer</em> and click\n<strong>Allow</strong>.</div><li><p>Finally, run the following command to enable ADB over TCP:<div class=sourceCode id=cb7 data-frame=lines data-autogobble><pre class=\"sourceCode bash\"><code class=\"sourceCode bash\"><span id=cb7-1><a href=#cb7-1 aria-hidden=true tabindex=-1></a><span class=ex>adb</span> tcpip 5555</span></code></pre></div></ol><div class=\"amalert danger\"><p><strong><em>Danger.</em></strong><p>You cannot disable developer options or USB debugging after enabling\nADB over TCP.</div></section><section id=subsubsec:adb-mode-in-app-manager class=level4 data-number=3.1.4.3><h4 data-number=3.1.4.3><span class=header-section-number>3.1.4.3</span> Enable ADB mode in App\nManager<a href=#subsubsec:adb-mode-in-app-manager class=anchor aria-hidden=true></a></h4><p>After enabling ADB over TCP, relaunch App Manager. App Manager should\ndetect ADB mode automatically. If it cannot, you can change the mode of\noperation to ADB over TCP in the <a href=#subsec:mode-of-operation>settings page</a>. There, you can also\nverify whether App Manager has correctly detected ADB as indicated by\nthe <em>inferred mode</em>.<div class=\"amalert tip\"><p><strong><em>Notice.</em></strong><p>In some Android devices, the USB cable is needed to be disconnected\nfrom the PC before connecting to App Manager.</div><div class=\"amalert warning\"><p><strong><em>Warning.</em></strong><p>ADB over TCP will be disabled after a reboot. In that case, you have\nto follow §<a href=#subsubsec:enable-adb-over-tcp-via-pc-or-mac data-reference-type=ref data-reference=subsubsec:enable-adb-over-tcp-via-pc-or-mac>3.1.4.2</a>\nagain.</div></section></section></section><section id=sec:wireless-debugging class=level2 data-number=3.2><h2 data-number=3.2><span class=header-section-number>3.2</span> <a href=#toc:sec:wireless-debugging>Wireless Debugging</a><a href=#sec:wireless-debugging class=anchor aria-hidden=true></a></h2><p>If you are running Android 11 or later and capable of connecting to a\nWi-Fi network for, at least, a few moments, Wireless Debugging is the\nrecommended approach as it offers more protection than <a href=#sec:adb-over-tcp>ADB over TCP</a>. It requires two steps:<ol class=incremental><li><p><strong>ADB pairing.</strong> The initial and a bit complex step\nfor a novice user. Fortunately, this step is not required all the\ntime.<li><p><strong>Connecting to ADB.</strong> Needs to be done every time\nyou reboot your phone. App Manager can also automate this step in most\ndevices.</ol><section id=subsec:enable-developer-options-and-usb-debugging class=level3 data-number=3.2.1><h3 data-number=3.2.1><span class=header-section-number>3.2.1</span>\n<a href=#toc:subsec:enable-developer-options-and-usb-debugging>Enable\ndeveloper options and USB Debugging</a><a href=#subsec:enable-developer-options-and-usb-debugging class=anchor aria-hidden=true></a></h3><p>See §<a href=#subsec:enable-developer-options data-reference-type=ref data-reference=subsec:enable-developer-options>3.1.1</a> and §<a href=#subsec:enable-usb-debugging data-reference-type=ref data-reference=subsec:enable-usb-debugging>3.1.2</a>.</section><section id=subsec:enable-wireless-debugging class=level3 data-number=3.2.2><h3 data-number=3.2.2><span class=header-section-number>3.2.2</span>\n<a href=#toc:subsec:enable-wireless-debugging>Enable Wireless\nDebugging</a><a href=#subsec:enable-wireless-debugging class=anchor aria-hidden=true></a></h3><p>In the <strong>Developer options</strong> page, find <strong>Wireless\ndebugging</strong> and click to open it. In the new page, turn on\n<em>Use wireless debugging</em>. Depending on the operating system, you\nmight see a dialog prompt asking you to verify your decision. If that is\nthe case, click <em>Allow</em>.<div class=\"amalert tip\"><p><strong><em>Tip.</em></strong><p>For easy access, you might want to add <strong>Wireless\ndebugging</strong> in the notification tiles section. To do this, find\n<strong>Quick settings developer tiles</strong> in the <strong>Developer\noptions</strong> page and click to open it. In the new window, enable\n<em>Wireless debugging</em>. In case you do not see this setting, you\nmay find a <strong>Wireless debugging</strong> tile in the tile\ncustomization panel.</div></section><section id=subsec:pair-adb-with-app-manager class=level3 data-number=3.2.3><h3 data-number=3.2.3><span class=header-section-number>3.2.3</span>\n<a href=#toc:subsec:pair-adb-with-app-manager>Pair ADB with App\nManager</a><a href=#subsec:pair-adb-with-app-manager class=anchor aria-hidden=true></a></h3><p>In App Manager, navigate to <strong>Settings</strong> > <a href=#subsec:mode-of-operation>Mode of operation</a> and then enable\n<em>Wireless debugging</em>. At this, App Manager will try to establish\na wireless debugging connection automatically which will fail if it has\nnot been paired before. Once it fails, it will ask you to either connect\nor pair ADB. Select <em>pair</em> and a new dialog will appear. It will\nask you to navigate to the <strong>Wireless debugging</strong> page.<div class=\"amalert tip\"><p><strong><em>Note.</em></strong><p>As of v4.0.0, pairing is done using a notification prompt. So, if you\nhave disabled notification for App Manager, you must enable it\nfirst.</div><p>In the <strong>Wireless debugging</strong> page, select <strong>Pair\ndevice with pairing code</strong>. At this, a dialog containing a\npairing code will be displayed. A notification asking for the pairing\ncode will also be visible almost instantly. Insert the pairing code in\nthe input box in the notification and click <em>pair</em>. If the\npairing is successful, App Manager will display notification with the\nmessage “paired”, and the dialog in the <strong>Wireless\ndebugging</strong> page will be dismissed automatically. You will also\nbe able to see App Manager listed as an ADB client in the same page.<div class=\"amalert tip\"><p><strong><em>Notice.</em></strong><p>If you do not use App Manager in ADB mode for a while, App Manager\nmight be removed from the list of clients. In that case, you have to\nrepeat the above procedure.</div></section><section id=subsec:connect-app-manager-to-adb class=level3 data-number=3.2.4><h3 data-number=3.2.4><span class=header-section-number>3.2.4</span>\n<a href=#toc:subsec:connect-app-manager-to-adb>Connect App Manager to\nADB</a><a href=#subsec:connect-app-manager-to-adb class=anchor aria-hidden=true></a></h3><p>App Manager should be able to connect to ADB automatically if the\nmode of operation is set to <em>auto</em>, <em>ADB over TCP</em> or\n<em>Wireless debugging</em>. If this is not the case, select\n<em>Wireless debugging</em> in <strong>Settings</strong> > <a href=#subsec:mode-of-operation>Mode of operation</a>. If App Manager\nfails to detect or connect to ADB, it will ask you to connect or pair\nADB. Select <em>connect</em>.<p>Now, navigate to the <strong>Wireless debugging</strong> page in\nAndroid settings, and note down the port number displayed in the page.\nIn App Manager’s dialog prompt, replace the port number with the one you\nhave noted earlier, and click <em>connect</em>.<p>Once a connection has been established, you can disable\n<strong>Wireless debugging</strong> in Android settings.<div class=\"amalert danger\"><p><strong><em>Caution.</em></strong><p>Never disable <strong>USB Debugging</strong> or any other additional\noptions described in §<a href=#subsec:enable-developer-options-and-usb-debugging data-reference-type=ref data-reference=subsec:enable-developer-options-and-usb-debugging>3.2.1</a>.\nIf you do this, the remote server used by App Manager will be stopped,\nand you may have to start all over again.</div></section></section><section id=sec:backup-restore class=level2 data-number=3.3><h2 data-number=3.3><span class=header-section-number>3.3</span> <a href=#toc:sec:backup-restore>Back up/Restore</a><a href=#sec:backup-restore class=anchor aria-hidden=true></a></h2><p>App Manager has a modern, advanced and easy-to-use backup/restore\nsystem implemented from the scratch. This is probably the only app that\nhas the ability to restore not only the app or its data but also\npermissions and rules that you’ve configured within App Manager. You can\nalso choose to back up an app multiple times (with custom names) or for\nall users.<div class=seealso><p><em>Ver também:</em><ul class=incremental><li><p><a href=#subsec:1-click-back-up>1-Click Ops: Back\nup</a><li><p><a href=#subsec:1-click-restore>1-Click Ops:\nRestore</a></ul></div><section id=subsec:backup-location class=level3 data-number=3.3.1><h3 data-number=3.3.1><span class=header-section-number>3.3.1</span>\n<a href=#toc:subsec:backup-location>Location</a><a href=#subsec:backup-location class=anchor aria-hidden=true></a></h3><p>Back up/restore is a part of <a href=#subsec:batch-operations>batch\noperations</a>. It is also located inside the <a href=#subsubsec:app-info-options-menu>options menu</a> in the <a href=#subsec:app-info-tab>App Info tab</a>. Clicking on\n<strong>Backup/Restore</strong> opens the <strong>Backup\nOptions</strong>. Backups are located at\n<code>/storage/emulated/0/AppManager</code> by default. You can\nconfigure custom backup location in the <a href=#subsubsec:backup-volume>settings page</a> in which case the\nbackups will be located at the <code>AppManager</code> folder in the\nselected volume.<div class=\"amalert tip\"><p><strong><em>Note.</em></strong><p>If one or more selected apps do not have any backup, the\n<strong>Restore</strong> and <strong>Delete Backup</strong> options will\nnot be displayed.</div></section><section id=subsec:backup-restore-backup-options class=level3 data-number=3.3.2><h3 data-number=3.3.2><span class=header-section-number>3.3.2</span>\n<a href=#toc:subsec:backup-restore-backup-options>Backup Options</a><a href=#subsec:backup-restore-backup-options class=anchor aria-hidden=true></a></h3><p>Backup options (internally known as backup flags) let you customise\nthe backups on the fly. However, the customisations will not be\nremembered for the future backups. If you want to customise this dialog,\nuse <a href=#subsubsec:settings-backup-options>Backup Options</a> in\nthe <a href=#sec:settings-page>Settings page</a>.<p>A complete description of the backup options is given below:<ul class=incremental><li><p><strong>APK files.</strong> Whether to back up the APK files.\nThis includes the <em>base APK</em> file along with the\n<code>split APK</code> files if they exist.<li><p><strong>Internal data.</strong> Whether to back up the internal\ndata directories. These directories are located at\n<code>/data/user/&lt;user_id></code> and (for Android N or later)\n<code>/data/user_de/&lt;user_id></code>.<li><p><strong>External data.</strong> Whether to back up data\ndirectories located in the internal memory as well as SD Card (if\nexists). External data directories often contain non-essential app data\nor media files (instead of using the dedicated media folder) and may\nincrease the backup size. However, it might be essential for some apps.\nAlthough it isn’t checked by default (as it might dramatically increase\nthe size of the backups), you may have to check it in order to ensure a\nsmooth restore of your backups.<div class=\"amalert warning\"><p><strong><em>Caution.</em></strong><p>Internal data folders should always be backed up if you are going to\nback up the external data folders. However, it could be useful to back\nup only the external folders if the app in question downloads a lot of\nassets from the Internet.</div><li><p><strong>OBB and media.</strong> Whether to back up or restore the\nOBB and the media directories located in the external storage or the SD\nCard. This is useful for games and the graphical software which actually\nuse these folders.<li><p><strong>Cache.</strong> Android apps have multiple cache\ndirectories located at every data directories (both internal and\nexternal). There are two types of cache: <strong>cache</strong> and\n<strong>code cache</strong>. Disabling this option excludes both cache\ndirectories from all the data directories. It is generally advised to\nexclude cache directories since most apps do not clear the cache\nregularly and usually handled by the OS itself. Apps such as Telegram\nmay use a very large cache (depending on the storage space) which may\ndramatically increase the backup size. When it is disabled, AM also\nignores the <strong>no_backup</strong> directories.<li><p><strong>Extras.</strong> Backup/restore app permissions, net\npolicy, battery optimization, SSAID, etc., enabled by default. Note\nthat, blocking rules are applied <em>after</em> applying the extras. So,\nif an item is present in both places, it will be overwritten (i.e., the\none from the blocking rules will be used).<li><p><strong>Rules.</strong> This option lets you back up blocking\nrules configured within App Manager. This might come in handy if you\nhave customised permissions or block some components using App Manager\nas they will also be backed up or restored when you enable this\noption.<li><p><strong>Backup Multiple.</strong> Whether this is a multiple\nbackup. By default, backups are saved using their user ID. Enabling this\noption allows you to create additional backups. These backups use the\ncurrent date-time as the default backup name, but you can also specify\ncustom backup name using the input field displayed when you click on the\n<strong>Backup</strong> button.<li><p><strong>Custom users.</strong> Backup or restore for the selected\nusers instead of only the current user. This option is only displayed if\nthe system has more than one user.<li><p><strong>Skip signature checks.</strong> When taking a backup,\nchecksum of every file (as well as the signing certificate(s) of the\nbase APK file) is generated and stored in the <code>checksums.txt</code>\nfile. When you restore the backup, the checksums are generated again and\nare matched with the checksums stored in the said file. Enabling this\noption will disable the signature checks. This option is applied only\nwhen you restore a backup. During backup, the checksums are generated\nregardless of this option.<div class=\"amalert warning\"><p><strong><em>Caution.</em></strong><p>You should always disable this option to ensure that your backups are\nnot modified by any third-party applications. However, this would only\nwork if you enabled encryption.</div></ul><div class=seealso-inline><p><em>Ver também: <span><a href=#subsubsec:settings-encryption>Settings:\nEncryption</a></span></em></div></section><section id=subsec:backup-restore-backup class=level3 data-number=3.3.3><h3 data-number=3.3.3><span class=header-section-number>3.3.3</span>\n<a href=#toc:subsec:backup-restore-backup>Backup</a><a href=#subsec:backup-restore-backup class=anchor aria-hidden=true></a></h3><p>Backup respects all the backup options except <strong>Skip signature\nchecks</strong>. If base backups (i.e., backups that don’t have the\n<strong>Backup Multiple</strong> option) already exist, you will get a\nwarning as the backups will be overwritten. If <strong>Backup\nMultiple</strong> is set, you have an option to input the backup name,\nor you can leave it blank to use the current date-time.</section><section id=subsec:backup-restore-restore class=level3 data-number=3.3.4><h3 data-number=3.3.4><span class=header-section-number>3.3.4</span>\n<a href=#toc:subsec:backup-restore-restore>Restore</a><a href=#subsec:backup-restore-restore class=anchor aria-hidden=true></a></h3><p>Restore respects all the backup options and will fail if <strong>APK\nfiles</strong> option is set, but the backup doesn’t contain such\nbackups or in other cases, if the app isn’t installed. When restoring\nbackups for multiple packages, you can only restore the base backups\n(see <a href=#subsec:backup-restore-backup>backup</a> section for an\nexplanation). However, when restoring backups for a single package, you\nhave the option to select which backup to restore. If <strong>All\nusers</strong> option is set, AM will restore the selected backup for\nall users in the latter case but in the former case, it will restore\nbase backups for the respective users.<div class=\"amalert tip\"><p><strong><em>Notice.</em></strong><p>Apps that use storage access framework (SAF), SSAID or Android\nKeyStore works properly only after an immediate restart.</div></section><section id=subsec:backup-restore-delete-backup class=level3 data-number=3.3.5><h3 data-number=3.3.5><span class=header-section-number>3.3.5</span>\n<a href=#toc:subsec:backup-restore-delete-backup>Delete Backup</a><a href=#subsec:backup-restore-delete-backup class=anchor aria-hidden=true></a></h3><p>Delete backup only respects <strong>All users</strong> option and\nwhen it is selected, only the base backups for all users will be deleted\nwith a prompt. When deleting backups for a single package, another\ndialog will be displayed where you can select the backups to delete.</section></section><section id=sec:automating-tasks class=level2 data-number=3.4><h2 data-number=3.4><span class=header-section-number>3.4</span> <a href=#toc:sec:automating-tasks>Automating Tasks</a><a href=#sec:automating-tasks class=anchor aria-hidden=true></a></h2><p>It is possible to trigger profiles configured inside App Manager via\nthird-party applications such as <strong>Automation</strong> or\n<strong>Tasker</strong>. Traditionally, <code>Intent</code>s are used to\ntrigger such operations.<section id=subsec:generating-authorization-key class=level3 data-number=3.4.1><h3 data-number=3.4.1><span class=header-section-number>3.4.1</span>\n<a href=#toc:subsec:generating-authorization-key>Generating\nauthorization key</a><a href=#subsec:generating-authorization-key class=anchor aria-hidden=true></a></h3><p>In order to ensure proper security, an authorization key is required.\nTo generate a authorization key, go to <strong>Settings</strong> page\nand then <strong>Privacy</strong> > <strong>Authorization\nManager</strong>. If an authorization key has not been generated, it\nwill be generated automatically. The key can be regenerated as\nrequired.<div class=\"amalert danger\"><p><strong><em>Caution.</em></strong><p>Regenerating the authorization key can have some side effects such as\ninvalidation of all the previously configured Intents.</div></section><section id=subsec:at:general-configuration class=level3 data-number=3.4.2><h3 data-number=3.4.2><span class=header-section-number>3.4.2</span>\n<a href=#toc:subsec:at:general-configuration>Configuring tasks</a><a href=#subsec:at:general-configuration class=anchor aria-hidden=true></a></h3><p>The activity\n<code>io.github.muntashirakon.AppManager.crypto.auth.AuthFeatureDemultiplexer</code>\nis responsible for handling all the automations. Sending an intent to\nthe activity lets App Manager perform the designated operation by\nredirecting the <code>Intent</code> to the designated activity or\nservice.<section id=required-extras class=level4 data-number=3.4.2.1><h4 data-number=3.4.2.1><span class=header-section-number>3.4.2.1</span> Required extras<a href=#required-extras class=anchor aria-hidden=true></a></h4><p>It has two primary extras required in all conditions. The key names,\ndata types are all follows:<ol class=incremental><li><p><strong><code>auth</code>.</strong> (String value) The\nauthorization key as described in the earlier section.<li><p><strong><code>feature</code>.</strong> (String value) Name of the\nfeature. Supported features are described in the next section.</ol></section></section><section id=subsec:at:features class=level3 data-number=3.4.3><h3 data-number=3.4.3><span class=header-section-number>3.4.3</span>\n<a href=#toc:subsec:at:features>Features</a><a href=#subsec:at:features class=anchor aria-hidden=true></a></h3><p>App Manager current support a single feature, namely\n<code>profile</code>.</section><section id=subsec:triggering-a-profile class=level3 data-number=3.4.4><h3 data-number=3.4.4><span class=header-section-number>3.4.4</span>\n<a href=#toc:subsec:triggering-a-profile>Triggering a profile</a><a href=#subsec:triggering-a-profile class=anchor aria-hidden=true></a></h3><p>In order to trigger a profile, <code>feature</code> must have the\nvalue <code>profile</code>. In addition, the following extras can be\nincluded:<ol class=incremental><li><p><strong><code>prof</code>.</strong> (String value – required) The\nname of the profile as displayed in the <a href=#sec:profiles-page>Profiles page</a>.<li><p><strong><code>state</code>.</strong> (String value – optional)\nState of the profile – currently <code>on</code> or <code>off</code> –\nas specified in the documentation. If this extra is not set, App Manager\nwill display a prompt where a state must be selected. Therefore, for\ncomplete automation, this option should be set.</ol></section></section><section id=sec:net-policy class=level2 data-number=3.5><h2 data-number=3.5><span class=header-section-number>3.5</span> <a href=#toc:sec:net-policy>Net Policy</a><a href=#sec:net-policy class=anchor aria-hidden=true></a></h2><p>Short for <strong>Network policy</strong> or network policies. It is\nusually located in the Android settings under <strong>Mobile data &\nWifi</strong> section in the app info page of an app. Not all policies\nare guaranteed to be included in this page (e.g. Samsung), and not all\nsettings are well-understood due to lack of documentation. App Manager\ncan display all the net policies declared in the <a href=https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/net/NetworkPolicyManager.java>NetworkPolicyManager</a>.\nPolicies unknown to App Manager will have a <em>Unknown</em> prefix\nalong with the policy constant name and number in the hexadecimal\nformat. Unknown policies should be reported to App Manager for\ninclusion.<p>Net policy allows a user to configure certain networking behaviour of\nan app without modifying the ip tables directly and/or running a\nfirewall app. However, the features it offers largely depend on Android\nversion and ROM. A list of known net policies are listed below:<ol class=incremental><li><p><strong>None</strong> or\n<strong><code>POLICY_NONE</code></strong>: (AOSP) No specific network\npolicy is set. System can still assign rules depending on the nature of\nthe app.<li><p><strong>Reject background data on metered networks</strong> or\n<strong><code>POLICY_REJECT_METERED_BACKGROUND</code></strong>: (AOSP)\nReject network usage on metered networks when the application is in\nbackground.<li><p><strong>Allow background data on metered networks even when Data\nSaver is on</strong> or\n<strong><code>POLICY_ALLOW_METERED_BACKGROUND</code></strong>: (AOSP)\nAllow metered network use in the background even when data saving mode\nis enabled.<li><p><strong>Reject cellular data</strong> or\n<strong><code>POLICY_REJECT_CELLULAR</code></strong> (Android 11+) or\n<strong><code>POLICY_REJECT_ON_DATA</code></strong> (up to Android 10):\n(Lineage OS) Reject mobile/cellular data. Signals network unavailable to\nthe configured app as if the mobile data is inactive.<li><p><strong>Reject VPN data</strong> or\n<strong><code>POLICY_REJECT_VPN</code></strong> (Android 11+) or\n<strong><code>POLICY_REJECT_ON_VPN</code></strong> (up to Android 10):\n(Lineage OS) Reject VPN data. Signals network unavailable to the\nconfigured app as if the VPN is inactive.<li><p><strong>Reject Wi-Fi data</strong> or\n<strong><code>POLICY_REJECT_WIFI</code></strong> (Android 11+) or\n<strong><code>POLICY_REJECT_ON_WLAN</code></strong> (up to Android 10):\n(Lineage OS) Reject Wi-Fi data. Signals network unavailable to the\nconfigured app as if the device is not connected to a Wi-Fi\nnetwork.<li><p><strong>Disable network access</strong> or\n<strong><code>POLICY_REJECT_ALL</code></strong> (Android 11+) or\n<strong><code>POLICY_NETWORK_ISOLATED</code></strong> (up to Android\n10): (Lineage OS) Reject network access in all circumstances. This is\nnot the same as enforcing the other three policies above, and is the\nrecommended policy for dodgy apps. If this policy is enforced, there is\nno need to enforce the other policies.<li><p><strong><code>POLICY_ALLOW_METERED_IN_ROAMING</code></strong>:\n(Samsung) Possibly allow metered network use during roaming. Exact\nmeaning is currently unknown.<li><p><strong><code>POLICY_ALLOW_WHITELIST_IN_ROAMING</code></strong>:\n(Samsung) Possibly allow network use during roaming. Exact meaning is\ncurrently unknown.<li><p><strong>Reject data on metered networks</strong> or\n<strong><code>POLICY_REJECT_METERED</code></strong>: (Motorola) Reject\nnetwork usage if it is a metered network.<li><p><strong>Reject background data</strong> or\n<strong><code>POLICY_REJECT_BACKGROUND</code></strong>: (Motorola)\nReject network usage in the background.<li><p><strong>Disable network access</strong> or\n<strong><code>POLICY_REJECT_ALL</code></strong>: (Motorola) Reject\nnetwork access altogether. Like Lineage OS, it blocks internet\nconnections via iptables. But whether it signals the unavailability of\nnetwork to the configured app is not known.</ol><div class=\"amalert tip\"><p><strong><em>Note.</em></strong><p>Corresponding Lineage OS patches are as follows:<ol class=incremental><li><p><a href=https://github.com/LineageOS/android_frameworks_base/commit/a04932bafbbf7d99efd18276152cc2c9c9b2073e>fw/b:\nSquash of app fw restriction commits</a><li><p><a href=https://github.com/LineageOS/android_frameworks_base/commit/02c8c82854348f52afe2199f310f44b5f578b5b8>fw/b:\nAdd support for per app network isolation</a></ol></div></section></section><section id=ch:faq class=level1 data-number=4><h1 data-number=4><span class=header-section-number>4</span> <a href=#toc:ch:faq>Frequently Asked Questions</a><a href=#ch:faq class=anchor aria-hidden=true></a></h1><section id=sec:faq:app-components class=level2 data-number=4.1><h2 data-number=4.1><span class=header-section-number>4.1</span> <a href=#toc:sec:faq:app-components>App Components</a><a href=#sec:faq:app-components class=anchor aria-hidden=true></a></h2><section id=subsec:faq:what-are-app-components class=level3 data-number=4.1.1><h3 data-number=4.1.1><span class=header-section-number>4.1.1</span>\n<a href=#toc:subsec:faq:what-are-app-components>What are the\napplication components?</a><a href=#subsec:faq:what-are-app-components class=anchor aria-hidden=true></a></h3><p>Activities, services, broadcast receivers (or only receivers) and\ncontent providers (or only providers) are jointly called application\ncomponents. More technically, they all inherit the <a href=https://developer.android.com/reference/android/content/pm/ComponentInfo>ComponentInfo</a>\nclass and can be launched via Intent.</section><section id=subsec:faq:how-components-blocked class=level3 data-number=4.1.2><h3 data-number=4.1.2><span class=header-section-number>4.1.2</span>\n<a href=#toc:subsec:faq:how-components-blocked>How are the tracker and\nother components blocked in App Manager? What are its limitations?</a><a href=#subsec:faq:how-components-blocked class=anchor aria-hidden=true></a></h3><p>App Manager typically blocks application components (or tracker\ncomponents) using a method called <a href=https://carteryagemann.com/pages/android-intent-firewall.html>Intent\nFirewall (IFW)</a>, it is superior to other methods such as <em>pm</em>\n(PackageManager), <a href=https://github.com/RikkaApps/Shizuku>Shizuku</a> or any other\nmethod that uses the package manager to enable or disable the\ncomponents. If a component is disabled by the latter methods, the\napplication itself can detect that the component is being blocked and\ncan re-enable it as it has full access to its own components. (Many\ndeceptive applications actually do this in order to keep the tracker\ncomponents unblocked.) On the other hand, IFW is a true firewall and the\napplication cannot detect if its components are being blocked. App\nManager uses the term <em>block</em> rather than <em>disable</em> for\nthis reason.<p>Even IFW has some limitations which are primarily applicable for the\nsystem applications:<ul class=incremental><li><p>The application in question is whitelisted by the system i.e. the\nsystem cannot function properly without these applications and may cause\nrandom crashes. These applications include but not limited to Android\nSystem, System UI, Phone Services. They will continue to work even if\nthey are disabled or blocked.<li><p>Another system application or system process has activated a\nspecific component of the application in question via interprocess\ncommunication (IPC). In this case, the component will be activated\nregardless of blocking status or even if the entire application is\ndisabled. If there is such a system application that is not needed, the\nonly way to prevent it from running is by getting rid of it.</ul></section><section id=subsec:faq:components-blocked-by-others class=level3 data-number=4.1.3><h3 data-number=4.1.3><span class=header-section-number>4.1.3</span>\n<a href=#toc:subsec:faq:components-blocked-by-others>Does app\ncomponents blocked by other tools retained in App Manager?</a><a href=#subsec:faq:components-blocked-by-others class=anchor aria-hidden=true></a></h3><p><strong>No.</strong> But the application components blocked by the\nsystem or any other tools are displayed in the <a href=#subsec:component-tabs>component tabs</a>. These rules can be\nimported from <a href=#par:import-existing-rules>Settings</a>.\nHowever, it is not possible for App Manager to distinguish the\ncomponents blocked by the third-party tools and components blocked by\nthe system. Therefore, the applications listed in the import page should\nbe selected with care.</section><section id=subsec:faq:components-reblocked-in-am class=level3 data-number=4.1.4><h3 data-number=4.1.4><span class=header-section-number>4.1.4</span>\n<a href=#toc:subsec:faq:components-reblocked-in-am>What happens to the\ncomponents blocked by App Manager which were previously blocked by other\ntools?</a><a href=#subsec:faq:components-reblocked-in-am class=anchor aria-hidden=true></a></h3><p><em>App Manager blocks the components again</em> if requested. In\ncase of unblocking, they will be reverted to the default state as\nspecified in the manifest of the application. But if the components were\nblocked by <a href=https://www.myandroidtools.com>MyAndroidTools\n(MAT)</a> with IFW method, they will not be unblocked by App Manager as\nit uses a different format. To fix this issue, the rules have to be\nimported from <a href=#par:import-existing-rules>Settings</a> at\nfirst, in which case MAT’s configurations will be permanently\nremoved.</section><section id=subsec:faq:what-is-instant-component-blocking class=level3 data-number=4.1.5><h3 data-number=4.1.5><span class=header-section-number>4.1.5</span>\n<a href=#toc:subsec:faq:what-is-instant-component-blocking>What is\ninstant component blocking?</a><a href=#subsec:faq:what-is-instant-component-blocking class=anchor aria-hidden=true></a></h3><p>When you block a component in the <a href=#sec:app-details-page>App\nDetails page</a>, the blocking is not applied by default. It is only\napplied when you apply blocking using the <em>Apply rules</em> option in\nthe top-right menu. If you enable <a href=#subsubsec:instant-component-blocking>instant component\nblocking</a>, blocking will be applied as soon as you block a component.\nIf you choose to block tracker components, however, blocking is applied\nautomatically regardless of this setting. You can also remove blocking\nfor an application by simply clicking on <em>Remove rules</em> in the\nsame menu in the <strong>App Details page</strong>. Since the default\nbehaviour gives you more control over applications, it is better to keep\n<em>instant component blocking</em> option disabled.</section><section id=subsec:tracker-classes-versus-tracker-components class=level3 data-number=4.1.6><h3 data-number=4.1.6><span class=header-section-number>4.1.6</span>\n<a href=#toc:subsec:tracker-classes-versus-tracker-components>Tracker\nclasses versus tracker components</a><a href=#subsec:tracker-classes-versus-tracker-components class=anchor aria-hidden=true></a></h3><p>All application components are classes but not all classes are\ncomponents. In fact, only a few of the classes are components. That\nbeing said, <a href=#sec:scanner-page>scanner page</a> displays a list\nof trackers along with the number of classes, not just the components.\nIn all other pages, trackers and tracker components are used\nsynonymously to denote tracker components, i.e. blocking tracker means\nblocking tracker components, not tracker classes.<div class=\"amalert tip\"><p><strong><em>Info.</em></strong><p>Tracker classes that are not components cannot be blocked. They can\nonly be removed by editing the application itself.</div></section></section><section id=sec:faq:adb-over-tcp class=level2 data-number=4.2><h2 data-number=4.2><span class=header-section-number>4.2</span> <a href=#toc:sec:faq:adb-over-tcp>ADB over TCP</a><a href=#sec:faq:adb-over-tcp class=anchor aria-hidden=true></a></h2><section id=subsec:faq:enable-adb-on-every-restart class=level3 data-number=4.2.1><h3 data-number=4.2.1><span class=header-section-number>4.2.1</span>\n<a href=#toc:subsec:faq:enable-adb-on-every-restart>Do I have to\nenable ADB over TCP everytime I restart?</a><a href=#subsec:faq:enable-adb-on-every-restart class=anchor aria-hidden=true></a></h3><p>Unfortunately, yes. This is because the ADB daemon, the process\nresponsible for ADB connection, is also restarted after a reboot, and it\ndoes not re-enable ADB over TCP.</section><section id=subsec:faq:usb-debugging class=level3 data-number=4.2.2><h3 data-number=4.2.2><span class=header-section-number>4.2.2</span>\n<a href=#toc:subsec:faq:usb-debugging>Cannot enable USB debugging.\nWhat to do?</a><a href=#subsec:faq:usb-debugging class=anchor aria-hidden=true></a></h3><p>See §<a href=#subsec:enable-usb-debugging data-reference-type=ref data-reference=subsec:enable-usb-debugging>3.1.2</a> in Capítulo <a href=#ch:guides data-reference-type=ref data-reference=ch:guides>3</a>.</section><section id=subsec:faq:block-components-using-adb class=level3 data-number=4.2.3><h3 data-number=4.2.3><span class=header-section-number>4.2.3</span>\n<a href=#toc:subsec:faq:block-components-using-adb>Can I block tracker\nor any other application components using ADB over TCP?</a><a href=#subsec:faq:block-components-using-adb class=anchor aria-hidden=true></a></h3><p>ADB has limited number of <a href=https://github.com/aosp-mirror/platform_frameworks_base/blob/master/packages/Shell/AndroidManifest.xml>permissions</a>\nand controlling application components is not one of them. However, the\ncomponents of a <em>test-only</em> app can be controlled via ADB. If App\nManager detects such an application, it enables the blocking options\nautomatically.</section><section id=subsec:faq:adb-features class=level3 data-number=4.2.4><h3 data-number=4.2.4><span class=header-section-number>4.2.4</span>\n<a href=#toc:subsec:faq:adb-features>Which features can be used in ADB\nmode?</a><a href=#subsec:faq:adb-features class=anchor aria-hidden=true></a></h3><p>Supported features are enabled automatically in the ADB mode.\nSupported features include disabling, force-stopping, clearing\napplication data, granting or revoking app ops and permissions, and so\non. It is also possible to install or uninstall applications without any\nprompt from the system.</section></section><section id=sec:faq:miscellanea class=level2 data-number=4.3><h2 data-number=4.3><span class=header-section-number>4.3</span> <a href=#toc:sec:faq:miscellanea>Miscellanea</a><a href=#sec:faq:miscellanea class=anchor aria-hidden=true></a></h2><section id=subsec:faq:no-root-no-harms class=level3 data-number=4.3.1><h3 data-number=4.3.1><span class=header-section-number>4.3.1</span>\n<a href=#toc:subsec:faq:no-root-no-harms>I don’t use root/ADB. Am I\ncompletely safe from any harms?</a><a href=#subsec:faq:no-root-no-harms class=anchor aria-hidden=true></a></h3><p>Yes. AM cannot modify any system settings without root or ADB.</section><section id=subsec:faq:how-trackers-libs-updated class=level3 data-number=4.3.2><h3 data-number=4.3.2><span class=header-section-number>4.3.2</span>\n<a href=#toc:subsec:faq:how-trackers-libs-updated>How are the trackers\nand libraries are updated?</a><a href=#subsec:faq:how-trackers-libs-updated class=anchor aria-hidden=true></a></h3><p>Trackers and libraries are updated manually before making a new\nrelease.</section><section id=subsec:faq:apks-deleted-after-installed class=level3 data-number=4.3.3><h3 data-number=4.3.3><span class=header-section-number>4.3.3</span>\n<a href=#toc:subsec:faq:apks-deleted-after-installed>Are APKs deleted\nafter installed?</a><a href=#subsec:faq:apks-deleted-after-installed class=anchor aria-hidden=true></a></h3><p>No, APKs aren’t deleted by App Manager after they are installed.</section><section id=subsec:faq:shizuku-support class=level3 data-number=4.3.4><h3 data-number=4.3.4><span class=header-section-number>4.3.4</span>\n<a href=#toc:subsec:faq:shizuku-support>Any plans for Shizuku?</a><a href=#subsec:faq:shizuku-support class=anchor aria-hidden=true></a></h3><p>App Manager’s use of hidden API and privileged code execution is now\nmuch more complex and cannot be integrated with other third party apps\nsuch as <a href=https://shizuku.rikka.app>Shizuku</a>. Here are some\nreasons for not considering Shizuku (which now has Apache 2.0 license)\nfor App Manager:<ol class=incremental><li><p>Shizuku was initially non-free which led me to use a similar\napproach for App Manager to support both root and ADB<li><p>App Manager already supports both ADB and root which in some\ncases is more capable than Shizuku<li><p>Relying on a third-party app for the major functionalities is not\na good design choice<li><p>Integration of Shizuku will increase the complexity of App\nManager.</ol></section><section id=subsec:faq:what-are-bloatware class=level3 data-number=4.3.5><h3 data-number=4.3.5><span class=header-section-number>4.3.5</span>\n<a href=#toc:subsec:faq:what-are-bloatware>What are bloatware and how\nto remove them?</a><a href=#subsec:faq:what-are-bloatware class=anchor aria-hidden=true></a></h3><p>Bloatware are the unnecessary pre-installed apps, usually system\napps. Some of the apps are often used to track users and collect user\ndata which they might sell for profits. Many system apps do not need to\nrequest any permission to access device info, contacts and messaging\ndata, and other usage info, such as your phone usage habits and\neverything you store on your shared storage(s).<p>The bloatware may also include Google apps, Meta apps, and Twitter/X\nwhich can also track users and/or collect user data without consent. You\ncan disable a few permissions from Android settings but be aware that\nAndroid settings hides many permissions a security researcher would call\npotentially <em>dangerous</em> (e.g., internet, sensor).<p>Were the bloatware user apps, they could be easily uninstalled either\nfrom Android settings or AM. Uninstalling system apps is not possible\nwithout privileged permission, but even then, it cannot <em>remove</em>\nthe system apps completely as they are located in the <em>system</em>\npartition which is a read-only partition. If you have root, you can\nremount this partition to manually <em>purge</em> these apps but this\nwill break Over the Air (OTA) updates since data in the system partition\nhas been modified. There are two kind of updates, delta (small-size,\nconsisting of only the changes between two versions) and full updates.\nYou may still be able to apply full updates, but the bloatware will be\ninstalled again, and consequently, you have to delete them all over\nagain.<p>Another solution is to disable these apps either from Android\nsettings or AM, but certain services can still run in the background as\nthey can be started by other system apps using Inter-process\nCommunication (IPC). One possible solution is to disable all bloatware\nuntil the service has finally stopped (after a restart). However, due to\nheavy modifications of the Android frameworks by the vendors, removing\nor disabling certain bloatware may cause the System UI to crash or even\ncause bootloop. From v4.0.0, AM has a new feature called\n<strong>Debloater</strong> which can be used as a starting point to\nmonitor, disable, and remove the bloatware from a proprietary Android\noperating system.<div class=\"amalert warning\"><p><strong><em>Note.</em></strong><p>In most cases, you cannot completely debloat your device. Therefore,\nit is recommended that you use a custom ROM free from bloatware, such as\nGraphene OS, Lineage OS or their derivatives.</div></section></section></section><section id=ch:specifications class=level1 data-number=5><h1 data-number=5><span class=header-section-number>5</span> <a href=#toc:ch:specifications>Specifications</a><a href=#ch:specifications class=anchor aria-hidden=true></a></h1><section id=sec:rules-specification class=level2 data-number=5.1><h2 data-number=5.1><span class=header-section-number>5.1</span> <a href=#toc:sec:rules-specification>Rules Specification</a><a href=#sec:rules-specification class=anchor aria-hidden=true></a></h2><section id=background class=level3 data-number=5.1.1><h3 data-number=5.1.1><span class=header-section-number>5.1.1</span>\n<a href=#toc:background>Background</a><a href=#background class=anchor aria-hidden=true></a></h3><p>AM currently supports blocking activities, broadcast receivers,\ncontent providers, services, app ops and permissions, and in future I\nmay add more blocking options. In order to add more portability, it is\nnecessary to import/export all these data.<p>Maintaining a database should be the best choice when it comes to\nstoring data. For now, several <code>tsv</code> files with each file\nhaving the name of the package and a <code>.tsv</code> extension. The\nfile/database will be queried/processed by the\n<code>RulesStorageManager</code> class. Due to this abstraction, it\nshould be easier to switch to database or encrypted database systems in\nfuture without changing the design of the entire project. Currently, All\nconfiguration files are stored at\n<code>/data/data/io.github.muntashirakon.AppManager/Files/conf</code>.</section><section id=rules-file-format class=level3 data-number=5.1.2><h3 data-number=5.1.2><span class=header-section-number>5.1.2</span>\n<a href=#toc:rules-file-format>Rules File Format</a><a href=#rules-file-format class=anchor aria-hidden=true></a></h3><section id=internal class=level4 data-number=5.1.2.1><h4 data-number=5.1.2.1><span class=header-section-number>5.1.2.1</span> Internal<a href=#internal class=anchor aria-hidden=true></a></h4><p>The format below is used internally within App Manager and is <em>not\ncompatible with the external format.</em><pre><code>    &lt;name&gt; &lt;type&gt; &lt;mode&gt;|&lt;component_status&gt;|&lt;is_granted&gt;</code></pre><p>Here:<ul class=incremental><li><p><code>&lt;name></code> – Component/permission/app op name (in\ncase of app op, it could be string or integer)<li><p><code>&lt;type></code> – One of the <code>ACTIVITY</code>,\n<code>RECEIVER</code>, <code>PROVIDER</code>, <code>SERVICE</code>,\n<code>APP_OP</code>, <code>PERMISSION</code><li><p><code>&lt;mode></code> – (For app ops) The associated <a href=#subsec:mode-constants>mode constant</a><li><p><code>&lt;component_status></code> – (For components)\nComponent status<ul class=incremental><li><p><code>true</code> – Component has been applied (<code>true</code>\nvalue is kept for compatibility)<li><p><code>false</code> – Component hasn’t been applied yet, but will\nbe applied in future (<code>false</code> value is kept for\ncompatibility)<li><p><code>unblocked</code> – Component is scheduled to be\nunblocked</ul><li><p><code>&lt;is_granted></code> – (For permissions) Whether the\npermission is granted or revoked</ul></section><section id=external class=level4 data-number=5.1.2.2><h4 data-number=5.1.2.2><span class=header-section-number>5.1.2.2</span> External<a href=#external class=anchor aria-hidden=true></a></h4><p>External format is used for importing or exporting rules in App\nManager.<pre><code>    &lt;package_name&gt; &lt;component_name&gt; &lt;type&gt; &lt;mode&gt;|&lt;component_status&gt;|&lt;is_granted&gt;</code></pre><p>This the format is essentially the same as above except for the first\nitem which is the name of the package.<div class=\"amalert danger\"><p><strong><em>Caution.</em></strong><p>The exported rules have a different format than the internal one and\nshould not be copied directly to the <strong>conf</strong> folder.</div></section></section></section></section><section id=ch:changelogs class=level1 data-number=6><h1 data-number=6><span class=header-section-number>6</span> <a href=#toc:ch:changelogs>Changelogs</a><a href=#ch:changelogs class=anchor aria-hidden=true></a></h1><section id=sec:v4.0.5-(445) class=level2 data-number=6.1><h2 data-number=6.1><span class=header-section-number>6.1</span> <a href=#toc:sec:v4.0.5-(445)>v4.0.5 (445)</a><a href=#sec:v4.0.5-(445) class=anchor aria-hidden=true></a></h2><ul class=incremental><li><p>Added option to allow installing the existing applications in the\ninstaller page<li><p>Display unsafe bloatware info<li><p>Display vector icon on the splash screen in Android 7.1 and\nearlier<li><p>Enabled “Clear data from uninstalled apps” to no-root users in\n1-click ops page<li><p>Enabled predictive back in Android 14 onwards<li><p>Improved accessibility by updating the content description of the\naction items<li><p>In app info tab, open “Open by default” setting in the “Open\nlinks” dialog<li><p>In debloater page, sort by app label (or app name) rather than\npackage name<li><p>Fixed freezing an app with “Remember for this app” turned\non<li><p>Fixed selecting texts in the list items due to framework\nbugs<li><p>Fixed setting app ops in custom ROMs with MIUI properties\ninjected<li><p>Fixed updating profile modification status when an application is\ndeleted from the list<li><p>Handled common colors and cursor movements in terminal\noutput.</ul></section><section id=sec:v4.0.4-(444) class=level2 data-number=6.2><h2 data-number=6.2><span class=header-section-number>6.2</span> <a href=#toc:sec:v4.0.4-(444)>v4.0.4 (444)</a><a href=#sec:v4.0.4-(444) class=anchor aria-hidden=true></a></h2><ul class=incremental><li><p>Optimized searching and filtering in the main page<li><p>Adopted sentence-case for the titles<li><p>Use the configured state to execute a profile for the simple\nshortcuts<li><p>Prevented crashing while searching throughout the\napplication<li><p>Fixed integer overflow issue in the tar compression.</ul></section><section id=sec:v4.0.3-(443) class=level2 data-number=6.3><h2 data-number=6.3><span class=header-section-number>6.3</span> <a href=#toc:sec:v4.0.3-(443)>v4.0.3 (443)</a><a href=#sec:v4.0.3-(443) class=anchor aria-hidden=true></a></h2><ul class=incremental><li><p>Updated translations<li><p>Improved handling the list items throughout App Manager<li><p>Fixed a regression error in file manager<li><p>Fixed spinners in the App Usage and the System Config\npages.</ul></section><section id=sec:v4.0.2-(442) class=level2 data-number=6.4><h2 data-number=6.4><span class=header-section-number>6.4</span> <a href=#toc:sec:v4.0.2-(442)>v4.0.2 (442)</a><a href=#sec:v4.0.2-(442) class=anchor aria-hidden=true></a></h2><ul class=incremental><li><p>Updated bloatware<li><p>Fixed fetching applications in multi-user environment in no-root\nmode<li><p>Fixed opening <code>app-manager</code> URLs from the web\nbrowsers<li><p>Fixed updating SSAID<li><p>Prevented a crash in Android &lt; 9.0 that occurs due to invalid\napp ops.</ul></section><section id=sec:v4.0.1-(441) class=level2 data-number=6.5><h2 data-number=6.5><span class=header-section-number>6.5</span> <a href=#toc:sec:v4.0.1-(441)>v4.0.1 (441)</a><a href=#sec:v4.0.1-(441) class=anchor aria-hidden=true></a></h2><section id=overlay-management class=level3 data-number=6.5.1><h3 data-number=6.5.1><span class=header-section-number>6.5.1</span>\n<a href=#toc:overlay-management>Overlay management</a><a href=#overlay-management class=anchor aria-hidden=true></a></h3><p>In the App Details page, a new tab “Overlays” is added where per-app\noverlays are displayed. They can also be enabled or disabled using the\ntoggle button. In addition, if the App Details page of an overlay\npackage is opened, a “Overlay” tag will be displayed in the App Info\ntab. Clicking on the tag opens a dialog containing additional info along\nwith a button that allows navigating to the App Details page of the\noverlay target package if it is installed.<section id=known-limitation class=level5 data-number=6.5.1.0.1><h5 data-number=6.5.1.0.1><span class=header-section-number>6.5.1.0.1</span> Known limitation<a href=#known-limitation class=anchor aria-hidden=true></a></h5><p>At present, it only works for root/ADB users in Android 8 (Oreo) and\nlater.</section></section><section id=unfreeze-option-in-activity-shortcuts class=level3 data-number=6.5.2><h3 data-number=6.5.2><span class=header-section-number>6.5.2</span>\n<a href=#toc:unfreeze-option-in-activity-shortcuts>Unfreeze option in\nactivity shortcuts</a><a href=#unfreeze-option-in-activity-shortcuts class=anchor aria-hidden=true></a></h3><p>If the application corresponding to the shortcut being launched is\nfrozen, App Manager will now offer you to unfreeze the app temporarily\nso that the shortcut can be launched. The app will be frozen again once\nthe screen is locked.<section id=known-limitation-1 class=level5 data-number=6.5.2.0.1><h5 data-number=6.5.2.0.1><span class=header-section-number>6.5.2.0.1</span> Known limitation<a href=#known-limitation-1 class=anchor aria-hidden=true></a></h5><p>This may not work on devices without a screen lock or if the screen\nis locked some time after the display goes off.</section></section><section id=market-like-url-support class=level3 data-number=6.5.3><h3 data-number=6.5.3><span class=header-section-number>6.5.3</span>\n<a href=#toc:market-like-url-support><code>market</code>-like URL\nsupport</a><a href=#market-like-url-support class=anchor aria-hidden=true></a></h3><p>Third-party applications can now open the App Details page of any\ninstalled package by invoking an Intent with an URL with the following\nformat:<pre><code>app-manager://details?id=&lt;pkg&gt;&amp;user=&lt;user_id&gt;</code></pre><p>where <code>&lt;pkg></code> stands for package name, and\n<code>&lt;user_id></code> stands for the user ID which is\noptional.</section><section id=updated-color-codes class=level3 data-number=6.5.4><h3 data-number=6.5.4><span class=header-section-number>6.5.4</span>\n<a href=#toc:updated-color-codes>Updated color codes</a><a href=#updated-color-codes class=anchor aria-hidden=true></a></h3><p>In order to improve accessibility, certain color codes have been\nimproved. Visit <a href=app-manager://settings/about/version>Settings\n> About > Version/Changelog</a> for details.</section><section id=others class=level3 data-number=6.5.5><h3 data-number=6.5.5><span class=header-section-number>6.5.5</span>\n<a href=#toc:others>Others</a><a href=#others class=anchor aria-hidden=true></a></h3><ul class=incremental><li><p>Avoided waiting for the remote server to respond when no-root\nmode is set<li><p>Fixed downgrading apps in Android 10 onwards<li><p>Fixed installer issues in the Huawei stock operating\nsystems<li><p>Improved text formatting in the “What’s New” dialog<li><p>In the UI tracker window, fixed clicking on the icon after it is\niconified<li><p>Updated bloatware and suggestions</ul></section></section><section id=sec:v4.0.0-(440) class=level2 data-number=6.6><h2 data-number=6.6><span class=header-section-number>6.6</span> <a href=#toc:sec:v4.0.0-(440)>v4.0.0 (440)</a><a href=#sec:v4.0.0-(440) class=anchor aria-hidden=true></a></h2><p>App Manager v4.0.0 comes with a lot of new features and improvements.\nVisit <a href=app-manager://settings/about/version>Settings > About\n> Version/Changelog</a> for details.<section id=new-logo class=level3 data-number=6.6.1><h3 data-number=6.6.1><span class=header-section-number>6.6.1</span>\n<a href=#toc:new-logo>New logo!</a><a href=#new-logo class=anchor aria-hidden=true></a></h3><p>The new logo is just a cursive “A”. The design is based on the <a href=https://freetengwar.sourceforge.net/>Tengwar Telcontar</a> font\nwhich was created to bring the Tengwar script, originally created by J.\nR. R. Tolkien, to the digital world. The letter has the classic App\nManager color (i.e., #dcaf74) and uses a pure black background instead\nof a shade of grey.</section><section id=android-14-and-15-support class=level3 data-number=6.6.2><h3 data-number=6.6.2><span class=header-section-number>6.6.2</span>\n<a href=#toc:android-14-and-15-support>Android 14 and 15 support</a><a href=#android-14-and-15-support class=anchor aria-hidden=true></a></h3><p>App Manager now targets Android 14 and fully supports Android 15.<section id=known-issue class=level5 data-number=6.6.2.0.1><h5 data-number=6.6.2.0.1><span class=header-section-number>6.6.2.0.1</span> Known issue<a href=#known-issue class=anchor aria-hidden=true></a></h5><p>KeyStore backup/restore is not working in Android 12 and later.</section></section><section id=revamped-debloater class=level3 data-number=6.6.3><h3 data-number=6.6.3><span class=header-section-number>6.6.3</span>\n<a href=#toc:revamped-debloater>Revamped debloater</a><a href=#revamped-debloater class=anchor aria-hidden=true></a></h3><p>Debloating profiles were available as “Presets” in the Profiles page\nwhich has now been replaced with the Debloater page and can be accessed\nfrom the three-dots menu in the Main page. <a href=https://github.com/MuntashirAkon/android-debloat-list>ADL</a> is\na new project that focuses on maintaining a list of bloatware as well as\npotential open source alternatives. Contributions are welcome!</section><section id=introducing-file-manager class=level3 data-number=6.6.4><h3 data-number=6.6.4><span class=header-section-number>6.6.4</span>\n<a href=#toc:introducing-file-manager>Introducing file manager</a><a href=#introducing-file-manager class=anchor aria-hidden=true></a></h3><p>App Manager offers an (almost) fully-featured file manager with basic\nfile operations, such as copy, cut, rename, and delete along with the\nbatch operations. It also offers an extensive “Open with…” dialog to\nopen a file with another app, and a comprehensive file properties\nviewer. Folders can also be added to the list of favorites for quick\naccess. And many more.</section><section id=integrated-code-editor class=level3 data-number=6.6.5><h3 data-number=6.6.5><span class=header-section-number>6.6.5</span>\n<a href=#toc:integrated-code-editor>Integrated code editor</a><a href=#integrated-code-editor class=anchor aria-hidden=true></a></h3><p>Manifest and code viewers have been replaced with this new editor.\nAmong other regular features, it includes proper syntax highlighting and\nadvanced searching options. In addition, files from third-party apps can\nalso be opened for editing.</section><section id=history-of-operations class=level3 data-number=6.6.6><h3 data-number=6.6.6><span class=header-section-number>6.6.6</span>\n<a href=#toc:history-of-operations>History of operations</a><a href=#history-of-operations class=anchor aria-hidden=true></a></h3><p>All 1-click operations, batch operations, and profile invocations are\nnow stored as history. The history items can also be executed from the\nHistory page. To ensure consistency, the profile state, configurations,\npackage list are also stored, and this stored version is executed\ninstead of the actual profile. As a result, this works even if the\nprofile is deleted.</section><section id=per-app-freezing-and-more class=level3 data-number=6.6.7><h3 data-number=6.6.7><span class=header-section-number>6.6.7</span>\n<a href=#toc:per-app-freezing-and-more>Per-app freezing, and\nmore</a><a href=#per-app-freezing-and-more class=anchor aria-hidden=true></a></h3><p>Freeze/unfreeze feature now supports setting per-app freezing method\nwhich is beneficial in certain scenarios, such as when a user want to\nsuspend some apps while using the disable method as the default. In\naddition, an “Advanced suspend” option is added which force-stops an\napplication before suspending it, thus, prevent it’s services from\nrunning in the background.</section><section id=log-viewer-enhancements class=level3 data-number=6.6.8><h3 data-number=6.6.8><span class=header-section-number>6.6.8</span>\n<a href=#toc:log-viewer-enhancements>Log viewer enhancements</a><a href=#log-viewer-enhancements class=anchor aria-hidden=true></a></h3><p>Log viewer now supports enhanced searching and filtering options,\nsuch as keyword- and regular expression-based searching and filtering.\nPlease read the in-app changelog for details. Support for batch\noperations has also been added.</section><section id=launching-non-exported-activities class=level3 data-number=6.6.9><h3 data-number=6.6.9><span class=header-section-number>6.6.9</span>\n<a href=#toc:launching-non-exported-activities>Launching non-exported\nactivities</a><a href=#launching-non-exported-activities class=anchor aria-hidden=true></a></h3><p>App Manager now supports launching non-exported activities in no-root\nand ADB mode. However, in no-root mode,\n<code>android.permission.WRITE_SECURE_SETTINGS</code> permission is\nrequired.</section><section id=new-tags-in-app-info-tab class=level3 data-number=6.6.10><h3 data-number=6.6.10><span class=header-section-number>6.6.10</span> <a href=#toc:new-tags-in-app-info-tab>New tags in App Info tab</a><a href=#new-tags-in-app-info-tab class=anchor aria-hidden=true></a></h3><p>Five new tags are added in the App Info tab. They are: bloatware,\nXposed, sensors disabled, open links, and static shared libs. Clicking\non “bloatware” will display more information regarding the bloatware and\nsuggest alternatives, “Xposed” tag will display dependency information,\n“open links” will display a list of links supported by the application,\nand “static shared libs” will display all version of the application\ninstalled in the system along with an option to uninstall them. The\nlatter is useful for applications, such as Trichrome.<section id=known-issue-1 class=level5 data-number=6.6.10.0.1><h5 data-number=6.6.10.0.1><span class=header-section-number>6.6.10.0.1</span> Known issue<a href=#known-issue-1 class=anchor aria-hidden=true></a></h5><p>“Sensors disabled” only works real-time. That means if the\napplication is not currently active, this tag will always display even\nthough the applications may use sensors while it is running. This is a\nframework limitation and nothing can be done to avoid it\neffectively.</section></section><section id=per-session-installer-options class=level3 data-number=6.6.11><h3 data-number=6.6.11><span class=header-section-number>6.6.11</span> <a href=#toc:per-session-installer-options>Per-session installer\noptions</a><a href=#per-session-installer-options class=anchor aria-hidden=true></a></h3><p>It is not possible to modify installer options during the\ninstallation by clicking on the “settings” button in the installation\ndialog. The installer options will be applied to all the applications\ninstalled in the same session (i.e., the installer queue).</section><section id=advanced-mode-of-operations-adb-enhancements class=level3 data-number=6.6.12><h3 data-number=6.6.12><span class=header-section-number>6.6.12</span> <a href=#toc:advanced-mode-of-operations-adb-enhancements>Advanced mode\nof operations, ADB enhancements, …</a><a href=#advanced-mode-of-operations-adb-enhancements class=anchor aria-hidden=true></a></h3><p>App Manager now supports running its remote server (which is used as\na proxy for running privileged operations) as any supported user (UID).\nThis includes root (0), system (1000), and shell/ADB (2000) through the\ncustom commands. This is also useful for Fire TVs which have disabled\nconnecting to ADB from localhost through socket connection. In addition,\nADB pairing is now done using notifications rather than split screen.\nADB connection speed can also be improved by choosing to run App Manager\nin the background which can be configured in the settings.</section><section id=data-usage-widget-and-more class=level3 data-number=6.6.13><h3 data-number=6.6.13><span class=header-section-number>6.6.13</span> <a href=#toc:data-usage-widget-and-more>Data usage widget, and more</a><a href=#data-usage-widget-and-more class=anchor aria-hidden=true></a></h3><p>Data usage widget display the total data usage for the day, similar\nto the screen time widget which displays the total screen time for the\nday. In addition, existing widgets have been improved.</section><section id=others-1 class=level3 data-number=6.6.14><h3 data-number=6.6.14><span class=header-section-number>6.6.14</span> <a href=#toc:others-1>Others</a><a href=#others-1 class=anchor aria-hidden=true></a></h3><ul class=incremental><li><p>Replaced log viewer, sys config, Terminal, etc. with Labs\npage<li><p>Added an option to disable sensors for each app in the App Info\ntab<li><p>Added an option to perform runtime optimization of applications\nin the 1-click Ops page and in the App Info tab<li><p>Added support for Zstandard compression for\nbackup/restore<li><p>Enabling APK signing now automatically enables zip align\nfeature<li><p>Support exporting application list as CSV or JSON in the batch\noperations<li><p>Added pure black theme support<li><p>Display current activity name (when possible) in the UI Tracker\nwindow<li><p>Added an option to filter apps by user in the Main page<li><p>Display a link to Pithus report in the scanner page if\navailable.</ul></section></section><section id=sec:v3.1.0-(423) class=level2 data-number=6.7><h2 data-number=6.7><span class=header-section-number>6.7</span> <a href=#toc:sec:v3.1.0-(423)>v3.1.0 (423)</a><a href=#sec:v3.1.0-(423) class=anchor aria-hidden=true></a></h2><p>App Manager v3.1.0 comes with a few new features and a lot of\nimprovements. Visit <a href=app-manager://settings/about/version>Settings > About >\nVersion/Changelog</a> for details.<section id=android-13-support class=level3 data-number=6.7.1><h3 data-number=6.7.1><span class=header-section-number>6.7.1</span>\n<a href=#toc:android-13-support>Android 13 support</a><a href=#android-13-support class=anchor aria-hidden=true></a></h3><p>App Manager now targets Android 13 which means most issues in Android\n12 and 13 has been addressed, including SSAID and SAF issues as well as\nmonochrome icons and other theming issues.<section id=known-issue-2 class=level5 data-number=6.7.1.0.1><h5 data-number=6.7.1.0.1><span class=header-section-number>6.7.1.0.1</span> Known issue<a href=#known-issue-2 class=anchor aria-hidden=true></a></h5><p>KeyStore backup/restore not working in Android 12 and later.</section></section><section id=introducing-freezeunfreeze class=level3 data-number=6.7.2><h3 data-number=6.7.2><span class=header-section-number>6.7.2</span>\n<a href=#toc:introducing-freezeunfreeze>Introducing\nfreeze/unfreeze</a><a href=#introducing-freezeunfreeze class=anchor aria-hidden=true></a></h3><p>Enable/disable is replaced with freeze/unfreeze to allow greater\ncontrol on the behaviours of an app. It supports suspend, disable and\nhide functionalities which can be controlled at <a href=app-manager://settings/rules_prefs/freeze_type>Settings >\nRules > Default freezing method</a>. In order to make it easy to\nfreeze or unfreeze an app, shortcuts can also be created from the App\nInfo tab by long clicking on the freeze or unfreeze button.</section><section id=export-app-list class=level3 data-number=6.7.3><h3 data-number=6.7.3><span class=header-section-number>6.7.3</span>\n<a href=#toc:export-app-list>Export app list</a><a href=#export-app-list class=anchor aria-hidden=true></a></h3><p>In the Main page, it is now possible to export the list of apps in\neither XML or Markdown format using batch operations. In the future, the\nXML file may also be imported to App Manager.</section><section id=elliptic-curve-crypography-ecc class=level3 data-number=6.7.4><h3 data-number=6.7.4><span class=header-section-number>6.7.4</span>\n<a href=#toc:elliptic-curve-crypography-ecc>Elliptic Curve Crypography\n(ECC)</a><a href=#elliptic-curve-crypography-ecc class=anchor aria-hidden=true></a></h3><p>App Manager now fully supports encrypting backups using ECC in\naddition to offering AES, RSA and OpenPGP.</section><section id=new-languages class=level3 data-number=6.7.5><h3 data-number=6.7.5><span class=header-section-number>6.7.5</span>\n<a href=#toc:new-languages>New languages</a><a href=#new-languages class=anchor aria-hidden=true></a></h3><p>Two new languages are added: Korean and Romanian.</section><section id=more-list-options class=level3 data-number=6.7.6><h3 data-number=6.7.6><span class=header-section-number>6.7.6</span>\n<a href=#toc:more-list-options>More list options</a><a href=#more-list-options class=anchor aria-hidden=true></a></h3><p>In the main page, more sorting and filtering options are added.\nSorting options include sorting the apps by total size, total data\nusage, launch count, screen time and last usage time. Filtering options\ninclude filtering the apps having at least one item in the Android\nKeyStore, filtering apps with URIs granted via SAF, and filtering apps\nwith SSAID.</section><section id=improved-handling-of-mode-of-operation class=level3 data-number=6.7.7><h3 data-number=6.7.7><span class=header-section-number>6.7.7</span>\n<a href=#toc:improved-handling-of-mode-of-operation>Improved handling\nof mode of operation</a><a href=#improved-handling-of-mode-of-operation class=anchor aria-hidden=true></a></h3><p>Fixed various issues with ADB pairing, handled incomplete USB\ndebugging. Some rooting methods cannot allow interprocess communication\nvia Binder. In those cases, ADB mode is used as a fallback method by\nenabling it automatically if possible.</section><section id=handling-multiple-users class=level3 data-number=6.7.8><h3 data-number=6.7.8><span class=header-section-number>6.7.8</span>\n<a href=#toc:handling-multiple-users>Handling multiple users</a><a href=#handling-multiple-users class=anchor aria-hidden=true></a></h3><p>When possible, App Manager will be able to display apps from work\nprofile in no-root mode in addition to allowing basic operations such as\nlaunching the app or navigating to the system settings. For backups, it\nis now possible to restore backups for other users, but for work\nprofile, some apps may only work properly after re-enabling the work\nprofile. In the installer page, selecting <em>All users</em> will now\ninstall the app for all users instead of only the current user. Finally,\nin the app info tab, current app can be installed in another profile\nusing the <em>Install for…</em> option available in the three-dots menu.\nThis is analogous to the <code>pm install-existing</code> command,\nthereby, making the installation process a lot faster.</section><section id=explorer-enhancements class=level3 data-number=6.7.9><h3 data-number=6.7.9><span class=header-section-number>6.7.9</span>\n<a href=#toc:explorer-enhancements>Explorer enhancements</a><a href=#explorer-enhancements class=anchor aria-hidden=true></a></h3><p>Explorer can now open DEX and JAR files in addition to APK files.\nSeveral sorting options as well as folder options are also added as the\nlist options.</section><section id=new-tag-wx class=level3 data-number=6.7.10><h3 data-number=6.7.10><span class=header-section-number>6.7.10</span> <a href=#toc:new-tag-wx>New tag: WX</a><a href=#new-tag-wx class=anchor aria-hidden=true></a></h3><p>In app info tab, a new tag called WX is added. It is displayed in\nAndroid 10 and later if the application targets Android 9 or earlier. It\nindicates <a href=https://en.wikipedia.org/wiki/W%5EX>W^X</a>\nviolation which allows the app to execute arbitrary executable files\neither by the modification of executables embedded within the app or by\ndownloading them from the Internet.</section><section id=app-ops-management class=level3 data-number=6.7.11><h3 data-number=6.7.11><span class=header-section-number>6.7.11</span> <a href=#toc:app-ops-management>App ops management</a><a href=#app-ops-management class=anchor aria-hidden=true></a></h3><p>App ops are now managed automatically to avoid various app ops\nrelated crashes in various platforms. This will also lessen the amount\nof crashes in an unsupported operating system.</section><section id=batch-uninstallation class=level3 data-number=6.7.12><h3 data-number=6.7.12><span class=header-section-number>6.7.12</span> <a href=#toc:batch-uninstallation>Batch uninstallation</a><a href=#batch-uninstallation class=anchor aria-hidden=true></a></h3><p>In the Main page, enabled batch uninstallation in no-root mode.</section><section id=running-apps class=level3 data-number=6.7.13><h3 data-number=6.7.13><span class=header-section-number>6.7.13</span> <a href=#toc:running-apps>Running apps</a><a href=#running-apps class=anchor aria-hidden=true></a></h3><p>Enabled advanced searching. Searching now matches not only app labels\nbut also package names.</section><section id=interceptor class=level3 data-number=6.7.14><h3 data-number=6.7.14><span class=header-section-number>6.7.14</span> <a href=#toc:interceptor>Interceptor</a><a href=#interceptor class=anchor aria-hidden=true></a></h3><p>Copy the intercepted Intent as am command which can be run from\neither an ADB shell or a terminal using root with the same\neffectiveness.</section><section id=device-specific-changes class=level3 data-number=6.7.15><h3 data-number=6.7.15><span class=header-section-number>6.7.15</span> <a href=#toc:device-specific-changes>Device-specific changes</a><a href=#device-specific-changes class=anchor aria-hidden=true></a></h3><section id=graphene-os class=level5 data-number=6.7.15.0.1><h5 data-number=6.7.15.0.1><span class=header-section-number>6.7.15.0.1</span> Graphene OS<a href=#graphene-os class=anchor aria-hidden=true></a></h5><p>Explicitly handle the Internet permission which is a runtime\npermission in the OS.</section><section id=miui class=level5 data-number=6.7.15.0.2><h5 data-number=6.7.15.0.2><span class=header-section-number>6.7.15.0.2</span> MIUI<a href=#miui class=anchor aria-hidden=true></a></h5><p>Fixed permission denied issues in the installer due to a framework\nissue introduced in MIUI 12.5.</section><section id=motorola class=level5 data-number=6.7.15.0.3><h5 data-number=6.7.15.0.3><span class=header-section-number>6.7.15.0.3</span> Motorola<a href=#motorola class=anchor aria-hidden=true></a></h5><p>Fixed crashes in the Interceptor page due to a framework issue\nintroduced in Android 11.</section></section><section id=others-2 class=level3 data-number=6.7.16><h3 data-number=6.7.16><span class=header-section-number>6.7.16</span> <a href=#toc:others-2>Others</a><a href=#others-2 class=anchor aria-hidden=true></a></h3><ul class=incremental><li><p>Improved Java-Smali conversion by including all the subclasses\nduring conversion<li><p>Improved scanning performance in the Scanner page<li><p>Improved updating the list of apps in the Main page<li><p>Scan all the available paths to detect systemless-ly installed\nsystem apps<li><p><code>vacuum</code> SQLite database before opening it for viewing\nor editing.</ul></section></section><section id=sec:v3.0.0-(410) class=level2 data-number=6.8><h2 data-number=6.8><span class=header-section-number>6.8</span> <a href=#toc:sec:v3.0.0-(410)>v3.0.0 (410)</a><a href=#sec:v3.0.0-(410) class=anchor aria-hidden=true></a></h2><p>App Manager v3.0.0 comes with a lot of features and improvements. See\n<a href=app-manager://settings/about/version>Settings > About >\nVersion/Changelog</a> to see a more detailed changelog.<section id=material-3-and-more class=level3 data-number=6.8.1><h3 data-number=6.8.1><span class=header-section-number>6.8.1</span>\n<a href=#toc:material-3-and-more>Material 3 and More</a><a href=#material-3-and-more class=anchor aria-hidden=true></a></h3><p>Material 3, somewhat similar to <em>Material You</em>, is a\nsignificant improvement over Material Design 2 with support for dynamic\ncolours in Android 12 and later. In addition, many design changes have\nbeen made in App Manager without any significant changes in the overall\nuser experience.<section id=known-issue-3 class=level5 data-number=6.8.1.0.1><h5 data-number=6.8.1.0.1><span class=header-section-number>6.8.1.0.1</span> Known issue<a href=#known-issue-3 class=anchor aria-hidden=true></a></h5><p>Switches are still based on Material Design 2 which will be fixed in\na future release.</section></section><section id=wireless-debugging class=level3 data-number=6.8.2><h3 data-number=6.8.2><span class=header-section-number>6.8.2</span>\n<a href=#toc:wireless-debugging>Wireless Debugging</a><a href=#wireless-debugging class=anchor aria-hidden=true></a></h3><p>Wireless debugging support has been fully implemented. Head over to\n§<a href=#sec:wireless-debugging data-reference-type=ref data-reference=sec:wireless-debugging>3.2</a> for instructions on how\nto configure wireless debugging.<div class=\"amalert tip\"><p><strong><em>No-root users.</em></strong><p>Due to auto-detection feature, startup time might be large for\nno-root users when the mode of operation is set to <em>auto</em>.\nInstead, no-root users should select <em>no-root</em> instead of\n<em>auto</em>.</div></section><section id=languages class=level3 data-number=6.8.3><h3 data-number=6.8.3><span class=header-section-number>6.8.3</span>\n<a href=#toc:languages>Languages</a><a href=#languages class=anchor aria-hidden=true></a></h3><p>App Manager is fully translated into Indonesian and Italian languages\nand can be enabled in settings. Bengali is removed due to lack of\ntranslators.</section><section id=introducing-app-explorer class=level3 data-number=6.8.4><h3 data-number=6.8.4><span class=header-section-number>6.8.4</span>\n<a href=#toc:introducing-app-explorer>Introducing App Explorer</a><a href=#introducing-app-explorer class=anchor aria-hidden=true></a></h3><p>App Explorer can be used to browse the contents of an application.\nThis includes binary XML files, DEX contents or any other media files.\nDEX contents can only be explored in Android Oreo (Android 8) and later.\nIt’s also possible to convert an <code>.smali</code> file into\n<code>.java</code> for a better understanding of the reversed code. This\nfeature, if not needed, can be disabled in Settings > Enable/disable\nfeatures.</section><section id=import-backups-from-other-applications class=level3 data-number=6.8.5><h3 data-number=6.8.5><span class=header-section-number>6.8.5</span>\n<a href=#toc:import-backups-from-other-applications>Import Backups\nfrom Other Applications</a><a href=#import-backups-from-other-applications class=anchor aria-hidden=true></a></h3><p>It is possible to import backups from discontinued or obsolete\napplications such as Titanium Backup, OAndBackup and Swift Backup\n(version 3.0 to 3.2). Go to Setting > Backup/restore to find this\noption.</section><section id=virustotal class=level3 data-number=6.8.6><h3 data-number=6.8.6><span class=header-section-number>6.8.6</span>\n<a href=#toc:virustotal>VirusTotal</a><a href=#virustotal class=anchor aria-hidden=true></a></h3><p>VirusTotal is a widely used tool to scan files and URLs for viruses.\nIn the scanner page and in the running apps page, an option to scan\nfiles with VirusTotal has been added. But the option is hidden by\ndefault. To enable the option, it is necessary to obtain an API key from\nVirusTotal. Go to Settings > VirusTotal API Key for more\ninformation.<div class=\"amalert warning\"><p><strong><em>Internet feature.</em></strong><p>This is currently the only feature which require an Internet\nconnection. If you wish to use any Internet feature that might also be\nadded in the future, enable <em>Use the Internet</em> in Settings >\nEnable/disable features.</div></section><section id=trigger-profiles-from-the-automation-software class=level3 data-number=6.8.7><h3 data-number=6.8.7><span class=header-section-number>6.8.7</span>\n<a href=#toc:trigger-profiles-from-the-automation-software>Trigger\nProfiles from the Automation Software</a><a href=#trigger-profiles-from-the-automation-software class=anchor aria-hidden=true></a></h3><p>As the implementation of routine operations is being delayed, an\noption to trigger profiles from the external automation software is\nadded. See §<a href=#sec:automating-tasks data-reference-type=ref data-reference=sec:automating-tasks>3.4</a> for instructions on how to\nconfigure profile automation.</section><section id=improved-application-installer class=level3 data-number=6.8.8><h3 data-number=6.8.8><span class=header-section-number>6.8.8</span>\n<a href=#toc:improved-application-installer>Improved Application\nInstaller</a><a href=#improved-application-installer class=anchor aria-hidden=true></a></h3><p>Application installer includes several improvements including the\nability to downgrade applications in no-root mode, installing multiple\napplications at once and blocking trackers after installation. In\nAndroid 12 and later, no-root users can update applications without any\nuser interactions.</section><section id=component-blocking class=level3 data-number=6.8.9><h3 data-number=6.8.9><span class=header-section-number>6.8.9</span>\n<a href=#toc:component-blocking>Component Blocking</a><a href=#component-blocking class=anchor aria-hidden=true></a></h3><p>It is now possible to configure how App Manager should block a\ncomponent. Visit Settings > Rules > Default blocking method for\nmore information. In the components tab, long clicking the block/unblock\nbutton opens a context menu which allows per-component blocking in a\nsimilar manner. ADB users can also block the components of a <em>Test\nonly</em> app.</section><section id=advanced-searching class=level3 data-number=6.8.10><h3 data-number=6.8.10><span class=header-section-number>6.8.10</span> <a href=#toc:advanced-searching>Advanced Searching</a><a href=#advanced-searching class=anchor aria-hidden=true></a></h3><p>In some pages, the search bar supports additional searching which\nincludes searching via prefix, suffix or even regular expressions. In\nthe main page, it is also possible to search for applications using the\nfirst letters of each word, e.g. <em>App Manager</em> can be listed by\nsearching for <em>am</em>.</section><section id=shared-libraries class=level3 data-number=6.8.11><h3 data-number=6.8.11><span class=header-section-number>6.8.11</span> <a href=#toc:shared-libraries>Shared Libraries</a><a href=#shared-libraries class=anchor aria-hidden=true></a></h3><p>Shared libraries tab has received a significant improvements. It can\ndisplay three types of libraries, such as native, jar and APK files.</section><section id=make-the-best-use-of-interceptor class=level3 data-number=6.8.12><h3 data-number=6.8.12><span class=header-section-number>6.8.12</span> <a href=#toc:make-the-best-use-of-interceptor>Make the Best Use of\nInterceptor</a><a href=#make-the-best-use-of-interceptor class=anchor aria-hidden=true></a></h3><p>Activity interceptor can be opened directly from the activities tab\nby long clicking on the launch button, and similarly, activities can be\nlaunched from the activity interceptor page with or without root, for\nany users.<div class=\"amalert tip\"><p><strong><em>Notice.</em></strong><p>Currently, activities opened via root cannot send the results back to\nthe original applications.</div></section><section id=widget-screen-time class=level3 data-number=6.8.13><h3 data-number=6.8.13><span class=header-section-number>6.8.13</span> <a href=#toc:widget-screen-time>Widget: Screen Time</a><a href=#widget-screen-time class=anchor aria-hidden=true></a></h3><p>Screen time widget is quite similar to Digital Wellbeing’s widget by\nthe same name. It displays the total screen time for the day along with\nthe top three apps from all users.</section><section id=widget-clear-cache class=level3 data-number=6.8.14><h3 data-number=6.8.14><span class=header-section-number>6.8.14</span> <a href=#toc:widget-clear-cache>Widget: Clear Cache</a><a href=#widget-clear-cache class=anchor aria-hidden=true></a></h3><p>Clear cache widget can be to clear cache from all the applications\ndirectly from the home screen.</section></section><section id=sec:v2.6.0-(385) class=level2 data-number=6.9><h2 data-number=6.9><span class=header-section-number>6.9</span> <a href=#toc:sec:v2.6.0-(385)>v2.6.0 (385)</a><a href=#sec:v2.6.0-(385) class=anchor aria-hidden=true></a></h2><section id=introducing-backups class=level3 data-number=6.9.1><h3 data-number=6.9.1><span class=header-section-number>6.9.1</span>\n<a href=#toc:introducing-backups>Introducing Backups</a><a href=#introducing-backups class=anchor aria-hidden=true></a></h3><p>Back up/restore feature is now finally out of beta! Read <a href=#sec:backup-restore>the corresponding guide</a> to understand how\nit works.</section><section id=introducing-log-viewer class=level3 data-number=6.9.2><h3 data-number=6.9.2><span class=header-section-number>6.9.2</span>\n<a href=#toc:introducing-log-viewer>Introducing Log Viewer</a><a href=#introducing-log-viewer class=anchor aria-hidden=true></a></h3><p><a href=#subsubsec:log-viewer>Log viewer</a> is essentially a\nfront-end for <code>logcat</code>. It can be used to filter logs by\n<em>tag</em> or <em>pid</em> (process ID), or even by custom filters.\nLog levels AKA verbosity can also be configured. You can also save,\nshare and manage logs.</section><section id=lock-app-manager class=level3 data-number=6.9.3><h3 data-number=6.9.3><span class=header-section-number>6.9.3</span>\n<a href=#toc:lock-app-manager>Lock App Manager</a><a href=#lock-app-manager class=anchor aria-hidden=true></a></h3><p><a href=#subsubsec:screen-lock>Lock App Manager</a> with the screen\nlock configured for your device.</section><section id=extended-modes-for-app-ops class=level3 data-number=6.9.4><h3 data-number=6.9.4><span class=header-section-number>6.9.4</span>\n<a href=#toc:extended-modes-for-app-ops>Extended Modes for App\nOps</a><a href=#extended-modes-for-app-ops class=anchor aria-hidden=true></a></h3><p>You can set any mode for any app ops that your device supports,\neither from the <a href=#subsec:set-mode-for-app-ops-dots>1-click ops\npage</a> or from the <a href=#subsubsec:app-ops>app ops tab</a>.</section><section id=new-batch-ops-add-to-profile class=level3 data-number=6.9.5><h3 data-number=6.9.5><span class=header-section-number>6.9.5</span>\n<a href=#toc:new-batch-ops-add-to-profile>New Batch Ops: Add to\nProfile</a><a href=#new-batch-ops-add-to-profile class=anchor aria-hidden=true></a></h3><p>You can now easily add selected apps to an existing profile using the\nbatch operations.</section><section id=app-info-improved class=level3 data-number=6.9.6><h3 data-number=6.9.6><span class=header-section-number>6.9.6</span>\n<a href=#toc:app-info-improved>App Info: Improved</a><a href=#app-info-improved class=anchor aria-hidden=true></a></h3><p>App info tab now has many options, including the ability to change <a href=#sec:terminologies>SSAID</a>, network policy (i.e. background\nnetwork usage), battery optimization, etc. Most of the tags used in this\ntab are also clickable, and if you click on them, you will be able to\nlook at the current state or configure them right away.</section><section id=advanced-sort-and-filtering-options-in-the-main-page class=level3 data-number=6.9.7><h3 data-number=6.9.7><span class=header-section-number>6.9.7</span>\n<a href=#toc:advanced-sort-and-filtering-options-in-the-main-page>Advanced\nSort and Filtering Options in the Main Page</a><a href=#advanced-sort-and-filtering-options-in-the-main-page class=anchor aria-hidden=true></a></h3><p>Sort and filter options are now replaced by <a href=#subsubsec:main-list-options>List Options</a> which is highly\nconfigurable, including the ability to filter using profiles.</section><section id=about-this-device class=level3 data-number=6.9.8><h3 data-number=6.9.8><span class=header-section-number>6.9.8</span>\n<a href=#toc:about-this-device>About This Device</a><a href=#about-this-device class=anchor aria-hidden=true></a></h3><p>Interested in knowing about your device in just one page? Go to the\nbottom of the <a href=#subsec:device-info>settings page</a>.</section><section id=enabledisable-features class=level3 data-number=6.9.9><h3 data-number=6.9.9><span class=header-section-number>6.9.9</span>\n<a href=#toc:enabledisable-features>Enable/disable Features</a><a href=#enabledisable-features class=anchor aria-hidden=true></a></h3><p>Not interested in all the features that AM offers? You can disable\nsome features in <a href=#subsubsec:enable/disable-features>settings</a>.</section><section id=new-languages-1 class=level3 data-number=6.9.10><h3 data-number=6.9.10><span class=header-section-number>6.9.10</span> <a href=#toc:new-languages-1>New Languages</a><a href=#new-languages-1 class=anchor aria-hidden=true></a></h3><p>AM now has more than 19 languages! New languages include Farsi,\nJapanese and Traditional Chinese.</section><section id=signing-the-apk-files class=level3 data-number=6.9.11><h3 data-number=6.9.11><span class=header-section-number>6.9.11</span> <a href=#toc:signing-the-apk-files>Signing the APK Files</a><a href=#signing-the-apk-files class=anchor aria-hidden=true></a></h3><p>You can now import external signing keys in AM! For security, App\nManager has its own encrypted KeyStore which can also be <a href=#subsubsec:import/export-keystore>imported or exported</a>.</section><section id=new-extension-unapkm class=level3 data-number=6.9.12><h3 data-number=6.9.12><span class=header-section-number>6.9.12</span> <a href=#toc:new-extension-unapkm>New Extension: UnAPKM</a><a href=#new-extension-unapkm class=anchor aria-hidden=true></a></h3><p>Since APKMirror has removed encryption from their APKM files, it’s no\nlonger necessary to decrypt them. As a result, the option to decrypt\nAPKM files has been removed. Instead, this option is now provided by the\nUnAPKM extension which you can grab from <a href=https://f-droid.org/packages/io.github.muntashirakon.unapkm/>F-Droid</a>.\nSo, if you have an encrypted APKM file and have this extension\ninstalled, you can open the file directly in AM.</section></section><section id=sec:v2.5.20-(375) class=level2 data-number=6.10><h2 data-number=6.10><span class=header-section-number>6.10</span>\n<a href=#toc:sec:v2.5.20-(375)>v2.5.20 (375)</a><a href=#sec:v2.5.20-(375) class=anchor aria-hidden=true></a></h2><section id=subsec:introducing-profiles class=level3 data-number=6.10.1><h3 data-number=6.10.1><span class=header-section-number>6.10.1</span> <a href=#toc:subsec:introducing-profiles>Introducing Profiles</a><a href=#subsec:introducing-profiles class=anchor aria-hidden=true></a></h3><p><a href=#sec:profile-page>Profiles</a> finally closes the <a href=https://github.com/MuntashirAkon/AppManager/issues/72>related\nissue</a>. Profiles can be used to execute certain tasks repeatedly\nwithout doing everything manually. A profile can be applied (or invoked)\neither from the <a href=#sec:profiles-page>Profiles page</a> or from\nthe home screen by creating shortcuts. There are also some presets which\nconsist of debloating profiles taken from <a href=https://gitlab.com/W1nst0n/universal-android-debloater>Universal\nAndroid Debloater</a>.<section id=known-limitations class=level5 data-number=6.10.1.0.1><h5 data-number=6.10.1.0.1><span class=header-section-number>6.10.1.0.1</span> Known limitations<a href=#known-limitations class=anchor aria-hidden=true></a></h5><ul class=incremental><li><p>Exporting rules and applying permissions are not currently\nworking.<li><p>Profiles are applied for all users.</ul></section></section><section id=subsec:the-interceptor class=level3 data-number=6.10.2><h3 data-number=6.10.2><span class=header-section-number>6.10.2</span> <a href=#toc:subsec:the-interceptor>The Interceptor</a><a href=#subsec:the-interceptor class=anchor aria-hidden=true></a></h3><p><a href=https://github.com/MuntashirAkon/intent-intercept>Intent\nIntercept</a> works as a man-in-the-middle between source and\ndestination, that is, when you open a file or URL with another app, you\ncan see what is being shared by opening it with Interceptor first. You\ncan also add or modify the intents before sending them to the\ndestination. Additionally, you can double-click on any exportable\nactivities in the Activities tab in the App Details page to open them in\nthe Interceptor to add more configurations.<section id=known-limitation-2 class=level5 data-number=6.10.2.0.1><h5 data-number=6.10.2.0.1><span class=header-section-number>6.10.2.0.1</span> Known limitation<a href=#known-limitation-2 class=anchor aria-hidden=true></a></h5><p>Editing extras is not currently possible.</section></section><section id=subsec:unapkm:-dedrm-the-apkm-files class=level3 data-number=6.10.3><h3 data-number=6.10.3><span class=header-section-number>6.10.3</span> <a href=#toc:subsec:unapkm:-dedrm-the-apkm-files>UnAPKM: DeDRM the APKM\nfiles</a><a href=#subsec:unapkm:-dedrm-the-apkm-files class=anchor aria-hidden=true></a></h3><p>When I released a small tool called <a href=https://f-droid.org/en/packages/io.github.muntashirakon.unapkm>UnAPKM</a>,\nI promised that similar feature will be available in App Manager. I am\nproud to announce that you can open APKM files directly in the App Info\npage or convert them to APKS or install them directly.</section><section id=subsec:multiple-user class=level3 data-number=6.10.4><h3 data-number=6.10.4><span class=header-section-number>6.10.4</span> <a href=#toc:subsec:multiple-user>Multiple user</a><a href=#subsec:multiple-user class=anchor aria-hidden=true></a></h3><p>App manager now supports multiple users! For now, this requires root\nor ADB. But no-root support is also being considered. If you have\nmultiple users enabled and click on an app installed in multiple\nprofiles, an alert prompt will be displayed where you can select the\nuser.</section><section id=vive-la-france class=level3 data-number=6.10.5><h3 data-number=6.10.5><span class=header-section-number>6.10.5</span> <a href=#toc:vive-la-france>Vive la France!</a><a href=#vive-la-france class=anchor aria-hidden=true></a></h3><p>Thanks to the contributors, we have one more addition to the language\nclub: French. You can add more languages or improve existing\ntranslations at <a href=https://hosted.weblate.org/engage/app-manager>Weblate</a>.</section><section id=report-crashes class=level3 data-number=6.10.6><h3 data-number=6.10.6><span class=header-section-number>6.10.6</span> <a href=#toc:report-crashes>Report crashes</a><a href=#report-crashes class=anchor aria-hidden=true></a></h3><p>If App Manager crashes, you can now easily report the crash from the\nnotifications which opens the share options. Crashes are not reported by\nApp Manager, it only redirects you to your favourite Email client.</section><section id=android-11 class=level3 data-number=6.10.7><h3 data-number=6.10.7><span class=header-section-number>6.10.7</span> <a href=#toc:android-11>Android 11</a><a href=#android-11 class=anchor aria-hidden=true></a></h3><p>Added support for Android 11. Not everything may work as expected\nthough.</section><section id=app-installer-improvements class=level3 data-number=6.10.8><h3 data-number=6.10.8><span class=header-section-number>6.10.8</span> <a href=#toc:app-installer-improvements>App Installer Improvements</a><a href=#app-installer-improvements class=anchor aria-hidden=true></a></h3><section id=set-installation-locations class=level4 data-number=6.10.8.1><h4 data-number=6.10.8.1><span class=header-section-number>6.10.8.1</span> Set installation\nlocations<a href=#set-installation-locations class=anchor aria-hidden=true></a></h4><p>In settings page, you can set install locations such as auto\n(default), internal only and prefer external.</section><section id=set-apk-installer class=level4 data-number=6.10.8.2><h4 data-number=6.10.8.2><span class=header-section-number>6.10.8.2</span> Set APK installer<a href=#set-apk-installer class=anchor aria-hidden=true></a></h4><p>In settings page, you can also set default APK installer (root/ADB\nonly) instead of App Manager.</section><section id=multiple-users class=level4 data-number=6.10.8.3><h4 data-number=6.10.8.3><span class=header-section-number>6.10.8.3</span> Multiple users<a href=#multiple-users class=anchor aria-hidden=true></a></h4><p>In settings page, you can allow App Manager to display multiple users\nduring APK installation.</section><section id=signing-apk-files class=level4 data-number=6.10.8.4><h4 data-number=6.10.8.4><span class=header-section-number>6.10.8.4</span> Signing APK files<a href=#signing-apk-files class=anchor aria-hidden=true></a></h4><p>In settings page, you can choose to sign APK files before installing\nthem. You can also select which signature scheme to use in the <em>APK\nsigning</em> option in settings.<section id=known-limitation-3 class=level5 data-number=6.10.8.4.1><h5 data-number=6.10.8.4.1><span class=header-section-number>6.10.8.4.1</span> Known limitation<a href=#known-limitation-3 class=anchor aria-hidden=true></a></h5><p>Currently, only a generic key is used to sign APK files</section></section></section></section><section id=v2.5.17-368 class=level2 data-number=6.11><h2 data-number=6.11><span class=header-section-number>6.11</span>\n<a href=#toc:v2.5.17-368>v2.5.17 (368)</a><a href=#v2.5.17-368 class=anchor aria-hidden=true></a></h2><section id=app-installer class=level3 data-number=6.11.1><h3 data-number=6.11.1><span class=header-section-number>6.11.1</span> <a href=#toc:app-installer>App Installer</a><a href=#app-installer class=anchor aria-hidden=true></a></h3><p>As promised, it is now possible to select splits. AM also provides\nrecommendations based on device configurations. If the app is already\ninstalled, recommendations are provided based on the installed app. It\nis also possible to downgrade to a lower version without data loss if\nthe device has root or ADB. But it should be noted that not all app can\nbe downgraded. Installer is also improved to speed up the installation\nprocess, especially, for root users. If the app has already been\ninstalled and the new (x)apk(s) is newer or older or the same version\nwith a different signature, AM will display a list of changes similar to\n<strong>What’s New</strong> before prompting the user to install the\napp. This is useful if the app has introduced tracker components, new\npermissions, etc.<section id=known-limitations-1 class=level5 data-number=6.11.1.0.1><h5 data-number=6.11.1.0.1><span class=header-section-number>6.11.1.0.1</span> Known Limitations<a href=#known-limitations-1 class=anchor aria-hidden=true></a></h5><ul class=incremental><li><p>Large app can take a long time to fetch app info, and therefore,\nit may take a long time display the installation prompt.<li><p>If the apk is not located in the internal storage, the app has to\nbe cached first which might also take a long time depending on the size\nof the apk.</ul></section></section><section id=scanner-replacement-for-exodus-page class=level3 data-number=6.11.2><h3 data-number=6.11.2><span class=header-section-number>6.11.2</span> <a href=#toc:scanner-replacement-for-exodus-page>Scanner: Replacement for\nExodus Page</a><a href=#scanner-replacement-for-exodus-page class=anchor aria-hidden=true></a></h3><p>Exodus page is now replaced with scanner page. <a href=#sec:scanner-page>Scanner page</a> contains not only a list of\ntrackers but also a list of used libraries. This is just a start. In the\nfuture, this page will contain more in depth analysis of the app.</section><section id=introducing-system-config class=level3 data-number=6.11.3><h3 data-number=6.11.3><span class=header-section-number>6.11.3</span> <a href=#toc:introducing-system-config>Introducing System Config</a><a href=#introducing-system-config class=anchor aria-hidden=true></a></h3><p>System Config lists various system configurations and\nwhitelists/blacklists included in Android by either OEM/vendor, AOSP or\neven some Magisk modules. Root users can access this option from the\noverflow menu in the main page. There isn’t any official documentation\nfor these options therefore it’s difficult to write a complete\ndocumentation for this page. I will gradually add documentations using\nmy own knowledge. However, some functions should be understandable by\ntheir name.</section><section id=more-languages class=level3 data-number=6.11.4><h3 data-number=6.11.4><span class=header-section-number>6.11.4</span> <a href=#toc:more-languages>More Languages</a><a href=#more-languages class=anchor aria-hidden=true></a></h3><p>Thanks to the contributors, AM now has more than 12 languages. New\nlanguages include Bengali, Hindi, Norwegian, Polish, Russian, Simplified\nChinese, Turkish and Ukrainian.</section><section id=app-info-tab class=level3 data-number=6.11.5><h3 data-number=6.11.5><span class=header-section-number>6.11.5</span> <a href=#toc:app-info-tab>App Info Tab</a><a href=#app-info-tab class=anchor aria-hidden=true></a></h3><p>More tags are added in the <a href=#subsec:app-info-tab>app info\ntab</a> such as <strong>KeyStore</strong> (apps with KeyStore items),\n<strong>Systemless app</strong> (apps installed via Magisk),\n<strong>Running</strong> (apps that are running). For external apk, two\nmore options are added namely <strong>Reinstall</strong> and\n<strong>Downgrade</strong>. Now it is possible to share an apk via\nBluetooth. For system apps, it is possible to uninstall updates for\nroot/ADB users. But like the similar option in the system settings, this\noperation will clear all app data. As stated above, exodus has been\nreplaced with scanner.</section><section id=navigation-improvements class=level3 data-number=6.11.6><h3 data-number=6.11.6><span class=header-section-number>6.11.6</span> <a href=#toc:navigation-improvements>Navigation Improvements</a><a href=#navigation-improvements class=anchor aria-hidden=true></a></h3><p>It’s now relatively easy to navigate to various UI components using\nkeyboard. You can use up/down button to navigate between list items and\ntab button to navigate to UI components inside an item.</section><section id=running-apps-page class=level3 data-number=6.11.7><h3 data-number=6.11.7><span class=header-section-number>6.11.7</span> <a href=#toc:running-apps-page>Running Apps Page</a><a href=#running-apps-page class=anchor aria-hidden=true></a></h3><p>It is now possible to sort and filter processes in this tab. Also,\nthe three big buttons are replaced with an easy-to-use three dot menu.\nPreviously the memory usage was wrong which is fixed in this\nversion.</section><section id=built-in-toybox class=level3 data-number=6.11.8><h3 data-number=6.11.8><span class=header-section-number>6.11.8</span> <a href=#toc:built-in-toybox>Built-in Toybox</a><a href=#built-in-toybox class=anchor aria-hidden=true></a></h3><p>Toybox (an alternative to busybox) is bundled with AM. Although\nAndroid has this utility built-in from API 23, toybox is bundled in\norder to prevent buggy implementations and to support API &lt; 23.</section><section id=component-blocker-improvements class=level3 data-number=6.11.9><h3 data-number=6.11.9><span class=header-section-number>6.11.9</span> <a href=#toc:component-blocker-improvements>Component Blocker\nImprovements</a><a href=#component-blocker-improvements class=anchor aria-hidden=true></a></h3><p>Component blocker seemed to be problematic in the previous version,\nespecially when global component blocking is enabled. The issues are\nmostly fixed now.<div class=\"amalert warning\"><p><strong><em>Caution.</em></strong><p>The component blocking mechanism is no longer compatible with v2.5.6\ndue to various security issues. If you have this version, upgrade to\nv2.5.13 or earlier versions first. After that, enable <a href=#subsubsec:instant-component-blocking>global component\nblocking</a> and disable it again.</div></section><section id=improvements-in-the-app-details-page class=level3 data-number=6.11.10><h3 data-number=6.11.10><span class=header-section-number>6.11.10</span> <a href=#toc:improvements-in-the-app-details-page>Improvements in the App\nDetails Page</a><a href=#improvements-in-the-app-details-page class=anchor aria-hidden=true></a></h3><p>Value of various app ops depend on their parent app ops. Therefore,\nwhen you allow/deny an app op, the parent of the app op gets modified.\nThis fixes the issues some users have been complaining regarding some\napp ops that couldn’t be changed.<p>If an app has the target API 23 or less, its permissions cannot be\nmodified using the <code>pm grant …</code> command. Therefore, for such\napps, option to toggle permission has been disabled.<p>The signature tab is improved to support localization. It also\ndisplays multiple checksums for a signature.</section><section id=app-manifest class=level3 data-number=6.11.11><h3 data-number=6.11.11><span class=header-section-number>6.11.11</span> <a href=#toc:app-manifest>App Manifest</a><a href=#app-manifest class=anchor aria-hidden=true></a></h3><p>Manifest no longer crashes if the size of the manifest is too long.\nGenerated manifest are now more accurate than before.</section></section><section id=v2.5.13-348 class=level2 data-number=6.12><h2 data-number=6.12><span class=header-section-number>6.12</span>\n<a href=#toc:v2.5.13-348>v2.5.13 (348)</a><a href=#v2.5.13-348 class=anchor aria-hidden=true></a></h2><section id=bundled-app-split-apk class=level3 data-number=6.12.1><h3 data-number=6.12.1><span class=header-section-number>6.12.1</span> <a href=#toc:bundled-app-split-apk>Bundled App (Split APK)</a><a href=#bundled-app-split-apk class=anchor aria-hidden=true></a></h3><p>Bundled app formats such as <strong>apks</strong> and\n<strong>xapk</strong> are now supported. You can install these apps\nusing the regular installation buttons. For root and adb users, apps are\ninstalled using shell, and for non-root users, the platform default\nmethod is used.<section id=known-limitations-2 class=level5 data-number=6.12.1.0.1><h5 data-number=6.12.1.0.1><span class=header-section-number>6.12.1.0.1</span> Known Limitations<a href=#known-limitations-2 class=anchor aria-hidden=true></a></h5><ul class=incremental><li><p>Currently <em>all</em> splits apks are installed. But this\nbehaviour is going to change in the next release. If you only need a few\nsplits instead of all, extract the <strong>APKS</strong> or\n<strong>XAPK</strong> file, and then, create a new zip file with your\ndesired split apks and replace the <strong>ZIP</strong> extension with\n<strong>APKS</strong>. Now, open it with AM.<li><p>There is no progress dialog to display the installation\nprogress.</ul></section></section><section id=direct-install-support class=level3 data-number=6.12.2><h3 data-number=6.12.2><span class=header-section-number>6.12.2</span> <a href=#toc:direct-install-support>Direct Install Support</a><a href=#direct-install-support class=anchor aria-hidden=true></a></h3><p>You can now install <strong>APK</strong>, <strong>APKS</strong> or\n<strong>XAPK</strong> directly from your favourite browser or file\nmanager. For apps that need updates, a <strong>What’s New</strong>\ndialog is displayed showing the changes in the new version.<section id=known-limitations-3 class=level5 data-number=6.12.2.0.1><h5 data-number=6.12.2.0.1><span class=header-section-number>6.12.2.0.1</span> Known Limitations<a href=#known-limitations-3 class=anchor aria-hidden=true></a></h5><ul class=incremental><li><p>Downgrade is not yet possible.<li><p>There is no progress dialog to display the installation progress.\nIf you cannot interact with the current page, wait until the\ninstallation is finished.</ul></section></section><section id=remove-all-blocking-rules class=level3 data-number=6.12.3><h3 data-number=6.12.3><span class=header-section-number>6.12.3</span> <a href=#toc:remove-all-blocking-rules>Remove All Blocking Rules</a><a href=#remove-all-blocking-rules class=anchor aria-hidden=true></a></h3><p>In the Settings page, a new option is added which can be used to\nremove all blocking rules configured within App Manager.</section><section id=app-ops-1 class=level3 data-number=6.12.4><h3 data-number=6.12.4><span class=header-section-number>6.12.4</span> <a href=#toc:app-ops-1>App\nOps</a><a href=#app-ops-1 class=anchor aria-hidden=true></a></h3><ul class=incremental><li><p>App Ops are now generated using a technique similar to AppOpsX.\nThis should decrease the loading time significantly in the App Ops\ntab.<li><p>In the App Ops tab, a menu item is added which can be used to\nlist only active app ops without including the default app ops. The\npreference is saved in the shared preferences.</ul><section id=known-limitation-4 class=level5 data-number=6.12.4.0.1><h5 data-number=6.12.4.0.1><span class=header-section-number>6.12.4.0.1</span> Known Limitation<a href=#known-limitation-4 class=anchor aria-hidden=true></a></h5><p>Often the App Ops tab may not be responsive. If that’s the case,\nrestart App Manager.</section></section><section id=enhanced-adb-support class=level3 data-number=6.12.5><h3 data-number=6.12.5><span class=header-section-number>6.12.5</span> <a href=#toc:enhanced-adb-support>Enhanced ADB Support</a><a href=#enhanced-adb-support class=anchor aria-hidden=true></a></h3><p>ADB shell commands are now executed using a technique similar to\nAppOpsX (This is the <em>free</em> alternative of AppOps by Rikka.).\nThis should dramatically increase the execution time.<section id=known-limitation-5 class=level5 data-number=6.12.5.0.1><h5 data-number=6.12.5.0.1><span class=header-section-number>6.12.5.0.1</span> Known Limitation<a href=#known-limitation-5 class=anchor aria-hidden=true></a></h5><p>AM can often crash or become not responsive. If that’s the case,\nrestart App Manager.</section></section><section id=filtering-in-main-page class=level3 data-number=6.12.6><h3 data-number=6.12.6><span class=header-section-number>6.12.6</span> <a href=#toc:filtering-in-main-page>Filtering in Main Page</a><a href=#filtering-in-main-page class=anchor aria-hidden=true></a></h3><p>Add an option to filter apps that has at least one activity.</section><section id=apk-backupsharing class=level3 data-number=6.12.7><h3 data-number=6.12.7><span class=header-section-number>6.12.7</span> <a href=#toc:apk-backupsharing>Apk Backup/Sharing</a><a href=#apk-backupsharing class=anchor aria-hidden=true></a></h3><p>Apk files are now saved as <code>app name_version.extension</code>\ninstead of <code>package.name.extension</code>.</section><section id=batch-ops class=level3 data-number=6.12.8><h3 data-number=6.12.8><span class=header-section-number>6.12.8</span> <a href=#toc:batch-ops>Batch Ops</a><a href=#batch-ops class=anchor aria-hidden=true></a></h3><ul class=incremental><li><p>Added a foreground service to run batch operations. The result of\nthe operation is displayed in a notification. If an operation has failed\nfor some packages, clicking on the notification will open a dialog box\nlisting the failed packages. There is also a <strong>Try Again</strong>\nbutton on the bottom which can be used to perform the operation again\nfor the failed packages.<li><p>Replaced Linux <em>kill</em> with\n<strong>force-stop</strong>.</ul></section><section id=translations class=level3 data-number=6.12.9><h3 data-number=6.12.9><span class=header-section-number>6.12.9</span> <a href=#toc:translations>Translations</a><a href=#translations class=anchor aria-hidden=true></a></h3><p>Added German and Portuguese (Brazilian) translations.<section id=known-limitation-6 class=level5 data-number=6.12.9.0.1><h5 data-number=6.12.9.0.1><span class=header-section-number>6.12.9.0.1</span> Known Limitation<a href=#known-limitation-6 class=anchor aria-hidden=true></a></h5><p>Not all translations are verified yet.</section></section><section id=app-data-backup class=level3 data-number=6.12.10><h3 data-number=6.12.10><span class=header-section-number>6.12.10</span> <a href=#toc:app-data-backup>App Data Backup</a><a href=#app-data-backup class=anchor aria-hidden=true></a></h3><p>Install app only for the current user at the time of restoring\nbackups. Support for split apks is also added.<p><em>Data backup feature is now considered unstable. If you encounter\nany problem, please report to me without hesitation.</em></section></section></section><section id=ch:app-ops class=level1 data-number=7><h1 data-number=7><span class=header-section-number>7</span> <a href=#toc:ch:app-ops>App Ops</a><a href=#ch:app-ops class=anchor aria-hidden=true></a></h1><section id=sec:app-ops-background class=level2 data-number=7.1><h2 data-number=7.1><span class=header-section-number>7.1</span> <a href=#toc:sec:app-ops-background>Background</a><a href=#sec:app-ops-background class=anchor aria-hidden=true></a></h2><p><strong>App Ops</strong> (short hand for <strong>Application\nOperations</strong>) are used by Android system (since Android 4.3) to\ncontrol application permissions. The user <em>can</em> control some\npermissions, but only the permissions that are considered dangerous (and\nGoogle thinks knowing your phone number isn’t a dangerous thing). So,\napp ops seems to be the one we need if we want to install apps like\nFacebook and it’s Messenger (the latter literary records everything if\nyou live outside the EU) and still want <em>some</em> privacy and/or\nsecurity. Although certain features of app ops were available in\nSettings and later in hidden settings in older version of Android, it’s\ncompletely hidden in newer versions of Android and is continued to be\nkept hidden. Now, any app with\n<strong>android.Manifest.permission.GET_APP_OPS_STATS</strong>\npermission can get the app ops information for other applications but\nthis permission is hidden from users and can only be enabled using ADB\nor root. Still, the app with this permission cannot grant or revoke\npermissions (actually mode of operation) for apps other than itself\n(with limited capacity, of course). To modify the ops of other app, the\napp needs\n<strong>android.Manifest.permission.UPDATE_APP_OPS_STATS</strong>\npermissions which isn’t accessible via <code>pm</code> command. So, you\ncannot grant it via root or ADB, the permission is only granted to the\nsystem apps. There are very few apps who support disabling permissions\nvia app ops. The best one to my knowledge is <a href=https://github.com/8enet/AppOpsX>AppOpsX</a>. The main (visible)\ndifference between my app (AppManager) and this app is that the latter\nalso provides you the ability to revoke internet permissions (by writing\nip tables). One crucial problem that I faced during the development of\nthe app ops API is the lack of documentation in English language.</section><section id=sec:introduction-to-app-ops class=level2 data-number=7.2><h2 data-number=7.2><span class=header-section-number>7.2</span> <a href=#toc:sec:introduction-to-app-ops>Introduction to App Ops</a><a href=#sec:introduction-to-app-ops class=anchor aria-hidden=true></a></h2><figure id=fig:appops><figure><object data=../images/appops.svg type=image/svg+xml></object></figure><figcaption>Figure 2: How app ops work</figcaption></figure><p>Figure <a href=#fig:appops>1</a> describes the process of changing\nand processing permission. <a href=#sec:appopsmanager>AppOpsManager</a> can be used to manage\npermissions in Settings app. <strong>AppOpsManager</strong> is also\nuseful in determining if a certain permission (or operation) is granted\nto the application. Most of the methods of\n<strong>AppOpsManager</strong> are accessible to the user app but unlike\na system app, it can only be used to check permissions for any app or\nfor the app itself and start or terminating certain operations.\nMoreover, not all operations are actually accessible from this Java\nclass. <strong>AppOpsManager</strong> holds all the necessary constants\nsuch as <a href=#subsec:op-constants><code>OP_*</code></a>,\n<code>OPSTR_*</code>, <a href=#subsec:mode-constants><code>MODE_*</code></a> which describes\noperation code, operation string and mode of operations respectively. It\nalso holds necessary data structures such as <a href=#subsec:package-ops>PackageOps</a> and <strong>OpEntry</strong>.\n<strong>PackageOps</strong> holds <strong>OpEntry</strong> for a\npackage, and <strong>OpEntry</strong>, as the name suggests, describes\neach operation.<p><code>AppOpService</code> is completely hidden from a user\napplication but accessible to the system applications. As it can be seen\nin Figure <a href=#fig:appops>1</a>, this is the class that does the\nactual management stuff. It contains data structures such as\n<strong>Ops</strong> to store basic package info and <strong>Op</strong>\nwhich is similar to <strong>OpEntry</strong> of\n<strong>AppOpsManager</strong>. It also has <strong>Shell</strong> which\nis actually the source code of the <a href=#sec:appops-cli><em>appops</em> command line tool</a>. It writes\nconfigurations to or read configurations from <a href=#sec:appops-xml><code>/data/system/appops.xml</code></a>. System\nservices calls <strong>AppOpsService</strong> to find out what an\napplication is allowed and what is not allowed to perform, and\n<strong>AppOpsService</strong> determines these permissions by parsing\n<code>/data/system/appops.xml</code>. If no custom values are present in\n<em>appops.xml</em>, it returns the default mode available in\n<strong>AppOpsManager</strong>.</section><section id=sec:appopsmanager class=level2 data-number=7.3><h2 data-number=7.3><span class=header-section-number>7.3</span> <a href=#toc:sec:appopsmanager>AppOpsManager</a><a href=#sec:appopsmanager class=anchor aria-hidden=true></a></h2><p><a href=https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/app/AppOpsManager.java>AppOpsManager</a>\nstands for application operations manager. It consists of various\nconstants and classes to modify app operations.<div class=seealso-inline><p><em>Ver também: <span><a href=https://developer.android.com/reference/android/app/AppOpsManager>AppOpsManager\ndocumentation</a></span></em></div><section id=subsec:op-constants class=level3 data-number=7.3.1><h3 data-number=7.3.1><span class=header-section-number>7.3.1</span>\n<a href=#toc:subsec:op-constants><code>OP_*</code> Constants</a><a href=#subsec:op-constants class=anchor aria-hidden=true></a></h3><p><code>OP_*</code> are the integer constants starting from\n<code>0</code>. <code>OP_NONE</code> implies that no operations are\nspecified whereas <code>_NUM_OP</code> denotes the number of operations\ndefined in <code>OP_*</code> prefix. While they denote each operation,\nthe operations are not necessarily unique. In fact, there are many\noperations that are actually a single operation denoted by multiple\n<code>OP_*</code> constant (possibly for future use). Vendors may define\ntheir own op based on their requirements. MIUI is one of the vendors who\nare known to do that.<div class=listing><div class=sourceCode id=cb11 data-frame=lines><pre class=\"sourceCode java\"><code class=\"sourceCode java\"><span id=cb11-1><a href=#cb11-1 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=dt>final</span> <span class=dt>int</span> OP_NONE <span class=op>=</span> <span class=op>-</span><span class=dv>1</span><span class=op>;</span></span>\n<span id=cb11-2><a href=#cb11-2 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=dt>final</span> <span class=dt>int</span> OP_COARSE_LOCATION <span class=op>=</span> <span class=dv>0</span><span class=op>;</span></span>\n<span id=cb11-3><a href=#cb11-3 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=dt>final</span> <span class=dt>int</span> OP_FINE_LOCATION <span class=op>=</span> <span class=dv>1</span><span class=op>;</span></span>\n<span id=cb11-4><a href=#cb11-4 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=dt>final</span> <span class=dt>int</span> OP_GPS <span class=op>=</span> <span class=dv>2</span><span class=op>;</span></span>\n<span id=cb11-5><a href=#cb11-5 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=dt>final</span> <span class=dt>int</span> OP_VIBRATE <span class=op>=</span> <span class=dv>3</span><span class=op>;</span></span>\n<span id=cb11-6><a href=#cb11-6 aria-hidden=true tabindex=-1></a><span class=kw>...</span></span>\n<span id=cb11-7><a href=#cb11-7 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=dt>final</span> <span class=dt>int</span> OP_READ_DEVICE_IDENTIFIERS <span class=op>=</span> <span class=dv>89</span><span class=op>;</span></span>\n<span id=cb11-8><a href=#cb11-8 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=dt>final</span> <span class=dt>int</span> OP_ACCESS_MEDIA_LOCATION <span class=op>=</span> <span class=dv>90</span><span class=op>;</span></span>\n<span id=cb11-9><a href=#cb11-9 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=dt>final</span> <span class=dt>int</span> OP_ACTIVATE_PLATFORM_VPN <span class=op>=</span> <span class=dv>91</span><span class=op>;</span></span>\n<span id=cb11-10><a href=#cb11-10 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=dt>final</span> <span class=dt>int</span> _NUM_OP <span class=op>=</span> <span class=dv>92</span><span class=op>;</span></span></code></pre></div></div><p>Whether an operation is unique is defined by\n<code>sOpToSwitch</code>. It maps each operation to another operation or\nto itself (if it’s a unique operation). For instance,\n<code>OP_FINE_LOCATION</code> and <code>OP_GPS</code> are mapped to\n<code>OP_COARSE_LOCATION</code>.<p>Each operation has a private name which are described by\n<code>sOpNames</code>. These names are usually the same names as the\nconstants without the <code>OP_</code> prefix. Some operations have\npublic names as well which are described by <code>sOpToString</code>.\nFor instance, <code>OP_COARSE_LOCATION</code> has the public name\n<strong>android:coarse_location</strong>.<p>As a gradual process of moving permissions to app ops, there are\nalready many permissions that are defined under some operations. These\npermissions are mapped in <code>sOpPerms</code>. For example, the\npermission\n<strong>android.Manifest.permission.ACCESS_COARSE_LOCATION</strong> is\nmapped to <code>OP_COARSE_LOCATION</code>. Some operations may not have\nany associated permissions which have <code>null</code> values.<p>As described in the previous section, operations that are configured\nfor an app are stored at <a href=#sec:appops-xml><code>/data/system/appops.xml</code></a>. If an\noperation is not configured, then whether system will allow that\noperation is determined from <code>sOpDefaultMode</code>. It lists the\n<em>default mode</em> for each operation.</section><section id=subsec:mode-constants class=level3 data-number=7.3.2><h3 data-number=7.3.2><span class=header-section-number>7.3.2</span>\n<a href=#toc:subsec:mode-constants><code>MODE_*</code> Constants</a><a href=#subsec:mode-constants class=anchor aria-hidden=true></a></h3><p><code>MODE_*</code> constants also integer constants starting from\n<code>0</code>. These constants are assigned to each operation\ndescribing whether an app is authorised to perform that operation. These\nmodes usually have associated names such as <strong>allow</strong> for\n<code>MODE_ALLOWED</code>, <strong>ignore</strong> for\n<code>MODE_IGNORED</code>, <strong>deny</strong> for\n<code>MODE_ERRORED</code> (a rather misnomer), <strong>default</strong>\nfor <code>MODE_DEFAULT</code> and <strong>foreground</strong> for\n<code>MODE_FOREGROUND</code>.<ol class=incremental><li><p><strong><code>MODE_ALLOWED</code>.</strong> The app is allowed to\nperform the given operation<li><p><strong><code>MODE_IGNORED</code>.</strong> The app is not\nallowed to perform the given operation, and any attempt to perform the\noperation should <em>silently fail</em>, i.e. it should not cause the\napp to crash<li><p><strong><code>MODE_ERRORED</code>.</strong> The app is not\nallowed to perform the given operation, and this attempt should cause it\nto have a fatal error, typically a\n<code>SecurityException</code><li><p><strong><code>MODE_DEFAULT</code>.</strong> The app should use\nits default security check, specified in\n<code>AppOpsManager</code><li><p><strong><code>MODE_FOREGROUND</code>.</strong> Special mode that\nmeans “allow only when app is in foreground.” This mode was added in\nAndroid 10<li><p><strong><code>MODE_ASK</code>.</strong> This is a custom mode\nused by MIUI whose uses are unknown.</ol></section><section id=subsec:package-ops class=level3 data-number=7.3.3><h3 data-number=7.3.3><span class=header-section-number>7.3.3</span>\n<a href=#toc:subsec:package-ops>PackageOps</a><a href=#subsec:package-ops class=anchor aria-hidden=true></a></h3><p><strong>AppOpsManager.PackageOps</strong> is a data structure to\nstore all the <strong>OpEntry</strong> for a package. In simple terms,\nit stores all the customised operations for a package.<div class=listing><div class=sourceCode id=cb12 data-frame=lines><pre class=\"sourceCode java\"><code class=\"sourceCode java\"><span id=cb12-1><a href=#cb12-1 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=kw>class</span> PackageOps <span class=kw>implements</span> Parcelable <span class=op>{</span></span>\n<span id=cb12-2><a href=#cb12-2 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=bu>String</span> mPackageName<span class=op>;</span></span>\n<span id=cb12-3><a href=#cb12-3 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=dt>int</span> mUid<span class=op>;</span></span>\n<span id=cb12-4><a href=#cb12-4 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=bu>List</span><span class=op>&lt;</span>OpEntry<span class=op>&gt;</span> mEntries<span class=op>;</span></span>\n<span id=cb12-5><a href=#cb12-5 aria-hidden=true tabindex=-1></a>    <span class=kw>...</span></span>\n<span id=cb12-6><a href=#cb12-6 aria-hidden=true tabindex=-1></a><span class=op>}</span></span></code></pre></div></div><p>As can be seen in Listing <a href=#lst:package-ops-class>2</a>, it\nstores all <strong>OpEntry</strong> for a package as well as the\ncorresponding package name and its kernel user ID.</section><section id=subsec:opentry class=level3 data-number=7.3.4><h3 data-number=7.3.4><span class=header-section-number>7.3.4</span>\n<a href=#toc:subsec:opentry>OpEntry</a><a href=#subsec:opentry class=anchor aria-hidden=true></a></h3><p><strong>AppOpsManager.OpEntry</strong> is a data structure that\nstores a single operation for any package.<div class=listing><div class=sourceCode id=cb13 data-frame=lines><pre class=\"sourceCode java\"><code class=\"sourceCode java\"><span id=cb13-1><a href=#cb13-1 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=dt>final</span> <span class=kw>class</span> OpEntry <span class=kw>implements</span> Parcelable <span class=op>{</span></span>\n<span id=cb13-2><a href=#cb13-2 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=dt>int</span> mOp<span class=op>;</span></span>\n<span id=cb13-3><a href=#cb13-3 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=dt>boolean</span> mRunning<span class=op>;</span></span>\n<span id=cb13-4><a href=#cb13-4 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=at>@Mode</span> <span class=dt>int</span> mMode<span class=op>;</span></span>\n<span id=cb13-5><a href=#cb13-5 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=at>@Nullable</span> LongSparseLongArray mAccessTimes<span class=op>;</span></span>\n<span id=cb13-6><a href=#cb13-6 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=at>@Nullable</span> LongSparseLongArray mRejectTimes<span class=op>;</span></span>\n<span id=cb13-7><a href=#cb13-7 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=at>@Nullable</span> LongSparseLongArray mDurations<span class=op>;</span></span>\n<span id=cb13-8><a href=#cb13-8 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=at>@Nullable</span> LongSparseLongArray mProxyUids<span class=op>;</span></span>\n<span id=cb13-9><a href=#cb13-9 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=at>@Nullable</span> LongSparseArray<span class=op>&lt;</span><span class=bu>String</span><span class=op>&gt;</span> mProxyPackageNames<span class=op>;</span></span>\n<span id=cb13-10><a href=#cb13-10 aria-hidden=true tabindex=-1></a>    <span class=kw>...</span></span>\n<span id=cb13-11><a href=#cb13-11 aria-hidden=true tabindex=-1></a><span class=op>}</span></span></code></pre></div></div><p>Here:<ul class=incremental><li><p><code>mOp</code>: Denotes one of the <a href=#subsec:op-constants><code>OP_*</code> constants</a><li><p><code>mRunning</code>: Whether the operation is in progress\n(i.e. the operation has started but not finished yet). Not all\noperations can be started or finished this way<li><p><code>mMOde</code>: One of the <a href=#subsec:mode-constants><code>MODE_*</code> constants</a><li><p><code>mAccessTimes</code>: Stores all the available access\ntimes<li><p><code>mRejectTimes</code>: Stores all the available reject\ntimes<li><p><code>mDurations</code>: All available access durations, checking\nthis with <code>mRunning</code> will tell you for how long the app is\nperforming a certain app operation<li><p><code>mProxyUids</code>: No documentation found<li><p><code>mProxyPackageNames:</code> No documentation found</ul></section><section id=subsec:usage class=level3 data-number=7.3.5><h3 data-number=7.3.5><span class=header-section-number>7.3.5</span>\n<a href=#toc:subsec:usage>Usage</a><a href=#subsec:usage class=anchor aria-hidden=true></a></h3><p>TODO</section></section><section id=sec:appopsservice class=level2 data-number=7.4><h2 data-number=7.4><span class=header-section-number>7.4</span> <a href=#toc:sec:appopsservice>AppOpsService</a><a href=#sec:appopsservice class=anchor aria-hidden=true></a></h2><p>TODO</section><section id=sec:appops-xml class=level2 data-number=7.5><h2 data-number=7.5><span class=header-section-number>7.5</span> <a href=#toc:sec:appops-xml>appops.xml</a><a href=#sec:appops-xml class=anchor aria-hidden=true></a></h2><p>Latest <code>appops.xml</code> has the following format: (This DTD is\nmade by me and by no means perfect, has compatibility issues.)<pre><code>&lt;!DOCTYPE app-ops [\n\n&lt;!ELEMENT app-ops (uid|pkg)*&gt;\n&lt;!ATTLIST app-ops v CDATA #IMPLIED&gt;\n\n&lt;!ELEMENT uid (op)*&gt;\n&lt;!ATTLIST uid n CDATA #REQUIRED&gt;\n\n&lt;!ELEMENT pkg (uid)*&gt;\n&lt;!ATTLIST pkg n CDATA #REQUIRED&gt;\n\n&lt;!ELEMENT uid (op)*&gt;\n&lt;!ATTLIST uid\nn CDATA #REQUIRED\np CDATA #IMPLIED&gt;\n\n&lt;!ELEMENT op (st)*&gt;\n&lt;!ATTLIST op\nn CDATA #REQUIRED\nm CDATA #REQUIRED&gt;\n\n&lt;!ELEMENT st EMPTY&gt;\n&lt;!ATTLIST st\nn CDATA #REQUIRED\nt CDATA #IMPLIED\nr CDATA #IMPLIED\nd CDATA #IMPLIED\npp CDATA #IMPLIED\npu CDATA #IMPLIED&gt;\n\n]&gt;</code></pre><p>The instruction below follows the exact order given above:<ul class=incremental><li><p><code>app-ops</code>: The root element. It can contain any number\nof <code>pkg</code> or package <code>uid</code><ul class=incremental><li><p><code>v</code>: (optional, integer) The version number (default:\n<code>NO_VERSION</code> or <code>-1</code>)</ul><li><p><code>pkg</code>: Stores package info. It can contain any number\nof <code>uid</code><ul class=incremental><li><p><code>n</code>: (required, string) Name of the package</ul><li><p>Package <code>uid</code>: Stores package or packages info<ul class=incremental><li><p><code>n</code>: (required, integer) The user ID</ul><li><p><code>uid</code>: The package user ID. It can contain any number\nof <code>op</code><ul class=incremental><li><p><code>n</code>: (required, integer) The user ID<li><p><code>p</code>: (optional, boolean) Is the app is a\nprivate/system app</ul><li><p><code>op</code>: The operation, can contain <code>st</code> or\nnothing at all<ul class=incremental><li><p><code>n</code>: (required, integer) The op name in integer,\ni.e. AppOpsManager.OP_*<li><p><code>m</code>: (required, integer) The op mode,\ni.e. AppOpsManager.MODE_*</ul><li><p><code>st</code>: State of operation: whether the operation is\naccessed, rejected or running (not available on old versions)<ul class=incremental><li><p><code>n</code>: (required, long) Key containing flags and\nuid<li><p><code>t</code>: (optional, long) Access time (default:\n<code>0</code>)<li><p><code>r</code>: (optional, long) Reject time (default:\n<code>0</code>)<li><p><code>d</code>: (optional, long) Access duration (default:\n<code>0</code>)<li><p><code>pp</code>: (optional, string) Proxy package name<li><p><code>pu</code>: (optional, integer) Proxy package uid</ul></ul><p>This definition can be found at <a href=https://android.googlesource.com/platform/frameworks/base/+/master/services/core/java/com/android/server/appop/AppOpsService.java>AppOpsService</a>.</section><section id=sec:appops-cli class=level2 data-number=7.6><h2 data-number=7.6><span class=header-section-number>7.6</span> <a href=#toc:sec:appops-cli>Command Line Interface</a><a href=#sec:appops-cli class=anchor aria-hidden=true></a></h2><p><code>appops</code> or <code>cmd appops</code> (on latest versions)\ncan be accessible via ADB or root. This is an easier method to get or\nupdate any operation for a package (provided the package name is known).\nThe help page of this command is self-explanatory:<pre><code>AppOps service (appops) commands:\nhelp\nPrint this help text.\nstart [--user &lt;USER_ID&gt;] &lt;PACKAGE | UID&gt; &lt;OP&gt;\nStarts a given operation for a particular application.\nstop [--user &lt;USER_ID&gt;] &lt;PACKAGE | UID&gt; &lt;OP&gt;\nStops a given operation for a particular application.\nset [--user &lt;USER_ID&gt;] &lt;[--uid] PACKAGE | UID&gt; &lt;OP&gt; &lt;MODE&gt;\nSet the mode for a particular application and operation.\nget [--user &lt;USER_ID&gt;] &lt;PACKAGE | UID&gt; [&lt;OP&gt;]\nReturn the mode for a particular application and optional operation.\nquery-op [--user &lt;USER_ID&gt;] &lt;OP&gt; [&lt;MODE&gt;]\nPrint all packages that currently have the given op in the given mode.\nreset [--user &lt;USER_ID&gt;] [&lt;PACKAGE&gt;]\nReset the given application or all applications to default modes.\nwrite-settings\nImmediately write pending changes to storage.\nread-settings\nRead the last written settings, replacing current state in RAM.\noptions:\n&lt;PACKAGE&gt; an Android package name or its UID if prefixed by --uid\n&lt;OP&gt;      an AppOps operation.\n&lt;MODE&gt;    one of allow, ignore, deny, or default\n&lt;USER_ID&gt; the user id under which the package is installed. If --user is not\nspecified, the current user is assumed.</code></pre></section></section><section id=footnotes class=\"footnotes footnotes-end-of-document\" role=doc-endnotes><hr><ol><li id=fn1><p>For distributing normal releases only<a href=#fnref1 class=footnote-back role=doc-backlink>↩︎</a><li id=fn2><p>GitHub pull requests will be merged manually using the\ncorresponding patches. As a result, GitHub may wrongfully mark them\nclosed instead of merged.<a href=#fnref2 class=footnote-back role=doc-backlink>↩︎</a><li id=fn3><p>You can also address me as “Muntashir Akon”<a href=#fnref3 class=footnote-back role=doc-backlink>↩︎</a></ol></section>"
  },
  {
    "path": "docs/raw/pt-rBR/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"keywords$see_also\">\\\\newcommand{\\\\KeywordSeeAlso}{Ver também:}</string>\n    <string name=\"intro$main$$introduction-chapter-title\">Introdução</string>\n    <string name=\"intro$main$$terminologies-title\">Terminologias</string>\n    <string name=\"intro$main$$supported-versions-title\">Versões suportadas</string>\n    <string name=\"intro$main$$official-sources-title\">Fontes Oficiais</string>\n    <string name=\"intro$main$$bin-sources-title\">Fontes de Distribuição Binária</string>\n    <string name=\"intro$main$$donation-title\">Doação \\\\&amp; Financiamento</string>\n    <string name=\"intro$main$$contact-title\">Contato</string>\n    <string name=\"intro$main$$submit-patches-title\">Submissão de correções</string>\n    <string name=\"intro$main$$source-code-links-title\">Links para o Código Fonte</string>\n    <string name=\"intro$main$$translations-title\">Traduções</string>\n    <string name=\"intro$main$$contributing-title\">Contribuição</string>\n    <string name=\"intro$main$$buiding-title\">Instruções de Contrução</string>\n    <string name=\"titlepage$quotation\">\\\\begin{quotation}\n\\n ``Devagar e sabiamente. Os que correm rápido, tropeçam.\\'\\'\n\\n %\\\\sourceatright\n\\n {--- Friar Laurence, \\\\textit{Romeu e Julieta}}\n\\n \\\\end{quotation}</string>\n    <string name=\"keywords$end_of_keyword_in_alert\">\\\\newcommand{\\\\KeywordEndOfKeyWordInAlert}{.}</string>\n    <string name=\"keywords$chapter\">\\\\newcommand{\\\\KeywordChapter}{Capítulo}</string>\n    <string name=\"intro$main$intro\">App Manager é um gerenciador de pacotes avançado para Android. Oferece inúmeros recursos e, consequentemente, exige um usuário\n\\nmanual para auxiliar seus usuários. Este documento funciona como um manual do usuário para o App Manager no sentido de que visa descrever\n\\ntodos os recursos que o App Manager tem a oferecer. Este documento também pode ser considerado como as diretrizes ``oficiais\\'\\' para\n\\nApp Manager e representa o comportamento esperado do App Manager. As traduções podem interpretar mal este documento (que é\n\\nescrito em inglês). Portanto, todo usuário competente deve ler a versão em inglês do documento para obter o melhor\n\\ndo Gerenciador de Aplicativos. Também pode haver outros recursos não oficiais ou de terceiros, como artigos de blog, vídeos, bate-papo\n\\ngrupos, etc. Embora esses recursos possam ser úteis para muitas pessoas, eles podem não estar atualizados com o atual\n\\nversão do Gerenciador de Aplicativos. Se quaisquer desvios forem detectados no App Manager a partir deste documento, eles devem ser relatados no\n\\n\\\\href{https://github.com/MuntashirAkon/AppManager/issues}{Rastreador de problemas do App Manager}.</string>\n    <string name=\"intro$main$terminologies\">\\\\begin{itemize}\n\\n \\\\item \\\\textbf{AM} --- nome curto para Gerenciador de aplicativos.\n\\n \\\\item \\\\textbf{Block/Unblock} --- Usado para bloquear ou desbloquear componentes. Como os componentes são bloqueados depende\n\\n as preferências do usuário.\n\\n \\\\item \\\\textbf{IFW} --- forma curta de Firewall de Intenção.\n\\n \\\\item \\\\textbf{Ops} --- Nome curto para operações, ops de aplicativos por exemplo, ops em lote, ops de 1 clique\n\\n \\\\item \\\\textbf{SSAID} --- forma curta de \\\\texttt{Configurações.Secure.ANDROID\\\\_ID}. É um identificador de dispositivo atribuído a\n\\n cada aplicativo (Android Oreo e em diante). É gerado a partir da combinação do certificado de assinatura do aplicativo\n\\n e o conjunto SSAID para o pacote \\\\texttt{android}. Como resultado, é garantido ser o mesmo para um aplicativo, a menos que\n\\n o usuário opta por formatar o dispositivo. É amplamente utilizado para rastreamento.\n\\n \\\\item \\\\textbf{Tracker} --- Denota componentes rastreadores em todo o documento e no Gerenciador de Aplicativos, exceto no App Manager, exceto no\n\\n \\\\hyperref[sec:scanner-page]{página do scanner}. Os rastreadores incluem bibliotecas como repórteres de acidentes, análises,\n\\n perfil, identificação, anúncio, localização, etc. Assim, não são iguais em funções. Não há distinção ou preconceito\n\\n entre bibliotecas de código aberto e de código fechado que promovem o rastreamento.\n\\n\\\\end{itemize}</string>\n    <string name=\"intro$main$bin-sources\">O App Manager é distribuído usando as seguintes fontes. Fontes não oficiais podem distribuir versões modificadas do App\n\\nGerente, e ninguém além de você será responsável pelas consequências do uso de tais distribuições.\n\\n\\\\begin{enumerate}\n\\n \\\\item Official F-Droid repository.\\\\footnote{For distributing normal releases only}\\\\\\\\\n\\n \\\\textit{Link:} \\\\url{https://f-droid.org/packages/io.github.muntashirakon.AppManager}\n\\n \\\\item GitHub repository.\\\\\\\\\n\\n \\\\textit{Normal releases:} \\\\url{https://github.com/MuntashirAkon/AppManager/releases}\\\\\\\\\n\\n \\\\textit{Debug releases:} \\\\url{https://github.com/MuntashirAkon/AppManager/actions}\n\\n \\\\item Telegram.\\\\\\\\\n\\n \\\\textit{Normal releases:} \\\\url{https://t.me/AppManagerChannel}\\\\\\\\\n\\n \\\\textit{Debug releases:} \\\\url{https://t.me/AppManagerDebug}\n\\n\\\\end{enumerate}</string>\n    <string name=\"titlepage$user_manual\">{\\\\huge\\\\bfseries Manual do Usuário\\\\par}</string>\n    <string name=\"intro$main$supported-versions\">Atualmente, as versões suportadas são v3.0.0 -- v3.0.3 (estável), v3.1.0 (alpha e de debug). Verções anteriores do App\n\\nManager pode conter vulnerabilidades de segurança e não deve usal-las.</string>\n    <string name=\"intro$main$buiding\">As instruções de compilação estão disponíveis no arquivo BUILDING localizado no diretório raiz do código.</string>\n    <string name=\"intro$main$translations\">O App Manager não aceita traduções diretamente por meio de solicitações pull/merge. As traduções são gerenciadas automaticamente via \n\\nWeblate. Para participar da equipe de tradução, visite \\\\url{https://hosted.weblate.org/engage/app-manager/}.</string>\n    <string name=\"intro$main$contributing\">Há várias maneiras pelas quais um usuário pode contribuir,\n\\ncriando tópicos de ajuda, participar de discussões, melhorando\n\\ndocumentações e traduções, adicionando bibliotecas ou rastreadores não reconhecidos, revisando o código-fonte,bem como\n\\n\n\\nrelatar vulnerabilidades de segurança.</string>\n</resources>"
  },
  {
    "path": "docs/raw/ru/index.html",
    "content": "<!doctype html><html xmlns=http://www.w3.org/1999/xhtml lang=ru xml:lang=ru><meta charset=utf-8><meta name=generator content=\"pandoc\"><meta name=viewport content=\"width=device-width,initial-scale=1,user-scalable=yes\"><meta name=author content=\"Muntashir Al-Islam\"><title>App Manager</title><style>code{white-space:pre-wrap}span.smallcaps{font-variant:small-caps}div.columns{display:flex;gap:min(4vw,1.5em)}div.column{flex:auto;overflow-x:auto}div.hanging-indent{margin-left:1.5em;text-indent:-1.5em}ul.task-list[class]{list-style:none}ul.task-list li input[type=checkbox]{font-size:inherit;width:.8em;margin:0 .8em .2em -1.6em;vertical-align:middle}.display.math{display:block;text-align:center;margin:.5rem auto}html{-webkit-text-size-adjust:100%}pre>code.sourceCode{white-space:pre;position:relative}pre>code.sourceCode>span{display:inline-block;line-height:1.25}pre>code.sourceCode>span:empty{height:1.2em}.sourceCode{overflow:visible}code.sourceCode>span{color:inherit;text-decoration:inherit}div.sourceCode{margin:1em 0}pre.sourceCode{margin:0}@media screen{div.sourceCode{overflow:auto}}@media print{pre>code.sourceCode{white-space:pre-wrap}pre>code.sourceCode>span{text-indent:-5em;padding-left:5em}}pre.numberSource code{counter-reset:source-line 0}pre.numberSource code>span{position:relative;left:-4em;counter-increment:source-line}pre.numberSource code>span>a:first-child::before{content:counter(source-line);position:relative;left:-1em;text-align:right;vertical-align:baseline;border:none;display:inline-block;-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;padding:0 4px;width:4em}pre.numberSource{margin-left:3em;padding-left:4px}div.sourceCode{}@media screen{pre>code.sourceCode>span>a:first-child::before{text-decoration:underline}}code span.al{font-weight:700}code span.an{font-style:italic}code span.cf{font-weight:700}code span.co{font-style:italic}code span.cv{font-style:italic}code span.do{font-style:italic}code span.dt{text-decoration:underline}code span.er{font-weight:700}code span.in{font-style:italic}code span.kw{font-weight:700}code span.pp{font-weight:700}code span.wa{font-style:italic}</style><link rel=stylesheet href=../css/custom.css><header id=title-block-header><h1 class=title>App Manager</h1><p class=author>Muntashir Al-Islam</header><nav id=TOC role=doc-toc><ul class=incremental><li><span><span class=toc-section-number>1</span> <a href=#ch:introduction id=toc:ch:introduction>Введение</a></span><ul class=incremental><li><span><span class=toc-section-number>1.1</span> <a href=#sec:terminologies id=toc:sec:terminologies>Терминология</a></span><li><span><span class=toc-section-number>1.2</span> <a href=#sec:supported-versions id=toc:sec:supported-versions>Поддерживаемые версии</a></span><li><span><span class=toc-section-number>1.3</span> <a href=#sec:official-sources id=toc:sec:official-sources>Официальные\nисточники</a></span><ul class=incremental><li><span><span class=toc-section-number>1.3.1</span> <a href=#subsec:binary-distribution-sources id=toc:subsec:binary-distribution-sources>Источники\nраспостранения</a></span><li><span><span class=toc-section-number>1.3.2</span> <a href=#subsec:links-to-source-code id=toc:subsec:links-to-source-code>Ссылки на исходный\nкод</a></span><li><span><span class=toc-section-number>1.3.3</span> <a href=#subsec:translations id=toc:subsec:translations>Переводы</a></span></ul><li><span><span class=toc-section-number>1.4</span> <a href=#sec:contributing id=toc:sec:contributing>Вклад</a></span><ul class=incremental><li><span><span class=toc-section-number>1.4.1</span> <a href=#subsec:build-instructions id=toc:subsec:build-instructions>Инструкции по сборке</a></span><li><span><span class=toc-section-number>1.4.2</span> <a href=#subsec:submitting-patches id=toc:subsec:submitting-patches>Отправка исправлений</a></span></ul><li><span><span class=toc-section-number>1.5</span> <a href=#sec:donation-&-funding id=toc:sec:donation-&-funding>Пожертвование &\nФинансирование</a></span><li><span><span class=toc-section-number>1.6</span> <a href=#sec:contact id=toc:sec:contact>Связь</a></span></ul><li><span><span class=toc-section-number>2</span> <a href=#ch:pages id=toc:ch:pages>Страницы</a></span><ul class=incremental><li><span><span class=toc-section-number>2.1</span> <a href=#sec:main-page id=toc:sec:main-page>Главная страница</a></span><ul class=incremental><li><span><span class=toc-section-number>2.1.1</span> <a href=#subsec:batch-operations id=toc:subsec:batch-operations>Пакетные операции</a></span><li><span><span class=toc-section-number>2.1.2</span> <a href=#subsec:main-colour-codes id=toc:subsec:main-colour-codes>Цветовые коды</a></span><li><span><span class=toc-section-number>2.1.3</span> <a href=#subsec:main-page-application-types id=toc:subsec:main-page-application-types>Типы\nприложений</a></span><li><span><span class=toc-section-number>2.1.4</span> <a href=#subsec:main-page-version-info id=toc:subsec:main-page-version-info>Информация о\nверсии</a></span><li><span><span class=toc-section-number>2.1.5</span> <a href=#subsec:main-page-options-menu id=toc:subsec:main-page-options-menu>Меню настроек</a></span></ul><li><span><span class=toc-section-number>2.2</span> <a href=#sec:app-details-page id=toc:sec:app-details-page>Страница\nсведений о приложении</a></span><ul class=incremental><li><span><span class=toc-section-number>2.2.1</span> <a href=#subsec:app-details-colour-codes id=toc:subsec:app-details-colour-codes>Цветовые коды</a></span><li><span><span class=toc-section-number>2.2.2</span> <a href=#subsec:app-info-tab id=toc:subsec:app-info-tab>Вкладка\n\"Сведения о приложении\"</a></span><li><span><span class=toc-section-number>2.2.3</span> <a href=#subsec:component-tabs id=toc:subsec:component-tabs>Вкладки\nкомпонентов</a></span><li><span><span class=toc-section-number>2.2.4</span> <a href=#subsec:permission-tabs id=toc:subsec:permission-tabs>Вкладки\nразрешений</a></span><li><span><span class=toc-section-number>2.2.5</span> <a href=#subsec:signatures-tab id=toc:subsec:signatures-tab>Signatures\nTab</a></span><li><span><span class=toc-section-number>2.2.6</span> <a href=#subsec:uses-features-tab id=toc:subsec:uses-features-tab>Uses\nFeatures tab</a></span><li><span><span class=toc-section-number>2.2.7</span> <a href=#subsec:configurations-tab id=toc:subsec:configurations-tab>Configurations tab</a></span><li><span><span class=toc-section-number>2.2.8</span> <a href=#subsec:shared-libs-tab id=toc:subsec:shared-libs-tab>Shared\nLibraries Tab</a></span></ul><li><span><span class=toc-section-number>2.3</span> <a href=#sec:1-click-ops-page id=toc:sec:1-click-ops-page>1-Click Ops\nPage</a></span><ul class=incremental><li><span><span class=toc-section-number>2.3.1</span> <a href=#subsec:block-unblock-trackers id=toc:subsec:block-unblock-trackers>Block/Unblock\nTrackers</a></span><li><span><span class=toc-section-number>2.3.2</span> <a href=#subsec:block-components-dots id=toc:subsec:block-components-dots>Block Components…</a></span><li><span><span class=toc-section-number>2.3.3</span> <a href=#subsec:set-mode-for-app-ops-dots id=toc:subsec:set-mode-for-app-ops-dots>Set Mode for App\nOps…</a></span><li><span><span class=toc-section-number>2.3.4</span> <a href=#subsec:1-click-back-up id=toc:subsec:1-click-back-up>Back\nup</a></span><li><span><span class=toc-section-number>2.3.5</span> <a href=#subsec:1-click-restore id=toc:subsec:1-click-restore>Restore</a></span><li><span><span class=toc-section-number>2.3.6</span> <a href=#subsec:trim-caches-in-all-apps id=toc:subsec:trim-caches-in-all-apps>Trim Caches in All\nApps</a></span></ul><li><span><span class=toc-section-number>2.4</span> <a href=#sec:profiles-page id=toc:sec:profiles-page>Profiles\nPage</a></span><ul class=incremental><li><span><span class=toc-section-number>2.4.1</span> <a href=#subsec:profiles-options-menu id=toc:subsec:profiles-options-menu>Options Menu</a></span></ul><li><span><span class=toc-section-number>2.5</span> <a href=#sec:profile-page id=toc:sec:profile-page>Profile\nPage</a></span><ul class=incremental><li><span><span class=toc-section-number>2.5.1</span> <a href=#subsec:profile-options-menu id=toc:subsec:profile-options-menu>Options Menu</a></span><li><span><span class=toc-section-number>2.5.2</span> <a href=#subsec:profile-apps-tab id=toc:subsec:profile-apps-tab>Apps\nTab</a></span><li><span><span class=toc-section-number>2.5.3</span> <a href=#subsec:profile-configurations-tab id=toc:subsec:profile-configurations-tab>Configurations\nTab</a></span></ul><li><span><span class=toc-section-number>2.6</span> <a href=#sec:settings-page id=toc:sec:settings-page>Settings\nPage</a></span><ul class=incremental><li><span><span class=toc-section-number>2.6.1</span> <a href=#subsec:language id=toc:subsec:language>Language</a></span><li><span><span class=toc-section-number>2.6.2</span> <a href=#subsec:appearance id=toc:subsec:appearance>Appearance</a></span><li><span><span class=toc-section-number>2.6.3</span> <a href=#subsec:privacy id=toc:subsec:privacy>Privacy</a></span><li><span><span class=toc-section-number>2.6.4</span> <a href=#subsec:mode-of-operation id=toc:subsec:mode-of-operation>Mode\nof Operation</a></span><li><span><span class=toc-section-number>2.6.5</span> <a href=#subsec:apk-signing id=toc:subsec:apk-signing>APK\nSigning</a></span><li><span><span class=toc-section-number>2.6.6</span> <a href=#subsec:installer id=toc:subsec:installer>Installer</a></span><li><span><span class=toc-section-number>2.6.7</span> <a href=#subsec:backup/restore id=toc:subsec:backup/restore>Back\nup/Restore</a></span><li><span><span class=toc-section-number>2.6.8</span> <a href=#subsec:rules id=toc:subsec:rules>Rules</a></span><li><span><span class=toc-section-number>2.6.9</span> <a href=#subsec:advanced id=toc:subsec:advanced>Advanced</a></span><li><span><span class=toc-section-number>2.6.10</span> <a href=#subsec:device-info id=toc:subsec:device-info>About the\ndevice</a></span></ul><li><span><span class=toc-section-number>2.7</span> <a href=#sec:scanner-page id=toc:sec:scanner-page>Scanner\nPage</a></span><li><span><span class=toc-section-number>2.8</span> <a href=#sec:interceptor-page id=toc:sec:interceptor-page>Interceptor\nPage</a></span><ul class=incremental><li><span><span class=toc-section-number>2.8.1</span> <a href=#subsec:intent-filters id=toc:subsec:intent-filters>Intent\nFilters</a></span><li><span><span class=toc-section-number>2.8.2</span> <a href=#subsec:matching-activities id=toc:subsec:matching-activities>Matching Activities</a></span><li><span><span class=toc-section-number>2.8.3</span> <a href=#subsec:interceptor-reset-to-default id=toc:subsec:interceptor-reset-to-default>Reset to\nDefault</a></span><li><span><span class=toc-section-number>2.8.4</span> <a href=#subsec:interceptor-send-edited-intent id=toc:subsec:interceptor-send-edited-intent>Send Edited\nIntent</a></span></ul><li><span><span class=toc-section-number>2.9</span> <a href=#sec:shared-preferences-editor-page id=toc:sec:shared-preferences-editor-page>Shared Preferences Editor\nPage</a></span></ul><li><span><span class=toc-section-number>3</span> <a href=#ch:guides id=toc:ch:guides>Guides</a></span><ul class=incremental><li><span><span class=toc-section-number>3.1</span> <a href=#sec:adb-over-tcp id=toc:sec:adb-over-tcp>ADB over\nTCP</a></span><ul class=incremental><li><span><span class=toc-section-number>3.1.1</span> <a href=#subsec:enable-developer-options id=toc:subsec:enable-developer-options>Enable developer\noptions</a></span><li><span><span class=toc-section-number>3.1.2</span> <a href=#subsec:enable-usb-debugging id=toc:subsec:enable-usb-debugging>Enable USB\ndebugging</a></span><li><span><span class=toc-section-number>3.1.3</span> <a href=#subsec:setup-adb-on-pc-or-mac id=toc:subsec:setup-adb-on-pc-or-mac>Setup ADB on PC or\nMac</a></span><li><span><span class=toc-section-number>3.1.4</span> <a href=#subsec:configure-adb-over-tcp id=toc:subsec:configure-adb-over-tcp>Configure ADB over\nTCP</a></span></ul><li><span><span class=toc-section-number>3.2</span> <a href=#sec:wireless-debugging id=toc:sec:wireless-debugging>Wireless\nDebugging</a></span><ul class=incremental><li><span><span class=toc-section-number>3.2.1</span> <a href=#subsec:enable-developer-options-and-usb-debugging id=toc:subsec:enable-developer-options-and-usb-debugging>Enable\ndeveloper options and USB Debugging</a></span><li><span><span class=toc-section-number>3.2.2</span> <a href=#subsec:enable-wireless-debugging id=toc:subsec:enable-wireless-debugging>Enable Wireless\nDebugging</a></span><li><span><span class=toc-section-number>3.2.3</span> <a href=#subsec:pair-adb-with-app-manager id=toc:subsec:pair-adb-with-app-manager>Pair ADB with App\nManager</a></span><li><span><span class=toc-section-number>3.2.4</span> <a href=#subsec:connect-app-manager-to-adb id=toc:subsec:connect-app-manager-to-adb>Connect App Manager to\nADB</a></span></ul><li><span><span class=toc-section-number>3.3</span> <a href=#sec:backup-restore id=toc:sec:backup-restore>Back\nup/Restore</a></span><ul class=incremental><li><span><span class=toc-section-number>3.3.1</span> <a href=#subsec:backup-location id=toc:subsec:backup-location>Location</a></span><li><span><span class=toc-section-number>3.3.2</span> <a href=#subsec:backup-restore-backup-options id=toc:subsec:backup-restore-backup-options>Backup\nOptions</a></span><li><span><span class=toc-section-number>3.3.3</span> <a href=#subsec:backup-restore-backup id=toc:subsec:backup-restore-backup>Backup</a></span><li><span><span class=toc-section-number>3.3.4</span> <a href=#subsec:backup-restore-restore id=toc:subsec:backup-restore-restore>Restore</a></span><li><span><span class=toc-section-number>3.3.5</span> <a href=#subsec:backup-restore-delete-backup id=toc:subsec:backup-restore-delete-backup>Delete\nBackup</a></span></ul><li><span><span class=toc-section-number>3.4</span> <a href=#sec:automating-tasks id=toc:sec:automating-tasks>Automating\nTasks</a></span><ul class=incremental><li><span><span class=toc-section-number>3.4.1</span> <a href=#subsec:generating-authorization-key id=toc:subsec:generating-authorization-key>Generating authorization\nkey</a></span><li><span><span class=toc-section-number>3.4.2</span> <a href=#subsec:at:general-configuration id=toc:subsec:at:general-configuration>Configuring\ntasks</a></span><li><span><span class=toc-section-number>3.4.3</span> <a href=#subsec:at:features id=toc:subsec:at:features>Features</a></span><li><span><span class=toc-section-number>3.4.4</span> <a href=#subsec:triggering-a-profile id=toc:subsec:triggering-a-profile>Triggering a\nprofile</a></span></ul><li><span><span class=toc-section-number>3.5</span> <a href=#sec:net-policy id=toc:sec:net-policy>Net\nPolicy</a></span></ul><li><span><span class=toc-section-number>4</span> <a href=#ch:faq id=toc:ch:faq>Frequently Asked Questions</a></span><ul class=incremental><li><span><span class=toc-section-number>4.1</span> <a href=#sec:faq:app-components id=toc:sec:faq:app-components>App\nComponents</a></span><ul class=incremental><li><span><span class=toc-section-number>4.1.1</span> <a href=#subsec:faq:what-are-app-components id=toc:subsec:faq:what-are-app-components>What are the application\ncomponents?</a></span><li><span><span class=toc-section-number>4.1.2</span> <a href=#subsec:faq:how-components-blocked id=toc:subsec:faq:how-components-blocked>How are the tracker and other\ncomponents blocked in App Manager? What are its\nlimitations?</a></span><li><span><span class=toc-section-number>4.1.3</span> <a href=#subsec:faq:components-blocked-by-others id=toc:subsec:faq:components-blocked-by-others>Does app components\nblocked by other tools retained in App Manager?</a></span><li><span><span class=toc-section-number>4.1.4</span> <a href=#subsec:faq:components-reblocked-in-am id=toc:subsec:faq:components-reblocked-in-am>What happens to the\ncomponents blocked by App Manager which were previously blocked by other\ntools?</a></span><li><span><span class=toc-section-number>4.1.5</span> <a href=#subsec:faq:what-is-instant-component-blocking id=toc:subsec:faq:what-is-instant-component-blocking>What is instant\ncomponent blocking?</a></span><li><span><span class=toc-section-number>4.1.6</span> <a href=#subsec:tracker-classes-versus-tracker-components id=toc:subsec:tracker-classes-versus-tracker-components>Tracker\nclasses versus tracker components</a></span></ul><li><span><span class=toc-section-number>4.2</span> <a href=#sec:faq:adb-over-tcp id=toc:sec:faq:adb-over-tcp>ADB over\nTCP</a></span><ul class=incremental><li><span><span class=toc-section-number>4.2.1</span> <a href=#subsec:faq:enable-adb-on-every-restart id=toc:subsec:faq:enable-adb-on-every-restart>Do I have to enable ADB\nover TCP everytime I restart?</a></span><li><span><span class=toc-section-number>4.2.2</span> <a href=#subsec:faq:usb-debugging id=toc:subsec:faq:usb-debugging>Cannot enable USB debugging. What to\ndo?</a></span><li><span><span class=toc-section-number>4.2.3</span> <a href=#subsec:faq:block-components-using-adb id=toc:subsec:faq:block-components-using-adb>Can I block tracker or\nany other application components using ADB over TCP?</a></span><li><span><span class=toc-section-number>4.2.4</span> <a href=#subsec:faq:adb-features id=toc:subsec:faq:adb-features>Which\nfeatures can be used in ADB mode?</a></span></ul><li><span><span class=toc-section-number>4.3</span> <a href=#sec:faq:miscellanea id=toc:sec:faq:miscellanea>Miscellanea</a></span><ul class=incremental><li><span><span class=toc-section-number>4.3.1</span> <a href=#subsec:faq:no-root-no-harms id=toc:subsec:faq:no-root-no-harms>I don’t use root/ADB. Am I\ncompletely safe from any harms?</a></span><li><span><span class=toc-section-number>4.3.2</span> <a href=#subsec:faq:how-trackers-libs-updated id=toc:subsec:faq:how-trackers-libs-updated>How are the trackers and\nlibraries are updated?</a></span><li><span><span class=toc-section-number>4.3.3</span> <a href=#subsec:faq:apks-deleted-after-installed id=toc:subsec:faq:apks-deleted-after-installed>Are APKs deleted after\ninstalled?</a></span><li><span><span class=toc-section-number>4.3.4</span> <a href=#subsec:faq:shizuku-support id=toc:subsec:faq:shizuku-support>Any plans for\nShizuku?</a></span><li><span><span class=toc-section-number>4.3.5</span> <a href=#subsec:faq:what-are-bloatware id=toc:subsec:faq:what-are-bloatware>What are bloatware and how to\nremove them?</a></span></ul></ul><li><span><span class=toc-section-number>5</span> <a href=#ch:specifications id=toc:ch:specifications>Specifications</a></span><ul class=incremental><li><span><span class=toc-section-number>5.1</span> <a href=#sec:rules-specification id=toc:sec:rules-specification>Rules\nSpecification</a></span><ul class=incremental><li><span><span class=toc-section-number>5.1.1</span> <a href=#background id=toc:background>Background</a></span><li><span><span class=toc-section-number>5.1.2</span> <a href=#rules-file-format id=toc:rules-file-format>Rules File\nFormat</a></span></ul></ul><li><span><span class=toc-section-number>6</span> <a href=#ch:changelogs id=toc:ch:changelogs>Changelogs</a></span><ul class=incremental><li><span><span class=toc-section-number>6.1</span> <a href=#sec:v4.0.5-(445) id=toc:sec:v4.0.5-(445)>v4.0.5\n(445)</a></span><li><span><span class=toc-section-number>6.2</span> <a href=#sec:v4.0.4-(444) id=toc:sec:v4.0.4-(444)>v4.0.4\n(444)</a></span><li><span><span class=toc-section-number>6.3</span> <a href=#sec:v4.0.3-(443) id=toc:sec:v4.0.3-(443)>v4.0.3\n(443)</a></span><li><span><span class=toc-section-number>6.4</span> <a href=#sec:v4.0.2-(442) id=toc:sec:v4.0.2-(442)>v4.0.2\n(442)</a></span><li><span><span class=toc-section-number>6.5</span> <a href=#sec:v4.0.1-(441) id=toc:sec:v4.0.1-(441)>v4.0.1\n(441)</a></span><ul class=incremental><li><span><span class=toc-section-number>6.5.1</span> <a href=#overlay-management id=toc:overlay-management>Overlay\nmanagement</a></span><li><span><span class=toc-section-number>6.5.2</span> <a href=#unfreeze-option-in-activity-shortcuts id=toc:unfreeze-option-in-activity-shortcuts>Unfreeze option in\nactivity shortcuts</a></span><li><span><span class=toc-section-number>6.5.3</span> <a href=#market-like-url-support id=toc:market-like-url-support><code>market</code>-like URL\nsupport</a></span><li><span><span class=toc-section-number>6.5.4</span> <a href=#updated-color-codes id=toc:updated-color-codes>Updated color\ncodes</a></span><li><span><span class=toc-section-number>6.5.5</span> <a href=#others id=toc:others>Others</a></span></ul><li><span><span class=toc-section-number>6.6</span> <a href=#sec:v4.0.0-(440) id=toc:sec:v4.0.0-(440)>v4.0.0\n(440)</a></span><ul class=incremental><li><span><span class=toc-section-number>6.6.1</span> <a href=#new-logo id=toc:new-logo>New logo!</a></span><li><span><span class=toc-section-number>6.6.2</span> <a href=#android-14-and-15-support id=toc:android-14-and-15-support>Android 14 and 15\nsupport</a></span><li><span><span class=toc-section-number>6.6.3</span> <a href=#revamped-debloater id=toc:revamped-debloater>Revamped\ndebloater</a></span><li><span><span class=toc-section-number>6.6.4</span> <a href=#introducing-file-manager id=toc:introducing-file-manager>Introducing file\nmanager</a></span><li><span><span class=toc-section-number>6.6.5</span> <a href=#integrated-code-editor id=toc:integrated-code-editor>Integrated code editor</a></span><li><span><span class=toc-section-number>6.6.6</span> <a href=#history-of-operations id=toc:history-of-operations>History of\noperations</a></span><li><span><span class=toc-section-number>6.6.7</span> <a href=#per-app-freezing-and-more id=toc:per-app-freezing-and-more>Per-app freezing, and\nmore</a></span><li><span><span class=toc-section-number>6.6.8</span> <a href=#log-viewer-enhancements id=toc:log-viewer-enhancements>Log\nviewer enhancements</a></span><li><span><span class=toc-section-number>6.6.9</span> <a href=#launching-non-exported-activities id=toc:launching-non-exported-activities>Launching non-exported\nactivities</a></span><li><span><span class=toc-section-number>6.6.10</span> <a href=#new-tags-in-app-info-tab id=toc:new-tags-in-app-info-tab>New\ntags in App Info tab</a></span><li><span><span class=toc-section-number>6.6.11</span> <a href=#per-session-installer-options id=toc:per-session-installer-options>Per-session installer\noptions</a></span><li><span><span class=toc-section-number>6.6.12</span> <a href=#advanced-mode-of-operations-adb-enhancements id=toc:advanced-mode-of-operations-adb-enhancements>Advanced mode of\noperations, ADB enhancements, …</a></span><li><span><span class=toc-section-number>6.6.13</span> <a href=#data-usage-widget-and-more id=toc:data-usage-widget-and-more>Data usage widget, and\nmore</a></span><li><span><span class=toc-section-number>6.6.14</span> <a href=#others-1 id=toc:others-1>Others</a></span></ul><li><span><span class=toc-section-number>6.7</span> <a href=#sec:v3.1.0-(423) id=toc:sec:v3.1.0-(423)>v3.1.0\n(423)</a></span><ul class=incremental><li><span><span class=toc-section-number>6.7.1</span> <a href=#android-13-support id=toc:android-13-support>Android 13\nsupport</a></span><li><span><span class=toc-section-number>6.7.2</span> <a href=#introducing-freezeunfreeze id=toc:introducing-freezeunfreeze>Introducing\nfreeze/unfreeze</a></span><li><span><span class=toc-section-number>6.7.3</span> <a href=#export-app-list id=toc:export-app-list>Export app\nlist</a></span><li><span><span class=toc-section-number>6.7.4</span> <a href=#elliptic-curve-crypography-ecc id=toc:elliptic-curve-crypography-ecc>Elliptic Curve Crypography\n(ECC)</a></span><li><span><span class=toc-section-number>6.7.5</span> <a href=#new-languages id=toc:new-languages>New\nlanguages</a></span><li><span><span class=toc-section-number>6.7.6</span> <a href=#more-list-options id=toc:more-list-options>More list\noptions</a></span><li><span><span class=toc-section-number>6.7.7</span> <a href=#improved-handling-of-mode-of-operation id=toc:improved-handling-of-mode-of-operation>Improved handling of\nmode of operation</a></span><li><span><span class=toc-section-number>6.7.8</span> <a href=#handling-multiple-users id=toc:handling-multiple-users>Handling multiple users</a></span><li><span><span class=toc-section-number>6.7.9</span> <a href=#explorer-enhancements id=toc:explorer-enhancements>Explorer\nenhancements</a></span><li><span><span class=toc-section-number>6.7.10</span> <a href=#new-tag-wx id=toc:new-tag-wx>New tag: WX</a></span><li><span><span class=toc-section-number>6.7.11</span> <a href=#app-ops-management id=toc:app-ops-management>App ops\nmanagement</a></span><li><span><span class=toc-section-number>6.7.12</span> <a href=#batch-uninstallation id=toc:batch-uninstallation>Batch\nuninstallation</a></span><li><span><span class=toc-section-number>6.7.13</span> <a href=#running-apps id=toc:running-apps>Running apps</a></span><li><span><span class=toc-section-number>6.7.14</span> <a href=#interceptor id=toc:interceptor>Interceptor</a></span><li><span><span class=toc-section-number>6.7.15</span> <a href=#device-specific-changes id=toc:device-specific-changes>Device-specific changes</a></span><li><span><span class=toc-section-number>6.7.16</span> <a href=#others-2 id=toc:others-2>Others</a></span></ul><li><span><span class=toc-section-number>6.8</span> <a href=#sec:v3.0.0-(410) id=toc:sec:v3.0.0-(410)>v3.0.0\n(410)</a></span><ul class=incremental><li><span><span class=toc-section-number>6.8.1</span> <a href=#material-3-and-more id=toc:material-3-and-more>Material 3 and\nMore</a></span><li><span><span class=toc-section-number>6.8.2</span> <a href=#wireless-debugging id=toc:wireless-debugging>Wireless\nDebugging</a></span><li><span><span class=toc-section-number>6.8.3</span> <a href=#languages id=toc:languages>Languages</a></span><li><span><span class=toc-section-number>6.8.4</span> <a href=#introducing-app-explorer id=toc:introducing-app-explorer>Introducing App\nExplorer</a></span><li><span><span class=toc-section-number>6.8.5</span> <a href=#import-backups-from-other-applications id=toc:import-backups-from-other-applications>Import Backups from\nOther Applications</a></span><li><span><span class=toc-section-number>6.8.6</span> <a href=#virustotal id=toc:virustotal>VirusTotal</a></span><li><span><span class=toc-section-number>6.8.7</span> <a href=#trigger-profiles-from-the-automation-software id=toc:trigger-profiles-from-the-automation-software>Trigger Profiles\nfrom the Automation Software</a></span><li><span><span class=toc-section-number>6.8.8</span> <a href=#improved-application-installer id=toc:improved-application-installer>Improved Application\nInstaller</a></span><li><span><span class=toc-section-number>6.8.9</span> <a href=#component-blocking id=toc:component-blocking>Component\nBlocking</a></span><li><span><span class=toc-section-number>6.8.10</span> <a href=#advanced-searching id=toc:advanced-searching>Advanced\nSearching</a></span><li><span><span class=toc-section-number>6.8.11</span> <a href=#shared-libraries id=toc:shared-libraries>Shared\nLibraries</a></span><li><span><span class=toc-section-number>6.8.12</span> <a href=#make-the-best-use-of-interceptor id=toc:make-the-best-use-of-interceptor>Make the Best Use of\nInterceptor</a></span><li><span><span class=toc-section-number>6.8.13</span> <a href=#widget-screen-time id=toc:widget-screen-time>Widget: Screen\nTime</a></span><li><span><span class=toc-section-number>6.8.14</span> <a href=#widget-clear-cache id=toc:widget-clear-cache>Widget: Clear\nCache</a></span></ul><li><span><span class=toc-section-number>6.9</span> <a href=#sec:v2.6.0-(385) id=toc:sec:v2.6.0-(385)>v2.6.0\n(385)</a></span><ul class=incremental><li><span><span class=toc-section-number>6.9.1</span> <a href=#introducing-backups id=toc:introducing-backups>Introducing\nBackups</a></span><li><span><span class=toc-section-number>6.9.2</span> <a href=#introducing-log-viewer id=toc:introducing-log-viewer>Introducing Log Viewer</a></span><li><span><span class=toc-section-number>6.9.3</span> <a href=#lock-app-manager id=toc:lock-app-manager>Lock App\nManager</a></span><li><span><span class=toc-section-number>6.9.4</span> <a href=#extended-modes-for-app-ops id=toc:extended-modes-for-app-ops>Extended Modes for App\nOps</a></span><li><span><span class=toc-section-number>6.9.5</span> <a href=#new-batch-ops-add-to-profile id=toc:new-batch-ops-add-to-profile>New Batch Ops: Add to\nProfile</a></span><li><span><span class=toc-section-number>6.9.6</span> <a href=#app-info-improved id=toc:app-info-improved>App Info:\nImproved</a></span><li><span><span class=toc-section-number>6.9.7</span> <a href=#advanced-sort-and-filtering-options-in-the-main-page id=toc:advanced-sort-and-filtering-options-in-the-main-page>Advanced\nSort and Filtering Options in the Main Page</a></span><li><span><span class=toc-section-number>6.9.8</span> <a href=#about-this-device id=toc:about-this-device>About This\nDevice</a></span><li><span><span class=toc-section-number>6.9.9</span> <a href=#enabledisable-features id=toc:enabledisable-features>Enable/disable Features</a></span><li><span><span class=toc-section-number>6.9.10</span> <a href=#new-languages-1 id=toc:new-languages-1>New\nLanguages</a></span><li><span><span class=toc-section-number>6.9.11</span> <a href=#signing-the-apk-files id=toc:signing-the-apk-files>Signing the\nAPK Files</a></span><li><span><span class=toc-section-number>6.9.12</span> <a href=#new-extension-unapkm id=toc:new-extension-unapkm>New\nExtension: UnAPKM</a></span></ul><li><span><span class=toc-section-number>6.10</span> <a href=#sec:v2.5.20-(375) id=toc:sec:v2.5.20-(375)>v2.5.20\n(375)</a></span><ul class=incremental><li><span><span class=toc-section-number>6.10.1</span> <a href=#subsec:introducing-profiles id=toc:subsec:introducing-profiles>Introducing\nProfiles</a></span><li><span><span class=toc-section-number>6.10.2</span> <a href=#subsec:the-interceptor id=toc:subsec:the-interceptor>The\nInterceptor</a></span><li><span><span class=toc-section-number>6.10.3</span> <a href=#subsec:unapkm:-dedrm-the-apkm-files id=toc:subsec:unapkm:-dedrm-the-apkm-files>UnAPKM: DeDRM the APKM\nfiles</a></span><li><span><span class=toc-section-number>6.10.4</span> <a href=#subsec:multiple-user id=toc:subsec:multiple-user>Multiple\nuser</a></span><li><span><span class=toc-section-number>6.10.5</span> <a href=#vive-la-france id=toc:vive-la-france>Vive la\nFrance!</a></span><li><span><span class=toc-section-number>6.10.6</span> <a href=#report-crashes id=toc:report-crashes>Report\ncrashes</a></span><li><span><span class=toc-section-number>6.10.7</span> <a href=#android-11 id=toc:android-11>Android 11</a></span><li><span><span class=toc-section-number>6.10.8</span> <a href=#app-installer-improvements id=toc:app-installer-improvements>App Installer\nImprovements</a></span></ul><li><span><span class=toc-section-number>6.11</span> <a href=#v2.5.17-368 id=toc:v2.5.17-368>v2.5.17 (368)</a></span><ul class=incremental><li><span><span class=toc-section-number>6.11.1</span> <a href=#app-installer id=toc:app-installer>App\nInstaller</a></span><li><span><span class=toc-section-number>6.11.2</span> <a href=#scanner-replacement-for-exodus-page id=toc:scanner-replacement-for-exodus-page>Scanner: Replacement for\nExodus Page</a></span><li><span><span class=toc-section-number>6.11.3</span> <a href=#introducing-system-config id=toc:introducing-system-config>Introducing System\nConfig</a></span><li><span><span class=toc-section-number>6.11.4</span> <a href=#more-languages id=toc:more-languages>More\nLanguages</a></span><li><span><span class=toc-section-number>6.11.5</span> <a href=#app-info-tab id=toc:app-info-tab>App Info Tab</a></span><li><span><span class=toc-section-number>6.11.6</span> <a href=#navigation-improvements id=toc:navigation-improvements>Navigation Improvements</a></span><li><span><span class=toc-section-number>6.11.7</span> <a href=#running-apps-page id=toc:running-apps-page>Running Apps\nPage</a></span><li><span><span class=toc-section-number>6.11.8</span> <a href=#built-in-toybox id=toc:built-in-toybox>Built-in\nToybox</a></span><li><span><span class=toc-section-number>6.11.9</span> <a href=#component-blocker-improvements id=toc:component-blocker-improvements>Component Blocker\nImprovements</a></span><li><span><span class=toc-section-number>6.11.10</span> <a href=#improvements-in-the-app-details-page id=toc:improvements-in-the-app-details-page>Improvements in the App\nDetails Page</a></span><li><span><span class=toc-section-number>6.11.11</span> <a href=#app-manifest id=toc:app-manifest>App Manifest</a></span></ul><li><span><span class=toc-section-number>6.12</span> <a href=#v2.5.13-348 id=toc:v2.5.13-348>v2.5.13 (348)</a></span><ul class=incremental><li><span><span class=toc-section-number>6.12.1</span> <a href=#bundled-app-split-apk id=toc:bundled-app-split-apk>Bundled App\n(Split APK)</a></span><li><span><span class=toc-section-number>6.12.2</span> <a href=#direct-install-support id=toc:direct-install-support>Direct\nInstall Support</a></span><li><span><span class=toc-section-number>6.12.3</span> <a href=#remove-all-blocking-rules id=toc:remove-all-blocking-rules>Remove All Blocking\nRules</a></span><li><span><span class=toc-section-number>6.12.4</span> <a href=#app-ops-1 id=toc:app-ops-1>App Ops</a></span><li><span><span class=toc-section-number>6.12.5</span> <a href=#enhanced-adb-support id=toc:enhanced-adb-support>Enhanced ADB\nSupport</a></span><li><span><span class=toc-section-number>6.12.6</span> <a href=#filtering-in-main-page id=toc:filtering-in-main-page>Filtering\nin Main Page</a></span><li><span><span class=toc-section-number>6.12.7</span> <a href=#apk-backupsharing id=toc:apk-backupsharing>Apk\nBackup/Sharing</a></span><li><span><span class=toc-section-number>6.12.8</span> <a href=#batch-ops id=toc:batch-ops>Batch Ops</a></span><li><span><span class=toc-section-number>6.12.9</span> <a href=#translations id=toc:translations>Translations</a></span><li><span><span class=toc-section-number>6.12.10</span> <a href=#app-data-backup id=toc:app-data-backup>App Data\nBackup</a></span></ul></ul><li><span><span class=toc-section-number>7</span> <a href=#ch:app-ops id=toc:ch:app-ops>App Ops</a></span><ul class=incremental><li><span><span class=toc-section-number>7.1</span> <a href=#sec:app-ops-background id=toc:sec:app-ops-background>Background</a></span><li><span><span class=toc-section-number>7.2</span> <a href=#sec:introduction-to-app-ops id=toc:sec:introduction-to-app-ops>Introduction to App\nOps</a></span><li><span><span class=toc-section-number>7.3</span> <a href=#sec:appopsmanager id=toc:sec:appopsmanager>AppOpsManager</a></span><ul class=incremental><li><span><span class=toc-section-number>7.3.1</span> <a href=#subsec:op-constants id=toc:subsec:op-constants><code>OP_*</code> Constants</a></span><li><span><span class=toc-section-number>7.3.2</span> <a href=#subsec:mode-constants id=toc:subsec:mode-constants><code>MODE_*</code>\nConstants</a></span><li><span><span class=toc-section-number>7.3.3</span> <a href=#subsec:package-ops id=toc:subsec:package-ops>PackageOps</a></span><li><span><span class=toc-section-number>7.3.4</span> <a href=#subsec:opentry id=toc:subsec:opentry>OpEntry</a></span><li><span><span class=toc-section-number>7.3.5</span> <a href=#subsec:usage id=toc:subsec:usage>Usage</a></span></ul><li><span><span class=toc-section-number>7.4</span> <a href=#sec:appopsservice id=toc:sec:appopsservice>AppOpsService</a></span><li><span><span class=toc-section-number>7.5</span> <a href=#sec:appops-xml id=toc:sec:appops-xml>appops.xml</a></span><li><span><span class=toc-section-number>7.6</span> <a href=#sec:appops-cli id=toc:sec:appops-cli>Command Line\nInterface</a></span></ul></ul></nav><div class=titlingpage><div class=center><p><img src=../images/icon.png style=width:1in alt=image><p><strong><span class=smallcaps>App Manager</span></strong><p><strong>Руководство пользователя</strong><p><em>v4.0.5</em><p>27 июля 2025<p>Copyright © 2020–2025 Muntashir Al-Islam<blockquote><p>“Мудро и медленно; они спотыкаются, что бегают быстро.” <span>— Брат\nЛоуренс, <em>Ромео и Джульетта</em></span></blockquote></div></div><section id=ch:introduction class=level1 data-number=1><h1 data-number=1><span class=header-section-number>1</span> <a href=#toc:ch:introduction>Введение</a><a href=#ch:introduction class=anchor aria-hidden=true></a></h1><p>App Manager это продвинутый менеджер приложений для Android. Оно\nпредоставляет несчётное количество возможностей, следовательно, требует\nруководство потльзователя чтобы помочь пользователям. Этот документ\nдействует как ркуоводство пользователя для App Manager в том смысле, что\nоно направлено на описание каждой возможности которую App Manager\nпредоставляет. Этот документ так же действует как “официальные”\nметодические рекомендации для App Manager, и представляет ожидаемое\nповедение App Manager. Переводы могут неверно истолковывать этот\nдокумент (который написан на английском языке). Поэтому каждый\nпонимающий андгийский язык пользователь должен прочитать версию на\nандгийском языке для лучшего понимания App Manager. Здесь так же могут\nбыть другие неофициальные или сторонние ресурсы тикое как сообщения\nблога, видео, чаты и т.п. Хотя эти ресурсы могут быть полезны для многих\nлюдей, они могут быть устаревшими для текущей версии App Manager. Если\nзамечены какие-либо отличия между App Manager и этом документом, о них\nследует сообщать в <a href=https://github.com/MuntashirAkon/AppManager/issues>App Manager\nissue tracker</a>.<section id=sec:terminologies class=level2 data-number=1.1><h2 data-number=1.1><span class=header-section-number>1.1</span> <a href=#toc:sec:terminologies>Терминология</a><a href=#sec:terminologies class=anchor aria-hidden=true></a></h2><ul class=incremental><li><p><strong>AM</strong> — Краткое название App Manager.<li><p><strong>Block/Unblock</strong> — Используется для\nблокировки/разблокировки компонентов. Способ блокировки компонентов\nзависит от пользовательских настроек.<li><p><strong>IFW</strong> — Краткая форма Intent Firewall.<li><p><strong>Ops</strong> — Краткое название для операций, таких как\nоперации приложения, пакетные операции, операции в 1 клик<li><p><strong>SSAID</strong> — Краткая форма\n<code>Settings.Secure.ANDROID_ID</code>. Это идентификатор устройства,\nпривязанный к каждому приложению (Android Oreo и выше). Он сгенерирован\nиз комбинации сертификата подписи приложения и SSAID установленного для\nпакета <code>android</code>. Как результат, он гарантированно будет\nодинаковым пока пользователь не решит отформатировать устройство. Он\nшироко используется для слежки.<li><p><strong>Трекер</strong> — Обозначает компоненты трекера во всем\nдокументе и в App Manager за исключением <a href=#sec:scanner-page>scanner page</a>. Трекеры включают в себя\nбиблиотеки для отправки краш-репортов, аналитики, профилирования,\nидентификации, рекламы, местоположения и т.п.. Таким образом, они не\nодинаковые по функциям. Здесь нет различия между библиотек с открытым и\nзакрытым исходным кодом, которые продвикают трекинг.</ul></section><section id=sec:supported-versions class=level2 data-number=1.2><h2 data-number=1.2><span class=header-section-number>1.2</span> <a href=#toc:sec:supported-versions>Поддерживаемые версии</a><a href=#sec:supported-versions class=anchor aria-hidden=true></a></h2><p>Сейчас поддерживаемые версии это v3.0.0 – v3.0.3 (стабильные), v3.1.0\n(альфа релизы). Предыдущие версии App Manager могут содержать уязвимости\nбезопасности и не должны быть использованы.</section><section id=sec:official-sources class=level2 data-number=1.3><h2 data-number=1.3><span class=header-section-number>1.3</span> <a href=#toc:sec:official-sources>Официальные источники</a><a href=#sec:official-sources class=anchor aria-hidden=true></a></h2><section id=subsec:binary-distribution-sources class=level3 data-number=1.3.1><h3 data-number=1.3.1><span class=header-section-number>1.3.1</span>\n<a href=#toc:subsec:binary-distribution-sources>Источники\nраспостранения</a><a href=#subsec:binary-distribution-sources class=anchor aria-hidden=true></a></h3><p>App Manager распостранятся используя следующий источники.\nНеофициальные источники могут распостранять модифицированную версию App\nManager, и никто, кроме вас, не несет ответственности за последствия\nиспользования таких дистрибутивов.<ol class=incremental><li><p>Офисиальный репозиторий F-Droid.<a href=#fn1 class=footnote-ref id=fnref1 role=doc-noteref><sup>1</sup></a><br><em>Ссылка:</em> <a href=https://f-droid.org/packages/io.github.muntashirakon.AppManager class=uri>https://f-droid.org/packages/io.github.muntashirakon.AppManager</a><li><p>GitHub репозиторий.<br><em>Стабильные релизы:</em> <a href=https://github.com/MuntashirAkon/AppManager/releases class=uri>https://github.com/MuntashirAkon/AppManager/releases</a><br><em>Бета релизы:</em> <a href=https://github.com/MuntashirAkon/AppManager/actions class=uri>https://github.com/MuntashirAkon/AppManager/actions</a><li><p>Телеграм.<br><em>Стабильные релизы:</em> <a href=https://t.me/AppManagerChannel class=uri>https://t.me/AppManagerChannel</a><br><em>Бета релизы:</em> <a href=https://t.me/AppManagerDebug class=uri>https://t.me/AppManagerDebug</a></ol></section><section id=subsec:links-to-source-code class=level3 data-number=1.3.2><h3 data-number=1.3.2><span class=header-section-number>1.3.2</span>\n<a href=#toc:subsec:links-to-source-code>Ссылки на исходный код</a><a href=#subsec:links-to-source-code class=anchor aria-hidden=true></a></h3><p>Все, кроме GitHub, являются зеркальными ссылками. Теги всегда должны\nбыть актуальными, но не гарантируется, что master-ветка будет\nактуальной. Если цель состоит в том, чтобы клонировать master-ветку,\nиспользуйте ссылку GitHub вместо других.<ol class=incremental><li><p>GitHub: <a href=https://github.com/MuntashirAkon/AppManager class=uri>https://github.com/MuntashirAkon/AppManager</a><li><p>Codeberg: <a href=https://codeberg.org/muntashir/AppManager class=uri>https://codeberg.org/muntashir/AppManager</a><li><p>GitLab: <a href=https://gitlab.com/muntashir/AppManager class=uri>https://gitlab.com/muntashir/AppManager</a><li><p>Riseup: <a href=https://0xacab.org/muntashir/AppManager class=uri>https://0xacab.org/muntashir/AppManager</a><li><p>sourcehut: <a href=https://git.sr.ht/~muntashir/AppManager class=uri>https://git.sr.ht/~muntashir/AppManager</a></ol></section><section id=subsec:translations class=level3 data-number=1.3.3><h3 data-number=1.3.3><span class=header-section-number>1.3.3</span>\n<a href=#toc:subsec:translations>Переводы</a><a href=#subsec:translations class=anchor aria-hidden=true></a></h3><p>App Manager не поддерживает переводы напрямую через pull/merge\nзапросы. Переводы управляются автоматически через Weblate. Чтобы\nприсоединиться к команде перевода, посетите <a href=https://hosted.weblate.org/engage/app-manager/ class=uri>https://hosted.weblate.org/engage/app-manager/</a>.</section></section><section id=sec:contributing class=level2 data-number=1.4><h2 data-number=1.4><span class=header-section-number>1.4</span> <a href=#toc:sec:contributing>Вклад</a><a href=#sec:contributing class=anchor aria-hidden=true></a></h2><p>Есть несколько способов, которыми пользователь может внести свой\nвклад, такие как создание полезных вопросов, посещение дискуссий,\nулучшение документаций и переводов, добавление библиотек или трекеров,\nпросмотр исходного кода, а так же сообщение об уязвимостях\nбезопасности.<section id=subsec:build-instructions class=level3 data-number=1.4.1><h3 data-number=1.4.1><span class=header-section-number>1.4.1</span>\n<a href=#toc:subsec:build-instructions>Инструкции по сборке</a><a href=#subsec:build-instructions class=anchor aria-hidden=true></a></h3><p>Инструкции по сборке доступны в файле BUILDING, расположенном в корне\nдиректории исходного кода.</section><section id=subsec:submitting-patches class=level3 data-number=1.4.2><h3 data-number=1.4.2><span class=header-section-number>1.4.2</span>\n<a href=#toc:subsec:submitting-patches>Отправка исправлений</a><a href=#subsec:submitting-patches class=anchor aria-hidden=true></a></h3><p>Репозитории, расположенные на сайтах, отличных от GitHub, в настоящее\nвремя считаются зеркалами, и pull/merge запросы, отправленные на этих\nсайтах не будут приняты.<a href=#fn2 class=footnote-ref id=fnref2 role=doc-noteref><sup>2</sup></a> Вместо этого патчи\n(<code>.patch</code> файлы) могут быть отправлены через вложения\nэлектронной почты. <em>Требуется подпись.</em> Прочитайте файл\nCONTRIBUTING расположенный в корне директории с исходным кодом чтобы\nполучить больше информации.<div class=\"amalert warning\"><p><strong><em>Внимание.</em></strong><p>В случае отправки исправлений по электронной почте вся беседа может\nстать общедоступной в будущем. Поэтому не надо включать любую личную\nинформацию, кроме вашего имени или адреса электронной почты.</div></section></section><section id=sec:donation-&-funding class=level2 data-number=1.5><h2 data-number=1.5><span class=header-section-number>1.5</span> <a href=#toc:sec:donation-&-funding>Пожертвование &\nФинансирование</a><a href=#sec:donation-&-funding class=anchor aria-hidden=true></a></h2><p><em>Подношения или покупки не требуются для использования App\nManager.</em> В данный момент App Manager не поддерживает покупки,\nподношения владельцам App Manager могут быть отправлены через Open\nSource Collective.<p>Open Source Collective это фискальный хост на платформе Open\nCollective, который помогает проектам с открытым исходным кодом\nуправлять финансами. В данный момент он поддерживает оплату с помощью\nбанковских аккаунтов, PayPal, кредитных или дебетовых карт, а также\nкриптовалют.<p><em>Link:</em> <a href=https://opencollective.com/muntashir class=uri>https://opencollective.com/muntashir</a>.<p>Отправляя подношения, отправитель соглашается с тем, что подношение\nне используется для приоритизации предложенных ими идей. Предложение\nидей не требует никаких наград или подношений, и их приоритизация\nосуществляется по усмотрению владельца.<p><em>App Manager принимает любые предложения по финансированию или\nгранты.</em> Представители заинтересованной организации могут связаться\nс владельцами напрямую, используя опции в §<a href=#sec:contact data-reference-type=ref data-reference=sec:contact>1.6</a>.<p>In addition, the maintainers and contributors of this project DO NOT\nconsent to the creation, sale, or promotion of tokens, cryptocurrencies,\nNFTs, or any other financial instruments that claim to represent this\nproject, its code, or its community. Any such attempts are unauthorized\nand not affiliated with this project in any way.</section><section id=sec:contact class=level2 data-number=1.6><h2 data-number=1.6><span class=header-section-number>1.6</span> <a href=#toc:sec:contact>Связь</a><a href=#sec:contact class=anchor aria-hidden=true></a></h2><p>Muntashir Al-Islam<a href=#fn3 class=footnote-ref id=fnref3 role=doc-noteref><sup>3</sup></a><br>Email: <a href=mailto:muntashirakon@riseup.net>muntashirakon [at]\nriseup [dot] net</a><br>Key Fingerprint:\n<code>7bad37c2981e41f8f6abea7f58f0b4f26c346fce</code><br>GitHub: <a href=https://github.com/MuntashirAkon class=uri>https://github.com/MuntashirAkon</a><br>Twitter: <a href=https://twitter.com/Muntashir class=uri>https://twitter.com/Muntashir</a></section></section><section id=ch:pages class=level1 data-number=2><h1 data-number=2><span class=header-section-number>2</span> <a href=#toc:ch:pages>Страницы</a><a href=#ch:pages class=anchor aria-hidden=true></a></h1><section id=sec:main-page class=level2 data-number=2.1><h2 data-number=2.1><span class=header-section-number>2.1</span> <a href=#toc:sec:main-page>Главная страница</a><a href=#sec:main-page class=anchor aria-hidden=true></a></h2><p>На главной странице перечислены все установленные, удаленные и\nрезервные копии приложений. Один клик по любому установленному элементу\nприложения открывает <a href=#sec:app-details-page>Страницу сведений о\nприложении</a>. Для удаленных системных приложений отображается\nдиалоговое окно, которое можно использовать для переустановки\nприложения. Используя <a href=#par:main-page-sort>сортировку</a> из\nсписка настроек, приложения можно сортировать различными способами.\nТакже есть возможность фильтровать приложения используя <a href=#par:main-page-filter>фильтр</a>. Возможна фильтрация также через\nстроку поиска с поддержкой регулярных выражений.<figure id=fig:main_page_entry_info_labeled><figure><object data=../images/main_page_entry_info_labeled.svg type=image/svg+xml></object></figure><figcaption>Figure 1: Элемент списка приложений на главной\nстранице</figcaption></figure><section id=subsec:batch-operations class=level3 data-number=2.1.1><h3 data-number=2.1.1><span class=header-section-number>2.1.1</span>\n<a href=#toc:subsec:batch-operations>Пакетные операции</a><a href=#subsec:batch-operations class=anchor aria-hidden=true></a></h3><p>На этой странице также доступны пакетные операции или операции с\nнесколькими приложениями. Режим множественного выбора может быть\nактивирован кликом на любое приложение или нажав и удерживая любой\nэлемент в списке. После активации одним нажатием на элемент списка\nвыбирает его вместо открытия страницы сведений о приложении. В этом\nрежиме пакетные операции расположены в меню множественного выбора внизу\nстраницы. Операции включают:<ul class=incremental><li><p>Добавление выбранных приложений в <a href=#sec:profiles-page>профиль</a><li><p><a href=#sec:backup-restore>Резервное копирование,\nвосстановление или удаление</a> приложений<li><p>Блокировка трекеров в приложениях<li><p>Очистка данных или кэша приложений<li><p>Включение/отключение/принудительная остановка/удаление\nприложений<li><p>Экспорт правил блокировки, сохранённых в App Manager<li><p>Предотвращение фоновой работы приложений (Android 7 и\nвыше)<li><p>Сохранение файлов APK в <code>AppManager/apks</code><li><p>Установка <a href=#sec:net-policy>политик</a></ul><div class=\"amalert tip\"><p><strong><em>Доступность.</em></strong><p>После активации режима множественного выбора можно входить или\nвыходить из меню с помощью правой или левой клавиши клавиатуры.</div></section><section id=subsec:main-colour-codes class=level3 data-number=2.1.2><h3 data-number=2.1.2><span class=header-section-number>2.1.2</span>\n<a href=#toc:subsec:main-colour-codes>Цветовые коды</a><a href=#subsec:main-colour-codes class=anchor aria-hidden=true></a></h3><ul class=incremental><li><p><span class=colorbox style=background-color:#fceed1><span style=color:#000>Светло-серовато-оранжевый (день)</span></span> /\n<span class=colorbox style=background-color:#091f36><span style=color:#fff>Тёмно-синий (ночь)</span></span> – Приложение\nвыбрано для множественной обработки<li><p><span class=colorbox style=background-color:#ff8a80><span style=color:#000>Светло-красный (день)</span></span> / <span class=colorbox style=background-color:#4f1c14><span style=color:#fff>Тёмно-красный (ночь)</span></span> – Приложение\nотключено<li><p><span class=colorbox style=background-color:#ff0><span style=color:#000>Жёлтый</span></span> – Отлаживаемое\nприложение<li><p><span style=color:#e05915>Оранжевая <em>дата</em></span> –\nПриложение имеет доступ к системным логам<li><p><span style=color:#e05915>Оранжевый <em>UID</em></span> –\nИдентификатор пользователя используется несколькими\nприложениями<li><p><span style=color:#e05915>Оранжевый <em>SDK</em></span> –\nВозможно, приложение использует трафик в открытом виде (напр.\nHTTP)<li><p><span style=color:red>Красное <em>имя пакета</em></span> –\nПриложение не позволяет очистить свои данные<li><p><span style=color:red>Красный <em>бекап</em></span> –\nУдаленное приложение с одной или несколькими резервными копиями,\nприсутствующими в App Manager<li><p><span style=color:#e05915>Оранжевый<em>бекап</em></span> –\nУстаревшая резервная копия, т.е. резервная копия содержит более старую\nверсия установленного приложения<li><p><span style=color:#09868b>Темно-голубой\n<em>бекап</em></span> – Актуальная резервная копия, т.е. резервная копия\nсодержит такую же или более позднюю версию установленного\nприложения<li><p><span style=color:#09868b>Темно-голубое <em>имя\nпакета</em></span> – Принудительно остановленное приложение<li><p><span style=color:#09868b>Темно-голубая\n<em>версия</em></span> – Неактивное приложение<li><p><span style=color:#f0f>Пурпурный</span> – Постоянное\nприложение, т. е. оно остается запущенным все время.</ul></section><section id=subsec:main-page-application-types class=level3 data-number=2.1.3><h3 data-number=2.1.3><span class=header-section-number>2.1.3</span>\n<a href=#toc:subsec:main-page-application-types>Типы приложений</a><a href=#subsec:main-page-application-types class=anchor aria-hidden=true></a></h3><p>Приложение может быть либо <strong>пользовательским</strong>, либо\n<strong>системным</strong> приложением вместе со следующими\nсуффиксами:<ul class=incremental><li><p><code>X</code> – Поддерживает несколько архитектур<li><p><code>0</code> – В приложении нет файлов dex<li><p><code>°</code>– Приложение приостановлено<li><p><code>#</code> – Приложение запросило у системы выделение\nбольшого количества оперативной памяти<li><p><code>?</code> – Приложение запросило, чтобы виртуальная машина\nнаходилась в безопасном режиме</ul></section><section id=subsec:main-page-version-info class=level3 data-number=2.1.4><h3 data-number=2.1.4><span class=header-section-number>2.1.4</span>\n<a href=#toc:subsec:main-page-version-info>Информация о версии</a><a href=#subsec:main-page-version-info class=anchor aria-hidden=true></a></h3><p>После названия версии следуют следующие префиксы:<ul class=incremental><li><p><code>_</code> – Нет аппаратного ускорения<li><p><code>~</code> – Только тестовый режим<li><p><code>debug</code> – Отлаживаемое приложение</ul></section><section id=subsec:main-page-options-menu class=level3 data-number=2.1.5><h3 data-number=2.1.5><span class=header-section-number>2.1.5</span>\n<a href=#toc:subsec:main-page-options-menu>Меню настроек</a><a href=#subsec:main-page-options-menu class=anchor aria-hidden=true></a></h3><p>В меню опций есть несколько опций, которые можно использовать для\nсортировки, фильтрации перечисленных приложений, а также для перехода к\nразличным страницам.<section id=subsubsec:main-list-options class=level4 data-number=2.1.5.1><h4 data-number=2.1.5.1><span class=header-section-number>2.1.5.1</span> Список настроек<a href=#subsubsec:main-list-options class=anchor aria-hidden=true></a></h4><p><strong>Параметры списка</strong> содержат параметры для сортировки\nили фильтрации списка приложений.<section id=сортировка class=level5 data-number=2.1.5.1.1><h5 data-number=2.1.5.1.1><span class=header-section-number>2.1.5.1.1</span> Сортировка<a href=#сортировка class=anchor aria-hidden=true></a></h5><div id=par:main-page-sort></div><p>Приложения, перечисленные на главной странице, можно отсортировать\nнесколькими способами:<ul class=incremental><li><p><strong>Сначала пользовательские.</strong> Пользовательские\nприложения будут отображаться первыми<li><p><strong>Название приложения.</strong> Сортировка по возрастанию\nна основе названий (также известны как <em>ярлыки приложений</em>). Это\nзначение сортировки по умолчанию<li><p><strong>Имя пакета.</strong> Сортировка по возрастанию по именам\nпакетов<li><p><strong>Последнее обновление.</strong> Сортировка в порядке\nубывания по дате обновления пакета<li><p><strong>Общий идентификатор пользователя.</strong> Сортировка по\nубыванию на основе идентификатора пользователя ядра<li><p><strong>Целевая версия SDK.</strong> Сортировка по возрастанию в\nзависимости от целевой SDK<li><p><strong>Подпись.</strong> Сортировка в порядке возрастания на\nоснове информации о подписи приложения<li><p><strong>Сначала отключенные.</strong> Отключенные приложения\nбудут отображаться первыми<li><p><strong>Сначала заблокированные.</strong> Сортировка по убыванию\nв зависимости от количества заблокированных компонентов в\nприложении<li><p><strong>Сначала резервные копии.</strong> Отображать приложения с\nрезервными копиями сверху<li><p><strong>Трекеры.</strong> Сортировка по убыванию в зависимости от\nколичества трекеров в приложении<li><p><strong>Последние действия.</strong> Сортировка по убыванию в\nзависимости от последнего времени любый действий, сделанных с помощью\nApp Manager.</ul><p>В дополнение, существует опция <em>Обратный порядок</em> для\nсортировки приложений в обратном порядке. Не считая настроек сортировки,\nприложения сначала сортируются в алфавитном порядке, чтобы предотвратить\nсоздание случайных результатов сортировки.</section><section id=фильтр class=level5 data-number=2.1.5.1.2><h5 data-number=2.1.5.1.2><span class=header-section-number>2.1.5.1.2</span> Фильтр<a href=#фильтр class=anchor aria-hidden=true></a></h5><div id=par:main-page-filter></div><p>Приложения, перечисленные на главной странице, могут быть\nотфильтрованы следующими способами:<ul class=incremental><li><p><strong>User apps.</strong> Список только пользовательских\nприложений<li><p><strong>System Apps.</strong> Список только системных\nприложений<li><p><strong>Disabled apps.</strong> Список только отключенных\nприложений<li><p><strong>Apps with rules.</strong> Список приложений с одним или\nнесколькими правилами блокировок<li><p><strong>Apps with activities.</strong> Список приложений с одним\nили несколькими действиями<li><p><strong>Apps with backups.</strong> Список приложений с одним или\nнесколькими резервными копиями<li><p><strong>Running apps.</strong> Список приложений, которые в\nнастоящее время запущены<li><p><strong>Apps with splits.</strong> Список приложений с одним или\nнесколькими файлами APK<li><p><strong>Installed apps.</strong> Список только установленных\nприложений<li><p><strong>Uninstalled apps.</strong> Список только удаленных\nприложений<li><p><strong>Apps without backups.</strong> Список приложений без\nрезервного копирования.</ul><p>Кроме сортировки, можно использовать более одного параметра\nфильтрации одновременно. Например, приложения отключенные пользователями\nмогут быть выбраны как <em>User apps</em>, так и <em>Disabled apps</em>.\nЭто может быть особенно полезно для <a href=#subsec:batch-operations>batch operations</a>, где может\nпотребоваться фильтрация пользовательских приложений для безопасного\nвыполнения определенных операций.</section><section id=имя-профиля class=level5 data-number=2.1.5.1.3><h5 data-number=2.1.5.1.3><span class=header-section-number>2.1.5.1.3</span> Имя профиля<a href=#имя-профиля class=anchor aria-hidden=true></a></h5><p>Также можно отобразить приложения, которые находятся только в <a href=#sec:profiles-page>profile</a>. Это может быть полезно для\nпереноса некоторых операций в профиль (к примеру удаление всех\nприложений в профиле), что не может быть сделано через <a href=#sec:profiles-page>Profiles page</a>.</section></section><section id=инструкции class=level4 data-number=2.1.5.2><h4 data-number=2.1.5.2><span class=header-section-number>2.1.5.2</span> Инструкции<a href=#инструкции class=anchor aria-hidden=true></a></h4><p>Нажатие на инструкции открывает оффлайн версию документации App\nManager. Она открывает онлайн версию, если не установлен соответствующий\nраздел функций. feat_docs или WebView не присутствует в системе для\nзагрузки документации.</section><section id=subsubsec:main:1-click-ops class=level4 data-number=2.1.5.3><h4 data-number=2.1.5.3><span class=header-section-number>2.1.5.3</span> Операции в 1 клик<a href=#subsubsec:main:1-click-ops class=anchor aria-hidden=true></a></h4><p><strong>1-Click Ops</strong> отвечает за операции с одним кликом. Он\nоткрывает <a href=#sec:1-click-ops-page>corresponding page</a> в новом\nдействии.</section><section id=использование-приложения class=level4 data-number=2.1.5.4><h4 data-number=2.1.5.4><span class=header-section-number>2.1.5.4</span> Использование приложения<a href=#использование-приложения class=anchor aria-hidden=true></a></h4><p>Статистики использования приложений, таких как <em>screen time</em>,\n<em>data usage</em> (both mobile and Wi-Fi), <em>the number of times an\napp was opened</em> можно получить кликнув на опцию <strong>App\nUsage</strong> в меню. Однако это требует разрешения <em>Usage\nAccess</em>. Этот пункт меню не будет указан, если функция доступа к\nиспользованию отключена в <a href=#subsec:enable/disable-features>settings</a>.</section><section id=subsubsec:main:running-apps class=level4 data-number=2.1.5.5><h4 data-number=2.1.5.5><span class=header-section-number>2.1.5.5</span> Запущеные приложения<a href=#subsubsec:main:running-apps class=anchor aria-hidden=true></a></h4><p>Этот пункт меню открывает новую страницу, на которой отображается\nсписок запущенных приложений или процессов. Он также отображает текущее\nиспользование памяти и кэша (если доступно). Если root или ADB\nнедоступны для диспетчера приложений, он отображает только себя в\nпоследних версиях Android. Запущенные приложения или процессы также\nмогут быть принудительно остановлены или завершены на результирующей\nстранице. Журналы для каждого идентификатора процесса (PID) также можно\nпросмотреть в <a href=#subsubsec:log-viewer>log viewer</a>. Также\nвозможно выполнять пакетные операции либо щелчком по значку, либо\nдлительным щелчком по элементу. Обычный щелчок по любому элементу\nоткрывает диалоговое окно, в котором отображается более подробная\nинформация.</section><section id=профили class=level4 data-number=2.1.5.6><h4 data-number=2.1.5.6><span class=header-section-number>2.1.5.6</span> Профили<a href=#профили class=anchor aria-hidden=true></a></h4><p>Этот пункт меню открывает <a href=#sec:profiles-page>profiles\npage</a>. Профили - это способ настройки регулярно используемых задач.\nОни также могут быть вызваны с помощью ярлыков.</section><section id=программа-обновления-apk class=level4 data-number=2.1.5.7><h4 data-number=2.1.5.7><span class=header-section-number>2.1.5.7</span> Программа обновления APK<a href=#программа-обновления-apk class=anchor aria-hidden=true></a></h4><p>Если в системе установлено приложение <a href=https://github.com/rumboalla/apkupdater>APK Updater</a>, его\nможно открыть через этот пункт меню. Параметр остается скрытым, если\nприложение отсутствует в системе.</section><section id=termux class=level4 data-number=2.1.5.8><h4 data-number=2.1.5.8><span class=header-section-number>2.1.5.8</span> Termux<a href=#termux class=anchor aria-hidden=true></a></h4><p>Если в системе установлено приложение <a href=https://github.com/termux/termux-app>Termux</a>, запущенный сеанс\n(или новый сеанс) можно открыть через этот пункт меню. Параметр остается\nскрытым, если приложение отсутствует в система.</section><section id=debloater class=level4 data-number=2.1.5.9><h4 data-number=2.1.5.9><span class=header-section-number>2.1.5.9</span> Debloater<a href=#debloater class=anchor aria-hidden=true></a></h4><p>This menu item opens the debloater page that lists all the bloatware\navailable in the device and in App Manager. It also suggests alternative\napplications based on the criteria set by the <a href=https://github.com/MuntashirAkon/android-debloat-list>Android\nDebloat List</a> project.</section><section id=subsubsec:main:labs class=level4 data-number=2.1.5.10><h4 data-number=2.1.5.10><span class=header-section-number>2.1.5.10</span> Labs<a href=#subsubsec:main:labs class=anchor aria-hidden=true></a></h4><p>This menu item opens the labs page that lists all the additional\nfeatures. They include Log Viewer, System Config, Terminal, File Manager\n(as Files), UI Tracker, Interceptor, and Code Editor pages.</section><section id=настройки class=level4 data-number=2.1.5.11><h4 data-number=2.1.5.11><span class=header-section-number>2.1.5.11</span> Настройки<a href=#настройки class=anchor aria-hidden=true></a></h4><p>This menu item opens the in-app <a href=#sec:settings-page>Settings\npage</a>.</section></section></section><section id=sec:app-details-page class=level2 data-number=2.2><h2 data-number=2.2><span class=header-section-number>2.2</span> <a href=#toc:sec:app-details-page>Страница сведений о приложении</a><a href=#sec:app-details-page class=anchor aria-hidden=true></a></h2><p><strong>App Details</strong> page consists of 11 (eleven) tabs. It\ndescribes almost every bit of information an application usually has,\nincluding all attributes from its manifest, <a href=#ch:app-ops>application operations</a> (app ops), signing\ninformation, libraries, and so on.<section id=subsec:app-details-colour-codes class=level3 data-number=2.2.1><h3 data-number=2.2.1><span class=header-section-number>2.2.1</span>\n<a href=#toc:subsec:app-details-colour-codes>Цветовые коды</a><a href=#subsec:app-details-colour-codes class=anchor aria-hidden=true></a></h3><p>List of colours used in this page, and their meaning:<ul class=incremental><li><p><span class=colorbox style=background-color:#ff0000b3><span style=color:#000>Red (day)</span></span> / <span class=colorbox style=background-color:#790d0d><span style=color:#fff>dark red (night)</span></span> – Denotes any app\nops or permissions having the dangerous flag, or any components blocked\nwithin App Manager, or any unsupported but required features.<li><p><span class=colorbox style=background-color:#ff8a80><span style=color:#000>Light red (day)</span></span> / <span class=colorbox style=background-color:#4f1c14bf><span style=color:#fff>very\ndark red (night)</span></span> – Denotes the components disabled outside\nof App Manager, or any unsupported but optional features.<div class=\"amalert tip\"><p><strong><em>Note.</em></strong><p>A component marked as disabled does not always mean that it is\ndisabled by the user: It could also be disabled by the system or marked\nas disabled in its manifest. The components of a disabled application\nare also considered disabled by the system (and App Manager).</div><li><p><span class=colorbox style=background-color:#ff8017><span style=color:#000>Vivid orange (day)</span></span> / <span class=colorbox style=background-color:#ff801780><span style=color:#fff>very\ndark orange (night)</span></span> – Denotes the tracker\ncomponents<li><p><span class=colorbox style=background-color:#ea80fc><span style=color:#000>Soft magenta (day)</span></span> / <span class=colorbox style=background-color:#431c5d><span style=color:#fff>very dark violet (night)</span></span> – Denotes\nthe running services.<li><p><span class=colorbox style=background-color:#1b8654><span style=color:#fff>Green</span></span> – Used in the tracker-indicator\ntag to denote that all the trackers in the application are\nblocked.</ul></section><section id=subsec:app-info-tab class=level3 data-number=2.2.2><h3 data-number=2.2.2><span class=header-section-number>2.2.2</span>\n<a href=#toc:subsec:app-info-tab>Вкладка \"Сведения о приложении\"</a><a href=#subsec:app-info-tab class=anchor aria-hidden=true></a></h3><p><strong>App Info</strong> tab contains general information about an\napplication. It also lists many actions that can be performed within\nthis tab.<section id=subsubsec:app-info-general-information class=level4 data-number=2.2.2.1><h4 data-number=2.2.2.1><span class=header-section-number>2.2.2.1</span> Общая информация<a href=#subsubsec:app-info-general-information class=anchor aria-hidden=true></a></h4><p>The list below is in the same order as listed in the App Info\ntab.<ul class=incremental><li><p><strong>Application Icon.</strong> The application icon. If the\napplication does not have an icon, the system default icon will be\ndisplayed. It is also possible to verify the APK signature via SHA or\nMD5 sums stored in the clipboard by simply clicking on it.<li><p><strong>Application Label.</strong> The application label or the\nname of the application.<li><p><strong>Package Name.</strong> The name of the application\npackage. Clicking on the name stores it in the clipboard.<li><p><strong>Version.</strong> The application version is divided into\ntwo parts. The first part is called <em>version name</em>. The format of\nthis part varies but often consists of multiple integers separated by\ndots. The second part is called <em>version code</em>. It is enclosed by\nthe first brackets. The version code is an integer used to differentiate\nbetween application versions (since a version name can be unreadable to\na machine). In general, a new version of an application has higher\nversion code than the old ones. For example, if <code>123</code> and\n<code>125</code> are two version codes of an application, we can say\nthat the latter is more updated than the former because the version code\nof the latter is higher. An application that serves different APK files\nfor the same version on different platforms (mobile, tabs, desktops,\netc.) or architectures (32/64 bit, ARM or Intel), the version numbers\ncan be misleading as they often add prefixes for each platform.<li><p><strong>Tags.</strong> (Also known as tag clouds) Tags include\nthe most basic, concise and useful information of an application. See\n§<a href=#subsubsec:tags data-reference-type=ref data-reference=subsubsec:tags>2.2.2.2</a> for a complete list of tags\nshown here.<li><p><strong>Horizontal Action Panel.</strong> An action panel\nconsisting of various actions that can be carried out for the\napplication. See §<a href=#subsubsec:horizontal-action-panel data-reference-type=ref data-reference=subsubsec:horizontal-action-panel>2.2.2.3</a> for a\ncomplete list of actions available here. Additional actions are\navailable in the <a href=#subsubsec:app-info-options-menu>options\nmenu</a>.<li><p><strong>Paths & Directories.</strong> Contains various\ninformation regarding application paths including <em>app directory</em>\n(where the APK files reside), <em>data directories</em> (internal,\ndevice protected and externals), and <em>JNI library directory</em> (if\npresent). JNI libraries are used to invoke native codes usually written\nin C/C++. Use of native library can make the application run faster or\nhelp an application use third-party libraries written using languages\nother than Java like in most games. The directories can be opened via\nfile managers provided they support it and have the necessary\npermissions, by clicking on the launch button on the right-hand side of\na directory item.<li><p><strong>Data Usage.</strong> Amount of data used by the\napplication as reported by the operating system. Depending on Android\nversion, this may require a wide range of permissions including\n<em>Usage Access</em> and <em>Telephony</em> permissions.<li><p><strong>Storage & Cache.</strong> Displays information\nregarding the size of the application (APK files, optimised files), data\nand cache. In older devices, size of external data, cache, media and OBB\nfolders are also displayed. This part remains hidden if <em>Usage\nAccess</em> permission is not granted in the newer devices.<li><p><strong>More Info.</strong> Displays other information such\nas–<ul class=incremental><li><p><strong>SDK.</strong> Displays information related to the Android\nSDK: <em>Max</em> denotes the target SDK and <em>Min</em> denotes the\nminimum SDK (the latter is not available in Android Lollipop). If the\ntarget SDK value is less than the platform SDK (i.e., the highest SDK\nthe current operating system supports), the application will run in the\ncompatibility mode. This means the application may have access to\ncertain features that are unavailable or restricted in a newer version\nof Android, which can be a security and/or privacy issue. SDK is also\nknown as <strong>API Level</strong>.<br><div class=seealso-inline><p><em>Смотрите также: <span><a href=https://en.wikipedia.org/wiki/Android_version_history#Overview>Android\nVersion History</a></span></em></div><li><p><strong>Flags.</strong> The application flags used at the time of\nbuilding the application. For a complete list of flags and what they do,\nread the <a href=https://developer.android.com/reference/android/content/pm/ApplicationInfo#flags>official\ndocumentation</a>.<li><p><strong>Date Installed.</strong> The date when the application\nwas first installed.<li><p><strong>Date Updated.</strong> The date when the application was\nlast updated. This is the same as <em>Date Installed</em> if the\napplication hasn’t been updated.<li><p><strong>Process Name.</strong> The name of the process if it is\ndifferent from the package name. Process name is set when an application\nis being started by the system, and is usually the same as the package\nname.<li><p><strong>Installer App.</strong> The application that installed\nthis application. The installer application may not always be the same\nas the application that installed this application, because Android\nallows setting an arbitrary value for this field. In Android 11 onwards,\nthe actual installer application is also stored by the system which can\nbe accessed by clicking the “Info” button on the right-hand side of the\nitem. The field will not be visible if the installer application is not\nreported by the system (e.g., due to the installer application being\nuninstalled or hidden). Installer application may be granted additional\nprivileges by the system so that it can control certain behaviour of the\napplication it installs.<li><p><strong>User ID.</strong> The unique user ID set by the system to\nthe application. For shared applications, the same user ID is assigned\nto multiple applications having the same <em>Shared User\nID</em>.<li><p><strong>Shared User ID.</strong> Applicable for applications that\nare shared together. The shared application must have the same <a href=#subsec:signatures-tab>signatures</a>.<li><p><strong>Primary ABI.</strong> Architecture supported by this\nplatform for this application.<li><p><strong>Zygote preload name.</strong> Responsible for preloading\napplication code and data shared across all the isolated services that\nuses app zygote.<li><p><strong>Hidden API enforcement policy.</strong> Since Android 9,\nmany methods and classes in Android framework have been made\ninaccessible to the third-party applications through hidden API\nenforcement policy. It has the following options:<ul class=incremental><li><p><em>Default.</em> Based on the type of application. For system\napplications, it should be disabled, and for others, it should be\nenforced.<li><p><em>None/disabled.</em> The application has full access to the\nhidden API as it used to be before Android 9.<li><p><em>Warn.</em> Same as above, except that warnings will be logged\neach time the application accesses the hidden API. This is mostly\nunused.<li><p><em>Enforce.</em> The application cannot access hidden API,\neither dark-grey list or blacklist, or both of them. This is the default\noption for the third-party applications in Android 9 onwards unless the\napplication is whitelisted by the OEM or the vendor.<div class=\"amalert warning\"><p><strong><em>Warning.</em></strong><p>Hidden API enforcement policy is not properly implemented in Android\nand can be bypassed by the application. As a result, this value should\nnot be trusted.</div></ul><li><p><strong>SELinux.</strong> Mandatory access control (MAC) policy\nset by the operating system via SELinux.<li><p><strong>Main Activity.</strong> The main entry point to the\napplication. This is only visible if the application has <a href=#subsubsec:activities>activities</a> and any of those are\nopenable from the Launcher. There’s also a launch button on the\nright-hand side which can be used to launch this activity.</ul></ul></section><section id=subsubsec:tags class=level4 data-number=2.2.2.2><h4 data-number=2.2.2.2><span class=header-section-number>2.2.2.2</span> Теги<a href=#subsubsec:tags class=anchor aria-hidden=true></a></h4><ul class=incremental><li><p><strong>Tracker info.</strong> Number of tracker components in\nthe application (e.g., <em>5 trackers</em>) The colour of the tag\nappears orange if the trackers are unblocked and dark cyan if they are\nblocked in App Manager. Clicking on the tag opens a dialog containing\nthe list of tracker components which can also be blocked or unblocked\nprovided App Manager has sufficient privileges.<li><p><strong>Application type.</strong> User application or system\napplication. For a system application, it displays whether the\napplication is an updated version of the system application or the\napplication is installed systemless-ly via Magisk.<li><p><strong>Split APK info.</strong> Number of splits in the APK\nexcluding the base APK (e.g., <em>5 splits</em>). Clicking on the tag\nopens a dialog containing a few additional information, such as name,\ntype, and size.<li><p><strong>Debuggable.</strong> The application can be debugged over\nADB. Debuggable applications can enjoy certain functions unavailable to\na regular application. The data of the application might be accessible\nvia ADB (e.g. using <code>run-as</code> command) without any additional\npermissions.<li><p><strong>Test only.</strong> The application is a test-only\napplication. Test-only applications can enjoy certain functions\nunavailable to a regular application. The data of the application might\nbe accessible via ADB (e.g. using <code>run-as</code> command) without\nany additional permissions.<li><p><strong>No code.</strong> The application does not have any code\nassociated with it i.e., DEX files aren’t present. In some system\napplications, the actual code might be located in another\nplace.<li><p><strong>Large heap.</strong> The application has requested large\nheap size i.e., more space in memory (RAM) is requested for dynamic\nallocation. It is still up to the operating system to decide whether to\nallocate large space for the application. App Manager, for example,\nrequests large heap size because it needs to load an entire APK into\nmemory while scanning an APK.<li><p><strong>Open links.</strong> The application may open certain\nlinks from any applications. If the application can open any links by\ndefault, the color of the tag would be red, dark cyan if otherwise.\nClicking on the tag opens a dialog with the supported hosts or domains\nlisted. In Android 12 onwards, it displays an option to enable or\ndisable opening links by default provided App Manager has sufficient\npermissions. Otherwise, it displays an option to open the system\nsettings page for the application.<li><p><strong>Running.</strong> One or more services of the application\nis currently running in the background. Clicking on the tag opens a\ndialog containing the list of running services. Clicking on any services\nopens the log viewer with default filter set to the UID associated with\nthe service (which can be different from the UID of the application if\nit is running in a separate or isolated process) provided the log viewer\nfeature is enabled. There’s also an option to force-stop the\napplication.<li><p><strong>Stopped.</strong> The application is force stopped. This\nmay not prevent it from running automatically later.<li><p><strong>Disabled.</strong> Denotes that the application is\ndisabled (hidden from the launcher).<li><p><strong>Suspended.</strong> Denotes that the application is\nsuspended (grayed out in the launcher).<li><p><strong>Hidden.</strong> Denotes that the application is hidden\n(hidden from the launcher).<li><p><strong>MagiskHide.</strong> MagiskHide is enabled for the\napplication. Clicking on the tag opens a dialog containing the list of\nprocess names within the application that can be added to or removed\nfrom the MagiskHide list.<li><p><strong>MagiskDenyList.</strong> The application is present in\nMagisk DenyList. Clicking on the tag opens a dialog containing the list\nof process names within the application that can be added to or removed\nfrom Magisk DenyList.<li><p><strong>WX.</strong> The application violates the “W^X policy”\nand is capable of writing and executing in the same directory or in the\nsame portion of memory. This allows the execution of arbitrary\nexecutables either by the modification of executables embedded within\nthe application or by downloading them from the Internet.<br><div class=seealso-inline><p><em>Смотрите также: <span><a href=https://en.wikipedia.org/wiki/W%5EX>W^X in\nWikipedia</a></span></em></div><li><p><strong>Bloatware.</strong> The application may be a known\nbloatware. Clicking on the tag opens a dialog containing detailed\ninformation in addition to suggestions (if available).<li><p><strong>KeyStore.</strong> The application has items in the\nAndroid KeyStore. Clicking on the tag opens a dialog containing all the\nKeyStore files that belong to the application.<li><p><strong>Backup.</strong> The application was backed up using App\nManager at least once. Clicking on the tag opens a dialog containing all\nthe available backups along with metadata.<li><p><strong>No battery optimisation.</strong> Battery optimisation is\ndisabled for the application. It is possible to re-enable battery\noptimisation by clicking on the tag.<li><p><strong>Sensors disabled.</strong> Sensors are disabled for the\napplication. Sensors are disabled for most applications by\ndefault.<li><p><a href=#sec:net-policy><strong>Net policy.</strong></a>\nNetwork policy (e.g., background data usage) is configured for the\napplication. Clicking on the tag displays a dialog containing the\nsupported policies for the platform along with the options to configure\nthem.<li><p><a href=#sec:terminologies><strong>SSAID.</strong></a> Clicking\non the tag opens a dialog containing the current SSAID assigned to the\napplication. It is also possible to reset/regenerate the SSAID if\nneeded.<li><p><strong>SAF.</strong> Denotes that the application has been\ngranted to access one or more storage locations or files i.e. URIs via\nStorage Access Framework (SAF). Clicking on the tag opens a dialog\ncontaining the list of granted URIs.<li><p><strong>Play App Signing.</strong> Indicates that the application\nmight be signed by Google.<li><p><strong>Xposed.</strong> Indicates that the application may be an\nXposed module. Clicking on the tag displays a dialog with additional\ninformation.<li><p><strong>Static Shared Library.</strong> Denotes that the\napplication serves as a static shared library for one or more\napplications. Clicking on the tag opens a dialog containing a list of\ninstalled versions of the library along with an option to uninstall\nthem.<div class=\"amalert tip\"><p><strong><em>Notice.</em></strong><p>The trichrome library (supplied by Google Chrome, Vanadium or similar\nprojects) is currently the only known static shared library on\nAndroid.</div></ul></section><section id=subsubsec:horizontal-action-panel class=level4 data-number=2.2.2.3><h4 data-number=2.2.2.3><span class=header-section-number>2.2.2.3</span> Горизонтальная панель\nдействий<a href=#subsubsec:horizontal-action-panel class=anchor aria-hidden=true></a></h4><p>Horizontal Action Panel, as described in the previous section,\nconsists of various application-related actions, such as–<ul class=incremental><li><p><strong>Launch.</strong> Launch the application provided it has a\nlauncher <a href=#subsubsec:activities>activity</a>.<li><p><strong>Freeze.</strong> Freeze the application. This button is\nnot displayed if it is already frozen or the user does not have enough\nprivileges. After the application is frozen, it may be hidden from the\napp drawer depending on how it was configured. Shortcuts configured by\nthe application may also be removed. The application may only be\nunfrozen via App Manager, <code>pm</code> command or any other tools\nthat offer such a feature. Long clicking on the button opens a dialog\nwhere a shortcut can be configured to quickly freeze or unfreeze the\napplication.<li><p><strong>Uninstall.</strong> Uninstall the application with a\nprompt. In the dialog prompt, it is possible to uninstall updates of a\nsystem application, or if App Manager has enough privileges or the\noperating system supports it, it is possible to uninstall the\napplication without clearing its data and signature. For the latter\ncase, the installed application must match the signature with the\npreviously installed application if it is installed again.<div class=\"amalert tip\"><p><strong><em>Tips.</em></strong><p>A better way to reinstall an application with a different signature\nwould be to back up its data using App Manager and restore it again\nafter installing the application instead of opting to preserving data\nand signature of the application during uninstallation as this option\nmay cause undefined behaviour in the future.</div><li><p><strong>Unfreeze.</strong> Unfreeze the application. This button\nis not displayed if it is already enabled or the user does not have\nenough privileges. Similar to the <em>Freeze</em> button, long clicking\non the button opens a dialog where a shortcut can be configured to\nquickly freeze or unfreeze the application.<li><p><strong>Force Stop.</strong> Force-stop the application.<li><p><strong>Clear Data.</strong> Clear data from the application.\nThis includes any information stored in the internal and, recently, the\nexternal directories, including accounts (if set by the application),\ncache, etc. Clearing data from App Manager, for example, removes all the\nrules (the blocking is not removed though) saved within the application\n(Which is why you should always take backups of your rules). This button\nis not displayed if the user does not have enough privileges.<li><p><strong>Clear Cache.</strong> Clear the application cache. If the\napplication is running during the operation, the cache may not be\ncleared as expected.<li><p><strong>Install.</strong> Install the application, only displayed\nif the application hasn’t already been installed.<li><p><strong>What’s New.</strong> Displayed for an external\napplication if an older version of it is already installed. Clicking on\nthis button opens a dialog containing the differences between this and\nthe installed version in a version control manner. Changes include\n<em>version</em>, <em>trackers</em>, <em>permissions</em>,\n<em>components</em>, <em>signatures</em> (only checksum changes),\n<em>features</em>, <em>shared libraries</em> and <em>SDK</em>.<li><p><strong>Update.</strong> Displayed if the application has a\nhigher version code than the installed application.<li><p><strong>Reinstall.</strong> Displayed if the application has the\nsame version code as the installed application.<li><p><strong>Downgrade.</strong> Displayed if the application has a\nlower version code than the installed application.<li><p><strong>Manifest.</strong> Opens the application’s manifest file\nin a separate page. If the application has more than one split, it will\ndisplay the list of split APK files, and clicking on an item will open\nthe corresponding manifest file instead.<li><p><strong>Scanner.</strong> Scan the application in order to list\npotential trackers and libraries. It also scans the file using\nVirusTotal and fetch results from Pithus if configured.<br><div class=seealso-inline><p><em>Смотрите также: <span><a href=#sec:scanner-page>Scanner\npage</a></span></em></div><li><p><strong>Shared Prefs.</strong> Displays a list of shared\npreferences used by the application. Clicking on a preference item in\nthe list opens the <a href=#sec:shared-preferences-editor-page>Shared\nPreferences Editor page</a>. This option is only visible if the user has\nthe required privileges.<li><p><strong>Databases.</strong> Displays a list of databases used by\nthe application. Clicking on an item opens a list of activities that can\nopen the database. This option is only visible if the user has the\nrequired privileges.<li><p><strong>F-Droid.</strong> Open the application in the selected\n<em>F-Droid</em> client.<li><p><strong>Store.</strong> Open the application in <em>Aurora\nStore</em>. The option is only visible if <em>Aurora Store</em> is\ninstalled.</ul></section><section id=subsubsec:app-info-options-menu class=level4 data-number=2.2.2.4><h4 data-number=2.2.2.4><span class=header-section-number>2.2.2.4</span> Меню параметров<a href=#subsubsec:app-info-options-menu class=anchor aria-hidden=true></a></h4><p>Options-menu is located in the top-right corner of the page. A\ncomplete description of the options present there are given below:<ul class=incremental><li><p><strong>Share.</strong> Share button can be used to share the APK\nor (if the application is has multiple splits, OBB files or any\ndependencies) <em>APKS</em> file extracted from the\napplication.<li><p><strong>Refresh.</strong> Refresh the App Info tab.<li><p><strong>View in Settings.</strong> Open the application in\nAndroid Settings.<li><p><strong>Backup/restore.</strong> Open the backup/restore\ndialog.<li><p><strong>Export blocking rules.</strong> Export rules configured\nfor the application within App Manager.<li><p><strong>Open in Termux.</strong> Open the application in Termux.\nThis actually runs <code>su - user_id</code> where <code>user_id</code>\ndenotes the application’s kernel user ID (described in §<a href=#subsubsec:app-info-general-information data-reference-type=ref data-reference=subsubsec:app-info-general-information>2.2.2.1</a>).\nThis option is only visible to the root users. See §<a href=#subsubsec:config-termux data-reference-type=ref data-reference=subsubsec:config-termux>2.2.2.5</a> to learn how to\nconfigure Termux to run commands from third-party applications.<li><p><strong>Run in Termux.</strong> Open the application via\n<code>run-as package_name</code> in Termux. This is only applicable to\nthe debuggable applications and works for both root and ADB users. See\n§<a href=#subsubsec:config-termux data-reference-type=ref data-reference=subsubsec:config-termux>2.2.2.5</a> to learn how to\nconfigure Termux to run commands from third-party applications.<li><p><strong>MagiskHide.</strong> Open a dialog containing the list of\nprocess names within the application that can be added or removed from\nthe MagiskHide list.<li><p><strong>Magisk DenyList.</strong> Open a dialog containing the\nlist of process namees within the application that can be added or\nremoved from Magisk DenyList.<li><p><strong>Battery optimisation.</strong> Enable/disable battery\noptimisation for this application.<li><p><strong>Sensors.</strong> Enable/disable sensors for this\napplication.<li><p><a href=#sec:net-policy><strong>Net policy.</strong></a>\nConfigure network policy (e.g., background data usage) for the\napplication.<li><p><strong>Extract Icon.</strong> Extract and save the application’s\nicon in the shared storage.<li><p><strong>Optimize.</strong> Perform optimisation for this\napplication. This option is for advanced users only.<li><p><strong>Add to profile.</strong> Add the application to one of\nthe configured <a href=#sec:profile-page>profiles</a>.<li><p><strong>Install for….</strong> Install the application for\nanother user and/or in the work profile if configured.</ul></section><section id=subsubsec:config-termux class=level4 data-number=2.2.2.5><h4 data-number=2.2.2.5><span class=header-section-number>2.2.2.5</span> Настройки Termux<a href=#subsubsec:config-termux class=anchor aria-hidden=true></a></h4><p>By default, Termux does not allow running commands from a third-party\napplication. To use this option, Termux v0.96 or later is required and\n<code>allow-external-apps=true</code> must be added in\n<code>~/.termux/termux.properties</code>.<div class=\"amalert tip\"><p><strong><em>Info.</em></strong><p>Enabling this option does not weaken Termux’ security. The\nthird-party applications still need to ask the user to allow running\narbitrary commands in Termux.</div></section></section><section id=subsec:component-tabs class=level3 data-number=2.2.3><h3 data-number=2.2.3><span class=header-section-number>2.2.3</span>\n<a href=#toc:subsec:component-tabs>Вкладки компонентов</a><a href=#subsec:component-tabs class=anchor aria-hidden=true></a></h3><p><strong>Activities</strong>, <strong>Services</strong>,\n<strong>Receivers</strong> (i.e., broadcast receivers) and\n<strong>Providers</strong> (e.g., content providers) are collectively\nknown as the application components, because they offer similar features\nand share similar properties. For example, they all have a\n<em>name</em>, a <em>label</em>, an <em>icon</em>, can be enabled or\ndisabled, and can be executed via <em>Intent</em>. Application\ncomponents are the building blocks of an application and must be\ndeclared in the application manifest (with a few exceptions).\nApplication manifest is a file where application specific metadata are\nstored. The Android operating system learns what to do with the\napplication by reading the metadata.<p>Colours used in these tabs are explained in §<a href=#subsec:app-details-colour-codes data-reference-type=ref data-reference=subsec:app-details-colour-codes>2.2.1</a>. It is also\npossible to sort the list of components to display blocked or tracker\ncomponents on top of the list via the <strong>Sort</strong> option\nlocated in the three-dots menu.<section id=subsubsec:activities class=level4 data-number=2.2.3.1><h4 data-number=2.2.3.1><span class=header-section-number>2.2.3.1</span> Activities<a href=#subsubsec:activities class=anchor aria-hidden=true></a></h4><p><strong>Activities</strong> are the windows or pages that can be\nuniquely identified by the Android operating system (e.g., <em>Main\npage</em> and <em>App Details page</em> are two activities). Each\nactivity can have multiple UI components known as <em>widgets</em> or\n<em>fragments</em>, and each component can be nested or placed on top of\neach other. The developer can also choose to open external files, links,\netc. within an activity using a method called <em>intent filters</em>.\nFor example, when you open a file in your file manager, either your file\nmanager or the operating system scans the intent filters via\nPackageManager, find the activities capable of opening the file, and\nlist those activities so that you can choose your preferred\nactivity.<p>Activities that are <em>exportable</em> can be opened by any\nthird-party applications. However, Some activities may require\npermissions, and only an application having those permissions can open\nthem. In the <em>Activities</em> tab, certain activities can be launched\nvia the <strong>Launch</strong> button. If it is necessary to supply\nadditional information, such as Intent extras, data or action, long\nclicking on the <strong>Launch</strong> button opens the <a href=#sec:interceptor-page>Activity Interceptor</a> page which\nprovides such features.<div class=\"amalert tip\"><p><strong><em>Tip.</em></strong><p>No-root users can grant\n<code>android.permission.WRITE_SECURE_SETTINGS</code> via ADB to launch\n<em>non-exportable</em> activities.</div><div class=\"amalert tip\"><p><strong><em>Notice.</em></strong><p>If launching an activity throws an error, it may have certain\ndependencies which are not met (e.g., <em>App Details</em> page in App\nManager cannot be launched using the launch button, because it requires\na package name). Since the dependencies cannot be inferred\nprogrammatically, the activity may not be opened from App Manager by\ndefault.</div><p>It is also possible to create shortcuts of an activity-launch using\nthe <strong>Create shortcut</strong> button. If you need to supply\nadditional information, you can create a shortcut from the Activity\nInterceptor page instead.<div class=\"amalert danger\"><p><strong><em>Caution.</em></strong><p>If you uninstall App Manager, all shortcuts created by App Manager\nwill be lost.</div></section><section id=subsubsec:details:servcies class=level4 data-number=2.2.3.2><h4 data-number=2.2.3.2><span class=header-section-number>2.2.3.2</span> Сервисы<a href=#subsubsec:details:servcies class=anchor aria-hidden=true></a></h4><p>Unlike <a href=#subsubsec:activities>activities</a> that users can\nsee, <strong>Services</strong> handle background tasks. For example, if\nyou’re downloading a video from the internet using your phone’s Internet\nbrowser, the Internet browser is using a <em>foreground service</em> to\ndownload the content.<p>When an activity is closed or removed from the <em>Recents</em> page,\nit may be destroyed immediately depending on the amount free memory the\nphone has, battery statistics, or how the activity is configured. But\nservices can be run indefinitely if desired. If more services run in the\nbackground, the phone may become slower due to the shortage of memory\nand/or processing power, and the phone’s battery will be drained more\nquickly. Newer versions of Android come with a battery optimisation\nfeature enabled by default for all applications. With this feature\nenabled, the system can randomly terminate any service depending on the\namount of resources the system has or the service requires. However,\nforeground services (i.e., services that run with a fixed notification,\nsuch as music player or downloader) are not typically terminated unless\nthe system is very low on resources (memory, battery, etc.). Certain\nstock ROMs can offer more aggressive optimisation. MIUI, for example,\nhas a very aggressive optimisation feature known as the <em>MIUI\noptimisation</em>.<p>Both activities and services are run in the same <a href=https://stackoverflow.com/questions/7597742>looper</a> called the\nmain looper, which means the services do not really run in the\nbackground. It is the task of the developer to ensure this. How do the\napplication communicate with the services? It uses <a href=#subsubsec:app-details-receivers>broadcast receiver</a> or\nBinder.</section><section id=subsubsec:app-details-receivers class=level4 data-number=2.2.3.3><h4 data-number=2.2.3.3><span class=header-section-number>2.2.3.3</span> Приемники<a href=#subsubsec:app-details-receivers class=anchor aria-hidden=true></a></h4><p><strong>Receivers</strong> (also called <em>broadcast receivers</em>)\ncan be used to trigger execution of certain tasks when certain events\noccur. These components are called broadcast receivers, because they are\nexecuted as soon as a broadcast message is received. These broadcast\nmessages are sent using a method called <em>Intent</em>. Intent is a\nspecial feature in Android that can be used to open applications (i.e.,\nactivities), run services and send broadcast messages. Therefore, like\n<a href=#subsubsec:activities>activities</a>, broadcast receivers use\n<em>intent filters</em> to receive the desired broadcast messages.\nBroadcast messages can be sent by the system or the application itself.\nWhen a broadcast message is sent, the corresponding receivers are\nactivated by the system so that they can execute tasks. For example, if\nyour phone is low on resources, it may freeze or experience lags for a\nmoment after you enable mobile data or connect it to the Wi-Fi. This is\nbecause broadcast receivers that can receive\n<code>android.net.conn.CONNECTIVITY_CHANGE</code> are activated by the\nsystem as soon as the data connection is enabled. Since many\napplications typically use this intent filter, they are all activated\nalmost immediately by the system which causes the freezing or lags.<p>Receivers can also be used for inter-process communication (IPC),\ni.e., it can be used to communicate across multiple applications or even\ndifferent components of a single application.</section><section id=subsubsec:providers class=level4 data-number=2.2.3.4><h4 data-number=2.2.3.4><span class=header-section-number>2.2.3.4</span> Providers<a href=#subsubsec:providers class=anchor aria-hidden=true></a></h4><p><strong>Providers</strong> are primarily used for data management.\nFor example, when you save an APK file or export rules in App Manager,\nit uses a content provider called <code>.fm.FmProvider</code> to save\nthe APK or export the rules. There are many providers, including the\nones provided by the system, that can be used to manage various\ncontent-related tasks, such as database management, tracking, searching,\netc. Each provider has a field called <em>Authority</em> which is unique\nto the application in the entire Android ecosystem just as the package\nname.</section><section id=дополнительные-функции-для-устройств-с-root-доступом class=level4 data-number=2.2.3.5><h4 data-number=2.2.3.5><span class=header-section-number>2.2.3.5</span> Дополнительные функции для\nустройств с root доступом<a href=#дополнительные-функции-для-устройств-с-root-доступом class=anchor aria-hidden=true></a></h4><p>Unlike the no-root users who are mostly spectators in these tabs,\nroot users can perform various operations.<section id=blocking-components. class=level5 data-number=2.2.3.5.1><h5 data-number=2.2.3.5.1><span class=header-section-number>2.2.3.5.1</span> Blocking Components.<a href=#blocking-components. class=anchor aria-hidden=true></a></h5><p>On the right-most side of each component item, there is a switch\nwhich can be used to toggle the blocking status of that particular\ncomponent. If <a href=#subsubsec:instant-component-blocking>Instant\nComponent Blocking</a> is not enabled or blocking is never applied to\nthe application before, it is required to apply the changes using the\n<strong>Apply rules</strong> option in three-dots menu. It is also\npossible to remove the already-applied rules using the same option\n(which would be read as <strong>Remove rules</strong> this time).<p>It is also possible to block the component using one of the several\nmethods by long clicking on the button.<div class=seealso-inline><p><em>Смотрите также: <span><a href=#sec:faq:app-components>FAQ: App\nComponents</a></span></em></div></section><section id=par:appdetails:blocking-trackers class=level5 data-number=2.2.3.5.2><h5 data-number=2.2.3.5.2><span class=header-section-number>2.2.3.5.2</span> Blocking Trackers.<a href=#par:appdetails:blocking-trackers class=anchor aria-hidden=true></a></h5><p>It is possible to disable tracker components using the <strong>Block\ntracker</strong> option in the three-dots menu. All tracker components\nwill be blocked regardless of the tab you’re currently in.<div class=\"amalert tip\"><p><strong><em>Info.</em></strong><p>Tracker components are a subset of application components. Therefore,\nthey are blocked using the same method used for blocking any other\ncomponents.</div><div class=seealso><p><em>Смотрите также:</em><ul class=incremental><li><p><a href=#subsec:tracker-classes-versus-tracker-components>FAQ:\nTracker classes versus tracker components</a><li><p><a href=#sec:scanner-page>Scanner Page</a><li><p><a href=#subsec:block-unblock-trackers>1-Click Ops Page:\nBlock/Unblock Trackers</a></ul></div></section></section></section><section id=subsec:permission-tabs class=level3 data-number=2.2.4><h3 data-number=2.2.4><span class=header-section-number>2.2.4</span>\n<a href=#toc:subsec:permission-tabs>Вкладки разрешений</a><a href=#subsec:permission-tabs class=anchor aria-hidden=true></a></h3><p><strong>App Ops</strong>, <strong>Uses Permissions</strong> and\n<strong>Permissions</strong> tabs are related to permissions. In Android\ncommunication across applications or processes not having the same\nidentity (known as <em>shared ID</em>) often require permissions. These\npermissions are managed by the permission controller. Some permissions\nare considered <em>normal</em> permissions which are granted\nautomatically if they appear in the application manifest, but\n<em>dangerous</em> and <em>development</em> permissions require\nconfirmation from the user. Colours used in these tabs are explained in\n§<a href=#subsec:app-details-colour-codes data-reference-type=ref data-reference=subsec:app-details-colour-codes>2.2.1</a>.<section id=subsubsec:app-ops class=level4 data-number=2.2.4.1><h4 data-number=2.2.4.1><span class=header-section-number>2.2.4.1</span> App Ops<a href=#subsubsec:app-ops class=anchor aria-hidden=true></a></h4><p><strong>App Ops</strong> stands for <strong>Application\nOperations</strong>. Since Android 4.3, <em>App Ops</em> are used by\nAndroid to control many system permissions. Each app op has a unique\nnumber associated with it which is displayed along with the private name\nof the operation in the App Ops tab. Some app ops also have a public\nname. A large number of app ops are also associated with\n<em>permissions</em>. In this tab, an app op is considered dangerous if\nits associated permission is marked as dangerous. Other information such\nas <em>flags</em>, <em>permission name</em>, <em>permission\ndescription</em>, <em>package name</em>, <em>group</em> are also taken\nfrom the associated <a href=#subsubsec:permissions>permission</a>.\nOthers may include the following:<ul class=incremental><li><p><strong>Mode.</strong> It describes the current authorisation\nstatus which can be <em>allow</em>, <em>deny</em> (a rather misnomer, it\nsimply means error), <em>ignore</em> (it actually means deny),\n<em>default</em> (inferred from a list of defaults set internally by the\nvendor or the AOSP), <em>foreground</em> (in newer Android versions, it\nmeans the app op can only be used when the application is running in\nforeground), and some custom modes set by the vendors (MIUI uses\n<em>ask</em>, for example).<li><p><strong>Duration.</strong> The amount of time this app op has\nbeen used (there can be negative durations whose use cases are currently\nunknown to me).<li><p><strong>Accept Time.</strong> Last time the app op was\naccepted.<li><p><strong>Reject Time.</strong> Last time the app op was\nrejected.</ul><div class=\"amalert tip\"><p><strong><em>Info.</em></strong><p>Contents of this tab are visible to no-root users if\n<code>android.permission.GET_APP_OPS_STATS</code> is granted via\nADB.</div><p>There is a toggle button next to each app op item which can be used\nto allow or deny (ignore) it. Other supported modes can also be set by\nlong clicking on the toggle button. If the desired app op is not listed\nin the tab, <em>Set custom app op</em> option in the menu can be used\ninstead. It is also possible to reset the changes using the <em>Reset to\ndefault</em> option, or deny all the dangerous app ops using the\ncorresponding option in the menu. Due to the nature how app ops work,\nthe system may take some time to apply them.<div class=\"amalert tip\"><p><strong><em>Tip.</em></strong><p>Denying certain app ops may cause the application to misbehave. If\nall attempts fail, <em>reset to default</em> option can be used as the\nlast resort.</div><p>It is possible to sort the list in ascending order by app op names\nand the associated unique numbers (or values), or list the denied app\nops first using the corresponding sorting options.<div class=seealso-inline><p><em>Смотрите также: <span><a href=#ch:app-ops>Appendix: App\nOps</a></span></em></div></section><section id=uses-permissions class=level4 data-number=2.2.4.2><h4 data-number=2.2.4.2><span class=header-section-number>2.2.4.2</span> Uses Permissions<a href=#uses-permissions class=anchor aria-hidden=true></a></h4><p><strong>Uses Permissions</strong> are the permissions used by the\napplication. This is named so because they are specified in the manifest\nusing <code>uses-permission</code> tags. Information such as\n<em>flags</em>, <em>permission name</em>, <em>permission\ndescription</em>, <em>package name</em>, <em>group</em> are taken from\nthe associated <a href=#subsubsec:permissions>permission</a>.<p>Privileged users can grant or revoke the <em>dangerous</em> and\n<em>development</em> permissions via the toggle button on the right side\nof each permission item. It is also possible revoke dangerous\npermissions all at once using the corresponding option in the menu. Only\nthese two types of permissions can be revoked because Android does not\nallow the modification of <em>normal</em> permissions (which most of\nthem are). It might still be possible to revoke them by editing\n<code>runtime-permissions.xml</code> itself, but whether this is a\npossibility is still being investigated.<div class=\"amalert tip\"><p><strong><em>Info.</em></strong><p>Since dangerous permissions are revoked by default by the system,\nrevoking all dangerous permissions is the same as resetting all the\npermissions.</div><p>It is possible to sort the permissions by their name (in ascending\norder) or choose to display denied or dangerous permissions at first\nusing the corresponding options in the menu.</section><section id=subsubsec:permissions class=level4 data-number=2.2.4.3><h4 data-number=2.2.4.3><span class=header-section-number>2.2.4.3</span> Permissions<a href=#subsubsec:permissions class=anchor aria-hidden=true></a></h4><p><strong>Permissions</strong> are usually custom permissions defined\nby the application itself. These type of permissions are marked as\n<em>Internal</em> permissions. It also contains permissions declared by\nother applications which are marked as <em>External</em> permissions. An\nexternal permission can be specified in an <em>exported</em> application\ncomponent so that another application may invoke the component only if\nit holds the permission. Below is a complete description of each item\ndisplayed in this tab:<ul class=incremental><li><p><strong>Name.</strong> A permission has a unique name (e.g.,\n<code>android.permission.INTERNET</code>) that multiple applications can\nrequest. The application that declared the permission is automatically\ngranted and cannot be revoked.<li><p><strong>Icon.</strong> Each permission can have a custom icon.\nThe other permission tabs do not have any icon because they do not\ncontain any icon in the application manifest.<li><p><strong>Description.</strong> This optional field describes the\npermission. If there isn’t any description associated with the\npermission, the field is not displayed.<li><p><strong>Flags.</strong> (Uses the flag symbol or\n<strong>Protection Level</strong> name) This describes various\npermission flags such as <em>normal</em>, <em>development</em>,\n<em>dangerous</em>, <em>instant</em>, <em>granted</em>,\n<em>revoked</em>, <em>signature</em>, <em>privileged</em>, etc.<li><p><strong>Package Name.</strong> Denotes the package name\nassociated with the permission, i.e. the package that defined the\npermission.<li><p><strong>Group.</strong> The group name associated with the\npermission (if any). Several related permissions can often be grouped\ntogether.</ul></section></section><section id=subsec:signatures-tab class=level3 data-number=2.2.5><h3 data-number=2.2.5><span class=header-section-number>2.2.5</span>\n<a href=#toc:subsec:signatures-tab>Signatures Tab</a><a href=#subsec:signatures-tab class=anchor aria-hidden=true></a></h3><p><strong>Signatures</strong> are actually called signing information.\nAn application is signed with one or more signing keys by its developer\nbefore publishing it. The integrity of an application, i.e., whether the\napplication is from the actual developer and has not been modified by\nanother person, can be checked using the signing certificate included in\nthe APK files. This is because when an application is modified by an\nunauthorised entity, the application can longer be signed with the\noriginal signing keys since the signing keys are unknown to the entity.\nOne way to verify the integrity of an application is via the checksums\ngenerated from the certificates. If the developer supplies the checksums\nfor the signing certificates, they can be compared against the checksums\ngenerated in the <strong>Signatures</strong> tab to verify the\napplication. For example, if you have downloaded App Manager from GitHub\nor Telegram Channel, you can verify whether the application was actually\nreleased by me by simply matching the following <em>SHA256</em> checksum\nwith the one displayed in this tab:<pre><code>320c0c0fe8cef873f2b554cb88c837f1512589dcced50c5b25c43c04596760ab</code></pre><p>Several hashing algorithms are used to generate checksums in this\ntab. They include <em>MD5</em>, <em>SHA1</em>, <em>SHA256</em> and\n<em>SHA512</em>.<div class=\"amalert danger\"><p><strong><em>Caution.</em></strong><p>Signing information should be verified using a reliable hashing\nalgorithm, such as <em>SHA256</em>. DO NOT rely on <em>MD5</em> or\n<em>SHA1</em> checksums as they are known to generate the same checksums\nfor multiple certificates.</div></section><section id=subsec:uses-features-tab class=level3 data-number=2.2.6><h3 data-number=2.2.6><span class=header-section-number>2.2.6</span>\n<a href=#toc:subsec:uses-features-tab>Uses Features tab</a><a href=#subsec:uses-features-tab class=anchor aria-hidden=true></a></h3><p><strong>Uses Features</strong> tab lists the features declared by the\napplication, such as OpenGL ES, telephony, and leanback. Some features\ncan be required by the application, and some features can be optional.\nRequired features must be present in the system along with the required\nversion. Otherwise, any attempt to install the application will be\ndenied by the system. Colours used in this tab are explained in §<a href=#subsec:app-details-colour-codes data-reference-type=ref data-reference=subsec:app-details-colour-codes>2.2.1</a>.</section><section id=subsec:configurations-tab class=level3 data-number=2.2.7><h3 data-number=2.2.7><span class=header-section-number>2.2.7</span>\n<a href=#toc:subsec:configurations-tab>Configurations tab</a><a href=#subsec:configurations-tab class=anchor aria-hidden=true></a></h3><p><strong>Configurations</strong> tab lists the configurations required\nby the application, such as input method type (qwerty, 12 key), touch\nscreen type (finger, stylus, etc.), and navigation type (dial pad,\ntrackball, wheel). This tab is going to be empty for most\napplications.</section><section id=subsec:shared-libs-tab class=level3 data-number=2.2.8><h3 data-number=2.2.8><span class=header-section-number>2.2.8</span>\n<a href=#toc:subsec:shared-libs-tab>Shared Libraries Tab</a><a href=#subsec:shared-libs-tab class=anchor aria-hidden=true></a></h3><p><strong>Shared libraries</strong> tab lists the legacy JAR\ndependencies, any static shared library dependencies (currently, the\nonly known cases are the Chromium-based browsers and WebViews) as well\nas the JNI (Java native interface) libraries. For JNI libraries, it\nspecifies platform (x86/x86_64/ARM/AArch64), architecture (32/64 bit),\nobject type (shared object or executable), etc.</section></section><section id=sec:1-click-ops-page class=level2 data-number=2.3><h2 data-number=2.3><span class=header-section-number>2.3</span> <a href=#toc:sec:1-click-ops-page>1-Click Ops Page</a><a href=#sec:1-click-ops-page class=anchor aria-hidden=true></a></h2><p>This page is displayed on selecting the <a href=#subsubsec:main:1-click-ops>1-Click Ops option</a> in the <a href=#subsec:main-page-options-menu>main menu</a>.<section id=subsec:block-unblock-trackers class=level3 data-number=2.3.1><h3 data-number=2.3.1><span class=header-section-number>2.3.1</span>\n<a href=#toc:subsec:block-unblock-trackers>Block/Unblock\nTrackers</a><a href=#subsec:block-unblock-trackers class=anchor aria-hidden=true></a></h3><p>This option can be used to block or unblock the ad/tracker components\nfrom the installed applications. On selecting this option, App Manager\nwill ask if it should list trackers from all the applications or only\nfrom the user applications. Novice users should avoid blocking trackers\nfrom the system applications in order to avoid bad consequences. After\nthat, a multi-choice dialog box will appear where it is possible to\nexclude one or more applications from this operation. The changes are\napplied immediately on pressing the <em>block</em> or <em>unblock</em>\nbutton.<div class=\"amalert warning\"><p><strong><em>Notice.</em></strong><p>Certain applications may not function as expected after blocking\ntheir trackers. If that is the case, remove the blocking rules all at\nonce or one by one in the component tabs of the <a href=#sec:app-details-page>App Details page</a> for the corresponding\napplication.</div><div class=seealso-inline><p><em>Смотрите также: <span><a href=#par:appdetails:blocking-trackers>App Details Page: Blocking\nTrackers</a></span></em></div></section><section id=subsec:block-components-dots class=level3 data-number=2.3.2><h3 data-number=2.3.2><span class=header-section-number>2.3.2</span>\n<a href=#toc:subsec:block-components-dots>Block Components…</a><a href=#subsec:block-components-dots class=anchor aria-hidden=true></a></h3><p>This option can be used to block certain application components as\nspecified by their signatures. A signature of a component is the full\nname or partial name of the component. For safety, it is recommended to\nadd a <code>.</code> (dot) at the end of each partial signature, because\nthe underlying algorithm searches and matches the components in a greedy\nmanner. It is also possible to insert more than one signature in which\ncase all the signatures have to be separated by white spaces. Similar to\nthe option above, there is also an option to apply blocking to the\nsystem applications.<div class=\"amalert danger\"><p><strong><em>Caution.</em></strong><p>If you are not aware of the consequences of blocking applcations\ncomponents by their signatures, you should avoid using this option as it\nmay result in bootloop or soft brick, and you may have to apply factory\nreset as a result.</div></section><section id=subsec:set-mode-for-app-ops-dots class=level3 data-number=2.3.3><h3 data-number=2.3.3><span class=header-section-number>2.3.3</span>\n<a href=#toc:subsec:set-mode-for-app-ops-dots>Set Mode for App\nOps…</a><a href=#subsec:set-mode-for-app-ops-dots class=anchor aria-hidden=true></a></h3><p>This option can be used to configure certain <a href=#ch:app-ops>applcation operations</a> of all or selected\napplications. There are two fields. The first field can be used to\ninsert more than one app op constants (either names or values) separated\nby white spaces. It is not always possible to know in advance about all\nthe app op constants as they vary from device to device and from OS to\nOS. Desired app op constant can be found in the <em>App Ops</em> tab\nlocated in the <a href=#sec:app-details-page>App Details page</a>. The\nsecond field can be used to insert or select one of the <a href=#subsec:mode-constants>modes</a> that will be set against the\nspecified app ops.<div class=\"amalert danger\"><p><strong><em>Caution.</em></strong><p>Unless you are well-informed about app ops and the consequences of\nblocking them, you should avoid using this option.</div></section><section id=subsec:1-click-back-up class=level3 data-number=2.3.4><h3 data-number=2.3.4><span class=header-section-number>2.3.4</span>\n<a href=#toc:subsec:1-click-back-up>Back up</a><a href=#subsec:1-click-back-up class=anchor aria-hidden=true></a></h3><p>1-Click options for back up. As a precaution, it lists the affected\nbackups before performing any operation.<section id=back-up-all-apps. class=level5 data-number=2.3.4.0.1><h5 data-number=2.3.4.0.1><span class=header-section-number>2.3.4.0.1</span> Back up all apps.<a href=#back-up-all-apps. class=anchor aria-hidden=true></a></h5><p>Back up all the installed applications.</section><section id=redo-existing-backups. class=level5 data-number=2.3.4.0.2><h5 data-number=2.3.4.0.2><span class=header-section-number>2.3.4.0.2</span> Redo existing backups.<a href=#redo-existing-backups. class=anchor aria-hidden=true></a></h5><p>Back up all the installed applications that have a previous\nbackup.</section><section id=back-up-apps-without-backups. class=level5 data-number=2.3.4.0.3><h5 data-number=2.3.4.0.3><span class=header-section-number>2.3.4.0.3</span> Back up apps without\nbackups.<a href=#back-up-apps-without-backups. class=anchor aria-hidden=true></a></h5><p>Back up all the installed applications without a previous backup.</section><section id=verify-and-redo-backups. class=level5 data-number=2.3.4.0.4><h5 data-number=2.3.4.0.4><span class=header-section-number>2.3.4.0.4</span> Verify and redo\nbackups.<a href=#verify-and-redo-backups. class=anchor aria-hidden=true></a></h5><p>Verify the recently made backups of the installed applications and\nredo backup if necessary.</section><section id=back-up-apps-with-changes. class=level5 data-number=2.3.4.0.5><h5 data-number=2.3.4.0.5><span class=header-section-number>2.3.4.0.5</span> Back up apps with\nchanges.<a href=#back-up-apps-with-changes. class=anchor aria-hidden=true></a></h5><p>If an app has changed since the last backup, redo its backup. It\nchecks a number of indices including application version, last update\ndate, last launch date, integrity and file hashes. Directory hashes are\ntaken during the backup process and are stored in a database. On running\nthis operation, new hashes are taken and compared with the ones kept in\nthe database.</section></section><section id=subsec:1-click-restore class=level3 data-number=2.3.5><h3 data-number=2.3.5><span class=header-section-number>2.3.5</span>\n<a href=#toc:subsec:1-click-restore>Restore</a><a href=#subsec:1-click-restore class=anchor aria-hidden=true></a></h3><p>1-Click options for restore. As a precaution, it lists the affected\nbackups before performing any operation.<section id=restore-all-apps. class=level5 data-number=2.3.5.0.1><h5 data-number=2.3.5.0.1><span class=header-section-number>2.3.5.0.1</span> Restore all apps.<a href=#restore-all-apps. class=anchor aria-hidden=true></a></h5><p>Restore <em>base backup</em> of all the backed up applications.</section><section id=restore-not-installed-apps. class=level5 data-number=2.3.5.0.2><h5 data-number=2.3.5.0.2><span class=header-section-number>2.3.5.0.2</span> Restore not installed\napps.<a href=#restore-not-installed-apps. class=anchor aria-hidden=true></a></h5><p>Restore <em>base backup</em> of all the backed up applications that\nare not currently installed.</section><section id=restore-latest-backups. class=level5 data-number=2.3.5.0.3><h5 data-number=2.3.5.0.3><span class=header-section-number>2.3.5.0.3</span> Restore latest backups.<a href=#restore-latest-backups. class=anchor aria-hidden=true></a></h5><p>Restore <em>base backup</em> of already installed applications whose\nversion codes are higher than the installed version code.</section></section><section id=subsec:trim-caches-in-all-apps class=level3 data-number=2.3.6><h3 data-number=2.3.6><span class=header-section-number>2.3.6</span>\n<a href=#toc:subsec:trim-caches-in-all-apps>Trim Caches in All\nApps</a><a href=#subsec:trim-caches-in-all-apps class=anchor aria-hidden=true></a></h3><p>Delete caches from all applications, including Android system. During\nthis operation, caches of all the running applications may not be\ncleared as expected.</section></section><section id=sec:profiles-page class=level2 data-number=2.4><h2 data-number=2.4><span class=header-section-number>2.4</span> <a href=#toc:sec:profiles-page>Profiles Page</a><a href=#sec:profiles-page class=anchor aria-hidden=true></a></h2><p>Profiles page can be accessed from the <a href=#subsec:main-page-options-menu>options-menu</a> in the main page.\nIt primarily displays a list of configured profiles along with the\ntypical options to perform operations on them. New profiles can also be\nadded using the <em>plus</em> button at the bottom-right corner.\nProfiles can be imported, duplicated or deleted. Clicking on a profile\nitem opens its <a href=#sec:profile-page>profile page</a>.<section id=subsec:profiles-options-menu class=level3 data-number=2.4.1><h3 data-number=2.4.1><span class=header-section-number>2.4.1</span>\n<a href=#toc:subsec:profiles-options-menu>Options Menu</a><a href=#subsec:profiles-options-menu class=anchor aria-hidden=true></a></h3><p>The three-dots menu in the top-right corner opens the global option\nmenu. It has an option to import an existing profile that was previously\nexported from App Manager.<p>Long clicking on any profile item brings up another options-menu. It\noffers the following options:<ul class=incremental><li><p><strong>Apply now….</strong> This option can be used to apply the\nprofile directly. When clicked, a dialog is displayed where it is\npossible to select a <a href=#subsubsec:profile-state>profile\nstate</a>. On selecting one of the states, the profile will be applied\nimmediately.<li><p><strong>Delete.</strong> Clicking on this option will remove the\nprofile immediately without a warning.<li><p><strong>Duplicate.</strong> This option can be used to duplicate\nthe profile. When clicked, a dialog is displayed where it is possible to\nset a name for the new profile. On clicking “OK”, the <a href=#sec:profile-page>profile page</a> will be loaded by duplicating\nall the configurations that this profile have. However, the profile will\nnot be saved until it is saved manually.<li><p><strong>Copy profile ID.</strong> This option is used to copy the\nunique profile ID of the profile. The profile ID can be used to <a href=#subsec:triggering-a-profile>trigger the profile</a> from a\nthird-party application.<li><p><strong>Export.</strong> Export the profile to an external\nstorage. Profiles exported this way can be imported via the\n<em>import</em> option as mentioned above.<li><p><strong>Create shortcut.</strong> This option can be used to\ncreate a shortcut for the profile. There are two options:\n<em>Simple</em> and <em>Advanced</em>. When configured with the latter\noption, it prompts the user to select a profile state when the shortcut\nis invoked. The former option, on the other hand, always uses the\ndefault state that was configured when the profile was last\nsaved.</ul></section></section><section id=sec:profile-page class=level2 data-number=2.5><h2 data-number=2.5><span class=header-section-number>2.5</span> <a href=#toc:sec:profile-page>Profile Page</a><a href=#sec:profile-page class=anchor aria-hidden=true></a></h2><p>Profile page displays the configurations for a profile. It also\noffers the options to edit them.<section id=subsec:profile-options-menu class=level3 data-number=2.5.1><h3 data-number=2.5.1><span class=header-section-number>2.5.1</span>\n<a href=#toc:subsec:profile-options-menu>Options Menu</a><a href=#subsec:profile-options-menu class=anchor aria-hidden=true></a></h3><p>The three dots menu in the top-right corner opens the options-menu.\nIt contains several options such as–<ul class=incremental><li><p><strong>Apply.</strong> This option can be used to apply the\nprofile directly. When clicked, a dialog is displayed where it is\npossible to select a <a href=#subsubsec:profile-state>profile\nstate</a>. On selecting one of the states, the profile will be applied\nimmediately.<div class=\"amalert tip\"><p><strong><em>Notice.</em></strong><p>When you apply a profile, if some packages do not match the criteria,\nthey will simply be ignored.</div><li><p><strong>Save.</strong> Save changes to the profile.<li><p><strong>Discard.</strong> Discard any modifications made since\nthe last time it was saved.<li><p><strong>Delete.</strong> Clicking on this option will remove the\nprofile immediately without a warning.<li><p><strong>Duplicate.</strong> This option can be used to duplicate\nthe profile. When clicked, a dialog is displayed where it is possible to\nset a name for the new profile. On clicking “OK”, this page will be\nreloaded by duplicating all the configurations that this profile have.\nHowever, the new profile will not be saved until it is saved\nmanually.<li><p><strong>Create shortcut.</strong> This option can be used to\ncreate a shortcut for the profile. There are two options:\n<em>Simple</em> and <em>Advanced</em>. When configured with the latter\noption, it prompts the user to select a profile state when the shortcut\nis invoked. The former option, on the other hand, always uses the\ndefault state that was configured when the profile was last\nsaved.</ul></section><section id=subsec:profile-apps-tab class=level3 data-number=2.5.2><h3 data-number=2.5.2><span class=header-section-number>2.5.2</span>\n<a href=#toc:subsec:profile-apps-tab>Apps Tab</a><a href=#subsec:profile-apps-tab class=anchor aria-hidden=true></a></h3><p>Apps tab lists the packages configured for this profile. Packages can\nbe added or removed using the <em>plus</em> button located near the\nbottom of the screen. A package can also be removed by long clicking on\nit (in which case, a popup will be displayed with the only option,\n<em>delete</em>).</section><section id=subsec:profile-configurations-tab class=level3 data-number=2.5.3><h3 data-number=2.5.3><span class=header-section-number>2.5.3</span>\n<a href=#toc:subsec:profile-configurations-tab>Configurations\nTab</a><a href=#subsec:profile-configurations-tab class=anchor aria-hidden=true></a></h3><p>Configurations tab can be used to configure the selected\npackages.<section id=profile-id class=level4 data-number=2.5.3.1><h4 data-number=2.5.3.1><span class=header-section-number>2.5.3.1</span> Profile ID<a href=#profile-id class=anchor aria-hidden=true></a></h4><p>The unique ID for this profile, currently set based on the profile\nname. The profile ID can be used to <a href=#subsec:triggering-a-profile>trigger the profile</a> from a\nthird-party application.</section><section id=comment class=level4 data-number=2.5.3.2><h4 data-number=2.5.3.2><span class=header-section-number>2.5.3.2</span> Comment<a href=#comment class=anchor aria-hidden=true></a></h4><p>This is the text that will be displayed in the <a href=#sec:profiles-page>profiles page</a>. If not set, the current\nconfigurations will be displayed instead.</section><section id=subsubsec:profile-state class=level4 data-number=2.5.3.3><h4 data-number=2.5.3.3><span class=header-section-number>2.5.3.3</span> State<a href=#subsubsec:profile-state class=anchor aria-hidden=true></a></h4><p>Denotes how certain configured options will behave by default. For\ninstance, if <em>disable</em> option is turned on, the applications will\nbe disabled if the state is <em>on</em> and will be enabled if the state\nis <em>off</em>. Currently, it only supports <em>on</em> and\n<em>off</em> values.</section><section id=users class=level4 data-number=2.5.3.4><h4 data-number=2.5.3.4><span class=header-section-number>2.5.3.4</span> Users<a href=#users class=anchor aria-hidden=true></a></h4><p>Select users for which is the profile will be applied. All users are\nselected by default.</section><section id=components class=level4 data-number=2.5.3.5><h4 data-number=2.5.3.5><span class=header-section-number>2.5.3.5</span> Components<a href=#components class=anchor aria-hidden=true></a></h4><p>This behaves the same way as the <a href=#subsec:block-components-dots>Block Components…</a> option does\nin the 1-Click Ops page. However, the blocking here is only applied to\nthe selected packages. If the <a href=#subsubsec:profile-state>state</a> is <em>on</em>, the components\nwill be blocked, and if the state is <em>off</em>, the components will\nbe unblocked. The option can be disabled (regardless of the inserted\nvalues) by clicking on the <em>disabled</em> button on the input\ndialog.<div class=seealso-inline><p><em>Смотрите также: <span><a href=#subsec:faq:what-are-app-components>What are the app\ncomponents?</a></span></em></div></section><section id=app-ops class=level4 data-number=2.5.3.6><h4 data-number=2.5.3.6><span class=header-section-number>2.5.3.6</span> App Ops<a href=#app-ops class=anchor aria-hidden=true></a></h4><p>This behaves the same way as the <a href=#subsec:set-mode-for-app-ops-dots>Set Mode for App Ops…</a>\noption does in the 1-Click Ops page. However, the operation here is only\napplied to the selected packages. If the <a href=#subsubsec:profile-state>state</a> is <em>on</em>, the app ops\nwill be denied (i.e. ignored), and if the state is <em>off</em>, the app\nops will be allowed. The option can be disabled (regardless of the\ninserted values) by clicking on the <em>disable</em> button in the input\ndialog.</section><section id=permissions class=level4 data-number=2.5.3.7><h4 data-number=2.5.3.7><span class=header-section-number>2.5.3.7</span> Permissions<a href=#permissions class=anchor aria-hidden=true></a></h4><p>This option can be used to grant or revoke certain permissions from\nthe selected packages. Like others above, permissions must be separated\nby white spaces. If the <a href=#subsubsec:profile-state>state</a> is\n<em>on</em>, the permissions will be revoked, and if the state is\n<em>off</em>, the permissions will be allowed. The option can be\ndisabled (regardless of the inserted values) by clicking on the\n<em>disable</em> button in the input dialog.</section><section id=backuprestore class=level4 data-number=2.5.3.8><h4 data-number=2.5.3.8><span class=header-section-number>2.5.3.8</span> Backup/Restore<a href=#backuprestore class=anchor aria-hidden=true></a></h4><p>This option can be used to take a backup of the selected applications\nand its data or restore them. Two options are available here: <em>Backup\noptions</em> and <em>backup name</em>.<ul class=incremental><li><p><strong>Backup options.</strong> Same as the <a href=#subsec:backup-restore-backup-options>backup options</a> of the\nbackup/restore feature. If not set, the default options will be\nused.<li><p><strong>Backup name.</strong> Set a custom name for the backup.\nIf the backup name is set, each time a backup is made, it will be given\na unique name with backup-name as the suffix. This behaviour will be\nfixed in a future release. Leave this field empty for regular “base”\nbackups (also, make sure not to enable <em>backup multiple</em> in the\nbackup options).</ul><p>If the <a href=#subsubsec:profile-state>state</a> is <em>on</em>,\nthe packages will be backed up, and if the state is <em>off</em>, the\npackages will be restored. The option can be disabled by clicking on the\n<em>disable</em> button in the input dialog.</section><section id=export-blocking-rules class=level4 data-number=2.5.3.9><h4 data-number=2.5.3.9><span class=header-section-number>2.5.3.9</span> Export Blocking Rules<a href=#export-blocking-rules class=anchor aria-hidden=true></a></h4><div class=\"amalert danger\"><p><strong><em>Danger.</em></strong><p>This option is not yet implemented.</div></section><section id=freeze class=level4 data-number=2.5.3.10><h4 data-number=2.5.3.10><span class=header-section-number>2.5.3.10</span> Freeze<a href=#freeze class=anchor aria-hidden=true></a></h4><p>Allow freezing or unfreezing the selected packages depending on the\nvalue of the <a href=#subsubsec:profile-state>state</a>. If the state\nis <em>on</em>, the packages will be frozen, and if the state is\n<em>off</em>, they will be unfrozen.</section><section id=force-stop class=level4 data-number=2.5.3.11><h4 data-number=2.5.3.11><span class=header-section-number>2.5.3.11</span> Force-stop<a href=#force-stop class=anchor aria-hidden=true></a></h4><p>Allow the selected packages to be force-stopped.</section><section id=clear-cache class=level4 data-number=2.5.3.12><h4 data-number=2.5.3.12><span class=header-section-number>2.5.3.12</span> Clear Cache<a href=#clear-cache class=anchor aria-hidden=true></a></h4><p>Enable clearing cache for the selected packages.</section><section id=clear-data class=level4 data-number=2.5.3.13><h4 data-number=2.5.3.13><span class=header-section-number>2.5.3.13</span> Clear Data<a href=#clear-data class=anchor aria-hidden=true></a></h4><p>Enable clearing data for the selected packages.</section><section id=block-trackers class=level4 data-number=2.5.3.14><h4 data-number=2.5.3.14><span class=header-section-number>2.5.3.14</span> Block Trackers<a href=#block-trackers class=anchor aria-hidden=true></a></h4><p>Enable blocking or unblocking of the tracker components from the\nselected packages depending on the value of the <a href=#subsubsec:profile-state>state</a>. If the state is <em>on</em>,\nthe trackers will be blocked, and if the state is <em>off</em>, the\ntrackers will be unblocked.</section><section id=save-apk class=level4 data-number=2.5.3.15><h4 data-number=2.5.3.15><span class=header-section-number>2.5.3.15</span> Save APK<a href=#save-apk class=anchor aria-hidden=true></a></h4><p>Enable saving APK files at <code>AppManager/apks</code> (or in the\ndirectory selected in the settings page) of the selected packages.</section></section></section><section id=sec:settings-page class=level2 data-number=2.6><h2 data-number=2.6><span class=header-section-number>2.6</span> <a href=#toc:sec:settings-page>Settings Page</a><a href=#sec:settings-page class=anchor aria-hidden=true></a></h2><p>Settings page can be used to customise the behaviour of App\nManager.<section id=subsec:language class=level3 data-number=2.6.1><h3 data-number=2.6.1><span class=header-section-number>2.6.1</span>\n<a href=#toc:subsec:language>Language</a><a href=#subsec:language class=anchor aria-hidden=true></a></h3><p>Configure in-app language. App Manager currently supports 22\n(twenty-two) languages.</section><section id=subsec:appearance class=level3 data-number=2.6.2><h3 data-number=2.6.2><span class=header-section-number>2.6.2</span>\n<a href=#toc:subsec:appearance>Appearance</a><a href=#subsec:appearance class=anchor aria-hidden=true></a></h3><section id=subsubsec:app-theme class=level4 data-number=2.6.2.1><h4 data-number=2.6.2.1><span class=header-section-number>2.6.2.1</span> App Theme<a href=#subsubsec:app-theme class=anchor aria-hidden=true></a></h4><p>Configure in-app theme.</section><section id=subsubsec:pure-black-theme class=level4 data-number=2.6.2.2><h4 data-number=2.6.2.2><span class=header-section-number>2.6.2.2</span> Pure Black Theme<a href=#subsubsec:pure-black-theme class=anchor aria-hidden=true></a></h4><p>Whether to use a black background instead of the material themed\nbackground.</section><section id=subsubsec:layout-direction class=level4 data-number=2.6.2.3><h4 data-number=2.6.2.3><span class=header-section-number>2.6.2.3</span> Layout Direction<a href=#subsubsec:layout-direction class=anchor aria-hidden=true></a></h4><p>Change layout direction, either left to right or right to left. This\nis usually set using the selected language but not everybody prefers the\nsame direction.</section><section id=subsubsec:enable/disable-features class=level4 data-number=2.6.2.4><h4 data-number=2.6.2.4><span class=header-section-number>2.6.2.4</span> Enable/Disable Features<a href=#subsubsec:enable/disable-features class=anchor aria-hidden=true></a></h4><p>Enable or disable certain features in App Manager, such as<ul class=incremental><li><p><strong>Interceptor</strong><li><p><strong>Manifest viewer</strong><li><p><strong>Scanner</strong><li><p><strong>Package installer</strong><li><p><strong>Usage access.</strong> With this feature turned off, App\nManager will never ask for the <em>Usage Access</em>\npermission.<li><p><strong>Log viewer</strong><li><p><strong>App explorer.</strong> The “Explore” option will not be\navailable while trying to open an APK file.<li><p><strong>App info.</strong> The “App info” option displayed while\ntrying to open an APK file.<li><p><strong>Code Editor</strong><li><p><strong>VirusTotal</strong></ul></section></section><section id=subsec:privacy class=level3 data-number=2.6.3><h3 data-number=2.6.3><span class=header-section-number>2.6.3</span>\n<a href=#toc:subsec:privacy>Privacy</a><a href=#subsec:privacy class=anchor aria-hidden=true></a></h3><section id=subsubsec:screen-lock class=level4 data-number=2.6.3.1><h4 data-number=2.6.3.1><span class=header-section-number>2.6.3.1</span> Screen Lock<a href=#subsubsec:screen-lock class=anchor aria-hidden=true></a></h4><p>Lock App Manager using Android screen lock provided a screen lock is\nconfigured.<div class=\"amalert warning\"><p><strong><em>Warning.</em></strong><p>If screen lock is disabled in Android after enabling this setting,\nApp Manager will not open until it is enabled again.</div></section><section id=subsubsec:run-am-in-background class=level4 data-number=2.6.3.2><h4 data-number=2.6.3.2><span class=header-section-number>2.6.3.2</span> Run App Manager in the\nBackground<a href=#subsubsec:run-am-in-background class=anchor aria-hidden=true></a></h4><p>Whether to run App Manager in the background to reduce the\ninitialisation delay. On certain devices, this can also help if you’re\nfrequently disconnected from ADB.</section><section id=subsubsec:use-the-internet class=level4 data-number=2.6.3.3><h4 data-number=2.6.3.3><span class=header-section-number>2.6.3.3</span> Use the Internet<a href=#subsubsec:use-the-internet class=anchor aria-hidden=true></a></h4><p>Whether to activate the Internet features in App Manager. This\ncurrently include VirusTotal and Pithus scanning in the <a href=#sec:scanner-page>Scanner page</a>.</section><section id=subsubsec:auth-manager class=level4 data-number=2.6.3.4><h4 data-number=2.6.3.4><span class=header-section-number>2.6.3.4</span> Authorization Manager<a href=#subsubsec:auth-manager class=anchor aria-hidden=true></a></h4><p>This setting allows a third-party application to get access to\ncertain features, such as profiles.</section></section><section id=subsec:mode-of-operation class=level3 data-number=2.6.4><h3 data-number=2.6.4><span class=header-section-number>2.6.4</span>\n<a href=#toc:subsec:mode-of-operation>Mode of Operation</a><a href=#subsec:mode-of-operation class=anchor aria-hidden=true></a></h3><p>Mode of operation defines how App Manager works as a whole. It has\nthe following options:<ul class=incremental><li><p><strong>Auto.</strong> Let App Manager decide the suitable\noption. Although this is the default option, non-rooted users should use\nthe <em>no-root</em> mode.<li><p><strong>Root.</strong> Operate App Manager in root mode. App\nManager will fall back to <em>no-root</em> mode if root is not detected,\nor in rare cases when Binder communication through root is disabled\n(e.g. in <a href=https://github.com/MuntashirAkon/AppManager/issues/606>Phh\nSuperUser</a>).<li><p><strong>ADB over TCP.</strong> Operate App Manager in ADB mode\nvia <a href=#sec:adb-over-tcp>ADB over TCP</a>. App Manager will fall\nback to <em>no-root</em> mode if ADB over TCP is not enabled.<li><p><strong>Wireless debugging.</strong> Enable ADB via Wireless\nDebugging. It will try to connect to the configured port automatically\nat first. On failure, it will ask the user to either pair or connect to\nthe ADB daemon manually. App Manager will fall back to <em>no-root</em>\nmode if it fails to connect to the ADB daemon this way.<div class=\"amalert tip\"><p><strong><em>Info.</em></strong><p>This option is only displayed in devices running Android 11 or later\nas Wireless Debugging was introduced in Android 11.</div><li><p><strong>No-root.</strong> Operate App Manager in no-root mode.\nWhile App Manager performs better in this mode, all the root- or\nADB-specific features will be disabled.</ul><p>It also displays the actual mode of operation at the top. The actual\nmode of operations are <em>root</em>, <em>ABD</em> and\n<em>no-root</em>.<div class=\"amalert tip\"><p><strong><em>Notice.</em></strong><p>“Remote service” is only required for ADB users or when you use the\ncustom commands.</div></section><section id=subsec:apk-signing class=level3 data-number=2.6.5><h3 data-number=2.6.5><span class=header-section-number>2.6.5</span>\n<a href=#toc:subsec:apk-signing>APK Signing</a><a href=#subsec:apk-signing class=anchor aria-hidden=true></a></h3><section id=signature-schemes class=level4 data-number=2.6.5.1><h4 data-number=2.6.5.1><span class=header-section-number>2.6.5.1</span> Signature Schemes<a href=#signature-schemes class=anchor aria-hidden=true></a></h4><p>Configure the <a href=https://source.android.com/security/apksigning>signature\nschemes</a> to be used when APK signing is enabled. v1 and v2 signature\nschemes are enabled by default, but v3 should also be enabled to ensure\nproper security in Android 9 or later.</section><section id=signing-key class=level4 data-number=2.6.5.2><h4 data-number=2.6.5.2><span class=header-section-number>2.6.5.2</span> Signing Key<a href=#signing-key class=anchor aria-hidden=true></a></h4><p>Configure the signing key for signing APK files. Keys from an\nexisting KeyStore can be imported to App Manager, or a new key can be\ngenerated.<div class=\"amalert tip\"><p><strong><em>Tip.</em></strong><p>If you need to use the key in the future, it is recommended that you\ncreate a KeyStore yourself and import the key here. Without a proper\nbackup, keys generated within App Manager are at the risk of being\ndeleted.</div></section><section id=align-apk-files class=level4 data-number=2.6.5.3><h4 data-number=2.6.5.3><span class=header-section-number>2.6.5.3</span> Align APK Files<a href=#align-apk-files class=anchor aria-hidden=true></a></h4><p>Performs zip alignment when App Manager signs an APK file. Zip\nalignment stores the files in the APK file (which is actually a zip\nfile) in a way that a zip file reader can access the files quite easily\nusing random access instead of loading the entire APK file in the\nmemory, which results in the reduction of Android’s memory usage. Note\nthat this step is required if an application’s manifest has\n<code>extractNativeLibs</code> set to <code>true</code>.</section></section><section id=subsec:installer class=level3 data-number=2.6.6><h3 data-number=2.6.6><span class=header-section-number>2.6.6</span>\n<a href=#toc:subsec:installer>Installer</a><a href=#subsec:installer class=anchor aria-hidden=true></a></h3><p>Configure the default behaviour of the installer. You can also find\nmost of the settings by clicking on the <em>cog</em> icon when you\ninstall an application.<section id=install-location class=level4 data-number=2.6.6.1><h4 data-number=2.6.6.1><span class=header-section-number>2.6.6.1</span> Install Location<a href=#install-location class=anchor aria-hidden=true></a></h4><p>Define APK installation location. This can be one of <em>auto</em>,\n<em>internal only</em> and <em>prefer external</em>. In newer Android\nversions, selecting the last option does not guarantee that the\napplication will be installed in the external storage.</section><section id=block-trackers-1 class=level4 data-number=2.6.6.2><h4 data-number=2.6.6.2><span class=header-section-number>2.6.6.2</span> Block Trackers<a href=#block-trackers-1 class=anchor aria-hidden=true></a></h4><p>Whether to block the tracking components immediately after installing\nthe application.</section><section id=display-changes class=level4 data-number=2.6.6.3><h4 data-number=2.6.6.3><span class=header-section-number>2.6.6.3</span> Display Changes<a href=#display-changes class=anchor aria-hidden=true></a></h4><p>Whether to display changes in version, trackers, components,\npermissions, signatures, SDK, etc. in a version controlled style before\ninstalling the application if the application has already been\ninstalled.</section><section id=installer-app class=level4 data-number=2.6.6.4><h4 data-number=2.6.6.4><span class=header-section-number>2.6.6.4</span> Installer App<a href=#installer-app class=anchor aria-hidden=true></a></h4><p>Select the installer application. This is useful for applications\nthat explicitly checks the installer as a way to verify if the\napplication is installed legitimately. This only works for root or ADB\nusers.<div class=\"amalert tip\"><p><strong><em>Notice.</em></strong><p>While checking for the installer might seem a legitimate concern for\nan application, the Android framework already deals with this during the\ninstallation. Checking for the installer is simply the wrong way to\nprove the legitimacy of the source of an application.</div></section><section id=sign-apk class=level4 data-number=2.6.6.5><h4 data-number=2.6.6.5><span class=header-section-number>2.6.6.5</span> Sign APK<a href=#sign-apk class=anchor aria-hidden=true></a></h4><p>Whether to sign the APK files before installing the application. A\nsigning key has to be added or generated before this option can be\nenabled. This can be done in the <a href=#subsec:apk-signing>APK\nsigning</a> page.</section><section id=immediately-perform-dex-optimization class=level4 data-number=2.6.6.6><h4 data-number=2.6.6.6><span class=header-section-number>2.6.6.6</span> Immediately Perform DEX\nOptimization<a href=#immediately-perform-dex-optimization class=anchor aria-hidden=true></a></h4><p>Whether to perform DEX optimization immediately after installing the\napplication. This can be useful for heavy applications, such as the\ngaming applications.</section><section id=install-in-the-background class=level4 data-number=2.6.6.7><h4 data-number=2.6.6.7><span class=header-section-number>2.6.6.7</span> Install in the Background<a href=#install-in-the-background class=anchor aria-hidden=true></a></h4><p>Whether to always install applications in the background. A\nnotification will be issued once the installation is finished.</section></section><section id=subsec:backup/restore class=level3 data-number=2.6.7><h3 data-number=2.6.7><span class=header-section-number>2.6.7</span>\n<a href=#toc:subsec:backup/restore>Back up/Restore</a><a href=#subsec:backup/restore class=anchor aria-hidden=true></a></h3><p>Settings related to <a href=#sec:backup-restore>back\nup/restore</a>.<section id=compression-method class=level4 data-number=2.6.7.1><h4 data-number=2.6.7.1><span class=header-section-number>2.6.7.1</span> Compression method<a href=#compression-method class=anchor aria-hidden=true></a></h4><p>Set the compression method to be used during backups. App Manager\nsupports GZip, BZip2 and Zstandard compression methods, GZip being the\ndefault compression method. It doesn’t affect the restore of an existing\nbackup.</section><section id=subsubsec:settings-backup-options class=level4 data-number=2.6.7.2><h4 data-number=2.6.7.2><span class=header-section-number>2.6.7.2</span> Backup Options<a href=#subsubsec:settings-backup-options class=anchor aria-hidden=true></a></h4><p>Customise the <em>back up/restore dialog</em> displayed while taking\na backup.<div class=seealso-inline><p><em>Смотрите также: <span><a href=#subsec:backup-restore-backup-options>Backup\noptions</a></span></em></div></section><section id=backup-apps-with-android-keystore class=level4 data-number=2.6.7.3><h4 data-number=2.6.7.3><span class=header-section-number>2.6.7.3</span> Backup apps with Android\nKeyStore<a href=#backup-apps-with-android-keystore class=anchor aria-hidden=true></a></h4><p>Allow backup of applications that has entries in the Android\nKeyStore. This option is disabled by default because a few apps (such as\nSignal or Element) may crash if restored.</section><section id=subsubsec:settings-encryption class=level4 data-number=2.6.7.4><h4 data-number=2.6.7.4><span class=header-section-number>2.6.7.4</span> Encryption<a href=#subsubsec:settings-encryption class=anchor aria-hidden=true></a></h4><p>Set an encryption method for the backups. App Manager currently\nsupports OpenPGP (via <a href=https://f-droid.org/packages/org.sufficientlysecure.keychain/>OpenKeyChain</a>),\nAES, RSA and ECC. Like <a href=#subsec:apk-signing>APK signing</a>,\nThe AES, RSA and ECC keys are stored in the KeyStore and can be imported\nfrom other KeyStores.<div class=\"amalert danger\"><p><strong><em>Danger.</em></strong><p>For your own safety, it is not recommended generating RSA and ECC\nkeys inside App Manager. Instead, they should be imported from a\nKeyStore stored in a secure place.<br>In case of AES, the generated key should be stored in a secure place,\nsuch as in a password manager.</div></section><section id=subsubsec:backup-volume class=level4 data-number=2.6.7.5><h4 data-number=2.6.7.5><span class=header-section-number>2.6.7.5</span> Backup Volume<a href=#subsubsec:backup-volume class=anchor aria-hidden=true></a></h4><p>Select the storage where the backups will be stored. This is also\nwhere logs and exported APK files are saved.<div class=\"amalert tip\"><p><strong><em>Notice.</em></strong><p>The backup volume only specifies the storage, not the path. Backups\nare traditionally stored in the <code>AppManager</code> folder inside\nthe storage path. But when the path is selected using Storage Access\nFramework (SAF), the selected path or directory is used directly.</div></section><section id=import-backups class=level4 data-number=2.6.7.6><h4 data-number=2.6.7.6><span class=header-section-number>2.6.7.6</span> Import Backups<a href=#import-backups class=anchor aria-hidden=true></a></h4><p>Import backups from old and discontinued projects such as Titanium\nBackup, OAndBackup, and Swift Backup (version 3.0 to 3.2). The backups\nare not deleted after importing to prevent data loss in case the\nimported backups cannot be restored properly.</section></section><section id=subsec:rules class=level3 data-number=2.6.8><h3 data-number=2.6.8><span class=header-section-number>2.6.8</span>\n<a href=#toc:subsec:rules>Rules</a><a href=#subsec:rules class=anchor aria-hidden=true></a></h3><section id=subsubsec:instant-component-blocking class=level4 data-number=2.6.8.1><h4 data-number=2.6.8.1><span class=header-section-number>2.6.8.1</span> Instant Component\nBlocking<a href=#subsubsec:instant-component-blocking class=anchor aria-hidden=true></a></h4><p>By default, blocking rules are not applied unless they are applied\nexplicitly in <a href=#sec:app-details-page>the App Details page</a>\nfor any application. After enabling this option, all (old and new) rules\nare applied immediately for all applications without explicitly enabling\nblocking for an application.<div class=seealso-inline><p><em>Смотрите также: <span><a href=#subsec:faq:what-is-instant-component-blocking>FAQ: What is\ninstant component blocking?</a></span></em></div></section><section id=importexport-blocking-rules class=level4 data-number=2.6.8.2><h4 data-number=2.6.8.2><span class=header-section-number>2.6.8.2</span> Import/Export Blocking\nRules<a href=#importexport-blocking-rules class=anchor aria-hidden=true></a></h4><p>It is possible to import or export blocking rules within App Manager\nfor all applications. The types of rules (components, app ops or\npermissions) that should be imported or exported can also be selected.\nIt is also possible to import blocking rules from <a href=https://github.com/lihenggui/blocker>Blocker</a> and <a href=https://github.com/tuyafeng/Watt>Watt</a>. If it is necessary to\nexport blocking rules for a single application, the corresponding <a href=#sec:app-details-page>App Details page</a> can be used to export\nrules, or for multiple apps, <a href=#subsec:batch-operations>batch\noperations</a> can be used.<div class=seealso-inline><p><em>Смотрите также: <span><a href=#sec:rules-specification>Rules\nSpecification</a></span></em></div><section id=export class=level5 data-number=2.6.8.2.1><h5 data-number=2.6.8.2.1><span class=header-section-number>2.6.8.2.1</span> Export<a href=#export class=anchor aria-hidden=true></a></h5><p>Export blocking rules for all applications configured within App\nManager. This may include <a href=#subsec:faq:what-are-app-components>app components</a>, app ops\nand permissions based on the options selected in the multi-choice\noptions.</section><section id=import class=level5 data-number=2.6.8.2.2><h5 data-number=2.6.8.2.2><span class=header-section-number>2.6.8.2.2</span> Import<a href=#import class=anchor aria-hidden=true></a></h5><p>Import previously exported blocking rules from App Manager. Similar\nto export, this may include <a href=#subsec:faq:what-are-app-components>app components</a>, app ops\nand permissions based on the options selected in the multi-choice\noptions.</section><section id=par:import-existing-rules class=level5 data-number=2.6.8.2.3><h5 data-number=2.6.8.2.3><span class=header-section-number>2.6.8.2.3</span> Import Existing Rules<a href=#par:import-existing-rules class=anchor aria-hidden=true></a></h5><p>Add components disabled by other applications to App Manager. App\nManager only keeps track of the components disabled within App Manager.\nIf application components are blocked or disabled by other tools or\napplications, this option can be utilised to import them. On clicking\nthis option, App Manager will find the components potentially disabled\nby other applications or tools and list only the name of the\napplications along with the number of matched components. For safety,\nall the applications are unselected by default. They have to be selected\nmanually, and the blocking has to be re-applied via App Manager.<div class=\"amalert danger\"><p><strong><em>Caution.</em></strong><p>Be careful when using this tool as there can be many false positives.\nChoose only the applications that you are certain about.</div></section><section id=import-from-watt class=level5 data-number=2.6.8.2.4><h5 data-number=2.6.8.2.4><span class=header-section-number>2.6.8.2.4</span> Import from Watt<a href=#import-from-watt class=anchor aria-hidden=true></a></h5><p>Import configuration files from <a href=https://github.com/tuyafeng/Watt>Watt</a>, each file containing\nrules for a single package and file name being the name of the package\nwith <code>.xml</code> extension.<div class=\"amalert tip\"><p><strong><em>Tip.</em></strong><p>Location of configuration files in Watt:\n<code>/sdcard/Android/data/com.tuyafeng.watt/files/ifw</code></div></section><section id=import-from-blocker class=level5 data-number=2.6.8.2.5><h5 data-number=2.6.8.2.5><span class=header-section-number>2.6.8.2.5</span> Import from Blocker<a href=#import-from-blocker class=anchor aria-hidden=true></a></h5><p>Import blocking rules from <a href=https://github.com/lihenggui/blocker>Blocker</a>, each file\ncontaining rules for a single package. These files have a\n<code>.json</code> extension.</section></section><section id=remove-all-rules class=level4 data-number=2.6.8.3><h4 data-number=2.6.8.3><span class=header-section-number>2.6.8.3</span> Remove all rules<a href=#remove-all-rules class=anchor aria-hidden=true></a></h4><p>One-click option to remove all rules configured within App Manager.\nThis will enable all blocked components, app ops will be set to their\ndefault values and permissions will be granted.</section></section><section id=subsec:advanced class=level3 data-number=2.6.9><h3 data-number=2.6.9><span class=header-section-number>2.6.9</span>\n<a href=#toc:subsec:advanced>Advanced</a><a href=#subsec:advanced class=anchor aria-hidden=true></a></h3><section id=subsubsec:selected-users class=level4 data-number=2.6.9.1><h4 data-number=2.6.9.1><span class=header-section-number>2.6.9.1</span> Selected Users<a href=#subsubsec:selected-users class=anchor aria-hidden=true></a></h4><p>This option lets you control the users App Manager should operate on.\nApp Manager operates on all users in root or ADB mode by default.</section><section id=subsubsec:saved-apk-name-format class=level4 data-number=2.6.9.2><h4 data-number=2.6.9.2><span class=header-section-number>2.6.9.2</span> Saved APK Name Format<a href=#subsubsec:saved-apk-name-format class=anchor aria-hidden=true></a></h4><p>Defines the format of the APK name to be used while saving it via\nbatch operations or through profiles. App Manager offers some special\nkeywords enclosed inside <code>%</code> (percentage) signs and available\nbelow the input box. These keywords are:<ul class=incremental><li><p><strong><code>label</code>.</strong> Denotes the name or label of\nthe application. This can be localised to the configured language\ndepending on the app.<li><p><strong><code>package_name</code>.</strong> Denotes the name of\nthe package or application ID, the unique identifier that each\napplication has.<li><p><strong><code>version</code>.</strong> Denotes the current\nversion of the application extracted from its manifest.<li><p><strong><code>version_code</code>.</strong> Denotes the current\nversion code of the application that can be used to separate two\nversions of the same application.<li><p><strong><code>min_sdk</code>.</strong> Denotes the minimum SDK\n(i.e. Android framework version) that the application can operate on.\nThis data is only available since Android 7 (Nougat).<li><p><strong><code>target_sdk</code>.</strong> Denotes the SDK that\nthis application targets. The application can operate on higher SDK but\nonly in the compatibility mode.<li><p><strong><code>datetime</code>.</strong> Denotes the time and date\nwhen the APK is exported.</ul></section><section id=subsubsec:import/export-keystore class=level4 data-number=2.6.9.3><h4 data-number=2.6.9.3><span class=header-section-number>2.6.9.3</span> Import/Export Keystore<a href=#subsubsec:import/export-keystore class=anchor aria-hidden=true></a></h4><p>Import or export the KeyStore used by App Manager. This is a Bouncy\nCastle KeyStore with <code>bks</code> extension. Therefore, other\nKeyStore such as Java KeyStore (JKS) or PKCS #12 are not supported. If a\nkey is needed to be imported from such a KeyStore, the relevant options\nshould be should as specified above.</section></section><section id=subsec:device-info class=level3 data-number=2.6.10><h3 data-number=2.6.10><span class=header-section-number>2.6.10</span> <a href=#toc:subsec:device-info>About the device</a><a href=#subsec:device-info class=anchor aria-hidden=true></a></h3><p>Display Android version, security, CPU, GPU, battery, memory, screen,\nlanguages, user info, etc.</section></section><section id=sec:scanner-page class=level2 data-number=2.7><h2 data-number=2.7><span class=header-section-number>2.7</span> <a href=#toc:sec:scanner-page>Scanner Page</a><a href=#sec:scanner-page class=anchor aria-hidden=true></a></h2><p><strong>Scanner page</strong> appears after clicking on the\n<em>scanner</em> button in the <a href=#subsec:app-info-tab>App Info\ntab</a>. External APK files can also be opened for scanning from file\nmanagers, web browsers, etc.<p>It scans for trackers and libraries, and displays the number of\ntrackers and libraries as a summary. It also displays checksums of the\nAPK file as well as the signing certificates. If VirusTotal is\nconfigured in the settings, it also attempts to retrieve reports from\nVirusTotal, or uploads the APK file if it is not in the database. It\nalso display a link to the <a href=https://beta.pithus.org>Pithus</a>\nreport provided the Internet features are enabled.<div class=\"amalert danger\"><p><strong><em>Disclaimer.</em></strong><p>App Manager only scans an application statically without prejudice.\nThe application may provide the options for opting out, or in some\ncases, certain features of the tracker may not be used at all by the\napplication (e.g. F-Droid), or some applications may simply use them as\nplaceholders to prevent the breaking of certain features (e.g. Fennec\nF-Droid). <strong>The intention of the scanner is to give you an idea\nabout what the APK might contain. It should be taken as an initial step\nfor further investigations.</strong></div><p>Clicking on the first item (i.e. number of classes) opens a new page\ncontaining a list of tracker classes for the application. All classes\ncan also be viewed by clicking on the <em>Toggle Class Listing</em>\nmenu. The SMALI or Java version of the class can be viewed by simply\nclicking on an item.<div class=\"amalert tip\"><p><strong><em>Notice.</em></strong><p>Due to various limitations, it is not possible to scan all the\ncomponents of an APK file. This is especially true if an APK is highly\nobfuscated or packed. The scanner also does not check strings (or\nwebsite signatures).</div><p>The second item lists the number of trackers along with their names.\nClicking on the item displays a dialog containing the name of trackers,\nmatched signatures, and the number of classes against each signature.\nSome tracker names may have <span class=\"math inline\"><sup>2</sup></span> prefix which indicates that the\ntrackers are in the <a href=https://etip.exodus-privacy.eu.org>ETIP</a> stand-by list, i.e.,\nwhether they are actual trackers is still being investigated.<p>The third item lists the number of libraries along with their names.\nThe information are mostly taken from <a href=https://gitlab.com/IzzyOnDroid/repo>IzzyOnDroid repo</a>.<div class=seealso-inline><p><em>Смотрите также: <span><a href=#subsec:tracker-classes-versus-tracker-components>FAQ: Tracker\nclasses vs tracker components</a></span></em></div></section><section id=sec:interceptor-page class=level2 data-number=2.8><h2 data-number=2.8><span class=header-section-number>2.8</span> <a href=#toc:sec:interceptor-page>Interceptor Page</a><a href=#sec:interceptor-page class=anchor aria-hidden=true></a></h2><p>Interceptor can be used to intercept communication between\napplications using <code>Intent</code>. It works as a man-in-the-middle\nbetween the source and the destination applications. It offers a\nfeature-complete user interface for editing <code>Intent</code>s.<div class=\"amalert warning\"><p><strong><em>Warning.</em></strong><p>Interceptor only works for <em>implicit</em> intents where the <a href=#subsec:faq:what-are-app-components>app component</a> isn’t\nspecified.</div><div class=seealso><p><em>Смотрите также:</em><ul class=incremental><li><p><a href=https://developer.android.com/guide/components/intents-common>Common\nIntents</a><li><p><a href=https://developer.android.com/guide/components/intents-filters>Intents\nand Intent Filters</a></ul></div><section id=subsec:intent-filters class=level3 data-number=2.8.1><h3 data-number=2.8.1><span class=header-section-number>2.8.1</span>\n<a href=#toc:subsec:intent-filters>Intent Filters</a><a href=#subsec:intent-filters class=anchor aria-hidden=true></a></h3><p>Intent filters are used by the applications to specify the tasks they\nare able to perform or the tasks they are going to perform using other\napplications. For example, when you’re opening a PDF file using a file\nmanager, the file manager will try to find the applications to open the\nPDF with. To find the right applications, the file manager will create\nan Intent with filters such as the MIME type and ask the system to\nretrieve the applications capable of opening this filter. The system\nwill search through the Manifest of the installed applications to match\nthe filter and list the application components that are able to open\nthis filter (in our case the PDF). At this, either the file manager will\nopen the desired application component all by itself or use a system\nprovided option to open it. If multiple application components are able\nto open it and no default is set, you may get a prompt where you have to\nchoose the right application component.<section id=subsubsec:action class=level4 data-number=2.8.1.1><h4 data-number=2.8.1.1><span class=header-section-number>2.8.1.1</span> Action<a href=#subsubsec:action class=anchor aria-hidden=true></a></h4><p>Action specifies the generic action to perform such as\n<code>android.intent.action.VIEW</code>. Applications often declare the\nrelevant actions in the Manifest file to catch the desired Intents. The\naction is particularly useful for broadcast Intent where it plays a\nvital rule. In other cases, it works as an initial way to filter out the\nrelevant application components. Generic actions such as\n<code>android.intent.action.VIEW</code> and\n<code>android.intent.action.SEND</code> are widely used by applications.\nHence, setting this alone may match many application components.</section><section id=subsubsec:data class=level4 data-number=2.8.1.2><h4 data-number=2.8.1.2><span class=header-section-number>2.8.1.2</span> Data<a href=#subsubsec:data class=anchor aria-hidden=true></a></h4><p>Data is originally known as URI (Uniform Resource Identifier) defined\nin <a href=http://www.faqs.org/rfcs/rfc2396.html>RFC 2396</a>. It can\nbe web links, file location, or a special feature called\n<em>content</em>. Contents are an Android feature managed by the <a href=#subsubsec:providers>content providers</a>. Data are often\nassociated with a <a href=#subsubsec:mime-type>MIME type</a>.<p>Examples:<pre><code>http://search.disroot.org/?q=URI%20in%20Android%20scheme&amp;categories=general&amp;language=en-US\nhttps://developer.android.com/reference/android/net/Uri\nfile:///sdcard/AppManager.apk\nmailto:email@example.com\ncontent://io.github.muntashirakon.AppManager.provider/23485af89b08d87e898a90c7e/AppManager.apk</code></pre></section><section id=subsubsec:mime-type class=level4 data-number=2.8.1.3><h4 data-number=2.8.1.3><span class=header-section-number>2.8.1.3</span> MIME Type<a href=#subsubsec:mime-type class=anchor aria-hidden=true></a></h4><p>MIME type of the <a href=#subsubsec:data>data</a>. For example, if\nthe data field is set to <code>file:///sdcard/AppManager.apk</code>, the\nassociated MIME type can be\n<code>application/vnd.android.package-archive</code>.</section><section id=categories class=level4 data-number=2.8.1.4><h4 data-number=2.8.1.4><span class=header-section-number>2.8.1.4</span> Categories<a href=#categories class=anchor aria-hidden=true></a></h4><p>This is similar to <a href=#subsubsec:action>action</a> in the\nsense that it is also used by the system to filter application\ncomponents. This has no further benefits. Unlike <em>action</em>, there\ncan be more than one category. Clicking on the <em>plus</em> button next\nto the title allows adding more categories.</section><section id=flags class=level4 data-number=2.8.1.5><h4 data-number=2.8.1.5><span class=header-section-number>2.8.1.5</span> Flags<a href=#flags class=anchor aria-hidden=true></a></h4><p>Flags are useful in determining how system should behave during the\nlaunch or after the launch of an activity. This should not be touched as\nit requires some technical background. The <em>plus</em> button next to\nthe title can be used to add one or more flags.</section><section id=extras class=level4 data-number=2.8.1.6><h4 data-number=2.8.1.6><span class=header-section-number>2.8.1.6</span> Extras<a href=#extras class=anchor aria-hidden=true></a></h4><p>Extras are the key-value pairs used for supplying additional\ninformation to the destination component. More extras can be added using\nthe <em>plus</em> button next to the title.</section><section id=uri class=level4 data-number=2.8.1.7><h4 data-number=2.8.1.7><span class=header-section-number>2.8.1.7</span> URI<a href=#uri class=anchor aria-hidden=true></a></h4><p>Represents the entire Intent as a URI (e.g. <code>intent://…</code>).\nSome data cannot be converted to string, and as a result, they might not\nappear here.</section></section><section id=subsec:matching-activities class=level3 data-number=2.8.2><h3 data-number=2.8.2><span class=header-section-number>2.8.2</span>\n<a href=#toc:subsec:matching-activities>Matching Activities</a><a href=#subsec:matching-activities class=anchor aria-hidden=true></a></h3><p>List all the activity components that matches the Intent. This is\ninternally determined by the system (rather than App Manager). The\nlaunch button next to each component can be used to launch them directly\nfrom App Manager.</section><section id=subsec:interceptor-reset-to-default class=level3 data-number=2.8.3><h3 data-number=2.8.3><span class=header-section-number>2.8.3</span>\n<a href=#toc:subsec:interceptor-reset-to-default>Reset to\nDefault</a><a href=#subsec:interceptor-reset-to-default class=anchor aria-hidden=true></a></h3><p>Reset the Intent to its initial state.</section><section id=subsec:interceptor-send-edited-intent class=level3 data-number=2.8.4><h3 data-number=2.8.4><span class=header-section-number>2.8.4</span>\n<a href=#toc:subsec:interceptor-send-edited-intent>Send Edited\nIntent</a><a href=#subsec:interceptor-send-edited-intent class=anchor aria-hidden=true></a></h3><p>Resend the edited Intent to the destination application. This may\nopen a list of applications where the desired application is needed to\nbe selected. The result received from the target application will be\nsent to the source application. As a result, the source application will\nnot know if there was a man-in-the-middle.</section></section><section id=sec:shared-preferences-editor-page class=level2 data-number=2.9><h2 data-number=2.9><span class=header-section-number>2.9</span> <a href=#toc:sec:shared-preferences-editor-page>Shared Preferences Editor\nPage</a><a href=#sec:shared-preferences-editor-page class=anchor aria-hidden=true></a></h2><p>Shared preferences can be edited in this page. Clicking any item on\nthe list opens the edit dialog where the item can be edited. The\nfloating action button in the bottom-right corner can be used to add a\nnew item. To save or delete the file, or to discard current changes, the\nrespective options in the menu can be used.</section></section><section id=ch:guides class=level1 data-number=3><h1 data-number=3><span class=header-section-number>3</span> <a href=#toc:ch:guides>Guides</a><a href=#ch:guides class=anchor aria-hidden=true></a></h1><section id=sec:adb-over-tcp class=level2 data-number=3.1><h2 data-number=3.1><span class=header-section-number>3.1</span> <a href=#toc:sec:adb-over-tcp>ADB over TCP</a><a href=#sec:adb-over-tcp class=anchor aria-hidden=true></a></h2><p>Many root-only features can still be used by enabling ADB over TCP.\nTo do that, a PC or Mac is required with Android platform-tools\ninstalled, and an Android phone with developer options & USB\ndebugging enabled.<div class=\"amalert tip\"><p><strong><em>Root users.</em></strong><p>If superuser permission has been granted to App Manager, it can\nalready execute privileged code without any problem. <strong>Therefore,\nroot users do not need to enable ADB over TCP.</strong> But if you\ninsist on using ADB over TCP, you must revoke superuser permission for\nApp Manager.</div><div class=seealso-inline><p><em>Смотрите также: <span><a href=#sec:faq:adb-over-tcp>FAQ: ADB\nover TCP</a></span></em></div><section id=subsec:enable-developer-options class=level3 data-number=3.1.1><h3 data-number=3.1.1><span class=header-section-number>3.1.1</span>\n<a href=#toc:subsec:enable-developer-options>Enable developer\noptions</a><a href=#subsec:enable-developer-options class=anchor aria-hidden=true></a></h3><section id=subsubsec:location-of-developer-options class=level4 data-number=3.1.1.1><h4 data-number=3.1.1.1><span class=header-section-number>3.1.1.1</span> Location of developer\noptions<a href=#subsubsec:location-of-developer-options class=anchor aria-hidden=true></a></h4><p><strong>Developer options</strong> is located in Android\n<strong>Settings</strong>, either directly near the bottom of the page\n(in most ROMs) or under some other settings, such as\n<strong>System</strong> (Google Pixel, Lineage OS, Asus Zenfone 8.0+),\n<strong>Additional Settings</strong> (Xiaomi MIUI, Oppo ColorOS),\n<strong>More Settings</strong> (Vivo FuntouchOS), <strong>More</strong>\n(ZTE Nubia). Unlike other options, it is not visible until explicitly\nenabled by the user. If it is already enabled, you can use the search\nbox in Android <strong>Settings</strong> to locate it as well.</section><section id=how-to-enable-developer-options class=level4 data-number=3.1.1.2><h4 data-number=3.1.1.2><span class=header-section-number>3.1.1.2</span> How to enable developer\noptions<a href=#how-to-enable-developer-options class=anchor aria-hidden=true></a></h4><p>This option is available within Android <strong>Settings</strong> as\nwell but like the location of the developer options, it also differs\nfrom device to device. But in general, you have to find <strong>Build\nnumber</strong> (or <strong>MIUI version</strong> for MIUI ROMs and\n<strong>Software version</strong> for Vivo FuntouchOS,\n<strong>Version</strong> for Oppo ColorOS) and tap it at least 7 (seven)\ntimes until you finally get a message saying <em>You are now a\ndeveloper</em> (you may be prompted to insert pin/password/pattern or\nsolve captchas at this point). In most devices, it is located at the\nbottom of the settings page, inside <strong>About Phone</strong>. But\nthe best way to find it is to use the search box.</section></section><section id=subsec:enable-usb-debugging class=level3 data-number=3.1.2><h3 data-number=3.1.2><span class=header-section-number>3.1.2</span>\n<a href=#toc:subsec:enable-usb-debugging>Enable USB debugging</a><a href=#subsec:enable-usb-debugging class=anchor aria-hidden=true></a></h3><p>After <a href=#subsubsec:location-of-developer-options>locating the\ndeveloper options</a>, enable <strong>Developer option</strong> (if not\nalready). After that, scroll down a bit until you will find the option\n<strong>USB debugging</strong>. Use the toggle button on the right-hand\nside to enable it. At this point, you may get an alert prompt where you\nmay have to click <em>OK</em> to actually enable it. You may also have\nto enable some other options depending on device vendor and ROM. Here\nare some examples:<section id=xiaomi-miui class=level4 data-number=3.1.2.1><h4 data-number=3.1.2.1><span class=header-section-number>3.1.2.1</span> Xiaomi (MIUI)<a href=#xiaomi-miui class=anchor aria-hidden=true></a></h4><p>Enable <strong>USB debugging (Security settings)</strong> as\nwell.</section><section id=huawei-emui class=level4 data-number=3.1.2.2><h4 data-number=3.1.2.2><span class=header-section-number>3.1.2.2</span> Huawei (EMUI)<a href=#huawei-emui class=anchor aria-hidden=true></a></h4><p>Enable <strong>Allow ADB debugging in charge only mode</strong> as\nwell. When connecting to your PC or Mac, you may get a prompt saying\n<strong>Allow access to device data?</strong> in which case click\n<strong>YES, ALLOW ACCESS</strong>.<div class=\"amalert tip\"><p><strong><em>Notice.</em></strong><p>Often the <strong>USB debugging</strong> mode could be disabled\nautomatically by the system. If that’s the case, repeat the above\nprocedure.</div></section><section id=realme class=level4 data-number=3.1.2.3><h4 data-number=3.1.2.3><span class=header-section-number>3.1.2.3</span> Realme<a href=#realme class=anchor aria-hidden=true></a></h4><p>Depending on the device and the version of operating system, you have\nto enable <strong>Disable Permission Monitoring</strong>, or <strong>USB\ndebugging (Security settings)</strong> along with <strong>Install via\nUSB</strong>.</section><section id=oneplus-oxygen-os class=level4 data-number=3.1.2.4><h4 data-number=3.1.2.4><span class=header-section-number>3.1.2.4</span> OnePlus (Oxygen OS)<a href=#oneplus-oxygen-os class=anchor aria-hidden=true></a></h4><p>Depending on the device and the version of operating system, you have\nto enable <strong>Disable Permission Monitoring</strong>.</section><section id=lg class=level4 data-number=3.1.2.5><h4 data-number=3.1.2.5><span class=header-section-number>3.1.2.5</span> LG<a href=#lg class=anchor aria-hidden=true></a></h4><p>Make sure you have <strong>USB tethering</strong> enabled.</section><section id=troubleshooting class=level4 data-number=3.1.2.6><h4 data-number=3.1.2.6><span class=header-section-number>3.1.2.6</span> Troubleshooting<a href=#troubleshooting class=anchor aria-hidden=true></a></h4><p>In case <strong>USB Debugging</strong> is greyed out, you can do the\nfollowing:<ol class=incremental><li><p>Make sure you enabled USB debugging before connecting your phone\nto the PC or Mac via USB cable<li><p>Enable USB tethering after connecting to PC or Mac via USB\ncable<li><p>(For Samsung) If your device is running KNOX, you may have to\nfollow some additional steps. See official documentations or consult\nsupport for further assistant</ol></section></section><section id=subsec:setup-adb-on-pc-or-mac class=level3 data-number=3.1.3><h3 data-number=3.1.3><span class=header-section-number>3.1.3</span>\n<a href=#toc:subsec:setup-adb-on-pc-or-mac>Setup ADB on PC or\nMac</a><a href=#subsec:setup-adb-on-pc-or-mac class=anchor aria-hidden=true></a></h3><p>In order to enable ADB over TCP, you have to set up ADB in your PC or\nMac. <strong><em>Lineage OS users can skip to §<a href=#subsubsec:lineage-os data-reference-type=ref data-reference=subsubsec:lineage-os>3.1.4.1</a>.</em></strong><section id=windows class=level4 data-number=3.1.3.1><h4 data-number=3.1.3.1><span class=header-section-number>3.1.3.1</span> Windows<a href=#windows class=anchor aria-hidden=true></a></h4><ol class=incremental><li><p>Download the latest version of <a href=https://dl.google.com/android/repository/platform-tools-latest-windows.zip>Android\nSDK Platform-Tools</a> for Windows<li><p>Extract the contents of the zip file into any directory (such as\n<code>C:\\</code><span><code>adb</code></span>) and navigate to that\ndirectory using <em>Explorer</em><li><p>Open <strong>Command Prompt</strong>,\n<strong>PowerShell</strong>, or <strong>Terminal</strong> from this\ndirectory. You can do it manually from the start menu or by holding\n<code>Shift</code> and right clicking within the directory in <em>File\nExplorer</em> and then clicking either on <em>Open command window\nhere</em>, or <em>Open PowerShell window here</em> (depending on what\nyou have installed). You can now access ADB by typing <code>adb</code>\n(Command Prompt) or <code>./adb</code> (PowerShell). Do not close this\nwindow yet.</ol><div class=\"amalert tip\"><p><strong><em>Tip.</em></strong><p>If you have <a href=https://learn.microsoft.com/en-us/windows/package-manager/winget/>WinGet</a>\ninstalled, you can install ADB using the following command:<div class=sourceCode id=cb3 data-frame=lines><pre class=\"sourceCode bash\"><code class=\"sourceCode bash\"><span id=cb3-1><a href=#cb3-1 aria-hidden=true tabindex=-1></a><span class=ex>winget</span> install <span class=at>--id</span> Google.PlatformTools</span></code></pre></div><p>After that, you can simply type <code>adb</code> to access ADB.</div></section><section id=macos class=level4 data-number=3.1.3.2><h4 data-number=3.1.3.2><span class=header-section-number>3.1.3.2</span> macOS<a href=#macos class=anchor aria-hidden=true></a></h4><ol class=incremental><li><p>Download the latest version of <a href=https://dl.google.com/android/repository/platform-tools-latest-darwin.zip>Android\nSDK Platform-Tools</a> for macOS<li><p>Extract the contents of the zip file into a directory by clicking\non it. After that, navigate to that directory using <em>Finder</em> and\nlocate <code>adb</code><li><p>Open <strong>Terminal</strong> using <em>Launchpad</em> or\n<em>Spotlight</em> and drag-and-drop <code>adb</code> from the\n<em>Finder</em> window into the <em>Terminal</em> window. Do not close\nthe <em>Terminal</em> window yet</ol><div class=\"amalert tip\"><p><strong><em>Tip.</em></strong><p>If you have <a href=https://brew.sh>Homebrew</a> installed, you can\ninstall ADB using the following command:<div class=sourceCode id=cb4 data-frame=lines><pre class=\"sourceCode bash\"><code class=\"sourceCode bash\"><span id=cb4-1><a href=#cb4-1 aria-hidden=true tabindex=-1></a><span class=ex>brew</span> install <span class=at>--cask</span> android-platform-tools</span></code></pre></div><p>After that, you can simply type <code>adb</code> in any\n<em>Terminal</em> window to access ADB.</div></section><section id=linux class=level4 data-number=3.1.3.3><h4 data-number=3.1.3.3><span class=header-section-number>3.1.3.3</span> Linux<a href=#linux class=anchor aria-hidden=true></a></h4><ol class=incremental><li><p>In your favourite terminal emulator, run the following\ncommand:<div class=sourceCode id=cb5 data-frame=lines data-autogobble><pre class=\"sourceCode bash\"><code class=\"sourceCode bash\"><span id=cb5-1><a href=#cb5-1 aria-hidden=true tabindex=-1></a><span class=bu>cd</span> ~/Downloads <span class=kw>&amp;&amp;</span> <span class=ex>curl</span> <span class=at>-o</span> platform-tools.zip <span class=at>-L</span> <span class=dt>\\</span></span>\n<span id=cb5-2><a href=#cb5-2 aria-hidden=true tabindex=-1></a>https://dl.google.com/android/repository/platform-tools-latest-linux.zip <span class=kw>&amp;&amp;</span> <span class=dt>\\</span></span>\n<span id=cb5-3><a href=#cb5-3 aria-hidden=true tabindex=-1></a><span class=fu>unzip</span> platform-tools.zip <span class=kw>&amp;&amp;</span> <span class=fu>rm</span> platform-tools.zip <span class=kw>&amp;&amp;</span> <span class=bu>cd</span> platform-tools</span></code></pre></div><li><p>If it is successful, you can simply type <code>./adb</code> in\nthe in <em>same</em> terminal emulator window or type\n<code>~/Downloads/platform-tools/adb</code> in any terminal emulator to\naccess ADB.</ol></section></section><section id=subsec:configure-adb-over-tcp class=level3 data-number=3.1.4><h3 data-number=3.1.4><span class=header-section-number>3.1.4</span>\n<a href=#toc:subsec:configure-adb-over-tcp>Configure ADB over\nTCP</a><a href=#subsec:configure-adb-over-tcp class=anchor aria-hidden=true></a></h3><section id=subsubsec:lineage-os class=level4 data-number=3.1.4.1><h4 data-number=3.1.4.1><span class=header-section-number>3.1.4.1</span> Lineage OS 17.1 and\nEarlier<a href=#subsubsec:lineage-os class=anchor aria-hidden=true></a></h4><p>Lineage OS (or its derivatives) users can directly enable ADB over\nTCP using the developer options. To enable that, go to the\n<strong>Developer options</strong>, scroll down until you find\n<strong>ADB over Network</strong>. Now, use the toggle button on the\nright-hand side to enable it and skip to §<a href=#subsubsec:adb-mode-in-app-manager data-reference-type=ref data-reference=subsubsec:adb-mode-in-app-manager>3.1.4.3</a>.<div class=\"amalert warning\"><p><strong><em>Warning.</em></strong><p>You can turn off <strong>ADB over Network</strong> in developer\noptions, but turning off this option will also stop App Manager’s remote\nserver. So, turn it off only when you’re not going to use App Manager in\nADB over TCP mode.</div></section><section id=subsubsec:enable-adb-over-tcp-via-pc-or-mac class=level4 data-number=3.1.4.2><h4 data-number=3.1.4.2><span class=header-section-number>3.1.4.2</span> Enable ADB over TCP via PC\nor Mac<a href=#subsubsec:enable-adb-over-tcp-via-pc-or-mac class=anchor aria-hidden=true></a></h4><p>For other ROMs, you can do this using the command\nprompt/PowerShell/terminal emulator that you’ve opened in the step 3 of\nthe previous section. In this section, I will use <code>adb</code> to\ndenote <code>./adb</code>, <code>adb</code> or any other command that\nyou needed to use based on your platform and software in the previous\nsection.<ol class=incremental><li><p>Connect your device to your PC or Mac using a USB cable. For some\ndevices, it is necessary to turn on <em>File transfer mode (MTP)</em> as\nwell<li><p>To confirm that everything is working as expected, type\n<code>adb devices</code> in your terminal. If your device is connected\nsuccessfully, you will see something like this:<pre><code>List of devices attached\nxxxxxxxx  device</code></pre><div class=\"amalert tip\"><p><strong><em>Notice.</em></strong><p>In some Android phones, an alert prompt will be appeared with a\nmessage <strong>Allow USB Debugging</strong> in which case, check\n<em>Always allow from this computer</em> and click\n<strong>Allow</strong>.</div><li><p>Finally, run the following command to enable ADB over TCP:<div class=sourceCode id=cb7 data-frame=lines data-autogobble><pre class=\"sourceCode bash\"><code class=\"sourceCode bash\"><span id=cb7-1><a href=#cb7-1 aria-hidden=true tabindex=-1></a><span class=ex>adb</span> tcpip 5555</span></code></pre></div></ol><div class=\"amalert danger\"><p><strong><em>Danger.</em></strong><p>You cannot disable developer options or USB debugging after enabling\nADB over TCP.</div></section><section id=subsubsec:adb-mode-in-app-manager class=level4 data-number=3.1.4.3><h4 data-number=3.1.4.3><span class=header-section-number>3.1.4.3</span> Enable ADB mode in App\nManager<a href=#subsubsec:adb-mode-in-app-manager class=anchor aria-hidden=true></a></h4><p>After enabling ADB over TCP, relaunch App Manager. App Manager should\ndetect ADB mode automatically. If it cannot, you can change the mode of\noperation to ADB over TCP in the <a href=#subsec:mode-of-operation>settings page</a>. There, you can also\nverify whether App Manager has correctly detected ADB as indicated by\nthe <em>inferred mode</em>.<div class=\"amalert tip\"><p><strong><em>Notice.</em></strong><p>In some Android devices, the USB cable is needed to be disconnected\nfrom the PC before connecting to App Manager.</div><div class=\"amalert warning\"><p><strong><em>Warning.</em></strong><p>ADB over TCP will be disabled after a reboot. In that case, you have\nto follow §<a href=#subsubsec:enable-adb-over-tcp-via-pc-or-mac data-reference-type=ref data-reference=subsubsec:enable-adb-over-tcp-via-pc-or-mac>3.1.4.2</a>\nagain.</div></section></section></section><section id=sec:wireless-debugging class=level2 data-number=3.2><h2 data-number=3.2><span class=header-section-number>3.2</span> <a href=#toc:sec:wireless-debugging>Wireless Debugging</a><a href=#sec:wireless-debugging class=anchor aria-hidden=true></a></h2><p>If you are running Android 11 or later and capable of connecting to a\nWi-Fi network for, at least, a few moments, Wireless Debugging is the\nrecommended approach as it offers more protection than <a href=#sec:adb-over-tcp>ADB over TCP</a>. It requires two steps:<ol class=incremental><li><p><strong>ADB pairing.</strong> The initial and a bit complex step\nfor a novice user. Fortunately, this step is not required all the\ntime.<li><p><strong>Connecting to ADB.</strong> Needs to be done every time\nyou reboot your phone. App Manager can also automate this step in most\ndevices.</ol><section id=subsec:enable-developer-options-and-usb-debugging class=level3 data-number=3.2.1><h3 data-number=3.2.1><span class=header-section-number>3.2.1</span>\n<a href=#toc:subsec:enable-developer-options-and-usb-debugging>Enable\ndeveloper options and USB Debugging</a><a href=#subsec:enable-developer-options-and-usb-debugging class=anchor aria-hidden=true></a></h3><p>See §<a href=#subsec:enable-developer-options data-reference-type=ref data-reference=subsec:enable-developer-options>3.1.1</a> and §<a href=#subsec:enable-usb-debugging data-reference-type=ref data-reference=subsec:enable-usb-debugging>3.1.2</a>.</section><section id=subsec:enable-wireless-debugging class=level3 data-number=3.2.2><h3 data-number=3.2.2><span class=header-section-number>3.2.2</span>\n<a href=#toc:subsec:enable-wireless-debugging>Enable Wireless\nDebugging</a><a href=#subsec:enable-wireless-debugging class=anchor aria-hidden=true></a></h3><p>In the <strong>Developer options</strong> page, find <strong>Wireless\ndebugging</strong> and click to open it. In the new page, turn on\n<em>Use wireless debugging</em>. Depending on the operating system, you\nmight see a dialog prompt asking you to verify your decision. If that is\nthe case, click <em>Allow</em>.<div class=\"amalert tip\"><p><strong><em>Tip.</em></strong><p>For easy access, you might want to add <strong>Wireless\ndebugging</strong> in the notification tiles section. To do this, find\n<strong>Quick settings developer tiles</strong> in the <strong>Developer\noptions</strong> page and click to open it. In the new window, enable\n<em>Wireless debugging</em>. In case you do not see this setting, you\nmay find a <strong>Wireless debugging</strong> tile in the tile\ncustomization panel.</div></section><section id=subsec:pair-adb-with-app-manager class=level3 data-number=3.2.3><h3 data-number=3.2.3><span class=header-section-number>3.2.3</span>\n<a href=#toc:subsec:pair-adb-with-app-manager>Pair ADB with App\nManager</a><a href=#subsec:pair-adb-with-app-manager class=anchor aria-hidden=true></a></h3><p>In App Manager, navigate to <strong>Settings</strong> > <a href=#subsec:mode-of-operation>Mode of operation</a> and then enable\n<em>Wireless debugging</em>. At this, App Manager will try to establish\na wireless debugging connection automatically which will fail if it has\nnot been paired before. Once it fails, it will ask you to either connect\nor pair ADB. Select <em>pair</em> and a new dialog will appear. It will\nask you to navigate to the <strong>Wireless debugging</strong> page.<div class=\"amalert tip\"><p><strong><em>Note.</em></strong><p>As of v4.0.0, pairing is done using a notification prompt. So, if you\nhave disabled notification for App Manager, you must enable it\nfirst.</div><p>In the <strong>Wireless debugging</strong> page, select <strong>Pair\ndevice with pairing code</strong>. At this, a dialog containing a\npairing code will be displayed. A notification asking for the pairing\ncode will also be visible almost instantly. Insert the pairing code in\nthe input box in the notification and click <em>pair</em>. If the\npairing is successful, App Manager will display notification with the\nmessage “paired”, and the dialog in the <strong>Wireless\ndebugging</strong> page will be dismissed automatically. You will also\nbe able to see App Manager listed as an ADB client in the same page.<div class=\"amalert tip\"><p><strong><em>Notice.</em></strong><p>If you do not use App Manager in ADB mode for a while, App Manager\nmight be removed from the list of clients. In that case, you have to\nrepeat the above procedure.</div></section><section id=subsec:connect-app-manager-to-adb class=level3 data-number=3.2.4><h3 data-number=3.2.4><span class=header-section-number>3.2.4</span>\n<a href=#toc:subsec:connect-app-manager-to-adb>Connect App Manager to\nADB</a><a href=#subsec:connect-app-manager-to-adb class=anchor aria-hidden=true></a></h3><p>App Manager should be able to connect to ADB automatically if the\nmode of operation is set to <em>auto</em>, <em>ADB over TCP</em> or\n<em>Wireless debugging</em>. If this is not the case, select\n<em>Wireless debugging</em> in <strong>Settings</strong> > <a href=#subsec:mode-of-operation>Mode of operation</a>. If App Manager\nfails to detect or connect to ADB, it will ask you to connect or pair\nADB. Select <em>connect</em>.<p>Now, navigate to the <strong>Wireless debugging</strong> page in\nAndroid settings, and note down the port number displayed in the page.\nIn App Manager’s dialog prompt, replace the port number with the one you\nhave noted earlier, and click <em>connect</em>.<p>Once a connection has been established, you can disable\n<strong>Wireless debugging</strong> in Android settings.<div class=\"amalert danger\"><p><strong><em>Caution.</em></strong><p>Never disable <strong>USB Debugging</strong> or any other additional\noptions described in §<a href=#subsec:enable-developer-options-and-usb-debugging data-reference-type=ref data-reference=subsec:enable-developer-options-and-usb-debugging>3.2.1</a>.\nIf you do this, the remote server used by App Manager will be stopped,\nand you may have to start all over again.</div></section></section><section id=sec:backup-restore class=level2 data-number=3.3><h2 data-number=3.3><span class=header-section-number>3.3</span> <a href=#toc:sec:backup-restore>Back up/Restore</a><a href=#sec:backup-restore class=anchor aria-hidden=true></a></h2><p>App Manager has a modern, advanced and easy-to-use backup/restore\nsystem implemented from the scratch. This is probably the only app that\nhas the ability to restore not only the app or its data but also\npermissions and rules that you’ve configured within App Manager. You can\nalso choose to back up an app multiple times (with custom names) or for\nall users.<div class=seealso><p><em>Смотрите также:</em><ul class=incremental><li><p><a href=#subsec:1-click-back-up>1-Click Ops: Back\nup</a><li><p><a href=#subsec:1-click-restore>1-Click Ops:\nRestore</a></ul></div><section id=subsec:backup-location class=level3 data-number=3.3.1><h3 data-number=3.3.1><span class=header-section-number>3.3.1</span>\n<a href=#toc:subsec:backup-location>Location</a><a href=#subsec:backup-location class=anchor aria-hidden=true></a></h3><p>Back up/restore is a part of <a href=#subsec:batch-operations>batch\noperations</a>. It is also located inside the <a href=#subsubsec:app-info-options-menu>options menu</a> in the <a href=#subsec:app-info-tab>App Info tab</a>. Clicking on\n<strong>Backup/Restore</strong> opens the <strong>Backup\nOptions</strong>. Backups are located at\n<code>/storage/emulated/0/AppManager</code> by default. You can\nconfigure custom backup location in the <a href=#subsubsec:backup-volume>settings page</a> in which case the\nbackups will be located at the <code>AppManager</code> folder in the\nselected volume.<div class=\"amalert tip\"><p><strong><em>Note.</em></strong><p>If one or more selected apps do not have any backup, the\n<strong>Restore</strong> and <strong>Delete Backup</strong> options will\nnot be displayed.</div></section><section id=subsec:backup-restore-backup-options class=level3 data-number=3.3.2><h3 data-number=3.3.2><span class=header-section-number>3.3.2</span>\n<a href=#toc:subsec:backup-restore-backup-options>Backup Options</a><a href=#subsec:backup-restore-backup-options class=anchor aria-hidden=true></a></h3><p>Backup options (internally known as backup flags) let you customise\nthe backups on the fly. However, the customisations will not be\nremembered for the future backups. If you want to customise this dialog,\nuse <a href=#subsubsec:settings-backup-options>Backup Options</a> in\nthe <a href=#sec:settings-page>Settings page</a>.<p>A complete description of the backup options is given below:<ul class=incremental><li><p><strong>APK files.</strong> Whether to back up the APK files.\nThis includes the <em>base APK</em> file along with the\n<code>split APK</code> files if they exist.<li><p><strong>Internal data.</strong> Whether to back up the internal\ndata directories. These directories are located at\n<code>/data/user/&lt;user_id></code> and (for Android N or later)\n<code>/data/user_de/&lt;user_id></code>.<li><p><strong>External data.</strong> Whether to back up data\ndirectories located in the internal memory as well as SD Card (if\nexists). External data directories often contain non-essential app data\nor media files (instead of using the dedicated media folder) and may\nincrease the backup size. However, it might be essential for some apps.\nAlthough it isn’t checked by default (as it might dramatically increase\nthe size of the backups), you may have to check it in order to ensure a\nsmooth restore of your backups.<div class=\"amalert warning\"><p><strong><em>Caution.</em></strong><p>Internal data folders should always be backed up if you are going to\nback up the external data folders. However, it could be useful to back\nup only the external folders if the app in question downloads a lot of\nassets from the Internet.</div><li><p><strong>OBB and media.</strong> Whether to back up or restore the\nOBB and the media directories located in the external storage or the SD\nCard. This is useful for games and the graphical software which actually\nuse these folders.<li><p><strong>Cache.</strong> Android apps have multiple cache\ndirectories located at every data directories (both internal and\nexternal). There are two types of cache: <strong>cache</strong> and\n<strong>code cache</strong>. Disabling this option excludes both cache\ndirectories from all the data directories. It is generally advised to\nexclude cache directories since most apps do not clear the cache\nregularly and usually handled by the OS itself. Apps such as Telegram\nmay use a very large cache (depending on the storage space) which may\ndramatically increase the backup size. When it is disabled, AM also\nignores the <strong>no_backup</strong> directories.<li><p><strong>Extras.</strong> Backup/restore app permissions, net\npolicy, battery optimization, SSAID, etc., enabled by default. Note\nthat, blocking rules are applied <em>after</em> applying the extras. So,\nif an item is present in both places, it will be overwritten (i.e., the\none from the blocking rules will be used).<li><p><strong>Rules.</strong> This option lets you back up blocking\nrules configured within App Manager. This might come in handy if you\nhave customised permissions or block some components using App Manager\nas they will also be backed up or restored when you enable this\noption.<li><p><strong>Backup Multiple.</strong> Whether this is a multiple\nbackup. By default, backups are saved using their user ID. Enabling this\noption allows you to create additional backups. These backups use the\ncurrent date-time as the default backup name, but you can also specify\ncustom backup name using the input field displayed when you click on the\n<strong>Backup</strong> button.<li><p><strong>Custom users.</strong> Backup or restore for the selected\nusers instead of only the current user. This option is only displayed if\nthe system has more than one user.<li><p><strong>Skip signature checks.</strong> When taking a backup,\nchecksum of every file (as well as the signing certificate(s) of the\nbase APK file) is generated and stored in the <code>checksums.txt</code>\nfile. When you restore the backup, the checksums are generated again and\nare matched with the checksums stored in the said file. Enabling this\noption will disable the signature checks. This option is applied only\nwhen you restore a backup. During backup, the checksums are generated\nregardless of this option.<div class=\"amalert warning\"><p><strong><em>Caution.</em></strong><p>You should always disable this option to ensure that your backups are\nnot modified by any third-party applications. However, this would only\nwork if you enabled encryption.</div></ul><div class=seealso-inline><p><em>Смотрите также: <span><a href=#subsubsec:settings-encryption>Settings:\nEncryption</a></span></em></div></section><section id=subsec:backup-restore-backup class=level3 data-number=3.3.3><h3 data-number=3.3.3><span class=header-section-number>3.3.3</span>\n<a href=#toc:subsec:backup-restore-backup>Backup</a><a href=#subsec:backup-restore-backup class=anchor aria-hidden=true></a></h3><p>Backup respects all the backup options except <strong>Skip signature\nchecks</strong>. If base backups (i.e., backups that don’t have the\n<strong>Backup Multiple</strong> option) already exist, you will get a\nwarning as the backups will be overwritten. If <strong>Backup\nMultiple</strong> is set, you have an option to input the backup name,\nor you can leave it blank to use the current date-time.</section><section id=subsec:backup-restore-restore class=level3 data-number=3.3.4><h3 data-number=3.3.4><span class=header-section-number>3.3.4</span>\n<a href=#toc:subsec:backup-restore-restore>Restore</a><a href=#subsec:backup-restore-restore class=anchor aria-hidden=true></a></h3><p>Restore respects all the backup options and will fail if <strong>APK\nfiles</strong> option is set, but the backup doesn’t contain such\nbackups or in other cases, if the app isn’t installed. When restoring\nbackups for multiple packages, you can only restore the base backups\n(see <a href=#subsec:backup-restore-backup>backup</a> section for an\nexplanation). However, when restoring backups for a single package, you\nhave the option to select which backup to restore. If <strong>All\nusers</strong> option is set, AM will restore the selected backup for\nall users in the latter case but in the former case, it will restore\nbase backups for the respective users.<div class=\"amalert tip\"><p><strong><em>Notice.</em></strong><p>Apps that use storage access framework (SAF), SSAID or Android\nKeyStore works properly only after an immediate restart.</div></section><section id=subsec:backup-restore-delete-backup class=level3 data-number=3.3.5><h3 data-number=3.3.5><span class=header-section-number>3.3.5</span>\n<a href=#toc:subsec:backup-restore-delete-backup>Delete Backup</a><a href=#subsec:backup-restore-delete-backup class=anchor aria-hidden=true></a></h3><p>Delete backup only respects <strong>All users</strong> option and\nwhen it is selected, only the base backups for all users will be deleted\nwith a prompt. When deleting backups for a single package, another\ndialog will be displayed where you can select the backups to delete.</section></section><section id=sec:automating-tasks class=level2 data-number=3.4><h2 data-number=3.4><span class=header-section-number>3.4</span> <a href=#toc:sec:automating-tasks>Automating Tasks</a><a href=#sec:automating-tasks class=anchor aria-hidden=true></a></h2><p>It is possible to trigger profiles configured inside App Manager via\nthird-party applications such as <strong>Automation</strong> or\n<strong>Tasker</strong>. Traditionally, <code>Intent</code>s are used to\ntrigger such operations.<section id=subsec:generating-authorization-key class=level3 data-number=3.4.1><h3 data-number=3.4.1><span class=header-section-number>3.4.1</span>\n<a href=#toc:subsec:generating-authorization-key>Generating\nauthorization key</a><a href=#subsec:generating-authorization-key class=anchor aria-hidden=true></a></h3><p>In order to ensure proper security, an authorization key is required.\nTo generate a authorization key, go to <strong>Settings</strong> page\nand then <strong>Privacy</strong> > <strong>Authorization\nManager</strong>. If an authorization key has not been generated, it\nwill be generated automatically. The key can be regenerated as\nrequired.<div class=\"amalert danger\"><p><strong><em>Caution.</em></strong><p>Regenerating the authorization key can have some side effects such as\ninvalidation of all the previously configured Intents.</div></section><section id=subsec:at:general-configuration class=level3 data-number=3.4.2><h3 data-number=3.4.2><span class=header-section-number>3.4.2</span>\n<a href=#toc:subsec:at:general-configuration>Configuring tasks</a><a href=#subsec:at:general-configuration class=anchor aria-hidden=true></a></h3><p>The activity\n<code>io.github.muntashirakon.AppManager.crypto.auth.AuthFeatureDemultiplexer</code>\nis responsible for handling all the automations. Sending an intent to\nthe activity lets App Manager perform the designated operation by\nredirecting the <code>Intent</code> to the designated activity or\nservice.<section id=required-extras class=level4 data-number=3.4.2.1><h4 data-number=3.4.2.1><span class=header-section-number>3.4.2.1</span> Required extras<a href=#required-extras class=anchor aria-hidden=true></a></h4><p>It has two primary extras required in all conditions. The key names,\ndata types are all follows:<ol class=incremental><li><p><strong><code>auth</code>.</strong> (String value) The\nauthorization key as described in the earlier section.<li><p><strong><code>feature</code>.</strong> (String value) Name of the\nfeature. Supported features are described in the next section.</ol></section></section><section id=subsec:at:features class=level3 data-number=3.4.3><h3 data-number=3.4.3><span class=header-section-number>3.4.3</span>\n<a href=#toc:subsec:at:features>Features</a><a href=#subsec:at:features class=anchor aria-hidden=true></a></h3><p>App Manager current support a single feature, namely\n<code>profile</code>.</section><section id=subsec:triggering-a-profile class=level3 data-number=3.4.4><h3 data-number=3.4.4><span class=header-section-number>3.4.4</span>\n<a href=#toc:subsec:triggering-a-profile>Triggering a profile</a><a href=#subsec:triggering-a-profile class=anchor aria-hidden=true></a></h3><p>In order to trigger a profile, <code>feature</code> must have the\nvalue <code>profile</code>. In addition, the following extras can be\nincluded:<ol class=incremental><li><p><strong><code>prof</code>.</strong> (String value – required) The\nname of the profile as displayed in the <a href=#sec:profiles-page>Profiles page</a>.<li><p><strong><code>state</code>.</strong> (String value – optional)\nState of the profile – currently <code>on</code> or <code>off</code> –\nas specified in the documentation. If this extra is not set, App Manager\nwill display a prompt where a state must be selected. Therefore, for\ncomplete automation, this option should be set.</ol></section></section><section id=sec:net-policy class=level2 data-number=3.5><h2 data-number=3.5><span class=header-section-number>3.5</span> <a href=#toc:sec:net-policy>Net Policy</a><a href=#sec:net-policy class=anchor aria-hidden=true></a></h2><p>Short for <strong>Network policy</strong> or network policies. It is\nusually located in the Android settings under <strong>Mobile data &\nWifi</strong> section in the app info page of an app. Not all policies\nare guaranteed to be included in this page (e.g. Samsung), and not all\nsettings are well-understood due to lack of documentation. App Manager\ncan display all the net policies declared in the <a href=https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/net/NetworkPolicyManager.java>NetworkPolicyManager</a>.\nPolicies unknown to App Manager will have a <em>Unknown</em> prefix\nalong with the policy constant name and number in the hexadecimal\nformat. Unknown policies should be reported to App Manager for\ninclusion.<p>Net policy allows a user to configure certain networking behaviour of\nan app without modifying the ip tables directly and/or running a\nfirewall app. However, the features it offers largely depend on Android\nversion and ROM. A list of known net policies are listed below:<ol class=incremental><li><p><strong>None</strong> or\n<strong><code>POLICY_NONE</code></strong>: (AOSP) No specific network\npolicy is set. System can still assign rules depending on the nature of\nthe app.<li><p><strong>Reject background data on metered networks</strong> or\n<strong><code>POLICY_REJECT_METERED_BACKGROUND</code></strong>: (AOSP)\nReject network usage on metered networks when the application is in\nbackground.<li><p><strong>Allow background data on metered networks even when Data\nSaver is on</strong> or\n<strong><code>POLICY_ALLOW_METERED_BACKGROUND</code></strong>: (AOSP)\nAllow metered network use in the background even when data saving mode\nis enabled.<li><p><strong>Reject cellular data</strong> or\n<strong><code>POLICY_REJECT_CELLULAR</code></strong> (Android 11+) or\n<strong><code>POLICY_REJECT_ON_DATA</code></strong> (up to Android 10):\n(Lineage OS) Reject mobile/cellular data. Signals network unavailable to\nthe configured app as if the mobile data is inactive.<li><p><strong>Reject VPN data</strong> or\n<strong><code>POLICY_REJECT_VPN</code></strong> (Android 11+) or\n<strong><code>POLICY_REJECT_ON_VPN</code></strong> (up to Android 10):\n(Lineage OS) Reject VPN data. Signals network unavailable to the\nconfigured app as if the VPN is inactive.<li><p><strong>Reject Wi-Fi data</strong> or\n<strong><code>POLICY_REJECT_WIFI</code></strong> (Android 11+) or\n<strong><code>POLICY_REJECT_ON_WLAN</code></strong> (up to Android 10):\n(Lineage OS) Reject Wi-Fi data. Signals network unavailable to the\nconfigured app as if the device is not connected to a Wi-Fi\nnetwork.<li><p><strong>Disable network access</strong> or\n<strong><code>POLICY_REJECT_ALL</code></strong> (Android 11+) or\n<strong><code>POLICY_NETWORK_ISOLATED</code></strong> (up to Android\n10): (Lineage OS) Reject network access in all circumstances. This is\nnot the same as enforcing the other three policies above, and is the\nrecommended policy for dodgy apps. If this policy is enforced, there is\nno need to enforce the other policies.<li><p><strong><code>POLICY_ALLOW_METERED_IN_ROAMING</code></strong>:\n(Samsung) Possibly allow metered network use during roaming. Exact\nmeaning is currently unknown.<li><p><strong><code>POLICY_ALLOW_WHITELIST_IN_ROAMING</code></strong>:\n(Samsung) Possibly allow network use during roaming. Exact meaning is\ncurrently unknown.<li><p><strong>Reject data on metered networks</strong> or\n<strong><code>POLICY_REJECT_METERED</code></strong>: (Motorola) Reject\nnetwork usage if it is a metered network.<li><p><strong>Reject background data</strong> or\n<strong><code>POLICY_REJECT_BACKGROUND</code></strong>: (Motorola)\nReject network usage in the background.<li><p><strong>Disable network access</strong> or\n<strong><code>POLICY_REJECT_ALL</code></strong>: (Motorola) Reject\nnetwork access altogether. Like Lineage OS, it blocks internet\nconnections via iptables. But whether it signals the unavailability of\nnetwork to the configured app is not known.</ol><div class=\"amalert tip\"><p><strong><em>Note.</em></strong><p>Corresponding Lineage OS patches are as follows:<ol class=incremental><li><p><a href=https://github.com/LineageOS/android_frameworks_base/commit/a04932bafbbf7d99efd18276152cc2c9c9b2073e>fw/b:\nSquash of app fw restriction commits</a><li><p><a href=https://github.com/LineageOS/android_frameworks_base/commit/02c8c82854348f52afe2199f310f44b5f578b5b8>fw/b:\nAdd support for per app network isolation</a></ol></div></section></section><section id=ch:faq class=level1 data-number=4><h1 data-number=4><span class=header-section-number>4</span> <a href=#toc:ch:faq>Frequently Asked Questions</a><a href=#ch:faq class=anchor aria-hidden=true></a></h1><section id=sec:faq:app-components class=level2 data-number=4.1><h2 data-number=4.1><span class=header-section-number>4.1</span> <a href=#toc:sec:faq:app-components>App Components</a><a href=#sec:faq:app-components class=anchor aria-hidden=true></a></h2><section id=subsec:faq:what-are-app-components class=level3 data-number=4.1.1><h3 data-number=4.1.1><span class=header-section-number>4.1.1</span>\n<a href=#toc:subsec:faq:what-are-app-components>What are the\napplication components?</a><a href=#subsec:faq:what-are-app-components class=anchor aria-hidden=true></a></h3><p>Activities, services, broadcast receivers (or only receivers) and\ncontent providers (or only providers) are jointly called application\ncomponents. More technically, they all inherit the <a href=https://developer.android.com/reference/android/content/pm/ComponentInfo>ComponentInfo</a>\nclass and can be launched via Intent.</section><section id=subsec:faq:how-components-blocked class=level3 data-number=4.1.2><h3 data-number=4.1.2><span class=header-section-number>4.1.2</span>\n<a href=#toc:subsec:faq:how-components-blocked>How are the tracker and\nother components blocked in App Manager? What are its limitations?</a><a href=#subsec:faq:how-components-blocked class=anchor aria-hidden=true></a></h3><p>App Manager typically blocks application components (or tracker\ncomponents) using a method called <a href=https://carteryagemann.com/pages/android-intent-firewall.html>Intent\nFirewall (IFW)</a>, it is superior to other methods such as <em>pm</em>\n(PackageManager), <a href=https://github.com/RikkaApps/Shizuku>Shizuku</a> or any other\nmethod that uses the package manager to enable or disable the\ncomponents. If a component is disabled by the latter methods, the\napplication itself can detect that the component is being blocked and\ncan re-enable it as it has full access to its own components. (Many\ndeceptive applications actually do this in order to keep the tracker\ncomponents unblocked.) On the other hand, IFW is a true firewall and the\napplication cannot detect if its components are being blocked. App\nManager uses the term <em>block</em> rather than <em>disable</em> for\nthis reason.<p>Even IFW has some limitations which are primarily applicable for the\nsystem applications:<ul class=incremental><li><p>The application in question is whitelisted by the system i.e. the\nsystem cannot function properly without these applications and may cause\nrandom crashes. These applications include but not limited to Android\nSystem, System UI, Phone Services. They will continue to work even if\nthey are disabled or blocked.<li><p>Another system application or system process has activated a\nspecific component of the application in question via interprocess\ncommunication (IPC). In this case, the component will be activated\nregardless of blocking status or even if the entire application is\ndisabled. If there is such a system application that is not needed, the\nonly way to prevent it from running is by getting rid of it.</ul></section><section id=subsec:faq:components-blocked-by-others class=level3 data-number=4.1.3><h3 data-number=4.1.3><span class=header-section-number>4.1.3</span>\n<a href=#toc:subsec:faq:components-blocked-by-others>Does app\ncomponents blocked by other tools retained in App Manager?</a><a href=#subsec:faq:components-blocked-by-others class=anchor aria-hidden=true></a></h3><p><strong>No.</strong> But the application components blocked by the\nsystem or any other tools are displayed in the <a href=#subsec:component-tabs>component tabs</a>. These rules can be\nimported from <a href=#par:import-existing-rules>Settings</a>.\nHowever, it is not possible for App Manager to distinguish the\ncomponents blocked by the third-party tools and components blocked by\nthe system. Therefore, the applications listed in the import page should\nbe selected with care.</section><section id=subsec:faq:components-reblocked-in-am class=level3 data-number=4.1.4><h3 data-number=4.1.4><span class=header-section-number>4.1.4</span>\n<a href=#toc:subsec:faq:components-reblocked-in-am>What happens to the\ncomponents blocked by App Manager which were previously blocked by other\ntools?</a><a href=#subsec:faq:components-reblocked-in-am class=anchor aria-hidden=true></a></h3><p><em>App Manager blocks the components again</em> if requested. In\ncase of unblocking, they will be reverted to the default state as\nspecified in the manifest of the application. But if the components were\nblocked by <a href=https://www.myandroidtools.com>MyAndroidTools\n(MAT)</a> with IFW method, they will not be unblocked by App Manager as\nit uses a different format. To fix this issue, the rules have to be\nimported from <a href=#par:import-existing-rules>Settings</a> at\nfirst, in which case MAT’s configurations will be permanently\nremoved.</section><section id=subsec:faq:what-is-instant-component-blocking class=level3 data-number=4.1.5><h3 data-number=4.1.5><span class=header-section-number>4.1.5</span>\n<a href=#toc:subsec:faq:what-is-instant-component-blocking>What is\ninstant component blocking?</a><a href=#subsec:faq:what-is-instant-component-blocking class=anchor aria-hidden=true></a></h3><p>When you block a component in the <a href=#sec:app-details-page>App\nDetails page</a>, the blocking is not applied by default. It is only\napplied when you apply blocking using the <em>Apply rules</em> option in\nthe top-right menu. If you enable <a href=#subsubsec:instant-component-blocking>instant component\nblocking</a>, blocking will be applied as soon as you block a component.\nIf you choose to block tracker components, however, blocking is applied\nautomatically regardless of this setting. You can also remove blocking\nfor an application by simply clicking on <em>Remove rules</em> in the\nsame menu in the <strong>App Details page</strong>. Since the default\nbehaviour gives you more control over applications, it is better to keep\n<em>instant component blocking</em> option disabled.</section><section id=subsec:tracker-classes-versus-tracker-components class=level3 data-number=4.1.6><h3 data-number=4.1.6><span class=header-section-number>4.1.6</span>\n<a href=#toc:subsec:tracker-classes-versus-tracker-components>Tracker\nclasses versus tracker components</a><a href=#subsec:tracker-classes-versus-tracker-components class=anchor aria-hidden=true></a></h3><p>All application components are classes but not all classes are\ncomponents. In fact, only a few of the classes are components. That\nbeing said, <a href=#sec:scanner-page>scanner page</a> displays a list\nof trackers along with the number of classes, not just the components.\nIn all other pages, trackers and tracker components are used\nsynonymously to denote tracker components, i.e. blocking tracker means\nblocking tracker components, not tracker classes.<div class=\"amalert tip\"><p><strong><em>Info.</em></strong><p>Tracker classes that are not components cannot be blocked. They can\nonly be removed by editing the application itself.</div></section></section><section id=sec:faq:adb-over-tcp class=level2 data-number=4.2><h2 data-number=4.2><span class=header-section-number>4.2</span> <a href=#toc:sec:faq:adb-over-tcp>ADB over TCP</a><a href=#sec:faq:adb-over-tcp class=anchor aria-hidden=true></a></h2><section id=subsec:faq:enable-adb-on-every-restart class=level3 data-number=4.2.1><h3 data-number=4.2.1><span class=header-section-number>4.2.1</span>\n<a href=#toc:subsec:faq:enable-adb-on-every-restart>Do I have to\nenable ADB over TCP everytime I restart?</a><a href=#subsec:faq:enable-adb-on-every-restart class=anchor aria-hidden=true></a></h3><p>Unfortunately, yes. This is because the ADB daemon, the process\nresponsible for ADB connection, is also restarted after a reboot, and it\ndoes not re-enable ADB over TCP.</section><section id=subsec:faq:usb-debugging class=level3 data-number=4.2.2><h3 data-number=4.2.2><span class=header-section-number>4.2.2</span>\n<a href=#toc:subsec:faq:usb-debugging>Cannot enable USB debugging.\nWhat to do?</a><a href=#subsec:faq:usb-debugging class=anchor aria-hidden=true></a></h3><p>See §<a href=#subsec:enable-usb-debugging data-reference-type=ref data-reference=subsec:enable-usb-debugging>3.1.2</a> in Раздел <a href=#ch:guides data-reference-type=ref data-reference=ch:guides>3</a>.</section><section id=subsec:faq:block-components-using-adb class=level3 data-number=4.2.3><h3 data-number=4.2.3><span class=header-section-number>4.2.3</span>\n<a href=#toc:subsec:faq:block-components-using-adb>Can I block tracker\nor any other application components using ADB over TCP?</a><a href=#subsec:faq:block-components-using-adb class=anchor aria-hidden=true></a></h3><p>ADB has limited number of <a href=https://github.com/aosp-mirror/platform_frameworks_base/blob/master/packages/Shell/AndroidManifest.xml>permissions</a>\nand controlling application components is not one of them. However, the\ncomponents of a <em>test-only</em> app can be controlled via ADB. If App\nManager detects such an application, it enables the blocking options\nautomatically.</section><section id=subsec:faq:adb-features class=level3 data-number=4.2.4><h3 data-number=4.2.4><span class=header-section-number>4.2.4</span>\n<a href=#toc:subsec:faq:adb-features>Which features can be used in ADB\nmode?</a><a href=#subsec:faq:adb-features class=anchor aria-hidden=true></a></h3><p>Supported features are enabled automatically in the ADB mode.\nSupported features include disabling, force-stopping, clearing\napplication data, granting or revoking app ops and permissions, and so\non. It is also possible to install or uninstall applications without any\nprompt from the system.</section></section><section id=sec:faq:miscellanea class=level2 data-number=4.3><h2 data-number=4.3><span class=header-section-number>4.3</span> <a href=#toc:sec:faq:miscellanea>Miscellanea</a><a href=#sec:faq:miscellanea class=anchor aria-hidden=true></a></h2><section id=subsec:faq:no-root-no-harms class=level3 data-number=4.3.1><h3 data-number=4.3.1><span class=header-section-number>4.3.1</span>\n<a href=#toc:subsec:faq:no-root-no-harms>I don’t use root/ADB. Am I\ncompletely safe from any harms?</a><a href=#subsec:faq:no-root-no-harms class=anchor aria-hidden=true></a></h3><p>Yes. AM cannot modify any system settings without root or ADB.</section><section id=subsec:faq:how-trackers-libs-updated class=level3 data-number=4.3.2><h3 data-number=4.3.2><span class=header-section-number>4.3.2</span>\n<a href=#toc:subsec:faq:how-trackers-libs-updated>How are the trackers\nand libraries are updated?</a><a href=#subsec:faq:how-trackers-libs-updated class=anchor aria-hidden=true></a></h3><p>Trackers and libraries are updated manually before making a new\nrelease.</section><section id=subsec:faq:apks-deleted-after-installed class=level3 data-number=4.3.3><h3 data-number=4.3.3><span class=header-section-number>4.3.3</span>\n<a href=#toc:subsec:faq:apks-deleted-after-installed>Are APKs deleted\nafter installed?</a><a href=#subsec:faq:apks-deleted-after-installed class=anchor aria-hidden=true></a></h3><p>No, APKs aren’t deleted by App Manager after they are installed.</section><section id=subsec:faq:shizuku-support class=level3 data-number=4.3.4><h3 data-number=4.3.4><span class=header-section-number>4.3.4</span>\n<a href=#toc:subsec:faq:shizuku-support>Any plans for Shizuku?</a><a href=#subsec:faq:shizuku-support class=anchor aria-hidden=true></a></h3><p>App Manager’s use of hidden API and privileged code execution is now\nmuch more complex and cannot be integrated with other third party apps\nsuch as <a href=https://shizuku.rikka.app>Shizuku</a>. Here are some\nreasons for not considering Shizuku (which now has Apache 2.0 license)\nfor App Manager:<ol class=incremental><li><p>Shizuku was initially non-free which led me to use a similar\napproach for App Manager to support both root and ADB<li><p>App Manager already supports both ADB and root which in some\ncases is more capable than Shizuku<li><p>Relying on a third-party app for the major functionalities is not\na good design choice<li><p>Integration of Shizuku will increase the complexity of App\nManager.</ol></section><section id=subsec:faq:what-are-bloatware class=level3 data-number=4.3.5><h3 data-number=4.3.5><span class=header-section-number>4.3.5</span>\n<a href=#toc:subsec:faq:what-are-bloatware>What are bloatware and how\nto remove them?</a><a href=#subsec:faq:what-are-bloatware class=anchor aria-hidden=true></a></h3><p>Bloatware are the unnecessary pre-installed apps, usually system\napps. Some of the apps are often used to track users and collect user\ndata which they might sell for profits. Many system apps do not need to\nrequest any permission to access device info, contacts and messaging\ndata, and other usage info, such as your phone usage habits and\neverything you store on your shared storage(s).<p>The bloatware may also include Google apps, Meta apps, and Twitter/X\nwhich can also track users and/or collect user data without consent. You\ncan disable a few permissions from Android settings but be aware that\nAndroid settings hides many permissions a security researcher would call\npotentially <em>dangerous</em> (e.g., internet, sensor).<p>Were the bloatware user apps, they could be easily uninstalled either\nfrom Android settings or AM. Uninstalling system apps is not possible\nwithout privileged permission, but even then, it cannot <em>remove</em>\nthe system apps completely as they are located in the <em>system</em>\npartition which is a read-only partition. If you have root, you can\nremount this partition to manually <em>purge</em> these apps but this\nwill break Over the Air (OTA) updates since data in the system partition\nhas been modified. There are two kind of updates, delta (small-size,\nconsisting of only the changes between two versions) and full updates.\nYou may still be able to apply full updates, but the bloatware will be\ninstalled again, and consequently, you have to delete them all over\nagain.<p>Another solution is to disable these apps either from Android\nsettings or AM, but certain services can still run in the background as\nthey can be started by other system apps using Inter-process\nCommunication (IPC). One possible solution is to disable all bloatware\nuntil the service has finally stopped (after a restart). However, due to\nheavy modifications of the Android frameworks by the vendors, removing\nor disabling certain bloatware may cause the System UI to crash or even\ncause bootloop. From v4.0.0, AM has a new feature called\n<strong>Debloater</strong> which can be used as a starting point to\nmonitor, disable, and remove the bloatware from a proprietary Android\noperating system.<div class=\"amalert warning\"><p><strong><em>Note.</em></strong><p>In most cases, you cannot completely debloat your device. Therefore,\nit is recommended that you use a custom ROM free from bloatware, such as\nGraphene OS, Lineage OS or their derivatives.</div></section></section></section><section id=ch:specifications class=level1 data-number=5><h1 data-number=5><span class=header-section-number>5</span> <a href=#toc:ch:specifications>Specifications</a><a href=#ch:specifications class=anchor aria-hidden=true></a></h1><section id=sec:rules-specification class=level2 data-number=5.1><h2 data-number=5.1><span class=header-section-number>5.1</span> <a href=#toc:sec:rules-specification>Rules Specification</a><a href=#sec:rules-specification class=anchor aria-hidden=true></a></h2><section id=background class=level3 data-number=5.1.1><h3 data-number=5.1.1><span class=header-section-number>5.1.1</span>\n<a href=#toc:background>Background</a><a href=#background class=anchor aria-hidden=true></a></h3><p>AM currently supports blocking activities, broadcast receivers,\ncontent providers, services, app ops and permissions, and in future I\nmay add more blocking options. In order to add more portability, it is\nnecessary to import/export all these data.<p>Maintaining a database should be the best choice when it comes to\nstoring data. For now, several <code>tsv</code> files with each file\nhaving the name of the package and a <code>.tsv</code> extension. The\nfile/database will be queried/processed by the\n<code>RulesStorageManager</code> class. Due to this abstraction, it\nshould be easier to switch to database or encrypted database systems in\nfuture without changing the design of the entire project. Currently, All\nconfiguration files are stored at\n<code>/data/data/io.github.muntashirakon.AppManager/Files/conf</code>.</section><section id=rules-file-format class=level3 data-number=5.1.2><h3 data-number=5.1.2><span class=header-section-number>5.1.2</span>\n<a href=#toc:rules-file-format>Rules File Format</a><a href=#rules-file-format class=anchor aria-hidden=true></a></h3><section id=internal class=level4 data-number=5.1.2.1><h4 data-number=5.1.2.1><span class=header-section-number>5.1.2.1</span> Internal<a href=#internal class=anchor aria-hidden=true></a></h4><p>The format below is used internally within App Manager and is <em>not\ncompatible with the external format.</em><pre><code>    &lt;name&gt; &lt;type&gt; &lt;mode&gt;|&lt;component_status&gt;|&lt;is_granted&gt;</code></pre><p>Here:<ul class=incremental><li><p><code>&lt;name></code> – Component/permission/app op name (in\ncase of app op, it could be string or integer)<li><p><code>&lt;type></code> – One of the <code>ACTIVITY</code>,\n<code>RECEIVER</code>, <code>PROVIDER</code>, <code>SERVICE</code>,\n<code>APP_OP</code>, <code>PERMISSION</code><li><p><code>&lt;mode></code> – (For app ops) The associated <a href=#subsec:mode-constants>mode constant</a><li><p><code>&lt;component_status></code> – (For components)\nComponent status<ul class=incremental><li><p><code>true</code> – Component has been applied (<code>true</code>\nvalue is kept for compatibility)<li><p><code>false</code> – Component hasn’t been applied yet, but will\nbe applied in future (<code>false</code> value is kept for\ncompatibility)<li><p><code>unblocked</code> – Component is scheduled to be\nunblocked</ul><li><p><code>&lt;is_granted></code> – (For permissions) Whether the\npermission is granted or revoked</ul></section><section id=external class=level4 data-number=5.1.2.2><h4 data-number=5.1.2.2><span class=header-section-number>5.1.2.2</span> External<a href=#external class=anchor aria-hidden=true></a></h4><p>External format is used for importing or exporting rules in App\nManager.<pre><code>    &lt;package_name&gt; &lt;component_name&gt; &lt;type&gt; &lt;mode&gt;|&lt;component_status&gt;|&lt;is_granted&gt;</code></pre><p>This the format is essentially the same as above except for the first\nitem which is the name of the package.<div class=\"amalert danger\"><p><strong><em>Caution.</em></strong><p>The exported rules have a different format than the internal one and\nshould not be copied directly to the <strong>conf</strong> folder.</div></section></section></section></section><section id=ch:changelogs class=level1 data-number=6><h1 data-number=6><span class=header-section-number>6</span> <a href=#toc:ch:changelogs>Changelogs</a><a href=#ch:changelogs class=anchor aria-hidden=true></a></h1><section id=sec:v4.0.5-(445) class=level2 data-number=6.1><h2 data-number=6.1><span class=header-section-number>6.1</span> <a href=#toc:sec:v4.0.5-(445)>v4.0.5 (445)</a><a href=#sec:v4.0.5-(445) class=anchor aria-hidden=true></a></h2><ul class=incremental><li><p>Added option to allow installing the existing applications in the\ninstaller page<li><p>Display unsafe bloatware info<li><p>Display vector icon on the splash screen in Android 7.1 and\nearlier<li><p>Enabled “Clear data from uninstalled apps” to no-root users in\n1-click ops page<li><p>Enabled predictive back in Android 14 onwards<li><p>Improved accessibility by updating the content description of the\naction items<li><p>In app info tab, open “Open by default” setting in the “Open\nlinks” dialog<li><p>In debloater page, sort by app label (or app name) rather than\npackage name<li><p>Fixed freezing an app with “Remember for this app” turned\non<li><p>Fixed selecting texts in the list items due to framework\nbugs<li><p>Fixed setting app ops in custom ROMs with MIUI properties\ninjected<li><p>Fixed updating profile modification status when an application is\ndeleted from the list<li><p>Handled common colors and cursor movements in terminal\noutput.</ul></section><section id=sec:v4.0.4-(444) class=level2 data-number=6.2><h2 data-number=6.2><span class=header-section-number>6.2</span> <a href=#toc:sec:v4.0.4-(444)>v4.0.4 (444)</a><a href=#sec:v4.0.4-(444) class=anchor aria-hidden=true></a></h2><ul class=incremental><li><p>Optimized searching and filtering in the main page<li><p>Adopted sentence-case for the titles<li><p>Use the configured state to execute a profile for the simple\nshortcuts<li><p>Prevented crashing while searching throughout the\napplication<li><p>Fixed integer overflow issue in the tar compression.</ul></section><section id=sec:v4.0.3-(443) class=level2 data-number=6.3><h2 data-number=6.3><span class=header-section-number>6.3</span> <a href=#toc:sec:v4.0.3-(443)>v4.0.3 (443)</a><a href=#sec:v4.0.3-(443) class=anchor aria-hidden=true></a></h2><ul class=incremental><li><p>Updated translations<li><p>Improved handling the list items throughout App Manager<li><p>Fixed a regression error in file manager<li><p>Fixed spinners in the App Usage and the System Config\npages.</ul></section><section id=sec:v4.0.2-(442) class=level2 data-number=6.4><h2 data-number=6.4><span class=header-section-number>6.4</span> <a href=#toc:sec:v4.0.2-(442)>v4.0.2 (442)</a><a href=#sec:v4.0.2-(442) class=anchor aria-hidden=true></a></h2><ul class=incremental><li><p>Updated bloatware<li><p>Fixed fetching applications in multi-user environment in no-root\nmode<li><p>Fixed opening <code>app-manager</code> URLs from the web\nbrowsers<li><p>Fixed updating SSAID<li><p>Prevented a crash in Android &lt; 9.0 that occurs due to invalid\napp ops.</ul></section><section id=sec:v4.0.1-(441) class=level2 data-number=6.5><h2 data-number=6.5><span class=header-section-number>6.5</span> <a href=#toc:sec:v4.0.1-(441)>v4.0.1 (441)</a><a href=#sec:v4.0.1-(441) class=anchor aria-hidden=true></a></h2><section id=overlay-management class=level3 data-number=6.5.1><h3 data-number=6.5.1><span class=header-section-number>6.5.1</span>\n<a href=#toc:overlay-management>Overlay management</a><a href=#overlay-management class=anchor aria-hidden=true></a></h3><p>In the App Details page, a new tab “Overlays” is added where per-app\noverlays are displayed. They can also be enabled or disabled using the\ntoggle button. In addition, if the App Details page of an overlay\npackage is opened, a “Overlay” tag will be displayed in the App Info\ntab. Clicking on the tag opens a dialog containing additional info along\nwith a button that allows navigating to the App Details page of the\noverlay target package if it is installed.<section id=known-limitation class=level5 data-number=6.5.1.0.1><h5 data-number=6.5.1.0.1><span class=header-section-number>6.5.1.0.1</span> Known limitation<a href=#known-limitation class=anchor aria-hidden=true></a></h5><p>At present, it only works for root/ADB users in Android 8 (Oreo) and\nlater.</section></section><section id=unfreeze-option-in-activity-shortcuts class=level3 data-number=6.5.2><h3 data-number=6.5.2><span class=header-section-number>6.5.2</span>\n<a href=#toc:unfreeze-option-in-activity-shortcuts>Unfreeze option in\nactivity shortcuts</a><a href=#unfreeze-option-in-activity-shortcuts class=anchor aria-hidden=true></a></h3><p>If the application corresponding to the shortcut being launched is\nfrozen, App Manager will now offer you to unfreeze the app temporarily\nso that the shortcut can be launched. The app will be frozen again once\nthe screen is locked.<section id=known-limitation-1 class=level5 data-number=6.5.2.0.1><h5 data-number=6.5.2.0.1><span class=header-section-number>6.5.2.0.1</span> Known limitation<a href=#known-limitation-1 class=anchor aria-hidden=true></a></h5><p>This may not work on devices without a screen lock or if the screen\nis locked some time after the display goes off.</section></section><section id=market-like-url-support class=level3 data-number=6.5.3><h3 data-number=6.5.3><span class=header-section-number>6.5.3</span>\n<a href=#toc:market-like-url-support><code>market</code>-like URL\nsupport</a><a href=#market-like-url-support class=anchor aria-hidden=true></a></h3><p>Third-party applications can now open the App Details page of any\ninstalled package by invoking an Intent with an URL with the following\nformat:<pre><code>app-manager://details?id=&lt;pkg&gt;&amp;user=&lt;user_id&gt;</code></pre><p>where <code>&lt;pkg></code> stands for package name, and\n<code>&lt;user_id></code> stands for the user ID which is\noptional.</section><section id=updated-color-codes class=level3 data-number=6.5.4><h3 data-number=6.5.4><span class=header-section-number>6.5.4</span>\n<a href=#toc:updated-color-codes>Updated color codes</a><a href=#updated-color-codes class=anchor aria-hidden=true></a></h3><p>In order to improve accessibility, certain color codes have been\nimproved. Visit <a href=app-manager://settings/about/version>Settings\n> About > Version/Changelog</a> for details.</section><section id=others class=level3 data-number=6.5.5><h3 data-number=6.5.5><span class=header-section-number>6.5.5</span>\n<a href=#toc:others>Others</a><a href=#others class=anchor aria-hidden=true></a></h3><ul class=incremental><li><p>Avoided waiting for the remote server to respond when no-root\nmode is set<li><p>Fixed downgrading apps in Android 10 onwards<li><p>Fixed installer issues in the Huawei stock operating\nsystems<li><p>Improved text formatting in the “What’s New” dialog<li><p>In the UI tracker window, fixed clicking on the icon after it is\niconified<li><p>Updated bloatware and suggestions</ul></section></section><section id=sec:v4.0.0-(440) class=level2 data-number=6.6><h2 data-number=6.6><span class=header-section-number>6.6</span> <a href=#toc:sec:v4.0.0-(440)>v4.0.0 (440)</a><a href=#sec:v4.0.0-(440) class=anchor aria-hidden=true></a></h2><p>App Manager v4.0.0 comes with a lot of new features and improvements.\nVisit <a href=app-manager://settings/about/version>Settings > About\n> Version/Changelog</a> for details.<section id=new-logo class=level3 data-number=6.6.1><h3 data-number=6.6.1><span class=header-section-number>6.6.1</span>\n<a href=#toc:new-logo>New logo!</a><a href=#new-logo class=anchor aria-hidden=true></a></h3><p>The new logo is just a cursive “A”. The design is based on the <a href=https://freetengwar.sourceforge.net/>Tengwar Telcontar</a> font\nwhich was created to bring the Tengwar script, originally created by J.\nR. R. Tolkien, to the digital world. The letter has the classic App\nManager color (i.e., #dcaf74) and uses a pure black background instead\nof a shade of grey.</section><section id=android-14-and-15-support class=level3 data-number=6.6.2><h3 data-number=6.6.2><span class=header-section-number>6.6.2</span>\n<a href=#toc:android-14-and-15-support>Android 14 and 15 support</a><a href=#android-14-and-15-support class=anchor aria-hidden=true></a></h3><p>App Manager now targets Android 14 and fully supports Android 15.<section id=known-issue class=level5 data-number=6.6.2.0.1><h5 data-number=6.6.2.0.1><span class=header-section-number>6.6.2.0.1</span> Known issue<a href=#known-issue class=anchor aria-hidden=true></a></h5><p>KeyStore backup/restore is not working in Android 12 and later.</section></section><section id=revamped-debloater class=level3 data-number=6.6.3><h3 data-number=6.6.3><span class=header-section-number>6.6.3</span>\n<a href=#toc:revamped-debloater>Revamped debloater</a><a href=#revamped-debloater class=anchor aria-hidden=true></a></h3><p>Debloating profiles were available as “Presets” in the Profiles page\nwhich has now been replaced with the Debloater page and can be accessed\nfrom the three-dots menu in the Main page. <a href=https://github.com/MuntashirAkon/android-debloat-list>ADL</a> is\na new project that focuses on maintaining a list of bloatware as well as\npotential open source alternatives. Contributions are welcome!</section><section id=introducing-file-manager class=level3 data-number=6.6.4><h3 data-number=6.6.4><span class=header-section-number>6.6.4</span>\n<a href=#toc:introducing-file-manager>Introducing file manager</a><a href=#introducing-file-manager class=anchor aria-hidden=true></a></h3><p>App Manager offers an (almost) fully-featured file manager with basic\nfile operations, such as copy, cut, rename, and delete along with the\nbatch operations. It also offers an extensive “Open with…” dialog to\nopen a file with another app, and a comprehensive file properties\nviewer. Folders can also be added to the list of favorites for quick\naccess. And many more.</section><section id=integrated-code-editor class=level3 data-number=6.6.5><h3 data-number=6.6.5><span class=header-section-number>6.6.5</span>\n<a href=#toc:integrated-code-editor>Integrated code editor</a><a href=#integrated-code-editor class=anchor aria-hidden=true></a></h3><p>Manifest and code viewers have been replaced with this new editor.\nAmong other regular features, it includes proper syntax highlighting and\nadvanced searching options. In addition, files from third-party apps can\nalso be opened for editing.</section><section id=history-of-operations class=level3 data-number=6.6.6><h3 data-number=6.6.6><span class=header-section-number>6.6.6</span>\n<a href=#toc:history-of-operations>History of operations</a><a href=#history-of-operations class=anchor aria-hidden=true></a></h3><p>All 1-click operations, batch operations, and profile invocations are\nnow stored as history. The history items can also be executed from the\nHistory page. To ensure consistency, the profile state, configurations,\npackage list are also stored, and this stored version is executed\ninstead of the actual profile. As a result, this works even if the\nprofile is deleted.</section><section id=per-app-freezing-and-more class=level3 data-number=6.6.7><h3 data-number=6.6.7><span class=header-section-number>6.6.7</span>\n<a href=#toc:per-app-freezing-and-more>Per-app freezing, and\nmore</a><a href=#per-app-freezing-and-more class=anchor aria-hidden=true></a></h3><p>Freeze/unfreeze feature now supports setting per-app freezing method\nwhich is beneficial in certain scenarios, such as when a user want to\nsuspend some apps while using the disable method as the default. In\naddition, an “Advanced suspend” option is added which force-stops an\napplication before suspending it, thus, prevent it’s services from\nrunning in the background.</section><section id=log-viewer-enhancements class=level3 data-number=6.6.8><h3 data-number=6.6.8><span class=header-section-number>6.6.8</span>\n<a href=#toc:log-viewer-enhancements>Log viewer enhancements</a><a href=#log-viewer-enhancements class=anchor aria-hidden=true></a></h3><p>Log viewer now supports enhanced searching and filtering options,\nsuch as keyword- and regular expression-based searching and filtering.\nPlease read the in-app changelog for details. Support for batch\noperations has also been added.</section><section id=launching-non-exported-activities class=level3 data-number=6.6.9><h3 data-number=6.6.9><span class=header-section-number>6.6.9</span>\n<a href=#toc:launching-non-exported-activities>Launching non-exported\nactivities</a><a href=#launching-non-exported-activities class=anchor aria-hidden=true></a></h3><p>App Manager now supports launching non-exported activities in no-root\nand ADB mode. However, in no-root mode,\n<code>android.permission.WRITE_SECURE_SETTINGS</code> permission is\nrequired.</section><section id=new-tags-in-app-info-tab class=level3 data-number=6.6.10><h3 data-number=6.6.10><span class=header-section-number>6.6.10</span> <a href=#toc:new-tags-in-app-info-tab>New tags in App Info tab</a><a href=#new-tags-in-app-info-tab class=anchor aria-hidden=true></a></h3><p>Five new tags are added in the App Info tab. They are: bloatware,\nXposed, sensors disabled, open links, and static shared libs. Clicking\non “bloatware” will display more information regarding the bloatware and\nsuggest alternatives, “Xposed” tag will display dependency information,\n“open links” will display a list of links supported by the application,\nand “static shared libs” will display all version of the application\ninstalled in the system along with an option to uninstall them. The\nlatter is useful for applications, such as Trichrome.<section id=known-issue-1 class=level5 data-number=6.6.10.0.1><h5 data-number=6.6.10.0.1><span class=header-section-number>6.6.10.0.1</span> Known issue<a href=#known-issue-1 class=anchor aria-hidden=true></a></h5><p>“Sensors disabled” only works real-time. That means if the\napplication is not currently active, this tag will always display even\nthough the applications may use sensors while it is running. This is a\nframework limitation and nothing can be done to avoid it\neffectively.</section></section><section id=per-session-installer-options class=level3 data-number=6.6.11><h3 data-number=6.6.11><span class=header-section-number>6.6.11</span> <a href=#toc:per-session-installer-options>Per-session installer\noptions</a><a href=#per-session-installer-options class=anchor aria-hidden=true></a></h3><p>It is not possible to modify installer options during the\ninstallation by clicking on the “settings” button in the installation\ndialog. The installer options will be applied to all the applications\ninstalled in the same session (i.e., the installer queue).</section><section id=advanced-mode-of-operations-adb-enhancements class=level3 data-number=6.6.12><h3 data-number=6.6.12><span class=header-section-number>6.6.12</span> <a href=#toc:advanced-mode-of-operations-adb-enhancements>Advanced mode\nof operations, ADB enhancements, …</a><a href=#advanced-mode-of-operations-adb-enhancements class=anchor aria-hidden=true></a></h3><p>App Manager now supports running its remote server (which is used as\na proxy for running privileged operations) as any supported user (UID).\nThis includes root (0), system (1000), and shell/ADB (2000) through the\ncustom commands. This is also useful for Fire TVs which have disabled\nconnecting to ADB from localhost through socket connection. In addition,\nADB pairing is now done using notifications rather than split screen.\nADB connection speed can also be improved by choosing to run App Manager\nin the background which can be configured in the settings.</section><section id=data-usage-widget-and-more class=level3 data-number=6.6.13><h3 data-number=6.6.13><span class=header-section-number>6.6.13</span> <a href=#toc:data-usage-widget-and-more>Data usage widget, and more</a><a href=#data-usage-widget-and-more class=anchor aria-hidden=true></a></h3><p>Data usage widget display the total data usage for the day, similar\nto the screen time widget which displays the total screen time for the\nday. In addition, existing widgets have been improved.</section><section id=others-1 class=level3 data-number=6.6.14><h3 data-number=6.6.14><span class=header-section-number>6.6.14</span> <a href=#toc:others-1>Others</a><a href=#others-1 class=anchor aria-hidden=true></a></h3><ul class=incremental><li><p>Replaced log viewer, sys config, Terminal, etc. with Labs\npage<li><p>Added an option to disable sensors for each app in the App Info\ntab<li><p>Added an option to perform runtime optimization of applications\nin the 1-click Ops page and in the App Info tab<li><p>Added support for Zstandard compression for\nbackup/restore<li><p>Enabling APK signing now automatically enables zip align\nfeature<li><p>Support exporting application list as CSV or JSON in the batch\noperations<li><p>Added pure black theme support<li><p>Display current activity name (when possible) in the UI Tracker\nwindow<li><p>Added an option to filter apps by user in the Main page<li><p>Display a link to Pithus report in the scanner page if\navailable.</ul></section></section><section id=sec:v3.1.0-(423) class=level2 data-number=6.7><h2 data-number=6.7><span class=header-section-number>6.7</span> <a href=#toc:sec:v3.1.0-(423)>v3.1.0 (423)</a><a href=#sec:v3.1.0-(423) class=anchor aria-hidden=true></a></h2><p>App Manager v3.1.0 comes with a few new features and a lot of\nimprovements. Visit <a href=app-manager://settings/about/version>Settings > About >\nVersion/Changelog</a> for details.<section id=android-13-support class=level3 data-number=6.7.1><h3 data-number=6.7.1><span class=header-section-number>6.7.1</span>\n<a href=#toc:android-13-support>Android 13 support</a><a href=#android-13-support class=anchor aria-hidden=true></a></h3><p>App Manager now targets Android 13 which means most issues in Android\n12 and 13 has been addressed, including SSAID and SAF issues as well as\nmonochrome icons and other theming issues.<section id=known-issue-2 class=level5 data-number=6.7.1.0.1><h5 data-number=6.7.1.0.1><span class=header-section-number>6.7.1.0.1</span> Known issue<a href=#known-issue-2 class=anchor aria-hidden=true></a></h5><p>KeyStore backup/restore not working in Android 12 and later.</section></section><section id=introducing-freezeunfreeze class=level3 data-number=6.7.2><h3 data-number=6.7.2><span class=header-section-number>6.7.2</span>\n<a href=#toc:introducing-freezeunfreeze>Introducing\nfreeze/unfreeze</a><a href=#introducing-freezeunfreeze class=anchor aria-hidden=true></a></h3><p>Enable/disable is replaced with freeze/unfreeze to allow greater\ncontrol on the behaviours of an app. It supports suspend, disable and\nhide functionalities which can be controlled at <a href=app-manager://settings/rules_prefs/freeze_type>Settings >\nRules > Default freezing method</a>. In order to make it easy to\nfreeze or unfreeze an app, shortcuts can also be created from the App\nInfo tab by long clicking on the freeze or unfreeze button.</section><section id=export-app-list class=level3 data-number=6.7.3><h3 data-number=6.7.3><span class=header-section-number>6.7.3</span>\n<a href=#toc:export-app-list>Export app list</a><a href=#export-app-list class=anchor aria-hidden=true></a></h3><p>In the Main page, it is now possible to export the list of apps in\neither XML or Markdown format using batch operations. In the future, the\nXML file may also be imported to App Manager.</section><section id=elliptic-curve-crypography-ecc class=level3 data-number=6.7.4><h3 data-number=6.7.4><span class=header-section-number>6.7.4</span>\n<a href=#toc:elliptic-curve-crypography-ecc>Elliptic Curve Crypography\n(ECC)</a><a href=#elliptic-curve-crypography-ecc class=anchor aria-hidden=true></a></h3><p>App Manager now fully supports encrypting backups using ECC in\naddition to offering AES, RSA and OpenPGP.</section><section id=new-languages class=level3 data-number=6.7.5><h3 data-number=6.7.5><span class=header-section-number>6.7.5</span>\n<a href=#toc:new-languages>New languages</a><a href=#new-languages class=anchor aria-hidden=true></a></h3><p>Two new languages are added: Korean and Romanian.</section><section id=more-list-options class=level3 data-number=6.7.6><h3 data-number=6.7.6><span class=header-section-number>6.7.6</span>\n<a href=#toc:more-list-options>More list options</a><a href=#more-list-options class=anchor aria-hidden=true></a></h3><p>In the main page, more sorting and filtering options are added.\nSorting options include sorting the apps by total size, total data\nusage, launch count, screen time and last usage time. Filtering options\ninclude filtering the apps having at least one item in the Android\nKeyStore, filtering apps with URIs granted via SAF, and filtering apps\nwith SSAID.</section><section id=improved-handling-of-mode-of-operation class=level3 data-number=6.7.7><h3 data-number=6.7.7><span class=header-section-number>6.7.7</span>\n<a href=#toc:improved-handling-of-mode-of-operation>Improved handling\nof mode of operation</a><a href=#improved-handling-of-mode-of-operation class=anchor aria-hidden=true></a></h3><p>Fixed various issues with ADB pairing, handled incomplete USB\ndebugging. Some rooting methods cannot allow interprocess communication\nvia Binder. In those cases, ADB mode is used as a fallback method by\nenabling it automatically if possible.</section><section id=handling-multiple-users class=level3 data-number=6.7.8><h3 data-number=6.7.8><span class=header-section-number>6.7.8</span>\n<a href=#toc:handling-multiple-users>Handling multiple users</a><a href=#handling-multiple-users class=anchor aria-hidden=true></a></h3><p>When possible, App Manager will be able to display apps from work\nprofile in no-root mode in addition to allowing basic operations such as\nlaunching the app or navigating to the system settings. For backups, it\nis now possible to restore backups for other users, but for work\nprofile, some apps may only work properly after re-enabling the work\nprofile. In the installer page, selecting <em>All users</em> will now\ninstall the app for all users instead of only the current user. Finally,\nin the app info tab, current app can be installed in another profile\nusing the <em>Install for…</em> option available in the three-dots menu.\nThis is analogous to the <code>pm install-existing</code> command,\nthereby, making the installation process a lot faster.</section><section id=explorer-enhancements class=level3 data-number=6.7.9><h3 data-number=6.7.9><span class=header-section-number>6.7.9</span>\n<a href=#toc:explorer-enhancements>Explorer enhancements</a><a href=#explorer-enhancements class=anchor aria-hidden=true></a></h3><p>Explorer can now open DEX and JAR files in addition to APK files.\nSeveral sorting options as well as folder options are also added as the\nlist options.</section><section id=new-tag-wx class=level3 data-number=6.7.10><h3 data-number=6.7.10><span class=header-section-number>6.7.10</span> <a href=#toc:new-tag-wx>New tag: WX</a><a href=#new-tag-wx class=anchor aria-hidden=true></a></h3><p>In app info tab, a new tag called WX is added. It is displayed in\nAndroid 10 and later if the application targets Android 9 or earlier. It\nindicates <a href=https://en.wikipedia.org/wiki/W%5EX>W^X</a>\nviolation which allows the app to execute arbitrary executable files\neither by the modification of executables embedded within the app or by\ndownloading them from the Internet.</section><section id=app-ops-management class=level3 data-number=6.7.11><h3 data-number=6.7.11><span class=header-section-number>6.7.11</span> <a href=#toc:app-ops-management>App ops management</a><a href=#app-ops-management class=anchor aria-hidden=true></a></h3><p>App ops are now managed automatically to avoid various app ops\nrelated crashes in various platforms. This will also lessen the amount\nof crashes in an unsupported operating system.</section><section id=batch-uninstallation class=level3 data-number=6.7.12><h3 data-number=6.7.12><span class=header-section-number>6.7.12</span> <a href=#toc:batch-uninstallation>Batch uninstallation</a><a href=#batch-uninstallation class=anchor aria-hidden=true></a></h3><p>In the Main page, enabled batch uninstallation in no-root mode.</section><section id=running-apps class=level3 data-number=6.7.13><h3 data-number=6.7.13><span class=header-section-number>6.7.13</span> <a href=#toc:running-apps>Running apps</a><a href=#running-apps class=anchor aria-hidden=true></a></h3><p>Enabled advanced searching. Searching now matches not only app labels\nbut also package names.</section><section id=interceptor class=level3 data-number=6.7.14><h3 data-number=6.7.14><span class=header-section-number>6.7.14</span> <a href=#toc:interceptor>Interceptor</a><a href=#interceptor class=anchor aria-hidden=true></a></h3><p>Copy the intercepted Intent as am command which can be run from\neither an ADB shell or a terminal using root with the same\neffectiveness.</section><section id=device-specific-changes class=level3 data-number=6.7.15><h3 data-number=6.7.15><span class=header-section-number>6.7.15</span> <a href=#toc:device-specific-changes>Device-specific changes</a><a href=#device-specific-changes class=anchor aria-hidden=true></a></h3><section id=graphene-os class=level5 data-number=6.7.15.0.1><h5 data-number=6.7.15.0.1><span class=header-section-number>6.7.15.0.1</span> Graphene OS<a href=#graphene-os class=anchor aria-hidden=true></a></h5><p>Explicitly handle the Internet permission which is a runtime\npermission in the OS.</section><section id=miui class=level5 data-number=6.7.15.0.2><h5 data-number=6.7.15.0.2><span class=header-section-number>6.7.15.0.2</span> MIUI<a href=#miui class=anchor aria-hidden=true></a></h5><p>Fixed permission denied issues in the installer due to a framework\nissue introduced in MIUI 12.5.</section><section id=motorola class=level5 data-number=6.7.15.0.3><h5 data-number=6.7.15.0.3><span class=header-section-number>6.7.15.0.3</span> Motorola<a href=#motorola class=anchor aria-hidden=true></a></h5><p>Fixed crashes in the Interceptor page due to a framework issue\nintroduced in Android 11.</section></section><section id=others-2 class=level3 data-number=6.7.16><h3 data-number=6.7.16><span class=header-section-number>6.7.16</span> <a href=#toc:others-2>Others</a><a href=#others-2 class=anchor aria-hidden=true></a></h3><ul class=incremental><li><p>Improved Java-Smali conversion by including all the subclasses\nduring conversion<li><p>Improved scanning performance in the Scanner page<li><p>Improved updating the list of apps in the Main page<li><p>Scan all the available paths to detect systemless-ly installed\nsystem apps<li><p><code>vacuum</code> SQLite database before opening it for viewing\nor editing.</ul></section></section><section id=sec:v3.0.0-(410) class=level2 data-number=6.8><h2 data-number=6.8><span class=header-section-number>6.8</span> <a href=#toc:sec:v3.0.0-(410)>v3.0.0 (410)</a><a href=#sec:v3.0.0-(410) class=anchor aria-hidden=true></a></h2><p>App Manager v3.0.0 comes with a lot of features and improvements. See\n<a href=app-manager://settings/about/version>Settings > About >\nVersion/Changelog</a> to see a more detailed changelog.<section id=material-3-and-more class=level3 data-number=6.8.1><h3 data-number=6.8.1><span class=header-section-number>6.8.1</span>\n<a href=#toc:material-3-and-more>Material 3 and More</a><a href=#material-3-and-more class=anchor aria-hidden=true></a></h3><p>Material 3, somewhat similar to <em>Material You</em>, is a\nsignificant improvement over Material Design 2 with support for dynamic\ncolours in Android 12 and later. In addition, many design changes have\nbeen made in App Manager without any significant changes in the overall\nuser experience.<section id=known-issue-3 class=level5 data-number=6.8.1.0.1><h5 data-number=6.8.1.0.1><span class=header-section-number>6.8.1.0.1</span> Known issue<a href=#known-issue-3 class=anchor aria-hidden=true></a></h5><p>Switches are still based on Material Design 2 which will be fixed in\na future release.</section></section><section id=wireless-debugging class=level3 data-number=6.8.2><h3 data-number=6.8.2><span class=header-section-number>6.8.2</span>\n<a href=#toc:wireless-debugging>Wireless Debugging</a><a href=#wireless-debugging class=anchor aria-hidden=true></a></h3><p>Wireless debugging support has been fully implemented. Head over to\n§<a href=#sec:wireless-debugging data-reference-type=ref data-reference=sec:wireless-debugging>3.2</a> for instructions on how\nto configure wireless debugging.<div class=\"amalert tip\"><p><strong><em>No-root users.</em></strong><p>Due to auto-detection feature, startup time might be large for\nno-root users when the mode of operation is set to <em>auto</em>.\nInstead, no-root users should select <em>no-root</em> instead of\n<em>auto</em>.</div></section><section id=languages class=level3 data-number=6.8.3><h3 data-number=6.8.3><span class=header-section-number>6.8.3</span>\n<a href=#toc:languages>Languages</a><a href=#languages class=anchor aria-hidden=true></a></h3><p>App Manager is fully translated into Indonesian and Italian languages\nand can be enabled in settings. Bengali is removed due to lack of\ntranslators.</section><section id=introducing-app-explorer class=level3 data-number=6.8.4><h3 data-number=6.8.4><span class=header-section-number>6.8.4</span>\n<a href=#toc:introducing-app-explorer>Introducing App Explorer</a><a href=#introducing-app-explorer class=anchor aria-hidden=true></a></h3><p>App Explorer can be used to browse the contents of an application.\nThis includes binary XML files, DEX contents or any other media files.\nDEX contents can only be explored in Android Oreo (Android 8) and later.\nIt’s also possible to convert an <code>.smali</code> file into\n<code>.java</code> for a better understanding of the reversed code. This\nfeature, if not needed, can be disabled in Settings > Enable/disable\nfeatures.</section><section id=import-backups-from-other-applications class=level3 data-number=6.8.5><h3 data-number=6.8.5><span class=header-section-number>6.8.5</span>\n<a href=#toc:import-backups-from-other-applications>Import Backups\nfrom Other Applications</a><a href=#import-backups-from-other-applications class=anchor aria-hidden=true></a></h3><p>It is possible to import backups from discontinued or obsolete\napplications such as Titanium Backup, OAndBackup and Swift Backup\n(version 3.0 to 3.2). Go to Setting > Backup/restore to find this\noption.</section><section id=virustotal class=level3 data-number=6.8.6><h3 data-number=6.8.6><span class=header-section-number>6.8.6</span>\n<a href=#toc:virustotal>VirusTotal</a><a href=#virustotal class=anchor aria-hidden=true></a></h3><p>VirusTotal is a widely used tool to scan files and URLs for viruses.\nIn the scanner page and in the running apps page, an option to scan\nfiles with VirusTotal has been added. But the option is hidden by\ndefault. To enable the option, it is necessary to obtain an API key from\nVirusTotal. Go to Settings > VirusTotal API Key for more\ninformation.<div class=\"amalert warning\"><p><strong><em>Internet feature.</em></strong><p>This is currently the only feature which require an Internet\nconnection. If you wish to use any Internet feature that might also be\nadded in the future, enable <em>Use the Internet</em> in Settings >\nEnable/disable features.</div></section><section id=trigger-profiles-from-the-automation-software class=level3 data-number=6.8.7><h3 data-number=6.8.7><span class=header-section-number>6.8.7</span>\n<a href=#toc:trigger-profiles-from-the-automation-software>Trigger\nProfiles from the Automation Software</a><a href=#trigger-profiles-from-the-automation-software class=anchor aria-hidden=true></a></h3><p>As the implementation of routine operations is being delayed, an\noption to trigger profiles from the external automation software is\nadded. See §<a href=#sec:automating-tasks data-reference-type=ref data-reference=sec:automating-tasks>3.4</a> for instructions on how to\nconfigure profile automation.</section><section id=improved-application-installer class=level3 data-number=6.8.8><h3 data-number=6.8.8><span class=header-section-number>6.8.8</span>\n<a href=#toc:improved-application-installer>Improved Application\nInstaller</a><a href=#improved-application-installer class=anchor aria-hidden=true></a></h3><p>Application installer includes several improvements including the\nability to downgrade applications in no-root mode, installing multiple\napplications at once and blocking trackers after installation. In\nAndroid 12 and later, no-root users can update applications without any\nuser interactions.</section><section id=component-blocking class=level3 data-number=6.8.9><h3 data-number=6.8.9><span class=header-section-number>6.8.9</span>\n<a href=#toc:component-blocking>Component Blocking</a><a href=#component-blocking class=anchor aria-hidden=true></a></h3><p>It is now possible to configure how App Manager should block a\ncomponent. Visit Settings > Rules > Default blocking method for\nmore information. In the components tab, long clicking the block/unblock\nbutton opens a context menu which allows per-component blocking in a\nsimilar manner. ADB users can also block the components of a <em>Test\nonly</em> app.</section><section id=advanced-searching class=level3 data-number=6.8.10><h3 data-number=6.8.10><span class=header-section-number>6.8.10</span> <a href=#toc:advanced-searching>Advanced Searching</a><a href=#advanced-searching class=anchor aria-hidden=true></a></h3><p>In some pages, the search bar supports additional searching which\nincludes searching via prefix, suffix or even regular expressions. In\nthe main page, it is also possible to search for applications using the\nfirst letters of each word, e.g. <em>App Manager</em> can be listed by\nsearching for <em>am</em>.</section><section id=shared-libraries class=level3 data-number=6.8.11><h3 data-number=6.8.11><span class=header-section-number>6.8.11</span> <a href=#toc:shared-libraries>Shared Libraries</a><a href=#shared-libraries class=anchor aria-hidden=true></a></h3><p>Shared libraries tab has received a significant improvements. It can\ndisplay three types of libraries, such as native, jar and APK files.</section><section id=make-the-best-use-of-interceptor class=level3 data-number=6.8.12><h3 data-number=6.8.12><span class=header-section-number>6.8.12</span> <a href=#toc:make-the-best-use-of-interceptor>Make the Best Use of\nInterceptor</a><a href=#make-the-best-use-of-interceptor class=anchor aria-hidden=true></a></h3><p>Activity interceptor can be opened directly from the activities tab\nby long clicking on the launch button, and similarly, activities can be\nlaunched from the activity interceptor page with or without root, for\nany users.<div class=\"amalert tip\"><p><strong><em>Notice.</em></strong><p>Currently, activities opened via root cannot send the results back to\nthe original applications.</div></section><section id=widget-screen-time class=level3 data-number=6.8.13><h3 data-number=6.8.13><span class=header-section-number>6.8.13</span> <a href=#toc:widget-screen-time>Widget: Screen Time</a><a href=#widget-screen-time class=anchor aria-hidden=true></a></h3><p>Screen time widget is quite similar to Digital Wellbeing’s widget by\nthe same name. It displays the total screen time for the day along with\nthe top three apps from all users.</section><section id=widget-clear-cache class=level3 data-number=6.8.14><h3 data-number=6.8.14><span class=header-section-number>6.8.14</span> <a href=#toc:widget-clear-cache>Widget: Clear Cache</a><a href=#widget-clear-cache class=anchor aria-hidden=true></a></h3><p>Clear cache widget can be to clear cache from all the applications\ndirectly from the home screen.</section></section><section id=sec:v2.6.0-(385) class=level2 data-number=6.9><h2 data-number=6.9><span class=header-section-number>6.9</span> <a href=#toc:sec:v2.6.0-(385)>v2.6.0 (385)</a><a href=#sec:v2.6.0-(385) class=anchor aria-hidden=true></a></h2><section id=introducing-backups class=level3 data-number=6.9.1><h3 data-number=6.9.1><span class=header-section-number>6.9.1</span>\n<a href=#toc:introducing-backups>Introducing Backups</a><a href=#introducing-backups class=anchor aria-hidden=true></a></h3><p>Back up/restore feature is now finally out of beta! Read <a href=#sec:backup-restore>the corresponding guide</a> to understand how\nit works.</section><section id=introducing-log-viewer class=level3 data-number=6.9.2><h3 data-number=6.9.2><span class=header-section-number>6.9.2</span>\n<a href=#toc:introducing-log-viewer>Introducing Log Viewer</a><a href=#introducing-log-viewer class=anchor aria-hidden=true></a></h3><p><a href=#subsubsec:log-viewer>Log viewer</a> is essentially a\nfront-end for <code>logcat</code>. It can be used to filter logs by\n<em>tag</em> or <em>pid</em> (process ID), or even by custom filters.\nLog levels AKA verbosity can also be configured. You can also save,\nshare and manage logs.</section><section id=lock-app-manager class=level3 data-number=6.9.3><h3 data-number=6.9.3><span class=header-section-number>6.9.3</span>\n<a href=#toc:lock-app-manager>Lock App Manager</a><a href=#lock-app-manager class=anchor aria-hidden=true></a></h3><p><a href=#subsubsec:screen-lock>Lock App Manager</a> with the screen\nlock configured for your device.</section><section id=extended-modes-for-app-ops class=level3 data-number=6.9.4><h3 data-number=6.9.4><span class=header-section-number>6.9.4</span>\n<a href=#toc:extended-modes-for-app-ops>Extended Modes for App\nOps</a><a href=#extended-modes-for-app-ops class=anchor aria-hidden=true></a></h3><p>You can set any mode for any app ops that your device supports,\neither from the <a href=#subsec:set-mode-for-app-ops-dots>1-click ops\npage</a> or from the <a href=#subsubsec:app-ops>app ops tab</a>.</section><section id=new-batch-ops-add-to-profile class=level3 data-number=6.9.5><h3 data-number=6.9.5><span class=header-section-number>6.9.5</span>\n<a href=#toc:new-batch-ops-add-to-profile>New Batch Ops: Add to\nProfile</a><a href=#new-batch-ops-add-to-profile class=anchor aria-hidden=true></a></h3><p>You can now easily add selected apps to an existing profile using the\nbatch operations.</section><section id=app-info-improved class=level3 data-number=6.9.6><h3 data-number=6.9.6><span class=header-section-number>6.9.6</span>\n<a href=#toc:app-info-improved>App Info: Improved</a><a href=#app-info-improved class=anchor aria-hidden=true></a></h3><p>App info tab now has many options, including the ability to change <a href=#sec:terminologies>SSAID</a>, network policy (i.e. background\nnetwork usage), battery optimization, etc. Most of the tags used in this\ntab are also clickable, and if you click on them, you will be able to\nlook at the current state or configure them right away.</section><section id=advanced-sort-and-filtering-options-in-the-main-page class=level3 data-number=6.9.7><h3 data-number=6.9.7><span class=header-section-number>6.9.7</span>\n<a href=#toc:advanced-sort-and-filtering-options-in-the-main-page>Advanced\nSort and Filtering Options in the Main Page</a><a href=#advanced-sort-and-filtering-options-in-the-main-page class=anchor aria-hidden=true></a></h3><p>Sort and filter options are now replaced by <a href=#subsubsec:main-list-options>List Options</a> which is highly\nconfigurable, including the ability to filter using profiles.</section><section id=about-this-device class=level3 data-number=6.9.8><h3 data-number=6.9.8><span class=header-section-number>6.9.8</span>\n<a href=#toc:about-this-device>About This Device</a><a href=#about-this-device class=anchor aria-hidden=true></a></h3><p>Interested in knowing about your device in just one page? Go to the\nbottom of the <a href=#subsec:device-info>settings page</a>.</section><section id=enabledisable-features class=level3 data-number=6.9.9><h3 data-number=6.9.9><span class=header-section-number>6.9.9</span>\n<a href=#toc:enabledisable-features>Enable/disable Features</a><a href=#enabledisable-features class=anchor aria-hidden=true></a></h3><p>Not interested in all the features that AM offers? You can disable\nsome features in <a href=#subsubsec:enable/disable-features>settings</a>.</section><section id=new-languages-1 class=level3 data-number=6.9.10><h3 data-number=6.9.10><span class=header-section-number>6.9.10</span> <a href=#toc:new-languages-1>New Languages</a><a href=#new-languages-1 class=anchor aria-hidden=true></a></h3><p>AM now has more than 19 languages! New languages include Farsi,\nJapanese and Traditional Chinese.</section><section id=signing-the-apk-files class=level3 data-number=6.9.11><h3 data-number=6.9.11><span class=header-section-number>6.9.11</span> <a href=#toc:signing-the-apk-files>Signing the APK Files</a><a href=#signing-the-apk-files class=anchor aria-hidden=true></a></h3><p>You can now import external signing keys in AM! For security, App\nManager has its own encrypted KeyStore which can also be <a href=#subsubsec:import/export-keystore>imported or exported</a>.</section><section id=new-extension-unapkm class=level3 data-number=6.9.12><h3 data-number=6.9.12><span class=header-section-number>6.9.12</span> <a href=#toc:new-extension-unapkm>New Extension: UnAPKM</a><a href=#new-extension-unapkm class=anchor aria-hidden=true></a></h3><p>Since APKMirror has removed encryption from their APKM files, it’s no\nlonger necessary to decrypt them. As a result, the option to decrypt\nAPKM files has been removed. Instead, this option is now provided by the\nUnAPKM extension which you can grab from <a href=https://f-droid.org/packages/io.github.muntashirakon.unapkm/>F-Droid</a>.\nSo, if you have an encrypted APKM file and have this extension\ninstalled, you can open the file directly in AM.</section></section><section id=sec:v2.5.20-(375) class=level2 data-number=6.10><h2 data-number=6.10><span class=header-section-number>6.10</span>\n<a href=#toc:sec:v2.5.20-(375)>v2.5.20 (375)</a><a href=#sec:v2.5.20-(375) class=anchor aria-hidden=true></a></h2><section id=subsec:introducing-profiles class=level3 data-number=6.10.1><h3 data-number=6.10.1><span class=header-section-number>6.10.1</span> <a href=#toc:subsec:introducing-profiles>Introducing Profiles</a><a href=#subsec:introducing-profiles class=anchor aria-hidden=true></a></h3><p><a href=#sec:profile-page>Profiles</a> finally closes the <a href=https://github.com/MuntashirAkon/AppManager/issues/72>related\nissue</a>. Profiles can be used to execute certain tasks repeatedly\nwithout doing everything manually. A profile can be applied (or invoked)\neither from the <a href=#sec:profiles-page>Profiles page</a> or from\nthe home screen by creating shortcuts. There are also some presets which\nconsist of debloating profiles taken from <a href=https://gitlab.com/W1nst0n/universal-android-debloater>Universal\nAndroid Debloater</a>.<section id=known-limitations class=level5 data-number=6.10.1.0.1><h5 data-number=6.10.1.0.1><span class=header-section-number>6.10.1.0.1</span> Known limitations<a href=#known-limitations class=anchor aria-hidden=true></a></h5><ul class=incremental><li><p>Exporting rules and applying permissions are not currently\nworking.<li><p>Profiles are applied for all users.</ul></section></section><section id=subsec:the-interceptor class=level3 data-number=6.10.2><h3 data-number=6.10.2><span class=header-section-number>6.10.2</span> <a href=#toc:subsec:the-interceptor>The Interceptor</a><a href=#subsec:the-interceptor class=anchor aria-hidden=true></a></h3><p><a href=https://github.com/MuntashirAkon/intent-intercept>Intent\nIntercept</a> works as a man-in-the-middle between source and\ndestination, that is, when you open a file or URL with another app, you\ncan see what is being shared by opening it with Interceptor first. You\ncan also add or modify the intents before sending them to the\ndestination. Additionally, you can double-click on any exportable\nactivities in the Activities tab in the App Details page to open them in\nthe Interceptor to add more configurations.<section id=known-limitation-2 class=level5 data-number=6.10.2.0.1><h5 data-number=6.10.2.0.1><span class=header-section-number>6.10.2.0.1</span> Known limitation<a href=#known-limitation-2 class=anchor aria-hidden=true></a></h5><p>Editing extras is not currently possible.</section></section><section id=subsec:unapkm:-dedrm-the-apkm-files class=level3 data-number=6.10.3><h3 data-number=6.10.3><span class=header-section-number>6.10.3</span> <a href=#toc:subsec:unapkm:-dedrm-the-apkm-files>UnAPKM: DeDRM the APKM\nfiles</a><a href=#subsec:unapkm:-dedrm-the-apkm-files class=anchor aria-hidden=true></a></h3><p>When I released a small tool called <a href=https://f-droid.org/en/packages/io.github.muntashirakon.unapkm>UnAPKM</a>,\nI promised that similar feature will be available in App Manager. I am\nproud to announce that you can open APKM files directly in the App Info\npage or convert them to APKS or install them directly.</section><section id=subsec:multiple-user class=level3 data-number=6.10.4><h3 data-number=6.10.4><span class=header-section-number>6.10.4</span> <a href=#toc:subsec:multiple-user>Multiple user</a><a href=#subsec:multiple-user class=anchor aria-hidden=true></a></h3><p>App manager now supports multiple users! For now, this requires root\nor ADB. But no-root support is also being considered. If you have\nmultiple users enabled and click on an app installed in multiple\nprofiles, an alert prompt will be displayed where you can select the\nuser.</section><section id=vive-la-france class=level3 data-number=6.10.5><h3 data-number=6.10.5><span class=header-section-number>6.10.5</span> <a href=#toc:vive-la-france>Vive la France!</a><a href=#vive-la-france class=anchor aria-hidden=true></a></h3><p>Thanks to the contributors, we have one more addition to the language\nclub: French. You can add more languages or improve existing\ntranslations at <a href=https://hosted.weblate.org/engage/app-manager>Weblate</a>.</section><section id=report-crashes class=level3 data-number=6.10.6><h3 data-number=6.10.6><span class=header-section-number>6.10.6</span> <a href=#toc:report-crashes>Report crashes</a><a href=#report-crashes class=anchor aria-hidden=true></a></h3><p>If App Manager crashes, you can now easily report the crash from the\nnotifications which opens the share options. Crashes are not reported by\nApp Manager, it only redirects you to your favourite Email client.</section><section id=android-11 class=level3 data-number=6.10.7><h3 data-number=6.10.7><span class=header-section-number>6.10.7</span> <a href=#toc:android-11>Android 11</a><a href=#android-11 class=anchor aria-hidden=true></a></h3><p>Added support for Android 11. Not everything may work as expected\nthough.</section><section id=app-installer-improvements class=level3 data-number=6.10.8><h3 data-number=6.10.8><span class=header-section-number>6.10.8</span> <a href=#toc:app-installer-improvements>App Installer Improvements</a><a href=#app-installer-improvements class=anchor aria-hidden=true></a></h3><section id=set-installation-locations class=level4 data-number=6.10.8.1><h4 data-number=6.10.8.1><span class=header-section-number>6.10.8.1</span> Set installation\nlocations<a href=#set-installation-locations class=anchor aria-hidden=true></a></h4><p>In settings page, you can set install locations such as auto\n(default), internal only and prefer external.</section><section id=set-apk-installer class=level4 data-number=6.10.8.2><h4 data-number=6.10.8.2><span class=header-section-number>6.10.8.2</span> Set APK installer<a href=#set-apk-installer class=anchor aria-hidden=true></a></h4><p>In settings page, you can also set default APK installer (root/ADB\nonly) instead of App Manager.</section><section id=multiple-users class=level4 data-number=6.10.8.3><h4 data-number=6.10.8.3><span class=header-section-number>6.10.8.3</span> Multiple users<a href=#multiple-users class=anchor aria-hidden=true></a></h4><p>In settings page, you can allow App Manager to display multiple users\nduring APK installation.</section><section id=signing-apk-files class=level4 data-number=6.10.8.4><h4 data-number=6.10.8.4><span class=header-section-number>6.10.8.4</span> Signing APK files<a href=#signing-apk-files class=anchor aria-hidden=true></a></h4><p>In settings page, you can choose to sign APK files before installing\nthem. You can also select which signature scheme to use in the <em>APK\nsigning</em> option in settings.<section id=known-limitation-3 class=level5 data-number=6.10.8.4.1><h5 data-number=6.10.8.4.1><span class=header-section-number>6.10.8.4.1</span> Known limitation<a href=#known-limitation-3 class=anchor aria-hidden=true></a></h5><p>Currently, only a generic key is used to sign APK files</section></section></section></section><section id=v2.5.17-368 class=level2 data-number=6.11><h2 data-number=6.11><span class=header-section-number>6.11</span>\n<a href=#toc:v2.5.17-368>v2.5.17 (368)</a><a href=#v2.5.17-368 class=anchor aria-hidden=true></a></h2><section id=app-installer class=level3 data-number=6.11.1><h3 data-number=6.11.1><span class=header-section-number>6.11.1</span> <a href=#toc:app-installer>App Installer</a><a href=#app-installer class=anchor aria-hidden=true></a></h3><p>As promised, it is now possible to select splits. AM also provides\nrecommendations based on device configurations. If the app is already\ninstalled, recommendations are provided based on the installed app. It\nis also possible to downgrade to a lower version without data loss if\nthe device has root or ADB. But it should be noted that not all app can\nbe downgraded. Installer is also improved to speed up the installation\nprocess, especially, for root users. If the app has already been\ninstalled and the new (x)apk(s) is newer or older or the same version\nwith a different signature, AM will display a list of changes similar to\n<strong>What’s New</strong> before prompting the user to install the\napp. This is useful if the app has introduced tracker components, new\npermissions, etc.<section id=known-limitations-1 class=level5 data-number=6.11.1.0.1><h5 data-number=6.11.1.0.1><span class=header-section-number>6.11.1.0.1</span> Known Limitations<a href=#known-limitations-1 class=anchor aria-hidden=true></a></h5><ul class=incremental><li><p>Large app can take a long time to fetch app info, and therefore,\nit may take a long time display the installation prompt.<li><p>If the apk is not located in the internal storage, the app has to\nbe cached first which might also take a long time depending on the size\nof the apk.</ul></section></section><section id=scanner-replacement-for-exodus-page class=level3 data-number=6.11.2><h3 data-number=6.11.2><span class=header-section-number>6.11.2</span> <a href=#toc:scanner-replacement-for-exodus-page>Scanner: Replacement for\nExodus Page</a><a href=#scanner-replacement-for-exodus-page class=anchor aria-hidden=true></a></h3><p>Exodus page is now replaced with scanner page. <a href=#sec:scanner-page>Scanner page</a> contains not only a list of\ntrackers but also a list of used libraries. This is just a start. In the\nfuture, this page will contain more in depth analysis of the app.</section><section id=introducing-system-config class=level3 data-number=6.11.3><h3 data-number=6.11.3><span class=header-section-number>6.11.3</span> <a href=#toc:introducing-system-config>Introducing System Config</a><a href=#introducing-system-config class=anchor aria-hidden=true></a></h3><p>System Config lists various system configurations and\nwhitelists/blacklists included in Android by either OEM/vendor, AOSP or\neven some Magisk modules. Root users can access this option from the\noverflow menu in the main page. There isn’t any official documentation\nfor these options therefore it’s difficult to write a complete\ndocumentation for this page. I will gradually add documentations using\nmy own knowledge. However, some functions should be understandable by\ntheir name.</section><section id=more-languages class=level3 data-number=6.11.4><h3 data-number=6.11.4><span class=header-section-number>6.11.4</span> <a href=#toc:more-languages>More Languages</a><a href=#more-languages class=anchor aria-hidden=true></a></h3><p>Thanks to the contributors, AM now has more than 12 languages. New\nlanguages include Bengali, Hindi, Norwegian, Polish, Russian, Simplified\nChinese, Turkish and Ukrainian.</section><section id=app-info-tab class=level3 data-number=6.11.5><h3 data-number=6.11.5><span class=header-section-number>6.11.5</span> <a href=#toc:app-info-tab>App Info Tab</a><a href=#app-info-tab class=anchor aria-hidden=true></a></h3><p>More tags are added in the <a href=#subsec:app-info-tab>app info\ntab</a> such as <strong>KeyStore</strong> (apps with KeyStore items),\n<strong>Systemless app</strong> (apps installed via Magisk),\n<strong>Running</strong> (apps that are running). For external apk, two\nmore options are added namely <strong>Reinstall</strong> and\n<strong>Downgrade</strong>. Now it is possible to share an apk via\nBluetooth. For system apps, it is possible to uninstall updates for\nroot/ADB users. But like the similar option in the system settings, this\noperation will clear all app data. As stated above, exodus has been\nreplaced with scanner.</section><section id=navigation-improvements class=level3 data-number=6.11.6><h3 data-number=6.11.6><span class=header-section-number>6.11.6</span> <a href=#toc:navigation-improvements>Navigation Improvements</a><a href=#navigation-improvements class=anchor aria-hidden=true></a></h3><p>It’s now relatively easy to navigate to various UI components using\nkeyboard. You can use up/down button to navigate between list items and\ntab button to navigate to UI components inside an item.</section><section id=running-apps-page class=level3 data-number=6.11.7><h3 data-number=6.11.7><span class=header-section-number>6.11.7</span> <a href=#toc:running-apps-page>Running Apps Page</a><a href=#running-apps-page class=anchor aria-hidden=true></a></h3><p>It is now possible to sort and filter processes in this tab. Also,\nthe three big buttons are replaced with an easy-to-use three dot menu.\nPreviously the memory usage was wrong which is fixed in this\nversion.</section><section id=built-in-toybox class=level3 data-number=6.11.8><h3 data-number=6.11.8><span class=header-section-number>6.11.8</span> <a href=#toc:built-in-toybox>Built-in Toybox</a><a href=#built-in-toybox class=anchor aria-hidden=true></a></h3><p>Toybox (an alternative to busybox) is bundled with AM. Although\nAndroid has this utility built-in from API 23, toybox is bundled in\norder to prevent buggy implementations and to support API &lt; 23.</section><section id=component-blocker-improvements class=level3 data-number=6.11.9><h3 data-number=6.11.9><span class=header-section-number>6.11.9</span> <a href=#toc:component-blocker-improvements>Component Blocker\nImprovements</a><a href=#component-blocker-improvements class=anchor aria-hidden=true></a></h3><p>Component blocker seemed to be problematic in the previous version,\nespecially when global component blocking is enabled. The issues are\nmostly fixed now.<div class=\"amalert warning\"><p><strong><em>Caution.</em></strong><p>The component blocking mechanism is no longer compatible with v2.5.6\ndue to various security issues. If you have this version, upgrade to\nv2.5.13 or earlier versions first. After that, enable <a href=#subsubsec:instant-component-blocking>global component\nblocking</a> and disable it again.</div></section><section id=improvements-in-the-app-details-page class=level3 data-number=6.11.10><h3 data-number=6.11.10><span class=header-section-number>6.11.10</span> <a href=#toc:improvements-in-the-app-details-page>Improvements in the App\nDetails Page</a><a href=#improvements-in-the-app-details-page class=anchor aria-hidden=true></a></h3><p>Value of various app ops depend on their parent app ops. Therefore,\nwhen you allow/deny an app op, the parent of the app op gets modified.\nThis fixes the issues some users have been complaining regarding some\napp ops that couldn’t be changed.<p>If an app has the target API 23 or less, its permissions cannot be\nmodified using the <code>pm grant …</code> command. Therefore, for such\napps, option to toggle permission has been disabled.<p>The signature tab is improved to support localization. It also\ndisplays multiple checksums for a signature.</section><section id=app-manifest class=level3 data-number=6.11.11><h3 data-number=6.11.11><span class=header-section-number>6.11.11</span> <a href=#toc:app-manifest>App Manifest</a><a href=#app-manifest class=anchor aria-hidden=true></a></h3><p>Manifest no longer crashes if the size of the manifest is too long.\nGenerated manifest are now more accurate than before.</section></section><section id=v2.5.13-348 class=level2 data-number=6.12><h2 data-number=6.12><span class=header-section-number>6.12</span>\n<a href=#toc:v2.5.13-348>v2.5.13 (348)</a><a href=#v2.5.13-348 class=anchor aria-hidden=true></a></h2><section id=bundled-app-split-apk class=level3 data-number=6.12.1><h3 data-number=6.12.1><span class=header-section-number>6.12.1</span> <a href=#toc:bundled-app-split-apk>Bundled App (Split APK)</a><a href=#bundled-app-split-apk class=anchor aria-hidden=true></a></h3><p>Bundled app formats such as <strong>apks</strong> and\n<strong>xapk</strong> are now supported. You can install these apps\nusing the regular installation buttons. For root and adb users, apps are\ninstalled using shell, and for non-root users, the platform default\nmethod is used.<section id=known-limitations-2 class=level5 data-number=6.12.1.0.1><h5 data-number=6.12.1.0.1><span class=header-section-number>6.12.1.0.1</span> Known Limitations<a href=#known-limitations-2 class=anchor aria-hidden=true></a></h5><ul class=incremental><li><p>Currently <em>all</em> splits apks are installed. But this\nbehaviour is going to change in the next release. If you only need a few\nsplits instead of all, extract the <strong>APKS</strong> or\n<strong>XAPK</strong> file, and then, create a new zip file with your\ndesired split apks and replace the <strong>ZIP</strong> extension with\n<strong>APKS</strong>. Now, open it with AM.<li><p>There is no progress dialog to display the installation\nprogress.</ul></section></section><section id=direct-install-support class=level3 data-number=6.12.2><h3 data-number=6.12.2><span class=header-section-number>6.12.2</span> <a href=#toc:direct-install-support>Direct Install Support</a><a href=#direct-install-support class=anchor aria-hidden=true></a></h3><p>You can now install <strong>APK</strong>, <strong>APKS</strong> or\n<strong>XAPK</strong> directly from your favourite browser or file\nmanager. For apps that need updates, a <strong>What’s New</strong>\ndialog is displayed showing the changes in the new version.<section id=known-limitations-3 class=level5 data-number=6.12.2.0.1><h5 data-number=6.12.2.0.1><span class=header-section-number>6.12.2.0.1</span> Known Limitations<a href=#known-limitations-3 class=anchor aria-hidden=true></a></h5><ul class=incremental><li><p>Downgrade is not yet possible.<li><p>There is no progress dialog to display the installation progress.\nIf you cannot interact with the current page, wait until the\ninstallation is finished.</ul></section></section><section id=remove-all-blocking-rules class=level3 data-number=6.12.3><h3 data-number=6.12.3><span class=header-section-number>6.12.3</span> <a href=#toc:remove-all-blocking-rules>Remove All Blocking Rules</a><a href=#remove-all-blocking-rules class=anchor aria-hidden=true></a></h3><p>In the Settings page, a new option is added which can be used to\nremove all blocking rules configured within App Manager.</section><section id=app-ops-1 class=level3 data-number=6.12.4><h3 data-number=6.12.4><span class=header-section-number>6.12.4</span> <a href=#toc:app-ops-1>App\nOps</a><a href=#app-ops-1 class=anchor aria-hidden=true></a></h3><ul class=incremental><li><p>App Ops are now generated using a technique similar to AppOpsX.\nThis should decrease the loading time significantly in the App Ops\ntab.<li><p>In the App Ops tab, a menu item is added which can be used to\nlist only active app ops without including the default app ops. The\npreference is saved in the shared preferences.</ul><section id=known-limitation-4 class=level5 data-number=6.12.4.0.1><h5 data-number=6.12.4.0.1><span class=header-section-number>6.12.4.0.1</span> Known Limitation<a href=#known-limitation-4 class=anchor aria-hidden=true></a></h5><p>Often the App Ops tab may not be responsive. If that’s the case,\nrestart App Manager.</section></section><section id=enhanced-adb-support class=level3 data-number=6.12.5><h3 data-number=6.12.5><span class=header-section-number>6.12.5</span> <a href=#toc:enhanced-adb-support>Enhanced ADB Support</a><a href=#enhanced-adb-support class=anchor aria-hidden=true></a></h3><p>ADB shell commands are now executed using a technique similar to\nAppOpsX (This is the <em>free</em> alternative of AppOps by Rikka.).\nThis should dramatically increase the execution time.<section id=known-limitation-5 class=level5 data-number=6.12.5.0.1><h5 data-number=6.12.5.0.1><span class=header-section-number>6.12.5.0.1</span> Known Limitation<a href=#known-limitation-5 class=anchor aria-hidden=true></a></h5><p>AM can often crash or become not responsive. If that’s the case,\nrestart App Manager.</section></section><section id=filtering-in-main-page class=level3 data-number=6.12.6><h3 data-number=6.12.6><span class=header-section-number>6.12.6</span> <a href=#toc:filtering-in-main-page>Filtering in Main Page</a><a href=#filtering-in-main-page class=anchor aria-hidden=true></a></h3><p>Add an option to filter apps that has at least one activity.</section><section id=apk-backupsharing class=level3 data-number=6.12.7><h3 data-number=6.12.7><span class=header-section-number>6.12.7</span> <a href=#toc:apk-backupsharing>Apk Backup/Sharing</a><a href=#apk-backupsharing class=anchor aria-hidden=true></a></h3><p>Apk files are now saved as <code>app name_version.extension</code>\ninstead of <code>package.name.extension</code>.</section><section id=batch-ops class=level3 data-number=6.12.8><h3 data-number=6.12.8><span class=header-section-number>6.12.8</span> <a href=#toc:batch-ops>Batch Ops</a><a href=#batch-ops class=anchor aria-hidden=true></a></h3><ul class=incremental><li><p>Added a foreground service to run batch operations. The result of\nthe operation is displayed in a notification. If an operation has failed\nfor some packages, clicking on the notification will open a dialog box\nlisting the failed packages. There is also a <strong>Try Again</strong>\nbutton on the bottom which can be used to perform the operation again\nfor the failed packages.<li><p>Replaced Linux <em>kill</em> with\n<strong>force-stop</strong>.</ul></section><section id=translations class=level3 data-number=6.12.9><h3 data-number=6.12.9><span class=header-section-number>6.12.9</span> <a href=#toc:translations>Translations</a><a href=#translations class=anchor aria-hidden=true></a></h3><p>Added German and Portuguese (Brazilian) translations.<section id=known-limitation-6 class=level5 data-number=6.12.9.0.1><h5 data-number=6.12.9.0.1><span class=header-section-number>6.12.9.0.1</span> Known Limitation<a href=#known-limitation-6 class=anchor aria-hidden=true></a></h5><p>Not all translations are verified yet.</section></section><section id=app-data-backup class=level3 data-number=6.12.10><h3 data-number=6.12.10><span class=header-section-number>6.12.10</span> <a href=#toc:app-data-backup>App Data Backup</a><a href=#app-data-backup class=anchor aria-hidden=true></a></h3><p>Install app only for the current user at the time of restoring\nbackups. Support for split apks is also added.<p><em>Data backup feature is now considered unstable. If you encounter\nany problem, please report to me without hesitation.</em></section></section></section><section id=ch:app-ops class=level1 data-number=7><h1 data-number=7><span class=header-section-number>7</span> <a href=#toc:ch:app-ops>App Ops</a><a href=#ch:app-ops class=anchor aria-hidden=true></a></h1><section id=sec:app-ops-background class=level2 data-number=7.1><h2 data-number=7.1><span class=header-section-number>7.1</span> <a href=#toc:sec:app-ops-background>Background</a><a href=#sec:app-ops-background class=anchor aria-hidden=true></a></h2><p><strong>App Ops</strong> (short hand for <strong>Application\nOperations</strong>) are used by Android system (since Android 4.3) to\ncontrol application permissions. The user <em>can</em> control some\npermissions, but only the permissions that are considered dangerous (and\nGoogle thinks knowing your phone number isn’t a dangerous thing). So,\napp ops seems to be the one we need if we want to install apps like\nFacebook and it’s Messenger (the latter literary records everything if\nyou live outside the EU) and still want <em>some</em> privacy and/or\nsecurity. Although certain features of app ops were available in\nSettings and later in hidden settings in older version of Android, it’s\ncompletely hidden in newer versions of Android and is continued to be\nkept hidden. Now, any app with\n<strong>android.Manifest.permission.GET_APP_OPS_STATS</strong>\npermission can get the app ops information for other applications but\nthis permission is hidden from users and can only be enabled using ADB\nor root. Still, the app with this permission cannot grant or revoke\npermissions (actually mode of operation) for apps other than itself\n(with limited capacity, of course). To modify the ops of other app, the\napp needs\n<strong>android.Manifest.permission.UPDATE_APP_OPS_STATS</strong>\npermissions which isn’t accessible via <code>pm</code> command. So, you\ncannot grant it via root or ADB, the permission is only granted to the\nsystem apps. There are very few apps who support disabling permissions\nvia app ops. The best one to my knowledge is <a href=https://github.com/8enet/AppOpsX>AppOpsX</a>. The main (visible)\ndifference between my app (AppManager) and this app is that the latter\nalso provides you the ability to revoke internet permissions (by writing\nip tables). One crucial problem that I faced during the development of\nthe app ops API is the lack of documentation in English language.</section><section id=sec:introduction-to-app-ops class=level2 data-number=7.2><h2 data-number=7.2><span class=header-section-number>7.2</span> <a href=#toc:sec:introduction-to-app-ops>Introduction to App Ops</a><a href=#sec:introduction-to-app-ops class=anchor aria-hidden=true></a></h2><figure id=fig:appops><figure><object data=../images/appops.svg type=image/svg+xml></object></figure><figcaption>Figure 2: How app ops work</figcaption></figure><p>Figure <a href=#fig:appops>1</a> describes the process of changing\nand processing permission. <a href=#sec:appopsmanager>AppOpsManager</a> can be used to manage\npermissions in Settings app. <strong>AppOpsManager</strong> is also\nuseful in determining if a certain permission (or operation) is granted\nto the application. Most of the methods of\n<strong>AppOpsManager</strong> are accessible to the user app but unlike\na system app, it can only be used to check permissions for any app or\nfor the app itself and start or terminating certain operations.\nMoreover, not all operations are actually accessible from this Java\nclass. <strong>AppOpsManager</strong> holds all the necessary constants\nsuch as <a href=#subsec:op-constants><code>OP_*</code></a>,\n<code>OPSTR_*</code>, <a href=#subsec:mode-constants><code>MODE_*</code></a> which describes\noperation code, operation string and mode of operations respectively. It\nalso holds necessary data structures such as <a href=#subsec:package-ops>PackageOps</a> and <strong>OpEntry</strong>.\n<strong>PackageOps</strong> holds <strong>OpEntry</strong> for a\npackage, and <strong>OpEntry</strong>, as the name suggests, describes\neach operation.<p><code>AppOpService</code> is completely hidden from a user\napplication but accessible to the system applications. As it can be seen\nin Figure <a href=#fig:appops>1</a>, this is the class that does the\nactual management stuff. It contains data structures such as\n<strong>Ops</strong> to store basic package info and <strong>Op</strong>\nwhich is similar to <strong>OpEntry</strong> of\n<strong>AppOpsManager</strong>. It also has <strong>Shell</strong> which\nis actually the source code of the <a href=#sec:appops-cli><em>appops</em> command line tool</a>. It writes\nconfigurations to or read configurations from <a href=#sec:appops-xml><code>/data/system/appops.xml</code></a>. System\nservices calls <strong>AppOpsService</strong> to find out what an\napplication is allowed and what is not allowed to perform, and\n<strong>AppOpsService</strong> determines these permissions by parsing\n<code>/data/system/appops.xml</code>. If no custom values are present in\n<em>appops.xml</em>, it returns the default mode available in\n<strong>AppOpsManager</strong>.</section><section id=sec:appopsmanager class=level2 data-number=7.3><h2 data-number=7.3><span class=header-section-number>7.3</span> <a href=#toc:sec:appopsmanager>AppOpsManager</a><a href=#sec:appopsmanager class=anchor aria-hidden=true></a></h2><p><a href=https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/app/AppOpsManager.java>AppOpsManager</a>\nstands for application operations manager. It consists of various\nconstants and classes to modify app operations.<div class=seealso-inline><p><em>Смотрите также: <span><a href=https://developer.android.com/reference/android/app/AppOpsManager>AppOpsManager\ndocumentation</a></span></em></div><section id=subsec:op-constants class=level3 data-number=7.3.1><h3 data-number=7.3.1><span class=header-section-number>7.3.1</span>\n<a href=#toc:subsec:op-constants><code>OP_*</code> Constants</a><a href=#subsec:op-constants class=anchor aria-hidden=true></a></h3><p><code>OP_*</code> are the integer constants starting from\n<code>0</code>. <code>OP_NONE</code> implies that no operations are\nspecified whereas <code>_NUM_OP</code> denotes the number of operations\ndefined in <code>OP_*</code> prefix. While they denote each operation,\nthe operations are not necessarily unique. In fact, there are many\noperations that are actually a single operation denoted by multiple\n<code>OP_*</code> constant (possibly for future use). Vendors may define\ntheir own op based on their requirements. MIUI is one of the vendors who\nare known to do that.<div class=listing><div class=sourceCode id=cb11 data-frame=lines><pre class=\"sourceCode java\"><code class=\"sourceCode java\"><span id=cb11-1><a href=#cb11-1 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=dt>final</span> <span class=dt>int</span> OP_NONE <span class=op>=</span> <span class=op>-</span><span class=dv>1</span><span class=op>;</span></span>\n<span id=cb11-2><a href=#cb11-2 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=dt>final</span> <span class=dt>int</span> OP_COARSE_LOCATION <span class=op>=</span> <span class=dv>0</span><span class=op>;</span></span>\n<span id=cb11-3><a href=#cb11-3 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=dt>final</span> <span class=dt>int</span> OP_FINE_LOCATION <span class=op>=</span> <span class=dv>1</span><span class=op>;</span></span>\n<span id=cb11-4><a href=#cb11-4 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=dt>final</span> <span class=dt>int</span> OP_GPS <span class=op>=</span> <span class=dv>2</span><span class=op>;</span></span>\n<span id=cb11-5><a href=#cb11-5 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=dt>final</span> <span class=dt>int</span> OP_VIBRATE <span class=op>=</span> <span class=dv>3</span><span class=op>;</span></span>\n<span id=cb11-6><a href=#cb11-6 aria-hidden=true tabindex=-1></a><span class=kw>...</span></span>\n<span id=cb11-7><a href=#cb11-7 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=dt>final</span> <span class=dt>int</span> OP_READ_DEVICE_IDENTIFIERS <span class=op>=</span> <span class=dv>89</span><span class=op>;</span></span>\n<span id=cb11-8><a href=#cb11-8 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=dt>final</span> <span class=dt>int</span> OP_ACCESS_MEDIA_LOCATION <span class=op>=</span> <span class=dv>90</span><span class=op>;</span></span>\n<span id=cb11-9><a href=#cb11-9 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=dt>final</span> <span class=dt>int</span> OP_ACTIVATE_PLATFORM_VPN <span class=op>=</span> <span class=dv>91</span><span class=op>;</span></span>\n<span id=cb11-10><a href=#cb11-10 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=dt>final</span> <span class=dt>int</span> _NUM_OP <span class=op>=</span> <span class=dv>92</span><span class=op>;</span></span></code></pre></div></div><p>Whether an operation is unique is defined by\n<code>sOpToSwitch</code>. It maps each operation to another operation or\nto itself (if it’s a unique operation). For instance,\n<code>OP_FINE_LOCATION</code> and <code>OP_GPS</code> are mapped to\n<code>OP_COARSE_LOCATION</code>.<p>Each operation has a private name which are described by\n<code>sOpNames</code>. These names are usually the same names as the\nconstants without the <code>OP_</code> prefix. Some operations have\npublic names as well which are described by <code>sOpToString</code>.\nFor instance, <code>OP_COARSE_LOCATION</code> has the public name\n<strong>android:coarse_location</strong>.<p>As a gradual process of moving permissions to app ops, there are\nalready many permissions that are defined under some operations. These\npermissions are mapped in <code>sOpPerms</code>. For example, the\npermission\n<strong>android.Manifest.permission.ACCESS_COARSE_LOCATION</strong> is\nmapped to <code>OP_COARSE_LOCATION</code>. Some operations may not have\nany associated permissions which have <code>null</code> values.<p>As described in the previous section, operations that are configured\nfor an app are stored at <a href=#sec:appops-xml><code>/data/system/appops.xml</code></a>. If an\noperation is not configured, then whether system will allow that\noperation is determined from <code>sOpDefaultMode</code>. It lists the\n<em>default mode</em> for each operation.</section><section id=subsec:mode-constants class=level3 data-number=7.3.2><h3 data-number=7.3.2><span class=header-section-number>7.3.2</span>\n<a href=#toc:subsec:mode-constants><code>MODE_*</code> Constants</a><a href=#subsec:mode-constants class=anchor aria-hidden=true></a></h3><p><code>MODE_*</code> constants also integer constants starting from\n<code>0</code>. These constants are assigned to each operation\ndescribing whether an app is authorised to perform that operation. These\nmodes usually have associated names such as <strong>allow</strong> for\n<code>MODE_ALLOWED</code>, <strong>ignore</strong> for\n<code>MODE_IGNORED</code>, <strong>deny</strong> for\n<code>MODE_ERRORED</code> (a rather misnomer), <strong>default</strong>\nfor <code>MODE_DEFAULT</code> and <strong>foreground</strong> for\n<code>MODE_FOREGROUND</code>.<ol class=incremental><li><p><strong><code>MODE_ALLOWED</code>.</strong> The app is allowed to\nperform the given operation<li><p><strong><code>MODE_IGNORED</code>.</strong> The app is not\nallowed to perform the given operation, and any attempt to perform the\noperation should <em>silently fail</em>, i.e. it should not cause the\napp to crash<li><p><strong><code>MODE_ERRORED</code>.</strong> The app is not\nallowed to perform the given operation, and this attempt should cause it\nto have a fatal error, typically a\n<code>SecurityException</code><li><p><strong><code>MODE_DEFAULT</code>.</strong> The app should use\nits default security check, specified in\n<code>AppOpsManager</code><li><p><strong><code>MODE_FOREGROUND</code>.</strong> Special mode that\nmeans “allow only when app is in foreground.” This mode was added in\nAndroid 10<li><p><strong><code>MODE_ASK</code>.</strong> This is a custom mode\nused by MIUI whose uses are unknown.</ol></section><section id=subsec:package-ops class=level3 data-number=7.3.3><h3 data-number=7.3.3><span class=header-section-number>7.3.3</span>\n<a href=#toc:subsec:package-ops>PackageOps</a><a href=#subsec:package-ops class=anchor aria-hidden=true></a></h3><p><strong>AppOpsManager.PackageOps</strong> is a data structure to\nstore all the <strong>OpEntry</strong> for a package. In simple terms,\nit stores all the customised operations for a package.<div class=listing><div class=sourceCode id=cb12 data-frame=lines><pre class=\"sourceCode java\"><code class=\"sourceCode java\"><span id=cb12-1><a href=#cb12-1 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=kw>class</span> PackageOps <span class=kw>implements</span> Parcelable <span class=op>{</span></span>\n<span id=cb12-2><a href=#cb12-2 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=bu>String</span> mPackageName<span class=op>;</span></span>\n<span id=cb12-3><a href=#cb12-3 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=dt>int</span> mUid<span class=op>;</span></span>\n<span id=cb12-4><a href=#cb12-4 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=bu>List</span><span class=op>&lt;</span>OpEntry<span class=op>&gt;</span> mEntries<span class=op>;</span></span>\n<span id=cb12-5><a href=#cb12-5 aria-hidden=true tabindex=-1></a>    <span class=kw>...</span></span>\n<span id=cb12-6><a href=#cb12-6 aria-hidden=true tabindex=-1></a><span class=op>}</span></span></code></pre></div></div><p>As can be seen in Listing <a href=#lst:package-ops-class>2</a>, it\nstores all <strong>OpEntry</strong> for a package as well as the\ncorresponding package name and its kernel user ID.</section><section id=subsec:opentry class=level3 data-number=7.3.4><h3 data-number=7.3.4><span class=header-section-number>7.3.4</span>\n<a href=#toc:subsec:opentry>OpEntry</a><a href=#subsec:opentry class=anchor aria-hidden=true></a></h3><p><strong>AppOpsManager.OpEntry</strong> is a data structure that\nstores a single operation for any package.<div class=listing><div class=sourceCode id=cb13 data-frame=lines><pre class=\"sourceCode java\"><code class=\"sourceCode java\"><span id=cb13-1><a href=#cb13-1 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=dt>final</span> <span class=kw>class</span> OpEntry <span class=kw>implements</span> Parcelable <span class=op>{</span></span>\n<span id=cb13-2><a href=#cb13-2 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=dt>int</span> mOp<span class=op>;</span></span>\n<span id=cb13-3><a href=#cb13-3 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=dt>boolean</span> mRunning<span class=op>;</span></span>\n<span id=cb13-4><a href=#cb13-4 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=at>@Mode</span> <span class=dt>int</span> mMode<span class=op>;</span></span>\n<span id=cb13-5><a href=#cb13-5 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=at>@Nullable</span> LongSparseLongArray mAccessTimes<span class=op>;</span></span>\n<span id=cb13-6><a href=#cb13-6 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=at>@Nullable</span> LongSparseLongArray mRejectTimes<span class=op>;</span></span>\n<span id=cb13-7><a href=#cb13-7 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=at>@Nullable</span> LongSparseLongArray mDurations<span class=op>;</span></span>\n<span id=cb13-8><a href=#cb13-8 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=at>@Nullable</span> LongSparseLongArray mProxyUids<span class=op>;</span></span>\n<span id=cb13-9><a href=#cb13-9 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=at>@Nullable</span> LongSparseArray<span class=op>&lt;</span><span class=bu>String</span><span class=op>&gt;</span> mProxyPackageNames<span class=op>;</span></span>\n<span id=cb13-10><a href=#cb13-10 aria-hidden=true tabindex=-1></a>    <span class=kw>...</span></span>\n<span id=cb13-11><a href=#cb13-11 aria-hidden=true tabindex=-1></a><span class=op>}</span></span></code></pre></div></div><p>Here:<ul class=incremental><li><p><code>mOp</code>: Denotes one of the <a href=#subsec:op-constants><code>OP_*</code> constants</a><li><p><code>mRunning</code>: Whether the operation is in progress\n(i.e. the operation has started but not finished yet). Not all\noperations can be started or finished this way<li><p><code>mMOde</code>: One of the <a href=#subsec:mode-constants><code>MODE_*</code> constants</a><li><p><code>mAccessTimes</code>: Stores all the available access\ntimes<li><p><code>mRejectTimes</code>: Stores all the available reject\ntimes<li><p><code>mDurations</code>: All available access durations, checking\nthis with <code>mRunning</code> will tell you for how long the app is\nperforming a certain app operation<li><p><code>mProxyUids</code>: No documentation found<li><p><code>mProxyPackageNames:</code> No documentation found</ul></section><section id=subsec:usage class=level3 data-number=7.3.5><h3 data-number=7.3.5><span class=header-section-number>7.3.5</span>\n<a href=#toc:subsec:usage>Usage</a><a href=#subsec:usage class=anchor aria-hidden=true></a></h3><p>TODO</section></section><section id=sec:appopsservice class=level2 data-number=7.4><h2 data-number=7.4><span class=header-section-number>7.4</span> <a href=#toc:sec:appopsservice>AppOpsService</a><a href=#sec:appopsservice class=anchor aria-hidden=true></a></h2><p>TODO</section><section id=sec:appops-xml class=level2 data-number=7.5><h2 data-number=7.5><span class=header-section-number>7.5</span> <a href=#toc:sec:appops-xml>appops.xml</a><a href=#sec:appops-xml class=anchor aria-hidden=true></a></h2><p>Latest <code>appops.xml</code> has the following format: (This DTD is\nmade by me and by no means perfect, has compatibility issues.)<pre><code>&lt;!DOCTYPE app-ops [\n\n&lt;!ELEMENT app-ops (uid|pkg)*&gt;\n&lt;!ATTLIST app-ops v CDATA #IMPLIED&gt;\n\n&lt;!ELEMENT uid (op)*&gt;\n&lt;!ATTLIST uid n CDATA #REQUIRED&gt;\n\n&lt;!ELEMENT pkg (uid)*&gt;\n&lt;!ATTLIST pkg n CDATA #REQUIRED&gt;\n\n&lt;!ELEMENT uid (op)*&gt;\n&lt;!ATTLIST uid\nn CDATA #REQUIRED\np CDATA #IMPLIED&gt;\n\n&lt;!ELEMENT op (st)*&gt;\n&lt;!ATTLIST op\nn CDATA #REQUIRED\nm CDATA #REQUIRED&gt;\n\n&lt;!ELEMENT st EMPTY&gt;\n&lt;!ATTLIST st\nn CDATA #REQUIRED\nt CDATA #IMPLIED\nr CDATA #IMPLIED\nd CDATA #IMPLIED\npp CDATA #IMPLIED\npu CDATA #IMPLIED&gt;\n\n]&gt;</code></pre><p>The instruction below follows the exact order given above:<ul class=incremental><li><p><code>app-ops</code>: The root element. It can contain any number\nof <code>pkg</code> or package <code>uid</code><ul class=incremental><li><p><code>v</code>: (optional, integer) The version number (default:\n<code>NO_VERSION</code> or <code>-1</code>)</ul><li><p><code>pkg</code>: Stores package info. It can contain any number\nof <code>uid</code><ul class=incremental><li><p><code>n</code>: (required, string) Name of the package</ul><li><p>Package <code>uid</code>: Stores package or packages info<ul class=incremental><li><p><code>n</code>: (required, integer) The user ID</ul><li><p><code>uid</code>: The package user ID. It can contain any number\nof <code>op</code><ul class=incremental><li><p><code>n</code>: (required, integer) The user ID<li><p><code>p</code>: (optional, boolean) Is the app is a\nprivate/system app</ul><li><p><code>op</code>: The operation, can contain <code>st</code> or\nnothing at all<ul class=incremental><li><p><code>n</code>: (required, integer) The op name in integer,\ni.e. AppOpsManager.OP_*<li><p><code>m</code>: (required, integer) The op mode,\ni.e. AppOpsManager.MODE_*</ul><li><p><code>st</code>: State of operation: whether the operation is\naccessed, rejected or running (not available on old versions)<ul class=incremental><li><p><code>n</code>: (required, long) Key containing flags and\nuid<li><p><code>t</code>: (optional, long) Access time (default:\n<code>0</code>)<li><p><code>r</code>: (optional, long) Reject time (default:\n<code>0</code>)<li><p><code>d</code>: (optional, long) Access duration (default:\n<code>0</code>)<li><p><code>pp</code>: (optional, string) Proxy package name<li><p><code>pu</code>: (optional, integer) Proxy package uid</ul></ul><p>This definition can be found at <a href=https://android.googlesource.com/platform/frameworks/base/+/master/services/core/java/com/android/server/appop/AppOpsService.java>AppOpsService</a>.</section><section id=sec:appops-cli class=level2 data-number=7.6><h2 data-number=7.6><span class=header-section-number>7.6</span> <a href=#toc:sec:appops-cli>Command Line Interface</a><a href=#sec:appops-cli class=anchor aria-hidden=true></a></h2><p><code>appops</code> or <code>cmd appops</code> (on latest versions)\ncan be accessible via ADB or root. This is an easier method to get or\nupdate any operation for a package (provided the package name is known).\nThe help page of this command is self-explanatory:<pre><code>AppOps service (appops) commands:\nhelp\nPrint this help text.\nstart [--user &lt;USER_ID&gt;] &lt;PACKAGE | UID&gt; &lt;OP&gt;\nStarts a given operation for a particular application.\nstop [--user &lt;USER_ID&gt;] &lt;PACKAGE | UID&gt; &lt;OP&gt;\nStops a given operation for a particular application.\nset [--user &lt;USER_ID&gt;] &lt;[--uid] PACKAGE | UID&gt; &lt;OP&gt; &lt;MODE&gt;\nSet the mode for a particular application and operation.\nget [--user &lt;USER_ID&gt;] &lt;PACKAGE | UID&gt; [&lt;OP&gt;]\nReturn the mode for a particular application and optional operation.\nquery-op [--user &lt;USER_ID&gt;] &lt;OP&gt; [&lt;MODE&gt;]\nPrint all packages that currently have the given op in the given mode.\nreset [--user &lt;USER_ID&gt;] [&lt;PACKAGE&gt;]\nReset the given application or all applications to default modes.\nwrite-settings\nImmediately write pending changes to storage.\nread-settings\nRead the last written settings, replacing current state in RAM.\noptions:\n&lt;PACKAGE&gt; an Android package name or its UID if prefixed by --uid\n&lt;OP&gt;      an AppOps operation.\n&lt;MODE&gt;    one of allow, ignore, deny, or default\n&lt;USER_ID&gt; the user id under which the package is installed. If --user is not\nspecified, the current user is assumed.</code></pre></section></section><section id=footnotes class=\"footnotes footnotes-end-of-document\" role=doc-endnotes><hr><ol><li id=fn1><p>Только для распостранения стабильных релизов<a href=#fnref1 class=footnote-back role=doc-backlink>↩︎</a><li id=fn2><p>GitHub pull запросы будут объединены вручную с помощью\nсоответствующих патчей. В результате GitHub может ошибочно пометить их\nкак закрытые вместо объединенных.<a href=#fnref2 class=footnote-back role=doc-backlink>↩︎</a><li id=fn3><p>Вы также можете обращаться ко мне как “Muntashir Akon”<a href=#fnref3 class=footnote-back role=doc-backlink>↩︎</a></ol></section>"
  },
  {
    "path": "docs/raw/ru/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"intro$main$translations\">App Manager не поддерживает переводы напрямую через pull/merge запросы. Переводы управляются автоматически через\n\\nWeblate. Чтобы присоединиться к команде перевода, посетите \\\\url{https://hosted.weblate.org/engage/app-manager/}.</string>\n    <string name=\"intro$main$contributing\">Есть несколько способов, которыми пользователь может внести свой вклад, такие как создание полезных вопросов, посещение дискуссий, улучшение\n\\nдокументаций и переводов, добавление библиотек или трекеров, просмотр исходного кода, а так же\n\\nсообщение об уязвимостях безопасности.</string>\n    <string name=\"titlepage$quotation\">\\\\begin{quotation}\n\\n ``Мудро и медленно; они спотыкаются, что бегают быстро.\\'\\'\n\\n %\\\\sourceatright\n\\n {--- Брат Лоуренс, \\\\textit{Ромео и Джульетта}}\n\\n \\\\end{quotation}</string>\n    <string name=\"intro$main$submit-patches\">Репозитории, расположенные на сайтах, отличных от GitHub, в настоящее время считаются зеркалами, и pull/merge запросы, отправленные на\n\\nэтих сайтах не будут приняты.\\\\footnote{GitHub pull запросы будут объединены вручную с помощью соответствующих патчей.\n\\nВ результате GitHub может ошибочно пометить их как закрытые вместо объединенных.} Вместо этого патчи (\\\\texttt{.patch} файлы) могут\n\\nбыть отправлены через вложения электронной почты. \\\\textit{Требуется подпись.} Прочитайте файл CONTRIBUTING расположенный в корне\n\\nдиректории с исходным кодом чтобы получить больше информации.\n\\n\n\\n\\\\begin{warning}{Внимание}\n\\n В случае отправки исправлений по электронной почте вся беседа может стать общедоступной в будущем. Поэтому не надо\n\\nвключать любую личную информацию, кроме вашего имени или адреса электронной почты.\n\\n\\\\end{warning}</string>\n    <string name=\"intro$main$intro\">App Manager это продвинутый менеджер приложений для Android. Оно предоставляет несчётное количество возможностей, следовательно, требует руководство потльзователя чтобы помочь пользователям. Этот документ действует как ркуоводство пользователя для App Manager в том смысле, что оно направлено на описание\n\\nкаждой возможности которую App Manager предоставляет. Этот документ так же действует как ``официальные\\'\\' методические рекомендации для\n\\nApp Manager, и представляет ожидаемое поведение App Manager. Переводы могут неверно истолковывать этот документ (который написан на английском языке). Поэтому каждый понимающий андгийский язык пользователь должен прочитать версию на андгийском языке для лучшего понимания\n\\nApp Manager. Здесь так же могут быть другие неофициальные или сторонние ресурсы тикое как сообщения блога, видео, чаты и т.п. \n\\nХотя эти ресурсы могут быть полезны для многих людей, они могут быть устаревшими для текущей\n\\nверсии App Manager. Если замечены какие-либо отличия между App Manager и этом документом, о них следует сообщать в\n\\n\\\\href{https://github.com/MuntashirAkon/AppManager/issues}{App Manager issue tracker}.</string>\n    <string name=\"intro$main$bin-sources\">App Manager распостранятся используя следующий источники. Неофициальные источники могут распостранять модифицированную версию App\n\\nManager, и никто, кроме вас, не несет ответственности за последствия использования таких дистрибутивов.\n\\n\\\\begin{enumerate}\n\\n \\\\item Офисиальный репозиторий F-Droid.\\\\footnote{Только для распостранения стабильных релизов}\\\\\\\\\n\\n \\\\textit{Ссылка:} \\\\url{https://f-droid.org/packages/io.github.muntashirakon.AppManager}\n\\n \\\\item GitHub репозиторий.\\\\\\\\\n\\n \\\\textit{Стабильные релизы:} \\\\url{https://github.com/MuntashirAkon/AppManager/releases}\\\\\\\\\n\\n \\\\textit{Бета релизы:} \\\\url{https://github.com/MuntashirAkon/AppManager/actions}\n\\n \\\\item Телеграм.\\\\\\\\\n\\n \\\\textit{Стабильные релизы:} \\\\url{https://t.me/AppManagerChannel}\\\\\\\\\n\\n \\\\textit{Бета релизы:} \\\\url{https://t.me/AppManagerDebug}\n\\n\\\\end{enumerate}</string>\n    <string name=\"pages$main-page$intro\">На главной странице перечислены все установленные, удаленные и резервные копии приложений. Один клик по любому установленному элементу приложения\n\\nоткрывает \\\\hyperref[sec:app-details-page]{Страницу сведений о приложении}. Для удаленных системных приложений отображается\n\\nдиалоговое окно, которое можно использовать для переустановки приложения. Используя \\\\hyperlink{par:main-page-sort}{сортировку} из\n\\nсписка настроек, приложения можно сортировать различными способами. Также есть возможность фильтровать приложения\n\\nиспользуя \\\\hyperlink{par:main-page-filter}{фильтр}. Возможна фильтрация также через\n\\nстроку поиска с поддержкой регулярных выражений.</string>\n    <string name=\"pages$main-page$application-types\">Приложение может быть либо \\\\textbf{пользовательским}, либо \\\\textbf{системным} приложением вместе со следующими суффиксами:\n\\n\\\\begin{itemize}\n\\n \\\\item \\\\texttt{X} -- Поддерживает несколько архитектур\n\\n \\\\item \\\\texttt{0} -- В приложении нет файлов dex\n\\n \\\\item \\\\texttt{°}-- Приложение приостановлено\n\\n \\\\item \\\\texttt{\\\\#} -- Приложение запросило у системы выделение большого количества оперативной памяти\n\\n \\\\item \\\\texttt{\\?} -- Приложение запросило, чтобы виртуальная машина находилась в безопасном режиме\n\\n\\\\end{itemize}</string>\n    <string name=\"pages$main-page$colour-codes\">\\\\begin{itemize}\n\\n \\\\item \\\\colorbox{AMLightGreyishOrange}{\\\\textcolor{black}{Светло-серовато-оранжевый (день)}} / \\\\colorbox{AMDarkBlue}{\n\\n \\\\textcolor{white}{Тёмно-синий (ночь)}} -- Приложение выбрано для множественной обработки\n\\n \\\\item \\\\colorbox{AMLightRed}{\\\\textcolor{black}{Светло-красный (день)}} / \\\\colorbox{AMVeryDarkRed}{\\\\textcolor{white}\n\\n {Тёмно-красный (ночь)}} -- Приложение отключено\n\\n \\\\item \\\\colorbox{AMYellow}{\\\\textcolor{black}{Жёлтый}} -- Отлаживаемое приложение\n\\n \\\\item \\\\textcolor{AMOrange}{Оранжевая \\\\textit{дата}} -- Приложение имеет доступ к системным логам\n\\n \\\\item \\\\textcolor{AMOrange}{Оранжевый \\\\textit{UID}} -- Идентификатор пользователя используется несколькими приложениями\n\\n \\\\item \\\\textcolor{AMOrange}{Оранжевый \\\\textit{SDK}} -- Возможно, приложение использует трафик в открытом виде (напр. HTTP)\n\\n \\\\item \\\\textcolor{red}{Красное \\\\textit{имя пакета}} -- Приложение не позволяет очистить свои данные\n\\n \\\\item \\\\textcolor{red}{Красный \\\\textit{бекап}} -- Удаленное приложение с одной или несколькими резервными копиями, присутствующими в App\n\\n Manager\n\\n \\\\item \\\\textcolor{AMOrange}{Оранжевый\\\\textit{бекап}} -- Устаревшая резервная копия, т.е. резервная копия содержит более старую\n\\n версия установленного приложения\n\\n \\\\item \\\\textcolor{AMDarkCyan}{Темно-голубой \\\\textit{бекап}} -- Актуальная резервная копия, т.е. резервная копия содержит\n\\n такую же или более позднюю версию установленного приложения\n\\n \\\\item \\\\textcolor{AMDarkCyan}{Темно-голубое \\\\textit{имя пакета}} -- Принудительно остановленное приложение\n\\n \\\\item \\\\textcolor{AMDarkCyan}{Темно-голубая \\\\textit{версия}} -- Неактивное приложение\n\\n \\\\item \\\\textcolor{magenta}{Пурпурный} -- Постоянное приложение, т. е. оно остается запущенным все время.\n\\n\\\\end{itemize}</string>\n    <string name=\"pages$main-page$instructions\">Нажатие на инструкции открывает оффлайн версию документации App Manager. Она открывает\n\\nонлайн версию, если не установлен соответствующий раздел функций. feat_docs или WebView не\n\\nприсутствует в системе для загрузки документации.</string>\n    <string name=\"pages$main-page$sort\">Приложения, перечисленные на главной странице, можно отсортировать несколькими способами:\n\\n\\\\begin{itemize}\n\\n \\\\item \\\\textbf{Сначала пользовательские.} Пользовательские приложения будут отображаться первыми\n\\n \\\\item \\\\textbf{Название приложения.} Сортировка по возрастанию на основе названий (также известны как \n\\n \\\\textit{ярлыки приложений}). Это значение сортировки по умолчанию\n\\n \\\\item \\\\textbf{Имя пакета.} Сортировка по возрастанию по именам пакетов\n\\n \\\\item \\\\textbf{Последнее обновление.} Сортировка в порядке убывания по дате обновления пакета\n\\n \\\\item \\\\textbf{Общий идентификатор пользователя.} Сортировка по убыванию на основе идентификатора пользователя ядра\n\\n \\\\item \\\\textbf{Целевая версия SDK.} Сортировка по возрастанию в зависимости от целевой SDK\n\\n \\\\item \\\\textbf{Подпись.} Сортировка в порядке возрастания на основе информации о подписи приложения\n\\n \\\\item \\\\textbf{Сначала отключенные.} Отключенные приложения будут отображаться первыми\n\\n \\\\item \\\\textbf{Сначала заблокированные.} Сортировка по убыванию в зависимости от количества заблокированных компонентов\n\\nв приложении\n\\n \\\\item \\\\textbf{Сначала резервные копии.} Отображать приложения с резервными копиями сверху\n\\n \\\\item \\\\textbf{Трекеры.} Сортировка по убыванию в зависимости от количества трекеров\n\\nв приложении\n\\n \\\\item \\\\textbf{Последние действия.} Сортировка по убыванию в зависимости от последнего времени любый действий,\n\\n сделанных с помощью App Manager.\n\\n\\\\end{itemize}\n\\n\n\\nВ дополнение, существует опция \\\\textit{Обратный порядок} для сортировки приложений в обратном порядке. Не считая\n\\nнастроек сортировки, приложения сначала сортируются в алфавитном порядке, чтобы предотвратить создание случайных\n\\nрезультатов сортировки.</string>\n    <string name=\"intro$main$$introduction-chapter-title\">Введение</string>\n    <string name=\"intro$main$$terminologies-title\">Терминология</string>\n    <string name=\"intro$main$$supported-versions-title\">Поддерживаемые версии</string>\n    <string name=\"intro$main$$official-sources-title\">Официальные источники</string>\n    <string name=\"intro$main$$source-code-links-title\">Ссылки на исходный код</string>\n    <string name=\"intro$main$$translations-title\">Переводы</string>\n    <string name=\"intro$main$$buiding-title\">Инструкции по сборке</string>\n    <string name=\"intro$main$$submit-patches-title\">Отправка исправлений</string>\n    <string name=\"intro$main$supported-versions\">\"Сейчас поддерживаемые версии это v3.0.0 -- v3.0.3  (стабильные), v3.1.0 (альфа релизы). Предыдущие версии App\n\\nManager могут содержать уязвимости безопасности и не должны быть использованы.\"</string>\n    <string name=\"intro$main$source-code-links\">Все, кроме GitHub, являются зеркальными ссылками. Теги всегда должны быть актуальными, но не гарантируется, что master-ветка будет\n\\nактуальной. Если цель состоит в том, чтобы клонировать master-ветку, используйте ссылку GitHub вместо других.</string>\n    <string name=\"intro$main$terminologies\">\\\\begin{itemize}\n\\n \\\\item \\\\textbf{AM} --- Краткое название App Manager.\n\\n \\\\item \\\\textbf{Block/Unblock} --- Используется для блокировки/разблокировки компонентов. Способ блокировки компонентов зависит от\n\\nпользовательских настроек.\n\\n \\\\item \\\\textbf{IFW} --- Краткая форма Intent Firewall.\n\\n \\\\item \\\\textbf{Ops} --- Краткое название для операций, таких как операции приложения, пакетные операции, операции в 1 клик\n\\n \\\\item \\\\textbf{SSAID} --- Краткая форма \\\\texttt{Settings.Secure.ANDROID\\\\_ID}. Это идентификатор устройства, привязанный к\n\\n каждому приложению (Android Oreo и выше). Он сгенерирован из комбинации сертификата подписи приложения\n\\n и SSAID установленного для пакета \\\\texttt{android}. Как результат, он гарантированно будет одинаковым пока\n\\n пользователь не решит отформатировать устройство. Он широко используется для слежки.\n\\n \\\\item \\\\textbf{Трекер} --- Обозначает компоненты трекера во всем документе и в App Manager за исключением\n\\n \\\\hyperref[sec:scanner-page]{scanner page}. Трекеры включают в себя библиотеки для отправки краш-репортов, аналитики,\n\\n профилирования, идентификации, рекламы, местоположения и т.п.. Таким образом, они не одинаковые по функциям. Здесь нет различия\n\\n между библиотек с открытым и закрытым исходным кодом, которые продвикают трекинг.\n\\n\\\\end{itemize}</string>\n    <string name=\"intro$main$$contributing-title\">Вклад</string>\n    <string name=\"intro$main$$bin-sources-title\">Источники распостранения</string>\n    <string name=\"intro$main$$donation-title\">Пожертвование \\\\&amp; Финансирование</string>\n    <string name=\"intro$main$$contact-title\">Связь</string>\n    <string name=\"intro$main$buiding\">Инструкции по сборке доступны в файле BUILDING, расположенном в корне директории исходного кода.</string>\n    <string name=\"intro$main$contact\">Muntashir Al-Islam\\\\footnote{Вы также можете обращаться ко мне как ``Muntashir Akon\\'\\'}\\\\\\\\\n\\nEmail: \\\\href{mailto:muntashirakon@riseup.net}{muntashirakon [at] riseup [dot] net}\\\\\\\\\n\\nKey Fingerprint: \\\\texttt{7bad37c2981e41f8f6abea7f58f0b4f26c346fce}\\\\\\\\\n\\nGitHub: \\\\url{https://github.com/MuntashirAkon}\\\\\\\\\n\\nTwitter: \\\\url{https://twitter.com/Muntashir}</string>\n    <string name=\"pages$main$$pages-chapter-title\">Страницы</string>\n    <string name=\"pages$main-page$$section-title\">Главная страница</string>\n    <string name=\"pages$main-page$$how-app-ops-work-title\">Элемент списка приложений на главной странице</string>\n    <string name=\"pages$main-page$$batch-operations-title\">Пакетные операции</string>\n    <string name=\"pages$main-page$$colour-codes-title\">Цветовые коды</string>\n    <string name=\"pages$main-page$$application-types-title\">Типы приложений</string>\n    <string name=\"pages$main-page$$version-info-title\">Информация о версии</string>\n    <string name=\"pages$main-page$$options-menu-title\">Меню настроек</string>\n    <string name=\"pages$main-page$$instructions-title\">Инструкции</string>\n    <string name=\"pages$main-page$$list-options-title\">Список настроек</string>\n    <string name=\"pages$main-page$$sort-title\">Сортировка</string>\n    <string name=\"pages$main-page$$filter-title\">Фильтр</string>\n    <string name=\"pages$main-page$$profile_name-title\">Имя профиля</string>\n    <string name=\"pages$main-page$$1-click-ops-title\">Операции в 1 клик</string>\n    <string name=\"pages$main-page$$app-usage-title\">Использование приложения</string>\n    <string name=\"pages$main-page$$running-apps-title\">Запущеные приложения</string>\n    <string name=\"pages$main-page$$profiles-title\">Профили</string>\n    <string name=\"pages$main-page$$apk-updater-title\">Программа обновления APK</string>\n    <string name=\"pages$main-page$$termux-title\">Termux</string>\n    <string name=\"pages$main-page$$settings-title\">Настройки</string>\n    <string name=\"pages$main-page$batch-operations\">На этой странице также доступны пакетные операции или операции с несколькими приложениями. Режим множественного выбора\n\\nможет быть активирован кликом на любое приложение или нажав и удерживая любой элемент в списке. После активации одним нажатием на\n\\nэлемент списка выбирает его вместо открытия страницы сведений о приложении. В этом режиме пакетные операции расположены в\n\\nменю множественного выбора внизу страницы. Операции включают:\n\\n\\\\begin{itemize}\n\\n \\\\item Добавление выбранных приложений в \\\\hyperref[sec:profiles-page]{профиль}\n\\n \\\\item \\\\hyperref[sec:backup-restore]{Резервное копирование, восстановление или удаление} приложений\n\\n \\\\item Блокировка трекеров в приложениях\n\\n \\\\item Очистка данных или кэша приложений\n\\n \\\\item Включение/отключение/принудительная остановка/удаление приложений\n\\n \\\\item Экспорт правил блокировки, сохранённых в App Manager\n\\n \\\\item Предотвращение фоновой работы приложений (Android 7 и выше)\n\\n \\\\item Сохранение файлов APK в \\\\texttt{AppManager/apks}\n\\n \\\\item Установка \\\\hyperref[sec:net-policy]{политик}\n\\n\\\\end{itemize}\n\\n\n\\n\\\\begin{tip}{Доступность}\n\\n После активации режима множественного выбора можно входить или выходить из\n\\n меню с помощью правой или левой клавиши клавиатуры.\n\\n\\\\end{tip}</string>\n    <string name=\"pages$main-page$version-info\">После названия версии следуют следующие префиксы:\n\\n\\\\begin{itemize}\n\\n \\\\item \\\\texttt{\\\\_} -- Нет аппаратного ускорения\n\\n \\\\item \\\\texttt{\\\\textasciitilde} -- Только тестовый режим\n\\n \\\\item \\\\texttt{debug} -- Отлаживаемое приложение\n\\n\\\\end{itemize}</string>\n    <string name=\"pages$main-page$options-menu\">В меню опций есть несколько опций, которые можно использовать для сортировки, фильтрации перечисленных приложений, а также для перехода\n\\n к различным страницам.</string>\n    <string name=\"pages$main-page$list-options\">\\\\textbf{Параметры списка} содержат параметры для сортировки или фильтрации списка приложений.</string>\n    <string name=\"titlepage$user_manual\">{\\\\huge\\\\bfseries Руководство пользователя\\\\par}</string>\n    <string name=\"keywords$chapter\">\\\\newcommand{\\\\KeywordChapter}{Раздел}</string>\n    <string name=\"keywords$see_also\">\\\\newcommand{\\\\KeywordSeeAlso}{Смотрите также:}</string>\n    <string name=\"keywords$end_of_keyword_in_alert\">\\\\newcommand{\\\\KeywordEndOfKeyWordInAlert}{.}</string>\n    <string name=\"intro$main$donation\">\\\\emph{Подношения или покупки не требуются для использования App Manager.} В данный момент App Manager не поддерживает покупки, подношения владельцам App Manager могут быть отправлены через Open Source Collective.\n\\n\n\\nOpen Source Collective это фискальный хост на платформе Open Collective, который помогает проектам с открытым исходным кодом управлять финансами. В данный момент он поддерживает оплату с помощью банковских аккаунтов, PayPal, кредитных или дебетовых карт, а также криптовалют.\n\\n\n\\n\\\\textit{Link:} \\\\url{https://opencollective.com/muntashir}.\n\\n\n\\nОтправляя подношения, отправитель соглашается с тем, что подношение не используется для приоритизации предложенных ими идей. Предложение идей не требует никаких наград или подношений, и их приоритизация осуществляется по усмотрению владельца.\n\\n\n\\n\\\\emph{App Manager принимает любые предложения по финансированию или гранты.} Представители заинтересованной организации могут связаться с владельцами напрямую, используя опции в \\\\Sref{sec:contact}.</string>\n    <string name=\"pages$main-page$1-click-ops\">\\\\textbf{1-Click Ops} отвечает за операции с одним кликом. Он открывает \\\\hyperref[sec:1-click-ops-page]{corresponding\n\\npage} в новом действии.</string>\n    <string name=\"pages$main-page$profile_name\">Также можно отобразить приложения, которые находятся только в \\\\hyperref[sec:profiles-page]{profile}.\n\\nЭто может быть полезно для переноса некоторых операций в профиль (к примеру удаление всех приложений в профиле),\n\\nчто не может быть сделано через \\\\hyperref[sec:profiles-page]{Profiles page}.</string>\n    <string name=\"pages$main-page$filter\">Приложения, перечисленные на главной странице, могут быть отфильтрованы следующими способами:\n\\n\\\\begin{itemize}\n\\n \\\\item \\\\textbf{User apps.} Список только пользовательских приложений\n\\n \\\\item \\\\textbf{System Apps.} Список только системных приложений\n\\n \\\\item \\\\textbf{Disabled apps.} Список только отключенных приложений\n\\n \\\\item \\\\textbf{Apps with rules.} Список приложений с одним или несколькими правилами блокировок\n\\n \\\\item \\\\textbf{Apps with activities.} Список приложений с одним или несколькими действиями\n\\n \\\\item \\\\textbf{Apps with backups.} Список приложений с одним или несколькими резервными копиями\n\\n \\\\item \\\\textbf{Running apps.} Список приложений, которые в настоящее время запущены\n\\n \\\\item \\\\textbf{Apps with splits.} Список приложений с одним или несколькими файлами APK\n\\n \\\\item \\\\textbf{Installed apps.} Список только установленных приложений\n\\n \\\\item \\\\textbf{Uninstalled apps.} Список только удаленных приложений\n\\n \\\\item \\\\textbf{Apps without backups.} Список приложений без резервного копирования.\n\\n\\\\end{itemize}\n\\n\n\\nКроме сортировки, можно использовать более одного параметра фильтрации одновременно. Например, \n\\nприложения отключенные пользователями могут быть выбраны как \\\\textit{User apps}, так и \\\\textit{Disabled apps}. Это может быть\n\\n особенно полезно для \\\\hyperref[subsec:batch-operations]{batch operations}, где может потребоваться фильтрация пользовательских приложений\n\\n для безопасного выполнения определенных операций.</string>\n    <string name=\"pages$main-page$app-usage\">Статистики использования приложений, таких как \\\\textit{screen time}, \\\\textit{data usage} (both mobile and Wi-Fi), \\\\textit{the number of\n\\ntimes an app was opened} можно получить кликнув на опцию \\\\textbf{App Usage} в меню. Однако это требует разрешения\n\\n\\\\textit{Usage Access}. Этот пункт меню не будет указан, если функция доступа к использованию отключена в\n\\n\\\\hyperref[subsec:enable/disable-features]{settings}.</string>\n    <string name=\"pages$main-page$running-apps\">Этот пункт меню открывает новую страницу, на которой отображается список запущенных приложений или\n\\nпроцессов. Он также отображает текущее использование памяти и кэша (если доступно). Если root или ADB\n\\nнедоступны для диспетчера приложений, он отображает только себя в последних версиях Android.\n\\nЗапущенные приложения или процессы также могут быть принудительно остановлены или завершены на\n\\nрезультирующей странице. Журналы для каждого идентификатора процесса (PID) также можно просмотреть\n\\nв \\\\hyperref[subsubsec:log-viewer]{log viewer}. Также возможно выполнять пакетные операции либо\n\\nщелчком по значку, либо длительным щелчком по элементу. Обычный щелчок по любому элементу открывает\n\\nдиалоговое окно, в котором отображается более подробная информация.</string>\n    <string name=\"pages$main-page$profiles\">Этот пункт меню открывает \\\\hyperref[sec:profiles-page]{profiles page}. Профили - это способ настройки\n\\nрегулярно используемых задач. Они также могут быть вызваны с помощью ярлыков.</string>\n    <string name=\"pages$app-details-page$$permission-tabs-title\">Вкладки разрешений</string>\n    <string name=\"pages$app-details-page$$servcies-title\">Сервисы</string>\n    <string name=\"pages$app-details-page$$receivers-title\">Приемники</string>\n    <string name=\"pages$main-page$apk-updater\">Если в системе установлено приложение \\\\href{https://github.com/rumboalla/apkupdater}{APK Updater}, его можно открыть через этот пункт меню. Параметр остается скрытым, если приложение отсутствует в системе.</string>\n    <string name=\"pages$app-details-page$$app-info-general-information-title\">Общая информация</string>\n    <string name=\"pages$app-details-page$$horizontal-action-panel-title\">Горизонтальная панель действий</string>\n    <string name=\"pages$app-details-page$$colour-codes-title\">Цветовые коды</string>\n    <string name=\"pages$app-details-page$$app-info-tab-title\">Вкладка \\\"Сведения о приложении\\\"</string>\n    <string name=\"pages$app-details-page$$section-title\">Страница сведений о приложении</string>\n    <string name=\"pages$main-page$termux\">Если в системе установлено приложение \\\\href{https://github.com/termux/termux-app}{Termux}, запущенный сеанс (или\n\\nновый сеанс) можно открыть через этот пункт меню. Параметр остается скрытым, если приложение отсутствует в\n\\nсистема.</string>\n    <string name=\"pages$app-details-page$$app-info-options-menu-title\">Меню параметров</string>\n    <string name=\"pages$app-details-page$$tags-title\">Теги</string>\n    <string name=\"pages$app-details-page$$config-termux-title\">Настройки Termux</string>\n    <string name=\"pages$app-details-page$$component-tabs-title\">Вкладки компонентов</string>\n    <string name=\"pages$app-details-page$$additional-features-for-rooted-phones-title\">Дополнительные функции для устройств с root доступом</string>\n</resources>"
  },
  {
    "path": "docs/raw/vi/index.html",
    "content": "<!doctype html><html xmlns=http://www.w3.org/1999/xhtml lang=vi xml:lang=vi><meta charset=utf-8><meta name=generator content=\"pandoc\"><meta name=viewport content=\"width=device-width,initial-scale=1,user-scalable=yes\"><meta name=author content=\"Muntashir Al-Islam\"><title>App Manager</title><style>code{white-space:pre-wrap}span.smallcaps{font-variant:small-caps}div.columns{display:flex;gap:min(4vw,1.5em)}div.column{flex:auto;overflow-x:auto}div.hanging-indent{margin-left:1.5em;text-indent:-1.5em}ul.task-list[class]{list-style:none}ul.task-list li input[type=checkbox]{font-size:inherit;width:.8em;margin:0 .8em .2em -1.6em;vertical-align:middle}.display.math{display:block;text-align:center;margin:.5rem auto}html{-webkit-text-size-adjust:100%}pre>code.sourceCode{white-space:pre;position:relative}pre>code.sourceCode>span{display:inline-block;line-height:1.25}pre>code.sourceCode>span:empty{height:1.2em}.sourceCode{overflow:visible}code.sourceCode>span{color:inherit;text-decoration:inherit}div.sourceCode{margin:1em 0}pre.sourceCode{margin:0}@media screen{div.sourceCode{overflow:auto}}@media print{pre>code.sourceCode{white-space:pre-wrap}pre>code.sourceCode>span{text-indent:-5em;padding-left:5em}}pre.numberSource code{counter-reset:source-line 0}pre.numberSource code>span{position:relative;left:-4em;counter-increment:source-line}pre.numberSource code>span>a:first-child::before{content:counter(source-line);position:relative;left:-1em;text-align:right;vertical-align:baseline;border:none;display:inline-block;-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;padding:0 4px;width:4em}pre.numberSource{margin-left:3em;padding-left:4px}div.sourceCode{}@media screen{pre>code.sourceCode>span>a:first-child::before{text-decoration:underline}}code span.al{font-weight:700}code span.an{font-style:italic}code span.cf{font-weight:700}code span.co{font-style:italic}code span.cv{font-style:italic}code span.do{font-style:italic}code span.dt{text-decoration:underline}code span.er{font-weight:700}code span.in{font-style:italic}code span.kw{font-weight:700}code span.pp{font-weight:700}code span.wa{font-style:italic}</style><link rel=stylesheet href=../css/custom.css><header id=title-block-header><h1 class=title>App Manager</h1><p class=author>Muntashir Al-Islam</header><nav id=TOC role=doc-toc><ul class=incremental><li><span><span class=toc-section-number>1</span> <a href=#ch:introduction id=toc:ch:introduction>Giới thiệu</a></span><ul class=incremental><li><span><span class=toc-section-number>1.1</span> <a href=#sec:terminologies id=toc:sec:terminologies>Thuật\nngữ</a></span><li><span><span class=toc-section-number>1.2</span> <a href=#sec:supported-versions id=toc:sec:supported-versions>Phiên bản\nđược hỗ trợ</a></span><li><span><span class=toc-section-number>1.3</span> <a href=#sec:official-sources id=toc:sec:official-sources>Nguồn chính\nthức</a></span><ul class=incremental><li><span><span class=toc-section-number>1.3.1</span> <a href=#subsec:binary-distribution-sources id=toc:subsec:binary-distribution-sources>Nguồn phân phối tệp nhị\nphân</a></span><li><span><span class=toc-section-number>1.3.2</span> <a href=#subsec:links-to-source-code id=toc:subsec:links-to-source-code>Liên kết đến mã\nnguồn</a></span><li><span><span class=toc-section-number>1.3.3</span> <a href=#subsec:translations id=toc:subsec:translations>Bản\ndịch</a></span></ul><li><span><span class=toc-section-number>1.4</span> <a href=#sec:contributing id=toc:sec:contributing>Đóng góp</a></span><ul class=incremental><li><span><span class=toc-section-number>1.4.1</span> <a href=#subsec:build-instructions id=toc:subsec:build-instructions>Hướng dẫn xây dựng</a></span><li><span><span class=toc-section-number>1.4.2</span> <a href=#subsec:submitting-patches id=toc:subsec:submitting-patches>Gửi\nbản vá</a></span></ul><li><span><span class=toc-section-number>1.5</span> <a href=#sec:donation-&-funding id=toc:sec:donation-&-funding>Ủng hộ & Tài\nchính</a></span><li><span><span class=toc-section-number>1.6</span> <a href=#sec:contact id=toc:sec:contact>Liên hệ</a></span></ul><li><span><span class=toc-section-number>2</span> <a href=#ch:pages id=toc:ch:pages>Trang</a></span><ul class=incremental><li><span><span class=toc-section-number>2.1</span> <a href=#sec:main-page id=toc:sec:main-page>Trang chính</a></span><ul class=incremental><li><span><span class=toc-section-number>2.1.1</span> <a href=#subsec:batch-operations id=toc:subsec:batch-operations>Hoạt\nđộng hàng loạt</a></span><li><span><span class=toc-section-number>2.1.2</span> <a href=#subsec:main-colour-codes id=toc:subsec:main-colour-codes>Mã\nmàu</a></span><li><span><span class=toc-section-number>2.1.3</span> <a href=#subsec:main-page-application-types id=toc:subsec:main-page-application-types>Các loại ứng\ndụng</a></span><li><span><span class=toc-section-number>2.1.4</span> <a href=#subsec:main-page-version-info id=toc:subsec:main-page-version-info>Thông tin phiên\nbản</a></span><li><span><span class=toc-section-number>2.1.5</span> <a href=#subsec:main-page-options-menu id=toc:subsec:main-page-options-menu>Trình đơn tùy\nchọn</a></span></ul><li><span><span class=toc-section-number>2.2</span> <a href=#sec:app-details-page id=toc:sec:app-details-page>App Details\nPage</a></span><ul class=incremental><li><span><span class=toc-section-number>2.2.1</span> <a href=#subsec:app-details-colour-codes id=toc:subsec:app-details-colour-codes>Colour Codes</a></span><li><span><span class=toc-section-number>2.2.2</span> <a href=#subsec:app-info-tab id=toc:subsec:app-info-tab>App Info\nTab</a></span><li><span><span class=toc-section-number>2.2.3</span> <a href=#subsec:component-tabs id=toc:subsec:component-tabs>Component\nTabs</a></span><li><span><span class=toc-section-number>2.2.4</span> <a href=#subsec:permission-tabs id=toc:subsec:permission-tabs>Permission Tabs</a></span><li><span><span class=toc-section-number>2.2.5</span> <a href=#subsec:signatures-tab id=toc:subsec:signatures-tab>Signatures\nTab</a></span><li><span><span class=toc-section-number>2.2.6</span> <a href=#subsec:uses-features-tab id=toc:subsec:uses-features-tab>Uses\nFeatures tab</a></span><li><span><span class=toc-section-number>2.2.7</span> <a href=#subsec:configurations-tab id=toc:subsec:configurations-tab>Configurations tab</a></span><li><span><span class=toc-section-number>2.2.8</span> <a href=#subsec:shared-libs-tab id=toc:subsec:shared-libs-tab>Shared\nLibraries Tab</a></span></ul><li><span><span class=toc-section-number>2.3</span> <a href=#sec:1-click-ops-page id=toc:sec:1-click-ops-page>1-Click Ops\nPage</a></span><ul class=incremental><li><span><span class=toc-section-number>2.3.1</span> <a href=#subsec:block-unblock-trackers id=toc:subsec:block-unblock-trackers>Block/Unblock\nTrackers</a></span><li><span><span class=toc-section-number>2.3.2</span> <a href=#subsec:block-components-dots id=toc:subsec:block-components-dots>Block Components…</a></span><li><span><span class=toc-section-number>2.3.3</span> <a href=#subsec:set-mode-for-app-ops-dots id=toc:subsec:set-mode-for-app-ops-dots>Set Mode for App\nOps…</a></span><li><span><span class=toc-section-number>2.3.4</span> <a href=#subsec:1-click-back-up id=toc:subsec:1-click-back-up>Back\nup</a></span><li><span><span class=toc-section-number>2.3.5</span> <a href=#subsec:1-click-restore id=toc:subsec:1-click-restore>Restore</a></span><li><span><span class=toc-section-number>2.3.6</span> <a href=#subsec:trim-caches-in-all-apps id=toc:subsec:trim-caches-in-all-apps>Trim Caches in All\nApps</a></span></ul><li><span><span class=toc-section-number>2.4</span> <a href=#sec:profiles-page id=toc:sec:profiles-page>Profiles\nPage</a></span><ul class=incremental><li><span><span class=toc-section-number>2.4.1</span> <a href=#subsec:profiles-options-menu id=toc:subsec:profiles-options-menu>Options Menu</a></span></ul><li><span><span class=toc-section-number>2.5</span> <a href=#sec:profile-page id=toc:sec:profile-page>Profile\nPage</a></span><ul class=incremental><li><span><span class=toc-section-number>2.5.1</span> <a href=#subsec:profile-options-menu id=toc:subsec:profile-options-menu>Options Menu</a></span><li><span><span class=toc-section-number>2.5.2</span> <a href=#subsec:profile-apps-tab id=toc:subsec:profile-apps-tab>Apps\nTab</a></span><li><span><span class=toc-section-number>2.5.3</span> <a href=#subsec:profile-configurations-tab id=toc:subsec:profile-configurations-tab>Configurations\nTab</a></span></ul><li><span><span class=toc-section-number>2.6</span> <a href=#sec:settings-page id=toc:sec:settings-page>Settings\nPage</a></span><ul class=incremental><li><span><span class=toc-section-number>2.6.1</span> <a href=#subsec:language id=toc:subsec:language>Language</a></span><li><span><span class=toc-section-number>2.6.2</span> <a href=#subsec:appearance id=toc:subsec:appearance>Appearance</a></span><li><span><span class=toc-section-number>2.6.3</span> <a href=#subsec:privacy id=toc:subsec:privacy>Privacy</a></span><li><span><span class=toc-section-number>2.6.4</span> <a href=#subsec:mode-of-operation id=toc:subsec:mode-of-operation>Mode\nof Operation</a></span><li><span><span class=toc-section-number>2.6.5</span> <a href=#subsec:apk-signing id=toc:subsec:apk-signing>APK\nSigning</a></span><li><span><span class=toc-section-number>2.6.6</span> <a href=#subsec:installer id=toc:subsec:installer>Installer</a></span><li><span><span class=toc-section-number>2.6.7</span> <a href=#subsec:backup/restore id=toc:subsec:backup/restore>Back\nup/Restore</a></span><li><span><span class=toc-section-number>2.6.8</span> <a href=#subsec:rules id=toc:subsec:rules>Rules</a></span><li><span><span class=toc-section-number>2.6.9</span> <a href=#subsec:advanced id=toc:subsec:advanced>Advanced</a></span><li><span><span class=toc-section-number>2.6.10</span> <a href=#subsec:device-info id=toc:subsec:device-info>About the\ndevice</a></span></ul><li><span><span class=toc-section-number>2.7</span> <a href=#sec:scanner-page id=toc:sec:scanner-page>Scanner\nPage</a></span><li><span><span class=toc-section-number>2.8</span> <a href=#sec:interceptor-page id=toc:sec:interceptor-page>Interceptor\nPage</a></span><ul class=incremental><li><span><span class=toc-section-number>2.8.1</span> <a href=#subsec:intent-filters id=toc:subsec:intent-filters>Intent\nFilters</a></span><li><span><span class=toc-section-number>2.8.2</span> <a href=#subsec:matching-activities id=toc:subsec:matching-activities>Matching Activities</a></span><li><span><span class=toc-section-number>2.8.3</span> <a href=#subsec:interceptor-reset-to-default id=toc:subsec:interceptor-reset-to-default>Reset to\nDefault</a></span><li><span><span class=toc-section-number>2.8.4</span> <a href=#subsec:interceptor-send-edited-intent id=toc:subsec:interceptor-send-edited-intent>Send Edited\nIntent</a></span></ul><li><span><span class=toc-section-number>2.9</span> <a href=#sec:shared-preferences-editor-page id=toc:sec:shared-preferences-editor-page>Shared Preferences Editor\nPage</a></span></ul><li><span><span class=toc-section-number>3</span> <a href=#ch:guides id=toc:ch:guides>Guides</a></span><ul class=incremental><li><span><span class=toc-section-number>3.1</span> <a href=#sec:adb-over-tcp id=toc:sec:adb-over-tcp>ADB over\nTCP</a></span><ul class=incremental><li><span><span class=toc-section-number>3.1.1</span> <a href=#subsec:enable-developer-options id=toc:subsec:enable-developer-options>Enable developer\noptions</a></span><li><span><span class=toc-section-number>3.1.2</span> <a href=#subsec:enable-usb-debugging id=toc:subsec:enable-usb-debugging>Enable USB\ndebugging</a></span><li><span><span class=toc-section-number>3.1.3</span> <a href=#subsec:setup-adb-on-pc-or-mac id=toc:subsec:setup-adb-on-pc-or-mac>Setup ADB on PC or\nMac</a></span><li><span><span class=toc-section-number>3.1.4</span> <a href=#subsec:configure-adb-over-tcp id=toc:subsec:configure-adb-over-tcp>Configure ADB over\nTCP</a></span></ul><li><span><span class=toc-section-number>3.2</span> <a href=#sec:wireless-debugging id=toc:sec:wireless-debugging>Wireless\nDebugging</a></span><ul class=incremental><li><span><span class=toc-section-number>3.2.1</span> <a href=#subsec:enable-developer-options-and-usb-debugging id=toc:subsec:enable-developer-options-and-usb-debugging>Enable\ndeveloper options and USB Debugging</a></span><li><span><span class=toc-section-number>3.2.2</span> <a href=#subsec:enable-wireless-debugging id=toc:subsec:enable-wireless-debugging>Enable Wireless\nDebugging</a></span><li><span><span class=toc-section-number>3.2.3</span> <a href=#subsec:pair-adb-with-app-manager id=toc:subsec:pair-adb-with-app-manager>Pair ADB with App\nManager</a></span><li><span><span class=toc-section-number>3.2.4</span> <a href=#subsec:connect-app-manager-to-adb id=toc:subsec:connect-app-manager-to-adb>Connect App Manager to\nADB</a></span></ul><li><span><span class=toc-section-number>3.3</span> <a href=#sec:backup-restore id=toc:sec:backup-restore>Back\nup/Restore</a></span><ul class=incremental><li><span><span class=toc-section-number>3.3.1</span> <a href=#subsec:backup-location id=toc:subsec:backup-location>Location</a></span><li><span><span class=toc-section-number>3.3.2</span> <a href=#subsec:backup-restore-backup-options id=toc:subsec:backup-restore-backup-options>Backup\nOptions</a></span><li><span><span class=toc-section-number>3.3.3</span> <a href=#subsec:backup-restore-backup id=toc:subsec:backup-restore-backup>Backup</a></span><li><span><span class=toc-section-number>3.3.4</span> <a href=#subsec:backup-restore-restore id=toc:subsec:backup-restore-restore>Restore</a></span><li><span><span class=toc-section-number>3.3.5</span> <a href=#subsec:backup-restore-delete-backup id=toc:subsec:backup-restore-delete-backup>Delete\nBackup</a></span></ul><li><span><span class=toc-section-number>3.4</span> <a href=#sec:automating-tasks id=toc:sec:automating-tasks>Automating\nTasks</a></span><ul class=incremental><li><span><span class=toc-section-number>3.4.1</span> <a href=#subsec:generating-authorization-key id=toc:subsec:generating-authorization-key>Generating authorization\nkey</a></span><li><span><span class=toc-section-number>3.4.2</span> <a href=#subsec:at:general-configuration id=toc:subsec:at:general-configuration>Configuring\ntasks</a></span><li><span><span class=toc-section-number>3.4.3</span> <a href=#subsec:at:features id=toc:subsec:at:features>Features</a></span><li><span><span class=toc-section-number>3.4.4</span> <a href=#subsec:triggering-a-profile id=toc:subsec:triggering-a-profile>Triggering a\nprofile</a></span></ul><li><span><span class=toc-section-number>3.5</span> <a href=#sec:net-policy id=toc:sec:net-policy>Net\nPolicy</a></span></ul><li><span><span class=toc-section-number>4</span> <a href=#ch:faq id=toc:ch:faq>Frequently Asked Questions</a></span><ul class=incremental><li><span><span class=toc-section-number>4.1</span> <a href=#sec:faq:app-components id=toc:sec:faq:app-components>App\nComponents</a></span><ul class=incremental><li><span><span class=toc-section-number>4.1.1</span> <a href=#subsec:faq:what-are-app-components id=toc:subsec:faq:what-are-app-components>What are the application\ncomponents?</a></span><li><span><span class=toc-section-number>4.1.2</span> <a href=#subsec:faq:how-components-blocked id=toc:subsec:faq:how-components-blocked>How are the tracker and other\ncomponents blocked in App Manager? What are its\nlimitations?</a></span><li><span><span class=toc-section-number>4.1.3</span> <a href=#subsec:faq:components-blocked-by-others id=toc:subsec:faq:components-blocked-by-others>Does app components\nblocked by other tools retained in App Manager?</a></span><li><span><span class=toc-section-number>4.1.4</span> <a href=#subsec:faq:components-reblocked-in-am id=toc:subsec:faq:components-reblocked-in-am>Điều gì xảy ra với các\nthành phần bị chặn bởi App Manager mà trước đây đã bị các công cụ khác\nchặn?</a></span><li><span><span class=toc-section-number>4.1.5</span> <a href=#subsec:faq:what-is-instant-component-blocking id=toc:subsec:faq:what-is-instant-component-blocking>What is instant\ncomponent blocking?</a></span><li><span><span class=toc-section-number>4.1.6</span> <a href=#subsec:tracker-classes-versus-tracker-components id=toc:subsec:tracker-classes-versus-tracker-components>Các lớp theo\ndõi so với các thành phần theo dõi</a></span></ul><li><span><span class=toc-section-number>4.2</span> <a href=#sec:faq:adb-over-tcp id=toc:sec:faq:adb-over-tcp>ADB over\nTCP</a></span><ul class=incremental><li><span><span class=toc-section-number>4.2.1</span> <a href=#subsec:faq:enable-adb-on-every-restart id=toc:subsec:faq:enable-adb-on-every-restart>Do I have to enable ADB\nover TCP everytime I restart?</a></span><li><span><span class=toc-section-number>4.2.2</span> <a href=#subsec:faq:usb-debugging id=toc:subsec:faq:usb-debugging>Cannot enable USB debugging. What to\ndo?</a></span><li><span><span class=toc-section-number>4.2.3</span> <a href=#subsec:faq:block-components-using-adb id=toc:subsec:faq:block-components-using-adb>Can I block tracker or\nany other application components using ADB over TCP?</a></span><li><span><span class=toc-section-number>4.2.4</span> <a href=#subsec:faq:adb-features id=toc:subsec:faq:adb-features>Which\nfeatures can be used in ADB mode?</a></span></ul><li><span><span class=toc-section-number>4.3</span> <a href=#sec:faq:miscellanea id=toc:sec:faq:miscellanea>Miscellanea</a></span><ul class=incremental><li><span><span class=toc-section-number>4.3.1</span> <a href=#subsec:faq:no-root-no-harms id=toc:subsec:faq:no-root-no-harms>I don’t use root/ADB. Am I\ncompletely safe from any harms?</a></span><li><span><span class=toc-section-number>4.3.2</span> <a href=#subsec:faq:how-trackers-libs-updated id=toc:subsec:faq:how-trackers-libs-updated>How are the trackers and\nlibraries are updated?</a></span><li><span><span class=toc-section-number>4.3.3</span> <a href=#subsec:faq:apks-deleted-after-installed id=toc:subsec:faq:apks-deleted-after-installed>Are APKs deleted after\ninstalled?</a></span><li><span><span class=toc-section-number>4.3.4</span> <a href=#subsec:faq:shizuku-support id=toc:subsec:faq:shizuku-support>Any plans for\nShizuku?</a></span><li><span><span class=toc-section-number>4.3.5</span> <a href=#subsec:faq:what-are-bloatware id=toc:subsec:faq:what-are-bloatware>What are bloatware and how to\nremove them?</a></span></ul></ul><li><span><span class=toc-section-number>5</span> <a href=#ch:specifications id=toc:ch:specifications>Specifications</a></span><ul class=incremental><li><span><span class=toc-section-number>5.1</span> <a href=#sec:rules-specification id=toc:sec:rules-specification>Rules\nSpecification</a></span><ul class=incremental><li><span><span class=toc-section-number>5.1.1</span> <a href=#background id=toc:background>Background</a></span><li><span><span class=toc-section-number>5.1.2</span> <a href=#rules-file-format id=toc:rules-file-format>Rules File\nFormat</a></span></ul></ul><li><span><span class=toc-section-number>6</span> <a href=#ch:changelogs id=toc:ch:changelogs>Nhật ký thay đổi</a></span><ul class=incremental><li><span><span class=toc-section-number>6.1</span> <a href=#sec:v4.0.5-(445) id=toc:sec:v4.0.5-(445)>v4.0.5\n(445)</a></span><li><span><span class=toc-section-number>6.2</span> <a href=#sec:v4.0.4-(444) id=toc:sec:v4.0.4-(444)>v4.0.4\n(444)</a></span><li><span><span class=toc-section-number>6.3</span> <a href=#sec:v4.0.3-(443) id=toc:sec:v4.0.3-(443)>v4.0.3\n(443)</a></span><li><span><span class=toc-section-number>6.4</span> <a href=#sec:v4.0.2-(442) id=toc:sec:v4.0.2-(442)>v4.0.2\n(442)</a></span><li><span><span class=toc-section-number>6.5</span> <a href=#sec:v4.0.1-(441) id=toc:sec:v4.0.1-(441)>v4.0.1\n(441)</a></span><ul class=incremental><li><span><span class=toc-section-number>6.5.1</span> <a href=#overlay-management id=toc:overlay-management>Overlay\nmanagement</a></span><li><span><span class=toc-section-number>6.5.2</span> <a href=#unfreeze-option-in-activity-shortcuts id=toc:unfreeze-option-in-activity-shortcuts>Unfreeze option in\nactivity shortcuts</a></span><li><span><span class=toc-section-number>6.5.3</span> <a href=#market-like-url-support id=toc:market-like-url-support><code>market</code>-like URL\nsupport</a></span><li><span><span class=toc-section-number>6.5.4</span> <a href=#updated-color-codes id=toc:updated-color-codes>Updated color\ncodes</a></span><li><span><span class=toc-section-number>6.5.5</span> <a href=#others id=toc:others>Others</a></span></ul><li><span><span class=toc-section-number>6.6</span> <a href=#sec:v4.0.0-(440) id=toc:sec:v4.0.0-(440)>v4.0.0\n(440)</a></span><ul class=incremental><li><span><span class=toc-section-number>6.6.1</span> <a href=#new-logo id=toc:new-logo>New logo!</a></span><li><span><span class=toc-section-number>6.6.2</span> <a href=#android-14-and-15-support id=toc:android-14-and-15-support>Android 14 and 15\nsupport</a></span><li><span><span class=toc-section-number>6.6.3</span> <a href=#revamped-debloater id=toc:revamped-debloater>Revamped\ndebloater</a></span><li><span><span class=toc-section-number>6.6.4</span> <a href=#introducing-file-manager id=toc:introducing-file-manager>Introducing file\nmanager</a></span><li><span><span class=toc-section-number>6.6.5</span> <a href=#integrated-code-editor id=toc:integrated-code-editor>Integrated code editor</a></span><li><span><span class=toc-section-number>6.6.6</span> <a href=#history-of-operations id=toc:history-of-operations>History of\noperations</a></span><li><span><span class=toc-section-number>6.6.7</span> <a href=#per-app-freezing-and-more id=toc:per-app-freezing-and-more>Per-app freezing, and\nmore</a></span><li><span><span class=toc-section-number>6.6.8</span> <a href=#log-viewer-enhancements id=toc:log-viewer-enhancements>Log\nviewer enhancements</a></span><li><span><span class=toc-section-number>6.6.9</span> <a href=#launching-non-exported-activities id=toc:launching-non-exported-activities>Launching non-exported\nactivities</a></span><li><span><span class=toc-section-number>6.6.10</span> <a href=#new-tags-in-app-info-tab id=toc:new-tags-in-app-info-tab>New\ntags in App Info tab</a></span><li><span><span class=toc-section-number>6.6.11</span> <a href=#per-session-installer-options id=toc:per-session-installer-options>Per-session installer\noptions</a></span><li><span><span class=toc-section-number>6.6.12</span> <a href=#advanced-mode-of-operations-adb-enhancements id=toc:advanced-mode-of-operations-adb-enhancements>Advanced mode of\noperations, ADB enhancements, …</a></span><li><span><span class=toc-section-number>6.6.13</span> <a href=#data-usage-widget-and-more id=toc:data-usage-widget-and-more>Data usage widget, and\nmore</a></span><li><span><span class=toc-section-number>6.6.14</span> <a href=#others-1 id=toc:others-1>Others</a></span></ul><li><span><span class=toc-section-number>6.7</span> <a href=#sec:v3.1.0-(423) id=toc:sec:v3.1.0-(423)>v3.1.0\n(423)</a></span><ul class=incremental><li><span><span class=toc-section-number>6.7.1</span> <a href=#android-13-support id=toc:android-13-support>Android 13\nsupport</a></span><li><span><span class=toc-section-number>6.7.2</span> <a href=#introducing-freezeunfreeze id=toc:introducing-freezeunfreeze>Introducing\nfreeze/unfreeze</a></span><li><span><span class=toc-section-number>6.7.3</span> <a href=#export-app-list id=toc:export-app-list>Export app\nlist</a></span><li><span><span class=toc-section-number>6.7.4</span> <a href=#elliptic-curve-crypography-ecc id=toc:elliptic-curve-crypography-ecc>Elliptic Curve Crypography\n(ECC)</a></span><li><span><span class=toc-section-number>6.7.5</span> <a href=#new-languages id=toc:new-languages>New\nlanguages</a></span><li><span><span class=toc-section-number>6.7.6</span> <a href=#more-list-options id=toc:more-list-options>More list\noptions</a></span><li><span><span class=toc-section-number>6.7.7</span> <a href=#improved-handling-of-mode-of-operation id=toc:improved-handling-of-mode-of-operation>Improved handling of\nmode of operation</a></span><li><span><span class=toc-section-number>6.7.8</span> <a href=#handling-multiple-users id=toc:handling-multiple-users>Handling multiple users</a></span><li><span><span class=toc-section-number>6.7.9</span> <a href=#explorer-enhancements id=toc:explorer-enhancements>Explorer\nenhancements</a></span><li><span><span class=toc-section-number>6.7.10</span> <a href=#new-tag-wx id=toc:new-tag-wx>New tag: WX</a></span><li><span><span class=toc-section-number>6.7.11</span> <a href=#app-ops-management id=toc:app-ops-management>App ops\nmanagement</a></span><li><span><span class=toc-section-number>6.7.12</span> <a href=#batch-uninstallation id=toc:batch-uninstallation>Batch\nuninstallation</a></span><li><span><span class=toc-section-number>6.7.13</span> <a href=#running-apps id=toc:running-apps>Running apps</a></span><li><span><span class=toc-section-number>6.7.14</span> <a href=#interceptor id=toc:interceptor>Interceptor</a></span><li><span><span class=toc-section-number>6.7.15</span> <a href=#device-specific-changes id=toc:device-specific-changes>Device-specific changes</a></span><li><span><span class=toc-section-number>6.7.16</span> <a href=#others-2 id=toc:others-2>Others</a></span></ul><li><span><span class=toc-section-number>6.8</span> <a href=#sec:v3.0.0-(410) id=toc:sec:v3.0.0-(410)>v3.0.0\n(410)</a></span><ul class=incremental><li><span><span class=toc-section-number>6.8.1</span> <a href=#material-3-and-more id=toc:material-3-and-more>Material 3 and\nMore</a></span><li><span><span class=toc-section-number>6.8.2</span> <a href=#wireless-debugging id=toc:wireless-debugging>Wireless\nDebugging</a></span><li><span><span class=toc-section-number>6.8.3</span> <a href=#languages id=toc:languages>Languages</a></span><li><span><span class=toc-section-number>6.8.4</span> <a href=#introducing-app-explorer id=toc:introducing-app-explorer>Introducing App\nExplorer</a></span><li><span><span class=toc-section-number>6.8.5</span> <a href=#import-backups-from-other-applications id=toc:import-backups-from-other-applications>Import Backups from\nOther Applications</a></span><li><span><span class=toc-section-number>6.8.6</span> <a href=#virustotal id=toc:virustotal>VirusTotal</a></span><li><span><span class=toc-section-number>6.8.7</span> <a href=#trigger-profiles-from-the-automation-software id=toc:trigger-profiles-from-the-automation-software>Trigger Profiles\nfrom the Automation Software</a></span><li><span><span class=toc-section-number>6.8.8</span> <a href=#improved-application-installer id=toc:improved-application-installer>Improved Application\nInstaller</a></span><li><span><span class=toc-section-number>6.8.9</span> <a href=#component-blocking id=toc:component-blocking>Component\nBlocking</a></span><li><span><span class=toc-section-number>6.8.10</span> <a href=#advanced-searching id=toc:advanced-searching>Advanced\nSearching</a></span><li><span><span class=toc-section-number>6.8.11</span> <a href=#shared-libraries id=toc:shared-libraries>Shared\nLibraries</a></span><li><span><span class=toc-section-number>6.8.12</span> <a href=#make-the-best-use-of-interceptor id=toc:make-the-best-use-of-interceptor>Make the Best Use of\nInterceptor</a></span><li><span><span class=toc-section-number>6.8.13</span> <a href=#widget-screen-time id=toc:widget-screen-time>Widget: Screen\nTime</a></span><li><span><span class=toc-section-number>6.8.14</span> <a href=#widget-clear-cache id=toc:widget-clear-cache>Widget: Clear\nCache</a></span></ul><li><span><span class=toc-section-number>6.9</span> <a href=#sec:v2.6.0-(385) id=toc:sec:v2.6.0-(385)>v2.6.0\n(385)</a></span><ul class=incremental><li><span><span class=toc-section-number>6.9.1</span> <a href=#introducing-backups id=toc:introducing-backups>Introducing\nBackups</a></span><li><span><span class=toc-section-number>6.9.2</span> <a href=#introducing-log-viewer id=toc:introducing-log-viewer>Introducing Log Viewer</a></span><li><span><span class=toc-section-number>6.9.3</span> <a href=#lock-app-manager id=toc:lock-app-manager>Lock App\nManager</a></span><li><span><span class=toc-section-number>6.9.4</span> <a href=#extended-modes-for-app-ops id=toc:extended-modes-for-app-ops>Extended Modes for App\nOps</a></span><li><span><span class=toc-section-number>6.9.5</span> <a href=#new-batch-ops-add-to-profile id=toc:new-batch-ops-add-to-profile>New Batch Ops: Add to\nProfile</a></span><li><span><span class=toc-section-number>6.9.6</span> <a href=#app-info-improved id=toc:app-info-improved>App Info:\nImproved</a></span><li><span><span class=toc-section-number>6.9.7</span> <a href=#advanced-sort-and-filtering-options-in-the-main-page id=toc:advanced-sort-and-filtering-options-in-the-main-page>Advanced\nSort and Filtering Options in the Main Page</a></span><li><span><span class=toc-section-number>6.9.8</span> <a href=#about-this-device id=toc:about-this-device>About This\nDevice</a></span><li><span><span class=toc-section-number>6.9.9</span> <a href=#enabledisable-features id=toc:enabledisable-features>Enable/disable Features</a></span><li><span><span class=toc-section-number>6.9.10</span> <a href=#new-languages-1 id=toc:new-languages-1>New\nLanguages</a></span><li><span><span class=toc-section-number>6.9.11</span> <a href=#signing-the-apk-files id=toc:signing-the-apk-files>Signing the\nAPK Files</a></span><li><span><span class=toc-section-number>6.9.12</span> <a href=#new-extension-unapkm id=toc:new-extension-unapkm>New\nExtension: UnAPKM</a></span></ul><li><span><span class=toc-section-number>6.10</span> <a href=#sec:v2.5.20-(375) id=toc:sec:v2.5.20-(375)>v2.5.20\n(375)</a></span><ul class=incremental><li><span><span class=toc-section-number>6.10.1</span> <a href=#subsec:introducing-profiles id=toc:subsec:introducing-profiles>Introducing\nProfiles</a></span><li><span><span class=toc-section-number>6.10.2</span> <a href=#subsec:the-interceptor id=toc:subsec:the-interceptor>The\nInterceptor</a></span><li><span><span class=toc-section-number>6.10.3</span> <a href=#subsec:unapkm:-dedrm-the-apkm-files id=toc:subsec:unapkm:-dedrm-the-apkm-files>UnAPKM: DeDRM the APKM\nfiles</a></span><li><span><span class=toc-section-number>6.10.4</span> <a href=#subsec:multiple-user id=toc:subsec:multiple-user>Multiple\nuser</a></span><li><span><span class=toc-section-number>6.10.5</span> <a href=#vive-la-france id=toc:vive-la-france>Vive la\nFrance!</a></span><li><span><span class=toc-section-number>6.10.6</span> <a href=#report-crashes id=toc:report-crashes>Report\ncrashes</a></span><li><span><span class=toc-section-number>6.10.7</span> <a href=#android-11 id=toc:android-11>Android 11</a></span><li><span><span class=toc-section-number>6.10.8</span> <a href=#app-installer-improvements id=toc:app-installer-improvements>App Installer\nImprovements</a></span></ul><li><span><span class=toc-section-number>6.11</span> <a href=#v2.5.17-368 id=toc:v2.5.17-368>v2.5.17 (368)</a></span><ul class=incremental><li><span><span class=toc-section-number>6.11.1</span> <a href=#app-installer id=toc:app-installer>App\nInstaller</a></span><li><span><span class=toc-section-number>6.11.2</span> <a href=#scanner-replacement-for-exodus-page id=toc:scanner-replacement-for-exodus-page>Scanner: Replacement for\nExodus Page</a></span><li><span><span class=toc-section-number>6.11.3</span> <a href=#introducing-system-config id=toc:introducing-system-config>Introducing System\nConfig</a></span><li><span><span class=toc-section-number>6.11.4</span> <a href=#more-languages id=toc:more-languages>More\nLanguages</a></span><li><span><span class=toc-section-number>6.11.5</span> <a href=#app-info-tab id=toc:app-info-tab>App Info Tab</a></span><li><span><span class=toc-section-number>6.11.6</span> <a href=#navigation-improvements id=toc:navigation-improvements>Navigation Improvements</a></span><li><span><span class=toc-section-number>6.11.7</span> <a href=#running-apps-page id=toc:running-apps-page>Running Apps\nPage</a></span><li><span><span class=toc-section-number>6.11.8</span> <a href=#built-in-toybox id=toc:built-in-toybox>Built-in\nToybox</a></span><li><span><span class=toc-section-number>6.11.9</span> <a href=#component-blocker-improvements id=toc:component-blocker-improvements>Component Blocker\nImprovements</a></span><li><span><span class=toc-section-number>6.11.10</span> <a href=#improvements-in-the-app-details-page id=toc:improvements-in-the-app-details-page>Improvements in the App\nDetails Page</a></span><li><span><span class=toc-section-number>6.11.11</span> <a href=#app-manifest id=toc:app-manifest>App Manifest</a></span></ul><li><span><span class=toc-section-number>6.12</span> <a href=#v2.5.13-348 id=toc:v2.5.13-348>v2.5.13 (348)</a></span><ul class=incremental><li><span><span class=toc-section-number>6.12.1</span> <a href=#bundled-app-split-apk id=toc:bundled-app-split-apk>Bundled App\n(Split APK)</a></span><li><span><span class=toc-section-number>6.12.2</span> <a href=#direct-install-support id=toc:direct-install-support>Direct\nInstall Support</a></span><li><span><span class=toc-section-number>6.12.3</span> <a href=#remove-all-blocking-rules id=toc:remove-all-blocking-rules>Remove All Blocking\nRules</a></span><li><span><span class=toc-section-number>6.12.4</span> <a href=#app-ops-1 id=toc:app-ops-1>App Ops</a></span><li><span><span class=toc-section-number>6.12.5</span> <a href=#enhanced-adb-support id=toc:enhanced-adb-support>Enhanced ADB\nSupport</a></span><li><span><span class=toc-section-number>6.12.6</span> <a href=#filtering-in-main-page id=toc:filtering-in-main-page>Filtering\nin Main Page</a></span><li><span><span class=toc-section-number>6.12.7</span> <a href=#apk-backupsharing id=toc:apk-backupsharing>Apk\nBackup/Sharing</a></span><li><span><span class=toc-section-number>6.12.8</span> <a href=#batch-ops id=toc:batch-ops>Batch Ops</a></span><li><span><span class=toc-section-number>6.12.9</span> <a href=#translations id=toc:translations>Translations</a></span><li><span><span class=toc-section-number>6.12.10</span> <a href=#app-data-backup id=toc:app-data-backup>App Data\nBackup</a></span></ul></ul><li><span><span class=toc-section-number>7</span> <a href=#ch:app-ops id=toc:ch:app-ops>App Ops</a></span><ul class=incremental><li><span><span class=toc-section-number>7.1</span> <a href=#sec:app-ops-background id=toc:sec:app-ops-background>Background</a></span><li><span><span class=toc-section-number>7.2</span> <a href=#sec:introduction-to-app-ops id=toc:sec:introduction-to-app-ops>Introduction to App\nOps</a></span><li><span><span class=toc-section-number>7.3</span> <a href=#sec:appopsmanager id=toc:sec:appopsmanager>AppOpsManager</a></span><ul class=incremental><li><span><span class=toc-section-number>7.3.1</span> <a href=#subsec:op-constants id=toc:subsec:op-constants><code>OP_*</code> Constants</a></span><li><span><span class=toc-section-number>7.3.2</span> <a href=#subsec:mode-constants id=toc:subsec:mode-constants><code>MODE_*</code>\nConstants</a></span><li><span><span class=toc-section-number>7.3.3</span> <a href=#subsec:package-ops id=toc:subsec:package-ops>PackageOps</a></span><li><span><span class=toc-section-number>7.3.4</span> <a href=#subsec:opentry id=toc:subsec:opentry>OpEntry</a></span><li><span><span class=toc-section-number>7.3.5</span> <a href=#subsec:usage id=toc:subsec:usage>Usage</a></span></ul><li><span><span class=toc-section-number>7.4</span> <a href=#sec:appopsservice id=toc:sec:appopsservice>AppOpsService</a></span><li><span><span class=toc-section-number>7.5</span> <a href=#sec:appops-xml id=toc:sec:appops-xml>appops.xml</a></span><li><span><span class=toc-section-number>7.6</span> <a href=#sec:appops-cli id=toc:sec:appops-cli>Command Line\nInterface</a></span></ul></ul></nav><div class=titlingpage><div class=center><p><img src=../images/icon.png style=width:1in alt=image><p><strong><span class=smallcaps>App Manager</span></strong><p><strong>Hướng dẫn sử dụng cho người dùng</strong><p><em>v4.0.5</em><p>27 tháng 7 2025<p>Copyright © 2020–2025 Muntashir Al-Islam<blockquote><p>“Khôn ngoan và chậm rãi. Những người chạy nhanh sẽ bị vấp.” <span>—\nFriar Laurence, <em>Romeo và Juliet</em></span></blockquote></div></div><section id=ch:introduction class=level1 data-number=1><h1 data-number=1><span class=header-section-number>1</span> <a href=#toc:ch:introduction>Giới thiệu</a><a href=#ch:introduction class=anchor aria-hidden=true></a></h1><p>App Manager là ứng dụng quản lý các ứng dụng khác dành cho Android.\nNó có vô số các tính năng, và do đó cần hướng dẫn sử dụng để hỗ trợ\nngười dùng. Tài liệu này đóng vai trò là hướng dẫn sử dụng cho App\nManager theo nghĩa là nó miêu tả mọi tính năng mà App Manager có. Tài\nliệu này cũng có thể được coi là “hướng dẫn” chính thức cho App Manager,\nvà đại diện cho hành vi thông thường của App Manager. Các bản dịch có\nthể làm lệch ý của tài liệu (được viết bằng tiếng Anh) này. Do đó, những\nngười dùng có hiểu biết nên đọc bản tiếng Anh của tài liệu để tận dụng\ntối đa công năng của App Manager. Ngoài ra có thể có các tài nguyên\nkhông chính thức khác như bài viết blog, video, nhóm chat, v.v. Các tài\nnguyên đó có thể giúp ích được nhiều người, nhưng chúng có khả năng là\ncũ hơn phiên bản hiện tại của App Manager. Nếu App Manager có hoạt động\nsai lệch so với tài liệu này, thì bạn nên báo cáo ở <a href=https://github.com/MuntashirAkon/AppManager/issues>nơi theo dõi\nvấn đề của App Manager</a>.<section id=sec:terminologies class=level2 data-number=1.1><h2 data-number=1.1><span class=header-section-number>1.1</span> <a href=#toc:sec:terminologies>Thuật ngữ</a><a href=#sec:terminologies class=anchor aria-hidden=true></a></h2><p>Hieucandy</section><section id=sec:supported-versions class=level2 data-number=1.2><h2 data-number=1.2><span class=header-section-number>1.2</span> <a href=#toc:sec:supported-versions>Phiên bản được hỗ trợ</a><a href=#sec:supported-versions class=anchor aria-hidden=true></a></h2><p>Hiện tại, các phiên bản được hỗ trợ là v3.0.4 và v3.1.0 (ổn định),\nv3.2.0 (bản phát hành alpha và gỡ lỗi). Các phiên bản trước của Trình\nquản lý ứng dụng có thể chứa các lỗ hổng bảo mật và không nên được sử\ndụng.</section><section id=sec:official-sources class=level2 data-number=1.3><h2 data-number=1.3><span class=header-section-number>1.3</span> <a href=#toc:sec:official-sources>Nguồn chính thức</a><a href=#sec:official-sources class=anchor aria-hidden=true></a></h2><section id=subsec:binary-distribution-sources class=level3 data-number=1.3.1><h3 data-number=1.3.1><span class=header-section-number>1.3.1</span>\n<a href=#toc:subsec:binary-distribution-sources>Nguồn phân phối tệp\nnhị phân</a><a href=#subsec:binary-distribution-sources class=anchor aria-hidden=true></a></h3><p>App Manager is distributed using the following sources. Unofficial\nsources may distribute modified versions of App Manager, and you alone\nshall be responsible for the consequences of using such a\ndistribution.<ol class=incremental><li><p>Official F-Droid repository.<a href=#fn1 class=footnote-ref id=fnref1 role=doc-noteref><sup>1</sup></a><br><em>Link:</em> <a href=https://f-droid.org/packages/io.github.muntashirakon.AppManager class=uri>https://f-droid.org/packages/io.github.muntashirakon.AppManager</a><li><p>GitHub repository.<br><em>Normal releases:</em> <a href=https://github.com/MuntashirAkon/AppManager/releases class=uri>https://github.com/MuntashirAkon/AppManager/releases</a><br><em>Debug releases:</em> <a href=https://github.com/MuntashirAkon/AMInsecureDebugBuilds class=uri>https://github.com/MuntashirAkon/AMInsecureDebugBuilds</a><li><p>Telegram.<br><em>Normal releases:</em> <a href=https://t.me/AppManagerChannel class=uri>https://t.me/AppManagerChannel</a><br><em>Debug releases:</em> <a href=https://t.me/AppManagerDebug class=uri>https://t.me/AppManagerDebug</a></ol></section><section id=subsec:links-to-source-code class=level3 data-number=1.3.2><h3 data-number=1.3.2><span class=header-section-number>1.3.2</span>\n<a href=#toc:subsec:links-to-source-code>Liên kết đến mã nguồn</a><a href=#subsec:links-to-source-code class=anchor aria-hidden=true></a></h3><p>Tất cả trừ GitHub là các liên kết nhân bản. Các thẻ phải luôn được\ncập nhật, nhưng nhánh chính không được đảm bảo là cập nhật. Nếu mục tiêu\nlà sao chép nhánh chính, hãy sử dụng liên kết GitHub thay vì các liên\nkết khác.<ol class=incremental><li><p>GitHub: <a href=https://github.com/MuntashirAkon/AppManager class=uri>https://github.com/MuntashirAkon/AppManager</a><li><p>Codeberg: <a href=https://codeberg.org/muntashir/AppManager class=uri>https://codeberg.org/muntashir/AppManager</a><li><p>GitLab: <a href=https://gitlab.com/muntashir/AppManager class=uri>https://gitlab.com/muntashir/AppManager</a><li><p>Riseup: <a href=https://0xacab.org/muntashir/AppManager class=uri>https://0xacab.org/muntashir/AppManager</a><li><p>sourcehut: <a href=https://git.sr.ht/~muntashir/AppManager class=uri>https://git.sr.ht/~muntashir/AppManager</a></ol></section><section id=subsec:translations class=level3 data-number=1.3.3><h3 data-number=1.3.3><span class=header-section-number>1.3.3</span>\n<a href=#toc:subsec:translations>Bản dịch</a><a href=#subsec:translations class=anchor aria-hidden=true></a></h3><p>Trình quản lý ứng dụng không chấp nhận bản dịch trực tiếp thông qua\nyêu cầu kéo/hợp nhất. Các bản dịch được quản lý thông qua Hosted\nWeblate. Để dịch Trình quản lý ứng dụng, hãy truy cập <a href=https://hosted.weblate.org/engage/app-manager/ class=uri>https://hosted.weblate.org/engage/app-manager/</a>.</section></section><section id=sec:contributing class=level2 data-number=1.4><h2 data-number=1.4><span class=header-section-number>1.4</span> <a href=#toc:sec:contributing>Đóng góp</a><a href=#sec:contributing class=anchor aria-hidden=true></a></h2><p>Có nhiều cách người dùng có thể đóng góp, chẳng hạn như tạo các vấn\nđề hữu ích, tham dự các cuộc thảo luận, cải thiện tài liệu và bản dịch,\nthêm các thư viện hoặc trình theo dõi không được công nhận, xem lại mã\nnguồn cũng như báo cáo lỗ hổng bảo mật.<section id=subsec:build-instructions class=level3 data-number=1.4.1><h3 data-number=1.4.1><span class=header-section-number>1.4.1</span>\n<a href=#toc:subsec:build-instructions>Hướng dẫn xây dựng</a><a href=#subsec:build-instructions class=anchor aria-hidden=true></a></h3><p>Hướng dẫn xây dựng có sẵn trong tệp BUILDING nằm ở thư mục gốc của mã\nnguồn.</section><section id=subsec:submitting-patches class=level3 data-number=1.4.2><h3 data-number=1.4.2><span class=header-section-number>1.4.2</span>\n<a href=#toc:subsec:submitting-patches>Gửi bản vá</a><a href=#subsec:submitting-patches class=anchor aria-hidden=true></a></h3><p>Repositories located on sites other than GitHub are currently\nconsidered mirrors, and pull/merge requests submitted on those sites\nwill not be accepted.<a href=#fn2 class=footnote-ref id=fnref2 role=doc-noteref><sup>2</sup></a> Instead, patches (as\n<code>.patch</code> files) can be submitted via email attachments.\n<em>Signing-off is a requirement.</em> See the CONTRIBUTING file located\nat the source root for more information.<div class=\"amalert warning\"><p><strong><em>Notice.</em></strong><p>In the case of submitting patches via email, the whole conversation\nmay be publicly accessible in the future. So, please do not include\npersonally identifiable information (PII) other than your name or email\naddress.</div></section></section><section id=sec:donation-&-funding class=level2 data-number=1.5><h2 data-number=1.5><span class=header-section-number>1.5</span> <a href=#toc:sec:donation-&-funding>Ủng hộ & Tài chính</a><a href=#sec:donation-&-funding class=anchor aria-hidden=true></a></h2><p>As of September 2024, App Manager is not accepting financial support\nuntil further notice. But you may still be able to send gifts (e.g.,\ngift cards, subscriptions, food and drink, flowers, or even cash).\nPlease reach out to the maintainer using the options given in §<a href=#sec:contact data-reference-type=ref data-reference=sec:contact>1.6</a> for further assistance.<p>In addition, the maintainers and contributors of this project DO NOT\nconsent to the creation, sale, or promotion of tokens, cryptocurrencies,\nNFTs, or any other financial instruments that claim to represent this\nproject, its code, or its community. Any such attempts are unauthorized\nand not affiliated with this project in any way.</section><section id=sec:contact class=level2 data-number=1.6><h2 data-number=1.6><span class=header-section-number>1.6</span> <a href=#toc:sec:contact>Liên hệ</a><a href=#sec:contact class=anchor aria-hidden=true></a></h2><p>App Manager Community<br>Email: <a href=mailto:am4android@riseup.net>am4android [at] riseup\n[dot] net</a><br>GitHub: <a href=https://github.com/AMCommunity class=uri>https://github.com/AMCommunity</a><br>Twitter/X: <a href=https://x.com/AppManagerNews class=uri>https://x.com/AppManagerNews</a><br>Mastodon: <a href=https://floss.social/@appmanager>@appmanager@floss.social</a><br><br>Muntashir Al-Islam<a href=#fn3 class=footnote-ref id=fnref3 role=doc-noteref><sup>3</sup></a><br>Email: <a href=mailto:muntashirakon@riseup.net>muntashirakon [at]\nriseup [dot] net</a><br>GitHub: <a href=https://github.com/MuntashirAkon class=uri>https://github.com/MuntashirAkon</a><br>Twitter/X: <a href=https://x.com/Muntashir class=uri>https://x.com/Muntashir</a><br>Mastodon: <a href=https://infosec.exchange/@muntashir>@muntashir@infosec.exchange</a></section></section><section id=ch:pages class=level1 data-number=2><h1 data-number=2><span class=header-section-number>2</span> <a href=#toc:ch:pages>Trang</a><a href=#ch:pages class=anchor aria-hidden=true></a></h1><section id=sec:main-page class=level2 data-number=2.1><h2 data-number=2.1><span class=header-section-number>2.1</span> <a href=#toc:sec:main-page>Trang chính</a><a href=#sec:main-page class=anchor aria-hidden=true></a></h2><p>Main page lists all the installed, uninstalled and backed up\napplications. A single click on any installed application item opens the\nrespective <a href=#sec:app-details-page>App Details page</a>. For the\nuninstalled system applications, a dialog prompt is displayed with an\noption reinstall them. The applications uninstalled without removing\ntheir data and signatures are also displayed in this page with an option\nto perform a full uninstallation. For the uninstalled applications\nhaving one or more backups, the restore dialog is displayed. Using the\n<a href=#par:main-page-sort>sort</a> option from the list options, the\nitems can be sorted in various ways. It is also possible to filter items\nusing the <a href=#par:main-page-filter>filter</a> option in the list\noptions. Filtering is also possible from the search bar with additional\nsupport for the regular expressions.<figure id=fig:main_page_entry_info_labeled><figure><object data=../images/main_page_entry_info_labeled.svg type=image/svg+xml></object></figure><figcaption>Figure 1: Một mục danh sách ứng dụng trong trang\nchính</figcaption></figure><section id=subsec:batch-operations class=level3 data-number=2.1.1><h3 data-number=2.1.1><span class=header-section-number>2.1.1</span>\n<a href=#toc:subsec:batch-operations>Hoạt động hàng loạt</a><a href=#subsec:batch-operations class=anchor aria-hidden=true></a></h3><p>Batch operations or operations on multiple applications are also\navailable within this page. Multiple selection mode can be activated by\nclicking on the app icon of an item or by long-clicking on any items in\nthe list. Once activated, a click on an item selects it instead of\nopening the App Details page. In this mode, the batch operations are\nlocated in the multiple selection menu at the bottom of the page. The\noperations include:<ul class=incremental><li><p>Adding the selected applications to a <a href=#sec:profiles-page>profile</a><li><p><a href=#sec:backup-restore>Backing up applications</a>, or\nrestoring and deleting the existing backups<li><p>Blocking the trackers from the applications<li><p>Clearing data or cache from the applications<li><p>Exporting the blocking rules configured inside App\nManager<li><p>Exporting the list of applications in Markdown, CSV, JSON or XML\nformat<li><p>Freezing/unfreezing/force-stopping/uninstalling the\napplications<li><p>Performing run-time optimization of the applications (Android 7\nonwards)<li><p>Preventing the background operations of the applications (Android\n7 onwards)<li><p>Saving the APK files to <code>AppManager/apks</code><li><p>Setting <a href=#sec:net-policy>net policies</a></ul><div class=\"amalert tip\"><p><strong><em>Accessibility.</em></strong><p>After the multiple selection mode has been activated, it is possible\nto navigate in or out of the multiple selection menu using the right or\nleft keys of the keyboard or remote.</div></section><section id=subsec:main-colour-codes class=level3 data-number=2.1.2><h3 data-number=2.1.2><span class=header-section-number>2.1.2</span>\n<a href=#toc:subsec:main-colour-codes>Mã màu</a><a href=#subsec:main-colour-codes class=anchor aria-hidden=true></a></h3><ul class=incremental><li><p><span class=colorbox style=background-color:#ff0000b3><span style=color:#000>Red (day)</span></span> / <span class=colorbox style=background-color:#790d0d><span style=color:#fff>dark red (night)</span></span> – Uninstalled\napplication<li><p><span class=colorbox style=background-color:#ff8a80><span style=color:#000>Light red (day)</span></span> / <span class=colorbox style=background-color:#4f1c14bf><span style=color:#fff>very\ndark red (night)</span></span> – Frozen application<li><p><span class=colorbox style=background-color:#09868b><span style=color:#fff>Dark cyan</span></span> – Force-stopped\napplication<li><p><span class=colorbox style=background-color:#ff0><span style=color:#000>Yellow Star</span></span> – Debuggable\napplication<li><p><span style=color:#e05915>Orange <em>Date</em></span> – The\napplication can read system logs<li><p><span style=color:#e05915>Orange <em>UID</em></span> – The\nuser ID is being shared among multiple applications<li><p><span style=color:#e05915>Orange <em>SDK</em></span> – The\napplication possibly uses cleartext (i.e. HTTP) traffic<li><p><span style=color:#ff8017>Light orange <em>package\nname</em></span> – The application has one or more trackers<li><p><span style=color:red>Red <em>app label</em></span> – The\napplication does not allow clearing its data<li><p><span style=color:#09868b>Dark cyan <em>version</em></span>\n– Inactive application<li><p><span style=color:#f0f>Magenta type</span> – Persistent\napplication i.e. it remains running all the time<li><p><span style=color:red>Red <em>backup</em></span> – The\nuninstalled application with one or more backups present in App\nManager<li><p><span style=color:#e05915>Orange <em>backup</em></span> –\nOutdated backup, i.e. the base backup contains an older version of the\ninstalled application<li><p><span style=color:#09868b>Dark cyan <em>backup</em></span>\n– Up to date backup, i.e. the base backup contains the same or higher\nversion of the installed application.</ul></section><section id=subsec:main-page-application-types class=level3 data-number=2.1.3><h3 data-number=2.1.3><span class=header-section-number>2.1.3</span>\n<a href=#toc:subsec:main-page-application-types>Các loại ứng\ndụng</a><a href=#subsec:main-page-application-types class=anchor aria-hidden=true></a></h3><p>An application can be either a <strong>User</strong> or a\n<strong>System</strong> application along with the following\nsuffixes:<ul class=incremental><li><p><code>X</code> – Supports multiple architectures<li><p><code>0</code> – No dex files present in the application<li><p><code>°</code> – Suspended application<li><p><code>#</code> – The application requested the system to allocate\na large heap i.e. large runtime memory<li><p><code>?</code> – The application requested the virtual machine to\nbe in the safe mode.</ul></section><section id=subsec:main-page-version-info class=level3 data-number=2.1.4><h3 data-number=2.1.4><span class=header-section-number>2.1.4</span>\n<a href=#toc:subsec:main-page-version-info>Thông tin phiên bản</a><a href=#subsec:main-page-version-info class=anchor aria-hidden=true></a></h3><p>Version name is followed by the prefixes below:<ul class=incremental><li><p><code>_</code> – No hardware acceleration (breaking the in-app\nanimations or transparencies)<li><p><code>~</code> – Test-only application<li><p><code>debug</code> – Debuggable application</ul></section><section id=subsec:main-page-options-menu class=level3 data-number=2.1.5><h3 data-number=2.1.5><span class=header-section-number>2.1.5</span>\n<a href=#toc:subsec:main-page-options-menu>Trình đơn tùy chọn</a><a href=#subsec:main-page-options-menu class=anchor aria-hidden=true></a></h3><p>Menu tùy chọn cung cấp một số tùy chọn có thể được sử dụng để sắp xếp\nvà lọc các ứng dụng được liệt kê cũng như để điều hướng đến các trang\nkhác nhau trong hoặc ngoài Trình quản lý ứng dụng.<section id=subsubsec:main-list-options class=level4 data-number=2.1.5.1><h4 data-number=2.1.5.1><span class=header-section-number>2.1.5.1</span> Tùy chọn danh sách<a href=#subsubsec:main-list-options class=anchor aria-hidden=true></a></h4><p><strong>Liệt kê các tùy chọn</strong> chứa các tùy chọn để sắp xếp và\nlọc danh sách trong trang chính.<section id=sắp-xếp class=level5 data-number=2.1.5.1.1><h5 data-number=2.1.5.1.1><span class=header-section-number>2.1.5.1.1</span> Sắp xếp<a href=#sắp-xếp class=anchor aria-hidden=true></a></h5><div id=par:main-page-sort></div><p>The applications listed in the main page can be sorted in the\nfollowing ways:<ul class=incremental><li><p><strong>User apps first.</strong> The user applications are\nlisted on top<li><p><strong>App label.</strong> Sort the list in ascending order\nbased on their application labels (also known as <em>application\nnames</em>). This is the default sorting preference<li><p><strong>Package name.</strong> Sort the list in ascending order\nbased on their package names<li><p><strong>Last update.</strong> Sort the list in descending order\nbased on the date they were last updated<li><p><strong>Shared user ID.</strong> Sort the list in descending\norder based on their kernel user ID<li><p><strong>Target SDK.</strong> Sort the list in ascending order\nbased on their target SDK<li><p><strong>Signature.</strong> Sort the list in ascending order\nbased on their signing information<li><p><strong>Frozen first.</strong> The frozen applications are listed\non the top<li><p><strong>Blocked first.</strong> Sort the list in descending order\nbased on the number of blocked components each application has<li><p><strong>Backed up first.</strong> Display the applications with\nbackups on the top<li><p><strong>Trackers.</strong> Sort the list in descending order\nbased on the number of tracker components each application has<li><p><strong>Last actions.</strong> Sort the list in descending order\nbased on the latest time and date of any actions made to the\napplications within App Manager.<li><p><strong>Installation date.</strong> Sort the list by the date of\ninstallation in descending order.<li><p><strong>Total size.</strong> Sort the list by the total size of\nthe applications and their data in descending order. Requires\n<code>Usage Access</code> permission.<li><p><strong>Data usage.</strong> Sort the list by the total data\nusage in descending order. Requires <code>Usage Access</code>\npermission.<li><p><strong>Times opened.</strong> List frequently used applications\non top. Requires <code>Usage Access</code> permission.<li><p><strong>Screen time.</strong> List the applications with the\nhighest engagements on top. Requires <code>Usage Access</code>\npermission.<li><p><strong>Last used.</strong> List last used apps on top. Requires\n<code>Usage Access</code> permission.</ul><p>In addition, there is the <em>reverse</em> option that can be used to\nsort the list in the reverse order. Regardless of the sorting\npreferences, the applications are sorted alphabetically at first in\norder to prevent producing any random sorting results.</section><section id=lọc class=level5 data-number=2.1.5.1.2><h5 data-number=2.1.5.1.2><span class=header-section-number>2.1.5.1.2</span> Lọc<a href=#lọc class=anchor aria-hidden=true></a></h5><div id=par:main-page-filter></div><p>The applications listed in the main page can be filtered in the\nfollowing ways:<ul class=incremental><li><p><strong>User apps.</strong> List only the user\napplications<li><p><strong>System apps.</strong> List only the system\napplications<li><p><strong>Frozen apps.</strong> List only the frozen\napplications<li><p><strong>Stopped apps.</strong> List only the applications that\nwere forced-stopped<li><p><strong>Installed apps.</strong> List only the installed\napplications<li><p><strong>Uninstalled apps.</strong> List only the uninstalled\napplications<li><p><strong>With rules.</strong> List the applications with one or\nmore blocking rules<li><p><strong>With activities.</strong> List the applications with one\nor more activities<li><p><strong>With backups.</strong> List the applications with one or\nmore backups<li><p><strong>Without backups.</strong> List the applications with no\nbackups present.<li><p><strong>Running apps.</strong> List the applications that are\ncurrently running<li><p><strong>With splits.</strong> List the applications with one or\nmore split APK files<li><p><strong>With KeyStore.</strong> List only the applications with\nAndroid KeyStore.<li><p><strong>With SAF.</strong> List only the applications with SAF\naccess.<li><p><strong>With SSAID.</strong> List only the applications with a\nvalid SSAID.</ul><p>Unlike sorting, it is possible to apply more than one filtering\noptions at the same time. For example, the frozen user applications can\nbe listed by selecting both <em>User apps</em> and <em>Frozen apps</em>.\nThis can be particularly useful for <a href=#subsec:batch-operations>batch operations</a> where filtering the\nuser applications may be necessary to carry out certain operations\nsafely.<div class=\"amalert warning\"><p><strong><em>Inconsistencies.</em></strong><p>App Manager extensively caches everything in this page. Therefore,\ncertain states (e.g., freeze and stopped states) may not always be\nup-to-date.</div></section><section id=tên-hồ-sơ class=level5 data-number=2.1.5.1.3><h5 data-number=2.1.5.1.3><span class=header-section-number>2.1.5.1.3</span> Tên hồ sơ<a href=#tên-hồ-sơ class=anchor aria-hidden=true></a></h5><p>It is also possible to list the applications that are only present in\na <a href=#sec:profiles-page>profile</a>. This can be useful for\ncarrying out certain operations on a profile (e.g., uninstalling all the\napplications in a profile) that cannot be done via the <a href=#sec:profiles-page>Profiles page</a>.</section></section><section id=hướng-dẫn-sử-dụng class=level4 data-number=2.1.5.2><h4 data-number=2.1.5.2><span class=header-section-number>2.1.5.2</span> Hướng dẫn sử dụng<a href=#hướng-dẫn-sử-dụng class=anchor aria-hidden=true></a></h4><p>Clicking on the <strong>User manual</strong> opens the offline\nversion of the App Manager user manual. It may also open the online\nversion if the corresponding feature split i.e. <code>feat_docs</code>\nis not installed, or if an WebView is not present in the system to load\nthe manual.</section><section id=subsubsec:main:1-click-ops class=level4 data-number=2.1.5.3><h4 data-number=2.1.5.3><span class=header-section-number>2.1.5.3</span> 1-Nhấp vào Hoạt động<a href=#subsubsec:main:1-click-ops class=anchor aria-hidden=true></a></h4><p><strong>1-Click Ops</strong> stands for the single-click operations.\nIt opens the <a href=#sec:1-click-ops-page>corresponding page</a> in a\nnew activity.</section><section id=sử-dụng-ứng-dụng class=level4 data-number=2.1.5.4><h4 data-number=2.1.5.4><span class=header-section-number>2.1.5.4</span> Sử dụng ứng dụng<a href=#sử-dụng-ứng-dụng class=anchor aria-hidden=true></a></h4><p>Application usage statistics, such as <em>screen time</em>, <em>data\nusage</em> (both mobile and Wi-Fi), <em>number of times an app was\nopened</em>, can be accessed by clicking on the <strong>App\nUsage</strong> option in the menu. However, it requires the <em>Usage\nAccess</em> permission. This menu item will not be listed if the usage\naccess feature is disabled in <a href=#subsubsec:enable/disable-features>settings</a>.</section><section id=subsubsec:main:running-apps class=level4 data-number=2.1.5.5><h4 data-number=2.1.5.5><span class=header-section-number>2.1.5.5</span> Đang chạy các ứng dụng<a href=#subsubsec:main:running-apps class=anchor aria-hidden=true></a></h4><p>This menu item opens a new page where a list of running applications\nor processes are displayed. It also displays the current memory and\ncache (if available) usage. If root or ADB is not available to App\nManager, it only displays itself in the recent versions of Android. The\nrunning applications or processes can also be force-stopped or killed\nwithin the resultant page. Logs for each process ID (PID) can also be\nviewed in the <a href=#subsubsec:main:labs>log viewer</a>. In\naddition, it is also possible to carry out batch operations either by\nclicking on the icon or by long-clicking on an item. Normal click on any\nitems opens a dialog where a more detailed information is displayed.</section><section id=hồ-sơ class=level4 data-number=2.1.5.6><h4 data-number=2.1.5.6><span class=header-section-number>2.1.5.6</span> Hồ sơ<a href=#hồ-sơ class=anchor aria-hidden=true></a></h4><p>This menu item opens the <a href=#sec:profiles-page>profiles\npage</a>. Profiles are a way to configure regularly used tasks. They can\nalso be invoked via shortcuts.</section><section id=trình-cập-nhật-apk class=level4 data-number=2.1.5.7><h4 data-number=2.1.5.7><span class=header-section-number>2.1.5.7</span> Trình cập nhật APK<a href=#trình-cập-nhật-apk class=anchor aria-hidden=true></a></h4><p>If the app <a href=https://github.com/rumboalla/apkupdater>APK\nUpdater</a> is installed in the system, it can be opened directly via\nthis menu item. The option remains hidden if the app is not present in\nthe system.</section><section id=termux class=level4 data-number=2.1.5.8><h4 data-number=2.1.5.8><span class=header-section-number>2.1.5.8</span> Termux<a href=#termux class=anchor aria-hidden=true></a></h4><p>If the app <a href=https://github.com/termux/termux-app>Termux</a>\nis installed in the system, the running session (or a new session) can\nbe opened directly via this menu item. The option remains hidden if the\napp is not present in the system.</section><section id=debloater class=level4 data-number=2.1.5.9><h4 data-number=2.1.5.9><span class=header-section-number>2.1.5.9</span> Debloater<a href=#debloater class=anchor aria-hidden=true></a></h4><p>This menu item opens the debloater page that lists all the bloatware\navailable in the device and in App Manager. It also suggests alternative\napplications based on the criteria set by the <a href=https://github.com/MuntashirAkon/android-debloat-list>Android\nDebloat List</a> project.</section><section id=subsubsec:main:labs class=level4 data-number=2.1.5.10><h4 data-number=2.1.5.10><span class=header-section-number>2.1.5.10</span> Labs<a href=#subsubsec:main:labs class=anchor aria-hidden=true></a></h4><p>This menu item opens the labs page that lists all the additional\nfeatures. They include Log Viewer, System Config, Terminal, File Manager\n(as Files), UI Tracker, Interceptor, and Code Editor pages.</section><section id=cài-đặt class=level4 data-number=2.1.5.11><h4 data-number=2.1.5.11><span class=header-section-number>2.1.5.11</span> Cài đặt<a href=#cài-đặt class=anchor aria-hidden=true></a></h4><p>This menu item opens the in-app <a href=#sec:settings-page>Settings\npage</a>.</section></section></section><section id=sec:app-details-page class=level2 data-number=2.2><h2 data-number=2.2><span class=header-section-number>2.2</span> <a href=#toc:sec:app-details-page>App Details Page</a><a href=#sec:app-details-page class=anchor aria-hidden=true></a></h2><p><strong>App Details</strong> page consists of 11 (eleven) tabs. It\ndescribes almost every bit of information an application usually has,\nincluding all attributes from its manifest, <a href=#ch:app-ops>application operations</a> (app ops), signing\ninformation, libraries, and so on.<section id=subsec:app-details-colour-codes class=level3 data-number=2.2.1><h3 data-number=2.2.1><span class=header-section-number>2.2.1</span>\n<a href=#toc:subsec:app-details-colour-codes>Colour Codes</a><a href=#subsec:app-details-colour-codes class=anchor aria-hidden=true></a></h3><p>List of colours used in this page, and their meaning:<ul class=incremental><li><p><span class=colorbox style=background-color:#ff0000b3><span style=color:#000>Red (day)</span></span> / <span class=colorbox style=background-color:#790d0d><span style=color:#fff>dark red (night)</span></span> – Denotes any app\nops or permissions having the dangerous flag, or any components blocked\nwithin App Manager, or any unsupported but required features.<li><p><span class=colorbox style=background-color:#ff8a80><span style=color:#000>Light red (day)</span></span> / <span class=colorbox style=background-color:#4f1c14bf><span style=color:#fff>very\ndark red (night)</span></span> – Denotes the components disabled outside\nof App Manager, or any unsupported but optional features.<div class=\"amalert tip\"><p><strong><em>Note.</em></strong><p>A component marked as disabled does not always mean that it is\ndisabled by the user: It could also be disabled by the system or marked\nas disabled in its manifest. The components of a disabled application\nare also considered disabled by the system (and App Manager).</div><li><p><span class=colorbox style=background-color:#ff8017><span style=color:#000>Vivid orange (day)</span></span> / <span class=colorbox style=background-color:#ff801780><span style=color:#fff>very\ndark orange (night)</span></span> – Denotes the tracker\ncomponents<li><p><span class=colorbox style=background-color:#ea80fc><span style=color:#000>Soft magenta (day)</span></span> / <span class=colorbox style=background-color:#431c5d><span style=color:#fff>very dark violet (night)</span></span> – Denotes\nthe running services.<li><p><span class=colorbox style=background-color:#1b8654><span style=color:#fff>Green</span></span> – Used in the tracker-indicator\ntag to denote that all the trackers in the application are\nblocked.</ul></section><section id=subsec:app-info-tab class=level3 data-number=2.2.2><h3 data-number=2.2.2><span class=header-section-number>2.2.2</span>\n<a href=#toc:subsec:app-info-tab>App Info Tab</a><a href=#subsec:app-info-tab class=anchor aria-hidden=true></a></h3><p><strong>App Info</strong> tab contains general information about an\napplication. It also lists many actions that can be performed within\nthis tab.<section id=subsubsec:app-info-general-information class=level4 data-number=2.2.2.1><h4 data-number=2.2.2.1><span class=header-section-number>2.2.2.1</span> General Information<a href=#subsubsec:app-info-general-information class=anchor aria-hidden=true></a></h4><p>The list below is in the same order as listed in the App Info\ntab.<ul class=incremental><li><p><strong>Application Icon.</strong> The application icon. If the\napplication does not have an icon, the system default icon will be\ndisplayed. It is also possible to verify the APK signature via SHA or\nMD5 sums stored in the clipboard by simply clicking on it.<li><p><strong>Application Label.</strong> The application label or the\nname of the application.<li><p><strong>Package Name.</strong> The name of the application\npackage. Clicking on the name stores it in the clipboard.<li><p><strong>Version.</strong> The application version is divided into\ntwo parts. The first part is called <em>version name</em>. The format of\nthis part varies but often consists of multiple integers separated by\ndots. The second part is called <em>version code</em>. It is enclosed by\nthe first brackets. The version code is an integer used to differentiate\nbetween application versions (since a version name can be unreadable to\na machine). In general, a new version of an application has higher\nversion code than the old ones. For example, if <code>123</code> and\n<code>125</code> are two version codes of an application, we can say\nthat the latter is more updated than the former because the version code\nof the latter is higher. An application that serves different APK files\nfor the same version on different platforms (mobile, tabs, desktops,\netc.) or architectures (32/64 bit, ARM or Intel), the version numbers\ncan be misleading as they often add prefixes for each platform.<li><p><strong>Tags.</strong> (Also known as tag clouds) Tags include\nthe most basic, concise and useful information of an application. See\n§<a href=#subsubsec:tags data-reference-type=ref data-reference=subsubsec:tags>2.2.2.2</a> for a complete list of tags\nshown here.<li><p><strong>Horizontal Action Panel.</strong> An action panel\nconsisting of various actions that can be carried out for the\napplication. See §<a href=#subsubsec:horizontal-action-panel data-reference-type=ref data-reference=subsubsec:horizontal-action-panel>2.2.2.3</a> for a\ncomplete list of actions available here. Additional actions are\navailable in the <a href=#subsubsec:app-info-options-menu>options\nmenu</a>.<li><p><strong>Paths & Directories.</strong> Contains various\ninformation regarding application paths including <em>app directory</em>\n(where the APK files reside), <em>data directories</em> (internal,\ndevice protected and externals), and <em>JNI library directory</em> (if\npresent). JNI libraries are used to invoke native codes usually written\nin C/C++. Use of native library can make the application run faster or\nhelp an application use third-party libraries written using languages\nother than Java like in most games. The directories can be opened via\nfile managers provided they support it and have the necessary\npermissions, by clicking on the launch button on the right-hand side of\na directory item.<li><p><strong>Data Usage.</strong> Amount of data used by the\napplication as reported by the operating system. Depending on Android\nversion, this may require a wide range of permissions including\n<em>Usage Access</em> and <em>Telephony</em> permissions.<li><p><strong>Storage & Cache.</strong> Displays information\nregarding the size of the application (APK files, optimised files), data\nand cache. In older devices, size of external data, cache, media and OBB\nfolders are also displayed. This part remains hidden if <em>Usage\nAccess</em> permission is not granted in the newer devices.<li><p><strong>More Info.</strong> Displays other information such\nas–<ul class=incremental><li><p><strong>SDK.</strong> Displays information related to the Android\nSDK: <em>Max</em> denotes the target SDK and <em>Min</em> denotes the\nminimum SDK (the latter is not available in Android Lollipop). If the\ntarget SDK value is less than the platform SDK (i.e., the highest SDK\nthe current operating system supports), the application will run in the\ncompatibility mode. This means the application may have access to\ncertain features that are unavailable or restricted in a newer version\nof Android, which can be a security and/or privacy issue. SDK is also\nknown as <strong>API Level</strong>.<br><div class=seealso-inline><p><em>Bạn cũng có thể xem: <span><a href=https://en.wikipedia.org/wiki/Android_version_history#Overview>Android\nVersion History</a></span></em></div><li><p><strong>Flags.</strong> The application flags used at the time of\nbuilding the application. For a complete list of flags and what they do,\nread the <a href=https://developer.android.com/reference/android/content/pm/ApplicationInfo#flags>official\ndocumentation</a>.<li><p><strong>Date Installed.</strong> The date when the application\nwas first installed.<li><p><strong>Date Updated.</strong> The date when the application was\nlast updated. This is the same as <em>Date Installed</em> if the\napplication hasn’t been updated.<li><p><strong>Process Name.</strong> The name of the process if it is\ndifferent from the package name. Process name is set when an application\nis being started by the system, and is usually the same as the package\nname.<li><p><strong>Installer App.</strong> The application that installed\nthis application. The installer application may not always be the same\nas the application that installed this application, because Android\nallows setting an arbitrary value for this field. In Android 11 onwards,\nthe actual installer application is also stored by the system which can\nbe accessed by clicking the “Info” button on the right-hand side of the\nitem. The field will not be visible if the installer application is not\nreported by the system (e.g., due to the installer application being\nuninstalled or hidden). Installer application may be granted additional\nprivileges by the system so that it can control certain behaviour of the\napplication it installs.<li><p><strong>User ID.</strong> The unique user ID set by the system to\nthe application. For shared applications, the same user ID is assigned\nto multiple applications having the same <em>Shared User\nID</em>.<li><p><strong>Shared User ID.</strong> Applicable for applications that\nare shared together. The shared application must have the same <a href=#subsec:signatures-tab>signatures</a>.<li><p><strong>Primary ABI.</strong> Architecture supported by this\nplatform for this application.<li><p><strong>Zygote preload name.</strong> Responsible for preloading\napplication code and data shared across all the isolated services that\nuses app zygote.<li><p><strong>Hidden API enforcement policy.</strong> Since Android 9,\nmany methods and classes in Android framework have been made\ninaccessible to the third-party applications through hidden API\nenforcement policy. It has the following options:<ul class=incremental><li><p><em>Default.</em> Based on the type of application. For system\napplications, it should be disabled, and for others, it should be\nenforced.<li><p><em>None/disabled.</em> The application has full access to the\nhidden API as it used to be before Android 9.<li><p><em>Warn.</em> Same as above, except that warnings will be logged\neach time the application accesses the hidden API. This is mostly\nunused.<li><p><em>Enforce.</em> The application cannot access hidden API,\neither dark-grey list or blacklist, or both of them. This is the default\noption for the third-party applications in Android 9 onwards unless the\napplication is whitelisted by the OEM or the vendor.<div class=\"amalert warning\"><p><strong><em>Warning.</em></strong><p>Hidden API enforcement policy is not properly implemented in Android\nand can be bypassed by the application. As a result, this value should\nnot be trusted.</div></ul><li><p><strong>SELinux.</strong> Mandatory access control (MAC) policy\nset by the operating system via SELinux.<li><p><strong>Main Activity.</strong> The main entry point to the\napplication. This is only visible if the application has <a href=#subsubsec:activities>activities</a> and any of those are\nopenable from the Launcher. There’s also a launch button on the\nright-hand side which can be used to launch this activity.</ul></ul></section><section id=subsubsec:tags class=level4 data-number=2.2.2.2><h4 data-number=2.2.2.2><span class=header-section-number>2.2.2.2</span> Tags<a href=#subsubsec:tags class=anchor aria-hidden=true></a></h4><ul class=incremental><li><p><strong>Tracker info.</strong> Number of tracker components in\nthe application (e.g., <em>5 trackers</em>) The colour of the tag\nappears orange if the trackers are unblocked and dark cyan if they are\nblocked in App Manager. Clicking on the tag opens a dialog containing\nthe list of tracker components which can also be blocked or unblocked\nprovided App Manager has sufficient privileges.<li><p><strong>Application type.</strong> User application or system\napplication. For a system application, it displays whether the\napplication is an updated version of the system application or the\napplication is installed systemless-ly via Magisk.<li><p><strong>Split APK info.</strong> Number of splits in the APK\nexcluding the base APK (e.g., <em>5 splits</em>). Clicking on the tag\nopens a dialog containing a few additional information, such as name,\ntype, and size.<li><p><strong>Debuggable.</strong> The application can be debugged over\nADB. Debuggable applications can enjoy certain functions unavailable to\na regular application. The data of the application might be accessible\nvia ADB (e.g. using <code>run-as</code> command) without any additional\npermissions.<li><p><strong>Test only.</strong> The application is a test-only\napplication. Test-only applications can enjoy certain functions\nunavailable to a regular application. The data of the application might\nbe accessible via ADB (e.g. using <code>run-as</code> command) without\nany additional permissions.<li><p><strong>No code.</strong> The application does not have any code\nassociated with it i.e., DEX files aren’t present. In some system\napplications, the actual code might be located in another\nplace.<li><p><strong>Large heap.</strong> The application has requested large\nheap size i.e., more space in memory (RAM) is requested for dynamic\nallocation. It is still up to the operating system to decide whether to\nallocate large space for the application. App Manager, for example,\nrequests large heap size because it needs to load an entire APK into\nmemory while scanning an APK.<li><p><strong>Open links.</strong> The application may open certain\nlinks from any applications. If the application can open any links by\ndefault, the color of the tag would be red, dark cyan if otherwise.\nClicking on the tag opens a dialog with the supported hosts or domains\nlisted. In Android 12 onwards, it displays an option to enable or\ndisable opening links by default provided App Manager has sufficient\npermissions. Otherwise, it displays an option to open the system\nsettings page for the application.<li><p><strong>Running.</strong> One or more services of the application\nis currently running in the background. Clicking on the tag opens a\ndialog containing the list of running services. Clicking on any services\nopens the log viewer with default filter set to the UID associated with\nthe service (which can be different from the UID of the application if\nit is running in a separate or isolated process) provided the log viewer\nfeature is enabled. There’s also an option to force-stop the\napplication.<li><p><strong>Stopped.</strong> The application is force stopped. This\nmay not prevent it from running automatically later.<li><p><strong>Disabled.</strong> Denotes that the application is\ndisabled (hidden from the launcher).<li><p><strong>Suspended.</strong> Denotes that the application is\nsuspended (grayed out in the launcher).<li><p><strong>Hidden.</strong> Denotes that the application is hidden\n(hidden from the launcher).<li><p><strong>MagiskHide.</strong> MagiskHide is enabled for the\napplication. Clicking on the tag opens a dialog containing the list of\nprocess names within the application that can be added to or removed\nfrom the MagiskHide list.<li><p><strong>MagiskDenyList.</strong> The application is present in\nMagisk DenyList. Clicking on the tag opens a dialog containing the list\nof process names within the application that can be added to or removed\nfrom Magisk DenyList.<li><p><strong>WX.</strong> The application violates the “W^X policy”\nand is capable of writing and executing in the same directory or in the\nsame portion of memory. This allows the execution of arbitrary\nexecutables either by the modification of executables embedded within\nthe application or by downloading them from the Internet.<br><div class=seealso-inline><p><em>Bạn cũng có thể xem: <span><a href=https://en.wikipedia.org/wiki/W%5EX>W^X in\nWikipedia</a></span></em></div><li><p><strong>Bloatware.</strong> The application may be a known\nbloatware. Clicking on the tag opens a dialog containing detailed\ninformation in addition to suggestions (if available).<li><p><strong>KeyStore.</strong> The application has items in the\nAndroid KeyStore. Clicking on the tag opens a dialog containing all the\nKeyStore files that belong to the application.<li><p><strong>Backup.</strong> The application was backed up using App\nManager at least once. Clicking on the tag opens a dialog containing all\nthe available backups along with metadata.<li><p><strong>No battery optimisation.</strong> Battery optimisation is\ndisabled for the application. It is possible to re-enable battery\noptimisation by clicking on the tag.<li><p><strong>Sensors disabled.</strong> Sensors are disabled for the\napplication. Sensors are disabled for most applications by\ndefault.<li><p><a href=#sec:net-policy><strong>Net policy.</strong></a>\nNetwork policy (e.g., background data usage) is configured for the\napplication. Clicking on the tag displays a dialog containing the\nsupported policies for the platform along with the options to configure\nthem.<li><p><a href=#sec:terminologies><strong>SSAID.</strong></a> Clicking\non the tag opens a dialog containing the current SSAID assigned to the\napplication. It is also possible to reset/regenerate the SSAID if\nneeded.<li><p><strong>SAF.</strong> Denotes that the application has been\ngranted to access one or more storage locations or files i.e. URIs via\nStorage Access Framework (SAF). Clicking on the tag opens a dialog\ncontaining the list of granted URIs.<li><p><strong>Play App Signing.</strong> Indicates that the application\nmight be signed by Google.<li><p><strong>Xposed.</strong> Indicates that the application may be an\nXposed module. Clicking on the tag displays a dialog with additional\ninformation.<li><p><strong>Static Shared Library.</strong> Denotes that the\napplication serves as a static shared library for one or more\napplications. Clicking on the tag opens a dialog containing a list of\ninstalled versions of the library along with an option to uninstall\nthem.<div class=\"amalert tip\"><p><strong><em>Notice.</em></strong><p>The trichrome library (supplied by Google Chrome, Vanadium or similar\nprojects) is currently the only known static shared library on\nAndroid.</div></ul></section><section id=subsubsec:horizontal-action-panel class=level4 data-number=2.2.2.3><h4 data-number=2.2.2.3><span class=header-section-number>2.2.2.3</span> Horizontal Action Panel<a href=#subsubsec:horizontal-action-panel class=anchor aria-hidden=true></a></h4><p>Horizontal Action Panel, as described in the previous section,\nconsists of various application-related actions, such as–<ul class=incremental><li><p><strong>Launch.</strong> Launch the application provided it has a\nlauncher <a href=#subsubsec:activities>activity</a>.<li><p><strong>Freeze.</strong> Freeze the application. This button is\nnot displayed if it is already frozen or the user does not have enough\nprivileges. After the application is frozen, it may be hidden from the\napp drawer depending on how it was configured. Shortcuts configured by\nthe application may also be removed. The application may only be\nunfrozen via App Manager, <code>pm</code> command or any other tools\nthat offer such a feature. Long clicking on the button opens a dialog\nwhere a shortcut can be configured to quickly freeze or unfreeze the\napplication.<li><p><strong>Uninstall.</strong> Uninstall the application with a\nprompt. In the dialog prompt, it is possible to uninstall updates of a\nsystem application, or if App Manager has enough privileges or the\noperating system supports it, it is possible to uninstall the\napplication without clearing its data and signature. For the latter\ncase, the installed application must match the signature with the\npreviously installed application if it is installed again.<div class=\"amalert tip\"><p><strong><em>Tips.</em></strong><p>A better way to reinstall an application with a different signature\nwould be to back up its data using App Manager and restore it again\nafter installing the application instead of opting to preserving data\nand signature of the application during uninstallation as this option\nmay cause undefined behaviour in the future.</div><li><p><strong>Unfreeze.</strong> Unfreeze the application. This button\nis not displayed if it is already enabled or the user does not have\nenough privileges. Similar to the <em>Freeze</em> button, long clicking\non the button opens a dialog where a shortcut can be configured to\nquickly freeze or unfreeze the application.<li><p><strong>Force Stop.</strong> Force-stop the application.<li><p><strong>Clear Data.</strong> Clear data from the application.\nThis includes any information stored in the internal and, recently, the\nexternal directories, including accounts (if set by the application),\ncache, etc. Clearing data from App Manager, for example, removes all the\nrules (the blocking is not removed though) saved within the application\n(Which is why you should always take backups of your rules). This button\nis not displayed if the user does not have enough privileges.<li><p><strong>Clear Cache.</strong> Clear the application cache. If the\napplication is running during the operation, the cache may not be\ncleared as expected.<li><p><strong>Install.</strong> Install the application, only displayed\nif the application hasn’t already been installed.<li><p><strong>What’s New.</strong> Displayed for an external\napplication if an older version of it is already installed. Clicking on\nthis button opens a dialog containing the differences between this and\nthe installed version in a version control manner. Changes include\n<em>version</em>, <em>trackers</em>, <em>permissions</em>,\n<em>components</em>, <em>signatures</em> (only checksum changes),\n<em>features</em>, <em>shared libraries</em> and <em>SDK</em>.<li><p><strong>Update.</strong> Displayed if the application has a\nhigher version code than the installed application.<li><p><strong>Reinstall.</strong> Displayed if the application has the\nsame version code as the installed application.<li><p><strong>Downgrade.</strong> Displayed if the application has a\nlower version code than the installed application.<li><p><strong>Manifest.</strong> Opens the application’s manifest file\nin a separate page. If the application has more than one split, it will\ndisplay the list of split APK files, and clicking on an item will open\nthe corresponding manifest file instead.<li><p><strong>Scanner.</strong> Scan the application in order to list\npotential trackers and libraries. It also scans the file using\nVirusTotal and fetch results from Pithus if configured.<br><div class=seealso-inline><p><em>Bạn cũng có thể xem: <span><a href=#sec:scanner-page>Scanner\npage</a></span></em></div><li><p><strong>Shared Prefs.</strong> Displays a list of shared\npreferences used by the application. Clicking on a preference item in\nthe list opens the <a href=#sec:shared-preferences-editor-page>Shared\nPreferences Editor page</a>. This option is only visible if the user has\nthe required privileges.<li><p><strong>Databases.</strong> Displays a list of databases used by\nthe application. Clicking on an item opens a list of activities that can\nopen the database. This option is only visible if the user has the\nrequired privileges.<li><p><strong>F-Droid.</strong> Open the application in the selected\n<em>F-Droid</em> client.<li><p><strong>Store.</strong> Open the application in <em>Aurora\nStore</em>. The option is only visible if <em>Aurora Store</em> is\ninstalled.</ul></section><section id=subsubsec:app-info-options-menu class=level4 data-number=2.2.2.4><h4 data-number=2.2.2.4><span class=header-section-number>2.2.2.4</span> Options Menu<a href=#subsubsec:app-info-options-menu class=anchor aria-hidden=true></a></h4><p>Options-menu is located in the top-right corner of the page. A\ncomplete description of the options present there are given below:<ul class=incremental><li><p><strong>Share.</strong> Share button can be used to share the APK\nor (if the application is has multiple splits, OBB files or any\ndependencies) <em>APKS</em> file extracted from the\napplication.<li><p><strong>Refresh.</strong> Refresh the App Info tab.<li><p><strong>View in Settings.</strong> Open the application in\nAndroid Settings.<li><p><strong>Backup/restore.</strong> Open the backup/restore\ndialog.<li><p><strong>Export blocking rules.</strong> Export rules configured\nfor the application within App Manager.<li><p><strong>Open in Termux.</strong> Open the application in Termux.\nThis actually runs <code>su - user_id</code> where <code>user_id</code>\ndenotes the application’s kernel user ID (described in §<a href=#subsubsec:app-info-general-information data-reference-type=ref data-reference=subsubsec:app-info-general-information>2.2.2.1</a>).\nThis option is only visible to the root users. See §<a href=#subsubsec:config-termux data-reference-type=ref data-reference=subsubsec:config-termux>2.2.2.5</a> to learn how to\nconfigure Termux to run commands from third-party applications.<li><p><strong>Run in Termux.</strong> Open the application via\n<code>run-as package_name</code> in Termux. This is only applicable to\nthe debuggable applications and works for both root and ADB users. See\n§<a href=#subsubsec:config-termux data-reference-type=ref data-reference=subsubsec:config-termux>2.2.2.5</a> to learn how to\nconfigure Termux to run commands from third-party applications.<li><p><strong>MagiskHide.</strong> Open a dialog containing the list of\nprocess names within the application that can be added or removed from\nthe MagiskHide list.<li><p><strong>Magisk DenyList.</strong> Open a dialog containing the\nlist of process namees within the application that can be added or\nremoved from Magisk DenyList.<li><p><strong>Battery optimisation.</strong> Enable/disable battery\noptimisation for this application.<li><p><strong>Sensors.</strong> Enable/disable sensors for this\napplication.<li><p><a href=#sec:net-policy><strong>Net policy.</strong></a>\nConfigure network policy (e.g., background data usage) for the\napplication.<li><p><strong>Extract Icon.</strong> Extract and save the application’s\nicon in the shared storage.<li><p><strong>Optimize.</strong> Perform optimisation for this\napplication. This option is for advanced users only.<li><p><strong>Add to profile.</strong> Add the application to one of\nthe configured <a href=#sec:profile-page>profiles</a>.<li><p><strong>Install for….</strong> Install the application for\nanother user and/or in the work profile if configured.</ul></section><section id=subsubsec:config-termux class=level4 data-number=2.2.2.5><h4 data-number=2.2.2.5><span class=header-section-number>2.2.2.5</span> Configuring Termux<a href=#subsubsec:config-termux class=anchor aria-hidden=true></a></h4><p>By default, Termux does not allow running commands from a third-party\napplication. To use this option, Termux v0.96 or later is required and\n<code>allow-external-apps=true</code> must be added in\n<code>~/.termux/termux.properties</code>.<div class=\"amalert tip\"><p><strong><em>Info.</em></strong><p>Enabling this option does not weaken Termux’ security. The\nthird-party applications still need to ask the user to allow running\narbitrary commands in Termux.</div></section></section><section id=subsec:component-tabs class=level3 data-number=2.2.3><h3 data-number=2.2.3><span class=header-section-number>2.2.3</span>\n<a href=#toc:subsec:component-tabs>Component Tabs</a><a href=#subsec:component-tabs class=anchor aria-hidden=true></a></h3><p><strong>Activities</strong>, <strong>Services</strong>,\n<strong>Receivers</strong> (i.e., broadcast receivers) and\n<strong>Providers</strong> (e.g., content providers) are collectively\nknown as the application components, because they offer similar features\nand share similar properties. For example, they all have a\n<em>name</em>, a <em>label</em>, an <em>icon</em>, can be enabled or\ndisabled, and can be executed via <em>Intent</em>. Application\ncomponents are the building blocks of an application and must be\ndeclared in the application manifest (with a few exceptions).\nApplication manifest is a file where application specific metadata are\nstored. The Android operating system learns what to do with the\napplication by reading the metadata.<p>Colours used in these tabs are explained in §<a href=#subsec:app-details-colour-codes data-reference-type=ref data-reference=subsec:app-details-colour-codes>2.2.1</a>. It is also\npossible to sort the list of components to display blocked or tracker\ncomponents on top of the list via the <strong>Sort</strong> option\nlocated in the three-dots menu.<section id=subsubsec:activities class=level4 data-number=2.2.3.1><h4 data-number=2.2.3.1><span class=header-section-number>2.2.3.1</span> Activities<a href=#subsubsec:activities class=anchor aria-hidden=true></a></h4><p><strong>Activities</strong> are the windows or pages that can be\nuniquely identified by the Android operating system (e.g., <em>Main\npage</em> and <em>App Details page</em> are two activities). Each\nactivity can have multiple UI components known as <em>widgets</em> or\n<em>fragments</em>, and each component can be nested or placed on top of\neach other. The developer can also choose to open external files, links,\netc. within an activity using a method called <em>intent filters</em>.\nFor example, when you open a file in your file manager, either your file\nmanager or the operating system scans the intent filters via\nPackageManager, find the activities capable of opening the file, and\nlist those activities so that you can choose your preferred\nactivity.<p>Activities that are <em>exportable</em> can be opened by any\nthird-party applications. However, Some activities may require\npermissions, and only an application having those permissions can open\nthem. In the <em>Activities</em> tab, certain activities can be launched\nvia the <strong>Launch</strong> button. If it is necessary to supply\nadditional information, such as Intent extras, data or action, long\nclicking on the <strong>Launch</strong> button opens the <a href=#sec:interceptor-page>Activity Interceptor</a> page which\nprovides such features.<div class=\"amalert tip\"><p><strong><em>Tip.</em></strong><p>No-root users can grant\n<code>android.permission.WRITE_SECURE_SETTINGS</code> via ADB to launch\n<em>non-exportable</em> activities.</div><div class=\"amalert tip\"><p><strong><em>Notice.</em></strong><p>If launching an activity throws an error, it may have certain\ndependencies which are not met (e.g., <em>App Details</em> page in App\nManager cannot be launched using the launch button, because it requires\na package name). Since the dependencies cannot be inferred\nprogrammatically, the activity may not be opened from App Manager by\ndefault.</div><p>It is also possible to create shortcuts of an activity-launch using\nthe <strong>Create shortcut</strong> button. If you need to supply\nadditional information, you can create a shortcut from the Activity\nInterceptor page instead.<div class=\"amalert danger\"><p><strong><em>Caution.</em></strong><p>If you uninstall App Manager, all shortcuts created by App Manager\nwill be lost.</div></section><section id=subsubsec:details:servcies class=level4 data-number=2.2.3.2><h4 data-number=2.2.3.2><span class=header-section-number>2.2.3.2</span> Services<a href=#subsubsec:details:servcies class=anchor aria-hidden=true></a></h4><p>Unlike <a href=#subsubsec:activities>activities</a> that users can\nsee, <strong>Services</strong> handle background tasks. For example, if\nyou’re downloading a video from the internet using your phone’s Internet\nbrowser, the Internet browser is using a <em>foreground service</em> to\ndownload the content.<p>When an activity is closed or removed from the <em>Recents</em> page,\nit may be destroyed immediately depending on the amount free memory the\nphone has, battery statistics, or how the activity is configured. But\nservices can be run indefinitely if desired. If more services run in the\nbackground, the phone may become slower due to the shortage of memory\nand/or processing power, and the phone’s battery will be drained more\nquickly. Newer versions of Android come with a battery optimisation\nfeature enabled by default for all applications. With this feature\nenabled, the system can randomly terminate any service depending on the\namount of resources the system has or the service requires. However,\nforeground services (i.e., services that run with a fixed notification,\nsuch as music player or downloader) are not typically terminated unless\nthe system is very low on resources (memory, battery, etc.). Certain\nstock ROMs can offer more aggressive optimisation. MIUI, for example,\nhas a very aggressive optimisation feature known as the <em>MIUI\noptimisation</em>.<p>Both activities and services are run in the same <a href=https://stackoverflow.com/questions/7597742>looper</a> called the\nmain looper, which means the services do not really run in the\nbackground. It is the task of the developer to ensure this. How do the\napplication communicate with the services? It uses <a href=#subsubsec:app-details-receivers>broadcast receiver</a> or\nBinder.</section><section id=subsubsec:app-details-receivers class=level4 data-number=2.2.3.3><h4 data-number=2.2.3.3><span class=header-section-number>2.2.3.3</span> Receivers<a href=#subsubsec:app-details-receivers class=anchor aria-hidden=true></a></h4><p><strong>Receivers</strong> (also called <em>broadcast receivers</em>)\ncan be used to trigger execution of certain tasks when certain events\noccur. These components are called broadcast receivers, because they are\nexecuted as soon as a broadcast message is received. These broadcast\nmessages are sent using a method called <em>Intent</em>. Intent is a\nspecial feature in Android that can be used to open applications (i.e.,\nactivities), run services and send broadcast messages. Therefore, like\n<a href=#subsubsec:activities>activities</a>, broadcast receivers use\n<em>intent filters</em> to receive the desired broadcast messages.\nBroadcast messages can be sent by the system or the application itself.\nWhen a broadcast message is sent, the corresponding receivers are\nactivated by the system so that they can execute tasks. For example, if\nyour phone is low on resources, it may freeze or experience lags for a\nmoment after you enable mobile data or connect it to the Wi-Fi. This is\nbecause broadcast receivers that can receive\n<code>android.net.conn.CONNECTIVITY_CHANGE</code> are activated by the\nsystem as soon as the data connection is enabled. Since many\napplications typically use this intent filter, they are all activated\nalmost immediately by the system which causes the freezing or lags.<p>Receivers can also be used for inter-process communication (IPC),\ni.e., it can be used to communicate across multiple applications or even\ndifferent components of a single application.</section><section id=subsubsec:providers class=level4 data-number=2.2.3.4><h4 data-number=2.2.3.4><span class=header-section-number>2.2.3.4</span> Providers<a href=#subsubsec:providers class=anchor aria-hidden=true></a></h4><p><strong>Providers</strong> are primarily used for data management.\nFor example, when you save an APK file or export rules in App Manager,\nit uses a content provider called <code>.fm.FmProvider</code> to save\nthe APK or export the rules. There are many providers, including the\nones provided by the system, that can be used to manage various\ncontent-related tasks, such as database management, tracking, searching,\netc. Each provider has a field called <em>Authority</em> which is unique\nto the application in the entire Android ecosystem just as the package\nname.</section><section id=additional-features-for-rooted-phones class=level4 data-number=2.2.3.5><h4 data-number=2.2.3.5><span class=header-section-number>2.2.3.5</span> Additional Features for\nRooted Phones<a href=#additional-features-for-rooted-phones class=anchor aria-hidden=true></a></h4><p>Unlike the no-root users who are mostly spectators in these tabs,\nroot users can perform various operations.<section id=blocking-components. class=level5 data-number=2.2.3.5.1><h5 data-number=2.2.3.5.1><span class=header-section-number>2.2.3.5.1</span> Blocking Components.<a href=#blocking-components. class=anchor aria-hidden=true></a></h5><p>On the right-most side of each component item, there is a switch\nwhich can be used to toggle the blocking status of that particular\ncomponent. If <a href=#subsubsec:instant-component-blocking>Instant\nComponent Blocking</a> is not enabled or blocking is never applied to\nthe application before, it is required to apply the changes using the\n<strong>Apply rules</strong> option in three-dots menu. It is also\npossible to remove the already-applied rules using the same option\n(which would be read as <strong>Remove rules</strong> this time).<p>It is also possible to block the component using one of the several\nmethods by long clicking on the button.<div class=seealso-inline><p><em>Bạn cũng có thể xem: <span><a href=#sec:faq:app-components>FAQ:\nApp Components</a></span></em></div></section><section id=par:appdetails:blocking-trackers class=level5 data-number=2.2.3.5.2><h5 data-number=2.2.3.5.2><span class=header-section-number>2.2.3.5.2</span> Blocking Trackers.<a href=#par:appdetails:blocking-trackers class=anchor aria-hidden=true></a></h5><p>It is possible to disable tracker components using the <strong>Block\ntracker</strong> option in the three-dots menu. All tracker components\nwill be blocked regardless of the tab you’re currently in.<div class=\"amalert tip\"><p><strong><em>Info.</em></strong><p>Tracker components are a subset of application components. Therefore,\nthey are blocked using the same method used for blocking any other\ncomponents.</div><div class=seealso><p><em>Bạn cũng có thể xem:</em><ul class=incremental><li><p><a href=#subsec:tracker-classes-versus-tracker-components>FAQ:\nTracker classes versus tracker components</a><li><p><a href=#sec:scanner-page>Scanner Page</a><li><p><a href=#subsec:block-unblock-trackers>1-Click Ops Page:\nBlock/Unblock Trackers</a></ul></div></section></section></section><section id=subsec:permission-tabs class=level3 data-number=2.2.4><h3 data-number=2.2.4><span class=header-section-number>2.2.4</span>\n<a href=#toc:subsec:permission-tabs>Permission Tabs</a><a href=#subsec:permission-tabs class=anchor aria-hidden=true></a></h3><p><strong>App Ops</strong>, <strong>Uses Permissions</strong> and\n<strong>Permissions</strong> tabs are related to permissions. In Android\ncommunication across applications or processes not having the same\nidentity (known as <em>shared ID</em>) often require permissions. These\npermissions are managed by the permission controller. Some permissions\nare considered <em>normal</em> permissions which are granted\nautomatically if they appear in the application manifest, but\n<em>dangerous</em> and <em>development</em> permissions require\nconfirmation from the user. Colours used in these tabs are explained in\n§<a href=#subsec:app-details-colour-codes data-reference-type=ref data-reference=subsec:app-details-colour-codes>2.2.1</a>.<section id=subsubsec:app-ops class=level4 data-number=2.2.4.1><h4 data-number=2.2.4.1><span class=header-section-number>2.2.4.1</span> App Ops<a href=#subsubsec:app-ops class=anchor aria-hidden=true></a></h4><p><strong>App Ops</strong> stands for <strong>Application\nOperations</strong>. Since Android 4.3, <em>App Ops</em> are used by\nAndroid to control many system permissions. Each app op has a unique\nnumber associated with it which is displayed along with the private name\nof the operation in the App Ops tab. Some app ops also have a public\nname. A large number of app ops are also associated with\n<em>permissions</em>. In this tab, an app op is considered dangerous if\nits associated permission is marked as dangerous. Other information such\nas <em>flags</em>, <em>permission name</em>, <em>permission\ndescription</em>, <em>package name</em>, <em>group</em> are also taken\nfrom the associated <a href=#subsubsec:permissions>permission</a>.\nOthers may include the following:<ul class=incremental><li><p><strong>Mode.</strong> It describes the current authorisation\nstatus which can be <em>allow</em>, <em>deny</em> (a rather misnomer, it\nsimply means error), <em>ignore</em> (it actually means deny),\n<em>default</em> (inferred from a list of defaults set internally by the\nvendor or the AOSP), <em>foreground</em> (in newer Android versions, it\nmeans the app op can only be used when the application is running in\nforeground), and some custom modes set by the vendors (MIUI uses\n<em>ask</em>, for example).<li><p><strong>Duration.</strong> The amount of time this app op has\nbeen used (there can be negative durations whose use cases are currently\nunknown to me).<li><p><strong>Accept Time.</strong> Last time the app op was\naccepted.<li><p><strong>Reject Time.</strong> Last time the app op was\nrejected.</ul><div class=\"amalert tip\"><p><strong><em>Info.</em></strong><p>Contents of this tab are visible to no-root users if\n<code>android.permission.GET_APP_OPS_STATS</code> is granted via\nADB.</div><p>There is a toggle button next to each app op item which can be used\nto allow or deny (ignore) it. Other supported modes can also be set by\nlong clicking on the toggle button. If the desired app op is not listed\nin the tab, <em>Set custom app op</em> option in the menu can be used\ninstead. It is also possible to reset the changes using the <em>Reset to\ndefault</em> option, or deny all the dangerous app ops using the\ncorresponding option in the menu. Due to the nature how app ops work,\nthe system may take some time to apply them.<div class=\"amalert tip\"><p><strong><em>Tip.</em></strong><p>Denying certain app ops may cause the application to misbehave. If\nall attempts fail, <em>reset to default</em> option can be used as the\nlast resort.</div><p>It is possible to sort the list in ascending order by app op names\nand the associated unique numbers (or values), or list the denied app\nops first using the corresponding sorting options.<div class=seealso-inline><p><em>Bạn cũng có thể xem: <span><a href=#ch:app-ops>Appendix: App\nOps</a></span></em></div></section><section id=uses-permissions class=level4 data-number=2.2.4.2><h4 data-number=2.2.4.2><span class=header-section-number>2.2.4.2</span> Uses Permissions<a href=#uses-permissions class=anchor aria-hidden=true></a></h4><p><strong>Uses Permissions</strong> are the permissions used by the\napplication. This is named so because they are specified in the manifest\nusing <code>uses-permission</code> tags. Information such as\n<em>flags</em>, <em>permission name</em>, <em>permission\ndescription</em>, <em>package name</em>, <em>group</em> are taken from\nthe associated <a href=#subsubsec:permissions>permission</a>.<p>Privileged users can grant or revoke the <em>dangerous</em> and\n<em>development</em> permissions via the toggle button on the right side\nof each permission item. It is also possible revoke dangerous\npermissions all at once using the corresponding option in the menu. Only\nthese two types of permissions can be revoked because Android does not\nallow the modification of <em>normal</em> permissions (which most of\nthem are). It might still be possible to revoke them by editing\n<code>runtime-permissions.xml</code> itself, but whether this is a\npossibility is still being investigated.<div class=\"amalert tip\"><p><strong><em>Info.</em></strong><p>Since dangerous permissions are revoked by default by the system,\nrevoking all dangerous permissions is the same as resetting all the\npermissions.</div><p>It is possible to sort the permissions by their name (in ascending\norder) or choose to display denied or dangerous permissions at first\nusing the corresponding options in the menu.</section><section id=subsubsec:permissions class=level4 data-number=2.2.4.3><h4 data-number=2.2.4.3><span class=header-section-number>2.2.4.3</span> Permissions<a href=#subsubsec:permissions class=anchor aria-hidden=true></a></h4><p><strong>Permissions</strong> are usually custom permissions defined\nby the application itself. These type of permissions are marked as\n<em>Internal</em> permissions. It also contains permissions declared by\nother applications which are marked as <em>External</em> permissions. An\nexternal permission can be specified in an <em>exported</em> application\ncomponent so that another application may invoke the component only if\nit holds the permission. Below is a complete description of each item\ndisplayed in this tab:<ul class=incremental><li><p><strong>Name.</strong> A permission has a unique name (e.g.,\n<code>android.permission.INTERNET</code>) that multiple applications can\nrequest. The application that declared the permission is automatically\ngranted and cannot be revoked.<li><p><strong>Icon.</strong> Each permission can have a custom icon.\nThe other permission tabs do not have any icon because they do not\ncontain any icon in the application manifest.<li><p><strong>Description.</strong> This optional field describes the\npermission. If there isn’t any description associated with the\npermission, the field is not displayed.<li><p><strong>Flags.</strong> (Uses the flag symbol or\n<strong>Protection Level</strong> name) This describes various\npermission flags such as <em>normal</em>, <em>development</em>,\n<em>dangerous</em>, <em>instant</em>, <em>granted</em>,\n<em>revoked</em>, <em>signature</em>, <em>privileged</em>, etc.<li><p><strong>Package Name.</strong> Denotes the package name\nassociated with the permission, i.e. the package that defined the\npermission.<li><p><strong>Group.</strong> The group name associated with the\npermission (if any). Several related permissions can often be grouped\ntogether.</ul></section></section><section id=subsec:signatures-tab class=level3 data-number=2.2.5><h3 data-number=2.2.5><span class=header-section-number>2.2.5</span>\n<a href=#toc:subsec:signatures-tab>Signatures Tab</a><a href=#subsec:signatures-tab class=anchor aria-hidden=true></a></h3><p><strong>Signatures</strong> are actually called signing information.\nAn application is signed with one or more signing keys by its developer\nbefore publishing it. The integrity of an application, i.e., whether the\napplication is from the actual developer and has not been modified by\nanother person, can be checked using the signing certificate included in\nthe APK files. This is because when an application is modified by an\nunauthorised entity, the application can longer be signed with the\noriginal signing keys since the signing keys are unknown to the entity.\nOne way to verify the integrity of an application is via the checksums\ngenerated from the certificates. If the developer supplies the checksums\nfor the signing certificates, they can be compared against the checksums\ngenerated in the <strong>Signatures</strong> tab to verify the\napplication. For example, if you have downloaded App Manager from GitHub\nor Telegram Channel, you can verify whether the application was actually\nreleased by me by simply matching the following <em>SHA256</em> checksum\nwith the one displayed in this tab:<pre><code>320c0c0fe8cef873f2b554cb88c837f1512589dcced50c5b25c43c04596760ab</code></pre><p>Several hashing algorithms are used to generate checksums in this\ntab. They include <em>MD5</em>, <em>SHA1</em>, <em>SHA256</em> and\n<em>SHA512</em>.<div class=\"amalert danger\"><p><strong><em>Caution.</em></strong><p>Signing information should be verified using a reliable hashing\nalgorithm, such as <em>SHA256</em>. DO NOT rely on <em>MD5</em> or\n<em>SHA1</em> checksums as they are known to generate the same checksums\nfor multiple certificates.</div></section><section id=subsec:uses-features-tab class=level3 data-number=2.2.6><h3 data-number=2.2.6><span class=header-section-number>2.2.6</span>\n<a href=#toc:subsec:uses-features-tab>Uses Features tab</a><a href=#subsec:uses-features-tab class=anchor aria-hidden=true></a></h3><p><strong>Uses Features</strong> tab lists the features declared by the\napplication, such as OpenGL ES, telephony, and leanback. Some features\ncan be required by the application, and some features can be optional.\nRequired features must be present in the system along with the required\nversion. Otherwise, any attempt to install the application will be\ndenied by the system. Colours used in this tab are explained in §<a href=#subsec:app-details-colour-codes data-reference-type=ref data-reference=subsec:app-details-colour-codes>2.2.1</a>.</section><section id=subsec:configurations-tab class=level3 data-number=2.2.7><h3 data-number=2.2.7><span class=header-section-number>2.2.7</span>\n<a href=#toc:subsec:configurations-tab>Configurations tab</a><a href=#subsec:configurations-tab class=anchor aria-hidden=true></a></h3><p><strong>Configurations</strong> tab lists the configurations required\nby the application, such as input method type (qwerty, 12 key), touch\nscreen type (finger, stylus, etc.), and navigation type (dial pad,\ntrackball, wheel). This tab is going to be empty for most\napplications.</section><section id=subsec:shared-libs-tab class=level3 data-number=2.2.8><h3 data-number=2.2.8><span class=header-section-number>2.2.8</span>\n<a href=#toc:subsec:shared-libs-tab>Shared Libraries Tab</a><a href=#subsec:shared-libs-tab class=anchor aria-hidden=true></a></h3><p><strong>Shared libraries</strong> tab lists the legacy JAR\ndependencies, any static shared library dependencies (currently, the\nonly known cases are the Chromium-based browsers and WebViews) as well\nas the JNI (Java native interface) libraries. For JNI libraries, it\nspecifies platform (x86/x86_64/ARM/AArch64), architecture (32/64 bit),\nobject type (shared object or executable), etc.</section></section><section id=sec:1-click-ops-page class=level2 data-number=2.3><h2 data-number=2.3><span class=header-section-number>2.3</span> <a href=#toc:sec:1-click-ops-page>1-Click Ops Page</a><a href=#sec:1-click-ops-page class=anchor aria-hidden=true></a></h2><p>This page is displayed on selecting the <a href=#subsubsec:main:1-click-ops>1-Click Ops option</a> in the <a href=#subsec:main-page-options-menu>main menu</a>.<section id=subsec:block-unblock-trackers class=level3 data-number=2.3.1><h3 data-number=2.3.1><span class=header-section-number>2.3.1</span>\n<a href=#toc:subsec:block-unblock-trackers>Block/Unblock\nTrackers</a><a href=#subsec:block-unblock-trackers class=anchor aria-hidden=true></a></h3><p>This option can be used to block or unblock the ad/tracker components\nfrom the installed applications. On selecting this option, App Manager\nwill ask if it should list trackers from all the applications or only\nfrom the user applications. Novice users should avoid blocking trackers\nfrom the system applications in order to avoid bad consequences. After\nthat, a multi-choice dialog box will appear where it is possible to\nexclude one or more applications from this operation. The changes are\napplied immediately on pressing the <em>block</em> or <em>unblock</em>\nbutton.<div class=\"amalert warning\"><p><strong><em>Notice.</em></strong><p>Certain applications may not function as expected after blocking\ntheir trackers. If that is the case, remove the blocking rules all at\nonce or one by one in the component tabs of the <a href=#sec:app-details-page>App Details page</a> for the corresponding\napplication.</div><div class=seealso-inline><p><em>Bạn cũng có thể xem: <span><a href=#par:appdetails:blocking-trackers>App Details Page: Blocking\nTrackers</a></span></em></div></section><section id=subsec:block-components-dots class=level3 data-number=2.3.2><h3 data-number=2.3.2><span class=header-section-number>2.3.2</span>\n<a href=#toc:subsec:block-components-dots>Block Components…</a><a href=#subsec:block-components-dots class=anchor aria-hidden=true></a></h3><p>This option can be used to block certain application components as\nspecified by their signatures. A signature of a component is the full\nname or partial name of the component. For safety, it is recommended to\nadd a <code>.</code> (dot) at the end of each partial signature, because\nthe underlying algorithm searches and matches the components in a greedy\nmanner. It is also possible to insert more than one signature in which\ncase all the signatures have to be separated by white spaces. Similar to\nthe option above, there is also an option to apply blocking to the\nsystem applications.<div class=\"amalert danger\"><p><strong><em>Caution.</em></strong><p>If you are not aware of the consequences of blocking applcations\ncomponents by their signatures, you should avoid using this option as it\nmay result in bootloop or soft brick, and you may have to apply factory\nreset as a result.</div></section><section id=subsec:set-mode-for-app-ops-dots class=level3 data-number=2.3.3><h3 data-number=2.3.3><span class=header-section-number>2.3.3</span>\n<a href=#toc:subsec:set-mode-for-app-ops-dots>Set Mode for App\nOps…</a><a href=#subsec:set-mode-for-app-ops-dots class=anchor aria-hidden=true></a></h3><p>This option can be used to configure certain <a href=#ch:app-ops>applcation operations</a> of all or selected\napplications. There are two fields. The first field can be used to\ninsert more than one app op constants (either names or values) separated\nby white spaces. It is not always possible to know in advance about all\nthe app op constants as they vary from device to device and from OS to\nOS. Desired app op constant can be found in the <em>App Ops</em> tab\nlocated in the <a href=#sec:app-details-page>App Details page</a>. The\nsecond field can be used to insert or select one of the <a href=#subsec:mode-constants>modes</a> that will be set against the\nspecified app ops.<div class=\"amalert danger\"><p><strong><em>Caution.</em></strong><p>Unless you are well-informed about app ops and the consequences of\nblocking them, you should avoid using this option.</div></section><section id=subsec:1-click-back-up class=level3 data-number=2.3.4><h3 data-number=2.3.4><span class=header-section-number>2.3.4</span>\n<a href=#toc:subsec:1-click-back-up>Back up</a><a href=#subsec:1-click-back-up class=anchor aria-hidden=true></a></h3><p>1-Click options for back up. As a precaution, it lists the affected\nbackups before performing any operation.<section id=back-up-all-apps. class=level5 data-number=2.3.4.0.1><h5 data-number=2.3.4.0.1><span class=header-section-number>2.3.4.0.1</span> Back up all apps.<a href=#back-up-all-apps. class=anchor aria-hidden=true></a></h5><p>Back up all the installed applications.</section><section id=redo-existing-backups. class=level5 data-number=2.3.4.0.2><h5 data-number=2.3.4.0.2><span class=header-section-number>2.3.4.0.2</span> Redo existing backups.<a href=#redo-existing-backups. class=anchor aria-hidden=true></a></h5><p>Back up all the installed applications that have a previous\nbackup.</section><section id=back-up-apps-without-backups. class=level5 data-number=2.3.4.0.3><h5 data-number=2.3.4.0.3><span class=header-section-number>2.3.4.0.3</span> Back up apps without\nbackups.<a href=#back-up-apps-without-backups. class=anchor aria-hidden=true></a></h5><p>Back up all the installed applications without a previous backup.</section><section id=verify-and-redo-backups. class=level5 data-number=2.3.4.0.4><h5 data-number=2.3.4.0.4><span class=header-section-number>2.3.4.0.4</span> Verify and redo\nbackups.<a href=#verify-and-redo-backups. class=anchor aria-hidden=true></a></h5><p>Verify the recently made backups of the installed applications and\nredo backup if necessary.</section><section id=back-up-apps-with-changes. class=level5 data-number=2.3.4.0.5><h5 data-number=2.3.4.0.5><span class=header-section-number>2.3.4.0.5</span> Back up apps with\nchanges.<a href=#back-up-apps-with-changes. class=anchor aria-hidden=true></a></h5><p>If an app has changed since the last backup, redo its backup. It\nchecks a number of indices including application version, last update\ndate, last launch date, integrity and file hashes. Directory hashes are\ntaken during the backup process and are stored in a database. On running\nthis operation, new hashes are taken and compared with the ones kept in\nthe database.</section></section><section id=subsec:1-click-restore class=level3 data-number=2.3.5><h3 data-number=2.3.5><span class=header-section-number>2.3.5</span>\n<a href=#toc:subsec:1-click-restore>Restore</a><a href=#subsec:1-click-restore class=anchor aria-hidden=true></a></h3><p>1-Click options for restore. As a precaution, it lists the affected\nbackups before performing any operation.<section id=restore-all-apps. class=level5 data-number=2.3.5.0.1><h5 data-number=2.3.5.0.1><span class=header-section-number>2.3.5.0.1</span> Restore all apps.<a href=#restore-all-apps. class=anchor aria-hidden=true></a></h5><p>Restore <em>base backup</em> of all the backed up applications.</section><section id=restore-not-installed-apps. class=level5 data-number=2.3.5.0.2><h5 data-number=2.3.5.0.2><span class=header-section-number>2.3.5.0.2</span> Restore not installed\napps.<a href=#restore-not-installed-apps. class=anchor aria-hidden=true></a></h5><p>Restore <em>base backup</em> of all the backed up applications that\nare not currently installed.</section><section id=restore-latest-backups. class=level5 data-number=2.3.5.0.3><h5 data-number=2.3.5.0.3><span class=header-section-number>2.3.5.0.3</span> Restore latest backups.<a href=#restore-latest-backups. class=anchor aria-hidden=true></a></h5><p>Restore <em>base backup</em> of already installed applications whose\nversion codes are higher than the installed version code.</section></section><section id=subsec:trim-caches-in-all-apps class=level3 data-number=2.3.6><h3 data-number=2.3.6><span class=header-section-number>2.3.6</span>\n<a href=#toc:subsec:trim-caches-in-all-apps>Trim Caches in All\nApps</a><a href=#subsec:trim-caches-in-all-apps class=anchor aria-hidden=true></a></h3><p>Delete caches from all applications, including Android system. During\nthis operation, caches of all the running applications may not be\ncleared as expected.</section></section><section id=sec:profiles-page class=level2 data-number=2.4><h2 data-number=2.4><span class=header-section-number>2.4</span> <a href=#toc:sec:profiles-page>Profiles Page</a><a href=#sec:profiles-page class=anchor aria-hidden=true></a></h2><p>Profiles page can be accessed from the <a href=#subsec:main-page-options-menu>options-menu</a> in the main page.\nIt primarily displays a list of configured profiles along with the\ntypical options to perform operations on them. New profiles can also be\nadded using the <em>plus</em> button at the bottom-right corner.\nProfiles can be imported, duplicated or deleted. Clicking on a profile\nitem opens its <a href=#sec:profile-page>profile page</a>.<section id=subsec:profiles-options-menu class=level3 data-number=2.4.1><h3 data-number=2.4.1><span class=header-section-number>2.4.1</span>\n<a href=#toc:subsec:profiles-options-menu>Options Menu</a><a href=#subsec:profiles-options-menu class=anchor aria-hidden=true></a></h3><p>The three-dots menu in the top-right corner opens the global option\nmenu. It has an option to import an existing profile that was previously\nexported from App Manager.<p>Long clicking on any profile item brings up another options-menu. It\noffers the following options:<ul class=incremental><li><p><strong>Apply now….</strong> This option can be used to apply the\nprofile directly. When clicked, a dialog is displayed where it is\npossible to select a <a href=#subsubsec:profile-state>profile\nstate</a>. On selecting one of the states, the profile will be applied\nimmediately.<li><p><strong>Delete.</strong> Clicking on this option will remove the\nprofile immediately without a warning.<li><p><strong>Duplicate.</strong> This option can be used to duplicate\nthe profile. When clicked, a dialog is displayed where it is possible to\nset a name for the new profile. On clicking “OK”, the <a href=#sec:profile-page>profile page</a> will be loaded by duplicating\nall the configurations that this profile have. However, the profile will\nnot be saved until it is saved manually.<li><p><strong>Copy profile ID.</strong> This option is used to copy the\nunique profile ID of the profile. The profile ID can be used to <a href=#subsec:triggering-a-profile>trigger the profile</a> from a\nthird-party application.<li><p><strong>Export.</strong> Export the profile to an external\nstorage. Profiles exported this way can be imported via the\n<em>import</em> option as mentioned above.<li><p><strong>Create shortcut.</strong> This option can be used to\ncreate a shortcut for the profile. There are two options:\n<em>Simple</em> and <em>Advanced</em>. When configured with the latter\noption, it prompts the user to select a profile state when the shortcut\nis invoked. The former option, on the other hand, always uses the\ndefault state that was configured when the profile was last\nsaved.</ul></section></section><section id=sec:profile-page class=level2 data-number=2.5><h2 data-number=2.5><span class=header-section-number>2.5</span> <a href=#toc:sec:profile-page>Profile Page</a><a href=#sec:profile-page class=anchor aria-hidden=true></a></h2><p>Profile page displays the configurations for a profile. It also\noffers the options to edit them.<section id=subsec:profile-options-menu class=level3 data-number=2.5.1><h3 data-number=2.5.1><span class=header-section-number>2.5.1</span>\n<a href=#toc:subsec:profile-options-menu>Options Menu</a><a href=#subsec:profile-options-menu class=anchor aria-hidden=true></a></h3><p>The three dots menu in the top-right corner opens the options-menu.\nIt contains several options such as–<ul class=incremental><li><p><strong>Apply.</strong> This option can be used to apply the\nprofile directly. When clicked, a dialog is displayed where it is\npossible to select a <a href=#subsubsec:profile-state>profile\nstate</a>. On selecting one of the states, the profile will be applied\nimmediately.<div class=\"amalert tip\"><p><strong><em>Notice.</em></strong><p>When you apply a profile, if some packages do not match the criteria,\nthey will simply be ignored.</div><li><p><strong>Save.</strong> Save changes to the profile.<li><p><strong>Discard.</strong> Discard any modifications made since\nthe last time it was saved.<li><p><strong>Delete.</strong> Clicking on this option will remove the\nprofile immediately without a warning.<li><p><strong>Duplicate.</strong> This option can be used to duplicate\nthe profile. When clicked, a dialog is displayed where it is possible to\nset a name for the new profile. On clicking “OK”, this page will be\nreloaded by duplicating all the configurations that this profile have.\nHowever, the new profile will not be saved until it is saved\nmanually.<li><p><strong>Create shortcut.</strong> This option can be used to\ncreate a shortcut for the profile. There are two options:\n<em>Simple</em> and <em>Advanced</em>. When configured with the latter\noption, it prompts the user to select a profile state when the shortcut\nis invoked. The former option, on the other hand, always uses the\ndefault state that was configured when the profile was last\nsaved.</ul></section><section id=subsec:profile-apps-tab class=level3 data-number=2.5.2><h3 data-number=2.5.2><span class=header-section-number>2.5.2</span>\n<a href=#toc:subsec:profile-apps-tab>Apps Tab</a><a href=#subsec:profile-apps-tab class=anchor aria-hidden=true></a></h3><p>Apps tab lists the packages configured for this profile. Packages can\nbe added or removed using the <em>plus</em> button located near the\nbottom of the screen. A package can also be removed by long clicking on\nit (in which case, a popup will be displayed with the only option,\n<em>delete</em>).</section><section id=subsec:profile-configurations-tab class=level3 data-number=2.5.3><h3 data-number=2.5.3><span class=header-section-number>2.5.3</span>\n<a href=#toc:subsec:profile-configurations-tab>Configurations\nTab</a><a href=#subsec:profile-configurations-tab class=anchor aria-hidden=true></a></h3><p>Configurations tab can be used to configure the selected\npackages.<section id=profile-id class=level4 data-number=2.5.3.1><h4 data-number=2.5.3.1><span class=header-section-number>2.5.3.1</span> Profile ID<a href=#profile-id class=anchor aria-hidden=true></a></h4><p>The unique ID for this profile, currently set based on the profile\nname. The profile ID can be used to <a href=#subsec:triggering-a-profile>trigger the profile</a> from a\nthird-party application.</section><section id=comment class=level4 data-number=2.5.3.2><h4 data-number=2.5.3.2><span class=header-section-number>2.5.3.2</span> Comment<a href=#comment class=anchor aria-hidden=true></a></h4><p>This is the text that will be displayed in the <a href=#sec:profiles-page>profiles page</a>. If not set, the current\nconfigurations will be displayed instead.</section><section id=subsubsec:profile-state class=level4 data-number=2.5.3.3><h4 data-number=2.5.3.3><span class=header-section-number>2.5.3.3</span> State<a href=#subsubsec:profile-state class=anchor aria-hidden=true></a></h4><p>Denotes how certain configured options will behave by default. For\ninstance, if <em>disable</em> option is turned on, the applications will\nbe disabled if the state is <em>on</em> and will be enabled if the state\nis <em>off</em>. Currently, it only supports <em>on</em> and\n<em>off</em> values.</section><section id=users class=level4 data-number=2.5.3.4><h4 data-number=2.5.3.4><span class=header-section-number>2.5.3.4</span> Users<a href=#users class=anchor aria-hidden=true></a></h4><p>Select users for which is the profile will be applied. All users are\nselected by default.</section><section id=components class=level4 data-number=2.5.3.5><h4 data-number=2.5.3.5><span class=header-section-number>2.5.3.5</span> Components<a href=#components class=anchor aria-hidden=true></a></h4><p>This behaves the same way as the <a href=#subsec:block-components-dots>Block Components…</a> option does\nin the 1-Click Ops page. However, the blocking here is only applied to\nthe selected packages. If the <a href=#subsubsec:profile-state>state</a> is <em>on</em>, the components\nwill be blocked, and if the state is <em>off</em>, the components will\nbe unblocked. The option can be disabled (regardless of the inserted\nvalues) by clicking on the <em>disabled</em> button on the input\ndialog.<div class=seealso-inline><p><em>Bạn cũng có thể xem: <span><a href=#subsec:faq:what-are-app-components>What are the app\ncomponents?</a></span></em></div></section><section id=app-ops class=level4 data-number=2.5.3.6><h4 data-number=2.5.3.6><span class=header-section-number>2.5.3.6</span> App Ops<a href=#app-ops class=anchor aria-hidden=true></a></h4><p>This behaves the same way as the <a href=#subsec:set-mode-for-app-ops-dots>Set Mode for App Ops…</a>\noption does in the 1-Click Ops page. However, the operation here is only\napplied to the selected packages. If the <a href=#subsubsec:profile-state>state</a> is <em>on</em>, the app ops\nwill be denied (i.e. ignored), and if the state is <em>off</em>, the app\nops will be allowed. The option can be disabled (regardless of the\ninserted values) by clicking on the <em>disable</em> button in the input\ndialog.</section><section id=permissions class=level4 data-number=2.5.3.7><h4 data-number=2.5.3.7><span class=header-section-number>2.5.3.7</span> Permissions<a href=#permissions class=anchor aria-hidden=true></a></h4><p>This option can be used to grant or revoke certain permissions from\nthe selected packages. Like others above, permissions must be separated\nby white spaces. If the <a href=#subsubsec:profile-state>state</a> is\n<em>on</em>, the permissions will be revoked, and if the state is\n<em>off</em>, the permissions will be allowed. The option can be\ndisabled (regardless of the inserted values) by clicking on the\n<em>disable</em> button in the input dialog.</section><section id=backuprestore class=level4 data-number=2.5.3.8><h4 data-number=2.5.3.8><span class=header-section-number>2.5.3.8</span> Backup/Restore<a href=#backuprestore class=anchor aria-hidden=true></a></h4><p>This option can be used to take a backup of the selected applications\nand its data or restore them. Two options are available here: <em>Backup\noptions</em> and <em>backup name</em>.<ul class=incremental><li><p><strong>Backup options.</strong> Same as the <a href=#subsec:backup-restore-backup-options>backup options</a> of the\nbackup/restore feature. If not set, the default options will be\nused.<li><p><strong>Backup name.</strong> Set a custom name for the backup.\nIf the backup name is set, each time a backup is made, it will be given\na unique name with backup-name as the suffix. This behaviour will be\nfixed in a future release. Leave this field empty for regular “base”\nbackups (also, make sure not to enable <em>backup multiple</em> in the\nbackup options).</ul><p>If the <a href=#subsubsec:profile-state>state</a> is <em>on</em>,\nthe packages will be backed up, and if the state is <em>off</em>, the\npackages will be restored. The option can be disabled by clicking on the\n<em>disable</em> button in the input dialog.</section><section id=export-blocking-rules class=level4 data-number=2.5.3.9><h4 data-number=2.5.3.9><span class=header-section-number>2.5.3.9</span> Export Blocking Rules<a href=#export-blocking-rules class=anchor aria-hidden=true></a></h4><div class=\"amalert danger\"><p><strong><em>Danger.</em></strong><p>This option is not yet implemented.</div></section><section id=freeze class=level4 data-number=2.5.3.10><h4 data-number=2.5.3.10><span class=header-section-number>2.5.3.10</span> Freeze<a href=#freeze class=anchor aria-hidden=true></a></h4><p>Allow freezing or unfreezing the selected packages depending on the\nvalue of the <a href=#subsubsec:profile-state>state</a>. If the state\nis <em>on</em>, the packages will be frozen, and if the state is\n<em>off</em>, they will be unfrozen.</section><section id=force-stop class=level4 data-number=2.5.3.11><h4 data-number=2.5.3.11><span class=header-section-number>2.5.3.11</span> Force-stop<a href=#force-stop class=anchor aria-hidden=true></a></h4><p>Allow the selected packages to be force-stopped.</section><section id=clear-cache class=level4 data-number=2.5.3.12><h4 data-number=2.5.3.12><span class=header-section-number>2.5.3.12</span> Clear Cache<a href=#clear-cache class=anchor aria-hidden=true></a></h4><p>Enable clearing cache for the selected packages.</section><section id=clear-data class=level4 data-number=2.5.3.13><h4 data-number=2.5.3.13><span class=header-section-number>2.5.3.13</span> Clear Data<a href=#clear-data class=anchor aria-hidden=true></a></h4><p>Enable clearing data for the selected packages.</section><section id=block-trackers class=level4 data-number=2.5.3.14><h4 data-number=2.5.3.14><span class=header-section-number>2.5.3.14</span> Block Trackers<a href=#block-trackers class=anchor aria-hidden=true></a></h4><p>Enable blocking or unblocking of the tracker components from the\nselected packages depending on the value of the <a href=#subsubsec:profile-state>state</a>. If the state is <em>on</em>,\nthe trackers will be blocked, and if the state is <em>off</em>, the\ntrackers will be unblocked.</section><section id=save-apk class=level4 data-number=2.5.3.15><h4 data-number=2.5.3.15><span class=header-section-number>2.5.3.15</span> Save APK<a href=#save-apk class=anchor aria-hidden=true></a></h4><p>Enable saving APK files at <code>AppManager/apks</code> (or in the\ndirectory selected in the settings page) of the selected packages.</section></section></section><section id=sec:settings-page class=level2 data-number=2.6><h2 data-number=2.6><span class=header-section-number>2.6</span> <a href=#toc:sec:settings-page>Settings Page</a><a href=#sec:settings-page class=anchor aria-hidden=true></a></h2><p>Settings page can be used to customise the behaviour of App\nManager.<section id=subsec:language class=level3 data-number=2.6.1><h3 data-number=2.6.1><span class=header-section-number>2.6.1</span>\n<a href=#toc:subsec:language>Language</a><a href=#subsec:language class=anchor aria-hidden=true></a></h3><p>Configure in-app language. App Manager currently supports 22\n(twenty-two) languages.</section><section id=subsec:appearance class=level3 data-number=2.6.2><h3 data-number=2.6.2><span class=header-section-number>2.6.2</span>\n<a href=#toc:subsec:appearance>Appearance</a><a href=#subsec:appearance class=anchor aria-hidden=true></a></h3><section id=subsubsec:app-theme class=level4 data-number=2.6.2.1><h4 data-number=2.6.2.1><span class=header-section-number>2.6.2.1</span> App Theme<a href=#subsubsec:app-theme class=anchor aria-hidden=true></a></h4><p>Configure in-app theme.</section><section id=subsubsec:pure-black-theme class=level4 data-number=2.6.2.2><h4 data-number=2.6.2.2><span class=header-section-number>2.6.2.2</span> Pure Black Theme<a href=#subsubsec:pure-black-theme class=anchor aria-hidden=true></a></h4><p>Whether to use a black background instead of the material themed\nbackground.</section><section id=subsubsec:layout-direction class=level4 data-number=2.6.2.3><h4 data-number=2.6.2.3><span class=header-section-number>2.6.2.3</span> Layout Direction<a href=#subsubsec:layout-direction class=anchor aria-hidden=true></a></h4><p>Change layout direction, either left to right or right to left. This\nis usually set using the selected language but not everybody prefers the\nsame direction.</section><section id=subsubsec:enable/disable-features class=level4 data-number=2.6.2.4><h4 data-number=2.6.2.4><span class=header-section-number>2.6.2.4</span> Enable/Disable Features<a href=#subsubsec:enable/disable-features class=anchor aria-hidden=true></a></h4><p>Enable or disable certain features in App Manager, such as<ul class=incremental><li><p><strong>Interceptor</strong><li><p><strong>Manifest viewer</strong><li><p><strong>Scanner</strong><li><p><strong>Package installer</strong><li><p><strong>Usage access.</strong> With this feature turned off, App\nManager will never ask for the <em>Usage Access</em>\npermission.<li><p><strong>Log viewer</strong><li><p><strong>App explorer.</strong> The “Explore” option will not be\navailable while trying to open an APK file.<li><p><strong>App info.</strong> The “App info” option displayed while\ntrying to open an APK file.<li><p><strong>Code Editor</strong><li><p><strong>VirusTotal</strong></ul></section></section><section id=subsec:privacy class=level3 data-number=2.6.3><h3 data-number=2.6.3><span class=header-section-number>2.6.3</span>\n<a href=#toc:subsec:privacy>Privacy</a><a href=#subsec:privacy class=anchor aria-hidden=true></a></h3><section id=subsubsec:screen-lock class=level4 data-number=2.6.3.1><h4 data-number=2.6.3.1><span class=header-section-number>2.6.3.1</span> Screen Lock<a href=#subsubsec:screen-lock class=anchor aria-hidden=true></a></h4><p>Lock App Manager using Android screen lock provided a screen lock is\nconfigured.<div class=\"amalert warning\"><p><strong><em>Warning.</em></strong><p>If screen lock is disabled in Android after enabling this setting,\nApp Manager will not open until it is enabled again.</div></section><section id=subsubsec:run-am-in-background class=level4 data-number=2.6.3.2><h4 data-number=2.6.3.2><span class=header-section-number>2.6.3.2</span> Run App Manager in the\nBackground<a href=#subsubsec:run-am-in-background class=anchor aria-hidden=true></a></h4><p>Whether to run App Manager in the background to reduce the\ninitialisation delay. On certain devices, this can also help if you’re\nfrequently disconnected from ADB.</section><section id=subsubsec:use-the-internet class=level4 data-number=2.6.3.3><h4 data-number=2.6.3.3><span class=header-section-number>2.6.3.3</span> Use the Internet<a href=#subsubsec:use-the-internet class=anchor aria-hidden=true></a></h4><p>Whether to activate the Internet features in App Manager. This\ncurrently include VirusTotal and Pithus scanning in the <a href=#sec:scanner-page>Scanner page</a>.</section><section id=subsubsec:auth-manager class=level4 data-number=2.6.3.4><h4 data-number=2.6.3.4><span class=header-section-number>2.6.3.4</span> Authorization Manager<a href=#subsubsec:auth-manager class=anchor aria-hidden=true></a></h4><p>This setting allows a third-party application to get access to\ncertain features, such as profiles.</section></section><section id=subsec:mode-of-operation class=level3 data-number=2.6.4><h3 data-number=2.6.4><span class=header-section-number>2.6.4</span>\n<a href=#toc:subsec:mode-of-operation>Mode of Operation</a><a href=#subsec:mode-of-operation class=anchor aria-hidden=true></a></h3><p>Mode of operation defines how App Manager works as a whole. It has\nthe following options:<ul class=incremental><li><p><strong>Auto.</strong> Let App Manager decide the suitable\noption. Although this is the default option, non-rooted users should use\nthe <em>no-root</em> mode.<li><p><strong>Root.</strong> Operate App Manager in root mode. App\nManager will fall back to <em>no-root</em> mode if root is not detected,\nor in rare cases when Binder communication through root is disabled\n(e.g. in <a href=https://github.com/MuntashirAkon/AppManager/issues/606>Phh\nSuperUser</a>).<li><p><strong>ADB over TCP.</strong> Operate App Manager in ADB mode\nvia <a href=#sec:adb-over-tcp>ADB over TCP</a>. App Manager will fall\nback to <em>no-root</em> mode if ADB over TCP is not enabled.<li><p><strong>Wireless debugging.</strong> Enable ADB via Wireless\nDebugging. It will try to connect to the configured port automatically\nat first. On failure, it will ask the user to either pair or connect to\nthe ADB daemon manually. App Manager will fall back to <em>no-root</em>\nmode if it fails to connect to the ADB daemon this way.<div class=\"amalert tip\"><p><strong><em>Info.</em></strong><p>This option is only displayed in devices running Android 11 or later\nas Wireless Debugging was introduced in Android 11.</div><li><p><strong>No-root.</strong> Operate App Manager in no-root mode.\nWhile App Manager performs better in this mode, all the root- or\nADB-specific features will be disabled.</ul><p>It also displays the actual mode of operation at the top. The actual\nmode of operations are <em>root</em>, <em>ABD</em> and\n<em>no-root</em>.<div class=\"amalert tip\"><p><strong><em>Notice.</em></strong><p>“Remote service” is only required for ADB users or when you use the\ncustom commands.</div></section><section id=subsec:apk-signing class=level3 data-number=2.6.5><h3 data-number=2.6.5><span class=header-section-number>2.6.5</span>\n<a href=#toc:subsec:apk-signing>APK Signing</a><a href=#subsec:apk-signing class=anchor aria-hidden=true></a></h3><section id=signature-schemes class=level4 data-number=2.6.5.1><h4 data-number=2.6.5.1><span class=header-section-number>2.6.5.1</span> Signature Schemes<a href=#signature-schemes class=anchor aria-hidden=true></a></h4><p>Configure the <a href=https://source.android.com/security/apksigning>signature\nschemes</a> to be used when APK signing is enabled. v1 and v2 signature\nschemes are enabled by default, but v3 should also be enabled to ensure\nproper security in Android 9 or later.</section><section id=signing-key class=level4 data-number=2.6.5.2><h4 data-number=2.6.5.2><span class=header-section-number>2.6.5.2</span> Signing Key<a href=#signing-key class=anchor aria-hidden=true></a></h4><p>Configure the signing key for signing APK files. Keys from an\nexisting KeyStore can be imported to App Manager, or a new key can be\ngenerated.<div class=\"amalert tip\"><p><strong><em>Tip.</em></strong><p>If you need to use the key in the future, it is recommended that you\ncreate a KeyStore yourself and import the key here. Without a proper\nbackup, keys generated within App Manager are at the risk of being\ndeleted.</div></section><section id=align-apk-files class=level4 data-number=2.6.5.3><h4 data-number=2.6.5.3><span class=header-section-number>2.6.5.3</span> Align APK Files<a href=#align-apk-files class=anchor aria-hidden=true></a></h4><p>Performs zip alignment when App Manager signs an APK file. Zip\nalignment stores the files in the APK file (which is actually a zip\nfile) in a way that a zip file reader can access the files quite easily\nusing random access instead of loading the entire APK file in the\nmemory, which results in the reduction of Android’s memory usage. Note\nthat this step is required if an application’s manifest has\n<code>extractNativeLibs</code> set to <code>true</code>.</section></section><section id=subsec:installer class=level3 data-number=2.6.6><h3 data-number=2.6.6><span class=header-section-number>2.6.6</span>\n<a href=#toc:subsec:installer>Installer</a><a href=#subsec:installer class=anchor aria-hidden=true></a></h3><p>Configure the default behaviour of the installer. You can also find\nmost of the settings by clicking on the <em>cog</em> icon when you\ninstall an application.<section id=install-location class=level4 data-number=2.6.6.1><h4 data-number=2.6.6.1><span class=header-section-number>2.6.6.1</span> Install Location<a href=#install-location class=anchor aria-hidden=true></a></h4><p>Define APK installation location. This can be one of <em>auto</em>,\n<em>internal only</em> and <em>prefer external</em>. In newer Android\nversions, selecting the last option does not guarantee that the\napplication will be installed in the external storage.</section><section id=block-trackers-1 class=level4 data-number=2.6.6.2><h4 data-number=2.6.6.2><span class=header-section-number>2.6.6.2</span> Block Trackers<a href=#block-trackers-1 class=anchor aria-hidden=true></a></h4><p>Whether to block the tracking components immediately after installing\nthe application.</section><section id=display-changes class=level4 data-number=2.6.6.3><h4 data-number=2.6.6.3><span class=header-section-number>2.6.6.3</span> Display Changes<a href=#display-changes class=anchor aria-hidden=true></a></h4><p>Whether to display changes in version, trackers, components,\npermissions, signatures, SDK, etc. in a version controlled style before\ninstalling the application if the application has already been\ninstalled.</section><section id=installer-app class=level4 data-number=2.6.6.4><h4 data-number=2.6.6.4><span class=header-section-number>2.6.6.4</span> Installer App<a href=#installer-app class=anchor aria-hidden=true></a></h4><p>Select the installer application. This is useful for applications\nthat explicitly checks the installer as a way to verify if the\napplication is installed legitimately. This only works for root or ADB\nusers.<div class=\"amalert tip\"><p><strong><em>Notice.</em></strong><p>While checking for the installer might seem a legitimate concern for\nan application, the Android framework already deals with this during the\ninstallation. Checking for the installer is simply the wrong way to\nprove the legitimacy of the source of an application.</div></section><section id=sign-apk class=level4 data-number=2.6.6.5><h4 data-number=2.6.6.5><span class=header-section-number>2.6.6.5</span> Sign APK<a href=#sign-apk class=anchor aria-hidden=true></a></h4><p>Whether to sign the APK files before installing the application. A\nsigning key has to be added or generated before this option can be\nenabled. This can be done in the <a href=#subsec:apk-signing>APK\nsigning</a> page.</section><section id=immediately-perform-dex-optimization class=level4 data-number=2.6.6.6><h4 data-number=2.6.6.6><span class=header-section-number>2.6.6.6</span> Immediately Perform DEX\nOptimization<a href=#immediately-perform-dex-optimization class=anchor aria-hidden=true></a></h4><p>Whether to perform DEX optimization immediately after installing the\napplication. This can be useful for heavy applications, such as the\ngaming applications.</section><section id=install-in-the-background class=level4 data-number=2.6.6.7><h4 data-number=2.6.6.7><span class=header-section-number>2.6.6.7</span> Install in the Background<a href=#install-in-the-background class=anchor aria-hidden=true></a></h4><p>Whether to always install applications in the background. A\nnotification will be issued once the installation is finished.</section></section><section id=subsec:backup/restore class=level3 data-number=2.6.7><h3 data-number=2.6.7><span class=header-section-number>2.6.7</span>\n<a href=#toc:subsec:backup/restore>Back up/Restore</a><a href=#subsec:backup/restore class=anchor aria-hidden=true></a></h3><p>Settings related to <a href=#sec:backup-restore>back\nup/restore</a>.<section id=compression-method class=level4 data-number=2.6.7.1><h4 data-number=2.6.7.1><span class=header-section-number>2.6.7.1</span> Compression method<a href=#compression-method class=anchor aria-hidden=true></a></h4><p>Set the compression method to be used during backups. App Manager\nsupports GZip, BZip2 and Zstandard compression methods, GZip being the\ndefault compression method. It doesn’t affect the restore of an existing\nbackup.</section><section id=subsubsec:settings-backup-options class=level4 data-number=2.6.7.2><h4 data-number=2.6.7.2><span class=header-section-number>2.6.7.2</span> Backup Options<a href=#subsubsec:settings-backup-options class=anchor aria-hidden=true></a></h4><p>Customise the <em>back up/restore dialog</em> displayed while taking\na backup.<div class=seealso-inline><p><em>Bạn cũng có thể xem: <span><a href=#subsec:backup-restore-backup-options>Backup\noptions</a></span></em></div></section><section id=backup-apps-with-android-keystore class=level4 data-number=2.6.7.3><h4 data-number=2.6.7.3><span class=header-section-number>2.6.7.3</span> Backup apps with Android\nKeyStore<a href=#backup-apps-with-android-keystore class=anchor aria-hidden=true></a></h4><p>Allow backup of applications that has entries in the Android\nKeyStore. This option is disabled by default because a few apps (such as\nSignal or Element) may crash if restored.</section><section id=subsubsec:settings-encryption class=level4 data-number=2.6.7.4><h4 data-number=2.6.7.4><span class=header-section-number>2.6.7.4</span> Encryption<a href=#subsubsec:settings-encryption class=anchor aria-hidden=true></a></h4><p>Set an encryption method for the backups. App Manager currently\nsupports OpenPGP (via <a href=https://f-droid.org/packages/org.sufficientlysecure.keychain/>OpenKeyChain</a>),\nAES, RSA and ECC. Like <a href=#subsec:apk-signing>APK signing</a>,\nThe AES, RSA and ECC keys are stored in the KeyStore and can be imported\nfrom other KeyStores.<div class=\"amalert danger\"><p><strong><em>Danger.</em></strong><p>For your own safety, it is not recommended generating RSA and ECC\nkeys inside App Manager. Instead, they should be imported from a\nKeyStore stored in a secure place.<br>In case of AES, the generated key should be stored in a secure place,\nsuch as in a password manager.</div></section><section id=subsubsec:backup-volume class=level4 data-number=2.6.7.5><h4 data-number=2.6.7.5><span class=header-section-number>2.6.7.5</span> Backup Volume<a href=#subsubsec:backup-volume class=anchor aria-hidden=true></a></h4><p>Select the storage where the backups will be stored. This is also\nwhere logs and exported APK files are saved.<div class=\"amalert tip\"><p><strong><em>Notice.</em></strong><p>The backup volume only specifies the storage, not the path. Backups\nare traditionally stored in the <code>AppManager</code> folder inside\nthe storage path. But when the path is selected using Storage Access\nFramework (SAF), the selected path or directory is used directly.</div></section><section id=import-backups class=level4 data-number=2.6.7.6><h4 data-number=2.6.7.6><span class=header-section-number>2.6.7.6</span> Import Backups<a href=#import-backups class=anchor aria-hidden=true></a></h4><p>Import backups from old and discontinued projects such as Titanium\nBackup, OAndBackup, and Swift Backup (version 3.0 to 3.2). The backups\nare not deleted after importing to prevent data loss in case the\nimported backups cannot be restored properly.</section></section><section id=subsec:rules class=level3 data-number=2.6.8><h3 data-number=2.6.8><span class=header-section-number>2.6.8</span>\n<a href=#toc:subsec:rules>Rules</a><a href=#subsec:rules class=anchor aria-hidden=true></a></h3><section id=subsubsec:instant-component-blocking class=level4 data-number=2.6.8.1><h4 data-number=2.6.8.1><span class=header-section-number>2.6.8.1</span> Instant Component\nBlocking<a href=#subsubsec:instant-component-blocking class=anchor aria-hidden=true></a></h4><p>By default, blocking rules are not applied unless they are applied\nexplicitly in <a href=#sec:app-details-page>the App Details page</a>\nfor any application. After enabling this option, all (old and new) rules\nare applied immediately for all applications without explicitly enabling\nblocking for an application.<div class=seealso-inline><p><em>Bạn cũng có thể xem: <span><a href=#subsec:faq:what-is-instant-component-blocking>FAQ: What is\ninstant component blocking?</a></span></em></div></section><section id=importexport-blocking-rules class=level4 data-number=2.6.8.2><h4 data-number=2.6.8.2><span class=header-section-number>2.6.8.2</span> Import/Export Blocking\nRules<a href=#importexport-blocking-rules class=anchor aria-hidden=true></a></h4><p>It is possible to import or export blocking rules within App Manager\nfor all applications. The types of rules (components, app ops or\npermissions) that should be imported or exported can also be selected.\nIt is also possible to import blocking rules from <a href=https://github.com/lihenggui/blocker>Blocker</a> and <a href=https://github.com/tuyafeng/Watt>Watt</a>. If it is necessary to\nexport blocking rules for a single application, the corresponding <a href=#sec:app-details-page>App Details page</a> can be used to export\nrules, or for multiple apps, <a href=#subsec:batch-operations>batch\noperations</a> can be used.<div class=seealso-inline><p><em>Bạn cũng có thể xem: <span><a href=#sec:rules-specification>Rules Specification</a></span></em></div><section id=export class=level5 data-number=2.6.8.2.1><h5 data-number=2.6.8.2.1><span class=header-section-number>2.6.8.2.1</span> Export<a href=#export class=anchor aria-hidden=true></a></h5><p>Export blocking rules for all applications configured within App\nManager. This may include <a href=#subsec:faq:what-are-app-components>app components</a>, app ops\nand permissions based on the options selected in the multi-choice\noptions.</section><section id=import class=level5 data-number=2.6.8.2.2><h5 data-number=2.6.8.2.2><span class=header-section-number>2.6.8.2.2</span> Import<a href=#import class=anchor aria-hidden=true></a></h5><p>Import previously exported blocking rules from App Manager. Similar\nto export, this may include <a href=#subsec:faq:what-are-app-components>app components</a>, app ops\nand permissions based on the options selected in the multi-choice\noptions.</section><section id=par:import-existing-rules class=level5 data-number=2.6.8.2.3><h5 data-number=2.6.8.2.3><span class=header-section-number>2.6.8.2.3</span> Import Existing Rules<a href=#par:import-existing-rules class=anchor aria-hidden=true></a></h5><p>Add components disabled by other applications to App Manager. App\nManager only keeps track of the components disabled within App Manager.\nIf application components are blocked or disabled by other tools or\napplications, this option can be utilised to import them. On clicking\nthis option, App Manager will find the components potentially disabled\nby other applications or tools and list only the name of the\napplications along with the number of matched components. For safety,\nall the applications are unselected by default. They have to be selected\nmanually, and the blocking has to be re-applied via App Manager.<div class=\"amalert danger\"><p><strong><em>Caution.</em></strong><p>Be careful when using this tool as there can be many false positives.\nChoose only the applications that you are certain about.</div></section><section id=import-from-watt class=level5 data-number=2.6.8.2.4><h5 data-number=2.6.8.2.4><span class=header-section-number>2.6.8.2.4</span> Import from Watt<a href=#import-from-watt class=anchor aria-hidden=true></a></h5><p>Import configuration files from <a href=https://github.com/tuyafeng/Watt>Watt</a>, each file containing\nrules for a single package and file name being the name of the package\nwith <code>.xml</code> extension.<div class=\"amalert tip\"><p><strong><em>Tip.</em></strong><p>Location of configuration files in Watt:\n<code>/sdcard/Android/data/com.tuyafeng.watt/files/ifw</code></div></section><section id=import-from-blocker class=level5 data-number=2.6.8.2.5><h5 data-number=2.6.8.2.5><span class=header-section-number>2.6.8.2.5</span> Import from Blocker<a href=#import-from-blocker class=anchor aria-hidden=true></a></h5><p>Import blocking rules from <a href=https://github.com/lihenggui/blocker>Blocker</a>, each file\ncontaining rules for a single package. These files have a\n<code>.json</code> extension.</section></section><section id=remove-all-rules class=level4 data-number=2.6.8.3><h4 data-number=2.6.8.3><span class=header-section-number>2.6.8.3</span> Remove all rules<a href=#remove-all-rules class=anchor aria-hidden=true></a></h4><p>One-click option to remove all rules configured within App Manager.\nThis will enable all blocked components, app ops will be set to their\ndefault values and permissions will be granted.</section></section><section id=subsec:advanced class=level3 data-number=2.6.9><h3 data-number=2.6.9><span class=header-section-number>2.6.9</span>\n<a href=#toc:subsec:advanced>Advanced</a><a href=#subsec:advanced class=anchor aria-hidden=true></a></h3><section id=subsubsec:selected-users class=level4 data-number=2.6.9.1><h4 data-number=2.6.9.1><span class=header-section-number>2.6.9.1</span> Selected Users<a href=#subsubsec:selected-users class=anchor aria-hidden=true></a></h4><p>This option lets you control the users App Manager should operate on.\nApp Manager operates on all users in root or ADB mode by default.</section><section id=subsubsec:saved-apk-name-format class=level4 data-number=2.6.9.2><h4 data-number=2.6.9.2><span class=header-section-number>2.6.9.2</span> Saved APK Name Format<a href=#subsubsec:saved-apk-name-format class=anchor aria-hidden=true></a></h4><p>Defines the format of the APK name to be used while saving it via\nbatch operations or through profiles. App Manager offers some special\nkeywords enclosed inside <code>%</code> (percentage) signs and available\nbelow the input box. These keywords are:<ul class=incremental><li><p><strong><code>label</code>.</strong> Denotes the name or label of\nthe application. This can be localised to the configured language\ndepending on the app.<li><p><strong><code>package_name</code>.</strong> Denotes the name of\nthe package or application ID, the unique identifier that each\napplication has.<li><p><strong><code>version</code>.</strong> Denotes the current\nversion of the application extracted from its manifest.<li><p><strong><code>version_code</code>.</strong> Denotes the current\nversion code of the application that can be used to separate two\nversions of the same application.<li><p><strong><code>min_sdk</code>.</strong> Denotes the minimum SDK\n(i.e. Android framework version) that the application can operate on.\nThis data is only available since Android 7 (Nougat).<li><p><strong><code>target_sdk</code>.</strong> Denotes the SDK that\nthis application targets. The application can operate on higher SDK but\nonly in the compatibility mode.<li><p><strong><code>datetime</code>.</strong> Denotes the time and date\nwhen the APK is exported.</ul></section><section id=subsubsec:import/export-keystore class=level4 data-number=2.6.9.3><h4 data-number=2.6.9.3><span class=header-section-number>2.6.9.3</span> Import/Export Keystore<a href=#subsubsec:import/export-keystore class=anchor aria-hidden=true></a></h4><p>Import or export the KeyStore used by App Manager. This is a Bouncy\nCastle KeyStore with <code>bks</code> extension. Therefore, other\nKeyStore such as Java KeyStore (JKS) or PKCS #12 are not supported. If a\nkey is needed to be imported from such a KeyStore, the relevant options\nshould be should as specified above.</section></section><section id=subsec:device-info class=level3 data-number=2.6.10><h3 data-number=2.6.10><span class=header-section-number>2.6.10</span> <a href=#toc:subsec:device-info>About the device</a><a href=#subsec:device-info class=anchor aria-hidden=true></a></h3><p>Display Android version, security, CPU, GPU, battery, memory, screen,\nlanguages, user info, etc.</section></section><section id=sec:scanner-page class=level2 data-number=2.7><h2 data-number=2.7><span class=header-section-number>2.7</span> <a href=#toc:sec:scanner-page>Scanner Page</a><a href=#sec:scanner-page class=anchor aria-hidden=true></a></h2><p><strong>Scanner page</strong> appears after clicking on the\n<em>scanner</em> button in the <a href=#subsec:app-info-tab>App Info\ntab</a>. External APK files can also be opened for scanning from file\nmanagers, web browsers, etc.<p>It scans for trackers and libraries, and displays the number of\ntrackers and libraries as a summary. It also displays checksums of the\nAPK file as well as the signing certificates. If VirusTotal is\nconfigured in the settings, it also attempts to retrieve reports from\nVirusTotal, or uploads the APK file if it is not in the database. It\nalso display a link to the <a href=https://beta.pithus.org>Pithus</a>\nreport provided the Internet features are enabled.<div class=\"amalert danger\"><p><strong><em>Disclaimer.</em></strong><p>App Manager only scans an application statically without prejudice.\nThe application may provide the options for opting out, or in some\ncases, certain features of the tracker may not be used at all by the\napplication (e.g. F-Droid), or some applications may simply use them as\nplaceholders to prevent the breaking of certain features (e.g. Fennec\nF-Droid). <strong>The intention of the scanner is to give you an idea\nabout what the APK might contain. It should be taken as an initial step\nfor further investigations.</strong></div><p>Clicking on the first item (i.e. number of classes) opens a new page\ncontaining a list of tracker classes for the application. All classes\ncan also be viewed by clicking on the <em>Toggle Class Listing</em>\nmenu. The SMALI or Java version of the class can be viewed by simply\nclicking on an item.<div class=\"amalert tip\"><p><strong><em>Notice.</em></strong><p>Due to various limitations, it is not possible to scan all the\ncomponents of an APK file. This is especially true if an APK is highly\nobfuscated or packed. The scanner also does not check strings (or\nwebsite signatures).</div><p>The second item lists the number of trackers along with their names.\nClicking on the item displays a dialog containing the name of trackers,\nmatched signatures, and the number of classes against each signature.\nSome tracker names may have <span class=\"math inline\"><sup>2</sup></span> prefix which indicates that the\ntrackers are in the <a href=https://etip.exodus-privacy.eu.org>ETIP</a> stand-by list, i.e.,\nwhether they are actual trackers is still being investigated.<p>The third item lists the number of libraries along with their names.\nThe information are mostly taken from <a href=https://gitlab.com/IzzyOnDroid/repo>IzzyOnDroid repo</a>.<div class=seealso-inline><p><em>Bạn cũng có thể xem: <span><a href=#subsec:tracker-classes-versus-tracker-components>FAQ: Tracker\nclasses vs tracker components</a></span></em></div></section><section id=sec:interceptor-page class=level2 data-number=2.8><h2 data-number=2.8><span class=header-section-number>2.8</span> <a href=#toc:sec:interceptor-page>Interceptor Page</a><a href=#sec:interceptor-page class=anchor aria-hidden=true></a></h2><p>Interceptor can be used to intercept communication between\napplications using <code>Intent</code>. It works as a man-in-the-middle\nbetween the source and the destination applications. It offers a\nfeature-complete user interface for editing <code>Intent</code>s.<div class=\"amalert warning\"><p><strong><em>Warning.</em></strong><p>Interceptor only works for <em>implicit</em> intents where the <a href=#subsec:faq:what-are-app-components>app component</a> isn’t\nspecified.</div><div class=seealso><p><em>Bạn cũng có thể xem:</em><ul class=incremental><li><p><a href=https://developer.android.com/guide/components/intents-common>Common\nIntents</a><li><p><a href=https://developer.android.com/guide/components/intents-filters>Intents\nand Intent Filters</a></ul></div><section id=subsec:intent-filters class=level3 data-number=2.8.1><h3 data-number=2.8.1><span class=header-section-number>2.8.1</span>\n<a href=#toc:subsec:intent-filters>Intent Filters</a><a href=#subsec:intent-filters class=anchor aria-hidden=true></a></h3><p>Intent filters are used by the applications to specify the tasks they\nare able to perform or the tasks they are going to perform using other\napplications. For example, when you’re opening a PDF file using a file\nmanager, the file manager will try to find the applications to open the\nPDF with. To find the right applications, the file manager will create\nan Intent with filters such as the MIME type and ask the system to\nretrieve the applications capable of opening this filter. The system\nwill search through the Manifest of the installed applications to match\nthe filter and list the application components that are able to open\nthis filter (in our case the PDF). At this, either the file manager will\nopen the desired application component all by itself or use a system\nprovided option to open it. If multiple application components are able\nto open it and no default is set, you may get a prompt where you have to\nchoose the right application component.<section id=subsubsec:action class=level4 data-number=2.8.1.1><h4 data-number=2.8.1.1><span class=header-section-number>2.8.1.1</span> Action<a href=#subsubsec:action class=anchor aria-hidden=true></a></h4><p>Action specifies the generic action to perform such as\n<code>android.intent.action.VIEW</code>. Applications often declare the\nrelevant actions in the Manifest file to catch the desired Intents. The\naction is particularly useful for broadcast Intent where it plays a\nvital rule. In other cases, it works as an initial way to filter out the\nrelevant application components. Generic actions such as\n<code>android.intent.action.VIEW</code> and\n<code>android.intent.action.SEND</code> are widely used by applications.\nHence, setting this alone may match many application components.</section><section id=subsubsec:data class=level4 data-number=2.8.1.2><h4 data-number=2.8.1.2><span class=header-section-number>2.8.1.2</span> Data<a href=#subsubsec:data class=anchor aria-hidden=true></a></h4><p>Data is originally known as URI (Uniform Resource Identifier) defined\nin <a href=http://www.faqs.org/rfcs/rfc2396.html>RFC 2396</a>. It can\nbe web links, file location, or a special feature called\n<em>content</em>. Contents are an Android feature managed by the <a href=#subsubsec:providers>content providers</a>. Data are often\nassociated with a <a href=#subsubsec:mime-type>MIME type</a>.<p>Examples:<pre><code>http://search.disroot.org/?q=URI%20in%20Android%20scheme&amp;categories=general&amp;language=en-US\nhttps://developer.android.com/reference/android/net/Uri\nfile:///sdcard/AppManager.apk\nmailto:email@example.com\ncontent://io.github.muntashirakon.AppManager.provider/23485af89b08d87e898a90c7e/AppManager.apk</code></pre></section><section id=subsubsec:mime-type class=level4 data-number=2.8.1.3><h4 data-number=2.8.1.3><span class=header-section-number>2.8.1.3</span> MIME Type<a href=#subsubsec:mime-type class=anchor aria-hidden=true></a></h4><p>MIME type of the <a href=#subsubsec:data>data</a>. For example, if\nthe data field is set to <code>file:///sdcard/AppManager.apk</code>, the\nassociated MIME type can be\n<code>application/vnd.android.package-archive</code>.</section><section id=categories class=level4 data-number=2.8.1.4><h4 data-number=2.8.1.4><span class=header-section-number>2.8.1.4</span> Categories<a href=#categories class=anchor aria-hidden=true></a></h4><p>This is similar to <a href=#subsubsec:action>action</a> in the\nsense that it is also used by the system to filter application\ncomponents. This has no further benefits. Unlike <em>action</em>, there\ncan be more than one category. Clicking on the <em>plus</em> button next\nto the title allows adding more categories.</section><section id=flags class=level4 data-number=2.8.1.5><h4 data-number=2.8.1.5><span class=header-section-number>2.8.1.5</span> Flags<a href=#flags class=anchor aria-hidden=true></a></h4><p>Flags are useful in determining how system should behave during the\nlaunch or after the launch of an activity. This should not be touched as\nit requires some technical background. The <em>plus</em> button next to\nthe title can be used to add one or more flags.</section><section id=extras class=level4 data-number=2.8.1.6><h4 data-number=2.8.1.6><span class=header-section-number>2.8.1.6</span> Extras<a href=#extras class=anchor aria-hidden=true></a></h4><p>Extras are the key-value pairs used for supplying additional\ninformation to the destination component. More extras can be added using\nthe <em>plus</em> button next to the title.</section><section id=uri class=level4 data-number=2.8.1.7><h4 data-number=2.8.1.7><span class=header-section-number>2.8.1.7</span> URI<a href=#uri class=anchor aria-hidden=true></a></h4><p>Represents the entire Intent as a URI (e.g. <code>intent://…</code>).\nSome data cannot be converted to string, and as a result, they might not\nappear here.</section></section><section id=subsec:matching-activities class=level3 data-number=2.8.2><h3 data-number=2.8.2><span class=header-section-number>2.8.2</span>\n<a href=#toc:subsec:matching-activities>Matching Activities</a><a href=#subsec:matching-activities class=anchor aria-hidden=true></a></h3><p>List all the activity components that matches the Intent. This is\ninternally determined by the system (rather than App Manager). The\nlaunch button next to each component can be used to launch them directly\nfrom App Manager.</section><section id=subsec:interceptor-reset-to-default class=level3 data-number=2.8.3><h3 data-number=2.8.3><span class=header-section-number>2.8.3</span>\n<a href=#toc:subsec:interceptor-reset-to-default>Reset to\nDefault</a><a href=#subsec:interceptor-reset-to-default class=anchor aria-hidden=true></a></h3><p>Reset the Intent to its initial state.</section><section id=subsec:interceptor-send-edited-intent class=level3 data-number=2.8.4><h3 data-number=2.8.4><span class=header-section-number>2.8.4</span>\n<a href=#toc:subsec:interceptor-send-edited-intent>Send Edited\nIntent</a><a href=#subsec:interceptor-send-edited-intent class=anchor aria-hidden=true></a></h3><p>Resend the edited Intent to the destination application. This may\nopen a list of applications where the desired application is needed to\nbe selected. The result received from the target application will be\nsent to the source application. As a result, the source application will\nnot know if there was a man-in-the-middle.</section></section><section id=sec:shared-preferences-editor-page class=level2 data-number=2.9><h2 data-number=2.9><span class=header-section-number>2.9</span> <a href=#toc:sec:shared-preferences-editor-page>Shared Preferences Editor\nPage</a><a href=#sec:shared-preferences-editor-page class=anchor aria-hidden=true></a></h2><p>Shared preferences can be edited in this page. Clicking any item on\nthe list opens the edit dialog where the item can be edited. The\nfloating action button in the bottom-right corner can be used to add a\nnew item. To save or delete the file, or to discard current changes, the\nrespective options in the menu can be used.</section></section><section id=ch:guides class=level1 data-number=3><h1 data-number=3><span class=header-section-number>3</span> <a href=#toc:ch:guides>Guides</a><a href=#ch:guides class=anchor aria-hidden=true></a></h1><section id=sec:adb-over-tcp class=level2 data-number=3.1><h2 data-number=3.1><span class=header-section-number>3.1</span> <a href=#toc:sec:adb-over-tcp>ADB over TCP</a><a href=#sec:adb-over-tcp class=anchor aria-hidden=true></a></h2><p>Many root-only features can still be used by enabling ADB over TCP.\nTo do that, a PC or Mac is required with Android platform-tools\ninstalled, and an Android phone with developer options & USB\ndebugging enabled.<div class=\"amalert tip\"><p><strong><em>Root users.</em></strong><p>If superuser permission has been granted to App Manager, it can\nalready execute privileged code without any problem. <strong>Therefore,\nroot users do not need to enable ADB over TCP.</strong> But if you\ninsist on using ADB over TCP, you must revoke superuser permission for\nApp Manager.</div><div class=seealso-inline><p><em>Bạn cũng có thể xem: <span><a href=#sec:faq:adb-over-tcp>FAQ:\nADB over TCP</a></span></em></div><section id=subsec:enable-developer-options class=level3 data-number=3.1.1><h3 data-number=3.1.1><span class=header-section-number>3.1.1</span>\n<a href=#toc:subsec:enable-developer-options>Enable developer\noptions</a><a href=#subsec:enable-developer-options class=anchor aria-hidden=true></a></h3><section id=subsubsec:location-of-developer-options class=level4 data-number=3.1.1.1><h4 data-number=3.1.1.1><span class=header-section-number>3.1.1.1</span> Location of developer\noptions<a href=#subsubsec:location-of-developer-options class=anchor aria-hidden=true></a></h4><p><strong>Developer options</strong> is located in Android\n<strong>Settings</strong>, either directly near the bottom of the page\n(in most ROMs) or under some other settings, such as\n<strong>System</strong> (Google Pixel, Lineage OS, Asus Zenfone 8.0+),\n<strong>Additional Settings</strong> (Xiaomi MIUI, Oppo ColorOS),\n<strong>More Settings</strong> (Vivo FuntouchOS), <strong>More</strong>\n(ZTE Nubia). Unlike other options, it is not visible until explicitly\nenabled by the user. If it is already enabled, you can use the search\nbox in Android <strong>Settings</strong> to locate it as well.</section><section id=how-to-enable-developer-options class=level4 data-number=3.1.1.2><h4 data-number=3.1.1.2><span class=header-section-number>3.1.1.2</span> How to enable developer\noptions<a href=#how-to-enable-developer-options class=anchor aria-hidden=true></a></h4><p>This option is available within Android <strong>Settings</strong> as\nwell but like the location of the developer options, it also differs\nfrom device to device. But in general, you have to find <strong>Build\nnumber</strong> (or <strong>MIUI version</strong> for MIUI ROMs and\n<strong>Software version</strong> for Vivo FuntouchOS,\n<strong>Version</strong> for Oppo ColorOS) and tap it at least 7 (seven)\ntimes until you finally get a message saying <em>You are now a\ndeveloper</em> (you may be prompted to insert pin/password/pattern or\nsolve captchas at this point). In most devices, it is located at the\nbottom of the settings page, inside <strong>About Phone</strong>. But\nthe best way to find it is to use the search box.</section></section><section id=subsec:enable-usb-debugging class=level3 data-number=3.1.2><h3 data-number=3.1.2><span class=header-section-number>3.1.2</span>\n<a href=#toc:subsec:enable-usb-debugging>Enable USB debugging</a><a href=#subsec:enable-usb-debugging class=anchor aria-hidden=true></a></h3><p>After <a href=#subsubsec:location-of-developer-options>locating the\ndeveloper options</a>, enable <strong>Developer option</strong> (if not\nalready). After that, scroll down a bit until you will find the option\n<strong>USB debugging</strong>. Use the toggle button on the right-hand\nside to enable it. At this point, you may get an alert prompt where you\nmay have to click <em>OK</em> to actually enable it. You may also have\nto enable some other options depending on device vendor and ROM. Here\nare some examples:<section id=xiaomi-miui class=level4 data-number=3.1.2.1><h4 data-number=3.1.2.1><span class=header-section-number>3.1.2.1</span> Xiaomi (MIUI)<a href=#xiaomi-miui class=anchor aria-hidden=true></a></h4><p>Enable <strong>USB debugging (Security settings)</strong> as\nwell.</section><section id=huawei-emui class=level4 data-number=3.1.2.2><h4 data-number=3.1.2.2><span class=header-section-number>3.1.2.2</span> Huawei (EMUI)<a href=#huawei-emui class=anchor aria-hidden=true></a></h4><p>Enable <strong>Allow ADB debugging in charge only mode</strong> as\nwell. When connecting to your PC or Mac, you may get a prompt saying\n<strong>Allow access to device data?</strong> in which case click\n<strong>YES, ALLOW ACCESS</strong>.<div class=\"amalert tip\"><p><strong><em>Notice.</em></strong><p>Often the <strong>USB debugging</strong> mode could be disabled\nautomatically by the system. If that’s the case, repeat the above\nprocedure.</div></section><section id=realme class=level4 data-number=3.1.2.3><h4 data-number=3.1.2.3><span class=header-section-number>3.1.2.3</span> Realme<a href=#realme class=anchor aria-hidden=true></a></h4><p>Depending on the device and the version of operating system, you have\nto enable <strong>Disable Permission Monitoring</strong>, or <strong>USB\ndebugging (Security settings)</strong> along with <strong>Install via\nUSB</strong>.</section><section id=oneplus-oxygen-os class=level4 data-number=3.1.2.4><h4 data-number=3.1.2.4><span class=header-section-number>3.1.2.4</span> OnePlus (Oxygen OS)<a href=#oneplus-oxygen-os class=anchor aria-hidden=true></a></h4><p>Depending on the device and the version of operating system, you have\nto enable <strong>Disable Permission Monitoring</strong>.</section><section id=lg class=level4 data-number=3.1.2.5><h4 data-number=3.1.2.5><span class=header-section-number>3.1.2.5</span> LG<a href=#lg class=anchor aria-hidden=true></a></h4><p>Make sure you have <strong>USB tethering</strong> enabled.</section><section id=troubleshooting class=level4 data-number=3.1.2.6><h4 data-number=3.1.2.6><span class=header-section-number>3.1.2.6</span> Troubleshooting<a href=#troubleshooting class=anchor aria-hidden=true></a></h4><p>In case <strong>USB Debugging</strong> is greyed out, you can do the\nfollowing:<ol class=incremental><li><p>Make sure you enabled USB debugging before connecting your phone\nto the PC or Mac via USB cable<li><p>Enable USB tethering after connecting to PC or Mac via USB\ncable<li><p>(For Samsung) If your device is running KNOX, you may have to\nfollow some additional steps. See official documentations or consult\nsupport for further assistant</ol></section></section><section id=subsec:setup-adb-on-pc-or-mac class=level3 data-number=3.1.3><h3 data-number=3.1.3><span class=header-section-number>3.1.3</span>\n<a href=#toc:subsec:setup-adb-on-pc-or-mac>Setup ADB on PC or\nMac</a><a href=#subsec:setup-adb-on-pc-or-mac class=anchor aria-hidden=true></a></h3><p>In order to enable ADB over TCP, you have to set up ADB in your PC or\nMac. <strong><em>Lineage OS users can skip to §<a href=#subsubsec:lineage-os data-reference-type=ref data-reference=subsubsec:lineage-os>3.1.4.1</a>.</em></strong><section id=windows class=level4 data-number=3.1.3.1><h4 data-number=3.1.3.1><span class=header-section-number>3.1.3.1</span> Windows<a href=#windows class=anchor aria-hidden=true></a></h4><ol class=incremental><li><p>Download the latest version of <a href=https://dl.google.com/android/repository/platform-tools-latest-windows.zip>Android\nSDK Platform-Tools</a> for Windows<li><p>Extract the contents of the zip file into any directory (such as\n<code>C:\\</code><span><code>adb</code></span>) and navigate to that\ndirectory using <em>Explorer</em><li><p>Open <strong>Command Prompt</strong>,\n<strong>PowerShell</strong>, or <strong>Terminal</strong> from this\ndirectory. You can do it manually from the start menu or by holding\n<code>Shift</code> and right clicking within the directory in <em>File\nExplorer</em> and then clicking either on <em>Open command window\nhere</em>, or <em>Open PowerShell window here</em> (depending on what\nyou have installed). You can now access ADB by typing <code>adb</code>\n(Command Prompt) or <code>./adb</code> (PowerShell). Do not close this\nwindow yet.</ol><div class=\"amalert tip\"><p><strong><em>Tip.</em></strong><p>If you have <a href=https://learn.microsoft.com/en-us/windows/package-manager/winget/>WinGet</a>\ninstalled, you can install ADB using the following command:<div class=sourceCode id=cb3 data-frame=lines><pre class=\"sourceCode bash\"><code class=\"sourceCode bash\"><span id=cb3-1><a href=#cb3-1 aria-hidden=true tabindex=-1></a><span class=ex>winget</span> install <span class=at>--id</span> Google.PlatformTools</span></code></pre></div><p>After that, you can simply type <code>adb</code> to access ADB.</div></section><section id=macos class=level4 data-number=3.1.3.2><h4 data-number=3.1.3.2><span class=header-section-number>3.1.3.2</span> macOS<a href=#macos class=anchor aria-hidden=true></a></h4><ol class=incremental><li><p>Download the latest version of <a href=https://dl.google.com/android/repository/platform-tools-latest-darwin.zip>Android\nSDK Platform-Tools</a> for macOS<li><p>Extract the contents of the zip file into a directory by clicking\non it. After that, navigate to that directory using <em>Finder</em> and\nlocate <code>adb</code><li><p>Open <strong>Terminal</strong> using <em>Launchpad</em> or\n<em>Spotlight</em> and drag-and-drop <code>adb</code> from the\n<em>Finder</em> window into the <em>Terminal</em> window. Do not close\nthe <em>Terminal</em> window yet</ol><div class=\"amalert tip\"><p><strong><em>Tip.</em></strong><p>If you have <a href=https://brew.sh>Homebrew</a> installed, you can\ninstall ADB using the following command:<div class=sourceCode id=cb4 data-frame=lines><pre class=\"sourceCode bash\"><code class=\"sourceCode bash\"><span id=cb4-1><a href=#cb4-1 aria-hidden=true tabindex=-1></a><span class=ex>brew</span> install <span class=at>--cask</span> android-platform-tools</span></code></pre></div><p>After that, you can simply type <code>adb</code> in any\n<em>Terminal</em> window to access ADB.</div></section><section id=linux class=level4 data-number=3.1.3.3><h4 data-number=3.1.3.3><span class=header-section-number>3.1.3.3</span> Linux<a href=#linux class=anchor aria-hidden=true></a></h4><ol class=incremental><li><p>In your favourite terminal emulator, run the following\ncommand:<div class=sourceCode id=cb5 data-frame=lines data-autogobble><pre class=\"sourceCode bash\"><code class=\"sourceCode bash\"><span id=cb5-1><a href=#cb5-1 aria-hidden=true tabindex=-1></a><span class=bu>cd</span> ~/Downloads <span class=kw>&amp;&amp;</span> <span class=ex>curl</span> <span class=at>-o</span> platform-tools.zip <span class=at>-L</span> <span class=dt>\\</span></span>\n<span id=cb5-2><a href=#cb5-2 aria-hidden=true tabindex=-1></a>https://dl.google.com/android/repository/platform-tools-latest-linux.zip <span class=kw>&amp;&amp;</span> <span class=dt>\\</span></span>\n<span id=cb5-3><a href=#cb5-3 aria-hidden=true tabindex=-1></a><span class=fu>unzip</span> platform-tools.zip <span class=kw>&amp;&amp;</span> <span class=fu>rm</span> platform-tools.zip <span class=kw>&amp;&amp;</span> <span class=bu>cd</span> platform-tools</span></code></pre></div><li><p>If it is successful, you can simply type <code>./adb</code> in\nthe in <em>same</em> terminal emulator window or type\n<code>~/Downloads/platform-tools/adb</code> in any terminal emulator to\naccess ADB.</ol></section></section><section id=subsec:configure-adb-over-tcp class=level3 data-number=3.1.4><h3 data-number=3.1.4><span class=header-section-number>3.1.4</span>\n<a href=#toc:subsec:configure-adb-over-tcp>Configure ADB over\nTCP</a><a href=#subsec:configure-adb-over-tcp class=anchor aria-hidden=true></a></h3><section id=subsubsec:lineage-os class=level4 data-number=3.1.4.1><h4 data-number=3.1.4.1><span class=header-section-number>3.1.4.1</span> Lineage OS 17.1 and\nEarlier<a href=#subsubsec:lineage-os class=anchor aria-hidden=true></a></h4><p>Lineage OS (or its derivatives) users can directly enable ADB over\nTCP using the developer options. To enable that, go to the\n<strong>Developer options</strong>, scroll down until you find\n<strong>ADB over Network</strong>. Now, use the toggle button on the\nright-hand side to enable it and skip to §<a href=#subsubsec:adb-mode-in-app-manager data-reference-type=ref data-reference=subsubsec:adb-mode-in-app-manager>3.1.4.3</a>.<div class=\"amalert warning\"><p><strong><em>Warning.</em></strong><p>You can turn off <strong>ADB over Network</strong> in developer\noptions, but turning off this option will also stop App Manager’s remote\nserver. So, turn it off only when you’re not going to use App Manager in\nADB over TCP mode.</div></section><section id=subsubsec:enable-adb-over-tcp-via-pc-or-mac class=level4 data-number=3.1.4.2><h4 data-number=3.1.4.2><span class=header-section-number>3.1.4.2</span> Enable ADB over TCP via PC\nor Mac<a href=#subsubsec:enable-adb-over-tcp-via-pc-or-mac class=anchor aria-hidden=true></a></h4><p>For other ROMs, you can do this using the command\nprompt/PowerShell/terminal emulator that you’ve opened in the step 3 of\nthe previous section. In this section, I will use <code>adb</code> to\ndenote <code>./adb</code>, <code>adb</code> or any other command that\nyou needed to use based on your platform and software in the previous\nsection.<ol class=incremental><li><p>Connect your device to your PC or Mac using a USB cable. For some\ndevices, it is necessary to turn on <em>File transfer mode (MTP)</em> as\nwell<li><p>To confirm that everything is working as expected, type\n<code>adb devices</code> in your terminal. If your device is connected\nsuccessfully, you will see something like this:<pre><code>List of devices attached\nxxxxxxxx  device</code></pre><div class=\"amalert tip\"><p><strong><em>Notice.</em></strong><p>In some Android phones, an alert prompt will be appeared with a\nmessage <strong>Allow USB Debugging</strong> in which case, check\n<em>Always allow from this computer</em> and click\n<strong>Allow</strong>.</div><li><p>Finally, run the following command to enable ADB over TCP:<div class=sourceCode id=cb7 data-frame=lines data-autogobble><pre class=\"sourceCode bash\"><code class=\"sourceCode bash\"><span id=cb7-1><a href=#cb7-1 aria-hidden=true tabindex=-1></a><span class=ex>adb</span> tcpip 5555</span></code></pre></div></ol><div class=\"amalert danger\"><p><strong><em>Danger.</em></strong><p>You cannot disable developer options or USB debugging after enabling\nADB over TCP.</div></section><section id=subsubsec:adb-mode-in-app-manager class=level4 data-number=3.1.4.3><h4 data-number=3.1.4.3><span class=header-section-number>3.1.4.3</span> Enable ADB mode in App\nManager<a href=#subsubsec:adb-mode-in-app-manager class=anchor aria-hidden=true></a></h4><p>After enabling ADB over TCP, relaunch App Manager. App Manager should\ndetect ADB mode automatically. If it cannot, you can change the mode of\noperation to ADB over TCP in the <a href=#subsec:mode-of-operation>settings page</a>. There, you can also\nverify whether App Manager has correctly detected ADB as indicated by\nthe <em>inferred mode</em>.<div class=\"amalert tip\"><p><strong><em>Notice.</em></strong><p>In some Android devices, the USB cable is needed to be disconnected\nfrom the PC before connecting to App Manager.</div><div class=\"amalert warning\"><p><strong><em>Warning.</em></strong><p>ADB over TCP will be disabled after a reboot. In that case, you have\nto follow §<a href=#subsubsec:enable-adb-over-tcp-via-pc-or-mac data-reference-type=ref data-reference=subsubsec:enable-adb-over-tcp-via-pc-or-mac>3.1.4.2</a>\nagain.</div></section></section></section><section id=sec:wireless-debugging class=level2 data-number=3.2><h2 data-number=3.2><span class=header-section-number>3.2</span> <a href=#toc:sec:wireless-debugging>Wireless Debugging</a><a href=#sec:wireless-debugging class=anchor aria-hidden=true></a></h2><p>If you are running Android 11 or later and capable of connecting to a\nWi-Fi network for, at least, a few moments, Wireless Debugging is the\nrecommended approach as it offers more protection than <a href=#sec:adb-over-tcp>ADB over TCP</a>. It requires two steps:<ol class=incremental><li><p><strong>ADB pairing.</strong> The initial and a bit complex step\nfor a novice user. Fortunately, this step is not required all the\ntime.<li><p><strong>Connecting to ADB.</strong> Needs to be done every time\nyou reboot your phone. App Manager can also automate this step in most\ndevices.</ol><section id=subsec:enable-developer-options-and-usb-debugging class=level3 data-number=3.2.1><h3 data-number=3.2.1><span class=header-section-number>3.2.1</span>\n<a href=#toc:subsec:enable-developer-options-and-usb-debugging>Enable\ndeveloper options and USB Debugging</a><a href=#subsec:enable-developer-options-and-usb-debugging class=anchor aria-hidden=true></a></h3><p>See §<a href=#subsec:enable-developer-options data-reference-type=ref data-reference=subsec:enable-developer-options>3.1.1</a> and §<a href=#subsec:enable-usb-debugging data-reference-type=ref data-reference=subsec:enable-usb-debugging>3.1.2</a>.</section><section id=subsec:enable-wireless-debugging class=level3 data-number=3.2.2><h3 data-number=3.2.2><span class=header-section-number>3.2.2</span>\n<a href=#toc:subsec:enable-wireless-debugging>Enable Wireless\nDebugging</a><a href=#subsec:enable-wireless-debugging class=anchor aria-hidden=true></a></h3><p>In the <strong>Developer options</strong> page, find <strong>Wireless\ndebugging</strong> and click to open it. In the new page, turn on\n<em>Use wireless debugging</em>. Depending on the operating system, you\nmight see a dialog prompt asking you to verify your decision. If that is\nthe case, click <em>Allow</em>.<div class=\"amalert tip\"><p><strong><em>Tip.</em></strong><p>For easy access, you might want to add <strong>Wireless\ndebugging</strong> in the notification tiles section. To do this, find\n<strong>Quick settings developer tiles</strong> in the <strong>Developer\noptions</strong> page and click to open it. In the new window, enable\n<em>Wireless debugging</em>. In case you do not see this setting, you\nmay find a <strong>Wireless debugging</strong> tile in the tile\ncustomization panel.</div></section><section id=subsec:pair-adb-with-app-manager class=level3 data-number=3.2.3><h3 data-number=3.2.3><span class=header-section-number>3.2.3</span>\n<a href=#toc:subsec:pair-adb-with-app-manager>Pair ADB with App\nManager</a><a href=#subsec:pair-adb-with-app-manager class=anchor aria-hidden=true></a></h3><p>In App Manager, navigate to <strong>Settings</strong> > <a href=#subsec:mode-of-operation>Mode of operation</a> and then enable\n<em>Wireless debugging</em>. At this, App Manager will try to establish\na wireless debugging connection automatically which will fail if it has\nnot been paired before. Once it fails, it will ask you to either connect\nor pair ADB. Select <em>pair</em> and a new dialog will appear. It will\nask you to navigate to the <strong>Wireless debugging</strong> page.<div class=\"amalert tip\"><p><strong><em>Note.</em></strong><p>As of v4.0.0, pairing is done using a notification prompt. So, if you\nhave disabled notification for App Manager, you must enable it\nfirst.</div><p>In the <strong>Wireless debugging</strong> page, select <strong>Pair\ndevice with pairing code</strong>. At this, a dialog containing a\npairing code will be displayed. A notification asking for the pairing\ncode will also be visible almost instantly. Insert the pairing code in\nthe input box in the notification and click <em>pair</em>. If the\npairing is successful, App Manager will display notification with the\nmessage “paired”, and the dialog in the <strong>Wireless\ndebugging</strong> page will be dismissed automatically. You will also\nbe able to see App Manager listed as an ADB client in the same page.<div class=\"amalert tip\"><p><strong><em>Notice.</em></strong><p>If you do not use App Manager in ADB mode for a while, App Manager\nmight be removed from the list of clients. In that case, you have to\nrepeat the above procedure.</div></section><section id=subsec:connect-app-manager-to-adb class=level3 data-number=3.2.4><h3 data-number=3.2.4><span class=header-section-number>3.2.4</span>\n<a href=#toc:subsec:connect-app-manager-to-adb>Connect App Manager to\nADB</a><a href=#subsec:connect-app-manager-to-adb class=anchor aria-hidden=true></a></h3><p>App Manager should be able to connect to ADB automatically if the\nmode of operation is set to <em>auto</em>, <em>ADB over TCP</em> or\n<em>Wireless debugging</em>. If this is not the case, select\n<em>Wireless debugging</em> in <strong>Settings</strong> > <a href=#subsec:mode-of-operation>Mode of operation</a>. If App Manager\nfails to detect or connect to ADB, it will ask you to connect or pair\nADB. Select <em>connect</em>.<p>Now, navigate to the <strong>Wireless debugging</strong> page in\nAndroid settings, and note down the port number displayed in the page.\nIn App Manager’s dialog prompt, replace the port number with the one you\nhave noted earlier, and click <em>connect</em>.<p>Once a connection has been established, you can disable\n<strong>Wireless debugging</strong> in Android settings.<div class=\"amalert danger\"><p><strong><em>Caution.</em></strong><p>Never disable <strong>USB Debugging</strong> or any other additional\noptions described in §<a href=#subsec:enable-developer-options-and-usb-debugging data-reference-type=ref data-reference=subsec:enable-developer-options-and-usb-debugging>3.2.1</a>.\nIf you do this, the remote server used by App Manager will be stopped,\nand you may have to start all over again.</div></section></section><section id=sec:backup-restore class=level2 data-number=3.3><h2 data-number=3.3><span class=header-section-number>3.3</span> <a href=#toc:sec:backup-restore>Back up/Restore</a><a href=#sec:backup-restore class=anchor aria-hidden=true></a></h2><p>App Manager has a modern, advanced and easy-to-use backup/restore\nsystem implemented from the scratch. This is probably the only app that\nhas the ability to restore not only the app or its data but also\npermissions and rules that you’ve configured within App Manager. You can\nalso choose to back up an app multiple times (with custom names) or for\nall users.<div class=seealso><p><em>Bạn cũng có thể xem:</em><ul class=incremental><li><p><a href=#subsec:1-click-back-up>1-Click Ops: Back\nup</a><li><p><a href=#subsec:1-click-restore>1-Click Ops:\nRestore</a></ul></div><section id=subsec:backup-location class=level3 data-number=3.3.1><h3 data-number=3.3.1><span class=header-section-number>3.3.1</span>\n<a href=#toc:subsec:backup-location>Location</a><a href=#subsec:backup-location class=anchor aria-hidden=true></a></h3><p>Back up/restore is a part of <a href=#subsec:batch-operations>batch\noperations</a>. It is also located inside the <a href=#subsubsec:app-info-options-menu>options menu</a> in the <a href=#subsec:app-info-tab>App Info tab</a>. Clicking on\n<strong>Backup/Restore</strong> opens the <strong>Backup\nOptions</strong>. Backups are located at\n<code>/storage/emulated/0/AppManager</code> by default. You can\nconfigure custom backup location in the <a href=#subsubsec:backup-volume>settings page</a> in which case the\nbackups will be located at the <code>AppManager</code> folder in the\nselected volume.<div class=\"amalert tip\"><p><strong><em>Note.</em></strong><p>If one or more selected apps do not have any backup, the\n<strong>Restore</strong> and <strong>Delete Backup</strong> options will\nnot be displayed.</div></section><section id=subsec:backup-restore-backup-options class=level3 data-number=3.3.2><h3 data-number=3.3.2><span class=header-section-number>3.3.2</span>\n<a href=#toc:subsec:backup-restore-backup-options>Backup Options</a><a href=#subsec:backup-restore-backup-options class=anchor aria-hidden=true></a></h3><p>Backup options (internally known as backup flags) let you customise\nthe backups on the fly. However, the customisations will not be\nremembered for the future backups. If you want to customise this dialog,\nuse <a href=#subsubsec:settings-backup-options>Backup Options</a> in\nthe <a href=#sec:settings-page>Settings page</a>.<p>A complete description of the backup options is given below:<ul class=incremental><li><p><strong>APK files.</strong> Whether to back up the APK files.\nThis includes the <em>base APK</em> file along with the\n<code>split APK</code> files if they exist.<li><p><strong>Internal data.</strong> Whether to back up the internal\ndata directories. These directories are located at\n<code>/data/user/&lt;user_id></code> and (for Android N or later)\n<code>/data/user_de/&lt;user_id></code>.<li><p><strong>External data.</strong> Whether to back up data\ndirectories located in the internal memory as well as SD Card (if\nexists). External data directories often contain non-essential app data\nor media files (instead of using the dedicated media folder) and may\nincrease the backup size. However, it might be essential for some apps.\nAlthough it isn’t checked by default (as it might dramatically increase\nthe size of the backups), you may have to check it in order to ensure a\nsmooth restore of your backups.<div class=\"amalert warning\"><p><strong><em>Caution.</em></strong><p>Internal data folders should always be backed up if you are going to\nback up the external data folders. However, it could be useful to back\nup only the external folders if the app in question downloads a lot of\nassets from the Internet.</div><li><p><strong>OBB and media.</strong> Whether to back up or restore the\nOBB and the media directories located in the external storage or the SD\nCard. This is useful for games and the graphical software which actually\nuse these folders.<li><p><strong>Cache.</strong> Android apps have multiple cache\ndirectories located at every data directories (both internal and\nexternal). There are two types of cache: <strong>cache</strong> and\n<strong>code cache</strong>. Disabling this option excludes both cache\ndirectories from all the data directories. It is generally advised to\nexclude cache directories since most apps do not clear the cache\nregularly and usually handled by the OS itself. Apps such as Telegram\nmay use a very large cache (depending on the storage space) which may\ndramatically increase the backup size. When it is disabled, AM also\nignores the <strong>no_backup</strong> directories.<li><p><strong>Extras.</strong> Backup/restore app permissions, net\npolicy, battery optimization, SSAID, etc., enabled by default. Note\nthat, blocking rules are applied <em>after</em> applying the extras. So,\nif an item is present in both places, it will be overwritten (i.e., the\none from the blocking rules will be used).<li><p><strong>Rules.</strong> This option lets you back up blocking\nrules configured within App Manager. This might come in handy if you\nhave customised permissions or block some components using App Manager\nas they will also be backed up or restored when you enable this\noption.<li><p><strong>Backup Multiple.</strong> Whether this is a multiple\nbackup. By default, backups are saved using their user ID. Enabling this\noption allows you to create additional backups. These backups use the\ncurrent date-time as the default backup name, but you can also specify\ncustom backup name using the input field displayed when you click on the\n<strong>Backup</strong> button.<li><p><strong>Custom users.</strong> Backup or restore for the selected\nusers instead of only the current user. This option is only displayed if\nthe system has more than one user.<li><p><strong>Skip signature checks.</strong> When taking a backup,\nchecksum of every file (as well as the signing certificate(s) of the\nbase APK file) is generated and stored in the <code>checksums.txt</code>\nfile. When you restore the backup, the checksums are generated again and\nare matched with the checksums stored in the said file. Enabling this\noption will disable the signature checks. This option is applied only\nwhen you restore a backup. During backup, the checksums are generated\nregardless of this option.<div class=\"amalert warning\"><p><strong><em>Caution.</em></strong><p>You should always disable this option to ensure that your backups are\nnot modified by any third-party applications. However, this would only\nwork if you enabled encryption.</div></ul><div class=seealso-inline><p><em>Bạn cũng có thể xem: <span><a href=#subsubsec:settings-encryption>Settings:\nEncryption</a></span></em></div></section><section id=subsec:backup-restore-backup class=level3 data-number=3.3.3><h3 data-number=3.3.3><span class=header-section-number>3.3.3</span>\n<a href=#toc:subsec:backup-restore-backup>Backup</a><a href=#subsec:backup-restore-backup class=anchor aria-hidden=true></a></h3><p>Backup respects all the backup options except <strong>Skip signature\nchecks</strong>. If base backups (i.e., backups that don’t have the\n<strong>Backup Multiple</strong> option) already exist, you will get a\nwarning as the backups will be overwritten. If <strong>Backup\nMultiple</strong> is set, you have an option to input the backup name,\nor you can leave it blank to use the current date-time.</section><section id=subsec:backup-restore-restore class=level3 data-number=3.3.4><h3 data-number=3.3.4><span class=header-section-number>3.3.4</span>\n<a href=#toc:subsec:backup-restore-restore>Restore</a><a href=#subsec:backup-restore-restore class=anchor aria-hidden=true></a></h3><p>Restore respects all the backup options and will fail if <strong>APK\nfiles</strong> option is set, but the backup doesn’t contain such\nbackups or in other cases, if the app isn’t installed. When restoring\nbackups for multiple packages, you can only restore the base backups\n(see <a href=#subsec:backup-restore-backup>backup</a> section for an\nexplanation). However, when restoring backups for a single package, you\nhave the option to select which backup to restore. If <strong>All\nusers</strong> option is set, AM will restore the selected backup for\nall users in the latter case but in the former case, it will restore\nbase backups for the respective users.<div class=\"amalert tip\"><p><strong><em>Notice.</em></strong><p>Apps that use storage access framework (SAF), SSAID or Android\nKeyStore works properly only after an immediate restart.</div></section><section id=subsec:backup-restore-delete-backup class=level3 data-number=3.3.5><h3 data-number=3.3.5><span class=header-section-number>3.3.5</span>\n<a href=#toc:subsec:backup-restore-delete-backup>Delete Backup</a><a href=#subsec:backup-restore-delete-backup class=anchor aria-hidden=true></a></h3><p>Delete backup only respects <strong>All users</strong> option and\nwhen it is selected, only the base backups for all users will be deleted\nwith a prompt. When deleting backups for a single package, another\ndialog will be displayed where you can select the backups to delete.</section></section><section id=sec:automating-tasks class=level2 data-number=3.4><h2 data-number=3.4><span class=header-section-number>3.4</span> <a href=#toc:sec:automating-tasks>Automating Tasks</a><a href=#sec:automating-tasks class=anchor aria-hidden=true></a></h2><p>It is possible to trigger profiles configured inside App Manager via\nthird-party applications such as <strong>Automation</strong> or\n<strong>Tasker</strong>. Traditionally, <code>Intent</code>s are used to\ntrigger such operations.<section id=subsec:generating-authorization-key class=level3 data-number=3.4.1><h3 data-number=3.4.1><span class=header-section-number>3.4.1</span>\n<a href=#toc:subsec:generating-authorization-key>Generating\nauthorization key</a><a href=#subsec:generating-authorization-key class=anchor aria-hidden=true></a></h3><p>In order to ensure proper security, an authorization key is required.\nTo generate a authorization key, go to <strong>Settings</strong> page\nand then <strong>Privacy</strong> > <strong>Authorization\nManager</strong>. If an authorization key has not been generated, it\nwill be generated automatically. The key can be regenerated as\nrequired.<div class=\"amalert danger\"><p><strong><em>Caution.</em></strong><p>Regenerating the authorization key can have some side effects such as\ninvalidation of all the previously configured Intents.</div></section><section id=subsec:at:general-configuration class=level3 data-number=3.4.2><h3 data-number=3.4.2><span class=header-section-number>3.4.2</span>\n<a href=#toc:subsec:at:general-configuration>Configuring tasks</a><a href=#subsec:at:general-configuration class=anchor aria-hidden=true></a></h3><p>The activity\n<code>io.github.muntashirakon.AppManager.crypto.auth.AuthFeatureDemultiplexer</code>\nis responsible for handling all the automations. Sending an intent to\nthe activity lets App Manager perform the designated operation by\nredirecting the <code>Intent</code> to the designated activity or\nservice.<section id=required-extras class=level4 data-number=3.4.2.1><h4 data-number=3.4.2.1><span class=header-section-number>3.4.2.1</span> Required extras<a href=#required-extras class=anchor aria-hidden=true></a></h4><p>It has two primary extras required in all conditions. The key names,\ndata types are all follows:<ol class=incremental><li><p><strong><code>auth</code>.</strong> (String value) The\nauthorization key as described in the earlier section.<li><p><strong><code>feature</code>.</strong> (String value) Name of the\nfeature. Supported features are described in the next section.</ol></section></section><section id=subsec:at:features class=level3 data-number=3.4.3><h3 data-number=3.4.3><span class=header-section-number>3.4.3</span>\n<a href=#toc:subsec:at:features>Features</a><a href=#subsec:at:features class=anchor aria-hidden=true></a></h3><p>App Manager current support a single feature, namely\n<code>profile</code>.</section><section id=subsec:triggering-a-profile class=level3 data-number=3.4.4><h3 data-number=3.4.4><span class=header-section-number>3.4.4</span>\n<a href=#toc:subsec:triggering-a-profile>Triggering a profile</a><a href=#subsec:triggering-a-profile class=anchor aria-hidden=true></a></h3><p>In order to trigger a profile, <code>feature</code> must have the\nvalue <code>profile</code>. In addition, the following extras can be\nincluded:<ol class=incremental><li><p><strong><code>prof</code>.</strong> (String value – required) The\nname of the profile as displayed in the <a href=#sec:profiles-page>Profiles page</a>.<li><p><strong><code>state</code>.</strong> (String value – optional)\nState of the profile – currently <code>on</code> or <code>off</code> –\nas specified in the documentation. If this extra is not set, App Manager\nwill display a prompt where a state must be selected. Therefore, for\ncomplete automation, this option should be set.</ol></section></section><section id=sec:net-policy class=level2 data-number=3.5><h2 data-number=3.5><span class=header-section-number>3.5</span> <a href=#toc:sec:net-policy>Net Policy</a><a href=#sec:net-policy class=anchor aria-hidden=true></a></h2><p>Short for <strong>Network policy</strong> or network policies. It is\nusually located in the Android settings under <strong>Mobile data &\nWifi</strong> section in the app info page of an app. Not all policies\nare guaranteed to be included in this page (e.g. Samsung), and not all\nsettings are well-understood due to lack of documentation. App Manager\ncan display all the net policies declared in the <a href=https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/net/NetworkPolicyManager.java>NetworkPolicyManager</a>.\nPolicies unknown to App Manager will have a <em>Unknown</em> prefix\nalong with the policy constant name and number in the hexadecimal\nformat. Unknown policies should be reported to App Manager for\ninclusion.<p>Net policy allows a user to configure certain networking behaviour of\nan app without modifying the ip tables directly and/or running a\nfirewall app. However, the features it offers largely depend on Android\nversion and ROM. A list of known net policies are listed below:<ol class=incremental><li><p><strong>None</strong> or\n<strong><code>POLICY_NONE</code></strong>: (AOSP) No specific network\npolicy is set. System can still assign rules depending on the nature of\nthe app.<li><p><strong>Reject background data on metered networks</strong> or\n<strong><code>POLICY_REJECT_METERED_BACKGROUND</code></strong>: (AOSP)\nReject network usage on metered networks when the application is in\nbackground.<li><p><strong>Allow background data on metered networks even when Data\nSaver is on</strong> or\n<strong><code>POLICY_ALLOW_METERED_BACKGROUND</code></strong>: (AOSP)\nAllow metered network use in the background even when data saving mode\nis enabled.<li><p><strong>Reject cellular data</strong> or\n<strong><code>POLICY_REJECT_CELLULAR</code></strong> (Android 11+) or\n<strong><code>POLICY_REJECT_ON_DATA</code></strong> (up to Android 10):\n(Lineage OS) Reject mobile/cellular data. Signals network unavailable to\nthe configured app as if the mobile data is inactive.<li><p><strong>Reject VPN data</strong> or\n<strong><code>POLICY_REJECT_VPN</code></strong> (Android 11+) or\n<strong><code>POLICY_REJECT_ON_VPN</code></strong> (up to Android 10):\n(Lineage OS) Reject VPN data. Signals network unavailable to the\nconfigured app as if the VPN is inactive.<li><p><strong>Reject Wi-Fi data</strong> or\n<strong><code>POLICY_REJECT_WIFI</code></strong> (Android 11+) or\n<strong><code>POLICY_REJECT_ON_WLAN</code></strong> (up to Android 10):\n(Lineage OS) Reject Wi-Fi data. Signals network unavailable to the\nconfigured app as if the device is not connected to a Wi-Fi\nnetwork.<li><p><strong>Disable network access</strong> or\n<strong><code>POLICY_REJECT_ALL</code></strong> (Android 11+) or\n<strong><code>POLICY_NETWORK_ISOLATED</code></strong> (up to Android\n10): (Lineage OS) Reject network access in all circumstances. This is\nnot the same as enforcing the other three policies above, and is the\nrecommended policy for dodgy apps. If this policy is enforced, there is\nno need to enforce the other policies.<li><p><strong><code>POLICY_ALLOW_METERED_IN_ROAMING</code></strong>:\n(Samsung) Possibly allow metered network use during roaming. Exact\nmeaning is currently unknown.<li><p><strong><code>POLICY_ALLOW_WHITELIST_IN_ROAMING</code></strong>:\n(Samsung) Possibly allow network use during roaming. Exact meaning is\ncurrently unknown.<li><p><strong>Reject data on metered networks</strong> or\n<strong><code>POLICY_REJECT_METERED</code></strong>: (Motorola) Reject\nnetwork usage if it is a metered network.<li><p><strong>Reject background data</strong> or\n<strong><code>POLICY_REJECT_BACKGROUND</code></strong>: (Motorola)\nReject network usage in the background.<li><p><strong>Disable network access</strong> or\n<strong><code>POLICY_REJECT_ALL</code></strong>: (Motorola) Reject\nnetwork access altogether. Like Lineage OS, it blocks internet\nconnections via iptables. But whether it signals the unavailability of\nnetwork to the configured app is not known.</ol><div class=\"amalert tip\"><p><strong><em>Note.</em></strong><p>Corresponding Lineage OS patches are as follows:<ol class=incremental><li><p><a href=https://github.com/LineageOS/android_frameworks_base/commit/a04932bafbbf7d99efd18276152cc2c9c9b2073e>fw/b:\nSquash of app fw restriction commits</a><li><p><a href=https://github.com/LineageOS/android_frameworks_base/commit/02c8c82854348f52afe2199f310f44b5f578b5b8>fw/b:\nAdd support for per app network isolation</a></ol></div></section></section><section id=ch:faq class=level1 data-number=4><h1 data-number=4><span class=header-section-number>4</span> <a href=#toc:ch:faq>Frequently Asked Questions</a><a href=#ch:faq class=anchor aria-hidden=true></a></h1><section id=sec:faq:app-components class=level2 data-number=4.1><h2 data-number=4.1><span class=header-section-number>4.1</span> <a href=#toc:sec:faq:app-components>App Components</a><a href=#sec:faq:app-components class=anchor aria-hidden=true></a></h2><section id=subsec:faq:what-are-app-components class=level3 data-number=4.1.1><h3 data-number=4.1.1><span class=header-section-number>4.1.1</span>\n<a href=#toc:subsec:faq:what-are-app-components>What are the\napplication components?</a><a href=#subsec:faq:what-are-app-components class=anchor aria-hidden=true></a></h3><p>Activities, services, broadcast receivers (or only receivers) and\ncontent providers (or only providers) are jointly called application\ncomponents. More technically, they all inherit the <a href=https://developer.android.com/reference/android/content/pm/ComponentInfo>ComponentInfo</a>\nclass and can be launched via Intent.</section><section id=subsec:faq:how-components-blocked class=level3 data-number=4.1.2><h3 data-number=4.1.2><span class=header-section-number>4.1.2</span>\n<a href=#toc:subsec:faq:how-components-blocked>How are the tracker and\nother components blocked in App Manager? What are its limitations?</a><a href=#subsec:faq:how-components-blocked class=anchor aria-hidden=true></a></h3><p>App Manager typically blocks application components (or tracker\ncomponents) using a method called <a href=https://carteryagemann.com/pages/android-intent-firewall.html>Intent\nFirewall (IFW)</a>, it is superior to other methods such as <em>pm</em>\n(PackageManager), <a href=https://github.com/RikkaApps/Shizuku>Shizuku</a> or any other\nmethod that uses the package manager to enable or disable the\ncomponents. If a component is disabled by the latter methods, the\napplication itself can detect that the component is being blocked and\ncan re-enable it as it has full access to its own components. (Many\ndeceptive applications actually do this in order to keep the tracker\ncomponents unblocked.) On the other hand, IFW is a true firewall and the\napplication cannot detect if its components are being blocked. App\nManager uses the term <em>block</em> rather than <em>disable</em> for\nthis reason.<p>Even IFW has some limitations which are primarily applicable for the\nsystem applications:<ul class=incremental><li><p>The application in question is whitelisted by the system i.e. the\nsystem cannot function properly without these applications and may cause\nrandom crashes. These applications include but not limited to Android\nSystem, System UI, Phone Services. They will continue to work even if\nthey are disabled or blocked.<li><p>Another system application or system process has activated a\nspecific component of the application in question via interprocess\ncommunication (IPC). In this case, the component will be activated\nregardless of blocking status or even if the entire application is\ndisabled. If there is such a system application that is not needed, the\nonly way to prevent it from running is by getting rid of it.</ul></section><section id=subsec:faq:components-blocked-by-others class=level3 data-number=4.1.3><h3 data-number=4.1.3><span class=header-section-number>4.1.3</span>\n<a href=#toc:subsec:faq:components-blocked-by-others>Does app\ncomponents blocked by other tools retained in App Manager?</a><a href=#subsec:faq:components-blocked-by-others class=anchor aria-hidden=true></a></h3><p><strong>No.</strong> But the application components blocked by the\nsystem or any other tools are displayed in the <a href=#subsec:component-tabs>component tabs</a>. These rules can be\nimported from <a href=#par:import-existing-rules>Settings</a>.\nHowever, it is not possible for App Manager to distinguish the\ncomponents blocked by the third-party tools and components blocked by\nthe system. Therefore, the applications listed in the import page should\nbe selected with care.</section><section id=subsec:faq:components-reblocked-in-am class=level3 data-number=4.1.4><h3 data-number=4.1.4><span class=header-section-number>4.1.4</span>\n<a href=#toc:subsec:faq:components-reblocked-in-am>Điều gì xảy ra với\ncác thành phần bị chặn bởi App Manager mà trước đây đã bị các công cụ\nkhác chặn?</a><a href=#subsec:faq:components-reblocked-in-am class=anchor aria-hidden=true></a></h3><p><em>App Manager blocks the components again</em> if requested. In\ncase of unblocking, they will be reverted to the default state as\nspecified in the manifest of the application. But if the components were\nblocked by <a href=https://www.myandroidtools.com>MyAndroidTools\n(MAT)</a> with IFW method, they will not be unblocked by App Manager as\nit uses a different format. To fix this issue, the rules have to be\nimported from <a href=#par:import-existing-rules>Settings</a> at\nfirst, in which case MAT’s configurations will be permanently\nremoved.</section><section id=subsec:faq:what-is-instant-component-blocking class=level3 data-number=4.1.5><h3 data-number=4.1.5><span class=header-section-number>4.1.5</span>\n<a href=#toc:subsec:faq:what-is-instant-component-blocking>What is\ninstant component blocking?</a><a href=#subsec:faq:what-is-instant-component-blocking class=anchor aria-hidden=true></a></h3><p>When you block a component in the <a href=#sec:app-details-page>App\nDetails page</a>, the blocking is not applied by default. It is only\napplied when you apply blocking using the <em>Apply rules</em> option in\nthe top-right menu. If you enable <a href=#subsubsec:instant-component-blocking>instant component\nblocking</a>, blocking will be applied as soon as you block a component.\nIf you choose to block tracker components, however, blocking is applied\nautomatically regardless of this setting. You can also remove blocking\nfor an application by simply clicking on <em>Remove rules</em> in the\nsame menu in the <strong>App Details page</strong>. Since the default\nbehaviour gives you more control over applications, it is better to keep\n<em>instant component blocking</em> option disabled.</section><section id=subsec:tracker-classes-versus-tracker-components class=level3 data-number=4.1.6><h3 data-number=4.1.6><span class=header-section-number>4.1.6</span>\n<a href=#toc:subsec:tracker-classes-versus-tracker-components>Các lớp\ntheo dõi so với các thành phần theo dõi</a><a href=#subsec:tracker-classes-versus-tracker-components class=anchor aria-hidden=true></a></h3><p>All application components are classes but not all classes are\ncomponents. In fact, only a few of the classes are components. That\nbeing said, <a href=#sec:scanner-page>scanner page</a> displays a list\nof trackers along with the number of classes, not just the components.\nIn all other pages, trackers and tracker components are used\nsynonymously to denote tracker components, i.e. blocking tracker means\nblocking tracker components, not tracker classes.<div class=\"amalert tip\"><p><strong><em>Info.</em></strong><p>Tracker classes that are not components cannot be blocked. They can\nonly be removed by editing the application itself.</div></section></section><section id=sec:faq:adb-over-tcp class=level2 data-number=4.2><h2 data-number=4.2><span class=header-section-number>4.2</span> <a href=#toc:sec:faq:adb-over-tcp>ADB over TCP</a><a href=#sec:faq:adb-over-tcp class=anchor aria-hidden=true></a></h2><section id=subsec:faq:enable-adb-on-every-restart class=level3 data-number=4.2.1><h3 data-number=4.2.1><span class=header-section-number>4.2.1</span>\n<a href=#toc:subsec:faq:enable-adb-on-every-restart>Do I have to\nenable ADB over TCP everytime I restart?</a><a href=#subsec:faq:enable-adb-on-every-restart class=anchor aria-hidden=true></a></h3><p>Unfortunately, yes. This is because the ADB daemon, the process\nresponsible for ADB connection, is also restarted after a reboot, and it\ndoes not re-enable ADB over TCP.</section><section id=subsec:faq:usb-debugging class=level3 data-number=4.2.2><h3 data-number=4.2.2><span class=header-section-number>4.2.2</span>\n<a href=#toc:subsec:faq:usb-debugging>Cannot enable USB debugging.\nWhat to do?</a><a href=#subsec:faq:usb-debugging class=anchor aria-hidden=true></a></h3><p>See §<a href=#subsec:enable-usb-debugging data-reference-type=ref data-reference=subsec:enable-usb-debugging>3.1.2</a> in Chương <a href=#ch:guides data-reference-type=ref data-reference=ch:guides>3</a>.</section><section id=subsec:faq:block-components-using-adb class=level3 data-number=4.2.3><h3 data-number=4.2.3><span class=header-section-number>4.2.3</span>\n<a href=#toc:subsec:faq:block-components-using-adb>Can I block tracker\nor any other application components using ADB over TCP?</a><a href=#subsec:faq:block-components-using-adb class=anchor aria-hidden=true></a></h3><p>ADB has limited number of <a href=https://github.com/aosp-mirror/platform_frameworks_base/blob/master/packages/Shell/AndroidManifest.xml>permissions</a>\nand controlling application components is not one of them. However, the\ncomponents of a <em>test-only</em> app can be controlled via ADB. If App\nManager detects such an application, it enables the blocking options\nautomatically.</section><section id=subsec:faq:adb-features class=level3 data-number=4.2.4><h3 data-number=4.2.4><span class=header-section-number>4.2.4</span>\n<a href=#toc:subsec:faq:adb-features>Which features can be used in ADB\nmode?</a><a href=#subsec:faq:adb-features class=anchor aria-hidden=true></a></h3><p>Supported features are enabled automatically in the ADB mode.\nSupported features include disabling, force-stopping, clearing\napplication data, granting or revoking app ops and permissions, and so\non. It is also possible to install or uninstall applications without any\nprompt from the system.</section></section><section id=sec:faq:miscellanea class=level2 data-number=4.3><h2 data-number=4.3><span class=header-section-number>4.3</span> <a href=#toc:sec:faq:miscellanea>Miscellanea</a><a href=#sec:faq:miscellanea class=anchor aria-hidden=true></a></h2><section id=subsec:faq:no-root-no-harms class=level3 data-number=4.3.1><h3 data-number=4.3.1><span class=header-section-number>4.3.1</span>\n<a href=#toc:subsec:faq:no-root-no-harms>I don’t use root/ADB. Am I\ncompletely safe from any harms?</a><a href=#subsec:faq:no-root-no-harms class=anchor aria-hidden=true></a></h3><p>Yes. AM cannot modify any system settings without root or ADB.</section><section id=subsec:faq:how-trackers-libs-updated class=level3 data-number=4.3.2><h3 data-number=4.3.2><span class=header-section-number>4.3.2</span>\n<a href=#toc:subsec:faq:how-trackers-libs-updated>How are the trackers\nand libraries are updated?</a><a href=#subsec:faq:how-trackers-libs-updated class=anchor aria-hidden=true></a></h3><p>Trackers and libraries are updated manually before making a new\nrelease.</section><section id=subsec:faq:apks-deleted-after-installed class=level3 data-number=4.3.3><h3 data-number=4.3.3><span class=header-section-number>4.3.3</span>\n<a href=#toc:subsec:faq:apks-deleted-after-installed>Are APKs deleted\nafter installed?</a><a href=#subsec:faq:apks-deleted-after-installed class=anchor aria-hidden=true></a></h3><p>No, APKs aren’t deleted by App Manager after they are installed.</section><section id=subsec:faq:shizuku-support class=level3 data-number=4.3.4><h3 data-number=4.3.4><span class=header-section-number>4.3.4</span>\n<a href=#toc:subsec:faq:shizuku-support>Any plans for Shizuku?</a><a href=#subsec:faq:shizuku-support class=anchor aria-hidden=true></a></h3><p>App Manager’s use of hidden API and privileged code execution is now\nmuch more complex and cannot be integrated with other third party apps\nsuch as <a href=https://shizuku.rikka.app>Shizuku</a>. Here are some\nreasons for not considering Shizuku (which now has Apache 2.0 license)\nfor App Manager:<ol class=incremental><li><p>Shizuku was initially non-free which led me to use a similar\napproach for App Manager to support both root and ADB<li><p>App Manager already supports both ADB and root which in some\ncases is more capable than Shizuku<li><p>Relying on a third-party app for the major functionalities is not\na good design choice<li><p>Integration of Shizuku will increase the complexity of App\nManager.</ol></section><section id=subsec:faq:what-are-bloatware class=level3 data-number=4.3.5><h3 data-number=4.3.5><span class=header-section-number>4.3.5</span>\n<a href=#toc:subsec:faq:what-are-bloatware>What are bloatware and how\nto remove them?</a><a href=#subsec:faq:what-are-bloatware class=anchor aria-hidden=true></a></h3><p>Bloatware are the unnecessary pre-installed apps, usually system\napps. Some of the apps are often used to track users and collect user\ndata which they might sell for profits. Many system apps do not need to\nrequest any permission to access device info, contacts and messaging\ndata, and other usage info, such as your phone usage habits and\neverything you store on your shared storage(s).<p>The bloatware may also include Google apps, Meta apps, and Twitter/X\nwhich can also track users and/or collect user data without consent. You\ncan disable a few permissions from Android settings but be aware that\nAndroid settings hides many permissions a security researcher would call\npotentially <em>dangerous</em> (e.g., internet, sensor).<p>Were the bloatware user apps, they could be easily uninstalled either\nfrom Android settings or AM. Uninstalling system apps is not possible\nwithout privileged permission, but even then, it cannot <em>remove</em>\nthe system apps completely as they are located in the <em>system</em>\npartition which is a read-only partition. If you have root, you can\nremount this partition to manually <em>purge</em> these apps but this\nwill break Over the Air (OTA) updates since data in the system partition\nhas been modified. There are two kind of updates, delta (small-size,\nconsisting of only the changes between two versions) and full updates.\nYou may still be able to apply full updates, but the bloatware will be\ninstalled again, and consequently, you have to delete them all over\nagain.<p>Another solution is to disable these apps either from Android\nsettings or AM, but certain services can still run in the background as\nthey can be started by other system apps using Inter-process\nCommunication (IPC). One possible solution is to disable all bloatware\nuntil the service has finally stopped (after a restart). However, due to\nheavy modifications of the Android frameworks by the vendors, removing\nor disabling certain bloatware may cause the System UI to crash or even\ncause bootloop. From v4.0.0, AM has a new feature called\n<strong>Debloater</strong> which can be used as a starting point to\nmonitor, disable, and remove the bloatware from a proprietary Android\noperating system.<div class=\"amalert warning\"><p><strong><em>Note.</em></strong><p>In most cases, you cannot completely debloat your device. Therefore,\nit is recommended that you use a custom ROM free from bloatware, such as\nGraphene OS, Lineage OS or their derivatives.</div></section></section></section><section id=ch:specifications class=level1 data-number=5><h1 data-number=5><span class=header-section-number>5</span> <a href=#toc:ch:specifications>Specifications</a><a href=#ch:specifications class=anchor aria-hidden=true></a></h1><section id=sec:rules-specification class=level2 data-number=5.1><h2 data-number=5.1><span class=header-section-number>5.1</span> <a href=#toc:sec:rules-specification>Rules Specification</a><a href=#sec:rules-specification class=anchor aria-hidden=true></a></h2><section id=background class=level3 data-number=5.1.1><h3 data-number=5.1.1><span class=header-section-number>5.1.1</span>\n<a href=#toc:background>Background</a><a href=#background class=anchor aria-hidden=true></a></h3><p>AM currently supports blocking activities, broadcast receivers,\ncontent providers, services, app ops and permissions, and in future I\nmay add more blocking options. In order to add more portability, it is\nnecessary to import/export all these data.<p>Maintaining a database should be the best choice when it comes to\nstoring data. For now, several <code>tsv</code> files with each file\nhaving the name of the package and a <code>.tsv</code> extension. The\nfile/database will be queried/processed by the\n<code>RulesStorageManager</code> class. Due to this abstraction, it\nshould be easier to switch to database or encrypted database systems in\nfuture without changing the design of the entire project. Currently, All\nconfiguration files are stored at\n<code>/data/data/io.github.muntashirakon.AppManager/Files/conf</code>.</section><section id=rules-file-format class=level3 data-number=5.1.2><h3 data-number=5.1.2><span class=header-section-number>5.1.2</span>\n<a href=#toc:rules-file-format>Rules File Format</a><a href=#rules-file-format class=anchor aria-hidden=true></a></h3><section id=internal class=level4 data-number=5.1.2.1><h4 data-number=5.1.2.1><span class=header-section-number>5.1.2.1</span> Internal<a href=#internal class=anchor aria-hidden=true></a></h4><p>The format below is used internally within App Manager and is <em>not\ncompatible with the external format.</em><pre><code>    &lt;name&gt; &lt;type&gt; &lt;mode&gt;|&lt;component_status&gt;|&lt;is_granted&gt;</code></pre><p>Here:<ul class=incremental><li><p><code>&lt;name></code> – Component/permission/app op name (in\ncase of app op, it could be string or integer)<li><p><code>&lt;type></code> – One of the <code>ACTIVITY</code>,\n<code>RECEIVER</code>, <code>PROVIDER</code>, <code>SERVICE</code>,\n<code>APP_OP</code>, <code>PERMISSION</code><li><p><code>&lt;mode></code> – (For app ops) The associated <a href=#subsec:mode-constants>mode constant</a><li><p><code>&lt;component_status></code> – (For components)\nComponent status<ul class=incremental><li><p><code>true</code> – Component has been applied (<code>true</code>\nvalue is kept for compatibility)<li><p><code>false</code> – Component hasn’t been applied yet, but will\nbe applied in future (<code>false</code> value is kept for\ncompatibility)<li><p><code>unblocked</code> – Component is scheduled to be\nunblocked</ul><li><p><code>&lt;is_granted></code> – (For permissions) Whether the\npermission is granted or revoked</ul></section><section id=external class=level4 data-number=5.1.2.2><h4 data-number=5.1.2.2><span class=header-section-number>5.1.2.2</span> External<a href=#external class=anchor aria-hidden=true></a></h4><p>External format is used for importing or exporting rules in App\nManager.<pre><code>    &lt;package_name&gt; &lt;component_name&gt; &lt;type&gt; &lt;mode&gt;|&lt;component_status&gt;|&lt;is_granted&gt;</code></pre><p>This the format is essentially the same as above except for the first\nitem which is the name of the package.<div class=\"amalert danger\"><p><strong><em>Caution.</em></strong><p>The exported rules have a different format than the internal one and\nshould not be copied directly to the <strong>conf</strong> folder.</div></section></section></section></section><section id=ch:changelogs class=level1 data-number=6><h1 data-number=6><span class=header-section-number>6</span> <a href=#toc:ch:changelogs>Nhật ký thay đổi</a><a href=#ch:changelogs class=anchor aria-hidden=true></a></h1><section id=sec:v4.0.5-(445) class=level2 data-number=6.1><h2 data-number=6.1><span class=header-section-number>6.1</span> <a href=#toc:sec:v4.0.5-(445)>v4.0.5 (445)</a><a href=#sec:v4.0.5-(445) class=anchor aria-hidden=true></a></h2><ul class=incremental><li><p>Added option to allow installing the existing applications in the\ninstaller page<li><p>Display unsafe bloatware info<li><p>Display vector icon on the splash screen in Android 7.1 and\nearlier<li><p>Enabled “Clear data from uninstalled apps” to no-root users in\n1-click ops page<li><p>Enabled predictive back in Android 14 onwards<li><p>Improved accessibility by updating the content description of the\naction items<li><p>In app info tab, open “Open by default” setting in the “Open\nlinks” dialog<li><p>In debloater page, sort by app label (or app name) rather than\npackage name<li><p>Fixed freezing an app with “Remember for this app” turned\non<li><p>Fixed selecting texts in the list items due to framework\nbugs<li><p>Fixed setting app ops in custom ROMs with MIUI properties\ninjected<li><p>Fixed updating profile modification status when an application is\ndeleted from the list<li><p>Handled common colors and cursor movements in terminal\noutput.</ul></section><section id=sec:v4.0.4-(444) class=level2 data-number=6.2><h2 data-number=6.2><span class=header-section-number>6.2</span> <a href=#toc:sec:v4.0.4-(444)>v4.0.4 (444)</a><a href=#sec:v4.0.4-(444) class=anchor aria-hidden=true></a></h2><ul class=incremental><li><p>Optimized searching and filtering in the main page<li><p>Adopted sentence-case for the titles<li><p>Use the configured state to execute a profile for the simple\nshortcuts<li><p>Prevented crashing while searching throughout the\napplication<li><p>Fixed integer overflow issue in the tar compression.</ul></section><section id=sec:v4.0.3-(443) class=level2 data-number=6.3><h2 data-number=6.3><span class=header-section-number>6.3</span> <a href=#toc:sec:v4.0.3-(443)>v4.0.3 (443)</a><a href=#sec:v4.0.3-(443) class=anchor aria-hidden=true></a></h2><ul class=incremental><li><p>Updated translations<li><p>Improved handling the list items throughout App Manager<li><p>Fixed a regression error in file manager<li><p>Fixed spinners in the App Usage and the System Config\npages.</ul></section><section id=sec:v4.0.2-(442) class=level2 data-number=6.4><h2 data-number=6.4><span class=header-section-number>6.4</span> <a href=#toc:sec:v4.0.2-(442)>v4.0.2 (442)</a><a href=#sec:v4.0.2-(442) class=anchor aria-hidden=true></a></h2><ul class=incremental><li><p>Updated bloatware<li><p>Fixed fetching applications in multi-user environment in no-root\nmode<li><p>Fixed opening <code>app-manager</code> URLs from the web\nbrowsers<li><p>Fixed updating SSAID<li><p>Prevented a crash in Android &lt; 9.0 that occurs due to invalid\napp ops.</ul></section><section id=sec:v4.0.1-(441) class=level2 data-number=6.5><h2 data-number=6.5><span class=header-section-number>6.5</span> <a href=#toc:sec:v4.0.1-(441)>v4.0.1 (441)</a><a href=#sec:v4.0.1-(441) class=anchor aria-hidden=true></a></h2><section id=overlay-management class=level3 data-number=6.5.1><h3 data-number=6.5.1><span class=header-section-number>6.5.1</span>\n<a href=#toc:overlay-management>Overlay management</a><a href=#overlay-management class=anchor aria-hidden=true></a></h3><p>In the App Details page, a new tab “Overlays” is added where per-app\noverlays are displayed. They can also be enabled or disabled using the\ntoggle button. In addition, if the App Details page of an overlay\npackage is opened, a “Overlay” tag will be displayed in the App Info\ntab. Clicking on the tag opens a dialog containing additional info along\nwith a button that allows navigating to the App Details page of the\noverlay target package if it is installed.<section id=known-limitation class=level5 data-number=6.5.1.0.1><h5 data-number=6.5.1.0.1><span class=header-section-number>6.5.1.0.1</span> Known limitation<a href=#known-limitation class=anchor aria-hidden=true></a></h5><p>At present, it only works for root/ADB users in Android 8 (Oreo) and\nlater.</section></section><section id=unfreeze-option-in-activity-shortcuts class=level3 data-number=6.5.2><h3 data-number=6.5.2><span class=header-section-number>6.5.2</span>\n<a href=#toc:unfreeze-option-in-activity-shortcuts>Unfreeze option in\nactivity shortcuts</a><a href=#unfreeze-option-in-activity-shortcuts class=anchor aria-hidden=true></a></h3><p>If the application corresponding to the shortcut being launched is\nfrozen, App Manager will now offer you to unfreeze the app temporarily\nso that the shortcut can be launched. The app will be frozen again once\nthe screen is locked.<section id=known-limitation-1 class=level5 data-number=6.5.2.0.1><h5 data-number=6.5.2.0.1><span class=header-section-number>6.5.2.0.1</span> Known limitation<a href=#known-limitation-1 class=anchor aria-hidden=true></a></h5><p>This may not work on devices without a screen lock or if the screen\nis locked some time after the display goes off.</section></section><section id=market-like-url-support class=level3 data-number=6.5.3><h3 data-number=6.5.3><span class=header-section-number>6.5.3</span>\n<a href=#toc:market-like-url-support><code>market</code>-like URL\nsupport</a><a href=#market-like-url-support class=anchor aria-hidden=true></a></h3><p>Third-party applications can now open the App Details page of any\ninstalled package by invoking an Intent with an URL with the following\nformat:<pre><code>app-manager://details?id=&lt;pkg&gt;&amp;user=&lt;user_id&gt;</code></pre><p>where <code>&lt;pkg></code> stands for package name, and\n<code>&lt;user_id></code> stands for the user ID which is\noptional.</section><section id=updated-color-codes class=level3 data-number=6.5.4><h3 data-number=6.5.4><span class=header-section-number>6.5.4</span>\n<a href=#toc:updated-color-codes>Updated color codes</a><a href=#updated-color-codes class=anchor aria-hidden=true></a></h3><p>In order to improve accessibility, certain color codes have been\nimproved. Visit <a href=app-manager://settings/about/version>Settings\n> About > Version/Changelog</a> for details.</section><section id=others class=level3 data-number=6.5.5><h3 data-number=6.5.5><span class=header-section-number>6.5.5</span>\n<a href=#toc:others>Others</a><a href=#others class=anchor aria-hidden=true></a></h3><ul class=incremental><li><p>Avoided waiting for the remote server to respond when no-root\nmode is set<li><p>Fixed downgrading apps in Android 10 onwards<li><p>Fixed installer issues in the Huawei stock operating\nsystems<li><p>Improved text formatting in the “What’s New” dialog<li><p>In the UI tracker window, fixed clicking on the icon after it is\niconified<li><p>Updated bloatware and suggestions</ul></section></section><section id=sec:v4.0.0-(440) class=level2 data-number=6.6><h2 data-number=6.6><span class=header-section-number>6.6</span> <a href=#toc:sec:v4.0.0-(440)>v4.0.0 (440)</a><a href=#sec:v4.0.0-(440) class=anchor aria-hidden=true></a></h2><p>App Manager v4.0.0 comes with a lot of new features and improvements.\nVisit <a href=app-manager://settings/about/version>Settings > About\n> Version/Changelog</a> for details.<section id=new-logo class=level3 data-number=6.6.1><h3 data-number=6.6.1><span class=header-section-number>6.6.1</span>\n<a href=#toc:new-logo>New logo!</a><a href=#new-logo class=anchor aria-hidden=true></a></h3><p>The new logo is just a cursive “A”. The design is based on the <a href=https://freetengwar.sourceforge.net/>Tengwar Telcontar</a> font\nwhich was created to bring the Tengwar script, originally created by J.\nR. R. Tolkien, to the digital world. The letter has the classic App\nManager color (i.e., #dcaf74) and uses a pure black background instead\nof a shade of grey.</section><section id=android-14-and-15-support class=level3 data-number=6.6.2><h3 data-number=6.6.2><span class=header-section-number>6.6.2</span>\n<a href=#toc:android-14-and-15-support>Android 14 and 15 support</a><a href=#android-14-and-15-support class=anchor aria-hidden=true></a></h3><p>App Manager now targets Android 14 and fully supports Android 15.<section id=known-issue class=level5 data-number=6.6.2.0.1><h5 data-number=6.6.2.0.1><span class=header-section-number>6.6.2.0.1</span> Known issue<a href=#known-issue class=anchor aria-hidden=true></a></h5><p>KeyStore backup/restore is not working in Android 12 and later.</section></section><section id=revamped-debloater class=level3 data-number=6.6.3><h3 data-number=6.6.3><span class=header-section-number>6.6.3</span>\n<a href=#toc:revamped-debloater>Revamped debloater</a><a href=#revamped-debloater class=anchor aria-hidden=true></a></h3><p>Debloating profiles were available as “Presets” in the Profiles page\nwhich has now been replaced with the Debloater page and can be accessed\nfrom the three-dots menu in the Main page. <a href=https://github.com/MuntashirAkon/android-debloat-list>ADL</a> is\na new project that focuses on maintaining a list of bloatware as well as\npotential open source alternatives. Contributions are welcome!</section><section id=introducing-file-manager class=level3 data-number=6.6.4><h3 data-number=6.6.4><span class=header-section-number>6.6.4</span>\n<a href=#toc:introducing-file-manager>Introducing file manager</a><a href=#introducing-file-manager class=anchor aria-hidden=true></a></h3><p>App Manager offers an (almost) fully-featured file manager with basic\nfile operations, such as copy, cut, rename, and delete along with the\nbatch operations. It also offers an extensive “Open with…” dialog to\nopen a file with another app, and a comprehensive file properties\nviewer. Folders can also be added to the list of favorites for quick\naccess. And many more.</section><section id=integrated-code-editor class=level3 data-number=6.6.5><h3 data-number=6.6.5><span class=header-section-number>6.6.5</span>\n<a href=#toc:integrated-code-editor>Integrated code editor</a><a href=#integrated-code-editor class=anchor aria-hidden=true></a></h3><p>Manifest and code viewers have been replaced with this new editor.\nAmong other regular features, it includes proper syntax highlighting and\nadvanced searching options. In addition, files from third-party apps can\nalso be opened for editing.</section><section id=history-of-operations class=level3 data-number=6.6.6><h3 data-number=6.6.6><span class=header-section-number>6.6.6</span>\n<a href=#toc:history-of-operations>History of operations</a><a href=#history-of-operations class=anchor aria-hidden=true></a></h3><p>All 1-click operations, batch operations, and profile invocations are\nnow stored as history. The history items can also be executed from the\nHistory page. To ensure consistency, the profile state, configurations,\npackage list are also stored, and this stored version is executed\ninstead of the actual profile. As a result, this works even if the\nprofile is deleted.</section><section id=per-app-freezing-and-more class=level3 data-number=6.6.7><h3 data-number=6.6.7><span class=header-section-number>6.6.7</span>\n<a href=#toc:per-app-freezing-and-more>Per-app freezing, and\nmore</a><a href=#per-app-freezing-and-more class=anchor aria-hidden=true></a></h3><p>Freeze/unfreeze feature now supports setting per-app freezing method\nwhich is beneficial in certain scenarios, such as when a user want to\nsuspend some apps while using the disable method as the default. In\naddition, an “Advanced suspend” option is added which force-stops an\napplication before suspending it, thus, prevent it’s services from\nrunning in the background.</section><section id=log-viewer-enhancements class=level3 data-number=6.6.8><h3 data-number=6.6.8><span class=header-section-number>6.6.8</span>\n<a href=#toc:log-viewer-enhancements>Log viewer enhancements</a><a href=#log-viewer-enhancements class=anchor aria-hidden=true></a></h3><p>Log viewer now supports enhanced searching and filtering options,\nsuch as keyword- and regular expression-based searching and filtering.\nPlease read the in-app changelog for details. Support for batch\noperations has also been added.</section><section id=launching-non-exported-activities class=level3 data-number=6.6.9><h3 data-number=6.6.9><span class=header-section-number>6.6.9</span>\n<a href=#toc:launching-non-exported-activities>Launching non-exported\nactivities</a><a href=#launching-non-exported-activities class=anchor aria-hidden=true></a></h3><p>App Manager now supports launching non-exported activities in no-root\nand ADB mode. However, in no-root mode,\n<code>android.permission.WRITE_SECURE_SETTINGS</code> permission is\nrequired.</section><section id=new-tags-in-app-info-tab class=level3 data-number=6.6.10><h3 data-number=6.6.10><span class=header-section-number>6.6.10</span> <a href=#toc:new-tags-in-app-info-tab>New tags in App Info tab</a><a href=#new-tags-in-app-info-tab class=anchor aria-hidden=true></a></h3><p>Five new tags are added in the App Info tab. They are: bloatware,\nXposed, sensors disabled, open links, and static shared libs. Clicking\non “bloatware” will display more information regarding the bloatware and\nsuggest alternatives, “Xposed” tag will display dependency information,\n“open links” will display a list of links supported by the application,\nand “static shared libs” will display all version of the application\ninstalled in the system along with an option to uninstall them. The\nlatter is useful for applications, such as Trichrome.<section id=known-issue-1 class=level5 data-number=6.6.10.0.1><h5 data-number=6.6.10.0.1><span class=header-section-number>6.6.10.0.1</span> Known issue<a href=#known-issue-1 class=anchor aria-hidden=true></a></h5><p>“Sensors disabled” only works real-time. That means if the\napplication is not currently active, this tag will always display even\nthough the applications may use sensors while it is running. This is a\nframework limitation and nothing can be done to avoid it\neffectively.</section></section><section id=per-session-installer-options class=level3 data-number=6.6.11><h3 data-number=6.6.11><span class=header-section-number>6.6.11</span> <a href=#toc:per-session-installer-options>Per-session installer\noptions</a><a href=#per-session-installer-options class=anchor aria-hidden=true></a></h3><p>It is not possible to modify installer options during the\ninstallation by clicking on the “settings” button in the installation\ndialog. The installer options will be applied to all the applications\ninstalled in the same session (i.e., the installer queue).</section><section id=advanced-mode-of-operations-adb-enhancements class=level3 data-number=6.6.12><h3 data-number=6.6.12><span class=header-section-number>6.6.12</span> <a href=#toc:advanced-mode-of-operations-adb-enhancements>Advanced mode\nof operations, ADB enhancements, …</a><a href=#advanced-mode-of-operations-adb-enhancements class=anchor aria-hidden=true></a></h3><p>App Manager now supports running its remote server (which is used as\na proxy for running privileged operations) as any supported user (UID).\nThis includes root (0), system (1000), and shell/ADB (2000) through the\ncustom commands. This is also useful for Fire TVs which have disabled\nconnecting to ADB from localhost through socket connection. In addition,\nADB pairing is now done using notifications rather than split screen.\nADB connection speed can also be improved by choosing to run App Manager\nin the background which can be configured in the settings.</section><section id=data-usage-widget-and-more class=level3 data-number=6.6.13><h3 data-number=6.6.13><span class=header-section-number>6.6.13</span> <a href=#toc:data-usage-widget-and-more>Data usage widget, and more</a><a href=#data-usage-widget-and-more class=anchor aria-hidden=true></a></h3><p>Data usage widget display the total data usage for the day, similar\nto the screen time widget which displays the total screen time for the\nday. In addition, existing widgets have been improved.</section><section id=others-1 class=level3 data-number=6.6.14><h3 data-number=6.6.14><span class=header-section-number>6.6.14</span> <a href=#toc:others-1>Others</a><a href=#others-1 class=anchor aria-hidden=true></a></h3><ul class=incremental><li><p>Replaced log viewer, sys config, Terminal, etc. with Labs\npage<li><p>Added an option to disable sensors for each app in the App Info\ntab<li><p>Added an option to perform runtime optimization of applications\nin the 1-click Ops page and in the App Info tab<li><p>Added support for Zstandard compression for\nbackup/restore<li><p>Enabling APK signing now automatically enables zip align\nfeature<li><p>Support exporting application list as CSV or JSON in the batch\noperations<li><p>Added pure black theme support<li><p>Display current activity name (when possible) in the UI Tracker\nwindow<li><p>Added an option to filter apps by user in the Main page<li><p>Display a link to Pithus report in the scanner page if\navailable.</ul></section></section><section id=sec:v3.1.0-(423) class=level2 data-number=6.7><h2 data-number=6.7><span class=header-section-number>6.7</span> <a href=#toc:sec:v3.1.0-(423)>v3.1.0 (423)</a><a href=#sec:v3.1.0-(423) class=anchor aria-hidden=true></a></h2><p>App Manager v3.1.0 comes with a few new features and a lot of\nimprovements. Visit <a href=app-manager://settings/about/version>Settings > About >\nVersion/Changelog</a> for details.<section id=android-13-support class=level3 data-number=6.7.1><h3 data-number=6.7.1><span class=header-section-number>6.7.1</span>\n<a href=#toc:android-13-support>Android 13 support</a><a href=#android-13-support class=anchor aria-hidden=true></a></h3><p>App Manager now targets Android 13 which means most issues in Android\n12 and 13 has been addressed, including SSAID and SAF issues as well as\nmonochrome icons and other theming issues.<section id=known-issue-2 class=level5 data-number=6.7.1.0.1><h5 data-number=6.7.1.0.1><span class=header-section-number>6.7.1.0.1</span> Known issue<a href=#known-issue-2 class=anchor aria-hidden=true></a></h5><p>KeyStore backup/restore not working in Android 12 and later.</section></section><section id=introducing-freezeunfreeze class=level3 data-number=6.7.2><h3 data-number=6.7.2><span class=header-section-number>6.7.2</span>\n<a href=#toc:introducing-freezeunfreeze>Introducing\nfreeze/unfreeze</a><a href=#introducing-freezeunfreeze class=anchor aria-hidden=true></a></h3><p>Enable/disable is replaced with freeze/unfreeze to allow greater\ncontrol on the behaviours of an app. It supports suspend, disable and\nhide functionalities which can be controlled at <a href=app-manager://settings/rules_prefs/freeze_type>Settings >\nRules > Default freezing method</a>. In order to make it easy to\nfreeze or unfreeze an app, shortcuts can also be created from the App\nInfo tab by long clicking on the freeze or unfreeze button.</section><section id=export-app-list class=level3 data-number=6.7.3><h3 data-number=6.7.3><span class=header-section-number>6.7.3</span>\n<a href=#toc:export-app-list>Export app list</a><a href=#export-app-list class=anchor aria-hidden=true></a></h3><p>In the Main page, it is now possible to export the list of apps in\neither XML or Markdown format using batch operations. In the future, the\nXML file may also be imported to App Manager.</section><section id=elliptic-curve-crypography-ecc class=level3 data-number=6.7.4><h3 data-number=6.7.4><span class=header-section-number>6.7.4</span>\n<a href=#toc:elliptic-curve-crypography-ecc>Elliptic Curve Crypography\n(ECC)</a><a href=#elliptic-curve-crypography-ecc class=anchor aria-hidden=true></a></h3><p>App Manager now fully supports encrypting backups using ECC in\naddition to offering AES, RSA and OpenPGP.</section><section id=new-languages class=level3 data-number=6.7.5><h3 data-number=6.7.5><span class=header-section-number>6.7.5</span>\n<a href=#toc:new-languages>New languages</a><a href=#new-languages class=anchor aria-hidden=true></a></h3><p>Two new languages are added: Korean and Romanian.</section><section id=more-list-options class=level3 data-number=6.7.6><h3 data-number=6.7.6><span class=header-section-number>6.7.6</span>\n<a href=#toc:more-list-options>More list options</a><a href=#more-list-options class=anchor aria-hidden=true></a></h3><p>In the main page, more sorting and filtering options are added.\nSorting options include sorting the apps by total size, total data\nusage, launch count, screen time and last usage time. Filtering options\ninclude filtering the apps having at least one item in the Android\nKeyStore, filtering apps with URIs granted via SAF, and filtering apps\nwith SSAID.</section><section id=improved-handling-of-mode-of-operation class=level3 data-number=6.7.7><h3 data-number=6.7.7><span class=header-section-number>6.7.7</span>\n<a href=#toc:improved-handling-of-mode-of-operation>Improved handling\nof mode of operation</a><a href=#improved-handling-of-mode-of-operation class=anchor aria-hidden=true></a></h3><p>Fixed various issues with ADB pairing, handled incomplete USB\ndebugging. Some rooting methods cannot allow interprocess communication\nvia Binder. In those cases, ADB mode is used as a fallback method by\nenabling it automatically if possible.</section><section id=handling-multiple-users class=level3 data-number=6.7.8><h3 data-number=6.7.8><span class=header-section-number>6.7.8</span>\n<a href=#toc:handling-multiple-users>Handling multiple users</a><a href=#handling-multiple-users class=anchor aria-hidden=true></a></h3><p>When possible, App Manager will be able to display apps from work\nprofile in no-root mode in addition to allowing basic operations such as\nlaunching the app or navigating to the system settings. For backups, it\nis now possible to restore backups for other users, but for work\nprofile, some apps may only work properly after re-enabling the work\nprofile. In the installer page, selecting <em>All users</em> will now\ninstall the app for all users instead of only the current user. Finally,\nin the app info tab, current app can be installed in another profile\nusing the <em>Install for…</em> option available in the three-dots menu.\nThis is analogous to the <code>pm install-existing</code> command,\nthereby, making the installation process a lot faster.</section><section id=explorer-enhancements class=level3 data-number=6.7.9><h3 data-number=6.7.9><span class=header-section-number>6.7.9</span>\n<a href=#toc:explorer-enhancements>Explorer enhancements</a><a href=#explorer-enhancements class=anchor aria-hidden=true></a></h3><p>Explorer can now open DEX and JAR files in addition to APK files.\nSeveral sorting options as well as folder options are also added as the\nlist options.</section><section id=new-tag-wx class=level3 data-number=6.7.10><h3 data-number=6.7.10><span class=header-section-number>6.7.10</span> <a href=#toc:new-tag-wx>New tag: WX</a><a href=#new-tag-wx class=anchor aria-hidden=true></a></h3><p>In app info tab, a new tag called WX is added. It is displayed in\nAndroid 10 and later if the application targets Android 9 or earlier. It\nindicates <a href=https://en.wikipedia.org/wiki/W%5EX>W^X</a>\nviolation which allows the app to execute arbitrary executable files\neither by the modification of executables embedded within the app or by\ndownloading them from the Internet.</section><section id=app-ops-management class=level3 data-number=6.7.11><h3 data-number=6.7.11><span class=header-section-number>6.7.11</span> <a href=#toc:app-ops-management>App ops management</a><a href=#app-ops-management class=anchor aria-hidden=true></a></h3><p>App ops are now managed automatically to avoid various app ops\nrelated crashes in various platforms. This will also lessen the amount\nof crashes in an unsupported operating system.</section><section id=batch-uninstallation class=level3 data-number=6.7.12><h3 data-number=6.7.12><span class=header-section-number>6.7.12</span> <a href=#toc:batch-uninstallation>Batch uninstallation</a><a href=#batch-uninstallation class=anchor aria-hidden=true></a></h3><p>In the Main page, enabled batch uninstallation in no-root mode.</section><section id=running-apps class=level3 data-number=6.7.13><h3 data-number=6.7.13><span class=header-section-number>6.7.13</span> <a href=#toc:running-apps>Running apps</a><a href=#running-apps class=anchor aria-hidden=true></a></h3><p>Enabled advanced searching. Searching now matches not only app labels\nbut also package names.</section><section id=interceptor class=level3 data-number=6.7.14><h3 data-number=6.7.14><span class=header-section-number>6.7.14</span> <a href=#toc:interceptor>Interceptor</a><a href=#interceptor class=anchor aria-hidden=true></a></h3><p>Copy the intercepted Intent as am command which can be run from\neither an ADB shell or a terminal using root with the same\neffectiveness.</section><section id=device-specific-changes class=level3 data-number=6.7.15><h3 data-number=6.7.15><span class=header-section-number>6.7.15</span> <a href=#toc:device-specific-changes>Device-specific changes</a><a href=#device-specific-changes class=anchor aria-hidden=true></a></h3><section id=graphene-os class=level5 data-number=6.7.15.0.1><h5 data-number=6.7.15.0.1><span class=header-section-number>6.7.15.0.1</span> Graphene OS<a href=#graphene-os class=anchor aria-hidden=true></a></h5><p>Explicitly handle the Internet permission which is a runtime\npermission in the OS.</section><section id=miui class=level5 data-number=6.7.15.0.2><h5 data-number=6.7.15.0.2><span class=header-section-number>6.7.15.0.2</span> MIUI<a href=#miui class=anchor aria-hidden=true></a></h5><p>Fixed permission denied issues in the installer due to a framework\nissue introduced in MIUI 12.5.</section><section id=motorola class=level5 data-number=6.7.15.0.3><h5 data-number=6.7.15.0.3><span class=header-section-number>6.7.15.0.3</span> Motorola<a href=#motorola class=anchor aria-hidden=true></a></h5><p>Fixed crashes in the Interceptor page due to a framework issue\nintroduced in Android 11.</section></section><section id=others-2 class=level3 data-number=6.7.16><h3 data-number=6.7.16><span class=header-section-number>6.7.16</span> <a href=#toc:others-2>Others</a><a href=#others-2 class=anchor aria-hidden=true></a></h3><ul class=incremental><li><p>Improved Java-Smali conversion by including all the subclasses\nduring conversion<li><p>Improved scanning performance in the Scanner page<li><p>Improved updating the list of apps in the Main page<li><p>Scan all the available paths to detect systemless-ly installed\nsystem apps<li><p><code>vacuum</code> SQLite database before opening it for viewing\nor editing.</ul></section></section><section id=sec:v3.0.0-(410) class=level2 data-number=6.8><h2 data-number=6.8><span class=header-section-number>6.8</span> <a href=#toc:sec:v3.0.0-(410)>v3.0.0 (410)</a><a href=#sec:v3.0.0-(410) class=anchor aria-hidden=true></a></h2><p>App Manager v3.0.0 comes with a lot of features and improvements. See\n<a href=app-manager://settings/about/version>Settings > About >\nVersion/Changelog</a> to see a more detailed changelog.<section id=material-3-and-more class=level3 data-number=6.8.1><h3 data-number=6.8.1><span class=header-section-number>6.8.1</span>\n<a href=#toc:material-3-and-more>Material 3 and More</a><a href=#material-3-and-more class=anchor aria-hidden=true></a></h3><p>Material 3, somewhat similar to <em>Material You</em>, is a\nsignificant improvement over Material Design 2 with support for dynamic\ncolours in Android 12 and later. In addition, many design changes have\nbeen made in App Manager without any significant changes in the overall\nuser experience.<section id=known-issue-3 class=level5 data-number=6.8.1.0.1><h5 data-number=6.8.1.0.1><span class=header-section-number>6.8.1.0.1</span> Known issue<a href=#known-issue-3 class=anchor aria-hidden=true></a></h5><p>Switches are still based on Material Design 2 which will be fixed in\na future release.</section></section><section id=wireless-debugging class=level3 data-number=6.8.2><h3 data-number=6.8.2><span class=header-section-number>6.8.2</span>\n<a href=#toc:wireless-debugging>Wireless Debugging</a><a href=#wireless-debugging class=anchor aria-hidden=true></a></h3><p>Wireless debugging support has been fully implemented. Head over to\n§<a href=#sec:wireless-debugging data-reference-type=ref data-reference=sec:wireless-debugging>3.2</a> for instructions on how\nto configure wireless debugging.<div class=\"amalert tip\"><p><strong><em>No-root users.</em></strong><p>Due to auto-detection feature, startup time might be large for\nno-root users when the mode of operation is set to <em>auto</em>.\nInstead, no-root users should select <em>no-root</em> instead of\n<em>auto</em>.</div></section><section id=languages class=level3 data-number=6.8.3><h3 data-number=6.8.3><span class=header-section-number>6.8.3</span>\n<a href=#toc:languages>Languages</a><a href=#languages class=anchor aria-hidden=true></a></h3><p>App Manager is fully translated into Indonesian and Italian languages\nand can be enabled in settings. Bengali is removed due to lack of\ntranslators.</section><section id=introducing-app-explorer class=level3 data-number=6.8.4><h3 data-number=6.8.4><span class=header-section-number>6.8.4</span>\n<a href=#toc:introducing-app-explorer>Introducing App Explorer</a><a href=#introducing-app-explorer class=anchor aria-hidden=true></a></h3><p>App Explorer can be used to browse the contents of an application.\nThis includes binary XML files, DEX contents or any other media files.\nDEX contents can only be explored in Android Oreo (Android 8) and later.\nIt’s also possible to convert an <code>.smali</code> file into\n<code>.java</code> for a better understanding of the reversed code. This\nfeature, if not needed, can be disabled in Settings > Enable/disable\nfeatures.</section><section id=import-backups-from-other-applications class=level3 data-number=6.8.5><h3 data-number=6.8.5><span class=header-section-number>6.8.5</span>\n<a href=#toc:import-backups-from-other-applications>Import Backups\nfrom Other Applications</a><a href=#import-backups-from-other-applications class=anchor aria-hidden=true></a></h3><p>It is possible to import backups from discontinued or obsolete\napplications such as Titanium Backup, OAndBackup and Swift Backup\n(version 3.0 to 3.2). Go to Setting > Backup/restore to find this\noption.</section><section id=virustotal class=level3 data-number=6.8.6><h3 data-number=6.8.6><span class=header-section-number>6.8.6</span>\n<a href=#toc:virustotal>VirusTotal</a><a href=#virustotal class=anchor aria-hidden=true></a></h3><p>VirusTotal is a widely used tool to scan files and URLs for viruses.\nIn the scanner page and in the running apps page, an option to scan\nfiles with VirusTotal has been added. But the option is hidden by\ndefault. To enable the option, it is necessary to obtain an API key from\nVirusTotal. Go to Settings > VirusTotal API Key for more\ninformation.<div class=\"amalert warning\"><p><strong><em>Internet feature.</em></strong><p>This is currently the only feature which require an Internet\nconnection. If you wish to use any Internet feature that might also be\nadded in the future, enable <em>Use the Internet</em> in Settings >\nEnable/disable features.</div></section><section id=trigger-profiles-from-the-automation-software class=level3 data-number=6.8.7><h3 data-number=6.8.7><span class=header-section-number>6.8.7</span>\n<a href=#toc:trigger-profiles-from-the-automation-software>Trigger\nProfiles from the Automation Software</a><a href=#trigger-profiles-from-the-automation-software class=anchor aria-hidden=true></a></h3><p>As the implementation of routine operations is being delayed, an\noption to trigger profiles from the external automation software is\nadded. See §<a href=#sec:automating-tasks data-reference-type=ref data-reference=sec:automating-tasks>3.4</a> for instructions on how to\nconfigure profile automation.</section><section id=improved-application-installer class=level3 data-number=6.8.8><h3 data-number=6.8.8><span class=header-section-number>6.8.8</span>\n<a href=#toc:improved-application-installer>Improved Application\nInstaller</a><a href=#improved-application-installer class=anchor aria-hidden=true></a></h3><p>Application installer includes several improvements including the\nability to downgrade applications in no-root mode, installing multiple\napplications at once and blocking trackers after installation. In\nAndroid 12 and later, no-root users can update applications without any\nuser interactions.</section><section id=component-blocking class=level3 data-number=6.8.9><h3 data-number=6.8.9><span class=header-section-number>6.8.9</span>\n<a href=#toc:component-blocking>Component Blocking</a><a href=#component-blocking class=anchor aria-hidden=true></a></h3><p>It is now possible to configure how App Manager should block a\ncomponent. Visit Settings > Rules > Default blocking method for\nmore information. In the components tab, long clicking the block/unblock\nbutton opens a context menu which allows per-component blocking in a\nsimilar manner. ADB users can also block the components of a <em>Test\nonly</em> app.</section><section id=advanced-searching class=level3 data-number=6.8.10><h3 data-number=6.8.10><span class=header-section-number>6.8.10</span> <a href=#toc:advanced-searching>Advanced Searching</a><a href=#advanced-searching class=anchor aria-hidden=true></a></h3><p>In some pages, the search bar supports additional searching which\nincludes searching via prefix, suffix or even regular expressions. In\nthe main page, it is also possible to search for applications using the\nfirst letters of each word, e.g. <em>App Manager</em> can be listed by\nsearching for <em>am</em>.</section><section id=shared-libraries class=level3 data-number=6.8.11><h3 data-number=6.8.11><span class=header-section-number>6.8.11</span> <a href=#toc:shared-libraries>Shared Libraries</a><a href=#shared-libraries class=anchor aria-hidden=true></a></h3><p>Shared libraries tab has received a significant improvements. It can\ndisplay three types of libraries, such as native, jar and APK files.</section><section id=make-the-best-use-of-interceptor class=level3 data-number=6.8.12><h3 data-number=6.8.12><span class=header-section-number>6.8.12</span> <a href=#toc:make-the-best-use-of-interceptor>Make the Best Use of\nInterceptor</a><a href=#make-the-best-use-of-interceptor class=anchor aria-hidden=true></a></h3><p>Activity interceptor can be opened directly from the activities tab\nby long clicking on the launch button, and similarly, activities can be\nlaunched from the activity interceptor page with or without root, for\nany users.<div class=\"amalert tip\"><p><strong><em>Notice.</em></strong><p>Currently, activities opened via root cannot send the results back to\nthe original applications.</div></section><section id=widget-screen-time class=level3 data-number=6.8.13><h3 data-number=6.8.13><span class=header-section-number>6.8.13</span> <a href=#toc:widget-screen-time>Widget: Screen Time</a><a href=#widget-screen-time class=anchor aria-hidden=true></a></h3><p>Screen time widget is quite similar to Digital Wellbeing’s widget by\nthe same name. It displays the total screen time for the day along with\nthe top three apps from all users.</section><section id=widget-clear-cache class=level3 data-number=6.8.14><h3 data-number=6.8.14><span class=header-section-number>6.8.14</span> <a href=#toc:widget-clear-cache>Widget: Clear Cache</a><a href=#widget-clear-cache class=anchor aria-hidden=true></a></h3><p>Clear cache widget can be to clear cache from all the applications\ndirectly from the home screen.</section></section><section id=sec:v2.6.0-(385) class=level2 data-number=6.9><h2 data-number=6.9><span class=header-section-number>6.9</span> <a href=#toc:sec:v2.6.0-(385)>v2.6.0 (385)</a><a href=#sec:v2.6.0-(385) class=anchor aria-hidden=true></a></h2><section id=introducing-backups class=level3 data-number=6.9.1><h3 data-number=6.9.1><span class=header-section-number>6.9.1</span>\n<a href=#toc:introducing-backups>Introducing Backups</a><a href=#introducing-backups class=anchor aria-hidden=true></a></h3><p>Back up/restore feature is now finally out of beta! Read <a href=#sec:backup-restore>the corresponding guide</a> to understand how\nit works.</section><section id=introducing-log-viewer class=level3 data-number=6.9.2><h3 data-number=6.9.2><span class=header-section-number>6.9.2</span>\n<a href=#toc:introducing-log-viewer>Introducing Log Viewer</a><a href=#introducing-log-viewer class=anchor aria-hidden=true></a></h3><p><a href=#subsubsec:log-viewer>Log viewer</a> is essentially a\nfront-end for <code>logcat</code>. It can be used to filter logs by\n<em>tag</em> or <em>pid</em> (process ID), or even by custom filters.\nLog levels AKA verbosity can also be configured. You can also save,\nshare and manage logs.</section><section id=lock-app-manager class=level3 data-number=6.9.3><h3 data-number=6.9.3><span class=header-section-number>6.9.3</span>\n<a href=#toc:lock-app-manager>Lock App Manager</a><a href=#lock-app-manager class=anchor aria-hidden=true></a></h3><p><a href=#subsubsec:screen-lock>Lock App Manager</a> with the screen\nlock configured for your device.</section><section id=extended-modes-for-app-ops class=level3 data-number=6.9.4><h3 data-number=6.9.4><span class=header-section-number>6.9.4</span>\n<a href=#toc:extended-modes-for-app-ops>Extended Modes for App\nOps</a><a href=#extended-modes-for-app-ops class=anchor aria-hidden=true></a></h3><p>You can set any mode for any app ops that your device supports,\neither from the <a href=#subsec:set-mode-for-app-ops-dots>1-click ops\npage</a> or from the <a href=#subsubsec:app-ops>app ops tab</a>.</section><section id=new-batch-ops-add-to-profile class=level3 data-number=6.9.5><h3 data-number=6.9.5><span class=header-section-number>6.9.5</span>\n<a href=#toc:new-batch-ops-add-to-profile>New Batch Ops: Add to\nProfile</a><a href=#new-batch-ops-add-to-profile class=anchor aria-hidden=true></a></h3><p>You can now easily add selected apps to an existing profile using the\nbatch operations.</section><section id=app-info-improved class=level3 data-number=6.9.6><h3 data-number=6.9.6><span class=header-section-number>6.9.6</span>\n<a href=#toc:app-info-improved>App Info: Improved</a><a href=#app-info-improved class=anchor aria-hidden=true></a></h3><p>App info tab now has many options, including the ability to change <a href=#sec:terminologies>SSAID</a>, network policy (i.e. background\nnetwork usage), battery optimization, etc. Most of the tags used in this\ntab are also clickable, and if you click on them, you will be able to\nlook at the current state or configure them right away.</section><section id=advanced-sort-and-filtering-options-in-the-main-page class=level3 data-number=6.9.7><h3 data-number=6.9.7><span class=header-section-number>6.9.7</span>\n<a href=#toc:advanced-sort-and-filtering-options-in-the-main-page>Advanced\nSort and Filtering Options in the Main Page</a><a href=#advanced-sort-and-filtering-options-in-the-main-page class=anchor aria-hidden=true></a></h3><p>Sort and filter options are now replaced by <a href=#subsubsec:main-list-options>List Options</a> which is highly\nconfigurable, including the ability to filter using profiles.</section><section id=about-this-device class=level3 data-number=6.9.8><h3 data-number=6.9.8><span class=header-section-number>6.9.8</span>\n<a href=#toc:about-this-device>About This Device</a><a href=#about-this-device class=anchor aria-hidden=true></a></h3><p>Interested in knowing about your device in just one page? Go to the\nbottom of the <a href=#subsec:device-info>settings page</a>.</section><section id=enabledisable-features class=level3 data-number=6.9.9><h3 data-number=6.9.9><span class=header-section-number>6.9.9</span>\n<a href=#toc:enabledisable-features>Enable/disable Features</a><a href=#enabledisable-features class=anchor aria-hidden=true></a></h3><p>Not interested in all the features that AM offers? You can disable\nsome features in <a href=#subsubsec:enable/disable-features>settings</a>.</section><section id=new-languages-1 class=level3 data-number=6.9.10><h3 data-number=6.9.10><span class=header-section-number>6.9.10</span> <a href=#toc:new-languages-1>New Languages</a><a href=#new-languages-1 class=anchor aria-hidden=true></a></h3><p>AM now has more than 19 languages! New languages include Farsi,\nJapanese and Traditional Chinese.</section><section id=signing-the-apk-files class=level3 data-number=6.9.11><h3 data-number=6.9.11><span class=header-section-number>6.9.11</span> <a href=#toc:signing-the-apk-files>Signing the APK Files</a><a href=#signing-the-apk-files class=anchor aria-hidden=true></a></h3><p>You can now import external signing keys in AM! For security, App\nManager has its own encrypted KeyStore which can also be <a href=#subsubsec:import/export-keystore>imported or exported</a>.</section><section id=new-extension-unapkm class=level3 data-number=6.9.12><h3 data-number=6.9.12><span class=header-section-number>6.9.12</span> <a href=#toc:new-extension-unapkm>New Extension: UnAPKM</a><a href=#new-extension-unapkm class=anchor aria-hidden=true></a></h3><p>Since APKMirror has removed encryption from their APKM files, it’s no\nlonger necessary to decrypt them. As a result, the option to decrypt\nAPKM files has been removed. Instead, this option is now provided by the\nUnAPKM extension which you can grab from <a href=https://f-droid.org/packages/io.github.muntashirakon.unapkm/>F-Droid</a>.\nSo, if you have an encrypted APKM file and have this extension\ninstalled, you can open the file directly in AM.</section></section><section id=sec:v2.5.20-(375) class=level2 data-number=6.10><h2 data-number=6.10><span class=header-section-number>6.10</span>\n<a href=#toc:sec:v2.5.20-(375)>v2.5.20 (375)</a><a href=#sec:v2.5.20-(375) class=anchor aria-hidden=true></a></h2><section id=subsec:introducing-profiles class=level3 data-number=6.10.1><h3 data-number=6.10.1><span class=header-section-number>6.10.1</span> <a href=#toc:subsec:introducing-profiles>Introducing Profiles</a><a href=#subsec:introducing-profiles class=anchor aria-hidden=true></a></h3><p><a href=#sec:profile-page>Profiles</a> finally closes the <a href=https://github.com/MuntashirAkon/AppManager/issues/72>related\nissue</a>. Profiles can be used to execute certain tasks repeatedly\nwithout doing everything manually. A profile can be applied (or invoked)\neither from the <a href=#sec:profiles-page>Profiles page</a> or from\nthe home screen by creating shortcuts. There are also some presets which\nconsist of debloating profiles taken from <a href=https://gitlab.com/W1nst0n/universal-android-debloater>Universal\nAndroid Debloater</a>.<section id=known-limitations class=level5 data-number=6.10.1.0.1><h5 data-number=6.10.1.0.1><span class=header-section-number>6.10.1.0.1</span> Known limitations<a href=#known-limitations class=anchor aria-hidden=true></a></h5><ul class=incremental><li><p>Exporting rules and applying permissions are not currently\nworking.<li><p>Profiles are applied for all users.</ul></section></section><section id=subsec:the-interceptor class=level3 data-number=6.10.2><h3 data-number=6.10.2><span class=header-section-number>6.10.2</span> <a href=#toc:subsec:the-interceptor>The Interceptor</a><a href=#subsec:the-interceptor class=anchor aria-hidden=true></a></h3><p><a href=https://github.com/MuntashirAkon/intent-intercept>Intent\nIntercept</a> works as a man-in-the-middle between source and\ndestination, that is, when you open a file or URL with another app, you\ncan see what is being shared by opening it with Interceptor first. You\ncan also add or modify the intents before sending them to the\ndestination. Additionally, you can double-click on any exportable\nactivities in the Activities tab in the App Details page to open them in\nthe Interceptor to add more configurations.<section id=known-limitation-2 class=level5 data-number=6.10.2.0.1><h5 data-number=6.10.2.0.1><span class=header-section-number>6.10.2.0.1</span> Known limitation<a href=#known-limitation-2 class=anchor aria-hidden=true></a></h5><p>Editing extras is not currently possible.</section></section><section id=subsec:unapkm:-dedrm-the-apkm-files class=level3 data-number=6.10.3><h3 data-number=6.10.3><span class=header-section-number>6.10.3</span> <a href=#toc:subsec:unapkm:-dedrm-the-apkm-files>UnAPKM: DeDRM the APKM\nfiles</a><a href=#subsec:unapkm:-dedrm-the-apkm-files class=anchor aria-hidden=true></a></h3><p>When I released a small tool called <a href=https://f-droid.org/en/packages/io.github.muntashirakon.unapkm>UnAPKM</a>,\nI promised that similar feature will be available in App Manager. I am\nproud to announce that you can open APKM files directly in the App Info\npage or convert them to APKS or install them directly.</section><section id=subsec:multiple-user class=level3 data-number=6.10.4><h3 data-number=6.10.4><span class=header-section-number>6.10.4</span> <a href=#toc:subsec:multiple-user>Multiple user</a><a href=#subsec:multiple-user class=anchor aria-hidden=true></a></h3><p>App manager now supports multiple users! For now, this requires root\nor ADB. But no-root support is also being considered. If you have\nmultiple users enabled and click on an app installed in multiple\nprofiles, an alert prompt will be displayed where you can select the\nuser.</section><section id=vive-la-france class=level3 data-number=6.10.5><h3 data-number=6.10.5><span class=header-section-number>6.10.5</span> <a href=#toc:vive-la-france>Vive la France!</a><a href=#vive-la-france class=anchor aria-hidden=true></a></h3><p>Thanks to the contributors, we have one more addition to the language\nclub: French. You can add more languages or improve existing\ntranslations at <a href=https://hosted.weblate.org/engage/app-manager>Weblate</a>.</section><section id=report-crashes class=level3 data-number=6.10.6><h3 data-number=6.10.6><span class=header-section-number>6.10.6</span> <a href=#toc:report-crashes>Report crashes</a><a href=#report-crashes class=anchor aria-hidden=true></a></h3><p>If App Manager crashes, you can now easily report the crash from the\nnotifications which opens the share options. Crashes are not reported by\nApp Manager, it only redirects you to your favourite Email client.</section><section id=android-11 class=level3 data-number=6.10.7><h3 data-number=6.10.7><span class=header-section-number>6.10.7</span> <a href=#toc:android-11>Android 11</a><a href=#android-11 class=anchor aria-hidden=true></a></h3><p>Added support for Android 11. Not everything may work as expected\nthough.</section><section id=app-installer-improvements class=level3 data-number=6.10.8><h3 data-number=6.10.8><span class=header-section-number>6.10.8</span> <a href=#toc:app-installer-improvements>App Installer Improvements</a><a href=#app-installer-improvements class=anchor aria-hidden=true></a></h3><section id=set-installation-locations class=level4 data-number=6.10.8.1><h4 data-number=6.10.8.1><span class=header-section-number>6.10.8.1</span> Set installation\nlocations<a href=#set-installation-locations class=anchor aria-hidden=true></a></h4><p>In settings page, you can set install locations such as auto\n(default), internal only and prefer external.</section><section id=set-apk-installer class=level4 data-number=6.10.8.2><h4 data-number=6.10.8.2><span class=header-section-number>6.10.8.2</span> Set APK installer<a href=#set-apk-installer class=anchor aria-hidden=true></a></h4><p>In settings page, you can also set default APK installer (root/ADB\nonly) instead of App Manager.</section><section id=multiple-users class=level4 data-number=6.10.8.3><h4 data-number=6.10.8.3><span class=header-section-number>6.10.8.3</span> Multiple users<a href=#multiple-users class=anchor aria-hidden=true></a></h4><p>In settings page, you can allow App Manager to display multiple users\nduring APK installation.</section><section id=signing-apk-files class=level4 data-number=6.10.8.4><h4 data-number=6.10.8.4><span class=header-section-number>6.10.8.4</span> Signing APK files<a href=#signing-apk-files class=anchor aria-hidden=true></a></h4><p>In settings page, you can choose to sign APK files before installing\nthem. You can also select which signature scheme to use in the <em>APK\nsigning</em> option in settings.<section id=known-limitation-3 class=level5 data-number=6.10.8.4.1><h5 data-number=6.10.8.4.1><span class=header-section-number>6.10.8.4.1</span> Known limitation<a href=#known-limitation-3 class=anchor aria-hidden=true></a></h5><p>Currently, only a generic key is used to sign APK files</section></section></section></section><section id=v2.5.17-368 class=level2 data-number=6.11><h2 data-number=6.11><span class=header-section-number>6.11</span>\n<a href=#toc:v2.5.17-368>v2.5.17 (368)</a><a href=#v2.5.17-368 class=anchor aria-hidden=true></a></h2><section id=app-installer class=level3 data-number=6.11.1><h3 data-number=6.11.1><span class=header-section-number>6.11.1</span> <a href=#toc:app-installer>App Installer</a><a href=#app-installer class=anchor aria-hidden=true></a></h3><p>As promised, it is now possible to select splits. AM also provides\nrecommendations based on device configurations. If the app is already\ninstalled, recommendations are provided based on the installed app. It\nis also possible to downgrade to a lower version without data loss if\nthe device has root or ADB. But it should be noted that not all app can\nbe downgraded. Installer is also improved to speed up the installation\nprocess, especially, for root users. If the app has already been\ninstalled and the new (x)apk(s) is newer or older or the same version\nwith a different signature, AM will display a list of changes similar to\n<strong>What’s New</strong> before prompting the user to install the\napp. This is useful if the app has introduced tracker components, new\npermissions, etc.<section id=known-limitations-1 class=level5 data-number=6.11.1.0.1><h5 data-number=6.11.1.0.1><span class=header-section-number>6.11.1.0.1</span> Known Limitations<a href=#known-limitations-1 class=anchor aria-hidden=true></a></h5><ul class=incremental><li><p>Large app can take a long time to fetch app info, and therefore,\nit may take a long time display the installation prompt.<li><p>If the apk is not located in the internal storage, the app has to\nbe cached first which might also take a long time depending on the size\nof the apk.</ul></section></section><section id=scanner-replacement-for-exodus-page class=level3 data-number=6.11.2><h3 data-number=6.11.2><span class=header-section-number>6.11.2</span> <a href=#toc:scanner-replacement-for-exodus-page>Scanner: Replacement for\nExodus Page</a><a href=#scanner-replacement-for-exodus-page class=anchor aria-hidden=true></a></h3><p>Exodus page is now replaced with scanner page. <a href=#sec:scanner-page>Scanner page</a> contains not only a list of\ntrackers but also a list of used libraries. This is just a start. In the\nfuture, this page will contain more in depth analysis of the app.</section><section id=introducing-system-config class=level3 data-number=6.11.3><h3 data-number=6.11.3><span class=header-section-number>6.11.3</span> <a href=#toc:introducing-system-config>Introducing System Config</a><a href=#introducing-system-config class=anchor aria-hidden=true></a></h3><p>System Config lists various system configurations and\nwhitelists/blacklists included in Android by either OEM/vendor, AOSP or\neven some Magisk modules. Root users can access this option from the\noverflow menu in the main page. There isn’t any official documentation\nfor these options therefore it’s difficult to write a complete\ndocumentation for this page. I will gradually add documentations using\nmy own knowledge. However, some functions should be understandable by\ntheir name.</section><section id=more-languages class=level3 data-number=6.11.4><h3 data-number=6.11.4><span class=header-section-number>6.11.4</span> <a href=#toc:more-languages>More Languages</a><a href=#more-languages class=anchor aria-hidden=true></a></h3><p>Thanks to the contributors, AM now has more than 12 languages. New\nlanguages include Bengali, Hindi, Norwegian, Polish, Russian, Simplified\nChinese, Turkish and Ukrainian.</section><section id=app-info-tab class=level3 data-number=6.11.5><h3 data-number=6.11.5><span class=header-section-number>6.11.5</span> <a href=#toc:app-info-tab>App Info Tab</a><a href=#app-info-tab class=anchor aria-hidden=true></a></h3><p>More tags are added in the <a href=#subsec:app-info-tab>app info\ntab</a> such as <strong>KeyStore</strong> (apps with KeyStore items),\n<strong>Systemless app</strong> (apps installed via Magisk),\n<strong>Running</strong> (apps that are running). For external apk, two\nmore options are added namely <strong>Reinstall</strong> and\n<strong>Downgrade</strong>. Now it is possible to share an apk via\nBluetooth. For system apps, it is possible to uninstall updates for\nroot/ADB users. But like the similar option in the system settings, this\noperation will clear all app data. As stated above, exodus has been\nreplaced with scanner.</section><section id=navigation-improvements class=level3 data-number=6.11.6><h3 data-number=6.11.6><span class=header-section-number>6.11.6</span> <a href=#toc:navigation-improvements>Navigation Improvements</a><a href=#navigation-improvements class=anchor aria-hidden=true></a></h3><p>It’s now relatively easy to navigate to various UI components using\nkeyboard. You can use up/down button to navigate between list items and\ntab button to navigate to UI components inside an item.</section><section id=running-apps-page class=level3 data-number=6.11.7><h3 data-number=6.11.7><span class=header-section-number>6.11.7</span> <a href=#toc:running-apps-page>Running Apps Page</a><a href=#running-apps-page class=anchor aria-hidden=true></a></h3><p>It is now possible to sort and filter processes in this tab. Also,\nthe three big buttons are replaced with an easy-to-use three dot menu.\nPreviously the memory usage was wrong which is fixed in this\nversion.</section><section id=built-in-toybox class=level3 data-number=6.11.8><h3 data-number=6.11.8><span class=header-section-number>6.11.8</span> <a href=#toc:built-in-toybox>Built-in Toybox</a><a href=#built-in-toybox class=anchor aria-hidden=true></a></h3><p>Toybox (an alternative to busybox) is bundled with AM. Although\nAndroid has this utility built-in from API 23, toybox is bundled in\norder to prevent buggy implementations and to support API &lt; 23.</section><section id=component-blocker-improvements class=level3 data-number=6.11.9><h3 data-number=6.11.9><span class=header-section-number>6.11.9</span> <a href=#toc:component-blocker-improvements>Component Blocker\nImprovements</a><a href=#component-blocker-improvements class=anchor aria-hidden=true></a></h3><p>Component blocker seemed to be problematic in the previous version,\nespecially when global component blocking is enabled. The issues are\nmostly fixed now.<div class=\"amalert warning\"><p><strong><em>Caution.</em></strong><p>The component blocking mechanism is no longer compatible with v2.5.6\ndue to various security issues. If you have this version, upgrade to\nv2.5.13 or earlier versions first. After that, enable <a href=#subsubsec:instant-component-blocking>global component\nblocking</a> and disable it again.</div></section><section id=improvements-in-the-app-details-page class=level3 data-number=6.11.10><h3 data-number=6.11.10><span class=header-section-number>6.11.10</span> <a href=#toc:improvements-in-the-app-details-page>Improvements in the App\nDetails Page</a><a href=#improvements-in-the-app-details-page class=anchor aria-hidden=true></a></h3><p>Value of various app ops depend on their parent app ops. Therefore,\nwhen you allow/deny an app op, the parent of the app op gets modified.\nThis fixes the issues some users have been complaining regarding some\napp ops that couldn’t be changed.<p>If an app has the target API 23 or less, its permissions cannot be\nmodified using the <code>pm grant …</code> command. Therefore, for such\napps, option to toggle permission has been disabled.<p>The signature tab is improved to support localization. It also\ndisplays multiple checksums for a signature.</section><section id=app-manifest class=level3 data-number=6.11.11><h3 data-number=6.11.11><span class=header-section-number>6.11.11</span> <a href=#toc:app-manifest>App Manifest</a><a href=#app-manifest class=anchor aria-hidden=true></a></h3><p>Manifest no longer crashes if the size of the manifest is too long.\nGenerated manifest are now more accurate than before.</section></section><section id=v2.5.13-348 class=level2 data-number=6.12><h2 data-number=6.12><span class=header-section-number>6.12</span>\n<a href=#toc:v2.5.13-348>v2.5.13 (348)</a><a href=#v2.5.13-348 class=anchor aria-hidden=true></a></h2><section id=bundled-app-split-apk class=level3 data-number=6.12.1><h3 data-number=6.12.1><span class=header-section-number>6.12.1</span> <a href=#toc:bundled-app-split-apk>Bundled App (Split APK)</a><a href=#bundled-app-split-apk class=anchor aria-hidden=true></a></h3><p>Bundled app formats such as <strong>apks</strong> and\n<strong>xapk</strong> are now supported. You can install these apps\nusing the regular installation buttons. For root and adb users, apps are\ninstalled using shell, and for non-root users, the platform default\nmethod is used.<section id=known-limitations-2 class=level5 data-number=6.12.1.0.1><h5 data-number=6.12.1.0.1><span class=header-section-number>6.12.1.0.1</span> Known Limitations<a href=#known-limitations-2 class=anchor aria-hidden=true></a></h5><ul class=incremental><li><p>Currently <em>all</em> splits apks are installed. But this\nbehaviour is going to change in the next release. If you only need a few\nsplits instead of all, extract the <strong>APKS</strong> or\n<strong>XAPK</strong> file, and then, create a new zip file with your\ndesired split apks and replace the <strong>ZIP</strong> extension with\n<strong>APKS</strong>. Now, open it with AM.<li><p>There is no progress dialog to display the installation\nprogress.</ul></section></section><section id=direct-install-support class=level3 data-number=6.12.2><h3 data-number=6.12.2><span class=header-section-number>6.12.2</span> <a href=#toc:direct-install-support>Direct Install Support</a><a href=#direct-install-support class=anchor aria-hidden=true></a></h3><p>You can now install <strong>APK</strong>, <strong>APKS</strong> or\n<strong>XAPK</strong> directly from your favourite browser or file\nmanager. For apps that need updates, a <strong>What’s New</strong>\ndialog is displayed showing the changes in the new version.<section id=known-limitations-3 class=level5 data-number=6.12.2.0.1><h5 data-number=6.12.2.0.1><span class=header-section-number>6.12.2.0.1</span> Known Limitations<a href=#known-limitations-3 class=anchor aria-hidden=true></a></h5><ul class=incremental><li><p>Downgrade is not yet possible.<li><p>There is no progress dialog to display the installation progress.\nIf you cannot interact with the current page, wait until the\ninstallation is finished.</ul></section></section><section id=remove-all-blocking-rules class=level3 data-number=6.12.3><h3 data-number=6.12.3><span class=header-section-number>6.12.3</span> <a href=#toc:remove-all-blocking-rules>Remove All Blocking Rules</a><a href=#remove-all-blocking-rules class=anchor aria-hidden=true></a></h3><p>In the Settings page, a new option is added which can be used to\nremove all blocking rules configured within App Manager.</section><section id=app-ops-1 class=level3 data-number=6.12.4><h3 data-number=6.12.4><span class=header-section-number>6.12.4</span> <a href=#toc:app-ops-1>App\nOps</a><a href=#app-ops-1 class=anchor aria-hidden=true></a></h3><ul class=incremental><li><p>App Ops are now generated using a technique similar to AppOpsX.\nThis should decrease the loading time significantly in the App Ops\ntab.<li><p>In the App Ops tab, a menu item is added which can be used to\nlist only active app ops without including the default app ops. The\npreference is saved in the shared preferences.</ul><section id=known-limitation-4 class=level5 data-number=6.12.4.0.1><h5 data-number=6.12.4.0.1><span class=header-section-number>6.12.4.0.1</span> Known Limitation<a href=#known-limitation-4 class=anchor aria-hidden=true></a></h5><p>Often the App Ops tab may not be responsive. If that’s the case,\nrestart App Manager.</section></section><section id=enhanced-adb-support class=level3 data-number=6.12.5><h3 data-number=6.12.5><span class=header-section-number>6.12.5</span> <a href=#toc:enhanced-adb-support>Enhanced ADB Support</a><a href=#enhanced-adb-support class=anchor aria-hidden=true></a></h3><p>ADB shell commands are now executed using a technique similar to\nAppOpsX (This is the <em>free</em> alternative of AppOps by Rikka.).\nThis should dramatically increase the execution time.<section id=known-limitation-5 class=level5 data-number=6.12.5.0.1><h5 data-number=6.12.5.0.1><span class=header-section-number>6.12.5.0.1</span> Known Limitation<a href=#known-limitation-5 class=anchor aria-hidden=true></a></h5><p>AM can often crash or become not responsive. If that’s the case,\nrestart App Manager.</section></section><section id=filtering-in-main-page class=level3 data-number=6.12.6><h3 data-number=6.12.6><span class=header-section-number>6.12.6</span> <a href=#toc:filtering-in-main-page>Filtering in Main Page</a><a href=#filtering-in-main-page class=anchor aria-hidden=true></a></h3><p>Add an option to filter apps that has at least one activity.</section><section id=apk-backupsharing class=level3 data-number=6.12.7><h3 data-number=6.12.7><span class=header-section-number>6.12.7</span> <a href=#toc:apk-backupsharing>Apk Backup/Sharing</a><a href=#apk-backupsharing class=anchor aria-hidden=true></a></h3><p>Apk files are now saved as <code>app name_version.extension</code>\ninstead of <code>package.name.extension</code>.</section><section id=batch-ops class=level3 data-number=6.12.8><h3 data-number=6.12.8><span class=header-section-number>6.12.8</span> <a href=#toc:batch-ops>Batch Ops</a><a href=#batch-ops class=anchor aria-hidden=true></a></h3><ul class=incremental><li><p>Added a foreground service to run batch operations. The result of\nthe operation is displayed in a notification. If an operation has failed\nfor some packages, clicking on the notification will open a dialog box\nlisting the failed packages. There is also a <strong>Try Again</strong>\nbutton on the bottom which can be used to perform the operation again\nfor the failed packages.<li><p>Replaced Linux <em>kill</em> with\n<strong>force-stop</strong>.</ul></section><section id=translations class=level3 data-number=6.12.9><h3 data-number=6.12.9><span class=header-section-number>6.12.9</span> <a href=#toc:translations>Translations</a><a href=#translations class=anchor aria-hidden=true></a></h3><p>Added German and Portuguese (Brazilian) translations.<section id=known-limitation-6 class=level5 data-number=6.12.9.0.1><h5 data-number=6.12.9.0.1><span class=header-section-number>6.12.9.0.1</span> Known Limitation<a href=#known-limitation-6 class=anchor aria-hidden=true></a></h5><p>Not all translations are verified yet.</section></section><section id=app-data-backup class=level3 data-number=6.12.10><h3 data-number=6.12.10><span class=header-section-number>6.12.10</span> <a href=#toc:app-data-backup>App Data Backup</a><a href=#app-data-backup class=anchor aria-hidden=true></a></h3><p>Install app only for the current user at the time of restoring\nbackups. Support for split apks is also added.<p><em>Data backup feature is now considered unstable. If you encounter\nany problem, please report to me without hesitation.</em></section></section></section><section id=ch:app-ops class=level1 data-number=7><h1 data-number=7><span class=header-section-number>7</span> <a href=#toc:ch:app-ops>App Ops</a><a href=#ch:app-ops class=anchor aria-hidden=true></a></h1><section id=sec:app-ops-background class=level2 data-number=7.1><h2 data-number=7.1><span class=header-section-number>7.1</span> <a href=#toc:sec:app-ops-background>Background</a><a href=#sec:app-ops-background class=anchor aria-hidden=true></a></h2><p><strong>App Ops</strong> (short hand for <strong>Application\nOperations</strong>) are used by Android system (since Android 4.3) to\ncontrol application permissions. The user <em>can</em> control some\npermissions, but only the permissions that are considered dangerous (and\nGoogle thinks knowing your phone number isn’t a dangerous thing). So,\napp ops seems to be the one we need if we want to install apps like\nFacebook and it’s Messenger (the latter literary records everything if\nyou live outside the EU) and still want <em>some</em> privacy and/or\nsecurity. Although certain features of app ops were available in\nSettings and later in hidden settings in older version of Android, it’s\ncompletely hidden in newer versions of Android and is continued to be\nkept hidden. Now, any app with\n<strong>android.Manifest.permission.GET_APP_OPS_STATS</strong>\npermission can get the app ops information for other applications but\nthis permission is hidden from users and can only be enabled using ADB\nor root. Still, the app with this permission cannot grant or revoke\npermissions (actually mode of operation) for apps other than itself\n(with limited capacity, of course). To modify the ops of other app, the\napp needs\n<strong>android.Manifest.permission.UPDATE_APP_OPS_STATS</strong>\npermissions which isn’t accessible via <code>pm</code> command. So, you\ncannot grant it via root or ADB, the permission is only granted to the\nsystem apps. There are very few apps who support disabling permissions\nvia app ops. The best one to my knowledge is <a href=https://github.com/8enet/AppOpsX>AppOpsX</a>. The main (visible)\ndifference between my app (AppManager) and this app is that the latter\nalso provides you the ability to revoke internet permissions (by writing\nip tables). One crucial problem that I faced during the development of\nthe app ops API is the lack of documentation in English language.</section><section id=sec:introduction-to-app-ops class=level2 data-number=7.2><h2 data-number=7.2><span class=header-section-number>7.2</span> <a href=#toc:sec:introduction-to-app-ops>Introduction to App Ops</a><a href=#sec:introduction-to-app-ops class=anchor aria-hidden=true></a></h2><figure id=fig:appops><figure><object data=../images/appops.svg type=image/svg+xml></object></figure><figcaption>Figure 2: How app ops work</figcaption></figure><p>Figure <a href=#fig:appops>1</a> describes the process of changing\nand processing permission. <a href=#sec:appopsmanager>AppOpsManager</a> can be used to manage\npermissions in Settings app. <strong>AppOpsManager</strong> is also\nuseful in determining if a certain permission (or operation) is granted\nto the application. Most of the methods of\n<strong>AppOpsManager</strong> are accessible to the user app but unlike\na system app, it can only be used to check permissions for any app or\nfor the app itself and start or terminating certain operations.\nMoreover, not all operations are actually accessible from this Java\nclass. <strong>AppOpsManager</strong> holds all the necessary constants\nsuch as <a href=#subsec:op-constants><code>OP_*</code></a>,\n<code>OPSTR_*</code>, <a href=#subsec:mode-constants><code>MODE_*</code></a> which describes\noperation code, operation string and mode of operations respectively. It\nalso holds necessary data structures such as <a href=#subsec:package-ops>PackageOps</a> and <strong>OpEntry</strong>.\n<strong>PackageOps</strong> holds <strong>OpEntry</strong> for a\npackage, and <strong>OpEntry</strong>, as the name suggests, describes\neach operation.<p><code>AppOpService</code> is completely hidden from a user\napplication but accessible to the system applications. As it can be seen\nin Figure <a href=#fig:appops>1</a>, this is the class that does the\nactual management stuff. It contains data structures such as\n<strong>Ops</strong> to store basic package info and <strong>Op</strong>\nwhich is similar to <strong>OpEntry</strong> of\n<strong>AppOpsManager</strong>. It also has <strong>Shell</strong> which\nis actually the source code of the <a href=#sec:appops-cli><em>appops</em> command line tool</a>. It writes\nconfigurations to or read configurations from <a href=#sec:appops-xml><code>/data/system/appops.xml</code></a>. System\nservices calls <strong>AppOpsService</strong> to find out what an\napplication is allowed and what is not allowed to perform, and\n<strong>AppOpsService</strong> determines these permissions by parsing\n<code>/data/system/appops.xml</code>. If no custom values are present in\n<em>appops.xml</em>, it returns the default mode available in\n<strong>AppOpsManager</strong>.</section><section id=sec:appopsmanager class=level2 data-number=7.3><h2 data-number=7.3><span class=header-section-number>7.3</span> <a href=#toc:sec:appopsmanager>AppOpsManager</a><a href=#sec:appopsmanager class=anchor aria-hidden=true></a></h2><p><a href=https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/app/AppOpsManager.java>AppOpsManager</a>\nstands for application operations manager. It consists of various\nconstants and classes to modify app operations.<div class=seealso-inline><p><em>Bạn cũng có thể xem: <span><a href=https://developer.android.com/reference/android/app/AppOpsManager>AppOpsManager\ndocumentation</a></span></em></div><section id=subsec:op-constants class=level3 data-number=7.3.1><h3 data-number=7.3.1><span class=header-section-number>7.3.1</span>\n<a href=#toc:subsec:op-constants><code>OP_*</code> Constants</a><a href=#subsec:op-constants class=anchor aria-hidden=true></a></h3><p><code>OP_*</code> are the integer constants starting from\n<code>0</code>. <code>OP_NONE</code> implies that no operations are\nspecified whereas <code>_NUM_OP</code> denotes the number of operations\ndefined in <code>OP_*</code> prefix. While they denote each operation,\nthe operations are not necessarily unique. In fact, there are many\noperations that are actually a single operation denoted by multiple\n<code>OP_*</code> constant (possibly for future use). Vendors may define\ntheir own op based on their requirements. MIUI is one of the vendors who\nare known to do that.<div class=listing><div class=sourceCode id=cb11 data-frame=lines><pre class=\"sourceCode java\"><code class=\"sourceCode java\"><span id=cb11-1><a href=#cb11-1 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=dt>final</span> <span class=dt>int</span> OP_NONE <span class=op>=</span> <span class=op>-</span><span class=dv>1</span><span class=op>;</span></span>\n<span id=cb11-2><a href=#cb11-2 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=dt>final</span> <span class=dt>int</span> OP_COARSE_LOCATION <span class=op>=</span> <span class=dv>0</span><span class=op>;</span></span>\n<span id=cb11-3><a href=#cb11-3 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=dt>final</span> <span class=dt>int</span> OP_FINE_LOCATION <span class=op>=</span> <span class=dv>1</span><span class=op>;</span></span>\n<span id=cb11-4><a href=#cb11-4 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=dt>final</span> <span class=dt>int</span> OP_GPS <span class=op>=</span> <span class=dv>2</span><span class=op>;</span></span>\n<span id=cb11-5><a href=#cb11-5 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=dt>final</span> <span class=dt>int</span> OP_VIBRATE <span class=op>=</span> <span class=dv>3</span><span class=op>;</span></span>\n<span id=cb11-6><a href=#cb11-6 aria-hidden=true tabindex=-1></a><span class=kw>...</span></span>\n<span id=cb11-7><a href=#cb11-7 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=dt>final</span> <span class=dt>int</span> OP_READ_DEVICE_IDENTIFIERS <span class=op>=</span> <span class=dv>89</span><span class=op>;</span></span>\n<span id=cb11-8><a href=#cb11-8 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=dt>final</span> <span class=dt>int</span> OP_ACCESS_MEDIA_LOCATION <span class=op>=</span> <span class=dv>90</span><span class=op>;</span></span>\n<span id=cb11-9><a href=#cb11-9 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=dt>final</span> <span class=dt>int</span> OP_ACTIVATE_PLATFORM_VPN <span class=op>=</span> <span class=dv>91</span><span class=op>;</span></span>\n<span id=cb11-10><a href=#cb11-10 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=dt>final</span> <span class=dt>int</span> _NUM_OP <span class=op>=</span> <span class=dv>92</span><span class=op>;</span></span></code></pre></div></div><p>Whether an operation is unique is defined by\n<code>sOpToSwitch</code>. It maps each operation to another operation or\nto itself (if it’s a unique operation). For instance,\n<code>OP_FINE_LOCATION</code> and <code>OP_GPS</code> are mapped to\n<code>OP_COARSE_LOCATION</code>.<p>Each operation has a private name which are described by\n<code>sOpNames</code>. These names are usually the same names as the\nconstants without the <code>OP_</code> prefix. Some operations have\npublic names as well which are described by <code>sOpToString</code>.\nFor instance, <code>OP_COARSE_LOCATION</code> has the public name\n<strong>android:coarse_location</strong>.<p>As a gradual process of moving permissions to app ops, there are\nalready many permissions that are defined under some operations. These\npermissions are mapped in <code>sOpPerms</code>. For example, the\npermission\n<strong>android.Manifest.permission.ACCESS_COARSE_LOCATION</strong> is\nmapped to <code>OP_COARSE_LOCATION</code>. Some operations may not have\nany associated permissions which have <code>null</code> values.<p>As described in the previous section, operations that are configured\nfor an app are stored at <a href=#sec:appops-xml><code>/data/system/appops.xml</code></a>. If an\noperation is not configured, then whether system will allow that\noperation is determined from <code>sOpDefaultMode</code>. It lists the\n<em>default mode</em> for each operation.</section><section id=subsec:mode-constants class=level3 data-number=7.3.2><h3 data-number=7.3.2><span class=header-section-number>7.3.2</span>\n<a href=#toc:subsec:mode-constants><code>MODE_*</code> Constants</a><a href=#subsec:mode-constants class=anchor aria-hidden=true></a></h3><p><code>MODE_*</code> constants also integer constants starting from\n<code>0</code>. These constants are assigned to each operation\ndescribing whether an app is authorised to perform that operation. These\nmodes usually have associated names such as <strong>allow</strong> for\n<code>MODE_ALLOWED</code>, <strong>ignore</strong> for\n<code>MODE_IGNORED</code>, <strong>deny</strong> for\n<code>MODE_ERRORED</code> (a rather misnomer), <strong>default</strong>\nfor <code>MODE_DEFAULT</code> and <strong>foreground</strong> for\n<code>MODE_FOREGROUND</code>.<ol class=incremental><li><p><strong><code>MODE_ALLOWED</code>.</strong> The app is allowed to\nperform the given operation<li><p><strong><code>MODE_IGNORED</code>.</strong> The app is not\nallowed to perform the given operation, and any attempt to perform the\noperation should <em>silently fail</em>, i.e. it should not cause the\napp to crash<li><p><strong><code>MODE_ERRORED</code>.</strong> The app is not\nallowed to perform the given operation, and this attempt should cause it\nto have a fatal error, typically a\n<code>SecurityException</code><li><p><strong><code>MODE_DEFAULT</code>.</strong> The app should use\nits default security check, specified in\n<code>AppOpsManager</code><li><p><strong><code>MODE_FOREGROUND</code>.</strong> Special mode that\nmeans “allow only when app is in foreground.” This mode was added in\nAndroid 10<li><p><strong><code>MODE_ASK</code>.</strong> This is a custom mode\nused by MIUI whose uses are unknown.</ol></section><section id=subsec:package-ops class=level3 data-number=7.3.3><h3 data-number=7.3.3><span class=header-section-number>7.3.3</span>\n<a href=#toc:subsec:package-ops>PackageOps</a><a href=#subsec:package-ops class=anchor aria-hidden=true></a></h3><p><strong>AppOpsManager.PackageOps</strong> is a data structure to\nstore all the <strong>OpEntry</strong> for a package. In simple terms,\nit stores all the customised operations for a package.<div class=listing><div class=sourceCode id=cb12 data-frame=lines><pre class=\"sourceCode java\"><code class=\"sourceCode java\"><span id=cb12-1><a href=#cb12-1 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=kw>class</span> PackageOps <span class=kw>implements</span> Parcelable <span class=op>{</span></span>\n<span id=cb12-2><a href=#cb12-2 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=bu>String</span> mPackageName<span class=op>;</span></span>\n<span id=cb12-3><a href=#cb12-3 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=dt>int</span> mUid<span class=op>;</span></span>\n<span id=cb12-4><a href=#cb12-4 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=bu>List</span><span class=op>&lt;</span>OpEntry<span class=op>&gt;</span> mEntries<span class=op>;</span></span>\n<span id=cb12-5><a href=#cb12-5 aria-hidden=true tabindex=-1></a>    <span class=kw>...</span></span>\n<span id=cb12-6><a href=#cb12-6 aria-hidden=true tabindex=-1></a><span class=op>}</span></span></code></pre></div></div><p>As can be seen in Listing <a href=#lst:package-ops-class>2</a>, it\nstores all <strong>OpEntry</strong> for a package as well as the\ncorresponding package name and its kernel user ID.</section><section id=subsec:opentry class=level3 data-number=7.3.4><h3 data-number=7.3.4><span class=header-section-number>7.3.4</span>\n<a href=#toc:subsec:opentry>OpEntry</a><a href=#subsec:opentry class=anchor aria-hidden=true></a></h3><p><strong>AppOpsManager.OpEntry</strong> is a data structure that\nstores a single operation for any package.<div class=listing><div class=sourceCode id=cb13 data-frame=lines><pre class=\"sourceCode java\"><code class=\"sourceCode java\"><span id=cb13-1><a href=#cb13-1 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=dt>final</span> <span class=kw>class</span> OpEntry <span class=kw>implements</span> Parcelable <span class=op>{</span></span>\n<span id=cb13-2><a href=#cb13-2 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=dt>int</span> mOp<span class=op>;</span></span>\n<span id=cb13-3><a href=#cb13-3 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=dt>boolean</span> mRunning<span class=op>;</span></span>\n<span id=cb13-4><a href=#cb13-4 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=at>@Mode</span> <span class=dt>int</span> mMode<span class=op>;</span></span>\n<span id=cb13-5><a href=#cb13-5 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=at>@Nullable</span> LongSparseLongArray mAccessTimes<span class=op>;</span></span>\n<span id=cb13-6><a href=#cb13-6 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=at>@Nullable</span> LongSparseLongArray mRejectTimes<span class=op>;</span></span>\n<span id=cb13-7><a href=#cb13-7 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=at>@Nullable</span> LongSparseLongArray mDurations<span class=op>;</span></span>\n<span id=cb13-8><a href=#cb13-8 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=at>@Nullable</span> LongSparseLongArray mProxyUids<span class=op>;</span></span>\n<span id=cb13-9><a href=#cb13-9 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=at>@Nullable</span> LongSparseArray<span class=op>&lt;</span><span class=bu>String</span><span class=op>&gt;</span> mProxyPackageNames<span class=op>;</span></span>\n<span id=cb13-10><a href=#cb13-10 aria-hidden=true tabindex=-1></a>    <span class=kw>...</span></span>\n<span id=cb13-11><a href=#cb13-11 aria-hidden=true tabindex=-1></a><span class=op>}</span></span></code></pre></div></div><p>Here:<ul class=incremental><li><p><code>mOp</code>: Denotes one of the <a href=#subsec:op-constants><code>OP_*</code> constants</a><li><p><code>mRunning</code>: Whether the operation is in progress\n(i.e. the operation has started but not finished yet). Not all\noperations can be started or finished this way<li><p><code>mMOde</code>: One of the <a href=#subsec:mode-constants><code>MODE_*</code> constants</a><li><p><code>mAccessTimes</code>: Stores all the available access\ntimes<li><p><code>mRejectTimes</code>: Stores all the available reject\ntimes<li><p><code>mDurations</code>: All available access durations, checking\nthis with <code>mRunning</code> will tell you for how long the app is\nperforming a certain app operation<li><p><code>mProxyUids</code>: No documentation found<li><p><code>mProxyPackageNames:</code> No documentation found</ul></section><section id=subsec:usage class=level3 data-number=7.3.5><h3 data-number=7.3.5><span class=header-section-number>7.3.5</span>\n<a href=#toc:subsec:usage>Usage</a><a href=#subsec:usage class=anchor aria-hidden=true></a></h3><p>TODO</section></section><section id=sec:appopsservice class=level2 data-number=7.4><h2 data-number=7.4><span class=header-section-number>7.4</span> <a href=#toc:sec:appopsservice>AppOpsService</a><a href=#sec:appopsservice class=anchor aria-hidden=true></a></h2><p>TODO</section><section id=sec:appops-xml class=level2 data-number=7.5><h2 data-number=7.5><span class=header-section-number>7.5</span> <a href=#toc:sec:appops-xml>appops.xml</a><a href=#sec:appops-xml class=anchor aria-hidden=true></a></h2><p>Latest <code>appops.xml</code> has the following format: (This DTD is\nmade by me and by no means perfect, has compatibility issues.)<pre><code>&lt;!DOCTYPE app-ops [\n\n&lt;!ELEMENT app-ops (uid|pkg)*&gt;\n&lt;!ATTLIST app-ops v CDATA #IMPLIED&gt;\n\n&lt;!ELEMENT uid (op)*&gt;\n&lt;!ATTLIST uid n CDATA #REQUIRED&gt;\n\n&lt;!ELEMENT pkg (uid)*&gt;\n&lt;!ATTLIST pkg n CDATA #REQUIRED&gt;\n\n&lt;!ELEMENT uid (op)*&gt;\n&lt;!ATTLIST uid\nn CDATA #REQUIRED\np CDATA #IMPLIED&gt;\n\n&lt;!ELEMENT op (st)*&gt;\n&lt;!ATTLIST op\nn CDATA #REQUIRED\nm CDATA #REQUIRED&gt;\n\n&lt;!ELEMENT st EMPTY&gt;\n&lt;!ATTLIST st\nn CDATA #REQUIRED\nt CDATA #IMPLIED\nr CDATA #IMPLIED\nd CDATA #IMPLIED\npp CDATA #IMPLIED\npu CDATA #IMPLIED&gt;\n\n]&gt;</code></pre><p>The instruction below follows the exact order given above:<ul class=incremental><li><p><code>app-ops</code>: The root element. It can contain any number\nof <code>pkg</code> or package <code>uid</code><ul class=incremental><li><p><code>v</code>: (optional, integer) The version number (default:\n<code>NO_VERSION</code> or <code>-1</code>)</ul><li><p><code>pkg</code>: Stores package info. It can contain any number\nof <code>uid</code><ul class=incremental><li><p><code>n</code>: (required, string) Name of the package</ul><li><p>Package <code>uid</code>: Stores package or packages info<ul class=incremental><li><p><code>n</code>: (required, integer) The user ID</ul><li><p><code>uid</code>: The package user ID. It can contain any number\nof <code>op</code><ul class=incremental><li><p><code>n</code>: (required, integer) The user ID<li><p><code>p</code>: (optional, boolean) Is the app is a\nprivate/system app</ul><li><p><code>op</code>: The operation, can contain <code>st</code> or\nnothing at all<ul class=incremental><li><p><code>n</code>: (required, integer) The op name in integer,\ni.e. AppOpsManager.OP_*<li><p><code>m</code>: (required, integer) The op mode,\ni.e. AppOpsManager.MODE_*</ul><li><p><code>st</code>: State of operation: whether the operation is\naccessed, rejected or running (not available on old versions)<ul class=incremental><li><p><code>n</code>: (required, long) Key containing flags and\nuid<li><p><code>t</code>: (optional, long) Access time (default:\n<code>0</code>)<li><p><code>r</code>: (optional, long) Reject time (default:\n<code>0</code>)<li><p><code>d</code>: (optional, long) Access duration (default:\n<code>0</code>)<li><p><code>pp</code>: (optional, string) Proxy package name<li><p><code>pu</code>: (optional, integer) Proxy package uid</ul></ul><p>This definition can be found at <a href=https://android.googlesource.com/platform/frameworks/base/+/master/services/core/java/com/android/server/appop/AppOpsService.java>AppOpsService</a>.</section><section id=sec:appops-cli class=level2 data-number=7.6><h2 data-number=7.6><span class=header-section-number>7.6</span> <a href=#toc:sec:appops-cli>Command Line Interface</a><a href=#sec:appops-cli class=anchor aria-hidden=true></a></h2><p><code>appops</code> or <code>cmd appops</code> (on latest versions)\ncan be accessible via ADB or root. This is an easier method to get or\nupdate any operation for a package (provided the package name is known).\nThe help page of this command is self-explanatory:<pre><code>AppOps service (appops) commands:\nhelp\nPrint this help text.\nstart [--user &lt;USER_ID&gt;] &lt;PACKAGE | UID&gt; &lt;OP&gt;\nStarts a given operation for a particular application.\nstop [--user &lt;USER_ID&gt;] &lt;PACKAGE | UID&gt; &lt;OP&gt;\nStops a given operation for a particular application.\nset [--user &lt;USER_ID&gt;] &lt;[--uid] PACKAGE | UID&gt; &lt;OP&gt; &lt;MODE&gt;\nSet the mode for a particular application and operation.\nget [--user &lt;USER_ID&gt;] &lt;PACKAGE | UID&gt; [&lt;OP&gt;]\nReturn the mode for a particular application and optional operation.\nquery-op [--user &lt;USER_ID&gt;] &lt;OP&gt; [&lt;MODE&gt;]\nPrint all packages that currently have the given op in the given mode.\nreset [--user &lt;USER_ID&gt;] [&lt;PACKAGE&gt;]\nReset the given application or all applications to default modes.\nwrite-settings\nImmediately write pending changes to storage.\nread-settings\nRead the last written settings, replacing current state in RAM.\noptions:\n&lt;PACKAGE&gt; an Android package name or its UID if prefixed by --uid\n&lt;OP&gt;      an AppOps operation.\n&lt;MODE&gt;    one of allow, ignore, deny, or default\n&lt;USER_ID&gt; the user id under which the package is installed. If --user is not\nspecified, the current user is assumed.</code></pre></section></section><section id=footnotes class=\"footnotes footnotes-end-of-document\" role=doc-endnotes><hr><ol><li id=fn1><p>For distributing normal releases only<a href=#fnref1 class=footnote-back role=doc-backlink>↩︎</a><li id=fn2><p>GitHub pull requests will be merged manually using the\ncorresponding patches. As a result, GitHub may wrongfully mark them\nclosed instead of merged.<a href=#fnref2 class=footnote-back role=doc-backlink>↩︎</a><li id=fn3><p>You can also address me as “Muntashir Akon”<a href=#fnref3 class=footnote-back role=doc-backlink>↩︎</a></ol></section>"
  },
  {
    "path": "docs/raw/vi/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"intro$main$$introduction-chapter-title\">Giới thiệu</string>\n    <string name=\"titlepage$user_manual\">{\\\\huge\\\\bfseries Hướng dẫn sử dụng cho người dùng\\\\par}</string>\n    <string name=\"keywords$see_also\">\\\\newcommand{\\\\KeywordSeeAlso}{Bạn cũng có thể xem:}</string>\n    <string name=\"keywords$end_of_keyword_in_alert\">\\\\newcommand{\\\\KeywordEndOfKeyWordInAlert}{.}</string>\n    <string name=\"keywords$chapter\">\\\\newcommand{\\\\KeywordChapter}{Chương}</string>\n    <string name=\"titlepage$quotation\">\\\\begin{quotation}\n\\n ``Khôn ngoan và chậm rãi. Những người chạy nhanh sẽ bị vấp.\\'\\'\n\\n %\\\\sourceatright\n\\n {--- Friar Laurence, \\\\textit{Romeo và Juliet}}\n\\n \\\\end{quotation}</string>\n    <string name=\"intro$main$$submit-patches-title\">Gửi bản vá</string>\n    <string name=\"intro$main$$donation-title\">Ủng hộ \\\\&amp; Tài chính</string>\n    <string name=\"intro$main$$contact-title\">Liên hệ</string>\n    <string name=\"intro$main$intro\">App Manager là ứng dụng quản lý các ứng dụng khác dành cho Android. Nó có vô số các tính năng, và do đó cần hướng dẫn\n\\nsử dụng để hỗ trợ người dùng. Tài liệu này đóng vai trò là hướng dẫn sử dụng cho App Manager theo nghĩa là nó miêu tả\n\\nmọi tính năng mà App Manager có. Tài liệu này cũng có thể được coi là ``hướng dẫn\\'\\' chính thức cho\n\\nApp Manager, và đại diện cho hành vi thông thường của App Manager. Các bản dịch có thể làm lệch ý của tài liệu (được viết bằng\n\\ntiếng Anh) này. Do đó, những người dùng có hiểu biết nên đọc bản tiếng Anh của tài liệu để tận dụng tối đa\n\\ncông năng của App Manager. Ngoài ra có thể có các tài nguyên không chính thức khác như bài viết blog, video, nhóm\n\\nchat, v.v. Các tài nguyên đó có thể giúp ích được nhiều người, nhưng chúng có khả năng là cũ hơn phiên bản\n\\nhiện tại của App Manager. Nếu App Manager có hoạt động sai lệch so với tài liệu này, thì bạn nên báo cáo ở \n\\n\\\\href{https://github.com/MuntashirAkon/AppManager/issues}{nơi theo dõi vấn đề của App Manager}.</string>\n    <string name=\"intro$main$$terminologies-title\">Thuật ngữ</string>\n    <string name=\"intro$main$$supported-versions-title\">Phiên bản được hỗ trợ</string>\n    <string name=\"intro$main$$official-sources-title\">Nguồn chính thức</string>\n    <string name=\"intro$main$$bin-sources-title\">Nguồn phân phối tệp nhị phân</string>\n    <string name=\"intro$main$$source-code-links-title\">Liên kết đến mã nguồn</string>\n    <string name=\"intro$main$$translations-title\">Bản dịch</string>\n    <string name=\"intro$main$$contributing-title\">Đóng góp</string>\n    <string name=\"intro$main$$buiding-title\">Hướng dẫn xây dựng</string>\n    <string name=\"intro$main$terminologies\">Hieucandy</string>\n    <string name=\"intro$main$source-code-links\">Tất cả trừ GitHub là các liên kết nhân bản. Các thẻ phải luôn được cập nhật, nhưng nhánh chính không được đảm bảo là\n\\ncập nhật. Nếu mục tiêu là sao chép nhánh chính, hãy sử dụng liên kết GitHub thay vì các liên kết khác.</string>\n    <string name=\"intro$main$buiding\">Hướng dẫn xây dựng có sẵn trong tệp BUILDING nằm ở thư mục gốc của mã nguồn.</string>\n    <string name=\"pages$main$$pages-chapter-title\">Trang</string>\n    <string name=\"pages$main-page$$section-title\">Trang chính</string>\n    <string name=\"pages$main-page$$how-app-ops-work-title\">Một mục danh sách ứng dụng trong trang chính</string>\n    <string name=\"pages$main-page$$settings-title\">Cài đặt</string>\n    <string name=\"pages$main-page$$profiles-title\">Hồ sơ</string>\n    <string name=\"pages$main-page$$apk-updater-title\">Trình cập nhật APK</string>\n    <string name=\"pages$main-page$$batch-operations-title\">Hoạt động hàng loạt</string>\n    <string name=\"pages$main-page$$1-click-ops-title\">1-Nhấp vào Hoạt động</string>\n    <string name=\"pages$main-page$$running-apps-title\">Đang chạy các ứng dụng</string>\n    <string name=\"pages$main-page$options-menu\">Menu tùy chọn cung cấp một số tùy chọn có thể được sử dụng để sắp xếp và lọc các ứng dụng được liệt kê cũng như để điều hướng\n\\nđến các trang khác nhau trong hoặc ngoài Trình quản lý ứng dụng.</string>\n    <string name=\"pages$main-page$list-options\">\\\\textbf{Liệt kê các tùy chọn} chứa các tùy chọn để sắp xếp và lọc danh sách trong trang chính.</string>\n    <string name=\"intro$main$supported-versions\">Hiện tại, các phiên bản được hỗ trợ là v3.0.4 và v3.1.0 (ổn định), v3.2.0 (bản phát hành alpha và gỡ lỗi).\n\\nCác phiên bản trước của Trình quản lý ứng dụng có thể chứa các lỗ hổng bảo mật và không nên được sử dụng.</string>\n    <string name=\"intro$main$translations\">Trình quản lý ứng dụng không chấp nhận bản dịch trực tiếp thông qua yêu cầu kéo/hợp nhất. Các bản dịch được quản lý thông qua Hosted Weblate.\n\\nĐể dịch Trình quản lý ứng dụng, hãy truy cập \\\\url{https://hosted.weblate.org/engage/app-manager/}.</string>\n    <string name=\"intro$main$contributing\">Có nhiều cách người dùng có thể đóng góp, chẳng hạn như tạo các vấn đề hữu ích, tham dự các cuộc thảo luận, cải thiện\n\\ntài liệu và bản dịch, thêm các thư viện hoặc trình theo dõi không được công nhận, xem lại mã nguồn cũng như\n\\nbáo cáo lỗ hổng bảo mật.</string>\n    <string name=\"pages$main-page$$app-usage-title\">Sử dụng ứng dụng</string>\n    <string name=\"pages$main-page$$sort-title\">Sắp xếp</string>\n    <string name=\"pages$main-page$$filter-title\">Lọc</string>\n    <string name=\"pages$main-page$$colour-codes-title\">Mã màu</string>\n    <string name=\"pages$main-page$$application-types-title\">Các loại ứng dụng</string>\n    <string name=\"pages$main-page$$version-info-title\">Thông tin phiên bản</string>\n    <string name=\"pages$main-page$$options-menu-title\">Trình đơn tùy chọn</string>\n    <string name=\"pages$main-page$$list-options-title\">Tùy chọn danh sách</string>\n    <string name=\"pages$main-page$$profile_name-title\">Tên hồ sơ</string>\n    <string name=\"pages$main-page$$instructions-title\">Hướng dẫn sử dụng</string>\n    <string name=\"appendices$changelogs$$chapter-title\">Nhật ký thay đổi</string>\n    <string name=\"faq$app-components$$tracker-classes-versus-tracker-components-title\">Các lớp theo dõi so với các thành phần theo dõi</string>\n    <string name=\"faq$app-components$$also-blocked-by-other-tools-title\">Điều gì xảy ra với các thành phần bị chặn bởi App Manager mà trước đây đã bị các công cụ khác chặn?</string>\n</resources>"
  },
  {
    "path": "docs/raw/zh-rCN/index.html",
    "content": "<!doctype html><html xmlns=http://www.w3.org/1999/xhtml lang=zh-Hans xml:lang=zh-Hans><meta charset=utf-8><meta name=generator content=\"pandoc\"><meta name=viewport content=\"width=device-width,initial-scale=1,user-scalable=yes\"><meta name=author content=\"Muntashir Al-Islam\"><title>App Manager</title><style>code{white-space:pre-wrap}span.smallcaps{font-variant:small-caps}div.columns{display:flex;gap:min(4vw,1.5em)}div.column{flex:auto;overflow-x:auto}div.hanging-indent{margin-left:1.5em;text-indent:-1.5em}ul.task-list[class]{list-style:none}ul.task-list li input[type=checkbox]{font-size:inherit;width:.8em;margin:0 .8em .2em -1.6em;vertical-align:middle}.display.math{display:block;text-align:center;margin:.5rem auto}html{-webkit-text-size-adjust:100%}pre>code.sourceCode{white-space:pre;position:relative}pre>code.sourceCode>span{display:inline-block;line-height:1.25}pre>code.sourceCode>span:empty{height:1.2em}.sourceCode{overflow:visible}code.sourceCode>span{color:inherit;text-decoration:inherit}div.sourceCode{margin:1em 0}pre.sourceCode{margin:0}@media screen{div.sourceCode{overflow:auto}}@media print{pre>code.sourceCode{white-space:pre-wrap}pre>code.sourceCode>span{text-indent:-5em;padding-left:5em}}pre.numberSource code{counter-reset:source-line 0}pre.numberSource code>span{position:relative;left:-4em;counter-increment:source-line}pre.numberSource code>span>a:first-child::before{content:counter(source-line);position:relative;left:-1em;text-align:right;vertical-align:baseline;border:none;display:inline-block;-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;padding:0 4px;width:4em}pre.numberSource{margin-left:3em;padding-left:4px}div.sourceCode{}@media screen{pre>code.sourceCode>span>a:first-child::before{text-decoration:underline}}code span.al{font-weight:700}code span.an{font-style:italic}code span.cf{font-weight:700}code span.co{font-style:italic}code span.cv{font-style:italic}code span.do{font-style:italic}code span.dt{text-decoration:underline}code span.er{font-weight:700}code span.in{font-style:italic}code span.kw{font-weight:700}code span.pp{font-weight:700}code span.wa{font-style:italic}</style><link rel=stylesheet href=../css/custom.css><header id=title-block-header><h1 class=title>App Manager</h1><p class=author>Muntashir Al-Islam</header><nav id=TOC role=doc-toc><ul class=incremental><li><span><span class=toc-section-number>1</span> <a href=#ch:introduction id=toc:ch:introduction>简介</a></span><ul class=incremental><li><span><span class=toc-section-number>1.1</span> <a href=#sec:terminologies id=toc:sec:terminologies>术语</a></span><li><span><span class=toc-section-number>1.2</span> <a href=#sec:supported-versions id=toc:sec:supported-versions>受支持的版本</a></span><li><span><span class=toc-section-number>1.3</span> <a href=#sec:official-sources id=toc:sec:official-sources>官方来源</a></span><ul class=incremental><li><span><span class=toc-section-number>1.3.1</span> <a href=#subsec:binary-distribution-sources id=toc:subsec:binary-distribution-sources>二进制(可执行)分发来源</a></span><li><span><span class=toc-section-number>1.3.2</span> <a href=#subsec:links-to-source-code id=toc:subsec:links-to-source-code>源码链接</a></span><li><span><span class=toc-section-number>1.3.3</span> <a href=#subsec:translations id=toc:subsec:translations>翻译</a></span></ul><li><span><span class=toc-section-number>1.4</span> <a href=#sec:contributing id=toc:sec:contributing>贡献</a></span><ul class=incremental><li><span><span class=toc-section-number>1.4.1</span> <a href=#subsec:build-instructions id=toc:subsec:build-instructions>构建说明</a></span><li><span><span class=toc-section-number>1.4.2</span> <a href=#subsec:submitting-patches id=toc:subsec:submitting-patches>提交补丁</a></span></ul><li><span><span class=toc-section-number>1.5</span> <a href=#sec:donation-&-funding id=toc:sec:donation-&-funding>捐赠 & 资助</a></span><li><span><span class=toc-section-number>1.6</span> <a href=#sec:contact id=toc:sec:contact>联系我们</a></span></ul><li><span><span class=toc-section-number>2</span> <a href=#ch:pages id=toc:ch:pages>页面</a></span><ul class=incremental><li><span><span class=toc-section-number>2.1</span> <a href=#sec:main-page id=toc:sec:main-page>主页</a></span><ul class=incremental><li><span><span class=toc-section-number>2.1.1</span> <a href=#subsec:batch-operations id=toc:subsec:batch-operations>批处理</a></span><li><span><span class=toc-section-number>2.1.2</span> <a href=#subsec:main-colour-codes id=toc:subsec:main-colour-codes>颜色代码含义</a></span><li><span><span class=toc-section-number>2.1.3</span> <a href=#subsec:main-page-application-types id=toc:subsec:main-page-application-types>应用类型</a></span><li><span><span class=toc-section-number>2.1.4</span> <a href=#subsec:main-page-version-info id=toc:subsec:main-page-version-info>版本信息</a></span><li><span><span class=toc-section-number>2.1.5</span> <a href=#subsec:main-page-options-menu id=toc:subsec:main-page-options-menu>选项菜单</a></span></ul><li><span><span class=toc-section-number>2.2</span> <a href=#sec:app-details-page id=toc:sec:app-details-page>应用程序详情页</a></span><ul class=incremental><li><span><span class=toc-section-number>2.2.1</span> <a href=#subsec:app-details-colour-codes id=toc:subsec:app-details-colour-codes>颜色代码含义</a></span><li><span><span class=toc-section-number>2.2.2</span> <a href=#subsec:app-info-tab id=toc:subsec:app-info-tab>应用信息</a></span><li><span><span class=toc-section-number>2.2.3</span> <a href=#subsec:component-tabs id=toc:subsec:component-tabs>组件选项卡</a></span><li><span><span class=toc-section-number>2.2.4</span> <a href=#subsec:permission-tabs id=toc:subsec:permission-tabs>权限选项卡</a></span><li><span><span class=toc-section-number>2.2.5</span> <a href=#subsec:signatures-tab id=toc:subsec:signatures-tab>签名选项卡</a></span><li><span><span class=toc-section-number>2.2.6</span> <a href=#subsec:uses-features-tab id=toc:subsec:uses-features-tab>使用特性选项卡</a></span><li><span><span class=toc-section-number>2.2.7</span> <a href=#subsec:configurations-tab id=toc:subsec:configurations-tab>配置选项卡</a></span><li><span><span class=toc-section-number>2.2.8</span> <a href=#subsec:shared-libs-tab id=toc:subsec:shared-libs-tab>共享库选项卡</a></span></ul><li><span><span class=toc-section-number>2.3</span> <a href=#sec:1-click-ops-page id=toc:sec:1-click-ops-page>一键操作页</a></span><ul class=incremental><li><span><span class=toc-section-number>2.3.1</span> <a href=#subsec:block-unblock-trackers id=toc:subsec:block-unblock-trackers>阻止/取消阻止跟踪器</a></span><li><span><span class=toc-section-number>2.3.2</span> <a href=#subsec:block-components-dots id=toc:subsec:block-components-dots>阻止组件…</a></span><li><span><span class=toc-section-number>2.3.3</span> <a href=#subsec:set-mode-for-app-ops-dots id=toc:subsec:set-mode-for-app-ops-dots>设置 App Ops 模式\n…</a></span><li><span><span class=toc-section-number>2.3.4</span> <a href=#subsec:1-click-back-up id=toc:subsec:1-click-back-up>备份</a></span><li><span><span class=toc-section-number>2.3.5</span> <a href=#subsec:1-click-restore id=toc:subsec:1-click-restore>恢复</a></span><li><span><span class=toc-section-number>2.3.6</span> <a href=#subsec:trim-caches-in-all-apps id=toc:subsec:trim-caches-in-all-apps>清理所有应用的缓存</a></span></ul><li><span><span class=toc-section-number>2.4</span> <a href=#sec:profiles-page id=toc:sec:profiles-page>配置文件页面</a></span><ul class=incremental><li><span><span class=toc-section-number>2.4.1</span> <a href=#subsec:profiles-options-menu id=toc:subsec:profiles-options-menu>选项菜单</a></span></ul><li><span><span class=toc-section-number>2.5</span> <a href=#sec:profile-page id=toc:sec:profile-page>配置页</a></span><ul class=incremental><li><span><span class=toc-section-number>2.5.1</span> <a href=#subsec:profile-options-menu id=toc:subsec:profile-options-menu>选项菜单</a></span><li><span><span class=toc-section-number>2.5.2</span> <a href=#subsec:profile-apps-tab id=toc:subsec:profile-apps-tab>应用程序选项卡</a></span><li><span><span class=toc-section-number>2.5.3</span> <a href=#subsec:profile-configurations-tab id=toc:subsec:profile-configurations-tab>配置选项卡</a></span></ul><li><span><span class=toc-section-number>2.6</span> <a href=#sec:settings-page id=toc:sec:settings-page>设置页面</a></span><ul class=incremental><li><span><span class=toc-section-number>2.6.1</span> <a href=#subsec:language id=toc:subsec:language>界面语言</a></span><li><span><span class=toc-section-number>2.6.2</span> <a href=#subsec:appearance id=toc:subsec:appearance>外观</a></span><li><span><span class=toc-section-number>2.6.3</span> <a href=#subsec:privacy id=toc:subsec:privacy>隐私</a></span><li><span><span class=toc-section-number>2.6.4</span> <a href=#subsec:mode-of-operation id=toc:subsec:mode-of-operation>操作模式</a></span><li><span><span class=toc-section-number>2.6.5</span> <a href=#subsec:apk-signing id=toc:subsec:apk-signing>APK\n签名</a></span><li><span><span class=toc-section-number>2.6.6</span> <a href=#subsec:installer id=toc:subsec:installer>安装器</a></span><li><span><span class=toc-section-number>2.6.7</span> <a href=#subsec:backup/restore id=toc:subsec:backup/restore>备份/恢复</a></span><li><span><span class=toc-section-number>2.6.8</span> <a href=#subsec:rules id=toc:subsec:rules>规则</a></span><li><span><span class=toc-section-number>2.6.9</span> <a href=#subsec:advanced id=toc:subsec:advanced>高级</a></span><li><span><span class=toc-section-number>2.6.10</span> <a href=#subsec:device-info id=toc:subsec:device-info>关于设备</a></span></ul><li><span><span class=toc-section-number>2.7</span> <a href=#sec:scanner-page id=toc:sec:scanner-page>扫描器页面</a></span><li><span><span class=toc-section-number>2.8</span> <a href=#sec:interceptor-page id=toc:sec:interceptor-page>拦截器页面</a></span><ul class=incremental><li><span><span class=toc-section-number>2.8.1</span> <a href=#subsec:intent-filters id=toc:subsec:intent-filters>意图(Intent)过滤器</a></span><li><span><span class=toc-section-number>2.8.2</span> <a href=#subsec:matching-activities id=toc:subsec:matching-activities>匹配的活动(Activity)</a></span><li><span><span class=toc-section-number>2.8.3</span> <a href=#subsec:interceptor-reset-to-default id=toc:subsec:interceptor-reset-to-default>重置为默认</a></span><li><span><span class=toc-section-number>2.8.4</span> <a href=#subsec:interceptor-send-edited-intent id=toc:subsec:interceptor-send-edited-intent>发送编辑过的意图(Intent)</a></span></ul><li><span><span class=toc-section-number>2.9</span> <a href=#sec:shared-preferences-editor-page id=toc:sec:shared-preferences-editor-page>共享首选项(Shared\nPreferences)编辑页</a></span></ul><li><span><span class=toc-section-number>3</span> <a href=#ch:guides id=toc:ch:guides>指南</a></span><ul class=incremental><li><span><span class=toc-section-number>3.1</span> <a href=#sec:adb-over-tcp id=toc:sec:adb-over-tcp>经由 TCP 的\nADB</a></span><ul class=incremental><li><span><span class=toc-section-number>3.1.1</span> <a href=#subsec:enable-developer-options id=toc:subsec:enable-developer-options>启用开发者选项</a></span><li><span><span class=toc-section-number>3.1.2</span> <a href=#subsec:enable-usb-debugging id=toc:subsec:enable-usb-debugging>启用USB调试</a></span><li><span><span class=toc-section-number>3.1.3</span> <a href=#subsec:setup-adb-on-pc-or-mac id=toc:subsec:setup-adb-on-pc-or-mac>在PC或Mac上配置ADB</a></span><li><span><span class=toc-section-number>3.1.4</span> <a href=#subsec:configure-adb-over-tcp id=toc:subsec:configure-adb-over-tcp>配置经由TCP的ADB</a></span></ul><li><span><span class=toc-section-number>3.2</span> <a href=#sec:wireless-debugging id=toc:sec:wireless-debugging>无线调试</a></span><ul class=incremental><li><span><span class=toc-section-number>3.2.1</span> <a href=#subsec:enable-developer-options-and-usb-debugging id=toc:subsec:enable-developer-options-and-usb-debugging>启用开发者选项和\nUSB 调试</a></span><li><span><span class=toc-section-number>3.2.2</span> <a href=#subsec:enable-wireless-debugging id=toc:subsec:enable-wireless-debugging>启用无线调试</a></span><li><span><span class=toc-section-number>3.2.3</span> <a href=#subsec:pair-adb-with-app-manager id=toc:subsec:pair-adb-with-app-manager>用 App Manager 匹配\nADB</a></span><li><span><span class=toc-section-number>3.2.4</span> <a href=#subsec:connect-app-manager-to-adb id=toc:subsec:connect-app-manager-to-adb>连接 App Manager 到\nADB</a></span></ul><li><span><span class=toc-section-number>3.3</span> <a href=#sec:backup-restore id=toc:sec:backup-restore>备份/恢复</a></span><ul class=incremental><li><span><span class=toc-section-number>3.3.1</span> <a href=#subsec:backup-location id=toc:subsec:backup-location>位置</a></span><li><span><span class=toc-section-number>3.3.2</span> <a href=#subsec:backup-restore-backup-options id=toc:subsec:backup-restore-backup-options>备份选项</a></span><li><span><span class=toc-section-number>3.3.3</span> <a href=#subsec:backup-restore-backup id=toc:subsec:backup-restore-backup>备份</a></span><li><span><span class=toc-section-number>3.3.4</span> <a href=#subsec:backup-restore-restore id=toc:subsec:backup-restore-restore>恢复</a></span><li><span><span class=toc-section-number>3.3.5</span> <a href=#subsec:backup-restore-delete-backup id=toc:subsec:backup-restore-delete-backup>删除备份</a></span></ul><li><span><span class=toc-section-number>3.4</span> <a href=#sec:automating-tasks id=toc:sec:automating-tasks>自动任务</a></span><ul class=incremental><li><span><span class=toc-section-number>3.4.1</span> <a href=#subsec:generating-authorization-key id=toc:subsec:generating-authorization-key>生成授权密钥</a></span><li><span><span class=toc-section-number>3.4.2</span> <a href=#subsec:at:general-configuration id=toc:subsec:at:general-configuration>配置任务</a></span><li><span><span class=toc-section-number>3.4.3</span> <a href=#subsec:at:features id=toc:subsec:at:features>功能特性</a></span><li><span><span class=toc-section-number>3.4.4</span> <a href=#subsec:triggering-a-profile id=toc:subsec:triggering-a-profile>触发配置文件</a></span></ul><li><span><span class=toc-section-number>3.5</span> <a href=#sec:net-policy id=toc:sec:net-policy>连网策略</a></span></ul><li><span><span class=toc-section-number>4</span> <a href=#ch:faq id=toc:ch:faq>常见问题</a></span><ul class=incremental><li><span><span class=toc-section-number>4.1</span> <a href=#sec:faq:app-components id=toc:sec:faq:app-components>应用组件</a></span><ul class=incremental><li><span><span class=toc-section-number>4.1.1</span> <a href=#subsec:faq:what-are-app-components id=toc:subsec:faq:what-are-app-components>什么是应用组件？</a></span><li><span><span class=toc-section-number>4.1.2</span> <a href=#subsec:faq:how-components-blocked id=toc:subsec:faq:how-components-blocked>追踪器和其他组件在App\nManager中是如何被禁用的？其局限性是什么？</a></span><li><span><span class=toc-section-number>4.1.3</span> <a href=#subsec:faq:components-blocked-by-others id=toc:subsec:faq:components-blocked-by-others>被其他工具禁用的应用程序组件是否保留在App\nManager中？</a></span><li><span><span class=toc-section-number>4.1.4</span> <a href=#subsec:faq:components-reblocked-in-am id=toc:subsec:faq:components-reblocked-in-am>现在被 App Manager\n拦截但先前被其他工具禁用的组件会发生什么？</a></span><li><span><span class=toc-section-number>4.1.5</span> <a href=#subsec:faq:what-is-instant-component-blocking id=toc:subsec:faq:what-is-instant-component-blocking>什么是即时组件禁用？</a></span><li><span><span class=toc-section-number>4.1.6</span> <a href=#subsec:tracker-classes-versus-tracker-components id=toc:subsec:tracker-classes-versus-tracker-components>跟踪器类与跟踪器组件</a></span></ul><li><span><span class=toc-section-number>4.2</span> <a href=#sec:faq:adb-over-tcp id=toc:sec:faq:adb-over-tcp>ADB over TCP\n(经由TCP的ADB)</a></span><ul class=incremental><li><span><span class=toc-section-number>4.2.1</span> <a href=#subsec:faq:enable-adb-on-every-restart id=toc:subsec:faq:enable-adb-on-every-restart>我必须在每次重启后启用ADB\nover TCP吗？</a></span><li><span><span class=toc-section-number>4.2.2</span> <a href=#subsec:faq:usb-debugging id=toc:subsec:faq:usb-debugging>无法启用 USB\n调试，怎么办？</a></span><li><span><span class=toc-section-number>4.2.3</span> <a href=#subsec:faq:block-components-using-adb id=toc:subsec:faq:block-components-using-adb>我可以使用 ADB over TCP\n来禁用跟踪器或任何其他应用程序组件吗？</a></span><li><span><span class=toc-section-number>4.2.4</span> <a href=#subsec:faq:adb-features id=toc:subsec:faq:adb-features>哪些功能可以在ADB模式下使用？</a></span></ul><li><span><span class=toc-section-number>4.3</span> <a href=#sec:faq:miscellanea id=toc:sec:faq:miscellanea>杂项</a></span><ul class=incremental><li><span><span class=toc-section-number>4.3.1</span> <a href=#subsec:faq:no-root-no-harms id=toc:subsec:faq:no-root-no-harms>我不使用root/ADB，是否完全安全？</a></span><li><span><span class=toc-section-number>4.3.2</span> <a href=#subsec:faq:how-trackers-libs-updated id=toc:subsec:faq:how-trackers-libs-updated>跟踪器和库是如何更新的？</a></span><li><span><span class=toc-section-number>4.3.3</span> <a href=#subsec:faq:apks-deleted-after-installed id=toc:subsec:faq:apks-deleted-after-installed>APK\n安装后是否被删除？</a></span><li><span><span class=toc-section-number>4.3.4</span> <a href=#subsec:faq:shizuku-support id=toc:subsec:faq:shizuku-support>对于 Shizuku\n有何计划？</a></span><li><span><span class=toc-section-number>4.3.5</span> <a href=#subsec:faq:what-are-bloatware id=toc:subsec:faq:what-are-bloatware>什么是预装(bloatware)软件以及如何删除？</a></span></ul></ul><li><span><span class=toc-section-number>5</span> <a href=#ch:specifications id=toc:ch:specifications>语法</a></span><ul class=incremental><li><span><span class=toc-section-number>5.1</span> <a href=#sec:rules-specification id=toc:sec:rules-specification>规则语法</a></span><ul class=incremental><li><span><span class=toc-section-number>5.1.1</span> <a href=#背景介绍 id=toc:背景介绍>背景介绍</a></span><li><span><span class=toc-section-number>5.1.2</span> <a href=#规则文件格式 id=toc:规则文件格式>规则文件格式</a></span></ul></ul><li><span><span class=toc-section-number>6</span> <a href=#ch:changelogs id=toc:ch:changelogs>更新日志</a></span><ul class=incremental><li><span><span class=toc-section-number>6.1</span> <a href=#sec:v4.0.5-(445) id=toc:sec:v4.0.5-(445)>v4.0.5\n(445)</a></span><li><span><span class=toc-section-number>6.2</span> <a href=#sec:v4.0.4-(444) id=toc:sec:v4.0.4-(444)>v4.0.4\n(444)</a></span><li><span><span class=toc-section-number>6.3</span> <a href=#sec:v4.0.3-(443) id=toc:sec:v4.0.3-(443)>v4.0.3\n(443)</a></span><li><span><span class=toc-section-number>6.4</span> <a href=#sec:v4.0.2-(442) id=toc:sec:v4.0.2-(442)>v4.0.2\n(442)</a></span><li><span><span class=toc-section-number>6.5</span> <a href=#sec:v4.0.1-(441) id=toc:sec:v4.0.1-(441)>v4.0.1\n(441)</a></span><ul class=incremental><li><span><span class=toc-section-number>6.5.1</span> <a href=#overlay-management id=toc:overlay-management>Overlay\nmanagement</a></span><li><span><span class=toc-section-number>6.5.2</span> <a href=#unfreeze-option-in-activity-shortcuts id=toc:unfreeze-option-in-activity-shortcuts>Unfreeze option in\nactivity shortcuts</a></span><li><span><span class=toc-section-number>6.5.3</span> <a href=#market-like-url-support id=toc:market-like-url-support><code>market</code>-like URL\nsupport</a></span><li><span><span class=toc-section-number>6.5.4</span> <a href=#updated-color-codes id=toc:updated-color-codes>Updated color\ncodes</a></span><li><span><span class=toc-section-number>6.5.5</span> <a href=#others id=toc:others>Others</a></span></ul><li><span><span class=toc-section-number>6.6</span> <a href=#sec:v4.0.0-(440) id=toc:sec:v4.0.0-(440)>v4.0.0\n(440)</a></span><ul class=incremental><li><span><span class=toc-section-number>6.6.1</span> <a href=#new-logo id=toc:new-logo>New logo!</a></span><li><span><span class=toc-section-number>6.6.2</span> <a href=#android-14-and-15-support id=toc:android-14-and-15-support>Android 14 and 15\nsupport</a></span><li><span><span class=toc-section-number>6.6.3</span> <a href=#revamped-debloater id=toc:revamped-debloater>Revamped\ndebloater</a></span><li><span><span class=toc-section-number>6.6.4</span> <a href=#introducing-file-manager id=toc:introducing-file-manager>Introducing file\nmanager</a></span><li><span><span class=toc-section-number>6.6.5</span> <a href=#integrated-code-editor id=toc:integrated-code-editor>Integrated code editor</a></span><li><span><span class=toc-section-number>6.6.6</span> <a href=#history-of-operations id=toc:history-of-operations>History of\noperations</a></span><li><span><span class=toc-section-number>6.6.7</span> <a href=#per-app-freezing-and-more id=toc:per-app-freezing-and-more>Per-app freezing, and\nmore</a></span><li><span><span class=toc-section-number>6.6.8</span> <a href=#log-viewer-enhancements id=toc:log-viewer-enhancements>Log\nviewer enhancements</a></span><li><span><span class=toc-section-number>6.6.9</span> <a href=#launching-non-exported-activities id=toc:launching-non-exported-activities>Launching non-exported\nactivities</a></span><li><span><span class=toc-section-number>6.6.10</span> <a href=#new-tags-in-app-info-tab id=toc:new-tags-in-app-info-tab>New\ntags in App Info tab</a></span><li><span><span class=toc-section-number>6.6.11</span> <a href=#per-session-installer-options id=toc:per-session-installer-options>Per-session installer\noptions</a></span><li><span><span class=toc-section-number>6.6.12</span> <a href=#advanced-mode-of-operations-adb-enhancements id=toc:advanced-mode-of-operations-adb-enhancements>Advanced mode of\noperations, ADB enhancements, …</a></span><li><span><span class=toc-section-number>6.6.13</span> <a href=#data-usage-widget-and-more id=toc:data-usage-widget-and-more>Data usage widget, and\nmore</a></span><li><span><span class=toc-section-number>6.6.14</span> <a href=#others-1 id=toc:others-1>Others</a></span></ul><li><span><span class=toc-section-number>6.7</span> <a href=#sec:v3.1.0-(423) id=toc:sec:v3.1.0-(423)>v3.1.0\n(423)</a></span><ul class=incremental><li><span><span class=toc-section-number>6.7.1</span> <a href=#android-13-support id=toc:android-13-support>Android 13\nsupport</a></span><li><span><span class=toc-section-number>6.7.2</span> <a href=#introducing-freezeunfreeze id=toc:introducing-freezeunfreeze>Introducing\nfreeze/unfreeze</a></span><li><span><span class=toc-section-number>6.7.3</span> <a href=#export-app-list id=toc:export-app-list>Export app\nlist</a></span><li><span><span class=toc-section-number>6.7.4</span> <a href=#elliptic-curve-crypography-ecc id=toc:elliptic-curve-crypography-ecc>Elliptic Curve Crypography\n(ECC)</a></span><li><span><span class=toc-section-number>6.7.5</span> <a href=#new-languages id=toc:new-languages>New\nlanguages</a></span><li><span><span class=toc-section-number>6.7.6</span> <a href=#more-list-options id=toc:more-list-options>More list\noptions</a></span><li><span><span class=toc-section-number>6.7.7</span> <a href=#improved-handling-of-mode-of-operation id=toc:improved-handling-of-mode-of-operation>Improved handling of\nmode of operation</a></span><li><span><span class=toc-section-number>6.7.8</span> <a href=#handling-multiple-users id=toc:handling-multiple-users>Handling multiple users</a></span><li><span><span class=toc-section-number>6.7.9</span> <a href=#explorer-enhancements id=toc:explorer-enhancements>Explorer\nenhancements</a></span><li><span><span class=toc-section-number>6.7.10</span> <a href=#new-tag-wx id=toc:new-tag-wx>New tag: WX</a></span><li><span><span class=toc-section-number>6.7.11</span> <a href=#app-ops-management id=toc:app-ops-management>App ops\nmanagement</a></span><li><span><span class=toc-section-number>6.7.12</span> <a href=#batch-uninstallation id=toc:batch-uninstallation>Batch\nuninstallation</a></span><li><span><span class=toc-section-number>6.7.13</span> <a href=#running-apps id=toc:running-apps>Running apps</a></span><li><span><span class=toc-section-number>6.7.14</span> <a href=#interceptor id=toc:interceptor>Interceptor</a></span><li><span><span class=toc-section-number>6.7.15</span> <a href=#device-specific-changes id=toc:device-specific-changes>Device-specific changes</a></span><li><span><span class=toc-section-number>6.7.16</span> <a href=#others-2 id=toc:others-2>Others</a></span></ul><li><span><span class=toc-section-number>6.8</span> <a href=#sec:v3.0.0-(410) id=toc:sec:v3.0.0-(410)>v3.0.0\n(410)</a></span><ul class=incremental><li><span><span class=toc-section-number>6.8.1</span> <a href=#material-3-and-more id=toc:material-3-and-more>Material 3 and\nMore</a></span><li><span><span class=toc-section-number>6.8.2</span> <a href=#wireless-debugging id=toc:wireless-debugging>Wireless\nDebugging</a></span><li><span><span class=toc-section-number>6.8.3</span> <a href=#languages id=toc:languages>Languages</a></span><li><span><span class=toc-section-number>6.8.4</span> <a href=#introducing-app-explorer id=toc:introducing-app-explorer>Introducing App\nExplorer</a></span><li><span><span class=toc-section-number>6.8.5</span> <a href=#import-backups-from-other-applications id=toc:import-backups-from-other-applications>Import Backups from\nOther Applications</a></span><li><span><span class=toc-section-number>6.8.6</span> <a href=#virustotal id=toc:virustotal>VirusTotal</a></span><li><span><span class=toc-section-number>6.8.7</span> <a href=#trigger-profiles-from-the-automation-software id=toc:trigger-profiles-from-the-automation-software>Trigger Profiles\nfrom the Automation Software</a></span><li><span><span class=toc-section-number>6.8.8</span> <a href=#improved-application-installer id=toc:improved-application-installer>Improved Application\nInstaller</a></span><li><span><span class=toc-section-number>6.8.9</span> <a href=#component-blocking id=toc:component-blocking>Component\nBlocking</a></span><li><span><span class=toc-section-number>6.8.10</span> <a href=#advanced-searching id=toc:advanced-searching>Advanced\nSearching</a></span><li><span><span class=toc-section-number>6.8.11</span> <a href=#shared-libraries id=toc:shared-libraries>Shared\nLibraries</a></span><li><span><span class=toc-section-number>6.8.12</span> <a href=#make-the-best-use-of-interceptor id=toc:make-the-best-use-of-interceptor>Make the Best Use of\nInterceptor</a></span><li><span><span class=toc-section-number>6.8.13</span> <a href=#widget-screen-time id=toc:widget-screen-time>Widget: Screen\nTime</a></span><li><span><span class=toc-section-number>6.8.14</span> <a href=#widget-clear-cache id=toc:widget-clear-cache>Widget: Clear\nCache</a></span></ul><li><span><span class=toc-section-number>6.9</span> <a href=#sec:v2.6.0-(385) id=toc:sec:v2.6.0-(385)>v2.6.0\n(385)</a></span><ul class=incremental><li><span><span class=toc-section-number>6.9.1</span> <a href=#introducing-backups id=toc:introducing-backups>Introducing\nBackups</a></span><li><span><span class=toc-section-number>6.9.2</span> <a href=#introducing-log-viewer id=toc:introducing-log-viewer>Introducing Log Viewer</a></span><li><span><span class=toc-section-number>6.9.3</span> <a href=#lock-app-manager id=toc:lock-app-manager>Lock App\nManager</a></span><li><span><span class=toc-section-number>6.9.4</span> <a href=#extended-modes-for-app-ops id=toc:extended-modes-for-app-ops>Extended Modes for App\nOps</a></span><li><span><span class=toc-section-number>6.9.5</span> <a href=#new-batch-ops-add-to-profile id=toc:new-batch-ops-add-to-profile>New Batch Ops: Add to\nProfile</a></span><li><span><span class=toc-section-number>6.9.6</span> <a href=#app-info-improved id=toc:app-info-improved>App Info:\nImproved</a></span><li><span><span class=toc-section-number>6.9.7</span> <a href=#advanced-sort-and-filtering-options-in-the-main-page id=toc:advanced-sort-and-filtering-options-in-the-main-page>Advanced\nSort and Filtering Options in the Main Page</a></span><li><span><span class=toc-section-number>6.9.8</span> <a href=#about-this-device id=toc:about-this-device>About This\nDevice</a></span><li><span><span class=toc-section-number>6.9.9</span> <a href=#enabledisable-features id=toc:enabledisable-features>Enable/disable Features</a></span><li><span><span class=toc-section-number>6.9.10</span> <a href=#new-languages-1 id=toc:new-languages-1>New\nLanguages</a></span><li><span><span class=toc-section-number>6.9.11</span> <a href=#signing-the-apk-files id=toc:signing-the-apk-files>Signing the\nAPK Files</a></span><li><span><span class=toc-section-number>6.9.12</span> <a href=#new-extension-unapkm id=toc:new-extension-unapkm>New\nExtension: UnAPKM</a></span></ul><li><span><span class=toc-section-number>6.10</span> <a href=#sec:v2.5.20-(375) id=toc:sec:v2.5.20-(375)>v2.5.20\n(375)</a></span><ul class=incremental><li><span><span class=toc-section-number>6.10.1</span> <a href=#subsec:introducing-profiles id=toc:subsec:introducing-profiles>Introducing\nProfiles</a></span><li><span><span class=toc-section-number>6.10.2</span> <a href=#subsec:the-interceptor id=toc:subsec:the-interceptor>The\nInterceptor</a></span><li><span><span class=toc-section-number>6.10.3</span> <a href=#subsec:unapkm:-dedrm-the-apkm-files id=toc:subsec:unapkm:-dedrm-the-apkm-files>UnAPKM: DeDRM the APKM\nfiles</a></span><li><span><span class=toc-section-number>6.10.4</span> <a href=#subsec:multiple-user id=toc:subsec:multiple-user>Multiple\nuser</a></span><li><span><span class=toc-section-number>6.10.5</span> <a href=#vive-la-france id=toc:vive-la-france>Vive la\nFrance!</a></span><li><span><span class=toc-section-number>6.10.6</span> <a href=#report-crashes id=toc:report-crashes>Report\ncrashes</a></span><li><span><span class=toc-section-number>6.10.7</span> <a href=#android-11 id=toc:android-11>Android 11</a></span><li><span><span class=toc-section-number>6.10.8</span> <a href=#app-installer-improvements id=toc:app-installer-improvements>App Installer\nImprovements</a></span></ul><li><span><span class=toc-section-number>6.11</span> <a href=#v2.5.17-368 id=toc:v2.5.17-368>v2.5.17 (368)</a></span><ul class=incremental><li><span><span class=toc-section-number>6.11.1</span> <a href=#app-installer id=toc:app-installer>App\nInstaller</a></span><li><span><span class=toc-section-number>6.11.2</span> <a href=#scanner-replacement-for-exodus-page id=toc:scanner-replacement-for-exodus-page>Scanner: Replacement for\nExodus Page</a></span><li><span><span class=toc-section-number>6.11.3</span> <a href=#introducing-system-config id=toc:introducing-system-config>Introducing System\nConfig</a></span><li><span><span class=toc-section-number>6.11.4</span> <a href=#more-languages id=toc:more-languages>More\nLanguages</a></span><li><span><span class=toc-section-number>6.11.5</span> <a href=#app-info-tab id=toc:app-info-tab>App Info Tab</a></span><li><span><span class=toc-section-number>6.11.6</span> <a href=#navigation-improvements id=toc:navigation-improvements>Navigation Improvements</a></span><li><span><span class=toc-section-number>6.11.7</span> <a href=#running-apps-page id=toc:running-apps-page>Running Apps\nPage</a></span><li><span><span class=toc-section-number>6.11.8</span> <a href=#built-in-toybox id=toc:built-in-toybox>Built-in\nToybox</a></span><li><span><span class=toc-section-number>6.11.9</span> <a href=#component-blocker-improvements id=toc:component-blocker-improvements>Component Blocker\nImprovements</a></span><li><span><span class=toc-section-number>6.11.10</span> <a href=#improvements-in-the-app-details-page id=toc:improvements-in-the-app-details-page>Improvements in the App\nDetails Page</a></span><li><span><span class=toc-section-number>6.11.11</span> <a href=#app-manifest id=toc:app-manifest>App Manifest</a></span></ul><li><span><span class=toc-section-number>6.12</span> <a href=#v2.5.13-348 id=toc:v2.5.13-348>v2.5.13 (348)</a></span><ul class=incremental><li><span><span class=toc-section-number>6.12.1</span> <a href=#bundled-app-split-apk id=toc:bundled-app-split-apk>Bundled App\n(Split APK)</a></span><li><span><span class=toc-section-number>6.12.2</span> <a href=#direct-install-support id=toc:direct-install-support>Direct\nInstall Support</a></span><li><span><span class=toc-section-number>6.12.3</span> <a href=#remove-all-blocking-rules id=toc:remove-all-blocking-rules>Remove All Blocking\nRules</a></span><li><span><span class=toc-section-number>6.12.4</span> <a href=#app-ops id=toc:app-ops>App Ops</a></span><li><span><span class=toc-section-number>6.12.5</span> <a href=#enhanced-adb-support id=toc:enhanced-adb-support>Enhanced ADB\nSupport</a></span><li><span><span class=toc-section-number>6.12.6</span> <a href=#filtering-in-main-page id=toc:filtering-in-main-page>Filtering\nin Main Page</a></span><li><span><span class=toc-section-number>6.12.7</span> <a href=#apk-backupsharing id=toc:apk-backupsharing>Apk\nBackup/Sharing</a></span><li><span><span class=toc-section-number>6.12.8</span> <a href=#batch-ops id=toc:batch-ops>Batch Ops</a></span><li><span><span class=toc-section-number>6.12.9</span> <a href=#translations id=toc:translations>Translations</a></span><li><span><span class=toc-section-number>6.12.10</span> <a href=#app-data-backup id=toc:app-data-backup>App Data\nBackup</a></span></ul></ul><li><span><span class=toc-section-number>7</span> <a href=#ch:app-ops id=toc:ch:app-ops>App Ops</a></span><ul class=incremental><li><span><span class=toc-section-number>7.1</span> <a href=#sec:app-ops-background id=toc:sec:app-ops-background>Background</a></span><li><span><span class=toc-section-number>7.2</span> <a href=#sec:introduction-to-app-ops id=toc:sec:introduction-to-app-ops>Introduction to App\nOps</a></span><li><span><span class=toc-section-number>7.3</span> <a href=#sec:appopsmanager id=toc:sec:appopsmanager>AppOpsManager</a></span><ul class=incremental><li><span><span class=toc-section-number>7.3.1</span> <a href=#subsec:op-constants id=toc:subsec:op-constants><code>OP_*</code> Constants</a></span><li><span><span class=toc-section-number>7.3.2</span> <a href=#subsec:mode-constants id=toc:subsec:mode-constants><code>MODE_*</code>\nConstants</a></span><li><span><span class=toc-section-number>7.3.3</span> <a href=#subsec:package-ops id=toc:subsec:package-ops>PackageOps</a></span><li><span><span class=toc-section-number>7.3.4</span> <a href=#subsec:opentry id=toc:subsec:opentry>OpEntry</a></span><li><span><span class=toc-section-number>7.3.5</span> <a href=#subsec:usage id=toc:subsec:usage>Usage</a></span></ul><li><span><span class=toc-section-number>7.4</span> <a href=#sec:appopsservice id=toc:sec:appopsservice>AppOpsService</a></span><li><span><span class=toc-section-number>7.5</span> <a href=#sec:appops-xml id=toc:sec:appops-xml>appops.xml</a></span><li><span><span class=toc-section-number>7.6</span> <a href=#sec:appops-cli id=toc:sec:appops-cli>Command Line\nInterface</a></span></ul></ul></nav><div class=titlingpage><div class=center><p><img src=../images/icon.png style=width:1in alt=image><p><strong><span class=smallcaps>App Manager</span></strong><p><strong>用户手册</strong><p><em>v4.0.5</em><p>27 七月 2025<p>Copyright © 2020–2025 Muntashir Al-Islam<blockquote><p>睿智而缓慢。跑得快的人会跌倒。\n<span>—劳伦斯修士，<em>罗密欧与朱丽叶</em></span></blockquote></div></div><section id=ch:introduction class=level1 data-number=1><h1 data-number=1><span class=header-section-number>1</span> <a href=#toc:ch:introduction>简介</a><a href=#ch:introduction class=anchor aria-hidden=true></a></h1><p>App Manager 是一个高级的 Android 包管理器。\n它提供了许多功能，因此需要用户手册来帮助用户。本文档作为 App Manager\n的用户手册，旨在描述 App Manager 提供的每一个功能。 本文档也可以被认为是\nApp Manager 的“官方”指南， 并代表了 App Manager\n的预期行为。翻译对文档理解可能有误（原文是用英语写的）。\n因此，有能力的用户应该阅读英文文档，以充分发挥文档 的作用。\n可能还有其他非官方或第三方资源，如博客文章、视频、论坛、聊天、群组等。\n虽然这些资源可能对很多人有用，但它们的内容可能跟不上最新的 App Manager\n版本。 如果在 App Manager 中发现任何偏离本文档的情况，应在 <a href=https://github.com/MuntashirAkon/AppManager/issues>App Manager\n问题追踪</a>进行报告。<section id=sec:terminologies class=level2 data-number=1.1><h2 data-number=1.1><span class=header-section-number>1.1</span> <a href=#toc:sec:terminologies>术语</a><a href=#sec:terminologies class=anchor aria-hidden=true></a></h2><ul class=incremental><li><p><strong>AM</strong> — App Manager 应用<li><p><strong>Block/Unblock</strong> — 用于拦截组件或解除组件拦截。\n如何拦截取决于 用户选项。<li><p><strong>IFW</strong> — Intent Firewall (意图防火墙)<li><p><strong>Ops</strong> — operations (操作), e.g. app ops, batch\nops, 1-click ops<li><p><strong>SAF</strong> — 存储访问框架（SAF）的缩写形式，Android\n系统所用的抽象概念，允许应用无需担忧底层文件系统便能\n使用或提供文件。<li><p><strong>SSAID</strong> — <code>Settings.Secure.ANDROID_ID</code>\n- 分配给每个应用的设备标识符 (Android Oreo以上版本)，\n由应用签名与包<code>android</code>的SSAID组合生成。\n因此，除非用户选择格式化设备，否则它保证对每个应用来说都是独一无二的。\n它被普遍用于跟踪用户。<li><p><strong>Tracker</strong> — 在文档和 App Manager\n中均表示跟踪器组件， <a href=#sec:scanner-page>scanner page</a>\n是个例外。\n跟踪器包括用于报告崩溃、数据分析、用户画像、身份识别、广告和定位等目的的库文件。因此，这些库的功能并不相同。推广跟踪的\n开源和闭源库之间不存在区别或偏向。</ul></section><section id=sec:supported-versions class=level2 data-number=1.2><h2 data-number=1.2><span class=header-section-number>1.2</span> <a href=#toc:sec:supported-versions>受支持的版本</a><a href=#sec:supported-versions class=anchor aria-hidden=true></a></h2><p>当前，支持的版本是 v4.0.1。 先前版本的 AppManager\n可能包含安全漏洞，不应继续使用。</section><section id=sec:official-sources class=level2 data-number=1.3><h2 data-number=1.3><span class=header-section-number>1.3</span> <a href=#toc:sec:official-sources>官方来源</a><a href=#sec:official-sources class=anchor aria-hidden=true></a></h2><section id=subsec:binary-distribution-sources class=level3 data-number=1.3.1><h3 data-number=1.3.1><span class=header-section-number>1.3.1</span>\n<a href=#toc:subsec:binary-distribution-sources>二进制(可执行)分发来源</a><a href=#subsec:binary-distribution-sources class=anchor aria-hidden=true></a></h3><p>App Manager 通过以下渠道发布。 非官方来源可能分发 App Manager\n的修改版本，使用这样版本的后果由你自己单独承担。<ol class=incremental><li><p>F-Droid <a href=#fn1 class=footnote-ref id=fnref1 role=doc-noteref><sup>1</sup></a><br><em>Link:</em> <a href=https://f-droid.org/packages/io.github.muntashirakon.AppManager class=uri>https://f-droid.org/packages/io.github.muntashirakon.AppManager</a><li><p>GitHub repository.<br><em>Normal releases:</em> <a href=https://github.com/MuntashirAkon/AppManager/releases class=uri>https://github.com/MuntashirAkon/AppManager/releases</a><br><em>Debug releases:</em> <a href=https://github.com/MuntashirAkon/AppManager/actions class=uri>https://github.com/MuntashirAkon/AppManager/actions</a><li><p>Telegram.<br><em>Normal releases:</em> <a href=https://t.me/AppManagerChannel class=uri>https://t.me/AppManagerChannel</a><br><em>Debug releases:</em> <a href=https://t.me/AppManagerDebug class=uri>https://t.me/AppManagerDebug</a></ol></section><section id=subsec:links-to-source-code class=level3 data-number=1.3.2><h3 data-number=1.3.2><span class=header-section-number>1.3.2</span>\n<a href=#toc:subsec:links-to-source-code>源码链接</a><a href=#subsec:links-to-source-code class=anchor aria-hidden=true></a></h3><p>除了GitHub外其他都是镜像链接。tags 应当始终是最新的，但 master\n分支也许不是。 如果计划克隆 master 分支，请使用 GitHub\n链接而不是其他链接。<ol class=incremental><li><p>GitHub: <a href=https://github.com/MuntashirAkon/AppManager class=uri>https://github.com/MuntashirAkon/AppManager</a><li><p>Codeberg: <a href=https://codeberg.org/muntashir/AppManager class=uri>https://codeberg.org/muntashir/AppManager</a><li><p>GitLab: <a href=https://gitlab.com/muntashir/AppManager class=uri>https://gitlab.com/muntashir/AppManager</a><li><p>Riseup: <a href=https://0xacab.org/muntashir/AppManager class=uri>https://0xacab.org/muntashir/AppManager</a><li><p>sourcehut: <a href=https://git.sr.ht/~muntashir/AppManager class=uri>https://git.sr.ht/~muntashir/AppManager</a></ol></section><section id=subsec:translations class=level3 data-number=1.3.3><h3 data-number=1.3.3><span class=header-section-number>1.3.3</span>\n<a href=#toc:subsec:translations>翻译</a><a href=#subsec:translations class=anchor aria-hidden=true></a></h3><p>App Manager 不接受通过 pull/merge 请求进行的翻译。 翻译通过 Hosted\nWeblate 管理。 要翻译App Manager，请访问 <a href=https://hosted.weblate.org/engage/app-manager/ class=uri>https://hosted.weblate.org/engage/app-manager/</a>。开始前请阅读\n<strong>信息</strong> 部分。</section></section><section id=sec:contributing class=level2 data-number=1.4><h2 data-number=1.4><span class=header-section-number>1.4</span> <a href=#toc:sec:contributing>贡献</a><a href=#sec:contributing class=anchor aria-hidden=true></a></h2><p>用户可有通过多种方式作贡献，如创建有用 issues 、参加讨论、\n改进文档和翻译、报告未知的库或跟踪器、 审查源代码以及报告安全漏洞。<section id=subsec:build-instructions class=level3 data-number=1.4.1><h3 data-number=1.4.1><span class=header-section-number>1.4.1</span>\n<a href=#toc:subsec:build-instructions>构建说明</a><a href=#subsec:build-instructions class=anchor aria-hidden=true></a></h3><p>在位于源码根目录下的BUILDING文件中可以获得编译教程。</section><section id=subsec:submitting-patches class=level3 data-number=1.4.2><h3 data-number=1.4.2><span class=header-section-number>1.4.2</span>\n<a href=#toc:subsec:submitting-patches>提交补丁</a><a href=#subsec:submitting-patches class=anchor aria-hidden=true></a></h3><p>除GitHub之外的仓库目前被视为镜像，在这些网站提交的 PR/MR 将不被接受.\n<a href=#fn2 class=footnote-ref id=fnref2 role=doc-noteref><sup>2</sup></a> 相反，patches (<code>.patch</code>\n文件)\n可以通过电子邮件附件提交。<em>请务必对Commits签名(Signing-off)</em>\n更多信息请参见位于源码根目录下的CONTRIBUTING文件.<div class=\"amalert warning\"><p><strong><em>注意.</em></strong><p>至于通过电子邮件提交补丁，完整邮件对话在将来可能可以公开访问.\n所以，请不要包含除了您的姓名和电子邮件地址之外的任何个人身份信息（PII）.</div></section></section><section id=sec:donation-&-funding class=level2 data-number=1.5><h2 data-number=1.5><span class=header-section-number>1.5</span> <a href=#toc:sec:donation-&-funding>捐赠 & 资助</a><a href=#sec:donation-&-funding class=anchor aria-hidden=true></a></h2><p>截至2024年9月， 在另行通知前 App Manager 不接受经济支持。\n但你仍可以向开发者赠送礼物（例如礼品卡、订阅、食物和饮料、鲜花甚至是现金）。\n请用 §<a href=#sec:contact data-reference-type=ref data-reference=sec:contact>1.6</a>\n中给出的选项联系维护者以获得进一步帮助。<p>In addition, the maintainers and contributors of this project DO NOT\nconsent to the creation, sale, or promotion of tokens, cryptocurrencies,\nNFTs, or any other financial instruments that claim to represent this\nproject, its code, or its community. Any such attempts are unauthorized\nand not affiliated with this project in any way.</section><section id=sec:contact class=level2 data-number=1.6><h2 data-number=1.6><span class=header-section-number>1.6</span> <a href=#toc:sec:contact>联系我们</a><a href=#sec:contact class=anchor aria-hidden=true></a></h2><p>App Manager 社区<br>邮箱: <a href=mailto:am4android@riseup.net>am4android [at] riseup\n[dot] net</a><br>GitHub 账户: <a href=https://github.com/AMCommunity class=uri>https://github.com/AMCommunity</a><br>Twitter/X 账户: <a href=https://x.com/AppManagerNews class=uri>https://x.com/AppManagerNews</a><br>Mastodon 账户: <a href=https://floss.social/@appmanager>@appmanager@floss.social</a><br><br>Muntashir Al-Islam<a href=#fn3 class=footnote-ref id=fnref3 role=doc-noteref><sup>3</sup></a><br>邮箱: <a href=mailto:muntashirakon@riseup.net>muntashirakon [at]\nriseup [dot] net</a><br>密钥指纹: <code>7bad37c2981e41f8f6abea7f58f0b4f26c346fce</code><br>GitHub 账户: <a href=https://github.com/MuntashirAkon class=uri>https://github.com/MuntashirAkon</a><br>Twitter 账户: <a href=https://twitter.com/Muntashir class=uri>https://twitter.com/Muntashir</a></section></section><section id=ch:pages class=level1 data-number=2><h1 data-number=2><span class=header-section-number>2</span> <a href=#toc:ch:pages>页面</a><a href=#ch:pages class=anchor aria-hidden=true></a></h1><section id=sec:main-page class=level2 data-number=2.1><h2 data-number=2.1><span class=header-section-number>2.1</span> <a href=#toc:sec:main-page>主页</a><a href=#sec:main-page class=anchor aria-hidden=true></a></h2><p>主页面列出所有已安装、已卸载和已备份的应用。\n单独点击任何已安装的应用项目可打开相应的 <a href=#sec:app-details-page>应用详情页</a>。\n对于未安装的系统应用，会显示一个对话框提示，可以用来重新安装该应用。\n使用列表选项中的 <a href=#par:main-page-sort>排序</a>\n，可以选择应用列表的排序方式，退出应用后仍会保留排序方式。\n使用列表选项中的 <a href=#par:main-page-filter>过滤</a>，可以过滤列表选项。\n筛选也可以通过搜索栏进行过滤，并支持正则表达式。<figure id=fig:main_page_entry_info_labeled><figure><object data=../images/main_page_entry_info_labeled.svg type=image/svg+xml></object></figure><figcaption>Figure 1: 主页面中的一个应用程序列表项</figcaption></figure><section id=subsec:batch-operations class=level3 data-number=2.1.1><h3 data-number=2.1.1><span class=header-section-number>2.1.1</span>\n<a href=#toc:subsec:batch-operations>批处理</a><a href=#subsec:batch-operations class=anchor aria-hidden=true></a></h3><p>批处理或者多应用处理也可以在这个页面内进行。\n多选模式可以由点击任何应用图标或长按列表中的任意一项进入。\n进入多选模式后，仅需单击列表中的任意一项便可选中，而不是打开应用程序详情页。\n该模式下，批处理操作位于页面底部的多选菜单。操作包括：<ul class=incremental><li><p>将选中应用添加到 <a href=#sec:profiles-page>配置</a><li><p><a href=#sec:backup-restore>备份、恢复或删除</a>应用程序<li><p>阻止应用中的追踪器<li><p>清除应用数据或缓存<li><p>导出App Manager中的屏蔽规则<li><p>以MarkDown，CSV，JSON或XML格式导出应用列表<li><p>启用/停用/强制停止/卸载应用程序<li><p>对应用执行运行时优化 (Android 7 及更高版本)<li><p>阻止应用的后台操作 (Android 7 及更高版本)<li><p>导出APK文件到 <code>AppManager/apks</code><li><p>设置<a href=#sec:net-policy>联网规则</a></ul><div class=\"amalert tip\"><p><strong><em>无障碍.</em></strong><p>进入多选模式后， 可以使用键盘或遥控器的左右键呼出多选菜单。</div></section><section id=subsec:main-colour-codes class=level3 data-number=2.1.2><h3 data-number=2.1.2><span class=header-section-number>2.1.2</span>\n<a href=#toc:subsec:main-colour-codes>颜色代码含义</a><a href=#subsec:main-colour-codes class=anchor aria-hidden=true></a></h3><ul class=incremental><li><p><span class=colorbox style=background-color:#ff0000b3><span style=color:#000>红色 (日间模式下)</span></span> / <span class=colorbox style=background-color:#790d0d><span style=color:#fff>深红色 (夜间模式下)</span></span>\n–已卸载的应用程序<li><p><span class=colorbox style=background-color:#ff8a80><span style=color:#000>浅红色 (日间模式下)</span></span> / <span class=colorbox style=background-color:#4f1c14bf><span style=color:#fff>暗红色 (夜间模式下)</span></span> –\n已停用的应用程序<li><p><span class=colorbox style=background-color:#09868b><span style=color:#fff>暗青色</span></span> –\n已强行停止的应用程序<li><p><span class=colorbox style=background-color:#ff0><span style=color:#000>黄色星标</span></span> – 可调试的应用程序<li><p><span style=color:#e05915>橙色 <em>日期</em></span> –\n可读取日志的应用程序<li><p><span style=color:#e05915>橙色 <em>UID</em></span> –\nUID在多个应用程序中被共享<li><p><span style=color:#e05915>橙色 <em>SDK</em></span> –\n使用明文网络通信(即 HTTP)<li><p><span style=color:#ff8017>亮橙色 <em>包名</em></span> –\n有一个或多个跟踪器的应用程序<li><p><span style=color:red>红色 <em>应用标签</em></span> –\n不允许清空数据的应用程序<li><p><span style=color:#09868b>暗青色 <em>版本</em></span> –\n未运行的应用程序<li><p><span style=color:#f0f>紫红色</span> –\n常驻应用(即一直运行的应用程序)<li><p><span style=color:red>红色 <em>备份标识</em></span> –\n已卸载的应用程序存在一个或多个备份 在App Manager中<li><p><span style=color:#e05915>橙色 <em>备份标识</em></span> –\n存在的备份已过期， 即基本备份中包含已安装应用程序的旧版本<li><p><span style=color:#09868b>暗青色 <em>备份标识</em></span> –\n存在的备份已更新，\n即基本备份中包含已安装应用程序的相同版本或更高版本</ul></section><section id=subsec:main-page-application-types class=level3 data-number=2.1.3><h3 data-number=2.1.3><span class=header-section-number>2.1.3</span>\n<a href=#toc:subsec:main-page-application-types>应用类型</a><a href=#subsec:main-page-application-types class=anchor aria-hidden=true></a></h3><p>一个应用程序可以是 <strong>用户</strong> 或 <strong>系统</strong>\n应用，同时存在以下后缀:<ul class=incremental><li><p><code>X</code> – 支持多种架构<li><p><code>0</code> – 应用程序中不存在dex文件<li><p><code>°</code> – 已暂停的应用程序<li><p><code>#</code> –\n应用程序请求系统分配一个大堆，即大运行时内存<li><p><code>?</code> – 应用程序请求虚拟机处于安全模式。</ul></section><section id=subsec:main-page-version-info class=level3 data-number=2.1.4><h3 data-number=2.1.4><span class=header-section-number>2.1.4</span>\n<a href=#toc:subsec:main-page-version-info>版本信息</a><a href=#subsec:main-page-version-info class=anchor aria-hidden=true></a></h3><p>版本名称有以下前缀:<ul class=incremental><li><p><code>_</code> –\n无硬件加速（减缓应用程序中的过渡动画或透明效果）<li><p><code>~</code> – 仅用于测试的应用程序<li><p><code>debug</code> – 可调试的应用程序</ul></section><section id=subsec:main-page-options-menu class=level3 data-number=2.1.5><h3 data-number=2.1.5><span class=header-section-number>2.1.5</span>\n<a href=#toc:subsec:main-page-options-menu>选项菜单</a><a href=#subsec:main-page-options-menu class=anchor aria-hidden=true></a></h3><p>选项菜单提供了若干个选项，以用于对列出的应用程序进行排序和过滤，\n以及转到 App Manager 内或外的不同页面。<section id=subsubsec:main-list-options class=level4 data-number=2.1.5.1><h4 data-number=2.1.5.1><span class=header-section-number>2.1.5.1</span> 列表选项<a href=#subsubsec:main-list-options class=anchor aria-hidden=true></a></h4><p><strong>列表选项</strong>\n包含了对主页面中的列表进行排序和过滤的选项。<section id=排序 class=level5 data-number=2.1.5.1.1><h5 data-number=2.1.5.1.1><span class=header-section-number>2.1.5.1.1</span> 排序<a href=#排序 class=anchor aria-hidden=true></a></h5><div id=par:main-page-sort></div><p>主页面中列出的应用程序可以按照以下方式进行排序:<ul class=incremental><li><p><strong>用户应用优先</strong> 用户应用将优先展示<li><p><strong>应用标签</strong> 根据应用标签（也称为\n<em>应用程序名称</em>）升序排序。(默认选项)<li><p><strong>包名</strong> 根据包名升序排序<li><p><strong>最后更新</strong> 根据更新时间降序排序<li><p><strong>共享 user ID</strong> 根据共享 user ID升序排序<li><p><strong>目标 SDK</strong> 根据目标SDK升序排序<li><p><strong>签名</strong> 根据签名信息升序排序<li><p><strong>已停用优先</strong> 已停用将优先展示<li><p><strong>已阻止优先</strong>\n根据已阻止的应用组件数目降序排序<li><p><strong>已备份优先</strong> 已备份将优先展示<li><p><strong>追踪器</strong> 根据追踪器数目降序排序S<li><p><strong>最后操作</strong> 根据被App\nManager操作的应用时间降序排序</ul><p>此外，还有 <em>反转</em> 选项，可以用来对列表进行反向排序。\n无论怎样的排序偏好，应用程序都会先按字母顺序排序，以防止产生任何随机排序结果。</section><section id=筛选 class=level5 data-number=2.1.5.1.2><h5 data-number=2.1.5.1.2><span class=header-section-number>2.1.5.1.2</span> 筛选<a href=#筛选 class=anchor aria-hidden=true></a></h5><div id=par:main-page-filter></div><p>主页面中列出的应用可以通过以下方式进行过滤:<ul class=incremental><li><p><strong>用户应用</strong> 仅列出用户应用程序<li><p><strong>系统应用</strong> 仅列出系统应用程序<li><p><strong>已停用应用</strong> 仅列出已停用的应用程序<li><p><strong>已停止应用</strong> 仅列出已停止运行的应用程序<li><p><strong>已安装应用</strong> 仅列出已安装的应用程序<li><p><strong>已卸载应用</strong> 仅列出已卸载的应用程序<li><p><strong>存在规则</strong>\n列出存在被一个或多个规则限制的应用程序<li><p><strong>有活动</strong> 列出存在一个或多个活动的应用程序<li><p><strong>有备份</strong> 列出存在一个或多个备份的应用程序<li><p><strong>无备份</strong> 列出不存在备份的应用程序<li><p><strong>运行中应用</strong> 列出当前正在运行的应用程序<li><p><strong>有分包</strong>\n列出存在一个或多个拆分APK的应用程序<li><p><strong>KeyStore</strong> 仅列出存在Android\n密钥库(KeyStore)的应用程序<li><p><strong>SAF</strong>\n仅列出使用存储访问框架(SAF)的应用程序<li><p><strong>SSAID</strong>\n仅列出存在可用的Settings.Secure.ANDROID_ID(即SSAID)的应用程序</ul><p>与排序不同，筛选过程中可同时应用多个筛选选项。\n比如被停用的用户应用程序可通过同时选择 <em>用户应用</em> and\n<em>已停用应用</em> 列出。\n对于需要筛选出用户应用以确保安全地执行某种操作的 <a href=#subsec:batch-operations>批处理操作</a> 而言， 这很有帮助。<div class=\"amalert warning\"><p><strong><em>状态不一致.</em></strong><p>App Manager 通过大量缓存相应的查询结果显示页面（并非实时更新）。\n所以，某些状态（比如说停用和已停止运行状态）并不总是最新的。</div></section><section id=配置文件名称 class=level5 data-number=2.1.5.1.3><h5 data-number=2.1.5.1.3><span class=header-section-number>2.1.5.1.3</span> 配置文件名称<a href=#配置文件名称 class=anchor aria-hidden=true></a></h5><p>也可以列出那些只存在于某个 <a href=#sec:profiles-page>配置文件</a>\n下的应用。 当执行某些无法通过 <a href=#sec:profiles-page>配置文件</a>\n完成的操作时（比如说卸载同配置文件下的所有应用程序)， 这会很有用。</section></section><section id=说明 class=level4 data-number=2.1.5.2><h4 data-number=2.1.5.2><span class=header-section-number>2.1.5.2</span> 说明<a href=#说明 class=anchor aria-hidden=true></a></h4><p>单击 <strong>用户手册</strong> 打开离线版本的 App Manager 用户手册。\n如果单独拆分出来的相应功能（即 <code>feat_docs</code> ）未安装,\n或系统里不存在加载手册的 WebView 也可以打开用户手册的在线版本。</section><section id=subsubsec:main:1-click-ops class=level4 data-number=2.1.5.3><h4 data-number=2.1.5.3><span class=header-section-number>2.1.5.3</span> 一键操作<a href=#subsubsec:main:1-click-ops class=anchor aria-hidden=true></a></h4><p><strong>1-Click Ops</strong>代表单击操作。 这将在新活动中打开<a href=#sec:1-click-ops-page>相应页面</a>。</section><section id=应用使用情况 class=level4 data-number=2.1.5.4><h4 data-number=2.1.5.4><span class=header-section-number>2.1.5.4</span> 应用使用情况<a href=#应用使用情况 class=anchor aria-hidden=true></a></h4><p>应用程序使用情况统计，比如说\n<em>屏幕时间</em>、<em>数据流量使用情况</em>\n(包括移动数据和无线网络)、<em>打开某应用的次数统计</em>，\n可通过单击菜单中的 <strong>应用程序使用情况</strong> 选项进行访问.。\n但是该功能需要 <em>使用情况统计信息访问</em> 权限。\n如使用情况统计信息访问功能在 <a href=#subsubsec:enable/disable-features>设置</a>中被禁用，该菜单项在设置中不会被列出。</section><section id=subsubsec:main:running-apps class=level4 data-number=2.1.5.5><h4 data-number=2.1.5.5><span class=header-section-number>2.1.5.5</span> 正在运行的应用<a href=#subsubsec:main:running-apps class=anchor aria-hidden=true></a></h4><p>该菜单项打开一个新页面，显示正在运行的应用程序或进程列表。它也会显示\n当前内存和缓存（如果可用）使用情况。如果 App Manager\n在非root或ADB访问下运行，它只会显示自身使用情况\n在近期的安卓版本。正在运行的应用或进程也可以在结果显示页面里被强行停止或杀掉。\n每个进程标识符(PID)的日志也可以在 <a href=#subsubsec:main:labs>log\nviewer</a> 里查阅。\n此外，也可以通过点击图标或长按某一项进行批量处理操作。\n通常情况下点击任意项目会打开一个显示更多详细信息的对话框。</section><section id=配置文件 class=level4 data-number=2.1.5.6><h4 data-number=2.1.5.6><span class=header-section-number>2.1.5.6</span> 配置文件<a href=#配置文件 class=anchor aria-hidden=true></a></h4><p>该菜单项会打开 <a href=#sec:profiles-page>配置文件页面</a>.\n配置文件是一种保存了频繁使用的任务的方式。\n这些配置文件也可以通过快捷方式调用。</section><section id=apk更新器 class=level4 data-number=2.1.5.7><h4 data-number=2.1.5.7><span class=header-section-number>2.1.5.7</span> APK更新器<a href=#apk更新器 class=anchor aria-hidden=true></a></h4><p>若系统中已安装<a href=https://github.com/rumboalla/apkupdater>APK\nUpdater</a> ，则可通过此菜单项直接打开.\n若系统中不存在该应用，则该选项将被隐藏.</section><section id=termux-终端模拟器 class=level4 data-number=2.1.5.8><h4 data-number=2.1.5.8><span class=header-section-number>2.1.5.8</span> Termux 终端模拟器<a href=#termux-终端模拟器 class=anchor aria-hidden=true></a></h4><p>如果系统中已安装<a href=https://github.com/termux/termux-app>Termux</a>\n，则可直接从此菜单项运行会话（或 新会话）.\n如果应用不存在，则此选项将被隐藏.</section><section id=预装应用卸载器 class=level4 data-number=2.1.5.9><h4 data-number=2.1.5.9><span class=header-section-number>2.1.5.9</span> 预装应用卸载器<a href=#预装应用卸载器 class=anchor aria-hidden=true></a></h4><p>该菜单项会打开预装应用卸载页面，列出在设备和 App Manager\n里可用的所有预装应用。 该页面也会推荐可替代的应用程序，这些预装应用以 <a href=https://github.com/MuntashirAkon/android-debloat-list>Android\nDebloat List</a> 项目为判断基准。</section><section id=subsubsec:main:labs class=level4 data-number=2.1.5.10><h4 data-number=2.1.5.10><span class=header-section-number>2.1.5.10</span> 标签<a href=#subsubsec:main:labs class=anchor aria-hidden=true></a></h4><p>该菜单项会打开一个标签页以列举所有附加功能。包括日志查看器、\n系统配置、终端、文件管理器（类似\n文件）、UI追踪器、意图拦截器，以及代码编辑器。</section><section id=设置 class=level4 data-number=2.1.5.11><h4 data-number=2.1.5.11><span class=header-section-number>2.1.5.11</span> 设置<a href=#设置 class=anchor aria-hidden=true></a></h4><p>此菜单项将打开本应用的 <a href=#sec:settings-page>设置</a>.</section></section></section><section id=sec:app-details-page class=level2 data-number=2.2><h2 data-number=2.2><span class=header-section-number>2.2</span> <a href=#toc:sec:app-details-page>应用程序详情页</a><a href=#sec:app-details-page class=anchor aria-hidden=true></a></h2><p><strong>应用详情</strong> 页面由 11\n个标签页组成。它描述了一个应用程序持有的几乎所有信息,\n包括其清单中的所有属性、<a href=#ch:app-ops>应用操作（App\nOps）</a>、签名 信息、库等等。<section id=subsec:app-details-colour-codes class=level3 data-number=2.2.1><h3 data-number=2.2.1><span class=header-section-number>2.2.1</span>\n<a href=#toc:subsec:app-details-colour-codes>颜色代码含义</a><a href=#subsec:app-details-colour-codes class=anchor aria-hidden=true></a></h3><p>本页中使用的颜色列表，以及对应的含义:<ul class=incremental><li><p><span class=colorbox style=background-color:#ff0000b3><span style=color:#000>红色 (日间模式)</span></span> / <span class=colorbox style=background-color:#790d0d><span style=color:#fff>深红色 (夜间模式)</span></span> –\n表示任何应用操作(App ops)或权限存在危险的标志(flag)，或者任何组件在 App\nManager 中被阻止， 又或者是任何需要却又不受支持的功能特性。<li><p><span class=colorbox style=background-color:#ff8a80><span style=color:#000>亮红色 (日间模式)</span></span> / <span class=colorbox style=background-color:#4f1c14bf><span style=color:#fff>暗红色 (夜间模式)</span></span> – 表示组件在 App\nManager 外被禁用，或任何不受支持的 可选功能特性。<div class=\"amalert tip\"><p><strong><em>注意.</em></strong><p>标记为禁用（停用/阻止）的组件并不意味着它被用户禁用，它也可能被系统禁用，\n或者在其清单(Android-Manifest.xml)中被标记为禁用（停用/阻止）。\n被禁用（停用/阻止）的应用程序也会被系统（和App\nManager）视为禁用（停用/阻止）。</div><li><p><span class=colorbox style=background-color:#ff8017><span style=color:#000>鲜橙色 (日间模式)</span></span> / <span class=colorbox style=background-color:#ff801780><span style=color:#fff>暗橙色 (夜间模式)</span></span> –\n表示存在跟踪器组件<li><p><span class=colorbox style=background-color:#ea80fc><span style=color:#000>紫色 (日间模式)</span></span> / <span class=colorbox style=background-color:#431c5d><span style=color:#fff>深紫色 (夜间模式)</span></span> –\n表示存在正在运行的服务。<li><p><span class=colorbox style=background-color:#1b8654><span style=color:白色>绿色</span></span> – 表示当前应用程序中的所有跟踪器\n已在 跟踪器指示器 标签页内被阻止。</ul></section><section id=subsec:app-info-tab class=level3 data-number=2.2.2><h3 data-number=2.2.2><span class=header-section-number>2.2.2</span>\n<a href=#toc:subsec:app-info-tab>应用信息</a><a href=#subsec:app-info-tab class=anchor aria-hidden=true></a></h3><p><strong>应用信息</strong> 选项卡包含关于一个应用程序的基本信息,\n许多操作可以在此标签中执行.<section id=subsubsec:app-info-general-information class=level4 data-number=2.2.2.1><h4 data-number=2.2.2.1><span class=header-section-number>2.2.2.1</span> 基本信息<a href=#subsubsec:app-info-general-information class=anchor aria-hidden=true></a></h4><p>以下的列表与“应用信息”选项卡中列出的顺序相同。<ul class=incremental><li><p><strong>应用图标</strong>:\n应用程序的图标，若该应用程序没有图标，则显示系统默认图标。\n可以轻轻点击图标，通过对比剪贴板中存储的 SHA 或 MD5 总和的方式进行 APK\n签名验证。<li><p><strong>应用标签</strong>: 应用程序的标签或名称。<li><p><strong>包名</strong>:\n应用程序包名，点击该包名可将其复制到剪切板。<li><p><strong>版本</strong>: 版本分为两部分： 第一部分称\n<em>版本名(Version Name)</em>。\n格式各不相同，但常由多个以点分隔的整数组成。 第二部分称\n<em>版本代号</em>。\n其被第一个括号括起来。版本代号是一个整数，用于区分应用程序版本\n(因为机器可能无法正确读取版本名)。简言之，新版本的应用程序具有比旧版本更高的版本代号。\n例如，如果 <code>123</code> 和 <code>125</code>\n是同一个应用程序的两个版本代号，我们可以说后者比前者更新（后者的版本代号更高）。\n当为同一版本的应用程序提供不同的 APK\n文件，并在不同平台（移动端、平板、桌面等）或架构（32/64 位、ARM 或\nIntel）上运行时，版本号可能会产生误导，因为通常应用程序提供商会为每个平台添加前缀以作区分。<li><p><strong>标签</strong>:(也称作标签云)\n标签包含应用程序最基本、最简洁、有用的信息。参阅 §<a href=#subsubsec:tags data-reference-type=ref data-reference=subsubsec:tags>2.2.2.2</a><span>标签</span>\n内的完整标签列表。<li><p><strong>水平操作面板</strong>\n一个操作面板，由可以对应用程序执行的各种操作组成，参阅 §<a href=#subsubsec:horizontal-action-panel data-reference-type=ref data-reference=subsubsec:horizontal-action-panel>2.2.2.3</a><span>水平操作面板</span>\n内的完整可用操作列表。 对于可用的其它操作列表，参阅 <a href=#subsubsec:app-info-options-menu>选项菜单</a>。<li><p><strong>路径与目录</strong>: 包含应用程序相关路径的各种信息，包括\n<em>应用目录</em> (存储 APK 文件的路径), <em>数据目录</em> (内部存储,\n设备保护区以及外部存储) 和 <em>JNI 库目录</em> (如果有). JNI (Java\nNative Interface，Java本机接口) 库用于调用通常用 C/C++\n编写的本机原生代码。使用本机原生库可以使应用程序运行得更快，或帮助应用程序使用非\nJava 语言编写的第三方库，同大多数游戏中所做的一样。\n通过单击每个目录项右侧的启动按钮，可以通过文件管理器打开目录，前提是它们提供相应的支持并被授予必要的权限。<li><p><strong>数据使用</strong>: 操作系统报告的应用程序使用的数据量。\n取决于 Android 版本，该项可能需要广泛的权限，包括 <em>使用情况访问</em>\n权限和 <em>电话</em> 权限。<li><p><strong>存储与缓存</strong>: 显示有关应用程序的大小（APK\n文件、优化文件、数据和缓存）。\n在旧设备中，还会显示外部数据、缓存、媒体和 OBB\n文件夹的大小。如果在较新的设备中未授予 <em>使用情况访问</em>\n权限，此部分将被隐藏。<li><p><strong>更多信息</strong> 显示其他信息，例如–<ul class=incremental><li><p><strong>SDK</strong> 显示与 Android SDK 相关的信息: <em>Max</em>\n表示目标SDK 而 <em>Min</em> 表示最小SDK（后者在 Android\n5及更低版本中不可用）\n如果目标SDK的值低于平台SDK的值（即当前操作系统支持的最大SDK的值），该应用程序会在兼容模式下运行。\n这意味着应用程序可能有权访问某些不可用或者被较新版本的 Android\n限制的功能， 这将导致安全和隐私问题。 SDK也被称作 <strong>API 级别 (API\nLevel)</strong>，<br><div class=seealso-inline><p><em>另见: <span><a href=https://en.wikipedia.org/wiki/Android_version_history#Overview>Android\n版本历史</a></span></em></div><li><p><strong>标志位(Flags)</strong>:\n构建应用程序时使用的应用标志，关于完整的标志列表及其作用，参阅<a href=https://developer.android.com/reference/android/content/pm/ApplicationInfo#flags>官方文档</a>。<li><p><strong>安装日期</strong>: 首次安装应用程序的日期。<li><p><strong>更新日期</strong>: 上次更新应用程序的日期。\n如果应用程序尚未更新，该项与 <em>安装日期</em> 相同。<li><p><strong>进程名</strong> 如果与包名不同的情况下，进程的名称。\n进程名在应用程序被系统启动时被设置，而通常情况下\n进程名与包名相同。<li><p><strong>安装器应用</strong> 安装该应用程序的应用程序。\n当安装该应用时，每次的安装器应用不总是会保持相同。 因为 Android\n允许对此字段设置任意值。 在 Android\n11及更高版本中，实际安装器应用会存储在系统，并可以通过点击\n项目右侧的“信息”按钮访问。即使系统并未报告安装器应用（比如说，安装器应用被卸载或隐藏），\n该字段也不会不可见。安装器应用可被系统授予额外的特殊权限\n以控制它安装的应用程序的某种行为。<li><p><strong>User ID</strong>: Android系统给应用设置的唯一用户ID.\n对于共享应用，相同的用户 ID 被分配给具有相同 <em>Shared User ID</em>\n的多个应用程序.<li><p><strong>User ID</strong> 系统设置的唯一的用户ID（User\nID，也被称作UID）并赋予应用程序。 对于共享的应用程序，多个持有相同的\n<em>Shared User ID</em> 的应用程序 会被赋予同样的用户ID。 .<li><p><strong>Shared User ID</strong>\n适用于共享同一个ID的应用程序们（它们之间的数据也是共享的）。\n共享的应用程序们必须持有同样的 <a href=#subsec:signatures-tab>签名</a>。<li><p><strong>首选ABI</strong>:\n此平台为此应用程序提供支持的架构。<li><p><strong>Zygote 预加载名称</strong>: 负责预加载应用程序代码\n和在所有使用应用 zygote 的隔离服务之间共享的数据。<li><p><strong>隐藏 API 执行策略</strong>: 从 Android 9\n开始，第三方应用程序无法通过隐藏 API 执行策略访问 Android\n框架中的许多方法和类。 存在以下选项：<ul class=incremental><li><p><em>默认</em>: 基于应用程序的类型。\n对于系统应用程序，隐藏API执行策略应该被禁用；而对于其他应用，则应该被强制执行。<li><p><em>无或已禁用</em>: 该应用可以像在 Android 9\n之前一样完全访问隐藏的 API。<li><p><em>警告</em>: 同上，只是每次应用程序访问隐藏 API\n时都会记录警告。绝大多数情况下不使用。<li><p><em>强制执行</em>:\n无论是深灰名单还是黑名单，或者两者都是的应用程序无法访问隐藏的 API。\n这是 Android 9 及更高版本中第三方应用程序的默认选项，除非该应用程序被\nOEM 或供应商列入白名单。<div class=\"amalert warning\"><p><strong><em>警告.</em></strong><p>隐藏 API 执行策略在 Android 中并没有被正确实现，\n应用程序可以绕过它。因此，不应该信任此值。</div></ul><li><p><strong>SELinux</strong>: 操作系统通过 SELinux 设置的强制访问控制\n(MAC) 策略。<li><p><strong>主活动</strong>: 应用的主要入口点。 仅在应用程序具有 <a href=#subsubsec:activities>活动</a>\n并且其中任何一个都可以从启动器中打开时显示。\n右侧也有一个启动按钮，可用于启动此活动。</ul></ul></section><section id=subsubsec:tags class=level4 data-number=2.2.2.2><h4 data-number=2.2.2.2><span class=header-section-number>2.2.2.2</span> Tags (标签)<a href=#subsubsec:tags class=anchor aria-hidden=true></a></h4><ul class=incremental><li><p><strong>跟踪器信息</strong> 应用程序里存在的跟踪器组件数量\n(比如说 <em>5个跟踪器</em>) 。 若追踪器未被阻止\n(禁用)，则标签颜色会被显示为橙色；若追踪器在 App Manager\n内被阻止，则标签颜色会被显示为暗青色。\n点击该标签以打开一个包含跟踪器组件的列表的对话框。 这些组件可以通过授予\nApp Manager 足够高的权限阻止 (禁用)或解除阻止 (启用)。<li><p><strong>应用程序类别</strong> 用户应用程序或者系统应用程序。\n对于系统应用程序，会显示该应用程序是否被更新，\n或者该系统应用程序是否通过 Magisk 以 systemless (不直接修改系统的)\n方式安装。<li><p><strong>拆分 APK 信息</strong> 排除基础 APK 的前提下，一个 APK\n的拆分数量 (比如 <em>5个拆分</em>).\n点击该标签以打开一个包含若干附加信息（比如说名称、类型和大小）的对话框。<li><p><strong>可调试</strong> 该应用程序可以通过 ADB(Android Debug\nBridge，Android 调试桥) 进行调试。\n可调试的应用程序可以使用某些不会提供给普通应用程序的功能。\n应用程序的数据可能会通过ADB (比如使用 <code>run-as</code> 命令)\n访问而无需额外的权限。<li><p><strong>仅用于测试</strong>\n该应用程序是仅用于测试用途的应用程序。\n仅用于测试的应用程序可以使用某些不会提供给普通应用程序的功能。\n应用程序的数据可能会通过ADB (比如使用 <code>run-as</code> 命令)\n访问而无需额外的权限。<li><p><strong>无代码</strong>\n该应用程序并没有任何代码（即DEX文件不存在）。\n对于某些系统应用程序，其实际代码可能被存放于别的地方。<li><p><strong>大堆内存 (Large heap)</strong>\n应用程序请求大堆内存占用（即在动态分配中请求更多的 RAM 内存占用）\n这仍然取决于系统，由系统决定是否给该应用程序分配较大的内存。 例如 App\nManager 会请求大堆内存占用，因为当扫描 APK时， 它需要加载整个 APK\n到内存中。<li><p><strong>打开链接</strong>\n该应用程序可能通过任意的应用程序打开某种链接。\n若该应用程序默认情况下能打开任何链接，则标签颜色会被显示为红色，否则会被显示为暗青色。\n点击该标签以打开一个包含受支持的hosts或域名的列表的对话框。 在 Android\n12 及更高版本，当授予 App Manager 足够高的权限时，\n会显示一个选项以启用或禁用打开默认链接。\n否则，会显示一个选项以打开该应用程序的系统设置页面。<li><p><strong>正在运行</strong>\n应用程序中的一个或多个服务当前正在后台运行。\n点击该标签以打开一个包含正在运行的服务列表的对话框。\n当日志浏览器功能被启用时，点击任意服务会打开日志浏览器，\n该日志浏览器会启用默认的筛选器合集，筛选出与UID关联的服务（若运行于独立进程或隔离进程，\n则服务关联的UID可能与应用程序自身的UID不同）\n除此以外还会提供一个选项以强行停止该应用程序。<li><p><strong>已停止</strong>\n已经被强行停止的应用程序。若该应用程序稍后自动运行，则可能不会被停止。<li><p><strong>已禁用</strong> 表示该应用程序已经被禁用\n(启动器里该应用程序的图标被隐藏)。<li><p><strong>已暂停</strong> 表示该应用程序已经被暂停\n(启动器里该应用程序的图标变成灰色)。<li><p><strong>已隐藏</strong> 表示该应用程序已经被隐藏\n(启动器里该应用程序的图标被隐藏)。<li><p><strong>MagiskHide</strong> 对该应用程序启用了 MagiskHide。\n点击该标签以打开一个包含该应用程序所有进程名的列表的对话框，\n该对话框内的进程列表可以被添加到 MagiskHide 或从 MagiskHide\n中移除。<li><p><strong>Magisk 排除列表</strong> 该应用程序在 Magisk\n的排除列表中。\n点击该标签以打开一个包含该应用程序所有进程名的列表的对话框，\n该对话框内的进程列表可以被添加到 Magisk 的排除列表或从 Magisk\n的排除列表中移除。<li><p><strong>WX</strong> 应用程序违反了“W^X 策略”（Write xor\nExecute，写异或执行），\n允许应用程序在同一目录或内存的同一部分中写入和执行。\n而这将允许执行任意可执行代码，\n无论是修改可执行代码并将其嵌入到应用程序中， 还是执行从 Internet\n下载的可执行代码。<br><div class=seealso-inline><p><em>另见: <span><a href=https://en.wikipedia.org/wiki/W%5EX>W^X in\nWikipedia</a></span></em></div><li><p><strong>Bloatware</strong>\n该应用程序可能是已知的预装软件（Bloatware）。\n它们预装在用户的设备上并占用大量的空间，哪怕用户并不需要它们。\n点击该标签以打开一个包含详细信息和额外建议（若可用）的对话框。<li><p><strong>密钥库</strong> 该应用程序有条目存储在 Android 密钥库\n中。\n点击该标签以打开一个包含所有属于该应用程序的密钥（KeyStore）文件的列表的对话框。<li><p><strong>已备份</strong> 该应用程序使用 App Manager\n进行过至少一次备份。 点击该标签以打开一个包含所有可用备份和 metadata\n的对话框。<li><p><strong>无电池优化</strong> 该应用程序的电池优化被禁用。\n通过点击该标签，可以尝试重新启用该应用程序的电池优化。<li><p><strong>传感器已禁用</strong> 该应用程序的传感器已被禁用。\n对绝大多数应用程序而言，传感器默认情况下是被禁用的。<li><p><a href=#sec:net-policy><strong>网络策略</strong></a>\n对该应用程序配置了网络策略 (例如后台数据流量使用)\n点击该标签以打开一个包含受支持的策略的对话框。\n这些策略视平台而定，并存在附加选项以配置它们。<li><p><a href=#sec:terminologies><strong>SSAID</strong></a>\n点击该标签以打开一个包含 当前被分配给该应用程序的 SSAID\n(Settings.Secure.ANDROID_ID)\n的对话框。SSAID可按需重置或重新生成。<li><p><strong>SAF</strong> 表示该应用程序已通过存储访问框架（Storage\nAccess Framework，即SAF）\n被授予访问一个或多个存储位置或文件（即URIs）权限。\n点击该标签以打开一个包含已授权的URIs的列表的对话框。<li><p><strong>Play 应用签名</strong>\n表示该应用程序可能由谷歌进行签名。<li><p><strong>Xposed</strong> 表示该应用程序可能是一个Xposed模块。\n点击该标签以打开一个包含附加信息的对话框。<li><p><strong>静态共享库</strong>\n表示该应用程序充当一个或多个应用程序的静态共享库。\n点击该标签以打开一个包含已安装库的版本的列表的对话框，\n并提供附加选项以卸载它们。<div class=\"amalert tip\"><p><strong><em>注意.</em></strong><p>Trichrome 库 (由Google Chrome，Vanadium或类似的项目提供)\n是目前已知的唯一一个 Android 静态共享库。</div></ul></section><section id=subsubsec:horizontal-action-panel class=level4 data-number=2.2.2.3><h4 data-number=2.2.2.3><span class=header-section-number>2.2.2.3</span> 水平操作面板<a href=#subsubsec:horizontal-action-panel class=anchor aria-hidden=true></a></h4><p>如上节所述，水平滚动操作面板由各种与应用程序相关的操作组成，比如\n–<ul class=incremental><li><p><strong>启动</strong>: 启动该应用程序。\n前提是要有一个可启动（打开）的 <a href=#subsubsec:activities>活动</a>。<li><p><strong>冻结</strong>: 冻结/禁用该应用程序。\n若应用程序已被冻结/禁用或用户没有足够的权限，则不会显示该按钮。\n冻结/禁用该应用程序后，其图标可能会从（启动器的）应用抽屉中被隐藏，这取决于其配置，该应用程序创建的快捷方式也可能被删除。\n该应用程序可能只能通过 App Manager 、<code>pm</code>\n命令或其他任意提供此功能的工具解冻/重新启用。\n长按该按钮以打开一个可创建用于快速冻结/禁用或解冻/重新启用该应用程序的快捷方式的对话框。<li><p><strong>卸载</strong> 根据提示卸载该应用程序。\n在对话框提示中可以卸载系统应用程序的更新， 或者当 App Manager\n被授予足够高的权限，抑或操作系统支持，\n也可以选择仅卸载应用程序而不清除其数据和签名。\n对于后者，如果再度安装该应用程序，安装的应用程序必须与之前已安装的应用程序的签名匹配。<div class=\"amalert tip\"><p><strong><em>提示.</em></strong><p>对于重新安装具有不同签名的应用程序， 更好的方法是使用 App Manager\n备份该应用程序的数据，然后在安装该应用程序后再还原数据，\n而不是在卸载该应用程序的过程中选择保留该应用程序的数据和签名，\n因为该操作在将来可能会导致未定义的行为的问题。</div><li><p><strong>解冻</strong> 解除冻结/重新启用该应用程序。\n若应用程序已被解冻/启用或用户没有足够的权限，则不会显示该按钮。 与\n<em>冻结</em>\n按钮类似，长按该按钮以打开一个可创建用于快速冻结/禁用或解冻/重新启用该应用程序的快捷方式的对话框。<li><p><strong>强行停止</strong>: 强行停止该应用程序。<li><p><strong>清除数据</strong>:\n清除应用程序的数据，清除包括存储在应用内部和（仅 Android 10\n以上）外部目录中的任何应用数据，包括帐户（如果由应用设置）、缓存等。\n例如，清除 App Manager 的数据将会删除所有保存在 App Manager\n内的规则（但不会清除或重置在 App Manager\n内设置的已阻止组件的状态），因此你需要随时备份你在 App Manager\n内设置的规则。若用户没有足够的权限，则不会显示该按钮。<li><p><strong>清除缓存</strong>:\n清除应用程序的缓存。若该应用程序在操作过程中处于正在运行的状态，则缓存可能无法如预期般被清除。<li><p><strong>安装</strong>:\n安装该应用程序。此按钮仅在该应用程序尚未安装时显示。<li><p><strong>新版变化 (What’s New)</strong>:\n若当前已安装的是该外部应用程序的旧版本，则会显示该按钮。\n点击该按钮以打开一个包含该版本和已安装版本在版本控制行为上的变化（差异）对比的对话框。\n变化包括：<em>版本</em>，<em>跟踪器</em>, <em>权限</em>, <em>组件</em>,\n<em>签名</em> (当校验值改变时显示)， <em>功能特性</em>, <em>共享库</em>\n与 <em>SDK</em>。<li><p><strong>更新</strong>:\n若该应用程序的版本代号高于已安装的应用程序，则会显示该按钮。<li><p><strong>重装</strong>:\n若该应用程序与已安装的应用程序具有相同的版本代号，则会显示该按钮。<li><p><strong>降级</strong>:\n若该应用程序的版本代号低于已安装的应用程序，则会显示该按钮。<li><p><strong>应用清单(Manifest)</strong>:\n点击该按钮以在单独的页面中显示该应用程序的清单文件。\n若该应用程序存在一个或多个拆分，则会显示拆分的 APK 文件列表。\n点击其中任意一项以打开相应的清单文件。<li><p><strong>扫描器</strong>: 扫描该应用程序以列出潜在的跟踪器和库。\n若已配置并处于可用状态，它还会使用VirusTotal扫描文件，并从Pithus中获得结果，<br><div class=seealso-inline><p><em>另见: <span><a href=#sec:scanner-page>扫描器页面</a></span></em></div><p>。<li><p><strong>共享首选项</strong>:\n显示该应用程序使用的共享首选项(Shared-Preferences)列表。\n点击列表中的首选项将打开<a href=#sec:shared-preferences-editor-page>共享首选项编辑器</a>。该按钮仅在用户拥有足够的权限时才会显示。<li><p><strong>数据库</strong>: 显示该应用程序使用的数据库列表。\n点击其中任意一项将打开可用于打开数据库的活动列表。\n该按钮仅在用户拥有足够的权限时才会显示。<li><p><strong>F-Droid</strong>: 在你常用的<em>F-Droid</em>\n客户端中打开该应用程序。<li><p><strong>Store</strong>: 在 <em>Aurora\nStore</em>打开该应用程序。该按钮仅在已安装 <em>Aurora Store</em>\n时显示。</ul></section><section id=subsubsec:app-info-options-menu class=level4 data-number=2.2.2.4><h4 data-number=2.2.2.4><span class=header-section-number>2.2.2.4</span> 选项菜单<a href=#subsubsec:app-info-options-menu class=anchor aria-hidden=true></a></h4><p>选项菜单位于页面的右上角, 下面给出了对现有选项的完整描述:<ul class=incremental><li><p><strong>分享</strong>: 分享按钮可用于分享 APK 或\n(如果该应用程序有多个拆分、OBB 文件或任意依赖项) 提取自应用程序的\n<em>APKS</em>。<li><p><strong>刷新</strong>: 刷新应用信息选项卡。<li><p><strong>在设置中查看</strong>: 在 Android\n设置中打开该应用程序。<li><p><strong>备份/恢复</strong>: 打开备份/恢复对话框。<li><p><strong>导出屏蔽规则</strong>: 导出在 App Manager\n中为该应用配置的规则。<li><p><strong>在 Termux 中打开</strong>: 在 Termux 中打开应用。\n实际是在表明 <code>user_id</code> 应用程序的内核用户ID的前提下运行\n<code>su - user_id</code> 命令 (参阅 §§<a href=#subsubsec:app-info-general-information data-reference-type=ref data-reference=subsubsec:app-info-general-information>2.2.2.1</a>\n中的描述)。该选项仅对 Root 用户显示。 请参阅 §§<a href=#subsubsec:config-termux data-reference-type=ref data-reference=subsubsec:config-termux>2.2.2.5</a> 以了解如何配置\nTermux 以运行来自第三方应用的命令。<li><p><strong>在 Termux 中运行</strong>: 在Termux中通过\n<code>run-as package_name</code> 打开应用。\n此选项仅对可调试应用有效，并同时适用于 Root 与 ADB 用户。 请参阅 §§<a href=#subsubsec:config-termux data-reference-type=ref data-reference=subsubsec:config-termux>2.2.2.5</a> 以了解如何配置\nTermux 以运行来自第三方应用的命令。<li><p><strong>MagiskHide</strong>:\n打开一个包含该应用程序所有进程名的列表的对话框，这些进程可以添加到\nMagiskHide 列表或从MagiskHide 列表中移除。<li><p><strong>Magisk 排除列表(DenyList)</strong>:\n打开一个包含该应用程序所有进程名的列表的对话框，这些进程可以添加到\nMagisk 排除列表或从Magisk 排除列表中移除。<li><p><strong>电池优化</strong>:\n为该应用程序启用/禁用电池优化。<li><p><strong>传感器</strong> 为该应用程序启用/禁用传感器。<li><p><a href=#sec:net-policy><strong>联网策略</strong></a>:\n为该应用程序配置联网策略（如后台数据使用）。<li><p><strong>导出图标</strong>:\n提取应用图标并将其保存至共享存储。<li><p><strong>添加到配置文件</strong>: 将应用程序添加到已配置的 <a href=#sec:profile-page>配置文件</a>。<li><p><strong>安装到……</strong>\n将该应用程序安装到其他用户和/或已配置文件（如果有）。</ul></section><section id=subsubsec:config-termux class=level4 data-number=2.2.2.5><h4 data-number=2.2.2.5><span class=header-section-number>2.2.2.5</span> 配置 Termux<a href=#subsubsec:config-termux class=anchor aria-hidden=true></a></h4><p>默认情况下，Termux\n不允许运行来自第三方应用的命令。要使用此选项，请使用 Termux v0.96\n以上版本，并且必须在 <code>~/.termux/termux.properties</code> 中添加\n<code>allow-external-apps=true</code>。<div class=\"amalert tip\"><p><strong><em>Info.</em></strong><p>启用此选项不会削弱Termux的安全性。\n第三方应用仍然需要取得用户允许才能在Termux中运行任意命令。</div></section></section><section id=subsec:component-tabs class=level3 data-number=2.2.3><h3 data-number=2.2.3><span class=header-section-number>2.2.3</span>\n<a href=#toc:subsec:component-tabs>组件选项卡</a><a href=#subsec:component-tabs class=anchor aria-hidden=true></a></h3><p><strong>活动(Activities)</strong>、<strong>服务(Services)</strong>、<strong>接收器</strong>\n(即广播接收器) 和 <strong>提供者</strong> (例如内容提供者)\n统称为应用程序组件， 因为它们提供类似的功能并共享类似的属性，\n例如它们都有一个 <em>名称</em>、 <em>标签</em>、 <em>图标</em>、\n可被启用或禁用、并且通过 <em>意图(Intent)</em> 执行。\n应用程序组件是应用的组成部分， 必须在应用程序清单中声明\n(也有一些例外情况)。 应用程序清单是存储应用程序特定元数据的文件，Android\n通过读取元数据来处理应用。<p>这些选项卡中使用的颜色在 §<a href=#subsec:app-details-colour-codes data-reference-type=ref data-reference=subsec:app-details-colour-codes>2.2.1</a><span>应用详情颜色代码</span>\n中进行了解释。 也可以通过位于三点菜单的 <strong>排序</strong>\n选项，对组件列表进行排序，\n以在列表顶部显示已阻止组件或者跟踪器组件。<section id=subsubsec:activities class=level4 data-number=2.2.3.1><h4 data-number=2.2.3.1><span class=header-section-number>2.2.3.1</span> 活动 (Activity)<a href=#subsubsec:activities class=anchor aria-hidden=true></a></h4><p><strong>活动 (Activity)</strong> 是可被 Android\n系统唯一标识的窗口或页面 (如<em>主页</em> 和 <em>应用详情页</em>\n是两个活动)。 每个活动可以有多个 UI 组件，称为 <em>部件(widgets)</em> 或\n<em>碎片(fragments)</em>， 每个组件都可以嵌套或放置在彼此之上。\n开发者还可以选择使用名为<em>意图过滤器(intent filters)</em> 的方法在活动\n(Activity)中打开外部文件、链接等。 例如，当你使用文件管理器打开文件时，\n文件管理器或操作系统通过应用包管理器 (PackageManager) 扫描意图过滤器\n以查找能够打开文件的活动，并列出它们，你可以选择打开该文件的方式\n(活动)。<p>标记为 <em>exportable (可导出)</em>\n的活动通常可被任意第三方应用程序打开。\n然而，有些活动可能需要权限，只有拥有这些权限的应用程序才能打开这些活动。\n在 <em>活动</em> 选项卡中，可通过 <strong>启动</strong>\n按钮启动某些活动。 若有必要可提供诸如意图 (Intent)的附加功能\n(extras)、数据 (data)或 Action (动作)等额外信息 (参数)， 则可通过长按\n<strong>启动</strong> 按钮以打开提供该功能的 <a href=#sec:interceptor-page>活动拦截器</a> 页面。<div class=\"amalert tip\"><p><strong><em>提示.</em></strong><p>无 Root 用户可通过 ADB 授予\n<code>android.permission.WRITE_SECURE_SETTINGS</code> 权限 以打开\n<em>不可导出的</em> 活动。</div><div class=\"amalert tip\"><p><strong><em>注意.</em></strong><p>若启动活动时抛出错误 (异常)，很可能是它具有某些未满足的依赖项目\n(例如无法通过启动按钮打开 App Manager 的 <em>应用详情页</em> ，\n因为该活动需要提供一个包名 (在缺少包名的情况下打开 App Manager\n的应用详情页没有意义)。\n由于无法有章法的推断这些依赖关系，默认情况下可能无法通过 App Manager\n打开这些活动。</div><p>也可通过 <strong>创建快捷方式</strong> 按钮创建活动的快捷方式。\n如果你需要提供额外信息 (参数)，\n那么可通过活动拦截器页面创建快捷方式。<div class=\"amalert danger\"><p><strong><em>警告.</em></strong><p>如果你卸载了 App Manager，那么所有由 App Manager\n创建的快捷方式都将被移除。</div></section><section id=subsubsec:details:servcies class=level4 data-number=2.2.3.2><h4 data-number=2.2.3.2><span class=header-section-number>2.2.3.2</span> 服务 (Services)<a href=#subsubsec:details:servcies class=anchor aria-hidden=true></a></h4><p>不同于用户能看见的 <a href=#subsubsec:activities>活动</a>，<strong>服务</strong>\n处理后台任务。 比如当你正在使用手机 Internet 浏览器从 Internet\n下载视频时， 该Internet 浏览器会使用 <em>前台服务</em> 下载内容。<p>当一个活动被关闭或从 <em>最近任务</em>\n页面被移除，它可能会被立刻销毁。\n这取决于手机可用的内存、电池统计或者该活动的配置情况。\n但是如果你想，服务可以一直运行下去。\n如果有多个在后台运行的服务，由于内存减少或者处理能力下降，\n手机会变得很卡很慢， 与此同时手机电量会被消耗得更快。较新版本的 Android\n推出了电池优化功能，并对所有应用默认开启。\n当该功能被启用时，系统能够根据系统拥有的资源量或服务请求，随机终止任意服务。\n但是，前台服务（即发送固定通知的服务，比如说音乐播放器、下载器）在通常情况下不会被终止，\n除非系统资源（内存，电量等）严重不足。\n某些原厂系统能提供更为强势激进的优化， 比如说MIUI\n有一个非常有名又强势的优化功能，即 <em>MIUI 优化</em>。<p>活动和服务都运行在同一套 <a href=https://stackoverflow.com/questions/7597742>looper</a>\n，称之为主looper，\n意味着服务并非真正在后台运行，而是需要开发者确认的任务。\n至于应用程序是如何通过服务进行交流的？ 是通过 <a href=#subsubsec:app-details-receivers>广播接收器</a> 或者 Binder\n进行通信的。</section><section id=subsubsec:app-details-receivers class=level4 data-number=2.2.3.3><h4 data-number=2.2.3.3><span class=header-section-number>2.2.3.3</span> (广播)接收器\n((Broadcast)Receiver)<a href=#subsubsec:app-details-receivers class=anchor aria-hidden=true></a></h4><p><strong>接收器</strong> (也被称作 <em>广播接收器</em>)\n可以用于在某些事件发生时触发某些任务的执行。\n由于这些组件在接收到广播信息时被执行，故被称作广播接收器。\n这些广播消息通过名为 <em>意图 (Intent)</em> 的方法发送。 意图 (Intent)\n是 Android\n的特殊功能，可用于打开应用程序（即活动）、运行服务和发送广播消息。\n因此，像 <a href=#subsubsec:activities>活动</a>和广播接收器会使用\n<em>意图过滤器</em> 接收需要的广播消息。\n广播消息可以被系统或应用程序自身发送。当广播消息被发送时，\n相应的接收器会被系统激活，这样它们就能执行任务。\n举个例子，如果你的手机资源不足，在你启用数据流量或连接至Wi-Fi时，\n手机可能会有片刻无响应或变得很卡。\n这是因为一旦数据连接被启用，可以接收<code>android.net.conn.CONNECTIVITY_CHANGE</code>的广播接收器将被系统激活。\n由于很多应用程序通常情况下都会使用该意图过滤器，这些应用几乎都会立刻被系统激活，这就导致了手机的无响应或卡顿。<p>接收器也可被用于 IPC (Inter-Process Communication，进程间通信)，即\n用于多个应用程序间交流（通信），甚至用于同一应用程序下不同组件的通信。</section><section id=subsubsec:providers class=level4 data-number=2.2.3.4><h4 data-number=2.2.3.4><span class=header-section-number>2.2.3.4</span> (内容)提供者\n((Content)Providers)<a href=#subsubsec:providers class=anchor aria-hidden=true></a></h4><p><strong>提供者</strong>主要用于数据管理。 比如，当你使用 App Manager\n保存 APK 文件或导出规则时会使用名为 <code>.fm.FmProvider</code>\n的内容提供者以保存 APK 或导出规则。 Android\n中存在很多的提供者，包括这个由系统提供的\n可被用于管理多个内容相关的任务，比如说数据库管理、跟踪、搜索等。\n每个提供者有一个名为 <em>Authority (授权)</em> 的字段， 该字段对于整个\nAndroid 生态系统中的应用程序来说是唯一的，就像包名一样。</section><section id=针对已root的手机的额外功能 class=level4 data-number=2.2.3.5><h4 data-number=2.2.3.5><span class=header-section-number>2.2.3.5</span>\n针对已root的手机的额外功能<a href=#针对已root的手机的额外功能 class=anchor aria-hidden=true></a></h4><p>与在这些标签面前只能当个看客的无 Root 用户不同，Root\n用户可以执行各种操作。<section id=拦截组件 class=level5 data-number=2.2.3.5.1><h5 data-number=2.2.3.5.1><span class=header-section-number>2.2.3.5.1</span> 拦截组件。<a href=#拦截组件 class=anchor aria-hidden=true></a></h5><p>在每个组件项目的最右侧，都有一个开关，可用于切换该组件的阻止状态。 若\n<a href=#subsubsec:instant-component-blocking>即时组件阻止</a> 未启用\n或者之前从未对此应用程序应用阻止规则， 则需要通过三点菜单中的\n<strong>应用规则</strong> 选项应用这些更改。 也可通过同样的选项\n(这次会显示为 <strong>移除规则</strong> )移除已经应用的规则。<p>也可长按按钮，以阻止使用一个或多个方法的组件。<div class=seealso-inline><p><em>另见: <span><a href=#sec:faq:app-components>FAQ:\n应用组件</a></span></em></div></section><section id=par:appdetails:blocking-trackers class=level5 data-number=2.2.3.5.2><h5 data-number=2.2.3.5.2><span class=header-section-number>2.2.3.5.2</span> 拦截跟踪器。<a href=#par:appdetails:blocking-trackers class=anchor aria-hidden=true></a></h5><p>可通过使用三点菜单中的 <strong>阻止跟踪器</strong>\n选项，对跟踪器组件进行阻止。\n无论当前你在哪个标签页中，所有的跟踪器组件都会被阻止。<div class=\"amalert tip\"><p><strong><em>Info.</em></strong><p>跟踪器组件是应用组件的一个子集。\n因此，阻止跟踪器组件与阻止其他任意组件使用的方法相同。</div><div class=seealso><p><em>另见:</em><ul class=incremental><li><p><a href=#subsec:tracker-classes-versus-tracker-components>FAQ:\n跟踪器类与跟踪器组件</a><li><p><a href=#sec:scanner-page>扫描器页面</a><li><p><a href=#subsec:block-unblock-trackers>一键操作页面：阻止/解除阻止跟踪器</a></ul></div></section></section></section><section id=subsec:permission-tabs class=level3 data-number=2.2.4><h3 data-number=2.2.4><span class=header-section-number>2.2.4</span>\n<a href=#toc:subsec:permission-tabs>权限选项卡</a><a href=#subsec:permission-tabs class=anchor aria-hidden=true></a></h3><p><strong>App Ops</strong>, <strong>使用权限</strong> and\n<strong>权限</strong> 选项卡与权限相关。 安卓中，在不具有相同身份（称为\n<em>shared\nID</em>）的应用或进程之间进行通信常常需要权限，其由权限控制器管理。\n一些被视为<em>普通</em>\n的权限，若它们出现在应用程序清单中，则会自动授予，但<em>危险</em>权限 和\n<em>开发</em> 权限需要用户确认。 选项卡中使用的颜色在 §<a href=#subsec:app-details-color-codes data-reference-type=ref data-reference=subsec:app-details-color-codes>[subsec:app-details-color-codes]</a>\n中有解释。<section id=subsubsec:app-ops class=level4 data-number=2.2.4.1><h4 data-number=2.2.4.1><span class=header-section-number>2.2.4.1</span> App Ops<a href=#subsubsec:app-ops class=anchor aria-hidden=true></a></h4><p><strong>App Ops</strong> 代表\"应用操作 <strong>(Application\nOperations)</strong> \"。 自 Android 4.3 起，Android 通过使用 <em>App\nOps</em> 控制诸多系统权限， 每个 App Op\n都有一个与之关联的唯一编号，该编号与其私有名称一同显示在“App\nOps”选项卡中， 一些 App Ops 也有一个公共名称。 许多 App Ops 与\n<em>权限</em> 相关。 在此选项卡中，若 App Ops 相关的权限被视为危险，则该\nApp Ops 会被标记为危险。 其他信息如 <em>标志位 (flags)</em> 、\n<em>权限名称</em> 、 <em>权限描述</em> 、 <em>包名</em> 、 <em>群组</em>\n也取自相关的 <a href=#subsubsec:permissions>权限</a>。\n其他信息可能包含以下内容：<ul class=incremental><li><p><strong>模式(Mode)</strong>：描述了当前授权状态，可以是“<em>允许\n(allow)</em>”、“<em>拒绝 (deny)</em>” (实际为错误)、 “<em>忽略\n(ignore)</em>” (实际为拒绝) 、 “<em>默认 (default)</em>” (从手机供应商或\nAOSP 内部设置的默认列表推断) 、 “<em>前台 (foreground)</em>” (在较新的\nAndroid 版本中，应用只能在前台运行时才能使用该 App Op) ，\n以及一些由供应商设定的模式 (例如 MIUI 使用 <em>询问\n(ask)</em>)。<li><p><strong>时长 (Duration)</strong>：该 App Op 现已使用的时间\n(可能为负，原因未知)。<li><p><strong>允许时刻 (Accept Time)</strong>: 上一次该 App Op\n被允许的时刻。<li><p><strong>拒绝时刻 (Reject Time)</strong>: 上一次该 App Op\n被拒绝的时刻。</ul><div class=\"amalert tip\"><p><strong><em>提示.</em></strong><p>若 <code>android.permission.GET_APP_OPS_STATS</code> 由\nADB授予，则该选项卡的内容对非 Root 用户可见。</div><p>每个 App Op 项都有切换按钮，可用于允许或拒绝 (忽略) 该App Op。\n其他受支持的模式也可以通过长按切换按钮进行设置。 若选项卡中未列出所需的\nApp Op，则可使用菜单中的 <strong>设置自定义 App Op</strong>。\n菜单中的<strong>重置为默认</strong> 选项可用于重置对 App Ops 的更改，\n或使用菜单中相关选项拒绝所有危险的 App Ops。 受限于 App Ops\n的工作方式，系统可能需要一段时间应用它们 (让这些更改生效)。<div class=\"amalert tip\"><p><strong><em>注意.</em></strong><p>拒绝某些 App Ops 可能会导致应用程序行为异常。\n若所有方式都失败，万不得已时可尝试使用 <em>重置为默认</em> 选项。</div><p>可以以升序方式按 App Ops 名称和其相关编号 (或值)对列表排序，\n也可通过相应的排序选项优先显示拒绝的 App Ops。<div class=seealso-inline><p><em>另见: <span><a href=#ch:app-ops>附录: App\nOps</a></span></em></div></section><section id=使用权限 class=level4 data-number=2.2.4.2><h4 data-number=2.2.4.2><span class=header-section-number>2.2.4.2</span> 使用权限<a href=#使用权限 class=anchor aria-hidden=true></a></h4><p><strong>预定义权限</strong>(<em>Uses Permissions</em>)\n是应用(申请)所使用的权限。 这些权限在应用程序清单中通过使用\n<code>uses-permission</code> 标签声明。 诸如 \"标志位\n(<em>flags</em>)\"、\"权限名 (<em>permission name</em>)\"、\"权限描述\n(<em>permission description</em>)\"、 \"包名 ( <em>package\nname</em>)\"、\"群组 (<em>group</em>)\" 此类的信息也取自其相关<a href=#subsubsec:permissions>权限</a>。<p>特权用户可通过点击每个权限右侧的切换按钮授予或撤销 危险\n(<em>dangerous</em>) 和 开发 (<em>development</em>) 权限，\n也可以使用菜单中的相应选项撤销危险权限。 因为 Android 不允许修改 普通\n(<em>normal</em>)\n权限（其中大多数是该类权限），只能撤销以上两种类别的权限。 也可尝试编辑\n<code>runtime-permissions.xml</code> 以撤销这些权限，\n但是否可行尚不明确。<div class=\"amalert tip\"><p><strong><em>提示.</em></strong><p>由于系统默认撤销危险权限，\n因此撤销所有危险权限与重置所有权限一致。</div><p>可以以升序方式按权限名称对列表进行排序，\n也可通过菜单中相应的选项优先显示拒绝的权限。</section><section id=subsubsec:permissions class=level4 data-number=2.2.4.3><h4 data-number=2.2.4.3><span class=header-section-number>2.2.4.3</span> 权限<a href=#subsubsec:permissions class=anchor aria-hidden=true></a></h4><p>(自定义)<strong>权限</strong>\n通常是应用自身定义的自定义权限，包括该应用声明的、标记为\"内部(\n<em>Internal</em>)\" 权限，其他应用声明、标记为\"外部(\n<em>External</em>)\"的权限。外部权限在应用程序组件中指定为依赖项，即应用只有在拥有指定的权限时才能调用该组件：<ul class=incremental><li><p><strong>名称</strong> 每个权限都有的唯一的名称，如\n<code>android.permission.INTERNET</code>\n，但多个应用可以请求同一个权限。<li><p><strong>图标</strong>\n每个权限都可以有一个自定义图标，其他权限选项卡没有任何图标，因为它们在应用程序清单中不包含任何图标。<li><p><strong>描述</strong>\n描述权限的可选字段，若没有与权限关联的任何描述，则不会显示该字段。<li><p><strong>标志位(Flags)</strong> 使用标志符号或\n<strong>保护名称(Protection Level)</strong> 名称描述权限， 诸如 普通\n<em>normal</em>、开发 <em>development</em>、危险\n<em>dangerous</em>,、即时 <em>instant</em>, 已授权\n<em>granted</em>、已撤销 <em>revoked</em>、签名 <em>signature</em>、特权\n<em>privileged</em> 等。<li><p><strong>包名</strong>\n表示与权限关联的包名，即定义权限的包名。<li><p><strong>群组(Group)</strong>\n与权限关联的群组（如果有），几个相关的权限通常可以组合在一起。</ul></section></section><section id=subsec:signatures-tab class=level3 data-number=2.2.5><h3 data-number=2.2.5><span class=header-section-number>2.2.5</span>\n<a href=#toc:subsec:signatures-tab>签名选项卡</a><a href=#subsec:signatures-tab class=anchor aria-hidden=true></a></h3><p><strong>签名</strong> 实际上被称作签名信息。\n一个应用程序在发布前，会被开发者用一个或多个签名密钥对该应用程序进行签名。\n一个应用程序的完整性，即该应用程序是否来自实际开发者且未被其他人改动，\n可通过使用内置在 APK 文件中的签名证书进行校验。\n这是因为当一个应用程序被未经授权的实体改动时，由于签名密钥对该实体而言是未知的，\n该应用程序就已经无法使用源签名密钥进行签名了。\n一种验证应用程序完整性的方式就是验证证书生成的检验和 (checksums)。\n若开发者提供签名证书的检验和，则它们可以 通过 <strong>签名</strong>\n标签页生成的检验和进行比较的方式校验该应用程序。 举个例子，如果你从\nGitHub 或 Telegram 频道中下载了 App Manager， 你可以通过简单匹配\n<em>SHA256</em> 检验和与显示在此标签的这一个作比较，\n以验证该应用程序是否真是由我发布：<pre><code>320c0c0fe8cef873f2b554cb88c837f1512589dcced50c5b25c43c04596760ab</code></pre><p>在此标签页中，使用了几种哈希算法以生成校验和， 包括 <em>MD5</em> 、\n<em>SHA1</em> 、 <em>SHA256</em> 和 <em>SHA512</em>。<div class=\"amalert danger\"><p><strong><em>小心.</em></strong><p>签名信息应当通过可靠的散列算法进行验证，例如 <em>SHA256</em>。\n请勿依靠 <em>MD5</em> 或 <em>SHA1</em> 校验和，因为它们可以为多个证书\n生成相同的校验和。</div></section><section id=subsec:uses-features-tab class=level3 data-number=2.2.6><h3 data-number=2.2.6><span class=header-section-number>2.2.6</span>\n<a href=#toc:subsec:uses-features-tab>使用特性选项卡</a><a href=#subsec:uses-features-tab class=anchor aria-hidden=true></a></h3><p><strong>使用功能</strong>\n该标签页列出了由该应用程序声称的功能列表，比如 OpenGL ES、电话和\nleanback。\n应用程序可能需要某些功能，而有些功能对应用程序而言则是可选的。\n所需功能必须与所需版本一起存在于系统中。\n否则，任何安装应用程序的尝试会被系统拒绝。 用于此标签的颜色在 §<a href=#subsec:app-details-colour-codes data-reference-type=ref data-reference=subsec:app-details-colour-codes>2.2.1</a>\n有详细解释。</section><section id=subsec:configurations-tab class=level3 data-number=2.2.7><h3 data-number=2.2.7><span class=header-section-number>2.2.7</span>\n<a href=#toc:subsec:configurations-tab>配置选项卡</a><a href=#subsec:configurations-tab class=anchor aria-hidden=true></a></h3><p><strong>配置</strong> 标签页列出了应用程序需要的配置， 比如输入法类型\n(qwerty、12键)，触屏方式 (手指、触摸笔等等)，以及导航方式\n(拨号盘、跟踪球、滚轮)\n对绝大多数应用程序而言，该标签页将会是空页面。</section><section id=subsec:shared-libs-tab class=level3 data-number=2.2.8><h3 data-number=2.2.8><span class=header-section-number>2.2.8</span>\n<a href=#toc:subsec:shared-libs-tab>共享库选项卡</a><a href=#subsec:shared-libs-tab class=anchor aria-hidden=true></a></h3><p><strong>共享库</strong> 该标签页列出了传统 JAR 依赖、\n任意静态共享库依赖\n(目前唯一一个已知的实例是基于Chromium的浏览器和WebViews ) 以及 JNI (Java\n本地接口) 库。对于JNI 库，有明确规定特定的平台\n(x86/x86_64/ARM/AArch64)、 架构 (32/64 bit)、对象 (共享对象或可执行代码)\n等。</section></section><section id=sec:1-click-ops-page class=level2 data-number=2.3><h2 data-number=2.3><span class=header-section-number>2.3</span> <a href=#toc:sec:1-click-ops-page>一键操作页</a><a href=#sec:1-click-ops-page class=anchor aria-hidden=true></a></h2><p>该页面在选择 <a href=#subsec:main-page-options-menu>主菜单</a> 中的\n<a href=#subsubsec:main:1-click-ops>一键操作选项</a> 时显示。<section id=subsec:block-unblock-trackers class=level3 data-number=2.3.1><h3 data-number=2.3.1><span class=header-section-number>2.3.1</span>\n<a href=#toc:subsec:block-unblock-trackers>阻止/取消阻止跟踪器</a><a href=#subsec:block-unblock-trackers class=anchor aria-hidden=true></a></h3><p>该选项可被用于阻止或解除阻止已安装应用程序的广告/跟踪器组件。\n选择此项时，App Manager\n会询问是否需要列出所有应用程序的跟踪器，或者仅列出用户应用程序的跟踪器。\n新手用户应避免阻止系统应用程序的跟踪器以避免产生不良后果。\n之后会弹出多选对话框，以将排除一个或多个应用程序从该操作中排除。 当按下\n<em>阻止</em> 或 <em>解除阻止</em> 按钮时，这些变更会立刻生效。<div class=\"amalert warning\"><p><strong><em>注意.</em></strong><p>某些应用程序在禁用它们的跟踪器以后，可能无法如预期般运行。\n若出现这种情况， 请移除所有阻止规则， 或者打开对应应用的 <a href=#sec:app-details-page>应用详情页</a>\n，将组件标签页中被阻止的规则逐个移除。</div><div class=seealso-inline><p><em>另见: <span><a href=#par:appdetails:blocking-trackers>应用详情页：阻止跟踪器</a></span></em></div></section><section id=subsec:block-components-dots class=level3 data-number=2.3.2><h3 data-number=2.3.2><span class=header-section-number>2.3.2</span>\n<a href=#toc:subsec:block-components-dots>阻止组件…</a><a href=#subsec:block-components-dots class=anchor aria-hidden=true></a></h3><p>该选项用于阻止某些应用程序的组件，而判断依据是它们的签名。\n一个组件的签名是组件的全称或部分名称。\n安全起见，推荐在每一部分的签名结尾添加 <code>.</code> (点)，\n因为底层算法以贪婪的方式搜索和匹配组件。\n也可以插入多个签名，在这种情况下，所有签名都要被空格隔开。\n类似于上面的选项，此处也会提供对系统应用程序应用阻止的选项。<div class=\"amalert danger\"><p><strong><em>小心.</em></strong><p>如果你并不知道通过签名阻止应用程序组件的后果是什么，你应当避免使用该功能。\n因为该功能使用不当可能会导致手机 bootloop\n(引导循环，具体现象就是手机不断重启并卡在开机第一屏或开机动画，但就是无法进入系统)\n或者变砖\n(除了通过特殊按键组合进入某些特殊模式外，手机保持黑屏状态)，最终你可能要执行恢复出厂设置。</div></section><section id=subsec:set-mode-for-app-ops-dots class=level3 data-number=2.3.3><h3 data-number=2.3.3><span class=header-section-number>2.3.3</span>\n<a href=#toc:subsec:set-mode-for-app-ops-dots>设置 App Ops 模式\n…</a><a href=#subsec:set-mode-for-app-ops-dots class=anchor aria-hidden=true></a></h3><p>该选项用于对所有或者已选中的应用程序配置某些 <a href=#ch:app-ops>应用操作 (App Ops)</a>。\n存在两个字段，第一个字段用于插入多个被空格隔开的应用操作常量\n(名称或值)。\n由于可用的应用操作因设备和操作系统而异，并非所有的应用操作常量都能被事先了解。.\n需要的应用操作常量可在位于 <a href=#sec:app-details-page>应用详情页</a> 中的 <em>App Ops</em>\n标签页内查阅。 第二个字段可用于插入或根据特定的应用操作选择 <a href=#subsec:mode-constants>模式</a>。<div class=\"amalert danger\"><p><strong><em>小心.</em></strong><p>除非你熟悉 App Ops (应用操作)\n和阻止它们的后果，你应该避免使用该选项。</div></section><section id=subsec:1-click-back-up class=level3 data-number=2.3.4><h3 data-number=2.3.4><span class=header-section-number>2.3.4</span>\n<a href=#toc:subsec:1-click-back-up>备份</a><a href=#subsec:1-click-back-up class=anchor aria-hidden=true></a></h3><p>一键备份操作。以防万一，在执行任何操作前会列出所有受影响的备份。<section id=备份所有应用 class=level5 data-number=2.3.4.0.1><h5 data-number=2.3.4.0.1><span class=header-section-number>2.3.4.0.1</span> 备份所有应用<a href=#备份所有应用 class=anchor aria-hidden=true></a></h5><p>备份所有的已安装的应用程序。</section><section id=重新备份现有备份 class=level5 data-number=2.3.4.0.2><h5 data-number=2.3.4.0.2><span class=header-section-number>2.3.4.0.2</span> 重新备份现有备份<a href=#重新备份现有备份 class=anchor aria-hidden=true></a></h5><p>重新备份所有已安装且之前备份过的应用程序。</section><section id=备份无备份应用 class=level5 data-number=2.3.4.0.3><h5 data-number=2.3.4.0.3><span class=header-section-number>2.3.4.0.3</span> 备份无备份应用<a href=#备份无备份应用 class=anchor aria-hidden=true></a></h5><p>备份所有已安装但尚未备份的应用程序。</section><section id=验证和重新备份 class=level5 data-number=2.3.4.0.4><h5 data-number=2.3.4.0.4><span class=header-section-number>2.3.4.0.4</span> 验证和重新备份<a href=#验证和重新备份 class=anchor aria-hidden=true></a></h5><p>验证已安装的应用程序的近期备份，并在必要时重新备份。</section><section id=备份发生变化的应用 class=level5 data-number=2.3.4.0.5><h5 data-number=2.3.4.0.5><span class=header-section-number>2.3.4.0.5</span> 备份发生变化的应用<a href=#备份发生变化的应用 class=anchor aria-hidden=true></a></h5><p>若某应用在上次备份后有所变化，则重新备份该应用。\n通过检查一系列指标判断该应用是否发生变化，包括应用程序版本、最后更新日期、最后启动日期、完整性和文件哈希值。\n目录哈希值会在备份过程中被计算并存储在数据库中。\n在执行此操作时，会计算新的哈希值，并比较存储在数据库中的该项。</section></section><section id=subsec:1-click-restore class=level3 data-number=2.3.5><h3 data-number=2.3.5><span class=header-section-number>2.3.5</span>\n<a href=#toc:subsec:1-click-restore>恢复</a><a href=#subsec:1-click-restore class=anchor aria-hidden=true></a></h3><p>一键还原。以防万一，在执行任何操作前会列出所有受影响的备份。<section id=还原所有应用 class=level5 data-number=2.3.5.0.1><h5 data-number=2.3.5.0.1><span class=header-section-number>2.3.5.0.1</span> 还原所有应用<a href=#还原所有应用 class=anchor aria-hidden=true></a></h5><p>还原 <em>基本备份</em> 中所有已备份的应用程序。</section><section id=还原未安装应用 class=level5 data-number=2.3.5.0.2><h5 data-number=2.3.5.0.2><span class=header-section-number>2.3.5.0.2</span> 还原未安装应用<a href=#还原未安装应用 class=anchor aria-hidden=true></a></h5><p>还原 <em>基本备份</em>\n中所有已备份的应用程序中尚未安装的应用程序。</section><section id=还原最新备份 class=level5 data-number=2.3.5.0.3><h5 data-number=2.3.5.0.3><span class=header-section-number>2.3.5.0.3</span> 还原最新备份<a href=#还原最新备份 class=anchor aria-hidden=true></a></h5><p>还原 <em>基本备份</em>\n中版本代号比已安装应用程序的版本代号高的应用程序。</section></section><section id=subsec:trim-caches-in-all-apps class=level3 data-number=2.3.6><h3 data-number=2.3.6><span class=header-section-number>2.3.6</span>\n<a href=#toc:subsec:trim-caches-in-all-apps>清理所有应用的缓存</a><a href=#subsec:trim-caches-in-all-apps class=anchor aria-hidden=true></a></h3><p>清除所有应用程序的缓存，包括 Android 系统。在执行此操作期间，\n所有正在运行的应用程序的缓存可能不会如预期般被清除。</section></section><section id=sec:profiles-page class=level2 data-number=2.4><h2 data-number=2.4><span class=header-section-number>2.4</span> <a href=#toc:sec:profiles-page>配置文件页面</a><a href=#sec:profiles-page class=anchor aria-hidden=true></a></h2><p>配置文件页面可通过主菜单的 <a href=#subsec:main-page-options-menu>选项菜单</a> 访问。\n页面主要展示了已配置的文件列表以及对其进行操作的常规选项。\n新配置文件也可通过位于底部右下角的 <em>加号</em> 按钮进行添加。\n配置文件可以被导入、复制或删除。 单击配置文件项目以打开其 <a href=#sec:profile-page>配置文件页面</a>。<section id=subsec:profiles-options-menu class=level3 data-number=2.4.1><h3 data-number=2.4.1><span class=header-section-number>2.4.1</span>\n<a href=#toc:subsec:profiles-options-menu>选项菜单</a><a href=#subsec:profiles-options-menu class=anchor aria-hidden=true></a></h3><p>通过 App Manager 顶部右上角的三点菜单打开全局选项菜单。\n其中有一个选项，用于导入先前从 App Manager 导出的已有配置文件。<p>长按任意配置文件项目会弹出另一个选项菜单。该选项菜单提供以下选项：<ul class=incremental><li><p><strong>立即应用….</strong> 该选项用于直接应用配置文件。\n点击时会显示一个对话框，在对话框内可选择 <a href=#subsubsec:profile-state>配置文件状态</a>。\n选择其中一个状态后，配置文件会被立即应用。<li><p><strong>删除</strong>\n点击该选项会在无警告的情况下直接移除配置文件。<li><p><strong>复制</strong> 该选项用于复制配置文件。\n点击时会显示一个对话框，在对话框内可为新的配置文件命名。\n单击“OK”后，会复制当前配置文件的所有配置信息并加载到 新的 <a href=#sec:profile-page>配置文件页面</a> 。\n尽管如此，复制的配置文件在手动保存之前都不会被保存。<li><p><strong>复制配置文件ID</strong>\n该选项用于复制配置文件的唯一配置ID。 该配置ID可用于 从第三方应用程序 <a href=#subsec:triggering-a-profile>触发配置文件</a> 。<li><p><strong>导出</strong> 导出配置文件到外部存储。\n通过该方式导出的配置文件可以通过之前提到的 <em>导入</em>\n选项导入。<li><p><strong>创建快捷方式</strong> 该选项用于\n创建该配置文件的快捷方式。 该功能提供两个选项： <em>简单</em> 和\n<em>高级</em> 。 选择 <em>高级</em>\n时，会提示用户选择快捷方式被调用时的配置文件状态。 选择 <em>简单</em>\n时，则总是使用配置文件上一次保存时设置的默认状态。</ul></section></section><section id=sec:profile-page class=level2 data-number=2.5><h2 data-number=2.5><span class=header-section-number>2.5</span> <a href=#toc:sec:profile-page>配置页</a><a href=#sec:profile-page class=anchor aria-hidden=true></a></h2><p>配置文件页面显示配置文件的配置信息。也提供相应的选项以编辑它们。<section id=subsec:profile-options-menu class=level3 data-number=2.5.1><h3 data-number=2.5.1><span class=header-section-number>2.5.1</span>\n<a href=#toc:subsec:profile-options-menu>选项菜单</a><a href=#subsec:profile-options-menu class=anchor aria-hidden=true></a></h3><p>顶部右上角的三点菜单会打开选项菜单。其中包含若干个选项，例如–<ul class=incremental><li><p><strong>应用</strong> 该选项用于直接应用配置文件。\n点击时，会显示一个可以选择 <a href=#subsubsec:profile-state>配置文件状态</a> 的对话框。\n在选择其中一个状态后，配置文件会立即生效。<div class=\"amalert tip\"><p><strong><em>注意.</em></strong><p>当你应用配置文件时，如果存在某些不符合标准的应用，它们会被直接忽略。</div><li><p><strong>保存</strong> 保存对配置文件的更改。<li><p><strong>丢弃</strong> 丢弃自上次保存后产生的全部更改。<li><p><strong>删除</strong>\n点击此选项将将在无警告的情况下直接移除配置文件。<li><p><strong>复制</strong> 该选项用于复制配置文件。\n点击时会显示一个对话框，在对话框内可为新的配置文件命名。\n单击“OK”后，会复制当前配置文件存储的配置信息 并加载到新的 <a href=#sec:profile-page>配置文件页面</a> 。\n尽管如此，复制的配置文件在手动保存之前都不会被保存。<li><p><strong>创建快捷方式</strong>\n该选项用于创建该配置文件的快捷方式。 该功能提供两个选项： <em>简单</em>\n和 <em>高级</em> 。 选择 <em>高级</em>\n进行配置时，会提示用户选择快捷方式被调用时的配置文件状态。 选择\n<em>简单</em>\n进行配置时，则总是使用上一次保存的配置文件设置的默认状态。</ul></section><section id=subsec:profile-apps-tab class=level3 data-number=2.5.2><h3 data-number=2.5.2><span class=header-section-number>2.5.2</span>\n<a href=#toc:subsec:profile-apps-tab>应用程序选项卡</a><a href=#subsec:profile-apps-tab class=anchor aria-hidden=true></a></h3><p>应用标签页会列出所有为该配置文件配置的包。\n包可以通过位于屏幕底部附近的 <em>添加</em> 按钮添加或移除。\n一个包可以通过长按该按钮的方式移除 (以防万一，会弹出一个仅显示\n<em>删除</em> 选项的对话框)。</section><section id=subsec:profile-configurations-tab class=level3 data-number=2.5.3><h3 data-number=2.5.3><span class=header-section-number>2.5.3</span>\n<a href=#toc:subsec:profile-configurations-tab>配置选项卡</a><a href=#subsec:profile-configurations-tab class=anchor aria-hidden=true></a></h3><p>配置标签可用于配置选中的包。<section id=配置文件id class=level4 data-number=2.5.3.1><h4 data-number=2.5.3.1><span class=header-section-number>2.5.3.1</span> 配置文件ID<a href=#配置文件id class=anchor aria-hidden=true></a></h4><p>该配置文件的唯一ID，目前是基于配置文件名设置。\n该配置文件ID可被第三方应用程序用于 <a href=#subsec:triggering-a-profile>触发配置文件</a> 。</section><section id=备注 class=level4 data-number=2.5.3.2><h4 data-number=2.5.3.2><span class=header-section-number>2.5.3.2</span> 备注<a href=#备注 class=anchor aria-hidden=true></a></h4><p>这是会显示在 <a href=#sec:profiles-page>配置文件页面</a> 的文本。\n若并未设置，则会显示当前配置信息。</section><section id=subsubsec:profile-state class=level4 data-number=2.5.3.3><h4 data-number=2.5.3.3><span class=header-section-number>2.5.3.3</span> 状态<a href=#subsubsec:profile-state class=anchor aria-hidden=true></a></h4><p>表示默认情况下某些配置文件选项的行为方式。 例如，若 <em>禁用</em>\n选项被打开，则状态为 <em>开</em> 的应用程序会被禁用，状态为 <em>关</em>\n的会被启用。 目前此项仅支持取值 <em>开</em> 和 <em>关</em> 。</section><section id=用户 class=level4 data-number=2.5.3.4><h4 data-number=2.5.3.4><span class=header-section-number>2.5.3.4</span> 用户<a href=#用户 class=anchor aria-hidden=true></a></h4><p>选择需要应用配置文件的用户。默认情况下会选择所有用户。</section><section id=组件 class=level4 data-number=2.5.3.5><h4 data-number=2.5.3.5><span class=header-section-number>2.5.3.5</span> 组件<a href=#组件 class=anchor aria-hidden=true></a></h4><p>该行为与位于一键操作页面中的 <a href=#subsec:block-components-dots>阻止组件…</a> 选项的行为相同。\n然而，此处的阻止操作仅对选中的包生效。 若 <a href=#subsubsec:profile-state>状态</a> 为\n<em>开</em>，则组件会被阻止。 若其状态为\n<em>关</em>，则组件会被解除阻止。 该选项可通过单击输入对话框中的\n<em>禁用</em> 按钮禁用 (无论被插入何值)。<div class=seealso-inline><p><em>另见: <span><a href=#subsec:faq:what-are-app-components>什么是应用组件？</a></span></em></div></section><section id=appops-权限 class=level4 data-number=2.5.3.6><h4 data-number=2.5.3.6><span class=header-section-number>2.5.3.6</span> AppOps 权限<a href=#appops-权限 class=anchor aria-hidden=true></a></h4><p>该行为与位于一键操作页面中的 <a href=#subsec:set-mode-for-app-ops-dots>设置 App Ops(应用操作)\n模式…</a> 选项的行为相同。 然而，此处的操作仅对选中的包生效。 若 <a href=#subsubsec:profile-state>状态</a> 为 <em>开</em>，则应用操作(App\nOps)会被拒绝 (即忽略)。 若其状态为 <em>关</em>，则应用操作(App\nOps)会被允许。 该选项可通过单击输入对话框中的 <em>禁用</em> 按钮禁用\n(无论被插入何值)。</section><section id=权限 class=level4 data-number=2.5.3.7><h4 data-number=2.5.3.7><span class=header-section-number>2.5.3.7</span> 权限<a href=#权限 class=anchor aria-hidden=true></a></h4><p>该选项用于对被选中的包授予或撤销某些权限。与其他选项类似，权限必须用空格隔开。\n若 <a href=#subsubsec:profile-state>状态</a> 为\n<em>开</em>，则权限会被撤销。 若其状态为 <em>关</em>，则权限会被允许。\n该选项可通过单击输入对话框中的 <em>禁用</em> 按钮禁用\n(无论被插入何值)。</section><section id=备份恢复 class=level4 data-number=2.5.3.8><h4 data-number=2.5.3.8><span class=header-section-number>2.5.3.8</span> 备份/恢复<a href=#备份恢复 class=anchor aria-hidden=true></a></h4><p>该选项用于对被选中的应用程序和其数据进行备份或还原。 提供两个选项：\n<em>备份选项</em> 和 <em>备份名称</em> 。<ul class=incremental><li><p><strong>备份选项</strong> 与备份/还原功能中的 <a href=#subsec:backup-restore-backup-options>备份选项</a> 相同。\n若没有设置，则使用默认选项。<li><p><strong>备份名称</strong>\n为备份设置自定义名称。若已经设置了备份名称，则每次备份都会沿用该名称。\n每个备份名称后都会被赋予唯一的名称作为后缀。该行为将在未来的正式版被修复。\n对于通常的“基本”备份，此区域会留空 (也请确保不要在备份选项中开启\n<em>多个备份</em> )。</ul><p>若 <a href=#subsubsec:profile-state>状态</a> 为\n<em>开</em>，则包会被备份。 若其状态为 <em>关</em>，则包会被还原。\n该选项可通过单击输入对话框中的 <em>禁用</em> 按钮禁用\n(无论被插入何值)。</section><section id=导出屏蔽规则 class=level4 data-number=2.5.3.9><h4 data-number=2.5.3.9><span class=header-section-number>2.5.3.9</span> 导出屏蔽规则<a href=#导出屏蔽规则 class=anchor aria-hidden=true></a></h4><div class=\"amalert danger\"><p><strong><em>危险.</em></strong><p>此选项尚未实现。</div></section><section id=冻结 class=level4 data-number=2.5.3.10><h4 data-number=2.5.3.10><span class=header-section-number>2.5.3.10</span> 冻结<a href=#冻结 class=anchor aria-hidden=true></a></h4><p>允许根据 <a href=#subsubsec:profile-state>状态</a>\n的值冻结或解冻选中的包。 若状态为 <em>开</em>，则包会被冻结。若状态为\n<em>关</em>，则包会被解冻。</section><section id=强制停止 class=level4 data-number=2.5.3.11><h4 data-number=2.5.3.11><span class=header-section-number>2.5.3.11</span> 强制停止<a href=#强制停止 class=anchor aria-hidden=true></a></h4><p>允许被选中的包被强行停止。</section><section id=清除缓存 class=level4 data-number=2.5.3.12><h4 data-number=2.5.3.12><span class=header-section-number>2.5.3.12</span> 清除缓存<a href=#清除缓存 class=anchor aria-hidden=true></a></h4><p>为被选中的包启用清除缓存。</section><section id=清除数据 class=level4 data-number=2.5.3.13><h4 data-number=2.5.3.13><span class=header-section-number>2.5.3.13</span> 清除数据<a href=#清除数据 class=anchor aria-hidden=true></a></h4><p>为选中的包启用清除数据。</section><section id=阻止跟踪器 class=level4 data-number=2.5.3.14><h4 data-number=2.5.3.14><span class=header-section-number>2.5.3.14</span> 阻止跟踪器<a href=#阻止跟踪器 class=anchor aria-hidden=true></a></h4><p>根据 <a href=#subsubsec:profile-state>状态</a>\n的值对选中的包的跟踪器组件启用阻止或解除阻止。 若状态为 <em>开</em>\n，则跟踪器会被阻止；若状态为 <em>关</em> ，则跟踪器会被解除阻止。</section><section id=保存apk class=level4 data-number=2.5.3.15><h4 data-number=2.5.3.15><span class=header-section-number>2.5.3.15</span> 保存APK<a href=#保存apk class=anchor aria-hidden=true></a></h4><p>对在 <code>AppManager/apks</code> (或在设置页面中被选中的目录)\n中被选中的包启用导出 APK 文件。</section></section></section><section id=sec:settings-page class=level2 data-number=2.6><h2 data-number=2.6><span class=header-section-number>2.6</span> <a href=#toc:sec:settings-page>设置页面</a><a href=#sec:settings-page class=anchor aria-hidden=true></a></h2><p>设置页面可被用于个性化 App Manager 的行为。<section id=subsec:language class=level3 data-number=2.6.1><h3 data-number=2.6.1><span class=header-section-number>2.6.1</span>\n<a href=#toc:subsec:language>界面语言</a><a href=#subsec:language class=anchor aria-hidden=true></a></h3><p>配置应用内语言。App Manager 目前支持 22 种语言。</section><section id=subsec:appearance class=level3 data-number=2.6.2><h3 data-number=2.6.2><span class=header-section-number>2.6.2</span>\n<a href=#toc:subsec:appearance>外观</a><a href=#subsec:appearance class=anchor aria-hidden=true></a></h3><section id=subsubsec:app-theme class=level4 data-number=2.6.2.1><h4 data-number=2.6.2.1><span class=header-section-number>2.6.2.1</span> 应用主题<a href=#subsubsec:app-theme class=anchor aria-hidden=true></a></h4><p>配置应用内主题。</section><section id=subsubsec:pure-black-theme class=level4 data-number=2.6.2.2><h4 data-number=2.6.2.2><span class=header-section-number>2.6.2.2</span> 纯黑色主题<a href=#subsubsec:pure-black-theme class=anchor aria-hidden=true></a></h4><p>使用纯黑色的背景，而不是Material 主题背景。</section><section id=subsubsec:layout-direction class=level4 data-number=2.6.2.3><h4 data-number=2.6.2.3><span class=header-section-number>2.6.2.3</span> 布局方向<a href=#subsubsec:layout-direction class=anchor aria-hidden=true></a></h4><p>更改布局方向，从左到右或者从右到左。\n通常情况下由选择的语言决定，但不是每个人都有相同的方向习惯。</section><section id=subsubsec:enable/disable-features class=level4 data-number=2.6.2.4><h4 data-number=2.6.2.4><span class=header-section-number>2.6.2.4</span> 启用/禁用功能<a href=#subsubsec:enable/disable-features class=anchor aria-hidden=true></a></h4><p>启用或禁用 App Manager 中的某些功能，如<ul class=incremental><li><p><strong>拦截器</strong><li><p><strong>Manifest 查看器</strong><li><p><strong>扫描器</strong><li><p><strong>包安装器</strong><li><p><strong>使用情况.</strong> 如关闭此功能，App Manager 永远不会请求\n<em>使用情况</em> 权限.<li><p><strong>日志查看器</strong><li><p><strong>App Explorer.</strong> “探索” 选项在尝试打开 APK\n文件时不可用。<li><p><strong>App info.</strong> 尝试打开 APK 文件时会显示\n“应用信息”选项<li><p><strong>代码编辑器</strong><li><p><strong>VirusTotal</strong></ul></section></section><section id=subsec:privacy class=level3 data-number=2.6.3><h3 data-number=2.6.3><span class=header-section-number>2.6.3</span>\n<a href=#toc:subsec:privacy>隐私</a><a href=#subsec:privacy class=anchor aria-hidden=true></a></h3><section id=subsubsec:screen-lock class=level4 data-number=2.6.3.1><h4 data-number=2.6.3.1><span class=header-section-number>2.6.3.1</span> 屏幕锁定<a href=#subsubsec:screen-lock class=anchor aria-hidden=true></a></h4><p>当设置了屏幕锁定时，使用 Android 屏幕锁定的设置锁定 App Manager。<div class=\"amalert warning\"><p><strong><em>警告.</em></strong><p>若启用该设置后，屏幕锁定在 Android\n中被禁用/移除，则直到再度启用屏幕锁定前 App Manager 将无法被打开。</div></section><section id=subsubsec:run-am-in-background class=level4 data-number=2.6.3.2><h4 data-number=2.6.3.2><span class=header-section-number>2.6.3.2</span> 在后台运行 App Manager<a href=#subsubsec:run-am-in-background class=anchor aria-hidden=true></a></h4><p>App Manager 在后台运行时会减少初始化延迟。 对缓解某些设备频繁断开\nADB连接的问题而言，这也很有用。</section><section id=subsubsec:use-the-internet class=level4 data-number=2.6.3.3><h4 data-number=2.6.3.3><span class=header-section-number>2.6.3.3</span> 使用网络<a href=#subsubsec:use-the-internet class=anchor aria-hidden=true></a></h4><p>在 App Manager 中激活网络功能。 目前包括在 <a href=#sec:scanner-page>扫描器页面</a>中进行扫描的 VirusTotal 和\nPithus。</section><section id=subsubsec:auth-manager class=level4 data-number=2.6.3.4><h4 data-number=2.6.3.4><span class=header-section-number>2.6.3.4</span> 授权管理器<a href=#subsubsec:auth-manager class=anchor aria-hidden=true></a></h4><p>该设置允许第三方应用程序获得某些功能的访问权限，比如说配置文件。</section></section><section id=subsec:mode-of-operation class=level3 data-number=2.6.4><h3 data-number=2.6.4><span class=header-section-number>2.6.4</span>\n<a href=#toc:subsec:mode-of-operation>操作模式</a><a href=#subsec:mode-of-operation class=anchor aria-hidden=true></a></h3><p>操作模式定义了 App Manager 整体的工作模式，其有以下选项：<ul class=incremental><li><p><strong>自动</strong> 让 App Manager 决定最佳选项。\n尽管这是默认选项，对于无 Root 用户而言应该使用 <em>无 Root</em>\n模式。<li><p><strong>Root</strong> 以 Root 模式运行 App Manager。若未检测到\nRoot 权限，App Manager 会回退至 <em>无 Root</em>\n模式。在极少数个例中，当通过 Root 发起的 Binder 通信被禁用时 (例如 <a href=https://github.com/MuntashirAkon/AppManager/issues/606>Phh\nSuperUser</a>)，App Manager 也会回退至 <em>无 Root</em> 模式。<li><p><strong>TCP 启动 ADB</strong> 通过 <a href=#sec:adb-over-tcp>TCP 启动 ADB</a> 的方式，在 ADB 模式下运行 App\nManager。 若未通过 TCP 启动 ADB ，App Manager 会回退至 <em>无 Root</em>\n模式。<li><p><strong>无线调试</strong> 通过无线调试启用 ADB\n。首先会自动尝试连接之前配置的端口，\n如失败会提示用户手动配对，或者手动连接到 ADB daemon。\n若通过该方式无法成功连接到 ADB daemon，App Manager会回退至 <em>无\nRoot</em> 模式。<div class=\"amalert tip\"><p><strong><em>信息.</em></strong><p>由于无线调试在 Android 11 才被引入，该选项仅在运行 Android 11\n及更高版本的设备上显示。</div><li><p><strong>无 Root</strong> 以无 Root 模式运行 App Manager。虽然 App\nManager 在此模式中表现更佳， 但所有 Root 或 ADB\n相关的功能会被禁用。</ul><p>也会在顶部显示实际操作模式。 实际操作模式是指\n<em>Root</em>、<em>ADB</em> 和 <em>无 Root</em> 。<div class=\"amalert tip\"><p><strong><em>注意.</em></strong><p>只有两种情况 \"远程服务“才是必需的。一是 ADB\n用户，二是使用自定义命令。</div></section><section id=subsec:apk-signing class=level3 data-number=2.6.5><h3 data-number=2.6.5><span class=header-section-number>2.6.5</span>\n<a href=#toc:subsec:apk-signing>APK 签名</a><a href=#subsec:apk-signing class=anchor aria-hidden=true></a></h3><section id=签名方案 class=level4 data-number=2.6.5.1><h4 data-number=2.6.5.1><span class=header-section-number>2.6.5.1</span> 签名方案<a href=#签名方案 class=anchor aria-hidden=true></a></h4><p>配置<a href=https://source.android.com/security/apksigning>签名方案</a>\n以用于启用 APK 签名的情况。 默认启用 v1 和 v2 签名方案，但应该也启用 v3\n以确保在 Android 9 及更高版本的安全性。</section><section id=签名密钥 class=level4 data-number=2.6.5.2><h4 data-number=2.6.5.2><span class=header-section-number>2.6.5.2</span> 签名密钥<a href=#签名密钥 class=anchor aria-hidden=true></a></h4><p>为签名 APK 文件配置签名密钥。 已存在密钥库中的密钥可以被导入到 App\nManager，或者可以生成新的密钥。<div class=\"amalert tip\"><p><strong><em>提示.</em></strong><p>如果你需要在将来使用密钥，推荐你自行创建密钥库并在此处导入密钥。\n在没有正确备份的情况下，在 App Manager 生成的密钥有被删除的风险。</div></section><section id=对齐-apk-文件 class=level4 data-number=2.6.5.3><h4 data-number=2.6.5.3><span class=header-section-number>2.6.5.3</span> 对齐 APK 文件<a href=#对齐-apk-文件 class=anchor aria-hidden=true></a></h4><p>在 App Manager 对一个 APK 文件签名时执行 ZIP 对齐。 ZIP对齐在 APK\n文件 (实际也是一种 ZIP 文件) 中 ZIP\n文件浏览器可通过随机访问非常轻易地访问文件而不是将整个 APK\n文件加载到内存， 进而导致 Android 可用内存的减少。\n记住一点：该步骤需要该应用程序的清单 (manifest) 中 存在\n<code>解压本地库 (extractNativeLibs)</code> 并被设定为\n<code>真 (true)</code>。</section></section><section id=subsec:installer class=level3 data-number=2.6.6><h3 data-number=2.6.6><span class=header-section-number>2.6.6</span>\n<a href=#toc:subsec:installer>安装器</a><a href=#subsec:installer class=anchor aria-hidden=true></a></h3><p>配置安装器的默认行为。在应用程序安装时， 你也可以通过点击\n<em>齿轮</em> 图标并找到绝大多数设置。<section id=安装位置 class=level4 data-number=2.6.6.1><h4 data-number=2.6.6.1><span class=header-section-number>2.6.6.1</span> 安装位置<a href=#安装位置 class=anchor aria-hidden=true></a></h4><p>定义 APK 安装位置，可以是 <em>自动</em>、<em>仅内部存储</em>\n和<em>偏好外部存储</em>。 在较新的 Android 版本中，选择最后一个选项\n并不保证应用将被安装在外部存储中。</section><section id=阻止跟踪器-1 class=level4 data-number=2.6.6.2><h4 data-number=2.6.6.2><span class=header-section-number>2.6.6.2</span> 阻止跟踪器<a href=#阻止跟踪器-1 class=anchor aria-hidden=true></a></h4><p>在安装应用程序后立刻阻止跟踪器组件。</section><section id=显示变化 class=level4 data-number=2.6.6.3><h4 data-number=2.6.6.3><span class=header-section-number>2.6.6.3</span> 显示变化<a href=#显示变化 class=anchor aria-hidden=true></a></h4><p>在安装应用程序前，若该应用程序已经被安装，\n则会在版本控制样式中显示版本、跟踪器、组件、权限、签名、SDK等信息的变更。</section><section id=安装来源 class=level4 data-number=2.6.6.4><h4 data-number=2.6.6.4><span class=header-section-number>2.6.6.4</span> 安装来源<a href=#安装来源 class=anchor aria-hidden=true></a></h4><p>选择安装程序。这对于明确检查安装程序以验证应用程序是否合法安装的应用程序很有用。\n这只适用于 root 或 ADB 用户。<div class=\"amalert tip\"><p><strong><em>Notice.</em></strong><p>对于应用来说，检查安装包似乎并无不妥， 但 Android\n框架已经在安装过程中处理了这个问题。因此，\n通过检查安装包是证明应用来源合法性是错误的。</div></section><section id=签名-apk class=level4 data-number=2.6.6.5><h4 data-number=2.6.6.5><span class=header-section-number>2.6.6.5</span> 签名 APK<a href=#签名-apk class=anchor aria-hidden=true></a></h4><p>安装应用前是否对 APK 文件进行签名。可用 <a href=#subsec:apk-signing>APK 签名</a> 页面 来配置签名。</section><section id=立即执行dex优化 class=level4 data-number=2.6.6.6><h4 data-number=2.6.6.6><span class=header-section-number>2.6.6.6</span> 立即执行DEX优化<a href=#立即执行dex优化 class=anchor aria-hidden=true></a></h4><p>在安装应用程序后立即执行DEX优化。\n对于大型应用程序（比如说游戏类应用程序）而言，这很有用。</section><section id=后台安装 class=level4 data-number=2.6.6.7><h4 data-number=2.6.6.7><span class=header-section-number>2.6.6.7</span> 后台安装<a href=#后台安装 class=anchor aria-hidden=true></a></h4><p>总是在后台安装应用程序。当安装完成时，会发出一条通知。</section></section><section id=subsec:backup/restore class=level3 data-number=2.6.7><h3 data-number=2.6.7><span class=header-section-number>2.6.7</span>\n<a href=#toc:subsec:backup/restore>备份/恢复</a><a href=#subsec:backup/restore class=anchor aria-hidden=true></a></h3><p>与 <a href=#sec:backup-restore>备份恢复</a> 相关的设置.<section id=压缩方法 class=level4 data-number=2.6.7.1><h4 data-number=2.6.7.1><span class=header-section-number>2.6.7.1</span> 压缩方法<a href=#压缩方法 class=anchor aria-hidden=true></a></h4><p>设置在备份时使用的压缩方式。 App Manager 支持 GZip、BZip2 和\nZstandard 压缩方式，且默认的压缩方式为 GZip。\n这不会影响到已有备份的还原。</section><section id=subsubsec:settings-backup-options class=level4 data-number=2.6.7.2><h4 data-number=2.6.7.2><span class=header-section-number>2.6.7.2</span> 备份选项<a href=#subsubsec:settings-backup-options class=anchor aria-hidden=true></a></h4><p>自定义备份时 <em>备份/还原对话框</em> 的显示。<div class=seealso-inline><p><em>另见: <span><a href=#subsec:backup-restore-backup-options>备份选项</a></span></em></div></section><section id=备份带-android-密钥库的应用程序 class=level4 data-number=2.6.7.3><h4 data-number=2.6.7.3><span class=header-section-number>2.6.7.3</span> 备份带 Android\n密钥库的应用程序<a href=#备份带-android-密钥库的应用程序 class=anchor aria-hidden=true></a></h4><p>允许备份在 Android 密钥库中有条目的应用程序。 由于一些应用 (比如说\nSignal 和 Element ) 在还原后会崩溃闪退，该选项会默认显示。</section><section id=subsubsec:settings-encryption class=level4 data-number=2.6.7.4><h4 data-number=2.6.7.4><span class=header-section-number>2.6.7.4</span> 加密<a href=#subsubsec:settings-encryption class=anchor aria-hidden=true></a></h4><p>为备份设置加密方式。App Manager 当前支持 OpenPGP (源自 <a href=https://f-droid.org/packages/org.sufficientlysecure.keychain/>OpenKeyChain</a>\n)、 AES、RSA和ECC。与 <a href=#subsec:apk-signing>APK\n签名</a>类似，AES、RSA和ECC密钥被存储在\n密钥库中，可从其它密钥库中导入。<div class=\"amalert danger\"><p><strong><em>危险.</em></strong><p>为了确保自身安全，推荐在 App Manager 内部生成 RSA 和 ECC 密钥。\n或者应该从存储在安全地方的密钥库中导入。<br>在 AES 的情况下，生成的密钥应存储在安全的地方，例如密码管理器中。</div></section><section id=subsubsec:backup-volume class=level4 data-number=2.6.7.5><h4 data-number=2.6.7.5><span class=header-section-number>2.6.7.5</span> 备份位置<a href=#subsubsec:backup-volume class=anchor aria-hidden=true></a></h4><p>选择存放备份的存储路径。这也将存放日志以及导出的 APK 文件。<div class=\"amalert tip\"><p><strong><em>注意.</em></strong><p>备份卷仅可指定存储空间而不是路径。一般情况下备份会被存放在位于存储路径内部的\n<code>AppManager</code> 文件夹内。 但当通过存储访问框架 (Storage Access\nFramework，即 SAF ) 选择路径时，会直接选择路径或目录。</div></section><section id=导入备份 class=level4 data-number=2.6.7.6><h4 data-number=2.6.7.6><span class=header-section-number>2.6.7.6</span> 导入备份<a href=#导入备份 class=anchor aria-hidden=true></a></h4><p>从旧版本和已停止更新的项目（比如说钛备份、OAndBackup 和 Swift Backup\n(从3.0到3.2的版本) 中导入备份。\n备份在导入后不会被删除，以防止在无法正确还原导入的备份时丢失数据。</section></section><section id=subsec:rules class=level3 data-number=2.6.8><h3 data-number=2.6.8><span class=header-section-number>2.6.8</span>\n<a href=#toc:subsec:rules>规则</a><a href=#subsec:rules class=anchor aria-hidden=true></a></h3><section id=subsubsec:instant-component-blocking class=level4 data-number=2.6.8.1><h4 data-number=2.6.8.1><span class=header-section-number>2.6.8.1</span> 即时组件拦截<a href=#subsubsec:instant-component-blocking class=anchor aria-hidden=true></a></h4><p>默认情况下，阻止规则不会生效，直到它们在任意应用程序的 <a href=#sec:app-details-page>应用详情页</a> 中被显式应用。\n在启用该选项后，所有应用程序的所有规则 (无论新旧)\n即刻生效，无需显式启用应用程序的阻止。<div class=seealso-inline><p><em>另见: <span><a href=#subsec:faq:what-is-instant-component-blocking>FAQ:\n什么是即时阻止组件？</a></span></em></div></section><section id=导入导出拦截规则 class=level4 data-number=2.6.8.2><h4 data-number=2.6.8.2><span class=header-section-number>2.6.8.2</span> 导入/导出拦截规则<a href=#导入导出拦截规则 class=anchor aria-hidden=true></a></h4><p>可以在 App Manager\n内为所有应用程序导入或导出阻止规则。可选择应被导入或导出的规则类型\n(组件、应用操作或权限)。 也可从 <a href=https://github.com/lihenggui/blocker>Blocker</a> 和 <a href=https://github.com/tuyafeng/Watt>Watt</a> 导入阻止规则。\n若要为单个应用程序导出阻止规则，则可使用相应的 <a href=#sec:app-details-page>应用详情页</a>\n导出规则。若要为多个应用程序导出规则，则可使用 <a href=#subsec:batch-operations>批处理操作</a> 。<div class=seealso-inline><p><em>另见: <span><a href=#sec:rules-specification>规则说明</a></span></em></div><section id=导出 class=level5 data-number=2.6.8.2.1><h5 data-number=2.6.8.2.1><span class=header-section-number>2.6.8.2.1</span> 导出<a href=#导出 class=anchor aria-hidden=true></a></h5><p>为所有应用程序导出在 App Manager 配置的阻止规则。 可包含 <a href=#subsec:faq:what-are-app-components>应用组件</a> 、应用操作 (App\nOps) 和权限，基于多选操作中选择的选项导出规则。</section><section id=导入 class=level5 data-number=2.6.8.2.2><h5 data-number=2.6.8.2.2><span class=header-section-number>2.6.8.2.2</span> 导入<a href=#导入 class=anchor aria-hidden=true></a></h5><p>导入之前从 App Manager 导出的阻止规则。 类似于导出，可包含 <a href=#subsec:faq:what-are-app-components>应用组件</a>、应用操作 (App\nOps) 和权限，基于多选操作中选择的选项导入规则。</section><section id=par:import-existing-rules class=level5 data-number=2.6.8.2.3><h5 data-number=2.6.8.2.3><span class=header-section-number>2.6.8.2.3</span> 导入已有规则<a href=#par:import-existing-rules class=anchor aria-hidden=true></a></h5><p>将被其他应用程序阻止的组件添加到 App Manager 中。App Manager 仅跟踪被\nApp Manager 禁用的组件。\n若应用程序的组件时被其他工具或应用程序阻止，则该选项可被用于导入它们。\n点击该选项， App Manager\n会查找潜在的被其他应用程序或工具阻止的组件，并仅列出应用程序的名称以及匹配的组件数量。\n安全起见，所有的应用程序默认情况下不会被选中。它们需要被手动选择，并在\nApp Manager 中重新应用阻止规则。<div class=\"amalert danger\"><p><strong><em>小心.</em></strong><p>谨慎使用可能存在错误结果的工具。 仅选择你十分确信的应用程序。</div></section><section id=从-watt-中导入 class=level5 data-number=2.6.8.2.4><h5 data-number=2.6.8.2.4><span class=header-section-number>2.6.8.2.4</span> 从 Watt 中导入<a href=#从-watt-中导入 class=anchor aria-hidden=true></a></h5><p>从 <a href=https://github.com/tuyafeng/Watt>Watt</a>\n中导入配置文件， 每个文件包含单个包的规则，文件名为包的名称跟着\n<code>.xml</code> 的扩展名。<div class=\"amalert tip\"><p><strong><em>提示.</em></strong><p>Watt 的配置文件存放位置为：\n<code>/sdcard/Android/data/com.tuyafeng.watt/files/ifw</code></div></section><section id=从-blocker-中导入 class=level5 data-number=2.6.8.2.5><h5 data-number=2.6.8.2.5><span class=header-section-number>2.6.8.2.5</span> 从 Blocker 中导入<a href=#从-blocker-中导入 class=anchor aria-hidden=true></a></h5><p>从 <a href=https://github.com/lihenggui/blocker>Blocker</a>\n中导入阻止规则，每个文件包含单个包的规则。 这些文件的扩展名为\n<code>.json</code> 。</section></section><section id=删除所有规则 class=level4 data-number=2.6.8.3><h4 data-number=2.6.8.3><span class=header-section-number>2.6.8.3</span> 删除所有规则<a href=#删除所有规则 class=anchor aria-hidden=true></a></h4><p>点击选项以移除App Manager 内配置的所有规则。\n这将启用所有已被阻止的组件，应用操作会被设置为默认值以及权限会被授予。</section></section><section id=subsec:advanced class=level3 data-number=2.6.9><h3 data-number=2.6.9><span class=header-section-number>2.6.9</span>\n<a href=#toc:subsec:advanced>高级</a><a href=#subsec:advanced class=anchor aria-hidden=true></a></h3><section id=subsubsec:selected-users class=level4 data-number=2.6.9.1><h4 data-number=2.6.9.1><span class=header-section-number>2.6.9.1</span> 选中的用户<a href=#subsubsec:selected-users class=anchor aria-hidden=true></a></h4><p>该选项允许你控制 App Manager 应作用的用户。默认情况下，在 Root 模式或\nADB 模式下 App Manager 对所有用户起作用。</section><section id=subsubsec:saved-apk-name-format class=level4 data-number=2.6.9.2><h4 data-number=2.6.9.2><span class=header-section-number>2.6.9.2</span> 保存的 APK 名称格式<a href=#subsubsec:saved-apk-name-format class=anchor aria-hidden=true></a></h4><p>定义用于批处理操作或通过配置文件导出的 APK 格式的文件名。 App Manager\n提供一些特殊的关键词，这些关键词包含在 <code>%</code> (百分号)\n符号内，并在输入框下方可用。 这些关键词为：<ul class=incremental><li><p><strong><code>标签</code>。</strong>\n表示该应用程序的名称或标签。可根据该应用程序设置的语言进行本地化。<li><p><strong><code>包名</code>。</strong>\n表示包名称或该应用程序ID，是每个应用程序拥有的唯一标识符。<li><p><strong><code>版本</code>。</strong>\n表示从该应用程序清单里提取出的当前版本。<li><p><strong><code>版本代号</code>。</strong>\n表示该应用程序的当前版本代号，可用于区分同一个应用程序的两个版本。<li><p><strong><code>最小SDK</code>。</strong>\n表示该应用程序可运行的最小的SDK (即 Android 框架版本)。该数据仅在\nAndroid 7 (Nougat) 及更高版本可用。<li><p><strong><code>目标SDK</code>。</strong>\n表示该应用程序的目标SDK。该应用程序可在更高的 SDK\n版本以兼容模式运行。<li><p><strong><code>日期时间</code>。</strong> 表示 APK\n导出的时间和日期。</ul></section><section id=subsubsec:import/export-keystore class=level4 data-number=2.6.9.3><h4 data-number=2.6.9.3><span class=header-section-number>2.6.9.3</span> 导入/导出密钥库<a href=#subsubsec:import/export-keystore class=anchor aria-hidden=true></a></h4><p>导入或导出用于 App Manager 的密钥库。该密钥库是 Bouncy Castle\nKeyStore 并以 <code>bks</code> 作为扩展名。 因此不支持其他诸如 Java\nKeyStore (JKS) 或 PKCS #12 的密钥库。\n若要从这类密钥库中导入密钥，则应使用如上所述的相关选项。</section></section><section id=subsec:device-info class=level3 data-number=2.6.10><h3 data-number=2.6.10><span class=header-section-number>2.6.10</span> <a href=#toc:subsec:device-info>关于设备</a><a href=#subsec:device-info class=anchor aria-hidden=true></a></h3><p>显示 Android\n版本、安全、CPU、GPU、电池、内存、屏幕、语言、用户信息等。</section></section><section id=sec:scanner-page class=level2 data-number=2.7><h2 data-number=2.7><span class=header-section-number>2.7</span> <a href=#toc:sec:scanner-page>扫描器页面</a><a href=#sec:scanner-page class=anchor aria-hidden=true></a></h2><p>在 <a href=#subsec:app-info-tab>应用详情页</a> 中点击\n<em>扫描器</em> 按钮后，会出现 <strong>扫描器页面</strong> 。 外部 APK\n文件也可从文件管理器、网页浏览器等用 App Manager 的扫描器打开以扫描 APK\n文件。<p>扫描器会扫描跟踪器和库，显示跟踪器和库的总数。 它也会显示 APK\n文件的检验和并进行签名验证。 若设置里配置了 VirusTotal ，则也可尝试从\nVirusTotal 中检索报告， 若该 APK 文件不在数据库时，则可以选择上传该 APK\n文件。 当启用网络功能时，还会显示前往 <a href=https://beta.pithus.org>Pithus</a>的链接，并提供报告功能。<div class=\"amalert danger\"><p><strong><em>免责声明.</em></strong><p>App Manager\n仅静态扫描应用程序，并不带任何偏见。应用程序可能会提供退出跟踪的选项。\n在某些情况下，某些跟踪器的功能并不会被应用程序使用 (比如 F-Droid)。\n某些应用程序可能只是单纯将它们当作占位符使用， 以防止某些功能被破坏\n(比如Fennec F-Droid)。 <strong>扫描器的目的是让你知道该 APK\n可能包含的内容。 应该把扫描结果当作进一步调查之前的第一步。</strong></div><p>点击第一项 (即类的数量)\n以打开一个新页面，该页面包含该应用程序的跟踪器类的列表。\n所有类可以通过点击 <em>切换类列表</em> 目录查阅。\n只需点击其中任意一项即可查看该类的 SMALI 或 Java 版本。<div class=\"amalert tip\"><p><strong><em>注意.</em></strong><p>由于诸多限制，不可能扫描一个 APK 文件里的所有组件。 若一个 APK\n文件被高度混淆或包装则更是如此。 扫描器也不会检查字符串\n(或网站签名)。</div><p>第二项列出了跟踪器数量以及它们的名称。\n点击其中一项以显示包含跟踪器名称、匹配签名和每个签名对应的类的数量的对话框。\n某些跟踪器名称可能包含 <span class=\"math inline\"><sup>2</sup></span>\n前缀， 表示这些跟踪器在 <a href=https://etip.exodus-privacy.eu.org>ETIP</a> 备选列表内，\n即它们是否确实是跟踪器还在调查中。<p>第三项列出了库的数量以及它们的名称。 这些信息大多叔来自 <a href=https://gitlab.com/IzzyOnDroid/repo>IzzyOnDroid repo</a>。<div class=seealso-inline><p><em>另见: <span><a href=#subsec:tracker-classes-versus-tracker-components>FAQ:\n跟踪器类与跟踪器组件</a></span></em></div></section><section id=sec:interceptor-page class=level2 data-number=2.8><h2 data-number=2.8><span class=header-section-number>2.8</span> <a href=#toc:sec:interceptor-page>拦截器页面</a><a href=#sec:interceptor-page class=anchor aria-hidden=true></a></h2><p>拦截器可被用于拦截应用间通过 <code>意图 (Intent) </code>进行的通信。\n作为源应用程序与目标应用程序之间的中间人工作。 并提供编辑\n<code>意图</code> 的界面给功能完整的用户。<div class=\"amalert warning\"><p><strong><em>警告.</em></strong><p>拦截器仅作用于未被指定 <a href=#subsec:faq:what-are-app-components>应用组件</a> 的 <em>隐式</em>\n意图。</div><div class=seealso><p><em>另见:</em><ul class=incremental><li><p><a href=https://developer.android.com/guide/components/intents-common>常见\nIntent</a><li><p><a href=https://developer.android.com/guide/components/intents-filters>Intent\n与 Intent 过滤器</a></ul></div><section id=subsec:intent-filters class=level3 data-number=2.8.1><h3 data-number=2.8.1><span class=header-section-number>2.8.1</span>\n<a href=#toc:subsec:intent-filters>意图(Intent)过滤器</a><a href=#subsec:intent-filters class=anchor aria-hidden=true></a></h3><p>应用程序使用意图过滤器来指定它们能够执行的任务或者它们将使用其他应用程序执行的任务。\n举个例子，当你使用文件管理器打开一个 PDF\n文件时，文件管理器会尝试寻找能够打开 PDF 的应用程序。\n为了找到正确的应用程序，文件管理器会创建一个带有MIME类型等过滤器的意图\n(Intent)，并要求系统检索能够打开该过滤器的应用程序。\n系统会通过检索已安装应用程序的清单\n(Manifest)匹配过滤器，并列出能够打开该过滤器\n(该例子中是PDF)的应用程序组件。\n此时，文件管理器将自行打开所需的应用程序组件或者使用系统提供的选项打开它。\n若多个应用程序组件能打开它并且没有设置默认的打开方式，则你可能会看到一个选择正确的应用程序组件打开的提示。<section id=subsubsec:action class=level4 data-number=2.8.1.1><h4 data-number=2.8.1.1><span class=header-section-number>2.8.1.1</span> 动作(Action)<a href=#subsubsec:action class=anchor aria-hidden=true></a></h4><p>动作 (Action) 指定要执行的通用动作，例如\n<code>android.intent.action.VIEW</code>。\n应用程序通常在清单文件中声明相关的动作以抓取所需的意图。\n该动作对广播意图非常有用，起到了至关重要的作用。在其他情况下，其作为过滤相关应用程序组件的初始方法。\n诸如 <code>android.intent.action.VIEW</code> 和\n<code>android.intent.action.SEND</code> 的通用动作被应用程序广泛使用。\n因此，单独设置它可能会匹配到很多应用程序组件。</section><section id=subsubsec:data class=level4 data-number=2.8.1.2><h4 data-number=2.8.1.2><span class=header-section-number>2.8.1.2</span> 数据(Data)<a href=#subsubsec:data class=anchor aria-hidden=true></a></h4><p>数据最初被称为 URI(Uniform Resource Identifier，统一资源标识符)，在\n<a href=http://www.faqs.org/rfcs/rfc2396.html>RFC 2396</a> 中被定义。\n它可以是网络链接、文件位置，或者名为 <em>内容 (content)</em>\n的特殊功能。内容是由 <a href=#subsubsec:providers>内容提供者</a>\n管理的一个 Android 功能。 数据经常被一种 <a href=#subsubsec:mime-type>MIME 类型</a> 关联。<p>例如：<pre><code>http://search.disroot.org/?q=URI%20in%20Android%20scheme&amp;categories=general&amp;language=en-US\nhttps://developer.android.com/reference/android/net/Uri\nfile:///sdcard/AppManager.apk\nmailto:email@example.com\ncontent://io.github.muntashirakon.AppManager.provider/23485af89b08d87e898a90c7e/AppManager.apk</code></pre></section><section id=subsubsec:mime-type class=level4 data-number=2.8.1.3><h4 data-number=2.8.1.3><span class=header-section-number>2.8.1.3</span> MIME 类型<a href=#subsubsec:mime-type class=anchor aria-hidden=true></a></h4><p><a href=#subsubsec:data>数据</a> 的 MIME类型。\n举个例子，若数据字段被设定为\n<code>file:///sdcard/AppManager.apk</code>， 则相关联的MIME类型为\n<code>application/vnd.android.package-archive</code>。</section><section id=类别categories class=level4 data-number=2.8.1.4><h4 data-number=2.8.1.4><span class=header-section-number>2.8.1.4</span> 类别(Categories)<a href=#类别categories class=anchor aria-hidden=true></a></h4><p>类别 (Category) 与 <a href=#subsubsec:action>动作 (Action)</a>\n类似。某种意义上来说，它也被系统用于过滤应用程序组件。\n它并没有更多优势。不同于 <em>动作\n(Action)</em>，可以拥有多个类别。点击标题旁边的 <em>添加</em>\n按钮以允许添加更多类别。</section><section id=标志位flags class=level4 data-number=2.8.1.5><h4 data-number=2.8.1.5><span class=header-section-number>2.8.1.5</span> 标志位(Flags)<a href=#标志位flags class=anchor aria-hidden=true></a></h4><p>标志 (Flags) 有助于确定活动 (Activity) 启动期间或活动 (Activity)\n启动后的系统行为。 因为它需要一些技术背景，不应该被随意触及。标题旁边的\n<em>添加</em> 按钮可用于添加一或多个标志 (Flags)。</section><section id=附加数据extras class=level4 data-number=2.8.1.6><h4 data-number=2.8.1.6><span class=header-section-number>2.8.1.6</span> 附加数据(Extras)<a href=#附加数据extras class=anchor aria-hidden=true></a></h4><p>额外数据 (Extras)\n是用于向目标组件提供附加信息的键值对。可以使用标题旁边的 <em>添加</em>\n按钮添加更多额外数据 (Extras)。</section><section id=uri class=level4 data-number=2.8.1.7><h4 data-number=2.8.1.7><span class=header-section-number>2.8.1.7</span> URI<a href=#uri class=anchor aria-hidden=true></a></h4><p>将整个意图表示为 URI (例如 <code>intent://…</code>)。\n一些数据无法被转换为字符串，结果可能无法在此显示。</section></section><section id=subsec:matching-activities class=level3 data-number=2.8.2><h3 data-number=2.8.2><span class=header-section-number>2.8.2</span>\n<a href=#toc:subsec:matching-activities>匹配的活动(Activity)</a><a href=#subsec:matching-activities class=anchor aria-hidden=true></a></h3><p>列出匹配意图的所有活动组件。这是由系统内部决定的 (而不是 App Manager)\n。 每个组件旁边的启动按钮可用于从 App Manager 直接启动它们。</section><section id=subsec:interceptor-reset-to-default class=level3 data-number=2.8.3><h3 data-number=2.8.3><span class=header-section-number>2.8.3</span>\n<a href=#toc:subsec:interceptor-reset-to-default>重置为默认</a><a href=#subsec:interceptor-reset-to-default class=anchor aria-hidden=true></a></h3><p>重置意图至其初始化状态。</section><section id=subsec:interceptor-send-edited-intent class=level3 data-number=2.8.4><h3 data-number=2.8.4><span class=header-section-number>2.8.4</span>\n<a href=#toc:subsec:interceptor-send-edited-intent>发送编辑过的意图(Intent)</a><a href=#subsec:interceptor-send-edited-intent class=anchor aria-hidden=true></a></h3><p>将编辑过的意图重新发送到目标应用程序。这可能会打开需要选择所需应用程序的应用程序列表。\n从目标应用程序接收的结果会被发送到源应用程序。因此，源应用程序将不会知道是否存在中间人。</section></section><section id=sec:shared-preferences-editor-page class=level2 data-number=2.9><h2 data-number=2.9><span class=header-section-number>2.9</span> <a href=#toc:sec:shared-preferences-editor-page>共享首选项(Shared\nPreferences)编辑页</a><a href=#sec:shared-preferences-editor-page class=anchor aria-hidden=true></a></h2><p>可以在此页面中编辑共享首选项。点击列表中的任意一项以打开可编辑该项目的编辑对话框。\n右下角的浮动操作按钮可用于添加新项目。\n若要保存或删除文件，或放弃当前更改，可使用菜单中的相应选项。</section></section><section id=ch:guides class=level1 data-number=3><h1 data-number=3><span class=header-section-number>3</span> <a href=#toc:ch:guides>指南</a><a href=#ch:guides class=anchor aria-hidden=true></a></h1><section id=sec:adb-over-tcp class=level2 data-number=3.1><h2 data-number=3.1><span class=header-section-number>3.1</span> <a href=#toc:sec:adb-over-tcp>经由 TCP 的 ADB</a><a href=#sec:adb-over-tcp class=anchor aria-hidden=true></a></h2><p>许多仅 Root 功能在通过 TCP 启动的 ADB 下依然可用。为此需要一台已安装\nAndroid 平台工具的 PC 或者 Mac 设备， 以及一部启用开发者选项和 USB\n调试的 Android 手机。<div class=\"amalert tip\"><p><strong><em>Root 用户.</em></strong><p>若 App Manager\n已被授予超级用户权限，则已经能够毫无问题地执行特权代码。\n<strong>因此，Root 用户无需启用通过 TCP 启用的 ADB。</strong>\n如果你仍想使用通过 TCP 启动的 ADB， 你必须撤销对 App Manager\n的超级用户权限的授予</div><div class=seealso-inline><p><em>另见: <span><a href=#sec:faq:adb-over-tcp>FAQ: 通过 TCP 启动的\nADB</a></span></em></div><section id=subsec:enable-developer-options class=level3 data-number=3.1.1><h3 data-number=3.1.1><span class=header-section-number>3.1.1</span>\n<a href=#toc:subsec:enable-developer-options>启用开发者选项</a><a href=#subsec:enable-developer-options class=anchor aria-hidden=true></a></h3><section id=subsubsec:location-of-developer-options class=level4 data-number=3.1.1.1><h4 data-number=3.1.1.1><span class=header-section-number>3.1.1.1</span> 开发人员选项的位置<a href=#subsubsec:location-of-developer-options class=anchor aria-hidden=true></a></h4><p><strong>开发者选项</strong> 位于 Android\n<strong>设置</strong>，要么直接 靠近设置页底部\n（多数ROMs），要么在其他一些设置下面，比如 <strong>系统</strong>\n（Google Pixel、 Lineage OS、 Asus Zenfone 8.0+）,\n<strong>附加设置</strong> （Xiaomi MIUI、Oppo ColorOS），\n<strong>更多设置</strong> （Vivo FuntouchOS）, <strong>更多</strong>\n（ZTE Nubia）。 不像其他设置，开发者选项\n在用户明确启用前不可见。如果已经启用开发者选项，你也可以使用 Android\n<strong>设置</strong> 中的搜索框来定位它。</section><section id=如何启用开发者选项 class=level4 data-number=3.1.1.2><h4 data-number=3.1.1.2><span class=header-section-number>3.1.1.2</span> 如何启用开发者选项<a href=#如何启用开发者选项 class=anchor aria-hidden=true></a></h4><p>该选项在 Android <strong>设置</strong>\n也可用，但是类似于开发者选项的位置，其位置也因设备而异。\n但总体来说，你需要找到 <strong>Build number (内部版本号)</strong> (或者\nMIUI ROM的 <strong>MIUI 版本</strong> 、 Vivo FuntouchOS的\n<strong>软件版本</strong> 、OPPO ColorOS 的 <strong>版本</strong> for )\n然后连续点击至少7次， 直到你最终看到一条写着\n<em>你已经启用了开发者选项！</em>的消息。\n（这一步你可能会看到需要输入PIN/密码/解锁图案或验证码的提示。）\n对绝大多数设备而言，其位于设置页面底部的 <strong>关于手机</strong>\n内。不过找到它的最佳方法是使用搜索框。</section></section><section id=subsec:enable-usb-debugging class=level3 data-number=3.1.2><h3 data-number=3.1.2><span class=header-section-number>3.1.2</span>\n<a href=#toc:subsec:enable-usb-debugging>启用USB调试</a><a href=#subsec:enable-usb-debugging class=anchor aria-hidden=true></a></h3><p>在 <a href=#subsubsec:location-of-developer-options>定位开发者选项</a> 后，\n启用 <strong>开发者选项</strong> (如果尚未启用)。然后一点点往下划，\n直到你看见 <strong>USB 调试</strong> 选项。点击右侧的切换按钮启用它。\n此时你可能会看见一个需要点击 <em>OK</em> 按钮才能实际启用 USB\n调试的警示信息。\n基于设备供应商和ROM，你可能还需要启用一些其他的选项。以下是一些例子：<section id=小米-miui class=level4 data-number=3.1.2.1><h4 data-number=3.1.2.1><span class=header-section-number>3.1.2.1</span> 小米 (MIUI)<a href=#小米-miui class=anchor aria-hidden=true></a></h4><p>同时启用 <strong>USB 调试 (安全设置)</strong> 。</section><section id=华为-emui class=level4 data-number=3.1.2.2><h4 data-number=3.1.2.2><span class=header-section-number>3.1.2.2</span> 华为 (EMUI)<a href=#华为-emui class=anchor aria-hidden=true></a></h4><p>也启用 <strong>允许在仅充电模式下进行 ADB 调试</strong> 。\n当连接到你的 PC 或 Mac 设备时，你可能会看到\n<strong>是否允许访问设备数据？</strong> 的提示。 无论哪种情况，请点击\n<strong>是，允许访问</strong>。<div class=\"amalert tip\"><p><strong><em>注意.</em></strong><p><strong>USB 调试</strong>\n模式经常会被系统自动禁止。遇到此情况时，请重复上述步骤。</div></section><section id=真我-realme class=level4 data-number=3.1.2.3><h4 data-number=3.1.2.3><span class=header-section-number>3.1.2.3</span> 真我 (Realme)<a href=#真我-realme class=anchor aria-hidden=true></a></h4><p>基于设备和操作系统版本，你需要启用 <strong>禁用权限监视</strong> 或\n<strong>USB 调试 (安全设置)</strong> 以及 <strong>从 USB 安装</strong>\n选项。</section><section id=一加-oxygen-os class=level4 data-number=3.1.2.4><h4 data-number=3.1.2.4><span class=header-section-number>3.1.2.4</span> 一加 (Oxygen OS)<a href=#一加-oxygen-os class=anchor aria-hidden=true></a></h4><p>基于设备和操作系统版本，你需要启用\n<strong>禁用权限监视</strong>。</section><section id=lg class=level4 data-number=3.1.2.5><h4 data-number=3.1.2.5><span class=header-section-number>3.1.2.5</span> LG<a href=#lg class=anchor aria-hidden=true></a></h4><p>确认你已启用 <strong>USB 网络共享</strong>。</section><section id=故障排除 class=level4 data-number=3.1.2.6><h4 data-number=3.1.2.6><span class=header-section-number>3.1.2.6</span> 故障排除<a href=#故障排除 class=anchor aria-hidden=true></a></h4><p>当 <strong>USB 调试</strong> 为灰色时，你可以执行以下步骤：<ol class=incremental><li><p>在通过 USB 数据线连接你的手机到 PC 或者 Mac 前，确认你已开启 USB\n调试；<li><p>在通过 USB 数据线连接到 PC 或 Mac 后启用 USB 网络共享；<li><p>(对三星设备而言)\n若你的设备正在运行KNOX，你可能需要执行一些额外步骤。\n参考官方文档或咨询官方客服以获得更多支持。</ol></section></section><section id=subsec:setup-adb-on-pc-or-mac class=level3 data-number=3.1.3><h3 data-number=3.1.3><span class=header-section-number>3.1.3</span>\n<a href=#toc:subsec:setup-adb-on-pc-or-mac>在PC或Mac上配置ADB</a><a href=#subsec:setup-adb-on-pc-or-mac class=anchor aria-hidden=true></a></h3><p>为了使用通过 TCP 启动 ADB 功能，你需要在你的 PC 或 Mac\n设备上安装并设置 ADB。 <strong><em>Lineage OS 用户可参考 §<a href=#subsubsec:lineage-os data-reference-type=ref data-reference=subsubsec:lineage-os>3.1.4.1</a>。</em></strong><section id=windows class=level4 data-number=3.1.3.1><h4 data-number=3.1.3.1><span class=header-section-number>3.1.3.1</span> Windows<a href=#windows class=anchor aria-hidden=true></a></h4><ol class=incremental><li><p>下载最新的 <a href=https://dl.google.com/android/repository/platform-tools-latest-windows.zip>Android\nSDK 平台工具</a> 的 Windows 版本。<li><p>解压 ZIP 文件的内容到任意目录 (例如\n<code>C:\\</code><span><code>adb</code></span>)，然后用\n<em>文件资源管理器</em> 导航到 (转到/打开) 该目录。<li><p>在此目录中打开 <strong>命令提示符</strong>、\n<strong>PowerShell</strong> 或 <strong>终端</strong>。\n你可以手动从开始菜单打开， 或者按住 <code>Shift</code>\n键，打开目录，在目录内用 <em>文件资源管理器</em> 右键单击，然后单击\n<em>在此处打开命令窗口</em> 或者 <em>在此处打开 PowerShell 窗口</em>\n(取决于你安装的软件)。 现在你可以通过输入 <code>adb</code>\n(在命令提示符中) 或者是 <code>./adb</code> (在PowerShell中) 的方式访问\nADB。 请不要关闭此窗口。</ol><div class=\"amalert tip\"><p><strong><em>Tip.</em></strong><p>如果你已经安装了 <a href=https://learn.microsoft.com/en-us/windows/package-manager/winget/>WinGet</a>\n，你可以使用以下命令安装 ADB：<div class=sourceCode id=cb3 data-frame=lines><pre class=\"sourceCode bash\"><code class=\"sourceCode bash\"><span id=cb3-1><a href=#cb3-1 aria-hidden=true tabindex=-1></a> <span class=ex>winget</span> install <span class=at>--id</span> Google.PlatformTools</span></code></pre></div><p>完毕后，你只需输入 <code>adb</code> 就可访问 ADB。</div></section><section id=macos class=level4 data-number=3.1.3.2><h4 data-number=3.1.3.2><span class=header-section-number>3.1.3.2</span> macOS<a href=#macos class=anchor aria-hidden=true></a></h4><ol class=incremental><li><p>下载最新版本的 <a href=https://dl.google.com/android/repository/platform-tools-latest-darwin.zip>Android\nSDK 平台工具</a> 的 macOS 版本。<li><p>点击它以解压 ZIP 文件的内容到目录。然后用 <em>Finder</em>\n导航到该目录并定位 <code>adb</code>。<li><p>使用 <em>Launchpad</em> 或 <em>Spotlight</em> 打开\n<strong>终端</strong>， 然后将 <code>adb</code> 从 <em>Finder</em>\n窗口拖到 <code>adb</code> 到 <em>终端</em> 窗口并松开。 请不要关闭\n<em>终端</em> 窗口。</ol><div class=\"amalert tip\"><p><strong><em>Tip.</em></strong><p>如果你已经安装了 <a href=https://brew.sh>Homebrew</a>，你可以用下列命令安装 ADB:<div class=sourceCode id=cb4 data-frame=lines><pre class=\"sourceCode bash\"><code class=\"sourceCode bash\"><span id=cb4-1><a href=#cb4-1 aria-hidden=true tabindex=-1></a><span class=ex>brew</span> install <span class=at>--cask</span> android-platform-tools</span></code></pre></div><p>完毕后，你只需在任意 <em>终端</em> 窗口中输入 <code>adb</code>\n即可访问 access ADB。</div></section><section id=linux class=level4 data-number=3.1.3.3><h4 data-number=3.1.3.3><span class=header-section-number>3.1.3.3</span> Linux<a href=#linux class=anchor aria-hidden=true></a></h4><ol class=incremental><li><p>在你喜欢的终端模拟器中，运行如下命令<div class=sourceCode id=cb5 data-frame=lines data-autogobble><pre class=\"sourceCode bash\"><code class=\"sourceCode bash\"><span id=cb5-1><a href=#cb5-1 aria-hidden=true tabindex=-1></a><span class=bu>cd</span> ~/Downloads <span class=kw>&amp;&amp;</span> <span class=ex>curl</span> <span class=at>-o</span> platform-tools.zip <span class=at>-L</span> <span class=dt>\\</span></span>\n<span id=cb5-2><a href=#cb5-2 aria-hidden=true tabindex=-1></a>https://dl.google.com/android/repository/platform-tools-latest-linux.zip <span class=kw>&amp;&amp;</span> <span class=dt>\\</span></span>\n<span id=cb5-3><a href=#cb5-3 aria-hidden=true tabindex=-1></a><span class=fu>unzip</span> platform-tools.zip <span class=kw>&amp;&amp;</span> <span class=fu>rm</span> platform-tools.zip <span class=kw>&amp;&amp;</span> <span class=bu>cd</span> platform-tools</span></code></pre></div><li><p>若成功，你只需在 <em>同一个</em> 终端模拟器窗口内输入\n<code>./adb</code> 或者在任意的模拟器输入\n<code>~/Downloads/platform-tools/adb</code> 就可以访问 ADB。</ol></section></section><section id=subsec:configure-adb-over-tcp class=level3 data-number=3.1.4><h3 data-number=3.1.4><span class=header-section-number>3.1.4</span>\n<a href=#toc:subsec:configure-adb-over-tcp>配置经由TCP的ADB</a><a href=#subsec:configure-adb-over-tcp class=anchor aria-hidden=true></a></h3><section id=subsubsec:lineage-os class=level4 data-number=3.1.4.1><h4 data-number=3.1.4.1><span class=header-section-number>3.1.4.1</span> Lineage OS 17.1\n及更早版本<a href=#subsubsec:lineage-os class=anchor aria-hidden=true></a></h4><p>Lineage OS (或其衍生ROM) 用户可直接通过开发者选项启用通过 TCP 启动\nADB 功能。 若要启用，请前往\n<strong>开发者选项</strong>，下划，直到你找到 <strong>通过网络启动\nADB</strong>。 现在，点击右侧的切换按钮以启用它并跳转至 §<a href=#subsubsec:adb-mode-in-app-manager data-reference-type=ref data-reference=subsubsec:adb-mode-in-app-manager>3.1.4.3</a><span>在\nApp Manager 内的 ADB 模式</span>。<div class=\"amalert warning\"><p><strong><em>Warning.</em></strong><p>你可以在开发者选项中关闭 <strong>ADB over\nNetwork</strong>，但关闭该选项也会停止 App Manager\n的服务器。因此，请只在你不打算在 ADB over TCP 模式下使用 App Manager\n时关闭它。</div></section><section id=subsubsec:enable-adb-over-tcp-via-pc-or-mac class=level4 data-number=3.1.4.2><h4 data-number=3.1.4.2><span class=header-section-number>3.1.4.2</span> 在 PC 或 Mac 上启用\n经由TCP的ADB<a href=#subsubsec:enable-adb-over-tcp-via-pc-or-mac class=anchor aria-hidden=true></a></h4><p>对于其他ROM，你可以通过在前面章节中的步骤3打开的命令提示符/PowerShell/终端模拟器进行操作。\n在此节中，我将使用 <code>adb</code> 表示 <code>./adb</code>，\n<code>adb</code>\n或其他你需要使用的任何命令基于前面的章节中你使用的平台和软件。<ol class=incremental><li><p>使用数据线连接你的设备到你的 PC 或 Mac。For some devices, it is\nnecessary to turn on 对某些设备而言，有必要同时启用 <em>文件传输模式\n(MTP)</em>。<li><p>确认一切都按预期运行，在你的终端输入 <code>adb devices</code> 。\n若你的设备已成功连接，则你会看到像这样的内容：<pre><code>List of devices attached\nxxxxxxxx device</code></pre><div class=\"amalert tip\"><p><strong><em>注意.</em></strong><p>在某些 Android 手机中，会出现这样的提示信息：<strong>允许 USB\n调试吗？</strong> 无论什么情况，勾选 <em>始终允许此计算机进行调试</em>\n然后点击 <strong>允许</strong>。</div><li><p>最终，运行下面的命令以启用通过 TCP 启用 ADB 功能。:<div class=sourceCode id=cb7 data-frame=lines data-autogobble><pre class=\"sourceCode bash\"><code class=\"sourceCode bash\"><span id=cb7-1><a href=#cb7-1 aria-hidden=true tabindex=-1></a><span class=ex>adb</span> tcpip 5555</span></code></pre></div></ol><div class=\"amalert danger\"><p><strong><em>危险.</em></strong><p>在启用通过 TCP 启用 ADB 功能后，你不能禁用开发者选项或者 USB\n调试。</div></section><section id=subsubsec:adb-mode-in-app-manager class=level4 data-number=3.1.4.3><h4 data-number=3.1.4.3><span class=header-section-number>3.1.4.3</span> 在 App Manager 中启用 ADB\n模式<a href=#subsubsec:adb-mode-in-app-manager class=anchor aria-hidden=true></a></h4><p>在启用通过 TCP 启动 ADB后，重新启动 App Manager。App Manager\n应该会自动检测到 ADB 模式。 若不能，你可以在 <a href=#subsec:mode-of-operation>设置页面</a> 更换操作模式为通过 TCP\n启动 ADB 模式。 你也可以在此处验证 App Manager 是否与 <em>推断模式</em>\n显示的一样正确检测到 ADB。<div class=\"amalert tip\"><p><strong><em>注意.</em></strong><p>在某些 Android 设备中，在连接到 App Manager 前，可能需要将 USB\n数据线从 PC 断开。</div><div class=\"amalert warning\"><p><strong><em>警告.</em></strong><p>通过 TCP 启动 ADB 在重启时会被禁用。对于这种情况，你需要按照 §<a href=#subsubsec:enable-adb-over-tcp-via-pc-or-mac data-reference-type=ref data-reference=subsubsec:enable-adb-over-tcp-via-pc-or-mac>3.1.4.2</a><span>在\nPC 或 Mac 上启用通过 TCP 启动 ADB 模式</span> 的步骤再度操作。</div></section></section></section><section id=sec:wireless-debugging class=level2 data-number=3.2><h2 data-number=3.2><span class=header-section-number>3.2</span> <a href=#toc:sec:wireless-debugging>无线调试</a><a href=#sec:wireless-debugging class=anchor aria-hidden=true></a></h2><p>若你的设备运行 Android 11 及更高版本，或稍后能够连接到 Wi-Fi\n网络至少几分钟， 则推荐使用无线调试方法，因为比起 <a href=#sec:adb-over-tcp>提供 TCP 启动 ADB</a> 它提供更多保护。\n它需要两个步骤：<ol class=incremental><li><p><strong>ADB 匹配</strong> 对新手用户而言有一点复杂的初始步骤\n幸运的是，该步骤并不总是每次都需要进行。<li><p><strong>.</strong><span>连接到 ADB</span>\n每次你重启手机后都需要进行该操作。App Manager\n在多数设备上也可以自动完成此步骤。</ol><section id=subsec:enable-developer-options-and-usb-debugging class=level3 data-number=3.2.1><h3 data-number=3.2.1><span class=header-section-number>3.2.1</span>\n<a href=#toc:subsec:enable-developer-options-and-usb-debugging>启用开发者选项和\nUSB 调试</a><a href=#subsec:enable-developer-options-and-usb-debugging class=anchor aria-hidden=true></a></h3><p>参阅 §<a href=#subsec:enable-developer-options data-reference-type=ref data-reference=subsec:enable-developer-options>3.1.1</a><span>启用开发者选项</span>\n和 §<a href=#subsec:enable-usb-debugging data-reference-type=ref data-reference=subsec:enable-usb-debugging>3.1.2</a><span>启用 USB\n调试</span>。</section><section id=subsec:enable-wireless-debugging class=level3 data-number=3.2.2><h3 data-number=3.2.2><span class=header-section-number>3.2.2</span>\n<a href=#toc:subsec:enable-wireless-debugging>启用无线调试</a><a href=#subsec:enable-wireless-debugging class=anchor aria-hidden=true></a></h3><p>在 <strong>开发者选项</strong> 页面，找到 <strong>无线调试</strong>\n并单击以打开它。 在新打开的页面中，打开 <em>使用无线调试</em>\n。取决于你的操作系统，你可能会看到一个提示对话框，要求你验证你的决定。\n若遇到此情况，请单击 <em>允许</em> 。<div class=\"amalert tip\"><p><strong><em>提示.</em></strong><p>为了更便于访问，你可能想将 <strong>无线调试</strong> 添加到通知块部件\n(快速设置磁贴)。 要做到这一点，请找到 <strong>开发者选项</strong> 页面的\n<strong>快速设置开发者磁贴</strong> ，单击以打开它。 在新窗口中，启用\n<em>无线调试</em>。然而该选项在大多数操作系统中不可用。\n如果你没看到这个设置，你可以在磁贴自定义面板中找到\n<strong>无线调试</strong> 磁贴。</div></section><section id=subsec:pair-adb-with-app-manager class=level3 data-number=3.2.3><h3 data-number=3.2.3><span class=header-section-number>3.2.3</span>\n<a href=#toc:subsec:pair-adb-with-app-manager>用 App Manager 匹配\nADB</a><a href=#subsec:pair-adb-with-app-manager class=anchor aria-hidden=true></a></h3><p>在 App Manager 中，转到 <strong>设置</strong> > <a href=#subsec:mode-of-operation>操作模式</a> ，接着开启\n<em>无线调试</em>。启用后，App Manager 会试着自动建立\n无线调试连接，如果先前未配对，那么该尝试会失败。尝试失败后，\n应用会请你连接或配对 ADB。选择<em>配对</em> 会出现新的对话框。\n对话框会让你转到 <strong>无线调试</strong> 页面。<div class=\"amalert tip\"><p><strong><em>注.</em></strong><p>截至 v4.0.0 版， App Manger 使用通知提示进行配对。因而，如果你停用了\nApp Manager 的通知权限，你必须先启用它。.</div><p>在<strong>无线调试</strong> 页面， 选择\n<strong>用配对码配对设备</strong>. 之后会展示\n一个包含配对码的对话框。一个请求配对码的通知也会几乎立马变得可见。\n将配对码输入通知中的输入框， 单击 <em>配对</em>。如配对成功，App Manager\n会显示 “已配对” 的消息通知， <strong>无线调试</strong>\n页中的对话框将被自动 忽略。你也可以在相同页面中看到 App Manager 被列为\nADB 客户端。<div class=\"amalert tip\"><p><strong><em>注意.</em></strong><p>如果你有一段时间不在 ADB 模式下使用 App Manager，那么 App Manager\n可能会从 Adb\n客户端列表中被删除。如果出现这种情况，你必须重复以上步骤。</div></section><section id=subsec:connect-app-manager-to-adb class=level3 data-number=3.2.4><h3 data-number=3.2.4><span class=header-section-number>3.2.4</span>\n<a href=#toc:subsec:connect-app-manager-to-adb>连接 App Manager 到\nADB</a><a href=#subsec:connect-app-manager-to-adb class=anchor aria-hidden=true></a></h3><p>若运行模式设置为 <em>自动</em>, <em>通过 TCP 启动的 ADB</em> 或\n<em>无线调试</em>， App Manager 应该能够自动连接到 ADB。\n若并非如此，则在<strong>设置</strong> > <a href=#subsec:mode-of-operation>操作模式</a> 中选择 <em>无线调试</em>\n。 若 App Manager 无法检测或连接到 ADB ，\n则会显示一个提示对话框以用于连接或配对 ADB 。 选择 <em>连接</em> 。<p>现在，从 Android 设置中转到 <strong>无线调试</strong>\n页面，记下页面显示的端口号。 在 App Manager 的提示对话框中，\n用你记下的端口号替换当前端口号，然后点击 <em>连接</em> 。<p>一旦成功建立连接，你就能够禁用 Android 设置的\n<strong>无线调试</strong>。<div class=\"amalert danger\"><p><strong><em>小心.</em></strong><p>不要禁用 <strong>USB 调试</strong> 或 §<a href=#subsec:enable-developer-options-and-usb-debugging data-reference-type=ref data-reference=subsec:enable-developer-options-and-usb-debugging>3.2.1</a><span>启用开发者选项和\nUSB 调试</span> 提及的任何附加选项。 一旦禁用，App Manager\n使用的远程服务器会被终止，你可能不得不重新开始。</div></section></section><section id=sec:backup-restore class=level2 data-number=3.3><h2 data-number=3.3><span class=header-section-number>3.3</span> <a href=#toc:sec:backup-restore>备份/恢复</a><a href=#sec:backup-restore class=anchor aria-hidden=true></a></h2><p>App Manager 具有从零开始的现代、高级和易于使用的备份/还原系统实现。\n可能仅本应用有能力 同时还原应用程序和数据以及你在 App Manager\n内配置的权限和规则。 你还可以选择多次备份应用程序 (使用自定义名称)\n或为所有用户进行备份。<div class=seealso><p><em>另见:</em><ul class=incremental><li><p><a href=#subsec:1-click-back-up>一键操作：备份</a><li><p><a href=#subsec:1-click-restore>一键操作：还原</a></ul></div><section id=subsec:backup-location class=level3 data-number=3.3.1><h3 data-number=3.3.1><span class=header-section-number>3.3.1</span>\n<a href=#toc:subsec:backup-location>位置</a><a href=#subsec:backup-location class=anchor aria-hidden=true></a></h3><p>备份/还原是 <a href=#subsec:batch-operations>批处理操作</a>\n的一部分。 它也位于 <a href=#subsec:app-info-tab>应用信息标签页</a> 的\n<a href=#subsubsec:app-info-options-menu>选项菜单</a> 中。 Clicking on\n<strong>Backup/Restore</strong> opens the <strong>Backup\nOptions</strong>. 默认情况下，备份存放在\n<code>/storage/emulated/0/AppManager</code> 。 你可以在 <a href=#subsubsec:backup-volume>设置页面</a> 配置自定义的备份位置。\n无论如何配置，备份都会存放在所选卷的 <code>AppManager</code>\n文件夹。<div class=\"amalert tip\"><p><strong><em>注意.</em></strong><p>若一个或多个应用程序并没有任何备份， 则不会显示 <strong>还原</strong>\n和 <strong>删除备份</strong> 选项。</div></section><section id=subsec:backup-restore-backup-options class=level3 data-number=3.3.2><h3 data-number=3.3.2><span class=header-section-number>3.3.2</span>\n<a href=#toc:subsec:backup-restore-backup-options>备份选项</a><a href=#subsec:backup-restore-backup-options class=anchor aria-hidden=true></a></h3><p>你可以通过备份选项 (内部称为备份标志) 自定义云端备份。\n然而，在将来的备份中不会记得这些自定义设置。 如果你想定制此对话框，在 <a href=#sec:settings-page>设置页面</a> 中使用 <a href=#subsubsec:settings-backup-options>备份选项</a>。<p>下面给出了备份选项的完整描述：<ul class=incremental><li><p><strong>APK 文件</strong> 是否备份 APK 文件。 这包括 <em>Base\nAPK</em> 文件以及 <code>APK 分包</code> 文件 (如果有)。<li><p><strong>内部数据</strong> 是否备份内部数据目录。 这些目录位于\n<code>/data/user/&lt;用户ID></code> 以及 (对 Android 7 及更高版本)\n<code>/data/user_de/&lt;用户ID></code>.<li><p><strong>外部数据</strong> 是否备份位于内部存储和SD 卡 (如果有)\n的数据目录。 外部数据目录通常包括非必要的应用数据或媒体文件\n(而不是使用专用的媒体文件夹)，若选择备份则可能增加备份文件的大小。\n然而，对一些应用来说可能是有必要的。 尽管默认情况下不会选中该项\n(因为它可能会显著增加备份文件的大小)，你可能需要检查此项以确保能够顺利还原你的备份。<div class=\"amalert warning\"><p><strong><em>小心.</em></strong><p>若你要备份外部数据文件夹，则应该总是备份内部数据文件夹。\n然而，如果所讨论的应用会从网络下载大量资源，那么仅备份外部文件夹也会很有用。</div><li><p><strong>OBB 和媒体</strong> 是否备份或还原 OBB 和位于 外部存储或\nSD 卡的媒体。\n这对实际使用这些文件夹的游戏和图形软件而言很有用。<li><p><strong>缓存</strong> Android 应用在每个数据目录 (内部和外部)\n中都有多个缓存目录。 有两种类型的缓存： <strong>缓存 (Cache)</strong> 和\n<strong>代码缓存 (Code Cache)</strong>。\n禁用此选项会将这两个缓存目录从所有数据目录中排除。\n一般情况下建议排除缓存目录，因为大多数应用程序并不会定期清除缓存，缓存通常是由操作系统自身处理。\n像 Telegram\n之类的应用可能会使用非常大的缓存(由存储空间决定)，这显著增加了备份文件大小。\n当该项被禁用时，App Manager 也会忽略 <strong>no_backup</strong>\n(无备份)目录。<li><p><strong>额外信息</strong>\n备份/还原应用权限、网络规则、电池优化、SSAID，等等，默认启用。\n注意：阻止规则在还原应用的额外信息 <em>后</em> 应用。\n所以，如果某个条目在两个地方(阻止规则和额外信息备份)同时存在，那么它将会被覆盖。(即会使用源自阻止规则的条目)。<li><p><strong>规则</strong> 你可以通过该选项备份在 App Manager\n内配置的阻止规则。 若你通过 App Manager\n配置了权限或阻止了一些组件，则当你启用该选项时，\n这些规则也会被备份或还原。<li><p><strong>多重备份</strong> 这是否为多重备份。\n默认情况下，备份使用其用户 ID 保存。 启用该选项将允许你创建多个备份。\n这些备份使用当前的时间日期作为默认备份名称，但你也可以指定自定义备份名称。\n当你点击 <strong>备份</strong>\n按钮时，使用输入框以自定义备份名称。<li><p><strong>自定义用户</strong>\n为所选的用户进行备份或还原，而不仅仅是当前用户。\n该选项仅在系统有多个用户的情况下显示。<li><p><strong>跳过签名检查</strong>\n当进行备份时，会生成每个文件的检验和 (以及基础 APK 文件的签名证书)\n并保存在 <code>checksums.txt</code> 文件中。\n当你还原备份时，会再度生成检验和，并用于匹配保存在先前提及的文件内的检验和。\n启用此选项以禁用签名检查。 该选项仅在你恢复备份时被应用\n(即启用该选项仅禁用恢复时的签名检查)。\n无论此处如何设置，备份时始终会生成用于签名检查的检验和。<div class=\"amalert warning\"><p><strong><em>小心.</em></strong><p>你应该总是禁用此选项，以确保你的备份不被任何第三方应用程序修改。\n然而仅在你启用了加密才起作用。</div></ul><div class=seealso-inline><p><em>另见: <span><a href=#subsubsec:settings-encryption>设置：加密</a></span></em></div></section><section id=subsec:backup-restore-backup class=level3 data-number=3.3.3><h3 data-number=3.3.3><span class=header-section-number>3.3.3</span>\n<a href=#toc:subsec:backup-restore-backup>备份</a><a href=#subsec:backup-restore-backup class=anchor aria-hidden=true></a></h3><p>备份功能会遵守除了 <strong>跳过签名检查</strong> 以外的所有备份选项。\n若基本备份 (即并未选择<strong>多重备份</strong> 选项)\n已存在，由于备份会被覆盖，你会看到一条警告信息。 若设置了\n<strong>多重备份</strong>\n，你需要在选项中输入(指定)备份名称，或者你也可以留空以使用当前日期时间作为备份名称。</section><section id=subsec:backup-restore-restore class=level3 data-number=3.3.4><h3 data-number=3.3.4><span class=header-section-number>3.3.4</span>\n<a href=#toc:subsec:backup-restore-restore>恢复</a><a href=#subsec:backup-restore-restore class=anchor aria-hidden=true></a></h3><p>还原会遵守全部备份选项，并在出现以下情况时失败：若设置了 <strong>APK\n文件</strong> 选项， 备份内容却不包括 APK\n文件选项设定的内容，或者其他情况下，未安装该应用程序。\n当为多个应用还原备份时，你只能选择还原基础备份 (参阅 <a href=#subsec:backup-restore-backup>备份</a> 章节以了解更多)。\n然而，当为单个应用程序还原备份时，你需要通过选项选择还原哪个备份。\n若设定了 <strong>所有用户</strong> 选项，则 App Manager\n将在后一种情况为所有用户还原所选备份。但是在前一种情况中，将会为各个用户还原基础备份。<div class=\"amalert tip\"><p><strong><em>注意.</em></strong><p>使用存储访问框架 (Storage Access Framework 即 SAF)、SSAID 或 Android\n密钥库只有在还原并立即重新启动后正常工作。</div></section><section id=subsec:backup-restore-delete-backup class=level3 data-number=3.3.5><h3 data-number=3.3.5><span class=header-section-number>3.3.5</span>\n<a href=#toc:subsec:backup-restore-delete-backup>删除备份</a><a href=#subsec:backup-restore-delete-backup class=anchor aria-hidden=true></a></h3><p>删除备份仅遵守 <strong>所有用户</strong>\n选项。当被选中时，仅会提示后删除所有用户的基础备份。\n当为单个应用删除备份时，会显示另外一个可供你选择要删除的备份的对话框。</section></section><section id=sec:automating-tasks class=level2 data-number=3.4><h2 data-number=3.4><span class=header-section-number>3.4</span> <a href=#toc:sec:automating-tasks>自动任务</a><a href=#sec:automating-tasks class=anchor aria-hidden=true></a></h2><p>可以通过诸如 <strong>Automation</strong> 或 <strong>Tasker</strong>\n之类的第三方应用程序触发在 App Manager 设置的配置文件。 通常情况下用\n<code>意图</code> 触发这类操作。<section id=subsec:generating-authorization-key class=level3 data-number=3.4.1><h3 data-number=3.4.1><span class=header-section-number>3.4.1</span>\n<a href=#toc:subsec:generating-authorization-key>生成授权密钥</a><a href=#subsec:generating-authorization-key class=anchor aria-hidden=true></a></h3><p>为了确保适当的安全性，需要授权密钥。前往 <strong>设置</strong>\n页面，接着是 <strong>隐私</strong> > <strong>授权管理器</strong>\n以生成授权密钥。\n若并未生成过授权密钥，则会自动生成。该密钥可根据需求重新生成。<div class=\"amalert danger\"><p><strong><em>小心.</em></strong><p>重新生成授权密钥可能会产生一些副作用，比如说令所有先前配置的意图失效。</div></section><section id=subsec:at:general-configuration class=level3 data-number=3.4.2><h3 data-number=3.4.2><span class=header-section-number>3.4.2</span>\n<a href=#toc:subsec:at:general-configuration>配置任务</a><a href=#subsec:at:general-configuration class=anchor aria-hidden=true></a></h3><p>活动\n<code>io.github.muntashirakon.AppManager.crypto.auth.AuthFeatureDemultiplexer</code>\n负责处理所有的自动化意图。 发送意图到该活动，让 App Manager 通过重定向\n<code>意图</code> 到指定活动或服务的方式执行指定操作。<section id=需求的附加选项 class=level4 data-number=3.4.2.1><h4 data-number=3.4.2.1><span class=header-section-number>3.4.2.1</span> 需求的附加选项<a href=#需求的附加选项 class=anchor aria-hidden=true></a></h4><p>所有条件都需要两种主要的附加功能：密钥名称和数据类型。如下所示：<ol class=incremental><li><p><strong><code>auth</code>.</strong> (字符串值)\n前一节所述的授权密钥。<li><p><strong><code>feature</code>.</strong> (字符串值)\n功能名称。下一节将介绍受支持的功能。</ol></section></section><section id=subsec:at:features class=level3 data-number=3.4.3><h3 data-number=3.4.3><span class=header-section-number>3.4.3</span>\n<a href=#toc:subsec:at:features>功能特性</a><a href=#subsec:at:features class=anchor aria-hidden=true></a></h3><p>目前 App Manager 支持的一个功能，即 <code>配置文件</code>。</section><section id=subsec:triggering-a-profile class=level3 data-number=3.4.4><h3 data-number=3.4.4><span class=header-section-number>3.4.4</span>\n<a href=#toc:subsec:triggering-a-profile>触发配置文件</a><a href=#subsec:triggering-a-profile class=anchor aria-hidden=true></a></h3><p>为了触发配置文件， <code>feature</code> (功能) 字段必须具有\n<code>profile</code> (配置文件) 值。 此外，接下来的 extras (额外选项)\n可包括：<ol class=incremental><li><p><strong><code>prof</code>.</strong> (字符串值 – 必须) 显示在 <a href=#sec:profiles-page>配置页面</a> 的配置名称。<li><p><strong><code>state</code>.</strong> (字符串值 – 可选)\n配置文件的状态 – 目前 <code>on</code> (启用) 或者 <code>off</code>\n(禁用) – 如文档所述。. 若此时未设置额外选项，则 App Manager\n会提示需要选择的状态。 因此，为了完全自动化，应该设置该选项。</ol></section></section><section id=sec:net-policy class=level2 data-number=3.5><h2 data-number=3.5><span class=header-section-number>3.5</span> <a href=#toc:sec:net-policy>连网策略</a><a href=#sec:net-policy class=anchor aria-hidden=true></a></h2><p>网络策略 (Network policies)，简写 <strong>Network policy</strong>。\n网络策略通常位于 Android 设置的应用详情页面中的 <strong>移动数据和\nWLAN</strong> 这一节的下面。 该页面中并非所有策略会被授权使用\n(比如三星)，以及由于缺少文档，并非所有设置都能被很好地理解。 App Manager\n可以显示所有在 <a href=https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/net/NetworkPolicyManager.java>网络策略管理器</a>\n声明的网络策略。 对 App Manager 而言位置的策略会被加上 <em>Unknown</em>\n前缀以及十六进制格式的策略常量名称和编号。 未知策略应报告给 App Manager\n以供纳入。<p>网络策略允许用户配置应用的某些网络行为，而不是直接修改 IP\n地址表和/或者使用防火墙应用。 然而，其提供的功能很大程度上依赖于 Android\n版本和 ROM。已知网络规则列表如下所示：<ol class=incremental><li><p><strong>无</strong> 或 <strong><code>POLICY_NONE</code></strong>:\n(AOSP) 并未设置特定的网络策略。\n系统仍可通过应用程序的性质分配规则。<li><p><strong>禁止在后台使用移动数据 (流量计费的网络)</strong> 或\n<strong><code>POLICY_REJECT_METERED_BACKGROUND</code></strong>: (AOSP)\n当应用在后台运行时，禁止使用移动数据 (流量计费的网络)。<li><p><strong>允许后台使用移动数据\n(流量计费的网络)，甚至在流量节省程序开启时</strong> 或\n<strong><code>POLICY_ALLOW_METERED_BACKGROUND</code></strong>: (AOSP)\n允许后台使用移动数据\n(流量计费的网络)，甚至是启用流量节省模式的情况下。<li><p><strong>禁止移动数据 (蜂窝数据)</strong> 或\n<strong><code>POLICY_REJECT_CELLULAR</code></strong> (Android 11+) 或\n<strong><code>POLICY_REJECT_ON_DATA</code></strong> (直到 Android 10):\n(Lineage OS) 禁止使用移动/蜂窝数据。\n向配置的应用程序发出网络不可用的信号，就像未激活移动数据\n(蜂窝数据)一样。<li><p><strong>禁止 VPN 数据</strong> 或\n<strong><code>POLICY_REJECT_VPN</code></strong> (Android 11+) 或\n<strong><code>POLICY_REJECT_ON_VPN</code></strong> (直到 Android 10):\n(Lineage OS) 禁止使用 VPN 数据。\n向配置的应用程序发出网络不可用的信号，就像未激活 VPN 一样。<li><p><strong>禁止 Wi-Fi 数据</strong> 或\n<strong><code>POLICY_REJECT_WIFI</code></strong> (Android 11+) 或\n<strong><code>POLICY_REJECT_ON_WLAN</code></strong> (直到 Android 10):\n(Lineage OS) 禁止使用 Wi-Fi 数据。\n向配置的应用程序发出网络不可用的信号，就像该设备未连接到 Wi-Fi\n网络一样。<li><p><strong>禁用网络访问</strong> 或\n<strong><code>POLICY_REJECT_ALL</code></strong> (Android 11+) 或\n<strong><code>POLICY_NETWORK_ISOLATED</code></strong> (直到 Android 10):\n(Lineage OS) 禁止所有情况下的网络访问。\n这与执行上述其他三项策略不同，推荐对可疑/狡诈的应用而言使用该策略。.\n若该策略被执行，则没有必要执行其他策略。<li><p><strong><code>POLICY_ALLOW_METERED_IN_ROAMING</code></strong>:\n(三星) 可能是在漫游时允许使用移动数据 (流量计费的网络)。\n目前不知道其确切含义。<li><p><strong><code>POLICY_ALLOW_WHITELIST_IN_ROAMING</code></strong>:\n(三星) 可能是在漫游时允许使用网络。 目前不知道其确切含义。<li><p><strong>禁止使用移动数据 (流量计费的网络)</strong> 或\n<strong><code>POLICY_REJECT_METERED</code></strong>: (摩托罗拉)\n若是移动数据 (流量计费的网络) 则禁止使用网络。<li><p><strong>禁止使用后台数据</strong> 或\n<strong><code>POLICY_REJECT_BACKGROUND</code></strong>: (摩托罗拉)\n禁止后台使用数据。<li><p><strong>禁用网络访问</strong> or\n<strong><code>POLICY_REJECT_ALL</code></strong>: (摩托罗拉)\n禁止所有的网络访问。 与 Lineage OS 类似，会通过 iptables (防火墙)\n阻止网络连接。但不知道它是否向配置的应用程序发出网络不可用的信号。</ol><div class=\"amalert tip\"><p><strong><em>注释.</em></strong><p>相应的 Lineage OS 补丁如下：<ol class=incremental><li><p><a href=https://github.com/LineageOS/android_frameworks_base/commit/a04932bafbbf7d99efd18276152cc2c9c9b2073e>fw/b:\nSquash of app fw restriction commits</a><li><p><a href=https://github.com/LineageOS/android_frameworks_base/commit/02c8c82854348f52afe2199f310f44b5f578b5b8>fw/b:\nAdd support for per app network isolation</a></ol></div></section></section><section id=ch:faq class=level1 data-number=4><h1 data-number=4><span class=header-section-number>4</span> <a href=#toc:ch:faq>常见问题</a><a href=#ch:faq class=anchor aria-hidden=true></a></h1><section id=sec:faq:app-components class=level2 data-number=4.1><h2 data-number=4.1><span class=header-section-number>4.1</span> <a href=#toc:sec:faq:app-components>应用组件</a><a href=#sec:faq:app-components class=anchor aria-hidden=true></a></h2><section id=subsec:faq:what-are-app-components class=level3 data-number=4.1.1><h3 data-number=4.1.1><span class=header-section-number>4.1.1</span>\n<a href=#toc:subsec:faq:what-are-app-components>什么是应用组件？</a><a href=#subsec:faq:what-are-app-components class=anchor aria-hidden=true></a></h3><p>活动、服务、广播接收器 (或者仅接收器) 和内容提供者 (或仅提供者)\n统称为应用程序组件。 技术上来说，它们都继承了 <a href=https://developer.android.com/reference/android/content/pm/ComponentInfo>ComponentInfo</a>\n类 并可以通过意图被启动。</section><section id=subsec:faq:how-components-blocked class=level3 data-number=4.1.2><h3 data-number=4.1.2><span class=header-section-number>4.1.2</span>\n<a href=#toc:subsec:faq:how-components-blocked>追踪器和其他组件在App\nManager中是如何被禁用的？其局限性是什么？</a><a href=#subsec:faq:how-components-blocked class=anchor aria-hidden=true></a></h3><p>App Manager 通常使用一个称作 <a href=https://carteryagemann.com/pages/android-intent-firewall.html>Intent\nFirewall (IFW)，意图防火墙</a> 的方法阻止应用程序组件 (或跟踪器组件)，\n它比其他诸如 <em>pm</em> (PackageManager，包管理器)、 <a href=https://github.com/RikkaApps/Shizuku>Shizuku</a>\n或其他任何使用包管理器启用或禁用组件的办法更优秀。\n若组件被后者的办法禁用，应用程序自身可以检测到组件被阻止并能重新启用，因为应用程序有自身组件的完整访问权限。\n(许多欺骗性应用程序这样做，实际上是为了让跟踪器组件保持不被阻止的状态。)\n另一方面，意图防火墙 (IFW)\n是一个真正的防火墙，应用程序无法检测自身组件是否被阻止。 这也是 App\nManager 使用术语 <em>阻止</em> 而非 <em>禁用</em> 的原因。<p>就算是意图防火墙也有一些局限性，主要适用于系统应用程序：<ul class=incremental><li><p>相关应用程序被系统加入白名单。\n即没有这些应用程序，系统将无法正常运行，并可能导致随机崩溃。\n这些应用程序包括但不限于 Android 系统、系统界面、电话服务。\n即使禁用或阻止，它们仍然会运行。<li><p>另外一部分系统应用程序或系统进程通过进程间通信 (Interprocess\nCommunication，IPC) 激活了被加入白名单的系统应用程序的应用程序组件。\n此情况下组件会被激活，并无视组件的阻止状态甚至是整个应用程序被禁用。\n若有不需要的系统应用程序，阻止其运行的唯一办法就是摆脱\n(卸载/移除)它。</ul></section><section id=subsec:faq:components-blocked-by-others class=level3 data-number=4.1.3><h3 data-number=4.1.3><span class=header-section-number>4.1.3</span>\n<a href=#toc:subsec:faq:components-blocked-by-others>被其他工具禁用的应用程序组件是否保留在App\nManager中？</a><a href=#subsec:faq:components-blocked-by-others class=anchor aria-hidden=true></a></h3><p><strong>不。</strong>\n但是被系统或任何其他工具阻止的应用程序组件会在<a href=#subsec:component-tabs>组件标签页</a> 显示。 这些规则可从 <a href=#par:import-existing-rules>设置</a> 导入。 然而，App Manager\n无法区分组件是被第三方工具阻止还是被系统阻止。\n因此，在导入页面中显示的应用程序列表应谨慎选择。</section><section id=subsec:faq:components-reblocked-in-am class=level3 data-number=4.1.4><h3 data-number=4.1.4><span class=header-section-number>4.1.4</span>\n<a href=#toc:subsec:faq:components-reblocked-in-am>现在被 App Manager\n拦截但先前被其他工具禁用的组件会发生什么？</a><a href=#subsec:faq:components-reblocked-in-am class=anchor aria-hidden=true></a></h3><p><em>如果请求，App Manager 会再次阻止组件。</em>\n解除阻止的情况下，它们将恢复到应用程序清单中指定的默认状态。\n但是如果组件是被 <a href=https://www.myandroidtools.com>MyAndroidTools\n(MAT)</a> 使用意图防火墙 (IFW) 阻止， 由于 MAT\n使用不同的格式，它们不会被 App Manager 解除阻止。\n为了修复这个问题，首先需要从 <a href=#par:import-existing-rules>设置</a> 导入规则 这种情况下，MAT\n的配置文件会被永久移除。</section><section id=subsec:faq:what-is-instant-component-blocking class=level3 data-number=4.1.5><h3 data-number=4.1.5><span class=header-section-number>4.1.5</span>\n<a href=#toc:subsec:faq:what-is-instant-component-blocking>什么是即时组件禁用？</a><a href=#subsec:faq:what-is-instant-component-blocking class=anchor aria-hidden=true></a></h3><p>当你在 <a href=#sec:app-details-page>应用详情页</a>\n中阻止组件时，默认情况下阻止规则不会立刻生效。 仅在你使用顶部右侧菜单的\n<em>应用规则</em> 选项时，阻止规则才会生效。 若你启用 <a href=#subsubsec:instant-component-blocking>即时阻止组件</a>\n选项，则当你阻止组件时，阻止规则会立刻生效。\n若你选择阻止跟踪器组件，阻止规则会自动生效，该选项设置会被忽略。\n你也可以通过在应用详情页内同一菜单简单点击 <em>移除规则</em>\n为该应用程序移除阻止规则。 由于默认行为使你更好地控制应用程序，保持选项\n<em>即时阻止组件</em> 选项为禁用状态更好。</section><section id=subsec:tracker-classes-versus-tracker-components class=level3 data-number=4.1.6><h3 data-number=4.1.6><span class=header-section-number>4.1.6</span>\n<a href=#toc:subsec:tracker-classes-versus-tracker-components>跟踪器类与跟踪器组件</a><a href=#subsec:tracker-classes-versus-tracker-components class=anchor aria-hidden=true></a></h3><p>所有应用程序组件都是类，但并非所有类都是组件。事实上，只有少数类是组件。\n话虽如此， <a href=#sec:scanner-page>扫描页面</a>\n展示的是跟踪器列表以及类的数量，而并非只是组件数。\n在所有其他页面，跟踪器和跟踪器组件是同一个意思，都用于表示跟踪器。\n即：阻止 tracker 是指阻止跟踪器组件，而不是跟踪器类。<div class=\"amalert tip\"><p><strong><em>信息.</em></strong><p>无法阻止并非组件的跟踪器类。它们仅能在编辑应用程序自身时被移除。</div></section></section><section id=sec:faq:adb-over-tcp class=level2 data-number=4.2><h2 data-number=4.2><span class=header-section-number>4.2</span> <a href=#toc:sec:faq:adb-over-tcp>ADB over TCP (经由TCP的ADB)</a><a href=#sec:faq:adb-over-tcp class=anchor aria-hidden=true></a></h2><section id=subsec:faq:enable-adb-on-every-restart class=level3 data-number=4.2.1><h3 data-number=4.2.1><span class=header-section-number>4.2.1</span>\n<a href=#toc:subsec:faq:enable-adb-on-every-restart>我必须在每次重启后启用ADB\nover TCP吗？</a><a href=#subsec:faq:enable-adb-on-every-restart class=anchor aria-hidden=true></a></h3><p>很不幸的是，是的。这是因为响应 ADB 连接的 ADB daemon (ADB 守护进程)\n也会在重新启动后重新开始。 而这并不会重新启用通过 TCP运行的 ADB。</section><section id=subsec:faq:usb-debugging class=level3 data-number=4.2.2><h3 data-number=4.2.2><span class=header-section-number>4.2.2</span>\n<a href=#toc:subsec:faq:usb-debugging>无法启用 USB\n调试，怎么办？</a><a href=#subsec:faq:usb-debugging class=anchor aria-hidden=true></a></h3><p>参阅位于 Chapter <a href=#ch:guides data-reference-type=ref data-reference=ch:guides>3</a><span>指引</span> 的 §<a href=#subsec:enable-usb-debugging data-reference-type=ref data-reference=subsec:enable-usb-debugging>3.1.2</a><span>启用 USB\n调试</span> 。</section><section id=subsec:faq:block-components-using-adb class=level3 data-number=4.2.3><h3 data-number=4.2.3><span class=header-section-number>4.2.3</span>\n<a href=#toc:subsec:faq:block-components-using-adb>我可以使用 ADB over\nTCP 来禁用跟踪器或任何其他应用程序组件吗？</a><a href=#subsec:faq:block-components-using-adb class=anchor aria-hidden=true></a></h3><p>ADB 具有数量限制 <a href=https://github.com/aosp-mirror/platform_frameworks_base/blob/master/packages/Shell/AndroidManifest.xml>权限</a>\n而并非它们其中一个控制应用程序组件。 然而，<em>仅用于测试</em>\n的应用程序的组件可以通过 ADB进行控制。 若 App Manager\n检测到此类应用程序，则会自动启用阻止选项。</section><section id=subsec:faq:adb-features class=level3 data-number=4.2.4><h3 data-number=4.2.4><span class=header-section-number>4.2.4</span>\n<a href=#toc:subsec:faq:adb-features>哪些功能可以在ADB模式下使用？</a><a href=#subsec:faq:adb-features class=anchor aria-hidden=true></a></h3><p>在 ADB 模式下，受支持的功能会自动启用。\n受支持的功能包括禁用、强制停止、清除应用程序数据、授予或撤销应用操作\n(App Ops) 和权限等。 也可在无系统提示的情况下安装或卸载应用程序。</section></section><section id=sec:faq:miscellanea class=level2 data-number=4.3><h2 data-number=4.3><span class=header-section-number>4.3</span> <a href=#toc:sec:faq:miscellanea>杂项</a><a href=#sec:faq:miscellanea class=anchor aria-hidden=true></a></h2><section id=subsec:faq:no-root-no-harms class=level3 data-number=4.3.1><h3 data-number=4.3.1><span class=header-section-number>4.3.1</span>\n<a href=#toc:subsec:faq:no-root-no-harms>我不使用root/ADB，是否完全安全？</a><a href=#subsec:faq:no-root-no-harms class=anchor aria-hidden=true></a></h3><p>是的，App Manager 不能在无 Root 或 ADB时修改任何系统设置。</section><section id=subsec:faq:how-trackers-libs-updated class=level3 data-number=4.3.2><h3 data-number=4.3.2><span class=header-section-number>4.3.2</span>\n<a href=#toc:subsec:faq:how-trackers-libs-updated>跟踪器和库是如何更新的？</a><a href=#subsec:faq:how-trackers-libs-updated class=anchor aria-hidden=true></a></h3><p>在新版本发布前，会手动更新跟踪器和库。</section><section id=subsec:faq:apks-deleted-after-installed class=level3 data-number=4.3.3><h3 data-number=4.3.3><span class=header-section-number>4.3.3</span>\n<a href=#toc:subsec:faq:apks-deleted-after-installed>APK\n安装后是否被删除？</a><a href=#subsec:faq:apks-deleted-after-installed class=anchor aria-hidden=true></a></h3><p>不会，在安装后，APK 不会被 App Manager 删除。</section><section id=subsec:faq:shizuku-support class=level3 data-number=4.3.4><h3 data-number=4.3.4><span class=header-section-number>4.3.4</span>\n<a href=#toc:subsec:faq:shizuku-support>对于 Shizuku 有何计划？</a><a href=#subsec:faq:shizuku-support class=anchor aria-hidden=true></a></h3><p>现在 App Manager 使用隐藏 API 和执行特权代码变得更加复杂， 无法和 <a href=https://shizuku.rikka.app>Shizuku</a>\n之类的其他第三方应用程序集成。 不考虑在 App Manager 中集成 Shizuku\n(现在具有 Apache 2.0 协议) 的理由如下：<ol class=incremental><li><p>最初 Shizuku 是不自由软件，这也导致我 在 App Manager\n中使用了类似的方法来支持 Root 和 ADB。<li><p>App Manager 已经支持 Root 和 ADB，并且在某些情况下比 Shizuku\n更优秀。<li><p>主要功能依赖于第三方应用并不是一个好的设计理念选择。<li><p>集成 Shizuku 会增加 App Manager 的复杂性。</ol></section><section id=subsec:faq:what-are-bloatware class=level3 data-number=4.3.5><h3 data-number=4.3.5><span class=header-section-number>4.3.5</span>\n<a href=#toc:subsec:faq:what-are-bloatware>什么是预装(bloatware)软件以及如何删除？</a><a href=#subsec:faq:what-are-bloatware class=anchor aria-hidden=true></a></h3><p>臃肿软件（Bloatware）为不必要的预装应用，通常是系统应用。\n一些臃肿软件通常用来跟踪用户并收集它们可能为了获利而出售的用户数据。\n许多系统应用无需请求任何权限便可访问设备信息、联系人和消息数据，以及其他使用信息，\n比如手机使用习惯和存储在共享存储空间中的一切。<p>臃肿软件同样包括 Google 地图、Meta 出品的应用，以及Twitter/X，\n这些应用也可以在没有用户同意情况下跟踪和/或收集用户数据。 你可以在\nAndeoid 系统设置那里禁用这些应用的一些权限，\n但请知晓，系统设置藏有很多权限被安全研究者认为具潜在<em>危险性</em>\n（比如联网、传感器等）。<p>如果臃肿软件是用户应用，可以轻易从系统设置或AM进行卸载。\n而属于系统应用的臃肿应用没有特权是不可能卸载的。\n即使有特权也无法完全<em>卸载</em> 这样的系统应用， 因为它们位于\n<em>system</em> 分区，这是一个只读分区。 如果你有 root\n权限，你可以重新挂载这个分区来手动 <em>清除</em>\n这些应用，但这样做会破化系统的 OTA 更新，\n因为系统分区中的数据已经被修改。 有两种更新，一种是 delta\n更新（仅由两个系统版本间的差异构成，下载东西少）和完整更新。\n你仍能使用完整更新，但更新后臃肿软件又会出现，你不得不再次彻底清理它们。<p>另一个解决方案是通过系统设置或 AM 停用这些应用，\n但某些服务仍能在后台运行，\n因为它们可以被其他系统应用使用进程间通信（IPC）方式启动。\n一个可能的解决方案是停用所有臃肿软件，直到服务最终停止（在重启后）。\n不过，由于厂商对 ANdroid 框架所做的巨大改动，\n删除或停用某些臃肿软件可能导致系统 UI 崩溃甚至造成启动循环。 从 v4.0.0\n版本起，AM 有了一个新功能，叫做 <strong>Debloater</strong>，\n可以用作从专有权利的 Android\n操作系统中监控、停用，及删除臃肿软件的基础。<div class=\"amalert warning\"><p><strong><em>注意.</em></strong><p>多数情况下，你无法完全 debloat 设备。\n因此，建议你使用没有臃肿软件的定制 ROM，如 Graphene OS、Lineage OS\n或它们的衍生品。</div></section></section></section><section id=ch:specifications class=level1 data-number=5><h1 data-number=5><span class=header-section-number>5</span> <a href=#toc:ch:specifications>语法</a><a href=#ch:specifications class=anchor aria-hidden=true></a></h1><section id=sec:rules-specification class=level2 data-number=5.1><h2 data-number=5.1><span class=header-section-number>5.1</span> <a href=#toc:sec:rules-specification>规则语法</a><a href=#sec:rules-specification class=anchor aria-hidden=true></a></h2><section id=背景介绍 class=level3 data-number=5.1.1><h3 data-number=5.1.1><span class=header-section-number>5.1.1</span>\n<a href=#toc:背景介绍>背景介绍</a><a href=#背景介绍 class=anchor aria-hidden=true></a></h3><p>App Manager 目前支持阻止活动、广播接收器、内容提供者、服务、应用操作\n(App Ops) 和权限， 并且在将来可能会添加更多阻止选项。\n为了增加更多便携性，导入/导出所有的这些数据是有必要的。<p>由于数据库专门用于存储数据，维护数据库是最佳选择。 目前为止有多个\n<code>tsv</code> 文件，每个文件都有包名和 <code>.tsv</code> 扩展名。\n<code>RulesStorageManager</code> (规则存储管理器)\n类负责查询/处理相应的文件/数据库。\n由于这种抽象概念，将来在不更改整个项目设计的情况下切换到数据库或加密数据库系统会更加容易。\n目前所有的配置文件存储在\n<code>/data/data/io.github.muntashirakon.AppManager/Files/conf</code>。</section><section id=规则文件格式 class=level3 data-number=5.1.2><h3 data-number=5.1.2><span class=header-section-number>5.1.2</span>\n<a href=#toc:规则文件格式>规则文件格式</a><a href=#规则文件格式 class=anchor aria-hidden=true></a></h3><section id=内部 class=level4 data-number=5.1.2.1><h4 data-number=5.1.2.1><span class=header-section-number>5.1.2.1</span> 内部<a href=#内部 class=anchor aria-hidden=true></a></h4><p>下述格式在 App Manager 内部使用，且 <em>与外部格式不兼容。</em><pre><code> &lt;name&gt; &lt;type&gt; &lt;mode&gt;|&lt;component_status&gt;|&lt;is_granted&gt;</code></pre><p>此处：<ul class=incremental><li><p><code>&lt;name></code> – 组件/权限/应用操作 (App Ops) 名 (对于\nApp Ops，值可能为字符串或整数)<li><p><code>&lt;type></code> – <code>ACTIVITY</code>、\n<code>RECEIVER</code>、 <code>PROVIDER</code>、 <code>SERVICE</code>、\n<code>APP_OP</code>、 <code>PERMISSION</code>的其中一个<li><p><code>&lt;mode></code> – (用于App Ops) 相关的 <a href=#subsec:mode-constants>模式常量</a><li><p><code>&lt;component_status></code> – (用于组件) 组件状态<ul class=incremental><li><p><code>true</code> – 已应用组件 (<code>true</code>\n值因为兼容性被保留)<li><p><code>false</code> – 尚未应用组件，但将来会生效\n(<code>false</code> 值因为兼容性被保留)<li><p><code>unblocked</code> – 计划解除阻止的组件</ul><li><p><code>&lt;is_granted></code> – (用于权限)\n是否授予或撤销权限</ul></section><section id=外部 class=level4 data-number=5.1.2.2><h4 data-number=5.1.2.2><span class=header-section-number>5.1.2.2</span> 外部<a href=#外部 class=anchor aria-hidden=true></a></h4><p>外部格式用于 App Manager 导入或导出规则。<pre><code> &lt;package_name&gt; &lt;component_name&gt; &lt;type&gt; &lt;mode&gt;|&lt;component_status&gt;|&lt;is_granted&gt;</code></pre><p>除了第一项是包的名称外，其格式与上述 (内部格式) 基本相同。<div class=\"amalert danger\"><p><strong><em>小心.</em></strong><p>导出的规则具有与内部格式不同的格式， 不应该被直接复制到\n<strong>conf</strong> 文件夹。</div></section></section></section></section><section id=ch:changelogs class=level1 data-number=6><h1 data-number=6><span class=header-section-number>6</span> <a href=#toc:ch:changelogs>更新日志</a><a href=#ch:changelogs class=anchor aria-hidden=true></a></h1><section id=sec:v4.0.5-(445) class=level2 data-number=6.1><h2 data-number=6.1><span class=header-section-number>6.1</span> <a href=#toc:sec:v4.0.5-(445)>v4.0.5 (445)</a><a href=#sec:v4.0.5-(445) class=anchor aria-hidden=true></a></h2><ul class=incremental><li><p>Added option to allow installing the existing applications in the\ninstaller page<li><p>Display unsafe bloatware info<li><p>Display vector icon on the splash screen in Android 7.1 and\nearlier<li><p>Enabled “Clear data from uninstalled apps” to no-root users in\n1-click ops page<li><p>Enabled predictive back in Android 14 onwards<li><p>Improved accessibility by updating the content description of the\naction items<li><p>In app info tab, open “Open by default” setting in the “Open\nlinks” dialog<li><p>In debloater page, sort by app label (or app name) rather than\npackage name<li><p>Fixed freezing an app with “Remember for this app” turned\non<li><p>Fixed selecting texts in the list items due to framework\nbugs<li><p>Fixed setting app ops in custom ROMs with MIUI properties\ninjected<li><p>Fixed updating profile modification status when an application is\ndeleted from the list<li><p>Handled common colors and cursor movements in terminal\noutput.</ul></section><section id=sec:v4.0.4-(444) class=level2 data-number=6.2><h2 data-number=6.2><span class=header-section-number>6.2</span> <a href=#toc:sec:v4.0.4-(444)>v4.0.4 (444)</a><a href=#sec:v4.0.4-(444) class=anchor aria-hidden=true></a></h2><ul class=incremental><li><p>Optimized searching and filtering in the main page<li><p>Adopted sentence-case for the titles<li><p>Use the configured state to execute a profile for the simple\nshortcuts<li><p>Prevented crashing while searching throughout the\napplication<li><p>Fixed integer overflow issue in the tar compression.</ul></section><section id=sec:v4.0.3-(443) class=level2 data-number=6.3><h2 data-number=6.3><span class=header-section-number>6.3</span> <a href=#toc:sec:v4.0.3-(443)>v4.0.3 (443)</a><a href=#sec:v4.0.3-(443) class=anchor aria-hidden=true></a></h2><ul class=incremental><li><p>Updated translations<li><p>Improved handling the list items throughout App Manager<li><p>Fixed a regression error in file manager<li><p>Fixed spinners in the App Usage and the System Config\npages.</ul></section><section id=sec:v4.0.2-(442) class=level2 data-number=6.4><h2 data-number=6.4><span class=header-section-number>6.4</span> <a href=#toc:sec:v4.0.2-(442)>v4.0.2 (442)</a><a href=#sec:v4.0.2-(442) class=anchor aria-hidden=true></a></h2><ul class=incremental><li><p>Updated bloatware<li><p>Fixed fetching applications in multi-user environment in no-root\nmode<li><p>Fixed opening <code>app-manager</code> URLs from the web\nbrowsers<li><p>Fixed updating SSAID<li><p>Prevented a crash in Android &lt; 9.0 that occurs due to invalid\napp ops.</ul></section><section id=sec:v4.0.1-(441) class=level2 data-number=6.5><h2 data-number=6.5><span class=header-section-number>6.5</span> <a href=#toc:sec:v4.0.1-(441)>v4.0.1 (441)</a><a href=#sec:v4.0.1-(441) class=anchor aria-hidden=true></a></h2><section id=overlay-management class=level3 data-number=6.5.1><h3 data-number=6.5.1><span class=header-section-number>6.5.1</span>\n<a href=#toc:overlay-management>Overlay management</a><a href=#overlay-management class=anchor aria-hidden=true></a></h3><p>In the App Details page, a new tab “Overlays” is added where per-app\noverlays are displayed. They can also be enabled or disabled using the\ntoggle button. In addition, if the App Details page of an overlay\npackage is opened, a “Overlay” tag will be displayed in the App Info\ntab. Clicking on the tag opens a dialog containing additional info along\nwith a button that allows navigating to the App Details page of the\noverlay target package if it is installed.<section id=known-limitation class=level5 data-number=6.5.1.0.1><h5 data-number=6.5.1.0.1><span class=header-section-number>6.5.1.0.1</span> Known limitation<a href=#known-limitation class=anchor aria-hidden=true></a></h5><p>At present, it only works for root/ADB users in Android 8 (Oreo) and\nlater.</section></section><section id=unfreeze-option-in-activity-shortcuts class=level3 data-number=6.5.2><h3 data-number=6.5.2><span class=header-section-number>6.5.2</span>\n<a href=#toc:unfreeze-option-in-activity-shortcuts>Unfreeze option in\nactivity shortcuts</a><a href=#unfreeze-option-in-activity-shortcuts class=anchor aria-hidden=true></a></h3><p>If the application corresponding to the shortcut being launched is\nfrozen, App Manager will now offer you to unfreeze the app temporarily\nso that the shortcut can be launched. The app will be frozen again once\nthe screen is locked.<section id=known-limitation-1 class=level5 data-number=6.5.2.0.1><h5 data-number=6.5.2.0.1><span class=header-section-number>6.5.2.0.1</span> Known limitation<a href=#known-limitation-1 class=anchor aria-hidden=true></a></h5><p>This may not work on devices without a screen lock or if the screen\nis locked some time after the display goes off.</section></section><section id=market-like-url-support class=level3 data-number=6.5.3><h3 data-number=6.5.3><span class=header-section-number>6.5.3</span>\n<a href=#toc:market-like-url-support><code>market</code>-like URL\nsupport</a><a href=#market-like-url-support class=anchor aria-hidden=true></a></h3><p>Third-party applications can now open the App Details page of any\ninstalled package by invoking an Intent with an URL with the following\nformat:<pre><code>app-manager://details?id=&lt;pkg&gt;&amp;user=&lt;user_id&gt;</code></pre><p>where <code>&lt;pkg></code> stands for package name, and\n<code>&lt;user_id></code> stands for the user ID which is\noptional.</section><section id=updated-color-codes class=level3 data-number=6.5.4><h3 data-number=6.5.4><span class=header-section-number>6.5.4</span>\n<a href=#toc:updated-color-codes>Updated color codes</a><a href=#updated-color-codes class=anchor aria-hidden=true></a></h3><p>In order to improve accessibility, certain color codes have been\nimproved. Visit <a href=app-manager://settings/about/version>Settings\n> About > Version/Changelog</a> for details.</section><section id=others class=level3 data-number=6.5.5><h3 data-number=6.5.5><span class=header-section-number>6.5.5</span>\n<a href=#toc:others>Others</a><a href=#others class=anchor aria-hidden=true></a></h3><ul class=incremental><li><p>Avoided waiting for the remote server to respond when no-root\nmode is set<li><p>Fixed downgrading apps in Android 10 onwards<li><p>Fixed installer issues in the Huawei stock operating\nsystems<li><p>Improved text formatting in the “What’s New” dialog<li><p>In the UI tracker window, fixed clicking on the icon after it is\niconified<li><p>Updated bloatware and suggestions</ul></section></section><section id=sec:v4.0.0-(440) class=level2 data-number=6.6><h2 data-number=6.6><span class=header-section-number>6.6</span> <a href=#toc:sec:v4.0.0-(440)>v4.0.0 (440)</a><a href=#sec:v4.0.0-(440) class=anchor aria-hidden=true></a></h2><p>App Manager v4.0.0 comes with a lot of new features and improvements.\nVisit <a href=app-manager://settings/about/version>Settings > About\n> Version/Changelog</a> for details.<section id=new-logo class=level3 data-number=6.6.1><h3 data-number=6.6.1><span class=header-section-number>6.6.1</span>\n<a href=#toc:new-logo>New logo!</a><a href=#new-logo class=anchor aria-hidden=true></a></h3><p>The new logo is just a cursive “A”. The design is based on the <a href=https://freetengwar.sourceforge.net/>Tengwar Telcontar</a> font\nwhich was created to bring the Tengwar script, originally created by J.\nR. R. Tolkien, to the digital world. The letter has the classic App\nManager color (i.e., #dcaf74) and uses a pure black background instead\nof a shade of grey.</section><section id=android-14-and-15-support class=level3 data-number=6.6.2><h3 data-number=6.6.2><span class=header-section-number>6.6.2</span>\n<a href=#toc:android-14-and-15-support>Android 14 and 15 support</a><a href=#android-14-and-15-support class=anchor aria-hidden=true></a></h3><p>App Manager now targets Android 14 and fully supports Android 15.<section id=known-issue class=level5 data-number=6.6.2.0.1><h5 data-number=6.6.2.0.1><span class=header-section-number>6.6.2.0.1</span> Known issue<a href=#known-issue class=anchor aria-hidden=true></a></h5><p>KeyStore backup/restore is not working in Android 12 and later.</section></section><section id=revamped-debloater class=level3 data-number=6.6.3><h3 data-number=6.6.3><span class=header-section-number>6.6.3</span>\n<a href=#toc:revamped-debloater>Revamped debloater</a><a href=#revamped-debloater class=anchor aria-hidden=true></a></h3><p>Debloating profiles were available as “Presets” in the Profiles page\nwhich has now been replaced with the Debloater page and can be accessed\nfrom the three-dots menu in the Main page. <a href=https://github.com/MuntashirAkon/android-debloat-list>ADL</a> is\na new project that focuses on maintaining a list of bloatware as well as\npotential open source alternatives. Contributions are welcome!</section><section id=introducing-file-manager class=level3 data-number=6.6.4><h3 data-number=6.6.4><span class=header-section-number>6.6.4</span>\n<a href=#toc:introducing-file-manager>Introducing file manager</a><a href=#introducing-file-manager class=anchor aria-hidden=true></a></h3><p>App Manager offers an (almost) fully-featured file manager with basic\nfile operations, such as copy, cut, rename, and delete along with the\nbatch operations. It also offers an extensive “Open with…” dialog to\nopen a file with another app, and a comprehensive file properties\nviewer. Folders can also be added to the list of favorites for quick\naccess. And many more.</section><section id=integrated-code-editor class=level3 data-number=6.6.5><h3 data-number=6.6.5><span class=header-section-number>6.6.5</span>\n<a href=#toc:integrated-code-editor>Integrated code editor</a><a href=#integrated-code-editor class=anchor aria-hidden=true></a></h3><p>Manifest and code viewers have been replaced with this new editor.\nAmong other regular features, it includes proper syntax highlighting and\nadvanced searching options. In addition, files from third-party apps can\nalso be opened for editing.</section><section id=history-of-operations class=level3 data-number=6.6.6><h3 data-number=6.6.6><span class=header-section-number>6.6.6</span>\n<a href=#toc:history-of-operations>History of operations</a><a href=#history-of-operations class=anchor aria-hidden=true></a></h3><p>All 1-click operations, batch operations, and profile invocations are\nnow stored as history. The history items can also be executed from the\nHistory page. To ensure consistency, the profile state, configurations,\npackage list are also stored, and this stored version is executed\ninstead of the actual profile. As a result, this works even if the\nprofile is deleted.</section><section id=per-app-freezing-and-more class=level3 data-number=6.6.7><h3 data-number=6.6.7><span class=header-section-number>6.6.7</span>\n<a href=#toc:per-app-freezing-and-more>Per-app freezing, and\nmore</a><a href=#per-app-freezing-and-more class=anchor aria-hidden=true></a></h3><p>Freeze/unfreeze feature now supports setting per-app freezing method\nwhich is beneficial in certain scenarios, such as when a user want to\nsuspend some apps while using the disable method as the default. In\naddition, an “Advanced suspend” option is added which force-stops an\napplication before suspending it, thus, prevent it’s services from\nrunning in the background.</section><section id=log-viewer-enhancements class=level3 data-number=6.6.8><h3 data-number=6.6.8><span class=header-section-number>6.6.8</span>\n<a href=#toc:log-viewer-enhancements>Log viewer enhancements</a><a href=#log-viewer-enhancements class=anchor aria-hidden=true></a></h3><p>Log viewer now supports enhanced searching and filtering options,\nsuch as keyword- and regular expression-based searching and filtering.\nPlease read the in-app changelog for details. Support for batch\noperations has also been added.</section><section id=launching-non-exported-activities class=level3 data-number=6.6.9><h3 data-number=6.6.9><span class=header-section-number>6.6.9</span>\n<a href=#toc:launching-non-exported-activities>Launching non-exported\nactivities</a><a href=#launching-non-exported-activities class=anchor aria-hidden=true></a></h3><p>App Manager now supports launching non-exported activities in no-root\nand ADB mode. However, in no-root mode,\n<code>android.permission.WRITE_SECURE_SETTINGS</code> permission is\nrequired.</section><section id=new-tags-in-app-info-tab class=level3 data-number=6.6.10><h3 data-number=6.6.10><span class=header-section-number>6.6.10</span> <a href=#toc:new-tags-in-app-info-tab>New tags in App Info tab</a><a href=#new-tags-in-app-info-tab class=anchor aria-hidden=true></a></h3><p>Five new tags are added in the App Info tab. They are: bloatware,\nXposed, sensors disabled, open links, and static shared libs. Clicking\non “bloatware” will display more information regarding the bloatware and\nsuggest alternatives, “Xposed” tag will display dependency information,\n“open links” will display a list of links supported by the application,\nand “static shared libs” will display all version of the application\ninstalled in the system along with an option to uninstall them. The\nlatter is useful for applications, such as Trichrome.<section id=known-issue-1 class=level5 data-number=6.6.10.0.1><h5 data-number=6.6.10.0.1><span class=header-section-number>6.6.10.0.1</span> Known issue<a href=#known-issue-1 class=anchor aria-hidden=true></a></h5><p>“Sensors disabled” only works real-time. That means if the\napplication is not currently active, this tag will always display even\nthough the applications may use sensors while it is running. This is a\nframework limitation and nothing can be done to avoid it\neffectively.</section></section><section id=per-session-installer-options class=level3 data-number=6.6.11><h3 data-number=6.6.11><span class=header-section-number>6.6.11</span> <a href=#toc:per-session-installer-options>Per-session installer\noptions</a><a href=#per-session-installer-options class=anchor aria-hidden=true></a></h3><p>It is not possible to modify installer options during the\ninstallation by clicking on the “settings” button in the installation\ndialog. The installer options will be applied to all the applications\ninstalled in the same session (i.e., the installer queue).</section><section id=advanced-mode-of-operations-adb-enhancements class=level3 data-number=6.6.12><h3 data-number=6.6.12><span class=header-section-number>6.6.12</span> <a href=#toc:advanced-mode-of-operations-adb-enhancements>Advanced mode\nof operations, ADB enhancements, …</a><a href=#advanced-mode-of-operations-adb-enhancements class=anchor aria-hidden=true></a></h3><p>App Manager now supports running its remote server (which is used as\na proxy for running privileged operations) as any supported user (UID).\nThis includes root (0), system (1000), and shell/ADB (2000) through the\ncustom commands. This is also useful for Fire TVs which have disabled\nconnecting to ADB from localhost through socket connection. In addition,\nADB pairing is now done using notifications rather than split screen.\nADB connection speed can also be improved by choosing to run App Manager\nin the background which can be configured in the settings.</section><section id=data-usage-widget-and-more class=level3 data-number=6.6.13><h3 data-number=6.6.13><span class=header-section-number>6.6.13</span> <a href=#toc:data-usage-widget-and-more>Data usage widget, and more</a><a href=#data-usage-widget-and-more class=anchor aria-hidden=true></a></h3><p>Data usage widget display the total data usage for the day, similar\nto the screen time widget which displays the total screen time for the\nday. In addition, existing widgets have been improved.</section><section id=others-1 class=level3 data-number=6.6.14><h3 data-number=6.6.14><span class=header-section-number>6.6.14</span> <a href=#toc:others-1>Others</a><a href=#others-1 class=anchor aria-hidden=true></a></h3><ul class=incremental><li><p>Replaced log viewer, sys config, Terminal, etc. with Labs\npage<li><p>Added an option to disable sensors for each app in the App Info\ntab<li><p>Added an option to perform runtime optimization of applications\nin the 1-click Ops page and in the App Info tab<li><p>Added support for Zstandard compression for\nbackup/restore<li><p>Enabling APK signing now automatically enables zip align\nfeature<li><p>Support exporting application list as CSV or JSON in the batch\noperations<li><p>Added pure black theme support<li><p>Display current activity name (when possible) in the UI Tracker\nwindow<li><p>Added an option to filter apps by user in the Main page<li><p>Display a link to Pithus report in the scanner page if\navailable.</ul></section></section><section id=sec:v3.1.0-(423) class=level2 data-number=6.7><h2 data-number=6.7><span class=header-section-number>6.7</span> <a href=#toc:sec:v3.1.0-(423)>v3.1.0 (423)</a><a href=#sec:v3.1.0-(423) class=anchor aria-hidden=true></a></h2><p>App Manager v3.1.0 comes with a few new features and a lot of\nimprovements. Visit <a href=app-manager://settings/about/version>Settings > About >\nVersion/Changelog</a> for details.<section id=android-13-support class=level3 data-number=6.7.1><h3 data-number=6.7.1><span class=header-section-number>6.7.1</span>\n<a href=#toc:android-13-support>Android 13 support</a><a href=#android-13-support class=anchor aria-hidden=true></a></h3><p>App Manager now targets Android 13 which means most issues in Android\n12 and 13 has been addressed, including SSAID and SAF issues as well as\nmonochrome icons and other theming issues.<section id=known-issue-2 class=level5 data-number=6.7.1.0.1><h5 data-number=6.7.1.0.1><span class=header-section-number>6.7.1.0.1</span> Known issue<a href=#known-issue-2 class=anchor aria-hidden=true></a></h5><p>KeyStore backup/restore not working in Android 12 and later.</section></section><section id=introducing-freezeunfreeze class=level3 data-number=6.7.2><h3 data-number=6.7.2><span class=header-section-number>6.7.2</span>\n<a href=#toc:introducing-freezeunfreeze>Introducing\nfreeze/unfreeze</a><a href=#introducing-freezeunfreeze class=anchor aria-hidden=true></a></h3><p>Enable/disable is replaced with freeze/unfreeze to allow greater\ncontrol on the behaviours of an app. It supports suspend, disable and\nhide functionalities which can be controlled at <a href=app-manager://settings/rules_prefs/freeze_type>Settings >\nRules > Default freezing method</a>. In order to make it easy to\nfreeze or unfreeze an app, shortcuts can also be created from the App\nInfo tab by long clicking on the freeze or unfreeze button.</section><section id=export-app-list class=level3 data-number=6.7.3><h3 data-number=6.7.3><span class=header-section-number>6.7.3</span>\n<a href=#toc:export-app-list>Export app list</a><a href=#export-app-list class=anchor aria-hidden=true></a></h3><p>In the Main page, it is now possible to export the list of apps in\neither XML or Markdown format using batch operations. In the future, the\nXML file may also be imported to App Manager.</section><section id=elliptic-curve-crypography-ecc class=level3 data-number=6.7.4><h3 data-number=6.7.4><span class=header-section-number>6.7.4</span>\n<a href=#toc:elliptic-curve-crypography-ecc>Elliptic Curve Crypography\n(ECC)</a><a href=#elliptic-curve-crypography-ecc class=anchor aria-hidden=true></a></h3><p>App Manager now fully supports encrypting backups using ECC in\naddition to offering AES, RSA and OpenPGP.</section><section id=new-languages class=level3 data-number=6.7.5><h3 data-number=6.7.5><span class=header-section-number>6.7.5</span>\n<a href=#toc:new-languages>New languages</a><a href=#new-languages class=anchor aria-hidden=true></a></h3><p>Two new languages are added: Korean and Romanian.</section><section id=more-list-options class=level3 data-number=6.7.6><h3 data-number=6.7.6><span class=header-section-number>6.7.6</span>\n<a href=#toc:more-list-options>More list options</a><a href=#more-list-options class=anchor aria-hidden=true></a></h3><p>In the main page, more sorting and filtering options are added.\nSorting options include sorting the apps by total size, total data\nusage, launch count, screen time and last usage time. Filtering options\ninclude filtering the apps having at least one item in the Android\nKeyStore, filtering apps with URIs granted via SAF, and filtering apps\nwith SSAID.</section><section id=improved-handling-of-mode-of-operation class=level3 data-number=6.7.7><h3 data-number=6.7.7><span class=header-section-number>6.7.7</span>\n<a href=#toc:improved-handling-of-mode-of-operation>Improved handling\nof mode of operation</a><a href=#improved-handling-of-mode-of-operation class=anchor aria-hidden=true></a></h3><p>Fixed various issues with ADB pairing, handled incomplete USB\ndebugging. Some rooting methods cannot allow interprocess communication\nvia Binder. In those cases, ADB mode is used as a fallback method by\nenabling it automatically if possible.</section><section id=handling-multiple-users class=level3 data-number=6.7.8><h3 data-number=6.7.8><span class=header-section-number>6.7.8</span>\n<a href=#toc:handling-multiple-users>Handling multiple users</a><a href=#handling-multiple-users class=anchor aria-hidden=true></a></h3><p>When possible, App Manager will be able to display apps from work\nprofile in no-root mode in addition to allowing basic operations such as\nlaunching the app or navigating to the system settings. For backups, it\nis now possible to restore backups for other users, but for work\nprofile, some apps may only work properly after re-enabling the work\nprofile. In the installer page, selecting <em>All users</em> will now\ninstall the app for all users instead of only the current user. Finally,\nin the app info tab, current app can be installed in another profile\nusing the <em>Install for…</em> option available in the three-dots menu.\nThis is analogous to the <code>pm install-existing</code> command,\nthereby, making the installation process a lot faster.</section><section id=explorer-enhancements class=level3 data-number=6.7.9><h3 data-number=6.7.9><span class=header-section-number>6.7.9</span>\n<a href=#toc:explorer-enhancements>Explorer enhancements</a><a href=#explorer-enhancements class=anchor aria-hidden=true></a></h3><p>Explorer can now open DEX and JAR files in addition to APK files.\nSeveral sorting options as well as folder options are also added as the\nlist options.</section><section id=new-tag-wx class=level3 data-number=6.7.10><h3 data-number=6.7.10><span class=header-section-number>6.7.10</span> <a href=#toc:new-tag-wx>New tag: WX</a><a href=#new-tag-wx class=anchor aria-hidden=true></a></h3><p>In app info tab, a new tag called WX is added. It is displayed in\nAndroid 10 and later if the application targets Android 9 or earlier. It\nindicates <a href=https://en.wikipedia.org/wiki/W%5EX>W^X</a>\nviolation which allows the app to execute arbitrary executable files\neither by the modification of executables embedded within the app or by\ndownloading them from the Internet.</section><section id=app-ops-management class=level3 data-number=6.7.11><h3 data-number=6.7.11><span class=header-section-number>6.7.11</span> <a href=#toc:app-ops-management>App ops management</a><a href=#app-ops-management class=anchor aria-hidden=true></a></h3><p>App ops are now managed automatically to avoid various app ops\nrelated crashes in various platforms. This will also lessen the amount\nof crashes in an unsupported operating system.</section><section id=batch-uninstallation class=level3 data-number=6.7.12><h3 data-number=6.7.12><span class=header-section-number>6.7.12</span> <a href=#toc:batch-uninstallation>Batch uninstallation</a><a href=#batch-uninstallation class=anchor aria-hidden=true></a></h3><p>In the Main page, enabled batch uninstallation in no-root mode.</section><section id=running-apps class=level3 data-number=6.7.13><h3 data-number=6.7.13><span class=header-section-number>6.7.13</span> <a href=#toc:running-apps>Running apps</a><a href=#running-apps class=anchor aria-hidden=true></a></h3><p>Enabled advanced searching. Searching now matches not only app labels\nbut also package names.</section><section id=interceptor class=level3 data-number=6.7.14><h3 data-number=6.7.14><span class=header-section-number>6.7.14</span> <a href=#toc:interceptor>Interceptor</a><a href=#interceptor class=anchor aria-hidden=true></a></h3><p>Copy the intercepted Intent as am command which can be run from\neither an ADB shell or a terminal using root with the same\neffectiveness.</section><section id=device-specific-changes class=level3 data-number=6.7.15><h3 data-number=6.7.15><span class=header-section-number>6.7.15</span> <a href=#toc:device-specific-changes>Device-specific changes</a><a href=#device-specific-changes class=anchor aria-hidden=true></a></h3><section id=graphene-os class=level5 data-number=6.7.15.0.1><h5 data-number=6.7.15.0.1><span class=header-section-number>6.7.15.0.1</span> Graphene OS<a href=#graphene-os class=anchor aria-hidden=true></a></h5><p>Explicitly handle the Internet permission which is a runtime\npermission in the OS.</section><section id=miui class=level5 data-number=6.7.15.0.2><h5 data-number=6.7.15.0.2><span class=header-section-number>6.7.15.0.2</span> MIUI<a href=#miui class=anchor aria-hidden=true></a></h5><p>Fixed permission denied issues in the installer due to a framework\nissue introduced in MIUI 12.5.</section><section id=motorola class=level5 data-number=6.7.15.0.3><h5 data-number=6.7.15.0.3><span class=header-section-number>6.7.15.0.3</span> Motorola<a href=#motorola class=anchor aria-hidden=true></a></h5><p>Fixed crashes in the Interceptor page due to a framework issue\nintroduced in Android 11.</section></section><section id=others-2 class=level3 data-number=6.7.16><h3 data-number=6.7.16><span class=header-section-number>6.7.16</span> <a href=#toc:others-2>Others</a><a href=#others-2 class=anchor aria-hidden=true></a></h3><ul class=incremental><li><p>Improved Java-Smali conversion by including all the subclasses\nduring conversion<li><p>Improved scanning performance in the Scanner page<li><p>Improved updating the list of apps in the Main page<li><p>Scan all the available paths to detect systemless-ly installed\nsystem apps<li><p><code>vacuum</code> SQLite database before opening it for viewing\nor editing.</ul></section></section><section id=sec:v3.0.0-(410) class=level2 data-number=6.8><h2 data-number=6.8><span class=header-section-number>6.8</span> <a href=#toc:sec:v3.0.0-(410)>v3.0.0 (410)</a><a href=#sec:v3.0.0-(410) class=anchor aria-hidden=true></a></h2><p>App Manager v3.0.0 comes with a lot of features and improvements. See\n<a href=app-manager://settings/about/version>Settings > About >\nVersion/Changelog</a> to see a more detailed changelog.<section id=material-3-and-more class=level3 data-number=6.8.1><h3 data-number=6.8.1><span class=header-section-number>6.8.1</span>\n<a href=#toc:material-3-and-more>Material 3 and More</a><a href=#material-3-and-more class=anchor aria-hidden=true></a></h3><p>Material 3, somewhat similar to <em>Material You</em>, is a\nsignificant improvement over Material Design 2 with support for dynamic\ncolours in Android 12 and later. In addition, many design changes have\nbeen made in App Manager without any significant changes in the overall\nuser experience.<section id=known-issue-3 class=level5 data-number=6.8.1.0.1><h5 data-number=6.8.1.0.1><span class=header-section-number>6.8.1.0.1</span> Known issue<a href=#known-issue-3 class=anchor aria-hidden=true></a></h5><p>Switches are still based on Material Design 2 which will be fixed in\na future release.</section></section><section id=wireless-debugging class=level3 data-number=6.8.2><h3 data-number=6.8.2><span class=header-section-number>6.8.2</span>\n<a href=#toc:wireless-debugging>Wireless Debugging</a><a href=#wireless-debugging class=anchor aria-hidden=true></a></h3><p>Wireless debugging support has been fully implemented. Head over to\n§<a href=#sec:wireless-debugging data-reference-type=ref data-reference=sec:wireless-debugging>3.2</a> for instructions on how\nto configure wireless debugging.<div class=\"amalert tip\"><p><strong><em>No-root users.</em></strong><p>Due to auto-detection feature, startup time might be large for\nno-root users when the mode of operation is set to <em>auto</em>.\nInstead, no-root users should select <em>no-root</em> instead of\n<em>auto</em>.</div></section><section id=languages class=level3 data-number=6.8.3><h3 data-number=6.8.3><span class=header-section-number>6.8.3</span>\n<a href=#toc:languages>Languages</a><a href=#languages class=anchor aria-hidden=true></a></h3><p>App Manager is fully translated into Indonesian and Italian languages\nand can be enabled in settings. Bengali is removed due to lack of\ntranslators.</section><section id=introducing-app-explorer class=level3 data-number=6.8.4><h3 data-number=6.8.4><span class=header-section-number>6.8.4</span>\n<a href=#toc:introducing-app-explorer>Introducing App Explorer</a><a href=#introducing-app-explorer class=anchor aria-hidden=true></a></h3><p>App Explorer can be used to browse the contents of an application.\nThis includes binary XML files, DEX contents or any other media files.\nDEX contents can only be explored in Android Oreo (Android 8) and later.\nIt’s also possible to convert an <code>.smali</code> file into\n<code>.java</code> for a better understanding of the reversed code. This\nfeature, if not needed, can be disabled in Settings > Enable/disable\nfeatures.</section><section id=import-backups-from-other-applications class=level3 data-number=6.8.5><h3 data-number=6.8.5><span class=header-section-number>6.8.5</span>\n<a href=#toc:import-backups-from-other-applications>Import Backups\nfrom Other Applications</a><a href=#import-backups-from-other-applications class=anchor aria-hidden=true></a></h3><p>It is possible to import backups from discontinued or obsolete\napplications such as Titanium Backup, OAndBackup and Swift Backup\n(version 3.0 to 3.2). Go to Setting > Backup/restore to find this\noption.</section><section id=virustotal class=level3 data-number=6.8.6><h3 data-number=6.8.6><span class=header-section-number>6.8.6</span>\n<a href=#toc:virustotal>VirusTotal</a><a href=#virustotal class=anchor aria-hidden=true></a></h3><p>VirusTotal is a widely used tool to scan files and URLs for viruses.\nIn the scanner page and in the running apps page, an option to scan\nfiles with VirusTotal has been added. But the option is hidden by\ndefault. To enable the option, it is necessary to obtain an API key from\nVirusTotal. Go to Settings > VirusTotal API Key for more\ninformation.<div class=\"amalert warning\"><p><strong><em>Internet feature.</em></strong><p>This is currently the only feature which require an Internet\nconnection. If you wish to use any Internet feature that might also be\nadded in the future, enable <em>Use the Internet</em> in Settings >\nEnable/disable features.</div></section><section id=trigger-profiles-from-the-automation-software class=level3 data-number=6.8.7><h3 data-number=6.8.7><span class=header-section-number>6.8.7</span>\n<a href=#toc:trigger-profiles-from-the-automation-software>Trigger\nProfiles from the Automation Software</a><a href=#trigger-profiles-from-the-automation-software class=anchor aria-hidden=true></a></h3><p>As the implementation of routine operations is being delayed, an\noption to trigger profiles from the external automation software is\nadded. See §<a href=#sec:automating-tasks data-reference-type=ref data-reference=sec:automating-tasks>3.4</a> for instructions on how to\nconfigure profile automation.</section><section id=improved-application-installer class=level3 data-number=6.8.8><h3 data-number=6.8.8><span class=header-section-number>6.8.8</span>\n<a href=#toc:improved-application-installer>Improved Application\nInstaller</a><a href=#improved-application-installer class=anchor aria-hidden=true></a></h3><p>Application installer includes several improvements including the\nability to downgrade applications in no-root mode, installing multiple\napplications at once and blocking trackers after installation. In\nAndroid 12 and later, no-root users can update applications without any\nuser interactions.</section><section id=component-blocking class=level3 data-number=6.8.9><h3 data-number=6.8.9><span class=header-section-number>6.8.9</span>\n<a href=#toc:component-blocking>Component Blocking</a><a href=#component-blocking class=anchor aria-hidden=true></a></h3><p>It is now possible to configure how App Manager should block a\ncomponent. Visit Settings > Rules > Default blocking method for\nmore information. In the components tab, long clicking the block/unblock\nbutton opens a context menu which allows per-component blocking in a\nsimilar manner. ADB users can also block the components of a <em>Test\nonly</em> app.</section><section id=advanced-searching class=level3 data-number=6.8.10><h3 data-number=6.8.10><span class=header-section-number>6.8.10</span> <a href=#toc:advanced-searching>Advanced Searching</a><a href=#advanced-searching class=anchor aria-hidden=true></a></h3><p>In some pages, the search bar supports additional searching which\nincludes searching via prefix, suffix or even regular expressions. In\nthe main page, it is also possible to search for applications using the\nfirst letters of each word, e.g. <em>App Manager</em> can be listed by\nsearching for <em>am</em>.</section><section id=shared-libraries class=level3 data-number=6.8.11><h3 data-number=6.8.11><span class=header-section-number>6.8.11</span> <a href=#toc:shared-libraries>Shared Libraries</a><a href=#shared-libraries class=anchor aria-hidden=true></a></h3><p>Shared libraries tab has received a significant improvements. It can\ndisplay three types of libraries, such as native, jar and APK files.</section><section id=make-the-best-use-of-interceptor class=level3 data-number=6.8.12><h3 data-number=6.8.12><span class=header-section-number>6.8.12</span> <a href=#toc:make-the-best-use-of-interceptor>Make the Best Use of\nInterceptor</a><a href=#make-the-best-use-of-interceptor class=anchor aria-hidden=true></a></h3><p>Activity interceptor can be opened directly from the activities tab\nby long clicking on the launch button, and similarly, activities can be\nlaunched from the activity interceptor page with or without root, for\nany users.<div class=\"amalert tip\"><p><strong><em>Notice.</em></strong><p>Currently, activities opened via root cannot send the results back to\nthe original applications.</div></section><section id=widget-screen-time class=level3 data-number=6.8.13><h3 data-number=6.8.13><span class=header-section-number>6.8.13</span> <a href=#toc:widget-screen-time>Widget: Screen Time</a><a href=#widget-screen-time class=anchor aria-hidden=true></a></h3><p>Screen time widget is quite similar to Digital Wellbeing’s widget by\nthe same name. It displays the total screen time for the day along with\nthe top three apps from all users.</section><section id=widget-clear-cache class=level3 data-number=6.8.14><h3 data-number=6.8.14><span class=header-section-number>6.8.14</span> <a href=#toc:widget-clear-cache>Widget: Clear Cache</a><a href=#widget-clear-cache class=anchor aria-hidden=true></a></h3><p>Clear cache widget can be to clear cache from all the applications\ndirectly from the home screen.</section></section><section id=sec:v2.6.0-(385) class=level2 data-number=6.9><h2 data-number=6.9><span class=header-section-number>6.9</span> <a href=#toc:sec:v2.6.0-(385)>v2.6.0 (385)</a><a href=#sec:v2.6.0-(385) class=anchor aria-hidden=true></a></h2><section id=introducing-backups class=level3 data-number=6.9.1><h3 data-number=6.9.1><span class=header-section-number>6.9.1</span>\n<a href=#toc:introducing-backups>Introducing Backups</a><a href=#introducing-backups class=anchor aria-hidden=true></a></h3><p>Back up/restore feature is now finally out of beta! Read <a href=#sec:backup-restore>the corresponding guide</a> to understand how\nit works.</section><section id=introducing-log-viewer class=level3 data-number=6.9.2><h3 data-number=6.9.2><span class=header-section-number>6.9.2</span>\n<a href=#toc:introducing-log-viewer>Introducing Log Viewer</a><a href=#introducing-log-viewer class=anchor aria-hidden=true></a></h3><p><a href=#subsubsec:log-viewer>Log viewer</a> is essentially a\nfront-end for <code>logcat</code>. It can be used to filter logs by\n<em>tag</em> or <em>pid</em> (process ID), or even by custom filters.\nLog levels AKA verbosity can also be configured. You can also save,\nshare and manage logs.</section><section id=lock-app-manager class=level3 data-number=6.9.3><h3 data-number=6.9.3><span class=header-section-number>6.9.3</span>\n<a href=#toc:lock-app-manager>Lock App Manager</a><a href=#lock-app-manager class=anchor aria-hidden=true></a></h3><p><a href=#subsubsec:screen-lock>Lock App Manager</a> with the screen\nlock configured for your device.</section><section id=extended-modes-for-app-ops class=level3 data-number=6.9.4><h3 data-number=6.9.4><span class=header-section-number>6.9.4</span>\n<a href=#toc:extended-modes-for-app-ops>Extended Modes for App\nOps</a><a href=#extended-modes-for-app-ops class=anchor aria-hidden=true></a></h3><p>You can set any mode for any app ops that your device supports,\neither from the <a href=#subsec:set-mode-for-app-ops-dots>1-click ops\npage</a> or from the <a href=#subsubsec:app-ops>app ops tab</a>.</section><section id=new-batch-ops-add-to-profile class=level3 data-number=6.9.5><h3 data-number=6.9.5><span class=header-section-number>6.9.5</span>\n<a href=#toc:new-batch-ops-add-to-profile>New Batch Ops: Add to\nProfile</a><a href=#new-batch-ops-add-to-profile class=anchor aria-hidden=true></a></h3><p>You can now easily add selected apps to an existing profile using the\nbatch operations.</section><section id=app-info-improved class=level3 data-number=6.9.6><h3 data-number=6.9.6><span class=header-section-number>6.9.6</span>\n<a href=#toc:app-info-improved>App Info: Improved</a><a href=#app-info-improved class=anchor aria-hidden=true></a></h3><p>App info tab now has many options, including the ability to change <a href=#sec:terminologies>SSAID</a>, network policy (i.e. background\nnetwork usage), battery optimization, etc. Most of the tags used in this\ntab are also clickable, and if you click on them, you will be able to\nlook at the current state or configure them right away.</section><section id=advanced-sort-and-filtering-options-in-the-main-page class=level3 data-number=6.9.7><h3 data-number=6.9.7><span class=header-section-number>6.9.7</span>\n<a href=#toc:advanced-sort-and-filtering-options-in-the-main-page>Advanced\nSort and Filtering Options in the Main Page</a><a href=#advanced-sort-and-filtering-options-in-the-main-page class=anchor aria-hidden=true></a></h3><p>Sort and filter options are now replaced by <a href=#subsubsec:main-list-options>List Options</a> which is highly\nconfigurable, including the ability to filter using profiles.</section><section id=about-this-device class=level3 data-number=6.9.8><h3 data-number=6.9.8><span class=header-section-number>6.9.8</span>\n<a href=#toc:about-this-device>About This Device</a><a href=#about-this-device class=anchor aria-hidden=true></a></h3><p>Interested in knowing about your device in just one page? Go to the\nbottom of the <a href=#subsec:device-info>settings page</a>.</section><section id=enabledisable-features class=level3 data-number=6.9.9><h3 data-number=6.9.9><span class=header-section-number>6.9.9</span>\n<a href=#toc:enabledisable-features>Enable/disable Features</a><a href=#enabledisable-features class=anchor aria-hidden=true></a></h3><p>Not interested in all the features that AM offers? You can disable\nsome features in <a href=#subsubsec:enable/disable-features>settings</a>.</section><section id=new-languages-1 class=level3 data-number=6.9.10><h3 data-number=6.9.10><span class=header-section-number>6.9.10</span> <a href=#toc:new-languages-1>New Languages</a><a href=#new-languages-1 class=anchor aria-hidden=true></a></h3><p>AM now has more than 19 languages! New languages include Farsi,\nJapanese and Traditional Chinese.</section><section id=signing-the-apk-files class=level3 data-number=6.9.11><h3 data-number=6.9.11><span class=header-section-number>6.9.11</span> <a href=#toc:signing-the-apk-files>Signing the APK Files</a><a href=#signing-the-apk-files class=anchor aria-hidden=true></a></h3><p>You can now import external signing keys in AM! For security, App\nManager has its own encrypted KeyStore which can also be <a href=#subsubsec:import/export-keystore>imported or exported</a>.</section><section id=new-extension-unapkm class=level3 data-number=6.9.12><h3 data-number=6.9.12><span class=header-section-number>6.9.12</span> <a href=#toc:new-extension-unapkm>New Extension: UnAPKM</a><a href=#new-extension-unapkm class=anchor aria-hidden=true></a></h3><p>Since APKMirror has removed encryption from their APKM files, it’s no\nlonger necessary to decrypt them. As a result, the option to decrypt\nAPKM files has been removed. Instead, this option is now provided by the\nUnAPKM extension which you can grab from <a href=https://f-droid.org/packages/io.github.muntashirakon.unapkm/>F-Droid</a>.\nSo, if you have an encrypted APKM file and have this extension\ninstalled, you can open the file directly in AM.</section></section><section id=sec:v2.5.20-(375) class=level2 data-number=6.10><h2 data-number=6.10><span class=header-section-number>6.10</span>\n<a href=#toc:sec:v2.5.20-(375)>v2.5.20 (375)</a><a href=#sec:v2.5.20-(375) class=anchor aria-hidden=true></a></h2><section id=subsec:introducing-profiles class=level3 data-number=6.10.1><h3 data-number=6.10.1><span class=header-section-number>6.10.1</span> <a href=#toc:subsec:introducing-profiles>Introducing Profiles</a><a href=#subsec:introducing-profiles class=anchor aria-hidden=true></a></h3><p><a href=#sec:profile-page>Profiles</a> finally closes the <a href=https://github.com/MuntashirAkon/AppManager/issues/72>related\nissue</a>. Profiles can be used to execute certain tasks repeatedly\nwithout doing everything manually. A profile can be applied (or invoked)\neither from the <a href=#sec:profiles-page>Profiles page</a> or from\nthe home screen by creating shortcuts. There are also some presets which\nconsist of debloating profiles taken from <a href=https://gitlab.com/W1nst0n/universal-android-debloater>Universal\nAndroid Debloater</a>.<section id=known-limitations class=level5 data-number=6.10.1.0.1><h5 data-number=6.10.1.0.1><span class=header-section-number>6.10.1.0.1</span> Known limitations<a href=#known-limitations class=anchor aria-hidden=true></a></h5><ul class=incremental><li><p>Exporting rules and applying permissions are not currently\nworking.<li><p>Profiles are applied for all users.</ul></section></section><section id=subsec:the-interceptor class=level3 data-number=6.10.2><h3 data-number=6.10.2><span class=header-section-number>6.10.2</span> <a href=#toc:subsec:the-interceptor>The Interceptor</a><a href=#subsec:the-interceptor class=anchor aria-hidden=true></a></h3><p><a href=https://github.com/MuntashirAkon/intent-intercept>Intent\nIntercept</a> works as a man-in-the-middle between source and\ndestination, that is, when you open a file or URL with another app, you\ncan see what is being shared by opening it with Interceptor first. You\ncan also add or modify the intents before sending them to the\ndestination. Additionally, you can double-click on any exportable\nactivities in the Activities tab in the App Details page to open them in\nthe Interceptor to add more configurations.<section id=known-limitation-2 class=level5 data-number=6.10.2.0.1><h5 data-number=6.10.2.0.1><span class=header-section-number>6.10.2.0.1</span> Known limitation<a href=#known-limitation-2 class=anchor aria-hidden=true></a></h5><p>Editing extras is not currently possible.</section></section><section id=subsec:unapkm:-dedrm-the-apkm-files class=level3 data-number=6.10.3><h3 data-number=6.10.3><span class=header-section-number>6.10.3</span> <a href=#toc:subsec:unapkm:-dedrm-the-apkm-files>UnAPKM: DeDRM the APKM\nfiles</a><a href=#subsec:unapkm:-dedrm-the-apkm-files class=anchor aria-hidden=true></a></h3><p>When I released a small tool called <a href=https://f-droid.org/en/packages/io.github.muntashirakon.unapkm>UnAPKM</a>,\nI promised that similar feature will be available in App Manager. I am\nproud to announce that you can open APKM files directly in the App Info\npage or convert them to APKS or install them directly.</section><section id=subsec:multiple-user class=level3 data-number=6.10.4><h3 data-number=6.10.4><span class=header-section-number>6.10.4</span> <a href=#toc:subsec:multiple-user>Multiple user</a><a href=#subsec:multiple-user class=anchor aria-hidden=true></a></h3><p>App manager now supports multiple users! For now, this requires root\nor ADB. But no-root support is also being considered. If you have\nmultiple users enabled and click on an app installed in multiple\nprofiles, an alert prompt will be displayed where you can select the\nuser.</section><section id=vive-la-france class=level3 data-number=6.10.5><h3 data-number=6.10.5><span class=header-section-number>6.10.5</span> <a href=#toc:vive-la-france>Vive la France!</a><a href=#vive-la-france class=anchor aria-hidden=true></a></h3><p>Thanks to the contributors, we have one more addition to the language\nclub: French. You can add more languages or improve existing\ntranslations at <a href=https://hosted.weblate.org/engage/app-manager>Weblate</a>.</section><section id=report-crashes class=level3 data-number=6.10.6><h3 data-number=6.10.6><span class=header-section-number>6.10.6</span> <a href=#toc:report-crashes>Report crashes</a><a href=#report-crashes class=anchor aria-hidden=true></a></h3><p>If App Manager crashes, you can now easily report the crash from the\nnotifications which opens the share options. Crashes are not reported by\nApp Manager, it only redirects you to your favourite Email client.</section><section id=android-11 class=level3 data-number=6.10.7><h3 data-number=6.10.7><span class=header-section-number>6.10.7</span> <a href=#toc:android-11>Android 11</a><a href=#android-11 class=anchor aria-hidden=true></a></h3><p>Added support for Android 11. Not everything may work as expected\nthough.</section><section id=app-installer-improvements class=level3 data-number=6.10.8><h3 data-number=6.10.8><span class=header-section-number>6.10.8</span> <a href=#toc:app-installer-improvements>App Installer Improvements</a><a href=#app-installer-improvements class=anchor aria-hidden=true></a></h3><section id=set-installation-locations class=level4 data-number=6.10.8.1><h4 data-number=6.10.8.1><span class=header-section-number>6.10.8.1</span> Set installation\nlocations<a href=#set-installation-locations class=anchor aria-hidden=true></a></h4><p>In settings page, you can set install locations such as auto\n(default), internal only and prefer external.</section><section id=set-apk-installer class=level4 data-number=6.10.8.2><h4 data-number=6.10.8.2><span class=header-section-number>6.10.8.2</span> Set APK installer<a href=#set-apk-installer class=anchor aria-hidden=true></a></h4><p>In settings page, you can also set default APK installer (root/ADB\nonly) instead of App Manager.</section><section id=multiple-users class=level4 data-number=6.10.8.3><h4 data-number=6.10.8.3><span class=header-section-number>6.10.8.3</span> Multiple users<a href=#multiple-users class=anchor aria-hidden=true></a></h4><p>In settings page, you can allow App Manager to display multiple users\nduring APK installation.</section><section id=signing-apk-files class=level4 data-number=6.10.8.4><h4 data-number=6.10.8.4><span class=header-section-number>6.10.8.4</span> Signing APK files<a href=#signing-apk-files class=anchor aria-hidden=true></a></h4><p>In settings page, you can choose to sign APK files before installing\nthem. You can also select which signature scheme to use in the <em>APK\nsigning</em> option in settings.<section id=known-limitation-3 class=level5 data-number=6.10.8.4.1><h5 data-number=6.10.8.4.1><span class=header-section-number>6.10.8.4.1</span> Known limitation<a href=#known-limitation-3 class=anchor aria-hidden=true></a></h5><p>Currently, only a generic key is used to sign APK files</section></section></section></section><section id=v2.5.17-368 class=level2 data-number=6.11><h2 data-number=6.11><span class=header-section-number>6.11</span>\n<a href=#toc:v2.5.17-368>v2.5.17 (368)</a><a href=#v2.5.17-368 class=anchor aria-hidden=true></a></h2><section id=app-installer class=level3 data-number=6.11.1><h3 data-number=6.11.1><span class=header-section-number>6.11.1</span> <a href=#toc:app-installer>App Installer</a><a href=#app-installer class=anchor aria-hidden=true></a></h3><p>As promised, it is now possible to select splits. AM also provides\nrecommendations based on device configurations. If the app is already\ninstalled, recommendations are provided based on the installed app. It\nis also possible to downgrade to a lower version without data loss if\nthe device has root or ADB. But it should be noted that not all app can\nbe downgraded. Installer is also improved to speed up the installation\nprocess, especially, for root users. If the app has already been\ninstalled and the new (x)apk(s) is newer or older or the same version\nwith a different signature, AM will display a list of changes similar to\n<strong>What’s New</strong> before prompting the user to install the\napp. This is useful if the app has introduced tracker components, new\npermissions, etc.<section id=known-limitations-1 class=level5 data-number=6.11.1.0.1><h5 data-number=6.11.1.0.1><span class=header-section-number>6.11.1.0.1</span> Known Limitations<a href=#known-limitations-1 class=anchor aria-hidden=true></a></h5><ul class=incremental><li><p>Large app can take a long time to fetch app info, and therefore,\nit may take a long time display the installation prompt.<li><p>If the apk is not located in the internal storage, the app has to\nbe cached first which might also take a long time depending on the size\nof the apk.</ul></section></section><section id=scanner-replacement-for-exodus-page class=level3 data-number=6.11.2><h3 data-number=6.11.2><span class=header-section-number>6.11.2</span> <a href=#toc:scanner-replacement-for-exodus-page>Scanner: Replacement for\nExodus Page</a><a href=#scanner-replacement-for-exodus-page class=anchor aria-hidden=true></a></h3><p>Exodus page is now replaced with scanner page. <a href=#sec:scanner-page>Scanner page</a> contains not only a list of\ntrackers but also a list of used libraries. This is just a start. In the\nfuture, this page will contain more in depth analysis of the app.</section><section id=introducing-system-config class=level3 data-number=6.11.3><h3 data-number=6.11.3><span class=header-section-number>6.11.3</span> <a href=#toc:introducing-system-config>Introducing System Config</a><a href=#introducing-system-config class=anchor aria-hidden=true></a></h3><p>System Config lists various system configurations and\nwhitelists/blacklists included in Android by either OEM/vendor, AOSP or\neven some Magisk modules. Root users can access this option from the\noverflow menu in the main page. There isn’t any official documentation\nfor these options therefore it’s difficult to write a complete\ndocumentation for this page. I will gradually add documentations using\nmy own knowledge. However, some functions should be understandable by\ntheir name.</section><section id=more-languages class=level3 data-number=6.11.4><h3 data-number=6.11.4><span class=header-section-number>6.11.4</span> <a href=#toc:more-languages>More Languages</a><a href=#more-languages class=anchor aria-hidden=true></a></h3><p>Thanks to the contributors, AM now has more than 12 languages. New\nlanguages include Bengali, Hindi, Norwegian, Polish, Russian, Simplified\nChinese, Turkish and Ukrainian.</section><section id=app-info-tab class=level3 data-number=6.11.5><h3 data-number=6.11.5><span class=header-section-number>6.11.5</span> <a href=#toc:app-info-tab>App Info Tab</a><a href=#app-info-tab class=anchor aria-hidden=true></a></h3><p>More tags are added in the <a href=#subsec:app-info-tab>app info\ntab</a> such as <strong>KeyStore</strong> (apps with KeyStore items),\n<strong>Systemless app</strong> (apps installed via Magisk),\n<strong>Running</strong> (apps that are running). For external apk, two\nmore options are added namely <strong>Reinstall</strong> and\n<strong>Downgrade</strong>. Now it is possible to share an apk via\nBluetooth. For system apps, it is possible to uninstall updates for\nroot/ADB users. But like the similar option in the system settings, this\noperation will clear all app data. As stated above, exodus has been\nreplaced with scanner.</section><section id=navigation-improvements class=level3 data-number=6.11.6><h3 data-number=6.11.6><span class=header-section-number>6.11.6</span> <a href=#toc:navigation-improvements>Navigation Improvements</a><a href=#navigation-improvements class=anchor aria-hidden=true></a></h3><p>It’s now relatively easy to navigate to various UI components using\nkeyboard. You can use up/down button to navigate between list items and\ntab button to navigate to UI components inside an item.</section><section id=running-apps-page class=level3 data-number=6.11.7><h3 data-number=6.11.7><span class=header-section-number>6.11.7</span> <a href=#toc:running-apps-page>Running Apps Page</a><a href=#running-apps-page class=anchor aria-hidden=true></a></h3><p>It is now possible to sort and filter processes in this tab. Also,\nthe three big buttons are replaced with an easy-to-use three dot menu.\nPreviously the memory usage was wrong which is fixed in this\nversion.</section><section id=built-in-toybox class=level3 data-number=6.11.8><h3 data-number=6.11.8><span class=header-section-number>6.11.8</span> <a href=#toc:built-in-toybox>Built-in Toybox</a><a href=#built-in-toybox class=anchor aria-hidden=true></a></h3><p>Toybox (an alternative to busybox) is bundled with AM. Although\nAndroid has this utility built-in from API 23, toybox is bundled in\norder to prevent buggy implementations and to support API &lt; 23.</section><section id=component-blocker-improvements class=level3 data-number=6.11.9><h3 data-number=6.11.9><span class=header-section-number>6.11.9</span> <a href=#toc:component-blocker-improvements>Component Blocker\nImprovements</a><a href=#component-blocker-improvements class=anchor aria-hidden=true></a></h3><p>Component blocker seemed to be problematic in the previous version,\nespecially when global component blocking is enabled. The issues are\nmostly fixed now.<div class=\"amalert warning\"><p><strong><em>Caution.</em></strong><p>The component blocking mechanism is no longer compatible with v2.5.6\ndue to various security issues. If you have this version, upgrade to\nv2.5.13 or earlier versions first. After that, enable <a href=#subsubsec:instant-component-blocking>global component\nblocking</a> and disable it again.</div></section><section id=improvements-in-the-app-details-page class=level3 data-number=6.11.10><h3 data-number=6.11.10><span class=header-section-number>6.11.10</span> <a href=#toc:improvements-in-the-app-details-page>Improvements in the App\nDetails Page</a><a href=#improvements-in-the-app-details-page class=anchor aria-hidden=true></a></h3><p>Value of various app ops depend on their parent app ops. Therefore,\nwhen you allow/deny an app op, the parent of the app op gets modified.\nThis fixes the issues some users have been complaining regarding some\napp ops that couldn’t be changed.<p>If an app has the target API 23 or less, its permissions cannot be\nmodified using the <code>pm grant …</code> command. Therefore, for such\napps, option to toggle permission has been disabled.<p>The signature tab is improved to support localization. It also\ndisplays multiple checksums for a signature.</section><section id=app-manifest class=level3 data-number=6.11.11><h3 data-number=6.11.11><span class=header-section-number>6.11.11</span> <a href=#toc:app-manifest>App Manifest</a><a href=#app-manifest class=anchor aria-hidden=true></a></h3><p>Manifest no longer crashes if the size of the manifest is too long.\nGenerated manifest are now more accurate than before.</section></section><section id=v2.5.13-348 class=level2 data-number=6.12><h2 data-number=6.12><span class=header-section-number>6.12</span>\n<a href=#toc:v2.5.13-348>v2.5.13 (348)</a><a href=#v2.5.13-348 class=anchor aria-hidden=true></a></h2><section id=bundled-app-split-apk class=level3 data-number=6.12.1><h3 data-number=6.12.1><span class=header-section-number>6.12.1</span> <a href=#toc:bundled-app-split-apk>Bundled App (Split APK)</a><a href=#bundled-app-split-apk class=anchor aria-hidden=true></a></h3><p>Bundled app formats such as <strong>apks</strong> and\n<strong>xapk</strong> are now supported. You can install these apps\nusing the regular installation buttons. For root and adb users, apps are\ninstalled using shell, and for non-root users, the platform default\nmethod is used.<section id=known-limitations-2 class=level5 data-number=6.12.1.0.1><h5 data-number=6.12.1.0.1><span class=header-section-number>6.12.1.0.1</span> Known Limitations<a href=#known-limitations-2 class=anchor aria-hidden=true></a></h5><ul class=incremental><li><p>Currently <em>all</em> splits apks are installed. But this\nbehaviour is going to change in the next release. If you only need a few\nsplits instead of all, extract the <strong>APKS</strong> or\n<strong>XAPK</strong> file, and then, create a new zip file with your\ndesired split apks and replace the <strong>ZIP</strong> extension with\n<strong>APKS</strong>. Now, open it with AM.<li><p>There is no progress dialog to display the installation\nprogress.</ul></section></section><section id=direct-install-support class=level3 data-number=6.12.2><h3 data-number=6.12.2><span class=header-section-number>6.12.2</span> <a href=#toc:direct-install-support>Direct Install Support</a><a href=#direct-install-support class=anchor aria-hidden=true></a></h3><p>You can now install <strong>APK</strong>, <strong>APKS</strong> or\n<strong>XAPK</strong> directly from your favourite browser or file\nmanager. For apps that need updates, a <strong>What’s New</strong>\ndialog is displayed showing the changes in the new version.<section id=known-limitations-3 class=level5 data-number=6.12.2.0.1><h5 data-number=6.12.2.0.1><span class=header-section-number>6.12.2.0.1</span> Known Limitations<a href=#known-limitations-3 class=anchor aria-hidden=true></a></h5><ul class=incremental><li><p>Downgrade is not yet possible.<li><p>There is no progress dialog to display the installation progress.\nIf you cannot interact with the current page, wait until the\ninstallation is finished.</ul></section></section><section id=remove-all-blocking-rules class=level3 data-number=6.12.3><h3 data-number=6.12.3><span class=header-section-number>6.12.3</span> <a href=#toc:remove-all-blocking-rules>Remove All Blocking Rules</a><a href=#remove-all-blocking-rules class=anchor aria-hidden=true></a></h3><p>In the Settings page, a new option is added which can be used to\nremove all blocking rules configured within App Manager.</section><section id=app-ops class=level3 data-number=6.12.4><h3 data-number=6.12.4><span class=header-section-number>6.12.4</span> <a href=#toc:app-ops>App\nOps</a><a href=#app-ops class=anchor aria-hidden=true></a></h3><ul class=incremental><li><p>App Ops are now generated using a technique similar to AppOpsX.\nThis should decrease the loading time significantly in the App Ops\ntab.<li><p>In the App Ops tab, a menu item is added which can be used to\nlist only active app ops without including the default app ops. The\npreference is saved in the shared preferences.</ul><section id=known-limitation-4 class=level5 data-number=6.12.4.0.1><h5 data-number=6.12.4.0.1><span class=header-section-number>6.12.4.0.1</span> Known Limitation<a href=#known-limitation-4 class=anchor aria-hidden=true></a></h5><p>Often the App Ops tab may not be responsive. If that’s the case,\nrestart App Manager.</section></section><section id=enhanced-adb-support class=level3 data-number=6.12.5><h3 data-number=6.12.5><span class=header-section-number>6.12.5</span> <a href=#toc:enhanced-adb-support>Enhanced ADB Support</a><a href=#enhanced-adb-support class=anchor aria-hidden=true></a></h3><p>ADB shell commands are now executed using a technique similar to\nAppOpsX (This is the <em>free</em> alternative of AppOps by Rikka.).\nThis should dramatically increase the execution time.<section id=known-limitation-5 class=level5 data-number=6.12.5.0.1><h5 data-number=6.12.5.0.1><span class=header-section-number>6.12.5.0.1</span> Known Limitation<a href=#known-limitation-5 class=anchor aria-hidden=true></a></h5><p>AM can often crash or become not responsive. If that’s the case,\nrestart App Manager.</section></section><section id=filtering-in-main-page class=level3 data-number=6.12.6><h3 data-number=6.12.6><span class=header-section-number>6.12.6</span> <a href=#toc:filtering-in-main-page>Filtering in Main Page</a><a href=#filtering-in-main-page class=anchor aria-hidden=true></a></h3><p>Add an option to filter apps that has at least one activity.</section><section id=apk-backupsharing class=level3 data-number=6.12.7><h3 data-number=6.12.7><span class=header-section-number>6.12.7</span> <a href=#toc:apk-backupsharing>Apk Backup/Sharing</a><a href=#apk-backupsharing class=anchor aria-hidden=true></a></h3><p>Apk files are now saved as <code>app name_version.extension</code>\ninstead of <code>package.name.extension</code>.</section><section id=batch-ops class=level3 data-number=6.12.8><h3 data-number=6.12.8><span class=header-section-number>6.12.8</span> <a href=#toc:batch-ops>Batch Ops</a><a href=#batch-ops class=anchor aria-hidden=true></a></h3><ul class=incremental><li><p>Added a foreground service to run batch operations. The result of\nthe operation is displayed in a notification. If an operation has failed\nfor some packages, clicking on the notification will open a dialog box\nlisting the failed packages. There is also a <strong>Try Again</strong>\nbutton on the bottom which can be used to perform the operation again\nfor the failed packages.<li><p>Replaced Linux <em>kill</em> with\n<strong>force-stop</strong>.</ul></section><section id=translations class=level3 data-number=6.12.9><h3 data-number=6.12.9><span class=header-section-number>6.12.9</span> <a href=#toc:translations>Translations</a><a href=#translations class=anchor aria-hidden=true></a></h3><p>Added German and Portuguese (Brazilian) translations.<section id=known-limitation-6 class=level5 data-number=6.12.9.0.1><h5 data-number=6.12.9.0.1><span class=header-section-number>6.12.9.0.1</span> Known Limitation<a href=#known-limitation-6 class=anchor aria-hidden=true></a></h5><p>Not all translations are verified yet.</section></section><section id=app-data-backup class=level3 data-number=6.12.10><h3 data-number=6.12.10><span class=header-section-number>6.12.10</span> <a href=#toc:app-data-backup>App Data Backup</a><a href=#app-data-backup class=anchor aria-hidden=true></a></h3><p>Install app only for the current user at the time of restoring\nbackups. Support for split apks is also added.<p><em>Data backup feature is now considered unstable. If you encounter\nany problem, please report to me without hesitation.</em></section></section></section><section id=ch:app-ops class=level1 data-number=7><h1 data-number=7><span class=header-section-number>7</span> <a href=#toc:ch:app-ops>App Ops</a><a href=#ch:app-ops class=anchor aria-hidden=true></a></h1><section id=sec:app-ops-background class=level2 data-number=7.1><h2 data-number=7.1><span class=header-section-number>7.1</span> <a href=#toc:sec:app-ops-background>Background</a><a href=#sec:app-ops-background class=anchor aria-hidden=true></a></h2><p><strong>App Ops</strong> (short hand for <strong>Application\nOperations</strong>) are used by Android system (since Android 4.3) to\ncontrol application permissions. The user <em>can</em> control some\npermissions, but only the permissions that are considered dangerous (and\nGoogle thinks knowing your phone number isn’t a dangerous thing). So,\napp ops seems to be the one we need if we want to install apps like\nFacebook and it’s Messenger (the latter literary records everything if\nyou live outside the EU) and still want <em>some</em> privacy and/or\nsecurity. Although certain features of app ops were available in\nSettings and later in hidden settings in older version of Android, it’s\ncompletely hidden in newer versions of Android and is continued to be\nkept hidden. Now, any app with\n<strong>android.Manifest.permission.GET_APP_OPS_STATS</strong>\npermission can get the app ops information for other applications but\nthis permission is hidden from users and can only be enabled using ADB\nor root. Still, the app with this permission cannot grant or revoke\npermissions (actually mode of operation) for apps other than itself\n(with limited capacity, of course). To modify the ops of other app, the\napp needs\n<strong>android.Manifest.permission.UPDATE_APP_OPS_STATS</strong>\npermissions which isn’t accessible via <code>pm</code> command. So, you\ncannot grant it via root or ADB, the permission is only granted to the\nsystem apps. There are very few apps who support disabling permissions\nvia app ops. The best one to my knowledge is <a href=https://github.com/8enet/AppOpsX>AppOpsX</a>. The main (visible)\ndifference between my app (AppManager) and this app is that the latter\nalso provides you the ability to revoke internet permissions (by writing\nip tables). One crucial problem that I faced during the development of\nthe app ops API is the lack of documentation in English language.</section><section id=sec:introduction-to-app-ops class=level2 data-number=7.2><h2 data-number=7.2><span class=header-section-number>7.2</span> <a href=#toc:sec:introduction-to-app-ops>Introduction to App Ops</a><a href=#sec:introduction-to-app-ops class=anchor aria-hidden=true></a></h2><figure id=fig:appops><figure><object data=../images/appops.svg type=image/svg+xml></object></figure><figcaption>Figure 2: How app ops work</figcaption></figure><p>Figure <a href=#fig:appops>1</a> describes the process of changing\nand processing permission. <a href=#sec:appopsmanager>AppOpsManager</a> can be used to manage\npermissions in Settings app. <strong>AppOpsManager</strong> is also\nuseful in determining if a certain permission (or operation) is granted\nto the application. Most of the methods of\n<strong>AppOpsManager</strong> are accessible to the user app but unlike\na system app, it can only be used to check permissions for any app or\nfor the app itself and start or terminating certain operations.\nMoreover, not all operations are actually accessible from this Java\nclass. <strong>AppOpsManager</strong> holds all the necessary constants\nsuch as <a href=#subsec:op-constants><code>OP_*</code></a>,\n<code>OPSTR_*</code>, <a href=#subsec:mode-constants><code>MODE_*</code></a> which describes\noperation code, operation string and mode of operations respectively. It\nalso holds necessary data structures such as <a href=#subsec:package-ops>PackageOps</a> and <strong>OpEntry</strong>.\n<strong>PackageOps</strong> holds <strong>OpEntry</strong> for a\npackage, and <strong>OpEntry</strong>, as the name suggests, describes\neach operation.<p><code>AppOpService</code> is completely hidden from a user\napplication but accessible to the system applications. As it can be seen\nin Figure <a href=#fig:appops>1</a>, this is the class that does the\nactual management stuff. It contains data structures such as\n<strong>Ops</strong> to store basic package info and <strong>Op</strong>\nwhich is similar to <strong>OpEntry</strong> of\n<strong>AppOpsManager</strong>. It also has <strong>Shell</strong> which\nis actually the source code of the <a href=#sec:appops-cli><em>appops</em> command line tool</a>. It writes\nconfigurations to or read configurations from <a href=#sec:appops-xml><code>/data/system/appops.xml</code></a>. System\nservices calls <strong>AppOpsService</strong> to find out what an\napplication is allowed and what is not allowed to perform, and\n<strong>AppOpsService</strong> determines these permissions by parsing\n<code>/data/system/appops.xml</code>. If no custom values are present in\n<em>appops.xml</em>, it returns the default mode available in\n<strong>AppOpsManager</strong>.</section><section id=sec:appopsmanager class=level2 data-number=7.3><h2 data-number=7.3><span class=header-section-number>7.3</span> <a href=#toc:sec:appopsmanager>AppOpsManager</a><a href=#sec:appopsmanager class=anchor aria-hidden=true></a></h2><p><a href=https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/app/AppOpsManager.java>AppOpsManager</a>\nstands for application operations manager. It consists of various\nconstants and classes to modify app operations.<div class=seealso-inline><p><em>另见: <span><a href=https://developer.android.com/reference/android/app/AppOpsManager>AppOpsManager\ndocumentation</a></span></em></div><section id=subsec:op-constants class=level3 data-number=7.3.1><h3 data-number=7.3.1><span class=header-section-number>7.3.1</span>\n<a href=#toc:subsec:op-constants><code>OP_*</code> Constants</a><a href=#subsec:op-constants class=anchor aria-hidden=true></a></h3><p><code>OP_*</code> are the integer constants starting from\n<code>0</code>. <code>OP_NONE</code> implies that no operations are\nspecified whereas <code>_NUM_OP</code> denotes the number of operations\ndefined in <code>OP_*</code> prefix. While they denote each operation,\nthe operations are not necessarily unique. In fact, there are many\noperations that are actually a single operation denoted by multiple\n<code>OP_*</code> constant (possibly for future use). Vendors may define\ntheir own op based on their requirements. MIUI is one of the vendors who\nare known to do that.<div class=listing><div class=sourceCode id=cb11 data-frame=lines><pre class=\"sourceCode java\"><code class=\"sourceCode java\"><span id=cb11-1><a href=#cb11-1 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=dt>final</span> <span class=dt>int</span> OP_NONE <span class=op>=</span> <span class=op>-</span><span class=dv>1</span><span class=op>;</span></span>\n<span id=cb11-2><a href=#cb11-2 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=dt>final</span> <span class=dt>int</span> OP_COARSE_LOCATION <span class=op>=</span> <span class=dv>0</span><span class=op>;</span></span>\n<span id=cb11-3><a href=#cb11-3 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=dt>final</span> <span class=dt>int</span> OP_FINE_LOCATION <span class=op>=</span> <span class=dv>1</span><span class=op>;</span></span>\n<span id=cb11-4><a href=#cb11-4 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=dt>final</span> <span class=dt>int</span> OP_GPS <span class=op>=</span> <span class=dv>2</span><span class=op>;</span></span>\n<span id=cb11-5><a href=#cb11-5 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=dt>final</span> <span class=dt>int</span> OP_VIBRATE <span class=op>=</span> <span class=dv>3</span><span class=op>;</span></span>\n<span id=cb11-6><a href=#cb11-6 aria-hidden=true tabindex=-1></a><span class=kw>...</span></span>\n<span id=cb11-7><a href=#cb11-7 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=dt>final</span> <span class=dt>int</span> OP_READ_DEVICE_IDENTIFIERS <span class=op>=</span> <span class=dv>89</span><span class=op>;</span></span>\n<span id=cb11-8><a href=#cb11-8 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=dt>final</span> <span class=dt>int</span> OP_ACCESS_MEDIA_LOCATION <span class=op>=</span> <span class=dv>90</span><span class=op>;</span></span>\n<span id=cb11-9><a href=#cb11-9 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=dt>final</span> <span class=dt>int</span> OP_ACTIVATE_PLATFORM_VPN <span class=op>=</span> <span class=dv>91</span><span class=op>;</span></span>\n<span id=cb11-10><a href=#cb11-10 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=dt>final</span> <span class=dt>int</span> _NUM_OP <span class=op>=</span> <span class=dv>92</span><span class=op>;</span></span></code></pre></div></div><p>Whether an operation is unique is defined by\n<code>sOpToSwitch</code>. It maps each operation to another operation or\nto itself (if it’s a unique operation). For instance,\n<code>OP_FINE_LOCATION</code> and <code>OP_GPS</code> are mapped to\n<code>OP_COARSE_LOCATION</code>.<p>Each operation has a private name which are described by\n<code>sOpNames</code>. These names are usually the same names as the\nconstants without the <code>OP_</code> prefix. Some operations have\npublic names as well which are described by <code>sOpToString</code>.\nFor instance, <code>OP_COARSE_LOCATION</code> has the public name\n<strong>android:coarse_location</strong>.<p>As a gradual process of moving permissions to app ops, there are\nalready many permissions that are defined under some operations. These\npermissions are mapped in <code>sOpPerms</code>. For example, the\npermission\n<strong>android.Manifest.permission.ACCESS_COARSE_LOCATION</strong> is\nmapped to <code>OP_COARSE_LOCATION</code>. Some operations may not have\nany associated permissions which have <code>null</code> values.<p>As described in the previous section, operations that are configured\nfor an app are stored at <a href=#sec:appops-xml><code>/data/system/appops.xml</code></a>. If an\noperation is not configured, then whether system will allow that\noperation is determined from <code>sOpDefaultMode</code>. It lists the\n<em>default mode</em> for each operation.</section><section id=subsec:mode-constants class=level3 data-number=7.3.2><h3 data-number=7.3.2><span class=header-section-number>7.3.2</span>\n<a href=#toc:subsec:mode-constants><code>MODE_*</code> Constants</a><a href=#subsec:mode-constants class=anchor aria-hidden=true></a></h3><p><code>MODE_*</code> constants also integer constants starting from\n<code>0</code>. These constants are assigned to each operation\ndescribing whether an app is authorised to perform that operation. These\nmodes usually have associated names such as <strong>allow</strong> for\n<code>MODE_ALLOWED</code>, <strong>ignore</strong> for\n<code>MODE_IGNORED</code>, <strong>deny</strong> for\n<code>MODE_ERRORED</code> (a rather misnomer), <strong>default</strong>\nfor <code>MODE_DEFAULT</code> and <strong>foreground</strong> for\n<code>MODE_FOREGROUND</code>.<ol class=incremental><li><p><strong><code>MODE_ALLOWED</code>.</strong> The app is allowed to\nperform the given operation<li><p><strong><code>MODE_IGNORED</code>.</strong> The app is not\nallowed to perform the given operation, and any attempt to perform the\noperation should <em>silently fail</em>, i.e. it should not cause the\napp to crash<li><p><strong><code>MODE_ERRORED</code>.</strong> The app is not\nallowed to perform the given operation, and this attempt should cause it\nto have a fatal error, typically a\n<code>SecurityException</code><li><p><strong><code>MODE_DEFAULT</code>.</strong> The app should use\nits default security check, specified in\n<code>AppOpsManager</code><li><p><strong><code>MODE_FOREGROUND</code>.</strong> Special mode that\nmeans “allow only when app is in foreground.” This mode was added in\nAndroid 10<li><p><strong><code>MODE_ASK</code>.</strong> This is a custom mode\nused by MIUI whose uses are unknown.</ol></section><section id=subsec:package-ops class=level3 data-number=7.3.3><h3 data-number=7.3.3><span class=header-section-number>7.3.3</span>\n<a href=#toc:subsec:package-ops>PackageOps</a><a href=#subsec:package-ops class=anchor aria-hidden=true></a></h3><p><strong>AppOpsManager.PackageOps</strong> is a data structure to\nstore all the <strong>OpEntry</strong> for a package. In simple terms,\nit stores all the customised operations for a package.<div class=listing><div class=sourceCode id=cb12 data-frame=lines><pre class=\"sourceCode java\"><code class=\"sourceCode java\"><span id=cb12-1><a href=#cb12-1 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=kw>class</span> PackageOps <span class=kw>implements</span> Parcelable <span class=op>{</span></span>\n<span id=cb12-2><a href=#cb12-2 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=bu>String</span> mPackageName<span class=op>;</span></span>\n<span id=cb12-3><a href=#cb12-3 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=dt>int</span> mUid<span class=op>;</span></span>\n<span id=cb12-4><a href=#cb12-4 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=bu>List</span><span class=op>&lt;</span>OpEntry<span class=op>&gt;</span> mEntries<span class=op>;</span></span>\n<span id=cb12-5><a href=#cb12-5 aria-hidden=true tabindex=-1></a>    <span class=kw>...</span></span>\n<span id=cb12-6><a href=#cb12-6 aria-hidden=true tabindex=-1></a><span class=op>}</span></span></code></pre></div></div><p>As can be seen in Listing <a href=#lst:package-ops-class>2</a>, it\nstores all <strong>OpEntry</strong> for a package as well as the\ncorresponding package name and its kernel user ID.</section><section id=subsec:opentry class=level3 data-number=7.3.4><h3 data-number=7.3.4><span class=header-section-number>7.3.4</span>\n<a href=#toc:subsec:opentry>OpEntry</a><a href=#subsec:opentry class=anchor aria-hidden=true></a></h3><p><strong>AppOpsManager.OpEntry</strong> is a data structure that\nstores a single operation for any package.<div class=listing><div class=sourceCode id=cb13 data-frame=lines><pre class=\"sourceCode java\"><code class=\"sourceCode java\"><span id=cb13-1><a href=#cb13-1 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=dt>final</span> <span class=kw>class</span> OpEntry <span class=kw>implements</span> Parcelable <span class=op>{</span></span>\n<span id=cb13-2><a href=#cb13-2 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=dt>int</span> mOp<span class=op>;</span></span>\n<span id=cb13-3><a href=#cb13-3 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=dt>boolean</span> mRunning<span class=op>;</span></span>\n<span id=cb13-4><a href=#cb13-4 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=at>@Mode</span> <span class=dt>int</span> mMode<span class=op>;</span></span>\n<span id=cb13-5><a href=#cb13-5 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=at>@Nullable</span> LongSparseLongArray mAccessTimes<span class=op>;</span></span>\n<span id=cb13-6><a href=#cb13-6 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=at>@Nullable</span> LongSparseLongArray mRejectTimes<span class=op>;</span></span>\n<span id=cb13-7><a href=#cb13-7 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=at>@Nullable</span> LongSparseLongArray mDurations<span class=op>;</span></span>\n<span id=cb13-8><a href=#cb13-8 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=at>@Nullable</span> LongSparseLongArray mProxyUids<span class=op>;</span></span>\n<span id=cb13-9><a href=#cb13-9 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=at>@Nullable</span> LongSparseArray<span class=op>&lt;</span><span class=bu>String</span><span class=op>&gt;</span> mProxyPackageNames<span class=op>;</span></span>\n<span id=cb13-10><a href=#cb13-10 aria-hidden=true tabindex=-1></a>    <span class=kw>...</span></span>\n<span id=cb13-11><a href=#cb13-11 aria-hidden=true tabindex=-1></a><span class=op>}</span></span></code></pre></div></div><p>Here:<ul class=incremental><li><p><code>mOp</code>: Denotes one of the <a href=#subsec:op-constants><code>OP_*</code> constants</a><li><p><code>mRunning</code>: Whether the operation is in progress\n(i.e. the operation has started but not finished yet). Not all\noperations can be started or finished this way<li><p><code>mMOde</code>: One of the <a href=#subsec:mode-constants><code>MODE_*</code> constants</a><li><p><code>mAccessTimes</code>: Stores all the available access\ntimes<li><p><code>mRejectTimes</code>: Stores all the available reject\ntimes<li><p><code>mDurations</code>: All available access durations, checking\nthis with <code>mRunning</code> will tell you for how long the app is\nperforming a certain app operation<li><p><code>mProxyUids</code>: No documentation found<li><p><code>mProxyPackageNames:</code> No documentation found</ul></section><section id=subsec:usage class=level3 data-number=7.3.5><h3 data-number=7.3.5><span class=header-section-number>7.3.5</span>\n<a href=#toc:subsec:usage>Usage</a><a href=#subsec:usage class=anchor aria-hidden=true></a></h3><p>TODO</section></section><section id=sec:appopsservice class=level2 data-number=7.4><h2 data-number=7.4><span class=header-section-number>7.4</span> <a href=#toc:sec:appopsservice>AppOpsService</a><a href=#sec:appopsservice class=anchor aria-hidden=true></a></h2><p>TODO</section><section id=sec:appops-xml class=level2 data-number=7.5><h2 data-number=7.5><span class=header-section-number>7.5</span> <a href=#toc:sec:appops-xml>appops.xml</a><a href=#sec:appops-xml class=anchor aria-hidden=true></a></h2><p>Latest <code>appops.xml</code> has the following format: (This DTD is\nmade by me and by no means perfect, has compatibility issues.)<pre><code>&lt;!DOCTYPE app-ops [\n\n&lt;!ELEMENT app-ops (uid|pkg)*&gt;\n&lt;!ATTLIST app-ops v CDATA #IMPLIED&gt;\n\n&lt;!ELEMENT uid (op)*&gt;\n&lt;!ATTLIST uid n CDATA #REQUIRED&gt;\n\n&lt;!ELEMENT pkg (uid)*&gt;\n&lt;!ATTLIST pkg n CDATA #REQUIRED&gt;\n\n&lt;!ELEMENT uid (op)*&gt;\n&lt;!ATTLIST uid\nn CDATA #REQUIRED\np CDATA #IMPLIED&gt;\n\n&lt;!ELEMENT op (st)*&gt;\n&lt;!ATTLIST op\nn CDATA #REQUIRED\nm CDATA #REQUIRED&gt;\n\n&lt;!ELEMENT st EMPTY&gt;\n&lt;!ATTLIST st\nn CDATA #REQUIRED\nt CDATA #IMPLIED\nr CDATA #IMPLIED\nd CDATA #IMPLIED\npp CDATA #IMPLIED\npu CDATA #IMPLIED&gt;\n\n]&gt;</code></pre><p>The instruction below follows the exact order given above:<ul class=incremental><li><p><code>app-ops</code>: The root element. It can contain any number\nof <code>pkg</code> or package <code>uid</code><ul class=incremental><li><p><code>v</code>: (optional, integer) The version number (default:\n<code>NO_VERSION</code> or <code>-1</code>)</ul><li><p><code>pkg</code>: Stores package info. It can contain any number\nof <code>uid</code><ul class=incremental><li><p><code>n</code>: (required, string) Name of the package</ul><li><p>Package <code>uid</code>: Stores package or packages info<ul class=incremental><li><p><code>n</code>: (required, integer) The user ID</ul><li><p><code>uid</code>: The package user ID. It can contain any number\nof <code>op</code><ul class=incremental><li><p><code>n</code>: (required, integer) The user ID<li><p><code>p</code>: (optional, boolean) Is the app is a\nprivate/system app</ul><li><p><code>op</code>: The operation, can contain <code>st</code> or\nnothing at all<ul class=incremental><li><p><code>n</code>: (required, integer) The op name in integer,\ni.e. AppOpsManager.OP_*<li><p><code>m</code>: (required, integer) The op mode,\ni.e. AppOpsManager.MODE_*</ul><li><p><code>st</code>: State of operation: whether the operation is\naccessed, rejected or running (not available on old versions)<ul class=incremental><li><p><code>n</code>: (required, long) Key containing flags and\nuid<li><p><code>t</code>: (optional, long) Access time (default:\n<code>0</code>)<li><p><code>r</code>: (optional, long) Reject time (default:\n<code>0</code>)<li><p><code>d</code>: (optional, long) Access duration (default:\n<code>0</code>)<li><p><code>pp</code>: (optional, string) Proxy package name<li><p><code>pu</code>: (optional, integer) Proxy package uid</ul></ul><p>This definition can be found at <a href=https://android.googlesource.com/platform/frameworks/base/+/master/services/core/java/com/android/server/appop/AppOpsService.java>AppOpsService</a>.</section><section id=sec:appops-cli class=level2 data-number=7.6><h2 data-number=7.6><span class=header-section-number>7.6</span> <a href=#toc:sec:appops-cli>Command Line Interface</a><a href=#sec:appops-cli class=anchor aria-hidden=true></a></h2><p><code>appops</code> or <code>cmd appops</code> (on latest versions)\ncan be accessible via ADB or root. This is an easier method to get or\nupdate any operation for a package (provided the package name is known).\nThe help page of this command is self-explanatory:<pre><code>AppOps service (appops) commands:\nhelp\nPrint this help text.\nstart [--user &lt;USER_ID&gt;] &lt;PACKAGE | UID&gt; &lt;OP&gt;\nStarts a given operation for a particular application.\nstop [--user &lt;USER_ID&gt;] &lt;PACKAGE | UID&gt; &lt;OP&gt;\nStops a given operation for a particular application.\nset [--user &lt;USER_ID&gt;] &lt;[--uid] PACKAGE | UID&gt; &lt;OP&gt; &lt;MODE&gt;\nSet the mode for a particular application and operation.\nget [--user &lt;USER_ID&gt;] &lt;PACKAGE | UID&gt; [&lt;OP&gt;]\nReturn the mode for a particular application and optional operation.\nquery-op [--user &lt;USER_ID&gt;] &lt;OP&gt; [&lt;MODE&gt;]\nPrint all packages that currently have the given op in the given mode.\nreset [--user &lt;USER_ID&gt;] [&lt;PACKAGE&gt;]\nReset the given application or all applications to default modes.\nwrite-settings\nImmediately write pending changes to storage.\nread-settings\nRead the last written settings, replacing current state in RAM.\noptions:\n&lt;PACKAGE&gt; an Android package name or its UID if prefixed by --uid\n&lt;OP&gt;      an AppOps operation.\n&lt;MODE&gt;    one of allow, ignore, deny, or default\n&lt;USER_ID&gt; the user id under which the package is installed. If --user is not\nspecified, the current user is assumed.</code></pre></section></section><section id=footnotes class=\"footnotes footnotes-end-of-document\" role=doc-endnotes><hr><ol><li id=fn1><p>For distributing normal releases only<a href=#fnref1 class=footnote-back role=doc-backlink>↩︎</a><li id=fn2><p>GitHub 的 PR 将使用 git patch 进行手动合并, 因此, GitHub\n可能会错误地将它们标记为closed而不是merged.<a href=#fnref2 class=footnote-back role=doc-backlink>↩︎</a><li id=fn3><p>你也可以叫我“Muntashir Akon”<a href=#fnref3 class=footnote-back role=doc-backlink>↩︎</a></ol></section>"
  },
  {
    "path": "docs/raw/zh-rCN/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"intro$main$$introduction-chapter-title\">简介</string>\n    <string name=\"intro$main$$supported-versions-title\">受支持的版本</string>\n    <string name=\"intro$main$$source-code-links-title\">源码链接</string>\n    <string name=\"intro$main$$contributing-title\">贡献</string>\n    <string name=\"intro$main$buiding\">在位于源码根目录下的BUILDING文件中可以获得编译教程。</string>\n    <string name=\"titlepage$user_manual\">{\\\\huge\\\\bfseries 用户手册\\\\par}</string>\n    <string name=\"intro$main$translations\">App Manager 不接受通过 pull/merge 请求进行的翻译。\\n翻译通过 Hosted Weblate 管理。\n\\n要翻译App Manager，请访问 \\\\url{https://hosted.weblate.org/engage/app-manager/}。开始前请阅读 \\\\textbf{信息} 部分。</string>\n    <string name=\"intro$main$supported-versions\">当前，支持的版本是 v4.0.1。\\n先前版本的 App\nManager 可能包含安全漏洞，不应继续使用。</string>\n    <string name=\"intro$main$intro\">App Manager 是一个高级的 Android 包管理器。\n\\n它提供了许多功能，因此需要用户手册来帮助用户。本文档作为 App Manager 的用户手册，旨在描述 App Manager 提供的每一个功能。\n\\n本文档也可以被认为是 App Manager 的“官方”指南，\n\\n并代表了 App Manager 的预期行为。翻译对文档理解可能有误（原文是用英语写的）。\n\\n因此，有能力的用户应该阅读英文文档，以充分发挥文档 的作用。\n\\n可能还有其他非官方或第三方资源，如博客文章、视频、论坛、聊天、群组等。\n\\n虽然这些资源可能对很多人有用，但它们的内容可能跟不上最新的 App Manager 版本。\n\\n如果在 App Manager 中发现任何偏离本文档的情况，应在\n\\n\\\\href{https://github.com/MuntashirAkon/AppManager/issues}{App Manager 问题追踪}进行报告。</string>\n    <string name=\"intro$main$bin-sources\">App Manager 通过以下渠道发布。\n\\n非官方来源可能分发 App Manager 的修改版本，使用这样版本的后果由你自己单独承担。\n\\n\\\\begin{enumerate}\n\\n \\\\item F-Droid \\\\footnote{For distributing normal releases only}\\\\\\\\\n\\n \\\\textit{Link:} \\\\url{https://f-droid.org/packages/io.github.muntashirakon.AppManager}\n\\n \\\\item GitHub repository.\\\\\\\\\n\\n \\\\textit{Normal releases:} \\\\url{https://github.com/MuntashirAkon/AppManager/releases}\\\\\\\\\n\\n \\\\textit{Debug releases:} \\\\url{https://github.com/MuntashirAkon/AppManager/actions}\n\\n \\\\item Telegram.\\\\\\\\\n\\n \\\\textit{Normal releases:} \\\\url{https://t.me/AppManagerChannel}\\\\\\\\\n\\n \\\\textit{Debug releases:} \\\\url{https://t.me/AppManagerDebug}\n\\n\\\\end{enumerate}</string>\n    <string name=\"intro$main$source-code-links\">除了GitHub外其他都是镜像链接。tags 应当始终是最新的，但 master 分支也许不是\n。 \\n如果计划克隆 master 分支，请使用 GitHub 链接而不是其他链接。</string>\n    <string name=\"intro$main$terminologies\">\\\\begin{itemize}\n\\n \\\\item \\\\textbf{AM} --- App Manager 应用\n\\n \\\\item \\\\textbf{Block/Unblock} --- 用于拦截组件或解除组件拦截。 如何拦截取决于\n\\n 用户选项。\n\\n \\\\item \\\\textbf{IFW} --- Intent Firewall (意图防火墙)\n\\n \\\\item \\\\textbf{Ops} --- operations (操作), e.g.\\\\ app ops, batch ops, 1-click ops\n\\n \\\\item \\\\textbf{SAF} --- 存储访问框架（SAF）的缩写形式，Android 系统所用的抽象概念，允许应用无需担忧底层文件系统便能\n\\n 使用或提供文件。\n\\n \\\\item \\\\textbf{SSAID} --- \\\\texttt{Settings.Secure.ANDROID\\\\_ID} - 分配给每个应用的设备标识符 (Android Oreo以上版本)，\n\\n 由应用签名与包\\\\texttt{android}的SSAID组合生成。\n\\n 因此，除非用户选择格式化设备，否则它保证对每个应用来说都是独一无二的。\n\\n 它被普遍用于跟踪用户。\n\\n \\\\item \\\\textbf{Tracker} --- 在文档和 App Manager 中均表示跟踪器组件，\n\\n \\\\hyperref[sec:scanner-page]{scanner page} 是个例外。\n\\n 跟踪器包括用于报告崩溃、数据分析、用户画像、身份识别、广告和定位等目的的库文件。因此，这些库的功能并不相同。推广跟踪的\n\\n 开源和闭源库之间不存在区别或偏向。\n\\n\\\\end{itemize}</string>\n    <string name=\"intro$main$$terminologies-title\">术语</string>\n    <string name=\"intro$main$$bin-sources-title\">二进制(可执行)分发来源</string>\n    <string name=\"intro$main$$buiding-title\">构建说明</string>\n    <string name=\"intro$main$$submit-patches-title\">提交补丁</string>\n    <string name=\"intro$main$$translations-title\">翻译</string>\n    <string name=\"intro$main$$official-sources-title\">官方来源</string>\n    <string name=\"intro$main$$donation-title\">捐赠 \\\\&amp; 资助</string>\n    <string name=\"intro$main$$contact-title\">联系我们</string>\n    <string name=\"intro$main$contributing\">用户可有通过多种方式作贡献，如创建有用 issues 、参加讨论、\n\\n改进文档和翻译、报告未知的库或跟踪器、\n\\n审查源代码以及报告安全漏洞。</string>\n    <string name=\"pages$main$$pages-chapter-title\">页面</string>\n    <string name=\"pages$main-page$$section-title\">主页</string>\n    <string name=\"pages$main-page$$how-app-ops-work-title\">主页面中的一个应用程序列表项</string>\n    <string name=\"pages$main-page$$application-types-title\">应用类型</string>\n    <string name=\"pages$main-page$$instructions-title\">说明</string>\n    <string name=\"pages$main-page$$sort-title\">排序</string>\n    <string name=\"pages$main-page$$filter-title\">筛选</string>\n    <string name=\"pages$main-page$$profile_name-title\">配置文件名称</string>\n    <string name=\"pages$main-page$$1-click-ops-title\">一键操作</string>\n    <string name=\"pages$main-page$$app-usage-title\">应用使用情况</string>\n    <string name=\"pages$main-page$$running-apps-title\">正在运行的应用</string>\n    <string name=\"pages$main-page$$profiles-title\">配置文件</string>\n    <string name=\"pages$main-page$$termux-title\">Termux 终端模拟器</string>\n    <string name=\"pages$main-page$$settings-title\">设置</string>\n    <string name=\"pages$main-page$options-menu\">选项菜单提供了若干个选项，以用于对列出的应用程序进行排序和过滤， \\n以及转到 App Manager 内或外的不同页面。</string>\n    <string name=\"pages$main-page$settings\">此菜单项将打开本应用的 \\\\hyperref[sec:settings-page]{设置}.</string>\n    <string name=\"pages$app-details-page$$section-title\">应用程序详情页</string>\n    <string name=\"pages$app-details-page$$colour-codes-title\">颜色代码含义</string>\n    <string name=\"pages$app-details-page$$app-info-tab-title\">应用信息</string>\n    <string name=\"pages$app-details-page$$app-info-general-information-title\">基本信息</string>\n    <string name=\"pages$app-details-page$$horizontal-action-panel-title\">水平操作面板</string>\n    <string name=\"pages$app-details-page$$app-info-options-menu-title\">选项菜单</string>\n    <string name=\"pages$app-details-page$$config-termux-title\">配置 Termux</string>\n    <string name=\"pages$app-details-page$$component-tabs-title\">组件选项卡</string>\n    <string name=\"pages$app-details-page$$receivers-title\">(广播)接收器 ((Broadcast)Receiver)</string>\n    <string name=\"pages$app-details-page$$providers-title\">(内容)提供者 ((Content)Providers)</string>\n    <string name=\"pages$app-details-page$$blocking-components-title\">拦截组件。</string>\n    <string name=\"pages$app-details-page$intro\">\\\\textbf{应用详情} 页面由 11 个标签页组成。它描述了一个应用程序持有的几乎所有信息, \\n包括其清单中的所有属性、\\\\hyperref[ch:app-ops]{应用操作（App Ops）}、签名 \\n信息、库等等。</string>\n    <string name=\"pages$app-details-page$app-info-tab\">\\\\textbf{应用信息} 选项卡包含关于一个应用程序的基本信息,\n\\n许多操作可以在此标签中执行.</string>\n    <string name=\"pages$one-click-ops-page$$section-title\">一键操作页</string>\n    <string name=\"pages$main-page$$colour-codes-title\">颜色代码含义</string>\n    <string name=\"intro$main$submit-patches\">除GitHub之外的仓库目前被视为镜像，在这些网站提交的 PR/MR 将不被接受.\n\\n\\\\footnote{GitHub 的 PR 将使用 git patch 进行手动合并, 因此, GitHub 可能会错误地将它们标记为closed而不是merged.}\n\\n相反，patches (\\\\texttt{.patch} 文件) 可以通过电子邮件附件提交。\\\\textit{请务必对Commits签名(Signing-off)}\n\\n更多信息请参见位于源码根目录下的CONTRIBUTING文件.\n\\n\n\\n\\\\begin{warning}{注意}\n\\n至于通过电子邮件提交补丁，完整邮件对话在将来可能可以公开访问.\n\\n所以，请不要包含除了您的姓名和电子邮件地址之外的任何个人身份信息（PII）.\n\\n\\\\end{warning}</string>\n    <string name=\"pages$main-page$colour-codes\">\\\\begin{itemize}\\n \\\\item \\\\colorbox{uninstalled-day}{\\\\textcolor{black}{红色 (日间模式下)}} / \\\\colorbox{uninstalled-night}{\\\\textcolor{white}\\n {深红色 (夜间模式下)}} --已卸载的应用程序\\n \\\\item \\\\colorbox{disabled-day}{\\\\textcolor{black}{浅红色 (日间模式下)}} / \\\\colorbox{disabled-night}{\\\\textcolor{white}\\n {暗红色 (夜间模式下)}} -- 已停用的应用程序\\n \\\\item \\\\colorbox{force-stopped}{\\\\textcolor{white}{暗青色}} -- 已强行停止的应用程序\\n \\\\item \\\\colorbox{AMYellow}{\\\\textcolor{black}{黄色星标}} -- 可调试的应用程序\\n\\n \\\\item \\\\textcolor{AMOrange}{橙色 \\\\textit{日期}} -- 可读取日志的应用程序\\n \\\\item \\\\textcolor{AMOrange}{橙色 \\\\textit{UID}} -- UID在多个应用程序中被共享\\n \\\\item \\\\textcolor{AMOrange}{橙色 \\\\textit{SDK}} -- 使用明文网络通信(即 HTTP)\\n \\\\item \\\\textcolor{tracker-day}{亮橙色 \\\\textit{包名}} -- 有一个或多个跟踪器的应用程序\\n \\\\item \\\\textcolor{red}{红色 \\\\textit{应用标签}} -- 不允许清空数据的应用程序\\n \\\\item \\\\textcolor{AMDarkCyan}{暗青色 \\\\textit{版本}} -- 未运行的应用程序\\n \\\\item \\\\textcolor{magenta}{紫红色} -- 常驻应用(即一直运行的应用程序)\\n\\n \\\\item \\\\textcolor{red}{红色 \\\\textit{备份标识}} -- 已卸载的应用程序存在一个或多个备份 \\n 在App Manager中\\n \\\\item \\\\textcolor{AMOrange}{橙色 \\\\textit{备份标识}} -- 存在的备份已过期，\\n 即基本备份中包含已安装应用程序的旧版本\\n \\\\item \\\\textcolor{AMDarkCyan}{暗青色 \\\\textit{备份标识}} -- 存在的备份已更新，\\n 即基本备份中包含已安装应用程序的相同版本或更高版本\\n\\\\end{itemize}</string>\n    <string name=\"pages$main-page$instructions\">单击 \\\\textbf{用户手册} 打开离线版本的 App Manager 用户手册。\\n如果单独拆分出来的相应功能（即\\\\ \\\\texttt{feat\\\\_docs} ）未安装, 或系统里不存在加载手册的 WebView\\n也可以打开用户手册的在线版本。</string>\n    <string name=\"pages$main-page$$list-options-title\">列表选项</string>\n    <string name=\"pages$main-page$$apk-updater-title\">APK更新器</string>\n    <string name=\"intro$main$donation\">% \\\\emph{捐赠或购买并不是使用App Manager的必要条件。} 虽然 App Manager 不支持任何内购，\\n% 但可以通过 Open Source Collective 向 App Manager 的所有者进行捐赠。 \\n%\\n% Open Source Collective 是 Open Collective 平台上的一个财政托管机构，\\n% 帮助开源项目管理他们的财务状况。 \\n% 目前支持通过银行账户、PayPal、信用卡或借记卡以及加密货币发起捐赠。\\n%\\n% \\\\textit{链接：} \\\\url{https://opencollective.com/muntashir} 。\\n%\\n% 向开发者捐赠意味着捐赠者同意\\n% “不应将捐款当作使作者优先考虑其所请求的功能的筹码” 。 \\n% 新功能的优先级根据开发者的偏好决定，并不需要任何报酬或捐赠。\\n%\\n% \\\\emph{App Manager 接受任何主动提供的资助或赠款} \\n% 有兴趣组织的代表可以通过 \\\\Sref{sec:contact} 中给出的选项联系所有者。\\n\\n截至2024年9月，\\n在另行通知前 App Manager 不接受经济支持。\\n但你仍可以向开发者赠送礼物（例如礼品卡、订阅、食物和饮料、鲜花甚至是现金）。\\n请用 \\\\Sref{sec:contact} 中给出的选项联系维护者以获得进一步帮助。</string>\n    <string name=\"intro$main$contact\">App Manager 社区\\\\\\\\\\n邮箱: \\\\href{mailto:am4android@riseup.net}{am4android [at] riseup [dot] net}\\\\\\\\\\nGitHub 账户: \\\\url{https://github.com/AMCommunity}\\\\\\\\\\nTwitter/X 账户: \\\\url{https://x.com/AppManagerNews}\\\\\\\\\\nMastodon 账户: \\\\href{https://floss.social/@appmanager}{@appmanager@floss.social}\\\\\\\\\\n\\\\\\\\\\n\\nMuntashir Al-Islam\\\\footnote{你也可以叫我``Muntashir Akon\\'\\'}\\\\\\\\ \\n邮箱: \\\\href{mailto:muntashirakon@riseup.net}{muntashirakon [at] riseup [dot] net}\\\\\\\\ \\n密钥指纹: \\\\texttt{7bad37c2981e41f8f6abea7f58f0b4f26c346fce}\\\\\\\\ \\nGitHub 账户: \\\\url{https://github.com/MuntashirAkon}\\\\\\\\ \\nTwitter 账户: \\\\url{https://twitter.com/Muntashir}</string>\n    <string name=\"pages$main-page$$batch-operations-title\">批处理</string>\n    <string name=\"pages$main-page$$version-info-title\">版本信息</string>\n    <string name=\"pages$main-page$$options-menu-title\">选项菜单</string>\n    <string name=\"pages$main-page$intro\">主页面列出所有已安装、已卸载和已备份的应用。 \\n单独点击任何已安装的应用项目可打开相应的 \\\\hyperref[sec:app-details-page]{应用详情页}。 \\n对于未安装的系统应用，会显示一个对话框提示，可以用来重新安装该应用。 \\n使用列表选项中的 \\\\hyperlink{par:main-page-sort}{排序} ，可以选择应用列表的排序方式，退出应用后仍会保留排序方式。 \\n使用列表选项中的 \\\\hyperlink{par:main-page-filter}{过滤}，可以过滤列表选项。 \\n筛选也可以通过搜索栏进行过滤，并支持正则表达式。</string>\n    <string name=\"pages$main-page$batch-operations\">批处理或者多应用处理也可以在这个页面内进行。 \\n多选模式可以由点击任何应用图标或长按列表中的任意一项进入。 \\n进入多选模式后，仅需单击列表中的任意一项便可选中，而不是打开应用程序详情页。 \\n该模式下，批处理操作位于页面底部的多选菜单。操作包括： \\n\\\\begin{itemize} \\n \\\\item 将选中应用添加到 \\\\hyperref[sec:profiles-page]{配置} \\n \\\\item \\\\hyperref[sec:backup-restore]{备份、恢复或删除}应用程序 \\n \\\\item 阻止应用中的追踪器 \\n \\\\item 清除应用数据或缓存 \\n \\\\item 导出App Manager中的屏蔽规则 \\n \\\\item 以MarkDown，CSV，JSON或XML格式导出应用列表 \\n \\\\item 启用/停用/强制停止/卸载应用程序 \\n \\\\item 对应用执行运行时优化 (Android 7 及更高版本) \\n \\\\item 阻止应用的后台操作 (Android 7 及更高版本) \\n \\\\item 导出APK文件到 \\\\texttt{AppManager/apks} \\n \\\\item 设置\\\\hyperref[sec:net-policy]{联网规则} \\n\\\\end{itemize} \\n \\n\\\\begin{tip}{无障碍} \\n 进入多选模式后， \\n 可以使用键盘或遥控器的左右键呼出多选菜单。 \\n\\\\end{tip}</string>\n    <string name=\"pages$main-page$application-types\">一个应用程序可以是 \\\\textbf{用户} 或 \\\\textbf{系统} 应用，同时存在以下后缀: \\n\\\\begin{itemize} \\n \\\\item \\\\texttt{X} -- 支持多种架构 \\n \\\\item \\\\texttt{0} -- 应用程序中不存在dex文件 \\n \\\\item \\\\texttt{°} -- 已暂停的应用程序\\n \\\\item \\\\texttt{\\\\#} -- 应用程序请求系统分配一个大堆，即大运行时内存 \\n \\\\item \\\\texttt{?} -- 应用程序请求虚拟机处于安全模式。 \\n\\\\end{itemize}</string>\n    <string name=\"pages$main-page$version-info\">版本名称有以下前缀: \\n\\\\begin{itemize} \\n \\\\item \\\\texttt{\\\\_} -- 无硬件加速（减缓应用程序中的过渡动画或透明效果） \\n \\\\item \\\\texttt{\\\\textasciitilde} -- 仅用于测试的应用程序 \\n \\\\item \\\\texttt{debug} -- 可调试的应用程序 \\n\\\\end{itemize}</string>\n    <string name=\"pages$main-page$list-options\">\\\\textbf{列表选项} 包含了对主页面中的列表进行排序和过滤的选项。</string>\n    <string name=\"pages$main-page$sort\">主页面中列出的应用程序可以按照以下方式进行排序: \\n\\\\begin{itemize} \\n \\\\item \\\\textbf{用户应用优先} 用户应用将优先展示 \\n \\\\item \\\\textbf{应用标签} 根据应用标签（也称为 \\\\textit{应用程序名称}）升序排序。(默认选项) \\n \\\\item \\\\textbf{包名} 根据包名升序排序 \\n \\\\item \\\\textbf{最后更新} 根据更新时间降序排序 \\n \\\\item \\\\textbf{共享 user ID} 根据共享 user ID升序排序 \\n \\\\item \\\\textbf{目标 SDK} 根据目标SDK升序排序 \\n \\\\item \\\\textbf{签名} 根据签名信息升序排序 \\n \\\\item \\\\textbf{已停用优先} 已停用将优先展示 \\n \\\\item \\\\textbf{已阻止优先} 根据已阻止的应用组件数目降序排序 \\n \\\\item \\\\textbf{已备份优先} 已备份将优先展示 \\n \\\\item \\\\textbf{追踪器} 根据追踪器数目降序排序S \\n \\\\item \\\\textbf{最后操作} 根据被App Manager操作的应用时间降序排序 \\n\\\\end{itemize} \\n \\n此外，还有 \\\\textit{反转} 选项，可以用来对列表进行反向排序。 \\n无论怎样的排序偏好，应用程序都会先按字母顺序排序，以防止产生任何随机排序结果。</string>\n    <string name=\"pages$main-page$filter\">主页面中列出的应用可以通过以下方式进行过滤:\\n\\\\begin{itemize}\\n \\\\item \\\\textbf{用户应用} 仅列出用户应用程序\\n \\\\item \\\\textbf{系统应用} 仅列出系统应用程序\\n \\\\item \\\\textbf{已停用应用} 仅列出已停用的应用程序\\n \\\\item \\\\textbf{已停止应用} 仅列出已停止运行的应用程序\\n \\\\item \\\\textbf{已安装应用} 仅列出已安装的应用程序\\n \\\\item \\\\textbf{已卸载应用} 仅列出已卸载的应用程序\\n \\\\item \\\\textbf{存在规则} 列出存在被一个或多个规则限制的应用程序\\n \\\\item \\\\textbf{有活动} 列出存在一个或多个活动的应用程序\\n \\\\item \\\\textbf{有备份} 列出存在一个或多个备份的应用程序\\n \\\\item \\\\textbf{无备份} 列出不存在备份的应用程序\\n \\\\item \\\\textbf{运行中应用} 列出当前正在运行的应用程序\\n \\\\item \\\\textbf{有分包} 列出存在一个或多个拆分APK的应用程序\\n \\\\item \\\\textbf{KeyStore} 仅列出存在Android 密钥库(KeyStore)的应用程序\\n \\\\item \\\\textbf{SAF} 仅列出使用存储访问框架(SAF)的应用程序\\n \\\\item \\\\textbf{SSAID} 仅列出存在可用的Settings.Secure.ANDROID_ID(即SSAID)的应用程序\\n\\\\end{itemize}\\n\\n与排序不同，筛选过程中可同时应用多个筛选选项。\\n比如被停用的用户应用程序可通过同时选择 \\\\textit{用户应用} and \\\\textit{已停用应用} 列出。 \\n对于需要筛选出用户应用以确保安全地执行某种操作的 \\\\hyperref[subsec:batch-operations]{批处理操作} 而言，\\n这很有帮助。\\n\\n\\\\begin{warning}{状态不一致}\\n App Manager 通过大量缓存相应的查询结果显示页面（并非实时更新）。\\n所以，某些状态（比如说停用和已停止运行状态）并不总是最新的。\\n\\\\end{warning}</string>\n    <string name=\"pages$app-details-page$$activities-title\">活动 (Activity)</string>\n    <string name=\"pages$app-details-page$$servcies-title\">服务 (Services)</string>\n    <string name=\"pages$app-details-page$$additional-features-for-rooted-phones-title\">针对已root的手机的额外功能</string>\n    <string name=\"pages$app-details-page$$permission-tabs-title\">权限选项卡</string>\n    <string name=\"pages$app-details-page$$uses-permissions-title\">使用权限</string>\n    <string name=\"pages$app-details-page$$permissions-title\">权限</string>\n    <string name=\"pages$app-details-page$$signatures-tab-title\">签名选项卡</string>\n    <string name=\"pages$app-details-page$$blocking-trackers-title\">拦截跟踪器。</string>\n    <string name=\"pages$app-details-page$$app-ops-title\">App Ops</string>\n    <string name=\"pages$app-details-page$colour-codes\">本页中使用的颜色列表，以及对应的含义:\\n\\\\begin{itemize}\\n \\\\item \\\\colorbox{uninstalled-day}{\\\\textcolor{black}{红色 (日间模式)}} / \\\\colorbox{uninstalled-night}{\\\\textcolor{white}{深红色 (夜间模式)}}\\n -- 表示任何应用操作(App ops)或权限存在危险的标志(flag)，或者任何组件在 App Manager 中被阻止，\\n 又或者是任何需要却又不受支持的功能特性。\\n\\n \\\\item \\\\colorbox{disabled-day}{\\\\textcolor{black}{亮红色 (日间模式)}} / \\\\colorbox{disabled-night}{\\\\textcolor{white}{暗红色 (夜间模式)}}\\n-- 表示组件在 App Manager 外被禁用，或任何不受支持的\\n可选功能特性。 \\n\\n \\\\begin{tip}{注意}\\n 标记为禁用（停用/阻止）的组件并不意味着它被用户禁用，它也可能被系统禁用，\\n或者在其清单(Android-Manifest.xml)中被标记为禁用（停用/阻止）。\\n被禁用（停用/阻止）的应用程序也会被系统（和App Manager）视为禁用（停用/阻止）。 \\n \\\\end{tip}\\n\\n \\\\item \\\\colorbox{tracker-day}{\\\\textcolor{black}{鲜橙色 (日间模式)}} / \\\\colorbox{tracker-night}{\\n \\\\textcolor{white}{暗橙色 (夜间模式)}} -- 表示存在跟踪器组件\\n\\n \\\\item \\\\colorbox{AMSoftMagenta}{\\\\textcolor{black}{紫色 (日间模式)}} / \\\\colorbox{AMVeryDarkViolet}{\\n \\\\textcolor{white}{深紫色 (夜间模式)}} -- 表示存在正在运行的服务。\\n\\n \\\\item \\\\colorbox{AMGreen}{\\\\textcolor{白色}{绿色}} -- 表示当前应用程序中的所有跟踪器\\n 已在 跟踪器指示器 标签页内被阻止。\\n\\\\end{itemize}</string>\n    <string name=\"pages$app-details-page$$shared-libs-tab-title\">共享库选项卡</string>\n    <string name=\"pages$one-click-ops-page$$1-click-back-up-title\">备份</string>\n    <string name=\"pages$one-click-ops-page$$1-click-restore-title\">恢复</string>\n    <string name=\"pages$settings-page$$install-location-title\">安装位置</string>\n    <string name=\"pages$settings-page$$installer-app-title\">安装来源</string>\n    <string name=\"pages$settings-page$$backup-restore-title\">备份/恢复</string>\n    <string name=\"pages$settings-page$$encryption-title\">加密</string>\n    <string name=\"pages$settings-page$$backup-volume-title\">备份位置</string>\n    <string name=\"pages$settings-page$$rules-title\">规则</string>\n    <string name=\"pages$settings-page$$instant-component-blocking-title\">即时组件拦截</string>\n    <string name=\"pages$settings-page$$import-export-blocking-rules-title\">导入/导出拦截规则</string>\n    <string name=\"pages$settings-page$$remove-all-rules-title\">删除所有规则</string>\n    <string name=\"pages$scanner-page$$missing-signatures-title\">缺少签名</string>\n    <string name=\"guide$backup-restore$$location-title\">位置</string>\n    <string name=\"guide$backup-restore$$options-title\">备份选项</string>\n    <string name=\"guide$backup-restore$$restore-title\">恢复</string>\n    <string name=\"guide$backup-restore$$delete-title\">删除备份</string>\n    <string name=\"faq$misc$$i-dont-use-root-adb-title\">我不使用root/ADB，是否完全安全？</string>\n    <string name=\"faq$misc$$how-tracker-updated-title\">跟踪器和库是如何更新的？</string>\n    <string name=\"faq$misc$$shizuku-title\">对于 Shizuku 有何计划？</string>\n    <string name=\"faq$misc$$bloatware-title\">什么是预装(bloatware)软件以及如何删除？</string>\n    <string name=\"appendices$specifications$$rules-specification-title\">规则语法</string>\n    <string name=\"pages$app-details-page$app-info-general-information\">以下的列表与“应用信息”选项卡中列出的顺序相同。 \\n\\\\begin{itemize} \\n \\\\item \\\\textbf{应用图标}: 应用程序的图标，若该应用程序没有图标，则显示系统默认图标。 \\n可以轻轻点击图标，通过对比剪贴板中存储的 SHA 或 MD5 总和的方式进行 APK 签名验证。 \\n \\\\item \\\\textbf{应用标签}: 应用程序的标签或名称。 \\n \\\\item \\\\textbf{包名}: 应用程序包名，点击该包名可将其复制到剪切板。 \\n \\\\item \\\\textbf{版本}: 版本分为两部分： \\n 第一部分称 \\\\textit{版本名(Version Name)}。 格式各不相同，但常由多个以点分隔的整数组成。 \\n 第二部分称 \\\\textit{版本代号}。 其被第一个括号括起来。版本代号是一个整数，用于区分应用程序版本 (因为机器可能无法正确读取版本名)。简言之，新版本的应用程序具有比旧版本更高的版本代号。 例如，如果 \\\\texttt{123} 和 \\\\texttt{125} 是同一个应用程序的两个版本代号，我们可以说后者比前者更新（后者的版本代号更高）。 \\n 当为同一版本的应用程序提供不同的 APK 文件，并在不同平台（移动端、平板、桌面等）或架构（32/64 位、ARM 或 Intel）上运行时，版本号可能会产生误导，因为通常应用程序提供商会为每个平台添加前缀以作区分。\\n \\n \\\\item \\\\textbf{标签}:(也称作标签云) 标签包含应用程序最基本、最简洁、有用的信息。参阅 \\\\Sref{subsubsec:tags}{标签} 内的完整标签列表。 \\n \\n \\\\item \\\\textbf{水平操作面板} 一个操作面板，由可以对应用程序执行的各种操作组成，参阅 \\\\Sref{subsubsec:horizontal-action-panel}{水平操作面板} 内的完整可用操作列表。 \\n 对于可用的其它操作列表，参阅 \\\\hyperref[subsubsec:app-info-options-menu]{选项菜单}。\\n \\n \\\\item \\\\textbf{路径与目录}: 包含应用程序相关路径的各种信息，包括 \\\\textit{应用目录} (存储 APK 文件的路径), \\\\textit{数据目录} (内部存储, 设备保护区以及外部存储) 和 \\\\textit{JNI 库目录} (如果有). JNI (Java Native Interface，Java本机接口) 库用于调用通常用 C/C++ 编写的本机原生代码。使用本机原生库可以使应用程序运行得更快，或帮助应用程序使用非 Java 语言编写的第三方库，同大多数游戏中所做的一样。 \\n通过单击每个目录项右侧的启动按钮，可以通过文件管理器打开目录，前提是它们提供相应的支持并被授予必要的权限。 \\n \\n \\\\item \\\\textbf{数据使用}: 操作系统报告的应用程序使用的数据量。 \\n 取决于 Android 版本，该项可能需要广泛的权限，包括 \\\\textit{使用情况访问} 权限和 \\\\textit{电话} 权限。 \\n \\n \\\\item \\\\textbf{存储与缓存}: 显示有关应用程序的大小（APK 文件、优化文件、数据和缓存）。 在旧设备中，还会显示外部数据、缓存、媒体和 OBB 文件夹的大小。如果在较新的设备中未授予 \\\\textit{使用情况访问} 权限，此部分将被隐藏。 \\n \\n \\\\item \\\\textbf{更多信息} 显示其他信息，例如-- \\n \\\\begin{itemize} \\n \\\\item \\\\textbf{SDK} 显示与 Android SDK 相关的信息: \\\\textit{Max} 表示目标SDK\\n 而 \\\\textit{Min} 表示最小SDK（后者在 Android 5及更低版本中不可用）\\n 如果目标SDK的值低于平台SDK的值（即当前操作系统支持的最大SDK的值），该应用程序会在兼容模式下运行。\\n 这意味着应用程序可能有权访问某些不可用或者被较新版本的 Android 限制的功能，\\n 这将导致安全和隐私问题。\\n SDK也被称作 \\\\textbf{API 级别 (API Level)}，\\\\\\\\\\n \\\\seealsoinline{\\\\href{https://en.wikipedia.org/wiki/Android_version_history\\\\#Overview}{Android 版本历史}}\\n \\n \\\\item \\\\textbf{标志位(Flags)}: 构建应用程序时使用的应用标志，关于完整的标志列表及其作用，参阅\\\\href{https://developer.android.com/reference/android/content/pm/ApplicationInfo\\\\#flags}{官方文档}。 \\n \\n \\\\item \\\\textbf{安装日期}: 首次安装应用程序的日期。 \\n \\n \\\\item \\\\textbf{更新日期}: 上次更新应用程序的日期。 如果应用程序尚未更新，该项与 \\\\textit{安装日期} 相同。 \\n\\n \\\\item \\\\textbf{进程名} 如果与包名不同的情况下，进程的名称。\\n 进程名在应用程序被系统启动时被设置，而通常情况下\\n 进程名与包名相同。\\n \\n \\\\item \\\\textbf{安装器应用} 安装该应用程序的应用程序。\\n 当安装该应用时，每次的安装器应用不总是会保持相同。\\n 因为 Android 允许对此字段设置任意值。\\n 在 Android 11及更高版本中，实际安装器应用会存储在系统，并可以通过点击\\n 项目右侧的“信息”按钮访问。即使系统并未报告安装器应用（比如说，安装器应用被卸载或隐藏），\\n 该字段也不会不可见。安装器应用可被系统授予额外的特殊权限\\n 以控制它安装的应用程序的某种行为。\\n \\n \\\\item \\\\textbf{User ID}: Android系统给应用设置的唯一用户ID. \\n 对于共享应用，相同的用户 ID 被分配给具有相同 \\\\textit{Shared User ID} 的多个应用程序. \\n\\n \\\\item \\\\textbf{User ID} 系统设置的唯一的用户ID（User ID，也被称作UID）并赋予应用程序。 \\n 对于共享的应用程序，多个持有相同的 \\\\textit{Shared User ID} 的应用程序\\n 会被赋予同样的用户ID。 .\\n \\n \\\\item \\\\textbf{Shared User ID} 适用于共享同一个ID的应用程序们（它们之间的数据也是共享的）。\\n共享的应用程序们必须持有同样的 \\\\hyperref[subsec:signatures-tab]{签名}。\\n \\n \\\\item \\\\textbf{首选ABI}: 此平台为此应用程序提供支持的架构。 \\n \\n \\\\item \\\\textbf{Zygote 预加载名称}: 负责预加载应用程序代码\\n和在所有使用应用 zygote 的隔离服务之间共享的数据。\\n \\n \\\\item \\\\textbf{隐藏 API 执行策略}: 从 Android 9 开始，第三方应用程序无法通过隐藏 API 执行策略访问 Android 框架中的许多方法和类。 \\n存在以下选项： \\n \\\\begin{itemize} \\n \\\\item \\\\textit{默认}: 基于应用程序的类型。 对于系统应用程序，隐藏API执行策略应该被禁用；而对于其他应用，则应该被强制执行。 \\n \\\\item \\\\textit{无或已禁用}: 该应用可以像在 Android 9 之前一样完全访问隐藏的 API。\\n \\\\item \\\\textit{警告}: 同上，只是每次应用程序访问隐藏 API 时都会记录警告。绝大多数情况下不使用。 \\n \\\\item \\\\textit{强制执行}: 无论是深灰名单还是黑名单，或者两者都是的应用程序无法访问隐藏的 API。 \\n这是 Android 9 及更高版本中第三方应用程序的默认选项，除非该应用程序被 OEM 或供应商列入白名单。 \\n \\\\begin{warning}{警告} \\n 隐藏 API 执行策略在 Android 中并没有被正确实现，\\n应用程序可以绕过它。因此，不应该信任此值。 \\n \\\\end{warning} \\n \\\\end{itemize} \\n \\n \\\\item \\\\textbf{SELinux}: 操作系统通过 SELinux 设置的强制访问控制 (MAC) 策略。 \\n \\n \\\\item \\\\textbf{主活动}: 应用的主要入口点。 \\n 仅在应用程序具有 \\\\hyperref[subsubsec:activities]{活动} 并且其中任何一个都可以从启动器中打开时显示。\\n 右侧也有一个启动按钮，可用于启动此活动。 \\n \\\\end{itemize} \\n\\\\end{itemize}</string>\n    <string name=\"pages$app-details-page$app-info-options-menu\">选项菜单位于页面的右上角, 下面给出了对现有选项的完整描述: \\n\\\\begin{itemize} \\n \\\\item \\\\textbf{分享}: 分享按钮可用于分享 APK 或 (如果该应用程序有多个拆分、OBB 文件或任意依赖项) 提取自应用程序的 \\\\textit{APKS}。\\n \\n \\\\item \\\\textbf{刷新}: 刷新应用信息选项卡。\\n \\n \\\\item \\\\textbf{在设置中查看}: 在 Android 设置中打开该应用程序。 \\n \\n \\\\item \\\\textbf{备份/恢复}: 打开备份/恢复对话框。 \\n \\n \\\\item \\\\textbf{导出屏蔽规则}: 导出在 App Manager 中为该应用配置的规则。 \\n \\n \\\\item \\\\textbf{在 Termux 中打开}: 在 Termux 中打开应用。 实际是在表明 \\\\texttt{user\\\\_id} 应用程序的内核用户ID的前提下运行 \\\\texttt{su - user\\\\_id} 命令 (参阅 §\\\\Sref{subsubsec:app-info-general-information} 中的描述)。该选项仅对 Root 用户显示。 \\n 请参阅 §\\\\Sref{subsubsec:config-termux} 以了解如何配置 Termux 以运行来自第三方应用的命令。 \\n \\n \\\\item \\\\textbf{在 Termux 中运行}: 在Termux中通过 \\\\texttt{run-as package\\\\_name} 打开应用。 \\n 此选项仅对可调试应用有效，并同时适用于 Root 与 ADB 用户。 \\n 请参阅 §\\\\Sref{subsubsec:config-termux} 以了解如何配置 Termux 以运行来自第三方应用的命令。 \\n \\n \\\\item \\\\textbf{MagiskHide}: 打开一个包含该应用程序所有进程名的列表的对话框，这些进程可以添加到 MagiskHide 列表或从MagiskHide 列表中移除。\\n \\n \\\\item \\\\textbf{Magisk 排除列表(DenyList)}: 打开一个包含该应用程序所有进程名的列表的对话框，这些进程可以添加到 Magisk 排除列表或从Magisk 排除列表中移除。\\n \\n \\\\item \\\\textbf{电池优化}: 为该应用程序启用/禁用电池优化。 \\n \\n \\\\item \\\\textbf{传感器} 为该应用程序启用/禁用传感器。\\n\\n \\\\item \\\\hyperref[sec:net-policy]{\\\\textbf{联网策略}}: 为该应用程序配置联网策略（如后台数据使用）。\\n \\n \\\\item \\\\textbf{导出图标}: 提取应用图标并将其保存至共享存储。 \\n \\n \\\\item \\\\textbf{添加到配置文件}: 将应用程序添加到已配置的 \\\\hyperref[sec:profile-page]{配置文件}。\\n\\n \\\\item \\\\textbf{安装到……} 将该应用程序安装到其他用户和/或已配置文件（如果有）。\\n\\\\end{itemize}</string>\n    <string name=\"pages$app-details-page$activities\">\\\\textbf{活动 (Activity)} 是可被 Android 系统唯一标识的窗口或页面 (如\\\\textit{主页} 和 \\\\textit{应用详情页} 是两个活动)。\\n每个活动可以有多个 UI 组件，称为 \\\\textit{部件(widgets)} 或 \\\\textit{碎片(fragments)}，\\n每个组件都可以嵌套或放置在彼此之上。\\n开发者还可以选择使用名为\\\\textit{意图过滤器(intent filters)} 的方法在活动 (Activity)中打开外部文件、链接等。\\n例如，当你使用文件管理器打开文件时，\\n文件管理器或操作系统通过应用包管理器 (PackageManager) 扫描意图过滤器\\n以查找能够打开文件的活动，并列出它们，你可以选择打开该文件的方式 (活动)。\\n \\n标记为 \\\\textit{exportable (可导出)} 的活动通常可被任意第三方应用程序打开。\\n然而，有些活动可能需要权限，只有拥有这些权限的应用程序才能打开这些活动。\\n在 \\\\textit{活动} 选项卡中，可通过 \\\\textbf{启动} 按钮启动某些活动。\\n若有必要可提供诸如意图 (Intent)的附加功能 (extras)、数据 (data)或 Action (动作)等额外信息 (参数)，\\n则可通过长按 \\\\textbf{启动} 按钮以打开提供该功能的 \\\\hyperref[sec:interceptor-page]{活动拦截器} 页面。\\n \\n\\\\begin{tip}{提示}\\n 无 Root 用户可通过 ADB 授予 \\\\texttt{android.permission.WRITE\\\\_SECURE\\\\_SETTINGS} 权限\\n 以打开 \\\\textit{不可导出的} 活动。\\n\\\\end{tip}\\n\\n\\\\begin{tip}{注意} \\n 若启动活动时抛出错误 (异常)，很可能是它具有某些未满足的依赖项目\\n (例如无法通过启动按钮打开 App Manager 的 \\\\textit{应用详情页} ，\\n 因为该活动需要提供一个包名 (在缺少包名的情况下打开 App Manager 的应用详情页没有意义)。 \\n 由于无法有章法的推断这些依赖关系，默认情况下可能无法通过 App Manager 打开这些活动。 \\n\\\\end{tip} \\n\\n也可通过 \\\\textbf{创建快捷方式} 按钮创建活动的快捷方式。\\n如果你需要提供额外信息 (参数)，\\n那么可通过活动拦截器页面创建快捷方式。 \\n \\n\\\\begin{danger}{警告} \\n 如果你卸载了 App Manager，那么所有由 App Manager 创建的快捷方式都将被移除。\\n\\\\end{danger}</string>\n    <string name=\"pages$profiles-page$$section-title\">配置文件页面</string>\n    <string name=\"pages$profiles-page$$options-menu-title\">选项菜单</string>\n    <string name=\"pages$profile-page$$configurations-tab-title\">配置选项卡</string>\n    <string name=\"pages$profile-page$$comment-title\">备注</string>\n    <string name=\"pages$profile-page$$section-title\">配置页</string>\n    <string name=\"pages$profile-page$$options-menu-title\">选项菜单</string>\n    <string name=\"pages$profile-page$$apps-tab-title\">应用程序选项卡</string>\n    <string name=\"pages$profile-page$$components-title\">组件</string>\n    <string name=\"pages$profile-page$$state-title\">状态</string>\n    <string name=\"pages$profile-page$$users-title\">用户</string>\n    <string name=\"pages$profile-page$$app-ops-title\">AppOps 权限</string>\n    <string name=\"pages$profile-page$$permissions-title\">权限</string>\n    <string name=\"pages$profile-page$$backup-restore-title\">备份/恢复</string>\n    <string name=\"pages$profile-page$$export-blocking-rules-title\">导出屏蔽规则</string>\n    <string name=\"pages$profile-page$$force-stop-title\">强制停止</string>\n    <string name=\"pages$profile-page$$clear-cache-title\">清除缓存</string>\n    <string name=\"pages$profile-page$$clear-data-title\">清除数据</string>\n    <string name=\"pages$profile-page$$save-apk-title\">保存APK</string>\n    <string name=\"pages$settings-page$$section-title\">设置页面</string>\n    <string name=\"pages$settings-page$$mode-of-operation-title\">操作模式</string>\n    <string name=\"pages$settings-page$$signature-schemes-title\">签名方案</string>\n    <string name=\"pages$settings-page$$signing-key-title\">签名密钥</string>\n    <string name=\"pages$settings-page$$language-title\">界面语言</string>\n    <string name=\"pages$settings-page$$app-theme-title\">应用主题</string>\n    <string name=\"pages$settings-page$$screen-lock-title\">屏幕锁定</string>\n    <string name=\"pages$settings-page$$installer-title\">安装器</string>\n    <string name=\"pages$settings-page$$sign-apk-title\">签名 APK</string>\n    <string name=\"pages$settings-page$$compression-method-title\">压缩方法</string>\n    <string name=\"pages$settings-page$$backup-options-title\">备份选项</string>\n    <string name=\"pages$settings-page$$backup-apps-with-keystore-title\">备份带 Android 密钥库的应用程序</string>\n    <string name=\"pages$settings-page$app-theme\">配置应用内主题。</string>\n    <string name=\"pages$settings-page$$import-export-keystore-title\">导入/导出密钥库</string>\n    <string name=\"pages$settings-page$$device-info-title\">关于设备</string>\n    <string name=\"pages$settings-page$install-location\">定义 APK 安装位置，可以是 \\\\textit{自动}、\\\\textit{仅内部存储} 和\\\\textit{偏好外部存储}。\n\\n在较新的 Android 版本中，选择最后一个选项\n\\n并不保证应用将被安装在外部存储中。</string>\n    <string name=\"pages$settings-page$enable-disable-features\">启用或禁用 App Manager 中的某些功能，如 \\n\\\\begin{itemize} \\n \\\\item \\\\textbf{拦截器} \\n \\\\item \\\\textbf{Manifest 查看器} \\n \\\\item \\\\textbf{扫描器} \\n \\\\item \\\\textbf{包安装器} \\n \\\\item \\\\textbf{使用情况.} 如关闭此功能，App Manager 永远不会请求 \\\\textit{使用情况} 权限. \\n \\\\item \\\\textbf{日志查看器} \\n\\\\item \\\\textbf{App Explorer.} ``探索\\'\\' 选项在尝试打开 APK 文件时不可用。 \\n \\\\item \\\\textbf{App info.} 尝试打开 APK 文件时会显示 ``应用信息\\'\\'选项 \\n \\\\item \\\\textbf{代码编辑器}\\n \\\\item \\\\textbf{VirusTotal}\\n\\\\end{itemize}</string>\n    <string name=\"pages$settings-page$backup-restore\">与 \\\\hyperref[sec:backup-restore]{备份恢复} 相关的设置.</string>\n    <string name=\"pages$interceptor-page$$data-title\">数据(Data)</string>\n    <string name=\"pages$interceptor-page$$mime-type-title\">MIME 类型</string>\n    <string name=\"pages$interceptor-page$$categories-title\">类别(Categories)</string>\n    <string name=\"pages$interceptor-page$$flags-title\">标志位(Flags)</string>\n    <string name=\"pages$interceptor-page$$extras-title\">附加数据(Extras)</string>\n    <string name=\"pages$interceptor-page$$uri-title\">URI</string>\n    <string name=\"pages$interceptor-page$$matching-activities-title\">匹配的活动(Activity)</string>\n    <string name=\"pages$interceptor-page$$reset-to-default-title\">重置为默认</string>\n    <string name=\"pages$interceptor-page$$send-edited-intent-title\">发送编辑过的意图(Intent)</string>\n    <string name=\"pages$shared-prefs-editor-page$$section_title\">共享首选项(Shared Preferences)编辑页</string>\n    <string name=\"guide$aot$$section-title\">经由 TCP 的 ADB</string>\n    <string name=\"guide$aot$$enable-dev-options-title\">启用开发者选项</string>\n    <string name=\"guide$aot$$location-dev-options-title\">开发人员选项的位置</string>\n    <string name=\"guide$aot$$how-to-enable-dev-options-title\">如何启用开发者选项</string>\n    <string name=\"guide$aot$$enable-usb-debugging-title\">启用USB调试</string>\n    <string name=\"guide$aot$$miui-usb-debug-title\">小米 (MIUI)</string>\n    <string name=\"guide$aot$$emui-usb-debug-title\">华为 (EMUI)</string>\n    <string name=\"guide$aot$$lg-usb-debug-title\">LG</string>\n    <string name=\"guide$aot$$troubleshooting-usb-debug-title\">故障排除</string>\n    <string name=\"guide$aot$$setup-adb-on-pc-title\">在PC或Mac上配置ADB</string>\n    <string name=\"guide$aot$$setup-adb-win-title\">Windows</string>\n    <string name=\"guide$aot$$setup-adb-linux-title\">Linux</string>\n    <string name=\"guide$aot$$configure-aot-title\">配置经由TCP的ADB</string>\n    <string name=\"guide$aot$$aot-lineage-os-title\">Lineage OS 17.1 及更早版本</string>\n    <string name=\"guide$aot$$enable-aot-via-pc-title\">在 PC 或 Mac 上启用 经由TCP的ADB</string>\n    <string name=\"guide$aot$$adb-mode-am-title\">在 App Manager 中启用 ADB 模式</string>\n    <string name=\"guide$aot$$setup-adb-mac-title\">macOS</string>\n    <string name=\"guide$backup-restore$$section-title\">备份/恢复</string>\n    <string name=\"guide$backup-restore$$backup-title\">备份</string>\n    <string name=\"guide$net-policy$$section-title\">连网策略</string>\n    <string name=\"faq$aot$$section-title\">ADB over TCP (经由TCP的ADB)</string>\n    <string name=\"faq$aot$$restart-title\">我必须在每次重启后启用ADB over TCP吗？</string>\n    <string name=\"faq$aot$$usb-debugging-title\">无法启用 USB 调试，怎么办？</string>\n    <string name=\"faq$aot$$block-tracker-title\">我可以使用 ADB over TCP 来禁用跟踪器或任何其他应用程序组件吗？</string>\n    <string name=\"faq$aot$$feature-adb-title\">哪些功能可以在ADB模式下使用？</string>\n    <string name=\"faq$misc$$section-title\">杂项</string>\n    <string name=\"appendices$specifications$$chapter-title\">语法</string>\n    <string name=\"appendices$specifications$$external-title\">外部</string>\n    <string name=\"appendices$specifications$$background-title\">背景介绍</string>\n    <string name=\"appendices$specifications$$rules-file-format-title\">规则文件格式</string>\n    <string name=\"appendices$specifications$$internal-title\">内部</string>\n    <string name=\"pages$main-page$apk-updater\">若系统中已安装\\\\href{https://github.com/rumboalla/apkupdater}{APK Updater} ，则可通过此菜单项直接打开.\n\\n若系统中不存在该应用，则该选项将被隐藏.</string>\n    <string name=\"pages$main-page$termux\">如果系统中已安装\\\\href{https://github.com/termux/termux-app}{Termux} ，则可直接从此菜单项运行会话（或\n\\n新会话）.\n\\n如果应用不存在，则此选项将被隐藏.</string>\n    <string name=\"pages$app-details-page$config-termux\">默认情况下，Termux 不允许运行来自第三方应用的命令。要使用此选项，请使用 Termux v0.96 以上版本，并且必须在 \\\\texttt{\\\\textasciitilde/.termux/termux.properties} 中添加 \\\\texttt{allow-external-apps=true}。 \\n \\n\\\\begin{tip}{Info} \\n 启用此选项不会削弱Termux的安全性。\\n 第三方应用仍然需要取得用户允许才能在Termux中运行任意命令。 \\n\\\\end{tip}</string>\n    <string name=\"pages$app-details-page$horizontal-action-panel\">如上节所述，水平滚动操作面板由各种与应用程序相关的操作组成，比如 -- \\n\\\\begin{itemize} \\n \\\\item \\\\textbf{启动}: 启动该应用程序。 前提是要有一个可启动（打开）的 \\\\hyperref[subsubsec:activities]{活动}。 \\n \\n \\\\item \\\\textbf{冻结}: 冻结/禁用该应用程序。 若应用程序已被冻结/禁用或用户没有足够的权限，则不会显示该按钮。 \\n 冻结/禁用该应用程序后，其图标可能会从（启动器的）应用抽屉中被隐藏，这取决于其配置，该应用程序创建的快捷方式也可能被删除。 \\n 该应用程序可能只能通过 App Manager 、\\\\texttt{pm} 命令或其他任意提供此功能的工具解冻/重新启用。 \\n 长按该按钮以打开一个可创建用于快速冻结/禁用或解冻/重新启用该应用程序的快捷方式的对话框。\\n \\n \\\\item \\\\textbf{卸载} 根据提示卸载该应用程序。\\n 在对话框提示中可以卸载系统应用程序的更新，\\n 或者当 App Manager 被授予足够高的权限，抑或操作系统支持，\\n 也可以选择仅卸载应用程序而不清除其数据和签名。\\n 对于后者，如果再度安装该应用程序，安装的应用程序必须与之前已安装的应用程序的签名匹配。\\n \\\\begin{tip}{提示}\\n 对于重新安装具有不同签名的应用程序，\\n 更好的方法是使用 App Manager 备份该应用程序的数据，然后在安装该应用程序后再还原数据，\\n 而不是在卸载该应用程序的过程中选择保留该应用程序的数据和签名，\\n 因为该操作在将来可能会导致未定义的行为的问题。\\n \\\\end{tip}\\n\\n \\\\item \\\\textbf{解冻} 解除冻结/重新启用该应用程序。\\n 若应用程序已被解冻/启用或用户没有足够的权限，则不会显示该按钮。\\n 与 \\\\textit{冻结} 按钮类似，长按该按钮以打开一个可创建用于快速冻结/禁用或解冻/重新启用该应用程序的快捷方式的对话框。\\n \\n \\\\item \\\\textbf{强行停止}: 强行停止该应用程序。 \\n \\n \\\\item \\\\textbf{清除数据}: 清除应用程序的数据，清除包括存储在应用内部和（仅 Android 10 以上）外部目录中的任何应用数据，包括帐户（如果由应用设置）、缓存等。 \\n例如，清除 App Manager 的数据将会删除所有保存在 App Manager 内的规则（但不会清除或重置在 App Manager 内设置的已阻止组件的状态），因此你需要随时备份你在 App Manager 内设置的规则。若用户没有足够的权限，则不会显示该按钮。 \\n \\n \\\\item \\\\textbf{清除缓存}: 清除应用程序的缓存。若该应用程序在操作过程中处于正在运行的状态，则缓存可能无法如预期般被清除。\\n\\n \\\\item \\\\textbf{安装}: 安装该应用程序。此按钮仅在该应用程序尚未安装时显示。 \\n \\n \\\\item \\\\textbf{新版变化 (What\\'s New)}: 若当前已安装的是该外部应用程序的旧版本，则会显示该按钮。\\n 点击该按钮以打开一个包含该版本和已安装版本在版本控制行为上的变化（差异）对比的对话框。\\n 变化包括：\\\\textit{版本}，\\\\textit{跟踪器}, \\\\textit{权限}, \\\\textit{组件}, \\\\textit{签名} (当校验值改变时显示)，\\n \\\\textit{功能特性}, \\\\textit{共享库} 与 \\\\textit{SDK}。\\n \\n \\\\item \\\\textbf{更新}: 若该应用程序的版本代号高于已安装的应用程序，则会显示该按钮。 \\n \\n \\\\item \\\\textbf{重装}: 若该应用程序与已安装的应用程序具有相同的版本代号，则会显示该按钮。 \\n \\n \\\\item \\\\textbf{降级}: 若该应用程序的版本代号低于已安装的应用程序，则会显示该按钮。 \\n \\n \\\\item \\\\textbf{应用清单(Manifest)}: 点击该按钮以在单独的页面中显示该应用程序的清单文件。\\n 若该应用程序存在一个或多个拆分，则会显示拆分的 APK 文件列表。\\n 点击其中任意一项以打开相应的清单文件。\\n \\n \\\\item \\\\textbf{扫描器}: 扫描该应用程序以列出潜在的跟踪器和库。\\n 若已配置并处于可用状态，它还会使用VirusTotal扫描文件，并从Pithus中获得结果，\\\\\\\\ \\n \\\\seealsoinline{\\\\hyperref[sec:scanner-page]{扫描器页面}} 。\\n \\n \\\\item \\\\textbf{共享首选项}: 显示该应用程序使用的共享首选项(Shared-Preferences)列表。 \\n 点击列表中的首选项将打开\\\\hyperref[sec:shared-preferences-editor-page]{共享首选项编辑器}。该按钮仅在用户拥有足够的权限时才会显示。\\n \\n \\\\item \\\\textbf{数据库}: 显示该应用程序使用的数据库列表。\\n 点击其中任意一项将打开可用于打开数据库的活动列表。\\n 该按钮仅在用户拥有足够的权限时才会显示。\\n \\n \\\\item \\\\textbf{F-Droid}: 在你常用的\\\\textit{F-Droid} 客户端中打开该应用程序。 \\n \\n \\\\item \\\\textbf{Store}: 在 \\\\textit{Aurora Store}打开该应用程序。该按钮仅在已安装 \\\\textit{Aurora Store} 时显示。\\n\\\\end{itemize}</string>\n    <string name=\"pages$app-details-page$component-tabs\">\\\\textbf{活动(Activities)}、\\\\textbf{服务(Services)}、\\\\textbf{接收器} (即广播接收器)\\n和 \\\\textbf{提供者} (例如内容提供者) 统称为应用程序组件，\\n因为它们提供类似的功能并共享类似的属性，\\n例如它们都有一个 \\\\textit{名称}、 \\\\textit{标签}、 \\\\textit{图标}、\\n可被启用或禁用、并且通过 \\\\textit{意图(Intent)} 执行。\\n应用程序组件是应用的组成部分，\\n必须在应用程序清单中声明 (也有一些例外情况)。 \\n应用程序清单是存储应用程序特定元数据的文件，Android 通过读取元数据来处理应用。 \\n \\n这些选项卡中使用的颜色在 \\\\Sref{subsec:app-details-colour-codes}{应用详情颜色代码} 中进行了解释。\\n也可以通过位于三点菜单的 \\\\textbf{排序} 选项，对组件列表进行排序，\\n以在列表顶部显示已阻止组件或者跟踪器组件。</string>\n    <string name=\"pages$settings-page$installer-app\">选择安装程序。这对于明确检查安装程序以验证应用程序是否合法安装的应用程序很有用。\n\\n这只适用于 root 或 ADB 用户。\n\\n\n\\n\\\\begin{tip}{Notice}\n\\n 对于应用来说，检查安装包似乎并无不妥，\n\\n 但 Android 框架已经在安装过程中处理了这个问题。因此，\n\\n 通过检查安装包是证明应用来源合法性是错误的。\n\\n\\\\end{tip}</string>\n    <string name=\"pages$settings-page$$enable-disable-features-title\">启用/禁用功能</string>\n    <string name=\"pages$settings-page$$apk-signing-title\">APK 签名</string>\n    <string name=\"pages$settings-page$sign-apk\">安装应用前是否对 APK 文件进行签名。可用 \\\\hyperref[subsec:apk-signing]{APK 签名} 页面\n\\n来配置签名。</string>\n    <string name=\"pages$scanner-page$$section-title\">扫描器页面</string>\n    <string name=\"pages$interceptor-page$$action-title\">动作(Action)</string>\n    <string name=\"pages$interceptor-page$$section-title\">拦截器页面</string>\n    <string name=\"pages$interceptor-page$$intent-filters-title\">意图(Intent)过滤器</string>\n    <string name=\"guide$main$$guides-chapter-title\">指南</string>\n    <string name=\"faq$app-components$$also-blocked-by-other-tools-title\">现在被 App Manager 拦截但先前被其他工具禁用的组件会发生什么？</string>\n    <string name=\"faq$main$$faq-chapter-title\">常见问题</string>\n    <string name=\"faq$app-components$$section-title\">应用组件</string>\n    <string name=\"faq$app-components$$what-are-app-components-title\">什么是应用组件？</string>\n    <string name=\"faq$app-components$$limitations-title\">追踪器和其他组件在App Manager中是如何被禁用的？其局限性是什么？</string>\n    <string name=\"faq$app-components$$other-tools-retained-in-am-title\">被其他工具禁用的应用程序组件是否保留在App Manager中？</string>\n    <string name=\"faq$app-components$$what-is-component-blocking-title\">什么是即时组件禁用？</string>\n    <string name=\"faq$app-components$$tracker-classes-versus-tracker-components-title\">跟踪器类与跟踪器组件</string>\n    <string name=\"appendices$changelogs$$chapter-title\">更新日志</string>\n    <string name=\"pages$app-details-page$uses-permissions\">\\\\textbf{预定义权限}(\\\\textit{Uses Permissions}) 是应用(申请)所使用的权限。\\n这些权限在应用程序清单中通过使用 \\\\texttt{uses-permission} 标签声明。\\n诸如 \\\"标志位 (\\\\textit{flags})\\\"、\\\"权限名 (\\\\textit{permission name})\\\"、\\\"权限描述 (\\\\textit{permission description})\\\"、\\n\\\"包名 ( \\\\textit{package name})\\\"、\\\"群组 (\\\\textit{group})\\\" 此类的信息也取自其相关\\\\hyperref[subsubsec:permissions]{权限}。\\n\\n特权用户可通过点击每个权限右侧的切换按钮授予或撤销 危险 (\\\\textit{dangerous}) 和 开发 (\\\\textit{development}) 权限，\\n也可以使用菜单中的相应选项撤销危险权限。\\n因为 Android 不允许修改 普通 (\\\\textit{normal}) 权限（其中大多数是该类权限），只能撤销以上两种类别的权限。\\n也可尝试编辑 \\\\texttt{runtime-permissions.xml} 以撤销这些权限，\\n但是否可行尚不明确。 \\n\\n\\\\begin{tip}{提示} \\n 由于系统默认撤销危险权限，\\n 因此撤销所有危险权限与重置所有权限一致。\\n\\\\end{tip} \\n\\n可以以升序方式按权限名称对列表进行排序，\\n也可通过菜单中相应的选项优先显示拒绝的权限。</string>\n    <string name=\"pages$app-details-page$permissions\">(自定义)\\\\textbf{权限} 通常是应用自身定义的自定义权限，包括该应用声明的、标记为\\\"内部( \\\\textit{Internal})\\\" 权限，其他应用声明、标记为\\\"外部( \\\\textit{External})\\\"的权限。外部权限在应用程序组件中指定为依赖项，即应用只有在拥有指定的权限时才能调用该组件：\n\\n\\\\begin{itemize}\n\\n \\\\item \\\\textbf{名称} 每个权限都有的唯一的名称，如 \\\\texttt{android.permission.INTERNET} ，但多个应用可以请求同一个权限。\n\\n\n\\n \\\\item \\\\textbf{图标} 每个权限都可以有一个自定义图标，其他权限选项卡没有任何图标，因为它们在应用程序清单中不包含任何图标。\n\\n\n\\n \\\\item \\\\textbf{描述} 描述权限的可选字段，若没有与权限关联的任何描述，则不会显示该字段。\n\\n\n\\n \\\\item \\\\textbf{标志位(Flags)} 使用标志符号或 \\\\textbf{保护名称(Protection Level)} 名称描述权限， 诸如 普通 \\\\textit{normal}、开发 \\\\textit{development}、危险 \\\\textit{dangerous},、即时 \\\\textit{instant}, 已授权 \\\\textit{granted}、已撤销 \\\\textit{revoked}、签名 \\\\textit{signature}、特权 \\\\textit{privileged} 等。\n\\n\n\\n \\\\item \\\\textbf{包名} 表示与权限关联的包名，即定义权限的包名。\n\\n\n\\n \\\\item \\\\textbf{群组(Group)} 与权限关联的群组（如果有），几个相关的权限通常可以组合在一起。\n\\n\\\\end{itemize}</string>\n    <string name=\"pages$settings-page$language\">配置应用内语言。App Manager 目前支持 22 种语言。</string>\n    <string name=\"pages$app-details-page$permission-tabs\">\\\\textbf{App Ops}, \\\\textbf{使用权限} and \\\\textbf{权限} 选项卡与权限相关。\n\\n安卓中，在不具有相同身份（称为 \\\\textit{shared ID}）的应用或进程之间进行通信常常需要权限，其由权限控制器管理。\n\\n一些被视为\\\\textit{普通} 的权限，若它们出现在应用程序清单中，则会自动授予，但\\\\textit{危险}权限 和 \\\\textit{开发} 权限需要用户确认。\n\\n选项卡中使用的颜色在 \\\\Sref{subsec:app-details-color-codes} 中有解释。</string>\n    <string name=\"pages$app-details-page$app-ops\">\\\\textbf{App Ops} 代表\\\"应用操作 \\\\textbf{ (Application Operations)} \\\"。 \\n自 Android 4.3 起，Android 通过使用 \\\\textit{App Ops} 控制诸多系统权限，\\n每个 App Op 都有一个与之关联的唯一编号，该编号与其私有名称一同显示在“App Ops”选项卡中，\\n一些 App Ops 也有一个公共名称。\\n许多 App Ops 与 \\\\textit{权限} 相关。\\n在此选项卡中，若 App Ops 相关的权限被视为危险，则该 App Ops 会被标记为危险。\\n其他信息如 \\\\textit{标志位 (flags)} 、 \\\\textit{权限名称} 、 \\\\textit{权限描述} 、\\n\\\\textit{包名} 、 \\\\textit{群组} 也取自相关的 \\\\hyperref[subsubsec:permissions]{权限}。\\n其他信息可能包含以下内容：\\n\\\\begin{itemize} \\n \\\\item \\\\textbf{模式(Mode)}：描述了当前授权状态，可以是“\\\\textit{允许 (allow)}”、“\\\\textit{拒绝 (deny)}” (实际为错误)、\\n“\\\\textit{忽略 (ignore)}” (实际为拒绝) 、\\n“\\\\textit{默认 (default)}” (从手机供应商或 AOSP 内部设置的默认列表推断) 、\\n“\\\\textit{前台 (foreground)}” (在较新的 Android 版本中，应用只能在前台运行时才能使用该 App Op) ，\\n以及一些由供应商设定的模式 (例如 MIUI 使用 \\\\textit{询问 (ask)})。 \\n\\n \\\\item \\\\textbf{时长 (Duration)}：该 App Op 现已使用的时间\\n (可能为负，原因未知)。\\n\\n \\\\item \\\\textbf{允许时刻 (Accept Time)}: 上一次该 App Op 被允许的时刻。 \\n\\n \\\\item \\\\textbf{拒绝时刻 (Reject Time)}: 上一次该 App Op 被拒绝的时刻。 \\n\\\\end{itemize} \\n\\n\\\\begin{tip}{提示} \\n若 \\\\texttt{android.permission.GET\\\\_APP\\\\_OPS\\\\_STATS} 由 ADB\\\\@ 授予，则该选项卡的内容对非 Root 用户可见。\\n\\\\end{tip}\\n\\n每个 App Op 项都有切换按钮，可用于允许或拒绝 (忽略) 该App Op。\\n其他受支持的模式也可以通过长按切换按钮进行设置。\\n若选项卡中未列出所需的 App Op，则可使用菜单中的 \\\\textbf{设置自定义 App Op}。\\n菜单中的\\\\textbf{重置为默认} 选项可用于重置对 App Ops 的更改， 或使用菜单中相关选项拒绝所有危险的 App Ops。\\n受限于 App Ops 的工作方式，系统可能需要一段时间应用它们 (让这些更改生效)。\\n\\n\\\\begin{tip}{注意} \\n拒绝某些 App Ops 可能会导致应用程序行为异常。\\n若所有方式都失败，万不得已时可尝试使用 \\\\textit{重置为默认} 选项。\\n\\\\end{tip} \\n\\n可以以升序方式按 App Ops 名称和其相关编号 (或值)对列表排序，\\n也可通过相应的排序选项优先显示拒绝的 App Ops。\\n\\n\\\\seealsoinline{\\\\hyperref[ch:app-ops]{附录: App Ops}}</string>\n    <string name=\"keywords$chapter\">\\\\newcommand{\\\\KeywordChapter}{Chapter}</string>\n    <string name=\"pages$main-page$1-click-ops\">\\\\textbf{1-Click Ops}代表单击操作。\n\\n这将在新活动中打开\\\\hyperref[sec:1-click-ops-page]{相应页面}。</string>\n    <string name=\"keywords$see_also\">\\\\newcommand{\\\\KeywordSeeAlso}{另见:}</string>\n    <string name=\"keywords$end_of_keyword_in_alert\">\\\\newcommand{\\\\KeywordEndOfKeyWordInAlert}{.}</string>\n    <string name=\"titlepage$quotation\">\\\\begin{quotation}\n\\n 睿智而缓慢。跑得快的人会跌倒。\n\\n %\\\\sourceatright\n\\n {---劳伦斯修士，\\\\textit{罗密欧与朱丽叶}}\n\\n \\\\end{quotation}</string>\n    <string name=\"pages$main-page$$labs-title\">标签</string>\n    <string name=\"pages$main-page$profile_name\">也可以列出那些只存在于某个 \\\\hyperref[sec:profiles-page]{配置文件} 下的应用。\\n当执行某些无法通过 \\\\hyperref[sec:profiles-page]{配置文件} 完成的操作时（比如说卸载同配置文件下的所有应用程序)，\\n这会很有用。</string>\n    <string name=\"pages$main-page$profiles\">该菜单项会打开 \\\\hyperref[sec:profiles-page]{配置文件页面}. 配置文件是一种保存了频繁使用的任务的方式。\\n这些配置文件也可以通过快捷方式调用。</string>\n    <string name=\"pages$main-page$app-usage\">应用程序使用情况统计，比如说 \\\\textit{屏幕时间}、\\\\textit{数据流量使用情况} (包括移动数据和无线网络)、\\\\textit{打开某应用的次数统计}，\\n可通过单击菜单中的 \\\\textbf{应用程序使用情况} 选项进行访问.。\\n但是该功能需要 \\\\textit{使用情况统计信息访问} 权限。 \\n如使用情况统计信息访问功能在 \\\\hyperref[subsubsec:enable/disable-features]{设置}中被禁用，该菜单项在设置中不会被列出。</string>\n    <string name=\"pages$main-page$running-apps\">该菜单项打开一个新页面，显示正在运行的应用程序或进程列表。它也会显示\\n当前内存和缓存（如果可用）使用情况。如果 App Manager 在非root或ADB访问下运行，它只会显示自身使用情况\\n在近期的安卓版本。正在运行的应用或进程也可以在结果显示页面里被强行停止或杀掉。\\n每个进程标识符(PID)的日志也可以在 \\\\hyperref[subsubsec:main:labs]{log viewer} 里查阅。\\n此外，也可以通过点击图标或长按某一项进行批量处理操作。\\n通常情况下点击任意项目会打开一个显示更多详细信息的对话框。</string>\n    <string name=\"pages$main-page$debloater\">该菜单项会打开预装应用卸载页面，列出在设备和 App Manager 里可用的所有预装应用。\\n该页面也会推荐可替代的应用程序，这些预装应用以 \\\\href{https://github.com/MuntashirAkon/android-debloat-list}{Android Debloat List}\\n项目为判断基准。</string>\n    <string name=\"pages$main-page$labs\">该菜单项会打开一个标签页以列举所有附加功能。包括日志查看器、\\n系统配置、终端、文件管理器（类似 文件）、UI追踪器、意图拦截器，以及代码编辑器。</string>\n    <string name=\"pages$main-page$$debloater-title\">预装应用卸载器</string>\n    <string name=\"pages$app-details-page$$uses-features-tab-title\">使用特性选项卡</string>\n    <string name=\"pages$app-details-page$$configurations-tab-title\">配置选项卡</string>\n    <string name=\"pages$app-details-page$$tags-title\">Tags (标签)</string>\n    <string name=\"pages$app-details-page$tags-list\">\\\\begin{itemize}\\n \\\\item \\\\textbf{跟踪器信息} 应用程序里存在的跟踪器组件数量 (比如说 \\\\textit{5个跟踪器}) 。\\n 若追踪器未被阻止 (禁用)，则标签颜色会被显示为橙色；若追踪器在 App Manager 内被阻止，则标签颜色会被显示为暗青色。\\n 点击该标签以打开一个包含跟踪器组件的列表的对话框。\\n 这些组件可以通过授予 App Manager 足够高的权限阻止 (禁用)或解除阻止 (启用)。\\n\\n \\\\item \\\\textbf{应用程序类别} 用户应用程序或者系统应用程序。\\n 对于系统应用程序，会显示该应用程序是否被更新，\\n 或者该系统应用程序是否通过 Magisk 以 systemless (不直接修改系统的) 方式安装。\\n\\n \\\\item \\\\textbf{拆分 APK 信息} 排除基础 APK 的前提下，一个 APK 的拆分数量 (比如 \\\\textit{5个拆分}).\\n 点击该标签以打开一个包含若干附加信息（比如说名称、类型和大小）的对话框。\\n\\n \\\\item \\\\textbf{可调试} 该应用程序可以通过 ADB\\\\@ (Android Debug Bridge，Android 调试桥) 进行调试。\\n 可调试的应用程序可以使用某些不会提供给普通应用程序的功能。\\n 应用程序的数据可能会通过ADB (比如使用 \\\\texttt{run-as} 命令) 访问而无需额外的权限。\\n\\n \\\\item \\\\textbf{仅用于测试} 该应用程序是仅用于测试用途的应用程序。\\n 仅用于测试的应用程序可以使用某些不会提供给普通应用程序的功能。\\n 应用程序的数据可能会通过ADB (比如使用 \\\\texttt{run-as} 命令) 访问而无需额外的权限。\\n\\n \\\\item \\\\textbf{无代码} 该应用程序并没有任何代码（即DEX文件不存在）。\\n 对于某些系统应用程序，其实际代码可能被存放于别的地方。\\n\\n \\\\item \\\\textbf{大堆内存 (Large heap)} 应用程序请求大堆内存占用（即在动态分配中请求更多的 RAM 内存占用）\\n 这仍然取决于系统，由系统决定是否给该应用程序分配较大的内存。\\n 例如 App Manager 会请求大堆内存占用，因为当扫描 APK\\\\@ 时，\\n 它需要加载整个 APK 到内存中。\\n\\n \\\\item \\\\textbf{打开链接} 该应用程序可能通过任意的应用程序打开某种链接。\\n 若该应用程序默认情况下能打开任何链接，则标签颜色会被显示为红色，否则会被显示为暗青色。\\n 点击该标签以打开一个包含受支持的hosts或域名的列表的对话框。\\n 在 Android 12 及更高版本，当授予 App Manager 足够高的权限时，\\n 会显示一个选项以启用或禁用打开默认链接。\\n 否则，会显示一个选项以打开该应用程序的系统设置页面。\\n\\n \\\\item \\\\textbf{正在运行} 应用程序中的一个或多个服务当前正在后台运行。\\n 点击该标签以打开一个包含正在运行的服务列表的对话框。\\n 当日志浏览器功能被启用时，点击任意服务会打开日志浏览器，\\n 该日志浏览器会启用默认的筛选器合集，筛选出与UID关联的服务（若运行于独立进程或隔离进程，\\n 则服务关联的UID可能与应用程序自身的UID不同）\\n 除此以外还会提供一个选项以强行停止该应用程序。\\n\\n \\\\item \\\\textbf{已停止} 已经被强行停止的应用程序。若该应用程序稍后自动运行，则可能不会被停止。\\n\\n \\\\item \\\\textbf{已禁用} 表示该应用程序已经被禁用 (启动器里该应用程序的图标被隐藏)。\\n\\n \\\\item \\\\textbf{已暂停} 表示该应用程序已经被暂停 (启动器里该应用程序的图标变成灰色)。\\n\\n \\\\item \\\\textbf{已隐藏} 表示该应用程序已经被隐藏 (启动器里该应用程序的图标被隐藏)。\\n\\n \\\\item \\\\textbf{MagiskHide} 对该应用程序启用了 MagiskHide。\\n 点击该标签以打开一个包含该应用程序所有进程名的列表的对话框，\\n 该对话框内的进程列表可以被添加到 MagiskHide 或从 MagiskHide 中移除。\\n\\n \\\\item \\\\textbf{Magisk 排除列表} 该应用程序在 Magisk 的排除列表中。\\n 点击该标签以打开一个包含该应用程序所有进程名的列表的对话框，\\n 该对话框内的进程列表可以被添加到 Magisk 的排除列表或从 Magisk 的排除列表中移除。\\n\\n \\\\item \\\\textbf{WX} 应用程序违反了“W\\\\textasciicircum{}X 策略”（Write xor Execute，写异或执行），\\n 允许应用程序在同一目录或内存的同一部分中写入和执行。 而这将允许执行任意可执行代码，\\n 无论是修改可执行代码并将其嵌入到应用程序中，\\n 还是执行从 Internet 下载的可执行代码。\\\\\\\\\\n \\\\seealsoinline{\\\\href{https://en.wikipedia.org/wiki/W\\\\%5EX}{W\\\\textasciicircum{}X in Wikipedia}}\\n\\n \\\\item \\\\textbf{Bloatware} 该应用程序可能是已知的预装软件（Bloatware）。\\n 它们预装在用户的设备上并占用大量的空间，哪怕用户并不需要它们。\\n 点击该标签以打开一个包含详细信息和额外建议（若可用）的对话框。\\n\\n \\\\item \\\\textbf{密钥库} 该应用程序有条目存储在 Android 密钥库 中。\\n 点击该标签以打开一个包含所有属于该应用程序的密钥（KeyStore）文件的列表的对话框。\\n\\n \\\\item \\\\textbf{已备份} 该应用程序使用 App Manager 进行过至少一次备份。\\n 点击该标签以打开一个包含所有可用备份和 metadata 的对话框。\\n\\n \\\\item \\\\textbf{无电池优化} 该应用程序的电池优化被禁用。\\n 通过点击该标签，可以尝试重新启用该应用程序的电池优化。\\n\\n \\\\item \\\\textbf{传感器已禁用} 该应用程序的传感器已被禁用。\\n 对绝大多数应用程序而言，传感器默认情况下是被禁用的。\\n\\n \\\\item \\\\hyperref[sec:net-policy]{\\\\textbf{网络策略}} 对该应用程序配置了网络策略 (例如后台数据流量使用)\\n 点击该标签以打开一个包含受支持的策略的对话框。\\n 这些策略视平台而定，并存在附加选项以配置它们。\\n\\n \\\\item \\\\hyperref[sec:terminologies]{\\\\textbf{SSAID}} 点击该标签以打开一个包含\\n 当前被分配给该应用程序的 SSAID (Settings.Secure.ANDROID_ID) 的对话框。SSAID可按需重置或重新生成。\\n\\n \\\\item \\\\textbf{SAF} 表示该应用程序已通过存储访问框架（Storage Access Framework，即SAF）\\n 被授予访问一个或多个存储位置或文件（即URIs）权限。\\n 点击该标签以打开一个包含已授权的URIs的列表的对话框。\\n\\n \\\\item \\\\textbf{Play 应用签名} 表示该应用程序可能由谷歌进行签名。\\n\\n \\\\item \\\\textbf{Xposed} 表示该应用程序可能是一个Xposed模块。\\n 点击该标签以打开一个包含附加信息的对话框。\\n\\n \\\\item \\\\textbf{静态共享库} 表示该应用程序充当一个或多个应用程序的静态共享库。\\n 点击该标签以打开一个包含已安装库的版本的列表的对话框，\\n 并提供附加选项以卸载它们。\\n \\\\begin{tip}{注意}\\n Trichrome 库 (由Google Chrome，Vanadium或类似的项目提供)\\n 是目前已知的唯一一个 Android 静态共享库。\\n \\\\end{tip}\\n\\\\end{itemize}</string>\n    <string name=\"pages$app-details-page$servcies\">不同于用户能看见的 \\\\hyperref[subsubsec:activities]{活动}，\\\\textbf{服务} 处理后台任务。\\n比如当你正在使用手机 Internet 浏览器从 Internet 下载视频时，\\n该Internet 浏览器会使用 \\\\textit{前台服务} 下载内容。\\n\\n当一个活动被关闭或从 \\\\textit{最近任务} 页面被移除，它可能会被立刻销毁。\\n这取决于手机可用的内存、电池统计或者该活动的配置情况。\\n但是如果你想，服务可以一直运行下去。\\n如果有多个在后台运行的服务，由于内存减少或者处理能力下降，\\n手机会变得很卡很慢，\\n与此同时手机电量会被消耗得更快。较新版本的 Android 推出了电池优化功能，并对所有应用默认开启。\\n当该功能被启用时，系统能够根据系统拥有的资源量或服务请求，随机终止任意服务。\\n但是，前台服务（即发送固定通知的服务，比如说音乐播放器、下载器）在通常情况下不会被终止，\\n除非系统资源（内存，电量等）严重不足。\\n某些原厂系统能提供更为强势激进的优化，\\n比如说MIUI 有一个非常有名又强势的优化功能，即 \\\\textit{MIUI 优化}。\\n\\n活动和服务都运行在同一套 \\\\href{https://stackoverflow.com/questions/7597742}{looper} ，称之为主looper，\\n意味着服务并非真正在后台运行，而是需要开发者确认的任务。\\n至于应用程序是如何通过服务进行交流的？\\n是通过 \\\\hyperref[subsubsec:app-details-receivers]{广播接收器} 或者 Binder 进行通信的。</string>\n    <string name=\"pages$app-details-page$additional-features-for-rooted-phones\">与在这些标签面前只能当个看客的无 Root 用户不同，Root 用户可以执行各种操作。</string>\n    <string name=\"pages$app-details-page$receivers\">\\\\textbf{接收器} (也被称作 \\\\textit{广播接收器}) 可以用于在某些事件发生时触发某些任务的执行。\\n由于这些组件在接收到广播信息时被执行，故被称作广播接收器。\\n这些广播消息通过名为 \\\\textit{意图 (Intent)} 的方法发送。\\n意图 (Intent) 是 Android 的特殊功能，可用于打开应用程序（即活动）、运行服务和发送广播消息。\\n因此，像 \\\\hyperref[subsubsec:activities]{活动}和广播接收器会使用 \\\\textit{意图过滤器} 接收需要的广播消息。\\n广播消息可以被系统或应用程序自身发送。当广播消息被发送时，\\n相应的接收器会被系统激活，这样它们就能执行任务。\\n举个例子，如果你的手机资源不足，在你启用数据流量或连接至Wi-Fi时，\\n手机可能会有片刻无响应或变得很卡。\\n这是因为一旦数据连接被启用，可以接收\\\\texttt{android.net.conn.CONNECTIVITY\\\\_CHANGE}的广播接收器将被系统激活。\\n由于很多应用程序通常情况下都会使用该意图过滤器，这些应用几乎都会立刻被系统激活，这就导致了手机的无响应或卡顿。\\n\\n接收器也可被用于 IPC (Inter-Process Communication，进程间通信)，即\\n用于多个应用程序间交流（通信），甚至用于同一应用程序下不同组件的通信。</string>\n    <string name=\"pages$app-details-page$blocking-components\">在每个组件项目的最右侧，都有一个开关，可用于切换该组件的阻止状态。\\n若 \\\\hyperref[subsubsec:instant-component-blocking]{即时组件阻止} 未启用\\n或者之前从未对此应用程序应用阻止规则，\\n则需要通过三点菜单中的 \\\\textbf{应用规则} 选项应用这些更改。\\n也可通过同样的选项 (这次会显示为 \\\\textbf{移除规则} )移除已经应用的规则。\\n\\n也可长按按钮，以阻止使用一个或多个方法的组件。\\n\\n\\\\seealsoinline{\\\\hyperref[sec:faq:app-components]{FAQ: 应用组件}}</string>\n    <string name=\"pages$app-details-page$blocking-trackers\">可通过使用三点菜单中的 \\\\textbf{阻止跟踪器} 选项，对跟踪器组件进行阻止。\\n无论当前你在哪个标签页中，所有的跟踪器组件都会被阻止。\\n\\n\\\\begin{tip}{Info}\\n 跟踪器组件是应用组件的一个子集。\\n 因此，阻止跟踪器组件与阻止其他任意组件使用的方法相同。\\n\\\\end{tip}\\n\\n\\\\begin{amseealso}{另请参阅}\\n \\\\item \\\\hyperref[subsec:tracker-classes-versus-tracker-components]{FAQ: 跟踪器类与跟踪器组件}\\n \\\\item \\\\hyperref[sec:scanner-page]{扫描器页面}\\n \\\\item \\\\hyperref[subsec:block-unblock-trackers]{一键操作页面：阻止/解除阻止跟踪器}\\n\\\\end{amseealso}</string>\n    <string name=\"pages$app-details-page$configurations-tab\">\\\\textbf{配置} 标签页列出了应用程序需要的配置，\\n比如输入法类型 (qwerty、12键)，触屏方式 (手指、触摸笔等等)，以及导航方式 (拨号盘、跟踪球、滚轮)\\n对绝大多数应用程序而言，该标签页将会是空页面。</string>\n    <string name=\"pages$one-click-ops-page$$trim-caches-in-all-apps-title\">清理所有应用的缓存</string>\n    <string name=\"pages$profile-page$$profile-id-title\">配置文件ID</string>\n    <string name=\"pages$profile-page$$freeze-title\">冻结</string>\n    <string name=\"pages$profile-page$configurations-tab\">配置标签可用于配置选中的包。</string>\n    <string name=\"pages$profile-page$profile-id\">该配置文件的唯一ID，目前是基于配置文件名设置。\\n该配置文件ID可被第三方应用程序用于 \\\\hyperref[subsec:triggering-a-profile]{触发配置文件} 。</string>\n    <string name=\"pages$profile-page$comment\">这是会显示在 \\\\hyperref[sec:profiles-page]{配置文件页面} 的文本。\\n若并未设置，则会显示当前配置信息。</string>\n    <string name=\"pages$profile-page$freeze\">允许根据 \\\\hyperref[subsubsec:profile-state]{状态} 的值冻结或解冻选中的包。\\n若状态为 \\\\textit{开}，则包会被冻结。若状态为 \\\\textit{关}，则包会被解冻。</string>\n    <string name=\"pages$one-click-ops-page$$block-unblock-trackers-title\">阻止/取消阻止跟踪器</string>\n    <string name=\"pages$one-click-ops-page$$block-components-dots-title\">阻止组件\\\\dots</string>\n    <string name=\"pages$one-click-ops-page$$set-mode-for-app-ops-dots-title\">设置 App Ops 模式 \\\\dots</string>\n    <string name=\"pages$profile-page$intro\">配置文件页面显示配置文件的配置信息。也提供相应的选项以编辑它们。</string>\n    <string name=\"pages$profile-page$$block-trackers-title\">阻止跟踪器</string>\n    <string name=\"pages$profile-page$export-blocking-rules\">\\\\begin{danger}{危险}\\n 此选项尚未实现。\\n\\\\end{danger}</string>\n    <string name=\"pages$app-details-page$signatures-tab_2\">在此标签页中，使用了几种哈希算法以生成校验和，\\n包括 \\\\textit{MD5} 、 \\\\textit{SHA1} 、 \\\\textit{SHA256} 和 \\\\textit{SHA512}。\\n\\n\\\\begin{danger}{小心}\\n 签名信息应当通过可靠的散列算法进行验证，例如 \\\\textit{SHA256}。\\n 请勿依靠 \\\\textit{MD5} 或 \\\\textit{SHA1} 校验和，因为它们可以为多个证书\\n 生成相同的校验和。\\n\\\\end{danger}</string>\n    <string name=\"pages$profile-page$users\">选择需要应用配置文件的用户。默认情况下会选择所有用户。</string>\n    <string name=\"pages$app-details-page$signatures-tab_1\">\\\\textbf{签名} 实际上被称作签名信息。\\n一个应用程序在发布前，会被开发者用一个或多个签名密钥对该应用程序进行签名。\\n一个应用程序的完整性，即该应用程序是否来自实际开发者且未被其他人改动，\\n可通过使用内置在 APK 文件中的签名证书进行校验。\\n这是因为当一个应用程序被未经授权的实体改动时，由于签名密钥对该实体而言是未知的，\\n该应用程序就已经无法使用源签名密钥进行签名了。\\n一种验证应用程序完整性的方式就是验证证书生成的检验和 (checksums)。\\n若开发者提供签名证书的检验和，则它们可以\\n通过 \\\\textbf{签名} 标签页生成的检验和进行比较的方式校验该应用程序。 \\n举个例子，如果你从 GitHub 或 Telegram 频道中下载了 App Manager，\\n你可以通过简单匹配 \\\\textit{SHA256} 检验和与显示在此标签的这一个作比较，\\n以验证该应用程序是否真是由我发布：</string>\n    <string name=\"pages$one-click-ops-page$set-mode-for-app-ops-dots\">该选项用于对所有或者已选中的应用程序配置某些 \\\\hyperref[ch:app-ops]{应用操作 (App Ops)}。\\n存在两个字段，第一个字段用于插入多个被空格隔开的应用操作常量 (名称或值)。\\n由于可用的应用操作因设备和操作系统而异，并非所有的应用操作常量都能被事先了解。\\\\@.\\n需要的应用操作常量可在位于 \\\\hyperref[sec:app-details-page]{应用详情页} 中的 \\\\textit{App Ops} 标签页内查阅。\\n第二个字段可用于插入或根据特定的应用操作选择 \\\\hyperref[subsec:mode-constants]{模式}。\\n\\n\\\\begin{danger}{小心}\\n 除非你熟悉 App Ops (应用操作) 和阻止它们的后果，你应该避免使用该选项。\\n\\\\end{danger}</string>\n    <string name=\"pages$one-click-ops-page$back-up\">一键备份操作。以防万一，在执行任何操作前会列出所有受影响的备份。\\n\\n\\\\paragraph{备份所有应用} 备份所有的已安装的应用程序。\\n\\n\\\\paragraph{重新备份现有备份} 重新备份所有已安装且之前备份过的应用程序。\\n\\n\\\\paragraph{备份无备份应用} 备份所有已安装但尚未备份的应用程序。\\n\\n\\\\paragraph{验证和重新备份} 验证已安装的应用程序的近期备份，并在必要时重新备份。\\n\\n\\\\paragraph{备份发生变化的应用} 若某应用在上次备份后有所变化，则重新备份该应用。\\n通过检查一系列指标判断该应用是否发生变化，包括应用程序版本、最后更新日期、最后启动日期、完整性和文件哈希值。\\n目录哈希值会在备份过程中被计算并存储在数据库中。\\n在执行此操作时，会计算新的哈希值，并比较存储在数据库中的该项。</string>\n    <string name=\"pages$one-click-ops-page$restore\">一键还原。以防万一，在执行任何操作前会列出所有受影响的备份。\\n\\n\\\\paragraph{还原所有应用} 还原 \\\\textit{基本备份} 中所有已备份的应用程序。\\n\\n\\\\paragraph{还原未安装应用} 还原 \\\\textit{基本备份} 中所有已备份的应用程序中尚未安装的应用程序。\\n\\n\\\\paragraph{还原最新备份} 还原 \\\\textit{基本备份} 中版本代号比已安装应用程序的版本代号高的应用程序。</string>\n    <string name=\"pages$app-details-page$providers\">\\\\textbf{提供者}主要用于数据管理。\\n比如，当你使用 App Manager 保存 APK 文件或导出规则时会使用名为 \\\\texttt{.fm.FmProvider} 的内容提供者以保存 APK 或导出规则。\\nAndroid 中存在很多的提供者，包括这个由系统提供的\\n可被用于管理多个内容相关的任务，比如说数据库管理、跟踪、搜索等。\\n每个提供者有一个名为 \\\\textit{Authority (授权)} 的字段，\\n该字段对于整个 Android 生态系统中的应用程序来说是唯一的，就像包名一样。</string>\n    <string name=\"pages$app-details-page$uses-features-tab\">\\\\textbf{使用功能} 该标签页列出了由该应用程序声称的功能列表，比如 OpenGL ES、电话和 leanback。\\n应用程序可能需要某些功能，而有些功能对应用程序而言则是可选的。\\n所需功能必须与所需版本一起存在于系统中。\\n否则，任何安装应用程序的尝试会被系统拒绝。\\n用于此标签的颜色在 \\\\Sref{subsec:app-details-colour-codes} 有详细解释。</string>\n    <string name=\"pages$one-click-ops-page$intro\">该页面在选择 \\\\hyperref[subsec:main-page-options-menu]{主菜单} 中的 \\\\hyperref[subsubsec:main:1-click-ops]{一键操作选项} 时显示。</string>\n    <string name=\"pages$app-details-page$shared-libs-tab\">\\\\textbf{共享库} 该标签页列出了传统 JAR 依赖、\\n任意静态共享库依赖 (目前唯一一个已知的实例是基于Chromium的浏览器和WebViews )\\n以及 JNI (Java 本地接口) 库。对于JNI 库，有明确规定特定的平台 (x86/x86\\\\_64/ARM/AArch64)、\\n架构 (32/64 bit)、对象 (共享对象或可执行代码) 等。</string>\n    <string name=\"pages$one-click-ops-page$trim-caches-in-all-apps\">清除所有应用程序的缓存，包括 Android 系统。在执行此操作期间，\\n所有正在运行的应用程序的缓存可能不会如预期般被清除。</string>\n    <string name=\"pages$one-click-ops-page$block-unblock-trackers\">该选项可被用于阻止或解除阻止已安装应用程序的广告/跟踪器组件。\\n选择此项时，App Manager 会询问是否需要列出所有应用程序的跟踪器，或者仅列出用户应用程序的跟踪器。\\n新手用户应避免阻止系统应用程序的跟踪器以避免产生不良后果。\\n之后会弹出多选对话框，以将排除一个或多个应用程序从该操作中排除。\\n当按下 \\\\textit{阻止} 或 \\\\textit{解除阻止} 按钮时，这些变更会立刻生效。\\n\\n\\\\begin{warning}{注意}\\n 某些应用程序在禁用它们的跟踪器以后，可能无法如预期般运行。 若出现这种情况， 请移除所有阻止规则，\\n 或者打开对应应用的 \\\\hyperref[sec:app-details-page]{应用详情页} ，将组件标签页中被阻止的规则逐个移除。\\n\\\\end{warning}\\n\\n\\\\seealsoinline{\\\\hyperref[par:appdetails:blocking-trackers]{应用详情页：阻止跟踪器}}</string>\n    <string name=\"pages$one-click-ops-page$block-components-dots\">该选项用于阻止某些应用程序的组件，而判断依据是它们的签名。\\n一个组件的签名是组件的全称或部分名称。\\n安全起见，推荐在每一部分的签名结尾添加 \\\\texttt{.} (点)，\\n因为底层算法以贪婪的方式搜索和匹配组件。\\n也可以插入多个签名，在这种情况下，所有签名都要被空格隔开。\\n类似于上面的选项，此处也会提供对系统应用程序应用阻止的选项。\\n\\n\\\\begin{danger}{小心}\\n 如果你并不知道通过签名阻止应用程序组件的后果是什么，你应当避免使用该功能。\\n因为该功能使用不当可能会导致手机 bootloop (引导循环，具体现象就是手机不断重启并卡在开机第一屏或开机动画，但就是无法进入系统) 或者变砖 (除了通过特殊按键组合进入某些特殊模式外，手机保持黑屏状态)，最终你可能要执行恢复出厂设置。\\n\\\\end{danger}</string>\n    <string name=\"pages$profiles-page$intro\">配置文件页面可通过主菜单的 \\\\hyperref[subsec:main-page-options-menu]{选项菜单} 访问。\\n页面主要展示了已配置的文件列表以及对其进行操作的常规选项。\\n新配置文件也可通过位于底部右下角的 \\\\textit{加号} 按钮进行添加。\\n配置文件可以被导入、复制或删除。\\n单击配置文件项目以打开其 \\\\hyperref[sec:profile-page]{配置文件页面}。</string>\n    <string name=\"pages$profile-page$options-menu\">顶部右上角的三点菜单会打开选项菜单。其中包含若干个选项，例如--\\n\\\\begin{itemize}\\n \\\\item \\\\textbf{应用} 该选项用于直接应用配置文件。\\n 点击时，会显示一个可以选择 \\\\hyperref[subsubsec:profile-state]{配置文件状态} 的对话框。\\n 在选择其中一个状态后，配置文件会立即生效。\\n \\\\begin{tip}{注意}\\n 当你应用配置文件时，如果存在某些不符合标准的应用，它们会被直接忽略。\\n \\\\end{tip}\\n\\n \\\\item \\\\textbf{保存} 保存对配置文件的更改。\\n\\n \\\\item \\\\textbf{丢弃} 丢弃自上次保存后产生的全部更改。\\n\\n \\\\item \\\\textbf{删除} 点击此选项将将在无警告的情况下直接移除配置文件。\\n\\n \\\\item \\\\textbf{复制} 该选项用于复制配置文件。\\n 点击时会显示一个对话框，在对话框内可为新的配置文件命名。\\n 单击“OK”后，会复制当前配置文件存储的配置信息\\n 并加载到新的 \\\\hyperref[sec:profile-page]{配置文件页面} 。\\n 尽管如此，复制的配置文件在手动保存之前都不会被保存。\\n\\n \\\\item \\\\textbf{创建快捷方式} 该选项用于创建该配置文件的快捷方式。\\n 该功能提供两个选项： \\\\textit{简单} 和 \\\\textit{高级} 。\\n 选择 \\\\textit{高级} 进行配置时，会提示用户选择快捷方式被调用时的配置文件状态。\\n 选择 \\\\textit{简单} 进行配置时，则总是使用上一次保存的配置文件设置的默认状态。\\n\\\\end{itemize}</string>\n    <string name=\"pages$profiles-page$options-menu\">通过 App Manager 顶部右上角的三点菜单打开全局选项菜单。\\n其中有一个选项，用于导入先前从 App Manager 导出的已有配置文件。\\n\\n长按任意配置文件项目会弹出另一个选项菜单。该选项菜单提供以下选项：\\n\\\\begin{itemize}\\n \\\\item \\\\textbf{立即应用\\\\dots.} 该选项用于直接应用配置文件。\\n 点击时会显示一个对话框，在对话框内可选择 \\\\hyperref[subsubsec:profile-state]{配置文件状态}。\\n 选择其中一个状态后，配置文件会被立即应用。\\n\\n \\\\item \\\\textbf{删除} 点击该选项会在无警告的情况下直接移除配置文件。\\n\\n \\\\item \\\\textbf{复制} 该选项用于复制配置文件。\\n 点击时会显示一个对话框，在对话框内可为新的配置文件命名。\\n 单击“OK”后，会复制当前配置文件的所有配置信息并加载到\\n 新的 \\\\hyperref[sec:profile-page]{配置文件页面} 。\\n 尽管如此，复制的配置文件在手动保存之前都不会被保存。\\n\\n \\\\item \\\\textbf{复制配置文件ID} 该选项用于复制配置文件的唯一配置ID。\\n 该配置ID可用于\\n从第三方应用程序 \\\\hyperref[subsec:triggering-a-profile]{触发配置文件} 。\\n\\n \\\\item \\\\textbf{导出} 导出配置文件到外部存储。\\n 通过该方式导出的配置文件可以通过之前提到的 \\\\textit{导入} 选项导入。\\n\\n \\\\item \\\\textbf{创建快捷方式} 该选项用于\\n 创建该配置文件的快捷方式。\\n 该功能提供两个选项： \\\\textit{简单} 和 \\\\textit{高级} 。\\n 选择 \\\\textit{高级} 时，会提示用户选择快捷方式被调用时的配置文件状态。\\n 选择 \\\\textit{简单} 时，则总是使用配置文件上一次保存时设置的默认状态。\\n\\\\end{itemize}</string>\n    <string name=\"pages$profile-page$apps-tab\">应用标签页会列出所有为该配置文件配置的包。\\n包可以通过位于屏幕底部附近的 \\\\textit{添加} 按钮添加或移除。\\n一个包可以通过长按该按钮的方式移除 (以防万一，会弹出一个仅显示 \\\\textit{删除} 选项的对话框)。</string>\n    <string name=\"pages$profile-page$state\">表示默认情况下某些配置文件选项的行为方式。\\n例如，若 \\\\textit{禁用} 选项被打开，则状态为 \\\\textit{开} 的应用程序会被禁用，状态为 \\\\textit{关} 的会被启用。\\n目前此项仅支持取值 \\\\textit{开} 和 \\\\textit{关} 。</string>\n    <string name=\"pages$profile-page$app-ops\">该行为与位于一键操作页面中的 \\\\hyperref[subsec:set-mode-for-app-ops-dots]{设置 App Ops(应用操作) 模式\\\\dots} 选项的行为相同。\\n然而，此处的操作仅对选中的包生效。\\n若 \\\\hyperref[subsubsec:profile-state]{状态} 为 \\\\textit{开}，则应用操作(App Ops)会被拒绝 (即忽略)。\\n若其状态为 \\\\textit{关}，则应用操作(App Ops)会被允许。\\n该选项可通过单击输入对话框中的 \\\\textit{禁用} 按钮禁用 (无论被插入何值)。</string>\n    <string name=\"pages$profile-page$components\">该行为与位于一键操作页面中的 \\\\hyperref[subsec:block-components-dots]{阻止组件\\\\dots} 选项的行为相同。\\n然而，此处的阻止操作仅对选中的包生效。\\n若 \\\\hyperref[subsubsec:profile-state]{状态} 为 \\\\textit{开}，则组件会被阻止。\\n若其状态为 \\\\textit{关}，则组件会被解除阻止。\\n该选项可通过单击输入对话框中的 \\\\textit{禁用} 按钮禁用 (无论被插入何值)。\\n\\n\\\\seealsoinline{\\\\hyperref[subsec:faq:what-are-app-components]{什么是应用组件？}}</string>\n    <string name=\"pages$profile-page$permissions\">该选项用于对被选中的包授予或撤销某些权限。与其他选项类似，权限必须用空格隔开。\\n若 \\\\hyperref[subsubsec:profile-state]{状态} 为 \\\\textit{开}，则权限会被撤销。\\n若其状态为 \\\\textit{关}，则权限会被允许。\\n该选项可通过单击输入对话框中的 \\\\textit{禁用} 按钮禁用 (无论被插入何值)。</string>\n    <string name=\"pages$profile-page$backup-restore\">该选项用于对被选中的应用程序和其数据进行备份或还原。\\n提供两个选项： \\\\textit{备份选项} 和 \\\\textit{备份名称} 。\\n\\\\begin{itemize}\\n \\\\item \\\\textbf{备份选项} 与备份/还原功能中的 \\\\hyperref[subsec:backup-restore-backup-options]{备份选项} 相同。\\n 若没有设置，则使用默认选项。\\n \\\\item \\\\textbf{备份名称} 为备份设置自定义名称。若已经设置了备份名称，则每次备份都会沿用该名称。\\n 每个备份名称后都会被赋予唯一的名称作为后缀。该行为将在未来的正式版被修复。\\n 对于通常的“基本”备份，此区域会留空\\n (也请确保不要在备份选项中开启 \\\\textit{多个备份} )。\\n\\\\end{itemize}\\n\\n若 \\\\hyperref[subsubsec:profile-state]{状态} 为 \\\\textit{开}，则包会被备份。\\n若其状态为 \\\\textit{关}，则包会被还原。\\n该选项可通过单击输入对话框中的 \\\\textit{禁用} 按钮禁用 (无论被插入何值)。</string>\n    <string name=\"pages$settings-page$$pure-black-theme-title\">纯黑色主题</string>\n    <string name=\"pages$settings-page$$layout-direction-title\">布局方向</string>\n    <string name=\"pages$settings-page$$privacy-settings-title\">隐私</string>\n    <string name=\"pages$settings-page$$run-am-in-background-title\">在后台运行 App Manager</string>\n    <string name=\"pages$settings-page$$use-the-internet-title\">使用网络</string>\n    <string name=\"pages$settings-page$$auth-manager-title\">授权管理器</string>\n    <string name=\"pages$settings-page$$align-apk-files-title\">对齐 APK 文件</string>\n    <string name=\"pages$settings-page$$display-changes-title\">显示变化</string>\n    <string name=\"pages$settings-page$$immediately-perform-dex-opt-title\">立即执行DEX优化</string>\n    <string name=\"pages$settings-page$$import-backups-title\">导入备份</string>\n    <string name=\"pages$settings-page$$advanced-settings-title\">高级</string>\n    <string name=\"pages$settings-page$pure-black-theme\">使用纯黑色的背景，而不是Material 主题背景。</string>\n    <string name=\"pages$settings-page$layout-direction\">更改布局方向，从左到右或者从右到左。\\n通常情况下由选择的语言决定，但不是每个人都有相同的方向习惯。</string>\n    <string name=\"pages$settings-page$screen-lock\">当设置了屏幕锁定时，使用 Android 屏幕锁定的设置锁定 App Manager。\\n\\n\\\\begin{warning}{警告}\\n 若启用该设置后，屏幕锁定在 Android 中被禁用/移除，则直到再度启用屏幕锁定前 App Manager 将无法被打开。\\n\\\\end{warning}</string>\n    <string name=\"pages$settings-page$use-the-internet\">在 App Manager 中激活网络功能。\\n目前包括在 \\\\hyperref[sec:scanner-page]{扫描器页面}中进行扫描的 VirusTotal 和 Pithus。</string>\n    <string name=\"pages$settings-page$auth-manager\">该设置允许第三方应用程序获得某些功能的访问权限，比如说配置文件。</string>\n    <string name=\"pages$settings-page$installer-subtitle\">配置安装器的默认行为。在应用程序安装时，\\n你也可以通过点击 \\\\textit{齿轮} 图标并找到绝大多数设置。</string>\n    <string name=\"pages$settings-page$immediately-perform-dex-op\">在安装应用程序后立即执行DEX优化。\\n对于大型应用程序（比如说游戏类应用程序）而言，这很有用。</string>\n    <string name=\"pages$settings-page$install-in-the-background\">总是在后台安装应用程序。当安装完成时，会发出一条通知。</string>\n    <string name=\"pages$settings-page$backup-volume\">选择存放备份的存储路径。这也将存放日志以及导出的 APK 文件。\\n\\n\\\\begin{tip}{注意}\\n 备份卷仅可指定存储空间而不是路径。一般情况下备份会被存放在位于存储路径内部的 \\\\texttt{AppManager} 文件夹内。\\n 但当通过存储访问框架 (Storage Access Framework，即 SAF ) 选择路径时，会直接选择路径或目录。\\n\\\\end{tip}</string>\n    <string name=\"pages$settings-page$import-backups\">从旧版本和已停止更新的项目（比如说钛备份、OAndBackup 和 Swift Backup (从3.0到3.2的版本) 中导入备份。\\n备份在导入后不会被删除，以防止在无法正确还原导入的备份时丢失数据。</string>\n    <string name=\"pages$profile-page$block-trackers\">根据 \\\\hyperref[subsubsec:profile-state]{状态} 的值对选中的包的跟踪器组件启用阻止或解除阻止。\\n若状态为 \\\\textit{开} ，则跟踪器会被阻止；若状态为 \\\\textit{关} ，则跟踪器会被解除阻止。</string>\n    <string name=\"pages$profile-page$save-apk\">对在 \\\\texttt{AppManager/apks} (或在设置页面中被选中的目录) 中被选中的包启用导出 APK 文件。</string>\n    <string name=\"pages$settings-page$intro\">设置页面可被用于个性化 App Manager 的行为。</string>\n    <string name=\"pages$profile-page$clear-cache\">为被选中的包启用清除缓存。</string>\n    <string name=\"pages$settings-page$$selected-users-title\">选中的用户</string>\n    <string name=\"pages$profile-page$clear-data\">为选中的包启用清除数据。</string>\n    <string name=\"pages$settings-page$$block-trackers-title\">阻止跟踪器</string>\n    <string name=\"pages$settings-page$signature-schemes\">配置\\\\href{https://source.android.com/security/apksigning}{签名方案} 以用于启用 APK 签名的情况。\\n默认启用 v1 和 v2 签名方案，但应该也启用 v3 以确保在 Android 9 及更高版本的安全性。</string>\n    <string name=\"pages$settings-page$block-trackers\">在安装应用程序后立刻阻止跟踪器组件。</string>\n    <string name=\"pages$settings-page$display-changes\">在安装应用程序前，若该应用程序已经被安装，\\n则会在版本控制样式中显示版本、跟踪器、组件、权限、签名、SDK等信息的变更。</string>\n    <string name=\"pages$settings-page$compression-method\">设置在备份时使用的压缩方式。\\nApp Manager 支持 GZip、BZip2 和 Zstandard 压缩方式，且默认的压缩方式为 GZip。\\n这不会影响到已有备份的还原。</string>\n    <string name=\"pages$profile-page$force-stop\">允许被选中的包被强行停止。</string>\n    <string name=\"pages$settings-page$signing-key\">为签名 APK 文件配置签名密钥。\\n已存在密钥库中的密钥可以被导入到 App Manager，或者可以生成新的密钥。\\n\\n\\\\begin{tip}{提示}\\n 如果你需要在将来使用密钥，推荐你自行创建密钥库并在此处导入密钥。\\n 在没有正确备份的情况下，在 App Manager 生成的密钥有被删除的风险。\\n\\\\end{tip}</string>\n    <string name=\"pages$settings-page$$appearance-title\">外观</string>\n    <string name=\"pages$settings-page$$install-in-the-background-title\">后台安装</string>\n    <string name=\"pages$settings-page$$saved-apk-name-format-title\">保存的 APK 名称格式</string>\n    <string name=\"pages$settings-page$run-am-in-background\">App Manager 在后台运行时会减少初始化延迟。\\n对缓解某些设备频繁断开 ADB\\\\@ 连接的问题而言，这也很有用。</string>\n    <string name=\"pages$settings-page$mode-of-operation\">操作模式定义了 App Manager 整体的工作模式，其有以下选项：\\n\\\\begin{itemize}\\n \\\\item \\\\textbf{自动} 让 App Manager 决定最佳选项。\\n 尽管这是默认选项，对于无 Root 用户而言应该使用 \\\\textit{无 Root} 模式。\\n\\n \\\\item \\\\textbf{Root} 以 Root 模式运行 App Manager。若未检测到 Root 权限，App Manager 会回退至 \\\\textit{无 Root} 模式。在极少数个例中，当通过 Root 发起的 Binder 通信被禁用时\\n (例如 \\\\href{https://github.com/MuntashirAkon/AppManager/issues/606}{Phh SuperUser})，App Manager 也会回退至 \\\\textit{无 Root} 模式。\\n\\n \\\\item \\\\textbf{TCP 启动 ADB} 通过 \\\\hyperref[sec:adb-over-tcp]{TCP 启动 ADB} 的方式，在 ADB 模式下运行 App Manager。\\n 若未通过 TCP 启动 ADB ，App Manager 会回退至 \\\\textit{无 Root} 模式。\\n\\n \\\\item \\\\textbf{无线调试} 通过无线调试启用 ADB 。首先会自动尝试连接之前配置的端口，\\n 如失败会提示用户手动配对，或者手动连接到 ADB daemon。\\n 若通过该方式无法成功连接到 ADB daemon，App Manager会回退至 \\\\textit{无 Root} 模式。\\n \\\\begin{tip}{信息}\\n 由于无线调试在 Android 11 才被引入，该选项仅在运行 Android 11 及更高版本的设备上显示。\\n \\\\end{tip}\\n\\n \\\\item \\\\textbf{无 Root} 以无 Root 模式运行 App Manager。虽然 App Manager 在此模式中表现更佳，\\n 但所有 Root 或 ADB 相关的功能会被禁用。\\n\\\\end{itemize}\\n\\n也会在顶部显示实际操作模式。\\n实际操作模式是指 \\\\textit{Root}、\\\\textit{ADB} 和 \\\\textit{无 Root} 。\\n\\n\\\\begin{tip}{注意}\\n只有两种情况 \\\"远程服务“才是必需的。一是 ADB 用户，二是使用自定义命令。\\n\\\\end{tip}</string>\n    <string name=\"pages$settings-page$backup-options\">自定义备份时 \\\\textit{备份/还原对话框} 的显示。\\n\\n\\\\seealsoinline{\\\\hyperref[subsec:backup-restore-backup-options]{备份选项}}</string>\n    <string name=\"pages$settings-page$backup-apps-with-keystore\">允许备份在 Android 密钥库中有条目的应用程序。\\n由于一些应用 (比如说 Signal 和 Element ) 在还原后会崩溃闪退，该选项会默认显示。</string>\n    <string name=\"pages$settings-page$align-apk-files\">在 App Manager 对一个 APK 文件签名时执行 ZIP 对齐。 ZIP对齐在 APK 文件 (实际也是一种 ZIP 文件) 中\\nZIP 文件浏览器可通过随机访问非常轻易地访问文件而不是将整个 APK 文件加载到内存，\\n进而导致 Android 可用内存的减少。\\n记住一点：该步骤需要该应用程序的清单 (manifest) 中\\n存在 \\\\texttt{解压本地库 (extractNativeLibs)} 并被设定为 \\\\texttt{真 (true)}。</string>\n    <string name=\"pages$settings-page$encryption\">为备份设置加密方式。App Manager 当前支持 OpenPGP\\n(源自 \\\\href{https://f-droid.org/packages/org.sufficientlysecure.keychain/}{OpenKeyChain} )、\\nAES、RSA和ECC\\\\@ 。与 \\\\hyperref[subsec:apk-signing]{APK 签名}类似，AES、RSA和ECC密钥被存储在\\n密钥库中，可从其它密钥库中导入。\\n\\n\\\\begin{danger}{危险}\\n 为了确保自身安全，推荐在 App Manager 内部生成 RSA 和 ECC 密钥。\\n 或者应该从存储在安全地方的密钥库中导入。\\\\\\\\\\n 在 AES 的情况下，生成的密钥应存储在安全的地方，例如密码管理器中。\\n\\\\end{danger}</string>\n    <string name=\"pages$interceptor-page$reset-to-default\">重置意图至其初始化状态。</string>\n    <string name=\"guide$aot$$oneplus-usb-debug-title\">一加 (Oxygen OS)</string>\n    <string name=\"guide$aot$miui-usb-debug\">同时启用 \\\\textbf{USB 调试 (安全设置)} 。</string>\n    <string name=\"pages$settings-page$selected-users\">该选项允许你控制 App Manager 应作用的用户。默认情况下，在 Root 模式或 ADB 模式下 App Manager 对所有用户起作用。</string>\n    <string name=\"pages$settings-page$device-info\">显示 Android 版本、安全、CPU、GPU、电池、内存、屏幕、语言、用户信息等。</string>\n    <string name=\"guide$aot$$realme-usb-debug-title\">真我 (Realme)</string>\n    <string name=\"pages$settings-page$instant-component-blocking\">默认情况下，阻止规则不会生效，直到它们在任意应用程序的 \\\\hyperref[sec:app-details-page]{应用详情页} 中被显式应用。\\n在启用该选项后，所有应用程序的所有规则 (无论新旧) 即刻生效，无需显式启用应用程序的阻止。\\n\\n\\\\seealsoinline{\\\\hyperref[subsec:faq:what-is-instant-component-blocking]{FAQ: 什么是即时阻止组件？}}</string>\n    <string name=\"pages$settings-page$import-export-blocking-rules\">可以在 App Manager 内为所有应用程序导入或导出阻止规则。可选择应被导入或导出的规则类型 (组件、应用操作或权限)。\\n也可从 \\\\href{https://github.com/lihenggui/blocker}{Blocker} 和 \\\\href{https://github.com/tuyafeng/Watt}{Watt} 导入阻止规则。\\n若要为单个应用程序导出阻止规则，则可使用相应的 \\\\hyperref[sec:app-details-page]{应用详情页} 导出规则。若要为多个应用程序导出规则，则可使用 \\\\hyperref[subsec:batch-operations]{批处理操作} 。\\n\\n\\\\seealsoinline{\\\\hyperref[sec:rules-specification]{规则说明}}\\n\\n\\\\paragraph{导出} 为所有应用程序导出在 App Manager 配置的阻止规则。\\n可包含 \\\\hyperref[subsec:faq:what-are-app-components]{应用组件} 、应用操作 (App Ops) 和权限，基于多选操作中选择的选项导出规则。\\n\\n\\\\paragraph{导入} 导入之前从 App Manager 导出的阻止规则。\\n类似于导出，可包含 \\\\hyperref[subsec:faq:what-are-app-components]{应用组件}、应用操作 (App Ops) 和权限，基于多选操作中选择的选项导入规则。\\n\\n\\\\paragraph{导入已有规则}\\\\label{par:import-existing-rules}\\n\\\\phantomsection\\n将被其他应用程序阻止的组件添加到 App Manager 中。App Manager 仅跟踪被 App Manager 禁用的组件。\\n若应用程序的组件时被其他工具或应用程序阻止，则该选项可被用于导入它们。\\n点击该选项， App Manager 会查找潜在的被其他应用程序或工具阻止的组件，并仅列出应用程序的名称以及匹配的组件数量。\\n安全起见，所有的应用程序默认情况下不会被选中。它们需要被手动选择，并在 App Manager 中重新应用阻止规则。\\n\\n\\\\begin{danger}{小心}\\n 谨慎使用可能存在错误结果的工具。\\n 仅选择你十分确信的应用程序。\\n\\\\end{danger}\\n\\n\\\\paragraph{从 Watt 中导入} 从 \\\\href{https://github.com/tuyafeng/Watt}{Watt} 中导入配置文件，\\n每个文件包含单个包的规则，文件名为包的名称跟着 \\\\texttt{.xml} 的扩展名。\\n\\n\\\\begin{tip}{提示}\\n Watt 的配置文件存放位置为： \\\\texttt{/sdcard/Android/data/com.tuyafeng.watt/files/ifw}\\n\\\\end{tip}\\n\\n\\\\paragraph{从 Blocker 中导入} 从 \\\\href{https://github.com/lihenggui/blocker}{Blocker} 中导入阻止规则，每个文件包含单个包的规则。\\n这些文件的扩展名为 \\\\texttt{.json} 。</string>\n    <string name=\"pages$settings-page$remove-all-rules\">点击选项以移除App Manager 内配置的所有规则。\\n这将启用所有已被阻止的组件，应用操作会被设置为默认值以及权限会被授予。</string>\n    <string name=\"pages$settings-page$saved-apk-name-format\">定义用于批处理操作或通过配置文件导出的 APK 格式的文件名。\\nApp Manager 提供一些特殊的关键词，这些关键词包含在 \\\\texttt{\\\\%} (百分号) 符号内，并在输入框下方可用。\\n这些关键词为：\\n\\\\begin{itemize}\\n \\\\item \\\\textbf{\\\\texttt{标签}。} 表示该应用程序的名称或标签。可根据该应用程序设置的语言进行本地化。\\n \\\\item \\\\textbf{\\\\texttt{包名}。} 表示包名称或该应用程序ID，是每个应用程序拥有的唯一标识符。\\n \\\\item \\\\textbf{\\\\texttt{版本}。} 表示从该应用程序清单里提取出的当前版本。\\n \\\\item \\\\textbf{\\\\texttt{版本代号}。} 表示该应用程序的当前版本代号，可用于区分同一个应用程序的两个版本。\\n \\\\item \\\\textbf{\\\\texttt{最小SDK}。} 表示该应用程序可运行的最小的SDK (即 Android 框架版本)。该数据仅在 Android 7 (Nougat) 及更高版本可用。\\n \\\\item \\\\textbf{\\\\texttt{目标SDK}。} 表示该应用程序的目标SDK。该应用程序可在更高的 SDK 版本以兼容模式运行。\\n \\\\item \\\\textbf{\\\\texttt{日期时间}。} 表示 APK 导出的时间和日期。\\n\\\\end{itemize}</string>\n    <string name=\"pages$settings-page$import-export-keystore\">导入或导出用于 App Manager 的密钥库。该密钥库是 Bouncy Castle KeyStore 并以 \\\\texttt{bks} 作为扩展名。\\n因此不支持其他诸如 Java KeyStore (JKS) 或 PKCS \\\\#12 的密钥库。\\n若要从这类密钥库中导入密钥，则应使用如上所述的相关选项。</string>\n    <string name=\"pages$interceptor-page$mime-type\">\\\\hyperref[subsubsec:data]{数据} 的 MIME类型。 举个例子，若数据字段被设定为 \\\\texttt{file:///sdcard/AppManager.apk}，\\n则相关联的MIME类型为 \\\\texttt{application/vnd.android.package-archive}。</string>\n    <string name=\"guide$aot$emui-usb-debug\">也启用 \\\\textbf{允许在仅充电模式下进行 ADB 调试} 。\\n当连接到你的 PC 或 Mac 设备时，你可能会看到 \\\\textbf{是否允许访问设备数据？} 的提示。\\n无论哪种情况，请点击 \\\\textbf{是，允许访问}。\\n\\n\\\\begin{tip}{注意}\\n \\\\textbf{USB 调试} 模式经常会被系统自动禁止。遇到此情况时，请重复上述步骤。\\n\\\\end{tip}</string>\n    <string name=\"pages$interceptor-page$categories\">类别 (Category) 与 \\\\hyperref[subsubsec:action]{动作 (Action)} 类似。某种意义上来说，它也被系统用于过滤应用程序组件。\\n它并没有更多优势。不同于 \\\\textit{动作 (Action)}，可以拥有多个类别。点击标题旁边的 \\\\textit{添加} 按钮以允许添加更多类别。</string>\n    <string name=\"pages$interceptor-page$uri\">将整个意图表示为 URI (例如 \\\\texttt{intent://\\\\dots})。\\n一些数据无法被转换为字符串，结果可能无法在此显示。</string>\n    <string name=\"pages$interceptor-page$flags\">标志 (Flags) 有助于确定活动 (Activity) 启动期间或活动 (Activity) 启动后的系统行为。\\n因为它需要一些技术背景，不应该被随意触及。标题旁边的 \\\\textit{添加} 按钮可用于添加一或多个标志 (Flags)。</string>\n    <string name=\"pages$interceptor-page$extras\">额外数据 (Extras) 是用于向目标组件提供附加信息的键值对。可以使用标题旁边的 \\\\textit{添加} 按钮添加更多额外数据 (Extras)。</string>\n    <string name=\"pages$scanner-page$intro\">在 \\\\hyperref[subsec:app-info-tab]{应用详情页} 中点击 \\\\emph{扫描器} 按钮后，会出现 \\\\textbf{扫描器页面} 。\\n外部 APK 文件也可从文件管理器、网页浏览器等用 App Manager 的扫描器打开以扫描 APK 文件。\\n\\n扫描器会扫描跟踪器和库，显示跟踪器和库的总数。\\n它也会显示 APK 文件的检验和并进行签名验证。\\n若设置里配置了 VirusTotal ，则也可尝试从 VirusTotal 中检索报告，\\n若该 APK 文件不在数据库时，则可以选择上传该 APK 文件。\\n当启用网络功能时，还会显示前往 \\\\href{https://beta.pithus.org}{Pithus}的链接，并提供报告功能。\\n\\n\\\\begin{danger}{免责声明}\\n App Manager 仅静态扫描应用程序，并不带任何偏见。应用程序可能会提供退出跟踪的选项。\\n 在某些情况下，某些跟踪器的功能并不会被应用程序使用 (比如 F-Droid)。\\n 某些应用程序可能只是单纯将它们当作占位符使用，\\n 以防止某些功能被破坏 (比如Fennec F-Droid)。\\n \\\\textbf{扫描器的目的是让你知道该 APK 可能包含的内容。\\n 应该把扫描结果当作进一步调查之前的第一步。}\\n\\\\end{danger}\\n\\n点击第一项 (即类的数量) 以打开一个新页面，该页面包含该应用程序的跟踪器类的列表。\\n所有类可以通过点击 \\\\textit{切换类列表} 目录查阅。\\n只需点击其中任意一项即可查看该类的 SMALI 或 Java 版本。\\n\\n\\\\begin{tip}{注意}\\n 由于诸多限制，不可能扫描一个 APK 文件里的所有组件。\\n 若一个 APK 文件被高度混淆或包装则更是如此。\\n 扫描器也不会检查字符串 (或网站签名)。\\n\\\\end{tip}\\n\\n第二项列出了跟踪器数量以及它们的名称。\\n点击其中一项以显示包含跟踪器名称、匹配签名和每个签名对应的类的数量的对话框。\\n某些跟踪器名称可能包含 $^2$ 前缀，\\n表示这些跟踪器在 \\\\href{https://etip.exodus-privacy.eu.org}{ETIP} 备选列表内，\\n即它们是否确实是跟踪器还在调查中。\\n\\n第三项列出了库的数量以及它们的名称。\\n这些信息大多叔来自 \\\\href{https://gitlab.com/IzzyOnDroid/repo}{IzzyOnDroid repo}。\\n\\n\\\\seealsoinline{\\\\hyperref[subsec:tracker-classes-versus-tracker-components]{FAQ: 跟踪器类与跟踪器组件}}</string>\n    <string name=\"pages$scanner-page$missing-signatures\">%在页面底部有一个特殊的项目，表明缺少签名的数量 (即缺少的类) 。\\n%缺少的签名是那些 App Manager 无法将其与任何已知的库相匹配的签名。\\n%由于许多库包含数百个类，数量本身并不具备特别的意义，因为许多库包含数百个类\\n%但单击项目会弹出包含签名的对话框，有助于检查缺失的签名。\\n%\\\\textbf{该功能仅为那些知道缺少签名的含义以及该怎么办的人而备，\\n%其他用户应该忽略此项。}</string>\n    <string name=\"pages$interceptor-page$intro\">拦截器可被用于拦截应用间通过 \\\\texttt{意图 (Intent) } 进行的通信。\\n作为源应用程序与目标应用程序之间的中间人工作。\\n并提供编辑 \\\\texttt{意图} 的界面给功能完整的用户。\\n\\n\\\\begin{warning}{警告}\\n 拦截器仅作用于未被指定 \\\\hyperref[subsec:faq:what-are-app-components]{应用组件} 的 \\\\textit{隐式} 意图。\\n\\\\end{warning}\\n\\n\\\\begin{amseealso}\\n \\\\item \\\\href{https://developer.android.com/guide/components/intents-common}{常见 Intent}\\n \\\\item \\\\href{https://developer.android.com/guide/components/intents-filters}{Intent 与 Intent 过滤器}\\n\\\\end{amseealso}</string>\n    <string name=\"pages$interceptor-page$intent-filters\">应用程序使用意图过滤器来指定它们能够执行的任务或者它们将使用其他应用程序执行的任务。\\n举个例子，当你使用文件管理器打开一个 PDF 文件时，文件管理器会尝试寻找能够打开 PDF 的应用程序。\\n为了找到正确的应用程序，文件管理器会创建一个带有MIME类型等过滤器的意图 (Intent)，并要求系统检索能够打开该过滤器的应用程序。\\n系统会通过检索已安装应用程序的清单 (Manifest)匹配过滤器，并列出能够打开该过滤器 (该例子中是PDF)的应用程序组件。\\n此时，文件管理器将自行打开所需的应用程序组件或者使用系统提供的选项打开它。\\n若多个应用程序组件能打开它并且没有设置默认的打开方式，则你可能会看到一个选择正确的应用程序组件打开的提示。</string>\n    <string name=\"pages$interceptor-page$action\">动作 (Action) 指定要执行的通用动作，例如 \\\\texttt{android.intent.action.VIEW}。\\n应用程序通常在清单文件中声明相关的动作以抓取所需的意图。\\n该动作对广播意图非常有用，起到了至关重要的作用。在其他情况下，其作为过滤相关应用程序组件的初始方法。\\n诸如 \\\\texttt{android.intent.action.VIEW} 和 \\\\texttt{android.intent.action.SEND} 的通用动作被应用程序广泛使用。\\n因此，单独设置它可能会匹配到很多应用程序组件。</string>\n    <string name=\"pages$interceptor-page$data\">数据最初被称为 URI(Uniform Resource Identifier，统一资源标识符)，在 \\\\href{http://www.faqs.org/rfcs/rfc2396.html}{RFC 2396} 中被定义。\\n它可以是网络链接、文件位置，或者名为 \\\\textit{内容 (content)} 的特殊功能。内容是由 \\\\hyperref[subsubsec:providers]{内容提供者} 管理的一个 Android 功能。\\n数据经常被一种 \\\\hyperref[subsubsec:mime-type]{MIME 类型} 关联。\\n\\n例如：</string>\n    <string name=\"pages$interceptor-page$matching-activities\">列出匹配意图的所有活动组件。这是由系统内部决定的 (而不是 App Manager) 。\\n每个组件旁边的启动按钮可用于从 App Manager 直接启动它们。</string>\n    <string name=\"pages$interceptor-page$send-edited-intent\">将编辑过的意图重新发送到目标应用程序。这可能会打开需要选择所需应用程序的应用程序列表。\\n从目标应用程序接收的结果会被发送到源应用程序。因此，源应用程序将不会知道是否存在中间人。</string>\n    <string name=\"guide$aot$oneplus-usb-debug\">基于设备和操作系统版本，你需要启用 \\\\textbf{禁用权限监视}。</string>\n    <string name=\"guide$aot$enable-aot-via-pc\">对于其他ROM，你可以通过在前面章节中的步骤3打开的命令提示符/PowerShell/终端模拟器进行操作。\\n在此节中，我将使用 \\\\texttt{adb} 表示 \\\\texttt{./adb}，\\n\\\\texttt{adb} 或其他你需要使用的任何命令基于前面的章节中你使用的平台和软件。\\n\\\\begin{enumerate}\\n \\\\item 使用数据线连接你的设备到你的 PC 或 Mac。For some devices, it is necessary to turn on\\n 对某些设备而言，有必要同时启用 \\\\textit{文件传输模式 (MTP)}。\\n \\\\item 确认一切都按预期运行，在你的终端输入 \\\\texttt{adb devices} 。\\n 若你的设备已成功连接，则你会看到像这样的内容：\\n \\\\begin{Verbatim}\\nList of devices attached\\nxxxxxxxx device\\n \\\\end{Verbatim}\\n \\\\begin{tip}{注意}\\n 在某些 Android 手机中，会出现这样的提示信息：\\\\textbf{允许 USB 调试吗？}\\n 无论什么情况，勾选 \\\\textit{始终允许此计算机进行调试} 然后点击 \\\\textbf{允许}。\\n \\\\end{tip}\\n \\\\item 最终，运行下面的命令以启用通过 TCP 启用 ADB 功能。:\\n \\\\begin{minted}[frame=lines,autogobble]{bash}\\nadb tcpip 5555\\n \\\\end{minted}\\n\\\\end{enumerate}\\n\\n\\\\begin{danger}{危险}\\n 在启用通过 TCP 启用 ADB 功能后，你不能禁用开发者选项或者 USB 调试。\\n\\\\end{danger}</string>\n    <string name=\"guide$aot$adb-mode-am\">在启用通过 TCP 启动 ADB后，重新启动 App Manager。App Manager 应该会自动检测到 ADB 模式。\\n若不能，你可以在 \\\\hyperref[subsec:mode-of-operation]{设置页面} 更换操作模式为通过 TCP 启动 ADB 模式。\\n你也可以在此处验证 App Manager 是否与 \\\\textit{推断模式} 显示的一样正确检测到 ADB。\\n\\n\\\\begin{tip}{注意}\\n 在某些 Android 设备中，在连接到 App Manager 前，可能需要将 USB 数据线从 PC 断开。\\n\\\\end{tip}\\n\\n\\\\begin{warning}{警告}\\n 通过 TCP 启动 ADB 在重启时会被禁用。对于这种情况，你需要按照 \\\\Sref{subsubsec:enable-adb-over-tcp-via-pc-or-mac}{在 PC 或 Mac 上启用通过 TCP 启动 ADB 模式} 的步骤再度操作。\\n\\\\end{warning}</string>\n    <string name=\"guide$wireless_debugging$$enable-developer-options-and-usb-debugging-title\">启用开发者选项和 USB 调试</string>\n    <string name=\"guide$wireless_debugging$$enable-wireless-debugging-title\">启用无线调试</string>\n    <string name=\"guide$wireless_debugging$$pair-adb-with-appmanager-title\">用 App Manager 匹配 ADB</string>\n    <string name=\"guide$wireless_debugging$$connect-am-to-adb-title\">连接 App Manager 到 ADB</string>\n    <string name=\"guide$aot$lg-usb-debug\">确认你已启用 \\\\textbf{USB 网络共享}。</string>\n    <string name=\"guide$aot$realme-usb-debug\">基于设备和操作系统版本，你需要启用 \\\\textbf{禁用权限监视}\\n或 \\\\textbf{USB 调试 (安全设置)} 以及 \\\\textbf{从 USB 安装} 选项。</string>\n    <string name=\"guide$aot$setup-adb-on-pc\">为了使用通过 TCP 启动 ADB 功能，你需要在你的 PC 或 Mac 设备上安装并设置 ADB。\\n\\\\textbf{\\\\textit{Lineage OS 用户可参考 \\\\Sref{subsubsec:lineage-os}。}}</string>\n    <string name=\"guide$wireless_debugging$$section-title\">无线调试</string>\n    <string name=\"guide$wireless_debugging$enable-developer-options-and-usb-debugging\">参阅 \\\\Sref{subsec:enable-developer-options}{启用开发者选项} 和 \\\\Sref{subsec:enable-usb-debugging}{启用 USB 调试}。</string>\n    <string name=\"guide$backup-restore$options\">你可以通过备份选项 (内部称为备份标志) 自定义云端备份。\\n然而，在将来的备份中不会记得这些自定义设置。\\n如果你想定制此对话框，在 \\\\hyperref[sec:settings-page]{设置页面} 中使用 \\\\hyperref[subsubsec:settings-backup-options]{备份选项}。 \\n\\n下面给出了备份选项的完整描述：\\n\\\\begin{itemize}\\n \\\\item \\\\textbf{APK 文件} 是否备份 APK 文件。\\n 这包括 \\\\textit{Base APK} 文件以及 \\\\texttt{APK 分包} 文件 (如果有)。\\n\\n \\\\item \\\\textbf{内部数据} 是否备份内部数据目录。\\n 这些目录位于 \\\\texttt{/data/user/&lt;用户ID&gt;} 以及 (对 Android 7 及更高版本) \\\\texttt{/data/user\\\\_de/&lt;用户ID&gt;}.\\n\\n \\\\item \\\\textbf{外部数据} 是否备份位于内部存储和SD 卡 (如果有) 的数据目录。\\n 外部数据目录通常包括非必要的应用数据或媒体文件 (而不是使用专用的媒体文件夹)，若选择备份则可能增加备份文件的大小。\\n 然而，对一些应用来说可能是有必要的。\\n 尽管默认情况下不会选中该项 (因为它可能会显著增加备份文件的大小)，你可能需要检查此项以确保能够顺利还原你的备份。\\n \\\\begin{warning}{小心}\\n 若你要备份外部数据文件夹，则应该总是备份内部数据文件夹。\\n 然而，如果所讨论的应用会从网络下载大量资源，那么仅备份外部文件夹也会很有用。\\n \\\\end{warning}\\n\\n \\\\item \\\\textbf{OBB 和媒体} 是否备份或还原 OBB 和位于\\n 外部存储或 SD 卡的媒体。\\n 这对实际使用这些文件夹的游戏和图形软件而言很有用。\\n\\n \\\\item \\\\textbf{缓存} Android 应用在每个数据目录 (内部和外部) 中都有多个缓存目录。\\n 有两种类型的缓存： \\\\textbf{缓存 (Cache)} 和 \\\\textbf{代码缓存 (Code Cache)}。\\n 禁用此选项会将这两个缓存目录从所有数据目录中排除。\\n 一般情况下建议排除缓存目录，因为大多数应用程序并不会定期清除缓存，缓存通常是由操作系统自身处理。\\n 像 Telegram 之类的应用可能会使用非常大的缓存(由存储空间决定)，这显著增加了备份文件大小。\\n 当该项被禁用时，App Manager 也会忽略 \\\\textbf{no\\\\_backup} (无备份)目录。\\n\\n \\\\item \\\\textbf{额外信息} 备份/还原应用权限、网络规则、电池优化、SSAID，等等，默认启用。\\n 注意：阻止规则在还原应用的额外信息 \\\\textit{后} 应用。\\n 所以，如果某个条目在两个地方(阻止规则和额外信息备份)同时存在，那么它将会被覆盖。(即会使用源自阻止规则的条目)。\\n\\n \\\\item \\\\textbf{规则} 你可以通过该选项备份在 App Manager 内配置的阻止规则。\\n 若你通过 App Manager 配置了权限或阻止了一些组件，则当你启用该选项时，\\n 这些规则也会被备份或还原。\\n\\n \\\\item \\\\textbf{多重备份} 这是否为多重备份。\\n 默认情况下，备份使用其用户 ID 保存。\\n 启用该选项将允许你创建多个备份。\\n 这些备份使用当前的时间日期作为默认备份名称，但你也可以指定自定义备份名称。\\n 当你点击 \\\\textbf{备份} 按钮时，使用输入框以自定义备份名称。\\n\\n \\\\item \\\\textbf{自定义用户} 为所选的用户进行备份或还原，而不仅仅是当前用户。\\n 该选项仅在系统有多个用户的情况下显示。\\n\\n \\\\item \\\\textbf{跳过签名检查} 当进行备份时，会生成每个文件的检验和 (以及基础 APK 文件的签名证书)\\n 并保存在 \\\\texttt{checksums.txt} 文件中。\\n 当你还原备份时，会再度生成检验和，并用于匹配保存在先前提及的文件内的检验和。\\n 启用此选项以禁用签名检查。\\n 该选项仅在你恢复备份时被应用 (即启用该选项仅禁用恢复时的签名检查)。\\n 无论此处如何设置，备份时始终会生成用于签名检查的检验和。\\n \\\\begin{warning}{小心}\\n 你应该总是禁用此选项，以确保你的备份不被任何第三方应用程序修改。\\n 然而仅在你启用了加密才起作用。\\n \\\\end{warning}\\n\\\\end{itemize}\\n\\n\\\\seealsoinline{\\\\hyperref[subsubsec:settings-encryption]{设置：加密}}</string>\n    <string name=\"pages$shared-prefs-editor-page$intro\">可以在此页面中编辑共享首选项。点击列表中的任意一项以打开可编辑该项目的编辑对话框。\\n右下角的浮动操作按钮可用于添加新项目。\\n若要保存或删除文件，或放弃当前更改，可使用菜单中的相应选项。</string>\n    <string name=\"guide$aot$intro\">许多仅 Root 功能在通过 TCP 启动的 ADB 下依然可用。为此需要一台已安装 Android 平台工具的 PC 或者 Mac 设备，\\n以及一部启用开发者选项和 USB 调试的 Android 手机。\\n\\n\\\\begin{tip}{Root 用户}\\n 若 App Manager 已被授予超级用户权限，则已经能够毫无问题地执行特权代码。\\n \\\\textbf{因此，Root 用户无需启用通过 TCP 启用的 ADB。} 如果你仍想使用通过 TCP 启动的 ADB，\\n 你必须撤销对 App Manager 的超级用户权限的授予\\n\\\\end{tip}\\n\\n\\\\seealsoinline{\\\\hyperref[sec:faq:adb-over-tcp]{FAQ: 通过 TCP 启动的 ADB}}</string>\n    <string name=\"guide$aot$location-dev-options\">\\\\textbf{开发者选项} 位于 Android \\\\textbf{设置}，要么直接\\n靠近设置页底部 （多数ROMs），要么在其他一些设置下面，比如 \\\\textbf{系统} （Google Pixel、\\nLineage OS、 Asus Zenfone 8.0+）, \\\\textbf{附加设置} （Xiaomi MIUI、Oppo ColorOS），\\n\\\\textbf{更多设置} （Vivo FuntouchOS）, \\\\textbf{更多} （ZTE Nubia）。 不像其他设置，开发者选项\\n在用户明确启用前不可见。如果已经启用开发者选项，你也可以使用\\nAndroid \\\\textbf{设置} 中的搜索框来定位它。</string>\n    <string name=\"guide$aot$how-to-enable-dev-options\">该选项在 Android \\\\textbf{设置} 也可用，但是类似于开发者选项的位置，其位置也因设备而异。\\n但总体来说，你需要找到 \\\\textbf{Build number (内部版本号)} (或者 MIUI ROM的 \\\\textbf{MIUI 版本} 、\\nVivo FuntouchOS的 \\\\textbf{软件版本} 、OPPO ColorOS 的 \\\\textbf{版本} for ) 然后连续点击至少7次，\\n直到你最终看到一条写着 \\\\textit{你已经启用了开发者选项！}的消息。\\n（这一步你可能会看到需要输入PIN/密码/解锁图案或验证码的提示。）\\n对绝大多数设备而言，其位于设置页面底部的 \\\\textbf{关于手机} 内。不过找到它的最佳方法是使用搜索框。</string>\n    <string name=\"guide$aot$enable-usb-debug\">在 \\\\hyperref[subsubsec:location-of-developer-options]{定位开发者选项} 后，\\n启用 \\\\textbf{开发者选项} (如果尚未启用)。然后一点点往下划，\\n直到你看见 \\\\textbf{USB 调试} 选项。点击右侧的切换按钮启用它。\\n此时你可能会看见一个需要点击 \\\\textit{OK} 按钮才能实际启用 USB 调试的警示信息。\\n基于设备供应商和ROM，你可能还需要启用一些其他的选项。以下是一些例子：</string>\n    <string name=\"guide$aot$troubleshooting-usb-debug\">当 \\\\textbf{USB 调试} 为灰色时，你可以执行以下步骤：\\n\\\\begin{enumerate}\\n \\\\item 在通过 USB 数据线连接你的手机到 PC 或者 Mac 前，确认你已开启 USB 调试；\\n \\\\item 在通过 USB 数据线连接到 PC 或 Mac 后启用 USB 网络共享；\\n \\\\item (对三星设备而言) 若你的设备正在运行KNOX，你可能需要执行一些额外步骤。\\n 参考官方文档或咨询官方客服以获得更多支持。\\n\\\\end{enumerate}</string>\n    <string name=\"guide$aot$setup-adb-win\">\\\\begin{enumerate}\\n \\\\item 下载最新的\\n \\\\href{https://dl.google.com/android/repository/platform-tools-latest-windows.zip}{Android SDK 平台工具}\\n的 Windows 版本。\\n \\\\item 解压 ZIP 文件的内容到任意目录 (例如 \\\\texttt{C:\\\\textbackslash{adb}})，然后用 \\\\textit{文件资源管理器}\\n 导航到 (转到/打开) 该目录。\\n \\\\item 在此目录中打开 \\\\textbf{命令提示符}、 \\\\textbf{PowerShell} 或 \\\\textbf{终端}。\\n你可以手动从开始菜单打开，\\n 或者按住 \\\\texttt{Shift} 键，打开目录，在目录内用 \\\\textit{文件资源管理器} 右键单击，然后单击 \\\\textit{在此处打开命令窗口}\\n 或者 \\\\textit{在此处打开 PowerShell 窗口} (取决于你安装的软件)。\\n 现在你可以通过输入 \\\\texttt{adb} (在命令提示符中) 或者是 \\\\texttt{./adb} (在PowerShell中) 的方式访问 ADB。\\n 请不要关闭此窗口。\\n\\\\end{enumerate}\\n\\n \\\\begin{tip}{Tip}\\n 如果你已经安装了 \\\\href{https://learn.microsoft.com/en-us/windows/package-manager/winget/}{WinGet}\\n ，你可以使用以下命令安装 ADB：\\n \\\\begin{minted}[frame=lines]{bash}\\n winget install --id Google.PlatformTools\\n \\\\end{minted}\\n 完毕后，你只需输入 \\\\texttt{adb} 就可访问 ADB\\\\@。\\n \\\\end{tip}</string>\n    <string name=\"guide$aot$setup-adb-mac\">\\\\begin{enumerate}\\n \\\\item 下载最新版本的\\n \\\\href{https://dl.google.com/android/repository/platform-tools-latest-darwin.zip}{Android SDK 平台工具}\\n 的 macOS 版本。\\n \\\\item 点击它以解压 ZIP 文件的内容到目录。然后用 \\\\textit{Finder} 导航到该目录并定位 \\\\texttt{adb}。\\n \\\\item 使用 \\\\textit{Launchpad} 或 \\\\textit{Spotlight} 打开 \\\\textbf{终端}，\\n 然后将 \\\\texttt{adb} 从 \\\\textit{Finder} 窗口拖到 \\\\texttt{adb} 到 \\\\textit{终端} 窗口并松开。\\n 请不要关闭 \\\\textit{终端} 窗口。\\n\\\\end{enumerate}\\n\\n\\\\begin{tip}{Tip}\\n如果你已经安装了 \\\\href{https://brew.sh}{Homebrew}，你可以用下列命令安装\\nADB:\\n\\\\begin{minted}[frame=lines]{bash}\\nbrew install --cask android-platform-tools\\n\\\\end{minted}\\n完毕后，你只需在任意 \\\\textit{终端} 窗口中输入 \\\\texttt{adb} 即可访问 access ADB\\\\@。\\n\\\\end{tip}</string>\n    <string name=\"guide$aot$setup-adb-linux\">\\\\begin{enumerate}\\n \\\\item 在你喜欢的终端模拟器中，运行如下命令\\n \\\\begin{minted}[frame=lines,autogobble]{bash}\\ncd ~/Downloads &amp;&amp; curl -o platform-tools.zip -L \\\\\\nhttps://dl.google.com/android/repository/platform-tools-latest-linux.zip &amp;&amp; \\\\\\nunzip platform-tools.zip &amp;&amp; rm platform-tools.zip &amp;&amp; cd platform-tools\\n \\\\end{minted}\\n \\\\item 若成功，你只需在 \\\\textit{同一个} 终端模拟器窗口内输入 \\\\texttt{./adb} \\n 或者在任意的模拟器输入 \\\\texttt{\\\\textasciitilde/Downloads/platform-tools/adb} 就可以访问 ADB\\\\@。\\n\\\\end{enumerate}</string>\n    <string name=\"guide$aot$aot-lineage-os\">Lineage OS (或其衍生ROM) 用户可直接通过开发者选项启用通过 TCP 启动 ADB 功能。\\n若要启用，请前往 \\\\textbf{开发者选项}，下划，直到你找到 \\\\textbf{通过网络启动 ADB}。\\n现在，点击右侧的切换按钮以启用它并跳转至 \\\\Sref{subsubsec:adb-mode-in-app-manager}{在 App Manager 内的 ADB 模式}。\\n\\n\\\\begin{warning}{Warning}\\n你可以在开发者选项中关闭 \\\\textbf{ADB over Network}，但关闭该选项也会停止 App\\nManager 的服务器。因此，请只在你不打算在 ADB over TCP 模式下使用 App Manager 时关闭它。\\n\\\\end{warning}</string>\n    <string name=\"guide$wireless_debugging$intro\">若你的设备运行 Android 11 及更高版本，或稍后能够连接到 Wi-Fi 网络至少几分钟，\\n则推荐使用无线调试方法，因为比起 \\\\hyperref[sec:adb-over-tcp]{提供 TCP 启动 ADB} 它提供更多保护。\\n它需要两个步骤：\\n\\\\begin{enumerate}\\n \\\\item \\\\textbf{ADB 匹配} 对新手用户而言有一点复杂的初始步骤\\n幸运的是，该步骤并不总是每次都需要进行。\\n \\\\item \\\\textbf.{连接到 ADB} 每次你重启手机后都需要进行该操作。App Manager\\n 在多数设备上也可以自动完成此步骤。\\n\\\\end{enumerate}</string>\n    <string name=\"guide$backup-restore$delete\">删除备份仅遵守 \\\\textbf{所有用户} 选项。当被选中时，仅会提示后删除所有用户的基础备份。\\n当为单个应用删除备份时，会显示另外一个可供你选择要删除的备份的对话框。</string>\n    <string name=\"guide$automation$$general-configuration-title\">配置任务</string>\n    <string name=\"guide$automation$$required-extras-title\">需求的附加选项</string>\n    <string name=\"guide$automation$$features-title\">功能特性</string>\n    <string name=\"guide$automation$$triggering-a-profile-title\">触发配置文件</string>\n    <string name=\"guide$automation$intro\">可以通过诸如 \\\\textbf{Automation} 或 \\\\textbf{Tasker} 之类的第三方应用程序触发在 App Manager 设置的配置文件。\\n通常情况下用 \\\\texttt{意图} 触发这类操作。</string>\n    <string name=\"guide$automation$general-configuration\">活动 \\\\texttt{io.github.muntashirakon.AppManager.crypto.auth.AuthFeatureDemultiplexer} 负责处理所有的自动化意图。\\n发送意图到该活动，让 App Manager 通过重定向 \\\\texttt{意图} 到指定活动或服务的方式执行指定操作。</string>\n    <string name=\"guide$automation$required-extras\">所有条件都需要两种主要的附加功能：密钥名称和数据类型。如下所示：\\n\\\\begin{enumerate}\\n \\\\item \\\\textbf{\\\\texttt{auth}.} (字符串值) 前一节所述的授权密钥。\\n \\\\item \\\\textbf{\\\\texttt{feature}.} (字符串值) 功能名称。下一节将介绍受支持的功能。\\n\\\\end{enumerate}</string>\n    <string name=\"guide$net-policy$intro\">网络策略 (Network policies)，简写 \\\\textbf{Network policy}。\\n网络策略通常位于 Android 设置的应用详情页面中的 \\\\textbf{移动数据和 WLAN} 这一节的下面。\\n该页面中并非所有策略会被授权使用 (比如三星)，以及由于缺少文档，并非所有设置都能被很好地理解。\\nApp Manager 可以显示所有在 \\\\href{https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/net/NetworkPolicyManager.java}{网络策略管理器} 声明的网络策略。\\n对 App Manager 而言位置的策略会被加上 \\\\textit{Unknown} 前缀以及十六进制格式的策略常量名称和编号。\\n未知策略应报告给 App Manager 以供纳入。\\n\\n网络策略允许用户配置应用的某些网络行为，而不是直接修改 IP 地址表和/或者使用防火墙应用。\\n然而，其提供的功能很大程度上依赖于 Android 版本和 ROM。已知网络规则列表如下所示：\\n\\n\\\\begin{enumerate}\\n \\\\item \\\\textbf{无} 或 \\\\textbf{\\\\texttt{POLICY\\\\_NONE}}: (AOSP) 并未设置特定的网络策略。\\n系统仍可通过应用程序的性质分配规则。\\n\\n \\\\item \\\\textbf{禁止在后台使用移动数据 (流量计费的网络)} 或 \\\\textbf{\\\\texttt{POLICY\\\\_REJECT\\\\_METERED\\\\_BACKGROUND}}: (AOSP) 当应用在后台运行时，禁止使用移动数据 (流量计费的网络)。\\n\\n \\\\item \\\\textbf{允许后台使用移动数据 (流量计费的网络)，甚至在流量节省程序开启时} 或 \\\\textbf{\\\\texttt{POLICY\\\\_ALLOW\\\\_METERED\\\\_BACKGROUND}}: (AOSP) 允许后台使用移动数据 (流量计费的网络)，甚至是启用流量节省模式的情况下。\\n\\n \\\\item \\\\textbf{禁止移动数据 (蜂窝数据)} 或 \\\\textbf{\\\\texttt{POLICY\\\\_REJECT\\\\_CELLULAR}} (Android 11+) 或 \\\\textbf{\\\\texttt{POLICY\\\\_REJECT\\\\_ON\\\\_DATA}} (直到 Android 10): (Lineage OS) 禁止使用移动/蜂窝数据。\\n 向配置的应用程序发出网络不可用的信号，就像未激活移动数据 (蜂窝数据)一样。\\n\\n \\\\item \\\\textbf{禁止 VPN 数据} 或 \\\\textbf{\\\\texttt{POLICY\\\\_REJECT\\\\_VPN}} (Android 11+) 或 \\\\textbf{\\\\texttt{POLICY\\\\_REJECT\\\\_ON\\\\_VPN}} (直到 Android 10): (Lineage OS) 禁止使用 VPN 数据。\\n 向配置的应用程序发出网络不可用的信号，就像未激活 VPN 一样。\\n\\n \\\\item \\\\textbf{禁止 Wi-Fi 数据} 或 \\\\textbf{\\\\texttt{POLICY\\\\_REJECT\\\\_WIFI}} (Android 11+) 或 \\\\textbf{\\\\texttt{POLICY\\\\_REJECT\\\\_ON\\\\_WLAN}} (直到 Android 10): (Lineage OS) 禁止使用 Wi-Fi 数据。\\n 向配置的应用程序发出网络不可用的信号，就像该设备未连接到 Wi-Fi 网络一样。\\n\\n \\\\item \\\\textbf{禁用网络访问} 或 \\\\textbf{\\\\texttt{POLICY\\\\_REJECT\\\\_ALL}} (Android 11+) 或 \\\\textbf{\\\\texttt{POLICY\\\\_NETWORK\\\\_ISOLATED}} (直到 Android 10): (Lineage OS) 禁止所有情况下的网络访问。\\n 这与执行上述其他三项策略不同，推荐对可疑/狡诈的应用而言使用该策略。.\\n 若该策略被执行，则没有必要执行其他策略。\\n\\n \\\\item \\\\textbf{\\\\texttt{POLICY\\\\_ALLOW\\\\_METERED\\\\_IN\\\\_ROAMING}}: (三星) 可能是在漫游时允许使用移动数据 (流量计费的网络)。\\n 目前不知道其确切含义。\\n\\n \\\\item \\\\textbf{\\\\texttt{POLICY\\\\_ALLOW\\\\_WHITELIST\\\\_IN\\\\_ROAMING}}: (三星) 可能是在漫游时允许使用网络。\\n 目前不知道其确切含义。\\n\\n \\\\item \\\\textbf{禁止使用移动数据 (流量计费的网络)} 或 \\\\textbf{\\\\texttt{POLICY\\\\_REJECT\\\\_METERED}}: (摩托罗拉) 若是移动数据 (流量计费的网络) 则禁止使用网络。\\n\\n \\\\item \\\\textbf{禁止使用后台数据} 或 \\\\textbf{\\\\texttt{POLICY\\\\_REJECT\\\\_BACKGROUND}}: (摩托罗拉) 禁止后台使用数据。\\n\\n \\\\item \\\\textbf{禁用网络访问} or \\\\textbf{\\\\texttt{POLICY\\\\_REJECT\\\\_ALL}}: (摩托罗拉) 禁止所有的网络访问。\\n 与 Lineage OS 类似，会通过 iptables (防火墙) 阻止网络连接。但不知道它是否向配置的应用程序发出网络不可用的信号。\\n\\\\end{enumerate}\\n\\n\\\\begin{tip}{注释}\\n 相应的 Lineage OS 补丁如下：\\n \\\\begin{enumerate}\\n \\\\item \\\\href{https://github.com/LineageOS/android\\\\_frameworks\\\\_base/commit/a04932bafbbf7d99efd18276152cc2c9c9b2073e}{fw/b: Squash of app fw restriction commits}\\n \\\\item \\\\href{https://github.com/LineageOS/android\\\\_frameworks\\\\_base/commit/02c8c82854348f52afe2199f310f44b5f578b5b8}{fw/b: Add support for per app network isolation}\\n \\\\end{enumerate}\\n\\\\end{tip}</string>\n    <string name=\"guide$automation$$section-title\">自动任务</string>\n    <string name=\"guide$automation$features\">目前 App Manager 支持的一个功能，即 \\\\texttt{配置文件}。</string>\n    <string name=\"guide$automation$$generating-authorization-key-title\">生成授权密钥</string>\n    <string name=\"guide$wireless_debugging$enable-wireless-debugging\">在 \\\\textbf{开发者选项} 页面，找到 \\\\textbf{无线调试} 并单击以打开它。\\n在新打开的页面中，打开 \\\\textit{使用无线调试} 。取决于你的操作系统，你可能会看到一个提示对话框，要求你验证你的决定。\\n若遇到此情况，请单击 \\\\textit{允许} 。\\n\\n\\\\begin{tip}{提示}\\n 为了更便于访问，你可能想将 \\\\textbf{无线调试} 添加到通知块部件 (快速设置磁贴)。\\n 要做到这一点，请找到 \\\\textbf{开发者选项} 页面的 \\\\textbf{快速设置开发者磁贴} ，单击以打开它。\\n 在新窗口中，启用 \\\\textit{无线调试}。然而该选项在大多数操作系统中不可用。\\n 如果你没看到这个设置，你可以在磁贴自定义面板中找到 \\\\textbf{无线调试}\\n 磁贴。\\n\\\\end{tip}</string>\n    <string name=\"guide$wireless_debugging$pair-adb-with-app-manager\">在 App Manager 中，转到 \\\\textbf{设置} &gt; \\\\hyperref[subsec:mode-of-operation]{操作模式}\\n，接着开启 \\\\textit{无线调试}。启用后，App Manager 会试着自动建立\\n无线调试连接，如果先前未配对，那么该尝试会失败。尝试失败后，\\n应用会请你连接或配对 ADB\\\\@。选择\\\\textit{配对} 会出现新的对话框。\\n对话框会让你转到 \\\\textbf{无线调试} 页面。\\n\\n\\\\begin{tip}{注}\\n 截至 v4.0.0 版， App Manger 使用通知提示进行配对。因而，如果你停用了\\n App Manager 的通知权限，你必须先启用它。.\\n\\\\end{tip}\\n\\n在\\\\textbf{无线调试} 页面， 选择 \\\\textbf{用配对码配对设备}. 之后会展示\\n一个包含配对码的对话框。一个请求配对码的通知也会几乎立马变得可见。\\n将配对码输入通知中的输入框，\\n单击 \\\\textit{配对}。如配对成功，App Manager 会显示\\n``已配对\\'\\' 的消息通知， \\\\textbf{无线调试} 页中的对话框将被自动\\n忽略。你也可以在相同页面中看到 App Manager 被列为 ADB 客户端。\\n\\n\\\\begin{tip}{注意}\\n 如果你有一段时间不在 ADB 模式下使用 App Manager，那么 App Manager 可能会从\\n Adb 客户端列表中被删除。如果出现这种情况，你必须重复以上步骤。\\n\\\\end{tip}</string>\n    <string name=\"guide$wireless_debugging$connect-am-to-adb\">若运行模式设置为 \\\\textit{自动}, \\\\textit{通过 TCP 启动的 ADB} 或 \\\\textit{无线调试}，\\nApp Manager 应该能够自动连接到 ADB。\\n若并非如此，则在\\\\textbf{设置} &gt; \\\\hyperref[subsec:mode-of-operation]{操作模式} 中选择 \\\\textit{无线调试} 。\\n若 App Manager 无法检测或连接到 ADB ，\\n则会显示一个提示对话框以用于连接或配对 ADB 。 选择 \\\\textit{连接} 。\\n\\n现在，从 Android 设置中转到 \\\\textbf{无线调试} 页面，记下页面显示的端口号。\\n在 App Manager 的提示对话框中，\\n用你记下的端口号替换当前端口号，然后点击 \\\\textit{连接} 。\\n\\n一旦成功建立连接，你就能够禁用 Android 设置的 \\\\textbf{无线调试}。\\n\\n\\\\begin{danger}{小心}\\n 不要禁用 \\\\textbf{USB 调试} 或 \\\\Sref{subsec:enable-developer-options-and-usb-debugging}{启用开发者选项和 USB 调试} 提及的任何附加选项。\\n 一旦禁用，App Manager 使用的远程服务器会被终止，你可能不得不重新开始。\\n\\\\end{danger}</string>\n    <string name=\"guide$backup-restore$intro\">App Manager 具有从零开始的现代、高级和易于使用的备份/还原系统实现。\\n可能仅本应用有能力\\n同时还原应用程序和数据以及你在 App Manager 内配置的权限和规则。\\n你还可以选择多次备份应用程序 (使用自定义名称) 或为所有用户进行备份。\\n\\n\\\\begin{amseealso}{另请参阅}\\n \\\\item \\\\hyperref[subsec:1-click-back-up]{一键操作：备份}\\n \\\\item \\\\hyperref[subsec:1-click-restore]{一键操作：还原}\\n\\\\end{amseealso}</string>\n    <string name=\"guide$backup-restore$location\">备份/还原是 \\\\hyperref[subsec:batch-operations]{批处理操作} 的一部分。\\n它也位于 \\\\hyperref[subsec:app-info-tab]{应用信息标签页} 的\\n\\\\hyperref[subsubsec:app-info-options-menu]{选项菜单} 中。\\nClicking on \\\\textbf{Backup/Restore} opens the \\\\textbf{Backup Options}.\\n默认情况下，备份存放在 \\\\texttt{/storage/emulated/0/AppManager} 。\\n你可以在 \\\\hyperref[subsubsec:backup-volume]{设置页面} 配置自定义的备份位置。\\n无论如何配置，备份都会存放在所选卷的 \\\\texttt{AppManager} 文件夹。\\n\\n\\\\begin{tip}{注意}\\n 若一个或多个应用程序并没有任何备份，\\n 则不会显示 \\\\textbf{还原} 和 \\\\textbf{删除备份} 选项。\\n\\\\end{tip}</string>\n    <string name=\"guide$automation$generating-authorization-key\">为了确保适当的安全性，需要授权密钥。前往 \\\\textbf{设置} 页面，接着是 \\\\textbf{隐私} &gt; \\\\textbf{授权管理器} 以生成授权密钥。\\n若并未生成过授权密钥，则会自动生成。该密钥可根据需求重新生成。\\n\\n\\\\begin{danger}{小心}\\n 重新生成授权密钥可能会产生一些副作用，比如说令所有先前配置的意图失效。\\n\\\\end{danger}</string>\n    <string name=\"guide$backup-restore$backup\">备份功能会遵守除了 \\\\textbf{跳过签名检查} 以外的所有备份选项。\\n若基本备份 (即并未选择\\\\textbf{多重备份} 选项) 已存在，由于备份会被覆盖，你会看到一条警告信息。\\n若设置了 \\\\textbf{多重备份} ，你需要在选项中输入(指定)备份名称，或者你也可以留空以使用当前日期时间作为备份名称。</string>\n    <string name=\"guide$backup-restore$restore\">还原会遵守全部备份选项，并在出现以下情况时失败：若设置了 \\\\textbf{APK 文件} 选项，\\n备份内容却不包括 APK 文件选项设定的内容，或者其他情况下，未安装该应用程序。\\n当为多个应用还原备份时，你只能选择还原基础备份 (参阅 \\\\hyperref[subsec:backup-restore-backup]{备份} 章节以了解更多)。\\n然而，当为单个应用程序还原备份时，你需要通过选项选择还原哪个备份。\\n若设定了 \\\\textbf{所有用户} 选项，则 App Manager 将在后一种情况为所有用户还原所选备份。但是在前一种情况中，将会为各个用户还原基础备份。\\n\\n\\\\begin{tip}{注意}\\n 使用存储访问框架 (Storage Access Framework 即 SAF)、SSAID 或 Android 密钥库只有在还原并立即重新启动后正常工作。\\n\\\\end{tip}</string>\n    <string name=\"guide$automation$triggering-a-profile\">为了触发配置文件， \\\\texttt{feature} (功能) 字段必须具有 \\\\texttt{profile} (配置文件) 值。 此外，接下来的 extras (额外选项) 可包括：\\n\\\\begin{enumerate}\\n \\\\item \\\\textbf{\\\\texttt{prof}.} (字符串值 -- 必须) 显示在 \\\\hyperref[sec:profiles-page]{配置页面} 的配置名称。\\n \\\\item \\\\textbf{\\\\texttt{state}.} (字符串值 -- 可选) 配置文件的状态 -- 目前 \\\\texttt{on} (启用) 或者 \\\\texttt{off} (禁用) -- 如文档所述。.\\n 若此时未设置额外选项，则 App Manager 会提示需要选择的状态。\\n因此，为了完全自动化，应该设置该选项。\\n\\\\end{enumerate}</string>\n    <string name=\"faq$app-components$what-are-app-components\">活动、服务、广播接收器 (或者仅接收器) 和内容提供者 (或仅提供者) 统称为应用程序组件。\\n技术上来说，它们都继承了\\n\\\\href{https://developer.android.com/reference/android/content/pm/ComponentInfo}{ComponentInfo} 类\\n并可以通过意图被启动。</string>\n    <string name=\"faq$app-components$limitations\">App Manager 通常使用一个称作\\n\\\\href{https://carteryagemann.com/pages/android-intent-firewall.html}{Intent Firewall (IFW)，意图防火墙} 的方法阻止应用程序组件 (或跟踪器组件)，\\n它比其他诸如 \\\\textit{pm} (PackageManager，包管理器)、 \\\\href{https://github.com/RikkaApps/Shizuku}{Shizuku} \\n或其他任何使用包管理器启用或禁用组件的办法更优秀。\\n若组件被后者的办法禁用，应用程序自身可以检测到组件被阻止并能重新启用，因为应用程序有自身组件的完整访问权限。\\n(许多欺骗性应用程序这样做，实际上是为了让跟踪器组件保持不被阻止的状态。)\\n另一方面，意图防火墙 (IFW) 是一个真正的防火墙，应用程序无法检测自身组件是否被阻止。\\n这也是 App Manager 使用术语 \\\\textit{阻止} 而非 \\\\textit{禁用} 的原因。\\n\\n就算是意图防火墙也有一些局限性，主要适用于系统应用程序：\\n\\\\begin{itemize}\\n \\\\item 相关应用程序被系统加入白名单。 即没有这些应用程序，系统将无法正常运行，并可能导致随机崩溃。\\n 这些应用程序包括但不限于 Android 系统、系统界面、电话服务。\\n 即使禁用或阻止，它们仍然会运行。\\n\\n \\\\item 另外一部分系统应用程序或系统进程通过进程间通信 (Interprocess Communication，IPC)\\n 激活了被加入白名单的系统应用程序的应用程序组件。\\n 此情况下组件会被激活，并无视组件的阻止状态甚至是整个应用程序被禁用。\\n 若有不需要的系统应用程序，阻止其运行的唯一办法就是摆脱 (卸载/移除)它。\\n\\\\end{itemize}</string>\n    <string name=\"faq$app-components$other-tools-retained-in-am\">\\\\textbf{不。} 但是被系统或任何其他工具阻止的应用程序组件会在\\\\hyperref[subsec:component-tabs]{组件标签页} 显示。\\n这些规则可从 \\\\hyperref[par:import-existing-rules]{设置} 导入。\\n然而，App Manager 无法区分组件是被第三方工具阻止还是被系统阻止。\\n因此，在导入页面中显示的应用程序列表应谨慎选择。</string>\n    <string name=\"faq$app-components$also-blocked-by-other-tools\">\\\\textit{如果请求，App Manager 会再次阻止组件。} 解除阻止的情况下，它们将恢复到应用程序清单中指定的默认状态。\\n但是如果组件是被 \\\\href{https://www.myandroidtools.com}{MyAndroidTools (MAT)} 使用意图防火墙 (IFW) 阻止，\\n由于 MAT 使用不同的格式，它们不会被 App Manager 解除阻止。\\n为了修复这个问题，首先需要从 \\\\hyperref[par:import-existing-rules]{设置} 导入规则\\n这种情况下，MAT 的配置文件会被永久移除。</string>\n    <string name=\"faq$misc$i-dont-use-root-adb\">是的，App Manager 不能在无 Root 或 ADB\\\\@ 时修改任何系统设置。</string>\n    <string name=\"faq$misc$apks-deleted-after-installed\">不会，在安装后，APK 不会被 App Manager 删除。</string>\n    <string name=\"faq$misc$$apks-deleted-after-installed\">APK 安装后是否被删除？</string>\n    <string name=\"faq$misc$bloatware\">臃肿软件（Bloatware）为不必要的预装应用，通常是系统应用。\\n一些臃肿软件通常用来跟踪用户并收集它们可能为了获利而出售的用户数据。\\n许多系统应用无需请求任何权限便可访问设备信息、联系人和消息数据，以及其他使用信息，\\n比如手机使用习惯和存储在共享存储空间中的一切。\\n\\n臃肿软件同样包括 Google 地图、Meta 出品的应用，以及Twitter/X，\\n这些应用也可以在没有用户同意情况下跟踪和/或收集用户数据。\\n你可以在 Andeoid 系统设置那里禁用这些应用的一些权限，\\n但请知晓，系统设置藏有很多权限被安全研究者认为具潜在\\\\emph{危险性} （比如联网、传感器等）。\\n\\n如果臃肿软件是用户应用，可以轻易从系统设置或AM\\\\@ 进行卸载。\\n而属于系统应用的臃肿应用没有特权是不可能卸载的。\\n即使有特权也无法完全\\\\emph{卸载} 这样的系统应用，\\n因为它们位于 \\\\emph{system} 分区，这是一个只读分区。\\n如果你有 root 权限，你可以重新挂载这个分区来手动 \\\\emph{清除} 这些应用，但这样做会破化系统的 OTA 更新，\\n因为系统分区中的数据已经被修改。\\n有两种更新，一种是 delta 更新（仅由两个系统版本间的差异构成，下载东西少）和完整更新。\\n你仍能使用完整更新，但更新后臃肿软件又会出现，你不得不再次彻底清理它们。\\n\\n另一个解决方案是通过系统设置或 AM 停用这些应用，\\n但某些服务仍能在后台运行，\\n因为它们可以被其他系统应用使用进程间通信（IPC）方式启动。\\n一个可能的解决方案是停用所有臃肿软件，直到服务最终停止（在重启后）。\\n不过，由于厂商对 ANdroid 框架所做的巨大改动，\\n删除或停用某些臃肿软件可能导致系统 UI 崩溃甚至造成启动循环。\\n从 v4.0.0 版本起，AM 有了一个新功能，叫做 \\\\textbf{Debloater}，\\n可以用作从专有权利的 Android 操作系统中监控、停用，及删除臃肿软件的基础。\\n\\n\\\\begin{warning}{注意}\\n多数情况下，你无法完全 debloat 设备。\\n因此，建议你使用没有臃肿软件的定制 ROM，如 Graphene OS、Lineage OS 或它们的衍生品。\\n\\\\end{warning}</string>\n    <string name=\"faq$aot$restart\">很不幸的是，是的。这是因为响应 ADB 连接的 ADB daemon (ADB 守护进程) 也会在重新启动后重新开始。\\n 而这并不会重新启用通过 TCP\\\\@ 运行的 ADB。</string>\n    <string name=\"faq$aot$usb-debugging\">参阅位于 \\\\Cref{ch:guides}{指引} 的 \\\\Sref{subsec:enable-usb-debugging}{启用 USB 调试} 。</string>\n    <string name=\"faq$misc$how-tracker-updated\">在新版本发布前，会手动更新跟踪器和库。</string>\n    <string name=\"faq$misc$shizuku\">现在 App Manager 使用隐藏 API 和执行特权代码变得更加复杂，\\n无法和 \\\\href{https://shizuku.rikka.app}{Shizuku} 之类的其他第三方应用程序集成。\\n不考虑在 App Manager 中集成 Shizuku (现在具有 Apache 2.0 协议) 的理由如下：\\n\\\\begin{enumerate}\\n \\\\item 最初 Shizuku 是不自由软件，这也导致我\\n 在 App Manager 中使用了类似的方法来支持 Root 和 ADB。\\n \\\\item App Manager 已经支持 Root 和 ADB，并且在某些情况下比 Shizuku 更优秀。\\n \\\\item 主要功能依赖于第三方应用并不是一个好的设计理念选择。\\n \\\\item 集成 Shizuku 会增加 App Manager 的复杂性。\\n\\\\end{enumerate}</string>\n    <string name=\"faq$aot$feature-adb\">在 ADB 模式下，受支持的功能会自动启用。\\n受支持的功能包括禁用、强制停止、清除应用程序数据、授予或撤销应用操作 (App Ops) 和权限等。\\n也可在无系统提示的情况下安装或卸载应用程序。</string>\n    <string name=\"faq$app-components$what-is-component-blocking\">当你在 \\\\hyperref[sec:app-details-page]{应用详情页} 中阻止组件时，默认情况下阻止规则不会立刻生效。\\n仅在你使用顶部右侧菜单的 \\\\textit{应用规则} 选项时，阻止规则才会生效。\\n若你启用 \\\\hyperref[subsubsec:instant-component-blocking]{即时阻止组件} 选项，则当你阻止组件时，阻止规则会立刻生效。\\n若你选择阻止跟踪器组件，阻止规则会自动生效，该选项设置会被忽略。\\n你也可以通过在应用详情页内同一菜单简单点击 \\\\textit{移除规则} 为该应用程序移除阻止规则。\\n由于默认行为使你更好地控制应用程序，保持选项 \\\\textit{即时阻止组件} 选项为禁用状态更好。</string>\n    <string name=\"faq$app-components$tracker-classes-versus-tracker-components\">所有应用程序组件都是类，但并非所有类都是组件。事实上，只有少数类是组件。\\n话虽如此， \\\\hyperref[sec:scanner-page]{扫描页面} 展示的是跟踪器列表以及类的数量，而并非只是组件数。\\n在所有其他页面，跟踪器和跟踪器组件是同一个意思，都用于表示跟踪器。\\n即：阻止 tracker 是指阻止跟踪器组件，而不是跟踪器类。\\n\\n\\\\begin{tip}{信息}\\n 无法阻止并非组件的跟踪器类。它们仅能在编辑应用程序自身时被移除。\\n\\\\end{tip}</string>\n    <string name=\"faq$aot$block-tracker\">ADB 具有数量限制 \\\\href{https://github.com/aosp-mirror/platform_frameworks_base/blob/master/packages/Shell/AndroidManifest.xml}{权限}\\n而并非它们其中一个控制应用程序组件。 然而，\\\\textit{仅用于测试} 的应用程序的组件可以通过 ADB\\\\@ 进行控制。\\n若 App Manager 检测到此类应用程序，则会自动启用阻止选项。</string>\n    <string name=\"appendices$specifications$background\">App Manager 目前支持阻止活动、广播接收器、内容提供者、服务、应用操作 (App Ops) 和权限，\\n并且在将来可能会添加更多阻止选项。\\n为了增加更多便携性，导入/导出所有的这些数据是有必要的。\\n\\n由于数据库专门用于存储数据，维护数据库是最佳选择。\\n目前为止有多个 \\\\texttt{tsv} 文件，每个文件都有包名和 \\\\texttt{.tsv} 扩展名。\\n\\\\texttt{RulesStorageManager} (规则存储管理器) 类负责查询/处理相应的文件/数据库。\\n由于这种抽象概念，将来在不更改整个项目设计的情况下切换到数据库或加密数据库系统会更加容易。\\n目前所有的配置文件存储在 \\\\texttt{/data/data/io.github.muntashirakon.AppManager/Files/conf}。</string>\n    <string name=\"appendices$specifications$internal\">下述格式在 App Manager 内部使用，且 \\\\textit{与外部格式不兼容。}\\n\\\\begin{Verbatim}\\n &lt;name&gt; &lt;type&gt; &lt;mode&gt;|&lt;component_status&gt;|&lt;is_granted&gt;\\n\\\\end{Verbatim}\\n此处：\\n\\\\begin{itemize}\\n \\\\item \\\\texttt{&lt;name&gt;} -- 组件/权限/应用操作 (App Ops) 名 (对于 App Ops，值可能为字符串或整数)\\n \\\\item \\\\texttt{&lt;type&gt;} -- \\\\texttt{ACTIVITY}、 \\\\texttt{RECEIVER}、 \\\\texttt{PROVIDER}、 \\\\texttt{SERVICE}、\\n \\\\texttt{APP\\\\_OP}、 \\\\texttt{PERMISSION}的其中一个\\n \\\\item \\\\texttt{&lt;mode&gt;} -- (用于App Ops) 相关的 \\\\hyperref[subsec:mode-constants]{模式常量}\\n \\\\item \\\\texttt{&lt;component\\\\_status&gt;} -- (用于组件) 组件状态\\n \\\\begin{itemize}\\n \\\\item \\\\texttt{true} -- 已应用组件 (\\\\texttt{true} 值因为兼容性被保留)\\n \\\\item \\\\texttt{false} -- 尚未应用组件，但将来会生效 (\\\\texttt{false} 值因为兼容性被保留)\\n \\\\item \\\\texttt{unblocked} -- 计划解除阻止的组件\\n \\\\end{itemize}\\n \\\\item \\\\texttt{&lt;is\\\\_granted&gt;} -- (用于权限) 是否授予或撤销权限\\n\\\\end{itemize}</string>\n    <string name=\"appendices$specifications$external\">外部格式用于 App Manager 导入或导出规则。\\n\\\\begin{Verbatim}\\n &lt;package_name&gt; &lt;component_name&gt; &lt;type&gt; &lt;mode&gt;|&lt;component_status&gt;|&lt;is_granted&gt;\\n\\\\end{Verbatim}\\n除了第一项是包的名称外，其格式与上述 (内部格式) 基本相同。\\n\\n\\\\begin{danger}{小心}\\n 导出的规则具有与内部格式不同的格式，\\n 不应该被直接复制到 \\\\textbf{conf} 文件夹。\\n\\\\end{danger}</string>\n</resources>\n"
  },
  {
    "path": "docs/raw/zh-rTW/index.html",
    "content": "<!doctype html><html xmlns=http://www.w3.org/1999/xhtml lang=zh-Hant xml:lang=zh-Hant><meta charset=utf-8><meta name=generator content=\"pandoc\"><meta name=viewport content=\"width=device-width,initial-scale=1,user-scalable=yes\"><meta name=author content=\"Muntashir Al-Islam\"><title>App Manager</title><style>code{white-space:pre-wrap}span.smallcaps{font-variant:small-caps}div.columns{display:flex;gap:min(4vw,1.5em)}div.column{flex:auto;overflow-x:auto}div.hanging-indent{margin-left:1.5em;text-indent:-1.5em}ul.task-list[class]{list-style:none}ul.task-list li input[type=checkbox]{font-size:inherit;width:.8em;margin:0 .8em .2em -1.6em;vertical-align:middle}.display.math{display:block;text-align:center;margin:.5rem auto}html{-webkit-text-size-adjust:100%}pre>code.sourceCode{white-space:pre;position:relative}pre>code.sourceCode>span{display:inline-block;line-height:1.25}pre>code.sourceCode>span:empty{height:1.2em}.sourceCode{overflow:visible}code.sourceCode>span{color:inherit;text-decoration:inherit}div.sourceCode{margin:1em 0}pre.sourceCode{margin:0}@media screen{div.sourceCode{overflow:auto}}@media print{pre>code.sourceCode{white-space:pre-wrap}pre>code.sourceCode>span{text-indent:-5em;padding-left:5em}}pre.numberSource code{counter-reset:source-line 0}pre.numberSource code>span{position:relative;left:-4em;counter-increment:source-line}pre.numberSource code>span>a:first-child::before{content:counter(source-line);position:relative;left:-1em;text-align:right;vertical-align:baseline;border:none;display:inline-block;-webkit-touch-callout:none;-webkit-user-select:none;-khtml-user-select:none;-moz-user-select:none;-ms-user-select:none;user-select:none;padding:0 4px;width:4em}pre.numberSource{margin-left:3em;padding-left:4px}div.sourceCode{}@media screen{pre>code.sourceCode>span>a:first-child::before{text-decoration:underline}}code span.al{font-weight:700}code span.an{font-style:italic}code span.cf{font-weight:700}code span.co{font-style:italic}code span.cv{font-style:italic}code span.do{font-style:italic}code span.dt{text-decoration:underline}code span.er{font-weight:700}code span.in{font-style:italic}code span.kw{font-weight:700}code span.pp{font-weight:700}code span.wa{font-style:italic}</style><link rel=stylesheet href=../css/custom.css><header id=title-block-header><h1 class=title>App Manager</h1><p class=author>Muntashir Al-Islam</header><nav id=TOC role=doc-toc><ul class=incremental><li><span><span class=toc-section-number>1</span> <a href=#ch:introduction id=toc:ch:introduction>簡介</a></span><ul class=incremental><li><span><span class=toc-section-number>1.1</span> <a href=#sec:terminologies id=toc:sec:terminologies>術語</a></span><li><span><span class=toc-section-number>1.2</span> <a href=#sec:supported-versions id=toc:sec:supported-versions>受支持的版本</a></span><li><span><span class=toc-section-number>1.3</span> <a href=#sec:official-sources id=toc:sec:official-sources>官方來源</a></span><ul class=incremental><li><span><span class=toc-section-number>1.3.1</span> <a href=#subsec:binary-distribution-sources id=toc:subsec:binary-distribution-sources>二進制(可執行)分發來源</a></span><li><span><span class=toc-section-number>1.3.2</span> <a href=#subsec:links-to-source-code id=toc:subsec:links-to-source-code>源碼鏈接</a></span><li><span><span class=toc-section-number>1.3.3</span> <a href=#subsec:translations id=toc:subsec:translations>翻譯</a></span></ul><li><span><span class=toc-section-number>1.4</span> <a href=#sec:contributing id=toc:sec:contributing>貢獻</a></span><ul class=incremental><li><span><span class=toc-section-number>1.4.1</span> <a href=#subsec:build-instructions id=toc:subsec:build-instructions>構建說明</a></span><li><span><span class=toc-section-number>1.4.2</span> <a href=#subsec:submitting-patches id=toc:subsec:submitting-patches>提交補丁</a></span></ul><li><span><span class=toc-section-number>1.5</span> <a href=#sec:donation-&-funding id=toc:sec:donation-&-funding>捐贈 & 資助</a></span><li><span><span class=toc-section-number>1.6</span> <a href=#sec:contact id=toc:sec:contact>聯系我們</a></span></ul><li><span><span class=toc-section-number>2</span> <a href=#ch:pages id=toc:ch:pages>頁面</a></span><ul class=incremental><li><span><span class=toc-section-number>2.1</span> <a href=#sec:main-page id=toc:sec:main-page>主頁</a></span><ul class=incremental><li><span><span class=toc-section-number>2.1.1</span> <a href=#subsec:batch-operations id=toc:subsec:batch-operations>批處理</a></span><li><span><span class=toc-section-number>2.1.2</span> <a href=#subsec:main-colour-codes id=toc:subsec:main-colour-codes>顏色代碼含義</a></span><li><span><span class=toc-section-number>2.1.3</span> <a href=#subsec:main-page-application-types id=toc:subsec:main-page-application-types>應用類型</a></span><li><span><span class=toc-section-number>2.1.4</span> <a href=#subsec:main-page-version-info id=toc:subsec:main-page-version-info>版本信息</a></span><li><span><span class=toc-section-number>2.1.5</span> <a href=#subsec:main-page-options-menu id=toc:subsec:main-page-options-menu>選項菜單</a></span></ul><li><span><span class=toc-section-number>2.2</span> <a href=#sec:app-details-page id=toc:sec:app-details-page>應用程序詳情頁</a></span><ul class=incremental><li><span><span class=toc-section-number>2.2.1</span> <a href=#subsec:app-details-colour-codes id=toc:subsec:app-details-colour-codes>顏色代碼含義</a></span><li><span><span class=toc-section-number>2.2.2</span> <a href=#subsec:app-info-tab id=toc:subsec:app-info-tab>應用信息</a></span><li><span><span class=toc-section-number>2.2.3</span> <a href=#subsec:component-tabs id=toc:subsec:component-tabs>組件選項卡</a></span><li><span><span class=toc-section-number>2.2.4</span> <a href=#subsec:permission-tabs id=toc:subsec:permission-tabs>權限選項卡</a></span><li><span><span class=toc-section-number>2.2.5</span> <a href=#subsec:signatures-tab id=toc:subsec:signatures-tab>簽名選項卡</a></span><li><span><span class=toc-section-number>2.2.6</span> <a href=#subsec:uses-features-tab id=toc:subsec:uses-features-tab>Uses\nFeatures tab</a></span><li><span><span class=toc-section-number>2.2.7</span> <a href=#subsec:configurations-tab id=toc:subsec:configurations-tab>Configurations tab</a></span><li><span><span class=toc-section-number>2.2.8</span> <a href=#subsec:shared-libs-tab id=toc:subsec:shared-libs-tab>共享庫選項卡</a></span></ul><li><span><span class=toc-section-number>2.3</span> <a href=#sec:1-click-ops-page id=toc:sec:1-click-ops-page>一鍵操作頁</a></span><ul class=incremental><li><span><span class=toc-section-number>2.3.1</span> <a href=#subsec:block-unblock-trackers id=toc:subsec:block-unblock-trackers>Block/Unblock\nTrackers</a></span><li><span><span class=toc-section-number>2.3.2</span> <a href=#subsec:block-components-dots id=toc:subsec:block-components-dots>Block Components…</a></span><li><span><span class=toc-section-number>2.3.3</span> <a href=#subsec:set-mode-for-app-ops-dots id=toc:subsec:set-mode-for-app-ops-dots>Set Mode for App\nOps…</a></span><li><span><span class=toc-section-number>2.3.4</span> <a href=#subsec:1-click-back-up id=toc:subsec:1-click-back-up>備份</a></span><li><span><span class=toc-section-number>2.3.5</span> <a href=#subsec:1-click-restore id=toc:subsec:1-click-restore>恢覆</a></span><li><span><span class=toc-section-number>2.3.6</span> <a href=#subsec:trim-caches-in-all-apps id=toc:subsec:trim-caches-in-all-apps>Trim Caches in All\nApps</a></span></ul><li><span><span class=toc-section-number>2.4</span> <a href=#sec:profiles-page id=toc:sec:profiles-page>配置文件頁面</a></span><ul class=incremental><li><span><span class=toc-section-number>2.4.1</span> <a href=#subsec:profiles-options-menu id=toc:subsec:profiles-options-menu>選項菜單</a></span></ul><li><span><span class=toc-section-number>2.5</span> <a href=#sec:profile-page id=toc:sec:profile-page>配置頁</a></span><ul class=incremental><li><span><span class=toc-section-number>2.5.1</span> <a href=#subsec:profile-options-menu id=toc:subsec:profile-options-menu>選項菜單</a></span><li><span><span class=toc-section-number>2.5.2</span> <a href=#subsec:profile-apps-tab id=toc:subsec:profile-apps-tab>應用程序選項卡</a></span><li><span><span class=toc-section-number>2.5.3</span> <a href=#subsec:profile-configurations-tab id=toc:subsec:profile-configurations-tab>配置選項卡</a></span></ul><li><span><span class=toc-section-number>2.6</span> <a href=#sec:settings-page id=toc:sec:settings-page>設置頁面</a></span><ul class=incremental><li><span><span class=toc-section-number>2.6.1</span> <a href=#subsec:language id=toc:subsec:language>界面語言</a></span><li><span><span class=toc-section-number>2.6.2</span> <a href=#subsec:appearance id=toc:subsec:appearance>Appearance</a></span><li><span><span class=toc-section-number>2.6.3</span> <a href=#subsec:privacy id=toc:subsec:privacy>Privacy</a></span><li><span><span class=toc-section-number>2.6.4</span> <a href=#subsec:mode-of-operation id=toc:subsec:mode-of-operation>操作模式</a></span><li><span><span class=toc-section-number>2.6.5</span> <a href=#subsec:apk-signing id=toc:subsec:apk-signing>APK\n簽名</a></span><li><span><span class=toc-section-number>2.6.6</span> <a href=#subsec:installer id=toc:subsec:installer>安裝器</a></span><li><span><span class=toc-section-number>2.6.7</span> <a href=#subsec:backup/restore id=toc:subsec:backup/restore>備份/恢覆</a></span><li><span><span class=toc-section-number>2.6.8</span> <a href=#subsec:rules id=toc:subsec:rules>規則</a></span><li><span><span class=toc-section-number>2.6.9</span> <a href=#subsec:advanced id=toc:subsec:advanced>Advanced</a></span><li><span><span class=toc-section-number>2.6.10</span> <a href=#subsec:device-info id=toc:subsec:device-info>關於設備</a></span></ul><li><span><span class=toc-section-number>2.7</span> <a href=#sec:scanner-page id=toc:sec:scanner-page>掃描器頁面</a></span><li><span><span class=toc-section-number>2.8</span> <a href=#sec:interceptor-page id=toc:sec:interceptor-page>攔截器頁面</a></span><ul class=incremental><li><span><span class=toc-section-number>2.8.1</span> <a href=#subsec:intent-filters id=toc:subsec:intent-filters>意圖(Intent)過濾器</a></span><li><span><span class=toc-section-number>2.8.2</span> <a href=#subsec:matching-activities id=toc:subsec:matching-activities>匹配的活動(Activity)</a></span><li><span><span class=toc-section-number>2.8.3</span> <a href=#subsec:interceptor-reset-to-default id=toc:subsec:interceptor-reset-to-default>重置為默認</a></span><li><span><span class=toc-section-number>2.8.4</span> <a href=#subsec:interceptor-send-edited-intent id=toc:subsec:interceptor-send-edited-intent>發送編輯過的意圖(Intent)</a></span></ul><li><span><span class=toc-section-number>2.9</span> <a href=#sec:shared-preferences-editor-page id=toc:sec:shared-preferences-editor-page>共享首選項(Shared\nPreferences)編輯頁</a></span></ul><li><span><span class=toc-section-number>3</span> <a href=#ch:guides id=toc:ch:guides>指南</a></span><ul class=incremental><li><span><span class=toc-section-number>3.1</span> <a href=#sec:adb-over-tcp id=toc:sec:adb-over-tcp>經由 TCP 的\nADB</a></span><ul class=incremental><li><span><span class=toc-section-number>3.1.1</span> <a href=#subsec:enable-developer-options id=toc:subsec:enable-developer-options>啟用開發者選項</a></span><li><span><span class=toc-section-number>3.1.2</span> <a href=#subsec:enable-usb-debugging id=toc:subsec:enable-usb-debugging>啟用USB調試</a></span><li><span><span class=toc-section-number>3.1.3</span> <a href=#subsec:setup-adb-on-pc-or-mac id=toc:subsec:setup-adb-on-pc-or-mac>在PC或Mac上配置ADB</a></span><li><span><span class=toc-section-number>3.1.4</span> <a href=#subsec:configure-adb-over-tcp id=toc:subsec:configure-adb-over-tcp>配置經由TCP的ADB</a></span></ul><li><span><span class=toc-section-number>3.2</span> <a href=#sec:wireless-debugging id=toc:sec:wireless-debugging>Wireless\nDebugging</a></span><ul class=incremental><li><span><span class=toc-section-number>3.2.1</span> <a href=#subsec:enable-developer-options-and-usb-debugging id=toc:subsec:enable-developer-options-and-usb-debugging>Enable\ndeveloper options and USB Debugging</a></span><li><span><span class=toc-section-number>3.2.2</span> <a href=#subsec:enable-wireless-debugging id=toc:subsec:enable-wireless-debugging>Enable Wireless\nDebugging</a></span><li><span><span class=toc-section-number>3.2.3</span> <a href=#subsec:pair-adb-with-app-manager id=toc:subsec:pair-adb-with-app-manager>Pair ADB with App\nManager</a></span><li><span><span class=toc-section-number>3.2.4</span> <a href=#subsec:connect-app-manager-to-adb id=toc:subsec:connect-app-manager-to-adb>Connect App Manager to\nADB</a></span></ul><li><span><span class=toc-section-number>3.3</span> <a href=#sec:backup-restore id=toc:sec:backup-restore>備份/恢覆</a></span><ul class=incremental><li><span><span class=toc-section-number>3.3.1</span> <a href=#subsec:backup-location id=toc:subsec:backup-location>位置</a></span><li><span><span class=toc-section-number>3.3.2</span> <a href=#subsec:backup-restore-backup-options id=toc:subsec:backup-restore-backup-options>備份選項</a></span><li><span><span class=toc-section-number>3.3.3</span> <a href=#subsec:backup-restore-backup id=toc:subsec:backup-restore-backup>備份</a></span><li><span><span class=toc-section-number>3.3.4</span> <a href=#subsec:backup-restore-restore id=toc:subsec:backup-restore-restore>恢覆</a></span><li><span><span class=toc-section-number>3.3.5</span> <a href=#subsec:backup-restore-delete-backup id=toc:subsec:backup-restore-delete-backup>刪除備份</a></span></ul><li><span><span class=toc-section-number>3.4</span> <a href=#sec:automating-tasks id=toc:sec:automating-tasks>Automating\nTasks</a></span><ul class=incremental><li><span><span class=toc-section-number>3.4.1</span> <a href=#subsec:generating-authorization-key id=toc:subsec:generating-authorization-key>Generating authorization\nkey</a></span><li><span><span class=toc-section-number>3.4.2</span> <a href=#subsec:at:general-configuration id=toc:subsec:at:general-configuration>Configuring\ntasks</a></span><li><span><span class=toc-section-number>3.4.3</span> <a href=#subsec:at:features id=toc:subsec:at:features>Features</a></span><li><span><span class=toc-section-number>3.4.4</span> <a href=#subsec:triggering-a-profile id=toc:subsec:triggering-a-profile>Triggering a\nprofile</a></span></ul><li><span><span class=toc-section-number>3.5</span> <a href=#sec:net-policy id=toc:sec:net-policy>連網策略</a></span></ul><li><span><span class=toc-section-number>4</span> <a href=#ch:faq id=toc:ch:faq>常見問題</a></span><ul class=incremental><li><span><span class=toc-section-number>4.1</span> <a href=#sec:faq:app-components id=toc:sec:faq:app-components>應用組件</a></span><ul class=incremental><li><span><span class=toc-section-number>4.1.1</span> <a href=#subsec:faq:what-are-app-components id=toc:subsec:faq:what-are-app-components>什麽是應用組件？</a></span><li><span><span class=toc-section-number>4.1.2</span> <a href=#subsec:faq:how-components-blocked id=toc:subsec:faq:how-components-blocked>追蹤器或其他組件在App\nManager中是如何被禁用的？其局限性是什麽？</a></span><li><span><span class=toc-section-number>4.1.3</span> <a href=#subsec:faq:components-blocked-by-others id=toc:subsec:faq:components-blocked-by-others>被其他工具禁用的應用程序組件是否保留在App\nManager中？</a></span><li><span><span class=toc-section-number>4.1.4</span> <a href=#subsec:faq:components-reblocked-in-am id=toc:subsec:faq:components-reblocked-in-am>被 App Manager\n禁用但同時也被其他工具禁用的組件會發生什麽？</a></span><li><span><span class=toc-section-number>4.1.5</span> <a href=#subsec:faq:what-is-instant-component-blocking id=toc:subsec:faq:what-is-instant-component-blocking>什麽是即時組件禁用？</a></span><li><span><span class=toc-section-number>4.1.6</span> <a href=#subsec:tracker-classes-versus-tracker-components id=toc:subsec:tracker-classes-versus-tracker-components>跟蹤器類與跟蹤器組件</a></span></ul><li><span><span class=toc-section-number>4.2</span> <a href=#sec:faq:adb-over-tcp id=toc:sec:faq:adb-over-tcp>ADB over TCP\n(經由TCP的ADB)</a></span><ul class=incremental><li><span><span class=toc-section-number>4.2.1</span> <a href=#subsec:faq:enable-adb-on-every-restart id=toc:subsec:faq:enable-adb-on-every-restart>我必須在每次重啟後啟用ADB\nover TCP嗎？</a></span><li><span><span class=toc-section-number>4.2.2</span> <a href=#subsec:faq:usb-debugging id=toc:subsec:faq:usb-debugging>無法啟用 USB\n調試，怎麽辦？</a></span><li><span><span class=toc-section-number>4.2.3</span> <a href=#subsec:faq:block-components-using-adb id=toc:subsec:faq:block-components-using-adb>我可以使用 ADB over TCP\n來禁用跟蹤器或任何其他應用程序組件嗎？</a></span><li><span><span class=toc-section-number>4.2.4</span> <a href=#subsec:faq:adb-features id=toc:subsec:faq:adb-features>哪些功能可以在ADB模式下使用？</a></span></ul><li><span><span class=toc-section-number>4.3</span> <a href=#sec:faq:miscellanea id=toc:sec:faq:miscellanea>雜項</a></span><ul class=incremental><li><span><span class=toc-section-number>4.3.1</span> <a href=#subsec:faq:no-root-no-harms id=toc:subsec:faq:no-root-no-harms>我不使用root/ADB，是否完全安全？</a></span><li><span><span class=toc-section-number>4.3.2</span> <a href=#subsec:faq:how-trackers-libs-updated id=toc:subsec:faq:how-trackers-libs-updated>跟蹤器和庫是如何更新的？</a></span><li><span><span class=toc-section-number>4.3.3</span> <a href=#subsec:faq:apks-deleted-after-installed id=toc:subsec:faq:apks-deleted-after-installed>Are APKs deleted after\ninstalled?</a></span><li><span><span class=toc-section-number>4.3.4</span> <a href=#subsec:faq:shizuku-support id=toc:subsec:faq:shizuku-support>對於 Shizuku\n有何計劃？</a></span><li><span><span class=toc-section-number>4.3.5</span> <a href=#subsec:faq:what-are-bloatware id=toc:subsec:faq:what-are-bloatware>什麽是預裝(bloatware)軟件以及如何刪除？</a></span></ul></ul><li><span><span class=toc-section-number>5</span> <a href=#ch:specifications id=toc:ch:specifications>語法</a></span><ul class=incremental><li><span><span class=toc-section-number>5.1</span> <a href=#sec:rules-specification id=toc:sec:rules-specification>規則語法</a></span><ul class=incremental><li><span><span class=toc-section-number>5.1.1</span> <a href=#背景介紹 id=toc:背景介紹>背景介紹</a></span><li><span><span class=toc-section-number>5.1.2</span> <a href=#規則文件格式 id=toc:規則文件格式>規則文件格式</a></span></ul></ul><li><span><span class=toc-section-number>6</span> <a href=#ch:changelogs id=toc:ch:changelogs>更新日志</a></span><ul class=incremental><li><span><span class=toc-section-number>6.1</span> <a href=#sec:v4.0.5-(445) id=toc:sec:v4.0.5-(445)>v4.0.5\n(445)</a></span><li><span><span class=toc-section-number>6.2</span> <a href=#sec:v4.0.4-(444) id=toc:sec:v4.0.4-(444)>v4.0.4\n(444)</a></span><li><span><span class=toc-section-number>6.3</span> <a href=#sec:v4.0.3-(443) id=toc:sec:v4.0.3-(443)>v4.0.3\n(443)</a></span><li><span><span class=toc-section-number>6.4</span> <a href=#sec:v4.0.2-(442) id=toc:sec:v4.0.2-(442)>v4.0.2\n(442)</a></span><li><span><span class=toc-section-number>6.5</span> <a href=#sec:v4.0.1-(441) id=toc:sec:v4.0.1-(441)>v4.0.1\n(441)</a></span><ul class=incremental><li><span><span class=toc-section-number>6.5.1</span> <a href=#overlay-management id=toc:overlay-management>Overlay\nmanagement</a></span><li><span><span class=toc-section-number>6.5.2</span> <a href=#unfreeze-option-in-activity-shortcuts id=toc:unfreeze-option-in-activity-shortcuts>Unfreeze option in\nactivity shortcuts</a></span><li><span><span class=toc-section-number>6.5.3</span> <a href=#market-like-url-support id=toc:market-like-url-support><code>market</code>-like URL\nsupport</a></span><li><span><span class=toc-section-number>6.5.4</span> <a href=#updated-color-codes id=toc:updated-color-codes>Updated color\ncodes</a></span><li><span><span class=toc-section-number>6.5.5</span> <a href=#others id=toc:others>Others</a></span></ul><li><span><span class=toc-section-number>6.6</span> <a href=#sec:v4.0.0-(440) id=toc:sec:v4.0.0-(440)>v4.0.0\n(440)</a></span><ul class=incremental><li><span><span class=toc-section-number>6.6.1</span> <a href=#new-logo id=toc:new-logo>New logo!</a></span><li><span><span class=toc-section-number>6.6.2</span> <a href=#android-14-and-15-support id=toc:android-14-and-15-support>Android 14 and 15\nsupport</a></span><li><span><span class=toc-section-number>6.6.3</span> <a href=#revamped-debloater id=toc:revamped-debloater>Revamped\ndebloater</a></span><li><span><span class=toc-section-number>6.6.4</span> <a href=#introducing-file-manager id=toc:introducing-file-manager>Introducing file\nmanager</a></span><li><span><span class=toc-section-number>6.6.5</span> <a href=#integrated-code-editor id=toc:integrated-code-editor>Integrated code editor</a></span><li><span><span class=toc-section-number>6.6.6</span> <a href=#history-of-operations id=toc:history-of-operations>History of\noperations</a></span><li><span><span class=toc-section-number>6.6.7</span> <a href=#per-app-freezing-and-more id=toc:per-app-freezing-and-more>Per-app freezing, and\nmore</a></span><li><span><span class=toc-section-number>6.6.8</span> <a href=#log-viewer-enhancements id=toc:log-viewer-enhancements>Log\nviewer enhancements</a></span><li><span><span class=toc-section-number>6.6.9</span> <a href=#launching-non-exported-activities id=toc:launching-non-exported-activities>Launching non-exported\nactivities</a></span><li><span><span class=toc-section-number>6.6.10</span> <a href=#new-tags-in-app-info-tab id=toc:new-tags-in-app-info-tab>New\ntags in App Info tab</a></span><li><span><span class=toc-section-number>6.6.11</span> <a href=#per-session-installer-options id=toc:per-session-installer-options>Per-session installer\noptions</a></span><li><span><span class=toc-section-number>6.6.12</span> <a href=#advanced-mode-of-operations-adb-enhancements id=toc:advanced-mode-of-operations-adb-enhancements>Advanced mode of\noperations, ADB enhancements, …</a></span><li><span><span class=toc-section-number>6.6.13</span> <a href=#data-usage-widget-and-more id=toc:data-usage-widget-and-more>Data usage widget, and\nmore</a></span><li><span><span class=toc-section-number>6.6.14</span> <a href=#others-1 id=toc:others-1>Others</a></span></ul><li><span><span class=toc-section-number>6.7</span> <a href=#sec:v3.1.0-(423) id=toc:sec:v3.1.0-(423)>v3.1.0\n(423)</a></span><ul class=incremental><li><span><span class=toc-section-number>6.7.1</span> <a href=#android-13-support id=toc:android-13-support>Android 13\nsupport</a></span><li><span><span class=toc-section-number>6.7.2</span> <a href=#introducing-freezeunfreeze id=toc:introducing-freezeunfreeze>Introducing\nfreeze/unfreeze</a></span><li><span><span class=toc-section-number>6.7.3</span> <a href=#export-app-list id=toc:export-app-list>Export app\nlist</a></span><li><span><span class=toc-section-number>6.7.4</span> <a href=#elliptic-curve-crypography-ecc id=toc:elliptic-curve-crypography-ecc>Elliptic Curve Crypography\n(ECC)</a></span><li><span><span class=toc-section-number>6.7.5</span> <a href=#new-languages id=toc:new-languages>New\nlanguages</a></span><li><span><span class=toc-section-number>6.7.6</span> <a href=#more-list-options id=toc:more-list-options>More list\noptions</a></span><li><span><span class=toc-section-number>6.7.7</span> <a href=#improved-handling-of-mode-of-operation id=toc:improved-handling-of-mode-of-operation>Improved handling of\nmode of operation</a></span><li><span><span class=toc-section-number>6.7.8</span> <a href=#handling-multiple-users id=toc:handling-multiple-users>Handling multiple users</a></span><li><span><span class=toc-section-number>6.7.9</span> <a href=#explorer-enhancements id=toc:explorer-enhancements>Explorer\nenhancements</a></span><li><span><span class=toc-section-number>6.7.10</span> <a href=#new-tag-wx id=toc:new-tag-wx>New tag: WX</a></span><li><span><span class=toc-section-number>6.7.11</span> <a href=#app-ops-management id=toc:app-ops-management>App ops\nmanagement</a></span><li><span><span class=toc-section-number>6.7.12</span> <a href=#batch-uninstallation id=toc:batch-uninstallation>Batch\nuninstallation</a></span><li><span><span class=toc-section-number>6.7.13</span> <a href=#running-apps id=toc:running-apps>Running apps</a></span><li><span><span class=toc-section-number>6.7.14</span> <a href=#interceptor id=toc:interceptor>Interceptor</a></span><li><span><span class=toc-section-number>6.7.15</span> <a href=#device-specific-changes id=toc:device-specific-changes>Device-specific changes</a></span><li><span><span class=toc-section-number>6.7.16</span> <a href=#others-2 id=toc:others-2>Others</a></span></ul><li><span><span class=toc-section-number>6.8</span> <a href=#sec:v3.0.0-(410) id=toc:sec:v3.0.0-(410)>v3.0.0\n(410)</a></span><ul class=incremental><li><span><span class=toc-section-number>6.8.1</span> <a href=#material-3-and-more id=toc:material-3-and-more>Material 3 and\nMore</a></span><li><span><span class=toc-section-number>6.8.2</span> <a href=#wireless-debugging id=toc:wireless-debugging>Wireless\nDebugging</a></span><li><span><span class=toc-section-number>6.8.3</span> <a href=#languages id=toc:languages>Languages</a></span><li><span><span class=toc-section-number>6.8.4</span> <a href=#introducing-app-explorer id=toc:introducing-app-explorer>Introducing App\nExplorer</a></span><li><span><span class=toc-section-number>6.8.5</span> <a href=#import-backups-from-other-applications id=toc:import-backups-from-other-applications>Import Backups from\nOther Applications</a></span><li><span><span class=toc-section-number>6.8.6</span> <a href=#virustotal id=toc:virustotal>VirusTotal</a></span><li><span><span class=toc-section-number>6.8.7</span> <a href=#trigger-profiles-from-the-automation-software id=toc:trigger-profiles-from-the-automation-software>Trigger Profiles\nfrom the Automation Software</a></span><li><span><span class=toc-section-number>6.8.8</span> <a href=#improved-application-installer id=toc:improved-application-installer>Improved Application\nInstaller</a></span><li><span><span class=toc-section-number>6.8.9</span> <a href=#component-blocking id=toc:component-blocking>Component\nBlocking</a></span><li><span><span class=toc-section-number>6.8.10</span> <a href=#advanced-searching id=toc:advanced-searching>Advanced\nSearching</a></span><li><span><span class=toc-section-number>6.8.11</span> <a href=#shared-libraries id=toc:shared-libraries>Shared\nLibraries</a></span><li><span><span class=toc-section-number>6.8.12</span> <a href=#make-the-best-use-of-interceptor id=toc:make-the-best-use-of-interceptor>Make the Best Use of\nInterceptor</a></span><li><span><span class=toc-section-number>6.8.13</span> <a href=#widget-screen-time id=toc:widget-screen-time>Widget: Screen\nTime</a></span><li><span><span class=toc-section-number>6.8.14</span> <a href=#widget-clear-cache id=toc:widget-clear-cache>Widget: Clear\nCache</a></span></ul><li><span><span class=toc-section-number>6.9</span> <a href=#sec:v2.6.0-(385) id=toc:sec:v2.6.0-(385)>v2.6.0\n(385)</a></span><ul class=incremental><li><span><span class=toc-section-number>6.9.1</span> <a href=#introducing-backups id=toc:introducing-backups>Introducing\nBackups</a></span><li><span><span class=toc-section-number>6.9.2</span> <a href=#introducing-log-viewer id=toc:introducing-log-viewer>Introducing Log Viewer</a></span><li><span><span class=toc-section-number>6.9.3</span> <a href=#lock-app-manager id=toc:lock-app-manager>Lock App\nManager</a></span><li><span><span class=toc-section-number>6.9.4</span> <a href=#extended-modes-for-app-ops id=toc:extended-modes-for-app-ops>Extended Modes for App\nOps</a></span><li><span><span class=toc-section-number>6.9.5</span> <a href=#new-batch-ops-add-to-profile id=toc:new-batch-ops-add-to-profile>New Batch Ops: Add to\nProfile</a></span><li><span><span class=toc-section-number>6.9.6</span> <a href=#app-info-improved id=toc:app-info-improved>App Info:\nImproved</a></span><li><span><span class=toc-section-number>6.9.7</span> <a href=#advanced-sort-and-filtering-options-in-the-main-page id=toc:advanced-sort-and-filtering-options-in-the-main-page>Advanced\nSort and Filtering Options in the Main Page</a></span><li><span><span class=toc-section-number>6.9.8</span> <a href=#about-this-device id=toc:about-this-device>About This\nDevice</a></span><li><span><span class=toc-section-number>6.9.9</span> <a href=#enabledisable-features id=toc:enabledisable-features>Enable/disable Features</a></span><li><span><span class=toc-section-number>6.9.10</span> <a href=#new-languages-1 id=toc:new-languages-1>New\nLanguages</a></span><li><span><span class=toc-section-number>6.9.11</span> <a href=#signing-the-apk-files id=toc:signing-the-apk-files>Signing the\nAPK Files</a></span><li><span><span class=toc-section-number>6.9.12</span> <a href=#new-extension-unapkm id=toc:new-extension-unapkm>New\nExtension: UnAPKM</a></span></ul><li><span><span class=toc-section-number>6.10</span> <a href=#sec:v2.5.20-(375) id=toc:sec:v2.5.20-(375)>v2.5.20\n(375)</a></span><ul class=incremental><li><span><span class=toc-section-number>6.10.1</span> <a href=#subsec:introducing-profiles id=toc:subsec:introducing-profiles>Introducing\nProfiles</a></span><li><span><span class=toc-section-number>6.10.2</span> <a href=#subsec:the-interceptor id=toc:subsec:the-interceptor>The\nInterceptor</a></span><li><span><span class=toc-section-number>6.10.3</span> <a href=#subsec:unapkm:-dedrm-the-apkm-files id=toc:subsec:unapkm:-dedrm-the-apkm-files>UnAPKM: DeDRM the APKM\nfiles</a></span><li><span><span class=toc-section-number>6.10.4</span> <a href=#subsec:multiple-user id=toc:subsec:multiple-user>Multiple\nuser</a></span><li><span><span class=toc-section-number>6.10.5</span> <a href=#vive-la-france id=toc:vive-la-france>Vive la\nFrance!</a></span><li><span><span class=toc-section-number>6.10.6</span> <a href=#report-crashes id=toc:report-crashes>Report\ncrashes</a></span><li><span><span class=toc-section-number>6.10.7</span> <a href=#android-11 id=toc:android-11>Android 11</a></span><li><span><span class=toc-section-number>6.10.8</span> <a href=#app-installer-improvements id=toc:app-installer-improvements>App Installer\nImprovements</a></span></ul><li><span><span class=toc-section-number>6.11</span> <a href=#v2.5.17-368 id=toc:v2.5.17-368>v2.5.17 (368)</a></span><ul class=incremental><li><span><span class=toc-section-number>6.11.1</span> <a href=#app-installer id=toc:app-installer>App\nInstaller</a></span><li><span><span class=toc-section-number>6.11.2</span> <a href=#scanner-replacement-for-exodus-page id=toc:scanner-replacement-for-exodus-page>Scanner: Replacement for\nExodus Page</a></span><li><span><span class=toc-section-number>6.11.3</span> <a href=#introducing-system-config id=toc:introducing-system-config>Introducing System\nConfig</a></span><li><span><span class=toc-section-number>6.11.4</span> <a href=#more-languages id=toc:more-languages>More\nLanguages</a></span><li><span><span class=toc-section-number>6.11.5</span> <a href=#app-info-tab id=toc:app-info-tab>App Info Tab</a></span><li><span><span class=toc-section-number>6.11.6</span> <a href=#navigation-improvements id=toc:navigation-improvements>Navigation Improvements</a></span><li><span><span class=toc-section-number>6.11.7</span> <a href=#running-apps-page id=toc:running-apps-page>Running Apps\nPage</a></span><li><span><span class=toc-section-number>6.11.8</span> <a href=#built-in-toybox id=toc:built-in-toybox>Built-in\nToybox</a></span><li><span><span class=toc-section-number>6.11.9</span> <a href=#component-blocker-improvements id=toc:component-blocker-improvements>Component Blocker\nImprovements</a></span><li><span><span class=toc-section-number>6.11.10</span> <a href=#improvements-in-the-app-details-page id=toc:improvements-in-the-app-details-page>Improvements in the App\nDetails Page</a></span><li><span><span class=toc-section-number>6.11.11</span> <a href=#app-manifest id=toc:app-manifest>App Manifest</a></span></ul><li><span><span class=toc-section-number>6.12</span> <a href=#v2.5.13-348 id=toc:v2.5.13-348>v2.5.13 (348)</a></span><ul class=incremental><li><span><span class=toc-section-number>6.12.1</span> <a href=#bundled-app-split-apk id=toc:bundled-app-split-apk>Bundled App\n(Split APK)</a></span><li><span><span class=toc-section-number>6.12.2</span> <a href=#direct-install-support id=toc:direct-install-support>Direct\nInstall Support</a></span><li><span><span class=toc-section-number>6.12.3</span> <a href=#remove-all-blocking-rules id=toc:remove-all-blocking-rules>Remove All Blocking\nRules</a></span><li><span><span class=toc-section-number>6.12.4</span> <a href=#app-ops id=toc:app-ops>App Ops</a></span><li><span><span class=toc-section-number>6.12.5</span> <a href=#enhanced-adb-support id=toc:enhanced-adb-support>Enhanced ADB\nSupport</a></span><li><span><span class=toc-section-number>6.12.6</span> <a href=#filtering-in-main-page id=toc:filtering-in-main-page>Filtering\nin Main Page</a></span><li><span><span class=toc-section-number>6.12.7</span> <a href=#apk-backupsharing id=toc:apk-backupsharing>Apk\nBackup/Sharing</a></span><li><span><span class=toc-section-number>6.12.8</span> <a href=#batch-ops id=toc:batch-ops>Batch Ops</a></span><li><span><span class=toc-section-number>6.12.9</span> <a href=#translations id=toc:translations>Translations</a></span><li><span><span class=toc-section-number>6.12.10</span> <a href=#app-data-backup id=toc:app-data-backup>App Data\nBackup</a></span></ul></ul><li><span><span class=toc-section-number>7</span> <a href=#ch:app-ops id=toc:ch:app-ops>App Ops</a></span><ul class=incremental><li><span><span class=toc-section-number>7.1</span> <a href=#sec:app-ops-background id=toc:sec:app-ops-background>Background</a></span><li><span><span class=toc-section-number>7.2</span> <a href=#sec:introduction-to-app-ops id=toc:sec:introduction-to-app-ops>Introduction to App\nOps</a></span><li><span><span class=toc-section-number>7.3</span> <a href=#sec:appopsmanager id=toc:sec:appopsmanager>AppOpsManager</a></span><ul class=incremental><li><span><span class=toc-section-number>7.3.1</span> <a href=#subsec:op-constants id=toc:subsec:op-constants><code>OP_*</code> Constants</a></span><li><span><span class=toc-section-number>7.3.2</span> <a href=#subsec:mode-constants id=toc:subsec:mode-constants><code>MODE_*</code>\nConstants</a></span><li><span><span class=toc-section-number>7.3.3</span> <a href=#subsec:package-ops id=toc:subsec:package-ops>PackageOps</a></span><li><span><span class=toc-section-number>7.3.4</span> <a href=#subsec:opentry id=toc:subsec:opentry>OpEntry</a></span><li><span><span class=toc-section-number>7.3.5</span> <a href=#subsec:usage id=toc:subsec:usage>Usage</a></span></ul><li><span><span class=toc-section-number>7.4</span> <a href=#sec:appopsservice id=toc:sec:appopsservice>AppOpsService</a></span><li><span><span class=toc-section-number>7.5</span> <a href=#sec:appops-xml id=toc:sec:appops-xml>appops.xml</a></span><li><span><span class=toc-section-number>7.6</span> <a href=#sec:appops-cli id=toc:sec:appops-cli>Command Line\nInterface</a></span></ul></ul></nav><div class=titlingpage><div class=center><p><img src=../images/icon.png style=width:1in alt=image><p><strong><span class=smallcaps>App Manager</span></strong><p><strong>用戶手冊</strong><p><em>v4.0.5</em><p>27 7月 2025<p>Copyright © 2020–2025 Muntashir Al-Islam<blockquote><p>明智而緩慢。他們跌跌撞撞地跑得很快。\n<span>—勞倫斯修士，<em>羅密歐與朱麗葉</em></span></blockquote></div></div><section id=ch:introduction class=level1 data-number=1><h1 data-number=1><span class=header-section-number>1</span> <a href=#toc:ch:introduction>簡介</a><a href=#ch:introduction class=anchor aria-hidden=true></a></h1><p>App Manager 是一個提供大量功能的高級的 Android\n軟件包管理器，因此，需要用戶手冊來幫助用戶正確使用。本文作為 App Manager\n的用戶手冊，旨在描述 App Manager 所提供的每一個功能。 本文也可以被認為是\nApp Manager 的 “官方” 指南，並指明 App Manager 的預期行為。翻譯可能有誤\n(原文為英文)。因此，每個有能力的用戶應該閱讀該文件的英文版本，以獲得最佳的體驗。\n此外還可能有其他非官方的或第三方的資源，如博客文章、視頻、聊天群組等。雖然這些資源可能對許多人有用，但它們可能不是針對最新版本。\n如果在App Manager中發現任何偏離本文檔的情況，應在 <a href=https://github.com/MuntashirAkon/AppManager/issues>App Manager\n問題追蹤</a>內反映。<section id=sec:terminologies class=level2 data-number=1.1><h2 data-number=1.1><span class=header-section-number>1.1</span> <a href=#toc:sec:terminologies>術語</a><a href=#sec:terminologies class=anchor aria-hidden=true></a></h2><ul class=incremental><li><p><strong>AM</strong> — App Manager<li><p><strong>Block/Unblock</strong> — Used for component blocking or\nunblocking. How components are blocked depends on the user\npreferences.<li><p><strong>IFW</strong> — Intent Firewall (意圖防火墻)<li><p><strong>Ops</strong> — operations (操作), e.g. app ops, batch\nops, 1-click ops<li><p><strong>SSAID</strong> — <code>Settings.Secure.ANDROID_ID</code>\n- 分配給每個應用的設備標識符 (Android\nOreo及以上版本)，由應用簽名與包<code>android</code>的SSAID組合生成的。因此，除非用戶選擇格式化設備，否則它保證對每個應用來說都是獨一無二的。它被廣泛用於跟蹤用戶。<li><p><strong>Tracker</strong> — Denotes tracker components throughout\nthe document and in App Manager except in the <a href=#sec:scanner-page>scanner page</a>. Trackers include libraries\nsuch as crash reporters, analytics, profiling, identification, ad,\nlocation, etc. Thus, they are not equal in functions. There is no\ndistinction or bias between open source and closed source libraries that\npromote tracking.</ul></section><section id=sec:supported-versions class=level2 data-number=1.2><h2 data-number=1.2><span class=header-section-number>1.2</span> <a href=#toc:sec:supported-versions>受支持的版本</a><a href=#sec:supported-versions class=anchor aria-hidden=true></a></h2><p>當前，支持的版本是v2.6.0（穩定版），v3.0.0（alpha和debug版）。先前版本的\nApp Manager 可能包含安全漏洞，不應繼續使用。</section><section id=sec:official-sources class=level2 data-number=1.3><h2 data-number=1.3><span class=header-section-number>1.3</span> <a href=#toc:sec:official-sources>官方來源</a><a href=#sec:official-sources class=anchor aria-hidden=true></a></h2><section id=subsec:binary-distribution-sources class=level3 data-number=1.3.1><h3 data-number=1.3.1><span class=header-section-number>1.3.1</span>\n<a href=#toc:subsec:binary-distribution-sources>二進制(可執行)分發來源</a><a href=#subsec:binary-distribution-sources class=anchor aria-hidden=true></a></h3><p>App Manager 通過以下渠道發布。 非官方來源可能分發 App Manager\n的修改版本，後果自負。<ol class=incremental><li><p>F-Droid <a href=#fn1 class=footnote-ref id=fnref1 role=doc-noteref><sup>1</sup></a><br><em>Link:</em> <a href=https://f-droid.org/packages/io.github.muntashirakon.AppManager class=uri>https://f-droid.org/packages/io.github.muntashirakon.AppManager</a><li><p>GitHub repository.<br><em>Normal releases:</em> <a href=https://github.com/MuntashirAkon/AppManager/releases class=uri>https://github.com/MuntashirAkon/AppManager/releases</a><br><em>Debug releases:</em> <a href=https://github.com/MuntashirAkon/AppManager/actions class=uri>https://github.com/MuntashirAkon/AppManager/actions</a><li><p>Telegram.<br><em>Normal releases:</em> <a href=https://t.me/AppManagerChannel class=uri>https://t.me/AppManagerChannel</a><br><em>Debug releases:</em> <a href=https://t.me/AppManagerDebug class=uri>https://t.me/AppManagerDebug</a></ol></section><section id=subsec:links-to-source-code class=level3 data-number=1.3.2><h3 data-number=1.3.2><span class=header-section-number>1.3.2</span>\n<a href=#toc:subsec:links-to-source-code>源碼鏈接</a><a href=#subsec:links-to-source-code class=anchor aria-hidden=true></a></h3><p>除了GitHub外其他都是鏡像鏈接。tags 應當始終是最新的，但 master\n分支不保證是 最新的。如果計劃 clone master 分支，請使用 GitHub\n鏈接而不是其他鏈接。<ol class=incremental><li><p>GitHub: <a href=https://github.com/MuntashirAkon/AppManager class=uri>https://github.com/MuntashirAkon/AppManager</a><li><p>Codeberg: <a href=https://codeberg.org/muntashir/AppManager class=uri>https://codeberg.org/muntashir/AppManager</a><li><p>GitLab: <a href=https://gitlab.com/muntashir/AppManager class=uri>https://gitlab.com/muntashir/AppManager</a><li><p>Riseup: <a href=https://0xacab.org/muntashir/AppManager class=uri>https://0xacab.org/muntashir/AppManager</a><li><p>sourcehut: <a href=https://git.sr.ht/~muntashir/AppManager class=uri>https://git.sr.ht/~muntashir/AppManager</a></ol></section><section id=subsec:translations class=level3 data-number=1.3.3><h3 data-number=1.3.3><span class=header-section-number>1.3.3</span>\n<a href=#toc:subsec:translations>翻譯</a><a href=#subsec:translations class=anchor aria-hidden=true></a></h3><p>App Manager 不接受直接通過PR/MR進行的翻譯。翻譯僅通過 Weblate\n進行自動化管理。 要加入翻譯團隊，請訪問 <a href=https://hosted.weblate.org/engage/app-manager/ class=uri>https://hosted.weblate.org/engage/app-manager/</a>。</section></section><section id=sec:contributing class=level2 data-number=1.4><h2 data-number=1.4><span class=header-section-number>1.4</span> <a href=#toc:sec:contributing>貢獻</a><a href=#sec:contributing class=anchor aria-hidden=true></a></h2><p>用戶可有通過多種方式做出貢獻，如創建有用 issues 、參加討論、\n改進文檔和翻譯，添加未被認可的庫或跟蹤器，\n審查源代碼以及報告安全漏洞。<section id=subsec:build-instructions class=level3 data-number=1.4.1><h3 data-number=1.4.1><span class=header-section-number>1.4.1</span>\n<a href=#toc:subsec:build-instructions>構建說明</a><a href=#subsec:build-instructions class=anchor aria-hidden=true></a></h3><p>在位於源碼根目錄下的BUILDING文件中可以獲得編譯指導。</section><section id=subsec:submitting-patches class=level3 data-number=1.4.2><h3 data-number=1.4.2><span class=header-section-number>1.4.2</span>\n<a href=#toc:subsec:submitting-patches>提交補丁</a><a href=#subsec:submitting-patches class=anchor aria-hidden=true></a></h3><p>除GitHub之外的倉庫目前被視為鏡像，在這些網站提交的 PR/MR 將不被接受.\n<a href=#fn2 class=footnote-ref id=fnref2 role=doc-noteref><sup>2</sup></a> 相反，patches (<code>.patch</code>\n文件)\n可以通過電子郵件附件提交。<em>請務必對Commits簽名(Signing-off)</em>\n更多信息請參見位於源碼根目錄下的CONTRIBUTING文件.<div class=\"amalert warning\"><p><strong><em>注意.</em></strong><p>在通過電子郵件提交補丁是，整個郵件對話在將來可能會被公開訪問.\n所以，請不要除了您的姓名和電子郵件地址之外，不要包含任何個人身份信息（PII）.</div></section></section><section id=sec:donation-&-funding class=level2 data-number=1.5><h2 data-number=1.5><span class=header-section-number>1.5</span> <a href=#toc:sec:donation-&-funding>捐贈 & 資助</a><a href=#sec:donation-&-funding class=anchor aria-hidden=true></a></h2><p><em>捐贈或購買並不是使用App Manager的必要條件.</em> 雖然 App Manager\n不支持任何任何內購, 但可以通過 Open Source Collective 向 App Manager\n的所有者發送捐贈.<p>Open Source Collective 是 Open Collective\n平台上的一個財政托管機構，以幫助開源項目管理他們的財務狀況。\n目前，它支持通過銀行賬戶、PayPal、信用卡或借記卡和加密貨幣發起捐贈.<p><em>Link:</em> <a href=https://opencollective.com/muntashir class=uri>https://opencollective.com/muntashir</a>.<p>通過發送捐款，發送者同意他們不應使用捐款作為籌碼來使作者優先考慮其所請求的功能.\n請求新功能不需要任何捐贈，且它們的優先級是按作者傾向排序.<p><em>App Manager 接受任何資助的提議</em>\n有興趣的組織的代表可以通過以下方式直接聯系聯系所有者: §<a href=#sec:contact data-reference-type=ref data-reference=sec:contact>1.6</a>.<p>In addition, the maintainers and contributors of this project DO NOT\nconsent to the creation, sale, or promotion of tokens, cryptocurrencies,\nNFTs, or any other financial instruments that claim to represent this\nproject, its code, or its community. Any such attempts are unauthorized\nand not affiliated with this project in any way.</section><section id=sec:contact class=level2 data-number=1.6><h2 data-number=1.6><span class=header-section-number>1.6</span> <a href=#toc:sec:contact>聯系我們</a><a href=#sec:contact class=anchor aria-hidden=true></a></h2><p>Muntashir Al-Islam<a href=#fn3 class=footnote-ref id=fnref3 role=doc-noteref><sup>3</sup></a><br>郵箱: <a href=mailto:muntashirakon@riseup.net>muntashirakon [at]\nriseup [dot] net</a><br>Key Fingerprint:\n<code>7bad37c2981e41f8f6abea7f58f0b4f26c346fce</code><br>GitHub: <a href=https://github.com/MuntashirAkon class=uri>https://github.com/MuntashirAkon</a><br>Twitter: <a href=https://twitter.com/Muntashir class=uri>https://twitter.com/Muntashir</a></section></section><section id=ch:pages class=level1 data-number=2><h1 data-number=2><span class=header-section-number>2</span> <a href=#toc:ch:pages>頁面</a><a href=#ch:pages class=anchor aria-hidden=true></a></h1><section id=sec:main-page class=level2 data-number=2.1><h2 data-number=2.1><span class=header-section-number>2.1</span> <a href=#toc:sec:main-page>主頁</a><a href=#sec:main-page class=anchor aria-hidden=true></a></h2><p>主頁面列出所有已安裝、已卸載和已備份的應用。\n單獨點擊任何已安裝的應用項目可打開相應的 <a href=#sec:app-details-page>應用詳情頁</a>。\n對於未安裝的系統應用，它會顯示一個 對話框提示，可以用來重新安裝該應用。\n使用列表選項中的 <a href=#par:main-page-sort>排序</a>\n，可以選擇應用列表的排序方式，退出應用後仍會保留排序方式。\n使用列表選項中的 <a href=#par:main-page-filter>過濾</a>，可以過濾列表選項。\n篩選也可以通過搜索欄進行過濾，並支持正則表達式。<figure id=fig:main_page_entry_info_labeled><figure><object data=../images/main_page_entry_info_labeled.svg type=image/svg+xml></object></figure><figcaption>Figure 1: 主頁面中的一個應用程序列表項</figcaption></figure><section id=subsec:batch-operations class=level3 data-number=2.1.1><h3 data-number=2.1.1><span class=header-section-number>2.1.1</span>\n<a href=#toc:subsec:batch-operations>批處理</a><a href=#subsec:batch-operations class=anchor aria-hidden=true></a></h3><p>批處理也可以在這個頁面內進行。\n多選模式可以由點擊任何應用圖標或長按列表中的任何一項進入。\n進入後，僅需單擊列表中的任何一項便可選中，而不是打開應用程序詳情頁。\n該模式下，批處理操作位於位於頁面底部的多選菜單，包括包括：<ul class=incremental><li><p>將選中應用添加到 <a href=#sec:profiles-page>配置</a><li><p><a href=#sec:backup-restore>備份、恢覆或刪除</a>應用程序<li><p>阻止應用中的追蹤器<li><p>清除應用數據或緩存<li><p>啟用/停用/強制停止/卸載應用程序<li><p>導出屏蔽規則<li><p>阻止應用的後台操作 (Android 7 及更高版本)<li><p>導出APK文件到 <code>AppManager/apks</code><li><p>設置<a href=#sec:net-policy>聯網規則</a></ul><div class=\"amalert tip\"><p><strong><em>無障礙.</em></strong><p>進入多選模式後，鍵盤或遙控器的左右鍵呼出多選菜單。</div></section><section id=subsec:main-colour-codes class=level3 data-number=2.1.2><h3 data-number=2.1.2><span class=header-section-number>2.1.2</span>\n<a href=#toc:subsec:main-colour-codes>顏色代碼含義</a><a href=#subsec:main-colour-codes class=anchor aria-hidden=true></a></h3><ul class=incremental><li><p><span class=colorbox style=background-color:#fceed1><span style=color:#000>淺灰橙(日間模式下)</span></span> / <span class=colorbox style=background-color:#091f36><span style=color:#fff>深藍(夜間模式下)</span></span> –\n多選模式下被選中的應用<li><p><span class=colorbox style=background-color:#ff8a80><span style=color:#000>淺紅(日間模式下)</span></span> / <span class=colorbox style=background-color:#4f1c14><span style=color:#fff>深紅\n(夜間模式下)</span></span> – 停用的應用<li><p><span class=colorbox style=background-color:#ff0><span style=color:#000>黃色星標</span></span> – 可調試的應用<li><p><span style=color:#e05915>橙色 <em>日期</em></span> –\n應用可讀取日志<li><p><span style=color:#e05915>橙色 <em>UID</em></span> – 用戶 ID\n在應用間被共享<li><p><span style=color:#e05915>橙色 <em>SDK</em></span> –\n使用明文網絡通信(如 HTTP)<li><p><span style=color:red>紅色 <em>包名</em></span> –\n應用禁止清除數據<li><p><span style=color:red>紅色<em>備份標識</em></span> –\n已卸載的應用存在一個或多個備份<li><p><span style=color:#e05915>橙色<em>備份標識</em></span> –\n備份過期, 如基本備份中包含已安裝的應用的舊版本<li><p><span style=color:#09868b>深藍綠色 <em>備份標識</em></span>\n– 備份在期, 如基本備份中包含已安裝應用的相同或更高版本<li><p><span style=color:#09868b>深藍綠色 <em>包名</em></span> –\n已強行停止運行的應用<li><p><span style=color:#09868b>深藍綠色 <em>版本</em></span> –\n不活躍的應用<li><p><span style=color:#f0f>紫紅</span> –\n常駐應用(一直運行的應用)</ul></section><section id=subsec:main-page-application-types class=level3 data-number=2.1.3><h3 data-number=2.1.3><span class=header-section-number>2.1.3</span>\n<a href=#toc:subsec:main-page-application-types>應用類型</a><a href=#subsec:main-page-application-types class=anchor aria-hidden=true></a></h3><p>一個應用程序可以是 <strong>用戶</strong> 或 <strong>系統</strong>\n應用，同時存在以下後綴:<ul class=incremental><li><p><code>X</code> – 支持多種架構<li><p><code>0</code> – 不含dex文件<li><p><code>°</code> – 已暫停應用<li><p><code>#</code> –\n應用程序請求系統分配一個大堆，即 大運行時內存<li><p><code>?</code> – 應用程序請求虛擬機處於安全模式。</ul></section><section id=subsec:main-page-version-info class=level3 data-number=2.1.4><h3 data-number=2.1.4><span class=header-section-number>2.1.4</span>\n<a href=#toc:subsec:main-page-version-info>版本信息</a><a href=#subsec:main-page-version-info class=anchor aria-hidden=true></a></h3><p>版本名稱有以下前綴:<ul class=incremental><li><p><code>_</code> – 沒有硬件加速（減慢應用中的過渡動畫）<li><p><code>~</code> – 僅測試模式<li><p><code>debug</code> – 可調試應用</ul></section><section id=subsec:main-page-options-menu class=level3 data-number=2.1.5><h3 data-number=2.1.5><span class=header-section-number>2.1.5</span>\n<a href=#toc:subsec:main-page-options-menu>選項菜單</a><a href=#subsec:main-page-options-menu class=anchor aria-hidden=true></a></h3><p>選項菜單提供了幾個選項，可用以對列出的應用程序進行排序和過濾，\n以及轉到 App Manager 內或外的不同頁面。<section id=subsubsec:main-list-options class=level4 data-number=2.1.5.1><h4 data-number=2.1.5.1><span class=header-section-number>2.1.5.1</span> 列表選項<a href=#subsubsec:main-list-options class=anchor aria-hidden=true></a></h4><p><strong>列表選項</strong>\n包含了對主頁面中的列表進行排序和過濾的選項。<section id=排序 class=level5 data-number=2.1.5.1.1><h5 data-number=2.1.5.1.1><span class=header-section-number>2.1.5.1.1</span> 排序<a href=#排序 class=anchor aria-hidden=true></a></h5><div id=par:main-page-sort></div><p>主頁面中列出的應用程序可以按照以下方式進行排序:<ul class=incremental><li><p><strong>用戶應用優先</strong> 用戶應用將優先展示<li><p><strong>應用標簽</strong> 根據應用標簽（也稱為\n<em>應用程序名稱</em>）升序排序。(默認選項)<li><p><strong>包名</strong> 根據包名升序排序<li><p><strong>最後更新</strong> 根據更新時間降序排序<li><p><strong>共享 user ID</strong> 根據共享 user ID升序排序<li><p><strong>目標 SDK</strong> 根據目標SDK升序排序<li><p><strong>簽名</strong> 根據簽名信息升序排序<li><p><strong>已停用優先</strong> 已停用將優先展示<li><p><strong>已阻止優先</strong>\n根據已阻止的應用組件數目降序排序<li><p><strong>已備份優先</strong> 已備份將優先展示<li><p><strong>追蹤器</strong> 根據追蹤器數目降序排序S<li><p><strong>最後操作</strong> 根據被App\nManager操作的應用時間降序排序</ul><p>此外，還有 <em>反轉</em> 選項，可以用來對列表進行反向排序。\n無論怎樣排序偏好，應用程序都是先按字母順序排序，以防止產生任何隨機排序結果.</section><section id=篩選 class=level5 data-number=2.1.5.1.2><h5 data-number=2.1.5.1.2><span class=header-section-number>2.1.5.1.2</span> 篩選<a href=#篩選 class=anchor aria-hidden=true></a></h5><div id=par:main-page-filter></div><p>主頁面中列出的應用可以通過以下方式進行過濾:<ul class=incremental><li><p><strong>用戶</strong> 僅用戶應用<li><p><strong>系統</strong> 僅系統應用<li><p><strong>停用</strong> 僅停用應用<li><p><strong>被阻止</strong> 僅被阻止組件的應用<li><p><strong>可打開</strong> 僅至少有一個Aactivity的應用<li><p><strong>有備份</strong> 僅有備份的應用<li><p><strong>無備份</strong> 僅沒有備份的應用<li><p><strong>運行中</strong> 僅正在運行的應用<li><p><strong>有分包</strong> 僅有分包(多Apk)應用<li><p><strong>已安裝</strong> 僅已安裝應用<li><p><strong>已卸載</strong> 僅已卸載應用</ul><p>與排序不同，它可以同時應用多個過濾選項，\n如，停用的用戶應用可以通過選擇 <em>用戶</em>和 <em>停用</em>列出，這對<a href=#subsec:batch-operations>批處理</a>特別有用，在這種情況下過濾用戶應用可能是必要的，以便安全地進行某些操作。\nUnlike sorting, it is possible to apply more than one filtering options\nat the same time. For example, the disabled user applications can be\nlisted by selecting both <em>User apps</em> and <em>Disabled apps</em>.\nThis can be particularly useful for <a href=#subsec:batch-operations>batch operations</a> where filtering the\nuser applications may be necessary to carry out certain operations\nsafely.</section><section id=配置文件名稱 class=level5 data-number=2.1.5.1.3><h5 data-number=2.1.5.1.3><span class=header-section-number>2.1.5.1.3</span> 配置文件名稱<a href=#配置文件名稱 class=anchor aria-hidden=true></a></h5><p>也可以列出僅存在於 <a href=#sec:profiles-page>profile</a>\n中的應用程序。這個可以\n對於在配置文件上執行某些操作（例如，卸載配置文件中的所有應用程序）很有用\n不能通過 <a href=#sec:profiles-page>Profiles page</a> 完成。</section></section><section id=說明 class=level4 data-number=2.1.5.2><h4 data-number=2.1.5.2><span class=header-section-number>2.1.5.2</span> 說明<a href=#說明 class=anchor aria-hidden=true></a></h4><p>點擊 <strong>指南</strong> 打開離線版的App Manager用戶手冊.\n它也可能打開在線版本如果如果相應的功能拆分<code>feat_docs</code>未安裝,\n或系統 WebView不存在.</section><section id=subsubsec:main:1-click-ops class=level4 data-number=2.1.5.3><h4 data-number=2.1.5.3><span class=header-section-number>2.1.5.3</span> 一鍵操作<a href=#subsubsec:main:1-click-ops class=anchor aria-hidden=true></a></h4><p><strong>1-Click Ops</strong> 代表單擊操作。它打開 <a href=#sec:1-click-ops-page>corresponding page</a> 在新活動中。</section><section id=應用使用情況 class=level4 data-number=2.1.5.4><h4 data-number=2.1.5.4><span class=header-section-number>2.1.5.4</span> 應用使用情況<a href=#應用使用情況 class=anchor aria-hidden=true></a></h4><p>應用程序使用統計，例如 <em>屏幕時間</em>、<em>數據使用量</em>（移動和\nWi-Fi）、 <em>單擊菜單中的 <strong>App Usage</strong>\n選項可以訪問打開應用程序的次數</em>。但是，它需要 <em>使用權限</em>\n權限。如果使用訪問功能被禁用，則不會列出此菜單項 <a href=#subsec:enable/disable-features>設置</a>。</section><section id=subsubsec:main:running-apps class=level4 data-number=2.1.5.5><h4 data-number=2.1.5.5><span class=header-section-number>2.1.5.5</span> 正在運行的應用<a href=#subsubsec:main:running-apps class=anchor aria-hidden=true></a></h4><p>此菜單項打開一個新頁面，其中顯示正在運行的應用程序或進程的列表。它還顯示\n當前內存和緩存（如果可用）使用情況。如果 App Manager 無法使用 root 或\nADB，它只會顯示自己 在最新版本的 Android\n中。正在運行的應用程序或進程也可以在 結果頁面。每個進程 ID (PID)\n的日誌也可以在 <a href=#subsubsec:log-viewer>log viewer</a> 中查看。\n此外，還可以通過單擊圖標或長按\n物品。正常單擊任何項目會打開一個對話框，其中顯示更詳細的信息。</section><section id=配置文件 class=level4 data-number=2.1.5.6><h4 data-number=2.1.5.6><span class=header-section-number>2.1.5.6</span> 配置文件<a href=#配置文件 class=anchor aria-hidden=true></a></h4><p>此菜單項打開 <a href=#sec:profiles-page>profiles\npage</a>。配置文件是一種配置經常使用的方法\n任務。它們也可以通過快捷方式調用。</section><section id=apk更新器 class=level4 data-number=2.1.5.7><h4 data-number=2.1.5.7><span class=header-section-number>2.1.5.7</span> APK更新器<a href=#apk更新器 class=anchor aria-hidden=true></a></h4><p>若系統中已安裝<a href=https://github.com/rumboalla/apkupdater>APK\nUpdater</a> ，則可通過此菜單項直接打開.\n若系統中不存在該應用，則該選項將被隱藏.</section><section id=termux-終端模擬器 class=level4 data-number=2.1.5.8><h4 data-number=2.1.5.8><span class=header-section-number>2.1.5.8</span> Termux 終端模擬器<a href=#termux-終端模擬器 class=anchor aria-hidden=true></a></h4><p>如果系統中已安裝<a href=https://github.com/termux/termux-app>Termux</a>\n，則可直接從此菜單項運行會話（或 新會話）.\n如果應用不存在，則此選項將被隱藏.</section><section id=debloater class=level4 data-number=2.1.5.9><h4 data-number=2.1.5.9><span class=header-section-number>2.1.5.9</span> Debloater<a href=#debloater class=anchor aria-hidden=true></a></h4><p>This menu item opens the debloater page that lists all the bloatware\navailable in the device and in App Manager. It also suggests alternative\napplications based on the criteria set by the <a href=https://github.com/MuntashirAkon/android-debloat-list>Android\nDebloat List</a> project.</section><section id=subsubsec:main:labs class=level4 data-number=2.1.5.10><h4 data-number=2.1.5.10><span class=header-section-number>2.1.5.10</span> Labs<a href=#subsubsec:main:labs class=anchor aria-hidden=true></a></h4><p>This menu item opens the labs page that lists all the additional\nfeatures. They include Log Viewer, System Config, Terminal, File Manager\n(as Files), UI Tracker, Interceptor, and Code Editor pages.</section><section id=設置 class=level4 data-number=2.1.5.11><h4 data-number=2.1.5.11><span class=header-section-number>2.1.5.11</span> 設置<a href=#設置 class=anchor aria-hidden=true></a></h4><p>此菜單項將打開本應用的 <a href=#sec:settings-page>設置</a>.</section></section></section><section id=sec:app-details-page class=level2 data-number=2.2><h2 data-number=2.2><span class=header-section-number>2.2</span> <a href=#toc:sec:app-details-page>應用程序詳情頁</a><a href=#sec:app-details-page class=anchor aria-hidden=true></a></h2><p><strong>應用詳情</strong> 頁面由 11\n個標簽頁組成。它描述了一個應用程序所能有的幾乎所有信息,\n包括其清單中的所有屬性、<a href=#ch:app-ops>應用操作</a>、簽名\n信息、庫等等。<section id=subsec:app-details-colour-codes class=level3 data-number=2.2.1><h3 data-number=2.2.1><span class=header-section-number>2.2.1</span>\n<a href=#toc:subsec:app-details-colour-codes>顏色代碼含義</a><a href=#subsec:app-details-colour-codes class=anchor aria-hidden=true></a></h3><p>本頁中使用的顏色列表及它們的含義：<ul class=incremental><li><p><span class=colorbox style=background-color:red><span style=color:#000>正紅 (日間)</span></span> / <span class=colorbox style=background-color:#790d0d><span style=color:#fff>深紅\n(夜間)</span></span> – 危險權限或, 被阻止的組件(使用App\nManager操作)<li><p><span class=colorbox style=background-color:#ff8a80><span style=color:#000>亮紅 (日間)</span></span> / <span class=colorbox style=background-color:#4f1c14><span style=color:#fff>緋紅\n(夜間)</span></span> – 被阻止的組件(其他應用操作)<div class=\"amalert tip\"><p><strong><em>注意.</em></strong><p>表示在 App Manager 之外禁用(阻止)的組件,\n標記為禁用(阻止)的組件並不意味著它被用戶禁用,它也可能是被系統禁用的,\n或者在其清單(Android-Manifest.xml)中被標記為禁用(阻止)。被停用的應用程序也會被系統（和App\nManager）視為禁用(阻止)。</div><li><p><span class=colorbox style=background-color:#ff8017><span style=color:#000>鮮橙 (日間)</span></span> / <span class=colorbox style=background-color:#ff801780><span style=color:#fff>深橙 (夜間)</span></span> – 追蹤器組件<li><p><span class=colorbox style=background-color:#ea80fc><span style=color:#000>亮紫 (日間)</span></span> / <span class=colorbox style=background-color:#431c5d><span style=color:#fff>深紫 (夜間)</span></span> – 正在運行的組件</ul></section><section id=subsec:app-info-tab class=level3 data-number=2.2.2><h3 data-number=2.2.2><span class=header-section-number>2.2.2</span>\n<a href=#toc:subsec:app-info-tab>應用信息</a><a href=#subsec:app-info-tab class=anchor aria-hidden=true></a></h3><p><strong>應用信息</strong> 選項卡包含關於一個應用程序的基本信息,\n許多操作可以在此標簽中執行.<section id=subsubsec:app-info-general-information class=level4 data-number=2.2.2.1><h4 data-number=2.2.2.1><span class=header-section-number>2.2.2.1</span> 基本信息<a href=#subsubsec:app-info-general-information class=anchor aria-hidden=true></a></h4><p>以下的列表與“應用信息”選項卡中列出的順序相同.<ul class=incremental><li><p><strong>應用圖標</strong>:\n應用圖標，若應用沒有圖標，則顯示系統默認圖標.\n可以點擊圖標，進行與剪貼板中的 SHA 或 MD5 進行 APK 簽名驗證.<li><p><strong>應用標簽</strong>: 應用程序名.<li><p><strong>包名</strong>: 應用程序包名，點擊覆制.<li><p><strong>版本</strong>: 版本分為兩部分: 第一部分稱\n<em>版本名(Version Name)</em>.\n格式各不相同，但常由多個以點分隔的整數組成. 第二部分稱 <em>版本號</em>.\n其被第一個括號括起來. 版本代碼是一個整數，用於 區分應用程序版本\n(因為機器無法讀取版本名). 簡言之,\n新版本的應用程序具有比舊版本更高的版本代碼. 如，如果 <code>123</code> 和\n<code>125</code>\n是一個應用程序的兩個版本代碼，我們可以說後者比前者更新(後者的版本代碼更高).\n在不同平台（移動、平板、桌面等）或架構（32/64 位、ARM 或\nIntel）上為同一版本提供不同 APK\n文件的應用程序，版本號可能會產生誤導，因為它們通常會為每個平台添加前綴\n.<li><p><strong>標簽</strong>: (也稱標簽雲)\n標簽包括應用程序最基本、最簡潔、有用的信息，如—<ul class=incremental><li><p><em>追蹤器信息</em> 應用程序中跟蹤器組件的數量 (如, <em>5\n個追蹤器</em>).\n如果跟蹤器未被阻止，則標記顏色顯示為橙色，如果跟蹤器在App\nManager中被阻止，則標記顏色顯示為深青色.\n單擊標簽會打開一個對話框，其包含跟蹤器組件列表，如果 App Manager\n具有足夠的權限，可以阻止或取消阻止這些組件.<li><p><em>應用類型</em>\n用戶應用或系統應用。系統應用程序的更新版本和通過 Magisk\n無系統安裝的應用也被認為是系統應用.<li><p><em>Split APK 信息</em> APK 中的拆分包數量，不包括基本 APK (e.g.,\n<em>5 分包</em>). 單擊標簽會打開一個對話框，其中包含分包 APK\n信息，例如類型和大小.<li><p><em>可調試</em> 應用可以通過\nADB調試.可調試應用可以享受常規應用無法使用的某些功能. 應用的數據可以通過\nADB 訪問 (如使用<code>run-as</code> 命令無需任何額外權限).<li><p><em>僅測試</em> 應用是僅測試應用程序.\n僅測試應用可以享受常規應用無法使用的某些功能. 應用的數據可以通過 ADB\n訪問 (如使用<code>run-as</code> 命令無需任何額外權限).<li><p><em>大(堆/Heap)內存</em> 應用將請求較大的堆內存, 即需要更多內存\n(RAM) 空間用於動態分配. 是否為應用程序分配大空間仍由操作系統決定.\n如，App Manager 請求較大的堆大小，因為它在 Android 8 之前需要在掃描的\nAPK 時將整個 APK 加載到內存中App.<li><p><em>無代碼</em> 該應用無任何相關代碼,如不含Dex文件.\n在某些系統應用中，實際代碼可能位於其他位置.<li><p><em>運行中</em> 應用的一項或多項服務正在後台運行.\n單擊標簽將打開一個對話框，其中包含正在運行的服務列表.\n如果啟用了日志查看器功能，單擊任何服務會將在日志查看器中它.<li><p><em>已停止</em> 應用被強制停止.\n這可能不會阻止它以後自動啟動.<li><p><em>已禁用</em> 應用被禁用 (在啟動器無圖標).<li><p><em>已掛起</em> 表示應用程序已掛起\n(在啟動器中顯示為灰色).<li><p><em>被隱藏</em> 示應用程序是隱藏的 (在啟動器無圖標).<li><p><em>MagiskHide</em> MagiskHide 已啟用.\n單擊該標簽會打開一個對話框，其中包含應用程序中可以從 MagiskHide\n添加或刪除的進程列表.<li><p><em>MagiskDenyList</em> 該應用程序存在於 MagiskDenyList 中.\n單擊標簽會打開一個對話框，其中包含應用程序中可以從 MagiskDenyList\n列表中添加或刪除的進程列表.<li><p><em>密匙庫</em> 應用在 Android KeyStore 中存有項目.\n單擊將打開一個對話框，其中包含屬於該應用程序的所有 KeyStore\n文件.<li><p><em>備份</em> 應用至少使用 App Manager 備份過一次.\n單擊標簽會打開一個對話框，其包含所有可用的備份以及元數據.<li><p><em>不進行電池優化</em> 電池優化對應用不生效.\n可以通過單擊標簽重新啟用電池優化.<li><p><a href=#sec:net-policy><em>聯網策略</em></a>\n為應用配置聯網策略（如，後台數據使用）.\n單擊標簽會顯示一個對話框，其中包含系統支持的策略.<li><p><a href=#sec:terminologies><em>SSAID</em></a>\n點擊打開一個對話框，其中包含分配給應用程序的當前\nSSAID。若需要可以重置/重新生成 SSAID.<li><p><em>SAF</em>\n表示應用已被授權訪問一個或多個存儲位置或文件，即獲得由存儲訪問框架 (SAF)\n的 URI. 單擊打開一個對話框，其中包含授予的 URI.<li><p><em>被 Google Play 簽名</em> 表示應用程序可能由 Google\n簽名.</ul><li><p><strong>水平滾動操作面板</strong>\n一個操作面板，由可以對應用執行的各種操作組成,\n有關可用操作的完整列表，請參閱§<a href=#subsubsec:horizontal-action-panel data-reference-type=ref data-reference=subsubsec:horizontal-action-panel>2.2.2.3</a>.<li><p><strong>路徑與目錄</strong>: 應用有關路徑的各種信息，包括\n<em>應用目錄</em> (where the APK files reside), <em>數據目錄</em>\n(internal, device protected and externals), <em>應用分包目錄</em> (along\nwith the split names), and <em>本機原生 JNI 庫</em> (如果有). JNI\n庫用於調用通常用 C/C++ 編寫的本機原生代碼,\n使用本機原生庫可以使應用程序運行得更快或幫助應用程序使用使用非 Java\n語言編寫的第三方庫，同大多數遊戲中一樣.\n通過單擊每個目錄項右側的啟動圖標,\n可以通過第三方文件管理器打開目錄，前提是它們支持並獲得必要的權限.<li><p><strong>數據使用</strong>: 操作系統報告的應用程序使用的數據量.\n根據 Android 版本，這可能需要廣泛的權限，包括 <em>訪問應用使用情況</em>\n和 <em>電話</em> 權限.<li><p><strong>存儲與緩存</strong>: 顯示有關應用程序大小（APK\n文件、優化文件）、數據和緩存的信息。\n在舊設備中，還會顯示外部數據、緩存、媒體和 OBB 文件夾的大小.\n如果在較新的設備中未授予 <em>訪問應用使用情況s</em>\n權限，此部分將隱藏.<li><p><strong>更多信息</strong> 例如–<ul class=incremental><li><p><strong>SDK</strong> 顯示與 Android SDK 相關的信息.\n存在兩個（舊設備只有一個）值: <em>最高</em> 目標 SDK 與<em>最低</em>\n最低SDK (後者不適用於舊設備). 最佳實踐是使用平台當前支持的最大 SDK\n的應用程序，以確保應用程序未在兼容模式下運行(以便使用隱私規避功能). SDK\n已稱為 <strong>等級(API Level)</strong>.<div class=seealso-inline><p><em>See also: <span><a href=https://en.wikipedia.org/wiki/Android_version_history#Overview>Android\nVersion History</a></span></em></div><li><p><strong>標志位(Flags)</strong>: 構建應用程序時使用的應用標志,\n有關標志的完整列表及其作用, 請見<a href=https://developer.android.com/reference/android/content/pm/ApplicationInfo#flags>official\ndocumentation</a>.<li><p><strong>安裝日期</strong>: 首次安裝應用的日期.<li><p><strong>更新日期</strong>: 上次更新應用程序的日期.\n如果應用程序尚未更新，這與 <em>安裝日期</em> 相同.<li><p><strong>安裝器</strong>: 安裝此應用的應用.\n並非所有應用程序都提供包管理器用來注冊安裝程序應用程序的信息.\n因此，這個值不應被視為理所當然。<li><p><strong>User ID</strong>: Android系統給應用設置的唯一用戶ID.\n對於共享應用，相同的用戶 ID 被分配給具有相同 <em>Shared User ID</em>\n的多個應用程序.<li><p><strong>Shared User ID</strong>: 適用於一起共享ID的應用.\n共享應用必須具有相同的 <a href=#subsec:signatures-tab>簽名</a>.<li><p><strong>首選ABI</strong>: 此平台為此應用程序支持的架構。<li><p><strong>Zygote preload name</strong>:\n負責預加載應用程序代碼和在所有使用應用程序 zygote\n的隔離服務之間共享的數據.<li><p><strong>隱藏 API 使用策略</strong>: 從 Android 9 開始，Android\nFramework 中的許多方法和類第三方應用程序無法通過隱藏 API 強制訪問.\n存在以下選項:<ul class=incremental><li><p><em>默認(Default</em>: 基於應用的類型。\n對於系統應用程序，它應該被禁用，而對於其他應用，它應該被強制執行.<li><p><em>無或關閉(None/disabled)</em>: 該應用可以完全訪問隱藏的\nAPI，就像在 Android 9 之前一樣.<li><p><em>警告(Warn)</em>: 與上面相同，除了每次應用程序訪問隱藏 API\n時都會記錄警告. 這一般未使用的.<li><p><em>強制(Enforce)</em>: 應用無法訪問隱藏的\nAPI，無論是深灰名單還是黑名單，或者兩者都無法訪問. 這是 Android 9\n及更高版本中第三方應用程序的默認選項，除非該應用程序被 OEM\n或供應商列入白名單.<div class=\"amalert warning\"><p><strong><em>Warning.</em></strong><p>隱藏 API 訪問限制策略在 Android 中沒有正確實現，應用程序可以繞過它.\n因此，不應信任此值.</div></ul><li><p><strong>SELinux</strong>: 操作系統通過 SELinux 設置的強制訪問控制\n(MAC) 策略.<li><p><strong>主活動</strong>: 應用的主要入口點. 這僅在應用程序具有 <a href=#subsubsec:activities>活動</a>\n並且其中任何一個都可以從啟動器中打開時顯示.\n右側還有一個啟動按鈕，可用於啟動此活動.</ul></ul></section><section id=subsubsec:tags class=level4 data-number=2.2.2.2><h4 data-number=2.2.2.2><span class=header-section-number>2.2.2.2</span> Tags<a href=#subsubsec:tags class=anchor aria-hidden=true></a></h4><ul class=incremental><li><p><strong>Tracker info.</strong> Number of tracker components in\nthe application (e.g., <em>5 trackers</em>) The colour of the tag\nappears orange if the trackers are unblocked and dark cyan if they are\nblocked in App Manager. Clicking on the tag opens a dialog containing\nthe list of tracker components which can also be blocked or unblocked\nprovided App Manager has sufficient privileges.<li><p><strong>Application type.</strong> User application or system\napplication. For a system application, it displays whether the\napplication is an updated version of the system application or the\napplication is installed systemless-ly via Magisk.<li><p><strong>Split APK info.</strong> Number of splits in the APK\nexcluding the base APK (e.g., <em>5 splits</em>). Clicking on the tag\nopens a dialog containing a few additional information, such as name,\ntype, and size.<li><p><strong>Debuggable.</strong> The application can be debugged over\nADB. Debuggable applications can enjoy certain functions unavailable to\na regular application. The data of the application might be accessible\nvia ADB (e.g. using <code>run-as</code> command) without any additional\npermissions.<li><p><strong>Test only.</strong> The application is a test-only\napplication. Test-only applications can enjoy certain functions\nunavailable to a regular application. The data of the application might\nbe accessible via ADB (e.g. using <code>run-as</code> command) without\nany additional permissions.<li><p><strong>No code.</strong> The application does not have any code\nassociated with it i.e., DEX files aren’t present. In some system\napplications, the actual code might be located in another\nplace.<li><p><strong>Large heap.</strong> The application has requested large\nheap size i.e., more space in memory (RAM) is requested for dynamic\nallocation. It is still up to the operating system to decide whether to\nallocate large space for the application. App Manager, for example,\nrequests large heap size because it needs to load an entire APK into\nmemory while scanning an APK.<li><p><strong>Open links.</strong> The application may open certain\nlinks from any applications. If the application can open any links by\ndefault, the color of the tag would be red, dark cyan if otherwise.\nClicking on the tag opens a dialog with the supported hosts or domains\nlisted. In Android 12 onwards, it displays an option to enable or\ndisable opening links by default provided App Manager has sufficient\npermissions. Otherwise, it displays an option to open the system\nsettings page for the application.<li><p><strong>Running.</strong> One or more services of the application\nis currently running in the background. Clicking on the tag opens a\ndialog containing the list of running services. Clicking on any services\nopens the log viewer with default filter set to the UID associated with\nthe service (which can be different from the UID of the application if\nit is running in a separate or isolated process) provided the log viewer\nfeature is enabled. There’s also an option to force-stop the\napplication.<li><p><strong>Stopped.</strong> The application is force stopped. This\nmay not prevent it from running automatically later.<li><p><strong>Disabled.</strong> Denotes that the application is\ndisabled (hidden from the launcher).<li><p><strong>Suspended.</strong> Denotes that the application is\nsuspended (grayed out in the launcher).<li><p><strong>Hidden.</strong> Denotes that the application is hidden\n(hidden from the launcher).<li><p><strong>MagiskHide.</strong> MagiskHide is enabled for the\napplication. Clicking on the tag opens a dialog containing the list of\nprocess names within the application that can be added to or removed\nfrom the MagiskHide list.<li><p><strong>MagiskDenyList.</strong> The application is present in\nMagisk DenyList. Clicking on the tag opens a dialog containing the list\nof process names within the application that can be added to or removed\nfrom Magisk DenyList.<li><p><strong>WX.</strong> The application violates the “W^X policy”\nand is capable of writing and executing in the same directory or in the\nsame portion of memory. This allows the execution of arbitrary\nexecutables either by the modification of executables embedded within\nthe application or by downloading them from the Internet.<br><div class=seealso-inline><p><em>See also: <span><a href=https://en.wikipedia.org/wiki/W%5EX>W^X\nin Wikipedia</a></span></em></div><li><p><strong>Bloatware.</strong> The application may be a known\nbloatware. Clicking on the tag opens a dialog containing detailed\ninformation in addition to suggestions (if available).<li><p><strong>KeyStore.</strong> The application has items in the\nAndroid KeyStore. Clicking on the tag opens a dialog containing all the\nKeyStore files that belong to the application.<li><p><strong>Backup.</strong> The application was backed up using App\nManager at least once. Clicking on the tag opens a dialog containing all\nthe available backups along with metadata.<li><p><strong>No battery optimisation.</strong> Battery optimisation is\ndisabled for the application. It is possible to re-enable battery\noptimisation by clicking on the tag.<li><p><strong>Sensors disabled.</strong> Sensors are disabled for the\napplication. Sensors are disabled for most applications by\ndefault.<li><p><a href=#sec:net-policy><strong>Net policy.</strong></a>\nNetwork policy (e.g., background data usage) is configured for the\napplication. Clicking on the tag displays a dialog containing the\nsupported policies for the platform along with the options to configure\nthem.<li><p><a href=#sec:terminologies><strong>SSAID.</strong></a> Clicking\non the tag opens a dialog containing the current SSAID assigned to the\napplication. It is also possible to reset/regenerate the SSAID if\nneeded.<li><p><strong>SAF.</strong> Denotes that the application has been\ngranted to access one or more storage locations or files i.e. URIs via\nStorage Access Framework (SAF). Clicking on the tag opens a dialog\ncontaining the list of granted URIs.<li><p><strong>Play App Signing.</strong> Indicates that the application\nmight be signed by Google.<li><p><strong>Xposed.</strong> Indicates that the application may be an\nXposed module. Clicking on the tag displays a dialog with additional\ninformation.<li><p><strong>Static Shared Library.</strong> Denotes that the\napplication serves as a static shared library for one or more\napplications. Clicking on the tag opens a dialog containing a list of\ninstalled versions of the library along with an option to uninstall\nthem.<div class=\"amalert tip\"><p><strong><em>Notice.</em></strong><p>The trichrome library (supplied by Google Chrome, Vanadium or similar\nprojects) is currently the only known static shared library on\nAndroid.</div></ul></section><section id=subsubsec:horizontal-action-panel class=level4 data-number=2.2.2.3><h4 data-number=2.2.2.3><span class=header-section-number>2.2.2.3</span> 水平操作面板<a href=#subsubsec:horizontal-action-panel class=anchor aria-hidden=true></a></h4><p>如上節所述,水平滾動操作面板由各種與應用相關的操作組成, 如 -<ul class=incremental><li><p><strong>啟動</strong>: 啟動應用. 前提是要有一個可啟動<a href=#subsubsec:activities>活動</a>.<li><p><strong>禁用</strong>: 停用應用.\n若應用已被禁用或用戶沒有足夠的權限，則不會顯示該按鈕.\n禁用應用後，將從應用程序列表中隱藏，應用的快捷方式也可能被刪除.\n只能通過App Manager或任何其他支工具重新啟用該應用.\nAndroid設置中沒有任何選項可以啟用禁用的用戶應用.<li><p><strong>卸載</strong>: 卸載應用<li><p><strong>啟用</strong>: 啟用應用.\n若應用已啟用或用戶沒有足夠的權限，則不會顯示該按鈕.<li><p><strong>強制停止</strong>: 強制停止應用.<li><p><strong>清除數據</strong>: 清除應用數據.\n清除包括存儲在應用內部和（僅Android 10\n以上）外部目錄中的任何應用數據，包括帳戶（如果由應用設置）、緩存等.\n例如，清除 App Manager\n數據將會刪除所有保存的規則（但不會清除已阻止組件），因此你應該檢查備份你的規則文件。若用戶沒有足夠的權限，則不會顯示此按鈕.<li><p><strong>清除緩存</strong>: 清除應用緩存.\n沒有任何原生方法可以清除特定應用程序的緩存，因此，需要root權限才能清除應用程序內部存儲中的緩存.<li><p><strong>安裝</strong>: 通過第三方應用安裝應用.\n此按鈕僅在應用尚未安裝時顯示.<li><p><strong>What’s New</strong>: 若外部應用已安裝，則會顯示此按鈕.\n單擊此按鈕將顯示一個對話框，將以版本控制方式，顯示打開的版本和安裝的版本之間的差異.\n包括: <em>版本</em>, <em>追蹤器</em>, <em>權限</em>, <em>組件</em>,\n<em>簽名</em> (校驗值改變 ), <em>特性</em>, <em>共享庫</em> 與\n<em>SDK</em>.<li><p><strong>更新</strong>:\n若應用的版本號高於已安裝的應用，則會顯示.<li><p><strong>重裝</strong>:\n若應用與已安裝的應用具有相同的版本號，則會顯示.<li><p><strong>降級</strong>:\n若應用的版本號低於已安裝的應用，則會顯示.<li><p><strong>應用清單(Manifest)</strong>:\n單擊將在單獨的頁面中顯示應用清單文件.\n可以使用對應切換按鈕（位於右上方）開啟自動換行，也可以使用保存按鈕保存到存儲器.<li><p><strong>掃描器</strong>: 掃描應用以列出潛在的跟蹤器和庫.\n若可用，它還會使用VirusTotal掃描文件.<br><div class=seealso-inline><p><em>See also: <span><a href=#sec:scanner-page>掃描器頁面</a></span></em></div><li><p><strong>共享首選項</strong>:\n顯示應用程序使用的共享首選項(Shared-Preferences)列表.\n單擊列表中的首選項將打開<a href=#sec:shared-preferences-editor-page>共享首選項編輯器</a>.\n若用戶沒有足夠的權限，則不會顯示此按鈕.<li><p><strong>數據庫</strong>: 將顯示應用程序使用的數據庫列表.\n若用戶沒有足夠的權限，則不會顯示此按鈕.<li><p><strong>F-Droid</strong>: 在你常用的<em>F-Droid</em>\n客戶端中打開該應用.<li><p><strong>Store</strong>: 在 <em>Aurora Store</em>打開該應用.\n僅在<em>Aurora Store</em>後顯示.</ul></section><section id=subsubsec:app-info-options-menu class=level4 data-number=2.2.2.4><h4 data-number=2.2.2.4><span class=header-section-number>2.2.2.4</span> 選項菜單<a href=#subsubsec:app-info-options-menu class=anchor aria-hidden=true></a></h4><p>選項菜單位於頁面的右上角, 下面給出了對現有選項的完整描述:<ul class=incremental><li><p><strong>分享</strong>: 共享按鈕可用於共享 APK\n或(如果應用程序有多個拆分) <em>APKS</em>.<li><p><strong>刷新</strong>: 刷新應用信息選項卡.<li><p><strong>在設置中查看</strong>: 在 Android\n設置中打開應用.<li><p><strong>備份/恢覆</strong>: 打開備份/恢覆對話框.<li><p><strong>導出屏蔽規則</strong>: 導出應用配置規則.<li><p><strong>在 Termux 中打開</strong>: 在 Termux 中打開應用. 實際以\n<code>su - user_id</code> 命令運行且該 <code>用戶ID</code>\n為應用的(內核)用戶 ID (參見§<a href=#subsubsec:app-info-general-information data-reference-type=ref data-reference=subsubsec:app-info-general-information>2.2.2.1</a>).\n此選項僅適用於 Root 用戶. 請參閱 §<a href=#subsubsec:config-termux data-reference-type=ref data-reference=subsubsec:config-termux>2.2.2.5</a> 以了解如何配置\nTermux 以運行來自第三方應用的命令.<li><p><strong>在 Termux 中運行</strong>: 在Termux中通過\n<code>run-as package_name</code> 打開應用.\n此選項僅對可調式應用有效並適用於 Root 與 Adb 用戶. 請參閱 §<a href=#subsubsec:config-termux data-reference-type=ref data-reference=subsubsec:config-termux>2.2.2.5</a> 以了解如何配置\nTermux 以運行來自第三方應用的命令.<li><p><strong>MagiskHide</strong>:\n打開一個對話框，其中包含應用程序中可以從 MagiskHide\n列表中添加或刪除的進程列表.<li><p><strong>MagiskDenyList</strong>:\n打開一個對話框，其中包含應用程序中可以從 MagiskDenyList\n添加或刪除的進程列表.<li><p><strong>電池優化</strong>: 啟用/禁用電池優化.<li><p><a href=#sec:net-policy><strong>聯網策略</strong></a>:\n配置應用的聯網策略（如後台數據使用） .<li><p><strong>導出圖標</strong>:\n提取應用圖標並將其保存至共享存儲.<li><p><strong>添加配置</strong>: 應用程序添加到已配置的 <a href=#sec:profile-page>配置文件</a>.</ul></section><section id=subsubsec:config-termux class=level4 data-number=2.2.2.5><h4 data-number=2.2.2.5><span class=header-section-number>2.2.2.5</span> 配置 Termux<a href=#subsubsec:config-termux class=anchor aria-hidden=true></a></h4><p>默認情況下，Termux\n不允許運行來自第三方應用的命令。要使用此選項，請使用 Termux v0.96\n以上版本，並且必須在 <code>~/.termux/termux.properties</code> 中添加\n<code>allow-external-apps=true</code>。<div class=\"amalert tip\"><p><strong><em>Info.</em></strong><p>啟用此選項不會削弱Termux的安全性。第三方應用仍然需要取得用戶允許才能在Termux中運行任意命令。</div></section></section><section id=subsec:component-tabs class=level3 data-number=2.2.3><h3 data-number=2.2.3><span class=header-section-number>2.2.3</span>\n<a href=#toc:subsec:component-tabs>組件選項卡</a><a href=#subsec:component-tabs class=anchor aria-hidden=true></a></h3><p><strong>活動(Activities)</strong>、<strong>服務(Services)</strong>、<strong>廣播接收器(Receivers)</strong>和\n<strong>內容提供者(Providers)</strong> 統稱為應用程序組件.\n它們共享在許多相似特征，如，它們都有一個 <em>名稱</em>、一個\n<em>標簽</em>、一個 <em>圖標</em> 並且通過 <em>意圖(Intent)</em> 執行.\n應用程序組件是應用的本構造，必須在應用程序清單中聲明.\n應用程序清單是存儲應用程序特定元數據的文件，Android\n通過讀取元數據來處理應用。<p>這些選項卡中使用的顏色在 §<a href=#subsec:app-details-colour-codes data-reference-type=ref data-reference=subsec:app-details-colour-codes>2.2.1</a>\n中進行了解釋。也可以在彈出菜單對列表進行排序.<section id=subsubsec:activities class=level4 data-number=2.2.3.1><h4 data-number=2.2.3.1><span class=header-section-number>2.2.3.1</span> 活動 (Activity)<a href=#subsubsec:activities class=anchor aria-hidden=true></a></h4><p><strong>Activity</strong> 是可以由 Android\n唯一標識的窗口或頁面(如<em>主頁</em> 和 <em>應用詳情頁</em> 是兩個活動).\n每個活動可以有多個 UI 組件，稱為 <em>部件(widgets)</em> 或\n<em>碎片(fragments)</em>，每個組件都可以嵌套或放置在彼此之上.\n開發人員還可以選擇使用名為<em>意圖過濾器(intent\nfilters)</em>選擇打開外部文件、鏈接等.\n如當使用文件管理器打開文件時，文件管理器或操作系統通過 PackageManager\n掃描意圖過濾器以查找能夠打開文件的活動，並用其打開文件.<p>標記<em>exportable</em> 的活動通常可以由任何第三方應用程序打開.\n有些活動需要權限，如果是這種情況，只有具有這些權限的應用程序才能打開. 在\n<em>活動</em> 選項卡中，可以通過 <strong>啟動</strong> 按鈕啟動，\n若有必要可提供額外信息，如意圖(Intent)的 extras、data或Action. 長按\n<strong>啟動</strong> 按鈕會打開提供此類功能的 <a href=#sec:interceptor-page>Activity Interceptor</a> 頁面.<div class=\"amalert tip\"><p><strong><em>Notice.</em></strong><p>如果您無法打開任何活動，則很可能它具有某些未滿足的依賴項目，例如<em>應用詳情頁</em>\n，由於其至少需要提供一包名.\n由於無法機械式推斷這些依賴關系，因此默認情況下可能無法通過 App Manager\n打開這些活動.</div><p>也可以通過 <strong>創建快捷方式</strong> 按鈕來創建活動的快捷方式<div class=\"amalert danger\"><p><strong><em>Caution.</em></strong><p>如果您卸載App Manager，應用管理器創建的所有快捷方式都將丟失.</div></section><section id=subsubsec:details:servcies class=level4 data-number=2.2.3.2><h4 data-number=2.2.3.2><span class=header-section-number>2.2.3.2</span> 服務 (Services)<a href=#subsubsec:details:servcies class=anchor aria-hidden=true></a></h4><p>與用戶可以看到的 <a href=#subsubsec:activities>activities</a>\n不同，<strong>Services</strong> 處理後台任務。例如， 如果您使用手機的\nInternet 瀏覽器從 Internet 下載視頻，則 Internet 瀏覽器正在使用\n<em>前台服務</em> 下載內容。<p>當一個活動被關閉或從 <em>Recents</em>\n部分中刪除時，它可能會立即被銷毀，具體取決於\n許多因素，例如手機有多少可用內存。但如果需要，服務可以無限期地運行。如果更多\n服務在後台運行，由於內存和/或處理能力不足，手機可能會變慢，以及\n手機的電池會更快耗盡。較新的 Android 版本啟用了電池優化功能\n默認情況下適用於所有應用程序。啟用此功能後，系統可以隨機終止任何服務。然而，\n前台服務（即使用固定通知運行的服務，例如音樂播放器）通常不是\n除非系統資源不足（內存、電池等），否則終止。供應商特定的庫存 ROM\n可以提供更多 積極的優化。例如，MIUI 有一個非常激進的優化功能，稱為\n<em>MIUI 優化</em>。<p>活動和服務都在同一個 <a href=https://stackoverflow.com/questions/7597742>looper</a> 中運行\n主循環器，這意味著服務並沒有真正在後台運行。開發人員的任務是\n確保這一點。應用程序如何與服務通信？它用 <a href=#subsubsec:app-details-receivers>broadcast receiver</a> 或\nBinder。</section><section id=subsubsec:app-details-receivers class=level4 data-number=2.2.3.3><h4 data-number=2.2.3.3><span class=header-section-number>2.2.3.3</span> (廣播)接收器\n((Broadcast)Receiver)<a href=#subsubsec:app-details-receivers class=anchor aria-hidden=true></a></h4><p><strong>Receivers</strong> (also called <em>broadcast receivers</em>)\ncan be used to trigger execution of certain tasks when certain events\noccur. These components are called broadcast receivers, because they are\nexecuted as soon as a broadcast message is received. These broadcast\nmessages are sent using a method called <em>Intent</em>. Intent is a\nspecial feature in Android that can be used to open applications (i.e.,\nactivities), run services and send broadcast messages. Therefore, like\n<a href=#subsubsec:activities>activities</a>, broadcast receivers use\n<em>intent filters</em> to receive the desired broadcast messages.\nBroadcast messages can be sent by the system or the application itself.\nWhen a broadcast message is sent, the corresponding receivers are\nactivated by the system so that they can execute tasks. For example, if\nyour phone is low on resources, it may freeze or experience lags for a\nmoment after you enable mobile data or connect it to the Wi-Fi. This is\nbecause broadcast receivers that can receive\n<code>android.net.conn.CONNECTIVITY_CHANGE</code> are activated by the\nsystem as soon as the data connection is enabled. Since many\napplications typically use this intent filter, they are all activated\nalmost immediately by the system which causes the freezing or lags.<p>Receivers can also be used for inter-process communication (IPC),\ni.e., it can be used to communicate across multiple applications or even\ndifferent components of a single application.</section><section id=subsubsec:providers class=level4 data-number=2.2.3.4><h4 data-number=2.2.3.4><span class=header-section-number>2.2.3.4</span> (內容)提供者\n((Content)Providers)<a href=#subsubsec:providers class=anchor aria-hidden=true></a></h4><p><strong>Providers</strong> are primarily used for data management.\nFor example, when you save an APK file or export rules in App Manager,\nit uses a content provider called <code>.fm.FmProvider</code> to save\nthe APK or export the rules. There are many providers, including the\nones provided by the system, that can be used to manage various\ncontent-related tasks, such as database management, tracking, searching,\netc. Each provider has a field called <em>Authority</em> which is unique\nto the application in the entire Android ecosystem just as the package\nname.</section><section id=針對已root的手機的額外功能 class=level4 data-number=2.2.3.5><h4 data-number=2.2.3.5><span class=header-section-number>2.2.3.5</span>\n針對已root的手機的額外功能<a href=#針對已root的手機的額外功能 class=anchor aria-hidden=true></a></h4><p>Unlike the no-root users who are mostly spectators in these tabs,\nroot users can perform various operations.<section id=阻止組件 class=level5 data-number=2.2.3.5.1><h5 data-number=2.2.3.5.1><span class=header-section-number>2.2.3.5.1</span> 阻止組件<a href=#阻止組件 class=anchor aria-hidden=true></a></h5><p>On the right-most side of each component item, there is a switch\nwhich can be used to toggle the blocking status of that particular\ncomponent. If <a href=#subsubsec:instant-component-blocking>Instant\nComponent Blocking</a> is not enabled or blocking is never applied to\nthe application before, it is required to apply the changes using the\n<strong>Apply rules</strong> option in three-dots menu. It is also\npossible to remove the already-applied rules using the same option\n(which would be read as <strong>Remove rules</strong> this time).<p>It is also possible to block the component using one of the several\nmethods by long clicking on the button.<div class=seealso-inline><p><em>See also: <span><a href=#sec:faq:app-components>FAQ: App\nComponents</a></span></em></div></section><section id=par:appdetails:blocking-trackers class=level5 data-number=2.2.3.5.2><h5 data-number=2.2.3.5.2><span class=header-section-number>2.2.3.5.2</span> 阻止跟蹤器<a href=#par:appdetails:blocking-trackers class=anchor aria-hidden=true></a></h5><p>It is possible to disable tracker components using the <strong>Block\ntracker</strong> option in the three-dots menu. All tracker components\nwill be blocked regardless of the tab you’re currently in.<div class=\"amalert tip\"><p><strong><em>Info.</em></strong><p>Tracker components are a subset of application components. Therefore,\nthey are blocked using the same method used for blocking any other\ncomponents.</div><div class=seealso><p><em>See also:</em><ul class=incremental><li><p><a href=#subsec:tracker-classes-versus-tracker-components>FAQ:\nTracker classes versus tracker components</a><li><p><a href=#sec:scanner-page>Scanner Page</a><li><p><a href=#subsec:block-unblock-trackers>1-Click Ops Page:\nBlock/Unblock Trackers</a></ul></div></section></section></section><section id=subsec:permission-tabs class=level3 data-number=2.2.4><h3 data-number=2.2.4><span class=header-section-number>2.2.4</span>\n<a href=#toc:subsec:permission-tabs>權限選項卡</a><a href=#subsec:permission-tabs class=anchor aria-hidden=true></a></h3><p><strong>App Ops</strong>, <strong>使用權限</strong> and\n<strong>權限</strong> 選項卡與權限相關。 安卓中，在不具有相同身份（稱為\n<em>shared\nID</em>）的應用或進程之間進行通信常常需要權限，其由權限控制器管理。\n一些被視為<em>普通</em>\n的權限，若它們出現在應用程序清單中，則會自動授予，但<em>危險</em>權限 和\n<em>開發</em> 權限需要用戶確認。 選項卡中使用的顏色在 §<a href=#subsec:app-details-color-codes data-reference-type=ref data-reference=subsec:app-details-color-codes>[subsec:app-details-color-codes]</a>\n中有解釋。<section id=subsubsec:app-ops class=level4 data-number=2.2.4.1><h4 data-number=2.2.4.1><span class=header-section-number>2.2.4.1</span> App Ops<a href=#subsubsec:app-ops class=anchor aria-hidden=true></a></h4><p><strong>App Ops</strong> 代表\"應用操作 <strong>(Application\nOperations)</strong> \". 自 Android 4.3 開始，Android 使用 <em>App\nOps</em> 控制大多系統權限，每個 App Op\n都有一個與之關聯的唯一編號，該編號與其私有名稱將一同顯示在“App\nOps”選項卡中，一些 App Ops 也有一個公共名稱。\n大量的應用操作是也與權限相關，在此選項卡中，若 App Ops\n相關的權限被視為危險則被標記為危險。其他信息如 標志位(<em>flags</em>),\n權限名稱 (<em>permission name</em>), 權限描述(<em>permission\ndescription</em>),包名 (<em>package name</em>),群組 ( <em>group</em>)\n也取自相關的 <a href=#subsubsec:permissions>權限</a>。<p>其他可能包括以下內容:<ul class=incremental><li><p><strong>模式(Mode)</strong>: 描述了當前授權狀態，可以是\"允許\n(<em>allow</em>)\"、\"拒絕(<em>deny</em>)\"（實際為錯誤）、\"忽略(<em>ignore</em>)\"（實際為拒絕）、\"默認(<em>default</em>)\"（從手機供應商或\nAOSP 內部設置的默認列表推斷）、\"前台(<em>foreground</em>)\"\n（在新的Android版本中，應用只能在前台運行時獲取該權限），以及一些供應商自定義的模式，如MIUI使用詢問(<em>ask</em>)。<li><p><strong>時長(Duration)</strong>: 此 App Ops\n現已使用的時間（可能為負原因未知）。<li><p><strong>允許時刻(Accept Time)</strong>: 上一次 App Op\n被許可。<li><p><strong>拒絕時刻(Reject Time)</strong>: 上一次 App Op\n被拒絕。</ul><div class=\"amalert tip\"><p><strong><em>提示.</em></strong><p>若 <code>android.permission.GET_APP_OPS_STATS</code> 由 ADB\n授予，則此選項卡的內容對非 root 用戶可見.</div><p>每個 App Op\n項都有切換按鈕，可用於允許或拒絕（忽略）它，其他受支持的模式也可以通過長按來設置。\n如果選項卡中未列出所需的 App Op，可使用菜單中的<strong>設置自定義 App\nOp</strong> 。 菜單中的<strong>重置為默認</strong> 可重置App Ops，\n或使用拒絕危險權限的相關操作。 受 App Ops\n本身工作方式所限，系統可能需要不少時間來更改它們。<div class=\"amalert tip\"><p><strong><em>Tip.</em></strong><p>拒絕某些 App Ops\n可能會導致應用行為異常，若所有修覆手段都失敗，可嘗試使用\n<em>重置為默認</em> 選項。</div><p>可以以升序方式按 App Ops 名稱和其編號對列表排序，也可以優先顯示拒絕的\nApp Ops。<div class=seealso-inline><p><em>See also: <span><a href=#ch:app-ops>附錄: App\nOps</a></span></em></div></section><section id=使用權限 class=level4 data-number=2.2.4.2><h4 data-number=2.2.4.2><span class=header-section-number>2.2.4.2</span> 使用權限<a href=#使用權限 class=anchor aria-hidden=true></a></h4><p><strong>系統預定義權限</strong>(<em>Uses Permissions</em>)\n是應用(申請)所使用的權限，其在應用程序清單中使用\n<code>uses-permission</code> 標簽聲明。 其 \"標志位\n(<em>flags</em>)\"、\"權限名 (<em>permission name</em>)\"、\"權限描述\n(<em>permission description</em>)\"、\"包名 ( <em>package\nname</em>)\"、\"群組 (<em>group</em>)\" 取自相關<a href=#subsubsec:permissions>權限</a>。<p>特權用戶可通過切換按鈕授予或撤銷 危險 (<em>dangerous</em>) 和 開發\n(<em>development</em>) 權限，也可以使用菜單中的相應選項。\n只能撤銷以上兩種權限，因為Android不允許修改 普通 (<em>normal</em>)\n權限（其中大多數是）。但仍有可能撤銷它們通過編輯\n<code>runtime-permissions.xml</code> 本身，但是否可能仍不明確。<div class=\"amalert tip\"><p><strong><em>提示.</em></strong><p>由於系統默認會撤銷危險權限，因此撤銷所有危險權限與重置所有權限是一樣的。</div><p>可以以升序方式按權限名稱對列表排序，也可以優先顯示拒絕的權限。</section><section id=subsubsec:permissions class=level4 data-number=2.2.4.3><h4 data-number=2.2.4.3><span class=header-section-number>2.2.4.3</span> 權限<a href=#subsubsec:permissions class=anchor aria-hidden=true></a></h4><p>(自定義)<strong>權限</strong>\n通常是應用自身定義的自定義權限，包括該應用聲明的、標記為\"內部(\n<em>Internal</em>)\" 權限，其他應用聲明、標記為\"外部(\n<em>External</em>)\"的權限。外部權限在應用程序組件中指定為依賴項，即應用只有在擁有指定的權限時才能調用該組件：<ul class=incremental><li><p><strong>名稱</strong> 每個權限都有的唯一的名稱，如\n<code>android.permission.INTERNET</code>\n，但多個應用可以請求同一個權限。<li><p><strong>圖標</strong>\n每個權限都可以有一個自定義圖標，其他權限選項卡沒有任何圖標，因為它們在應用程序清單中不包含任何圖標。<li><p><strong>描述</strong>\n描述權限的可選字段，若沒有與權限關聯的任何描述，則不會顯示該字段。<li><p><strong>標志位(Flags)</strong> 使用標志符號或\n<strong>保護名稱(Protection Level)</strong> 名稱描述權限， 諸如 普通\n<em>normal</em>、開發 <em>development</em>、危險\n<em>dangerous</em>,、即時 <em>instant</em>, 已授權\n<em>granted</em>、已撤銷 <em>revoked</em>、簽名 <em>signature</em>、特權\n<em>privileged</em> 等。<li><p><strong>包名</strong>\n表示與權限關聯的包名，即定義權限的包名。<li><p><strong>群組(Group)</strong>\n與權限關聯的群組（如果有），幾個相關的權限通常可以組合在一起。</ul></section></section><section id=subsec:signatures-tab class=level3 data-number=2.2.5><h3 data-number=2.2.5><span class=header-section-number>2.2.5</span>\n<a href=#toc:subsec:signatures-tab>簽名選項卡</a><a href=#subsec:signatures-tab class=anchor aria-hidden=true></a></h3><p><strong>Signatures</strong> are actually called signing information.\nAn application is signed with one or more signing keys by its developer\nbefore publishing it. The integrity of an application, i.e., whether the\napplication is from the actual developer and has not been modified by\nanother person, can be checked using the signing certificate included in\nthe APK files. This is because when an application is modified by an\nunauthorised entity, the application can longer be signed with the\noriginal signing keys since the signing keys are unknown to the entity.\nOne way to verify the integrity of an application is via the checksums\ngenerated from the certificates. If the developer supplies the checksums\nfor the signing certificates, they can be compared against the checksums\ngenerated in the <strong>Signatures</strong> tab to verify the\napplication. For example, if you have downloaded App Manager from GitHub\nor Telegram Channel, you can verify whether the application was actually\nreleased by me by simply matching the following <em>SHA256</em> checksum\nwith the one displayed in this tab:<pre><code>320c0c0fe8cef873f2b554cb88c837f1512589dcced50c5b25c43c04596760ab</code></pre><p>Several hashing algorithms are used to generate checksums in this\ntab. They include <em>MD5</em>, <em>SHA1</em>, <em>SHA256</em> and\n<em>SHA512</em>.<div class=\"amalert danger\"><p><strong><em>Caution.</em></strong><p>Signing information should be verified using a reliable hashing\nalgorithm, such as <em>SHA256</em>. DO NOT rely on <em>MD5</em> or\n<em>SHA1</em> checksums as they are known to generate the same checksums\nfor multiple certificates.</div></section><section id=subsec:uses-features-tab class=level3 data-number=2.2.6><h3 data-number=2.2.6><span class=header-section-number>2.2.6</span>\n<a href=#toc:subsec:uses-features-tab>Uses Features tab</a><a href=#subsec:uses-features-tab class=anchor aria-hidden=true></a></h3><p><strong>Uses Features</strong> tab lists the features declared by the\napplication, such as OpenGL ES, telephony, and leanback. Some features\ncan be required by the application, and some features can be optional.\nRequired features must be present in the system along with the required\nversion. Otherwise, any attempt to install the application will be\ndenied by the system. Colours used in this tab are explained in §<a href=#subsec:app-details-colour-codes data-reference-type=ref data-reference=subsec:app-details-colour-codes>2.2.1</a>.</section><section id=subsec:configurations-tab class=level3 data-number=2.2.7><h3 data-number=2.2.7><span class=header-section-number>2.2.7</span>\n<a href=#toc:subsec:configurations-tab>Configurations tab</a><a href=#subsec:configurations-tab class=anchor aria-hidden=true></a></h3><p><strong>Configurations</strong> tab lists the configurations required\nby the application, such as input method type (qwerty, 12 key), touch\nscreen type (finger, stylus, etc.), and navigation type (dial pad,\ntrackball, wheel). This tab is going to be empty for most\napplications.</section><section id=subsec:shared-libs-tab class=level3 data-number=2.2.8><h3 data-number=2.2.8><span class=header-section-number>2.2.8</span>\n<a href=#toc:subsec:shared-libs-tab>共享庫選項卡</a><a href=#subsec:shared-libs-tab class=anchor aria-hidden=true></a></h3><p><strong>Shared libraries</strong> tab lists the legacy JAR\ndependencies, any static shared library dependencies (currently, the\nonly known cases are the Chromium-based browsers and WebViews) as well\nas the JNI (Java native interface) libraries. For JNI libraries, it\nspecifies platform (x86/x86_64/ARM/AArch64), architecture (32/64 bit),\nobject type (shared object or executable), etc.</section></section><section id=sec:1-click-ops-page class=level2 data-number=2.3><h2 data-number=2.3><span class=header-section-number>2.3</span> <a href=#toc:sec:1-click-ops-page>一鍵操作頁</a><a href=#sec:1-click-ops-page class=anchor aria-hidden=true></a></h2><p>This page is displayed on selecting the <a href=#subsubsec:main:1-click-ops>1-Click Ops option</a> in the <a href=#subsec:main-page-options-menu>main menu</a>.<section id=subsec:block-unblock-trackers class=level3 data-number=2.3.1><h3 data-number=2.3.1><span class=header-section-number>2.3.1</span>\n<a href=#toc:subsec:block-unblock-trackers>Block/Unblock\nTrackers</a><a href=#subsec:block-unblock-trackers class=anchor aria-hidden=true></a></h3><p>This option can be used to block or unblock the ad/tracker components\nfrom the installed applications. On selecting this option, App Manager\nwill ask if it should list trackers from all the applications or only\nfrom the user applications. Novice users should avoid blocking trackers\nfrom the system applications in order to avoid bad consequences. After\nthat, a multi-choice dialog box will appear where it is possible to\nexclude one or more applications from this operation. The changes are\napplied immediately on pressing the <em>block</em> or <em>unblock</em>\nbutton.<div class=\"amalert warning\"><p><strong><em>Notice.</em></strong><p>Certain applications may not function as expected after blocking\ntheir trackers. If that is the case, remove the blocking rules all at\nonce or one by one in the component tabs of the <a href=#sec:app-details-page>App Details page</a> for the corresponding\napplication.</div><div class=seealso-inline><p><em>See also: <span><a href=#par:appdetails:blocking-trackers>App\nDetails Page: Blocking Trackers</a></span></em></div></section><section id=subsec:block-components-dots class=level3 data-number=2.3.2><h3 data-number=2.3.2><span class=header-section-number>2.3.2</span>\n<a href=#toc:subsec:block-components-dots>Block Components…</a><a href=#subsec:block-components-dots class=anchor aria-hidden=true></a></h3><p>This option can be used to block certain application components as\nspecified by their signatures. A signature of a component is the full\nname or partial name of the component. For safety, it is recommended to\nadd a <code>.</code> (dot) at the end of each partial signature, because\nthe underlying algorithm searches and matches the components in a greedy\nmanner. It is also possible to insert more than one signature in which\ncase all the signatures have to be separated by white spaces. Similar to\nthe option above, there is also an option to apply blocking to the\nsystem applications.<div class=\"amalert danger\"><p><strong><em>Caution.</em></strong><p>If you are not aware of the consequences of blocking applcations\ncomponents by their signatures, you should avoid using this option as it\nmay result in bootloop or soft brick, and you may have to apply factory\nreset as a result.</div></section><section id=subsec:set-mode-for-app-ops-dots class=level3 data-number=2.3.3><h3 data-number=2.3.3><span class=header-section-number>2.3.3</span>\n<a href=#toc:subsec:set-mode-for-app-ops-dots>Set Mode for App\nOps…</a><a href=#subsec:set-mode-for-app-ops-dots class=anchor aria-hidden=true></a></h3><p>This option can be used to configure certain <a href=#ch:app-ops>applcation operations</a> of all or selected\napplications. There are two fields. The first field can be used to\ninsert more than one app op constants (either names or values) separated\nby white spaces. It is not always possible to know in advance about all\nthe app op constants as they vary from device to device and from OS to\nOS. Desired app op constant can be found in the <em>App Ops</em> tab\nlocated in the <a href=#sec:app-details-page>App Details page</a>. The\nsecond field can be used to insert or select one of the <a href=#subsec:mode-constants>modes</a> that will be set against the\nspecified app ops.<div class=\"amalert danger\"><p><strong><em>Caution.</em></strong><p>Unless you are well-informed about app ops and the consequences of\nblocking them, you should avoid using this option.</div></section><section id=subsec:1-click-back-up class=level3 data-number=2.3.4><h3 data-number=2.3.4><span class=header-section-number>2.3.4</span>\n<a href=#toc:subsec:1-click-back-up>備份</a><a href=#subsec:1-click-back-up class=anchor aria-hidden=true></a></h3><p>1-Click options for back up. As a precaution, it lists the affected\nbackups before performing any operation.<section id=back-up-all-apps. class=level5 data-number=2.3.4.0.1><h5 data-number=2.3.4.0.1><span class=header-section-number>2.3.4.0.1</span> Back up all apps.<a href=#back-up-all-apps. class=anchor aria-hidden=true></a></h5><p>Back up all the installed applications.</section><section id=redo-existing-backups. class=level5 data-number=2.3.4.0.2><h5 data-number=2.3.4.0.2><span class=header-section-number>2.3.4.0.2</span> Redo existing backups.<a href=#redo-existing-backups. class=anchor aria-hidden=true></a></h5><p>Back up all the installed applications that have a previous\nbackup.</section><section id=back-up-apps-without-backups. class=level5 data-number=2.3.4.0.3><h5 data-number=2.3.4.0.3><span class=header-section-number>2.3.4.0.3</span> Back up apps without\nbackups.<a href=#back-up-apps-without-backups. class=anchor aria-hidden=true></a></h5><p>Back up all the installed applications without a previous backup.</section><section id=verify-and-redo-backups. class=level5 data-number=2.3.4.0.4><h5 data-number=2.3.4.0.4><span class=header-section-number>2.3.4.0.4</span> Verify and redo\nbackups.<a href=#verify-and-redo-backups. class=anchor aria-hidden=true></a></h5><p>Verify the recently made backups of the installed applications and\nredo backup if necessary.</section><section id=back-up-apps-with-changes. class=level5 data-number=2.3.4.0.5><h5 data-number=2.3.4.0.5><span class=header-section-number>2.3.4.0.5</span> Back up apps with\nchanges.<a href=#back-up-apps-with-changes. class=anchor aria-hidden=true></a></h5><p>If an app has changed since the last backup, redo its backup. It\nchecks a number of indices including application version, last update\ndate, last launch date, integrity and file hashes. Directory hashes are\ntaken during the backup process and are stored in a database. On running\nthis operation, new hashes are taken and compared with the ones kept in\nthe database.</section></section><section id=subsec:1-click-restore class=level3 data-number=2.3.5><h3 data-number=2.3.5><span class=header-section-number>2.3.5</span>\n<a href=#toc:subsec:1-click-restore>恢覆</a><a href=#subsec:1-click-restore class=anchor aria-hidden=true></a></h3><p>1-Click options for restore. As a precaution, it lists the affected\nbackups before performing any operation.<section id=restore-all-apps. class=level5 data-number=2.3.5.0.1><h5 data-number=2.3.5.0.1><span class=header-section-number>2.3.5.0.1</span> Restore all apps.<a href=#restore-all-apps. class=anchor aria-hidden=true></a></h5><p>Restore <em>base backup</em> of all the backed up applications.</section><section id=restore-not-installed-apps. class=level5 data-number=2.3.5.0.2><h5 data-number=2.3.5.0.2><span class=header-section-number>2.3.5.0.2</span> Restore not installed\napps.<a href=#restore-not-installed-apps. class=anchor aria-hidden=true></a></h5><p>Restore <em>base backup</em> of all the backed up applications that\nare not currently installed.</section><section id=restore-latest-backups. class=level5 data-number=2.3.5.0.3><h5 data-number=2.3.5.0.3><span class=header-section-number>2.3.5.0.3</span> Restore latest backups.<a href=#restore-latest-backups. class=anchor aria-hidden=true></a></h5><p>Restore <em>base backup</em> of already installed applications whose\nversion codes are higher than the installed version code.</section></section><section id=subsec:trim-caches-in-all-apps class=level3 data-number=2.3.6><h3 data-number=2.3.6><span class=header-section-number>2.3.6</span>\n<a href=#toc:subsec:trim-caches-in-all-apps>Trim Caches in All\nApps</a><a href=#subsec:trim-caches-in-all-apps class=anchor aria-hidden=true></a></h3><p>Delete caches from all applications, including Android system. During\nthis operation, caches of all the running applications may not be\ncleared as expected.</section></section><section id=sec:profiles-page class=level2 data-number=2.4><h2 data-number=2.4><span class=header-section-number>2.4</span> <a href=#toc:sec:profiles-page>配置文件頁面</a><a href=#sec:profiles-page class=anchor aria-hidden=true></a></h2><p>Profiles page can be accessed from the <a href=#subsec:main-page-options-menu>options-menu</a> in the main page.\nIt primarily displays a list of configured profiles along with the\ntypical options to perform operations on them. New profiles can also be\nadded using the <em>plus</em> button at the bottom-right corner.\nProfiles can be imported, duplicated or deleted. Clicking on a profile\nitem opens its <a href=#sec:profile-page>profile page</a>.<section id=subsec:profiles-options-menu class=level3 data-number=2.4.1><h3 data-number=2.4.1><span class=header-section-number>2.4.1</span>\n<a href=#toc:subsec:profiles-options-menu>選項菜單</a><a href=#subsec:profiles-options-menu class=anchor aria-hidden=true></a></h3><p>The three-dots menu in the top-right corner opens the global option\nmenu. It has an option to import an existing profile that was previously\nexported from App Manager.<p>Long clicking on any profile item brings up another options-menu. It\noffers the following options:<ul class=incremental><li><p><strong>Apply now….</strong> This option can be used to apply the\nprofile directly. When clicked, a dialog is displayed where it is\npossible to select a <a href=#subsubsec:profile-state>profile\nstate</a>. On selecting one of the states, the profile will be applied\nimmediately.<li><p><strong>Delete.</strong> Clicking on this option will remove the\nprofile immediately without a warning.<li><p><strong>Duplicate.</strong> This option can be used to duplicate\nthe profile. When clicked, a dialog is displayed where it is possible to\nset a name for the new profile. On clicking “OK”, the <a href=#sec:profile-page>profile page</a> will be loaded by duplicating\nall the configurations that this profile have. However, the profile will\nnot be saved until it is saved manually.<li><p><strong>Copy profile ID.</strong> This option is used to copy the\nunique profile ID of the profile. The profile ID can be used to <a href=#subsec:triggering-a-profile>trigger the profile</a> from a\nthird-party application.<li><p><strong>Export.</strong> Export the profile to an external\nstorage. Profiles exported this way can be imported via the\n<em>import</em> option as mentioned above.<li><p><strong>Create shortcut.</strong> This option can be used to\ncreate a shortcut for the profile. There are two options:\n<em>Simple</em> and <em>Advanced</em>. When configured with the latter\noption, it prompts the user to select a profile state when the shortcut\nis invoked. The former option, on the other hand, always uses the\ndefault state that was configured when the profile was last\nsaved.</ul></section></section><section id=sec:profile-page class=level2 data-number=2.5><h2 data-number=2.5><span class=header-section-number>2.5</span> <a href=#toc:sec:profile-page>配置頁</a><a href=#sec:profile-page class=anchor aria-hidden=true></a></h2><p>Profile page displays the configurations for a profile. It also\noffers the options to edit them.<section id=subsec:profile-options-menu class=level3 data-number=2.5.1><h3 data-number=2.5.1><span class=header-section-number>2.5.1</span>\n<a href=#toc:subsec:profile-options-menu>選項菜單</a><a href=#subsec:profile-options-menu class=anchor aria-hidden=true></a></h3><p>The three dots menu in the top-right corner opens the options-menu.\nIt contains several options such as–<ul class=incremental><li><p><strong>Apply.</strong> This option can be used to apply the\nprofile directly. When clicked, a dialog is displayed where it is\npossible to select a <a href=#subsubsec:profile-state>profile\nstate</a>. On selecting one of the states, the profile will be applied\nimmediately.<div class=\"amalert tip\"><p><strong><em>Notice.</em></strong><p>When you apply a profile, if some packages do not match the criteria,\nthey will simply be ignored.</div><li><p><strong>Save.</strong> Save changes to the profile.<li><p><strong>Discard.</strong> Discard any modifications made since\nthe last time it was saved.<li><p><strong>Delete.</strong> Clicking on this option will remove the\nprofile immediately without a warning.<li><p><strong>Duplicate.</strong> This option can be used to duplicate\nthe profile. When clicked, a dialog is displayed where it is possible to\nset a name for the new profile. On clicking “OK”, this page will be\nreloaded by duplicating all the configurations that this profile have.\nHowever, the new profile will not be saved until it is saved\nmanually.<li><p><strong>Create shortcut.</strong> This option can be used to\ncreate a shortcut for the profile. There are two options:\n<em>Simple</em> and <em>Advanced</em>. When configured with the latter\noption, it prompts the user to select a profile state when the shortcut\nis invoked. The former option, on the other hand, always uses the\ndefault state that was configured when the profile was last\nsaved.</ul></section><section id=subsec:profile-apps-tab class=level3 data-number=2.5.2><h3 data-number=2.5.2><span class=header-section-number>2.5.2</span>\n<a href=#toc:subsec:profile-apps-tab>應用程序選項卡</a><a href=#subsec:profile-apps-tab class=anchor aria-hidden=true></a></h3><p>Apps tab lists the packages configured for this profile. Packages can\nbe added or removed using the <em>plus</em> button located near the\nbottom of the screen. A package can also be removed by long clicking on\nit (in which case, a popup will be displayed with the only option,\n<em>delete</em>).</section><section id=subsec:profile-configurations-tab class=level3 data-number=2.5.3><h3 data-number=2.5.3><span class=header-section-number>2.5.3</span>\n<a href=#toc:subsec:profile-configurations-tab>配置選項卡</a><a href=#subsec:profile-configurations-tab class=anchor aria-hidden=true></a></h3><p>Configurations tab can be used to configure the selected\npackages.<section id=profile-id class=level4 data-number=2.5.3.1><h4 data-number=2.5.3.1><span class=header-section-number>2.5.3.1</span> Profile ID<a href=#profile-id class=anchor aria-hidden=true></a></h4><p>The unique ID for this profile, currently set based on the profile\nname. The profile ID can be used to <a href=#subsec:triggering-a-profile>trigger the profile</a> from a\nthird-party application.</section><section id=備注 class=level4 data-number=2.5.3.2><h4 data-number=2.5.3.2><span class=header-section-number>2.5.3.2</span> 備注<a href=#備注 class=anchor aria-hidden=true></a></h4><p>This is the text that will be displayed in the <a href=#sec:profiles-page>profiles page</a>. If not set, the current\nconfigurations will be displayed instead.</section><section id=subsubsec:profile-state class=level4 data-number=2.5.3.3><h4 data-number=2.5.3.3><span class=header-section-number>2.5.3.3</span> 狀態<a href=#subsubsec:profile-state class=anchor aria-hidden=true></a></h4><p>Denotes how certain configured options will behave by default. For\ninstance, if <em>disable</em> option is turned on, the applications will\nbe disabled if the state is <em>on</em> and will be enabled if the state\nis <em>off</em>. Currently, it only supports <em>on</em> and\n<em>off</em> values.</section><section id=用戶 class=level4 data-number=2.5.3.4><h4 data-number=2.5.3.4><span class=header-section-number>2.5.3.4</span> 用戶<a href=#用戶 class=anchor aria-hidden=true></a></h4><p>Select users for which is the profile will be applied. All users are\nselected by default.</section><section id=組件 class=level4 data-number=2.5.3.5><h4 data-number=2.5.3.5><span class=header-section-number>2.5.3.5</span> 組件<a href=#組件 class=anchor aria-hidden=true></a></h4><p>This behaves the same way as the <a href=#subsec:block-components-dots>Block Components…</a> option does\nin the 1-Click Ops page. However, the blocking here is only applied to\nthe selected packages. If the <a href=#subsubsec:profile-state>state</a> is <em>on</em>, the components\nwill be blocked, and if the state is <em>off</em>, the components will\nbe unblocked. The option can be disabled (regardless of the inserted\nvalues) by clicking on the <em>disabled</em> button on the input\ndialog.<div class=seealso-inline><p><em>See also: <span><a href=#subsec:faq:what-are-app-components>What are the app\ncomponents?</a></span></em></div></section><section id=appops-權限 class=level4 data-number=2.5.3.6><h4 data-number=2.5.3.6><span class=header-section-number>2.5.3.6</span> AppOps 權限<a href=#appops-權限 class=anchor aria-hidden=true></a></h4><p>This behaves the same way as the <a href=#subsec:set-mode-for-app-ops-dots>Set Mode for App Ops…</a>\noption does in the 1-Click Ops page. However, the operation here is only\napplied to the selected packages. If the <a href=#subsubsec:profile-state>state</a> is <em>on</em>, the app ops\nwill be denied (i.e. ignored), and if the state is <em>off</em>, the app\nops will be allowed. The option can be disabled (regardless of the\ninserted values) by clicking on the <em>disable</em> button in the input\ndialog.</section><section id=權限 class=level4 data-number=2.5.3.7><h4 data-number=2.5.3.7><span class=header-section-number>2.5.3.7</span> 權限<a href=#權限 class=anchor aria-hidden=true></a></h4><p>This option can be used to grant or revoke certain permissions from\nthe selected packages. Like others above, permissions must be separated\nby white spaces. If the <a href=#subsubsec:profile-state>state</a> is\n<em>on</em>, the permissions will be revoked, and if the state is\n<em>off</em>, the permissions will be allowed. The option can be\ndisabled (regardless of the inserted values) by clicking on the\n<em>disable</em> button in the input dialog.</section><section id=備份恢覆 class=level4 data-number=2.5.3.8><h4 data-number=2.5.3.8><span class=header-section-number>2.5.3.8</span> 備份/恢覆<a href=#備份恢覆 class=anchor aria-hidden=true></a></h4><p>This option can be used to take a backup of the selected applications\nand its data or restore them. Two options are available here: <em>Backup\noptions</em> and <em>backup name</em>.<ul class=incremental><li><p><strong>Backup options.</strong> Same as the <a href=#subsec:backup-restore-backup-options>backup options</a> of the\nbackup/restore feature. If not set, the default options will be\nused.<li><p><strong>Backup name.</strong> Set a custom name for the backup.\nIf the backup name is set, each time a backup is made, it will be given\na unique name with backup-name as the suffix. This behaviour will be\nfixed in a future release. Leave this field empty for regular “base”\nbackups (also, make sure not to enable <em>backup multiple</em> in the\nbackup options).</ul><p>If the <a href=#subsubsec:profile-state>state</a> is <em>on</em>,\nthe packages will be backed up, and if the state is <em>off</em>, the\npackages will be restored. The option can be disabled by clicking on the\n<em>disable</em> button in the input dialog.</section><section id=導出屏蔽規則 class=level4 data-number=2.5.3.9><h4 data-number=2.5.3.9><span class=header-section-number>2.5.3.9</span> 導出屏蔽規則<a href=#導出屏蔽規則 class=anchor aria-hidden=true></a></h4><div class=\"amalert danger\"><p><strong><em>Danger.</em></strong><p>This option is not yet implemented.</div></section><section id=freeze class=level4 data-number=2.5.3.10><h4 data-number=2.5.3.10><span class=header-section-number>2.5.3.10</span> Freeze<a href=#freeze class=anchor aria-hidden=true></a></h4><p>Allow freezing or unfreezing the selected packages depending on the\nvalue of the <a href=#subsubsec:profile-state>state</a>. If the state\nis <em>on</em>, the packages will be frozen, and if the state is\n<em>off</em>, they will be unfrozen.</section><section id=強制停止 class=level4 data-number=2.5.3.11><h4 data-number=2.5.3.11><span class=header-section-number>2.5.3.11</span> 強制停止<a href=#強制停止 class=anchor aria-hidden=true></a></h4><p>Allow the selected packages to be force-stopped.</section><section id=清除緩存 class=level4 data-number=2.5.3.12><h4 data-number=2.5.3.12><span class=header-section-number>2.5.3.12</span> 清除緩存<a href=#清除緩存 class=anchor aria-hidden=true></a></h4><p>Enable clearing cache for the selected packages.</section><section id=清除數據 class=level4 data-number=2.5.3.13><h4 data-number=2.5.3.13><span class=header-section-number>2.5.3.13</span> 清除數據<a href=#清除數據 class=anchor aria-hidden=true></a></h4><p>Enable clearing data for the selected packages.</section><section id=block-trackers class=level4 data-number=2.5.3.14><h4 data-number=2.5.3.14><span class=header-section-number>2.5.3.14</span> Block Trackers<a href=#block-trackers class=anchor aria-hidden=true></a></h4><p>Enable blocking or unblocking of the tracker components from the\nselected packages depending on the value of the <a href=#subsubsec:profile-state>state</a>. If the state is <em>on</em>,\nthe trackers will be blocked, and if the state is <em>off</em>, the\ntrackers will be unblocked.</section><section id=保存apk class=level4 data-number=2.5.3.15><h4 data-number=2.5.3.15><span class=header-section-number>2.5.3.15</span> 保存APK<a href=#保存apk class=anchor aria-hidden=true></a></h4><p>Enable saving APK files at <code>AppManager/apks</code> (or in the\ndirectory selected in the settings page) of the selected packages.</section></section></section><section id=sec:settings-page class=level2 data-number=2.6><h2 data-number=2.6><span class=header-section-number>2.6</span> <a href=#toc:sec:settings-page>設置頁面</a><a href=#sec:settings-page class=anchor aria-hidden=true></a></h2><p>Settings page can be used to customise the behaviour of App\nManager.<section id=subsec:language class=level3 data-number=2.6.1><h3 data-number=2.6.1><span class=header-section-number>2.6.1</span>\n<a href=#toc:subsec:language>界面語言</a><a href=#subsec:language class=anchor aria-hidden=true></a></h3><p>配置應用內語言， App Manager 目前支持19種語言。</section><section id=subsec:appearance class=level3 data-number=2.6.2><h3 data-number=2.6.2><span class=header-section-number>2.6.2</span>\n<a href=#toc:subsec:appearance>Appearance</a><a href=#subsec:appearance class=anchor aria-hidden=true></a></h3><section id=subsubsec:app-theme class=level4 data-number=2.6.2.1><h4 data-number=2.6.2.1><span class=header-section-number>2.6.2.1</span> 應用主題<a href=#subsubsec:app-theme class=anchor aria-hidden=true></a></h4><p>配置應用程式內主題。</section><section id=subsubsec:pure-black-theme class=level4 data-number=2.6.2.2><h4 data-number=2.6.2.2><span class=header-section-number>2.6.2.2</span> Pure Black Theme<a href=#subsubsec:pure-black-theme class=anchor aria-hidden=true></a></h4><p>Whether to use a black background instead of the material themed\nbackground.</section><section id=subsubsec:layout-direction class=level4 data-number=2.6.2.3><h4 data-number=2.6.2.3><span class=header-section-number>2.6.2.3</span> Layout Direction<a href=#subsubsec:layout-direction class=anchor aria-hidden=true></a></h4><p>Change layout direction, either left to right or right to left. This\nis usually set using the selected language but not everybody prefers the\nsame direction.</section><section id=subsubsec:enable/disable-features class=level4 data-number=2.6.2.4><h4 data-number=2.6.2.4><span class=header-section-number>2.6.2.4</span> 啟用/禁用功能<a href=#subsubsec:enable/disable-features class=anchor aria-hidden=true></a></h4><p>啟用或禁用應用 App Manager 中的某些功能，如<ul class=incremental><li><p>攔截器(Interceptor)<li><p>應用清單文件瀏覽器(Manifest viewer)<li><p>掃描器(Scanner)<li><p>包安裝器(Package installer)<li><p>使用情況(Usage access): 關閉此選項後，App Manager 將永遠不會請求\n<em>Usage Access</em> 權限.<li><p>日志瀏覽器(Log viewer)</ul></section></section><section id=subsec:privacy class=level3 data-number=2.6.3><h3 data-number=2.6.3><span class=header-section-number>2.6.3</span>\n<a href=#toc:subsec:privacy>Privacy</a><a href=#subsec:privacy class=anchor aria-hidden=true></a></h3><section id=subsubsec:screen-lock class=level4 data-number=2.6.3.1><h4 data-number=2.6.3.1><span class=header-section-number>2.6.3.1</span> 屏幕鎖定<a href=#subsubsec:screen-lock class=anchor aria-hidden=true></a></h4><p>Lock App Manager using Android screen lock provided a screen lock is\nconfigured.<div class=\"amalert warning\"><p><strong><em>Warning.</em></strong><p>If screen lock is disabled in Android after enabling this setting,\nApp Manager will not open until it is enabled again.</div></section><section id=subsubsec:run-am-in-background class=level4 data-number=2.6.3.2><h4 data-number=2.6.3.2><span class=header-section-number>2.6.3.2</span> Run App Manager in the\nBackground<a href=#subsubsec:run-am-in-background class=anchor aria-hidden=true></a></h4><p>Whether to run App Manager in the background to reduce the\ninitialisation delay. On certain devices, this can also help if you’re\nfrequently disconnected from ADB.</section><section id=subsubsec:use-the-internet class=level4 data-number=2.6.3.3><h4 data-number=2.6.3.3><span class=header-section-number>2.6.3.3</span> Use the Internet<a href=#subsubsec:use-the-internet class=anchor aria-hidden=true></a></h4><p>Whether to activate the Internet features in App Manager. This\ncurrently include VirusTotal and Pithus scanning in the <a href=#sec:scanner-page>Scanner page</a>.</section><section id=subsubsec:auth-manager class=level4 data-number=2.6.3.4><h4 data-number=2.6.3.4><span class=header-section-number>2.6.3.4</span> Authorization Manager<a href=#subsubsec:auth-manager class=anchor aria-hidden=true></a></h4><p>This setting allows a third-party application to get access to\ncertain features, such as profiles.</section></section><section id=subsec:mode-of-operation class=level3 data-number=2.6.4><h3 data-number=2.6.4><span class=header-section-number>2.6.4</span>\n<a href=#toc:subsec:mode-of-operation>操作模式</a><a href=#subsec:mode-of-operation class=anchor aria-hidden=true></a></h3><p>Mode of operation defines how App Manager works as a whole. It has\nthe following options:<ul class=incremental><li><p><strong>Auto.</strong> Let App Manager decide the suitable\noption. Although this is the default option, non-rooted users should use\nthe <em>no-root</em> mode.<li><p><strong>Root.</strong> Operate App Manager in root mode. App\nManager will fall back to <em>no-root</em> mode if root is not detected,\nor in rare cases when Binder communication through root is disabled\n(e.g. in <a href=https://github.com/MuntashirAkon/AppManager/issues/606>Phh\nSuperUser</a>).<li><p><strong>ADB over TCP.</strong> Operate App Manager in ADB mode\nvia <a href=#sec:adb-over-tcp>ADB over TCP</a>. App Manager will fall\nback to <em>no-root</em> mode if ADB over TCP is not enabled.<li><p><strong>Wireless debugging.</strong> Enable ADB via Wireless\nDebugging. It will try to connect to the configured port automatically\nat first. On failure, it will ask the user to either pair or connect to\nthe ADB daemon manually. App Manager will fall back to <em>no-root</em>\nmode if it fails to connect to the ADB daemon this way.<div class=\"amalert tip\"><p><strong><em>Info.</em></strong><p>This option is only displayed in devices running Android 11 or later\nas Wireless Debugging was introduced in Android 11.</div><li><p><strong>No-root.</strong> Operate App Manager in no-root mode.\nWhile App Manager performs better in this mode, all the root- or\nADB-specific features will be disabled.</ul><p>It also displays the actual mode of operation at the top. The actual\nmode of operations are <em>root</em>, <em>ABD</em> and\n<em>no-root</em>.<div class=\"amalert tip\"><p><strong><em>Notice.</em></strong><p>“Remote service” is only required for ADB users or when you use the\ncustom commands.</div></section><section id=subsec:apk-signing class=level3 data-number=2.6.5><h3 data-number=2.6.5><span class=header-section-number>2.6.5</span>\n<a href=#toc:subsec:apk-signing>APK 簽名</a><a href=#subsec:apk-signing class=anchor aria-hidden=true></a></h3><section id=簽名方案 class=level4 data-number=2.6.5.1><h4 data-number=2.6.5.1><span class=header-section-number>2.6.5.1</span> 簽名方案<a href=#簽名方案 class=anchor aria-hidden=true></a></h4><p>Configure the <a href=https://source.android.com/security/apksigning>signature\nschemes</a> to be used when APK signing is enabled. v1 and v2 signature\nschemes are enabled by default, but v3 should also be enabled to ensure\nproper security in Android 9 or later.</section><section id=簽名密鑰 class=level4 data-number=2.6.5.2><h4 data-number=2.6.5.2><span class=header-section-number>2.6.5.2</span> 簽名密鑰<a href=#簽名密鑰 class=anchor aria-hidden=true></a></h4><p>Configure the signing key for signing APK files. Keys from an\nexisting KeyStore can be imported to App Manager, or a new key can be\ngenerated.<div class=\"amalert tip\"><p><strong><em>Tip.</em></strong><p>If you need to use the key in the future, it is recommended that you\ncreate a KeyStore yourself and import the key here. Without a proper\nbackup, keys generated within App Manager are at the risk of being\ndeleted.</div></section><section id=align-apk-files class=level4 data-number=2.6.5.3><h4 data-number=2.6.5.3><span class=header-section-number>2.6.5.3</span> Align APK Files<a href=#align-apk-files class=anchor aria-hidden=true></a></h4><p>Performs zip alignment when App Manager signs an APK file. Zip\nalignment stores the files in the APK file (which is actually a zip\nfile) in a way that a zip file reader can access the files quite easily\nusing random access instead of loading the entire APK file in the\nmemory, which results in the reduction of Android’s memory usage. Note\nthat this step is required if an application’s manifest has\n<code>extractNativeLibs</code> set to <code>true</code>.</section></section><section id=subsec:installer class=level3 data-number=2.6.6><h3 data-number=2.6.6><span class=header-section-number>2.6.6</span>\n<a href=#toc:subsec:installer>安裝器</a><a href=#subsec:installer class=anchor aria-hidden=true></a></h3><p>Configure the default behaviour of the installer. You can also find\nmost of the settings by clicking on the <em>cog</em> icon when you\ninstall an application.<section id=安裝位置 class=level4 data-number=2.6.6.1><h4 data-number=2.6.6.1><span class=header-section-number>2.6.6.1</span> 安裝位置<a href=#安裝位置 class=anchor aria-hidden=true></a></h4><p>選擇APK安裝位置，可以為 <em>自動</em>、<em>僅內部</em>\n和<em>傾向外部</em>.\n在較新的Android版本中，最後一個選項可能並不總是能如期在外部存儲中安裝應用.</section><section id=block-trackers-1 class=level4 data-number=2.6.6.2><h4 data-number=2.6.6.2><span class=header-section-number>2.6.6.2</span> Block Trackers<a href=#block-trackers-1 class=anchor aria-hidden=true></a></h4><p>Whether to block the tracking components immediately after installing\nthe application.</section><section id=display-changes class=level4 data-number=2.6.6.3><h4 data-number=2.6.6.3><span class=header-section-number>2.6.6.3</span> Display Changes<a href=#display-changes class=anchor aria-hidden=true></a></h4><p>Whether to display changes in version, trackers, components,\npermissions, signatures, SDK, etc. in a version controlled style before\ninstalling the application if the application has already been\ninstalled.</section><section id=安裝來源 class=level4 data-number=2.6.6.4><h4 data-number=2.6.6.4><span class=header-section-number>2.6.6.4</span> 安裝來源<a href=#安裝來源 class=anchor aria-hidden=true></a></h4><p>選擇安裝程序，對一些明確檢查其安裝程序的應用很有用 (只適用於 root/ADB\n用戶).</section><section id=簽名-apk class=level4 data-number=2.6.6.5><h4 data-number=2.6.6.5><span class=header-section-number>2.6.6.5</span> 簽名 APK<a href=#簽名-apk class=anchor aria-hidden=true></a></h4><p>安裝應用前是否對 APK 文件進行簽名. 轉至 <a href=#subsec:apk-signing>APK 簽名</a> 部分來配置簽名.</section><section id=immediately-perform-dex-optimization class=level4 data-number=2.6.6.6><h4 data-number=2.6.6.6><span class=header-section-number>2.6.6.6</span> Immediately Perform DEX\nOptimization<a href=#immediately-perform-dex-optimization class=anchor aria-hidden=true></a></h4><p>Whether to perform DEX optimization immediately after installing the\napplication. This can be useful for heavy applications, such as the\ngaming applications.</section><section id=install-in-the-background class=level4 data-number=2.6.6.7><h4 data-number=2.6.6.7><span class=header-section-number>2.6.6.7</span> Install in the Background<a href=#install-in-the-background class=anchor aria-hidden=true></a></h4><p>Whether to always install applications in the background. A\nnotification will be issued once the installation is finished.</section></section><section id=subsec:backup/restore class=level3 data-number=2.6.7><h3 data-number=2.6.7><span class=header-section-number>2.6.7</span>\n<a href=#toc:subsec:backup/restore>備份/恢覆</a><a href=#subsec:backup/restore class=anchor aria-hidden=true></a></h3><p>與 <a href=#sec:backup-restore>備份恢覆</a> 相關的設置.<section id=壓縮方法 class=level4 data-number=2.6.7.1><h4 data-number=2.6.7.1><span class=header-section-number>2.6.7.1</span> 壓縮方法<a href=#壓縮方法 class=anchor aria-hidden=true></a></h4><p>Set the compression method to be used during backups. App Manager\nsupports GZip, BZip2 and Zstandard compression methods, GZip being the\ndefault compression method. It doesn’t affect the restore of an existing\nbackup.</section><section id=subsubsec:settings-backup-options class=level4 data-number=2.6.7.2><h4 data-number=2.6.7.2><span class=header-section-number>2.6.7.2</span> 備份選項<a href=#subsubsec:settings-backup-options class=anchor aria-hidden=true></a></h4><p>Customise the <em>back up/restore dialog</em> displayed while taking\na backup.<div class=seealso-inline><p><em>See also: <span><a href=#subsec:backup-restore-backup-options>Backup\noptions</a></span></em></div></section><section id=備份帶-android-密鑰庫的應用程序 class=level4 data-number=2.6.7.3><h4 data-number=2.6.7.3><span class=header-section-number>2.6.7.3</span> 備份帶 Android\n密鑰庫的應用程序<a href=#備份帶-android-密鑰庫的應用程序 class=anchor aria-hidden=true></a></h4><p>Allow backup of applications that has entries in the Android\nKeyStore. This option is disabled by default because a few apps (such as\nSignal or Element) may crash if restored.</section><section id=subsubsec:settings-encryption class=level4 data-number=2.6.7.4><h4 data-number=2.6.7.4><span class=header-section-number>2.6.7.4</span> 加密<a href=#subsubsec:settings-encryption class=anchor aria-hidden=true></a></h4><p>Set an encryption method for the backups. App Manager currently\nsupports OpenPGP (via <a href=https://f-droid.org/packages/org.sufficientlysecure.keychain/>OpenKeyChain</a>),\nAES, RSA and ECC. Like <a href=#subsec:apk-signing>APK signing</a>,\nThe AES, RSA and ECC keys are stored in the KeyStore and can be imported\nfrom other KeyStores.<div class=\"amalert danger\"><p><strong><em>Danger.</em></strong><p>For your own safety, it is not recommended generating RSA and ECC\nkeys inside App Manager. Instead, they should be imported from a\nKeyStore stored in a secure place.<br>In case of AES, the generated key should be stored in a secure place,\nsuch as in a password manager.</div></section><section id=subsubsec:backup-volume class=level4 data-number=2.6.7.5><h4 data-number=2.6.7.5><span class=header-section-number>2.6.7.5</span> 備份位置<a href=#subsubsec:backup-volume class=anchor aria-hidden=true></a></h4><p>Select the storage where the backups will be stored. This is also\nwhere logs and exported APK files are saved.<div class=\"amalert tip\"><p><strong><em>Notice.</em></strong><p>The backup volume only specifies the storage, not the path. Backups\nare traditionally stored in the <code>AppManager</code> folder inside\nthe storage path. But when the path is selected using Storage Access\nFramework (SAF), the selected path or directory is used directly.</div></section><section id=import-backups class=level4 data-number=2.6.7.6><h4 data-number=2.6.7.6><span class=header-section-number>2.6.7.6</span> Import Backups<a href=#import-backups class=anchor aria-hidden=true></a></h4><p>Import backups from old and discontinued projects such as Titanium\nBackup, OAndBackup, and Swift Backup (version 3.0 to 3.2). The backups\nare not deleted after importing to prevent data loss in case the\nimported backups cannot be restored properly.</section></section><section id=subsec:rules class=level3 data-number=2.6.8><h3 data-number=2.6.8><span class=header-section-number>2.6.8</span>\n<a href=#toc:subsec:rules>規則</a><a href=#subsec:rules class=anchor aria-hidden=true></a></h3><section id=subsubsec:instant-component-blocking class=level4 data-number=2.6.8.1><h4 data-number=2.6.8.1><span class=header-section-number>2.6.8.1</span> 即時組件攔截<a href=#subsubsec:instant-component-blocking class=anchor aria-hidden=true></a></h4><p>By default, blocking rules are not applied unless they are applied\nexplicitly in <a href=#sec:app-details-page>the App Details page</a>\nfor any application. After enabling this option, all (old and new) rules\nare applied immediately for all applications without explicitly enabling\nblocking for an application.<div class=seealso-inline><p><em>See also: <span><a href=#subsec:faq:what-is-instant-component-blocking>FAQ: What is\ninstant component blocking?</a></span></em></div></section><section id=導入導出阻止規則 class=level4 data-number=2.6.8.2><h4 data-number=2.6.8.2><span class=header-section-number>2.6.8.2</span> 導入/導出阻止規則<a href=#導入導出阻止規則 class=anchor aria-hidden=true></a></h4><p>It is possible to import or export blocking rules within App Manager\nfor all applications. The types of rules (components, app ops or\npermissions) that should be imported or exported can also be selected.\nIt is also possible to import blocking rules from <a href=https://github.com/lihenggui/blocker>Blocker</a> and <a href=https://github.com/tuyafeng/Watt>Watt</a>. If it is necessary to\nexport blocking rules for a single application, the corresponding <a href=#sec:app-details-page>App Details page</a> can be used to export\nrules, or for multiple apps, <a href=#subsec:batch-operations>batch\noperations</a> can be used.<div class=seealso-inline><p><em>See also: <span><a href=#sec:rules-specification>Rules\nSpecification</a></span></em></div><section id=export class=level5 data-number=2.6.8.2.1><h5 data-number=2.6.8.2.1><span class=header-section-number>2.6.8.2.1</span> Export<a href=#export class=anchor aria-hidden=true></a></h5><p>Export blocking rules for all applications configured within App\nManager. This may include <a href=#subsec:faq:what-are-app-components>app components</a>, app ops\nand permissions based on the options selected in the multi-choice\noptions.</section><section id=import class=level5 data-number=2.6.8.2.2><h5 data-number=2.6.8.2.2><span class=header-section-number>2.6.8.2.2</span> Import<a href=#import class=anchor aria-hidden=true></a></h5><p>Import previously exported blocking rules from App Manager. Similar\nto export, this may include <a href=#subsec:faq:what-are-app-components>app components</a>, app ops\nand permissions based on the options selected in the multi-choice\noptions.</section><section id=par:import-existing-rules class=level5 data-number=2.6.8.2.3><h5 data-number=2.6.8.2.3><span class=header-section-number>2.6.8.2.3</span> Import Existing Rules<a href=#par:import-existing-rules class=anchor aria-hidden=true></a></h5><p>Add components disabled by other applications to App Manager. App\nManager only keeps track of the components disabled within App Manager.\nIf application components are blocked or disabled by other tools or\napplications, this option can be utilised to import them. On clicking\nthis option, App Manager will find the components potentially disabled\nby other applications or tools and list only the name of the\napplications along with the number of matched components. For safety,\nall the applications are unselected by default. They have to be selected\nmanually, and the blocking has to be re-applied via App Manager.<div class=\"amalert danger\"><p><strong><em>Caution.</em></strong><p>Be careful when using this tool as there can be many false positives.\nChoose only the applications that you are certain about.</div></section><section id=import-from-watt class=level5 data-number=2.6.8.2.4><h5 data-number=2.6.8.2.4><span class=header-section-number>2.6.8.2.4</span> Import from Watt<a href=#import-from-watt class=anchor aria-hidden=true></a></h5><p>Import configuration files from <a href=https://github.com/tuyafeng/Watt>Watt</a>, each file containing\nrules for a single package and file name being the name of the package\nwith <code>.xml</code> extension.<div class=\"amalert tip\"><p><strong><em>Tip.</em></strong><p>Location of configuration files in Watt:\n<code>/sdcard/Android/data/com.tuyafeng.watt/files/ifw</code></div></section><section id=import-from-blocker class=level5 data-number=2.6.8.2.5><h5 data-number=2.6.8.2.5><span class=header-section-number>2.6.8.2.5</span> Import from Blocker<a href=#import-from-blocker class=anchor aria-hidden=true></a></h5><p>Import blocking rules from <a href=https://github.com/lihenggui/blocker>Blocker</a>, each file\ncontaining rules for a single package. These files have a\n<code>.json</code> extension.</section></section><section id=刪除所有規則 class=level4 data-number=2.6.8.3><h4 data-number=2.6.8.3><span class=header-section-number>2.6.8.3</span> 刪除所有規則<a href=#刪除所有規則 class=anchor aria-hidden=true></a></h4><p>One-click option to remove all rules configured within App Manager.\nThis will enable all blocked components, app ops will be set to their\ndefault values and permissions will be granted.</section></section><section id=subsec:advanced class=level3 data-number=2.6.9><h3 data-number=2.6.9><span class=header-section-number>2.6.9</span>\n<a href=#toc:subsec:advanced>Advanced</a><a href=#subsec:advanced class=anchor aria-hidden=true></a></h3><section id=subsubsec:selected-users class=level4 data-number=2.6.9.1><h4 data-number=2.6.9.1><span class=header-section-number>2.6.9.1</span> Selected Users<a href=#subsubsec:selected-users class=anchor aria-hidden=true></a></h4><p>This option lets you control the users App Manager should operate on.\nApp Manager operates on all users in root or ADB mode by default.</section><section id=subsubsec:saved-apk-name-format class=level4 data-number=2.6.9.2><h4 data-number=2.6.9.2><span class=header-section-number>2.6.9.2</span> Saved APK Name Format<a href=#subsubsec:saved-apk-name-format class=anchor aria-hidden=true></a></h4><p>Defines the format of the APK name to be used while saving it via\nbatch operations or through profiles. App Manager offers some special\nkeywords enclosed inside <code>%</code> (percentage) signs and available\nbelow the input box. These keywords are:<ul class=incremental><li><p><strong><code>label</code>.</strong> Denotes the name or label of\nthe application. This can be localised to the configured language\ndepending on the app.<li><p><strong><code>package_name</code>.</strong> Denotes the name of\nthe package or application ID, the unique identifier that each\napplication has.<li><p><strong><code>version</code>.</strong> Denotes the current\nversion of the application extracted from its manifest.<li><p><strong><code>version_code</code>.</strong> Denotes the current\nversion code of the application that can be used to separate two\nversions of the same application.<li><p><strong><code>min_sdk</code>.</strong> Denotes the minimum SDK\n(i.e. Android framework version) that the application can operate on.\nThis data is only available since Android 7 (Nougat).<li><p><strong><code>target_sdk</code>.</strong> Denotes the SDK that\nthis application targets. The application can operate on higher SDK but\nonly in the compatibility mode.<li><p><strong><code>datetime</code>.</strong> Denotes the time and date\nwhen the APK is exported.</ul></section><section id=subsubsec:import/export-keystore class=level4 data-number=2.6.9.3><h4 data-number=2.6.9.3><span class=header-section-number>2.6.9.3</span> 導入/導出密鑰庫<a href=#subsubsec:import/export-keystore class=anchor aria-hidden=true></a></h4><p>Import or export the KeyStore used by App Manager. This is a Bouncy\nCastle KeyStore with <code>bks</code> extension. Therefore, other\nKeyStore such as Java KeyStore (JKS) or PKCS #12 are not supported. If a\nkey is needed to be imported from such a KeyStore, the relevant options\nshould be should as specified above.</section></section><section id=subsec:device-info class=level3 data-number=2.6.10><h3 data-number=2.6.10><span class=header-section-number>2.6.10</span> <a href=#toc:subsec:device-info>關於設備</a><a href=#subsec:device-info class=anchor aria-hidden=true></a></h3><p>Display Android version, security, CPU, GPU, battery, memory, screen,\nlanguages, user info, etc.</section></section><section id=sec:scanner-page class=level2 data-number=2.7><h2 data-number=2.7><span class=header-section-number>2.7</span> <a href=#toc:sec:scanner-page>掃描器頁面</a><a href=#sec:scanner-page class=anchor aria-hidden=true></a></h2><p><strong>Scanner page</strong> appears after clicking on the\n<em>scanner</em> button in the <a href=#subsec:app-info-tab>App Info\ntab</a>. External APK files can also be opened for scanning from file\nmanagers, web browsers, etc.<p>It scans for trackers and libraries, and displays the number of\ntrackers and libraries as a summary. It also displays checksums of the\nAPK file as well as the signing certificates. If VirusTotal is\nconfigured in the settings, it also attempts to retrieve reports from\nVirusTotal, or uploads the APK file if it is not in the database. It\nalso display a link to the <a href=https://beta.pithus.org>Pithus</a>\nreport provided the Internet features are enabled.<div class=\"amalert danger\"><p><strong><em>Disclaimer.</em></strong><p>App Manager only scans an application statically without prejudice.\nThe application may provide the options for opting out, or in some\ncases, certain features of the tracker may not be used at all by the\napplication (e.g. F-Droid), or some applications may simply use them as\nplaceholders to prevent the breaking of certain features (e.g. Fennec\nF-Droid). <strong>The intention of the scanner is to give you an idea\nabout what the APK might contain. It should be taken as an initial step\nfor further investigations.</strong></div><p>Clicking on the first item (i.e. number of classes) opens a new page\ncontaining a list of tracker classes for the application. All classes\ncan also be viewed by clicking on the <em>Toggle Class Listing</em>\nmenu. The SMALI or Java version of the class can be viewed by simply\nclicking on an item.<div class=\"amalert tip\"><p><strong><em>Notice.</em></strong><p>Due to various limitations, it is not possible to scan all the\ncomponents of an APK file. This is especially true if an APK is highly\nobfuscated or packed. The scanner also does not check strings (or\nwebsite signatures).</div><p>The second item lists the number of trackers along with their names.\nClicking on the item displays a dialog containing the name of trackers,\nmatched signatures, and the number of classes against each signature.\nSome tracker names may have <span class=\"math inline\"><sup>2</sup></span> prefix which indicates that the\ntrackers are in the <a href=https://etip.exodus-privacy.eu.org>ETIP</a> stand-by list, i.e.,\nwhether they are actual trackers is still being investigated.<p>The third item lists the number of libraries along with their names.\nThe information are mostly taken from <a href=https://gitlab.com/IzzyOnDroid/repo>IzzyOnDroid repo</a>.<div class=seealso-inline><p><em>See also: <span><a href=#subsec:tracker-classes-versus-tracker-components>FAQ: Tracker\nclasses vs tracker components</a></span></em></div></section><section id=sec:interceptor-page class=level2 data-number=2.8><h2 data-number=2.8><span class=header-section-number>2.8</span> <a href=#toc:sec:interceptor-page>攔截器頁面</a><a href=#sec:interceptor-page class=anchor aria-hidden=true></a></h2><p>Interceptor can be used to intercept communication between\napplications using <code>Intent</code>. It works as a man-in-the-middle\nbetween the source and the destination applications. It offers a\nfeature-complete user interface for editing <code>Intent</code>s.<div class=\"amalert warning\"><p><strong><em>Warning.</em></strong><p>Interceptor only works for <em>implicit</em> intents where the <a href=#subsec:faq:what-are-app-components>app component</a> isn’t\nspecified.</div><div class=seealso><p><em>See also:</em><ul class=incremental><li><p><a href=https://developer.android.com/guide/components/intents-common>Common\nIntents</a><li><p><a href=https://developer.android.com/guide/components/intents-filters>Intents\nand Intent Filters</a></ul></div><section id=subsec:intent-filters class=level3 data-number=2.8.1><h3 data-number=2.8.1><span class=header-section-number>2.8.1</span>\n<a href=#toc:subsec:intent-filters>意圖(Intent)過濾器</a><a href=#subsec:intent-filters class=anchor aria-hidden=true></a></h3><p>Intent filters are used by the applications to specify the tasks they\nare able to perform or the tasks they are going to perform using other\napplications. For example, when you’re opening a PDF file using a file\nmanager, the file manager will try to find the applications to open the\nPDF with. To find the right applications, the file manager will create\nan Intent with filters such as the MIME type and ask the system to\nretrieve the applications capable of opening this filter. The system\nwill search through the Manifest of the installed applications to match\nthe filter and list the application components that are able to open\nthis filter (in our case the PDF). At this, either the file manager will\nopen the desired application component all by itself or use a system\nprovided option to open it. If multiple application components are able\nto open it and no default is set, you may get a prompt where you have to\nchoose the right application component.<section id=subsubsec:action class=level4 data-number=2.8.1.1><h4 data-number=2.8.1.1><span class=header-section-number>2.8.1.1</span> 動作(Action)<a href=#subsubsec:action class=anchor aria-hidden=true></a></h4><p>Action specifies the generic action to perform such as\n<code>android.intent.action.VIEW</code>. Applications often declare the\nrelevant actions in the Manifest file to catch the desired Intents. The\naction is particularly useful for broadcast Intent where it plays a\nvital rule. In other cases, it works as an initial way to filter out the\nrelevant application components. Generic actions such as\n<code>android.intent.action.VIEW</code> and\n<code>android.intent.action.SEND</code> are widely used by applications.\nHence, setting this alone may match many application components.</section><section id=subsubsec:data class=level4 data-number=2.8.1.2><h4 data-number=2.8.1.2><span class=header-section-number>2.8.1.2</span> 數據(Data)<a href=#subsubsec:data class=anchor aria-hidden=true></a></h4><p>Data is originally known as URI (Uniform Resource Identifier) defined\nin <a href=http://www.faqs.org/rfcs/rfc2396.html>RFC 2396</a>. It can\nbe web links, file location, or a special feature called\n<em>content</em>. Contents are an Android feature managed by the <a href=#subsubsec:providers>content providers</a>. Data are often\nassociated with a <a href=#subsubsec:mime-type>MIME type</a>.<p>Examples:<pre><code>http://search.disroot.org/?q=URI%20in%20Android%20scheme&amp;categories=general&amp;language=en-US\nhttps://developer.android.com/reference/android/net/Uri\nfile:///sdcard/AppManager.apk\nmailto:email@example.com\ncontent://io.github.muntashirakon.AppManager.provider/23485af89b08d87e898a90c7e/AppManager.apk</code></pre></section><section id=subsubsec:mime-type class=level4 data-number=2.8.1.3><h4 data-number=2.8.1.3><span class=header-section-number>2.8.1.3</span> MIME 類型<a href=#subsubsec:mime-type class=anchor aria-hidden=true></a></h4><p>MIME type of the <a href=#subsubsec:data>data</a>. For example, if\nthe data field is set to <code>file:///sdcard/AppManager.apk</code>, the\nassociated MIME type can be\n<code>application/vnd.android.package-archive</code>.</section><section id=類別categories class=level4 data-number=2.8.1.4><h4 data-number=2.8.1.4><span class=header-section-number>2.8.1.4</span> 類別(Categories)<a href=#類別categories class=anchor aria-hidden=true></a></h4><p>This is similar to <a href=#subsubsec:action>action</a> in the\nsense that it is also used by the system to filter application\ncomponents. This has no further benefits. Unlike <em>action</em>, there\ncan be more than one category. Clicking on the <em>plus</em> button next\nto the title allows adding more categories.</section><section id=標志位flags class=level4 data-number=2.8.1.5><h4 data-number=2.8.1.5><span class=header-section-number>2.8.1.5</span> 標志位(Flags)<a href=#標志位flags class=anchor aria-hidden=true></a></h4><p>Flags are useful in determining how system should behave during the\nlaunch or after the launch of an activity. This should not be touched as\nit requires some technical background. The <em>plus</em> button next to\nthe title can be used to add one or more flags.</section><section id=附加數據extras class=level4 data-number=2.8.1.6><h4 data-number=2.8.1.6><span class=header-section-number>2.8.1.6</span> 附加數據(Extras)<a href=#附加數據extras class=anchor aria-hidden=true></a></h4><p>Extras are the key-value pairs used for supplying additional\ninformation to the destination component. More extras can be added using\nthe <em>plus</em> button next to the title.</section><section id=uri class=level4 data-number=2.8.1.7><h4 data-number=2.8.1.7><span class=header-section-number>2.8.1.7</span> URI<a href=#uri class=anchor aria-hidden=true></a></h4><p>Represents the entire Intent as a URI (e.g. <code>intent://…</code>).\nSome data cannot be converted to string, and as a result, they might not\nappear here.</section></section><section id=subsec:matching-activities class=level3 data-number=2.8.2><h3 data-number=2.8.2><span class=header-section-number>2.8.2</span>\n<a href=#toc:subsec:matching-activities>匹配的活動(Activity)</a><a href=#subsec:matching-activities class=anchor aria-hidden=true></a></h3><p>List all the activity components that matches the Intent. This is\ninternally determined by the system (rather than App Manager). The\nlaunch button next to each component can be used to launch them directly\nfrom App Manager.</section><section id=subsec:interceptor-reset-to-default class=level3 data-number=2.8.3><h3 data-number=2.8.3><span class=header-section-number>2.8.3</span>\n<a href=#toc:subsec:interceptor-reset-to-default>重置為默認</a><a href=#subsec:interceptor-reset-to-default class=anchor aria-hidden=true></a></h3><p>Reset the Intent to its initial state.</section><section id=subsec:interceptor-send-edited-intent class=level3 data-number=2.8.4><h3 data-number=2.8.4><span class=header-section-number>2.8.4</span>\n<a href=#toc:subsec:interceptor-send-edited-intent>發送編輯過的意圖(Intent)</a><a href=#subsec:interceptor-send-edited-intent class=anchor aria-hidden=true></a></h3><p>Resend the edited Intent to the destination application. This may\nopen a list of applications where the desired application is needed to\nbe selected. The result received from the target application will be\nsent to the source application. As a result, the source application will\nnot know if there was a man-in-the-middle.</section></section><section id=sec:shared-preferences-editor-page class=level2 data-number=2.9><h2 data-number=2.9><span class=header-section-number>2.9</span> <a href=#toc:sec:shared-preferences-editor-page>共享首選項(Shared\nPreferences)編輯頁</a><a href=#sec:shared-preferences-editor-page class=anchor aria-hidden=true></a></h2><p>Shared preferences can be edited in this page. Clicking any item on\nthe list opens the edit dialog where the item can be edited. The\nfloating action button in the bottom-right corner can be used to add a\nnew item. To save or delete the file, or to discard current changes, the\nrespective options in the menu can be used.</section></section><section id=ch:guides class=level1 data-number=3><h1 data-number=3><span class=header-section-number>3</span> <a href=#toc:ch:guides>指南</a><a href=#ch:guides class=anchor aria-hidden=true></a></h1><section id=sec:adb-over-tcp class=level2 data-number=3.1><h2 data-number=3.1><span class=header-section-number>3.1</span> <a href=#toc:sec:adb-over-tcp>經由 TCP 的 ADB</a><a href=#sec:adb-over-tcp class=anchor aria-hidden=true></a></h2><p>Many root-only features can still be used by enabling ADB over TCP.\nTo do that, a PC or Mac is required with Android platform-tools\ninstalled, and an Android phone with developer options & USB\ndebugging enabled.<div class=\"amalert tip\"><p><strong><em>Root users.</em></strong><p>If superuser permission has been granted to App Manager, it can\nalready execute privileged code without any problem. <strong>Therefore,\nroot users do not need to enable ADB over TCP.</strong> But if you\ninsist on using ADB over TCP, you must revoke superuser permission for\nApp Manager.</div><div class=seealso-inline><p><em>See also: <span><a href=#sec:faq:adb-over-tcp>FAQ: ADB over\nTCP</a></span></em></div><section id=subsec:enable-developer-options class=level3 data-number=3.1.1><h3 data-number=3.1.1><span class=header-section-number>3.1.1</span>\n<a href=#toc:subsec:enable-developer-options>啟用開發者選項</a><a href=#subsec:enable-developer-options class=anchor aria-hidden=true></a></h3><section id=subsubsec:location-of-developer-options class=level4 data-number=3.1.1.1><h4 data-number=3.1.1.1><span class=header-section-number>3.1.1.1</span> 開發人員選項的位置<a href=#subsubsec:location-of-developer-options class=anchor aria-hidden=true></a></h4><p><strong>Developer options</strong> is located in Android\n<strong>Settings</strong>, either directly near the bottom of the page\n(in most ROMs) or under some other settings, such as\n<strong>System</strong> (Google Pixel, Lineage OS, Asus Zenfone 8.0+),\n<strong>Additional Settings</strong> (Xiaomi MIUI, Oppo ColorOS),\n<strong>More Settings</strong> (Vivo FuntouchOS), <strong>More</strong>\n(ZTE Nubia). Unlike other options, it is not visible until explicitly\nenabled by the user. If it is already enabled, you can use the search\nbox in Android <strong>Settings</strong> to locate it as well.</section><section id=如何啟用開發者選項 class=level4 data-number=3.1.1.2><h4 data-number=3.1.1.2><span class=header-section-number>3.1.1.2</span> 如何啟用開發者選項<a href=#如何啟用開發者選項 class=anchor aria-hidden=true></a></h4><p>This option is available within Android <strong>Settings</strong> as\nwell but like the location of the developer options, it also differs\nfrom device to device. But in general, you have to find <strong>Build\nnumber</strong> (or <strong>MIUI version</strong> for MIUI ROMs and\n<strong>Software version</strong> for Vivo FuntouchOS,\n<strong>Version</strong> for Oppo ColorOS) and tap it at least 7 (seven)\ntimes until you finally get a message saying <em>You are now a\ndeveloper</em> (you may be prompted to insert pin/password/pattern or\nsolve captchas at this point). In most devices, it is located at the\nbottom of the settings page, inside <strong>About Phone</strong>. But\nthe best way to find it is to use the search box.</section></section><section id=subsec:enable-usb-debugging class=level3 data-number=3.1.2><h3 data-number=3.1.2><span class=header-section-number>3.1.2</span>\n<a href=#toc:subsec:enable-usb-debugging>啟用USB調試</a><a href=#subsec:enable-usb-debugging class=anchor aria-hidden=true></a></h3><p>After <a href=#subsubsec:location-of-developer-options>locating the\ndeveloper options</a>, enable <strong>Developer option</strong> (if not\nalready). After that, scroll down a bit until you will find the option\n<strong>USB debugging</strong>. Use the toggle button on the right-hand\nside to enable it. At this point, you may get an alert prompt where you\nmay have to click <em>OK</em> to actually enable it. You may also have\nto enable some other options depending on device vendor and ROM. Here\nare some examples:<section id=小米-miui class=level4 data-number=3.1.2.1><h4 data-number=3.1.2.1><span class=header-section-number>3.1.2.1</span> 小米 (MIUI)<a href=#小米-miui class=anchor aria-hidden=true></a></h4><p>Enable <strong>USB debugging (Security settings)</strong> as\nwell.</section><section id=華為-emui class=level4 data-number=3.1.2.2><h4 data-number=3.1.2.2><span class=header-section-number>3.1.2.2</span> 華為 (EMUI)<a href=#華為-emui class=anchor aria-hidden=true></a></h4><p>Enable <strong>Allow ADB debugging in charge only mode</strong> as\nwell. When connecting to your PC or Mac, you may get a prompt saying\n<strong>Allow access to device data?</strong> in which case click\n<strong>YES, ALLOW ACCESS</strong>.<div class=\"amalert tip\"><p><strong><em>Notice.</em></strong><p>Often the <strong>USB debugging</strong> mode could be disabled\nautomatically by the system. If that’s the case, repeat the above\nprocedure.</div></section><section id=realme class=level4 data-number=3.1.2.3><h4 data-number=3.1.2.3><span class=header-section-number>3.1.2.3</span> Realme<a href=#realme class=anchor aria-hidden=true></a></h4><p>Depending on the device and the version of operating system, you have\nto enable <strong>Disable Permission Monitoring</strong>, or <strong>USB\ndebugging (Security settings)</strong> along with <strong>Install via\nUSB</strong>.</section><section id=oneplus-oxygen-os class=level4 data-number=3.1.2.4><h4 data-number=3.1.2.4><span class=header-section-number>3.1.2.4</span> OnePlus (Oxygen OS)<a href=#oneplus-oxygen-os class=anchor aria-hidden=true></a></h4><p>Depending on the device and the version of operating system, you have\nto enable <strong>Disable Permission Monitoring</strong>.</section><section id=lg class=level4 data-number=3.1.2.5><h4 data-number=3.1.2.5><span class=header-section-number>3.1.2.5</span> LG<a href=#lg class=anchor aria-hidden=true></a></h4><p>Make sure you have <strong>USB tethering</strong> enabled.</section><section id=故障排除 class=level4 data-number=3.1.2.6><h4 data-number=3.1.2.6><span class=header-section-number>3.1.2.6</span> 故障排除<a href=#故障排除 class=anchor aria-hidden=true></a></h4><p>In case <strong>USB Debugging</strong> is greyed out, you can do the\nfollowing:<ol class=incremental><li><p>Make sure you enabled USB debugging before connecting your phone\nto the PC or Mac via USB cable<li><p>Enable USB tethering after connecting to PC or Mac via USB\ncable<li><p>(For Samsung) If your device is running KNOX, you may have to\nfollow some additional steps. See official documentations or consult\nsupport for further assistant</ol></section></section><section id=subsec:setup-adb-on-pc-or-mac class=level3 data-number=3.1.3><h3 data-number=3.1.3><span class=header-section-number>3.1.3</span>\n<a href=#toc:subsec:setup-adb-on-pc-or-mac>在PC或Mac上配置ADB</a><a href=#subsec:setup-adb-on-pc-or-mac class=anchor aria-hidden=true></a></h3><p>In order to enable ADB over TCP, you have to set up ADB in your PC or\nMac. <strong><em>Lineage OS users can skip to §<a href=#subsubsec:lineage-os data-reference-type=ref data-reference=subsubsec:lineage-os>3.1.4.1</a>.</em></strong><section id=windows class=level4 data-number=3.1.3.1><h4 data-number=3.1.3.1><span class=header-section-number>3.1.3.1</span> Windows<a href=#windows class=anchor aria-hidden=true></a></h4><ol class=incremental><li><p>Download the latest version of <a href=https://dl.google.com/android/repository/platform-tools-latest-windows.zip>Android\nSDK Platform-Tools</a> for Windows<li><p>Extract the contents of the zip file into any directory (such as\n<code>C:\\</code><span><code>adb</code></span>) and navigate to that\ndirectory using <em>Explorer</em><li><p>Open <strong>Command Prompt</strong>,\n<strong>PowerShell</strong>, or <strong>Terminal</strong> from this\ndirectory. You can do it manually from the start menu or by holding\n<code>Shift</code> and right clicking within the directory in <em>File\nExplorer</em> and then clicking either on <em>Open command window\nhere</em>, or <em>Open PowerShell window here</em> (depending on what\nyou have installed). You can now access ADB by typing <code>adb</code>\n(Command Prompt) or <code>./adb</code> (PowerShell). Do not close this\nwindow yet.</ol><div class=\"amalert tip\"><p><strong><em>Tip.</em></strong><p>If you have <a href=https://learn.microsoft.com/en-us/windows/package-manager/winget/>WinGet</a>\ninstalled, you can install ADB using the following command:<div class=sourceCode id=cb3 data-frame=lines><pre class=\"sourceCode bash\"><code class=\"sourceCode bash\"><span id=cb3-1><a href=#cb3-1 aria-hidden=true tabindex=-1></a><span class=ex>winget</span> install <span class=at>--id</span> Google.PlatformTools</span></code></pre></div><p>After that, you can simply type <code>adb</code> to access ADB.</div></section><section id=macos class=level4 data-number=3.1.3.2><h4 data-number=3.1.3.2><span class=header-section-number>3.1.3.2</span> macOS<a href=#macos class=anchor aria-hidden=true></a></h4><ol class=incremental><li><p>Download the latest version of <a href=https://dl.google.com/android/repository/platform-tools-latest-darwin.zip>Android\nSDK Platform-Tools</a> for macOS<li><p>Extract the contents of the zip file into a directory by clicking\non it. After that, navigate to that directory using <em>Finder</em> and\nlocate <code>adb</code><li><p>Open <strong>Terminal</strong> using <em>Launchpad</em> or\n<em>Spotlight</em> and drag-and-drop <code>adb</code> from the\n<em>Finder</em> window into the <em>Terminal</em> window. Do not close\nthe <em>Terminal</em> window yet</ol><div class=\"amalert tip\"><p><strong><em>Tip.</em></strong><p>If you have <a href=https://brew.sh>Homebrew</a> installed, you can\ninstall ADB using the following command:<div class=sourceCode id=cb4 data-frame=lines><pre class=\"sourceCode bash\"><code class=\"sourceCode bash\"><span id=cb4-1><a href=#cb4-1 aria-hidden=true tabindex=-1></a><span class=ex>brew</span> install <span class=at>--cask</span> android-platform-tools</span></code></pre></div><p>After that, you can simply type <code>adb</code> in any\n<em>Terminal</em> window to access ADB.</div></section><section id=linux class=level4 data-number=3.1.3.3><h4 data-number=3.1.3.3><span class=header-section-number>3.1.3.3</span> Linux<a href=#linux class=anchor aria-hidden=true></a></h4><ol class=incremental><li><p>In your favourite terminal emulator, run the following\ncommand:<div class=sourceCode id=cb5 data-frame=lines data-autogobble><pre class=\"sourceCode bash\"><code class=\"sourceCode bash\"><span id=cb5-1><a href=#cb5-1 aria-hidden=true tabindex=-1></a><span class=bu>cd</span> ~/Downloads <span class=kw>&amp;&amp;</span> <span class=ex>curl</span> <span class=at>-o</span> platform-tools.zip <span class=at>-L</span> <span class=dt>\\</span></span>\n<span id=cb5-2><a href=#cb5-2 aria-hidden=true tabindex=-1></a>https://dl.google.com/android/repository/platform-tools-latest-linux.zip <span class=kw>&amp;&amp;</span> <span class=dt>\\</span></span>\n<span id=cb5-3><a href=#cb5-3 aria-hidden=true tabindex=-1></a><span class=fu>unzip</span> platform-tools.zip <span class=kw>&amp;&amp;</span> <span class=fu>rm</span> platform-tools.zip <span class=kw>&amp;&amp;</span> <span class=bu>cd</span> platform-tools</span></code></pre></div><li><p>If it is successful, you can simply type <code>./adb</code> in\nthe in <em>same</em> terminal emulator window or type\n<code>~/Downloads/platform-tools/adb</code> in any terminal emulator to\naccess ADB.</ol></section></section><section id=subsec:configure-adb-over-tcp class=level3 data-number=3.1.4><h3 data-number=3.1.4><span class=header-section-number>3.1.4</span>\n<a href=#toc:subsec:configure-adb-over-tcp>配置經由TCP的ADB</a><a href=#subsec:configure-adb-over-tcp class=anchor aria-hidden=true></a></h3><section id=subsubsec:lineage-os class=level4 data-number=3.1.4.1><h4 data-number=3.1.4.1><span class=header-section-number>3.1.4.1</span> Lineage OS<a href=#subsubsec:lineage-os class=anchor aria-hidden=true></a></h4><p>Lineage OS (or its derivatives) users can directly enable ADB over\nTCP using the developer options. To enable that, go to the\n<strong>Developer options</strong>, scroll down until you find\n<strong>ADB over Network</strong>. Now, use the toggle button on the\nright-hand side to enable it and skip to §<a href=#subsubsec:adb-mode-in-app-manager data-reference-type=ref data-reference=subsubsec:adb-mode-in-app-manager>3.1.4.3</a>.<div class=\"amalert warning\"><p><strong><em>Warning.</em></strong><p>You can turn off <strong>ADB over Network</strong> in developer\noptions, but turning off this option will also stop App Manager’s remote\nserver. So, turn it off only when you’re not going to use App Manager in\nADB over TCP mode.</div></section><section id=subsubsec:enable-adb-over-tcp-via-pc-or-mac class=level4 data-number=3.1.4.2><h4 data-number=3.1.4.2><span class=header-section-number>3.1.4.2</span> 在 PC 或 Mac 上啟用\n經由TCP的ADB<a href=#subsubsec:enable-adb-over-tcp-via-pc-or-mac class=anchor aria-hidden=true></a></h4><p>For other ROMs, you can do this using the command\nprompt/PowerShell/terminal emulator that you’ve opened in the step 3 of\nthe previous section. In this section, I will use <code>adb</code> to\ndenote <code>./adb</code>, <code>adb</code> or any other command that\nyou needed to use based on your platform and software in the previous\nsection.<ol class=incremental><li><p>Connect your device to your PC or Mac using a USB cable. For some\ndevices, it is necessary to turn on <em>File transfer mode (MTP)</em> as\nwell<li><p>To confirm that everything is working as expected, type\n<code>adb devices</code> in your terminal. If your device is connected\nsuccessfully, you will see something like this:<pre><code>List of devices attached\nxxxxxxxx  device</code></pre><div class=\"amalert tip\"><p><strong><em>Notice.</em></strong><p>In some Android phones, an alert prompt will be appeared with a\nmessage <strong>Allow USB Debugging</strong> in which case, check\n<em>Always allow from this computer</em> and click\n<strong>Allow</strong>.</div><li><p>Finally, run the following command to enable ADB over TCP:<div class=sourceCode id=cb7 data-frame=lines data-autogobble><pre class=\"sourceCode bash\"><code class=\"sourceCode bash\"><span id=cb7-1><a href=#cb7-1 aria-hidden=true tabindex=-1></a><span class=ex>adb</span> tcpip 5555</span></code></pre></div></ol><div class=\"amalert danger\"><p><strong><em>Danger.</em></strong><p>You cannot disable developer options or USB debugging after enabling\nADB over TCP.</div></section><section id=subsubsec:adb-mode-in-app-manager class=level4 data-number=3.1.4.3><h4 data-number=3.1.4.3><span class=header-section-number>3.1.4.3</span> 在App\nManager上啟用ADB模式<a href=#subsubsec:adb-mode-in-app-manager class=anchor aria-hidden=true></a></h4><p>After enabling ADB over TCP, relaunch App Manager. App Manager should\ndetect ADB mode automatically. If it cannot, you can change the mode of\noperation to ADB over TCP in the <a href=#subsec:mode-of-operation>settings page</a>. There, you can also\nverify whether App Manager has correctly detected ADB as indicated by\nthe <em>inferred mode</em>.<div class=\"amalert tip\"><p><strong><em>Notice.</em></strong><p>In some Android devices, the USB cable is needed to be disconnected\nfrom the PC before connecting to App Manager.</div><div class=\"amalert warning\"><p><strong><em>Warning.</em></strong><p>ADB over TCP will be disabled after a reboot. In that case, you have\nto follow §<a href=#subsubsec:enable-adb-over-tcp-via-pc-or-mac data-reference-type=ref data-reference=subsubsec:enable-adb-over-tcp-via-pc-or-mac>3.1.4.2</a>\nagain.</div></section></section></section><section id=sec:wireless-debugging class=level2 data-number=3.2><h2 data-number=3.2><span class=header-section-number>3.2</span> <a href=#toc:sec:wireless-debugging>Wireless Debugging</a><a href=#sec:wireless-debugging class=anchor aria-hidden=true></a></h2><p>If you are running Android 11 or later and capable of connecting to a\nWi-Fi network for, at least, a few moments, Wireless Debugging is the\nrecommended approach as it offers more protection than <a href=#sec:adb-over-tcp>ADB over TCP</a>. It requires two steps:<ol class=incremental><li><p><strong>ADB pairing.</strong> The initial and a bit complex step\nfor a novice user. Fortunately, this step is not required all the\ntime.<li><p><strong>Connecting to ADB.</strong> Needs to be done every time\nyou reboot your phone. App Manager can also automate this step in most\ndevices.</ol><section id=subsec:enable-developer-options-and-usb-debugging class=level3 data-number=3.2.1><h3 data-number=3.2.1><span class=header-section-number>3.2.1</span>\n<a href=#toc:subsec:enable-developer-options-and-usb-debugging>Enable\ndeveloper options and USB Debugging</a><a href=#subsec:enable-developer-options-and-usb-debugging class=anchor aria-hidden=true></a></h3><p>See §<a href=#subsec:enable-developer-options data-reference-type=ref data-reference=subsec:enable-developer-options>3.1.1</a> and §<a href=#subsec:enable-usb-debugging data-reference-type=ref data-reference=subsec:enable-usb-debugging>3.1.2</a>.</section><section id=subsec:enable-wireless-debugging class=level3 data-number=3.2.2><h3 data-number=3.2.2><span class=header-section-number>3.2.2</span>\n<a href=#toc:subsec:enable-wireless-debugging>Enable Wireless\nDebugging</a><a href=#subsec:enable-wireless-debugging class=anchor aria-hidden=true></a></h3><p>In the <strong>Developer options</strong> page, find <strong>Wireless\ndebugging</strong> and click to open it. In the new page, turn on\n<em>Use wireless debugging</em>. Depending on the operating system, you\nmight see a dialog prompt asking you to verify your decision. If that is\nthe case, click <em>Allow</em>.<div class=\"amalert tip\"><p><strong><em>Tip.</em></strong><p>For easy access, you might want to add <strong>Wireless\ndebugging</strong> in the notification tiles section. To do this, find\n<strong>Quick settings developer tiles</strong> in the <strong>Developer\noptions</strong> page and click to open it. In the new window, enable\n<em>Wireless debugging</em>. In case you do not see this setting, you\nmay find a <strong>Wireless debugging</strong> tile in the tile\ncustomization panel.</div></section><section id=subsec:pair-adb-with-app-manager class=level3 data-number=3.2.3><h3 data-number=3.2.3><span class=header-section-number>3.2.3</span>\n<a href=#toc:subsec:pair-adb-with-app-manager>Pair ADB with App\nManager</a><a href=#subsec:pair-adb-with-app-manager class=anchor aria-hidden=true></a></h3><p>In App Manager, navigate to <strong>Settings</strong> > <a href=#subsec:mode-of-operation>Mode of operation</a> and then enable\n<em>Wireless debugging</em>. At this, App Manager will try to establish\na wireless debugging connection automatically which will fail if it has\nnot been paired before. Once it fails, it will ask you to either connect\nor pair ADB. Select <em>pair</em> and a new dialog will appear. It will\nask you to navigate to the <strong>Wireless debugging</strong> page.<div class=\"amalert tip\"><p><strong><em>Note.</em></strong><p>As of v4.0.0, pairing is done using a notification prompt. So, if you\nhave disabled notification for App Manager, you must enable it\nfirst.</div><p>In the <strong>Wireless debugging</strong> page, select <strong>Pair\ndevice with pairing code</strong>. At this, a dialog containing a\npairing code will be displayed. A notification asking for the pairing\ncode will also be visible almost instantly. Insert the pairing code in\nthe input box in the notification and click <em>pair</em>. If the\npairing is successful, App Manager will display notification with the\nmessage “paired”, and the dialog in the <strong>Wireless\ndebugging</strong> page will be dismissed automatically. You will also\nbe able to see App Manager listed as an ADB client in the same page.<div class=\"amalert tip\"><p><strong><em>Notice.</em></strong><p>If you do not use App Manager in ADB mode for a while, App Manager\nmight be removed from the list of clients. In that case, you have to\nrepeat the above procedure.</div></section><section id=subsec:connect-app-manager-to-adb class=level3 data-number=3.2.4><h3 data-number=3.2.4><span class=header-section-number>3.2.4</span>\n<a href=#toc:subsec:connect-app-manager-to-adb>Connect App Manager to\nADB</a><a href=#subsec:connect-app-manager-to-adb class=anchor aria-hidden=true></a></h3><p>App Manager should be able to connect to ADB automatically if the\nmode of operation is set to <em>auto</em>, <em>ADB over TCP</em> or\n<em>Wireless debugging</em>. If this is not the case, select\n<em>Wireless debugging</em> in <strong>Settings</strong> > <a href=#subsec:mode-of-operation>Mode of operation</a>. If App Manager\nfails to detect or connect to ADB, it will ask you to connect or pair\nADB. Select <em>connect</em>.<p>Now, navigate to the <strong>Wireless debugging</strong> page in\nAndroid settings, and note down the port number displayed in the page.\nIn App Manager’s dialog prompt, replace the port number with the one you\nhave noted earlier, and click <em>connect</em>.<p>Once a connection has been established, you can disable\n<strong>Wireless debugging</strong> in Android settings.<div class=\"amalert danger\"><p><strong><em>Caution.</em></strong><p>Never disable <strong>USB Debugging</strong> or any other additional\noptions described in §<a href=#subsec:enable-developer-options-and-usb-debugging data-reference-type=ref data-reference=subsec:enable-developer-options-and-usb-debugging>3.2.1</a>.\nIf you do this, the remote server used by App Manager will be stopped,\nand you may have to start all over again.</div></section></section><section id=sec:backup-restore class=level2 data-number=3.3><h2 data-number=3.3><span class=header-section-number>3.3</span> <a href=#toc:sec:backup-restore>備份/恢覆</a><a href=#sec:backup-restore class=anchor aria-hidden=true></a></h2><p>App Manager has a modern, advanced and easy-to-use backup/restore\nsystem implemented from the scratch. This is probably the only app that\nhas the ability to restore not only the app or its data but also\npermissions and rules that you’ve configured within App Manager. You can\nalso choose to back up an app multiple times (with custom names) or for\nall users.<div class=seealso><p><em>See also:</em><ul class=incremental><li><p><a href=#subsec:1-click-back-up>1-Click Ops: Back\nup</a><li><p><a href=#subsec:1-click-restore>1-Click Ops:\nRestore</a></ul></div><section id=subsec:backup-location class=level3 data-number=3.3.1><h3 data-number=3.3.1><span class=header-section-number>3.3.1</span>\n<a href=#toc:subsec:backup-location>位置</a><a href=#subsec:backup-location class=anchor aria-hidden=true></a></h3><p>Back up/restore is a part of <a href=#subsec:batch-operations>batch\noperations</a>. It is also located inside the <a href=#subsubsec:app-info-options-menu>options menu</a> in the <a href=#subsec:app-info-tab>App Info tab</a>. Clicking on\n<strong>Backup/Restore</strong> opens the <strong>Backup\nOptions</strong>. Backups are located at\n<code>/storage/emulated/0/AppManager</code> by default. You can\nconfigure custom backup location in the <a href=#subsubsec:backup-volume>settings page</a> in which case the\nbackups will be located at the <code>AppManager</code> folder in the\nselected volume.<div class=\"amalert tip\"><p><strong><em>Note.</em></strong><p>If one or more selected apps do not have any backup, the\n<strong>Restore</strong> and <strong>Delete Backup</strong> options will\nnot be displayed.</div></section><section id=subsec:backup-restore-backup-options class=level3 data-number=3.3.2><h3 data-number=3.3.2><span class=header-section-number>3.3.2</span>\n<a href=#toc:subsec:backup-restore-backup-options>備份選項</a><a href=#subsec:backup-restore-backup-options class=anchor aria-hidden=true></a></h3><p>Backup options (internally known as backup flags) let you customise\nthe backups on the fly. However, the customisations will not be\nremembered for the future backups. If you want to customise this dialog,\nuse <a href=#subsubsec:settings-backup-options>Backup Options</a> in\nthe <a href=#sec:settings-page>Settings page</a>.<p>A complete description of the backup options is given below:<ul class=incremental><li><p><strong>APK files.</strong> Whether to back up the APK files.\nThis includes the <em>base APK</em> file along with the\n<code>split APK</code> files if they exist.<li><p><strong>Internal data.</strong> Whether to back up the internal\ndata directories. These directories are located at\n<code>/data/user/&lt;user_id></code> and (for Android N or later)\n<code>/data/user_de/&lt;user_id></code>.<li><p><strong>External data.</strong> Whether to back up data\ndirectories located in the internal memory as well as SD Card (if\nexists). External data directories often contain non-essential app data\nor media files (instead of using the dedicated media folder) and may\nincrease the backup size. However, it might be essential for some apps.\nAlthough it isn’t checked by default (as it might dramatically increase\nthe size of the backups), you may have to check it in order to ensure a\nsmooth restore of your backups.<div class=\"amalert warning\"><p><strong><em>Caution.</em></strong><p>Internal data folders should always be backed up if you are going to\nback up the external data folders. However, it could be useful to back\nup only the external folders if the app in question downloads a lot of\nassets from the Internet.</div><li><p><strong>OBB and media.</strong> Whether to back up or restore the\nOBB and the media directories located in the external storage or the SD\nCard. This is useful for games and the graphical software which actually\nuse these folders.<li><p><strong>Cache.</strong> Android apps have multiple cache\ndirectories located at every data directories (both internal and\nexternal). There are two types of cache: <strong>cache</strong> and\n<strong>code cache</strong>. Disabling this option excludes both cache\ndirectories from all the data directories. It is generally advised to\nexclude cache directories since most apps do not clear the cache\nregularly and usually handled by the OS itself. Apps such as Telegram\nmay use a very large cache (depending on the storage space) which may\ndramatically increase the backup size. When it is disabled, AM also\nignores the <strong>no_backup</strong> directories.<li><p><strong>Extras.</strong> Backup/restore app permissions, net\npolicy, battery optimization, SSAID, etc., enabled by default. Note\nthat, blocking rules are applied <em>after</em> applying the extras. So,\nif an item is present in both places, it will be overwritten (i.e., the\none from the blocking rules will be used).<li><p><strong>Rules.</strong> This option lets you back up blocking\nrules configured within App Manager. This might come in handy if you\nhave customised permissions or block some components using App Manager\nas they will also be backed up or restored when you enable this\noption.<li><p><strong>Backup Multiple.</strong> Whether this is a multiple\nbackup. By default, backups are saved using their user ID. Enabling this\noption allows you to create additional backups. These backups use the\ncurrent date-time as the default backup name, but you can also specify\ncustom backup name using the input field displayed when you click on the\n<strong>Backup</strong> button.<li><p><strong>Custom users.</strong> Backup or restore for the selected\nusers instead of only the current user. This option is only displayed if\nthe system has more than one user.<li><p><strong>Skip signature checks.</strong> When taking a backup,\nchecksum of every file (as well as the signing certificate(s) of the\nbase APK file) is generated and stored in the <code>checksums.txt</code>\nfile. When you restore the backup, the checksums are generated again and\nare matched with the checksums stored in the said file. Enabling this\noption will disable the signature checks. This option is applied only\nwhen you restore a backup. During backup, the checksums are generated\nregardless of this option.<div class=\"amalert warning\"><p><strong><em>Caution.</em></strong><p>You should always disable this option to ensure that your backups are\nnot modified by any third-party applications. However, this would only\nwork if you enabled encryption.</div></ul><div class=seealso-inline><p><em>See also: <span><a href=#subsubsec:settings-encryption>Settings:\nEncryption</a></span></em></div></section><section id=subsec:backup-restore-backup class=level3 data-number=3.3.3><h3 data-number=3.3.3><span class=header-section-number>3.3.3</span>\n<a href=#toc:subsec:backup-restore-backup>備份</a><a href=#subsec:backup-restore-backup class=anchor aria-hidden=true></a></h3><p>Backup respects all the backup options except <strong>Skip signature\nchecks</strong>. If base backups (i.e., backups that don’t have the\n<strong>Backup Multiple</strong> option) already exist, you will get a\nwarning as the backups will be overwritten. If <strong>Backup\nMultiple</strong> is set, you have an option to input the backup name,\nor you can leave it blank to use the current date-time.</section><section id=subsec:backup-restore-restore class=level3 data-number=3.3.4><h3 data-number=3.3.4><span class=header-section-number>3.3.4</span>\n<a href=#toc:subsec:backup-restore-restore>恢覆</a><a href=#subsec:backup-restore-restore class=anchor aria-hidden=true></a></h3><p>Restore respects all the backup options and will fail if <strong>APK\nfiles</strong> option is set, but the backup doesn’t contain such\nbackups or in other cases, if the app isn’t installed. When restoring\nbackups for multiple packages, you can only restore the base backups\n(see <a href=#subsec:backup-restore-backup>backup</a> section for an\nexplanation). However, when restoring backups for a single package, you\nhave the option to select which backup to restore. If <strong>All\nusers</strong> option is set, AM will restore the selected backup for\nall users in the latter case but in the former case, it will restore\nbase backups for the respective users.<div class=\"amalert tip\"><p><strong><em>Notice.</em></strong><p>Apps that use storage access framework (SAF), SSAID or Android\nKeyStore works properly only after an immediate restart.</div></section><section id=subsec:backup-restore-delete-backup class=level3 data-number=3.3.5><h3 data-number=3.3.5><span class=header-section-number>3.3.5</span>\n<a href=#toc:subsec:backup-restore-delete-backup>刪除備份</a><a href=#subsec:backup-restore-delete-backup class=anchor aria-hidden=true></a></h3><p>Delete backup only respects <strong>All users</strong> option and\nwhen it is selected, only the base backups for all users will be deleted\nwith a prompt. When deleting backups for a single package, another\ndialog will be displayed where you can select the backups to delete.</section></section><section id=sec:automating-tasks class=level2 data-number=3.4><h2 data-number=3.4><span class=header-section-number>3.4</span> <a href=#toc:sec:automating-tasks>Automating Tasks</a><a href=#sec:automating-tasks class=anchor aria-hidden=true></a></h2><p>It is possible to trigger profiles configured inside App Manager via\nthird-party applications such as <strong>Automation</strong> or\n<strong>Tasker</strong>. Traditionally, <code>Intent</code>s are used to\ntrigger such operations.<section id=subsec:generating-authorization-key class=level3 data-number=3.4.1><h3 data-number=3.4.1><span class=header-section-number>3.4.1</span>\n<a href=#toc:subsec:generating-authorization-key>Generating\nauthorization key</a><a href=#subsec:generating-authorization-key class=anchor aria-hidden=true></a></h3><p>In order to ensure proper security, an authorization key is required.\nTo generate a authorization key, go to <strong>Settings</strong> page\nand then <strong>Privacy</strong> > <strong>Authorization\nManager</strong>. If an authorization key has not been generated, it\nwill be generated automatically. The key can be regenerated as\nrequired.<div class=\"amalert danger\"><p><strong><em>Caution.</em></strong><p>Regenerating the authorization key can have some side effects such as\ninvalidation of all the previously configured Intents.</div></section><section id=subsec:at:general-configuration class=level3 data-number=3.4.2><h3 data-number=3.4.2><span class=header-section-number>3.4.2</span>\n<a href=#toc:subsec:at:general-configuration>Configuring tasks</a><a href=#subsec:at:general-configuration class=anchor aria-hidden=true></a></h3><p>The activity\n<code>io.github.muntashirakon.AppManager.crypto.auth.AuthFeatureDemultiplexer</code>\nis responsible for handling all the automations. Sending an intent to\nthe activity lets App Manager perform the designated operation by\nredirecting the <code>Intent</code> to the designated activity or\nservice.<section id=required-extras class=level4 data-number=3.4.2.1><h4 data-number=3.4.2.1><span class=header-section-number>3.4.2.1</span> Required extras<a href=#required-extras class=anchor aria-hidden=true></a></h4><p>It has two primary extras required in all conditions. The key names,\ndata types are all follows:<ol class=incremental><li><p><strong><code>auth</code>.</strong> (String value) The\nauthorization key as described in the earlier section.<li><p><strong><code>feature</code>.</strong> (String value) Name of the\nfeature. Supported features are described in the next section.</ol></section></section><section id=subsec:at:features class=level3 data-number=3.4.3><h3 data-number=3.4.3><span class=header-section-number>3.4.3</span>\n<a href=#toc:subsec:at:features>Features</a><a href=#subsec:at:features class=anchor aria-hidden=true></a></h3><p>App Manager current support a single feature, namely\n<code>profile</code>.</section><section id=subsec:triggering-a-profile class=level3 data-number=3.4.4><h3 data-number=3.4.4><span class=header-section-number>3.4.4</span>\n<a href=#toc:subsec:triggering-a-profile>Triggering a profile</a><a href=#subsec:triggering-a-profile class=anchor aria-hidden=true></a></h3><p>In order to trigger a profile, <code>feature</code> must have the\nvalue <code>profile</code>. In addition, the following extras can be\nincluded:<ol class=incremental><li><p><strong><code>prof</code>.</strong> (String value – required) The\nname of the profile as displayed in the <a href=#sec:profiles-page>Profiles page</a>.<li><p><strong><code>state</code>.</strong> (String value – optional)\nState of the profile – currently <code>on</code> or <code>off</code> –\nas specified in the documentation. If this extra is not set, App Manager\nwill display a prompt where a state must be selected. Therefore, for\ncomplete automation, this option should be set.</ol></section></section><section id=sec:net-policy class=level2 data-number=3.5><h2 data-number=3.5><span class=header-section-number>3.5</span> <a href=#toc:sec:net-policy>連網策略</a><a href=#sec:net-policy class=anchor aria-hidden=true></a></h2><p>Short for <strong>Network policy</strong> or network policies. It is\nusually located in the Android settings under <strong>Mobile data &\nWifi</strong> section in the app info page of an app. Not all policies\nare guaranteed to be included in this page (e.g. Samsung), and not all\nsettings are well-understood due to lack of documentation. App Manager\ncan display all the net policies declared in the <a href=https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/net/NetworkPolicyManager.java>NetworkPolicyManager</a>.\nPolicies unknown to App Manager will have a <em>Unknown</em> prefix\nalong with the policy constant name and number in the hexadecimal\nformat. Unknown policies should be reported to App Manager for\ninclusion.<p>Net policy allows a user to configure certain networking behaviour of\nan app without modifying the ip tables directly and/or running a\nfirewall app. However, the features it offers largely depend on Android\nversion and ROM. A list of known net policies are listed below:<ol class=incremental><li><p><strong>None</strong> or\n<strong><code>POLICY_NONE</code></strong>: (AOSP) No specific network\npolicy is set. System can still assign rules depending on the nature of\nthe app.<li><p><strong>Reject background data on metered networks</strong> or\n<strong><code>POLICY_REJECT_METERED_BACKGROUND</code></strong>: (AOSP)\nReject network usage on metered networks when the application is in\nbackground.<li><p><strong>Allow background data on metered networks even when Data\nSaver is on</strong> or\n<strong><code>POLICY_ALLOW_METERED_BACKGROUND</code></strong>: (AOSP)\nAllow metered network use in the background even when data saving mode\nis enabled.<li><p><strong>Reject cellular data</strong> or\n<strong><code>POLICY_REJECT_CELLULAR</code></strong> (Android 11+) or\n<strong><code>POLICY_REJECT_ON_DATA</code></strong> (up to Android 10):\n(Lineage OS) Reject mobile/cellular data. Signals network unavailable to\nthe configured app as if the mobile data is inactive.<li><p><strong>Reject VPN data</strong> or\n<strong><code>POLICY_REJECT_VPN</code></strong> (Android 11+) or\n<strong><code>POLICY_REJECT_ON_VPN</code></strong> (up to Android 10):\n(Lineage OS) Reject VPN data. Signals network unavailable to the\nconfigured app as if the VPN is inactive.<li><p><strong>Reject Wi-Fi data</strong> or\n<strong><code>POLICY_REJECT_WIFI</code></strong> (Android 11+) or\n<strong><code>POLICY_REJECT_ON_WLAN</code></strong> (up to Android 10):\n(Lineage OS) Reject Wi-Fi data. Signals network unavailable to the\nconfigured app as if the device is not connected to a Wi-Fi\nnetwork.<li><p><strong>Disable network access</strong> or\n<strong><code>POLICY_REJECT_ALL</code></strong> (Android 11+) or\n<strong><code>POLICY_NETWORK_ISOLATED</code></strong> (up to Android\n10): (Lineage OS) Reject network access in all circumstances. This is\nnot the same as enforcing the other three policies above, and is the\nrecommended policy for dodgy apps. If this policy is enforced, there is\nno need to enforce the other policies.<li><p><strong><code>POLICY_ALLOW_METERED_IN_ROAMING</code></strong>:\n(Samsung) Possibly allow metered network use during roaming. Exact\nmeaning is currently unknown.<li><p><strong><code>POLICY_ALLOW_WHITELIST_IN_ROAMING</code></strong>:\n(Samsung) Possibly allow network use during roaming. Exact meaning is\ncurrently unknown.<li><p><strong>Reject data on metered networks</strong> or\n<strong><code>POLICY_REJECT_METERED</code></strong>: (Motorola) Reject\nnetwork usage if it is a metered network.<li><p><strong>Reject background data</strong> or\n<strong><code>POLICY_REJECT_BACKGROUND</code></strong>: (Motorola)\nReject network usage in the background.<li><p><strong>Disable network access</strong> or\n<strong><code>POLICY_REJECT_ALL</code></strong>: (Motorola) Reject\nnetwork access altogether. Like Lineage OS, it blocks internet\nconnections via iptables. But whether it signals the unavailability of\nnetwork to the configured app is not known.</ol><div class=\"amalert tip\"><p><strong><em>Note.</em></strong><p>Corresponding Lineage OS patches are as follows:<ol class=incremental><li><p><a href=https://github.com/LineageOS/android_frameworks_base/commit/a04932bafbbf7d99efd18276152cc2c9c9b2073e>fw/b:\nSquash of app fw restriction commits</a><li><p><a href=https://github.com/LineageOS/android_frameworks_base/commit/02c8c82854348f52afe2199f310f44b5f578b5b8>fw/b:\nAdd support for per app network isolation</a></ol></div></section></section><section id=ch:faq class=level1 data-number=4><h1 data-number=4><span class=header-section-number>4</span> <a href=#toc:ch:faq>常見問題</a><a href=#ch:faq class=anchor aria-hidden=true></a></h1><section id=sec:faq:app-components class=level2 data-number=4.1><h2 data-number=4.1><span class=header-section-number>4.1</span> <a href=#toc:sec:faq:app-components>應用組件</a><a href=#sec:faq:app-components class=anchor aria-hidden=true></a></h2><section id=subsec:faq:what-are-app-components class=level3 data-number=4.1.1><h3 data-number=4.1.1><span class=header-section-number>4.1.1</span>\n<a href=#toc:subsec:faq:what-are-app-components>什麽是應用組件？</a><a href=#subsec:faq:what-are-app-components class=anchor aria-hidden=true></a></h3><p>Activities, services, broadcast receivers (or only receivers) and\ncontent providers (or only providers) are jointly called application\ncomponents. More technically, they all inherit the <a href=https://developer.android.com/reference/android/content/pm/ComponentInfo>ComponentInfo</a>\nclass and can be launched via Intent.</section><section id=subsec:faq:how-components-blocked class=level3 data-number=4.1.2><h3 data-number=4.1.2><span class=header-section-number>4.1.2</span>\n<a href=#toc:subsec:faq:how-components-blocked>追蹤器或其他組件在App\nManager中是如何被禁用的？其局限性是什麽？</a><a href=#subsec:faq:how-components-blocked class=anchor aria-hidden=true></a></h3><p>App Manager typically blocks application components (or tracker\ncomponents) using a method called <a href=https://carteryagemann.com/pages/android-intent-firewall.html>Intent\nFirewall (IFW)</a>, it is superior to other methods such as <em>pm</em>\n(PackageManager), <a href=https://github.com/RikkaApps/Shizuku>Shizuku</a> or any other\nmethod that uses the package manager to enable or disable the\ncomponents. If a component is disabled by the latter methods, the\napplication itself can detect that the component is being blocked and\ncan re-enable it as it has full access to its own components. (Many\ndeceptive applications actually do this in order to keep the tracker\ncomponents unblocked.) On the other hand, IFW is a true firewall and the\napplication cannot detect if its components are being blocked. App\nManager uses the term <em>block</em> rather than <em>disable</em> for\nthis reason.<p>Even IFW has some limitations which are primarily applicable for the\nsystem applications:<ul class=incremental><li><p>The application in question is whitelisted by the system i.e. the\nsystem cannot function properly without these applications and may cause\nrandom crashes. These applications include but not limited to Android\nSystem, System UI, Phone Services. They will continue to work even if\nthey are disabled or blocked.<li><p>Another system application or system process has activated a\nspecific component of the application in question via interprocess\ncommunication (IPC). In this case, the component will be activated\nregardless of blocking status or even if the entire application is\ndisabled. If there is such a system application that is not needed, the\nonly way to prevent it from running is by getting rid of it.</ul></section><section id=subsec:faq:components-blocked-by-others class=level3 data-number=4.1.3><h3 data-number=4.1.3><span class=header-section-number>4.1.3</span>\n<a href=#toc:subsec:faq:components-blocked-by-others>被其他工具禁用的應用程序組件是否保留在App\nManager中？</a><a href=#subsec:faq:components-blocked-by-others class=anchor aria-hidden=true></a></h3><p><strong>No.</strong> But the application components blocked by the\nsystem or any other tools are displayed in the <a href=#subsec:component-tabs>component tabs</a>. These rules can be\nimported from <a href=#par:import-existing-rules>Settings</a>.\nHowever, it is not possible for App Manager to distinguish the\ncomponents blocked by the third-party tools and components blocked by\nthe system. Therefore, the applications listed in the import page should\nbe selected with care.</section><section id=subsec:faq:components-reblocked-in-am class=level3 data-number=4.1.4><h3 data-number=4.1.4><span class=header-section-number>4.1.4</span>\n<a href=#toc:subsec:faq:components-reblocked-in-am>被 App Manager\n禁用但同時也被其他工具禁用的組件會發生什麽？</a><a href=#subsec:faq:components-reblocked-in-am class=anchor aria-hidden=true></a></h3><p><em>App Manager blocks the components again</em> if requested. In\ncase of unblocking, they will be reverted to the default state as\nspecified in the manifest of the application. But if the components were\nblocked by <a href=https://www.myandroidtools.com>MyAndroidTools\n(MAT)</a> with IFW method, they will not be unblocked by App Manager as\nit uses a different format. To fix this issue, the rules have to be\nimported from <a href=#par:import-existing-rules>Settings</a> at\nfirst, in which case MAT’s configurations will be permanently\nremoved.</section><section id=subsec:faq:what-is-instant-component-blocking class=level3 data-number=4.1.5><h3 data-number=4.1.5><span class=header-section-number>4.1.5</span>\n<a href=#toc:subsec:faq:what-is-instant-component-blocking>什麽是即時組件禁用？</a><a href=#subsec:faq:what-is-instant-component-blocking class=anchor aria-hidden=true></a></h3><p>When you block a component in the <a href=#sec:app-details-page>App\nDetails page</a>, the blocking is not applied by default. It is only\napplied when you apply blocking using the <em>Apply rules</em> option in\nthe top-right menu. If you enable <a href=#subsubsec:instant-component-blocking>instant component\nblocking</a>, blocking will be applied as soon as you block a component.\nIf you choose to block tracker components, however, blocking is applied\nautomatically regardless of this setting. You can also remove blocking\nfor an application by simply clicking on <em>Remove rules</em> in the\nsame menu in the <strong>App Details page</strong>. Since the default\nbehaviour gives you more control over applications, it is better to keep\n<em>instant component blocking</em> option disabled.</section><section id=subsec:tracker-classes-versus-tracker-components class=level3 data-number=4.1.6><h3 data-number=4.1.6><span class=header-section-number>4.1.6</span>\n<a href=#toc:subsec:tracker-classes-versus-tracker-components>跟蹤器類與跟蹤器組件</a><a href=#subsec:tracker-classes-versus-tracker-components class=anchor aria-hidden=true></a></h3><p>All application components are classes but not all classes are\ncomponents. In fact, only a few of the classes are components. That\nbeing said, <a href=#sec:scanner-page>scanner page</a> displays a list\nof trackers along with the number of classes, not just the components.\nIn all other pages, trackers and tracker components are used\nsynonymously to denote tracker components, i.e. blocking tracker means\nblocking tracker components, not tracker classes.<div class=\"amalert tip\"><p><strong><em>Info.</em></strong><p>Tracker classes that are not components cannot be blocked. They can\nonly be removed by editing the application itself.</div></section></section><section id=sec:faq:adb-over-tcp class=level2 data-number=4.2><h2 data-number=4.2><span class=header-section-number>4.2</span> <a href=#toc:sec:faq:adb-over-tcp>ADB over TCP (經由TCP的ADB)</a><a href=#sec:faq:adb-over-tcp class=anchor aria-hidden=true></a></h2><section id=subsec:faq:enable-adb-on-every-restart class=level3 data-number=4.2.1><h3 data-number=4.2.1><span class=header-section-number>4.2.1</span>\n<a href=#toc:subsec:faq:enable-adb-on-every-restart>我必須在每次重啟後啟用ADB\nover TCP嗎？</a><a href=#subsec:faq:enable-adb-on-every-restart class=anchor aria-hidden=true></a></h3><p>Unfortunately, yes. This is because the ADB daemon, the process\nresponsible for ADB connection, is also restarted after a reboot, and it\ndoes not re-enable ADB over TCP.</section><section id=subsec:faq:usb-debugging class=level3 data-number=4.2.2><h3 data-number=4.2.2><span class=header-section-number>4.2.2</span>\n<a href=#toc:subsec:faq:usb-debugging>無法啟用 USB\n調試，怎麽辦？</a><a href=#subsec:faq:usb-debugging class=anchor aria-hidden=true></a></h3><p>See §<a href=#subsec:enable-usb-debugging data-reference-type=ref data-reference=subsec:enable-usb-debugging>3.1.2</a> in Chapter <a href=#ch:guides data-reference-type=ref data-reference=ch:guides>3</a>.</section><section id=subsec:faq:block-components-using-adb class=level3 data-number=4.2.3><h3 data-number=4.2.3><span class=header-section-number>4.2.3</span>\n<a href=#toc:subsec:faq:block-components-using-adb>我可以使用 ADB over\nTCP 來禁用跟蹤器或任何其他應用程序組件嗎？</a><a href=#subsec:faq:block-components-using-adb class=anchor aria-hidden=true></a></h3><p>ADB has limited number of <a href=https://github.com/aosp-mirror/platform_frameworks_base/blob/master/packages/Shell/AndroidManifest.xml>permissions</a>\nand controlling application components is not one of them. However, the\ncomponents of a <em>test-only</em> app can be controlled via ADB. If App\nManager detects such an application, it enables the blocking options\nautomatically.</section><section id=subsec:faq:adb-features class=level3 data-number=4.2.4><h3 data-number=4.2.4><span class=header-section-number>4.2.4</span>\n<a href=#toc:subsec:faq:adb-features>哪些功能可以在ADB模式下使用？</a><a href=#subsec:faq:adb-features class=anchor aria-hidden=true></a></h3><p>Supported features are enabled automatically in the ADB mode.\nSupported features include disabling, force-stopping, clearing\napplication data, granting or revoking app ops and permissions, and so\non. It is also possible to install or uninstall applications without any\nprompt from the system.</section></section><section id=sec:faq:miscellanea class=level2 data-number=4.3><h2 data-number=4.3><span class=header-section-number>4.3</span> <a href=#toc:sec:faq:miscellanea>雜項</a><a href=#sec:faq:miscellanea class=anchor aria-hidden=true></a></h2><section id=subsec:faq:no-root-no-harms class=level3 data-number=4.3.1><h3 data-number=4.3.1><span class=header-section-number>4.3.1</span>\n<a href=#toc:subsec:faq:no-root-no-harms>我不使用root/ADB，是否完全安全？</a><a href=#subsec:faq:no-root-no-harms class=anchor aria-hidden=true></a></h3><p>Yes. AM cannot modify any system settings without root or ADB.</section><section id=subsec:faq:how-trackers-libs-updated class=level3 data-number=4.3.2><h3 data-number=4.3.2><span class=header-section-number>4.3.2</span>\n<a href=#toc:subsec:faq:how-trackers-libs-updated>跟蹤器和庫是如何更新的？</a><a href=#subsec:faq:how-trackers-libs-updated class=anchor aria-hidden=true></a></h3><p>Trackers and libraries are updated manually before making a new\nrelease.</section><section id=subsec:faq:apks-deleted-after-installed class=level3 data-number=4.3.3><h3 data-number=4.3.3><span class=header-section-number>4.3.3</span>\n<a href=#toc:subsec:faq:apks-deleted-after-installed>Are APKs deleted\nafter installed?</a><a href=#subsec:faq:apks-deleted-after-installed class=anchor aria-hidden=true></a></h3><p>No, APKs aren’t deleted by App Manager after they are installed.</section><section id=subsec:faq:shizuku-support class=level3 data-number=4.3.4><h3 data-number=4.3.4><span class=header-section-number>4.3.4</span>\n<a href=#toc:subsec:faq:shizuku-support>對於 Shizuku 有何計劃？</a><a href=#subsec:faq:shizuku-support class=anchor aria-hidden=true></a></h3><p>App Manager’s use of hidden API and privileged code execution is now\nmuch more complex and cannot be integrated with other third party apps\nsuch as <a href=https://shizuku.rikka.app>Shizuku</a>. Here are some\nreasons for not considering Shizuku (which now has Apache 2.0 license)\nfor App Manager:<ol class=incremental><li><p>Shizuku was initially non-free which led me to use a similar\napproach for App Manager to support both root and ADB<li><p>App Manager already supports both ADB and root which in some\ncases is more capable than Shizuku<li><p>Relying on a third-party app for the major functionalities is not\na good design choice<li><p>Integration of Shizuku will increase the complexity of App\nManager.</ol></section><section id=subsec:faq:what-are-bloatware class=level3 data-number=4.3.5><h3 data-number=4.3.5><span class=header-section-number>4.3.5</span>\n<a href=#toc:subsec:faq:what-are-bloatware>什麽是預裝(bloatware)軟件以及如何刪除？</a><a href=#subsec:faq:what-are-bloatware class=anchor aria-hidden=true></a></h3><p>Bloatware are the unnecessary pre-installed apps, usually system\napps. Some of the apps are often used to track users and collect user\ndata which they might sell for profits. Many system apps do not need to\nrequest any permission to access device info, contacts and messaging\ndata, and other usage info, such as your phone usage habits and\neverything you store on your shared storage(s).<p>The bloatware may also include Google apps, Meta apps, and Twitter/X\nwhich can also track users and/or collect user data without consent. You\ncan disable a few permissions from Android settings but be aware that\nAndroid settings hides many permissions a security researcher would call\npotentially <em>dangerous</em> (e.g., internet, sensor).<p>Were the bloatware user apps, they could be easily uninstalled either\nfrom Android settings or AM. Uninstalling system apps is not possible\nwithout privileged permission, but even then, it cannot <em>remove</em>\nthe system apps completely as they are located in the <em>system</em>\npartition which is a read-only partition. If you have root, you can\nremount this partition to manually <em>purge</em> these apps but this\nwill break Over the Air (OTA) updates since data in the system partition\nhas been modified. There are two kind of updates, delta (small-size,\nconsisting of only the changes between two versions) and full updates.\nYou may still be able to apply full updates, but the bloatware will be\ninstalled again, and consequently, you have to delete them all over\nagain.<p>Another solution is to disable these apps either from Android\nsettings or AM, but certain services can still run in the background as\nthey can be started by other system apps using Inter-process\nCommunication (IPC). One possible solution is to disable all bloatware\nuntil the service has finally stopped (after a restart). However, due to\nheavy modifications of the Android frameworks by the vendors, removing\nor disabling certain bloatware may cause the System UI to crash or even\ncause bootloop. From v4.0.0, AM has a new feature called\n<strong>Debloater</strong> which can be used as a starting point to\nmonitor, disable, and remove the bloatware from a proprietary Android\noperating system.<div class=\"amalert warning\"><p><strong><em>Note.</em></strong><p>In most cases, you cannot completely debloat your device. Therefore,\nit is recommended that you use a custom ROM free from bloatware, such as\nGraphene OS, Lineage OS or their derivatives.</div></section></section></section><section id=ch:specifications class=level1 data-number=5><h1 data-number=5><span class=header-section-number>5</span> <a href=#toc:ch:specifications>語法</a><a href=#ch:specifications class=anchor aria-hidden=true></a></h1><section id=sec:rules-specification class=level2 data-number=5.1><h2 data-number=5.1><span class=header-section-number>5.1</span> <a href=#toc:sec:rules-specification>規則語法</a><a href=#sec:rules-specification class=anchor aria-hidden=true></a></h2><section id=背景介紹 class=level3 data-number=5.1.1><h3 data-number=5.1.1><span class=header-section-number>5.1.1</span>\n<a href=#toc:背景介紹>背景介紹</a><a href=#背景介紹 class=anchor aria-hidden=true></a></h3><p>AM currently supports blocking activities, broadcast receivers,\ncontent providers, services, app ops and permissions, and in future I\nmay add more blocking options. In order to add more portability, it is\nnecessary to import/export all these data.<p>Maintaining a database should be the best choice when it comes to\nstoring data. For now, several <code>tsv</code> files with each file\nhaving the name of the package and a <code>.tsv</code> extension. The\nfile/database will be queried/processed by the\n<code>RulesStorageManager</code> class. Due to this abstraction, it\nshould be easier to switch to database or encrypted database systems in\nfuture without changing the design of the entire project. Currently, All\nconfiguration files are stored at\n<code>/data/data/io.github.muntashirakon.AppManager/Files/conf</code>.</section><section id=規則文件格式 class=level3 data-number=5.1.2><h3 data-number=5.1.2><span class=header-section-number>5.1.2</span>\n<a href=#toc:規則文件格式>規則文件格式</a><a href=#規則文件格式 class=anchor aria-hidden=true></a></h3><section id=內部 class=level4 data-number=5.1.2.1><h4 data-number=5.1.2.1><span class=header-section-number>5.1.2.1</span> 內部<a href=#內部 class=anchor aria-hidden=true></a></h4><p>The format below is used internally within App Manager and is <em>not\ncompatible with the external format.</em><pre><code>    &lt;name&gt; &lt;type&gt; &lt;mode&gt;|&lt;component_status&gt;|&lt;is_granted&gt;</code></pre><p>Here:<ul class=incremental><li><p><code>&lt;name></code> – Component/permission/app op name (in\ncase of app op, it could be string or integer)<li><p><code>&lt;type></code> – One of the <code>ACTIVITY</code>,\n<code>RECEIVER</code>, <code>PROVIDER</code>, <code>SERVICE</code>,\n<code>APP_OP</code>, <code>PERMISSION</code><li><p><code>&lt;mode></code> – (For app ops) The associated <a href=#subsec:mode-constants>mode constant</a><li><p><code>&lt;component_status></code> – (For components)\nComponent status<ul class=incremental><li><p><code>true</code> – Component has been applied (<code>true</code>\nvalue is kept for compatibility)<li><p><code>false</code> – Component hasn’t been applied yet, but will\nbe applied in future (<code>false</code> value is kept for\ncompatibility)<li><p><code>unblocked</code> – Component is scheduled to be\nunblocked</ul><li><p><code>&lt;is_granted></code> – (For permissions) Whether the\npermission is granted or revoked</ul></section><section id=外部 class=level4 data-number=5.1.2.2><h4 data-number=5.1.2.2><span class=header-section-number>5.1.2.2</span> 外部<a href=#外部 class=anchor aria-hidden=true></a></h4><p>外部格式用於在 App Manager 中導入或導出規則。<pre><code> &lt;package_name&gt; &lt;component_name&gt; &lt;type&gt; &lt;mode&gt;|&lt;component_status&gt;|&lt;is_granted&gt;</code></pre><p>除了第一項是包的名稱外，該格式與上述格式基本相同。<div class=\"amalert danger\"><p><strong><em>注意.</em></strong><p>導出的規則與內部規則的格式不同，不應直接複製到 <strong>conf</strong>\n文件夾。</div></section></section></section></section><section id=ch:changelogs class=level1 data-number=6><h1 data-number=6><span class=header-section-number>6</span> <a href=#toc:ch:changelogs>更新日志</a><a href=#ch:changelogs class=anchor aria-hidden=true></a></h1><section id=sec:v4.0.5-(445) class=level2 data-number=6.1><h2 data-number=6.1><span class=header-section-number>6.1</span> <a href=#toc:sec:v4.0.5-(445)>v4.0.5 (445)</a><a href=#sec:v4.0.5-(445) class=anchor aria-hidden=true></a></h2><ul class=incremental><li><p>Added option to allow installing the existing applications in the\ninstaller page<li><p>Display unsafe bloatware info<li><p>Display vector icon on the splash screen in Android 7.1 and\nearlier<li><p>Enabled “Clear data from uninstalled apps” to no-root users in\n1-click ops page<li><p>Enabled predictive back in Android 14 onwards<li><p>Improved accessibility by updating the content description of the\naction items<li><p>In app info tab, open “Open by default” setting in the “Open\nlinks” dialog<li><p>In debloater page, sort by app label (or app name) rather than\npackage name<li><p>Fixed freezing an app with “Remember for this app” turned\non<li><p>Fixed selecting texts in the list items due to framework\nbugs<li><p>Fixed setting app ops in custom ROMs with MIUI properties\ninjected<li><p>Fixed updating profile modification status when an application is\ndeleted from the list<li><p>Handled common colors and cursor movements in terminal\noutput.</ul></section><section id=sec:v4.0.4-(444) class=level2 data-number=6.2><h2 data-number=6.2><span class=header-section-number>6.2</span> <a href=#toc:sec:v4.0.4-(444)>v4.0.4 (444)</a><a href=#sec:v4.0.4-(444) class=anchor aria-hidden=true></a></h2><ul class=incremental><li><p>Optimized searching and filtering in the main page<li><p>Adopted sentence-case for the titles<li><p>Use the configured state to execute a profile for the simple\nshortcuts<li><p>Prevented crashing while searching throughout the\napplication<li><p>Fixed integer overflow issue in the tar compression.</ul></section><section id=sec:v4.0.3-(443) class=level2 data-number=6.3><h2 data-number=6.3><span class=header-section-number>6.3</span> <a href=#toc:sec:v4.0.3-(443)>v4.0.3 (443)</a><a href=#sec:v4.0.3-(443) class=anchor aria-hidden=true></a></h2><ul class=incremental><li><p>Updated translations<li><p>Improved handling the list items throughout App Manager<li><p>Fixed a regression error in file manager<li><p>Fixed spinners in the App Usage and the System Config\npages.</ul></section><section id=sec:v4.0.2-(442) class=level2 data-number=6.4><h2 data-number=6.4><span class=header-section-number>6.4</span> <a href=#toc:sec:v4.0.2-(442)>v4.0.2 (442)</a><a href=#sec:v4.0.2-(442) class=anchor aria-hidden=true></a></h2><ul class=incremental><li><p>Updated bloatware<li><p>Fixed fetching applications in multi-user environment in no-root\nmode<li><p>Fixed opening <code>app-manager</code> URLs from the web\nbrowsers<li><p>Fixed updating SSAID<li><p>Prevented a crash in Android &lt; 9.0 that occurs due to invalid\napp ops.</ul></section><section id=sec:v4.0.1-(441) class=level2 data-number=6.5><h2 data-number=6.5><span class=header-section-number>6.5</span> <a href=#toc:sec:v4.0.1-(441)>v4.0.1 (441)</a><a href=#sec:v4.0.1-(441) class=anchor aria-hidden=true></a></h2><section id=overlay-management class=level3 data-number=6.5.1><h3 data-number=6.5.1><span class=header-section-number>6.5.1</span>\n<a href=#toc:overlay-management>Overlay management</a><a href=#overlay-management class=anchor aria-hidden=true></a></h3><p>In the App Details page, a new tab “Overlays” is added where per-app\noverlays are displayed. They can also be enabled or disabled using the\ntoggle button. In addition, if the App Details page of an overlay\npackage is opened, a “Overlay” tag will be displayed in the App Info\ntab. Clicking on the tag opens a dialog containing additional info along\nwith a button that allows navigating to the App Details page of the\noverlay target package if it is installed.<section id=known-limitation class=level5 data-number=6.5.1.0.1><h5 data-number=6.5.1.0.1><span class=header-section-number>6.5.1.0.1</span> Known limitation<a href=#known-limitation class=anchor aria-hidden=true></a></h5><p>At present, it only works for root/ADB users in Android 8 (Oreo) and\nlater.</section></section><section id=unfreeze-option-in-activity-shortcuts class=level3 data-number=6.5.2><h3 data-number=6.5.2><span class=header-section-number>6.5.2</span>\n<a href=#toc:unfreeze-option-in-activity-shortcuts>Unfreeze option in\nactivity shortcuts</a><a href=#unfreeze-option-in-activity-shortcuts class=anchor aria-hidden=true></a></h3><p>If the application corresponding to the shortcut being launched is\nfrozen, App Manager will now offer you to unfreeze the app temporarily\nso that the shortcut can be launched. The app will be frozen again once\nthe screen is locked.<section id=known-limitation-1 class=level5 data-number=6.5.2.0.1><h5 data-number=6.5.2.0.1><span class=header-section-number>6.5.2.0.1</span> Known limitation<a href=#known-limitation-1 class=anchor aria-hidden=true></a></h5><p>This may not work on devices without a screen lock or if the screen\nis locked some time after the display goes off.</section></section><section id=market-like-url-support class=level3 data-number=6.5.3><h3 data-number=6.5.3><span class=header-section-number>6.5.3</span>\n<a href=#toc:market-like-url-support><code>market</code>-like URL\nsupport</a><a href=#market-like-url-support class=anchor aria-hidden=true></a></h3><p>Third-party applications can now open the App Details page of any\ninstalled package by invoking an Intent with an URL with the following\nformat:<pre><code>app-manager://details?id=&lt;pkg&gt;&amp;user=&lt;user_id&gt;</code></pre><p>where <code>&lt;pkg></code> stands for package name, and\n<code>&lt;user_id></code> stands for the user ID which is\noptional.</section><section id=updated-color-codes class=level3 data-number=6.5.4><h3 data-number=6.5.4><span class=header-section-number>6.5.4</span>\n<a href=#toc:updated-color-codes>Updated color codes</a><a href=#updated-color-codes class=anchor aria-hidden=true></a></h3><p>In order to improve accessibility, certain color codes have been\nimproved. Visit <a href=app-manager://settings/about/version>Settings\n> About > Version/Changelog</a> for details.</section><section id=others class=level3 data-number=6.5.5><h3 data-number=6.5.5><span class=header-section-number>6.5.5</span>\n<a href=#toc:others>Others</a><a href=#others class=anchor aria-hidden=true></a></h3><ul class=incremental><li><p>Avoided waiting for the remote server to respond when no-root\nmode is set<li><p>Fixed downgrading apps in Android 10 onwards<li><p>Fixed installer issues in the Huawei stock operating\nsystems<li><p>Improved text formatting in the “What’s New” dialog<li><p>In the UI tracker window, fixed clicking on the icon after it is\niconified<li><p>Updated bloatware and suggestions</ul></section></section><section id=sec:v4.0.0-(440) class=level2 data-number=6.6><h2 data-number=6.6><span class=header-section-number>6.6</span> <a href=#toc:sec:v4.0.0-(440)>v4.0.0 (440)</a><a href=#sec:v4.0.0-(440) class=anchor aria-hidden=true></a></h2><p>App Manager v4.0.0 comes with a lot of new features and improvements.\nVisit <a href=app-manager://settings/about/version>Settings > About\n> Version/Changelog</a> for details.<section id=new-logo class=level3 data-number=6.6.1><h3 data-number=6.6.1><span class=header-section-number>6.6.1</span>\n<a href=#toc:new-logo>New logo!</a><a href=#new-logo class=anchor aria-hidden=true></a></h3><p>The new logo is just a cursive “A”. The design is based on the <a href=https://freetengwar.sourceforge.net/>Tengwar Telcontar</a> font\nwhich was created to bring the Tengwar script, originally created by J.\nR. R. Tolkien, to the digital world. The letter has the classic App\nManager color (i.e., #dcaf74) and uses a pure black background instead\nof a shade of grey.</section><section id=android-14-and-15-support class=level3 data-number=6.6.2><h3 data-number=6.6.2><span class=header-section-number>6.6.2</span>\n<a href=#toc:android-14-and-15-support>Android 14 and 15 support</a><a href=#android-14-and-15-support class=anchor aria-hidden=true></a></h3><p>App Manager now targets Android 14 and fully supports Android 15.<section id=known-issue class=level5 data-number=6.6.2.0.1><h5 data-number=6.6.2.0.1><span class=header-section-number>6.6.2.0.1</span> Known issue<a href=#known-issue class=anchor aria-hidden=true></a></h5><p>KeyStore backup/restore is not working in Android 12 and later.</section></section><section id=revamped-debloater class=level3 data-number=6.6.3><h3 data-number=6.6.3><span class=header-section-number>6.6.3</span>\n<a href=#toc:revamped-debloater>Revamped debloater</a><a href=#revamped-debloater class=anchor aria-hidden=true></a></h3><p>Debloating profiles were available as “Presets” in the Profiles page\nwhich has now been replaced with the Debloater page and can be accessed\nfrom the three-dots menu in the Main page. <a href=https://github.com/MuntashirAkon/android-debloat-list>ADL</a> is\na new project that focuses on maintaining a list of bloatware as well as\npotential open source alternatives. Contributions are welcome!</section><section id=introducing-file-manager class=level3 data-number=6.6.4><h3 data-number=6.6.4><span class=header-section-number>6.6.4</span>\n<a href=#toc:introducing-file-manager>Introducing file manager</a><a href=#introducing-file-manager class=anchor aria-hidden=true></a></h3><p>App Manager offers an (almost) fully-featured file manager with basic\nfile operations, such as copy, cut, rename, and delete along with the\nbatch operations. It also offers an extensive “Open with…” dialog to\nopen a file with another app, and a comprehensive file properties\nviewer. Folders can also be added to the list of favorites for quick\naccess. And many more.</section><section id=integrated-code-editor class=level3 data-number=6.6.5><h3 data-number=6.6.5><span class=header-section-number>6.6.5</span>\n<a href=#toc:integrated-code-editor>Integrated code editor</a><a href=#integrated-code-editor class=anchor aria-hidden=true></a></h3><p>Manifest and code viewers have been replaced with this new editor.\nAmong other regular features, it includes proper syntax highlighting and\nadvanced searching options. In addition, files from third-party apps can\nalso be opened for editing.</section><section id=history-of-operations class=level3 data-number=6.6.6><h3 data-number=6.6.6><span class=header-section-number>6.6.6</span>\n<a href=#toc:history-of-operations>History of operations</a><a href=#history-of-operations class=anchor aria-hidden=true></a></h3><p>All 1-click operations, batch operations, and profile invocations are\nnow stored as history. The history items can also be executed from the\nHistory page. To ensure consistency, the profile state, configurations,\npackage list are also stored, and this stored version is executed\ninstead of the actual profile. As a result, this works even if the\nprofile is deleted.</section><section id=per-app-freezing-and-more class=level3 data-number=6.6.7><h3 data-number=6.6.7><span class=header-section-number>6.6.7</span>\n<a href=#toc:per-app-freezing-and-more>Per-app freezing, and\nmore</a><a href=#per-app-freezing-and-more class=anchor aria-hidden=true></a></h3><p>Freeze/unfreeze feature now supports setting per-app freezing method\nwhich is beneficial in certain scenarios, such as when a user want to\nsuspend some apps while using the disable method as the default. In\naddition, an “Advanced suspend” option is added which force-stops an\napplication before suspending it, thus, prevent it’s services from\nrunning in the background.</section><section id=log-viewer-enhancements class=level3 data-number=6.6.8><h3 data-number=6.6.8><span class=header-section-number>6.6.8</span>\n<a href=#toc:log-viewer-enhancements>Log viewer enhancements</a><a href=#log-viewer-enhancements class=anchor aria-hidden=true></a></h3><p>Log viewer now supports enhanced searching and filtering options,\nsuch as keyword- and regular expression-based searching and filtering.\nPlease read the in-app changelog for details. Support for batch\noperations has also been added.</section><section id=launching-non-exported-activities class=level3 data-number=6.6.9><h3 data-number=6.6.9><span class=header-section-number>6.6.9</span>\n<a href=#toc:launching-non-exported-activities>Launching non-exported\nactivities</a><a href=#launching-non-exported-activities class=anchor aria-hidden=true></a></h3><p>App Manager now supports launching non-exported activities in no-root\nand ADB mode. However, in no-root mode,\n<code>android.permission.WRITE_SECURE_SETTINGS</code> permission is\nrequired.</section><section id=new-tags-in-app-info-tab class=level3 data-number=6.6.10><h3 data-number=6.6.10><span class=header-section-number>6.6.10</span> <a href=#toc:new-tags-in-app-info-tab>New tags in App Info tab</a><a href=#new-tags-in-app-info-tab class=anchor aria-hidden=true></a></h3><p>Five new tags are added in the App Info tab. They are: bloatware,\nXposed, sensors disabled, open links, and static shared libs. Clicking\non “bloatware” will display more information regarding the bloatware and\nsuggest alternatives, “Xposed” tag will display dependency information,\n“open links” will display a list of links supported by the application,\nand “static shared libs” will display all version of the application\ninstalled in the system along with an option to uninstall them. The\nlatter is useful for applications, such as Trichrome.<section id=known-issue-1 class=level5 data-number=6.6.10.0.1><h5 data-number=6.6.10.0.1><span class=header-section-number>6.6.10.0.1</span> Known issue<a href=#known-issue-1 class=anchor aria-hidden=true></a></h5><p>“Sensors disabled” only works real-time. That means if the\napplication is not currently active, this tag will always display even\nthough the applications may use sensors while it is running. This is a\nframework limitation and nothing can be done to avoid it\neffectively.</section></section><section id=per-session-installer-options class=level3 data-number=6.6.11><h3 data-number=6.6.11><span class=header-section-number>6.6.11</span> <a href=#toc:per-session-installer-options>Per-session installer\noptions</a><a href=#per-session-installer-options class=anchor aria-hidden=true></a></h3><p>It is not possible to modify installer options during the\ninstallation by clicking on the “settings” button in the installation\ndialog. The installer options will be applied to all the applications\ninstalled in the same session (i.e., the installer queue).</section><section id=advanced-mode-of-operations-adb-enhancements class=level3 data-number=6.6.12><h3 data-number=6.6.12><span class=header-section-number>6.6.12</span> <a href=#toc:advanced-mode-of-operations-adb-enhancements>Advanced mode\nof operations, ADB enhancements, …</a><a href=#advanced-mode-of-operations-adb-enhancements class=anchor aria-hidden=true></a></h3><p>App Manager now supports running its remote server (which is used as\na proxy for running privileged operations) as any supported user (UID).\nThis includes root (0), system (1000), and shell/ADB (2000) through the\ncustom commands. This is also useful for Fire TVs which have disabled\nconnecting to ADB from localhost through socket connection. In addition,\nADB pairing is now done using notifications rather than split screen.\nADB connection speed can also be improved by choosing to run App Manager\nin the background which can be configured in the settings.</section><section id=data-usage-widget-and-more class=level3 data-number=6.6.13><h3 data-number=6.6.13><span class=header-section-number>6.6.13</span> <a href=#toc:data-usage-widget-and-more>Data usage widget, and more</a><a href=#data-usage-widget-and-more class=anchor aria-hidden=true></a></h3><p>Data usage widget display the total data usage for the day, similar\nto the screen time widget which displays the total screen time for the\nday. In addition, existing widgets have been improved.</section><section id=others-1 class=level3 data-number=6.6.14><h3 data-number=6.6.14><span class=header-section-number>6.6.14</span> <a href=#toc:others-1>Others</a><a href=#others-1 class=anchor aria-hidden=true></a></h3><ul class=incremental><li><p>Replaced log viewer, sys config, Terminal, etc. with Labs\npage<li><p>Added an option to disable sensors for each app in the App Info\ntab<li><p>Added an option to perform runtime optimization of applications\nin the 1-click Ops page and in the App Info tab<li><p>Added support for Zstandard compression for\nbackup/restore<li><p>Enabling APK signing now automatically enables zip align\nfeature<li><p>Support exporting application list as CSV or JSON in the batch\noperations<li><p>Added pure black theme support<li><p>Display current activity name (when possible) in the UI Tracker\nwindow<li><p>Added an option to filter apps by user in the Main page<li><p>Display a link to Pithus report in the scanner page if\navailable.</ul></section></section><section id=sec:v3.1.0-(423) class=level2 data-number=6.7><h2 data-number=6.7><span class=header-section-number>6.7</span> <a href=#toc:sec:v3.1.0-(423)>v3.1.0 (423)</a><a href=#sec:v3.1.0-(423) class=anchor aria-hidden=true></a></h2><p>App Manager v3.1.0 comes with a few new features and a lot of\nimprovements. Visit <a href=app-manager://settings/about/version>Settings > About >\nVersion/Changelog</a> for details.<section id=android-13-support class=level3 data-number=6.7.1><h3 data-number=6.7.1><span class=header-section-number>6.7.1</span>\n<a href=#toc:android-13-support>Android 13 support</a><a href=#android-13-support class=anchor aria-hidden=true></a></h3><p>App Manager now targets Android 13 which means most issues in Android\n12 and 13 has been addressed, including SSAID and SAF issues as well as\nmonochrome icons and other theming issues.<section id=known-issue-2 class=level5 data-number=6.7.1.0.1><h5 data-number=6.7.1.0.1><span class=header-section-number>6.7.1.0.1</span> Known issue<a href=#known-issue-2 class=anchor aria-hidden=true></a></h5><p>KeyStore backup/restore not working in Android 12 and later.</section></section><section id=introducing-freezeunfreeze class=level3 data-number=6.7.2><h3 data-number=6.7.2><span class=header-section-number>6.7.2</span>\n<a href=#toc:introducing-freezeunfreeze>Introducing\nfreeze/unfreeze</a><a href=#introducing-freezeunfreeze class=anchor aria-hidden=true></a></h3><p>Enable/disable is replaced with freeze/unfreeze to allow greater\ncontrol on the behaviours of an app. It supports suspend, disable and\nhide functionalities which can be controlled at <a href=app-manager://settings/rules_prefs/freeze_type>Settings >\nRules > Default freezing method</a>. In order to make it easy to\nfreeze or unfreeze an app, shortcuts can also be created from the App\nInfo tab by long clicking on the freeze or unfreeze button.</section><section id=export-app-list class=level3 data-number=6.7.3><h3 data-number=6.7.3><span class=header-section-number>6.7.3</span>\n<a href=#toc:export-app-list>Export app list</a><a href=#export-app-list class=anchor aria-hidden=true></a></h3><p>In the Main page, it is now possible to export the list of apps in\neither XML or Markdown format using batch operations. In the future, the\nXML file may also be imported to App Manager.</section><section id=elliptic-curve-crypography-ecc class=level3 data-number=6.7.4><h3 data-number=6.7.4><span class=header-section-number>6.7.4</span>\n<a href=#toc:elliptic-curve-crypography-ecc>Elliptic Curve Crypography\n(ECC)</a><a href=#elliptic-curve-crypography-ecc class=anchor aria-hidden=true></a></h3><p>App Manager now fully supports encrypting backups using ECC in\naddition to offering AES, RSA and OpenPGP.</section><section id=new-languages class=level3 data-number=6.7.5><h3 data-number=6.7.5><span class=header-section-number>6.7.5</span>\n<a href=#toc:new-languages>New languages</a><a href=#new-languages class=anchor aria-hidden=true></a></h3><p>Two new languages are added: Korean and Romanian.</section><section id=more-list-options class=level3 data-number=6.7.6><h3 data-number=6.7.6><span class=header-section-number>6.7.6</span>\n<a href=#toc:more-list-options>More list options</a><a href=#more-list-options class=anchor aria-hidden=true></a></h3><p>In the main page, more sorting and filtering options are added.\nSorting options include sorting the apps by total size, total data\nusage, launch count, screen time and last usage time. Filtering options\ninclude filtering the apps having at least one item in the Android\nKeyStore, filtering apps with URIs granted via SAF, and filtering apps\nwith SSAID.</section><section id=improved-handling-of-mode-of-operation class=level3 data-number=6.7.7><h3 data-number=6.7.7><span class=header-section-number>6.7.7</span>\n<a href=#toc:improved-handling-of-mode-of-operation>Improved handling\nof mode of operation</a><a href=#improved-handling-of-mode-of-operation class=anchor aria-hidden=true></a></h3><p>Fixed various issues with ADB pairing, handled incomplete USB\ndebugging. Some rooting methods cannot allow interprocess communication\nvia Binder. In those cases, ADB mode is used as a fallback method by\nenabling it automatically if possible.</section><section id=handling-multiple-users class=level3 data-number=6.7.8><h3 data-number=6.7.8><span class=header-section-number>6.7.8</span>\n<a href=#toc:handling-multiple-users>Handling multiple users</a><a href=#handling-multiple-users class=anchor aria-hidden=true></a></h3><p>When possible, App Manager will be able to display apps from work\nprofile in no-root mode in addition to allowing basic operations such as\nlaunching the app or navigating to the system settings. For backups, it\nis now possible to restore backups for other users, but for work\nprofile, some apps may only work properly after re-enabling the work\nprofile. In the installer page, selecting <em>All users</em> will now\ninstall the app for all users instead of only the current user. Finally,\nin the app info tab, current app can be installed in another profile\nusing the <em>Install for…</em> option available in the three-dots menu.\nThis is analogous to the <code>pm install-existing</code> command,\nthereby, making the installation process a lot faster.</section><section id=explorer-enhancements class=level3 data-number=6.7.9><h3 data-number=6.7.9><span class=header-section-number>6.7.9</span>\n<a href=#toc:explorer-enhancements>Explorer enhancements</a><a href=#explorer-enhancements class=anchor aria-hidden=true></a></h3><p>Explorer can now open DEX and JAR files in addition to APK files.\nSeveral sorting options as well as folder options are also added as the\nlist options.</section><section id=new-tag-wx class=level3 data-number=6.7.10><h3 data-number=6.7.10><span class=header-section-number>6.7.10</span> <a href=#toc:new-tag-wx>New tag: WX</a><a href=#new-tag-wx class=anchor aria-hidden=true></a></h3><p>In app info tab, a new tag called WX is added. It is displayed in\nAndroid 10 and later if the application targets Android 9 or earlier. It\nindicates <a href=https://en.wikipedia.org/wiki/W%5EX>W^X</a>\nviolation which allows the app to execute arbitrary executable files\neither by the modification of executables embedded within the app or by\ndownloading them from the Internet.</section><section id=app-ops-management class=level3 data-number=6.7.11><h3 data-number=6.7.11><span class=header-section-number>6.7.11</span> <a href=#toc:app-ops-management>App ops management</a><a href=#app-ops-management class=anchor aria-hidden=true></a></h3><p>App ops are now managed automatically to avoid various app ops\nrelated crashes in various platforms. This will also lessen the amount\nof crashes in an unsupported operating system.</section><section id=batch-uninstallation class=level3 data-number=6.7.12><h3 data-number=6.7.12><span class=header-section-number>6.7.12</span> <a href=#toc:batch-uninstallation>Batch uninstallation</a><a href=#batch-uninstallation class=anchor aria-hidden=true></a></h3><p>In the Main page, enabled batch uninstallation in no-root mode.</section><section id=running-apps class=level3 data-number=6.7.13><h3 data-number=6.7.13><span class=header-section-number>6.7.13</span> <a href=#toc:running-apps>Running apps</a><a href=#running-apps class=anchor aria-hidden=true></a></h3><p>Enabled advanced searching. Searching now matches not only app labels\nbut also package names.</section><section id=interceptor class=level3 data-number=6.7.14><h3 data-number=6.7.14><span class=header-section-number>6.7.14</span> <a href=#toc:interceptor>Interceptor</a><a href=#interceptor class=anchor aria-hidden=true></a></h3><p>Copy the intercepted Intent as am command which can be run from\neither an ADB shell or a terminal using root with the same\neffectiveness.</section><section id=device-specific-changes class=level3 data-number=6.7.15><h3 data-number=6.7.15><span class=header-section-number>6.7.15</span> <a href=#toc:device-specific-changes>Device-specific changes</a><a href=#device-specific-changes class=anchor aria-hidden=true></a></h3><section id=graphene-os class=level5 data-number=6.7.15.0.1><h5 data-number=6.7.15.0.1><span class=header-section-number>6.7.15.0.1</span> Graphene OS<a href=#graphene-os class=anchor aria-hidden=true></a></h5><p>Explicitly handle the Internet permission which is a runtime\npermission in the OS.</section><section id=miui class=level5 data-number=6.7.15.0.2><h5 data-number=6.7.15.0.2><span class=header-section-number>6.7.15.0.2</span> MIUI<a href=#miui class=anchor aria-hidden=true></a></h5><p>Fixed permission denied issues in the installer due to a framework\nissue introduced in MIUI 12.5.</section><section id=motorola class=level5 data-number=6.7.15.0.3><h5 data-number=6.7.15.0.3><span class=header-section-number>6.7.15.0.3</span> Motorola<a href=#motorola class=anchor aria-hidden=true></a></h5><p>Fixed crashes in the Interceptor page due to a framework issue\nintroduced in Android 11.</section></section><section id=others-2 class=level3 data-number=6.7.16><h3 data-number=6.7.16><span class=header-section-number>6.7.16</span> <a href=#toc:others-2>Others</a><a href=#others-2 class=anchor aria-hidden=true></a></h3><ul class=incremental><li><p>Improved Java-Smali conversion by including all the subclasses\nduring conversion<li><p>Improved scanning performance in the Scanner page<li><p>Improved updating the list of apps in the Main page<li><p>Scan all the available paths to detect systemless-ly installed\nsystem apps<li><p><code>vacuum</code> SQLite database before opening it for viewing\nor editing.</ul></section></section><section id=sec:v3.0.0-(410) class=level2 data-number=6.8><h2 data-number=6.8><span class=header-section-number>6.8</span> <a href=#toc:sec:v3.0.0-(410)>v3.0.0 (410)</a><a href=#sec:v3.0.0-(410) class=anchor aria-hidden=true></a></h2><p>App Manager v3.0.0 comes with a lot of features and improvements. See\n<a href=app-manager://settings/about/version>Settings > About >\nVersion/Changelog</a> to see a more detailed changelog.<section id=material-3-and-more class=level3 data-number=6.8.1><h3 data-number=6.8.1><span class=header-section-number>6.8.1</span>\n<a href=#toc:material-3-and-more>Material 3 and More</a><a href=#material-3-and-more class=anchor aria-hidden=true></a></h3><p>Material 3, somewhat similar to <em>Material You</em>, is a\nsignificant improvement over Material Design 2 with support for dynamic\ncolours in Android 12 and later. In addition, many design changes have\nbeen made in App Manager without any significant changes in the overall\nuser experience.<section id=known-issue-3 class=level5 data-number=6.8.1.0.1><h5 data-number=6.8.1.0.1><span class=header-section-number>6.8.1.0.1</span> Known issue<a href=#known-issue-3 class=anchor aria-hidden=true></a></h5><p>Switches are still based on Material Design 2 which will be fixed in\na future release.</section></section><section id=wireless-debugging class=level3 data-number=6.8.2><h3 data-number=6.8.2><span class=header-section-number>6.8.2</span>\n<a href=#toc:wireless-debugging>Wireless Debugging</a><a href=#wireless-debugging class=anchor aria-hidden=true></a></h3><p>Wireless debugging support has been fully implemented. Head over to\n§<a href=#sec:wireless-debugging data-reference-type=ref data-reference=sec:wireless-debugging>3.2</a> for instructions on how\nto configure wireless debugging.<div class=\"amalert tip\"><p><strong><em>No-root users.</em></strong><p>Due to auto-detection feature, startup time might be large for\nno-root users when the mode of operation is set to <em>auto</em>.\nInstead, no-root users should select <em>no-root</em> instead of\n<em>auto</em>.</div></section><section id=languages class=level3 data-number=6.8.3><h3 data-number=6.8.3><span class=header-section-number>6.8.3</span>\n<a href=#toc:languages>Languages</a><a href=#languages class=anchor aria-hidden=true></a></h3><p>App Manager is fully translated into Indonesian and Italian languages\nand can be enabled in settings. Bengali is removed due to lack of\ntranslators.</section><section id=introducing-app-explorer class=level3 data-number=6.8.4><h3 data-number=6.8.4><span class=header-section-number>6.8.4</span>\n<a href=#toc:introducing-app-explorer>Introducing App Explorer</a><a href=#introducing-app-explorer class=anchor aria-hidden=true></a></h3><p>App Explorer can be used to browse the contents of an application.\nThis includes binary XML files, DEX contents or any other media files.\nDEX contents can only be explored in Android Oreo (Android 8) and later.\nIt’s also possible to convert an <code>.smali</code> file into\n<code>.java</code> for a better understanding of the reversed code. This\nfeature, if not needed, can be disabled in Settings > Enable/disable\nfeatures.</section><section id=import-backups-from-other-applications class=level3 data-number=6.8.5><h3 data-number=6.8.5><span class=header-section-number>6.8.5</span>\n<a href=#toc:import-backups-from-other-applications>Import Backups\nfrom Other Applications</a><a href=#import-backups-from-other-applications class=anchor aria-hidden=true></a></h3><p>It is possible to import backups from discontinued or obsolete\napplications such as Titanium Backup, OAndBackup and Swift Backup\n(version 3.0 to 3.2). Go to Setting > Backup/restore to find this\noption.</section><section id=virustotal class=level3 data-number=6.8.6><h3 data-number=6.8.6><span class=header-section-number>6.8.6</span>\n<a href=#toc:virustotal>VirusTotal</a><a href=#virustotal class=anchor aria-hidden=true></a></h3><p>VirusTotal is a widely used tool to scan files and URLs for viruses.\nIn the scanner page and in the running apps page, an option to scan\nfiles with VirusTotal has been added. But the option is hidden by\ndefault. To enable the option, it is necessary to obtain an API key from\nVirusTotal. Go to Settings > VirusTotal API Key for more\ninformation.<div class=\"amalert warning\"><p><strong><em>Internet feature.</em></strong><p>This is currently the only feature which require an Internet\nconnection. If you wish to use any Internet feature that might also be\nadded in the future, enable <em>Use the Internet</em> in Settings >\nEnable/disable features.</div></section><section id=trigger-profiles-from-the-automation-software class=level3 data-number=6.8.7><h3 data-number=6.8.7><span class=header-section-number>6.8.7</span>\n<a href=#toc:trigger-profiles-from-the-automation-software>Trigger\nProfiles from the Automation Software</a><a href=#trigger-profiles-from-the-automation-software class=anchor aria-hidden=true></a></h3><p>As the implementation of routine operations is being delayed, an\noption to trigger profiles from the external automation software is\nadded. See §<a href=#sec:automating-tasks data-reference-type=ref data-reference=sec:automating-tasks>3.4</a> for instructions on how to\nconfigure profile automation.</section><section id=improved-application-installer class=level3 data-number=6.8.8><h3 data-number=6.8.8><span class=header-section-number>6.8.8</span>\n<a href=#toc:improved-application-installer>Improved Application\nInstaller</a><a href=#improved-application-installer class=anchor aria-hidden=true></a></h3><p>Application installer includes several improvements including the\nability to downgrade applications in no-root mode, installing multiple\napplications at once and blocking trackers after installation. In\nAndroid 12 and later, no-root users can update applications without any\nuser interactions.</section><section id=component-blocking class=level3 data-number=6.8.9><h3 data-number=6.8.9><span class=header-section-number>6.8.9</span>\n<a href=#toc:component-blocking>Component Blocking</a><a href=#component-blocking class=anchor aria-hidden=true></a></h3><p>It is now possible to configure how App Manager should block a\ncomponent. Visit Settings > Rules > Default blocking method for\nmore information. In the components tab, long clicking the block/unblock\nbutton opens a context menu which allows per-component blocking in a\nsimilar manner. ADB users can also block the components of a <em>Test\nonly</em> app.</section><section id=advanced-searching class=level3 data-number=6.8.10><h3 data-number=6.8.10><span class=header-section-number>6.8.10</span> <a href=#toc:advanced-searching>Advanced Searching</a><a href=#advanced-searching class=anchor aria-hidden=true></a></h3><p>In some pages, the search bar supports additional searching which\nincludes searching via prefix, suffix or even regular expressions. In\nthe main page, it is also possible to search for applications using the\nfirst letters of each word, e.g. <em>App Manager</em> can be listed by\nsearching for <em>am</em>.</section><section id=shared-libraries class=level3 data-number=6.8.11><h3 data-number=6.8.11><span class=header-section-number>6.8.11</span> <a href=#toc:shared-libraries>Shared Libraries</a><a href=#shared-libraries class=anchor aria-hidden=true></a></h3><p>Shared libraries tab has received a significant improvements. It can\ndisplay three types of libraries, such as native, jar and APK files.</section><section id=make-the-best-use-of-interceptor class=level3 data-number=6.8.12><h3 data-number=6.8.12><span class=header-section-number>6.8.12</span> <a href=#toc:make-the-best-use-of-interceptor>Make the Best Use of\nInterceptor</a><a href=#make-the-best-use-of-interceptor class=anchor aria-hidden=true></a></h3><p>Activity interceptor can be opened directly from the activities tab\nby long clicking on the launch button, and similarly, activities can be\nlaunched from the activity interceptor page with or without root, for\nany users.<div class=\"amalert tip\"><p><strong><em>Notice.</em></strong><p>Currently, activities opened via root cannot send the results back to\nthe original applications.</div></section><section id=widget-screen-time class=level3 data-number=6.8.13><h3 data-number=6.8.13><span class=header-section-number>6.8.13</span> <a href=#toc:widget-screen-time>Widget: Screen Time</a><a href=#widget-screen-time class=anchor aria-hidden=true></a></h3><p>Screen time widget is quite similar to Digital Wellbeing’s widget by\nthe same name. It displays the total screen time for the day along with\nthe top three apps from all users.</section><section id=widget-clear-cache class=level3 data-number=6.8.14><h3 data-number=6.8.14><span class=header-section-number>6.8.14</span> <a href=#toc:widget-clear-cache>Widget: Clear Cache</a><a href=#widget-clear-cache class=anchor aria-hidden=true></a></h3><p>Clear cache widget can be to clear cache from all the applications\ndirectly from the home screen.</section></section><section id=sec:v2.6.0-(385) class=level2 data-number=6.9><h2 data-number=6.9><span class=header-section-number>6.9</span> <a href=#toc:sec:v2.6.0-(385)>v2.6.0 (385)</a><a href=#sec:v2.6.0-(385) class=anchor aria-hidden=true></a></h2><section id=introducing-backups class=level3 data-number=6.9.1><h3 data-number=6.9.1><span class=header-section-number>6.9.1</span>\n<a href=#toc:introducing-backups>Introducing Backups</a><a href=#introducing-backups class=anchor aria-hidden=true></a></h3><p>Back up/restore feature is now finally out of beta! Read <a href=#sec:backup-restore>the corresponding guide</a> to understand how\nit works.</section><section id=introducing-log-viewer class=level3 data-number=6.9.2><h3 data-number=6.9.2><span class=header-section-number>6.9.2</span>\n<a href=#toc:introducing-log-viewer>Introducing Log Viewer</a><a href=#introducing-log-viewer class=anchor aria-hidden=true></a></h3><p><a href=#subsubsec:log-viewer>Log viewer</a> is essentially a\nfront-end for <code>logcat</code>. It can be used to filter logs by\n<em>tag</em> or <em>pid</em> (process ID), or even by custom filters.\nLog levels AKA verbosity can also be configured. You can also save,\nshare and manage logs.</section><section id=lock-app-manager class=level3 data-number=6.9.3><h3 data-number=6.9.3><span class=header-section-number>6.9.3</span>\n<a href=#toc:lock-app-manager>Lock App Manager</a><a href=#lock-app-manager class=anchor aria-hidden=true></a></h3><p><a href=#subsubsec:screen-lock>Lock App Manager</a> with the screen\nlock configured for your device.</section><section id=extended-modes-for-app-ops class=level3 data-number=6.9.4><h3 data-number=6.9.4><span class=header-section-number>6.9.4</span>\n<a href=#toc:extended-modes-for-app-ops>Extended Modes for App\nOps</a><a href=#extended-modes-for-app-ops class=anchor aria-hidden=true></a></h3><p>You can set any mode for any app ops that your device supports,\neither from the <a href=#subsec:set-mode-for-app-ops-dots>1-click ops\npage</a> or from the <a href=#subsubsec:app-ops>app ops tab</a>.</section><section id=new-batch-ops-add-to-profile class=level3 data-number=6.9.5><h3 data-number=6.9.5><span class=header-section-number>6.9.5</span>\n<a href=#toc:new-batch-ops-add-to-profile>New Batch Ops: Add to\nProfile</a><a href=#new-batch-ops-add-to-profile class=anchor aria-hidden=true></a></h3><p>You can now easily add selected apps to an existing profile using the\nbatch operations.</section><section id=app-info-improved class=level3 data-number=6.9.6><h3 data-number=6.9.6><span class=header-section-number>6.9.6</span>\n<a href=#toc:app-info-improved>App Info: Improved</a><a href=#app-info-improved class=anchor aria-hidden=true></a></h3><p>App info tab now has many options, including the ability to change <a href=#sec:terminologies>SSAID</a>, network policy (i.e. background\nnetwork usage), battery optimization, etc. Most of the tags used in this\ntab are also clickable, and if you click on them, you will be able to\nlook at the current state or configure them right away.</section><section id=advanced-sort-and-filtering-options-in-the-main-page class=level3 data-number=6.9.7><h3 data-number=6.9.7><span class=header-section-number>6.9.7</span>\n<a href=#toc:advanced-sort-and-filtering-options-in-the-main-page>Advanced\nSort and Filtering Options in the Main Page</a><a href=#advanced-sort-and-filtering-options-in-the-main-page class=anchor aria-hidden=true></a></h3><p>Sort and filter options are now replaced by <a href=#subsubsec:main-list-options>List Options</a> which is highly\nconfigurable, including the ability to filter using profiles.</section><section id=about-this-device class=level3 data-number=6.9.8><h3 data-number=6.9.8><span class=header-section-number>6.9.8</span>\n<a href=#toc:about-this-device>About This Device</a><a href=#about-this-device class=anchor aria-hidden=true></a></h3><p>Interested in knowing about your device in just one page? Go to the\nbottom of the <a href=#subsec:device-info>settings page</a>.</section><section id=enabledisable-features class=level3 data-number=6.9.9><h3 data-number=6.9.9><span class=header-section-number>6.9.9</span>\n<a href=#toc:enabledisable-features>Enable/disable Features</a><a href=#enabledisable-features class=anchor aria-hidden=true></a></h3><p>Not interested in all the features that AM offers? You can disable\nsome features in <a href=#subsubsec:enable/disable-features>settings</a>.</section><section id=new-languages-1 class=level3 data-number=6.9.10><h3 data-number=6.9.10><span class=header-section-number>6.9.10</span> <a href=#toc:new-languages-1>New Languages</a><a href=#new-languages-1 class=anchor aria-hidden=true></a></h3><p>AM now has more than 19 languages! New languages include Farsi,\nJapanese and Traditional Chinese.</section><section id=signing-the-apk-files class=level3 data-number=6.9.11><h3 data-number=6.9.11><span class=header-section-number>6.9.11</span> <a href=#toc:signing-the-apk-files>Signing the APK Files</a><a href=#signing-the-apk-files class=anchor aria-hidden=true></a></h3><p>You can now import external signing keys in AM! For security, App\nManager has its own encrypted KeyStore which can also be <a href=#subsubsec:import/export-keystore>imported or exported</a>.</section><section id=new-extension-unapkm class=level3 data-number=6.9.12><h3 data-number=6.9.12><span class=header-section-number>6.9.12</span> <a href=#toc:new-extension-unapkm>New Extension: UnAPKM</a><a href=#new-extension-unapkm class=anchor aria-hidden=true></a></h3><p>Since APKMirror has removed encryption from their APKM files, it’s no\nlonger necessary to decrypt them. As a result, the option to decrypt\nAPKM files has been removed. Instead, this option is now provided by the\nUnAPKM extension which you can grab from <a href=https://f-droid.org/packages/io.github.muntashirakon.unapkm/>F-Droid</a>.\nSo, if you have an encrypted APKM file and have this extension\ninstalled, you can open the file directly in AM.</section></section><section id=sec:v2.5.20-(375) class=level2 data-number=6.10><h2 data-number=6.10><span class=header-section-number>6.10</span>\n<a href=#toc:sec:v2.5.20-(375)>v2.5.20 (375)</a><a href=#sec:v2.5.20-(375) class=anchor aria-hidden=true></a></h2><section id=subsec:introducing-profiles class=level3 data-number=6.10.1><h3 data-number=6.10.1><span class=header-section-number>6.10.1</span> <a href=#toc:subsec:introducing-profiles>Introducing Profiles</a><a href=#subsec:introducing-profiles class=anchor aria-hidden=true></a></h3><p><a href=#sec:profile-page>Profiles</a> finally closes the <a href=https://github.com/MuntashirAkon/AppManager/issues/72>related\nissue</a>. Profiles can be used to execute certain tasks repeatedly\nwithout doing everything manually. A profile can be applied (or invoked)\neither from the <a href=#sec:profiles-page>Profiles page</a> or from\nthe home screen by creating shortcuts. There are also some presets which\nconsist of debloating profiles taken from <a href=https://gitlab.com/W1nst0n/universal-android-debloater>Universal\nAndroid Debloater</a>.<section id=known-limitations class=level5 data-number=6.10.1.0.1><h5 data-number=6.10.1.0.1><span class=header-section-number>6.10.1.0.1</span> Known limitations<a href=#known-limitations class=anchor aria-hidden=true></a></h5><ul class=incremental><li><p>Exporting rules and applying permissions are not currently\nworking.<li><p>Profiles are applied for all users.</ul></section></section><section id=subsec:the-interceptor class=level3 data-number=6.10.2><h3 data-number=6.10.2><span class=header-section-number>6.10.2</span> <a href=#toc:subsec:the-interceptor>The Interceptor</a><a href=#subsec:the-interceptor class=anchor aria-hidden=true></a></h3><p><a href=https://github.com/MuntashirAkon/intent-intercept>Intent\nIntercept</a> works as a man-in-the-middle between source and\ndestination, that is, when you open a file or URL with another app, you\ncan see what is being shared by opening it with Interceptor first. You\ncan also add or modify the intents before sending them to the\ndestination. Additionally, you can double-click on any exportable\nactivities in the Activities tab in the App Details page to open them in\nthe Interceptor to add more configurations.<section id=known-limitation-2 class=level5 data-number=6.10.2.0.1><h5 data-number=6.10.2.0.1><span class=header-section-number>6.10.2.0.1</span> Known limitation<a href=#known-limitation-2 class=anchor aria-hidden=true></a></h5><p>Editing extras is not currently possible.</section></section><section id=subsec:unapkm:-dedrm-the-apkm-files class=level3 data-number=6.10.3><h3 data-number=6.10.3><span class=header-section-number>6.10.3</span> <a href=#toc:subsec:unapkm:-dedrm-the-apkm-files>UnAPKM: DeDRM the APKM\nfiles</a><a href=#subsec:unapkm:-dedrm-the-apkm-files class=anchor aria-hidden=true></a></h3><p>When I released a small tool called <a href=https://f-droid.org/en/packages/io.github.muntashirakon.unapkm>UnAPKM</a>,\nI promised that similar feature will be available in App Manager. I am\nproud to announce that you can open APKM files directly in the App Info\npage or convert them to APKS or install them directly.</section><section id=subsec:multiple-user class=level3 data-number=6.10.4><h3 data-number=6.10.4><span class=header-section-number>6.10.4</span> <a href=#toc:subsec:multiple-user>Multiple user</a><a href=#subsec:multiple-user class=anchor aria-hidden=true></a></h3><p>App manager now supports multiple users! For now, this requires root\nor ADB. But no-root support is also being considered. If you have\nmultiple users enabled and click on an app installed in multiple\nprofiles, an alert prompt will be displayed where you can select the\nuser.</section><section id=vive-la-france class=level3 data-number=6.10.5><h3 data-number=6.10.5><span class=header-section-number>6.10.5</span> <a href=#toc:vive-la-france>Vive la France!</a><a href=#vive-la-france class=anchor aria-hidden=true></a></h3><p>Thanks to the contributors, we have one more addition to the language\nclub: French. You can add more languages or improve existing\ntranslations at <a href=https://hosted.weblate.org/engage/app-manager>Weblate</a>.</section><section id=report-crashes class=level3 data-number=6.10.6><h3 data-number=6.10.6><span class=header-section-number>6.10.6</span> <a href=#toc:report-crashes>Report crashes</a><a href=#report-crashes class=anchor aria-hidden=true></a></h3><p>If App Manager crashes, you can now easily report the crash from the\nnotifications which opens the share options. Crashes are not reported by\nApp Manager, it only redirects you to your favourite Email client.</section><section id=android-11 class=level3 data-number=6.10.7><h3 data-number=6.10.7><span class=header-section-number>6.10.7</span> <a href=#toc:android-11>Android 11</a><a href=#android-11 class=anchor aria-hidden=true></a></h3><p>Added support for Android 11. Not everything may work as expected\nthough.</section><section id=app-installer-improvements class=level3 data-number=6.10.8><h3 data-number=6.10.8><span class=header-section-number>6.10.8</span> <a href=#toc:app-installer-improvements>App Installer Improvements</a><a href=#app-installer-improvements class=anchor aria-hidden=true></a></h3><section id=set-installation-locations class=level4 data-number=6.10.8.1><h4 data-number=6.10.8.1><span class=header-section-number>6.10.8.1</span> Set installation\nlocations<a href=#set-installation-locations class=anchor aria-hidden=true></a></h4><p>In settings page, you can set install locations such as auto\n(default), internal only and prefer external.</section><section id=set-apk-installer class=level4 data-number=6.10.8.2><h4 data-number=6.10.8.2><span class=header-section-number>6.10.8.2</span> Set APK installer<a href=#set-apk-installer class=anchor aria-hidden=true></a></h4><p>In settings page, you can also set default APK installer (root/ADB\nonly) instead of App Manager.</section><section id=multiple-users class=level4 data-number=6.10.8.3><h4 data-number=6.10.8.3><span class=header-section-number>6.10.8.3</span> Multiple users<a href=#multiple-users class=anchor aria-hidden=true></a></h4><p>In settings page, you can allow App Manager to display multiple users\nduring APK installation.</section><section id=signing-apk-files class=level4 data-number=6.10.8.4><h4 data-number=6.10.8.4><span class=header-section-number>6.10.8.4</span> Signing APK files<a href=#signing-apk-files class=anchor aria-hidden=true></a></h4><p>In settings page, you can choose to sign APK files before installing\nthem. You can also select which signature scheme to use in the <em>APK\nsigning</em> option in settings.<section id=known-limitation-3 class=level5 data-number=6.10.8.4.1><h5 data-number=6.10.8.4.1><span class=header-section-number>6.10.8.4.1</span> Known limitation<a href=#known-limitation-3 class=anchor aria-hidden=true></a></h5><p>Currently, only a generic key is used to sign APK files</section></section></section></section><section id=v2.5.17-368 class=level2 data-number=6.11><h2 data-number=6.11><span class=header-section-number>6.11</span>\n<a href=#toc:v2.5.17-368>v2.5.17 (368)</a><a href=#v2.5.17-368 class=anchor aria-hidden=true></a></h2><section id=app-installer class=level3 data-number=6.11.1><h3 data-number=6.11.1><span class=header-section-number>6.11.1</span> <a href=#toc:app-installer>App Installer</a><a href=#app-installer class=anchor aria-hidden=true></a></h3><p>As promised, it is now possible to select splits. AM also provides\nrecommendations based on device configurations. If the app is already\ninstalled, recommendations are provided based on the installed app. It\nis also possible to downgrade to a lower version without data loss if\nthe device has root or ADB. But it should be noted that not all app can\nbe downgraded. Installer is also improved to speed up the installation\nprocess, especially, for root users. If the app has already been\ninstalled and the new (x)apk(s) is newer or older or the same version\nwith a different signature, AM will display a list of changes similar to\n<strong>What’s New</strong> before prompting the user to install the\napp. This is useful if the app has introduced tracker components, new\npermissions, etc.<section id=known-limitations-1 class=level5 data-number=6.11.1.0.1><h5 data-number=6.11.1.0.1><span class=header-section-number>6.11.1.0.1</span> Known Limitations<a href=#known-limitations-1 class=anchor aria-hidden=true></a></h5><ul class=incremental><li><p>Large app can take a long time to fetch app info, and therefore,\nit may take a long time display the installation prompt.<li><p>If the apk is not located in the internal storage, the app has to\nbe cached first which might also take a long time depending on the size\nof the apk.</ul></section></section><section id=scanner-replacement-for-exodus-page class=level3 data-number=6.11.2><h3 data-number=6.11.2><span class=header-section-number>6.11.2</span> <a href=#toc:scanner-replacement-for-exodus-page>Scanner: Replacement for\nExodus Page</a><a href=#scanner-replacement-for-exodus-page class=anchor aria-hidden=true></a></h3><p>Exodus page is now replaced with scanner page. <a href=#sec:scanner-page>Scanner page</a> contains not only a list of\ntrackers but also a list of used libraries. This is just a start. In the\nfuture, this page will contain more in depth analysis of the app.</section><section id=introducing-system-config class=level3 data-number=6.11.3><h3 data-number=6.11.3><span class=header-section-number>6.11.3</span> <a href=#toc:introducing-system-config>Introducing System Config</a><a href=#introducing-system-config class=anchor aria-hidden=true></a></h3><p>System Config lists various system configurations and\nwhitelists/blacklists included in Android by either OEM/vendor, AOSP or\neven some Magisk modules. Root users can access this option from the\noverflow menu in the main page. There isn’t any official documentation\nfor these options therefore it’s difficult to write a complete\ndocumentation for this page. I will gradually add documentations using\nmy own knowledge. However, some functions should be understandable by\ntheir name.</section><section id=more-languages class=level3 data-number=6.11.4><h3 data-number=6.11.4><span class=header-section-number>6.11.4</span> <a href=#toc:more-languages>More Languages</a><a href=#more-languages class=anchor aria-hidden=true></a></h3><p>Thanks to the contributors, AM now has more than 12 languages. New\nlanguages include Bengali, Hindi, Norwegian, Polish, Russian, Simplified\nChinese, Turkish and Ukrainian.</section><section id=app-info-tab class=level3 data-number=6.11.5><h3 data-number=6.11.5><span class=header-section-number>6.11.5</span> <a href=#toc:app-info-tab>App Info Tab</a><a href=#app-info-tab class=anchor aria-hidden=true></a></h3><p>More tags are added in the <a href=#subsec:app-info-tab>app info\ntab</a> such as <strong>KeyStore</strong> (apps with KeyStore items),\n<strong>Systemless app</strong> (apps installed via Magisk),\n<strong>Running</strong> (apps that are running). For external apk, two\nmore options are added namely <strong>Reinstall</strong> and\n<strong>Downgrade</strong>. Now it is possible to share an apk via\nBluetooth. For system apps, it is possible to uninstall updates for\nroot/ADB users. But like the similar option in the system settings, this\noperation will clear all app data. As stated above, exodus has been\nreplaced with scanner.</section><section id=navigation-improvements class=level3 data-number=6.11.6><h3 data-number=6.11.6><span class=header-section-number>6.11.6</span> <a href=#toc:navigation-improvements>Navigation Improvements</a><a href=#navigation-improvements class=anchor aria-hidden=true></a></h3><p>It’s now relatively easy to navigate to various UI components using\nkeyboard. You can use up/down button to navigate between list items and\ntab button to navigate to UI components inside an item.</section><section id=running-apps-page class=level3 data-number=6.11.7><h3 data-number=6.11.7><span class=header-section-number>6.11.7</span> <a href=#toc:running-apps-page>Running Apps Page</a><a href=#running-apps-page class=anchor aria-hidden=true></a></h3><p>It is now possible to sort and filter processes in this tab. Also,\nthe three big buttons are replaced with an easy-to-use three dot menu.\nPreviously the memory usage was wrong which is fixed in this\nversion.</section><section id=built-in-toybox class=level3 data-number=6.11.8><h3 data-number=6.11.8><span class=header-section-number>6.11.8</span> <a href=#toc:built-in-toybox>Built-in Toybox</a><a href=#built-in-toybox class=anchor aria-hidden=true></a></h3><p>Toybox (an alternative to busybox) is bundled with AM. Although\nAndroid has this utility built-in from API 23, toybox is bundled in\norder to prevent buggy implementations and to support API &lt; 23.</section><section id=component-blocker-improvements class=level3 data-number=6.11.9><h3 data-number=6.11.9><span class=header-section-number>6.11.9</span> <a href=#toc:component-blocker-improvements>Component Blocker\nImprovements</a><a href=#component-blocker-improvements class=anchor aria-hidden=true></a></h3><p>Component blocker seemed to be problematic in the previous version,\nespecially when global component blocking is enabled. The issues are\nmostly fixed now.<div class=\"amalert warning\"><p><strong><em>Caution.</em></strong><p>The component blocking mechanism is no longer compatible with v2.5.6\ndue to various security issues. If you have this version, upgrade to\nv2.5.13 or earlier versions first. After that, enable <a href=#subsubsec:instant-component-blocking>global component\nblocking</a> and disable it again.</div></section><section id=improvements-in-the-app-details-page class=level3 data-number=6.11.10><h3 data-number=6.11.10><span class=header-section-number>6.11.10</span> <a href=#toc:improvements-in-the-app-details-page>Improvements in the App\nDetails Page</a><a href=#improvements-in-the-app-details-page class=anchor aria-hidden=true></a></h3><p>Value of various app ops depend on their parent app ops. Therefore,\nwhen you allow/deny an app op, the parent of the app op gets modified.\nThis fixes the issues some users have been complaining regarding some\napp ops that couldn’t be changed.<p>If an app has the target API 23 or less, its permissions cannot be\nmodified using the <code>pm grant …</code> command. Therefore, for such\napps, option to toggle permission has been disabled.<p>The signature tab is improved to support localization. It also\ndisplays multiple checksums for a signature.</section><section id=app-manifest class=level3 data-number=6.11.11><h3 data-number=6.11.11><span class=header-section-number>6.11.11</span> <a href=#toc:app-manifest>App Manifest</a><a href=#app-manifest class=anchor aria-hidden=true></a></h3><p>Manifest no longer crashes if the size of the manifest is too long.\nGenerated manifest are now more accurate than before.</section></section><section id=v2.5.13-348 class=level2 data-number=6.12><h2 data-number=6.12><span class=header-section-number>6.12</span>\n<a href=#toc:v2.5.13-348>v2.5.13 (348)</a><a href=#v2.5.13-348 class=anchor aria-hidden=true></a></h2><section id=bundled-app-split-apk class=level3 data-number=6.12.1><h3 data-number=6.12.1><span class=header-section-number>6.12.1</span> <a href=#toc:bundled-app-split-apk>Bundled App (Split APK)</a><a href=#bundled-app-split-apk class=anchor aria-hidden=true></a></h3><p>Bundled app formats such as <strong>apks</strong> and\n<strong>xapk</strong> are now supported. You can install these apps\nusing the regular installation buttons. For root and adb users, apps are\ninstalled using shell, and for non-root users, the platform default\nmethod is used.<section id=known-limitations-2 class=level5 data-number=6.12.1.0.1><h5 data-number=6.12.1.0.1><span class=header-section-number>6.12.1.0.1</span> Known Limitations<a href=#known-limitations-2 class=anchor aria-hidden=true></a></h5><ul class=incremental><li><p>Currently <em>all</em> splits apks are installed. But this\nbehaviour is going to change in the next release. If you only need a few\nsplits instead of all, extract the <strong>APKS</strong> or\n<strong>XAPK</strong> file, and then, create a new zip file with your\ndesired split apks and replace the <strong>ZIP</strong> extension with\n<strong>APKS</strong>. Now, open it with AM.<li><p>There is no progress dialog to display the installation\nprogress.</ul></section></section><section id=direct-install-support class=level3 data-number=6.12.2><h3 data-number=6.12.2><span class=header-section-number>6.12.2</span> <a href=#toc:direct-install-support>Direct Install Support</a><a href=#direct-install-support class=anchor aria-hidden=true></a></h3><p>You can now install <strong>APK</strong>, <strong>APKS</strong> or\n<strong>XAPK</strong> directly from your favourite browser or file\nmanager. For apps that need updates, a <strong>What’s New</strong>\ndialog is displayed showing the changes in the new version.<section id=known-limitations-3 class=level5 data-number=6.12.2.0.1><h5 data-number=6.12.2.0.1><span class=header-section-number>6.12.2.0.1</span> Known Limitations<a href=#known-limitations-3 class=anchor aria-hidden=true></a></h5><ul class=incremental><li><p>Downgrade is not yet possible.<li><p>There is no progress dialog to display the installation progress.\nIf you cannot interact with the current page, wait until the\ninstallation is finished.</ul></section></section><section id=remove-all-blocking-rules class=level3 data-number=6.12.3><h3 data-number=6.12.3><span class=header-section-number>6.12.3</span> <a href=#toc:remove-all-blocking-rules>Remove All Blocking Rules</a><a href=#remove-all-blocking-rules class=anchor aria-hidden=true></a></h3><p>In the Settings page, a new option is added which can be used to\nremove all blocking rules configured within App Manager.</section><section id=app-ops class=level3 data-number=6.12.4><h3 data-number=6.12.4><span class=header-section-number>6.12.4</span> <a href=#toc:app-ops>App\nOps</a><a href=#app-ops class=anchor aria-hidden=true></a></h3><ul class=incremental><li><p>App Ops are now generated using a technique similar to AppOpsX.\nThis should decrease the loading time significantly in the App Ops\ntab.<li><p>In the App Ops tab, a menu item is added which can be used to\nlist only active app ops without including the default app ops. The\npreference is saved in the shared preferences.</ul><section id=known-limitation-4 class=level5 data-number=6.12.4.0.1><h5 data-number=6.12.4.0.1><span class=header-section-number>6.12.4.0.1</span> Known Limitation<a href=#known-limitation-4 class=anchor aria-hidden=true></a></h5><p>Often the App Ops tab may not be responsive. If that’s the case,\nrestart App Manager.</section></section><section id=enhanced-adb-support class=level3 data-number=6.12.5><h3 data-number=6.12.5><span class=header-section-number>6.12.5</span> <a href=#toc:enhanced-adb-support>Enhanced ADB Support</a><a href=#enhanced-adb-support class=anchor aria-hidden=true></a></h3><p>ADB shell commands are now executed using a technique similar to\nAppOpsX (This is the <em>free</em> alternative of AppOps by Rikka.).\nThis should dramatically increase the execution time.<section id=known-limitation-5 class=level5 data-number=6.12.5.0.1><h5 data-number=6.12.5.0.1><span class=header-section-number>6.12.5.0.1</span> Known Limitation<a href=#known-limitation-5 class=anchor aria-hidden=true></a></h5><p>AM can often crash or become not responsive. If that’s the case,\nrestart App Manager.</section></section><section id=filtering-in-main-page class=level3 data-number=6.12.6><h3 data-number=6.12.6><span class=header-section-number>6.12.6</span> <a href=#toc:filtering-in-main-page>Filtering in Main Page</a><a href=#filtering-in-main-page class=anchor aria-hidden=true></a></h3><p>Add an option to filter apps that has at least one activity.</section><section id=apk-backupsharing class=level3 data-number=6.12.7><h3 data-number=6.12.7><span class=header-section-number>6.12.7</span> <a href=#toc:apk-backupsharing>Apk Backup/Sharing</a><a href=#apk-backupsharing class=anchor aria-hidden=true></a></h3><p>Apk files are now saved as <code>app name_version.extension</code>\ninstead of <code>package.name.extension</code>.</section><section id=batch-ops class=level3 data-number=6.12.8><h3 data-number=6.12.8><span class=header-section-number>6.12.8</span> <a href=#toc:batch-ops>Batch Ops</a><a href=#batch-ops class=anchor aria-hidden=true></a></h3><ul class=incremental><li><p>Added a foreground service to run batch operations. The result of\nthe operation is displayed in a notification. If an operation has failed\nfor some packages, clicking on the notification will open a dialog box\nlisting the failed packages. There is also a <strong>Try Again</strong>\nbutton on the bottom which can be used to perform the operation again\nfor the failed packages.<li><p>Replaced Linux <em>kill</em> with\n<strong>force-stop</strong>.</ul></section><section id=translations class=level3 data-number=6.12.9><h3 data-number=6.12.9><span class=header-section-number>6.12.9</span> <a href=#toc:translations>Translations</a><a href=#translations class=anchor aria-hidden=true></a></h3><p>Added German and Portuguese (Brazilian) translations.<section id=known-limitation-6 class=level5 data-number=6.12.9.0.1><h5 data-number=6.12.9.0.1><span class=header-section-number>6.12.9.0.1</span> Known Limitation<a href=#known-limitation-6 class=anchor aria-hidden=true></a></h5><p>Not all translations are verified yet.</section></section><section id=app-data-backup class=level3 data-number=6.12.10><h3 data-number=6.12.10><span class=header-section-number>6.12.10</span> <a href=#toc:app-data-backup>App Data Backup</a><a href=#app-data-backup class=anchor aria-hidden=true></a></h3><p>Install app only for the current user at the time of restoring\nbackups. Support for split apks is also added.<p><em>Data backup feature is now considered unstable. If you encounter\nany problem, please report to me without hesitation.</em></section></section></section><section id=ch:app-ops class=level1 data-number=7><h1 data-number=7><span class=header-section-number>7</span> <a href=#toc:ch:app-ops>App Ops</a><a href=#ch:app-ops class=anchor aria-hidden=true></a></h1><section id=sec:app-ops-background class=level2 data-number=7.1><h2 data-number=7.1><span class=header-section-number>7.1</span> <a href=#toc:sec:app-ops-background>Background</a><a href=#sec:app-ops-background class=anchor aria-hidden=true></a></h2><p><strong>App Ops</strong> (short hand for <strong>Application\nOperations</strong>) are used by Android system (since Android 4.3) to\ncontrol application permissions. The user <em>can</em> control some\npermissions, but only the permissions that are considered dangerous (and\nGoogle thinks knowing your phone number isn’t a dangerous thing). So,\napp ops seems to be the one we need if we want to install apps like\nFacebook and it’s Messenger (the latter literary records everything if\nyou live outside the EU) and still want <em>some</em> privacy and/or\nsecurity. Although certain features of app ops were available in\nSettings and later in hidden settings in older version of Android, it’s\ncompletely hidden in newer versions of Android and is continued to be\nkept hidden. Now, any app with\n<strong>android.Manifest.permission.GET_APP_OPS_STATS</strong>\npermission can get the app ops information for other applications but\nthis permission is hidden from users and can only be enabled using ADB\nor root. Still, the app with this permission cannot grant or revoke\npermissions (actually mode of operation) for apps other than itself\n(with limited capacity, of course). To modify the ops of other app, the\napp needs\n<strong>android.Manifest.permission.UPDATE_APP_OPS_STATS</strong>\npermissions which isn’t accessible via <code>pm</code> command. So, you\ncannot grant it via root or ADB, the permission is only granted to the\nsystem apps. There are very few apps who support disabling permissions\nvia app ops. The best one to my knowledge is <a href=https://github.com/8enet/AppOpsX>AppOpsX</a>. The main (visible)\ndifference between my app (AppManager) and this app is that the latter\nalso provides you the ability to revoke internet permissions (by writing\nip tables). One crucial problem that I faced during the development of\nthe app ops API is the lack of documentation in English language.</section><section id=sec:introduction-to-app-ops class=level2 data-number=7.2><h2 data-number=7.2><span class=header-section-number>7.2</span> <a href=#toc:sec:introduction-to-app-ops>Introduction to App Ops</a><a href=#sec:introduction-to-app-ops class=anchor aria-hidden=true></a></h2><figure id=fig:appops><figure><object data=../images/appops.svg type=image/svg+xml></object></figure><figcaption>Figure 2: How app ops work</figcaption></figure><p>Figure <a href=#fig:appops>1</a> describes the process of changing\nand processing permission. <a href=#sec:appopsmanager>AppOpsManager</a> can be used to manage\npermissions in Settings app. <strong>AppOpsManager</strong> is also\nuseful in determining if a certain permission (or operation) is granted\nto the application. Most of the methods of\n<strong>AppOpsManager</strong> are accessible to the user app but unlike\na system app, it can only be used to check permissions for any app or\nfor the app itself and start or terminating certain operations.\nMoreover, not all operations are actually accessible from this Java\nclass. <strong>AppOpsManager</strong> holds all the necessary constants\nsuch as <a href=#subsec:op-constants><code>OP_*</code></a>,\n<code>OPSTR_*</code>, <a href=#subsec:mode-constants><code>MODE_*</code></a> which describes\noperation code, operation string and mode of operations respectively. It\nalso holds necessary data structures such as <a href=#subsec:package-ops>PackageOps</a> and <strong>OpEntry</strong>.\n<strong>PackageOps</strong> holds <strong>OpEntry</strong> for a\npackage, and <strong>OpEntry</strong>, as the name suggests, describes\neach operation.<p><code>AppOpService</code> is completely hidden from a user\napplication but accessible to the system applications. As it can be seen\nin Figure <a href=#fig:appops>1</a>, this is the class that does the\nactual management stuff. It contains data structures such as\n<strong>Ops</strong> to store basic package info and <strong>Op</strong>\nwhich is similar to <strong>OpEntry</strong> of\n<strong>AppOpsManager</strong>. It also has <strong>Shell</strong> which\nis actually the source code of the <a href=#sec:appops-cli><em>appops</em> command line tool</a>. It writes\nconfigurations to or read configurations from <a href=#sec:appops-xml><code>/data/system/appops.xml</code></a>. System\nservices calls <strong>AppOpsService</strong> to find out what an\napplication is allowed and what is not allowed to perform, and\n<strong>AppOpsService</strong> determines these permissions by parsing\n<code>/data/system/appops.xml</code>. If no custom values are present in\n<em>appops.xml</em>, it returns the default mode available in\n<strong>AppOpsManager</strong>.</section><section id=sec:appopsmanager class=level2 data-number=7.3><h2 data-number=7.3><span class=header-section-number>7.3</span> <a href=#toc:sec:appopsmanager>AppOpsManager</a><a href=#sec:appopsmanager class=anchor aria-hidden=true></a></h2><p><a href=https://android.googlesource.com/platform/frameworks/base/+/master/core/java/android/app/AppOpsManager.java>AppOpsManager</a>\nstands for application operations manager. It consists of various\nconstants and classes to modify app operations.<div class=seealso-inline><p><em>See also: <span><a href=https://developer.android.com/reference/android/app/AppOpsManager>AppOpsManager\ndocumentation</a></span></em></div><section id=subsec:op-constants class=level3 data-number=7.3.1><h3 data-number=7.3.1><span class=header-section-number>7.3.1</span>\n<a href=#toc:subsec:op-constants><code>OP_*</code> Constants</a><a href=#subsec:op-constants class=anchor aria-hidden=true></a></h3><p><code>OP_*</code> are the integer constants starting from\n<code>0</code>. <code>OP_NONE</code> implies that no operations are\nspecified whereas <code>_NUM_OP</code> denotes the number of operations\ndefined in <code>OP_*</code> prefix. While they denote each operation,\nthe operations are not necessarily unique. In fact, there are many\noperations that are actually a single operation denoted by multiple\n<code>OP_*</code> constant (possibly for future use). Vendors may define\ntheir own op based on their requirements. MIUI is one of the vendors who\nare known to do that.<div class=listing><div class=sourceCode id=cb11 data-frame=lines><pre class=\"sourceCode java\"><code class=\"sourceCode java\"><span id=cb11-1><a href=#cb11-1 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=dt>final</span> <span class=dt>int</span> OP_NONE <span class=op>=</span> <span class=op>-</span><span class=dv>1</span><span class=op>;</span></span>\n<span id=cb11-2><a href=#cb11-2 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=dt>final</span> <span class=dt>int</span> OP_COARSE_LOCATION <span class=op>=</span> <span class=dv>0</span><span class=op>;</span></span>\n<span id=cb11-3><a href=#cb11-3 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=dt>final</span> <span class=dt>int</span> OP_FINE_LOCATION <span class=op>=</span> <span class=dv>1</span><span class=op>;</span></span>\n<span id=cb11-4><a href=#cb11-4 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=dt>final</span> <span class=dt>int</span> OP_GPS <span class=op>=</span> <span class=dv>2</span><span class=op>;</span></span>\n<span id=cb11-5><a href=#cb11-5 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=dt>final</span> <span class=dt>int</span> OP_VIBRATE <span class=op>=</span> <span class=dv>3</span><span class=op>;</span></span>\n<span id=cb11-6><a href=#cb11-6 aria-hidden=true tabindex=-1></a><span class=kw>...</span></span>\n<span id=cb11-7><a href=#cb11-7 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=dt>final</span> <span class=dt>int</span> OP_READ_DEVICE_IDENTIFIERS <span class=op>=</span> <span class=dv>89</span><span class=op>;</span></span>\n<span id=cb11-8><a href=#cb11-8 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=dt>final</span> <span class=dt>int</span> OP_ACCESS_MEDIA_LOCATION <span class=op>=</span> <span class=dv>90</span><span class=op>;</span></span>\n<span id=cb11-9><a href=#cb11-9 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=dt>final</span> <span class=dt>int</span> OP_ACTIVATE_PLATFORM_VPN <span class=op>=</span> <span class=dv>91</span><span class=op>;</span></span>\n<span id=cb11-10><a href=#cb11-10 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=dt>final</span> <span class=dt>int</span> _NUM_OP <span class=op>=</span> <span class=dv>92</span><span class=op>;</span></span></code></pre></div></div><p>Whether an operation is unique is defined by\n<code>sOpToSwitch</code>. It maps each operation to another operation or\nto itself (if it’s a unique operation). For instance,\n<code>OP_FINE_LOCATION</code> and <code>OP_GPS</code> are mapped to\n<code>OP_COARSE_LOCATION</code>.<p>Each operation has a private name which are described by\n<code>sOpNames</code>. These names are usually the same names as the\nconstants without the <code>OP_</code> prefix. Some operations have\npublic names as well which are described by <code>sOpToString</code>.\nFor instance, <code>OP_COARSE_LOCATION</code> has the public name\n<strong>android:coarse_location</strong>.<p>As a gradual process of moving permissions to app ops, there are\nalready many permissions that are defined under some operations. These\npermissions are mapped in <code>sOpPerms</code>. For example, the\npermission\n<strong>android.Manifest.permission.ACCESS_COARSE_LOCATION</strong> is\nmapped to <code>OP_COARSE_LOCATION</code>. Some operations may not have\nany associated permissions which have <code>null</code> values.<p>As described in the previous section, operations that are configured\nfor an app are stored at <a href=#sec:appops-xml><code>/data/system/appops.xml</code></a>. If an\noperation is not configured, then whether system will allow that\noperation is determined from <code>sOpDefaultMode</code>. It lists the\n<em>default mode</em> for each operation.</section><section id=subsec:mode-constants class=level3 data-number=7.3.2><h3 data-number=7.3.2><span class=header-section-number>7.3.2</span>\n<a href=#toc:subsec:mode-constants><code>MODE_*</code> Constants</a><a href=#subsec:mode-constants class=anchor aria-hidden=true></a></h3><p><code>MODE_*</code> constants also integer constants starting from\n<code>0</code>. These constants are assigned to each operation\ndescribing whether an app is authorised to perform that operation. These\nmodes usually have associated names such as <strong>allow</strong> for\n<code>MODE_ALLOWED</code>, <strong>ignore</strong> for\n<code>MODE_IGNORED</code>, <strong>deny</strong> for\n<code>MODE_ERRORED</code> (a rather misnomer), <strong>default</strong>\nfor <code>MODE_DEFAULT</code> and <strong>foreground</strong> for\n<code>MODE_FOREGROUND</code>.<ol class=incremental><li><p><strong><code>MODE_ALLOWED</code>.</strong> The app is allowed to\nperform the given operation<li><p><strong><code>MODE_IGNORED</code>.</strong> The app is not\nallowed to perform the given operation, and any attempt to perform the\noperation should <em>silently fail</em>, i.e. it should not cause the\napp to crash<li><p><strong><code>MODE_ERRORED</code>.</strong> The app is not\nallowed to perform the given operation, and this attempt should cause it\nto have a fatal error, typically a\n<code>SecurityException</code><li><p><strong><code>MODE_DEFAULT</code>.</strong> The app should use\nits default security check, specified in\n<code>AppOpsManager</code><li><p><strong><code>MODE_FOREGROUND</code>.</strong> Special mode that\nmeans “allow only when app is in foreground.” This mode was added in\nAndroid 10<li><p><strong><code>MODE_ASK</code>.</strong> This is a custom mode\nused by MIUI whose uses are unknown.</ol></section><section id=subsec:package-ops class=level3 data-number=7.3.3><h3 data-number=7.3.3><span class=header-section-number>7.3.3</span>\n<a href=#toc:subsec:package-ops>PackageOps</a><a href=#subsec:package-ops class=anchor aria-hidden=true></a></h3><p><strong>AppOpsManager.PackageOps</strong> is a data structure to\nstore all the <strong>OpEntry</strong> for a package. In simple terms,\nit stores all the customised operations for a package.<div class=listing><div class=sourceCode id=cb12 data-frame=lines><pre class=\"sourceCode java\"><code class=\"sourceCode java\"><span id=cb12-1><a href=#cb12-1 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=kw>class</span> PackageOps <span class=kw>implements</span> Parcelable <span class=op>{</span></span>\n<span id=cb12-2><a href=#cb12-2 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=bu>String</span> mPackageName<span class=op>;</span></span>\n<span id=cb12-3><a href=#cb12-3 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=dt>int</span> mUid<span class=op>;</span></span>\n<span id=cb12-4><a href=#cb12-4 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=bu>List</span><span class=op>&lt;</span>OpEntry<span class=op>&gt;</span> mEntries<span class=op>;</span></span>\n<span id=cb12-5><a href=#cb12-5 aria-hidden=true tabindex=-1></a>    <span class=kw>...</span></span>\n<span id=cb12-6><a href=#cb12-6 aria-hidden=true tabindex=-1></a><span class=op>}</span></span></code></pre></div></div><p>As can be seen in Listing <a href=#lst:package-ops-class>2</a>, it\nstores all <strong>OpEntry</strong> for a package as well as the\ncorresponding package name and its kernel user ID.</section><section id=subsec:opentry class=level3 data-number=7.3.4><h3 data-number=7.3.4><span class=header-section-number>7.3.4</span>\n<a href=#toc:subsec:opentry>OpEntry</a><a href=#subsec:opentry class=anchor aria-hidden=true></a></h3><p><strong>AppOpsManager.OpEntry</strong> is a data structure that\nstores a single operation for any package.<div class=listing><div class=sourceCode id=cb13 data-frame=lines><pre class=\"sourceCode java\"><code class=\"sourceCode java\"><span id=cb13-1><a href=#cb13-1 aria-hidden=true tabindex=-1></a><span class=kw>public</span> <span class=dt>static</span> <span class=dt>final</span> <span class=kw>class</span> OpEntry <span class=kw>implements</span> Parcelable <span class=op>{</span></span>\n<span id=cb13-2><a href=#cb13-2 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=dt>int</span> mOp<span class=op>;</span></span>\n<span id=cb13-3><a href=#cb13-3 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=dt>boolean</span> mRunning<span class=op>;</span></span>\n<span id=cb13-4><a href=#cb13-4 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=at>@Mode</span> <span class=dt>int</span> mMode<span class=op>;</span></span>\n<span id=cb13-5><a href=#cb13-5 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=at>@Nullable</span> LongSparseLongArray mAccessTimes<span class=op>;</span></span>\n<span id=cb13-6><a href=#cb13-6 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=at>@Nullable</span> LongSparseLongArray mRejectTimes<span class=op>;</span></span>\n<span id=cb13-7><a href=#cb13-7 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=at>@Nullable</span> LongSparseLongArray mDurations<span class=op>;</span></span>\n<span id=cb13-8><a href=#cb13-8 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=at>@Nullable</span> LongSparseLongArray mProxyUids<span class=op>;</span></span>\n<span id=cb13-9><a href=#cb13-9 aria-hidden=true tabindex=-1></a>    <span class=kw>private</span> <span class=dt>final</span> <span class=at>@Nullable</span> LongSparseArray<span class=op>&lt;</span><span class=bu>String</span><span class=op>&gt;</span> mProxyPackageNames<span class=op>;</span></span>\n<span id=cb13-10><a href=#cb13-10 aria-hidden=true tabindex=-1></a>    <span class=kw>...</span></span>\n<span id=cb13-11><a href=#cb13-11 aria-hidden=true tabindex=-1></a><span class=op>}</span></span></code></pre></div></div><p>Here:<ul class=incremental><li><p><code>mOp</code>: Denotes one of the <a href=#subsec:op-constants><code>OP_*</code> constants</a><li><p><code>mRunning</code>: Whether the operation is in progress\n(i.e. the operation has started but not finished yet). Not all\noperations can be started or finished this way<li><p><code>mMOde</code>: One of the <a href=#subsec:mode-constants><code>MODE_*</code> constants</a><li><p><code>mAccessTimes</code>: Stores all the available access\ntimes<li><p><code>mRejectTimes</code>: Stores all the available reject\ntimes<li><p><code>mDurations</code>: All available access durations, checking\nthis with <code>mRunning</code> will tell you for how long the app is\nperforming a certain app operation<li><p><code>mProxyUids</code>: No documentation found<li><p><code>mProxyPackageNames:</code> No documentation found</ul></section><section id=subsec:usage class=level3 data-number=7.3.5><h3 data-number=7.3.5><span class=header-section-number>7.3.5</span>\n<a href=#toc:subsec:usage>Usage</a><a href=#subsec:usage class=anchor aria-hidden=true></a></h3><p>TODO</section></section><section id=sec:appopsservice class=level2 data-number=7.4><h2 data-number=7.4><span class=header-section-number>7.4</span> <a href=#toc:sec:appopsservice>AppOpsService</a><a href=#sec:appopsservice class=anchor aria-hidden=true></a></h2><p>TODO</section><section id=sec:appops-xml class=level2 data-number=7.5><h2 data-number=7.5><span class=header-section-number>7.5</span> <a href=#toc:sec:appops-xml>appops.xml</a><a href=#sec:appops-xml class=anchor aria-hidden=true></a></h2><p>Latest <code>appops.xml</code> has the following format: (This DTD is\nmade by me and by no means perfect, has compatibility issues.)<pre><code>&lt;!DOCTYPE app-ops [\n\n&lt;!ELEMENT app-ops (uid|pkg)*&gt;\n&lt;!ATTLIST app-ops v CDATA #IMPLIED&gt;\n\n&lt;!ELEMENT uid (op)*&gt;\n&lt;!ATTLIST uid n CDATA #REQUIRED&gt;\n\n&lt;!ELEMENT pkg (uid)*&gt;\n&lt;!ATTLIST pkg n CDATA #REQUIRED&gt;\n\n&lt;!ELEMENT uid (op)*&gt;\n&lt;!ATTLIST uid\nn CDATA #REQUIRED\np CDATA #IMPLIED&gt;\n\n&lt;!ELEMENT op (st)*&gt;\n&lt;!ATTLIST op\nn CDATA #REQUIRED\nm CDATA #REQUIRED&gt;\n\n&lt;!ELEMENT st EMPTY&gt;\n&lt;!ATTLIST st\nn CDATA #REQUIRED\nt CDATA #IMPLIED\nr CDATA #IMPLIED\nd CDATA #IMPLIED\npp CDATA #IMPLIED\npu CDATA #IMPLIED&gt;\n\n]&gt;</code></pre><p>The instruction below follows the exact order given above:<ul class=incremental><li><p><code>app-ops</code>: The root element. It can contain any number\nof <code>pkg</code> or package <code>uid</code><ul class=incremental><li><p><code>v</code>: (optional, integer) The version number (default:\n<code>NO_VERSION</code> or <code>-1</code>)</ul><li><p><code>pkg</code>: Stores package info. It can contain any number\nof <code>uid</code><ul class=incremental><li><p><code>n</code>: (required, string) Name of the package</ul><li><p>Package <code>uid</code>: Stores package or packages info<ul class=incremental><li><p><code>n</code>: (required, integer) The user ID</ul><li><p><code>uid</code>: The package user ID. It can contain any number\nof <code>op</code><ul class=incremental><li><p><code>n</code>: (required, integer) The user ID<li><p><code>p</code>: (optional, boolean) Is the app is a\nprivate/system app</ul><li><p><code>op</code>: The operation, can contain <code>st</code> or\nnothing at all<ul class=incremental><li><p><code>n</code>: (required, integer) The op name in integer,\ni.e. AppOpsManager.OP_*<li><p><code>m</code>: (required, integer) The op mode,\ni.e. AppOpsManager.MODE_*</ul><li><p><code>st</code>: State of operation: whether the operation is\naccessed, rejected or running (not available on old versions)<ul class=incremental><li><p><code>n</code>: (required, long) Key containing flags and\nuid<li><p><code>t</code>: (optional, long) Access time (default:\n<code>0</code>)<li><p><code>r</code>: (optional, long) Reject time (default:\n<code>0</code>)<li><p><code>d</code>: (optional, long) Access duration (default:\n<code>0</code>)<li><p><code>pp</code>: (optional, string) Proxy package name<li><p><code>pu</code>: (optional, integer) Proxy package uid</ul></ul><p>This definition can be found at <a href=https://android.googlesource.com/platform/frameworks/base/+/master/services/core/java/com/android/server/appop/AppOpsService.java>AppOpsService</a>.</section><section id=sec:appops-cli class=level2 data-number=7.6><h2 data-number=7.6><span class=header-section-number>7.6</span> <a href=#toc:sec:appops-cli>Command Line Interface</a><a href=#sec:appops-cli class=anchor aria-hidden=true></a></h2><p><code>appops</code> or <code>cmd appops</code> (on latest versions)\ncan be accessible via ADB or root. This is an easier method to get or\nupdate any operation for a package (provided the package name is known).\nThe help page of this command is self-explanatory:<pre><code>AppOps service (appops) commands:\nhelp\nPrint this help text.\nstart [--user &lt;USER_ID&gt;] &lt;PACKAGE | UID&gt; &lt;OP&gt;\nStarts a given operation for a particular application.\nstop [--user &lt;USER_ID&gt;] &lt;PACKAGE | UID&gt; &lt;OP&gt;\nStops a given operation for a particular application.\nset [--user &lt;USER_ID&gt;] &lt;[--uid] PACKAGE | UID&gt; &lt;OP&gt; &lt;MODE&gt;\nSet the mode for a particular application and operation.\nget [--user &lt;USER_ID&gt;] &lt;PACKAGE | UID&gt; [&lt;OP&gt;]\nReturn the mode for a particular application and optional operation.\nquery-op [--user &lt;USER_ID&gt;] &lt;OP&gt; [&lt;MODE&gt;]\nPrint all packages that currently have the given op in the given mode.\nreset [--user &lt;USER_ID&gt;] [&lt;PACKAGE&gt;]\nReset the given application or all applications to default modes.\nwrite-settings\nImmediately write pending changes to storage.\nread-settings\nRead the last written settings, replacing current state in RAM.\noptions:\n&lt;PACKAGE&gt; an Android package name or its UID if prefixed by --uid\n&lt;OP&gt;      an AppOps operation.\n&lt;MODE&gt;    one of allow, ignore, deny, or default\n&lt;USER_ID&gt; the user id under which the package is installed. If --user is not\nspecified, the current user is assumed.</code></pre></section></section><section id=footnotes class=\"footnotes footnotes-end-of-document\" role=doc-endnotes><hr><ol><li id=fn1><p>For distributing normal releases only<a href=#fnref1 class=footnote-back role=doc-backlink>↩︎</a><li id=fn2><p>GitHub 的 PR 將使用 git patch 進行手動合並, 因此, GitHub\n可能會錯誤地將它們標記為closed而不是merged.<a href=#fnref2 class=footnote-back role=doc-backlink>↩︎</a><li id=fn3><p>可稱“Muntashir Akon”<a href=#fnref3 class=footnote-back role=doc-backlink>↩︎</a></ol></section>"
  },
  {
    "path": "docs/raw/zh-rTW/strings.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <string name=\"intro$main$$bin-sources-title\">二進制(可執行)分發來源</string>\n    <string name=\"intro$main$$translations-title\">翻譯</string>\n    <string name=\"intro$main$$contributing-title\">貢獻</string>\n    <string name=\"intro$main$$buiding-title\">構建說明</string>\n    <string name=\"intro$main$$submit-patches-title\">提交補丁</string>\n    <string name=\"intro$main$$source-code-links-title\">源碼鏈接</string>\n    <string name=\"pages$main-page$$apk-updater-title\">APK更新器</string>\n    <string name=\"pages$main-page$$settings-title\">設置</string>\n    <string name=\"intro$main$$official-sources-title\">官方來源</string>\n    <string name=\"intro$main$$contact-title\">聯系我們</string>\n    <string name=\"intro$main$$donation-title\">捐贈 \\\\&amp; 資助</string>\n    <string name=\"intro$main$source-code-links\">除了GitHub外其他都是鏡像鏈接。tags 應當始終是最新的，但 master 分支不保證是\n\\n最新的。如果計劃 clone master 分支，請使用 GitHub 鏈接而不是其他鏈接。</string>\n    <string name=\"intro$main$bin-sources\">App Manager 通過以下渠道發布。\n\\n非官方來源可能分發 App Manager 的修改版本，後果自負。\n\\n\\\\begin{enumerate}\n\\n \\\\item F-Droid \\\\footnote{For distributing normal releases only}\\\\\\\\\n\\n \\\\textit{Link:} \\\\url{https://f-droid.org/packages/io.github.muntashirakon.AppManager}\n\\n \\\\item GitHub repository.\\\\\\\\\n\\n \\\\textit{Normal releases:} \\\\url{https://github.com/MuntashirAkon/AppManager/releases}\\\\\\\\\n\\n \\\\textit{Debug releases:} \\\\url{https://github.com/MuntashirAkon/AppManager/actions}\n\\n \\\\item Telegram.\\\\\\\\\n\\n \\\\textit{Normal releases:} \\\\url{https://t.me/AppManagerChannel}\\\\\\\\\n\\n \\\\textit{Debug releases:} \\\\url{https://t.me/AppManagerDebug}\n\\n\\\\end{enumerate}</string>\n    <string name=\"pages$main-page$$version-info-title\">版本信息</string>\n    <string name=\"pages$main-page$$options-menu-title\">選項菜單</string>\n    <string name=\"pages$main-page$$1-click-ops-title\">一鍵操作</string>\n    <string name=\"pages$main$$pages-chapter-title\">頁面</string>\n    <string name=\"pages$main-page$$batch-operations-title\">批處理</string>\n    <string name=\"pages$main-page$$instructions-title\">說明</string>\n    <string name=\"pages$main-page$$filter-title\">篩選</string>\n    <string name=\"pages$main-page$$colour-codes-title\">顏色代碼含義</string>\n    <string name=\"pages$main-page$$profile_name-title\">配置文件名稱</string>\n    <string name=\"pages$main-page$$profiles-title\">配置文件</string>\n    <string name=\"pages$main-page$$application-types-title\">應用類型</string>\n    <string name=\"pages$main-page$$app-usage-title\">應用使用情況</string>\n    <string name=\"pages$main-page$$running-apps-title\">正在運行的應用</string>\n    <string name=\"pages$main-page$$section-title\">主頁</string>\n    <string name=\"pages$main-page$$how-app-ops-work-title\">主頁面中的一個應用程序列表項</string>\n    <string name=\"pages$app-details-page$$servcies-title\">服務 (Services)</string>\n    <string name=\"pages$app-details-page$$receivers-title\">(廣播)接收器 ((Broadcast)Receiver)</string>\n    <string name=\"pages$app-details-page$$blocking-components-title\">阻止組件</string>\n    <string name=\"pages$app-details-page$$uses-permissions-title\">使用權限</string>\n    <string name=\"pages$app-details-page$$permissions-title\">權限</string>\n    <string name=\"pages$app-details-page$$app-ops-title\">App Ops</string>\n    <string name=\"pages$app-details-page$$permission-tabs-title\">權限選項卡</string>\n    <string name=\"pages$app-details-page$$signatures-tab-title\">簽名選項卡</string>\n    <string name=\"pages$app-details-page$$blocking-trackers-title\">阻止跟蹤器</string>\n    <string name=\"pages$app-details-page$intro\">\\\\textbf{應用詳情} 頁面由 11 個標簽頁組成。它描述了一個應用程序所能有的幾乎所有信息,\n\\n包括其清單中的所有屬性、\\\\hyperref[ch:app-ops]{應用操作}、簽名\n\\n信息、庫等等。</string>\n    <string name=\"pages$app-details-page$app-info-tab\">\\\\textbf{應用信息} 選項卡包含關於一個應用程序的基本信息,\n\\n許多操作可以在此標簽中執行.</string>\n    <string name=\"intro$main$supported-versions\">當前，支持的版本是v2.6.0（穩定版），v3.0.0（alpha和debug版）。先前版本的 App\n\\nManager 可能包含安全漏洞，不應繼續使用。</string>\n    <string name=\"pages$app-details-page$$providers-title\">(內容)提供者 ((Content)Providers)</string>\n    <string name=\"pages$app-details-page$$additional-features-for-rooted-phones-title\">針對已root的手機的額外功能</string>\n    <string name=\"intro$main$terminologies\">\\\\begin{itemize}\n\\n \\\\item \\\\textbf{AM} --- App Manager\n\\n \\\\item \\\\textbf{Block/Unblock} --- Used for component blocking or unblocking. How components are blocked depends on\n\\n the user preferences.\n\\n \\\\item \\\\textbf{IFW} --- Intent Firewall (意圖防火墻)\n\\n \\\\item \\\\textbf{Ops} --- operations (操作), e.g.\\\\ app ops, batch ops, 1-click ops\n\\n \\\\item \\\\textbf{SSAID} --- \\\\texttt{Settings.Secure.ANDROID\\\\_ID} - 分配給每個應用的設備標識符 (Android Oreo及以上版本)，由應用簽名與包\\\\texttt{android}的SSAID組合生成的。因此，除非用戶選擇格式化設備，否則它保證對每個應用來說都是獨一無二的。它被廣泛用於跟蹤用戶。\n\\n \\\\item \\\\textbf{Tracker} --- Denotes tracker components throughout the document and in App Manager except in the\n\\n \\\\hyperref[sec:scanner-page]{scanner page}. Trackers include libraries such as crash reporters, analytics,\n\\n profiling, identification, ad, location, etc. Thus, they are not equal in functions. There is no distinction or bias\n\\n between open source and closed source libraries that promote tracking.\n\\n\\\\end{itemize}</string>\n    <string name=\"pages$main-page$instructions\">點擊 \\\\textbf{指南} 打開離線版的App Manager用戶手冊.\n\\n它也可能打開在線版本如果如果相應的功能拆分\\\\texttt{feat\\\\_docs}未安裝,\n\\n或系統 WebView不存在.</string>\n    <string name=\"pages$main-page$colour-codes\">\\\\begin{itemize}\n\\n \\\\item \\\\colorbox{AMLightGreyishOrange}{\\\\textcolor{black}{淺灰橙(日間模式下)}} / \\\\colorbox{AMDarkBlue}{\n\\n \\\\textcolor{white}{深藍(夜間模式下)}} -- 多選模式下被選中的應用\n\\n \\\\item \\\\colorbox{AMLightRed}{\\\\textcolor{black}{淺紅(日間模式下)}} / \\\\colorbox{AMVeryDarkRed}{\\\\textcolor{white}\n\\n {深紅 (夜間模式下)}} -- 停用的應用\n\\n \\\\item \\\\colorbox{AMYellow}{\\\\textcolor{black}{黃色星標}} -- 可調試的應用\n\\n \\\\item \\\\textcolor{AMOrange}{橙色 \\\\textit{日期}} -- 應用可讀取日志\n\\n \\\\item \\\\textcolor{AMOrange}{橙色 \\\\textit{UID}} -- 用戶 ID 在應用間被共享\n\\n \\\\item \\\\textcolor{AMOrange}{橙色 \\\\textit{SDK}} -- 使用明文網絡通信(如 HTTP)\n\\n \\\\item \\\\textcolor{red}{紅色 \\\\textit{包名}} -- 應用禁止清除數據\n\\n \\\\item \\\\textcolor{red}{紅色\\\\textit{備份標識}} -- 已卸載的應用存在一個或多個備份\n\\n \\\\item \\\\textcolor{AMOrange}{橙色\\\\textit{備份標識}} -- 備份過期,\n\\n 如基本備份中包含已安裝的應用的舊版本\n\\n \\\\item \\\\textcolor{AMDarkCyan}{深藍綠色 \\\\textit{備份標識}} -- 備份在期,\n\\n 如基本備份中包含已安裝應用的相同或更高版本\n\\n \\\\item \\\\textcolor{AMDarkCyan}{深藍綠色 \\\\textit{包名}} -- 已強行停止運行的應用\n\\n \\\\item \\\\textcolor{AMDarkCyan}{深藍綠色 \\\\textit{版本}} -- 不活躍的應用\n\\n \\\\item \\\\textcolor{magenta}{紫紅} -- 常駐應用(一直運行的應用)\n\\n\\\\end{itemize}</string>\n    <string name=\"pages$app-details-page$colour-codes\">本頁中使用的顏色列表及它們的含義：\n\\n\\\\begin{itemize}\n\\n \\\\item \\\\colorbox{AMRed}{\\\\textcolor{black}{正紅 (日間)}} / \\\\colorbox{AMDarkRed}{\\\\textcolor{white}{深紅 (夜間)}}\n\\n -- 危險權限或, 被阻止的組件(使用App Manager操作)\n\\n\n\\n \\\\item \\\\colorbox{AMLightRed}{\\\\textcolor{black}{亮紅 (日間)}} / \\\\colorbox{AMVeryDarkRed}{\\\\textcolor{white}{緋紅 (夜間)}} -- 被阻止的組件(其他應用操作)\n\\n\n\\n \\\\begin{tip}{注意}\n\\n表示在 App Manager 之外禁用(阻止)的組件, 標記為禁用(阻止)的組件並不意味著它被用戶禁用,它也可能是被系統禁用的, 或者在其清單(Android-Manifest.xml)中被標記為禁用(阻止)。被停用的應用程序也會被系統（和App Manager）視為禁用(阻止)。\n\\n \\\\end{tip}\n\\n\n\\n \\\\item \\\\colorbox{AMVividOrange}{\\\\textcolor{black}{鮮橙 (日間)}} / \\\\colorbox{AMVeryDarkOrange}{\n\\n \\\\textcolor{white}{深橙 (夜間)}} -- 追蹤器組件\n\\n\n\\n \\\\item \\\\colorbox{AMSoftMagenta}{\\\\textcolor{black}{亮紫 (日間)}} / \\\\colorbox{AMVeryDarkViolet}{\n\\n \\\\textcolor{white}{深紫 (夜間)}} -- 正在運行的組件\n\\n\\\\end{itemize}</string>\n    <string name=\"intro$main$donation\">\\\\emph{捐贈或購買並不是使用App Manager的必要條件.} 雖然 App Manager 不支持任何任何內購,\n\\n但可以通過 Open Source Collective 向 App Manager 的所有者發送捐贈.\n\\n\n\\nOpen Source Collective 是 Open Collective 平台上的一個財政托管機構，以幫助開源項目管理他們的財務狀況。\n\\n目前，它支持通過銀行賬戶、PayPal、信用卡或借記卡和加密貨幣發起捐贈.\n\\n\n\\n\\\\textit{Link:} \\\\url{https://opencollective.com/muntashir}.\n\\n\n\\n通過發送捐款，發送者同意他們不應使用捐款作為籌碼來使作者優先考慮其所請求的功能.\n\\n請求新功能不需要任何捐贈，且它們的優先級是按作者傾向排序.\n\\n\n\\n\\\\emph{App Manager 接受任何資助的提議}\n\\n有興趣的組織的代表可以通過以下方式直接聯系聯系所有者: §\\\\ref{sec:contact}.</string>\n    <string name=\"pages$main-page$filter\">主頁面中列出的應用可以通過以下方式進行過濾:\n\\n\\\\begin{itemize}\n\\n \\\\item \\\\textbf{用戶} 僅用戶應用\n\\n \\\\item \\\\textbf{系統} 僅系統應用\n\\n \\\\item \\\\textbf{停用} 僅停用應用\n\\n \\\\item \\\\textbf{被阻止} 僅被阻止組件的應用\n\\n \\\\item \\\\textbf{可打開} 僅至少有一個Aactivity的應用\n\\n \\\\item \\\\textbf{有備份} 僅有備份的應用\n\\n \\\\item \\\\textbf{無備份} 僅沒有備份的應用\n\\n \\\\item \\\\textbf{運行中} 僅正在運行的應用\n\\n \\\\item \\\\textbf{有分包} 僅有分包(多Apk)應用\n\\n \\\\item \\\\textbf{已安裝} 僅已安裝應用\n\\n \\\\item \\\\textbf{已卸載} 僅已卸載應用\n\\n\\\\end{itemize}\n\\n\n\\n與排序不同，它可以同時應用多個過濾選項，\n\\n如，停用的用戶應用可以通過選擇 \\\\textit{用戶}和 \\\\textit{停用}列出，這對\\\\hyperref[subsec:batch-operations]{批處理}特別有用，在這種情況下過濾用戶應用可能是必要的，以便安全地進行某些操作。\n\\nUnlike sorting, it is possible to apply more than one filtering options at the same time. For example, the disabled user\n\\napplications can be listed by selecting both \\\\textit{User apps} and \\\\textit{Disabled apps}. This can be particularly\n\\nuseful for \\\\hyperref[subsec:batch-operations]{batch operations} where filtering the user applications may be necessary\n\\nto carry out certain operations safely.</string>\n    <string name=\"intro$main$translations\">App Manager 不接受直接通過PR/MR進行的翻譯。翻譯僅通過 Weblate 進行自動化管理。\n\\n要加入翻譯團隊，請訪問 \\\\url{https://hosted.weblate.org/engage/app-manager/}。</string>\n    <string name=\"intro$main$intro\">App Manager 是一個提供大量功能的高級的 Android 軟件包管理器，因此，需要用戶手冊來幫助用戶正確使用。本文作為 App Manager 的用戶手冊，旨在描述 App Manager 所提供的每一個功能。\n\\n本文也可以被認為是 App Manager 的 ``官方\\'\\' 指南，並指明 App Manager 的預期行為。翻譯可能有誤 (原文為英文)。因此，每個有能力的用戶應該閱讀該文件的英文版本，以獲得最佳的體驗。\n\\n此外還可能有其他非官方的或第三方的資源，如博客文章、視頻、聊天群組等。雖然這些資源可能對許多人有用，但它們可能不是針對最新版本。\n\\n如果在App Manager中發現任何偏離本文檔的情況，應在\n\\n\\\\href{https://github.com/MuntashirAkon/AppManager/issues}{App Manager 問題追蹤}內反映。</string>\n    <string name=\"intro$main$submit-patches\">除GitHub之外的倉庫目前被視為鏡像，在這些網站提交的 PR/MR 將不被接受.\n\\n\\\\footnote{GitHub 的 PR 將使用 git patch 進行手動合並, 因此, GitHub 可能會錯誤地將它們標記為closed而不是merged.}\n\\n相反，patches (\\\\texttt{.patch} 文件) 可以通過電子郵件附件提交。\\\\textit{請務必對Commits簽名(Signing-off)}\n\\n更多信息請參見位於源碼根目錄下的CONTRIBUTING文件.\n\\n\n\\n\\\\begin{warning}{注意}\n\\n在通過電子郵件提交補丁是，整個郵件對話在將來可能會被公開訪問.\n\\n所以，請不要除了您的姓名和電子郵件地址之外，不要包含任何個人身份信息（PII）.\n\\n\\\\end{warning}</string>\n    <string name=\"intro$main$contributing\">用戶可有通過多種方式做出貢獻，如創建有用 issues 、參加討論、\n\\n改進文檔和翻譯，添加未被認可的庫或跟蹤器，\n\\n審查源代碼以及報告安全漏洞。</string>\n    <string name=\"pages$main-page$batch-operations\">批處理也可以在這個頁面內進行。\n\\n多選模式可以由點擊任何應用圖標或長按列表中的任何一項進入。\n\\n進入後，僅需單擊列表中的任何一項便可選中，而不是打開應用程序詳情頁。\n\\n該模式下，批處理操作位於位於頁面底部的多選菜單，包括包括：\n\\n\\\\begin{itemize}\n\\n \\\\item 將選中應用添加到 \\\\hyperref[sec:profiles-page]{配置}\n\\n \\\\item \\\\hyperref[sec:backup-restore]{備份、恢覆或刪除}應用程序\n\\n \\\\item 阻止應用中的追蹤器\n\\n \\\\item 清除應用數據或緩存\n\\n \\\\item 啟用/停用/強制停止/卸載應用程序\n\\n \\\\item 導出屏蔽規則\n\\n \\\\item 阻止應用的後台操作 (Android 7 及更高版本)\n\\n \\\\item 導出APK文件到 \\\\texttt{AppManager/apks}\n\\n \\\\item 設置\\\\hyperref[sec:net-policy]{聯網規則}\n\\n\\\\end{itemize}\n\\n\n\\n\\\\begin{tip}{無障礙}\n\\n 進入多選模式後，鍵盤或遙控器的左右鍵呼出多選菜單。\n\\n\\\\end{tip}</string>\n    <string name=\"pages$main-page$options-menu\">選項菜單提供了幾個選項，可用以對列出的應用程序進行排序和過濾，\n\\n以及轉到 App Manager 內或外的不同頁面。</string>\n    <string name=\"pages$main-page$sort\">主頁面中列出的應用程序可以按照以下方式進行排序:\n\\n\\\\begin{itemize}\n\\n \\\\item \\\\textbf{用戶應用優先} 用戶應用將優先展示\n\\n \\\\item \\\\textbf{應用標簽} 根據應用標簽（也稱為 \\\\textit{應用程序名稱}）升序排序。(默認選項)\n\\n \\\\item \\\\textbf{包名} 根據包名升序排序\n\\n \\\\item \\\\textbf{最後更新} 根據更新時間降序排序\n\\n \\\\item \\\\textbf{共享 user ID} 根據共享 user ID升序排序\n\\n \\\\item \\\\textbf{目標 SDK} 根據目標SDK升序排序\n\\n \\\\item \\\\textbf{簽名} 根據簽名信息升序排序\n\\n \\\\item \\\\textbf{已停用優先} 已停用將優先展示\n\\n \\\\item \\\\textbf{已阻止優先} 根據已阻止的應用組件數目降序排序\n\\n \\\\item \\\\textbf{已備份優先} 已備份將優先展示\n\\n \\\\item \\\\textbf{追蹤器} 根據追蹤器數目降序排序S\n\\n \\\\item \\\\textbf{最後操作} 根據被App Manager操作的應用時間降序排序\n\\n\\\\end{itemize}\n\\n\n\\n此外，還有 \\\\textit{反轉} 選項，可以用來對列表進行反向排序。\n\\n無論怎樣排序偏好，應用程序都是先按字母順序排序，以防止產生任何隨機排序結果.</string>\n    <string name=\"pages$main-page$intro\">主頁面列出所有已安裝、已卸載和已備份的應用。\n\\n單獨點擊任何已安裝的應用項目可打開相應的 \\\\hyperref[sec:app-details-page]{應用詳情頁}。\n\\n對於未安裝的系統應用，它會顯示一個 對話框提示，可以用來重新安裝該應用。\n\\n使用列表選項中的 \\\\hyperlink{par:main-page-sort}{排序} ，可以選擇應用列表的排序方式，退出應用後仍會保留排序方式。\n\\n使用列表選項中的 \\\\hyperlink{par:main-page-filter}{過濾}，可以過濾列表選項。\n\\n篩選也可以通過搜索欄進行過濾，並支持正則表達式。</string>\n    <string name=\"titlepage$user_manual\">{\\\\huge\\\\bfseries 用戶手冊\\\\par}</string>\n    <string name=\"intro$main$$introduction-chapter-title\">簡介</string>\n    <string name=\"intro$main$$terminologies-title\">術語</string>\n    <string name=\"intro$main$$supported-versions-title\">受支持的版本</string>\n    <string name=\"intro$main$buiding\">在位於源碼根目錄下的BUILDING文件中可以獲得編譯指導。</string>\n    <string name=\"intro$main$contact\">Muntashir Al-Islam\\\\footnote{可稱``Muntashir Akon\\'\\'}\\\\\\\\\n\\n郵箱: \\\\href{mailto:muntashirakon@riseup.net}{muntashirakon [at] riseup [dot] net}\\\\\\\\\n\\nKey Fingerprint: \\\\texttt{7bad37c2981e41f8f6abea7f58f0b4f26c346fce}\\\\\\\\\n\\nGitHub: \\\\url{https://github.com/MuntashirAkon}\\\\\\\\\n\\nTwitter: \\\\url{https://twitter.com/Muntashir}</string>\n    <string name=\"pages$main-page$$sort-title\">排序</string>\n    <string name=\"pages$main-page$$list-options-title\">列表選項</string>\n    <string name=\"pages$main-page$application-types\">一個應用程序可以是 \\\\textbf{用戶} 或 \\\\textbf{系統} 應用，同時存在以下後綴:\n\\n\\\\begin{itemize}\n\\n \\\\item \\\\texttt{X} -- 支持多種架構\n\\n \\\\item \\\\texttt{0} -- 不含dex文件\n\\n \\\\item \\\\texttt{°} -- 已暫停應用\n\\n \\\\item \\\\texttt{\\\\#} -- 應用程序請求系統分配一個大堆，即\\\\ 大運行時內存\n\\n \\\\item \\\\texttt{\\?} -- 應用程序請求虛擬機處於安全模式。\n\\n\\\\end{itemize}</string>\n    <string name=\"pages$main-page$version-info\">版本名稱有以下前綴:\n\\n\\\\begin{itemize}\n\\n \\\\item \\\\texttt{\\\\_} -- 沒有硬件加速（減慢應用中的過渡動畫）\n\\n \\\\item \\\\texttt{\\\\textasciitilde} -- 僅測試模式\n\\n \\\\item \\\\texttt{debug} -- 可調試應用\n\\n\\\\end{itemize}</string>\n    <string name=\"pages$main-page$list-options\">\\\\textbf{列表選項} 包含了對主頁面中的列表進行排序和過濾的選項。</string>\n    <string name=\"pages$main-page$settings\">此菜單項將打開本應用的 \\\\hyperref[sec:settings-page]{設置}.</string>\n    <string name=\"pages$app-details-page$$horizontal-action-panel-title\">水平操作面板</string>\n    <string name=\"pages$app-details-page$$activities-title\">活動 (Activity)</string>\n    <string name=\"pages$app-details-page$$colour-codes-title\">顏色代碼含義</string>\n    <string name=\"pages$app-details-page$$app-info-options-menu-title\">選項菜單</string>\n    <string name=\"pages$app-details-page$$app-info-general-information-title\">基本信息</string>\n    <string name=\"pages$app-details-page$$component-tabs-title\">組件選項卡</string>\n    <string name=\"pages$app-details-page$$app-info-tab-title\">應用信息</string>\n    <string name=\"pages$app-details-page$$section-title\">應用程序詳情頁</string>\n    <string name=\"pages$one-click-ops-page$$section-title\">一鍵操作頁</string>\n    <string name=\"pages$main-page$$termux-title\">Termux 終端模擬器</string>\n    <string name=\"pages$app-details-page$$config-termux-title\">配置 Termux</string>\n    <string name=\"pages$settings-page$$compression-method-title\">壓縮方法</string>\n    <string name=\"pages$settings-page$$backup-options-title\">備份選項</string>\n    <string name=\"pages$settings-page$$backup-apps-with-keystore-title\">備份帶 Android 密鑰庫的應用程序</string>\n    <string name=\"pages$settings-page$$backup-volume-title\">備份位置</string>\n    <string name=\"pages$interceptor-page$$mime-type-title\">MIME 類型</string>\n    <string name=\"pages$settings-page$language\">配置應用內語言，\n\\nApp Manager 目前支持19種語言。</string>\n    <string name=\"pages$interceptor-page$$categories-title\">類別(Categories)</string>\n    <string name=\"faq$misc$$i-dont-use-root-adb-title\">我不使用root/ADB，是否完全安全？</string>\n    <string name=\"guide$aot$$adb-mode-am-title\">在App Manager上啟用ADB模式</string>\n    <string name=\"faq$app-components$$also-blocked-by-other-tools-title\">被 App Manager 禁用但同時也被其他工具禁用的組件會發生什麽？</string>\n    <string name=\"faq$app-components$$what-is-component-blocking-title\">什麽是即時組件禁用？</string>\n    <string name=\"faq$app-components$$tracker-classes-versus-tracker-components-title\">跟蹤器類與跟蹤器組件</string>\n    <string name=\"pages$app-details-page$uses-permissions\">\\\\textbf{系統預定義權限}(\\\\textit{Uses Permissions}) 是應用(申請)所使用的權限，其在應用程序清單中使用 \\\\texttt{uses-permission} 標簽聲明。\n\\n其 \\\"標志位 (\\\\textit{flags})\\\"、\\\"權限名 (\\\\textit{permission name})\\\"、\\\"權限描述 (\\\\textit{permission description})\\\"、\\\"包名 ( \\\\textit{package name})\\\"、\\\"群組 (\\\\textit{group})\\\" 取自相關\\\\hyperref[subsubsec:permissions]{權限}。\n\\n\n\\n\n\\n特權用戶可通過切換按鈕授予或撤銷 危險 (\\\\textit{dangerous}) 和 開發 (\\\\textit{development}) 權限，也可以使用菜單中的相應選項。\n\\n只能撤銷以上兩種權限，因為Android不允許修改 普通 (\\\\textit{normal}) 權限（其中大多數是）。但仍有可能撤銷它們通過編輯 \\\\texttt{runtime-permissions.xml} 本身，但是否可能仍不明確。\n\\n\n\\n\\\\begin{tip}{提示}\n\\n 由於系統默認會撤銷危險權限，因此撤銷所有危險權限與重置所有權限是一樣的。\n\\n\\\\end{tip}\n\\n\n\\n可以以升序方式按權限名稱對列表排序，也可以優先顯示拒絕的權限。</string>\n    <string name=\"pages$interceptor-page$$flags-title\">標志位(Flags)</string>\n    <string name=\"guide$aot$$aot-lineage-os-title\">Lineage OS</string>\n    <string name=\"pages$profiles-page$$options-menu-title\">選項菜單</string>\n    <string name=\"pages$profile-page$$state-title\">狀態</string>\n    <string name=\"pages$settings-page$$section-title\">設置頁面</string>\n    <string name=\"pages$settings-page$$language-title\">界面語言</string>\n    <string name=\"pages$scanner-page$$section-title\">掃描器頁面</string>\n    <string name=\"guide$aot$$setup-adb-linux-title\">Linux</string>\n    <string name=\"guide$backup-restore$$delete-title\">刪除備份</string>\n    <string name=\"guide$backup-restore$$restore-title\">恢覆</string>\n    <string name=\"faq$app-components$$limitations-title\">追蹤器或其他組件在App Manager中是如何被禁用的？其局限性是什麽？</string>\n    <string name=\"appendices$specifications$external\">外部格式用於在 App Manager 中導入或導出規則。\n\\n\\\\begin{Verbatim}\n\\n &lt;package_name&gt; &lt;component_name&gt; &lt;type&gt; &lt;mode&gt;|&lt;component_status&gt;|&lt;is_granted&gt;\n\\n\\\\end{Verbatim}\n\\n除了第一項是包的名稱外，該格式與上述格式基本相同。\n\\n\n\\n\\\\begin{danger}{注意}\n\\n 導出的規則與內部規則的格式不同，不應直接複製到\n\\n \\\\textbf{conf} 文件夾。\n\\n\\\\end{danger}</string>\n    <string name=\"pages$app-details-page$$shared-libs-tab-title\">共享庫選項卡</string>\n    <string name=\"pages$app-details-page$permission-tabs\">\\\\textbf{App Ops}, \\\\textbf{使用權限} and \\\\textbf{權限} 選項卡與權限相關。\n\\n安卓中，在不具有相同身份（稱為 \\\\textit{shared ID}）的應用或進程之間進行通信常常需要權限，其由權限控制器管理。\n\\n一些被視為\\\\textit{普通} 的權限，若它們出現在應用程序清單中，則會自動授予，但\\\\textit{危險}權限 和 \\\\textit{開發} 權限需要用戶確認。\n\\n選項卡中使用的顏色在 §\\\\ref{subsec:app-details-color-codes} 中有解釋。</string>\n    <string name=\"pages$profile-page$$users-title\">用戶</string>\n    <string name=\"pages$interceptor-page$$data-title\">數據(Data)</string>\n    <string name=\"faq$app-components$$other-tools-retained-in-am-title\">被其他工具禁用的應用程序組件是否保留在App Manager中？</string>\n    <string name=\"pages$app-details-page$horizontal-action-panel\">如上節所述,水平滾動操作面板由各種與應用相關的操作組成, 如 -\n\\n\\\\begin{itemize}\n\\n \\\\item \\\\textbf{啟動}: 啟動應用. 前提是要有一個可啟動\\\\hyperref[subsubsec:activities]{活動}.\n\\n\n\\n \\\\item \\\\textbf{禁用}: 停用應用. 若應用已被禁用或用戶沒有足夠的權限，則不會顯示該按鈕.\n\\n禁用應用後，將從應用程序列表中隱藏，應用的快捷方式也可能被刪除.\n\\n只能通過App Manager或任何其他支工具重新啟用該應用.\n\\nAndroid設置中沒有任何選項可以啟用禁用的用戶應用.\n\\n\n\\n \\\\item \\\\textbf{卸載}: 卸載應用\n\\n\n\\n \\\\item \\\\textbf{啟用}: 啟用應用. 若應用已啟用或用戶沒有足夠的權限，則不會顯示該按鈕.\n\\n\n\\n \\\\item \\\\textbf{強制停止}: 強制停止應用.\n\\n\n\\n \\\\item \\\\textbf{清除數據}: 清除應用數據. 清除包括存儲在應用內部和（僅Android 10 以上）外部目錄中的任何應用數據，包括帳戶（如果由應用設置）、緩存等.\n\\n例如，清除 App Manager 數據將會刪除所有保存的規則（但不會清除已阻止組件），因此你應該檢查備份你的規則文件。若用戶沒有足夠的權限，則不會顯示此按鈕.\n\\n\n\\n \\\\item \\\\textbf{清除緩存}: 清除應用緩存. 沒有任何原生方法可以清除特定應用程序的緩存，因此，需要root權限才能清除應用程序內部存儲中的緩存.\n\\n\n\\n \\\\item \\\\textbf{安裝}: 通過第三方應用安裝應用. 此按鈕僅在應用尚未安裝時顯示.\n\\n\n\\n \\\\item \\\\textbf{What\\'s New}: 若外部應用已安裝，則會顯示此按鈕. 單擊此按鈕將顯示一個對話框，將以版本控制方式，顯示打開的版本和安裝的版本之間的差異.\n\\n包括: \\\\textit{版本}, \\\\textit{追蹤器}, \\\\textit{權限}, \\\\textit{組件}, \\\\textit{簽名} (校驗值改變\n\\n), \\\\textit{特性}, \\\\textit{共享庫} 與 \\\\textit{SDK}.\n\\n\n\\n \\\\item \\\\textbf{更新}: 若應用的版本號高於已安裝的應用，則會顯示.\n\\n\n\\n \\\\item \\\\textbf{重裝}: 若應用與已安裝的應用具有相同的版本號，則會顯示.\n\\n\n\\n \\\\item \\\\textbf{降級}: 若應用的版本號低於已安裝的應用，則會顯示.\n\\n\n\\n \\\\item \\\\textbf{應用清單(Manifest)}: 單擊將在單獨的頁面中顯示應用清單文件.\n\\n可以使用對應切換按鈕（位於右上方）開啟自動換行，也可以使用保存按鈕保存到存儲器.\n\\n\n\\n \\\\item \\\\textbf{掃描器}: 掃描應用以列出潛在的跟蹤器和庫.\n\\n若可用，它還會使用VirusTotal掃描文件.\\\\\\\\\n\\n \\\\seealsoinline{\\\\hyperref[sec:scanner-page]{掃描器頁面}}\n\\n\n\\n \\\\item \\\\textbf{共享首選項}: 顯示應用程序使用的共享首選項(Shared-Preferences)列表.\n\\n 單擊列表中的首選項將打開\\\\hyperref[sec:shared-preferences-editor-page]{共享首選項編輯器}. 若用戶沒有足夠的權限，則不會顯示此按鈕.\n\\n\n\\n \\\\item \\\\textbf{數據庫}: 將顯示應用程序使用的數據庫列表. 若用戶沒有足夠的權限，則不會顯示此按鈕.\n\\n\n\\n \\\\item \\\\textbf{F-Droid}: 在你常用的\\\\textit{F-Droid} 客戶端中打開該應用.\n\\n\n\\n \\\\item \\\\textbf{Store}: 在 \\\\textit{Aurora Store}打開該應用. 僅在\\\\textit{Aurora Store}後顯示.\n\\n\\\\end{itemize}</string>\n    <string name=\"pages$app-details-page$app-info-options-menu\">選項菜單位於頁面的右上角, 下面給出了對現有選項的完整描述:\n\\n\\\\begin{itemize}\n\\n \\\\item \\\\textbf{分享}: 共享按鈕可用於共享 APK 或(如果應用程序有多個拆分) \\\\textit{APKS}.\n\\n\n\\n \\\\item \\\\textbf{刷新}: 刷新應用信息選項卡.\n\\n\n\\n \\\\item \\\\textbf{在設置中查看}: 在 Android 設置中打開應用.\n\\n\n\\n \\\\item \\\\textbf{備份/恢覆}: 打開備份/恢覆對話框.\n\\n\n\\n \\\\item \\\\textbf{導出屏蔽規則}: 導出應用配置規則.\n\\n\n\\n \\\\item \\\\textbf{在 Termux 中打開}: 在 Termux 中打開應用. 實際以 \\\\texttt{su - user\\\\_id} 命令運行且該 \\\\texttt{用戶ID} 為應用的(內核)用戶 ID (參見§\\\\ref{subsubsec:app-info-general-information}).\n\\n 此選項僅適用於 Root 用戶.\n\\n 請參閱 §\\\\ref{subsubsec:config-termux} 以了解如何配置 Termux 以運行來自第三方應用的命令.\n\\n\n\\n \\\\item \\\\textbf{在 Termux 中運行}: 在Termux中通過 \\\\texttt{run-as package\\\\_name} 打開應用.\n\\n 此選項僅對可調式應用有效並適用於 Root 與 Adb 用戶.\n\\n 請參閱 §\\\\ref{subsubsec:config-termux} 以了解如何配置 Termux 以運行來自第三方應用的命令.\n\\n\n\\n \\\\item \\\\textbf{MagiskHide}: 打開一個對話框，其中包含應用程序中可以從 MagiskHide 列表中添加或刪除的進程列表.\n\\n\n\\n \\\\item \\\\textbf{MagiskDenyList}: 打開一個對話框，其中包含應用程序中可以從 MagiskDenyList 添加或刪除的進程列表.\n\\n\n\\n \\\\item \\\\textbf{電池優化}: 啟用/禁用電池優化.\n\\n\n\\n \\\\item \\\\hyperref[sec:net-policy]{\\\\textbf{聯網策略}}: 配置應用的聯網策略（如後台數據使用） .\n\\n\n\\n \\\\item \\\\textbf{導出圖標}: 提取應用圖標並將其保存至共享存儲.\n\\n\n\\n \\\\item \\\\textbf{添加配置}: 應用程序添加到已配置的 \\\\hyperref[sec:profile-page]{配置文件}.\n\\n\\\\end{itemize}</string>\n    <string name=\"pages$app-details-page$config-termux\">默認情況下，Termux 不允許運行來自第三方應用的命令。要使用此選項，請使用 Termux v0.96 以上版本，並且必須在 \\\\texttt{\\\\textasciitilde/.termux/termux.properties} 中添加 \\\\texttt{allow-external-apps=true}。\n\\n\n\\n\\\\begin{tip}{Info}\n\\n 啟用此選項不會削弱Termux的安全性。第三方應用仍然需要取得用戶允許才能在Termux中運行任意命令。\n\\n\\\\end{tip}</string>\n    <string name=\"pages$app-details-page$component-tabs\">\\\\textbf{活動(Activities)}、\\\\textbf{服務(Services)}、\\\\textbf{廣播接收器(Receivers)}和 \\\\textbf{內容提供者(Providers)} 統稱為應用程序組件. 它們共享在許多相似特征，如，它們都有一個 \\\\textit{名稱}、一個 \\\\textit{標簽}、一個 \\\\textit{圖標} 並且通過 \\\\textit{意圖(Intent)} 執行.\n\\n應用程序組件是應用的本構造，必須在應用程序清單中聲明.\n\\n應用程序清單是存儲應用程序特定元數據的文件，Android 通過讀取元數據來處理應用。\n\\n\n\\n這些選項卡中使用的顏色在 §\\\\ref{subsec:app-details-colour-codes} 中進行了解釋。也可以在彈出菜單對列表進行排序.</string>\n    <string name=\"pages$app-details-page$activities\">\\\\textbf{Activity} 是可以由 Android 唯一標識的窗口或頁面(如\\\\textit{主頁} 和 \\\\textit{應用詳情頁} 是兩個活動).\n\\n每個活動可以有多個 UI 組件，稱為 \\\\textit{部件(widgets)} 或 \\\\textit{碎片(fragments)}，每個組件都可以嵌套或放置在彼此之上.\n\\n開發人員還可以選擇使用名為\\\\textit{意圖過濾器(intent filters)}選擇打開外部文件、鏈接等.\n\\n如當使用文件管理器打開文件時，文件管理器或操作系統通過 PackageManager 掃描意圖過濾器以查找能夠打開文件的活動，並用其打開文件.\n\\n\n\\n標記\\\\textit{exportable} 的活動通常可以由任何第三方應用程序打開.\n\\n有些活動需要權限，如果是這種情況，只有具有這些權限的應用程序才能打開.\n\\n在 \\\\textit{活動} 選項卡中，可以通過 \\\\textbf{啟動} 按鈕啟動， 若有必要可提供額外信息，如意圖(Intent)的 extras、data或Action.\n\\n長按 \\\\textbf{啟動} 按鈕會打開提供此類功能的 \\\\hyperref[sec:interceptor-page]{Activity Interceptor} 頁面.\n\\n\n\\n\\\\begin{tip}{Notice}\n\\n 如果您無法打開任何活動，則很可能它具有某些未滿足的依賴項目，例如\\\\您無法打開 \\\\textit{應用詳情頁} ，由於其至少需要提供一包名.\n\\n 由於無法機械式推斷這些依賴關系，因此默認情況下可能無法通過 App Manager 打開這些活動.\n\\n\\\\end{tip}\n\\n\n\\n也可以通過 \\\\textbf{創建快捷方式} 按鈕來創建活動的快捷方式\n\\n\n\\n\\\\begin{danger}{Caution}\n\\n 如果您卸載App Manager，應用管理器創建的所有快捷方式都將丟失.\n\\n\\\\end{danger}</string>\n    <string name=\"pages$app-details-page$app-ops\">\\\\textbf{App Ops} 代表\\\"應用操作 \\\\textbf{ (Application Operations)} \\\".\n\\n自 Android 4.3 開始，Android 使用 \\\\textit{App Ops} 控制大多系統權限，每個 App Op 都有一個與之關聯的唯一編號，該編號與其私有名稱將一同顯示在“App Ops”選項卡中，一些 App Ops 也有一個公共名稱。\n\\n大量的應用操作是也與權限相關，在此選項卡中，若 App Ops 相關的權限被視為危險則被標記為危險。其他信息如 標志位(\\\\textit{flags}), 權限名稱 (\\\\textit{permission name}), 權限描述(\\\\textit{permission description}),包名 (\\\\textit{package name}),群組 ( \\\\textit{group}) 也取自相關的 \\\\hyperref[subsubsec:permissions]{權限}。\n\\n\n\\n其他可能包括以下內容:\n\\n\\\\begin{itemize}\n\\n \\\\item \\\\textbf{模式(Mode)}: 描述了當前授權狀態，可以是\\\"允許 (\\\\textit{allow})\\\"、\\\"拒絕(\\\\textit{deny})\\\"（實際為錯誤）、\\\"忽略(\\\\textit{ignore})\\\"（實際為拒絕）、\\\"默認(\\\\textit{default})\\\"（從手機供應商或 AOSP 內部設置的默認列表推斷）、\\\"前台(\\\\textit{foreground})\\\" （在新的Android版本中，應用只能在前台運行時獲取該權限），以及一些供應商自定義的模式，如MIUI使用詢問(\\\\textit{ask})。\n\\n\n\\n \\\\item \\\\textbf{時長(Duration)}: 此 App Ops 現已使用的時間（可能為負原因未知）。\n\\n\n\\n \\\\item \\\\textbf{允許時刻(Accept Time)}: 上一次 App Op 被許可。\n\\n\n\\n \\\\item \\\\textbf{拒絕時刻(Reject Time)}: 上一次 App Op 被拒絕。\n\\n\\\\end{itemize}\n\\n\n\\n\n\\n\\\\begin{tip}{提示}\n\\n若 \\\\texttt{android.permission.GET\\\\_APP\\\\_OPS\\\\_STATS} 由 ADB 授予，則此選項卡的內容對非 root 用戶可見\\\\@.\n\\n\\\\end{tip}\n\\n\n\\n每個 App Op 項都有切換按鈕，可用於允許或拒絕（忽略）它，其他受支持的模式也可以通過長按來設置。\n\\n如果選項卡中未列出所需的 App Op，可使用菜單中的\\\\textbf{設置自定義 App Op }。\n\\n菜單中的\\\\textbf{重置為默認} 可重置App Ops， 或使用拒絕危險權限的相關操作。\n\\n受 App Ops 本身工作方式所限，系統可能需要不少時間來更改它們。\n\\n\n\\n\\\\begin{tip}{Tip}\n\\n拒絕某些 App Ops 可能會導致應用行為異常，若所有修覆手段都失敗，可嘗試使用 \\\\textit{重置為默認} 選項。\n\\n\\\\end{tip}\n\\n\n\\n可以以升序方式按 App Ops 名稱和其編號對列表排序，也可以優先顯示拒絕的 App Ops。\n\\n\n\\n\\\\seealsoinline{\\\\hyperref[ch:app-ops]{附錄: App Ops}}</string>\n    <string name=\"pages$app-details-page$permissions\">(自定義)\\\\textbf{權限} 通常是應用自身定義的自定義權限，包括該應用聲明的、標記為\\\"內部( \\\\textit{Internal})\\\" 權限，其他應用聲明、標記為\\\"外部( \\\\textit{External})\\\"的權限。外部權限在應用程序組件中指定為依賴項，即應用只有在擁有指定的權限時才能調用該組件：\n\\n\\\\begin{itemize}\n\\n \\\\item \\\\textbf{名稱} 每個權限都有的唯一的名稱，如 \\\\texttt{android.permission.INTERNET} ，但多個應用可以請求同一個權限。\n\\n\n\\n \\\\item \\\\textbf{圖標} 每個權限都可以有一個自定義圖標，其他權限選項卡沒有任何圖標，因為它們在應用程序清單中不包含任何圖標。\n\\n\n\\n \\\\item \\\\textbf{描述} 描述權限的可選字段，若沒有與權限關聯的任何描述，則不會顯示該字段。\n\\n\n\\n \\\\item \\\\textbf{標志位(Flags)} 使用標志符號或 \\\\textbf{保護名稱(Protection Level)} 名稱描述權限， 諸如 普通 \\\\textit{normal}、開發 \\\\textit{development}、危險 \\\\textit{dangerous},、即時 \\\\textit{instant}, 已授權 \\\\textit{granted}、已撤銷 \\\\textit{revoked}、簽名 \\\\textit{signature}、特權 \\\\textit{privileged} 等。\n\\n\n\\n \\\\item \\\\textbf{包名} 表示與權限關聯的包名，即定義權限的包名。\n\\n\n\\n \\\\item \\\\textbf{群組(Group)} 與權限關聯的群組（如果有），幾個相關的權限通常可以組合在一起。\n\\n\\\\end{itemize}</string>\n    <string name=\"pages$profile-page$$export-blocking-rules-title\">導出屏蔽規則</string>\n    <string name=\"pages$settings-page$$app-theme-title\">應用主題</string>\n    <string name=\"pages$settings-page$$screen-lock-title\">屏幕鎖定</string>\n    <string name=\"pages$settings-page$$encryption-title\">加密</string>\n    <string name=\"pages$settings-page$$rules-title\">規則</string>\n    <string name=\"pages$settings-page$$instant-component-blocking-title\">即時組件攔截</string>\n    <string name=\"pages$settings-page$$import-export-blocking-rules-title\">導入/導出阻止規則</string>\n    <string name=\"pages$settings-page$$device-info-title\">關於設備</string>\n    <string name=\"pages$settings-page$app-theme\">配置應用程式內主題。</string>\n    <string name=\"pages$settings-page$enable-disable-features\">啟用或禁用應用 App Manager 中的某些功能，如\n\\n\\\\begin{itemize}\n\\n \\\\item 攔截器(Interceptor)\n\\n \\\\item 應用清單文件瀏覽器(Manifest viewer)\n\\n \\\\item 掃描器(Scanner)\n\\n \\\\item 包安裝器(Package installer)\n\\n \\\\item 使用情況(Usage access): 關閉此選項後，App Manager 將永遠不會請求 \\\\textit{Usage Access} 權限.\n\\n \\\\item 日志瀏覽器(Log viewer)\n\\n\\\\end{itemize}</string>\n    <string name=\"pages$settings-page$backup-restore\">與 \\\\hyperref[sec:backup-restore]{備份恢覆} 相關的設置.</string>\n    <string name=\"pages$scanner-page$$missing-signatures-title\">缺少簽名</string>\n    <string name=\"pages$interceptor-page$$send-edited-intent-title\">發送編輯過的意圖(Intent)</string>\n    <string name=\"pages$shared-prefs-editor-page$$section_title\">共享首選項(Shared Preferences)編輯頁</string>\n    <string name=\"guide$aot$$section-title\">經由 TCP 的 ADB</string>\n    <string name=\"guide$aot$$enable-dev-options-title\">啟用開發者選項</string>\n    <string name=\"guide$aot$$location-dev-options-title\">開發人員選項的位置</string>\n    <string name=\"guide$aot$$how-to-enable-dev-options-title\">如何啟用開發者選項</string>\n    <string name=\"guide$aot$$configure-aot-title\">配置經由TCP的ADB</string>\n    <string name=\"guide$aot$$enable-aot-via-pc-title\">在 PC 或 Mac 上啟用 經由TCP的ADB</string>\n    <string name=\"pages$settings-page$sign-apk\">安裝應用前是否對 APK 文件進行簽名.\n\\n轉至 \\\\hyperref[subsec:apk-signing]{APK 簽名} 部分來配置簽名.</string>\n    <string name=\"faq$misc$$section-title\">雜項</string>\n    <string name=\"faq$misc$$how-tracker-updated-title\">跟蹤器和庫是如何更新的？</string>\n    <string name=\"faq$misc$$shizuku-title\">對於 Shizuku 有何計劃？</string>\n    <string name=\"faq$misc$$bloatware-title\">什麽是預裝(bloatware)軟件以及如何刪除？</string>\n    <string name=\"appendices$specifications$$chapter-title\">語法</string>\n    <string name=\"appendices$specifications$$rules-specification-title\">規則語法</string>\n    <string name=\"pages$main-page$running-apps\">此菜單項打開一個新頁面，其中顯示正在運行的應用程序或進程的列表。它還顯示\n\\n當前內存和緩存（如果可用）使用情況。如果 App Manager 無法使用 root 或 ADB，它只會顯示自己\n\\n在最新版本的 Android 中。正在運行的應用程序或進程也可以在\n\\n結果頁面。每個進程 ID (PID) 的日誌也可以在 \\\\hyperref[subsubsec:log-viewer]{log viewer} 中查看。\n\\n此外，還可以通過單擊圖標或長按\n\\n物品。正常單擊任何項目會打開一個對話框，其中顯示更詳細的信息。</string>\n    <string name=\"pages$app-details-page$servcies\">與用戶可以看到的 \\\\hyperref[subsubsec:activities]{activities} 不同，\\\\textbf{Services} 處理後台任務。例如，\n\\n如果您使用手機的 Internet 瀏覽器從 Internet 下載視頻，則 Internet 瀏覽器正在使用\n\\n\\\\textit{前台服務} 下載內容。\n\\n\n\\n當一個活動被關閉或從 \\\\textit{Recents} 部分中刪除時，它可能會立即被銷毀，具體取決於\n\\n許多因素，例如手機有多少可用內存。但如果需要，服務可以無限期地運行。如果更多\n\\n服務在後台運行，由於內存和/或處理能力不足，手機可能會變慢，以及\n\\n手機的電池會更快耗盡。較新的 Android 版本啟用了電池優化功能\n\\n默認情況下適用於所有應用程序。啟用此功能後，系統可以隨機終止任何服務。然而，\n\\n前台服務（即使用固定通知運行的服務，例如音樂播放器）通常不是\n\\n除非系統資源不足（內存、電池等），否則終止。供應商特定的庫存 ROM 可以提供更多\n\\n積極的優化。例如，MIUI 有一個非常激進的優化功能，稱為 \\\\textit{MIUI 優化}。\n\\n\n\\n活動和服務都在同一個 \\\\href{https://stackoverflow.com/questions/7597742}{looper} 中運行\n\\n主循環器，這意味著服務並沒有真正在後台運行。開發人員的任務是\n\\n確保這一點。應用程序如何與服務通信？它用\n\\n\\\\hyperref[subsubsec:app-details-receivers]{broadcast receiver} 或 Binder。</string>\n    <string name=\"pages$main-page$app-usage\">應用程序使用統計，例如 \\\\textit{屏幕時間}、\\\\textit{數據使用量}（移動和 Wi-Fi）、\\\\textit{\n\\n單擊菜單中的 \\\\textbf{App Usage} 選項可以訪問打開應用程序的次數}。但是，它需要\n\\n\\\\textit{使用權限} 權限。如果使用訪問功能被禁用，則不會列出此菜單項\n\\n\\\\hyperref[subsec:enable/disable-features]{設置}。</string>\n    <string name=\"pages$main-page$profiles\">此菜單項打開 \\\\hyperref[sec:profiles-page]{profiles page}。配置文件是一種配置經常使用的方法\n\\n任務。它們也可以通過快捷方式調用。</string>\n    <string name=\"pages$main-page$termux\">如果系統中已安裝\\\\href{https://github.com/termux/termux-app}{Termux} ，則可直接從此菜單項運行會話（或\n\\n新會話）.\n\\n如果應用不存在，則此選項將被隱藏.</string>\n    <string name=\"pages$main-page$apk-updater\">若系統中已安裝\\\\href{https://github.com/rumboalla/apkupdater}{APK Updater} ，則可通過此菜單項直接打開.\n\\n若系統中不存在該應用，則該選項將被隱藏.</string>\n    <string name=\"pages$app-details-page$app-info-general-information\">以下的列表與“應用信息”選項卡中列出的順序相同.\n\\n\\\\begin{itemize}\n\\n \\\\item \\\\textbf{應用圖標}: 應用圖標，若應用沒有圖標，則顯示系統默認圖標.\n\\n可以點擊圖標，進行與剪貼板中的 SHA 或 MD5 進行 APK 簽名驗證.\n\\n \\\\item \\\\textbf{應用標簽}: 應用程序名.\n\\n \\\\item \\\\textbf{包名}: 應用程序包名，點擊覆制.\n\\n \\\\item \\\\textbf{版本}: 版本分為兩部分:\n\\n第一部分稱 \\\\textit{版本名(Version Name)}. 格式各不相同，但常由多個以點分隔的整數組成.\n\\n第二部分稱 \\\\textit{版本號}. 其被第一個括號括起來. 版本代碼是一個整數，用於 區分應用程序版本 (因為機器無法讀取版本名). 簡言之, 新版本的應用程序具有比舊版本更高的版本代碼. 如，如果 \\\\texttt{123} 和 \\\\texttt{125} 是一個應用程序的兩個版本代碼，我們可以說後者比前者更新(後者的版本代碼更高).\n\\n在不同平台（移動、平板、桌面等）或架構（32/64 位、ARM 或 Intel）上為同一版本提供不同 APK 文件的應用程序，版本號可能會產生誤導，因為它們通常會為每個平台添加前綴 .\n\\n\n\\n \\\\item \\\\textbf{標簽}: (也稱標簽雲) 標簽包括應用程序最基本、最簡潔、有用的信息，如--- \\\\begin{itemize}\n\\n \\\\item \\\\textit{追蹤器信息} 應用程序中跟蹤器組件的數量 (如, \\\\textit{5 個追蹤器}).\n\\n如果跟蹤器未被阻止，則標記顏色顯示為橙色，如果跟蹤器在App Manager中被阻止，則標記顏色顯示為深青色.\n\\n單擊標簽會打開一個對話框，其包含跟蹤器組件列表，如果 App Manager 具有足夠的權限，可以阻止或取消阻止這些組件.\n\\n \\\\item \\\\textit{應用類型} 用戶應用或系統應用。系統應用程序的更新版本和通過 Magisk 無系統安裝的應用也被認為是系統應用.\n\\n \\\\item \\\\textit{Split APK 信息} APK 中的拆分包數量，不包括基本 APK (e.g., \\\\textit{5 分包}). 單擊標簽會打開一個對話框，其中包含分包 APK 信息，例如類型和大小.\n\\n \\\\item \\\\textit{可調試} 應用可以通過 ADB調試.可調試應用可以享受常規應用無法使用的某些功能. 應用的數據可以通過 ADB 訪問 (如使用\\\\texttt{run-as} 命令無需任何額外權限).\n\\n \\\\item \\\\textit{僅測試} 應用是僅測試應用程序. 僅測試應用可以享受常規應用無法使用的某些功能. 應用的數據可以通過 ADB 訪問 (如使用\\\\texttt{run-as} 命令無需任何額外權限).\n\\n \\\\item \\\\textit{大(堆/Heap)內存} 應用將請求較大的堆內存, 即需要更多內存 (RAM) 空間用於動態分配.\n\\n 是否為應用程序分配大空間仍由操作系統決定. 如，App Manager 請求較大的堆大小，因為它在 Android 8 之前需要在掃描的 APK 時將整個 APK 加載到內存中App.\n\\n \\\\item \\\\textit{無代碼} 該應用無任何相關代碼,如不含Dex文件.\n\\n在某些系統應用中，實際代碼可能位於其他位置.\n\\n \\\\item \\\\textit{運行中} 應用的一項或多項服務正在後台運行.\n\\n單擊標簽將打開一個對話框，其中包含正在運行的服務列表.\n\\n如果啟用了日志查看器功能，單擊任何服務會將在日志查看器中它.\n\\n \\\\item \\\\textit{已停止} 應用被強制停止. 這可能不會阻止它以後自動啟動.\n\\n \\\\item \\\\textit{已禁用} 應用被禁用 (在啟動器無圖標).\n\\n \\\\item \\\\textit{已掛起} 表示應用程序已掛起 (在啟動器中顯示為灰色).\n\\n \\\\item \\\\textit{被隱藏} 示應用程序是隱藏的 (在啟動器無圖標).\n\\n \\\\item \\\\textit{MagiskHide} MagiskHide 已啟用. 單擊該標簽會打開一個對話框，其中包含應用程序中可以從 MagiskHide 添加或刪除的進程列表.\n\\n \\\\item \\\\textit{MagiskDenyList} 該應用程序存在於 MagiskDenyList 中. 單擊標簽會打開一個對話框，其中包含應用程序中可以從 MagiskDenyList 列表中添加或刪除的進程列表.\n\\n \\\\item \\\\textit{密匙庫} 應用在 Android KeyStore 中存有項目. 單擊將打開一個對話框，其中包含屬於該應用程序的所有 KeyStore 文件.\n\\n \\\\item \\\\textit{備份} 應用至少使用 App Manager 備份過一次. 單擊標簽會打開一個對話框，其包含所有可用的備份以及元數據.\n\\n \\\\item \\\\textit{不進行電池優化} 電池優化對應用不生效. 可以通過單擊標簽重新啟用電池優化.\n\\n \\\\item \\\\hyperref[sec:net-policy]{\\\\textit{聯網策略}} 為應用配置聯網策略（如，後台數據使用）. 單擊標簽會顯示一個對話框，其中包含系統支持的策略.\n\\n \\\\item \\\\hyperref[sec:terminologies]{\\\\textit{SSAID}} 點擊打開一個對話框，其中包含分配給應用程序的當前 SSAID。若需要可以重置/重新生成 SSAID.\n\\n \\\\item \\\\textit{SAF} 表示應用已被授權訪問一個或多個存儲位置或文件，即獲得由存儲訪問框架 (SAF) 的 URI.\n\\n單擊打開一個對話框，其中包含授予的 URI.\n\\n \\\\item \\\\textit{被 Google Play 簽名} 表示應用程序可能由 Google 簽名.\n\\n \\\\end{itemize}\n\\n\n\\n \\\\item \\\\textbf{水平滾動操作面板} 一個操作面板，由可以對應用執行的各種操作組成, 有關可用操作的完整列表，請參閱§\\\\ref{subsubsec:horizontal-action-panel}.\n\\n\n\\n \\\\item \\\\textbf{路徑與目錄}: 應用有關路徑的各種信息，包括 \\\\textit{應用目錄} (where the APK files reside), \\\\textit{數據目錄} (internal, device protected and externals), \\\\textit{應用分包目錄} (along with the split names), and \\\\textit{本機原生 JNI 庫} (如果有). JNI 庫用於調用通常用 C/C++ 編寫的本機原生代碼, 使用本機原生庫可以使應用程序運行得更快或幫助應用程序使用使用非 Java 語言編寫的第三方庫，同大多數遊戲中一樣.\n\\n通過單擊每個目錄項右側的啟動圖標, 可以通過第三方文件管理器打開目錄，前提是它們支持並獲得必要的權限.\n\\n\n\\n \\\\item \\\\textbf{數據使用}: 操作系統報告的應用程序使用的數據量.\n\\n 根據 Android 版本，這可能需要廣泛的權限，包括 \\\\textit{訪問應用使用情況} 和 \\\\textit{電話} 權限.\n\\n\n\\n \\\\item \\\\textbf{存儲與緩存}: 顯示有關應用程序大小（APK 文件、優化文件）、數據和緩存的信息。 在舊設備中，還會顯示外部數據、緩存、媒體和 OBB 文件夾的大小. 如果在較新的設備中未授予 \\\\textit{訪問應用使用情況s} 權限，此部分將隱藏.\n\\n\n\\n \\\\item \\\\textbf{更多信息} 例如--\n\\n \\\\begin{itemize}\n\\n \\\\item \\\\textbf{SDK} 顯示與 Android SDK 相關的信息. 存在兩個（舊設備只有一個）值:\n\\n \\\\textit{最高} 目標 SDK 與\\\\textit{最低} 最低SDK (後者不適用於舊設備).\n\\n最佳實踐是使用平台當前支持的最大 SDK 的應用程序，以確保應用程序未在兼容模式下運行(以便使用隱私規避功能).\n\\n SDK 已稱為 \\\\textbf{等級(API Level)}.\n\\n \\\\seealsoinline{\\\\href{https://en.wikipedia.org/wiki/Android_version_history\\\\#Overview}{Android Version History}}\n\\n\n\\n \\\\item \\\\textbf{標志位(Flags)}: 構建應用程序時使用的應用標志, 有關標志的完整列表及其作用, 請見\\\\href{https://developer.android.com/reference/android/content/pm/ApplicationInfo\\\\#flags}{official documentation}.\n\\n\n\\n \\\\item \\\\textbf{安裝日期}: 首次安裝應用的日期.\n\\n\n\\n \\\\item \\\\textbf{更新日期}: 上次更新應用程序的日期. 如果應用程序尚未更新，這與 \\\\textit{安裝日期} 相同.\n\\n\n\\n \\\\item \\\\textbf{安裝器}: 安裝此應用的應用.\n\\n並非所有應用程序都提供包管理器用來注冊安裝程序應用程序的信息. 因此，這個值不應被視為理所當然。\n\\n\n\\n \\\\item \\\\textbf{User ID}: Android系統給應用設置的唯一用戶ID.\n\\n 對於共享應用，相同的用戶 ID 被分配給具有相同 \\\\textit{Shared User ID} 的多個應用程序.\n\\n\n\\n \\\\item \\\\textbf{Shared User ID}: 適用於一起共享ID的應用. 共享應用必須具有相同的 \\\\hyperref[subsec:signatures-tab]{簽名}.\n\\n\n\\n \\\\item \\\\textbf{首選ABI}: 此平台為此應用程序支持的架構。\n\\n\n\\n \\\\item \\\\textbf{Zygote preload name}: 負責預加載應用程序代碼和在所有使用應用程序 zygote 的隔離服務之間共享的數據.\n\\n\n\\n \\\\item \\\\textbf{隱藏 API 使用策略}: 從 Android 9 開始，Android Framework 中的許多方法和類第三方應用程序無法通過隱藏 API 強制訪問.\n\\n存在以下選項:\n\\n \\\\begin{itemize}\n\\n \\\\item \\\\textit{默認(Default}: 基於應用的類型。 對於系統應用程序，它應該被禁用，而對於其他應用，它應該被強制執行.\n\\n \\\\item \\\\textit{無或關閉(None/disabled)}: 該應用可以完全訪問隱藏的 API，就像在 Android 9 之前一樣.\n\\n \\\\item \\\\textit{警告(Warn)}: 與上面相同，除了每次應用程序訪問隱藏 API 時都會記錄警告. 這一般未使用的.\n\\n \\\\item \\\\textit{強制(Enforce)}: 應用無法訪問隱藏的 API，無論是深灰名單還是黑名單，或者兩者都無法訪問.\n\\n這是 Android 9 及更高版本中第三方應用程序的默認選項，除非該應用程序被 OEM 或供應商列入白名單.\n\\n \\\\begin{warning}{Warning}\n\\n 隱藏 API 訪問限制策略在 Android 中沒有正確實現，應用程序可以繞過它.\n\\n 因此，不應信任此值.\n\\n \\\\end{warning}\n\\n \\\\end{itemize}\n\\n\n\\n \\\\item \\\\textbf{SELinux}: 操作系統通過 SELinux 設置的強制訪問控制 (MAC) 策略.\n\\n\n\\n \\\\item \\\\textbf{主活動}: 應用的主要入口點.\n\\n這僅在應用程序具有 \\\\hyperref[subsubsec:activities]{活動} 並且其中任何一個都可以從啟動器中打開時顯示. 右側還有一個啟動按鈕，可用於啟動此活動.\n\\n \\\\end{itemize}\n\\n\\\\end{itemize}</string>\n    <string name=\"pages$profile-page$$section-title\">配置頁</string>\n    <string name=\"pages$profile-page$$options-menu-title\">選項菜單</string>\n    <string name=\"pages$profile-page$$apps-tab-title\">應用程序選項卡</string>\n    <string name=\"pages$profile-page$$configurations-tab-title\">配置選項卡</string>\n    <string name=\"pages$profile-page$$comment-title\">備注</string>\n    <string name=\"pages$profile-page$$components-title\">組件</string>\n    <string name=\"pages$profile-page$$app-ops-title\">AppOps 權限</string>\n    <string name=\"pages$profile-page$$permissions-title\">權限</string>\n    <string name=\"pages$profile-page$$backup-restore-title\">備份/恢覆</string>\n    <string name=\"pages$profile-page$$force-stop-title\">強制停止</string>\n    <string name=\"pages$profile-page$$clear-cache-title\">清除緩存</string>\n    <string name=\"pages$profile-page$$clear-data-title\">清除數據</string>\n    <string name=\"pages$profile-page$$save-apk-title\">保存APK</string>\n    <string name=\"pages$settings-page$$mode-of-operation-title\">操作模式</string>\n    <string name=\"pages$settings-page$$enable-disable-features-title\">啟用/禁用功能</string>\n    <string name=\"pages$settings-page$$apk-signing-title\">APK 簽名</string>\n    <string name=\"pages$settings-page$$signature-schemes-title\">簽名方案</string>\n    <string name=\"pages$settings-page$$signing-key-title\">簽名密鑰</string>\n    <string name=\"pages$settings-page$$installer-title\">安裝器</string>\n    <string name=\"pages$settings-page$$sign-apk-title\">簽名 APK</string>\n    <string name=\"pages$settings-page$$install-location-title\">安裝位置</string>\n    <string name=\"pages$settings-page$$remove-all-rules-title\">刪除所有規則</string>\n    <string name=\"pages$settings-page$$import-export-keystore-title\">導入/導出密鑰庫</string>\n    <string name=\"pages$interceptor-page$$extras-title\">附加數據(Extras)</string>\n    <string name=\"pages$interceptor-page$$uri-title\">URI</string>\n    <string name=\"pages$interceptor-page$$matching-activities-title\">匹配的活動(Activity)</string>\n    <string name=\"pages$interceptor-page$$reset-to-default-title\">重置為默認</string>\n    <string name=\"guide$aot$$enable-usb-debugging-title\">啟用USB調試</string>\n    <string name=\"guide$aot$$setup-adb-win-title\">Windows</string>\n    <string name=\"guide$aot$$miui-usb-debug-title\">小米 (MIUI)</string>\n    <string name=\"guide$aot$$emui-usb-debug-title\">華為 (EMUI)</string>\n    <string name=\"guide$aot$$lg-usb-debug-title\">LG</string>\n    <string name=\"guide$aot$$troubleshooting-usb-debug-title\">故障排除</string>\n    <string name=\"guide$aot$$setup-adb-on-pc-title\">在PC或Mac上配置ADB</string>\n    <string name=\"guide$backup-restore$$location-title\">位置</string>\n    <string name=\"guide$backup-restore$$options-title\">備份選項</string>\n    <string name=\"guide$backup-restore$$backup-title\">備份</string>\n    <string name=\"guide$backup-restore$$section-title\">備份/恢覆</string>\n    <string name=\"faq$aot$$usb-debugging-title\">無法啟用 USB 調試，怎麽辦？</string>\n    <string name=\"faq$aot$$feature-adb-title\">哪些功能可以在ADB模式下使用？</string>\n    <string name=\"faq$aot$$block-tracker-title\">我可以使用 ADB over TCP 來禁用跟蹤器或任何其他應用程序組件嗎？</string>\n    <string name=\"appendices$specifications$$background-title\">背景介紹</string>\n    <string name=\"appendices$specifications$$rules-file-format-title\">規則文件格式</string>\n    <string name=\"appendices$specifications$$internal-title\">內部</string>\n    <string name=\"appendices$specifications$$external-title\">外部</string>\n    <string name=\"appendices$changelogs$$chapter-title\">更新日志</string>\n    <string name=\"titlepage$quotation\">\\\\begin{quote}\n\\n 明智而緩慢。他們跌跌撞撞地跑得很快。\n\\n %\\\\sourceatright\n\\n {---勞倫斯修士，\\\\textit{羅密歐與朱麗葉}}\n\\n \\\\end{quote}</string>\n    <string name=\"pages$main-page$profile_name\">也可以列出僅存在於 \\\\hyperref[sec:profiles-page]{profile} 中的應用程序。這個可以\n\\n對於在配置文件上執行某些操作（例如，卸載配置文件中的所有應用程序）很有用\n\\n不能通過 \\\\hyperref[sec:profiles-page]{Profiles page} 完成。</string>\n    <string name=\"pages$main-page$1-click-ops\">\\\\textbf{1-Click Ops} 代表單擊操作。它打開 \\\\hyperref[sec:1-click-ops-page]{corresponding\n\\npage} 在新活動中。</string>\n    <string name=\"pages$one-click-ops-page$$1-click-back-up-title\">備份</string>\n    <string name=\"pages$one-click-ops-page$$1-click-restore-title\">恢覆</string>\n    <string name=\"pages$profiles-page$$section-title\">配置文件頁面</string>\n    <string name=\"pages$settings-page$$installer-app-title\">安裝來源</string>\n    <string name=\"pages$settings-page$$backup-restore-title\">備份/恢覆</string>\n    <string name=\"pages$settings-page$install-location\">選擇APK安裝位置，可以為 \\\\textit{自動}、\\\\textit{僅內部} 和\\\\textit{傾向外部}.\n\\n在較新的Android版本中，最後一個選項可能並不總是能如期在外部存儲中安裝應用.</string>\n    <string name=\"pages$settings-page$installer-app\">選擇安裝程序，對一些明確檢查其安裝程序的應用很有用 (只適用於 root/ADB 用戶).</string>\n    <string name=\"pages$interceptor-page$$section-title\">攔截器頁面</string>\n    <string name=\"pages$interceptor-page$$intent-filters-title\">意圖(Intent)過濾器</string>\n    <string name=\"pages$interceptor-page$$action-title\">動作(Action)</string>\n    <string name=\"guide$main$$guides-chapter-title\">指南</string>\n    <string name=\"guide$aot$$setup-adb-mac-title\">macOS</string>\n    <string name=\"guide$net-policy$$section-title\">連網策略</string>\n    <string name=\"faq$main$$faq-chapter-title\">常見問題</string>\n    <string name=\"faq$app-components$$section-title\">應用組件</string>\n    <string name=\"faq$app-components$$what-are-app-components-title\">什麽是應用組件？</string>\n    <string name=\"faq$aot$$section-title\">ADB over TCP (經由TCP的ADB)</string>\n    <string name=\"faq$aot$$restart-title\">我必須在每次重啟後啟用ADB over TCP嗎？</string>\n</resources>"
  },
  {
    "path": "docs/src/main/AndroidManifest.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<manifest xmlns:dist=\"http://schemas.android.com/apk/distribution\">\n\n    <dist:module\n        dist:instant=\"false\"\n        dist:title=\"Docs\">\n        <dist:delivery>\n            <dist:install-time />\n        </dist:delivery>\n        <dist:fusing dist:include=\"true\" />\n    </dist:module>\n</manifest>"
  },
  {
    "path": "fastlane/metadata/android/en-US/changelogs/437.txt",
    "content": "Private messages should be emailed to am4android@riseup.net. Emails sent to any other email addresses shall be discarded.\n- Added full support for Android 14-r29 and later\n- [App Info] New tag: Sensors disabled\n- [App Info] Added option to enable/disable sensors\n- [App Info] Display detailed installer info\n- Display blocking method in the components tabs\n- Fixed applying IFW method in the components tabs\n- Improved the usage time calculation method\n- Improved handling custom users in backups\n- Fixed creating custom backups\n- [Batch Ops] Added option to export app list as CSV and JSON\n- Added support for pure black theme\n- Added a fallback server runner command from DE storage\n- [UI Tracker] Display current activity name when possible\n- Updated documentation to reflect latest changes, so on."
  },
  {
    "path": "fastlane/metadata/android/en-US/changelogs/440.txt",
    "content": "App Manager v4.0.0 comes with a lot of new features and improvements. Visit in-app changelog for details.\n- New logo!\n- Android 14 and 15 support\n- Revamped debloater\n- Introducing file manager\n- Integrated code editor\n- History of operations\n- Per-app freezing, and more\n- Log viewer enhancements\n- Launching non-exported activities\n- New tags in App Info tab\n- Per-session installer options\n- Advanced mode of operations, ADB enhancements, etc.\n- Data usage widget, and more\n- Replaced log viewer, sys config, Terminal, etc. with Labs page\n- Added an option to disable sensors for each app in the App Info tab\n- Added an option to perform runtime optimization of applications in the 1-click Ops page and in the App Info tab\n- Added support for Zstandard compression for backup/restore\n- Enabling APK signing now automatically enables zip align feature\n- Support exporting application list as CSV or JSON in the batch operations\n- Added pure black theme support\n- Display current activity name (when possible) in the UI Tracker window\n- Added an option to filter apps by user in the Main page\n- Display a link to Pithus report in the scanner page if available."
  },
  {
    "path": "fastlane/metadata/android/en-US/changelogs/441.txt",
    "content": "- Overlay package management\n- Unfreeze option in activity shortcuts\n- Support market-like URL to open App Details page\n- Updated color codes\n- Fixed downgrading apps in Android 10 onwards\n- Fixed installer issues in the Huawei devices\n- In UI tracker, fixed clicking on the icon after it is iconified\n"
  },
  {
    "path": "fastlane/metadata/android/en-US/changelogs/442.txt",
    "content": "- Updated bloatware\n- Fixed fetching applications in multi-user environment in no-root mode\n- Fixed opening \"app-manager\" URLs from the web browsers\n- Fixed updating SSAID\n- Prevented a crash in Android < 9.0 that occurs due to invalid app ops."
  },
  {
    "path": "fastlane/metadata/android/en-US/changelogs/443.txt",
    "content": "- Updated translations\n- Improved handling the list items throughout App Manager\n- Fixed a regression error in file manager\n- Fixed spinners in the App Usage and the System Config pages."
  },
  {
    "path": "fastlane/metadata/android/en-US/changelogs/444.txt",
    "content": "- [Main page] Optimize searching and filtering\n- [Profile page] Use the configured state to execute a profile for simple shortcuts\n- Use sentence case for all strings\n- Prevent crashing while searching\n- Fix integer overflow in tar compression"
  },
  {
    "path": "fastlane/metadata/android/en-US/changelogs/445.txt",
    "content": "- [1-Click ops] Enabled \"Clear data from uninstalled apps\" to no-root users\n- [App info] Fixed freezing an app with \"Remember for this app\" turned on\n- [App ops] Fixed setting app ops in custom ROMs with MIUI properties injected\n- [Debloater] Display unsafe bloatware info\n- [Debloater] Sort by app label (or app name) rather than package name\n- [Installer] Added option to allow installing the existing applications\n- [Profile] Fixed updating profile modification status when an application is deleted from the list\n- [Terminal] Handled common colors and cursor movements\n- Enabled predictive back in Android 14 onwards, and others."
  },
  {
    "path": "fastlane/metadata/android/en-US/full_description.txt",
    "content": "<i>App Manager</i> began by merging the features of <i>App_packages Info</i> (formerly <i>Application Info</i>), <i>ClassyShark3xodus</i>, <i>Activity Launcher</i> and <i>Watt</i> into a single app with material design and dark mode to give a modern look and feel.\n\n<b>General features</b>\n\n• Fully reproducible, copylefted libre software (GPLv3+)\n• Material 3 with dynamic colours\n• Display as much information as possible in the main page\n• List activities, broadcast receivers, services, providers, app ops, permissions, signatures, shared libraries, etc. of an application\n• Launch activities and services\n• Create shortcuts of activities\n• Intercept activities\n• Scan for trackers and libraries in apps and list (all or only) tracking classes (and their code dump)\n• View/save the manifest of an app\n• Display app usage, data usage (mobile and Wi-Fi), and app storage info (requires “Usage Access” permission)\n• Install/uninstall APK files (including APKS, APKM and XAPK with OBB files)\n• Share APK files\n• Back up/restore APK files\n• Batch operations\n• Single-click operations\n• Logcat viewer, manager and exporter\n• Profiles\n• Debloater\n• Code editor\n• File manager\n• Simple terminal emulator\n• Open an app in Aurora Store or in your favourite F-Droid client\n• Sign APK files with custom signatures before installing\n• Backup encryption: OpenPGP via OpenKeychain, RSA, ECC (hybrid encryption with AES) and AES.\n• Track foreground UI components\n\n<b>Root/ADB-only features</b>\n\n• Revoke runtime (AKA dangerous) and development permissions\n• Change the mode of an app op\n• Display/kill/force-stop running apps or processes\n• Clear app data or app cache\n• View/change net policy\n• Control battery optimization\n• Freeze/unfreeze apps\n\n<b>Root-only features</b>\n\n• Block any activities, broadcast receivers, services, or providers of an app with native import/export as well as Watt and Blocker import support\n• View/edit/delete shared preferences of any app\n• Back up/restore apps with data, rules and extras (such as permissions, battery optimization, SSAID, etc.)\n• View system configurations including blacklisted or whitelisted apps, permissions, etc.\n• View/change SSAID.\n\n…and many more! This single app combines the features of 5 or 6 apps any tech-savvy person needs!\n\nSee the instructions page within the app for more information on how to use the app."
  },
  {
    "path": "fastlane/metadata/android/en-US/short_description.txt",
    "content": "A fully-featured package manager for android.\n"
  },
  {
    "path": "fastlane/metadata/android/en-US/title.txt",
    "content": "App Manager"
  },
  {
    "path": "fastlane/metadata/android/ja/full_description.txt",
    "content": "<i>App Manager</i>は<i>App_packages Info</i> (<i>Application Info</i>)、<i>ClassyShark3xodus</i>、<i>Activity Launcher</i>、<i>Watt</i>などの機能を一つのアプリに統合するために開発され、マテリアルデザインやダークモードに対応したモダンなデザインのAndroid用パッケージマネージャです。\n\n<b>特徴:</b>\n<ul>\n    <li>フリーでオープンソースです。</li>\n    <li>マテリアルデザインの洗練されたUIを備えています。</li>\n    <li>不要な権限を要求しません。</li>\n    <li>インターネット接続を行いません。 (ネットワーク権限はADBモードのために必要)</li>\n    <li>メイン画面だけで多くの情報を確認できます</li>\n    <li>あらゆるアプリのアクティビティ、ブロードキャストレシーバ、サービス、プロバイダ、アプリ権限、署名、共有ライブラリなどを確認できます。</li>\n    <li>アクティビティを選択して起動したり、カスタマイズ可能なショートカットを作成できます。</li>\n    <li>あらゆるアクティビティ、レシーバ、サービス、プロバイダをブロックすることができます。WattやBlockerからブロックリストをインポートすることもできます。 (Root化が必須)</li>\n    <li>Revoke <i>危険性のある</i> アプリ権限を拒否することができます。 (Root化またはADBが必須)</li>\n    <li>アプリのAppOpsを無効化することができます。(Root化またはADBが必須)</li>\n    <li>アプリのトラッカーをスキャンしてトラッカーのクラスを表示することができます。（最新版では日本のものも含む殆どのトラッカーの検出に対応しています。）</li>\n    <li>アプリのマニフェストファイルを確認できます。</li>\n    <li>アプリの共有設定を確認/編集/消去できます。 (Root化が必須)</li>\n    <li>実行中のアプリ、プロセスを確認/強制停止できます。 (Root化またはADBが必須)</li>\n    <li>アプリの使用状況、データ使用量、ストレージ情報を確認できます。 (使用状況へのアクセス権限の許可が必要)</li>\n    <li>APKファイルのエクスポートができます</li>\n    <li>アプリのデーター、キャッシュを消去できます。 (Root化またはADBが必須)</li>\n    <li>一括処理: アプリのデータを消去、 バックグラウンド実行を無効化、 アプリを無効化/強制停止/アンインストール</li>\n    <li>ワンタップ一括処理: 広告/トラッカーのコンポーネントをブロック、 指定した定義リストでコンポーネントをブロック、 複数のAppOpsをブロック</li>\n</ul>\n\n...他にも アプリをインストール/アンインストール/アップデート/有効化/無効化、アプリのインストール情報の表示、ストアで開くなど細かな機能がたくさんあります。\n\nアプリの使用方法について詳細な情報を知りたい場合、アプリ右上の「ヘルプ」をご参照ください（現在日本語翻訳作業中です）\n"
  },
  {
    "path": "fastlane/metadata/android/ja/short_description.txt",
    "content": "Androidの高機能でオープンソースなパッケージマネージャです。\n"
  },
  {
    "path": "fastlane/metadata/android/ja/title.txt",
    "content": "App Manager"
  },
  {
    "path": "gradle/wrapper/gradle-wrapper.properties",
    "content": "distributionBase=GRADLE_USER_HOME\ndistributionPath=wrapper/dists\ndistributionSha256Sum=8fad3d78296ca518113f3d29016617c7f9367dc005f932bd9d93bf45ba46072b\ndistributionUrl=https\\://services.gradle.org/distributions/gradle-9.0.0-bin.zip\nnetworkTimeout=10000\nvalidateDistributionUrl=true\nzipStoreBase=GRADLE_USER_HOME\nzipStorePath=wrapper/dists\n"
  },
  {
    "path": "gradle.properties",
    "content": "# Project-wide Gradle settings.\n\n# IDE (e.g. Android Studio) users:\n# Settings specified in this file will override any Gradle settings\n# configured through the IDE.\n\nandroid.useAndroidX=true\nandroid.enableJetifier=false\nandroid.nonTransitiveRClass=true\nandroid.nonFinalResIds=false\n\norg.gradle.jvmargs=-Xmx2048m -XX:MaxMetaspaceSize=512m -XX:+UseParallelGC -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8\norg.gradle.caching=true\n# org.gradle.unsafe.configuration-cache=true\n"
  },
  {
    "path": "gradlew",
    "content": "#!/bin/sh\n\n#\n# Copyright © 2015 the original authors.\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\");\n# you may not use this file except in compliance with the License.\n# You may obtain a copy of the License at\n#\n#      https://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS,\n# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n# See the License for the specific language governing permissions and\n# limitations under the License.\n#\n# SPDX-License-Identifier: Apache-2.0\n#\n\n##############################################################################\n#\n#   Gradle start up script for POSIX generated by Gradle.\n#\n#   Important for running:\n#\n#   (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is\n#       noncompliant, but you have some other compliant shell such as ksh or\n#       bash, then to run this script, type that shell name before the whole\n#       command line, like:\n#\n#           ksh Gradle\n#\n#       Busybox and similar reduced shells will NOT work, because this script\n#       requires all of these POSIX shell features:\n#         * functions;\n#         * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,\n#           «${var#prefix}», «${var%suffix}», and «$( cmd )»;\n#         * compound commands having a testable exit status, especially «case»;\n#         * various built-in commands including «command», «set», and «ulimit».\n#\n#   Important for patching:\n#\n#   (2) This script targets any POSIX shell, so it avoids extensions provided\n#       by Bash, Ksh, etc; in particular arrays are avoided.\n#\n#       The \"traditional\" practice of packing multiple parameters into a\n#       space-separated string is a well documented source of bugs and security\n#       problems, so this is (mostly) avoided, by progressively accumulating\n#       options in \"$@\", and eventually passing that to Java.\n#\n#       Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,\n#       and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;\n#       see the in-line comments for details.\n#\n#       There are tweaks for specific operating systems such as AIX, CygWin,\n#       Darwin, MinGW, and NonStop.\n#\n#   (3) This script is generated from the Groovy template\n#       https://github.com/gradle/gradle/blob/HEAD/platforms/jvm/plugins-application/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt\n#       within the Gradle project.\n#\n#       You can find Gradle at https://github.com/gradle/gradle/.\n#\n##############################################################################\n\n# Attempt to set APP_HOME\n\n# Resolve links: $0 may be a link\napp_path=$0\n\n# Need this for daisy-chained symlinks.\nwhile\n    APP_HOME=${app_path%\"${app_path##*/}\"}  # leaves a trailing /; empty if no leading path\n    [ -h \"$app_path\" ]\ndo\n    ls=$( ls -ld \"$app_path\" )\n    link=${ls#*' -> '}\n    case $link in             #(\n      /*)   app_path=$link ;; #(\n      *)    app_path=$APP_HOME$link ;;\n    esac\ndone\n\n# This is normally unused\n# shellcheck disable=SC2034\nAPP_BASE_NAME=${0##*/}\n# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036)\nAPP_HOME=$( cd -P \"${APP_HOME:-./}\" > /dev/null && printf '%s\\n' \"$PWD\" ) || exit\n\n# Use the maximum available, or set MAX_FD != -1 to use that value.\nMAX_FD=maximum\n\nwarn () {\n    echo \"$*\"\n} >&2\n\ndie () {\n    echo\n    echo \"$*\"\n    echo\n    exit 1\n} >&2\n\n# OS specific support (must be 'true' or 'false').\ncygwin=false\nmsys=false\ndarwin=false\nnonstop=false\ncase \"$( uname )\" in                #(\n  CYGWIN* )         cygwin=true  ;; #(\n  Darwin* )         darwin=true  ;; #(\n  MSYS* | MINGW* )  msys=true    ;; #(\n  NONSTOP* )        nonstop=true ;;\nesac\n\nCLASSPATH=\"\\\\\\\"\\\\\\\"\"\n\n\n# Determine the Java command to use to start the JVM.\nif [ -n \"$JAVA_HOME\" ] ; then\n    if [ -x \"$JAVA_HOME/jre/sh/java\" ] ; then\n        # IBM's JDK on AIX uses strange locations for the executables\n        JAVACMD=$JAVA_HOME/jre/sh/java\n    else\n        JAVACMD=$JAVA_HOME/bin/java\n    fi\n    if [ ! -x \"$JAVACMD\" ] ; then\n        die \"ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\n    fi\nelse\n    JAVACMD=java\n    if ! command -v java >/dev/null 2>&1\n    then\n        die \"ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.\n\nPlease set the JAVA_HOME variable in your environment to match the\nlocation of your Java installation.\"\n    fi\nfi\n\n# Increase the maximum file descriptors if we can.\nif ! \"$cygwin\" && ! \"$darwin\" && ! \"$nonstop\" ; then\n    case $MAX_FD in #(\n      max*)\n        # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.\n        # shellcheck disable=SC2039,SC3045\n        MAX_FD=$( ulimit -H -n ) ||\n            warn \"Could not query maximum file descriptor limit\"\n    esac\n    case $MAX_FD in  #(\n      '' | soft) :;; #(\n      *)\n        # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.\n        # shellcheck disable=SC2039,SC3045\n        ulimit -n \"$MAX_FD\" ||\n            warn \"Could not set maximum file descriptor limit to $MAX_FD\"\n    esac\nfi\n\n# Collect all arguments for the java command, stacking in reverse order:\n#   * args from the command line\n#   * the main class name\n#   * -classpath\n#   * -D...appname settings\n#   * --module-path (only if needed)\n#   * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.\n\n# For Cygwin or MSYS, switch paths to Windows format before running java\nif \"$cygwin\" || \"$msys\" ; then\n    APP_HOME=$( cygpath --path --mixed \"$APP_HOME\" )\n    CLASSPATH=$( cygpath --path --mixed \"$CLASSPATH\" )\n\n    JAVACMD=$( cygpath --unix \"$JAVACMD\" )\n\n    # Now convert the arguments - kludge to limit ourselves to /bin/sh\n    for arg do\n        if\n            case $arg in                                #(\n              -*)   false ;;                            # don't mess with options #(\n              /?*)  t=${arg#/} t=/${t%%/*}              # looks like a POSIX filepath\n                    [ -e \"$t\" ] ;;                      #(\n              *)    false ;;\n            esac\n        then\n            arg=$( cygpath --path --ignore --mixed \"$arg\" )\n        fi\n        # Roll the args list around exactly as many times as the number of\n        # args, so each arg winds up back in the position where it started, but\n        # possibly modified.\n        #\n        # NB: a `for` loop captures its iteration list before it begins, so\n        # changing the positional parameters here affects neither the number of\n        # iterations, nor the values presented in `arg`.\n        shift                   # remove old arg\n        set -- \"$@\" \"$arg\"      # push replacement arg\n    done\nfi\n\n\n# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\nDEFAULT_JVM_OPTS='\"-Xmx64m\" \"-Xms64m\"'\n\n# Collect all arguments for the java command:\n#   * DEFAULT_JVM_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments,\n#     and any embedded shellness will be escaped.\n#   * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be\n#     treated as '${Hostname}' itself on the command line.\n\nset -- \\\n        \"-Dorg.gradle.appname=$APP_BASE_NAME\" \\\n        -classpath \"$CLASSPATH\" \\\n        -jar \"$APP_HOME/gradle/wrapper/gradle-wrapper.jar\" \\\n        \"$@\"\n\n# Stop when \"xargs\" is not available.\nif ! command -v xargs >/dev/null 2>&1\nthen\n    die \"xargs is not available\"\nfi\n\n# Use \"xargs\" to parse quoted args.\n#\n# With -n1 it outputs one arg per line, with the quotes and backslashes removed.\n#\n# In Bash we could simply go:\n#\n#   readarray ARGS < <( xargs -n1 <<<\"$var\" ) &&\n#   set -- \"${ARGS[@]}\" \"$@\"\n#\n# but POSIX shell has neither arrays nor command substitution, so instead we\n# post-process each arg (as a line of input to sed) to backslash-escape any\n# character that might be a shell metacharacter, then use eval to reverse\n# that process (while maintaining the separation between arguments), and wrap\n# the whole thing up as a single \"set\" statement.\n#\n# This will of course break if any of these variables contains a newline or\n# an unmatched quote.\n#\n\neval \"set -- $(\n        printf '%s\\n' \"$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS\" |\n        xargs -n1 |\n        sed ' s~[^-[:alnum:]+,./:=@_]~\\\\&~g; ' |\n        tr '\\n' ' '\n    )\" '\"$@\"'\n\nexec \"$JAVACMD\" \"$@\"\n"
  },
  {
    "path": "gradlew.bat",
    "content": "@rem\r\n@rem Copyright 2015 the original author or authors.\r\n@rem\r\n@rem Licensed under the Apache License, Version 2.0 (the \"License\");\r\n@rem you may not use this file except in compliance with the License.\r\n@rem You may obtain a copy of the License at\r\n@rem\r\n@rem      https://www.apache.org/licenses/LICENSE-2.0\r\n@rem\r\n@rem Unless required by applicable law or agreed to in writing, software\r\n@rem distributed under the License is distributed on an \"AS IS\" BASIS,\r\n@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r\n@rem See the License for the specific language governing permissions and\r\n@rem limitations under the License.\r\n@rem\r\n@rem SPDX-License-Identifier: Apache-2.0\r\n@rem\r\n\r\n@if \"%DEBUG%\"==\"\" @echo off\r\n@rem ##########################################################################\r\n@rem\r\n@rem  Gradle startup script for Windows\r\n@rem\r\n@rem ##########################################################################\r\n\r\n@rem Set local scope for the variables with windows NT shell\r\nif \"%OS%\"==\"Windows_NT\" setlocal\r\n\r\nset DIRNAME=%~dp0\r\nif \"%DIRNAME%\"==\"\" set DIRNAME=.\r\n@rem This is normally unused\r\nset APP_BASE_NAME=%~n0\r\nset APP_HOME=%DIRNAME%\r\n\r\n@rem Resolve any \".\" and \"..\" in APP_HOME to make it shorter.\r\nfor %%i in (\"%APP_HOME%\") do set APP_HOME=%%~fi\r\n\r\n@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.\r\nset DEFAULT_JVM_OPTS=\"-Xmx64m\" \"-Xms64m\"\r\n\r\n@rem Find java.exe\r\nif defined JAVA_HOME goto findJavaFromJavaHome\r\n\r\nset JAVA_EXE=java.exe\r\n%JAVA_EXE% -version >NUL 2>&1\r\nif %ERRORLEVEL% equ 0 goto execute\r\n\r\necho. 1>&2\r\necho ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2\r\necho. 1>&2\r\necho Please set the JAVA_HOME variable in your environment to match the 1>&2\r\necho location of your Java installation. 1>&2\r\n\r\ngoto fail\r\n\r\n:findJavaFromJavaHome\r\nset JAVA_HOME=%JAVA_HOME:\"=%\r\nset JAVA_EXE=%JAVA_HOME%/bin/java.exe\r\n\r\nif exist \"%JAVA_EXE%\" goto execute\r\n\r\necho. 1>&2\r\necho ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2\r\necho. 1>&2\r\necho Please set the JAVA_HOME variable in your environment to match the 1>&2\r\necho location of your Java installation. 1>&2\r\n\r\ngoto fail\r\n\r\n:execute\r\n@rem Setup the command line\r\n\r\nset CLASSPATH=\r\n\r\n\r\n@rem Execute Gradle\r\n\"%JAVA_EXE%\" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% \"-Dorg.gradle.appname=%APP_BASE_NAME%\" -classpath \"%CLASSPATH%\" -jar \"%APP_HOME%\\gradle\\wrapper\\gradle-wrapper.jar\" %*\r\n\r\n:end\r\n@rem End local scope for the variables with windows NT shell\r\nif %ERRORLEVEL% equ 0 goto mainEnd\r\n\r\n:fail\r\nrem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of\r\nrem the _cmd.exe /c_ return code!\r\nset EXIT_CODE=%ERRORLEVEL%\r\nif %EXIT_CODE% equ 0 set EXIT_CODE=1\r\nif not \"\"==\"%GRADLE_EXIT_CONSOLE%\" exit %EXIT_CODE%\r\nexit /b %EXIT_CODE%\r\n\r\n:mainEnd\r\nif \"%OS%\"==\"Windows_NT\" endlocal\r\n\r\n:omega\r\n"
  },
  {
    "path": "hiddenapi/.gitignore",
    "content": "/build"
  },
  {
    "path": "hiddenapi/build.gradle",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\nplugins {\n    id('com.android.library')\n}\n\nandroid {\n    namespace 'io.github.muntashirakon.hiddenapi'\n    compileSdk compile_sdk\n    buildToolsVersion = build_tools\n\n    defaultConfig {\n        minSdk min_sdk\n        targetSdk target_sdk\n    }\n\n    compileOptions {\n        sourceCompatibility JavaVersion.VERSION_1_8\n        targetCompatibility JavaVersion.VERSION_1_8\n    }\n}\n\ndependencies {\n    annotationProcessor \"dev.rikka.tools.refine:annotation-processor:${refine_version}\"\n    compileOnly \"dev.rikka.tools.refine:annotation:${refine_version}\"\n    compileOnly \"org.jetbrains:annotations:${jb_annotation_version}\"\n    compileOnly \"androidx.annotation:annotation:${annotation_version}\"\n}\n"
  },
  {
    "path": "hiddenapi/src/main/AndroidManifest.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<manifest />"
  },
  {
    "path": "hiddenapi/src/main/java/android/annotation/AppIdInt.java",
    "content": "package android.annotation;\n\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.Target;\n\nimport static java.lang.annotation.ElementType.FIELD;\nimport static java.lang.annotation.ElementType.METHOD;\nimport static java.lang.annotation.ElementType.PARAMETER;\nimport static java.lang.annotation.RetentionPolicy.SOURCE;\n\n/**\n * Denotes that the annotated element is a multi-user application ID. This is\n * <em>not</em> the same as a UID.\n */\n@Retention(SOURCE)\n@Target({METHOD, PARAMETER, FIELD})\npublic @interface AppIdInt {\n}"
  },
  {
    "path": "hiddenapi/src/main/java/android/annotation/UserIdInt.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage android.annotation;\n\npublic @interface UserIdInt {\n}\n"
  },
  {
    "path": "hiddenapi/src/main/java/android/app/ActivityManagerNative.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage android.app;\n\nimport android.os.Binder;\nimport android.os.IBinder;\n\nimport misc.utils.HiddenUtil;\n\n/**\n * @deprecated Since Android O\n */\npublic abstract class ActivityManagerNative extends Binder implements IActivityManager {\n    /**\n     * Cast a Binder object into an activity manager interface, generating\n     * a proxy if needed.\n     *\n     * @deprecated Since Android O. Use {@link IActivityManager.Stub#asInterface(IBinder)} instead.\n     */\n    @Deprecated\n    static public IActivityManager asInterface(IBinder obj) {\n        return HiddenUtil.throwUOE(obj);\n    }\n}\n"
  },
  {
    "path": "hiddenapi/src/main/java/android/app/ActivityThread.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage android.app;\n\nimport android.content.pm.ApplicationInfo;\nimport android.content.pm.IPackageManager;\n\nimport misc.utils.HiddenUtil;\n\npublic class ActivityThread {\n    public static IPackageManager getPackageManager() {\n        return HiddenUtil.throwUOE();\n    }\n\n    public static ActivityThread systemMain() {\n        return HiddenUtil.throwUOE();\n    }\n\n    public static ActivityThread currentActivityThread() {\n        return HiddenUtil.throwUOE();\n    }\n\n    public static Application currentApplication() {\n        return HiddenUtil.throwUOE();\n    }\n\n    public static String currentProcessName() {\n        return HiddenUtil.throwUOE();\n    }\n\n    public ContextImpl getSystemContext() {\n        return HiddenUtil.throwUOE();\n    }\n\n    public IApplicationThread getApplicationThread() {\n        return HiddenUtil.throwUOE();\n    }\n\n    public void installSystemApplicationInfo(ApplicationInfo info, ClassLoader classLoader) {\n        HiddenUtil.throwUOE(info, classLoader);\n    }\n}\n"
  },
  {
    "path": "hiddenapi/src/main/java/android/app/AppOpsManagerHidden.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage android.app;\n\nimport android.os.Build;\nimport android.os.Parcel;\nimport android.os.Parcelable;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.RequiresApi;\n\nimport java.util.List;\n\nimport dev.rikka.tools.refine.RefineAs;\nimport misc.utils.HiddenUtil;\n\n@SuppressWarnings(\"FieldMayBeFinal\")\n@RefineAs(AppOpsManager.class)\npublic class AppOpsManagerHidden {\n    /**\n     * Uid state: The UID is a foreground persistent app. The lower the UID\n     * state the more important the UID is for the user.\n     */\n    @RequiresApi(Build.VERSION_CODES.P)\n    public static /*final*/ int UID_STATE_PERSISTENT = 100;\n\n    /**\n     * Uid state: The UID is top foreground app. The lower the UID\n     * state the more important the UID is for the user.\n     */\n    @RequiresApi(Build.VERSION_CODES.P)\n    public static /*final*/ int UID_STATE_TOP = 200;\n\n    /**\n     * Uid state: The UID is running a foreground service of location type.\n     * The lower the UID state the more important the UID is for the user.\n     */\n    @RequiresApi(Build.VERSION_CODES.Q)\n    public static final int UID_STATE_FOREGROUND_SERVICE_LOCATION = 300;\n\n    /**\n     * Uid state: The UID is running a foreground service. The lower the UID\n     * state the more important the UID is for the user.\n     */\n    @RequiresApi(Build.VERSION_CODES.P)\n    public static /*final*/ int UID_STATE_FOREGROUND_SERVICE = 400;\n\n    /**\n     * Uid state: The UID is a foreground app. The lower the UID\n     * state the more important the UID is for the user.\n     */\n    @RequiresApi(Build.VERSION_CODES.P)\n    public static /*final*/ int UID_STATE_FOREGROUND = 500;\n\n    /**\n     * Last UID state in which we don't restrict what an op can do.\n     *\n     * @deprecated Replaced by {@link #UID_STATE_MAX_LAST_NON_RESTRICTED} in Android 10 (SDK 29)\n     */\n    @Deprecated\n    @RequiresApi(Build.VERSION_CODES.P)\n    public static /*final*/ int UID_STATE_LAST_NON_RESTRICTED = HiddenUtil.throwUOE();\n\n    /**\n     * The max, which is min priority, UID state for which any app op\n     * would be considered as performed in the foreground.\n     */\n    @RequiresApi(Build.VERSION_CODES.Q)\n    public static /*final*/ int UID_STATE_MAX_LAST_NON_RESTRICTED = HiddenUtil.throwUOE();\n\n    /**\n     * Uid state: The UID is a background app. The lower the UID\n     * state the more important the UID is for the user.\n     */\n    @RequiresApi(Build.VERSION_CODES.P)\n    public static /*final*/ int UID_STATE_BACKGROUND = 600;\n\n    /**\n     * Uid state: The UID is a cached app. The lower the UID\n     * state the more important the UID is for the user.\n     */\n    @RequiresApi(Build.VERSION_CODES.P)\n    public static /*final*/ int UID_STATE_CACHED = 700;\n\n    /**\n     * Uid state: The UID state with the highest priority.\n     */\n    @RequiresApi(Build.VERSION_CODES.Q)\n    public static final int MAX_PRIORITY_UID_STATE = UID_STATE_PERSISTENT;\n\n    /**\n     * Uid state: The UID state with the lowest priority.\n     */\n    @RequiresApi(Build.VERSION_CODES.Q)\n    public static final int MIN_PRIORITY_UID_STATE = UID_STATE_CACHED;\n\n\n    /**\n     * Flag: non proxy operations. These are operations\n     * performed on behalf of the app itself and not on behalf of\n     * another one.\n     */\n    @RequiresApi(Build.VERSION_CODES.Q)\n    public static final int OP_FLAG_SELF = 0x1;\n\n    /**\n     * Flag: trusted proxy operations. These are operations\n     * performed on behalf of another app by a trusted app.\n     * Which is work a trusted app blames on another app.\n     */\n    @RequiresApi(Build.VERSION_CODES.Q)\n    public static final int OP_FLAG_TRUSTED_PROXY = 0x2;\n\n    /**\n     * Flag: untrusted proxy operations. These are operations\n     * performed on behalf of another app by an untrusted app.\n     * Which is work an untrusted app blames on another app.\n     */\n    @RequiresApi(Build.VERSION_CODES.Q)\n    public static final int OP_FLAG_UNTRUSTED_PROXY = 0x4;\n\n    /**\n     * Flag: trusted proxied operations. These are operations\n     * performed by a trusted other app on behalf of an app.\n     * Which is work an app was blamed for by a trusted app.\n     */\n    @RequiresApi(Build.VERSION_CODES.Q)\n    public static final int OP_FLAG_TRUSTED_PROXIED = 0x8;\n\n    /**\n     * Flag: untrusted proxied operations. These are operations\n     * performed by an untrusted other app on behalf of an app.\n     * Which is work an app was blamed for by an untrusted app.\n     */\n    @RequiresApi(Build.VERSION_CODES.Q)\n    public static final int OP_FLAG_UNTRUSTED_PROXIED = 0x10;\n\n    /**\n     * Flags: all operations. These include operations matched\n     * by {@link #OP_FLAG_SELF}, {@link #OP_FLAG_TRUSTED_PROXIED},\n     * {@link #OP_FLAG_UNTRUSTED_PROXIED}, {@link #OP_FLAG_TRUSTED_PROXIED},\n     * {@link #OP_FLAG_UNTRUSTED_PROXIED}.\n     */\n    @RequiresApi(Build.VERSION_CODES.Q)\n    public static final int OP_FLAGS_ALL = OP_FLAG_SELF\n            | OP_FLAG_TRUSTED_PROXY\n            | OP_FLAG_UNTRUSTED_PROXY\n            | OP_FLAG_TRUSTED_PROXIED\n            | OP_FLAG_UNTRUSTED_PROXIED;\n\n    /**\n     * Flags: all trusted operations which is ones either the app did {@link #OP_FLAG_SELF},\n     * or it was blamed for by a trusted app {@link #OP_FLAG_TRUSTED_PROXIED}, or ones the\n     * app if untrusted blamed on other apps {@link #OP_FLAG_UNTRUSTED_PROXY}.\n     */\n    @RequiresApi(Build.VERSION_CODES.Q)\n    public static final int OP_FLAGS_ALL_TRUSTED = OP_FLAG_SELF\n            | OP_FLAG_UNTRUSTED_PROXY\n            | OP_FLAG_TRUSTED_PROXIED;\n\n\n    public static final int OP_NONE = -1;\n    /**\n     * Retrieve current usage stats via {@link android.app.usage.UsageStatsManager}.\n     */\n    public static /*final*/ int OP_GET_USAGE_STATS = 43;\n    /**\n     * Control whether an application is allowed to run in the background.\n     */\n    @RequiresApi(Build.VERSION_CODES.N)\n    public static /*final*/ int OP_RUN_IN_BACKGROUND = 63;\n    /**\n     * Run jobs when in background\n     */\n    @RequiresApi(Build.VERSION_CODES.P)\n    public static /*final*/ int OP_RUN_ANY_IN_BACKGROUND = 70;\n    /**\n     * Access all external storage\n     */\n    public static /*final*/ int OP_MANAGE_EXTERNAL_STORAGE = 92;\n    public static /*final*/ int _NUM_OP = 121;\n\n    public static /*final*/ int MIUI_OP_START = 10000;\n    public static /*final*/ int MIUI_OP_END = 10040;\n\n    /**\n     * This maps each operation to the public string constant for it.\n     * If it doesn't have a public string constant, it maps to null.\n     */\n    private static String[] sOpToString = HiddenUtil.throwUOE();\n\n    /**\n     * Retrieve the op switch that controls the given operation.\n     */\n    public static int opToSwitch(int op) {\n        return HiddenUtil.throwUOE(op);\n    }\n\n    /**\n     * Retrieve a non-localized name for the operation, for debugging output.\n     */\n    @NonNull\n    public static String opToName(int op) {\n        return HiddenUtil.throwUOE(op);\n    }\n\n    /**\n     * Retrieve a non-localized public name for the operation.\n     */\n    @RequiresApi(Build.VERSION_CODES.Q)\n    @NonNull\n    public static String opToPublicName(int op) {\n        return HiddenUtil.throwUOE(op);\n    }\n\n    /**\n     * Retrieve the permission associated with an operation, or null if there is not one.\n     */\n    @Nullable\n    public static String opToPermission(int op) {\n        return HiddenUtil.throwUOE(op);\n    }\n\n    /**\n     * Retrieve the permission associated with an operation, or null if there is not one.\n     *\n     * @param op The operation name.\n     */\n    @RequiresApi(Build.VERSION_CODES.Q)\n    @Nullable\n    public static String opToPermission(@NonNull String op) {\n        return HiddenUtil.throwUOE(op);\n    }\n\n    /**\n     * Retrieve the user restriction associated with an operation, or null if there is not one.\n     */\n    @Nullable\n    public static String opToRestriction(int op) {\n        return HiddenUtil.throwUOE(op);\n    }\n\n    /**\n     * Retrieve the app op code for a permission, or {@link #OP_NONE} if there is not one.\n     */\n    @RequiresApi(Build.VERSION_CODES.M)\n    public static int permissionToOpCode(String permission) {\n        return HiddenUtil.throwUOE(permission);\n    }\n\n    /**\n     * Retrieve whether the op allows the system (and system ui) to\n     * bypass the user restriction.\n     */\n    public static boolean opAllowSystemBypassRestriction(int op) {\n        return HiddenUtil.throwUOE(op);\n    }\n\n    /**\n     * Retrieve the default mode for the operation.\n     * <p>\n     * <b>Note:</b> In some cases, this might throw {@link NoSuchMethodError} in which case, use {@link #opToDefaultMode(int, boolean)}.\n     */\n    public static int opToDefaultMode(int op) {\n        return HiddenUtil.throwUOE(op);\n    }\n\n    /**\n     * Retrieve the default mode for the operation.\n     * <p>\n     * <b>Note:</b> The only known case is Android 6.0.1 in Samsung devices (API 23)\n     */\n    public static int opToDefaultMode(int op, boolean isStrict) {\n        return HiddenUtil.throwUOE(op);\n    }\n\n    /**\n     * Retrieve the default mode for the app op.\n     *\n     * @param appOp The app op name\n     * @return the default mode for the app op\n     */\n    @RequiresApi(Build.VERSION_CODES.Q)\n    public static int opToDefaultMode(@NonNull String appOp) {\n        return HiddenUtil.throwUOE(appOp);\n    }\n\n    /**\n     * Retrieve the human readable mode.\n     */\n    @RequiresApi(Build.VERSION_CODES.P)\n    public static String modeToName(int mode) {\n        return HiddenUtil.throwUOE(mode);\n    }\n\n    /**\n     * Retrieve whether the op can be read by apps with manage appops permission.\n     */\n    @RequiresApi(Build.VERSION_CODES.TIRAMISU)\n    public static boolean opRestrictsRead(int op) {\n        return HiddenUtil.throwUOE(op);\n    }\n\n    /**\n     * Retrieve whether the op allows itself to be reset.\n     */\n    public static boolean opAllowsReset(int op) {\n        return HiddenUtil.throwUOE(op);\n    }\n\n    /**\n     * Gets the app op name associated with a given permission.\n     * The app op name is one of the public constants defined\n     * in this class such as {@code OPSTR_COARSE_LOCATION}.\n     * This API is intended to be used for mapping runtime\n     * permissions to the corresponding app op.\n     *\n     * @param permission The permission.\n     * @return The app op associated with the permission or null.\n     */\n    @RequiresApi(Build.VERSION_CODES.M)\n    public static String permissionToOp(String permission) {\n        return HiddenUtil.throwUOE(permission);\n    }\n\n    public static int strOpToOp(String op) {\n        return HiddenUtil.throwUOE(op);\n    }\n\n    public static class PackageOps implements Parcelable {\n        @NonNull\n        public String getPackageName() {\n            return HiddenUtil.throwUOE();\n        }\n\n        public int getUid() {\n            return HiddenUtil.throwUOE();\n        }\n\n        @NonNull\n        public List<Parcelable> getOps() {\n            return HiddenUtil.throwUOE();\n        }\n\n        public static final Creator<PackageOps> CREATOR = HiddenUtil.creator();\n\n        @Override\n        public int describeContents() {\n            return HiddenUtil.throwUOE();\n        }\n\n        @Override\n        public void writeToParcel(Parcel dest, int flags) {\n            HiddenUtil.throwUOE(dest, flags);\n        }\n    }\n\n    public static class OpEntry implements Parcelable {\n        @Override\n        public void writeToParcel(Parcel dest, int flags) {\n            HiddenUtil.throwUOE(dest, flags);\n        }\n\n        @Override\n        public int describeContents() {\n            return HiddenUtil.throwUOE();\n        }\n\n        public static final Creator<OpEntry> CREATOR = HiddenUtil.creator();\n\n        public int getOp() {\n            return HiddenUtil.throwUOE();\n        }\n\n        @RequiresApi(Build.VERSION_CODES.Q)\n        @NonNull\n        public String getOpStr() {\n            return HiddenUtil.throwUOE();\n        }\n\n        public int getMode() {\n            return HiddenUtil.throwUOE();\n        }\n\n        /**\n         * @deprecated since Android 11 (R)\n         */\n        @Deprecated\n        public long getTime() {\n            return HiddenUtil.throwUOE();\n        }\n\n        /**\n         * @deprecated Removed in Android 10 (Q)\n         */\n        @RequiresApi(Build.VERSION_CODES.P)\n        @Deprecated\n        public long getLastAccessTime() {\n            return HiddenUtil.throwUOE();\n        }\n\n        @RequiresApi(Build.VERSION_CODES.Q)\n        public long getLastAccessTime(int flags) {\n            return HiddenUtil.throwUOE(flags);\n        }\n\n        /**\n         * @deprecated Removed in Android 10 (Q)\n         */\n        @RequiresApi(Build.VERSION_CODES.P)\n        public long getLastAccessForegroundTime() {\n            return HiddenUtil.throwUOE();\n        }\n\n        @RequiresApi(Build.VERSION_CODES.Q)\n        public long getLastAccessForegroundTime(int flags) {\n            return HiddenUtil.throwUOE(flags);\n        }\n\n        /**\n         * @deprecated Removed in Android 10 (Q)\n         */\n        @RequiresApi(Build.VERSION_CODES.P)\n        public long getLastAccessBackgroundTime() {\n            return HiddenUtil.throwUOE();\n        }\n\n        @RequiresApi(Build.VERSION_CODES.Q)\n        public long getLastAccessBackgroundTime(int flags) {\n            return HiddenUtil.throwUOE(flags);\n        }\n\n        /**\n         * @deprecated Removed in Android 10 (Q)\n         */\n        @RequiresApi(Build.VERSION_CODES.P)\n        public long getLastTimeFor(int uidState) {\n            return HiddenUtil.throwUOE(uidState);\n        }\n\n        @RequiresApi(Build.VERSION_CODES.Q)\n        public long getLastAccessTime(int fromUidState, int toUidState, int flags) {\n            return HiddenUtil.throwUOE(fromUidState, toUidState, flags);\n        }\n\n        /**\n         * @deprecated since Android 11 (R)\n         */\n        @Deprecated\n        public long getRejectTime() {\n            return HiddenUtil.throwUOE();\n        }\n\n        /**\n         * @deprecated Removed in Android 10 (Q)\n         */\n        @RequiresApi(Build.VERSION_CODES.P)\n        public long getLastRejectTime() {\n            return HiddenUtil.throwUOE();\n        }\n\n        @RequiresApi(Build.VERSION_CODES.Q)\n        public long getLastRejectTime(int flags) {\n            return HiddenUtil.throwUOE(flags);\n        }\n\n        /**\n         * @deprecated Removed in Android 10 (Q)\n         */\n        @RequiresApi(Build.VERSION_CODES.P)\n        public long getLastRejectForegroundTime() {\n            return HiddenUtil.throwUOE();\n        }\n\n        @RequiresApi(Build.VERSION_CODES.Q)\n        public long getLastRejectForegroundTime(int flags) {\n            return HiddenUtil.throwUOE(flags);\n        }\n\n        /**\n         * @deprecated Removed in Android 10 (Q)\n         */\n        @RequiresApi(Build.VERSION_CODES.P)\n        public long getLastRejectBackgroundTime() {\n            return HiddenUtil.throwUOE();\n        }\n\n        @RequiresApi(Build.VERSION_CODES.Q)\n        public long getLastRejectBackgroundTime(int flags) {\n            return HiddenUtil.throwUOE(flags);\n        }\n\n        /**\n         * @deprecated Removed in Android 10 (Q)\n         */\n        @RequiresApi(Build.VERSION_CODES.P)\n        public long getLastRejectTimeFor(int uidState) {\n            return HiddenUtil.throwUOE(uidState);\n        }\n\n        @RequiresApi(Build.VERSION_CODES.Q)\n        public long getLastRejectTime(int fromUidState, int toUidState, int flags) {\n            return HiddenUtil.throwUOE(fromUidState, toUidState, flags);\n        }\n\n        public boolean isRunning() {\n            return HiddenUtil.throwUOE();\n        }\n\n        /**\n         * @return {@code int} value up to Android 9 (P), {@code long} after Android 10 (Q)\n         * @deprecated since Android 11 (R), but mustn't be used since Android 10 (Q)\n         */\n        @Deprecated\n        public int getDuration() {\n            return HiddenUtil.throwUOE();\n        }\n\n        @RequiresApi(Build.VERSION_CODES.R)\n        public long getLastDuration(int flags) {\n            return HiddenUtil.throwUOE(flags);\n        }\n\n        @RequiresApi(Build.VERSION_CODES.Q)\n        public long getLastForegroundDuration(int flags) {\n            return HiddenUtil.throwUOE(flags);\n        }\n\n        @RequiresApi(Build.VERSION_CODES.Q)\n        public long getLastBackgroundDuration(int flags) {\n            return HiddenUtil.throwUOE(flags);\n        }\n\n        @RequiresApi(Build.VERSION_CODES.Q)\n        public long getLastDuration(int fromUidState, int toUidState, int flags) {\n            return HiddenUtil.throwUOE(fromUidState, toUidState, flags);\n        }\n\n        /**\n         * @deprecated since Android 11 (R)\n         */\n        @RequiresApi(Build.VERSION_CODES.M)\n        public int getProxyUid() {\n            return HiddenUtil.throwUOE();\n        }\n\n        /**\n         * @deprecated since Android 11 (R)\n         */\n        @RequiresApi(Build.VERSION_CODES.Q)\n        public int getProxyUid(int uidState, int flags) {\n            return HiddenUtil.throwUOE(uidState, flags);\n        }\n\n        /**\n         * @deprecated since Android 11 (R)\n         */\n        @RequiresApi(Build.VERSION_CODES.M)\n        @Nullable\n        public String getProxyPackageName() {\n            return HiddenUtil.throwUOE();\n        }\n\n        /**\n         * @deprecated since Android 11 (R)\n         */\n        @RequiresApi(Build.VERSION_CODES.Q)\n        @Nullable\n        public String getProxyPackageName(int uidState, int flags) {\n            return HiddenUtil.throwUOE(uidState, flags);\n        }\n\n        // TODO(24/12/20): Get proxy info (From API 30)\n    }\n}\n"
  },
  {
    "path": "hiddenapi/src/main/java/android/app/ContentProviderHolder.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage android.app;\n\nimport android.content.IContentProvider;\nimport android.os.Build;\nimport android.os.Parcel;\nimport android.os.Parcelable;\n\nimport androidx.annotation.RequiresApi;\n\nimport misc.utils.HiddenUtil;\n\n@RequiresApi(Build.VERSION_CODES.O)\npublic class ContentProviderHolder implements Parcelable {\n    public IContentProvider provider;\n\n    @Override\n    public void writeToParcel(Parcel dest, int flags) {\n        HiddenUtil.throwUOE(dest, flags);\n    }\n\n    @Override\n    public int describeContents() {\n        return HiddenUtil.throwUOE();\n    }\n\n    public static final Creator<ContentProviderHolder> CREATOR = HiddenUtil.creator();\n}\n"
  },
  {
    "path": "hiddenapi/src/main/java/android/app/ContextImpl.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage android.app;\n\nimport android.content.Context;\nimport android.content.pm.PackageManager;\nimport android.os.UserHandle;\n\nimport misc.utils.HiddenUtil;\n\npublic abstract class ContextImpl extends Context {\n    public Context createPackageContextAsUser(String packageName, int flags, UserHandle user)\n            throws PackageManager.NameNotFoundException {\n        return HiddenUtil.throwUOE();\n    }\n}\n"
  },
  {
    "path": "hiddenapi/src/main/java/android/app/GrantedUriPermission.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage android.app;\n\nimport android.net.Uri;\nimport android.os.Parcel;\nimport android.os.Parcelable;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport misc.utils.HiddenUtil;\n\npublic class GrantedUriPermission implements Parcelable {\n    public final Uri uri;\n    public final String packageName;\n\n    public GrantedUriPermission(@NonNull Uri uri, @Nullable String packageName) {\n        HiddenUtil.throwUOE(uri, packageName);\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public void writeToParcel(Parcel dest, int flags) {\n        HiddenUtil.throwUOE(dest, flags);\n    }\n\n    @Override\n    public int describeContents() {\n        return HiddenUtil.throwUOE();\n    }\n\n    public static final Creator<GrantedUriPermission> CREATOR = HiddenUtil.creator();\n}\n"
  },
  {
    "path": "hiddenapi/src/main/java/android/app/IActivityManager.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage android.app;\n\nimport android.content.ComponentName;\nimport android.content.IContentProvider;\nimport android.content.IIntentReceiver;\nimport android.content.IIntentSender;\nimport android.content.Intent;\nimport android.content.IntentFilter;\nimport android.content.UriPermission;\nimport android.content.pm.ApplicationInfo;\nimport android.content.pm.IPackageDataObserver;\nimport android.content.pm.ParceledListSlice;\nimport android.content.pm.UserInfo;\nimport android.net.Uri;\nimport android.os.Binder;\nimport android.os.Build;\nimport android.os.Bundle;\nimport android.os.IBinder;\nimport android.os.IInterface;\nimport android.os.Parcel;\nimport android.os.ParcelFileDescriptor;\nimport android.os.Parcelable;\nimport android.os.RemoteException;\n\nimport androidx.annotation.RequiresApi;\n\nimport java.util.List;\n\nimport misc.utils.HiddenUtil;\n\n/**\n * System private API for talking with the activity manager service.  This\n * provides calls from the application back to the activity manager.\n */\npublic interface IActivityManager extends IInterface {\n    // WARNING: when these transactions are updated, check if they are any callers on the native\n    // side. If so, make sure they are using the correct transaction ids and arguments.\n    // If a transaction which will also be used on the native side is being inserted, add it to\n    // below block of transactions.\n    // Since these transactions are also called from native code, these must be kept in sync with\n    // the ones in frameworks/native/libs/binder/include/binder/IActivityManager.h\n    // =============== Beginning of transactions used on native side as well ======================\n\n    ParcelFileDescriptor openContentUri(String uriString) throws RemoteException;\n\n    boolean isUidActive(int uid, String callingPackage) throws RemoteException;\n\n    int getUidProcessState(int uid, String callingPackage) throws RemoteException;\n    // =============== End of transactions used on native side as well ============================\n    // Special low-level communication with activity manager.\n\n    /**\n     * @deprecated Use {@link #startActivityWithFeature} instead\n     */\n    int startActivity(IApplicationThread caller, String callingPackage, Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode, int flags, ProfilerInfo profilerInfo, Bundle options) throws RemoteException;\n\n    int startActivityWithFeature(IApplicationThread caller, String callingPackage, String callingFeatureId, Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode, int flags, ProfilerInfo profilerInfo, Bundle options) throws RemoteException;\n\n    boolean finishActivity(IBinder token, int code, Intent data, int finishTask) throws RemoteException;\n\n    Intent registerReceiver(IApplicationThread caller, String callerPackage, IIntentReceiver receiver, IntentFilter filter, String requiredPermission, int userId, int flags) throws RemoteException;\n\n    Intent registerReceiverWithFeature(IApplicationThread caller, String callerPackage, String callingFeatureId, IIntentReceiver receiver, IntentFilter filter, String requiredPermission, int userId, int flags) throws RemoteException;\n\n    void unregisterReceiver(IIntentReceiver receiver) throws RemoteException;\n\n\n    /**\n     * @deprecated Removed in Android M.\n     */\n    @Deprecated\n    int broadcastIntent(IApplicationThread caller, Intent intent, String resolvedType,\n                        IIntentReceiver resultTo, int resultCode, String resultData, Bundle map,\n                        String requiredPermission, int appOp, boolean serialized, boolean sticky,\n                        int userId) throws RemoteException;\n\n    /**\n     * @deprecated Deprecated in Android 11. Use {@link #broadcastIntentWithFeature} instead\n     */\n    @Deprecated\n    @RequiresApi(Build.VERSION_CODES.M)\n    int broadcastIntent(IApplicationThread caller, Intent intent, String resolvedType,\n                        IIntentReceiver resultTo, int resultCode, String resultData, Bundle map,\n                        String[] requiredPermissions, int appOp, Bundle options, boolean serialized,\n                        boolean sticky, int userId) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.R)\n    int broadcastIntentWithFeature(IApplicationThread caller, String callingFeatureId,\n                                   Intent intent, String resolvedType, IIntentReceiver resultTo,\n                                   int resultCode, String resultData, Bundle map,\n                                   String[] requiredPermissions, int appOp, Bundle options,\n                                   boolean serialized, boolean sticky, int userId)\n            throws RemoteException;\n\n    void unbroadcastIntent(IApplicationThread caller, Intent intent, int userId) throws RemoteException;\n\n    void finishReceiver(IBinder who, int resultCode, String resultData, Bundle map, boolean abortBroadcast, int flags) throws RemoteException;\n\n    void attachApplication(IApplicationThread app, long startSeq) throws RemoteException;\n\n    List<ActivityManager.RunningTaskInfo> getTasks(int maxNum) throws RemoteException;\n\n    @RequiresApi(29)\n    android.app.ContentProviderHolder getContentProviderExternal(String name, int userId, IBinder token, String tag) throws RemoteException;\n\n    /**\n     * @deprecated Removed in Android Q\n     * @return {@link ContentProviderHolder} before Android O and {@link android.app.ContentProviderHolder} after Android O\n     */\n    @Deprecated\n    Object getContentProviderExternal(String name, int userId, IBinder token) throws RemoteException;\n\n    void removeContentProvider(IBinder connection, boolean stable) throws RemoteException;\n\n    void removeContentProviderExternal(String name, IBinder token) throws RemoteException;\n\n    /**\n     * @deprecated Removed in Android O.\n     */\n    @Deprecated\n    class ContentProviderHolder implements Parcelable {\n        public IContentProvider provider;\n\n        public static final Creator<ContentProviderHolder> CREATOR = HiddenUtil.creator();\n\n        @Override\n        public int describeContents() {\n            return HiddenUtil.throwUOE();\n        }\n\n        @Override\n        public void writeToParcel(Parcel dest, int flags) {\n            HiddenUtil.throwUOE(dest, flags);\n        }\n    }\n\n    /**\n     * @deprecated Removed in Android M\n     */\n    @Deprecated\n    ComponentName startService(IApplicationThread caller, Intent service, String resolvedType, int userId) throws RemoteException;\n\n    /**\n     * @deprecated Removed in Android O\n     */\n    @Deprecated\n    @RequiresApi(Build.VERSION_CODES.M)\n    ComponentName startService(IApplicationThread caller, Intent service, String resolvedType, String callingPackage, int userId) throws RemoteException;\n\n    /**\n     * @deprecated Removed in Android R\n     */\n    @Deprecated\n    @RequiresApi(Build.VERSION_CODES.O)\n    ComponentName startService(IApplicationThread caller, Intent service, String resolvedType, boolean requireForeground, String callingPackage, int userId) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.R)\n    ComponentName startService(IApplicationThread caller, Intent service, String resolvedType, boolean requireForeground, String callingPackage, String callingFeatureId, int userId) throws RemoteException;\n\n    int stopService(IApplicationThread caller, Intent service, String resolvedType, int userId) throws RemoteException;\n    // Currently keeping old bindService because it is on the greylist\n\n    int bindService(IApplicationThread caller, IBinder token, Intent service, String resolvedType, IServiceConnection connection, int flags, String callingPackage, int userId) throws RemoteException;\n\n    int bindIsolatedService(IApplicationThread caller, IBinder token, Intent service, String resolvedType, IServiceConnection connection, int flags, String instanceName, String callingPackage, int userId) throws RemoteException;\n\n    void updateServiceGroup(IServiceConnection connection, int group, int importance) throws RemoteException;\n\n    boolean unbindService(IServiceConnection connection) throws RemoteException;\n\n    void publishService(IBinder token, Intent intent, IBinder service) throws RemoteException;\n\n    void setDebugApp(String packageName, boolean waitForDebugger, boolean persistent) throws RemoteException;\n\n    void setAgentApp(String packageName, String agent) throws RemoteException;\n\n    void setAlwaysFinish(boolean enabled) throws RemoteException;\n\n    boolean stopServiceToken(ComponentName className, IBinder token, int startId) throws RemoteException;\n\n    void setProcessLimit(int max) throws RemoteException;\n\n    int getProcessLimit() throws RemoteException;\n\n    int checkPermission(String permission, int pid, int uid) throws RemoteException;\n\n    /**\n     * @deprecated Removed in Android LOLLIPOP_MR1.\n     */\n    @Deprecated\n    int checkUriPermission(Uri uri, int pid, int uid, int mode, int userId) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.LOLLIPOP_MR1)\n    int checkUriPermission(Uri uri, int pid, int uid, int mode, int userId, IBinder callerToken) throws RemoteException;\n\n    void grantUriPermission(IApplicationThread caller, String targetPkg, Uri uri, int mode, int userId) throws RemoteException;\n\n    /**\n     * @deprecated Removed in Android O.\n     */\n    @Deprecated\n    void revokeUriPermission(IApplicationThread caller, Uri uri, int mode, int userId) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.O)\n    void revokeUriPermission(IApplicationThread caller, String targetPkg, Uri uri, int mode, int userId) throws RemoteException;\n\n    /**\n     * Gets the URI permissions granted to an arbitrary package (or all packages if null)\n     * <p>\n     * NOTE: this is different from getPersistedUriPermissions(), which returns the URIs the package granted to another\n     * packages (instead of those granted to it).\n     * @return {@link UriPermission} before Android P and {@link GrantedUriPermission} from Android P\n     */\n    @RequiresApi(Build.VERSION_CODES.N)\n    ParceledListSlice<Parcelable> getGrantedUriPermissions(String packageName, int userId)\n            throws RemoteException;\n\n    // Clears the URI permissions granted to an arbitrary package.\n    @RequiresApi(Build.VERSION_CODES.N)\n    void clearGrantedUriPermissions(String packageName, int userId) throws RemoteException;\n\n    /**\n     * @deprecated Removed in Android Q.\n     */\n    @Deprecated\n    IBinder newUriPermissionOwner(String name) throws RemoteException;\n\n    /**\n     * @deprecated Removed in Android Q.\n     */\n    @Deprecated\n    @RequiresApi(Build.VERSION_CODES.N_MR1)\n    IBinder getUriPermissionOwnerForActivity(IBinder activityToken) throws RemoteException;\n\n    /**\n     * @deprecated Removed in Android Q.\n     */\n    @Deprecated\n    void grantUriPermissionFromOwner(IBinder owner, int fromUid, String targetPkg, Uri uri, int mode, int sourceUserId, int targetUserId) throws RemoteException;\n\n    /**\n     * @deprecated Removed in Android Q.\n     */\n    @Deprecated\n    void revokeUriPermissionFromOwner(IBinder owner, Uri uri, int mode, int userId) throws RemoteException;\n\n    /**\n     * @deprecated Removed in Android Q.\n     */\n    @Deprecated\n    int checkGrantUriPermission(int callingUid, String targetPkg, Uri uri, int modeFlags, int userId) throws RemoteException;\n\n    android.content.pm.ParceledListSlice getRecentTasks(int maxNum, int flags, int userId) throws RemoteException;\n\n    void serviceDoneExecuting(IBinder token, int type, int startId, int res) throws RemoteException;\n\n    /**\n     * @deprecated Use {@link #getIntentSenderWithFeature} instead\n     */\n    IIntentSender getIntentSender(int type, String packageName, IBinder token, String resultWho, int requestCode, Intent[] intents, String[] resolvedTypes, int flags, Bundle options, int userId) throws RemoteException;\n\n    IIntentSender getIntentSenderWithFeature(int type, String packageName, String featureId, IBinder token, String resultWho, int requestCode, Intent[] intents, String[] resolvedTypes, int flags, Bundle options, int userId) throws RemoteException;\n\n    void cancelIntentSender(IIntentSender sender) throws RemoteException;\n\n    String getPackageForIntentSender(IIntentSender sender) throws RemoteException;\n\n    void setProcessImportant(IBinder token, int pid, boolean isForeground, String reason) throws RemoteException;\n\n    void setServiceForeground(ComponentName className, IBinder token, int id, Notification notification, int flags, int foregroundServiceType) throws RemoteException;\n\n    int getForegroundServiceType(ComponentName className, IBinder token) throws RemoteException;\n\n    void getMemoryInfo(ActivityManager.MemoryInfo outInfo) throws RemoteException;\n\n    boolean clearApplicationUserData(String packageName, boolean keepState, IPackageDataObserver observer, int userId) throws RemoteException;\n\n    void forceStopPackage(String packageName, int userId) throws RemoteException;\n\n    boolean killPids(int[] pids, String reason, boolean secure) throws RemoteException;\n\n    List<ActivityManager.RunningServiceInfo> getServices(int maxNum, int flags) throws RemoteException;\n    // Retrieve running application processes in the system\n\n    List<ActivityManager.RunningAppProcessInfo> getRunningAppProcesses() throws RemoteException;\n\n    IBinder peekService(Intent service, String resolvedType, String callingPackage) throws RemoteException;\n    // Turn on/off profiling in a particular process.\n\n    boolean profileControl(String process, int userId, boolean start, ProfilerInfo profilerInfo, int profileType) throws RemoteException;\n\n    boolean shutdown(int timeout) throws RemoteException;\n\n    void stopAppSwitches() throws RemoteException;\n\n    void resumeAppSwitches() throws RemoteException;\n\n    boolean bindBackupAgent(String packageName, int backupRestoreMode, int targetUserId) throws RemoteException;\n\n    void backupAgentCreated(String packageName, IBinder agent, int userId) throws RemoteException;\n\n    void unbindBackupAgent(ApplicationInfo appInfo) throws RemoteException;\n\n    int getUidForIntentSender(IIntentSender sender) throws RemoteException;\n\n    int handleIncomingUser(int callingPid, int callingUid, int userId, boolean allowAll, boolean requireFull, String name, String callerPackage) throws RemoteException;\n\n    void addPackageDependency(String packageName) throws RemoteException;\n\n    void killApplication(String pkg, int appId, int userId, String reason) throws RemoteException;\n\n    void killApplicationProcess(String processName, int uid) throws RemoteException;\n    // Special low-level communication with activity manager.\n\n    void killBackgroundProcesses(String packageName, int userId) throws RemoteException;\n\n    boolean isUserAMonkey() throws RemoteException;\n    // Retrieve info of applications installed on external media that are currently\n    // running.\n\n    List<ApplicationInfo> getRunningExternalApplications() throws RemoteException;\n\n    void finishHeavyWeightApp() throws RemoteException;\n    // A StrictMode violation to be handled.\n\n    boolean isTopActivityImmersive() throws RemoteException;\n\n    void crashApplication(int uid, int initialPid, String packageName, int userId, String message, boolean force) throws RemoteException;\n\n    boolean isUserRunning(int userid, int flags) throws RemoteException;\n\n    void setPackageScreenCompatMode(String packageName, int mode) throws RemoteException;\n\n    boolean switchUser(int userid) throws RemoteException;\n\n    boolean removeTask(int taskId) throws RemoteException;\n\n    boolean isIntentSenderTargetedToPackage(IIntentSender sender) throws RemoteException;\n\n    long[] getProcessPss(int[] pids) throws RemoteException;\n\n    void showBootMessage(java.lang.CharSequence msg, boolean always) throws RemoteException;\n\n    void killAllBackgroundProcesses() throws RemoteException;\n\n    void getMyMemoryState(ActivityManager.RunningAppProcessInfo outInfo) throws RemoteException;\n\n    boolean killProcessesBelowForeground(String reason) throws RemoteException;\n\n    UserInfo getCurrentUser() throws RemoteException;\n    // This is not because you need to be very careful in how you\n    // manage your activity to make sure it is always the uid you expect.\n\n    int getLaunchedFromUid(IBinder activityToken) throws RemoteException;\n\n    void unstableProviderDied(IBinder connection) throws RemoteException;\n\n    boolean isIntentSenderAnActivity(IIntentSender sender) throws RemoteException;\n\n    boolean isIntentSenderAForegroundService(IIntentSender sender) throws RemoteException;\n\n    boolean isIntentSenderABroadcast(IIntentSender sender) throws RemoteException;\n\n    /**\n     * @deprecated Since Android 11. Use {@link #startActivityAsUserWithFeature} instead\n     */\n    int startActivityAsUser(IApplicationThread caller, String callingPackage, Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode, int flags, ProfilerInfo profilerInfo, Bundle options, int userId) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.R)\n    int startActivityAsUserWithFeature(IApplicationThread caller, String callingPackage, String callingFeatureId, Intent intent, String resolvedType, IBinder resultTo, String resultWho, int requestCode, int flags, ProfilerInfo profilerInfo, Bundle options, int userId) throws RemoteException;\n\n    int[] getRunningUserIds() throws RemoteException;\n\n    /**\n     * Takes a telephony bug report and notifies the user with the title and description\n     * that are passed to this API as parameters\n     *\n     * @param shareTitle       should be a valid legible string less than 50 chars long\n     * @param shareDescription should be less than 150 chars long\n     * @throws IllegalArgumentException if shareTitle or shareDescription is too big or if the\n     *                                  paremeters cannot be encoding to an UTF-8 charset.\n     */\n    void requestTelephonyBugReport(String shareTitle, String shareDescription) throws RemoteException;\n\n    /**\n     * This method is only used by Wifi.\n     * <p>\n     * Takes a minimal bugreport of Wifi-related state.\n     *\n     * @param shareTitle       should be a valid legible string less than 50 chars long\n     * @param shareDescription should be less than 150 chars long\n     * @throws IllegalArgumentException if shareTitle or shareDescription is too big or if the\n     *                                  parameters cannot be encoding to an UTF-8 charset.\n     */\n    void requestWifiBugReport(String shareTitle, String shareDescription) throws RemoteException;\n\n    void requestInteractiveBugReportWithDescription(String shareTitle, String shareDescription) throws RemoteException;\n\n    void requestInteractiveBugReport() throws RemoteException;\n\n    void requestFullBugReport() throws RemoteException;\n\n    void requestRemoteBugReport() throws RemoteException;\n\n    boolean launchBugReportHandlerApp() throws RemoteException;\n\n    List<String> getBugreportWhitelistedPackages() throws RemoteException;\n\n    Intent getIntentForIntentSender(IIntentSender sender) throws RemoteException;\n    // This is not because you need to be very careful in how you\n    // manage your activity to make sure it is always the uid you expect.\n\n    String getLaunchedFromPackage(IBinder activityToken) throws RemoteException;\n\n    void killUid(int appId, int userId, String reason) throws RemoteException;\n\n    void setUserIsMonkey(boolean monkey) throws RemoteException;\n\n    void hang(IBinder who, boolean allowRestart) throws RemoteException;\n\n    void restart() throws RemoteException;\n\n    void performIdleMaintenance() throws RemoteException;\n\n    void appNotRespondingViaProvider(IBinder connection) throws RemoteException;\n\n    boolean setProcessMemoryTrimLevel(String process, int uid, int level) throws RemoteException;\n    // Start of L transactions\n\n    String getTagForIntentSender(IIntentSender sender, String prefix) throws RemoteException;\n\n    boolean startUserInBackground(int userid) throws RemoteException;\n\n    boolean isInLockTaskMode() throws RemoteException;\n\n    void startSystemLockTaskMode(int taskId) throws RemoteException;\n\n    boolean isTopOfTask(IBinder token) throws RemoteException;\n\n    void bootAnimationComplete() throws RemoteException;\n\n    int checkPermissionWithToken(String permission, int pid, int uid, IBinder callerToken) throws RemoteException;\n\n    void notifyCleartextNetwork(int uid, byte[] firstPacket) throws RemoteException;\n\n    int getLockTaskModeState() throws RemoteException;\n\n    void setDumpHeapDebugLimit(String processName, int uid, long maxMemSize, String reportPackage) throws RemoteException;\n\n    void dumpHeapFinished(String path) throws RemoteException;\n\n    void updateLockTaskPackages(int userId, String[] packages) throws RemoteException;\n\n    int getPackageProcessState(String packageName, String callingPackage) throws RemoteException;\n\n    void updateDeviceOwner(String packageName) throws RemoteException;\n    // Start of N transactions\n    // Start Binder transaction tracking for all applications.\n\n    boolean startBinderTracking() throws RemoteException;\n    // Stop Binder transaction tracking for all applications and dump trace data to the given file\n    // descriptor.\n\n    boolean stopBinderTrackingAndDump(ParcelFileDescriptor fd) throws RemoteException;\n\n    /**\n     * Try to place task to provided position. The final position might be different depending on\n     * current user and stacks state. The task will be moved to target stack if it's currently in\n     * different stack.\n     */\n    void positionTaskInStack(int taskId, int stackId, int position) throws RemoteException;\n\n    void suppressResizeConfigChanges(boolean suppress) throws RemoteException;\n\n    boolean isAppStartModeDisabled(int uid, String packageName) throws RemoteException;\n\n    void killPackageDependents(String packageName, int userId) throws RemoteException;\n\n    void removeStack(int stackId) throws RemoteException;\n\n    void makePackageIdle(String packageName, int userId) throws RemoteException;\n\n    int getMemoryTrimLevel() throws RemoteException;\n\n    boolean isVrModePackageEnabled(ComponentName packageName) throws RemoteException;\n\n    void notifyLockedProfile(int userId) throws RemoteException;\n\n    void startConfirmDeviceCredentialIntent(Intent intent, Bundle options) throws RemoteException;\n\n    void sendIdleJobTrigger() throws RemoteException;\n\n    int sendIntentSender(IIntentSender target, IBinder whitelistToken, int code, Intent intent, String resolvedType, IIntentReceiver finishedReceiver, String requiredPermission, Bundle options) throws RemoteException;\n\n    boolean isBackgroundRestricted(String packageName) throws RemoteException;\n    // Start of N MR1 transactions\n\n    void setRenderThread(int tid) throws RemoteException;\n\n    /**\n     * Lets activity manager know whether the calling process is currently showing \"top-level\" UI\n     * that is not an activity, i.e. windows on the screen the user is currently interacting with.\n     *\n     * <p>This flag can only be set for persistent processes.\n     *\n     * @param hasTopUi Whether the calling process has \"top-level\" UI.\n     */\n    void setHasTopUi(boolean hasTopUi) throws RemoteException;\n    // Start of O transactions\n\n    int restartUserInBackground(int userId) throws RemoteException;\n\n    void scheduleApplicationInfoChanged(List<String> packageNames, int userId) throws RemoteException;\n\n    void setPersistentVrThread(int tid) throws RemoteException;\n\n    void waitForNetworkStateUpdate(long procStateSeq) throws RemoteException;\n\n    /**\n     * Add a bare uid to the background restrictions whitelist.  Only the system uid may call this.\n     */\n    void backgroundWhitelistUid(int uid) throws RemoteException;\n    // Start of P transactions\n\n    /**\n     * Method for the shell UID to start deletating its permission identity to an\n     * active instrumenation. The shell can delegate permissions only to one active\n     * instrumentation at a time. An active instrumentation is one running and\n     * started from the shell.\n     */\n    void startDelegateShellPermissionIdentity(int uid, String[] permissions) throws RemoteException;\n\n    /**\n     * Method for the shell UID to stop deletating its permission identity to an\n     * active instrumenation. An active instrumentation is one running and\n     * started from the shell.\n     */\n    void stopDelegateShellPermissionIdentity() throws RemoteException;\n\n    /**\n     * Returns a file descriptor that'll be closed when the system server process dies.\n     */\n    ParcelFileDescriptor getLifeMonitor() throws RemoteException;\n\n    /**\n     * Method for the app to tell system that it's wedged and would like to trigger an ANR.\n     */\n    void appNotResponding(String reason) throws RemoteException;\n\n    /**\n     * Return a list of {@link ApplicationExitInfo} records.\n     *\n     * <p class=\"note\"> Note: System stores these historical information in a ring buffer, older\n     * records would be overwritten by newer records. </p>\n     *\n     * <p class=\"note\"> Note: In the case that this application bound to an external service with\n     * flag {@link android.content.Context#BIND_EXTERNAL_SERVICE}, the process of that external\n     * service will be included in this package's exit info. </p>\n     *\n     * @param packageName Optional, an empty value means match all packages belonging to the\n     *                    caller's UID. If this package belongs to another UID, you must hold\n     *                    {@link android.Manifest.permission#DUMP} in order to retrieve it.\n     * @param pid         Optional, it could be a process ID that used to belong to this package but\n     *                    died later; A value of 0 means to ignore this parameter and return all\n     *                    matching records.\n     * @param maxNum      Optional, the maximum number of results should be returned; A value of 0\n     *                    means to ignore this parameter and return all matching records\n     * @param userId      The userId in the multi-user environment.\n     * @return a list of {@link ApplicationExitInfo} records with the matching criteria, sorted in\n     * the order from most recent to least recent.\n     */\n    ParceledListSlice<ApplicationExitInfo> getHistoricalProcessExitReasons(String packageName, int pid, int maxNum, int userId) throws RemoteException;\n\n    /*\n     * Kill the given PIDs, but the killing will be delayed until the device is idle\n     * and the given process is imperceptible.\n     */\n    void killProcessesWhenImperceptible(int[] pids, String reason) throws RemoteException;\n\n    /**\n     * Set custom state data for this process. It will be included in the record of\n     * {@link ApplicationExitInfo} on the death of the current calling process; the new process\n     * of the app can retrieve this state data by calling\n     * {@link ApplicationExitInfo#getProcessStateSummary} on the record returned by\n     * {@link #getHistoricalProcessExitReasons}.\n     *\n     * <p> This would be useful for the calling app to save its stateful data: if it's\n     * killed later for any reason, the new process of the app can know what the\n     * previous process of the app was doing. For instance, you could use this to encode\n     * the current level in a game, or a set of features/experiments that were enabled. Later you\n     * could analyze under what circumstances the app tends to crash or use too much memory.\n     * However, it's not suggested to rely on this to restore the applications previous UI state\n     * or so, it's only meant for analyzing application healthy status.</p>\n     *\n     * <p> System might decide to throttle the calls to this API; so call this API in a reasonable\n     * manner, excessive calls to this API could result a {@link java.lang.RuntimeException}.\n     * </p>\n     *\n     * @param state The customized state data\n     */\n    void setProcessStateSummary(byte[] state) throws RemoteException;\n\n    /**\n     * Return whether the app freezer is supported (true) or not (false) by this system.\n     */\n    boolean isAppFreezerSupported() throws RemoteException;\n\n    /**\n     * Kills uid with the reason of permission change.\n     */\n    void killUidForPermissionChange(int appId, int userId, String reason) throws RemoteException;\n\n    /**\n     * Control the app freezer state. Returns true in case of success, false if the operation\n     * didn't succeed (for example, when the app freezer isn't supported).\n     * Handling the freezer state via this method is reentrant, that is it can be\n     * disabled and re-enabled multiple times in parallel. As long as there's a 1:1 disable to\n     * enable match, the freezer is re-enabled at last enable only.\n     *\n     * @param enable set it to true to enable the app freezer, false to disable it.\n     */\n    boolean enableAppFreezer(boolean enable) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.O)\n    abstract class Stub extends Binder implements IActivityManager {\n        public static IActivityManager asInterface(IBinder obj) {\n            throw new UnsupportedOperationException();\n        }\n\n        @Override\n        public IBinder asBinder() {\n            return this;\n        }\n    }\n}"
  },
  {
    "path": "hiddenapi/src/main/java/android/app/IApplicationThread.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage android.app;\n\nimport android.os.IBinder;\n\n/**\n * System private API for communicating with the application.  This is given to\n * the activity manager by an application  when it starts up, for the activity\n * manager to tell the application about things it needs to do.\n */\npublic interface IApplicationThread extends android.os.IInterface {\n    abstract class Stub extends android.os.Binder implements android.app.IApplicationThread {\n        public static android.app.IApplicationThread asInterface(IBinder obj) {\n            throw new UnsupportedOperationException();\n        }\n\n        @Override\n        public IBinder asBinder() {\n            return this;\n        }\n    }\n}"
  },
  {
    "path": "hiddenapi/src/main/java/android/app/INotificationManager.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage android.app;\n\nimport android.content.ComponentName;\nimport android.os.Binder;\nimport android.os.Build;\nimport android.os.IBinder;\nimport android.os.IInterface;\nimport android.os.RemoteException;\nimport android.service.notification.StatusBarNotification;\n\nimport androidx.annotation.RequiresApi;\n\nimport java.util.List;\n\npublic interface INotificationManager extends IInterface {\n    abstract class Stub extends Binder implements INotificationManager {\n        public static INotificationManager asInterface(IBinder obj) {\n            throw new UnsupportedOperationException();\n        }\n\n        @Override\n        public IBinder asBinder() {\n            return this;\n        }\n    }\n\n    void setNotificationsEnabledForPackage(String pkg, int uid, boolean enabled) throws RemoteException;\n\n    // Added because there's no public API to get these notifications\n    StatusBarNotification[] getActiveNotifications(String callingPkg) throws RemoteException;\n\n    /**\n     * Updates the notification's enabled state. Additionally locks importance for all of the\n     * notifications belonging to the app, such that future notifications aren't reconsidered for\n     * blocking helper.\n     */\n    @RequiresApi(Build.VERSION_CODES.P)\n    void setNotificationsEnabledWithImportanceLockForPackage(String pkg, int uid, boolean enabled) throws RemoteException;\n\n    boolean areNotificationsEnabledForPackage(String pkg, int uid) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.N)\n    boolean areNotificationsEnabled(String pkg) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.N)\n    int getPackageImportance(String pkg) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.O_MR1)\n    boolean isNotificationListenerAccessGranted(ComponentName listener) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.O_MR1)\n    boolean isNotificationListenerAccessGrantedForUser(ComponentName listener, int userId) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.O_MR1)\n    boolean isNotificationAssistantAccessGranted(ComponentName assistant) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.O_MR1)\n    void setNotificationListenerAccessGranted(ComponentName listener, boolean enabled) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.O_MR1)\n    void setNotificationAssistantAccessGranted(ComponentName assistant, boolean enabled) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.O_MR1)\n    void setNotificationListenerAccessGrantedForUser(ComponentName listener, int userId, boolean enabled) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.O_MR1)\n    void setNotificationAssistantAccessGrantedForUser(ComponentName assistant, int userId, boolean enabled) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.O_MR1)\n    List<String> getEnabledNotificationListenerPackages() throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.O_MR1)\n    List<ComponentName> getEnabledNotificationListeners(int userId) throws RemoteException;\n}"
  },
  {
    "path": "hiddenapi/src/main/java/android/app/IServiceConnection.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage android.app;\n\nimport android.content.ComponentName;\nimport android.os.Binder;\nimport android.os.IBinder;\nimport android.os.IInterface;\nimport android.os.RemoteException;\n\npublic interface IServiceConnection extends IInterface {\n    abstract class Stub extends Binder implements IServiceConnection {\n        public static IServiceConnection asInterface(IBinder obj) {\n            throw new UnsupportedOperationException();\n        }\n\n        @Override\n        public IBinder asBinder() {\n            return this;\n        }\n\n    }\n\n    void connected(ComponentName name, IBinder service, boolean dead) throws RemoteException;\n}"
  },
  {
    "path": "hiddenapi/src/main/java/android/app/IUriGrantsManager.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage android.app;\n\nimport android.content.UriPermission;\nimport android.content.pm.ParceledListSlice;\nimport android.net.Uri;\nimport android.os.Binder;\nimport android.os.Build;\nimport android.os.IBinder;\nimport android.os.RemoteException;\n\nimport androidx.annotation.RequiresApi;\n\nimport misc.utils.HiddenUtil;\n\n/**\n * Interface for managing an app's permission to access a particular URI.\n */\n@RequiresApi(Build.VERSION_CODES.Q)\npublic interface IUriGrantsManager extends android.os.IInterface {\n    void takePersistableUriPermission(Uri uri, int modeFlags, String toPackage, int userId) throws RemoteException;\n\n    void releasePersistableUriPermission(Uri uri, int modeFlags, String toPackage, int userId) throws RemoteException;\n\n    void grantUriPermissionFromOwner(IBinder owner, int fromUid, String targetPkg, Uri uri, int mode, int sourceUserId, int targetUserId) throws RemoteException;\n\n    /**\n     * Gets the URI permissions granted to an arbitrary package (or all packages if null)\n     * <p>\n     * NOTE: this is different from {@link #getUriPermissions(String, boolean, boolean)}, which returns the URIs the\n     * package granted to another packages (instead of those granted to it).\n     */\n    ParceledListSlice<GrantedUriPermission> getGrantedUriPermissions(String packageName, int userId) throws RemoteException;\n\n    /**\n     * Clears the URI permissions granted to an arbitrary package.\n     */\n    void clearGrantedUriPermissions(String packageName, int userId) throws RemoteException;\n\n    ParceledListSlice<UriPermission> getUriPermissions(String packageName, boolean incoming, boolean persistedOnly) throws RemoteException;\n\n    abstract class Stub extends Binder implements IUriGrantsManager {\n        public static IUriGrantsManager asInterface(IBinder obj) {\n            return HiddenUtil.throwUOE(obj);\n        }\n\n        @Override\n        public IBinder asBinder() {\n            return this;\n        }\n    }\n}"
  },
  {
    "path": "hiddenapi/src/main/java/android/app/ProfilerInfo.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage android.app;\n\nimport android.os.Parcel;\nimport android.os.ParcelFileDescriptor;\nimport android.os.Parcelable;\n\nimport misc.utils.HiddenUtil;\n\n/**\n * System private API for passing profiler settings.\n */\npublic class ProfilerInfo implements Parcelable {\n\n    private static final String TAG = \"ProfilerInfo\";\n\n    /* Name of profile output file. */\n    public final String profileFile;\n\n    /* File descriptor for profile output file, can be null. */\n    public ParcelFileDescriptor profileFd;\n\n    /* Indicates sample profiling when nonzero, interval in microseconds. */\n    public final int samplingInterval;\n\n    /* Automatically stop the profiler when the app goes idle. */\n    public final boolean autoStopProfiler;\n\n    /*\n     * Indicates whether to stream the profiling info to the out file continuously.\n     */\n    public final boolean streamingOutput;\n\n    /**\n     * Denotes an agent (and its parameters) to attach for profiling.\n     */\n    public final String agent;\n\n    /**\n     * Whether the {@link #agent} should be attached early (before bind-application) or during\n     * bind-application. Agents attached prior to binding cannot be loaded from the app's APK\n     * directly and must be given as an absolute path (or available in the default LD_LIBRARY_PATH).\n     * Agents attached during bind-application will miss early setup (e.g., resource initialization\n     * and classloader generation), but are searched in the app's library search path.\n     */\n    public final boolean attachAgentDuringBind;\n\n    public ProfilerInfo(String filename, ParcelFileDescriptor fd, int interval, boolean autoStop,\n            boolean streaming, String agent, boolean attachAgentDuringBind) {\n        HiddenUtil.throwUOE(filename, fd, interval, autoStop, streaming, agent, attachAgentDuringBind);\n        throw new UnsupportedOperationException();\n    }\n\n    /**\n     * Return a new ProfilerInfo instance, with fields populated from this object,\n     * and {@link #agent} and {@link #attachAgentDuringBind} as given.\n     */\n    public ProfilerInfo setAgent(String agent, boolean attachAgentDuringBind) {\n        return HiddenUtil.throwUOE(agent, attachAgentDuringBind);\n    }\n\n    /**\n     * Close profileFd, if it is open. The field will be null after a call to this function.\n     */\n    public void closeFd() {\n        HiddenUtil.throwUOE();\n    }\n\n    public static final Creator<ProfilerInfo> CREATOR = HiddenUtil.creator();\n\n    @Override\n    public int describeContents() {\n        return HiddenUtil.throwUOE();\n    }\n\n    @Override\n    public void writeToParcel(Parcel dest, int flags) {\n        HiddenUtil.throwUOE(dest, flags);\n    }\n}"
  },
  {
    "path": "hiddenapi/src/main/java/android/app/backup/IBackupManager.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage android.app.backup;\n\nimport android.os.Binder;\nimport android.os.Build;\nimport android.os.IBinder;\nimport android.os.IInterface;\nimport android.os.ParcelFileDescriptor;\nimport android.os.RemoteException;\n\nimport androidx.annotation.RequiresApi;\n\n/**\n * Direct interface to the Backup Manager Service that applications invoke on.  The only\n * operation currently needed is a simple notification that the app has made changes to\n * data it wishes to back up, so the system should run a backup pass.\n * <p>\n * Apps will use the {@link android.app.backup.BackupManager} class rather than going through\n * this Binder interface directly.\n */\n@SuppressWarnings(\"DeprecatedIsStillUsed\")\npublic interface IBackupManager extends IInterface {\n    abstract class Stub extends Binder implements IBackupManager {\n        public static IBackupManager asInterface(IBinder binder) {\n            throw new UnsupportedOperationException();\n        }\n    }\n\n    /**\n     * Enable/disable the backup service entirely.  When disabled, no backup\n     * or restore operations will take place.  Data-changed notifications will\n     * still be observed and collected, however, so that changes made while the\n     * mechanism was disabled will still be backed up properly if it is enabled\n     * at some point in the future.\n     *\n     * <p>Callers must hold the android.permission.BACKUP permission to use this method.\n     * If {@code userId} is different from the calling user id, then the caller must hold the\n     * android.permission.INTERACT_ACROSS_USERS_FULL permission.\n     *\n     * @param userId User id for which backup service should be enabled/disabled.\n     */\n    @RequiresApi(Build.VERSION_CODES.Q)\n    void setBackupEnabledForUser(int userId, boolean isEnabled) throws RemoteException;\n\n    /**\n     * Enable/disable the backup service entirely.  When disabled, no backup\n     * or restore operations will take place.  Data-changed notifications will\n     * still be observed and collected, however, so that changes made while the\n     * mechanism was disabled will still be backed up properly if it is enabled\n     * at some point in the future.\n     * <p>\n     * Callers must hold the android.permission.BACKUP permission to use this method.\n     */\n    void setBackupEnabled(boolean isEnabled) throws RemoteException;\n\n    /**\n     * Report whether the backup mechanism is currently enabled.\n     *\n     * <p>Callers must hold the android.permission.BACKUP permission to use this method.\n     * If {@code userId} is different from the calling user id, then the caller must hold the\n     * android.permission.INTERACT_ACROSS_USERS_FULL permission.\n     *\n     * @param userId User id for which the backup service status should be reported.\n     */\n    @RequiresApi(Build.VERSION_CODES.Q)\n    boolean isBackupEnabledForUser(int userId) throws RemoteException;\n\n    /**\n     * Report whether the backup mechanism is currently enabled.\n     *\n     * <p>Callers must hold the android.permission.BACKUP permission to use this method.\n     */\n    boolean isBackupEnabled() throws RemoteException;\n\n    /**\n     * Set the device's backup password.  Returns {@code true} if the password was set\n     * successfully, {@code false} otherwise.  Typically a failure means that an incorrect\n     * current password was supplied.\n     *\n     * <p>Callers must hold the android.permission.BACKUP permission to use this method.\n     */\n    boolean setBackupPassword(String currentPw, String newPw) throws RemoteException;\n\n    /**\n     * Reports whether a backup password is currently set.  If not, then a null or empty\n     * \"current password\" argument should be passed to setBackupPassword().\n     *\n     * <p>Callers must hold the android.permission.BACKUP permission to use this method.\n     */\n    boolean hasBackupPassword() throws RemoteException;\n\n    /**\n     * Write a full backup of the given package to the supplied file descriptor.\n     * The fd may be a socket or other non-seekable destination.  If no package names\n     * are supplied, then every application on the device will be backed up to the output.\n     *\n     * <p>This method is <i>synchronous</i> -- it does not return until the backup has\n     * completed.\n     *\n     * <p>Callers must hold the android.permission.BACKUP permission to use this method.\n     *\n     * @param fd                The file descriptor to which a 'tar' file stream is to be written\n     * @param includeApks       If <code>true</code>, the resulting tar stream will include the\n     *                          application .apk files themselves as well as their data.\n     * @param includeObbs       If <code>true</code>, the resulting tar stream will include any\n     *                          application expansion (OBB) files themselves belonging to each application.\n     * @param includeShared     If <code>true</code>, the resulting tar stream will include\n     *                          the contents of the device's shared storage (SD card or equivalent).\n     * @param allApps           If <code>true</code>, the resulting tar stream will include all\n     *                          installed applications' data, not just those named in the <code>packageNames</code>\n     *                          parameter.\n     * @param allIncludesSystem If {@code true}, then {@code allApps} will be interpreted\n     *                          as including packages pre-installed as part of the system. If {@code false},\n     *                          then setting {@code allApps} to {@code true} will mean only that all 3rd-party\n     *                          applications will be included in the dataset.\n     * @param packageNames      The package names of the apps whose data (and optionally .apk files)\n     *                          are to be backed up.  The <code>allApps</code> parameter supersedes this.\n     * @deprecated Replaced by {@link #adbBackup(ParcelFileDescriptor, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, String[])} in API 26 (Android O)\n     */\n    @Deprecated\n    void fullBackup(ParcelFileDescriptor fd, boolean includeApks, boolean includeObbs,\n                    boolean includeShared, boolean doWidgets, boolean allApps, boolean allIncludesSystem,\n                    boolean doCompress, String[] packageNames) throws RemoteException;\n\n    /**\n     * Write a backup of the given package to the supplied file descriptor.\n     * The fd may be a socket or other non-seekable destination.  If no package names\n     * are supplied, then every application on the device will be backed up to the output.\n     * Currently only used by the 'adb backup' command.\n     *\n     * <p>This method is <i>synchronous</i> -- it does not return until the backup has\n     * completed.\n     *\n     * <p>Callers must hold the android.permission.BACKUP permission to use this method.\n     *\n     * @param fd                The file descriptor to which a 'tar' file stream is to be written\n     * @param includeApks       If <code>true</code>, the resulting tar stream will include the\n     *                          application .apk files themselves as well as their data.\n     * @param includeObbs       If <code>true</code>, the resulting tar stream will include any\n     *                          application expansion (OBB) files themselves belonging to each application.\n     * @param includeShared     If <code>true</code>, the resulting tar stream will include\n     *                          the contents of the device's shared storage (SD card or equivalent).\n     * @param allApps           If <code>true</code>, the resulting tar stream will include all\n     *                          installed applications' data, not just those named in the <code>packageNames</code>\n     *                          parameter.\n     * @param allIncludesSystem If {@code true}, then {@code allApps} will be interpreted\n     *                          as including packages pre-installed as part of the system. If {@code false},\n     *                          then setting {@code allApps} to {@code true} will mean only that all 3rd-party\n     *                          applications will be included in the dataset.\n     * @param doKeyValue        If {@code true}, also packages supporting key-value backup will be backed\n     *                          up. If {@code false}, key-value packages will be skipped.\n     * @param packageNames      The package names of the apps whose data (and optionally .apk files)\n     *                          are to be backed up.  The <code>allApps</code> parameter supersedes this.\n     * @deprecated Replaced by {@link #adbBackup(int, ParcelFileDescriptor, boolean, boolean, boolean, boolean, boolean, boolean, boolean, boolean, String[])} in API 29 (Android 10)\n     */\n    @Deprecated\n    @RequiresApi(Build.VERSION_CODES.O)\n    void adbBackup(ParcelFileDescriptor fd, boolean includeApks, boolean includeObbs,\n                   boolean includeShared, boolean doWidgets, boolean allApps, boolean allIncludesSystem,\n                   boolean doCompress, boolean doKeyValue, String[] packageNames) throws RemoteException;\n\n    /**\n     * Write a backup of the given package to the supplied file descriptor.\n     * The fd may be a socket or other non-seekable destination.  If no package names\n     * are supplied, then every application on the device will be backed up to the output.\n     * Currently only used by the 'adb backup' command.\n     *\n     * <p>This method is <i>synchronous</i> -- it does not return until the backup has\n     * completed.\n     *\n     * <p>Callers must hold the android.permission.BACKUP permission to use this method.\n     * If the {@code userId} is different from the calling user id, then the caller must hold the\n     * android.permission.INTERACT_ACROSS_USERS_FULL permission.\n     *\n     * @param userId            User id for which backup should be performed.\n     * @param fd                The file descriptor to which a 'tar' file stream is to be written.\n     * @param includeApks       If <code>true</code>, the resulting tar stream will include the\n     *                          application .apk files themselves as well as their data.\n     * @param includeObbs       If <code>true</code>, the resulting tar stream will include any\n     *                          application expansion (OBB) files themselves belonging to each application.\n     * @param includeShared     If <code>true</code>, the resulting tar stream will include\n     *                          the contents of the device's shared storage (SD card or equivalent).\n     * @param allApps           If <code>true</code>, the resulting tar stream will include all\n     *                          installed applications' data, not just those named in the <code>packageNames</code>\n     *                          parameter.\n     * @param allIncludesSystem If {@code true}, then {@code allApps} will be interpreted\n     *                          as including packages pre-installed as part of the system. If {@code false},\n     *                          then setting {@code allApps} to {@code true} will mean only that all 3rd-party\n     *                          applications will be included in the dataset.\n     * @param doKeyValue        If {@code true}, also packages supporting key-value backup will be backed\n     *                          up. If {@code false}, key-value packages will be skipped.\n     * @param packageNames      The package names of the apps whose data (and optionally .apk files)\n     *                          are to be backed up.  The <code>allApps</code> parameter supersedes this.\n     */\n    @RequiresApi(Build.VERSION_CODES.Q)\n    void adbBackup(int userId, ParcelFileDescriptor fd, boolean includeApks, boolean includeObbs,\n                   boolean includeShared, boolean doWidgets, boolean allApps, boolean allIncludesSystem,\n                   boolean doCompress, boolean doKeyValue, String[] packageNames) throws RemoteException;\n\n    /**\n     * Restore device content from the data stream passed through the given socket.  The\n     * data stream must be in the format emitted by fullBackup().\n     *\n     * <p>Callers must hold the android.permission.BACKUP permission to use this method.\n     *\n     * @deprecated Replaced by {@link #adbRestore(ParcelFileDescriptor)} in API 26 (Android O)\n     */\n    void fullRestore(ParcelFileDescriptor fd) throws RemoteException;\n\n    /**\n     * Restore device content from the data stream passed through the given socket.  The\n     * data stream must be in the format emitted by adbBackup().\n     * Currently only used by the 'adb restore' command.\n     *\n     * <p>Callers must hold the android.permission.BACKUP permission to use this method.\n     *\n     * @deprecated Replaced by {@link #adbRestore(int, ParcelFileDescriptor)} in API 29 (Android 10)\n     */\n    @Deprecated\n    @RequiresApi(Build.VERSION_CODES.O)\n    void adbRestore(ParcelFileDescriptor fd) throws RemoteException;\n\n    /**\n     * Restore device content from the data stream passed through the given socket.  The\n     * data stream must be in the format emitted by adbBackup().\n     * Currently only used by the 'adb restore' command.\n     *\n     * <p>Callers must hold the android.permission.BACKUP permission to use this method.\n     * If the {@code userId} is different from the calling user id, then the caller must hold the\n     * android.permission.INTERACT_ACROSS_USERS_FULL.\n     *\n     * @param userId User id for which restore should be performed.\n     */\n    @RequiresApi(Build.VERSION_CODES.Q)\n    void adbRestore(int userId, ParcelFileDescriptor fd) throws RemoteException;\n\n    /**\n     * Make the device's backup and restore machinery (in)active.  When it is inactive,\n     * the device will not perform any backup operations, nor will it deliver data for\n     * restore, although clients can still safely call BackupManager methods.\n     *\n     * @param whichUser  User handle of the defined user whose backup active state\n     *                   is to be adjusted.\n     * @param makeActive {@code true} when backup services are to be made active;\n     *                   {@code false} otherwise.\n     */\n    @RequiresApi(Build.VERSION_CODES.M)\n    void setBackupServiceActive(int whichUser, boolean makeActive) throws RemoteException;\n\n    /**\n     * Queries the activity status of backup service as set by {@link #setBackupServiceActive}.\n     *\n     * @param whichUser User handle of the defined user whose backup active state\n     *                  is being queried.\n     */\n    @RequiresApi(Build.VERSION_CODES.M)\n    boolean isBackupServiceActive(int whichUser) throws RemoteException;\n\n    /**\n     * Checks if the user is ready for backup or not.\n     *\n     * @param userId User id for which this operation should be performed.\n     */\n    @RequiresApi(Build.VERSION_CODES.R)\n    boolean isUserReadyForBackup(int userId) throws RemoteException;\n\n    /**\n     * Ask the framework whether this app is eligible for backup.\n     *\n     * <p>Callers must hold the android.permission.BACKUP permission to use this method.\n     *\n     * @param packageName The name of the package.\n     * @return Whether this app is eligible for backup.\n     * @deprecated Replaced by {@link #isAppEligibleForBackupForUser(int, String)} in API 29 (Android 10)\n     */\n    @Deprecated\n    @RequiresApi(Build.VERSION_CODES.N)\n    boolean isAppEligibleForBackup(String packageName) throws RemoteException;\n\n    /**\n     * Ask the framework whether this app is eligible for backup.\n     *\n     * <p>If you are calling this method multiple times, you should instead use\n     * {@link #filterAppsEligibleForBackup(String[])} to save resources.\n     *\n     * <p>Callers must hold the android.permission.BACKUP permission to use this method.\n     * If {@code userId} is different from the calling user id, then the caller must hold the\n     * android.permission.INTERACT_ACROSS_USERS_FULL permission.\n     *\n     * @param userId      User id for which this operation should be performed.\n     * @param packageName The name of the package.\n     * @return Whether this app is eligible for backup.\n     */\n    @RequiresApi(Build.VERSION_CODES.Q)\n    boolean isAppEligibleForBackupForUser(int userId, String packageName) throws RemoteException;\n\n    /**\n     * Filter the packages that are eligible for backup and return the result.\n     *\n     * <p>Callers must hold the android.permission.BACKUP permission to use this method.\n     *\n     * @param packages The list of packages to filter.\n     * @return The packages eligible for backup.\n     * @deprecated Replaced by {@link #filterAppsEligibleForBackupForUser(int, String[])} in API 29 (Android 10)\n     */\n    @Deprecated\n    @RequiresApi(Build.VERSION_CODES.P)\n    String[] filterAppsEligibleForBackup(String[] packages) throws RemoteException;\n\n    /**\n     * Filter the packages that are eligible for backup and return the result.\n     *\n     * <p>Callers must hold the android.permission.BACKUP permission to use this method.\n     * If {@code userId} is different from the calling user id, then the caller must hold the\n     * android.permission.INTERACT_ACROSS_USERS_FULL permission.\n     *\n     * @param userId   User id for which the filter should be performed.\n     * @param packages The list of packages to filter.\n     * @return The packages eligible for backup.\n     */\n    @RequiresApi(Build.VERSION_CODES.Q)\n    String[] filterAppsEligibleForBackupForUser(int userId, String[] packages) throws RemoteException;\n}"
  },
  {
    "path": "hiddenapi/src/main/java/android/app/usage/IStorageStatsManager.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage android.app.usage;\n\nimport android.content.pm.ParceledListSlice;\nimport android.os.Binder;\nimport android.os.Build;\nimport android.os.IBinder;\nimport android.os.IInterface;\nimport android.os.RemoteException;\n\nimport androidx.annotation.RequiresApi;\n\n@RequiresApi(Build.VERSION_CODES.O)\npublic interface IStorageStatsManager extends IInterface {\n    abstract class Stub extends Binder implements IStorageStatsManager {\n        public Stub() {\n        }\n\n        public static IStorageStatsManager asInterface(IBinder obj) {\n            throw new UnsupportedOperationException();\n        }\n\n        @Override\n        public IBinder asBinder() {\n            return this;\n        }\n    }\n\n    boolean isQuotaSupported(String volumeUuid, String callingPackage) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.P)\n    boolean isReservedSupported(String volumeUuid, String callingPackage) throws RemoteException;\n\n    long getTotalBytes(String volumeUuid, String callingPackage) throws RemoteException;\n\n    long getFreeBytes(String volumeUuid, String callingPackage) throws RemoteException;\n\n    long getCacheBytes(String volumeUuid, String callingPackage) throws RemoteException;\n\n    long getCacheQuotaBytes(String volumeUuid, int uid, String callingPackage) throws RemoteException;\n\n    StorageStats queryStatsForPackage(String volumeUuid, String packageName, int userId, String callingPackage) throws RemoteException;\n\n    StorageStats queryStatsForUid(String volumeUuid, int uid, String callingPackage) throws RemoteException;\n\n    StorageStats queryStatsForUser(String volumeUuid, int userId, String callingPackage) throws RemoteException;\n\n    ExternalStorageStats queryExternalStatsForUser(String volumeUuid, int userId, String callingPackage) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.R)\n    ParceledListSlice queryCratesForPackage(String volumeUuid, String packageName, int userId, String callingPackage) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.R)\n    ParceledListSlice queryCratesForUid(String volumeUuid, int uid, String callingPackage) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.R)\n    ParceledListSlice queryCratesForUser(String volumeUuid, int userId, String callingPackage) throws RemoteException;\n}"
  },
  {
    "path": "hiddenapi/src/main/java/android/app/usage/IUsageStatsManager.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage android.app.usage;\n\nimport android.app.PendingIntent;\nimport android.content.pm.ParceledListSlice;\nimport android.os.Binder;\nimport android.os.Build;\nimport android.os.IBinder;\nimport android.os.IInterface;\nimport android.os.RemoteException;\n\nimport androidx.annotation.RequiresApi;\n\nimport misc.utils.HiddenUtil;\n\npublic interface IUsageStatsManager extends IInterface {\n    abstract class Stub extends Binder implements IUsageStatsManager {\n        public Stub() {\n        }\n\n        public static IUsageStatsManager asInterface(IBinder obj) {\n            return HiddenUtil.throwUOE(obj);\n        }\n\n        @Override\n        public IBinder asBinder() {\n            return this;\n        }\n    }\n\n    ParceledListSlice queryUsageStats(int bucketType, long beginTime, long endTime, String callingPackage)\n            throws RemoteException;\n\n    ParceledListSlice queryConfigurationStats(int bucketType, long beginTime, long endTime, String callingPackage)\n            throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.P)\n    ParceledListSlice queryEventStats(int bucketType, long beginTime, long endTime, String callingPackage)\n            throws RemoteException;\n\n    UsageEvents queryEvents(long beginTime, long endTime, String callingPackage) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.P)\n    UsageEvents queryEventsForPackage(long beginTime, long endTime, String callingPackage) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.P)\n    UsageEvents queryEventsForUser(long beginTime, long endTime, int userId, String callingPackage)\n            throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.P)\n    UsageEvents queryEventsForPackageForUser(long beginTime, long endTime, int userId, String pkg,\n                                             String callingPackage) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.M)\n    void setAppInactive(String packageName, boolean inactive, int userId) throws RemoteException;\n\n    /**\n     * @deprecated Replaced in API 30 (Android R) by {@link #isAppInactive(String, int, String)}\n     */\n    @RequiresApi(Build.VERSION_CODES.M)\n    @Deprecated\n    boolean isAppInactive(String packageName, int userId) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.R)\n    boolean isAppInactive(String packageName, int userId, String callingPackage) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.M)\n    void whitelistAppTemporarily(String packageName, long duration, int userId) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.N)\n    void onCarrierPrivilegedAppsChanged() throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.O)\n    void reportChooserSelection(String packageName, int userId, String contentType, String[] annotations, String action)\n            throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.P)\n    int getAppStandbyBucket(String packageName, String callingPackage, int userId) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.P)\n    void setAppStandbyBucket(String packageName, int bucket, int userId) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.P)\n    ParceledListSlice getAppStandbyBuckets(String callingPackage, int userId) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.P)\n    void setAppStandbyBuckets(ParceledListSlice appBuckets, int userId) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.P)\n    void registerAppUsageObserver(int observerId, String[] packages, long timeLimitMs, PendingIntent callback,\n                                  String callingPackage) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.P)\n    void unregisterAppUsageObserver(int observerId, String callingPackage) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.Q)\n    void registerUsageSessionObserver(int sessionObserverId, String[] observed, long timeLimitMs,\n                                      long sessionThresholdTimeMs, PendingIntent limitReachedCallbackIntent,\n                                      PendingIntent sessionEndCallbackIntent, String callingPackage)\n            throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.Q)\n    void unregisterUsageSessionObserver(int sessionObserverId, String callingPackage) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.Q)\n    void registerAppUsageLimitObserver(int observerId, String[] packages, long timeLimitMs, long timeUsedMs,\n                                       PendingIntent callback, String callingPackage) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.Q)\n    void unregisterAppUsageLimitObserver(int observerId, String callingPackage) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.Q)\n    void reportUsageStart(IBinder activity, String token, String callingPackage) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.Q)\n    void reportPastUsageStart(IBinder activity, String token, long timeAgoMs, String callingPackage)\n            throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.Q)\n    void reportUsageStop(IBinder activity, String token, String callingPackage) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.Q)\n    int getUsageSource() throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.Q)\n    void forceUsageSourceSettingRead() throws RemoteException;\n}\n"
  },
  {
    "path": "hiddenapi/src/main/java/android/content/ComponentCallbacks2.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage android.content;\n\npublic interface ComponentCallbacks2 {\n}"
  },
  {
    "path": "hiddenapi/src/main/java/android/content/Context.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage android.content;\n\nimport android.content.pm.PackageManager;\nimport android.os.UserHandle;\n\nimport misc.utils.HiddenUtil;\n\npublic class Context {\n    public Context createPackageContextAsUser(String packageName, int flags, UserHandle user)\n            throws PackageManager.NameNotFoundException {\n        return HiddenUtil.throwUOE();\n    }\n}\n"
  },
  {
    "path": "hiddenapi/src/main/java/android/content/IContentProvider.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage android.content;\n\nimport android.os.IInterface;\n\npublic interface IContentProvider extends IInterface {\n}"
  },
  {
    "path": "hiddenapi/src/main/java/android/content/IIntentReceiver.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage android.content;\n\nimport android.os.Binder;\nimport android.os.Bundle;\nimport android.os.IBinder;\nimport android.os.IInterface;\n\npublic interface IIntentReceiver extends IInterface {\n\n    void performReceive(Intent intent, int resultCode, String data, Bundle extras, boolean ordered,\n                        boolean sticky, int sendingUser);\n\n    abstract class Stub extends Binder implements IIntentReceiver {\n        public static IIntentReceiver asInterface(android.os.IBinder obj) {\n            throw new UnsupportedOperationException();\n        }\n\n        @Override\n        public IBinder asBinder() {\n            return this;\n        }\n    }\n}"
  },
  {
    "path": "hiddenapi/src/main/java/android/content/IIntentSender.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage android.content;\n\nimport android.os.Binder;\nimport android.os.Build;\nimport android.os.Bundle;\nimport android.os.IBinder;\nimport android.os.IInterface;\nimport android.os.RemoteException;\n\nimport androidx.annotation.RequiresApi;\n\npublic interface IIntentSender extends IInterface {\n\n    int send(int code, Intent intent, String resolvedType,\n             IIntentReceiver finishedReceiver, String requiredPermission) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.M)\n    int send(int code, Intent intent, String resolvedType,\n             IIntentReceiver finishedReceiver, String requiredPermission, Bundle options) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.O)\n    void send(int code, Intent intent, String resolvedType, IBinder whitelistToken,\n              IIntentReceiver finishedReceiver, String requiredPermission, Bundle options) throws RemoteException;\n\n    abstract class Stub extends Binder implements IIntentSender {\n        public static IIntentSender asInterface(android.os.IBinder obj) {\n            throw new UnsupportedOperationException();\n        }\n\n        @Override\n        public android.os.IBinder asBinder() {\n            throw new UnsupportedOperationException();\n        }\n    }\n}"
  },
  {
    "path": "hiddenapi/src/main/java/android/content/IntentHidden.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage android.content;\n\nimport android.os.Build;\n\nimport androidx.annotation.IntDef;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.RequiresApi;\n\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\n\nimport dev.rikka.tools.refine.RefineAs;\nimport misc.utils.HiddenUtil;\n\n@RefineAs(Intent.class)\npublic class IntentHidden {\n    @IntDef(flag = true, value = {\n            EXTENDED_FLAG_FILTER_MISMATCH,\n    })\n    @Retention(RetentionPolicy.SOURCE)\n    public @interface ExtendedFlags {}\n\n    /**\n     * This flag is not normally set by application code, but set for you by the system if\n     * an external intent does not match the receiving component's intent filter.\n     */\n    @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE) // Android 14 r50\n    public static final int EXTENDED_FLAG_FILTER_MISMATCH = 1 << 0;\n\n\n    /**\n     * Retrieve any extended flags associated with this intent.  You will\n     * normally just set them with {@code #setExtendedFlags} and let the system\n     * take the appropriate action with them.\n     *\n     * @return The currently set extended flags.\n     * @see #addExtendedFlags\n     * @see #removeExtendedFlags\n     */\n    @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE) // Android 14 r50\n    public @ExtendedFlags int getExtendedFlags() {\n        return HiddenUtil.throwUOE();\n    }\n\n\n    /**\n     * Add additional extended flags to the intent (or with existing flags value).\n     *\n     * @param flags The new flags to set.\n     * @return Returns the same Intent object, for chaining multiple calls into\n     *         a single statement.\n     * @see #getExtendedFlags\n     * @see #removeExtendedFlags\n     */\n    @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE) // Android 14 r50\n    public @NonNull Intent addExtendedFlags(@ExtendedFlags int flags) {\n        return HiddenUtil.throwUOE(flags);\n    }\n\n\n    /**\n     * Remove these extended flags from the intent.\n     *\n     * @param flags The flags to remove.\n     * @see #getExtendedFlags\n     * @see #addExtendedFlags\n     */\n    @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE) // Android 14 r50\n    public void removeExtendedFlags(@ExtendedFlags int flags) {\n        HiddenUtil.throwUOE(flags);\n    }\n}\n"
  },
  {
    "path": "hiddenapi/src/main/java/android/content/om/IOverlayManager.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage android.content.om;\n\nimport android.os.Build;\nimport android.os.IBinder;\nimport android.os.IInterface;\nimport android.os.RemoteException;\n\nimport androidx.annotation.RequiresApi;\n\nimport java.util.List;\nimport java.util.Map;\n\nimport misc.utils.HiddenUtil;\n\n/**\n * Api for getting information about overlay packages.\n */\n@SuppressWarnings(\"unused\")\n@RequiresApi(Build.VERSION_CODES.O)\npublic interface IOverlayManager extends IInterface {\n    /**\n     * Returns information about all installed overlay packages for the\n     * specified user. If there are no installed overlay packages for this user,\n     * an empty map is returned (i.e. null is never returned). The returned map is a\n     * mapping of target package names to lists of overlays. Each list for a\n     * given target package is sorted priority order, with the overlay with\n     * the highest priority at the end of the list.\n     *\n     * @param userId The user to get the OverlayInfos for.\n     * @return A Map<String, List<OverlayInfo>> with target package names\n     * mapped to lists of overlays; if no overlays exist for the\n     * requested user, an empty map is returned.\n     */\n    Map<String, List<OverlayInfo>> getAllOverlays(int userId) throws RemoteException;\n\n    /**\n     * Returns information about all overlays for the given target package for\n     * the specified user. The returned list is ordered according to the\n     * overlay priority with the highest priority at the end of the list.\n     *\n     * @param targetPackageName The name of the target package.\n     * @param userId            The user to get the OverlayInfos for.\n     * @return A list of OverlayInfo objects; if no overlays exist for the\n     * requested package, an empty list is returned.\n     */\n    List<OverlayInfo> getOverlayInfosForTarget(String targetPackageName, int userId) throws RemoteException;\n\n    /**\n     * Returns information about the overlay with the given package name for the\n     * specified user.\n     *\n     * @param packageName The name of the overlay package.\n     * @param userId      The user to get the OverlayInfo for.\n     * @return The OverlayInfo for the overlay package; or null if no such\n     * overlay package exists.\n     */\n    OverlayInfo getOverlayInfo(String packageName, int userId) throws RemoteException;\n\n    /**\n     * Request that an overlay package be enabled or disabled when possible to\n     * do so.\n     * <p>\n     * It is always possible to disable an overlay, but due to technical and\n     * security reasons it may not always be possible to enable an overlay. An\n     * example of the latter is when the related target package is not\n     * installed. If the technical obstacle is later overcome, the overlay is\n     * automatically enabled at that point time.\n     * <p>\n     * An enabled overlay is a part of target package's resources, i.e. it will\n     * be part of any lookups performed via {@link android.content.res.Resources}\n     * and {@link android.content.res.AssetManager}. A disabled overlay will no\n     * longer affect the resources of the target package. If the target is\n     * currently running, its outdated resources will be replaced by new ones.\n     * This happens the same way as when an application enters or exits split\n     * window mode.\n     *\n     * @param packageName The name of the overlay package.\n     * @param enable      true to enable the overlay, false to disable it.\n     * @param userId      The user for which to change the overlay.\n     * @return true if the system successfully registered the request, false\n     * otherwise.\n     */\n    boolean setEnabled(String packageName, boolean enable, int userId) throws RemoteException;\n\n    /**\n     * Change the priority of the given overlay to be just higher than the\n     * overlay with package name newParentPackageName. Both overlay packages\n     * must have the same target and user.\n     *\n     * @param packageName          The name of the overlay package whose priority should\n     *                             be adjusted.\n     * @param newParentPackageName The name of the overlay package the newly\n     *                             adjusted overlay package should just outrank.\n     * @param userId               The user for which to change the overlay.\n     * @see #getOverlayInfosForTarget(String, int)\n     */\n    boolean setPriority(String packageName, String newParentPackageName, int userId) throws RemoteException;\n\n    /**\n     * Change the priority of the given overlay to the highest priority relative to\n     * the other overlays with the same target and user.\n     *\n     * @param packageName The name of the overlay package whose priority should\n     *                    be adjusted.\n     * @param userId      The user for which to change the overlay.\n     * @see #getOverlayInfosForTarget(String, int)\n     */\n    boolean setHighestPriority(String packageName, int userId) throws RemoteException;\n\n    /**\n     * Change the priority of the overlay to the lowest priority relative to\n     * the other overlays for the same target and user.\n     *\n     * @param packageName The name of the overlay package whose priority should\n     *                    be adjusted.\n     * @param userId      The user for which to change the overlay.\n     * @see #getOverlayInfosForTarget(String, int)\n     */\n    boolean setLowestPriority(String packageName, int userId) throws RemoteException;\n\n    public static abstract class Stub {\n        public static IOverlayManager asInterface(IBinder binder) {\n            return HiddenUtil.throwUOE(binder);\n        }\n    }\n}"
  },
  {
    "path": "hiddenapi/src/main/java/android/content/om/OverlayInfoHidden.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage android.content.om;\n\nimport android.annotation.SuppressLint;\nimport android.os.Build;\n\nimport androidx.annotation.IntDef;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.RequiresApi;\n\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\n\nimport dev.rikka.tools.refine.RefineAs;\nimport misc.utils.HiddenUtil;\n\n/**\n * An immutable information about an overlay.\n *\n * <p>Applications calling {@link OverlayManager#getOverlayInfosForTarget(String)} get the\n * information list of the registered overlays. Each element in the list presents the information of\n * the particular overlay.\n *\n * <p>Immutable overlay information about a package. All PackageInfos that\n * represent an overlay package will have a corresponding OverlayInfo.\n *\n * @see OverlayManager#getOverlayInfosForTarget(String)\n */\n@RequiresApi(api = Build.VERSION_CODES.O)\n@RefineAs(OverlayInfo.class)\npublic final class OverlayInfoHidden {\n    @SuppressLint(\"InlinedApi\")\n    @IntDef(value = {\n            STATE_UNKNOWN,\n            STATE_MISSING_TARGET,\n            STATE_NO_IDMAP,\n            STATE_DISABLED,\n            STATE_ENABLED,\n            STATE_ENABLED_IMMUTABLE,\n            STATE_OVERLAY_IS_BEING_REPLACED,\n            STATE_SYSTEM_UPDATE_UNINSTALL,\n    })\n    @Retention(RetentionPolicy.SOURCE)\n    public @interface State {\n    }\n\n    /**\n     * An internal state used as the initial state of an overlay. OverlayInfo\n     * objects exposed outside the {@code\n     * com.android.server.om.OverlayManagerService} should never have this\n     * state.\n     */\n    public static final int STATE_UNKNOWN = -1;\n\n    /**\n     * The target package of the overlay is not installed. The overlay cannot be enabled.\n     */\n    public static final int STATE_MISSING_TARGET = 0;\n\n    /**\n     * Creation of idmap file failed (e.g. no matching resources). The overlay\n     * cannot be enabled.\n     */\n    public static final int STATE_NO_IDMAP = 1;\n\n    /**\n     * The overlay is currently disabled. It can be enabled.\n     *\n     * @see IOverlayManager#setEnabled\n     */\n    public static final int STATE_DISABLED = 2;\n\n    /**\n     * The overlay is currently enabled. It can be disabled.\n     *\n     * @see IOverlayManager#setEnabled\n     */\n    public static final int STATE_ENABLED = 3;\n\n    /**\n     * The target package is currently being upgraded or downgraded; the state\n     * will change once the package installation has finished.\n     *\n     * @deprecated No longer used. Caused invalid transitions from enabled -> upgrading -> enabled,\n     * where an update is propagated when nothing has changed. Can occur during --dont-kill\n     * installs when code and resources are hot swapped and the Activity should not be relaunched.\n     * In all other cases, the process and therefore Activity is killed, so the state loop is\n     * irrelevant.\n     */\n    @RequiresApi(Build.VERSION_CODES.P)\n    @Deprecated//SinceApi(api = Build.VERSION_CODES.Q)\n    public static final int STATE_TARGET_IS_BEING_REPLACED = 4;\n    /**\n     * The overlay package is currently being upgraded or downgraded; the state\n     * will change once the package installation has finished.\n     */\n    @RequiresApi(Build.VERSION_CODES.P)\n    public static final int STATE_OVERLAY_IS_BEING_REPLACED = 5;\n\n    /**\n     * The overlay package is currently enabled because it is marked as\n     * 'immutable'. It cannot be disabled but will change state if for instance\n     * its target is uninstalled.\n     */\n    @RequiresApi(Build.VERSION_CODES.P)\n    @Deprecated//SinceApi(api = Build.VERSION_CODES.R)\n    public static final int STATE_ENABLED_IMMUTABLE = 6;\n\n    /**\n     * The target package needs to be refreshed as a result of a system update uninstall, which\n     * must recalculate the state of overlays against the newly enabled system package, which may\n     * differ in resources/policy from the /data variant that was uninstalled.\n     */\n    @RequiresApi(Build.VERSION_CODES.TIRAMISU)\n    public static final int STATE_SYSTEM_UPDATE_UNINSTALL = 7;\n\n    /**\n     * Overlay category: theme.\n     * <p>\n     * Change how Android (including the status bar, dialogs, ...) looks.\n     */\n    @RequiresApi(Build.VERSION_CODES.P)\n    public static final String CATEGORY_THEME = \"android.theme\";\n\n    /**\n     * Package name of the overlay package\n     */\n    @NonNull\n    public final String packageName = HiddenUtil.throwUOE();\n\n    /**\n     * The unique name within the package of the overlay.\n     */\n    @Nullable\n    @RequiresApi(Build.VERSION_CODES.S)\n    public final String overlayName = HiddenUtil.throwUOE();\n\n    /**\n     * Package name of the target package\n     */\n    @NonNull\n    public final String targetPackageName = HiddenUtil.throwUOE();\n\n    /**\n     * Name of the target overlayable declaration.\n     */\n    @RequiresApi(Build.VERSION_CODES.Q)\n    @Nullable\n    public final String targetOverlayableName = HiddenUtil.throwUOE();\n\n    /**\n     * Category of the overlay package\n     */\n    @Nullable\n    @RequiresApi(Build.VERSION_CODES.P)\n    public final String category = HiddenUtil.throwUOE();\n\n    /**\n     * Full path to the base APK for this overlay package\n     */\n    @NonNull\n    public final String baseCodePath = HiddenUtil.throwUOE();\n\n    /**\n     * The state of this OverlayInfo as defined by the STATE_* constants in this class.\n     */\n    public final @State int state = HiddenUtil.throwUOE();\n\n    /**\n     * User handle for which this overlay applies\n     */\n    public final int userId = HiddenUtil.throwUOE();\n\n    /**\n     * Priority as configured by {@code com.android.internal.content.om.OverlayConfig}.\n     * Not intended to be exposed to 3rd party.\n     */\n    @RequiresApi(Build.VERSION_CODES.P)\n    public final int priority = HiddenUtil.throwUOE();\n\n    /**\n     * isMutable as configured by {@code com.android.internal.content.om.OverlayConfig}.\n     * If false, the overlay is unconditionally loaded and cannot be unloaded. Not intended to be\n     * exposed to 3rd party.\n     */\n    @RequiresApi(Build.VERSION_CODES.Q)\n    public final boolean isMutable = HiddenUtil.throwUOE();\n    /**\n     * isFabricated if this Overlay was made by the shell/ some SystemUI \"theme\" loaders, also\n     * this value is not updated nor tracked outside of the real manager so this value can't be trusted.\n     */\n    @RequiresApi(Build.VERSION_CODES.S)\n    public final boolean isFabricated = HiddenUtil.throwUOE();\n\n\n    /**\n     * Return true if this overlay is enabled, i.e. should be used to overlay\n     * the resources in the target package.\n     * <p>\n     * Disabled overlay packages are installed but are currently not in use.\n     *\n     * @return true if the overlay is enabled, else false.\n     */\n\n    public boolean isEnabled() {\n        return HiddenUtil.throwUOE();\n    }\n\n    /**\n     * Translate a state to a human readable string. Only intended for\n     * debugging purposes.\n     *\n     * @return a human readable String representing the state.\n     */\n    public static String stateToString(@State int state) {\n        return HiddenUtil.throwUOE(state);\n    }\n}\n"
  },
  {
    "path": "hiddenapi/src/main/java/android/content/pm/ApplicationInfoHidden.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\npackage android.content.pm;\n\nimport android.os.Build;\n\nimport androidx.annotation.Nullable;\nimport androidx.annotation.RequiresApi;\n\nimport dev.rikka.tools.refine.RefineAs;\nimport misc.utils.HiddenUtil;\n\n@RefineAs(ApplicationInfo.class)\npublic class ApplicationInfoHidden {\n    /**\n     * Private/hidden flags. See {@code PRIVATE_FLAG_...} constants.\n     */\n    @RequiresApi(Build.VERSION_CODES.M)\n    public int privateFlags;\n\n    /**\n     * String retrieved from the seinfo tag found in selinux policy. This value can be set through\n     * the mac_permissions.xml policy construct. This value is used for setting an SELinux security\n     * context on the process as well as its data directory.\n     */\n    @RequiresApi(Build.VERSION_CODES.O)\n    public String seInfo;\n\n    /**\n     * String retrieved from the seinfo tag found in selinux policy. This value\n     * can be overridden with a value set through the mac_permissions.xml policy\n     * construct. This value is useful in setting an SELinux security context on\n     * the process as well as its data directory. The String default is being used\n     * here to represent a catchall label when no policy matches.\n     *\n     * @deprecated Replaced with {@link #seInfo} in Android 8 (Oreo)\n     */\n    @Deprecated\n    public String seinfo = \"default\";\n\n    /**\n     * The seinfo tag generated per-user. This value may change based upon the\n     * user's configuration. For example, when an instant app is installed for\n     * a user. It is an error if this field is ever {@code null} when trying to\n     * start a new process.\n     * <p>NOTE: We need to separate this out because we modify per-user values\n     * multiple times. This needs to be refactored since we're performing more\n     * work than necessary and these values should only be set once. When that\n     * happens, we can merge the per-user value with the seInfo state above.\n     */\n    @RequiresApi(Build.VERSION_CODES.O)\n    public String seInfoUser;\n\n    /**\n     * The primary ABI that this application requires, This is inferred from the ABIs\n     * of the native JNI libraries the application bundles. Will be {@code null}\n     * if this application does not require any particular ABI.\n     * <p>\n     * If non-null, the application will always be launched with this ABI.\n     */\n    @Nullable\n    public String primaryCpuAbi;\n\n    @RequiresApi(Build.VERSION_CODES.Q)\n    @Nullable\n    public String zygotePreloadName;\n\n    @RequiresApi(Build.VERSION_CODES.P)\n    public int getHiddenApiEnforcementPolicy() {\n        return HiddenUtil.throwUOE();\n    }\n}\n"
  },
  {
    "path": "hiddenapi/src/main/java/android/content/pm/IOnPermissionsChangeListener.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage android.content.pm;\n\nimport android.os.IInterface;\n\ninterface IOnPermissionsChangeListener extends IInterface {\n    void onPermissionsChanged(int uid);\n}"
  },
  {
    "path": "hiddenapi/src/main/java/android/content/pm/IPackageDataObserver.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage android.content.pm;\n\nimport android.os.Binder;\nimport android.os.IBinder;\nimport android.os.IInterface;\nimport android.os.RemoteException;\n\npublic interface IPackageDataObserver extends IInterface {\n    void onRemoveCompleted(String packageName, boolean succeeded) throws RemoteException;\n\n    abstract class Stub extends Binder implements IPackageDataObserver {\n        public static IPackageDataObserver asInterface(IBinder binder) {\n            throw new UnsupportedOperationException();\n        }\n\n        @Override\n        public IBinder asBinder() {\n            return this;\n        }\n    }\n}"
  },
  {
    "path": "hiddenapi/src/main/java/android/content/pm/IPackageDeleteObserver.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage android.content.pm;\n\nimport android.os.IInterface;\n\ninterface IPackageDeleteObserver extends IInterface {\n    void packageDeleted(String packageName, int returnCode);\n}"
  },
  {
    "path": "hiddenapi/src/main/java/android/content/pm/IPackageDeleteObserver2.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage android.content.pm;\n\nimport android.content.Intent;\n\ninterface IPackageDeleteObserver2 {\n    void onUserActionRequired(Intent intent);\n\n    void onPackageDeleted(String packageName, int returnCode, String msg);\n}"
  },
  {
    "path": "hiddenapi/src/main/java/android/content/pm/IPackageInstallObserver2.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage android.content.pm;\n\nimport android.content.Intent;\nimport android.os.Bundle;\n\ninterface IPackageInstallObserver2 {\n    void onUserActionRequired(Intent intent);\n\n    /**\n     * The install operation has completed.  {@code returnCode} holds a numeric code\n     * indicating success or failure.  In certain cases the {@code extras} Bundle will\n     * contain additional details:\n     *\n     * <p><table>\n     * <tr>\n     *   <td>INSTALL_FAILED_DUPLICATE_PERMISSION</td>\n     *   <td>Two strings are provided in the extras bundle: EXTRA_EXISTING_PERMISSION\n     *       is the name of the permission that the app is attempting to define, and\n     *       EXTRA_EXISTING_PACKAGE is the package name of the app which has already\n     *       defined the permission.</td>\n     * </tr>\n     * </table>\n     */\n    void onPackageInstalled(String basePackageName, int returnCode, String msg, Bundle extras);\n}\n"
  },
  {
    "path": "hiddenapi/src/main/java/android/content/pm/IPackageInstaller.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage android.content.pm;\n\nimport android.content.IntentSender;\nimport android.graphics.Bitmap;\nimport android.os.Binder;\nimport android.os.Build;\nimport android.os.IBinder;\nimport android.os.IInterface;\nimport android.os.RemoteException;\n\nimport androidx.annotation.RequiresApi;\n\nimport java.util.List;\n\npublic interface IPackageInstaller extends IInterface {\n    /**\n     * @deprecated Removed in Android 12 (API 31)\n     */\n    @Deprecated\n    int createSession(PackageInstaller.SessionParams params, String installerPackageName,\n                      int userId) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.S)\n    int createSession(PackageInstaller.SessionParams params, String installerPackageName,\n                      String installerAttributionTag, int userId);\n\n    void updateSessionAppIcon(int sessionId, Bitmap appIcon) throws RemoteException;\n\n    void updateSessionAppLabel(int sessionId, String appLabel) throws RemoteException;\n\n    void abandonSession(int sessionId) throws RemoteException;\n\n    IPackageInstallerSession openSession(int sessionId) throws RemoteException;\n\n    PackageInstaller.SessionInfo getSessionInfo(int sessionId) throws RemoteException;\n\n    ParceledListSlice<PackageInstaller.SessionInfo> getAllSessions(int userId)\n            throws RemoteException;\n\n    ParceledListSlice<PackageInstaller.SessionInfo> getMySessions(String installerPackageName,\n                                                                  int userId)\n            throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.Q)\n    ParceledListSlice<PackageInstaller.SessionInfo> getStagedSessions() throws RemoteException;\n\n    void registerCallback(IPackageInstallerCallback callback, int userId) throws RemoteException;\n\n    void unregisterCallback(IPackageInstallerCallback callback) throws RemoteException;\n\n    /**\n     * @deprecated Removed in Android M.\n     */\n    @Deprecated\n    void uninstall(String packageName, int flags, IntentSender statusReceiver, int userId) throws RemoteException;\n\n    /**\n     * @deprecated Removed in Android O.\n     */\n    @Deprecated\n    @RequiresApi(Build.VERSION_CODES.M)\n    void uninstall(String packageName, String callerPackageName, int flags,\n                   IntentSender statusReceiver, int userId) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.O)\n    void uninstall(VersionedPackage versionedPackage, String callerPackageName, int flags,\n                   IntentSender statusReceiver, int userId) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.Q)\n    void uninstallExistingPackage(VersionedPackage versionedPackage, String callerPackageName,\n                                  IntentSender statusReceiver, int userId);\n\n    @RequiresApi(Build.VERSION_CODES.Q)\n    void installExistingPackage(String packageName, int installFlags, int installReason,\n                                IntentSender statusReceiver, int userId,\n                                List<String> whiteListedPermissions) throws RemoteException;\n\n    void setPermissionsResult(int sessionId, boolean accepted) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)\n    void disableVerificationForUid(int uid) throws RemoteException;\n\n    abstract class Stub extends Binder implements IPackageInstaller {\n        public static IPackageInstaller asInterface(IBinder binder) {\n            throw new UnsupportedOperationException();\n        }\n\n        @Override\n        public IBinder asBinder() {\n            return this;\n        }\n    }\n}"
  },
  {
    "path": "hiddenapi/src/main/java/android/content/pm/IPackageInstallerCallback.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage android.content.pm;\n\npublic interface IPackageInstallerCallback {\n}"
  },
  {
    "path": "hiddenapi/src/main/java/android/content/pm/IPackageInstallerSession.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage android.content.pm;\n\nimport android.content.IntentSender;\nimport android.os.Binder;\nimport android.os.IBinder;\nimport android.os.IInterface;\nimport android.os.ParcelFileDescriptor;\nimport android.os.RemoteException;\n\nimport androidx.annotation.RequiresApi;\n\npublic interface IPackageInstallerSession extends IInterface {\n    void setClientProgress(float progress)\n            throws RemoteException;\n\n    void addClientProgress(float progress)\n            throws RemoteException;\n\n    String[] getNames()\n            throws RemoteException;\n\n    ParcelFileDescriptor openWrite(String name, long offsetBytes, long lengthBytes)\n            throws RemoteException;\n\n    ParcelFileDescriptor openRead(String name)\n            throws RemoteException;\n\n    @RequiresApi(27)\n    void write(String name, long offsetBytes, long lengthBytes, ParcelFileDescriptor fd)\n            throws RemoteException;\n\n    @RequiresApi(24)\n    void removeSplit(String splitName)\n            throws RemoteException;\n\n    void close()\n            throws RemoteException;\n\n    // removed from 28\n    void commit(IntentSender statusReceiver)\n            throws RemoteException;\n\n    @RequiresApi(28)\n    void commit(IntentSender statusReceiver, boolean forTransferred)\n            throws RemoteException;\n\n    @RequiresApi(28)\n    void transfer(String packageName)\n            throws RemoteException;\n\n    void abandon()\n            throws RemoteException;\n\n    @RequiresApi(29)\n    boolean isMultiPackage()\n            throws RemoteException;\n\n    @RequiresApi(29)\n    int[] getChildSessionIds()\n            throws RemoteException;\n\n    @RequiresApi(29)\n    void addChildSessionId(int sessionId)\n            throws RemoteException;\n\n    @RequiresApi(29)\n    void removeChildSessionId(int sessionId)\n            throws RemoteException;\n\n    @RequiresApi(29)\n    int getParentSessionId()\n            throws RemoteException;\n\n    @RequiresApi(29)\n    boolean isStaged()\n            throws RemoteException;\n\n    abstract class Stub extends Binder implements IPackageInstallerSession {\n\n        public static IPackageInstallerSession asInterface(IBinder binder) {\n            throw new UnsupportedOperationException();\n        }\n    }\n}"
  },
  {
    "path": "hiddenapi/src/main/java/android/content/pm/IPackageManager.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage android.content.pm;\n\nimport android.content.ComponentName;\nimport android.content.Intent;\nimport android.content.IntentFilter;\nimport android.content.IntentSender;\nimport android.content.pm.permission.SplitPermissionInfoParcelable;\nimport android.graphics.Bitmap;\nimport android.os.BaseBundle;\nimport android.os.Binder;\nimport android.os.Build;\nimport android.os.Bundle;\nimport android.os.IBinder;\nimport android.os.IInterface;\nimport android.os.PersistableBundle;\nimport android.os.RemoteException;\n\nimport androidx.annotation.Nullable;\nimport androidx.annotation.RequiresApi;\n\nimport java.util.List;\nimport java.util.Map;\n\npublic interface IPackageManager extends IInterface {\n    @RequiresApi(Build.VERSION_CODES.N)\n    void checkPackageStartable(String packageName, int userId) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.M)\n    boolean isPackageFrozen(String packageName) throws RemoteException;\n\n    boolean isPackageAvailable(String packageName, int userId) throws RemoteException;\n\n    /**\n     * @deprecated Removed in API 33 (Android T)\n     */\n    @Deprecated\n    PackageInfo getPackageInfo(String packageName, int flags, int userId) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.TIRAMISU)\n    PackageInfo getPackageInfo(String packageName, long flags, int userId) throws RemoteException;\n\n    /**\n     * @deprecated Removed in API 33 (Android T)\n     */\n    @Deprecated\n    @RequiresApi(Build.VERSION_CODES.O)\n    PackageInfo getPackageInfoVersioned(VersionedPackage versionedPackage, int flags, int userId) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.TIRAMISU)\n    PackageInfo getPackageInfoVersioned(VersionedPackage versionedPackage, long flags, int userId) throws RemoteException;\n\n    /**\n     * @deprecated Removed in API 24 (Android N)\n     */\n    @Deprecated\n    int getPackageUid(String packageName, int userId) throws RemoteException;\n\n    /**\n     * @deprecated Removed in API 33 (Android T)\n     */\n    @Deprecated\n    @RequiresApi(Build.VERSION_CODES.N)\n    int getPackageUid(String packageName, int flags, int userId) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.TIRAMISU)\n    int getPackageUid(String packageName, long flags, int userId) throws RemoteException;\n\n    /**\n     * @deprecated Removed in API 23 (Android M)\n     */\n    @Deprecated\n    int[] getPackageGids(String packageName) throws RemoteException;\n\n    /**\n     * @deprecated Removed in API 24 (Android N)\n     */\n    @Deprecated\n    @RequiresApi(Build.VERSION_CODES.M)\n    int[] getPackageGids(String packageName, int userId) throws RemoteException;\n\n    /**\n     * @deprecated Removed in API 33 (Android T)\n     */\n    @Deprecated\n    @RequiresApi(Build.VERSION_CODES.N)\n    int[] getPackageGids(String packageName, int flags, int userId) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.TIRAMISU)\n    int[] getPackageGids(String packageName, long flags, int userId) throws RemoteException;\n\n    String[] currentToCanonicalPackageNames(String[] names) throws RemoteException;\n\n    String[] canonicalToCurrentPackageNames(String[] names) throws RemoteException;\n\n    /**\n     * @deprecated Removed in API 26 (Android O)\n     */\n    @Deprecated\n    PermissionInfo getPermissionInfo(String name, int flags) throws RemoteException;\n\n    /**\n     * @deprecated Removed in API 30 (Android R)\n     */\n    @Deprecated\n    @RequiresApi(Build.VERSION_CODES.O)\n    PermissionInfo getPermissionInfo(String name, String packageName, int flags) throws RemoteException;\n\n    /**\n     * @deprecated Use {@link IPackageManagerN#queryPermissionsByGroup(String, int)} instead.\n     */\n    @Deprecated\n    List<PermissionInfo> queryPermissionsByGroup(String group, int flags) throws RemoteException;\n\n    /**\n     * @deprecated Deprecated since API 30 (Android R)\n     */\n    @Deprecated\n    PermissionGroupInfo getPermissionGroupInfo(String name, int flags) throws RemoteException;\n\n    /**\n     * @deprecated Use {@link IPackageManagerN#getAllPermissionGroups(int)} instead.\n     */\n    @Deprecated\n    List<PermissionGroupInfo> getAllPermissionGroups(int flags) throws RemoteException;\n\n    /**\n     * @deprecated Removed in API 33 (Android T)\n     */\n    @Deprecated\n    ApplicationInfo getApplicationInfo(String packageName, int flags, int userId) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.TIRAMISU)\n    ApplicationInfo getApplicationInfo(String packageName, long flags, int userId) throws RemoteException;\n\n    /**\n     * @deprecated Removed in API 33 (Android T)\n     */\n    @Deprecated\n    ActivityInfo getActivityInfo(ComponentName className, int flags, int userId) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.TIRAMISU)\n    ActivityInfo getActivityInfo(ComponentName className, long flags, int userId) throws RemoteException;\n\n    boolean activitySupportsIntent(ComponentName className, Intent intent,\n                                   String resolvedType) throws RemoteException;\n\n    /**\n     * @deprecated Removed in API 33 (Android T)\n     */\n    @Deprecated\n    ActivityInfo getReceiverInfo(ComponentName className, int flags, int userId) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.TIRAMISU)\n    ActivityInfo getReceiverInfo(ComponentName className, long flags, int userId) throws RemoteException;\n\n    /**\n     * @deprecated Removed in API 33 (Android T)\n     */\n    @Deprecated\n    ServiceInfo getServiceInfo(ComponentName className, int flags, int userId) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.TIRAMISU)\n    ServiceInfo getServiceInfo(ComponentName className, long flags, int userId) throws RemoteException;\n\n    /**\n     * @deprecated Removed in API 33 (Android T)\n     */\n    @Deprecated\n    ProviderInfo getProviderInfo(ComponentName className, int flags, int userId) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.TIRAMISU)\n    ProviderInfo getProviderInfo(ComponentName className, long flags, int userId) throws RemoteException;\n\n    /**\n     * @deprecated Removed in API 23 (Android M)\n     */\n    @Deprecated\n    int checkPermission(String permName, String pkgName) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.M)\n    int checkPermission(String permName, String pkgName, int userId) throws RemoteException;\n\n    int checkUidPermission(String permName, int uid) throws RemoteException;\n\n    /**\n     * @deprecated Deprecated since API 30 (Android R)\n     */\n    @Deprecated\n    boolean addPermission(PermissionInfo info) throws RemoteException;\n\n    /**\n     * @deprecated Deprecated since API 30 (Android R)\n     */\n    @Deprecated\n    void removePermission(String name) throws RemoteException;\n\n    /**\n     * @deprecated Removed in API 23 (Android M)\n     */\n    @Deprecated\n    void grantPermission(String packageName, String permissionName) throws RemoteException;\n\n    /**\n     * @deprecated Removed in API 23 (Android M)\n     */\n    @Deprecated\n    void revokePermission(String packageName, String permissionName) throws RemoteException;\n\n    /**\n     * @deprecated Deprecated since API 30 (Android R)\n     */\n    @Deprecated\n    @RequiresApi(Build.VERSION_CODES.M)\n    void grantRuntimePermission(String packageName, String permissionName, int userId) throws RemoteException;\n\n    /**\n     * @deprecated Removed in API 30 (Android R)\n     */\n    @Deprecated\n    @RequiresApi(Build.VERSION_CODES.M)\n    void revokeRuntimePermission(String packageName, String permissionName, int userId) throws RemoteException;\n\n    /**\n     * @deprecated Removed in API 30 (Android R)\n     */\n    @Deprecated\n    @RequiresApi(Build.VERSION_CODES.M)\n    void resetRuntimePermissions() throws RemoteException;\n\n    /**\n     * @deprecated Removed in API 30 (Android R)\n     */\n    @Deprecated\n    @RequiresApi(Build.VERSION_CODES.M)\n    int getPermissionFlags(String permissionName, String packageName, int userId) throws RemoteException;\n\n    /**\n     * @deprecated Removed in API 29 (Android Q)\n     */\n    @Deprecated\n    @RequiresApi(Build.VERSION_CODES.M)\n    void updatePermissionFlags(String permissionName, String packageName, int flagMask,\n                               int flagValues, int userId) throws RemoteException;\n\n    /**\n     * @deprecated Removed in API 30 (Android R)\n     */\n    @Deprecated\n    @RequiresApi(Build.VERSION_CODES.Q)\n    void updatePermissionFlags(String permissionName, String packageName, int flagMask,\n                               int flagValues, boolean checkAdjustPolicyFlagPermission, int userId) throws RemoteException;\n\n    /**\n     * @deprecated Removed in API 30 (Android R)\n     */\n    @Deprecated\n    @RequiresApi(Build.VERSION_CODES.M)\n    void updatePermissionFlagsForAllApps(int flagMask, int flagValues, int userId) throws RemoteException;\n\n    /**\n     * @deprecated Removed in API 30 (Android R)\n     */\n    @Deprecated\n    @RequiresApi(Build.VERSION_CODES.Q)\n    List<String> getWhitelistedRestrictedPermissions(String packageName, int flags, int userId) throws RemoteException;\n\n    /**\n     * @deprecated Removed in API 30 (Android R)\n     */\n    @Deprecated\n    @RequiresApi(Build.VERSION_CODES.Q)\n    boolean addWhitelistedRestrictedPermission(String packageName, String permission, int whitelistFlags, int userId) throws RemoteException;\n\n    /**\n     * @deprecated Removed in API 30 (Android R)\n     */\n    @Deprecated\n    @RequiresApi(Build.VERSION_CODES.Q)\n    boolean removeWhitelistedRestrictedPermission(String packageName, String permission, int whitelistFlags, int userId) throws RemoteException;\n\n    /**\n     * @deprecated Removed in API 30 (Android R)\n     */\n    @Deprecated\n    @RequiresApi(Build.VERSION_CODES.M)\n    boolean shouldShowRequestPermissionRationale(String permissionName, String packageName, int userId) throws RemoteException;\n\n    boolean isProtectedBroadcast(String actionName) throws RemoteException;\n\n    int checkSignatures(String pkg1, String pkg2) throws RemoteException;\n\n    int checkUidSignatures(int uid1, int uid2) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.N)\n    List<String> getAllPackages() throws RemoteException;\n\n    String[] getPackagesForUid(int uid) throws RemoteException;\n\n    String getNameForUid(int uid) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.O_MR1)\n    String[] getNamesForUids(int[] uids) throws RemoteException;\n\n    int getUidForSharedUser(String sharedUserName) throws RemoteException;\n\n    int getFlagsForUid(int uid) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.M)\n    int getPrivateFlagsForUid(int uid) throws RemoteException;\n\n    boolean isUidPrivileged(int uid) throws RemoteException;\n\n    String[] getAppOpPermissionPackages(String permissionName) throws RemoteException;\n\n    /**\n     * @deprecated Removed in API 33 (Android T)\n     */\n    @Deprecated\n    ResolveInfo resolveIntent(Intent intent, String resolvedType, int flags, int userId) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.TIRAMISU)\n    ResolveInfo resolveIntent(Intent intent, String resolvedType, long flags, int userId) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.O)\n    ResolveInfo findPersistentPreferredActivity(Intent intent, int userId) throws RemoteException;\n\n    boolean canForwardTo(Intent intent, String resolvedType, int sourceUserId, int targetUserId) throws RemoteException;\n\n    /**\n     * @deprecated Use {@link IPackageManagerN#queryIntentActivities(Intent, String, int, int)} instead.\n     */\n    @Deprecated\n    List<ResolveInfo> queryIntentActivities(Intent intent, String resolvedType, int flags, int userId) throws RemoteException;\n\n    /**\n     * @deprecated Use {@link IPackageManagerN#queryIntentActivityOptions(ComponentName, Intent[], String[], Intent, String, int, int)} instead.\n     */\n    @Deprecated\n    List<ResolveInfo> queryIntentActivityOptions(ComponentName caller, Intent[] specifics,\n                                                 String[] specificTypes, Intent intent,\n                                                 String resolvedType, int flags, int userId) throws RemoteException;\n\n    /**\n     * @deprecated Use {@link IPackageManagerN#queryIntentReceivers(Intent, String, int, int)} instead.\n     */\n    @Deprecated\n    List<ResolveInfo> queryIntentReceivers(Intent intent, String resolvedType, int flags, int userId)\n            throws RemoteException;\n\n    /**\n     * @deprecated Removed in API 33 (Android T)\n     */\n    @Deprecated\n    ResolveInfo resolveService(Intent intent, String resolvedType, int flags, int userId) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.TIRAMISU)\n    ResolveInfo resolveService(Intent intent, String resolvedType, long flags, int userId) throws RemoteException;\n\n    /**\n     * @deprecated Use {@link IPackageManagerN#queryIntentServices(Intent, String, int, int)} instead.\n     */\n    @Deprecated\n    List<ResolveInfo> queryIntentServices(Intent intent, String resolvedType, int flags, int userId)\n            throws RemoteException;\n\n    /**\n     * @deprecated Use {@link IPackageManagerN#queryIntentContentProviders(Intent, String, int, int)} instead.\n     */\n    @Deprecated\n    List<ResolveInfo> queryIntentContentProviders(Intent intent, String resolvedType, int flags, int userId)\n            throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.O)\n    ParceledListSlice<ResolveInfo> queryContentProviders(String processName, int uid, int flags, String metaDataKey) throws RemoteException;\n\n    /**\n     * @deprecated Removed in API 33 (Android T)\n     */\n    @Deprecated\n    ParceledListSlice<PackageInfo> getInstalledPackages(int flags, int userId) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.TIRAMISU)\n    ParceledListSlice<PackageInfo> getInstalledPackages(long flags, int userId) throws RemoteException;\n\n    /**\n     * @deprecated Removed in API 33 (Android T)\n     */\n    @Deprecated\n    ParceledListSlice<PackageInfo> getPackagesHoldingPermissions(String[] permissions, int flags, int userId) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.TIRAMISU)\n    ParceledListSlice<PackageInfo> getPackagesHoldingPermissions(String[] permissions, long flags, int userId) throws RemoteException;\n\n    /**\n     * @deprecated Removed in API 33 (Android T)\n     */\n    @Deprecated\n    ParceledListSlice<ApplicationInfo> getInstalledApplications(int flags, int userId) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.TIRAMISU)\n    ParceledListSlice<ApplicationInfo> getInstalledApplications(long flags, int userId) throws RemoteException;\n\n    /**\n     * @deprecated Use {@link IPackageManagerN#getPersistentApplications(int)} instead.\n     */\n    @Deprecated\n    List<ApplicationInfo> getPersistentApplications(int flags) throws RemoteException;\n\n    /**\n     * @deprecated Removed in API 33 (Android T)\n     */\n    @Deprecated\n    ProviderInfo resolveContentProvider(String name, int flags, int userId) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.TIRAMISU)\n    ProviderInfo resolveContentProvider(String name, long flags, int userId) throws RemoteException;\n\n    /**\n     * Retrieve sync information for all content providers.\n     *\n     * @param outNames Filled in with a list of the root names of the content\n     *                 providers that can sync.\n     * @param outInfo  Filled in with a list of the ProviderInfo for each\n     *                 name in 'outNames'.\n     */\n    void querySyncProviders(List<String> outNames, List<ProviderInfo> outInfo) throws RemoteException;\n\n    /**\n     * @deprecated Use {@link IPackageManagerN#queryContentProviders(String, int, int)} instead.\n     */\n    @Deprecated\n    List<ProviderInfo> queryContentProviders(String processName, int uid, int flags) throws RemoteException;\n\n    InstrumentationInfo getInstrumentationInfo(ComponentName className, int flags) throws RemoteException;\n\n    /**\n     * @deprecated Use {@link IPackageManagerN#queryInstrumentation(String, int)} instead.\n     */\n    @Deprecated\n    List<InstrumentationInfo> queryInstrumentation(String targetPackage, int flags) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.O)\n    void setApplicationCategoryHint(String packageName, int categoryHint, String callerPackageName) throws RemoteException;\n\n    /**\n     * @deprecated Removed in API 26 (Android O)\n     */\n    void deletePackageAsUser(String packageName, IPackageDeleteObserver observer, int userId, int flags) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.O)\n    void deletePackageAsUser(String packageName, int versionCode, IPackageDeleteObserver observer, int userId, int flags) throws RemoteException;\n\n    /**\n     * Delete a package for a specific user.\n     *\n     * @param packageName The fully qualified name of the package to delete.\n     * @param observer    a callback to use to notify when the package deletion in finished.\n     * @param userId      the id of the user for whom to delete the package\n     * @param flags       - possible values: {@code #DONT_DELETE_DATA}\n     * @deprecated Removed in API 26 (Android O)\n     */\n    @Deprecated\n    void deletePackage(String packageName, IPackageDeleteObserver2 observer, int userId, int flags) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.O)\n    void deletePackageVersioned(VersionedPackage versionedPackage, IPackageDeleteObserver2 observer, int userId, int flags) throws RemoteException;\n\n    /**\n     * Delete a package for a specific user.\n     *\n     * @param versionedPackage The package to delete.\n     * @param observer         a callback to use to notify when the package deletion in finished.\n     * @param userId           the id of the user for whom to delete the package\n     */\n    @RequiresApi(Build.VERSION_CODES.R)\n    void deleteExistingPackageAsUser(VersionedPackage versionedPackage, IPackageDeleteObserver2 observer, int userId) throws RemoteException;\n\n    String getInstallerPackageName(String packageName) throws RemoteException;\n\n    /**\n     * @deprecated Removed in API 34 (Android U)\n     */\n    @Deprecated\n    @RequiresApi(Build.VERSION_CODES.R)\n    InstallSourceInfo getInstallSourceInfo(String packageName) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)\n    InstallSourceInfo getInstallSourceInfo(String packageName, int userId) throws RemoteException;\n\n    /**\n     * @deprecated Removed in API 23 (Android M)\n     */\n    @Deprecated\n    void resetPreferredActivities(int userId) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.M)\n    void resetApplicationPreferences(int userId) throws RemoteException;\n\n    ResolveInfo getLastChosenActivity(Intent intent,\n                                      String resolvedType, int flags) throws RemoteException;\n\n    void setLastChosenActivity(Intent intent, String resolvedType, int flags,\n                               IntentFilter filter, int match, ComponentName activity) throws RemoteException;\n\n    void addPreferredActivity(IntentFilter filter, int match, ComponentName[] set,\n                              ComponentName activity, int userId) throws RemoteException;\n\n    void replacePreferredActivity(IntentFilter filter, int match, ComponentName[] set,\n                                  ComponentName activity, int userId) throws RemoteException;\n\n    void clearPackagePreferredActivities(String packageName) throws RemoteException;\n\n    int getPreferredActivities(List<IntentFilter> outFilters, List<ComponentName> outActivities,\n                               String packageName) throws RemoteException;\n\n    void addPersistentPreferredActivity(IntentFilter filter, ComponentName activity, int userId) throws RemoteException;\n\n    void clearPackagePersistentPreferredActivities(String packageName, int userId) throws RemoteException;\n\n    /**\n     * @deprecated Removed in API 23 (Android M)\n     */\n    @Deprecated\n    void addCrossProfileIntentFilter(IntentFilter intentFilter, String ownerPackage,\n                                     int ownerUserId, int sourceUserId, int targetUserId, int flags) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.M)\n    void addCrossProfileIntentFilter(IntentFilter intentFilter, String ownerPackage,\n                                     int sourceUserId, int targetUserId, int flags) throws RemoteException;\n\n    /**\n     * @deprecated Removed in API 23 (Android M)\n     */\n    @Deprecated\n    void clearCrossProfileIntentFilters(int sourceUserId, String ownerPackage, int ownerUserId) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.M)\n    void clearCrossProfileIntentFilters(int sourceUserId, String ownerPackage) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.Q)\n    String[] setDistractingPackageRestrictionsAsUser(String[] packageNames, int restrictionFlags,\n                                                     int userId) throws RemoteException;\n\n    /**\n     * @deprecated Replaced in API 28 (Android P) by {@link #setPackagesSuspendedAsUser(String[], boolean, PersistableBundle, PersistableBundle, String, String, int)}\n     */\n    @Deprecated\n    @RequiresApi(Build.VERSION_CODES.N)\n    String[] setPackagesSuspendedAsUser(String[] packageNames, boolean suspended, int userId) throws RemoteException;\n\n    /**\n     * @deprecated Replaced in API 29 (Android Q) by {@link #setPackagesSuspendedAsUser(String[], boolean, PersistableBundle, PersistableBundle, SuspendDialogInfo, String, int)}\n     */\n    @Deprecated\n    @RequiresApi(Build.VERSION_CODES.P)\n    String[] setPackagesSuspendedAsUser(String[] packageNames, boolean suspended,\n                                        PersistableBundle appExtras, PersistableBundle launcherExtras,\n                                        String dialogMessage, String callingPackage, int userId) throws RemoteException;\n\n    /**\n     * @deprecated Replaced in API 34 r29 (Android U) by {@link #setPackagesSuspendedAsUser(String[], boolean, PersistableBundle, PersistableBundle, SuspendDialogInfo, int, String, int, int)}\n     */\n    @Deprecated\n    @RequiresApi(Build.VERSION_CODES.Q)\n    String[] setPackagesSuspendedAsUser(String[] packageNames, boolean suspended,\n                                        PersistableBundle appExtras, PersistableBundle launcherExtras,\n                                        SuspendDialogInfo dialogInfo, String callingPackage, int userId) throws RemoteException;\n\n    /**\n     * Introduced in API 34 r29\n     */\n    @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)\n    String[] setPackagesSuspendedAsUser(String[] packageNames, boolean suspended,\n                                        PersistableBundle appExtras, PersistableBundle launcherExtras,\n                                        SuspendDialogInfo dialogInfo, int flags, String suspendingPackage,\n                                        int suspendingUserId, int targetUserId) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.N)\n    boolean isPackageSuspendedForUser(String packageName, int userId) throws RemoteException;\n\n    /**\n     * @return In Android P (API 28) and Q (API 29), it returned {@link PersistableBundle} but from\n     * Android R (API 30) it returns {@link Bundle}.\n     */\n    @RequiresApi(Build.VERSION_CODES.P)\n    BaseBundle getSuspendedPackageAppExtras(String packageName, int userId) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.Q)\n    String[] getUnsuspendablePackagesForUser(String[] packageNames, int userId) throws RemoteException;\n\n    /**\n     * Backup/restore support - only the system uid may use these.\n     */\n    @RequiresApi(Build.VERSION_CODES.M)\n    byte[] getPreferredActivityBackup(int userId) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.M)\n    void restorePreferredActivities(byte[] backup, int userId) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.M)\n    byte[] getDefaultAppsBackup(int userId) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.M)\n    void restoreDefaultApps(byte[] backup, int userId) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.M)\n    byte[] getIntentFilterVerificationBackup(int userId) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.M)\n    void restoreIntentFilterVerification(byte[] backup, int userId) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.N)\n    byte[] getPermissionGrantBackup(int userId) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.N)\n    void restorePermissionGrants(byte[] backup, int userId) throws RemoteException;\n\n    /**\n     * Report the set of 'Home' activity candidates, plus (if any) which of them\n     * is the current \"always use this one\" setting.\n     */\n    ComponentName getHomeActivities(List<ResolveInfo> outHomeCandidates) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.N)\n    void setHomeActivity(ComponentName className, int userId) throws RemoteException;\n\n    /**\n     * Overrides the label and icon of the component specified by the component name. The component\n     * must belong to the calling app.\n     * <p>\n     * These changes will be reset on the next boot and whenever the package is updated.\n     * <p>\n     * Only the app defined as com.android.internal.R.config_overrideComponentUiPackage is allowed\n     * to call this.\n     *\n     * @param componentName     The component name to override the label/icon of.\n     * @param nonLocalizedLabel The label to be displayed.\n     * @param icon              The icon to be displayed.\n     * @param userId            The user id.\n     */\n    @RequiresApi(Build.VERSION_CODES.R)\n    void overrideLabelAndIcon(ComponentName componentName, String nonLocalizedLabel,\n                              int icon, int userId) throws RemoteException;\n\n    /**\n     * Restores the label and icon of the activity specified by the component name if either has\n     * been overridden. The component must belong to the calling app.\n     * <p>\n     * Only the app defined as com.android.internal.R.config_overrideComponentUiPackage is allowed\n     * to call this.\n     *\n     * @param componentName The component name.\n     * @param userId        The user id.\n     */\n    @RequiresApi(Build.VERSION_CODES.R)\n    void restoreLabelAndIcon(ComponentName componentName, int userId) throws RemoteException;\n\n    /**\n     * As per {@link android.content.pm.PackageManager#setComponentEnabledSetting}.\n     *\n     * @deprecated Replaced by {@link #setComponentEnabledSetting(ComponentName, int, int, int, String)} in Android 14 (SDK 34)\n     */\n    @Deprecated\n    void setComponentEnabledSetting(ComponentName componentName, int newState, int flags, int userId) throws RemoteException;\n\n    /**\n     * As per {@link android.content.pm.PackageManager#setComponentEnabledSetting}.\n     */\n    @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)\n    void setComponentEnabledSetting(ComponentName componentName, int newState, int flags, int userId, String callingPackage) throws RemoteException;\n\n    /**\n     * As per {@link android.content.pm.PackageManager#getComponentEnabledSetting}.\n     */\n    int getComponentEnabledSetting(ComponentName componentName, int userId) throws RemoteException;\n\n    /**\n     * As per {@link android.content.pm.PackageManager#setApplicationEnabledSetting}.\n     */\n    void setApplicationEnabledSetting(String packageName, int newState, int flags,\n                                      int userId, String callingPackage) throws RemoteException;\n\n    /**\n     * As per {@link android.content.pm.PackageManager#getApplicationEnabledSetting}.\n     */\n    int getApplicationEnabledSetting(String packageName, int userId) throws RemoteException;\n\n    /**\n     * Logs process start information (including APK hash) to the security log.\n     */\n    @RequiresApi(Build.VERSION_CODES.N)\n    void logAppProcessStartIfNeeded(String processName, int uid, String seinfo, String apkFile,\n                                    int pid) throws RemoteException;\n\n    /**\n     * As per {@link android.content.pm.PackageManager#flushPackageRestrictionsAsUser}.\n     */\n    @RequiresApi(Build.VERSION_CODES.N)\n    void flushPackageRestrictionsAsUser(int userId) throws RemoteException;\n\n    /**\n     * Set whether the given package should be considered stopped, making\n     * it not visible to implicit intents that filter out stopped packages.\n     */\n    void setPackageStoppedState(String packageName, boolean stopped, int userId) throws RemoteException;\n\n    /**\n     * Free storage by deleting LRU sorted list of cache files across\n     * all applications. If the currently available free storage\n     * on the device is greater than or equal to the requested\n     * free storage, no cache files are cleared. If the currently\n     * available storage on the device is less than the requested\n     * free storage, some or all of the cache files across\n     * all applications are deleted (based on last accessed time)\n     * to increase the free storage space on the device to\n     * the requested value. There is no guarantee that clearing all\n     * the cache files from all applications will clear up\n     * enough storage to achieve the desired value.\n     *\n     * @param freeStorageSize The number of bytes of storage to be\n     *                        freed by the system. Say if freeStorageSize is XX,\n     *                        and the current free storage is YY,\n     *                        if XX is less than YY, just return. if not free XX-YY number\n     *                        of bytes if possible.\n     * @param observer        call back used to notify when\n     *                        the operation is completed\n     * @deprecated Removed in API 23 (Android M)\n     */\n    @Deprecated\n    void freeStorageAndNotify(long freeStorageSize, IPackageDataObserver observer) throws RemoteException;\n\n    /**\n     * @deprecated Removed in API 26 (Android O)\n     */\n    @Deprecated\n    @RequiresApi(Build.VERSION_CODES.M)\n    void freeStorageAndNotify(String volumeUuid, long freeStorageSize, IPackageDataObserver observer) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.O)\n    void freeStorageAndNotify(String volumeUuid, long freeStorageSize, int storageFlags,\n                              IPackageDataObserver observer) throws RemoteException;\n\n    /**\n     * Free storage by deleting LRU sorted list of cache files across\n     * all applications. If the currently available free storage\n     * on the device is greater than or equal to the requested\n     * free storage, no cache files are cleared. If the currently\n     * available storage on the device is less than the requested\n     * free storage, some or all of the cache files across\n     * all applications are deleted (based on last accessed time)\n     * to increase the free storage space on the device to\n     * the requested value. There is no guarantee that clearing all\n     * the cache files from all applications will clear up\n     * enough storage to achieve the desired value.\n     *\n     * @param freeStorageSize The number of bytes of storage to be\n     *                        freed by the system. Say if freeStorageSize is XX,\n     *                        and the current free storage is YY,\n     *                        if XX is less than YY, just return. if not free XX-YY number\n     *                        of bytes if possible.\n     * @param pi              IntentSender call back used to\n     *                        notify when the operation is completed.May be null\n     *                        to indicate that no call back is desired.\n     * @deprecated Removed in API 23 (Android M)\n     */\n    @Deprecated\n    void freeStorage(long freeStorageSize, IntentSender pi) throws RemoteException;\n\n    /**\n     * @deprecated Removed in API 26 (Android O)\n     */\n    @Deprecated\n    @RequiresApi(Build.VERSION_CODES.M)\n    void freeStorage(String volumeUuid, long freeStorageSize, IntentSender pi) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.O)\n    void freeStorage(String volumeUuid, long freeStorageSize, int storageFlags, IntentSender pi) throws RemoteException;\n\n    /**\n     * Delete all the cache files in an applications cache directory\n     *\n     * @param packageName The package name of the application whose cache\n     *                    files need to be deleted\n     * @param observer    a callback used to notify when the deletion is finished.\n     */\n    void deleteApplicationCacheFiles(String packageName, IPackageDataObserver observer) throws RemoteException;\n\n    /**\n     * Delete all the cache files in an applications cache directory\n     *\n     * @param packageName The package name of the application whose cache\n     *                    files need to be deleted\n     * @param userId      the user to delete application cache for\n     * @param observer    a callback used to notify when the deletion is finished.\n     */\n    @RequiresApi(Build.VERSION_CODES.N)\n    void deleteApplicationCacheFilesAsUser(String packageName, int userId, IPackageDataObserver observer) throws RemoteException;\n\n    /**\n     * Clear the user data directory of an application.\n     *\n     * @param packageName The package name of the application whose cache\n     *                    files need to be deleted\n     * @param observer    a callback used to notify when the operation is completed.\n     */\n    void clearApplicationUserData(String packageName, IPackageDataObserver observer, int userId) throws RemoteException;\n\n    /**\n     * Clear the profile data of an application.\n     *\n     * @param packageName The package name of the application whose profile data\n     *                    need to be deleted\n     */\n    @RequiresApi(Build.VERSION_CODES.N)\n    void clearApplicationProfileData(String packageName) throws RemoteException;\n\n    /**\n     * Get package statistics including the code, data and cache size for\n     * an already installed package\n     *\n     * @param packageName The package name of the application\n     * @param userHandle  Which user the size should be retrieved for\n     * @param observer    a callback to use to notify when the asynchronous\n     *                    retrieval of information is complete.\n     */\n    void getPackageSizeInfo(String packageName, int userHandle, IPackageStatsObserver observer) throws RemoteException;\n\n    /**\n     * Get a list of shared libraries that are available on the\n     * system.\n     */\n    String[] getSystemSharedLibraryNames() throws RemoteException;\n\n    /**\n     * Get a list of features that are available on the\n     * system.\n     *\n     * @return It used to return {@code FeatureInfo[]} but from Android N (API 24), it returns\n     * {@link ParceledListSlice<FeatureInfo>}.\n     */\n    FeatureInfo[] getSystemAvailableFeatures() throws RemoteException;\n\n    boolean hasSystemFeature(String name) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.N)\n    boolean hasSystemFeature(String name, int version) throws RemoteException;\n\n    void enterSafeMode() throws RemoteException;\n\n    boolean isSafeMode() throws RemoteException;\n\n    void systemReady() throws RemoteException;\n\n    boolean hasSystemUidErrors() throws RemoteException;\n\n    /**\n     * Ask the package manager to perform boot-time dex-opt of all\n     * existing packages.\n     *\n     * @deprecated Removed in API 24 (Android N)\n     */\n    @Deprecated\n    void performBootDexOpt() throws RemoteException;\n\n    /**\n     * Ask the package manager to fstrim the disk if needed.\n     */\n    @RequiresApi(Build.VERSION_CODES.N)\n    void performFstrimIfNeeded() throws RemoteException;\n\n    /**\n     * Ask the package manager to update packages if needed.\n     */\n    @RequiresApi(Build.VERSION_CODES.N)\n    void updatePackagesIfNeeded() throws RemoteException;\n\n    /**\n     * Notify the package manager that a package is going to be used and why.\n     * <p>\n     * See PackageManager.NOTIFY_PACKAGE_USE_* for reasons.\n     */\n    @RequiresApi(Build.VERSION_CODES.N)\n    void notifyPackageUse(String packageName, int reason) throws RemoteException;\n\n    /**\n     * Ask the package manager to perform dex-opt (if needed) on the given\n     * package and for the given instruction set if it already hasn't done\n     * so.\n     * <p>\n     * If the supplied instructionSet is null, the package manager will use\n     * the packages default instruction set.\n     * <p>\n     * In most cases, apps are dexopted in advance and this function will\n     * be a no-op.\n     *\n     * @deprecated Removed in API 24 (Android N)\n     */\n    @Deprecated\n    boolean performDexOptIfNeeded(String packageName, String instructionSet) throws RemoteException;\n\n    /**\n     * Ask the package manager to perform dex-opt (if needed) on the given\n     * package if it already hasn't done so.\n     * <p>\n     * In most cases, apps are dexopted in advance and this function will\n     * be a no-op.\n     *\n     * @deprecated Removed in API 26 (Android O)\n     */\n    @Deprecated\n    @RequiresApi(Build.VERSION_CODES.N)\n    boolean performDexOptIfNeeded(String packageName) throws RemoteException;\n\n    /**\n     * Notify the package manager that a list of dex files have been loaded.\n     *\n     * @param loadingPackageName the name of the package who performs the load\n     * @param dexPaths           the list of the dex files paths that have been loaded\n     * @param loaderIsa          the ISA of the loader process\n     * @deprecated Removed in API 27 (Android O MR1)\n     */\n    @Deprecated\n    @RequiresApi(Build.VERSION_CODES.O)\n    void notifyDexLoad(String loadingPackageName, List<String> dexPaths, String loaderIsa) throws RemoteException;\n\n    /**\n     * @deprecated Removed in API 30 (Android R)\n     */\n    @Deprecated\n    @RequiresApi(Build.VERSION_CODES.O_MR1)\n    void notifyDexLoad(String loadingPackageName, List<String> classLoadersNames, List<String> classPaths, String loaderIsa) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.R)\n    void notifyDexLoad(String loadingPackageName, Map<String, String> classLoaderContextMap, String loaderIsa) throws RemoteException;\n\n    /**\n     * Ask the package manager to perform a dex-opt for the given reason. The package\n     * manager will map the reason to a compiler filter according to the current system\n     * configuration.\n     *\n     * @deprecated Removed in API 27 (Android O MR1)\n     */\n    @Deprecated\n    @RequiresApi(Build.VERSION_CODES.N)\n    boolean performDexOpt(String packageName, boolean checkProfiles, int compileReason, boolean force) throws RemoteException;\n\n    /**\n     * Ask the package manager to perform a dex-opt with the given compiler filter.\n     * <p>\n     * Note: exposed only for the shell command to allow moving packages explicitly to a\n     * definite state.\n     *\n     * @deprecated Replaced by {@link #performDexOptMode(String, boolean, String, boolean, boolean, String)} in API 27 (Android O MR1)\n     */\n    @Deprecated\n    @RequiresApi(Build.VERSION_CODES.N)\n    boolean performDexOptMode(String packageName, boolean checkProfiles,\n                              String targetCompilerFilter, boolean force) throws RemoteException;\n\n    /**\n     * Ask the package manager to perform a dex-opt with the given compiler filter.\n     * <p>\n     * Note: exposed only for the shell command to allow moving packages explicitly to a\n     * definite state.\n     */\n    @RequiresApi(Build.VERSION_CODES.O_MR1)\n    boolean performDexOptMode(String packageName, boolean checkProfiles,\n                              String targetCompilerFilter, boolean force, boolean bootComplete, String splitName) throws RemoteException;\n\n    /**\n     * Ask the package manager to perform a dex-opt with the given compiler filter on the\n     * secondary dex files belonging to the given package.\n     * <p>\n     * Note: exposed only for the shell command to allow moving packages explicitly to a\n     * definite state.\n     */\n    @RequiresApi(Build.VERSION_CODES.O)\n    boolean performDexOptSecondary(String packageName, String targetCompilerFilter, boolean force) throws RemoteException;\n\n    /**\n     * Ask the package manager to compile layouts in the given package.\n     *\n     * @deprecated Removed in API 31 (Android 12)\n     */\n    @RequiresApi(Build.VERSION_CODES.Q)\n    @Deprecated\n    boolean compileLayouts(String packageName) throws RemoteException;\n\n    /**\n     * Ask the package manager to dump profiles associated with a package.\n     */\n    @RequiresApi(Build.VERSION_CODES.N)\n    void dumpProfiles(String packageName) throws RemoteException;\n\n    /**\n     * @deprecated Removed in API 34 (Android 14)\n     */\n    @Deprecated\n    void forceDexOpt(String packageName) throws RemoteException;\n\n    /**\n     * Execute the background dexopt job immediately.\n     *\n     * @deprecated Removed in API 29 (Android P)\n     */\n    @Deprecated\n    @RequiresApi(Build.VERSION_CODES.O)\n    boolean runBackgroundDexoptJob() throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.P)\n    boolean runBackgroundDexoptJob(@Nullable List<String> packageNames) throws RemoteException;\n\n    /**\n     * Reconcile the information we have about the secondary dex files belonging to\n     * {@code packagName} and the actual dex files. For all dex files that were\n     * deleted, update the internal records and delete the generated oat files.\n     */\n    @RequiresApi(Build.VERSION_CODES.O)\n    void reconcileSecondaryDexFiles(String packageName) throws RemoteException;\n\n    PackageCleanItem nextPackageToClean(PackageCleanItem lastPackage) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.M)\n    int getMoveStatus(int moveId) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.M)\n    void registerMoveCallback(IPackageMoveObserver callback) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.M)\n    void unregisterMoveCallback(IPackageMoveObserver callback) throws RemoteException;\n\n    /**\n     * @deprecated Removed in API 23 (Android M)\n     */\n    @Deprecated\n    void movePackage(String packageName, IPackageMoveObserver observer, int flags) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.M)\n    int movePackage(String packageName, String volumeUuid) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.M)\n    int movePrimaryStorage(String volumeUuid) throws RemoteException;\n\n    /**\n     * @deprecated Deprecated since API 30 (Android R)\n     */\n    @Deprecated\n    boolean addPermissionAsync(PermissionInfo info) throws RemoteException;\n\n    boolean setInstallLocation(int loc) throws RemoteException;\n\n    int getInstallLocation() throws RemoteException;\n\n    /**\n     * @deprecated Removed in API 26 (Android O)\n     */\n    @Deprecated\n    int installExistingPackageAsUser(String packageName, int userId) throws RemoteException;\n\n    /**\n     * @deprecated Removed in API 29 (Android Q)\n     */\n    @Deprecated\n    @RequiresApi(Build.VERSION_CODES.O)\n    int installExistingPackageAsUser(String packageName, int userId, int installFlags, int installReason) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.Q)\n    int installExistingPackageAsUser(String packageName, int userId, int installFlags,\n                                     int installReason, List<String> whiteListedPermissions) throws RemoteException;\n\n    void verifyPendingInstall(int id, int verificationCode) throws RemoteException;\n\n    void extendVerificationTimeout(int id, int verificationCodeAtTimeout, long millisecondsToDelay) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.M)\n    void verifyIntentFilter(int id, int verificationCode, List<String> failedDomains) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.M)\n    int getIntentVerificationStatus(String packageName, int userId) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.M)\n    boolean updateIntentVerificationStatus(String packageName, int status, int userId) throws RemoteException;\n\n    /**\n     * @return In Android M (API 23), it returned {@link List<IntentFilterVerificationInfo>} but\n     * from Android N, it returns {@link ParceledListSlice<IntentFilterVerificationInfo>}.\n     */\n    @RequiresApi(Build.VERSION_CODES.M)\n    Object getIntentFilterVerifications(String packageName) throws RemoteException;\n\n    /**\n     * @deprecated Use {@link IPackageManagerN#getAllIntentFilters(String)} instead.\n     */\n    @RequiresApi(Build.VERSION_CODES.M)\n    @Deprecated\n    List<IntentFilter> getAllIntentFilters(String packageName) throws RemoteException;\n\n    /**\n     * @deprecated Removed in API 30 (Android R)\n     */\n    @Deprecated\n    boolean setDefaultBrowserPackageName(String packageName, int userId) throws RemoteException;\n\n    /**\n     * @deprecated Removed in API 30 (Android R)\n     */\n    @Deprecated\n    String getDefaultBrowserPackageName(int userId) throws RemoteException; //\n\n    VerifierDeviceIdentity getVerifierDeviceIdentity() throws RemoteException;\n\n    boolean isFirstBoot() throws RemoteException;\n\n    boolean isOnlyCoreApps() throws RemoteException;\n\n    /**\n     * @deprecated Removed in API 29 (Android Q)\n     */\n    @Deprecated\n    @RequiresApi(Build.VERSION_CODES.LOLLIPOP_MR1)\n    boolean isUpgrade() throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.Q)\n    boolean isDeviceUpgrading() throws RemoteException;\n\n    /**\n     * @deprecated Removed in API 30 (Android R)\n     */\n    @Deprecated\n    void setPermissionEnforced(String permission, boolean enforced) throws RemoteException;\n\n    /**\n     * @deprecated Removed in API 30 (Android R)\n     */\n    @Deprecated\n    boolean isPermissionEnforced(String permission) throws RemoteException;\n\n    /**\n     * Reflects current DeviceStorageMonitorService state\n     */\n    boolean isStorageLow() throws RemoteException;\n\n    boolean setApplicationHiddenSettingAsUser(String packageName, boolean hidden, int userId) throws RemoteException;\n\n    boolean getApplicationHiddenSettingAsUser(String packageName, int userId) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.Q)\n    void setSystemAppHiddenUntilInstalled(String packageName, boolean hidden) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.Q)\n    boolean setSystemAppInstallState(String packageName, boolean installed, int userId) throws RemoteException;\n\n    IPackageInstaller getPackageInstaller() throws RemoteException;\n\n    boolean setBlockUninstallForUser(String packageName, boolean blockUninstall, int userId) throws RemoteException;\n\n    boolean getBlockUninstallForUser(String packageName, int userId) throws RemoteException;\n\n    KeySet getKeySetByAlias(String packageName, String alias) throws RemoteException;\n\n    KeySet getSigningKeySet(String packageName) throws RemoteException;\n\n    boolean isPackageSignedByKeySet(String packageName, KeySet ks) throws RemoteException;\n\n    boolean isPackageSignedByKeySetExactly(String packageName, KeySet ks) throws RemoteException;\n\n    /**\n     * @deprecated Removed in API 30 (Android R)\n     */\n    @Deprecated\n    @RequiresApi(Build.VERSION_CODES.M)\n    void addOnPermissionsChangeListener(IOnPermissionsChangeListener listener) throws RemoteException;\n\n    /**\n     * @deprecated Removed in API 30 (Android R)\n     */\n    @Deprecated\n    @RequiresApi(Build.VERSION_CODES.M)\n    void removeOnPermissionsChangeListener(IOnPermissionsChangeListener listener) throws RemoteException;\n\n    /**\n     * @deprecated Removed in API 30 (Android R)\n     */\n    @Deprecated\n    @RequiresApi(Build.VERSION_CODES.M)\n    void grantDefaultPermissionsToEnabledCarrierApps(String[] packageNames, int userId) throws RemoteException;\n\n    /**\n     * @deprecated Removed in API 30 (Android R)\n     */\n    @Deprecated\n    @RequiresApi(Build.VERSION_CODES.O)\n    void grantDefaultPermissionsToEnabledImsServices(String[] packageNames, int userId) throws RemoteException;\n\n    /**\n     * @deprecated Removed in API 30 (Android R)\n     */\n    @Deprecated\n    @RequiresApi(Build.VERSION_CODES.P)\n    void grantDefaultPermissionsToEnabledTelephonyDataServices(String[] packageNames, int userId) throws RemoteException;\n\n    /**\n     * @deprecated Removed in API 30 (Android R)\n     */\n    @Deprecated\n    @RequiresApi(Build.VERSION_CODES.P)\n    void revokeDefaultPermissionsFromDisabledTelephonyDataServices(String[] packageNames, int userId) throws RemoteException;\n\n    /**\n     * @deprecated Removed in API 30 (Android R)\n     */\n    @Deprecated\n    @RequiresApi(Build.VERSION_CODES.P)\n    void grantDefaultPermissionsToActiveLuiApp(String packageName, int userId) throws RemoteException;\n\n    /**\n     * @deprecated Removed in API 30 (Android R)\n     */\n    @Deprecated\n    @RequiresApi(Build.VERSION_CODES.P)\n    void revokeDefaultPermissionsFromLuiApps(String[] packageNames, int userId) throws RemoteException;\n\n    /**\n     * @deprecated Removed in API 30 (Android R)\n     */\n    @Deprecated\n    @RequiresApi(Build.VERSION_CODES.M)\n    boolean isPermissionRevokedByPolicy(String permission, String packageName, int userId) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.M)\n    String getPermissionControllerPackageName() throws RemoteException;\n\n    /**\n     * @deprecated Replaced by {@link #getInstantApps(int)} in API 26 (Android O)\n     */\n    @Deprecated\n    @RequiresApi(Build.VERSION_CODES.N)\n    ParceledListSlice getEphemeralApplications(int userId) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.O)\n    ParceledListSlice getInstantApps(int userId) throws RemoteException;\n\n    /**\n     * @deprecated Deprecated in API 26 (Android O)\n     */\n    @Deprecated\n    @RequiresApi(Build.VERSION_CODES.N)\n    byte[] getEphemeralApplicationCookie(String packageName, int userId) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.O)\n    byte[] getInstantAppCookie(String packageName, int userId) throws RemoteException;\n\n    /**\n     * @deprecated Deprecated in API 26 (Android O)\n     */\n    @Deprecated\n    @RequiresApi(Build.VERSION_CODES.N)\n    boolean setEphemeralApplicationCookie(String packageName, byte[] cookie, int userId) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.O)\n    boolean setInstantAppCookie(String packageName, byte[] cookie, int userId) throws RemoteException;\n\n    /**\n     * @deprecated Deprecated in API 26 (Android O)\n     */\n    @Deprecated\n    @RequiresApi(Build.VERSION_CODES.N)\n    Bitmap getEphemeralApplicationIcon(String packageName, int userId) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.O)\n    Bitmap getInstantAppIcon(String packageName, int userId) throws RemoteException;\n\n    /**\n     * @deprecated Deprecated in API 26 (Android O)\n     */\n    @Deprecated\n    @RequiresApi(Build.VERSION_CODES.N)\n    boolean isEphemeralApplication(String packageName, int userId) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.O)\n    boolean isInstantApp(String packageName, int userId) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.N)\n    boolean setRequiredForSystemUser(String packageName, boolean systemUserApp) throws RemoteException;\n\n    /**\n     * Sets whether or not an update is available. Ostensibly for instant apps\n     * to force exteranl resolution.\n     */\n    @RequiresApi(Build.VERSION_CODES.O)\n    void setUpdateAvailable(String packageName, boolean updateAvailable) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.N)\n    String getServicesSystemSharedLibraryPackageName() throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.N)\n    String getSharedSystemSharedLibraryPackageName() throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.O)\n    ChangedPackages getChangedPackages(int sequenceNumber, int userId) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.N)\n    boolean isPackageDeviceAdminOnAnyUser(String packageName) throws RemoteException;\n\n    /**\n     * @deprecated Removed in API 29 (Android P)\n     */\n    @Deprecated\n    @RequiresApi(Build.VERSION_CODES.N)\n    List<String> getPreviousCodePaths(String packageName) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.O)\n    int getInstallReason(String packageName, int userId) throws RemoteException;\n\n    /**\n     * @deprecated Removed in API 33 (Android T)\n     */\n    @Deprecated\n    @RequiresApi(Build.VERSION_CODES.O)\n    ParceledListSlice getSharedLibraries(String packageName, int flags, int userId) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.TIRAMISU)\n    ParceledListSlice getSharedLibraries(String packageName, long flags, int userId) throws RemoteException;\n\n    /**\n     * @deprecated Removed in API 33 (Android T)\n     */\n    @Deprecated\n    @RequiresApi(Build.VERSION_CODES.Q)\n    ParceledListSlice getDeclaredSharedLibraries(String packageName, int flags, int userId) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.TIRAMISU)\n    ParceledListSlice getDeclaredSharedLibraries(String packageName, long flags, int userId) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.O)\n    boolean canRequestPackageInstalls(String packageName, int userId) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.O)\n    void deletePreloadsFileCache() throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.O)\n    ComponentName getInstantAppResolverComponent() throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.O)\n    ComponentName getInstantAppResolverSettingsComponent() throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.O)\n    ComponentName getInstantAppInstallerComponent() throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.O)\n    String getInstantAppAndroidId(String packageName, int userId) throws RemoteException;\n\n//    @RequiresApi(Build.VERSION_CODES.P)\n//    IArtManager getArtManager() throws RemoteException;  // TODO(25/12/20)\n\n    @RequiresApi(Build.VERSION_CODES.P)\n    void setHarmfulAppWarning(String packageName, CharSequence warning, int userId) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.P)\n    CharSequence getHarmfulAppWarning(String packageName, int userId) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.P)\n    boolean hasSigningCertificate(String packageName, byte[] signingCertificate, int flags) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.P)\n    boolean hasUidSigningCertificate(int uid, byte[] signingCertificate, int flags) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.R)\n    String getDefaultTextClassifierPackageName() throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.P)\n    String getSystemTextClassifierPackageName() throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.Q)\n    String getAttentionServicePackageName() throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.Q)\n    String getWellbeingPackageName() throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.Q)\n    String getAppPredictionServicePackageName() throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.Q)\n    String getSystemCaptionsServicePackageName() throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.R)\n    String getSetupWizardPackageName() throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.Q)\n    String getIncidentReportApproverPackageName() throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.R)\n    String getContentCaptureServicePackageName() throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.P)\n    boolean isPackageStateProtected(String packageName, int userId) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.Q)\n    void sendDeviceCustomizationReadyBroadcast() throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.Q)\n    List<ModuleInfo> getInstalledModules(int flags) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.Q)\n    ModuleInfo getModuleInfo(String packageName, int flags) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.Q)\n    int getRuntimePermissionsVersion(int userId) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.Q)\n    void setRuntimePermissionsVersion(int version, int userId) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.Q)\n    void notifyPackagesReplacedReceived(String[] packages) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.Q)\n    List<SplitPermissionInfoParcelable> getSplitPermissions();\n\n    abstract class Stub extends Binder implements IPackageManager {\n        public static IPackageManager asInterface(IBinder binder) {\n            throw new UnsupportedOperationException();\n        }\n    }\n}\n"
  },
  {
    "path": "hiddenapi/src/main/java/android/content/pm/IPackageManagerN.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\npackage android.content.pm;\n\nimport android.content.ComponentName;\nimport android.content.Intent;\nimport android.content.IntentFilter;\nimport android.os.Build;\nimport android.os.RemoteException;\n\nimport androidx.annotation.RequiresApi;\n\nimport dev.rikka.tools.refine.RefineAs;\n\n@RequiresApi(Build.VERSION_CODES.N)\n@RefineAs(IPackageManager.class)\npublic interface IPackageManagerN {\n    /**\n     * @deprecated Removed in API 30 (Android R)\n     */\n    @Deprecated\n    ParceledListSlice<PermissionInfo> queryPermissionsByGroup(String group, int flags) throws RemoteException;\n\n    /**\n     * @deprecated Removed in API 30 (Android R)\n     */\n    @Deprecated\n    ParceledListSlice<PermissionGroupInfo> getAllPermissionGroups(int flags) throws RemoteException;\n\n    /**\n     * @deprecated Removed in API 33 (Android T)\n     */\n    @Deprecated\n    ParceledListSlice<ResolveInfo> queryIntentActivities(Intent intent, String resolvedType, int flags, int userId)\n            throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.TIRAMISU)\n    ParceledListSlice<ResolveInfo> queryIntentActivities(Intent intent, String resolvedType, long flags, int userId)\n            throws RemoteException;\n\n    /**\n     * @deprecated Removed in API 33 (Android T)\n     */\n    @Deprecated\n    ParceledListSlice<ResolveInfo> queryIntentActivityOptions(ComponentName caller, Intent[] specifics,\n                                                              String[] specificTypes, Intent intent,\n                                                              String resolvedType, int flags, int userId) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.TIRAMISU)\n    ParceledListSlice<ResolveInfo> queryIntentActivityOptions(ComponentName caller, Intent[] specifics,\n                                                              String[] specificTypes, Intent intent,\n                                                              String resolvedType, long flags, int userId) throws RemoteException;\n\n    /**\n     * @deprecated Removed in API 33 (Android T)\n     */\n    @Deprecated\n    ParceledListSlice<ResolveInfo> queryIntentReceivers(Intent intent, String resolvedType, int flags, int userId)\n            throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.TIRAMISU)\n    ParceledListSlice<ResolveInfo> queryIntentReceivers(Intent intent, String resolvedType, long flags, int userId)\n            throws RemoteException;\n\n    /**\n     * @deprecated Removed in API 33 (Android T)\n     */\n    @Deprecated\n    ParceledListSlice<ResolveInfo> queryIntentServices(Intent intent, String resolvedType, int flags, int userId)\n            throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.TIRAMISU)\n    ParceledListSlice<ResolveInfo> queryIntentServices(Intent intent, String resolvedType, long flags, int userId)\n            throws RemoteException;\n\n    /**\n     * @deprecated Removed in API 33 (Android T)\n     */\n    @Deprecated\n    ParceledListSlice<ResolveInfo> queryIntentContentProviders(Intent intent, String resolvedType, int flags,\n                                                               int userId) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.TIRAMISU)\n    ParceledListSlice<ResolveInfo> queryIntentContentProviders(Intent intent, String resolvedType, long flags,\n                                                               int userId) throws RemoteException;\n\n    ParceledListSlice<ApplicationInfo> getPersistentApplications(int flags) throws RemoteException;\n\n    /**\n     * @deprecated Removed in API 26 (Android O)\n     */\n    @Deprecated\n    ParceledListSlice<ProviderInfo> queryContentProviders(String processName, int uid, int flags) throws RemoteException;\n\n    /**\n     * @deprecated Removed in API 33 (Android T)\n     */\n    @Deprecated\n    @RequiresApi(Build.VERSION_CODES.O)\n    ParceledListSlice<ProviderInfo> queryContentProviders(String processName, int uid, int flags, String metaDataKey)\n            throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.TIRAMISU)\n    ParceledListSlice<ProviderInfo> queryContentProviders(String processName, int uid, long flags, String metaDataKey)\n            throws RemoteException;\n\n    ParceledListSlice<InstrumentationInfo> queryInstrumentation(String targetPackage, int flags) throws RemoteException;\n\n    ParceledListSlice<IntentFilter> getAllIntentFilters(String packageName) throws RemoteException;\n}\n"
  },
  {
    "path": "hiddenapi/src/main/java/android/content/pm/IPackageMoveObserver.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage android.content.pm;\n\ninterface IPackageMoveObserver {\n    void packageMoved(String packageName, int returnCode);\n}\n"
  },
  {
    "path": "hiddenapi/src/main/java/android/content/pm/IPackageStatsObserver.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage android.content.pm;\n\nimport android.os.Binder;\nimport android.os.IBinder;\nimport android.os.IInterface;\n\npublic interface IPackageStatsObserver extends IInterface {\n    void onGetStatsCompleted(PackageStats pStats, boolean succeeded);\n\n    abstract class Stub extends Binder implements IPackageStatsObserver {\n        public static IPackageDataObserver asInterface(IBinder binder) {\n            throw new UnsupportedOperationException();\n        }\n\n        @Override\n        public IBinder asBinder() {\n            return this;\n        }\n    }\n}\n"
  },
  {
    "path": "hiddenapi/src/main/java/android/content/pm/KeySet.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage android.content.pm;\n\nimport android.os.IBinder;\nimport android.os.Parcel;\nimport android.os.Parcelable;\n\nimport misc.utils.HiddenUtil;\n\n/**\n * Represents a {@code KeySet} that has been declared in the AndroidManifest.xml\n * file for the application.  A {@code KeySet} can be used explicitly to\n * represent a trust relationship with other applications on the device.\n */\npublic class KeySet implements Parcelable {\n    public KeySet(IBinder token) {\n        HiddenUtil.throwUOE(token);\n    }\n\n    public IBinder getToken() {\n        return HiddenUtil.throwUOE();\n    }\n\n    @Override\n    public void writeToParcel(Parcel dest, int flags) {\n        HiddenUtil.throwUOE(dest, flags);\n    }\n\n    @Override\n    public int describeContents() {\n        return HiddenUtil.throwUOE();\n    }\n\n    public static final Creator<KeySet> CREATOR = HiddenUtil.creator();\n}\n"
  },
  {
    "path": "hiddenapi/src/main/java/android/content/pm/PackageCleanItem.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage android.content.pm;\n\nimport android.os.Parcel;\nimport android.os.Parcelable;\n\nimport misc.utils.HiddenUtil;\n\npublic class PackageCleanItem implements Parcelable {\n    public final int userId;\n    public final String packageName;\n    public final boolean andCode;\n\n    public PackageCleanItem(int userId, String packageName, boolean andCode) {\n        HiddenUtil.throwUOE(userId, packageName, andCode);\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public void writeToParcel(Parcel dest, int flags) {\n        HiddenUtil.throwUOE(dest, flags);\n    }\n\n    @Override\n    public int describeContents() {\n        return HiddenUtil.throwUOE();\n    }\n\n    public static final Creator<PackageCleanItem> CREATOR = HiddenUtil.creator();\n}\n"
  },
  {
    "path": "hiddenapi/src/main/java/android/content/pm/PackageInfoHidden.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage android.content.pm;\n\nimport android.os.Build;\n\nimport androidx.annotation.Nullable;\nimport androidx.annotation.RequiresApi;\n\nimport dev.rikka.tools.refine.RefineAs;\nimport misc.utils.HiddenUtil;\n\n@RefineAs(PackageInfo.class)\npublic class PackageInfoHidden {\n    @RequiresApi(Build.VERSION_CODES.O_MR1)\n    public boolean isStub;\n\n    public boolean coreApp;\n\n    public boolean requiredForAllUsers;\n\n    public String restrictedAccountType;\n\n    public String requiredAccountType;\n\n    /**\n     * What package, if any, this package will overlay.\n     * <p>\n     * Package name of target package, or null.\n     */\n    @Nullable\n    public String overlayTarget;\n\n    /**\n     * The name of the overlayable set of elements package, if any, this package will overlay.\n     * <p>\n     * Overlayable name defined within the target package, or null.\n     */\n    @RequiresApi(Build.VERSION_CODES.Q)\n    @Nullable\n    public String targetOverlayableName;\n\n    /**\n     * The overlay category, if any, of this package\n     */\n    @RequiresApi(Build.VERSION_CODES.P)\n    @Nullable\n    public String overlayCategory;\n\n    @RequiresApi(Build.VERSION_CODES.O)\n    public int overlayPriority;\n\n    /**\n     * @deprecated Replaced by {@link #overlayFlags} in Android 8.0.0_r37 and in Android 8.1.0_r15\n     */\n    @RequiresApi(Build.VERSION_CODES.O)\n    @Deprecated\n    public boolean isStaticOverlay;\n\n    /**\n     * Flag for use with {@link #overlayFlags}. Marks the overlay as static, meaning it cannot\n     * be enabled/disabled at runtime.\n     */\n    @RequiresApi(Build.VERSION_CODES.O)\n    public static final int FLAG_OVERLAY_STATIC = 1 << 1;\n\n    /**\n     * Flag for use with {@link #overlayFlags}. Marks the overlay as trusted (not 3rd party).\n     */\n    @RequiresApi(Build.VERSION_CODES.O)\n    public static final int FLAG_OVERLAY_TRUSTED = 1 << 2;\n\n    /**\n     * Modifiers that affect the state of this overlay. See {@link #FLAG_OVERLAY_STATIC},\n     * {@link #FLAG_OVERLAY_TRUSTED}.\n     *\n     * @deprecated Replaced in Android 9.0 by {@link #isStaticOverlayPackage()}\n     */\n    @RequiresApi(Build.VERSION_CODES.O)\n    @Deprecated\n    public int overlayFlags;\n\n    /**\n     * Whether the overlay is static, meaning it cannot be enabled/disabled at runtime.\n     */\n    @RequiresApi(Build.VERSION_CODES.R)\n    public boolean mOverlayIsStatic;\n\n    /**\n     * Returns true if the package is a valid static Runtime Overlay package. Static overlays\n     * are not updatable outside of a system update and are safe to load in the system process.\n     */\n    @RequiresApi(Build.VERSION_CODES.P)\n    public boolean isStaticOverlayPackage() {\n        return HiddenUtil.throwUOE();\n    }\n}\n"
  },
  {
    "path": "hiddenapi/src/main/java/android/content/pm/PackageInstallerHidden.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage android.content.pm;\n\nimport android.content.Context;\nimport android.os.Build;\n\nimport androidx.annotation.RequiresApi;\n\nimport dev.rikka.tools.refine.RefineAs;\nimport misc.utils.HiddenUtil;\n\n@RefineAs(PackageInstaller.class)\npublic class PackageInstallerHidden {\n    @RequiresApi(Build.VERSION_CODES.S)\n    public PackageInstallerHidden(IPackageInstaller installer,\n                                  String installerPackageName,\n                                  String installerAttributionTag,\n                                  int userId) {\n        HiddenUtil.throwUOE(installer, installerPackageName, installerAttributionTag, userId);\n    }\n\n    /**\n     * @deprecated Removed in Android 12 (API 31)\n     */\n    @Deprecated\n    @RequiresApi(Build.VERSION_CODES.O)\n    public PackageInstallerHidden(IPackageInstaller installer,\n                                  String installerPackageName,\n                                  int userId) {\n        HiddenUtil.throwUOE(installer, installerPackageName, userId);\n    }\n\n    /**\n     * @deprecated Removed in Android 8 (API 26)\n     */\n    @Deprecated\n    public PackageInstallerHidden(Context context,\n                                  PackageManager packageManager,\n                                  IPackageInstaller installer,\n                                  String installerPackageName,\n                                  int userId) {\n        HiddenUtil.throwUOE(context, packageManager, installer, installerPackageName, userId);\n    }\n\n    public static class Session {\n        public Session(IPackageInstallerSession session) {\n            HiddenUtil.throwUOE(session);\n        }\n    }\n\n    public static class SessionParams {\n        public int installFlags;\n        @RequiresApi(Build.VERSION_CODES.P)\n        public String installerPackageName;\n    }\n}\n"
  },
  {
    "path": "hiddenapi/src/main/java/android/content/pm/ParceledListSlice.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage android.content.pm;\n\nimport android.os.Parcelable;\n\nimport java.util.List;\n\nimport misc.utils.HiddenUtil;\n\npublic class ParceledListSlice<T extends Parcelable> {\n    public List<T> getList() {\n        return HiddenUtil.throwUOE();\n    }\n}\n"
  },
  {
    "path": "hiddenapi/src/main/java/android/content/pm/SuspendDialogInfo.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage android.content.pm;\n\nimport android.os.Parcel;\nimport android.os.Parcelable;\n\nimport androidx.annotation.DrawableRes;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.StringRes;\n\nimport java.util.Locale;\n\nimport misc.utils.HiddenUtil;\n\npublic final class SuspendDialogInfo implements Parcelable {\n    /**\n     * @return the resource id of the icon to be used with the dialog\n     */\n    @DrawableRes\n    public int getIconResId() {\n        return HiddenUtil.throwUOE();\n    }\n\n    /**\n     * @return the resource id of the title to be used with the dialog\n     */\n    @StringRes\n    public int getTitleResId() {\n        return HiddenUtil.throwUOE();\n    }\n\n    /**\n     * @return the resource id of the text to be shown in the dialog's body\n     */\n    @StringRes\n    public int getDialogMessageResId() {\n        return HiddenUtil.throwUOE();\n    }\n\n    /**\n     * @return the text to be shown in the dialog's body. Returns {@code null} if\n     * {@link #getDialogMessageResId()} returns a valid resource id.\n     */\n    @Nullable\n    public String getDialogMessage() {\n        return HiddenUtil.throwUOE();\n    }\n\n    /**\n     * @return the text to be shown\n     */\n    @StringRes\n    public int getNeutralButtonTextResId() {\n        return HiddenUtil.throwUOE();\n    }\n\n    SuspendDialogInfo(Builder b) {\n        HiddenUtil.throwUOE(b);\n    }\n\n\n    @Override\n    public void writeToParcel(Parcel dest, int flags) {\n        HiddenUtil.throwUOE(dest, flags);\n    }\n\n    @Override\n    public int describeContents() {\n        return HiddenUtil.throwUOE();\n    }\n\n    public static final Creator<SuspendDialogInfo> CREATOR = HiddenUtil.creator();\n\n    /**\n     * Builder to build a {@link SuspendDialogInfo} object.\n     */\n    public static final class Builder {\n        /**\n         * Set the resource id of the icon to be used. If not provided, no icon will be shown.\n         *\n         * @param resId The resource id of the icon.\n         * @return this builder object.\n         */\n        @NonNull\n        public Builder setIcon(@DrawableRes int resId) {\n            return HiddenUtil.throwUOE(resId);\n        }\n\n        /**\n         * Set the resource id of the title text to be displayed. If this is not provided, the\n         * system will use a default title.\n         *\n         * @param resId The resource id of the title.\n         * @return this builder object.\n         */\n        @NonNull\n        public Builder setTitle(@StringRes int resId) {\n            return HiddenUtil.throwUOE(resId);\n        }\n\n        /**\n         * Set the text to show in the body of the dialog. Ignored if a resource id is set via\n         * {@link #setMessage(int)}.\n         * <p>\n         * The system will use {@link String#format(Locale, String, Object...) String.format} to\n         * insert the suspended app name into the message, so an example format string could be\n         * {@code \"The app %1$s is currently suspended\"}. This is optional - if the string passed in\n         * {@code message} does not accept an argument, it will be used as is.\n         *\n         * @param message The dialog message.\n         * @return this builder object.\n         * @see #setMessage(int)\n         */\n        @NonNull\n        public Builder setMessage(@NonNull String message) {\n            return HiddenUtil.throwUOE(message);\n        }\n\n        /**\n         * Set the resource id of the dialog message to be shown. If no dialog message is provided\n         * via either this method or {@link #setMessage(String)}, the system will use a\n         * default message.\n         * <p>\n         * The system will use {@link android.content.res.Resources#getString(int, Object...)\n         * getString} to insert the suspended app name into the message, so an example format string\n         * could be {@code \"The app %1$s is currently suspended\"}. This is optional - if the string\n         * referred to by {@code resId} does not accept an argument, it will be used as is.\n         *\n         * @param resId The resource id of the dialog message.\n         * @return this builder object.\n         * @see #setMessage(String)\n         */\n        @NonNull\n        public Builder setMessage(@StringRes int resId) {\n            return HiddenUtil.throwUOE(resId);\n        }\n\n        /**\n         * Set the resource id of text to be shown on the neutral button. Tapping this button starts\n         * the {@link android.content.Intent#ACTION_SHOW_SUSPENDED_APP_DETAILS} activity. If this is\n         * not provided, the system will use a default text.\n         *\n         * @param resId The resource id of the button text\n         * @return this builder object.\n         */\n        @NonNull\n        public Builder setNeutralButtonText(@StringRes int resId) {\n            return HiddenUtil.throwUOE(resId);\n        }\n\n        /**\n         * Build the final object based on given inputs.\n         *\n         * @return The {@link SuspendDialogInfo} object built using this builder.\n         */\n        @NonNull\n        public SuspendDialogInfo build() {\n            return HiddenUtil.throwUOE();\n        }\n    }\n}"
  },
  {
    "path": "hiddenapi/src/main/java/android/content/pm/UserInfo.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage android.content.pm;\n\nimport android.os.Build;\nimport android.os.Parcel;\nimport android.os.Parcelable;\nimport android.os.UserHandle;\n\nimport androidx.annotation.RequiresApi;\n\nimport misc.utils.HiddenUtil;\n\n/**\n * Per-user information.\n */\npublic class UserInfo implements Parcelable {\n    /*\n     * *************************** NOTE ***************************\n     * These flag values CAN NOT CHANGE because they are written\n     * directly to storage.\n     */\n\n    /**\n     * Primary user. Only one user can have this flag set. It identifies the first human user\n     * on a device.\n     */\n    public static final int FLAG_PRIMARY = 0x00000001;\n\n    /**\n     * User with administrative privileges. Such a user can create and\n     * delete users.\n     */\n    public static final int FLAG_ADMIN = 0x00000002;\n\n    /**\n     * Indicates a guest user that may be transient.\n     */\n    public static final int FLAG_GUEST = 0x00000004;\n\n    /**\n     * Indicates the user has restrictions in privileges, in addition to those for normal users.\n     * Exact meaning TBD. For instance, maybe they can't install apps or administer WiFi access pts.\n     */\n    public static final int FLAG_RESTRICTED = 0x00000008;\n\n    /**\n     * Indicates that this user has gone through its first-time initialization.\n     */\n    public static final int FLAG_INITIALIZED = 0x00000010;\n\n    /**\n     * Indicates that this user is a profile of another user, for example holding a users\n     * corporate data.\n     */\n    public static final int FLAG_MANAGED_PROFILE = 0x00000020;\n\n    /**\n     * Indicates that this user is disabled.\n     *\n     * <p>Note: If an ephemeral user is disabled, it shouldn't be later re-enabled. Ephemeral users\n     * are disabled as their removal is in progress to indicate that they shouldn't be re-entered.\n     */\n    public static final int FLAG_DISABLED = 0x00000040;\n\n    @RequiresApi(Build.VERSION_CODES.N)\n    public static final int FLAG_QUIET_MODE = 0x00000080;\n\n    /**\n     * Indicates that this user is ephemeral. I.e. the user will be removed after leaving\n     * the foreground.\n     */\n    @RequiresApi(Build.VERSION_CODES.N)\n    public static final int FLAG_EPHEMERAL = 0x00000100;\n\n    /**\n     * User is for demo purposes only and can be removed at any time.\n     */\n    @RequiresApi(Build.VERSION_CODES.N_MR1)\n    public static final int FLAG_DEMO = 0x00000200;\n\n    public static final int NO_PROFILE_GROUP_ID = -1;\n\n    public int id;\n    public int serialNumber;\n    public String name;\n    public String iconPath;\n    public int flags;\n    public long creationTime;\n    public long lastLoggedInTime;\n    @RequiresApi(Build.VERSION_CODES.N)\n    public String lastLoggedInFingerprint;\n    /**\n     * If this user is a parent user, it would be its own user id.\n     * If this user is a child user, it would be its parent user id.\n     * Otherwise, it would be {@link #NO_PROFILE_GROUP_ID}.\n     */\n    public int profileGroupId;\n    @RequiresApi(Build.VERSION_CODES.N)\n    public int restrictedProfileParentId;\n    /**\n     * Which profile badge color/label to use.\n     */\n    @RequiresApi(Build.VERSION_CODES.O)\n    public int profileBadge;\n    /**\n     * User is only partially created.\n     */\n    public boolean partial;\n    public boolean guestToRemove;\n\n    public boolean isPrimary() {\n        return HiddenUtil.throwUOE();\n    }\n\n    public boolean isAdmin() {\n        return HiddenUtil.throwUOE();\n    }\n\n    public boolean isGuest() {\n        return HiddenUtil.throwUOE();\n    }\n\n    public boolean isRestricted() {\n        return HiddenUtil.throwUOE();\n    }\n\n    public boolean isManagedProfile() {\n        return HiddenUtil.throwUOE();\n    }\n\n    public boolean isEnabled() {\n        return HiddenUtil.throwUOE();\n    }\n\n    @RequiresApi(Build.VERSION_CODES.N)\n    public boolean isQuietModeEnabled() {\n        return HiddenUtil.throwUOE();\n    }\n\n    @RequiresApi(Build.VERSION_CODES.N)\n    public boolean isEphemeral() {\n        return HiddenUtil.throwUOE();\n    }\n\n    @RequiresApi(Build.VERSION_CODES.N)\n    public boolean isInitialized() {\n        return HiddenUtil.throwUOE();\n    }\n\n    @RequiresApi(Build.VERSION_CODES.N_MR1)\n    public boolean isDemo() {\n        return HiddenUtil.throwUOE();\n    }\n\n    /**\n     * @return true if this user can be switched to.\n     **/\n    public boolean supportsSwitchTo() {\n        return HiddenUtil.throwUOE();\n    }\n\n    public UserHandle getUserHandle() {\n        return HiddenUtil.throwUOE();\n    }\n\n    @Override\n    public int describeContents() {\n        return HiddenUtil.throwUOE();\n    }\n\n    @Override\n    public void writeToParcel(Parcel dest, int flags) {\n        HiddenUtil.throwUOE(dest, flags);\n    }\n\n    public static final Creator<UserInfo> CREATOR = new Creator<UserInfo>() {\n        @Override\n        public UserInfo createFromParcel(Parcel in) {\n            return HiddenUtil.throwUOE(in);\n        }\n\n        @Override\n        public UserInfo[] newArray(int size) {\n            return HiddenUtil.throwUOE(size);\n        }\n    };\n}\n"
  },
  {
    "path": "hiddenapi/src/main/java/android/content/pm/VerifierDeviceIdentity.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage android.content.pm;\n\nimport android.os.Parcel;\nimport android.os.Parcelable;\n\nimport misc.utils.HiddenUtil;\n\npublic class VerifierDeviceIdentity implements Parcelable {\n    /**\n     * Create a verifier device identity from a long.\n     *\n     * @param identity device identity in a 64-bit integer.\n     */\n    public VerifierDeviceIdentity(long identity) {\n        HiddenUtil.throwUOE(identity);\n    }\n\n    /**\n     * Generate a new device identity.\n     *\n     * @return random uniformly-distributed device identity\n     */\n    public static VerifierDeviceIdentity generate() {\n        return HiddenUtil.throwUOE();\n    }\n\n    public static VerifierDeviceIdentity parse(String deviceIdentity)\n            throws IllegalArgumentException {\n        return HiddenUtil.throwUOE(deviceIdentity);\n    }\n\n    @Override\n    public void writeToParcel(Parcel dest, int flags) {\n        HiddenUtil.throwUOE(dest, flags);\n    }\n\n    @Override\n    public int describeContents() {\n        return HiddenUtil.throwUOE();\n    }\n\n    public static final Creator<VerifierDeviceIdentity> CREATOR = HiddenUtil.creator();\n}\n"
  },
  {
    "path": "hiddenapi/src/main/java/android/content/pm/permission/SplitPermissionInfoParcelable.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage android.content.pm.permission;\n\nimport android.os.Parcel;\nimport android.os.Parcelable;\n\nimport androidx.annotation.IntRange;\nimport androidx.annotation.NonNull;\n\nimport java.util.List;\n\nimport misc.utils.HiddenUtil;\n\n/**\n * Parcelable version of {@link android.permission.PermissionManager.SplitPermissionInfo}\n */\npublic class SplitPermissionInfoParcelable implements Parcelable {\n    /**\n     * Creates a new SplitPermissionInfoParcelable.\n     *\n     * @param splitPermission The permission that is split.\n     * @param newPermissions  The permissions that are added.\n     * @param targetSdk       The target API level when the permission was split.\n     */\n    public SplitPermissionInfoParcelable(\n            @NonNull String splitPermission,\n            @NonNull List<String> newPermissions,\n            @IntRange(from = 0) int targetSdk) {\n        HiddenUtil.throwUOE(splitPermission, newPermissions, targetSdk);\n    }\n\n    /**\n     * The permission that is split.\n     */\n    @NonNull\n    public String getSplitPermission() {\n        return HiddenUtil.throwUOE();\n    }\n\n    /**\n     * The permissions that are added.\n     */\n    @NonNull\n    public List<String> getNewPermissions() {\n        return HiddenUtil.throwUOE();\n    }\n\n    /**\n     * The target API level when the permission was split.\n     */\n    @IntRange(from = 0)\n    public int getTargetSdk() {\n        return HiddenUtil.throwUOE();\n    }\n\n    @Override\n    public int describeContents() {\n        return HiddenUtil.throwUOE();\n    }\n\n    @Override\n    public void writeToParcel(Parcel dest, int flags) {\n        HiddenUtil.throwUOE(dest, flags);\n    }\n\n    public static final Creator<SplitPermissionInfoParcelable> CREATOR = HiddenUtil.creator();\n}"
  },
  {
    "path": "hiddenapi/src/main/java/android/content/pm/verify/domain/IDomainVerificationManager.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage android.content.pm.verify.domain;\n\nimport android.content.Intent;\nimport android.os.Binder;\nimport android.os.Build;\nimport android.os.IBinder;\nimport android.os.IInterface;\nimport android.os.RemoteException;\n\nimport androidx.annotation.Nullable;\nimport androidx.annotation.RequiresApi;\n\nimport misc.utils.HiddenUtil;\n\n@RequiresApi(Build.VERSION_CODES.S)\npublic interface IDomainVerificationManager extends IInterface {\n    /**\n     * Retrieve the user state for the given package and the user.\n     *\n     * @param packageName The app to query state for.\n     * @return The user selection verification data for the given package for the user, or null if\n     * the package does not declare any HTTP/HTTPS domains.\n     */\n    @Nullable\n    DomainVerificationUserState getDomainVerificationUserState(String packageName,\n            int userId) throws RemoteException;\n\n    /**\n     * Change whether the given packageName is allowed to handle BROWSABLE and DEFAULT category web\n     * (HTTP/HTTPS) {@link Intent} Activity open requests. The final state is determined along with\n     * the verification status for the specific domain being opened and other system state. An app\n     * with this enabled is not guaranteed to be the sole link handler for its domains.\n     * <p>\n     * By default, all apps are allowed to open links. Users must disable them explicitly.\n     */\n    void setDomainVerificationLinkHandlingAllowed(String packageName, boolean allowed, int userId) throws RemoteException;\n\n    abstract class Stub extends Binder implements IDomainVerificationManager {\n        public static IDomainVerificationManager asInterface(IBinder obj) {\n            return HiddenUtil.throwUOE(obj);\n        }\n\n        @Override\n        public android.os.IBinder asBinder() {\n            return this;\n        }\n    }\n}\n"
  },
  {
    "path": "hiddenapi/src/main/java/android/hardware/input/IInputManager.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage android.hardware.input;\n\nimport android.os.Binder;\nimport android.os.Build;\nimport android.os.IBinder;\nimport android.os.IInterface;\nimport android.os.RemoteException;\nimport android.view.InputEvent;\n\nimport androidx.annotation.RequiresApi;\n\nimport misc.utils.HiddenUtil;\n\npublic interface IInputManager extends IInterface {\n    /**\n     * Injects an input event into the system. The caller must have the INJECT_EVENTS permssion.\n     * This method exists only for compatibility purposes and may be removed in a future release.\n     */\n    boolean injectInputEvent(InputEvent ev, int mode) throws RemoteException;\n\n    /**\n     * Injects an input event into the system. The caller must have the INJECT_EVENTS permission.\n     * The caller can target windows owned by a certain UID by providing a valid UID, or by\n     * providing {@link android.os.Process#INVALID_UID} to target all windows.\n     */\n    @RequiresApi(Build.VERSION_CODES.TIRAMISU)\n    boolean injectInputEventToTarget(InputEvent ev, int mode, int targetUid) throws RemoteException;\n\n    abstract class Stub extends Binder implements IInputManager {\n        public static IInputManager asInterface(IBinder obj) {\n            return HiddenUtil.throwUOE(obj);\n        }\n\n        @Override\n        public IBinder asBinder() {\n            return this;\n        }\n    }\n}\n"
  },
  {
    "path": "hiddenapi/src/main/java/android/hardware/input/InputManagerHidden.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage android.hardware.input;\n\nimport dev.rikka.tools.refine.RefineAs;\n\n@RefineAs(InputManager.class)\npublic class InputManagerHidden {\n    /**\n     * Input Event Injection Synchronization Mode: None.\n     * Never blocks.  Injection is asynchronous and is assumed always to be successful.\n     */\n    public static /*final*/ int INJECT_INPUT_EVENT_MODE_ASYNC;\n\n    /**\n     * Input Event Injection Synchronization Mode: Wait for result.\n     * Waits for previous events to be dispatched so that the input dispatcher can\n     * determine whether input event injection will be permitted based on the current\n     * input focus.  Does not wait for the input event to finish being handled\n     * by the application.\n     */\n    public static /*final*/ int INJECT_INPUT_EVENT_MODE_WAIT_FOR_RESULT;\n\n    /**\n     * Input Event Injection Synchronization Mode: Wait for finish.\n     * Waits for the event to be delivered to the application and handled.\n     */\n    public static /*final*/ int INJECT_INPUT_EVENT_MODE_WAIT_FOR_FINISH;\n}\n"
  },
  {
    "path": "hiddenapi/src/main/java/android/miui/AppOpsUtils.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage android.miui;\n\nimport misc.utils.HiddenUtil;\n\n// This is a MIUI specific API\npublic class AppOpsUtils {\n    public static boolean isXOptMode() {\n        return HiddenUtil.throwUOE();\n    }\n}\n"
  },
  {
    "path": "hiddenapi/src/main/java/android/net/ConnectivityManagerHidden.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage android.net;\n\nimport android.os.Build;\n\nimport androidx.annotation.RequiresApi;\n\npublic class ConnectivityManagerHidden {\n    /**\n     * Firewall chain for device idle (doze mode).\n     * Allowlist of apps that have network access in device idle.\n     */\n    @RequiresApi(Build.VERSION_CODES.TIRAMISU)\n    public static final int FIREWALL_CHAIN_DOZABLE = 1;\n\n    /**\n     * Firewall chain used for app standby.\n     * Denylist of apps that do not have network access.\n     */\n    @RequiresApi(Build.VERSION_CODES.TIRAMISU)\n    public static final int FIREWALL_CHAIN_STANDBY = 2;\n\n    /**\n     * Firewall chain used for battery saver.\n     * Allowlist of apps that have network access when battery saver is on.\n     */\n    @RequiresApi(Build.VERSION_CODES.TIRAMISU)\n    public static final int FIREWALL_CHAIN_POWERSAVE = 3;\n\n    /**\n     * Firewall chain used for restricted networking mode.\n     * Allowlist of apps that have access in restricted networking mode.\n     */\n    @RequiresApi(Build.VERSION_CODES.TIRAMISU)\n    public static final int FIREWALL_CHAIN_RESTRICTED = 4;\n\n    /**\n     * Firewall chain used for low power standby.\n     * Allowlist of apps that have access in low power standby.\n     */\n    @RequiresApi(Build.VERSION_CODES.TIRAMISU)\n    public static final int FIREWALL_CHAIN_LOW_POWER_STANDBY = 5;\n\n    /**\n     * Firewall chain used for lockdown VPN.\n     * Denylist of apps that cannot receive incoming packets except on loopback because they are\n     * subject to an always-on VPN which is not currently connected.\n     *\n     * @deprecated Removed in Android 14 (Upside Down Cake)\n     */\n    @RequiresApi(Build.VERSION_CODES.TIRAMISU)\n    public static final int FIREWALL_CHAIN_LOCKDOWN_VPN = 6;\n\n    /**\n     * Firewall chain used for always-on default background restrictions.\n     * Allowlist of apps that have access because either they are in the foreground or they are\n     * exempted for specific situations while in the background.\n     */\n    @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM)\n    public static final int FIREWALL_CHAIN_BACKGROUND = 6;\n\n    /**\n     * Firewall chain used for OEM-specific application restrictions.\n     * <p>\n     * Denylist of apps that will not have network access due to OEM-specific restrictions. If an\n     * app UID is placed on this chain, and the chain is enabled, the app's packets will be dropped.\n     * <p>\n     * All the {@code FIREWALL_CHAIN_OEM_DENY_x} chains are equivalent, and each one is\n     * independent of the others. The chains can be enabled and disabled independently, and apps can\n     * be added and removed from each chain independently.\n     *\n     * @see #FIREWALL_CHAIN_OEM_DENY_2\n     * @see #FIREWALL_CHAIN_OEM_DENY_3\n     */\n    @RequiresApi(Build.VERSION_CODES.TIRAMISU)\n    public static final int FIREWALL_CHAIN_OEM_DENY_1 = 7;\n\n    /**\n     * Firewall chain used for OEM-specific application restrictions.\n     * <p>\n     * Denylist of apps that will not have network access due to OEM-specific restrictions. If an\n     * app UID is placed on this chain, and the chain is enabled, the app's packets will be dropped.\n     * <p>\n     * All the {@code FIREWALL_CHAIN_OEM_DENY_x} chains are equivalent, and each one is\n     * independent of the others. The chains can be enabled and disabled independently, and apps can\n     * be added and removed from each chain independently.\n     *\n     * @see #FIREWALL_CHAIN_OEM_DENY_1\n     * @see #FIREWALL_CHAIN_OEM_DENY_3\n     */\n    @RequiresApi(Build.VERSION_CODES.TIRAMISU)\n    public static final int FIREWALL_CHAIN_OEM_DENY_2 = 8;\n\n    /**\n     * Firewall chain used for OEM-specific application restrictions.\n     * <p>\n     * Denylist of apps that will not have network access due to OEM-specific restrictions. If an\n     * app UID is placed on this chain, and the chain is enabled, the app's packets will be dropped.\n     * <p>\n     * All the {@code FIREWALL_CHAIN_OEM_DENY_x} chains are equivalent, and each one is\n     * independent of the others. The chains can be enabled and disabled independently, and apps can\n     * be added and removed from each chain independently.\n     *\n     * @see #FIREWALL_CHAIN_OEM_DENY_1\n     * @see #FIREWALL_CHAIN_OEM_DENY_2\n     */\n    @RequiresApi(Build.VERSION_CODES.TIRAMISU)\n    public static final int FIREWALL_CHAIN_OEM_DENY_3 = 9;\n\n    /**\n     * Firewall chain for allow list on metered networks\n     * <p>\n     * UIDs added to this chain have access to metered networks, unless they're also in one of the\n     * denylist, {@link #FIREWALL_CHAIN_METERED_DENY_USER},\n     * {@link #FIREWALL_CHAIN_METERED_DENY_ADMIN}\n     * <p>\n     * Note that this chain is used from a separate bpf program that is triggered by iptables and\n     * can not be controlled by {@link IConnectivityManager#setFirewallChainEnabled}.\n     */\n    // TODO: Merge this chain with data saver and support setFirewallChainEnabled\n    @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM)\n    public static final int FIREWALL_CHAIN_METERED_ALLOW = 10;\n\n    /**\n     * Firewall chain for user-set restrictions on metered networks\n     * <p>\n     * UIDs added to this chain do not have access to metered networks.\n     * UIDs should be added to this chain based on user settings.\n     * To restrict metered network based on admin configuration (e.g. enterprise policies),\n     * {@link #FIREWALL_CHAIN_METERED_DENY_ADMIN} should be used.\n     * This chain corresponds to {@code #BLOCKED_METERED_REASON_USER_RESTRICTED}\n     * <p>\n     * Note that this chain is used from a separate bpf program that is triggered by iptables and\n     * can not be controlled by {@link IConnectivityManager#setFirewallChainEnabled}.\n     */\n    // TODO: Support setFirewallChainEnabled to control this chain\n    @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM)\n    public static final int FIREWALL_CHAIN_METERED_DENY_USER = 11;\n\n    /**\n     * Firewall chain for admin-set restrictions on metered networks\n     * <p>\n     * UIDs added to this chain do not have access to metered networks.\n     * UIDs should be added to this chain based on admin configuration (e.g. enterprise policies).\n     * To restrict metered network based on user settings, {@link #FIREWALL_CHAIN_METERED_DENY_USER}\n     * should be used.\n     * This chain corresponds to {@code #BLOCKED_METERED_REASON_ADMIN_DISABLED}\n     * <p>\n     * Note that this chain is used from a separate bpf program that is triggered by iptables and\n     * can not be controlled by {@link IConnectivityManager#setFirewallChainEnabled}.\n     */\n    // TODO: Support setFirewallChainEnabled to control this chain\n    @RequiresApi(Build.VERSION_CODES.VANILLA_ICE_CREAM)\n    public static final int FIREWALL_CHAIN_METERED_DENY_ADMIN = 12;\n\n    /**\n     * A firewall rule which allows or drops packets depending on existing policy.\n     * Used by {@link IConnectivityManager#setUidFirewallRule(int, int, int)} to follow existing policy to handle\n     * specific uid's packets in specific firewall chain.\n     */\n    @RequiresApi(Build.VERSION_CODES.TIRAMISU)\n    public static final int FIREWALL_RULE_DEFAULT = 0;\n\n    /**\n     * A firewall rule which allows packets. Used by {@link IConnectivityManager#setUidFirewallRule(int, int, int)} to\n     * allow specific uid's packets in specific firewall chain.\n     */\n    @RequiresApi(Build.VERSION_CODES.TIRAMISU)\n    public static final int FIREWALL_RULE_ALLOW = 1;\n\n    /**\n     * A firewall rule which drops packets. Used by {@link IConnectivityManager#setUidFirewallRule(int, int, int)} to\n     * drop specific uid's packets in specific firewall chain.\n     */\n    @RequiresApi(Build.VERSION_CODES.TIRAMISU)\n    public static final int FIREWALL_RULE_DENY = 2;\n}\n"
  },
  {
    "path": "hiddenapi/src/main/java/android/net/IConnectivityManager.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage android.net;\n\nimport android.os.Build;\nimport android.os.IBinder;\nimport android.os.IInterface;\nimport android.os.RemoteException;\n\nimport androidx.annotation.RequiresApi;\n\nimport misc.utils.HiddenUtil;\n\npublic interface IConnectivityManager extends IInterface {\n    @RequiresApi(Build.VERSION_CODES.TIRAMISU)\n    void setUidFirewallRule(int chain, int uid, int rule) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)\n    int getUidFirewallRule(int chain, int uid) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.TIRAMISU)\n    void setFirewallChainEnabled(int chain, boolean enable) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)\n    boolean getFirewallChainEnabled(int chain) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.TIRAMISU)\n    void replaceFirewallChain(int chain, int[] uids) throws RemoteException;\n\n    abstract class Stub extends android.os.Binder implements IConnectivityManager {\n\n        public static IConnectivityManager asInterface(IBinder obj) {\n            return HiddenUtil.throwUOE(obj);\n        }\n\n        @Override\n        public IBinder asBinder() {\n            return this;\n        }\n    }\n}\n"
  },
  {
    "path": "hiddenapi/src/main/java/android/net/INetworkPolicyListener.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage android.net;\n\nimport android.os.IBinder;\nimport android.os.IInterface;\nimport android.os.RemoteException;\n\npublic interface INetworkPolicyListener extends IInterface {\n\n    void onUidRulesChanged(int uid, int uidRules) throws RemoteException;\n\n    void onMeteredIfacesChanged(java.lang.String[] meteredIfaces) throws RemoteException;\n\n    void onRestrictBackgroundChanged(boolean restrictBackground) throws RemoteException;\n\n    void onUidPoliciesChanged(int uid, int uidPolicies) throws RemoteException;\n\n    void onSubscriptionOverride(int subId, int overrideMask, int overrideValue) throws RemoteException;\n\n    abstract class Stub extends android.os.Binder implements INetworkPolicyListener {\n\n        public static INetworkPolicyListener asInterface(IBinder obj) {\n            throw new UnsupportedOperationException();\n        }\n\n        @Override\n        public IBinder asBinder() {\n            return this;\n        }\n    }\n}\n"
  },
  {
    "path": "hiddenapi/src/main/java/android/net/INetworkPolicyManager.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage android.net;\n\nimport android.os.Binder;\nimport android.os.Build;\nimport android.os.IBinder;\nimport android.os.IInterface;\nimport android.os.RemoteException;\n\nimport androidx.annotation.RequiresApi;\n\npublic interface INetworkPolicyManager extends IInterface {\n    /**\n     * Control UID policies.\n     */\n    void setUidPolicy(int uid, int policy) throws RemoteException;\n\n    void addUidPolicy(int uid, int policy) throws RemoteException;\n\n    void removeUidPolicy(int uid, int policy) throws RemoteException;\n\n    int getUidPolicy(int uid) throws RemoteException;\n\n    int[] getUidsWithPolicy(int policy) throws RemoteException;\n\n    void registerListener(INetworkPolicyListener listener) throws RemoteException;\n\n    void unregisterListener(INetworkPolicyListener listener) throws RemoteException;\n\n    /**\n     * Control if background data is restricted system-wide.\n     */\n    void setRestrictBackground(boolean restrictBackground) throws RemoteException;\n\n    boolean getRestrictBackground() throws RemoteException;\n\n    /**\n     * Gets the restrict background status based on the caller's UID:\n     * 1 - disabled\n     * 2 - whitelisted\n     * 3 - enabled\n     */\n    @RequiresApi(Build.VERSION_CODES.N)\n    int getRestrictBackgroundByCaller() throws RemoteException;\n\n    abstract class Stub extends Binder implements INetworkPolicyManager {\n        public static INetworkPolicyManager asInterface(IBinder obj) {\n            throw new UnsupportedOperationException();\n        }\n    }\n}"
  },
  {
    "path": "hiddenapi/src/main/java/android/net/INetworkStatsService.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage android.net;\n\nimport android.os.Build;\nimport android.os.IInterface;\nimport android.os.RemoteException;\n\nimport androidx.annotation.RequiresApi;\n\nimport misc.utils.HiddenUtil;\n\npublic interface INetworkStatsService extends IInterface {\n    /**\n     * Start a statistics query session. In Android Lollipop, this requires the permission\n     * {@code android.permission.READ_NETWORK_USAGE_HISTORY}\n     */\n    INetworkStatsSession openSession() throws RemoteException;\n\n    /**\n     * Start a statistics query session. If calling package is profile or device owner then it is\n     * granted automatic access if apiLevel is NetworkStatsManager.API_LEVEL_DPC_ALLOWED. If\n     * apiLevel is at least NetworkStatsManager.API_LEVEL_REQUIRES_PACKAGE_USAGE_STATS then\n     * PACKAGE_USAGE_STATS permission is always checked. If PACKAGE_USAGE_STATS is not granted\n     * READ_NETWORK_USAGE_STATS is checked for.\n     */\n    @RequiresApi(Build.VERSION_CODES.M)\n    INetworkStatsSession openSessionForUsageStats(String callingPackage) throws RemoteException;\n\n    /**\n     * Start a statistics query session. If calling package is profile or device owner then it is\n     * granted automatic access if apiLevel is NetworkStatsManager.API_LEVEL_DPC_ALLOWED. If\n     * apiLevel is at least NetworkStatsManager.API_LEVEL_REQUIRES_PACKAGE_USAGE_STATS then\n     * PACKAGE_USAGE_STATS permission is always checked. If PACKAGE_USAGE_STATS is not granted\n     * READ_NETWORK_USAGE_STATS is checked for.\n     */\n    @RequiresApi(Build.VERSION_CODES.O_MR1)\n    INetworkStatsSession openSessionForUsageStats(int flags, String callingPackage) throws RemoteException;\n\n    abstract class Stub {\n        public static INetworkStatsService asInterface(android.os.IBinder obj) {\n            return HiddenUtil.throwUOE(obj);\n        }\n    }\n}\n"
  },
  {
    "path": "hiddenapi/src/main/java/android/net/INetworkStatsSession.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage android.net;\n\nimport android.os.Build;\nimport android.os.IInterface;\nimport android.os.RemoteException;\n\nimport androidx.annotation.RequiresApi;\n\npublic interface INetworkStatsSession extends IInterface {\n    /**\n     * Return device aggregated network layer usage summary for traffic that matches template.\n     */\n    @RequiresApi(Build.VERSION_CODES.M)\n    NetworkStats getDeviceSummaryForNetwork(NetworkTemplate template, long start, long end) throws RemoteException;\n\n    /**\n     * Return network layer usage summary for traffic that matches template.\n     */\n    NetworkStats getSummaryForNetwork(NetworkTemplate template, long start, long end) throws RemoteException;\n//    /** Return historical network layer stats for traffic that matches template. */\n//    NetworkStatsHistory getHistoryForNetwork(NetworkTemplate template, int fields) throws RemoteException;\n//    /**\n//     * Return historical network layer stats for traffic that matches template, start and end\n//     * timestamp.\n//     */\n//    @RequiresApi(Build.VERSION_CODES.TIRAMISU)\n//    NetworkStatsHistory getHistoryIntervalForNetwork(NetworkTemplate template, int fields, long start, long end) throws RemoteException;\n\n    /**\n     * Return network layer usage summary per UID for traffic that matches template.\n     *\n     * <p>The resulting {@code NetworkStats#getElapsedRealtime()} contains time delta between\n     * {@code start} and {@code end}.\n     *\n     * @param template    - a predicate to filter netstats.\n     * @param start       - start of the range, timestamp in milliseconds since the epoch.\n     * @param end         - end of the range, timestamp in milliseconds since the epoch.\n     * @param includeTags - includes data usage tags if true.\n     */\n    NetworkStats getSummaryForAllUid(NetworkTemplate template, long start, long end, boolean includeTags) throws RemoteException;\n\n    /**\n     * Return network layer usage summary per UID for tagged traffic that matches template.\n     */\n    @RequiresApi(Build.VERSION_CODES.TIRAMISU)\n    NetworkStats getTaggedSummaryForAllUid(NetworkTemplate template, long start, long end);\n//    /** Return historical network layer stats for specific UID traffic that matches template. */\n//    NetworkStatsHistory getHistoryForUid(NetworkTemplate template, int uid, int set, int tag, int fields) throws RemoteException;\n//    /** Return historical network layer stats for specific UID traffic that matches template. */\n//    @RequiresApi(Build.VERSION_CODES.M)\n//    NetworkStatsHistory getHistoryIntervalForUid(NetworkTemplate template, int uid, int set, int tag, int fields, long start, long end) throws RemoteException;\n\n    /**\n     * Return array of uids that have stats and are accessible to the calling user\n     */\n    @RequiresApi(Build.VERSION_CODES.M)\n    int[] getRelevantUids() throws RemoteException;\n\n    void close() throws RemoteException;\n}"
  },
  {
    "path": "hiddenapi/src/main/java/android/net/NetworkPolicyManager.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage android.net;\n\n/**\n * Manager for creating and modifying network policy rules.\n */\npublic class NetworkPolicyManager {\n    /* POLICY_* are masks and can be ORed, although currently they are not. */\n    /**\n     * No specific network policy, use system default.\n     */\n    public static final int POLICY_NONE = 0;\n    /**\n     * Reject network usage on metered networks when application in background.\n     */\n    public static final int POLICY_REJECT_METERED_BACKGROUND = 1;\n    /**\n     * Allow metered network use in the background even when in data usage save mode.\n     */\n    public static final int POLICY_ALLOW_METERED_BACKGROUND = 1 << 2;\n}"
  },
  {
    "path": "hiddenapi/src/main/java/android/net/NetworkStats.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage android.net;\n\nimport android.os.Parcel;\nimport android.os.Parcelable;\n\nimport androidx.annotation.Nullable;\n\nimport misc.utils.HiddenUtil;\n\n/**\n * Collection of active network statistics. Can contain summary details across\n * all interfaces, or details with per-UID granularity. Internally stores data\n * as a large table, closely matching {@code /proc/} data format.\n */\npublic class NetworkStats implements Parcelable {\n    public static class Entry {\n        public String iface;\n        public int uid;\n        public int set;\n        public int tag;\n        public long rxBytes;\n        public long rxPackets;\n        public long txBytes;\n        public long txPackets;\n        public long operations;\n\n        public Entry() {\n            HiddenUtil.throwUOE();\n        }\n    }\n\n    public NetworkStats(Parcel parcel) {\n        HiddenUtil.throwUOE(parcel);\n    }\n\n    @Override\n    public void writeToParcel(Parcel dest, int flags) {\n    }\n\n    /**\n     * Return specific stats entry.\n     */\n    public Entry getValues(int i, @Nullable Entry recycle) {\n        return HiddenUtil.throwUOE(i, recycle);\n    }\n\n    public int size() {\n        return HiddenUtil.throwUOE();\n    }\n\n    @Override\n    public int describeContents() {\n        return 0;\n    }\n\n    public static final Creator<NetworkStats> CREATOR = HiddenUtil.creator();\n}"
  },
  {
    "path": "hiddenapi/src/main/java/android/net/NetworkTemplate.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage android.net;\n\nimport android.os.Parcel;\nimport android.os.Parcelable;\n\nimport androidx.annotation.Nullable;\n\nimport misc.utils.HiddenUtil;\n\npublic class NetworkTemplate implements Parcelable {\n\n    // public static final int MATCH_MOBILE_ALL = 1;\n    public static final int MATCH_WIFI = 4;\n\n    /**\n     * Template to match {@link ConnectivityManager#TYPE_MOBILE} networks with\n     * the given IMSI.\n     */\n    public static NetworkTemplate buildTemplateMobileAll(String subscriberId) {\n        return HiddenUtil.throwUOE(subscriberId);\n    }\n\n    /**\n     * Template to match {@link ConnectivityManager#TYPE_MOBILE} networks,\n     * regardless of IMSI.\n     */\n    public static NetworkTemplate buildTemplateMobileWildcard() {\n        return HiddenUtil.throwUOE();\n    }\n\n    /**\n     * Template to match all {@link ConnectivityManager#TYPE_WIFI} networks,\n     * regardless of SSID.\n     */\n    public static NetworkTemplate buildTemplateWifiWildcard() {\n        return HiddenUtil.throwUOE();\n    }\n\n    public NetworkTemplate(int matchRule, @Nullable String subscriberId, @Nullable String networkId) {\n        HiddenUtil.throwUOE(matchRule, subscriberId, networkId);\n    }\n\n    private NetworkTemplate(Parcel in) {\n        HiddenUtil.throwUOE(in);\n    }\n\n    @Override\n    public void writeToParcel(Parcel dest, int flags) {\n        HiddenUtil.throwUOE(dest, flags);\n    }\n\n    @Override\n    public int describeContents() {\n        return 0;\n    }\n\n    public static final Creator<NetworkTemplate> CREATOR = HiddenUtil.creator();\n}"
  },
  {
    "path": "hiddenapi/src/main/java/android/os/IBinderHidden.java",
    "content": "// SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-or-later\n\npackage android.os;\n\nimport androidx.annotation.Nullable;\nimport androidx.annotation.RequiresApi;\n\nimport java.io.FileDescriptor;\n\nimport dev.rikka.tools.refine.RefineAs;\n\n@RefineAs(IBinder.class)\npublic interface IBinderHidden {\n    /**\n     * @deprecated Replaced in Android 8 (Oreo) by {@link #shellCommand(FileDescriptor, FileDescriptor, FileDescriptor, String[], ShellCallback, ResultReceiver)}\n     */\n    @Deprecated\n    @RequiresApi(Build.VERSION_CODES.N)\n    void shellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,\n                      String[] args, ResultReceiver resultReceiver) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.O)\n    void shellCommand(FileDescriptor in, FileDescriptor out, FileDescriptor err,\n                      String[] args, @Nullable ShellCallback shellCallback,\n                      ResultReceiver resultReceiver) throws RemoteException;\n}\n"
  },
  {
    "path": "hiddenapi/src/main/java/android/os/IDeviceIdleController.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage android.os;\n\nimport androidx.annotation.RequiresApi;\n\nimport misc.utils.HiddenUtil;\n\n@RequiresApi(Build.VERSION_CODES.M)\npublic interface IDeviceIdleController extends IInterface {\n    void addPowerSaveWhitelistApp(String name) throws RemoteException;\n    void removePowerSaveWhitelistApp(String name) throws RemoteException;\n\n    boolean isPowerSaveWhitelistExceptIdleApp(String name) throws RemoteException;\n    boolean isPowerSaveWhitelistApp(String name) throws RemoteException;\n\n    abstract class Stub {\n        public static IDeviceIdleController asInterface(android.os.IBinder obj) {\n            return HiddenUtil.throwUOE(obj);\n        }\n    }\n}\n"
  },
  {
    "path": "hiddenapi/src/main/java/android/os/IUserManager.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage android.os;\n\nimport android.annotation.UserIdInt;\nimport android.content.pm.UserInfo;\n\nimport androidx.annotation.RequiresApi;\n\nimport java.util.List;\n\nimport misc.utils.HiddenUtil;\n\npublic interface IUserManager extends IInterface {\n    UserInfo getPrimaryUser() throws RemoteException;\n\n    List<UserInfo> getUsers(boolean excludeDying) throws RemoteException;\n\n    // Changed in 10.0.0_r30\n    @RequiresApi(Build.VERSION_CODES.Q)\n    List<UserInfo> getUsers(boolean excludePartial, boolean excludeDying, boolean excludePreCreated)\n            throws RemoteException;\n\n    List<UserInfo> getProfiles(@UserIdInt int userId, boolean enabledOnly);\n\n    int getManagedProfileBadge(int userId) throws RemoteException;\n\n    boolean hasUserRestriction(String restrictionKey, int userHandle) throws RemoteException;\n\n    abstract class Stub {\n        public static IUserManager asInterface(android.os.IBinder obj) {\n            return HiddenUtil.throwUOE(obj);\n        }\n    }\n}\n"
  },
  {
    "path": "hiddenapi/src/main/java/android/os/ResultReceiver.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage android.os;\n\nimport androidx.annotation.NonNull;\n\nimport misc.utils.HiddenUtil;\n\n/**\n * Generic interface for receiving a callback result from someone.  Use this\n * by creating a subclass and implement {@link #onReceiveResult}, which you can\n * then pass to others and send through IPC, and receive results they\n * supply with {@link #send}.\n *\n * <p>Note: the implementation underneath is just a simple wrapper around\n * a {@link Binder} that is used to perform the communication.  This means\n * semantically you should treat it as such: this class does not impact process\n * lifecycle management (you must be using some higher-level component to tell\n * the system that your process needs to continue running), the connection will\n * break if your process goes away for any reason, etc.</p>\n */\npublic class ResultReceiver implements Parcelable {\n    /**\n     * Create a new ResultReceive to receive results.  Your\n     * {@link #onReceiveResult} method will be called from the thread running\n     * <var>handler</var> if given, or from an arbitrary thread if null.\n     */\n    public ResultReceiver(Handler handler) {\n        HiddenUtil.throwUOE(handler);\n    }\n\n    /**\n     * Deliver a result to this receiver.  Will call {@link #onReceiveResult},\n     * always asynchronously if the receiver has supplied a Handler in which\n     * to dispatch the result.\n     *\n     * @param resultCode Arbitrary result code to deliver, as defined by you.\n     * @param resultData Any additional data provided by you.\n     */\n    public void send(int resultCode, Bundle resultData) {\n        HiddenUtil.throwUOE(resultCode, resultData);\n    }\n\n    /**\n     * Override to receive results delivered to this object.\n     *\n     * @param resultCode Arbitrary result code delivered by the sender, as\n     *                   defined by the sender.\n     * @param resultData Any additional data provided by the sender.\n     */\n    protected void onReceiveResult(int resultCode, Bundle resultData) {\n    }\n\n    public int describeContents() {\n        return 0;\n    }\n\n    public void writeToParcel(@NonNull Parcel out, int flags) {\n        HiddenUtil.throwUOE(out, flags);\n    }\n\n    public static final Parcelable.Creator<ResultReceiver> CREATOR\n            = new Parcelable.Creator<ResultReceiver>() {\n        public ResultReceiver createFromParcel(Parcel in) {\n            return HiddenUtil.throwUOE(in);\n        }\n\n        public ResultReceiver[] newArray(int size) {\n            return new ResultReceiver[size];\n        }\n    };\n}"
  },
  {
    "path": "hiddenapi/src/main/java/android/os/SELinux.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage android.os;\n\nimport java.io.File;\n\nimport misc.utils.HiddenUtil;\n\npublic class SELinux {\n    /**\n     * Determine whether SELinux is disabled or enabled.\n     *\n     * @return a boolean indicating whether SELinux is enabled.\n     */\n    public static final native boolean isSELinuxEnabled();\n\n    /**\n     * Determine whether SELinux is permissive or enforcing.\n     *\n     * @return a boolean indicating whether SELinux is enforcing.\n     */\n    public static final native boolean isSELinuxEnforced();\n\n    /**\n     * Change the security context of an existing file object.\n     *\n     * @param path    representing the path of file object to relabel.\n     * @param context new security context given as a String.\n     * @return a boolean indicating whether the operation succeeded.\n     */\n    public static final native boolean setFileContext(String path, String context);\n\n    /**\n     * Get the security context of a file object.\n     *\n     * @param path the pathname of the file object.\n     * @return a security context given as a String.\n     */\n    public static final native String getFileContext(String path);\n\n    /**\n     * Gets the security context of the current process.\n     *\n     * @return a String representing the security context of the current process.\n     */\n    public static final native String getContext();\n\n    /**\n     * Gets the security context of a given process id.\n     *\n     * @param pid an int representing the process id to check.\n     * @return a String representing the security context of the given pid.\n     */\n    public static final native String getPidContext(int pid);\n\n    /**\n     * Check permissions between two security contexts.\n     *\n     * @param scon   The source or subject security context.\n     * @param tcon   The target or object security context.\n     * @param tclass The object security class name.\n     * @param perm   The permission name.\n     * @return a boolean indicating whether permission was granted.\n     */\n    public static final native boolean checkSELinuxAccess(String scon, String tcon, String tclass, String perm);\n\n    /**\n     * Restores a file to its default SELinux security context.\n     * If the system is not compiled with SELinux, then {@code true}\n     * is automatically returned.\n     * If SELinux is compiled in, but disabled, then {@code true} is\n     * returned.\n     *\n     * @param pathname The pathname of the file to be relabeled.\n     * @return a boolean indicating whether the relabeling succeeded.\n     * @throws NullPointerException if the pathname is a null object.\n     */\n    public static boolean restorecon(String pathname) throws NullPointerException {\n        return HiddenUtil.throwUOE(pathname);\n    }\n\n    /**\n     * Restores a file to its default SELinux security context.\n     * If the system is not compiled with SELinux, then {@code true}\n     * is automatically returned.\n     * If SELinux is compiled in, but disabled, then {@code true} is\n     * returned.\n     *\n     * @param file The File object representing the path to be relabeled.\n     * @return a boolean indicating whether the relabeling succeeded.\n     * @throws NullPointerException if the file is a null object.\n     */\n    public static boolean restorecon(File file) throws NullPointerException {\n        return HiddenUtil.throwUOE(file);\n    }\n\n    /**\n     * Recursively restores all files under the given path to their default\n     * SELinux security context. If the system is not compiled with SELinux,\n     * then {@code true} is automatically returned. If SELinux is compiled in,\n     * but disabled, then {@code true} is returned.\n     *\n     * @return a boolean indicating whether the relabeling succeeded.\n     */\n    public static boolean restoreconRecursive(File file) {\n        return HiddenUtil.throwUOE(file);\n    }\n}\n"
  },
  {
    "path": "hiddenapi/src/main/java/android/os/ServiceManager.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage android.os;\n\nimport androidx.annotation.Nullable;\n\nimport misc.utils.HiddenUtil;\n\npublic class ServiceManager {\n    @Nullable\n    public static IBinder getService(String name) {\n        return HiddenUtil.throwUOE(name);\n    }\n\n    public static void addService(String name, IBinder service) {\n        HiddenUtil.throwUOE(name, service);\n    }\n}\n"
  },
  {
    "path": "hiddenapi/src/main/java/android/os/ServiceSpecificException.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage android.os;\n\nimport androidx.annotation.RequiresApi;\n\nimport misc.utils.HiddenUtil;\n\n@RequiresApi(Build.VERSION_CODES.N)\npublic class ServiceSpecificException extends RuntimeException {\n    public final int errorCode = HiddenUtil.throwUOE();\n}"
  },
  {
    "path": "hiddenapi/src/main/java/android/os/ShellCallback.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage android.os;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.RequiresApi;\n\nimport misc.utils.HiddenUtil;\n\n/**\n * Special-purpose API for use with {@link IBinderHidden#shellCommand IBinder.shellCommand} for\n * performing operations back on the invoking shell.\n */\n@RequiresApi(Build.VERSION_CODES.O)\npublic class ShellCallback implements Parcelable {\n    /**\n     * Create a new ShellCallback to receive requests.\n     */\n    public ShellCallback() {\n        HiddenUtil.throwUOE();\n    }\n\n    /**\n     * Ask the shell to open a file for writing.  This will truncate the file if it\n     * already exists.  It will create the file if it doesn't exist.\n     *\n     * @param path           Path of the file to be opened/created.\n     * @param seLinuxContext Optional SELinux context that must be allowed to have\n     *                       access to the file; if null, nothing is required.\n     * @deprecated Replaced in Android 9 (Pie) by {@link #openFile(String, String, String)}\n     */\n    @Deprecated\n    public ParcelFileDescriptor openOutputFile(String path, String seLinuxContext) {\n        return HiddenUtil.throwUOE(path, seLinuxContext);\n    }\n\n    /**\n     * @deprecated Replaced in Android 9 (Pie) by {@link #onOpenFile(String, String, String)}\n     */\n    @Deprecated\n    public ParcelFileDescriptor onOpenOutputFile(String path, String seLinuxContext) {\n        return HiddenUtil.throwUOE(path, seLinuxContext);\n    }\n\n    /**\n     * Ask the shell to open a file.  If opening for writing, will truncate the file if it\n     * already exists and will create the file if it doesn't exist.\n     *\n     * @param path           Path of the file to be opened/created.\n     * @param seLinuxContext Optional SELinux context that must be allowed to have\n     *                       access to the file; if null, nothing is required.\n     * @param mode           Mode to open file in: \"r\" for input/reading an existing file,\n     *                       \"r+\" for reading/writing an existing file, \"w\" for output/writing a new file (either\n     *                       creating or truncating an existing one), \"w+\" for reading/writing a new file (either\n     *                       creating or truncating an existing one).\n     */\n    @RequiresApi(Build.VERSION_CODES.P)\n    @Nullable\n    public ParcelFileDescriptor openFile(String path, String seLinuxContext, String mode) {\n        return HiddenUtil.throwUOE(path, seLinuxContext, mode);\n    }\n\n    @RequiresApi(Build.VERSION_CODES.P)\n    @Nullable\n    public ParcelFileDescriptor onOpenFile(String path, String seLinuxContext, String mode) {\n        return HiddenUtil.throwUOE(path, seLinuxContext, mode);\n    }\n\n    public static void writeToParcel(@Nullable ShellCallback callback, Parcel out) {\n        HiddenUtil.throwUOE(callback, out);\n    }\n\n    public int describeContents() {\n        return 0;\n    }\n\n    public void writeToParcel(@NonNull Parcel out, int flags) {\n        HiddenUtil.throwUOE(out, flags);\n    }\n\n    @RequiresApi(Build.VERSION_CODES.S)\n    public IBinder getShellCallbackBinder() {\n        return HiddenUtil.throwUOE();\n    }\n\n    public static final Parcelable.Creator<ShellCallback> CREATOR\n            = new Parcelable.Creator<ShellCallback>() {\n        public ShellCallback createFromParcel(Parcel in) {\n            return HiddenUtil.throwUOE(in);\n        }\n\n        public ShellCallback[] newArray(int size) {\n            return new ShellCallback[size];\n        }\n    };\n}"
  },
  {
    "path": "hiddenapi/src/main/java/android/os/SystemProperties.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage android.os;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport misc.utils.HiddenUtil;\n\npublic class SystemProperties {\n    /**\n     * Get the String value for the given {@code key}.\n     *\n     * @param key the key to lookup\n     * @return an empty string if the {@code key} isn't found\n     */\n    public static String get(@NonNull String key) {\n        return HiddenUtil.throwUOE(key);\n    }\n\n    /**\n     * Get the String value for the given {@code key}.\n     *\n     * @param key the key to lookup\n     * @param def the default value in case the property is not set or empty\n     * @return if the {@code key} isn't found, return {@code def} if it isn't null, or an empty\n     * string otherwise\n     */\n    @NonNull\n    public static String get(@NonNull String key, @Nullable String def) {\n        return HiddenUtil.throwUOE(key, def);\n    }\n\n    /**\n     * Get the value for the given key, and return as an integer.\n     *\n     * @param key the key to lookup\n     * @param def a default value to return\n     * @return the key parsed as an integer, or def if the key isn't found or\n     * cannot be parsed\n     * @throws IllegalArgumentException if the key exceeds 32 characters\n     */\n    public static int getInt(String key, int def) {\n        return HiddenUtil.throwUOE(key, def);\n    }\n\n    /**\n     * Get the value for the given key, and return as a long.\n     *\n     * @param key the key to lookup\n     * @param def a default value to return\n     * @return the key parsed as a long, or def if the key isn't found or\n     * cannot be parsed\n     * @throws IllegalArgumentException if the key exceeds 32 characters\n     */\n    public static long getLong(String key, long def) {\n        return HiddenUtil.throwUOE(key, def);\n    }\n\n    /**\n     * Get the value for the given key, returned as a boolean.\n     * Values 'n', 'no', '0', 'false' or 'off' are considered false.\n     * Values 'y', 'yes', '1', 'true' or 'on' are considered true.\n     * (case sensitive).\n     * If the key does not exist, or has any other value, then the default\n     * result is returned.\n     *\n     * @param key the key to lookup\n     * @param def a default value to return\n     * @return the key parsed as a boolean, or def if the key isn't found or is\n     * not able to be parsed as a boolean.\n     * @throws IllegalArgumentException if the key exceeds 32 characters\n     */\n    public static boolean getBoolean(String key, boolean def) {\n        return HiddenUtil.throwUOE(key, def);\n    }\n}"
  },
  {
    "path": "hiddenapi/src/main/java/android/os/UserHandleHidden.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage android.os;\n\nimport android.annotation.AppIdInt;\nimport android.annotation.UserIdInt;\n\nimport dev.rikka.tools.refine.RefineAs;\nimport misc.utils.HiddenUtil;\n\n@RefineAs(UserHandle.class)\npublic class UserHandleHidden {\n    /**\n     * A user id to indicate all users on the device\n     */\n    @UserIdInt\n    public static final int USER_ALL = -1;\n\n    /**\n     * An undefined user id\n     */\n    @UserIdInt\n    public static final int USER_NULL = -10000;\n\n    /**\n     * Checks to see if the user id is the same for the two uids, i.e., they belong to the same\n     * user.\n     */\n    public static boolean isSameUser(int uid1, int uid2) {\n        return HiddenUtil.throwUOE(uid1, uid2);\n    }\n\n    /**\n     * Checks to see if both uids are referring to the same app id, ignoring the user id part of the\n     * uids.\n     *\n     * @param uid1 uid to compare\n     * @param uid2 other uid to compare\n     * @return whether the appId is the same for both uids\n     */\n    public static boolean isSameApp(int uid1, int uid2) {\n        return HiddenUtil.throwUOE(uid1, uid2);\n    }\n\n    /**\n     * Whether a UID is an \"isolated\" UID.\n     */\n    public static boolean isIsolated(int uid) {\n        return HiddenUtil.throwUOE(uid);\n    }\n\n    /**\n     * Whether a UID belongs to a regular app. *Note* \"Not a regular app\" does not mean\n     * \"it's system\", because of isolated UIDs. Use {@code #isCore} for that.\n     */\n    public static boolean isApp(int uid) {\n        return HiddenUtil.throwUOE(uid);\n    }\n\n    /**\n     * Returns the user id for a given uid.\n     */\n    @UserIdInt\n    public static int getUserId(int uid) {\n        return HiddenUtil.throwUOE(uid);\n    }\n\n    /**\n     * Returns the uid that is composed from the userId and the appId.\n     */\n    public static int getUid(@UserIdInt int userId, @AppIdInt int appId) {\n        return HiddenUtil.throwUOE(userId, appId);\n    }\n\n    /**\n     * Returns the app id (or base uid) for a given uid, stripping out the user id from it.\n     */\n    @AppIdInt\n    public static int getAppId(int uid) {\n        return HiddenUtil.throwUOE(uid);\n    }\n\n    /**\n     * Returns the user id of the current process\n     *\n     * @return user id of the current process\n     */\n    @UserIdInt\n    public static int myUserId() {\n        return HiddenUtil.throwUOE();\n    }\n\n    /**\n     * Generate a text representation of the uid, breaking out its individual\n     * components -- user, app, isolated, etc.\n     */\n    public static void formatUid(StringBuilder sb, int uid) {\n        HiddenUtil.throwUOE(sb, uid);\n    }\n\n    public int getIdentifier() {\n        return HiddenUtil.throwUOE();\n    }\n}"
  },
  {
    "path": "hiddenapi/src/main/java/android/os/storage/IMountService.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage android.os.storage;\n\nimport android.os.Build;\nimport android.os.IInterface;\nimport android.os.RemoteException;\n\nimport androidx.annotation.RequiresApi;\n\nimport misc.utils.HiddenUtil;\n\n/**\n * @deprecated Replaced with {@link IStorageManager} in SDK 26 (Android O)\n */\n@Deprecated\npublic interface IMountService extends IInterface {\n    /**\n     * Returns list of all mountable volumes.\n     *\n     * @deprecated Replaced by {@link #getVolumeList(int, String, int)} in SDK 23 (Android M)\n     */\n    @Deprecated\n    StorageVolume[] getVolumeList() throws RemoteException;\n\n    /**\n     * Returns list of all mountable volumes.\n     */\n    @RequiresApi(Build.VERSION_CODES.M)\n    StorageVolume[] getVolumeList(int uid, String packageName, int flags) throws RemoteException;\n\n    abstract class Stub {\n        public static IMountService asInterface(android.os.IBinder obj) {\n            return HiddenUtil.throwUOE(obj);\n        }\n    }\n}"
  },
  {
    "path": "hiddenapi/src/main/java/android/os/storage/IStorageManager.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage android.os.storage;\n\nimport android.os.Build;\nimport android.os.IInterface;\nimport android.os.RemoteException;\n\nimport androidx.annotation.RequiresApi;\n\nimport misc.utils.HiddenUtil;\n\n@RequiresApi(Build.VERSION_CODES.O)\npublic interface IStorageManager extends IInterface {\n    /**\n     * Returns list of all mountable volumes for the specified userId\n     */\n    // userId was uid and callingPackage was packageName until Android 13\n    StorageVolume[] getVolumeList(int uidOrA13UserId, String callingPackage, int flags) throws RemoteException;\n\n    abstract class Stub {\n        public static IStorageManager asInterface(android.os.IBinder obj) {\n            return HiddenUtil.throwUOE(obj);\n        }\n    }\n}\n"
  },
  {
    "path": "hiddenapi/src/main/java/android/os/storage/StorageManagerHidden.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage android.os.storage;\n\nimport android.os.Build;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.RequiresApi;\n\nimport java.util.UUID;\n\nimport dev.rikka.tools.refine.RefineAs;\nimport misc.utils.HiddenUtil;\n\n@RefineAs(StorageManager.class)\npublic class StorageManagerHidden {\n    @RequiresApi(Build.VERSION_CODES.M)\n    public static /*final*/ int FLAG_FOR_WRITE = 1;  // 1 << 8 in later versions\n\n    /**\n     * Returns list of all mountable volumes.\n     */\n    @Nullable // @NonNull since Android 6 (M)\n    public StorageVolume[] getVolumeList() {\n        return HiddenUtil.throwUOE();\n    }\n\n    @RequiresApi(Build.VERSION_CODES.M)\n    @NonNull\n    public static StorageVolume[] getVolumeList(int userId, int flags) {\n        return HiddenUtil.throwUOE(userId, flags);\n    }\n\n    @RequiresApi(Build.VERSION_CODES.O)\n    public static UUID convert(String uuid) {\n        return HiddenUtil.throwUOE(uuid);\n    }\n\n    @RequiresApi(Build.VERSION_CODES.O)\n    public static String convert(UUID storageUuid) {\n        return HiddenUtil.throwUOE(storageUuid);\n    }\n}\n"
  },
  {
    "path": "hiddenapi/src/main/java/android/os/storage/StorageVolumeHidden.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage android.os.storage;\n\nimport java.io.File;\n\nimport dev.rikka.tools.refine.RefineAs;\nimport misc.utils.HiddenUtil;\n\n@RefineAs(StorageVolume.class)\npublic final class StorageVolumeHidden {\n    public File getPathFile() {\n        return HiddenUtil.throwUOE();\n    }\n\n    public String getUserLabel() {\n        return HiddenUtil.throwUOE();\n    }\n}\n"
  },
  {
    "path": "hiddenapi/src/main/java/android/permission/IOnPermissionsChangeListener.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage android.permission;\n\nimport android.os.IInterface;\n\ninterface IOnPermissionsChangeListener extends IInterface {\n    void onPermissionsChanged(int uid);\n}"
  },
  {
    "path": "hiddenapi/src/main/java/android/permission/IPermissionManager.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage android.permission;\n\nimport android.content.pm.ParceledListSlice;\nimport android.content.pm.PermissionGroupInfo;\nimport android.content.pm.PermissionInfo;\nimport android.content.pm.permission.SplitPermissionInfoParcelable;\nimport android.os.Binder;\nimport android.os.Build;\nimport android.os.IBinder;\nimport android.os.IInterface;\nimport android.os.RemoteException;\n\nimport androidx.annotation.RequiresApi;\n\nimport java.util.List;\n\n/**\n * Interface to communicate directly with the permission manager service.\n *\n * @see PermissionManager\n */\n@RequiresApi(Build.VERSION_CODES.R)\npublic interface IPermissionManager extends IInterface {\n    /**\n     * @deprecated Removed in Android 12 (S), use {@link android.content.pm.IPackageManager#getAppOpPermissionPackages(String)} instead.\n     */\n    @Deprecated\n    String[] getAppOpPermissionPackages(String permName) throws RemoteException;\n\n    ParceledListSlice<PermissionGroupInfo> getAllPermissionGroups(int flags) throws RemoteException;\n\n    PermissionGroupInfo getPermissionGroupInfo(String groupName, int flags) throws RemoteException;\n\n    PermissionInfo getPermissionInfo(String permName, String packageName, int flags) throws RemoteException;\n\n    ParceledListSlice<PermissionInfo> queryPermissionsByGroup(String groupName, int flags) throws RemoteException;\n\n    boolean addPermission(PermissionInfo info, boolean async) throws RemoteException;\n\n    void removePermission(String name) throws RemoteException;\n\n    /**\n     * First two parameters are permuted since Android 12 (S)\n     *\n     * @deprecated Replaced in Android 14 r29 (Upside Down Cake) by {@link #getPermissionFlags(String, String, int, int)}\n     */\n    @Deprecated\n    int getPermissionFlags(String permName, String packageName, int userId) throws RemoteException;\n\n    /**\n     * @deprecated Replaced in Android 14 r50 (Upside Down Cake) by {@link #getPermissionFlags(String, String, String, int)}\n     */\n    @Deprecated\n    @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)\n    int getPermissionFlags(String packageName, String permName, int deviceId, int userId) throws RemoteException;\n\n    /**\n     * Introduced in Android 14.0.0_r50\n     */\n    @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)\n    int getPermissionFlags(String packageName, String permissionName, String persistentDeviceId,\n                           int userId) throws RemoteException;\n\n    /**\n     * First two parameters are permuted since Android 12 (S)\n     *\n     * @deprecated Replaced in Android 14 r29 (Upside Down Cake) by {@link #updatePermissionFlags(String, String, int, int, boolean, int, int)}\n     */\n    @Deprecated\n    void updatePermissionFlags(String permName, String packageName, int flagMask,\n                               int flagValues, boolean checkAdjustPolicyFlagPermission, int userId) throws RemoteException;\n\n    /**\n     * @deprecated Replaced in Android 14 r50 (Upside Down Cake) by {@link #updatePermissionFlags(String, String, int, int, boolean, String, int)}\n     */\n    @Deprecated\n    @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)\n    void updatePermissionFlags(String packageName, String permName, int flagMask,\n                               int flagValues, boolean checkAdjustPolicyFlagPermission, int deviceId, int userId) throws RemoteException;\n\n    /**\n     * Introduced in Android 14.0.0_r50\n     */\n    @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)\n    void updatePermissionFlags(String packageName, String permissionName, int flagMask,\n                               int flagValues, boolean checkAdjustPolicyFlagPermission, String persistentDeviceId,\n                               int userId) throws RemoteException;\n\n    void updatePermissionFlagsForAllApps(int flagMask, int flagValues, int userId) throws RemoteException;\n\n    /**\n     * @deprecated Removed in Android 12 (S), use {@link android.content.pm.IPackageManager#checkPermission(String, String, int)} instead.\n     */\n    @Deprecated\n    int checkPermission(String permName, String pkgName, int userId) throws RemoteException;\n\n    /**\n     * @deprecated Removed in Android 12 (S), use {@link android.content.pm.IPackageManager#checkUidPermission(String, int)} instead.\n     */\n    @Deprecated\n    int checkUidPermission(String permName, int uid) throws RemoteException;\n\n    /**\n     * @deprecated Removed in Android 12 (S)\n     */\n    @Deprecated\n    int checkDeviceIdentifierAccess(String packageName, String callingFeatureId, String message, int pid, int uid) throws RemoteException;\n\n    void addOnPermissionsChangeListener(IOnPermissionsChangeListener listener) throws RemoteException;\n\n    void removeOnPermissionsChangeListener(IOnPermissionsChangeListener listener) throws RemoteException;\n\n    /**\n     * @deprecated Removed in Android 12 (S)\n     */\n    @Deprecated\n    List<String> getWhitelistedRestrictedPermissions(String packageName, int flags, int userId) throws RemoteException;\n\n    /**\n     * @deprecated Removed in Android 12 (S)\n     */\n    @Deprecated\n    boolean addWhitelistedRestrictedPermission(String packageName, String permName,\n                                               int flags, int userId) throws RemoteException;\n\n    /**\n     * @deprecated Removed in Android 12 (S)\n     */\n    @Deprecated\n    boolean removeWhitelistedRestrictedPermission(String packageName, String permName,\n                                                  int flags, int userId) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.S)\n    List<String> getAllowlistedRestrictedPermissions(String packageName, int flags, int userId) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.S)\n    boolean addAllowlistedRestrictedPermission(String packageName, String permissionName, int flags, int userId)\n            throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.S)\n    boolean removeAllowlistedRestrictedPermission(String packageName, String permissionName, int flags, int userId)\n            throws RemoteException;\n\n    /**\n     * @deprecated Replaced in Android 14 r29 (Upside Down Cake) by {@link #grantRuntimePermission(String, String, int, int)}\n     */\n    @Deprecated\n    void grantRuntimePermission(String packageName, String permName, int userId) throws RemoteException;\n\n    /**\n     * @deprecated Replaced in Android 14 r50 (Upside Down Cake) by {@link #grantRuntimePermission(String, String, String, int)}\n     */\n    @Deprecated\n    @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)\n    void grantRuntimePermission(String packageName, String permName, int deviceId, int userId) throws RemoteException;\n\n    /**\n     * Introduced in Android 14.0.0_r50\n     */\n    @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)\n    void grantRuntimePermission(String packageName, String permissionName,\n                                String persistentDeviceId, int userId) throws RemoteException;\n\n    /**\n     * @deprecated Replaced in Android 14 r29 (Upside Down Cake) by {@link #revokeRuntimePermission(String, String, int, int, String)}\n     */\n    @Deprecated\n    void revokeRuntimePermission(String packageName, String permName, int userId, String reason) throws RemoteException;\n\n    /**\n     * @deprecated Replaced in Android 14 r50 (Upside Down Cake) by {@link #revokeRuntimePermission(String, String, String, int, String)}\n     */\n    @Deprecated\n    @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)\n    void revokeRuntimePermission(String packageName, String permName, int deviceId,\n                                 int userId, String reason) throws RemoteException;\n\n    /**\n     * Introduced in Android 14.0.0_r50\n     */\n    @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)\n    void revokeRuntimePermission(String packageName, String permissionName,\n                                 String persistentDeviceId, int userId, String reason) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.TIRAMISU)\n    void revokePostNotificationPermissionWithoutKillForTest(String packageName, int userId) throws RemoteException;\n\n    /**\n     * @deprecated Removed in Android 12 (S)\n     */\n    @Deprecated\n    void resetRuntimePermissions() throws RemoteException;\n\n    /**\n     * @deprecated Removed in Android 12 (S)\n     */\n    @Deprecated\n    boolean setDefaultBrowser(String packageName, int userId) throws RemoteException;\n\n    /**\n     * @deprecated Removed in Android 12 (S)\n     */\n    @Deprecated\n    String getDefaultBrowser(int userId) throws RemoteException;\n\n    /**\n     * @deprecated Removed in Android 12 (S)\n     */\n    @Deprecated\n    void grantDefaultPermissionsToEnabledCarrierApps(String[] packageNames, int userId) throws RemoteException;\n\n    /**\n     * @deprecated Removed in Android 12 (S)\n     */\n    @Deprecated\n    void grantDefaultPermissionsToEnabledImsServices(String[] packageNames, int userId) throws RemoteException;\n\n    /**\n     * @deprecated Removed in Android 12 (S)\n     */\n    @Deprecated\n    void grantDefaultPermissionsToEnabledTelephonyDataServices(String[] packageNames, int userId) throws RemoteException;\n\n    /**\n     * @deprecated Removed in Android 12 (S)\n     */\n    @Deprecated\n    void revokeDefaultPermissionsFromDisabledTelephonyDataServices(String[] packageNames, int userId) throws RemoteException;\n\n    /**\n     * @deprecated Removed in Android 12 (S)\n     */\n    @Deprecated\n    void grantDefaultPermissionsToActiveLuiApp(String packageName, int userId) throws RemoteException;\n\n    /**\n     * @deprecated Removed in Android 12 (S)\n     */\n    @Deprecated\n    void revokeDefaultPermissionsFromLuiApps(String[] packageNames, int userId) throws RemoteException;\n\n    /**\n     * @deprecated Removed in Android 12 (S)\n     */\n    @Deprecated\n    void setPermissionEnforced(String permName, boolean enforced) throws RemoteException;\n\n    /**\n     * @deprecated Removed in Android 12 (S)\n     */\n    @Deprecated\n    boolean isPermissionEnforced(String permName) throws RemoteException;\n\n    /**\n     * First two parameters are permuted since Android 12 (S)\n     *\n     * @deprecated Replaced in Android 14 r29 (Upside Down Cake) by {@link #shouldShowRequestPermissionRationale(String, String, int, int)}\n     */\n    @Deprecated\n    boolean shouldShowRequestPermissionRationale(String permName, String packageName, int userId)\n            throws RemoteException;\n\n    /**\n     * Introduced in Android 14.0.0_r29\n     */\n    @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)\n    boolean shouldShowRequestPermissionRationale(String packageName, String permName, int deviceId, int userId)\n            throws RemoteException;\n\n    /**\n     * First two parameters are permuted since Android 12 (S)\n     *\n     * @deprecated Replaced in Android 14 r29 (Upside Down Cake) by {@link #isPermissionRevokedByPolicy(String, String, int, int)}\n     */\n    @Deprecated\n    boolean isPermissionRevokedByPolicy(String permName, String packageName, int userId) throws RemoteException;\n\n    /**\n     * Introduced in Android 14.0.0_r29\n     */\n    @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)\n    boolean isPermissionRevokedByPolicy(String packageName, String permName, int deviceId,\n                                        int userId) throws RemoteException;\n\n    List<SplitPermissionInfoParcelable> getSplitPermissions() throws RemoteException;\n\n    /**\n     * @deprecated Replaced in Android 13 (Tiramisu) by {@link #startOneTimePermissionSession(String, int, long, long, int, int)}\n     */\n    @Deprecated\n    void startOneTimePermissionSession(String packageName, int userId, long timeout,\n                                       int importanceToResetTimer, int importanceToKeepSessionAlive) throws RemoteException;\n\n    /**\n     * @deprecated Replaced in Android 14 (Upside Down Cake) by {@link #startOneTimePermissionSession(String, int, long, long)}\n     */\n    @Deprecated\n    @RequiresApi(Build.VERSION_CODES.TIRAMISU)\n    void startOneTimePermissionSession(String packageName, int userId, long timeout,\n                                       long revokeAfterKilledDelay, int importanceToResetTimer,\n                                       int importanceToKeepSessionAlive) throws RemoteException;\n\n    /**\n     * @deprecated Replaced in Android 14 r29 (Upside Down Cake) by {@link #startOneTimePermissionSession(String, int, int, long, long)}\n     */\n    @Deprecated\n    @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)\n    void startOneTimePermissionSession(String packageName, int userId, long timeout,\n                                       long revokeAfterKilledDelay) throws RemoteException;\n\n    /**\n     * Introduced in Android 14.0.0_r29\n     */\n    @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)\n    void startOneTimePermissionSession(String packageName, int deviceId, int userId, long timeout,\n                                       long revokeAfterKilledDelay) throws RemoteException;\n\n    void stopOneTimePermissionSession(String packageName, int userId) throws RemoteException;\n\n    List<String> getAutoRevokeExemptionRequestedPackages(int userId) throws RemoteException;\n\n    List<String> getAutoRevokeExemptionGrantedPackages(int userId) throws RemoteException;\n\n    /**\n     * @deprecated Removed in Android 12 (S), replaced by {@link #setAutoRevokeExempted(String, boolean, int)}.\n     */\n    @Deprecated\n    boolean setAutoRevokeWhitelisted(String packageName, boolean whitelisted, int userId) throws RemoteException;\n\n    /**\n     * @deprecated Removed in Android 12 (S), replaced by {@link #isAutoRevokeExempted(String, int)}.\n     */\n    @Deprecated\n    boolean isAutoRevokeWhitelisted(String packageName, int userId) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.S)\n    boolean setAutoRevokeExempted(String packageName, boolean exempted, int userId) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.S)\n    boolean isAutoRevokeExempted(String packageName, int userId) throws RemoteException;\n\n    /**\n     * Introduced in Android 14.0.0_r29\n     *\n     * @deprecated Replaced in Android 14 r50 (Upside Down Cake) by {@link #checkPermission(String, String, String, int)}\n     */\n    @Deprecated\n    @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)\n    int checkPermission(String packageName, String permissionName, int deviceId, int userId) throws RemoteException;\n\n    /**\n     * Introduced in Android 14.0.0_r50\n     */\n    @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)\n    int checkPermission(String packageName, String permissionName, String persistentDeviceId,\n                        int userId) throws RemoteException;\n\n    /**\n     * Introduced in Android 14.0.0_r29\n     */\n    @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)\n    int checkUidPermission(int uid, String permissionName, int deviceId) throws RemoteException;\n\n    abstract class Stub extends Binder implements IPermissionManager {\n        public static IPermissionManager asInterface(IBinder binder) {\n            throw new UnsupportedOperationException();\n        }\n    }\n}"
  },
  {
    "path": "hiddenapi/src/main/java/android/provider/SettingsHidden.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage android.provider;\n\nimport android.os.Build;\n\nimport androidx.annotation.RequiresApi;\n\nimport dev.rikka.tools.refine.RefineAs;\n\n@RefineAs(Settings.class)\npublic final class SettingsHidden {\n    public static final class Global {\n        /**\n         * Whether ADB over Wifi is enabled.\n         */\n        @RequiresApi(Build.VERSION_CODES.R)\n        public static /*final*/ String ADB_WIFI_ENABLED = \"adb_wifi_enabled\";\n    }\n}\n"
  },
  {
    "path": "hiddenapi/src/main/java/android/system/OsHidden.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage android.system;\n\nimport dev.rikka.tools.refine.RefineAs;\nimport misc.utils.HiddenUtil;\n\n@RefineAs(Os.class)\npublic class OsHidden {\n    public static StructPasswd getpwuid(int uid) throws ErrnoException {\n        return HiddenUtil.throwUOE(uid);\n    }\n}\n"
  },
  {
    "path": "hiddenapi/src/main/java/android/system/StructPasswd.java",
    "content": "package android.system;\n\n/**\n * Corresponds to C's {@code struct passwd} from {@code &lt;pwd.h&gt;}.\n */\npublic final class StructPasswd {\n    public final String pw_name;\n    public final int pw_uid;\n    public final int pw_gid;\n    public final String pw_dir;\n    public final String pw_shell;\n\n    public StructPasswd(String pw_name, int pw_uid, int pw_gid, String pw_dir, String pw_shell) {\n        this.pw_name = pw_name;\n        this.pw_uid = pw_uid;\n        this.pw_gid = pw_gid;\n        this.pw_dir = pw_dir;\n        this.pw_shell = pw_shell;\n    }\n}"
  },
  {
    "path": "hiddenapi/src/main/java/android/util/TypedXmlPullParser.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage android.util;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.RequiresApi;\n\nimport org.xmlpull.v1.XmlPullParser;\nimport org.xmlpull.v1.XmlPullParserException;\n\n/**\n * Specialization of {@link XmlPullParser} which adds explicit methods to\n * support consistent and efficient conversion of primitive data types.\n */\n@RequiresApi(31)\npublic interface TypedXmlPullParser extends XmlPullParser {\n    /**\n     * @return index of requested attribute, otherwise {@code -1} if undefined\n     */\n    default int getAttributeIndex(@Nullable String namespace, @NonNull String name) {\n        final boolean namespaceNull = (namespace == null);\n        final int count = getAttributeCount();\n        for (int i = 0; i < count; i++) {\n            if ((namespaceNull || namespace.equals(getAttributeNamespace(i)))\n                    && name.equals(getAttributeName(i))) {\n                return i;\n            }\n        }\n        return -1;\n    }\n\n    /**\n     * @return index of requested attribute\n     * @throws XmlPullParserException if the value is undefined\n     */\n    default int getAttributeIndexOrThrow(@Nullable String namespace, @NonNull String name)\n            throws XmlPullParserException {\n        final int index = getAttributeIndex(namespace, name);\n        if (index == -1) {\n            throw new XmlPullParserException(\"Missing attribute \" + name);\n        } else {\n            return index;\n        }\n    }\n\n    /**\n     * @return decoded strongly-typed {@link #getAttributeValue}\n     * @throws XmlPullParserException if the value is malformed\n     */\n    @NonNull\n    byte[] getAttributeBytesHex(int index) throws XmlPullParserException;\n\n    /**\n     * @return decoded strongly-typed {@link #getAttributeValue}\n     * @throws XmlPullParserException if the value is malformed\n     */\n    @NonNull\n    byte[] getAttributeBytesBase64(int index) throws XmlPullParserException;\n\n    /**\n     * @return decoded strongly-typed {@link #getAttributeValue}\n     * @throws XmlPullParserException if the value is malformed\n     */\n    int getAttributeInt(int index) throws XmlPullParserException;\n\n    /**\n     * @return decoded strongly-typed {@link #getAttributeValue}\n     * @throws XmlPullParserException if the value is malformed\n     */\n    int getAttributeIntHex(int index) throws XmlPullParserException;\n\n    /**\n     * @return decoded strongly-typed {@link #getAttributeValue}\n     * @throws XmlPullParserException if the value is malformed\n     */\n    long getAttributeLong(int index) throws XmlPullParserException;\n\n    /**\n     * @return decoded strongly-typed {@link #getAttributeValue}\n     * @throws XmlPullParserException if the value is malformed\n     */\n    long getAttributeLongHex(int index) throws XmlPullParserException;\n\n    /**\n     * @return decoded strongly-typed {@link #getAttributeValue}\n     * @throws XmlPullParserException if the value is malformed\n     */\n    float getAttributeFloat(int index) throws XmlPullParserException;\n\n    /**\n     * @return decoded strongly-typed {@link #getAttributeValue}\n     * @throws XmlPullParserException if the value is malformed\n     */\n    double getAttributeDouble(int index) throws XmlPullParserException;\n\n    /**\n     * @return decoded strongly-typed {@link #getAttributeValue}\n     * @throws XmlPullParserException if the value is malformed\n     */\n    boolean getAttributeBoolean(int index) throws XmlPullParserException;\n\n    /**\n     * @return decoded strongly-typed {@link #getAttributeValue}\n     * @throws XmlPullParserException if the value is malformed or undefined\n     */\n    default @NonNull\n    byte[] getAttributeBytesHex(@Nullable String namespace,\n                                @NonNull String name) throws XmlPullParserException {\n        return getAttributeBytesHex(getAttributeIndexOrThrow(namespace, name));\n    }\n\n    /**\n     * @return decoded strongly-typed {@link #getAttributeValue}\n     * @throws XmlPullParserException if the value is malformed or undefined\n     */\n    default @NonNull\n    byte[] getAttributeBytesBase64(@Nullable String namespace,\n                                   @NonNull String name) throws XmlPullParserException {\n        return getAttributeBytesBase64(getAttributeIndexOrThrow(namespace, name));\n    }\n\n    /**\n     * @return decoded strongly-typed {@link #getAttributeValue}\n     * @throws XmlPullParserException if the value is malformed or undefined\n     */\n    default int getAttributeInt(@Nullable String namespace, @NonNull String name)\n            throws XmlPullParserException {\n        return getAttributeInt(getAttributeIndexOrThrow(namespace, name));\n    }\n\n    /**\n     * @return decoded strongly-typed {@link #getAttributeValue}\n     * @throws XmlPullParserException if the value is malformed or undefined\n     */\n    default int getAttributeIntHex(@Nullable String namespace, @NonNull String name)\n            throws XmlPullParserException {\n        return getAttributeIntHex(getAttributeIndexOrThrow(namespace, name));\n    }\n\n    /**\n     * @return decoded strongly-typed {@link #getAttributeValue}\n     * @throws XmlPullParserException if the value is malformed or undefined\n     */\n    default long getAttributeLong(@Nullable String namespace, @NonNull String name)\n            throws XmlPullParserException {\n        return getAttributeLong(getAttributeIndexOrThrow(namespace, name));\n    }\n\n    /**\n     * @return decoded strongly-typed {@link #getAttributeValue}\n     * @throws XmlPullParserException if the value is malformed or undefined\n     */\n    default long getAttributeLongHex(@Nullable String namespace, @NonNull String name)\n            throws XmlPullParserException {\n        return getAttributeLongHex(getAttributeIndexOrThrow(namespace, name));\n    }\n\n    /**\n     * @return decoded strongly-typed {@link #getAttributeValue}\n     * @throws XmlPullParserException if the value is malformed or undefined\n     */\n    default float getAttributeFloat(@Nullable String namespace, @NonNull String name)\n            throws XmlPullParserException {\n        return getAttributeFloat(getAttributeIndexOrThrow(namespace, name));\n    }\n\n    /**\n     * @return decoded strongly-typed {@link #getAttributeValue}\n     * @throws XmlPullParserException if the value is malformed or undefined\n     */\n    default double getAttributeDouble(@Nullable String namespace, @NonNull String name)\n            throws XmlPullParserException {\n        return getAttributeDouble(getAttributeIndexOrThrow(namespace, name));\n    }\n\n    /**\n     * @return decoded strongly-typed {@link #getAttributeValue}\n     * @throws XmlPullParserException if the value is malformed or undefined\n     */\n    default boolean getAttributeBoolean(@Nullable String namespace, @NonNull String name)\n            throws XmlPullParserException {\n        return getAttributeBoolean(getAttributeIndexOrThrow(namespace, name));\n    }\n\n    /**\n     * @return decoded strongly-typed {@link #getAttributeValue}, otherwise\n     * default value if the value is malformed or undefined\n     */\n    default @Nullable\n    byte[] getAttributeBytesHex(@Nullable String namespace,\n                                @NonNull String name, @Nullable byte[] defaultValue) {\n        final int index = getAttributeIndex(namespace, name);\n        if (index == -1) return defaultValue;\n        try {\n            return getAttributeBytesHex(index);\n        } catch (Exception ignored) {\n            return defaultValue;\n        }\n    }\n\n    /**\n     * @return decoded strongly-typed {@link #getAttributeValue}, otherwise\n     * default value if the value is malformed or undefined\n     */\n    default @Nullable\n    byte[] getAttributeBytesBase64(@Nullable String namespace,\n                                   @NonNull String name, @Nullable byte[] defaultValue) {\n        final int index = getAttributeIndex(namespace, name);\n        if (index == -1) return defaultValue;\n        try {\n            return getAttributeBytesBase64(index);\n        } catch (Exception ignored) {\n            return defaultValue;\n        }\n    }\n\n    /**\n     * @return decoded strongly-typed {@link #getAttributeValue}, otherwise\n     * default value if the value is malformed or undefined\n     */\n    default int getAttributeInt(@Nullable String namespace, @NonNull String name,\n                                int defaultValue) {\n        final int index = getAttributeIndex(namespace, name);\n        if (index == -1) return defaultValue;\n        try {\n            return getAttributeInt(index);\n        } catch (Exception ignored) {\n            return defaultValue;\n        }\n    }\n\n    /**\n     * @return decoded strongly-typed {@link #getAttributeValue}, otherwise\n     * default value if the value is malformed or undefined\n     */\n    default int getAttributeIntHex(@Nullable String namespace, @NonNull String name,\n                                   int defaultValue) {\n        final int index = getAttributeIndex(namespace, name);\n        if (index == -1) return defaultValue;\n        try {\n            return getAttributeIntHex(index);\n        } catch (Exception ignored) {\n            return defaultValue;\n        }\n    }\n\n    /**\n     * @return decoded strongly-typed {@link #getAttributeValue}, otherwise\n     * default value if the value is malformed or undefined\n     */\n    default long getAttributeLong(@Nullable String namespace, @NonNull String name,\n                                  long defaultValue) {\n        final int index = getAttributeIndex(namespace, name);\n        if (index == -1) return defaultValue;\n        try {\n            return getAttributeLong(index);\n        } catch (Exception ignored) {\n            return defaultValue;\n        }\n    }\n\n    /**\n     * @return decoded strongly-typed {@link #getAttributeValue}, otherwise\n     * default value if the value is malformed or undefined\n     */\n    default long getAttributeLongHex(@Nullable String namespace, @NonNull String name,\n                                     long defaultValue) {\n        final int index = getAttributeIndex(namespace, name);\n        if (index == -1) return defaultValue;\n        try {\n            return getAttributeLongHex(index);\n        } catch (Exception ignored) {\n            return defaultValue;\n        }\n    }\n\n    /**\n     * @return decoded strongly-typed {@link #getAttributeValue}, otherwise\n     * default value if the value is malformed or undefined\n     */\n    default float getAttributeFloat(@Nullable String namespace, @NonNull String name,\n                                    float defaultValue) {\n        final int index = getAttributeIndex(namespace, name);\n        if (index == -1) return defaultValue;\n        try {\n            return getAttributeFloat(index);\n        } catch (Exception ignored) {\n            return defaultValue;\n        }\n    }\n\n    /**\n     * @return decoded strongly-typed {@link #getAttributeValue}, otherwise\n     * default value if the value is malformed or undefined\n     */\n    default double getAttributeDouble(@Nullable String namespace, @NonNull String name,\n                                      double defaultValue) {\n        final int index = getAttributeIndex(namespace, name);\n        if (index == -1) return defaultValue;\n        try {\n            return getAttributeDouble(index);\n        } catch (Exception ignored) {\n            return defaultValue;\n        }\n    }\n\n    /**\n     * @return decoded strongly-typed {@link #getAttributeValue}, otherwise\n     * default value if the value is malformed or undefined\n     */\n    default boolean getAttributeBoolean(@Nullable String namespace, @NonNull String name,\n                                        boolean defaultValue) {\n        final int index = getAttributeIndex(namespace, name);\n        if (index == -1) return defaultValue;\n        try {\n            return getAttributeBoolean(index);\n        } catch (Exception ignored) {\n            return defaultValue;\n        }\n    }\n}"
  },
  {
    "path": "hiddenapi/src/main/java/android/util/TypedXmlSerializer.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage android.util;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.RequiresApi;\n\nimport org.xmlpull.v1.XmlSerializer;\n\nimport java.io.IOException;\n\n/**\n * Specialization of {@link XmlSerializer} which adds explicit methods to\n * support consistent and efficient conversion of primitive data types.\n */\n@RequiresApi(31)\npublic interface TypedXmlSerializer extends XmlSerializer {\n    /**\n     * Functionally equivalent to {@link #attribute(String, String, String)} but\n     * with the additional signal that the given value is a candidate for being\n     * canonicalized, similar to {@link String#intern()}.\n     */\n    @NonNull\n    XmlSerializer attributeInterned(@Nullable String namespace, @NonNull String name,\n                                    @NonNull String value) throws IOException;\n\n    /**\n     * Encode the given strongly-typed value and serialize using\n     * {@link #attribute(String, String, String)}.\n     */\n    @NonNull\n    XmlSerializer attributeBytesHex(@Nullable String namespace, @NonNull String name,\n                                    @NonNull byte[] value) throws IOException;\n\n    /**\n     * Encode the given strongly-typed value and serialize using\n     * {@link #attribute(String, String, String)}.\n     */\n    @NonNull\n    XmlSerializer attributeBytesBase64(@Nullable String namespace, @NonNull String name,\n                                       @NonNull byte[] value) throws IOException;\n\n    /**\n     * Encode the given strongly-typed value and serialize using\n     * {@link #attribute(String, String, String)}.\n     */\n    @NonNull\n    XmlSerializer attributeInt(@Nullable String namespace, @NonNull String name,\n                               int value) throws IOException;\n\n    /**\n     * Encode the given strongly-typed value and serialize using\n     * {@link #attribute(String, String, String)}.\n     */\n    @NonNull\n    XmlSerializer attributeIntHex(@Nullable String namespace, @NonNull String name,\n                                  int value) throws IOException;\n\n    /**\n     * Encode the given strongly-typed value and serialize using\n     * {@link #attribute(String, String, String)}.\n     */\n    @NonNull\n    XmlSerializer attributeLong(@Nullable String namespace, @NonNull String name,\n                                long value) throws IOException;\n\n    /**\n     * Encode the given strongly-typed value and serialize using\n     * {@link #attribute(String, String, String)}.\n     */\n    @NonNull\n    XmlSerializer attributeLongHex(@Nullable String namespace, @NonNull String name,\n                                   long value) throws IOException;\n\n    /**\n     * Encode the given strongly-typed value and serialize using\n     * {@link #attribute(String, String, String)}.\n     */\n    @NonNull\n    XmlSerializer attributeFloat(@Nullable String namespace, @NonNull String name,\n                                 float value) throws IOException;\n\n    /**\n     * Encode the given strongly-typed value and serialize using\n     * {@link #attribute(String, String, String)}.\n     */\n    @NonNull\n    XmlSerializer attributeDouble(@Nullable String namespace, @NonNull String name,\n                                  double value) throws IOException;\n\n    /**\n     * Encode the given strongly-typed value and serialize using\n     * {@link #attribute(String, String, String)}.\n     */\n    @NonNull\n    XmlSerializer attributeBoolean(@Nullable String namespace, @NonNull String name,\n                                   boolean value) throws IOException;\n}"
  },
  {
    "path": "hiddenapi/src/main/java/android/util/XmlHidden.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage android.util;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.RequiresApi;\n\nimport org.xmlpull.v1.XmlPullParser;\nimport org.xmlpull.v1.XmlPullParserException;\nimport org.xmlpull.v1.XmlSerializer;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\n\nimport dev.rikka.tools.refine.RefineAs;\nimport misc.utils.HiddenUtil;\n\n@RefineAs(Xml.class)\n@RequiresApi(31)\npublic class XmlHidden {\n    /**\n     * Creates a new {@link TypedXmlPullParser} which is optimized for use\n     * inside the system, typically by supporting only a basic set of features.\n     * <p>\n     * In particular, the returned parser does not support namespaces, prefixes,\n     * properties, or options.\n     */\n    @NonNull\n    public static TypedXmlPullParser newFastPullParser() {\n        return HiddenUtil.throwUOE();\n    }\n\n    /**\n     * Creates a new {@link XmlPullParser} that reads XML documents using a\n     * custom binary wire protocol which benchmarking has shown to be 8.5x\n     * faster than {@code Xml.newFastPullParser()} for a typical\n     * {@code packages.xml}.\n     */\n    @NonNull\n    public static TypedXmlPullParser newBinaryPullParser() {\n        return HiddenUtil.throwUOE();\n    }\n\n    /**\n     * Creates a new {@link XmlPullParser} which is optimized for use inside the\n     * system, typically by supporting only a basic set of features.\n     * <p>\n     * This returned instance may be configured to read using an efficient\n     * binary format instead of a human-readable text format, depending on\n     * device feature flags.\n     * <p>\n     * To ensure that both formats are detected and transparently handled\n     * correctly, you must shift to using both {@link #resolveSerializer} and\n     * {@link #resolvePullParser}.\n     */\n    public static @NonNull\n    TypedXmlPullParser resolvePullParser(@NonNull InputStream in) throws IOException {\n        return HiddenUtil.throwUOE(in);\n    }\n\n    /**\n     * Creates a new {@link XmlSerializer} which is optimized for use inside the\n     * system, typically by supporting only a basic set of features.\n     * <p>\n     * In particular, the returned parser does not support namespaces, prefixes,\n     * properties, or options.\n     */\n    @SuppressWarnings(\"AndroidFrameworkEfficientXml\")\n    public static @NonNull\n    TypedXmlSerializer newFastSerializer() {\n        return HiddenUtil.throwUOE();\n    }\n\n    /**\n     * Creates a new {@link XmlSerializer} that writes XML documents using a\n     * custom binary wire protocol which benchmarking has shown to be 4.4x\n     * faster and use 2.8x less disk space than {@code Xml.newFastSerializer()}\n     * for a typical {@code packages.xml}.\n     */\n    public static @NonNull\n    TypedXmlSerializer newBinarySerializer() {\n        return HiddenUtil.throwUOE();\n    }\n\n    /**\n     * Creates a new {@link XmlSerializer} which is optimized for use inside the\n     * system, typically by supporting only a basic set of features.\n     * <p>\n     * This returned instance may be configured to write using an efficient\n     * binary format instead of a human-readable text format, depending on\n     * device feature flags.\n     * <p>\n     * To ensure that both formats are detected and transparently handled\n     * correctly, you must shift to using both {@link #resolveSerializer} and\n     * {@link #resolvePullParser}.\n     */\n    public static @NonNull\n    TypedXmlSerializer resolveSerializer(@NonNull OutputStream out)\n            throws IOException {\n        return HiddenUtil.throwUOE(out);\n    }\n\n    /**\n     * Copy the first XML document into the second document.\n     * <p>\n     * Implemented by reading all events from the given {@link XmlPullParser}\n     * and writing them directly to the given {@link XmlSerializer}. This can be\n     * useful for transparently converting between underlying wire protocols.\n     */\n    public static void copy(@NonNull XmlPullParser in, @NonNull XmlSerializer out)\n            throws XmlPullParserException, IOException {\n        HiddenUtil.throwUOE(in, out);\n    }\n}\n"
  },
  {
    "path": "hiddenapi/src/main/java/com/android/internal/app/IAppOpsActiveCallback.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage com.android.internal.app;\n\n// Interface to observe op active changes\ninterface IAppOpsActiveCallback {\n    void opActiveChanged(int op, int uid, String packageName, boolean active);\n}"
  },
  {
    "path": "hiddenapi/src/main/java/com/android/internal/app/IAppOpsCallback.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage com.android.internal.app;\n\n// This interface is also used by native code, so must\n// be kept in sync with frameworks/native/libs/binder/include/binder/IAppOpsCallback.h\ninterface IAppOpsCallback {\n    void opChanged(int op, int uid, String packageName);\n}"
  },
  {
    "path": "hiddenapi/src/main/java/com/android/internal/app/IAppOpsNotedCallback.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage com.android.internal.app;\n\n// Interface to observe op note/checks of ops\ninterface IAppOpsNotedCallback {\n    void opNoted(int op, int uid, String packageName, int mode);\n}"
  },
  {
    "path": "hiddenapi/src/main/java/com/android/internal/app/IAppOpsService.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage com.android.internal.app;\n\nimport android.os.Build;\nimport android.os.IInterface;\nimport android.os.Parcelable;\nimport android.os.RemoteException;\n\nimport androidx.annotation.RequiresApi;\n\nimport java.util.List;\n\npublic interface IAppOpsService extends IInterface {\n    int checkOperation(int code, int uid, String packageName) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.M)\n    int permissionToOpCode(String permission) throws RemoteException;\n\n    int checkPackage(int uid, String packageName) throws RemoteException;\n\n    List<Parcelable> getPackagesForOps(int[] ops) throws RemoteException;\n\n    List<Parcelable> getOpsForPackage(int uid, String packageName, int[] ops)\n            throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.O)\n    List<Parcelable> getUidOps(int uid, int[] ops) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.M)\n    void setUidMode(int code, int uid, int mode) throws RemoteException;\n\n    void setMode(int code, int uid, String packageName, int mode) throws RemoteException;\n\n    // Removed in 22\n    void resetAllModes() throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.LOLLIPOP_MR1)\n    void resetAllModes(int reqUserId, String reqPackageName) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.P)\n    boolean isOperationActive(int code, int uid, String packageName) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.Q)\n    int checkOperationRaw(int code, int uid, String packageName) throws RemoteException;\n\n    abstract class Stub {\n        public static IAppOpsService asInterface(android.os.IBinder obj) {\n            return null;\n        }\n    }\n}\n"
  },
  {
    "path": "hiddenapi/src/main/java/com/android/internal/os/PowerProfile.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage com.android.internal.os;\n\nimport android.content.Context;\n\nimport misc.utils.HiddenUtil;\n\npublic class PowerProfile {\n    /**\n     * Battery capacity in milliAmpHour (mAh).\n     */\n    public static final String POWER_BATTERY_CAPACITY = \"battery.capacity\";\n\n    public PowerProfile(Context context) {\n        HiddenUtil.throwUOE(context);\n    }\n\n    /**\n     * Returns the average current in mA consumed by the subsystem\n     *\n     * @param type the subsystem type\n     * @return the average current in milliAmps.\n     */\n    public double getAveragePower(String type) {\n        return HiddenUtil.throwUOE(type);\n    }\n\n    /**\n     * Returns the battery capacity, if available, in milli Amp Hours. If not available,\n     * it returns zero.\n     *\n     * @return the battery capacity in mAh\n     */\n    public double getBatteryCapacity() {\n        return HiddenUtil.throwUOE();\n    }\n}\n"
  },
  {
    "path": "hiddenapi/src/main/java/com/android/internal/telephony/IPhoneSubInfo.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage com.android.internal.telephony;\n\nimport android.os.Build;\nimport android.os.IInterface;\nimport android.os.RemoteException;\n\nimport androidx.annotation.Nullable;\nimport androidx.annotation.RequiresApi;\n\nimport misc.utils.HiddenUtil;\n\npublic interface IPhoneSubInfo extends IInterface {\n    /**\n     * @deprecated Replaced by {@link #getSubscriberIdForSubscriber(int)} in SDK 22 (Android Lollipop MR1)\n     */\n    @Deprecated\n    String getSubscriberIdForSubscriber(long subId) throws RemoteException;\n\n    /**\n     * @deprecated Replaced by {@link #getSubscriberIdForSubscriber(int, String)} in SDK 23 (Android M)\n     */\n    @RequiresApi(Build.VERSION_CODES.LOLLIPOP_MR1)\n    @Deprecated\n    String getSubscriberIdForSubscriber(int subId) throws RemoteException;\n\n    /**\n     * @deprecated Replaced by {@link #getSubscriberIdForSubscriber(int, String, String)} in SDK 30 (Android R)\n     */\n    @RequiresApi(Build.VERSION_CODES.M)\n    @Deprecated\n    String getSubscriberIdForSubscriber(int subId, String callingPackage) throws RemoteException;\n\n    /**\n     * Retrieves the unique subscriber ID of a given subId, e.g., IMSI for GSM phones.\n     */\n    @RequiresApi(Build.VERSION_CODES.R)\n    String getSubscriberIdForSubscriber(int subId, String callingPackage, @Nullable String callingFeatureId) throws RemoteException;\n\n    abstract class Stub {\n        public static IPhoneSubInfo asInterface(android.os.IBinder obj) {\n            return HiddenUtil.throwUOE(obj);\n        }\n    }\n}\n"
  },
  {
    "path": "hiddenapi/src/main/java/com/android/internal/telephony/ISub.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage com.android.internal.telephony;\n\nimport android.os.Build;\nimport android.os.IInterface;\nimport android.os.RemoteException;\nimport android.telephony.SubscriptionInfo;\n\nimport androidx.annotation.Nullable;\nimport androidx.annotation.RequiresApi;\n\nimport java.util.List;\n\nimport misc.utils.HiddenUtil;\n\npublic interface ISub extends IInterface {\n    /**\n     * @deprecated Replaced with {@link #getActiveSubscriptionInfoList(String)} in API 23 (Android M)\n     */\n    @RequiresApi(Build.VERSION_CODES.LOLLIPOP_MR1)\n    @Deprecated\n    List<SubscriptionInfo> getActiveSubscriptionInfoList() throws RemoteException;\n\n    /**\n     * @deprecated Replaced with {@link #getActiveSubscriptionInfoList(String, String)} in API 30 (Android R)\n     */\n    @RequiresApi(Build.VERSION_CODES.M)\n    @Deprecated\n    List<SubscriptionInfo> getActiveSubscriptionInfoList(String callingPackage) throws RemoteException;\n\n    @RequiresApi(Build.VERSION_CODES.R)\n    List<SubscriptionInfo> getActiveSubscriptionInfoList(String callingPackage, @Nullable String callingFeatureId) throws RemoteException;\n\n    /**\n     * Added in Google Pixel stock ROM\n     */\n    @RequiresApi(Build.VERSION_CODES.UPSIDE_DOWN_CAKE)\n    List<SubscriptionInfo> getActiveSubscriptionInfoList(String callingPackage, @Nullable String callingFeatureId, boolean allUsers) throws RemoteException;\n\n    abstract class Stub {\n        public static ISub asInterface(android.os.IBinder obj) {\n            return HiddenUtil.throwUOE(obj);\n        }\n    }\n}\n"
  },
  {
    "path": "hiddenapi/src/main/java/com/android/org/conscrypt/Conscrypt.java",
    "content": "package com.android.org.conscrypt;\n\nimport android.os.Build;\n\nimport androidx.annotation.RequiresApi;\n\nimport javax.net.ssl.SSLException;\nimport javax.net.ssl.SSLSocket;\n\nimport misc.utils.HiddenUtil;\n\n@RequiresApi(Build.VERSION_CODES.R)\npublic final class Conscrypt {\n    /**\n     * Exports a value derived from the TLS master secret as described in RFC 5705.\n     *\n     * @param label   the label to use in calculating the exported value.  This must be\n     *                an ASCII-only string.\n     * @param context the application-specific context value to use in calculating the\n     *                exported value.  This may be {@code null} to use no application context, which is\n     *                treated differently than an empty byte array.\n     * @param length  the number of bytes of keying material to return.\n     * @return a value of the specified length, or {@code null} if the handshake has not yet\n     * completed or the connection has been closed.\n     * @throws SSLException if the value could not be exported.\n     */\n    public static byte[] exportKeyingMaterial(SSLSocket socket, String label, byte[] context,\n                                              int length) throws SSLException {\n        return HiddenUtil.throwUOE(socket, label, context, length);\n    }\n}\n"
  },
  {
    "path": "hiddenapi/src/main/java/misc/utils/HiddenUtil.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage misc.utils;\n\nimport android.os.Parcelable;\n\nimport org.jetbrains.annotations.Contract;\n\n// This isn't part of Hidden API\npublic class HiddenUtil {\n    @Contract(\"_ -> _\")\n    @SuppressWarnings({\"unused\", \"Contract\"})\n    public static <T> T throwUOE(Object... sink) {\n        throw new UnsupportedOperationException();\n    }\n\n    public static <T> Parcelable.Creator<T> creator() {\n        return throwUOE();\n    }\n}\n"
  },
  {
    "path": "libcore/.gitignore",
    "content": "/build"
  },
  {
    "path": "libcore/compat/.gitignore",
    "content": "/build"
  },
  {
    "path": "libcore/compat/build.gradle",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\nplugins {\n    id('com.android.library')\n}\n\nandroid {\n    namespace 'io.github.muntashirakon.AppManager.compat'\n    compileSdk compile_sdk\n    buildToolsVersion = build_tools\n\n    defaultConfig {\n        minSdk min_sdk\n        targetSdk target_sdk\n    }\n\n    compileOptions {\n        encoding \"UTF-8\"\n        sourceCompatibility JavaVersion.VERSION_1_8\n        targetCompatibility JavaVersion.VERSION_1_8\n    }\n\n    testOptions {\n        unitTests {\n            includeAndroidResources = true\n        }\n    }\n    buildFeatures {\n        buildConfig true\n    }\n}\n\ndependencies {\n    compileOnly project(path: ':hiddenapi')\n\n    api \"androidx.annotation:annotation:${annotation_version}\"\n\n    // Unit Testing\n    testImplementation \"junit:junit:${junit_version}\"\n    testImplementation \"org.robolectric:robolectric:${robolectric_version}\"\n}"
  },
  {
    "path": "libcore/compat/src/main/AndroidManifest.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<manifest />\n"
  },
  {
    "path": "libcore/compat/src/main/java/io/github/muntashirakon/compat/HexDump.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.compat;\n\npublic class HexDump {\n    private final static char[] HEX_DIGITS = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};\n    private final static char[] HEX_LOWER_CASE_DIGITS = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};\n\n    public static String toHexString(byte[] array) {\n        return toHexString(array, 0, array.length, true);\n    }\n\n    public static String toHexString(byte[] array, int offset, int length) {\n        return toHexString(array, offset, length, true);\n    }\n\n    public static String toHexString(byte[] array, int offset, int length, boolean upperCase) {\n        char[] digits = upperCase ? HEX_DIGITS : HEX_LOWER_CASE_DIGITS;\n        char[] buf = new char[length * 2];\n\n        int bufIndex = 0;\n        for (int i = offset; i < offset + length; i++) {\n            byte b = array[i];\n            buf[bufIndex++] = digits[(b >>> 4) & 0x0F];\n            buf[bufIndex++] = digits[b & 0x0F];\n        }\n\n        return new String(buf);\n    }\n\n    private static int toByte(char c) {\n        if (c >= '0' && c <= '9') return (c - '0');\n        if (c >= 'A' && c <= 'F') return (c - 'A' + 10);\n        if (c >= 'a' && c <= 'f') return (c - 'a' + 10);\n\n        throw new RuntimeException(\"Invalid hex char '\" + c + \"'\");\n    }\n\n    public static byte[] hexStringToByteArray(String hexString) {\n        int length = hexString.length();\n        byte[] buffer = new byte[length / 2];\n\n        for (int i = 0; i < length; i += 2) {\n            buffer[i / 2] = (byte) ((toByte(hexString.charAt(i)) << 4) | toByte(hexString.charAt(i + 1)));\n        }\n\n        return buffer;\n    }\n}\n"
  },
  {
    "path": "libcore/compat/src/main/java/io/github/muntashirakon/compat/ObjectsCompat.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.compat;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport java.util.Objects;\n\npublic class ObjectsCompat {\n    @NonNull\n    public static <T> T requireNonNullElse(@Nullable T obj, @NonNull T defaultObj) {\n        return (obj != null) ? obj : Objects.requireNonNull(defaultObj, \"defaultObj\");\n    }\n}\n"
  },
  {
    "path": "libcore/compat/src/main/java/io/github/muntashirakon/compat/io/FastDataInput.java",
    "content": "// SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-or-later\n\npackage io.github.muntashirakon.compat.io;\n\nimport androidx.annotation.NonNull;\n\nimport java.io.BufferedInputStream;\nimport java.io.Closeable;\nimport java.io.DataInput;\nimport java.io.DataInputStream;\nimport java.io.EOFException;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.nio.charset.StandardCharsets;\nimport java.util.Arrays;\nimport java.util.Objects;\nimport java.util.concurrent.atomic.AtomicReference;\n\n/**\n * Optimized implementation of {@link DataInput} which buffers data in memory\n * from the underlying {@link InputStream}.\n * <p>\n * Benchmarks have demonstrated this class is 3x more efficient than using a\n * {@link DataInputStream} with a {@link BufferedInputStream}.\n */\n// NOTE: This class is not actually optimised because we can't use VMRuntime right now\npublic class FastDataInput implements DataInput, Closeable {\n    private static final int MAX_UNSIGNED_SHORT = 65_535;\n\n    private static final int DEFAULT_BUFFER_SIZE = 32_768;\n\n    private static final AtomicReference<FastDataInput> sInCache = new AtomicReference<>();\n\n    // private final VMRuntime mRuntime;\n\n    private final byte[] mBuffer;\n    // private final long mBufferPtr;\n    private final int mBufferCap;\n    private final boolean mUse4ByteSequence;\n\n    private InputStream mIn;\n    private int mBufferPos;\n    private int mBufferLim;\n\n    /**\n     * Values that have been \"interned\" by {@link #readInternedUTF()}.\n     */\n    private int mStringRefCount = 0;\n    private String[] mStringRefs = new String[32];\n\n    /**\n     * @deprecated callers must specify {@code use4ByteSequence} so they make a\n     *             clear choice about working around a long-standing ART bug, as\n     *             described by the {@code kUtfUse4ByteSequence} comments in\n     *             {@code art/runtime/jni/jni_internal.cc}.\n     */\n    @Deprecated\n    public FastDataInput(@NonNull InputStream in, int bufferSize) {\n        this(in, bufferSize, true /* use4ByteSequence */);\n    }\n\n    public FastDataInput(@NonNull InputStream in, int bufferSize, boolean use4ByteSequence) {\n        // mRuntime = VMRuntime.getRuntime();\n        mIn = Objects.requireNonNull(in);\n        if (bufferSize < 8) {\n            throw new IllegalArgumentException();\n        }\n\n        mBuffer = new byte[bufferSize]; // (byte[]) mRuntime.newNonMovableArray(byte.class, bufferSize);\n        // mBufferPtr = mRuntime.addressOf(mBuffer);\n        mBufferCap = mBuffer.length;\n        mUse4ByteSequence = use4ByteSequence;\n    }\n\n    /**\n     * Obtain a {@link FastDataInput} configured with the given\n     * {@link InputStream} and which encodes large code-points using 3-byte\n     * sequences.\n     * <p>\n     * This <em>is</em> compatible with the {@link DataInput} API contract,\n     * which specifies that large code-points must be encoded with 3-byte\n     * sequences.\n     */\n    public static FastDataInput obtainUsing3ByteSequences(@NonNull InputStream in) {\n        return new FastDataInput(in, DEFAULT_BUFFER_SIZE, false /* use4ByteSequence */);\n    }\n\n    /**\n     * Obtain a {@link FastDataInput} configured with the given\n     * {@link InputStream} and which decodes large code-points using 4-byte\n     * sequences.\n     * <p>\n     * This <em>is not</em> compatible with the {@link DataInput} API contract,\n     * which specifies that large code-points must be encoded with 3-byte\n     * sequences.\n     */\n    public static FastDataInput obtainUsing4ByteSequences(@NonNull InputStream in) {\n        FastDataInput instance = sInCache.getAndSet(null);\n        if (instance != null) {\n            instance.setInput(in);\n            return instance;\n        }\n        return new FastDataInput(in, DEFAULT_BUFFER_SIZE, true /* use4ByteSequence */);\n    }\n\n    /**\n     * Release a {@link FastDataInput} to potentially be recycled. You must not\n     * interact with the object after releasing it.\n     */\n    public void release() {\n        mIn = null;\n        mBufferPos = 0;\n        mBufferLim = 0;\n        mStringRefCount = 0;\n\n        if (mBufferCap == DEFAULT_BUFFER_SIZE && mUse4ByteSequence) {\n            // Try to return to the cache.\n            sInCache.compareAndSet(null, this);\n        }\n    }\n\n    /**\n     * Re-initializes the object for the new input.\n     */\n    private void setInput(@NonNull InputStream in) {\n        mIn = Objects.requireNonNull(in);\n        mBufferPos = 0;\n        mBufferLim = 0;\n        mStringRefCount = 0;\n    }\n\n    private void fill(int need) throws IOException {\n        final int remain = mBufferLim - mBufferPos;\n        System.arraycopy(mBuffer, mBufferPos, mBuffer, 0, remain);\n        mBufferPos = 0;\n        mBufferLim = remain;\n        need -= remain;\n\n        while (need > 0) {\n            int c = mIn.read(mBuffer, mBufferLim, mBufferCap - mBufferLim);\n            if (c == -1) {\n                throw new EOFException();\n            } else {\n                mBufferLim += c;\n                need -= c;\n            }\n        }\n    }\n\n    @Override\n    public void close() throws IOException {\n        mIn.close();\n        release();\n    }\n\n    @Override\n    public void readFully(byte[] b) throws IOException {\n        readFully(b, 0, b.length);\n    }\n\n    @Override\n    public void readFully(byte[] b, int off, int len) throws IOException {\n        // Attempt to read directly from buffer space if there's enough room,\n        // otherwise fall back to chunking into place\n        if (mBufferCap >= len) {\n            if (mBufferLim - mBufferPos < len) fill(len);\n            System.arraycopy(mBuffer, mBufferPos, b, off, len);\n            mBufferPos += len;\n        } else {\n            final int remain = mBufferLim - mBufferPos;\n            System.arraycopy(mBuffer, mBufferPos, b, off, remain);\n            mBufferPos += remain;\n            off += remain;\n            len -= remain;\n\n            while (len > 0) {\n                int c = mIn.read(b, off, len);\n                if (c == -1) {\n                    throw new EOFException();\n                } else {\n                    off += c;\n                    len -= c;\n                }\n            }\n        }\n    }\n\n    @Override\n    public String readUTF() throws IOException {\n        // Attempt to read directly from buffer space if there's enough room,\n        // otherwise fall back to chunking into place\n        final int len = readUnsignedShort();\n\n        // Unfortunately, we can't use VMRuntime right now\n        byte[] tmp = new byte[len];\n        readFully(tmp, 0, len);\n\n        return new String(tmp, StandardCharsets.UTF_8);\n\n//        if (mUse4ByteSequence) {\n//            return readUTFUsing4ByteSequences();\n//        } else {\n//            return readUTFUsing3ByteSequences();\n//        }\n    }\n\n//    private String readUTFUsing4ByteSequences() throws IOException {\n//        // Attempt to read directly from buffer space if there's enough room,\n//        // otherwise fall back to chunking into place\n//        final int len = readUnsignedShort();\n//        if (mBufferCap > len) {\n//            if (mBufferLim - mBufferPos < len) fill(len);\n//            final String res = CharsetUtils.fromModifiedUtf8Bytes(mBufferPtr, mBufferPos, len);\n//            mBufferPos += len;\n//            return res;\n//        } else {\n//            final byte[] tmp = (byte[]) mRuntime.newNonMovableArray(byte.class, len + 1);\n//            readFully(tmp, 0, len);\n//            return CharsetUtils.fromModifiedUtf8Bytes(mRuntime.addressOf(tmp), 0, len);\n//        }\n//    }\n//\n//    private String readUTFUsing3ByteSequences() throws IOException {\n//        // Attempt to read directly from buffer space if there's enough room,\n//        // otherwise fall back to chunking into place\n//        final int len = readUnsignedShort();\n//        if (mBufferCap > len) {\n//            if (mBufferLim - mBufferPos < len) fill(len);\n//            final String res = ModifiedUtf8.decode(mBuffer, new char[len], mBufferPos, len);\n//            mBufferPos += len;\n//            return res;\n//        } else {\n//            final byte[] tmp = (byte[]) mRuntime.newNonMovableArray(byte.class, len + 1);\n//            readFully(tmp, 0, len);\n//            return ModifiedUtf8.decode(tmp, new char[len], 0, len);\n//        }\n//    }\n\n    /**\n     * Read a {@link String} value with the additional signal that the given\n     * value is a candidate for being canonicalized, similar to\n     * {@link String#intern()}.\n     * <p>\n     * Canonicalization is implemented by writing each unique string value once\n     * the first time it appears, and then writing a lightweight {@code short}\n     * reference when that string is written again in the future.\n     *\n     * @see FastDataOutput#writeInternedUTF(String)\n     */\n    public @NonNull String readInternedUTF() throws IOException {\n        final int ref = readUnsignedShort();\n        if (ref == MAX_UNSIGNED_SHORT) {\n            final String s = readUTF();\n\n            // We can only safely intern when we have remaining values; if we're\n            // full we at least sent the string value above\n            if (mStringRefCount < MAX_UNSIGNED_SHORT) {\n                if (mStringRefCount == mStringRefs.length) {\n                    mStringRefs = Arrays.copyOf(mStringRefs,\n                            mStringRefCount + (mStringRefCount >> 1));\n                }\n                mStringRefs[mStringRefCount++] = s;\n            }\n\n            return s;\n        } else {\n            return mStringRefs[ref];\n        }\n    }\n\n    @Override\n    public boolean readBoolean() throws IOException {\n        return readByte() != 0;\n    }\n\n    /**\n     * Returns the same decoded value as {@link #readByte()} but without\n     * actually consuming the underlying data.\n     */\n    public byte peekByte() throws IOException {\n        if (mBufferLim - mBufferPos < 1) fill(1);\n        return mBuffer[mBufferPos];\n    }\n\n    @Override\n    public byte readByte() throws IOException {\n        if (mBufferLim - mBufferPos < 1) fill(1);\n        return mBuffer[mBufferPos++];\n    }\n\n    @Override\n    public int readUnsignedByte() throws IOException {\n        return Byte.toUnsignedInt(readByte());\n    }\n\n    @Override\n    public short readShort() throws IOException {\n        if (mBufferLim - mBufferPos < 2) fill(2);\n        return (short) (((mBuffer[mBufferPos++] & 0xff) <<  8) |\n                        ((mBuffer[mBufferPos++] & 0xff) <<  0));\n    }\n\n    @Override\n    public int readUnsignedShort() throws IOException {\n        return Short.toUnsignedInt(readShort());\n    }\n\n    @Override\n    public char readChar() throws IOException {\n        return (char) readShort();\n    }\n\n    @Override\n    public int readInt() throws IOException {\n        if (mBufferLim - mBufferPos < 4) fill(4);\n        return (((mBuffer[mBufferPos++] & 0xff) << 24) |\n                ((mBuffer[mBufferPos++] & 0xff) << 16) |\n                ((mBuffer[mBufferPos++] & 0xff) <<  8) |\n                ((mBuffer[mBufferPos++] & 0xff) <<  0));\n    }\n\n    @Override\n    public long readLong() throws IOException {\n        if (mBufferLim - mBufferPos < 8) fill(8);\n        int h = ((mBuffer[mBufferPos++] & 0xff) << 24) |\n                ((mBuffer[mBufferPos++] & 0xff) << 16) |\n                ((mBuffer[mBufferPos++] & 0xff) <<  8) |\n                ((mBuffer[mBufferPos++] & 0xff) <<  0);\n        int l = ((mBuffer[mBufferPos++] & 0xff) << 24) |\n                ((mBuffer[mBufferPos++] & 0xff) << 16) |\n                ((mBuffer[mBufferPos++] & 0xff) <<  8) |\n                ((mBuffer[mBufferPos++] & 0xff) <<  0);\n        return (((long) h) << 32L) | ((long) l) & 0xffffffffL;\n    }\n\n    @Override\n    public float readFloat() throws IOException {\n        return Float.intBitsToFloat(readInt());\n    }\n\n    @Override\n    public double readDouble() throws IOException {\n        return Double.longBitsToDouble(readLong());\n    }\n\n    @Override\n    public int skipBytes(int n) {\n        // Callers should read data piecemeal\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public String readLine() throws IOException {\n        // Callers should read data piecemeal\n        throw new UnsupportedOperationException();\n    }\n}"
  },
  {
    "path": "libcore/compat/src/main/java/io/github/muntashirakon/compat/io/FastDataOutput.java",
    "content": "// SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-or-later\n\npackage io.github.muntashirakon.compat.io;\n\nimport androidx.annotation.NonNull;\n\nimport java.io.BufferedOutputStream;\nimport java.io.Closeable;\nimport java.io.DataOutput;\nimport java.io.DataOutputStream;\nimport java.io.Flushable;\nimport java.io.IOException;\nimport java.io.OutputStream;\nimport java.nio.charset.StandardCharsets;\nimport java.util.HashMap;\nimport java.util.Objects;\nimport java.util.concurrent.atomic.AtomicReference;\n\n/**\n * Optimized implementation of {@link DataOutput} which buffers data in memory\n * before flushing to the underlying {@link OutputStream}.\n * <p>\n * Benchmarks have demonstrated this class is 2x more efficient than using a\n * {@link DataOutputStream} with a {@link BufferedOutputStream}.\n */\n// NOTE: This class is not actually optimised because we can't use VMRuntime right now\npublic class FastDataOutput implements DataOutput, Flushable, Closeable {\n    private static final int MAX_UNSIGNED_SHORT = 65_535;\n\n    private static final int DEFAULT_BUFFER_SIZE = 32_768;\n\n    private static final AtomicReference<FastDataOutput> sOutCache = new AtomicReference<>();\n\n    // private final VMRuntime mRuntime;\n\n    private final byte[] mBuffer;\n    // private final long mBufferPtr;\n    private final int mBufferCap;\n    private final boolean mUse4ByteSequence;\n\n    private OutputStream mOut;\n    private int mBufferPos;\n\n    /**\n     * Values that have been \"interned\" by {@link #writeInternedUTF(String)}.\n     */\n    private final HashMap<String, Short> mStringRefs = new HashMap<>();\n\n    /**\n     * @deprecated callers must specify {@code use4ByteSequence} so they make a\n     *             clear choice about working around a long-standing ART bug, as\n     *             described by the {@code kUtfUse4ByteSequence} comments in\n     *             {@code art/runtime/jni/jni_internal.cc}.\n     */\n    @Deprecated\n    public FastDataOutput(@NonNull OutputStream out, int bufferSize) {\n        this(out, bufferSize, true /* use4ByteSequence */);\n    }\n\n    public FastDataOutput(@NonNull OutputStream out, int bufferSize, boolean use4ByteSequence) {\n        // mRuntime = VMRuntime.getRuntime();\n        if (bufferSize < 8) {\n            throw new IllegalArgumentException();\n        }\n\n        mBuffer = new byte[bufferSize]; // (byte[]) mRuntime.newNonMovableArray(byte.class, bufferSize);\n        // mBufferPtr = mRuntime.addressOf(mBuffer);\n        mBufferCap = mBuffer.length;\n        mUse4ByteSequence = use4ByteSequence;\n\n        setOutput(out);\n    }\n\n    /**\n     * Obtain a {@link FastDataOutput} configured with the given\n     * {@link OutputStream} and which encodes large code-points using 3-byte\n     * sequences.\n     * <p>\n     * This <em>is</em> compatible with the {@link DataOutput} API contract,\n     * which specifies that large code-points must be encoded with 3-byte\n     * sequences.\n     */\n    public static FastDataOutput obtainUsing3ByteSequences(@NonNull OutputStream out) {\n        return new FastDataOutput(out, DEFAULT_BUFFER_SIZE, false /* use4ByteSequence */);\n    }\n\n    /**\n     * Obtain a {@link FastDataOutput} configured with the given\n     * {@link OutputStream} and which encodes large code-points using 4-byte\n     * sequences.\n     * <p>\n     * This <em>is not</em> compatible with the {@link DataOutput} API contract,\n     * which specifies that large code-points must be encoded with 3-byte\n     * sequences.\n     */\n    public static FastDataOutput obtainUsing4ByteSequences(@NonNull OutputStream out) {\n        FastDataOutput instance = sOutCache.getAndSet(null);\n        if (instance != null) {\n            instance.setOutput(out);\n            return instance;\n        }\n        return new FastDataOutput(out, DEFAULT_BUFFER_SIZE, true /* use4ByteSequence */);\n    }\n\n    /**\n     * Release a {@link FastDataOutput} to potentially be recycled. You must not\n     * interact with the object after releasing it.\n     */\n    public void release() {\n        if (mBufferPos > 0) {\n            throw new IllegalStateException(\"Lingering data, call flush() before releasing.\");\n        }\n\n        mOut = null;\n        mBufferPos = 0;\n        mStringRefs.clear();\n\n        if (mBufferCap == DEFAULT_BUFFER_SIZE && mUse4ByteSequence) {\n            // Try to return to the cache.\n            sOutCache.compareAndSet(null, this);\n        }\n    }\n\n    /**\n     * Re-initializes the object for the new output.\n     */\n    private void setOutput(@NonNull OutputStream out) {\n        mOut = Objects.requireNonNull(out);\n        mBufferPos = 0;\n        mStringRefs.clear();\n    }\n\n    private void drain() throws IOException {\n        if (mBufferPos > 0) {\n            mOut.write(mBuffer, 0, mBufferPos);\n            mBufferPos = 0;\n        }\n    }\n\n    @Override\n    public void flush() throws IOException {\n        drain();\n        mOut.flush();\n    }\n\n    @Override\n    public void close() throws IOException {\n        mOut.close();\n        release();\n    }\n\n    @Override\n    public void write(int b) throws IOException {\n        writeByte(b);\n    }\n\n    @Override\n    public void write(byte[] b) throws IOException {\n        write(b, 0, b.length);\n    }\n\n    @Override\n    public void write(byte[] b, int off, int len) throws IOException {\n        if (mBufferCap < len) {\n            drain();\n            mOut.write(b, off, len);\n        } else {\n            if (mBufferCap - mBufferPos < len) drain();\n            System.arraycopy(b, off, mBuffer, mBufferPos, len);\n            mBufferPos += len;\n        }\n    }\n\n    @Override\n    public void writeUTF(String s) throws IOException {\n        // Attempt to write directly to buffer space if there's enough room,\n        // otherwise fall back to chunking into place\n        if (mBufferCap - mBufferPos < 2 + s.length()) drain();\n\n        // Unfoturnately, we cannot use VMRuntime, so we will take len to be negative as specified below\n        // and insert manually\n        final byte[] tmp = s.getBytes(StandardCharsets.UTF_8);\n        writeShort(tmp.length);\n        write(tmp, 0, tmp.length);\n\n//        if (mUse4ByteSequence) {\n//            writeUTFUsing4ByteSequences(s);\n//        } else {\n//            writeUTFUsing3ByteSequences(s);\n//        }\n    }\n\n//    private void writeUTFUsing4ByteSequences(String s) throws IOException {\n//        // Attempt to write directly to buffer space if there's enough room,\n//        // otherwise fall back to chunking into place\n//        if (mBufferCap - mBufferPos < 2 + s.length()) drain();\n//\n//        // Unfoturnately, we cannot use VMRuntime, so we will take len to be negative as specified below\n//        // and insert manually\n//        final byte[] tmp = s.getBytes(StandardCharsets.UTF_8);\n//        writeShort(tmp.length);\n//        write(tmp, 0, tmp.length);\n//\n//        // Magnitude of this returned value indicates the number of bytes\n//        // required to encode the string; sign indicates success/failure\n//        int len = CharsetUtils.toModifiedUtf8Bytes(s, mBufferPtr, mBufferPos + 2, mBufferCap);\n//        if (Math.abs(len) > MAX_UNSIGNED_SHORT) {\n//            throw new IOException(\"Modified UTF-8 length too large: \" + len);\n//        }\n//\n//        if (len >= 0) {\n//            // Positive value indicates the string was encoded into the buffer\n//            // successfully, so we only need to prefix with length\n//            writeShort(len);\n//            mBufferPos += len;\n//        } else {\n//            // Negative value indicates buffer was too small and we need to\n//            // allocate a temporary buffer for encoding\n//            len = -len;\n//            final byte[] tmp = (byte[]) mRuntime.newNonMovableArray(byte.class, len + 1);\n//            CharsetUtils.toModifiedUtf8Bytes(s, mRuntime.addressOf(tmp), 0, tmp.length);\n//            writeShort(len);\n//            write(tmp, 0, len);\n//        }\n//    }\n//\n//    private void writeUTFUsing3ByteSequences(String s) throws IOException {\n//        final int len = (int) ModifiedUtf8.countBytes(s, false);\n//        if (len > MAX_UNSIGNED_SHORT) {\n//            throw new IOException(\"Modified UTF-8 length too large: \" + len);\n//        }\n//\n//        // Attempt to write directly to buffer space if there's enough room,\n//        // otherwise fall back to chunking into place\n//        if (mBufferCap >= 2 + len) {\n//            if (mBufferCap - mBufferPos < 2 + len) drain();\n//            writeShort(len);\n//            ModifiedUtf8.encode(mBuffer, mBufferPos, s);\n//            mBufferPos += len;\n//        } else {\n//            final byte[] tmp = (byte[]) mRuntime.newNonMovableArray(byte.class, len + 1);\n//            ModifiedUtf8.encode(tmp, 0, s);\n//            writeShort(len);\n//            write(tmp, 0, len);\n//        }\n//    }\n\n    /**\n     * Write a {@link String} value with the additional signal that the given\n     * value is a candidate for being canonicalized, similar to\n     * {@link String#intern()}.\n     * <p>\n     * Canonicalization is implemented by writing each unique string value once\n     * the first time it appears, and then writing a lightweight {@code short}\n     * reference when that string is written again in the future.\n     *\n     * @see FastDataInput#readInternedUTF()\n     */\n    public void writeInternedUTF(@NonNull String s) throws IOException {\n        Short ref = mStringRefs.get(s);\n        if (ref != null) {\n            writeShort(ref);\n        } else {\n            writeShort(MAX_UNSIGNED_SHORT);\n            writeUTF(s);\n\n            // We can only safely intern when we have remaining values; if we're\n            // full we at least sent the string value above\n            ref = (short) mStringRefs.size();\n            if (ref < MAX_UNSIGNED_SHORT) {\n                mStringRefs.put(s, ref);\n            }\n        }\n    }\n\n    @Override\n    public void writeBoolean(boolean v) throws IOException {\n        writeByte(v ? 1 : 0);\n    }\n\n    @Override\n    public void writeByte(int v) throws IOException {\n        if (mBufferCap - mBufferPos < 1) drain();\n        mBuffer[mBufferPos++] = (byte) ((v >>  0) & 0xff);\n    }\n\n    @Override\n    public void writeShort(int v) throws IOException {\n        if (mBufferCap - mBufferPos < 2) drain();\n        mBuffer[mBufferPos++] = (byte) ((v >>  8) & 0xff);\n        mBuffer[mBufferPos++] = (byte) ((v >>  0) & 0xff);\n    }\n\n    @Override\n    public void writeChar(int v) throws IOException {\n        writeShort((short) v);\n    }\n\n    @Override\n    public void writeInt(int v) throws IOException {\n        if (mBufferCap - mBufferPos < 4) drain();\n        mBuffer[mBufferPos++] = (byte) ((v >> 24) & 0xff);\n        mBuffer[mBufferPos++] = (byte) ((v >> 16) & 0xff);\n        mBuffer[mBufferPos++] = (byte) ((v >>  8) & 0xff);\n        mBuffer[mBufferPos++] = (byte) ((v >>  0) & 0xff);\n    }\n\n    @Override\n    public void writeLong(long v) throws IOException {\n        if (mBufferCap - mBufferPos < 8) drain();\n        int i = (int) (v >> 32);\n        mBuffer[mBufferPos++] = (byte) ((i >> 24) & 0xff);\n        mBuffer[mBufferPos++] = (byte) ((i >> 16) & 0xff);\n        mBuffer[mBufferPos++] = (byte) ((i >>  8) & 0xff);\n        mBuffer[mBufferPos++] = (byte) ((i >>  0) & 0xff);\n        i = (int) v;\n        mBuffer[mBufferPos++] = (byte) ((i >> 24) & 0xff);\n        mBuffer[mBufferPos++] = (byte) ((i >> 16) & 0xff);\n        mBuffer[mBufferPos++] = (byte) ((i >>  8) & 0xff);\n        mBuffer[mBufferPos++] = (byte) ((i >>  0) & 0xff);\n    }\n\n    @Override\n    public void writeFloat(float v) throws IOException {\n        writeInt(Float.floatToIntBits(v));\n    }\n\n    @Override\n    public void writeDouble(double v) throws IOException {\n        writeLong(Double.doubleToLongBits(v));\n    }\n\n    @Override\n    public void writeBytes(String s) {\n        // Callers should use writeUTF()\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public void writeChars(String s) {\n        // Callers should use writeUTF()\n        throw new UnsupportedOperationException();\n    }\n}\n"
  },
  {
    "path": "libcore/compat/src/main/java/io/github/muntashirakon/compat/os/ParcelCompat2.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.compat.os;\n\nimport android.os.Build;\nimport android.os.IBinder;\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\n\npublic final class ParcelCompat2 {\n    @NonNull\n    public static Parcel obtain(@NonNull IBinder binder) {\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {\n            return Parcel.obtain(binder);\n        }\n        return Parcel.obtain();\n    }\n}\n"
  },
  {
    "path": "libcore/compat/src/main/java/io/github/muntashirakon/compat/system/OsCompat.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.compat.system;\n\nimport android.system.ErrnoException;\nimport android.system.StructPasswd;\n\nimport androidx.annotation.Keep;\n\n@Keep\npublic class OsCompat {\n    // Lists the syscalls unavailable in Os\n\n    static {\n        System.loadLibrary(\"am\");\n    }\n\n    public static long UTIME_NOW;\n    public static long UTIME_OMIT;\n    public static int AT_FDCWD;\n    public static int AT_SYMLINK_NOFOLLOW;\n\n    static {\n        setNativeConstants();\n    }\n\n    private static native void setNativeConstants();\n\n    public static native void setgrent() throws ErrnoException;\n\n    public static native void setpwent() throws ErrnoException;\n\n    public static native StructGroup getgrent() throws ErrnoException;\n\n    public static native StructPasswd getpwent() throws ErrnoException;\n\n    public static native void endgrent() throws ErrnoException;\n\n    public static native void endpwent() throws ErrnoException;\n\n    public static native void utimensat(int dirfd, String pathname, StructTimespec atime, StructTimespec mtime,\n                                        int flags) throws ErrnoException;\n}\n"
  },
  {
    "path": "libcore/compat/src/main/java/io/github/muntashirakon/compat/system/StructGroup.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.compat.system;\n\nimport androidx.annotation.Keep;\n\n@Keep\npublic class StructGroup {\n    public final String gr_name;\n    public final String gr_passwd;\n    public final int gr_id;\n    public final String[] gr_mem;\n\n    public StructGroup(String grName, String grPasswd, int grId, String[] grMem) {\n        gr_name = grName;\n        gr_passwd = grPasswd;\n        gr_id = grId;\n        gr_mem = grMem;\n    }\n}\n"
  },
  {
    "path": "libcore/compat/src/main/java/io/github/muntashirakon/compat/system/StructTimespec.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage io.github.muntashirakon.compat.system;\n\nimport androidx.annotation.Keep;\nimport androidx.annotation.NonNull;\n\n/**\n * Corresponds to C's {@code struct timespec} from {@code <time.h>}.\n */\n@Keep\npublic final class StructTimespec implements Comparable<StructTimespec> {\n    /**\n     * Seconds part of time of last data modification.\n     */\n    public final long tv_sec; /*time_t*/\n\n    /**\n     * Nanoseconds (values are [0, 999999999]).\n     */\n    public final long tv_nsec;\n\n    public StructTimespec(long tv_sec, long tv_nsec) {\n        this.tv_sec = tv_sec;\n        this.tv_nsec = tv_nsec;\n        if (tv_nsec == OsCompat.UTIME_OMIT || tv_nsec == OsCompat.UTIME_NOW) {\n            return;\n        }\n        if (tv_nsec < 0 || tv_nsec > 999_999_999) {\n            throw new IllegalArgumentException(\"tv_nsec value \" + tv_nsec + \" is not in [0, 999999999]\");\n        }\n    }\n\n    @Override\n    public int compareTo(StructTimespec other) {\n        if (tv_sec > other.tv_sec) {\n            return 1;\n        }\n        if (tv_sec < other.tv_sec) {\n            return -1;\n        }\n        if (tv_nsec > other.tv_nsec) {\n            return 1;\n        }\n        if (tv_nsec < other.tv_nsec) {\n            return -1;\n        }\n        return 0;\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) return true;\n        if (o == null || getClass() != o.getClass()) return false;\n\n        StructTimespec that = (StructTimespec) o;\n\n        if (tv_sec != that.tv_sec) return false;\n        return tv_nsec == that.tv_nsec;\n    }\n\n    @Override\n    public int hashCode() {\n        int result = (int) (tv_sec ^ (tv_sec >>> 32));\n        result = 31 * result + (int) (tv_nsec ^ (tv_nsec >>> 32));\n        return result;\n    }\n\n    @Override\n    @NonNull\n    public String toString() {\n        return \"StructTimespec{\" +\n                \"tv_sec=\" + tv_sec +\n                \", tv_nsec=\" + tv_nsec +\n                '}';\n    }\n}\n"
  },
  {
    "path": "libcore/compat/src/main/java/io/github/muntashirakon/compat/xml/BinaryXmlPullParser.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage io.github.muntashirakon.compat.xml;\n\nimport static io.github.muntashirakon.compat.xml.BinaryXmlSerializer.ATTRIBUTE;\nimport static io.github.muntashirakon.compat.xml.BinaryXmlSerializer.PROTOCOL_MAGIC_VERSION_0;\nimport static io.github.muntashirakon.compat.xml.BinaryXmlSerializer.TYPE_BOOLEAN_FALSE;\nimport static io.github.muntashirakon.compat.xml.BinaryXmlSerializer.TYPE_BOOLEAN_TRUE;\nimport static io.github.muntashirakon.compat.xml.BinaryXmlSerializer.TYPE_BYTES_BASE64;\nimport static io.github.muntashirakon.compat.xml.BinaryXmlSerializer.TYPE_BYTES_HEX;\nimport static io.github.muntashirakon.compat.xml.BinaryXmlSerializer.TYPE_DOUBLE;\nimport static io.github.muntashirakon.compat.xml.BinaryXmlSerializer.TYPE_FLOAT;\nimport static io.github.muntashirakon.compat.xml.BinaryXmlSerializer.TYPE_INT;\nimport static io.github.muntashirakon.compat.xml.BinaryXmlSerializer.TYPE_INT_HEX;\nimport static io.github.muntashirakon.compat.xml.BinaryXmlSerializer.TYPE_LONG;\nimport static io.github.muntashirakon.compat.xml.BinaryXmlSerializer.TYPE_LONG_HEX;\nimport static io.github.muntashirakon.compat.xml.BinaryXmlSerializer.TYPE_NULL;\nimport static io.github.muntashirakon.compat.xml.BinaryXmlSerializer.TYPE_STRING;\nimport static io.github.muntashirakon.compat.xml.BinaryXmlSerializer.TYPE_STRING_INTERNED;\n\nimport android.text.TextUtils;\nimport android.util.Base64;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport org.xmlpull.v1.XmlPullParser;\nimport org.xmlpull.v1.XmlPullParserException;\n\nimport java.io.EOFException;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.Reader;\nimport java.nio.charset.StandardCharsets;\nimport java.util.Arrays;\nimport java.util.Objects;\n\nimport io.github.muntashirakon.compat.io.FastDataInput;\n\n/**\n * Parser that reads XML documents using a custom binary wire protocol which\n * benchmarking has shown to be 8.5x faster than {@link Xml#newFastPullParser()}\n * for a typical {@code packages.xml}.\n * <p>\n * The high-level design of the wire protocol is to directly serialize the event\n * stream, while efficiently and compactly writing strongly-typed primitives\n * delivered through the {@link TypedXmlSerializer} interface.\n * <p>\n * Each serialized event is a single byte where the lower half is a normal\n * {@link XmlPullParser} token and the upper half is an optional data type\n * signal, such as {@link BinaryXmlSerializer#TYPE_INT}.\n * <p>\n * This parser has some specific limitations:\n * <ul>\n * <li>Only the UTF-8 encoding is supported.\n * <li>Variable length values, such as {@code byte[]} or {@link String}, are\n * limited to 65,535 bytes in length. Note that {@link String} values are stored\n * as UTF-8 on the wire.\n * <li>Namespaces, prefixes, properties, and options are unsupported.\n * </ul>\n */\npublic final class BinaryXmlPullParser implements TypedXmlPullParser {\n    private FastDataInput mIn;\n\n    private int mCurrentToken = START_DOCUMENT;\n    private int mCurrentDepth = 0;\n    private String mCurrentName;\n    private String mCurrentText;\n\n    /**\n     * Pool of attributes parsed for the currently tag. All interactions should\n     * be done via {@link #obtainAttribute()}, {@link #findAttribute(String)},\n     * and {@link #resetAttributes()}.\n     */\n    private int mAttributeCount = 0;\n    private Attribute[] mAttributes;\n\n    @Override\n    public void setInput(InputStream is, String encoding) throws XmlPullParserException {\n        if (encoding != null && !StandardCharsets.UTF_8.name().equalsIgnoreCase(encoding)) {\n            throw new UnsupportedOperationException();\n        }\n\n        if (mIn != null) {\n            mIn.release();\n            mIn = null;\n        }\n\n        mIn = FastDataInput.obtainUsing4ByteSequences(is);\n\n        mCurrentToken = START_DOCUMENT;\n        mCurrentDepth = 0;\n        mCurrentName = null;\n        mCurrentText = null;\n\n        mAttributeCount = 0;\n        mAttributes = new Attribute[8];\n        for (int i = 0; i < mAttributes.length; i++) {\n            mAttributes[i] = new Attribute();\n        }\n\n        try {\n            final byte[] magic = new byte[4];\n            mIn.readFully(magic);\n            if (!Arrays.equals(magic, PROTOCOL_MAGIC_VERSION_0)) {\n                throw new IOException(\"Unexpected magic \" + bytesToHexString(magic));\n            }\n\n            // We're willing to immediately consume a START_DOCUMENT if present,\n            // but we're okay if it's missing\n            if (peekNextExternalToken() == START_DOCUMENT) {\n                consumeToken();\n            }\n        } catch (IOException e) {\n            throw new XmlPullParserException(e.toString());\n        }\n    }\n\n    @Override\n    public void setInput(Reader in) throws XmlPullParserException {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public int next() throws XmlPullParserException, IOException {\n        while (true) {\n            final int token = nextToken();\n            switch (token) {\n                case START_TAG:\n                case END_TAG:\n                case END_DOCUMENT:\n                    return token;\n                case TEXT:\n                    consumeAdditionalText();\n                    // Per interface docs, empty text regions are skipped\n                    if (mCurrentText == null || mCurrentText.length() == 0) {\n                        continue;\n                    } else {\n                        return TEXT;\n                    }\n            }\n        }\n    }\n\n    @Override\n    public int nextToken() throws XmlPullParserException, IOException {\n        if (mCurrentToken == XmlPullParser.END_TAG) {\n            mCurrentDepth--;\n        }\n\n        int token;\n        try {\n            token = peekNextExternalToken();\n            consumeToken();\n        } catch (EOFException e) {\n            token = END_DOCUMENT;\n        }\n        switch (token) {\n            case XmlPullParser.START_TAG:\n                // We need to peek forward to find the next external token so\n                // that we parse all pending INTERNAL_ATTRIBUTE tokens\n                peekNextExternalToken();\n                mCurrentDepth++;\n                break;\n        }\n        mCurrentToken = token;\n        return token;\n    }\n\n    /**\n     * Peek at the next \"external\" token without consuming it.\n     * <p>\n     * External tokens, such as {@link #START_TAG}, are expected by typical\n     * {@link XmlPullParser} clients. In contrast, internal tokens, such as\n     * {@link BinaryXmlSerializer#ATTRIBUTE}, are not expected by typical clients.\n     * <p>\n     * This method consumes any internal events until it reaches the next\n     * external event.\n     */\n    private int peekNextExternalToken() throws IOException, XmlPullParserException {\n        while (true) {\n            final int token = peekNextToken();\n            switch (token) {\n                case ATTRIBUTE:\n                    consumeToken();\n                    continue;\n                default:\n                    return token;\n            }\n        }\n    }\n\n    /**\n     * Peek at the next token in the underlying stream without consuming it.\n     */\n    private int peekNextToken() throws IOException {\n        return mIn.peekByte() & 0x0f;\n    }\n\n    /**\n     * Parse and consume the next token in the underlying stream.\n     */\n    private void consumeToken() throws IOException, XmlPullParserException {\n        final int event = mIn.readByte();\n        final int token = event & 0x0f;\n        final int type = event & 0xf0;\n        switch (token) {\n            case ATTRIBUTE: {\n                final Attribute attr = obtainAttribute();\n                attr.name = mIn.readInternedUTF();\n                attr.type = type;\n                switch (type) {\n                    case TYPE_NULL:\n                    case TYPE_BOOLEAN_TRUE:\n                    case TYPE_BOOLEAN_FALSE:\n                        // Nothing extra to fill in\n                        break;\n                    case TYPE_STRING:\n                        attr.valueString = mIn.readUTF();\n                        break;\n                    case TYPE_STRING_INTERNED:\n                        attr.valueString = mIn.readInternedUTF();\n                        break;\n                    case TYPE_BYTES_HEX:\n                    case TYPE_BYTES_BASE64:\n                        final int len = mIn.readUnsignedShort();\n                        final byte[] res = new byte[len];\n                        mIn.readFully(res);\n                        attr.valueBytes = res;\n                        break;\n                    case TYPE_INT:\n                    case TYPE_INT_HEX:\n                        attr.valueInt = mIn.readInt();\n                        break;\n                    case TYPE_LONG:\n                    case TYPE_LONG_HEX:\n                        attr.valueLong = mIn.readLong();\n                        break;\n                    case TYPE_FLOAT:\n                        attr.valueFloat = mIn.readFloat();\n                        break;\n                    case TYPE_DOUBLE:\n                        attr.valueDouble = mIn.readDouble();\n                        break;\n                    default:\n                        throw new IOException(\"Unexpected data type \" + type);\n                }\n                break;\n            }\n            case XmlPullParser.START_DOCUMENT: {\n                mCurrentName = null;\n                mCurrentText = null;\n                if (mAttributeCount > 0) resetAttributes();\n                break;\n            }\n            case XmlPullParser.END_DOCUMENT: {\n                mCurrentName = null;\n                mCurrentText = null;\n                if (mAttributeCount > 0) resetAttributes();\n                break;\n            }\n            case XmlPullParser.START_TAG: {\n                mCurrentName = mIn.readInternedUTF();\n                mCurrentText = null;\n                if (mAttributeCount > 0) resetAttributes();\n                break;\n            }\n            case XmlPullParser.END_TAG: {\n                mCurrentName = mIn.readInternedUTF();\n                mCurrentText = null;\n                if (mAttributeCount > 0) resetAttributes();\n                break;\n            }\n            case XmlPullParser.TEXT:\n            case XmlPullParser.CDSECT:\n            case XmlPullParser.PROCESSING_INSTRUCTION:\n            case XmlPullParser.COMMENT:\n            case XmlPullParser.DOCDECL:\n            case XmlPullParser.IGNORABLE_WHITESPACE: {\n                mCurrentName = null;\n                mCurrentText = mIn.readUTF();\n                if (mAttributeCount > 0) resetAttributes();\n                break;\n            }\n            case XmlPullParser.ENTITY_REF: {\n                mCurrentName = mIn.readUTF();\n                mCurrentText = resolveEntity(mCurrentName);\n                if (mAttributeCount > 0) resetAttributes();\n                break;\n            }\n            default: {\n                throw new IOException(\"Unknown token \" + token + \" with type \" + type);\n            }\n        }\n    }\n\n    /**\n     * When the current tag is {@link #TEXT}, consume all subsequent \"text\"\n     * events, as described by {@link #next}. When finished, the current event\n     * will still be {@link #TEXT}.\n     */\n    private void consumeAdditionalText() throws IOException, XmlPullParserException {\n        String combinedText = mCurrentText;\n        while (true) {\n            final int token = peekNextExternalToken();\n            switch (token) {\n                case COMMENT:\n                case PROCESSING_INSTRUCTION:\n                    // Quietly consumed\n                    consumeToken();\n                    break;\n                case TEXT:\n                case CDSECT:\n                case ENTITY_REF:\n                    // Additional text regions collected\n                    consumeToken();\n                    combinedText += mCurrentText;\n                    break;\n                default:\n                    // Next token is something non-text, so wrap things up\n                    mCurrentToken = TEXT;\n                    mCurrentName = null;\n                    mCurrentText = combinedText;\n                    return;\n            }\n        }\n    }\n\n    static @NonNull String resolveEntity(@NonNull String entity)\n            throws XmlPullParserException {\n        switch (entity) {\n            case \"lt\": return \"<\";\n            case \"gt\": return \">\";\n            case \"amp\": return \"&\";\n            case \"apos\": return \"'\";\n            case \"quot\": return \"\\\"\";\n        }\n        if (entity.length() > 1 && entity.charAt(0) == '#') {\n            final char c = (char) Integer.parseInt(entity.substring(1));\n            return new String(new char[] { c });\n        }\n        throw new XmlPullParserException(\"Unknown entity \" + entity);\n    }\n\n    @Override\n    public void require(int type, String namespace, String name)\n            throws XmlPullParserException, IOException {\n        if (namespace != null && !namespace.isEmpty()) throw illegalNamespace();\n        if (mCurrentToken != type || !Objects.equals(mCurrentName, name)) {\n            throw new XmlPullParserException(getPositionDescription());\n        }\n    }\n\n    @Override\n    public String nextText() throws XmlPullParserException, IOException {\n        if (getEventType() != START_TAG) {\n            throw new XmlPullParserException(getPositionDescription());\n        }\n        int eventType = next();\n        if (eventType == TEXT) {\n            String result = getText();\n            eventType = next();\n            if (eventType != END_TAG) {\n                throw new XmlPullParserException(getPositionDescription());\n            }\n            return result;\n        } else if (eventType == END_TAG) {\n            return \"\";\n        } else {\n            throw new XmlPullParserException(getPositionDescription());\n        }\n    }\n\n    @Override\n    public int nextTag() throws XmlPullParserException, IOException {\n        int eventType = next();\n        if (eventType == TEXT && isWhitespace()) {\n            eventType = next();\n        }\n        if (eventType != START_TAG && eventType != END_TAG) {\n            throw new XmlPullParserException(getPositionDescription());\n        }\n        return eventType;\n    }\n\n    /**\n     * Allocate and return a new {@link Attribute} associated with the tag being\n     * currently processed. This will automatically grow the internal pool as\n     * needed.\n     */\n    private @NonNull Attribute obtainAttribute() {\n        if (mAttributeCount == mAttributes.length) {\n            final int before = mAttributes.length;\n            final int after = before + (before >> 1);\n            mAttributes = Arrays.copyOf(mAttributes, after);\n            for (int i = before; i < after; i++) {\n                mAttributes[i] = new Attribute();\n            }\n        }\n        return mAttributes[mAttributeCount++];\n    }\n\n    /**\n     * Clear any {@link Attribute} instances that have been allocated by\n     * {@link #obtainAttribute()}, returning them into the pool for recycling.\n     */\n    private void resetAttributes() {\n        for (int i = 0; i < mAttributeCount; i++) {\n            mAttributes[i].reset();\n        }\n        mAttributeCount = 0;\n    }\n\n    @Override\n    public int getAttributeIndex(String namespace, String name) {\n        if (namespace != null && !namespace.isEmpty()) throw illegalNamespace();\n        for (int i = 0; i < mAttributeCount; i++) {\n            if (Objects.equals(mAttributes[i].name, name)) {\n                return i;\n            }\n        }\n        return -1;\n    }\n\n    @Override\n    public String getAttributeValue(String namespace, String name) {\n        final int index = getAttributeIndex(namespace, name);\n        if (index != -1) {\n            return mAttributes[index].getValueString();\n        } else {\n            return null;\n        }\n    }\n\n    @Override\n    public String getAttributeValue(int index) {\n        return mAttributes[index].getValueString();\n    }\n\n    @Override\n    public byte[] getAttributeBytesHex(int index) throws XmlPullParserException {\n        return mAttributes[index].getValueBytesHex();\n    }\n\n    @Override\n    public byte[] getAttributeBytesBase64(int index) throws XmlPullParserException {\n        return mAttributes[index].getValueBytesBase64();\n    }\n\n    @Override\n    public int getAttributeInt(int index) throws XmlPullParserException {\n        return mAttributes[index].getValueInt();\n    }\n\n    @Override\n    public int getAttributeIntHex(int index) throws XmlPullParserException {\n        return mAttributes[index].getValueIntHex();\n    }\n\n    @Override\n    public long getAttributeLong(int index) throws XmlPullParserException {\n        return mAttributes[index].getValueLong();\n    }\n\n    @Override\n    public long getAttributeLongHex(int index) throws XmlPullParserException {\n        return mAttributes[index].getValueLongHex();\n    }\n\n    @Override\n    public float getAttributeFloat(int index) throws XmlPullParserException {\n        return mAttributes[index].getValueFloat();\n    }\n\n    @Override\n    public double getAttributeDouble(int index) throws XmlPullParserException {\n        return mAttributes[index].getValueDouble();\n    }\n\n    @Override\n    public boolean getAttributeBoolean(int index) throws XmlPullParserException {\n        return mAttributes[index].getValueBoolean();\n    }\n\n    @Override\n    public String getText() {\n        return mCurrentText;\n    }\n\n    @Override\n    public char[] getTextCharacters(int[] holderForStartAndLength) {\n        final char[] chars = mCurrentText.toCharArray();\n        holderForStartAndLength[0] = 0;\n        holderForStartAndLength[1] = chars.length;\n        return chars;\n    }\n\n    @Override\n    public String getInputEncoding() {\n        return StandardCharsets.UTF_8.name();\n    }\n\n    @Override\n    public int getDepth() {\n        return mCurrentDepth;\n    }\n\n    @Override\n    public String getPositionDescription() {\n        // Not very helpful, but it's the best information we have\n        return \"Token \" + mCurrentToken + \" at depth \" + mCurrentDepth;\n    }\n\n    @Override\n    public int getLineNumber() {\n        return -1;\n    }\n\n    @Override\n    public int getColumnNumber() {\n        return -1;\n    }\n\n    @Override\n    public boolean isWhitespace() throws XmlPullParserException {\n        switch (mCurrentToken) {\n            case IGNORABLE_WHITESPACE:\n                return true;\n            case TEXT:\n            case CDSECT:\n                return !TextUtils.isGraphic(mCurrentText);\n            default:\n                throw new XmlPullParserException(\"Not applicable for token \" + mCurrentToken);\n        }\n    }\n\n    @Override\n    public String getNamespace() {\n        switch (mCurrentToken) {\n            case START_TAG:\n            case END_TAG:\n                // Namespaces are unsupported\n                return NO_NAMESPACE;\n            default:\n                return null;\n        }\n    }\n\n    @Override\n    public String getName() {\n        return mCurrentName;\n    }\n\n    @Override\n    public String getPrefix() {\n        // Prefixes are not supported\n        return null;\n    }\n\n    @Override\n    public boolean isEmptyElementTag() throws XmlPullParserException {\n        switch (mCurrentToken) {\n            case START_TAG:\n                try {\n                    return (peekNextExternalToken() == END_TAG);\n                } catch (IOException e) {\n                    throw new XmlPullParserException(e.toString());\n                }\n            default:\n                throw new XmlPullParserException(\"Not at START_TAG\");\n        }\n    }\n\n    @Override\n    public int getAttributeCount() {\n        return mAttributeCount;\n    }\n\n    @Override\n    public String getAttributeNamespace(int index) {\n        // Namespaces are unsupported\n        return NO_NAMESPACE;\n    }\n\n    @Override\n    public String getAttributeName(int index) {\n        return mAttributes[index].name;\n    }\n\n    @Override\n    public String getAttributePrefix(int index) {\n        // Prefixes are not supported\n        return null;\n    }\n\n    @Override\n    public String getAttributeType(int index) {\n        // Validation is not supported\n        return \"CDATA\";\n    }\n\n    @Override\n    public boolean isAttributeDefault(int index) {\n        // Validation is not supported\n        return false;\n    }\n\n    @Override\n    public int getEventType() throws XmlPullParserException {\n        return mCurrentToken;\n    }\n\n    @Override\n    public int getNamespaceCount(int depth) throws XmlPullParserException {\n        // Namespaces are unsupported\n        return 0;\n    }\n\n    @Override\n    public String getNamespacePrefix(int pos) throws XmlPullParserException {\n        // Namespaces are unsupported\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public String getNamespaceUri(int pos) throws XmlPullParserException {\n        // Namespaces are unsupported\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public String getNamespace(String prefix) {\n        // Namespaces are unsupported\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public void defineEntityReplacementText(String entityName, String replacementText)\n            throws XmlPullParserException {\n        // Custom entities are not supported\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public void setFeature(String name, boolean state) throws XmlPullParserException {\n        // Features are not supported\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public boolean getFeature(String name) {\n        // Features are not supported\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public void setProperty(String name, Object value) throws XmlPullParserException {\n        // Properties are not supported\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public Object getProperty(String name) {\n        // Properties are not supported\n        throw new UnsupportedOperationException();\n    }\n\n    private static IllegalArgumentException illegalNamespace() {\n        throw new IllegalArgumentException(\"Namespaces are not supported\");\n    }\n\n    /**\n     * Holder representing a single attribute. This design enables object\n     * recycling without resorting to autoboxing.\n     * <p>\n     * To support conversion between human-readable XML and binary XML, the\n     * various accessor methods will transparently convert from/to\n     * human-readable values when needed.\n     */\n    private static class Attribute {\n        public String name;\n        public int type;\n\n        public String valueString;\n        public byte[] valueBytes;\n        public int valueInt;\n        public long valueLong;\n        public float valueFloat;\n        public double valueDouble;\n\n        public void reset() {\n            name = null;\n            valueString = null;\n            valueBytes = null;\n        }\n\n        public @Nullable String getValueString() {\n            switch (type) {\n                case TYPE_NULL:\n                    return null;\n                case TYPE_STRING:\n                case TYPE_STRING_INTERNED:\n                    return valueString;\n                case TYPE_BYTES_HEX:\n                    return bytesToHexString(valueBytes);\n                case TYPE_BYTES_BASE64:\n                    return Base64.encodeToString(valueBytes, Base64.NO_WRAP);\n                case TYPE_INT:\n                    return Integer.toString(valueInt);\n                case TYPE_INT_HEX:\n                    return Integer.toString(valueInt, 16);\n                case TYPE_LONG:\n                    return Long.toString(valueLong);\n                case TYPE_LONG_HEX:\n                    return Long.toString(valueLong, 16);\n                case TYPE_FLOAT:\n                    return Float.toString(valueFloat);\n                case TYPE_DOUBLE:\n                    return Double.toString(valueDouble);\n                case TYPE_BOOLEAN_TRUE:\n                    return \"true\";\n                case TYPE_BOOLEAN_FALSE:\n                    return \"false\";\n                default:\n                    // Unknown data type; null is the best we can offer\n                    return null;\n            }\n        }\n\n        public @Nullable byte[] getValueBytesHex() throws XmlPullParserException {\n            switch (type) {\n                case TYPE_NULL:\n                    return null;\n                case TYPE_BYTES_HEX:\n                case TYPE_BYTES_BASE64:\n                    return valueBytes;\n                case TYPE_STRING:\n                case TYPE_STRING_INTERNED:\n                    try {\n                        return hexStringToBytes(valueString);\n                    } catch (Exception e) {\n                        throw new XmlPullParserException(\"Invalid attribute \" + name + \": \" + e);\n                    }\n                default:\n                    throw new XmlPullParserException(\"Invalid conversion from \" + type);\n            }\n        }\n\n        public @Nullable byte[] getValueBytesBase64() throws XmlPullParserException {\n            switch (type) {\n                case TYPE_NULL:\n                    return null;\n                case TYPE_BYTES_HEX:\n                case TYPE_BYTES_BASE64:\n                    return valueBytes;\n                case TYPE_STRING:\n                case TYPE_STRING_INTERNED:\n                    try {\n                        return Base64.decode(valueString, Base64.NO_WRAP);\n                    } catch (Exception e) {\n                        throw new XmlPullParserException(\"Invalid attribute \" + name + \": \" + e);\n                    }\n                default:\n                    throw new XmlPullParserException(\"Invalid conversion from \" + type);\n            }\n        }\n\n        public int getValueInt() throws XmlPullParserException {\n            switch (type) {\n                case TYPE_INT:\n                case TYPE_INT_HEX:\n                    return valueInt;\n                case TYPE_STRING:\n                case TYPE_STRING_INTERNED:\n                    try {\n                        return Integer.parseInt(valueString);\n                    } catch (Exception e) {\n                        throw new XmlPullParserException(\"Invalid attribute \" + name + \": \" + e);\n                    }\n                default:\n                    throw new XmlPullParserException(\"Invalid conversion from \" + type);\n            }\n        }\n\n        public int getValueIntHex() throws XmlPullParserException {\n            switch (type) {\n                case TYPE_INT:\n                case TYPE_INT_HEX:\n                    return valueInt;\n                case TYPE_STRING:\n                case TYPE_STRING_INTERNED:\n                    try {\n                        return Integer.parseInt(valueString, 16);\n                    } catch (Exception e) {\n                        throw new XmlPullParserException(\"Invalid attribute \" + name + \": \" + e);\n                    }\n                default:\n                    throw new XmlPullParserException(\"Invalid conversion from \" + type);\n            }\n        }\n\n        public long getValueLong() throws XmlPullParserException {\n            switch (type) {\n                case TYPE_LONG:\n                case TYPE_LONG_HEX:\n                    return valueLong;\n                case TYPE_STRING:\n                case TYPE_STRING_INTERNED:\n                    try {\n                        return Long.parseLong(valueString);\n                    } catch (Exception e) {\n                        throw new XmlPullParserException(\"Invalid attribute \" + name + \": \" + e);\n                    }\n                default:\n                    throw new XmlPullParserException(\"Invalid conversion from \" + type);\n            }\n        }\n\n        public long getValueLongHex() throws XmlPullParserException {\n            switch (type) {\n                case TYPE_LONG:\n                case TYPE_LONG_HEX:\n                    return valueLong;\n                case TYPE_STRING:\n                case TYPE_STRING_INTERNED:\n                    try {\n                        return Long.parseLong(valueString, 16);\n                    } catch (Exception e) {\n                        throw new XmlPullParserException(\"Invalid attribute \" + name + \": \" + e);\n                    }\n                default:\n                    throw new XmlPullParserException(\"Invalid conversion from \" + type);\n            }\n        }\n\n        public float getValueFloat() throws XmlPullParserException {\n            switch (type) {\n                case TYPE_FLOAT:\n                    return valueFloat;\n                case TYPE_STRING:\n                case TYPE_STRING_INTERNED:\n                    try {\n                        return Float.parseFloat(valueString);\n                    } catch (Exception e) {\n                        throw new XmlPullParserException(\"Invalid attribute \" + name + \": \" + e);\n                    }\n                default:\n                    throw new XmlPullParserException(\"Invalid conversion from \" + type);\n            }\n        }\n\n        public double getValueDouble() throws XmlPullParserException {\n            switch (type) {\n                case TYPE_DOUBLE:\n                    return valueDouble;\n                case TYPE_STRING:\n                case TYPE_STRING_INTERNED:\n                    try {\n                        return Double.parseDouble(valueString);\n                    } catch (Exception e) {\n                        throw new XmlPullParserException(\"Invalid attribute \" + name + \": \" + e);\n                    }\n                default:\n                    throw new XmlPullParserException(\"Invalid conversion from \" + type);\n            }\n        }\n\n        public boolean getValueBoolean() throws XmlPullParserException {\n            switch (type) {\n                case TYPE_BOOLEAN_TRUE:\n                    return true;\n                case TYPE_BOOLEAN_FALSE:\n                    return false;\n                case TYPE_STRING:\n                case TYPE_STRING_INTERNED:\n                    if (\"true\".equalsIgnoreCase(valueString)) {\n                        return true;\n                    } else if (\"false\".equalsIgnoreCase(valueString)) {\n                        return false;\n                    } else {\n                        throw new XmlPullParserException(\n                                \"Invalid attribute \" + name + \": \" + valueString);\n                    }\n                default:\n                    throw new XmlPullParserException(\"Invalid conversion from \" + type);\n            }\n        }\n    }\n\n    // NOTE: To support unbundled clients, we include an inlined copy\n    // of hex conversion logic from HexDump below\n    private final static char[] HEX_DIGITS =\n            { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };\n\n    private static int toByte(char c) {\n        if (c >= '0' && c <= '9') return (c - '0');\n        if (c >= 'A' && c <= 'F') return (c - 'A' + 10);\n        if (c >= 'a' && c <= 'f') return (c - 'a' + 10);\n        throw new IllegalArgumentException(\"Invalid hex char '\" + c + \"'\");\n    }\n\n    static String bytesToHexString(byte[] value) {\n        final int length = value.length;\n        final char[] buf = new char[length * 2];\n        int bufIndex = 0;\n        for (int i = 0; i < length; i++) {\n            byte b = value[i];\n            buf[bufIndex++] = HEX_DIGITS[(b >>> 4) & 0x0F];\n            buf[bufIndex++] = HEX_DIGITS[b & 0x0F];\n        }\n        return new String(buf);\n    }\n\n    static byte[] hexStringToBytes(String value) {\n        final int length = value.length();\n        if (length % 2 != 0) {\n            throw new IllegalArgumentException(\"Invalid hex length \" + length);\n        }\n        byte[] buffer = new byte[length / 2];\n        for (int i = 0; i < length; i += 2) {\n            buffer[i / 2] = (byte) ((toByte(value.charAt(i)) << 4)\n                    | toByte(value.charAt(i + 1)));\n        }\n        return buffer;\n    }\n}"
  },
  {
    "path": "libcore/compat/src/main/java/io/github/muntashirakon/compat/xml/BinaryXmlSerializer.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage io.github.muntashirakon.compat.xml;\n\nimport static org.xmlpull.v1.XmlPullParser.CDSECT;\nimport static org.xmlpull.v1.XmlPullParser.COMMENT;\nimport static org.xmlpull.v1.XmlPullParser.DOCDECL;\nimport static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;\nimport static org.xmlpull.v1.XmlPullParser.END_TAG;\nimport static org.xmlpull.v1.XmlPullParser.ENTITY_REF;\nimport static org.xmlpull.v1.XmlPullParser.IGNORABLE_WHITESPACE;\nimport static org.xmlpull.v1.XmlPullParser.PROCESSING_INSTRUCTION;\nimport static org.xmlpull.v1.XmlPullParser.START_DOCUMENT;\nimport static org.xmlpull.v1.XmlPullParser.START_TAG;\nimport static org.xmlpull.v1.XmlPullParser.TEXT;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport org.xmlpull.v1.XmlPullParser;\nimport org.xmlpull.v1.XmlSerializer;\n\nimport java.io.IOException;\nimport java.io.OutputStream;\nimport java.io.Writer;\nimport java.nio.charset.StandardCharsets;\nimport java.util.Arrays;\n\nimport io.github.muntashirakon.compat.io.FastDataOutput;\n\n/**\n * Serializer that writes XML documents using a custom binary wire protocol\n * which benchmarking has shown to be 4.3x faster and use 2.4x less disk space\n * than {@code Xml.newFastSerializer()} for a typical {@code packages.xml}.\n * <p>\n * The high-level design of the wire protocol is to directly serialize the event\n * stream, while efficiently and compactly writing strongly-typed primitives\n * delivered through the {@link TypedXmlSerializer} interface.\n * <p>\n * Each serialized event is a single byte where the lower half is a normal\n * {@link XmlPullParser} token and the upper half is an optional data type\n * signal, such as {@link #TYPE_INT}.\n * <p>\n * This serializer has some specific limitations:\n * <ul>\n * <li>Only the UTF-8 encoding is supported.\n * <li>Variable length values, such as {@code byte[]} or {@link String}, are\n * limited to 65,535 bytes in length. Note that {@link String} values are stored\n * as UTF-8 on the wire.\n * <li>Namespaces, prefixes, properties, and options are unsupported.\n * </ul>\n */\npublic final class BinaryXmlSerializer implements TypedXmlSerializer {\n    /**\n     * The wire protocol always begins with a well-known magic value of\n     * {@code ABX_}, representing \"Android Binary XML.\" The final byte is a\n     * version number which may be incremented as the protocol changes.\n     */\n    public static final byte[] PROTOCOL_MAGIC_VERSION_0 = new byte[] { 0x41, 0x42, 0x58, 0x00 };\n\n    /**\n     * Internal token which represents an attribute associated with the most\n     * recent {@link XmlPullParser#START_TAG} token.\n     */\n    static final int ATTRIBUTE = 15;\n\n    static final int TYPE_NULL = 1 << 4;\n    static final int TYPE_STRING = 2 << 4;\n    static final int TYPE_STRING_INTERNED = 3 << 4;\n    static final int TYPE_BYTES_HEX = 4 << 4;\n    static final int TYPE_BYTES_BASE64 = 5 << 4;\n    static final int TYPE_INT = 6 << 4;\n    static final int TYPE_INT_HEX = 7 << 4;\n    static final int TYPE_LONG = 8 << 4;\n    static final int TYPE_LONG_HEX = 9 << 4;\n    static final int TYPE_FLOAT = 10 << 4;\n    static final int TYPE_DOUBLE = 11 << 4;\n    static final int TYPE_BOOLEAN_TRUE = 12 << 4;\n    static final int TYPE_BOOLEAN_FALSE = 13 << 4;\n\n    private FastDataOutput mOut;\n\n    /**\n     * Stack of tags which are currently active via {@link #startTag} and which\n     * haven't been terminated via {@link #endTag}.\n     */\n    private int mTagCount = 0;\n    private String[] mTagNames;\n\n    /**\n     * Write the given token and optional {@link String} into our buffer.\n     */\n    private void writeToken(int token, @Nullable String text) throws IOException {\n        if (text != null) {\n            mOut.writeByte(token | TYPE_STRING);\n            mOut.writeUTF(text);\n        } else {\n            mOut.writeByte(token | TYPE_NULL);\n        }\n    }\n\n    @Override\n    public void setOutput(@NonNull OutputStream os, @Nullable String encoding) throws IOException {\n        if (encoding != null && !StandardCharsets.UTF_8.name().equalsIgnoreCase(encoding)) {\n            throw new UnsupportedOperationException();\n        }\n\n        mOut = FastDataOutput.obtainUsing4ByteSequences(os);\n        mOut.write(PROTOCOL_MAGIC_VERSION_0);\n\n        mTagCount = 0;\n        mTagNames = new String[8];\n    }\n\n    @Override\n    public void setOutput(Writer writer) {\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public void flush() throws IOException {\n        if (mOut != null) {\n            mOut.flush();\n        }\n    }\n\n    @Override\n    public void startDocument(@Nullable String encoding, @Nullable Boolean standalone)\n            throws IOException {\n        if (encoding != null && !StandardCharsets.UTF_8.name().equalsIgnoreCase(encoding)) {\n            throw new UnsupportedOperationException();\n        }\n        if (standalone != null && !standalone) {\n            throw new UnsupportedOperationException();\n        }\n        mOut.writeByte(START_DOCUMENT | TYPE_NULL);\n    }\n\n    @Override\n    public void endDocument() throws IOException {\n        mOut.writeByte(END_DOCUMENT | TYPE_NULL);\n        flush();\n\n        mOut.release();\n        mOut = null;\n    }\n\n    @Override\n    public int getDepth() {\n        return mTagCount;\n    }\n\n    @Override\n    public String getNamespace() {\n        // Namespaces are unsupported\n        return XmlPullParser.NO_NAMESPACE;\n    }\n\n    @Override\n    public String getName() {\n        return mTagNames[mTagCount - 1];\n    }\n\n    @Override\n    public XmlSerializer startTag(String namespace, String name) throws IOException {\n        if (namespace != null && !namespace.isEmpty()) throw illegalNamespace();\n        if (mTagCount == mTagNames.length) {\n            mTagNames = Arrays.copyOf(mTagNames, mTagCount + (mTagCount >> 1));\n        }\n        mTagNames[mTagCount++] = name;\n        mOut.writeByte(START_TAG | TYPE_STRING_INTERNED);\n        mOut.writeInternedUTF(name);\n        return this;\n    }\n\n    @Override\n    public XmlSerializer endTag(String namespace, String name) throws IOException {\n        if (namespace != null && !namespace.isEmpty()) throw illegalNamespace();\n        mTagCount--;\n        mOut.writeByte(END_TAG | TYPE_STRING_INTERNED);\n        mOut.writeInternedUTF(name);\n        return this;\n    }\n\n    @Override\n    public XmlSerializer attribute(String namespace, String name, String value) throws IOException {\n        if (namespace != null && !namespace.isEmpty()) throw illegalNamespace();\n        mOut.writeByte(ATTRIBUTE | TYPE_STRING);\n        mOut.writeInternedUTF(name);\n        mOut.writeUTF(value);\n        return this;\n    }\n\n    @Override\n    public XmlSerializer attributeInterned(String namespace, String name, String value)\n            throws IOException {\n        if (namespace != null && !namespace.isEmpty()) throw illegalNamespace();\n        mOut.writeByte(ATTRIBUTE | TYPE_STRING_INTERNED);\n        mOut.writeInternedUTF(name);\n        mOut.writeInternedUTF(value);\n        return this;\n    }\n\n    @Override\n    public XmlSerializer attributeBytesHex(String namespace, String name, byte[] value)\n            throws IOException {\n        if (namespace != null && !namespace.isEmpty()) throw illegalNamespace();\n        mOut.writeByte(ATTRIBUTE | TYPE_BYTES_HEX);\n        mOut.writeInternedUTF(name);\n        mOut.writeShort(value.length);\n        mOut.write(value);\n        return this;\n    }\n\n    @Override\n    public XmlSerializer attributeBytesBase64(String namespace, String name, byte[] value)\n            throws IOException {\n        if (namespace != null && !namespace.isEmpty()) throw illegalNamespace();\n        mOut.writeByte(ATTRIBUTE | TYPE_BYTES_BASE64);\n        mOut.writeInternedUTF(name);\n        mOut.writeShort(value.length);\n        mOut.write(value);\n        return this;\n    }\n\n    @Override\n    public XmlSerializer attributeInt(String namespace, String name, int value)\n            throws IOException {\n        if (namespace != null && !namespace.isEmpty()) throw illegalNamespace();\n        mOut.writeByte(ATTRIBUTE | TYPE_INT);\n        mOut.writeInternedUTF(name);\n        mOut.writeInt(value);\n        return this;\n    }\n\n    @Override\n    public XmlSerializer attributeIntHex(String namespace, String name, int value)\n            throws IOException {\n        if (namespace != null && !namespace.isEmpty()) throw illegalNamespace();\n        mOut.writeByte(ATTRIBUTE | TYPE_INT_HEX);\n        mOut.writeInternedUTF(name);\n        mOut.writeInt(value);\n        return this;\n    }\n\n    @Override\n    public XmlSerializer attributeLong(String namespace, String name, long value)\n            throws IOException {\n        if (namespace != null && !namespace.isEmpty()) throw illegalNamespace();\n        mOut.writeByte(ATTRIBUTE | TYPE_LONG);\n        mOut.writeInternedUTF(name);\n        mOut.writeLong(value);\n        return this;\n    }\n\n    @Override\n    public XmlSerializer attributeLongHex(String namespace, String name, long value)\n            throws IOException {\n        if (namespace != null && !namespace.isEmpty()) throw illegalNamespace();\n        mOut.writeByte(ATTRIBUTE | TYPE_LONG_HEX);\n        mOut.writeInternedUTF(name);\n        mOut.writeLong(value);\n        return this;\n    }\n\n    @Override\n    public XmlSerializer attributeFloat(String namespace, String name, float value)\n            throws IOException {\n        if (namespace != null && !namespace.isEmpty()) throw illegalNamespace();\n        mOut.writeByte(ATTRIBUTE | TYPE_FLOAT);\n        mOut.writeInternedUTF(name);\n        mOut.writeFloat(value);\n        return this;\n    }\n\n    @Override\n    public XmlSerializer attributeDouble(String namespace, String name, double value)\n            throws IOException {\n        if (namespace != null && !namespace.isEmpty()) throw illegalNamespace();\n        mOut.writeByte(ATTRIBUTE | TYPE_DOUBLE);\n        mOut.writeInternedUTF(name);\n        mOut.writeDouble(value);\n        return this;\n    }\n\n    @Override\n    public XmlSerializer attributeBoolean(String namespace, String name, boolean value)\n            throws IOException {\n        if (namespace != null && !namespace.isEmpty()) throw illegalNamespace();\n        if (value) {\n            mOut.writeByte(ATTRIBUTE | TYPE_BOOLEAN_TRUE);\n            mOut.writeInternedUTF(name);\n        } else {\n            mOut.writeByte(ATTRIBUTE | TYPE_BOOLEAN_FALSE);\n            mOut.writeInternedUTF(name);\n        }\n        return this;\n    }\n\n    @Override\n    public XmlSerializer text(char[] buf, int start, int len) throws IOException {\n        writeToken(TEXT, new String(buf, start, len));\n        return this;\n    }\n\n    @Override\n    public XmlSerializer text(String text) throws IOException {\n        writeToken(TEXT, text);\n        return this;\n    }\n\n    @Override\n    public void cdsect(String text) throws IOException {\n        writeToken(CDSECT, text);\n    }\n\n    @Override\n    public void entityRef(String text) throws IOException {\n        writeToken(ENTITY_REF, text);\n    }\n\n    @Override\n    public void processingInstruction(String text) throws IOException {\n        writeToken(PROCESSING_INSTRUCTION, text);\n    }\n\n    @Override\n    public void comment(String text) throws IOException {\n        writeToken(COMMENT, text);\n    }\n\n    @Override\n    public void docdecl(String text) throws IOException {\n        writeToken(DOCDECL, text);\n    }\n\n    @Override\n    public void ignorableWhitespace(String text) throws IOException {\n        writeToken(IGNORABLE_WHITESPACE, text);\n    }\n\n    @Override\n    public void setFeature(String name, boolean state) {\n        // Quietly handle no-op features\n        if (\"http://xmlpull.org/v1/doc/features.html#indent-output\".equals(name)) {\n            return;\n        }\n        // Features are not supported\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public boolean getFeature(String name) {\n        // Features are not supported\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public void setProperty(String name, Object value) {\n        // Properties are not supported\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public Object getProperty(String name) {\n        // Properties are not supported\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public void setPrefix(String prefix, String namespace) {\n        // Prefixes are not supported\n        throw new UnsupportedOperationException();\n    }\n\n    @Override\n    public String getPrefix(String namespace, boolean generatePrefix) {\n        // Prefixes are not supported\n        throw new UnsupportedOperationException();\n    }\n\n    private static IllegalArgumentException illegalNamespace() {\n        throw new IllegalArgumentException(\"Namespaces are not supported\");\n    }\n}"
  },
  {
    "path": "libcore/compat/src/main/java/io/github/muntashirakon/compat/xml/FastXmlSerializer.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage io.github.muntashirakon.compat.xml;\n\nimport org.xmlpull.v1.XmlSerializer;\n\nimport java.io.IOException;\nimport java.io.OutputStream;\nimport java.io.OutputStreamWriter;\nimport java.io.UnsupportedEncodingException;\nimport java.io.Writer;\nimport java.nio.ByteBuffer;\nimport java.nio.CharBuffer;\nimport java.nio.charset.Charset;\nimport java.nio.charset.CharsetEncoder;\nimport java.nio.charset.CoderResult;\nimport java.nio.charset.CodingErrorAction;\nimport java.nio.charset.IllegalCharsetNameException;\nimport java.nio.charset.UnsupportedCharsetException;\n\n/**\n * This is a quick and dirty implementation of XmlSerializer that isn't horribly\n * painfully slow like the normal one.  It only does what is needed for the\n * specific XML files being written with it.\n */\npublic class FastXmlSerializer implements XmlSerializer {\n    private static final String ESCAPE_TABLE[] = new String[] {\n        \"&#0;\",   \"&#1;\",   \"&#2;\",   \"&#3;\",  \"&#4;\",    \"&#5;\",   \"&#6;\",  \"&#7;\",  // 0-7\n        \"&#8;\",   \"&#9;\",   \"&#10;\",  \"&#11;\", \"&#12;\",   \"&#13;\",  \"&#14;\", \"&#15;\", // 8-15\n        \"&#16;\",  \"&#17;\",  \"&#18;\",  \"&#19;\", \"&#20;\",   \"&#21;\",  \"&#22;\", \"&#23;\", // 16-23\n        \"&#24;\",  \"&#25;\",  \"&#26;\",  \"&#27;\", \"&#28;\",   \"&#29;\",  \"&#30;\", \"&#31;\", // 24-31\n        null,     null,     \"&quot;\", null,     null,     null,     \"&amp;\",  null,   // 32-39\n        null,     null,     null,     null,     null,     null,     null,     null,   // 40-47\n        null,     null,     null,     null,     null,     null,     null,     null,   // 48-55\n        null,     null,     null,     null,     \"&lt;\",   null,     \"&gt;\",   null,   // 56-63\n    };\n\n    private static final int DEFAULT_BUFFER_LEN = 32*1024;\n\n    private static String sSpace = \"                                                              \";\n\n    private final int mBufferLen;\n    private final char[] mText;\n    private int mPos;\n\n    private Writer mWriter;\n\n    private OutputStream mOutputStream;\n    private CharsetEncoder mCharset;\n    private ByteBuffer mBytes;\n\n    private boolean mIndent = false;\n    private boolean mInTag;\n\n    private int mNesting = 0;\n    private boolean mLineStart = true;\n\n    public FastXmlSerializer() {\n        this(DEFAULT_BUFFER_LEN);\n    }\n\n    /**\n     * Allocate a FastXmlSerializer with the given internal output buffer size.  If the\n     * size is zero or negative, then the default buffer size will be used.\n     *\n     * @param bufferSize Size in bytes of the in-memory output buffer that the writer will use.\n     */\n    public FastXmlSerializer(int bufferSize) {\n        mBufferLen = (bufferSize > 0) ? bufferSize : DEFAULT_BUFFER_LEN;\n        mText = new char[mBufferLen];\n        mBytes = ByteBuffer.allocate(mBufferLen);\n    }\n\n    private void append(char c) throws IOException {\n        int pos = mPos;\n        if (pos >= (mBufferLen-1)) {\n            flush();\n            pos = mPos;\n        }\n        mText[pos] = c;\n        mPos = pos+1;\n    }\n\n    private void append(String str, int i, final int length) throws IOException {\n        if (length > mBufferLen) {\n            final int end = i + length;\n            while (i < end) {\n                int next = i + mBufferLen;\n                append(str, i, next<end ? mBufferLen : (end-i));\n                i = next;\n            }\n            return;\n        }\n        int pos = mPos;\n        if ((pos+length) > mBufferLen) {\n            flush();\n            pos = mPos;\n        }\n        str.getChars(i, i+length, mText, pos);\n        mPos = pos + length;\n    }\n\n    private void append(char[] buf, int i, final int length) throws IOException {\n        if (length > mBufferLen) {\n            final int end = i + length;\n            while (i < end) {\n                int next = i + mBufferLen;\n                append(buf, i, next<end ? mBufferLen : (end-i));\n                i = next;\n            }\n            return;\n        }\n        int pos = mPos;\n        if ((pos+length) > mBufferLen) {\n            flush();\n            pos = mPos;\n        }\n        System.arraycopy(buf, i, mText, pos, length);\n        mPos = pos + length;\n    }\n\n    private void append(String str) throws IOException {\n        append(str, 0, str.length());\n    }\n\n    private void appendIndent(int indent) throws IOException {\n        indent *= 4;\n        if (indent > sSpace.length()) {\n            indent = sSpace.length();\n        }\n        append(sSpace, 0, indent);\n    }\n\n    private void escapeAndAppendString(final String string) throws IOException {\n        final int N = string.length();\n        final char NE = (char)ESCAPE_TABLE.length;\n        final String[] escapes = ESCAPE_TABLE;\n        int lastPos = 0;\n        int pos;\n        for (pos=0; pos<N; pos++) {\n            char c = string.charAt(pos);\n            if (c >= NE) continue;\n            String escape = escapes[c];\n            if (escape == null) continue;\n            if (lastPos < pos) append(string, lastPos, pos-lastPos);\n            lastPos = pos + 1;\n            append(escape);\n        }\n        if (lastPos < pos) append(string, lastPos, pos-lastPos);\n    }\n\n    private void escapeAndAppendString(char[] buf, int start, int len) throws IOException {\n        final char NE = (char)ESCAPE_TABLE.length;\n        final String[] escapes = ESCAPE_TABLE;\n        int end = start+len;\n        int lastPos = start;\n        int pos;\n        for (pos=start; pos<end; pos++) {\n            char c = buf[pos];\n            if (c >= NE) continue;\n            String escape = escapes[c];\n            if (escape == null) continue;\n            if (lastPos < pos) append(buf, lastPos, pos-lastPos);\n            lastPos = pos + 1;\n            append(escape);\n        }\n        if (lastPos < pos) append(buf, lastPos, pos-lastPos);\n    }\n\n    public XmlSerializer attribute(String namespace, String name, String value) throws IOException,\n            IllegalArgumentException, IllegalStateException {\n        append(' ');\n        if (namespace != null) {\n            append(namespace);\n            append(':');\n        }\n        append(name);\n        append(\"=\\\"\");\n\n        escapeAndAppendString(value);\n        append('\"');\n        mLineStart = false;\n        return this;\n    }\n\n    public void cdsect(String text) throws IOException, IllegalArgumentException,\n            IllegalStateException {\n        throw new UnsupportedOperationException();\n    }\n\n    public void comment(String text) throws IOException, IllegalArgumentException,\n            IllegalStateException {\n        throw new UnsupportedOperationException();\n    }\n\n    public void docdecl(String text) throws IOException, IllegalArgumentException,\n            IllegalStateException {\n        throw new UnsupportedOperationException();\n    }\n\n    public void endDocument() throws IOException, IllegalArgumentException, IllegalStateException {\n        flush();\n    }\n\n    public XmlSerializer endTag(String namespace, String name) throws IOException,\n            IllegalArgumentException, IllegalStateException {\n        mNesting--;\n        if (mInTag) {\n            append(\" />\\n\");\n        } else {\n            if (mIndent && mLineStart) {\n                appendIndent(mNesting);\n            }\n            append(\"</\");\n            if (namespace != null) {\n                append(namespace);\n                append(':');\n            }\n            append(name);\n            append(\">\\n\");\n        }\n        mLineStart = true;\n        mInTag = false;\n        return this;\n    }\n\n    public void entityRef(String text) throws IOException, IllegalArgumentException,\n            IllegalStateException {\n        throw new UnsupportedOperationException();\n    }\n\n    private void flushBytes() throws IOException {\n        int position;\n        if ((position = mBytes.position()) > 0) {\n            mBytes.flip();\n            mOutputStream.write(mBytes.array(), 0, position);\n            mBytes.clear();\n        }\n    }\n\n    public void flush() throws IOException {\n        //Log.i(\"PackageManager\", \"flush mPos=\" + mPos);\n        if (mPos > 0) {\n            if (mOutputStream != null) {\n                CharBuffer charBuffer = CharBuffer.wrap(mText, 0, mPos);\n                CoderResult result = mCharset.encode(charBuffer, mBytes, true);\n                while (true) {\n                    if (result.isError()) {\n                        throw new IOException(result.toString());\n                    } else if (result.isOverflow()) {\n                        flushBytes();\n                        result = mCharset.encode(charBuffer, mBytes, true);\n                        continue;\n                    }\n                    break;\n                }\n                flushBytes();\n                mOutputStream.flush();\n            } else {\n                mWriter.write(mText, 0, mPos);\n                mWriter.flush();\n            }\n            mPos = 0;\n        }\n    }\n\n    public int getDepth() {\n        throw new UnsupportedOperationException();\n    }\n\n    public boolean getFeature(String name) {\n        throw new UnsupportedOperationException();\n    }\n\n    public String getName() {\n        throw new UnsupportedOperationException();\n    }\n\n    public String getNamespace() {\n        throw new UnsupportedOperationException();\n    }\n\n    public String getPrefix(String namespace, boolean generatePrefix)\n            throws IllegalArgumentException {\n        throw new UnsupportedOperationException();\n    }\n\n    public Object getProperty(String name) {\n        throw new UnsupportedOperationException();\n    }\n\n    public void ignorableWhitespace(String text) throws IOException, IllegalArgumentException,\n            IllegalStateException {\n        throw new UnsupportedOperationException();\n    }\n\n    public void processingInstruction(String text) throws IOException, IllegalArgumentException,\n            IllegalStateException {\n        throw new UnsupportedOperationException();\n    }\n\n    public void setFeature(String name, boolean state) throws IllegalArgumentException,\n            IllegalStateException {\n        if (name.equals(\"http://xmlpull.org/v1/doc/features.html#indent-output\")) {\n            mIndent = true;\n            return;\n        }\n        throw new UnsupportedOperationException();\n    }\n\n    public void setOutput(OutputStream os, String encoding) throws IOException,\n            IllegalArgumentException, IllegalStateException {\n        if (os == null)\n            throw new IllegalArgumentException();\n        if (true) {\n            try {\n                mCharset = Charset.forName(encoding).newEncoder()\n                        .onMalformedInput(CodingErrorAction.REPLACE)\n                        .onUnmappableCharacter(CodingErrorAction.REPLACE);\n            } catch (IllegalCharsetNameException e) {\n                throw (UnsupportedEncodingException) (new UnsupportedEncodingException(\n                        encoding).initCause(e));\n            } catch (UnsupportedCharsetException e) {\n                throw (UnsupportedEncodingException) (new UnsupportedEncodingException(\n                        encoding).initCause(e));\n            }\n            mOutputStream = os;\n        } else {\n            setOutput(\n                encoding == null\n                    ? new OutputStreamWriter(os)\n                    : new OutputStreamWriter(os, encoding));\n        }\n    }\n\n    public void setOutput(Writer writer) throws IOException, IllegalArgumentException,\n            IllegalStateException {\n        mWriter = writer;\n    }\n\n    public void setPrefix(String prefix, String namespace) throws IOException,\n            IllegalArgumentException, IllegalStateException {\n        throw new UnsupportedOperationException();\n    }\n\n    public void setProperty(String name, Object value) throws IllegalArgumentException,\n            IllegalStateException {\n        throw new UnsupportedOperationException();\n    }\n\n    public void startDocument(String encoding, Boolean standalone) throws IOException,\n            IllegalArgumentException, IllegalStateException {\n        append(\"<?xml version='1.0' encoding='utf-8'\");\n        if (standalone != null) {\n            append(\" standalone='\" + (standalone ? \"yes\" : \"no\") + \"'\");\n        }\n        append(\" ?>\\n\");\n        mLineStart = true;\n    }\n\n    public XmlSerializer startTag(String namespace, String name) throws IOException,\n            IllegalArgumentException, IllegalStateException {\n        if (mInTag) {\n            append(\">\\n\");\n        }\n        if (mIndent) {\n            appendIndent(mNesting);\n        }\n        mNesting++;\n        append('<');\n        if (namespace != null) {\n            append(namespace);\n            append(':');\n        }\n        append(name);\n        mInTag = true;\n        mLineStart = false;\n        return this;\n    }\n\n    public XmlSerializer text(char[] buf, int start, int len) throws IOException,\n            IllegalArgumentException, IllegalStateException {\n        if (mInTag) {\n            append(\">\");\n            mInTag = false;\n        }\n        escapeAndAppendString(buf, start, len);\n        if (mIndent) {\n            mLineStart = buf[start+len-1] == '\\n';\n        }\n        return this;\n    }\n\n    public XmlSerializer text(String text) throws IOException, IllegalArgumentException,\n            IllegalStateException {\n        if (mInTag) {\n            append(\">\");\n            mInTag = false;\n        }\n        escapeAndAppendString(text);\n        if (mIndent) {\n            mLineStart = text.length() > 0 && (text.charAt(text.length()-1) == '\\n');\n        }\n        return this;\n    }\n\n}"
  },
  {
    "path": "libcore/compat/src/main/java/io/github/muntashirakon/compat/xml/TypedXmlPullParser.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage io.github.muntashirakon.compat.xml;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport org.xmlpull.v1.XmlPullParser;\nimport org.xmlpull.v1.XmlPullParserException;\n\n/**\n * Specialization of {@link XmlPullParser} which adds explicit methods to\n * support consistent and efficient conversion of primitive data types.\n */\npublic interface TypedXmlPullParser extends XmlPullParser {\n    /**\n     * @return index of requested attribute, otherwise {@code -1} if undefined\n     */\n    default int getAttributeIndex(@Nullable String namespace, @NonNull String name) {\n        final boolean namespaceNull = (namespace == null);\n        final int count = getAttributeCount();\n        for (int i = 0; i < count; i++) {\n            if ((namespaceNull || namespace.equals(getAttributeNamespace(i)))\n                    && name.equals(getAttributeName(i))) {\n                return i;\n            }\n        }\n        return -1;\n    }\n\n    /**\n     * @return index of requested attribute\n     * @throws XmlPullParserException if the value is undefined\n     */\n    default int getAttributeIndexOrThrow(@Nullable String namespace, @NonNull String name)\n            throws XmlPullParserException {\n        final int index = getAttributeIndex(namespace, name);\n        if (index == -1) {\n            throw new XmlPullParserException(\"Missing attribute \" + name);\n        } else {\n            return index;\n        }\n    }\n\n    /**\n     * @return decoded strongly-typed {@link #getAttributeValue}\n     * @throws XmlPullParserException if the value is malformed\n     */\n    @NonNull\n    byte[] getAttributeBytesHex(int index) throws XmlPullParserException;\n\n    /**\n     * @return decoded strongly-typed {@link #getAttributeValue}\n     * @throws XmlPullParserException if the value is malformed\n     */\n    @NonNull\n    byte[] getAttributeBytesBase64(int index) throws XmlPullParserException;\n\n    /**\n     * @return decoded strongly-typed {@link #getAttributeValue}\n     * @throws XmlPullParserException if the value is malformed\n     */\n    int getAttributeInt(int index) throws XmlPullParserException;\n\n    /**\n     * @return decoded strongly-typed {@link #getAttributeValue}\n     * @throws XmlPullParserException if the value is malformed\n     */\n    int getAttributeIntHex(int index) throws XmlPullParserException;\n\n    /**\n     * @return decoded strongly-typed {@link #getAttributeValue}\n     * @throws XmlPullParserException if the value is malformed\n     */\n    long getAttributeLong(int index) throws XmlPullParserException;\n\n    /**\n     * @return decoded strongly-typed {@link #getAttributeValue}\n     * @throws XmlPullParserException if the value is malformed\n     */\n    long getAttributeLongHex(int index) throws XmlPullParserException;\n\n    /**\n     * @return decoded strongly-typed {@link #getAttributeValue}\n     * @throws XmlPullParserException if the value is malformed\n     */\n    float getAttributeFloat(int index) throws XmlPullParserException;\n\n    /**\n     * @return decoded strongly-typed {@link #getAttributeValue}\n     * @throws XmlPullParserException if the value is malformed\n     */\n    double getAttributeDouble(int index) throws XmlPullParserException;\n\n    /**\n     * @return decoded strongly-typed {@link #getAttributeValue}\n     * @throws XmlPullParserException if the value is malformed\n     */\n    boolean getAttributeBoolean(int index) throws XmlPullParserException;\n\n    /**\n     * @return decoded strongly-typed {@link #getAttributeValue}\n     * @throws XmlPullParserException if the value is malformed or undefined\n     */\n    default @NonNull byte[] getAttributeBytesHex(@Nullable String namespace,\n                                                 @NonNull String name) throws XmlPullParserException {\n        return getAttributeBytesHex(getAttributeIndexOrThrow(namespace, name));\n    }\n\n    /**\n     * @return decoded strongly-typed {@link #getAttributeValue}\n     * @throws XmlPullParserException if the value is malformed or undefined\n     */\n    default @NonNull byte[] getAttributeBytesBase64(@Nullable String namespace,\n                                                    @NonNull String name) throws XmlPullParserException {\n        return getAttributeBytesBase64(getAttributeIndexOrThrow(namespace, name));\n    }\n\n    /**\n     * @return decoded strongly-typed {@link #getAttributeValue}\n     * @throws XmlPullParserException if the value is malformed or undefined\n     */\n    default int getAttributeInt(@Nullable String namespace, @NonNull String name)\n            throws XmlPullParserException {\n        return getAttributeInt(getAttributeIndexOrThrow(namespace, name));\n    }\n\n    /**\n     * @return decoded strongly-typed {@link #getAttributeValue}\n     * @throws XmlPullParserException if the value is malformed or undefined\n     */\n    default int getAttributeIntHex(@Nullable String namespace, @NonNull String name)\n            throws XmlPullParserException {\n        return getAttributeIntHex(getAttributeIndexOrThrow(namespace, name));\n    }\n\n    /**\n     * @return decoded strongly-typed {@link #getAttributeValue}\n     * @throws XmlPullParserException if the value is malformed or undefined\n     */\n    default long getAttributeLong(@Nullable String namespace, @NonNull String name)\n            throws XmlPullParserException {\n        return getAttributeLong(getAttributeIndexOrThrow(namespace, name));\n    }\n\n    /**\n     * @return decoded strongly-typed {@link #getAttributeValue}\n     * @throws XmlPullParserException if the value is malformed or undefined\n     */\n    default long getAttributeLongHex(@Nullable String namespace, @NonNull String name)\n            throws XmlPullParserException {\n        return getAttributeLongHex(getAttributeIndexOrThrow(namespace, name));\n    }\n\n    /**\n     * @return decoded strongly-typed {@link #getAttributeValue}\n     * @throws XmlPullParserException if the value is malformed or undefined\n     */\n    default float getAttributeFloat(@Nullable String namespace, @NonNull String name)\n            throws XmlPullParserException {\n        return getAttributeFloat(getAttributeIndexOrThrow(namespace, name));\n    }\n\n    /**\n     * @return decoded strongly-typed {@link #getAttributeValue}\n     * @throws XmlPullParserException if the value is malformed or undefined\n     */\n    default double getAttributeDouble(@Nullable String namespace, @NonNull String name)\n            throws XmlPullParserException {\n        return getAttributeDouble(getAttributeIndexOrThrow(namespace, name));\n    }\n\n    /**\n     * @return decoded strongly-typed {@link #getAttributeValue}\n     * @throws XmlPullParserException if the value is malformed or undefined\n     */\n    default boolean getAttributeBoolean(@Nullable String namespace, @NonNull String name)\n            throws XmlPullParserException {\n        return getAttributeBoolean(getAttributeIndexOrThrow(namespace, name));\n    }\n\n    /**\n     * @return decoded strongly-typed {@link #getAttributeValue}, otherwise\n     * default value if the value is malformed or undefined\n     */\n    default @Nullable byte[] getAttributeBytesHex(@Nullable String namespace,\n                                                  @NonNull String name, @Nullable byte[] defaultValue) {\n        final int index = getAttributeIndex(namespace, name);\n        if (index == -1) return defaultValue;\n        try {\n            return getAttributeBytesHex(index);\n        } catch (Exception ignored) {\n            return defaultValue;\n        }\n    }\n\n    /**\n     * @return decoded strongly-typed {@link #getAttributeValue}, otherwise\n     * default value if the value is malformed or undefined\n     */\n    default @Nullable byte[] getAttributeBytesBase64(@Nullable String namespace,\n                                                     @NonNull String name, @Nullable byte[] defaultValue) {\n        final int index = getAttributeIndex(namespace, name);\n        if (index == -1) return defaultValue;\n        try {\n            return getAttributeBytesBase64(index);\n        } catch (Exception ignored) {\n            return defaultValue;\n        }\n    }\n\n    /**\n     * @return decoded strongly-typed {@link #getAttributeValue}, otherwise\n     * default value if the value is malformed or undefined\n     */\n    default int getAttributeInt(@Nullable String namespace, @NonNull String name,\n                                int defaultValue) {\n        final int index = getAttributeIndex(namespace, name);\n        if (index == -1) return defaultValue;\n        try {\n            return getAttributeInt(index);\n        } catch (Exception ignored) {\n            return defaultValue;\n        }\n    }\n\n    /**\n     * @return decoded strongly-typed {@link #getAttributeValue}, otherwise\n     * default value if the value is malformed or undefined\n     */\n    default int getAttributeIntHex(@Nullable String namespace, @NonNull String name,\n                                   int defaultValue) {\n        final int index = getAttributeIndex(namespace, name);\n        if (index == -1) return defaultValue;\n        try {\n            return getAttributeIntHex(index);\n        } catch (Exception ignored) {\n            return defaultValue;\n        }\n    }\n\n    /**\n     * @return decoded strongly-typed {@link #getAttributeValue}, otherwise\n     * default value if the value is malformed or undefined\n     */\n    default long getAttributeLong(@Nullable String namespace, @NonNull String name,\n                                  long defaultValue) {\n        final int index = getAttributeIndex(namespace, name);\n        if (index == -1) return defaultValue;\n        try {\n            return getAttributeLong(index);\n        } catch (Exception ignored) {\n            return defaultValue;\n        }\n    }\n\n    /**\n     * @return decoded strongly-typed {@link #getAttributeValue}, otherwise\n     * default value if the value is malformed or undefined\n     */\n    default long getAttributeLongHex(@Nullable String namespace, @NonNull String name,\n                                     long defaultValue) {\n        final int index = getAttributeIndex(namespace, name);\n        if (index == -1) return defaultValue;\n        try {\n            return getAttributeLongHex(index);\n        } catch (Exception ignored) {\n            return defaultValue;\n        }\n    }\n\n    /**\n     * @return decoded strongly-typed {@link #getAttributeValue}, otherwise\n     * default value if the value is malformed or undefined\n     */\n    default float getAttributeFloat(@Nullable String namespace, @NonNull String name,\n                                    float defaultValue) {\n        final int index = getAttributeIndex(namespace, name);\n        if (index == -1) return defaultValue;\n        try {\n            return getAttributeFloat(index);\n        } catch (Exception ignored) {\n            return defaultValue;\n        }\n    }\n\n    /**\n     * @return decoded strongly-typed {@link #getAttributeValue}, otherwise\n     * default value if the value is malformed or undefined\n     */\n    default double getAttributeDouble(@Nullable String namespace, @NonNull String name,\n                                      double defaultValue) {\n        final int index = getAttributeIndex(namespace, name);\n        if (index == -1) return defaultValue;\n        try {\n            return getAttributeDouble(index);\n        } catch (Exception ignored) {\n            return defaultValue;\n        }\n    }\n\n    /**\n     * @return decoded strongly-typed {@link #getAttributeValue}, otherwise\n     * default value if the value is malformed or undefined\n     */\n    default boolean getAttributeBoolean(@Nullable String namespace, @NonNull String name,\n                                        boolean defaultValue) {\n        final int index = getAttributeIndex(namespace, name);\n        if (index == -1) return defaultValue;\n        try {\n            return getAttributeBoolean(index);\n        } catch (Exception ignored) {\n            return defaultValue;\n        }\n    }\n}"
  },
  {
    "path": "libcore/compat/src/main/java/io/github/muntashirakon/compat/xml/TypedXmlSerializer.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage io.github.muntashirakon.compat.xml;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.RequiresApi;\n\nimport org.xmlpull.v1.XmlSerializer;\n\nimport java.io.IOException;\n\n/**\n * Specialization of {@link XmlSerializer} which adds explicit methods to\n * support consistent and efficient conversion of primitive data types.\n */\npublic interface TypedXmlSerializer extends XmlSerializer {\n    /**\n     * Functionally equivalent to {@link #attribute(String, String, String)} but\n     * with the additional signal that the given value is a candidate for being\n     * canonicalized, similar to {@link String#intern()}.\n     */\n    @NonNull\n    XmlSerializer attributeInterned(@Nullable String namespace, @NonNull String name,\n                                    @NonNull String value) throws IOException;\n\n    /**\n     * Encode the given strongly-typed value and serialize using\n     * {@link #attribute(String, String, String)}.\n     */\n    @NonNull\n    XmlSerializer attributeBytesHex(@Nullable String namespace, @NonNull String name,\n                                    @NonNull byte[] value) throws IOException;\n\n    /**\n     * Encode the given strongly-typed value and serialize using\n     * {@link #attribute(String, String, String)}.\n     */\n    @NonNull\n    XmlSerializer attributeBytesBase64(@Nullable String namespace, @NonNull String name,\n                                       @NonNull byte[] value) throws IOException;\n\n    /**\n     * Encode the given strongly-typed value and serialize using\n     * {@link #attribute(String, String, String)}.\n     */\n    @NonNull\n    XmlSerializer attributeInt(@Nullable String namespace, @NonNull String name,\n                               int value) throws IOException;\n\n    /**\n     * Encode the given strongly-typed value and serialize using\n     * {@link #attribute(String, String, String)}.\n     */\n    @NonNull\n    XmlSerializer attributeIntHex(@Nullable String namespace, @NonNull String name,\n                                  int value) throws IOException;\n\n    /**\n     * Encode the given strongly-typed value and serialize using\n     * {@link #attribute(String, String, String)}.\n     */\n    @NonNull\n    XmlSerializer attributeLong(@Nullable String namespace, @NonNull String name,\n                                long value) throws IOException;\n\n    /**\n     * Encode the given strongly-typed value and serialize using\n     * {@link #attribute(String, String, String)}.\n     */\n    @NonNull\n    XmlSerializer attributeLongHex(@Nullable String namespace, @NonNull String name,\n                                   long value) throws IOException;\n\n    /**\n     * Encode the given strongly-typed value and serialize using\n     * {@link #attribute(String, String, String)}.\n     */\n    @NonNull\n    XmlSerializer attributeFloat(@Nullable String namespace, @NonNull String name,\n                                 float value) throws IOException;\n\n    /**\n     * Encode the given strongly-typed value and serialize using\n     * {@link #attribute(String, String, String)}.\n     */\n    @NonNull\n    XmlSerializer attributeDouble(@Nullable String namespace, @NonNull String name,\n                                  double value) throws IOException;\n\n    /**\n     * Encode the given strongly-typed value and serialize using\n     * {@link #attribute(String, String, String)}.\n     */\n    @NonNull\n    XmlSerializer attributeBoolean(@Nullable String namespace, @NonNull String name,\n                                   boolean value) throws IOException;\n}"
  },
  {
    "path": "libcore/compat/src/main/java/io/github/muntashirakon/compat/xml/Xml.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage io.github.muntashirakon.compat.xml;\n\nimport android.os.Build;\nimport android.system.ErrnoException;\nimport android.system.Os;\n\nimport androidx.annotation.NonNull;\n\nimport org.xmlpull.v1.XmlPullParser;\nimport org.xmlpull.v1.XmlPullParserException;\nimport org.xmlpull.v1.XmlSerializer;\n\nimport java.io.BufferedInputStream;\nimport java.io.FileInputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.nio.ByteBuffer;\nimport java.nio.charset.StandardCharsets;\nimport java.util.Arrays;\nimport java.util.Objects;\n\npublic class Xml {\n    /**\n     * Feature flag: when set, {@link #resolveSerializer(OutputStream)} will\n     * emit binary XML by default.\n     */\n    public static final boolean ENABLE_BINARY_DEFAULT;\n\n    static {\n        boolean useAbx;\n        try {\n            useAbx = (boolean) Objects.requireNonNull(Class.forName(\"android.os.SystemProperties\")\n                    .getDeclaredMethod(\"getBoolean\", String.class, boolean.class)\n                    .invoke(null, \"persist.sys.binary_xml\", Build.VERSION.SDK_INT >= Build.VERSION_CODES.S));\n        } catch (Exception ignore) {\n            useAbx = Build.VERSION.SDK_INT >= Build.VERSION_CODES.S;\n        }\n        ENABLE_BINARY_DEFAULT = useAbx;\n    }\n\n    public static boolean isBinaryXml(@NonNull InputStream in) throws IOException {\n        final byte[] magic = new byte[4];\n        if (in instanceof FileInputStream) {\n            try {\n                Os.pread(((FileInputStream) in).getFD(), magic, 0, magic.length, 0);\n            } catch (ErrnoException e) {\n                throw new IOException(e.getMessage(), e);\n            }\n        } else {\n            if (!in.markSupported()) {\n                in = new BufferedInputStream(in);\n            }\n            in.mark(8);\n            in.read(magic);\n            in.reset();\n        }\n        return Arrays.equals(magic, BinaryXmlSerializer.PROTOCOL_MAGIC_VERSION_0);\n    }\n\n    public static boolean isBinaryXml(@NonNull ByteBuffer buffer) {\n        final byte[] magic = new byte[4];\n        buffer.mark();\n        buffer.get(magic);\n        buffer.reset();\n        return Arrays.equals(magic, BinaryXmlSerializer.PROTOCOL_MAGIC_VERSION_0);\n    }\n\n    /**\n     * Creates a new {@link TypedXmlPullParser} which is optimized for use\n     * inside the system, typically by supporting only a basic set of features.\n     * <p>\n     * In particular, the returned parser does not support namespaces, prefixes,\n     * properties, or options.\n     */\n    public static @NonNull TypedXmlPullParser newFastPullParser() {\n        return XmlUtils.makeTyped(android.util.Xml.newPullParser());\n    }\n\n    /**\n     * Creates a new {@link XmlPullParser} that reads XML documents using a\n     * custom binary wire protocol which benchmarking has shown to be 8.5x\n     * faster than {@code Xml.newFastPullParser()} for a typical\n     * {@code packages.xml}.\n     */\n    public static @NonNull TypedXmlPullParser newBinaryPullParser() {\n        return new BinaryXmlPullParser();\n    }\n\n    /**\n     * Creates a new {@link XmlPullParser} which is optimized for use inside the\n     * system, typically by supporting only a basic set of features.\n     * <p>\n     * This returned instance may be configured to read using an efficient\n     * binary format instead of a human-readable text format, depending on\n     * device feature flags.\n     * <p>\n     * To ensure that both formats are detected and transparently handled\n     * correctly, you must shift to using both {@link #resolveSerializer} and\n     * {@code #resolvePullParser}.\n     */\n    public static @NonNull TypedXmlPullParser resolvePullParser(@NonNull InputStream in) throws IOException {\n        if (!in.markSupported()) {\n            in = new BufferedInputStream(in);\n        }\n        final TypedXmlPullParser xml;\n        if (isBinaryXml(in)) {\n            xml = newBinaryPullParser();\n        } else {\n            xml = newFastPullParser();\n        }\n        try {\n            xml.setInput(in, StandardCharsets.UTF_8.name());\n        } catch (XmlPullParserException e) {\n            throw new IOException(e);\n        }\n        return xml;\n    }\n\n    /**\n     * Creates a new {@link XmlSerializer} which is optimized for use inside the\n     * system, typically by supporting only a basic set of features.\n     * <p>\n     * In particular, the returned parser does not support namespaces, prefixes,\n     * properties, or options.\n     */\n    @SuppressWarnings(\"AndroidFrameworkEfficientXml\")\n    public static @NonNull TypedXmlSerializer newFastSerializer() {\n        return XmlUtils.makeTyped(new FastXmlSerializer());\n    }\n\n    /**\n     * Creates a new {@link XmlSerializer} that writes XML documents using a\n     * custom binary wire protocol which benchmarking has shown to be 4.4x\n     * faster and use 2.8x less disk space than {@code Xml.newFastSerializer()}\n     * for a typical {@code packages.xml}.\n     */\n    public static @NonNull TypedXmlSerializer newBinarySerializer() {\n        return new BinaryXmlSerializer();\n    }\n\n    /**\n     * Creates a new {@link XmlSerializer} which is optimized for use inside the\n     * system, typically by supporting only a basic set of features.\n     * <p>\n     * This returned instance may be configured to write using an efficient\n     * binary format instead of a human-readable text format, depending on\n     * device feature flags.\n     * <p>\n     * To ensure that both formats are detected and transparently handled\n     * correctly, you must shift to using both {@code #resolveSerializer} and\n     * {@link #resolvePullParser}.\n     */\n    public static @NonNull TypedXmlSerializer resolveSerializer(@NonNull OutputStream out)\n            throws IOException {\n        final TypedXmlSerializer xml;\n        if (ENABLE_BINARY_DEFAULT) {\n            xml = newBinarySerializer();\n        } else {\n            xml = newFastSerializer();\n        }\n        xml.setOutput(out, StandardCharsets.UTF_8.name());\n        return xml;\n    }\n}\n"
  },
  {
    "path": "libcore/compat/src/main/java/io/github/muntashirakon/compat/xml/XmlPullParserWrapper.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage io.github.muntashirakon.compat.xml;\n\nimport androidx.annotation.NonNull;\n\nimport org.xmlpull.v1.XmlPullParser;\nimport org.xmlpull.v1.XmlPullParserException;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.Reader;\nimport java.util.Objects;\n\n/**\n * Wrapper which delegates all calls through to the given {@link XmlPullParser}.\n */\npublic class XmlPullParserWrapper implements XmlPullParser {\n    private final XmlPullParser mWrapped;\n\n    public XmlPullParserWrapper(@NonNull XmlPullParser wrapped) {\n        mWrapped = Objects.requireNonNull(wrapped);\n    }\n\n    public void setFeature(String name, boolean state) throws XmlPullParserException {\n        mWrapped.setFeature(name, state);\n    }\n\n    public boolean getFeature(String name) {\n        return mWrapped.getFeature(name);\n    }\n\n    public void setProperty(String name, Object value) throws XmlPullParserException {\n        mWrapped.setProperty(name, value);\n    }\n\n    public Object getProperty(String name) {\n        return mWrapped.getProperty(name);\n    }\n\n    public void setInput(Reader in) throws XmlPullParserException {\n        mWrapped.setInput(in);\n    }\n\n    public void setInput(InputStream inputStream, String inputEncoding)\n            throws XmlPullParserException {\n        mWrapped.setInput(inputStream, inputEncoding);\n    }\n\n    public String getInputEncoding() {\n        return mWrapped.getInputEncoding();\n    }\n\n    public void defineEntityReplacementText(String entityName, String replacementText)\n            throws XmlPullParserException {\n        mWrapped.defineEntityReplacementText(entityName, replacementText);\n    }\n\n    public int getNamespaceCount(int depth) throws XmlPullParserException {\n        return mWrapped.getNamespaceCount(depth);\n    }\n\n    public String getNamespacePrefix(int pos) throws XmlPullParserException {\n        return mWrapped.getNamespacePrefix(pos);\n    }\n\n    public String getNamespaceUri(int pos) throws XmlPullParserException {\n        return mWrapped.getNamespaceUri(pos);\n    }\n\n    public String getNamespace(String prefix) {\n        return mWrapped.getNamespace(prefix);\n    }\n\n    public int getDepth() {\n        return mWrapped.getDepth();\n    }\n\n    public String getPositionDescription() {\n        return mWrapped.getPositionDescription();\n    }\n\n    public int getLineNumber() {\n        return mWrapped.getLineNumber();\n    }\n\n    public int getColumnNumber() {\n        return mWrapped.getColumnNumber();\n    }\n\n    public boolean isWhitespace() throws XmlPullParserException {\n        return mWrapped.isWhitespace();\n    }\n\n    public String getText() {\n        return mWrapped.getText();\n    }\n\n    public char[] getTextCharacters(int[] holderForStartAndLength) {\n        return mWrapped.getTextCharacters(holderForStartAndLength);\n    }\n\n    public String getNamespace() {\n        return mWrapped.getNamespace();\n    }\n\n    public String getName() {\n        return mWrapped.getName();\n    }\n\n    public String getPrefix() {\n        return mWrapped.getPrefix();\n    }\n\n    public boolean isEmptyElementTag() throws XmlPullParserException {\n        return mWrapped.isEmptyElementTag();\n    }\n\n    public int getAttributeCount() {\n        return mWrapped.getAttributeCount();\n    }\n\n    public String getAttributeNamespace(int index) {\n        return mWrapped.getAttributeNamespace(index);\n    }\n\n    public String getAttributeName(int index) {\n        return mWrapped.getAttributeName(index);\n    }\n\n    public String getAttributePrefix(int index) {\n        return mWrapped.getAttributePrefix(index);\n    }\n\n    public String getAttributeType(int index) {\n        return mWrapped.getAttributeType(index);\n    }\n\n    public boolean isAttributeDefault(int index) {\n        return mWrapped.isAttributeDefault(index);\n    }\n\n    public String getAttributeValue(int index) {\n        return mWrapped.getAttributeValue(index);\n    }\n\n    public String getAttributeValue(String namespace, String name) {\n        return mWrapped.getAttributeValue(namespace, name);\n    }\n\n    public int getEventType() throws XmlPullParserException {\n        return mWrapped.getEventType();\n    }\n\n    public int next() throws XmlPullParserException, IOException {\n        return mWrapped.next();\n    }\n\n    public int nextToken() throws XmlPullParserException, IOException {\n        return mWrapped.nextToken();\n    }\n\n    public void require(int type, String namespace, String name)\n            throws XmlPullParserException, IOException {\n        mWrapped.require(type, namespace, name);\n    }\n\n    public String nextText() throws XmlPullParserException, IOException {\n        return mWrapped.nextText();\n    }\n\n    public int nextTag() throws XmlPullParserException, IOException {\n        return mWrapped.nextTag();\n    }\n}"
  },
  {
    "path": "libcore/compat/src/main/java/io/github/muntashirakon/compat/xml/XmlSerializerWrapper.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage io.github.muntashirakon.compat.xml;\n\nimport androidx.annotation.NonNull;\n\nimport org.xmlpull.v1.XmlSerializer;\n\nimport java.io.IOException;\nimport java.io.OutputStream;\nimport java.io.Writer;\nimport java.util.Objects;\n\n/**\n * Wrapper which delegates all calls through to the given {@link XmlSerializer}.\n */\npublic class XmlSerializerWrapper implements XmlSerializer {\n    private final XmlSerializer mWrapped;\n\n    public XmlSerializerWrapper(@NonNull XmlSerializer wrapped) {\n        mWrapped = Objects.requireNonNull(wrapped);\n    }\n\n    public void setFeature(String name, boolean state) {\n        mWrapped.setFeature(name, state);\n    }\n\n    public boolean getFeature(String name) {\n        return mWrapped.getFeature(name);\n    }\n\n    public void setProperty(String name, Object value) {\n        mWrapped.setProperty(name, value);\n    }\n\n    public Object getProperty(String name) {\n        return mWrapped.getProperty(name);\n    }\n\n    public void setOutput(OutputStream os, String encoding) throws IOException {\n        mWrapped.setOutput(os, encoding);\n    }\n\n    public void setOutput(Writer writer)\n            throws IOException, IllegalArgumentException, IllegalStateException {\n        mWrapped.setOutput(writer);\n    }\n\n    public void startDocument(String encoding, Boolean standalone) throws IOException {\n        mWrapped.startDocument(encoding, standalone);\n    }\n\n    public void endDocument() throws IOException {\n        mWrapped.endDocument();\n    }\n\n    public void setPrefix(String prefix, String namespace) throws IOException {\n        mWrapped.setPrefix(prefix, namespace);\n    }\n\n    public String getPrefix(String namespace, boolean generatePrefix) {\n        return mWrapped.getPrefix(namespace, generatePrefix);\n    }\n\n    public int getDepth() {\n        return mWrapped.getDepth();\n    }\n\n    public String getNamespace() {\n        return mWrapped.getNamespace();\n    }\n\n    public String getName() {\n        return mWrapped.getName();\n    }\n\n    public XmlSerializer startTag(String namespace, String name) throws IOException {\n        return mWrapped.startTag(namespace, name);\n    }\n\n    public XmlSerializer attribute(String namespace, String name, String value)\n            throws IOException {\n        return mWrapped.attribute(namespace, name, value);\n    }\n\n    public XmlSerializer endTag(String namespace, String name) throws IOException {\n        return mWrapped.endTag(namespace, name);\n    }\n\n    public XmlSerializer text(String text) throws IOException{\n        return mWrapped.text(text);\n    }\n\n    public XmlSerializer text(char[] buf, int start, int len) throws IOException {\n        return mWrapped.text(buf, start, len);\n    }\n\n    public void cdsect(String text)\n            throws IOException, IllegalArgumentException, IllegalStateException {\n        mWrapped.cdsect(text);\n    }\n\n    public void entityRef(String text) throws IOException {\n        mWrapped.entityRef(text);\n    }\n\n    public void processingInstruction(String text) throws IOException {\n        mWrapped.processingInstruction(text);\n    }\n\n    public void comment(String text) throws IOException {\n        mWrapped.comment(text);\n    }\n\n    public void docdecl(String text) throws IOException {\n        mWrapped.docdecl(text);\n    }\n\n    public void ignorableWhitespace(String text) throws IOException {\n        mWrapped.ignorableWhitespace(text);\n    }\n\n    public void flush() throws IOException {\n        mWrapped.flush();\n    }\n}"
  },
  {
    "path": "libcore/compat/src/main/java/io/github/muntashirakon/compat/xml/XmlUtils.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage io.github.muntashirakon.compat.xml;\n\nimport android.text.TextUtils;\nimport android.util.Base64;\n\nimport androidx.annotation.NonNull;\n\nimport org.xmlpull.v1.XmlPullParser;\nimport org.xmlpull.v1.XmlPullParserException;\nimport org.xmlpull.v1.XmlSerializer;\n\nimport java.io.IOException;\n\nimport io.github.muntashirakon.compat.HexDump;\n\npublic class XmlUtils {\n    private static class ForcedTypedXmlSerializer extends XmlSerializerWrapper\n            implements TypedXmlSerializer {\n        public ForcedTypedXmlSerializer(XmlSerializer wrapped) {\n            super(wrapped);\n        }\n\n        @Override\n        public XmlSerializer attributeInterned(String namespace, String name, String value)\n                throws IOException {\n            return attribute(namespace, name, value);\n        }\n\n        @Override\n        public XmlSerializer attributeBytesHex(String namespace, String name, byte[] value)\n                throws IOException {\n            return attribute(namespace, name, HexDump.toHexString(value));\n        }\n\n        @Override\n        public XmlSerializer attributeBytesBase64(String namespace, String name, byte[] value)\n                throws IOException {\n            return attribute(namespace, name, Base64.encodeToString(value, Base64.NO_WRAP));\n        }\n\n        @Override\n        public XmlSerializer attributeInt(String namespace, String name, int value)\n                throws IOException {\n            return attribute(namespace, name, Integer.toString(value));\n        }\n\n        @Override\n        public XmlSerializer attributeIntHex(String namespace, String name, int value)\n                throws IOException {\n            return attribute(namespace, name, Integer.toString(value, 16));\n        }\n\n        @Override\n        public XmlSerializer attributeLong(String namespace, String name, long value)\n                throws IOException {\n            return attribute(namespace, name, Long.toString(value));\n        }\n\n        @Override\n        public XmlSerializer attributeLongHex(String namespace, String name, long value)\n                throws IOException {\n            return attribute(namespace, name, Long.toString(value, 16));\n        }\n\n        @Override\n        public XmlSerializer attributeFloat(String namespace, String name, float value)\n                throws IOException {\n            return attribute(namespace, name, Float.toString(value));\n        }\n\n        @Override\n        public XmlSerializer attributeDouble(String namespace, String name, double value)\n                throws IOException {\n            return attribute(namespace, name, Double.toString(value));\n        }\n\n        @Override\n        public XmlSerializer attributeBoolean(String namespace, String name, boolean value)\n                throws IOException {\n            return attribute(namespace, name, Boolean.toString(value));\n        }\n    }\n\n    /**\n     * Return a specialization of the given {@link XmlSerializer} which has\n     * explicit methods to support consistent and efficient conversion of\n     * primitive data types.\n     */\n    public static @NonNull TypedXmlSerializer makeTyped(@NonNull XmlSerializer xml) {\n        if (xml instanceof TypedXmlSerializer) {\n            return (TypedXmlSerializer) xml;\n        } else {\n            return new ForcedTypedXmlSerializer(xml);\n        }\n    }\n\n    private static class ForcedTypedXmlPullParser extends XmlPullParserWrapper\n            implements TypedXmlPullParser {\n        public ForcedTypedXmlPullParser(XmlPullParser wrapped) {\n            super(wrapped);\n        }\n\n        @Override\n        public byte[] getAttributeBytesHex(int index)\n                throws XmlPullParserException {\n            try {\n                return HexDump.hexStringToByteArray(getAttributeValue(index));\n            } catch (Exception e) {\n                throw new XmlPullParserException(\n                        \"Invalid attribute \" + getAttributeName(index) + \": \" + e);\n            }\n        }\n\n        @Override\n        public byte[] getAttributeBytesBase64(int index)\n                throws XmlPullParserException {\n            try {\n                return Base64.decode(getAttributeValue(index), Base64.NO_WRAP);\n            } catch (Exception e) {\n                throw new XmlPullParserException(\n                        \"Invalid attribute \" + getAttributeName(index) + \": \" + e);\n            }\n        }\n\n        @Override\n        public int getAttributeInt(int index)\n                throws XmlPullParserException {\n            try {\n                return Integer.parseInt(getAttributeValue(index));\n            } catch (Exception e) {\n                throw new XmlPullParserException(\n                        \"Invalid attribute \" + getAttributeName(index) + \": \" + e);\n            }\n        }\n\n        @Override\n        public int getAttributeIntHex(int index)\n                throws XmlPullParserException {\n            try {\n                return Integer.parseInt(getAttributeValue(index), 16);\n            } catch (Exception e) {\n                throw new XmlPullParserException(\n                        \"Invalid attribute \" + getAttributeName(index) + \": \" + e);\n            }\n        }\n\n        @Override\n        public long getAttributeLong(int index)\n                throws XmlPullParserException {\n            try {\n                return Long.parseLong(getAttributeValue(index));\n            } catch (Exception e) {\n                throw new XmlPullParserException(\n                        \"Invalid attribute \" + getAttributeName(index) + \": \" + e);\n            }\n        }\n\n        @Override\n        public long getAttributeLongHex(int index)\n                throws XmlPullParserException {\n            try {\n                return Long.parseLong(getAttributeValue(index), 16);\n            } catch (Exception e) {\n                throw new XmlPullParserException(\n                        \"Invalid attribute \" + getAttributeName(index) + \": \" + e);\n            }\n        }\n\n        @Override\n        public float getAttributeFloat(int index)\n                throws XmlPullParserException {\n            try {\n                return Float.parseFloat(getAttributeValue(index));\n            } catch (Exception e) {\n                throw new XmlPullParserException(\n                        \"Invalid attribute \" + getAttributeName(index) + \": \" + e);\n            }\n        }\n\n        @Override\n        public double getAttributeDouble(int index)\n                throws XmlPullParserException {\n            try {\n                return Double.parseDouble(getAttributeValue(index));\n            } catch (Exception e) {\n                throw new XmlPullParserException(\n                        \"Invalid attribute \" + getAttributeName(index) + \": \" + e);\n            }\n        }\n\n        @Override\n        public boolean getAttributeBoolean(int index)\n                throws XmlPullParserException {\n            final String value = getAttributeValue(index);\n            if (\"true\".equalsIgnoreCase(value)) {\n                return true;\n            } else if (\"false\".equalsIgnoreCase(value)) {\n                return false;\n            } else {\n                throw new XmlPullParserException(\n                        \"Invalid attribute \" + getAttributeName(index) + \": \" + value);\n            }\n        }\n    }\n\n    /**\n     * Return a specialization of the given {@link XmlPullParser} which has\n     * explicit methods to support consistent and efficient conversion of\n     * primitive data types.\n     */\n    public static @NonNull TypedXmlPullParser makeTyped(@NonNull XmlPullParser xml) {\n        if (xml instanceof TypedXmlPullParser) {\n            return (TypedXmlPullParser) xml;\n        } else {\n            return new ForcedTypedXmlPullParser(xml);\n        }\n    }\n\n    public static void skipCurrentTag(XmlPullParser parser)\n            throws XmlPullParserException, IOException {\n        int outerDepth = parser.getDepth();\n        int type;\n        while ((type = parser.next()) != XmlPullParser.END_DOCUMENT\n                && (type != XmlPullParser.END_TAG\n                || parser.getDepth() > outerDepth)) {\n        }\n    }\n\n    public static final void nextElement(XmlPullParser parser) throws XmlPullParserException, IOException {\n        int type;\n        while ((type = parser.next()) != parser.START_TAG\n                && type != parser.END_DOCUMENT) {\n        }\n    }\n\n    public static boolean nextElementWithin(XmlPullParser parser, int outerDepth)\n            throws IOException, XmlPullParserException {\n        for (;;) {\n            int type = parser.next();\n            if (type == XmlPullParser.END_DOCUMENT\n                    || (type == XmlPullParser.END_TAG && parser.getDepth() == outerDepth)) {\n                return false;\n            }\n            if (type == XmlPullParser.START_TAG\n                    && parser.getDepth() == outerDepth + 1) {\n                return true;\n            }\n        }\n    }\n\n    public static int readIntAttribute(XmlPullParser in, String name, int defaultValue) {\n        final String value = in.getAttributeValue(null, name);\n        if (TextUtils.isEmpty(value)) {\n            return defaultValue;\n        }\n        try {\n            return Integer.parseInt(value);\n        } catch (NumberFormatException e) {\n            return defaultValue;\n        }\n    }\n\n    public static boolean readBooleanAttribute(XmlPullParser in, String name,\n                                               boolean defaultValue) {\n        final String value = in.getAttributeValue(null, name);\n        if (TextUtils.isEmpty(value)) {\n            return defaultValue;\n        } else {\n            return Boolean.parseBoolean(value);\n        }\n    }\n}\n"
  },
  {
    "path": "libcore/compat/src/main/java/org/slf4j/Logger.java",
    "content": "// SPDX-License-Identifier: MIT\n\npackage org.slf4j;\n\npublic interface Logger {\n    public String getName();\n\n    public boolean isTraceEnabled();\n\n    public void trace(String msg);\n\n    public void trace(String format, Object arg);\n\n    public void trace(String format, Object arg1, Object arg2);\n\n    public void trace(String format, Object... arguments);\n\n    public void trace(String msg, Throwable t);\n\n    public boolean isDebugEnabled();\n\n    public void debug(String msg);\n\n    public void debug(String format, Object arg);\n\n    public void debug(String format, Object arg1, Object arg2);\n\n    public void debug(String format, Object... arguments);\n\n    public void debug(String msg, Throwable t);\n\n    public boolean isInfoEnabled();\n\n    public void info(String msg);\n\n    public void info(String format, Object arg);\n\n    public void info(String format, Object arg1, Object arg2);\n\n    public void info(String format, Object... arguments);\n\n    public void info(String msg, Throwable t);\n\n    public boolean isWarnEnabled();\n\n    public void warn(String msg);\n\n    public void warn(String format, Object arg);\n\n    public void warn(String format, Object... arguments);\n\n    public void warn(String format, Object arg1, Object arg2);\n\n    public void warn(String msg, Throwable t);\n\n    public boolean isErrorEnabled();\n\n    public void error(String msg);\n\n    public void error(String format, Object arg);\n\n    public void error(String format, Object arg1, Object arg2);\n\n    public void error(String format, Object... arguments);\n\n    public void error(String msg, Throwable t);\n}"
  },
  {
    "path": "libcore/compat/src/main/java/org/slf4j/LoggerFactory.java",
    "content": "// SPDX-License-Identifier: MIT\n\npackage org.slf4j;\n\npublic final class LoggerFactory {\n    public static Logger getLogger(String name) {\n        return new LoggerImpl(name);\n    }\n\n    public static Logger getLogger(Class<?> clazz) {\n        return getLogger(clazz.getName());\n    }\n}\n"
  },
  {
    "path": "libcore/compat/src/main/java/org/slf4j/LoggerImpl.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage org.slf4j;\n\nimport android.util.Log;\n\nimport java.util.Locale;\n\nimport io.github.muntashirakon.AppManager.compat.BuildConfig;\n\nclass LoggerImpl implements Logger {\n    private final String mTag;\n\n    protected LoggerImpl(String tag) {\n        mTag = tag;\n    }\n\n    public String getName() {\n        return mTag;\n    }\n\n    public boolean isTraceEnabled() {\n        return false;\n    }\n\n    public void trace(String msg) {\n    }\n\n    public void trace(String format, Object arg) {\n    }\n\n    public void trace(String format, Object arg1, Object arg2) {\n    }\n\n    public void trace(String format, Object... arguments) {\n    }\n\n    public void trace(String msg, Throwable t) {\n    }\n\n    public boolean isDebugEnabled() {\n        return BuildConfig.DEBUG;\n    }\n\n    public void debug(String msg) {\n        Log.d(mTag, msg);\n    }\n\n    public void debug(String format, Object arg) {\n        Log.d(mTag, String.format(format, arg));\n    }\n\n    public void debug(String format, Object arg1, Object arg2) {\n        Log.d(mTag, String.format(format, arg1, arg2));\n    }\n\n    public void debug(String format, Object... arguments) {\n        Log.d(mTag, String.format(format, arguments));\n    }\n\n    public void debug(String msg, Throwable t) {\n        Log.d(mTag, msg, t);\n    }\n\n    public boolean isInfoEnabled() {\n        return true;\n    }\n\n    public void info(String msg) {\n        Log.i(mTag, msg);\n    }\n\n    public void info(String format, Object arg) {\n        Log.i(mTag, String.format(format, arg));\n    }\n\n    public void info(String format, Object arg1, Object arg2) {\n        Log.i(mTag, String.format(format, arg1, arg2));\n    }\n\n    public void info(String format, Object... arguments) {\n        Log.i(mTag, String.format(format, arguments));\n    }\n\n    public void info(String msg, Throwable t) {\n        Log.i(mTag, msg, t);\n    }\n\n    public boolean isWarnEnabled() {\n        return true;\n    }\n\n    public void warn(String msg) {\n        Log.w(mTag, msg);\n    }\n\n    public void warn(String format, Object arg) {\n        Log.w(mTag, String.format(Locale.ROOT, format, arg));\n    }\n\n    public void warn(String format, Object... arguments) {\n        Log.w(mTag, String.format(Locale.ROOT, format, arguments));\n    }\n\n    public void warn(String format, Object arg1, Object arg2) {\n        Log.w(mTag, String.format(Locale.ROOT, format, arg1, arg2));\n    }\n\n    public void warn(String msg, Throwable t) {\n        Log.w(mTag, msg, t);\n    }\n\n    public boolean isErrorEnabled() {\n        return true;\n    }\n\n    public void error(String msg) {\n        Log.e(mTag, msg);\n    }\n\n    public void error(String format, Object arg) {\n        Log.e(mTag, String.format(Locale.ROOT, format, arg));\n    }\n\n    public void error(String format, Object arg1, Object arg2) {\n        Log.e(mTag, String.format(Locale.ROOT, format, arg1, arg2));\n    }\n\n    public void error(String format, Object... arguments) {\n        Log.e(mTag, String.format(Locale.ROOT, format, arguments));\n    }\n\n    public void error(String msg, Throwable t) {\n        Log.e(mTag, msg, t);\n    }\n}"
  },
  {
    "path": "libcore/compat/src/test/java/io/github/muntashirakon/compat/xml/XmlTest.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.compat.xml;\n\nimport static org.junit.Assert.assertEquals;\nimport static org.junit.Assert.assertTrue;\nimport static org.xmlpull.v1.XmlPullParser.CDSECT;\nimport static org.xmlpull.v1.XmlPullParser.COMMENT;\nimport static org.xmlpull.v1.XmlPullParser.DOCDECL;\nimport static org.xmlpull.v1.XmlPullParser.END_DOCUMENT;\nimport static org.xmlpull.v1.XmlPullParser.END_TAG;\nimport static org.xmlpull.v1.XmlPullParser.ENTITY_REF;\nimport static org.xmlpull.v1.XmlPullParser.IGNORABLE_WHITESPACE;\nimport static org.xmlpull.v1.XmlPullParser.PROCESSING_INSTRUCTION;\nimport static org.xmlpull.v1.XmlPullParser.START_TAG;\nimport static org.xmlpull.v1.XmlPullParser.TEXT;\n\nimport androidx.annotation.NonNull;\n\nimport org.junit.Test;\nimport org.junit.runner.RunWith;\nimport org.robolectric.RobolectricTestRunner;\nimport org.xmlpull.v1.XmlPullParser;\nimport org.xmlpull.v1.XmlPullParserException;\n\nimport java.io.BufferedInputStream;\nimport java.io.ByteArrayOutputStream;\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.nio.charset.StandardCharsets;\nimport java.util.Objects;\n\nimport io.github.muntashirakon.compat.HexDump;\n\n@RunWith(RobolectricTestRunner.class)\npublic class XmlTest {\n    private final ClassLoader classLoader = Objects.requireNonNull(getClass().getClassLoader());\n    private final File ssaidAbxFile = new File(classLoader.getResource(\"settings_ssaid.abx.xml\").getFile());\n    private final File ssaidXmlFile = new File(classLoader.getResource(\"settings_ssaid.plain.xml\").getFile());\n    private final File uriGrantsAbxFile = new File(classLoader.getResource(\"urigrants.abx.xml\").getFile());\n    private final File uriGrantsXmlFile = new File(classLoader.getResource(\"urigrants.plain.xml\").getFile());\n\n    @Test\n    public void isBinaryXml() throws IOException {\n        try (InputStream is = new BufferedInputStream(new FileInputStream(ssaidAbxFile))) {\n            assertTrue(Xml.isBinaryXml(is));\n        }\n        try (InputStream is = new BufferedInputStream(new FileInputStream(uriGrantsAbxFile))) {\n            assertTrue(Xml.isBinaryXml(is));\n        }\n    }\n\n    @Test\n    public void newBinaryPullParserReadSsaid() throws IOException, XmlPullParserException {\n        byte[] xmlActualBytes;\n        try (InputStream is = new BufferedInputStream(new FileInputStream(ssaidAbxFile));\n             ByteArrayOutputStream os = new ByteArrayOutputStream()) {\n            TypedXmlPullParser parser = Xml.newBinaryPullParser();\n            parser.setInput(is, StandardCharsets.UTF_8.name());\n            TypedXmlSerializer serializer = Xml.newFastSerializer();\n            serializer.setOutput(os, StandardCharsets.UTF_8.name());\n            copyXml(parser, serializer);\n            xmlActualBytes = os.toByteArray();\n        }\n\n        byte[] xmlExpectedBytes = new byte[(int) ssaidXmlFile.length()];\n        try (InputStream is = new BufferedInputStream(new FileInputStream(ssaidXmlFile))) {\n            is.read(xmlExpectedBytes);\n        }\n        assertEquals(new String(xmlExpectedBytes), new String(xmlActualBytes));\n    }\n\n    @Test\n    public void newBinaryPullParserReadUriGrants() throws IOException, XmlPullParserException {\n        byte[] xmlActualBytes;\n        try (InputStream is = new BufferedInputStream(new FileInputStream(uriGrantsAbxFile));\n             ByteArrayOutputStream os = new ByteArrayOutputStream()) {\n            TypedXmlPullParser parser = Xml.newBinaryPullParser();\n            parser.setInput(is, StandardCharsets.UTF_8.name());\n            TypedXmlSerializer serializer = Xml.newFastSerializer();\n            serializer.setOutput(os, StandardCharsets.UTF_8.name());\n            copyXml(parser, serializer);\n            xmlActualBytes = os.toByteArray();\n        }\n\n        byte[] xmlExpectedBytes = new byte[(int) uriGrantsXmlFile.length()];\n        try (InputStream is = new BufferedInputStream(new FileInputStream(uriGrantsXmlFile))) {\n            is.read(xmlExpectedBytes);\n        }\n        assertEquals(new String(xmlExpectedBytes), new String(xmlActualBytes));\n    }\n\n//    @Test\n//    public void newBinarySerializerWriteSsaid() throws IOException, XmlPullParserException {\n//        byte[] xmlActualBytes;\n//        try (InputStream is = new BufferedInputStream(new FileInputStream(ssaidXmlFile));\n//             ByteArrayOutputStream os = new ByteArrayOutputStream()) {\n//            TypedXmlPullParser parser = Xml.newFastPullParser();\n//            parser.setInput(is, StandardCharsets.UTF_8.name());\n//            TypedXmlSerializer serializer = Xml.newBinarySerializer();\n//            serializer.setOutput(os, StandardCharsets.UTF_8.name());\n//            copyXml(parser, serializer);\n//            xmlActualBytes = os.toByteArray();\n//        }\n//\n//        byte[] xmlExpectedBytes = new byte[(int) ssaidAbxFile.length()];\n//        try (InputStream is = new BufferedInputStream(new FileInputStream(ssaidAbxFile))) {\n//            is.read(xmlExpectedBytes);\n//        }\n//        assertEquals(new String(xmlExpectedBytes), new String(xmlActualBytes));\n//    }\n//\n//    @Test\n//    public void newBinarySerializerWriteUriGrants() throws IOException, XmlPullParserException {\n//        byte[] xmlActualBytes;\n//        try (InputStream is = new BufferedInputStream(new FileInputStream(uriGrantsXmlFile));\n//             ByteArrayOutputStream os = new ByteArrayOutputStream()) {\n//            TypedXmlPullParser parser = Xml.newFastPullParser();\n//            parser.setInput(is, StandardCharsets.UTF_8.name());\n//            TypedXmlSerializer serializer = Xml.newBinarySerializer();\n//            serializer.setOutput(os, StandardCharsets.UTF_8.name());\n//            copyXml(parser, serializer);\n//            xmlActualBytes = os.toByteArray();\n//        }\n//\n//        byte[] xmlExpectedBytes = new byte[(int) uriGrantsAbxFile.length()];\n//        try (InputStream is = new BufferedInputStream(new FileInputStream(uriGrantsAbxFile))) {\n//            is.read(xmlExpectedBytes);\n//        }\n//        assertEquals(HexDump.toHexString(xmlExpectedBytes), HexDump.toHexString(xmlActualBytes));\n//    }\n\n    public static void copyXml(@NonNull TypedXmlPullParser parser, @NonNull TypedXmlSerializer serializer)\n            throws IOException, XmlPullParserException {\n        serializer.startDocument(null, null);\n        int event;\n        do {\n            event = parser.nextToken();\n            switch (event) {\n                case START_TAG:\n                    serializer.startTag(null, parser.getName());\n                    for (int i = 0; i < parser.getAttributeCount(); i++) {\n                        String attributeName = parser.getAttributeName(i);\n                        serializer.attribute(null, attributeName, parser.getAttributeValue(i));\n                    }\n                    break;\n                case END_TAG:\n                    serializer.endTag(null, parser.getName());\n                    break;\n                case TEXT:\n                    serializer.text(parser.getText());\n                    break;\n                case IGNORABLE_WHITESPACE:\n                    try {\n                        serializer.ignorableWhitespace(parser.getText());\n                    } catch (UnsupportedOperationException ignore) {\n                    }\n                    break;\n                case CDSECT:\n                    serializer.cdsect(parser.getText());\n                    break;\n                case PROCESSING_INSTRUCTION:\n                    serializer.processingInstruction(parser.getText());\n                    break;\n                case COMMENT:\n                    serializer.comment(parser.getText());\n                    break;\n                case ENTITY_REF:\n                    String text = parser.getText();\n                    if (text != null) {\n                        serializer.text(text);\n                        break;\n                    }\n                    int[] holder = new int[2];\n                    char[] chars = parser.getTextCharacters(holder);\n                    text = new String(chars, holder[0], holder[1]);\n                    if (text.equals(\"#10\")) {\n                        text = \"\\n\";\n                    }\n                    serializer.entityRef(text);\n                    break;\n                case DOCDECL:\n                    serializer.docdecl(parser.getText());\n                case END_DOCUMENT:\n                    serializer.endDocument();\n                    break;\n                default:\n                    throw new UnsupportedOperationException();\n            }\n        } while (event != END_DOCUMENT);\n    }\n}"
  },
  {
    "path": "libcore/compat/src/test/resources/robolectric.properties",
    "content": "sdk=32"
  },
  {
    "path": "libcore/compat/src/test/resources/settings_ssaid.plain.xml",
    "content": "<?xml version='1.0' encoding='utf-8' ?>\n<settings version=\"-1\">\n<setting id=\"0\" name=\"userkey\" value=\"1CC7C1428FF5D1F88CF0FBD9C16ABDFF3ED518A4489B368E46C43B39E54BE647\" package=\"android\" defaultValue=\"1CC7C1428FF5D1F88CF0FBD9C16ABDFF3ED518A4489B368E46C43B39E54BE647\" defaultSysSet=\"true\" tag=\"null\" />\n<setting id=\"1\" name=\"10105\" value=\"55145d0ea8dfa144\" package=\"io.github.muntashirakon.AppManager.debug\" defaultValue=\"55145d0ea8dfa144\" defaultSysSet=\"false\" tag=\"null\" />\n</settings>\n<namespaceHashes />\n"
  },
  {
    "path": "libcore/compat/src/test/resources/urigrants.plain.xml",
    "content": "<?xml version='1.0' encoding='utf-8' ?>\n<uri-grants>\n<uri-grant sourceUserId=\"0\" targetUserId=\"0\" sourcePkg=\"com.android.externalstorage\" targetPkg=\"io.github.muntashirakon.AppManager.debug\" uri=\"content://com.android.externalstorage.documents/tree/primary%3AAppManager\" prefix=\"true\" modeFlags=\"3\" createdTime=\"1673724685372\" />\n</uri-grants>\n"
  },
  {
    "path": "libcore/io/.gitignore",
    "content": "/build"
  },
  {
    "path": "libcore/io/build.gradle",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\nplugins {\n    id('com.android.library')\n}\n\nandroid {\n    namespace 'io.github.muntashirakon.io'\n    compileSdk compile_sdk\n    buildToolsVersion = build_tools\n\n    defaultConfig {\n        minSdk min_sdk\n        targetSdk target_sdk\n    }\n\n    compileOptions {\n        encoding \"UTF-8\"\n        sourceCompatibility JavaVersion.VERSION_1_8\n        targetCompatibility JavaVersion.VERSION_1_8\n    }\n    buildFeatures {\n        aidl true\n        buildConfig true\n    }\n}\n\ndependencies {\n    compileOnly project(path: ':hiddenapi')\n\n    implementation project(path: ':libcore:compat')\n\n    api \"androidx.documentfile:documentfile:${documentfile_version}\"\n\n    implementation \"androidx.annotation:annotation:${annotation_version}\"\n}"
  },
  {
    "path": "libcore/io/src/main/AndroidManifest.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<manifest />"
  },
  {
    "path": "libcore/io/src/main/aidl/aosp/android/content/pm/ParceledListSlice.aidl",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage aosp.android.content.pm;\n\nparcelable ParceledListSlice;\n"
  },
  {
    "path": "libcore/io/src/main/aidl/aosp/android/content/pm/StringParceledListSlice.aidl",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage aosp.android.content.pm;\n\nparcelable StringParceledListSlice;"
  },
  {
    "path": "libcore/io/src/main/aidl/io/github/muntashirakon/io/IFileSystemService.aidl",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage io.github.muntashirakon.io;\n\nimport aosp.android.content.pm.StringParceledListSlice;\nimport io.github.muntashirakon.io.IOResult;\n\n// Copyright 2022 John \"topjohnwu\" Wu\n// Copyright 2022 Muntashir Al-Islam\ninterface IFileSystemService {\n    // File APIs\n    /* (err, String) */ IOResult getCanonicalPath(String path);\n    boolean isDirectory(String path);\n    boolean isFile(String path);\n    boolean isHidden(String path);\n    long lastModified(String path);\n    /* (err, long) */ IOResult lastAccess(String path);\n    /* (err, long) */ IOResult creationTime(String path);\n    long length(String path);\n    /* (err, bool) */ IOResult createNewFile(String path);\n    boolean delete(String path);\n    StringParceledListSlice list(String path);\n    boolean mkdir(String path);\n    boolean mkdirs(String path);\n    boolean renameTo(String path, String dest);\n    boolean setLastModified(String path, long time);\n    /* (err) */ IOResult setLastAccess(String path, long time);\n    boolean setReadOnly(String path);\n    boolean setWritable(String path, boolean writable, boolean ownerOnly);\n    boolean setReadable(String path, boolean readable, boolean ownerOnly);\n    boolean setExecutable(String path, boolean executable, boolean ownerOnly);\n    boolean checkAccess(String path, int access);\n    long getTotalSpace(String path);\n    long getFreeSpace(String path);\n    long getUsableSpace(String path);\n    /* (err, int) */ IOResult getMode(String path);\n    /* (err) */ IOResult setMode(String path, int mode);\n    /* (err, int, int) */ IOResult getUidGid(String path);\n    /* (err) */ IOResult setUidGid(String path, int uid, int gid);\n    String getSelinuxContext(String path);\n    boolean restoreSelinuxContext(String path);\n    boolean setSelinuxContext(String path, String context);\n    /* (err, bool) */ IOResult createLink(String link, String target, boolean soft);\n\n    // I/O APIs\n    oneway void register(IBinder client);\n    /* (err, int) */ IOResult openChannel(String path, int mode, String fifo);\n    /* (err) */ IOResult openReadStream(String path, in ParcelFileDescriptor fd);\n    /* (err) */ IOResult openWriteStream(String path, in ParcelFileDescriptor fd, boolean append);\n    oneway void close(int handle);\n    /* (err, int) */ IOResult pread(int handle, int len, long offset);\n    /* (err) */ IOResult pwrite(int handle, int len, long offset);\n    /* (err, long) */ IOResult lseek(int handle, long offset, int whence);\n    /* (err, long) */ IOResult size(int handle);\n    /* (err) */ IOResult ftruncate(int handle, long length);\n    /* (err) */ IOResult sync(int handle, boolean metadata);\n}\n"
  },
  {
    "path": "libcore/io/src/main/aidl/io/github/muntashirakon/io/IOResult.aidl",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage io.github.muntashirakon.io;\n\nparcelable IOResult;\n"
  },
  {
    "path": "libcore/io/src/main/aidl/io/github/muntashirakon/io/UidGidPair.aidl",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage io.github.muntashirakon.io;\n\nparcelable UidGidPair;\n"
  },
  {
    "path": "libcore/io/src/main/java/androidx/documentfile/provider/ExtendedRawDocumentFile.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage androidx.documentfile.provider;\n\nimport android.net.Uri;\nimport android.util.Log;\nimport android.webkit.MimeTypeMap;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.util.ArrayList;\nimport java.util.Locale;\n\nimport io.github.muntashirakon.io.ExtendedFile;\n\n/**\n * Same as {@link RawDocumentFile} with additional support for {@link ExtendedFile}.\n */\npublic class ExtendedRawDocumentFile extends DocumentFile {\n    public static final String TAG = \"DF\";\n\n    private ExtendedFile mFile;\n\n    public ExtendedRawDocumentFile(@NonNull ExtendedFile file) {\n        super(getParentDocumentFile(file));\n        mFile = file;\n    }\n\n    public ExtendedRawDocumentFile(@Nullable DocumentFile parent, @NonNull ExtendedFile file) {\n        super(parent);\n        mFile = file;\n    }\n\n    @Override\n    @Nullable\n    public DocumentFile createFile(@NonNull String mimeType, @NonNull String displayName) {\n        if (displayName.contains(File.separator)) {\n            // displayName cannot contain a separator\n            return null;\n        }\n        // Tack on extension when valid MIME type provided\n        String extension = MimeTypeMap.getSingleton().getExtensionFromMimeType(mimeType);\n        if (extension != null) {\n            displayName += \".\" + extension;\n        }\n        final ExtendedFile target = mFile.getChildFile(displayName);\n        try {\n            target.createNewFile();\n            return new ExtendedRawDocumentFile(this, target);\n        } catch (IOException e) {\n            Log.w(TAG, \"Failed to create \" + target, e);\n            return null;\n        }\n    }\n\n    @Override\n    @Nullable\n    public DocumentFile createDirectory(@NonNull String displayName) {\n        if (displayName.contains(File.separator)) {\n            // displayName cannot contain a separator\n            return null;\n        }\n        final ExtendedFile target = mFile.getChildFile(displayName);\n        if (target.isDirectory() || target.mkdir()) {\n            return new ExtendedRawDocumentFile(this, target);\n        } else {\n            return null;\n        }\n    }\n\n    @Override\n    @NonNull\n    public Uri getUri() {\n        return Uri.fromFile(mFile);\n    }\n\n    public ExtendedFile getFile() {\n        return mFile;\n    }\n\n    @Override\n    @NonNull\n    public String getName() {\n        return mFile.getName();\n    }\n\n    @Override\n    @Nullable\n    public String getType() {\n        if (mFile.isDirectory()) {\n            return \"resource/folder\";\n        } else if (mFile.isFile()) {\n            String name = mFile.getName();\n            final int lastDot = name.lastIndexOf('.');\n            if (lastDot >= 0) {\n                final String extension = name.substring(lastDot + 1).toLowerCase(Locale.ROOT);\n                return MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);\n            }\n        }\n        return null;\n    }\n\n    @Override\n    public boolean isDirectory() {\n        return mFile.isDirectory();\n    }\n\n    @Override\n    public boolean isFile() {\n        return mFile.isFile();\n    }\n\n    @Override\n    public boolean isVirtual() {\n        return false;\n    }\n\n    @Override\n    public long lastModified() {\n        return mFile.lastModified();\n    }\n\n    @Override\n    public long length() {\n        return mFile.length();\n    }\n\n    @Override\n    public boolean canRead() {\n        return mFile.canRead();\n    }\n\n    @Override\n    public boolean canWrite() {\n        return mFile.canWrite();\n    }\n\n    @Override\n    public boolean delete() {\n        deleteContents(mFile);\n        return mFile.delete();\n    }\n\n    @Override\n    public boolean exists() {\n        return mFile.exists();\n    }\n\n    @Nullable\n    @Override\n    public DocumentFile findFile(@NonNull String displayName) {\n        if (displayName.contains(File.separator)) {\n            // displayName cannot contain a separator\n            return null;\n        }\n        ExtendedFile file = mFile.getChildFile(displayName);\n        return file.exists() ? new ExtendedRawDocumentFile(this, file) : null;\n    }\n\n    @NonNull\n    @Override\n    public DocumentFile[] listFiles() {\n        final ArrayList<DocumentFile> results = new ArrayList<>();\n        final ExtendedFile[] files = mFile.listFiles();\n        if (files != null) {\n            for (ExtendedFile file : files) {\n                results.add(new ExtendedRawDocumentFile(this, file));\n            }\n        }\n        return results.toArray(new DocumentFile[0]);\n    }\n\n    @Override\n    public boolean renameTo(@NonNull String displayName) {\n        if (displayName.contains(File.separator)) {\n            // displayName cannot contain a separator\n            return false;\n        }\n        ExtendedFile parent = mFile.getParentFile();\n        if (parent == null) return false;\n        ExtendedFile target = mFile.getParentFile().getChildFile(displayName);\n        if (mFile.renameTo(target)) {\n            mFile = target;\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    public boolean renameTo(@NonNull ExtendedRawDocumentFile targetFile) {\n        if (mFile.renameTo(targetFile.mFile)) {\n            mFile = targetFile.mFile;\n            return true;\n        } else {\n            return false;\n        }\n    }\n\n    private static String getTypeForName(String name) {\n        final int lastDot = name.lastIndexOf('.');\n        if (lastDot >= 0) {\n            final String extension = name.substring(lastDot + 1).toLowerCase(Locale.ROOT);\n            final String mime = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);\n            if (mime != null) {\n                return mime;\n            }\n        }\n        return \"application/octet-stream\";\n    }\n\n    private static boolean deleteContents(ExtendedFile dir) {\n        if (dir.isSymlink()) {\n            // Do not follow symbolic links\n            return true;\n        }\n        ExtendedFile[] files = dir.listFiles();\n        boolean success = true;\n        if (files != null) {\n            for (ExtendedFile file : files) {\n                if (file.isDirectory()) {\n                    success &= deleteContents(file);\n                }\n                if (!file.delete()) {\n                    Log.w(TAG, \"Failed to delete \" + file);\n                    success = false;\n                }\n            }\n        }\n        return success;\n    }\n\n    @Nullable\n    private static DocumentFile getParentDocumentFile(@NonNull ExtendedFile file) {\n        ExtendedFile parent = file.getParentFile();\n        if (parent != null) {\n            return new ExtendedRawDocumentFile(parent);\n        }\n        return null;\n    }\n}\n"
  },
  {
    "path": "libcore/io/src/main/java/aosp/android/content/pm/BaseParceledListSlice.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage aosp.android.content.pm;\n\nimport android.os.Binder;\nimport android.os.Build;\nimport android.os.IBinder;\nimport android.os.Parcel;\nimport android.os.Parcelable;\nimport android.os.RemoteException;\nimport android.util.Log;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport io.github.muntashirakon.compat.os.ParcelCompat2;\nimport io.github.muntashirakon.io.IoUtils;\n\n/**\n * Transfer a large list of Parcelable objects across an IPC.  Splits into\n * multiple transactions if needed.\n * <p>\n * Caveat: for efficiency and security, all elements must be the same concrete type.\n * In order to avoid writing the class name of each object, we must ensure that\n * each object is the same type, or else unparceling then reparceling the data may yield\n * a different result if the class name encoded in the Parcelable is a Base type.\n * See b/17671747.\n */\n// Copyright 2011 The Android Open Source Project\nabstract class BaseParceledListSlice<T> implements Parcelable {\n    private static final String TAG = \"ParceledListSlice\";\n    private static final boolean DEBUG = false;\n\n    private static final int MAX_IPC_SIZE;\n\n    static {\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {\n            MAX_IPC_SIZE = IBinder.getSuggestedMaxIpcSizeBytes();\n        } else MAX_IPC_SIZE = IoUtils.DEFAULT_BUFFER_SIZE;\n    }\n\n    private final List<T> mList;\n\n    private int mInlineCountLimit = Integer.MAX_VALUE;\n\n    public BaseParceledListSlice(List<T> list) {\n        mList = list;\n    }\n\n    BaseParceledListSlice(@NonNull Parcel p) {\n        // Unlike the Android frameworks, we have no access to certain remote class\n        ClassLoader loader = BaseParceledListSlice.class.getClassLoader();\n        final int N = p.readInt();\n        mList = new ArrayList<>(N);\n        if (DEBUG) Log.d(TAG, \"Retrieving \" + N + \" items\");\n        if (N <= 0) {\n            return;\n        }\n\n        Parcelable.Creator<?> creator = readParcelableCreator(p, loader);\n        Class<?> listElementClass = null;\n\n        int i = 0;\n        while (i < N) {\n            if (p.readInt() == 0) {\n                break;\n            }\n\n            final T parcelable = readCreator(creator, p, loader);\n            if (listElementClass == null) {\n                listElementClass = parcelable.getClass();\n            } else {\n                verifySameType(listElementClass, parcelable.getClass());\n            }\n\n            mList.add(parcelable);\n\n            if (DEBUG) Log.d(TAG, \"Read inline #\" + i + \": \" + mList.get(mList.size() - 1));\n            i++;\n        }\n        if (i >= N) {\n            return;\n        }\n        final IBinder retriever = p.readStrongBinder();\n        while (i < N) {\n            if (DEBUG) Log.d(TAG, \"Reading more @\" + i + \" of \" + N + \": retriever=\" + retriever);\n            Parcel data = ParcelCompat2.obtain(retriever);\n            Parcel reply = ParcelCompat2.obtain(retriever);\n            data.writeInt(i);\n            try {\n                retriever.transact(IBinder.FIRST_CALL_TRANSACTION, data, reply, 0);\n            } catch (RemoteException e) {\n                Log.w(TAG, \"Failure retrieving array; only received \" + i + \" of \" + N, e);\n                return;\n            }\n            while (i < N && reply.readInt() != 0) {\n                final T parcelable = readCreator(creator, reply, loader);\n                verifySameType(listElementClass, parcelable.getClass());\n\n                mList.add(parcelable);\n\n                if (DEBUG) Log.d(TAG, \"Read extra #\" + i + \": \" + mList.get(mList.size() - 1));\n                i++;\n            }\n            reply.recycle();\n            data.recycle();\n        }\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    private T readCreator(Parcelable.Creator<?> creator, Parcel p, @Nullable ClassLoader loader) {\n        if (creator instanceof Parcelable.ClassLoaderCreator<?>) {\n            Parcelable.ClassLoaderCreator<?> classLoaderCreator =\n                    (Parcelable.ClassLoaderCreator<?>) creator;\n            return (T) classLoaderCreator.createFromParcel(p, loader);\n        }\n        return (T) creator.createFromParcel(p);\n    }\n\n    private static void verifySameType(@Nullable final Class<?> expected, @NonNull final Class<?> actual) {\n        if (!actual.equals(expected)) {\n            throw new IllegalArgumentException(\"Can't unparcel type \"\n                    + actual.getName() + \" in list of type \"\n                    + (expected == null ? null : expected.getName()));\n        }\n    }\n\n    public List<T> getList() {\n        return mList;\n    }\n\n    /**\n     * Set a limit on the maximum number of entries in the array that will be included\n     * inline in the initial parcelling of this object.\n     */\n    public void setInlineCountLimit(int maxCount) {\n        mInlineCountLimit = maxCount;\n    }\n\n    /**\n     * Write this to another Parcel. Note that this discards the internal Parcel\n     * and should not be used anymore. This is so we can pass this to a Binder\n     * where we won't have a chance to call recycle on this.\n     */\n    @Override\n    public void writeToParcel(Parcel dest, int flags) {\n        final int N = mList.size();\n        final int callFlags = flags;\n        dest.writeInt(N);\n        if (DEBUG) Log.d(TAG, \"Writing \" + N + \" items\");\n        if (N > 0) {\n            final Class<?> listElementClass = mList.get(0).getClass();\n            writeParcelableCreator(mList.get(0), dest);\n            int i = 0;\n            while (i < N && i < mInlineCountLimit && dest.dataSize() < MAX_IPC_SIZE) {\n                dest.writeInt(1);\n\n                final T parcelable = mList.get(i);\n                verifySameType(listElementClass, parcelable.getClass());\n                writeElement(parcelable, dest, callFlags);\n\n                if (DEBUG) Log.d(TAG, \"Wrote inline #\" + i + \": \" + mList.get(i));\n                i++;\n            }\n            if (i < N) {\n                dest.writeInt(0);\n                Binder retriever = new Binder() {\n                    @Override\n                    protected boolean onTransact(int code, @NonNull Parcel data, Parcel reply, int flags)\n                            throws RemoteException {\n                        if (code != FIRST_CALL_TRANSACTION) {\n                            return super.onTransact(code, data, reply, flags);\n                        }\n                        int i = data.readInt();\n                        if (DEBUG) Log.d(TAG, \"Writing more @\" + i + \" of \" + N);\n                        while (i < N && reply.dataSize() < MAX_IPC_SIZE) {\n                            reply.writeInt(1);\n\n                            final T parcelable = mList.get(i);\n                            verifySameType(listElementClass, parcelable.getClass());\n                            writeElement(parcelable, reply, callFlags);\n\n                            if (DEBUG) Log.d(TAG, \"Wrote extra #\" + i + \": \" + mList.get(i));\n                            i++;\n                        }\n                        if (i < N) {\n                            if (DEBUG) Log.d(TAG, \"Breaking @\" + i + \" of \" + N);\n                            reply.writeInt(0);\n                        }\n                        return true;\n                    }\n                };\n                if (DEBUG) Log.d(TAG, \"Breaking @\" + i + \" of \" + N + \": retriever=\" + retriever);\n                dest.writeStrongBinder(retriever);\n            }\n        }\n    }\n\n    protected abstract void writeElement(T parcelable, Parcel reply, int callFlags);\n\n    protected abstract void writeParcelableCreator(T parcelable, Parcel dest);\n\n    protected abstract Parcelable.Creator<?> readParcelableCreator(Parcel from, @Nullable ClassLoader loader);\n}"
  },
  {
    "path": "libcore/io/src/main/java/aosp/android/content/pm/ParcelUtils.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage aosp.android.content.pm;\n\nimport android.os.BadParcelableException;\nimport android.os.Build;\nimport android.os.Parcel;\nimport android.os.Parcelable;\nimport android.util.Log;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport java.lang.reflect.Field;\nimport java.lang.reflect.Modifier;\nimport java.util.HashMap;\n\npublic class ParcelUtils {\n    private static final String TAG = ParcelUtils.class.getSimpleName();\n\n    public static <T> void writeParcelableCreator(@NonNull T parcelable, @NonNull Parcel dest) {\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {\n            dest.writeParcelableCreator((Parcelable) parcelable);\n        } else {\n            String name = parcelable.getClass().getName();\n            dest.writeString(name);\n        }\n    }\n\n    // Cache of previously looked up CREATOR.createFromParcel() methods for\n    // particular classes.  Keys are the names of the classes, values are\n    // Method objects.\n    private static final HashMap<ClassLoader, HashMap<String, Parcelable.Creator<?>>> mCreators = new HashMap<>();\n\n    @Nullable\n    public static Parcelable.Creator<?> readParcelableCreator(@NonNull Parcel from, @Nullable ClassLoader loader) {\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {\n            return from.readParcelableCreator(loader);\n        }\n        String name = from.readString();\n        if (name == null) {\n            return null;\n        }\n        Parcelable.Creator<?> creator;\n        synchronized (mCreators) {\n            HashMap<String, Parcelable.Creator<?>> map = mCreators.get(loader);\n            if (map == null) {\n                map = new HashMap<>();\n                mCreators.put(loader, map);\n            }\n            creator = map.get(name);\n            if (creator == null) {\n                try {\n                    // If loader == null, explicitly emulate Class.forName(String) \"caller\n                    // classloader\" behavior.\n                    ClassLoader parcelableClassLoader = (loader == null ? from.getClass().getClassLoader() : loader);\n                    // Avoid initializing the Parcelable class until we know it implements\n                    // Parcelable and has the necessary CREATOR field.\n                    Class<?> parcelableClass = Class.forName(name, false /* initialize */,\n                            parcelableClassLoader);\n                    if (!Parcelable.class.isAssignableFrom(parcelableClass)) {\n                        throw new BadParcelableException(\"Parcelable protocol requires that the \"\n                                + \"class implements Parcelable\");\n                    }\n                    Field f = parcelableClass.getField(\"CREATOR\");\n                    if ((f.getModifiers() & Modifier.STATIC) == 0) {\n                        throw new BadParcelableException(\"Parcelable protocol requires \"\n                                + \"the CREATOR object to be static on class \" + name);\n                    }\n                    Class<?> creatorType = f.getType();\n                    if (!Parcelable.Creator.class.isAssignableFrom(creatorType)) {\n                        // Fail before calling Field.get(), not after, to avoid initializing\n                        // parcelableClass unnecessarily.\n                        throw new BadParcelableException(\"Parcelable protocol requires a \"\n                                + \"Parcelable.Creator object called \"\n                                + \"CREATOR on class \" + name);\n                    }\n                    creator = (Parcelable.Creator<?>) f.get(null);\n                } catch (IllegalAccessException e) {\n                    Log.e(TAG, \"Illegal access when unmarshalling: \" + name, e);\n                    throw new BadParcelableException(\n                            \"IllegalAccessException when unmarshalling: \" + name);\n                } catch (ClassNotFoundException e) {\n                    Log.e(TAG, \"Class not found when unmarshalling: \" + name, e);\n                    throw new BadParcelableException(\"ClassNotFoundException when unmarshalling: \" + name);\n                } catch (NoSuchFieldException e) {\n                    throw new BadParcelableException(\"Parcelable protocol requires a \"\n                            + \"Parcelable.Creator object called \"\n                            + \"CREATOR on class \" + name);\n                }\n                if (creator == null) {\n                    throw new BadParcelableException(\"Parcelable protocol requires a \"\n                            + \"non-null Parcelable.Creator object called \"\n                            + \"CREATOR on class \" + name);\n                }\n                map.put(name, creator);\n            }\n        }\n\n        return creator;\n    }\n}\n"
  },
  {
    "path": "libcore/io/src/main/java/aosp/android/content/pm/ParceledListSlice.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage aosp.android.content.pm;\n\nimport android.os.Parcel;\nimport android.os.Parcelable;\n\nimport androidx.annotation.Nullable;\n\nimport java.util.Collections;\nimport java.util.List;\n\n/**\n * Transfer a large list of Parcelable objects across an IPC.  Splits into\n * multiple transactions if needed.\n *\n * @see BaseParceledListSlice\n */\n// Copyright 2011 The Android Open Source Project\n@SuppressWarnings(\"rawtypes\")\npublic class ParceledListSlice<T extends Parcelable> extends BaseParceledListSlice<T> {\n    public ParceledListSlice(List<T> list) {\n        super(list);\n    }\n\n    private ParceledListSlice(Parcel in) {\n        super(in);\n    }\n\n    public static <T extends Parcelable> ParceledListSlice<T> emptyList() {\n        return new ParceledListSlice<>(Collections.emptyList());\n    }\n\n    @Override\n    public int describeContents() {\n        int contents = 0;\n        final List<T> list = getList();\n        for (T t : list) {\n            contents |= t.describeContents();\n        }\n        return contents;\n    }\n\n    @Override\n    protected void writeElement(T parcelable, Parcel dest, int callFlags) {\n        parcelable.writeToParcel(dest, callFlags);\n    }\n\n    @Override\n    protected void writeParcelableCreator(T parcelable, Parcel dest) {\n        ParcelUtils.writeParcelableCreator(parcelable, dest);\n    }\n\n    @Override\n    protected Parcelable.Creator<?> readParcelableCreator(Parcel from, @Nullable ClassLoader loader) {\n        return ParcelUtils.readParcelableCreator(from, loader);\n    }\n\n    public static final Parcelable.Creator<ParceledListSlice> CREATOR = new Parcelable.Creator<ParceledListSlice>() {\n        @Override\n        public ParceledListSlice createFromParcel(Parcel in) {\n            return new ParceledListSlice(in);\n        }\n\n        @Override\n        public ParceledListSlice[] newArray(int size) {\n            return new ParceledListSlice[size];\n        }\n    };\n}"
  },
  {
    "path": "libcore/io/src/main/java/aosp/android/content/pm/StringParceledListSlice.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage aosp.android.content.pm;\n\nimport android.os.Parcel;\nimport android.os.Parcelable;\n\nimport androidx.annotation.Nullable;\n\nimport java.util.Collections;\nimport java.util.List;\n\n/**\n * Transfer a large list of Parcelable objects across an IPC.  Splits into\n * multiple transactions if needed.\n *\n * @see BaseParceledListSlice\n */\n// Copyright 2017 The Android Open Source Project\npublic class StringParceledListSlice extends BaseParceledListSlice<String> {\n    public StringParceledListSlice(List<String> list) {\n        super(list);\n    }\n\n    private StringParceledListSlice(Parcel in) {\n        super(in);\n    }\n\n    public static StringParceledListSlice emptyList() {\n        return new StringParceledListSlice(Collections.emptyList());\n    }\n\n    @Override\n    public int describeContents() {\n        return 0;\n    }\n\n    @Override\n    protected void writeElement(String parcelable, Parcel reply, int callFlags) {\n        reply.writeString(parcelable);\n    }\n\n    @Override\n    protected void writeParcelableCreator(String parcelable, Parcel dest) {\n    }\n\n    @Override\n    protected Parcelable.Creator<?> readParcelableCreator(Parcel from, @Nullable ClassLoader loader) {\n        return Parcel.STRING_CREATOR;\n    }\n\n    public static final Parcelable.Creator<StringParceledListSlice> CREATOR =\n            new Parcelable.Creator<StringParceledListSlice>() {\n                @Override\n                public StringParceledListSlice createFromParcel(Parcel in) {\n                    return new StringParceledListSlice(in);\n                }\n\n                @Override\n                public StringParceledListSlice[] newArray(int size) {\n                    return new StringParceledListSlice[size];\n                }\n            };\n}"
  },
  {
    "path": "libcore/io/src/main/java/io/github/muntashirakon/io/AtomicExtendedFile.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.io;\n\nimport android.os.RemoteException;\nimport android.util.Log;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.WorkerThread;\n\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileNotFoundException;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.util.Objects;\n\n/**\n * Static library support version of the framework's {@link android.util.AtomicFile}, a helper class\n * for performing atomic operations on a file by writing to a new file and renaming it into the\n * place of the original file after the write has successfully completed.\n * <p>\n * Atomic file guarantees file integrity by ensuring that a file has been completely written and\n * sync'd to disk before renaming it to the original file. Previously this is done by renaming the\n * original file to a backup file beforehand, but this approach couldn't handle the case where the\n * file is created for the first time. This class will also handle the backup file created by the\n * old implementation properly.\n * <p>\n * Atomic file does not confer any file locking semantics. Do not use this class when the file may\n * be accessed or modified concurrently by multiple threads or processes. The caller is responsible\n * for ensuring appropriate mutual exclusion invariants whenever it accesses the file.\n */\npublic class AtomicExtendedFile {\n    private static final String TAG = \"AtomicExtendedFile\";\n\n    private final ExtendedFile mBaseName;\n    private final ExtendedFile mNewName;\n    private final ExtendedFile mLegacyBackupName;\n\n    /**\n     * Create a new AtomicFile for a file located at the given File path.\n     * The new file created when writing will be the same file path with \".new\" appended.\n     */\n    public AtomicExtendedFile(@NonNull ExtendedFile baseName) {\n        mBaseName = baseName;\n        mNewName = Objects.requireNonNull(baseName.getParentFile()).getChildFile(baseName.getName() + \".new\");\n        mLegacyBackupName = baseName.getParentFile().getChildFile(baseName.getName() + \".bak\");\n    }\n\n    /**\n     * Return the path to the base file.  You should not generally use this,\n     * as the data at that path may not be valid.\n     */\n    @NonNull\n    public ExtendedFile getBaseFile() {\n        return mBaseName;\n    }\n\n    /**\n     * Delete the atomic file.  This deletes both the base and new files.\n     */\n    public void delete() {\n        mBaseName.delete();\n        mNewName.delete();\n        mLegacyBackupName.delete();\n    }\n\n    /**\n     * Start a new write operation on the file.  This returns a FileOutputStream\n     * to which you can write the new file data.  The existing file is replaced\n     * with the new data.  You <em>must not</em> directly close the given\n     * FileOutputStream; instead call either {@link #finishWrite(FileOutputStream)}\n     * or {@link #failWrite(FileOutputStream)}.\n     *\n     * <p>Note that if another thread is currently performing\n     * a write, this will simply replace whatever that thread is writing\n     * with the new file being written by this thread, and when the other\n     * thread finishes the write the new write operation will no longer be\n     * safe (or will be lost).  You must do your own threading protection for\n     * access to AtomicFile.\n     */\n    @WorkerThread\n    @NonNull\n    public FileOutputStream startWrite() throws IOException {\n        if (mLegacyBackupName.exists()) {\n            rename(mLegacyBackupName, mBaseName);\n        }\n\n        try {\n            return mNewName.newOutputStream();\n        } catch (FileNotFoundException e) {\n            File parent = mNewName.getParentFile();\n            if (!parent.mkdirs()) {\n                throw new IOException(\"Failed to create directory for \" + mNewName, e);\n            }\n            try {\n                return mNewName.newOutputStream();\n            } catch (FileNotFoundException e2) {\n                throw new IOException(\"Failed to create new file \" + mNewName, e2);\n            }\n        }\n    }\n\n    /**\n     * Call when you have successfully finished writing to the stream\n     * returned by {@link #startWrite()}.  This will close, sync, and\n     * commit the new data.  The next attempt to read the atomic file\n     * will return the new file stream.\n     */\n    public void finishWrite(@Nullable FileOutputStream str) {\n        if (str == null) {\n            return;\n        }\n        if (!sync(str)) {\n            Log.e(TAG, \"Failed to sync file output stream\");\n        }\n        try {\n            str.close();\n        } catch (IOException e) {\n            Log.e(TAG, \"Failed to close file output stream\", e);\n        }\n        rename(mNewName, mBaseName);\n    }\n\n    /**\n     * Call when you have failed for some reason at writing to the stream\n     * returned by {@link #startWrite()}.  This will close the current\n     * write stream, and delete the new file.\n     */\n    public void failWrite(@Nullable FileOutputStream str) {\n        if (str == null) {\n            return;\n        }\n        if (!sync(str)) {\n            Log.e(TAG, \"Failed to sync file output stream\");\n        }\n        try {\n            str.close();\n        } catch (IOException e) {\n            Log.e(TAG, \"Failed to close file output stream\", e);\n        }\n        if (!mNewName.delete()) {\n            Log.e(TAG, \"Failed to delete new file \" + mNewName);\n        }\n    }\n\n    /**\n     * Open the atomic file for reading. You should call close() on the FileInputStream when you are\n     * done reading from it.\n     * <p>\n     * You must do your own threading protection for access to AtomicFile.\n     */\n    @WorkerThread\n    @NonNull\n    public FileInputStream openRead() throws IOException, RemoteException {\n        if (mLegacyBackupName.exists()) {\n            rename(mLegacyBackupName, mBaseName);\n        }\n\n        // It was okay to call openRead() between startWrite() and finishWrite() for the first time\n        // (because there is no backup file), where openRead() would open the file being written,\n        // which makes no sense, but finishWrite() would still persist the write properly. For all\n        // subsequent writes, if openRead() was called in between, it would see a backup file and\n        // delete the file being written, the same behavior as our new implementation. So we only\n        // need a special case for the first write, and don't delete the new file in this case so\n        // that finishWrite() can still work.\n        if (mNewName.exists() && mBaseName.exists()) {\n            if (!mNewName.delete()) {\n                Log.e(TAG, \"Failed to delete outdated new file \" + mNewName);\n            }\n        }\n        return mBaseName.newInputStream();\n    }\n\n    /**\n     * Checks if the original or legacy backup file exists.\n     * @return whether the original or legacy backup file exists.\n     */\n    public boolean exists() {\n        return mBaseName.exists() || mLegacyBackupName.exists();\n    }\n\n    /**\n     * A convenience for {@link #openRead()} that also reads all of the\n     * file contents into a byte array which is returned.\n     */\n    @NonNull\n    public byte[] readFully() throws IOException, RemoteException {\n        try (FileInputStream stream = openRead()) {\n            int pos = 0;\n            int avail = stream.available();\n            byte[] data = new byte[avail];\n            while (true) {\n                int amt = stream.read(data, pos, data.length - pos);\n                //Log.i(\"foo\", \"Read \" + amt + \" bytes at \" + pos\n                //        + \" of avail \" + data.length);\n                if (amt <= 0) {\n                    //Log.i(\"foo\", \"**** FINISHED READING: pos=\" + pos\n                    //        + \" len=\" + data.length);\n                    return data;\n                }\n                pos += amt;\n                avail = stream.available();\n                if (avail > data.length - pos) {\n                    byte[] newData = new byte[pos + avail];\n                    System.arraycopy(data, 0, newData, 0, pos);\n                    data = newData;\n                }\n            }\n        }\n    }\n\n    private static boolean sync(@NonNull FileOutputStream stream) {\n        try {\n            stream.getFD().sync();\n            return true;\n        } catch (IOException ignored) {\n        }\n        return true;\n    }\n\n    private static void rename(@NonNull File source, @NonNull File target) {\n        // We used to delete the target file before rename, but that isn't atomic, and the rename()\n        // syscall should atomically replace the target file. However in the case where the target\n        // file is a directory, a simple rename() won't work. We need to delete the file in this\n        // case because there are callers who erroneously called mBaseName.mkdirs() (instead of\n        // mBaseName.getParentFile().mkdirs()) before creating the AtomicFile, and it worked\n        // regardless, so this deletion became some kind of API.\n        if (target.isDirectory()) {\n            if (!target.delete()) {\n                Log.e(TAG, \"Failed to delete file which is a directory \" + target);\n            }\n        }\n        if (!source.renameTo(target)) {\n            Log.e(TAG, \"Failed to rename \" + source + \" to \" + target);\n        }\n    }\n}\n"
  },
  {
    "path": "libcore/io/src/main/java/io/github/muntashirakon/io/CharSequenceInputStream.java",
    "content": "// SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-or-later\n\npackage io.github.muntashirakon.io;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.nio.ByteBuffer;\nimport java.nio.CharBuffer;\nimport java.nio.charset.CharacterCodingException;\nimport java.nio.charset.Charset;\nimport java.nio.charset.CharsetEncoder;\nimport java.nio.charset.CoderResult;\nimport java.util.Objects;\n\n/**\n * Implements an {@link InputStream} to read from String, StringBuffer, StringBuilder or CharBuffer.\n * <p>\n * <strong>Note:</strong> Supports {@link #mark(int)} and {@link #reset()}.\n */\n// Copyright 2012 Apache Software Foundation\npublic class CharSequenceInputStream extends InputStream {\n    private static final int NO_MARK = -1;\n    private static final int EOF = -1;\n\n    private final ByteBuffer mByteBuffer;\n    private int mByteBufferMark; // position in mByteBuffer\n    private final CharBuffer mCharBuffer;\n    private int mCharBufferMark; // position in mCharBuffer\n    private final CharsetEncoder mCharsetEncoder;\n\n    /**\n     * Constructs a new instance with a buffer size of {@link IoUtils#DEFAULT_BUFFER_SIZE}.\n     *\n     * @param cs      the input character sequence.\n     * @param charset the character set name to use.\n     * @throws IllegalArgumentException if the buffer is not large enough to hold a complete character.\n     */\n    public CharSequenceInputStream(final CharSequence cs, final Charset charset) {\n        this(cs, charset, IoUtils.DEFAULT_BUFFER_SIZE);\n    }\n\n    /**\n     * Constructs a new instance.\n     *\n     * @param cs         the input character sequence.\n     * @param charset    the character set name to use, null maps to the default Charset.\n     * @param bufferSize the buffer size to use.\n     * @throws IllegalArgumentException if the buffer is not large enough to hold a complete character.\n     */\n    public CharSequenceInputStream(final CharSequence cs, final Charset charset, final int bufferSize) {\n        this(cs, bufferSize, charset.newEncoder());\n    }\n\n    private CharSequenceInputStream(final CharSequence cs, final int bufferSize, final CharsetEncoder charsetEncoder) {\n        mCharsetEncoder = charsetEncoder;\n        // Ensure that buffer is long enough to hold a complete character\n        mByteBuffer = ByteBuffer.allocate(checkMinBufferSize(charsetEncoder, bufferSize));\n        mByteBuffer.flip();\n        mCharBuffer = CharBuffer.wrap(cs);\n        mCharBufferMark = NO_MARK;\n        mByteBufferMark = NO_MARK;\n    }\n\n    /**\n     * Constructs a new instance with a buffer size of {@link IoUtils#DEFAULT_BUFFER_SIZE}.\n     *\n     * @param cs      the input character sequence.\n     * @param charset the character set name to use.\n     * @throws IllegalArgumentException if the buffer is not large enough to hold a complete character.\n     */\n    public CharSequenceInputStream(final CharSequence cs, final String charset) {\n        this(cs, charset, IoUtils.DEFAULT_BUFFER_SIZE);\n    }\n\n    /**\n     * Constructs a new instance.\n     *\n     * @param cs         the input character sequence.\n     * @param charset    the character set name to use, null maps to the default Charset.\n     * @param bufferSize the buffer size to use.\n     * @throws IllegalArgumentException if the buffer is not large enough to hold a complete character.\n     */\n    public CharSequenceInputStream(final CharSequence cs, final String charset, final int bufferSize) {\n        this(cs, Charset.forName(charset), bufferSize);\n    }\n\n    /**\n     * Return an estimate of the number of bytes remaining in the byte stream.\n     *\n     * @return the count of bytes that can be read without blocking (or returning EOF).\n     */\n    @Override\n    public int available() {\n        // The cached entries are in bBuf; since encoding always creates at least one byte\n        // per character, we can add the two to get a better estimate (e.g. if bBuf is empty)\n        // Note that the implementation in 2.4 could return zero even though there were\n        // encoded bytes still available.\n        return mByteBuffer.remaining() + mCharBuffer.remaining();\n    }\n\n    @Override\n    public void close() {\n        // noop\n    }\n\n    /**\n     * Fills the byte output buffer from the input char buffer.\n     *\n     * @throws CharacterCodingException an error encoding data.\n     */\n    private void fillBuffer() throws CharacterCodingException {\n        mByteBuffer.compact();\n        final CoderResult result = mCharsetEncoder.encode(mCharBuffer, mByteBuffer, true);\n        if (result.isError()) {\n            result.throwException();\n        }\n        mByteBuffer.flip();\n    }\n\n    /**\n     * Gets the CharsetEncoder.\n     *\n     * @return the CharsetEncoder.\n     */\n    CharsetEncoder getCharsetEncoder() {\n        return mCharsetEncoder;\n    }\n\n    /**\n     * {@inheritDoc}\n     *\n     * @param readlimit max read limit (ignored).\n     */\n    @Override\n    public synchronized void mark(final int readlimit) {\n        mCharBufferMark = mCharBuffer.position();\n        mByteBufferMark = mByteBuffer.position();\n        mCharBuffer.mark();\n        mByteBuffer.mark();\n        // It would be nice to be able to use mark & reset on the cBuf and bBuf;\n        // however the bBuf is re-used so that won't work\n    }\n\n    @Override\n    public boolean markSupported() {\n        return true;\n    }\n\n    @Override\n    public int read() throws IOException {\n        for (; ; ) {\n            if (mByteBuffer.hasRemaining()) {\n                return mByteBuffer.get() & 0xFF;\n            }\n            fillBuffer();\n            if (!mByteBuffer.hasRemaining() && !mCharBuffer.hasRemaining()) {\n                return EOF;\n            }\n        }\n    }\n\n    @Override\n    public int read(final byte[] b) throws IOException {\n        return read(b, 0, b.length);\n    }\n\n    @Override\n    public int read(final byte[] array, int off, int len) throws IOException {\n        Objects.requireNonNull(array, \"array\");\n        if (len < 0 || off + len > array.length) {\n            throw new IndexOutOfBoundsException(\"Array Size=\" + array.length + \", offset=\" + off + \", length=\" + len);\n        }\n        if (len == 0) {\n            return 0; // must return 0 for zero length read\n        }\n        if (!mByteBuffer.hasRemaining() && !mCharBuffer.hasRemaining()) {\n            return EOF;\n        }\n        int bytesRead = 0;\n        while (len > 0) {\n            if (mByteBuffer.hasRemaining()) {\n                final int chunk = Math.min(mByteBuffer.remaining(), len);\n                mByteBuffer.get(array, off, chunk);\n                off += chunk;\n                len -= chunk;\n                bytesRead += chunk;\n            } else {\n                fillBuffer();\n                if (!mByteBuffer.hasRemaining() && !mCharBuffer.hasRemaining()) {\n                    break;\n                }\n            }\n        }\n        return bytesRead == 0 && !mCharBuffer.hasRemaining() ? EOF : bytesRead;\n    }\n\n    @Override\n    public synchronized void reset() throws IOException {\n        //\n        // This is not the most efficient implementation, as it re-encodes from the beginning.\n        //\n        // Since the bBuf is re-used, in general it's necessary to re-encode the data.\n        //\n        // It should be possible to apply some optimizations however:\n        // + use mark/reset on the cBuf and bBuf. This would only work if the buffer had not been (re)filled since\n        // the mark. The code would have to catch InvalidMarkException - does not seem possible to check if mark is\n        // valid otherwise. + Try saving the state of the cBuf before each fillBuffer; it might be possible to\n        // restart from there.\n        //\n        if (mCharBufferMark != NO_MARK) {\n            // if cBuf is at 0, we have not started reading anything, so skip re-encoding\n            if (mCharBuffer.position() != 0) {\n                mCharsetEncoder.reset();\n                mCharBuffer.rewind();\n                mByteBuffer.rewind();\n                mByteBuffer.limit(0); // rewind does not clear the buffer\n                while (mCharBuffer.position() < mCharBufferMark) {\n                    mByteBuffer.rewind(); // empty the buffer (we only refill when empty during normal processing)\n                    mByteBuffer.limit(0);\n                    fillBuffer();\n                }\n            }\n            if (mCharBuffer.position() != mCharBufferMark) {\n                throw new IllegalStateException(\"Unexpected CharBuffer position: actual=\" + mCharBuffer.position() + \" \" +\n                        \"expected=\" + mCharBufferMark);\n            }\n            mByteBuffer.position(mByteBufferMark);\n            mCharBufferMark = NO_MARK;\n            mByteBufferMark = NO_MARK;\n        }\n    }\n\n    @Override\n    public long skip(long n) throws IOException {\n        //\n        // This could be made more efficient by using position to skip within the current buffer.\n        //\n        long skipped = 0;\n        while (n > 0 && available() > 0) {\n            read();\n            n--;\n            skipped++;\n        }\n        return skipped;\n    }\n\n    private static int checkMinBufferSize(final CharsetEncoder charsetEncoder, final int bufferSize) {\n        final float minRequired = minBufferSize(charsetEncoder);\n        if (bufferSize < minRequired) {\n            throw new IllegalArgumentException(String.format(\"Buffer size %,d must be at least %s for a CharsetEncoder %s.\", bufferSize, minRequired,\n                    charsetEncoder.charset().displayName()));\n        }\n        return bufferSize;\n    }\n\n    private static float minBufferSize(final CharsetEncoder charsetEncoder) {\n        return charsetEncoder.maxBytesPerChar() * 2;\n    }\n}\n"
  },
  {
    "path": "libcore/io/src/main/java/io/github/muntashirakon/io/ExtendedFile.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.io;\n\nimport android.system.ErrnoException;\nimport android.system.Os;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport java.io.File;\nimport java.io.FileFilter;\nimport java.io.FileInputStream;\nimport java.io.FileOutputStream;\nimport java.io.FilenameFilter;\nimport java.io.IOException;\nimport java.net.URI;\n\n/**\n * {@link File} API with extended features.\n * <p>\n * The goal of this class is to extend missing features in the {@link File} API that are available\n * in the NIO package but not possible to be re-implemented without low-level file system access.\n * For instance, detecting file types other than regular files and directories, handling and\n * creating hard links and symbolic links.\n * <p>\n * Another goal of this class is to provide a generalized API interface for custom file system\n * backends. The library includes backends for accessing files locally, accessing files remotely\n * via IPC, and accessing files through shell commands (by using {@code SuFile}, included in the\n * {@code io} module). The developer can get instances of this class with\n * {@link FileSystemManager#getFile}.\n * <p>\n * Implementations of this class is required to return the same type of {@link ExtendedFile} in\n * all of its APIs returning {@link File}s. This means that, for example, if the developer is\n * getting a list of files in a directory using a remote file system with {@link #listFiles()},\n * all files returned in the array will also be using the same remote file system backend.\n */\n// Copyright 2022 John \"topjohnwu\" Wu\n// Copyright 2022 Muntashir Al-Islam\npublic abstract class ExtendedFile extends File {\n\n    /**\n     * @see File#File(String)\n     */\n    protected ExtendedFile(@NonNull String pathname) {\n        super(pathname);\n    }\n\n    /**\n     * @see File#File(String, String)\n     */\n    protected ExtendedFile(@Nullable String parent, @NonNull String child) {\n        super(parent, child);\n    }\n\n    /**\n     * @see File#File(File, String)\n     */\n    protected ExtendedFile(@Nullable File parent, @NonNull String child) {\n        super(parent, child);\n    }\n\n    /**\n     * @see File#File(URI)\n     */\n    protected ExtendedFile(@NonNull URI uri) {\n        super(uri);\n    }\n\n    /**\n     * @return Get mode (permission) of the abstract pathname.\n     */\n    public abstract int getMode() throws ErrnoException;\n\n    /**\n     * Set mode (permission) of the abstract pathname.\n     *\n     * @return <code>true</code> on success.\n     * @see Os#chmod(String, int)\n     */\n    public abstract boolean setMode(int mode) throws ErrnoException;\n\n    /**\n     * @return Get UID and GID of the abstract pathname.\n     */\n    public abstract UidGidPair getUidGid() throws ErrnoException;\n\n    /**\n     * Set UID and GID of the abstract pathname.\n     *\n     * @return <code>true</code> on success.\n     * @see Os#chown(String, int, int)\n     */\n    public abstract boolean setUidGid(int uid, int gid) throws ErrnoException;\n\n    @Nullable\n    public abstract String getSelinuxContext();\n\n    public abstract boolean restoreSelinuxContext();\n\n    public abstract boolean setSelinuxContext(@NonNull String context);\n\n    /**\n     * @return true if the abstract pathname denotes a block device.\n     */\n    public abstract boolean isBlock();\n\n    /**\n     * @return true if the abstract pathname denotes a character device.\n     */\n    public abstract boolean isCharacter();\n\n    /**\n     * @return true if the abstract pathname denotes a symbolic link.\n     */\n    public abstract boolean isSymlink();\n\n    /**\n     * @return true if the abstract pathname denotes a named pipe (FIFO).\n     */\n    public abstract boolean isNamedPipe();\n\n    /**\n     * @return true if the abstract pathname denotes a socket file.\n     */\n    public abstract boolean isSocket();\n\n    /**\n     * Returns the time that the file denoted by this abstract pathname was created.\n     *\n     * @return A <code>long</code> value representing the time the file was\n     * created, measured in milliseconds since the epoch\n     * (00:00:00 GMT, January 1, 1970), or <code>0L</code> if the\n     * file does not exist or if an I/O error occurs\n     */\n    public abstract long creationTime();\n\n    /**\n     * Returns the time that the file denoted by this abstract pathname was last accessed.\n     *\n     * @return A <code>long</code> value representing the time the file was\n     * last accessed, measured in milliseconds since the epoch\n     * (00:00:00 GMT, January 1, 1970), or <code>0L</code> if the\n     * file does not exist or if an I/O error occurs\n     */\n    public abstract long lastAccess();\n\n    /**\n     * Set the time that the file denoted by this abstract pathname was last accessed.\n     *\n     * @param millis A <code>long</code> value representing the time the file was\n     *               last accessed, measured in milliseconds since the epoch\n     *               (00:00:00 GMT, January 1, 1970)\n     * @return {@code true} if and only if the operation succeeded; {@code false} otherwise.\n     */\n    public abstract boolean setLastAccess(long millis);\n\n    /**\n     * Creates a new hard link named by this abstract pathname of an existing file\n     * if and only if a file with this name does not yet exist.\n     *\n     * @param existing a path to an existing file.\n     * @return <code>true</code> if the named file does not exist and was successfully\n     * created; <code>false</code> if the named file already exists.\n     * @throws IOException if an I/O error occurred.\n     */\n    public abstract boolean createNewLink(String existing) throws IOException;\n\n    /**\n     * Creates a new symbolic link named by this abstract pathname to a target file\n     * if and only if a file with this name does not yet exist.\n     *\n     * @param target the target of the symbolic link.\n     * @return <code>true</code> if the named file does not exist and was successfully\n     * created; <code>false</code> if the named file already exists.\n     * @throws IOException if an I/O error occurred.\n     */\n    public abstract boolean createNewSymlink(String target) throws IOException;\n\n    /**\n     * Opens an InputStream with the matching file system backend of the file.\n     *\n     * @see FileInputStream#FileInputStream(File)\n     */\n    @NonNull\n    public abstract FileInputStream newInputStream() throws IOException;\n\n    /**\n     * Opens an OutputStream with the matching file system backend of the file.\n     *\n     * @see FileOutputStream#FileOutputStream(File)\n     */\n    @NonNull\n    public final FileOutputStream newOutputStream() throws IOException {\n        return newOutputStream(false);\n    }\n\n    /**\n     * Opens an OutputStream with the matching file system backend of the file.\n     *\n     * @see FileOutputStream#FileOutputStream(File, boolean)\n     */\n    @NonNull\n    public abstract FileOutputStream newOutputStream(boolean append) throws IOException;\n\n    /**\n     * Create a child relative to the abstract pathname using the same file system backend.\n     *\n     * @see File#File(File, String)\n     */\n    @NonNull\n    public abstract ExtendedFile getChildFile(String child);\n\n    /**\n     * {@inheritDoc}\n     */\n    @NonNull\n    @Override\n    public abstract ExtendedFile getAbsoluteFile();\n\n    /**\n     * {@inheritDoc}\n     */\n    @NonNull\n    @Override\n    public abstract ExtendedFile getCanonicalFile() throws IOException;\n\n    /**\n     * {@inheritDoc}\n     */\n    @Nullable\n    @Override\n    public abstract ExtendedFile getParentFile();\n\n    /**\n     * {@inheritDoc}\n     */\n    @Nullable\n    @Override\n    public abstract ExtendedFile[] listFiles();\n\n    /**\n     * {@inheritDoc}\n     */\n    @Nullable\n    @Override\n    public abstract ExtendedFile[] listFiles(@Nullable FilenameFilter filter);\n\n    /**\n     * {@inheritDoc}\n     */\n    @Nullable\n    @Override\n    public abstract ExtendedFile[] listFiles(@Nullable FileFilter filter);\n}"
  },
  {
    "path": "libcore/io/src/main/java/io/github/muntashirakon/io/FileContainer.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage io.github.muntashirakon.io;\n\nimport android.os.Binder;\nimport android.util.SparseArray;\n\nimport androidx.annotation.NonNull;\n\nimport java.io.IOException;\n\n// Copyright 2022 John \"topjohnwu\" Wu\nclass FileContainer {\n\n    private final static String ERROR_MSG = \"Requested file was not opened!\";\n\n    private int nextHandle = 0;\n    // pid -> handle -> holder\n    private final SparseArray<SparseArray<OpenFile>> files = new SparseArray<>();\n\n    @NonNull\n    synchronized OpenFile get(int handle) throws IOException {\n        int pid = Binder.getCallingPid();\n        SparseArray<OpenFile> pidFiles = files.get(pid);\n        if (pidFiles == null)\n            throw new IOException(ERROR_MSG);\n        OpenFile h = pidFiles.get(handle);\n        if (h == null)\n            throw new IOException(ERROR_MSG);\n        return h;\n    }\n\n    synchronized int put(OpenFile h) {\n        int pid = Binder.getCallingPid();\n        SparseArray<OpenFile> pidFiles = files.get(pid);\n        if (pidFiles == null) {\n            pidFiles = new SparseArray<>();\n            files.put(pid, pidFiles);\n        }\n        int handle = nextHandle++;\n        pidFiles.append(handle, h);\n        return handle;\n    }\n\n    synchronized void remove(int handle) {\n        int pid = Binder.getCallingPid();\n        SparseArray<OpenFile> pidFiles = files.get(pid);\n        if (pidFiles == null)\n            return;\n        OpenFile h = pidFiles.get(handle);\n        if (h == null)\n            return;\n        pidFiles.remove(handle);\n        h.close();\n    }\n\n    synchronized void pidDied(int pid) {\n        SparseArray<OpenFile> pidFiles = files.get(pid);\n        if (pidFiles == null)\n            return;\n        files.remove(pid);\n        for (int i = 0; i < pidFiles.size(); ++i) {\n            pidFiles.valueAt(i).close();\n        }\n    }\n}"
  },
  {
    "path": "libcore/io/src/main/java/io/github/muntashirakon/io/FileImpl.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.io;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport java.io.FileFilter;\nimport java.io.FilenameFilter;\nimport java.io.IOException;\nimport java.util.ArrayList;\n\n// Copyright 2022 John \"topjohnwu\" Wu\nabstract class FileImpl<T extends ExtendedFile> extends ExtendedFile {\n\n    protected FileImpl(@NonNull String pathname) {\n        super(pathname);\n    }\n\n    protected FileImpl(@Nullable String parent, @NonNull String child) {\n        super(parent, child);\n    }\n\n    protected abstract T create(String path);\n    protected abstract T[] createArray(int n);\n    @NonNull\n    @Override\n    public abstract T getChildFile(String name);\n\n    @NonNull\n    @Override\n    public T getAbsoluteFile() {\n        return create(getAbsolutePath());\n    }\n\n    @NonNull\n    @Override\n    public T getCanonicalFile() throws IOException {\n        return create(getCanonicalPath());\n    }\n\n    @Nullable\n    @Override\n    public T getParentFile() {\n        String parent = getParent();\n        return parent != null ? create(parent) : null;\n    }\n\n    @Nullable\n    @Override\n    public T[] listFiles() {\n        String[] ss = list();\n        if (ss == null)\n            return null;\n        int n = ss.length;\n        T[] fs = createArray(n);\n        for (int i = 0; i < n; i++) {\n            fs[i] = getChildFile(ss[i]);\n        }\n        return fs;\n    }\n\n    @Nullable\n    @Override\n    public T[] listFiles(@Nullable FilenameFilter filter) {\n        String[] ss = list();\n        if (ss == null)\n            return null;\n        ArrayList<T> files = new ArrayList<>();\n        for (String s : ss) {\n            if ((filter == null) || filter.accept(this, s))\n                files.add(getChildFile(s));\n        }\n        return files.toArray(createArray(0));\n    }\n\n    @Nullable\n    @Override\n    public T[] listFiles(@Nullable FileFilter filter) {\n        String[] ss = list();\n        if (ss == null)\n            return null;\n        ArrayList<T> files = new ArrayList<>();\n        for (String s : ss) {\n            T f = getChildFile(s);\n            if ((filter == null) || filter.accept(f))\n                files.add(f);\n        }\n        return files.toArray(createArray(0));\n    }\n}"
  },
  {
    "path": "libcore/io/src/main/java/io/github/muntashirakon/io/FileSystemManager.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.io;\n\nimport android.os.Binder;\nimport android.os.Bundle;\nimport android.os.IBinder;\nimport android.os.ParcelFileDescriptor;\nimport android.os.RemoteException;\n\nimport androidx.annotation.IntDef;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.lang.annotation.Retention;\nimport java.net.URI;\nimport java.nio.channels.FileChannel;\n\nimport static java.lang.annotation.RetentionPolicy.SOURCE;\n\n/**\n * Access file system APIs.\n */\n// Copyright 2022 John \"topjohnwu\" Wu\npublic abstract class FileSystemManager {\n\n    /**\n     * For use with {@link #openChannel}: open the file with read-only access.\n     */\n    public static final int MODE_READ_ONLY = ParcelFileDescriptor.MODE_READ_ONLY;\n    /**\n     * For use with {@link #openChannel}: open the file with write-only access.\n     */\n    public static final int MODE_WRITE_ONLY = ParcelFileDescriptor.MODE_WRITE_ONLY;\n    /**\n     * For use with {@link #openChannel}: open the file with read and write access.\n     */\n    public static final int MODE_READ_WRITE = ParcelFileDescriptor.MODE_READ_WRITE;\n    /**\n     * For use with {@link #openChannel}: create the file if it doesn't already exist.\n     */\n    public static final int MODE_CREATE = ParcelFileDescriptor.MODE_CREATE;\n    /**\n     * For use with {@link #openChannel}: erase contents of file when opening.\n     */\n    public static final int MODE_TRUNCATE = ParcelFileDescriptor.MODE_TRUNCATE;\n    /**\n     * For use with {@link #openChannel}: append to end of file while writing.\n     */\n    public static final int MODE_APPEND = ParcelFileDescriptor.MODE_APPEND;\n\n    @Retention(SOURCE)\n    @IntDef(value = {\n            MODE_READ_ONLY, MODE_WRITE_ONLY, MODE_READ_WRITE,\n            MODE_CREATE, MODE_TRUNCATE, MODE_APPEND}, flag = true)\n    @interface OpenMode {}\n\n    private static final FileSystemManager LOCAL = NIOFactory.createLocal();\n\n    private static Binder fsService;\n\n    /**\n     * Get the service that exports the file system of the current process over Binder IPC.\n     * <p>\n     * Sending the {@link Binder} obtained from this method to a client process enables\n     * the current process to perform file system operations on behalf of the client.\n     * This allows a client process to access files normally denied by its permissions.\n     * This method is usually called in a root process, and the Binder service returned will\n     * be send over to a non-root client process.\n     * <p>\n     * You can pass this {@link Binder} object in multiple ways, such as returning it in the\n     * {@code onBind()} method of root services, passing it around in a {@link Bundle},\n     * or returning it in an AIDL interface method. The receiving end will get an {@link IBinder},\n     * which the developer should then pass to {@link #getRemote(IBinder)} for usage.\n     */\n    @NonNull\n    public synchronized static Binder getService() {\n        if (fsService == null) {\n            fsService = NIOFactory.createFsService();\n        }\n        return fsService;\n    }\n\n    /**\n     * Get the {@link FileSystemManager} to access the file system of the current local process.\n     */\n    @NonNull\n    public static FileSystemManager getLocal() {\n        return LOCAL;\n    }\n\n    /**\n     * Create a {@link FileSystemManager} to access the file system of a remote process.\n     * <p>\n     * Several APIs are not supported through a remote process:\n     * <ul>\n     *     <li>{@link File#deleteOnExit()}</li>\n     *     <li>{@link FileChannel#map(FileChannel.MapMode, long, long)}</li>\n     *     <li>{@link FileChannel#lock()}</li>\n     *     <li>{@link FileChannel#lock(long, long, boolean)}</li>\n     *     <li>{@link FileChannel#tryLock()}</li>\n     *     <li>{@link FileChannel#tryLock(long, long, boolean)}</li>\n     * </ul>\n     * Calling these APIs will throw {@link UnsupportedOperationException}.\n     *\n     * @param binder a remote proxy of the {@link Binder} obtained from {@link #getService()}\n     * @throws RemoteException if the remote process has died.\n     */\n    @NonNull\n    public static FileSystemManager getRemote(@NonNull IBinder binder) throws RemoteException {\n        return NIOFactory.createRemote(binder);\n    }\n\n    /**\n     * @see File#File(String)\n     */\n    @NonNull\n    public abstract ExtendedFile getFile(@NonNull String pathname);\n\n    /**\n     * @see File#File(String, String)\n     */\n    @NonNull\n    public abstract ExtendedFile getFile(@Nullable String parent, @NonNull String child);\n\n    /**\n     * @see File#File(File, String)\n     */\n    @NonNull\n    public final ExtendedFile getFile(@Nullable File parent, @NonNull String child) {\n        return getFile(parent == null ? null : parent.getPath(), child);\n    }\n\n    /**\n     * @see File#File(URI)\n     */\n    @NonNull\n    public final ExtendedFile getFile(@NonNull URI uri) {\n        return getFile(new File(uri).getPath());\n    }\n\n    /**\n     * Opens a file channel to access the file.\n     *\n     * @param pathname the file to be opened.\n     * @param mode     the desired access mode.\n     * @return a new FileChannel pointing to the given file.\n     * @throws IOException if the given file can not be opened with the requested mode.\n     */\n    @NonNull\n    public final FileChannel openChannel(@NonNull String pathname, @OpenMode int mode) throws IOException {\n        return openChannel(new File(pathname), mode);\n    }\n\n    /**\n     * Opens a file channel to access the file.\n     *\n     * @param file the file to be opened.\n     * @param mode the desired access mode.\n     * @return a new FileChannel pointing to the given file.\n     * @throws IOException if the given file can not be opened with the requested mode.\n     */\n    @NonNull\n    public abstract FileChannel openChannel(@NonNull File file, @OpenMode int mode) throws IOException;\n}"
  },
  {
    "path": "libcore/io/src/main/java/io/github/muntashirakon/io/FileSystemService.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.io;\n\nimport static android.system.OsConstants.O_APPEND;\nimport static android.system.OsConstants.O_CREAT;\nimport static android.system.OsConstants.O_NONBLOCK;\nimport static android.system.OsConstants.O_RDONLY;\nimport static android.system.OsConstants.O_TRUNC;\nimport static android.system.OsConstants.O_WRONLY;\n\nimport android.annotation.SuppressLint;\nimport android.os.Binder;\nimport android.os.IBinder;\nimport android.os.ParcelFileDescriptor;\nimport android.os.RemoteException;\nimport android.os.SELinux;\nimport android.system.ErrnoException;\nimport android.system.Os;\nimport android.system.OsConstants;\nimport android.system.StructStat;\nimport android.util.LruCache;\n\nimport java.io.File;\nimport java.io.IOException;\nimport java.util.Arrays;\nimport java.util.concurrent.ExecutorService;\nimport java.util.concurrent.Executors;\n\nimport aosp.android.content.pm.StringParceledListSlice;\nimport io.github.muntashirakon.compat.system.OsCompat;\nimport io.github.muntashirakon.compat.system.StructTimespec;\n\n// Copyright 2022 John \"topjohnwu\" Wu\n// Copyright 2022 Muntashir Al-Islam\nclass FileSystemService extends IFileSystemService.Stub {\n\n    static final int PIPE_CAPACITY = 16 * 4096;\n\n    private final LruCache<String, File> mCache = new LruCache<String, File>(100) {\n        @Override\n        protected File create(String key) {\n            return new File(key);\n        }\n    };\n\n    @Override\n    public IOResult getCanonicalPath(String path) {\n        try {\n            return new IOResult(mCache.get(path).getCanonicalPath());\n        } catch (IOException e) {\n            return new IOResult(e);\n        }\n    }\n\n    @Override\n    public boolean isDirectory(String path) {\n        return mCache.get(path).isDirectory();\n    }\n\n    @Override\n    public boolean isFile(String path) {\n        return mCache.get(path).isFile();\n    }\n\n    @Override\n    public boolean isHidden(String path) {\n        return mCache.get(path).isHidden();\n    }\n\n    @Override\n    public long lastModified(String path) {\n        return mCache.get(path).lastModified();\n    }\n\n    @Override\n    public IOResult lastAccess(String path) {\n        try {\n            return new IOResult(Os.lstat(path).st_atime * 1000);\n        } catch (ErrnoException e) {\n            return new IOResult(e);\n        }\n    }\n\n    @Override\n    public IOResult creationTime(String path) {\n        try {\n            return new IOResult(Os.lstat(path).st_ctime * 1000);\n        } catch (ErrnoException e) {\n            return new IOResult(e);\n        }\n    }\n\n    @Override\n    public long length(String path) {\n        return mCache.get(path).length();\n    }\n\n    @Override\n    public IOResult createNewFile(String path) {\n        try {\n            return new IOResult(mCache.get(path).createNewFile());\n        } catch (IOException e) {\n            return new IOResult(e);\n        }\n    }\n\n    @Override\n    public boolean delete(String path) {\n        return mCache.get(path).delete();\n    }\n\n    @Override\n    public StringParceledListSlice list(String path) {\n        String[] list = mCache.get(path).list();\n        return list != null ? new StringParceledListSlice(Arrays.asList(list)) : null;\n    }\n\n    @Override\n    public boolean mkdir(String path) {\n        return mCache.get(path).mkdir();\n    }\n\n    @Override\n    public boolean mkdirs(String path) {\n        return mCache.get(path).mkdirs();\n    }\n\n    @Override\n    public boolean renameTo(String path, String dest) {\n        return mCache.get(path).renameTo(mCache.get(dest));\n    }\n\n    @Override\n    public boolean setLastModified(String path, long time) {\n        return mCache.get(path).setLastModified(time);\n    }\n\n    @Override\n    public IOResult setLastAccess(String path, long time) {\n        long seconds_part = time / 1_000;\n        long nanoseconds_part = (time % 1_000) * 1_000_000;\n        StructTimespec atime = new StructTimespec(seconds_part, nanoseconds_part);\n        StructTimespec mtime = new StructTimespec(0, OsCompat.UTIME_OMIT);\n        try {\n            OsCompat.utimensat(OsCompat.AT_FDCWD, path, atime, mtime, OsCompat.AT_SYMLINK_NOFOLLOW);\n            return new IOResult(true);\n        } catch (ErrnoException e) {\n            return new IOResult(e);\n        }\n    }\n\n    @Override\n    public boolean setReadOnly(String path) {\n        return mCache.get(path).setReadOnly();\n    }\n\n    @Override\n    public boolean setWritable(String path, boolean writable, boolean ownerOnly) {\n        return mCache.get(path).setWritable(writable, ownerOnly);\n    }\n\n    @Override\n    public boolean setReadable(String path, boolean readable, boolean ownerOnly) {\n        return mCache.get(path).setReadable(readable, ownerOnly);\n    }\n\n    @Override\n    public boolean setExecutable(String path, boolean executable, boolean ownerOnly) {\n        return mCache.get(path).setExecutable(executable, ownerOnly);\n    }\n\n    @Override\n    public boolean checkAccess(String path, int access) {\n        try {\n            return Os.access(path, access);\n        } catch (ErrnoException e) {\n            return false;\n        }\n    }\n\n    @Override\n    public long getTotalSpace(String path) {\n        return mCache.get(path).getTotalSpace();\n    }\n\n    @Override\n    public long getFreeSpace(String path) {\n        return mCache.get(path).getFreeSpace();\n    }\n\n    @SuppressLint(\"UsableSpace\")\n    @Override\n    public long getUsableSpace(String path) {\n        return mCache.get(path).getUsableSpace();\n    }\n\n    @Override\n    public IOResult getMode(String path) {\n        try {\n            return new IOResult(Os.lstat(path).st_mode);\n        } catch (ErrnoException e) {\n            return new IOResult(e);\n        }\n    }\n\n    @Override\n    public IOResult setMode(String path, int mode) {\n        try {\n            Os.chmod(path, mode);\n            return new IOResult(true);\n        } catch (ErrnoException e) {\n            return new IOResult(e);\n        }\n    }\n\n    @Override\n    public IOResult getUidGid(String path) {\n        try {\n            StructStat s = Os.lstat(path);\n            return new IOResult(new UidGidPair(s.st_uid, s.st_gid));\n        } catch (ErrnoException e) {\n            return new IOResult(e);\n        }\n    }\n\n    @Override\n    public IOResult setUidGid(String path, int uid, int gid) {\n        try {\n            Os.chown(path, uid, gid);\n            return new IOResult(true);\n        } catch (ErrnoException e) {\n            return new IOResult(e);\n        }\n    }\n\n    @Override\n    public String getSelinuxContext(String path) {\n        return SELinux.getFileContext(path);\n    }\n\n    @Override\n    public boolean restoreSelinuxContext(String path) {\n        return SELinux.restorecon(path);\n    }\n\n    @Override\n    public boolean setSelinuxContext(String path, String context) {\n        return SELinux.setFileContext(path, context);\n    }\n\n    @Override\n    public IOResult createLink(String link, String target, boolean soft) {\n        try {\n            if (soft) {\n                Os.symlink(target, link);\n            } else {\n                Os.link(target, link);\n            }\n            return new IOResult(true);\n        } catch (ErrnoException e) {\n            if (e.errno == OsConstants.EEXIST) {\n                return new IOResult(false);\n            } else {\n                return new IOResult(e);\n            }\n        }\n    }\n\n    // I/O APIs\n\n    private final FileContainer openFiles = new FileContainer();\n    private final ExecutorService streamPool = Executors.newCachedThreadPool();\n\n    @Override\n    public void register(IBinder client) {\n        int pid = Binder.getCallingPid();\n        try {\n            client.linkToDeath(() -> openFiles.pidDied(pid), 0);\n        } catch (RemoteException ignored) {\n        }\n    }\n\n    @SuppressWarnings(\"OctalInteger\")\n    @Override\n    public IOResult openChannel(String path, int mode, String fifo) {\n        OpenFile f = new OpenFile();\n        try {\n            f.fd = Os.open(path, mode | O_NONBLOCK, 0666);\n            f.read = Os.open(fifo, O_RDONLY | O_NONBLOCK, 0);\n            f.write = Os.open(fifo, O_WRONLY | O_NONBLOCK, 0);\n            return new IOResult(openFiles.put(f));\n        } catch (ErrnoException e) {\n            f.close();\n            return new IOResult(e);\n        }\n    }\n\n    @Override\n    public IOResult openReadStream(String path, ParcelFileDescriptor fd) {\n        OpenFile f = new OpenFile();\n        try {\n            f.fd = Os.open(path, O_RDONLY, 0);\n            streamPool.execute(() -> {\n                try (OpenFile of = f) {\n                    of.write = FileUtils.createFileDescriptor(fd.detachFd());\n                    while (of.pread(PIPE_CAPACITY, -1) > 0);\n                } catch (ErrnoException | IOException ignored) {}\n            });\n            return new IOResult();\n        } catch (ErrnoException e) {\n            f.close();\n            return new IOResult(e);\n        }\n    }\n\n    @SuppressWarnings(\"OctalInteger\")\n    @Override\n    public IOResult openWriteStream(String path, ParcelFileDescriptor fd, boolean append) {\n        OpenFile f = new OpenFile();\n        try {\n            int mode = O_CREAT | O_WRONLY | (append ? O_APPEND : O_TRUNC);\n            f.fd = Os.open(path, mode, 0666);\n            streamPool.execute(() -> {\n                try (OpenFile of = f) {\n                    of.read = FileUtils.createFileDescriptor(fd.detachFd());\n                    while (of.pwrite(PIPE_CAPACITY, -1, false) > 0);\n                } catch (ErrnoException | IOException ignored) {}\n            });\n            return new IOResult();\n        } catch (ErrnoException e) {\n            f.close();\n            return new IOResult(e);\n        }\n    }\n\n    @Override\n    public void close(int handle) {\n        openFiles.remove(handle);\n    }\n\n    @Override\n    public IOResult pread(int handle, int len, long offset) {\n        try {\n            return new IOResult(openFiles.get(handle).pread(len, offset));\n        } catch (IOException | ErrnoException e) {\n            return new IOResult(e);\n        }\n    }\n\n    @Override\n    public IOResult pwrite(int handle, int len, long offset) {\n        try {\n            openFiles.get(handle).pwrite(len, offset, true);\n            return new IOResult();\n        } catch (IOException | ErrnoException e) {\n            return new IOResult(e);\n        }\n    }\n\n    @Override\n    public IOResult lseek(int handle, long offset, int whence) {\n        try {\n            return new IOResult(openFiles.get(handle).lseek(offset, whence));\n        } catch (IOException | ErrnoException e) {\n            return new IOResult(e);\n        }\n    }\n\n    @Override\n    public IOResult size(int handle) {\n        try {\n            return new IOResult(openFiles.get(handle).size());\n        } catch (IOException | ErrnoException e) {\n            return new IOResult(e);\n        }\n    }\n\n    @Override\n    public IOResult ftruncate(int handle, long length) {\n        try {\n            openFiles.get(handle).ftruncate(length);\n            return new IOResult();\n        } catch (IOException | ErrnoException e) {\n            return new IOResult(e);\n        }\n    }\n\n    @Override\n    public IOResult sync(int handle, boolean metadata) {\n        try {\n            openFiles.get(handle).sync(metadata);\n            return new IOResult();\n        } catch (IOException | ErrnoException e) {\n            return new IOResult(e);\n        }\n    }\n}"
  },
  {
    "path": "libcore/io/src/main/java/io/github/muntashirakon/io/FileUtils.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage io.github.muntashirakon.io;\n\nimport static android.system.OsConstants.ENOSYS;\nimport static android.system.OsConstants.O_APPEND;\nimport static android.system.OsConstants.O_CREAT;\nimport static android.system.OsConstants.O_RDONLY;\nimport static android.system.OsConstants.O_RDWR;\nimport static android.system.OsConstants.O_TRUNC;\nimport static android.system.OsConstants.O_WRONLY;\nimport static io.github.muntashirakon.io.FileSystemManager.MODE_APPEND;\nimport static io.github.muntashirakon.io.FileSystemManager.MODE_CREATE;\nimport static io.github.muntashirakon.io.FileSystemManager.MODE_READ_ONLY;\nimport static io.github.muntashirakon.io.FileSystemManager.MODE_READ_WRITE;\nimport static io.github.muntashirakon.io.FileSystemManager.MODE_TRUNCATE;\nimport static io.github.muntashirakon.io.FileSystemManager.MODE_WRITE_ONLY;\n\nimport android.annotation.SuppressLint;\nimport android.os.Build;\nimport android.system.ErrnoException;\nimport android.system.Int64Ref;\nimport android.system.Os;\nimport android.util.ArraySet;\nimport android.util.MutableLong;\n\nimport androidx.annotation.RequiresApi;\n\nimport java.io.File;\nimport java.io.FileDescriptor;\nimport java.io.IOException;\nimport java.lang.reflect.AccessibleObject;\nimport java.lang.reflect.Constructor;\nimport java.lang.reflect.InvocationTargetException;\nimport java.lang.reflect.Method;\nimport java.nio.file.OpenOption;\nimport java.nio.file.StandardOpenOption;\nimport java.util.Set;\n\n// Copyright 2022 John \"topjohnwu\" Wu\n@SuppressWarnings({\"ConstantConditions\", \"JavaReflectionMemberAccess\"})\n@SuppressLint(\"DiscouragedPrivateApi\")\nclass FileUtils {\n    private static Object os;\n    private static Method splice;\n    private static Method sendfile;\n    private static AccessibleObject setFd;\n\n    static class Flag {\n        boolean read;\n        boolean write;\n        boolean create;\n        boolean truncate;\n        boolean append;\n    }\n\n    static int modeToPosix(int mode) {\n        int res;\n        if ((mode & MODE_READ_WRITE) == MODE_READ_WRITE) {\n            res = O_RDWR;\n        } else if ((mode & MODE_WRITE_ONLY) == MODE_WRITE_ONLY) {\n            res = O_WRONLY;\n        } else if ((mode & MODE_READ_ONLY) == MODE_READ_ONLY) {\n            res = O_RDONLY;\n        } else {\n            throw new IllegalArgumentException(\"Bad mode: \" + mode);\n        }\n        if ((mode & MODE_CREATE) == MODE_CREATE) {\n            res |= O_CREAT;\n        }\n        if ((mode & MODE_TRUNCATE) == MODE_TRUNCATE) {\n            res |= O_TRUNC;\n        }\n        if ((mode & MODE_APPEND) == MODE_APPEND) {\n            res |= O_APPEND;\n        }\n        return res;\n    }\n\n    @RequiresApi(api = 26)\n    static Set<OpenOption> modeToOptions(int mode) {\n        Set<OpenOption> set = new ArraySet<>();\n        if ((mode & MODE_READ_WRITE) == MODE_READ_WRITE) {\n            set.add(StandardOpenOption.READ);\n            set.add(StandardOpenOption.WRITE);\n        } else if ((mode & MODE_WRITE_ONLY) == MODE_WRITE_ONLY) {\n            set.add(StandardOpenOption.WRITE);\n        } else if ((mode & MODE_READ_ONLY) == MODE_READ_ONLY) {\n            set.add(StandardOpenOption.READ);\n        } else {\n            throw new IllegalArgumentException(\"Bad mode: \" + mode);\n        }\n        if ((mode & MODE_CREATE) == MODE_CREATE) {\n            set.add(StandardOpenOption.CREATE);\n        }\n        if ((mode & MODE_TRUNCATE) == MODE_TRUNCATE) {\n            set.add(StandardOpenOption.TRUNCATE_EXISTING);\n        }\n        if ((mode & MODE_APPEND) == MODE_APPEND) {\n            set.add(StandardOpenOption.APPEND);\n        }\n        return set;\n    }\n\n    static Flag modeToFlag(int mode) {\n        Flag f = new Flag();\n        if ((mode & MODE_READ_WRITE) == MODE_READ_WRITE) {\n            f.read = true;\n            f.write = true;\n        } else if ((mode & MODE_WRITE_ONLY) == MODE_WRITE_ONLY) {\n            f.write = true;\n        } else if ((mode & MODE_READ_ONLY) == MODE_READ_ONLY) {\n            f.read = true;\n        } else {\n            throw new IllegalArgumentException(\"Bad mode: \" + mode);\n        }\n        if ((mode & MODE_CREATE) == MODE_CREATE) {\n            f.create = true;\n        }\n        if ((mode & MODE_TRUNCATE) == MODE_TRUNCATE) {\n            f.truncate = true;\n        }\n        if ((mode & MODE_APPEND) == MODE_APPEND) {\n            f.append = true;\n        }\n\n        // Validate flags\n        if (f.append && f.read) {\n            throw new IllegalArgumentException(\"READ + APPEND not allowed\");\n        }\n        if (f.append && f.truncate) {\n            throw new IllegalArgumentException(\"APPEND + TRUNCATE not allowed\");\n        }\n\n        return f;\n    }\n\n    @RequiresApi(api = 28)\n    static long splice(\n            FileDescriptor fdIn, Int64Ref offIn,\n            FileDescriptor fdOut, Int64Ref offOut,\n            long len, int flags) throws ErrnoException {\n        try {\n            if (splice == null) {\n                splice = Os.class.getMethod(\"splice\",\n                        FileDescriptor.class, Int64Ref.class,\n                        FileDescriptor.class, Int64Ref.class,\n                        long.class, int.class);\n            }\n            return (long) splice.invoke(null, fdIn, offIn, fdOut, offOut, len, flags);\n        } catch (InvocationTargetException e) {\n            throw (ErrnoException) e.getTargetException();\n        } catch (ReflectiveOperationException e) {\n            throw new ErrnoException(\"splice\", ENOSYS);\n        }\n    }\n\n    @SuppressWarnings(\"deprecation\")\n    @SuppressLint(\"NewApi\")\n    static long sendfile(\n            FileDescriptor outFd, FileDescriptor inFd,\n            MutableLong inOffset, long byteCount) throws ErrnoException {\n        if (Build.VERSION.SDK_INT >= 28) {\n            Int64Ref off = inOffset == null ? null : new Int64Ref(inOffset.value);\n            long result = Os.sendfile(outFd, inFd, off, byteCount);\n            if (off != null)\n                inOffset.value = off.value;\n            return result;\n        } else {\n            try {\n                if (os == null) {\n                    os = Class.forName(\"libcore.io.Libcore\").getField(\"os\").get(null);\n                }\n                if (sendfile == null) {\n                    sendfile = os.getClass().getMethod(\"sendfile\",\n                            FileDescriptor.class, FileDescriptor.class,\n                            MutableLong.class, long.class);\n                }\n                return (long) sendfile.invoke(os, outFd, inFd, inOffset, byteCount);\n            } catch (InvocationTargetException e) {\n                throw (ErrnoException) e.getTargetException();\n            } catch (ReflectiveOperationException e) {\n                throw new ErrnoException(\"sendfile\", ENOSYS);\n            }\n        }\n    }\n\n    @SuppressWarnings(\"OctalInteger\")\n    static File createTempFIFO() throws ErrnoException, IOException {\n        File fifo = File.createTempFile(\"libsu-fifo-\", null);\n        fifo.delete();\n        Os.mkfifo(fifo.getPath(), 0644);\n        return fifo;\n    }\n\n    static FileDescriptor createFileDescriptor(int fd) {\n        if (setFd == null) {\n            try {\n                // Available API 24+\n                setFd = FileDescriptor.class.getDeclaredConstructor(int.class);\n            } catch (NoSuchMethodException e) {\n                // This is actually how the Android framework sets the fd internally\n                try {\n                    setFd = FileDescriptor.class.getDeclaredMethod(\"setInt$\", int.class);\n                } catch (NoSuchMethodException ignored) {}\n            }\n            setFd.setAccessible(true);\n        }\n        try {\n            if (setFd instanceof Constructor) {\n                return (FileDescriptor) ((Constructor<?>) setFd).newInstance(fd);\n            } else {\n                FileDescriptor f = new FileDescriptor();\n                ((Method) setFd).invoke(f, fd);\n                return f;\n            }\n        } catch (ReflectiveOperationException e) {\n            return null;\n        }\n    }\n}"
  },
  {
    "path": "libcore/io/src/main/java/io/github/muntashirakon/io/IOResult.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage io.github.muntashirakon.io;\n\nimport android.os.Parcel;\nimport android.os.Parcelable;\nimport android.os.RemoteException;\nimport android.system.ErrnoException;\n\nimport java.io.IOException;\n\n// Copyright 2023 John \"topjohnwu\" Wu\nclass IOResult implements Parcelable {\n    private static final String REMOTE_ERR_MSG = \"Exception thrown on remote process\";\n    private static final ClassLoader cl = IOResult.class.getClassLoader();\n\n    private final Object val;\n\n    IOResult() {\n        val = null;\n    }\n\n    IOResult(Object v) {\n        val = v;\n    }\n\n    @Override\n    public void writeToParcel(Parcel dest, int flags) {\n        dest.writeValue(val);\n    }\n\n    void checkException() throws IOException {\n        if (val instanceof Throwable) {\n            throw new IOException(REMOTE_ERR_MSG, (Throwable) val);\n        }\n    }\n\n    void checkErrnoException() throws ErrnoException, RemoteException {\n        if (val instanceof ErrnoException) {\n            throw (ErrnoException) val;\n        } else if (val instanceof Throwable) {\n            Throwable th = (Throwable) val;\n            throw (RemoteException) new RemoteException(th.getMessage()).initCause(th);\n        }\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    <T> T tryAndGet() throws IOException {\n        checkException();\n        return (T) val;\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    <T> T tryAndGetErrnoException() throws ErrnoException, RemoteException {\n        checkErrnoException();\n        return (T) val;\n    }\n\n    @Override\n    public int describeContents() {\n        return 0;\n    }\n\n    private IOResult(Parcel in) {\n        val = in.readValue(cl);\n    }\n\n    static final Creator<IOResult> CREATOR = new Creator<IOResult>() {\n        @Override\n        public IOResult createFromParcel(Parcel in) {\n            return new IOResult(in);\n        }\n\n        @Override\n        public IOResult[] newArray(int size) {\n            return new IOResult[size];\n        }\n    };\n}"
  },
  {
    "path": "libcore/io/src/main/java/io/github/muntashirakon/io/IoUtils.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.io;\n\nimport android.os.Build;\nimport android.os.FileUtils;\nimport android.util.Log;\n\nimport androidx.annotation.AnyThread;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport java.io.EOFException;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.nio.charset.Charset;\nimport java.util.Arrays;\nimport java.util.concurrent.Executor;\n\npublic final class IoUtils {\n    public static final String TAG = IoUtils.class.getSimpleName();\n\n    public static final int DEFAULT_BUFFER_SIZE = 1024 * 50;\n\n    /**\n     * Get byte array from an InputStream most efficiently.\n     * Taken from sun.misc.IOUtils\n     *\n     * @param is      InputStream\n     * @param length  Length of the buffer, -1 to read the whole stream\n     * @param readAll Whether to read the whole stream\n     * @return Desired byte array\n     * @throws IOException If maximum capacity exceeded.\n     */\n    @AnyThread\n    public static byte[] readFully(@NonNull InputStream is, int length, boolean readAll)\n            throws IOException {\n        byte[] output = {};\n        if (length == -1) length = Integer.MAX_VALUE;\n        int pos = 0;\n        while (pos < length) {\n            int bytesToRead;\n            if (pos >= output.length) {\n                bytesToRead = Math.min(length - pos, output.length + 1024);\n                if (output.length < pos + bytesToRead) {\n                    output = Arrays.copyOf(output, pos + bytesToRead);\n                }\n            } else {\n                bytesToRead = output.length - pos;\n            }\n            int cc = is.read(output, pos, bytesToRead);\n            if (cc < 0) {\n                if (readAll && length != Integer.MAX_VALUE) {\n                    throw new EOFException(\"Detect premature EOF\");\n                } else {\n                    if (output.length != pos) {\n                        output = Arrays.copyOf(output, pos);\n                    }\n                    break;\n                }\n            }\n            pos += cc;\n        }\n        return output;\n    }\n\n    @AnyThread\n    @NonNull\n    public static String getInputStreamContent(@NonNull InputStream inputStream) throws IOException {\n        return new String(IoUtils.readFully(inputStream, -1, true), Charset.defaultCharset());\n    }\n\n    @AnyThread\n    public static long copy(@NonNull Path from, @NonNull Path to)\n            throws IOException {\n        try (InputStream in = from.openInputStream();\n             OutputStream out = to.openOutputStream()) {\n            return copy(in, out);\n        }\n    }\n\n    /**\n     * Copy the contents of one stream to another.\n     */\n    @AnyThread\n    public static long copy(@NonNull InputStream in, @NonNull OutputStream out) throws IOException {\n        return copy(in, out, null, null);\n    }\n\n    /**\n     * Copy the contents of one stream to another.\n     *\n     * @param executor         that listener events should be delivered via.\n     * @param progressListener to be periodically notified as the copy progresses.\n     */\n    @AnyThread\n    public static long copy(@NonNull InputStream in, @NonNull OutputStream out, @Nullable Executor executor,\n                            @Nullable ProgressListener progressListener) throws IOException {\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {\n            return FileUtils.copy(in, out, null, executor, progress -> {\n                if (progressListener != null) {\n                    progressListener.onProgress(progress);\n                }\n            });\n        } else {\n            return copyLarge(in, out, executor, progressListener);\n        }\n    }\n\n    @AnyThread\n    public static void closeQuietly(@Nullable AutoCloseable closeable) {\n        if (closeable == null) return;\n        try {\n            closeable.close();\n        } catch (Exception e) {\n            Log.w(TAG, String.format(\"Unable to close %s\", closeable.getClass().getCanonicalName()), e);\n        }\n    }\n\n    @AnyThread\n    private static long copyLarge(@NonNull InputStream in, @NonNull OutputStream out, @Nullable Executor executor,\n                                  @Nullable ProgressListener progressListener)\n            throws IOException {\n        byte[] buffer = new byte[DEFAULT_BUFFER_SIZE];\n        long count = 0;\n        long checkpoint = 0;\n        int n;\n        while ((n = in.read(buffer)) > 0) {\n            out.write(buffer, 0, n);\n            count += n;\n            checkpoint += n;\n            if (checkpoint >= (1 << 19)) { // 512 kB\n                if (executor != null && progressListener != null) {\n                    long countSnapshot = count;\n                    executor.execute(() -> progressListener.onProgress(countSnapshot));\n                }\n                checkpoint = 0;\n            }\n        }\n        return count;\n    }\n\n    /**\n     * Listener that is called periodically as progress is made.\n     */\n    public interface ProgressListener {\n        void onProgress(long progress);\n    }\n}\n"
  },
  {
    "path": "libcore/io/src/main/java/io/github/muntashirakon/io/LocalFile.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.io;\n\nimport android.os.SELinux;\nimport android.system.ErrnoException;\nimport android.system.Os;\nimport android.system.OsConstants;\nimport android.system.StructStat;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport java.io.FileInputStream;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\n\nimport io.github.muntashirakon.compat.system.OsCompat;\nimport io.github.muntashirakon.compat.system.StructTimespec;\n\n// Copyright 2022 John \"topjohnwu\" Wu\n// Copyright 2022 Muntashir Al-Islam\nclass LocalFile extends FileImpl<LocalFile> {\n\n    LocalFile(@NonNull String pathname) {\n        super(pathname);\n    }\n\n    LocalFile(@Nullable String parent, @NonNull String child) {\n        super(parent, child);\n    }\n\n    @Override\n    protected LocalFile create(String path) {\n        return new LocalFile(path);\n    }\n\n    @NonNull\n    @Override\n    public LocalFile getChildFile(String name) {\n        return new LocalFile(getPath(), name);\n    }\n\n    @Override\n    protected LocalFile[] createArray(int n) {\n        return new LocalFile[n];\n    }\n\n    @Override\n    public int getMode() throws ErrnoException {\n        return Os.lstat(getPath()).st_mode;\n    }\n\n    @Override\n    public boolean setMode(int mode) throws ErrnoException {\n        Os.chmod(getPath(), mode);\n        return true;\n    }\n\n    @Override\n    public UidGidPair getUidGid() throws ErrnoException {\n        StructStat s = Os.lstat(getPath());\n        return new UidGidPair(s.st_uid, s.st_gid);\n    }\n\n    @Override\n    public boolean setUidGid(int uid, int gid) throws ErrnoException {\n        Os.chown(getPath(), uid, gid);\n        return true;\n    }\n\n    @Override\n    public String getSelinuxContext() {\n        return SELinux.getFileContext(getPath());\n    }\n\n    @Override\n    public boolean restoreSelinuxContext() {\n        return SELinux.restorecon(getPath());\n    }\n\n    @Override\n    public boolean setSelinuxContext(String context) {\n        return SELinux.setFileContext(getPath(), context);\n    }\n\n    @Override\n    public boolean isBlock() {\n        try {\n            return OsConstants.S_ISBLK(getMode());\n        } catch (ErrnoException e) {\n            return false;\n        }\n    }\n\n    @Override\n    public boolean isCharacter() {\n        try {\n            return OsConstants.S_ISCHR(getMode());\n        } catch (ErrnoException e) {\n            return false;\n        }\n    }\n\n    @Override\n    public boolean isSymlink() {\n        try {\n            return OsConstants.S_ISLNK(getMode());\n        } catch (ErrnoException e) {\n            return false;\n        }\n    }\n\n    @Override\n    public boolean isNamedPipe() {\n        try {\n            return OsConstants.S_ISFIFO(getMode());\n        } catch (ErrnoException e) {\n            return false;\n        }\n    }\n\n    @Override\n    public boolean isSocket() {\n        try {\n            return OsConstants.S_ISSOCK(getMode());\n        } catch (ErrnoException e) {\n            return false;\n        }\n    }\n\n    @Override\n    public long creationTime() {\n        try {\n            return Os.lstat(getPath()).st_ctime * 1000;\n        } catch (ErrnoException e) {\n            return 0;\n        }\n    }\n\n    @Override\n    public long lastAccess() {\n        try {\n            return Os.lstat(getPath()).st_atime * 1000;\n        } catch (ErrnoException e) {\n            return 0;\n        }\n    }\n\n    @Override\n    public boolean setLastAccess(long millis) {\n        long seconds_part = millis / 1_000;\n        long nanoseconds_part = (millis % 1_000) * 1_000_000;\n        StructTimespec atime = new StructTimespec(seconds_part, nanoseconds_part);\n        StructTimespec mtime = new StructTimespec(0, OsCompat.UTIME_OMIT);\n        try {\n            OsCompat.utimensat(OsCompat.AT_FDCWD, getPath(), atime, mtime, OsCompat.AT_SYMLINK_NOFOLLOW);\n            return true;\n        } catch (ErrnoException e) {\n            return false;\n        }\n    }\n\n    @NonNull\n    @Override\n    public FileInputStream newInputStream() throws IOException {\n        return new FileInputStream(this);\n    }\n\n    @NonNull\n    @Override\n    public FileOutputStream newOutputStream(boolean append) throws IOException {\n        return new FileOutputStream(this, append);\n    }\n\n    @Override\n    public boolean createNewLink(String existing) throws IOException {\n        return createLink(existing, false);\n    }\n\n    @Override\n    public boolean createNewSymlink(String target) throws IOException {\n        return createLink(target, true);\n    }\n\n    private boolean createLink(String target, boolean soft) throws IOException {\n        try {\n            if (soft)\n                Os.symlink(target, getPath());\n            else\n                Os.link(target, getPath());\n            return true;\n        } catch (ErrnoException e) {\n            if (e.errno != OsConstants.EEXIST) {\n                throw new IOException(e);\n            }\n            return false;\n        }\n    }\n}"
  },
  {
    "path": "libcore/io/src/main/java/io/github/muntashirakon/io/NIOFactory.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.io;\n\nimport android.annotation.SuppressLint;\nimport android.os.Binder;\nimport android.os.Build;\nimport android.os.IBinder;\nimport android.os.RemoteException;\nimport android.system.ErrnoException;\nimport android.system.OsConstants;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.RestrictTo;\n\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileNotFoundException;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\nimport java.io.RandomAccessFile;\nimport java.nio.channels.FileChannel;\nimport java.util.Objects;\n\n// Copyright 2022 John \"topjohnwu\" Wu\n@RestrictTo(RestrictTo.Scope.LIBRARY)\npublic final class NIOFactory {\n\n    private NIOFactory() {}\n\n    public static FileSystemManager createLocal() {\n        return new FileSystemManager() {\n            @NonNull\n            @Override\n            public ExtendedFile getFile(@NonNull String pathname) {\n                return new LocalFile(pathname);\n            }\n\n            @NonNull\n            @Override\n            public ExtendedFile getFile(@Nullable String parent, @NonNull String child) {\n                return new LocalFile(parent, child);\n            }\n\n            @SuppressLint(\"NewApi\")\n            @NonNull\n            @Override\n            public FileChannel openChannel(@NonNull File file, int mode) throws IOException {\n                if (Build.VERSION.SDK_INT >= 26) {\n                    return FileChannel.open(file.toPath(), FileUtils.modeToOptions(mode));\n                } else {\n                    FileUtils.Flag f = FileUtils.modeToFlag(mode);\n                    if (f.write) {\n                        if (!f.create) {\n                            if (!file.exists()) {\n                                ErrnoException e = new ErrnoException(\"open\", OsConstants.ENOENT);\n                                throw new FileNotFoundException(file + \": \" + e.getMessage());\n                            }\n                        }\n                        if (f.append) {\n                            return new FileOutputStream(file, true).getChannel();\n                        }\n                        if (!f.read && f.truncate) {\n                            return new FileOutputStream(file, false).getChannel();\n                        }\n\n                        // Unfortunately, there is no way to create a write-only channel\n                        // without truncating. Forced to open rw RAF in all cases.\n                        FileChannel ch = new RandomAccessFile(file, \"rw\").getChannel();\n                        if (f.truncate) {\n                            ch.truncate(0);\n                        }\n                        return ch;\n                    } else {\n                        return new FileInputStream(file).getChannel();\n                    }\n                }\n            }\n        };\n    }\n\n    public static FileSystemManager createRemote(@NonNull IBinder b) throws RemoteException {\n        Objects.requireNonNull(b);\n        IFileSystemService fs = IFileSystemService.Stub.asInterface(b);\n        if (fs == null) {\n            throw new IllegalArgumentException(\"The IBinder provided is invalid\");\n        }\n\n        fs.register(new Binder());\n        return new FileSystemManager() {\n            @NonNull\n            @Override\n            public ExtendedFile getFile(@NonNull String pathname) {\n                return new RemoteFile(fs, pathname);\n            }\n\n            @NonNull\n            @Override\n            public ExtendedFile getFile(@Nullable String parent, @NonNull String child) {\n                return new RemoteFile(fs, parent, child);\n            }\n\n            @NonNull\n            @Override\n            public FileChannel openChannel(@NonNull File file, int mode) throws IOException {\n                return new RemoteFileChannel(fs, file, mode);\n            }\n        };\n    }\n\n    public static FileSystemService createFsService() {\n        return new FileSystemService();\n    }\n}"
  },
  {
    "path": "libcore/io/src/main/java/io/github/muntashirakon/io/OpenFile.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage io.github.muntashirakon.io;\n\nimport static android.system.OsConstants.SEEK_CUR;\nimport static android.system.OsConstants.SEEK_END;\nimport static android.system.OsConstants.SEEK_SET;\n\nimport android.annotation.SuppressLint;\nimport android.os.Build;\nimport android.system.ErrnoException;\nimport android.system.Int64Ref;\nimport android.system.Os;\nimport android.system.OsConstants;\nimport android.system.StructStat;\nimport android.util.MutableLong;\n\nimport java.io.Closeable;\nimport java.io.FileDescriptor;\nimport java.io.IOException;\nimport java.nio.ByteBuffer;\nimport java.nio.channels.ClosedChannelException;\n\n// Copyright 2022 John \"topjohnwu\" Wu\nclass OpenFile implements Closeable {\n    // This is only for testing purpose\n    private static final boolean FORCE_NO_SPLICE = false;\n\n    FileDescriptor fd;\n    FileDescriptor read;\n    FileDescriptor write;\n\n    private ByteBuffer buf;\n    private StructStat st;\n\n    private ByteBuffer getBuf() {\n        if (buf == null)\n            buf = ByteBuffer.allocateDirect(FileSystemService.PIPE_CAPACITY);\n        buf.clear();\n        return buf;\n    }\n\n    private StructStat getStat() throws ErrnoException {\n        if (st == null)\n            st = Os.fstat(fd);\n        return st;\n    }\n\n    private void ensureOpen() throws ClosedChannelException {\n        if (fd == null)\n            throw new ClosedChannelException();\n    }\n\n    @Override\n    synchronized public void close() {\n        if (fd != null) {\n            try {\n                Os.close(fd);\n            } catch (ErrnoException ignored) {\n            }\n            fd = null;\n        }\n        if (read != null) {\n            try {\n                Os.close(read);\n            } catch (ErrnoException ignored) {\n            }\n            read = null;\n        }\n        if (write != null) {\n            try {\n                Os.close(write);\n            } catch (ErrnoException ignored) {\n            }\n            write = null;\n        }\n    }\n\n    synchronized long lseek(long offset, int whence) throws ErrnoException, IOException {\n        ensureOpen();\n        return Os.lseek(fd, offset, whence);\n    }\n\n    synchronized long size() throws ErrnoException, IOException {\n        ensureOpen();\n        long cur = Os.lseek(fd, 0, SEEK_CUR);\n        Os.lseek(fd, 0, SEEK_END);\n        long sz = Os.lseek(fd, 0, SEEK_CUR);\n        Os.lseek(fd, cur, SEEK_SET);\n        return sz;\n    }\n\n    synchronized void ftruncate(long length) throws ErrnoException, IOException {\n        ensureOpen();\n        Os.ftruncate(fd, length);\n    }\n\n    synchronized void sync(boolean metadata) throws ErrnoException, IOException {\n        ensureOpen();\n        if (metadata)\n            Os.fsync(fd);\n        else\n            Os.fdatasync(fd);\n    }\n\n    @SuppressLint(\"NewApi\")\n    synchronized int pread(int len, long offset) throws ErrnoException, IOException {\n        if (fd == null || write == null)\n            throw new ClosedChannelException();\n        final long result;\n        if (!FORCE_NO_SPLICE && Build.VERSION.SDK_INT >= 28) {\n            Int64Ref inOff = offset < 0 ? null : new Int64Ref(offset);\n            result = FileUtils.splice(fd, inOff, write, null, len, 0);\n        } else {\n            StructStat st = getStat();\n            if (OsConstants.S_ISREG(st.st_mode) || OsConstants.S_ISBLK(st.st_mode)) {\n                // sendfile only supports reading from mmap-able files\n                MutableLong inOff = offset < 0 ? null : new MutableLong(offset);\n                result = FileUtils.sendfile(write, fd, inOff, len);\n            } else {\n                // Fallback to copy into internal buffer\n                ByteBuffer buf = getBuf();\n                buf.limit(Math.min(len, buf.capacity()));\n                if (offset < 0) {\n                    Os.read(fd, buf);\n                } else {\n                    Os.pread(fd, buf, offset);\n                }\n                buf.flip();\n                result = buf.remaining();\n                // Need to write all bytes\n                for (int sz = (int) result; sz > 0; ) {\n                    sz -= Os.write(write, buf);\n                }\n            }\n        }\n        return (int) result;\n    }\n\n    @SuppressLint(\"NewApi\")\n    synchronized int pwrite(int len, long offset, boolean exact) throws ErrnoException, IOException {\n        if (fd == null || read == null)\n            throw new ClosedChannelException();\n        if (!FORCE_NO_SPLICE && Build.VERSION.SDK_INT >= 28) {\n            Int64Ref outOff = offset < 0 ? null : new Int64Ref(offset);\n            if (exact) {\n                int sz = len;\n                while (sz > 0) {\n                    sz -= FileUtils.splice(read, null, fd, outOff, sz, 0);\n                }\n                return len;\n            } else {\n                return (int) FileUtils.splice(read, null, fd, outOff, len, 0);\n            }\n        } else {\n            // Unfortunately, sendfile does not allow reading from pipes.\n            // Manually read into an internal buffer then write to output.\n            ByteBuffer buf = getBuf();\n            int sz = 0;\n            buf.limit(len);\n            if (exact) {\n                while (len > sz) {\n                    sz += Os.read(read, buf);\n                }\n            } else {\n                sz = Os.read(read, buf);\n            }\n            len = sz;\n            buf.flip();\n            while (sz > 0) {\n                if (offset < 0) {\n                    sz -= Os.write(fd, buf);\n                } else {\n                    int w = Os.pwrite(fd, buf, offset);\n                    sz -= w;\n                    offset += w;\n                }\n            }\n            return len;\n        }\n    }\n}"
  },
  {
    "path": "libcore/io/src/main/java/io/github/muntashirakon/io/Path.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.io;\n\nimport android.content.Context;\nimport android.net.Uri;\nimport android.os.Handler;\nimport android.os.ParcelFileDescriptor;\nimport android.system.ErrnoException;\n\nimport androidx.annotation.CheckResult;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.documentfile.provider.DocumentFile;\n\nimport org.jetbrains.annotations.Contract;\n\nimport java.io.File;\nimport java.io.FileNotFoundException;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.nio.channels.FileChannel;\nimport java.nio.charset.Charset;\nimport java.util.ArrayList;\nimport java.util.Locale;\nimport java.util.Objects;\n\n/**\n * Provide an interface to {@link File} and {@link DocumentFile} with basic functionalities.\n */\npublic abstract class Path implements Comparable<Path> {\n    @NonNull\n    protected final Context context;\n    @NonNull\n    protected DocumentFile documentFile;\n\n    protected Path(@NonNull Context context, @NonNull DocumentFile documentFile) {\n        this.context = context;\n        this.documentFile = documentFile;\n    }\n\n    /**\n     * Return the last segment of this path.\n     */\n    @NonNull\n    public abstract String getName();\n\n    @Nullable\n    public String getExtension() {\n        String name = getName();\n        int lastIndexOfDot = name.lastIndexOf('.');\n        if (lastIndexOfDot == -1 || lastIndexOfDot + 1 == name.length()) {\n            return null;\n        }\n        return name.substring(lastIndexOfDot + 1).toLowerCase(Locale.ROOT);\n    }\n\n    /**\n     * Return a URI for the underlying document represented by this file. This\n     * can be used with other platform APIs to manipulate or share the\n     * underlying content. {@link DocumentFile#isDocumentUri(Context, Uri)} can\n     * be used to test if the returned Uri is backed by an\n     * {@link android.provider.DocumentsProvider}.\n     */\n    @NonNull\n    public Uri getUri() {\n        return documentFile.getUri();\n    }\n\n    /**\n     * Return the underlying {@link ExtendedFile} if the path is backed by a real file,\n     * {@code null} otherwise.\n     */\n    @Nullable\n    public abstract ExtendedFile getFile();\n\n    /**\n     * Same as {@link #getFile()} except it return a raw string.\n     */\n    @Nullable\n    public abstract String getFilePath();\n\n    /**\n     * Same as {@link #getFile()} except it returns the real path if the\n     * current path is a symbolic link.\n     */\n    @Nullable\n    public abstract String getRealFilePath() throws IOException;\n\n    /**\n     * Same as {@link #getFile()} except it returns the real path if the\n     * current path is a symbolic link.\n     */\n    @Nullable\n    public abstract Path getRealPath() throws IOException;\n\n    /**\n     * Return the MIME type of the path\n     */\n    @NonNull\n    public abstract String getType();\n\n    /**\n     * Return the content info of the path.\n     * <p>\n     * This is an expensive operation and should be done in a non-UI thread.\n     */\n    @NonNull\n    public abstract PathContentInfo getPathContentInfo();\n\n    /**\n     * Returns the length of this path in bytes. Returns 0 if the path does not\n     * exist, or if the length is unknown. The result for a directory is not\n     * defined.\n     */\n    @CheckResult\n    public abstract long length();\n\n    /**\n     * Recreate this path if required.\n     * <p>\n     * This only recreates files and not directories in order to avoid potential mass destructive operation.\n     *\n     * @return {@code true} iff the path has been recreated.\n     */\n    @CheckResult\n    public abstract boolean recreate();\n\n    /**\n     * Create a new file as a direct child of this directory. If the file\n     * already exists, and it is not a directory, it will try to delete it\n     * and create a new one.\n     *\n     * @param displayName Display name for the file with or without extension.\n     *                    The name must not contain any file separator.\n     * @param mimeType    Mime type for the new file. Underlying provider may\n     *                    choose to add extension based on the mime type. If\n     *                    displayName contains an extension, set it to null.\n     * @return The newly created file.\n     * @throws IOException              If the target is a mount point, a directory, or the current file is not a\n     *                                  directory, or failed for any other reason.\n     * @throws IllegalArgumentException If the display name contains file separator.\n     */\n    @NonNull\n    public abstract Path createNewFile(@NonNull String displayName, @Nullable String mimeType) throws IOException;\n\n    /**\n     * Create a new directory as a direct child of this directory.\n     *\n     * @param displayName Display name for the directory. The name must not\n     *                    contain any file separator.\n     * @return The newly created directory.\n     * @throws IOException              If the target is a mount point or the current file is not a directory,\n     *                                  or failed for any other reason.\n     * @throws IllegalArgumentException If the display name contains file separator.\n     */\n    @NonNull\n    public abstract Path createNewDirectory(@NonNull String displayName) throws IOException;\n\n    /**\n     * Create a new file at some arbitrary level under this directory,\n     * non-existing paths are created if necessary. If the file already exists,\n     * and it isn't a directory, it will try to delete it and create a new one.\n     * If mount points encountered while iterating through the paths, it will\n     * try to create a new file under the last mount point.\n     *\n     * @param displayName Display name for the file with or without extension\n     *                    and/or file separator.\n     * @param mimeType    Mime type for the new file. Underlying provider may\n     *                    choose to add extension based on the mime type. If\n     *                    displayName contains an extension, set it to null.\n     * @return The newly created file.\n     * @throws IOException              If the target is a mount point, a directory or failed for any other reason.\n     * @throws IllegalArgumentException If the display name is malformed.\n     */\n    @NonNull\n    public abstract Path createNewArbitraryFile(@NonNull String displayName, @Nullable String mimeType) throws IOException;\n\n\n    /**\n     * Create all the non-existing directories under this directory. If mount\n     * points encountered while iterating through the paths, it will try to\n     * create a new directory under the last mount point.\n     *\n     * @param displayName Relative path to the target directory.\n     * @return The newly created directory.\n     * @throws IOException If the target is a mount point, or failed for any other reason.\n     */\n    @NonNull\n    public abstract Path createDirectoriesIfRequired(@NonNull String displayName) throws IOException;\n\n    /**\n     * Create all the non-existing directories under this directory. If mount\n     * points encountered while iterating through the paths, it will try to\n     * create a new directory under the last mount point.\n     *\n     * @param displayName Relative path to the target directory.\n     * @return The newly created directory.\n     * @throws IOException If the target exists, or it is a mount point, or failed for any other reason.\n     */\n    @NonNull\n    public abstract Path createDirectories(@NonNull String displayName) throws IOException;\n\n    /**\n     * Delete this file. If this is a directory, it is deleted recursively.\n     *\n     * @return {@code true} if the file was deleted, {@code false} if the file\n     * is a mount point or any other error occurred.\n     */\n    public boolean delete() {\n        if (isMountPoint()) {\n            return false;\n        }\n        return documentFile.delete();\n    }\n\n    /**\n     * Return the parent file of this document. If this is a mount point,\n     * the parent is the parent of the mount point. For tree-documents,\n     * the consistency of the parent file isn't guaranteed as the underlying\n     * directory tree might be altered by another application.\n     */\n    @Nullable\n    public abstract Path getParent();\n\n    /**\n     * Return the parent file of this document. If this is a mount point,\n     * the parent is the parent of the mount point. For tree-documents,\n     * the consistency of the parent file isn't guaranteed as the underlying\n     * directory tree might be altered by another application.\n     */\n    @NonNull\n    public Path requireParent() {\n        return Objects.requireNonNull(getParent());\n    }\n\n    /**\n     * Whether this file has a file denoted by this abstract name. The file\n     * isn't necessarily have to be a direct child of this file.\n     *\n     * @param displayName Display name for the file with extension and/or\n     *                    file separator if applicable.\n     * @return {@code true} if the file denoted by this abstract name exists.\n     */\n    public abstract boolean hasFile(@NonNull String displayName);\n\n    /**\n     * Return the file denoted by this abstract name in this file. File name\n     * can be either case-sensitive or case-insensitive depending on the file\n     * provider.\n     *\n     * @param displayName Display name for the file with extension and/or\n     *                    file separator if applicable.\n     * @return The first file that matches the name.\n     * @throws FileNotFoundException If the file was not found.\n     */\n    @NonNull\n    public abstract Path findFile(@NonNull String displayName) throws FileNotFoundException;\n\n    /**\n     * Return the file denoted by this abstract name in this file. File name\n     * can be either case-sensitive or case-insensitive depending on the file\n     * provider.\n     *\n     * @param displayName Display name for the file with extension and/or\n     *                    file separator if applicable.\n     * @return The first file that matches the name, {@code null} otherwise.\n     */\n    @Nullable\n    public Path findFileOrNull(@NonNull String displayName) {\n        try {\n            return findFile(displayName);\n        } catch (FileNotFoundException ignore) {\n            return null;\n        }\n    }\n\n    /**\n     * Return a file that is a direct child of this directory, creating if necessary.\n     *\n     * @param displayName Display name for the file with or without extension.\n     *                    The name must not contain any file separator.\n     * @param mimeType    Mime type for the new file. Underlying provider may\n     *                    choose to add extension based on the mime type. If\n     *                    displayName contains an extension, set it to null.\n     * @return The existing or newly created file.\n     * @throws IOException              If the target is a mount point, a directory, or the current file is not a\n     *                                  directory, or failed for any other reason.\n     * @throws IllegalArgumentException If the display name contains file separator.\n     */\n    @NonNull\n    public abstract Path findOrCreateFile(@NonNull String displayName, @Nullable String mimeType) throws IOException;\n\n    /**\n     * Return a directory that is a direct child of this directory, creating\n     * if necessary.\n     *\n     * @param displayName Display name for the directory. The name must not\n     *                    contain any file separator.\n     * @return The existing or newly created directory or mount point.\n     * @throws IOException              If the target directory could not be created, or the existing or the\n     *                                  current file is not a directory.\n     * @throws IllegalArgumentException If the display name contains file separator.\n     */\n    @NonNull\n    public abstract Path findOrCreateDirectory(@NonNull String displayName) throws IOException;\n\n    @NonNull\n    public abstract PathAttributes getAttributes() throws IOException;\n\n    /**\n     * Whether this file can be found. This is useful only for the paths\n     * accessed using Java File API. In other cases, the file has to exist\n     * before it can be accessed. However, in SAF, the file can be deleted\n     * by another application in which case the URI becomes non-existent.\n     *\n     * @return {@code true} if the file exists.\n     */\n    @CheckResult\n    public abstract boolean exists();\n\n    /**\n     * Whether this file is a directory. A mount point is also considered as a\n     * directory.\n     * <p>\n     * Note that the return value {@code false} does not necessarily mean that\n     * the path is a file.\n     *\n     * @return {@code true} if the file is a directory or a mount point.\n     */\n    @CheckResult\n    public abstract boolean isDirectory();\n\n    /**\n     * Whether this file is a file.\n     * <p>\n     * Note that the return value {@code false} does not necessarily mean that\n     * the path is a directory.\n     *\n     * @return {@code true} if the file is a file.\n     */\n    @CheckResult\n    public abstract boolean isFile();\n\n    /**\n     * Whether the file is a virtual file i.e. it has no physical existence.\n     *\n     * @return {@code true} if this is a virtual file.\n     */\n    @CheckResult\n    public abstract boolean isVirtual();\n\n    /**\n     * Whether the file is a symbolic link, only applicable for Java File API.\n     *\n     * @return {@code true} iff the file is accessed using Java File API and\n     * is a symbolic link.\n     */\n    @CheckResult\n    public abstract boolean isSymbolicLink();\n\n    /**\n     * Creates a new symbolic link named by this abstract pathname to a target file if and only if the pathname is a\n     * physical file and is not yet exist.\n     *\n     * @param target the target of the symbolic link.\n     * @return {@code true} if target did not exist and the link was successfully created, and {@code false} otherwise.\n     */\n    public abstract boolean createNewSymbolicLink(String target);\n\n    /**\n     * Whether the file can be read.\n     *\n     * @return {@code true} if it can be read.\n     */\n    public abstract boolean canRead();\n\n    /**\n     * Whether the file can be written.\n     *\n     * @return {@code true} if it can be written.\n     */\n    public abstract boolean canWrite();\n\n    /**\n     * Whether the file can be executed.\n     *\n     * @return {@code true} if it can be executed.\n     */\n    public abstract boolean canExecute();\n\n    public abstract int getMode();\n\n    public abstract boolean setMode(int mode);\n\n    @Nullable\n    public abstract UidGidPair getUidGid();\n\n    public abstract boolean setUidGid(UidGidPair uidGidPair);\n\n    @Nullable\n    public abstract String getSelinuxContext();\n\n    public abstract boolean setSelinuxContext(@Nullable String context);\n\n    /**\n     * Whether the file is a mount point, thereby, is being overridden by another file system.\n     *\n     * @return {@code true} if this is a mount point.\n     */\n    public abstract boolean isMountPoint();\n\n    public abstract boolean mkdir();\n\n    public abstract boolean mkdirs();\n\n    /**\n     * Renames this file to {@code displayName}, both containing in the same directory.\n     * <p>\n     * Note that this method does <i>not</i> throw {@code IOException} on\n     * failure. Callers must check the return value.\n     * <p>\n     * Some providers may need to create a new document to reflect the rename,\n     * potentially with a different MIME type, so {@link #getUri()} and\n     * {@link #getType()} may change to reflect the rename.\n     * <p>\n     * When renaming a directory, children previously enumerated through\n     * {@link #listFiles()} may no longer be valid.\n     *\n     * @param displayName the new display name.\n     * @return {@code true} on success. It returns {@code false} if the displayName is invalid or if it already exists.\n     * @throws UnsupportedOperationException when working with a single document\n     */\n    public abstract boolean renameTo(@NonNull String displayName);\n\n    /**\n     * Same as {@link #moveTo(Path, boolean)} with override enabled\n     */\n    public boolean moveTo(@NonNull Path dest) {\n        return moveTo(dest, true);\n    }\n\n    /**\n     * Move the given path based on the following criteria:\n     * <ol>\n     *     <li>If both paths are physical (i.e. uses File API), use normal move behaviour\n     *     <li>If one of the paths is virtual or the above fails, use special copy and delete operation\n     * </ol>\n     * <p>\n     * Move behavior is as follows:\n     * <ul>\n     *     <li>If both are directories, move {@code this} inside {@code path}\n     *     <li>If both are files, move {@code this} to {@code path} overriding it\n     *     <li>If {@code this} is a file and {@code path} is a directory, move the file inside the directory\n     *     <li>If {@code path} does not exist, it is created based on {@code this}.\n     * </ul>\n     *\n     * @param path     Target file/directory which may or may not exist\n     * @param override Whether to override the files in the destination\n     * @return {@code true} on success and {@code false} on failure\n     */\n    public abstract boolean moveTo(@NonNull Path path, boolean override);\n\n\n    @Nullable\n    public Path copyTo(@NonNull Path path) {\n        return copyTo(path, true);\n    }\n\n    @Nullable\n    public abstract Path copyTo(@NonNull Path path, boolean override);\n\n    public abstract long lastModified();\n\n    public abstract boolean setLastModified(long time);\n\n    public abstract long lastAccess();\n\n    public abstract boolean setLastAccess(long millis);\n\n    public abstract long creationTime();\n\n    @NonNull\n    public abstract Path[] listFiles();\n\n    @NonNull\n    public Path[] listFiles(@Nullable FileFilter filter) {\n        Path[] ss = listFiles();\n        ArrayList<Path> files = new ArrayList<>();\n        for (Path s : ss) {\n            if ((filter == null) || filter.accept(s)) {\n                files.add(s);\n            }\n        }\n        return files.toArray(new Path[0]);\n    }\n\n    @NonNull\n    public Path[] listFiles(@Nullable FilenameFilter filter) {\n        Path[] ss = listFiles();\n        ArrayList<Path> files = new ArrayList<>();\n        for (Path s : ss) {\n            if (filter == null || filter.accept(this, s.getName())) {\n                files.add(s);\n            }\n        }\n        return files.toArray(new Path[0]);\n    }\n\n    @NonNull\n    public String[] listFileNames() {\n        Path[] ss = listFiles();\n        ArrayList<String> files = new ArrayList<>();\n        for (Path s : ss) {\n            files.add(s.getName());\n        }\n        return files.toArray(new String[0]);\n    }\n\n    @NonNull\n    public String[] listFileNames(@Nullable FileFilter filter) {\n        Path[] ss = listFiles();\n        ArrayList<String> files = new ArrayList<>();\n        for (Path s : ss) {\n            if (filter == null || filter.accept(s)) {\n                files.add(s.getName());\n            }\n        }\n        return files.toArray(new String[0]);\n    }\n\n    @NonNull\n    public String[] listFileNames(@Nullable FilenameFilter filter) {\n        Path[] ss = listFiles();\n        ArrayList<String> files = new ArrayList<>();\n        for (Path s : ss) {\n            String name = s.getName();\n            if (filter == null || filter.accept(this, name)) {\n                files.add(name);\n            }\n        }\n        return files.toArray(new String[0]);\n    }\n\n    @NonNull\n    public abstract ParcelFileDescriptor openFileDescriptor(@NonNull String mode, @NonNull Handler callbackHandler)\n            throws FileNotFoundException;\n\n    public OutputStream openOutputStream() throws IOException {\n        return openOutputStream(false);\n    }\n\n    @NonNull\n    public abstract OutputStream openOutputStream(boolean append) throws IOException;\n\n    @NonNull\n    public abstract InputStream openInputStream() throws IOException;\n\n    public abstract FileChannel openFileChannel(int mode) throws IOException;\n\n    @NonNull\n    public byte[] getContentAsBinary() {\n        return getContentAsBinary(new byte[0]);\n    }\n\n    @Nullable\n    @Contract(\"!null -> !null\")\n    public byte[] getContentAsBinary(byte[] emptyValue) {\n        try (InputStream inputStream = openInputStream()) {\n            return IoUtils.readFully(inputStream, -1, true);\n        } catch (IOException e) {\n            if (!(e.getCause() instanceof ErrnoException)) {\n                // This isn't just another EACCESS exception\n                e.printStackTrace();\n            }\n        }\n        return emptyValue;\n    }\n\n    @NonNull\n    public String getContentAsString() {\n        return getContentAsString(\"\");\n    }\n\n    @Nullable\n    @Contract(\"!null -> !null\")\n    public String getContentAsString(@Nullable String emptyValue) {\n        return getContentAsString(emptyValue, Charset.defaultCharset());\n    }\n\n\n    @Nullable\n    @Contract(\"!null,_ -> !null\")\n    public String getContentAsString(@Nullable String emptyValue, @NonNull Charset charset) {\n        try (InputStream inputStream = openInputStream()) {\n            return new String(IoUtils.readFully(inputStream, -1, true), charset);\n        } catch (Exception e) {\n            e.printStackTrace();\n            return emptyValue;\n        }\n    }\n\n    @NonNull\n    @Override\n    public String toString() {\n        return getUri().toString();\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) return true;\n        if (!(o instanceof Path)) return false;\n        Path path = (Path) o;\n        return documentFile.getUri().equals(path.documentFile.getUri());\n    }\n\n    @Override\n    public int hashCode() {\n        return documentFile.getUri().hashCode();\n    }\n\n    @Override\n    public int compareTo(@NonNull Path o) {\n        return documentFile.getUri().compareTo(o.documentFile.getUri());\n    }\n\n    @FunctionalInterface\n    public interface FilenameFilter {\n        /**\n         * Tests if a specified file should be included in a file list.\n         *\n         * @param dir  the directory in which the file was found.\n         * @param name the name of the file.\n         * @return <code>true</code> if and only if the name should be\n         * included in the file list; <code>false</code> otherwise.\n         */\n        boolean accept(Path dir, String name);\n    }\n\n    @FunctionalInterface\n    public interface FileFilter {\n\n        /**\n         * Tests whether or not the specified abstract pathname should be\n         * included in a pathname list.\n         *\n         * @param pathname The abstract pathname to be tested\n         * @return <code>true</code> if and only if <code>pathname</code>\n         * should be included\n         */\n        boolean accept(Path pathname);\n    }\n}\n"
  },
  {
    "path": "libcore/io/src/main/java/io/github/muntashirakon/io/PathAttributes.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.io;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\npublic class PathAttributes {\n    @NonNull\n    public final String name;\n    @Nullable\n    public final String mimeType;\n    public final long lastModified;\n    public final long lastAccess;\n    public final long creationTime;\n    public final boolean isRegularFile;\n    public final boolean isDirectory;\n    public final boolean isSymbolicLink;\n    public final boolean isOtherFile;\n    public final long size;\n\n    protected PathAttributes(@NonNull String displayName, @Nullable String mimeType, long lastModified, long lastAccess,\n                             long creationTime, boolean isRegularFile, boolean isDirectory, boolean isSymbolicLink,\n                             long size) {\n        this.name = displayName;\n        this.mimeType = mimeType;\n        this.lastModified = lastModified;\n        this.lastAccess = lastAccess;\n        this.creationTime = creationTime;\n        this.isRegularFile = isRegularFile;\n        this.isDirectory = isDirectory;\n        this.isSymbolicLink = isSymbolicLink;\n        this.isOtherFile = !isRegularFile && !isDirectory && !isSymbolicLink;\n        this.size = size;\n    }\n}\n"
  },
  {
    "path": "libcore/io/src/main/java/io/github/muntashirakon/io/PathContentInfo.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.io;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\npublic abstract class PathContentInfo {\n    public static final String TAG = PathContentInfo.class.getSimpleName();\n\n    @NonNull\n    private final String mName;\n    @Nullable\n    private final String mMessage;\n    @Nullable\n    private final String mMimeType;\n    @Nullable\n    private final String[] mFileExtensions;\n    private final boolean mPartial;\n\n    protected PathContentInfo(@NonNull String name, @Nullable String message, @Nullable String mimeType,\n                              @Nullable String[] fileExtensions, boolean partial) {\n        mName = name;\n        mMessage = message;\n        mMimeType = mimeType;\n        mFileExtensions = fileExtensions;\n        mPartial = partial;\n    }\n\n    /**\n     * Returns the short name of the content either from the content-type or extracted from the message. If the\n     * content-type is known then this is a specific name string. Otherwise, this is usually the first word of the\n     * message generated by the magic file.\n     */\n    @NonNull\n    public String getName() {\n        return mName;\n    }\n\n    /**\n     * Returns the mime-type or null if none.\n     */\n    @Nullable\n    public String getMimeType() {\n        return mMimeType;\n    }\n\n    /**\n     * Returns the full message as generated by the magic matching code or null if none. This should be similar to the\n     * output from the Unix file(1) command.\n     */\n    @Nullable\n    public String getMessage() {\n        return mMessage;\n    }\n\n    /**\n     * Returns an array of associated file-extensions or null if none.\n     */\n    @Nullable\n    public String[] getFileExtensions() {\n        return mFileExtensions;\n    }\n\n    /**\n     * Whether this was a partial match. For some types, there is a main matching pattern and then more\n     * specific patterns which detect additional features of the type. A partial match means that none of the more\n     * specific patterns fully matched the content. It's probably still of the type but just not a variant that the\n     * entries from the magic file(s) know about.\n     */\n    public boolean isPartial() {\n        return mPartial;\n    }\n}\n"
  },
  {
    "path": "libcore/io/src/main/java/io/github/muntashirakon/io/PathReader.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.io;\n\nimport androidx.annotation.NonNull;\n\nimport java.io.FileNotFoundException;\nimport java.io.IOException;\nimport java.io.InputStreamReader;\n\npublic class PathReader extends InputStreamReader {\n    /**\n     * Creates a new {@link PathReader}, given the <tt>Path</tt>\n     * to read from.\n     *\n     * @param file the <tt>Path</tt> to read from\n     * @throws FileNotFoundException if the file does not exist,\n     *                               is a directory rather than a regular file,\n     *                               or for some other reason cannot be opened for\n     *                               reading.\n     */\n    public PathReader(@NonNull Path file) throws IOException {\n        super(file.openInputStream());\n    }\n}\n"
  },
  {
    "path": "libcore/io/src/main/java/io/github/muntashirakon/io/PathWriter.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.io;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.WorkerThread;\n\nimport java.io.IOException;\nimport java.io.OutputStreamWriter;\n\npublic class PathWriter extends OutputStreamWriter {\n    /**\n     * Constructs a ProxyFileWriter object given a File object.\n     *\n     * @param file a Path object to write to.\n     * @throws IOException if the file exists but is a directory rather than\n     *                     a regular file, does not exist but cannot be created,\n     *                     or cannot be opened for any other reason\n     */\n    @WorkerThread\n    public PathWriter(@NonNull Path file) throws IOException {\n        super(file.openOutputStream());\n    }\n}\n"
  },
  {
    "path": "libcore/io/src/main/java/io/github/muntashirakon/io/RemoteFile.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.io;\n\nimport android.os.ParcelFileDescriptor;\nimport android.os.RemoteException;\nimport android.system.ErrnoException;\nimport android.system.OsConstants;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.FileOutputStream;\nimport java.io.IOException;\n\nimport aosp.android.content.pm.StringParceledListSlice;\n\n// Copyright 2022 John \"topjohnwu\" Wu\n// Copyright 2022 Muntashir Al-Islam\nclass RemoteFile extends FileImpl<RemoteFile> {\n\n    private final IFileSystemService fs;\n\n    RemoteFile(IFileSystemService f, String path) {\n        super(path);\n        fs = f;\n    }\n\n    RemoteFile(IFileSystemService f, String parent, String child) {\n        super(parent, child);\n        fs = f;\n    }\n\n    @Override\n    protected RemoteFile create(String path) {\n        return new RemoteFile(fs, path);\n    }\n\n    @NonNull\n    @Override\n    public RemoteFile getChildFile(String name) {\n        return new RemoteFile(fs, getPath(), name);\n    }\n\n    @Override\n    protected RemoteFile[] createArray(int n) {\n        return new RemoteFile[n];\n    }\n\n    @Override\n    @NonNull\n    public String getCanonicalPath() throws IOException {\n        try {\n            return fs.getCanonicalPath(getPath()).tryAndGet();\n        } catch (RemoteException e) {\n            throw new IOException(e);\n        }\n    }\n\n    private boolean checkAccess(int access) {\n        try {\n            return fs.checkAccess(getPath(), access);\n        } catch (RemoteException e) {\n            return false;\n        }\n    }\n\n    @Override\n    public boolean canRead() {\n        return checkAccess(OsConstants.R_OK);\n    }\n\n    @Override\n    public boolean canWrite() {\n        return checkAccess(OsConstants.W_OK);\n    }\n\n    @Override\n    public boolean canExecute() {\n        return checkAccess(OsConstants.X_OK);\n    }\n\n    @Override\n    public boolean exists() {\n        return checkAccess(OsConstants.F_OK);\n    }\n\n    @Override\n    public boolean isDirectory() {\n        try {\n            return fs.isDirectory(getPath());\n        } catch (RemoteException e) {\n            return false;\n        }\n    }\n\n    @Override\n    public boolean isFile() {\n        try {\n            return fs.isFile(getPath());\n        } catch (RemoteException e) {\n            return false;\n        }\n    }\n\n    @Override\n    public int getMode() throws ErrnoException {\n        try {\n            return fs.getMode(getPath()).tryAndGetErrnoException();\n        } catch (RemoteException e) {\n            return 0;\n        }\n    }\n\n    @Override\n    public boolean setMode(int mode) throws ErrnoException {\n        try {\n            fs.setMode(getPath(), mode).checkErrnoException();\n            return true;\n        } catch (RemoteException e) {\n            return false;\n        }\n    }\n\n    @Override\n    public UidGidPair getUidGid() throws ErrnoException {\n        try {\n            return fs.getUidGid(getPath()).tryAndGetErrnoException();\n        } catch (RemoteException e) {\n            return new UidGidPair(0, 0);\n        }\n    }\n\n    @Override\n    public boolean setUidGid(int uid, int gid) throws ErrnoException {\n        try {\n            fs.setUidGid(getPath(), uid, gid).checkErrnoException();\n            return true;\n        } catch (RemoteException e) {\n            return false;\n        }\n    }\n\n    @Nullable\n    @Override\n    public String getSelinuxContext() {\n        try {\n            return fs.getSelinuxContext(getPath());\n        } catch (RemoteException e) {\n            return null;\n        }\n    }\n\n    @Override\n    public boolean restoreSelinuxContext() {\n        try {\n            return fs.restoreSelinuxContext(getPath());\n        } catch (RemoteException e) {\n            return false;\n        }\n    }\n\n    @Override\n    public boolean setSelinuxContext(@NonNull String context) {\n        try {\n            return fs.setSelinuxContext(getPath(), context);\n        } catch (RemoteException e) {\n            return false;\n        }\n    }\n\n    @Override\n    public boolean isBlock() {\n        try {\n            return OsConstants.S_ISBLK(getMode());\n        } catch (ErrnoException e) {\n            return false;\n        }\n    }\n\n    @Override\n    public boolean isCharacter() {\n        try {\n            return OsConstants.S_ISCHR(getMode());\n        } catch (ErrnoException e) {\n            return false;\n        }\n    }\n\n    @Override\n    public boolean isSymlink() {\n        try {\n            return OsConstants.S_ISLNK(getMode());\n        } catch (ErrnoException e) {\n            return false;\n        }\n    }\n\n    @Override\n    public boolean isNamedPipe() {\n        try {\n            return OsConstants.S_ISFIFO(getMode());\n        } catch (ErrnoException e) {\n            return false;\n        }\n    }\n\n    @Override\n    public boolean isSocket() {\n        try {\n            return OsConstants.S_ISSOCK(getMode());\n        } catch (ErrnoException e) {\n            return false;\n        }\n    }\n\n    @Override\n    public boolean isHidden() {\n        try {\n            return fs.isHidden(getPath());\n        } catch (RemoteException e) {\n            return false;\n        }\n    }\n\n    @Override\n    public long lastModified() {\n        try {\n            return fs.lastModified(getPath());\n        } catch (RemoteException e) {\n            return Long.MIN_VALUE;\n        }\n    }\n\n    @Override\n    public long creationTime() {\n        try {\n            return fs.creationTime(getPath()).tryAndGetErrnoException();\n        } catch (RemoteException | ErrnoException e) {\n            return 0;\n        }\n    }\n\n    @Override\n    public long lastAccess() {\n        try {\n            return fs.lastAccess(getPath()).tryAndGetErrnoException();\n        } catch (RemoteException | ErrnoException e) {\n            return 0;\n        }\n    }\n\n    @Override\n    public boolean setLastAccess(long millis) {\n        try {\n            fs.setLastAccess(getPath(), millis).checkErrnoException();\n            return true;\n        } catch (RemoteException | ErrnoException e) {\n            return false;\n        }\n    }\n\n    @Override\n    public long length() {\n        try {\n            return fs.length(getPath());\n        } catch (RemoteException e) {\n            return 0L;\n        }\n    }\n\n    @Override\n    public boolean createNewFile() throws IOException {\n        try {\n            return fs.createNewFile(getPath()).tryAndGet();\n        } catch (RemoteException e) {\n            throw new IOException(e);\n        }\n    }\n\n    @Override\n    public boolean createNewLink(String existing) throws IOException {\n        try {\n            return fs.createLink(getPath(), existing, false).tryAndGet();\n        } catch (RemoteException e) {\n            throw new IOException(e);\n        }\n    }\n\n    @Override\n    public boolean createNewSymlink(String target) throws IOException {\n        try {\n            return fs.createLink(getPath(), target, true).tryAndGet();\n        } catch (RemoteException e) {\n            throw new IOException(e);\n        }\n    }\n\n    @Override\n    public boolean delete() {\n        try {\n            return fs.delete(getPath());\n        } catch (RemoteException e) {\n            return false;\n        }\n    }\n\n    @Override\n    public void deleteOnExit() {\n        throw new UnsupportedOperationException(\"deleteOnExit() is not supported in RemoteFile\");\n    }\n\n    @Override\n    public String[] list() {\n        try {\n            StringParceledListSlice list = fs.list(getPath());\n            return list != null ? list.getList().toArray(new String[0]) : null;\n        } catch (RemoteException e) {\n            return null;\n        }\n    }\n\n    @Override\n    public boolean mkdir() {\n        try {\n            return fs.mkdir(getPath());\n        } catch (RemoteException e) {\n            return false;\n        }\n    }\n\n    @Override\n    public boolean mkdirs() {\n        try {\n            return fs.mkdirs(getPath());\n        } catch (RemoteException e) {\n            return false;\n        }\n    }\n\n    @Override\n    public boolean renameTo(@NonNull File dest) {\n        try {\n            return fs.renameTo(getPath(), dest.getAbsolutePath());\n        } catch (RemoteException e) {\n            return false;\n        }\n    }\n\n    @Override\n    public boolean setLastModified(long time) {\n        try {\n            return fs.setLastModified(getPath(), time);\n        } catch (RemoteException e) {\n            return false;\n        }\n    }\n\n    @Override\n    public boolean setReadOnly() {\n        try {\n            return fs.setReadOnly(getPath());\n        } catch (RemoteException e) {\n            return false;\n        }\n    }\n\n    @Override\n    public boolean setWritable(boolean writable, boolean ownerOnly) {\n        try {\n            return fs.setWritable(getPath(), writable, ownerOnly);\n        } catch (RemoteException e) {\n            return false;\n        }\n    }\n\n    @Override\n    public boolean setReadable(boolean readable, boolean ownerOnly) {\n        try {\n            return fs.setReadable(getPath(), readable, ownerOnly);\n        } catch (RemoteException e) {\n            return false;\n        }\n    }\n\n    @Override\n    public boolean setExecutable(boolean executable, boolean ownerOnly) {\n        try {\n            return fs.setExecutable(getPath(), executable, ownerOnly);\n        } catch (RemoteException e) {\n            return false;\n        }\n    }\n\n    @Override\n    public long getTotalSpace() {\n        try {\n            return fs.getTotalSpace(getPath());\n        } catch (RemoteException e) {\n            return 0L;\n        }\n    }\n\n    @Override\n    public long getFreeSpace() {\n        try {\n            return fs.getFreeSpace(getPath());\n        } catch (RemoteException e) {\n            return 0L;\n        }\n    }\n\n    @Override\n    public long getUsableSpace() {\n        try {\n            return fs.getUsableSpace(getPath());\n        } catch (RemoteException e) {\n            return 0L;\n        }\n    }\n\n    @NonNull\n    @Override\n    public FileInputStream newInputStream() throws IOException {\n        ParcelFileDescriptor[] pipe = ParcelFileDescriptor.createPipe();\n        try {\n            fs.openReadStream(getPath(), pipe[1]).checkException();\n        } catch (RemoteException e) {\n            pipe[0].close();\n            throw new IOException(e);\n        } finally {\n            pipe[1].close();\n        }\n        return new ParcelFileDescriptor.AutoCloseInputStream(pipe[0]);\n    }\n\n    @NonNull\n    @Override\n    public FileOutputStream newOutputStream(boolean append) throws IOException {\n        ParcelFileDescriptor[] pipe = ParcelFileDescriptor.createPipe();\n        try {\n            fs.openWriteStream(getPath(), pipe[0], append).checkException();\n        } catch (RemoteException e) {\n            pipe[1].close();\n            throw new IOException(e);\n        } finally {\n            pipe[0].close();\n        }\n        return new ParcelFileDescriptor.AutoCloseOutputStream(pipe[1]);\n    }\n}"
  },
  {
    "path": "libcore/io/src/main/java/io/github/muntashirakon/io/RemoteFileChannel.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\n/*\n * Copyright 2022 John \"topjohnwu\" Wu\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n *     http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\npackage io.github.muntashirakon.io;\n\nimport android.os.RemoteException;\nimport android.system.ErrnoException;\nimport android.system.Os;\nimport android.system.OsConstants;\n\nimport java.io.File;\nimport java.io.FileDescriptor;\nimport java.io.IOException;\nimport java.nio.ByteBuffer;\nimport java.nio.MappedByteBuffer;\nimport java.nio.channels.ClosedChannelException;\nimport java.nio.channels.FileChannel;\nimport java.nio.channels.FileLock;\nimport java.nio.channels.NonReadableChannelException;\nimport java.nio.channels.NonWritableChannelException;\nimport java.nio.channels.ReadableByteChannel;\nimport java.nio.channels.WritableByteChannel;\n\nimport static android.os.ParcelFileDescriptor.MODE_READ_ONLY;\nimport static android.os.ParcelFileDescriptor.MODE_READ_WRITE;\nimport static android.os.ParcelFileDescriptor.MODE_WRITE_ONLY;\nimport static android.system.OsConstants.O_NONBLOCK;\nimport static android.system.OsConstants.O_RDONLY;\nimport static android.system.OsConstants.O_WRONLY;\n\nclass RemoteFileChannel extends FileChannel {\n\n    private static final int PIPE_CAPACITY = 16 * 4096;\n\n    private final IFileSystemService fs;\n    private final int mode;\n    private final Object fdLock = new Object();\n\n    private final FileDescriptor read;\n    private final FileDescriptor write;\n    private final int handle;\n\n    RemoteFileChannel(IFileSystemService fs, File file, int mode) throws IOException {\n        this.fs = fs;\n        this.mode = mode;\n        File fifo = null;\n        try {\n            // We use a FIFO created on the client side instead of opening a pipe and\n            // passing it through binder as this is the most portable and reliable method.\n            fifo = FileUtils.createTempFIFO();\n\n            // Open the file on the remote process\n            int posixMode = FileUtils.modeToPosix(mode);\n            handle = fs.openChannel(file.getAbsolutePath(), posixMode, fifo.getPath()).tryAndGet();\n\n            // Since we do not have the machinery to interrupt native pthreads, we\n            // have to make sure none of our I/O can block in all operations.\n            read = Os.open(fifo.getPath(), O_RDONLY | O_NONBLOCK, 0);\n            write = Os.open(fifo.getPath(), O_WRONLY | O_NONBLOCK, 0);\n        } catch (RemoteException | ErrnoException e) {\n            throw new IOException(e);\n        } finally {\n            // Once both sides opened the pipe, it can be unlinked\n            if (fifo != null)\n                fifo.delete();\n        }\n    }\n\n    private void ensureOpen() throws IOException {\n        if (!isOpen())\n            throw new ClosedChannelException();\n    }\n\n    private boolean writable() {\n        switch (mode & MODE_READ_WRITE) {\n            case MODE_READ_WRITE:\n            case MODE_WRITE_ONLY:\n                return true;\n            default:\n                return false;\n        }\n    }\n\n    private boolean readable() {\n        switch (mode & MODE_READ_WRITE) {\n            case MODE_READ_WRITE:\n            case MODE_READ_ONLY:\n                return true;\n            default:\n                return false;\n        }\n    }\n\n    private int read0(ByteBuffer dst, long offset) throws IOException {\n        begin();\n        final int limit = dst.limit();\n        final int initial = dst.position();\n        boolean success = false;\n        try {\n            int pos = initial;\n            for (; limit > pos; pos = dst.position()) {\n                final int len;\n                synchronized (fdLock) {\n                    if (!isOpen() || Thread.interrupted())\n                        return -1;\n                    len = fs.pread(handle, limit - pos, offset).tryAndGet();\n                    if (len == 0)\n                        break;\n                    dst.limit(pos + len);\n                    // Must read exactly len bytes\n                    for (int sz = 0; sz < len;) {\n                        sz += Os.read(read, dst);\n                    }\n                }\n                if (offset >= 0) {\n                    offset += len;\n                }\n            }\n            success = true;\n            return pos - initial;\n        } catch (ErrnoException | RemoteException e) {\n            throw new IOException(e);\n        } finally {\n            dst.limit(limit);\n            end(success);\n        }\n    }\n\n    @Override\n    public int read(ByteBuffer dst) throws IOException {\n        ensureOpen();\n        if (!readable())\n            throw new NonReadableChannelException();\n        return read0(dst, -1);\n    }\n\n    @Override\n    public long read(ByteBuffer[] dsts, int offset, int length) throws IOException {\n        if ((offset < 0) || (length < 0) || (offset > dsts.length - length))\n            throw new IndexOutOfBoundsException();\n        ensureOpen();\n        if (!readable())\n            throw new NonReadableChannelException();\n        int sz = 0;\n        // Real scattered I/O is too complicated, let's cheat\n        for (int i = offset; i < offset + length; ++i) {\n            sz += read0(dsts[i], -1);\n        }\n        return sz;\n    }\n\n    private int write0(ByteBuffer src, long offset) throws IOException {\n        begin();\n        final int remaining = src.remaining();\n        boolean success = false;\n        try {\n            while (src.hasRemaining()) {\n                final int len;\n                synchronized (fdLock) {\n                    if (!isOpen() || Thread.interrupted())\n                        return -1;\n                    len = Os.write(write, src);\n                    fs.pwrite(handle, len, offset).checkException();\n                }\n                if (offset >= 0) {\n                    offset += len;\n                }\n            }\n            success = true;\n            return remaining;\n        } catch (ErrnoException | RemoteException e) {\n            throw new IOException(e);\n        } finally {\n            end(success);\n        }\n    }\n\n    @Override\n    public int write(ByteBuffer src) throws IOException {\n        ensureOpen();\n        if (!writable())\n            throw new NonWritableChannelException();\n        return write0(src, -1);\n    }\n\n    @Override\n    public long write(ByteBuffer[] srcs, int offset, int length) throws IOException {\n        if ((offset < 0) || (length < 0) || (offset > srcs.length - length))\n            throw new IndexOutOfBoundsException();\n        ensureOpen();\n        if (!writable())\n            throw new NonWritableChannelException();\n        int sz = 0;\n        // Real scattered I/O is too complicated, let's cheat\n        for (int i = offset; i < offset + length; ++i) {\n            sz += write(srcs[i]);\n        }\n        return sz;\n    }\n\n    @Override\n    public long position() throws IOException {\n        ensureOpen();\n        try {\n            return fs.lseek(handle, 0, OsConstants.SEEK_CUR).tryAndGet();\n        } catch (RemoteException e) {\n            throw new IOException(e);\n        }\n    }\n\n    @Override\n    public RemoteFileChannel position(long newPosition) throws IOException {\n        ensureOpen();\n        if (newPosition < 0)\n            throw new IllegalArgumentException();\n        try {\n            fs.lseek(handle, newPosition, OsConstants.SEEK_SET).checkException();\n            return this;\n        } catch (RemoteException e) {\n            throw new IOException(e);\n        }\n    }\n\n    @Override\n    public long size() throws IOException {\n        ensureOpen();\n        try {\n            return fs.size(handle).tryAndGet();\n        } catch (RemoteException e) {\n            throw new IOException(e);\n        }\n    }\n\n    @Override\n    public RemoteFileChannel truncate(long size) throws IOException {\n        ensureOpen();\n        if (size < 0)\n            throw new IllegalArgumentException(\"Negative size\");\n        if (!writable())\n            throw new NonWritableChannelException();\n        try {\n            fs.ftruncate(handle, size).checkException();\n            return this;\n        } catch (RemoteException e) {\n            throw new IOException(e);\n        }\n    }\n\n    @Override\n    public void force(boolean metaData) throws IOException {\n        ensureOpen();\n        try {\n            fs.sync(handle, metaData).checkException();\n        } catch (RemoteException e) {\n            throw new IOException(e);\n        }\n    }\n\n    @Override\n    public long transferTo(long position, long count, WritableByteChannel target)\n            throws IOException {\n        ensureOpen();\n        if (!target.isOpen())\n            throw new ClosedChannelException();\n        if (!readable())\n            throw new NonReadableChannelException();\n        if ((position < 0) || (count < 0))\n            throw new IllegalArgumentException();\n\n        ByteBuffer b = ByteBuffer.allocateDirect(PIPE_CAPACITY);\n        long bytes = 0;\n        while (count > bytes) {\n            int limit = (int) Math.min(b.capacity(), count - bytes);\n            b.limit(limit);\n            if (read0(b, position) <= 0)\n                break;\n            b.flip();\n            int len = target.write(b);\n            position += len;\n            bytes += len;\n            b.clear();\n        }\n        return bytes;\n    }\n\n    @Override\n    public long transferFrom(ReadableByteChannel src, long position, long count) throws IOException {\n        ensureOpen();\n        if (!src.isOpen())\n            throw new ClosedChannelException();\n        if (!writable())\n            throw new NonWritableChannelException();\n        if ((position < 0) || (count < 0))\n            throw new IllegalArgumentException();\n\n        ByteBuffer b = ByteBuffer.allocateDirect(PIPE_CAPACITY);\n        long bytes = 0;\n        while (count > bytes) {\n            int limit = (int) Math.min(b.capacity(), count - bytes);\n            b.limit(limit);\n            if (src.read(b) <= 0)\n                break;\n            b.flip();\n            int len = write0(b, position);\n            position += len;\n            bytes += len;\n            b.clear();\n        }\n        return bytes;\n    }\n\n    @Override\n    public int read(ByteBuffer dst, long position) throws IOException {\n        if (position < 0)\n            throw new IllegalArgumentException(\"Negative position\");\n        ensureOpen();\n        return read0(dst, position);\n    }\n\n    @Override\n    public int write(ByteBuffer src, long position) throws IOException {\n        if (position < 0)\n            throw new IllegalArgumentException(\"Negative position\");\n        ensureOpen();\n        return write0(src, position);\n    }\n\n    @Override\n    protected void implCloseChannel() {\n        try { fs.close(handle); } catch (RemoteException ignored) {}\n        synchronized (fdLock) {\n            try { Os.close(read); } catch (ErrnoException ignored) {}\n            try { Os.close(write); } catch (ErrnoException ignored) {}\n        }\n    }\n\n    // Unsupported operations\n\n    @Override\n    public MappedByteBuffer map(MapMode mode, long position, long size) {\n        throw new UnsupportedOperationException(\"Memory mapping a remote file is not supported!\");\n    }\n\n    @Override\n    public FileLock lock(long position, long size, boolean shared) {\n        throw new UnsupportedOperationException(\"Locking a remote file is not supported!\");\n    }\n\n    @Override\n    public FileLock tryLock(long position, long size, boolean shared) {\n        throw new UnsupportedOperationException(\"Locking a remote file is not supported!\");\n    }\n}"
  },
  {
    "path": "libcore/io/src/main/java/io/github/muntashirakon/io/SplitInputStream.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.io;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.WorkerThread;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\n\npublic class SplitInputStream extends InputStream {\n    private final List<InputStream> mInputStreams;\n    private int mCurrentIndex = -1;\n    private final List<Path> mFiles;\n\n    private final byte[] mBuf;\n\n    // Number of valid bytes in buf\n    private int mCount = 0;\n    // Current read pos, > 0 in buf, < 0 in markBuf (interpret in bitwise negate)\n    private int mPos = 0;\n\n    // -1 when no active mark, 0 when markBuf is active, pos when mark is called\n    private int mMarkPos = -1;\n    // Number of valid bytes in markBuf\n    private int mMarkBufCount = 0;\n\n    // markBuf.length == markBufSize\n    private int mMarkBufSize;\n    @Nullable\n    private byte[] mMarkBuf;\n\n    // Some value ranges:\n    // 0 <= count <= buf.length\n    // 0 <= pos <= count (if pos > 0)\n    // 0 <= markPos <= pos (markPos = -1 means no mark)\n    // 0 <= ~pos <= markBufCount (if pos < 0)\n    // 0 <= markBufCount <= markLimit\n\n    public SplitInputStream(@NonNull List<Path> files) {\n        mFiles = files;\n        mInputStreams = new ArrayList<>(files.size());\n        mBuf = new byte[1024 * 4];\n    }\n\n    public SplitInputStream(@NonNull Path[] files) {\n        this(Arrays.asList(files));\n    }\n\n    @Override\n    public int read() throws IOException {\n        byte[] bytes = new byte[1];\n        int readBytes = read(bytes);\n        if (readBytes != 1) return -1;\n        else return bytes[0];\n    }\n\n    @Override\n    public int read(byte[] b) throws IOException {\n        return read(b, 0, b.length);\n    }\n\n    @Override\n    public int read(byte[] b, int off, int len) throws IOException {\n        if (off < 0 || len < 0 || off + len > b.length)\n            throw new IndexOutOfBoundsException();\n        return read0(b, off, len);\n    }\n\n    @Override\n    public long skip(long n) throws IOException {\n        if (n <= 0) return 0;\n        return Math.max(read0(null, 0, (int) n), 0);\n    }\n\n    @Override\n    public void close() throws IOException {\n        IOException failure = null;\n        for (InputStream stream : mInputStreams) {\n            try {\n                stream.close();\n            } catch (IOException e) {\n                if (failure == null) {\n                    failure = e;\n                } else {\n                    failure.addSuppressed(e);\n                }\n            }\n        }\n        if (failure != null) throw failure;\n    }\n\n    @Override\n    public synchronized void mark(int readlimit) {\n        // Reset mark\n        mMarkPos = mPos;\n        mMarkBufCount = 0;\n        mMarkBuf = null;\n\n        int remain = mCount - mPos;\n        if (readlimit <= remain) {\n            // Don't need a separate buffer\n            mMarkBufSize = 0;\n        } else {\n            // Extra buffer required is remain + n * buf.length\n            mMarkBufSize = remain + ((readlimit - remain) / mBuf.length) * mBuf.length;\n        }\n    }\n\n    @Override\n    public synchronized void reset() throws IOException {\n        if (mMarkPos < 0)\n            throw new IOException(\"Resetting to invalid mark\");\n        // Switch to markPos or use markBuf\n        mPos = mMarkBuf == null ? mMarkPos : ~0;\n    }\n\n    @WorkerThread\n    @Override\n    public synchronized int available() throws IOException {\n        if (mCount < 0) return 0;\n        if (mPos >= mCount) {\n            // Try to read the next chunk into memory\n            read0(null, 0, 1);\n            if (mCount < 0) return 0;\n            // Revert the 1 byte read\n            --mPos;\n        }\n        // Return the size available in memory\n        if (mPos < 0) {\n            return (mMarkBufCount - ~mPos) + mCount;\n        } else {\n            return mCount - mPos;\n        }\n    }\n\n    @Override\n    public boolean markSupported() {\n        return true;\n    }\n\n    @WorkerThread\n    private synchronized int read0(@Nullable byte[] b, int off, int len) throws IOException {\n        int n = 0;\n        while (n < len) {\n            if (mPos < 0) {\n                // Read from markBuf\n                int pos = ~mPos;\n                int size = Math.min(mMarkBufCount - pos, len - n);\n                if (b != null) {\n                    System.arraycopy(mMarkBuf, pos, b, off + n, size);\n                }\n                n += size;\n                pos += size;\n                if (pos == mMarkBufCount) {\n                    // markBuf done, switch to buf\n                    mPos = 0;\n                } else {\n                    // continue reading markBuf\n                    mPos = ~pos;\n                }\n                continue;\n            }\n            // Read from buf\n            if (mPos >= mCount) {\n                // We ran out of buffer, need to either refill or abort\n                if (mMarkPos >= 0) {\n                    // We need to preserve some buffer for mark\n                    long size = mCount - mMarkPos;\n                    if ((mMarkBufSize - mMarkBufCount) < size) {\n                        // Out of mark limit, discard markBuf\n                        mMarkBuf = null;\n                        mMarkBufCount = 0;\n                        mMarkPos = -1;\n                    } else if (mMarkBuf == null) {\n                        mMarkBuf = new byte[(int) mMarkBufSize];\n                        mMarkBufCount = 0;\n                    }\n                    if (mMarkBuf != null) {\n                        // Accumulate data in markBuf\n                        System.arraycopy(mBuf, mMarkPos, mMarkBuf, mMarkBufCount, (int) size);\n                        mMarkBufCount += (int) size;\n                        // Set markPos to 0 as buffer will refill\n                        mMarkPos = 0;\n                    }\n                }\n                // refill buffer\n                mPos = 0;\n                mCount = readStream(mBuf);\n                if (mCount < 0) {\n                    return n == 0 ? -1 : n;\n                }\n            }\n            int size = Math.min(mCount - mPos, len - n);\n            if (b != null) {\n                System.arraycopy(mBuf, mPos, b, off + n, size);\n            }\n            n += size;\n            mPos += size;\n        }\n        return n;\n    }\n\n    @WorkerThread\n    private synchronized int readStream(@NonNull byte[] b) throws IOException {\n        int off = 0;\n        int len = b.length;\n        if (len <= 0) return len;\n        try {\n            if (mFiles.isEmpty()) {\n                // No files supplied, nothing to read\n                return -1;\n            } else if (mCurrentIndex == -1) {\n                // Initialize a new stream\n                mInputStreams.add(mFiles.get(0).openInputStream());\n                ++mCurrentIndex;\n            }\n            do {\n                int readCount = mInputStreams.get(mCurrentIndex).read(b, off, len);\n                if (readCount <= 0) {\n                    // This stream has been read completely, initialize new stream if available\n                    if (mCurrentIndex + 1 != mFiles.size()) {\n                        mInputStreams.add(mFiles.get(mCurrentIndex + 1).openInputStream());\n                        ++mCurrentIndex;\n                    } else {\n                        // Last stream reached\n                        if (len == b.length) {\n                            // Read nothing\n                            return -1;\n                        } else {\n                            // Read something\n                            return b.length - len;\n                        }\n                    }\n                } else {\n                    off += readCount;\n                    len -= readCount;\n                }\n            } while (len > 0);\n            return b.length - len;\n        } catch (IOException e) {\n            throw e;\n        } catch (Throwable th) {\n            throw new IOException(th);\n        }\n    }\n}\n"
  },
  {
    "path": "libcore/io/src/main/java/io/github/muntashirakon/io/SplitOutputStream.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.io;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.WorkerThread;\n\nimport java.io.IOException;\nimport java.io.OutputStream;\nimport java.util.ArrayList;\nimport java.util.List;\n\npublic class SplitOutputStream extends OutputStream {\n    private static final long MAX_BYTES_WRITTEN = 1024 * 1024 * 1024;  // 1GB\n\n    private final List<OutputStream> mOutputStreams = new ArrayList<>(1);\n    private final List<Path> mFiles = new ArrayList<>(1);\n    private int mCurrentIndex = -1;\n    private long mBytesWritten;\n    private final long mMaxBytesPerFile;\n    private final String mBaseName;\n    private final Path mBasePath;\n\n    public SplitOutputStream(@NonNull Path basePath, @NonNull String baseName) {\n        this(basePath, baseName, MAX_BYTES_WRITTEN);\n    }\n\n    public SplitOutputStream(@NonNull Path basePath, @NonNull String baseName, long maxBytesPerFile) {\n        mBasePath = basePath;\n        mBaseName = baseName;\n        mMaxBytesPerFile = maxBytesPerFile;\n        mBytesWritten = maxBytesPerFile;\n    }\n\n    public List<Path> getFiles() {\n        return mFiles;\n    }\n\n    @WorkerThread\n    @Override\n    public void write(int b) throws IOException {\n        checkCurrentStream(1);\n        mOutputStreams.get(mCurrentIndex).write(b);\n        ++mBytesWritten;\n    }\n\n    @WorkerThread\n    @Override\n    public void write(@NonNull byte[] b) throws IOException {\n        checkCurrentStream(b.length);\n        mOutputStreams.get(mCurrentIndex).write(b);\n        mBytesWritten += b.length;\n    }\n\n    @WorkerThread\n    @Override\n    public void write(byte[] b, int off, int len) throws IOException {\n        checkCurrentStream(len);\n        mOutputStreams.get(mCurrentIndex).write(b, off, len);\n        mBytesWritten += len;\n    }\n\n    @WorkerThread\n    @Override\n    public void flush() throws IOException {\n        for (OutputStream stream : mOutputStreams) {\n            stream.flush();\n        }\n    }\n\n    @WorkerThread\n    @Override\n    public void close() throws IOException {\n        for (OutputStream stream : mOutputStreams) {\n            stream.close();\n        }\n    }\n\n    @WorkerThread\n    private void checkCurrentStream(int nextBytesSize) throws IOException {\n        if (mBytesWritten + nextBytesSize > mMaxBytesPerFile) {\n            // Need to create a new stream\n            Path newFile = getNextFile();\n            mFiles.add(newFile);\n            mOutputStreams.add(newFile.openOutputStream());\n            ++mCurrentIndex;\n            mBytesWritten = 0;\n        }\n    }\n\n    @NonNull\n    private Path getNextFile() throws IOException {\n        return mBasePath.createNewFile(mBaseName + \".\" + (mCurrentIndex + 1), null);\n    }\n}\n"
  },
  {
    "path": "libcore/io/src/main/java/io/github/muntashirakon/io/UidGidPair.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.io;\n\nimport android.os.Parcel;\nimport android.os.Parcelable;\n\nimport androidx.annotation.NonNull;\n\nimport java.util.Objects;\n\npublic class UidGidPair implements Parcelable {\n    public final int uid;\n    public final int gid;\n\n    public UidGidPair(int uid, int gid) {\n        this.uid = uid;\n        this.gid = gid;\n    }\n\n    protected UidGidPair(Parcel in) {\n        uid = in.readInt();\n        gid = in.readInt();\n    }\n\n    public static final Creator<UidGidPair> CREATOR = new Creator<UidGidPair>() {\n        @Override\n        public UidGidPair createFromParcel(Parcel in) {\n            return new UidGidPair(in);\n        }\n\n        @Override\n        public UidGidPair[] newArray(int size) {\n            return new UidGidPair[size];\n        }\n    };\n\n    @Override\n    public int describeContents() {\n        return 0;\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        dest.writeInt(uid);\n        dest.writeInt(gid);\n    }\n\n    @Override\n    public boolean equals(Object o) {\n        if (this == o) return true;\n        if (!(o instanceof UidGidPair)) return false;\n        UidGidPair that = (UidGidPair) o;\n        return uid == that.uid && gid == that.gid;\n    }\n\n    @Override\n    public int hashCode() {\n        return Objects.hash(uid, gid);\n    }\n}\n"
  },
  {
    "path": "libcore/ui/.gitignore",
    "content": "/build"
  },
  {
    "path": "libcore/ui/build.gradle",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\nplugins {\n    id('com.android.library')\n}\n\nandroid {\n    namespace 'io.github.muntashirakon.ui'\n    compileSdk compile_sdk\n    buildToolsVersion = build_tools\n\n    defaultConfig {\n        minSdk min_sdk\n        targetSdk target_sdk\n\n        consumerProguardFiles 'consumer-rules.pro'\n    }\n\n    compileOptions {\n        encoding \"UTF-8\"\n        sourceCompatibility JavaVersion.VERSION_1_8\n        targetCompatibility JavaVersion.VERSION_1_8\n    }\n}\n\ndependencies {\n    api \"androidx.annotation:annotation:${annotation_version}\"\n    api \"androidx.appcompat:appcompat:${appcompat_version}\"\n    api \"com.google.android.material:material:${material_version}\"\n    api \"androidx.swiperefreshlayout:swiperefreshlayout:${swipe_refresh_version}\"\n    api \"androidx.preference:preference:${preferences_version}\"\n    api \"me.zhanghai.android.fastscroll:library:${fastscroll_version}\"\n    api \"com.leinardi.android:speed-dial:${speed_dial_version}\"\n}\n"
  },
  {
    "path": "libcore/ui/consumer-rules.pro",
    "content": "# BottomSheetBehavior\n-keepclassmembers public class com.google.android.material.bottomsheet.BottomSheetBehavior {\n  void setStateInternal(int);\n}\n# ViewPager\n-keepclassmembers public class androidx.viewpager.widget.ViewPager$LayoutParams {\n  int position;\n}\n"
  },
  {
    "path": "libcore/ui/src/main/AndroidManifest.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<manifest />\n"
  },
  {
    "path": "libcore/ui/src/main/java/io/github/muntashirakon/adapters/AnyFilterArrayAdapter.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.adapters;\n\nimport android.content.Context;\nimport android.widget.ArrayAdapter;\nimport android.widget.Filter;\n\nimport androidx.annotation.LayoutRes;\nimport androidx.annotation.NonNull;\n\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Locale;\n\n/**\n * An {@link ArrayAdapter} that filters using {@link String#contains(CharSequence)} (case-insensitive) rather than using\n * {@link String#startsWith(String)} (i.e. prefix matching).\n */\npublic class AnyFilterArrayAdapter<T> extends SelectedArrayAdapter<T> {\n    @NonNull\n    private final List<T> mObjects;\n    private final Filter mFilter = new Filter() {\n        @NonNull\n        @Override\n        protected FilterResults performFiltering(CharSequence constraint) {\n            FilterResults filterResults = new FilterResults();\n            String query;\n            if (constraint == null || constraint.length() == 0) {\n                filterResults.count = mObjects.size();\n                filterResults.values = mObjects;\n                return filterResults;\n            }\n\n            query = constraint.toString().toLowerCase(Locale.ROOT);\n            List<T> list = new ArrayList<>(mObjects.size());\n            for (T item : mObjects) {\n                if (item.toString().toLowerCase(Locale.ROOT).contains(query))\n                    list.add(item);\n            }\n            filterResults.count = list.size();\n            filterResults.values = list;\n            return filterResults;\n        }\n\n        @SuppressWarnings(\"unchecked\")\n        @Override\n        protected void publishResults(CharSequence constraint, @NonNull FilterResults results) {\n            clear();\n            addAll((List<T>) results.values);\n            notifyDataSetChanged();\n        }\n    };\n\n    public AnyFilterArrayAdapter(@NonNull Context context, @LayoutRes int resource, @NonNull List<T> objects) {\n        super(context, resource, new ArrayList<>(objects));\n        mObjects = objects;\n    }\n\n    @NonNull\n    @Override\n    public Filter getFilter() {\n        return mFilter;\n    }\n}\n"
  },
  {
    "path": "libcore/ui/src/main/java/io/github/muntashirakon/adapters/NoFilterArrayAdapter.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.adapters;\n\nimport android.content.Context;\nimport android.widget.ArrayAdapter;\nimport android.widget.Filter;\n\nimport androidx.annotation.LayoutRes;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport java.util.List;\n\n/**\n * An {@link ArrayAdapter} incapable of filtering i.e. returns everything regardless of the filtered text.\n */\npublic class NoFilterArrayAdapter<T> extends SelectedArrayAdapter<T> {\n    private final Filter mDummyFilter = new Filter() {\n        @Override\n        @Nullable\n        protected FilterResults performFiltering(CharSequence constraint) {\n            return null;\n        }\n\n        @Override\n        protected void publishResults(CharSequence constraint, @Nullable FilterResults results) {\n            notifyDataSetChanged();\n        }\n    };\n\n    public NoFilterArrayAdapter(@NonNull Context context, @LayoutRes int resource, @NonNull List<T> objects) {\n        super(context, resource, objects);\n    }\n\n    @NonNull\n    @Override\n    public Filter getFilter() {\n        return mDummyFilter;\n    }\n}\n"
  },
  {
    "path": "libcore/ui/src/main/java/io/github/muntashirakon/adapters/SelectedArrayAdapter.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.adapters;\n\nimport android.content.Context;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.ArrayAdapter;\nimport android.widget.TextView;\n\nimport androidx.annotation.ArrayRes;\nimport androidx.annotation.IdRes;\nimport androidx.annotation.LayoutRes;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\n\n/**\n * Same as {@link ArrayAdapter} except that it selects the TextView to allow marquee mode.\n */\npublic class SelectedArrayAdapter<T> extends ArrayAdapter<T> {\n\n    public static @NonNull ArrayAdapter<CharSequence> createFromResource(@NonNull Context context,\n                                                                         @ArrayRes int textArrayResId,\n                                                                         @LayoutRes int textViewResId) {\n        final CharSequence[] strings = context.getResources().getTextArray(textArrayResId);\n        return new SelectedArrayAdapter<>(context, textViewResId, 0, Arrays.asList(strings));\n    }\n\n    private final int mFieldId;\n\n    public SelectedArrayAdapter(@NonNull Context context, @LayoutRes int resource) {\n        this(context, resource, 0, new ArrayList<>());\n    }\n\n    public SelectedArrayAdapter(@NonNull Context context, @LayoutRes int resource, @IdRes int textViewResourceId) {\n        this(context, resource, textViewResourceId, new ArrayList<>());\n    }\n\n    public SelectedArrayAdapter(@NonNull Context context, @LayoutRes int resource, @NonNull T[] objects) {\n        this(context, resource, 0, Arrays.asList(objects));\n    }\n\n    public SelectedArrayAdapter(@NonNull Context context, @LayoutRes int resource, @IdRes int textViewResourceId, @NonNull T[] objects) {\n        this(context, resource, textViewResourceId, Arrays.asList(objects));\n    }\n\n    public SelectedArrayAdapter(@NonNull Context context, @LayoutRes int resource, @NonNull List<T> objects) {\n        this(context, resource, 0, objects);\n    }\n\n    public SelectedArrayAdapter(@NonNull Context context, @LayoutRes int resource, @IdRes int textViewResourceId, @NonNull List<T> objects) {\n        super(context, resource, textViewResourceId, objects);\n        mFieldId = 0;\n    }\n\n    @NonNull\n    @Override\n    public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {\n        View v = super.getView(position, convertView, parent);\n        return setSelected(v);\n    }\n\n    @Override\n    public View getDropDownView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {\n        View v = super.getDropDownView(position, convertView, parent);\n        return setSelected(v);\n    }\n\n    @NonNull\n    private View setSelected(@NonNull View v) {\n        TextView tv;\n        if (mFieldId == 0) {\n            //  If no custom field is assigned, assume the whole resource is a TextView\n            tv = (TextView) v;\n        } else {\n            //  Otherwise, find the TextView field within the layout\n            tv = v.findViewById(mFieldId);\n        }\n        if (tv.isSelected()) {\n            tv.setSelected(false);\n        }\n        tv.setSelected(true);\n        return v;\n    }\n}\n"
  },
  {
    "path": "libcore/ui/src/main/java/io/github/muntashirakon/dialog/AlertDialogBuilder.java",
    "content": "// SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-or-later\n\npackage io.github.muntashirakon.dialog;\n\nimport android.annotation.SuppressLint;\nimport android.content.Context;\nimport android.content.DialogInterface;\nimport android.content.DialogInterface.OnCancelListener;\nimport android.content.DialogInterface.OnClickListener;\nimport android.content.DialogInterface.OnDismissListener;\nimport android.content.DialogInterface.OnKeyListener;\nimport android.content.DialogInterface.OnMultiChoiceClickListener;\nimport android.content.res.ColorStateList;\nimport android.content.res.Resources.Theme;\nimport android.database.Cursor;\nimport android.graphics.Rect;\nimport android.graphics.drawable.Drawable;\nimport android.os.Build;\nimport android.os.Build.VERSION_CODES;\nimport android.util.TypedValue;\nimport android.view.View;\nimport android.view.Window;\nimport android.widget.AdapterView;\nimport android.widget.Button;\nimport android.widget.ListAdapter;\n\nimport androidx.annotation.ArrayRes;\nimport androidx.annotation.AttrRes;\nimport androidx.annotation.DrawableRes;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.Px;\nimport androidx.annotation.StringRes;\nimport androidx.annotation.StyleRes;\nimport androidx.appcompat.app.AlertDialog;\nimport androidx.appcompat.view.ContextThemeWrapper;\nimport androidx.core.view.ViewCompat;\n\nimport com.google.android.material.color.MaterialColors;\nimport com.google.android.material.dialog.InsetDialogOnTouchListener;\nimport com.google.android.material.dialog.MaterialDialogs;\nimport com.google.android.material.resources.MaterialAttributes;\nimport com.google.android.material.shape.MaterialShapeDrawable;\n\nimport io.github.muntashirakon.ui.R;\nimport io.github.muntashirakon.util.UiUtils;\n\nimport static com.google.android.material.theme.overlay.MaterialThemeOverlay.wrap;\n\n/**\n * An extension of {@link AlertDialog.Builder} for use with a Material theme (e.g.,\n * Theme.MaterialComponents).\n *\n * <p>This Builder must be used in order for AlertDialog objects to respond to color and shape\n * theming provided by Material themes.\n *\n * <p>The type of dialog returned is still an {@link AlertDialog}; there is no specific Material\n * implementation of {@link AlertDialog}.\n */\n// Copyright 2018 The Android Open Source Project\npublic class AlertDialogBuilder extends AlertDialog.Builder {\n    @AttrRes\n    private static final int DEF_STYLE_ATTR = androidx.appcompat.R.attr.alertDialogStyle;\n    @StyleRes\n    private static final int DEF_STYLE_RES = com.google.android.material.R.style.MaterialAlertDialog_Material3;\n\n    @AttrRes\n    private static final int MATERIAL_ALERT_DIALOG_THEME_OVERLAY = com.google.android.material.R.attr.materialAlertDialogTheme;\n\n    @Nullable\n    private final FullScreenDialogTitleBuilder mTitleBuilder;\n    @NonNull\n    private final Rect mBackgroundInsets;\n    private final boolean mFullScreenMode;\n\n    @Nullable\n    private Drawable mBackground;\n    private boolean mExitOnButtonPress = true;\n    @Nullable\n    private DialogInterface.OnClickListener mPositiveButtonListener;\n    @Nullable\n    private DialogInterface.OnClickListener mNegativeButtonListener;\n    @Nullable\n    private DialogInterface.OnClickListener mNeutralButtonListener;\n\n    @SuppressLint(\"RestrictedApi\")\n    private static int getMaterialAlertDialogThemeOverlay(@NonNull Context context) {\n        TypedValue materialAlertDialogThemeOverlay =\n                MaterialAttributes.resolve(context, MATERIAL_ALERT_DIALOG_THEME_OVERLAY);\n        if (materialAlertDialogThemeOverlay == null) {\n            return 0;\n        }\n        return materialAlertDialogThemeOverlay.data;\n    }\n\n    @NonNull\n    private static Context createMaterialAlertDialogThemedContext(@NonNull Context context) {\n        int themeOverlayId = getMaterialAlertDialogThemeOverlay(context);\n        Context themedContext = wrap(context, null, DEF_STYLE_ATTR, DEF_STYLE_RES);\n        if (themeOverlayId == 0) {\n            return themedContext;\n        }\n        return new ContextThemeWrapper(themedContext, themeOverlayId);\n    }\n\n    private static int getOverridingThemeResId(@NonNull Context context, int overrideThemeResId) {\n        return overrideThemeResId == 0\n                ? getMaterialAlertDialogThemeOverlay(context)\n                : overrideThemeResId;\n    }\n\n    private static boolean supportsFullScreen(@NonNull Context context, boolean fullScreenMode) {\n        return fullScreenMode && !context.getResources().getBoolean(R.bool.large_layout);\n    }\n\n    public AlertDialogBuilder(@NonNull Context context) {\n        this(context, 0);\n    }\n\n    public AlertDialogBuilder(@NonNull Context context, boolean fullScreenMode) {\n        this(context, supportsFullScreen(context, fullScreenMode) ?\n                UiUtils.getStyle(context, R.attr.materialFullScreenAlertDialogTheme) : 0, fullScreenMode);\n    }\n\n    public AlertDialogBuilder(@NonNull Context context, @StyleRes int overrideThemeResId) {\n        this(context, overrideThemeResId, false);\n    }\n\n    @SuppressLint(\"RestrictedApi\")\n    public AlertDialogBuilder(@NonNull Context context, @StyleRes int overrideThemeResId, boolean fullScreenMode) {\n        // Only pass in 0 for overrideThemeResId if both overrideThemeResId and\n        // MATERIAL_ALERT_DIALOG_THEME_OVERLAY are 0 otherwise alertDialogTheme will override both.\n        super(createMaterialAlertDialogThemedContext(context),\n                getOverridingThemeResId(context, overrideThemeResId));\n        mFullScreenMode = supportsFullScreen(context, fullScreenMode);\n        // Ensure we are using the correctly themed context rather than the context that was passed in.\n        context = getContext();\n        Theme theme = context.getTheme();\n        if (fullScreenMode) {\n            mTitleBuilder = new FullScreenDialogTitleBuilder(context);\n        } else mTitleBuilder = null;\n\n        mBackgroundInsets = MaterialDialogs.getDialogBackgroundInsets(context, DEF_STYLE_ATTR, DEF_STYLE_RES);\n\n        int surfaceColor = MaterialColors.getColor(context, com.google.android.material.R.attr.colorSurface, getClass().getCanonicalName());\n        MaterialShapeDrawable materialShapeDrawable =\n                new MaterialShapeDrawable(context, null, DEF_STYLE_ATTR, DEF_STYLE_RES);\n        materialShapeDrawable.initializeElevationOverlay(context);\n        materialShapeDrawable.setFillColor(ColorStateList.valueOf(surfaceColor));\n\n        // dialogCornerRadius first appeared in Android Pie\n        if (Build.VERSION.SDK_INT >= VERSION_CODES.P) {\n            TypedValue dialogCornerRadiusValue = new TypedValue();\n            theme.resolveAttribute(android.R.attr.dialogCornerRadius, dialogCornerRadiusValue, true);\n            float dialogCornerRadius =\n                    dialogCornerRadiusValue.getDimension(getContext().getResources().getDisplayMetrics());\n            if (dialogCornerRadiusValue.type == TypedValue.TYPE_DIMENSION && dialogCornerRadius >= 0) {\n                materialShapeDrawable.setCornerSize(dialogCornerRadius);\n            }\n        }\n        mBackground = materialShapeDrawable;\n    }\n\n    @SuppressLint(\"RestrictedApi\")\n    @NonNull\n    @Override\n    public AlertDialog create() {\n        AlertDialog alertDialog = super.create();\n        Window window = alertDialog.getWindow();\n        // TODO: 28/1/22 Use Handler instead of lamda functions\n        if (mFullScreenMode && mTitleBuilder != null) {\n            alertDialog.setOnShowListener(dialog -> {\n                Button neutralButton = alertDialog.getButton(DialogInterface.BUTTON_NEUTRAL);\n                if (mNeutralButtonListener != null) {\n                    neutralButton.setOnClickListener(v -> {\n                        mNeutralButtonListener.onClick(alertDialog, DialogInterface.BUTTON_NEUTRAL);\n                        if (mExitOnButtonPress) alertDialog.dismiss();\n                    });\n                }\n            });\n            mTitleBuilder.setOnPositiveButtonClickListener(mPositiveButtonListener);\n            mTitleBuilder.setOnCloseButtonClickListener(mNegativeButtonListener);\n            alertDialog.setCustomTitle(mTitleBuilder.build(alertDialog));\n            window.setWindowAnimations(R.style.AppTheme_FullScreenDialog_Animation);\n            // No need to set any insets\n            return alertDialog;\n        }\n        alertDialog.setOnShowListener(dialog -> {\n            Button neutralButton = alertDialog.getButton(DialogInterface.BUTTON_NEUTRAL);\n            if (mNeutralButtonListener != null) {\n                neutralButton.setOnClickListener(v -> {\n                    mNeutralButtonListener.onClick(alertDialog, DialogInterface.BUTTON_NEUTRAL);\n                    if (mExitOnButtonPress) alertDialog.dismiss();\n                });\n            }\n            Button positiveButton = alertDialog.getButton(DialogInterface.BUTTON_POSITIVE);\n            if (mPositiveButtonListener != null) {\n                positiveButton.setOnClickListener(v -> {\n                    mPositiveButtonListener.onClick(alertDialog, DialogInterface.BUTTON_POSITIVE);\n                    if (mExitOnButtonPress) alertDialog.dismiss();\n                });\n            }\n            Button negativeButton = alertDialog.getButton(DialogInterface.BUTTON_NEGATIVE);\n            if (mNegativeButtonListener != null) {\n                negativeButton.setOnClickListener(v -> {\n                    mNegativeButtonListener.onClick(alertDialog, DialogInterface.BUTTON_NEGATIVE);\n                    if (mExitOnButtonPress) alertDialog.dismiss();\n                });\n            }\n        });\n        /* {@link Window#getDecorView()} should be called before any changes are made to the Window\n         * as it locks in attributes and affects layout. */\n        View decorView = window.getDecorView();\n        if (mBackground instanceof MaterialShapeDrawable) {\n            ((MaterialShapeDrawable) mBackground).setElevation(ViewCompat.getElevation(decorView));\n        }\n\n        Drawable insetDrawable = MaterialDialogs.insetDrawable(mBackground, mBackgroundInsets);\n        window.setBackgroundDrawable(insetDrawable);\n        decorView.setOnTouchListener(new InsetDialogOnTouchListener(alertDialog, mBackgroundInsets));\n        return alertDialog;\n    }\n\n    @Nullable\n    public Drawable getBackground() {\n        return mBackground;\n    }\n\n    @NonNull\n    public AlertDialogBuilder setBackground(@Nullable Drawable background) {\n        mBackground = background;\n        return this;\n    }\n\n    @NonNull\n    public AlertDialogBuilder setBackgroundInsetStart(@Px int backgroundInsetStart) {\n        if (getContext().getResources().getConfiguration().getLayoutDirection() == ViewCompat.LAYOUT_DIRECTION_RTL) {\n            mBackgroundInsets.right = backgroundInsetStart;\n        } else {\n            mBackgroundInsets.left = backgroundInsetStart;\n        }\n        return this;\n    }\n\n    @NonNull\n    public AlertDialogBuilder setBackgroundInsetTop(@Px int backgroundInsetTop) {\n        mBackgroundInsets.top = backgroundInsetTop;\n        return this;\n    }\n\n    @NonNull\n    public AlertDialogBuilder setBackgroundInsetEnd(@Px int backgroundInsetEnd) {\n        if (getContext().getResources().getConfiguration().getLayoutDirection() == ViewCompat.LAYOUT_DIRECTION_RTL) {\n            mBackgroundInsets.left = backgroundInsetEnd;\n        } else {\n            mBackgroundInsets.right = backgroundInsetEnd;\n        }\n        return this;\n    }\n\n    @NonNull\n    public AlertDialogBuilder setBackgroundInsetBottom(@Px int backgroundInsetBottom) {\n        mBackgroundInsets.bottom = backgroundInsetBottom;\n        return this;\n    }\n\n    /**\n     * Whether to exit after a button (negative, positive or neutral) has been pressed.\n     */\n    public AlertDialogBuilder setExitOnButtonPress(boolean exitOnButtonPress) {\n        if (mTitleBuilder != null) {\n            mTitleBuilder.setExitOnButtonPress(exitOnButtonPress);\n        }\n        mExitOnButtonPress = exitOnButtonPress;\n        return this;\n    }\n\n    // The following methods are all pass-through methods used to specify the return type for the\n    // builder chain.\n\n    @NonNull\n    @Override\n    public AlertDialogBuilder setTitle(@StringRes int titleId) {\n        if (mFullScreenMode && mTitleBuilder != null) {\n            mTitleBuilder.setTitle(titleId);\n            return this;\n        }\n        return (AlertDialogBuilder) super.setTitle(titleId);\n    }\n\n    @NonNull\n    @Override\n    public AlertDialogBuilder setTitle(@Nullable CharSequence title) {\n        if (mFullScreenMode && mTitleBuilder != null) {\n            mTitleBuilder.setTitle(title);\n            return this;\n        }\n        return (AlertDialogBuilder) super.setTitle(title);\n    }\n\n    @NonNull\n    @Override\n    public AlertDialogBuilder setCustomTitle(@Nullable View customTitleView) {\n        return (AlertDialogBuilder) super.setCustomTitle(customTitleView);\n    }\n\n    @NonNull\n    @Override\n    public AlertDialogBuilder setMessage(@StringRes int messageId) {\n        return (AlertDialogBuilder) super.setMessage(messageId);\n    }\n\n    @NonNull\n    @Override\n    public AlertDialogBuilder setMessage(@Nullable CharSequence message) {\n        return (AlertDialogBuilder) super.setMessage(message);\n    }\n\n    @NonNull\n    @Override\n    public AlertDialogBuilder setIcon(@DrawableRes int iconId) {\n        return (AlertDialogBuilder) super.setIcon(iconId);\n    }\n\n    @NonNull\n    @Override\n    public AlertDialogBuilder setIcon(@Nullable Drawable icon) {\n        return (AlertDialogBuilder) super.setIcon(icon);\n    }\n\n    @NonNull\n    @Override\n    public AlertDialogBuilder setIconAttribute(@AttrRes int attrId) {\n        return (AlertDialogBuilder) super.setIconAttribute(attrId);\n    }\n\n    @NonNull\n    @Override\n    public AlertDialogBuilder setPositiveButton(\n            @StringRes int textId, @Nullable final OnClickListener listener) {\n        mPositiveButtonListener = listener;\n        if (mFullScreenMode && mTitleBuilder != null) {\n            mTitleBuilder.setPositiveButtonText(textId);\n            return this;\n        }\n        return (AlertDialogBuilder) super.setPositiveButton(textId, null);\n    }\n\n    @NonNull\n    @Override\n    public AlertDialogBuilder setPositiveButton(\n            @Nullable CharSequence text, @Nullable final OnClickListener listener) {\n        mPositiveButtonListener = listener;\n        if (mFullScreenMode && mTitleBuilder != null) {\n            mTitleBuilder.setPositiveButtonText(text);\n            return this;\n        }\n        return (AlertDialogBuilder) super.setPositiveButton(text, null);\n    }\n\n    @NonNull\n    @Override\n    public AlertDialogBuilder setPositiveButtonIcon(@Nullable Drawable icon) {\n        if (mFullScreenMode && mTitleBuilder != null) {\n            mTitleBuilder.setPositiveButtonIcon(icon);\n            return this;\n        }\n        return (AlertDialogBuilder) super.setPositiveButtonIcon(icon);\n    }\n\n    @NonNull\n    @Override\n    public AlertDialogBuilder setNegativeButton(\n            @StringRes int textId, @Nullable final OnClickListener listener) {\n        mNegativeButtonListener = listener;\n        if (mFullScreenMode && mTitleBuilder != null) {\n            mTitleBuilder.setCloseIconContentDescription(textId);\n            return this;\n        }\n        return (AlertDialogBuilder) super.setNegativeButton(textId, null);\n    }\n\n    @NonNull\n    @Override\n    public AlertDialogBuilder setNegativeButton(\n            @Nullable CharSequence text, @Nullable final OnClickListener listener) {\n        mNegativeButtonListener = listener;\n        if (mFullScreenMode && mTitleBuilder != null) {\n            mTitleBuilder.setCloseIconContentDescription(text);\n            return this;\n        }\n        return (AlertDialogBuilder) super.setNegativeButton(text, null);\n    }\n\n    @NonNull\n    @Override\n    public AlertDialogBuilder setNegativeButtonIcon(@Nullable Drawable icon) {\n        if (mFullScreenMode && mTitleBuilder != null) {\n            mTitleBuilder.setCloseButtonIcon(icon);\n            return this;\n        }\n        return (AlertDialogBuilder) super.setNegativeButtonIcon(icon);\n    }\n\n    @NonNull\n    @Override\n    public AlertDialogBuilder setNeutralButton(\n            @StringRes int textId, @Nullable final OnClickListener listener) {\n        mNeutralButtonListener = listener;\n        return (AlertDialogBuilder) super.setNeutralButton(textId, null);\n    }\n\n    @NonNull\n    @Override\n    public AlertDialogBuilder setNeutralButton(\n            @Nullable CharSequence text, @Nullable final OnClickListener listener) {\n        mNeutralButtonListener = listener;\n        return (AlertDialogBuilder) super.setNeutralButton(text, null);\n    }\n\n    @NonNull\n    @Override\n    public AlertDialogBuilder setNeutralButtonIcon(@Nullable Drawable icon) {\n        return (AlertDialogBuilder) super.setNeutralButtonIcon(icon);\n    }\n\n    @NonNull\n    @Override\n    public AlertDialogBuilder setCancelable(boolean cancelable) {\n        return (AlertDialogBuilder) super.setCancelable(cancelable);\n    }\n\n    @NonNull\n    @Override\n    public AlertDialogBuilder setOnCancelListener(\n            @Nullable OnCancelListener onCancelListener) {\n        return (AlertDialogBuilder) super.setOnCancelListener(onCancelListener);\n    }\n\n    @NonNull\n    @Override\n    public AlertDialogBuilder setOnDismissListener(\n            @Nullable OnDismissListener onDismissListener) {\n        return (AlertDialogBuilder) super.setOnDismissListener(onDismissListener);\n    }\n\n    @NonNull\n    @Override\n    public AlertDialogBuilder setOnKeyListener(@Nullable OnKeyListener onKeyListener) {\n        return (AlertDialogBuilder) super.setOnKeyListener(onKeyListener);\n    }\n\n    @NonNull\n    @Override\n    public AlertDialogBuilder setItems(\n            @ArrayRes int itemsId, @Nullable final OnClickListener listener) {\n        return (AlertDialogBuilder) super.setItems(itemsId, listener);\n    }\n\n    @NonNull\n    @Override\n    public AlertDialogBuilder setItems(\n            @Nullable CharSequence[] items, @Nullable final OnClickListener listener) {\n        return (AlertDialogBuilder) super.setItems(items, listener);\n    }\n\n    @NonNull\n    @Override\n    public AlertDialogBuilder setAdapter(\n            @Nullable final ListAdapter adapter, @Nullable final OnClickListener listener) {\n        return (AlertDialogBuilder) super.setAdapter(adapter, listener);\n    }\n\n    @NonNull\n    @Override\n    public AlertDialogBuilder setCursor(\n            @Nullable final Cursor cursor,\n            @Nullable final OnClickListener listener,\n            @NonNull String labelColumn) {\n        return (AlertDialogBuilder) super.setCursor(cursor, listener, labelColumn);\n    }\n\n    @NonNull\n    @Override\n    public AlertDialogBuilder setMultiChoiceItems(\n            @ArrayRes int itemsId,\n            @Nullable boolean[] checkedItems,\n            @Nullable final OnMultiChoiceClickListener listener) {\n        return (AlertDialogBuilder) super.setMultiChoiceItems(itemsId, checkedItems, listener);\n    }\n\n    @NonNull\n    @Override\n    public AlertDialogBuilder setMultiChoiceItems(\n            @Nullable CharSequence[] items,\n            @Nullable boolean[] checkedItems,\n            @Nullable final OnMultiChoiceClickListener listener) {\n        return (AlertDialogBuilder) super.setMultiChoiceItems(items, checkedItems, listener);\n    }\n\n    @NonNull\n    @Override\n    public AlertDialogBuilder setMultiChoiceItems(\n            @Nullable Cursor cursor,\n            @NonNull String isCheckedColumn,\n            @NonNull String labelColumn,\n            @Nullable final OnMultiChoiceClickListener listener) {\n        return (AlertDialogBuilder) super.setMultiChoiceItems(cursor, isCheckedColumn, labelColumn, listener);\n    }\n\n    @NonNull\n    @Override\n    public AlertDialogBuilder setSingleChoiceItems(\n            @ArrayRes int itemsId, int checkedItem, @Nullable final OnClickListener listener) {\n        return (AlertDialogBuilder) super.setSingleChoiceItems(itemsId, checkedItem, listener);\n    }\n\n    @NonNull\n    @Override\n    public AlertDialogBuilder setSingleChoiceItems(\n            @Nullable Cursor cursor,\n            int checkedItem,\n            @NonNull String labelColumn,\n            @Nullable final OnClickListener listener) {\n        return (AlertDialogBuilder)\n                super.setSingleChoiceItems(cursor, checkedItem, labelColumn, listener);\n    }\n\n    @NonNull\n    @Override\n    public AlertDialogBuilder setSingleChoiceItems(\n            @Nullable CharSequence[] items, int checkedItem, @Nullable final OnClickListener listener) {\n        return (AlertDialogBuilder) super.setSingleChoiceItems(items, checkedItem, listener);\n    }\n\n    @NonNull\n    @Override\n    public AlertDialogBuilder setSingleChoiceItems(\n            @Nullable ListAdapter adapter, int checkedItem, @Nullable final OnClickListener listener) {\n        return (AlertDialogBuilder) super.setSingleChoiceItems(adapter, checkedItem, listener);\n    }\n\n    @NonNull\n    @Override\n    public AlertDialogBuilder setOnItemSelectedListener(\n            @Nullable final AdapterView.OnItemSelectedListener listener) {\n        return (AlertDialogBuilder) super.setOnItemSelectedListener(listener);\n    }\n\n    @NonNull\n    @Override\n    public AlertDialogBuilder setView(int layoutResId) {\n        return (AlertDialogBuilder) super.setView(layoutResId);\n    }\n\n    @NonNull\n    @Override\n    public AlertDialogBuilder setView(@Nullable View view) {\n        return (AlertDialogBuilder) super.setView(view);\n    }\n}\n"
  },
  {
    "path": "libcore/ui/src/main/java/io/github/muntashirakon/dialog/BottomSheetAlertDialogFragment.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.dialog;\n\nimport android.graphics.drawable.Drawable;\nimport android.os.Bundle;\nimport android.text.method.MovementMethod;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.RelativeLayout;\n\nimport androidx.annotation.CallSuper;\nimport androidx.annotation.DrawableRes;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.StringRes;\nimport androidx.appcompat.widget.LinearLayoutCompat;\n\nimport com.google.android.material.button.MaterialButton;\nimport com.google.android.material.textview.MaterialTextView;\n\nimport io.github.muntashirakon.ui.R;\n\npublic class BottomSheetAlertDialogFragment extends CapsuleBottomSheetDialogFragment {\n    protected static final String ARG_TITLE = \"title\";\n    protected static final String ARG_SUBTITLE = \"subtitle\";\n    protected static final String ARG_MESSAGE = \"message\";\n\n    @NonNull\n    protected static Bundle getArgs(@Nullable CharSequence title, @Nullable CharSequence subtitle,\n                                    @Nullable CharSequence message) {\n        Bundle args = new Bundle();\n        args.putCharSequence(ARG_TITLE, title);\n        args.putCharSequence(ARG_SUBTITLE, subtitle);\n        args.putCharSequence(ARG_MESSAGE, message);\n        return args;\n    }\n\n    private LinearLayoutCompat mMessageContainer;\n    private MaterialTextView mMessageView;\n    private RelativeLayout mActionContainer;\n    private MaterialButton mActionPrimary;\n    private MaterialButton mActionSecondary;\n    private MaterialButton mActionMore;\n    private DialogTitleBuilder mDialogTitleBuilder;\n\n    @NonNull\n    @Override\n    public final View initRootView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {\n        View view = inflater.inflate(R.layout.dialog_bottom_sheet_alert, container, false);\n        mDialogTitleBuilder = new DialogTitleBuilder(view.getContext());\n        mMessageContainer = view.findViewById(R.id.container);\n        mMessageView = view.findViewById(android.R.id.text1);\n        mActionContainer = view.findViewById(R.id.action_container);\n        mActionPrimary = view.findViewById(R.id.action_primary);\n        mActionSecondary = view.findViewById(R.id.action_secondary);\n        mActionMore = view.findViewById(R.id.action_more);\n        return view;\n    }\n\n    @CallSuper\n    @Override\n    public void onBodyInitialized(@NonNull View bodyView, @Nullable Bundle savedInstanceState) {\n        Bundle args = getArguments();\n        if (args != null) {\n            CharSequence title = args.getCharSequence(ARG_TITLE);\n            CharSequence subtitle = args.getCharSequence(ARG_SUBTITLE);\n            CharSequence message = args.getCharSequence(ARG_MESSAGE);\n            if (title != null) {\n                setTitle(title);\n            }\n            if (subtitle != null) {\n                setSubtitle(subtitle);\n            }\n            if (message != null) {\n                setMessage(message);\n            }\n        }\n    }\n\n    public void setTitle(@StringRes int title) {\n        mDialogTitleBuilder.setTitle(title);\n        setHeader(mDialogTitleBuilder.build());\n    }\n\n    public void setTitle(@Nullable CharSequence title) {\n        mDialogTitleBuilder.setTitle(title);\n        setHeader(mDialogTitleBuilder.build());\n    }\n\n    public void setSubtitle(@StringRes int subtitle) {\n        mDialogTitleBuilder.setSubtitle(subtitle);\n        setHeader(mDialogTitleBuilder.build());\n    }\n\n    public void setSubtitle(@Nullable CharSequence subtitle) {\n        mDialogTitleBuilder.setSubtitle(subtitle);\n        setHeader(mDialogTitleBuilder.build());\n    }\n\n    public void setStartIcon(@DrawableRes int drawable) {\n        mDialogTitleBuilder.setStartIcon(drawable);\n        setHeader(mDialogTitleBuilder.build());\n    }\n\n    public void setStartIcon(@Nullable Drawable drawable) {\n        mDialogTitleBuilder.setStartIcon(drawable);\n        setHeader(mDialogTitleBuilder.build());\n    }\n\n    public void setEndIcon(@DrawableRes int drawable, @StringRes int contentDescription, @Nullable View.OnClickListener clickListener) {\n        mDialogTitleBuilder.setEndIcon(drawable, clickListener);\n        mDialogTitleBuilder.setEndIconContentDescription(contentDescription);\n        setHeader(mDialogTitleBuilder.build());\n    }\n\n    public void setEndIcon(@Nullable Drawable drawable, @Nullable CharSequence contentDescription, @Nullable View.OnClickListener clickListener) {\n        mDialogTitleBuilder.setEndIcon(drawable, clickListener);\n        mDialogTitleBuilder.setEndIconContentDescription(contentDescription);\n        setHeader(mDialogTitleBuilder.build());\n    }\n\n    public void setMessage(@StringRes int message) {\n        mMessageView.setText(message);\n    }\n\n    public void setMessage(@Nullable CharSequence message) {\n        mMessageView.setText(message);\n    }\n\n    public void setMessageIsSelectable(boolean selectable) {\n        mMessageView.setTextIsSelectable(selectable);\n    }\n\n    public void setMessageMovementMethod(MovementMethod movementMethod) {\n        mMessageView.setMovementMethod(movementMethod);\n    }\n\n    public void setPrimaryAction(@StringRes int title, @Nullable View.OnClickListener onClickListener) {\n        if (mActionContainer.getVisibility() == View.GONE) {\n            mActionContainer.setVisibility(View.VISIBLE);\n        }\n        if (mActionPrimary.getVisibility() == View.GONE) {\n            mActionPrimary.setVisibility(View.VISIBLE);\n        }\n        mActionPrimary.setText(title);\n        mActionPrimary.setOnClickListener(onClickListener);\n    }\n\n    public void setPrimaryAction(@Nullable CharSequence title, @Nullable View.OnClickListener onClickListener) {\n        if (mActionContainer.getVisibility() == View.GONE) {\n            mActionContainer.setVisibility(View.VISIBLE);\n        }\n        if (mActionPrimary.getVisibility() == View.GONE) {\n            mActionPrimary.setVisibility(View.VISIBLE);\n        }\n        mActionPrimary.setText(title);\n        mActionPrimary.setOnClickListener(onClickListener);\n    }\n\n    public void setSecondaryAction(@StringRes int title, @Nullable View.OnClickListener onClickListener) {\n        if (mActionContainer.getVisibility() == View.GONE) {\n            mActionContainer.setVisibility(View.VISIBLE);\n        }\n        if (mActionSecondary.getVisibility() == View.GONE) {\n            mActionSecondary.setVisibility(View.VISIBLE);\n        }\n        mActionSecondary.setText(title);\n        mActionSecondary.setOnClickListener(onClickListener);\n    }\n\n    public void setSecondaryAction(@Nullable CharSequence title, @Nullable View.OnClickListener onClickListener) {\n        if (mActionContainer.getVisibility() == View.GONE) {\n            mActionContainer.setVisibility(View.VISIBLE);\n        }\n        if (mActionSecondary.getVisibility() == View.GONE) {\n            mActionSecondary.setVisibility(View.VISIBLE);\n        }\n        mActionSecondary.setText(title);\n        mActionSecondary.setOnClickListener(onClickListener);\n    }\n\n    public void prependView(View view, LinearLayoutCompat.LayoutParams layoutParams) {\n        mMessageContainer.addView(view, 0, layoutParams);\n    }\n\n    public void appendView(View view, ViewGroup.LayoutParams layoutParams) {\n        mMessageContainer.addView(view, layoutParams);\n    }\n}\n"
  },
  {
    "path": "libcore/ui/src/main/java/io/github/muntashirakon/dialog/BottomSheetBehavior.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\n// This class is copied from material components to implement the following features:\n// 1. Add option to disable STATE_HALF_EXPANDED\n// 2. Fix layout issues when STATE_HALF_EXPANDED option is disabled\n// 3. Fix scrolling issues with ViewPager2\npackage io.github.muntashirakon.dialog;\n\nimport com.google.android.material.R;\n\nimport static androidx.annotation.RestrictTo.Scope.LIBRARY_GROUP;\nimport static java.lang.Math.max;\nimport static java.lang.Math.min;\n\nimport android.animation.ValueAnimator;\nimport android.animation.ValueAnimator.AnimatorUpdateListener;\nimport android.annotation.SuppressLint;\nimport android.content.Context;\nimport android.content.res.ColorStateList;\nimport android.content.res.TypedArray;\nimport android.os.Build;\nimport android.os.Build.VERSION;\nimport android.os.Build.VERSION_CODES;\nimport android.os.Parcel;\nimport android.os.Parcelable;\nimport android.util.AttributeSet;\nimport android.util.Log;\nimport android.util.SparseIntArray;\nimport android.util.TypedValue;\nimport android.view.MotionEvent;\nimport android.view.VelocityTracker;\nimport android.view.View;\nimport android.view.View.MeasureSpec;\nimport android.view.ViewConfiguration;\nimport android.view.ViewGroup;\nimport android.view.ViewGroup.MarginLayoutParams;\nimport android.view.ViewParent;\nimport android.view.accessibility.AccessibilityEvent;\nimport androidx.annotation.FloatRange;\nimport androidx.annotation.IntDef;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.Px;\nimport androidx.annotation.RestrictTo;\nimport androidx.annotation.StringRes;\nimport androidx.annotation.VisibleForTesting;\nimport androidx.coordinatorlayout.widget.CoordinatorLayout;\nimport androidx.coordinatorlayout.widget.CoordinatorLayout.LayoutParams;\nimport androidx.core.graphics.Insets;\nimport androidx.core.math.MathUtils;\nimport androidx.core.view.ViewCompat;\nimport androidx.core.view.WindowInsetsCompat;\nimport androidx.core.view.accessibility.AccessibilityNodeInfoCompat;\nimport androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat;\nimport androidx.core.view.accessibility.AccessibilityViewCommand;\nimport androidx.customview.view.AbsSavedState;\nimport androidx.customview.widget.ViewDragHelper;\nimport androidx.recyclerview.widget.RecyclerView;\nimport androidx.viewpager.widget.ViewPager;\nimport androidx.viewpager2.widget.ViewPager2;\nimport com.google.android.material.internal.ViewUtils;\nimport com.google.android.material.internal.ViewUtils.RelativePadding;\nimport com.google.android.material.resources.MaterialResources;\nimport com.google.android.material.shape.MaterialShapeDrawable;\nimport com.google.android.material.shape.ShapeAppearanceModel;\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\nimport java.lang.ref.WeakReference;\nimport java.lang.reflect.Field;\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.Map;\n\n/**\n * An interaction behavior plugin for a child view of {@link CoordinatorLayout} to make it work as a\n * bottom sheet.\n *\n * <p>To send useful accessibility events, set a title on bottom sheets that are windows or are\n * window-like. For BottomSheetDialog use {@link BottomSheetDialog#setTitle(int)}, and for\n * BottomSheetDialogFragment use {@link ViewCompat#setAccessibilityPaneTitle(View, CharSequence)}.\n */\npublic class BottomSheetBehavior<V extends View> extends CoordinatorLayout.Behavior<V> {\n\n    /** Callback for monitoring events about bottom sheets. */\n    public abstract static class BottomSheetCallback {\n\n        /**\n         * Called when the bottom sheet changes its state.\n         *\n         * @param bottomSheet The bottom sheet view.\n         * @param newState The new state. This will be one of {@link #STATE_DRAGGING}, {@link\n         *     #STATE_SETTLING}, {@link #STATE_EXPANDED}, {@link #STATE_COLLAPSED}, {@link\n         *     #STATE_HIDDEN}, or {@link #STATE_HALF_EXPANDED}.\n         */\n        public abstract void onStateChanged(@NonNull View bottomSheet, @State int newState);\n\n        /**\n         * Called when the bottom sheet is being dragged.\n         *\n         * @param bottomSheet The bottom sheet view.\n         * @param slideOffset The new offset of this bottom sheet within [-1,1] range. Offset increases\n         *     as this bottom sheet is moving upward. From 0 to 1 the sheet is between collapsed and\n         *     expanded states and from -1 to 0 it is between hidden and collapsed states.\n         */\n        public abstract void onSlide(@NonNull View bottomSheet, float slideOffset);\n\n        void onLayout(@NonNull View bottomSheet) {}\n    }\n\n    /** The bottom sheet is dragging. */\n    public static final int STATE_DRAGGING = 1;\n\n    /** The bottom sheet is settling. */\n    public static final int STATE_SETTLING = 2;\n\n    /** The bottom sheet is expanded. */\n    public static final int STATE_EXPANDED = 3;\n\n    /** The bottom sheet is collapsed. */\n    public static final int STATE_COLLAPSED = 4;\n\n    /** The bottom sheet is hidden. */\n    public static final int STATE_HIDDEN = 5;\n\n    /** The bottom sheet is half-expanded (used when fitToContents is false). */\n    public static final int STATE_HALF_EXPANDED = 6;\n\n    /** @hide */\n    @RestrictTo(LIBRARY_GROUP)\n    @IntDef({\n            STATE_EXPANDED,\n            STATE_COLLAPSED,\n            STATE_DRAGGING,\n            STATE_SETTLING,\n            STATE_HIDDEN,\n            STATE_HALF_EXPANDED\n    })\n    @Retention(RetentionPolicy.SOURCE)\n    public @interface State {}\n\n    /**\n     * Stable states that can be set by the {@link #setState(int)} method. These includes all the\n     * possible states a bottom sheet can be in when it's settled.\n     *\n     * @hide\n     */\n    @RestrictTo(LIBRARY_GROUP)\n    @IntDef({STATE_EXPANDED, STATE_COLLAPSED, STATE_HIDDEN, STATE_HALF_EXPANDED})\n    @Retention(RetentionPolicy.SOURCE)\n    public @interface StableState {}\n\n    /**\n     * Peek at the 16:9 ratio keyline of its parent.\n     *\n     * <p>This can be used as a parameter for {@link #setPeekHeight(int)}. {@link #getPeekHeight()}\n     * will return this when the value is set.\n     */\n    public static final int PEEK_HEIGHT_AUTO = -1;\n\n    /** This flag will preserve the peekHeight int value on configuration change. */\n    public static final int SAVE_PEEK_HEIGHT = 0x1;\n\n    /** This flag will preserve the fitToContents boolean value on configuration change. */\n    public static final int SAVE_FIT_TO_CONTENTS = 1 << 1;\n\n    /** This flag will preserve the hideable boolean value on configuration change. */\n    public static final int SAVE_HIDEABLE = 1 << 2;\n\n    /** This flag will preserve the skipCollapsed boolean value on configuration change. */\n    public static final int SAVE_SKIP_COLLAPSED = 1 << 3;\n\n    // BEGIN AppManager-added: Add SAVE_SKIP_HALF_EXPANDED flag\n    /**  This flag will preserve the skipHalfExpanded boolean value on configuration change. */\n    public static final int SAVE_SKIP_HALF_EXPANDED = 1 << 4;\n    // END AppManager-added: Add SAVE_SKIP_HALF_EXPANDED flag\n\n    /** This flag will preserve all aforementioned values on configuration change. */\n    public static final int SAVE_ALL = -1;\n\n    /**\n     * This flag will not preserve the aforementioned values set at runtime if the view is destroyed\n     * and recreated. The only value preserved will be the positional state, e.g. collapsed, hidden,\n     * expanded, etc. This is the default behavior.\n     */\n    public static final int SAVE_NONE = 0;\n\n    /** @hide */\n    @RestrictTo(LIBRARY_GROUP)\n    @IntDef(\n            flag = true,\n            value = {\n                    SAVE_PEEK_HEIGHT,\n                    SAVE_FIT_TO_CONTENTS,\n                    SAVE_HIDEABLE,\n                    SAVE_SKIP_COLLAPSED,\n                    SAVE_ALL,\n                    SAVE_NONE,\n            })\n    @Retention(RetentionPolicy.SOURCE)\n    public @interface SaveFlags {}\n\n    private static final String TAG = \"BottomSheetBehavior\";\n\n    @SaveFlags private int saveFlags = SAVE_NONE;\n\n    @VisibleForTesting static final int DEFAULT_SIGNIFICANT_VEL_THRESHOLD = 500;\n\n    private static final float HIDE_THRESHOLD = 0.5f;\n\n    private static final float HIDE_FRICTION = 0.1f;\n\n    private static final int CORNER_ANIMATION_DURATION = 500;\n\n    private static final int NO_MAX_SIZE = -1;\n\n    private static final int VIEW_INDEX_BOTTOM_SHEET = 0;\n\n    @VisibleForTesting\n    static final int VIEW_INDEX_ACCESSIBILITY_DELEGATE_VIEW = 1;\n\n    private boolean fitToContents = true;\n\n    private boolean updateImportantForAccessibilityOnSiblings = false;\n\n    private float maximumVelocity;\n\n    private int significantVelocityThreshold;\n\n    /** Peek height set by the user. */\n    private int peekHeight;\n\n    /** Whether or not to use automatic peek height. */\n    private boolean peekHeightAuto;\n\n    /** Minimum peek height permitted. */\n    private int peekHeightMin;\n\n    /** Peek height gesture inset buffer to ensure enough swipeable space. */\n    private int peekHeightGestureInsetBuffer;\n\n    private MaterialShapeDrawable materialShapeDrawable;\n\n    @Nullable private ColorStateList backgroundTint;\n\n    private int maxWidth = NO_MAX_SIZE;\n\n    private int maxHeight = NO_MAX_SIZE;\n\n    private int gestureInsetBottom;\n    private boolean gestureInsetBottomIgnored;\n    private boolean paddingBottomSystemWindowInsets;\n    private boolean paddingLeftSystemWindowInsets;\n    private boolean paddingRightSystemWindowInsets;\n    private boolean paddingTopSystemWindowInsets;\n    private boolean marginLeftSystemWindowInsets;\n    private boolean marginRightSystemWindowInsets;\n    private boolean marginTopSystemWindowInsets;\n\n    private int insetBottom;\n    private int insetTop;\n\n    private boolean shouldRemoveExpandedCorners;\n\n    /** Default Shape Appearance to be used in bottomsheet */\n    private ShapeAppearanceModel shapeAppearanceModelDefault;\n\n    private boolean expandedCornersRemoved;\n\n    private final StateSettlingTracker stateSettlingTracker = new StateSettlingTracker();\n\n    @Nullable private ValueAnimator interpolatorAnimator;\n\n    private static final int DEF_STYLE_RES = R.style.Widget_Design_BottomSheet_Modal;\n\n    int expandedOffset;\n\n    int fitToContentsOffset;\n\n    int halfExpandedOffset;\n\n    float halfExpandedRatio = 0.5f;\n\n    int collapsedOffset;\n\n    float elevation = -1;\n\n    boolean hideable;\n\n    private boolean skipCollapsed;\n\n    // AppManager-added: skipHalfExpanded\n    private boolean skipHalfExpanded = false;\n\n    private boolean draggable = true;\n\n    @State int state = STATE_COLLAPSED;\n\n    @State int lastStableState = STATE_COLLAPSED;\n\n    @Nullable ViewDragHelper viewDragHelper;\n\n    private boolean ignoreEvents;\n\n    private int lastNestedScrollDy;\n\n    private boolean nestedScrolled;\n\n    private float hideFriction = HIDE_FRICTION;\n\n    private int childHeight;\n    int parentWidth;\n    int parentHeight;\n\n    @Nullable WeakReference<V> viewRef;\n    @Nullable WeakReference<View> accessibilityDelegateViewRef;\n\n    @Nullable WeakReference<View> nestedScrollingChildRef;\n\n    @NonNull private final ArrayList<BottomSheetCallback> callbacks = new ArrayList<>();\n\n    @Nullable private VelocityTracker velocityTracker;\n\n    int activePointerId;\n\n    private int initialY;\n\n    boolean touchingScrollingChild;\n\n    @Nullable private Map<View, Integer> importantForAccessibilityMap;\n\n    @VisibleForTesting\n    final SparseIntArray expandHalfwayActionIds = new SparseIntArray();\n\n    public BottomSheetBehavior() {}\n\n    @SuppressLint(\"RestrictedApi\")\n    public BottomSheetBehavior(@NonNull Context context, @Nullable AttributeSet attrs) {\n        super(context, attrs);\n\n        peekHeightGestureInsetBuffer =\n                context.getResources().getDimensionPixelSize(R.dimen.mtrl_min_touch_target_size);\n\n        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.BottomSheetBehavior_Layout);\n        if (a.hasValue(R.styleable.BottomSheetBehavior_Layout_backgroundTint)) {\n            this.backgroundTint = MaterialResources.getColorStateList(\n                    context, a, R.styleable.BottomSheetBehavior_Layout_backgroundTint);\n        }\n        if (a.hasValue(R.styleable.BottomSheetBehavior_Layout_shapeAppearance)) {\n            this.shapeAppearanceModelDefault =\n                    ShapeAppearanceModel.builder(context, attrs, R.attr.bottomSheetStyle, DEF_STYLE_RES)\n                            .build();\n        }\n        createMaterialShapeDrawableIfNeeded(context);\n        createShapeValueAnimator();\n\n        if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {\n            this.elevation = a.getDimension(R.styleable.BottomSheetBehavior_Layout_android_elevation, -1);\n        }\n\n        if (a.hasValue(R.styleable.BottomSheetBehavior_Layout_android_maxWidth)) {\n            setMaxWidth(\n                    a.getDimensionPixelSize(\n                            R.styleable.BottomSheetBehavior_Layout_android_maxWidth, NO_MAX_SIZE));\n        }\n\n        if (a.hasValue(R.styleable.BottomSheetBehavior_Layout_android_maxHeight)) {\n            setMaxHeight(\n                    a.getDimensionPixelSize(\n                            R.styleable.BottomSheetBehavior_Layout_android_maxHeight, NO_MAX_SIZE));\n        }\n\n        TypedValue value = a.peekValue(R.styleable.BottomSheetBehavior_Layout_behavior_peekHeight);\n        if (value != null && value.data == PEEK_HEIGHT_AUTO) {\n            setPeekHeight(value.data);\n        } else {\n            setPeekHeight(\n                    a.getDimensionPixelSize(\n                            R.styleable.BottomSheetBehavior_Layout_behavior_peekHeight, PEEK_HEIGHT_AUTO));\n        }\n        setHideable(a.getBoolean(R.styleable.BottomSheetBehavior_Layout_behavior_hideable, false));\n        setGestureInsetBottomIgnored(\n                a.getBoolean(R.styleable.BottomSheetBehavior_Layout_gestureInsetBottomIgnored, false));\n        setFitToContents(\n                a.getBoolean(R.styleable.BottomSheetBehavior_Layout_behavior_fitToContents, true));\n        setSkipCollapsed(\n                a.getBoolean(R.styleable.BottomSheetBehavior_Layout_behavior_skipCollapsed, false));\n        setDraggable(a.getBoolean(R.styleable.BottomSheetBehavior_Layout_behavior_draggable, true));\n        setSaveFlags(a.getInt(R.styleable.BottomSheetBehavior_Layout_behavior_saveFlags, SAVE_NONE));\n        setHalfExpandedRatio(\n                a.getFloat(R.styleable.BottomSheetBehavior_Layout_behavior_halfExpandedRatio, 0.5f));\n\n        value = a.peekValue(R.styleable.BottomSheetBehavior_Layout_behavior_expandedOffset);\n        if (value != null && value.type == TypedValue.TYPE_FIRST_INT) {\n            setExpandedOffset(value.data);\n        } else {\n            setExpandedOffset(\n                    a.getDimensionPixelOffset(\n                            R.styleable.BottomSheetBehavior_Layout_behavior_expandedOffset, 0));\n        }\n\n        setSignificantVelocityThreshold(\n                a.getInt(\n                        R.styleable.BottomSheetBehavior_Layout_behavior_significantVelocityThreshold,\n                        DEFAULT_SIGNIFICANT_VEL_THRESHOLD));\n\n        // Reading out if we are handling padding, so we can apply it to the content.\n        paddingBottomSystemWindowInsets =\n                a.getBoolean(R.styleable.BottomSheetBehavior_Layout_paddingBottomSystemWindowInsets, false);\n        paddingLeftSystemWindowInsets =\n                a.getBoolean(R.styleable.BottomSheetBehavior_Layout_paddingLeftSystemWindowInsets, false);\n        paddingRightSystemWindowInsets =\n                a.getBoolean(R.styleable.BottomSheetBehavior_Layout_paddingRightSystemWindowInsets, false);\n        // Setting this to false will prevent the bottomsheet from going below the status bar. Since\n        // this is a breaking change from the old behavior the default is true.\n        paddingTopSystemWindowInsets =\n                a.getBoolean(R.styleable.BottomSheetBehavior_Layout_paddingTopSystemWindowInsets, true);\n        marginLeftSystemWindowInsets =\n                a.getBoolean(R.styleable.BottomSheetBehavior_Layout_marginLeftSystemWindowInsets, false);\n        marginRightSystemWindowInsets =\n                a.getBoolean(R.styleable.BottomSheetBehavior_Layout_marginRightSystemWindowInsets, false);\n        marginTopSystemWindowInsets =\n                a.getBoolean(R.styleable.BottomSheetBehavior_Layout_marginTopSystemWindowInsets, false);\n        shouldRemoveExpandedCorners =\n                a.getBoolean(R.styleable.BottomSheetBehavior_Layout_shouldRemoveExpandedCorners, true);\n\n        a.recycle();\n        ViewConfiguration configuration = ViewConfiguration.get(context);\n        maximumVelocity = configuration.getScaledMaximumFlingVelocity();\n    }\n\n    @NonNull\n    @Override\n    public Parcelable onSaveInstanceState(@NonNull CoordinatorLayout parent, @NonNull V child) {\n        return new SavedState(super.onSaveInstanceState(parent, child), this);\n    }\n\n    @Override\n    public void onRestoreInstanceState(\n            @NonNull CoordinatorLayout parent, @NonNull V child, @NonNull Parcelable state) {\n        SavedState ss = (SavedState) state;\n        super.onRestoreInstanceState(parent, child, ss.getSuperState());\n        // Restore Optional State values designated by saveFlags\n        restoreOptionalState(ss);\n        // Intermediate states are restored as collapsed state\n        if (ss.state == STATE_DRAGGING || ss.state == STATE_SETTLING) {\n            this.state = STATE_COLLAPSED;\n            this.lastStableState = this.state;\n        } else {\n            this.state = ss.state;\n            this.lastStableState = this.state;\n        }\n    }\n\n    @Override\n    public void onAttachedToLayoutParams(@NonNull LayoutParams layoutParams) {\n        super.onAttachedToLayoutParams(layoutParams);\n        // These may already be null, but just be safe, explicitly assign them. This lets us know the\n        // first time we layout with this behavior by checking (viewRef == null).\n        viewRef = null;\n        viewDragHelper = null;\n    }\n\n    @Override\n    public void onDetachedFromLayoutParams() {\n        super.onDetachedFromLayoutParams();\n        // Release references so we don't run unnecessary codepaths while not attached to a view.\n        viewRef = null;\n        viewDragHelper = null;\n    }\n\n    @Override\n    public boolean onMeasureChild(\n            @NonNull CoordinatorLayout parent,\n            @NonNull V child,\n            int parentWidthMeasureSpec,\n            int widthUsed,\n            int parentHeightMeasureSpec,\n            int heightUsed) {\n        MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();\n        int childWidthMeasureSpec =\n                getChildMeasureSpec(\n                        parentWidthMeasureSpec,\n                        parent.getPaddingLeft()\n                                + parent.getPaddingRight()\n                                + lp.leftMargin\n                                + lp.rightMargin\n                                + widthUsed,\n                        maxWidth,\n                        lp.width);\n        int childHeightMeasureSpec =\n                getChildMeasureSpec(\n                        parentHeightMeasureSpec,\n                        parent.getPaddingTop()\n                                + parent.getPaddingBottom()\n                                + lp.topMargin\n                                + lp.bottomMargin\n                                + heightUsed,\n                        maxHeight,\n                        lp.height);\n        child.measure(childWidthMeasureSpec, childHeightMeasureSpec);\n        return true; // Child was measured\n    }\n\n    private int getChildMeasureSpec(\n            int parentMeasureSpec, int padding, int maxSize, int childDimension) {\n        int result = ViewGroup.getChildMeasureSpec(parentMeasureSpec, padding, childDimension);\n        if (maxSize == NO_MAX_SIZE) {\n            return result;\n        } else {\n            int mode = MeasureSpec.getMode(result);\n            int size = MeasureSpec.getSize(result);\n            switch (mode) {\n                case MeasureSpec.EXACTLY:\n                    return MeasureSpec.makeMeasureSpec(min(size, maxSize), MeasureSpec.EXACTLY);\n                case MeasureSpec.AT_MOST:\n                case MeasureSpec.UNSPECIFIED:\n                default:\n                    return MeasureSpec.makeMeasureSpec(\n                            size == 0 ? maxSize : min(size, maxSize), MeasureSpec.AT_MOST);\n            }\n        }\n    }\n\n    @Override\n    public boolean onLayoutChild(\n            @NonNull CoordinatorLayout parent, @NonNull final V child, int layoutDirection) {\n        if (ViewCompat.getFitsSystemWindows(parent) && !ViewCompat.getFitsSystemWindows(child)) {\n            child.setFitsSystemWindows(true);\n        }\n\n        if (viewRef == null) {\n            // First layout with this behavior.\n            peekHeightMin =\n                    parent.getResources().getDimensionPixelSize(R.dimen.design_bottom_sheet_peek_height_min);\n            setWindowInsetsListener(child);\n            viewRef = new WeakReference<>(child);\n            // Only set MaterialShapeDrawable as background if shapeTheming is enabled, otherwise will\n            // default to android:background declared in styles or layout.\n            if (materialShapeDrawable != null) {\n                ViewCompat.setBackground(child, materialShapeDrawable);\n                // Use elevation attr if set on bottomsheet; otherwise, use elevation of child view.\n                materialShapeDrawable.setElevation(\n                        elevation == -1 ? ViewCompat.getElevation(child) : elevation);\n            } else if (backgroundTint != null) {\n                ViewCompat.setBackgroundTintList(child, backgroundTint);\n            }\n            updateAccessibilityActions();\n            if (ViewCompat.getImportantForAccessibility(child)\n                    == ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_AUTO) {\n                ViewCompat.setImportantForAccessibility(child, ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_YES);\n            }\n        }\n        if (viewDragHelper == null) {\n            viewDragHelper = ViewDragHelper.create(parent, dragCallback);\n        }\n\n        int savedTop = child.getTop();\n        // First let the parent lay it out\n        parent.onLayoutChild(child, layoutDirection);\n        // Offset the bottom sheet\n        parentWidth = parent.getWidth();\n        parentHeight = parent.getHeight();\n        childHeight = child.getHeight();\n        if (parentHeight - childHeight < insetTop) {\n            if (paddingTopSystemWindowInsets) {\n                // If the bottomsheet would land in the middle of the status bar when fully expanded add\n                // extra space to make sure it goes all the way.\n                childHeight = parentHeight;\n            } else {\n                // If we don't want the bottomsheet to go under the status bar we cap its height\n                childHeight = parentHeight - insetTop;\n            }\n        }\n        fitToContentsOffset = max(0, parentHeight - childHeight);\n        calculateHalfExpandedOffset();\n        calculateCollapsedOffset();\n\n        if (state == STATE_EXPANDED) {\n            ViewCompat.offsetTopAndBottom(child, getExpandedOffset());\n        } else if (state == STATE_HALF_EXPANDED) {\n            ViewCompat.offsetTopAndBottom(child, halfExpandedOffset);\n        } else if (hideable && state == STATE_HIDDEN) {\n            ViewCompat.offsetTopAndBottom(child, parentHeight);\n        } else if (state == STATE_COLLAPSED) {\n            ViewCompat.offsetTopAndBottom(child, collapsedOffset);\n        } else if (state == STATE_DRAGGING || state == STATE_SETTLING) {\n            ViewCompat.offsetTopAndBottom(child, savedTop - child.getTop());\n        }\n        updateDrawableForTargetState(state, /* animate= */ false);\n\n        nestedScrollingChildRef = new WeakReference<>(findScrollingChild(child));\n\n        for (int i = 0; i < callbacks.size(); i++) {\n            callbacks.get(i).onLayout(child);\n        }\n        return true;\n    }\n\n    @Override\n    public boolean onInterceptTouchEvent(\n            @NonNull CoordinatorLayout parent, @NonNull V child, @NonNull MotionEvent event) {\n        if (!child.isShown() || !draggable) {\n            ignoreEvents = true;\n            return false;\n        }\n        int action = event.getActionMasked();\n        // Record the velocity\n        if (action == MotionEvent.ACTION_DOWN) {\n            reset();\n        }\n        if (velocityTracker == null) {\n            velocityTracker = VelocityTracker.obtain();\n        }\n        velocityTracker.addMovement(event);\n        switch (action) {\n            case MotionEvent.ACTION_UP:\n            case MotionEvent.ACTION_CANCEL:\n                touchingScrollingChild = false;\n                activePointerId = MotionEvent.INVALID_POINTER_ID;\n                // Reset the ignore flag\n                if (ignoreEvents) {\n                    ignoreEvents = false;\n                    return false;\n                }\n                break;\n            case MotionEvent.ACTION_DOWN:\n                int initialX = (int) event.getX();\n                initialY = (int) event.getY();\n                // Only intercept nested scrolling events here if the view not being moved by the\n                // ViewDragHelper.\n                if (state != STATE_SETTLING) {\n                    View scroll = nestedScrollingChildRef != null ? nestedScrollingChildRef.get() : null;\n                    if (scroll != null && parent.isPointInChildBounds(scroll, initialX, initialY)) {\n                        activePointerId = event.getPointerId(event.getActionIndex());\n                        touchingScrollingChild = true;\n                    }\n                }\n                ignoreEvents =\n                        activePointerId == MotionEvent.INVALID_POINTER_ID\n                                && !parent.isPointInChildBounds(child, initialX, initialY);\n                break;\n            default: // fall out\n        }\n        if (!ignoreEvents\n                && viewDragHelper != null\n                && viewDragHelper.shouldInterceptTouchEvent(event)) {\n            return true;\n        }\n        // We have to handle cases that the ViewDragHelper does not capture the bottom sheet because\n        // it is not the top most view of its parent. This is not necessary when the touch event is\n        // happening over the scrolling content as nested scrolling logic handles that case.\n        View scroll = nestedScrollingChildRef != null ? nestedScrollingChildRef.get() : null;\n        return action == MotionEvent.ACTION_MOVE\n                && scroll != null\n                && !ignoreEvents\n                && state != STATE_DRAGGING\n                && !parent.isPointInChildBounds(scroll, (int) event.getX(), (int) event.getY())\n                && viewDragHelper != null\n                && Math.abs(initialY - event.getY()) > viewDragHelper.getTouchSlop();\n    }\n\n    @Override\n    public boolean onTouchEvent(\n            @NonNull CoordinatorLayout parent, @NonNull V child, @NonNull MotionEvent event) {\n        if (!child.isShown()) {\n            return false;\n        }\n        int action = event.getActionMasked();\n        if (state == STATE_DRAGGING && action == MotionEvent.ACTION_DOWN) {\n            return true;\n        }\n        if (shouldHandleDraggingWithHelper()) {\n            viewDragHelper.processTouchEvent(event);\n        }\n        // Record the velocity\n        if (action == MotionEvent.ACTION_DOWN) {\n            reset();\n        }\n        if (velocityTracker == null) {\n            velocityTracker = VelocityTracker.obtain();\n        }\n        velocityTracker.addMovement(event);\n        // The ViewDragHelper tries to capture only the top-most View. We have to explicitly tell it\n        // to capture the bottom sheet in case it is not captured and the touch slop is passed.\n        if (shouldHandleDraggingWithHelper() && action == MotionEvent.ACTION_MOVE && !ignoreEvents) {\n            if (Math.abs(initialY - event.getY()) > viewDragHelper.getTouchSlop()) {\n                viewDragHelper.captureChildView(child, event.getPointerId(event.getActionIndex()));\n            }\n        }\n        return !ignoreEvents;\n    }\n\n    @Override\n    public boolean onStartNestedScroll(\n            @NonNull CoordinatorLayout coordinatorLayout,\n            @NonNull V child,\n            @NonNull View directTargetChild,\n            @NonNull View target,\n            int axes,\n            int type) {\n        lastNestedScrollDy = 0;\n        nestedScrolled = false;\n        return (axes & ViewCompat.SCROLL_AXIS_VERTICAL) != 0;\n    }\n\n    @Override\n    public void onNestedPreScroll(\n            @NonNull CoordinatorLayout coordinatorLayout,\n            @NonNull V child,\n            @NonNull View target,\n            int dx,\n            int dy,\n            @NonNull int[] consumed,\n            int type) {\n        if (type == ViewCompat.TYPE_NON_TOUCH) {\n            // Ignore fling here. The ViewDragHelper handles it.\n            return;\n        }\n        View scrollingChild = nestedScrollingChildRef != null ? nestedScrollingChildRef.get() : null;\n        if (isNestedScrollingCheckEnabled() && target != scrollingChild) {\n            return;\n        }\n        int currentTop = child.getTop();\n        int newTop = currentTop - dy;\n        if (dy > 0) { // Upward\n            if (newTop < getExpandedOffset()) {\n                consumed[1] = currentTop - getExpandedOffset();\n                ViewCompat.offsetTopAndBottom(child, -consumed[1]);\n                setStateInternal(STATE_EXPANDED);\n            } else {\n                if (!draggable) {\n                    // Prevent dragging\n                    return;\n                }\n\n                consumed[1] = dy;\n                ViewCompat.offsetTopAndBottom(child, -dy);\n                setStateInternal(STATE_DRAGGING);\n            }\n        } else if (dy < 0) { // Downward\n            if (!target.canScrollVertically(-1)) {\n                if (newTop <= collapsedOffset || canBeHiddenByDragging()) {\n                    if (!draggable) {\n                        // Prevent dragging\n                        return;\n                    }\n\n                    consumed[1] = dy;\n                    ViewCompat.offsetTopAndBottom(child, -dy);\n                    setStateInternal(STATE_DRAGGING);\n                } else {\n                    consumed[1] = currentTop - collapsedOffset;\n                    ViewCompat.offsetTopAndBottom(child, -consumed[1]);\n                    setStateInternal(STATE_COLLAPSED);\n                }\n            }\n        }\n        dispatchOnSlide(child.getTop());\n        lastNestedScrollDy = dy;\n        nestedScrolled = true;\n    }\n\n    @Override\n    public void onStopNestedScroll(\n            @NonNull CoordinatorLayout coordinatorLayout,\n            @NonNull V child,\n            @NonNull View target,\n            int type) {\n        if (child.getTop() == getExpandedOffset()) {\n            setStateInternal(STATE_EXPANDED);\n            return;\n        }\n        if (isNestedScrollingCheckEnabled()\n                && (nestedScrollingChildRef == null\n                || target != nestedScrollingChildRef.get()\n                || !nestedScrolled)) {\n            return;\n        }\n        @StableState int targetState;\n        if (lastNestedScrollDy > 0) {\n            if (fitToContents) {\n                targetState = STATE_EXPANDED;\n            } else {\n                int currentTop = child.getTop();\n                // BEGIN AppManager-changed: Handle skipHalfExpanded\n                //if (currentTop > halfExpandedOffset) {\n                if (!shouldSkipHalfExpandedStateWhenDragging() && currentTop > halfExpandedOffset) {\n                    targetState = STATE_HALF_EXPANDED;\n                } else {\n                    targetState = STATE_EXPANDED;\n                }\n                // END AppManager-changed: Handle skipHalfExpanded\n            }\n        } else if (hideable && shouldHide(child, getYVelocity())) {\n            targetState = STATE_HIDDEN;\n        } else if (lastNestedScrollDy == 0) {\n            int currentTop = child.getTop();\n            if (fitToContents) {\n                if (Math.abs(currentTop - fitToContentsOffset) < Math.abs(currentTop - collapsedOffset)) {\n                    targetState = STATE_EXPANDED;\n                } else {\n                    targetState = STATE_COLLAPSED;\n                }\n            } else {\n                if (currentTop < halfExpandedOffset) {\n                    if (currentTop < Math.abs(currentTop - collapsedOffset)) {\n                        targetState = STATE_EXPANDED;\n                    } else {\n                        if (shouldSkipHalfExpandedStateWhenDragging()) {\n                            targetState = STATE_COLLAPSED;\n                        } else {\n                            targetState = STATE_HALF_EXPANDED;\n                        }\n                    }\n                } else {\n                    // BEGIN AppManager-changed: Handle skipHalfExpanded\n                    //if (Math.abs(currentTop - halfExpandedOffset) < Math.abs(currentTop - collapsedOffset)) {\n                    if (!shouldSkipHalfExpandedStateWhenDragging()\n                            && Math.abs(currentTop - halfExpandedOffset) < Math.abs(currentTop - collapsedOffset)) {\n                        targetState = STATE_HALF_EXPANDED;\n                    } else {\n                        targetState = STATE_COLLAPSED;\n                    }\n                    // END AppManager-changed: Handle skipHalfExpanded\n                }\n            }\n        } else {\n            if (fitToContents) {\n                targetState = STATE_COLLAPSED;\n            } else {\n                // Settle to nearest height.\n                int currentTop = child.getTop();\n                // BEGIN AppManager-changed: Handle skipHalfExpanded\n                //if (Math.abs(currentTop - halfExpandedOffset) < Math.abs(currentTop - collapsedOffset)) {\n                if (!shouldSkipHalfExpandedStateWhenDragging()\n                        && Math.abs(currentTop - halfExpandedOffset) < Math.abs(currentTop - collapsedOffset)) {\n                    targetState = STATE_HALF_EXPANDED;\n                } else {\n                    targetState = STATE_COLLAPSED;\n                }\n                // END AppManager-changed: Handle skipHalfExpanded\n            }\n        }\n        startSettling(child, targetState, false);\n        nestedScrolled = false;\n    }\n\n    @Override\n    public void onNestedScroll(\n            @NonNull CoordinatorLayout coordinatorLayout,\n            @NonNull V child,\n            @NonNull View target,\n            int dxConsumed,\n            int dyConsumed,\n            int dxUnconsumed,\n            int dyUnconsumed,\n            int type,\n            @NonNull int[] consumed) {\n        // Overridden to prevent the default consumption of the entire scroll distance.\n    }\n\n    @Override\n    public boolean onNestedPreFling(\n            @NonNull CoordinatorLayout coordinatorLayout,\n            @NonNull V child,\n            @NonNull View target,\n            float velocityX,\n            float velocityY) {\n\n        if (isNestedScrollingCheckEnabled() && nestedScrollingChildRef != null) {\n            return target == nestedScrollingChildRef.get()\n                    && (state != STATE_EXPANDED\n                    || super.onNestedPreFling(coordinatorLayout, child, target, velocityX, velocityY));\n        } else {\n            return false;\n        }\n    }\n\n    /**\n     * @return whether the height of the expanded sheet is determined by the height of its contents,\n     *     or if it is expanded in two stages (half the height of the parent container, full height of\n     *     parent container).\n     */\n    public boolean isFitToContents() {\n        return fitToContents;\n    }\n\n    /**\n     * Sets whether the height of the expanded sheet is determined by the height of its contents, or\n     * if it is expanded in two stages (half the height of the parent container, full height of parent\n     * container). Default value is true.\n     *\n     * @param fitToContents whether or not to fit the expanded sheet to its contents.\n     */\n    public void setFitToContents(boolean fitToContents) {\n        if (this.fitToContents == fitToContents) {\n            return;\n        }\n        this.fitToContents = fitToContents;\n\n        // If sheet is already laid out, recalculate the collapsed offset based on new setting.\n        // Otherwise, let onLayoutChild handle this later.\n        if (viewRef != null) {\n            calculateCollapsedOffset();\n        }\n        // Fix incorrect expanded settings depending on whether or not we are fitting sheet to contents.\n        setStateInternal((this.fitToContents && state == STATE_HALF_EXPANDED) ? STATE_EXPANDED : state);\n\n        updateDrawableForTargetState(state, /* animate= */ true);\n        updateAccessibilityActions();\n    }\n\n    /**\n     * Sets the maximum width of the bottom sheet. The layout will be at most this dimension wide.\n     * This method should be called before {@link BottomSheetDialog#show()} in order for the width to\n     * be adjusted as expected.\n     *\n     * @param maxWidth The maximum width in pixels to be set\n     * @attr ref com.google.android.material.R.styleable#BottomSheetBehavior_Layout_android_maxWidth\n     * @see #getMaxWidth()\n     */\n    public void setMaxWidth(@Px int maxWidth) {\n        this.maxWidth = maxWidth;\n    }\n\n    /**\n     * Returns the bottom sheet's maximum width, or -1 if no maximum width is set.\n     *\n     * @attr ref com.google.android.material.R.styleable#BottomSheetBehavior_Layout_android_maxWidth\n     * @see #setMaxWidth(int)\n     */\n    @Px\n    public int getMaxWidth() {\n        return maxWidth;\n    }\n\n    /**\n     * Sets the maximum height of the bottom sheet. This method should be called before {@link\n     * BottomSheetDialog#show()} in order for the height to be adjusted as expected.\n     *\n     * @param maxHeight The maximum height in pixels to be set\n     * @attr ref com.google.android.material.R.styleable#BottomSheetBehavior_Layout_android_maxHeight\n     * @see #getMaxHeight()\n     */\n    public void setMaxHeight(@Px int maxHeight) {\n        this.maxHeight = maxHeight;\n    }\n\n    /**\n     * Returns the bottom sheet's maximum height, or -1 if no maximum height is set.\n     *\n     * @attr ref com.google.android.material.R.styleable#BottomSheetBehavior_Layout_android_maxHeight\n     * @see #setMaxHeight(int)\n     */\n    @Px\n    public int getMaxHeight() {\n        return maxHeight;\n    }\n\n    /**\n     * Sets the height of the bottom sheet when it is collapsed.\n     *\n     * @param peekHeight The height of the collapsed bottom sheet in pixels, or {@link\n     *     #PEEK_HEIGHT_AUTO} to configure the sheet to peek automatically at 16:9 ratio keyline.\n     * @attr ref\n     *     com.google.android.material.R.styleable#BottomSheetBehavior_Layout_behavior_peekHeight\n     */\n    public void setPeekHeight(int peekHeight) {\n        setPeekHeight(peekHeight, false);\n    }\n\n    /**\n     * Sets the height of the bottom sheet when it is collapsed while optionally animating between the\n     * old height and the new height.\n     *\n     * @param peekHeight The height of the collapsed bottom sheet in pixels, or {@link\n     *     #PEEK_HEIGHT_AUTO} to configure the sheet to peek automatically at 16:9 ratio keyline.\n     * @param animate Whether to animate between the old height and the new height.\n     * @attr ref\n     *     com.google.android.material.R.styleable#BottomSheetBehavior_Layout_behavior_peekHeight\n     */\n    public final void setPeekHeight(int peekHeight, boolean animate) {\n        boolean layout = false;\n        if (peekHeight == PEEK_HEIGHT_AUTO) {\n            if (!peekHeightAuto) {\n                peekHeightAuto = true;\n                layout = true;\n            }\n        } else if (peekHeightAuto || this.peekHeight != peekHeight) {\n            peekHeightAuto = false;\n            this.peekHeight = max(0, peekHeight);\n            layout = true;\n        }\n        // If sheet is already laid out, recalculate the collapsed offset based on new setting.\n        // Otherwise, let onLayoutChild handle this later.\n        if (layout) {\n            updatePeekHeight(animate);\n        }\n    }\n\n    private void updatePeekHeight(boolean animate) {\n        if (viewRef != null) {\n            calculateCollapsedOffset();\n            if (state == STATE_COLLAPSED) {\n                V view = viewRef.get();\n                if (view != null) {\n                    if (animate) {\n                        setState(STATE_COLLAPSED);\n                    } else {\n                        view.requestLayout();\n                    }\n                }\n            }\n        }\n    }\n\n    /**\n     * Gets the height of the bottom sheet when it is collapsed.\n     *\n     * @return The height of the collapsed bottom sheet in pixels, or {@link #PEEK_HEIGHT_AUTO} if the\n     *     sheet is configured to peek automatically at 16:9 ratio keyline\n     * @attr ref\n     *     com.google.android.material.R.styleable#BottomSheetBehavior_Layout_behavior_peekHeight\n     */\n    public int getPeekHeight() {\n        return peekHeightAuto ? PEEK_HEIGHT_AUTO : peekHeight;\n    }\n\n    /**\n     * Determines the height of the BottomSheet in the {@link #STATE_HALF_EXPANDED} state. The\n     * material guidelines recommended a value of 0.5, which results in the sheet filling half of the\n     * parent. The height of the BottomSheet will be smaller as this ratio is decreased and taller as\n     * it is increased. The default value is 0.5.\n     *\n     * @param ratio a float between 0 and 1, representing the {@link #STATE_HALF_EXPANDED} ratio.\n     * @attr ref\n     *     com.google.android.material.R.styleable#BottomSheetBehavior_Layout_behavior_halfExpandedRatio\n     */\n    public void setHalfExpandedRatio(\n            @FloatRange(from = 0.0f, to = 1.0f, fromInclusive = false, toInclusive = false) float ratio) {\n\n        if ((ratio <= 0) || (ratio >= 1)) {\n            throw new IllegalArgumentException(\"ratio must be a float value between 0 and 1\");\n        }\n        this.halfExpandedRatio = ratio;\n        // If sheet is already laid out, recalculate the half expanded offset based on new setting.\n        // Otherwise, let onLayoutChild handle this later.\n        if (viewRef != null) {\n            calculateHalfExpandedOffset();\n        }\n    }\n\n    /**\n     * Gets the ratio for the height of the BottomSheet in the {@link #STATE_HALF_EXPANDED} state.\n     *\n     * @attr ref\n     *     com.google.android.material.R.styleable#BottomSheetBehavior_Layout_behavior_halfExpandedRatio\n     */\n    @FloatRange(from = 0.0f, to = 1.0f)\n    public float getHalfExpandedRatio() {\n        return halfExpandedRatio;\n    }\n\n    /**\n     * Determines the top offset of the BottomSheet in the {@link #STATE_EXPANDED} state when\n     * fitsToContent is false. The default value is 0, which results in the sheet matching the\n     * parent's top.\n     *\n     * @param offset an integer value greater than equal to 0, representing the {@link\n     *     #STATE_EXPANDED} offset. Value must not exceed the offset in the half expanded state.\n     * @attr ref\n     *     com.google.android.material.R.styleable#BottomSheetBehavior_Layout_behavior_expandedOffset\n     */\n    public void setExpandedOffset(int offset) {\n        if (offset < 0) {\n            throw new IllegalArgumentException(\"offset must be greater than or equal to 0\");\n        }\n        this.expandedOffset = offset;\n        updateDrawableForTargetState(state, /* animate= */ true);\n    }\n\n    /**\n     * Returns the current expanded offset. If {@code fitToContents} is true, it will automatically\n     * pick the offset depending on the height of the content.\n     *\n     * @attr ref\n     *     com.google.android.material.R.styleable#BottomSheetBehavior_Layout_behavior_expandedOffset\n     */\n    public int getExpandedOffset() {\n        return fitToContents\n                ? fitToContentsOffset\n                : Math.max(expandedOffset, paddingTopSystemWindowInsets ? 0 : insetTop);\n    }\n\n    /**\n     * Calculates the current offset of the bottom sheet.\n     *\n     * This method should be called when the child view is laid out.\n     *\n     * @return The offset of this bottom sheet within [-1,1] range. Offset increases\n     * as this bottom sheet is moving upward. From 0 to 1 the sheet is between collapsed and\n     * expanded states and from -1 to 0 it is between hidden and collapsed states. Returns\n     * -1 if the bottom sheet is not laid out (therefore it's hidden).\n     */\n    public float calculateSlideOffset() {\n        if (viewRef == null || viewRef.get() == null) {\n            return -1;\n        }\n\n        return calculateSlideOffsetWithTop(viewRef.get().getTop());\n    }\n\n    /**\n     * Sets whether this bottom sheet can hide.\n     *\n     * @param hideable {@code true} to make this bottom sheet hideable.\n     * @attr ref com.google.android.material.R.styleable#BottomSheetBehavior_Layout_behavior_hideable\n     */\n    public void setHideable(boolean hideable) {\n        if (this.hideable != hideable) {\n            this.hideable = hideable;\n            if (!hideable && state == STATE_HIDDEN) {\n                // Lift up to collapsed state\n                setState(STATE_COLLAPSED);\n            }\n            updateAccessibilityActions();\n        }\n    }\n\n    /**\n     * Gets whether this bottom sheet can hide when it is swiped down.\n     *\n     * @return {@code true} if this bottom sheet can hide.\n     * @attr ref com.google.android.material.R.styleable#BottomSheetBehavior_Layout_behavior_hideable\n     */\n    public boolean isHideable() {\n        return hideable;\n    }\n\n    /**\n     * Sets whether this bottom sheet should skip the collapsed state when it is being hidden after it\n     * is expanded once. Setting this to true has no effect unless the sheet is hideable.\n     *\n     * @param skipCollapsed True if the bottom sheet should skip the collapsed state.\n     * @attr ref\n     *     com.google.android.material.R.styleable#BottomSheetBehavior_Layout_behavior_skipCollapsed\n     */\n    public void setSkipCollapsed(boolean skipCollapsed) {\n        this.skipCollapsed = skipCollapsed;\n    }\n\n    /**\n     * Sets whether this bottom sheet should skip the collapsed state when it is being hidden after it\n     * is expanded once.\n     *\n     * @return Whether the bottom sheet should skip the collapsed state.\n     * @attr ref\n     *     com.google.android.material.R.styleable#BottomSheetBehavior_Layout_behavior_skipCollapsed\n     */\n    public boolean getSkipCollapsed() {\n        return skipCollapsed;\n    }\n\n    // BEGIN AppManager-added: skipHalfExpanded\n    /**\n     * Sets whether this bottom sheet should skip the half-expanded state.\n     *\n     * @param skipHalfExpanded True if the bottom sheet should skip the half-expanded state.\n     */\n    public void setSkipHalfExpanded(boolean skipHalfExpanded) {\n        this.skipHalfExpanded = skipHalfExpanded;\n    }\n\n    /**\n     * Sets whether this bottom sheet should skip the half-expanded state.\n     *\n     * @return Whether the bottom sheet should skip the half-expanded state.\n     */\n    public boolean getSkipHalfExpanded() {\n        return skipHalfExpanded;\n    }\n    // END AppManager-added: skipHalfExpanded\n\n    /**\n     * Sets whether this bottom sheet is can be collapsed/expanded by dragging. Note: When disabling\n     * dragging, an app will require to implement a custom way to expand/collapse the bottom sheet\n     *\n     * @param draggable {@code false} to prevent dragging the sheet to collapse and expand\n     * @attr ref com.google.android.material.R.styleable#BottomSheetBehavior_Layout_behavior_draggable\n     */\n    public void setDraggable(boolean draggable) {\n        this.draggable = draggable;\n    }\n\n    public boolean isDraggable() {\n        return draggable;\n    }\n\n    /*\n     * Sets the velocity threshold considered significant enough to trigger a slide\n     * to the next stable state.\n     *\n     * @param significantVelocityThreshold The velocity threshold that warrants a vertical swipe.\n     * @see #getSignificantVelocityThreshold()\n     * @attr ref com.google.android.material.R.styleable#BottomSheetBehavior_Layout_behavior_significantVelocityThreshold\n     */\n    public void setSignificantVelocityThreshold(int significantVelocityThreshold) {\n        this.significantVelocityThreshold = significantVelocityThreshold;\n    }\n\n    /*\n     * Returns the significant velocity threshold.\n     *\n     * @see #setSignificantVelocityThreshold(int)\n     * @attr ref com.google.android.material.R.styleable#BottomSheetBehavior_Layout_behavior_significantVelocityThreshold\n     */\n    public int getSignificantVelocityThreshold() {\n        return this.significantVelocityThreshold;\n    }\n\n    /**\n     * Sets save flags to be preserved in bottomsheet on configuration change.\n     *\n     * @param flags bitwise int of {@link #SAVE_PEEK_HEIGHT}, {@link #SAVE_FIT_TO_CONTENTS}, {@link\n     *     #SAVE_HIDEABLE}, {@link #SAVE_SKIP_COLLAPSED}, {@link #SAVE_ALL} and {@link #SAVE_NONE}.\n     * @see #getSaveFlags()\n     * @attr ref com.google.android.material.R.styleable#BottomSheetBehavior_Layout_behavior_saveFlags\n     */\n    public void setSaveFlags(@SaveFlags int flags) {\n        this.saveFlags = flags;\n    }\n    /**\n     * Returns the save flags.\n     *\n     * @see #setSaveFlags(int)\n     * @attr ref com.google.android.material.R.styleable#BottomSheetBehavior_Layout_behavior_saveFlags\n     */\n    @SaveFlags\n    public int getSaveFlags() {\n        return this.saveFlags;\n    }\n\n    /**\n     * Sets the friction coefficient to hide the bottom sheet, or set it to the next closest\n     * expanded state.\n     *\n     * @param hideFriction The friction coefficient that determines the swipe velocity needed to\n     *  hide or set the bottom sheet to the closest expanded state.\n     */\n    public void setHideFriction(float hideFriction) {\n        this.hideFriction = hideFriction;\n    }\n\n    /**\n     * Gets the friction coefficient to hide the bottom sheet, or set it to the next closest\n     * expanded state.\n     *\n     * @return The friction coefficient that determines the swipe velocity needed to hide or set the\n     *  bottom sheet to the closest expanded state.\n     */\n    public float getHideFriction() {\n        return this.hideFriction;\n    }\n\n    /**\n     * Sets a callback to be notified of bottom sheet events.\n     *\n     * @param callback The callback to notify when bottom sheet events occur.\n     * @deprecated use {@link #addBottomSheetCallback(BottomSheetCallback)} and {@link\n     *     #removeBottomSheetCallback(BottomSheetCallback)} instead\n     */\n    @Deprecated\n    public void setBottomSheetCallback(BottomSheetCallback callback) {\n        Log.w(\n                TAG,\n                \"BottomSheetBehavior now supports multiple callbacks. `setBottomSheetCallback()` removes\"\n                        + \" all existing callbacks, including ones set internally by library authors, which\"\n                        + \" may result in unintended behavior. This may change in the future. Please use\"\n                        + \" `addBottomSheetCallback()` and `removeBottomSheetCallback()` instead to set your\"\n                        + \" own callbacks.\");\n        callbacks.clear();\n        if (callback != null) {\n            callbacks.add(callback);\n        }\n    }\n\n    /**\n     * Adds a callback to be notified of bottom sheet events.\n     *\n     * @param callback The callback to notify when bottom sheet events occur.\n     */\n    public void addBottomSheetCallback(@NonNull BottomSheetCallback callback) {\n        if (!callbacks.contains(callback)) {\n            callbacks.add(callback);\n        }\n    }\n\n    /**\n     * Removes a previously added callback.\n     *\n     * @param callback The callback to remove.\n     */\n    public void removeBottomSheetCallback(@NonNull BottomSheetCallback callback) {\n        callbacks.remove(callback);\n    }\n\n    /**\n     * Sets the state of the bottom sheet. The bottom sheet will transition to that state with\n     * animation.\n     *\n     * @param state One of {@link #STATE_COLLAPSED}, {@link #STATE_EXPANDED}, {@link #STATE_HIDDEN},\n     *     or {@link #STATE_HALF_EXPANDED}.\n     */\n    public void setState(@StableState int state) {\n        if (state == STATE_DRAGGING || state == STATE_SETTLING) {\n            throw new IllegalArgumentException(\n                    \"STATE_\"\n                            + (state == STATE_DRAGGING ? \"DRAGGING\" : \"SETTLING\")\n                            + \" should not be set externally.\");\n        }\n        if (!hideable && state == STATE_HIDDEN) {\n            Log.w(TAG, \"Cannot set state: \" + state);\n            return;\n        }\n        final int finalState;\n        if (state == STATE_HALF_EXPANDED\n                && fitToContents\n                && getTopOffsetForState(state) <= fitToContentsOffset) {\n            // Skip to the expanded state if we would scroll past the height of the contents.\n            finalState = STATE_EXPANDED;\n        } else {\n            finalState = state;\n        }\n        if (viewRef == null || viewRef.get() == null) {\n            // The view is not laid out yet; modify mState and let onLayoutChild handle it later\n            setStateInternal(state);\n        } else {\n            final V child = viewRef.get();\n            runAfterLayout(\n                    child,\n                    new Runnable() {\n                        @Override\n                        public void run() {\n                            startSettling(child, finalState, false);\n                        }\n                    });\n        }\n    }\n\n    private void runAfterLayout(V child, Runnable runnable) {\n        if (isLayouting(child)) {\n            child.post(runnable);\n        } else {\n            runnable.run();\n        }\n    }\n\n    private boolean isLayouting(V child) {\n        ViewParent parent = child.getParent();\n        return parent != null && parent.isLayoutRequested() && ViewCompat.isAttachedToWindow(child);\n    }\n\n    /**\n     * Sets whether this bottom sheet should adjust it's position based on the system gesture area on\n     * Android Q and above.\n     *\n     * <p>Note: the bottom sheet will only adjust it's position if it would be unable to be scrolled\n     * upwards because the peekHeight is less than the gesture inset margins,(because that would cause\n     * a gesture conflict), gesture navigation is enabled, and this {@code ignoreGestureInsetBottom}\n     * flag is false.\n     */\n    public void setGestureInsetBottomIgnored(boolean gestureInsetBottomIgnored) {\n        this.gestureInsetBottomIgnored = gestureInsetBottomIgnored;\n    }\n\n    /**\n     * Returns whether this bottom sheet should adjust it's position based on the system gesture area.\n     */\n    public boolean isGestureInsetBottomIgnored() {\n        return gestureInsetBottomIgnored;\n    }\n\n    /**\n     * Gets the current state of the bottom sheet.\n     *\n     * @return One of {@link #STATE_EXPANDED}, {@link #STATE_HALF_EXPANDED}, {@link #STATE_COLLAPSED},\n     *     {@link #STATE_DRAGGING}, or {@link #STATE_SETTLING}.\n     */\n    @State\n    public int getState() {\n        return state;\n    }\n\n    void setStateInternal(@State int state) {\n        if (this.state == state) {\n            return;\n        }\n        // BEGIN AppManager-added: Validate state\n        if (state == STATE_HALF_EXPANDED && skipHalfExpanded) {\n            state = (lastStableState == STATE_EXPANDED) ? STATE_COLLAPSED : STATE_EXPANDED;\n        }\n        if (state == STATE_COLLAPSED && skipCollapsed) {\n            state = STATE_HIDDEN;\n        }\n        // END AppManager-added: Validate state\n        this.state = state;\n        if (state == STATE_COLLAPSED\n                || state == STATE_EXPANDED\n                || state == STATE_HALF_EXPANDED\n                || (hideable && state == STATE_HIDDEN)) {\n            this.lastStableState = state;\n        }\n\n        if (viewRef == null) {\n            return;\n        }\n\n        View bottomSheet = viewRef.get();\n        if (bottomSheet == null) {\n            return;\n        }\n\n        if (state == STATE_EXPANDED) {\n            updateImportantForAccessibility(true);\n        } else if (state == STATE_HALF_EXPANDED || state == STATE_HIDDEN || state == STATE_COLLAPSED) {\n            updateImportantForAccessibility(false);\n        }\n\n        updateDrawableForTargetState(state, /* animate= */ true);\n        for (int i = 0; i < callbacks.size(); i++) {\n            callbacks.get(i).onStateChanged(bottomSheet, state);\n        }\n        updateAccessibilityActions();\n    }\n\n    private void updateDrawableForTargetState(@State int state, boolean animate) {\n        if (state == STATE_SETTLING) {\n            // Special case: we want to know which state we're settling to, so wait for another call.\n            return;\n        }\n\n        boolean removeCorners = isExpandedAndShouldRemoveCorners();\n        if (expandedCornersRemoved == removeCorners || materialShapeDrawable == null) {\n            return;\n        }\n        expandedCornersRemoved = removeCorners;\n        if (animate && interpolatorAnimator != null) {\n            if (interpolatorAnimator.isRunning()) {\n                interpolatorAnimator.reverse();\n            } else {\n                float to = removeCorners ? 0f : 1f;\n                float from = 1f - to;\n                interpolatorAnimator.setFloatValues(from, to);\n                interpolatorAnimator.start();\n            }\n        } else {\n            if (interpolatorAnimator != null && interpolatorAnimator.isRunning()) {\n                interpolatorAnimator.cancel();\n            }\n            materialShapeDrawable.setInterpolation(expandedCornersRemoved ? 0f : 1f);\n        }\n    }\n\n    private boolean isExpandedAndShouldRemoveCorners() {\n        // Only remove corners when it's full screen.\n        return state == STATE_EXPANDED && (shouldRemoveExpandedCorners || getExpandedOffset() == 0);\n    }\n\n    private int calculatePeekHeight() {\n        if (peekHeightAuto) {\n            int desiredHeight = max(peekHeightMin, parentHeight - parentWidth * 9 / 16);\n            return min(desiredHeight, childHeight) + insetBottom;\n        }\n        // Only make sure the peek height is above the gesture insets if we're not applying system\n        // insets.\n        if (!gestureInsetBottomIgnored && !paddingBottomSystemWindowInsets && gestureInsetBottom > 0) {\n            return max(peekHeight, gestureInsetBottom + peekHeightGestureInsetBuffer);\n        }\n        return peekHeight + insetBottom;\n    }\n\n    private void calculateCollapsedOffset() {\n        int peek = calculatePeekHeight();\n\n        if (fitToContents) {\n            collapsedOffset = max(parentHeight - peek, fitToContentsOffset);\n        } else {\n            collapsedOffset = parentHeight - peek;\n        }\n    }\n\n    private void calculateHalfExpandedOffset() {\n        this.halfExpandedOffset = (int) (parentHeight * (1 - halfExpandedRatio));\n    }\n\n    private float calculateSlideOffsetWithTop(int top) {\n        return\n                (top > collapsedOffset || collapsedOffset == getExpandedOffset())\n                        ? (float) (collapsedOffset - top) / (parentHeight - collapsedOffset)\n                        : (float) (collapsedOffset - top) / (collapsedOffset - getExpandedOffset());\n    }\n\n    private void reset() {\n        activePointerId = ViewDragHelper.INVALID_POINTER;\n        if (velocityTracker != null) {\n            velocityTracker.recycle();\n            velocityTracker = null;\n        }\n    }\n\n    private void restoreOptionalState(@NonNull SavedState ss) {\n        if (this.saveFlags == SAVE_NONE) {\n            return;\n        }\n        if (this.saveFlags == SAVE_ALL || (this.saveFlags & SAVE_PEEK_HEIGHT) == SAVE_PEEK_HEIGHT) {\n            this.peekHeight = ss.peekHeight;\n        }\n        if (this.saveFlags == SAVE_ALL\n                || (this.saveFlags & SAVE_FIT_TO_CONTENTS) == SAVE_FIT_TO_CONTENTS) {\n            this.fitToContents = ss.fitToContents;\n        }\n        if (this.saveFlags == SAVE_ALL || (this.saveFlags & SAVE_HIDEABLE) == SAVE_HIDEABLE) {\n            this.hideable = ss.hideable;\n        }\n        if (this.saveFlags == SAVE_ALL\n                || (this.saveFlags & SAVE_SKIP_COLLAPSED) == SAVE_SKIP_COLLAPSED) {\n            this.skipCollapsed = ss.skipCollapsed;\n        }\n        // BEGIN AppManager-added: Restore skipHalfExpanded\n        if (this.saveFlags == SAVE_ALL\n                || (this.saveFlags & SAVE_SKIP_HALF_EXPANDED) == SAVE_SKIP_HALF_EXPANDED) {\n            this.skipHalfExpanded = ss.skipHalfExpanded;\n        }\n        // END AppManager-added: restore skipHalfExpanded\n    }\n\n    boolean shouldHide(@NonNull View child, float yvel) {\n        if (skipCollapsed) {\n            return true;\n        }\n        if (!isHideableWhenDragging()) {\n            return false;\n        }\n        if (child.getTop() < collapsedOffset) {\n            // It should not hide, but collapse.\n            return false;\n        }\n        int peek = calculatePeekHeight();\n        final float newTop = child.getTop() + yvel * hideFriction;\n        return Math.abs(newTop - collapsedOffset) / (float) peek > HIDE_THRESHOLD;\n    }\n\n    @Nullable\n    @VisibleForTesting\n    View findScrollingChild(View view) {\n        if (view.getVisibility() != View.VISIBLE) {\n            return null;\n        }\n        if (ViewCompat.isNestedScrollingEnabled(view)) {\n            return view;\n        }\n        // BEGIN AppManager-changed: Fix for ViewPagers\n        if (view instanceof ViewPager) {\n            ViewPager viewPager = (ViewPager) view;\n            for (int i = 0; i < viewPager.getChildCount(); ++i) {\n                View child = viewPager.getChildAt(i);\n                ViewPager.LayoutParams lp = (ViewPager.LayoutParams) child.getLayoutParams();\n                if (!lp.isDecor) {\n                    try {\n                        Field positionField = ViewPager.LayoutParams.class.getDeclaredField(\"position\");\n                        positionField.setAccessible(true);\n                        int position = positionField.getInt(lp);\n                        if (position == viewPager.getCurrentItem()) {\n                            View scrollingChild = findScrollingChild(child);\n                            if (scrollingChild != null) {\n                                return scrollingChild;\n                            }\n                        }\n                    } catch (Exception e) {\n                        throw new RuntimeException(e);\n                    }\n                }\n            }\n        }\n        if (view instanceof ViewPager2) {\n            View v = ((ViewPager2) view).getChildAt(0);\n            if (v instanceof RecyclerView) {\n                View v2 = ((RecyclerView) v).getFocusedChild();\n                if (v2 == null) v2 = ((RecyclerView) v).getChildAt(0);\n                if (v2 != null) {\n                    View scrollingChild = findScrollingChild(v2);\n                    if (scrollingChild != null) {\n                        return scrollingChild;\n                    }\n                }\n            }\n        }\n        // END AppManager-changed: Fix for ViewPagers\n        if (view instanceof ViewGroup) {\n            ViewGroup group = (ViewGroup) view;\n            for (int i = 0, count = group.getChildCount(); i < count; i++) {\n                View scrollingChild = findScrollingChild(group.getChildAt(i));\n                if (scrollingChild != null) {\n                    return scrollingChild;\n                }\n            }\n        }\n        return null;\n    }\n\n    // BEGIN AppManager-added: Add a way to update scrolling references to allow variable references\n    public void updateScrollingChild() {\n        if (viewRef == null) {\n            return;\n        }\n        View view = viewRef.get();\n        if (view == null) {\n            return;\n        }\n        View scrollingChild = findScrollingChild(viewRef.get());\n        nestedScrollingChildRef = new WeakReference<>(scrollingChild);\n    }\n    // END AppManager-added: Add a way to update scrolling references to allow variable references\n\n    private boolean shouldHandleDraggingWithHelper() {\n        // If it's not draggable, do not forward events to viewDragHelper; however, if it's already\n        // dragging, let it finish.\n        return viewDragHelper != null && (draggable || state == STATE_DRAGGING);\n    }\n\n    private void createMaterialShapeDrawableIfNeeded(@NonNull Context context) {\n        if (shapeAppearanceModelDefault == null) {\n            return;\n        }\n\n        this.materialShapeDrawable = new MaterialShapeDrawable(shapeAppearanceModelDefault);\n        this.materialShapeDrawable.initializeElevationOverlay(context);\n\n        if (backgroundTint != null) {\n            materialShapeDrawable.setFillColor(backgroundTint);\n        } else {\n            // If the tint isn't set, use the theme default background color.\n            TypedValue defaultColor = new TypedValue();\n            context.getTheme().resolveAttribute(android.R.attr.colorBackground, defaultColor, true);\n            materialShapeDrawable.setTint(defaultColor.data);\n        }\n    }\n\n    MaterialShapeDrawable getMaterialShapeDrawable() {\n        return materialShapeDrawable;\n    }\n\n    private void createShapeValueAnimator() {\n        interpolatorAnimator = ValueAnimator.ofFloat(0f, 1f);\n        interpolatorAnimator.setDuration(CORNER_ANIMATION_DURATION);\n        interpolatorAnimator.addUpdateListener(\n                new AnimatorUpdateListener() {\n                    @Override\n                    public void onAnimationUpdate(@NonNull ValueAnimator animation) {\n                        float value = (float) animation.getAnimatedValue();\n                        if (materialShapeDrawable != null) {\n                            materialShapeDrawable.setInterpolation(value);\n                        }\n                    }\n                });\n    }\n\n    @SuppressLint(\"RestrictedApi\")\n    private void setWindowInsetsListener(@NonNull View child) {\n        // Ensure the peek height is at least as large as the bottom gesture inset size so that\n        // the sheet can always be dragged, but only when the inset is required by the system.\n        final boolean shouldHandleGestureInsets =\n                VERSION.SDK_INT >= VERSION_CODES.Q && !isGestureInsetBottomIgnored() && !peekHeightAuto;\n\n        // If were not handling insets at all, don't apply the listener.\n        if (!paddingBottomSystemWindowInsets\n                && !paddingLeftSystemWindowInsets\n                && !paddingRightSystemWindowInsets\n                && !marginLeftSystemWindowInsets\n                && !marginRightSystemWindowInsets\n                && !marginTopSystemWindowInsets\n                && !shouldHandleGestureInsets) {\n            return;\n        }\n        ViewUtils.doOnApplyWindowInsets(\n                child,\n                new ViewUtils.OnApplyWindowInsetsListener() {\n                    @Override\n                    @SuppressWarnings(\"deprecation\") // getSystemWindowInsetBottom is used for adjustResize.\n                    public WindowInsetsCompat onApplyWindowInsets(\n                            View view, WindowInsetsCompat insets, RelativePadding initialPadding) {\n                        Insets systemBarInsets = insets.getInsets(WindowInsetsCompat.Type.systemBars());\n                        Insets mandatoryGestureInsets =\n                                insets.getInsets(WindowInsetsCompat.Type.mandatorySystemGestures());\n\n                        insetTop = systemBarInsets.top;\n\n                        boolean isRtl = ViewUtils.isLayoutRtl(view);\n\n                        int bottomPadding = view.getPaddingBottom();\n                        int leftPadding = view.getPaddingLeft();\n                        int rightPadding = view.getPaddingRight();\n\n                        if (paddingBottomSystemWindowInsets) {\n                            // Intentionally uses getSystemWindowInsetBottom to apply padding properly when\n                            // adjustResize is used as the windowSoftInputMode.\n                            insetBottom = insets.getSystemWindowInsetBottom();\n                            bottomPadding = initialPadding.bottom + insetBottom;\n                        }\n\n                        if (paddingLeftSystemWindowInsets) {\n                            leftPadding = isRtl ? initialPadding.end : initialPadding.start;\n                            leftPadding += systemBarInsets.left;\n                        }\n\n                        if (paddingRightSystemWindowInsets) {\n                            rightPadding = isRtl ? initialPadding.start : initialPadding.end;\n                            rightPadding += systemBarInsets.right;\n                        }\n\n                        MarginLayoutParams mlp = (MarginLayoutParams) view.getLayoutParams();\n                        boolean marginUpdated = false;\n\n                        if (marginLeftSystemWindowInsets && mlp.leftMargin != systemBarInsets.left) {\n                            mlp.leftMargin = systemBarInsets.left;\n                            marginUpdated = true;\n                        }\n\n                        if (marginRightSystemWindowInsets && mlp.rightMargin != systemBarInsets.right) {\n                            mlp.rightMargin = systemBarInsets.right;\n                            marginUpdated = true;\n                        }\n\n                        if (marginTopSystemWindowInsets && mlp.topMargin != systemBarInsets.top) {\n                            mlp.topMargin = systemBarInsets.top;\n                            marginUpdated = true;\n                        }\n\n                        if (marginUpdated) {\n                            view.setLayoutParams(mlp);\n                        }\n                        view.setPadding(leftPadding, view.getPaddingTop(), rightPadding, bottomPadding);\n\n                        if (shouldHandleGestureInsets) {\n                            gestureInsetBottom = mandatoryGestureInsets.bottom;\n                        }\n\n                        // Don't update the peek height to be above the navigation bar or gestures if these\n                        // flags are off. It means the client is already handling it.\n                        if (paddingBottomSystemWindowInsets || shouldHandleGestureInsets) {\n                            updatePeekHeight(/* animate= */ false);\n                        }\n                        return insets;\n                    }\n                });\n    }\n\n    private float getYVelocity() {\n        if (velocityTracker == null) {\n            return 0;\n        }\n        velocityTracker.computeCurrentVelocity(1000, maximumVelocity);\n        return velocityTracker.getYVelocity(activePointerId);\n    }\n\n    private void startSettling(View child, @StableState int state, boolean isReleasingView) {\n        int top = getTopOffsetForState(state);\n        boolean settling =\n                viewDragHelper != null\n                        && (isReleasingView\n                        ? viewDragHelper.settleCapturedViewAt(child.getLeft(), top)\n                        : viewDragHelper.smoothSlideViewTo(child, child.getLeft(), top));\n        if (settling) {\n            setStateInternal(STATE_SETTLING);\n            // STATE_SETTLING won't animate the material shape, so do that here with the target state.\n            updateDrawableForTargetState(state, /* animate= */ true);\n            stateSettlingTracker.continueSettlingToState(state);\n        } else {\n            setStateInternal(state);\n        }\n    }\n\n    private int getTopOffsetForState(@StableState int state) {\n        switch (state) {\n            case STATE_COLLAPSED:\n                return collapsedOffset;\n            case STATE_EXPANDED:\n                return getExpandedOffset();\n            case STATE_HALF_EXPANDED:\n                return halfExpandedOffset;\n            case STATE_HIDDEN:\n                return parentHeight;\n            default:\n                // Fall through\n        }\n        throw new IllegalArgumentException(\"Invalid state to get top offset: \" + state);\n    }\n\n    private final ViewDragHelper.Callback dragCallback =\n            new ViewDragHelper.Callback() {\n\n                private long viewCapturedMillis;\n\n                @Override\n                public boolean tryCaptureView(@NonNull View child, int pointerId) {\n                    if (state == STATE_DRAGGING) {\n                        return false;\n                    }\n                    if (touchingScrollingChild) {\n                        return false;\n                    }\n                    if (state == STATE_EXPANDED && activePointerId == pointerId) {\n                        View scroll = nestedScrollingChildRef != null ? nestedScrollingChildRef.get() : null;\n                        if (scroll != null && scroll.canScrollVertically(-1)) {\n                            // Let the content scroll up\n                            return false;\n                        }\n                    }\n                    viewCapturedMillis = System.currentTimeMillis();\n                    return viewRef != null && viewRef.get() == child;\n                }\n\n                @Override\n                public void onViewPositionChanged(\n                        @NonNull View changedView, int left, int top, int dx, int dy) {\n                    dispatchOnSlide(top);\n                }\n\n                @Override\n                public void onViewDragStateChanged(@State int state) {\n                    if (state == ViewDragHelper.STATE_DRAGGING && draggable) {\n                        setStateInternal(STATE_DRAGGING);\n                    }\n                }\n\n                private boolean releasedLow(@NonNull View child) {\n                    // Needs to be at least half way to the bottom.\n                    return child.getTop() > (parentHeight + getExpandedOffset()) / 2;\n                }\n\n                @Override\n                public void onViewReleased(@NonNull View releasedChild, float xvel, float yvel) {\n                    @State int targetState;\n                    if (yvel < 0) { // Moving up\n                        if (fitToContents) {\n                            targetState = STATE_EXPANDED;\n                        } else {\n                            int currentTop = releasedChild.getTop();\n                            long dragDurationMillis = System.currentTimeMillis() - viewCapturedMillis;\n\n                            if (shouldSkipHalfExpandedStateWhenDragging()) {\n                                float yPositionPercentage = currentTop * 100f / parentHeight;\n\n                                if (shouldExpandOnUpwardDrag(dragDurationMillis, yPositionPercentage)) {\n                                    targetState = STATE_EXPANDED;\n                                } else {\n                                    targetState = STATE_COLLAPSED;\n                                }\n                            } else {\n                                if (currentTop > halfExpandedOffset) {\n                                    targetState = STATE_HALF_EXPANDED;\n                                } else {\n                                    targetState = STATE_EXPANDED;\n                                }\n                            }\n                        }\n                    } else if (hideable && shouldHide(releasedChild, yvel)) {\n                        // Hide if the view was either released low or it was a significant vertical swipe\n                        // otherwise settle to closest expanded state.\n                        if ((Math.abs(xvel) < Math.abs(yvel) && yvel > significantVelocityThreshold)\n                                || releasedLow(releasedChild)) {\n                            targetState = STATE_HIDDEN;\n                        } else if (fitToContents) {\n                            targetState = STATE_EXPANDED;\n                        } else if (Math.abs(releasedChild.getTop() - getExpandedOffset())\n                                < Math.abs(releasedChild.getTop() - halfExpandedOffset)) {\n                            targetState = STATE_EXPANDED;\n                        } else {\n                            targetState = STATE_HALF_EXPANDED;\n                        }\n                    } else if (yvel == 0.f || Math.abs(xvel) > Math.abs(yvel)) {\n                        // If the Y velocity is 0 or the swipe was mostly horizontal indicated by the X velocity\n                        // being greater than the Y velocity, settle to the nearest correct height.\n                        int currentTop = releasedChild.getTop();\n                        if (fitToContents) {\n                            if (Math.abs(currentTop - fitToContentsOffset)\n                                    < Math.abs(currentTop - collapsedOffset)) {\n                                targetState = STATE_EXPANDED;\n                            } else {\n                                targetState = STATE_COLLAPSED;\n                            }\n                        } else {\n                            if (currentTop < halfExpandedOffset) {\n                                if (currentTop < Math.abs(currentTop - collapsedOffset)) {\n                                    targetState = STATE_EXPANDED;\n                                } else {\n                                    if (shouldSkipHalfExpandedStateWhenDragging()) {\n                                        targetState = STATE_COLLAPSED;\n                                    } else {\n                                        targetState = STATE_HALF_EXPANDED;\n                                    }\n                                }\n                            } else {\n                                if (Math.abs(currentTop - halfExpandedOffset)\n                                        < Math.abs(currentTop - collapsedOffset)) {\n                                    if (shouldSkipHalfExpandedStateWhenDragging()) {\n                                        targetState = STATE_COLLAPSED;\n                                    } else {\n                                        targetState = STATE_HALF_EXPANDED;\n                                    }\n                                } else {\n                                    targetState = STATE_COLLAPSED;\n                                }\n                            }\n                        }\n                    } else { // Moving Down\n                        if (fitToContents) {\n                            targetState = STATE_COLLAPSED;\n                        } else {\n                            // Settle to the nearest correct height.\n                            int currentTop = releasedChild.getTop();\n                            if (Math.abs(currentTop - halfExpandedOffset)\n                                    < Math.abs(currentTop - collapsedOffset)) {\n                                if (shouldSkipHalfExpandedStateWhenDragging()) {\n                                    targetState = STATE_COLLAPSED;\n                                } else {\n                                    targetState = STATE_HALF_EXPANDED;\n                                }\n                            } else {\n                                targetState = STATE_COLLAPSED;\n                            }\n                        }\n                    }\n                    startSettling(releasedChild, targetState, shouldSkipSmoothAnimation());\n                }\n\n                @Override\n                public int clampViewPositionVertical(@NonNull View child, int top, int dy) {\n                    return MathUtils.clamp(\n                            top,\n                            getExpandedOffset(),\n                            getViewVerticalDragRange(child));\n                }\n\n                @Override\n                public int clampViewPositionHorizontal(@NonNull View child, int left, int dx) {\n                    return child.getLeft();\n                }\n\n                @Override\n                public int getViewVerticalDragRange(@NonNull View child) {\n                    if (canBeHiddenByDragging()) {\n                        return parentHeight;\n                    } else {\n                        return collapsedOffset;\n                    }\n                }\n            };\n\n    void dispatchOnSlide(int top) {\n        View bottomSheet = viewRef.get();\n        if (bottomSheet != null && !callbacks.isEmpty()) {\n            float slideOffset = calculateSlideOffsetWithTop(top);\n            for (int i = 0; i < callbacks.size(); i++) {\n                callbacks.get(i).onSlide(bottomSheet, slideOffset);\n            }\n        }\n    }\n\n    @VisibleForTesting\n    int getPeekHeightMin() {\n        return peekHeightMin;\n    }\n\n    /**\n     * Disables the shaped corner {@link ShapeAppearanceModel} interpolation transition animations.\n     * Will have no effect unless the sheet utilizes a {@link MaterialShapeDrawable} with set shape\n     * theming properties. Only For use in UI testing.\n     *\n     * @hide\n     */\n    @RestrictTo(LIBRARY_GROUP)\n    @VisibleForTesting\n    public void disableShapeAnimations() {\n        // Sets the shape value animator to null, prevents animations from occurring during testing.\n        interpolatorAnimator = null;\n    }\n\n    /**\n     * Checks weather a nested scroll should be enabled. If {@code false} all nested scrolls will be\n     * consumed by the bottomSheet.\n     *\n     * @hide\n     */\n    @RestrictTo(LIBRARY_GROUP)\n    public boolean isNestedScrollingCheckEnabled() {\n        return true;\n    }\n\n    /**\n     * Checks weather half expended state should be skipped when drag is ended. If {@code true}, the\n     * bottomSheet will go to the next closest state.\n     *\n     * @hide\n     */\n    @RestrictTo(LIBRARY_GROUP)\n    public boolean shouldSkipHalfExpandedStateWhenDragging() {\n        // AppManager-changed: return skipHalfExpanded instead of false\n        return skipHalfExpanded;\n    }\n\n    /**\n     * Checks whether an animation should be smooth after the bottomSheet is released after dragging.\n     *\n     * @hide\n     */\n    @RestrictTo(LIBRARY_GROUP)\n    public boolean shouldSkipSmoothAnimation() {\n        return true;\n    }\n\n    /**\n     * Checks whether hiding gestures should be enabled while {@code isHideable} is set to true.\n     *\n     * @hide\n     */\n    @RestrictTo(LIBRARY_GROUP)\n    public boolean isHideableWhenDragging() {\n        return true;\n    }\n\n    private boolean canBeHiddenByDragging() {\n        return isHideable() && isHideableWhenDragging();\n    }\n\n    /**\n     * Checks whether the bottom sheet should be expanded after it has been released after dragging.\n     *\n     * @param dragDurationMillis how long the bottom sheet was dragged.\n     * @param yPositionPercentage position of the bottom sheet when released after dragging. Lower\n     *     values mean that view was released closer to the top of the screen.\n     * @hide\n     */\n    @RestrictTo(LIBRARY_GROUP)\n    public boolean shouldExpandOnUpwardDrag(\n            long dragDurationMillis, @FloatRange(from = 0.0f, to = 100.0f) float yPositionPercentage) {\n        // AppManager-changed: return skipHalfExpanded instead of false\n        return skipHalfExpanded;\n    }\n\n    /**\n     * Sets whether this bottom sheet can hide when it is swiped down.\n     *\n     * @param hideable {@code true} to make this bottom sheet hideable.\n     * @hide\n     */\n    @RestrictTo(LIBRARY_GROUP)\n    public void setHideableInternal(boolean hideable) {\n        this.hideable = hideable;\n    }\n\n    /**\n     * Gets the last stable state of the bottom sheet.\n     *\n     * @return One of {@link #STATE_EXPANDED}, {@link #STATE_HALF_EXPANDED}, {@link #STATE_COLLAPSED},\n     *     {@link #STATE_HIDDEN}.\n     * @hide\n     */\n    @State\n    @RestrictTo(LIBRARY_GROUP)\n    public int getLastStableState() {\n        return lastStableState;\n    }\n\n    private class StateSettlingTracker {\n        @State private int targetState;\n        private boolean isContinueSettlingRunnablePosted;\n\n        private final Runnable continueSettlingRunnable =\n                new Runnable() {\n                    @Override\n                    public void run() {\n                        isContinueSettlingRunnablePosted = false;\n                        if (viewDragHelper != null && viewDragHelper.continueSettling(true)) {\n                            continueSettlingToState(targetState);\n                        } else if (state == STATE_SETTLING) {\n                            setStateInternal(targetState);\n                        }\n                        // In other cases, settling has been interrupted by certain UX interactions. Do nothing.\n                    }\n                };\n\n        void continueSettlingToState(@State int targetState) {\n            if (viewRef == null || viewRef.get() == null) {\n                return;\n            }\n            this.targetState = targetState;\n            if (!isContinueSettlingRunnablePosted) {\n                ViewCompat.postOnAnimation(viewRef.get(), continueSettlingRunnable);\n                isContinueSettlingRunnablePosted = true;\n            }\n        }\n    }\n\n    /** State persisted across instances */\n    protected static class SavedState extends AbsSavedState {\n        @State final int state;\n        int peekHeight;\n        boolean fitToContents;\n        boolean hideable;\n        boolean skipCollapsed;\n        // AppManager-added: Store skipHalfExpanded\n        boolean skipHalfExpanded;\n\n        public SavedState(@NonNull Parcel source) {\n            this(source, null);\n        }\n\n        public SavedState(@NonNull Parcel source, ClassLoader loader) {\n            super(source, loader);\n            //noinspection ResourceType\n            state = source.readInt();\n            peekHeight = source.readInt();\n            fitToContents = source.readInt() == 1;\n            hideable = source.readInt() == 1;\n            skipCollapsed = source.readInt() == 1;\n            // AppManager-added: Store skipHalfExpanded\n            skipHalfExpanded = source.readInt() == 1;\n        }\n\n        public SavedState(Parcelable superState, @NonNull BottomSheetBehavior<?> behavior) {\n            super(superState);\n            this.state = behavior.state;\n            this.peekHeight = behavior.peekHeight;\n            this.fitToContents = behavior.fitToContents;\n            this.hideable = behavior.hideable;\n            this.skipCollapsed = behavior.skipCollapsed;\n            // AppManager-added: Store skipHalfExpanded\n            this.skipHalfExpanded = behavior.skipHalfExpanded;\n        }\n\n        /**\n         * This constructor does not respect flags: {@link BottomSheetBehavior#SAVE_PEEK_HEIGHT}, {@link\n         * BottomSheetBehavior#SAVE_FIT_TO_CONTENTS}, {@link BottomSheetBehavior#SAVE_HIDEABLE}, {@link\n         * BottomSheetBehavior#SAVE_SKIP_COLLAPSED}. It is as if {@link BottomSheetBehavior#SAVE_NONE}\n         * were set.\n         *\n         * @deprecated Use {@link #SavedState(Parcelable, BottomSheetBehavior)} instead.\n         */\n        @Deprecated\n        public SavedState(Parcelable superstate, @State int state) {\n            super(superstate);\n            this.state = state;\n        }\n\n        @Override\n        public void writeToParcel(@NonNull Parcel out, int flags) {\n            super.writeToParcel(out, flags);\n            out.writeInt(state);\n            out.writeInt(peekHeight);\n            out.writeInt(fitToContents ? 1 : 0);\n            out.writeInt(hideable ? 1 : 0);\n            out.writeInt(skipCollapsed ? 1 : 0);\n            // AppManager-added: Store skipHalfExpanded\n            out.writeInt(skipHalfExpanded ? 1 : 0);\n        }\n\n        public static final Creator<SavedState> CREATOR =\n                new ClassLoaderCreator<SavedState>() {\n                    @NonNull\n                    @Override\n                    public SavedState createFromParcel(@NonNull Parcel in, ClassLoader loader) {\n                        return new SavedState(in, loader);\n                    }\n\n                    @Nullable\n                    @Override\n                    public SavedState createFromParcel(@NonNull Parcel in) {\n                        return new SavedState(in, null);\n                    }\n\n                    @NonNull\n                    @Override\n                    public SavedState[] newArray(int size) {\n                        return new SavedState[size];\n                    }\n                };\n    }\n\n    /**\n     * A utility function to get the {@link BottomSheetBehavior} associated with the {@code view}.\n     *\n     * @param view The {@link View} with {@link BottomSheetBehavior}.\n     * @return The {@link BottomSheetBehavior} associated with the {@code view}.\n     */\n    @NonNull\n    @SuppressWarnings(\"unchecked\")\n    public static <V extends View> BottomSheetBehavior<V> from(@NonNull V view) {\n        ViewGroup.LayoutParams params = view.getLayoutParams();\n        if (!(params instanceof CoordinatorLayout.LayoutParams)) {\n            throw new IllegalArgumentException(\"The view is not a child of CoordinatorLayout\");\n        }\n        CoordinatorLayout.Behavior<?> behavior =\n                ((CoordinatorLayout.LayoutParams) params).getBehavior();\n        if (!(behavior instanceof BottomSheetBehavior)) {\n            throw new IllegalArgumentException(\"The view is not associated with BottomSheetBehavior\");\n        }\n        return (BottomSheetBehavior<V>) behavior;\n    }\n\n    /**\n     * Sets whether the BottomSheet should update the accessibility status of its {@link\n     * CoordinatorLayout} siblings when expanded.\n     *\n     * <p>Set this to true if the expanded state of the sheet blocks access to siblings (e.g., when\n     * the sheet expands over the full screen).\n     */\n    public void setUpdateImportantForAccessibilityOnSiblings(\n            boolean updateImportantForAccessibilityOnSiblings) {\n        this.updateImportantForAccessibilityOnSiblings = updateImportantForAccessibilityOnSiblings;\n    }\n\n    private void updateImportantForAccessibility(boolean expanded) {\n        if (viewRef == null) {\n            return;\n        }\n\n        ViewParent viewParent = viewRef.get().getParent();\n        if (!(viewParent instanceof CoordinatorLayout)) {\n            return;\n        }\n\n        CoordinatorLayout parent = (CoordinatorLayout) viewParent;\n        final int childCount = parent.getChildCount();\n        if ((Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) && expanded) {\n            if (importantForAccessibilityMap == null) {\n                importantForAccessibilityMap = new HashMap<>(childCount);\n            } else {\n                // The important for accessibility values of the child views have been saved already.\n                return;\n            }\n        }\n\n        for (int i = 0; i < childCount; i++) {\n            final View child = parent.getChildAt(i);\n            if (child == viewRef.get()) {\n                continue;\n            }\n\n            if (expanded) {\n                // Saves the important for accessibility value of the child view.\n                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {\n                    importantForAccessibilityMap.put(child, child.getImportantForAccessibility());\n                }\n                if (updateImportantForAccessibilityOnSiblings) {\n                    ViewCompat.setImportantForAccessibility(\n                            child, ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS);\n                }\n            } else {\n                if (updateImportantForAccessibilityOnSiblings\n                        && importantForAccessibilityMap != null\n                        && importantForAccessibilityMap.containsKey(child)) {\n                    // Restores the original important for accessibility value of the child view.\n                    ViewCompat.setImportantForAccessibility(child, importantForAccessibilityMap.get(child));\n                }\n            }\n        }\n\n        if (!expanded) {\n            importantForAccessibilityMap = null;\n        } else if (updateImportantForAccessibilityOnSiblings) {\n            // If the siblings of the bottom sheet have been set to not important for a11y, move the focus\n            // to the bottom sheet when expanded.\n            viewRef.get().sendAccessibilityEvent(AccessibilityEvent.TYPE_VIEW_FOCUSED);\n        }\n    }\n\n    void setAccessibilityDelegateView(@Nullable View accessibilityDelegateView) {\n        if (accessibilityDelegateView == null && accessibilityDelegateViewRef != null) {\n            clearAccessibilityAction(\n                    accessibilityDelegateViewRef.get(), VIEW_INDEX_ACCESSIBILITY_DELEGATE_VIEW);\n            accessibilityDelegateViewRef = null;\n            return;\n        }\n        accessibilityDelegateViewRef = new WeakReference<>(accessibilityDelegateView);\n        updateAccessibilityActions(accessibilityDelegateView, VIEW_INDEX_ACCESSIBILITY_DELEGATE_VIEW);\n    }\n\n    private void updateAccessibilityActions() {\n        if (viewRef != null) {\n            updateAccessibilityActions(viewRef.get(), VIEW_INDEX_BOTTOM_SHEET);\n        }\n        if (accessibilityDelegateViewRef != null) {\n            updateAccessibilityActions(\n                    accessibilityDelegateViewRef.get(), VIEW_INDEX_ACCESSIBILITY_DELEGATE_VIEW);\n        }\n    }\n\n    private void updateAccessibilityActions(View view, int viewIndex) {\n        if (view == null) {\n            return;\n        }\n        clearAccessibilityAction(view, viewIndex);\n\n        if (!fitToContents && state != STATE_HALF_EXPANDED) {\n            expandHalfwayActionIds.put(\n                    viewIndex,\n                    addAccessibilityActionForState(\n                            view, R.string.bottomsheet_action_expand_halfway, STATE_HALF_EXPANDED));\n        }\n\n        if ((hideable && isHideableWhenDragging()) && state != STATE_HIDDEN) {\n            replaceAccessibilityActionForState(\n                    view, AccessibilityActionCompat.ACTION_DISMISS, STATE_HIDDEN);\n        }\n\n        switch (state) {\n            case STATE_EXPANDED:\n            {\n                int nextState = fitToContents ? STATE_COLLAPSED : STATE_HALF_EXPANDED;\n                replaceAccessibilityActionForState(\n                        view, AccessibilityActionCompat.ACTION_COLLAPSE, nextState);\n                break;\n            }\n            case STATE_HALF_EXPANDED:\n            {\n                replaceAccessibilityActionForState(\n                        view, AccessibilityActionCompat.ACTION_COLLAPSE, STATE_COLLAPSED);\n                replaceAccessibilityActionForState(\n                        view, AccessibilityActionCompat.ACTION_EXPAND, STATE_EXPANDED);\n                break;\n            }\n            case STATE_COLLAPSED:\n            {\n                int nextState = fitToContents ? STATE_EXPANDED : STATE_HALF_EXPANDED;\n                replaceAccessibilityActionForState(\n                        view, AccessibilityActionCompat.ACTION_EXPAND, nextState);\n                break;\n            }\n            case STATE_HIDDEN:\n            case STATE_DRAGGING:\n            case STATE_SETTLING:\n                // Accessibility actions are not applicable, do nothing\n        }\n    }\n\n    private void clearAccessibilityAction(View view, int viewIndex) {\n        if (view == null) {\n            return;\n        }\n        ViewCompat.removeAccessibilityAction(view, AccessibilityNodeInfoCompat.ACTION_COLLAPSE);\n        ViewCompat.removeAccessibilityAction(view, AccessibilityNodeInfoCompat.ACTION_EXPAND);\n        ViewCompat.removeAccessibilityAction(view, AccessibilityNodeInfoCompat.ACTION_DISMISS);\n\n        int expandHalfwayActionId = expandHalfwayActionIds.get(viewIndex, View.NO_ID);\n        if (expandHalfwayActionId != View.NO_ID) {\n            ViewCompat.removeAccessibilityAction(view, expandHalfwayActionId);\n            expandHalfwayActionIds.delete(viewIndex);\n        }\n    }\n\n    private void replaceAccessibilityActionForState(\n            View child, AccessibilityActionCompat action, @StableState int state) {\n        ViewCompat.replaceAccessibilityAction(\n                child, action, null, createAccessibilityViewCommandForState(state));\n    }\n\n    private int addAccessibilityActionForState(\n            View child, @StringRes int stringResId, @StableState int state) {\n        return ViewCompat.addAccessibilityAction(\n                child,\n                child.getResources().getString(stringResId),\n                createAccessibilityViewCommandForState(state));\n    }\n\n    private AccessibilityViewCommand createAccessibilityViewCommandForState(@StableState final int state) {\n        return new AccessibilityViewCommand() {\n            @Override\n            public boolean perform(@NonNull View view, @Nullable CommandArguments arguments) {\n                setState(state);\n                return true;\n            }\n        };\n    }\n}\n"
  },
  {
    "path": "libcore/ui/src/main/java/io/github/muntashirakon/dialog/BottomSheetDialog.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\n// This class is copied from material components to enable setting a custom BottomSheetBehaviour\n// See BottomSheetBehaviour class for details.\n\npackage io.github.muntashirakon.dialog;\n\nimport static com.google.android.material.color.MaterialColors.isColorLight;\n\nimport android.annotation.SuppressLint;\nimport android.content.Context;\nimport android.content.res.ColorStateList;\nimport android.content.res.TypedArray;\nimport android.graphics.Color;\nimport android.graphics.drawable.ColorDrawable;\nimport android.os.Build;\nimport android.os.Build.VERSION;\nimport android.os.Build.VERSION_CODES;\nimport android.os.Bundle;\nimport androidx.appcompat.app.AppCompatDialog;\nimport android.util.TypedValue;\nimport android.view.MotionEvent;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.view.Window;\nimport android.view.WindowManager.LayoutParams;\nimport android.widget.FrameLayout;\nimport androidx.annotation.LayoutRes;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.StyleRes;\nimport androidx.coordinatorlayout.widget.CoordinatorLayout;\nimport androidx.core.view.AccessibilityDelegateCompat;\nimport androidx.core.view.OnApplyWindowInsetsListener;\nimport androidx.core.view.ViewCompat;\nimport androidx.core.view.WindowCompat;\nimport androidx.core.view.WindowInsetsCompat;\nimport androidx.core.view.WindowInsetsControllerCompat;\nimport androidx.core.view.accessibility.AccessibilityNodeInfoCompat;\nimport com.google.android.material.internal.EdgeToEdgeUtils;\nimport com.google.android.material.shape.MaterialShapeDrawable;\n\nimport io.github.muntashirakon.ui.R;\n\n/**\n * Base class for {@link android.app.Dialog}s styled as a bottom sheet.\n *\n * <p>Edge to edge window flags are automatically applied if the {@link\n * android.R.attr#navigationBarColor} is transparent or translucent and {@code enableEdgeToEdge} is\n * true. These can be set in the theme that is passed to the constructor, or will be taken from the\n * theme of the context (ie. your application or activity theme).\n *\n * <p>In edge to edge mode, padding will be added automatically to the top when sliding under the\n * status bar. Padding can be applied automatically to the left, right, or bottom if any of\n * `paddingBottomSystemWindowInsets`, `paddingLeftSystemWindowInsets`, or\n * `paddingRightSystemWindowInsets` are set to true in the style.\n */\n// Copyright 2015 The Android Open Source Project\npublic class BottomSheetDialog extends AppCompatDialog {\n\n    private BottomSheetBehavior<FrameLayout> behavior;\n\n    private FrameLayout container;\n    private CoordinatorLayout coordinator;\n    private FrameLayout bottomSheet;\n\n    boolean dismissWithAnimation;\n\n    boolean cancelable = true;\n    private boolean canceledOnTouchOutside = true;\n    private boolean canceledOnTouchOutsideSet;\n    private EdgeToEdgeCallback edgeToEdgeCallback;\n    private boolean edgeToEdgeEnabled;\n\n    public BottomSheetDialog(@NonNull Context context) {\n        this(context, 0);\n\n        edgeToEdgeEnabled =\n                getContext()\n                        .getTheme()\n                        .obtainStyledAttributes(new int[] {com.google.android.material.R.attr.enableEdgeToEdge})\n                        .getBoolean(0, false);\n    }\n\n    public BottomSheetDialog(@NonNull Context context, @StyleRes int theme) {\n        super(context, getThemeResId(context, theme));\n        // We hide the title bar for any style configuration. Otherwise, there will be a gap\n        // above the bottom sheet when it is expanded.\n        supportRequestWindowFeature(Window.FEATURE_NO_TITLE);\n\n        edgeToEdgeEnabled =\n                getContext()\n                        .getTheme()\n                        .obtainStyledAttributes(new int[] {com.google.android.material.R.attr.enableEdgeToEdge})\n                        .getBoolean(0, false);\n    }\n\n    protected BottomSheetDialog(\n            @NonNull Context context, boolean cancelable, OnCancelListener cancelListener) {\n        super(context, cancelable, cancelListener);\n        supportRequestWindowFeature(Window.FEATURE_NO_TITLE);\n        this.cancelable = cancelable;\n\n        edgeToEdgeEnabled =\n                getContext()\n                        .getTheme()\n                        .obtainStyledAttributes(new int[] {com.google.android.material.R.attr.enableEdgeToEdge})\n                        .getBoolean(0, false);\n    }\n\n    @Override\n    public void setContentView(@LayoutRes int layoutResId) {\n        super.setContentView(wrapInBottomSheet(layoutResId, null, null));\n    }\n\n    @Override\n    protected void onCreate(Bundle savedInstanceState) {\n        super.onCreate(savedInstanceState);\n        Window window = getWindow();\n        if (window != null) {\n            if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {\n                // The status bar should always be transparent because of the window animation.\n                window.setStatusBarColor(0);\n\n                window.addFlags(LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);\n                if (VERSION.SDK_INT < VERSION_CODES.M) {\n                    // It can be transparent for API 23 and above because we will handle switching the status\n                    // bar icons to light or dark as appropriate. For API 21 and API 22 we just set the\n                    // translucent status bar.\n                    window.addFlags(LayoutParams.FLAG_TRANSLUCENT_STATUS);\n                }\n            }\n            window.setLayout(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT);\n        }\n    }\n\n    @Override\n    public void setContentView(View view) {\n        super.setContentView(wrapInBottomSheet(0, view, null));\n    }\n\n    @Override\n    public void setContentView(View view, ViewGroup.LayoutParams params) {\n        super.setContentView(wrapInBottomSheet(0, view, params));\n    }\n\n    @Override\n    public void setCancelable(boolean cancelable) {\n        super.setCancelable(cancelable);\n        if (this.cancelable != cancelable) {\n            this.cancelable = cancelable;\n            if (behavior != null) {\n                behavior.setHideable(cancelable);\n            }\n        }\n    }\n\n    @Override\n    protected void onStart() {\n        super.onStart();\n        if (behavior != null && behavior.getState() == BottomSheetBehavior.STATE_HIDDEN) {\n            behavior.setState(BottomSheetBehavior.STATE_COLLAPSED);\n        }\n    }\n\n    @Override\n    public void onAttachedToWindow() {\n        super.onAttachedToWindow();\n        Window window = getWindow();\n        if (window != null) {\n            if (VERSION.SDK_INT >= VERSION_CODES.LOLLIPOP) {\n                // If the navigation bar is transparent at all the BottomSheet should be edge to edge.\n                boolean drawEdgeToEdge =\n                        edgeToEdgeEnabled && Color.alpha(window.getNavigationBarColor()) < 255;\n                if (container != null) {\n                    container.setFitsSystemWindows(!drawEdgeToEdge);\n                }\n                if (coordinator != null) {\n                    coordinator.setFitsSystemWindows(!drawEdgeToEdge);\n                }\n                WindowCompat.setDecorFitsSystemWindows(window, !drawEdgeToEdge);\n            }\n            if (edgeToEdgeCallback != null) {\n                edgeToEdgeCallback.setWindow(window);\n            }\n        }\n    }\n\n    @Override\n    public void onDetachedFromWindow() {\n        if (edgeToEdgeCallback != null) {\n            edgeToEdgeCallback.setWindow(null);\n        }\n    }\n\n    /**\n     * This function can be called from a few different use cases, including Swiping the dialog down\n     * or calling `dismiss()` from a `BottomSheetDialogFragment`, tapping outside a dialog, etc...\n     *\n     * <p>The default animation to dismiss this dialog is a fade-out transition through a\n     * windowAnimation. Call {@link #setDismissWithAnimation(true)} if you want to utilize the\n     * BottomSheet animation instead.\n     *\n     * <p>If this function is called from a swipe down interaction, or dismissWithAnimation is false,\n     * then keep the default behavior.\n     *\n     * <p>Else, since this is a terminal event which will finish this dialog, we override the attached\n     * {@link BottomSheetBehavior.BottomSheetCallback} to call this function, after {@link\n     * BottomSheetBehavior#STATE_HIDDEN} is set. This will enforce the swipe down animation before\n     * canceling this dialog.\n     */\n    @Override\n    public void cancel() {\n        BottomSheetBehavior<FrameLayout> behavior = getBehavior();\n\n        if (!dismissWithAnimation || behavior.getState() == BottomSheetBehavior.STATE_HIDDEN) {\n            super.cancel();\n        } else {\n            behavior.setState(BottomSheetBehavior.STATE_HIDDEN);\n        }\n    }\n\n    @Override\n    public void setCanceledOnTouchOutside(boolean cancel) {\n        super.setCanceledOnTouchOutside(cancel);\n        if (cancel && !cancelable) {\n            cancelable = true;\n        }\n        canceledOnTouchOutside = cancel;\n        canceledOnTouchOutsideSet = true;\n    }\n\n    @NonNull\n    public BottomSheetBehavior<FrameLayout> getBehavior() {\n        if (behavior == null) {\n            // The content hasn't been set, so the behavior doesn't exist yet. Let's create it.\n            ensureContainerAndBehavior();\n        }\n        return behavior;\n    }\n\n    /**\n     * Set to perform the swipe down animation when dismissing instead of the window animation for the\n     * dialog.\n     *\n     * @param dismissWithAnimation True if swipe down animation should be used when dismissing.\n     */\n    public void setDismissWithAnimation(boolean dismissWithAnimation) {\n        this.dismissWithAnimation = dismissWithAnimation;\n    }\n\n    /**\n     * Returns if dismissing will perform the swipe down animation on the bottom sheet, rather than\n     * the window animation for the dialog.\n     */\n    public boolean getDismissWithAnimation() {\n        return dismissWithAnimation;\n    }\n\n    /** Returns if edge to edge behavior is enabled for this dialog. */\n    public boolean getEdgeToEdgeEnabled() {\n        return edgeToEdgeEnabled;\n    }\n\n    /** Creates the container layout which must exist to find the behavior */\n    private FrameLayout ensureContainerAndBehavior() {\n        if (container == null) {\n            container =\n                    (FrameLayout) View.inflate(getContext(), R.layout.dialog_bottom_sheet, null);\n\n            coordinator = (CoordinatorLayout) container.findViewById(R.id.coordinator);\n            bottomSheet = (FrameLayout) container.findViewById(R.id.design_bottom_sheet);\n\n            behavior = BottomSheetBehavior.from(bottomSheet);\n            behavior.addBottomSheetCallback(bottomSheetCallback);\n            behavior.setHideable(cancelable);\n        }\n        return container;\n    }\n\n    private View wrapInBottomSheet(\n            int layoutResId, @Nullable View view, @Nullable ViewGroup.LayoutParams params) {\n        ensureContainerAndBehavior();\n        CoordinatorLayout coordinator = (CoordinatorLayout) container.findViewById(R.id.coordinator);\n        if (layoutResId != 0 && view == null) {\n            view = getLayoutInflater().inflate(layoutResId, coordinator, false);\n        }\n\n        if (edgeToEdgeEnabled) {\n            ViewCompat.setOnApplyWindowInsetsListener(\n                    bottomSheet,\n                    new OnApplyWindowInsetsListener() {\n                        @Override\n                        public WindowInsetsCompat onApplyWindowInsets(View view, WindowInsetsCompat insets) {\n                            if (edgeToEdgeCallback != null) {\n                                behavior.removeBottomSheetCallback(edgeToEdgeCallback);\n                            }\n\n                            if (insets != null) {\n                                edgeToEdgeCallback = new EdgeToEdgeCallback(bottomSheet, insets);\n                                edgeToEdgeCallback.setWindow(getWindow());\n                                behavior.addBottomSheetCallback(edgeToEdgeCallback);\n                            }\n\n                            return insets;\n                        }\n                    });\n        }\n\n        bottomSheet.removeAllViews();\n        if (params == null) {\n            bottomSheet.addView(view);\n        } else {\n            bottomSheet.addView(view, params);\n        }\n        // We treat the CoordinatorLayout as outside the dialog though it is technically inside\n        coordinator\n                .findViewById(R.id.touch_outside)\n                .setOnClickListener(\n                        new View.OnClickListener() {\n                            @Override\n                            public void onClick(View view) {\n                                if (cancelable && isShowing() && shouldWindowCloseOnTouchOutside()) {\n                                    cancel();\n                                }\n                            }\n                        });\n        // Handle accessibility events\n        ViewCompat.setAccessibilityDelegate(\n                bottomSheet,\n                new AccessibilityDelegateCompat() {\n                    @Override\n                    public void onInitializeAccessibilityNodeInfo(\n                            View host, @NonNull AccessibilityNodeInfoCompat info) {\n                        super.onInitializeAccessibilityNodeInfo(host, info);\n                        if (cancelable) {\n                            info.addAction(AccessibilityNodeInfoCompat.ACTION_DISMISS);\n                            info.setDismissable(true);\n                        } else {\n                            info.setDismissable(false);\n                        }\n                    }\n\n                    @Override\n                    public boolean performAccessibilityAction(View host, int action, Bundle args) {\n                        if (action == AccessibilityNodeInfoCompat.ACTION_DISMISS && cancelable) {\n                            cancel();\n                            return true;\n                        }\n                        return super.performAccessibilityAction(host, action, args);\n                    }\n                });\n        bottomSheet.setOnTouchListener(\n                new View.OnTouchListener() {\n                    @Override\n                    public boolean onTouch(View view, MotionEvent event) {\n                        // Consume the event and prevent it from falling through\n                        return true;\n                    }\n                });\n        return container;\n    }\n\n    boolean shouldWindowCloseOnTouchOutside() {\n        if (!canceledOnTouchOutsideSet) {\n            TypedArray a =\n                    getContext().obtainStyledAttributes(new int[] {android.R.attr.windowCloseOnTouchOutside});\n            canceledOnTouchOutside = a.getBoolean(0, true);\n            a.recycle();\n            canceledOnTouchOutsideSet = true;\n        }\n        return canceledOnTouchOutside;\n    }\n\n    private static int getThemeResId(@NonNull Context context, int themeId) {\n        if (themeId == 0) {\n            // If the provided theme is 0, then retrieve the dialogTheme from our theme\n            TypedValue outValue = new TypedValue();\n            if (context.getTheme().resolveAttribute(com.google.android.material.R.attr.bottomSheetDialogTheme, outValue, true)) {\n                themeId = outValue.resourceId;\n            } else {\n                // bottomSheetDialogTheme is not provided; we default to our light theme\n                themeId = com.google.android.material.R.style.Theme_Design_Light_BottomSheetDialog;\n            }\n        }\n        return themeId;\n    }\n\n    void removeDefaultCallback() {\n        behavior.removeBottomSheetCallback(bottomSheetCallback);\n    }\n\n    @NonNull\n    private BottomSheetBehavior.BottomSheetCallback bottomSheetCallback =\n            new BottomSheetBehavior.BottomSheetCallback() {\n                @Override\n                public void onStateChanged(\n                        @NonNull View bottomSheet, @BottomSheetBehavior.State int newState) {\n                    if (newState == BottomSheetBehavior.STATE_HIDDEN) {\n                        cancel();\n                    }\n                }\n\n                @Override\n                public void onSlide(@NonNull View bottomSheet, float slideOffset) {}\n            };\n\n    private static class EdgeToEdgeCallback extends BottomSheetBehavior.BottomSheetCallback {\n\n        @Nullable private final Boolean lightBottomSheet;\n        @NonNull private final WindowInsetsCompat insetsCompat;\n\n        @Nullable private Window window;\n        private boolean lightStatusBar;\n\n        private EdgeToEdgeCallback(\n                @NonNull final View bottomSheet, @NonNull WindowInsetsCompat insetsCompat) {\n            this.insetsCompat = insetsCompat;\n\n            // Try to find the background color to automatically change the status bar icons so they will\n            // still be visible when the bottomsheet slides underneath the status bar.\n            ColorStateList backgroundTint;\n            MaterialShapeDrawable msd = BottomSheetBehavior.from(bottomSheet).getMaterialShapeDrawable();\n            if (msd != null) {\n                backgroundTint = msd.getFillColor();\n            } else {\n                backgroundTint = ViewCompat.getBackgroundTintList(bottomSheet);\n            }\n\n            if (backgroundTint != null) {\n                // First check for a tint\n                lightBottomSheet = isColorLight(backgroundTint.getDefaultColor());\n            } else if (bottomSheet.getBackground() instanceof ColorDrawable) {\n                // Then check for the background color\n                lightBottomSheet = isColorLight(((ColorDrawable) bottomSheet.getBackground()).getColor());\n            } else {\n                // Otherwise don't change the status bar color\n                lightBottomSheet = null;\n            }\n        }\n\n        @Override\n        public void onStateChanged(@NonNull View bottomSheet, int newState) {\n            setPaddingForPosition(bottomSheet);\n        }\n\n        @Override\n        public void onSlide(@NonNull View bottomSheet, float slideOffset) {\n            setPaddingForPosition(bottomSheet);\n        }\n\n        @Override\n        void onLayout(@NonNull View bottomSheet) {\n            setPaddingForPosition(bottomSheet);\n        }\n\n        void setWindow(@Nullable Window window) {\n            if (this.window == window) {\n                return;\n            }\n            this.window = window;\n            if (window != null) {\n                WindowInsetsControllerCompat insetsController =\n                        WindowCompat.getInsetsController(window, window.getDecorView());\n                lightStatusBar = insetsController.isAppearanceLightStatusBars();\n            }\n        }\n\n        @SuppressLint(\"RestrictedApi\")\n        private void setPaddingForPosition(View bottomSheet) {\n            if (bottomSheet.getTop() < insetsCompat.getSystemWindowInsetTop()) {\n                // If the bottomsheet is light, we should set light status bar so the icons are visible\n                // since the bottomsheet is now under the status bar.\n                if (window != null) {\n                    EdgeToEdgeUtils.setLightStatusBar(\n                            window, lightBottomSheet == null ? lightStatusBar : lightBottomSheet);\n                }\n                // Smooth transition into status bar when drawing edge to edge.\n                bottomSheet.setPadding(\n                        bottomSheet.getPaddingLeft(),\n                        (insetsCompat.getSystemWindowInsetTop() - bottomSheet.getTop()),\n                        bottomSheet.getPaddingRight(),\n                        bottomSheet.getPaddingBottom());\n            } else if (bottomSheet.getTop() != 0) {\n                // Reset the status bar icons to the original color because the bottomsheet is not under the\n                // status bar.\n                if (window != null) {\n                    EdgeToEdgeUtils.setLightStatusBar(window, lightStatusBar);\n                }\n                bottomSheet.setPadding(\n                        bottomSheet.getPaddingLeft(),\n                        0,\n                        bottomSheet.getPaddingRight(),\n                        bottomSheet.getPaddingBottom());\n            }\n        }\n    }\n\n    /**\n     * @deprecated use {@link EdgeToEdgeUtils#setLightStatusBar(Window, boolean)} instead\n     */\n    @Deprecated\n    public static void setLightStatusBar(@NonNull View view, boolean isLight) {\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {\n            int flags = view.getSystemUiVisibility();\n            if (isLight) {\n                flags |= View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;\n            } else {\n                flags &= ~View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;\n            }\n            view.setSystemUiVisibility(flags);\n        }\n    }\n}\n"
  },
  {
    "path": "libcore/ui/src/main/java/io/github/muntashirakon/dialog/CapsuleBottomSheetDialogFragment.java",
    "content": "// SPDX-License-Identifier: MIT AND GPL-3.0-or-later\n\npackage io.github.muntashirakon.dialog;\n\nimport android.app.Dialog;\nimport android.content.Context;\nimport android.graphics.drawable.Drawable;\nimport android.graphics.drawable.TransitionDrawable;\nimport android.os.Build;\nimport android.os.Bundle;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.view.Window;\nimport android.view.WindowManager;\nimport android.widget.FrameLayout;\nimport android.widget.RelativeLayout;\n\nimport androidx.annotation.CallSuper;\nimport androidx.annotation.MainThread;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.appcompat.widget.LinearLayoutCompat;\nimport androidx.core.content.ContextCompat;\nimport androidx.core.view.WindowCompat;\nimport androidx.core.view.WindowInsetsControllerCompat;\n\nimport com.google.android.material.bottomsheet.BottomSheetDialogFragment;\nimport com.google.android.material.bottomsheet.BottomSheetDragHandleView;\n\nimport java.util.Objects;\n\nimport io.github.muntashirakon.ui.R;\nimport io.github.muntashirakon.util.UiUtils;\n\n/**\n * A {@link BottomSheetDialogFragment} with a {@link BottomSheetDragHandleView} on top\n */\n// Copyright 2022 Muntashir Al-Islam\n// Copyright 2022 Absinthe\npublic abstract class CapsuleBottomSheetDialogFragment extends BottomSheetDialogFragment {\n    public static final String TAG = CapsuleBottomSheetDialogFragment.class.getSimpleName();\n\n    private LinearLayoutCompat mBottomSheetContainer;\n    private BottomSheetDragHandleView mDragHandle;\n    private LinearLayoutCompat mHeaderContainer;\n    private FrameLayout mMainContainer;\n    private LinearLayoutCompat mBodyContainer;\n    private RelativeLayout mLoadingLayout;\n    @Nullable\n    private View mHeader;\n    private View mBody;\n    private boolean mIsCapsuleActivated;\n    private boolean mIsLoadingFinished;\n    private BottomSheetBehavior<FrameLayout> mBehavior;\n\n    private final BottomSheetBehavior.BottomSheetCallback mBottomSheetCallback = new BottomSheetBehavior.BottomSheetCallback() {\n        @Override\n        public void onStateChanged(@NonNull View bottomSheet, int newState) {\n            switch (newState) {\n                case BottomSheetBehavior.STATE_DRAGGING:\n                    if (!mIsCapsuleActivated) {\n                        mIsCapsuleActivated = true;\n                        onCapsuleActivated(true);\n                    }\n                    break;\n                case BottomSheetBehavior.STATE_HALF_EXPANDED:\n                    throw new UnsupportedOperationException();\n                case BottomSheetBehavior.STATE_COLLAPSED:\n                    throw new UnsupportedOperationException();\n                case BottomSheetBehavior.STATE_EXPANDED:\n                    if (mIsCapsuleActivated) {\n                        mIsCapsuleActivated = false;\n                        onCapsuleActivated(false);\n                    }\n                    break;\n                case BottomSheetBehavior.STATE_HIDDEN:\n                case BottomSheetBehavior.STATE_SETTLING:\n                    break;\n            }\n        }\n\n        @Override\n        public void onSlide(@NonNull View bottomSheet, float slideOffset) {\n        }\n    };\n\n    public View getBody() {\n        return mBody;\n    }\n\n    public BottomSheetBehavior<FrameLayout> getBehavior() {\n        return mBehavior;\n    }\n\n    @MainThread\n    @NonNull\n    public abstract View initRootView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState);\n\n    @MainThread\n    public void onBodyInitialized(@NonNull View bodyView, @Nullable Bundle savedInstanceState) {\n    }\n\n    @MainThread\n    public boolean displayLoaderByDefault() {\n        return false;\n    }\n\n    @MainThread\n    public void startLoading() {\n        if (!mIsLoadingFinished) {\n            return;\n        }\n        mIsLoadingFinished = false;\n        mLoadingLayout.setVisibility(View.VISIBLE);\n        mBodyContainer.setVisibility(View.GONE);\n    }\n\n    @MainThread\n    public void finishLoading() {\n        if (mIsLoadingFinished) {\n            return;\n        }\n        mIsLoadingFinished = true;\n        mBodyContainer.setVisibility(View.VISIBLE);\n        if (mBodyContainer.getChildCount() != 1 && getBody() != null) {\n            mBodyContainer.addView(getBody(), new ViewGroup.LayoutParams(\n                    ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));\n        } // else Body has already been set, no need to set it again\n        mLoadingLayout.setVisibility(View.GONE);\n        mBehavior.setStateInternal(BottomSheetBehavior.STATE_EXPANDED);\n    }\n\n    @Nullable\n    public View getHeader() {\n        return mHeader;\n    }\n\n    public void setHeader(@Nullable View header) {\n        mHeader = header;\n        mHeaderContainer.removeAllViews();\n        if (header != null) {\n            // Remove top padding\n            // TODO: 12/8/22 Fix this workaround by unsetting the top padding in the DialogTitleBuilder\n            if (header.isPaddingRelative()) {\n                header.setPaddingRelative(header.getPaddingStart(), 0, header.getPaddingEnd(), header.getPaddingBottom());\n            } else {\n                header.setPadding(header.getPaddingStart(), 0, header.getPaddingEnd(), header.getPaddingBottom());\n            }\n            mHeaderContainer.addView(header, new LinearLayoutCompat.LayoutParams(\n                    ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));\n        }\n    }\n\n    @CallSuper\n    @NonNull\n    @Override\n    public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {\n        BottomSheetDialog dialog = new BottomSheetDialogInternal(requireContext(), getTheme());\n        mBehavior = dialog.getBehavior();\n        mBehavior.setFitToContents(true);\n        mBehavior.setSkipHalfExpanded(true);\n        mBehavior.setSkipCollapsed(true);\n        return dialog;\n    }\n\n    @NonNull\n    @Override\n    public final View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {\n        mBottomSheetContainer = (LinearLayoutCompat) inflater.inflate(R.layout.dialog_bottom_sheet_capsule, container, false);\n        mDragHandle = mBottomSheetContainer.findViewById(R.id.capsule);\n        mDragHandle.setImageDrawable(new TransitionDrawable(new Drawable[]{\n                ContextCompat.getDrawable(requireContext(), R.drawable.bottom_sheet_drag_handle),\n                ContextCompat.getDrawable(requireContext(), R.drawable.bottom_sheet_drag_handle_activated)\n        }));\n        mHeaderContainer = mBottomSheetContainer.findViewById(R.id.header);\n        mBodyContainer = mBottomSheetContainer.findViewById(R.id.body);\n        mLoadingLayout = mBottomSheetContainer.findViewById(R.id.loader);\n        mMainContainer = (FrameLayout) mBodyContainer.getParent();\n        mBody = initRootView(inflater, mBottomSheetContainer, savedInstanceState);\n\n        if (!displayLoaderByDefault()) {\n            finishLoading();\n        }\n        return mBottomSheetContainer;\n    }\n\n    @CallSuper\n    @Override\n    public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {\n        onBodyInitialized(mBody, savedInstanceState);\n    }\n\n    @CallSuper\n    @Override\n    public void onStart() {\n        super.onStart();\n        mBehavior.addBottomSheetCallback(mBottomSheetCallback);\n    }\n\n    @CallSuper\n    @Override\n    public void onStop() {\n        super.onStop();\n        mBehavior.removeBottomSheetCallback(mBottomSheetCallback);\n    }\n\n    @CallSuper\n    @Override\n    public void onDestroyView() {\n        mHeader = null;\n        mBody = null;\n        super.onDestroyView();\n    }\n\n    public void onCapsuleActivated(boolean activated) {\n        if (activated) {\n            ((TransitionDrawable) mDragHandle.getDrawable()).startTransition(150);\n        } else {\n            ((TransitionDrawable) mDragHandle.getDrawable()).reverseTransition(150);\n        }\n    }\n\n    private static class BottomSheetDialogInternal extends BottomSheetDialog {\n        public BottomSheetDialogInternal(@NonNull Context context, int theme) {\n            super(context, theme);\n        }\n\n        @Override\n        public void onAttachedToWindow() {\n            super.onAttachedToWindow();\n            Window window = getWindow();\n            if (window != null) {\n                window.getAttributes().windowAnimations = R.style.AppTheme_BottomSheetAnimation;\n                WindowCompat.setDecorFitsSystemWindows(window, false);\n                UiUtils.setSystemBarStyle(window, true);\n                new WindowInsetsControllerCompat(window, window.getDecorView())\n                        .setAppearanceLightNavigationBars(!UiUtils.isDarkMode());\n                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {\n                    window.addFlags(WindowManager.LayoutParams.FLAG_BLUR_BEHIND);\n                    window.getAttributes().setBlurBehindRadius(64);\n                    window.addFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);\n                }\n            }\n\n            Objects.requireNonNull((View) findViewById(R.id.container)).setFitsSystemWindows(false);\n            Objects.requireNonNull((View) findViewById(R.id.coordinator)).setFitsSystemWindows(false);\n        }\n    }\n}\n"
  },
  {
    "path": "libcore/ui/src/main/java/io/github/muntashirakon/dialog/DialogTitleBuilder.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.dialog;\n\nimport android.content.Context;\nimport android.graphics.drawable.Drawable;\nimport android.view.View;\nimport android.widget.FrameLayout;\nimport android.widget.ImageView;\nimport android.widget.TextView;\n\nimport androidx.annotation.DrawableRes;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.StringRes;\n\nimport com.google.android.material.button.MaterialButton;\n\nimport io.github.muntashirakon.ui.R;\nimport io.github.muntashirakon.util.UiUtils;\n\npublic class DialogTitleBuilder {\n    @NonNull\n    private final Context mContext;\n    private final View mView;\n    private final TextView mTitle;\n    private final TextView mSubtitle;\n    private final ImageView mStartIcon;\n    private final MaterialButton mEndIcon;\n    private final int mIconTopPadding;\n\n    public DialogTitleBuilder(@NonNull Context context) {\n        mContext = context;\n        mView = View.inflate(mContext, R.layout.dialog_title_with_two_icons, null);\n        mTitle = mView.findViewById(R.id.title);\n        mSubtitle = mView.findViewById(R.id.subtitle);\n        mSubtitle.setVisibility(View.GONE);\n        mStartIcon = mView.findViewById(R.id.icon);\n        mStartIcon.setVisibility(View.GONE);\n        mEndIcon = mView.findViewById(R.id.action);\n        mEndIcon.setVisibility(View.GONE);\n        mIconTopPadding = UiUtils.dpToPx(context, 12);\n    }\n\n    public DialogTitleBuilder setTitle(@Nullable CharSequence title) {\n        mTitle.setText(title);\n        return this;\n    }\n\n    public DialogTitleBuilder setTitle(@StringRes int titleRes) {\n        mTitle.setText(titleRes);\n        return this;\n    }\n\n    public DialogTitleBuilder setTitleSelectable(boolean titleSelectable) {\n        mTitle.setTextIsSelectable(titleSelectable);\n        return this;\n    }\n\n    public DialogTitleBuilder setSubtitle(@Nullable CharSequence subtitle) {\n        toggleVisibility(mSubtitle, subtitle != null);\n        updateIconPadding(subtitle != null);\n        mSubtitle.setText(subtitle);\n        return this;\n    }\n\n    public DialogTitleBuilder setSubtitle(@StringRes int subtitleRes) {\n        toggleVisibility(mSubtitle, subtitleRes != 0);\n        updateIconPadding(subtitleRes != 0);\n        mSubtitle.setText(subtitleRes);\n        return this;\n    }\n\n    public DialogTitleBuilder setSubtitleSelectable(boolean subtitleSelectable) {\n        mSubtitle.setTextIsSelectable(subtitleSelectable);\n        return this;\n    }\n\n    public DialogTitleBuilder setStartIcon(@Nullable Drawable startIcon) {\n        toggleVisibility(mStartIcon, startIcon != null);\n        mStartIcon.setImageDrawable(startIcon);\n        return this;\n    }\n\n    public DialogTitleBuilder setStartIcon(@DrawableRes int startIconRes) {\n        toggleVisibility(mStartIcon, startIconRes != 0);\n        mStartIcon.setImageResource(startIconRes);\n        return this;\n    }\n\n    public DialogTitleBuilder setEndIcon(@Nullable Drawable endIcon, @Nullable View.OnClickListener listener) {\n        toggleVisibility(mEndIcon, endIcon != null);\n        mEndIcon.setIcon(endIcon);\n        mEndIcon.setOnClickListener(listener);\n        return this;\n    }\n\n    public DialogTitleBuilder setEndIcon(@DrawableRes int endIconRes, @Nullable View.OnClickListener listener) {\n        toggleVisibility(mEndIcon, endIconRes != 0);\n        mEndIcon.setIconResource(endIconRes);\n        mEndIcon.setOnClickListener(listener);\n        return this;\n    }\n\n    public DialogTitleBuilder setEndIconContentDescription(@Nullable CharSequence endIconContentDescription) {\n        mEndIcon.setContentDescription(endIconContentDescription);\n        return this;\n    }\n\n    public DialogTitleBuilder setEndIconContentDescription(@StringRes int endIconContentDescriptionRes) {\n        mEndIcon.setContentDescription(mContext.getText(endIconContentDescriptionRes));\n        return this;\n    }\n\n    public View build() {\n        return mView;\n    }\n\n    private void toggleVisibility(@NonNull View v, boolean show) {\n        boolean isShown = v.isShown();\n        if (show) {\n            if (!isShown) {\n                v.setVisibility(View.VISIBLE);\n            }\n        } else if (isShown) {\n            v.setVisibility(View.GONE);\n        }\n    }\n\n    private void updateIconPadding(boolean set) {\n        ((FrameLayout) mStartIcon.getParent()).setPadding(0, set ? mIconTopPadding : 0, 0, 0);\n    }\n}\n"
  },
  {
    "path": "libcore/ui/src/main/java/io/github/muntashirakon/dialog/FullScreenDialogTitleBuilder.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.dialog;\n\nimport android.app.AlertDialog;\nimport android.content.Context;\nimport android.content.DialogInterface;\nimport android.graphics.drawable.Drawable;\nimport android.view.View;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.StringRes;\n\nimport com.google.android.material.appbar.MaterialToolbar;\nimport com.google.android.material.button.MaterialButton;\n\nimport io.github.muntashirakon.ui.R;\n\n@SuppressWarnings(\"UnusedReturnValue\")\npublic class FullScreenDialogTitleBuilder {\n    @NonNull\n    private final Context mContext;\n    @StringRes\n    private int mTitleRes;\n    @Nullable\n    private CharSequence mTitle;\n    @Nullable\n    private DialogInterface.OnClickListener mOnCloseButtonClickListener;\n    private int mCloseIconDescriptionRes = android.R.string.cancel;\n    @Nullable\n    private CharSequence mCloseIconDescription;\n    @Nullable\n    private Drawable mCloseButtonIcon;\n    @Nullable\n    private Drawable mPositiveButtonIcon;\n    @StringRes\n    private int mPositiveButtonTextRes;\n    @Nullable\n    private CharSequence mPositiveButtonText;\n    private DialogInterface.OnClickListener mOnPositiveButtonClickListener;\n    private boolean mExitOnButtonPress = true;\n\n    public FullScreenDialogTitleBuilder(@NonNull Context context) {\n        mContext = context;\n    }\n\n    public FullScreenDialogTitleBuilder setTitle(@Nullable CharSequence title) {\n        mTitle = title;\n        return this;\n    }\n\n    public FullScreenDialogTitleBuilder setTitle(@StringRes int titleId) {\n        mTitleRes = titleId;\n        return this;\n    }\n\n    public FullScreenDialogTitleBuilder setExitOnButtonPress(boolean exitOnButtonPress) {\n        mExitOnButtonPress = exitOnButtonPress;\n        return this;\n    }\n\n    public FullScreenDialogTitleBuilder setCloseButtonIcon(@Nullable Drawable closeButtonIcon) {\n        mCloseButtonIcon = closeButtonIcon;\n        return this;\n    }\n\n    public FullScreenDialogTitleBuilder setOnCloseButtonClickListener(@Nullable DialogInterface.OnClickListener listener) {\n        mOnCloseButtonClickListener = listener;\n        return this;\n    }\n\n    public FullScreenDialogTitleBuilder setCloseIconContentDescription(@Nullable CharSequence closeIconDescription) {\n        mCloseIconDescription = closeIconDescription;\n        return this;\n    }\n\n    public FullScreenDialogTitleBuilder setCloseIconContentDescription(@StringRes int strRes) {\n        mCloseIconDescriptionRes = strRes;\n        return this;\n    }\n\n    public FullScreenDialogTitleBuilder setPositiveButtonIcon(Drawable positiveButtonIcon) {\n        mPositiveButtonIcon = positiveButtonIcon;\n        return this;\n    }\n\n    public FullScreenDialogTitleBuilder setPositiveButtonText(@Nullable CharSequence text) {\n        mPositiveButtonText = text;\n        return this;\n    }\n\n    public FullScreenDialogTitleBuilder setPositiveButtonText(@StringRes int textId) {\n        mPositiveButtonTextRes = textId;\n        return this;\n    }\n\n    public FullScreenDialogTitleBuilder setOnPositiveButtonClickListener(DialogInterface.OnClickListener listener) {\n        mOnPositiveButtonClickListener = listener;\n        return this;\n    }\n\n    public View build(DialogInterface dialog) {\n        View v = View.inflate(mContext, R.layout.dialog_title_toolbar, null);\n        MaterialToolbar toolbar = v.findViewById(R.id.toolbar);\n        if (mTitle != null) toolbar.setTitle(mTitle);\n        else if (mTitleRes != 0) toolbar.setTitle(mTitleRes);\n        if (mCloseButtonIcon != null) {\n            toolbar.setNavigationIcon(mCloseButtonIcon);\n        }\n        // TODO: 28/1/22 Use Handler instead of lamda functions\n        if (mOnCloseButtonClickListener != null) {\n            toolbar.setNavigationOnClickListener(v1 -> {\n                mOnCloseButtonClickListener.onClick(dialog, AlertDialog.BUTTON_NEGATIVE);\n                if (mExitOnButtonPress) dialog.dismiss();\n            });\n        } else {\n            toolbar.setNavigationOnClickListener(v1 -> dialog.dismiss());\n        }\n        if (mCloseIconDescription != null) {\n            toolbar.setNavigationContentDescription(mCloseIconDescription);\n        } else {\n            toolbar.setNavigationContentDescription(mCloseIconDescriptionRes);\n        }\n        MaterialButton positiveButton = v.findViewById(android.R.id.button1);\n        if (mOnPositiveButtonClickListener != null) {\n            positiveButton.setOnClickListener(v1 -> {\n                mOnPositiveButtonClickListener.onClick(dialog, AlertDialog.BUTTON_POSITIVE);\n                if (mExitOnButtonPress) dialog.dismiss();\n            });\n        } else {\n            positiveButton.setOnClickListener(v1 -> dialog.dismiss());\n        }\n        if (mPositiveButtonIcon != null) {\n            // Set icon only, remove text\n            positiveButton.setIcon(mPositiveButtonIcon);\n            positiveButton.setIconPadding(0);\n            positiveButton.setIconGravity(MaterialButton.ICON_GRAVITY_TEXT_TOP);\n            positiveButton.setText(null);\n            if (mPositiveButtonText != null) {\n                positiveButton.setContentDescription(mPositiveButtonText);\n            } else if (mPositiveButtonTextRes != 0) {\n                positiveButton.setContentDescription(mContext.getString(mPositiveButtonTextRes));\n            }\n        } else if (mPositiveButtonText != null) {\n            positiveButton.setText(mPositiveButtonText);\n        } else if (mPositiveButtonTextRes != 0) {\n            positiveButton.setText(mPositiveButtonTextRes);\n        } else positiveButton.setVisibility(View.GONE);\n        return v;\n    }\n}\n"
  },
  {
    "path": "libcore/ui/src/main/java/io/github/muntashirakon/dialog/ScrollableDialogBuilder.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.dialog;\n\nimport android.content.Context;\nimport android.content.DialogInterface;\nimport android.text.method.LinkMovementMethod;\nimport android.text.util.Linkify;\nimport android.view.View;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.StringRes;\nimport androidx.appcompat.app.AlertDialog;\nimport androidx.core.text.util.LinkifyCompat;\n\nimport com.google.android.material.checkbox.MaterialCheckBox;\nimport com.google.android.material.textview.MaterialTextView;\n\nimport io.github.muntashirakon.ui.R;\n\n@SuppressWarnings(\"unused\")\npublic class ScrollableDialogBuilder {\n    @NonNull\n    private final MaterialTextView mMessage;\n    @NonNull\n    private final MaterialCheckBox mCheckBox;\n    @NonNull\n    private final AlertDialogBuilder mBuilder;\n\n    public interface OnClickListener {\n        void onClick(DialogInterface dialog, int which, boolean isChecked);\n    }\n\n    public ScrollableDialogBuilder(@NonNull Context context, @Nullable CharSequence message, boolean fullScreen) {\n        View view = View.inflate(context, R.layout.dialog_scrollable_text_view, null);\n        mMessage = view.findViewById(android.R.id.content);\n        mMessage.setText(message);\n        mCheckBox = view.findViewById(android.R.id.checkbox);\n        mCheckBox.setVisibility(View.GONE);\n        mBuilder = new AlertDialogBuilder(context, fullScreen).setView(view);\n    }\n\n    public ScrollableDialogBuilder(@NonNull Context context, @Nullable CharSequence message) {\n        this(context, message, false);\n    }\n\n    public ScrollableDialogBuilder(@NonNull Context context, boolean fullScreen) {\n        this(context, null, fullScreen);\n    }\n\n    public ScrollableDialogBuilder(@NonNull Context context) {\n        this(context, null);\n    }\n\n    public ScrollableDialogBuilder(@NonNull Context context, @StringRes int inputTextLabel) {\n        this(context, context.getText(inputTextLabel));\n    }\n\n    public ScrollableDialogBuilder setTitle(@Nullable View title) {\n        mBuilder.setCustomTitle(title);\n        return this;\n    }\n\n    public ScrollableDialogBuilder setTitle(@Nullable CharSequence title) {\n        mBuilder.setTitle(title);\n        return this;\n    }\n\n    public ScrollableDialogBuilder setTitle(@StringRes int title) {\n        mBuilder.setTitle(title);\n        return this;\n    }\n\n    public ScrollableDialogBuilder setMessage(@StringRes int message) {\n        mMessage.setText(message);\n        return this;\n    }\n\n    public ScrollableDialogBuilder setMessage(@Nullable CharSequence message) {\n        mMessage.setText(message);\n        return this;\n    }\n\n    public ScrollableDialogBuilder setSelectable(boolean selectable) {\n        mMessage.setTextIsSelectable(selectable);\n        return this;\n    }\n\n    public ScrollableDialogBuilder enableAnchors() {\n        mMessage.setMovementMethod(LinkMovementMethod.getInstance());\n        return this;\n    }\n\n    public ScrollableDialogBuilder linkify(@LinkifyCompat.LinkifyMask int mask) {\n        LinkifyCompat.addLinks(mMessage, mask);\n        return this;\n    }\n\n    public ScrollableDialogBuilder linkifyAll() {\n        return linkify(Linkify.ALL);\n    }\n\n    public ScrollableDialogBuilder setCheckboxLabel(@Nullable CharSequence checkboxLabel) {\n        if (checkboxLabel != null) {\n            mCheckBox.setVisibility(View.VISIBLE);\n            mCheckBox.setText(checkboxLabel);\n        } else mCheckBox.setVisibility(View.GONE);\n        return this;\n    }\n\n    public ScrollableDialogBuilder setCheckboxLabel(@StringRes int checkboxLabel) {\n        if (checkboxLabel != 0) {\n            mCheckBox.setVisibility(View.VISIBLE);\n            mCheckBox.setText(checkboxLabel);\n        } else mCheckBox.setVisibility(View.GONE);\n        return this;\n    }\n\n    public ScrollableDialogBuilder setPositiveButton(@StringRes int textId, @Nullable OnClickListener listener) {\n        mBuilder.setPositiveButton(textId, (dialog, which) -> {\n            if (listener != null) listener.onClick(dialog, which, mCheckBox.isChecked());\n        });\n        return this;\n    }\n\n    public ScrollableDialogBuilder setPositiveButton(@NonNull CharSequence text, @Nullable OnClickListener listener) {\n        mBuilder.setPositiveButton(text, (dialog, which) -> {\n            if (listener != null) listener.onClick(dialog, which, mCheckBox.isChecked());\n        });\n        return this;\n    }\n\n    public ScrollableDialogBuilder setNegativeButton(@StringRes int textId, @Nullable OnClickListener listener) {\n        mBuilder.setNegativeButton(textId, (dialog, which) -> {\n            if (listener != null) listener.onClick(dialog, which, mCheckBox.isChecked());\n        });\n        return this;\n    }\n\n    public ScrollableDialogBuilder setNegativeButton(@NonNull CharSequence text, @Nullable OnClickListener listener) {\n        mBuilder.setNegativeButton(text, (dialog, which) -> {\n            if (listener != null) listener.onClick(dialog, which, mCheckBox.isChecked());\n        });\n        return this;\n    }\n\n    public ScrollableDialogBuilder setNeutralButton(@StringRes int textId, @Nullable OnClickListener listener) {\n        mBuilder.setNeutralButton(textId, (dialog, which) -> {\n            if (listener != null) listener.onClick(dialog, which, mCheckBox.isChecked());\n        });\n        return this;\n    }\n\n    public ScrollableDialogBuilder setNeutralButton(@NonNull CharSequence text, @Nullable OnClickListener listener) {\n        mBuilder.setNeutralButton(text, (dialog, which) -> {\n            if (listener != null) listener.onClick(dialog, which, mCheckBox.isChecked());\n        });\n        return this;\n    }\n\n    @NonNull\n    public AlertDialog create() {\n        return mBuilder.create();\n    }\n\n    public void show() {\n        create().show();\n    }\n}\n"
  },
  {
    "path": "libcore/ui/src/main/java/io/github/muntashirakon/dialog/SearchableFlagsDialogBuilder.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.dialog;\n\nimport android.content.Context;\nimport android.view.View;\n\nimport androidx.annotation.ArrayRes;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.StringRes;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\n\npublic class SearchableFlagsDialogBuilder<T extends Number> extends SearchableMultiChoiceDialogBuilder<T> {\n    public SearchableFlagsDialogBuilder(@NonNull Context context, @NonNull List<T> items, @ArrayRes int itemNames,\n                                        @NonNull T defaultFlags) {\n        this(context, items, context.getResources().getTextArray(itemNames), defaultFlags);\n    }\n\n    public SearchableFlagsDialogBuilder(@NonNull Context context, @NonNull T[] items, @NonNull CharSequence[] itemNames,\n                                        @NonNull T defaultFlags) {\n        this(context, Arrays.asList(items), Arrays.asList(itemNames), defaultFlags);\n    }\n\n    public SearchableFlagsDialogBuilder(@NonNull Context context, @NonNull List<T> items,\n                                        @NonNull CharSequence[] itemNames, @NonNull T defaultFlags) {\n        this(context, items, Arrays.asList(itemNames), defaultFlags);\n    }\n\n    public SearchableFlagsDialogBuilder(@NonNull Context context, @NonNull List<T> items,\n                                        @NonNull List<CharSequence> itemNames, @NonNull T defaultFlags) {\n        super(context, items, itemNames);\n        List<T> selectedFlags = new ArrayList<>();\n        long flags = defaultFlags.longValue();\n        for (T item : items) {\n            if ((flags & item.longValue()) != 0) {\n                selectedFlags.add(item);\n            }\n        }\n        addSelections(selectedFlags);\n    }\n\n\n    @Override\n    public SearchableFlagsDialogBuilder<T> setOnMultiChoiceClickListener(@Nullable OnMultiChoiceClickListener<T> onMultiChoiceClickListener) {\n        super.setOnMultiChoiceClickListener(onMultiChoiceClickListener);\n        return this;\n    }\n\n    @Override\n    public SearchableFlagsDialogBuilder<T> addDisabledItems(@Nullable List<T> disabledItems) {\n        super.addDisabledItems(disabledItems);\n        return this;\n    }\n\n    @Override\n    public SearchableFlagsDialogBuilder<T> addSelections(@Nullable List<T> selectedItems) {\n        super.addSelections(selectedItems);\n        return this;\n    }\n\n    @Override\n    public SearchableFlagsDialogBuilder<T> addSelections(@Nullable int[] selectedIndexes) {\n        super.addSelections(selectedIndexes);\n        return this;\n    }\n\n    @Override\n    public SearchableFlagsDialogBuilder<T> removeSelections(@Nullable int[] selectedIndexes) {\n        super.removeSelections(selectedIndexes);\n        return this;\n    }\n\n    @Override\n    public SearchableFlagsDialogBuilder<T> reloadListUi() {\n        super.reloadListUi();\n        return this;\n    }\n\n    @Override\n    public SearchableFlagsDialogBuilder<T> setTextSelectable(boolean textSelectable) {\n        super.setTextSelectable(textSelectable);\n        return this;\n    }\n\n    @Override\n    public SearchableFlagsDialogBuilder<T> setCancelable(boolean cancelable) {\n        super.setCancelable(cancelable);\n        return this;\n    }\n\n    @Override\n    public SearchableFlagsDialogBuilder<T> hideSearchBar(boolean hide) {\n        super.hideSearchBar(hide);\n        return this;\n    }\n\n    @Override\n    public SearchableFlagsDialogBuilder<T> showSelectAll(boolean show) {\n        super.showSelectAll(show);\n        return this;\n    }\n\n    @Override\n    public SearchableFlagsDialogBuilder<T> setTitle(@Nullable CharSequence title) {\n        super.setTitle(title);\n        return this;\n    }\n\n    @Override\n    public SearchableFlagsDialogBuilder<T> setTitle(@StringRes int title) {\n        super.setTitle(title);\n        return this;\n    }\n\n    @Override\n    public SearchableFlagsDialogBuilder<T> setTitle(@Nullable View title) {\n        super.setTitle(title);\n        return this;\n    }\n\n    @Override\n    public SearchableFlagsDialogBuilder<T> setPositiveButton(@StringRes int textId, @Nullable OnClickListener<T> listener) {\n        super.setPositiveButton(textId, listener);\n        return this;\n    }\n\n    @Override\n    public SearchableFlagsDialogBuilder<T> setPositiveButton(@NonNull CharSequence text, @Nullable OnClickListener<T> listener) {\n        super.setPositiveButton(text, listener);\n        return this;\n    }\n\n    @Override\n    public SearchableFlagsDialogBuilder<T> setNegativeButton(@StringRes int textId, @Nullable OnClickListener<T> listener) {\n        super.setNegativeButton(textId, listener);\n        return this;\n    }\n\n    @Override\n    public SearchableFlagsDialogBuilder<T> setNegativeButton(@NonNull CharSequence text, @Nullable OnClickListener<T> listener) {\n        super.setNegativeButton(text, listener);\n        return this;\n    }\n\n    @Override\n    public SearchableFlagsDialogBuilder<T> setNeutralButton(@StringRes int textId, @Nullable OnClickListener<T> listener) {\n        super.setNeutralButton(textId, listener);\n        return this;\n    }\n\n    @Override\n    public SearchableFlagsDialogBuilder<T> setNeutralButton(@NonNull CharSequence text, @Nullable OnClickListener<T> listener) {\n        super.setNeutralButton(text, listener);\n        return this;\n    }\n}\n"
  },
  {
    "path": "libcore/ui/src/main/java/io/github/muntashirakon/dialog/SearchableItemsDialogBuilder.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.dialog;\n\nimport android.annotation.SuppressLint;\nimport android.content.Context;\nimport android.content.DialogInterface;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.TextView;\n\nimport androidx.annotation.ArrayRes;\nimport androidx.annotation.ColorInt;\nimport androidx.annotation.LayoutRes;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.StringRes;\nimport androidx.appcompat.app.AlertDialog;\nimport androidx.collection.ArraySet;\nimport androidx.recyclerview.widget.LinearLayoutManager;\nimport androidx.recyclerview.widget.RecyclerView;\n\nimport com.google.android.material.card.MaterialCardView;\nimport com.google.android.material.dialog.MaterialAlertDialogBuilder;\nimport com.google.android.material.resources.MaterialAttributes;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Set;\n\nimport io.github.muntashirakon.ui.R;\nimport io.github.muntashirakon.util.AdapterUtils;\nimport io.github.muntashirakon.widget.SearchView;\n\npublic class SearchableItemsDialogBuilder<T extends CharSequence> {\n    @NonNull\n    private final MaterialAlertDialogBuilder mBuilder;\n    private final SearchView mSearchView;\n    @NonNull\n    private final SearchableRecyclerViewAdapter mAdapter;\n    @Nullable\n    private AlertDialog mDialog;\n    @Nullable\n    private OnItemClickListener<T> mOnItemClickListener;\n    private boolean mIsTextSelectable;\n    @ColorInt\n    private Integer mListBackgroundColorEven;\n    @ColorInt\n    private Integer mListBackgroundColorOdd;\n\n    public interface OnItemClickListener<T> {\n        void onClick(DialogInterface dialog, int which, T item);\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    public SearchableItemsDialogBuilder(@NonNull Context context, @ArrayRes int itemNames) {\n        this(context, (T[]) context.getResources().getTextArray(itemNames));\n    }\n\n    public SearchableItemsDialogBuilder(@NonNull Context context, @NonNull T[] itemNames) {\n        this(context, Arrays.asList(itemNames));\n    }\n\n    public SearchableItemsDialogBuilder(@NonNull Context context, @NonNull List<T> itemNames) {\n        View view = View.inflate(context, R.layout.dialog_searchable_single_choice, null);\n        RecyclerView recyclerView = view.findViewById(android.R.id.list);\n        recyclerView.setLayoutManager(new LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false));\n        mSearchView = view.findViewById(R.id.action_search);\n        mSearchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {\n            @Override\n            public boolean onQueryTextSubmit(String query) {\n                return false;\n            }\n\n            @Override\n            public boolean onQueryTextChange(String newText) {\n                mAdapter.setFilteredItems(newText);\n                return true;\n            }\n        });\n        // Don't display search bar if items are less than 6\n        if (itemNames.size() < 6) {\n            mSearchView.setVisibility(View.GONE);\n        }\n        mBuilder = new MaterialAlertDialogBuilder(context).setView(view);\n        @SuppressLint({\"RestrictedApi\", \"PrivateResource\"})\n        int layoutId = MaterialAttributes.resolveInteger(context, androidx.appcompat.R.attr.listItemLayout,\n                R.layout.m3_alert_select_dialog_item);\n        mAdapter = new SearchableRecyclerViewAdapter(itemNames, layoutId);\n        recyclerView.setAdapter(mAdapter);\n    }\n\n    public SearchableItemsDialogBuilder<T> setOnItemClickListener(@Nullable OnItemClickListener<T>\n                                                                          onItemClickListener) {\n        mOnItemClickListener = onItemClickListener;\n        return this;\n    }\n\n    public SearchableItemsDialogBuilder<T> addDisabledItems(@Nullable List<T> disabledItems) {\n        mAdapter.addDisabledItems(disabledItems);\n        return this;\n    }\n\n    public SearchableItemsDialogBuilder<T> setListBackgroundColorEven(@ColorInt Integer color) {\n        mListBackgroundColorEven = color;\n        return this;\n    }\n\n    public SearchableItemsDialogBuilder<T> setListBackgroundColorOdd(@ColorInt Integer color) {\n        mListBackgroundColorOdd = color;\n        return this;\n    }\n\n    public SearchableItemsDialogBuilder<T> reloadListUi() {\n        mAdapter.notifyItemRangeChanged(0, mAdapter.getItemCount(), AdapterUtils.STUB);\n        return this;\n    }\n\n    public SearchableItemsDialogBuilder<T> setTextSelectable(boolean textSelectable) {\n        mIsTextSelectable = textSelectable;\n        return this;\n    }\n\n    public SearchableItemsDialogBuilder<T> setCancelable(boolean cancelable) {\n        mBuilder.setCancelable(cancelable);\n        return this;\n    }\n\n    public SearchableItemsDialogBuilder<T> hideSearchBar(boolean hide) {\n        mSearchView.setVisibility(hide ? View.GONE : View.VISIBLE);\n        return this;\n    }\n\n    public SearchableItemsDialogBuilder<T> setTitle(@Nullable CharSequence title) {\n        mBuilder.setTitle(title);\n        return this;\n    }\n\n    public SearchableItemsDialogBuilder<T> setTitle(@StringRes int title) {\n        mBuilder.setTitle(title);\n        return this;\n    }\n\n    public SearchableItemsDialogBuilder<T> setTitle(View title) {\n        mBuilder.setCustomTitle(title);\n        return this;\n    }\n\n    public SearchableItemsDialogBuilder<T> setPositiveButton(@StringRes int textId,\n                                                             @Nullable DialogInterface.OnClickListener listener) {\n        mBuilder.setPositiveButton(textId, listener);\n        return this;\n    }\n\n    public SearchableItemsDialogBuilder<T> setPositiveButton(@NonNull CharSequence text,\n                                                             @Nullable DialogInterface.OnClickListener listener) {\n        mBuilder.setPositiveButton(text, listener);\n        return this;\n    }\n\n    public SearchableItemsDialogBuilder<T> setNegativeButton(@StringRes int textId,\n                                                             @Nullable DialogInterface.OnClickListener listener) {\n        mBuilder.setNegativeButton(textId, listener);\n        return this;\n    }\n\n    public SearchableItemsDialogBuilder<T> setNegativeButton(@NonNull CharSequence text,\n                                                             @Nullable DialogInterface.OnClickListener listener) {\n        mBuilder.setNegativeButton(text, listener);\n        return this;\n    }\n\n    public SearchableItemsDialogBuilder<T> setNeutralButton(@StringRes int textId,\n                                                            @Nullable DialogInterface.OnClickListener listener) {\n        mBuilder.setNeutralButton(textId, listener);\n        return this;\n    }\n\n    public SearchableItemsDialogBuilder<T> setNeutralButton(@NonNull CharSequence text,\n                                                            @Nullable DialogInterface.OnClickListener listener) {\n        mBuilder.setNeutralButton(text, listener);\n        return this;\n    }\n\n    public AlertDialog create() {\n        return mDialog = mBuilder.create();\n    }\n\n    public AlertDialog show() {\n        return mDialog = mBuilder.show();\n    }\n\n    private void triggerItemClickListener(int index) {\n        if (mDialog != null && mOnItemClickListener != null) {\n            mOnItemClickListener.onClick(mDialog, index, mAdapter.mItems.get(index));\n        }\n    }\n\n    class SearchableRecyclerViewAdapter extends RecyclerView.Adapter<SearchableRecyclerViewAdapter.ViewHolder> {\n        @NonNull\n        private final List<T> mItems;\n        @NonNull\n        private final ArrayList<Integer> mFilteredItems = new ArrayList<>();\n        private final Set<Integer> mDisabledItems = new ArraySet<>();\n        @LayoutRes\n        private final int mLayoutId;\n\n        SearchableRecyclerViewAdapter(@NonNull List<T> items, int layoutId) {\n            mItems = items;\n            mLayoutId = layoutId;\n            synchronized (mFilteredItems) {\n                for (int i = 0; i < mItems.size(); ++i) {\n                    mFilteredItems.add(i);\n                }\n            }\n        }\n\n        void setFilteredItems(CharSequence constraint) {\n            Locale locale = Locale.getDefault();\n            synchronized (mFilteredItems) {\n                int previousCount = mFilteredItems.size();\n                mFilteredItems.clear();\n                for (int i = 0; i < mItems.size(); ++i) {\n                    if (mItems.get(i).toString().toLowerCase(locale).contains(constraint)) {\n                        mFilteredItems.add(i);\n                    }\n                }\n                AdapterUtils.notifyDataSetChanged(this, previousCount, mFilteredItems.size());\n            }\n        }\n\n        void addDisabledItems(@Nullable List<T> disabledItems) {\n            if (disabledItems != null) {\n                for (T item : disabledItems) {\n                    int index = mItems.indexOf(item);\n                    if (index != -1) {\n                        synchronized (mDisabledItems) {\n                            mDisabledItems.add(index);\n                        }\n                    }\n                }\n            }\n        }\n\n        @NonNull\n        @Override\n        public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {\n            View view = LayoutInflater.from(parent.getContext()).inflate(mLayoutId, parent, false);\n            return new ViewHolder(view);\n        }\n\n        @Override\n        public void onBindViewHolder(@NonNull ViewHolder holder, int position) {\n            Integer index;\n            synchronized (mFilteredItems) {\n                index = mFilteredItems.get(position);\n            }\n            holder.item.setText(mItems.get(index));\n            holder.item.setTextIsSelectable(mIsTextSelectable);\n            synchronized (mDisabledItems) {\n                holder.item.setEnabled(!mDisabledItems.contains(index));\n            }\n            holder.itemView.setOnClickListener(v -> triggerItemClickListener(index));\n            // Set background colors if set (position starts at 1, so the situation is reversed)\n            setBackgroundColor(holder.itemView, position % 2 == 0 ? mListBackgroundColorOdd : mListBackgroundColorEven);\n        }\n\n        private void setBackgroundColor(View view, @Nullable Integer color) {\n            if (view instanceof MaterialCardView) {\n                MaterialCardView card = (MaterialCardView) view;\n                if (color != null) {\n                    card.setCardBackgroundColor(color);\n                } else {\n                    // Reset background\n                    card.setCardBackgroundColor(null);\n                }\n            } else {\n                if (color != null) {\n                    view.setBackgroundColor(color);\n                } else {\n                    // Reset background\n                    view.setBackground(null);\n                }\n            }\n        }\n\n        @Override\n        public int getItemCount() {\n            synchronized (mFilteredItems) {\n                return mFilteredItems.size();\n            }\n        }\n\n        class ViewHolder extends RecyclerView.ViewHolder {\n            TextView item;\n\n            @SuppressLint(\"RestrictedApi\")\n            public ViewHolder(@NonNull View itemView) {\n                super(itemView);\n                itemView.findViewById(R.id.icon_frame).setVisibility(View.GONE);\n                itemView.findViewById(android.R.id.widget_frame).setVisibility(View.GONE);\n                item = itemView.findViewById(android.R.id.text1);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "libcore/ui/src/main/java/io/github/muntashirakon/dialog/SearchableMultiChoiceDialogBuilder.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.dialog;\n\nimport android.annotation.SuppressLint;\nimport android.content.Context;\nimport android.content.DialogInterface;\nimport android.util.TypedValue;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.CheckedTextView;\n\nimport androidx.annotation.ArrayRes;\nimport androidx.annotation.LayoutRes;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.StringRes;\nimport androidx.appcompat.app.AlertDialog;\nimport androidx.collection.ArraySet;\nimport androidx.core.widget.TextViewCompat;\nimport androidx.recyclerview.widget.LinearLayoutManager;\nimport androidx.recyclerview.widget.RecyclerView;\n\nimport com.google.android.material.color.MaterialColors;\nimport com.google.android.material.dialog.MaterialAlertDialogBuilder;\nimport com.google.android.material.resources.MaterialAttributes;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Set;\nimport java.util.concurrent.atomic.AtomicBoolean;\n\nimport io.github.muntashirakon.ui.R;\nimport io.github.muntashirakon.util.AdapterUtils;\nimport io.github.muntashirakon.widget.CheckBox;\nimport io.github.muntashirakon.widget.SearchView;\n\npublic class SearchableMultiChoiceDialogBuilder<T> {\n    private final View mView;\n    @NonNull\n    private final MaterialAlertDialogBuilder mBuilder;\n    private final SearchView mSearchView;\n    private final CheckBox mSelectAll;\n    @NonNull\n    private final SearchableRecyclerViewAdapter mAdapter;\n    @Nullable\n    private AlertDialog mDialog;\n    @Nullable\n    private OnMultiChoiceClickListener<T> mOnMultiChoiceClickListener;\n    private boolean mIsTextSelectable;\n\n    public interface OnClickListener<T> {\n        void onClick(DialogInterface dialog, int which, @NonNull ArrayList<T> selectedItems);\n    }\n\n    public interface OnMultiChoiceClickListener<T> {\n        void onClick(DialogInterface dialog, int which, T item, boolean isChecked);\n    }\n\n    public SearchableMultiChoiceDialogBuilder(@NonNull Context context, @NonNull List<T> items, @ArrayRes int itemNames) {\n        this(context, items, context.getResources().getTextArray(itemNames));\n    }\n\n    public SearchableMultiChoiceDialogBuilder(@NonNull Context context, @NonNull T[] items, @NonNull CharSequence[] itemNames) {\n        this(context, Arrays.asList(items), Arrays.asList(itemNames));\n    }\n\n    public SearchableMultiChoiceDialogBuilder(@NonNull Context context, @NonNull List<T> items, @NonNull CharSequence[] itemNames) {\n        this(context, items, Arrays.asList(itemNames));\n    }\n\n    public SearchableMultiChoiceDialogBuilder(@NonNull Context context, @NonNull List<T> items, @NonNull List<CharSequence> itemNames) {\n        mView = View.inflate(context, R.layout.dialog_searchable_multi_choice, null);\n        RecyclerView recyclerView = mView.findViewById(android.R.id.list);\n        recyclerView.setLayoutManager(new LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false));\n        mSearchView = mView.findViewById(R.id.action_search);\n        mSelectAll = mView.findViewById(android.R.id.checkbox);\n        mSearchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {\n            @Override\n            public boolean onQueryTextSubmit(String query) {\n                return false;\n            }\n\n            @Override\n            public boolean onQueryTextChange(String newText) {\n                mAdapter.setFilteredItems(newText);\n                return true;\n            }\n        });\n        // Don't display search bar if items are less than 6\n        if (items.size() < 6) {\n            mSearchView.setVisibility(View.GONE);\n        }\n        mBuilder = new MaterialAlertDialogBuilder(context).setView(mView);\n        @SuppressLint({\"RestrictedApi\", \"PrivateResource\"})\n        int layoutId = MaterialAttributes.resolveInteger(context, androidx.appcompat.R.attr.multiChoiceItemLayout,\n                com.google.android.material.R.layout.mtrl_alert_select_dialog_multichoice);\n        mAdapter = new SearchableRecyclerViewAdapter(itemNames, items, layoutId);\n        recyclerView.setAdapter(mAdapter);\n        mSelectAll.setOnCheckedChangeListener((buttonView, isChecked) -> {\n            if (isChecked) {\n                mAdapter.selectAll();\n            } else {\n                mAdapter.deselectAll();\n            }\n        });\n        if (items.size() < 2) {\n            // No need to display select all if only one item is present\n            mSelectAll.setVisibility(View.GONE);\n        }\n        checkSelections();\n    }\n\n    public View getView() {\n        return mView;\n    }\n\n    public SearchableMultiChoiceDialogBuilder<T> setOnMultiChoiceClickListener(@Nullable OnMultiChoiceClickListener<T>\n                                                                                       onMultiChoiceClickListener) {\n        mOnMultiChoiceClickListener = onMultiChoiceClickListener;\n        return this;\n    }\n\n    public SearchableMultiChoiceDialogBuilder<T> addDisabledItems(@Nullable List<T> disabledItems) {\n        mAdapter.addDisabledItems(disabledItems);\n        checkSelections();\n        return this;\n    }\n\n    public SearchableMultiChoiceDialogBuilder<T> addSelections(@Nullable List<T> selectedItems) {\n        mAdapter.addSelectedItems(selectedItems);\n        checkSelections();\n        return this;\n    }\n\n    public SearchableMultiChoiceDialogBuilder<T> addSelections(@Nullable int[] selectedIndexes) {\n        mAdapter.addSelectedIndexes(selectedIndexes);\n        checkSelections();\n        return this;\n    }\n\n    public SearchableMultiChoiceDialogBuilder<T> removeSelections(@Nullable int[] selectedIndexes) {\n        mAdapter.removeSelectedIndexes(selectedIndexes);\n        checkSelections();\n        return this;\n    }\n\n    public SearchableMultiChoiceDialogBuilder<T> reloadListUi() {\n        mAdapter.notifyItemRangeChanged(0, mAdapter.getItemCount(), AdapterUtils.STUB);\n        return this;\n    }\n\n    public SearchableMultiChoiceDialogBuilder<T> setTextSelectable(boolean textSelectable) {\n        mIsTextSelectable = textSelectable;\n        return this;\n    }\n\n    public SearchableMultiChoiceDialogBuilder<T> setCancelable(boolean cancelable) {\n        mBuilder.setCancelable(cancelable);\n        return this;\n    }\n\n    public SearchableMultiChoiceDialogBuilder<T> hideSearchBar(boolean hide) {\n        mSearchView.setVisibility(hide ? View.GONE : View.VISIBLE);\n        return this;\n    }\n\n    public SearchableMultiChoiceDialogBuilder<T> showSelectAll(boolean show) {\n        mSelectAll.setVisibility(show ? View.VISIBLE : View.GONE);\n        return this;\n    }\n\n    public SearchableMultiChoiceDialogBuilder<T> setTitle(@Nullable CharSequence title) {\n        mBuilder.setTitle(title);\n        return this;\n    }\n\n    public SearchableMultiChoiceDialogBuilder<T> setTitle(@StringRes int title) {\n        mBuilder.setTitle(title);\n        return this;\n    }\n\n    public SearchableMultiChoiceDialogBuilder<T> setTitle(@Nullable View title) {\n        mBuilder.setCustomTitle(title);\n        return this;\n    }\n\n    public SearchableMultiChoiceDialogBuilder<T> setPositiveButton(@StringRes int textId, @Nullable OnClickListener<T> listener) {\n        mBuilder.setPositiveButton(textId, (dialog, which) -> {\n            if (listener != null) listener.onClick(dialog, which, mAdapter.getSelectedItems());\n        });\n        return this;\n    }\n\n    public SearchableMultiChoiceDialogBuilder<T> setPositiveButton(@NonNull CharSequence text, @Nullable OnClickListener<T> listener) {\n        mBuilder.setPositiveButton(text, (dialog, which) -> {\n            if (listener != null) listener.onClick(dialog, which, mAdapter.getSelectedItems());\n        });\n        return this;\n    }\n\n    public SearchableMultiChoiceDialogBuilder<T> setNegativeButton(@StringRes int textId, @Nullable OnClickListener<T> listener) {\n        mBuilder.setNegativeButton(textId, (dialog, which) -> {\n            if (listener != null) listener.onClick(dialog, which, mAdapter.getSelectedItems());\n        });\n        return this;\n    }\n\n    public SearchableMultiChoiceDialogBuilder<T> setNegativeButton(@NonNull CharSequence text, @Nullable OnClickListener<T> listener) {\n        mBuilder.setNegativeButton(text, (dialog, which) -> {\n            if (listener != null) listener.onClick(dialog, which, mAdapter.getSelectedItems());\n        });\n        return this;\n    }\n\n    public SearchableMultiChoiceDialogBuilder<T> setNeutralButton(@StringRes int textId, @Nullable OnClickListener<T> listener) {\n        mBuilder.setNeutralButton(textId, (dialog, which) -> {\n            if (listener != null) listener.onClick(dialog, which, mAdapter.getSelectedItems());\n        });\n        return this;\n    }\n\n    public SearchableMultiChoiceDialogBuilder<T> setNeutralButton(@NonNull CharSequence text, @Nullable OnClickListener<T> listener) {\n        mBuilder.setNeutralButton(text, (dialog, which) -> {\n            if (listener != null) listener.onClick(dialog, which, mAdapter.getSelectedItems());\n        });\n        return this;\n    }\n\n    public AlertDialog create() {\n        return mDialog = mBuilder.create();\n    }\n\n    public void show() {\n        create().show();\n    }\n\n    private void checkSelections() {\n        mSelectAll.setChecked(mAdapter.areAllSelected(), false);\n    }\n\n    private void triggerMultiChoiceClickListener(int index, boolean isChecked) {\n        if (mDialog != null && mOnMultiChoiceClickListener != null) {\n            mOnMultiChoiceClickListener.onClick(mDialog, index, mAdapter.mItems.get(index), isChecked);\n        }\n    }\n\n    class SearchableRecyclerViewAdapter extends RecyclerView.Adapter<SearchableRecyclerViewAdapter.ViewHolder> {\n        @NonNull\n        private final List<CharSequence> mItemNames;\n        @NonNull\n        private final List<T> mItems;\n        @NonNull\n        private final List<T> mNotFoundItems = new ArrayList<>();\n        @NonNull\n        private final ArrayList<Integer> mFilteredItems = new ArrayList<>();\n        @NonNull\n        private final Set<Integer> mSelectedItems = new ArraySet<>();\n        private final Set<Integer> mDisabledItems = new ArraySet<>();\n        @LayoutRes\n        private final int mLayoutId;\n\n        SearchableRecyclerViewAdapter(@NonNull List<CharSequence> itemNames, @NonNull List<T> items, int layoutId) {\n            mItemNames = itemNames;\n            mItems = items;\n            mLayoutId = layoutId;\n            new Thread(() -> {\n                synchronized (mFilteredItems) {\n                    for (int i = 0; i < items.size(); ++i) {\n                        mFilteredItems.add(i);\n                    }\n                }\n            }, \"searchable_multi_choice_dialog\").start();\n        }\n\n        void setFilteredItems(CharSequence constraint) {\n            Locale locale = Locale.getDefault();\n            synchronized (mFilteredItems) {\n                int previousCount = mFilteredItems.size();\n                mFilteredItems.clear();\n                for (int i = 0; i < mItems.size(); ++i) {\n                    if (mItemNames.get(i).toString().toLowerCase(locale).contains(constraint)\n                            || mItems.get(i).toString().toLowerCase(Locale.ROOT).contains(constraint)) {\n                        mFilteredItems.add(i);\n                    }\n                }\n                checkSelections();\n                AdapterUtils.notifyDataSetChanged(this, previousCount, mFilteredItems.size());\n            }\n        }\n\n        ArrayList<T> getSelectedItems() {\n            ArrayList<T> selections = new ArrayList<>(mNotFoundItems);\n            synchronized (mSelectedItems) {\n                for (int item : mSelectedItems) {\n                    selections.add(mItems.get(item));\n                }\n            }\n            return selections;\n        }\n\n        void addSelectedItems(@Nullable List<T> selectedItems) {\n            if (selectedItems != null) {\n                for (T item : selectedItems) {\n                    int index = mItems.indexOf(item);\n                    if (index != -1) {\n                        synchronized (mSelectedItems) {\n                            mSelectedItems.add(index);\n                        }\n                    } else mNotFoundItems.add(item);\n                }\n            }\n        }\n\n        void addSelectedIndexes(@Nullable int[] selectedIndexes) {\n            if (selectedIndexes != null) {\n                for (int index : selectedIndexes) {\n                    synchronized (mSelectedItems) {\n                        mSelectedItems.add(index);\n                    }\n                }\n            }\n        }\n\n        void removeSelectedIndexes(@Nullable int[] selectedIndexes) {\n            if (selectedIndexes != null) {\n                for (int index : selectedIndexes) {\n                    synchronized (mSelectedItems) {\n                        mSelectedItems.remove(index);\n                    }\n                }\n            }\n        }\n\n        void addDisabledItems(@Nullable List<T> disabledItems) {\n            if (disabledItems != null) {\n                for (T item : disabledItems) {\n                    int index = mItems.indexOf(item);\n                    if (index != -1) {\n                        synchronized (mDisabledItems) {\n                            mDisabledItems.add(index);\n                        }\n                    }\n                }\n            }\n        }\n\n        void selectAll() {\n            synchronized (mSelectedItems) {\n                synchronized (mFilteredItems) {\n                    List<Integer> newSelections = new ArrayList<>();\n                    for (int index : mFilteredItems) {\n                        if (!mSelectedItems.contains(index)) {\n                            newSelections.add(index);\n                        }\n                    }\n                    mSelectedItems.addAll(newSelections);\n                    checkSelections();\n                    for (int index : newSelections) {\n                        triggerMultiChoiceClickListener(index, true);\n                    }\n                    notifyItemRangeChanged(0, getItemCount(), AdapterUtils.STUB);\n                }\n            }\n        }\n\n        void deselectAll() {\n            synchronized (mSelectedItems) {\n                synchronized (mFilteredItems) {\n                    List<Integer> oldSelections = new ArrayList<>();\n                    for (int index : mFilteredItems) {\n                        if (mSelectedItems.contains(index)) {\n                            oldSelections.add(index);\n                        }\n                    }\n                    //noinspection SlowAbstractSetRemoveAll\n                    mSelectedItems.removeAll(oldSelections);\n                    checkSelections();\n                    for (int index : oldSelections) {\n                        triggerMultiChoiceClickListener(index, false);\n                    }\n                    notifyItemRangeChanged(0, getItemCount(), AdapterUtils.STUB);\n                }\n            }\n        }\n\n        boolean areAllSelected() {\n            synchronized (mSelectedItems) {\n                synchronized (mFilteredItems) {\n                    return mSelectedItems.containsAll(mFilteredItems);\n                }\n            }\n        }\n\n        @NonNull\n        @Override\n        public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {\n            View view = LayoutInflater.from(parent.getContext()).inflate(mLayoutId, parent, false);\n            return new ViewHolder(view);\n        }\n\n        @Override\n        public void onBindViewHolder(@NonNull SearchableRecyclerViewAdapter.ViewHolder holder, int position) {\n            Integer index;\n            synchronized (mFilteredItems) {\n                index = mFilteredItems.get(position);\n            }\n            final AtomicBoolean selected;\n            synchronized (mSelectedItems) {\n                selected = new AtomicBoolean(mSelectedItems.contains(index));\n            }\n            holder.item.setText(mItemNames.get(index));\n            holder.item.setTextIsSelectable(mIsTextSelectable);\n            synchronized (mDisabledItems) {\n                holder.item.setEnabled(!mDisabledItems.contains(index));\n            }\n            holder.item.setChecked(selected.get());\n            holder.item.setOnClickListener(v -> {\n                synchronized (mSelectedItems) {\n                    boolean isSelected = selected.get();\n                    if (isSelected) {\n                        mSelectedItems.remove(index);\n                    } else mSelectedItems.add(index);\n                    selected.set(!isSelected);\n                    holder.item.setChecked(!isSelected);\n                    checkSelections();\n                    triggerMultiChoiceClickListener(index, selected.get());\n                }\n            });\n        }\n\n        @Override\n        public int getItemCount() {\n            synchronized (mFilteredItems) {\n                return mFilteredItems.size();\n            }\n        }\n\n        class ViewHolder extends RecyclerView.ViewHolder {\n            CheckedTextView item;\n\n            @SuppressLint(\"RestrictedApi\")\n            public ViewHolder(@NonNull View itemView) {\n                super(itemView);\n                item = itemView.findViewById(android.R.id.text1);\n                int textAppearanceBodyLarge = MaterialAttributes.resolveInteger(item.getContext(), com.google.android.material.R.attr.textAppearanceBodyLarge, 0);\n                TextViewCompat.setTextAppearance(item, textAppearanceBodyLarge);\n                item.setTextSize(TypedValue.COMPLEX_UNIT_SP, 16);\n                item.setTextColor(MaterialColors.getColor(item.getContext(), com.google.android.material.R.attr.colorOnSurfaceVariant, -1));\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "libcore/ui/src/main/java/io/github/muntashirakon/dialog/SearchableSingleChoiceDialogBuilder.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.dialog;\n\nimport android.annotation.SuppressLint;\nimport android.content.Context;\nimport android.content.DialogInterface;\nimport android.graphics.drawable.Drawable;\nimport android.text.TextUtils;\nimport android.util.TypedValue;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.CheckedTextView;\nimport android.widget.FrameLayout;\n\nimport androidx.annotation.ArrayRes;\nimport androidx.annotation.DrawableRes;\nimport androidx.annotation.LayoutRes;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.StringRes;\nimport androidx.appcompat.app.AlertDialog;\nimport androidx.collection.ArraySet;\nimport androidx.core.widget.TextViewCompat;\nimport androidx.recyclerview.widget.LinearLayoutManager;\n\nimport com.google.android.material.color.MaterialColors;\nimport com.google.android.material.dialog.MaterialAlertDialogBuilder;\nimport com.google.android.material.resources.MaterialAttributes;\n\nimport java.util.ArrayList;\nimport java.util.Arrays;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.Set;\nimport java.util.concurrent.atomic.AtomicBoolean;\n\nimport io.github.muntashirakon.ui.R;\nimport io.github.muntashirakon.util.AdapterUtils;\nimport io.github.muntashirakon.widget.RecyclerView;\nimport io.github.muntashirakon.widget.SearchView;\n\npublic class SearchableSingleChoiceDialogBuilder<T> {\n    @NonNull\n    private final MaterialAlertDialogBuilder mBuilder;\n    private final SearchView mSearchView;\n    private final RecyclerView mRecyclerView;\n    private final FrameLayout mViewContainer;\n    @NonNull\n    private final SearchableRecyclerViewAdapter mAdapter;\n    @Nullable\n    private AlertDialog mDialog;\n    @Nullable\n    private OnSingleChoiceClickListener<T> mOnSingleChoiceClickListener;\n    private boolean mIsTextSelectable;\n\n    public interface OnClickListener<T> {\n        void onClick(DialogInterface dialog, int which, @Nullable T selectedItem);\n    }\n\n    public interface OnSingleChoiceClickListener<T> {\n        void onClick(DialogInterface dialog, int which, T item, boolean isChecked);\n    }\n\n    public SearchableSingleChoiceDialogBuilder(@NonNull Context context, @NonNull List<T> items, @ArrayRes int itemNames) {\n        this(context, items, context.getResources().getTextArray(itemNames));\n    }\n\n    public SearchableSingleChoiceDialogBuilder(@NonNull Context context, @NonNull List<T> items, @NonNull CharSequence[] itemNames) {\n        this(context, items, Arrays.asList(itemNames));\n    }\n\n    public SearchableSingleChoiceDialogBuilder(@NonNull Context context, @NonNull T[] items, @NonNull CharSequence[] itemNames) {\n        this(context, Arrays.asList(items), Arrays.asList(itemNames));\n    }\n\n    public SearchableSingleChoiceDialogBuilder(@NonNull Context context, @NonNull List<T> items, @NonNull List<CharSequence> itemNames) {\n        View view = View.inflate(context, R.layout.dialog_searchable_single_choice, null);\n        mRecyclerView = view.findViewById(android.R.id.list);\n        mRecyclerView.setLayoutManager(new LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false));\n        mViewContainer = view.findViewById(R.id.container);\n        mSearchView = view.findViewById(R.id.action_search);\n        mSearchView.setOnQueryTextListener(new SearchView.OnQueryTextListener() {\n            @Override\n            public boolean onQueryTextSubmit(String query) {\n                return false;\n            }\n\n            @Override\n            public boolean onQueryTextChange(String newText) {\n                mAdapter.setFilteredItems(newText);\n                return true;\n            }\n        });\n        // Don't display search bar if items are less than 6\n        if (items.size() < 6) {\n            mSearchView.setVisibility(View.GONE);\n        }\n        mBuilder = new MaterialAlertDialogBuilder(context)\n                .setView(view);\n        @SuppressLint({\"RestrictedApi\", \"PrivateResource\"})\n        int layoutId = MaterialAttributes.resolveInteger(context, androidx.appcompat.R.attr.singleChoiceItemLayout,\n                com.google.android.material.R.layout.mtrl_alert_select_dialog_singlechoice);\n        mAdapter = new SearchableRecyclerViewAdapter(itemNames, items, layoutId);\n        mRecyclerView.setAdapter(mAdapter);\n    }\n\n    public SearchableSingleChoiceDialogBuilder<T> setOnDismissListener(@Nullable DialogInterface.OnDismissListener dismissListener) {\n        mBuilder.setOnDismissListener(dismissListener);\n        return this;\n    }\n\n    public SearchableSingleChoiceDialogBuilder<T> setOnSingleChoiceClickListener(@Nullable OnSingleChoiceClickListener<T>\n                                                                                         onSingleChoiceClickListener) {\n        mOnSingleChoiceClickListener = onSingleChoiceClickListener;\n        return this;\n    }\n\n    public SearchableSingleChoiceDialogBuilder<T> addDisabledItems(@Nullable List<T> disabledItems) {\n        mAdapter.addDisabledItems(disabledItems);\n        return this;\n    }\n\n    public SearchableSingleChoiceDialogBuilder<T> setSelection(@Nullable T selectedItem) {\n        mAdapter.setSelection(selectedItem);\n        return this;\n    }\n\n    public SearchableSingleChoiceDialogBuilder<T> setSelectionIndex(int selectedIndex) {\n        mAdapter.setSelectedIndex(selectedIndex);\n        return this;\n    }\n\n    public SearchableSingleChoiceDialogBuilder<T> removeSelection() {\n        mAdapter.setSelectedIndex(-1);\n        return this;\n    }\n\n    public SearchableSingleChoiceDialogBuilder<T> setView(@Nullable View view) {\n        mViewContainer.removeAllViews();\n        if (view != null) {\n            mViewContainer.addView(view);\n        }\n        return this;\n    }\n\n    public SearchableSingleChoiceDialogBuilder<T> reloadListUi() {\n        mAdapter.notifyItemRangeChanged(0, mAdapter.getItemCount(), AdapterUtils.STUB);\n        return this;\n    }\n\n    public SearchableSingleChoiceDialogBuilder<T> setTextSelectable(boolean textSelectable) {\n        mIsTextSelectable = textSelectable;\n        return this;\n    }\n\n    public SearchableSingleChoiceDialogBuilder<T> setCancelable(boolean cancelable) {\n        mBuilder.setCancelable(cancelable);\n        return this;\n    }\n\n    public SearchableSingleChoiceDialogBuilder<T> hideSearchBar(boolean hide) {\n        mSearchView.setVisibility(hide ? View.GONE : View.VISIBLE);\n        return this;\n    }\n\n    public SearchableSingleChoiceDialogBuilder<T> setIcon(@DrawableRes int iconRes) {\n        mBuilder.setIcon(iconRes);\n        return this;\n    }\n\n    public SearchableSingleChoiceDialogBuilder<T> setIcon(@Nullable Drawable icon) {\n        mBuilder.setIcon(icon);\n        return this;\n    }\n\n    public SearchableSingleChoiceDialogBuilder<T> setTitle(@Nullable CharSequence title) {\n        mBuilder.setTitle(title);\n        return this;\n    }\n\n    public SearchableSingleChoiceDialogBuilder<T> setTitle(@StringRes int title) {\n        mBuilder.setTitle(title);\n        return this;\n    }\n\n    public SearchableSingleChoiceDialogBuilder<T> setTitle(@Nullable View title) {\n        mBuilder.setCustomTitle(title);\n        return this;\n    }\n\n    public SearchableSingleChoiceDialogBuilder<T> setPositiveButton(@StringRes int textId, @Nullable OnClickListener<T> listener) {\n        mBuilder.setPositiveButton(textId, (dialog, which) -> {\n            if (listener != null) listener.onClick(dialog, which, mAdapter.getSelection());\n        });\n        return this;\n    }\n\n    public SearchableSingleChoiceDialogBuilder<T> setPositiveButton(@NonNull CharSequence text, @Nullable OnClickListener<T> listener) {\n        mBuilder.setPositiveButton(text, (dialog, which) -> {\n            if (listener != null) listener.onClick(dialog, which, mAdapter.getSelection());\n        });\n        return this;\n    }\n\n    public SearchableSingleChoiceDialogBuilder<T> setNegativeButton(@StringRes int textId, @Nullable OnClickListener<T> listener) {\n        mBuilder.setNegativeButton(textId, (dialog, which) -> {\n            if (listener != null) listener.onClick(dialog, which, mAdapter.getSelection());\n        });\n        return this;\n    }\n\n    public SearchableSingleChoiceDialogBuilder<T> setNegativeButton(@NonNull CharSequence text, @Nullable OnClickListener<T> listener) {\n        mBuilder.setNegativeButton(text, (dialog, which) -> {\n            if (listener != null) listener.onClick(dialog, which, mAdapter.getSelection());\n        });\n        return this;\n    }\n\n    public SearchableSingleChoiceDialogBuilder<T> setNeutralButton(@StringRes int textId, @Nullable OnClickListener<T> listener) {\n        mBuilder.setNeutralButton(textId, (dialog, which) -> {\n            if (listener != null) listener.onClick(dialog, which, mAdapter.getSelection());\n        });\n        return this;\n    }\n\n    public SearchableSingleChoiceDialogBuilder<T> setNeutralButton(@NonNull CharSequence text, @Nullable OnClickListener<T> listener) {\n        mBuilder.setNeutralButton(text, (dialog, which) -> {\n            if (listener != null) listener.onClick(dialog, which, mAdapter.getSelection());\n        });\n        return this;\n    }\n\n    @NonNull\n    public AlertDialog create() {\n        return mDialog = mBuilder.create();\n    }\n\n    @NonNull\n    public AlertDialog show() {\n        return mDialog = mBuilder.show();\n    }\n\n    private void triggerSingleChoiceClickListener(int index, boolean isChecked) {\n        if (mDialog != null && mOnSingleChoiceClickListener != null) {\n            mOnSingleChoiceClickListener.onClick(mDialog, index, mAdapter.mItems.get(index), isChecked);\n        }\n    }\n\n    class SearchableRecyclerViewAdapter extends RecyclerView.Adapter<SearchableRecyclerViewAdapter.ViewHolder> {\n        @NonNull\n        private final List<CharSequence> mItemNames;\n        @NonNull\n        private final List<T> mItems;\n        @NonNull\n        private final ArrayList<Integer> mFilteredItems = new ArrayList<>();\n        private int mSelectedItem = -1;\n        private final Set<Integer> mDisabledItems = new ArraySet<>();\n        @LayoutRes\n        private final int mLayoutId;\n\n        SearchableRecyclerViewAdapter(@NonNull List<CharSequence> itemNames, @NonNull List<T> items, int layoutId) {\n            mItemNames = itemNames;\n            mItems = items;\n            mLayoutId = layoutId;\n            synchronized (mFilteredItems) {\n                for (int i = 0; i < items.size(); ++i) {\n                    mFilteredItems.add(i);\n                }\n            }\n        }\n\n        void setFilteredItems(String constraint) {\n            constraint = TextUtils.isEmpty(constraint) ? null : constraint.toLowerCase(Locale.ROOT);\n            Locale locale = Locale.getDefault();\n            synchronized (mFilteredItems) {\n                int previousCount = mFilteredItems.size();\n                mFilteredItems.clear();\n                for (int i = 0; i < mItems.size(); ++i) {\n                    if (constraint == null\n                            || mItemNames.get(i).toString().toLowerCase(locale).contains(constraint)\n                            || mItems.get(i).toString().toLowerCase(Locale.ROOT).contains(constraint)) {\n                        mFilteredItems.add(i);\n                    }\n                }\n                AdapterUtils.notifyDataSetChanged(this, previousCount, mFilteredItems.size());\n            }\n        }\n\n        @Nullable\n        T getSelection() {\n            if (mSelectedItem >= 0) {\n                return mItems.get(mSelectedItem);\n            }\n            return null;\n        }\n\n        void setSelection(@Nullable T selectedItem) {\n            if (selectedItem != null) {\n                int index = mItems.indexOf(selectedItem);\n                if (index != -1) {\n                    setSelectedIndex(index);\n                }\n            }\n        }\n\n        void setSelectedIndex(int selectedIndex) {\n            if (selectedIndex == mSelectedItem) {\n                // Do nothing\n                return;\n            }\n            updateSelection(false);\n            mSelectedItem = selectedIndex;\n            updateSelection(true);\n            mRecyclerView.setSelection(selectedIndex);\n        }\n\n        void addDisabledItems(@Nullable List<T> disabledItems) {\n            if (disabledItems != null) {\n                for (T item : disabledItems) {\n                    int index = mItems.indexOf(item);\n                    if (index != -1) {\n                        synchronized (mDisabledItems) {\n                            mDisabledItems.add(index);\n                        }\n                    }\n                }\n            }\n        }\n\n        @NonNull\n        @Override\n        public SearchableRecyclerViewAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {\n            View view = LayoutInflater.from(parent.getContext()).inflate(mLayoutId, parent, false);\n            return new SearchableRecyclerViewAdapter.ViewHolder(view);\n        }\n\n        @Override\n        public void onBindViewHolder(@NonNull SearchableRecyclerViewAdapter.ViewHolder holder, int position) {\n            Integer index;\n            synchronized (mFilteredItems) {\n                index = mFilteredItems.get(position);\n            }\n            final AtomicBoolean selected = new AtomicBoolean(mSelectedItem == index);\n            holder.item.setText(mItemNames.get(index));\n            holder.item.setTextIsSelectable(mIsTextSelectable);\n            synchronized (mDisabledItems) {\n                holder.item.setEnabled(!mDisabledItems.contains(index));\n            }\n            holder.item.setChecked(selected.get());\n            holder.item.setOnClickListener(v -> {\n                if (selected.get()) {\n                    // Already selected, do nothing\n                    return;\n                }\n                // Unselect the previous and select this one\n                updateSelection(false);\n                mSelectedItem = index;\n                // Update selection manually\n                selected.set(!selected.get());\n                holder.item.setChecked(selected.get());\n                triggerSingleChoiceClickListener(index, selected.get());\n            });\n        }\n\n        @Override\n        public int getItemCount() {\n            synchronized (mFilteredItems) {\n                return mFilteredItems.size();\n            }\n        }\n\n        private void updateSelection(boolean selected) {\n            if (mSelectedItem < 0) {\n                return;\n            }\n            int position;\n            synchronized (mFilteredItems) {\n                position = mFilteredItems.indexOf(mSelectedItem);\n            }\n            if (position >= 0) {\n                notifyItemChanged(position, AdapterUtils.STUB);\n            }\n            triggerSingleChoiceClickListener(mSelectedItem, selected);\n        }\n\n        class ViewHolder extends RecyclerView.ViewHolder {\n            CheckedTextView item;\n\n            @SuppressLint(\"RestrictedApi\")\n            public ViewHolder(@NonNull View itemView) {\n                super(itemView);\n                item = itemView.findViewById(android.R.id.text1);\n                int textAppearanceBodyLarge = MaterialAttributes.resolveInteger(item.getContext(), com.google.android.material.R.attr.textAppearanceBodyLarge, 0);\n                TextViewCompat.setTextAppearance(item, textAppearanceBodyLarge);\n                item.setTextSize(TypedValue.COMPLEX_UNIT_SP, 16);\n                item.setTextColor(MaterialColors.getColor(item.getContext(), com.google.android.material.R.attr.colorOnSurfaceVariant, -1));\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "libcore/ui/src/main/java/io/github/muntashirakon/dialog/TextInputDialogBuilder.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.dialog;\n\nimport android.annotation.SuppressLint;\nimport android.content.Context;\nimport android.content.DialogInterface;\nimport android.graphics.Typeface;\nimport android.text.Editable;\nimport android.view.View;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.StringRes;\nimport androidx.appcompat.app.AlertDialog;\n\nimport com.google.android.material.checkbox.MaterialCheckBox;\nimport com.google.android.material.dialog.MaterialAlertDialogBuilder;\nimport com.google.android.material.textfield.TextInputEditText;\nimport com.google.android.material.textfield.TextInputLayout;\n\nimport io.github.muntashirakon.ui.R;\nimport io.github.muntashirakon.util.UiUtils;\n\n@SuppressWarnings(\"unused\")\npublic class TextInputDialogBuilder {\n    @NonNull\n    private final Context mContext;\n    @NonNull\n    private final TextInputLayout mTextInputLayout;\n    @NonNull\n    private final TextInputEditText mEditText;\n    @NonNull\n    private final MaterialCheckBox mCheckBox;\n    @NonNull\n    private final MaterialAlertDialogBuilder mBuilder;\n\n    @Nullable\n    private DialogInterface.OnShowListener mShowListener;\n\n    public interface OnClickListener {\n        void onClick(DialogInterface dialog, int which, @Nullable Editable inputText, boolean isChecked);\n    }\n\n    @SuppressLint(\"InflateParams\")\n    public TextInputDialogBuilder(@NonNull Context context, @Nullable CharSequence inputTextLabel) {\n        mContext = context;\n        View view = View.inflate(context, R.layout.dialog_text_input, null);\n        mTextInputLayout = view.findViewById(android.R.id.text1);\n        mTextInputLayout.setHint(inputTextLabel);\n        mEditText = view.findViewById(android.R.id.input);\n        mCheckBox = view.findViewById(android.R.id.checkbox);\n        mCheckBox.setVisibility(View.GONE);\n        mBuilder = new MaterialAlertDialogBuilder(context).setView(view);\n    }\n\n    @SuppressLint(\"InflateParams\")\n    public TextInputDialogBuilder(@NonNull Context context, @StringRes int inputTextLabel) {\n        this(context, context.getText(inputTextLabel));\n    }\n\n    public TextInputDialogBuilder setTitle(@Nullable CharSequence title) {\n        mBuilder.setTitle(title);\n        return this;\n    }\n\n    public TextInputDialogBuilder setTitle(@StringRes int title) {\n        mBuilder.setTitle(title);\n        return this;\n    }\n\n    public TextInputDialogBuilder setInputText(@Nullable CharSequence inputText) {\n        mEditText.setText(inputText);\n        return this;\n    }\n\n    public TextInputDialogBuilder setInputText(@StringRes int inputText) {\n        mEditText.setText(inputText);\n        return this;\n    }\n\n    public TextInputDialogBuilder setInputTypeface(Typeface tf) {\n        mEditText.setTypeface(tf);\n        return this;\n    }\n\n    public TextInputDialogBuilder setInputInputType(int inputType) {\n        mEditText.setInputType(inputType);\n        return this;\n    }\n\n    public TextInputDialogBuilder setInputImeOptions(int options) {\n        mEditText.setImeOptions(options);\n        return this;\n    }\n\n    public TextInputDialogBuilder setHelperText(@Nullable CharSequence helperText) {\n        mTextInputLayout.setHelperText(helperText);\n        return this;\n    }\n\n    public TextInputDialogBuilder setHelperText(@StringRes int helperText) {\n        mTextInputLayout.setHelperText(mContext.getText(helperText));\n        return this;\n    }\n\n    public TextInputDialogBuilder setChecked(boolean checked) {\n        mCheckBox.setChecked(checked);\n        return this;\n    }\n\n    public TextInputDialogBuilder setCheckboxLabel(@Nullable CharSequence checkboxLabel) {\n        if (checkboxLabel != null) {\n            mCheckBox.setVisibility(View.VISIBLE);\n            mCheckBox.setText(checkboxLabel);\n        } else mCheckBox.setVisibility(View.GONE);\n        return this;\n    }\n\n    public TextInputDialogBuilder setCheckboxLabel(@StringRes int checkboxLabel) {\n        if (checkboxLabel != 0) {\n            mCheckBox.setVisibility(View.VISIBLE);\n            mCheckBox.setText(checkboxLabel);\n        } else mCheckBox.setVisibility(View.GONE);\n        return this;\n    }\n\n    public TextInputDialogBuilder setPositiveButton(@StringRes int textId, @Nullable OnClickListener listener) {\n        mBuilder.setPositiveButton(textId, (dialog, which) -> {\n            if (listener != null) listener.onClick(dialog, which, mEditText.getText(), mCheckBox.isChecked());\n        });\n        return this;\n    }\n\n    public TextInputDialogBuilder setPositiveButton(@NonNull CharSequence text, @Nullable OnClickListener listener) {\n        mBuilder.setPositiveButton(text, (dialog, which) -> {\n            if (listener != null) listener.onClick(dialog, which, mEditText.getText(), mCheckBox.isChecked());\n        });\n        return this;\n    }\n\n    public TextInputDialogBuilder setNegativeButton(@StringRes int textId, @Nullable OnClickListener listener) {\n        mBuilder.setNegativeButton(textId, (dialog, which) -> {\n            if (listener != null) listener.onClick(dialog, which, mEditText.getText(), mCheckBox.isChecked());\n        });\n        return this;\n    }\n\n    public TextInputDialogBuilder setNegativeButton(@NonNull CharSequence text, @Nullable OnClickListener listener) {\n        mBuilder.setNegativeButton(text, (dialog, which) -> {\n            if (listener != null) listener.onClick(dialog, which, mEditText.getText(), mCheckBox.isChecked());\n        });\n        return this;\n    }\n\n    public TextInputDialogBuilder setNeutralButton(@StringRes int textId, @Nullable OnClickListener listener) {\n        mBuilder.setNeutralButton(textId, (dialog, which) -> {\n            if (listener != null) listener.onClick(dialog, which, mEditText.getText(), mCheckBox.isChecked());\n        });\n        return this;\n    }\n\n    public TextInputDialogBuilder setNeutralButton(@NonNull CharSequence text, @Nullable OnClickListener listener) {\n        mBuilder.setNeutralButton(text, (dialog, which) -> {\n            if (listener != null) listener.onClick(dialog, which, mEditText.getText(), mCheckBox.isChecked());\n        });\n        return this;\n    }\n\n    public TextInputDialogBuilder setOnShowListener(@Nullable DialogInterface.OnShowListener listener) {\n        mShowListener = listener;\n        return this;\n    }\n\n    public TextInputDialogBuilder setOnDismissListener(@Nullable DialogInterface.OnDismissListener listener) {\n        mBuilder.setOnDismissListener(listener);\n        return this;\n    }\n\n    public TextInputDialogBuilder setCancelable(boolean cancelable) {\n        mBuilder.setCancelable(cancelable);\n        return this;\n    }\n\n    @Nullable\n    public Editable getInputText() {\n        return mEditText.getText();\n    }\n\n    @NonNull\n    public AlertDialog create() {\n        AlertDialog dialog = mBuilder.create();\n        dialog.setOnShowListener(dialog1 -> {\n            if (mShowListener != null) {\n                mShowListener.onShow(dialog1);\n            }\n            mEditText.postDelayed(() -> {\n                mEditText.requestFocus();\n                mEditText.requestFocusFromTouch();\n                mEditText.setSelection(mEditText.length());\n                UiUtils.showKeyboard(mEditText);\n            }, 200);\n        });\n        return dialog;\n    }\n\n    public void show() {\n        create().show();\n    }\n}\n"
  },
  {
    "path": "libcore/ui/src/main/java/io/github/muntashirakon/dialog/TextInputDropdownDialogBuilder.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.dialog;\n\nimport android.annotation.SuppressLint;\nimport android.content.DialogInterface;\nimport android.text.Editable;\nimport android.text.InputType;\nimport android.view.View;\nimport android.widget.ArrayAdapter;\nimport android.widget.AutoCompleteTextView;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.StringRes;\nimport androidx.appcompat.app.AlertDialog;\nimport androidx.fragment.app.FragmentActivity;\n\nimport com.google.android.material.checkbox.MaterialCheckBox;\nimport com.google.android.material.dialog.MaterialAlertDialogBuilder;\nimport com.google.android.material.textfield.TextInputLayout;\n\nimport java.util.List;\n\nimport io.github.muntashirakon.ui.R;\nimport io.github.muntashirakon.adapters.AnyFilterArrayAdapter;\nimport io.github.muntashirakon.adapters.NoFilterArrayAdapter;\n\n@SuppressWarnings(\"unused\")\npublic class TextInputDropdownDialogBuilder {\n    @NonNull\n    private final FragmentActivity mActivity;\n    @NonNull\n    private final TextInputLayout mMainInputLayout;\n    @NonNull\n    private final AutoCompleteTextView mMainInput;\n    @NonNull\n    private final TextInputLayout mAuxiliaryInputLayout;\n    @NonNull\n    private final AutoCompleteTextView mAuxiliaryInput;\n    @NonNull\n    private final MaterialCheckBox mCheckBox;\n    @NonNull\n    private final MaterialAlertDialogBuilder mBuilder;\n\n    public interface OnClickListener {\n        void onClick(DialogInterface dialog, int which, @Nullable Editable inputText, boolean isChecked);\n    }\n\n    @SuppressLint(\"InflateParams\")\n    public TextInputDropdownDialogBuilder(@NonNull FragmentActivity activity, @NonNull CharSequence inputTextLabel) {\n        mActivity = activity;\n        View view = activity.getLayoutInflater().inflate(R.layout.dialog_text_input_dropdown, null);\n        // Main input layout: always visible\n        mMainInputLayout = view.findViewById(android.R.id.text1);\n        mMainInputLayout.setHint(inputTextLabel);\n        mMainInputLayout.setEndIconMode(TextInputLayout.END_ICON_NONE);\n        mMainInput = view.findViewById(android.R.id.input);\n        // Auxiliary input layout: visible on demand\n        mAuxiliaryInputLayout = view.findViewById(android.R.id.text2);\n        mAuxiliaryInput = view.findViewById(android.R.id.custom);\n        mAuxiliaryInputLayout.setVisibility(View.GONE);\n        // Checkbox: visible on demand\n        mCheckBox = view.findViewById(android.R.id.checkbox);\n        mCheckBox.setVisibility(View.GONE);\n        mBuilder = new MaterialAlertDialogBuilder(activity).setView(view);\n    }\n\n    @SuppressLint(\"InflateParams\")\n    public TextInputDropdownDialogBuilder(@NonNull FragmentActivity activity, @StringRes int inputTextLabel) {\n        this(activity, activity.getText(inputTextLabel));\n    }\n\n    public TextInputDropdownDialogBuilder setTitle(@Nullable View title) {\n        mBuilder.setCustomTitle(title);\n        return this;\n    }\n\n    public TextInputDropdownDialogBuilder setTitle(@Nullable CharSequence title) {\n        mBuilder.setTitle(title);\n        return this;\n    }\n\n    public TextInputDropdownDialogBuilder setTitle(@StringRes int title) {\n        mBuilder.setTitle(title);\n        return this;\n    }\n\n    public <T> TextInputDropdownDialogBuilder setDropdownItems(List<T> items, int choice, boolean filterable) {\n        ArrayAdapter<T> adapter;\n        if (filterable) {\n            adapter = new AnyFilterArrayAdapter<>(mActivity, R.layout.auto_complete_dropdown_item, items);\n        } else {\n            adapter = new NoFilterArrayAdapter<>(mActivity, R.layout.auto_complete_dropdown_item, items);\n        }\n        mMainInput.setAdapter(adapter);\n        if (choice >= 0) {\n            T selectedItem = adapter.getItem(choice);\n            mMainInput.setText(selectedItem == null ? \"\" : selectedItem.toString());\n        }\n        mMainInputLayout.setEndIconMode(TextInputLayout.END_ICON_DROPDOWN_MENU);\n        return this;\n    }\n\n    public <T> TextInputDropdownDialogBuilder setAuxiliaryInput(@NonNull CharSequence inputLabel,\n                                                                @Nullable CharSequence helperText,\n                                                                @Nullable CharSequence inputText,\n                                                                @Nullable List<T> dropdownItems,\n                                                                boolean isEnabled) {\n        mAuxiliaryInputLayout.setVisibility(View.VISIBLE);\n        mAuxiliaryInputLayout.setHint(inputLabel);\n        mAuxiliaryInputLayout.setHelperText(helperText);\n        mAuxiliaryInput.setText(inputText);\n        if (dropdownItems != null) {\n            ArrayAdapter<T> adapter = new NoFilterArrayAdapter<>(mActivity, R.layout.auto_complete_dropdown_item, dropdownItems);\n            mAuxiliaryInput.setAdapter(adapter);\n            mAuxiliaryInputLayout.setEndIconMode(TextInputLayout.END_ICON_DROPDOWN_MENU);\n        } else {\n            mAuxiliaryInputLayout.setEndIconMode(TextInputLayout.END_ICON_NONE);\n        }\n        if (isEnabled)\n            mAuxiliaryInput.setInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS | InputType.TYPE_TEXT_FLAG_MULTI_LINE);\n        else mAuxiliaryInput.setInputType(InputType.TYPE_NULL);\n        return this;\n    }\n\n    public <T> TextInputDropdownDialogBuilder setAuxiliaryInput(@StringRes int inputLabel,\n                                                                @Nullable @StringRes Integer helperText,\n                                                                @Nullable @StringRes Integer inputText,\n                                                                @Nullable List<T> dropdownItems,\n                                                                boolean isEnabled) {\n        return setAuxiliaryInput(mActivity.getString(inputLabel),\n                helperText == null ? null : mActivity.getText(helperText),\n                inputText == null ? null : mActivity.getText(inputText),\n                dropdownItems, isEnabled);\n    }\n\n    public TextInputDropdownDialogBuilder setAuxiliaryInputLabel(@Nullable CharSequence inputText) {\n        mAuxiliaryInputLayout.setVisibility(View.VISIBLE);\n        mAuxiliaryInputLayout.setHint(inputText);\n        return this;\n    }\n\n    public TextInputDropdownDialogBuilder setAuxiliaryInputLabel(@StringRes int inputText) {\n        mAuxiliaryInputLayout.setVisibility(View.VISIBLE);\n        mAuxiliaryInputLayout.setHint(inputText);\n        return this;\n    }\n\n    public TextInputDropdownDialogBuilder setAuxiliaryInputHelperText(@Nullable CharSequence helperText) {\n        mAuxiliaryInputLayout.setHelperText(helperText);\n        return this;\n    }\n\n    public TextInputDropdownDialogBuilder setAuxiliaryInputHelperText(@StringRes int helperText) {\n        mAuxiliaryInputLayout.setHelperText(mActivity.getText(helperText));\n        return this;\n    }\n\n    public TextInputDropdownDialogBuilder setAuxiliaryInputText(@Nullable CharSequence inputText) {\n        mAuxiliaryInput.setText(inputText);\n        return this;\n    }\n\n    public TextInputDropdownDialogBuilder setAuxiliaryInputText(@StringRes int inputText) {\n        mAuxiliaryInput.setText(inputText);\n        return this;\n    }\n\n    @Nullable\n    public Editable getAuxiliaryInput() {\n        return mAuxiliaryInput.getText();\n    }\n\n    @Nullable\n    public Editable getInputText() {\n        return mMainInput.getText();\n    }\n\n    public TextInputDropdownDialogBuilder setEnable(boolean enable) {\n        if (enable)\n            mMainInput.setInputType(InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS | InputType.TYPE_TEXT_FLAG_MULTI_LINE);\n        else mMainInput.setInputType(InputType.TYPE_NULL);\n        return this;\n    }\n\n    public TextInputDropdownDialogBuilder setInputText(@Nullable CharSequence inputText) {\n        mMainInput.setText(inputText);\n        return this;\n    }\n\n    public TextInputDropdownDialogBuilder setInputText(@StringRes int inputText) {\n        mMainInput.setText(inputText);\n        return this;\n    }\n\n    public TextInputDropdownDialogBuilder setHelperText(@Nullable CharSequence helperText) {\n        mMainInputLayout.setHelperText(helperText);\n        return this;\n    }\n\n    public TextInputDropdownDialogBuilder setHelperText(@StringRes int helperText) {\n        mMainInputLayout.setHelperText(mActivity.getText(helperText));\n        return this;\n    }\n\n    public TextInputDropdownDialogBuilder setCheckboxLabel(@Nullable CharSequence checkboxLabel) {\n        if (checkboxLabel != null) {\n            mCheckBox.setVisibility(View.VISIBLE);\n            mCheckBox.setText(checkboxLabel);\n        } else mCheckBox.setVisibility(View.GONE);\n        return this;\n    }\n\n    public TextInputDropdownDialogBuilder setCheckboxLabel(@StringRes int checkboxLabel) {\n        if (checkboxLabel != 0) {\n            mCheckBox.setVisibility(View.VISIBLE);\n            mCheckBox.setText(checkboxLabel);\n        } else mCheckBox.setVisibility(View.GONE);\n        return this;\n    }\n\n    public TextInputDropdownDialogBuilder setPositiveButton(@StringRes int textId, @Nullable OnClickListener listener) {\n        mBuilder.setPositiveButton(textId, (dialog, which) -> {\n            if (listener != null) listener.onClick(dialog, which, mMainInput.getText(), mCheckBox.isChecked());\n        });\n        return this;\n    }\n\n    public TextInputDropdownDialogBuilder setPositiveButton(@NonNull CharSequence text, @Nullable OnClickListener listener) {\n        mBuilder.setPositiveButton(text, (dialog, which) -> {\n            if (listener != null) listener.onClick(dialog, which, mMainInput.getText(), mCheckBox.isChecked());\n        });\n        return this;\n    }\n\n    public TextInputDropdownDialogBuilder setNegativeButton(@StringRes int textId, @Nullable OnClickListener listener) {\n        mBuilder.setNegativeButton(textId, (dialog, which) -> {\n            if (listener != null) listener.onClick(dialog, which, mMainInput.getText(), mCheckBox.isChecked());\n        });\n        return this;\n    }\n\n    public TextInputDropdownDialogBuilder setNegativeButton(@NonNull CharSequence text, @Nullable OnClickListener listener) {\n        mBuilder.setNegativeButton(text, (dialog, which) -> {\n            if (listener != null) listener.onClick(dialog, which, mMainInput.getText(), mCheckBox.isChecked());\n        });\n        return this;\n    }\n\n    public TextInputDropdownDialogBuilder setNeutralButton(@StringRes int textId, @Nullable OnClickListener listener) {\n        mBuilder.setNeutralButton(textId, (dialog, which) -> {\n            if (listener != null) listener.onClick(dialog, which, mMainInput.getText(), mCheckBox.isChecked());\n        });\n        return this;\n    }\n\n    public TextInputDropdownDialogBuilder setNeutralButton(@NonNull CharSequence text, @Nullable OnClickListener listener) {\n        mBuilder.setNeutralButton(text, (dialog, which) -> {\n            if (listener != null) listener.onClick(dialog, which, mMainInput.getText(), mCheckBox.isChecked());\n        });\n        return this;\n    }\n\n    public AlertDialog create() {\n        return mBuilder.create();\n    }\n\n    public void show() {\n        create().show();\n    }\n}\n"
  },
  {
    "path": "libcore/ui/src/main/java/io/github/muntashirakon/lifecycle/SingleLiveEvent.java",
    "content": "// SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-or-later\n\npackage io.github.muntashirakon.lifecycle;\n\nimport android.util.Log;\n\nimport androidx.annotation.MainThread;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.lifecycle.LifecycleOwner;\nimport androidx.lifecycle.MutableLiveData;\nimport androidx.lifecycle.Observer;\n\nimport java.util.concurrent.atomic.AtomicBoolean;\n\n/**\n * A lifecycle-aware observable that sends only new updates after subscription, used for events like\n * navigation and Snackbar messages.\n * <p>\n * This avoids a common problem with events: on configuration change (like rotation) an update\n * can be emitted if the observer is active. This LiveData only calls the observable if there's an\n * explicit call to setValue() or call().\n * <p>\n * Note that only one observer is going to be notified of changes.\n */\n// Copyright 2017 Google Inc.\npublic class SingleLiveEvent<T> extends MutableLiveData<T> {\n    private static final String TAG = SingleLiveEvent.class.getSimpleName();\n\n    private final AtomicBoolean mPending = new AtomicBoolean(false);\n\n    @MainThread\n    public void observe(@NonNull LifecycleOwner owner, @NonNull final Observer<? super T> observer) {\n\n        if (hasActiveObservers()) {\n            Log.w(TAG, \"Multiple observers registered but only one will be notified of changes.\");\n        }\n\n        // Observe the internal MutableLiveData\n        super.observe(owner, t -> {\n            if (mPending.compareAndSet(true, false)) {\n                observer.onChanged(t);\n            }\n        });\n    }\n\n    @MainThread\n    public void setValue(@Nullable T t) {\n        mPending.set(true);\n        super.setValue(t);\n    }\n\n    /**\n     * Used for cases where T is Void, to make calls cleaner.\n     */\n    @MainThread\n    public void call() {\n        setValue(null);\n    }\n}"
  },
  {
    "path": "libcore/ui/src/main/java/io/github/muntashirakon/lifecycle/SoftInputLifeCycleObserver.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.lifecycle;\n\nimport android.content.Context;\nimport android.view.View;\nimport android.view.inputmethod.InputMethodManager;\n\nimport androidx.annotation.NonNull;\nimport androidx.lifecycle.DefaultLifecycleObserver;\nimport androidx.lifecycle.LifecycleOwner;\n\nimport java.lang.ref.WeakReference;\n\npublic class SoftInputLifeCycleObserver implements DefaultLifecycleObserver {\n    @NonNull\n    private final WeakReference<View> mViewRef;\n\n    public SoftInputLifeCycleObserver(@NonNull WeakReference<View> viewRef) {\n        mViewRef = viewRef;\n    }\n\n    @Override\n    public void onResume(@NonNull LifecycleOwner owner) {\n        if (mViewRef.get() == null) {\n            return;\n        }\n        mViewRef.get().postDelayed(() -> {\n            View v = mViewRef.get();\n            if (v == null) return;\n            v.requestFocus();\n            InputMethodManager imm = (InputMethodManager) v.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);\n            imm.showSoftInput(v, InputMethodManager.SHOW_IMPLICIT);\n        }, 100);\n    }\n\n    @Override\n    public void onPause(@NonNull LifecycleOwner owner) {\n        if (mViewRef.get() == null) {\n            return;\n        }\n        mViewRef.get().postDelayed(() -> {\n            View v = mViewRef.get();\n            if (v == null) return;\n            InputMethodManager imm = (InputMethodManager) v.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);\n            imm.hideSoftInputFromWindow(v.getWindowToken(), 0);\n        }, 100);\n    }\n}\n"
  },
  {
    "path": "libcore/ui/src/main/java/io/github/muntashirakon/multiselection/MultiSelectionActionsMenu.java",
    "content": "// SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-or-later\n\npackage io.github.muntashirakon.multiselection;\n\nimport android.annotation.SuppressLint;\nimport android.content.Context;\nimport android.view.MenuItem;\nimport android.view.SubMenu;\n\nimport androidx.annotation.NonNull;\nimport androidx.appcompat.view.menu.MenuBuilder;\nimport androidx.appcompat.view.menu.MenuItemImpl;\n\n/**\n * Provides a {@link MenuBuilder} that can be used to build a menu that can be placed inside\n * navigation bar view such as the bottom navigation menu or the navigation rail view. This\n * implementation of the menu builder prevents the addition of submenus to the primary destinations.\n */\n// Copyright 2020 The Android Open Source Project\n@SuppressLint(\"RestrictedApi\")\nfinal class MultiSelectionActionsMenu extends MenuBuilder {\n\n    public MultiSelectionActionsMenu(@NonNull Context context) {\n        super(context);\n    }\n\n    @NonNull\n    @Override\n    public SubMenu addSubMenu(int group, int id, int categoryOrder, @NonNull CharSequence title) {\n        throw new UnsupportedOperationException(\"MultiSelectionActionsView does not support submenus\");\n    }\n\n    @Override\n    @NonNull\n    protected MenuItem addInternal(int group, int id, int categoryOrder, @NonNull CharSequence title) {\n        stopDispatchingItemsChanged();\n        final MenuItem item = super.addInternal(group, id, categoryOrder, title);\n        if (item instanceof MenuItemImpl) {\n            ((MenuItemImpl) item).setExclusiveCheckable(true);\n        }\n        startDispatchingItemsChanged();\n        return item;\n    }\n}"
  },
  {
    "path": "libcore/ui/src/main/java/io/github/muntashirakon/multiselection/MultiSelectionActionsMenuPresenter.java",
    "content": "// SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-or-later\n\npackage io.github.muntashirakon.multiselection;\n\nimport android.annotation.SuppressLint;\nimport android.content.Context;\nimport android.os.Parcel;\nimport android.os.Parcelable;\nimport android.view.ViewGroup;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.appcompat.view.menu.MenuBuilder;\nimport androidx.appcompat.view.menu.MenuItemImpl;\nimport androidx.appcompat.view.menu.MenuPresenter;\nimport androidx.appcompat.view.menu.MenuView;\nimport androidx.appcompat.view.menu.SubMenuBuilder;\n\n// Copyright 2020 The Android Open Source Project\n@SuppressLint(\"RestrictedApi\")\nclass MultiSelectionActionsMenuPresenter implements MenuPresenter {\n    private MultiSelectionActionsView mMenuView;\n    private boolean mUpdateSuspended = false;\n    private int mId;\n\n    public void setMenuView(@NonNull MultiSelectionActionsView menuView) {\n        mMenuView = menuView;\n    }\n\n    @Override\n    public void initForMenu(@NonNull Context context, @NonNull MenuBuilder menu) {\n        mMenuView.initialize(menu);\n    }\n\n    @Override\n    @Nullable\n    public MenuView getMenuView(@Nullable ViewGroup root) {\n        return mMenuView;\n    }\n\n    @Override\n    public void updateMenuView(boolean cleared) {\n        if (mUpdateSuspended) {\n            return;\n        }\n        if (cleared) {\n            mMenuView.buildMenuView();\n        } else {\n            mMenuView.updateMenuView();\n        }\n    }\n\n    @Override\n    public void setCallback(@Nullable Callback cb) {\n    }\n\n    @Override\n    public boolean onSubMenuSelected(@Nullable SubMenuBuilder subMenu) {\n        return false;\n    }\n\n    @Override\n    public void onCloseMenu(@Nullable MenuBuilder menu, boolean allMenusAreClosing) {\n    }\n\n    @Override\n    public boolean flagActionItems() {\n        return false;\n    }\n\n    @Override\n    public boolean expandItemActionView(@Nullable MenuBuilder menu, @Nullable MenuItemImpl item) {\n        return false;\n    }\n\n    @Override\n    public boolean collapseItemActionView(@Nullable MenuBuilder menu, @Nullable MenuItemImpl item) {\n        return false;\n    }\n\n    public void setId(int id) {\n        mId = id;\n    }\n\n    @Override\n    public int getId() {\n        return mId;\n    }\n\n\n    @NonNull\n    @Override\n    public Parcelable onSaveInstanceState() {\n        return new SavedState();\n    }\n\n    @Override\n    public void onRestoreInstanceState(@NonNull Parcelable state) {\n    }\n\n    public void setUpdateSuspended(boolean updateSuspended) {\n        mUpdateSuspended = updateSuspended;\n    }\n\n    static class SavedState implements Parcelable {\n        SavedState() {\n        }\n\n        SavedState(@NonNull Parcel in) {\n        }\n\n        @Override\n        public int describeContents() {\n            return 0;\n        }\n\n        @Override\n        public void writeToParcel(@NonNull Parcel out, int flags) {\n        }\n\n        public static final Creator<SavedState> CREATOR = new Creator<SavedState>() {\n            @NonNull\n            @Override\n            public SavedState createFromParcel(@NonNull Parcel in) {\n                return new SavedState(in);\n            }\n\n            @NonNull\n            @Override\n            public SavedState[] newArray(int size) {\n                return new SavedState[size];\n            }\n        };\n    }\n}"
  },
  {
    "path": "libcore/ui/src/main/java/io/github/muntashirakon/multiselection/MultiSelectionActionsView.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.multiselection;\n\nimport static com.google.android.material.theme.overlay.MaterialThemeOverlay.wrap;\n\nimport android.annotation.SuppressLint;\nimport android.content.Context;\nimport android.content.res.ColorStateList;\nimport android.graphics.drawable.ColorDrawable;\nimport android.graphics.drawable.Drawable;\nimport android.os.Build;\nimport android.os.Bundle;\nimport android.os.Parcel;\nimport android.os.Parcelable;\nimport android.text.TextUtils;\nimport android.util.AttributeSet;\nimport android.util.TypedValue;\nimport android.view.Menu;\nimport android.view.MenuInflater;\nimport android.view.MenuItem;\nimport android.view.ViewGroup;\n\nimport androidx.annotation.AttrRes;\nimport androidx.annotation.DimenRes;\nimport androidx.annotation.Dimension;\nimport androidx.annotation.DrawableRes;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.StyleRes;\nimport androidx.appcompat.content.res.AppCompatResources;\nimport androidx.appcompat.view.SupportMenuInflater;\nimport androidx.appcompat.view.menu.MenuBuilder;\nimport androidx.appcompat.view.menu.MenuItemImpl;\nimport androidx.appcompat.view.menu.MenuView;\nimport androidx.appcompat.widget.LinearLayoutCompat;\nimport androidx.appcompat.widget.PopupMenu;\nimport androidx.appcompat.widget.TintTypedArray;\nimport androidx.appcompat.widget.TooltipCompat;\nimport androidx.core.content.ContextCompat;\nimport androidx.core.graphics.drawable.DrawableCompat;\nimport androidx.core.view.ViewCompat;\nimport androidx.customview.view.AbsSavedState;\n\nimport com.google.android.material.internal.ThemeEnforcement;\nimport com.google.android.material.resources.MaterialResources;\nimport com.google.android.material.shape.MaterialShapeDrawable;\nimport com.google.android.material.shape.MaterialShapeUtils;\n\nimport java.util.ArrayList;\nimport java.util.Collections;\nimport java.util.List;\n\nimport io.github.muntashirakon.ui.R;\nimport io.github.muntashirakon.util.UiUtils;\n\n@SuppressLint({\"RestrictedApi\"})\n@SuppressWarnings({\"unused\"})\npublic class MultiSelectionActionsView extends LinearLayoutCompat implements MenuView {\n    private static final int MENU_PRESENTER_ID = 1;\n    private static final int[] CHECKED_STATE_SET = {android.R.attr.state_checked};\n    private static final int[] DISABLED_STATE_SET = {-android.R.attr.state_enabled};\n\n    /**\n     * Listener for handling selection events on options.\n     */\n    public interface OnItemSelectedListener {\n\n        /**\n         * Called when an item in the options menu is selected.\n         *\n         * @param item The selected item\n         * @return Whether the menu item selection was handled.\n         */\n        boolean onNavigationItemSelected(@NonNull MenuItem item);\n    }\n\n    @NonNull\n    private final MultiSelectionActionsMenu mMenu;\n    private final List<MenuItemImpl> mVisibleMenuItems = new ArrayList<>();\n\n    @NonNull\n    private final MultiSelectionActionsMenuPresenter mPresenter = new MultiSelectionActionsMenuPresenter();\n    private MenuInflater mMenuInflater;\n    private MenuBuilder mMenuBuilder;\n    @Nullable\n    private OnItemSelectedListener mSelectedListener;\n\n    @Nullable\n    private final ColorStateList mItemTextColorDefault;\n    @Nullable\n    private ColorStateList mItemIconTint;\n    @Dimension\n    private int mItemIconSize;\n    @Nullable\n    private ColorStateList mItemTextColorFromUser;\n    @StyleRes\n    private int mItemTextAppearanceInactive;\n    @StyleRes\n    private int mItemTextAppearanceActive;\n    @Nullable\n    private Drawable mItemBackground;\n    private int mItemBackgroundRes;\n    private boolean mItemActiveBackgroundEnabled;\n\n    public MultiSelectionActionsView(@NonNull Context context) {\n        this(context, null);\n    }\n\n    public MultiSelectionActionsView(@NonNull Context context, @Nullable AttributeSet attrs) {\n        this(context, attrs, R.attr.multiSelectionActionsView);\n    }\n\n    private MultiSelectionActionsView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {\n        this(context, attrs, defStyleAttr, R.style.Widget_AppTheme_MultiSelectionActionsView);\n    }\n\n    private MultiSelectionActionsView(@NonNull Context context, @Nullable AttributeSet attrs, @AttrRes int defStyleAttr,\n                                     @StyleRes int defStyleRes) {\n        super(wrap(context, attrs, defStyleAttr, defStyleRes), attrs, defStyleAttr);\n        context = getContext();\n\n        mItemTextColorDefault = createDefaultColorStateList(android.R.attr.textColorSecondary);\n\n        TintTypedArray attributes = ThemeEnforcement.obtainTintedStyledAttributes(\n                context,\n                attrs,\n                R.styleable.MultiSelectionActionsView,\n                defStyleAttr,\n                defStyleRes,\n                R.styleable.MultiSelectionActionsView_itemTextAppearanceInactive,\n                R.styleable.MultiSelectionActionsView_itemTextAppearanceActive);\n\n        if (attributes.hasValue(R.styleable.MultiSelectionActionsView_itemIconTint)) {\n            mItemIconTint = attributes.getColorStateList(R.styleable.MultiSelectionActionsView_itemIconTint);\n        } else {\n            mItemIconTint = createDefaultColorStateList(android.R.attr.textColorSecondary);\n        }\n\n        mItemIconSize = attributes.getDimensionPixelSize(R.styleable.MultiSelectionActionsView_itemIconSize,\n                getResources().getDimensionPixelSize(com.google.android.material.R.dimen.mtrl_navigation_bar_item_default_icon_size));\n\n        if (attributes.hasValue(R.styleable.MultiSelectionActionsView_itemTextAppearanceInactive)) {\n            mItemTextAppearanceInactive = attributes.getResourceId(\n                    R.styleable.MultiSelectionActionsView_itemTextAppearanceInactive, 0);\n        }\n\n        if (attributes.hasValue(R.styleable.MultiSelectionActionsView_itemTextAppearanceActive)) {\n            mItemTextAppearanceActive = attributes.getResourceId(\n                    R.styleable.MultiSelectionActionsView_itemTextAppearanceActive, 0);\n        }\n\n        if (attributes.hasValue(R.styleable.MultiSelectionActionsView_itemTextColor)) {\n            mItemTextColorFromUser = attributes.getColorStateList(R.styleable.MultiSelectionActionsView_itemTextColor);\n        }\n\n        if (getBackground() == null || getBackground() instanceof ColorDrawable) {\n            // Add a MaterialShapeDrawable as background that supports tinting in every API level.\n            ViewCompat.setBackground(this, createMaterialShapeDrawableBackground(context));\n        }\n\n        if (attributes.hasValue(R.styleable.MultiSelectionActionsView_elevation)) {\n            setElevation(attributes.getDimensionPixelSize(R.styleable.MultiSelectionActionsView_elevation, 0));\n        }\n\n        ColorStateList backgroundTint = MaterialResources.getColorStateList(\n                context, attributes, R.styleable.MultiSelectionActionsView_backgroundTint);\n        DrawableCompat.setTintList(getBackground().mutate(), backgroundTint);\n\n        int itemBackground = attributes.getResourceId(R.styleable.MultiSelectionActionsView_itemBackground, 0);\n        if (itemBackground != 0) {\n            mItemBackgroundRes = itemBackground;\n        }\n\n        setOrientation(HORIZONTAL);\n        mPresenter.setMenuView(this);\n        mPresenter.setId(MENU_PRESENTER_ID);\n        mMenu = new MultiSelectionActionsMenu(context);\n        mMenu.addMenuPresenter(mPresenter);\n        mPresenter.initForMenu(context, mMenu);\n\n        if (attributes.hasValue(R.styleable.MultiSelectionActionsView_menu)) {\n            inflateMenu(attributes.getResourceId(R.styleable.MultiSelectionActionsView_menu, 0));\n        }\n\n        attributes.recycle();\n\n        mMenu.setCallback(new MenuBuilder.Callback() {\n            @Override\n            public boolean onMenuItemSelected(@NonNull MenuBuilder menu, @NonNull MenuItem item) {\n                return mSelectedListener != null && !mSelectedListener.onNavigationItemSelected(item);\n            }\n\n            @Override\n            public void onMenuModeChange(@NonNull MenuBuilder menu) {\n            }\n        });\n    }\n\n    @Override\n    public void initialize(MenuBuilder menu) {\n        mMenuBuilder = menu;\n    }\n\n    @Override\n    public int getWindowAnimations() {\n        return 0;\n    }\n\n    @Override\n    protected void onSizeChanged(int w, int h, int oldw, int oldh) {\n        super.onSizeChanged(w, h, oldw, oldh);\n        if (w != oldw) {\n            renderItems();\n        }\n    }\n\n    @Override\n    protected void onAttachedToWindow() {\n        super.onAttachedToWindow();\n        MaterialShapeUtils.setParentAbsoluteElevation(this);\n    }\n\n    /**\n     * Sets the base elevation of this view, in pixels.\n     *\n     * @see R.styleable#MultiSelectionActionsView_elevation\n     */\n    @Override\n    public void setElevation(float elevation) {\n        super.setElevation(elevation);\n        MaterialShapeUtils.setElevation(this, elevation);\n    }\n\n    @NonNull\n    public MultiSelectionActionsMenu getMenu() {\n        return mMenu;\n    }\n\n    /**\n     * Set a listener that will be notified when an option is selected.\n     *\n     * @param listener The listener to notify\n     */\n    public void setOnItemSelectedListener(@Nullable OnItemSelectedListener listener) {\n        mSelectedListener = listener;\n    }\n\n    /**\n     * Returns the tint which is applied to our menu items' icons.\n     *\n     * @see R.styleable#MultiSelectionActionsView_itemIconTint\n     * @see #setItemIconTintList(ColorStateList)\n     */\n    @Nullable\n    public ColorStateList getItemIconTintList() {\n        return mItemIconTint;\n    }\n\n    /**\n     * Set the tint which is applied to our menu items' icons.\n     *\n     * @param tint the tint to apply.\n     * @see R.styleable#MultiSelectionActionsView_itemIconTint\n     */\n    public void setItemIconTintList(@Nullable ColorStateList tint) {\n        mItemIconTint = tint;\n        renderItems();\n    }\n\n    /**\n     * Set the size to provide for the menu item icons.\n     *\n     * <p>For best image resolution, use an icon with the same size set in this method.\n     *\n     * @param iconSize the size in pixels to provide for the menu item icons\n     * @see R.styleable#MultiSelectionActionsView_itemIconSize\n     */\n    public void setItemIconSize(@Dimension int iconSize) {\n        mItemIconSize = iconSize;\n        renderItems();\n    }\n\n    /**\n     * Set the size to provide for the menu item icons using a resource ID.\n     *\n     * <p>For best image resolution, use an icon with the same size set in this method.\n     *\n     * @param iconSizeRes the resource ID for the size to provide for the menu item icons\n     * @see R.styleable#MultiSelectionActionsView_itemIconSize\n     */\n    public void setItemIconSizeRes(@DimenRes int iconSizeRes) {\n        setItemIconSize(getResources().getDimensionPixelSize(iconSizeRes));\n    }\n\n    /**\n     * Returns the size provided for the menu item icons in pixels.\n     *\n     * @see R.styleable#MultiSelectionActionsView_itemIconSize\n     * @see #setItemIconSize(int)\n     */\n    @Dimension\n    public int getItemIconSize() {\n        return mItemIconSize;\n    }\n\n    /**\n     * Returns colors used for the different states (normal, selected, focused, etc.) of the menu item\n     * text.\n     *\n     * @return the ColorStateList of colors used for the different states of the menu items text.\n     * @see R.styleable#MultiSelectionActionsView_itemTextColor\n     * @see #setItemTextColor(ColorStateList)\n     */\n    @Nullable\n    public ColorStateList getItemTextColor() {\n        return mItemTextColorFromUser;\n    }\n\n    /**\n     * Set the colors to use for the different states (normal, selected, focused, etc.) of the menu\n     * item text.\n     *\n     * @see R.styleable#MultiSelectionActionsView_itemTextColor\n     * @see #getItemTextColor()\n     */\n    public void setItemTextColor(@Nullable ColorStateList textColor) {\n        mItemTextColorFromUser = textColor;\n        renderItems();\n    }\n\n    /**\n     * Returns the background resource of the menu items.\n     *\n     * @see R.styleable#MultiSelectionActionsView_itemBackground\n     * @see #setItemBackgroundResource(int)\n     * @deprecated Use {@link #getItemBackground()} instead.\n     */\n    @Deprecated\n    @DrawableRes\n    public int getItemBackgroundResource() {\n        return mItemBackgroundRes;\n    }\n\n    /**\n     * Set the background of our menu items to the given resource.\n     *\n     * @param resId The identifier of the resource.\n     * @see R.styleable#MultiSelectionActionsView_itemBackground\n     */\n    public void setItemBackgroundResource(@DrawableRes int resId) {\n        mItemBackgroundRes = resId;\n        renderItems();\n    }\n\n    /**\n     * Returns the background drawable of the menu items.\n     *\n     * @see R.styleable#MultiSelectionActionsView_itemBackground\n     * @see #setItemBackground(Drawable)\n     */\n    @Nullable\n    public Drawable getItemBackground() {\n        return mItemBackground;\n    }\n\n    /**\n     * Set the background of our menu items to the given drawable.\n     *\n     * @param background The drawable for the background.\n     * @see R.styleable#MultiSelectionActionsView_itemBackground\n     */\n    public void setItemBackground(@Nullable Drawable background) {\n        mItemBackground = background;\n        renderItems();\n    }\n\n    /**\n     * Get whether or not a selected item should show an active background.\n     *\n     * @return true if an active background will be shown when an item is selected.\n     */\n    public boolean isItemActiveBackgroundEnabled() {\n        return mItemActiveBackgroundEnabled;\n    }\n\n    /**\n     * Set whether a selected item should show an active background.\n     *\n     * @param enabled true if a selected item should show an active background.\n     */\n    public void setItemActiveBackgroundEnabled(boolean enabled) {\n        mItemActiveBackgroundEnabled = enabled;\n        renderItems();\n    }\n\n    /**\n     * Sets the text appearance to be used for inactive menu item labels.\n     *\n     * @param textAppearanceRes the text appearance ID used for inactive menu item labels\n     */\n    public void setItemTextAppearanceInactive(@StyleRes int textAppearanceRes) {\n        mItemTextAppearanceInactive = textAppearanceRes;\n        renderItems();\n    }\n\n    /**\n     * Returns the text appearance used for inactive menu item labels.\n     *\n     * @return the text appearance ID used for inactive menu item labels\n     */\n    @StyleRes\n    public int getItemTextAppearanceInactive() {\n        return mItemTextAppearanceInactive;\n    }\n\n    /**\n     * Sets the text appearance to be used for the menu item labels.\n     *\n     * @param textAppearanceRes the text appearance ID used for menu item labels\n     */\n    public void setItemTextAppearanceActive(@StyleRes int textAppearanceRes) {\n        mItemTextAppearanceActive = textAppearanceRes;\n        renderItems();\n    }\n\n    /**\n     * Returns the text appearance used for the active menu item label.\n     *\n     * @return the text appearance ID used for the active menu item label\n     */\n    @StyleRes\n    public int getItemTextAppearanceActive() {\n        return mItemTextAppearanceActive;\n    }\n\n    /**\n     * Inflate a menu resource into this navigation view.\n     *\n     * <p>Existing items in the menu will not be modified or removed.\n     *\n     * @param resId ID of a menu resource to inflate\n     */\n    public void inflateMenu(int resId) {\n        mPresenter.setUpdateSuspended(true);\n        getMenuInflater().inflate(resId, mMenu);\n        mPresenter.setUpdateSuspended(false);\n        mPresenter.updateMenuView(true);\n    }\n\n    public void updateMenuView() {\n        if (mMenuBuilder == null) {\n            return;\n        }\n        mVisibleMenuItems.clear();\n        mVisibleMenuItems.addAll(mMenuBuilder.getVisibleItems());\n        renderItems();\n    }\n\n    void buildMenuView() {\n        updateMenuView();\n    }\n\n    @SuppressLint(\"ClickableViewAccessibility\")\n    private void renderItems() {\n        if (getWidth() == 0) {\n            return;\n        }\n\n        boolean wasLayoutRequested = isLayoutRequested();\n        int widthDp = UiUtils.pxToDp(getContext(), getWidth());\n        int minButtonWidthDp = 80;\n        int maxButtons = widthDp / minButtonWidthDp;\n        int usableButtonCount = mVisibleMenuItems.size() <= maxButtons ? mVisibleMenuItems.size() : maxButtons - 1;\n        int allocatedWidth = getWidth() / maxButtons;\n\n        List<MenuItemImpl> renderableItems = mVisibleMenuItems.subList(0, usableButtonCount);\n        List<MenuItemImpl> overflowItems = renderableItems.size() < mVisibleMenuItems.size()\n                ? mVisibleMenuItems.subList(usableButtonCount, mVisibleMenuItems.size())\n                : Collections.emptyList();\n\n        removeAllViews();\n\n        for (MenuItemImpl menuItem : renderableItems) {\n            addNewOptionItemFromMenuItem(menuItem, allocatedWidth);\n        }\n\n        if (!overflowItems.isEmpty()) {\n            ReflowMenuItemView overflowView = getNewOptionItem();\n            addView(overflowView, new LinearLayoutCompat.LayoutParams(allocatedWidth, ViewGroup.LayoutParams.MATCH_PARENT));\n            // init\n            CharSequence tooltipText = getContext().getString(androidx.appcompat.R.string.abc_action_menu_overflow_description);\n            overflowView.setIcon(ContextCompat.getDrawable(getContext(), R.drawable.ic_more_horiz));\n            overflowView.setTitle(tooltipText);\n            overflowView.setContentDescription(tooltipText);\n            // Avoid calling tooltip for L and M devices because long pressing twice may freeze devices.\n            if (Build.VERSION.SDK_INT > Build.VERSION_CODES.M) {\n                TooltipCompat.setTooltipText(this, tooltipText);\n            }\n            overflowView.setOnClickListener(v -> {\n                PopupMenu overflowMenu = new PopupMenu(getContext(), overflowView);\n                overflowMenu.setForceShowIcon(true);\n                Menu menu = overflowMenu.getMenu();\n                for (int i = overflowItems.size() - 1; i >= 0; --i) {\n                    MenuItemImpl menuItem = overflowItems.get(i);\n                    addMenuFromMenuItem(menu, menuItem);\n                }\n                overflowMenu.show();\n            });\n        }\n        if (wasLayoutRequested) {\n            post(this::requestLayout);\n        }\n    }\n\n    private void addMenuFromMenuItem(@NonNull Menu menu, @NonNull MenuItemImpl menuItem) {\n        MenuItem newMenuItem = menu.add(menuItem.getItemId())\n                .setCheckable(menuItem.isCheckable())\n                .setChecked(menuItem.isChecked())\n                .setEnabled(menuItem.isEnabled())\n                .setIcon(menuItem.getIcon())\n                .setTitle(menuItem.getTitle());\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O && !TextUtils.isEmpty(menuItem.getContentDescription())) {\n            newMenuItem.setContentDescription(menuItem.getContentDescription());\n            CharSequence tooltip = !TextUtils.isEmpty(menuItem.getTooltipText())\n                    ? menuItem.getTooltipText()\n                    : menuItem.getTitle();\n            newMenuItem.setTooltipText(tooltip);\n        }\n        newMenuItem.setOnMenuItemClickListener(item -> mMenu.performItemAction(menuItem, mPresenter, 0));\n    }\n\n    @SuppressLint(\"ClickableViewAccessibility\")\n    private void addNewOptionItemFromMenuItem(@NonNull MenuItemImpl menuItem, int width) {\n        ReflowMenuItemView item = getNewOptionItem();\n        item.initialize(menuItem);\n        item.setOnClickListener(v -> mMenu.performItemAction(menuItem, mPresenter, 0));\n        addView(item, new LinearLayoutCompat.LayoutParams(width, ViewGroup.LayoutParams.MATCH_PARENT));\n    }\n\n    @NonNull\n    @SuppressLint(\"ClickableViewAccessibility\")\n    private ReflowMenuItemView getNewOptionItem() {\n        ReflowMenuItemView item = new ReflowMenuItemView(getContext());\n        item.setIconTintList(mItemIconTint);\n        item.setIconSize(mItemIconSize);\n        // Set the text color the default, then look for another text color in order of precedence.\n        item.setTextColor(mItemTextColorDefault);\n        item.setTextAppearanceInactive(mItemTextAppearanceInactive);\n        item.setTextAppearanceActive(mItemTextAppearanceActive);\n        item.setTextColor(mItemTextColorFromUser);\n        item.setActiveBackgroundEnabled(mItemActiveBackgroundEnabled);\n        if (mItemBackground != null) {\n            item.setItemBackground(mItemBackground);\n        } else {\n            item.setItemBackground(mItemBackgroundRes);\n        }\n        return item;\n    }\n\n    private MenuInflater getMenuInflater() {\n        if (mMenuInflater == null) {\n            mMenuInflater = new SupportMenuInflater(getContext());\n        }\n        return mMenuInflater;\n    }\n\n    @Nullable\n    public ColorStateList createDefaultColorStateList(int baseColorThemeAttr) {\n        final TypedValue value = new TypedValue();\n        if (!getContext().getTheme().resolveAttribute(baseColorThemeAttr, value, true)) {\n            return null;\n        }\n        ColorStateList baseColor = AppCompatResources.getColorStateList(getContext(), value.resourceId);\n        if (!getContext()\n                .getTheme()\n                .resolveAttribute(androidx.appcompat.R.attr.colorPrimary, value, true)) {\n            return null;\n        }\n        int colorPrimary = value.data;\n        int defaultColor = baseColor.getDefaultColor();\n        return new ColorStateList(\n                new int[][]{DISABLED_STATE_SET, CHECKED_STATE_SET, EMPTY_STATE_SET},\n                new int[]{\n                        baseColor.getColorForState(DISABLED_STATE_SET, defaultColor), colorPrimary, defaultColor\n                });\n    }\n\n    @NonNull\n    private MaterialShapeDrawable createMaterialShapeDrawableBackground(Context context) {\n        MaterialShapeDrawable materialShapeDrawable = new MaterialShapeDrawable();\n        Drawable originalBackground = getBackground();\n        if (originalBackground instanceof ColorDrawable) {\n            materialShapeDrawable.setFillColor(ColorStateList.valueOf(((ColorDrawable) originalBackground).getColor()));\n        }\n        materialShapeDrawable.initializeElevationOverlay(context);\n        return materialShapeDrawable;\n    }\n\n    @Override\n    @NonNull\n    protected Parcelable onSaveInstanceState() {\n        Parcelable superState = super.onSaveInstanceState();\n        SavedState savedState = new SavedState(superState);\n        savedState.menuPresenterState = new Bundle();\n        mMenu.savePresenterStates(savedState.menuPresenterState);\n        return savedState;\n    }\n\n    @Override\n    protected void onRestoreInstanceState(@Nullable Parcelable state) {\n        if (!(state instanceof SavedState)) {\n            super.onRestoreInstanceState(state);\n            return;\n        }\n        SavedState savedState = (SavedState) state;\n        super.onRestoreInstanceState(savedState.getSuperState());\n        mMenu.restorePresenterStates(savedState.menuPresenterState);\n    }\n\n    static class SavedState extends AbsSavedState {\n        @Nullable\n        Bundle menuPresenterState;\n\n        public SavedState(Parcelable superState) {\n            super(superState);\n        }\n\n        public SavedState(@NonNull Parcel source, @Nullable ClassLoader loader) {\n            super(source, loader);\n            if (loader == null) {\n                loader = getClass().getClassLoader();\n            }\n            readFromParcel(source, loader);\n        }\n\n        @Override\n        public void writeToParcel(@NonNull Parcel out, int flags) {\n            super.writeToParcel(out, flags);\n            out.writeBundle(menuPresenterState);\n        }\n\n        private void readFromParcel(@NonNull Parcel in, @Nullable ClassLoader loader) {\n            menuPresenterState = in.readBundle(loader);\n        }\n\n        public static final Creator<SavedState> CREATOR = new ClassLoaderCreator<SavedState>() {\n            @NonNull\n            @Override\n            public SavedState createFromParcel(@NonNull Parcel in, @Nullable ClassLoader loader) {\n                return new SavedState(in, loader);\n            }\n\n            @NonNull\n            @Override\n            public SavedState createFromParcel(@NonNull Parcel in) {\n                return new SavedState(in, null);\n            }\n\n            @NonNull\n            @Override\n            public SavedState[] newArray(int size) {\n                return new SavedState[size];\n            }\n        };\n    }\n}\n"
  },
  {
    "path": "libcore/ui/src/main/java/io/github/muntashirakon/multiselection/ReflowMenuItemView.java",
    "content": "// SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-or-later\n\npackage io.github.muntashirakon.multiselection;\n\nimport android.annotation.SuppressLint;\nimport android.content.Context;\nimport android.content.res.ColorStateList;\nimport android.graphics.drawable.Drawable;\nimport android.os.Build.VERSION;\nimport android.os.Build.VERSION_CODES;\nimport android.text.TextUtils;\nimport android.util.AttributeSet;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.view.accessibility.AccessibilityNodeInfo;\nimport android.widget.FrameLayout;\nimport android.widget.ImageView;\nimport android.widget.TextView;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.StyleRes;\nimport androidx.appcompat.view.menu.MenuItemImpl;\nimport androidx.appcompat.widget.LinearLayoutCompat;\nimport androidx.appcompat.widget.TooltipCompat;\nimport androidx.core.content.ContextCompat;\nimport androidx.core.graphics.drawable.DrawableCompat;\nimport androidx.core.view.PointerIconCompat;\nimport androidx.core.view.ViewCompat;\nimport androidx.core.view.accessibility.AccessibilityNodeInfoCompat;\nimport androidx.core.view.accessibility.AccessibilityNodeInfoCompat.AccessibilityActionCompat;\nimport androidx.core.view.accessibility.AccessibilityNodeInfoCompat.CollectionItemInfoCompat;\nimport androidx.core.widget.TextViewCompat;\n\nimport io.github.muntashirakon.ui.R;\n\n// Copyright 2020 The Android Open Source Project\n@SuppressLint(\"RestrictedApi\")\npublic final class ReflowMenuItemView extends FrameLayout {\n    private static final int[] CHECKED_STATE_SET = {android.R.attr.state_checked};\n\n    private final ImageView mIcon;\n    private final TextView mLabel;\n\n    @Nullable\n    private MenuItemImpl mItemData;\n\n    @Nullable\n    private ColorStateList mIconTint;\n    @Nullable\n    private Drawable mOriginalIconDrawable;\n    @Nullable\n    private Drawable mWrappedIconDrawable;\n\n    private boolean mActiveBackgroundEnabled = false;\n\n    public ReflowMenuItemView(Context context) {\n        this(context, null);\n    }\n\n    public ReflowMenuItemView(Context context, @Nullable AttributeSet attrs) {\n        super(context, attrs);\n\n        // Inflate layout\n        LayoutInflater.from(context).inflate(R.layout.item_reflow_menu, this, true);\n        mIcon = findViewById(R.id.icon);\n        mLabel = findViewById(R.id.label);\n\n        ViewCompat.setImportantForAccessibility(mLabel, ViewCompat.IMPORTANT_FOR_ACCESSIBILITY_YES);\n        setFocusable(true);\n    }\n\n    public void initialize(@NonNull MenuItemImpl itemData) {\n        mItemData = itemData;\n        setCheckable(itemData.isCheckable());\n        setChecked(itemData.isChecked());\n        setEnabled(itemData.isEnabled());\n        setIcon(itemData.getIcon());\n        setTitle(itemData.getTitle());\n        setId(itemData.getItemId());\n        if (!TextUtils.isEmpty(itemData.getContentDescription())) {\n            setContentDescription(itemData.getContentDescription());\n        }\n\n        CharSequence tooltipText = !TextUtils.isEmpty(itemData.getTooltipText())\n                ? itemData.getTooltipText()\n                : itemData.getTitle();\n\n        // Avoid calling tooltip for L and M devices because long pressing twice may freeze devices.\n        if (VERSION.SDK_INT > VERSION_CODES.M) {\n            TooltipCompat.setTooltipText(this, tooltipText);\n        }\n        setVisibility(itemData.isVisible() ? View.VISIBLE : View.GONE);\n    }\n\n    public void setTitle(@Nullable CharSequence title) {\n        mLabel.setText(title);\n        if (mItemData == null || TextUtils.isEmpty(mItemData.getContentDescription())) {\n            setContentDescription(title);\n        }\n\n        CharSequence tooltipText = mItemData == null || TextUtils.isEmpty(mItemData.getTooltipText())\n                ? title\n                : mItemData.getTooltipText();\n        // Avoid calling tooltip for L and M devices because long pressing twice may freeze devices.\n        if (VERSION.SDK_INT > VERSION_CODES.M) {\n            TooltipCompat.setTooltipText(this, tooltipText);\n        }\n    }\n\n    public void setCheckable(boolean checkable) {\n        refreshDrawableState();\n    }\n\n    public void setChecked(boolean checked) {\n        mLabel.setPivotX(mLabel.getWidth() / 2F);\n        mLabel.setPivotY(mLabel.getBaseline());\n\n        refreshDrawableState();\n\n        // Set the item as selected to send an AccessibilityEvent.TYPE_VIEW_SELECTED from View, so that\n        // the item is read out as selected.\n        setSelected(checked);\n    }\n\n    @Override\n    public void onInitializeAccessibilityNodeInfo(@NonNull AccessibilityNodeInfo info) {\n        super.onInitializeAccessibilityNodeInfo(info);\n        AccessibilityNodeInfoCompat infoCompat = AccessibilityNodeInfoCompat.wrap(info);\n        infoCompat.setCollectionItemInfo(\n                CollectionItemInfoCompat.obtain(\n                        /* rowIndex= */ 0,\n                        /* rowSpan= */ 1,\n                        /* columnIndex= */ getItemVisiblePosition(),\n                        /* columnSpan= */ 1,\n                        /* heading= */ false,\n                        /* selected= */ isSelected()));\n        if (isSelected()) {\n            infoCompat.setClickable(false);\n            infoCompat.removeAction(AccessibilityActionCompat.ACTION_CLICK);\n        }\n        infoCompat.setRoleDescription(getResources().getString(com.google.android.material.R.string.item_view_role_description));\n    }\n\n    /**\n     * Iterate through all the preceding bottom navigating items to determine this item's visible\n     * position.\n     *\n     * @return This item's visible position in a bottom navigation.\n     */\n    private int getItemVisiblePosition() {\n        ViewGroup parent = (ViewGroup) getParent();\n        int index = parent.indexOfChild(this);\n        int visiblePosition = 0;\n        for (int i = 0; i < index; i++) {\n            View child = parent.getChildAt(i);\n            if (child instanceof ReflowMenuItemView && child.getVisibility() == View.VISIBLE) {\n                visiblePosition++;\n            }\n        }\n        return visiblePosition;\n    }\n\n    @Override\n    public void setEnabled(boolean enabled) {\n        super.setEnabled(enabled);\n        mLabel.setEnabled(enabled);\n        mIcon.setEnabled(enabled);\n\n        if (enabled) {\n            ViewCompat.setPointerIcon(this, PointerIconCompat.getSystemIcon(getContext(), PointerIconCompat.TYPE_HAND));\n        } else {\n            ViewCompat.setPointerIcon(this, null);\n        }\n    }\n\n    @Override\n    @NonNull\n    public int[] onCreateDrawableState(final int extraSpace) {\n        final int[] drawableState = super.onCreateDrawableState(extraSpace + 1);\n        if (mActiveBackgroundEnabled && mItemData != null && mItemData.isCheckable() && mItemData.isChecked()) {\n            mergeDrawableStates(drawableState, CHECKED_STATE_SET);\n        }\n        return drawableState;\n    }\n\n    public void setIcon(@Nullable Drawable iconDrawable) {\n        if (iconDrawable == mOriginalIconDrawable) {\n            return;\n        }\n\n        // Save the original icon to check if it has changed in future calls of this method.\n        mOriginalIconDrawable = iconDrawable;\n        if (iconDrawable != null) {\n            Drawable.ConstantState state = iconDrawable.getConstantState();\n            iconDrawable = DrawableCompat.wrap(state == null ? iconDrawable : state.newDrawable()).mutate();\n            mWrappedIconDrawable = iconDrawable;\n            if (mIconTint != null) {\n                DrawableCompat.setTintList(mWrappedIconDrawable, mIconTint);\n            }\n        }\n        mIcon.setImageDrawable(iconDrawable);\n    }\n\n    public void setIconTintList(@Nullable ColorStateList tint) {\n        mIconTint = tint;\n        if (mItemData != null && mWrappedIconDrawable != null) {\n            DrawableCompat.setTintList(mWrappedIconDrawable, mIconTint);\n            mWrappedIconDrawable.invalidateSelf();\n        }\n    }\n\n    public void setIconSize(int iconSize) {\n        LinearLayoutCompat.LayoutParams iconParams = (LinearLayoutCompat.LayoutParams) mIcon.getLayoutParams();\n        iconParams.width = iconSize;\n        iconParams.height = iconSize;\n        mIcon.setLayoutParams(iconParams);\n    }\n\n    public void setTextAppearanceInactive(@StyleRes int inactiveTextAppearance) {\n        TextViewCompat.setTextAppearance(mLabel, inactiveTextAppearance);\n    }\n\n    public void setTextAppearanceActive(@StyleRes int activeTextAppearance) {\n        TextViewCompat.setTextAppearance(mLabel, activeTextAppearance);\n    }\n\n    public void setTextColor(@Nullable ColorStateList color) {\n        if (color != null) {\n            mLabel.setTextColor(color);\n        }\n    }\n\n    public void setItemBackground(int background) {\n        Drawable backgroundDrawable = background == 0 ? null : ContextCompat.getDrawable(getContext(), background);\n        setItemBackground(backgroundDrawable);\n    }\n\n    public void setItemBackground(@Nullable Drawable background) {\n        if (background != null && background.getConstantState() != null) {\n            background = background.getConstantState().newDrawable().mutate();\n        }\n        ViewCompat.setBackground(this, background);\n    }\n\n    /**\n     * Set whether or not this item should show an active indicator when checked.\n     */\n    public void setActiveBackgroundEnabled(boolean enabled) {\n        mActiveBackgroundEnabled = enabled;\n        requestLayout();\n    }\n}\n"
  },
  {
    "path": "libcore/ui/src/main/java/io/github/muntashirakon/preference/DefaultAlertPreference.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.preference;\n\nimport android.content.Context;\nimport android.os.Build;\nimport android.text.method.LinkMovementMethod;\nimport android.util.AttributeSet;\nimport android.view.Gravity;\nimport android.view.View;\nimport android.widget.TextView;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.appcompat.widget.LinearLayoutCompat;\nimport androidx.preference.Preference;\nimport androidx.preference.PreferenceViewHolder;\n\nimport io.github.muntashirakon.ui.R;\n\npublic class DefaultAlertPreference extends Preference {\n    private boolean mAddSpaceBetweenIconAndText = true;\n\n    public DefaultAlertPreference(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {\n        super(context, attrs, defStyleAttr, defStyleRes);\n    }\n\n    public DefaultAlertPreference(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {\n        this(context, attrs, defStyleAttr, R.style.Preference_M3_Alert);\n    }\n\n    public DefaultAlertPreference(@NonNull Context context, @Nullable AttributeSet attrs) {\n        this(context, attrs, R.attr.alertPreferenceStyle);\n    }\n\n    public DefaultAlertPreference(@NonNull Context context) {\n        this(context, null);\n    }\n\n    @Override\n    public void onBindViewHolder(@NonNull PreferenceViewHolder holder) {\n        super.onBindViewHolder(holder);\n        final TextView summaryView = (TextView) holder.findViewById(android.R.id.summary);\n        if (summaryView != null) {\n            summaryView.setMovementMethod(LinkMovementMethod.getInstance());\n        }\n        View imageFrame = holder.findViewById(androidx.preference.R.id.icon_frame);\n        if (imageFrame == null && Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {\n            imageFrame = holder.findViewById(android.R.id.icon_frame);\n        }\n        if (imageFrame instanceof LinearLayoutCompat) {\n            ((LinearLayoutCompat) imageFrame).setGravity(Gravity.START);\n        }\n        View empty = holder.findViewById(android.R.id.empty);\n        if (empty != null) {\n            if (mAddSpaceBetweenIconAndText && imageFrame != null && imageFrame.getVisibility() != View.GONE) {\n                empty.setVisibility(View.VISIBLE);\n            } else {\n                empty.setVisibility(View.GONE);\n            }\n        }\n    }\n\n    public void setAddSpaceBetweenIconAndText(boolean addSpaceBetweenIconAndText) {\n        mAddSpaceBetweenIconAndText = addSpaceBetweenIconAndText;\n    }\n\n    public boolean isAddSpaceBetweenIconAndText() {\n        return mAddSpaceBetweenIconAndText;\n    }\n}\n"
  },
  {
    "path": "libcore/ui/src/main/java/io/github/muntashirakon/preference/HyperlinkPreference.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.preference;\n\nimport android.content.Context;\nimport android.text.method.LinkMovementMethod;\nimport android.util.AttributeSet;\nimport android.widget.TextView;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.preference.Preference;\nimport androidx.preference.PreferenceViewHolder;\n\npublic class HyperlinkPreference extends Preference {\n    public HyperlinkPreference(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {\n        super(context, attrs, defStyleAttr, defStyleRes);\n    }\n\n    public HyperlinkPreference(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {\n        super(context, attrs, defStyleAttr);\n    }\n\n    public HyperlinkPreference(@NonNull Context context, @Nullable AttributeSet attrs) {\n        super(context, attrs);\n    }\n\n    public HyperlinkPreference(@NonNull Context context) {\n        super(context);\n    }\n\n    @Override\n    public void onBindViewHolder(@NonNull PreferenceViewHolder holder) {\n        super.onBindViewHolder(holder);\n        final TextView summaryView = (TextView) holder.findViewById(android.R.id.summary);\n        if (summaryView != null) {\n            summaryView.setMovementMethod(LinkMovementMethod.getInstance());\n        }\n    }\n}\n"
  },
  {
    "path": "libcore/ui/src/main/java/io/github/muntashirakon/preference/InfoAlertPreference.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.preference;\n\nimport android.content.Context;\nimport android.content.res.ColorStateList;\nimport android.util.AttributeSet;\nimport android.widget.ImageView;\nimport android.widget.TextView;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.preference.PreferenceViewHolder;\n\nimport com.google.android.material.card.MaterialCardView;\nimport com.google.android.material.color.MaterialColors;\n\nimport io.github.muntashirakon.ui.R;\n\npublic class InfoAlertPreference extends DefaultAlertPreference {\n    public InfoAlertPreference(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {\n        super(context, attrs, defStyleAttr, defStyleRes);\n        setAddSpaceBetweenIconAndText(false);\n    }\n\n    public InfoAlertPreference(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {\n        this(context, attrs, defStyleAttr, R.style.Preference_M3_Alert);\n    }\n\n    public InfoAlertPreference(@NonNull Context context, @Nullable AttributeSet attrs) {\n        this(context, attrs, R.attr.alertPreferenceStyle);\n    }\n\n    public InfoAlertPreference(@NonNull Context context) {\n        this(context, null);\n    }\n\n    @Override\n    public void onBindViewHolder(@NonNull PreferenceViewHolder holder) {\n        super.onBindViewHolder(holder);\n        int background = MaterialColors.getColor(holder.itemView, com.google.android.material.R.attr.colorPrimaryContainer);\n        int foreground = MaterialColors.getColor(holder.itemView, com.google.android.material.R.attr.colorOnPrimaryContainer);\n        if (holder.itemView instanceof MaterialCardView) {\n            MaterialCardView cardView = (MaterialCardView) holder.itemView;\n            cardView.setCardBackgroundColor(background);\n        }\n        final TextView summaryView = (TextView) holder.findViewById(android.R.id.summary);\n        if (summaryView != null) {\n            summaryView.setTextColor(foreground);\n        }\n        final ImageView imageView = (ImageView)holder.findViewById(android.R.id.icon);\n        if (imageView != null) {\n            imageView.setImageTintList(ColorStateList.valueOf(foreground));\n        }\n    }\n}\n"
  },
  {
    "path": "libcore/ui/src/main/java/io/github/muntashirakon/preference/PrimaryButtonPreference.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.preference;\n\nimport android.content.Context;\nimport android.util.AttributeSet;\nimport android.view.View;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.preference.Preference;\nimport androidx.preference.PreferenceViewHolder;\n\nimport com.google.android.material.button.MaterialButton;\n\nimport io.github.muntashirakon.ui.R;\n\npublic class PrimaryButtonPreference extends Preference {\n    public PrimaryButtonPreference(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {\n        super(context, attrs, defStyleAttr, defStyleRes);\n    }\n\n    public PrimaryButtonPreference(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {\n        this(context, attrs, defStyleAttr, R.style.Preference_M3_ButtonPreference_Primary);\n    }\n\n    public PrimaryButtonPreference(@NonNull Context context, @Nullable AttributeSet attrs) {\n        this(context, attrs, R.attr.primaryButtonPreferenceStyle);\n    }\n\n    public PrimaryButtonPreference(@NonNull Context context) {\n        this(context, null);\n    }\n\n    @Override\n    public void onBindViewHolder(@NonNull PreferenceViewHolder holder) {\n        super.onBindViewHolder(holder);\n        View itemView = holder.itemView;\n        MaterialButton button = (MaterialButton) holder.findViewById(android.R.id.button1);\n        button.setText(getTitle());\n        button.setIcon(getIcon());\n        if (itemView.hasOnClickListeners()) {\n            // Proxy listeners\n            button.setOnClickListener(v -> itemView.callOnClick());\n        }\n        // Selectable\n        boolean isSelectable = isSelectable();\n        itemView.setClickable(false);\n        itemView.setFocusable(false);\n        button.setClickable(isSelectable);\n        button.setFocusable(isSelectable);\n    }\n}\n"
  },
  {
    "path": "libcore/ui/src/main/java/io/github/muntashirakon/preference/TopSwitchPreference.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.preference;\n\nimport android.content.Context;\nimport android.util.AttributeSet;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.preference.SwitchPreferenceCompat;\n\nimport io.github.muntashirakon.ui.R;\n\npublic class TopSwitchPreference extends SwitchPreferenceCompat {\n    public TopSwitchPreference(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {\n        this(context, attrs, defStyleAttr, R.style.Preference_M3_TopSwitchPreference);\n    }\n\n    public TopSwitchPreference(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {\n        super(context, attrs, defStyleAttr, defStyleRes);\n    }\n\n    public TopSwitchPreference(@NonNull Context context, @Nullable AttributeSet attrs) {\n        this(context, attrs, R.attr.topSwitchPreferenceStyle);\n    }\n\n    public TopSwitchPreference(@NonNull Context context) {\n        this(context, null);\n    }\n}\n"
  },
  {
    "path": "libcore/ui/src/main/java/io/github/muntashirakon/preference/WarningAlertPreference.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.preference;\n\nimport android.content.Context;\nimport android.content.res.ColorStateList;\nimport android.util.AttributeSet;\nimport android.widget.ImageView;\nimport android.widget.TextView;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.preference.PreferenceViewHolder;\n\nimport com.google.android.material.card.MaterialCardView;\nimport com.google.android.material.color.MaterialColors;\n\nimport io.github.muntashirakon.ui.R;\n\npublic class WarningAlertPreference extends DefaultAlertPreference {\n    public WarningAlertPreference(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {\n        super(context, attrs, defStyleAttr, defStyleRes);\n        setAddSpaceBetweenIconAndText(false);\n    }\n\n    public WarningAlertPreference(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {\n        this(context, attrs, defStyleAttr, R.style.Preference_M3_Alert);\n    }\n\n    public WarningAlertPreference(@NonNull Context context, @Nullable AttributeSet attrs) {\n        this(context, attrs, R.attr.alertPreferenceStyle);\n    }\n\n    public WarningAlertPreference(@NonNull Context context) {\n        this(context, null);\n    }\n\n    @Override\n    public void onBindViewHolder(@NonNull PreferenceViewHolder holder) {\n        super.onBindViewHolder(holder);\n        int background = MaterialColors.getColor(holder.itemView, com.google.android.material.R.attr.colorErrorContainer);\n        int foreground = MaterialColors.getColor(holder.itemView, com.google.android.material.R.attr.colorOnErrorContainer);\n        if (holder.itemView instanceof MaterialCardView) {\n            MaterialCardView cardView = (MaterialCardView) holder.itemView;\n            cardView.setCardBackgroundColor(background);\n        }\n        final TextView summaryView = (TextView) holder.findViewById(android.R.id.summary);\n        if (summaryView != null) {\n            summaryView.setTextColor(foreground);\n        }\n        final ImageView imageView = (ImageView)holder.findViewById(android.R.id.icon);\n        if (imageView != null) {\n            imageView.setImageTintList(ColorStateList.valueOf(foreground));\n        }\n    }\n}\n"
  },
  {
    "path": "libcore/ui/src/main/java/io/github/muntashirakon/text/style/ListSpan.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.text.style;\n\nimport android.graphics.Canvas;\nimport android.graphics.Paint;\nimport android.text.Layout;\nimport android.text.style.LeadingMarginSpan;\n\nimport java.util.Locale;\n\n/**\n * Create numeric or bulleted list by aligning all the lines in a paragraph.\n */\npublic class ListSpan implements LeadingMarginSpan {\n    private final int mLeadingGapWidth;\n    private final int mTrailingGapWidth;\n    private final String mText;\n\n    /**\n     * @param leadingGap  Leading gaps including the numeric digit(s).\n     * @param trailingGap Gaps to add after the numeric digits.\n     * @param index       Index number for a numeric list.\n     */\n    public ListSpan(int leadingGap, int trailingGap, int index, Locale locale) {\n        mLeadingGapWidth = leadingGap;\n        mTrailingGapWidth = trailingGap;\n        mText = String.format(locale, \"%d.\", index);\n    }\n\n    /**\n     * @param leadingGap  Leading gaps including the numeric digit(s).\n     * @param trailingGap Gaps to add after the numeric digits.\n     * @param index       Index number for a numeric list.\n     */\n    public ListSpan(int leadingGap, int trailingGap, int index) {\n        mLeadingGapWidth = leadingGap;\n        mTrailingGapWidth = trailingGap;\n        mText = String.format(Locale.getDefault(), \"%d.\", index);\n    }\n\n    /**\n     * @param leadingGap  Leading gaps including the numeric digit(s).\n     * @param trailingGap Gaps to add after the numeric digits.\n     * @param ch          Character for a bulleted list (preferably a bullet).\n     */\n    public ListSpan(int leadingGap, int trailingGap, char ch) {\n        mLeadingGapWidth = leadingGap;\n        mTrailingGapWidth = trailingGap;\n        mText = String.valueOf(ch);\n    }\n\n    @Override\n    public int getLeadingMargin(boolean first) {\n        return mLeadingGapWidth + mTrailingGapWidth;\n    }\n\n    @Override\n    public void drawLeadingMargin(Canvas c, Paint p, int x, int dir, int top, int baseline, int bottom, CharSequence text, int start, int end, boolean first, Layout l) {\n        if (first) {\n            Paint.Style lastStyle = p.getStyle();\n            p.setStyle(Paint.Style.FILL);\n            float width = p.measureText(mText);\n            c.drawText(mText, x * dir, bottom - p.descent(), p);\n            c.drawText(\"\", (mLeadingGapWidth + x - width / 2) * dir, bottom - p.descent(), p);\n            p.setStyle(lastStyle);\n        }\n    }\n}"
  },
  {
    "path": "libcore/ui/src/main/java/io/github/muntashirakon/util/AccessibilityUtils.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.util;\n\nimport android.annotation.SuppressLint;\nimport android.os.Build;\nimport android.os.Bundle;\nimport android.view.MenuItem;\nimport android.view.View;\nimport android.view.accessibility.AccessibilityNodeInfo;\nimport android.widget.TextView;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.appcompat.widget.PopupMenu;\nimport androidx.core.view.ViewCompat;\n\npublic final class AccessibilityUtils {\n    public static void requestParentAccessibilityFocus(@NonNull View view) {\n        requestAccessibilityFocus(view.getParentForAccessibility());\n    }\n\n    public static void requestParentAccessibilityFocus(@NonNull View view, long delayMillis) {\n        requestAccessibilityFocus(view.getParentForAccessibility(), delayMillis);\n    }\n\n    @SuppressLint(\"AccessibilityFocus\")\n    public static <T> void requestAccessibilityFocus(@Nullable T anyView) {\n        if (anyView instanceof View) {\n            View view = (View) anyView;\n            view.post(() -> view.performAccessibilityAction(AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS, null));\n        }\n    }\n\n    @SuppressLint(\"AccessibilityFocus\")\n    public static <T> void requestAccessibilityFocus(@Nullable T anyView, long delayMillis) {\n        if (anyView instanceof View) {\n            View view = (View) anyView;\n            view.postDelayed(() ->\n                    view.performAccessibilityAction(AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS, null), delayMillis);\n        }\n    }\n\n    public static void setAccessibilityHeading(@NonNull View view, boolean enable) {\n        if (view instanceof TextView) {\n            ViewCompat.setAccessibilityHeading(view, enable);\n            return;\n        }\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {\n            view.setAccessibilityDelegate(new View.AccessibilityDelegate() {\n                @Override\n                public void onInitializeAccessibilityNodeInfo(@NonNull View host, @NonNull AccessibilityNodeInfo info) {\n                    super.onInitializeAccessibilityNodeInfo(host, info);\n                    info.setHeading(enable && info.getContentDescription() != null);\n                }\n            });\n        }\n    }\n\n    public static void popupMenuToAccessibleOptions(@NonNull View view, @NonNull PopupMenu popupMenu) {\n        view.setAccessibilityDelegate(new View.AccessibilityDelegate() {\n            @Override\n            public void onInitializeAccessibilityNodeInfo(@NonNull View host, @NonNull AccessibilityNodeInfo info) {\n                super.onInitializeAccessibilityNodeInfo(host, info);\n                // Add each PopupMenu item as an AccessibilityAction\n                for (int i = 0; i < popupMenu.getMenu().size(); i++) {\n                    MenuItem item = popupMenu.getMenu().getItem(i);\n                    if (item.isVisible() && item.isEnabled()) {\n                        info.addAction(new AccessibilityNodeInfo.AccessibilityAction(\n                                item.getItemId(),\n                                item.getTitle()\n                        ));\n                    }\n                }\n            }\n\n            @Override\n            public boolean performAccessibilityAction(@NonNull View host, int action, Bundle args) {\n                MenuItem menuItem = popupMenu.getMenu().findItem(action);\n                if (menuItem != null) {\n                    // Invoke the corresponding PopupMenu action programmatically\n                    popupMenu.getMenu().performIdentifierAction(action, 0);\n                    return true;\n                }\n                return super.performAccessibilityAction(host, action, args);\n            }\n        });\n    }\n}\n"
  },
  {
    "path": "libcore/ui/src/main/java/io/github/muntashirakon/util/AdapterUtils.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.util;\n\nimport android.os.Looper;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.TextView;\n\nimport androidx.annotation.IntRange;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.collection.SimpleArrayMap;\nimport androidx.recyclerview.widget.DiffUtil;\nimport androidx.recyclerview.widget.RecyclerView;\n\nimport java.util.List;\nimport java.util.Objects;\n\npublic final class AdapterUtils {\n    public static final Object STUB = new Object();\n\n    private static class SimpleListDiffCallback<T> extends DiffUtil.Callback {\n        private final List<T> mOldList;\n        private final List<T> mNewList;\n        private final int mStartPosition;\n\n        private SimpleListDiffCallback(@NonNull List<T> oldList, @Nullable List<T> newList) {\n            mOldList = oldList;\n            mNewList = newList;\n            mStartPosition = 0;\n        }\n\n\n        private SimpleListDiffCallback(@NonNull List<T> oldList, @Nullable List<T> newList, int startPosition) {\n            mOldList = oldList;\n            mNewList = newList;\n            mStartPosition = startPosition;\n        }\n\n        @Override\n        public int getOldListSize() {\n            return mOldList.size();\n        }\n\n        @Override\n        public int getNewListSize() {\n            return (mNewList != null ? mNewList.size() : 0) + mStartPosition;\n        }\n\n        @Override\n        public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) {\n            if (newItemPosition < mStartPosition) {\n                // Both values are null\n                return true;\n            }\n            if (mNewList == null) {\n                return false;\n            }\n            return Objects.equals(mOldList.get(oldItemPosition), mNewList.get(newItemPosition - mStartPosition));\n        }\n\n        @Override\n        public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) {\n            if (newItemPosition < mStartPosition) {\n                // Both values are null\n                return true;\n            }\n            return false;\n        }\n\n        @Nullable\n        @Override\n        public Object getChangePayload(int oldItemPosition, int newItemPosition) {\n            return AdapterUtils.STUB;\n        }\n    }\n\n    private static class SimpleArrayMapDiffCallback<K, V> extends DiffUtil.Callback {\n        private final SimpleArrayMap<K, V> mOldList;\n        private final SimpleArrayMap<K, V> mNewList;\n\n        private SimpleArrayMapDiffCallback(@NonNull SimpleArrayMap<K, V> oldList, @Nullable SimpleArrayMap<K, V> newList) {\n            mOldList = oldList;\n            mNewList = newList;\n        }\n\n        @Override\n        public int getOldListSize() {\n            return mOldList.size();\n        }\n\n        @Override\n        public int getNewListSize() {\n            return mNewList != null ? mNewList.size() : 0;\n        }\n\n        @Override\n        public boolean areItemsTheSame(int oldItemPosition, int newItemPosition) {\n            if (mNewList == null) {\n                return false;\n            }\n            return Objects.equals(mOldList.keyAt(oldItemPosition), mNewList.keyAt(newItemPosition));\n        }\n\n        @Override\n        public boolean areContentsTheSame(int oldItemPosition, int newItemPosition) {\n            return false;\n        }\n\n        @Nullable\n        @Override\n        public Object getChangePayload(int oldItemPosition, int newItemPosition) {\n            return AdapterUtils.STUB;\n        }\n    }\n\n    public static <T, V> void notifyDataSetChanged(@NonNull RecyclerView.Adapter<?> adapter,\n                                                   @NonNull SimpleArrayMap<T, V> baseList,\n                                                   @Nullable SimpleArrayMap<T, V> newList) {\n        DiffUtil.DiffResult result = DiffUtil.calculateDiff(new SimpleArrayMapDiffCallback<>(baseList, newList));\n        baseList.clear();\n        if (newList != null) {\n            baseList.putAll(newList);\n        }\n        result.dispatchUpdatesTo(adapter);\n    }\n\n    public static <T> void notifyDataSetChanged(@NonNull RecyclerView.Adapter<?> adapter,\n                                                @NonNull List<T> baseList,\n                                                @Nullable List<T> newList) {\n        notifyDataSetChanged(adapter, 0, baseList, newList);\n    }\n\n    public static <T> void notifyDataSetChanged(@NonNull RecyclerView.Adapter<?> adapter,\n                                                @IntRange(from = 0) int startIndex,\n                                                @NonNull List<T> baseList,\n                                                @Nullable List<T> newList) {\n        // base list always has placeholders < startIndex, newList do not. So, it is necessary to\n        // offset the placeholders during comparison.\n        DiffUtil.DiffResult result = DiffUtil.calculateDiff(new SimpleListDiffCallback<>(baseList, newList, startIndex));\n        baseList.clear();\n        // Add |startIndex| no. of null as placeholders\n        for (int i = 0; i < startIndex; ++i) {\n            baseList.add(null);\n        }\n        if (newList != null) {\n            baseList.addAll(newList);\n        }\n        // When dispatching updates, null items are never updated in partial update.\n        result.dispatchUpdatesTo(adapter);\n    }\n\n    public static void notifyDataSetChanged(@NonNull RecyclerView.Adapter<?> adapter, int previousCount,\n                                            int currentCount) {\n        if (Thread.currentThread() != Looper.getMainLooper().getThread()) {\n            // Main thread is required\n            throw new RuntimeException(\"Must be called on the UI thread\");\n        }\n        if (previousCount > currentCount) {\n            // Some values are removed\n            if (currentCount > 0) {\n                adapter.notifyItemRangeChanged(0, currentCount, STUB);\n            }\n            adapter.notifyItemRangeRemoved(currentCount + 0, previousCount - currentCount);\n        } else if (previousCount < currentCount) {\n            // Some values are added\n            if (previousCount > 0) {\n                adapter.notifyItemRangeChanged(0, previousCount, STUB);\n            }\n            adapter.notifyItemRangeInserted(previousCount + 0, currentCount - previousCount);\n        } else if (previousCount > 0) {\n            // No values are added or removed\n            adapter.notifyItemRangeChanged(0, previousCount, STUB);\n        }\n    }\n\n    public static void setVisible(@NonNull View v, boolean visible) {\n        if (visible && v.getVisibility() != View.VISIBLE) {\n            v.setVisibility(View.VISIBLE);\n        } else if (!visible && v.getVisibility() != View.GONE) {\n            v.setVisibility(View.GONE);\n        }\n    }\n\n    public static <VH extends RecyclerView.ViewHolder> void fixTextSelectionInView(@NonNull VH holder) {\n        fixTextSelectionInView(holder.itemView);\n    }\n\n    private static void fixTextSelectionInView(@Nullable View view) {\n        if (view instanceof TextView) {\n            TextView tv = (TextView) view;\n            // Apply the enabled toggle workaround\n            tv.setEnabled(false);\n            tv.setEnabled(true);\n        } else if (view instanceof ViewGroup) {\n            // If it's a ViewGroup, recurse into children\n            ViewGroup vg = (ViewGroup) view;\n            for (int i = 0; i < vg.getChildCount(); i++) {\n                fixTextSelectionInView(vg.getChildAt(i));\n            }\n        }\n    }\n}"
  },
  {
    "path": "libcore/ui/src/main/java/io/github/muntashirakon/util/LocalizedString.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.util;\n\nimport android.content.Context;\n\nimport androidx.annotation.NonNull;\n\npublic interface LocalizedString {\n    @NonNull\n    CharSequence toLocalizedString(@NonNull Context context);\n}\n"
  },
  {
    "path": "libcore/ui/src/main/java/io/github/muntashirakon/util/MotionUtils.java",
    "content": "// SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-or-later\n\npackage io.github.muntashirakon.util;\n\nimport android.animation.TimeInterpolator;\nimport android.annotation.SuppressLint;\nimport android.content.Context;\nimport android.util.TypedValue;\n\nimport androidx.annotation.AttrRes;\nimport androidx.annotation.NonNull;\nimport androidx.core.graphics.PathParser;\nimport androidx.core.view.animation.PathInterpolatorCompat;\n\nimport com.google.android.material.resources.MaterialAttributes;\n\n/**\n * A utility class for motion system functions.\n */\n// Copyright 2020 The Android Open Source Project\npublic class MotionUtils {\n    // Constants corresponding to motionEasing* theme attr values.\n    private static final String EASING_TYPE_CUBIC_BEZIER = \"cubic-bezier\";\n    private static final String EASING_TYPE_PATH = \"path\";\n    private static final String EASING_TYPE_FORMAT_START = \"(\";\n    private static final String EASING_TYPE_FORMAT_END = \")\";\n\n    private MotionUtils() {\n    }\n\n    @SuppressLint(\"RestrictedApi\")\n    public static int resolveThemeDuration(\n            @NonNull Context context, @AttrRes int attrResId, int defaultDuration) {\n        return MaterialAttributes.resolveInteger(context, attrResId, defaultDuration);\n    }\n\n    @NonNull\n    public static TimeInterpolator resolveThemeInterpolator(\n            @NonNull Context context,\n            @AttrRes int attrResId,\n            @NonNull TimeInterpolator defaultInterpolator) {\n        TypedValue easingValue = new TypedValue();\n        if (context.getTheme().resolveAttribute(attrResId, easingValue, true)) {\n            if (easingValue.type != TypedValue.TYPE_STRING) {\n                throw new IllegalArgumentException(\"Motion easing theme attribute must be a string\");\n            }\n\n            String easingString = String.valueOf(easingValue.string);\n\n            if (isEasingType(easingString, EASING_TYPE_CUBIC_BEZIER)) {\n                String controlPointsString = getEasingContent(easingString, EASING_TYPE_CUBIC_BEZIER);\n                String[] controlPoints = controlPointsString.split(\",\");\n                if (controlPoints.length != 4) {\n                    throw new IllegalArgumentException(\n                            \"Motion easing theme attribute must have 4 control points if using bezier curve\"\n                                    + \" format; instead got: \"\n                                    + controlPoints.length);\n                }\n\n                float controlX1 = getControlPoint(controlPoints, 0);\n                float controlY1 = getControlPoint(controlPoints, 1);\n                float controlX2 = getControlPoint(controlPoints, 2);\n                float controlY2 = getControlPoint(controlPoints, 3);\n                return PathInterpolatorCompat.create(controlX1, controlY1, controlX2, controlY2);\n            } else if (isEasingType(easingString, EASING_TYPE_PATH)) {\n                String path = getEasingContent(easingString, EASING_TYPE_PATH);\n                return PathInterpolatorCompat.create(PathParser.createPathFromPathData(path));\n            } else {\n                throw new IllegalArgumentException(\"Invalid motion easing type: \" + easingString);\n            }\n        }\n        return defaultInterpolator;\n    }\n\n    private static boolean isEasingType(String easingString, String easingType) {\n        return easingString.startsWith(easingType + EASING_TYPE_FORMAT_START)\n                && easingString.endsWith(EASING_TYPE_FORMAT_END);\n    }\n\n    private static String getEasingContent(String easingString, String easingType) {\n        return easingString.substring(\n                easingType.length() + EASING_TYPE_FORMAT_START.length(),\n                easingString.length() - EASING_TYPE_FORMAT_END.length());\n    }\n\n    private static float getControlPoint(String[] controlPoints, int index) {\n        float controlPoint = Float.parseFloat(controlPoints[index]);\n        if (controlPoint < 0 || controlPoint > 1) {\n            throw new IllegalArgumentException(\n                    \"Motion easing control point value must be between 0 and 1; instead got: \"\n                            + controlPoint);\n        }\n        return controlPoint;\n    }\n}"
  },
  {
    "path": "libcore/ui/src/main/java/io/github/muntashirakon/util/ParcelUtils.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.util;\n\nimport android.os.Parcel;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.collection.ArrayMap;\nimport androidx.collection.ArraySet;\n\nimport java.util.ArrayList;\nimport java.util.HashMap;\nimport java.util.Map;\n\npublic class ParcelUtils {\n    /**\n     * Write an array set to the parcel.\n     *\n     * @param val The array set to write.\n     */\n    public static void writeArraySet(@Nullable ArraySet<?> val, @NonNull Parcel dest) {\n        final int size = (val != null) ? val.size() : -1;\n        dest.writeInt(size);\n        for (int i = 0; i < size; i++) {\n            dest.writeValue(val.valueAt(i));\n        }\n    }\n\n    /**\n     * Reads an array set.\n     *\n     * @param loader The class loader to use.\n     */\n    @Nullable\n    public static ArraySet<?> readArraySet(@NonNull Parcel in, @Nullable ClassLoader loader) {\n        final int size = in.readInt();\n        if (size < 0) {\n            return null;\n        }\n        ArraySet<Object> result = new ArraySet<>(size);\n        for (int i = 0; i < size; i++) {\n            Object value = in.readValue(loader);\n            result.add(value);\n        }\n        return result;\n    }\n\n    public static void writeMap(@NonNull Map<?, ?> map, @NonNull Parcel parcel) {\n        parcel.writeInt(map.size());\n        for (Map.Entry<?, ?> e : map.entrySet()) {\n            parcel.writeValue(e.getKey());\n            parcel.writeValue(e.getValue());\n        }\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    @NonNull\n    public static <K, V> Map<K, V> readMap(@NonNull Parcel parcel, @Nullable ClassLoader keyCl, @Nullable ClassLoader valCl) {\n        int size = parcel.readInt();\n        Map<K, V> map = new HashMap<>(size);\n        for (int i = 0; i < size; i++) {\n            map.put((K) parcel.readValue(keyCl), (V) parcel.readValue(valCl));\n        }\n        return map;\n    }\n\n    @SuppressWarnings(\"unchecked\")\n    @NonNull\n    public static <K, V> ArrayMap<K, V> readArrayMap(@NonNull Parcel parcel, @Nullable ClassLoader keyCl, @Nullable ClassLoader valCl) {\n        int size = parcel.readInt();\n        ArrayMap<K, V> map = new ArrayMap<>(size);\n        for (int i = 0; i < size; i++) {\n            map.put((K) parcel.readValue(keyCl), (V) parcel.readValue(valCl));\n        }\n        return map;\n    }\n\n    public static void writeArrayList(@Nullable ArrayList<?> val, @NonNull Parcel dest) {\n        final int size = (val != null) ? val.size() : -1;\n        dest.writeInt(size);\n        for (int i = 0; i < size; i++) {\n            dest.writeValue(val.get(i));\n        }\n    }\n\n\n    @Nullable\n    public static <T> ArrayList<T> readArrayList(@NonNull Parcel in, @Nullable ClassLoader loader) {\n        final int size = in.readInt();\n        if (size < 0) {\n            return null;\n        }\n        ArrayList<T> result = new ArrayList<>(size);\n        for (int i = 0; i < size; i++) {\n            Object value = in.readValue(loader);\n            //noinspection unchecked\n            result.add((T) value);\n        }\n        return result;\n    }\n}\n"
  },
  {
    "path": "libcore/ui/src/main/java/io/github/muntashirakon/util/UiUtils.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.util;\n\nimport android.annotation.SuppressLint;\nimport android.content.Context;\nimport android.content.res.Configuration;\nimport android.content.res.Resources;\nimport android.graphics.Color;\nimport android.graphics.Rect;\nimport android.graphics.drawable.Drawable;\nimport android.os.Build;\nimport android.text.Spannable;\nimport android.text.SpannableString;\nimport android.text.SpannableStringBuilder;\nimport android.text.Spanned;\nimport android.text.style.LeadingMarginSpan;\nimport android.util.TypedValue;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.view.Window;\nimport android.view.WindowInsets;\nimport android.view.WindowManager;\nimport android.view.inputmethod.InputMethodManager;\n\nimport androidx.annotation.AttrRes;\nimport androidx.annotation.Dimension;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.Px;\nimport androidx.annotation.StyleRes;\nimport androidx.appcompat.app.AppCompatDelegate;\nimport androidx.core.content.ContextCompat;\nimport androidx.core.view.ViewCompat;\nimport androidx.core.view.WindowInsetsCompat;\n\nimport com.google.android.material.internal.ViewUtils;\n\nimport java.util.Locale;\n\nimport io.github.muntashirakon.text.style.ListSpan;\n\npublic final class UiUtils {\n    private UiUtils() {\n    }\n\n    @Px\n    public static int dpToPx(@NonNull Context context, @Dimension(unit = Dimension.DP) int dp) {\n        return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp,\n                context.getResources().getDisplayMetrics());\n    }\n\n    @Px\n    public static int dpToPx(@NonNull Context context, @Dimension(unit = Dimension.DP) float dp) {\n        return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp, context.getResources().getDisplayMetrics());\n    }\n\n    @Px\n    public static int spToPx(@NonNull Context context, @Dimension(unit = Dimension.SP) float sp) {\n        return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, sp, context.getResources().getDisplayMetrics());\n    }\n\n    @Dimension(unit = Dimension.DP)\n    public static int pxToDp(@NonNull Context context, @Px int pixel) {\n        return (int) ((float) pixel / context.getResources().getDisplayMetrics().density);\n    }\n\n    @StyleRes\n    public static int getStyle(@NonNull Context context, @AttrRes int resId) {\n        TypedValue typedValue = new TypedValue();\n        context.getTheme().resolveAttribute(resId, typedValue, true);\n        return typedValue.data;\n    }\n\n    @Nullable\n    public static Drawable getDrawable(@NonNull Context context, @AttrRes int resId) {\n        TypedValue typedValue = new TypedValue();\n        context.getTheme().resolveAttribute(resId, typedValue, true);\n        return ContextCompat.getDrawable(context, typedValue.resourceId);\n    }\n\n    public static int getColumnCount(@NonNull View v, @Dimension(unit = Dimension.DP) int columnWidth, int defaultCount) {\n        int width = v.getWidth();\n        if (width == 0) {\n            return defaultCount;\n        }\n        int widthDp = pxToDp(v.getContext(), width);\n        return (int) (widthDp / columnWidth + 0.5);\n    }\n\n    public static void showKeyboard(@NonNull View v) {\n        InputMethodManager imm = (InputMethodManager) v.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);\n        imm.showSoftInput(v, InputMethodManager.SHOW_IMPLICIT);\n    }\n\n    public static void hideKeyboard(@NonNull View v) {\n        InputMethodManager imm = (InputMethodManager) v.getContext().getSystemService(Context.INPUT_METHOD_SERVICE);\n        imm.hideSoftInputFromWindow(v.getWindowToken(), 0);\n    }\n\n    /**\n     * Get a well-formatted list from the given list of CharSequences. Example:\n     * <pre>\n     * [\"A single-line list-item\", \"A multi-line\\nlist-item\"]\n     * </pre>\n     * The above will be translated as follows:\n     * <pre>\n     * 1  A single-line list-item\n     * 2  A multi-line\n     *    list-item\n     * </pre>\n     *\n     * @param List List of CharSequences\n     * @return Formatted list\n     */\n    @NonNull\n    public static <T extends CharSequence> Spanned getOrderedList(@NonNull Iterable<T> List) {\n        SpannableStringBuilder spannableStringBuilder = new SpannableStringBuilder();\n        Locale locale = Locale.getDefault();\n        Spannable spannable;\n        int j = 0;\n        for (CharSequence charSequence : List) {\n            int len = charSequence.length();\n            spannable = new SpannableString(charSequence);\n            int finish = spannable.toString().indexOf(\"\\n\");\n            spannable.setSpan(new ListSpan(40, 30, ++j, locale), 0, (finish == -1 ? len : finish),\n                    Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);\n            if (finish != -1) {\n                spannable.setSpan(new LeadingMarginSpan.Standard(40 + 30), finish + 1, len,\n                        Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);\n            }\n            spannableStringBuilder.append(spannable).append(\"\\n\");\n        }\n        return spannableStringBuilder;\n    }\n\n    /**\n     * Wrapper around {@link androidx.core.view.OnApplyWindowInsetsListener} which also passes the\n     * initial padding/margin set on the view. Used with {@link #doOnApplyWindowInsets(View,\n     * OnApplyWindowInsetsListener)}.\n     */\n    public interface OnApplyWindowInsetsListener {\n\n        /**\n         * When {@link View#setOnApplyWindowInsetsListener(View.OnApplyWindowInsetsListener) set} on a\n         * View, this listener method will be called instead of the view's own {@link\n         * View#onApplyWindowInsets(WindowInsets)} method. The {@code initial*} is the view's\n         * original padding/margin which can be updated and will be applied to the view automatically. This\n         * method should return a new {@link WindowInsetsCompat} with any insets consumed.\n         */\n        WindowInsetsCompat onApplyWindowInsets(View view, WindowInsetsCompat insets, @NonNull Rect initialPadding,\n                                               @Nullable Rect initialMargin);\n    }\n\n    public static void applyWindowInsetsAsPaddingNoTop(View v) {\n        applyWindowInsetsAsPadding(v, false, true, true, true);\n    }\n\n    public static void applyWindowInsetsNone(View v) {\n        applyWindowInsetsAsPadding(v, false, false, false, false);\n    }\n\n    public static void applyWindowInsetsAsPadding(View v, boolean applyVertical, boolean applyHorizontal) {\n        applyWindowInsetsAsPadding(v, applyVertical, applyVertical, applyHorizontal, applyHorizontal);\n    }\n\n    @SuppressWarnings(\"deprecation\")\n    public static void applyWindowInsetsAsPadding(View v, boolean applyTop, boolean applyBottom, boolean applyStart, boolean applyEnd) {\n        doOnApplyWindowInsets(v, (view, insets, initialPadding, initialMargin) -> {\n            if (!ViewCompat.getFitsSystemWindows(view)) {\n                // Do not add padding if fitsSystemWindows is false\n                return insets;\n            }\n            int systemWindowInsetTop = insets.getSystemWindowInsetTop();\n            int systemWindowInsetBottom = insets.getSystemWindowInsetBottom();\n            int top = initialPadding.top + (applyTop ? systemWindowInsetTop : 0);\n            int bottom = initialPadding.bottom + (applyBottom ? systemWindowInsetBottom : 0);\n            boolean isRtl = ViewCompat.getLayoutDirection(view) == ViewCompat.LAYOUT_DIRECTION_RTL;\n            int systemWindowInsetLeft = insets.getSystemWindowInsetLeft();\n            int systemWindowInsetRight = insets.getSystemWindowInsetRight();\n            int start;\n            int end;\n            if (isRtl) {\n                start = initialPadding.right + (applyStart ? systemWindowInsetRight : 0);\n                end = initialPadding.left + (applyEnd ? systemWindowInsetLeft : 0);\n            } else {\n                start = initialPadding.left + (applyStart ? systemWindowInsetLeft : 0);\n                end = initialPadding.right + (applyEnd ? systemWindowInsetRight : 0);\n            }\n            ViewCompat.setPaddingRelative(view, start, top, end, bottom);\n            return insets;\n        });\n    }\n\n    public static void applyWindowInsetsAsMargin(View v) {\n        applyWindowInsetsAsMargin(v, true, true);\n    }\n\n    @SuppressWarnings(\"deprecation\")\n    public static void applyWindowInsetsAsMargin(View v, boolean bottomMargin, boolean topMargin) {\n        doOnApplyWindowInsets(v, (view, insets, initialPadding, initialMargin) -> {\n            if (initialMargin == null || !ViewCompat.getFitsSystemWindows(view)) {\n                // Do not add padding if fitsSystemWindows is false\n                return insets;\n            }\n            ViewGroup.LayoutParams layoutParams = view.getLayoutParams();\n            if (!(layoutParams instanceof ViewGroup.MarginLayoutParams)) {\n                return insets;\n            }\n            ViewGroup.MarginLayoutParams marginLayoutParams = (ViewGroup.MarginLayoutParams) layoutParams;\n\n            if (topMargin) {\n                marginLayoutParams.topMargin = initialMargin.top + insets.getSystemWindowInsetTop();\n            }\n            if (bottomMargin) {\n                marginLayoutParams.bottomMargin = initialMargin.bottom + insets.getSystemWindowInsetBottom();\n            }\n            marginLayoutParams.leftMargin = initialMargin.left + insets.getSystemWindowInsetLeft();\n            marginLayoutParams.rightMargin = initialMargin.right + insets.getSystemWindowInsetRight();\n\n            view.setLayoutParams(marginLayoutParams);\n            return insets;\n        });\n    }\n\n    /**\n     * Wrapper around {@link androidx.core.view.OnApplyWindowInsetsListener} that records the initial\n     * margin of the view and requests that insets are applied when attached.\n     */\n    @SuppressLint(\"RestrictedApi\")\n    public static void doOnApplyWindowInsets(@NonNull View view, @NonNull OnApplyWindowInsetsListener listener) {\n        ViewGroup.LayoutParams layoutParams = view.getLayoutParams();\n        Rect initialMargins;\n        if (layoutParams instanceof ViewGroup.MarginLayoutParams) {\n            ViewGroup.MarginLayoutParams marginLayoutParams = (ViewGroup.MarginLayoutParams) layoutParams;\n            // Create a snapshot of the view's margin state.\n            initialMargins = new Rect(marginLayoutParams.leftMargin, marginLayoutParams.topMargin,\n                    marginLayoutParams.rightMargin, marginLayoutParams.bottomMargin);\n        } else initialMargins = null;\n        Rect initialPadding = new Rect(view.getPaddingLeft(), view.getPaddingTop(), view.getPaddingRight(),\n                view.getPaddingBottom());\n        // Set an actual OnApplyWindowInsetsListener which proxies to the given callback, also passing\n        // in the original margin state.\n        ViewCompat.setOnApplyWindowInsetsListener(view, (view1, insets) ->\n                listener.onApplyWindowInsets(view1, insets, initialPadding, initialMargins));\n        // Request some insets\n        ViewUtils.requestApplyInsetsWhenAttached(view);\n    }\n\n    public static boolean isDarkMode(@NonNull Context context) {\n        Configuration conf = context.getResources().getConfiguration();\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {\n            return conf.isNightModeActive();\n        }\n        return (conf.uiMode & Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES;\n    }\n\n    @SuppressWarnings(\"deprecation\")\n    public static boolean isDarkMode() {\n        switch (AppCompatDelegate.getDefaultNightMode()) {\n            case AppCompatDelegate.MODE_NIGHT_YES:\n                return true;\n            default:\n            case AppCompatDelegate.MODE_NIGHT_NO:\n                return false;\n            case AppCompatDelegate.MODE_NIGHT_FOLLOW_SYSTEM:\n            case AppCompatDelegate.MODE_NIGHT_AUTO_BATTERY:\n            case AppCompatDelegate.MODE_NIGHT_UNSPECIFIED:\n            case AppCompatDelegate.MODE_NIGHT_AUTO_TIME:\n                return isDarkModeOnSystem();\n        }\n    }\n\n    public static boolean isDarkModeOnSystem() {\n        Configuration conf = Resources.getSystem().getConfiguration();\n        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {\n            return conf.isNightModeActive();\n        }\n        return (conf.uiMode & Configuration.UI_MODE_NIGHT_MASK) == Configuration.UI_MODE_NIGHT_YES;\n    }\n\n    /**\n     * Fixes focus by forcing Android to focus on the current view and reset\n     */\n    public static void fixFocus(@NonNull View view) {\n        if (!view.hasFocus()) {\n            boolean focusable = view.isFocusable();\n            boolean focusableInTouch = view.isFocusableInTouchMode();\n            if (!focusable) {\n                view.setFocusable(true);\n            }\n            if (!focusableInTouch) {\n                view.setFocusableInTouchMode(true);\n            }\n            view.requestFocus();\n            view.post(view::clearFocus);\n            if (!focusable) {\n                view.setFocusable(false);\n            }\n            if (!focusableInTouch) {\n                view.setFocusableInTouchMode(false);\n            }\n        }\n    }\n\n    @SuppressWarnings(\"deprecation\")\n    public static void setSystemBarStyle(@NonNull Window window, boolean needLightStatusBar) {\n        window.getDecorView().setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE\n                | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION\n                | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN);\n\n        if (!isDarkMode()) {\n            window.getDecorView().setSystemUiVisibility(window.getDecorView().getSystemUiVisibility()\n                    | WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);\n\n            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && needLightStatusBar) {\n                window.getDecorView().setSystemUiVisibility(window.getDecorView().getSystemUiVisibility()\n                        | View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR);\n            }\n            if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {\n                int windowInsetBottom = window.getDecorView().getRootWindowInsets().getSystemWindowInsetBottom();\n                if (windowInsetBottom >= Resources.getSystem().getDisplayMetrics().density * 40) {\n                    window.getDecorView().setSystemUiVisibility(window.getDecorView().getSystemUiVisibility()\n                            | View.SYSTEM_UI_FLAG_LIGHT_NAVIGATION_BAR);\n                }\n            }\n        }\n        setSystemBarTransparent(window);\n    }\n\n    @SuppressWarnings(\"deprecation\")\n    private static void setSystemBarTransparent(@NonNull Window window) {\n        window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);\n        window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);\n        window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);\n        window.setStatusBarColor(Color.TRANSPARENT);\n        window.setNavigationBarColor(Color.TRANSPARENT);\n    }\n}\n"
  },
  {
    "path": "libcore/ui/src/main/java/io/github/muntashirakon/view/AutoCompleteTextViewCompat.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.view;\n\nimport android.annotation.SuppressLint;\nimport android.graphics.drawable.Drawable;\nimport android.widget.AutoCompleteTextView;\nimport android.widget.ListPopupWindow;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport com.google.android.material.textfield.MaterialAutoCompleteTextView;\n\nimport java.lang.reflect.Field;\n\npublic final class AutoCompleteTextViewCompat {\n    @SuppressWarnings(\"JavaReflectionMemberAccess\")\n    @SuppressLint(\"DiscouragedPrivateApi\")\n    public static void setListSelector(@NonNull AutoCompleteTextView view, @Nullable Drawable listSelector) {\n        try {\n            ListPopupWindow popupWindow;\n            Field mPopup = AutoCompleteTextView.class.getDeclaredField(\"mPopup\");\n            mPopup.setAccessible(true);\n            popupWindow = (ListPopupWindow) mPopup.get(view);\n            if (popupWindow != null) {\n                popupWindow.setListSelector(listSelector);\n            }\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n    }\n\n    public static void setListSelectorMaterial(@NonNull MaterialAutoCompleteTextView view, @Nullable Drawable listSelector) {\n        setListSelector(view, listSelector);\n        try {\n            androidx.appcompat.widget.ListPopupWindow popupWindow;\n            Field mPopup = MaterialAutoCompleteTextView.class.getDeclaredField(\"modalListPopup\");\n            mPopup.setAccessible(true);\n            popupWindow = (androidx.appcompat.widget.ListPopupWindow) mPopup.get(view);\n            if (popupWindow != null) {\n                popupWindow.setListSelector(listSelector);\n            }\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n    }\n}\n"
  },
  {
    "path": "libcore/ui/src/main/java/io/github/muntashirakon/view/AutoFitGridLayoutManager.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.view;\n\nimport android.content.Context;\n\nimport androidx.annotation.Px;\nimport androidx.recyclerview.widget.GridLayoutManager;\nimport androidx.recyclerview.widget.RecyclerView;\n\n// Source: https://stackoverflow.com/a/55487382\n// Copyright 2019 Vishal Nagvadiya\npublic class AutoFitGridLayoutManager extends GridLayoutManager {\n    @Px\n    private int mColumnWidth;\n    private boolean mColumnWidthChanged = true;\n\n    public AutoFitGridLayoutManager(Context context, @Px int columnWidth) {\n        super(context, 1);\n        setColumnWidth(columnWidth);\n    }\n\n\n    public void setColumnWidth(@Px int newColumnWidth) {\n        if (newColumnWidth > 0 && newColumnWidth != mColumnWidth) {\n            mColumnWidth = newColumnWidth;\n            mColumnWidthChanged = true;\n        }\n    }\n\n    @Override\n    public void onLayoutChildren(RecyclerView.Recycler recycler, RecyclerView.State state) {\n        if (mColumnWidthChanged && mColumnWidth > 0) {\n            int totalSpace;\n            if (getOrientation() == VERTICAL) {\n                totalSpace = getWidth() - getPaddingRight() - getPaddingLeft();\n            } else {\n                totalSpace = getHeight() - getPaddingTop() - getPaddingBottom();\n            }\n            int spanCount = Math.max(1, totalSpace / mColumnWidth);\n            setSpanCount(spanCount);\n            mColumnWidthChanged = false;\n        }\n        super.onLayoutChildren(recycler, state);\n    }\n}\n"
  },
  {
    "path": "libcore/ui/src/main/java/io/github/muntashirakon/view/ProgressIndicatorCompat.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.view;\n\nimport android.view.View;\n\nimport androidx.annotation.Nullable;\n\nimport com.google.android.material.progressindicator.BaseProgressIndicator;\n\npublic final class ProgressIndicatorCompat {\n    public static <T extends BaseProgressIndicator<?>> void setVisibility(@Nullable T progressIndicator, boolean visible) {\n        if (progressIndicator == null) {\n            return;\n        }\n        if (visible) {\n            progressIndicator.show();\n        } else {\n            progressIndicator.hide();\n            progressIndicator.setVisibility(View.GONE);\n        }\n    }\n}\n"
  },
  {
    "path": "libcore/ui/src/main/java/io/github/muntashirakon/view/TextInputLayoutCompat.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.view;\n\nimport android.view.Gravity;\nimport android.widget.EditText;\nimport android.widget.FrameLayout;\nimport android.widget.ImageView;\n\nimport androidx.annotation.NonNull;\nimport androidx.appcompat.widget.AppCompatImageButton;\n\nimport com.google.android.material.R;\nimport com.google.android.material.textfield.TextInputEditText;\nimport com.google.android.material.textfield.TextInputLayout;\n\n// TODO: 26/6/23 Make it a full replacement for TextInputLayout which is purposefully made for devs to suffer\npublic final class TextInputLayoutCompat {\n    public static TextInputLayout fromTextInputEditText(@NonNull TextInputEditText editText) {\n        return (TextInputLayout) editText.getParent().getParent();\n    }\n\n    public static void fixEndIcon(@NonNull TextInputLayout layout) {\n        EditText editText = layout.getEditText();\n        if (editText == null) {\n            // Invalid\n            return;\n        }\n        layout.post(() -> {\n            AppCompatImageButton endIconView = layout.findViewById(R.id.text_input_end_icon);\n            int endIconSize = layout.getEndIconMinSize();\n            int width = editText.getMinimumHeight(); // For consistency\n            int newHeight = endIconSize > 0 ? endIconSize : width;\n            int newWidth = Math.max(width, newHeight);\n            // AppCompatImageButton errorIconView = layout.findViewById(R.id.text_input_error_icon);\n            FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(newWidth, newHeight);\n            layoutParams.gravity = Gravity.CENTER_VERTICAL | Gravity.END;\n            endIconView.setLayoutParams(layoutParams);\n            endIconView.setScaleType(ImageView.ScaleType.CENTER_INSIDE);\n        });\n    }\n}\n"
  },
  {
    "path": "libcore/ui/src/main/java/io/github/muntashirakon/widget/AlwaysFocusedCheckedTextView.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.widget;\n\nimport android.content.Context;\nimport android.graphics.Rect;\nimport android.util.AttributeSet;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.appcompat.widget.AppCompatCheckedTextView;\n\n/**\n * Same as {@link AppCompatCheckedTextView} except that it's always on focus which fixes issues related to marquee text.\n */\npublic class AlwaysFocusedCheckedTextView extends AppCompatCheckedTextView {\n    public AlwaysFocusedCheckedTextView(@NonNull Context context) {\n        super(context);\n    }\n\n    public AlwaysFocusedCheckedTextView(@NonNull Context context, @Nullable AttributeSet attrs) {\n        super(context, attrs);\n    }\n\n    public AlwaysFocusedCheckedTextView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {\n        super(context, attrs, defStyleAttr);\n    }\n\n    @Override\n    protected void onFocusChanged(boolean focused, int direction, Rect previouslyFocusedRect) {\n        if (focused) {\n            super.onFocusChanged(true, direction, previouslyFocusedRect);\n        }\n    }\n\n    @Override\n    public void onWindowFocusChanged(boolean hasWindowFocus) {\n        if (hasWindowFocus) {\n            super.onWindowFocusChanged(true);\n        }\n    }\n\n    @Override\n    public boolean isFocused() {\n        return true;\n    }\n}\n"
  },
  {
    "path": "libcore/ui/src/main/java/io/github/muntashirakon/widget/AppBarLayout.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.widget;\n\nimport android.annotation.SuppressLint;\nimport android.content.Context;\nimport android.util.AttributeSet;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.core.view.ViewCompat;\n\nimport com.google.android.material.internal.ViewUtils;\n\npublic class AppBarLayout extends com.google.android.material.appbar.AppBarLayout {\n    public AppBarLayout(@NonNull Context context) {\n        this(context, null);\n    }\n\n    public AppBarLayout(@NonNull Context context, @Nullable AttributeSet attrs) {\n        this(context, attrs, com.google.android.material.R.attr.appBarLayoutStyle);\n    }\n\n    @SuppressWarnings(\"deprecation\")\n    @SuppressLint(\"RestrictedApi\")\n    public AppBarLayout(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {\n        super(context, attrs, defStyleAttr);\n        ViewUtils.doOnApplyWindowInsets(this, (view, insets, initialPadding) -> {\n            if (!ViewCompat.getFitsSystemWindows(view)) {\n                return insets;\n            }\n            initialPadding.top += insets.getSystemWindowInsetTop();\n            boolean isRtl = ViewCompat.getLayoutDirection(view) == ViewCompat.LAYOUT_DIRECTION_RTL;\n            int systemWindowInsetLeft = insets.getSystemWindowInsetLeft();\n            int systemWindowInsetRight = insets.getSystemWindowInsetRight();\n            initialPadding.start += isRtl ? systemWindowInsetRight : systemWindowInsetLeft;\n            initialPadding.end += isRtl ? systemWindowInsetLeft : systemWindowInsetRight;\n            initialPadding.applyToView(view);\n            return insets;\n        });\n    }\n}\n"
  },
  {
    "path": "libcore/ui/src/main/java/io/github/muntashirakon/widget/CheckBox.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.widget;\n\nimport android.content.Context;\nimport android.util.AttributeSet;\n\nimport com.google.android.material.checkbox.MaterialCheckBox;\n\npublic class CheckBox extends MaterialCheckBox {\n    private OnCheckedChangeListener mListener;\n\n    public CheckBox(final Context context) {\n        super(context);\n    }\n\n    public CheckBox(final Context context, final AttributeSet attrs) {\n        super(context, attrs);\n    }\n\n    public CheckBox(final Context context, final AttributeSet attrs, final int defStyleAttr) {\n        super(context, attrs, defStyleAttr);\n    }\n\n    @Override\n    public void setOnCheckedChangeListener(final OnCheckedChangeListener listener) {\n        mListener = listener;\n        super.setOnCheckedChangeListener(listener);\n    }\n\n    public void setChecked(final boolean checked, final boolean triggerListener) {\n        if (!triggerListener) {\n            super.setOnCheckedChangeListener(null);\n            super.setChecked(checked);\n            super.setOnCheckedChangeListener(mListener);\n            return;\n        }\n        super.setChecked(checked);\n    }\n\n    public void toggle(boolean triggerListener) {\n        if (!triggerListener) {\n            super.setOnCheckedChangeListener(null);\n            super.toggle();\n            super.setOnCheckedChangeListener(mListener);\n            return;\n        }\n        super.toggle();\n    }\n}"
  },
  {
    "path": "libcore/ui/src/main/java/io/github/muntashirakon/widget/FloatingActionButtonGroup.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.widget;\n\nimport android.annotation.SuppressLint;\nimport android.content.Context;\nimport android.graphics.Color;\nimport android.util.AttributeSet;\nimport android.widget.TextView;\n\nimport androidx.annotation.Nullable;\nimport androidx.cardview.widget.CardView;\nimport androidx.core.widget.TextViewCompat;\n\nimport com.google.android.material.color.MaterialColors;\nimport com.google.android.material.floatingactionbutton.FloatingActionButton;\nimport com.google.android.material.resources.MaterialAttributes;\nimport com.leinardi.android.speeddial.FabWithLabelView;\nimport com.leinardi.android.speeddial.SpeedDialActionItem;\nimport com.leinardi.android.speeddial.SpeedDialOverlayLayout;\nimport com.leinardi.android.speeddial.SpeedDialView;\n\nimport io.github.muntashirakon.util.UiUtils;\n\n// Based on https://github.com/zhanghai/MaterialFiles/blob/9a6db781087f9e3b6345af15c735c33b305d24c2/app/src/main/java/me/zhanghai/android/files/ui/ThemedSpeedDialView.kt\n// TODO: 26/6/23 Replace this with a custom implementation by removing all those bad practices that this library follows\npublic class FloatingActionButtonGroup extends SpeedDialView {\n    public FloatingActionButtonGroup(Context context) {\n        this(context, null);\n    }\n\n    public FloatingActionButtonGroup(Context context, @Nullable AttributeSet attrs) {\n        this(context, attrs, 0);\n    }\n\n    public FloatingActionButtonGroup(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {\n        super(context, attrs, defStyleAttr);\n        FloatingActionButton fab = getMainFab();\n        int margin = UiUtils.dpToPx(getContext(), 16);\n        MarginLayoutParams layoutParams = (MarginLayoutParams) fab.getLayoutParams();\n        layoutParams.setMargins(margin, margin, margin, margin);\n        fab.setLayoutParams(layoutParams);\n        fab.setUseCompatPadding(false);\n        setMainFabOpenedBackgroundColor(MaterialColors.getColor(this, androidx.appcompat.R.attr.colorError));\n        setMainFabOpenedIconColor(MaterialColors.getColor(this, com.google.android.material.R.attr.colorOnError));\n        setMainFabClosedBackgroundColor(MaterialColors.getColor(this, com.google.android.material.R.attr.colorSecondaryContainer));\n        setMainFabClosedIconColor(MaterialColors.getColor(this, com.google.android.material.R.attr.colorOnSecondaryContainer));\n    }\n\n    @SuppressLint(\"RestrictedApi\")\n    @Override\n    protected void onAttachedToWindow() {\n        super.onAttachedToWindow();\n        SpeedDialOverlayLayout overlayLayout = getOverlayLayout();\n        if (overlayLayout != null) {\n            overlayLayout.setBackgroundColor(Color.TRANSPARENT);\n        }\n    }\n\n    @SuppressLint(\"RestrictedApi\")\n    @Nullable\n    @Override\n    public FabWithLabelView addActionItem(SpeedDialActionItem actionItem, int position, boolean animate) {\n        int fabImageTintColor = MaterialColors.getColor(this, com.google.android.material.R.attr.colorOnPrimaryContainer);\n        int fabBackgroundColor = MaterialColors.getColor(this, com.google.android.material.R.attr.colorPrimaryContainer);\n        int labelColor = MaterialColors.getColor(this, android.R.attr.textColorSecondary);\n        int labelBackgroundColor = Color.TRANSPARENT;\n        Context context = getContext();\n        SpeedDialActionItem item = new SpeedDialActionItem.Builder(actionItem.getId(), actionItem.getFabImageDrawable(context))\n                .setLabel(actionItem.getLabel(context))\n                .setFabImageTintColor(fabImageTintColor)\n                .setFabBackgroundColor(fabBackgroundColor)\n                .setLabelColor(labelColor)\n                .setLabelBackgroundColor(labelBackgroundColor)\n                .setLabelClickable(actionItem.isLabelClickable())\n                .setTheme(actionItem.getTheme())\n                .create();\n        FabWithLabelView fabWrapper = super.addActionItem(item, position, animate);\n        if (fabWrapper == null) {\n            return null;\n        }\n        FloatingActionButton fab = fabWrapper.getFab();\n        int margin = UiUtils.dpToPx(getContext(), 16);\n        MarginLayoutParams layoutParams = (MarginLayoutParams) fab.getLayoutParams();\n        layoutParams.setMargins(margin, 0, margin, 0);\n        fab.setLayoutParams(layoutParams);\n        fab.setUseCompatPadding(false);\n        CardView labelBackground = fabWrapper.getLabelBackground();\n        labelBackground.setUseCompatPadding(false);\n        labelBackground.setContentPadding(0, 0, 0, 0);\n        labelBackground.setForeground(null);\n        TextView label = (TextView) labelBackground.getChildAt(0);\n        int textAppearance = MaterialAttributes.resolveOrThrow(this, com.google.android.material.R.attr.textAppearanceLabelLarge);\n        TextViewCompat.setTextAppearance(label, textAppearance);\n        return fabWrapper;\n    }\n}\n"
  },
  {
    "path": "libcore/ui/src/main/java/io/github/muntashirakon/widget/FlowLayout.java",
    "content": "// SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-or-later\n\npackage io.github.muntashirakon.widget;\n\nimport android.content.Context;\nimport android.content.res.TypedArray;\nimport android.util.AttributeSet;\nimport android.util.TypedValue;\nimport android.view.Gravity;\nimport android.view.LayoutInflater;\nimport android.view.View;\nimport android.view.ViewGroup;\n\nimport androidx.annotation.LayoutRes;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport java.util.ArrayList;\nimport java.util.List;\n\nimport io.github.muntashirakon.ui.R;\n\n// Copyright 2017 Tianxing Li\n// Copyright 2021 Muntashir Al-Islam\n@SuppressWarnings(\"unused\")\npublic class FlowLayout extends ViewGroup {\n    private static final String TAG = FlowLayout.class.getSimpleName();\n\n    /**\n     * Special value for the child view spacing.\n     * SPACING_AUTO mean's that the actual spacing is calculated according to the size of the\n     * container and the number of the child views, so that the child views are placed evenly in\n     * the container.\n     */\n    public static final int SPACING_AUTO = -65536;\n\n    /**\n     * Special value for the horizontal spacing of the child views in the last row\n     * SPACING_ALIGN means that the horizontal spacing of the child views in the last row keeps\n     * the same with the spacing used in the row above. If there is only one row, this value is\n     * ignored and the spacing will be calculated according to childSpacing.\n     */\n    public static final int SPACING_ALIGN = -65537;\n\n    private static final int SPACING_UNDEFINED = -65538;\n\n    private static final int UNSPECIFIED_GRAVITY = -1;\n\n    private static final int ROW_VERTICAL_GRAVITY_AUTO = -65536;\n\n    private boolean mSingleLine;\n    private int mChildSpacing;\n    private int mMinChildSpacing;\n    private int mChildSpacingForLastRow;\n    private float mRowSpacing;\n    private float mAdjustedRowSpacing = 0;\n    private int mMaxRows;\n    private int mGravity;\n    private int mRowVerticalGravity;\n    private int mExactMeasuredHeight;\n\n    private final List<Float> mHorizontalSpacingForRow = new ArrayList<>();\n    private final List<Integer> mHeightForRow = new ArrayList<>();\n    private final List<Integer> mWidthForRow = new ArrayList<>();\n    private final List<Integer> mChildNumForRow = new ArrayList<>();\n\n    public FlowLayout(Context context) {\n        this(context, null);\n    }\n\n    public FlowLayout(Context context, AttributeSet attrs) {\n        this(context, attrs, 0);\n    }\n\n    public FlowLayout(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {\n        this(context, attrs, defStyleAttr, 0);\n    }\n\n    public FlowLayout(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {\n        super(context, attrs, defStyleAttr, defStyleRes);\n        TypedArray array = context.getTheme().obtainStyledAttributes(attrs, R.styleable.FlowLayout, 0, 0);\n        try {\n            mSingleLine = array.getBoolean(R.styleable.FlowLayout_singleLine, false);\n            mChildSpacing = getDimensionOrInt(array, R.styleable.FlowLayout_childSpacing, 0);\n            mMinChildSpacing = getDimensionOrInt(array, R.styleable.FlowLayout_minChildSpacing, 0);\n            mChildSpacingForLastRow = getDimensionOrInt(array, R.styleable.FlowLayout_childSpacingForLastRow, SPACING_UNDEFINED);\n            mRowSpacing = getDimensionOrInt(array, R.styleable.FlowLayout_rowSpacing, 0);\n            mMaxRows = array.getInt(R.styleable.FlowLayout_maxRows, Integer.MAX_VALUE);\n            mGravity = array.getInt(R.styleable.FlowLayout_android_gravity, UNSPECIFIED_GRAVITY);\n            mRowVerticalGravity = array.getInt(R.styleable.FlowLayout_rowVerticalGravity, ROW_VERTICAL_GRAVITY_AUTO);\n            if (isInEditMode()) {\n                int listItemId = array.getResourceId(R.styleable.FlowLayout_listItem, 0);\n                int itemCount = array.getInt(R.styleable.FlowLayout_itemCount, 10);\n                initPreview(listItemId, itemCount);\n            }\n        } finally {\n            array.recycle();\n        }\n    }\n\n    private void initPreview(@LayoutRes int layoutId, int count) {\n        if (layoutId != 0) {\n            for (int i = 0; i < count; ++i) {\n                LayoutInflater.from(getContext()).inflate(layoutId, this, true);\n            }\n        }\n    }\n\n    private int getDimensionOrInt(@NonNull TypedArray a, int index, int defValue) {\n        TypedValue tv = new TypedValue();\n        a.getValue(index, tv);\n        if (tv.type == TypedValue.TYPE_DIMENSION) {\n            return a.getDimensionPixelSize(index, defValue);\n        } else {\n            return a.getInt(index, defValue);\n        }\n    }\n\n    @Override\n    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {\n        super.onMeasure(widthMeasureSpec, heightMeasureSpec);\n\n        final int widthSize = MeasureSpec.getSize(widthMeasureSpec);\n        final int widthMode = MeasureSpec.getMode(widthMeasureSpec);\n        final int heightSize = MeasureSpec.getSize(heightMeasureSpec);\n        final int heightMode = MeasureSpec.getMode(heightMeasureSpec);\n\n        mHorizontalSpacingForRow.clear();\n        mHeightForRow.clear();\n        mWidthForRow.clear();\n        mChildNumForRow.clear();\n\n        int measuredHeight = 0;\n        int measuredWidth = 0;\n        int childCount = getChildCount();\n        int rowWidth = 0;\n        int maxChildHeightInRow = 0;\n        int childNumInRow = 0;\n        final int rowSize = widthSize - getPaddingLeft() - getPaddingRight();\n        int rowTotalChildWidth = 0;\n        final boolean allowFlow = widthMode != MeasureSpec.UNSPECIFIED && !mSingleLine;\n        final int childSpacing = mChildSpacing == SPACING_AUTO && widthMode == MeasureSpec.UNSPECIFIED\n                ? 0 : mChildSpacing;\n        final float tmpSpacing = childSpacing == SPACING_AUTO ? mMinChildSpacing : childSpacing;\n\n        for (int i = 0; i < childCount; i++) {\n            View child = getChildAt(i);\n            if (child.getVisibility() == GONE) {\n                continue;\n            }\n\n            LayoutParams childParams = child.getLayoutParams();\n            int horizontalMargin = 0;\n            int verticalMargin = 0;\n            if (childParams instanceof MarginLayoutParams) {\n                measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, measuredHeight);\n                MarginLayoutParams marginParams = (MarginLayoutParams) childParams;\n                horizontalMargin = marginParams.leftMargin + marginParams.rightMargin;\n                verticalMargin = marginParams.topMargin + marginParams.bottomMargin;\n            } else {\n                measureChild(child, widthMeasureSpec, heightMeasureSpec);\n            }\n\n            int childWidth = child.getMeasuredWidth() + horizontalMargin;\n            int childHeight = child.getMeasuredHeight() + verticalMargin;\n            if (allowFlow && rowWidth + childWidth > rowSize) { // Need flow to next row\n                // Save parameters for current row\n                mHorizontalSpacingForRow.add(\n                        getSpacingForRow(childSpacing, rowSize, rowTotalChildWidth, childNumInRow));\n                mChildNumForRow.add(childNumInRow);\n                mHeightForRow.add(maxChildHeightInRow);\n                mWidthForRow.add(rowWidth - (int) tmpSpacing);\n                if (mHorizontalSpacingForRow.size() <= mMaxRows) {\n                    measuredHeight += maxChildHeightInRow;\n                }\n                measuredWidth = Math.max(measuredWidth, rowWidth);\n\n                // Place the child view to next row\n                childNumInRow = 1;\n                rowWidth = childWidth + (int) tmpSpacing;\n                rowTotalChildWidth = childWidth;\n                maxChildHeightInRow = childHeight;\n            } else {\n                childNumInRow++;\n                rowWidth += childWidth + (int) tmpSpacing;\n                rowTotalChildWidth += childWidth;\n                maxChildHeightInRow = Math.max(maxChildHeightInRow, childHeight);\n            }\n        }\n\n        // Measure remaining child views in the last row\n        if (mChildSpacingForLastRow == SPACING_ALIGN) {\n            // For SPACING_ALIGN, use the same spacing from the row above if there is more than one row.\n            if (mHorizontalSpacingForRow.size() >= 1) {\n                mHorizontalSpacingForRow.add(\n                        mHorizontalSpacingForRow.get(mHorizontalSpacingForRow.size() - 1));\n            } else {\n                mHorizontalSpacingForRow.add(\n                        getSpacingForRow(childSpacing, rowSize, rowTotalChildWidth, childNumInRow));\n            }\n        } else if (mChildSpacingForLastRow != SPACING_UNDEFINED) {\n            // For SPACING_AUTO and specific DP values, apply them to the spacing strategy.\n            mHorizontalSpacingForRow.add(\n                    getSpacingForRow(mChildSpacingForLastRow, rowSize, rowTotalChildWidth, childNumInRow));\n        } else {\n            // For SPACING_UNDEFINED, apply childSpacing to the spacing strategy for the last row.\n            mHorizontalSpacingForRow.add(\n                    getSpacingForRow(childSpacing, rowSize, rowTotalChildWidth, childNumInRow));\n        }\n\n        mChildNumForRow.add(childNumInRow);\n        mHeightForRow.add(maxChildHeightInRow);\n        mWidthForRow.add(rowWidth - (int) tmpSpacing);\n        if (mHorizontalSpacingForRow.size() <= mMaxRows) {\n            measuredHeight += maxChildHeightInRow;\n        }\n        measuredWidth = Math.max(measuredWidth, rowWidth);\n\n        if (childSpacing == SPACING_AUTO) {\n            measuredWidth = widthSize;\n        } else if (widthMode == MeasureSpec.UNSPECIFIED) {\n            measuredWidth = measuredWidth + getPaddingLeft() + getPaddingRight();\n        } else {\n            measuredWidth = Math.min(measuredWidth + getPaddingLeft() + getPaddingRight(), widthSize);\n        }\n\n        measuredHeight += getPaddingTop() + getPaddingBottom();\n        int rowNum = Math.min(mHorizontalSpacingForRow.size(), mMaxRows);\n        float rowSpacing = mRowSpacing == SPACING_AUTO && heightMode == MeasureSpec.UNSPECIFIED\n                ? 0 : mRowSpacing;\n        if (rowSpacing == SPACING_AUTO) {\n            if (rowNum > 1) {\n                mAdjustedRowSpacing = (heightSize - measuredHeight) / (rowNum - 1f);\n            } else {\n                mAdjustedRowSpacing = 0;\n            }\n            measuredHeight = heightSize;\n        } else {\n            mAdjustedRowSpacing = rowSpacing;\n            if (rowNum > 1) {\n                measuredHeight = heightMode == MeasureSpec.UNSPECIFIED\n                        ? ((int) (measuredHeight + mAdjustedRowSpacing * (rowNum - 1)))\n                        : (Math.min((int) (measuredHeight + mAdjustedRowSpacing * (rowNum - 1)),\n                        heightSize));\n            }\n        }\n\n        mExactMeasuredHeight = measuredHeight;\n\n        measuredWidth = widthMode == MeasureSpec.EXACTLY ? widthSize : measuredWidth;\n        measuredHeight = heightMode == MeasureSpec.EXACTLY ? heightSize : measuredHeight;\n\n        setMeasuredDimension(measuredWidth, measuredHeight);\n    }\n\n    @Override\n    protected void onLayout(boolean changed, int l, int t, int r, int b) {\n        final int paddingStart = getPaddingStart();\n        final int paddingEnd = getPaddingEnd();\n        final int paddingTop = getPaddingTop();\n        final int paddingBottom = getPaddingBottom();\n\n        final boolean isRtl = getLayoutDirection() == LAYOUT_DIRECTION_RTL;\n        int x;\n        int y = paddingTop;\n\n        final int verticalGravity = mGravity & Gravity.VERTICAL_GRAVITY_MASK;\n        final int horizontalGravity = mGravity & Gravity.HORIZONTAL_GRAVITY_MASK;\n\n        // Calculate y\n        switch (verticalGravity) {\n            case Gravity.CENTER_VERTICAL: {\n                int offset = (b - t - paddingTop - paddingBottom - mExactMeasuredHeight) / 2;\n                y += offset;\n                break;\n            }\n            case Gravity.BOTTOM: {\n                int offset = b - t - paddingTop - paddingBottom - mExactMeasuredHeight;\n                y += offset;\n                break;\n            }\n            default:\n                break;\n        }\n\n        final int horizontalPadding = paddingStart + paddingEnd;\n        final int layoutWidth = r - l;\n\n        int verticalRowGravity = mRowVerticalGravity & Gravity.VERTICAL_GRAVITY_MASK;\n\n        int rowCount = mChildNumForRow.size();\n        int childIdx = 0;\n        for (int row = 0; row < Math.min(rowCount, mMaxRows); row++) {\n            int childNum = mChildNumForRow.get(row);\n            int rowHeight = mHeightForRow.get(row);\n            float spacing = mHorizontalSpacingForRow.get(row);\n            x = paddingStart + getHorizontalGravityOffsetForRow(horizontalGravity, layoutWidth, horizontalPadding, row);\n            if (isRtl) {\n                x = layoutWidth - x;\n            }\n            for (int i = 0; i < childNum && childIdx < getChildCount(); ) {\n                View child = getChildAt(childIdx++);\n                if (child.getVisibility() == GONE) {\n                    continue;\n                } else {\n                    i++;\n                }\n\n                LayoutParams childParams = child.getLayoutParams();\n                int marginStart = 0;\n                int marginTop = 0;\n                int marginBottom = 0;\n                int marginEnd = 0;\n                if (childParams instanceof MarginLayoutParams) {\n                    MarginLayoutParams marginParams = (MarginLayoutParams) childParams;\n                    marginStart = marginParams.getMarginStart();\n                    marginEnd = marginParams.getMarginEnd();\n                    marginTop = marginParams.topMargin;\n                    marginBottom = marginParams.bottomMargin;\n                }\n\n                int childWidth = child.getMeasuredWidth();\n                int childHeight = child.getMeasuredHeight();\n                int tt = y + marginTop;\n                if (verticalRowGravity == Gravity.BOTTOM) {\n                    tt = y + rowHeight - marginBottom - childHeight;\n                } else if (verticalRowGravity == Gravity.CENTER_VERTICAL) {\n                    tt = y + marginTop + (rowHeight - marginTop - marginBottom - childHeight) / 2;\n                }\n                int bb = tt + childHeight;\n                if (isRtl) {\n                    int l2 = x - marginStart;\n                    int r2 = l2 - childWidth;\n                    child.layout(r2, tt, l2, bb);\n                } else {\n                    int l2 = x + marginStart;\n                    int r2 = l2 + childWidth;\n                    child.layout(l2, tt, r2, bb);\n                }\n                // The width consumed by this child\n                int consumedWidth = childWidth + (int) spacing + marginStart + marginEnd;\n                x = x + (isRtl ? -consumedWidth : consumedWidth);\n            }\n            y += rowHeight + (int) mAdjustedRowSpacing;\n        }\n\n        for (int i = childIdx; i < getChildCount(); i++) {\n            View child = getChildAt(i);\n            if (child.getVisibility() == GONE) {\n                continue;\n            }\n            if (isRtl) {\n                child.layout(layoutWidth, 0, layoutWidth, 0);\n            } else {\n                child.layout(0, 0, 0, 0);\n            }\n        }\n    }\n\n    private int getHorizontalGravityOffsetForRow(int horizontalGravity, int parentLayoutWidth, int horizontalPadding,\n                                                 int row) {\n        if (mChildSpacing == SPACING_AUTO || row >= mWidthForRow.size()\n                || row >= mChildNumForRow.size() || mChildNumForRow.get(row) <= 0) {\n            return 0;\n        }\n\n        int offset = 0;\n        switch (horizontalGravity) {\n            case Gravity.CENTER_HORIZONTAL:\n                // (Layout width - (total horizontal padding + real row width)) / 2\n                offset = (parentLayoutWidth - horizontalPadding - mWidthForRow.get(row)) / 2;\n                break;\n            case Gravity.END:\n                offset = parentLayoutWidth - horizontalPadding - mWidthForRow.get(row);\n                break;\n            default:\n                break;\n        }\n        return offset;\n    }\n\n    @Override\n    protected LayoutParams generateLayoutParams(LayoutParams p) {\n        return new MarginLayoutParams(p);\n    }\n\n    @Override\n    public LayoutParams generateLayoutParams(AttributeSet attrs) {\n        return new MarginLayoutParams(getContext(), attrs);\n    }\n\n    /**\n     * Whether the items are constrained to a single horizontal line.\n     *\n     * @return {@code true} if the items are constrained to a single horizontal line, {@code false} otherwise.\n     */\n    public boolean isSingleLine() {\n        return mSingleLine;\n    }\n\n    /**\n     * Sets whether to constraint items to a single horizontal line.\n     *\n     * @param singleLine {@code true} to constraint items to a single horizontal line, {@code false} otherwise.\n     */\n    public void setSingleLine(boolean singleLine) {\n        mSingleLine = singleLine;\n        requestLayout();\n    }\n\n    /**\n     * Returns the horizontal spacing between child views.\n     *\n     * @return The spacing, either {@link FlowLayout#SPACING_AUTO}, or a fixed size in pixels.\n     */\n    public int getChildSpacing() {\n        return mChildSpacing;\n    }\n\n    /**\n     * Sets the horizontal spacing between child views.\n     *\n     * @param childSpacing The spacing, either {@link FlowLayout#SPACING_AUTO}, or a fixed size in\n     *                     pixels.\n     */\n    public void setChildSpacing(int childSpacing) {\n        mChildSpacing = childSpacing;\n        requestLayout();\n    }\n\n    /**\n     * Returns the horizontal spacing between child views of the last row.\n     *\n     * @return The spacing, either {@link FlowLayout#SPACING_AUTO},\n     * {@link FlowLayout#SPACING_ALIGN}, or a fixed size in pixels\n     */\n    public int getChildSpacingForLastRow() {\n        return mChildSpacingForLastRow;\n    }\n\n    /**\n     * Sets the horizontal spacing between child views of the last row.\n     *\n     * @param childSpacingForLastRow The spacing, either {@link FlowLayout#SPACING_AUTO},\n     *                               {@link FlowLayout#SPACING_ALIGN}, or a fixed size in pixels\n     */\n    public void setChildSpacingForLastRow(int childSpacingForLastRow) {\n        mChildSpacingForLastRow = childSpacingForLastRow;\n        requestLayout();\n    }\n\n    /**\n     * Returns the vertical spacing between rows.\n     *\n     * @return The spacing, either {@link FlowLayout#SPACING_AUTO}, or a fixed size in pixels.\n     */\n    public float getRowSpacing() {\n        return mRowSpacing;\n    }\n\n    /**\n     * Sets the vertical spacing between rows in pixels. Use SPACING_AUTO to evenly place all rows\n     * in vertical.\n     *\n     * @param rowSpacing The spacing, either {@link FlowLayout#SPACING_AUTO}, or a fixed size in\n     *                   pixels.\n     */\n    public void setRowSpacing(float rowSpacing) {\n        mRowSpacing = rowSpacing;\n        requestLayout();\n    }\n\n    /**\n     * Returns the maximum number of rows of the FlowLayout.\n     *\n     * @return The maximum number of rows.\n     */\n    public int getMaxRows() {\n        return mMaxRows;\n    }\n\n    /**\n     * Sets the height of the FlowLayout to be at most maxRows tall.\n     *\n     * @param maxRows The maximum number of rows.\n     */\n    public void setMaxRows(int maxRows) {\n        mMaxRows = maxRows;\n        requestLayout();\n    }\n\n    public void setGravity(int gravity) {\n        if (mGravity != gravity) {\n            mGravity = gravity;\n            requestLayout();\n        }\n    }\n\n    public void setRowVerticalGravity(int rowVerticalGravity) {\n        if (mRowVerticalGravity != rowVerticalGravity) {\n            mRowVerticalGravity = rowVerticalGravity;\n            requestLayout();\n        }\n    }\n\n    public int getMinChildSpacing() {\n        return mMinChildSpacing;\n    }\n\n    public void setMinChildSpacing(int minChildSpacing) {\n        this.mMinChildSpacing = minChildSpacing;\n        requestLayout();\n    }\n\n    public int getRowsCount() {\n        return mChildNumForRow.size();\n    }\n\n    private float getSpacingForRow(int spacingAttribute, int rowSize, int usedSize, int childNum) {\n        if (spacingAttribute == SPACING_AUTO) {\n            if (childNum > 1) {\n                return (rowSize - usedSize) / (childNum - 1f);\n            }\n            return 0;\n        }\n        return spacingAttribute;\n    }\n}"
  },
  {
    "path": "libcore/ui/src/main/java/io/github/muntashirakon/widget/HyperlinkTextView.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.widget;\n\nimport android.content.Context;\nimport android.text.method.LinkMovementMethod;\nimport android.text.method.MovementMethod;\nimport android.util.AttributeSet;\n\nimport androidx.annotation.Nullable;\n\nimport com.google.android.material.textview.MaterialTextView;\n\npublic class HyperlinkTextView extends MaterialTextView {\n    public HyperlinkTextView(Context context) {\n        super(context);\n    }\n\n    public HyperlinkTextView(Context context, @Nullable AttributeSet attrs) {\n        super(context, attrs);\n    }\n\n    public HyperlinkTextView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {\n        super(context, attrs, defStyleAttr);\n    }\n\n    /**\n     * Set default movement method to {@link LinkMovementMethod}\n     *\n     * @return Link movement method as the default movement method\n     */\n    @Override\n    protected MovementMethod getDefaultMovementMethod() {\n        return LinkMovementMethod.getInstance();\n    }\n}\n"
  },
  {
    "path": "libcore/ui/src/main/java/io/github/muntashirakon/widget/MaterialAlertView.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.widget;\n\nimport static com.google.android.material.theme.overlay.MaterialThemeOverlay.wrap;\n\nimport android.annotation.SuppressLint;\nimport android.content.Context;\nimport android.content.res.ColorStateList;\nimport android.text.method.LinkMovementMethod;\nimport android.text.method.MovementMethod;\nimport android.util.AttributeSet;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.view.ViewParent;\nimport android.widget.LinearLayout;\nimport android.widget.TextView;\n\nimport androidx.annotation.IntDef;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.StringRes;\nimport androidx.appcompat.widget.TintTypedArray;\nimport androidx.core.widget.TextViewCompat;\nimport androidx.transition.TransitionManager;\nimport androidx.transition.Visibility;\n\nimport com.google.android.material.color.MaterialColors;\nimport com.google.android.material.internal.ThemeEnforcement;\nimport com.google.android.material.textfield.TextInputLayout;\nimport com.google.android.material.transition.MaterialFadeThrough;\n\nimport java.lang.annotation.Retention;\nimport java.lang.annotation.RetentionPolicy;\n\nimport io.github.muntashirakon.ui.R;\n\npublic class MaterialAlertView extends TextInputLayout {\n    @IntDef({ALERT_TYPE_INFO, ALERT_TYPE_WARN, ALERT_TYPE_CUSTOM})\n    @Retention(RetentionPolicy.SOURCE)\n    public @interface AlertType {\n    }\n\n    public static final int ALERT_TYPE_CUSTOM = -1;\n    public static final int ALERT_TYPE_INFO = 0;\n    public static final int ALERT_TYPE_WARN = 1;\n\n    private static final int DEF_STYLE_RES = R.style.Widget_AppTheme_MaterialAlertView;\n\n    private final TextInputTextView mTextInputTextView;\n\n    @AlertType\n    private int mAlertType;\n\n    public MaterialAlertView(@NonNull Context context) {\n        this(context, null);\n    }\n\n    public MaterialAlertView(@NonNull Context context, @Nullable AttributeSet attrs) {\n        this(context, attrs, R.attr.materialAlertViewStyle);\n    }\n\n    @SuppressLint(\"RestrictedApi\")\n    public MaterialAlertView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {\n        super(wrap(context, attrs, defStyleAttr, DEF_STYLE_RES), attrs, defStyleAttr);\n        context = getContext();\n        // AlertView only has a single layout by default\n        mTextInputTextView = new TextInputTextView(context);\n        mTextInputTextView.setMovementMethod(LinkMovementMethod.getInstance());\n\n        addView(mTextInputTextView, new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));\n\n        final TintTypedArray a = ThemeEnforcement.obtainTintedStyledAttributes(\n                context, attrs, R.styleable.MaterialAlertView, defStyleAttr, DEF_STYLE_RES);\n        mAlertType = a.getInt(R.styleable.MaterialAlertView_alertType, ALERT_TYPE_INFO);\n        int texAppearance = a.getResourceId(R.styleable.MaterialAlertView_android_textAppearance, 0);\n        ColorStateList textColor = a.getColorStateList(R.styleable.MaterialAlertView_android_textColor);\n        CharSequence text = a.getText(R.styleable.MaterialAlertView_android_text);\n        a.recycle();\n\n        TextViewCompat.setTextAppearance(mTextInputTextView, texAppearance);\n        if (textColor != null) {\n            mTextInputTextView.setTextColor(textColor);\n        }\n        mTextInputTextView.setText(text);\n        mTextInputTextView.setOverScrollMode(OVER_SCROLL_NEVER);\n\n        // Override colors, drawables\n        applyAlertType();\n    }\n\n    @AlertType\n    public int getAlertType() {\n        return mAlertType;\n    }\n\n    public void setAlertType(@AlertType int alertType) {\n        mAlertType = alertType;\n        applyAlertType();\n    }\n\n    public void setText(CharSequence text) {\n        mTextInputTextView.setText(text);\n    }\n\n    public void setText(CharSequence text, @NonNull TextView.BufferType type) {\n        mTextInputTextView.setText(text, type);\n    }\n\n    public void setText(@StringRes int resid) {\n        mTextInputTextView.setText(resid);\n    }\n\n    public void setText(@StringRes int resid, @NonNull TextView.BufferType type) {\n        mTextInputTextView.setText(resid, type);\n    }\n\n    public void setText(char[] text, int start, int len) {\n        mTextInputTextView.setText(text, start, len);\n    }\n\n    public void setTextIsSelectable(boolean selectable) {\n        mTextInputTextView.setTextIsSelectable(selectable);\n    }\n\n    public void setMovementMethod(MovementMethod movementMethod) {\n        mTextInputTextView.setMovementMethod(movementMethod);\n    }\n\n    public void show() {\n        MaterialFadeThrough fadeThrough = new MaterialFadeThrough();\n        fadeThrough.addTarget(this);\n        fadeThrough.setDuration(500);\n        fadeThrough.setMode(Visibility.MODE_IN);\n        ViewParent parent = getParent();\n        if (parent instanceof ViewGroup) {\n            TransitionManager.beginDelayedTransition((ViewGroup) parent, fadeThrough);\n        } else {\n            TransitionManager.beginDelayedTransition(this, fadeThrough);\n        }\n        setVisibility(View.VISIBLE);\n    }\n\n    public void hide() {\n        MaterialFadeThrough fadeThrough = new MaterialFadeThrough();\n        fadeThrough.addTarget(this);\n        fadeThrough.setSecondaryAnimatorProvider(null);\n        fadeThrough.setDuration(1000);\n        fadeThrough.setMode(Visibility.MODE_OUT);\n        ViewParent parent = getParent();\n        if (parent instanceof ViewGroup) {\n            TransitionManager.beginDelayedTransition((ViewGroup) parent, fadeThrough);\n        } else {\n            TransitionManager.beginDelayedTransition(this, fadeThrough);\n        }\n        setVisibility(View.GONE);\n    }\n\n    private void applyAlertType() {\n        // Four things have to be changed: text colors and drawable\n        switch (mAlertType) {\n            case ALERT_TYPE_CUSTOM:\n                // Do not change anything\n                break;\n            default:\n            case ALERT_TYPE_INFO: {\n                setStartIconDrawable(R.drawable.ic_information);\n                ColorStateList foreground = ColorStateList.valueOf(MaterialColors.getColor(this, com.google.android.material.R.attr.colorOnPrimaryContainer));\n                ColorStateList background = ColorStateList.valueOf(MaterialColors.getColor(this, com.google.android.material.R.attr.colorPrimaryContainer));\n                setBoxBackgroundColorStateList(background);\n                setStartIconTintList(foreground);\n                mTextInputTextView.setTextColor(foreground);\n                break;\n            }\n            case ALERT_TYPE_WARN: {\n                setStartIconDrawable(R.drawable.ic_caution);\n                ColorStateList foreground = ColorStateList.valueOf(MaterialColors.getColor(this, com.google.android.material.R.attr.colorOnErrorContainer));\n                ColorStateList background = ColorStateList.valueOf(MaterialColors.getColor(this, com.google.android.material.R.attr.colorErrorContainer));\n                setBoxBackgroundColorStateList(background);\n                setStartIconTintList(foreground);\n                mTextInputTextView.setTextColor(foreground);\n                break;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "libcore/ui/src/main/java/io/github/muntashirakon/widget/MaterialAutoCompleteTextView.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.widget;\n\nimport android.annotation.SuppressLint;\nimport android.content.Context;\nimport android.content.res.TypedArray;\nimport android.graphics.drawable.Drawable;\nimport android.util.AttributeSet;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport com.google.android.material.internal.ThemeEnforcement;\n\nimport io.github.muntashirakon.ui.R;\nimport io.github.muntashirakon.view.AutoCompleteTextViewCompat;\n\npublic class MaterialAutoCompleteTextView extends com.google.android.material.textfield.MaterialAutoCompleteTextView {\n    public MaterialAutoCompleteTextView(@NonNull Context context) {\n        this(context, null);\n    }\n\n    public MaterialAutoCompleteTextView(@NonNull Context context, @Nullable AttributeSet attributeSet) {\n        this(context, attributeSet, androidx.appcompat.R.attr.autoCompleteTextViewStyle);\n    }\n\n    @SuppressLint(\"RestrictedApi\")\n    public MaterialAutoCompleteTextView(@NonNull Context context, @Nullable AttributeSet attributeSet, int defStyleAttr) {\n        super(context, attributeSet, defStyleAttr);\n\n        context = getContext();\n\n        TypedArray attributes = ThemeEnforcement.obtainStyledAttributes(\n                context,\n                attributeSet,\n                com.google.android.material.R.styleable.MaterialAutoCompleteTextView,\n                defStyleAttr,\n                androidx.appcompat.R.style.Widget_AppCompat_AutoCompleteTextView);\n\n        Drawable popupListSelector = attributes.getDrawable(R.styleable.MaterialAutoCompleteTextView_android_dropDownSelector);\n        if (popupListSelector != null) {\n            AutoCompleteTextViewCompat.setListSelectorMaterial(this, popupListSelector);\n        }\n        attributes.recycle();\n    }\n}\n"
  },
  {
    "path": "libcore/ui/src/main/java/io/github/muntashirakon/widget/MaterialSpinner.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.widget;\n\nimport android.content.Context;\nimport android.util.AttributeSet;\nimport android.view.ViewGroup;\nimport android.view.inputmethod.EditorInfo;\nimport android.widget.AdapterView;\nimport android.widget.Filterable;\nimport android.widget.ListAdapter;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport com.google.android.material.textfield.TextInputLayout;\n\nimport io.github.muntashirakon.ui.R;\nimport io.github.muntashirakon.view.TextInputLayoutCompat;\n\npublic class MaterialSpinner extends TextInputLayout {\n    private final MaterialAutoCompleteTextView mAutoCompleteTextView;\n\n    private int mSelection;\n\n    public MaterialSpinner(@NonNull Context context) {\n        this(context, null);\n    }\n\n    public MaterialSpinner(@NonNull Context context, @Nullable AttributeSet attrs) {\n        this(context, attrs, R.attr.materialSpinnerStyle);\n    }\n\n    public MaterialSpinner(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {\n        super(context, attrs, defStyleAttr);\n        context = getContext();\n        mAutoCompleteTextView = new MaterialAutoCompleteTextView(context);\n        addView(mAutoCompleteTextView, new LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));\n        mAutoCompleteTextView.setInputType(EditorInfo.TYPE_NULL);\n        mAutoCompleteTextView.setKeyListener(null);\n        mAutoCompleteTextView.setFocusable(false);\n        setEndIconTintList(mAutoCompleteTextView.getTextColors());\n        setEndIconMode(END_ICON_DROPDOWN_MENU);\n        TextInputLayoutCompat.fixEndIcon(this);\n    }\n\n    public <T extends ListAdapter & Filterable> void setAdapter(@Nullable T adapter) {\n        mAutoCompleteTextView.setAdapter(adapter);\n        if (adapter != null) {\n            setSelection(mSelection);\n        }\n    }\n\n    public void setOnItemClickListener(@Nullable AdapterView.OnItemClickListener listener) {\n        mAutoCompleteTextView.setOnItemClickListener(listener);\n    }\n\n    public void setSelection(int position) {\n        mSelection = position;\n        ListAdapter adapter = mAutoCompleteTextView.getAdapter();\n        Object object;\n        if (adapter == null || mSelection < 0 || adapter.getCount() <= mSelection) {\n            object = null;\n        } else {\n            object = adapter.getItem(mSelection);\n        }\n        mAutoCompleteTextView.setText(object == null ? \"\" : object.toString(), false);\n    }\n}\n"
  },
  {
    "path": "libcore/ui/src/main/java/io/github/muntashirakon/widget/MaxHeightScrollView.java",
    "content": "// SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-or-later\n\npackage io.github.muntashirakon.widget;\n\nimport android.content.Context;\nimport android.content.res.TypedArray;\nimport android.util.AttributeSet;\nimport android.widget.ScrollView;\n\nimport io.github.muntashirakon.ui.R;\nimport io.github.muntashirakon.util.UiUtils;\n\n// Copyright 2016 Bumsoo Kim\npublic class MaxHeightScrollView extends ScrollView {\n    private int mMaxHeight;\n\n    public MaxHeightScrollView(Context context) {\n        super(context);\n    }\n\n    public MaxHeightScrollView(Context context, AttributeSet attrs) {\n        super(context, attrs);\n        init(context, attrs);\n    }\n\n    public MaxHeightScrollView(Context context, AttributeSet attrs, int defStyleAttr) {\n        super(context, attrs, defStyleAttr);\n        init(context, attrs);\n    }\n\n    public MaxHeightScrollView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {\n        super(context, attrs, defStyleAttr, defStyleRes);\n        init(context, attrs);\n    }\n\n    private void init(Context context, AttributeSet attrs) {\n        if (attrs == null) {\n            return;\n        }\n\n        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.MaxHeightScrollView);\n\n        if (a.hasValue(R.styleable.MaxHeightScrollView_maxHeight)) {\n            setMaxHeight(a.getDimensionPixelSize(R.styleable.MaxHeightScrollView_maxHeight, 0));\n        }\n\n        a.recycle();\n    }\n\n    @Override\n    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {\n        heightMeasureSpec = MeasureSpec.makeMeasureSpec(mMaxHeight, MeasureSpec.AT_MOST);\n        super.onMeasure(widthMeasureSpec, heightMeasureSpec);\n    }\n\n    public void setMaxHeight(int maxHeight) {\n        mMaxHeight = maxHeight;\n    }\n\n    public void setMaxHeightDp(int maxHeightDp) {\n        mMaxHeight = UiUtils.dpToPx(getContext(), maxHeightDp);\n    }\n\n    public int getMaxHeight() {\n        return mMaxHeight;\n    }\n\n    public int getMaxHeightDp() {\n        return UiUtils.pxToDp(getContext(), mMaxHeight);\n    }\n}\n"
  },
  {
    "path": "libcore/ui/src/main/java/io/github/muntashirakon/widget/MultiSelectionView.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.widget;\n\nimport android.annotation.SuppressLint;\nimport android.content.Context;\nimport android.graphics.Rect;\nimport android.os.Parcel;\nimport android.os.Parcelable;\nimport android.util.AttributeSet;\nimport android.view.Gravity;\nimport android.view.LayoutInflater;\nimport android.view.Menu;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.widget.TextView;\n\nimport androidx.annotation.AnyThread;\nimport androidx.annotation.AttrRes;\nimport androidx.annotation.CallSuper;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.Px;\nimport androidx.annotation.UiThread;\nimport androidx.appcompat.widget.TintTypedArray;\nimport androidx.core.os.ParcelCompat;\nimport androidx.core.util.ObjectsCompat;\nimport androidx.core.view.OnApplyWindowInsetsListener;\nimport androidx.core.view.ViewCompat;\nimport androidx.core.view.WindowInsetsCompat;\nimport androidx.customview.view.AbsSavedState;\nimport androidx.recyclerview.widget.RecyclerView;\nimport androidx.transition.Transition;\nimport androidx.transition.TransitionManager;\n\nimport com.google.android.material.card.MaterialCardView;\nimport com.google.android.material.internal.ThemeEnforcement;\nimport com.google.android.material.transition.MaterialSharedAxis;\n\nimport java.lang.reflect.Field;\nimport java.util.Locale;\n\nimport io.github.muntashirakon.multiselection.MultiSelectionActionsView;\nimport io.github.muntashirakon.ui.R;\nimport io.github.muntashirakon.util.AdapterUtils;\nimport io.github.muntashirakon.util.UiUtils;\n\n@SuppressLint(\"RestrictedApi\")\npublic class MultiSelectionView extends MaterialCardView implements OnApplyWindowInsetsListener {\n    public interface OnSelectionChangeListener {\n        /**\n         * Called when the number of selections has changed or an update is required internally or via\n         * {@link #updateCounter(boolean)}.\n         *\n         * @param selectionCount Present selection count\n         * @return {@code true} if it's necessary to update the visibility of menu items, or {@code false} otherwise.\n         */\n        @UiThread\n        boolean onSelectionChange(int selectionCount);\n    }\n\n    public interface OnSelectionModeChangeListener {\n        @UiThread\n        void onSelectionModeEnabled();\n\n        @UiThread\n        void onSelectionModeDisabled();\n    }\n\n    private final MultiSelectionActionsView mSelectionActionsView;\n    private final View mDivider;\n    private final View mCancelSelectionView;\n    private final CheckBox mSelectAllView;\n    private final TextView mSelectionCounter;\n    @Px\n    private final int mHorizontalMargin;\n    @Px\n    private final int mBottomMargin;\n    @Px\n    private final int mMaxHeight;\n    @Px\n    private final int mTitleHeight;\n\n    @Px\n    private int mCurrentHeight;\n    @Px\n    private int mSelectionBottomPadding;\n    private boolean mInSelectionMode = false;\n    @Nullable\n    private Adapter<?> mAdapter;\n    @Nullable\n    private OnSelectionChangeListener mSelectionChangeListener;\n    @Nullable\n    private OnSelectionModeChangeListener mSelectionModeChangeListener;\n    @Nullable\n    private WindowInsetsCompat mLastInsets;\n\n    public MultiSelectionView(Context context) {\n        this(context, null);\n    }\n\n    public MultiSelectionView(Context context, @Nullable AttributeSet attrs) {\n        this(context, attrs, com.google.android.material.R.attr.materialCardViewStyle);\n    }\n\n    @SuppressLint(\"ClickableViewAccessibility\")\n    public MultiSelectionView(Context context, @Nullable AttributeSet attrs, @AttrRes int defStyleAttr) {\n        super(context, attrs, defStyleAttr);\n        // Ensure we are using the correctly themed context rather than the context that was passed in.\n        context = getContext();\n\n        // Inflate layout\n        LayoutInflater.from(context).inflate(R.layout.view_selection_panel, this, true);\n        mSelectionActionsView = findViewById(R.id.selection_actions);\n        mCancelSelectionView = findViewById(R.id.action_cancel);\n        mSelectAllView = findViewById(R.id.action_select_all);\n        mSelectionCounter = findViewById(R.id.selection_counter);\n        mDivider = findViewById(R.id.divider);\n\n        // Set heights\n        mMaxHeight = UiUtils.dpToPx(context, 36 + 1 + 75); // This is a pessimistic approximation, not a real height\n        mTitleHeight = UiUtils.dpToPx(context, 48);\n        mCurrentHeight = mMaxHeight;\n\n        // Clicking on counter maximizes/minimizes the selection actions\n        mSelectionCounter.setOnClickListener((v) -> {\n            Adapter.OnLayoutChangeListener listener;\n            if (mAdapter != null) {\n                listener = mAdapter.getLayoutChangeListener();\n                mAdapter.setOnLayoutChangeListener(null);\n            } else listener = null;\n            if (mCurrentHeight == mTitleHeight) {\n                // Minimized mode\n                maximize();\n            } else minimize();\n            if (mAdapter != null) {\n                mAdapter.setOnLayoutChangeListener(listener);\n            }\n        });\n\n        // Custom attributes\n        TintTypedArray attributes = ThemeEnforcement.obtainTintedStyledAttributes(context, attrs,\n                R.styleable.MultiSelectionView, defStyleAttr, com.google.android.material.R.style.Widget_MaterialComponents_CardView);\n\n        // Set styles\n        @Px\n        int smallSize = getResources().getDimensionPixelSize(R.dimen.padding_small);\n        setPreventCornerOverlap(false);\n        setCardElevation(UiUtils.dpToPx(context, 8));\n\n        mHorizontalMargin = smallSize;\n        mBottomMargin = getResources().getDimensionPixelSize(R.dimen.padding_very_small);\n\n        if (attributes.hasValue(R.styleable.MultiSelectionView_menu)) {\n            mSelectionActionsView.inflateMenu(attributes.getResourceId(R.styleable.MultiSelectionView_menu, 0));\n        }\n\n        attributes.recycle();\n\n        ViewCompat.setOnApplyWindowInsetsListener(this, this);\n    }\n\n    static class SavedState extends AbsSavedState {\n        int currentHeight;\n        int selectionBottomPadding;\n        int selectionBottomPaddingMinimum;\n        boolean inSelectionMode;\n\n        SavedState(@NonNull Parcelable superState) {\n            super(superState);\n        }\n\n        public SavedState(@NonNull Parcel source, @Nullable ClassLoader loader) {\n            super(source, loader);\n            currentHeight = source.readInt();\n            selectionBottomPadding = source.readInt();\n            selectionBottomPaddingMinimum = source.readInt();\n            inSelectionMode = ParcelCompat.readBoolean(source);\n        }\n\n        @Override\n        public void writeToParcel(Parcel dest, int flags) {\n            super.writeToParcel(dest, flags);\n            dest.writeInt(currentHeight);\n            dest.writeInt(selectionBottomPadding);\n            dest.writeInt(selectionBottomPaddingMinimum);\n            ParcelCompat.writeBoolean(dest, inSelectionMode);\n        }\n\n        @NonNull\n        @Override\n        public String toString() {\n            return \"SavedState{\"\n                    + Integer.toHexString(System.identityHashCode(this))\n                    + \"currentHeight=\" + currentHeight\n                    + \" selectionBottomPadding=\" + selectionBottomPadding\n                    + \" selectionBottomPaddingMinimum=\" + selectionBottomPaddingMinimum +\n                    '}';\n        }\n\n        public static final Creator<SavedState> CREATOR = new ClassLoaderCreator<SavedState>() {\n            @Override\n            public SavedState createFromParcel(Parcel in, ClassLoader loader) {\n                return new SavedState(in, loader);\n            }\n\n            @Override\n            public SavedState createFromParcel(Parcel in) {\n                return new SavedState(in, null);\n            }\n\n            @Override\n            public SavedState[] newArray(int size) {\n                return new SavedState[size];\n            }\n        };\n    }\n\n    @Nullable\n    @Override\n    protected Parcelable onSaveInstanceState() {\n        Parcelable superState = super.onSaveInstanceState();\n        if (superState == null) {\n            return null;\n        }\n        SavedState ss = new SavedState(superState);\n        ss.currentHeight = mCurrentHeight;\n        ss.selectionBottomPadding = mSelectionBottomPadding;\n        ss.inSelectionMode = mInSelectionMode;\n        return ss;\n    }\n\n    @Override\n    protected void onRestoreInstanceState(Parcelable state) {\n        if (state instanceof SavedState) {\n            SavedState ss = (SavedState) state;\n            super.onRestoreInstanceState(ss.getSuperState());\n            mCurrentHeight = ss.currentHeight;\n            mSelectionBottomPadding = ss.selectionBottomPadding;\n            mInSelectionMode = ss.inSelectionMode;\n        } else super.onRestoreInstanceState(state);\n        if (mInSelectionMode) {\n            show();\n            updateCounter(false);\n        } else {\n            updateCounter(true);\n        }\n    }\n\n    @Override\n    protected void onAttachedToWindow() {\n        super.onAttachedToWindow();\n        // Set layout params\n        updateMarginAndPosition();\n    }\n\n    @Override\n    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {\n        super.onLayout(changed, left, top, right, bottom);\n        ViewGroup.MarginLayoutParams lp = (MarginLayoutParams) getLayoutParams();\n        mSelectionBottomPadding = getHeight() + lp.topMargin + lp.bottomMargin + UiUtils.dpToPx(getContext(), 5);\n        if (mAdapter != null) {\n            mAdapter.setSelectionBottomPadding(mSelectionBottomPadding);\n        }\n    }\n\n    @Override\n    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {\n        super.onMeasure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(mCurrentHeight, MeasureSpec.AT_MOST));\n    }\n\n    @Override\n    @NonNull\n    public WindowInsetsCompat onApplyWindowInsets(@NonNull View v, @NonNull WindowInsetsCompat insets) {\n        WindowInsetsCompat newInsets = null;\n        if (getFitsSystemWindows()) {\n            newInsets = insets;\n        }\n        if (!ObjectsCompat.equals(mLastInsets, newInsets)) {\n            mLastInsets = newInsets;\n            updateMarginAndPosition();\n            requestLayout();\n        }\n        return insets;\n    }\n\n    @NonNull\n    public Menu getMenu() {\n        return mSelectionActionsView.getMenu();\n    }\n\n    @Px\n    public int getHorizontalMargin() {\n        return mHorizontalMargin;\n    }\n\n    @Px\n    public int getBottomMargin() {\n        return mBottomMargin;\n    }\n\n    @Px\n    public int getSelectionBottomPadding() {\n        return mSelectionBottomPadding;\n    }\n\n    public void setAdapter(@NonNull Adapter<?> adapter) {\n        mAdapter = adapter;\n        // Set listeners\n        adapter.setOnLayoutChangeListener((v, rect, oldRect) -> toggleSelectionActions(rect.height()));\n        mCancelSelectionView.setOnClickListener(v -> {\n            adapter.cancelSelection();\n            hide();\n        });\n        mSelectAllView.setOnCheckedChangeListener((buttonView, isChecked) -> {\n            if (isChecked) adapter.selectAll();\n            else adapter.deselectAll();\n        });\n        adapter.setOnSelectionChangeListener(() -> updateCounter(false));\n    }\n\n    @UiThread\n    public void show() {\n        if (mSelectionModeChangeListener != null) {\n            mSelectionModeChangeListener.onSelectionModeEnabled();\n        }\n        Transition sharedAxis = new MaterialSharedAxis(MaterialSharedAxis.Y, true);\n        TransitionManager.beginDelayedTransition(this, sharedAxis);\n        setVisibility(VISIBLE);\n        ViewGroup.MarginLayoutParams lp = (MarginLayoutParams) getLayoutParams();\n        mSelectionBottomPadding = getHeight() + lp.topMargin + lp.bottomMargin;\n        mInSelectionMode = true;\n        if (mAdapter != null) {\n            mAdapter.setInSelectionMode(true);\n            mAdapter.setSelectionBottomPadding(mSelectionBottomPadding);\n        }\n    }\n\n    public void cancel() {\n        mCancelSelectionView.performClick();\n    }\n\n    @SuppressWarnings(\"deprecation\")\n    @UiThread\n    public void hide() {\n        Transition sharedAxis = new MaterialSharedAxis(MaterialSharedAxis.Y, false);\n        TransitionManager.beginDelayedTransition(this, sharedAxis);\n        setVisibility(GONE);\n        mSelectionBottomPadding = 0;\n        mInSelectionMode = false;\n        if (mAdapter != null) {\n            //noinspection PointlessNullCheck\n            if (mAdapter.mRecyclerView != null\n                    && mAdapter.mRecyclerView.getFitsSystemWindows()\n                    && mLastInsets != null) {\n                mSelectionBottomPadding += mLastInsets.getSystemWindowInsetBottom();\n            }\n            mAdapter.setInSelectionMode(false);\n            mAdapter.setSelectionBottomPadding(mSelectionBottomPadding);\n        }\n        if (mSelectionModeChangeListener != null) {\n            mSelectionModeChangeListener.onSelectionModeDisabled();\n        }\n    }\n\n    public void setOnItemSelectedListener(MultiSelectionActionsView.OnItemSelectedListener listener) {\n        mSelectionActionsView.setOnItemSelectedListener(listener);\n    }\n\n    public void setOnSelectionChangeListener(OnSelectionChangeListener selectionChangeListener) {\n        mSelectionChangeListener = selectionChangeListener;\n    }\n\n    public void setOnSelectionModeChangeListener(OnSelectionModeChangeListener selectionModeChangeListener) {\n        mSelectionModeChangeListener = selectionModeChangeListener;\n    }\n\n    @SuppressLint(\"SetTextI18n\")\n    @UiThread\n    public void updateCounter(boolean hideOnEmpty) {\n        if (mAdapter == null) {\n            hide();\n            return;\n        }\n        int selectionCount = mAdapter.getSelectedItemCount();\n        if (selectionCount <= 0 && hideOnEmpty) {\n            if (getVisibility() != GONE) hide();\n            if (mSelectionChangeListener != null && mSelectionChangeListener.onSelectionChange(0)) {\n                mSelectionActionsView.updateMenuView();\n            }\n            return;\n        }\n        if (selectionCount > 0) {\n            if (getVisibility() != VISIBLE) show();\n        }\n        int totalItems = mAdapter.getTotalItemCount();\n        mSelectionCounter.setText(String.format(Locale.getDefault(), \"%d/%d\", selectionCount, totalItems));\n        mSelectionCounter.setContentDescription(getContext().getString(R.string.selected_items_accessibility_description, selectionCount, totalItems));\n        mSelectAllView.setChecked(mAdapter.areAllSelected(), false);\n        if (mSelectionChangeListener != null && mSelectionChangeListener.onSelectionChange(selectionCount)) {\n            mSelectionActionsView.updateMenuView();\n        }\n        if (!mAdapter.isInSelectionMode()) {\n            // Special check to avoid displaying the selection panel on resizing the view\n            hide();\n        }\n    }\n\n    private void toggleSelectionActions(int recyclerViewHeight) {\n        if (mMaxHeight * 2 > recyclerViewHeight) {\n            minimize();\n        } else {\n            maximize();\n        }\n    }\n\n    private void minimize() {\n        mCurrentHeight = mTitleHeight;\n        mSelectionActionsView.setVisibility(GONE);\n        mDivider.setVisibility(GONE);\n        requestLayout();\n    }\n\n    private void maximize() {\n        mCurrentHeight = mMaxHeight;\n        mSelectionActionsView.setVisibility(VISIBLE);\n        mDivider.setVisibility(VISIBLE);\n        requestLayout();\n    }\n\n    @SuppressWarnings(\"deprecation\")\n    private void updateMarginAndPosition() {\n        ViewGroup.LayoutParams params = getLayoutParams();\n        if (params instanceof MarginLayoutParams) {\n            int totalLeftMargin = mHorizontalMargin;\n            int totalRightMargin = mHorizontalMargin;\n            int totalBottomMargin = mBottomMargin;\n            if (ViewCompat.getFitsSystemWindows(this) && mLastInsets != null) {\n                totalLeftMargin += mLastInsets.getSystemWindowInsetLeft();\n                totalRightMargin += mLastInsets.getSystemWindowInsetRight();\n                totalBottomMargin += mLastInsets.getSystemWindowInsetBottom();\n            }\n            ((MarginLayoutParams) params).leftMargin = totalLeftMargin;\n            ((MarginLayoutParams) params).rightMargin = totalRightMargin;\n            ((MarginLayoutParams) params).bottomMargin = totalBottomMargin;\n        }\n        try {\n            Field gravity = params.getClass().getField(\"gravity\");\n            gravity.set(params, Gravity.BOTTOM);\n        } catch (NoSuchFieldException | IllegalAccessException ignore) {\n        }\n        setLayoutParams(params);\n    }\n\n    public abstract static class Adapter<VH extends ViewHolder> extends RecyclerView.Adapter<VH> implements View.OnLayoutChangeListener {\n        private interface OnSelectionChangeListener {\n            @UiThread\n            void onSelectionChange();\n        }\n\n        private interface OnLayoutChangeListener {\n            @UiThread\n            void onLayoutChange(RecyclerView v, Rect rect, Rect oldRect);\n        }\n\n        @Nullable\n        private OnSelectionChangeListener mSelectionChangeListener;\n        @Nullable\n        private OnLayoutChangeListener mLayoutChangeListener;\n        private boolean mIsInSelectionMode;\n        @Nullable\n        private RecyclerView mRecyclerView;\n        private int mDefaultBottomPadding;\n\n        public Adapter() {\n            setHasStableIds(true);\n        }\n\n        @AnyThread\n        public abstract long getItemId(int position);\n\n        @UiThread\n        protected abstract boolean select(int position);\n\n        @UiThread\n        protected abstract boolean deselect(int position);\n\n        @AnyThread\n        protected abstract boolean isSelected(int position);\n\n        @AnyThread\n        protected boolean isSelectable(int position) {\n            return true;\n        }\n\n        /**\n         * Cancel the selection process. This should clear all the selected items that may not be displayed in the\n         * {@link RecyclerView} due to filtering, etc.\n         */\n        @UiThread\n        @CallSuper\n        protected void cancelSelection() {\n            deselectAll();\n        }\n\n        @AnyThread\n        protected abstract int getSelectedItemCount();\n\n        @AnyThread\n        protected abstract int getTotalItemCount();\n\n        @AnyThread\n        public final boolean isInSelectionMode() {\n            return mIsInSelectionMode;\n        }\n\n        @AnyThread\n        public final boolean areAllSelected() {\n            for (int position = 0; position < getItemCount(); ++position) {\n                if (isSelectable(position) && !isSelected(position)) {\n                    return false;\n                }\n            }\n            return true;\n        }\n\n        @UiThread\n        public final void notifySelectionChange() {\n            if (mSelectionChangeListener != null) mSelectionChangeListener.onSelectionChange();\n        }\n\n        @AnyThread\n        public final void setInSelectionMode(boolean inSelectionMode) {\n            mIsInSelectionMode = inSelectionMode;\n        }\n\n        @UiThread\n        @CallSuper\n        public void toggleSelection(int position) {\n            if (!isSelectable(position)) {\n                return;\n            }\n            if (isSelected(position)) {\n                if (deselect(position)) {\n                    notifyItemChanged(position, AdapterUtils.STUB);\n                    notifySelectionChange();\n                }\n            } else {\n                if (select(position)) {\n                    notifySelectionChange();\n                    notifyItemChanged(position, AdapterUtils.STUB);\n                }\n            }\n        }\n\n        @UiThread\n        @CallSuper\n        public void selectAll() {\n            int selStart = -1;\n            int selEnd = -1;\n            for (int position = 0; position < getItemCount(); ++position) {\n                if (isSelectable(position) && select(position)) {\n                    if (selStart == -1) {\n                        selStart = position;\n                    }\n                    selEnd = position;\n                }\n            }\n            notifySelectionChange();\n            int selSize = (selEnd - selStart) + 1;\n            if (selSize > 0) {\n                notifyItemRangeChanged(selStart, selSize, AdapterUtils.STUB);\n            }\n        }\n\n        @UiThread\n        @CallSuper\n        public void deselectAll() {\n            for (int position = 0; position < getItemCount(); ++position) {\n                if (isSelectable(position) && isSelected(position) && deselect(position)) {\n                    notifyItemChanged(position, AdapterUtils.STUB);\n                }\n            }\n            notifySelectionChange();\n        }\n\n        @UiThread\n        @CallSuper\n        public void selectRange(int firstPosition, int secondPosition) {\n            int beginPosition = Math.min(firstPosition, secondPosition);\n            int endPosition = Math.max(firstPosition, secondPosition);\n            for (int position = beginPosition; position <= endPosition; ++position) {\n                select(position);\n            }\n            notifySelectionChange();\n            notifyItemRangeChanged(beginPosition, endPosition - beginPosition + 1, AdapterUtils.STUB);\n        }\n\n        @Override\n        public final void onLayoutChange(View v, int left, int top, int right, int bottom,\n                                         int oldLeft, int oldTop, int oldRight, int oldBottom) {\n            if (mLayoutChangeListener == null) return;\n            Rect rect = new Rect(left, top, right, bottom);\n            Rect oldRect = new Rect(oldLeft, oldTop, oldRight, oldBottom);\n            if (rect.width() != oldRect.width() || rect.height() != oldRect.height()) {\n                mLayoutChangeListener.onLayoutChange(mRecyclerView, rect, oldRect);\n            }\n        }\n\n        @AnyThread\n        private void setOnSelectionChangeListener(@Nullable OnSelectionChangeListener listener) {\n            mSelectionChangeListener = listener;\n        }\n\n        @AnyThread\n        private void setOnLayoutChangeListener(@Nullable OnLayoutChangeListener listener) {\n            mLayoutChangeListener = listener;\n        }\n\n        @AnyThread\n        @Nullable\n        private OnLayoutChangeListener getLayoutChangeListener() {\n            return mLayoutChangeListener;\n        }\n\n        /**\n         * @param selectionBottomPadding Set {@code 0} to reset\n         */\n        @UiThread\n        private void setSelectionBottomPadding(@Px int selectionBottomPadding) {\n            if (mRecyclerView == null) return;\n            if (mRecyclerView.getClipToPadding()) {\n                // Clip to padding must be disabled\n                mRecyclerView.setClipToPadding(false);\n            }\n            mRecyclerView.setPadding(mRecyclerView.getPaddingLeft(), mRecyclerView.getPaddingTop(),\n                    mRecyclerView.getPaddingRight(), selectionBottomPadding == 0 ? mDefaultBottomPadding\n                            : selectionBottomPadding);\n        }\n\n        @CallSuper\n        @Override\n        public void onAttachedToRecyclerView(@NonNull RecyclerView recyclerView) {\n            super.onAttachedToRecyclerView(recyclerView);\n            mRecyclerView = recyclerView;\n            mDefaultBottomPadding = recyclerView.getPaddingBottom();\n            recyclerView.addOnLayoutChangeListener(this);\n        }\n\n        @CallSuper\n        @Override\n        public void onDetachedFromRecyclerView(@NonNull RecyclerView recyclerView) {\n            super.onDetachedFromRecyclerView(recyclerView);\n            recyclerView.removeOnLayoutChangeListener(this);\n            mRecyclerView = null;\n        }\n\n        @CallSuper\n        @Override\n        public void onBindViewHolder(@NonNull VH holder, int position) {\n            // Set focus right to select all\n            holder.itemView.setNextFocusRightId(R.id.action_select_all);\n            // Set selection background\n            boolean isSelected = isSelected(position);\n            if (holder.itemView instanceof MaterialCardView) {\n                MaterialCardView cardView = (MaterialCardView) holder.itemView;\n                if (cardView.isCheckable()) {\n                    cardView.setChecked(isSelected);\n                } else if (isSelected) {\n                    throw new UnsupportedOperationException(\"Card is not checkable\");\n                }\n            } else if (isSelected) {\n                holder.itemView.setBackgroundResource(R.drawable.item_highlight);\n            }\n        }\n    }\n\n    public abstract static class ViewHolder extends RecyclerView.ViewHolder {\n        public ViewHolder(@NonNull View itemView) {\n            super(itemView);\n        }\n    }\n}\n"
  },
  {
    "path": "libcore/ui/src/main/java/io/github/muntashirakon/widget/NestedScrollView.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.widget;\n\nimport android.content.Context;\nimport android.content.res.TypedArray;\nimport android.util.AttributeSet;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport io.github.muntashirakon.ui.R;\nimport io.github.muntashirakon.util.UiUtils;\nimport me.zhanghai.android.fastscroll.FastScrollNestedScrollView;\nimport me.zhanghai.android.fastscroll.FastScrollerBuilder;\n\npublic class NestedScrollView extends FastScrollNestedScrollView {\n    public NestedScrollView(@NonNull Context context) {\n        this(context, null);\n    }\n\n    public NestedScrollView(@NonNull Context context, @Nullable AttributeSet attrs) {\n        this(context, attrs, androidx.core.R.attr.nestedScrollViewStyle);\n    }\n\n    public NestedScrollView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {\n        super(context, attrs, defStyleAttr);\n\n        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.NestedScrollView);\n        boolean fastScrollEnabled = a.getBoolean(R.styleable.NestedScrollView_fastScrollerEnabled, false);\n        a.recycle();\n\n        if (fastScrollEnabled) {\n            new FastScrollerBuilder(this).useMd2Style().build();\n        }\n        UiUtils.applyWindowInsetsAsPaddingNoTop(this);\n    }\n}\n"
  },
  {
    "path": "libcore/ui/src/main/java/io/github/muntashirakon/widget/NestedScrollableHost.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\n// This is the java version of NestedScrollableHost\n// Source: https://github.com/android/views-widgets-samples/blob/64bd334762dbe479aae285cadb0d8b2d976381a8/ViewPager2/app/src/main/java/androidx/viewpager2/integration/testapp/NestedScrollableHost.kt\n\npackage io.github.muntashirakon.widget;\n\nimport android.content.Context;\nimport android.util.AttributeSet;\nimport android.view.MotionEvent;\nimport android.view.View;\nimport android.view.ViewConfiguration;\nimport android.widget.FrameLayout;\n\nimport androidx.annotation.AttrRes;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.StyleRes;\nimport androidx.viewpager2.widget.ViewPager2;\n\n/**\n * Layout to wrap a scrollable component inside a ViewPager2. Provided as a solution to the problem\n * where pages of ViewPager2 have nested scrollable elements that scroll in the same direction as\n * ViewPager2. The scrollable element needs to be the immediate and only child of this host layout.\n * <p>\n * This solution has limitations when using multiple levels of nested scrollable elements\n * (e.g. a horizontal RecyclerView in a vertical RecyclerView in a horizontal ViewPager2).\n */\npublic class NestedScrollableHost extends FrameLayout {\n    private int mTouchSlop = 0;\n    private float mInitialX = 0f;\n    private float mInitialY = 0f;\n\n    public NestedScrollableHost(@NonNull Context context) {\n        super(context);\n        init(context);\n    }\n\n    public NestedScrollableHost(@NonNull Context context, @Nullable AttributeSet attrs) {\n        super(context, attrs);\n        init(context);\n    }\n\n    public NestedScrollableHost(@NonNull Context context, @Nullable AttributeSet attrs, @AttrRes int defStyleAttr) {\n        super(context, attrs, defStyleAttr);\n        init(context);\n    }\n\n    public NestedScrollableHost(@NonNull Context context, @Nullable AttributeSet attrs, @AttrRes int defStyleAttr, @StyleRes int defStyleRes) {\n        super(context, attrs, defStyleAttr, defStyleRes);\n        init(context);\n    }\n\n    private void init(Context context) {\n        mTouchSlop = ViewConfiguration.get(context).getScaledTouchSlop();\n    }\n\n    @Nullable\n    public ViewPager2 getParentViewPager() {\n        View v = (View) getParent();\n        while (v != null && !(v instanceof ViewPager2)) {\n            v = (View) v.getParent();\n        }\n        return (ViewPager2) v;\n    }\n\n    @Nullable\n    private View getChild() {\n        return getChildCount() > 0 ? getChildAt(0) : null;\n    }\n\n    @Override\n    public boolean onInterceptTouchEvent(MotionEvent e) {\n        handleInterceptTouchEvent(e);\n        return super.onInterceptTouchEvent(e);\n    }\n\n    private boolean canChildScroll(int orientation, float delta) {\n        int direction = (int) -Math.signum(delta);\n        View child = getChild();\n        if (child == null) {\n            return false;\n        }\n        if (orientation == 0) {\n            return child.canScrollHorizontally(direction);\n        } else if (orientation == 1) {\n            return child.canScrollVertically(direction);\n        } else {\n            throw new IllegalArgumentException();\n        }\n    }\n\n    private void handleInterceptTouchEvent(MotionEvent e) {\n        ViewPager2 parentViewPager = getParentViewPager();\n        if (parentViewPager == null) {\n            return;\n        }\n        int orientation = parentViewPager.getOrientation();\n\n        // Early return if child can't scroll in same direction as parent\n        if (!canChildScroll(orientation, -1f) && !canChildScroll(orientation, 1f)) {\n            return;\n        }\n\n        if (e.getAction() == MotionEvent.ACTION_DOWN) {\n            mInitialX = e.getX();\n            mInitialY = e.getY();\n            getParent().requestDisallowInterceptTouchEvent(true);\n        } else if (e.getAction() == MotionEvent.ACTION_MOVE) {\n            float dx = e.getX() - mInitialX;\n            float dy = e.getY() - mInitialY;\n            boolean isVpHorizontal = orientation == ViewPager2.ORIENTATION_HORIZONTAL;\n\n            // assuming ViewPager2 touch-slop is 2x touch-slop of child\n            float scaledDx = Math.abs(dx) * (isVpHorizontal ? 0.5f : 1f);\n            float scaledDy = Math.abs(dy) * (isVpHorizontal ? 1f : 0.5f);\n\n            if (scaledDx > mTouchSlop || scaledDy > mTouchSlop) {\n                if (isVpHorizontal == (scaledDy > scaledDx)) {\n                    // Gesture is perpendicular, allow all parents to intercept\n                    getParent().requestDisallowInterceptTouchEvent(false);\n                } else {\n                    // Gesture is parallel, query child if movement in that direction is possible\n                    if (canChildScroll(orientation, isVpHorizontal ? dx : dy)) {\n                        // Child can scroll, disallow all parents to intercept\n                        getParent().requestDisallowInterceptTouchEvent(true);\n                    } else {\n                        // Child cannot scroll, allow all parents to intercept\n                        getParent().requestDisallowInterceptTouchEvent(false);\n                    }\n                }\n            }\n        }\n    }\n}"
  },
  {
    "path": "libcore/ui/src/main/java/io/github/muntashirakon/widget/RadioGroupGridLayout.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.widget;\n\nimport android.content.Context;\nimport android.util.AttributeSet;\nimport android.view.View;\nimport android.view.ViewGroup;\nimport android.view.accessibility.AccessibilityEvent;\nimport android.view.accessibility.AccessibilityNodeInfo;\nimport android.widget.CompoundButton;\nimport android.widget.GridLayout;\n\nimport androidx.annotation.NonNull;\nimport androidx.appcompat.widget.AppCompatRadioButton;\n\nimport java.util.concurrent.atomic.AtomicInteger;\n\n/**\n * <p>This class is used to create a multiple-exclusion scope for a set of radio\n * buttons. Checking one radio button that belongs to a radio group unchecks\n * any previously checked radio button within the same group.</p>\n * <p/>\n * <p>Intially, all of the radio buttons are unchecked. While it is not possible\n * to uncheck a particular radio button, the radio group can be cleared to\n * remove the checked state.</p>\n * <p/>\n * <p>The selection is identified by the unique id of the radio button as defined\n * in the XML layout file.</p>\n * <p/>\n * <p>See\n * {@link android.widget.GridLayout.LayoutParams GridLayout.LayoutParams}\n * for layout attributes.</p>\n *\n * @see AppCompatRadioButton\n */\npublic class RadioGroupGridLayout extends GridLayout {\n    private static final AtomicInteger sNextGeneratedId = new AtomicInteger(1);\n    private int mCheckedId = -1;\n    private CompoundButton.OnCheckedChangeListener mChildOnCheckedChangeListener;\n    private boolean mProtectFromCheckedChange = false;\n    private OnCheckedChangeListener mOnCheckedChangeListener;\n    private PassThroughHierarchyChangeListener mPassThroughListener;\n\n    public RadioGroupGridLayout(Context context) {\n        super(context);\n        init();\n    }\n\n    public RadioGroupGridLayout(Context context, AttributeSet attrs) {\n        super(context, attrs);\n        init();\n    }\n\n    private void init() {\n        mChildOnCheckedChangeListener = new CheckedStateTracker();\n        mPassThroughListener = new PassThroughHierarchyChangeListener();\n        super.setOnHierarchyChangeListener(mPassThroughListener);\n    }\n\n    @Override\n    public void setOnHierarchyChangeListener(OnHierarchyChangeListener listener) {\n        mPassThroughListener.mOnHierarchyChangeListener = listener;\n    }\n\n    @Override\n    protected void onFinishInflate() {\n        super.onFinishInflate();\n\n        if (mCheckedId != -1) {\n            mProtectFromCheckedChange = true;\n            setCheckedStateForView(mCheckedId, true);\n            mProtectFromCheckedChange = false;\n            setCheckedId(mCheckedId);\n        }\n    }\n\n    @Override\n    public void addView(@NonNull View child, int index, ViewGroup.LayoutParams params) {\n        if (child instanceof AppCompatRadioButton) {\n            final AppCompatRadioButton button = (AppCompatRadioButton) child;\n            if (button.isChecked()) {\n                mProtectFromCheckedChange = true;\n                if (mCheckedId != -1) {\n                    setCheckedStateForView(mCheckedId, false);\n                }\n                mProtectFromCheckedChange = false;\n                setCheckedId(button.getId());\n            }\n        }\n\n        super.addView(child, index, params);\n    }\n\n    public void check(int id) {\n        if (id != -1 && (id == mCheckedId)) {\n            return;\n        }\n\n        if (mCheckedId != -1) {\n            setCheckedStateForView(mCheckedId, false);\n        }\n\n        if (id != -1) {\n            setCheckedStateForView(id, true);\n        }\n\n        setCheckedId(id);\n    }\n\n    private void setCheckedId(int id) {\n        mCheckedId = id;\n        if (mOnCheckedChangeListener != null) {\n            mOnCheckedChangeListener.onCheckedChanged(this, mCheckedId);\n        }\n    }\n\n    private void setCheckedStateForView(int viewId, boolean checked) {\n        View checkedView = findViewById(viewId);\n        if (checkedView instanceof AppCompatRadioButton) {\n            ((AppCompatRadioButton) checkedView).setChecked(checked);\n        }\n    }\n\n    public int getCheckedCheckableImageButtonId() {\n        return mCheckedId;\n    }\n\n    public void clearCheck() {\n        check(-1);\n    }\n\n    public void setOnCheckedChangeListener(OnCheckedChangeListener listener) {\n        mOnCheckedChangeListener = listener;\n    }\n\n    @Override\n    public void onInitializeAccessibilityEvent(@NonNull AccessibilityEvent event) {\n        super.onInitializeAccessibilityEvent(event);\n        event.setClassName(RadioGroupGridLayout.class.getName());\n    }\n\n    @Override\n    public void onInitializeAccessibilityNodeInfo(@NonNull AccessibilityNodeInfo info) {\n        super.onInitializeAccessibilityNodeInfo(info);\n        info.setClassName(RadioGroupGridLayout.class.getName());\n    }\n\n    public interface OnCheckedChangeListener {\n        void onCheckedChanged(RadioGroupGridLayout group, int checkedId);\n    }\n\n    private class CheckedStateTracker implements CompoundButton.OnCheckedChangeListener {\n        @Override\n        public void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {\n            if (mProtectFromCheckedChange) {\n                return;\n            }\n\n            mProtectFromCheckedChange = true;\n            if (mCheckedId != -1) {\n                setCheckedStateForView(mCheckedId, false);\n            }\n            mProtectFromCheckedChange = false;\n\n            int id = buttonView.getId();\n            setCheckedId(id);\n        }\n    }\n\n    private class PassThroughHierarchyChangeListener implements\n            ViewGroup.OnHierarchyChangeListener {\n        private ViewGroup.OnHierarchyChangeListener mOnHierarchyChangeListener;\n\n        public void onChildViewAdded(View parent, View child) {\n            if (parent == RadioGroupGridLayout.this && child instanceof AppCompatRadioButton) {\n                int id = child.getId();\n                // generates an id if it's missing\n                if (id == View.NO_ID) {\n                    id = generateViewId();\n                    child.setId(id);\n                }\n                ((AppCompatRadioButton) child).setOnCheckedChangeListener(\n                        mChildOnCheckedChangeListener);\n            }\n\n            if (mOnHierarchyChangeListener != null) {\n                mOnHierarchyChangeListener.onChildViewAdded(parent, child);\n            }\n        }\n\n        public void onChildViewRemoved(View parent, View child) {\n            if (parent == RadioGroupGridLayout.this && child instanceof AppCompatRadioButton) {\n                ((AppCompatRadioButton) child).setOnCheckedChangeListener(null);\n            }\n\n            if (mOnHierarchyChangeListener != null) {\n                mOnHierarchyChangeListener.onChildViewRemoved(parent, child);\n            }\n        }\n    }\n\n    public static int generateViewId() {\n        for (; ; ) {\n            final int result = sNextGeneratedId.get();\n\n            // aapt-generated IDs have the high byte nonzero; clamp to the range under that.\n            int newValue = result + 1;\n            if (newValue > 0x00FFFFFF) newValue = 1; // Roll over to 1, not 0.\n\n            if (sNextGeneratedId.compareAndSet(result, newValue)) {\n                return result;\n            }\n        }\n    }\n}"
  },
  {
    "path": "libcore/ui/src/main/java/io/github/muntashirakon/widget/RecyclerView.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.widget;\n\nimport android.content.Context;\nimport android.content.res.TypedArray;\nimport android.util.AttributeSet;\nimport android.view.View;\n\nimport androidx.annotation.CallSuper;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.UiThread;\nimport androidx.recyclerview.widget.LinearLayoutManager;\n\nimport io.github.muntashirakon.ui.R;\nimport io.github.muntashirakon.util.AdapterUtils;\nimport io.github.muntashirakon.util.UiUtils;\nimport me.zhanghai.android.fastscroll.FastScrollerBuilder;\n\npublic class RecyclerView extends androidx.recyclerview.widget.RecyclerView {\n    public static class AdapterDataChangedObserver extends AdapterDataObserver {\n        @Override\n        public void onItemRangeChanged(int positionStart, int itemCount) {\n            onChanged();\n        }\n\n        @Override\n        public void onItemRangeInserted(int positionStart, int itemCount) {\n            onChanged();\n        }\n\n        @Override\n        public void onItemRangeRemoved(int positionStart, int itemCount) {\n            onChanged();\n        }\n\n        @Override\n        public void onItemRangeMoved(int fromPosition, int toPosition, int itemCount) {\n            onChanged();\n        }\n    }\n\n    private View mEmptyView;\n    final private AdapterDataObserver mObserver = new AdapterDataObserver() {\n        @Override\n        public void onChanged() {\n            checkIfEmpty();\n        }\n\n        @Override\n        public void onItemRangeInserted(int positionStart, int itemCount) {\n            checkIfEmpty();\n        }\n\n        @Override\n        public void onItemRangeRemoved(int positionStart, int itemCount) {\n            checkIfEmpty();\n        }\n\n        @Override\n        public void onItemRangeChanged(int positionStart, int itemCount) {\n            checkIfEmpty();\n        }\n\n        @Override\n        public void onItemRangeMoved(int fromPosition, int toPosition, int itemCount) {\n            checkIfEmpty();\n        }\n    };\n\n    public RecyclerView(@NonNull Context context) {\n        this(context, null);\n    }\n\n    public RecyclerView(@NonNull Context context, @Nullable AttributeSet attrs) {\n        this(context, attrs, androidx.recyclerview.R.attr.recyclerViewStyle);\n    }\n\n    public RecyclerView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {\n        super(context, attrs, defStyleAttr);\n        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.RecyclerView);\n        boolean fastScrollEnabled = a.getBoolean(R.styleable.RecyclerView_fastScrollerEnabled, false);\n        a.recycle();\n\n        if (fastScrollEnabled) {\n            new FastScrollerBuilder(this).useMd2Style().build();\n        }\n        UiUtils.applyWindowInsetsAsPaddingNoTop(this);\n    }\n\n    void checkIfEmpty() {\n        if (isInEditMode()) {\n            return;\n        }\n        if (mEmptyView != null && getAdapter() != null) {\n            boolean emptyViewVisible = getAdapter().getItemCount() == 0;\n            mEmptyView.setVisibility(emptyViewVisible ? VISIBLE : GONE);\n            setVisibility(emptyViewVisible ? GONE : VISIBLE);\n        }\n    }\n\n    @UiThread\n    @Override\n    public void setAdapter(@Nullable androidx.recyclerview.widget.RecyclerView.Adapter adapter) {\n        @SuppressWarnings(\"rawtypes\")\n        androidx.recyclerview.widget.RecyclerView.Adapter oldAdapter = getAdapter();\n        if (oldAdapter != null) {\n            oldAdapter.unregisterAdapterDataObserver(mObserver);\n        }\n        super.setAdapter(adapter);\n        if (adapter != null) {\n            adapter.registerAdapterDataObserver(mObserver);\n        }\n        checkIfEmpty();\n    }\n\n    public void setEmptyView(View emptyView) {\n        mEmptyView = emptyView;\n        checkIfEmpty();\n    }\n\n    public void setSelection(int position) {\n        LayoutManager layoutManager = getLayoutManager();\n        if (layoutManager instanceof LinearLayoutManager) {\n            LinearLayoutManager linearLayoutManager = (LinearLayoutManager) layoutManager;\n            linearLayoutManager.scrollToPositionWithOffset(position, 0);\n        }\n    }\n\n    public abstract static class Adapter<VH extends ViewHolder> extends androidx.recyclerview.widget.RecyclerView.Adapter<VH> {\n        @CallSuper\n        @Override\n        public void onViewAttachedToWindow(@NonNull VH holder) {\n            super.onViewAttachedToWindow(holder);\n            AdapterUtils.fixTextSelectionInView(holder);\n        }\n    }\n}\n"
  },
  {
    "path": "libcore/ui/src/main/java/io/github/muntashirakon/widget/RoundedFirstAndLastChildViewGroup.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.widget;\n\nimport android.content.Context;\nimport android.util.AttributeSet;\nimport android.view.View;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport com.google.android.material.shape.ShapeAppearanceModel;\nimport com.google.android.material.shape.Shapeable;\n\nimport io.github.muntashirakon.ui.R;\n\npublic class RoundedFirstAndLastChildViewGroup extends FlowLayout {\n    public RoundedFirstAndLastChildViewGroup(Context context) {\n        this(context, null);\n    }\n\n    public RoundedFirstAndLastChildViewGroup(Context context, @Nullable AttributeSet attrs) {\n        this(context, attrs, 0);\n    }\n\n    public RoundedFirstAndLastChildViewGroup(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {\n        this(context, attrs, defStyleAttr, 0);\n    }\n\n    public RoundedFirstAndLastChildViewGroup(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {\n        super(context, attrs, defStyleAttr, defStyleRes);\n    }\n\n    @Override\n    public void addView(View child, int index, LayoutParams params) {\n        super.addView(child, index, params);\n        updateFirstAndLastViews();\n    }\n\n    private void updateFirstAndLastViews() {\n        int count = getChildCount();\n        switch (count) {\n            case 0:\n                // No children\n                return;\n            case 1: {\n                // Only one view present, make it rounded\n                View v = getChildAt(0);\n                if (v instanceof Shapeable) {\n                    ShapeAppearanceModel model = ShapeAppearanceModel.builder(v.getContext(),\n                                    R.style.ShapeAppearance_AppTheme_LargeComponent, 0)\n                            .build();\n                    ((Shapeable) v).setShapeAppearanceModel(model);\n                }\n                break;\n            }\n            case 2: {\n                // 2 views present, need to set shape for both views\n                View firstView = getChildAt(0);\n                if (firstView instanceof Shapeable) {\n                    ShapeAppearanceModel model = ShapeAppearanceModel.builder(firstView.getContext(),\n                                    R.style.ShapeAppearance_AppTheme_LeftRounded, 0)\n                            .build();\n                    ((Shapeable) firstView).setShapeAppearanceModel(model);\n                }\n                View secondView = getChildAt(count - 1);\n                if (secondView instanceof Shapeable) {\n                    ShapeAppearanceModel model = ShapeAppearanceModel.builder(secondView.getContext(),\n                                    R.style.ShapeAppearance_AppTheme_RightRounded, 0)\n                            .build();\n                    ((Shapeable) secondView).setShapeAppearanceModel(model);\n                }\n                break;\n            }\n            default: {\n                // More than 2 views present\n                View lastView = getChildAt(count - 2);\n                if (lastView instanceof Shapeable) {\n                    // Reset last view\n                    ShapeAppearanceModel model = ShapeAppearanceModel.builder(lastView.getContext(),\n                                    0, 0)\n                            .build();\n                    ((Shapeable) lastView).setShapeAppearanceModel(model);\n                }\n                View thisView = getChildAt(count - 1);\n                if (thisView instanceof Shapeable) {\n                    ShapeAppearanceModel model = ShapeAppearanceModel.builder(thisView.getContext(),\n                                    R.style.ShapeAppearance_AppTheme_RightRounded,\n                                    0)\n                            .build();\n                    ((Shapeable) thisView).setShapeAppearanceModel(model);\n                }\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "libcore/ui/src/main/java/io/github/muntashirakon/widget/SearchView.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.widget;\n\nimport android.annotation.SuppressLint;\nimport android.content.Context;\nimport android.graphics.drawable.Drawable;\nimport android.util.AttributeSet;\nimport android.view.ViewGroup;\nimport android.widget.ImageView;\nimport android.widget.LinearLayout;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.StyleRes;\nimport androidx.appcompat.widget.TintTypedArray;\nimport androidx.core.widget.TextViewCompat;\n\nimport com.google.android.material.internal.ThemeEnforcement;\nimport com.google.android.material.resources.MaterialResources;\nimport com.google.android.material.shape.MaterialShapeDrawable;\nimport com.google.android.material.shape.ShapeAppearanceModel;\nimport com.google.android.material.shape.Shapeable;\n\nimport io.github.muntashirakon.ui.R;\nimport io.github.muntashirakon.view.AutoCompleteTextViewCompat;\n\nimport static com.google.android.material.theme.overlay.MaterialThemeOverlay.wrap;\n\npublic class SearchView extends androidx.appcompat.widget.SearchView implements Shapeable {\n    private static final int DEF_STYLE_RES = R.style.Widget_AppTheme_SearchView;\n\n    @SuppressLint(\"RestrictedApi\")\n    private final SearchAutoComplete mSearchSrcTextView;\n    private final LinearLayout mSearchEditFrame;\n    private final ImageView mCloseButton;\n    private final MaterialShapeDrawable mExpandedSearchViewShapeDrawable;\n    private float mElevation;\n\n    public SearchView(@NonNull Context context) {\n        this(context, null);\n    }\n\n    public SearchView(@NonNull Context context, @Nullable AttributeSet attrs) {\n        this(context, attrs, androidx.appcompat.R.attr.searchViewStyle);\n    }\n\n    public SearchView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {\n        this(context, attrs, defStyleAttr, DEF_STYLE_RES);\n    }\n\n    @SuppressLint(\"RestrictedApi\")\n    public SearchView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr, @StyleRes int defStyleRes) {\n        super(wrap(context, attrs, defStyleAttr, defStyleRes), attrs, defStyleAttr);\n\n        context = getContext();\n        mCloseButton = findViewById(androidx.appcompat.R.id.search_close_btn);\n        mSearchSrcTextView = findViewById(androidx.appcompat.R.id.search_src_text);\n        mSearchEditFrame = findViewById(androidx.appcompat.R.id.search_edit_frame);\n        mElevation = getElevation();\n\n        final TintTypedArray a = ThemeEnforcement.obtainTintedStyledAttributes(\n                context, attrs, R.styleable.SearchView, defStyleAttr, DEF_STYLE_RES);\n\n        int textAppearance = a.getResourceId(R.styleable.SearchView_android_textAppearance, 0);\n        TextViewCompat.setTextAppearance(mSearchSrcTextView, textAppearance);\n\n        mCloseButton.setImageTintList(MaterialResources.getColorStateList(\n                context, a, R.styleable.SearchView_closeIconTint));\n\n        int popupBackgroundResource = a.getResourceId(R.styleable.SearchView_android_popupBackground, 0);\n        if (popupBackgroundResource != 0) {\n            mSearchSrcTextView.setDropDownBackgroundResource(popupBackgroundResource);\n        }\n\n        Drawable popupListSelector = a.getDrawable(R.styleable.SearchView_android_dropDownSelector);\n        if (popupListSelector != null) {\n            AutoCompleteTextViewCompat.setListSelector(mSearchSrcTextView, popupListSelector);\n        }\n\n        int frameMarginHorizontal = a.getDimensionPixelSize(R.styleable.SearchView_frameMarginHorizontal, 0);\n\n        a.recycle();\n        mExpandedSearchViewShapeDrawable = new MaterialShapeDrawable(context, attrs, defStyleAttr, DEF_STYLE_RES);\n        ViewGroup.MarginLayoutParams layoutParams = (MarginLayoutParams) mSearchEditFrame.getLayoutParams();\n        layoutParams.setMarginStart(frameMarginHorizontal);\n        layoutParams.setMarginEnd(frameMarginHorizontal);\n        updateBackgroundExpanded();\n    }\n\n    @NonNull\n    @Override\n    public ShapeAppearanceModel getShapeAppearanceModel() {\n        return mExpandedSearchViewShapeDrawable.getShapeAppearanceModel();\n    }\n\n    @Override\n    public void setShapeAppearanceModel(@NonNull ShapeAppearanceModel shapeAppearanceModel) {\n        mExpandedSearchViewShapeDrawable.setShapeAppearanceModel(shapeAppearanceModel);\n    }\n\n    @Override\n    public void setElevation(float elevation) {\n        mElevation = elevation;\n        super.setElevation(elevation);\n        if (mExpandedSearchViewShapeDrawable != null) {\n            mExpandedSearchViewShapeDrawable.setElevation(elevation);\n        }\n    }\n\n    private void updateBackgroundExpanded() {\n        mExpandedSearchViewShapeDrawable.initializeElevationOverlay(getContext());\n        mExpandedSearchViewShapeDrawable.setElevation(mElevation);\n        setBackground(mExpandedSearchViewShapeDrawable);\n    }\n}\n"
  },
  {
    "path": "libcore/ui/src/main/java/io/github/muntashirakon/widget/SwipeRefreshLayout.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.widget;\n\nimport android.annotation.SuppressLint;\nimport android.content.Context;\nimport android.content.res.TypedArray;\nimport android.util.AttributeSet;\nimport android.util.TypedValue;\n\nimport androidx.annotation.AttrRes;\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\nimport androidx.annotation.StyleRes;\n\nimport com.google.android.material.color.MaterialColors;\nimport com.google.android.material.internal.ThemeEnforcement;\nimport com.google.android.material.theme.overlay.MaterialThemeOverlay;\n\nimport io.github.muntashirakon.ui.R;\n\npublic class SwipeRefreshLayout extends androidx.swiperefreshlayout.widget.SwipeRefreshLayout {\n    private static final int DEFAULT_STYLE_RES = R.style.Widget_AppTheme_SwipeRefreshLayout;\n\n    public SwipeRefreshLayout(@NonNull Context context) {\n        this(context, null);\n    }\n\n    public SwipeRefreshLayout(@NonNull Context context, @Nullable AttributeSet attrs) {\n        this(context, attrs, 0);\n    }\n\n    public SwipeRefreshLayout(@NonNull Context context, @Nullable AttributeSet attrs, @AttrRes final int defStyleAttr) {\n        this(context, attrs, defStyleAttr, DEFAULT_STYLE_RES);\n    }\n\n    public SwipeRefreshLayout(@NonNull Context context, @Nullable AttributeSet attrs, @AttrRes final int defStyleAttr,\n                              @StyleRes final int defStyleRes) {\n        super(MaterialThemeOverlay.wrap(context, attrs, defStyleAttr, DEFAULT_STYLE_RES), attrs);\n\n        // Ensures that we are using the correctly themed context rather than the context that was\n        // passed in.\n        context = getContext();\n\n        // Loads additional attributes for view level.\n        @SuppressLint(\"RestrictedApi\")\n        TypedArray a = ThemeEnforcement.obtainStyledAttributes(context, attrs, R.styleable.SwipeRefreshLayout,\n                defStyleAttr, defStyleRes);\n        try {\n            setProgressBackgroundColorSchemeColor(a.getColor(R.styleable.SwipeRefreshLayout_progressBackgroundColor,\n                    MaterialColors.getColor(context, com.google.android.material.R.attr.colorSurface, -1)));\n            setColorSchemeColors(loadIndicatorColors(context, a));\n        } finally {\n            a.recycle();\n        }\n    }\n\n    @NonNull\n    private static int[] loadIndicatorColors(@NonNull Context context, @NonNull TypedArray typedArray) {\n        if (!typedArray.hasValue(R.styleable.SwipeRefreshLayout_indicatorColor)) {\n            // Uses theme primary color for indicator if not provided in the attribute set.\n            return new int[]{MaterialColors.getColor(context, androidx.appcompat.R.attr.colorPrimary, -1)};\n        }\n\n        TypedValue indicatorColorValue = typedArray.peekValue(R.styleable.SwipeRefreshLayout_indicatorColor);\n\n        if (indicatorColorValue.type != TypedValue.TYPE_REFERENCE) {\n            return new int[]{typedArray.getColor(R.styleable.SwipeRefreshLayout_indicatorColor, -1)};\n        }\n\n        int[] indicatorColors = context.getResources().getIntArray(typedArray.getResourceId(\n                R.styleable.SwipeRefreshLayout_indicatorColor, -1));\n        if (indicatorColors.length == 0) {\n            throw new IllegalArgumentException(\n                    \"indicatorColors cannot be empty when indicatorColor is not used.\");\n        }\n        return indicatorColors;\n    }\n}\n"
  },
  {
    "path": "libcore/ui/src/main/java/io/github/muntashirakon/widget/TextInputTextView.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.widget;\n\nimport android.content.Context;\nimport android.util.AttributeSet;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport com.google.android.material.textfield.TextInputEditText;\n\npublic class TextInputTextView extends TextInputEditText {\n    public TextInputTextView(@NonNull Context context) {\n        this(context, null);\n    }\n\n    public TextInputTextView(@NonNull Context context, @Nullable AttributeSet attrs) {\n        this(context, attrs, androidx.appcompat.R.attr.editTextStyle);\n    }\n\n    public TextInputTextView(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {\n        super(context, attrs, defStyleAttr);\n        setKeyListener(null);\n    }\n}\n"
  },
  {
    "path": "libcore/ui/src/main/res/anim/bottom_sheet_slide_down.xml",
    "content": "<!-- SPDX-License-Identifier: MIT -->\n<set xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <translate\n        android:duration=\"@android:integer/config_mediumAnimTime\"\n        android:fromYDelta=\"0%p\"\n        android:interpolator=\"@android:anim/accelerate_interpolator\"\n        android:toYDelta=\"100%p\" />\n</set>"
  },
  {
    "path": "libcore/ui/src/main/res/anim/bottom_sheet_slide_up.xml",
    "content": "<!-- SPDX-License-Identifier: MIT -->\n<set xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <translate\n        android:duration=\"@android:integer/config_mediumAnimTime\"\n        android:fromYDelta=\"100%p\"\n        android:interpolator=\"@android:anim/accelerate_interpolator\"\n        android:toXDelta=\"0%p\" />\n</set>\n"
  },
  {
    "path": "libcore/ui/src/main/res/anim/fullscreen_dialog_enter.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!-- SPDX-License-Identifier: Apache-2.0 -->\n<set xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:shareInterpolator=\"false\">\n    <alpha\n        android:fromAlpha=\"0\"\n        android:toAlpha=\"1.0\"\n        android:fillEnabled=\"true\"\n        android:fillBefore=\"true\"\n        android:fillAfter=\"true\"\n        android:interpolator=\"@android:interpolator/linear\"\n        android:startOffset=\"50\"\n        android:duration=\"50\" />\n    <scale\n        android:fromXScale=\"0.85\"\n        android:toXScale=\"1\"\n        android:fromYScale=\"0.85\"\n        android:toYScale=\"1\"\n        android:pivotX=\"50%\"\n        android:pivotY=\"50%\"\n        android:fillEnabled=\"true\"\n        android:fillBefore=\"true\"\n        android:fillAfter=\"true\"\n        android:interpolator=\"@android:interpolator/accelerate_decelerate\"\n        android:duration=\"200\" />\n</set>\n"
  },
  {
    "path": "libcore/ui/src/main/res/anim/fullscreen_dialog_exit.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!-- SPDX-License-Identifier: Apache-2.0 -->\n<set xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:shareInterpolator=\"false\">\n    <alpha\n        android:fromAlpha=\"1.0\"\n        android:toAlpha=\"0\"\n        android:fillEnabled=\"true\"\n        android:fillBefore=\"true\"\n        android:fillAfter=\"true\"\n        android:interpolator=\"@android:interpolator/linear\"\n        android:startOffset=\"50\"\n        android:duration=\"100\" />\n    <scale\n        android:fromXScale=\"1\"\n        android:toXScale=\"0.85\"\n        android:fromYScale=\"1\"\n        android:toYScale=\"0.85\"\n        android:pivotX=\"50%\"\n        android:pivotY=\"50%\"\n        android:fillEnabled=\"true\"\n        android:fillBefore=\"true\"\n        android:fillAfter=\"true\"\n        android:interpolator=\"@android:interpolator/accelerate_decelerate\"\n        android:duration=\"250\" />\n</set>\n"
  },
  {
    "path": "libcore/ui/src/main/res/color/bottom_sheet_drag_handle_color.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:color=\"?attr/colorOnSurfaceVariant\" android:alpha=\".4\" />\n</selector>\n"
  },
  {
    "path": "libcore/ui/src/main/res/color/bottom_sheet_drag_handle_color_activated.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:color=\"?attr/colorOnSurfaceVariant\" />\n</selector>\n"
  },
  {
    "path": "libcore/ui/src/main/res/color/tab_item_background_color.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:color=\"?attr/colorPrimary\" android:state_selected=\"true\"/>\n    <item android:color=\"?attr/colorSecondaryContainer\" />\n</selector>\n"
  },
  {
    "path": "libcore/ui/src/main/res/drawable/bottom_sheet_drag_handle.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:shape=\"rectangle\">\n    <corners android:radius=\"16dp\" />\n    <solid android:color=\"@color/bottom_sheet_drag_handle_color\" />\n    <size\n        android:width=\"64dp\"\n        android:height=\"5dp\" />\n</shape>\n"
  },
  {
    "path": "libcore/ui/src/main/res/drawable/bottom_sheet_drag_handle_activated.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:shape=\"rectangle\">\n    <corners android:radius=\"16dp\" />\n    <solid android:color=\"@color/bottom_sheet_drag_handle_color_activated\" />\n    <size\n        android:width=\"64dp\"\n        android:height=\"5dp\" />\n</shape>\n"
  },
  {
    "path": "libcore/ui/src/main/res/drawable/ic_caution.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"?attr/colorControlNormal\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M12,5.99L19.53,19L4.47,19L12,5.99M12,2L1,21h22L12,2zM13,16h-2v2h2v-2zM13,10h-2v4h2v-4z\" />\n</vector>\n"
  },
  {
    "path": "libcore/ui/src/main/res/drawable/ic_clear.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"?attr/colorControlNormal\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M19,6.41L17.59,5 12,10.59 6.41,5 5,6.41 10.59,12 5,17.59 6.41,19 12,13.41 17.59,19 19,17.59 13.41,12z\" />\n</vector>\n"
  },
  {
    "path": "libcore/ui/src/main/res/drawable/ic_information.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24\"\n    android:viewportHeight=\"24\"\n    android:tint=\"?attr/colorControlNormal\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M13.5,4A1.5,1.5 0,0 0,12 5.5A1.5,1.5 0,0 0,13.5 7A1.5,1.5 0,0 0,15 5.5A1.5,1.5 0,0 0,13.5 4M13.14,8.77C11.95,8.87 8.7,11.46 8.7,11.46C8.5,11.61 8.56,11.6 8.72,11.88C8.88,12.15 8.86,12.17 9.05,12.04C9.25,11.91 9.58,11.7 10.13,11.36C12.25,10 10.47,13.14 9.56,18.43C9.2,21.05 11.56,19.7 12.17,19.3C12.77,18.91 14.38,17.8 14.54,17.69C14.76,17.54 14.6,17.42 14.43,17.17C14.31,17 14.19,17.12 14.19,17.12C13.54,17.55 12.35,18.45 12.19,17.88C12,17.31 13.22,13.4 13.89,10.71C14,10.07 14.3,8.67 13.14,8.77Z\" />\n</vector>\n"
  },
  {
    "path": "libcore/ui/src/main/res/drawable/ic_keyboard_backspace.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24.0\"\n    android:viewportHeight=\"24.0\"\n    android:tint=\"?attr/colorControlNormal\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M21,11H6.83l3.58,-3.59L9,6l-6,6 6,6 1.41,-1.41L6.83,13H21z\" />\n</vector>\n"
  },
  {
    "path": "libcore/ui/src/main/res/drawable/ic_more_horiz.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24.0\"\n    android:viewportHeight=\"24.0\"\n    android:tint=\"?attr/colorControlNormal\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M6,10c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2zM18,10c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2zM12,10c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2z\" />\n</vector>\n"
  },
  {
    "path": "libcore/ui/src/main/res/drawable/ic_more_vert.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24.0\"\n    android:viewportHeight=\"24.0\"\n    android:tint=\"?attr/colorControlNormal\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M12,8c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2zM12,10c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2zM12,16c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2z\" />\n</vector>\n"
  },
  {
    "path": "libcore/ui/src/main/res/drawable/ic_search.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:height=\"24dp\"\n    android:viewportHeight=\"24.0\"\n    android:viewportWidth=\"24.0\"\n    android:width=\"24dp\"\n    android:tint=\"?attr/colorControlNormal\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M15.5,14h-0.79l-0.28,-0.27C15.41,12.59 16,11.11 16,9.5 16,5.91 13.09,3 9.5,3S3,5.91 3,9.5 5.91,16 9.5,16c1.61,0 3.09,-0.59 4.23,-1.57l0.27,0.28v0.79l5,4.99L20.49,19l-4.99,-5zM9.5,14C7.01,14 5,11.99 5,9.5S7.01,5 9.5,5 14,7.01 14,9.5 11.99,14 9.5,14z\" />\n</vector>\n"
  },
  {
    "path": "libcore/ui/src/main/res/drawable/ic_spinner_caret.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"24dp\"\n    android:height=\"24dp\"\n    android:viewportWidth=\"24.0\"\n    android:viewportHeight=\"24.0\"\n    android:tint=\"?attr/colorControlNormal\">\n    <path\n        android:fillColor=\"@android:color/white\"\n        android:pathData=\"M7,10l5,5,5-5z\" />\n</vector>\n"
  },
  {
    "path": "libcore/ui/src/main/res/drawable/item_highlight.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<ripple xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:color=\"?attr/colorControlHighlight\">\n    <item>\n        <color android:color=\"@color/highlight\" />\n    </item>\n    <item android:id=\"@android:id/mask\">\n        <color android:color=\"@android:color/white\" />\n    </item>\n</ripple>\n"
  },
  {
    "path": "libcore/ui/src/main/res/drawable/item_semi_transparent.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<ripple xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:color=\"?attr/colorControlHighlight\">\n    <item>\n        <color android:color=\"@color/semi_transparent\" />\n    </item>\n    <item android:id=\"@android:id/mask\">\n        <color android:color=\"@android:color/white\" />\n    </item>\n</ripple>\n"
  },
  {
    "path": "libcore/ui/src/main/res/drawable/item_transparent.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<ripple xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:color=\"?attr/colorControlHighlight\">\n    <item>\n        <color android:color=\"@android:color/transparent\" />\n    </item>\n    <item android:id=\"@android:id/mask\">\n        <color android:color=\"@android:color/white\" />\n    </item>\n</ripple>\n"
  },
  {
    "path": "libcore/ui/src/main/res/drawable/mtrl_switch_thumb_checked_medium.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- Copyright (C) 2022 The Android Open Source Project\n\n     Licensed under the Apache License, Version 2.0 (the \"License\");\n     you may not use this file except in compliance with the License.\n     You may obtain a copy of the License at\n\n         http://www.apache.org/licenses/LICENSE-2.0\n\n     Unless required by applicable law or agreed to in writing, software\n     distributed under the License is distributed on an \"AS IS\" BASIS,\n     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n     See the License for the specific language governing permissions and\n     limitations under the License.\n-->\n\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"@dimen/mtrl_switch_thumb_size_medium\"\n    android:height=\"@dimen/mtrl_switch_thumb_size_medium\"\n    android:viewportHeight=\"@integer/mtrl_switch_thumb_viewport_size\"\n    android:viewportWidth=\"@integer/mtrl_switch_thumb_viewport_size\">\n\n    <group\n        android:name=\"@string/mtrl_switch_thumb_group_name\"\n        android:pivotX=\"@integer/mtrl_switch_thumb_viewport_center_coordinate\"\n        android:pivotY=\"@integer/mtrl_switch_thumb_viewport_center_coordinate\">\n        <path\n            android:name=\"@string/mtrl_switch_thumb_path_name\"\n            android:fillColor=\"#FFFFFFFF\"\n            android:pathData=\"@string/mtrl_switch_thumb_path_checked\" />\n    </group>\n\n</vector>\n"
  },
  {
    "path": "libcore/ui/src/main/res/drawable/mtrl_switch_thumb_checked_pressed_medium.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- Copyright (C) 2022 The Android Open Source Project\n\n     Licensed under the Apache License, Version 2.0 (the \"License\");\n     you may not use this file except in compliance with the License.\n     You may obtain a copy of the License at\n\n         http://www.apache.org/licenses/LICENSE-2.0\n\n     Unless required by applicable law or agreed to in writing, software\n     distributed under the License is distributed on an \"AS IS\" BASIS,\n     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n     See the License for the specific language governing permissions and\n     limitations under the License.\n-->\n\n<animated-vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:aapt=\"http://schemas.android.com/aapt\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:drawable=\"@drawable/mtrl_switch_thumb_checked_medium\"\n    tools:ignore=\"NewApi\">\n\n    <target android:name=\"@string/mtrl_switch_thumb_path_name\">\n        <aapt:attr name=\"android:animation\">\n            <objectAnimator\n                android:duration=\"@integer/mtrl_switch_thumb_pressed_duration\"\n                android:interpolator=\"@interpolator/m3_sys_motion_easing_standard\"\n                android:propertyName=\"pathData\"\n                android:valueFrom=\"@string/mtrl_switch_thumb_path_checked\"\n                android:valueTo=\"@string/mtrl_switch_thumb_path_pressed\"\n                android:valueType=\"pathType\" />\n        </aapt:attr>\n    </target>\n</animated-vector>\n"
  },
  {
    "path": "libcore/ui/src/main/res/drawable/mtrl_switch_thumb_checked_unchecked_medium.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- Copyright (C) 2022 The Android Open Source Project\n\n     Licensed under the Apache License, Version 2.0 (the \"License\");\n     you may not use this file except in compliance with the License.\n     You may obtain a copy of the License at\n\n         http://www.apache.org/licenses/LICENSE-2.0\n\n     Unless required by applicable law or agreed to in writing, software\n     distributed under the License is distributed on an \"AS IS\" BASIS,\n     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n     See the License for the specific language governing permissions and\n     limitations under the License.\n-->\n\n<animated-vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:aapt=\"http://schemas.android.com/aapt\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:drawable=\"@drawable/mtrl_switch_thumb_checked_medium\"\n    tools:ignore=\"NewApi\">\n\n    <set\n        android:interpolator=\"@interpolator/m3_sys_motion_easing_emphasized\"\n        android:shareInterpolator=\"true\">\n        <target android:name=\"@string/mtrl_switch_thumb_path_name\">\n            <aapt:attr name=\"android:animation\">\n                <objectAnimator\n                    android:duration=\"@integer/mtrl_switch_thumb_pre_morphing_duration\"\n                    android:propertyName=\"pathData\"\n                    android:valueFrom=\"@string/mtrl_switch_thumb_path_checked\"\n                    android:valueTo=\"@string/mtrl_switch_thumb_path_morphing\"\n                    android:valueType=\"pathType\" />\n            </aapt:attr>\n        </target>\n        <target android:name=\"@string/mtrl_switch_thumb_path_name\">\n            <aapt:attr name=\"android:animation\">\n                <objectAnimator\n                    android:startOffset=\"@integer/mtrl_switch_thumb_pre_morphing_duration\"\n                    android:duration=\"@integer/mtrl_switch_thumb_post_morphing_duration\"\n                    android:propertyName=\"pathData\"\n                    android:valueFrom=\"@string/mtrl_switch_thumb_path_morphing\"\n                    android:valueTo=\"@string/mtrl_switch_thumb_path_unchecked\"\n                    android:valueType=\"pathType\" />\n            </aapt:attr>\n        </target>\n    </set>\n</animated-vector>\n"
  },
  {
    "path": "libcore/ui/src/main/res/drawable/mtrl_switch_thumb_medium.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<animated-selector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    android:width=\"@dimen/mtrl_switch_thumb_size_medium\"\n    android:height=\"@dimen/mtrl_switch_thumb_size_medium\">\n\n    <item\n        android:id=\"@+id/pressed\"\n        android:drawable=\"@drawable/mtrl_switch_thumb_pressed_medium\"\n        android:state_pressed=\"true\" />\n\n    <item\n        android:id=\"@+id/checked\"\n        android:drawable=\"@drawable/mtrl_switch_thumb_checked_medium\"\n        android:state_checked=\"true\" />\n\n    <item\n        android:id=\"@+id/with_icon\"\n        android:drawable=\"@drawable/mtrl_switch_thumb_checked_medium\"\n        app:state_with_icon=\"true\" />\n\n    <item\n        android:id=\"@+id/unchecked\"\n        android:drawable=\"@drawable/mtrl_switch_thumb_unchecked_medium\" />\n\n    <transition\n        android:fromId=\"@+id/pressed\"\n        android:toId=\"@+id/checked\"\n        android:drawable=\"@drawable/mtrl_switch_thumb_pressed_checked_medium\" />\n\n    <transition\n        android:fromId=\"@+id/pressed\"\n        android:toId=\"@+id/with_icon\"\n        android:drawable=\"@drawable/mtrl_switch_thumb_pressed_checked_medium\" />\n\n    <transition\n        android:fromId=\"@+id/pressed\"\n        android:toId=\"@+id/unchecked\"\n        android:drawable=\"@drawable/mtrl_switch_thumb_pressed_unchecked_medium\" />\n\n    <transition\n        android:fromId=\"@+id/checked\"\n        android:toId=\"@+id/pressed\"\n        android:drawable=\"@drawable/mtrl_switch_thumb_checked_pressed_medium\" />\n\n    <transition\n        android:fromId=\"@+id/checked\"\n        android:toId=\"@+id/unchecked\"\n        android:drawable=\"@drawable/mtrl_switch_thumb_checked_unchecked_medium\" />\n\n    <transition\n        android:fromId=\"@+id/with_icon\"\n        android:toId=\"@+id/pressed\"\n        android:drawable=\"@drawable/mtrl_switch_thumb_checked_pressed_medium\" />\n\n    <transition\n        android:fromId=\"@+id/unchecked\"\n        android:toId=\"@+id/pressed\"\n        android:drawable=\"@drawable/mtrl_switch_thumb_unchecked_pressed_medium\" />\n\n    <transition\n        android:fromId=\"@+id/unchecked\"\n        android:toId=\"@+id/checked\"\n        android:drawable=\"@drawable/mtrl_switch_thumb_unchecked_checked_medium\" />\n\n</animated-selector>\n"
  },
  {
    "path": "libcore/ui/src/main/res/drawable/mtrl_switch_thumb_pressed_checked_medium.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- Copyright (C) 2022 The Android Open Source Project\n\n     Licensed under the Apache License, Version 2.0 (the \"License\");\n     you may not use this file except in compliance with the License.\n     You may obtain a copy of the License at\n\n         http://www.apache.org/licenses/LICENSE-2.0\n\n     Unless required by applicable law or agreed to in writing, software\n     distributed under the License is distributed on an \"AS IS\" BASIS,\n     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n     See the License for the specific language governing permissions and\n     limitations under the License.\n-->\n\n<animated-vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:aapt=\"http://schemas.android.com/aapt\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:drawable=\"@drawable/mtrl_switch_thumb_pressed_medium\"\n    tools:ignore=\"NewApi\">\n\n    <target android:name=\"@string/mtrl_switch_thumb_path_name\">\n        <aapt:attr name=\"android:animation\">\n            <objectAnimator\n                android:duration=\"@integer/mtrl_switch_thumb_pressed_duration\"\n                android:interpolator=\"@interpolator/m3_sys_motion_easing_standard\"\n                android:propertyName=\"pathData\"\n                android:valueFrom=\"@string/mtrl_switch_thumb_path_pressed\"\n                android:valueTo=\"@string/mtrl_switch_thumb_path_checked\"\n                android:valueType=\"pathType\" />\n        </aapt:attr>\n    </target>\n</animated-vector>\n"
  },
  {
    "path": "libcore/ui/src/main/res/drawable/mtrl_switch_thumb_pressed_medium.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- Copyright (C) 2022 The Android Open Source Project\n\n     Licensed under the Apache License, Version 2.0 (the \"License\");\n     you may not use this file except in compliance with the License.\n     You may obtain a copy of the License at\n\n         http://www.apache.org/licenses/LICENSE-2.0\n\n     Unless required by applicable law or agreed to in writing, software\n     distributed under the License is distributed on an \"AS IS\" BASIS,\n     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n     See the License for the specific language governing permissions and\n     limitations under the License.\n-->\n\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"@dimen/mtrl_switch_thumb_size_medium\"\n    android:height=\"@dimen/mtrl_switch_thumb_size_medium\"\n    android:viewportHeight=\"@integer/mtrl_switch_thumb_viewport_size\"\n    android:viewportWidth=\"@integer/mtrl_switch_thumb_viewport_size\">\n\n    <group\n        android:name=\"@string/mtrl_switch_thumb_group_name\"\n        android:pivotX=\"@integer/mtrl_switch_thumb_viewport_center_coordinate\"\n        android:pivotY=\"@integer/mtrl_switch_thumb_viewport_center_coordinate\">\n        <path\n            android:name=\"@string/mtrl_switch_thumb_path_name\"\n            android:fillColor=\"#ffffffff\"\n            android:pathData=\"@string/mtrl_switch_thumb_path_pressed\" />\n    </group>\n\n</vector>\n"
  },
  {
    "path": "libcore/ui/src/main/res/drawable/mtrl_switch_thumb_pressed_unchecked_medium.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- Copyright (C) 2022 The Android Open Source Project\n\n     Licensed under the Apache License, Version 2.0 (the \"License\");\n     you may not use this file except in compliance with the License.\n     You may obtain a copy of the License at\n\n         http://www.apache.org/licenses/LICENSE-2.0\n\n     Unless required by applicable law or agreed to in writing, software\n     distributed under the License is distributed on an \"AS IS\" BASIS,\n     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n     See the License for the specific language governing permissions and\n     limitations under the License.\n-->\n\n<animated-vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:aapt=\"http://schemas.android.com/aapt\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:drawable=\"@drawable/mtrl_switch_thumb_pressed_medium\"\n    tools:ignore=\"NewApi\">\n\n    <target android:name=\"@string/mtrl_switch_thumb_path_name\">\n        <aapt:attr name=\"android:animation\">\n            <objectAnimator\n                android:duration=\"@integer/mtrl_switch_thumb_pressed_duration\"\n                android:interpolator=\"@interpolator/m3_sys_motion_easing_emphasized\"\n                android:propertyName=\"pathData\"\n                android:valueFrom=\"@string/mtrl_switch_thumb_path_pressed\"\n                android:valueTo=\"@string/mtrl_switch_thumb_path_unchecked\"\n                android:valueType=\"pathType\" />\n        </aapt:attr>\n    </target>\n</animated-vector>\n"
  },
  {
    "path": "libcore/ui/src/main/res/drawable/mtrl_switch_thumb_unchecked_checked_medium.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- Copyright (C) 2022 The Android Open Source Project\n\n     Licensed under the Apache License, Version 2.0 (the \"License\");\n     you may not use this file except in compliance with the License.\n     You may obtain a copy of the License at\n\n         http://www.apache.org/licenses/LICENSE-2.0\n\n     Unless required by applicable law or agreed to in writing, software\n     distributed under the License is distributed on an \"AS IS\" BASIS,\n     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n     See the License for the specific language governing permissions and\n     limitations under the License.\n-->\n\n<animated-vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:aapt=\"http://schemas.android.com/aapt\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:drawable=\"@drawable/mtrl_switch_thumb_unchecked_medium\"\n    tools:ignore=\"NewApi\">\n\n    <set\n        android:interpolator=\"@interpolator/m3_sys_motion_easing_emphasized\"\n        android:shareInterpolator=\"true\">\n        <target android:name=\"@string/mtrl_switch_thumb_path_name\">\n            <aapt:attr name=\"android:animation\">\n                <objectAnimator\n                    android:duration=\"@integer/mtrl_switch_thumb_post_morphing_duration\"\n                    android:propertyName=\"pathData\"\n                    android:valueFrom=\"@string/mtrl_switch_thumb_path_unchecked\"\n                    android:valueTo=\"@string/mtrl_switch_thumb_path_morphing\"\n                    android:valueType=\"pathType\" />\n            </aapt:attr>\n        </target>\n        <target android:name=\"@string/mtrl_switch_thumb_path_name\">\n            <aapt:attr name=\"android:animation\">\n                <objectAnimator\n                    android:startOffset=\"@integer/mtrl_switch_thumb_post_morphing_duration\"\n                    android:duration=\"@integer/mtrl_switch_thumb_pre_morphing_duration\"\n                    android:propertyName=\"pathData\"\n                    android:valueFrom=\"@string/mtrl_switch_thumb_path_morphing\"\n                    android:valueTo=\"@string/mtrl_switch_thumb_path_checked\"\n                    android:valueType=\"pathType\" />\n            </aapt:attr>\n        </target>\n    </set>\n</animated-vector>\n"
  },
  {
    "path": "libcore/ui/src/main/res/drawable/mtrl_switch_thumb_unchecked_medium.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- Copyright (C) 2022 The Android Open Source Project\n\n     Licensed under the Apache License, Version 2.0 (the \"License\");\n     you may not use this file except in compliance with the License.\n     You may obtain a copy of the License at\n\n         http://www.apache.org/licenses/LICENSE-2.0\n\n     Unless required by applicable law or agreed to in writing, software\n     distributed under the License is distributed on an \"AS IS\" BASIS,\n     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n     See the License for the specific language governing permissions and\n     limitations under the License.\n-->\n\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:width=\"@dimen/mtrl_switch_thumb_size_medium\"\n    android:height=\"@dimen/mtrl_switch_thumb_size_medium\"\n    android:viewportHeight=\"@integer/mtrl_switch_thumb_viewport_size\"\n    android:viewportWidth=\"@integer/mtrl_switch_thumb_viewport_size\"\n    tools:ignore=\"NewApi\">\n\n    <group\n        android:name=\"@string/mtrl_switch_thumb_group_name\"\n        android:pivotX=\"@integer/mtrl_switch_thumb_viewport_center_coordinate\"\n        android:pivotY=\"@integer/mtrl_switch_thumb_viewport_center_coordinate\">\n        <path\n            android:name=\"@string/mtrl_switch_thumb_path_name\"\n            android:fillColor=\"#FFFFFFFF\"\n            android:pathData=\"@string/mtrl_switch_thumb_path_unchecked\" />\n    </group>\n\n</vector>\n"
  },
  {
    "path": "libcore/ui/src/main/res/drawable/mtrl_switch_thumb_unchecked_pressed_medium.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- Copyright (C) 2022 The Android Open Source Project\n\n     Licensed under the Apache License, Version 2.0 (the \"License\");\n     you may not use this file except in compliance with the License.\n     You may obtain a copy of the License at\n\n         http://www.apache.org/licenses/LICENSE-2.0\n\n     Unless required by applicable law or agreed to in writing, software\n     distributed under the License is distributed on an \"AS IS\" BASIS,\n     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n     See the License for the specific language governing permissions and\n     limitations under the License.\n-->\n\n<animated-vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:aapt=\"http://schemas.android.com/aapt\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:drawable=\"@drawable/mtrl_switch_thumb_unchecked_medium\"\n    tools:ignore=\"NewApi\">\n\n    <target android:name=\"@string/mtrl_switch_thumb_path_name\">\n        <aapt:attr name=\"android:animation\">\n            <objectAnimator\n                android:duration=\"@integer/mtrl_switch_thumb_pressed_duration\"\n                android:interpolator=\"@interpolator/m3_sys_motion_easing_standard\"\n                android:propertyName=\"pathData\"\n                android:valueFrom=\"@string/mtrl_switch_thumb_path_unchecked\"\n                android:valueTo=\"@string/mtrl_switch_thumb_path_pressed\"\n                android:valueType=\"pathType\" />\n        </aapt:attr>\n    </target>\n</animated-vector>\n"
  },
  {
    "path": "libcore/ui/src/main/res/drawable/mtrl_switch_track_decoration_medium.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"@dimen/mtrl_switch_track_width_medium\"\n    android:height=\"@dimen/mtrl_switch_track_height_medium\"\n    android:viewportWidth=\"@integer/mtrl_switch_track_viewport_width\"\n    android:viewportHeight=\"@integer/mtrl_switch_track_viewport_height\">\n\n    <path\n        android:name=\"outline\"\n        android:strokeColor=\"?attr/colorOutline\"\n        android:strokeWidth=\"2\"\n        android:pathData=\"@string/mtrl_switch_track_decoration_path\" />\n\n</vector>"
  },
  {
    "path": "libcore/ui/src/main/res/drawable/mtrl_switch_track_medium.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<vector xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:width=\"@dimen/mtrl_switch_track_width_medium\"\n    android:height=\"@dimen/mtrl_switch_track_height_medium\"\n    android:viewportWidth=\"52\"\n    android:viewportHeight=\"32\">\n\n    <path\n        android:name=\"track\"\n        android:fillColor=\"#FFFFFFFF\"\n        android:pathData=\"@string/mtrl_switch_track_path\" />\n\n</vector>\n"
  },
  {
    "path": "libcore/ui/src/main/res/drawable/popup_menu_background.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<!-- See: @drawable/m3_popupmenu_background_overlay -->\n<shape xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <solid android:color=\"@macro/m3_comp_menu_container_color\"/>\n\n    <corners\n        android:bottomLeftRadius=\"16dp\"\n        android:bottomRightRadius=\"16dp\"\n        android:topLeftRadius=\"16dp\"\n        android:topRightRadius=\"16dp\"/>\n</shape>\n"
  },
  {
    "path": "libcore/ui/src/main/res/drawable/popup_menu_item_background.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<selector xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item android:state_pressed=\"true\" android:drawable=\"@drawable/popup_menu_item_background_ripple\" />\n    <item android:state_focused=\"true\" android:drawable=\"@drawable/popup_menu_item_background_ripple\" />\n    <item android:drawable=\"@android:color/transparent\" />\n</selector>\n"
  },
  {
    "path": "libcore/ui/src/main/res/drawable/popup_menu_item_background_ripple.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<ripple xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:color=\"?colorControlHighlight\">\n\n    <item android:id=\"@android:id/mask\">\n        <shape android:shape=\"rectangle\">\n            <solid android:color=\"@android:color/white\" />\n            <corners android:radius=\"16dp\" />\n        </shape>\n    </item>\n</ripple>"
  },
  {
    "path": "libcore/ui/src/main/res/drawable/spinner_rounded_border.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<ripple xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:color=\"?attr/colorControlHighlight\">\n    <item>\n        <shape>\n            <solid android:color=\"@android:color/transparent\" />\n            <stroke\n                android:width=\"1dip\"\n                android:color=\"?android:attr/colorAccent\" />\n            <corners android:radius=\"15dp\" />\n        </shape>\n    </item>\n    <item\n        android:drawable=\"@drawable/ic_spinner_caret\"\n        android:gravity=\"end|center_vertical\"\n        android:right=\"@dimen/padding_small\" />\n</ripple>\n"
  },
  {
    "path": "libcore/ui/src/main/res/drawable/tab_item_background_rounded.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<layer-list xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item\n        android:top=\"@dimen/padding_small\"\n        android:bottom=\"@dimen/padding_small\"\n        android:left=\"@dimen/padding_very_small\"\n        android:right=\"@dimen/padding_very_small\">\n        <shape android:shape=\"rectangle\">\n            <solid android:color=\"@color/tab_item_background_color\" />\n            <corners android:radius=\"16dp\" />\n        </shape>\n    </item>\n</layer-list>\n"
  },
  {
    "path": "libcore/ui/src/main/res/drawable-v23/popup_menu_background.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<!-- See: @drawable/m3_popupmenu_background_overlay -->\n<layer-list xmlns:android=\"http://schemas.android.com/apk/res/android\">\n    <item>\n        <shape>\n            <solid android:color=\"@macro/m3_comp_menu_container_color\" />\n            <corners\n                android:bottomLeftRadius=\"16dp\"\n                android:bottomRightRadius=\"16dp\"\n                android:topLeftRadius=\"16dp\"\n                android:topRightRadius=\"16dp\" />\n        </shape>\n    </item>\n    <item>\n        <shape>\n            <solid android:color=\"@color/m3_popupmenu_overlay_color\" />\n            <corners\n                android:bottomLeftRadius=\"16dp\"\n                android:bottomRightRadius=\"16dp\"\n                android:topLeftRadius=\"16dp\"\n                android:topRightRadius=\"16dp\" />\n        </shape>\n    </item>\n</layer-list>\n"
  },
  {
    "path": "libcore/ui/src/main/res/layout/auto_complete_dropdown_item.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<io.github.muntashirakon.widget.AlwaysFocusedCheckedTextView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:id=\"@android:id/text1\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:paddingVertical=\"13dp\"\n    android:paddingHorizontal=\"16dp\"\n    android:ellipsize=\"marquee\"\n    android:marqueeRepeatLimit=\"marquee_forever\"\n    android:singleLine=\"true\"\n    android:textAppearance=\"?attr/textAppearanceBodyLarge\"\n    tools:text=\"@tools:sample/lorem/random\" />\n"
  },
  {
    "path": "libcore/ui/src/main/res/layout/auto_complete_dropdown_item_small.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<io.github.muntashirakon.widget.AlwaysFocusedCheckedTextView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:id=\"@android:id/text1\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:paddingVertical=\"8dp\"\n    android:paddingHorizontal=\"16dp\"\n    android:ellipsize=\"marquee\"\n    android:marqueeRepeatLimit=\"marquee_forever\"\n    android:singleLine=\"true\"\n    android:textAppearance=\"?attr/textAppearanceBodyMedium\"\n    tools:text=\"@tools:sample/lorem/random\" />\n"
  },
  {
    "path": "libcore/ui/src/main/res/layout/dialog_bottom_sheet.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 -->\n<FrameLayout\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:id=\"@+id/container\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:fitsSystemWindows=\"true\">\n\n    <androidx.coordinatorlayout.widget.CoordinatorLayout\n        android:id=\"@+id/coordinator\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"match_parent\"\n        android:fitsSystemWindows=\"true\">\n\n        <View\n            android:id=\"@+id/touch_outside\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"match_parent\"\n            android:focusable=\"false\"\n            android:importantForAccessibility=\"no\"\n            android:soundEffectsEnabled=\"false\"\n            tools:ignore=\"UnusedAttribute\"/>\n\n        <FrameLayout\n            android:id=\"@+id/design_bottom_sheet\"\n            style=\"?attr/bottomSheetStyle\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_gravity=\"center_horizontal|top\"\n            app:layout_behavior=\"io.github.muntashirakon.dialog.BottomSheetBehavior\"/>\n\n    </androidx.coordinatorlayout.widget.CoordinatorLayout>\n\n</FrameLayout>\n"
  },
  {
    "path": "libcore/ui/src/main/res/layout/dialog_bottom_sheet_alert.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<androidx.appcompat.widget.LinearLayoutCompat xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:orientation=\"vertical\">\n\n    <io.github.muntashirakon.widget.NestedScrollView\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:scrollbars=\"vertical\"\n        android:scrollIndicators=\"top|bottom\"\n        tools:ignore=\"UnusedAttribute\">\n\n        <androidx.appcompat.widget.LinearLayoutCompat\n            android:id=\"@+id/container\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:orientation=\"vertical\">\n\n            <com.google.android.material.textview.MaterialTextView\n                android:id=\"@android:id/text1\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:paddingHorizontal=\"@dimen/padding_medium\"\n                android:overScrollMode=\"never\"\n                tools:text=\"@tools:sample/lorem[100]\" />\n\n        </androidx.appcompat.widget.LinearLayoutCompat>\n\n    </io.github.muntashirakon.widget.NestedScrollView>\n\n    <RelativeLayout\n        android:id=\"@+id/action_container\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"?attr/actionBarSize\"\n        android:layout_gravity=\"bottom\"\n        android:paddingHorizontal=\"@dimen/padding_medium\"\n        android:visibility=\"gone\"\n        tools:visibility=\"visible\">\n\n        <com.google.android.material.button.MaterialButton\n            android:id=\"@+id/action_primary\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_alignParentEnd=\"true\"\n            android:layout_centerInParent=\"true\"\n            android:layout_marginStart=\"@dimen/padding_small\"\n            android:visibility=\"gone\"\n            tools:visibility=\"visible\"\n            tools:text=\"Primary\" />\n\n        <com.google.android.material.button.MaterialButton\n            style=\"@style/Widget.AppTheme.Button.FilledTonalButton\"\n            android:id=\"@+id/action_secondary\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_toStartOf=\"@id/action_primary\"\n            android:layout_centerInParent=\"true\"\n            android:layout_marginStart=\"@dimen/padding_small\"\n            android:visibility=\"gone\"\n            tools:visibility=\"visible\"\n            tools:text=\"Secondary\" />\n\n        <com.google.android.material.button.MaterialButton\n            style=\"@style/Widget.AppTheme.Button.IconButton\"\n            android:id=\"@+id/action_more\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_toStartOf=\"@id/action_secondary\"\n            android:layout_centerInParent=\"true\"\n            android:minWidth=\"48dp\"\n            android:maxWidth=\"0dp\"\n            android:maxHeight=\"0dp\"\n            app:icon=\"@drawable/ic_more_vert\"\n            app:iconSize=\"24dp\"\n            android:visibility=\"gone\"\n            tools:visibility=\"visible\" />\n\n    </RelativeLayout>\n\n</androidx.appcompat.widget.LinearLayoutCompat>\n"
  },
  {
    "path": "libcore/ui/src/main/res/layout/dialog_bottom_sheet_capsule.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<androidx.appcompat.widget.LinearLayoutCompat xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:orientation=\"vertical\">\n\n    <!-- We cannot afford 48dp height -->\n    <com.google.android.material.bottomsheet.BottomSheetDragHandleView\n        android:id=\"@+id/capsule\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:minHeight=\"35dp\"\n        app:srcCompat=\"@null\"\n        tools:srcCompat=\"@drawable/bottom_sheet_drag_handle\" />\n\n    <androidx.appcompat.widget.LinearLayoutCompat\n        android:id=\"@+id/header\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:orientation=\"vertical\">\n\n<!--        <include layout=\"@layout/dialog_title_with_two_icons\" />-->\n\n    </androidx.appcompat.widget.LinearLayoutCompat>\n\n    <FrameLayout\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\">\n\n        <androidx.appcompat.widget.LinearLayoutCompat\n            android:id=\"@+id/body\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:orientation=\"vertical\" />\n\n        <RelativeLayout\n            android:id=\"@+id/loader\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"240dp\">\n\n            <com.google.android.material.progressindicator.CircularProgressIndicator\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_centerInParent=\"true\"\n                android:indeterminate=\"true\" />\n\n        </RelativeLayout>\n\n    </FrameLayout>\n\n</androidx.appcompat.widget.LinearLayoutCompat>\n"
  },
  {
    "path": "libcore/ui/src/main/res/layout/dialog_scrollable_text_view.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<androidx.core.widget.NestedScrollView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:id=\"@+id/scrollView\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:layout_marginTop=\"@dimen/padding_medium\"\n    android:scrollIndicators=\"top|bottom\"\n    android:fitsSystemWindows=\"true\"\n    android:clipToPadding=\"false\"\n    tools:ignore=\"UnusedAttribute\">\n\n    <androidx.appcompat.widget.LinearLayoutCompat\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:orientation=\"vertical\"\n        android:paddingVertical=\"@dimen/padding_small\"\n        android:paddingHorizontal=\"@dimen/padding_medium\">\n\n        <com.google.android.material.textview.MaterialTextView\n            android:id=\"@android:id/content\"\n            android:textIsSelectable=\"true\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            tools:text=\"@tools:sample/lorem/random\" />\n\n        <com.google.android.material.checkbox.MaterialCheckBox\n            android:id=\"@android:id/checkbox\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            tools:text=\"Never show this again\" />\n\n    </androidx.appcompat.widget.LinearLayoutCompat>\n\n</androidx.core.widget.NestedScrollView>"
  },
  {
    "path": "libcore/ui/src/main/res/layout/dialog_searchable_multi_choice.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<androidx.appcompat.widget.LinearLayoutCompat xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:orientation=\"vertical\">\n\n    <io.github.muntashirakon.widget.SearchView\n        style=\"@style/Widget.AppTheme.SearchView.Small\"\n        android:id=\"@+id/action_search\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"40dp\"\n        android:layout_marginHorizontal=\"@dimen/padding_medium\"\n        app:iconifiedByDefault=\"false\" />\n\n    <io.github.muntashirakon.widget.CheckBox\n        android:id=\"@android:id/checkbox\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"48dp\"\n        android:layout_gravity=\"center_vertical\"\n        android:layout_marginStart=\"@dimen/padding_medium\"\n        android:layout_marginEnd=\"@dimen/padding_medium\"\n        android:text=\"@string/select_all\" />\n\n    <io.github.muntashirakon.widget.RecyclerView\n        android:id=\"@android:id/list\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:scrollIndicators=\"top|bottom\"\n        android:scrollbars=\"none\"\n        app:fastScrollerEnabled=\"true\"\n        tools:ignore=\"UnusedAttribute\"\n        tools:listitem=\"@layout/mtrl_alert_select_dialog_multichoice\" />\n\n</androidx.appcompat.widget.LinearLayoutCompat>"
  },
  {
    "path": "libcore/ui/src/main/res/layout/dialog_searchable_single_choice.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<androidx.appcompat.widget.LinearLayoutCompat xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:orientation=\"vertical\">\n\n    <io.github.muntashirakon.widget.SearchView\n        style=\"@style/Widget.AppTheme.SearchView.Small\"\n        android:id=\"@+id/action_search\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"40dp\"\n        android:layout_weight=\"0\"\n        android:layout_marginHorizontal=\"@dimen/padding_medium\"\n        app:iconifiedByDefault=\"false\" />\n\n    <io.github.muntashirakon.widget.RecyclerView\n        android:id=\"@android:id/list\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_weight=\"1\"\n        android:scrollIndicators=\"top|bottom\"\n        android:scrollbars=\"none\"\n        app:fastScrollerEnabled=\"true\"\n        tools:ignore=\"UnusedAttribute\"\n        tools:listitem=\"@layout/mtrl_alert_select_dialog_singlechoice\"\n        tools:itemCount=\"50\"/>\n\n    <FrameLayout\n        android:id=\"@+id/container\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_weight=\"0\" />\n\n</androidx.appcompat.widget.LinearLayoutCompat>"
  },
  {
    "path": "libcore/ui/src/main/res/layout/dialog_text_input.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<ScrollView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:layout_marginTop=\"@dimen/padding_medium\"\n    android:scrollIndicators=\"top|bottom\"\n    tools:theme=\"@style/AppTheme\"\n    tools:ignore=\"UnusedAttribute\">\n\n    <androidx.appcompat.widget.LinearLayoutCompat\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:orientation=\"vertical\"\n        android:paddingVertical=\"@dimen/padding_small\"\n        android:paddingHorizontal=\"@dimen/padding_medium\">\n\n        <com.google.android.material.textfield.TextInputLayout\n            android:id=\"@android:id/text1\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            tools:hint=\"Primary Input\"\n            tools:helperText=\"Primary input helper text\"\n            app:hintAnimationEnabled=\"true\"\n            app:hintEnabled=\"true\">\n\n            <com.google.android.material.textfield.TextInputEditText\n                android:id=\"@android:id/input\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                tools:text=\"@tools:sample/lorem[4]\" />\n\n        </com.google.android.material.textfield.TextInputLayout>\n\n        <com.google.android.material.checkbox.MaterialCheckBox\n            android:id=\"@android:id/checkbox\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            tools:text=\"Apply to all\" />\n\n    </androidx.appcompat.widget.LinearLayoutCompat>\n</ScrollView>"
  },
  {
    "path": "libcore/ui/src/main/res/layout/dialog_text_input_dropdown.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<ScrollView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"match_parent\"\n    android:layout_marginTop=\"@dimen/padding_medium\"\n    android:scrollIndicators=\"top|bottom\"\n    tools:theme=\"@style/AppTheme\"\n    tools:ignore=\"UnusedAttribute\">\n\n    <androidx.appcompat.widget.LinearLayoutCompat\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:orientation=\"vertical\"\n        android:paddingVertical=\"@dimen/padding_small\"\n        android:paddingHorizontal=\"16dp\">\n\n        <com.google.android.material.textfield.TextInputLayout\n            android:id=\"@android:id/text1\"\n            style=\"@style/Widget.AppTheme.TextInputLayout.ExposedDropdownMenu\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            tools:hint=\"Principle Input\"\n            tools:helperText=\"Principle input helper text\"\n            app:hintAnimationEnabled=\"true\"\n            app:hintEnabled=\"true\">\n\n            <io.github.muntashirakon.widget.MaterialAutoCompleteTextView\n                android:id=\"@android:id/input\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:singleLine=\"true\"\n                tools:text=\"@tools:sample/full_names\" />\n\n        </com.google.android.material.textfield.TextInputLayout>\n\n        <com.google.android.material.textfield.TextInputLayout\n            android:id=\"@android:id/text2\"\n            style=\"@style/Widget.AppTheme.TextInputLayout.ExposedDropdownMenu\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            tools:hint=\"Auxiliary Input\"\n            tools:helperText=\"Auxiliary input helper text.\"\n            app:hintAnimationEnabled=\"true\"\n            app:hintEnabled=\"true\">\n\n            <io.github.muntashirakon.widget.MaterialAutoCompleteTextView\n                android:id=\"@android:id/custom\"\n                android:layout_width=\"match_parent\"\n                android:layout_height=\"wrap_content\"\n                android:singleLine=\"true\"\n                tools:text=\"@tools:sample/full_names\" />\n\n        </com.google.android.material.textfield.TextInputLayout>\n\n        <com.google.android.material.checkbox.MaterialCheckBox\n            android:id=\"@android:id/checkbox\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            tools:text=\"Apply to all\" />\n\n    </androidx.appcompat.widget.LinearLayoutCompat>\n</ScrollView>"
  },
  {
    "path": "libcore/ui/src/main/res/layout/dialog_title_toolbar.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<com.google.android.material.appbar.AppBarLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:id=\"@+id/appbar\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:fitsSystemWindows=\"true\"\n    app:liftOnScroll=\"true\"\n    app:liftOnScrollTargetViewId=\"@id/scrollView\">\n\n    <com.google.android.material.appbar.MaterialToolbar\n        android:id=\"@+id/toolbar\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"?attr/actionBarSize\"\n        app:navigationIcon=\"@drawable/ic_clear\"\n        tools:title=\"Full-screen dialog\">\n\n        <com.google.android.material.button.MaterialButton\n            android:id=\"@android:id/button1\"\n            style=\"@style/Widget.AppTheme.Button.TextButton\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_marginEnd=\"@dimen/padding_medium\"\n            android:layout_gravity=\"center_vertical|end\"\n            android:focusable=\"true\"\n            android:clickable=\"true\"\n            android:textAppearance=\"?attr/textAppearanceLabelLarge\"\n            tools:text=\"Save\" />\n\n    </com.google.android.material.appbar.MaterialToolbar>\n\n</com.google.android.material.appbar.AppBarLayout>"
  },
  {
    "path": "libcore/ui/src/main/res/layout/dialog_title_with_two_icons.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<androidx.appcompat.widget.LinearLayoutCompat xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:orientation=\"horizontal\"\n    android:gravity=\"center_vertical|start\"\n    android:paddingHorizontal=\"?attr/dialogPreferredPadding\"\n    android:paddingTop=\"18dp\"\n    tools:theme=\"@style/AppTheme\">\n\n    <FrameLayout\n        android:id=\"@+id/icon_frame\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"match_parent\">\n\n        <androidx.appcompat.widget.AppCompatImageView\n            android:id=\"@+id/icon\"\n            style=\"?attr/materialAlertDialogTitleIconStyle\"\n            android:layout_width=\"32dp\"\n            android:layout_height=\"32dp\"\n            android:layout_marginEnd=\"8dp\"\n            android:layout_gravity=\"top\"\n            tools:srcCompat=\"@drawable/ic_clear\" />\n\n    </FrameLayout>\n\n    <androidx.appcompat.widget.LinearLayoutCompat\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:layout_weight=\"1\"\n        android:orientation=\"vertical\">\n\n        <androidx.appcompat.widget.LinearLayoutCompat\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:orientation=\"horizontal\">\n\n            <com.google.android.material.textview.MaterialTextView\n                android:id=\"@+id/title\"\n                android:ellipsize=\"end\"\n                android:layout_width=\"0dp\"\n                android:layout_height=\"wrap_content\"\n                android:layout_weight=\"1\"\n                android:layout_gravity=\"start\"\n                style=\"?attr/materialAlertDialogTitleTextStyle\"\n                android:textAppearance=\"?attr/textAppearanceHeadlineSmall\"\n                android:textColor=\"?attr/colorOnSurface\"\n                tools:text=\"@tools:sample/lorem[1]\" />\n\n            <com.google.android.material.button.MaterialButton\n                android:id=\"@+id/action\"\n                style=\"@style/Widget.AppTheme.Button.IconButton.InverseColor\"\n                android:layout_width=\"34dp\"\n                android:layout_height=\"34dp\"\n                android:layout_weight=\"0\"\n                android:layout_marginStart=\"8dp\"\n                android:layout_gravity=\"end\"\n                app:icon=\"@drawable/ic_more_vert\"\n                app:iconSize=\"24dp\" />\n\n        </androidx.appcompat.widget.LinearLayoutCompat>\n\n        <com.google.android.material.textview.MaterialTextView\n            android:id=\"@+id/subtitle\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_weight=\"0\"\n            android:layout_marginBottom=\"8dp\"\n            style=\"?attr/materialAlertDialogTitleTextStyle\"\n            android:textAlignment=\"viewStart\"\n            android:textAppearance=\"?attr/textAppearanceBodyMedium\"\n            android:textColor=\"?attr/colorOnSurfaceVariant\"\n            tools:text=\"@tools:sample/lorem[30]\" />\n\n    </androidx.appcompat.widget.LinearLayoutCompat>\n\n</androidx.appcompat.widget.LinearLayoutCompat>"
  },
  {
    "path": "libcore/ui/src/main/res/layout/item_reflow_menu.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-or-later -->\n<androidx.appcompat.widget.LinearLayoutCompat xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:orientation=\"vertical\"\n    android:layout_width=\"wrap_content\"\n    android:layout_height=\"wrap_content\"\n    android:layout_gravity=\"center_horizontal\"\n    android:minWidth=\"80dp\"\n    android:paddingTop=\"12dp\"\n    android:paddingBottom=\"12dp\"\n    android:paddingStart=\"6dp\"\n    android:paddingEnd=\"6dp\"\n    android:background=\"?attr/selectableItemBackgroundBorderless\"\n    android:gravity=\"center_horizontal\">\n\n    <androidx.appcompat.widget.AppCompatImageView\n        android:id=\"@+id/icon\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_marginBottom=\"4dp\"\n        tools:src=\"@drawable/ic_information\" />\n\n    <TextView\n        android:id=\"@+id/label\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:textAppearance=\"?attr/textAppearanceBodyMedium\"\n        android:gravity=\"center_horizontal\"\n        android:maxLines=\"1\"\n        android:ellipsize=\"end\"\n        tools:text=\"Info\" />\n\n</androidx.appcompat.widget.LinearLayoutCompat>\n"
  },
  {
    "path": "libcore/ui/src/main/res/layout/m3_alert_select_dialog_item.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<com.google.android.material.card.MaterialCardView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    style=\"@style/Widget.AppTheme.CardView.ListItem\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:minHeight=\"?android:attr/listPreferredItemHeightSmall\"\n    android:focusable=\"true\"\n    android:layout_marginHorizontal=\"?attr/listItemMarginHorizontal\">\n\n    <androidx.appcompat.widget.LinearLayoutCompat\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:gravity=\"center_vertical\"\n        android:paddingStart=\"?android:attr/listPreferredItemPaddingStart\"\n        android:paddingEnd=\"?android:attr/listPreferredItemPaddingEnd\"\n        android:clipToPadding=\"false\"\n        android:baselineAligned=\"false\">\n\n        <include layout=\"@layout/m3_preference_image_frame\" />\n\n        <TextView\n            android:id=\"@android:id/text1\"\n            android:layout_width=\"0dp\"\n            android:layout_height=\"wrap_content\"\n            android:layout_weight=\"1\"\n            android:minHeight=\"?attr/listPreferredItemHeightSmall\"\n            style=\"?attr/materialAlertDialogListItemTextStyle\"\n            android:gravity=\"center_vertical\"\n            android:ellipsize=\"marquee\"\n            android:paddingTop=\"8dp\"\n            android:paddingBottom=\"8dp\"\n            tools:text=\"@tools:sample/lorem/random\" />\n\n        <!-- Preference should place its actual preference widget here. -->\n        <androidx.appcompat.widget.LinearLayoutCompat\n            android:id=\"@android:id/widget_frame\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"match_parent\"\n            android:gravity=\"end|center_vertical\"\n            android:paddingStart=\"16dp\"\n            android:paddingEnd=\"0dp\"\n            android:orientation=\"vertical\" />\n\n    </androidx.appcompat.widget.LinearLayoutCompat>\n</com.google.android.material.card.MaterialCardView>\n"
  },
  {
    "path": "libcore/ui/src/main/res/layout/m3_preference.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-or-later -->\n<com.google.android.material.card.MaterialCardView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    style=\"@style/Widget.AppTheme.CardView.ListItem\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:minHeight=\"?android:attr/listPreferredItemHeightSmall\"\n    android:focusable=\"true\"\n    android:layout_marginHorizontal=\"?attr/listItemMarginHorizontal\">\n\n    <androidx.appcompat.widget.LinearLayoutCompat\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:gravity=\"center_vertical\"\n        android:paddingStart=\"?android:attr/listPreferredItemPaddingStart\"\n        android:paddingEnd=\"?android:attr/listPreferredItemPaddingEnd\"\n        android:clipToPadding=\"false\"\n        android:baselineAligned=\"false\">\n\n        <include layout=\"@layout/m3_preference_image_frame\" />\n\n        <RelativeLayout\n            android:layout_width=\"0dp\"\n            android:layout_height=\"wrap_content\"\n            android:layout_weight=\"1\"\n            android:paddingTop=\"16dp\"\n            android:paddingBottom=\"16dp\">\n\n            <com.google.android.material.textview.MaterialTextView\n                android:id=\"@android:id/title\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:singleLine=\"true\"\n                android:textAppearance=\"?android:attr/textAppearanceListItem\"\n                android:ellipsize=\"marquee\"\n                tools:text=\"@tools:sample/lorem[10]\" />\n\n            <com.google.android.material.textview.MaterialTextView\n                android:id=\"@android:id/summary\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_below=\"@android:id/title\"\n                android:layout_alignLeft=\"@android:id/title\"\n                android:layout_alignStart=\"@android:id/title\"\n                android:layout_gravity=\"start\"\n                android:textAlignment=\"viewStart\"\n                android:textAppearance=\"?android:attr/textAppearanceListItemSecondary\"\n                android:maxLines=\"10\"\n                tools:text=\"@tools:sample/lorem[10]\" />\n\n        </RelativeLayout>\n\n        <!-- Preference should place its actual preference widget here. -->\n        <androidx.appcompat.widget.LinearLayoutCompat\n            android:id=\"@android:id/widget_frame\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"match_parent\"\n            android:gravity=\"end|center_vertical\"\n            android:paddingStart=\"16dp\"\n            android:paddingEnd=\"0dp\"\n            android:orientation=\"vertical\" />\n\n    </androidx.appcompat.widget.LinearLayoutCompat>\n</com.google.android.material.card.MaterialCardView>\n"
  },
  {
    "path": "libcore/ui/src/main/res/layout/m3_preference_alert.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-or-later -->\n<com.google.android.material.card.MaterialCardView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    style=\"@style/Widget.AppTheme.CardView.ListItem\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:minHeight=\"?android:attr/listPreferredItemHeightSmall\"\n    android:focusable=\"false\"\n    android:layout_marginVertical=\"4dp\"\n    android:layout_marginHorizontal=\"?attr/listItemMarginHorizontal\">\n\n    <androidx.appcompat.widget.LinearLayoutCompat\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:orientation=\"vertical\"\n        android:gravity=\"center_vertical\"\n        android:paddingStart=\"?android:attr/listPreferredItemPaddingStart\"\n        android:paddingEnd=\"?android:attr/listPreferredItemPaddingEnd\"\n        android:paddingTop=\"16dp\"\n        android:paddingBottom=\"16dp\"\n        android:clipToPadding=\"false\"\n        android:baselineAligned=\"false\">\n\n        <include layout=\"@layout/m3_preference_image_frame\" />\n\n        <View\n            android:id=\"@android:id/empty\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"16dp\"\n            android:layout_weight=\"0\" />\n\n        <RelativeLayout\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"0dp\"\n            android:layout_weight=\"1\">\n\n            <com.google.android.material.textview.MaterialTextView\n                android:id=\"@android:id/title\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:singleLine=\"true\"\n                android:textAppearance=\"?android:attr/textAppearanceListItem\"\n                android:ellipsize=\"marquee\"\n                tools:text=\"@tools:sample/lorem[10]\" />\n\n            <com.google.android.material.textview.MaterialTextView\n                android:id=\"@android:id/summary\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_below=\"@android:id/title\"\n                android:layout_alignLeft=\"@android:id/title\"\n                android:layout_alignStart=\"@android:id/title\"\n                android:layout_gravity=\"start\"\n                android:textAlignment=\"viewStart\"\n                android:textAppearance=\"?android:attr/textAppearanceListItemSecondary\"\n                android:maxLines=\"10\"\n                tools:text=\"@tools:sample/lorem[10]\" />\n\n        </RelativeLayout>\n\n        <!-- Preference should place its actual preference widget here. -->\n        <androidx.appcompat.widget.LinearLayoutCompat\n            android:id=\"@android:id/widget_frame\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:gravity=\"end|center_vertical\"\n            android:paddingStart=\"16dp\"\n            android:paddingEnd=\"0dp\"\n            android:orientation=\"vertical\" />\n\n    </androidx.appcompat.widget.LinearLayoutCompat>\n</com.google.android.material.card.MaterialCardView>\n"
  },
  {
    "path": "libcore/ui/src/main/res/layout/m3_preference_button.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-or-later -->\n<androidx.appcompat.widget.LinearLayoutCompat xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    android:gravity=\"center_vertical\"\n    android:minHeight=\"?android:attr/listPreferredItemHeightSmall\"\n    android:paddingStart=\"?android:attr/listPreferredItemPaddingStart\"\n    android:paddingEnd=\"?android:attr/listPreferredItemPaddingEnd\"\n    android:layout_marginHorizontal=\"?attr/listItemMarginHorizontal\"\n    android:paddingVertical=\"16dp\"\n    android:clipToPadding=\"false\"\n    android:baselineAligned=\"false\"\n    android:orientation=\"vertical\">\n\n    <com.google.android.material.button.MaterialButton\n        android:id=\"@android:id/button1\"\n        style=\"@style/Widget.AppTheme.Button.FilledButton.Dense\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:layout_gravity=\"start|center_vertical\"\n        android:textAppearance=\"?attr/textAppearanceTitleMedium\"\n        app:iconSize=\"18dp\"\n        android:paddingHorizontal=\"16dp\"\n        tools:text=\"Button\" />\n\n</androidx.appcompat.widget.LinearLayoutCompat>\n"
  },
  {
    "path": "libcore/ui/src/main/res/layout/m3_preference_category.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-or-later -->\n<androidx.appcompat.widget.LinearLayoutCompat xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:paddingStart=\"?android:attr/listPreferredItemPaddingStart\"\n    android:paddingRight=\"?android:attr/listPreferredItemPaddingRight\"\n    android:background=\"?android:attr/selectableItemBackground\"\n    android:baselineAligned=\"false\"\n    android:layout_marginTop=\"16dp\"\n    android:gravity=\"center_vertical\"\n    android:layout_marginHorizontal=\"8dp\">\n\n    <include layout=\"@layout/m3_preference_image_frame\" />\n\n    <RelativeLayout\n        android:layout_width=\"0dp\"\n        android:layout_height=\"wrap_content\"\n        android:layout_weight=\"1\"\n        android:paddingTop=\"8dp\"\n        android:paddingBottom=\"8dp\">\n\n        <com.google.android.material.textview.MaterialTextView\n            android:id=\"@android:id/title\"\n            android:layout_width=\"match_parent\"\n            android:layout_height=\"wrap_content\"\n            android:layout_gravity=\"start\"\n            android:textAlignment=\"viewStart\"\n            android:textAppearance=\"?attr/preferenceCategoryTitleTextAppearance\"\n            android:textColor=\"?attr/preferenceCategoryTitleTextColor\"\n            tools:text=\"@tools:sample/lorem[10]\" />\n\n        <com.google.android.material.textview.MaterialTextView\n            android:id=\"@android:id/summary\"\n            android:ellipsize=\"end\"\n            android:singleLine=\"true\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"wrap_content\"\n            android:layout_below=\"@android:id/title\"\n            android:layout_alignLeft=\"@android:id/title\"\n            android:layout_alignStart=\"@android:id/title\"\n            android:layout_gravity=\"start\"\n            android:textAlignment=\"viewStart\"\n            android:maxLines=\"10\"\n            android:textAppearance=\"?attr/textAppearanceListItemSecondary\"\n            tools:text=\"@tools:sample/lorem[10]\" />\n\n    </RelativeLayout>\n</androidx.appcompat.widget.LinearLayoutCompat>\n"
  },
  {
    "path": "libcore/ui/src/main/res/layout/m3_preference_image_frame.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-or-later -->\n<androidx.appcompat.widget.LinearLayoutCompat xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:id=\"@+id/icon_frame\"\n    android:layout_width=\"wrap_content\"\n    android:layout_height=\"wrap_content\"\n    android:minWidth=\"56dp\"\n    android:gravity=\"center\"\n    android:orientation=\"horizontal\"\n    android:paddingStart=\"0dp\"\n    android:paddingEnd=\"8dp\"\n    android:paddingTop=\"4dp\"\n    android:paddingBottom=\"4dp\">\n\n    <androidx.appcompat.widget.AppCompatImageView\n        android:id=\"@android:id/icon\"\n        android:layout_width=\"wrap_content\"\n        android:layout_height=\"wrap_content\"\n        android:maxWidth=\"48dp\"\n        android:maxHeight=\"48dp\"\n        android:adjustViewBounds=\"true\"\n        tools:srcCompat=\"@tools:sample/avatars\" />\n\n</androidx.appcompat.widget.LinearLayoutCompat>"
  },
  {
    "path": "libcore/ui/src/main/res/layout/m3_preference_top_switch.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-or-later -->\n<com.google.android.material.card.MaterialCardView xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    style=\"@style/Widget.AppTheme.CardView.ListItem\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:minHeight=\"?android:attr/listPreferredItemHeightSmall\"\n    android:focusable=\"true\"\n    app:cardBackgroundColor=\"?attr/colorPrimaryContainer\"\n    android:layout_marginHorizontal=\"@dimen/padding_large\">\n\n    <androidx.appcompat.widget.LinearLayoutCompat\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:gravity=\"center_vertical\"\n        android:paddingVertical=\"?attr/listItemPaddingVertical\"\n        android:paddingStart=\"?android:attr/listPreferredItemPaddingStart\"\n        android:paddingEnd=\"?android:attr/listPreferredItemPaddingEnd\"\n        android:clipToPadding=\"false\"\n        android:baselineAligned=\"false\">\n\n        <include layout=\"@layout/m3_preference_image_frame\" />\n\n        <RelativeLayout\n            android:layout_width=\"0dp\"\n            android:layout_height=\"wrap_content\"\n            android:layout_weight=\"1\"\n            android:paddingTop=\"16dp\"\n            android:paddingBottom=\"16dp\">\n\n            <com.google.android.material.textview.MaterialTextView\n                android:id=\"@android:id/title\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:singleLine=\"true\"\n                android:textAppearance=\"?android:attr/textAppearanceListItem\"\n                android:textColor=\"?attr/colorOnPrimaryContainer\"\n                android:ellipsize=\"marquee\"\n                tools:text=\"@tools:sample/lorem[10]\" />\n\n            <com.google.android.material.textview.MaterialTextView\n                android:id=\"@android:id/summary\"\n                android:layout_width=\"wrap_content\"\n                android:layout_height=\"wrap_content\"\n                android:layout_below=\"@android:id/title\"\n                android:layout_alignStart=\"@android:id/title\"\n                android:layout_alignLeft=\"@android:id/title\"\n                android:layout_gravity=\"start\"\n                android:maxLines=\"10\"\n                android:textAlignment=\"viewStart\"\n                android:textAppearance=\"?android:attr/textAppearanceListItemSecondary\"\n                android:textColor=\"?attr/colorOnPrimaryContainer\"\n                tools:text=\"@tools:sample/lorem[10]\" />\n\n        </RelativeLayout>\n\n        <!-- Preference should place its actual preference widget here. -->\n        <androidx.appcompat.widget.LinearLayoutCompat\n            android:id=\"@android:id/widget_frame\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"match_parent\"\n            android:gravity=\"end|center_vertical\"\n            android:paddingStart=\"16dp\"\n            android:paddingEnd=\"0dp\"\n            android:orientation=\"vertical\" />\n\n    </androidx.appcompat.widget.LinearLayoutCompat>\n</com.google.android.material.card.MaterialCardView>\n"
  },
  {
    "path": "libcore/ui/src/main/res/layout/m3_preference_widget_material_switch.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<com.google.android.material.materialswitch.MaterialSwitch\n    xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    android:id=\"@+id/switchWidget\"\n    android:layout_width=\"wrap_content\"\n    android:layout_height=\"wrap_content\"\n    android:focusable=\"false\"\n    android:clickable=\"false\"\n    android:background=\"@null\"/>\n"
  },
  {
    "path": "libcore/ui/src/main/res/layout/view_selection_panel.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<androidx.appcompat.widget.LinearLayoutCompat xmlns:android=\"http://schemas.android.com/apk/res/android\"\n    xmlns:app=\"http://schemas.android.com/apk/res-auto\"\n    xmlns:tools=\"http://schemas.android.com/tools\"\n    android:layout_width=\"match_parent\"\n    android:layout_height=\"wrap_content\"\n    android:layout_weight=\"0\"\n    android:orientation=\"vertical\"\n    android:focusable=\"false\"\n    tools:theme=\"@style/AppTheme\">\n\n    <androidx.appcompat.widget.LinearLayoutCompat\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"36dp\"\n        android:orientation=\"horizontal\"\n        android:focusable=\"false\">\n\n        <io.github.muntashirakon.widget.CheckBox\n            android:id=\"@+id/action_select_all\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"match_parent\"\n            android:layout_weight=\"0\"\n            android:layout_gravity=\"center_vertical\"\n            android:layout_marginHorizontal=\"@dimen/padding_small\"\n            android:focusable=\"true\"\n            android:clickable=\"true\"\n            android:nextFocusRight=\"@id/action_cancel\"\n            android:nextFocusDown=\"@id/selection_actions\"\n            android:textAppearance=\"?attr/textAppearanceBodySmall\"\n            android:text=\"@android:string/selectAll\" />\n\n        <com.google.android.material.textview.MaterialTextView\n            android:id=\"@+id/selection_counter\"\n            android:layout_width=\"wrap_content\"\n            android:layout_height=\"match_parent\"\n            android:layout_weight=\"1\"\n            android:layout_gravity=\"center\"\n            android:paddingHorizontal=\"@dimen/padding_small\"\n            android:focusable=\"true\"\n            android:focusableInTouchMode=\"false\"\n            android:gravity=\"center\"\n            android:textAppearance=\"?attr/textAppearanceBodySmall\"\n            tools:text=\"10/11\" />\n\n        <com.google.android.material.button.MaterialButton\n            android:id=\"@+id/action_cancel\"\n            style=\"@style/Widget.AppTheme.Button.IconButton\"\n            android:layout_width=\"24dp\"\n            android:layout_height=\"24dp\"\n            android:layout_weight=\"0\"\n            android:layout_gravity=\"center_vertical\"\n            android:layout_marginHorizontal=\"@dimen/padding_small\"\n            android:focusable=\"true\"\n            android:clickable=\"true\"\n            android:nextFocusLeft=\"@id/action_select_all\"\n            android:nextFocusDown=\"@id/selection_actions\"\n            android:contentDescription=\"@android:string/cancel\"\n            app:icon=\"@drawable/mtrl_ic_cancel\"\n            app:iconTint=\"@color/m3_textfield_indicator_text_color\"\n            app:iconSize=\"24dp\" />\n\n    </androidx.appcompat.widget.LinearLayoutCompat>\n\n    <com.google.android.material.divider.MaterialDivider\n        android:id=\"@+id/divider\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\" />\n\n    <io.github.muntashirakon.multiselection.MultiSelectionActionsView\n        android:id=\"@+id/selection_actions\"\n        android:layout_width=\"match_parent\"\n        android:layout_height=\"wrap_content\"\n        android:focusable=\"false\"\n        android:nextFocusUp=\"@id/action_select_all\" />\n\n</androidx.appcompat.widget.LinearLayoutCompat>\n"
  },
  {
    "path": "libcore/ui/src/main/res/values/attrs.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-or-later -->\n<resources>\n    <attr name=\"listItemMarginVertical\" format=\"dimension\" />\n    <attr name=\"listItemMarginHorizontal\" format=\"dimension\" />\n    <attr name=\"listItemPaddingVertical\" format=\"dimension\" />\n    <attr name=\"listItemPaddingHorizontal\" format=\"dimension\" />\n    <attr name=\"listItemCornerRadius\" format=\"dimension\" />\n    <attr name=\"listItemIndicatorWidth\" format=\"dimension\" />\n\n    <attr name=\"materialAlertViewStyle\" format=\"reference\" />\n    <attr name=\"materialAlertDialogListItemTextStyle\" format=\"reference\" />\n    <attr name=\"materialFullScreenAlertDialogTheme\" format=\"reference\" />\n    <attr name=\"materialSpinnerStyle\" format=\"reference\" />\n    <attr name=\"multiSelectionActionsView\" format=\"reference\" />\n\n    <attr name=\"topSwitchPreferenceStyle\" format=\"reference\" />\n    <attr name=\"alertPreferenceStyle\" format=\"reference\" />\n    <attr name=\"primaryButtonPreferenceStyle\" format=\"reference\" />\n\n    <declare-styleable name=\"SearchView\">\n        <!-- Tint to apply to the SearchView's close icon. -->\n        <attr name=\"closeIconTint\" />\n        <attr name=\"queryHint\" />\n        <attr name=\"searchHintIcon\" />\n        <attr name=\"android:textAppearance\" />\n        <attr name=\"android:popupBackground\" />\n        <attr name=\"android:dropDownSelector\" />\n        <!-- Horizontal margin of the edit frame -->\n        <attr name=\"frameMarginHorizontal\" format=\"dimension\" />\n    </declare-styleable>\n    <declare-styleable name=\"FlowLayout\">\n        <!-- Constrains items to a single horizontal line. By default, this is false and items will reflow to multiple\n             lines. If this is set to true, the view should be wrapped inside a HorizontalScrollView. -->\n        <attr name=\"singleLine\" />\n        <!-- Horizontal spacing between two items being laid out. Either \"auto\", or a fixed size. Default is 0dp. -->\n        <attr name=\"childSpacing\" format=\"enum|dimension\">\n            <enum name=\"auto\" value=\"-65536\" />\n        </attr>\n        <!-- Minimum horizontal spacing between two items. Default is 0dp. -->\n        <attr name=\"minChildSpacing\" format=\"dimension\" />\n        <!-- Horizontal spacing between two items of the last row. Either \"auto\", \"align\" or a fixed size.\n             If not set, childSpacing will be used instead. -->\n        <attr name=\"childSpacingForLastRow\" format=\"enum|dimension\">\n            <enum name=\"auto\" value=\"-65536\" />\n            <enum name=\"align\" value=\"-65537\" />\n        </attr>\n        <!-- Vertical Spacing between two lines of items being laid out. Either \"auto\", or a fixed size.\n             Default is 0dp. -->\n        <attr name=\"rowSpacing\" format=\"enum|dimension\">\n            <enum name=\"auto\" value=\"-65536\" />\n        </attr>\n        <!-- The maximum height of FlowLayout in terms of number of rows. -->\n        <attr name=\"maxRows\" format=\"integer\" />\n        <!-- Vertical gravity of each line -->\n        <attr name=\"rowVerticalGravity\" format=\"enum\">\n            <enum name=\"auto\" value=\"-65536\" />\n            <enum name=\"top\" value=\"0x30\" />\n            <enum name=\"center\" value=\"0x10\" />\n            <enum name=\"bottom\" value=\"0x50\" />\n        </attr>\n        <attr name=\"android:gravity\" />\n        <!-- Preview only: set items to be displayed inside the layout -->\n        <attr name=\"listItem\" format=\"reference\" />\n        <!-- Preview only: Number of times the list item has to be displayed inside the layout. Default is 10. -->\n        <attr name=\"itemCount\" format=\"integer\" />\n    </declare-styleable>\n    <declare-styleable name=\"MaterialAlertView\">\n        <attr name=\"alertType\" format=\"enum\">\n            <enum name=\"info\" value=\"0\" />\n            <enum name=\"warn\" value=\"1\" />\n            <enum name=\"custom\" value=\"-1\" />\n        </attr>\n        <attr name=\"android:text\" />\n        <attr name=\"android:textAppearance\" />\n        <attr name=\"android:textColor\" />\n    </declare-styleable>\n    <declare-styleable name=\"MaterialAutoCompleteTextView\">\n        <attr name=\"android:dropDownSelector\" />\n    </declare-styleable>\n    <declare-styleable name=\"MaxHeightScrollView\">\n        <attr name=\"maxHeight\" format=\"dimension\" />\n    </declare-styleable>\n    <declare-styleable name=\"MultiSelectionView\">\n        <!-- The menu resource to inflate and populate items from. Attribute type definition is in\n             navigation package. -->\n        <attr name=\"menu\" format=\"reference\" />\n    </declare-styleable>\n    <declare-styleable name=\"NestedScrollView\">\n        <!-- Whether fast scroller is enabled. Default is false. -->\n        <attr name=\"fastScrollerEnabled\" />\n    </declare-styleable>\n    <declare-styleable name=\"RecyclerView\">\n        <!-- Whether fast scroller is enabled. Default is false. -->\n        <attr name=\"fastScrollerEnabled\" format=\"boolean\" />\n    </declare-styleable>\n    <declare-styleable name=\"MultiSelectionActionsView\">\n        <!-- Background tint for the navigation bar. -->\n        <attr name=\"backgroundTint\" />\n        <!-- The menu resource to inflate and populate items from. Attribute type definition is in\n             navigation package. -->\n        <attr name=\"menu\" />\n        <!-- The background for the navigation items. Attribute type definition is in navigation\n             package. -->\n        <attr name=\"itemBackground\" />\n        <!-- The size to provide for the navigation item icons. -->\n        <attr name=\"itemIconSize\" />\n        <!-- The tint to apply to the navigation item icons. Attribute type definition is in navigation\n             package. -->\n        <attr name=\"itemIconTint\" />\n        <!-- The text appearance to apply to the inactive navigation item labels. Setting\n             android:textColor in itemTextAppearanceInactive will take precedence over android:textColor\n             in itemTextAppearanceActive. Instead, set itemTextColor with a ColorStateList to make\n             the text color stateful. -->\n        <attr name=\"itemTextAppearanceInactive\" format=\"reference\" />\n        <!-- The text appearance to apply to the active navigation item label. You should not set\n             android:textColor in itemTextAppearanceActive. Instead, set itemTextColor to a\n             ColorStateList to make the text color stateful. -->\n        <attr name=\"itemTextAppearanceActive\" format=\"reference\" />\n        <!-- The color to apply to the navigation items' text. Setting itemTextColor will take\n             precedence over android:textColor in itemTextAppearanceInactive or\n             itemTextAppearanceActive. Attribute type definition is in navigation package. -->\n        <attr name=\"itemTextColor\" />\n        <!-- The elevation to use for the navigation bar view -->\n        <attr name=\"elevation\" />\n    </declare-styleable>\n    <declare-styleable name=\"SwipeRefreshLayout\">\n        <!-- The background color of the progress spinner disc. Default is colorSurface.  -->\n        <attr name=\"progressBackgroundColor\" format=\"color\" />\n        <!-- The colors used in the progress animation. The first color will also be the color of the bar that grows in response to a user swipe gesture. -->\n        <attr name=\"indicatorColor\" />\n    </declare-styleable>\n    <declare-styleable name=\"AppWidgetAttrs\">\n        <attr name=\"appWidgetPadding\" format=\"dimension\" />\n        <attr name=\"appWidgetInnerRadius\" format=\"dimension\" />\n        <attr name=\"appWidgetRadius\" format=\"dimension\" />\n    </declare-styleable>\n</resources>"
  },
  {
    "path": "libcore/ui/src/main/res/values/bools.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <bool name=\"large_layout\">false</bool>\n</resources>"
  },
  {
    "path": "libcore/ui/src/main/res/values/colors.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<resources>\n    <color name=\"textColorPrimary\">#DE000000</color>\n    <color name=\"textColorSecondary\">#99000000</color>\n\n    <color name=\"salem_green\">#1b8654</color>\n    <color name=\"lilac_bush_purple\">#8267b8</color>\n    <color name=\"pumpkin_orange\">#ff8017</color>\n\n    <color name=\"disabled_user\">#FF8A80</color>\n    <color name=\"highlight\">#FFFF9F</color>\n    <color name=\"red\">#B3FF0000</color>\n    <color name=\"running\">#EA80FC</color>\n    <color name=\"semi_transparent\">#10000000</color>\n    <color name=\"stopped\">@color/blue_mountain</color>\n    <color name=\"sixty_percent_white\">#9AFFFFFF</color>\n    <color name=\"sixty_percent_black\">#9A000000</color>\n    <color name=\"tracker\">#FFFF8017</color> <!-- dark orange -->\n    <color name=\"changelog_new\">#198754</color>\n    <color name=\"changelog_improve\">#563d7c</color>\n    <color name=\"changelog_fix\">#ffc107</color>\n\n    <color name=\"grey\">#ffe0e0e0</color>\n    <color name=\"original_orange\">#ff9702</color>\n    <color name=\"dark_orange\">#ff8017</color>\n    <color name=\"pink\">#7D1B7E</color>\n    <color name=\"ocean_blue\">#2B65EC</color>\n    <color name=\"pure_red\">#FF0000</color>\n\n    <color name=\"bright_green\">#BEEF00</color>\n    <color name=\"electric_red\">#ff0028</color>\n    <color name=\"deep_green\">#657a00</color>\n    <color name=\"power_blue\">#1400c6</color>\n    <color name=\"background_tan\">#fceed1</color>\n    <color name=\"purple_y\">#7d3cff</color>\n    <color name=\"yellow_gloves\">#f2d53c</color>\n    <color name=\"readhead\">#c80e13</color>\n    <color name=\"sand_tan\">#E1B382</color>\n    <color name=\"sand_tan_shadow\">#c89666</color>\n    <color name=\"night_blue\">#2D545e</color>\n    <color name=\"night_blue_shadow\">#12343B</color>\n    <color name=\"ragin_beige\">#fff5d7</color>\n    <color name=\"coral_pink\">#ff5e6c</color>\n    <color name=\"sleuthe_yellow\">#feb300</color>\n    <color name=\"pink_leaf\">#ffaaab</color>\n    <color name=\"grassy_green\">#9bc400</color>\n    <color name=\"purple_mountains_majesty\">#8076a3</color>\n    <color name=\"misty_mountain_pink\">#f9c5bd</color>\n    <color name=\"factory_stone_purple\">#7c677f</color>\n    <color name=\"green_treeline\">#478559</color>\n    <color name=\"purple_baseline\">#161748</color>\n    <color name=\"pink_highlight\">#f95d9b</color>\n    <color name=\"bluewater_lowlight\">#39a0ca</color>\n    <color name=\"yellow_background\">#ffde22</color>\n    <color name=\"pink_red_circle\">#ff414e</color>\n    <color name=\"orange_circle\">#ff8928</color>\n    <color name=\"white_layover\">#ffffff</color>\n    <color name=\"mountain_shadow_blue\">#101357</color>\n    <color name=\"old_makeup_pink\">#fea49f</color>\n    <color name=\"goldenrod_yellow\">#fbaf08</color>\n    <color name=\"bluebell_light_blue\">#00a0a0</color>\n    <color name=\"bold_2019_green\">#007f4f</color>\n    <color name=\"lightning_blue\">#51d0de</color>\n    <color name=\"lightning_purple\">#bf4aa8</color>\n    <color name=\"brian_wrinkle_white\">#d9d9d9</color>\n    <color name=\"blue_popsicle\">#0f2862</color>\n    <color name=\"redline\">#9e363a</color>\n    <color name=\"purple_shadow\">#091f36</color>\n    <color name=\"grey_blue_leaf\">#4f5f76</color>\n    <color name=\"blueberry\">#6b7a8f</color>\n    <color name=\"apricot\">#f7882f</color>\n    <color name=\"citrus\">#f7c331</color>\n    <color name=\"apple_core\">#dcc7aa</color>\n    <color name=\"left_blue\">#1561ad</color>\n    <color name=\"right_blue_muted\">#1c77ac</color>\n    <color name=\"blue_green\">#1dbab4</color>\n    <color name=\"red_orange\">#fc5226</color>\n    <color name=\"redder_than_you\">#ff3a22</color>\n    <color name=\"goldi_lots\">#c7af6b</color>\n    <color name=\"darker_gold\">#a4893d</color>\n    <color name=\"silver_tongue\">#628078</color>\n    <color name=\"barely_green\">#acb7ae</color>\n    <color name=\"the_brown_shirts\">#82716e</color>\n    <color name=\"tan_blonde\">#e4decd</color>\n    <color name=\"blondey\">#c2b490</color>\n    <color name=\"green_mountain\">#3d7c47</color>\n    <color name=\"blue_mountain\">#09868b</color>\n    <color name=\"light_blue_backdrop\">#76c1d4</color>\n    <color name=\"barely_gray_edge\">#f7f7f7</color>\n    <color name=\"grey_silver\">#bccbde</color>\n    <color name=\"lightsaber_blue\">#c2dde6</color>\n    <color name=\"purple\">#431c5d</color>\n    <color name=\"orange\">#e05915</color>\n    <color name=\"yellowbrite\">#cdd422</color>\n    <color name=\"painful_red\">#eb1736</color>\n    <color name=\"_35_years_old_purple\">#5252d4</color>\n    <color name=\"lighter_purple_on_the_gradient\">#7575dd</color>\n    <color name=\"shadow_purple_red\">#781a44</color>\n    <color name=\"green\">#8bf0ba</color>\n    <color name=\"ironic_blues\">#0e0fed</color>\n    <color name=\"blue_underling\">#94f0f1</color>\n    <color name=\"pinky_ring\">#f2b1d8</color>\n    <color name=\"egg_yellows\">#ffdc6a</color>\n\n    <color name=\"android_theme_tag_color_01\">#FF222222</color>\n    <color name=\"android_theme_tag_color_02\">#FF996666</color>\n    <color name=\"android_theme_tag_color_03\">#FFFFCC99</color>\n    <color name=\"android_theme_tag_color_04\">#FFCC0000</color>\n    <color name=\"android_theme_tag_color_05\">#FF666633</color>\n    <color name=\"android_theme_tag_color_06\">#FF990099</color>\n    <color name=\"android_theme_tag_color_07\">#FF006600</color>\n    <color name=\"android_theme_tag_color_08\">#FF660066</color>\n    <color name=\"android_theme_tag_color_09\">#FF003399</color>\n    <color name=\"android_theme_tag_color_10\">#FFFF6633</color>\n    <color name=\"android_theme_tag_color_11\">#FFFFFFFF</color>\n    <color name=\"android_theme_tag_color_12\">#FFCC3333</color>\n    <color name=\"android_theme_tag_color_13\">#FFFFFF00</color>\n    <color name=\"android_theme_tag_color_14\">#FF0099CC</color>\n    <color name=\"android_theme_tag_color_15\">#FF009933</color>\n    <color name=\"android_theme_tag_color_16\">#FFCC3399</color>\n    <color name=\"android_theme_tag_color_17\">#FFFFCC00</color>\n</resources>\n"
  },
  {
    "path": "libcore/ui/src/main/res/values/dimens.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?><!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<resources>\n    <dimen name=\"padding_very_large\">32dp</dimen>\n    <dimen name=\"padding_large\">24dp</dimen>\n    <dimen name=\"padding_medium\">16dp</dimen>\n    <dimen name=\"padding_small\">8dp</dimen>\n    <dimen name=\"padding_very_small\">4dp</dimen>\n\n    <dimen name=\"font_size_larger\">16sp</dimen>\n    <dimen name=\"font_size_large\">14sp</dimen>\n    <dimen name=\"font_size_medium\">12sp</dimen>\n    <dimen name=\"font_size_small\">10sp</dimen>\n    <dimen name=\"font_size_smaller\">9sp</dimen>\n\n    <dimen name=\"mtrl_switch_thumb_size_medium\">24dp</dimen>\n    <dimen name=\"mtrl_switch_track_height_medium\">24dp</dimen>\n    <dimen name=\"mtrl_switch_track_width_medium\">39dp</dimen> <!-- 52*24/32 -->\n\n    <!--\n     Dropdown menus in AutoCompleteTextView when coupled with TextInputLayout uses unacceptable hard-coded values for\n      background radius and vertical padding. They are overriden here to have a consistent UI design.\n      -->\n    <dimen name=\"mtrl_shape_corner_size_small_component\">16dp</dimen>\n    <dimen name=\"mtrl_exposed_dropdown_menu_popup_vertical_padding\">0dp</dimen>\n</resources>\n"
  },
  {
    "path": "libcore/ui/src/main/res/values/strings.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<resources>\n    <string name=\"select_all\">Select all</string>\n    <string name=\"selected_items_accessibility_description\">Selected %d out of %d items</string>\n</resources>"
  },
  {
    "path": "libcore/ui/src/main/res/values/styles.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<resources xmlns:tools=\"http://schemas.android.com/tools\">\n\n    <style name=\"AppThemeOverlay\" parent=\"Theme.Material3.Light.NoActionBar\">\n        <item name=\"android:statusBarColor\">#99000000</item>\n        <item name=\"android:navigationBarColor\">#99000000</item>\n    </style>\n\n    <style name=\"AppTheme\" parent=\"AppThemeOverlay\">\n        <item name=\"navigationIcon\">@drawable/ic_keyboard_backspace</item>\n\n        <item name=\"android:colorBackground\">?colorSurface</item>\n\n        <!-- Medium title should've been 18sp, not 16 -->\n        <item name=\"textAppearanceTitleMedium\">@style/TextAppearance.AppTheme.TitleMedium</item>\n\n        <item name=\"materialFullScreenAlertDialogTheme\">@style/AppTheme</item>\n        <item name=\"bottomSheetDialogTheme\">@style/AppTheme.BottomSheetDialog</item>\n        <item name=\"checkboxStyle\">@style/Widget.AppTheme.CompoundButton.CheckBox</item>\n        <item name=\"chipStyle\">@style/Widget.AppTheme.Chip.Assist</item>\n        <item name=\"chipGroupStyle\">@style/Widget.AppTheme.ChipGroup</item>\n        <item name=\"chipStandaloneStyle\">@style/Widget.AppTheme.Chip.Input</item>\n        <item name=\"floatingActionButtonStyle\">@style/Widget.AppTheme.Button.FAB</item>\n        <item name=\"materialAlertViewStyle\">@style/Widget.AppTheme.MaterialAlertView</item>\n        <item name=\"materialCalendarTheme\">@style/Widget.AppTheme.MaterialCalendar</item>\n        <item name=\"materialCardViewStyle\">@style/Widget.AppTheme.CardView.Elevated</item>\n        <item name=\"materialDividerStyle\">@style/Widget.AppTheme.Divider</item>\n        <item name=\"materialSwitchStyle\">@style/Widget.AppTheme.MaterialSwitch.Large</item>\n        <item name=\"searchViewStyle\">@style/Widget.AppTheme.SearchView</item>\n        <item name=\"textInputStyle\">@style/Widget.AppTheme.TextInputLayout</item>\n        <item name=\"materialSpinnerStyle\">@style/Widget.AppTheme.MaterialSpinner</item>\n        <item name=\"toolbarStyle\">@style/Widget.AppTheme.MaterialToolbar</item>\n        <item name=\"multiSelectionActionsView\">@style/Widget.AppTheme.MultiSelectionActionsView</item>\n\n        <!-- Preferences -->\n        <item name=\"preferenceStyle\">@style/Preference.M3</item>\n        <item name=\"alertPreferenceStyle\">@style/Preference.M3.Alert</item>\n        <item name=\"checkBoxPreferenceStyle\">@style/Preference.M3.CheckBoxPreference</item>\n        <item name=\"dialogPreferenceStyle\">@style/Preference.M3.DialogPreference</item>\n        <item name=\"primaryButtonPreferenceStyle\">@style/Preference.M3.ButtonPreference.Primary</item>\n        <item name=\"topSwitchPreferenceStyle\">@style/Preference.M3.TopSwitchPreference</item>\n\n        <item name=\"dropdownPreferenceStyle\">@style/Preference.DropDown.Material</item>\n\n        <item name=\"editTextPreferenceStyle\">@style/Preference.M3.DialogPreference.EditTextPreference</item>\n        <item name=\"preferenceCategoryStyle\">@style/Preference.M3.Category</item>\n        <item name=\"preferenceCategoryTitleTextAppearance\">?attr/textAppearanceLabelLarge</item>\n        <item name=\"preferenceCategoryTitleTextColor\">?attr/colorPrimary</item>\n\n        <item name=\"preferenceFragmentCompatStyle\">@style/PreferenceFragment.Material</item>\n        <item name=\"preferenceFragmentListStyle\">@style/PreferenceFragmentList.Material</item>\n        <item name=\"preferenceFragmentStyle\">@style/PreferenceFragment.Material</item>\n\n        <item name=\"preferenceScreenStyle\">@style/Preference.M3.PreferenceScreen</item>\n\n        <item name=\"seekBarPreferenceStyle\">@style/Preference.SeekBarPreference.Material</item>\n\n        <item name=\"switchPreferenceStyle\">@style/Preference.M3.SwitchPreference</item>\n        <item name=\"switchPreferenceCompatStyle\">@style/Preference.M3.SwitchPreferenceCompat</item>\n\n        <!-- List items -->\n        <item name=\"android:textAppearanceListItem\">?attr/textAppearanceTitleMedium</item>\n        <item name=\"android:textAppearanceListItemSecondary\">@style/TextAppearance.AppTheme.BodyMedium.Secondary</item>\n        <item name=\"listItemMarginVertical\">1dp</item>\n        <item name=\"listItemMarginHorizontal\">@dimen/padding_small</item>\n        <item name=\"listItemPaddingVertical\">@dimen/padding_small</item>\n        <item name=\"listItemPaddingHorizontal\">?android:attr/listPreferredItemPaddingStart</item>\n        <item name=\"listItemCornerRadius\">24dp</item>\n        <item name=\"listItemIndicatorWidth\">9dp</item>\n\n        <!-- Dialog -->\n        <item name=\"materialAlertDialogListItemTextStyle\">@style/MaterialAlertDialog.Material3.Body.Text.Large</item>\n\n        <!-- Popup Menu -->\n        <item name=\"popupMenuStyle\">@style/Widget.AppTheme.PopupMenu</item>\n        <item name=\"listPopupWindowStyle\">@style/Widget.AppTheme.PopupMenu.ListPopupWindow</item>\n        <item name=\"android:contextPopupMenuStyle\" tools:targetApi=\"N\">\n            @style/Widget.AppTheme.PopupMenu.ContextMenu\n        </item>\n        <item name=\"actionOverflowButtonStyle\">@style/Widget.AppTheme.PopupMenu.OverflowButton</item>\n        <item name=\"actionOverflowMenuStyle\">@style/Widget.AppTheme.PopupMenu.Overflow</item>\n        <item name=\"popupMenuBackground\">@drawable/popup_menu_background</item>\n        <item name=\"listChoiceBackgroundIndicator\">@drawable/popup_menu_item_background</item>\n        <item name=\"android:dropDownListViewStyle\">@style/Widget.AppTheme.PopupMenu.DropDown</item>\n\n        <!-- Misc -->\n        <item name=\"android:windowActivityTransitions\">true</item>\n        <item name=\"android:windowContentTransitions\">true</item>\n        <item name=\"android:windowAllowEnterTransitionOverlap\">true</item>\n        <item name=\"android:windowAllowReturnTransitionOverlap\">true</item>\n    </style>\n\n    <style name=\"AppTheme.Black\" parent=\"AppTheme\">\n        <item name=\"materialFullScreenAlertDialogTheme\">@style/AppTheme.Black</item>\n    </style>\n\n    <style name=\"AppTheme.TransparentBackground\" parent=\"AppTheme\">\n        <item name=\"android:background\">@null</item>\n        <item name=\"background\">@null</item>\n        <item name=\"android:windowBackground\">@android:color/transparent</item>\n        <item name=\"android:colorBackgroundCacheHint\">@null</item>\n        <item name=\"android:windowContentOverlay\">@null</item>\n        <item name=\"android:windowIsTranslucent\">true</item>\n        <item name=\"android:windowAnimationStyle\">@null</item>\n        <item name=\"android:windowNoTitle\">true</item>\n    </style>\n\n    <style name=\"AppTheme.TransparentBackground.Black\" parent=\"AppTheme.TransparentBackground\">\n        <item name=\"materialFullScreenAlertDialogTheme\">@style/AppTheme.Black</item>\n    </style>\n\n    <!-- Animation for full-screen alert dialog -->\n    <style name=\"AppTheme.FullScreenDialog.Animation\" parent=\"\">\n        <item name=\"android:windowEnterAnimation\">@anim/fullscreen_dialog_enter</item>\n        <item name=\"android:windowExitAnimation\">@anim/fullscreen_dialog_exit</item>\n    </style>\n\n    <!-- MaterialSpinner -->\n    <style name=\"Widget.AppTheme.MaterialSpinner\" parent=\"Widget.AppTheme.TextInputLayout.ExposedDropdownMenu\" />\n\n    <style name=\"Widget.AppTheme.MaterialSpinner.Small\" parent=\"Widget.AppTheme.TextInputLayout.ExposedDropdownMenu.Small\" />\n\n    <style name=\"Widget.AppTheme.MaterialSpinner.Spinner\" parent=\"Widget.AppTheme.MaterialSpinner\">\n        <item name=\"boxStrokeWidth\">0dp</item>\n        <item name=\"boxBackgroundColor\">?attr/colorPrimaryContainer</item>\n        <item name=\"materialThemeOverlay\">@style/ThemeOverlay.AppTheme.MaterialSpinner</item>\n    </style>\n\n    <style name=\"Widget.AppTheme.MaterialSpinner.Spinner.Small\" parent=\"Widget.AppTheme.MaterialSpinner.Small\">\n        <item name=\"boxStrokeWidth\">0dp</item>\n        <item name=\"boxBackgroundColor\">?attr/colorPrimaryContainer</item>\n        <item name=\"materialThemeOverlay\">@style/ThemeOverlay.AppTheme.MaterialSpinner.Small</item>\n    </style>\n\n    <style name=\"ThemeOverlay.AppTheme.MaterialSpinner\" parent=\"\">\n        <item name=\"autoCompleteTextViewStyle\">@style/Widget.AppTheme.MaterialSpinner.AutoCompleteTextView</item>\n    </style>\n\n    <style name=\"ThemeOverlay.AppTheme.MaterialSpinner.Small\" parent=\"\">\n        <item name=\"autoCompleteTextViewStyle\">@style/Widget.AppTheme.MaterialSpinner.AutoCompleteTextView.Small</item>\n        <item name=\"endIconMinSize\">18dp</item> <!-- 34 - 8*2 -->\n    </style>\n\n    <style name=\"Widget.AppTheme.MaterialSpinner.AutoCompleteTextView\" parent=\"Widget.Material3.AutoCompleteTextView.OutlinedBox.Dense\">\n        <item name=\"simpleItemLayout\">@layout/auto_complete_dropdown_item</item>\n        <item name=\"android:dropDownSelector\">?attr/listChoiceBackgroundIndicator</item>\n        <item name=\"android:textColor\">?attr/colorOnPrimaryContainer</item>\n    </style>\n\n    <style name=\"Widget.AppTheme.MaterialSpinner.AutoCompleteTextView.Small\" parent=\"Widget.AppTheme.AutoCompleteTextView\">\n        <item name=\"android:paddingStart\">12dp</item>\n        <item name=\"android:paddingEnd\">12dp</item>\n        <item name=\"android:paddingTop\">8dp</item>\n        <item name=\"android:paddingBottom\">8dp</item>\n        <item name=\"android:minHeight\">34dp</item>\n        <item name=\"android:textColor\">?attr/colorOnPrimaryContainer</item>\n    </style>\n\n    <!-- MaterialAlertDialog -->\n    <style name=\"MaterialAlertDialog.Material3.Body.Text.Large\" parent=\"MaterialAlertDialog.Material3.Body.Text\">\n        <item name=\"android:textAppearance\">?attr/textAppearanceBodyLarge</item>\n    </style>\n\n    <!-- BottomSheetDialog -->\n    <style name=\"AppTheme.BottomSheetDialog\" parent=\"ThemeOverlay.Material3.BottomSheetDialog\">\n        <item name=\"android:windowSoftInputMode\">adjustResize</item>\n        <item name=\"bottomSheetStyle\">@style/AppTheme.BottomSheetModal</item>\n    </style>\n\n    <style name=\"AppTheme.BottomSheetModal\" parent=\"Widget.Material3.BottomSheet.Modal\">\n        <item name=\"shapeAppearance\">@style/ShapeAppearance.AppTheme.MediumComponent.RoundedTop</item>\n    </style>\n\n    <style name=\"AppTheme.BottomSheetAnimation\" parent=\"\">\n        <item name=\"android:windowEnterAnimation\">@anim/bottom_sheet_slide_up</item>\n        <item name=\"android:windowExitAnimation\">@anim/bottom_sheet_slide_down</item>\n    </style>\n\n    <!-- CheckBox -->\n    <style name=\"Widget.AppTheme.CompoundButton.CheckBox\" parent=\"Widget.Material3.CompoundButton.CheckBox\">\n        <item name=\"android:minWidth\">12dp</item>\n        <item name=\"android:minHeight\">12dp</item>\n        <item name=\"android:textAppearance\">@style/TextAppearance.AppTheme.BodySmall</item>\n    </style>\n\n    <!-- Chip -->\n    <style name=\"Widget.AppTheme.Chip.Assist\" parent=\"Widget.Material3.Chip.Assist\">\n        <item name=\"chipMinHeight\">24dp</item>\n        <item name=\"chipMinTouchTargetSize\">24dp</item>\n        <item name=\"chipIconSize\">18dp</item>\n        <item name=\"android:textAppearance\">@style/TextAppearance.AppTheme.BodySmall</item>\n    </style>\n\n    <style name=\"Widget.AppTheme.Chip.Assist.Elevated\" parent=\"Widget.Material3.Chip.Assist.Elevated\">\n        <item name=\"chipMinHeight\">24dp</item>\n        <item name=\"chipMinTouchTargetSize\">24dp</item>\n        <item name=\"chipIconSize\">18dp</item>\n        <item name=\"android:textAppearance\">@style/TextAppearance.AppTheme.BodySmall</item>\n    </style>\n\n    <style name=\"Widget.AppTheme.Chip.Assist.Elevated.Padded\" parent=\"Widget.AppTheme.Chip.Assist.Elevated\">\n        <!-- Fix margin issue -->\n        <item name=\"android:layout_marginTop\">@dimen/padding_very_small</item>\n        <item name=\"android:layout_marginBottom\">@dimen/padding_very_small</item>\n        <item name=\"android:layout_marginStart\">@dimen/padding_very_small</item>\n        <item name=\"android:layout_marginEnd\">@dimen/padding_very_small</item>\n    </style>\n\n    <style name=\"Widget.AppTheme.Chip.Filter\" parent=\"Widget.Material3.Chip.Filter\">\n        <item name=\"chipMinHeight\">24dp</item>\n        <item name=\"chipMinTouchTargetSize\">24dp</item>\n        <item name=\"chipIconSize\">18dp</item>\n        <item name=\"android:textAppearance\">@style/TextAppearance.AppTheme.BodySmall</item>\n    </style>\n\n    <style name=\"Widget.AppTheme.Chip.Input\" parent=\"Widget.Material3.Chip.Input.Elevated\">\n        <item name=\"chipMinHeight\">24dp</item>\n        <item name=\"chipMinTouchTargetSize\">24dp</item>\n        <item name=\"chipIconSize\">18dp</item>\n        <item name=\"android:textAppearance\">@style/TextAppearance.AppTheme.BodySmall</item>\n    </style>\n\n    <style name=\"Widget.AppTheme.Chip.Suggestion\" parent=\"Widget.Material3.Chip.Suggestion.Elevated\">\n        <item name=\"chipMinHeight\">24dp</item>\n        <item name=\"chipMinTouchTargetSize\">24dp</item>\n        <item name=\"chipIconSize\">18dp</item>\n        <item name=\"android:textAppearance\">@style/TextAppearance.AppTheme.BodySmall</item>\n    </style>\n\n    <!-- ChipGroup -->\n    <style name=\"Widget.AppTheme.ChipGroup\" parent=\"Widget.Material3.ChipGroup\" />\n\n    <style name=\"Widget.AppTheme.ChipGroup.Assist\" parent=\"Widget.Material3.ChipGroup\">\n        <!-- chipStyle is set via ChipGroup because the Chip's are generated dynamically -->\n        <item name=\"chipStyle\">@style/Widget.AppTheme.Chip.Assist</item>\n    </style>\n\n    <style name=\"Widget.AppTheme.ChipGroup.Assist.Elevated\" parent=\"Widget.Material3.ChipGroup\">\n        <!-- chipStyle is set via ChipGroup because the Chip's are generated dynamically -->\n        <item name=\"chipStyle\">@style/Widget.AppTheme.Chip.Assist.Elevated</item>\n    </style>\n\n    <style name=\"Widget.AppTheme.ChipGroup.Filter\" parent=\"Widget.Material3.ChipGroup\">\n        <!-- chipStyle is set via ChipGroup because the Chip's are generated dynamically -->\n        <item name=\"chipStyle\">@style/Widget.AppTheme.Chip.Filter</item>\n    </style>\n\n    <style name=\"Widget.AppTheme.ChipGroup.Input\" parent=\"Widget.Material3.ChipGroup\">\n        <!-- chipStyle is set via ChipGroup because the Chip's are generated dynamically -->\n        <item name=\"chipStyle\">@style/Widget.AppTheme.Chip.Input</item>\n    </style>\n\n    <style name=\"Widget.AppTheme.ChipGroup.Suggestion\" parent=\"Widget.Material3.ChipGroup\">\n        <!-- chipStyle is set via ChipGroup because the Chip's are generated dynamically -->\n        <item name=\"chipStyle\">@style/Widget.AppTheme.Chip.Suggestion</item>\n    </style>\n\n    <!-- MaterialDivider -->\n    <style name=\"Widget.AppTheme.Divider\" parent=\"Widget.Material3.MaterialDivider\">\n        <item name=\"dividerColor\">?android:attr/colorControlHighlight</item>\n    </style>\n\n    <!-- MaterialCardView -->\n    <style name=\"Widget.AppTheme.CardView.Elevated\" parent=\"Widget.Material3.CardView.Elevated\">\n        <item name=\"cardCornerRadius\">24dp</item>\n    </style>\n\n    <style name=\"Widget.AppTheme.CardView.ListItem\" parent=\"Widget.Material3.CardView.Elevated\">\n        <item name=\"cardCornerRadius\">?attr/listItemCornerRadius</item>\n        <item name=\"cardElevation\">0dp</item>\n        <item name=\"cardBackgroundColor\">@android:color/transparent</item>\n    </style>\n\n    <style name=\"Widget.AppTheme.CardView.ListItem.Outlined\" parent=\"Widget.Material3.CardView.Outlined\">\n        <item name=\"cardCornerRadius\">?attr/listItemCornerRadius</item>\n        <item name=\"strokeWidth\">1dp</item>\n        <item name=\"cardBackgroundColor\">@macro/m3_comp_elevated_card_container_color</item>\n    </style>\n\n    <style name=\"Widget.AppTheme.CardView.ListItem.Padded\" parent=\"Widget.AppTheme.CardView.ListItem\">\n        <!-- Fix margin issue -->\n        <item name=\"android:layout_marginTop\">@dimen/padding_very_small</item>\n        <item name=\"android:layout_marginBottom\">@dimen/padding_very_small</item>\n        <item name=\"android:layout_marginStart\">@dimen/padding_small</item>\n        <item name=\"android:layout_marginEnd\">@dimen/padding_small</item>\n    </style>\n\n    <style name=\"Widget.AppTheme.CardView.Filled\" parent=\"Widget.Material3.CardView.Filled\" />\n\n    <style name=\"Widget.AppTheme.CardView.Outlined\" parent=\"Widget.Material3.CardView.Outlined\" />\n\n    <style name=\"Widget.AppTheme.CardView.Outlined.DiagonallyRounded\" parent=\"Widget.Material3.CardView.Outlined\">\n        <item name=\"shapeAppearance\">@style/ShapeAppearance.AppTheme.DiagonallyRounded</item>\n    </style>\n\n    <!-- MaterialCalendar -->\n    <style name=\"Widget.AppTheme.MaterialCalendar\" parent=\"ThemeOverlay.Material3.MaterialCalendar\">\n        <!-- MaterialCalendar doesn't follow the M3-styled dialog -->\n        <item name=\"shapeAppearanceMediumComponent\">@style/ShapeAppearance.AppTheme.LargeComponent</item>\n    </style>\n\n    <!-- MaterialSwitch -->\n    <style name=\"Widget.AppTheme.MaterialSwitch\" parent=\"Widget.Material3.CompoundButton.MaterialSwitch\">\n        <!-- Matches CheckBox -->\n        <item name=\"minHeight\">32dp</item>\n        <item name=\"switchPadding\">8dp</item>\n        <item name=\"android:thumb\">@drawable/mtrl_switch_thumb_medium</item>\n        <item name=\"track\">@drawable/mtrl_switch_track_medium</item>\n        <item name=\"trackDecoration\">@drawable/mtrl_switch_track_decoration_medium</item>\n    </style>\n\n    <style name=\"Widget.AppTheme.MaterialSwitch.Large\" parent=\"Widget.Material3.CompoundButton.MaterialSwitch\" />\n\n    <!-- MaterialToolbar -->\n    <style name=\"Widget.AppTheme.MaterialToolbar\" parent=\"Widget.Material3.Toolbar\">\n        <item name=\"subtitleTextAppearance\">@style/TextAppearance.AppTheme.BodyMedium</item>\n    </style>\n\n    <!-- Menu -->\n    <style name=\"Widget.AppTheme.PopupMenu\" parent=\"Widget.Material3.PopupMenu\" />\n\n    <style name=\"Widget.AppTheme.PopupMenu.ListPopupWindow\" parent=\"Widget.Material3.PopupMenu.ListPopupWindow\" />\n\n    <style name=\"Widget.AppTheme.PopupMenu.ContextMenu\" parent=\"Widget.Material3.PopupMenu.ContextMenu\" />\n\n    <style name=\"Widget.AppTheme.PopupMenu.Overflow\" parent=\"Widget.Material3.PopupMenu.Overflow\" />\n    <!-- Overflow menu button -->\n    <style name=\"Widget.AppTheme.PopupMenu.OverflowButton\" parent=\"Widget.AppCompat.ActionButton.Overflow\">\n        <item name=\"android:src\">@drawable/ic_more_vert</item>\n    </style>\n\n    <style name=\"Widget.AppTheme.PopupMenu.DropDown\" parent=\"Widget.AppCompat.ListView.DropDown\">\n        <item name=\"android:listSelector\">@drawable/popup_menu_item_background</item>\n    </style>\n\n    <!-- MultiSelectionActionsView -->\n    <style name=\"Widget.AppTheme.MultiSelectionActionsView\" parent=\"android:Widget\">\n        <item name=\"android:background\">@macro/m3_comp_nav_bar_container_color</item>\n        <item name=\"backgroundTint\">@null</item>\n        <item name=\"elevation\">@dimen/m3_sys_elevation_level2</item>\n        <item name=\"itemTextAppearanceInactive\">?attr/textAppearanceBodyMedium</item>\n        <item name=\"itemTextAppearanceActive\">?attr/textAppearanceBodyMedium</item>\n        <item name=\"itemIconSize\">24dp</item>\n        <item name=\"itemIconTint\">@color/m3_textfield_indicator_text_color</item>\n        <item name=\"itemTextColor\">@color/m3_textfield_indicator_text_color</item>\n        <item name=\"enforceTextAppearance\">true</item>\n        <item name=\"enforceMaterialTheme\">true</item>\n        <item name=\"itemBackground\">@null</item>\n        <item name=\"itemHorizontalTranslationEnabled\">false</item>\n    </style>\n\n    <!-- ProgressIndicator -->\n    <style name=\"Widget.AppTheme.LinearProgressIndicator\" parent=\"Widget.Material3.LinearProgressIndicator\" />\n\n    <style name=\"Widget.AppTheme.CircularProgressIndicator\" parent=\"Widget.Material3.CircularProgressIndicator\" />\n\n    <style name=\"Widget.AppTheme.CircularProgressIndicator.Medium\" parent=\"Widget.Material3.CircularProgressIndicator.Medium\" />\n\n    <style name=\"Widget.AppTheme.CircularProgressIndicator.Small\" parent=\"Widget.Material3.CircularProgressIndicator.Small\" />\n\n    <style name=\"Widget.AppTheme.CircularProgressIndicator.ExtraSmall\" parent=\"Widget.Material3.CircularProgressIndicator.ExtraSmall\" />\n\n    <!-- SwipeRefreshLayout -->\n    <style name=\"Widget.AppTheme.SwipeRefreshLayout\" parent=\"android:Widget\">\n        <item name=\"progressBackgroundColor\">?attr/colorSurface</item>\n        <item name=\"indicatorColor\">?attr/colorSecondary</item>\n    </style>\n\n    <!-- SearchView -->\n    <style name=\"Widget.AppTheme.SearchView\" parent=\"Widget.AppCompat.SearchView\">\n        <item name=\"queryBackground\">@null</item>\n        <item name=\"closeIcon\">@drawable/mtrl_ic_cancel</item>\n        <item name=\"closeIconTint\">@color/m3_textfield_indicator_text_color</item>\n        <item name=\"searchIcon\">@drawable/ic_search</item>\n        <item name=\"queryHint\">@android:string/search_go</item>\n        <item name=\"frameMarginHorizontal\">8dp</item>\n        <item name=\"android:backgroundTint\">?attr/colorSurfaceVariant</item>\n        <item name=\"android:textAppearance\">?attr/textAppearanceBodyLarge</item>\n        <item name=\"shapeAppearanceOverlay\">@style/ShapeAppearance.AppTheme.LargeComponent</item>\n        <item name=\"android:popupBackground\">?attr/popupMenuBackground</item>\n        <item name=\"android:dropDownSelector\">?attr/listChoiceBackgroundIndicator</item>\n    </style>\n\n    <style name=\"Widget.AppTheme.SearchView.Small\" parent=\"Widget.AppTheme.SearchView\">\n        <item name=\"frameMarginHorizontal\">2dp</item>\n        <item name=\"android:textAppearance\">?attr/textAppearanceBodyMedium</item>\n    </style>\n\n    <!-- MaterialAlertView -->\n    <style name=\"Widget.AppTheme.MaterialAlertView\" parent=\"Widget.AppTheme.TextInputLayout\">\n        <item name=\"boxBackgroundColor\">?attr/colorPrimaryContainer</item>\n        <item name=\"boxStrokeWidth\">0dp</item>\n        <item name=\"boxStrokeWidthFocused\">0dp</item>\n        <item name=\"startIconDrawable\">@drawable/ic_information</item>\n        <item name=\"startIconTint\">?attr/colorOnPrimaryContainer</item>\n        <item name=\"android:textColor\">?attr/colorOnPrimaryContainer</item>\n        <item name=\"android:textAppearance\">?attr/textAppearanceBodyMedium</item>\n        <item name=\"shapeAppearanceOverlay\">@style/ShapeAppearance.AppTheme.MediumComponent</item>\n    </style>\n\n    <style name=\"Widget.AppTheme.MaterialAlertView.Warn\" parent=\"Widget.AppTheme.MaterialAlertView\">\n        <item name=\"boxBackgroundColor\">?attr/colorErrorContainer</item>\n        <item name=\"startIconDrawable\">@drawable/ic_caution</item>\n        <item name=\"startIconTint\">?attr/colorOnErrorContainer</item>\n        <item name=\"android:textColor\">?attr/colorOnErrorContainer</item>\n    </style>\n\n    <!-- Preferences -->\n    <style name=\"Preference.M3\" parent=\"Preference.Material\">\n        <item name=\"android:layout\">@layout/m3_preference</item>\n    </style>\n\n    <style name=\"Preference.M3.Alert\" parent=\"Preference.Material\">\n        <item name=\"android:layout\">@layout/m3_preference_alert</item>\n    </style>\n\n    <style name=\"Preference.M3.Category\" parent=\"Preference.Category.Material\">\n        <item name=\"android:layout\">@layout/m3_preference_category</item>\n        <item name=\"allowDividerAbove\">false</item>\n    </style>\n\n    <style name=\"Preference.M3.CheckBoxPreference\" parent=\"Preference.CheckBoxPreference.Material\">\n        <item name=\"android:layout\">@layout/m3_preference</item>\n    </style>\n\n    <style name=\"Preference.M3.DialogPreference\" parent=\"Preference.DialogPreference.Material\">\n        <item name=\"android:layout\">@layout/m3_preference</item>\n    </style>\n\n    <style name=\"Preference.M3.DialogPreference.EditTextPreference\" parent=\"Preference.DialogPreference.EditTextPreference.Material\">\n        <item name=\"android:layout\">@layout/m3_preference</item>\n    </style>\n\n    <style name=\"Preference.M3.PreferenceScreen\" parent=\"Preference.PreferenceScreen.Material\">\n        <item name=\"android:layout\">@layout/m3_preference</item>\n    </style>\n\n    <style name=\"Preference.M3.ButtonPreference.Primary\" parent=\"Preference.Material\">\n        <item name=\"android:layout\">@layout/m3_preference_button</item>\n    </style>\n\n    <style name=\"Preference.M3.SwitchPreference\" parent=\"Preference.SwitchPreference.Material\">\n        <item name=\"android:layout\">@layout/m3_preference</item>\n    </style>\n\n    <style name=\"Preference.M3.SwitchPreferenceCompat\" parent=\"Preference.SwitchPreferenceCompat.Material\">\n        <item name=\"android:layout\">@layout/m3_preference</item>\n        <item name=\"android:widgetLayout\">@layout/m3_preference_widget_material_switch</item>\n    </style>\n\n    <style name=\"Preference.M3.TopSwitchPreference\" parent=\"Preference.M3.SwitchPreferenceCompat\">\n        <item name=\"android:layout\">@layout/m3_preference_top_switch</item>\n        <item name=\"listItemPaddingVertical\">@dimen/padding_medium</item>\n    </style>\n\n    <!-- TextInputLayout -->\n    <style name=\"Widget.AppTheme.TextInputLayout\" parent=\"Widget.Material3.TextInputLayout.OutlinedBox.Dense\">\n        <item name=\"shapeAppearanceOverlay\">@style/ShapeAppearance.AppTheme.LargeComponent</item>\n        <item name=\"materialThemeOverlay\">@style/ThemeOverlay.AppTheme.TextInputLayout</item>\n    </style>\n\n    <style name=\"Widget.AppTheme.TextInputLayout.Small\" parent=\"Widget.AppTheme.TextInputLayout\">\n        <item name=\"hintTextAppearance\">@style/TextAppearance.AppTheme.LabelSmaller</item>\n        <item name=\"materialThemeOverlay\">@style/ThemeOverlay.AppTheme.TextInputLayout.Small</item>\n    </style>\n\n    <style name=\"Widget.AppTheme.TextInputLayout.ExposedDropdownMenu\" parent=\"Widget.Material3.TextInputLayout.OutlinedBox.Dense.ExposedDropdownMenu\">\n        <item name=\"shapeAppearanceOverlay\">@style/ShapeAppearance.AppTheme.LargeComponent</item>\n        <item name=\"materialThemeOverlay\">@style/ThemeOverlay.AppTheme.TextInputLayout</item>\n    </style>\n\n    <style name=\"Widget.AppTheme.TextInputLayout.ExposedDropdownMenu.Small\" parent=\"Widget.AppTheme.TextInputLayout.ExposedDropdownMenu\">\n        <item name=\"hintTextAppearance\">@style/TextAppearance.AppTheme.LabelSmaller</item>\n        <item name=\"materialThemeOverlay\">@style/ThemeOverlay.AppTheme.TextInputLayout.Small</item>\n    </style>\n\n    <style name=\"ThemeOverlay.AppTheme.TextInputLayout\" parent=\"\">\n        <item name=\"autoCompleteTextViewStyle\">@style/Widget.AppTheme.AutoCompleteTextView</item>\n        <item name=\"editTextStyle\">@style/Widget.AppTheme.TextInputEditText</item>\n    </style>\n\n    <style name=\"ThemeOverlay.AppTheme.TextInputLayout.Small\" parent=\"\">\n        <item name=\"autoCompleteTextViewStyle\">@style/Widget.AppTheme.AutoCompleteTextView.Small</item>\n        <item name=\"editTextStyle\">@style/Widget.AppTheme.TextInputEditText.Small</item>\n        <item name=\"endIconMinSize\">40dp</item>\n    </style>\n\n    <!-- TextInputEditText -->\n    <style name=\"Widget.AppTheme.TextInputEditText\" parent=\"Widget.Material3.TextInputEditText.OutlinedBox.Dense\" />\n\n    <style name=\"Widget.AppTheme.TextInputEditText.Small\" parent=\"Widget.AppTheme.TextInputEditText\">\n        <item name=\"android:textAppearance\">?attr/textAppearanceBodySmall</item>\n        <item name=\"android:paddingStart\">12dp</item>\n        <item name=\"android:paddingEnd\">12dp</item>\n        <item name=\"android:paddingTop\">8dp</item>\n        <item name=\"android:paddingBottom\">8dp</item>\n        <item name=\"android:minHeight\">34dp</item>\n    </style>\n\n    <!-- AutoCompleteTextView -->\n    <style name=\"Widget.AppTheme.AutoCompleteTextView\" parent=\"Widget.Material3.AutoCompleteTextView.OutlinedBox.Dense\">\n        <item name=\"simpleItemLayout\">@layout/auto_complete_dropdown_item</item>\n        <item name=\"android:dropDownSelector\">?attr/listChoiceBackgroundIndicator</item>\n    </style>\n\n    <style name=\"Widget.AppTheme.AutoCompleteTextView.Small\" parent=\"Widget.AppTheme.AutoCompleteTextView\">\n        <item name=\"android:textAppearance\">?attr/textAppearanceBodySmall</item>\n        <item name=\"android:paddingStart\">12dp</item>\n        <item name=\"android:paddingEnd\">12dp</item>\n        <item name=\"android:paddingTop\">8dp</item>\n        <item name=\"android:paddingBottom\">8dp</item>\n        <item name=\"android:minHeight\">34dp</item>\n    </style>\n\n    <!-- Button attributes -->\n    <style name=\"Widget.AppTheme.Button.ElevatedButton\" parent=\"Widget.Material3.Button.ElevatedButton\" />\n\n    <style name=\"Widget.AppTheme.Button.ElevatedButton.Dense\" parent=\"Widget.AppTheme.Button.ElevatedButton\">\n        <item name=\"android:minWidth\">0dp</item>\n        <item name=\"android:minHeight\">0dp</item>\n    </style>\n\n    <style name=\"Widget.AppTheme.Button.FilledButton\" parent=\"Widget.Material3.Button\" />\n\n    <style name=\"Widget.AppTheme.Button.FilledButton.Dense\" parent=\"Widget.AppTheme.Button.FilledButton\">\n        <item name=\"android:minWidth\">0dp</item>\n        <item name=\"android:minHeight\">0dp</item>\n    </style>\n\n    <style name=\"Widget.AppTheme.Button.FilledTonalButton\" parent=\"Widget.Material3.Button.TonalButton\" />\n\n    <style name=\"Widget.AppTheme.Button.FilledTonalButton.Dense\" parent=\"Widget.AppTheme.Button.FilledTonalButton\">\n        <item name=\"android:minWidth\">0dp</item>\n        <item name=\"android:minHeight\">0dp</item>\n    </style>\n\n    <style name=\"Widget.AppTheme.Button.OutlinedButton\" parent=\"Widget.Material3.Button.OutlinedButton\" />\n\n    <style name=\"Widget.AppTheme.Button.OutlinedButton.Dense\" parent=\"Widget.AppTheme.Button.OutlinedButton\">\n        <item name=\"android:minWidth\">0dp</item>\n        <item name=\"android:minHeight\">0dp</item>\n    </style>\n\n    <style name=\"Widget.AppTheme.Button.TextButton\" parent=\"Widget.Material3.Button.TextButton\" />\n\n    <style name=\"Widget.AppTheme.Button.TextIconButton\" parent=\"Widget.AppTheme.Button.TextButton\">\n        <item name=\"android:minWidth\">120dp</item>\n        <item name=\"android:gravity\">center</item>\n        <item name=\"android:padding\">16dp</item>\n        <item name=\"android:textAppearance\">?android:attr/textAppearanceListItem</item>\n        <item name=\"android:textColor\">?attr/colorOnSurfaceVariant</item>\n        <item name=\"android:textSize\">14sp</item>\n        <item name=\"iconGravity\">textTop</item>\n        <item name=\"iconSize\">30dp</item>\n        <item name=\"iconTint\">?attr/colorOnSurfaceVariant</item>\n        <item name=\"shapeAppearanceOverlay\">@style/ShapeAppearance.AppTheme.None</item>\n    </style>\n\n    <style name=\"Widget.AppTheme.Button.TextButton.Icon\" parent=\"Widget.Material3.Button.TextButton.Icon\" />\n\n    <style name=\"Widget.AppTheme.Button.IconButton\" parent=\"Widget.Material3.Button.IconButton\">\n        <item name=\"iconGravity\">textStart</item>\n    </style>\n\n    <style name=\"Widget.AppTheme.Button.IconButton.InverseColor\" parent=\"Widget.Material3.Button.IconButton\">\n        <item name=\"backgroundTint\">@color/sixty_percent_black</item>\n        <item name=\"iconTint\">?attr/colorSurface</item>\n        <item name=\"iconGravity\">textStart</item>\n    </style>\n\n    <style name=\"Widget.AppTheme.Button.FAB\" parent=\"Widget.Material3.FloatingActionButton.Primary\" />\n\n    <style name=\"Widget.AppTheme.Button.EFAB\" parent=\"Widget.Material3.ExtendedFloatingActionButton.Primary\" />\n\n    <!-- ShapeAppearance attributes -->\n    <style name=\"ShapeAppearance.AppTheme.None\" parent=\"ShapeAppearance.Material3.SmallComponent\">\n        <item name=\"cornerSize\">0dp</item>\n    </style>\n\n    <style name=\"ShapeAppearance.AppTheme.SmallComponent\" parent=\"ShapeAppearance.Material3.SmallComponent\">\n        <item name=\"cornerSize\">12dp</item>\n    </style>\n\n    <style name=\"ShapeAppearance.AppTheme.MediumComponent\" parent=\"ShapeAppearance.Material3.MediumComponent\">\n        <item name=\"cornerSize\">16dp</item>\n    </style>\n\n    <style name=\"ShapeAppearance.AppTheme.LargeComponent\" parent=\"ShapeAppearance.Material3.LargeComponent\">\n        <item name=\"cornerSize\">24dp</item>\n    </style>\n\n    <style name=\"ShapeAppearance.AppTheme.CircleComponent\" parent=\"\">\n        <item name=\"cornerSize\">50%</item>\n    </style>\n\n    <style name=\"ShapeAppearance.AppTheme.DiagonallyRounded\" parent=\"\">\n        <item name=\"cornerSize\">24dp</item>\n        <item name=\"cornerFamily\">rounded</item>\n        <item name=\"cornerSizeBottomRight\">0dp</item>\n        <item name=\"cornerSizeTopLeft\">0dp</item>\n    </style>\n\n    <style name=\"ShapeAppearance.AppTheme.LeftRounded\" parent=\"\">\n        <item name=\"cornerSize\">24dp</item>\n        <item name=\"cornerFamily\">rounded</item>\n        <item name=\"cornerSizeTopRight\">0dp</item>\n        <item name=\"cornerSizeBottomRight\">0dp</item>\n    </style>\n\n    <style name=\"ShapeAppearance.AppTheme.RightRounded\" parent=\"\">\n        <item name=\"cornerSize\">24dp</item>\n        <item name=\"cornerFamily\">rounded</item>\n        <item name=\"cornerSizeTopLeft\">0dp</item>\n        <item name=\"cornerSizeBottomLeft\">0dp</item>\n    </style>\n\n    <style name=\"ShapeAppearance.AppTheme.MediumComponent.RoundedTop\" parent=\"\">\n        <item name=\"cornerSize\">16dp</item>\n        <item name=\"cornerFamily\">rounded</item>\n        <item name=\"cornerSizeBottomLeft\">0dp</item>\n        <item name=\"cornerSizeBottomRight\">0dp</item>\n    </style>\n\n    <!-- TextAppearance attributes: We do not use Material* or AppCompat because they change over time -->\n    <style name=\"TextAppearance.AppTheme.DisplayLarge\" parent=\"TextAppearance.Material3.DisplayLarge\" />\n\n    <style name=\"TextAppearance.AppTheme.DisplayMedium\" parent=\"TextAppearance.Material3.DisplayMedium\" />\n\n    <style name=\"TextAppearance.AppTheme.DisplaySmall\" parent=\"TextAppearance.Material3.DisplaySmall\" />\n\n    <style name=\"TextAppearance.AppTheme.HeadlineLarge\" parent=\"TextAppearance.Material3.HeadlineLarge\" />\n\n    <style name=\"TextAppearance.AppTheme.HeadlineMedium\" parent=\"TextAppearance.Material3.HeadlineMedium\" />\n\n    <style name=\"TextAppearance.AppTheme.HeadlineSmall\" parent=\"TextAppearance.Material3.HeadlineSmall\" />\n\n    <style name=\"TextAppearance.AppTheme.TitleLarge\" parent=\"TextAppearance.Material3.TitleLarge\" />\n\n    <style name=\"TextAppearance.AppTheme.TitleMedium\" parent=\"TextAppearance.Material3.TitleMedium\">\n        <item name=\"android:letterSpacing\">0</item>\n        <item name=\"android:textSize\">18sp</item>\n        <item name=\"android:fontFamily\">@string/m3_ref_typeface_brand_regular</item>\n        <item name=\"fontFamily\">@string/m3_ref_typeface_brand_regular</item>\n    </style>\n\n    <style name=\"TextAppearance.AppTheme.TitleSmall\" parent=\"TextAppearance.Material3.TitleSmall\" />\n\n    <style name=\"TextAppearance.AppTheme.BodyLarge\" parent=\"TextAppearance.Material3.BodyLarge\" />\n\n    <style name=\"TextAppearance.AppTheme.BodyMedium\" parent=\"TextAppearance.Material3.BodyMedium\" />\n\n    <style name=\"TextAppearance.AppTheme.BodyMedium.Secondary\" parent=\"TextAppearance.AppTheme.BodyMedium\">\n        <item name=\"android:textColor\">?android:attr/textColorSecondary</item>\n    </style>\n\n    <style name=\"TextAppearance.AppTheme.BodySmall\" parent=\"TextAppearance.Material3.BodySmall\" />\n\n    <style name=\"TextAppearance.AppTheme.LabelLarge\" parent=\"TextAppearance.Material3.LabelLarge\" />\n\n    <style name=\"TextAppearance.AppTheme.LabelMedium\" parent=\"TextAppearance.Material3.LabelMedium\" />\n\n    <style name=\"TextAppearance.AppTheme.LabelSmall\" parent=\"TextAppearance.Material3.LabelSmall\" />\n\n    <style name=\"TextAppearance.AppTheme.LabelSmaller\" parent=\"TextAppearance.Material3.LabelSmall\">\n        <item name=\"android:textSize\">10sp</item>\n    </style>\n</resources>\n"
  },
  {
    "path": "libcore/ui/src/main/res/values-large/bools.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <bool name=\"large_layout\">true</bool>\n</resources>"
  },
  {
    "path": "libcore/ui/src/main/res/values-ldrtl/styles.xml",
    "content": "<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<resources>\n    <style name=\"ShapeAppearance.AppTheme.DiagonallyRounded\" parent=\"\">\n        <item name=\"cornerSize\">24dp</item>\n        <item name=\"cornerFamily\">rounded</item>\n        <item name=\"cornerSizeBottomLeft\">0dp</item>\n        <item name=\"cornerSizeTopRight\">0dp</item>\n    </style>\n</resources>\n"
  },
  {
    "path": "libcore/ui/src/main/res/values-night/colors.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<resources>\n    <color name=\"textColorPrimary\">@android:color/white</color>\n    <color name=\"textColorSecondary\">#FFBEBEBE</color>\n\n    <color name=\"disabled_user\">#BF4F1C14</color>\n    <color name=\"highlight\">#6f5f4f</color>\n    <color name=\"red\">#790D0D</color>\n    <color name=\"running\">@color/purple</color>\n    <color name=\"semi_transparent\">#10FFFFFF</color>\n    <color name=\"sixty_percent_white\">#9A000000</color>\n    <color name=\"sixty_percent_black\">#9AFFFFFF</color>\n    <color name=\"tracker\">#80FF8017</color>\n</resources>\n"
  },
  {
    "path": "libcore/ui/src/main/res/values-night/styles.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<resources>\n\n    <style name=\"AppThemeOverlay\" parent=\"Theme.Material3.Dark.NoActionBar\">\n        <item name=\"android:statusBarColor\">@android:color/transparent</item>\n        <item name=\"android:navigationBarColor\">@android:color/transparent</item>\n    </style>\n\n    <style name=\"AppTheme.Black\" parent=\"AppTheme\">\n        <item name=\"colorSurface\">@android:color/black</item>\n        <item name=\"android:windowBackground\">@android:drawable/screen_background_dark</item>\n        <item name=\"materialFullScreenAlertDialogTheme\">@style/AppTheme.Black</item>\n    </style>\n\n    <style name=\"AppTheme.TransparentBackground.Black\" parent=\"AppTheme.TransparentBackground\">\n        <item name=\"colorSurface\">@android:color/black</item>\n        <item name=\"materialFullScreenAlertDialogTheme\">@style/AppTheme.Black</item>\n    </style>\n</resources>\n"
  },
  {
    "path": "libcore/ui/src/main/res/values-v23/styles.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<resources>\n    <style name=\"AppThemeOverlay\" parent=\"Theme.Material3.Light.NoActionBar\">\n        <item name=\"android:windowLightStatusBar\">true</item>\n        <item name=\"android:statusBarColor\">@android:color/transparent</item>\n        <item name=\"android:navigationBarColor\">#99000000</item>\n    </style>\n</resources>\n"
  },
  {
    "path": "libcore/ui/src/main/res/values-v27/styles.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<resources>\n    <style name=\"AppThemeOverlay\" parent=\"Theme.Material3.DayNight.NoActionBar\">\n        <item name=\"android:windowLightStatusBar\">true</item>\n        <item name=\"android:windowLightNavigationBar\">true</item>\n        <item name=\"android:statusBarColor\">@android:color/transparent</item>\n        <item name=\"android:navigationBarColor\">@android:color/transparent</item>\n        <item name=\"android:windowLayoutInDisplayCutoutMode\">shortEdges</item>\n    </style>\n</resources>\n"
  },
  {
    "path": "libcore/ui/src/main/res/values-v29/styles.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<resources>\n    <style name=\"AppThemeOverlay\" parent=\"Theme.Material3.DayNight.NoActionBar\">\n        <item name=\"android:windowLightStatusBar\">true</item>\n        <item name=\"android:windowLightNavigationBar\">true</item>\n        <item name=\"android:enforceNavigationBarContrast\">false</item>\n        <item name=\"android:statusBarColor\">@android:color/transparent</item>\n        <item name=\"android:navigationBarColor\">@android:color/transparent</item>\n        <item name=\"android:windowLayoutInDisplayCutoutMode\">shortEdges</item>\n    </style>\n</resources>\n"
  },
  {
    "path": "libopenpgp/.gitignore",
    "content": "/build"
  },
  {
    "path": "libopenpgp/build.gradle",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\napply plugin: 'com.android.library'\n\nandroid {\n    namespace 'org.openintents.openpgp'\n    compileSdk compile_sdk\n    buildToolsVersion = build_tools\n\n    defaultConfig {\n        minSdk min_sdk\n        targetSdk target_sdk\n    }\n\n    compileOptions {\n        encoding \"UTF-8\"\n        sourceCompatibility JavaVersion.VERSION_1_8\n        targetCompatibility JavaVersion.VERSION_1_8\n    }\n    buildFeatures {\n        aidl true\n    }\n}\n\ndependencies {\n    implementation \"androidx.annotation:annotation:${annotation_version}\"\n}\n"
  },
  {
    "path": "libopenpgp/src/main/AndroidManifest.xml",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-or-later -->\n<manifest />"
  },
  {
    "path": "libopenpgp/src/main/aidl/org/openintents/openpgp/IOpenPgpService.aidl",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage org.openintents.openpgp;\n\n// Copyright 2014-2015 Dominik Schürmann\ninterface IOpenPgpService {\n\n    /**\n     * do NOT use this, data returned from the service through \"output\" may be truncated\n     * @deprecated\n     */\n    Intent execute(in Intent data, in ParcelFileDescriptor input, in ParcelFileDescriptor output);\n\n}"
  },
  {
    "path": "libopenpgp/src/main/aidl/org/openintents/openpgp/IOpenPgpService2.aidl",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage org.openintents.openpgp;\n\n// Copyright 2015 Dominik Schürmann\ninterface IOpenPgpService2 {\n\n    /**\n     * see org.openintents.openpgp.util.OpenPgpApi for documentation\n     */\n    ParcelFileDescriptor createOutputPipe(in int pipeId);\n\n    /**\n     * see org.openintents.openpgp.util.OpenPgpApi for documentation\n     */\n    Intent execute(in Intent data, in ParcelFileDescriptor input, int pipeId);\n}\n"
  },
  {
    "path": "libopenpgp/src/main/java/org/openintents/openpgp/AutocryptPeerUpdate.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage org.openintents.openpgp;\n\n\nimport java.util.Date;\n\nimport android.os.Parcel;\nimport android.os.Parcelable;\n\n\n// Copyright 2014-2015 Dominik Schürmann\n@SuppressWarnings(\"unused\")\npublic class AutocryptPeerUpdate implements Parcelable {\n    /**\n     * Since there might be a case where new versions of the client using the library getting\n     * old versions of the protocol (and thus old versions of this class), we need a versioning\n     * system for the parcels sent between the clients and the providers.\n     */\n    private static final int PARCELABLE_VERSION = 1;\n\n\n    private final byte[] keyData;\n    private final Date effectiveDate;\n    private final PreferEncrypt preferEncrypt;\n\n\n    private AutocryptPeerUpdate(byte[] keyData, Date effectiveDate, PreferEncrypt preferEncrypt) {\n        this.keyData = keyData;\n        this.effectiveDate = effectiveDate;\n        this.preferEncrypt = preferEncrypt;\n    }\n\n    private AutocryptPeerUpdate(Parcel source, int version) {\n        this.keyData = source.createByteArray();\n        this.effectiveDate = source.readInt() != 0 ? new Date(source.readLong()) : null;\n        this.preferEncrypt = PreferEncrypt.values()[source.readInt()];\n    }\n\n\n    public static AutocryptPeerUpdate createAutocryptPeerUpdate(byte[] keyData, Date timestamp) {\n        return new AutocryptPeerUpdate(keyData, timestamp, PreferEncrypt.NOPREFERENCE);\n    }\n\n    public byte[] getKeyData() {\n        return keyData;\n    }\n\n    public boolean hasKeyData() {\n        return keyData != null;\n    }\n\n    public Date getEffectiveDate() {\n        return effectiveDate;\n    }\n\n    public PreferEncrypt getPreferEncrypt() {\n        return preferEncrypt;\n    }\n\n\n    public int describeContents() {\n        return 0;\n    }\n\n    public void writeToParcel(Parcel dest, int flags) {\n        /*\n          NOTE: When adding fields in the process of updating this API, make sure to bump\n          {@link #PARCELABLE_VERSION}.\n         */\n        dest.writeInt(PARCELABLE_VERSION);\n        // Inject a placeholder that will store the parcel size from this point on\n        // (not including the size itself).\n        int sizePosition = dest.dataPosition();\n        dest.writeInt(0);\n        int startPosition = dest.dataPosition();\n\n        // version 1\n        dest.writeByteArray(keyData);\n        if (effectiveDate != null) {\n            dest.writeInt(1);\n            dest.writeLong(effectiveDate.getTime());\n        } else {\n            dest.writeInt(0);\n        }\n\n        dest.writeInt(preferEncrypt.ordinal());\n\n        // Go back and write the size\n        int parcelableSize = dest.dataPosition() - startPosition;\n        dest.setDataPosition(sizePosition);\n        dest.writeInt(parcelableSize);\n        dest.setDataPosition(startPosition + parcelableSize);\n    }\n\n    public static final Creator<AutocryptPeerUpdate> CREATOR = new Creator<AutocryptPeerUpdate>() {\n        public AutocryptPeerUpdate createFromParcel(final Parcel source) {\n            int version = source.readInt(); // parcelableVersion\n            int parcelableSize = source.readInt();\n            int startPosition = source.dataPosition();\n\n            AutocryptPeerUpdate vr = new AutocryptPeerUpdate(source, version);\n\n            // skip over all fields added in future versions of this parcel\n            source.setDataPosition(startPosition + parcelableSize);\n\n            return vr;\n        }\n\n        public AutocryptPeerUpdate[] newArray(final int size) {\n            return new AutocryptPeerUpdate[size];\n        }\n    };\n\n    public enum PreferEncrypt {\n        NOPREFERENCE, MUTUAL\n    }\n}\n"
  },
  {
    "path": "libopenpgp/src/main/java/org/openintents/openpgp/OpenPgpDecryptionResult.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage org.openintents.openpgp;\n\nimport java.util.Arrays;\n\nimport android.os.Parcel;\nimport android.os.Parcelable;\n\n// Copyright 2015 Dominik Schürmann\npublic class OpenPgpDecryptionResult implements Parcelable {\n    /**\n     * Since there might be a case where new versions of the client using the library getting\n     * old versions of the protocol (and thus old versions of this class), we need a versioning\n     * system for the parcels sent between the clients and the providers.\n     */\n    public static final int PARCELABLE_VERSION = 2;\n\n    // content not encrypted\n    public static final int RESULT_NOT_ENCRYPTED = -1;\n    // insecure!\n    public static final int RESULT_INSECURE = 0;\n    // encrypted\n    public static final int RESULT_ENCRYPTED = 1;\n\n    private final int result;\n    private final byte[] sessionKey;\n    private final byte[] decryptedSessionKey;\n\n    public OpenPgpDecryptionResult(int result) {\n        this.result = result;\n        this.sessionKey = null;\n        this.decryptedSessionKey = null;\n    }\n\n    public OpenPgpDecryptionResult(int result, byte[] sessionKey, byte[] decryptedSessionKey) {\n        this.result = result;\n        if ((sessionKey == null) != (decryptedSessionKey == null)) {\n            throw new AssertionError(\"sessionkey must be null iff decryptedSessionKey is null\");\n        }\n        this.sessionKey = sessionKey;\n        this.decryptedSessionKey = decryptedSessionKey;\n    }\n\n    public int getResult() {\n        return result;\n    }\n\n    public boolean hasDecryptedSessionKey() {\n        return sessionKey != null;\n    }\n\n    public byte[] getSessionKey() {\n        if (sessionKey == null) {\n            return null;\n        }\n        return Arrays.copyOf(sessionKey, sessionKey.length);\n    }\n\n    public byte[] getDecryptedSessionKey() {\n        if (sessionKey == null || decryptedSessionKey == null) {\n            return null;\n        }\n        return Arrays.copyOf(decryptedSessionKey, decryptedSessionKey.length);\n    }\n\n    public int describeContents() {\n        return 0;\n    }\n\n    public void writeToParcel(Parcel dest, int flags) {\n        /*\n          NOTE: When adding fields in the process of updating this API, make sure to bump\n          {@link #PARCELABLE_VERSION}.\n         */\n        dest.writeInt(PARCELABLE_VERSION);\n        // Inject a placeholder that will store the parcel size from this point on\n        // (not including the size itself).\n        int sizePosition = dest.dataPosition();\n        dest.writeInt(0);\n        int startPosition = dest.dataPosition();\n        // version 1\n        dest.writeInt(result);\n        // version 2\n        dest.writeByteArray(sessionKey);\n        dest.writeByteArray(decryptedSessionKey);\n        // Go back and write the size\n        int parcelableSize = dest.dataPosition() - startPosition;\n        dest.setDataPosition(sizePosition);\n        dest.writeInt(parcelableSize);\n        dest.setDataPosition(startPosition + parcelableSize);\n    }\n\n    public static final Creator<OpenPgpDecryptionResult> CREATOR = new Creator<OpenPgpDecryptionResult>() {\n        public OpenPgpDecryptionResult createFromParcel(final Parcel source) {\n            int version = source.readInt(); // parcelableVersion\n            int parcelableSize = source.readInt();\n            int startPosition = source.dataPosition();\n\n            int result = source.readInt();\n            byte[] sessionKey = version > 1 ? source.createByteArray() : null;\n            byte[] decryptedSessionKey = version > 1 ? source.createByteArray() : null;\n\n            OpenPgpDecryptionResult vr = new OpenPgpDecryptionResult(result, sessionKey, decryptedSessionKey);\n\n            // skip over all fields added in future versions of this parcel\n            source.setDataPosition(startPosition + parcelableSize);\n\n            return vr;\n        }\n\n        public OpenPgpDecryptionResult[] newArray(final int size) {\n            return new OpenPgpDecryptionResult[size];\n        }\n    };\n\n    @Override\n    public String toString() {\n        return \"\\nresult: \" + result;\n    }\n\n}\n"
  },
  {
    "path": "libopenpgp/src/main/java/org/openintents/openpgp/OpenPgpError.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage org.openintents.openpgp;\n\nimport android.os.Parcel;\nimport android.os.Parcelable;\n\n// Copyright 2014-2015 Dominik Schürmann\npublic class OpenPgpError implements Parcelable {\n    /**\n     * Since there might be a case where new versions of the client using the library getting\n     * old versions of the protocol (and thus old versions of this class), we need a versioning\n     * system for the parcels sent between the clients and the providers.\n     */\n    public static final int PARCELABLE_VERSION = 1;\n\n    // possible values for errorId\n    public static final int CLIENT_SIDE_ERROR = -1;\n    public static final int GENERIC_ERROR = 0;\n    public static final int INCOMPATIBLE_API_VERSIONS = 1;\n    public static final int NO_OR_WRONG_PASSPHRASE = 2;\n    public static final int NO_USER_IDS = 3;\n    public static final int OPPORTUNISTIC_MISSING_KEYS = 4;\n\n\n    int errorId;\n    String message;\n\n    public OpenPgpError() {\n    }\n\n    public OpenPgpError(int errorId, String message) {\n        this.errorId = errorId;\n        this.message = message;\n    }\n\n    public OpenPgpError(OpenPgpError b) {\n        this.errorId = b.errorId;\n        this.message = b.message;\n    }\n\n    public int getErrorId() {\n        return errorId;\n    }\n\n    public void setErrorId(int errorId) {\n        this.errorId = errorId;\n    }\n\n    public String getMessage() {\n        return message;\n    }\n\n    public void setMessage(String message) {\n        this.message = message;\n    }\n\n    public int describeContents() {\n        return 0;\n    }\n\n    public void writeToParcel(Parcel dest, int flags) {\n        /*\n          NOTE: When adding fields in the process of updating this API, make sure to bump\n          {@link #PARCELABLE_VERSION}.\n         */\n        dest.writeInt(PARCELABLE_VERSION);\n        // Inject a placeholder that will store the parcel size from this point on\n        // (not including the size itself).\n        int sizePosition = dest.dataPosition();\n        dest.writeInt(0);\n        int startPosition = dest.dataPosition();\n        // version 1\n        dest.writeInt(errorId);\n        dest.writeString(message);\n        // Go back and write the size\n        int parcelableSize = dest.dataPosition() - startPosition;\n        dest.setDataPosition(sizePosition);\n        dest.writeInt(parcelableSize);\n        dest.setDataPosition(startPosition + parcelableSize);\n    }\n\n    public static final Creator<OpenPgpError> CREATOR = new Creator<OpenPgpError>() {\n        public OpenPgpError createFromParcel(final Parcel source) {\n            source.readInt(); // parcelableVersion\n            int parcelableSize = source.readInt();\n            int startPosition = source.dataPosition();\n\n            OpenPgpError error = new OpenPgpError();\n            error.errorId = source.readInt();\n            error.message = source.readString();\n\n            // skip over all fields added in future versions of this parcel\n            source.setDataPosition(startPosition + parcelableSize);\n\n            return error;\n        }\n\n        public OpenPgpError[] newArray(final int size) {\n            return new OpenPgpError[size];\n        }\n    };\n}\n"
  },
  {
    "path": "libopenpgp/src/main/java/org/openintents/openpgp/OpenPgpMetadata.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage org.openintents.openpgp;\n\nimport android.os.Parcel;\nimport android.os.Parcelable;\n\n// Copyright 2014-2015 Dominik Schürmann\npublic class OpenPgpMetadata implements Parcelable {\n    /**\n     * Since there might be a case where new versions of the client using the library getting\n     * old versions of the protocol (and thus old versions of this class), we need a versioning\n     * system for the parcels sent between the clients and the providers.\n     */\n    public static final int PARCELABLE_VERSION = 2;\n\n    String filename;\n    String mimeType;\n    String charset;\n    long modificationTime;\n    long originalSize;\n\n    public String getFilename() {\n        return filename;\n    }\n\n    public String getMimeType() {\n        return mimeType;\n    }\n\n    public long getModificationTime() {\n        return modificationTime;\n    }\n\n    public long getOriginalSize() {\n        return originalSize;\n    }\n\n    public String getCharset() {\n        return charset;\n    }\n\n    public OpenPgpMetadata() {\n    }\n\n    public OpenPgpMetadata(String filename, String mimeType, long modificationTime,\n                           long originalSize, String charset) {\n        this.filename = filename;\n        this.mimeType = mimeType;\n        this.modificationTime = modificationTime;\n        this.originalSize = originalSize;\n        this.charset = charset;\n    }\n\n    public OpenPgpMetadata(String filename, String mimeType, long modificationTime,\n                           long originalSize) {\n        this.filename = filename;\n        this.mimeType = mimeType;\n        this.modificationTime = modificationTime;\n        this.originalSize = originalSize;\n    }\n\n    public OpenPgpMetadata(OpenPgpMetadata b) {\n        this.filename = b.filename;\n        this.mimeType = b.mimeType;\n        this.modificationTime = b.modificationTime;\n        this.originalSize = b.originalSize;\n    }\n\n    public int describeContents() {\n        return 0;\n    }\n\n    public void writeToParcel(Parcel dest, int flags) {\n        /*\n         * NOTE: When adding fields in the process of updating this API, make sure to bump\n         * {@link #PARCELABLE_VERSION}.\n         */\n        dest.writeInt(PARCELABLE_VERSION);\n        // Inject a placeholder that will store the parcel size from this point on\n        // (not including the size itself).\n        int sizePosition = dest.dataPosition();\n        dest.writeInt(0);\n        int startPosition = dest.dataPosition();\n        // version 1\n        dest.writeString(filename);\n        dest.writeString(mimeType);\n        dest.writeLong(modificationTime);\n        dest.writeLong(originalSize);\n        // version 2\n        dest.writeString(charset);\n        // Go back and write the size\n        int parcelableSize = dest.dataPosition() - startPosition;\n        dest.setDataPosition(sizePosition);\n        dest.writeInt(parcelableSize);\n        dest.setDataPosition(startPosition + parcelableSize);\n    }\n\n    public static final Creator<OpenPgpMetadata> CREATOR = new Creator<OpenPgpMetadata>() {\n        public OpenPgpMetadata createFromParcel(final Parcel source) {\n            int version = source.readInt(); // parcelableVersion\n            int parcelableSize = source.readInt();\n            int startPosition = source.dataPosition();\n\n            OpenPgpMetadata vr = new OpenPgpMetadata();\n            vr.filename = source.readString();\n            vr.mimeType = source.readString();\n            vr.modificationTime = source.readLong();\n            vr.originalSize = source.readLong();\n            if (version >= 2) {\n                vr.charset = source.readString();\n            }\n\n            // skip over all fields added in future versions of this parcel\n            source.setDataPosition(startPosition + parcelableSize);\n\n            return vr;\n        }\n\n        public OpenPgpMetadata[] newArray(final int size) {\n            return new OpenPgpMetadata[size];\n        }\n    };\n\n    @Override\n    public String toString() {\n        String out = \"\\nfilename: \" + filename;\n        out += \"\\nmimeType: \" + mimeType;\n        out += \"\\nmodificationTime: \" + modificationTime;\n        out += \"\\noriginalSize: \" + originalSize;\n        out += \"\\ncharset: \" + charset;\n        return out;\n    }\n\n}\n"
  },
  {
    "path": "libopenpgp/src/main/java/org/openintents/openpgp/OpenPgpSignatureResult.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage org.openintents.openpgp;\n\nimport java.util.Collections;\nimport java.util.Date;\nimport java.util.List;\n\nimport android.os.Parcel;\nimport android.os.Parcelable;\n\nimport org.openintents.openpgp.util.OpenPgpUtils;\n\n// Copyright 2014-2015 Dominik Schürmann\n@SuppressWarnings(\"unused\")\npublic class OpenPgpSignatureResult implements Parcelable {\n    /**\n     * Since there might be a case where new versions of the client using the library getting\n     * old versions of the protocol (and thus old versions of this class), we need a versioning\n     * system for the parcels sent between the clients and the providers.\n     */\n    private static final int PARCELABLE_VERSION = 5;\n\n    // content not signed\n    public static final int RESULT_NO_SIGNATURE = -1;\n    // invalid signature!\n    public static final int RESULT_INVALID_SIGNATURE = 0;\n    // successfully verified signature, with confirmed key\n    public static final int RESULT_VALID_KEY_CONFIRMED = 1;\n    // no key was found for this signature verification\n    public static final int RESULT_KEY_MISSING = 2;\n    // successfully verified signature, but with unconfirmed key\n    public static final int RESULT_VALID_KEY_UNCONFIRMED = 3;\n    // key has been revoked -> invalid signature!\n    public static final int RESULT_INVALID_KEY_REVOKED = 4;\n    // key is expired -> invalid signature!\n    public static final int RESULT_INVALID_KEY_EXPIRED = 5;\n    // insecure cryptographic algorithms/protocol -> invalid signature!\n    public static final int RESULT_INVALID_KEY_INSECURE = 6;\n    // data wasn't encrypted to recipient intended in signature\n    public static final int RESULT_INVALID_NOT_INTENDED_RECIPIENT = 7;\n\n    private final int result;\n    private final long keyId;\n    private final String primaryUserId;\n    private final List<String> userIds;\n    private final List<String> confirmedUserIds;\n    private final SenderStatusResult senderStatusResult;\n    private final Date signatureTimestamp;\n    private final AutocryptPeerResult autocryptPeerentityResult;\n\n    private OpenPgpSignatureResult(int signatureStatus, String signatureUserId, long keyId,\n                                   List<String> userIds, List<String> confirmedUserIds, SenderStatusResult senderStatusResult,\n                                   Boolean signatureOnly, Date signatureTimestamp, AutocryptPeerResult autocryptPeerentityResult) {\n        this.result = signatureStatus;\n        this.primaryUserId = signatureUserId;\n        this.keyId = keyId;\n        this.userIds = userIds;\n        this.confirmedUserIds = confirmedUserIds;\n        this.senderStatusResult = senderStatusResult;\n        this.signatureTimestamp = signatureTimestamp;\n        this.autocryptPeerentityResult = autocryptPeerentityResult;\n    }\n\n    private OpenPgpSignatureResult(Parcel source, int version) {\n        this.result = source.readInt();\n        // we dropped support for signatureOnly, but need to skip the value for compatibility\n        source.readByte();\n        this.primaryUserId = source.readString();\n        this.keyId = source.readLong();\n\n        if (version > 1) {\n            this.userIds = source.createStringArrayList();\n        } else {\n            this.userIds = null;\n        }\n        // backward compatibility for this exact version\n        if (version > 2) {\n            this.senderStatusResult = readEnumWithNullAndFallback(\n                    source, SenderStatusResult.values, SenderStatusResult.UNKNOWN);\n            this.confirmedUserIds = source.createStringArrayList();\n        } else {\n            this.senderStatusResult = SenderStatusResult.UNKNOWN;\n            this.confirmedUserIds = null;\n        }\n\n        if (version > 3) {\n            this.signatureTimestamp = source.readInt() > 0 ? new Date(source.readLong()) : null;\n        } else {\n            this.signatureTimestamp = null;\n        }\n\n        if (version > 4) {\n            this.autocryptPeerentityResult = readEnumWithNullAndFallback(source, AutocryptPeerResult.values, null);\n        } else {\n            this.autocryptPeerentityResult = null;\n        }\n    }\n\n    public int getResult() {\n        return result;\n    }\n\n    public SenderStatusResult getSenderStatusResult() {\n        return senderStatusResult;\n    }\n\n    public String getPrimaryUserId() {\n        return primaryUserId;\n    }\n\n    public List<String> getUserIds() {\n        return Collections.unmodifiableList(userIds);\n    }\n\n    public List<String> getConfirmedUserIds() {\n        return Collections.unmodifiableList(confirmedUserIds);\n    }\n\n    public long getKeyId() {\n        return keyId;\n    }\n\n    public Date getSignatureTimestamp() {\n        return signatureTimestamp;\n    }\n\n    public int describeContents() {\n        return 0;\n    }\n\n    public void writeToParcel(Parcel dest, int flags) {\n        /*\n          NOTE: When adding fields in the process of updating this API, make sure to bump\n          {@link #PARCELABLE_VERSION}.\n         */\n        dest.writeInt(PARCELABLE_VERSION);\n        // Inject a placeholder that will store the parcel size from this point on\n        // (not including the size itself).\n        int sizePosition = dest.dataPosition();\n        dest.writeInt(0);\n        int startPosition = dest.dataPosition();\n        // version 1\n        dest.writeInt(result);\n        // signatureOnly is deprecated since version 3. we pass a dummy value for compatibility\n        dest.writeByte((byte) 0);\n        dest.writeString(primaryUserId);\n        dest.writeLong(keyId);\n        // version 2\n        dest.writeStringList(userIds);\n        // version 3\n        writeEnumWithNull(dest, senderStatusResult);\n        dest.writeStringList(confirmedUserIds);\n        // version 4\n        if (signatureTimestamp != null) {\n            dest.writeInt(1);\n            dest.writeLong(signatureTimestamp.getTime());\n        } else {\n            dest.writeInt(0);\n        }\n        // version 5\n        writeEnumWithNull(dest, autocryptPeerentityResult);\n        // Go back and write the size\n        int parcelableSize = dest.dataPosition() - startPosition;\n        dest.setDataPosition(sizePosition);\n        dest.writeInt(parcelableSize);\n        dest.setDataPosition(startPosition + parcelableSize);\n    }\n\n    public static final Creator<OpenPgpSignatureResult> CREATOR = new Creator<OpenPgpSignatureResult>() {\n        public OpenPgpSignatureResult createFromParcel(final Parcel source) {\n            int version = source.readInt(); // parcelableVersion\n            int parcelableSize = source.readInt();\n            int startPosition = source.dataPosition();\n\n            OpenPgpSignatureResult vr = new OpenPgpSignatureResult(source, version);\n\n            // skip over all fields added in future versions of this parcel\n            source.setDataPosition(startPosition + parcelableSize);\n\n            return vr;\n        }\n\n        public OpenPgpSignatureResult[] newArray(final int size) {\n            return new OpenPgpSignatureResult[size];\n        }\n    };\n\n    @Override\n    public String toString() {\n        String out = \"\\nresult: \" + result;\n        out += \"\\nprimaryUserId: \" + primaryUserId;\n        out += \"\\nuserIds: \" + userIds;\n        out += \"\\nkeyId: \" + OpenPgpUtils.convertKeyIdToHex(keyId);\n        return out;\n    }\n\n    public static OpenPgpSignatureResult createWithValidSignature(int signatureStatus, String primaryUserId,\n                                                                  long keyId, List<String> userIds, List<String> confirmedUserIds,\n                                                                  SenderStatusResult senderStatusResult, Date signatureTimestamp) {\n        if (signatureStatus == RESULT_NO_SIGNATURE || signatureStatus == RESULT_KEY_MISSING ||\n                signatureStatus == RESULT_INVALID_SIGNATURE) {\n            throw new IllegalArgumentException(\"can only use this method for valid types of signatures\");\n        }\n        return new OpenPgpSignatureResult(signatureStatus, primaryUserId, keyId, userIds, confirmedUserIds,\n                senderStatusResult, null, signatureTimestamp, null);\n    }\n\n    public static OpenPgpSignatureResult createWithNoSignature() {\n        return new OpenPgpSignatureResult(RESULT_NO_SIGNATURE, null, 0L, null, null, null, null, null, null);\n    }\n\n    public static OpenPgpSignatureResult createWithKeyMissing(long keyId, Date signatureTimestamp) {\n        return new OpenPgpSignatureResult(RESULT_KEY_MISSING, null, keyId, null, null, null, null, signatureTimestamp, null);\n    }\n\n    public static OpenPgpSignatureResult createWithInvalidSignature() {\n        return new OpenPgpSignatureResult(RESULT_INVALID_SIGNATURE, null, 0L, null, null, null, null, null, null);\n    }\n\n    @Deprecated\n    public OpenPgpSignatureResult withSignatureOnlyFlag(boolean signatureOnly) {\n        return new OpenPgpSignatureResult(result, primaryUserId, keyId, userIds, confirmedUserIds,\n                senderStatusResult, signatureOnly, signatureTimestamp, autocryptPeerentityResult);\n    }\n\n    public OpenPgpSignatureResult withAutocryptPeerResult(AutocryptPeerResult autocryptPeerentityResult) {\n        return new OpenPgpSignatureResult(\n                result, primaryUserId, keyId, userIds, confirmedUserIds,\n                senderStatusResult, null, signatureTimestamp, autocryptPeerentityResult);\n    }\n\n    private static <T extends Enum<T>> T readEnumWithNullAndFallback(Parcel source, T[] enumValues, T fallback) {\n        int valueOrdinal = source.readInt();\n        if (valueOrdinal == -1) {\n            return null;\n        }\n        if (valueOrdinal >= enumValues.length) {\n            return fallback;\n        }\n        return enumValues[valueOrdinal];\n    }\n\n    private static void writeEnumWithNull(Parcel dest, Enum<?> enumValue) {\n        if (enumValue == null) {\n            dest.writeInt(-1);\n            return;\n        }\n        dest.writeInt(enumValue.ordinal());\n    }\n\n    public enum SenderStatusResult {\n        UNKNOWN, USER_ID_CONFIRMED, USER_ID_UNCONFIRMED, USER_ID_MISSING;\n        public static final SenderStatusResult[] values = values();\n    }\n\n    public enum AutocryptPeerResult {\n        OK, NEW, MISMATCH;\n        public static final AutocryptPeerResult[] values = values();\n    }\n}\n"
  },
  {
    "path": "libopenpgp/src/main/java/org/openintents/openpgp/util/OpenPgpApi.java",
    "content": "// SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-or-later\n\npackage org.openintents.openpgp.util;\n\nimport android.content.Context;\nimport android.content.Intent;\nimport android.os.Handler;\nimport android.os.Looper;\nimport android.os.ParcelFileDescriptor;\nimport android.util.Log;\n\nimport androidx.annotation.NonNull;\n\nimport org.openintents.openpgp.IOpenPgpService2;\nimport org.openintents.openpgp.OpenPgpError;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.util.concurrent.Executor;\nimport java.util.concurrent.atomic.AtomicInteger;\n\n// Copyright 2014-2015 Dominik Schürmann\n@SuppressWarnings(\"unused\")\npublic class OpenPgpApi {\n\n    public static final String TAG = \"OpenPgp API\";\n\n    public static final String SERVICE_INTENT_2 = \"org.openintents.openpgp.IOpenPgpService2\";\n\n    /**\n     * see CHANGELOG.md\n     */\n    public static final int API_VERSION = 11;\n\n    /*\n     * General extras\n     * --------------\n     *\n     * required extras:\n     * int           EXTRA_API_VERSION           (always required)\n     *\n     * returned extras:\n     * int           RESULT_CODE                 (RESULT_CODE_ERROR, RESULT_CODE_SUCCESS or RESULT_CODE_USER_INTERACTION_REQUIRED)\n     * OpenPgpError  RESULT_ERROR                (if RESULT_CODE == RESULT_CODE_ERROR)\n     * PendingIntent RESULT_INTENT               (if RESULT_CODE == RESULT_CODE_USER_INTERACTION_REQUIRED)\n     */\n\n    /**\n     * This action performs no operation, but can be used to check if the App has permission\n     * to access the API in general, returning a user interaction PendingIntent otherwise.\n     * This can be used to trigger the permission dialog explicitly.\n     * <p>\n     * This action uses no extras.\n     */\n    public static final String ACTION_CHECK_PERMISSION = \"org.openintents.openpgp.action.CHECK_PERMISSION\";\n\n    @Deprecated\n    public static final String ACTION_SIGN = \"org.openintents.openpgp.action.SIGN\";\n\n    /**\n     * Sign text resulting in a cleartext signature\n     * Some magic pre-processing of the text is done to convert it to a format usable for\n     * cleartext signatures per RFC 4880 before the text is actually signed:\n     * - end cleartext with newline\n     * - remove whitespaces on line endings\n     * <p>\n     * required extras:\n     * long          EXTRA_SIGN_KEY_ID           (key id of signing key)\n     * <p>\n     * optional extras:\n     * char[]        EXTRA_PASSPHRASE            (key passphrase)\n     */\n    public static final String ACTION_CLEARTEXT_SIGN = \"org.openintents.openpgp.action.CLEARTEXT_SIGN\";\n\n    /**\n     * Sign text or binary data resulting in a detached signature.\n     * No OutputStream necessary for ACTION_DETACHED_SIGN (No magic pre-processing like in ACTION_CLEARTEXT_SIGN)!\n     * The detached signature is returned separately in RESULT_DETACHED_SIGNATURE.\n     * <p>\n     * required extras:\n     * long          EXTRA_SIGN_KEY_ID           (key id of signing key)\n     * <p>\n     * optional extras:\n     * boolean       EXTRA_REQUEST_ASCII_ARMOR   (request ascii armor for detached signature)\n     * char[]        EXTRA_PASSPHRASE            (key passphrase)\n     * <p>\n     * returned extras:\n     * byte[]        RESULT_DETACHED_SIGNATURE\n     * String        RESULT_SIGNATURE_MICALG     (contains the name of the used signature algorithm as a string)\n     */\n    public static final String ACTION_DETACHED_SIGN = \"org.openintents.openpgp.action.DETACHED_SIGN\";\n\n    /**\n     * Encrypt\n     * <p>\n     * required extras:\n     * String[]      EXTRA_USER_IDS              (=emails of recipients, if more than one key has a user_id, a PendingIntent is returned via RESULT_INTENT)\n     * or\n     * long[]        EXTRA_KEY_IDS\n     * <p>\n     * optional extras:\n     * boolean       EXTRA_REQUEST_ASCII_ARMOR   (request ascii armor for output)\n     * char[]        EXTRA_PASSPHRASE            (key passphrase)\n     * String        EXTRA_ORIGINAL_FILENAME     (original filename to be encrypted as metadata)\n     * boolean       EXTRA_ENABLE_COMPRESSION    (enable ZLIB compression, default ist true)\n     */\n    public static final String ACTION_ENCRYPT = \"org.openintents.openpgp.action.ENCRYPT\";\n\n    /**\n     * Sign and encrypt\n     * <p>\n     * required extras:\n     * String[]      EXTRA_USER_IDS              (=emails of recipients, if more than one key has a user_id, a PendingIntent is returned via RESULT_INTENT)\n     * or\n     * long[]        EXTRA_KEY_IDS\n     * <p>\n     * optional extras:\n     * long          EXTRA_SIGN_KEY_ID           (key id of signing key)\n     * boolean       EXTRA_REQUEST_ASCII_ARMOR   (request ascii armor for output)\n     * char[]        EXTRA_PASSPHRASE            (key passphrase)\n     * String        EXTRA_ORIGINAL_FILENAME     (original filename to be encrypted as metadata)\n     * boolean       EXTRA_ENABLE_COMPRESSION    (enable ZLIB compression, default ist true)\n     */\n    public static final String ACTION_SIGN_AND_ENCRYPT = \"org.openintents.openpgp.action.SIGN_AND_ENCRYPT\";\n\n    public static final String ACTION_QUERY_AUTOCRYPT_STATUS = \"org.openintents.openpgp.action.QUERY_AUTOCRYPT_STATUS\";\n\n    /**\n     * Decrypts and verifies given input stream. This methods handles encrypted-only, signed-and-encrypted,\n     * and also signed-only input.\n     * OutputStream is optional, e.g., for verifying detached signatures!\n     * <p>\n     * If OpenPgpSignatureResult.getResult() == OpenPgpSignatureResult.RESULT_KEY_MISSING\n     * in addition a PendingIntent is returned via RESULT_INTENT to download missing keys.\n     * On all other status, in addition a PendingIntent is returned via RESULT_INTENT to open\n     * the key view in OpenKeychain.\n     * <p>\n     * optional extras:\n     * byte[]        EXTRA_DETACHED_SIGNATURE    (detached signature)\n     * <p>\n     * returned extras:\n     * OpenPgpSignatureResult   RESULT_SIGNATURE\n     * OpenPgpDecryptionResult  RESULT_DECRYPTION\n     * OpenPgpDecryptMetadata   RESULT_METADATA\n     * String                   RESULT_CHARSET   (charset which was specified in the headers of ascii armored input, if any)\n     */\n    public static final String ACTION_DECRYPT_VERIFY = \"org.openintents.openpgp.action.DECRYPT_VERIFY\";\n\n    /**\n     * Decrypts the header of an encrypted file to retrieve metadata such as original filename.\n     * <p>\n     * This does not decrypt the actual content of the file.\n     * <p>\n     * returned extras:\n     * OpenPgpDecryptMetadata   RESULT_METADATA\n     * String                   RESULT_CHARSET   (charset which was specified in the headers of ascii armored input, if any)\n     */\n    public static final String ACTION_DECRYPT_METADATA = \"org.openintents.openpgp.action.DECRYPT_METADATA\";\n\n    /**\n     * Select key id for signing\n     * <p>\n     * optional extras:\n     * String      EXTRA_USER_ID\n     * <p>\n     * returned extras:\n     * long        EXTRA_SIGN_KEY_ID\n     */\n    public static final String ACTION_GET_SIGN_KEY_ID = \"org.openintents.openpgp.action.GET_SIGN_KEY_ID\";\n    public static final String ACTION_GET_SIGN_KEY_ID_LEGACY = \"org.openintents.openpgp.action.GET_SIGN_KEY_ID_LEGACY\";\n\n    /**\n     * Get key ids based on given user ids (=emails)\n     * <p>\n     * required extras:\n     * String[]      EXTRA_USER_IDS\n     * <p>\n     * returned extras:\n     * long[]        RESULT_KEY_IDS\n     */\n    public static final String ACTION_GET_KEY_IDS = \"org.openintents.openpgp.action.GET_KEY_IDS\";\n\n    /**\n     * This action returns RESULT_CODE_SUCCESS if the OpenPGP Provider already has the key\n     * corresponding to the given key id in its database.\n     * <p>\n     * It returns RESULT_CODE_USER_INTERACTION_REQUIRED if the Provider does not have the key.\n     * The PendingIntent from RESULT_INTENT can be used to retrieve those from a keyserver.\n     * <p>\n     * If an Output stream has been defined the whole public key is returned.\n     * required extras:\n     * long        EXTRA_KEY_ID\n     * <p>\n     * optional extras:\n     * String      EXTRA_REQUEST_ASCII_ARMOR (request that the returned key is encoded in ASCII Armor)\n     */\n    public static final String ACTION_GET_KEY = \"org.openintents.openpgp.action.GET_KEY\";\n\n    /**\n     * Backup all keys given by EXTRA_KEY_IDS and if requested their secret parts.\n     * The encrypted backup will be written to the OutputStream.\n     * The client app has no access to the backup code used to encrypt the backup!\n     * This operation always requires user interaction with RESULT_CODE_USER_INTERACTION_REQUIRED!\n     * <p>\n     * required extras:\n     * long[]      EXTRA_KEY_IDS       (keys that should be included in the backup)\n     * boolean     EXTRA_BACKUP_SECRET (also backup secret keys)\n     */\n    public static final String ACTION_BACKUP = \"org.openintents.openpgp.action.BACKUP\";\n\n    public static final String ACTION_UPDATE_AUTOCRYPT_PEER = \"org.openintents.openpgp.action.UPDATE_AUTOCRYPT_PEER\";\n\n    /* Intent extras */\n    public static final String EXTRA_API_VERSION = \"api_version\";\n\n    // ACTION_DETACHED_SIGN, ENCRYPT, SIGN_AND_ENCRYPT, DECRYPT_VERIFY\n    // request ASCII Armor for output\n    // OpenPGP Radix-64, 33 percent overhead compared to binary, see http://tools.ietf.org/html/rfc4880#page-53)\n    public static final String EXTRA_REQUEST_ASCII_ARMOR = \"ascii_armor\";\n\n    // ACTION_DETACHED_SIGN\n    public static final String RESULT_DETACHED_SIGNATURE = \"detached_signature\";\n    public static final String RESULT_SIGNATURE_MICALG = \"signature_micalg\";\n\n    // ENCRYPT, SIGN_AND_ENCRYPT, QUERY_AUTOCRYPT_STATUS\n    public static final String EXTRA_USER_IDS = \"user_ids\";\n    public static final String EXTRA_KEY_IDS = \"key_ids\";\n    public static final String EXTRA_KEY_IDS_SELECTED = \"key_ids_selected\";\n    public static final String EXTRA_SIGN_KEY_ID = \"sign_key_id\";\n\n    public static final String RESULT_KEYS_CONFIRMED = \"keys_confirmed\";\n    public static final String RESULT_AUTOCRYPT_STATUS = \"autocrypt_status\";\n    public static final int AUTOCRYPT_STATUS_UNAVAILABLE = 0;\n    public static final int AUTOCRYPT_STATUS_DISCOURAGE = 1;\n    public static final int AUTOCRYPT_STATUS_AVAILABLE = 2;\n    public static final int AUTOCRYPT_STATUS_MUTUAL = 3;\n\n    // optional extras:\n    public static final String EXTRA_PASSPHRASE = \"passphrase\";\n    public static final String EXTRA_ORIGINAL_FILENAME = \"original_filename\";\n    public static final String EXTRA_ENABLE_COMPRESSION = \"enable_compression\";\n    public static final String EXTRA_OPPORTUNISTIC_ENCRYPTION = \"opportunistic\";\n    public static final String EXTRA_CUSTOM_HEADERS = \"custom_headers\";\n\n    // GET_SIGN_KEY_ID\n    public static final String EXTRA_USER_ID = \"user_id\";\n    public static final String EXTRA_PRESELECT_KEY_ID = \"preselect_key_id\";\n    public static final String EXTRA_SHOW_AUTOCRYPT_HINT = \"show_autocrypt_hint\";\n\n    public static final String RESULT_SIGN_KEY_ID = \"sign_key_id\";\n    public static final String RESULT_PRIMARY_USER_ID = \"primary_user_id\";\n    public static final String RESULT_KEY_CREATION_TIME = \"key_creation_time\";\n\n    // GET_KEY\n    public static final String EXTRA_KEY_ID = \"key_id\";\n    public static final String EXTRA_MINIMIZE = \"minimize\";\n    public static final String EXTRA_MINIMIZE_USER_ID = \"minimize_user_id\";\n    public static final String RESULT_KEY_IDS = \"key_ids\";\n\n    // BACKUP\n    public static final String EXTRA_BACKUP_SECRET = \"backup_secret\";\n\n    public static final String ACTION_AUTOCRYPT_KEY_TRANSFER = \"autocrypt_key_transfer\";\n\n    /* Service Intent returns */\n    public static final String RESULT_CODE = \"result_code\";\n\n    // get actual error object from RESULT_ERROR\n    public static final int RESULT_CODE_ERROR = 0;\n    // success!\n    public static final int RESULT_CODE_SUCCESS = 1;\n    // get PendingIntent from RESULT_INTENT, start PendingIntent with startIntentSenderForResult,\n    // and execute service method again in onActivityResult\n    public static final int RESULT_CODE_USER_INTERACTION_REQUIRED = 2;\n\n    public static final String RESULT_ERROR = \"error\";\n    public static final String RESULT_INTENT = \"intent\";\n\n    // DECRYPT_VERIFY\n    public static final String EXTRA_DETACHED_SIGNATURE = \"detached_signature\";\n    public static final String EXTRA_PROGRESS_MESSENGER = \"progress_messenger\";\n    public static final String EXTRA_DATA_LENGTH = \"data_length\";\n    public static final String EXTRA_DECRYPTION_RESULT = \"decryption_result\";\n    public static final String EXTRA_SENDER_ADDRESS = \"sender_address\";\n    public static final String EXTRA_SUPPORT_OVERRIDE_CRYPTO_WARNING = \"support_override_crpto_warning\";\n    public static final String EXTRA_AUTOCRYPT_PEER_ID = \"autocrypt_peer_id\";\n    public static final String EXTRA_AUTOCRYPT_PEER_UPDATE = \"autocrypt_peer_update\";\n    public static final String EXTRA_AUTOCRYPT_PEER_GOSSIP_UPDATES = \"autocrypt_peer_gossip_updates\";\n    public static final String RESULT_SIGNATURE = \"signature\";\n    public static final String RESULT_DECRYPTION = \"decryption\";\n    public static final String RESULT_METADATA = \"metadata\";\n    public static final String RESULT_INSECURE_DETAIL_INTENT = \"insecure_detail_intent\";\n    public static final String RESULT_OVERRIDE_CRYPTO_WARNING = \"override_crypto_warning\";\n    // This will be the charset which was specified in the headers of ascii armored input, if any\n    public static final String RESULT_CHARSET = \"charset\";\n\n    // INTERNAL, must not be used\n    public static final String EXTRA_CALL_UUID1 = \"call_uuid1\";\n    public static final String EXTRA_CALL_UUID2 = \"call_uuid2\";\n\n    IOpenPgpService2 mService;\n    Context mContext;\n    final AtomicInteger mPipeIdGen = new AtomicInteger();\n\n    public OpenPgpApi(Context context, IOpenPgpService2 service) {\n        this.mContext = context;\n        this.mService = service;\n    }\n\n    public interface IOpenPgpCallback {\n        void onReturn(final Intent result);\n    }\n\n    public void executeApiAsync(@NonNull Executor executor, Intent data, InputStream is,\n                                OutputStream os, IOpenPgpCallback callback) {\n        Handler handler = new Handler(Looper.getMainLooper());\n        executor.execute(() -> {\n            Intent result = executeApi(data, is, os);\n            handler.post(() -> callback.onReturn(result));\n        });\n    }\n\n    public Intent executeApi(Intent data, InputStream is, OutputStream os) {\n        ParcelFileDescriptor input = null;\n        try {\n            if (is != null) {\n                input = ParcelFileDescriptorUtil.pipeFrom(is);\n            }\n\n            return executeApi(data, input, os);\n        } catch (Exception e) {\n            Log.e(OpenPgpApi.TAG, \"Exception in executeApi call\", e);\n            Intent result = new Intent();\n            result.putExtra(RESULT_CODE, RESULT_CODE_ERROR);\n            result.putExtra(RESULT_ERROR, new OpenPgpError(OpenPgpError.CLIENT_SIDE_ERROR, e.getMessage()));\n            return result;\n        } finally {\n            if (input != null) {\n                try {\n                    input.close();\n                } catch (IOException e) {\n                    Log.e(OpenPgpApi.TAG, \"IOException when closing ParcelFileDescriptor!\", e);\n                }\n            }\n        }\n    }\n\n    /**\n     * InputStream and OutputStreams are always closed after operating on them!\n     */\n    @NonNull\n    private Intent executeApi(Intent data, ParcelFileDescriptor input, OutputStream os) {\n        ParcelFileDescriptor output = null;\n        try {\n            // always send version from client\n            data.putExtra(EXTRA_API_VERSION, OpenPgpApi.API_VERSION);\n\n            Intent result;\n\n            Thread pumpThread = null;\n            int outputPipeId = 0;\n\n            if (os != null) {\n                outputPipeId = mPipeIdGen.incrementAndGet();\n                output = mService.createOutputPipe(outputPipeId);\n                pumpThread = ParcelFileDescriptorUtil.pipeTo(os, output);\n            }\n\n            // blocks until result is ready\n            result = mService.execute(data, input, outputPipeId);\n\n            // set class loader to current context to allow unparcelling\n            // of OpenPgpError and OpenPgpSignatureResult\n            // http://stackoverflow.com/a/3806769\n            result.setExtrasClassLoader(mContext.getClassLoader());\n\n            //wait for ALL data being pumped from remote side\n            if (pumpThread != null) {\n                pumpThread.join();\n            }\n\n            return result;\n        } catch (Exception e) {\n            Log.e(OpenPgpApi.TAG, \"Exception in executeApi call\", e);\n            Intent result = new Intent();\n            result.putExtra(RESULT_CODE, RESULT_CODE_ERROR);\n            result.putExtra(RESULT_ERROR,\n                    new OpenPgpError(OpenPgpError.CLIENT_SIDE_ERROR, e.getMessage()));\n            return result;\n        } finally {\n            // close() is required to halt the TransferThread\n            if (output != null) {\n                try {\n                    output.close();\n                } catch (IOException e) {\n                    Log.e(OpenPgpApi.TAG, \"IOException when closing ParcelFileDescriptor!\", e);\n                }\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "libopenpgp/src/main/java/org/openintents/openpgp/util/OpenPgpServiceConnection.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage org.openintents.openpgp.util;\n\nimport android.content.ComponentName;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.ServiceConnection;\nimport android.os.IBinder;\n\nimport org.openintents.openpgp.IOpenPgpService2;\n\n// Copyright 2014-2015 Dominik Schürmann\npublic class OpenPgpServiceConnection {\n\n    // callback interface\n    public interface OnBound {\n        void onBound(IOpenPgpService2 service);\n\n        void onError(Exception e);\n    }\n\n    private Context mApplicationContext;\n\n    private IOpenPgpService2 mService;\n    private String mProviderPackageName;\n\n    private OnBound mOnBoundListener;\n\n    /**\n     * Create new connection\n     *\n     * @param context\n     * @param providerPackageName specify package name of OpenPGP provider,\n     *                            e.g., \"org.sufficientlysecure.keychain\"\n     */\n    public OpenPgpServiceConnection(Context context, String providerPackageName) {\n        this.mApplicationContext = context.getApplicationContext();\n        this.mProviderPackageName = providerPackageName;\n    }\n\n    /**\n     * Create new connection with callback\n     *\n     * @param context\n     * @param providerPackageName specify package name of OpenPGP provider,\n     *                            e.g., \"org.sufficientlysecure.keychain\"\n     * @param onBoundListener     callback, executed when connection to service has been established\n     */\n    public OpenPgpServiceConnection(Context context, String providerPackageName,\n                                    OnBound onBoundListener) {\n        this(context, providerPackageName);\n        this.mOnBoundListener = onBoundListener;\n    }\n\n    public IOpenPgpService2 getService() {\n        return mService;\n    }\n\n    public boolean isBound() {\n        return (mService != null);\n    }\n\n    private ServiceConnection mServiceConnection = new ServiceConnection() {\n        public void onServiceConnected(ComponentName name, IBinder service) {\n            mService = IOpenPgpService2.Stub.asInterface(service);\n            if (mOnBoundListener != null) {\n                mOnBoundListener.onBound(mService);\n            }\n        }\n\n        public void onServiceDisconnected(ComponentName name) {\n            mService = null;\n        }\n    };\n\n    /**\n     * If not already bound, bind to service!\n     */\n    public void bindToService() {\n        // if not already bound...\n        if (mService == null) {\n            try {\n                Intent serviceIntent = new Intent(OpenPgpApi.SERVICE_INTENT_2);\n                // NOTE: setPackage is very important to restrict the intent to this provider only!\n                serviceIntent.setPackage(mProviderPackageName);\n                boolean connect = mApplicationContext.bindService(serviceIntent, mServiceConnection,\n                        Context.BIND_AUTO_CREATE);\n                if (!connect) {\n                    throw new Exception(\"bindService() returned false!\");\n                }\n            } catch (Exception e) {\n                if (mOnBoundListener != null) {\n                    mOnBoundListener.onError(e);\n                }\n            }\n        } else {\n            // already bound, but also inform client about it with callback\n            if (mOnBoundListener != null) {\n                mOnBoundListener.onBound(mService);\n            }\n        }\n    }\n\n    public void unbindFromService() {\n        mApplicationContext.unbindService(mServiceConnection);\n    }\n\n}\n"
  },
  {
    "path": "libopenpgp/src/main/java/org/openintents/openpgp/util/OpenPgpUtils.java",
    "content": "// SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-or-later\n\npackage org.openintents.openpgp.util;\n\nimport android.annotation.SuppressLint;\nimport android.content.Context;\nimport android.content.Intent;\nimport android.content.pm.PackageManager;\nimport android.content.pm.ResolveInfo;\nimport android.content.pm.ServiceInfo;\nimport android.text.TextUtils;\n\nimport androidx.annotation.NonNull;\n\nimport java.io.Serializable;\nimport java.util.ArrayList;\nimport java.util.List;\nimport java.util.Locale;\nimport java.util.regex.Matcher;\nimport java.util.regex.Pattern;\n\n// Copyright 2014-2015 Dominik Schürmann\npublic class OpenPgpUtils {\n\n    public static final Pattern PGP_MESSAGE = Pattern.compile(\n            \".*?(-----BEGIN PGP MESSAGE-----.*?-----END PGP MESSAGE-----).*\",\n            Pattern.DOTALL);\n\n    public static final Pattern PGP_SIGNED_MESSAGE = Pattern.compile(\n            \".*?(-----BEGIN PGP SIGNED MESSAGE-----.*?-----BEGIN PGP SIGNATURE-----.*?-----END PGP SIGNATURE-----).*\",\n            Pattern.DOTALL);\n\n    public static final int PARSE_RESULT_NO_PGP = -1;\n    public static final int PARSE_RESULT_MESSAGE = 0;\n    public static final int PARSE_RESULT_SIGNED_MESSAGE = 1;\n\n    public static int parseMessage(String message) {\n        Matcher matcherSigned = PGP_SIGNED_MESSAGE.matcher(message);\n        Matcher matcherMessage = PGP_MESSAGE.matcher(message);\n\n        if (matcherMessage.matches()) {\n            return PARSE_RESULT_MESSAGE;\n        } else if (matcherSigned.matches()) {\n            return PARSE_RESULT_SIGNED_MESSAGE;\n        } else {\n            return PARSE_RESULT_NO_PGP;\n        }\n    }\n\n    @SuppressLint(\"QueryPermissionsNeeded\")\n    public static boolean isAvailable(Context context) {\n        Intent intent = new Intent(OpenPgpApi.SERVICE_INTENT_2);\n        List<ResolveInfo> resInfo = context.getPackageManager().queryIntentServices(intent, 0);\n        return !resInfo.isEmpty();\n    }\n\n    public static String convertKeyIdToHex(long keyId) {\n        return \"0x\" + convertKeyIdToHex32bit(keyId >> 32) + convertKeyIdToHex32bit(keyId);\n    }\n\n    private static String convertKeyIdToHex32bit(long keyId) {\n        StringBuilder hexString = new StringBuilder(Long.toHexString(keyId & 0xffffffffL).toLowerCase(Locale.ENGLISH));\n        while (hexString.length() < 8) {\n            hexString.insert(0, \"0\");\n        }\n        return hexString.toString();\n    }\n\n    @SuppressLint(\"QueryPermissionsNeeded\")\n    @NonNull\n    public static List<ServiceInfo> getPgpClientServices(@NonNull Context context) {\n        PackageManager pm = context.getPackageManager();\n        final List<ResolveInfo> resolveInfoList = new ArrayList<>(pm.queryIntentServices(\n                new Intent(OpenPgpApi.SERVICE_INTENT_2), 0));\n        Intent intent = new Intent(\"org.openintents.openpgp.IOpenPgpService\");\n        intent.setPackage(\"org.thialfihar.android.apg\");\n        try {\n            resolveInfoList.addAll(pm.queryIntentServices(intent, 0));\n        } catch (NullPointerException ignore) {\n        }\n        List<ServiceInfo> serviceInfoList = new ArrayList<>(resolveInfoList.size());\n        for (ResolveInfo resolveInfo : resolveInfoList) {\n            if (resolveInfo.serviceInfo == null) {\n                continue;\n            }\n            serviceInfoList.add(resolveInfo.serviceInfo);\n        }\n        return serviceInfoList;\n    }\n\n\n    private static final Pattern USER_ID_PATTERN = Pattern.compile(\"^(.*?)(?: \\\\((.*)\\\\))?(?: <(.*)>)?$\");\n\n    private static final Pattern EMAIL_PATTERN = Pattern.compile(\"^<?\\\"?([^<>\\\"]*@[^<>\\\"]*\\\\.[^<>\\\"]*)\\\"?>?$\");\n\n    /**\n     * Splits userId string into naming part, email part, and comment part.\n     * See SplitUserIdTest for examples.\n     */\n    public static UserId splitUserId(final String userId) {\n        if (!TextUtils.isEmpty(userId)) {\n            final Matcher matcher = USER_ID_PATTERN.matcher(userId);\n            if (matcher.matches()) {\n                String name = matcher.group(1).isEmpty() ? null : matcher.group(1);\n                String comment = matcher.group(2);\n                String email = matcher.group(3);\n                if (email != null && name != null) {\n                    final Matcher emailMatcher = EMAIL_PATTERN.matcher(name);\n                    if (emailMatcher.matches() && email.equals(emailMatcher.group(1))) {\n                        email = emailMatcher.group(1);\n                        name = null;\n                    }\n                }\n                if (email == null && name != null) {\n                    final Matcher emailMatcher = EMAIL_PATTERN.matcher(name);\n                    if (emailMatcher.matches()) {\n                        email = emailMatcher.group(1);\n                        name = null;\n                    }\n                }\n                return new UserId(name, email, comment);\n            }\n        }\n        return new UserId(null, null, null);\n    }\n\n    /**\n     * Returns a composed user id. Returns null if name, email and comment are empty.\n     */\n    public static String createUserId(UserId userId) {\n        StringBuilder userIdBuilder = new StringBuilder();\n        if (!TextUtils.isEmpty(userId.name)) {\n            userIdBuilder.append(userId.name);\n        }\n        if (!TextUtils.isEmpty(userId.comment)) {\n            userIdBuilder.append(\" (\");\n            userIdBuilder.append(userId.comment);\n            userIdBuilder.append(\")\");\n        }\n        if (!TextUtils.isEmpty(userId.email)) {\n            userIdBuilder.append(\" <\");\n            userIdBuilder.append(userId.email);\n            userIdBuilder.append(\">\");\n        }\n        return userIdBuilder.length() == 0 ? null : userIdBuilder.toString();\n    }\n\n    public static class UserId implements Serializable {\n        public final String name;\n        public final String email;\n        public final String comment;\n\n        public UserId(String name, String email, String comment) {\n            this.name = name;\n            this.email = email;\n            this.comment = comment;\n        }\n    }\n}\n"
  },
  {
    "path": "libopenpgp/src/main/java/org/openintents/openpgp/util/ParcelFileDescriptorUtil.java",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage org.openintents.openpgp.util;\n\nimport android.os.ParcelFileDescriptor;\nimport android.util.Log;\n\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\n\n// Copyright 2013 Florian Schmaus\npublic class ParcelFileDescriptorUtil {\n\n    public static ParcelFileDescriptor pipeFrom(InputStream inputStream)\n            throws IOException {\n        ParcelFileDescriptor[] pipe = ParcelFileDescriptor.createPipe();\n        ParcelFileDescriptor readSide = pipe[0];\n        ParcelFileDescriptor writeSide = pipe[1];\n\n        new TransferThread(inputStream, new ParcelFileDescriptor.AutoCloseOutputStream(writeSide))\n                .start();\n\n        return readSide;\n    }\n\n\n    public static TransferThread pipeTo(OutputStream outputStream, ParcelFileDescriptor output)\n            throws IOException {\n\n        TransferThread t = new TransferThread(new ParcelFileDescriptor.AutoCloseInputStream(output), outputStream);\n\n        t.start();\n        return t;\n    }\n\n\n    static class TransferThread extends Thread {\n        final InputStream mIn;\n        final OutputStream mOut;\n\n        TransferThread(InputStream in, OutputStream out) {\n            super(\"IPC Transfer Thread\");\n            mIn = in;\n            mOut = out;\n            setDaemon(true);\n        }\n\n        @Override\n        public void run() {\n            byte[] buf = new byte[4096];\n            int len;\n\n            try {\n                while ((len = mIn.read(buf)) > 0) {\n                    mOut.write(buf, 0, len);\n                }\n            } catch (IOException e) {\n                Log.e(OpenPgpApi.TAG, \"IOException when writing to out\", e);\n            } finally {\n                try {\n                    mIn.close();\n                } catch (IOException ignored) {\n                }\n                try {\n                    mOut.close();\n                } catch (IOException ignored) {\n                }\n            }\n        }\n    }\n\n}\n"
  },
  {
    "path": "libs/README.md",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later OR CC-BY-SA-4.0 -->\n# Libs\n\n- `libsmali.txt` contains additional libraries not present in the [IzzyOnDroid's repo](https://gitlab.com/IzzyOnDroid/repo/-/blob/master/libs) using the same file structure.\n- `add_lib.php` can be used to add libraries interactively to the `libsmali.txt`.\n"
  },
  {
    "path": "libs/add_lib.php",
    "content": "#!/usr/bin/env php\n<?php\n/* SPDX-License-Identifier: GPL-3.0-or-later */\n\n// Example usage: php ./libs/add_lib.php\n\n$filename = __DIR__ . '/libs/libsmali.jsonl';\n\n$library_type = [\n    \"ui\" => \"UI Component\",           // GUI support.\n    \"df\" => \"Development Framework\",  // bigger frameworks\n    \"ut\" => \"Utility\",                // other components to support a functional things like AWS support, video player.\n    \"da\" => \"Development Aid\",        // fallback for dev stuff that doesn't fit in above or is unknown where to fit\n    \"sn\" => \"Social Network\",\n    \"ad\" => \"Advertisement\",\n    \"am\" => \"App Market\",\n    \"ma\" => \"Mobile Analytics\",\n    \"pa\" => \"Payment\",\n    \"ge\" => \"Game Engine\",\n    \"mp\" => \"Map\"\n];\n\nwhile(true) {\n    $entry = array();\n    echo \"ID: \";\n    $entry[\"id\"] = format_path(trim(fgets(STDIN)));\n    echo \"Path (Enter if same as ID): \";\n    $entry[\"path\"] = format_path(trim(fgets(STDIN)));\n    if ($entry[\"path\"] == '') $entry[\"path\"] = $entry[\"id\"];\n    echo \"Name: \";\n    $entry[\"name\"] = trim(fgets(STDIN));\n    foreach($library_type as $key => $type) {\n        echo ' ' . $key. ': ' . $type.\"\\n\";\n    }\n    echo \"Type: \";\n    $entry[\"type\"] = $library_type[trim(fgets(STDIN))];\n    echo \"Permissions: \";\n    $entry[\"perms\"] = trim(fgets(STDIN));\n    echo \"URL: \";\n    $entry[\"url\"] = trim(fgets(STDIN));\n    file_put_contents($filename, json_encode($entry).\"\\n\", FILE_APPEND);\n\n    echo \"Add another? (y/n): \";\n    if (trim(fgets(STDIN)) != 'y') break;\n    echo \"\\n\";\n}\n\nfunction format_path($path) {\n    if ($path == '') return $path;\n    if ($path[0] != '/') $path = '/'.$path;\n    return str_replace('.', '/', $path);\n}\n"
  },
  {
    "path": "libs/libsmali.jsonl",
    "content": "{\"id\":\"\\/org\\/json\",\"path\":\"\\/org\\/json\",\"name\":\"JSON-java\",\"type\":\"Utility\",\"perms\":\"\",\"url\":\"https:\\/\\/www.json.org\\/json-en.html\"}\n{\"id\":\"\\/dalvik\\/system\",\"path\":\"\\/dalvik\\/system\",\"name\":\"dalvik.system\",\"type\":\"Utility\",\"perms\":\"\",\"url\":\"https:\\/\\/developer.android.com\\/reference\\/dalvik\\/system\\/package-summary\"}\n{\"id\":\"\\/im\\/dacer\\/androidcharts\",\"path\":\"\\/im\\/dacer\\/androidcharts\",\"name\":\"AndroidCharts\",\"type\":\"UI Component\",\"perms\":\"\",\"url\":\"https:\\/\\/github.com\\/HackPlan\\/AndroidCharts\"}\n{\"id\":\"\\/org\\/jetbrains\\/annotations\",\"path\":\"\\/org\\/jetbrains\\/annotations\",\"name\":\"JetBrains' java-annotations\",\"type\":\"Development Aid\",\"perms\":\"\",\"url\":\"https:\\/\\/github.com\\/JetBrains\\/java-annotations\"}\n{\"id\":\"\\/org\\/h2\\/\",\"path\":\"\\/org\\/h2\\/\",\"name\":\"H2 Database Engine\",\"type\":\"Utility\",\"perms\":\"\",\"url\":\"https:\\/\\/github.com\\/h2database\\/h2database\"}\n{\"id\":\"\\/com\\/hbb20\",\"path\":\"\\/com\\/hbb20\",\"name\":\"Country Code Picker Library\",\"type\":\"Utility\",\"perms\":\"\",\"url\":\"https:\\/\\/github.com\\/hbb20\\/CountryCodePickerProject\"}\n{\"id\":\"\\/io\\/lbry\\/lbrysdk\",\"path\":\"\\/io\\/lbry\\/lbrysdk\",\"name\":\"LBRY Android SDK\",\"type\":\"Utility\",\"perms\":\"\",\"url\":\"https:\\/\\/github.com\\/lbryio\\/lbry-android-sdk\"}\n{\"id\":\"\\/org\\/apache\\/sanselan\",\"path\":\"\\/org\\/apache\\/sanselan\",\"name\":\"Apache Sanselan\",\"type\":\"Utility\",\"perms\":\"\",\"url\":\"http:\\/\\/commons.apache.org\\/sanselan\\/\"}\n{\"id\":\"\\/com\\/pixplicity\\/htmlcompat\",\"path\":\"\\/com\\/pixplicity\\/htmlcompat\",\"name\":\"Pixplicity HtmlCompat\",\"type\":\"Development Aid\",\"perms\":\"\",\"url\":\"https:\\/\\/github.com\\/Pixplicity\\/HtmlCompat\"}\n{\"id\":\"\\/com\\/google\\/vr\\/sdk\",\"path\":\"\\/com\\/google\\/vr\\/sdk\",\"name\":\"Google VR SDK for Android\",\"type\":\"Development Framework\",\"perms\":\"\",\"url\":\"https:\\/\\/github.com\\/googlevr\\/gvr-android-sdk\"}\n{\"id\":\"\\/com\\/avito\\/android\\/krop\",\"path\":\"\\/com\\/avito\\/android\\/krop\",\"name\":\"Krop\",\"type\":\"UI Component\",\"perms\":\"\",\"url\":\"https:\\/\\/github.com\\/avito-tech\\/krop\"}\n{\"id\":\"\\/com\\/tiper\\/MaterialSpinner\",\"path\":\"\\/com\\/tiper\\/MaterialSpinner\",\"name\":\"MaterialSpinner\",\"type\":\"UI Component\",\"perms\":\"\",\"url\":\"https:\\/\\/github.com\\/tiper\\/MaterialSpinner\"}\n{\"id\":\"\\/org\\/eclipse\\/jgit\",\"path\":\"\\/org\\/eclipse\\/jgit\",\"name\":\"JGit\",\"type\":\"Development Framework\",\"perms\":\"\",\"url\":\"http:\\/\\/www.eclipse.org\\/jgit\\/\"}\n{\"id\":\"\\/de\\/cotech\\/hw\",\"path\":\"\\/de\\/cotech\\/hw\",\"name\":\"Hardware Security SDK\",\"type\":\"Development Framework\",\"perms\":\"\",\"url\":\"https:\\/\\/github.com\\/cotechde\\/hwsecurity\"}\n{\"id\":\"\\/de\\/cotech\\/sweetspot\",\"path\":\"\\/de\\/cotech\\/sweetspot\",\"name\":\"NFC Sweetspot Library\",\"type\":\"Utility\",\"perms\":\"\",\"url\":\"https:\\/\\/github.com\\/morristech\\/nfc-sweetspot\"}\n{\"id\":\"\\/org\\/apache\\/xpath\",\"path\":\"\\/org\\/apache\\/xpath\",\"name\":\"Apache XPath\",\"type\":\"Utility\",\"perms\":\"\",\"url\":\"http:\\/\\/xml.apache.org\\/xalan-j\\/apidocs\\/org\\/apache\\/xpath\\/package-summary.html#package_description\"}\n{\"id\":\"\\/com\\/github\\/oxo42\\/stateless4j\",\"path\":\"\\/com\\/github\\/oxo42\\/stateless4j\",\"name\":\"stateless4j\",\"type\":\"Development Aid\",\"perms\":\"\",\"url\":\"https:\\/\\/github.com\\/stateless4j\\/stateless4j\"}\n{\"id\":\"\\/io\\/noties\\/prism4j\",\"path\":\"\\/io\\/noties\\/prism4j\",\"name\":\"Prism4j\",\"type\":\"Utility\",\"perms\":\"\",\"url\":\"https:\\/\\/github.com\\/noties\\/Prism4j\"}\n{\"id\":\"\\/com\\/googlecode\\/javaewah\",\"path\":\"\\/com\\/googlecode\\/javaewah\",\"name\":\"JavaEWAH\",\"type\":\"Utility\",\"perms\":\"\",\"url\":\"https:\\/\\/github.com\\/lemire\\/javaewah\"}\n{\"id\":\"\\/com\\/hierynomus\\/asn1\",\"path\":\"\\/com\\/hierynomus\\/asn1\",\"name\":\"ASN.1 library for Java\",\"type\":\"Development Aid\",\"perms\":\"\",\"url\":\"https:\\/\\/github.com\\/hierynomus\\/asn-one\"}\n{\"id\":\"\\/com\\/beint\\/zangi\",\"path\":\"\\/com\\/beint\\/zangi\",\"name\":\"Zangi\",\"type\":\"App Market\",\"perms\":\"\",\"url\":\"https:\\/\\/zangi.com\\/sip-provider\"}\n{\"id\":\"\\/com\\/paypal\\/android\\/sdk\\/payments\\/\",\"path\":\"\\/com\\/paypal\\/android\\/sdk\\/payments\\/\",\"name\":\"Paypal Android SDK\",\"type\":\"Development Aid\",\"perms\":\"\",\"url\":\"https:\\/\\/github.com\\/paypal\\/PayPal-Android-SDK\"}\n{\"id\":\"\\/com\\/alipay\\/mobile\\/framework\",\"path\":\"\\/com\\/alipay\\/mobile\\/framework\",\"name\":\"Alipay\",\"type\":\"Payment\",\"perms\":\"\",\"url\":\"http:\\/\\/www.alipay.com\"}\n{\"id\":\"\\/sun\\/misc\\/Unsafe\",\"path\":\"\\/sun\\/misc\\/Unsafe\",\"name\":\"Java Unsafe\",\"type\":\"Utility\",\"perms\":\"\",\"url\":\"http:\\/\\/mishadoff.github.io\\/blog\\/java-magic-part-4-sun-dot-misc-dot-unsafe\\/\"}\n{\"id\":\"\\/io\\/vavr\\/\",\"path\":\"\\/io\\/vavr\\/\",\"name\":\"v\\u028cvr (formerly Javaslang)\",\"type\":\"Development Framework\",\"perms\":\"\",\"url\":\"https:\\/\\/github.com\\/vavr-io\\/vavr\"}\n{\"id\":\"\\/com\\/unity3d\\/player\\/\",\"path\":\"\\/com\\/unity3d\\/player\\/\",\"name\":\"Unity3D Player\",\"type\":\"Game Engine\",\"perms\":\"\",\"url\":\"https:\\/\\/docs.unity3d.com\\/Manual\\/AndroidJARPlugins.html\"}\n{\"id\":\"\\/com\\/aurora\\/gplayapi\\/\",\"path\":\"\\/com\\/aurora\\/gplayapi\\/\",\"name\":\"GPlayApi\",\"type\":\"App Market\",\"perms\":\"\",\"url\":\"https:\\/\\/gitlab.com\\/AuroraOSS\\/gplayapi\"}\n{\"id\":\"\\/com\\/connectsdk\",\"path\":\"\\/com\\/connectsdk\",\"name\":\"Connect SDK Android\",\"type\":\"Development Framework\",\"perms\":\"\",\"url\":\"https:\\/\\/github.com\\/ConnectSDK\\/Connect-SDK-Android\"}\n"
  },
  {
    "path": "libserver/.gitignore",
    "content": "/build"
  },
  {
    "path": "libserver/build.gradle",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\nplugins {\n    id('com.android.library')\n}\n\nandroid {\n    namespace 'io.github.muntashirakon.AppManager.server.common'\n    compileSdk compile_sdk\n    buildToolsVersion = build_tools\n\n    defaultConfig {\n        minSdk min_sdk\n        targetSdk target_sdk\n    }\n\n    compileOptions {\n        encoding \"UTF-8\"\n        sourceCompatibility JavaVersion.VERSION_1_8\n        targetCompatibility JavaVersion.VERSION_1_8\n    }\n    buildFeatures {\n        aidl true\n    }\n}\n\ndependencies {\n    compileOnly project(path: ':hiddenapi')\n\n    implementation \"androidx.annotation:annotation:${annotation_version}\"\n}\n"
  },
  {
    "path": "libserver/src/main/AndroidManifest.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<manifest />"
  },
  {
    "path": "libserver/src/main/aidl/io/github/muntashirakon/AppManager/server/common/IRootServiceManager.aidl",
    "content": "// SPDX-License-Identifier: Apache-2.0\n\npackage io.github.muntashirakon.AppManager.server.common;\n\n// Copyright 2020 John \"topjohnwu\" Wu\ninterface IRootServiceManager {\n    oneway void broadcast(int uid);\n    oneway void stop(in ComponentName name, int uid);\n    void connect(in IBinder binder);\n    IBinder bind(in Intent intent);\n    oneway void unbind(in ComponentName name);\n}\n"
  },
  {
    "path": "libserver/src/main/java/io/github/muntashirakon/AppManager/server/common/BaseCaller.java",
    "content": "// SPDX-License-Identifier: MIT AND GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.server.common;\n\nimport android.os.Parcel;\nimport android.os.Parcelable;\n\nimport androidx.annotation.NonNull;\n\n// Copyright 2017 Zheng Li\npublic class BaseCaller implements Parcelable {\n    public static final int TYPE_CLOSE = -10;\n    public static final int TYPE_SHELL = 5;\n\n    private final int mType;\n    private byte[] mRawBytes;\n\n    public BaseCaller(@NonNull Caller method) {\n        mType = method.getType();\n        mRawBytes = ParcelableUtil.marshall(method);\n    }\n\n    public BaseCaller(int type) {\n        this.mType = type;\n    }\n\n    public int getType() {\n        return mType;\n    }\n\n    public byte[] getRawBytes() {\n        return mRawBytes;\n    }\n\n    @Override\n    public int describeContents() {\n        return 0;\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        dest.writeInt(this.mType);\n        dest.writeByteArray(this.mRawBytes);\n    }\n\n\n    protected BaseCaller(@NonNull Parcel in) {\n        this.mType = in.readInt();\n        this.mRawBytes = in.createByteArray();\n    }\n\n    public static final Parcelable.Creator<BaseCaller> CREATOR = new Parcelable.Creator<BaseCaller>() {\n        @NonNull\n        @Override\n        public BaseCaller createFromParcel(Parcel source) {\n            return new BaseCaller(source);\n        }\n\n        @NonNull\n        @Override\n        public BaseCaller[] newArray(int size) {\n            return new BaseCaller[size];\n        }\n    };\n}\n"
  },
  {
    "path": "libserver/src/main/java/io/github/muntashirakon/AppManager/server/common/Caller.java",
    "content": "// SPDX-License-Identifier: MIT AND GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.server.common;\n\nimport android.os.Parcelable;\n\n// Copyright 2017 Zheng Li\npublic abstract class Caller implements Parcelable {\n    protected Class<?>[] mParameterTypes;\n    protected String[] mParameterTypesAsString;\n    protected Object[] mParameters;\n\n    protected void initParameters(Class<?>[] parameterTypes, Object[] parameters) {\n        setParameterTypes(parameterTypes);\n        this.mParameters = parameters;\n    }\n\n    public void setParameterTypes(Class<?>[] parameterTypes) {\n        if (parameterTypes != null) {\n            mParameterTypesAsString = new String[parameterTypes.length];\n            for (int i = 0; i < parameterTypes.length; i++) {\n                mParameterTypesAsString[i] = parameterTypes[i].getName();\n            }\n        }\n    }\n\n    public void setParameterTypes(String[] parameterTypes) {\n        this.mParameterTypesAsString = parameterTypes;\n    }\n\n    public Class<?>[] getParameterTypes() {\n        if (mParameterTypesAsString != null) {\n            if (mParameterTypes == null) {\n                mParameterTypes = ClassUtils.string2Class(mParameterTypesAsString);\n            }\n            return mParameterTypes;\n        }\n        return null;\n    }\n\n    public Object[] getParameters() {\n        return mParameters;\n    }\n\n    public Caller wrapParameters() {\n        return ParamsFixer.wrap(this);\n    }\n\n    public Caller unwrapParameters() {\n        return ParamsFixer.unwrap(this);\n    }\n\n    public abstract int getType();\n}\n"
  },
  {
    "path": "libserver/src/main/java/io/github/muntashirakon/AppManager/server/common/CallerResult.java",
    "content": "// SPDX-License-Identifier: MIT AND GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.server.common;\n\nimport android.os.Parcel;\nimport android.os.Parcelable;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\n// Copyright 2017 Zheng Li\npublic class CallerResult implements Parcelable {\n    @Nullable\n    private byte[] mReply;\n    @Nullable\n    private Throwable mThrowable;\n    @Nullable\n    private Object mReplyObj;\n\n    @Nullable\n    public byte[] getReply() {\n        return mReply;\n    }\n\n    @Nullable\n    public Throwable getThrowable() {\n        return mThrowable;\n    }\n\n    @Nullable\n    public Object getReplyObj() {\n        if (mReplyObj == null && mReply != null) {\n            mReplyObj = ParcelableUtil.readValue(mReply);\n        }\n        return mReplyObj;\n    }\n\n    public void setReply(byte[] reply) {\n        this.mReply = reply;\n    }\n\n    public void setThrowable(Throwable throwable) {\n        this.mThrowable = throwable;\n    }\n\n    @Override\n    public int describeContents() {\n        return 0;\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        dest.writeByteArray(this.mReply);\n        dest.writeSerializable(this.mThrowable);\n    }\n\n    public CallerResult() {}\n\n    protected CallerResult(@NonNull Parcel in) {\n        this.mReply = in.createByteArray();\n        this.mThrowable = (Throwable) in.readSerializable();\n    }\n\n    public static final Creator<CallerResult> CREATOR = new Creator<CallerResult>() {\n        @NonNull\n        @Override\n        public CallerResult createFromParcel(Parcel source) {\n            return new CallerResult(source);\n        }\n\n        @NonNull\n        @Override\n        public CallerResult[] newArray(int size) {\n            return new CallerResult[size];\n        }\n    };\n\n    @NonNull\n    @Override\n    public String toString() {\n        return \"CallerResult{\" +\n                \"reply=\" + getReplyObj() +\n                \", throwable=\" + mThrowable +\n                '}';\n    }\n}\n"
  },
  {
    "path": "libserver/src/main/java/io/github/muntashirakon/AppManager/server/common/ClassUtils.java",
    "content": "// SPDX-License-Identifier: MIT AND GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.server.common;\n\nimport android.content.ComponentName;\nimport android.content.Intent;\nimport android.content.IntentFilter;\nimport android.os.Bundle;\nimport android.os.Message;\nimport android.os.ParcelFileDescriptor;\nimport android.os.ResultReceiver;\nimport android.os.UserHandle;\nimport android.os.WorkSource;\nimport android.util.LruCache;\n\nimport androidx.annotation.Nullable;\n\nimport java.util.HashMap;\nimport java.util.Map;\n\n// Copyright 2017 Zheng Li\npublic class ClassUtils {\n    private static final Map<String, Class<?>> sDefaultClassMap = new HashMap<>();\n    private static final LruCache<String, Class<?>> sClassCache = new LruCache<>(128);\n\n    static {\n        // Primitive types\n        defCacheClass(byte.class);\n        defCacheClass(boolean.class);\n        defCacheClass(short.class);\n        defCacheClass(char.class);\n        defCacheClass(int.class);\n        defCacheClass(float.class);\n        defCacheClass(long.class);\n        defCacheClass(double.class);\n        // Non-primitive types\n        defCacheClass(String.class);\n        defCacheClass(Bundle.class);\n        defCacheClass(ComponentName.class);\n        defCacheClass(Message.class);\n        defCacheClass(ParcelFileDescriptor.class);\n        defCacheClass(ResultReceiver.class);\n        defCacheClass(WorkSource.class);\n        defCacheClass(Intent.class);\n        defCacheClass(IntentFilter.class);\n        defCacheClass(UserHandle.class);\n        // Arrays\n        defCacheClass(byte[].class);\n        defCacheClass(int[].class);\n        defCacheClass(String[].class);\n        defCacheClass(Intent[].class);\n    }\n\n    private static void defCacheClass(Class<?> clazz) {\n        sDefaultClassMap.put(clazz.getName(), clazz);\n    }\n\n    @Nullable\n    public static Class<?>[] string2Class(String... names) {\n        if (names != null) {\n            Class<?>[] ret = new Class[names.length];\n            for (int i = 0; i < names.length; i++) {\n                ret[i] = string2Class(names[i]);\n            }\n            return ret;\n        }\n        return null;\n    }\n\n    @Nullable\n    public static Class<?> string2Class(String name) {\n        try {\n            Class<?> clazz = sDefaultClassMap.get(name);\n            if (clazz == null) {\n                clazz = sClassCache.get(name);\n            }\n            if (clazz == null) {\n                clazz = Class.forName(name, false, null);\n                sClassCache.put(name, clazz);\n            }\n            return clazz;\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n        return null;\n    }\n\n}\n"
  },
  {
    "path": "libserver/src/main/java/io/github/muntashirakon/AppManager/server/common/ConfigParams.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.server.common;\n\nimport androidx.annotation.NonNull;\n\npublic final class ConfigParams {\n    public static final String PARAM_DEBUG = \"debug\";\n    public static final String PARAM_APP = \"app\";\n    public static final String PARAM_PATH = \"path\";\n    public static final String PARAM_RUN_IN_BACKGROUND = \"bgrun\";\n    public static final String PARAM_TOKEN = \"token\";\n    public static final String PARAM_UID = \"uid\";\n\n    private boolean mIsDebug;\n    private String mAppName;\n    private String mPath;\n    private boolean mRunInBackground;\n    private String mToken;\n    private String mUid;\n\n    public ConfigParams() {\n    }\n\n    public void put(@NonNull String key, @NonNull String value) {\n        switch (key) {\n            case PARAM_DEBUG:\n                mIsDebug = \"1\".equals(value);\n                break;\n            case PARAM_APP:\n                mAppName = value;\n                break;\n            case PARAM_PATH:\n                mPath = value;\n                break;\n            case PARAM_RUN_IN_BACKGROUND:\n                mRunInBackground = \"1\".equals(value);\n                break;\n            case PARAM_TOKEN:\n                mToken = value;\n                break;\n            case PARAM_UID:\n                mUid = value;\n        }\n    }\n\n    public boolean isIsDebug() {\n        return mIsDebug;\n    }\n\n    public String getAppName() {\n        return mAppName;\n    }\n\n    public String getPath() {\n        return mPath;\n    }\n\n    public boolean isRunInBackground() {\n        return mRunInBackground;\n    }\n\n    public String getToken() {\n        return mToken;\n    }\n\n    public String getUid() {\n        return mUid;\n    }\n\n    @NonNull\n    @Override\n    public String toString() {\n        return \"ConfigParam{\" +\n                \"mIsDebug=\" + mIsDebug +\n                \", mPath='\" + mPath + '\\'' +\n                \", mRunInBackground=\" + mRunInBackground +\n                \", mToken='\" + mToken + '\\'' +\n                \", mUid='\" + mUid + '\\'' +\n                '}';\n    }\n}\n"
  },
  {
    "path": "libserver/src/main/java/io/github/muntashirakon/AppManager/server/common/Constants.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.server.common;\n\npublic class Constants {\n    public static final String SERVER_NAME = \"am_local_server\";\n    public static final String JAR_NAME = \"am.jar\";\n}\n"
  },
  {
    "path": "libserver/src/main/java/io/github/muntashirakon/AppManager/server/common/DataTransmission.java",
    "content": "// SPDX-License-Identifier: MIT AND GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.server.common;\n\nimport android.util.Log;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport java.io.Closeable;\nimport java.io.DataInputStream;\nimport java.io.DataOutputStream;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.util.Objects;\n\n/**\n * <code>DataTransmission</code> class handles the data sent and received by server or client.\n */\n// Copyright 2017 Zheng Li\npublic final class DataTransmission implements Closeable {\n    /**\n     * Protocol version. Specification: <code>protocol-version,token</code>\n     */\n    public static final String PROTOCOL_VERSION = \"1.2.4\";\n\n    public enum Role {\n        Server,\n        Client\n    }\n\n    @NonNull\n    private final DataOutputStream mOutputStream;\n    @NonNull\n    private final DataInputStream mInputStream;\n    private final boolean mAsync;\n\n    @Nullable\n    private OnReceiveCallback mOnReceiveCallback;\n    private boolean mRunning = true;\n\n    public DataTransmission(@NonNull OutputStream outputStream, @NonNull InputStream inputStream,\n                            @Nullable OnReceiveCallback onReceiveCallback, boolean async) {\n        mOutputStream = new DataOutputStream(outputStream);\n        mInputStream = new DataInputStream(inputStream);\n        mOnReceiveCallback = onReceiveCallback;\n        mAsync = async;\n    }\n\n    /**\n     * Create a new asynchronous data transfer object with receiver callback\n     *\n     * @param outputStream      Stream where new messages will be written\n     * @param inputStream       Stream where new messages will be read from\n     * @param onReceiveCallback The callback object whose method is called after receiving new messages\n     */\n    public DataTransmission(@NonNull OutputStream outputStream, @NonNull InputStream inputStream,\n                            @Nullable OnReceiveCallback onReceiveCallback) {\n        this(outputStream, inputStream, onReceiveCallback, true);\n    }\n\n    /**\n     * Create a new asynchronous data transfer object\n     *\n     * @param outputStream Stream where new messages will be written\n     * @param inputStream  Stream where new messages will be read from\n     */\n    public DataTransmission(@NonNull OutputStream outputStream, @NonNull InputStream inputStream) {\n        this(outputStream, inputStream, true);\n    }\n\n    /**\n     * Create a new data transfer object\n     *\n     * @param outputStream Stream where new messages will be written\n     * @param inputStream  Stream where new messages will be read from\n     * @param async        Whether the transfer should be asynchronous or synchronous\n     */\n    public DataTransmission(@NonNull OutputStream outputStream, @NonNull InputStream inputStream, boolean async) {\n        this(outputStream, inputStream, null, async);\n    }\n\n    /**\n     * Set custom callback for receiving message.\n     *\n     * @param onReceiveCallback Callback that wants to receive message.\n     */\n    public void setOnReceiveCallback(@Nullable OnReceiveCallback onReceiveCallback) {\n        mOnReceiveCallback = onReceiveCallback;\n    }\n\n    /**\n     * Send text message\n     *\n     * @param text Text to be sent\n     * @throws IOException When it fails to send the message\n     * @see #sendMessage(byte[])\n     * @see #sendAndReceiveMessage(byte[])\n     */\n    public void sendMessage(@Nullable String text) throws IOException {\n        if (text != null) {\n            sendMessage(text.getBytes());\n        }\n    }\n\n    /**\n     * Send message as bytes\n     *\n     * @param messageBytes Bytes to be sent\n     * @throws IOException When it fails to send the message\n     * @see #sendMessage(String)\n     * @see #sendAndReceiveMessage(byte[])\n     */\n    public void sendMessage(@Nullable byte[] messageBytes) throws IOException {\n        if (messageBytes != null) {\n            mOutputStream.writeInt(messageBytes.length);\n            mOutputStream.write(messageBytes);\n            mOutputStream.flush();\n        }\n    }\n\n    /**\n     * Read response as bytes after sending a message\n     *\n     * @return The bytes to be read\n     * @throws IOException When it fails to read the message\n     */\n    @NonNull\n    private byte[] readMessage() throws IOException {\n        int len = mInputStream.readInt();\n        byte[] bytes = new byte[len];\n        mInputStream.readFully(bytes, 0, len);\n        return bytes;\n    }\n\n    /**\n     * Send and receive messages at the same time (half-duplex)\n     *\n     * @param messageBytes Bytes to be sent\n     * @return Bytes to be read\n     * @throws IOException When it fails to send or read the message\n     * @see #sendMessage(String)\n     * @see #sendMessage(byte[])\n     */\n    @NonNull\n    public synchronized byte[] sendAndReceiveMessage(@NonNull byte[] messageBytes) throws IOException {\n        sendMessage(messageBytes);\n        return readMessage();\n    }\n\n    /**\n     * Handshake: verify tokens\n     *\n     * @param token Token supplied by server or client based\n     * @param role  Whether the supplied token is from server or client\n     * @throws IOException              When it fails to verify the token\n     * @throws ProtocolVersionException When the {@link #PROTOCOL_VERSION} mismatch occurs\n     */\n    public void shakeHands(@NonNull String token, Role role) throws IOException {\n        Objects.requireNonNull(token);\n        if (role == Role.Server) {\n            FLog.log(\"DataTransmission#shakeHands: Server protocol: \" + PROTOCOL_VERSION);\n            String auth = new String(readMessage());  // <protocol-version>,<token>\n            FLog.log(\"Received authentication: \" + auth);\n            String[] split = auth.split(\",\");\n            String clientToken = split[1];\n            // Match tokens\n            if (token.equals(clientToken)) {\n                // Connection is authorised\n                FLog.log(\"DataTransmission#shakeHands: Authentication successful.\");\n            } else {\n                FLog.log(\"DataTransmission#shakeHands: Authentication failed.\");\n                throw new IOException(\"Unauthorized client, token: \" + token);\n            }\n            // Check protocol version\n            String protocolVersion = split[0];\n            if (!PROTOCOL_VERSION.equals(protocolVersion)) {\n                throw new ProtocolVersionException(\"Client protocol version: \" + protocolVersion + \", \" +\n                        \"Server protocol version: \" + PROTOCOL_VERSION);\n            }\n        } else if (role == Role.Client) {\n            Log.e(\"DataTransmission\", \"shakeHands: Client protocol: \" + PROTOCOL_VERSION);\n            sendMessage(PROTOCOL_VERSION + \",\" + token);\n        }\n    }\n\n    /**\n     * Handle for messages received. For asynchronous operations or when the socket is not active,\n     * nothing is done. But when server is running {@link #onReceiveMessage(byte[])} is called.\n     *\n     * @throws IOException When it fails to read the message received\n     */\n    public void handleReceive() throws IOException {\n        if (!mAsync) return;\n        while (mRunning) {\n            onReceiveMessage(readMessage());\n        }\n    }\n\n    /**\n     * Calls the callback function {@link OnReceiveCallback#onMessage(byte[])}.\n     *\n     * @param bytes Bytes that was received earlier\n     */\n    private void onReceiveMessage(@NonNull byte[] bytes) {\n        if (mOnReceiveCallback != null) {\n            mOnReceiveCallback.onMessage(bytes);\n        }\n    }\n\n    /**\n     * Stop data transmission, called when socket connection is being closed\n     */\n    @Override\n    public void close() {\n        mRunning = false;\n        try {\n            mOutputStream.close();\n        } catch (IOException e) {\n            e.printStackTrace();\n        }\n        try {\n            mInputStream.close();\n        } catch (IOException e) {\n            e.printStackTrace();\n        }\n    }\n\n    /**\n     * The callback that executes when a new message is received\n     */\n    public interface OnReceiveCallback {\n        /**\n         * Implement this method to handle the received message\n         *\n         * @param bytes The message that was received\n         */\n        void onMessage(@NonNull byte[] bytes);\n    }\n\n    /**\n     * Indicates that a protocol version mismatch has been occurred\n     */\n    public static class ProtocolVersionException extends IOException {\n        public ProtocolVersionException(String message) {\n            super(message);\n        }\n    }\n}\n"
  },
  {
    "path": "libserver/src/main/java/io/github/muntashirakon/AppManager/server/common/FLog.java",
    "content": "// SPDX-License-Identifier: MIT AND GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.server.common;\n\nimport android.system.ErrnoException;\nimport android.system.Os;\nimport android.util.Log;\n\nimport java.io.File;\nimport java.io.FileOutputStream;\nimport java.util.Date;\nimport java.util.concurrent.atomic.AtomicInteger;\n\n// Copyright 2017 Zheng Li\npublic class FLog {\n\n    public static boolean writeLog = false;\n    private static FileOutputStream fos;\n    private static final AtomicInteger sBufferSize = new AtomicInteger();\n    private static final AtomicInteger sErrorCount = new AtomicInteger();\n\n    private static void openFile() {\n        try {\n            if (writeLog && fos == null && sErrorCount.get() < 5) {\n                File file = new File(\"/data/local/tmp/am.txt\");\n                fos = new FileOutputStream(file);\n\n                fos.write(\"\\n\\n\\n--------------------\".getBytes());\n                fos.write(new Date().toString().getBytes());\n                fos.write(\"\\n\\n\".getBytes());\n                chown(file.getAbsolutePath(), 2000, 2000);\n                chmod(file.getAbsolutePath(), 0755);\n            }\n        } catch (Exception e) {\n            e.printStackTrace();\n            sErrorCount.incrementAndGet();\n            fos = null;\n        }\n    }\n\n    private static void chown(String path, int uid, int gid) {\n        try {\n            Os.chown(path, uid, gid);\n        } catch (ErrnoException e) {\n            e.printStackTrace();\n        }\n    }\n\n    private static void chmod(String path, int mode) {\n        try {\n            Os.chmod(path, mode);\n        } catch (ErrnoException e) {\n            e.printStackTrace();\n        }\n    }\n\n    public static void log(String log) {\n        if (writeLog) {\n            System.out.println(log);\n        } else {\n            Log.e(\"am\", \"Flog --> \" + log);\n        }\n\n        try {\n            if (writeLog) {\n                openFile();\n                if (fos != null) {\n                    fos.write(log.getBytes());\n                    fos.write(\"\\n\".getBytes());\n\n                    if (sBufferSize.incrementAndGet() > 10) {\n                        fos.getFD().sync();\n                        fos.flush();\n                        sBufferSize.set(0);\n                    }\n                }\n            }\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n    }\n\n    public static void log(Throwable e) {\n        log(Log.getStackTraceString(e));\n    }\n\n    public static void close() {\n        try {\n            if (writeLog && fos != null) {\n                fos.getFD().sync();\n                fos.close();\n            }\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n    }\n\n}\n\n"
  },
  {
    "path": "libserver/src/main/java/io/github/muntashirakon/AppManager/server/common/ParamsFixer.java",
    "content": "// SPDX-License-Identifier: MIT AND GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.server.common;\n\nimport android.os.ParcelFileDescriptor;\n\nimport androidx.annotation.NonNull;\n\nimport java.io.FileDescriptor;\nimport java.io.IOException;\n\n// Copyright 2017 Zheng Li\n@SuppressWarnings(\"rawtypes\")\npublic class ParamsFixer {\n    @NonNull\n    public static Caller wrap(@NonNull Caller caller) {\n        Object[] params = caller.getParameters();\n        if (caller.getParameterTypes() != null && params != null) {\n            Class[] paramsType = caller.getParameterTypes();\n            for (int i = 0; i < params.length; i++) {\n                params[i] = marshall(paramsType[i], params[i]);\n            }\n        }\n        return caller;\n    }\n\n    @NonNull\n    public static Caller unwrap(@NonNull Caller caller) {\n        Object[] params = caller.getParameters();\n        if (caller.getParameterTypes() != null && params != null) {\n            Class[] paramsType = caller.getParameterTypes();\n            for (int i = 0; i < params.length; i++) {\n                params[i] = unmarshall(paramsType[i], params[i]);\n            }\n        }\n        return caller;\n    }\n\n    private static Object marshall(Class type, Object obj) {\n        if (FileDescriptor.class.equals(type) && obj instanceof FileDescriptor) {\n            try {\n                return ParcelFileDescriptor.dup(((FileDescriptor) obj));\n            } catch (IOException e) {\n                e.printStackTrace();\n            }\n        }\n        return obj;\n    }\n\n    private static Object unmarshall(Class type, Object obj) {\n        if (FileDescriptor.class.equals(type) && obj instanceof ParcelFileDescriptor) {\n            return ((ParcelFileDescriptor) obj).getFileDescriptor();\n        }\n        return obj;\n    }\n}\n"
  },
  {
    "path": "libserver/src/main/java/io/github/muntashirakon/AppManager/server/common/ParcelableUtil.java",
    "content": "// SPDX-License-Identifier: MIT AND GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.server.common;\n\nimport android.os.Parcel;\nimport android.os.Parcelable;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport org.jetbrains.annotations.Contract;\n\n// Copyright 2017 Zheng Li\npublic class ParcelableUtil {\n    @NonNull\n    public static byte[] marshall(@NonNull Parcelable parcelable) {\n        Parcel parcel = Parcel.obtain();\n        try {\n            parcelable.writeToParcel(parcel, 0);\n            return parcel.marshall();\n        } finally {\n            parcel.recycle();\n        }\n    }\n\n    @Contract(\"!null,_ -> !null\")\n    @Nullable\n    public static <T extends Parcelable> T unmarshall(@Nullable byte[] bytes, @NonNull Parcelable.Creator<T> creator) {\n        if (bytes == null) {\n            return null;\n        }\n        Parcel parcel = unmarshall(bytes);\n        return creator.createFromParcel(parcel);\n    }\n\n    @Contract(\"!null -> !null\")\n    @Nullable\n    public static Parcel unmarshall(@Nullable byte[] bytes) {\n        if (bytes == null) {\n            return null;\n        }\n        Parcel parcel = Parcel.obtain();\n        parcel.unmarshall(bytes, 0, bytes.length);\n        parcel.setDataPosition(0);\n        return parcel;\n    }\n\n    @Nullable\n    public static Object readValue(byte[] bytes) {\n        if (bytes == null) {\n            return null;\n        }\n        Parcel unmarshall = unmarshall(bytes);\n        try {\n            return unmarshall.readValue(ParcelableUtil.class.getClassLoader());\n        } finally {\n            unmarshall.recycle();\n        }\n    }\n}"
  },
  {
    "path": "libserver/src/main/java/io/github/muntashirakon/AppManager/server/common/ServerActions.java",
    "content": "// SPDX-License-Identifier: MIT AND GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.server.common;\n\n// Copyright 2017 Zheng Li\npublic final class ServerActions {\n    // This hard coded value won't cause any issue because it's only used internally.\n    public static final String PACKAGE_NAME = \"io.github.muntashirakon.AppManager\";\n\n    public static final String ACTION_SERVER_STARTED = PACKAGE_NAME + \".action.SERVER_STARTED\";\n    public static final String ACTION_SERVER_CONNECTED = PACKAGE_NAME + \".action.SERVER_CONNECTED\";\n    public static final String ACTION_SERVER_DISCONNECTED = PACKAGE_NAME + \".action.SERVER_DISCONNECTED\";\n    public static final String ACTION_SERVER_STOPPED = PACKAGE_NAME + \".action.SERVER_STOPED\";\n}\n"
  },
  {
    "path": "libserver/src/main/java/io/github/muntashirakon/AppManager/server/common/ServerInfo.java",
    "content": "// SPDX-License-Identifier: MIT AND GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.server.common;\n\nimport android.os.Parcel;\nimport android.os.Parcelable;\n\nimport androidx.annotation.NonNull;\n\n// Copyright 2017 Zheng Li\npublic class ServerInfo implements Parcelable {\n    public String protocolVersion = DataTransmission.PROTOCOL_VERSION;\n\n    public String startArgs;\n    public long startTime;\n    public long startRealTime;\n    public long rxBytes;  // Received\n    public long txBytes;  // Sent\n    public long successCount;\n    public long errorCount;\n\n\n    @Override\n    public int describeContents() {\n        return 0;\n    }\n\n    @Override\n    public void writeToParcel(@NonNull Parcel dest, int flags) {\n        dest.writeString(this.protocolVersion);\n        dest.writeString(this.startArgs);\n        dest.writeLong(this.startTime);\n        dest.writeLong(this.startRealTime);\n        dest.writeLong(this.rxBytes);\n        dest.writeLong(this.txBytes);\n        dest.writeLong(this.successCount);\n        dest.writeLong(this.errorCount);\n    }\n\n    public ServerInfo() {\n    }\n\n    protected ServerInfo(@NonNull Parcel in) {\n        this.protocolVersion = in.readString();\n        this.startArgs = in.readString();\n        this.startTime = in.readLong();\n        this.startRealTime = in.readLong();\n        this.rxBytes = in.readLong();\n        this.txBytes = in.readLong();\n        this.successCount = in.readLong();\n        this.errorCount = in.readLong();\n    }\n\n    public static final Creator<ServerInfo> CREATOR = new Creator<ServerInfo>() {\n        @NonNull\n        @Override\n        public ServerInfo createFromParcel(Parcel source) {\n            return new ServerInfo(source);\n        }\n\n        @NonNull\n        @Override\n        public ServerInfo[] newArray(int size) {\n            return new ServerInfo[size];\n        }\n    };\n\n    @NonNull\n    @Override\n    public String toString() {\n        return \"ServerInfo{\" +\n                \"protocolVersion='\" + protocolVersion + '\\'' +\n                \", startArgs='\" + startArgs + '\\'' +\n                \", startTime=\" + startTime +\n                \", startRealTime=\" + startRealTime +\n                \", rxBytes=\" + rxBytes +\n                \", txBytes=\" + txBytes +\n                \", successCount=\" + successCount +\n                \", errorCount=\" + errorCount +\n                '}';\n    }\n}\n"
  },
  {
    "path": "libserver/src/main/java/io/github/muntashirakon/AppManager/server/common/ServerUtils.java",
    "content": "// SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-or-later\npackage io.github.muntashirakon.AppManager.server.common;\n\nimport android.content.Context;\nimport android.os.Looper;\n\nimport java.lang.reflect.Method;\n\n// Copyright 2020 John \"topjohnwu\" Wu\n// Must be accessed via reflection\npublic final class ServerUtils {\n    public static final String CMDLINE_START_SERVICE = \"start\";\n    public static final String CMDLINE_START_DAEMON = \"daemon\";\n    public static final String CMDLINE_STOP_SERVICE = \"stop\";\n\n    public static final String CMDLINE_STOP_SERVER = \"stopServer\";\n\n    public static Context getSystemContext() {\n        try {\n            synchronized (Looper.class) {\n                if (Looper.getMainLooper() == null)\n                    Looper.prepareMainLooper();\n            }\n\n            Class<?> atClazz = Class.forName(\"android.app.ActivityThread\");\n            Method systemMain = atClazz.getMethod(\"systemMain\");\n            Object activityThread = systemMain.invoke(null);\n            Method getSystemContext = atClazz.getMethod(\"getSystemContext\");\n            return (Context) getSystemContext.invoke(activityThread);\n        } catch (Exception e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    // Put \"app-manager-\" in front of the service name to prevent possible conflicts\n    public static String getServiceName(String pkg) {\n        return \"app-manager-\" + pkg;\n    }\n}\n"
  },
  {
    "path": "libserver/src/main/java/io/github/muntashirakon/AppManager/server/common/Shell.java",
    "content": "// SPDX-License-Identifier: MIT AND GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.server.common;\n\nimport android.os.Parcel;\nimport android.os.Parcelable;\n\nimport androidx.annotation.NonNull;\n\nimport java.io.BufferedReader;\nimport java.io.IOException;\nimport java.io.InputStreamReader;\nimport java.io.OutputStream;\nimport java.util.UUID;\nimport java.util.concurrent.LinkedBlockingQueue;\nimport java.util.concurrent.atomic.AtomicInteger;\n\n// Copyright 2017 Zheng Li\npublic final class Shell {\n    private static final String TOKEN = UUID.randomUUID().toString();\n\n    private static Shell sShell;\n\n    @NonNull\n    public static Shell getShell(String path) throws IOException {\n        if (sShell == null) {\n            synchronized (Shell.class) {\n                if (sShell == null) {\n                    sShell = new Shell(\"sh\");\n                    sShell.exec(\"export PATH=\" + path + \":$PATH\");\n                }\n            }\n        }\n        return sShell;\n    }\n\n    private final Process mProcess;\n    private final BufferedReader mIn;\n    private final OutputStream mOut;\n    private final LinkedBlockingQueue<Command> mCommandQueue = new LinkedBlockingQueue<>();\n    private final AtomicInteger mNextCmdID = new AtomicInteger(0);\n\n    private volatile boolean mClosed = false;\n\n    private Shell(String cmd) throws IOException {\n        mProcess = new ProcessBuilder(cmd).redirectErrorStream(true).start();\n        mIn = new BufferedReader(new InputStreamReader(mProcess.getInputStream()));\n        mOut = mProcess.getOutputStream();\n\n        Runnable shellRunnable = () -> {\n            while (!mClosed) {\n                try {\n                    Command command = mCommandQueue.take();\n                    if (command != null && !mClosed) {\n                        Shell.this.writeCommand(command);\n                        Shell.this.readCommand(command);\n                    }\n                } catch (Exception e) {\n                    e.printStackTrace();\n                }\n            }\n            if (mClosed) {\n                Shell.this.destroyShell();\n            }\n        };\n\n        new Thread(shellRunnable, \"shell\").start();\n    }\n\n    private void writeCommand(@NonNull Command command) throws IOException {\n        OutputStream out = this.mOut;\n        command.writeCommand(out);\n        String line = \"\\necho \" + TOKEN + \" \" + command.getID() + \" $?\\n\";\n        out.write(line.getBytes());\n        out.flush();\n    }\n\n    private void readCommand(Command command) throws IOException {\n        if (command != null) {\n            while (!mClosed) {\n                String line = mIn.readLine();\n                if (line == null || mClosed) {\n                    break;\n                }\n                int pos = line.indexOf(TOKEN);\n                if (pos > 0) {\n                    command.onUpdate(command.getID(), line.substring(0, pos));\n                }\n                if (pos >= 0) {\n                    line = line.substring(pos);\n                    String[] fields = line.split(\" \");\n                    if (fields.length >= 2 && fields[1] != null) {\n                        int id = 0;\n                        try {\n                            id = Integer.parseInt(fields[1]);\n                        } catch (NumberFormatException ignored) {\n                        }\n                        int exitCode = -1;\n                        try {\n                            exitCode = Integer.parseInt(fields[2]);\n                        } catch (NumberFormatException ignored) {\n                        }\n                        if (id == command.getID()) {\n                            command.setExitCode(exitCode);\n                            break;\n                        }\n                    }\n                }\n                command.onUpdate(command.getID(), line);\n            }\n        }\n    }\n\n    public void destroyShell() {\n        //proc.waitFor();\n        try {\n            writeCommand(new Command(\"exit 33\\n\") {\n                @Override\n                public void onUpdate(int id, String message) {\n\n                }\n\n                @Override\n                public void onFinished(int id) {\n\n                }\n            });\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n        try {\n            if (mIn != null) {\n                mIn.close();\n            }\n        } catch (IOException e) {\n            e.printStackTrace();\n        }\n\n        try {\n            if (mOut != null) {\n                mOut.close();\n            }\n        } catch (IOException e) {\n            e.printStackTrace();\n        }\n\n        if (!mCommandQueue.isEmpty()) {\n            Command command;\n            while ((command = mCommandQueue.poll()) != null) {\n                command.terminate(\"Unexpected Termination.\");\n                command = null;\n            }\n        }\n\n        mProcess.destroy();\n    }\n\n    public boolean isClosed() {\n        return mClosed;\n    }\n\n    public void close() {\n        this.mClosed = true;\n    }\n\n    /**\n     * Whether all commands are executed (ie. queue is cleared)\n     */\n    public boolean allCommandsOver() {\n        return mCommandQueue.isEmpty();\n    }\n\n\n    private int generateCommandID() {\n        int id = mNextCmdID.getAndIncrement();\n        if (id > 0x00FFFFFF) {\n            mNextCmdID.set(1);\n            id = generateCommandID();\n        }\n        return id;\n    }\n\n    @NonNull\n    private Command add(Command command) {\n        if (mClosed) {\n            throw new IllegalStateException(\"Unable to add commands to a closed shell.\");\n        }\n        command.setId(generateCommandID());\n        mCommandQueue.offer(command);\n        return command;\n    }\n\n    @NonNull\n    public Result exec(String cmd) {\n        Result result = new Result();\n        FLog.log(\"Command:  \" + cmd);\n        final StringBuilder outLine = new StringBuilder();\n        try {\n            result.mStatusCode = add(new Command(cmd) {\n                @Override\n                public void onUpdate(int id, String message) {\n                    outLine.append(message).append('\\n');\n                }\n\n                @Override\n                public void onFinished(int id) {\n                }\n            }).waitForFinish();\n        } catch (InterruptedException e) {\n            e.printStackTrace();\n        }\n        if (result.mStatusCode == -1) {\n            try {\n                outLine.setLength(0);\n                result.mStatusCode = add(new Command(cmd) {\n                    @Override\n                    public void onUpdate(int id, String message) {\n                        outLine.append(message).append('\\n');\n                    }\n\n                    @Override\n                    public void onFinished(int id) {\n                    }\n                }).waitForFinish();\n            } catch (InterruptedException e) {\n                e.printStackTrace();\n            }\n        }\n        result.mMessage = outLine.toString();\n        return result;\n    }\n\n    public int countCommands() {\n        return mCommandQueue.size();\n    }\n\n\n    abstract class Command {\n        private final String[] mCommands;\n        private final long mTimeout;\n\n        private boolean mIsFinished;\n        private int mExitCode;\n        private int mId;\n\n        public abstract void onUpdate(int id, String message);\n\n        public abstract void onFinished(int id);\n\n        public Command(String... commands) {\n            this(1000 * 30, commands);\n        }\n\n        public Command(int timeout, String... commands) {\n            mTimeout = timeout;\n            mCommands = commands;\n        }\n\n        void setId(int id) {\n            mId = id;\n        }\n\n        public int getID() {\n            return mId;\n        }\n\n        public void setExitCode(int code) {\n            synchronized (this) {\n                mExitCode = code;\n                mIsFinished = true;\n                onFinished(mId);\n                this.notifyAll();\n            }\n        }\n\n        public boolean isFinished() {\n            synchronized (this) {\n                return mIsFinished;\n            }\n        }\n\n        public void terminate(String reason) {\n            close();\n            setExitCode(-1);\n        }\n\n        public int waitForFinish(long timeout) throws InterruptedException {\n            synchronized (this) {\n                while (!mIsFinished) {\n                    this.wait(timeout);\n                    if (!mIsFinished) {\n                        mIsFinished = true;\n                        terminate(\"Timeout Exception\");\n                    }\n                }\n            }\n            return mExitCode;\n        }\n\n        public int waitForFinish() throws InterruptedException {\n            synchronized (this) {\n                waitForFinish(mTimeout);\n            }\n            return mExitCode;\n        }\n\n        public String getCommand() {\n            if (mCommands == null || mCommands.length == 0) {\n                return \"\";\n            }\n\n            StringBuilder sb = new StringBuilder();\n            for (String s : mCommands) {\n                sb.append(s);\n                sb.append('\\n');\n            }\n            return sb.toString();\n        }\n\n        public void writeCommand(@NonNull OutputStream out) throws IOException {\n            out.write(getCommand().getBytes());\n            out.flush();\n        }\n\n    }\n\n    public static class Result implements Parcelable {\n        private String mMessage;\n        private int mStatusCode = -1;\n\n        Result() {\n        }\n\n        protected Result(@NonNull Parcel in) {\n            mMessage = in.readString();\n            mStatusCode = in.readInt();\n        }\n\n        public static final Creator<Result> CREATOR = new Creator<Result>() {\n            @NonNull\n            @Override\n            public Result createFromParcel(Parcel in) {\n                return new Result(in);\n            }\n\n            @NonNull\n            @Override\n            public Result[] newArray(int size) {\n                return new Result[size];\n            }\n        };\n\n        public String getMessage() {\n            return mMessage;\n        }\n\n        public int getStatusCode() {\n            return mStatusCode;\n        }\n\n        @Override\n        public int describeContents() {\n            return 0;\n        }\n\n        @Override\n        public void writeToParcel(@NonNull Parcel dest, int flags) {\n            dest.writeString(mMessage);\n            dest.writeInt(mStatusCode);\n        }\n    }\n}\n"
  },
  {
    "path": "libserver/src/main/java/io/github/muntashirakon/AppManager/server/common/ShellCaller.java",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.server.common;\n\nimport android.os.Parcel;\nimport android.os.Parcelable;\n\nimport androidx.annotation.NonNull;\n\npublic class ShellCaller extends Caller {\n    private final String mCommand;\n\n    public ShellCaller(String command) {\n        mCommand = command;\n    }\n\n    public String getCommand() {\n        return mCommand;\n    }\n\n    @Override\n    public int getType() {\n        return BaseCaller.TYPE_SHELL;\n    }\n\n    @Override\n    public int describeContents() {\n        return 0;\n    }\n\n    @Override\n    public void writeToParcel(Parcel dest, int flags) {\n        dest.writeString(mCommand);\n    }\n\n    protected ShellCaller(@NonNull Parcel in) {\n        mCommand = in.readString();\n    }\n\n    public static final Parcelable.Creator<ShellCaller> CREATOR = new Parcelable.Creator<ShellCaller>() {\n        @NonNull\n        @Override\n        public ShellCaller createFromParcel(Parcel source) {\n            return new ShellCaller(source);\n        }\n\n        @NonNull\n        @Override\n        public ShellCaller[] newArray(int size) {\n            return new ShellCaller[size];\n        }\n    };\n}\n"
  },
  {
    "path": "schema/changlelog.dtd",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<!DOCTYPE changelog [\n    <!ELEMENT changelog (release+)>\n    <!ATTLIST changelog bullet CDATA #IMPLIED>\n\n    <!ELEMENT release ((title|note|new|improve|fix)*)>\n    <!ATTLIST release type CDATA #REQUIRED>\n    <!ATTLIST release version CDATA #REQUIRED>\n    <!ATTLIST release code CDATA #REQUIRED>\n    <!ATTLIST release date CDATA #REQUIRED>\n\n    <!ELEMENT title (#PCDATA)>\n    <!ATTLIST title type CDATA #IMPLIED>\n\n    <!ELEMENT note (#PCDATA)>\n    <!ATTLIST note title CDATA #IMPLIED>\n    <!ATTLIST note bullet CDATA #IMPLIED>\n    <!ATTLIST note subtext CDATA #IMPLIED>\n\n    <!ELEMENT new (#PCDATA)>\n    <!ATTLIST new title CDATA #IMPLIED>\n    <!ATTLIST new bullet CDATA #IMPLIED>\n    <!ATTLIST new subtext CDATA #IMPLIED>\n\n    <!ELEMENT improve (#PCDATA)>\n    <!ATTLIST improve title CDATA #IMPLIED>\n    <!ATTLIST improve bullet CDATA #IMPLIED>\n    <!ATTLIST improve subtext CDATA #IMPLIED>\n\n    <!ELEMENT fix (#PCDATA)>\n    <!ATTLIST fix title CDATA #IMPLIED>\n    <!ATTLIST fix bullet CDATA #IMPLIED>\n    <!ATTLIST fix subtext CDATA #IMPLIED>\n    ]>\n"
  },
  {
    "path": "schema/packages.dtd",
    "content": "<!-- SPDX-License-Identifier: Apache-2.0 OR GPL-3.0-or-later -->\n<!DOCTYPE packages [\n    <!ELEMENT packages (package+)>\n    <!ATTLIST packages version CDATA #REQUIRED>\n\n    <!ELEMENT package ()>\n    <!ATTLIST package name CDATA #REQUIRED>\n    <!ATTLIST package label CDATA #REQUIRED>\n    <!ATTLIST package versionCode CDATA #REQUIRED>\n    <!ATTLIST package versionName CDATA #REQUIRED>\n    <!ATTLIST package minSdk CDATA #IMPLIED>\n    <!ATTLIST package targetSdk CDATA #IMPLIED>\n    <!ATTLIST package signature CDATA #REQUIRED>\n    <!ATTLIST package firstInstallTime CDATA #IMPLIED>\n    <!ATTLIST package lastUpdateTime CDATA #IMPLIED>\n    <!ATTLIST package installerPackageName CDATA #IMPLIED>\n    <!ATTLIST package installerPackageLabel CDATA #IMPLIED>\n    ]>\n"
  },
  {
    "path": "scripts/aab_to_apks.sh",
    "content": "#!/usr/bin/env bash\n# SPDX-License-Identifier: GPL-3.0-or-later\n\nset -e\n\n{ [[ $(uname) == Darwin ]] || [[ $(uname) =~ .*BSD.* ]]; } && {\n  alias sed=\"gsed\"\n  alias grep=\"ggrep\"\n}\n\nif [[ \"$#\" -lt 1 ]]; then\n  echo \"USAGE: RELEASE_TYPE [INTERACTIVE]\"\n  exit 1\nfi\n\nif ! which bundletool >/dev/null 2>&1; then\n  echo \"Bundletool doesn't exist in path\"\n  exit 1\nfi\n\nRELEASE_TYPE=$1\nINTERACTIVE=true\nif [[ \"$2\" == \"false\" ]] || [[ \"$2\" == \"0\" ]]; then\n  INTERACTIVE=false\nfi\n\nAPP_VERSION=\"v$(grep -m1 versionName ./app/build.gradle | awk -F \\\" '{print $2}')\"\nAPP_NAME=\"AppManager_${APP_VERSION}\"\nDEFAULT_NAME=\"app-${RELEASE_TYPE}\"\nCAPITALIZED_RELEASE_TYPE=$(tr '[:lower:]' '[:upper:]' <<<\"${RELEASE_TYPE:0:1}\")${RELEASE_TYPE:1}\n\nRELEASE_PATH=\"app/build/outputs/bundle/${RELEASE_TYPE}\"\nUNIVERSAL_APK_RELEASE_PATH=\"app/build/outputs/apk_from_bundle/${RELEASE_TYPE}\"\nTMP_PATH=\"tmp\"\n\nAAB_PATH=\"${RELEASE_PATH}/${DEFAULT_NAME}.aab\"\nAPKS_PATH=\"${RELEASE_PATH}/${DEFAULT_NAME}.apks\"\nAPK_PATH=\"${UNIVERSAL_APK_RELEASE_PATH}/${DEFAULT_NAME}-universal.apk\"\n\nSUPPORTED_LANGUAGES=(ar de en es fa fr hi id it ja ko nb pl pt ro ru tr uk vi zh)\nSUPPORTED_DPIS=(ldpi mdpi tvdpi hdpi xhdpi xxhdpi xxxhdpi)\nSUPPORTED_ARCHS=(armeabi_v7a arm64_v8a x86 x86_64)\n\nif [[ -f $(which secret) ]]; then\n  echo \"Using secret (https://github.com/angt/secret) for secrets...\";\n  KEYSTORE_PASS=$(secret show android_keystore)\n  if [[ \"$KEYSTORE_PASS\" == \"\" ]]; then\n    echo \"android_keystore does not exists.\"\n  else\n    KEY_ALIAS_PASS=$(secret show android_keystore_alias_key0)\n    if [[ \"$KEY_ALIAS_PASS\" == \"\" ]]; then\n      echo \"android_keystore_alias_key0 does not exists.\"\n    else\n      KEYSTORE=~/keystores/android_keystore.jks\n      KEY_ALIAS=key0\n    fi\n  fi\nfi\n\nif [[ \"${KEYSTORE}\" == \"\" ]]; then\n  if [[ \"$INTERACTIVE\" == true ]]; then\n    read -rp \"KeyStore file: \" KEYSTORE\n    echo\n    read -rsp \"KeyStore pass: \" KEYSTORE_PASS\n    echo\n    read -rp \"Key alias: \" KEY_ALIAS\n    echo\n    read -rsp \"Key alias pass: \" KEY_ALIAS_PASS\n    echo\n  else\n    echo \"Building unsigned APK...\"\n  fi\nfi\n\n# Build APKS\nif [[ -f \"${AAB_PATH}\" ]]; then\n  rm \"${AAB_PATH}\"\nfi\n./gradlew \"bundle$CAPITALIZED_RELEASE_TYPE\" --no-build-cache --no-configuration-cache --no-daemon\n\nif [[ -f ${AAB_PATH} ]]; then\n  if ! [[ \"${KEYSTORE}\" == \"\" ]]; then\n    KS_PARAMS=(\n      --ks=\"${KEYSTORE}\"\n      --ks-pass=pass:\"${KEYSTORE_PASS}\"\n      --ks-key-alias=\"${KEY_ALIAS}\"\n      --key-pass=pass:\"${KEY_ALIAS_PASS}\"\n    )\n  else\n    KS_PARAMS=()\n  fi\n  bundletool build-apks --overwrite --mode=default --bundle=\"${AAB_PATH}\" --output=\"${APKS_PATH}\" \"${KS_PARAMS[@]}\"\n  rm \"${AAB_PATH}\"\nelse\n  echo \"$AAB_PATH doesn't exist\"\n  exit 1\nfi\n\n# Unzip output APKS file\nif [[ -f ${APKS_PATH} ]]; then\n  unzip \"${APKS_PATH}\" -d \"${RELEASE_PATH}\"/${TMP_PATH}\n  rm \"${APKS_PATH}\"\nelse\n  echo \"$APKS_PATH doesn't exist\"\n  exit 1\nfi\n\nlastPWD=$(pwd)\ncd \"${RELEASE_PATH}\"/${TMP_PATH}/splits\n# Move required files\nmv base-master.apk base.apk\nfor lang in \"${SUPPORTED_LANGUAGES[@]}\"; do\n  mv \"base-${lang}.apk\" \"config.${lang}.apk\"\ndone\nfor dpi in \"${SUPPORTED_DPIS[@]}\"; do\n  mv \"base-${dpi}.apk\" \"config.${dpi}.apk\"\ndone\nfor arch in \"${SUPPORTED_ARCHS[@]}\"; do\n  if [ -f \"base-${arch}.apk\" ]; then\n    mv \"base-${arch}.apk\" \"config.${arch}.apk\"\n  else\n    echo 2>&1 \"base-${arch}.apk: not found.\"\n  fi\ndone\n# Delete rests\nrm ./base-*\n# Make zip\ncd \"${lastPWD}\"\nzip -j \"${RELEASE_PATH}/${APP_NAME}.apks\" \"${RELEASE_PATH}/${TMP_PATH}/splits\"/*\nrm -rf \"${RELEASE_PATH:?}/${TMP_PATH}\"\n\n# Build universal APK file\nif [[ -f ${APK_PATH} ]]; then\n  rm \"${APK_PATH}\"\nfi\n\nif ! [[ \"${KEYSTORE}\" == \"\" ]]; then\n  KS_PARAMS=(\n    -Pandroid.injected.signing.store.file=\"${KEYSTORE}\"\n    -Pandroid.injected.signing.store.password=\"${KEYSTORE_PASS}\"\n    -Pandroid.injected.signing.key.alias=\"${KEY_ALIAS}\"\n    -Pandroid.injected.signing.key.password=\"${KEY_ALIAS_PASS}\"\n  )\nelse\n  KS_PARAMS=()\nfi\n./gradlew \"package${CAPITALIZED_RELEASE_TYPE}UniversalApk\" --no-daemon \"${KS_PARAMS[@]}\"\n\nif [[ -f ${APK_PATH} ]]; then\n  mv \"${APK_PATH}\" \"${RELEASE_PATH}/${APP_NAME}.apk\"\nfi\n\necho \"Output generated at $(pwd)/${RELEASE_PATH}\"\n"
  },
  {
    "path": "scripts/backup_github_project.sh",
    "content": "#!/bin/bash\n# SPDX-License-Identifier: GPL-3.0-or-later\n\nGITHUB_USERNAME=\"MuntashirAkon\"\nREPOSITORY_NAME=\"AppManager\"\n\nif [[ -z \"$GITHUB_TOKEN\" ]]; then\n  if [[ -f $(which secret) ]]; then\n    echo \"Using secret (https://github.com/angt/secret) for secrets...\";\n    GITHUB_TOKEN=$(secret show app_manager_backup)\n  else\n    echo \"Error: GITHUB_TOKEN environment variable is not set.\"\n    exit 1\n  fi\nfi\n\nif [[ $# -lt 1 ]]; then\n  echo \"Usage: $0 <backup-directory>\"\n  exit 1\nfi\n\nBACKUP_DIRECTORY=\"$1\"\n\ngithub-backup \"$GITHUB_USERNAME\" \\\n  --token \"$GITHUB_TOKEN\" \\\n  --repository \"$REPOSITORY_NAME\" \\\n  --issues \\\n  --issue-comments \\\n  --issue-events \\\n  --pulls \\\n  --pull-comments \\\n  --pull-commits \\\n  --pull-details \\\n  --milestones \\\n  --releases \\\n  --assets \\\n  --labels \\\n  --skip-existing \\\n  --output-directory \"$BACKUP_DIRECTORY\"\n"
  },
  {
    "path": "scripts/docs.php",
    "content": "#!/usr/bin/env php\n<?php\n/* SPDX-License-Identifier: GPL-3.0-or-later */\n\ndate_default_timezone_set('UTC');\n\nconst HELP = <<<EOF\nUSAGE: php ./scripts/docs.php VERB [ARGS]\nVERBS:\n build <lang>   Build HTML from TeX using Pandoc for the given language.\n rebase         Extract strings from the TeX files and re-create the base\n                translation file.\n update <lang>  Rebuild HTML from strings.xml for the given language.\n deploy [force] Rebuild HTML and deploy it to the GitHub pages.\n pdf            Build PDF from TeX using pdflatex (English-only).\n debug          Do experiments.\n\nDEPENDENCIES: Pandoc, pandoc-crossref, minify\n\nEOF;\n\nrequire_once __DIR__ . \"/utils.php\";\n\nconst MAIN_TEX = 'main.tex';\nconst CUSTOM_CSS = 'custom.css';\nconst OUTPUT_FILENAME = 'index.html';\nconst STRINGS_XML = 'strings.xml';\nconst RAW_DIR = './docs/raw';\nconst BASE_DIR = RAW_DIR . '/en';\n\n// Deployment\nconst DIST_DIR = './docs/dist';\nconst DIST_REPO = 'git@github.com:MuntashirAkon/AppManager.git';\nconst DIST_BRANCH = 'pages';\n\n/**\n * Build and minify the outputs from TeX.\n *\n * @param string $lang Target language e.g. en, ru, ja, etc.\n */\nfunction build_html(string $lang): void {\n    $pwd = RAW_DIR . '/' . $lang;\n    $main_tex = $pwd . '/' . MAIN_TEX;\n    $output_file = $pwd . '/' . OUTPUT_FILENAME;\n    // Fixed directories\n    $base_dir = getcwd() . '/' . BASE_DIR;\n    $custom_css = $base_dir . '/' . CUSTOM_CSS;\n    $lua_dir = $base_dir . '/lua';\n    // Sequence must be preserved\n    $lua_files = [\n        'toc_generator.lua',\n        'img_to_object.lua',\n        'header_with_hyperlinks.lua',\n        'alert_fix.lua'\n    ];\n    $cmd = 'cd \"' .$pwd. '\" && pandoc \"' . MAIN_TEX . '\" -c \"' . CUSTOM_CSS .'\" -o \"' . OUTPUT_FILENAME . '\" -t html5'\n        . ' -f latex -s --toc -N --section-divs --default-image-extension=png -i -F pandoc-crossref --citeproc'\n        . ' --highlight-style=monochrome -M lang=' . get_IETF_language_tag($lang);\n    foreach ($lua_files as $lua_script) {\n        $cmd .= ' --lua-filter=\"' . $lua_dir . '/' . $lua_script . '\"';\n    }\n    // Create variables first\n    create_transient_tex($pwd, get_IETF_language_tag($lang));\n    // Run command\n    passthru($cmd, $ret_val);\n    if ($ret_val != 0) {\n        fprintf(STDERR, \"Pandoc could not generate an HTML file.\\n\");\n        exit(1);\n    }\n\n    // Read colours\n    $main_contents = file_get_contents($main_tex);\n    preg_match_all('/\\\\\\definecolor\\{(?<name>[^\\}]+)\\}\\{HTML\\}\\{(?<color>[0-9a-fA-F]+)\\}/', $main_contents, $matches);\n\n    // Replace colours\n    $to_search = array();\n    $to_replace = array();\n    foreach ($matches['name'] as $color_name) {\n        array_push($to_search, \"/style=\\\"background-color: $color_name\\\"/\", \"/style=\\\"color: $color_name\\\"/\");\n    }\n    foreach ($matches['color'] as $color_value) {\n        array_push($to_replace, \"class=\\\"colorbox\\\" style=\\\"background-color: #$color_value\\\"\", \"style=\\\"color: #$color_value\\\"\");\n    }\n\n    $to_search[] = '/href=\\\"custom\\.css\\\"/';\n    $to_replace[] = 'href=\"../css/custom.css\"';\n    $output_contents = file_get_contents($output_file);\n    $output_contents = preg_replace($to_search, $to_replace, $output_contents);\n\n    file_put_contents($output_file, $output_contents);\n\n    // Minify CSS\n    $cmd = \"minify \\\"$custom_css\\\" -o \\\"$base_dir/../css/custom.css\\\"\";\n    system($cmd, $ret_val);\n    if ($ret_val != 0) {\n        fprintf(STDERR, \"Could not minify custom.css\\n\");\n        exit(1);\n    }\n    // Minify HTML\n    $cmd = \"minify \\\"$output_file\\\" -o \\\"$pwd/index.min.html\\\" && mv \\\"$pwd/index.min.html\\\" \\\"$output_file\\\"\";\n    system($cmd, $ret_val);\n    if ($ret_val != 0) {\n        fprintf(STDERR, \"Could not minify index.html\\n\");\n        exit(1);\n    }\n    // Replace custom.css with ../css/custom.css\n}\n\n/**\n * Recursively parse all the \\input command and gather all the included tex files from main.tex.\n *\n * @param string[] $tex_files Relative links to the TeX files\n */\nfunction collect_tex_files(array &$tex_files, string $base_dir = null, string $tex_file = null): void {\n    if ($tex_file == null) {\n        $base_dir = getcwd() . '/' . BASE_DIR;\n        $tex_file = MAIN_TEX;\n    }\n    if (str_ends_with($tex_file, \".tex\") === false) {\n        $tex_file .= \".tex\";\n    }\n    if (!file_exists($base_dir . '/' . $tex_file)) {\n        echo \"File $tex_file does not exist!\\n\";\n        return;\n    }\n    $tex_files[] = $tex_file;\n    $contents = file_get_contents($base_dir . '/' . $tex_file);\n    preg_match_all('/\\\\\\input\\{(?<tex_file>[^\\}]+)\\}/', $contents, $matches);\n    foreach ($matches['tex_file'] as $t) {\n        collect_tex_files($tex_files, $base_dir, $t);\n    }\n}\n\n/**\n * Parse the given TeX file and return the parsed contents as a key-value pair.\n */\nfunction get_tex_contents_assoc(string $tex_file): array {\n    $tex_file_contents = file_get_contents($tex_file);\n\n    // Get all the titles\n    preg_match_all('/((?<=section{)|(?<=subsection{)|(?<=subsubsection{)|(?<=chapter{)|(?<=caption{)|(?<=paragraph{))(?<raw_title>.*)(?<=%%##)(?<key>.*)(?=>>)/', $tex_file_contents, $matches);\n    // Get titles from the raw titles\n    $title_values = array();\n    foreach ($matches['raw_title'] as $raw_title) {\n        $c = 0; // number of extra {\n        $len = strlen($raw_title);\n        for ($i = 0; $i < $len; ++$i) {\n            if ($raw_title[$i] == '{') {\n                if ($i == 0 || $raw_title[$i - 1] != '\\\\') {\n                    // Unescaped {\n                    ++$c; // Increase { counter\n                }\n            } else if ($raw_title[$i] == '}') {\n                if ($i == 0 || $raw_title[$i - 1] != '\\\\') {\n                    // Unescaped }\n                    --$c; // Decrease { counter since one match was found\n                    if ($c < 0) {\n                        // End of the title reached\n                        $title_values[] = substr($raw_title, 0, $i);\n                        break;\n                    }\n                }\n            }\n        }\n    }\n    // Check keys for verification testing\n    foreach ($matches['key'] as $key) {\n        if (strlen($key) == 0) {\n            echo \"Warning: Empty raw title for key $key\\n\";\n            continue;\n        }\n        if ($key[0] != '$') {\n            echo \"Warning: First letter of the title is not `$` (key: $key)\\n\";\n        }\n        if (!preg_match('/^\\$[a-zA-Z0-9-_.]+$/', $key)) {\n            echo \"Warning: Key ($key) didn't match the required Regex\\n\";\n        }\n    }\n    // Convert to key => value pair\n    $titles = array_combine($matches['key'], $title_values);\n\n    // Extract all the contents\n    preg_match_all('/(?<=%%!!)(?<key>.*)(?=<<)/', $tex_file_contents, $matches);\n    $content_values = array();\n    $offset = 0;\n    foreach ($matches['key'] as $key) {\n        $start_magic = '%%!!' . $key . \"<<\\n\";\n        $start_pos = strpos($tex_file_contents, $start_magic, $offset);\n        if ($start_pos === false) {\n            fprintf(STDERR, \"Error: Could not find key $key in $tex_file\\n\");\n            exit(1);\n        }\n        $start_pos += strlen($start_magic);\n        $end_pos = strpos($tex_file_contents, \"\\n%%!!>>\", $offset);\n        if ($end_pos === false) {\n            $supposed_block_start_pos = strpos($tex_file_contents, \"\\n%%!!\", $start_pos);\n            if ($supposed_block_start_pos !== false) {\n                syntax_error_with_position($tex_file, $tex_file_contents, $supposed_block_start_pos, \"Could not locate %%!!>> for key: $key\");\n            } else {\n                syntax_error_with_position($tex_file, $tex_file_contents, strlen($tex_file_contents), \"EOF reached before matching %%!!>> for key: $key\");\n            }\n        }\n        // Ensure there is no %%!!<string><< or %%##$<string>>> between start and end since nesting isn't allowed\n        $mal_pos1 = strpos($tex_file_contents, \"\\n%%!!\", $start_pos);\n        $mal_pos2 = strpos($tex_file_contents, \"\\n%%##\", $start_pos);\n        if ($mal_pos1 !== $end_pos) {\n            syntax_error_with_position($tex_file, $tex_file_contents, $mal_pos1);\n        }\n        if ($mal_pos2 !== false && $mal_pos2 < $end_pos) {\n            syntax_error_with_position($tex_file, $tex_file_contents, $mal_pos2);\n        }\n        $offset = $end_pos + 7;\n        $content_values[] = substr($tex_file_contents, $start_pos, $end_pos - $start_pos);\n        // Ensure that the next key is available before running into %%!!>> again\n        $mal_pos1 = strpos($tex_file_contents, \"\\n%%!!\", $offset);\n        $mal_pos2 = strpos($tex_file_contents, \"\\n%%!!>>\", $offset);\n        if ($mal_pos1 !== false && $mal_pos1 === $mal_pos2) {\n            // Invalid %%!!>> i.e. the end position considered earlier is wrong\n            syntax_error_with_position($tex_file, $tex_file_contents, $end_pos);\n        }\n    }\n    foreach ($matches['key'] as $key) {\n        if (strlen($key) == 0) {\n            echo \"Warning: Empty raw title for key $key\\n\";\n            continue;\n        }\n        if (!preg_match('/^[a-zA-Z0-9-_.]+$/', $key)) {\n            echo \"Warning: Key ($key) didn't match the required Regex\\n\";\n        }\n    }\n    $contents = array_combine($matches['key'], $content_values);\n\n    return array_merge($titles, $contents);\n}\n\n/**\n * Update base strings.xml\n */\nfunction rebase_strings(): void {\n    $base_dir = getcwd() . '/' . BASE_DIR;\n    $strings_file = $base_dir . '/' . STRINGS_XML;\n    $tex_files = array();\n    // Gather all the tex files\n    collect_tex_files($tex_files);\n    $xml = new XMLWriter();\n    $xml->openUri($strings_file);\n    $xml->setIndent(true);\n    $xml->setIndentString('    ');\n    $xml->startDocument('1.0', 'utf-8');\n    $xml->writeComment('This file is auto-generated by ./scripts/docs.php. DO NOT EDIT THIS FILE.');\n    $xml->startElement('resources');\n    $xml->writeAttribute('xmlns:xliff', 'urn:oasis:names:tc:xliff:document:1.2');\n    foreach ($tex_files as $tex_file) {\n        $contents = get_tex_contents_assoc($base_dir . '/' . $tex_file);\n        // Replace `/` and `.tex` with `$`\n        $key_prefix = preg_replace(['/\\//', '/\\.tex$/'], '$', $tex_file);\n        foreach ($contents as $key => $val) {\n            $xml->startElement('string');\n            $xml->writeAttribute('name', $key_prefix . $key);\n            $xml->writeRaw(android_escape_slash_newline(ltrim($val)));\n            $xml->endElement(); // string\n        }\n    }\n    $xml->endElement(); // resources\n}\n\n/**\n * Update translation from strings.xml for the given language. It replaces the strings available in the strings.xml and\n * then rebuilds the HTML file.\n *\n * @param string $lang Target language e.g. en, ru, ja, etc.\n */\nfunction update_translations(string $lang): void {\n    $base_dir = getcwd() . '/' . BASE_DIR;\n    $pwd = $base_dir . '/../' . $lang;\n    $strings_file = $pwd . '/' . STRINGS_XML;\n    // Read strings.xml: Get tex file and key\n    $dom = new DOMDocument();\n    $dom->loadXML(file_get_contents($strings_file));\n    $string_nodes = $dom->getElementsByTagName('string');\n    $strings = array();  // tex_file => [ key => value ]\n    foreach ($string_nodes as $node) {\n        $raw_key = $node->getAttribute('name');\n        $pos = strrpos($raw_key, '$');\n        if ($raw_key[$pos - 1] == '$') --$pos; // This $ was part of the title\n        $tex_file = str_replace('$', '/', substr($raw_key, 0, $pos) . '.tex');\n        $key = substr($raw_key, $pos + 1);\n        if (strlen($tex_file) == 0 || strlen($key) == 0) {\n            fprintf(STDERR, \"Invalid TeX filename or key (raw: $raw_key)\\n\");\n            exit(1);\n        }\n        if (!isset($strings[$tex_file])) $strings[$tex_file] = array();\n        $strings[$tex_file][$key] = get_trimmed_content($node->textContent);\n    }\n    // Gather all the tex files\n    $tex_files = array();\n    collect_tex_files($tex_files);\n    foreach ($tex_files as $tex_file) {\n        $target_path = $pwd . '/' . $tex_file;\n        // Create directories if not exists\n        $dir = substr($target_path, 0, strrpos($target_path, '/'));\n        if (!is_dir($dir)) {\n            if (file_exists($dir)) unlink($dir);\n            if (!mkdir($dir, 0777, true)) {\n                fprintf(STDERR, \"Error: Could not create $dir\\n\");\n                exit(1);\n            }\n        }\n        if (isset($strings[$tex_file])) { // Matched a tex file\n            $contents = $strings[$tex_file];\n            $tex_file_contents = file_get_contents($base_dir . '/' . $tex_file);\n            foreach ($contents as $key => $val) {\n                if (strlen($key) == 0) {\n                    echo \"Warning: Empty key (file: $tex_file)\";\n                    continue;\n                }\n                if ($key[0] == '$') {\n                    // Fetch raw title and its offset\n                    $magic = preg_quote('%%##' . $key . '>>', '/');\n                    preg_match('/((?<=section{)|(?<=subsection{)|(?<=subsubsection{)|(?<=chapter{)|(?<=caption{)|(?<=paragraph{))(?<raw_title>.*)'. $magic .'/', $tex_file_contents, $matches, PREG_OFFSET_CAPTURE);\n                    if (!isset($matches['raw_title'])) {\n                        echo \"Warning: Could not find magic $magic in $tex_file\\n\";\n                        continue;\n                    }\n                    // Sanitize raw title to real title\n                    $raw_title = $matches['raw_title'][0];\n                    $start_pos = $matches['raw_title'][1];\n                    $title = null;\n                    $c = 0; // number of extra {\n                    $len = strlen($raw_title);\n                    for ($i = 0; $i < $len; ++$i) {\n                        if ($raw_title[$i] == '{') {\n                            if ($i == 0 || $raw_title[$i - 1] != '\\\\') {\n                                // Unescaped {\n                                ++$c; // Increase { counter\n                            }\n                        } else if ($raw_title[$i] == '}') {\n                            if ($i == 0 || $raw_title[$i - 1] != '\\\\') {\n                                // Unescaped }\n                                --$c; // Decrease { counter since one match was found\n                                if ($c < 0) {\n                                    // End of the title reached\n                                    $title = substr($raw_title, 0, $i);\n                                    break;\n                                }\n                            }\n                        }\n                    }\n                    // Replace title with translated title\n                    $tex_file_contents = substr_replace($tex_file_contents, $val, $start_pos, strlen($title));\n                    continue;\n                }\n                // Replace TeX contents\n                $start_magic = '%%!!' . $key . \"<<\\n\";\n                $start_pos = strpos($tex_file_contents, $start_magic);\n                if ($start_pos === false) {\n                    echo \"Warning: Key not found (file: $tex_file, key: $key)\\n\";\n                    continue;\n                }\n                $start_pos += strlen($start_magic);\n                $end_pos = strpos($tex_file_contents, \"\\n%%!!>>\", $start_pos);\n                $tex_file_contents = substr_replace($tex_file_contents, $val, $start_pos, $end_pos - $start_pos);\n            }\n            // Store the files in pwd\n            file_put_contents($pwd . '/' . $tex_file, $tex_file_contents);\n            // Check if curly braces are closed correctly\n            $brace_count = 0;\n            $len = strlen($tex_file_contents);\n            for ($i = 0; $i < $len; ++$i) {\n                if ($tex_file_contents[$i] == '{' && ($i == 0 || $tex_file_contents[$i - 1] != '\\\\')) {\n                    // Unescaped {\n                    ++$brace_count;\n                } else if ($tex_file_contents[$i] == '}' && ($i == 0 || $tex_file_contents[$i - 1] != '\\\\')) {\n                    // Unescaped }\n                    --$brace_count;\n                    if ($brace_count < 0) {\n                        syntax_error_with_position($pwd . '/' . $tex_file, $tex_file_contents, $i, \"Syntax error '$tex_file_contents[$i]'\");\n                    }\n                }\n            }\n            if ($brace_count > 0) {\n                $brace_count = 0;\n                for ($i = $len - 1; $i >= 0; --$i) {\n                    if ($tex_file_contents[$i] == '{' && ($i == 0 || $tex_file_contents[$i - 1] != '\\\\')) {\n                        // Unescaped {\n                        --$brace_count;\n                        if ($brace_count < 0) {\n                            syntax_error_with_position($pwd . '/' . $tex_file, $tex_file_contents, $i, \"Syntax error '$tex_file_contents[$i]'\");\n                        }\n                    } else if ($tex_file_contents[$i] == '}' && ($i == 0 || $tex_file_contents[$i - 1] != '\\\\')) {\n                        // Unescaped }\n                        ++$brace_count;\n                    }\n                }\n            }\n            // Begin/end checks FIXME: This check is only covers a few things. It completely ignores checks like nesting\n            preg_match_all('/(?<=\\\\begin\\{)(?<env>.*)(?=})/', $tex_file_contents, $matches);\n            $env_begin = $matches['env'];\n            sort($env_begin);\n            preg_match_all('/(?<=\\\\end\\{)(?<env>.*)(?=})/', $tex_file_contents, $matches);\n            $env_end = $matches['env'];\n            sort($env_end);\n            if (count($env_begin) != count($env_end)) {\n                fprintf(STDERR, \"Error: Invalid number of begin and ending of environments.\\n\");\n                exit(1);\n            }\n            for ($i = 0; $i < count($env_begin); ++$i) {\n                if ($env_begin[$i] != $env_end[$i]) {\n                    fprintf(STDERR, \"Error: Could not find the end of the environment: $env_begin[$i].\\n\");\n                    exit(1);\n                }\n            }\n        } else { // Didn't match any translation\n            // Simply copy the file\n            copy($base_dir . '/' . $tex_file, $pwd . '/' . $tex_file);\n        }\n    }\n    // Build HTML\n    build_html($lang);\n    // Delete all except index.html and strings.xml\n    $skip_delete = [OUTPUT_FILENAME, STRINGS_XML];\n    $paths = list_files_recursive($pwd);\n    rsort($paths);\n    foreach ($paths as $path) {\n        if (!in_array($path, $skip_delete)) {\n            $full_path = $pwd . '/' . $path;\n            if (is_dir($full_path)) rmdir($full_path);\n            else unlink($full_path);\n        }\n    }\n}\n\nfunction deploy(bool $force = false): void {\n    $languages = collect_languages();\n    // Rebuild HTML\n    foreach ($languages as $language) {\n        $output_file = RAW_DIR . '/' . $language . '/' . OUTPUT_FILENAME;\n        $strings_file = RAW_DIR . '/' . $language . '/' . STRINGS_XML;\n        if (!$force && !need_update($output_file, $strings_file)) {\n            fprintf(STDERR, \"Skipped updating HTML for language $language\\n\");\n            continue;\n        }\n        if ($language == 'en') {\n            // For en, only build HTML\n            build_html($language);\n        } else {\n            update_translations($language);\n        }\n    }\n    if (!is_dir(DIST_DIR)) {\n        mkdir(DIST_DIR);\n    }\n    // Copy HTML files to dist dir\n    foreach ($languages as $language) {\n        $src_html = RAW_DIR . '/' . $language . '/index.html';\n        $dst_dir = DIST_DIR . '/' . $language;\n        if (!is_dir($dst_dir)) {\n            mkdir($dst_dir);\n        }\n        copy($src_html, $dst_dir . '/index.html');\n    }\n    // Copy other files\n    // - images\n    $dir = RAW_DIR . '/images';\n    $files = list_files_recursive($dir);\n    mkdir(DIST_DIR . '/images');\n    foreach ($files as $file) {\n        copy($dir . '/' . $file, DIST_DIR . '/images/' . $file);\n    }\n    // - css\n    $dir = RAW_DIR . '/css';\n    $files = list_files_recursive($dir);\n    mkdir(DIST_DIR . '/css');\n    foreach ($files as $file) {\n        copy($dir . '/' . $file, DIST_DIR . '/css/' . $file);\n    }\n    // Generate index.html\n    $js_lang_html = array();\n    foreach ($languages as $language) {\n        $lang_code = get_IETF_language_tag($language);\n        $js_lang_html[] = \"  <a class=\\\"link\\\" href=\\\"$language/\\\" onclick=\\\"return setLanguage('$language')\\\">\" . trim(Locale::getDisplayName($lang_code, $lang_code)) . \"</a>\";\n    }\n    $html_contents = file_get_contents(RAW_DIR . '/index.html');\n    $html_contents = str_replace('PLACEHOLDER_LANGUAGES_AS_ARRAY', implode('\\', \\'', $languages), $html_contents);\n    $html_contents = str_replace('<!-- PLACEHOLDER_LANGUAGES_AS_HTML -->', \"\\n\" . implode(\" &#x2022;\\n\", $js_lang_html) . \"\\n\", $html_contents);\n    file_put_contents(DIST_DIR . '/index.html', $html_contents);\n    // Ignore .DS_Store files\n    file_put_contents(DIST_DIR . '/' . '.gitignore', '*.DS_Store');\n    // Commit changes\n    system('cd ' . DIST_DIR . ' && git init && git add -A && git commit && git push -f ' . DIST_REPO . ' master:' . DIST_BRANCH);\n    // Delete dist dir\n    system('rm -rf ' . DIST_DIR);\n}\n\nfunction collect_languages() : array {\n    $files = array_diff(list_files(RAW_DIR), array('css', 'images'));\n    $languages = array();\n    foreach ($files as $file) {\n        if (is_dir(RAW_DIR . '/' . $file)) {\n            $languages[] = $file;\n        }\n    }\n    return $languages;\n}\n\nfunction need_update(string $html_file, string $strings_file) : bool {\n    if (!is_file($html_file) || !is_file($strings_file)) {\n        return true;\n    }\n    $html_time = filemtime($html_file);\n    $strings_time = filemtime($strings_file);\n    if ($html_time === false || $strings_time === false) {\n        return true;\n    }\n    return $strings_time > $html_time;\n}\n\nfunction get_trimmed_content(string $content) : string {\n    $len = strlen($content);\n    if ($len > 0 && $content[0] == '\"' && $content[$len - 1] == '\"') {\n        // Remove starting and ending quotations\n        $content = substr($content, 1, strlen($content) - 2);\n    }\n    // Remove all newline literals\n    return android_escape_slash_newline_reverse(str_replace(\"\\n\", '', $content));\n}\n\nfunction get_IETF_language_tag(string $lang): string {\n    if (!str_contains($lang, '-')) {\n        return $lang;\n    }\n    $lang_parts = explode('-', $lang);\n    if ($lang_parts[1][0] == 'r') {\n        // Skip r\n        $lang_parts[1] = substr($lang_parts[1], 1, strlen($lang_parts[1]) - 1);\n    }\n    if ($lang_parts[1] == 'CN') $lang_parts[1] = 'Hans';\n    else if ($lang_parts[1] == 'TW') $lang_parts[1] = 'Hant';\n    return implode('-', $lang_parts);\n}\n\nfunction create_transient_tex(string $target_dir, string $ietf_lang = 'en'): void {\n    $am_version = system(\"grep -m1 versionName ./app/build.gradle | awk -F \\\\\\\" '{print $2}'\", $ret_val);\n    if ($ret_val != 0) {\n        fprintf(STDERR, \"Could not get the versionName from ./app/build.gradle\\n\");\n        exit(1);\n    }\n    $fmt = new IntlDateFormatter(\n        $ietf_lang,\n        IntlDateFormatter::FULL,\n        IntlDateFormatter::FULL,\n        'UTC',\n        IntlDateFormatter::GREGORIAN,\n        'd MMMM yyyy'\n    );\n    $today = $fmt->format(new DateTime());\n    $content = <<<EOF\n\\\\newcommand{\\\\version}{v{$am_version}}\n\\\\ifdefined\\\\Vanilla\\\\else\n    \\\\renewcommand{\\\\today}{{$today}}\n\\\\fi\nEOF;\n\n    file_put_contents($target_dir . '/transient.tex', $content);\n}\n\n// MAIN //\nif ($argc < 2) {\n    fprintf(STDERR, \"Invalid number of arguments.\\n\\n\");\n    fprintf(STDERR, HELP);\n    exit(1);\n}\n\n$verb = $argv[1];\n\nswitch($verb) {\n    case 'build':\n        if (!isset($argv[2])) {\n            fprintf(STDERR, \"build <lang>\\n\");\n            exit(1);\n        }\n        build_html($argv[2]);\n        break;\n    case 'rebase':\n        rebase_strings();\n        break;\n    case 'update':\n        if (!isset($argv[2])) {\n            fprintf(STDERR, \"update <lang>\\n\");\n            exit(1);\n        }\n        if ($argv[2] == 'en') {\n            // For en, we only rebase string and update HTML (for some reason)\n            rebase_strings();\n            build_html($argv[2]);\n        } else {\n            update_translations($argv[2]);\n        }\n        break;\n    case 'deploy':\n        $force = isset($argv[2]) && $argv[2] == 'force';\n        deploy($force);\n        break;\n    case 'pdf':\n        create_transient_tex(BASE_DIR);\n        passthru('cd ' . BASE_DIR . ' && pdflatex -shell-escape main_vanilla.tex', $return_code);\n        if ($return_code == 0) {\n            echo 'Built pdf: ' . BASE_DIR . '/main_vanilla.pdf' . \"\\n\";\n        } else {\n            // Error\n            exit($return_code);\n        }\n        break;\n    case 'debug':\n        echo \"Nothing to do.\\n\";\n        break;\n    case 'help':\n        echo HELP;\n        exit(0);\n    default:\n        fprintf(STDERR, \"Invalid verb $verb\\n\\n\");\n        fprintf(STDERR, HELP);\n        exit(1);\n}\n"
  },
  {
    "path": "scripts/fix_strings.php",
    "content": "#!/usr/bin/env php\n<?php\n/* SPDX-License-Identifier: GPL-3.0-or-later */\n\n// Example usage: php ./scripts/fix_strings.php ./app/src/main/res/\n\nif ($argc != 2) {\n    echo \"USAGE: php ./scripts/fix_strings.php <res_dir>\\n\";\n    exit(1);\n}\n\n$res_dir = $argv[1];\n$string_files = array();\n\nif (file_exists($res_dir)) {\n    if (!is_dir($res_dir)) {\n        echo \"$res_dir is not a directory.\\n\";\n        exit(1);\n    } else {\n        $_files = array_diff(scandir($res_dir), array('..', '.'));\n        foreach ($_files as $file) {\n            if (str_contains($file, 'values-')) {\n                $file = $res_dir . '/' . $file . '/strings.xml';\n                if (file_exists($file)) {\n                    $string_files[] = $file;\n                }\n            }\n        }\n    }\n} else {\n    echo \"$res_dir doesn't exist.\\n\";\n    exit(1);\n}\n\n// We've got all the strings.xml files at this point\n// Apply fixes\n$patterns = [\n    /** @lang RegExp */\n    '/\\&lt\\;xliff\\:g xmlns\\:xliff\\=\\\\\\\"urn\\:oasis\\:names\\:tc\\:xliff\\:document\\:1\\.2\\\\\\\" id\\=\\\\\\\"([^\\\"]+)\\\\\\\" example\\=\\\\\\\"([^\\\"]+)\\\\\\\"\\&gt\\;([^\\&]+)\\&lt\\;\\/xliff\\:g\\&gt\\;/',\n    /** @lang RegExp */\n    '/\\&lt\\;a href\\=\\\\\\\"([^\\\"]+)\\\\\\\"\\&gt\\;([^\\&]+)\\&lt\\;\\/a\\&gt\\;/',\n    /** @lang RegExp */\n    '/\\&lt\\;(\\w+)\\&gt\\;([^\\&]+)\\&lt\\;\\/(\\w+)\\&gt\\;/',\n];\n$replacements = [\n    /** @lang text */\n    '<xliff:g id=\"$1\" example=\"$2\">$3</xliff:g>',\n    /** @lang text */\n    '<a href=\"$1\">$2</a>',\n    /** @lang text */\n    '<$1>$2</$3>'\n];\nforeach ($string_files as $string_file) {\n    $contents = file_get_contents($string_file);\n    file_put_contents($string_file, preg_replace($patterns, $replacements, $contents));\n}\n"
  },
  {
    "path": "scripts/keep-five.sh",
    "content": "#!/bin/bash\n\nINITIAL_HASH=\"021151c5a2b1cc201461625e286d1ca4531274db\"\nBRANCH=\"master\"\n\n# Ensure complete history\ngit fetch --unshallow origin\n\n# Get up to 5 commits after initial in chronological order\ncommits=$(git rev-list --max-count=5 --reverse \"$BRANCH\" ^$INITIAL_HASH)\n\n# Create new history from initial commit\ngit checkout -B temp-branch $INITIAL_HASH\n\n# Batch cherry-pick all eligible commits at once\nif [ -n \"$commits\" ]; then\n  git cherry-pick $commits\nfi\n\n# Finalize branch update\ngit branch -f $BRANCH temp-branch\ngit checkout $BRANCH\ngit branch -D temp-branch\n"
  },
  {
    "path": "scripts/make_debloat_list.php",
    "content": "<?php\n/* SPDX-License-Identifier: AGPL-3.0-or-later */\n\nrequire_once __DIR__ . '/utils.php';\n\nconst SUPPORTED_REMOVAL_TYPES = ['delete', 'replace', 'caution', 'unsafe'];\nconst SUPPORTED_TAGS = [];\nconst REPO_DIR = __DIR__ . '/android-debloat-list';\n\n$target_file = __DIR__ . '/../app/src/main/assets/debloat.json';\n\n$debloat_list = array();\nforeach (list_files(REPO_DIR) as $filename) {\n    if (!str_ends_with($filename, \".json\")) {\n        continue;\n    }\n    $file = REPO_DIR . '/' . $filename;\n    $type = substr($filename, 0, -5);\n    $list = json_decode(file_get_contents($file), true);\n    if ($list === null) {\n        fprintf(STDERR, \"Malformed file: $file\\n\");\n        continue;\n    } else fprintf(STDERR, \"Adding $filename\\n\");\n    foreach ($list as $item) {\n        if (isset($item['suppress'])) {\n            unset($item['suppress']);\n        }\n        $item['type'] = $type;\n        $debloat_list[] = $item;\n    }\n}\n\nfile_put_contents($target_file, json_encode($debloat_list, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE));\n"
  },
  {
    "path": "scripts/make_docs.sh",
    "content": "#!/usr/bin/env bash\n# SPDX-License-Identifier: GPL-3.0-or-later\n\n# Abort on errors\nset -e\n\n{ [[ $(uname) == Darwin ]] || [[ $(uname) =~ .*BSD.* ]]; } && {\n  alias sed=\"gsed\"\n  alias grep=\"ggrep\"\n}\n\n# Contains all supported languages except English\nSUPPORTED_LANGUAGES=(de es ja ru zh-rCN)\n\nres_folder=\"docs/src/main/res\"\nassets_folder=\"docs/src/main/assets\"\ndocs_folder=\"docs/raw\"\n\n[[ -d \"${res_folder}\" ]] || mkdir -p \"${res_folder}\"\n[[ -d \"${assets_folder}\" ]] || mkdir -p \"${assets_folder}\"\n! [[ -e \"${assets_folder}/docs\" ]] || rm -rf \"${assets_folder}/docs\"\n\n# Copy base files\nraw_folder=\"${res_folder}/raw\"\n[[ -d \"${raw_folder}\" ]] || mkdir -p \"${raw_folder}\"\ncp -a \"${docs_folder}/css/\"* \"${raw_folder}\"\ncp -a \"${docs_folder}/images/\"* \"${raw_folder}\"\ncp -a \"${docs_folder}/en/index.html\" \"${raw_folder}/\"\nsed -i -e 's|src=\\.\\./images/|src=|' \\\n -e 's|href=\\.\\./css/|href=|' \\\n -e 's|data=\\.\\./images/|data=|'  \"${raw_folder}/index.html\"\n\n# Copy index html and css files\nfor lang in \"${SUPPORTED_LANGUAGES[@]}\"; do\n  raw_folder=\"${res_folder}/raw-${lang}\"\n  [[ -d \"${raw_folder}\" ]] || mkdir -p \"${raw_folder}\"\n  cp -a \"${docs_folder}/${lang}/index.html\" \"${raw_folder}/\"\n  sed -i -e 's|src=\\.\\./images/|src=|' \\\n   -e 's|href=\\.\\./css/|href=|' \\\n   -e 's|data=\\.\\./images/|data=|' \"${raw_folder}/index.html\"\ndone\n"
  },
  {
    "path": "scripts/make_suggestions.php",
    "content": "<?php\n/* SPDX-License-Identifier: AGPL-3.0-or-later */\n\nrequire_once __DIR__ . '/utils.php';\n\nconst REPO_DIR = __DIR__ . '/android-debloat-list';\nconst SUGGESTIONS_DIR = REPO_DIR . '/suggestions';\n\n$target_file = __DIR__ . '/../app/src/main/assets/suggestions.json';\n\n$suggestions = array();\nforeach (list_files(SUGGESTIONS_DIR) as $filename) {\n    if (!str_ends_with($filename, \".json\")) {\n        continue;\n    }\n    $suggestion_file = SUGGESTIONS_DIR . '/' . $filename;\n    $suggestion_id = substr($filename, 0, -5);\n    $single_suggestion_list = json_decode(file_get_contents($suggestion_file), true);\n    if ($single_suggestion_list === null) {\n        fprintf(STDERR, \"Malformed file: $suggestion_file\\n\");\n        continue;\n    } else fprintf(STDERR, \"Adding $filename\\n\");\n    foreach ($single_suggestion_list as $suggestion) {\n        $suggestion['_id'] = $suggestion_id;\n        $suggestions[] = $suggestion;\n    }\n}\n\nfile_put_contents($target_file, json_encode($suggestions, JSON_UNESCAPED_UNICODE));\n"
  },
  {
    "path": "scripts/push_to_mirrors.sh",
    "content": "#!/usr/bin/env sh\n# SPDX-License-Identifier: GPL-3.0-or-later\n\nif ! git remote get-url gitlab; then\n    git remote add --mirror=push gitlab git@gitlab.com:muntashir/AppManager.git\nfi\n\nif ! git remote get-url riseup; then\n    git remote add --mirror=push riseup git@0xacab.org:muntashir/AppManager.git\nfi\n\nif ! git remote get-url codeberg; then\n    git remote add --mirror=push codeberg git@codeberg.org:muntashir/AppManager.git\nfi\n\nif ! git remote get-url sourcehut; then\n    git remote add --mirror=push sourcehut git@git.sr.ht:~muntashir/AppManager\nfi\n\ngit push gitlab\ngit push riseup\ngit push codeberg\ngit push sourcehut\n"
  },
  {
    "path": "scripts/update_libraries.php",
    "content": "<?php\n/* SPDX-License-Identifier: GPL-3.0-or-later */\n\nrequire_once __DIR__ . '/android-libraries/php/AndroidLibV1.php';\nrequire_once __DIR__ . '/utils.php';\n\nconst LIBS_FILE = __DIR__ . '/android-libraries/libs.json';\n\nconst TRACKERS_XML = __DIR__ . '/../app/src/main/res/values/trackers.xml';\nconst LIBS_XML = __DIR__ . '/../app/src/main/res/values/libs.xml';\nconst NATIVE_LIBS_XML = __DIR__ . '/../app/src/main/res/values/native_libs.xml';\n\n$libs = parse_libs_file(LIBS_FILE);\n\nupdate_trackers($libs);\nupdate_native_libraries($libs);\nupdate_libraries($libs);\n\n/**\n * @param AndroidLibV1[] $libs\n * @return void\n */\nfunction update_libraries(array $libs): void {\n    $libs_info = array();\n    foreach ($libs as $lib) {\n        if ($lib->code_signatures == null) continue;\n        $lib_info = array();\n        $lib_info['code_sigs'] = array();\n        $arr = explode(\"|\", $lib->code_signatures);\n        foreach ($arr as $sig) {\n            if (!in_array($sig, $lib_info['code_sigs'])) {\n                if (str_starts_with($sig, '/')) {\n                    $sig = substr($sig, 1, strlen($sig) - 1);\n                }\n                $lib_info['code_sigs'][] = str_replace('/', '.', $sig);\n            }\n        }\n        $lib_info['type'] = $lib->type;\n        $lib_info['website'] = $lib->website ?? '';\n        $libs_info[$lib->label] = $lib_info;\n    }\n    ksort($libs_info);\n    $out = <<<EOF\n<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<resources>\n    <array name=\"lib_signatures\">\n\nEOF;\n\n    foreach ($libs_info as $info) {\n        foreach ($info[\"code_sigs\"] as $sig) {\n            $out .= \"        <item>$sig</item>\\n\";\n        }\n    }\n\n    $out .= <<<EOF\n    </array>\n    <array name=\"lib_names\">\n\nEOF;\n\n    foreach ($libs_info as $name => $info) {\n        foreach ($info[\"code_sigs\"] as $ignored) {\n            $out .= \"        <item>\" . android_escape($name) . \"</item>\\n\";\n        }\n    }\n\n    $out .= <<<EOF\n    </array>\n    <array name=\"lib_types\">\n\nEOF;\n\n    foreach ($libs_info as $info) {\n        foreach ($info[\"code_sigs\"] as $ignored) {\n            $out .= \"        <item>\" . android_escape($info['type']) . \"</item>\\n\";\n        }\n    }\n\n    $out .= <<<EOF\n    </array>\n    <array name=\"lib_website\">\n\nEOF;\n\n    foreach ($libs_info as $info) {\n        foreach ($info[\"code_sigs\"] as $ignored) {\n            $out .= \"        <item>\" . android_escape($info['website']) . \"</item>\\n\";\n        }\n    }\n\n    $out .= <<<EOF\n    </array>\n</resources>\nEOF;\n    file_put_contents(LIBS_XML, $out);\n}\n\n\n/**\n * @param AndroidLibV1[] $libs\n * @return void\n */\nfunction update_native_libraries(array $libs): void {\n    $libs_info = array();\n    foreach ($libs as $lib) {\n        if ($lib->solib_signatures == null) continue;\n        $lib_info = array();\n        $lib_info['label'] = $lib->label;\n        $lib_info['signature'] = $lib->solib_signatures;\n        $lib_info['tracker'] = $lib->anti_features != null && in_array('Tracking', $lib->anti_features);\n        $lib_info['relativeUrl'] = $lib->website ?? '';\n        $libs_info[] = $lib_info;\n    }\n    usort($libs_info, function ($o1, $o2) {\n        return $o1['label'] <=> $o2['label'];\n    });\n    $out = <<<EOF\n<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<resources>\n    <array name=\"lib_native_signatures\">\n\nEOF;\n\n    foreach ($libs_info as $info) {\n        $out .= \"        <item>\" . android_escape_slash($info[\"signature\"]) . \"</item>\\n\";\n    }\n\n    $out .= <<<EOF\n    </array>\n    <array name=\"lib_native_names\">\n\nEOF;\n\n    foreach ($libs_info as $info) {\n        $out .= \"        <item>\" . android_escape($info['label']) . \"</item>\\n\";\n    }\n\n    $out .= <<<EOF\n    </array>\n    <integer-array name=\"lib_native_is_tracker\">\n\nEOF;\n\n    foreach ($libs_info as $info) {\n        $out .= \"        <item>\" . ($info['tracker'] == \"yes\" ? 1 : 0) . \"</item>\\n\";\n    }\n\n    $out .= <<<EOF\n    </integer-array>\n    <array name=\"lib_native_website\">\n\nEOF;\n\n    foreach ($libs_info as $info) {\n        $out .= \"        <item>\" . android_escape($info['relativeUrl']) . \"</item>\\n\";\n    }\n\n    $out .= <<<EOF\n    </array>\n</resources>\nEOF;\n    file_put_contents(NATIVE_LIBS_XML, $out);\n}\n\n\n/**\n * @param AndroidLibV1[] $libs\n * @return void\n */\nfunction update_trackers(array $libs) : void {\n    $tracker_info = array();\n    foreach ($libs as $lib) {\n        if ($lib->code_signatures == null) continue;\n        if ($lib->exodus_id != null || $lib->etip_id != null) {\n            $label = ($lib->exodus_id != null ? '' : '²') . $lib->label;\n            if (!isset($tracker_info[$label])) {\n                $tracker_info[$label] = array();\n            }\n            $tracker_info[$label]['code_sigs'] = array();\n            $arr = explode(\"|\", $lib->code_signatures);\n            foreach ($arr as $sig) {\n                if (!in_array($sig, $tracker_info[$label][\"code_sigs\"])) {\n                    if (str_starts_with($sig, '/')) {\n                        $sig = substr($sig, 1, strlen($sig) - 1);\n                    }\n                    $tracker_info[$label][\"code_sigs\"][] = str_replace('/', '.', $sig);\n                }\n            }\n        }\n    }\n    ksort($tracker_info);\n    $out = <<<EOF\n<?xml version=\"1.0\" encoding=\"utf-8\"?>\n<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<resources>\n    <string-array name=\"tracker_signatures\">\n\nEOF;\n\n    foreach($tracker_info as $info) {\n        foreach($info[\"code_sigs\"] as $sig) {\n            $out .= \"        <item>$sig</item>\\n\";\n        }\n    }\n\n    $out .= <<<EOF\n    </string-array>\n    <string-array name=\"tracker_names\">\n\nEOF;\n\n    foreach($tracker_info as $tracker => $info) {\n        foreach($info[\"code_sigs\"] as $ignored) {\n            $out .= \"        <item>$tracker</item>\\n\";\n        }\n    }\n\n    $out .= <<<EOF\n    </string-array>\n</resources>\nEOF;\n    file_put_contents(TRACKERS_XML, $out);\n}\n\n\n/**\n * @param string $libs_file\n * @return AndroidLibV1[]\n */\nfunction parse_libs_file(string $libs_file): array {\n    $libs = json_decode(file_get_contents($libs_file), true);\n\n    $parsed_lib = array();\n    foreach ($libs as $lib) {\n        $parsed_lib[] = AndroidLibV1::fromJson($lib);\n    }\n    return $parsed_lib;\n}\n"
  },
  {
    "path": "scripts/utils.php",
    "content": "<?php\n/* SPDX-License-Identifier: GPL-3.0-or-later */\n\nuse JetBrains\\PhpStorm\\NoReturn;\n\nfunction list_files(string $dir): array {\n    return array_diff(scandir($dir), array('..', '.'));\n}\n\nfunction list_files_recursive(string $dir) : array {\n    if ($dir[strlen($dir) - 1] != '/') $dir = $dir . '/';\n    $iterator = new RecursiveIteratorIterator(new RecursiveDirectoryIterator($dir));\n    $paths = array();\n    foreach ($iterator as $file) {\n        // Ignore .. and .\n        $pathname = $file->getPathname();\n        $last_segment = substr($pathname, strrpos($pathname, '/') + 1);\n        if ($last_segment == '..') continue;\n        $relative_path = str_replace($dir, '', $pathname);\n        if ($relative_path == '.') continue; // Ignore this directory\n        if ($last_segment == '.') $relative_path = substr($relative_path, 0, strlen($relative_path) - 1);\n        $paths[] = $relative_path;\n    }\n    return $paths;\n}\n\n// https://developer.android.com/guide/topics/resources/string-resource.html#FormattingAndStyling\nfunction android_escape(string $string): string {\n    return strtr($string, array('@' => '\\@', '?' => '\\?', '<' => '&lt;', '>' => '&gt;', '\"' => '\\\"', \"'\" => \"\\'\", '&' => '&amp;'));\n}\n\nfunction android_escape_slash(string $string) : string {\n    return strtr($string, array('@' => '\\@', '?' => '\\?', '<' => '&lt;', '>' => '&gt;', '\"' => '\\\"', \"'\" => \"\\'\", '&' => '&amp;', '\\\\' => '\\\\\\\\'));\n}\n\nfunction android_escape_slash_newline(string $string) : string {\n    return strtr($string, array('@' => '\\@', '?' => '\\?', '<' => '&lt;', '>' => '&gt;', '\"' => '\\\"', \"'\" => \"\\'\", '&' => '&amp;', '\\\\' => '\\\\\\\\', \"\\n\" => '\\n'));\n}\n\nfunction android_escape_slash_newline_reverse(string $string) : string {\n    return strtr($string, array('\\@' => '@', '\\?' => '?', '&lt;' => '<', '&gt;' => '>', '\\\"' => '\"', \"\\'\" => \"'\", '&amp;' => '&', '\\\\\\\\' => '\\\\', '\\n' => \"\\n\"));\n}\n\n#[NoReturn]\nfunction syntax_error_with_position(string $path, string $texts, int $position, string $error_message = \"Syntax error\"): void {\n    $lines = explode(\"\\n\", $texts);\n    $line_no = 0;\n    foreach ($lines as $line) {\n        ++$line_no;\n        $len = strlen($line);\n        if ($len > $position) {\n            break;\n        }\n        $position -= ($len + 1);\n    }\n    fprintf(STDERR, \"\\e[41;1mError:\\e[0m %s near $path:$line_no:%d \\n\", $error_message, abs($position));\n    exit(1);\n}"
  },
  {
    "path": "server/.gitignore",
    "content": "/build\n/checksum.txt"
  },
  {
    "path": "server/build.gradle",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\n\nimport javax.inject.Inject\nimport java.nio.file.Files\nimport java.nio.file.Paths\nimport java.util.stream.Collectors\n\nplugins {\n    id('com.android.library')\n}\n\nandroid {\n    namespace 'io.github.muntashirakon.AppManager.server'\n    compileSdk compile_sdk\n    buildToolsVersion = build_tools\n\n    defaultConfig {\n        minSdk min_sdk\n        targetSdk target_sdk\n    }\n\n    compileOptions {\n        encoding \"UTF-8\"\n        sourceCompatibility JavaVersion.VERSION_1_8\n        targetCompatibility JavaVersion.VERSION_1_8\n    }\n}\n\ndependencies {\n    compileOnly project(path: ':hiddenapi')\n\n    api project(path: ':libserver')\n\n    implementation \"androidx.annotation:annotation:${annotation_version}\"\n}\n\n// https://docs.gradle.org/current/userguide/service_injection.html#execoperations\ninterface InjectedExecOps {\n    @Inject\n    ExecOperations getExecOps()\n}\n\nandroid.libraryVariants.configureEach { variant ->\n    String buildType = variant.buildType.name\n    def injected = project.objects.newInstance(InjectedExecOps)\n    def jarTask = tasks.register(\"create${buildType.capitalize()}ServerJars\") {\n        doLast {\n            println(\"Build type: ${buildType}\")\n\n            String rootDir = project.rootDir.absolutePath\n            String serverPkg = \"io/github/muntashirakon/AppManager/server\"\n            String intermediatePath = \"build/intermediates/javac/${buildType}/compile${buildType.capitalize()}JavaWithJavac/classes\"\n            String serverClassDir = \"${rootDir}/server/${intermediatePath}/${serverPkg}/\"\n            String libserverClassDir = \"${rootDir}/libserver/${intermediatePath}/${serverPkg}/common\"\n            String androidJar = \"${android.sdkDirectory.path}/platforms/android-${target_sdk}/android.jar\"\n            String amJar = \"${rootDir}/app/src/main/assets/am.jar\"\n            String mainJar = \"${rootDir}/app/src/main/assets/main.jar\"\n\n            println(\"Creating am.jar...\")\n            def buildArgs = ['--release', '--output', amJar, '--classpath', androidJar]\n            buildArgs.addAll(Files.list(Paths.get(libserverClassDir)).filter {\n                !it.fileName.toString().startsWith(\"IRootServiceManager\")\n            }.map { it.toString() }.collect(Collectors.toList()))\n            buildArgs.addAll(Files.list(Paths.get(serverClassDir)).filter {\n                !it.fileName.toString().startsWith(\"RootServiceMain\")\n            }.map { it.toString() }.collect(Collectors.toList()))\n            injected.execOps.exec {\n                workingDir = project.rootDir\n                executable = file(\"${android.sdkDirectory.path}/build-tools/${android.buildToolsVersion}/d8\")\n                args = buildArgs\n            }\n            println(\"Created ${amJar}\")\n\n            println(\"Creating main.jar...\")\n            buildArgs = ['--release', '--output', mainJar, '--classpath', androidJar]\n            buildArgs.addAll(Files.list(Paths.get(libserverClassDir)).filter {\n                it.fileName.toString().startsWith(\"IRootServiceManager\") || it.fileName.toString().startsWith(\"ServerUtils\")\n            }.map { it.toString() }.collect(Collectors.toList()))\n            buildArgs.addAll(Files.list(Paths.get(serverClassDir)).filter {\n                it.fileName.toString().startsWith(\"RootServiceMain\")\n            }.map { it.toString() }.collect(Collectors.toList()))\n            injected.execOps.exec {\n                workingDir = project.rootDir\n                executable = file(\"${android.sdkDirectory.path}/build-tools/${android.buildToolsVersion}/d8\")\n                args = buildArgs\n            }\n            println(\"Created ${mainJar}\")\n        }\n    }\n    javaCompileProvider.get().finalizedBy(jarTask)\n}\n\ntasks.register('cleanupServerJars') {\n    doLast {\n        file(\"${rootProject.projectDir.absolutePath}/app/src/main/assets/am.jar\").delete()\n        file(\"${rootProject.projectDir.absolutePath}/app/src/main/assets/main.jar\").delete()\n    }\n}\n\nclean.dependsOn cleanupServerJars\n"
  },
  {
    "path": "server/src/main/AndroidManifest.xml",
    "content": "<!-- SPDX-License-Identifier: GPL-3.0-or-later -->\n<manifest />\n"
  },
  {
    "path": "server/src/main/java/io/github/muntashirakon/AppManager/server/BroadcastSender.java",
    "content": "// SPDX-License-Identifier: MIT AND GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.server;\n\nimport android.app.Application;\nimport android.content.Intent;\n\nimport io.github.muntashirakon.AppManager.server.common.FLog;\n\n// Copyright 2017 Zheng Li\nclass BroadcastSender {\n    static void sendBroadcast(Intent intent) {\n        try {\n            Application app = (Application) Class.forName(\"android.app.ActivityThread\")\n                    .getMethod(\"currentApplication\")\n                    .invoke(null);\n            if (app == null) {\n                FLog.log(\"BroadcastSender: NullPointerException \" + intent.toString());\n                return;\n            }\n            app.sendBroadcast(intent);\n        } catch (Exception e) {\n            e.printStackTrace();\n            FLog.log(e);\n        }\n    }\n}\n"
  },
  {
    "path": "server/src/main/java/io/github/muntashirakon/AppManager/server/LifecycleAgent.java",
    "content": "// SPDX-License-Identifier: MIT AND GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.server;\n\nimport android.content.Intent;\n\nimport androidx.annotation.NonNull;\n\nimport io.github.muntashirakon.AppManager.server.common.ConfigParams;\nimport io.github.muntashirakon.AppManager.server.common.ServerActions;\nimport io.github.muntashirakon.AppManager.server.common.ServerInfo;\n\nimport static io.github.muntashirakon.AppManager.server.common.ConfigParams.PARAM_TOKEN;\nimport static io.github.muntashirakon.AppManager.server.common.ConfigParams.PARAM_UID;\n\n// Copyright 2017 Zheng Li\nfinal class LifecycleAgent {\n    static final ServerInfo sServerInfo = new ServerInfo();\n\n    @NonNull\n    private final ConfigParams mConfigParams;\n\n    public LifecycleAgent(@NonNull ConfigParams configParams) {\n        mConfigParams = configParams;\n    }\n\n    @NonNull\n    public ConfigParams getConfigParams() {\n        return mConfigParams;\n    }\n\n    void onStarted() {\n        BroadcastSender.sendBroadcast(makeIntent(ServerActions.ACTION_SERVER_STARTED));\n    }\n\n    void onConnected() {\n        BroadcastSender.sendBroadcast(makeIntent(ServerActions.ACTION_SERVER_CONNECTED));\n    }\n\n    void onDisconnected() {\n        BroadcastSender.sendBroadcast(makeIntent(ServerActions.ACTION_SERVER_DISCONNECTED));\n    }\n\n    void onStopped() {\n        BroadcastSender.sendBroadcast(makeIntent(ServerActions.ACTION_SERVER_STOPPED));\n    }\n\n    @NonNull\n    private Intent makeIntent(String action) {\n        return new Intent(action)\n                .setClassName(mConfigParams.getAppName(), ServerActions.PACKAGE_NAME + \".servermanager.ServerStatusChangeReceiver\")\n                .putExtra(PARAM_TOKEN, mConfigParams.getToken())\n                .putExtra(PARAM_UID, mConfigParams.getUid());\n    }\n}\n"
  },
  {
    "path": "server/src/main/java/io/github/muntashirakon/AppManager/server/RootServiceMain.java",
    "content": "// SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.server;\n\nimport android.annotation.SuppressLint;\nimport android.content.ComponentName;\nimport android.content.Context;\nimport android.content.ContextWrapper;\nimport android.content.pm.PackageManager;\nimport android.content.res.Resources;\nimport android.os.IBinder;\nimport android.os.Looper;\nimport android.os.Process;\nimport android.os.RemoteException;\nimport android.os.UserHandle;\nimport android.util.Log;\n\nimport java.io.IOException;\nimport java.lang.reflect.Constructor;\nimport java.lang.reflect.Field;\nimport java.lang.reflect.Method;\nimport java.util.concurrent.Callable;\n\nimport io.github.muntashirakon.AppManager.server.common.IRootServiceManager;\n\nimport static io.github.muntashirakon.AppManager.server.common.ServerUtils.CMDLINE_START_DAEMON;\nimport static io.github.muntashirakon.AppManager.server.common.ServerUtils.CMDLINE_START_SERVICE;\nimport static io.github.muntashirakon.AppManager.server.common.ServerUtils.CMDLINE_STOP_SERVICE;\nimport static io.github.muntashirakon.AppManager.server.common.ServerUtils.getServiceName;\n\n/**\n * Trampoline to start a root service.\n * <p>\n * This is the only class included in main.jar as raw resources.\n * The client code will execute this main method in a root shell.\n * <p>\n * This class will get the system context by calling into Android private APIs with reflection, and\n * uses that to create our client package context. The client context will have the full APK loaded,\n * just like it was launched in a non-root environment.\n * <p>\n * Expected command-line args:\n * args[0]: client service component name\n * args[1]: client UID\n * args[2]: CMDLINE_START_SERVICE, CMDLINE_START_DAEMON, or CMDLINE_STOP_SERVICE\n * <p>\n * <b>Note:</b> This class is hardcoded in {@code IPCClient#IPCMAIN_CLASSNAME}. Don't change the class name or package\n * path without changing them there.\n */\n// Copyright 2020 John \"topjohnwu\" Wu\npublic class RootServiceMain extends ContextWrapper implements Callable<Object[]> {\n    private static final Method getService;\n    private static final Method attachBaseContext;\n\n    static {\n        try {\n            @SuppressLint(\"PrivateApi\")\n            Class<?> sm = Class.forName(\"android.os.ServiceManager\");\n            getService = sm.getDeclaredMethod(\"getService\", String.class);\n            attachBaseContext = ContextWrapper.class.getDeclaredMethod(\"attachBaseContext\", Context.class);\n            attachBaseContext.setAccessible(true);\n        } catch (Exception e) {\n            // Shall not happen!\n            throw new RuntimeException(e);\n        }\n    }\n\n    @SuppressLint(\"PrivateApi\")\n    private static Context getSystemContext() {\n        try {\n            Class<?> atClazz = Class.forName(\"android.app.ActivityThread\");\n            Method systemMain = atClazz.getMethod(\"systemMain\");\n            Object activityThread = systemMain.invoke(null);\n            Method getSystemContext = atClazz.getMethod(\"getSystemContext\");\n            return (Context) getSystemContext.invoke(activityThread);\n        } catch (Exception e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    @SuppressWarnings({\"DataFlowIssue\", \"JavaReflectionMemberAccess\"})\n    private static Context createPackageContextAsUser(String packageName, int userId, int flags)\n            throws PackageManager.NameNotFoundException {\n        Context systemContext = getSystemContext();\n        try {\n            UserHandle userHandle;\n            try {\n                userHandle = (UserHandle) UserHandle.class\n                        .getDeclaredMethod(\"of\", int.class).invoke(null, userId);\n            } catch (NoSuchMethodException e) {\n                userHandle = UserHandle.class\n                        .getDeclaredConstructor(int.class).newInstance(userId);\n            }\n            return (Context) systemContext.getClass()\n                    .getDeclaredMethod(\"createPackageContextAsUser\",\n                            String.class, int.class, UserHandle.class)\n                    .invoke(systemContext, packageName, flags, userHandle);\n        } catch (Throwable e) {\n            Log.w(\"IPC\", \"Failed to create package context as user: \" + userId, e);\n            return systemContext.createPackageContext(packageName, flags);\n        }\n    }\n\n    private static boolean allowBinderCommunication() {\n        try {\n            Class<?> SELinuxClass = Class.forName(\"android.os.SELinux\");\n            Method getContext = SELinuxClass.getMethod(\"getContext\");\n            String context = (String) getContext.invoke(null);\n            Method checkSELinuxAccess = SELinuxClass.getMethod(\"checkSELinuxAccess\", String.class, String.class, String.class, String.class);\n            return Boolean.TRUE.equals(checkSELinuxAccess.invoke(null, \"u:r:untrusted_app:s0\", context, \"binder\", \"call\"))\n                    && Boolean.TRUE.equals(checkSELinuxAccess.invoke(null, \"u:r:untrusted_app:s0\", context, \"binder\", \"transfer\"));\n        } catch (Exception e) {\n            throw new RuntimeException(e);\n        }\n    }\n\n    public static void main(String[] args) {\n        // Close STDOUT/STDERR since it belongs to the parent shell\n        System.out.close();\n        System.err.close();\n        if (args.length < 3) {\n            System.exit(1);\n        }\n\n        Looper.prepareMainLooper();\n\n        try {\n            new RootServiceMain(args);\n        } catch (Throwable e) {\n            Log.e(\"IPC\", \"Error in IPCMain\", e);\n            System.exit(1);\n        }\n\n        // Main thread event loop\n        Looper.loop();\n        System.exit(1);\n    }\n\n    private final int uid;\n    private final boolean isDaemon;\n\n    @Override\n    public Object[] call() {\n        Object[] objs = new Object[2];\n        objs[0] = uid;\n        objs[1] = isDaemon;\n        return objs;\n    }\n\n    @SuppressLint(\"DiscouragedPrivateApi\")\n    public RootServiceMain(String[] args) throws Exception {\n        super(null);\n\n        if (Process.myUid() == 0 && !allowBinderCommunication()) {\n            throw new IOException(\"Current su does not allow Binder communication.\");\n        }\n\n        ComponentName name = ComponentName.unflattenFromString(args[0]);\n        uid = Integer.parseInt(args[1]);\n        String action = args[2];\n        boolean stop = false;\n\n        switch (action) {\n            case CMDLINE_STOP_SERVICE:\n                stop = true;\n                // fallthrough\n            case CMDLINE_START_DAEMON:\n                isDaemon = true;\n                break;\n            case CMDLINE_START_SERVICE:\n                isDaemon = false;\n                break;\n            default:\n                throw new IllegalArgumentException(\"Unknown action: \" + action);\n        }\n\n        if (isDaemon) daemon: try {\n            // Get existing daemon process\n            Object binder = getService.invoke(null, getServiceName(name.getPackageName()));\n            IRootServiceManager m = IRootServiceManager.Stub.asInterface((IBinder) binder);\n            if (m == null)\n                break daemon;\n\n            if (stop) {\n                m.stop(name, uid);\n            } else {\n                m.broadcast(uid);\n                // Terminate process if broadcast went through without exception\n                System.exit(0);\n            }\n        } catch (RemoteException ignored) {\n        } finally {\n            if (stop)\n                System.exit(0);\n        }\n\n        // Calling createPackageContext crashes on LG ROM\n        // Override the system resources object to prevent crashing\n        try {\n            // This class only exists on LG ROMs with broken implementations\n            Class.forName(\"com.lge.systemservice.core.integrity.IntegrityManager\");\n            // If control flow goes here, we need the resource hack\n            Resources systemRes = Resources.getSystem();\n            Resources wrapper = new ResourcesWrapper(systemRes);\n            Field systemResField = Resources.class.getDeclaredField(\"mSystem\");\n            systemResField.setAccessible(true);\n            systemResField.set(null, wrapper);\n        } catch (ReflectiveOperationException ignored) {}\n        int userId = uid / 100_000;\n        int flags = Context.CONTEXT_INCLUDE_CODE | Context.CONTEXT_IGNORE_SECURITY;\n        Context context = createPackageContextAsUser(name.getPackageName(), userId, flags);\n        attachBaseContext(context);\n\n        // Use classloader from the package context to run everything\n        ClassLoader cl = context.getClassLoader();\n\n        Class<?> clz = cl.loadClass(name.getClassName());\n        Constructor<?> ctor = clz.getDeclaredConstructor();\n        ctor.setAccessible(true);\n        attachBaseContext.invoke(ctor.newInstance(), this);\n    }\n\n    private static class ResourcesWrapper extends Resources {\n        @SuppressWarnings({\"JavaReflectionMemberAccess\", \"deprecation\"})\n        @SuppressLint(\"DiscouragedPrivateApi\")\n        public ResourcesWrapper(Resources res) throws ReflectiveOperationException {\n            super(res.getAssets(), res.getDisplayMetrics(), res.getConfiguration());\n            Method getImpl = Resources.class.getDeclaredMethod(\"getImpl\");\n            getImpl.setAccessible(true);\n            Method setImpl = Resources.class.getDeclaredMethod(\"setImpl\", getImpl.getReturnType());\n            setImpl.setAccessible(true);\n            Object impl = getImpl.invoke(res);\n            setImpl.invoke(this, impl);\n        }\n\n        @Override\n        public boolean getBoolean(int id) {\n            try {\n                return super.getBoolean(id);\n            } catch (NotFoundException e) {\n                return false;\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "server/src/main/java/io/github/muntashirakon/AppManager/server/Server.java",
    "content": "// SPDX-License-Identifier: MIT AND GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.server;\n\nimport android.net.LocalServerSocket;\nimport android.net.LocalSocket;\n\nimport androidx.annotation.NonNull;\nimport androidx.annotation.Nullable;\n\nimport java.io.Closeable;\nimport java.io.IOException;\nimport java.io.InputStream;\nimport java.io.OutputStream;\nimport java.net.ServerSocket;\nimport java.net.Socket;\n\nimport io.github.muntashirakon.AppManager.server.common.DataTransmission;\nimport io.github.muntashirakon.AppManager.server.common.FLog;\n\n// Copyright 2017 Zheng Li\nclass Server implements Closeable {\n    @NonNull\n    private final LifecycleAgent mLifecycleAgent;\n    @NonNull\n    private final IServer mServer;\n    @NonNull\n    private final String mToken;\n    @Nullable\n    private final DataTransmission.OnReceiveCallback mOnReceiveCallback;\n\n    private DataTransmission mDataTransmission;\n    private boolean mRunning = true;\n    boolean mRunInBackground = false;\n\n    /**\n     * Constructor for starting a local server\n     *\n     * @param name              Socket address\n     * @param token             Token for handshaking\n     * @param onReceiveCallback Callback for sending message (received by the calling class)\n     * @throws IOException On failing to create a socket connection\n     */\n    Server(String name, @NonNull String token, @NonNull LifecycleAgent lifecycleAgent,\n           @Nullable DataTransmission.OnReceiveCallback onReceiveCallback)\n            throws IOException {\n        mToken = token;\n        mLifecycleAgent = lifecycleAgent;\n        mServer = new LocalServerImpl(name);\n        mOnReceiveCallback = onReceiveCallback;\n    }\n\n    /**\n     * Constructor for starting a local server\n     *\n     * @param port              Port number\n     * @param token             Token for handshaking\n     * @param onReceiveCallback Callback for sending message (received by the calling class)\n     * @throws IOException On failing to create a socket connection\n     */\n    Server(int port, @NonNull String token, @NonNull LifecycleAgent lifecycleAgent,\n           @Nullable DataTransmission.OnReceiveCallback onReceiveCallback)\n            throws IOException {\n        mToken = token;\n        mLifecycleAgent = lifecycleAgent;\n        mServer = new NetSocketServerImpl(port);\n        mOnReceiveCallback = onReceiveCallback;\n    }\n\n    /**\n     * Run the server\n     *\n     * @throws IOException When server has failed to shake hands or the connection cannot be made\n     */\n    void run() throws IOException, RuntimeException {\n        while (mRunning) {\n            try {\n                // Allow only one client\n                mServer.accept();\n                // Prepare input and output streams for data interchange\n                mDataTransmission = new DataTransmission(mServer.getOutputStream(), mServer.getInputStream(),\n                        mOnReceiveCallback);\n                // Handshake: check if tokens matched\n                mDataTransmission.shakeHands(mToken, DataTransmission.Role.Server);\n                // Send broadcast message to the system that the server has connected\n                mLifecycleAgent.onConnected();\n                // Handle the data received initially from the client\n                mDataTransmission.handleReceive();\n            } catch (DataTransmission.ProtocolVersionException e) {\n                FLog.log(e);\n                throw e;\n            } catch (IOException e) {\n                FLog.log(e);\n                FLog.log(\"Run in background: \" + mRunInBackground);\n                // Send broadcast message to the system that the server has disconnected\n                mLifecycleAgent.onDisconnected();\n                // Throw exception only when run in background is not requested\n                if (!mRunInBackground) {\n                    mRunning = false;\n                    throw e;\n                }\n            } catch (RuntimeException e) {\n                FLog.log(e);\n                // Send broadcast message to the system that the server has disconnected\n                mLifecycleAgent.onDisconnected();\n                // Re-throw the exception\n                mRunInBackground = false;\n                mRunning = false;\n                throw e;\n            }\n        }\n    }\n\n    public void sendResult(byte[] bytes) throws IOException {\n        if (mRunning && mDataTransmission != null) {\n            LifecycleAgent.sServerInfo.txBytes += bytes.length;\n            mDataTransmission.sendMessage(bytes);\n        }\n    }\n\n    @Override\n    public void close() throws IOException {\n        mRunning = false;\n        if (mDataTransmission != null) {\n            mDataTransmission.close();\n        }\n        mServer.close();\n    }\n\n    private interface IServer extends Closeable {\n        InputStream getInputStream() throws IOException;\n\n        OutputStream getOutputStream() throws IOException;\n\n        void accept() throws IOException;\n\n        @Override\n        void close() throws IOException;\n    }\n\n    private static class LocalServerImpl implements IServer {\n        private final LocalServerSocket mServerSocket;\n        private LocalSocket mLocalSocket;\n\n        public LocalServerImpl(String name) throws IOException {\n            mServerSocket = new LocalServerSocket(name);\n        }\n\n        @Override\n        public InputStream getInputStream() throws IOException {\n            return mLocalSocket.getInputStream();\n        }\n\n        @Override\n        public OutputStream getOutputStream() throws IOException {\n            return mLocalSocket.getOutputStream();\n        }\n\n        @Override\n        public void accept() throws IOException {\n            mLocalSocket = mServerSocket.accept();\n        }\n\n        @Override\n        public void close() throws IOException {\n            mLocalSocket.close();\n            mServerSocket.close();\n        }\n    }\n\n    private static class NetSocketServerImpl implements IServer {\n        private final ServerSocket mServerSocket;\n        private Socket mSocket;\n\n        public NetSocketServerImpl(int port) throws IOException {\n            mServerSocket = new ServerSocket(port);\n        }\n\n        @Override\n        public InputStream getInputStream() throws IOException {\n            return mSocket.getInputStream();\n        }\n\n        @Override\n        public OutputStream getOutputStream() throws IOException {\n            return mSocket.getOutputStream();\n        }\n\n        @Override\n        public void accept() throws IOException {\n            mSocket = mServerSocket.accept();\n        }\n\n        @Override\n        public void close() throws IOException {\n            mSocket.close();\n            mServerSocket.close();\n        }\n    }\n}\n"
  },
  {
    "path": "server/src/main/java/io/github/muntashirakon/AppManager/server/ServerHandler.java",
    "content": "// SPDX-License-Identifier: MIT AND GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.server;\n\nimport android.os.Handler;\nimport android.os.HandlerThread;\nimport android.os.Message;\nimport android.os.Parcel;\nimport android.os.Parcelable;\n\nimport androidx.annotation.NonNull;\n\nimport java.io.Closeable;\nimport java.io.IOException;\n\nimport io.github.muntashirakon.AppManager.server.common.BaseCaller;\nimport io.github.muntashirakon.AppManager.server.common.CallerResult;\nimport io.github.muntashirakon.AppManager.server.common.ConfigParams;\nimport io.github.muntashirakon.AppManager.server.common.DataTransmission;\nimport io.github.muntashirakon.AppManager.server.common.FLog;\nimport io.github.muntashirakon.AppManager.server.common.ParcelableUtil;\nimport io.github.muntashirakon.AppManager.server.common.Shell;\nimport io.github.muntashirakon.AppManager.server.common.ShellCaller;\n\n// Copyright 2017 Zheng Li\nclass ServerHandler implements DataTransmission.OnReceiveCallback, Closeable {\n    private static final int MSG_TIMEOUT = 1;\n    private static final int DEFAULT_TIMEOUT = 1000 * 60; // 1 min\n    private static final int BG_TIMEOUT = DEFAULT_TIMEOUT * 10; // 10 min\n\n    private final LifecycleAgent mLifecycleAgent;\n    private final ConfigParams mConfigParams;\n    private final Server mServer;\n    private final boolean mRunInBackground;\n\n    private Handler mHandler;\n    private volatile boolean mIsDead = false;\n\n    ServerHandler(@NonNull LifecycleAgent lifecycleAgent) throws IOException {\n        mLifecycleAgent = lifecycleAgent;\n        mConfigParams = mLifecycleAgent.getConfigParams();\n        // Set params\n        System.out.println(\"Config params: \" + mConfigParams);\n        String path = mConfigParams.getPath();\n        int port = -1;\n        try {\n            if (path != null) port = Integer.parseInt(path);\n        } catch (Exception ignore) {\n        }\n        String token = mConfigParams.getToken();\n        if (token == null) throw new IOException(\"Token is not found.\");\n        mRunInBackground = mConfigParams.isRunInBackground();\n        // Set server\n        if (port == -1) {\n            mServer = new Server(path, token, mLifecycleAgent, this);\n        } else {\n            mServer = new Server(port, token, mLifecycleAgent, this);\n        }\n        mServer.mRunInBackground = mRunInBackground;\n        // If run in background not requested, stop server on timeout\n        if (!mRunInBackground) {\n            HandlerThread handlerThread = new HandlerThread(\"am_server_watcher\");\n            handlerThread.start();\n            mHandler = new Handler(handlerThread.getLooper()) {\n                @Override\n                public void handleMessage(@NonNull Message message) {\n                    super.handleMessage(message);\n                    if (message.what == MSG_TIMEOUT) {\n                        close();\n                    }\n                }\n            };\n            mHandler.sendEmptyMessageDelayed(MSG_TIMEOUT, DEFAULT_TIMEOUT);\n        }\n    }\n\n    void start() throws IOException, RuntimeException {\n        mServer.run();\n    }\n\n    @Override\n    public void close() {\n        FLog.log(\"ServerHandler: Destroying...\");\n        try {\n            if (!mRunInBackground && mHandler != null) {\n                mHandler.removeCallbacksAndMessages(null);\n                mHandler.removeMessages(MSG_TIMEOUT);\n                mHandler.getLooper().quit();\n            }\n        } catch (Exception e) {\n            e.printStackTrace();\n            FLog.log(e);\n        }\n        try {\n            mIsDead = true;\n            mServer.close();\n        } catch (Exception e) {\n            e.printStackTrace();\n            FLog.log(e);\n        }\n    }\n\n    private void sendOpResult(Parcelable result) {\n        try {\n            mServer.sendResult(ParcelableUtil.marshall(result));\n        } catch (IOException e) {\n            e.printStackTrace();\n        }\n    }\n\n    @Override\n    public void onMessage(@NonNull byte[] bytes) {\n        if (mHandler != null) {\n            mHandler.removeCallbacksAndMessages(null);\n            mHandler.removeMessages(MSG_TIMEOUT);\n        }\n\n        if (!mIsDead) {\n            if (!mRunInBackground && mHandler != null) {\n                mHandler.sendEmptyMessageDelayed(MSG_TIMEOUT, BG_TIMEOUT);\n            }\n            LifecycleAgent.sServerInfo.rxBytes += bytes.length;\n            CallerResult result = null;\n            try {\n                BaseCaller baseCaller = ParcelableUtil.unmarshall(bytes, BaseCaller.CREATOR);\n                int type = baseCaller.getType();\n                switch (type) {\n                    case BaseCaller.TYPE_CLOSE:\n                        close();\n                        return;\n                    case BaseCaller.TYPE_SHELL:\n                        ShellCaller shellCaller = ParcelableUtil.unmarshall(baseCaller.getRawBytes(), ShellCaller.CREATOR);\n                        Shell shell = Shell.getShell(\"\");\n                        Shell.Result shellResult = shell.exec(shellCaller.getCommand());\n                        result = new CallerResult();\n                        Parcel parcel = Parcel.obtain();\n                        try {\n                            parcel.writeValue(shellResult);\n                            result.setReply(parcel.marshall());\n                        } finally {\n                            parcel.recycle();\n                        }\n                }\n                LifecycleAgent.sServerInfo.successCount++;\n            } catch (Throwable e) {\n                FLog.log(e);\n                result = new CallerResult();\n                result.setThrowable(e);\n                LifecycleAgent.sServerInfo.errorCount++;\n            } finally {\n                if (result == null) {\n                    result = new CallerResult();\n                }\n                sendOpResult(result);\n            }\n        }\n    }\n}\n"
  },
  {
    "path": "server/src/main/java/io/github/muntashirakon/AppManager/server/ServerRunner.java",
    "content": "// SPDX-License-Identifier: MIT AND GPL-3.0-or-later\n\npackage io.github.muntashirakon.AppManager.server;\n\nimport android.os.Looper;\nimport android.os.Process;\nimport android.os.SystemClock;\nimport android.system.Os;\n\nimport androidx.annotation.NonNull;\n\nimport java.io.File;\nimport java.io.FileInputStream;\nimport java.io.IOException;\nimport java.util.Arrays;\n\nimport io.github.muntashirakon.AppManager.server.common.ConfigParams;\nimport io.github.muntashirakon.AppManager.server.common.Constants;\nimport io.github.muntashirakon.AppManager.server.common.FLog;\n\nimport static io.github.muntashirakon.AppManager.server.common.ConfigParams.PARAM_UID;\n\n/**\n * ServerRunner runs the server based on the parameters given. It takes two arguments:\n * <ol>\n *     <li>\n *         <b>Parameters.</b> Each parameter is a key-value pair separated by a comma and key-values\n *         are separated by a colon. See {@link ConfigParams} to see a list of parameters.\n *     </li>\n *     <li>\n *         <b>Process ID.</b> The old process ID that has to be killed. This is an optional argument\n *     </li>\n * </ol>\n */\n// Copyright 2017 Zheng Li\npublic final class ServerRunner {\n    /**\n     * The main method\n     *\n     * @param args See {@link ServerRunner}\n     */\n    public static void main(String[] args) {\n        try {\n            FLog.writeLog = true;\n            FLog.log(\"Arguments: \" + Arrays.toString(args));\n            if (args == null || args.length == 0) {\n                return;\n            }\n            // Get arguments\n            String paramsStr = args[0];\n            int oldPid = -1;\n            if (args.length > 1) {\n                try {\n                    oldPid = Integer.parseInt(args[1]);\n                } catch (Exception ignore) {\n                }\n            }\n            // Make it main looper\n            //noinspection deprecation\n            Looper.prepareMainLooper();\n            Class.forName(\"android.app.ActivityThread\")\n                    .getMethod(\"systemMain\")\n                    .invoke(null);\n            // Parse arguments\n            String[] split = paramsStr.split(\",\");\n            final ConfigParams configParams = new ConfigParams();\n            for (String s : split) {\n                String[] param = s.split(\":\");\n                configParams.put(param[0], param[1]);\n            }\n            configParams.put(PARAM_UID, \"\" + Process.myUid());\n            // Set server info\n            LifecycleAgent.sServerInfo.startArgs = paramsStr;\n            LifecycleAgent.sServerInfo.startTime = System.currentTimeMillis();\n            LifecycleAgent.sServerInfo.startRealTime = SystemClock.elapsedRealtime();\n            // Print debug\n            System.out.println(\"UID: \" + configParams.getUid() + \", UID: \" + Process.myUid());\n            System.out.println(\"Params: \" + configParams);\n            // Kill old server if requested\n            if (oldPid != -1) {\n                killOldServer(oldPid);\n                SystemClock.sleep(1000);\n            }\n            // Start server\n            Thread thread = new Thread(() -> {\n                new ServerRunner().runServer(configParams);\n                // Exit current thread, regardless of whether the server started or not\n                FLog.close();\n                killSelfProcess();\n            });\n            thread.setName(\"AM-IPC\");\n            thread.start();\n            Looper.loop();\n        } catch (Throwable e) {\n            e.printStackTrace();\n            FLog.log(e);\n        } finally {\n            // Exit current process, regardless of whether the server started or not\n            FLog.log(\"Log closed.\");\n            FLog.close();\n            killSelfProcess();\n        }\n    }\n\n    /**\n     * Kill old server by process ID, process name is verified before killed.\n     *\n     * @param oldPid Process ID of the old server\n     */\n    private static void killOldServer(int oldPid) {\n        try {\n            String processName = getProcessName(oldPid);\n            if (Constants.SERVER_NAME.equals(processName)) {\n                Process.killProcess(oldPid);\n                FLog.log(\"Killed old server with pid \" + oldPid);\n            }\n        } catch (Throwable throwable) {\n            FLog.log(throwable);\n        }\n    }\n\n    /**\n     * Kill current process\n     */\n    private static void killSelfProcess() {\n        int pid = Process.myPid();\n        System.out.println(\"Killing self process with pid \" + pid);\n        killProcess(pid);\n    }\n\n    /**\n     * Kill a process by process ID\n     *\n     * @param pid Process ID to be killed\n     */\n    private static void killProcess(int pid) {\n        try {\n            Process.killProcess(pid);\n        } catch (Throwable e) {\n            e.printStackTrace();\n        } finally {\n            try {\n                // Kill using SIGNAL 9\n                Os.execve(\"/system/bin/kill\", new String[]{\"-9\", String.valueOf(pid)}, null);\n            } catch (Throwable e) {\n                e.printStackTrace();\n            }\n        }\n    }\n\n    /**\n     * Get the process name from process ID\n     *\n     * @param pid Process ID\n     * @return Process name or empty string\n     */\n    @NonNull\n    private static String getProcessName(int pid) {\n        File cmdLine = new File(\"/proc/\" + pid + \"/cmdline\");\n        if (!cmdLine.exists()) return \"\";\n        try (FileInputStream fis = new FileInputStream(cmdLine)) {\n            byte[] buff = new byte[512];\n            int len = fis.read(buff);\n            if (len > 0) {\n                int i;\n                for (i = 0; i < len; i++) {\n                    if (buff[i] == '\\0') {\n                        break;\n                    }\n                }\n                return new String(buff, 0, i);\n            }\n        } catch (Exception e) {\n            e.printStackTrace();\n        }\n        return \"\";\n    }\n\n    private ServerRunner() {\n    }\n\n    /**\n     * Run the local server. The server is actually run by {@link ServerHandler}.\n     *\n     * @param configParams The parameters to be used during and after the server starts.\n     */\n    private void runServer(@NonNull ConfigParams configParams) {\n        LifecycleAgent lifecycleAgent = new LifecycleAgent(configParams);\n        try (ServerHandler serverHandler = new ServerHandler(lifecycleAgent)) {\n            System.out.println(\"Success! Server has started.\");\n            int pid = Process.myPid();\n            System.out.println(\"Process: \" + getProcessName(pid) + \", PID: \" + pid);\n            // Send broadcast message to the system that the server has started\n            lifecycleAgent.onStarted();\n            // Start server\n            serverHandler.start();\n        } catch (IOException | RuntimeException e) {\n            System.out.println(\"Error! Could not start server. \" + e.getMessage());\n            FLog.log(e);\n        } finally {\n            // Send broadcast message to the system that the server has stopped\n            lifecycleAgent.onStopped();\n        }\n    }\n}\n"
  },
  {
    "path": "settings.gradle",
    "content": "// SPDX-License-Identifier: Apache-2.0 AND GPL-3.0-or-later\ninclude ':app'\ninclude ':docs'\ninclude ':hiddenapi'\ninclude ':libcore:compat'\ninclude ':libcore:io'\ninclude ':libcore:ui'\ninclude ':libopenpgp'\ninclude ':libserver'\ninclude ':server'\nrootProject.name = \"AppManager\"\ngradle.ext.appManagerRoot = settingsDir\n"
  },
  {
    "path": "versions.gradle",
    "content": "// SPDX-License-Identifier: GPL-3.0-or-later\n\next {\n    compile_sdk = 36\n    min_sdk = 21\n    target_sdk = 36\n    build_tools = '36.1.0'\n\n    // Gradle plugins\n    agp_version = '8.13.2'\n\n    // Library dependencies\n    activity_version = \"1.11.0\" // API 21-22 support dropped in 1.12.x\n    androidx_core_version = \"1.17.0\" // Added temporarily until appcompat migrates to it\n    annotation_version = \"1.9.1\"\n    apksig_version = \"4.4.0\" // https://github.com/MuntashirAkon/apksig-android\n    appcompat_version = \"1.7.1\" // https://developer.android.com/jetpack/androidx/releases/appcompat\n    arsclib_version = \"66051037ef\" // https://github.com/MuntashirAkon/ARSCLib\n    baksmali_version = \"3.0.9\" // https://github.com/google/smali/tags\n    biometric_version = \"1.4.0-alpha04\" // API 21-22 support dropped in 1.4.0-alpha05\n    bouncycastle_version = \"1.83\" // https://www.bouncycastle.org/download/bouncy-castle-java\n    desugar_jdk_version = \"2.1.5\" // https://github.com/google/desugar_jdk_libs\n    documentfile_version = \"1.1.0\" // AppCompat still includes the buggy implementation of documentfile library (1.0.0)\n    duration_picker = \"c3c89adf3d\" // https://github.com/MuntashirAkon/time-duration-picker\n    fastscroll_version = \"1.3.0\" // https://github.com/zhanghai/AndroidFastScroll\n    gson_version = \"2.13.2\" // https://github.com/google/gson\n    hiddenapibypass_version = \"6.1\" // https://github.com/LSPosed/AndroidHiddenApiBypass\n    jadx_version = \"1.4.7\" // https://github.com/MuntashirAkon/jadx-android\n    jb_annotation_version = \"26.1.0\" // https://github.com/JetBrains/java-annotations (Compile-only)\n    libadb_version = \"3.1.1\" // https://github.com/MuntashirAkon/libadb-android\n    libsu_version = \"6.0.0\" // https://github.com/topjohnwu/libsu\n    material_version = \"1.13.0\" // https://github.com/material-components/material-components-android\n    preferences_version = \"1.2.1\"\n    refine_version = \"4.0.0\" // https://github.com/RikkaApps/HiddenApiRefinePlugin\n    room_version = \"2.7.2\" // API 21-22 support dropped in 2.8.x\n    simplemagic_version = \"1.17\" // https://github.com/j256/simplemagic\n    sora_editor_version = \"0.22.2\" // https://github.com/MuntashirAkon/sora-editor\n    speed_dial_version = \"3.3.0\" // https://github.com/leinardi/FloatingActionButtonSpeedDial\n    splashscreen_version = \"1.2.0\"\n    sun_security_version = \"1.1\" // https://github.com/MuntashirAkon/sun-security-android\n    swipe_refresh_version = \"1.2.0\"\n    unapkm_version = \"v1.4\" // https://github.com/MuntashirAkon/unapkm-android\n    webkit_version = \"1.14.0\" // API 21-22 support dropped in 1.15.x\n    zstd_version = \"1.5.7-7\" // https://github.com/luben/zstd-jni\n\n    // Test dependencies\n    junit_version = \"4.13.2\" // https://github.com/junit-team/junit4\n    robolectric_version = \"4.16.1\" // https://github.com/robolectric/robolectric\n}\n"
  }
]